am a9bce468: am 84742149: Merge "Make EntropyMixer mix in output of Hardware RNG into Linux RNG."

* commit 'a9bce46876d6f1f82727ab6922748fcc6b43c767':
  Make EntropyMixer mix in output of Hardware RNG into Linux RNG.
diff --git a/Android.mk b/Android.mk
index 0065529..49dc6af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,7 +26,10 @@
 # TODO: find a more appropriate way to do this.
 framework_res_source_path := APPS/framework-res_intermediates/src
 
-# the library
+# Build the master framework library.
+# The framework contains too many method references (>64K) for poor old DEX.
+# So we first build the framework as a monolithic static library then split it
+# up into smaller pieces.
 # ============================================================
 include $(CLEAR_VARS)
 
@@ -39,14 +42,6 @@
        core/java/android/speech/tts/EventLogTags.logtags \
        core/java/android/webkit/EventLogTags.logtags \
 
-# The following filters out code we are temporarily not including at all.
-# TODO: Move AWT and beans (and associated harmony code) back into libcore.
-# TODO: Maybe remove javax.microedition entirely?
-# TODO: Move SyncML (org.mobilecontrol.*) into its own library.
-LOCAL_SRC_FILES := $(filter-out \
-			org/mobilecontrol/% \
-			,$(LOCAL_SRC_FILES))
-
 ## READ ME: ########################################################
 ##
 ## When updating this list of aidl files, consider if that aidl is
@@ -100,6 +95,7 @@
 	core/java/android/bluetooth/IBluetoothManager.aidl \
 	core/java/android/bluetooth/IBluetoothManagerCallback.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
+	core/java/android/bluetooth/IBluetoothMap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
 	core/java/android/bluetooth/IBluetoothGatt.aidl \
 	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
@@ -109,6 +105,7 @@
 	core/java/android/content/IIntentReceiver.aidl \
 	core/java/android/content/IIntentSender.aidl \
 	core/java/android/content/IOnPrimaryClipChangedListener.aidl \
+	core/java/android/content/IAnonymousSyncAdapter.aidl \
 	core/java/android/content/ISyncAdapter.aidl \
 	core/java/android/content/ISyncContext.aidl \
 	core/java/android/content/ISyncStatusObserver.aidl \
@@ -119,11 +116,22 @@
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
 	core/java/android/database/IContentObserver.aidl \
+	core/java/android/hardware/ICameraService.aidl \
+	core/java/android/hardware/ICameraServiceListener.aidl \
+	core/java/android/hardware/ICamera.aidl \
+	core/java/android/hardware/ICameraClient.aidl \
+	core/java/android/hardware/IConsumerIrService.aidl \
+	core/java/android/hardware/IProCameraUser.aidl \
+	core/java/android/hardware/IProCameraCallbacks.aidl \
+	core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
+	core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
 	core/java/android/hardware/ISerialManager.aidl \
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
+	core/java/android/hardware/location/IFusedLocationHardware.aidl \
+	core/java/android/hardware/location/IFusedLocationHardwareSink.aidl \
 	core/java/android/hardware/location/IGeofenceHardware.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
@@ -135,10 +143,13 @@
 	core/java/android/net/INetworkStatsService.aidl \
 	core/java/android/net/INetworkStatsSession.aidl \
 	core/java/android/net/nsd/INsdManager.aidl \
-	core/java/android/nfc/INdefPushCallback.aidl \
+	core/java/android/nfc/IAppCallback.aidl \
 	core/java/android/nfc/INfcAdapter.aidl \
 	core/java/android/nfc/INfcAdapterExtras.aidl \
 	core/java/android/nfc/INfcTag.aidl \
+	core/java/android/nfc/INfcCardEmulation.aidl \
+	core/java/android/os/IBatteryPropertiesListener.aidl \
+	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
 	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
@@ -151,6 +162,18 @@
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
+	core/java/android/print/ILayoutResultCallback.aidl \
+	core/java/android/print/IPrinterDiscoveryObserver.aidl \
+	core/java/android/print/IPrintDocumentAdapter.aidl \
+	core/java/android/print/IPrintClient.aidl \
+	core/java/android/print/IPrintJobStateChangeListener.aidl \
+	core/java/android/print/IPrintManager.aidl \
+	core/java/android/print/IPrintSpooler.aidl \
+	core/java/android/print/IPrintSpoolerCallbacks.aidl \
+	core/java/android/print/IPrintSpoolerClient.aidl \
+	core/java/android/print/IWriteResultCallback.aidl \
+	core/java/android/printservice/IPrintService.aidl \
+	core/java/android/printservice/IPrintServiceClient.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
@@ -161,6 +184,7 @@
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
 	core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
 	core/java/android/view/IApplicationToken.aidl \
+	core/java/android/view/IAssetAtlas.aidl \
 	core/java/android/view/IMagnificationCallbacks.aidl \
 	core/java/android/view/IInputFilter.aidl \
 	core/java/android/view/IInputFilterHost.aidl \
@@ -178,6 +202,7 @@
 	core/java/com/android/internal/app/IAppOpsCallback.aidl \
 	core/java/com/android/internal/app/IAppOpsService.aidl \
 	core/java/com/android/internal/app/IBatteryStats.aidl \
+	core/java/com/android/internal/app/IProcessStats.aidl \
 	core/java/com/android/internal/app/IUsageStats.aidl \
 	core/java/com/android/internal/app/IMediaContainerService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
@@ -186,6 +211,9 @@
 	core/java/com/android/internal/backup/IObbBackupService.aidl \
 	core/java/com/android/internal/policy/IFaceLockCallback.aidl \
 	core/java/com/android/internal/policy/IFaceLockInterface.aidl \
+	core/java/com/android/internal/policy/IKeyguardShowCallback.aidl \
+	core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
+	core/java/com/android/internal/policy/IKeyguardService.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
 	core/java/com/android/internal/statusbar/IStatusBar.aidl \
@@ -209,12 +237,14 @@
 	keystore/java/android/security/IKeyChainService.aidl \
 	location/java/android/location/ICountryDetector.aidl \
 	location/java/android/location/ICountryListener.aidl \
+	location/java/android/location/IFusedProvider.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
 	location/java/android/location/IGeofenceProvider.aidl \
 	location/java/android/location/IGpsStatusListener.aidl \
 	location/java/android/location/IGpsStatusProvider.aidl \
 	location/java/android/location/ILocationListener.aidl \
 	location/java/android/location/ILocationManager.aidl \
+	location/java/android/location/IFusedGeofenceHardware.aidl \
 	location/java/android/location/IGpsGeofenceHardware.aidl \
 	location/java/android/location/INetInitiatedListener.aidl \
 	location/java/com/android/internal/location/ILocationProvider.aidl \
@@ -234,9 +264,10 @@
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
-	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
-#
-
+	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
+	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
+	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
+	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
 
 # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
 LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
@@ -249,17 +280,11 @@
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt core core-junit ext okhttp
 
-LOCAL_MODULE := framework
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE := framework-base
 
-# List of classes and interfaces which should be loaded by the Zygote.
-LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes
+LOCAL_JAR_EXCLUDE_FILES := none
 
-#LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-
-LOCAL_DX_FLAGS := --core-library
-
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # Make sure that R.java and Manifest.java are built before we build
 # the source for this library.
@@ -267,14 +292,53 @@
 	$(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp
 $(full_classes_compiled_jar): $(framework_res_R_stamp)
 
-# Make sure that framework-res is installed when framework is.
-$(LOCAL_INSTALLED_MODULE): | $(dir $(LOCAL_INSTALLED_MODULE))framework-res.apk
-
-framework_built := $(call java-lib-deps,framework)
-
-# AIDL files to be preprocessed and included in the SDK,
-# relative to the root of the build tree.
+# Build part 1 of the framework library.
 # ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := framework
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_STATIC_JAVA_LIBRARIES := framework-base
+LOCAL_DX_FLAGS := --core-library
+
+# Packages to include, use \* wildcard to include descendants.
+LOCAL_JAR_PACKAGES := android\*
+
+# List of classes and interfaces which should be loaded by the Zygote.
+LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes
+
+include $(BUILD_JAVA_LIBRARY)
+framework_module := $(LOCAL_INSTALLED_MODULE)
+
+# Build part 2 of the framework library.
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := framework2
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_STATIC_JAVA_LIBRARIES := framework-base
+LOCAL_DX_FLAGS := --core-library
+
+# Packages to include, use \* wildcard to include descendants.
+LOCAL_JAR_PACKAGES := com\* javax\*
+
+include $(BUILD_JAVA_LIBRARY)
+framework2_module := $(LOCAL_INSTALLED_MODULE)
+
+# Make sure that all framework modules are installed when framework is.
+# ============================================================
+$(framework_module): | $(dir $(framework_module))framework-res.apk
+$(framework_module): | $(dir $(framework_module))framework2.jar
+
+framework_built := $(call java-lib-deps,framework framework2)
+
+# Copy AIDL files to be preprocessed and included in the SDK,
+# specified relative to the root of the build tree.
+# ============================================================
+include $(CLEAR_VARS)
+
 aidl_files := \
 	frameworks/base/core/java/android/accounts/IAccountManager.aidl \
 	frameworks/base/core/java/android/accounts/IAccountManagerResponse.aidl \
@@ -290,9 +354,11 @@
 	frameworks/base/core/java/android/content/Intent.aidl \
 	frameworks/base/core/java/android/content/IntentSender.aidl \
 	frameworks/base/core/java/android/content/PeriodicSync.aidl \
+	frameworks/base/core/java/android/content/SyncRequest.aidl \
 	frameworks/base/core/java/android/content/SyncStats.aidl \
 	frameworks/base/core/java/android/content/res/Configuration.aidl \
 	frameworks/base/core/java/android/database/CursorWindow.aidl \
+	frameworks/base/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl \
 	frameworks/base/core/java/android/net/Uri.aidl \
 	frameworks/base/core/java/android/nfc/NdefMessage.aidl \
 	frameworks/base/core/java/android/nfc/NdefRecord.aidl \
@@ -323,11 +389,14 @@
 	frameworks/base/location/java/android/location/Geofence.aidl \
 	frameworks/base/location/java/android/location/Location.aidl \
 	frameworks/base/location/java/android/location/LocationRequest.aidl \
+	frameworks/base/location/java/android/location/FusedBatchOptions.aidl \
 	frameworks/base/location/java/com/android/internal/location/ProviderProperties.aidl \
 	frameworks/base/location/java/com/android/internal/location/ProviderRequest.aidl \
 	frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
 	frameworks/base/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl \
+	frameworks/base/wifi/java/android/net/wifi/BatchedScanSettings.aidl \
+	frameworks/base/wifi/java/android/net/wifi/BatchedScanResult.aidl \
 
 gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
 $(gen): PRIVATE_SRC_FILES := $(aidl_files)
@@ -364,6 +433,7 @@
 
 non_base_dirs := \
 	../../external/apache-http/src/org/apache/http \
+	../opt/telephony/src/java/android/provider \
 	../opt/telephony/src/java/android/telephony \
 	../opt/telephony/src/java/android/telephony/gsm \
 	../opt/net/voip/src/java/android/net/rtp \
@@ -420,6 +490,7 @@
 	okhttp \
 	ext \
 	framework \
+	framework2 \
 	mms-common \
 	telephony-common \
 	voip-common
@@ -456,7 +527,7 @@
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
 framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
-	$(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)
+	$(call intermediates-dir-for,JAVA_LIBRARIES,framework-base,,COMMON)
 
 framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= \
 	$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR) \
@@ -467,104 +538,116 @@
     frameworks/base/docs/knowntags.txt
 
 sample_dir := development/samples
+new_sample_dir := developers/samples/android
+
+# Whitelist of valid groups, used for default TOC grouping. Each sample must
+# belong to one (and only one) group. Assign samples to groups by setting
+# a sample.group var to one of these groups in the sample's _index.jd.
+sample_groups := -samplegroup Input \
+                 -samplegroup Sensors \
+                 -samplegroup Connectivity
 
 # the list here should match the list of samples included in the sdk samples package
 # (see development/build/sdk.atree)
 # remove htmlified samples for now -- samples are still available through the SDK
-# web_docs_sample_code_flags := \
+web_docs_sample_code_flags := \
 		-hdf android.hasSamples 1 \
+		-samplecode $(new_sample_dir)/input/gestures/BasicGestureDetect/BasicGestureDetect \
+ 		            samples/BasicGestureDetect/ "Basic Gestures" \
 		-samplecode $(sample_dir)/AccelerometerPlay \
-		            resources/samples/AccelerometerPlay "Accelerometer Play" \
+ 		            samples/AccelerometerPlay "Accelerometer Play" \
 		-samplecode $(sample_dir)/ActionBarCompat \
-		            resources/samples/ActionBarCompat "Action Bar Compatibility" \
-                -samplecode $(sample_dir)/AndroidBeamDemo \
-		            resources/samples/AndroidBeamDemo "Android Beam Demo" \
-		-samplecode $(sample_dir)/ApiDemos \
-		            resources/samples/ApiDemos "API Demos" \
-		-samplecode $(sample_dir)/Support4Demos \
-		            resources/samples/Support4Demos "API 4+ Support Demos" \
-		-samplecode $(sample_dir)/Support13Demos \
-		            resources/samples/Support13Demos "API 13+ Support Demos" \
-		-samplecode $(sample_dir)/BackupRestore \
-		            resources/samples/BackupRestore "Backup and Restore" \
-		-samplecode $(sample_dir)/BluetoothChat \
-		            resources/samples/BluetoothChat "Bluetooth Chat" \
-		-samplecode $(sample_dir)/BluetoothHDP \
-		            resources/samples/BluetoothHDP "Bluetooth HDP Demo" \
-		-samplecode $(sample_dir)/BusinessCard \
-		            resources/samples/BusinessCard "Business Card" \
-		-samplecode $(sample_dir)/ContactManager \
-		            resources/samples/ContactManager "Contact Manager" \
-		-samplecode $(sample_dir)/CubeLiveWallpaper \
-		            resources/samples/CubeLiveWallpaper "Cube Live Wallpaper" \
-		-samplecode $(sample_dir)/Home \
-		            resources/samples/Home "Home" \
-		-samplecode $(sample_dir)/HoneycombGallery \
-		            resources/samples/HoneycombGallery "Honeycomb Gallery" \
-		-samplecode $(sample_dir)/JetBoy \
-		            resources/samples/JetBoy "JetBoy" \
-		-samplecode $(sample_dir)/KeyChainDemo \
-		            resources/samples/KeyChainDemo "KeyChain Demo" \
-		-samplecode $(sample_dir)/LunarLander \
-		            resources/samples/LunarLander "Lunar Lander" \
-		-samplecode $(sample_dir)/training/ads-and-ux \
-		            resources/samples/training/ads-and-ux "Mobile Advertisement Integration" \
-		-samplecode $(sample_dir)/MultiResolution \
-		            resources/samples/MultiResolution "Multiple Resolutions" \
-		-samplecode $(sample_dir)/training/multiscreen/newsreader \
-		            resources/samples/newsreader "News Reader" \
-		-samplecode $(sample_dir)/NotePad \
-		            resources/samples/NotePad "Note Pad" \
-		-samplecode $(sample_dir)/SpellChecker/SampleSpellCheckerService \
-		            resources/samples/SpellChecker/SampleSpellCheckerService "Spell Checker Service" \
-		-samplecode $(sample_dir)/SpellChecker/HelloSpellChecker \
-		            resources/samples/SpellChecker/HelloSpellChecker "Spell Checker Client" \
-		-samplecode $(sample_dir)/SampleSyncAdapter \
-		            resources/samples/SampleSyncAdapter "Sample Sync Adapter" \
-		-samplecode $(sample_dir)/RandomMusicPlayer \
-		            resources/samples/RandomMusicPlayer "Random Music Player" \
-		-samplecode $(sample_dir)/RenderScript \
-		            resources/samples/RenderScript "RenderScript" \
-		-samplecode $(sample_dir)/SearchableDictionary \
-		            resources/samples/SearchableDictionary "Searchable Dictionary v2" \
-		-samplecode $(sample_dir)/SipDemo \
-		            resources/samples/SipDemo "SIP Demo" \
-		-samplecode $(sample_dir)/Snake \
-		            resources/samples/Snake "Snake" \
-		-samplecode $(sample_dir)/SoftKeyboard \
-		            resources/samples/SoftKeyboard "Soft Keyboard" \
-		-samplecode $(sample_dir)/Spinner  \
-		            resources/samples/Spinner "Spinner" \
-		-samplecode $(sample_dir)/SpinnerTest \
-		            resources/samples/SpinnerTest "SpinnerTest" \
-		-samplecode $(sample_dir)/StackWidget \
-		            resources/samples/StackWidget "StackView Widget" \
-		-samplecode $(sample_dir)/TicTacToeLib  \
-		            resources/samples/TicTacToeLib "TicTacToeLib" \
-		-samplecode $(sample_dir)/TicTacToeMain \
-		            resources/samples/TicTacToeMain "TicTacToeMain" \
-		-samplecode $(sample_dir)/ToyVpn \
-		            resources/samples/ToyVpn "Toy VPN Client" \
-		-samplecode $(sample_dir)/USB \
-		            resources/samples/USB "USB" \
-		-samplecode $(sample_dir)/WeatherListWidget \
-		            resources/samples/WeatherListWidget "Weather List Widget" \
-		-samplecode $(sample_dir)/WiFiDirectDemo \
-                            resources/samples/WiFiDirectDemo "Wi-Fi Direct Demo" \
-		-samplecode $(sample_dir)/Wiktionary \
-		            resources/samples/Wiktionary "Wiktionary" \
-		-samplecode $(sample_dir)/WiktionarySimple \
-		            resources/samples/WiktionarySimple "Wiktionary (Simplified)" \
-		-samplecode $(sample_dir)/VoiceRecognitionService \
-		            resources/samples/VoiceRecognitionService "Voice Recognition Service" \
-		-samplecode $(sample_dir)/VoicemailProviderDemo \
-		            resources/samples/VoicemailProviderDemo "Voicemail Provider Demo" \
-		-samplecode $(sample_dir)/XmlAdapters \
-		            resources/samples/XmlAdapters "XML Adapters" \
-		-samplecode $(sample_dir)/TtsEngine \
-		            resources/samples/TtsEngine "Text To Speech Engine" \
-		-samplecode $(sample_dir)/training/device-management-policy \
-		            resources/samples/training/device-management-policy "Device Management Policy"
+ 		            samples/ActionBarCompat "Action Bar Compatibility" \
+ 		-samplecode $(sample_dir)/BluetoothHDP \
+ 		            samples/BluetoothHDP "Bluetooth HDP Demo" \
+ 		-samplecode $(sample_dir)/BluetoothLeGatt \
+ 		            samples/BluetoothLeGatt "Bluetooth HDP Demo"
+#       -samplecode $(sample_dir)/AndroidBeamDemo \
+# 		            samples/AndroidBeamDemo "Android Beam Demo" \
+# 		-samplecode $(sample_dir)/ApiDemos \
+# 		            samples/ApiDemos "API Demos" \
+# 		-samplecode $(sample_dir)/Support4Demos \
+# 		            samples/Support4Demos "API 4+ Support Demos" \
+# 		-samplecode $(sample_dir)/Support13Demos \
+# 		            samples/Support13Demos "API 13+ Support Demos" \
+# 		-samplecode $(sample_dir)/BackupRestore \
+# 		            samples/BackupRestore "Backup and Restore" \
+#		-samplecode $(sample_dir)/BluetoothChat \
+# 		            samples/BluetoothChat "Bluetooth Chat" \
+# 		-samplecode $(sample_dir)/BusinessCard \
+# 		            samples/BusinessCard "Business Card" \
+# 		-samplecode $(sample_dir)/ContactManager \
+# 		            samples/ContactManager "Contact Manager" \
+# 		-samplecode $(sample_dir)/CubeLiveWallpaper \
+# 		            samples/CubeLiveWallpaper "Cube Live Wallpaper" \
+# 		-samplecode $(sample_dir)/Home \
+# 		            samples/Home "Home" \
+# 		-samplecode $(sample_dir)/HoneycombGallery \
+# 		            samples/HoneycombGallery "Honeycomb Gallery" \
+# 		-samplecode $(sample_dir)/JetBoy \
+# 		            samples/JetBoy "JetBoy" \
+# 		-samplecode $(sample_dir)/KeyChainDemo \
+# 		            samples/KeyChainDemo "KeyChain Demo" \
+# 		-samplecode $(sample_dir)/LunarLander \
+# 		            samples/LunarLander "Lunar Lander" \
+# 		-samplecode $(sample_dir)/training/ads-and-ux \
+# 		            samples/training/ads-and-ux "Mobile Advertisement Integration" \
+# 		-samplecode $(sample_dir)/MultiResolution \
+# 		            samples/MultiResolution "Multiple Resolutions" \
+# 		-samplecode $(sample_dir)/training/multiscreen/newsreader \
+# 		            samples/newsreader "News Reader" \
+# 		-samplecode $(sample_dir)/NotePad \
+# 		            samples/NotePad "Note Pad" \
+# 		-samplecode $(sample_dir)/SpellChecker/SampleSpellCheckerService \
+# 		            samples/SpellChecker/SampleSpellCheckerService "Spell Checker Service" \
+# 		-samplecode $(sample_dir)/SpellChecker/HelloSpellChecker \
+# 		            samples/SpellChecker/HelloSpellChecker "Spell Checker Client" \
+# 		-samplecode $(sample_dir)/SampleSyncAdapter \
+# 		            samples/SampleSyncAdapter "Sample Sync Adapter" \
+# 		-samplecode $(sample_dir)/RandomMusicPlayer \
+# 		            samples/RandomMusicPlayer "Random Music Player" \
+# 		-samplecode $(sample_dir)/RenderScript \
+# 		            samples/RenderScript "RenderScript" \
+# 		-samplecode $(sample_dir)/SearchableDictionary \
+# 		            samples/SearchableDictionary "Searchable Dictionary v2" \
+# 		-samplecode $(sample_dir)/SipDemo \
+# 		            samples/SipDemo "SIP Demo" \
+# 		-samplecode $(sample_dir)/Snake \
+# 		            samples/Snake "Snake" \
+# 		-samplecode $(sample_dir)/SoftKeyboard \
+# 		            samples/SoftKeyboard "Soft Keyboard" \
+# 		-samplecode $(sample_dir)/Spinner  \
+# 		            samples/Spinner "Spinner" \
+# 		-samplecode $(sample_dir)/SpinnerTest \
+# 		            samples/SpinnerTest "SpinnerTest" \
+# 		-samplecode $(sample_dir)/StackWidget \
+# 		            samples/StackWidget "StackView Widget" \
+# 		-samplecode $(sample_dir)/TicTacToeLib  \
+# 		            samples/TicTacToeLib "TicTacToeLib" \
+# 		-samplecode $(sample_dir)/TicTacToeMain \
+# 		            samples/TicTacToeMain "TicTacToeMain" \
+# 		-samplecode $(sample_dir)/ToyVpn \
+# 		            samples/ToyVpn "Toy VPN Client" \
+# 		-samplecode $(sample_dir)/USB \
+# 		            samples/USB "USB" \
+# 		-samplecode $(sample_dir)/WeatherListWidget \
+# 		            samples/WeatherListWidget "Weather List Widget" \
+# 		-samplecode $(sample_dir)/WiFiDirectDemo \
+#                   samples/WiFiDirectDemo "Wi-Fi Direct Demo" \
+# 		-samplecode $(sample_dir)/Wiktionary \
+# 		            samples/Wiktionary "Wiktionary" \
+# 		-samplecode $(sample_dir)/WiktionarySimple \
+# 		            samples/WiktionarySimple "Wiktionary (Simplified)" \
+# 		-samplecode $(sample_dir)/VoiceRecognitionService \
+# 		            samples/VoiceRecognitionService "Voice Recognition Service" \
+# 		-samplecode $(sample_dir)/VoicemailProviderDemo \
+# 		            samples/VoicemailProviderDemo "Voicemail Provider Demo" \
+# 		-samplecode $(sample_dir)/XmlAdapters \
+# 		            samples/XmlAdapters "XML Adapters" \
+# 		-samplecode $(sample_dir)/TtsEngine \
+# 		            samples/TtsEngine "Text To Speech Engine" \
+# 		-samplecode $(sample_dir)/training/device-management-policy \
+# 		            samples/training/device-management-policy "Device Management Policy"
 
 
 ## SDK version identifiers used in the published docs
@@ -656,13 +739,13 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-                $(web_docs_sample_code_flags) \
-                -offlinemode \
+		-offlinemode \
 		-title "Android SDK" \
 		-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
 		-todo $(OUT_DOCS)/$(LOCAL_MODULE)-docs-todo.html \
 		-sdkvalues $(OUT_DOCS) \
 		-hdf android.whichdoc offline
+#		$(web_docs_sample_code_flags)
 
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
@@ -696,10 +779,10 @@
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-		$(web_docs_sample_code_flags) \
 		-toroot / \
-		-hdf android.whichdoc online \
-		-hdf template.showLanguageMenu true
+		-hdf android.whichdoc online
+#		$(sample_groups) \
+#		$(web_docs_sample_code_flags)
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
@@ -723,11 +806,11 @@
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-		$(web_docs_sample_code_flags) \
 		-devsite \
 		-toroot / \
 		-hdf android.whichdoc online \
 		-hdf devsite true
+#		$(web_docs_sample_code_flags)
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
@@ -738,7 +821,7 @@
 
 LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
 LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
-LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) framework
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
 LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
 LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 0c3ccec..c5c7fe3 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -80,12 +80,12 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content/IClipboard.P)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/ITelephonyRegistry.P)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates)
-$(call add-clean-step, rm -rf out/target/common/docs/api-stubs*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/docs/api-stubs*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/trustedlogic)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/com/trustedlogic)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/trustedlogic)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/com/trustedlogic)
-$(call add-clean-step, rm -rf $(OUT_DIR)/target/target/common/obj/APPS/Music2_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Music2_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/INdefTag.java)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_aacdec_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_mp3dec_intermediates)
@@ -161,6 +161,27 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodCallback.*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libandroidfw_intermediates/import_includes)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(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/src/core/java/android/print/IPrinterDiscoveryObserver.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/printservice/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/packages/services/Proxy/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrinterDiscoverySessionObserver.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrinterDiscoverySessionClient.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/os/IBattery*)
+$(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/android_stubs_current_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/usr/idc/frameworks)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/usr/keylayout/frameworks)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/usr/keychars/frameworks)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/media/video/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/effects/)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index 6f0bbce..2ed9c58 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,15 +20,20 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_CALL_SERVICE = "android.permission.BIND_CALL_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+    field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
+    field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
+    field public static final java.lang.String BIND_PRINT_SPOOLER_SERVICE = "android.permission.BIND_PRINT_SPOOLER_SERVICE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
+    field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
     field public static final java.lang.String BRICK = "android.permission.BRICK";
     field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -37,6 +42,9 @@
     field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
     field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
     field public static final java.lang.String CAMERA = "android.permission.CAMERA";
+    field public static final java.lang.String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT";
+    field public static final java.lang.String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT";
+    field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
     field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
     field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -64,13 +72,17 @@
     field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
+    field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
     field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
     field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+    field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+    field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
+    field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
     field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
     field public static final java.lang.String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
     field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
@@ -121,6 +133,8 @@
     field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
     field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
     field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
+    field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
+    field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
     field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
@@ -219,6 +233,7 @@
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
     field public static final int accessibilityFlags = 16843652; // 0x1010384
+    field public static final int accessibilityLiveRegion = 16843758; // 0x10103ee
     field public static final int accountPreferences = 16843423; // 0x101029f
     field public static final int accountType = 16843407; // 0x101028f
     field public static final int action = 16842797; // 0x101002d
@@ -253,6 +268,7 @@
     field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
     field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+    field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
     field public static final int alertDialogIcon = 16843605; // 0x1010355
@@ -280,12 +296,14 @@
     field public static final deprecated int animationResolution = 16843546; // 0x101031a
     field public static final int antialias = 16843034; // 0x101011a
     field public static final int anyDensity = 16843372; // 0x101026c
+    field public static final int apduServiceBanner = 16843757; // 0x10103ed
     field public static final int apiKey = 16843281; // 0x1010211
     field public static final int author = 16843444; // 0x10102b4
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
     field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
     field public static final int autoLink = 16842928; // 0x10100b0
+    field public static final int autoMirrored = 16843754; // 0x10103ea
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -326,6 +344,7 @@
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final deprecated int capitalize = 16843113; // 0x1010169
+    field public static final int category = 16843752; // 0x10103e8
     field public static final int centerBright = 16842956; // 0x10100cc
     field public static final int centerColor = 16843275; // 0x101020b
     field public static final int centerDark = 16842952; // 0x10100c8
@@ -474,6 +493,7 @@
     field public static final int fadeScrollbars = 16843434; // 0x10102aa
     field public static final int fadingEdge = 16842975; // 0x10100df
     field public static final int fadingEdgeLength = 16842976; // 0x10100e0
+    field public static final int fadingMode = 16843745; // 0x10103e1
     field public static final int fastScrollAlwaysVisible = 16843573; // 0x1010335
     field public static final int fastScrollEnabled = 16843302; // 0x1010226
     field public static final int fastScrollOverlayPosition = 16843578; // 0x101033a
@@ -513,6 +533,7 @@
     field public static final int freezesText = 16843116; // 0x101016c
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
+    field public static final int fromScene = 16843741; // 0x10103dd
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
     field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -598,6 +619,7 @@
     field public static final int installLocation = 16843447; // 0x10102b7
     field public static final int interpolator = 16843073; // 0x1010141
     field public static final int isAlwaysSyncable = 16843571; // 0x1010333
+    field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
     field public static final int isDefault = 16843297; // 0x1010221
     field public static final int isIndicator = 16843079; // 0x1010147
@@ -621,6 +643,7 @@
     field public static final int keyPreviewHeight = 16843321; // 0x1010239
     field public static final int keyPreviewLayout = 16843319; // 0x1010237
     field public static final int keyPreviewOffset = 16843320; // 0x1010238
+    field public static final int keySet = 16843739; // 0x10103db
     field public static final int keyTextColor = 16843318; // 0x1010236
     field public static final int keyTextSize = 16843316; // 0x1010234
     field public static final int keyWidth = 16843325; // 0x101023d
@@ -853,6 +876,7 @@
     field public static final int reqKeyboardType = 16843304; // 0x1010228
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
+    field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
@@ -951,9 +975,13 @@
     field public static final int spinnersShown = 16843595; // 0x101034b
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
     field public static final int src = 16843033; // 0x1010119
+    field public static final int ssp = 16843747; // 0x10103e3
+    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 starStyle = 16842882; // 0x1010082
     field public static final int startColor = 16843165; // 0x101019d
+    field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -997,6 +1025,7 @@
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsRtl = 16843695; // 0x10103af
+    field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
@@ -1013,6 +1042,7 @@
     field public static final int targetActivity = 16843266; // 0x1010202
     field public static final int targetClass = 16842799; // 0x101002f
     field public static final int targetDescriptions = 16843680; // 0x10103a0
+    field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetPackage = 16842785; // 0x1010021
     field public static final int targetSdkVersion = 16843376; // 0x1010270
     field public static final int taskAffinity = 16842770; // 0x1010012
@@ -1101,6 +1131,7 @@
     field public static final int titleTextStyle = 16843512; // 0x10102f8
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
+    field public static final int toScene = 16843742; // 0x10103de
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
     field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1115,6 +1146,8 @@
     field public static final int transcriptMode = 16843008; // 0x1010100
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
+    field public static final int transition = 16843743; // 0x10103df
+    field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
     field public static final int type = 16843169; // 0x10101a1
@@ -1133,6 +1166,7 @@
     field public static final int valueTo = 16843487; // 0x10102df
     field public static final int valueType = 16843488; // 0x10102e0
     field public static final int variablePadding = 16843157; // 0x1010195
+    field public static final int vendor = 16843751; // 0x10103e7
     field public static final int versionCode = 16843291; // 0x101021b
     field public static final int versionName = 16843292; // 0x101021c
     field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -2316,6 +2350,7 @@
   public abstract class Animator implements java.lang.Cloneable {
     ctor public Animator();
     method public void addListener(android.animation.Animator.AnimatorListener);
+    method public void addPauseListener(android.animation.Animator.AnimatorPauseListener);
     method public void cancel();
     method public android.animation.Animator clone();
     method public void end();
@@ -2323,10 +2358,14 @@
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
     method public abstract long getStartDelay();
+    method public boolean isPaused();
     method public abstract boolean isRunning();
     method public boolean isStarted();
+    method public void pause();
     method public void removeAllListeners();
     method public void removeListener(android.animation.Animator.AnimatorListener);
+    method public void removePauseListener(android.animation.Animator.AnimatorPauseListener);
+    method public void resume();
     method public abstract android.animation.Animator setDuration(long);
     method public abstract void setInterpolator(android.animation.TimeInterpolator);
     method public abstract void setStartDelay(long);
@@ -2343,16 +2382,23 @@
     method public abstract void onAnimationStart(android.animation.Animator);
   }
 
+  public static abstract interface Animator.AnimatorPauseListener {
+    method public abstract void onAnimationPause(android.animation.Animator);
+    method public abstract void onAnimationResume(android.animation.Animator);
+  }
+
   public class AnimatorInflater {
     ctor public AnimatorInflater();
     method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
   }
 
-  public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener {
+  public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
     ctor public AnimatorListenerAdapter();
     method public void onAnimationCancel(android.animation.Animator);
     method public void onAnimationEnd(android.animation.Animator);
+    method public void onAnimationPause(android.animation.Animator);
     method public void onAnimationRepeat(android.animation.Animator);
+    method public void onAnimationResume(android.animation.Animator);
     method public void onAnimationStart(android.animation.Animator);
   }
 
@@ -2808,6 +2854,7 @@
     method public void recreate();
     method public void registerForContextMenu(android.view.View);
     method public final deprecated void removeDialog(int);
+    method public void reportFullyDrawn();
     method public final boolean requestWindowFeature(int);
     method public final void runOnUiThread(java.lang.Runnable);
     method public void setContentView(int);
@@ -2877,6 +2924,8 @@
   }
 
   public class ActivityManager {
+    method public boolean clearApplicationUserData();
+    method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
     method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
@@ -2891,12 +2940,14 @@
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
+    method public boolean isLowRamDevice();
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
     method public void killBackgroundProcesses(java.lang.String);
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
     field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
     field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2
@@ -3028,17 +3079,19 @@
   public class AlarmManager {
     method public void cancel(android.app.PendingIntent);
     method public void set(int, long, android.app.PendingIntent);
-    method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
+    method public void setExact(int, long, android.app.PendingIntent);
+    method public deprecated void setInexactRepeating(int, long, long, android.app.PendingIntent);
     method public void setRepeating(int, long, long, android.app.PendingIntent);
     method public void setTime(long);
     method public void setTimeZone(java.lang.String);
+    method public void setWindow(int, long, long, android.app.PendingIntent);
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
-    field public static final long INTERVAL_DAY = 86400000L; // 0x5265c00L
-    field public static final long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L
-    field public static final long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L
-    field public static final long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L
-    field public static final long INTERVAL_HOUR = 3600000L; // 0x36ee80L
+    field public static final deprecated long INTERVAL_DAY = 86400000L; // 0x5265c00L
+    field public static final deprecated long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L
+    field public static final deprecated long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L
+    field public static final deprecated long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L
+    field public static final deprecated long INTERVAL_HOUR = 3600000L; // 0x36ee80L
     field public static final int RTC = 1; // 0x1
     field public static final int RTC_WAKEUP = 0; // 0x0
   }
@@ -3116,6 +3169,30 @@
     ctor public AliasActivity();
   }
 
+  public class AppOpsManager {
+    method public int checkOp(java.lang.String, int, java.lang.String);
+    method public int checkOpNoThrow(java.lang.String, int, java.lang.String);
+    method public void checkPackage(int, java.lang.String);
+    method public void finishOp(java.lang.String, int, java.lang.String);
+    method public int noteOp(java.lang.String, int, java.lang.String);
+    method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
+    method public int startOp(java.lang.String, int, java.lang.String);
+    method public int startOpNoThrow(java.lang.String, int, java.lang.String);
+    method public void startWatchingMode(int, java.lang.String, android.app.AppOpsManager.OnOpChangedListener);
+    method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_ERRORED = 2; // 0x2
+    field public static final int MODE_IGNORED = 1; // 0x1
+    field public static final java.lang.String OPSTR_COARSE_LOCATION = "android:coarse_location";
+    field public static final java.lang.String OPSTR_FINE_LOCATION = "android:fine_location";
+    field public static final java.lang.String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
+    field public static final java.lang.String OPSTR_MONITOR_LOCATION = "android:monitor_location";
+  }
+
+  public static abstract interface AppOpsManager.OnOpChangedListener {
+    method public abstract void onOpChanged(java.lang.String, java.lang.String);
+  }
+
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
     method public void onConfigurationChanged(android.content.res.Configuration);
@@ -3839,6 +3916,23 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final java.lang.String EXTRA_PEOPLE = "android.people";
+    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
+    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
+    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
+    field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
+    field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final java.lang.String EXTRA_TEXT = "android.text";
+    field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final java.lang.String EXTRA_TITLE = "android.title";
+    field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
     field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
     field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
@@ -3853,12 +3947,14 @@
     field public static final int PRIORITY_MAX = 2; // 0x2
     field public static final int PRIORITY_MIN = -2; // 0xfffffffe
     field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public android.app.Notification.Action[] actions;
     field public int audioStreamType;
     field public android.widget.RemoteViews bigContentView;
     field public android.app.PendingIntent contentIntent;
     field public android.widget.RemoteViews contentView;
     field public int defaults;
     field public android.app.PendingIntent deleteIntent;
+    field public android.os.Bundle extras;
     field public int flags;
     field public android.app.PendingIntent fullScreenIntent;
     field public int icon;
@@ -3876,12 +3972,22 @@
     field public long when;
   }
 
+  public static class Notification.Action implements android.os.Parcelable {
+    ctor public Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.Notification.Action clone();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public android.app.PendingIntent actionIntent;
+    field public int icon;
+    field public java.lang.CharSequence title;
+  }
+
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
     ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
-    method public android.app.Notification build();
     method public android.app.Notification.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.BigPictureStyle setSummaryText(java.lang.CharSequence);
   }
@@ -3890,7 +3996,6 @@
     ctor public Notification.BigTextStyle();
     ctor public Notification.BigTextStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence);
-    method public android.app.Notification build();
     method public android.app.Notification.BigTextStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
   }
@@ -3908,6 +4013,7 @@
     method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
     method public android.app.Notification.Builder setDefaults(int);
     method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
+    method public android.app.Notification.Builder setExtras(android.os.Bundle);
     method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
     method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.Builder setLights(int, int, int);
@@ -3934,14 +4040,13 @@
     ctor public Notification.InboxStyle();
     ctor public Notification.InboxStyle(android.app.Notification.Builder);
     method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
-    method public android.app.Notification build();
     method public android.app.Notification.InboxStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setSummaryText(java.lang.CharSequence);
   }
 
   public static abstract class Notification.Style {
     ctor public Notification.Style();
-    method public abstract android.app.Notification build();
+    method public android.app.Notification build();
     method protected void checkBuilder();
     method protected android.widget.RemoteViews getStandardView(int);
     method protected void internalSetBigContentTitle(java.lang.CharSequence);
@@ -4257,6 +4362,7 @@
     method public void clear() throws java.io.IOException;
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
+    method public android.content.Intent getCropAndSetWallpaperIntent(android.net.Uri);
     method public int getDesiredMinimumHeight();
     method public int getDesiredMinimumWidth();
     method public android.graphics.drawable.Drawable getDrawable();
@@ -4274,6 +4380,7 @@
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
     field public static final java.lang.String ACTION_CHANGE_LIVE_WALLPAPER = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER";
+    field public static final java.lang.String ACTION_CROP_AND_SET_WALLPAPER = "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
     field public static final java.lang.String ACTION_LIVE_WALLPAPER_CHOOSER = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
     field public static final java.lang.String COMMAND_DROP = "android.home.drop";
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
@@ -4675,68 +4782,165 @@
   }
 
   public class BluetoothAssignedNumbers {
+    field public static final int AAMP_OF_AMERICA = 190; // 0xbe
     field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a
+    field public static final int ACE_SENSOR = 188; // 0xbc
+    field public static final int ADIDAS = 195; // 0xc3
+    field public static final int ADVANCED_PANMOBIL_SYSTEMS = 145; // 0x91
+    field public static final int AIROHA_TECHNOLOGY = 148; // 0x94
     field public static final int ALCATEL = 36; // 0x24
+    field public static final int ALPWISE = 154; // 0x9a
+    field public static final int AMICCOM_ELECTRONICS = 192; // 0xc0
+    field public static final int APLIX = 189; // 0xbd
     field public static final int APPLE = 76; // 0x4c
     field public static final int APT_LICENSING = 79; // 0x4f
+    field public static final int ARCHOS = 207; // 0xcf
+    field public static final int ARP_DEVICES = 168; // 0xa8
     field public static final int ATHEROS_COMMUNICATIONS = 69; // 0x45
     field public static final int ATMEL = 19; // 0x13
+    field public static final int AUSTCO_COMMUNICATION_SYSTEMS = 213; // 0xd5
+    field public static final int AUTONET_MOBILE = 127; // 0x7f
     field public static final int AVAGO = 78; // 0x4e
     field public static final int AVM_BERLIN = 31; // 0x1f
+    field public static final int A_AND_D_ENGINEERING = 105; // 0x69
+    field public static final int A_AND_R_CAMBRIDGE = 124; // 0x7c
     field public static final int BANDSPEED = 32; // 0x20
+    field public static final int BAND_XI_INTERNATIONAL = 100; // 0x64
+    field public static final int BDE_TECHNOLOGY = 180; // 0xb4
+    field public static final int BEATS_ELECTRONICS = 204; // 0xcc
+    field public static final int BEAUTIFUL_ENTERPRISE = 108; // 0x6c
+    field public static final int BEKEY = 178; // 0xb2
     field public static final int BELKIN_INTERNATIONAL = 92; // 0x5c
+    field public static final int BINAURIC = 203; // 0xcb
+    field public static final int BIOSENTRONICS = 219; // 0xdb
     field public static final int BLUEGIGA = 71; // 0x47
+    field public static final int BLUERADIOS = 133; // 0x85
     field public static final int BLUETOOTH_SIG = 63; // 0x3f
+    field public static final int BLUETREK_TECHNOLOGIES = 151; // 0x97
+    field public static final int BOSE = 158; // 0x9e
+    field public static final int BRIARTEK = 109; // 0x6d
     field public static final int BROADCOM = 15; // 0xf
+    field public static final int CAEN_RFID = 170; // 0xaa
     field public static final int CAMBRIDGE_SILICON_RADIO = 10; // 0xa
     field public static final int CATC = 52; // 0x34
+    field public static final int CINETIX = 175; // 0xaf
+    field public static final int CLARINOX_TECHNOLOGIES = 179; // 0xb3
+    field public static final int COLORFY = 156; // 0x9c
     field public static final int COMMIL = 51; // 0x33
     field public static final int CONEXANT_SYSTEMS = 28; // 0x1c
+    field public static final int CONNECTBLUE = 113; // 0x71
     field public static final int CONTINENTAL_AUTOMOTIVE = 75; // 0x4b
     field public static final int CONWISE_TECHNOLOGY = 66; // 0x42
+    field public static final int CREATIVE_TECHNOLOGY = 118; // 0x76
     field public static final int C_TECHNOLOGIES = 38; // 0x26
+    field public static final int DANLERS = 225; // 0xe1
+    field public static final int DELORME_PUBLISHING_COMPANY = 128; // 0x80
+    field public static final int DEXCOM = 208; // 0xd0
+    field public static final int DIALOG_SEMICONDUCTOR = 210; // 0xd2
     field public static final int DIGIANSWER = 12; // 0xc
     field public static final int ECLIPSE = 53; // 0x35
+    field public static final int ECOTEST = 136; // 0x88
+    field public static final int ELGATO_SYSTEMS = 206; // 0xce
     field public static final int EM_MICROELECTRONIC_MARIN = 90; // 0x5a
+    field public static final int EQUINOX_AG = 134; // 0x86
     field public static final int ERICSSON_TECHNOLOGY = 0; // 0x0
+    field public static final int EVLUMA = 201; // 0xc9
     field public static final int FREE2MOVE = 83; // 0x53
+    field public static final int FUNAI_ELECTRIC = 144; // 0x90
+    field public static final int GARMIN_INTERNATIONAL = 135; // 0x87
     field public static final int GCT_SEMICONDUCTOR = 45; // 0x2d
+    field public static final int GELO = 200; // 0xc8
+    field public static final int GENEQ = 194; // 0xc2
+    field public static final int GENERAL_MOTORS = 104; // 0x68
     field public static final int GENNUM = 59; // 0x3b
+    field public static final int GEOFORCE = 157; // 0x9d
+    field public static final int GIBSON_GUITARS = 98; // 0x62
+    field public static final int GN_NETCOM = 103; // 0x67
+    field public static final int GN_RESOUND = 137; // 0x89
+    field public static final int GOOGLE = 224; // 0xe0
+    field public static final int GREEN_THROTTLE_GAMES = 172; // 0xac
+    field public static final int GROUP_SENSE = 115; // 0x73
+    field public static final int HANLYNN_TECHNOLOGIES = 123; // 0x7b
     field public static final int HARMAN_INTERNATIONAL = 87; // 0x57
+    field public static final int HEWLETT_PACKARD = 101; // 0x65
     field public static final int HITACHI = 41; // 0x29
+    field public static final int HOSIDEN = 221; // 0xdd
     field public static final int IBM = 3; // 0x3
     field public static final int INFINEON_TECHNOLOGIES = 9; // 0x9
+    field public static final int INGENIEUR_SYSTEMGRUPPE_ZAHN = 171; // 0xab
     field public static final int INTEGRATED_SILICON_SOLUTION = 65; // 0x41
     field public static final int INTEGRATED_SYSTEM_SOLUTION = 57; // 0x39
     field public static final int INTEL = 2; // 0x2
     field public static final int INVENTEL = 30; // 0x1e
     field public static final int IPEXTREME = 61; // 0x3d
+    field public static final int I_TECH_DYNAMIC_GLOBAL_DISTRIBUTION = 153; // 0x99
+    field public static final int JAWBONE = 138; // 0x8a
+    field public static final int JIANGSU_TOPPOWER_AUTOMOTIVE_ELECTRONICS = 155; // 0x9b
+    field public static final int JOHNSON_CONTROLS = 185; // 0xb9
     field public static final int J_AND_M = 82; // 0x52
+    field public static final int KAWANTECH = 212; // 0xd4
     field public static final int KC_TECHNOLOGY = 22; // 0x16
+    field public static final int KENSINGTON_COMPUTER_PRODUCTS_GROUP = 160; // 0xa0
+    field public static final int LAIRD_TECHNOLOGIES = 119; // 0x77
+    field public static final int LESSWIRE = 121; // 0x79
+    field public static final int LG_ELECTRONICS = 196; // 0xc4
+    field public static final int LINAK = 164; // 0xa4
     field public static final int LUCENT = 7; // 0x7
+    field public static final int LUDUS_HELSINKI = 132; // 0x84
     field public static final int MACRONIX = 44; // 0x2c
+    field public static final int MAGNETI_MARELLI = 169; // 0xa9
     field public static final int MANSELLA = 33; // 0x21
     field public static final int MARVELL = 72; // 0x48
     field public static final int MATSUSHITA_ELECTRIC = 58; // 0x3a
+    field public static final int MC10 = 202; // 0xca
     field public static final int MEDIATEK = 70; // 0x46
+    field public static final int MESO_INTERNATIONAL = 182; // 0xb6
+    field public static final int META_WATCH = 163; // 0xa3
     field public static final int MEWTEL_TECHNOLOGY = 47; // 0x2f
+    field public static final int MICOMMAND = 99; // 0x63
+    field public static final int MICROCHIP_TECHNOLOGY = 205; // 0xcd
     field public static final int MICROSOFT = 6; // 0x6
+    field public static final int MINDTREE = 106; // 0x6a
+    field public static final int MISFIT_WEARABLES = 223; // 0xdf
     field public static final int MITEL_SEMICONDUCTOR = 16; // 0x10
     field public static final int MITSUBISHI_ELECTRIC = 20; // 0x14
     field public static final int MOBILIAN_CORPORATION = 55; // 0x37
+    field public static final int MONSTER = 112; // 0x70
     field public static final int MOTOROLA = 8; // 0x8
+    field public static final int MSTAR_SEMICONDUCTOR = 122; // 0x7a
+    field public static final int MUZIK = 222; // 0xde
     field public static final int NEC = 34; // 0x22
+    field public static final int NEC_LIGHTING = 149; // 0x95
     field public static final int NEWLOGIC = 23; // 0x17
+    field public static final int NIKE = 120; // 0x78
+    field public static final int NINE_SOLUTIONS = 102; // 0x66
     field public static final int NOKIA_MOBILE_PHONES = 1; // 0x1
     field public static final int NORDIC_SEMICONDUCTOR = 89; // 0x59
     field public static final int NORWOOD_SYSTEMS = 46; // 0x2e
+    field public static final int ODM_TECHNOLOGY = 150; // 0x96
+    field public static final int OMEGAWAVE = 174; // 0xae
+    field public static final int ONSET_COMPUTER = 197; // 0xc5
     field public static final int OPEN_INTERFACE = 39; // 0x27
+    field public static final int OTL_DYNAMICS = 165; // 0xa5
+    field public static final int PANDA_OCEAN = 166; // 0xa6
     field public static final int PARROT = 67; // 0x43
     field public static final int PARTHUS_TECHNOLOGIES = 14; // 0xe
+    field public static final int PASSIF_SEMICONDUCTOR = 176; // 0xb0
+    field public static final int PETER_SYSTEMTECHNIK = 173; // 0xad
     field public static final int PHILIPS_SEMICONDUCTORS = 37; // 0x25
     field public static final int PLANTRONICS = 85; // 0x55
+    field public static final int POLAR_ELECTRO = 107; // 0x6b
+    field public static final int POLAR_ELECTRO_EUROPE = 209; // 0xd1
+    field public static final int PROCTER_AND_GAMBLE = 220; // 0xdc
     field public static final int QUALCOMM = 29; // 0x1d
+    field public static final int QUALCOMM_CONNECTED_EXPERIENCES = 216; // 0xd8
+    field public static final int QUALCOMM_INNOVATION_CENTER = 184; // 0xb8
+    field public static final int QUALCOMM_LABS = 140; // 0x8c
+    field public static final int QUALCOMM_TECHNOLOGIES = 215; // 0xd7
+    field public static final int QUINTIC = 142; // 0x8e
+    field public static final int QUUPPA = 199; // 0xc7
     field public static final int RALINK_TECHNOLOGY = 91; // 0x5b
+    field public static final int RDA_MICROELECTRONICS = 97; // 0x61
     field public static final int REALTEK_SEMICONDUCTOR = 93; // 0x5d
     field public static final int RED_M = 50; // 0x32
     field public static final int RENESAS_TECHNOLOGY = 54; // 0x36
@@ -4745,33 +4949,66 @@
     field public static final int RIVIERAWAVES = 96; // 0x60
     field public static final int ROHDE_AND_SCHWARZ = 25; // 0x19
     field public static final int RTX_TELECOM = 21; // 0x15
+    field public static final int SAMSUNG_ELECTRONICS = 117; // 0x75
+    field public static final int SARIS_CYCLING_GROUP = 177; // 0xb1
+    field public static final int SEERS_TECHNOLOGY = 125; // 0x7d
     field public static final int SEIKO_EPSON = 64; // 0x40
+    field public static final int SELFLY = 198; // 0xc6
+    field public static final int SEMILINK = 226; // 0xe2
+    field public static final int SENNHEISER_COMMUNICATIONS = 130; // 0x82
+    field public static final int SHANGHAI_SUPER_SMART_ELECTRONICS = 114; // 0x72
+    field public static final int SHENZHEN_EXCELSECU_DATA_TECHNOLOGY = 193; // 0xc1
     field public static final int SIGNIA_TECHNOLOGIES = 27; // 0x1b
     field public static final int SILICON_WAVE = 11; // 0xb
     field public static final int SIRF_TECHNOLOGY = 80; // 0x50
     field public static final int SOCKET_MOBILE = 68; // 0x44
     field public static final int SONY_ERICSSON = 86; // 0x56
+    field public static final int SOUND_ID = 111; // 0x6f
+    field public static final int SPORTS_TRACKING_TECHNOLOGIES = 126; // 0x7e
+    field public static final int SR_MEDIZINELEKTRONIK = 161; // 0xa1
     field public static final int STACCATO_COMMUNICATIONS = 77; // 0x4d
+    field public static final int STALMART_TECHNOLOGY = 191; // 0xbf
+    field public static final int STARKEY_LABORATORIES = 186; // 0xba
+    field public static final int STOLLMAN_E_PLUS_V = 143; // 0x8f
     field public static final int STONESTREET_ONE = 94; // 0x5e
     field public static final int ST_MICROELECTRONICS = 48; // 0x30
+    field public static final int SUMMIT_DATA_COMMUNICATIONS = 110; // 0x6e
+    field public static final int SUUNTO = 159; // 0x9f
+    field public static final int SWIRL_NETWORKS = 181; // 0xb5
     field public static final int SYMBOL_TECHNOLOGIES = 42; // 0x2a
     field public static final int SYNOPSYS = 49; // 0x31
     field public static final int SYSTEMS_AND_CHIPS = 62; // 0x3e
+    field public static final int S_POWER_ELECTRONICS = 187; // 0xbb
+    field public static final int TAIXINGBANG_TECHNOLOGY = 211; // 0xd3
     field public static final int TENOVIS = 43; // 0x2b
     field public static final int TERAX = 56; // 0x38
     field public static final int TEXAS_INSTRUMENTS = 13; // 0xd
+    field public static final int THINKOPTICS = 146; // 0x92
     field public static final int THREECOM = 5; // 0x5
     field public static final int THREE_DIJOY = 84; // 0x54
     field public static final int THREE_DSP = 73; // 0x49
+    field public static final int TIMEKEEPING_SYSTEMS = 131; // 0x83
+    field public static final int TIMEX_GROUP_USA = 214; // 0xd6
+    field public static final int TOPCORN_POSITIONING_SYSTEMS = 139; // 0x8b
     field public static final int TOSHIBA = 4; // 0x4
     field public static final int TRANSILICA = 24; // 0x18
+    field public static final int TRELAB = 183; // 0xb7
     field public static final int TTPCOM = 26; // 0x1a
+    field public static final int TXTR = 218; // 0xda
     field public static final int TZERO_TECHNOLOGIES = 81; // 0x51
+    field public static final int UNIVERSAL_ELECTRONICS = 147; // 0x93
+    field public static final int VERTU = 162; // 0xa2
+    field public static final int VISTEON = 167; // 0xa7
     field public static final int VIZIO = 88; // 0x58
+    field public static final int VOYETRA_TURTLE_BEACH = 217; // 0xd9
     field public static final int WAVEPLUS_TECHNOLOGY = 35; // 0x23
     field public static final int WICENTRIC = 95; // 0x5f
     field public static final int WIDCOMM = 17; // 0x11
+    field public static final int WUXI_VIMICRO = 129; // 0x81
     field public static final int ZEEVO = 18; // 0x12
+    field public static final int ZER01_TV = 152; // 0x98
+    field public static final int ZOMM = 116; // 0x74
+    field public static final int ZSCAN_SOFTWARE = 141; // 0x8d
   }
 
   public final class BluetoothClass implements android.os.Parcelable {
@@ -4867,6 +5104,7 @@
 
   public final class BluetoothDevice implements android.os.Parcelable {
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
+    method public boolean createBond();
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
@@ -4877,6 +5115,8 @@
     method public java.lang.String getName();
     method public int getType();
     method public android.os.ParcelUuid[] getUuids();
+    method public boolean setPairingConfirmation(boolean);
+    method public boolean setPin(byte[]);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
     field public static final java.lang.String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
@@ -4885,6 +5125,7 @@
     field public static final java.lang.String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
     field public static final java.lang.String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
     field public static final java.lang.String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
+    field public static final java.lang.String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
     field public static final java.lang.String ACTION_UUID = "android.bluetooth.device.action.UUID";
     field public static final int BOND_BONDED = 12; // 0xc
     field public static final int BOND_BONDING = 11; // 0xb
@@ -4899,13 +5140,18 @@
     field public static final java.lang.String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
     field public static final java.lang.String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
     field public static final java.lang.String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
+    field public static final java.lang.String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
+    field public static final java.lang.String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
     field public static final java.lang.String EXTRA_PREVIOUS_BOND_STATE = "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
     field public static final java.lang.String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
     field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+    field public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; // 0x2
+    field public static final int PAIRING_VARIANT_PIN = 0; // 0x0
   }
 
   public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
-    method public void abortReliableWrite(android.bluetooth.BluetoothDevice);
+    method public void abortReliableWrite();
+    method public deprecated void abortReliableWrite(android.bluetooth.BluetoothDevice);
     method public boolean beginReliableWrite();
     method public void close();
     method public boolean connect();
@@ -5066,6 +5312,7 @@
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     method public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
+    method public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, java.lang.String, java.lang.String);
     method public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
     method public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
     field public static final java.lang.String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
@@ -5082,6 +5329,7 @@
     field public static final int STATE_AUDIO_CONNECTED = 12; // 0xc
     field public static final int STATE_AUDIO_CONNECTING = 11; // 0xb
     field public static final int STATE_AUDIO_DISCONNECTED = 10; // 0xa
+    field public static final java.lang.String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
     field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
   }
 
@@ -5376,8 +5624,10 @@
     method public void attachInfo(android.content.Context, android.content.pm.ProviderInfo);
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]);
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
+    method public android.net.Uri canonicalize(android.net.Uri);
     method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final java.lang.String getCallingPackage();
     method public final android.content.Context getContext();
     method public final android.content.pm.PathPermission[] getPathPermissions();
     method public final java.lang.String getReadPermission();
@@ -5391,16 +5641,20 @@
     method public void onLowMemory();
     method public void onTrimMemory(int);
     method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
     method protected final void setPathPermissions(android.content.pm.PathPermission[]);
     method protected final void setReadPermission(java.lang.String);
     method protected final void setWritePermission(java.lang.String);
     method public void shutdown();
+    method public android.net.Uri uncanonicalize(android.net.Uri);
     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
@@ -5412,17 +5666,22 @@
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
+    method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
     method public java.lang.String getType(android.net.Uri) throws android.os.RemoteException;
     method public android.net.Uri insert(android.net.Uri, android.content.ContentValues) throws android.os.RemoteException;
     method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
     method public boolean release();
+    method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
 
@@ -5488,12 +5747,14 @@
     method public final android.os.Bundle call(android.net.Uri, java.lang.String, java.lang.String, android.os.Bundle);
     method public deprecated void cancelSync(android.net.Uri);
     method public static void cancelSync(android.accounts.Account, java.lang.String);
+    method public final android.net.Uri canonicalize(android.net.Uri);
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public static deprecated android.content.SyncInfo getCurrentSync();
     method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
     method public static int getIsSyncable(android.accounts.Account, java.lang.String);
     method public static boolean getMasterSyncAutomatically();
     method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String);
+    method public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
     method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
     method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String);
@@ -5504,21 +5765,28 @@
     method public void notifyChange(android.net.Uri, android.database.ContentObserver);
     method public void notifyChange(android.net.Uri, android.database.ContentObserver, boolean);
     method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public final java.io.InputStream openInputStream(android.net.Uri) throws java.io.FileNotFoundException;
     method public final java.io.OutputStream openOutputStream(android.net.Uri) throws java.io.FileNotFoundException;
     method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
     method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
+    method public void releasePersistableUriPermission(android.net.Uri, int);
     method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public static void removeStatusChangeListener(java.lang.Object);
     method public static void requestSync(android.accounts.Account, java.lang.String, android.os.Bundle);
+    method public static void requestSync(android.content.SyncRequest);
     method public static void setIsSyncable(android.accounts.Account, java.lang.String, int);
     method public static void setMasterSyncAutomatically(boolean);
     method public static void setSyncAutomatically(android.accounts.Account, java.lang.String, boolean);
     method public deprecated void startSync(android.net.Uri, android.os.Bundle);
+    method public void takePersistableUriPermission(android.net.Uri, int);
+    method public final android.net.Uri uncanonicalize(android.net.Uri);
     method public final void unregisterContentObserver(android.database.ContentObserver);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
     method public static void validateSyncExtrasBundle(android.os.Bundle);
@@ -5621,11 +5889,14 @@
     method public abstract java.io.File getDatabasePath(java.lang.String);
     method public abstract java.io.File getDir(java.lang.String, int);
     method public abstract java.io.File getExternalCacheDir();
+    method public abstract java.io.File[] getExternalCacheDirs();
     method public abstract java.io.File getExternalFilesDir(java.lang.String);
+    method public abstract java.io.File[] getExternalFilesDirs(java.lang.String);
     method public abstract java.io.File getFileStreamPath(java.lang.String);
     method public abstract java.io.File getFilesDir();
     method public abstract android.os.Looper getMainLooper();
     method public abstract java.io.File getObbDir();
+    method public abstract java.io.File[] getObbDirs();
     method public abstract java.lang.String getPackageCodePath();
     method public abstract android.content.pm.PackageManager getPackageManager();
     method public abstract java.lang.String getPackageName();
@@ -5687,6 +5958,7 @@
     field public static final java.lang.String ACCOUNT_SERVICE = "account";
     field public static final java.lang.String ACTIVITY_SERVICE = "activity";
     field public static final java.lang.String ALARM_SERVICE = "alarm";
+    field public static final java.lang.String APP_OPS_SERVICE = "appops";
     field public static final java.lang.String AUDIO_SERVICE = "audio";
     field public static final int BIND_ABOVE_CLIENT = 8; // 0x8
     field public static final int BIND_ADJUST_WITH_ACTIVITY = 128; // 0x80
@@ -5697,8 +5969,11 @@
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
     field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
+    field public static final java.lang.String CAMERA_SERVICE = "camera";
+    field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
+    field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
     field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
     field public static final int CONTEXT_RESTRICTED = 4; // 0x4
@@ -5722,6 +5997,7 @@
     field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
     field public static final java.lang.String NSD_SERVICE = "servicediscovery";
     field public static final java.lang.String POWER_SERVICE = "power";
+    field public static final java.lang.String PRINT_SERVICE = "print";
     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";
@@ -5773,11 +6049,14 @@
     method public java.io.File getDatabasePath(java.lang.String);
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
+    method public java.io.File[] getExternalCacheDirs();
     method public java.io.File getExternalFilesDir(java.lang.String);
+    method public java.io.File[] getExternalFilesDirs(java.lang.String);
     method public java.io.File getFileStreamPath(java.lang.String);
     method public java.io.File getFilesDir();
     method public android.os.Looper getMainLooper();
     method public java.io.File getObbDir();
+    method public java.io.File[] getObbDirs();
     method public java.lang.String getPackageCodePath();
     method public android.content.pm.PackageManager getPackageManager();
     method public java.lang.String getPackageName();
@@ -6043,6 +6322,7 @@
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
     field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
+    field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
     field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
     field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
     field public static final java.lang.String ACTION_DEFAULT = "android.intent.action.VIEW";
@@ -6085,6 +6365,7 @@
     field public static final java.lang.String ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED";
     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_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";
@@ -6192,6 +6473,7 @@
     field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT";
     field public static final java.lang.String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
     field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
+    field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
@@ -6206,6 +6488,7 @@
     field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
     field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
@@ -6240,10 +6523,12 @@
     field public static final int FLAG_DEBUG_LOG_RESOLUTION = 8; // 0x8
     field public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 16; // 0x10
     field public static final int FLAG_FROM_BACKGROUND = 4; // 0x4
+    field public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int FLAG_GRANT_READ_URI_PERMISSION = 1; // 0x1
     field public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 2; // 0x2
     field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
     field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
+    field public static final int FLAG_RECEIVER_NO_ABORT = 134217728; // 0x8000000
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -6276,6 +6561,7 @@
     method public final void addDataAuthority(java.lang.String, java.lang.String);
     method public final void addDataPath(java.lang.String, int);
     method public final void addDataScheme(java.lang.String);
+    method public final void addDataSchemeSpecificPart(java.lang.String, int);
     method public final void addDataType(java.lang.String) throws android.content.IntentFilter.MalformedMimeTypeException;
     method public final java.util.Iterator<android.content.IntentFilter.AuthorityEntry> authoritiesIterator();
     method public final java.util.Iterator<java.lang.String> categoriesIterator();
@@ -6283,6 +6569,7 @@
     method public final int countCategories();
     method public final int countDataAuthorities();
     method public final int countDataPaths();
+    method public final int countDataSchemeSpecificParts();
     method public final int countDataSchemes();
     method public final int countDataTypes();
     method public static android.content.IntentFilter create(java.lang.String, java.lang.String);
@@ -6293,6 +6580,7 @@
     method public final android.content.IntentFilter.AuthorityEntry getDataAuthority(int);
     method public final android.os.PatternMatcher getDataPath(int);
     method public final java.lang.String getDataScheme(int);
+    method public final android.os.PatternMatcher getDataSchemeSpecificPart(int);
     method public final java.lang.String getDataType(int);
     method public final int getPriority();
     method public final boolean hasAction(java.lang.String);
@@ -6300,6 +6588,7 @@
     method public final boolean hasDataAuthority(android.net.Uri);
     method public final boolean hasDataPath(java.lang.String);
     method public final boolean hasDataScheme(java.lang.String);
+    method public final boolean hasDataSchemeSpecificPart(java.lang.String);
     method public final boolean hasDataType(java.lang.String);
     method public final int match(android.content.ContentResolver, android.content.Intent, boolean, java.lang.String);
     method public final int match(java.lang.String, java.lang.String, java.lang.String, android.net.Uri, java.util.Set<java.lang.String>, java.lang.String);
@@ -6309,6 +6598,7 @@
     method public final int matchDataAuthority(android.net.Uri);
     method public final java.util.Iterator<android.os.PatternMatcher> pathsIterator();
     method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public final java.util.Iterator<android.os.PatternMatcher> schemeSpecificPartsIterator();
     method public final java.util.Iterator<java.lang.String> schemesIterator();
     method public final void setPriority(int);
     method public final java.util.Iterator<java.lang.String> typesIterator();
@@ -6323,6 +6613,7 @@
     field public static final int MATCH_CATEGORY_PATH = 5242880; // 0x500000
     field public static final int MATCH_CATEGORY_PORT = 4194304; // 0x400000
     field public static final int MATCH_CATEGORY_SCHEME = 2097152; // 0x200000
+    field public static final int MATCH_CATEGORY_SCHEME_SPECIFIC_PART = 5767168; // 0x580000
     field public static final int MATCH_CATEGORY_TYPE = 6291456; // 0x600000
     field public static final int NO_MATCH_ACTION = -3; // 0xfffffffd
     field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
@@ -6555,6 +6846,27 @@
     field public final long startTime;
   }
 
+  public class SyncRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static class SyncRequest.Builder {
+    ctor public SyncRequest.Builder();
+    method public android.content.SyncRequest build();
+    method public android.content.SyncRequest.Builder setDisallowMetered(boolean);
+    method public android.content.SyncRequest.Builder setExpedited(boolean);
+    method public android.content.SyncRequest.Builder setExtras(android.os.Bundle);
+    method public android.content.SyncRequest.Builder setIgnoreBackoff(boolean);
+    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 setSyncAdapter(android.accounts.Account, java.lang.String);
+    method public android.content.SyncRequest.Builder syncOnce();
+    method public android.content.SyncRequest.Builder syncPeriodic(long, long);
+  }
+
   public final class SyncResult implements android.os.Parcelable {
     ctor public SyncResult();
     method public void clear();
@@ -6607,6 +6919,17 @@
     field public static final int NO_MATCH = -1; // 0xffffffff
   }
 
+  public final class UriPermission implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getPersistedTime();
+    method public android.net.Uri getUri();
+    method public boolean isReadPermission();
+    method public boolean isWritePermission();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final long INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
+  }
+
 }
 
 package android.content.pm {
@@ -6744,6 +7067,7 @@
     ctor public ComponentInfo(android.content.pm.ComponentInfo);
     ctor protected ComponentInfo(android.os.Parcel);
     method public final int getIconResource();
+    method public final int getLogoResource();
     method public boolean isEnabled();
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public int descriptionRes;
@@ -6953,6 +7277,7 @@
     field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
+    field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -6964,6 +7289,7 @@
     field public static final java.lang.String FEATURE_LOCATION_NETWORK = "android.hardware.location.network";
     field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
+    field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
@@ -7159,7 +7485,7 @@
 
 package android.content.res {
 
-  public class AssetFileDescriptor implements android.os.Parcelable {
+  public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
     ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long);
     method public void close() throws java.io.IOException;
     method public java.io.FileInputStream createInputStream() throws java.io.IOException;
@@ -7432,7 +7758,7 @@
     method public void recycle();
   }
 
-  public abstract interface XmlResourceParser implements android.util.AttributeSet org.xmlpull.v1.XmlPullParser {
+  public abstract interface XmlResourceParser implements android.util.AttributeSet java.lang.AutoCloseable org.xmlpull.v1.XmlPullParser {
     method public abstract void close();
   }
 
@@ -7572,6 +7898,7 @@
     method public abstract float getFloat(int);
     method public abstract int getInt(int);
     method public abstract long getLong(int);
+    method public abstract android.net.Uri getNotificationUri();
     method public abstract int getPosition();
     method public abstract short getShort(int);
     method public abstract java.lang.String getString(int);
@@ -7677,6 +8004,7 @@
     method public float getFloat(int);
     method public int getInt(int);
     method public long getLong(int);
+    method public android.net.Uri getNotificationUri();
     method public int getPosition();
     method public short getShort(int);
     method public java.lang.String getString(int);
@@ -7824,6 +8152,7 @@
 
   public class MatrixCursor.RowBuilder {
     method public android.database.MatrixCursor.RowBuilder add(java.lang.Object);
+    method public android.database.MatrixCursor.RowBuilder add(java.lang.String, java.lang.Object);
   }
 
   public class MergeCursor extends android.database.AbstractCursor {
@@ -8568,6 +8897,7 @@
     method public void eraseColor(int);
     method public android.graphics.Bitmap extractAlpha();
     method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
+    method public final int getAllocationByteCount();
     method public final int getByteCount();
     method public final android.graphics.Bitmap.Config getConfig();
     method public int getDensity();
@@ -8590,13 +8920,18 @@
     method public final boolean isPremultiplied();
     method public final boolean isRecycled();
     method public void prepareToDraw();
+    method public void reconfigure(int, int, android.graphics.Bitmap.Config);
     method public void recycle();
     method public boolean sameAs(android.graphics.Bitmap);
+    method public void setConfig(android.graphics.Bitmap.Config);
     method public void setDensity(int);
     method public void setHasAlpha(boolean);
     method public final void setHasMipMap(boolean);
+    method public void setHeight(int);
     method public void setPixel(int, int, int);
     method public void setPixels(int[], int, int, int, int, int, int);
+    method public final void setPremultiplied(boolean);
+    method public void setWidth(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DENSITY_NONE = 0; // 0x0
@@ -8645,6 +8980,7 @@
     field public boolean inMutable;
     field public boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
+    field public boolean inPremultiplied;
     field public boolean inPurgeable;
     field public int inSampleSize;
     field public boolean inScaled;
@@ -8903,8 +9239,10 @@
     field public static final int JPEG = 256; // 0x100
     field public static final int NV16 = 16; // 0x10
     field public static final int NV21 = 17; // 0x11
+    field public static final int RAW_SENSOR = 32; // 0x20
     field public static final int RGB_565 = 4; // 0x4
     field public static final int UNKNOWN = 0; // 0x0
+    field public static final int YUV_420_888 = 35; // 0x23
     field public static final int YUY2 = 20; // 0x14
     field public static final int YV12 = 842094169; // 0x32315659
   }
@@ -9032,12 +9370,16 @@
   }
 
   public class NinePatch {
+    ctor public NinePatch(android.graphics.Bitmap, byte[]);
     ctor public NinePatch(android.graphics.Bitmap, byte[], java.lang.String);
     method public void draw(android.graphics.Canvas, android.graphics.RectF);
     method public void draw(android.graphics.Canvas, android.graphics.Rect);
     method public void draw(android.graphics.Canvas, android.graphics.Rect, android.graphics.Paint);
+    method public android.graphics.Bitmap getBitmap();
     method public int getDensity();
     method public int getHeight();
+    method public java.lang.String getName();
+    method public android.graphics.Paint getPaint();
     method public final android.graphics.Region getTransparentRegion(android.graphics.Rect);
     method public int getWidth();
     method public final boolean hasAlpha();
@@ -9138,6 +9480,7 @@
     field public static final int ANTI_ALIAS_FLAG = 1; // 0x1
     field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100
     field public static final int DITHER_FLAG = 4; // 0x4
+    field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400
     field public static final int FAKE_BOLD_TEXT_FLAG = 32; // 0x20
     field public static final int FILTER_BITMAP_FLAG = 2; // 0x2
     field public static final int HINTING_OFF = 0; // 0x0
@@ -9229,6 +9572,8 @@
     method public void moveTo(float, float);
     method public void offset(float, float, android.graphics.Path);
     method public void offset(float, float);
+    method public boolean op(android.graphics.Path, android.graphics.Path.Op);
+    method public boolean op(android.graphics.Path, android.graphics.Path, android.graphics.Path.Op);
     method public void quadTo(float, float, float, float);
     method public void rCubicTo(float, float, float, float, float, float);
     method public void rLineTo(float, float);
@@ -9260,6 +9605,16 @@
     enum_constant public static final android.graphics.Path.FillType WINDING;
   }
 
+  public static final class Path.Op extends java.lang.Enum {
+    method public static android.graphics.Path.Op valueOf(java.lang.String);
+    method public static final android.graphics.Path.Op[] values();
+    enum_constant public static final android.graphics.Path.Op DIFFERENCE;
+    enum_constant public static final android.graphics.Path.Op INTERSECT;
+    enum_constant public static final android.graphics.Path.Op REVERSE_DIFFERENCE;
+    enum_constant public static final android.graphics.Path.Op UNION;
+    enum_constant public static final android.graphics.Path.Op XOR;
+  }
+
   public class PathDashPathEffect extends android.graphics.PathEffect {
     ctor public PathDashPathEffect(android.graphics.Path, float, float, android.graphics.PathDashPathEffect.Style);
   }
@@ -9306,10 +9661,10 @@
     ctor public PixelFormat();
     method public static boolean formatHasAlpha(int);
     method public static void getPixelFormatInfo(int, android.graphics.PixelFormat);
-    field public static final int A_8 = 8; // 0x8
+    field public static final deprecated int A_8 = 8; // 0x8
     field public static final deprecated int JPEG = 256; // 0x100
     field public static final deprecated int LA_88 = 10; // 0xa
-    field public static final int L_8 = 9; // 0x9
+    field public static final deprecated int L_8 = 9; // 0x9
     field public static final int OPAQUE = -1; // 0xffffffff
     field public static final deprecated int RGBA_4444 = 7; // 0x7
     field public static final deprecated int RGBA_5551 = 6; // 0x6
@@ -9567,11 +9922,13 @@
 
   public class SurfaceTexture {
     ctor public SurfaceTexture(int);
+    ctor public SurfaceTexture(int, boolean);
     method public void attachToGLContext(int);
     method public void detachFromGLContext();
     method public long getTimestamp();
     method public void getTransformMatrix(float[]);
     method public void release();
+    method public void releaseTexImage();
     method public void setDefaultBufferSize(int, int);
     method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
     method public void updateTexImage();
@@ -9581,7 +9938,7 @@
     method public abstract void onFrameAvailable(android.graphics.SurfaceTexture);
   }
 
-  public static class SurfaceTexture.OutOfResourcesException extends java.lang.Exception {
+  public static deprecated class SurfaceTexture.OutOfResourcesException extends java.lang.Exception {
     ctor public SurfaceTexture.OutOfResourcesException();
     ctor public SurfaceTexture.OutOfResourcesException(java.lang.String);
   }
@@ -9669,6 +10026,7 @@
     method public android.graphics.Shader.TileMode getTileModeY();
     method public boolean hasAntiAlias();
     method public boolean hasMipMap();
+    method public final boolean isAutoMirrored();
     method public void setAlpha(int);
     method public void setAntiAlias(boolean);
     method public void setColorFilter(android.graphics.ColorFilter);
@@ -9699,7 +10057,6 @@
     ctor public ColorDrawable();
     ctor public ColorDrawable(int);
     method public void draw(android.graphics.Canvas);
-    method public int getAlpha();
     method public int getColor();
     method public int getOpacity();
     method public void setAlpha(int);
@@ -9719,6 +10076,7 @@
     method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public abstract void draw(android.graphics.Canvas);
+    method public int getAlpha();
     method public final android.graphics.Rect getBounds();
     method public android.graphics.drawable.Drawable.Callback getCallback();
     method public int getChangingConfigurations();
@@ -9735,6 +10093,7 @@
     method public android.graphics.Region getTransparentRegion();
     method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void invalidateSelf();
+    method public boolean isAutoMirrored();
     method public boolean isStateful();
     method public final boolean isVisible();
     method public void jumpToCurrentState();
@@ -9745,6 +10104,7 @@
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(java.lang.Runnable, long);
     method public abstract void setAlpha(int);
+    method public void setAutoMirrored(boolean);
     method public void setBounds(int, int, int, int);
     method public void setBounds(android.graphics.Rect);
     method public final void setCallback(android.graphics.drawable.Drawable.Callback);
@@ -9792,6 +10152,7 @@
     method public synchronized boolean canConstantState();
     method protected void computeConstantSize();
     method public int getChangingConfigurations();
+    method public final android.graphics.drawable.Drawable getChild(int);
     method public final int getChildCount();
     method public final android.graphics.drawable.Drawable[] getChildren();
     method public final int getConstantHeight();
@@ -9858,6 +10219,7 @@
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
     method public void draw(android.graphics.Canvas);
+    method public android.graphics.drawable.Drawable getDrawable();
     method public int getOpacity();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10025,6 +10387,37 @@
 
 }
 
+package android.graphics.pdf {
+
+  public class PdfDocument {
+    ctor public PdfDocument();
+    method public void close();
+    method public void finishPage(android.graphics.pdf.PdfDocument.Page);
+    method public java.util.List<android.graphics.pdf.PdfDocument.PageInfo> getPages();
+    method public android.graphics.pdf.PdfDocument.Page startPage(android.graphics.pdf.PdfDocument.PageInfo);
+    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
+  }
+
+  public static final class PdfDocument.Page {
+    method public android.graphics.Canvas getCanvas();
+    method public android.graphics.pdf.PdfDocument.PageInfo getInfo();
+  }
+
+  public static final class PdfDocument.PageInfo {
+    method public android.graphics.Rect getContentRect();
+    method public int getPageHeight();
+    method public int getPageNumber();
+    method public int getPageWidth();
+  }
+
+  public static final class PdfDocument.PageInfo.Builder {
+    ctor public PdfDocument.PageInfo.Builder(int, int, int);
+    method public android.graphics.pdf.PdfDocument.PageInfo create();
+    method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect);
+  }
+
+}
+
 package android.hardware {
 
   public class Camera {
@@ -10279,6 +10672,22 @@
     field public int width;
   }
 
+  public final class ConsumerIrManager {
+    method public android.hardware.ConsumerIrManager.CarrierFrequencyRange[] getCarrierFrequencies();
+    method public boolean hasIrEmitter();
+    method public void transmit(int, int[]);
+  }
+
+  public final class ConsumerIrManager.CarrierFrequencyRange {
+    ctor public ConsumerIrManager.CarrierFrequencyRange(int, int);
+    method public int getMaxFrequency();
+    method public int getMinFrequency();
+  }
+
+  public abstract interface FlushCompleteListener {
+    method public abstract void onFlushCompleted(android.hardware.Sensor);
+  }
+
   public class GeomagneticField {
     ctor public GeomagneticField(float, float, float, long);
     method public float getDeclination();
@@ -10291,6 +10700,8 @@
   }
 
   public final class Sensor {
+    method public int getFifoMaxEventCount();
+    method public int getFifoReservedEventCount();
     method public float getMaximumRange();
     method public int getMinDelay();
     method public java.lang.String getName();
@@ -10303,6 +10714,7 @@
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
     field public static final int TYPE_GAME_ROTATION_VECTOR = 15; // 0xf
+    field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
@@ -10316,6 +10728,8 @@
     field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
     field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
     field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+    field public static final int TYPE_STEP_COUNTER = 19; // 0x13
+    field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
   }
 
@@ -10338,6 +10752,7 @@
 
   public abstract class SensorManager {
     method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+    method public boolean flush(android.hardware.Sensor);
     method public static float getAltitude(float, float);
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
@@ -10351,7 +10766,9 @@
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
+    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, int, android.hardware.FlushCompleteListener);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, android.os.Handler);
+    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, int, android.os.Handler, android.hardware.FlushCompleteListener);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
@@ -10430,15 +10847,419 @@
 
 }
 
+package android.hardware.camera2 {
+
+  public class CameraAccessException extends android.util.AndroidException {
+    ctor public CameraAccessException(int);
+    ctor public CameraAccessException(int, java.lang.String);
+    ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable);
+    ctor public CameraAccessException(int, java.lang.Throwable);
+    method public final int getReason();
+    field public static final int CAMERA_DISABLED = 1; // 0x1
+    field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+    field public static final int CAMERA_ERROR = 3; // 0x3
+  }
+
+  public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
+    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys();
+    method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureResultKeys();
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_STEP;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_EFFECTS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_SCENE_MODES;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MAX_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_INFO_AVAILABLE;
+    field public static final android.hardware.camera2.CameraMetadata.Key INFO_SUPPORTED_HARDWARE_LEVEL;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_AVAILABLE_THUMBNAIL_SIZES;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FACING;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_APERTURES;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_HYPERFOCAL_DISTANCE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_SHADING_MAP_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_MIN_DURATIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_EXPOSURE_TIME_RANGE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_MAX_FRAME_DURATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PHYSICAL_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_SENSITIVITY_RANGE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_MAX_FACE_COUNT;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MAX_CURVE_POINTS;
+  }
+
+  public abstract interface CameraDevice implements java.lang.AutoCloseable {
+    method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void close();
+    method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException;
+    method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void flush() throws android.hardware.camera2.CameraAccessException;
+    method public abstract java.lang.String getId();
+    method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
+    method public abstract void waitUntilIdle() throws android.hardware.camera2.CameraAccessException;
+    field public static final int TEMPLATE_PREVIEW = 1; // 0x1
+    field public static final int TEMPLATE_RECORD = 3; // 0x3
+    field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
+    field public static final int TEMPLATE_VIDEO_SNAPSHOT = 4; // 0x4
+  }
+
+  public static abstract class CameraDevice.CaptureListener {
+    ctor public CameraDevice.CaptureListener();
+    method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+    method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
+    method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, int);
+    method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long);
+  }
+
+  public static abstract class CameraDevice.StateListener {
+    ctor public CameraDevice.StateListener();
+    method public void onActive(android.hardware.camera2.CameraDevice);
+    method public void onBusy(android.hardware.camera2.CameraDevice);
+    method public void onClosed(android.hardware.camera2.CameraDevice);
+    method public abstract void onDisconnected(android.hardware.camera2.CameraDevice);
+    method public abstract void onError(android.hardware.camera2.CameraDevice, int);
+    method public void onIdle(android.hardware.camera2.CameraDevice);
+    method public abstract void onOpened(android.hardware.camera2.CameraDevice);
+    method public void onUnconfigured(android.hardware.camera2.CameraDevice);
+    field public static final int ERROR_CAMERA_DEVICE = 4; // 0x4
+    field public static final int ERROR_CAMERA_DISABLED = 3; // 0x3
+    field public static final int ERROR_CAMERA_IN_USE = 1; // 0x1
+    field public static final int ERROR_CAMERA_SERVICE = 5; // 0x5
+    field public static final int ERROR_MAX_CAMERAS_IN_USE = 2; // 0x2
+  }
+
+  public final class CameraManager {
+    method public void addAvailabilityListener(android.hardware.camera2.CameraManager.AvailabilityListener, android.os.Handler);
+    method public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(java.lang.String) throws android.hardware.camera2.CameraAccessException;
+    method public java.lang.String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
+    method public void openCamera(java.lang.String, android.hardware.camera2.CameraDevice.StateListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public void removeAvailabilityListener(android.hardware.camera2.CameraManager.AvailabilityListener);
+  }
+
+  public static abstract class CameraManager.AvailabilityListener {
+    ctor public CameraManager.AvailabilityListener();
+    method public void onCameraAvailable(java.lang.String);
+    method public void onCameraUnavailable(java.lang.String);
+  }
+
+  public abstract class CameraMetadata {
+    method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getKeys();
+    field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
+    field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
+    field public static final int CONTROL_AE_ANTIBANDING_MODE_50HZ = 1; // 0x1
+    field public static final int CONTROL_AE_ANTIBANDING_MODE_60HZ = 2; // 0x2
+    field public static final int CONTROL_AE_ANTIBANDING_MODE_AUTO = 3; // 0x3
+    field public static final int CONTROL_AE_ANTIBANDING_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_AE_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_AE_MODE_ON = 1; // 0x1
+    field public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3; // 0x3
+    field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2; // 0x2
+    field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4; // 0x4
+    field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0; // 0x0
+    field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1; // 0x1
+    field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
+    field public static final int CONTROL_AE_STATE_FLASH_REQUIRED = 4; // 0x4
+    field public static final int CONTROL_AE_STATE_INACTIVE = 0; // 0x0
+    field public static final int CONTROL_AE_STATE_LOCKED = 3; // 0x3
+    field public static final int CONTROL_AE_STATE_PRECAPTURE = 5; // 0x5
+    field public static final int CONTROL_AE_STATE_SEARCHING = 1; // 0x1
+    field public static final int CONTROL_AF_MODE_AUTO = 1; // 0x1
+    field public static final int CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4; // 0x4
+    field public static final int CONTROL_AF_MODE_CONTINUOUS_VIDEO = 3; // 0x3
+    field public static final int CONTROL_AF_MODE_EDOF = 5; // 0x5
+    field public static final int CONTROL_AF_MODE_MACRO = 2; // 0x2
+    field public static final int CONTROL_AF_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3; // 0x3
+    field public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4; // 0x4
+    field public static final int CONTROL_AF_STATE_INACTIVE = 0; // 0x0
+    field public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5; // 0x5
+    field public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2; // 0x2
+    field public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1; // 0x1
+    field public static final int CONTROL_AF_STATE_PASSIVE_UNFOCUSED = 6; // 0x6
+    field public static final int CONTROL_AF_TRIGGER_CANCEL = 2; // 0x2
+    field public static final int CONTROL_AF_TRIGGER_IDLE = 0; // 0x0
+    field public static final int CONTROL_AF_TRIGGER_START = 1; // 0x1
+    field public static final int CONTROL_AWB_MODE_AUTO = 1; // 0x1
+    field public static final int CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6; // 0x6
+    field public static final int CONTROL_AWB_MODE_DAYLIGHT = 5; // 0x5
+    field public static final int CONTROL_AWB_MODE_FLUORESCENT = 3; // 0x3
+    field public static final int CONTROL_AWB_MODE_INCANDESCENT = 2; // 0x2
+    field public static final int CONTROL_AWB_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_AWB_MODE_SHADE = 8; // 0x8
+    field public static final int CONTROL_AWB_MODE_TWILIGHT = 7; // 0x7
+    field public static final int CONTROL_AWB_MODE_WARM_FLUORESCENT = 4; // 0x4
+    field public static final int CONTROL_AWB_STATE_CONVERGED = 2; // 0x2
+    field public static final int CONTROL_AWB_STATE_INACTIVE = 0; // 0x0
+    field public static final int CONTROL_AWB_STATE_LOCKED = 3; // 0x3
+    field public static final int CONTROL_AWB_STATE_SEARCHING = 1; // 0x1
+    field public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0; // 0x0
+    field public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1; // 0x1
+    field public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2; // 0x2
+    field public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3; // 0x3
+    field public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4; // 0x4
+    field public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5; // 0x5
+    field public static final int CONTROL_EFFECT_MODE_AQUA = 8; // 0x8
+    field public static final int CONTROL_EFFECT_MODE_BLACKBOARD = 7; // 0x7
+    field public static final int CONTROL_EFFECT_MODE_MONO = 1; // 0x1
+    field public static final int CONTROL_EFFECT_MODE_NEGATIVE = 2; // 0x2
+    field public static final int CONTROL_EFFECT_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_EFFECT_MODE_POSTERIZE = 5; // 0x5
+    field public static final int CONTROL_EFFECT_MODE_SEPIA = 4; // 0x4
+    field public static final int CONTROL_EFFECT_MODE_SOLARIZE = 3; // 0x3
+    field public static final int CONTROL_EFFECT_MODE_WHITEBOARD = 6; // 0x6
+    field public static final int CONTROL_MODE_AUTO = 1; // 0x1
+    field public static final int CONTROL_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_MODE_USE_SCENE_MODE = 2; // 0x2
+    field public static final int CONTROL_SCENE_MODE_ACTION = 2; // 0x2
+    field public static final int CONTROL_SCENE_MODE_BARCODE = 16; // 0x10
+    field public static final int CONTROL_SCENE_MODE_BEACH = 8; // 0x8
+    field public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15; // 0xf
+    field public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1; // 0x1
+    field public static final int CONTROL_SCENE_MODE_FIREWORKS = 12; // 0xc
+    field public static final int CONTROL_SCENE_MODE_LANDSCAPE = 4; // 0x4
+    field public static final int CONTROL_SCENE_MODE_NIGHT = 5; // 0x5
+    field public static final int CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6; // 0x6
+    field public static final int CONTROL_SCENE_MODE_PARTY = 14; // 0xe
+    field public static final int CONTROL_SCENE_MODE_PORTRAIT = 3; // 0x3
+    field public static final int CONTROL_SCENE_MODE_SNOW = 9; // 0x9
+    field public static final int CONTROL_SCENE_MODE_SPORTS = 13; // 0xd
+    field public static final int CONTROL_SCENE_MODE_STEADYPHOTO = 11; // 0xb
+    field public static final int CONTROL_SCENE_MODE_SUNSET = 10; // 0xa
+    field public static final int CONTROL_SCENE_MODE_THEATRE = 7; // 0x7
+    field public static final int CONTROL_SCENE_MODE_UNSUPPORTED = 0; // 0x0
+    field public static final int EDGE_MODE_FAST = 1; // 0x1
+    field public static final int EDGE_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int EDGE_MODE_OFF = 0; // 0x0
+    field public static final int FLASH_MODE_OFF = 0; // 0x0
+    field public static final int FLASH_MODE_SINGLE = 1; // 0x1
+    field public static final int FLASH_MODE_TORCH = 2; // 0x2
+    field public static final int FLASH_STATE_CHARGING = 1; // 0x1
+    field public static final int FLASH_STATE_FIRED = 3; // 0x3
+    field public static final int FLASH_STATE_READY = 2; // 0x2
+    field public static final int FLASH_STATE_UNAVAILABLE = 0; // 0x0
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
+    field public static final int LENS_FACING_BACK = 1; // 0x1
+    field public static final int LENS_FACING_FRONT = 0; // 0x0
+    field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0
+    field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
+    field public static final int LENS_STATE_MOVING = 1; // 0x1
+    field public static final int LENS_STATE_STATIONARY = 0; // 0x0
+    field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
+    field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
+    field public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2; // 0x2
+    field public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0; // 0x0
+    field public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1; // 0x1
+    field public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0; // 0x0
+    field public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1; // 0x1
+    field public static final int STATISTICS_SCENE_FLICKER_50HZ = 1; // 0x1
+    field public static final int STATISTICS_SCENE_FLICKER_60HZ = 2; // 0x2
+    field public static final int STATISTICS_SCENE_FLICKER_NONE = 0; // 0x0
+    field public static final int TONEMAP_MODE_CONTRAST_CURVE = 0; // 0x0
+    field public static final int TONEMAP_MODE_FAST = 1; // 0x1
+    field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2
+  }
+
+  public static class CameraMetadata.Key {
+    method public final boolean equals(java.lang.Object);
+    method public final java.lang.String getName();
+    method public final int hashCode();
+  }
+
+  public class CaptureFailure {
+    method public int getFrameNumber();
+    method public int getReason();
+    method public android.hardware.camera2.CaptureRequest getRequest();
+    method public int getSequenceId();
+    method public boolean wasImageCaptured();
+    field public static final int REASON_ERROR = 0; // 0x0
+    field public static final int REASON_FLUSHED = 1; // 0x1
+  }
+
+  public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
+    method public int describeContents();
+    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public java.lang.Object getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
+    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
+    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE;
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_ORIENTATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_QUALITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_QUALITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_APERTURE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FILTER_DENSITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCAL_LENGTH;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_OPTICAL_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
+  }
+
+  public static final class CaptureRequest.Builder {
+    method public void addTarget(android.view.Surface);
+    method public android.hardware.camera2.CaptureRequest build();
+    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public void removeTarget(android.view.Surface);
+    method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
+    method public void setTag(java.lang.Object);
+  }
+
+  public final class CaptureResult extends android.hardware.camera2.CameraMetadata {
+    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public int getFrameNumber();
+    method public android.hardware.camera2.CaptureRequest getRequest();
+    method public int getSequenceId();
+    field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
+    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
+    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_ORIENTATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_QUALITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_QUALITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_APERTURE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FILTER_DENSITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCAL_LENGTH;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_RANGE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_OPTICAL_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_FRAME_COUNT;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_IDS;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_LANDMARKS;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_RECTANGLES;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_SCORES;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_PREDICTED_COLOR_GAINS;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_PREDICTED_COLOR_TRANSFORM;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED;
+    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
+  }
+
+  public final class Face {
+    method public android.graphics.Rect getBounds();
+    method public int getId();
+    method public android.graphics.Point getLeftEyePosition();
+    method public android.graphics.Point getMouthPosition();
+    method public android.graphics.Point getRightEyePosition();
+    method public int getScore();
+    field public static final int ID_UNSUPPORTED = -1; // 0xffffffff
+    field public static final int SCORE_MAX = 100; // 0x64
+    field public static final int SCORE_MIN = 1; // 0x1
+  }
+
+  public final class Rational {
+    ctor public Rational(int, int);
+    method public int getDenominator();
+    method public int getNumerator();
+  }
+
+  public final class Size {
+    ctor public Size(int, int);
+    method public final int getHeight();
+    method public final int getWidth();
+  }
+
+}
+
 package android.hardware.display {
 
   public final class DisplayManager {
+    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, android.view.Surface, int);
     method public android.view.Display getDisplay(int);
     method public android.view.Display[] getDisplays();
     method public android.view.Display[] getDisplays(java.lang.String);
     method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
     method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
     field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+    field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
+    field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
+    field public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 4; // 0x4
   }
 
   public static abstract interface DisplayManager.DisplayListener {
@@ -10447,6 +11268,11 @@
     method public abstract void onDisplayRemoved(int);
   }
 
+  public final class VirtualDisplay {
+    method public android.view.Display getDisplay();
+    method public void release();
+  }
+
 }
 
 package android.hardware.input {
@@ -11154,6 +11980,7 @@
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
     field public static final java.lang.String KEY_PROXIMITY_ENTERING = "entering";
     field public static final java.lang.String KEY_STATUS_CHANGED = "status";
+    field public static final java.lang.String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
     field public static final java.lang.String NETWORK_PROVIDER = "network";
     field public static final java.lang.String PASSIVE_PROVIDER = "passive";
     field public static final java.lang.String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
@@ -11176,6 +12003,19 @@
     field public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
   }
 
+  public abstract class SettingInjectorService extends android.app.Service {
+    ctor public SettingInjectorService(java.lang.String);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected abstract boolean onGetEnabled();
+    method protected abstract java.lang.String onGetSummary();
+    method public final void onStart(android.content.Intent, int);
+    method public final int onStartCommand(android.content.Intent, int, int);
+    field public static final java.lang.String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
+    field public static final java.lang.String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
+    field public static final java.lang.String ATTRIBUTES_NAME = "injected-location-setting";
+    field public static final java.lang.String META_DATA_NAME = "android.location.SettingInjectorService";
+  }
+
 }
 
 package android.media {
@@ -11237,6 +12077,7 @@
     method public void adjustStreamVolume(int, int, int);
     method public void adjustSuggestedStreamVolume(int, int, int);
     method public void adjustVolume(int, int);
+    method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
     method public java.lang.String getProperty(java.lang.String);
@@ -11258,6 +12099,7 @@
     method public void registerMediaButtonEventReceiver(android.content.ComponentName);
     method public void registerMediaButtonEventReceiver(android.app.PendingIntent);
     method public void registerRemoteControlClient(android.media.RemoteControlClient);
+    method public boolean registerRemoteController(android.media.RemoteController);
     method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public deprecated void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
@@ -11279,6 +12121,7 @@
     method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
     method public void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
     method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
+    method public void unregisterRemoteController(android.media.RemoteController);
     field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
@@ -11287,6 +12130,7 @@
     field public static final int ADJUST_SAME = 0; // 0x0
     field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
     field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
     field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
@@ -11308,6 +12152,7 @@
     field public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; // 0x4
     field public static final int FX_FOCUS_NAVIGATION_UP = 1; // 0x1
     field public static final int FX_KEYPRESS_DELETE = 7; // 0x7
+    field public static final int FX_KEYPRESS_INVALID = 9; // 0x9
     field public static final int FX_KEYPRESS_RETURN = 8; // 0x8
     field public static final int FX_KEYPRESS_SPACEBAR = 6; // 0x6
     field public static final int FX_KEYPRESS_STANDARD = 5; // 0x5
@@ -11395,6 +12240,12 @@
     method public abstract void onPeriodicNotification(android.media.AudioRecord);
   }
 
+  public final class AudioTimestamp {
+    ctor public AudioTimestamp();
+    field public long framePosition;
+    field public long nanoTime;
+  }
+
   public class AudioTrack {
     ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
@@ -11407,7 +12258,7 @@
     method public static float getMaxVolume();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
-    method protected int getNativeFrameCount();
+    method protected deprecated int getNativeFrameCount();
     method public static int getNativeOutputSampleRate(int);
     method public int getNotificationMarkerPosition();
     method public int getPlayState();
@@ -11417,6 +12268,7 @@
     method public int getSampleRate();
     method public int getState();
     method public int getStreamType();
+    method public boolean getTimestamp(android.media.AudioTimestamp);
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
     method public void release();
@@ -11429,7 +12281,7 @@
     method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener, android.os.Handler);
     method public int setPlaybackRate(int);
     method public int setPositionNotificationPeriod(int);
-    method protected void setState(int);
+    method protected deprecated void setState(int);
     method public int setStereoVolume(float, float);
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
@@ -11562,6 +12414,38 @@
     field public static final int EULER_Z = 2; // 0x2
   }
 
+  public abstract class Image implements java.lang.AutoCloseable {
+    method public abstract void close();
+    method public abstract int getFormat();
+    method public abstract int getHeight();
+    method public abstract android.media.Image.Plane[] getPlanes();
+    method public abstract long getTimestamp();
+    method public abstract int getWidth();
+  }
+
+  public static abstract class Image.Plane {
+    method public abstract java.nio.ByteBuffer getBuffer();
+    method public abstract int getPixelStride();
+    method public abstract int getRowStride();
+  }
+
+  public class ImageReader implements java.lang.AutoCloseable {
+    method public android.media.Image acquireLatestImage();
+    method public android.media.Image acquireNextImage();
+    method public void close();
+    method public int getHeight();
+    method public int getImageFormat();
+    method public int getMaxImages();
+    method public android.view.Surface getSurface();
+    method public int getWidth();
+    method public static android.media.ImageReader newInstance(int, int, int, int);
+    method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
+  }
+
+  public static abstract interface ImageReader.OnImageAvailableListener {
+    method public abstract void onImageAvailable(android.media.ImageReader);
+  }
+
   public class JetPlayer {
     method public boolean clearQueue();
     method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
@@ -11619,6 +12503,7 @@
     method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
+    method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
     method public final void start();
@@ -11632,6 +12517,9 @@
     field public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
     field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
     field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
+    field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+    field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -11648,6 +12536,9 @@
   public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
     ctor public MediaCodec.CryptoException(int, java.lang.String);
     method public int getErrorCode();
+    field public static final int ERROR_KEY_EXPIRED = 2; // 0x2
+    field public static final int ERROR_NO_KEY = 1; // 0x1
+    field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
   }
 
   public static final class MediaCodec.CryptoInfo {
@@ -11670,6 +12561,7 @@
 
   public static final class MediaCodecInfo.CodecCapabilities {
     ctor public MediaCodecInfo.CodecCapabilities();
+    method public final boolean isFeatureSupported(java.lang.String);
     field public static final int COLOR_Format12bitRGB444 = 3; // 0x3
     field public static final int COLOR_Format16bitARGB1555 = 5; // 0x5
     field public static final int COLOR_Format16bitARGB4444 = 4; // 0x4
@@ -11716,6 +12608,7 @@
     field public static final int COLOR_FormatYUV444Interleaved = 29; // 0x1d
     field public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
+    field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
     field public int[] colorFormats;
     field public android.media.MediaCodecInfo.CodecProfileLevel[] profileLevels;
   }
@@ -11831,6 +12724,7 @@
     method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
     method public java.util.List<byte[]> getSecureStops();
     method public static final boolean isCryptoSchemeSupported(java.util.UUID);
+    method public static final boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String);
     method public byte[] openSession() throws android.media.NotProvisionedException;
     method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException;
     method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException;
@@ -11914,6 +12808,7 @@
     ctor public MediaFormat();
     method public final boolean containsKey(java.lang.String);
     method public static final android.media.MediaFormat createAudioFormat(java.lang.String, int, int);
+    method public static final android.media.MediaFormat createSubtitleFormat(java.lang.String, java.lang.String);
     method public static final android.media.MediaFormat createVideoFormat(java.lang.String, int, int);
     method public final java.nio.ByteBuffer getByteBuffer(java.lang.String);
     method public final float getFloat(java.lang.String);
@@ -11935,13 +12830,40 @@
     field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
     field public static final java.lang.String KEY_HEIGHT = "height";
     field public static final java.lang.String KEY_IS_ADTS = "is-adts";
+    field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
+    field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
+    field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
     field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
+    field public static final java.lang.String KEY_LANGUAGE = "language";
+    field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
     field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
+    field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
     field public static final java.lang.String KEY_MIME = "mime";
+    field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
+    field public static final java.lang.String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
     field public static final java.lang.String KEY_SAMPLE_RATE = "sample-rate";
     field public static final java.lang.String KEY_WIDTH = "width";
   }
 
+  public abstract class MediaMetadataEditor {
+    method public synchronized void addEditableKey(int);
+    method public abstract void apply();
+    method public synchronized void clear();
+    method public synchronized android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized int[] getEditableKeys();
+    method public synchronized long getLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized java.lang.Object getObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public synchronized java.lang.String getString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public synchronized void removeEditableKeys();
+    field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+    field public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
+    field public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
+  }
+
   public class MediaMetadataRetriever {
     ctor public MediaMetadataRetriever();
     method public java.lang.String extractMetadata(int);
@@ -11988,6 +12910,7 @@
     ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
     method public int addTrack(android.media.MediaFormat);
     method public void release();
+    method public void setLocation(float, float);
     method public void setOrientationHint(int);
     method public void start();
     method public void stop();
@@ -12062,7 +12985,9 @@
     field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd
     field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322
     field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321
+    field public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; // 0x386
     field public static final int MEDIA_INFO_UNKNOWN = 1; // 0x1
+    field public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; // 0x385
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
     field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
@@ -12104,6 +13029,7 @@
 
   public static class MediaPlayer.TrackInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.media.MediaFormat getFormat();
     method public java.lang.String getLanguage();
     method public int getTrackType();
     method public void writeToParcel(android.os.Parcel, int);
@@ -12165,6 +13091,7 @@
     field public static final int CAMCORDER = 5; // 0x5
     field public static final int DEFAULT = 0; // 0x0
     field public static final int MIC = 1; // 0x1
+    field public static final int REMOTE_SUBMIX = 8; // 0x8
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
     field public static final int VOICE_DOWNLINK = 3; // 0x3
@@ -12353,10 +13280,34 @@
     ctor public NotProvisionedException(java.lang.String);
   }
 
+  public final class Rating implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getPercentRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.media.Rating newHeartRating(boolean);
+    method public static android.media.Rating newPercentageRating(float);
+    method public static android.media.Rating newStarRating(int, float);
+    method public static android.media.Rating newThumbRating(boolean);
+    method public static android.media.Rating newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
   public class RemoteControlClient {
     ctor public RemoteControlClient(android.app.PendingIntent);
     ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
     method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
+    method public void setMetadataUpdateListener(android.media.RemoteControlClient.OnMetadataUpdateListener);
     method public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener);
     method public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener);
     method public void setPlaybackState(int);
@@ -12369,6 +13320,7 @@
     field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
     field public static final int FLAG_KEY_MEDIA_POSITION_UPDATE = 256; // 0x100
     field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field public static final int FLAG_KEY_MEDIA_RATING = 512; // 0x200
     field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
     field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
     field public static final int PLAYSTATE_BUFFERING = 8; // 0x8
@@ -12382,12 +13334,8 @@
     field public static final int PLAYSTATE_STOPPED = 1; // 0x1
   }
 
-  public class RemoteControlClient.MetadataEditor {
+  public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
     method public synchronized void apply();
-    method public synchronized void clear();
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
     field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
   }
 
@@ -12395,10 +13343,48 @@
     method public abstract long onGetPlaybackPosition();
   }
 
+  public static abstract interface RemoteControlClient.OnMetadataUpdateListener {
+    method public abstract void onMetadataUpdate(int, java.lang.Object);
+  }
+
   public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
     method public abstract void onPlaybackPositionUpdate(long);
   }
 
+  public final class RemoteController {
+    ctor public RemoteController(android.content.Context) throws java.lang.IllegalArgumentException;
+    ctor public RemoteController(android.content.Context, android.os.Looper) throws java.lang.IllegalArgumentException;
+    method public int clearArtworkConfiguration();
+    method public android.media.RemoteController.MetadataEditor editMetadata();
+    method public int seekTo(long);
+    method public int sendMediaKeyEvent(android.view.KeyEvent);
+    method public int setArtworkConfiguration(int, int);
+    method public void setOnClientUpdateListener(android.media.RemoteController.OnClientUpdateListener);
+    method public int setSynchronizationMode(int);
+    field public static final int ERROR = -1; // 0xffffffff
+    field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int POSITION_SYNCHRONIZATION_CHECK = 1; // 0x1
+    field public static final int POSITION_SYNCHRONIZATION_NONE = 0; // 0x0
+    field public static final int SUCCESS = 0; // 0x0
+  }
+
+  public class RemoteController.MetadataEditor extends android.media.MediaMetadataEditor {
+    method public synchronized void apply();
+  }
+
+  public static abstract class RemoteController.OnClientUpdateListener {
+    ctor public RemoteController.OnClientUpdateListener();
+    method public void onClientChange(boolean);
+    method public void onClientMetadataUpdate(android.media.RemoteController.MetadataEditor);
+    method public void onClientPlaybackStateUpdate(int);
+    method public void onClientPlaybackStateUpdate(int, long, long, float);
+    method public void onClientTransportControlUpdate(int);
+  }
+
+  public final class ResourceBusyException extends android.media.MediaDrmException {
+    ctor public ResourceBusyException(java.lang.String);
+  }
+
   public class Ringtone {
     method public int getStreamType();
     method public java.lang.String getTitle(android.content.Context);
@@ -12415,7 +13401,7 @@
     method public android.database.Cursor getCursor();
     method public static int getDefaultType(android.net.Uri);
     method public static android.net.Uri getDefaultUri(int);
-    method public boolean getIncludeDrm();
+    method public deprecated boolean getIncludeDrm();
     method public android.media.Ringtone getRingtone(int);
     method public static android.media.Ringtone getRingtone(android.content.Context, android.net.Uri);
     method public int getRingtonePosition(android.net.Uri);
@@ -12425,14 +13411,14 @@
     method public int inferStreamType();
     method public static boolean isDefault(android.net.Uri);
     method public static void setActualDefaultRingtoneUri(android.content.Context, int, android.net.Uri);
-    method public void setIncludeDrm(boolean);
+    method public deprecated void setIncludeDrm(boolean);
     method public void setStopPreviousRingtone(boolean);
     method public void setType(int);
     method public void stopPreviousRingtone();
     field public static final java.lang.String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
     field public static final java.lang.String EXTRA_RINGTONE_DEFAULT_URI = "android.intent.extra.ringtone.DEFAULT_URI";
     field public static final java.lang.String EXTRA_RINGTONE_EXISTING_URI = "android.intent.extra.ringtone.EXISTING_URI";
-    field public static final java.lang.String EXTRA_RINGTONE_INCLUDE_DRM = "android.intent.extra.ringtone.INCLUDE_DRM";
+    field public static final deprecated java.lang.String EXTRA_RINGTONE_INCLUDE_DRM = "android.intent.extra.ringtone.INCLUDE_DRM";
     field public static final java.lang.String EXTRA_RINGTONE_PICKED_URI = "android.intent.extra.ringtone.PICKED_URI";
     field public static final java.lang.String EXTRA_RINGTONE_SHOW_DEFAULT = "android.intent.extra.ringtone.SHOW_DEFAULT";
     field public static final java.lang.String EXTRA_RINGTONE_SHOW_SILENT = "android.intent.extra.ringtone.SHOW_SILENT";
@@ -12789,6 +13775,12 @@
     field public short numBands;
   }
 
+  public class LoudnessEnhancer extends android.media.audiofx.AudioEffect {
+    method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+    method public void setTargetGain(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+    field public static final int PARAM_TARGET_GAIN_MB = 0; // 0x0
+  }
+
   public class NoiseSuppressor extends android.media.audiofx.AudioEffect {
     method public static android.media.audiofx.NoiseSuppressor create(int);
     method public static boolean isAvailable();
@@ -12850,6 +13842,8 @@
     method public boolean getEnabled();
     method public int getFft(byte[]) throws java.lang.IllegalStateException;
     method public static int getMaxCaptureRate();
+    method public int getMeasurementMode() throws java.lang.IllegalStateException;
+    method public int getMeasurementPeakRms(android.media.audiofx.Visualizer.MeasurementPeakRms);
     method public int getSamplingRate() throws java.lang.IllegalStateException;
     method public int getScalingMode() throws java.lang.IllegalStateException;
     method public int getWaveForm(byte[]) throws java.lang.IllegalStateException;
@@ -12857,6 +13851,7 @@
     method public int setCaptureSize(int) throws java.lang.IllegalStateException;
     method public int setDataCaptureListener(android.media.audiofx.Visualizer.OnDataCaptureListener, int, boolean, boolean);
     method public int setEnabled(boolean) throws java.lang.IllegalStateException;
+    method public int setMeasurementMode(int) throws java.lang.IllegalStateException;
     method public int setScalingMode(int) throws java.lang.IllegalStateException;
     field public static final int ALREADY_EXISTS = -2; // 0xfffffffe
     field public static final int ERROR = -1; // 0xffffffff
@@ -12865,6 +13860,8 @@
     field public static final int ERROR_INVALID_OPERATION = -5; // 0xfffffffb
     field public static final int ERROR_NO_INIT = -3; // 0xfffffffd
     field public static final int ERROR_NO_MEMORY = -6; // 0xfffffffa
+    field public static final int MEASUREMENT_MODE_NONE = 0; // 0x0
+    field public static final int MEASUREMENT_MODE_PEAK_RMS = 1; // 0x1
     field public static final int SCALING_MODE_AS_PLAYED = 1; // 0x1
     field public static final int SCALING_MODE_NORMALIZED = 0; // 0x0
     field public static final int STATE_ENABLED = 2; // 0x2
@@ -12873,6 +13870,12 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
+  public static final class Visualizer.MeasurementPeakRms {
+    ctor public Visualizer.MeasurementPeakRms();
+    field public int mPeak;
+    field public int mRms;
+  }
+
   public static abstract interface Visualizer.OnDataCaptureListener {
     method public abstract void onFftDataCapture(android.media.audiofx.Visualizer, byte[], int);
     method public abstract void onWaveFormDataCapture(android.media.audiofx.Visualizer, byte[], int);
@@ -13129,6 +14132,7 @@
 
   public class LocalSocket implements java.io.Closeable {
     ctor public LocalSocket();
+    ctor public LocalSocket(int);
     method public void bind(android.net.LocalSocketAddress) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public void connect(android.net.LocalSocketAddress) throws java.io.IOException;
@@ -13154,6 +14158,9 @@
     method public void setSoTimeout(int) throws java.io.IOException;
     method public void shutdownInput() throws java.io.IOException;
     method public void shutdownOutput() throws java.io.IOException;
+    field public static final int SOCKET_DGRAM = 1; // 0x1
+    field public static final int SOCKET_SEQPACKET = 3; // 0x3
+    field public static final int SOCKET_STREAM = 2; // 0x2
   }
 
   public class LocalSocketAddress {
@@ -14023,6 +15030,8 @@
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
+    method public void setTdlsEnabled(java.net.InetAddress, boolean);
+    method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
     method public boolean startScan();
     method public int updateNetwork(android.net.wifi.WifiConfiguration);
@@ -14339,8 +15348,10 @@
   public final class NfcAdapter {
     method public void disableForegroundDispatch(android.app.Activity);
     method public deprecated void disableForegroundNdefPush(android.app.Activity);
+    method public void disableReaderMode(android.app.Activity);
     method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][]);
     method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
+    method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
@@ -14356,7 +15367,15 @@
     field public static final java.lang.String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
     field public static final java.lang.String EXTRA_ID = "android.nfc.extra.ID";
     field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
+    field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
     field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
+    field public static final int FLAG_READER_NFC_A = 1; // 0x1
+    field public static final int FLAG_READER_NFC_B = 2; // 0x2
+    field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
+    field public static final int FLAG_READER_NFC_F = 4; // 0x4
+    field public static final int FLAG_READER_NFC_V = 8; // 0x8
+    field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
+    field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80
     field public static final int STATE_OFF = 1; // 0x1
     field public static final int STATE_ON = 3; // 0x3
     field public static final int STATE_TURNING_OFF = 4; // 0x4
@@ -14375,6 +15394,10 @@
     method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
   }
 
+  public static abstract interface NfcAdapter.ReaderCallback {
+    method public abstract void onTagDiscovered(android.nfc.Tag);
+  }
+
   public final class NfcEvent {
     field public final android.nfc.NfcAdapter nfcAdapter;
   }
@@ -14398,6 +15421,45 @@
 
 }
 
+package android.nfc.cardemulation {
+
+  public final class CardEmulation {
+    method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
+    method public int getSelectionModeForCategory(java.lang.String);
+    method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
+    method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
+    field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
+    field public static final java.lang.String CATEGORY_OTHER = "other";
+    field public static final java.lang.String CATEGORY_PAYMENT = "payment";
+    field public static final java.lang.String EXTRA_CATEGORY = "category";
+    field public static final java.lang.String EXTRA_SERVICE_COMPONENT = "component";
+    field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
+    field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
+    field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
+  }
+
+  public abstract class HostApduService extends android.app.Service {
+    ctor public HostApduService();
+    method public final void notifyUnhandled();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onDeactivated(int);
+    method public abstract byte[] processCommandApdu(byte[], android.os.Bundle);
+    method public final void sendResponseApdu(byte[]);
+    field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
+    field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
+  }
+
+  public abstract class OffHostApduService extends android.app.Service {
+    ctor public OffHostApduService();
+    method public abstract android.os.IBinder onBind(android.content.Intent);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service";
+  }
+
+}
+
 package android.nfc.tech {
 
    abstract class BasicTagTechnology implements android.nfc.tech.TagTechnology {
@@ -16613,7 +17675,7 @@
   }
 
   public class Matrix {
-    ctor public Matrix();
+    ctor public deprecated Matrix();
     method public static void frustumM(float[], int, float, float, float, float, float, float);
     method public static boolean invertM(float[], int, float[], int);
     method public static float length(float, float, float);
@@ -16787,6 +17849,7 @@
     field public static final int JELLY_BEAN = 16; // 0x10
     field public static final int JELLY_BEAN_MR1 = 17; // 0x11
     field public static final int JELLY_BEAN_MR2 = 18; // 0x12
+    field public static final int KITKAT = 10000; // 0x2710
   }
 
   public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -16998,13 +18061,12 @@
   public static class Debug.MemoryInfo implements android.os.Parcelable {
     ctor public Debug.MemoryInfo();
     method public int describeContents();
-    method public static java.lang.String getOtherLabel(int);
-    method public int getOtherPrivateDirty(int);
-    method public int getOtherPss(int);
-    method public int getOtherSharedDirty(int);
+    method public int getTotalPrivateClean();
     method public int getTotalPrivateDirty();
     method public int getTotalPss();
+    method public int getTotalSharedClean();
     method public int getTotalSharedDirty();
+    method public int getTotalSwappablePss();
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -17059,10 +18121,12 @@
     method public static java.io.File getExternalStoragePublicDirectory(java.lang.String);
     method public static java.lang.String getExternalStorageState();
     method public static java.io.File getRootDirectory();
+    method public static java.lang.String getStorageState(java.io.File);
     method public static boolean isExternalStorageEmulated();
     method public static boolean isExternalStorageRemovable();
     field public static java.lang.String DIRECTORY_ALARMS;
     field public static java.lang.String DIRECTORY_DCIM;
+    field public static java.lang.String DIRECTORY_DOCUMENTS;
     field public static java.lang.String DIRECTORY_DOWNLOADS;
     field public static java.lang.String DIRECTORY_MOVIES;
     field public static java.lang.String DIRECTORY_MUSIC;
@@ -17077,6 +18141,7 @@
     field public static final java.lang.String MEDIA_NOFS = "nofs";
     field public static final java.lang.String MEDIA_REMOVED = "removed";
     field public static final java.lang.String MEDIA_SHARED = "shared";
+    field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
     field public static final java.lang.String MEDIA_UNMOUNTABLE = "unmountable";
     field public static final java.lang.String MEDIA_UNMOUNTED = "unmounted";
   }
@@ -17373,8 +18438,14 @@
   public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable {
     ctor public ParcelFileDescriptor(android.os.ParcelFileDescriptor);
     method public static android.os.ParcelFileDescriptor adoptFd(int);
+    method public boolean canDetectErrors();
+    method public void checkError() throws java.io.IOException;
     method public void close() throws java.io.IOException;
+    method public void closeWithError(java.lang.String) throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor[] createPipe() throws java.io.IOException;
+    method public static android.os.ParcelFileDescriptor[] createReliablePipe() throws java.io.IOException;
+    method public static android.os.ParcelFileDescriptor[] createReliableSocketPair() throws java.io.IOException;
+    method public static android.os.ParcelFileDescriptor[] createSocketPair() throws java.io.IOException;
     method public int describeContents();
     method public int detachFd();
     method public static android.os.ParcelFileDescriptor dup(java.io.FileDescriptor) throws java.io.IOException;
@@ -17386,6 +18457,8 @@
     method public java.io.FileDescriptor getFileDescriptor();
     method public long getStatSize();
     method public static android.os.ParcelFileDescriptor open(java.io.File, int) throws java.io.FileNotFoundException;
+    method public static android.os.ParcelFileDescriptor open(java.io.File, int, android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
+    method public static int parseMode(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int MODE_APPEND = 33554432; // 0x2000000
@@ -17393,8 +18466,8 @@
     field public static final int MODE_READ_ONLY = 268435456; // 0x10000000
     field public static final int MODE_READ_WRITE = 805306368; // 0x30000000
     field public static final int MODE_TRUNCATE = 67108864; // 0x4000000
-    field public static final int MODE_WORLD_READABLE = 1; // 0x1
-    field public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
+    field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
+    field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
     field public static final int MODE_WRITE_ONLY = 536870912; // 0x20000000
   }
 
@@ -17406,6 +18479,14 @@
     ctor public ParcelFileDescriptor.AutoCloseOutputStream(android.os.ParcelFileDescriptor);
   }
 
+  public static class ParcelFileDescriptor.FileDescriptorDetachedException extends java.io.IOException {
+    ctor public ParcelFileDescriptor.FileDescriptorDetachedException();
+  }
+
+  public static abstract interface ParcelFileDescriptor.OnCloseListener {
+    method public abstract void onClose(java.io.IOException);
+  }
+
   public class ParcelFormatException extends java.lang.RuntimeException {
     ctor public ParcelFormatException();
     ctor public ParcelFormatException(java.lang.String);
@@ -17672,6 +18753,7 @@
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
+    method public boolean setRestrictionsChallenge(java.lang.String);
     method public void setUserRestriction(java.lang.String, boolean);
     method public void setUserRestrictions(android.os.Bundle);
     method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
@@ -17858,6 +18940,7 @@
     method protected android.view.View onCreateView(android.view.ViewGroup);
     method public void onDependencyChanged(android.preference.Preference, boolean);
     method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
+    method public void onParentChanged(android.preference.Preference, boolean);
     method protected void onPrepareForRemoval();
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -17921,6 +19004,7 @@
     method public boolean hasHeaders();
     method public void invalidateHeaders();
     method public boolean isMultiPane();
+    method protected boolean isValidFragment(java.lang.String);
     method public void loadHeadersFromResource(int, java.util.List<android.preference.PreferenceActivity.Header>);
     method public void onBuildHeaders(java.util.List<android.preference.PreferenceActivity.Header>);
     method public android.content.Intent onBuildStartFragmentIntent(java.lang.String, android.os.Bundle, int, int);
@@ -18096,15 +19180,384 @@
 
 }
 
+package android.print {
+
+  public final class PageRange implements android.os.Parcelable {
+    ctor public PageRange(int, int);
+    method public int describeContents();
+    method public int getEnd();
+    method public int getStart();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.print.PageRange ALL_PAGES;
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class PrintAttributes implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getColorMode();
+    method public android.print.PrintAttributes.MediaSize getMediaSize();
+    method public android.print.PrintAttributes.Margins getMinMargins();
+    method public android.print.PrintAttributes.Resolution getResolution();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int COLOR_MODE_COLOR = 2; // 0x2
+    field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class PrintAttributes.Builder {
+    ctor public PrintAttributes.Builder();
+    method public android.print.PrintAttributes build();
+    method public android.print.PrintAttributes.Builder setColorMode(int);
+    method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
+    method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
+    method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
+  }
+
+  public static final class PrintAttributes.Margins {
+    ctor public PrintAttributes.Margins(int, int, int, int);
+    method public int getBottomMils();
+    method public int getLeftMils();
+    method public int getRightMils();
+    method public int getTopMils();
+    field public static final android.print.PrintAttributes.Margins NO_MARGINS;
+  }
+
+  public static final class PrintAttributes.MediaSize {
+    ctor public PrintAttributes.MediaSize(java.lang.String, java.lang.String, int, int);
+    method public android.print.PrintAttributes.MediaSize asLandscape();
+    method public android.print.PrintAttributes.MediaSize asPortrait();
+    method public int getHeightMils();
+    method public java.lang.String getId();
+    method public java.lang.String getLabel(android.content.pm.PackageManager);
+    method public int getWidthMils();
+    method public boolean isPortrait();
+    field public static final android.print.PrintAttributes.MediaSize ISO_A0;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A1;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A10;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A2;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A3;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A4;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A5;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A6;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A7;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A8;
+    field public static final android.print.PrintAttributes.MediaSize ISO_A9;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B0;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B1;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B10;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B2;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B3;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B4;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B5;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B6;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B7;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B8;
+    field public static final android.print.PrintAttributes.MediaSize ISO_B9;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C0;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C1;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C10;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C2;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C3;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C4;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C5;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C6;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C7;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C8;
+    field public static final android.print.PrintAttributes.MediaSize ISO_C9;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B0;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B1;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B10;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B2;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B3;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B4;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B5;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B6;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B7;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B8;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B9;
+    field public static final android.print.PrintAttributes.MediaSize JIS_EXEC;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU2;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU3;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU4;
+    field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI;
+    field public static final android.print.PrintAttributes.MediaSize JPN_KAHU;
+    field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2;
+    field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU;
+    field public static final android.print.PrintAttributes.MediaSize JPN_YOU4;
+    field public static final android.print.PrintAttributes.MediaSize NA_FOOLSCAP;
+    field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_3X5;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_4X6;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_5X8;
+    field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL;
+    field public static final android.print.PrintAttributes.MediaSize NA_LEDGER;
+    field public static final android.print.PrintAttributes.MediaSize NA_LEGAL;
+    field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
+    field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
+    field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
+    field public static final android.print.PrintAttributes.MediaSize NA_TABLOID;
+    field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
+    field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
+    field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
+    field public static final android.print.PrintAttributes.MediaSize PRC_1;
+    field public static final android.print.PrintAttributes.MediaSize PRC_10;
+    field public static final android.print.PrintAttributes.MediaSize PRC_16k;
+    field public static final android.print.PrintAttributes.MediaSize PRC_2;
+    field public static final android.print.PrintAttributes.MediaSize PRC_3;
+    field public static final android.print.PrintAttributes.MediaSize PRC_4;
+    field public static final android.print.PrintAttributes.MediaSize PRC_5;
+    field public static final android.print.PrintAttributes.MediaSize PRC_6;
+    field public static final android.print.PrintAttributes.MediaSize PRC_7;
+    field public static final android.print.PrintAttributes.MediaSize PRC_8;
+    field public static final android.print.PrintAttributes.MediaSize PRC_9;
+    field public static final android.print.PrintAttributes.MediaSize ROC_16K;
+    field public static final android.print.PrintAttributes.MediaSize ROC_8K;
+    field public static final android.print.PrintAttributes.MediaSize UNKNOWN_LANDSCAPE;
+    field public static final android.print.PrintAttributes.MediaSize UNKNOWN_PORTRAIT;
+  }
+
+  public static final class PrintAttributes.Resolution {
+    ctor public PrintAttributes.Resolution(java.lang.String, java.lang.String, int, int);
+    method public int getHorizontalDpi();
+    method public java.lang.String getId();
+    method public java.lang.String getLabel();
+    method public int getVerticalDpi();
+  }
+
+  public abstract class PrintDocumentAdapter {
+    ctor public PrintDocumentAdapter();
+    method public void onFinish();
+    method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
+    method public void onStart();
+    method public abstract void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
+    field public static final java.lang.String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
+  }
+
+  public static abstract class PrintDocumentAdapter.LayoutResultCallback {
+    method public void onLayoutCancelled();
+    method public void onLayoutFailed(java.lang.CharSequence);
+    method public void onLayoutFinished(android.print.PrintDocumentInfo, boolean);
+  }
+
+  public static abstract class PrintDocumentAdapter.WriteResultCallback {
+    method public void onWriteCancelled();
+    method public void onWriteFailed(java.lang.CharSequence);
+    method public void onWriteFinished(android.print.PageRange[]);
+  }
+
+  public final class PrintDocumentInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getContentType();
+    method public long getDataSize();
+    method public java.lang.String getName();
+    method public int getPageCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CONTENT_TYPE_DOCUMENT = 0; // 0x0
+    field public static final int CONTENT_TYPE_PHOTO = 1; // 0x1
+    field public static final int CONTENT_TYPE_UNKNOWN = -1; // 0xffffffff
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff
+  }
+
+  public static final class PrintDocumentInfo.Builder {
+    ctor public PrintDocumentInfo.Builder(java.lang.String);
+    method public android.print.PrintDocumentInfo build();
+    method public android.print.PrintDocumentInfo.Builder setContentType(int);
+    method public android.print.PrintDocumentInfo.Builder setPageCount(int);
+  }
+
+  public class PrintFileDocumentAdapter extends android.print.PrintDocumentAdapter {
+    ctor public PrintFileDocumentAdapter(android.content.Context, java.io.File, android.print.PrintDocumentInfo);
+    method public void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
+    method public void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
+  }
+
+  public final class PrintJob {
+    method public void cancel();
+    method public android.print.PrintJobId getId();
+    method public android.print.PrintJobInfo getInfo();
+    method public boolean isBlocked();
+    method public boolean isCancelled();
+    method public boolean isCompleted();
+    method public boolean isFailed();
+    method public boolean isQueued();
+    method public boolean isStarted();
+    method public void restart();
+  }
+
+  public final class PrintJobId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class PrintJobInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.print.PrintAttributes getAttributes();
+    method public int getCopies();
+    method public long getCreationTime();
+    method public android.print.PrintJobId getId();
+    method public java.lang.String getLabel();
+    method public android.print.PageRange[] getPages();
+    method public android.print.PrinterId getPrinterId();
+    method public int getState();
+    method public java.lang.String getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int PRINT_JOB_ID_UNDEFINED = -1; // 0xffffffff
+    field public static final int STATE_BLOCKED = 4; // 0x4
+    field public static final int STATE_CANCELED = 7; // 0x7
+    field public static final int STATE_COMPLETED = 5; // 0x5
+    field public static final int STATE_CREATED = 1; // 0x1
+    field public static final int STATE_FAILED = 6; // 0x6
+    field public static final int STATE_QUEUED = 2; // 0x2
+    field public static final int STATE_STARTED = 3; // 0x3
+  }
+
+  public final class PrintManager {
+    method public java.util.List<android.print.PrintJob> getPrintJobs();
+    method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
+  }
+
+  public final class PrinterCapabilitiesInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getColorModes();
+    method public android.print.PrintAttributes getDefaults();
+    method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
+    method public android.print.PrintAttributes.Margins getMinMargins();
+    method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class PrinterCapabilitiesInfo.Builder {
+    ctor public PrinterCapabilitiesInfo.Builder(android.print.PrinterId);
+    method public android.print.PrinterCapabilitiesInfo.Builder addMediaSize(android.print.PrintAttributes.MediaSize, boolean);
+    method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
+    method public android.print.PrinterCapabilitiesInfo build();
+    method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
+    method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
+  }
+
+  public final class PrinterId implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getLocalId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class PrinterInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.print.PrinterCapabilitiesInfo getCapabilities();
+    method public java.lang.String getDescription();
+    method public android.print.PrinterId getId();
+    method public java.lang.String getName();
+    method public int getStatus();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int STATUS_BUSY = 2; // 0x2
+    field public static final int STATUS_IDLE = 1; // 0x1
+    field public static final int STATUS_UNAVAILABLE = 3; // 0x3
+  }
+
+  public static final class PrinterInfo.Builder {
+    ctor public PrinterInfo.Builder(android.print.PrinterId, java.lang.String, int);
+    ctor public PrinterInfo.Builder(android.print.PrinterInfo);
+    method public android.print.PrinterInfo build();
+    method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
+    method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+    method public android.print.PrinterInfo.Builder setName(java.lang.String);
+    method public android.print.PrinterInfo.Builder setStatus(int);
+  }
+
+}
+
+package android.print.pdf {
+
+  public class PrintedPdfDocument extends android.graphics.pdf.PdfDocument {
+    ctor public PrintedPdfDocument(android.content.Context, android.print.PrintAttributes);
+    method public android.graphics.Rect getPageContentRect();
+    method public int getPageHeight();
+    method public int getPageWidth();
+    method public android.graphics.pdf.PdfDocument.Page startPage(int);
+  }
+
+}
+
+package android.printservice {
+
+  public final class PrintDocument {
+    method public android.os.ParcelFileDescriptor getData();
+    method public android.print.PrintDocumentInfo getInfo();
+  }
+
+  public final class PrintJob {
+    method public boolean block(java.lang.String);
+    method public boolean cancel();
+    method public boolean complete();
+    method public boolean fail(java.lang.String);
+    method public android.printservice.PrintDocument getDocument();
+    method public android.print.PrintJobId getId();
+    method public android.print.PrintJobInfo getInfo();
+    method public boolean isBlocked();
+    method public boolean isCancelled();
+    method public boolean isCompleted();
+    method public boolean isFailed();
+    method public boolean isQueued();
+    method public boolean isStarted();
+    method public boolean setTag(java.lang.String);
+    method public boolean start();
+  }
+
+  public abstract class PrintService extends android.app.Service {
+    ctor public PrintService();
+    method protected final void attachBaseContext(android.content.Context);
+    method public final android.print.PrinterId generatePrinterId(java.lang.String);
+    method public final java.util.List<android.printservice.PrintJob> getActivePrintJobs();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected void onConnected();
+    method protected abstract android.printservice.PrinterDiscoverySession onCreatePrinterDiscoverySession();
+    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 SERVICE_INTERFACE = "android.printservice.PrintService";
+    field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
+  }
+
+  public abstract class PrinterDiscoverySession {
+    ctor public PrinterDiscoverySession();
+    method public final void addPrinters(java.util.List<android.print.PrinterInfo>);
+    method public final java.util.List<android.print.PrinterInfo> getPrinters();
+    method public final java.util.List<android.print.PrinterId> getTrackedPrinters();
+    method public final boolean isDestroyed();
+    method public final boolean isPrinterDiscoveryStarted();
+    method public abstract void onDestroy();
+    method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
+    method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
+    method public abstract void onStopPrinterDiscovery();
+    method public abstract void onStopPrinterStateTracking(android.print.PrinterId);
+    method public abstract void onValidatePrinters(java.util.List<android.print.PrinterId>);
+    method public final void removePrinters(java.util.List<android.print.PrinterId>);
+  }
+
+}
+
 package android.provider {
 
   public final class AlarmClock {
     ctor public AlarmClock();
     field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
+    field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
+    field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
+    field public static final java.lang.String EXTRA_DAYS = "android.intent.extra.alarm.DAYS";
     field public static final java.lang.String EXTRA_HOUR = "android.intent.extra.alarm.HOUR";
+    field public static final java.lang.String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH";
     field public static final java.lang.String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
     field public static final java.lang.String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES";
+    field public static final java.lang.String EXTRA_RINGTONE = "android.intent.extra.alarm.RINGTONE";
     field public static final java.lang.String EXTRA_SKIP_UI = "android.intent.extra.alarm.SKIP_UI";
+    field public static final java.lang.String EXTRA_VIBRATE = "android.intent.extra.alarm.VIBRATE";
+    field public static final java.lang.String VALUE_RINGTONE_SILENT = "silent";
   }
 
   public abstract interface BaseColumns {
@@ -18474,8 +19927,13 @@
     field public static final int MISSED_TYPE = 3; // 0x3
     field public static final java.lang.String NEW = "new";
     field public static final java.lang.String NUMBER = "number";
+    field public static final java.lang.String NUMBER_PRESENTATION = "presentation";
     field public static final java.lang.String OFFSET_PARAM_KEY = "offset";
     field public static final int OUTGOING_TYPE = 2; // 0x2
+    field public static final int PRESENTATION_ALLOWED = 1; // 0x1
+    field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
+    field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
+    field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
     field public static final java.lang.String TYPE = "type";
   }
 
@@ -19512,6 +20970,80 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
+  public final class DocumentsContract {
+    method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
+    method public static android.net.Uri buildDocumentUri(java.lang.String, 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 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 boolean isDocumentUri(android.content.Context, android.net.Uri);
+    field public static final java.lang.String EXTRA_ERROR = "error";
+    field public static final java.lang.String EXTRA_INFO = "info";
+    field public static final java.lang.String EXTRA_LOADING = "loading";
+  }
+
+  public static final class DocumentsContract.Document {
+    field public static final java.lang.String COLUMN_DISPLAY_NAME = "_display_name";
+    field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
+    field public static final java.lang.String COLUMN_FLAGS = "flags";
+    field public static final java.lang.String COLUMN_ICON = "icon";
+    field public static final java.lang.String COLUMN_LAST_MODIFIED = "last_modified";
+    field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
+    field public static final java.lang.String COLUMN_SIZE = "_size";
+    field public static final java.lang.String COLUMN_SUMMARY = "summary";
+    field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
+    field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
+    field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
+    field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
+    field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
+    field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
+    field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
+  }
+
+  public static final class DocumentsContract.Root {
+    field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
+    field public static final java.lang.String COLUMN_FLAGS = "flags";
+    field public static final java.lang.String COLUMN_ICON = "icon";
+    field public static final java.lang.String COLUMN_MIME_TYPES = "mime_types";
+    field public static final java.lang.String COLUMN_ROOT_ID = "root_id";
+    field public static final java.lang.String COLUMN_SUMMARY = "summary";
+    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_RECENTS = 4; // 0x4
+    field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
+  }
+
+  public abstract class DocumentsProvider extends android.content.ContentProvider {
+    ctor public DocumentsProvider();
+    method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+    method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
+    method public final java.lang.String getType(android.net.Uri);
+    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public abstract android.os.ParcelFileDescriptor openDocument(java.lang.String, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openDocumentThumbnail(java.lang.String, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public abstract android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], java.lang.String) throws java.io.FileNotFoundException;
+    method public abstract android.database.Cursor queryDocument(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
+    method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+  }
+
   public final deprecated class LiveFolders implements android.provider.BaseColumns {
     field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
     field public static final java.lang.String DESCRIPTION = "description";
@@ -19863,6 +21395,7 @@
     field public static final java.lang.String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
     field public static final java.lang.String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
     field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
+    field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
@@ -19878,7 +21411,9 @@
     field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
     field public static final java.lang.String ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS";
     field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
+    field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
     field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+    field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
     field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
@@ -19970,12 +21505,12 @@
     method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
     method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
     method public static android.net.Uri getUriFor(java.lang.String);
-    method public static final boolean isLocationProviderEnabled(android.content.ContentResolver, java.lang.String);
+    method public static final deprecated boolean isLocationProviderEnabled(android.content.ContentResolver, java.lang.String);
     method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
     method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
     method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
-    method public static final void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
+    method public static final deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
     field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
     field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
     field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
@@ -19994,7 +21529,12 @@
     field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
     field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
     field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-    field public static final java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
+    field public static final java.lang.String LOCATION_MODE = "location_mode";
+    field public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
+    field public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
+    field public static final int LOCATION_MODE_OFF = 0; // 0x0
+    field public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
+    field public static final deprecated java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
     field public static final java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
     field public static final deprecated java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
     field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
@@ -20196,6 +21736,277 @@
     method public static void update(android.content.ContentProviderClient, android.net.Uri, byte[]) throws android.os.RemoteException;
   }
 
+  public final class Telephony {
+  }
+
+  public static abstract interface Telephony.BaseMmsColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String CONTENT_CLASS = "ct_cls";
+    field public static final java.lang.String CONTENT_LOCATION = "ct_l";
+    field public static final java.lang.String CONTENT_TYPE = "ct_t";
+    field public static final java.lang.String DATE = "date";
+    field public static final java.lang.String DATE_SENT = "date_sent";
+    field public static final java.lang.String DELIVERY_REPORT = "d_rpt";
+    field public static final java.lang.String DELIVERY_TIME = "d_tm";
+    field public static final java.lang.String EXPIRY = "exp";
+    field public static final java.lang.String LOCKED = "locked";
+    field public static final java.lang.String MESSAGE_BOX = "msg_box";
+    field public static final int MESSAGE_BOX_ALL = 0; // 0x0
+    field public static final int MESSAGE_BOX_DRAFTS = 3; // 0x3
+    field public static final int MESSAGE_BOX_INBOX = 1; // 0x1
+    field public static final int MESSAGE_BOX_OUTBOX = 4; // 0x4
+    field public static final int MESSAGE_BOX_SENT = 2; // 0x2
+    field public static final java.lang.String MESSAGE_CLASS = "m_cls";
+    field public static final java.lang.String MESSAGE_ID = "m_id";
+    field public static final java.lang.String MESSAGE_SIZE = "m_size";
+    field public static final java.lang.String MESSAGE_TYPE = "m_type";
+    field public static final java.lang.String MMS_VERSION = "v";
+    field public static final java.lang.String PRIORITY = "pri";
+    field public static final java.lang.String READ = "read";
+    field public static final java.lang.String READ_REPORT = "rr";
+    field public static final java.lang.String READ_STATUS = "read_status";
+    field public static final java.lang.String REPORT_ALLOWED = "rpt_a";
+    field public static final java.lang.String RESPONSE_STATUS = "resp_st";
+    field public static final java.lang.String RESPONSE_TEXT = "resp_txt";
+    field public static final java.lang.String RETRIEVE_STATUS = "retr_st";
+    field public static final java.lang.String RETRIEVE_TEXT = "retr_txt";
+    field public static final java.lang.String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
+    field public static final java.lang.String SEEN = "seen";
+    field public static final java.lang.String STATUS = "st";
+    field public static final java.lang.String SUBJECT = "sub";
+    field public static final java.lang.String SUBJECT_CHARSET = "sub_cs";
+    field public static final java.lang.String TEXT_ONLY = "text_only";
+    field public static final java.lang.String THREAD_ID = "thread_id";
+    field public static final java.lang.String TRANSACTION_ID = "tr_id";
+  }
+
+  public static abstract interface Telephony.CanonicalAddressesColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String ADDRESS = "address";
+  }
+
+  public static final class Telephony.Carriers implements android.provider.BaseColumns {
+    field public static final java.lang.String APN = "apn";
+    field public static final java.lang.String AUTH_TYPE = "authtype";
+    field public static final java.lang.String BEARER = "bearer";
+    field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String CURRENT = "current";
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
+    field public static final java.lang.String MCC = "mcc";
+    field public static final java.lang.String MMSC = "mmsc";
+    field public static final java.lang.String MMSPORT = "mmsport";
+    field public static final java.lang.String MMSPROXY = "mmsproxy";
+    field public static final java.lang.String MNC = "mnc";
+    field public static final java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
+    field public static final java.lang.String MVNO_TYPE = "mvno_type";
+    field public static final java.lang.String NAME = "name";
+    field public static final java.lang.String NUMERIC = "numeric";
+    field public static final java.lang.String PASSWORD = "password";
+    field public static final java.lang.String PORT = "port";
+    field public static final java.lang.String PROTOCOL = "protocol";
+    field public static final java.lang.String PROXY = "proxy";
+    field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
+    field public static final java.lang.String SERVER = "server";
+    field public static final java.lang.String TYPE = "type";
+    field public static final java.lang.String USER = "user";
+  }
+
+  public static final class Telephony.Mms implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final android.net.Uri REPORT_REQUEST_URI;
+    field public static final android.net.Uri REPORT_STATUS_URI;
+  }
+
+  public static final class Telephony.Mms.Addr implements android.provider.BaseColumns {
+    field public static final java.lang.String ADDRESS = "address";
+    field public static final java.lang.String CHARSET = "charset";
+    field public static final java.lang.String CONTACT_ID = "contact_id";
+    field public static final java.lang.String MSG_ID = "msg_id";
+    field public static final java.lang.String TYPE = "type";
+  }
+
+  public static final class Telephony.Mms.Draft implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Mms.Inbox implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Mms.Intents {
+    field public static final java.lang.String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED";
+    field public static final java.lang.String DELETED_CONTENTS = "deleted_contents";
+  }
+
+  public static final class Telephony.Mms.Outbox implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Mms.Part implements android.provider.BaseColumns {
+    field public static final java.lang.String CHARSET = "chset";
+    field public static final java.lang.String CONTENT_DISPOSITION = "cd";
+    field public static final java.lang.String CONTENT_ID = "cid";
+    field public static final java.lang.String CONTENT_LOCATION = "cl";
+    field public static final java.lang.String CONTENT_TYPE = "ct";
+    field public static final java.lang.String CT_START = "ctt_s";
+    field public static final java.lang.String CT_TYPE = "ctt_t";
+    field public static final java.lang.String FILENAME = "fn";
+    field public static final java.lang.String MSG_ID = "mid";
+    field public static final java.lang.String NAME = "name";
+    field public static final java.lang.String SEQ = "seq";
+    field public static final java.lang.String TEXT = "text";
+    field public static final java.lang.String _DATA = "_data";
+  }
+
+  public static final class Telephony.Mms.Rate {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String SENT_TIME = "sent_time";
+  }
+
+  public static final class Telephony.Mms.Sent implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.MmsSms implements android.provider.BaseColumns {
+    field public static final android.net.Uri CONTENT_CONVERSATIONS_URI;
+    field public static final android.net.Uri CONTENT_DRAFT_URI;
+    field public static final android.net.Uri CONTENT_FILTER_BYPHONE_URI;
+    field public static final android.net.Uri CONTENT_LOCKED_URI;
+    field public static final android.net.Uri CONTENT_UNDELIVERED_URI;
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final int ERR_TYPE_GENERIC = 1; // 0x1
+    field public static final int ERR_TYPE_GENERIC_PERMANENT = 10; // 0xa
+    field public static final int ERR_TYPE_MMS_PROTO_PERMANENT = 12; // 0xc
+    field public static final int ERR_TYPE_MMS_PROTO_TRANSIENT = 3; // 0x3
+    field public static final int ERR_TYPE_SMS_PROTO_PERMANENT = 11; // 0xb
+    field public static final int ERR_TYPE_SMS_PROTO_TRANSIENT = 2; // 0x2
+    field public static final int ERR_TYPE_TRANSPORT_FAILURE = 4; // 0x4
+    field public static final int MMS_PROTO = 1; // 0x1
+    field public static final int NO_ERROR = 0; // 0x0
+    field public static final android.net.Uri SEARCH_URI;
+    field public static final int SMS_PROTO = 0; // 0x0
+    field public static final java.lang.String TYPE_DISCRIMINATOR_COLUMN = "transport_type";
+  }
+
+  public static final class Telephony.MmsSms.PendingMessages implements android.provider.BaseColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DUE_TIME = "due_time";
+    field public static final java.lang.String ERROR_CODE = "err_code";
+    field public static final java.lang.String ERROR_TYPE = "err_type";
+    field public static final java.lang.String LAST_TRY = "last_try";
+    field public static final java.lang.String MSG_ID = "msg_id";
+    field public static final java.lang.String MSG_TYPE = "msg_type";
+    field public static final java.lang.String PROTO_TYPE = "proto_type";
+    field public static final java.lang.String RETRY_INDEX = "retry_index";
+  }
+
+  public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    method public static java.lang.String getDefaultSmsPackage(android.content.Context);
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Conversations implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final java.lang.String MESSAGE_COUNT = "msg_count";
+    field public static final java.lang.String SNIPPET = "snippet";
+  }
+
+  public static final class Telephony.Sms.Draft implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Inbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Intents {
+    method public static android.telephony.SmsMessage[] getMessagesFromIntent(android.content.Intent);
+    field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
+    field public static final java.lang.String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+    field public static final int RESULT_SMS_DUPLICATED = 5; // 0x5
+    field public static final int RESULT_SMS_GENERIC_ERROR = 2; // 0x2
+    field public static final int RESULT_SMS_HANDLED = 1; // 0x1
+    field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
+    field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
+    field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+    field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
+    field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
+    field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
+    field public static final java.lang.String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
+    field public static final java.lang.String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED";
+    field public static final java.lang.String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
+    field public static final java.lang.String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER";
+    field public static final java.lang.String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
+  }
+
+  public static final class Telephony.Sms.Outbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Sent implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static abstract interface Telephony.TextBasedSmsColumns {
+    field public static final java.lang.String ADDRESS = "address";
+    field public static final java.lang.String BODY = "body";
+    field public static final java.lang.String DATE = "date";
+    field public static final java.lang.String DATE_SENT = "date_sent";
+    field public static final java.lang.String ERROR_CODE = "error_code";
+    field public static final java.lang.String LOCKED = "locked";
+    field public static final int MESSAGE_TYPE_ALL = 0; // 0x0
+    field public static final int MESSAGE_TYPE_DRAFT = 3; // 0x3
+    field public static final int MESSAGE_TYPE_FAILED = 5; // 0x5
+    field public static final int MESSAGE_TYPE_INBOX = 1; // 0x1
+    field public static final int MESSAGE_TYPE_OUTBOX = 4; // 0x4
+    field public static final int MESSAGE_TYPE_QUEUED = 6; // 0x6
+    field public static final int MESSAGE_TYPE_SENT = 2; // 0x2
+    field public static final java.lang.String PERSON = "person";
+    field public static final java.lang.String PROTOCOL = "protocol";
+    field public static final java.lang.String READ = "read";
+    field public static final java.lang.String REPLY_PATH_PRESENT = "reply_path_present";
+    field public static final java.lang.String SEEN = "seen";
+    field public static final java.lang.String SERVICE_CENTER = "service_center";
+    field public static final java.lang.String STATUS = "status";
+    field public static final int STATUS_COMPLETE = 0; // 0x0
+    field public static final int STATUS_FAILED = 64; // 0x40
+    field public static final int STATUS_NONE = -1; // 0xffffffff
+    field public static final int STATUS_PENDING = 32; // 0x20
+    field public static final java.lang.String SUBJECT = "subject";
+    field public static final java.lang.String THREAD_ID = "thread_id";
+    field public static final java.lang.String TYPE = "type";
+  }
+
+  public static final class Telephony.Threads implements android.provider.Telephony.ThreadsColumns {
+    field public static final int BROADCAST_THREAD = 1; // 0x1
+    field public static final int COMMON_THREAD = 0; // 0x0
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final android.net.Uri OBSOLETE_THREADS_URI;
+  }
+
+  public static abstract interface Telephony.ThreadsColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String DATE = "date";
+    field public static final java.lang.String ERROR = "error";
+    field public static final java.lang.String HAS_ATTACHMENT = "has_attachment";
+    field public static final java.lang.String MESSAGE_COUNT = "message_count";
+    field public static final java.lang.String READ = "read";
+    field public static final java.lang.String RECIPIENT_IDS = "recipient_ids";
+    field public static final java.lang.String SNIPPET = "snippet";
+    field public static final java.lang.String SNIPPET_CHARSET = "snippet_cs";
+    field public static final java.lang.String TYPE = "type";
+  }
+
   public class UserDictionary {
     ctor public UserDictionary();
     field public static final java.lang.String AUTHORITY = "user_dictionary";
@@ -20325,6 +22136,7 @@
     method public deprecated synchronized void resize(int);
     method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
     method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
+    method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener);
     method public void setSurface(android.view.Surface);
     method public void syncAll(int);
     field public static final int USAGE_GRAPHICS_CONSTANTS = 8; // 0x8
@@ -20345,6 +22157,10 @@
     enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_ON_SYNC_TO_TEXTURE;
   }
 
+  public static abstract interface Allocation.OnBufferAvailableListener {
+    method public abstract void onBufferAvailable(android.renderscript.Allocation);
+  }
+
   public class AllocationAdapter extends android.renderscript.Allocation {
     method public static android.renderscript.AllocationAdapter create1D(android.renderscript.RenderScript, android.renderscript.Allocation);
     method public static android.renderscript.AllocationAdapter create2D(android.renderscript.RenderScript, android.renderscript.Allocation);
@@ -20471,6 +22287,7 @@
     method public static android.renderscript.Element U8_2(android.renderscript.RenderScript);
     method public static android.renderscript.Element U8_3(android.renderscript.RenderScript);
     method public static android.renderscript.Element U8_4(android.renderscript.RenderScript);
+    method public static android.renderscript.Element YUV(android.renderscript.RenderScript);
     method public static android.renderscript.Element createPixel(android.renderscript.RenderScript, android.renderscript.Element.DataType, android.renderscript.Element.DataKind);
     method public static android.renderscript.Element createVector(android.renderscript.RenderScript, android.renderscript.Element.DataType, int);
     method public int getBytesSize();
@@ -20994,9 +22811,12 @@
   }
 
   public final class ScriptIntrinsicColorMatrix extends android.renderscript.ScriptIntrinsic {
-    method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element);
+    method public static deprecated android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element);
+    method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript);
     method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation);
     method public android.renderscript.Script.KernelID getKernelID();
+    method public void setAdd(android.renderscript.Float4);
+    method public void setAdd(float, float, float, float);
     method public void setColorMatrix(android.renderscript.Matrix4f);
     method public void setColorMatrix(android.renderscript.Matrix3f);
     method public void setGreyscale();
@@ -21022,6 +22842,16 @@
     method public void setInput(android.renderscript.Allocation);
   }
 
+  public final class ScriptIntrinsicHistogram extends android.renderscript.ScriptIntrinsic {
+    method public static android.renderscript.ScriptIntrinsicHistogram create(android.renderscript.RenderScript, android.renderscript.Element);
+    method public void forEach(android.renderscript.Allocation);
+    method public void forEach_Dot(android.renderscript.Allocation);
+    method public android.renderscript.Script.FieldID getFieldID_Input();
+    method public android.renderscript.Script.KernelID getKernelID_Separate();
+    method public void setDotCoefficients(float, float, float, float);
+    method public void setOutput(android.renderscript.Allocation);
+  }
+
   public final class ScriptIntrinsicLUT extends android.renderscript.ScriptIntrinsic {
     method public static android.renderscript.ScriptIntrinsicLUT create(android.renderscript.RenderScript, android.renderscript.Element);
     method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation);
@@ -21170,8 +23000,11 @@
   }
 
   public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
     method public android.content.Context getContext();
     method public java.util.Date getEndDate();
+    method public int getKeySize();
+    method public java.lang.String getKeyType();
     method public java.lang.String getKeystoreAlias();
     method public java.math.BigInteger getSerialNumber();
     method public java.util.Date getStartDate();
@@ -21182,9 +23015,12 @@
   public static final class KeyPairGeneratorSpec.Builder {
     ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
     method public android.security.KeyPairGeneratorSpec build();
+    method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
     method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
     method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
     method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
     method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
@@ -21456,6 +23292,7 @@
 
   public final class SynthesisRequest {
     ctor public SynthesisRequest(java.lang.String, android.os.Bundle);
+    method public int getCallerUid();
     method public java.lang.String getCountry();
     method public java.lang.String getLanguage();
     method public android.os.Bundle getParams();
@@ -22475,11 +24312,14 @@
     method public java.io.File getDatabasePath(java.lang.String);
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
+    method public java.io.File[] getExternalCacheDirs();
     method public java.io.File getExternalFilesDir(java.lang.String);
+    method public java.io.File[] getExternalFilesDirs(java.lang.String);
     method public java.io.File getFileStreamPath(java.lang.String);
     method public java.io.File getFilesDir();
     method public android.os.Looper getMainLooper();
     method public java.io.File getObbDir();
+    method public java.io.File[] getObbDirs();
     method public java.lang.String getPackageCodePath();
     method public android.content.pm.PackageManager getPackageManager();
     method public java.lang.String getPackageName();
@@ -22546,6 +24386,7 @@
     method public float getFloat(int);
     method public int getInt(int);
     method public long getLong(int);
+    method public android.net.Uri getNotificationUri();
     method public int getPosition();
     method public short getShort(int);
     method public java.lang.String getString(int);
@@ -23539,7 +25380,9 @@
     method public static void clearMetaKeyState(android.text.Editable, int);
     method public long clearMetaKeyState(long, int);
     method public static final int getMetaState(java.lang.CharSequence);
+    method public static final int getMetaState(java.lang.CharSequence, android.view.KeyEvent);
     method public static final int getMetaState(java.lang.CharSequence, int);
+    method public static final int getMetaState(java.lang.CharSequence, int, android.view.KeyEvent);
     method public static final int getMetaState(long);
     method public static final int getMetaState(long, int);
     method public static long handleKeyDown(long, int, android.view.KeyEvent);
@@ -24089,6 +25932,125 @@
 
 }
 
+package android.transition {
+
+  public class AutoTransition extends android.transition.TransitionSet {
+    ctor public AutoTransition();
+  }
+
+  public class ChangeBounds extends android.transition.Transition {
+    ctor public ChangeBounds();
+    method public void captureEndValues(android.transition.TransitionValues);
+    method public void captureStartValues(android.transition.TransitionValues);
+    method public void setReparent(boolean);
+    method public void setResizeClip(boolean);
+  }
+
+  public class Fade extends android.transition.Visibility {
+    ctor public Fade();
+    ctor public Fade(int);
+    field public static final int IN = 1; // 0x1
+    field public static final int OUT = 2; // 0x2
+  }
+
+  public final class Scene {
+    ctor public Scene(android.view.ViewGroup);
+    ctor public Scene(android.view.ViewGroup, android.view.ViewGroup);
+    method public void enter();
+    method public void exit();
+    method public static android.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
+    method public android.view.ViewGroup getSceneRoot();
+    method public void setEnterAction(java.lang.Runnable);
+    method public void setExitAction(java.lang.Runnable);
+  }
+
+  public abstract class Transition implements java.lang.Cloneable {
+    ctor public Transition();
+    method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
+    method public android.transition.Transition addTarget(int);
+    method public android.transition.Transition addTarget(android.view.View);
+    method public abstract void captureEndValues(android.transition.TransitionValues);
+    method public abstract void captureStartValues(android.transition.TransitionValues);
+    method public android.transition.Transition clone();
+    method public android.animation.Animator createAnimator(android.view.ViewGroup, android.transition.TransitionValues, android.transition.TransitionValues);
+    method public android.transition.Transition excludeChildren(int, boolean);
+    method public android.transition.Transition excludeChildren(android.view.View, boolean);
+    method public android.transition.Transition excludeChildren(java.lang.Class, boolean);
+    method public android.transition.Transition excludeTarget(int, boolean);
+    method public android.transition.Transition excludeTarget(android.view.View, boolean);
+    method public android.transition.Transition excludeTarget(java.lang.Class, boolean);
+    method public long getDuration();
+    method public android.animation.TimeInterpolator getInterpolator();
+    method public java.lang.String getName();
+    method public long getStartDelay();
+    method public java.util.List<java.lang.Integer> getTargetIds();
+    method public java.util.List<android.view.View> getTargets();
+    method public java.lang.String[] getTransitionProperties();
+    method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean);
+    method public android.transition.Transition removeListener(android.transition.Transition.TransitionListener);
+    method public android.transition.Transition removeTarget(int);
+    method public android.transition.Transition removeTarget(android.view.View);
+    method public android.transition.Transition setDuration(long);
+    method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
+    method public android.transition.Transition setStartDelay(long);
+  }
+
+  public static abstract interface Transition.TransitionListener {
+    method public abstract void onTransitionCancel(android.transition.Transition);
+    method public abstract void onTransitionEnd(android.transition.Transition);
+    method public abstract void onTransitionPause(android.transition.Transition);
+    method public abstract void onTransitionResume(android.transition.Transition);
+    method public abstract void onTransitionStart(android.transition.Transition);
+  }
+
+  public class TransitionInflater {
+    method public static android.transition.TransitionInflater from(android.content.Context);
+    method public android.transition.Transition inflateTransition(int);
+    method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
+  }
+
+  public class TransitionManager {
+    ctor public TransitionManager();
+    method public static void beginDelayedTransition(android.view.ViewGroup);
+    method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
+    method public static android.transition.Transition getDefaultTransition();
+    method public static void go(android.transition.Scene);
+    method public static void go(android.transition.Scene, android.transition.Transition);
+    method public void setDefaultTransition(android.transition.Transition);
+    method public void setTransition(android.transition.Scene, android.transition.Transition);
+    method public void setTransition(android.transition.Scene, android.transition.Scene, android.transition.Transition);
+    method public void transitionTo(android.transition.Scene);
+  }
+
+  public class TransitionSet extends android.transition.Transition {
+    ctor public TransitionSet();
+    method public android.transition.TransitionSet addTransition(android.transition.Transition);
+    method public void captureEndValues(android.transition.TransitionValues);
+    method public void captureStartValues(android.transition.TransitionValues);
+    method public int getOrdering();
+    method public android.transition.TransitionSet removeTransition(android.transition.Transition);
+    method public android.transition.TransitionSet setOrdering(int);
+    field public static final int ORDERING_SEQUENTIAL = 1; // 0x1
+    field public static final int ORDERING_TOGETHER = 0; // 0x0
+  }
+
+  public class TransitionValues {
+    ctor public TransitionValues();
+    field public final java.util.Map values;
+    field public android.view.View view;
+  }
+
+  public abstract class Visibility extends android.transition.Transition {
+    ctor public Visibility();
+    method public void captureEndValues(android.transition.TransitionValues);
+    method public void captureStartValues(android.transition.TransitionValues);
+    method public boolean isVisible(android.transition.TransitionValues);
+    method public android.animation.Animator onAppear(android.view.ViewGroup, android.transition.TransitionValues, int, android.transition.TransitionValues, int);
+    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.transition.TransitionValues, int, android.transition.TransitionValues, int);
+  }
+
+}
+
 package android.util {
 
   public class AndroidException extends java.lang.Exception {
@@ -24105,6 +26067,33 @@
     ctor public AndroidRuntimeException(java.lang.Exception);
   }
 
+  public final class ArrayMap implements java.util.Map {
+    ctor public ArrayMap();
+    ctor public ArrayMap(int);
+    ctor public ArrayMap(android.util.ArrayMap);
+    method public void clear();
+    method public boolean containsAll(java.util.Collection<?>);
+    method public boolean containsKey(java.lang.Object);
+    method public boolean containsValue(java.lang.Object);
+    method public void ensureCapacity(int);
+    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public V get(java.lang.Object);
+    method public boolean isEmpty();
+    method public K keyAt(int);
+    method public java.util.Set<K> keySet();
+    method public V put(K, V);
+    method public void putAll(android.util.ArrayMap<? extends K, ? extends V>);
+    method public void putAll(java.util.Map<? extends K, ? extends V>);
+    method public V remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public V removeAt(int);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public V setValueAt(int, V);
+    method public int size();
+    method public V valueAt(int);
+    method public java.util.Collection<V> values();
+  }
+
   public class AtomicFile {
     ctor public AtomicFile(java.io.File);
     method public void delete();
@@ -24300,6 +26289,13 @@
     method public android.util.JsonWriter value(java.lang.Number) throws java.io.IOException;
   }
 
+  public final class LayoutDirection {
+    field public static final int INHERIT = 2; // 0x2
+    field public static final int LOCALE = 3; // 0x3
+    field public static final int LTR = 0; // 0x0
+    field public static final int RTL = 1; // 0x1
+  }
+
   public final class Log {
     method public static int d(java.lang.String, java.lang.String);
     method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
@@ -24458,6 +26454,7 @@
     method public void put(int, E);
     method public void remove(int);
     method public void removeAt(int);
+    method public void removeAtRange(int, int);
     method public void setValueAt(int, E);
     method public int size();
     method public E valueAt(int);
@@ -24741,6 +26738,8 @@
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
+    field public static final int FLAG_PRESENTATION = 8; // 0x8
+    field public static final int FLAG_PRIVATE = 4; // 0x4
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
   }
@@ -24868,6 +26867,7 @@
 
   public final class InputDevice implements android.os.Parcelable {
     method public int describeContents();
+    method public int getControllerNumber();
     method public java.lang.String getDescriptor();
     method public static android.view.InputDevice getDevice(int);
     method public static int[] getDeviceIds();
@@ -24878,8 +26878,11 @@
     method public android.view.InputDevice.MotionRange getMotionRange(int, int);
     method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
     method public java.lang.String getName();
+    method public int getProductId();
     method public int getSources();
+    method public int getVendorId();
     method public android.os.Vibrator getVibrator();
+    method public boolean[] hasKeys(int...);
     method public boolean isVirtual();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -25195,6 +27198,7 @@
     field public static final int KEYCODE_LEFT_BRACKET = 71; // 0x47
     field public static final int KEYCODE_M = 41; // 0x29
     field public static final int KEYCODE_MANNER_MODE = 205; // 0xcd
+    field public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222; // 0xde
     field public static final int KEYCODE_MEDIA_CLOSE = 128; // 0x80
     field public static final int KEYCODE_MEDIA_EJECT = 129; // 0x81
     field public static final int KEYCODE_MEDIA_FAST_FORWARD = 90; // 0x5a
@@ -25467,6 +27471,7 @@
   }
 
   public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable {
+    method public static java.lang.String actionToString(int);
     method public final void addBatch(long, float, float, float, float, int);
     method public final void addBatch(long, android.view.MotionEvent.PointerCoords[], int);
     method public static int axisFromString(java.lang.String);
@@ -25683,6 +27688,7 @@
 
   public class ScaleGestureDetector {
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
+    ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler);
     method public float getCurrentSpan();
     method public float getCurrentSpanX();
     method public float getCurrentSpanY();
@@ -25695,7 +27701,9 @@
     method public float getScaleFactor();
     method public long getTimeDelta();
     method public boolean isInProgress();
+    method public boolean isQuickScaleEnabled();
     method public boolean onTouchEvent(android.view.MotionEvent);
+    method public void setQuickScaleEnabled(boolean);
   }
 
   public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
@@ -25749,7 +27757,7 @@
     field public static final int ROTATION_90 = 1; // 0x1
   }
 
-  public static class Surface.OutOfResourcesException extends java.lang.Exception {
+  public static class Surface.OutOfResourcesException extends java.lang.RuntimeException {
     ctor public Surface.OutOfResourcesException();
     ctor public Surface.OutOfResourcesException(java.lang.String);
   }
@@ -25871,9 +27879,13 @@
     method public void buildDrawingCache(boolean);
     method public void buildLayer();
     method public boolean callOnClick();
+    method public boolean canResolveLayoutDirection();
+    method public boolean canResolveTextAlignment();
+    method public boolean canResolveTextDirection();
     method public boolean canScrollHorizontally(int);
     method public boolean canScrollVertically(int);
     method public void cancelLongPress();
+    method public final void cancelPendingInputEvents();
     method public boolean checkInputConnectionProxy(android.view.View);
     method public void clearAnimation();
     method public void clearFocus();
@@ -25923,6 +27935,7 @@
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
+    method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
@@ -26056,6 +28069,7 @@
     method public void invalidate();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public boolean isActivated();
+    method public boolean isAttachedToWindow();
     method public boolean isClickable();
     method public boolean isDirty();
     method public boolean isDrawingCacheEnabled();
@@ -26072,6 +28086,8 @@
     method public boolean isInEditMode();
     method public boolean isInLayout();
     method public boolean isInTouchMode();
+    method public boolean isLaidOut();
+    method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
     method public boolean isLongClickable();
     method public boolean isOpaque();
@@ -26085,6 +28101,8 @@
     method public boolean isSelected();
     method public boolean isShown();
     method public boolean isSoundEffectsEnabled();
+    method public boolean isTextAlignmentResolved();
+    method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
@@ -26096,6 +28114,7 @@
     method protected void onAnimationEnd();
     method protected void onAnimationStart();
     method protected void onAttachedToWindow();
+    method public void onCancelPendingInputEvents();
     method public boolean onCheckIsTextEditor();
     method protected void onConfigurationChanged(android.content.res.Configuration);
     method protected void onCreateContextMenu(android.view.ContextMenu);
@@ -26178,6 +28197,7 @@
     method public void sendAccessibilityEvent(int);
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
     method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
+    method public void setAccessibilityLiveRegion(int);
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
@@ -26283,6 +28303,9 @@
     method protected boolean verifyDrawable(android.graphics.drawable.Drawable);
     method public boolean willNotCacheDrawing();
     method public boolean willNotDraw();
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property ALPHA;
     field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
     field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
@@ -26346,6 +28369,7 @@
     field protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET;
     field protected static final int[] PRESSED_SELECTED_STATE_SET;
     field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
+    field protected static final int[] PRESSED_STATE_SET;
     field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET;
     field public static final android.util.Property ROTATION;
     field public static final android.util.Property ROTATION_X;
@@ -26368,10 +28392,13 @@
     field public static final deprecated int STATUS_BAR_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_FLAG_FULLSCREEN = 4; // 0x4
     field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
+    field public static final int SYSTEM_UI_FLAG_IMMERSIVE = 2048; // 0x800
     field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
     field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
     field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
+    field public static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 8192; // 0x2000
+    field public static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 4096; // 0x1000
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
     field public static final int TEXT_ALIGNMENT_CENTER = 4; // 0x4
@@ -26588,6 +28615,7 @@
     method protected boolean canAnimate();
     method protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams);
     method public void childDrawableStateChanged(android.view.View);
+    method public void childHasTransientStateChanged(android.view.View, boolean);
     method protected void cleanupLayoutState(android.view.View);
     method public void clearChildFocus(android.view.View);
     method public void clearDisappearingChildren();
@@ -26634,6 +28662,7 @@
     method protected void measureChild(android.view.View, int, int);
     method protected void measureChildWithMargins(android.view.View, int, int, int, int);
     method protected void measureChildren(int, int);
+    method public void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public final void offsetDescendantRectToMyCoords(android.view.View, android.graphics.Rect);
     method public final void offsetRectIntoDescendantCoords(android.view.View, android.graphics.Rect);
     method public boolean onInterceptHoverEvent(android.view.MotionEvent);
@@ -26748,17 +28777,28 @@
 
   public abstract interface ViewParent {
     method public abstract void bringChildToFront(android.view.View);
+    method public abstract boolean canResolveLayoutDirection();
+    method public abstract boolean canResolveTextAlignment();
+    method public abstract boolean canResolveTextDirection();
     method public abstract void childDrawableStateChanged(android.view.View);
+    method public abstract void childHasTransientStateChanged(android.view.View, boolean);
     method public abstract void clearChildFocus(android.view.View);
     method public abstract void createContextMenu(android.view.ContextMenu);
     method public abstract android.view.View focusSearch(android.view.View, int);
     method public abstract void focusableViewAvailable(android.view.View);
     method public abstract boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
+    method public abstract int getLayoutDirection();
     method public abstract android.view.ViewParent getParent();
     method public abstract android.view.ViewParent getParentForAccessibility();
+    method public abstract int getTextAlignment();
+    method public abstract int getTextDirection();
     method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
     method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+    method public abstract boolean isLayoutDirectionResolved();
     method public abstract boolean isLayoutRequested();
+    method public abstract boolean isTextAlignmentResolved();
+    method public abstract boolean isTextDirectionResolved();
+    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract void recomputeViewAttributes(android.view.View);
     method public abstract void requestChildFocus(android.view.View, android.view.View);
     method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
@@ -26792,6 +28832,7 @@
     method public android.view.ViewPropertyAnimator setInterpolator(android.animation.TimeInterpolator);
     method public android.view.ViewPropertyAnimator setListener(android.animation.Animator.AnimatorListener);
     method public android.view.ViewPropertyAnimator setStartDelay(long);
+    method public android.view.ViewPropertyAnimator setUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
     method public void start();
     method public android.view.ViewPropertyAnimator translationX(float);
     method public android.view.ViewPropertyAnimator translationXBy(float);
@@ -26906,6 +28947,7 @@
     method public final boolean hasChildren();
     method public boolean hasFeature(int);
     method protected final boolean hasSoftInputMode();
+    method public void injectInputEvent(android.view.InputEvent);
     method public abstract void invalidatePanelMenu(int);
     method public final boolean isActive();
     method public abstract boolean isFloating();
@@ -26941,7 +28983,10 @@
     method public void setFlags(int, int);
     method public void setFormat(int);
     method public void setGravity(int);
+    method public void setIcon(int);
     method public void setLayout(int, int);
+    method public void setLocalFocus(boolean, boolean);
+    method public void setLogo(int);
     method public void setSoftInputMode(int);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitleColor(int);
@@ -27079,6 +29124,7 @@
     field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
     field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
     field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
+    field public static final int FLAG_LOCAL_FOCUS_MODE = 268435456; // 0x10000000
     field public static final int FLAG_NOT_FOCUSABLE = 8; // 0x8
     field public static final int FLAG_NOT_TOUCHABLE = 16; // 0x10
     field public static final int FLAG_NOT_TOUCH_MODAL = 32; // 0x20
@@ -27135,6 +29181,7 @@
     field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
     field public static final int TYPE_PHONE = 2002; // 0x7d2
     field public static final int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
+    field public static final int TYPE_PRIVATE_PRESENTATION = 2030; // 0x7ee
     field public static final int TYPE_SEARCH_BAR = 2001; // 0x7d1
     field public static final int TYPE_STATUS_BAR = 2000; // 0x7d0
     field public static final int TYPE_STATUS_BAR_PANEL = 2014; // 0x7de
@@ -27177,6 +29224,7 @@
     method public int describeContents();
     method public static java.lang.String eventTypeToString(int);
     method public int getAction();
+    method public int getContentChangeTypes();
     method public long getEventTime();
     method public int getEventType();
     method public int getMovementGranularity();
@@ -27188,11 +29236,16 @@
     method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
     method public static android.view.accessibility.AccessibilityEvent obtain();
     method public void setAction(int);
+    method public void setContentChangeTypes(int);
     method public void setEventTime(long);
     method public void setEventType(int);
     method public void setMovementGranularity(int);
     method public void setPackageName(java.lang.CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int INVALID_POSITION = -1; // 0xffffffff
     field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4
@@ -27246,6 +29299,7 @@
     method public void addAction(int);
     method public void addChild(android.view.View);
     method public void addChild(android.view.View, int);
+    method public boolean canOpenPopup();
     method public int describeContents();
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(java.lang.String);
@@ -27257,12 +29311,18 @@
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
     method public int getChildCount();
     method public java.lang.CharSequence getClassName();
+    method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
+    method public android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo getCollectionItemInfo();
     method public java.lang.CharSequence getContentDescription();
+    method public android.os.Bundle getExtras();
+    method public int getInputType();
     method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
     method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
+    method public int getLiveRegion();
     method public int getMovementGranularities();
     method public java.lang.CharSequence getPackageName();
     method public android.view.accessibility.AccessibilityNodeInfo getParent();
+    method public android.view.accessibility.AccessibilityNodeInfo.RangeInfo getRangeInfo();
     method public java.lang.CharSequence getText();
     method public int getTextSelectionEnd();
     method public int getTextSelectionStart();
@@ -27272,11 +29332,14 @@
     method public boolean isCheckable();
     method public boolean isChecked();
     method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isDismissable();
     method public boolean isEditable();
     method public boolean isEnabled();
     method public boolean isFocusable();
     method public boolean isFocused();
     method public boolean isLongClickable();
+    method public boolean isMultiLine();
     method public boolean isPassword();
     method public boolean isScrollable();
     method public boolean isSelected();
@@ -27292,25 +29355,34 @@
     method public void setAccessibilityFocused(boolean);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
+    method public void setCanOpenPopup(boolean);
     method public void setCheckable(boolean);
     method public void setChecked(boolean);
     method public void setClassName(java.lang.CharSequence);
     method public void setClickable(boolean);
+    method public void setCollectionInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionInfo);
+    method public void setCollectionItemInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo);
     method public void setContentDescription(java.lang.CharSequence);
+    method public void setContentInvalid(boolean);
+    method public void setDismissable(boolean);
     method public void setEditable(boolean);
     method public void setEnabled(boolean);
     method public void setFocusable(boolean);
     method public void setFocused(boolean);
+    method public void setInputType(int);
     method public void setLabelFor(android.view.View);
     method public void setLabelFor(android.view.View, int);
     method public void setLabeledBy(android.view.View);
     method public void setLabeledBy(android.view.View, int);
+    method public void setLiveRegion(int);
     method public void setLongClickable(boolean);
     method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
     method public void setPackageName(java.lang.CharSequence);
     method public void setParent(android.view.View);
     method public void setParent(android.view.View, int);
     method public void setPassword(boolean);
+    method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
     method public void setScrollable(boolean);
     method public void setSelected(boolean);
     method public void setSource(android.view.View);
@@ -27330,8 +29402,11 @@
     field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
     field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
     field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
     field public static final int ACTION_COPY = 16384; // 0x4000
     field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
     field public static final int ACTION_FOCUS = 1; // 0x1
     field public static final int ACTION_LONG_CLICK = 32; // 0x20
     field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
@@ -27353,10 +29428,38 @@
     field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
   }
 
+  public static final class AccessibilityNodeInfo.CollectionInfo {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public boolean isHierarchical();
+    method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
+  }
+
+  public static final class AccessibilityNodeInfo.CollectionItemInfo {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method public boolean isHeading();
+    method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
+  }
+
+  public static final class AccessibilityNodeInfo.RangeInfo {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    method public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
+    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public boolean performAction(int, int, android.os.Bundle);
   }
 
@@ -27409,6 +29512,34 @@
     method public void setToIndex(int);
   }
 
+  public class CaptioningManager {
+    method public void addCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
+    method public final float getFontScale();
+    method public final java.util.Locale getLocale();
+    method public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
+    method public final boolean isEnabled();
+    method public void removeCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
+  }
+
+  public static final class CaptioningManager.CaptionStyle {
+    method public android.graphics.Typeface getTypeface();
+    field public static final int EDGE_TYPE_DROP_SHADOW = 2; // 0x2
+    field public static final int EDGE_TYPE_NONE = 0; // 0x0
+    field public static final int EDGE_TYPE_OUTLINE = 1; // 0x1
+    field public final int backgroundColor;
+    field public final int edgeColor;
+    field public final int edgeType;
+    field public final int foregroundColor;
+  }
+
+  public static abstract class CaptioningManager.CaptioningChangeListener {
+    ctor public CaptioningManager.CaptioningChangeListener();
+    method public void onEnabledChanged(boolean);
+    method public void onFontScaleChanged(float);
+    method public void onLocaleChanged(java.util.Locale);
+    method public void onUserStyleChanged(android.view.accessibility.CaptioningManager.CaptionStyle);
+  }
+
 }
 
 package android.view.animation {
@@ -27661,10 +29792,10 @@
     method public void setAlpha(float);
     method public void setTransformationType(int);
     method public java.lang.String toShortString();
-    field public static int TYPE_ALPHA;
-    field public static int TYPE_BOTH;
-    field public static int TYPE_IDENTITY;
-    field public static int TYPE_MATRIX;
+    field public static final int TYPE_ALPHA = 1; // 0x1
+    field public static final int TYPE_BOTH = 3; // 0x3
+    field public static final int TYPE_IDENTITY = 0; // 0x0
+    field public static final int TYPE_MATRIX = 2; // 0x2
     field protected float mAlpha;
     field protected android.graphics.Matrix mMatrix;
     field protected int mTransformationType;
@@ -27928,6 +30059,7 @@
     method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
     method public void setInputMethod(android.os.IBinder, java.lang.String);
     method public void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
+    method public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
     method public void showInputMethodAndSubtypeEnabler(java.lang.String);
     method public void showInputMethodPicker();
     method public boolean showSoftInput(android.view.View, int);
@@ -27971,8 +30103,8 @@
   }
 
   public final class InputMethodSubtype implements android.os.Parcelable {
-    ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
-    ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int);
+    ctor public deprecated InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
+    ctor public deprecated InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int);
     method public boolean containsExtraValueKey(java.lang.String);
     method public int describeContents();
     method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
@@ -27982,12 +30114,27 @@
     method public java.lang.String getLocale();
     method public java.lang.String getMode();
     method public int getNameResId();
+    method public boolean isAsciiCapable();
     method public boolean isAuxiliary();
     method public boolean overridesImplicitlyEnabledSubtype();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public static class InputMethodSubtype.InputMethodSubtypeBuilder {
+    ctor public InputMethodSubtype.InputMethodSubtypeBuilder();
+    method public android.view.inputmethod.InputMethodSubtype build();
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAsciiCapable(boolean);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAuxiliary(boolean);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(boolean);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(java.lang.String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeIconResId(int);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeId(int);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeLocale(java.lang.String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeMode(java.lang.String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeNameResId(int);
+  }
+
 }
 
 package android.view.textservice {
@@ -28226,7 +30373,7 @@
     method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
     method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
     method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
-    method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onGeolocationPermissionsHidePrompt();
     method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
     method public void onHideCustomView();
@@ -28236,7 +30383,7 @@
     method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
     method public deprecated boolean onJsTimeout();
     method public void onProgressChanged(android.webkit.WebView, int);
-    method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
     method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
     method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -28292,12 +30439,12 @@
     method public int getCacheMode();
     method public synchronized java.lang.String getCursiveFontFamily();
     method public synchronized boolean getDatabaseEnabled();
-    method public synchronized java.lang.String getDatabasePath();
+    method public deprecated synchronized java.lang.String getDatabasePath();
     method public synchronized int getDefaultFixedFontSize();
     method public synchronized int getDefaultFontSize();
     method public synchronized java.lang.String getDefaultTextEncodingName();
     method public static java.lang.String getDefaultUserAgent(android.content.Context);
-    method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+    method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public boolean getDisplayZoomControls();
     method public synchronized boolean getDomStorageEnabled();
     method public synchronized java.lang.String getFantasyFontFamily();
@@ -28334,11 +30481,11 @@
     method public void setCacheMode(int);
     method public synchronized void setCursiveFontFamily(java.lang.String);
     method public synchronized void setDatabaseEnabled(boolean);
-    method public synchronized void setDatabasePath(java.lang.String);
+    method public deprecated synchronized void setDatabasePath(java.lang.String);
     method public synchronized void setDefaultFixedFontSize(int);
     method public synchronized void setDefaultFontSize(int);
     method public synchronized void setDefaultTextEncodingName(java.lang.String);
-    method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+    method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
     method public void setDisplayZoomControls(boolean);
     method public synchronized void setDomStorageEnabled(boolean);
     method public deprecated void setEnableSmoothTransition(boolean);
@@ -28381,9 +30528,10 @@
   public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
     method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
     method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
-    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
     enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
   }
 
   public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -28436,7 +30584,7 @@
     method public long getUsage();
   }
 
-  public static abstract interface WebStorage.QuotaUpdater {
+  public static abstract deprecated interface WebStorage.QuotaUpdater {
     method public abstract void updateQuota(long);
   }
 
@@ -28464,7 +30612,7 @@
     method public boolean canGoForward();
     method public deprecated boolean canZoomIn();
     method public deprecated boolean canZoomOut();
-    method public android.graphics.Picture capturePicture();
+    method public deprecated android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
     method public void clearFormData();
     method public void clearHistory();
@@ -28472,14 +30620,16 @@
     method public void clearSslPreferences();
     method public deprecated void clearView();
     method public android.webkit.WebBackForwardList copyBackForwardList();
+    method public android.print.PrintDocumentAdapter createPrintDocumentAdapter();
     method public void destroy();
     method public void documentHasImages(android.os.Message);
+    method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
     method public static java.lang.String findAddress(java.lang.String);
     method public deprecated int findAll(java.lang.String);
     method public void findAllAsync(java.lang.String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
-    method public void freeMemory();
+    method public deprecated void freeMemory();
     method public android.net.http.SslCertificate getCertificate();
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
@@ -28532,6 +30682,7 @@
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
     method public void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
+    method public static void setWebContentsDebuggingEnabled(boolean);
     method public void setWebViewClient(android.webkit.WebViewClient);
     method public deprecated boolean showFindDialog(java.lang.String, boolean);
     method public void stopLoading();
@@ -28630,6 +30781,7 @@
     ctor public AbsListView(android.content.Context, android.util.AttributeSet, int);
     method public void afterTextChanged(android.text.Editable);
     method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
+    method public boolean canScrollList(int);
     method public void clearChoices();
     method public void clearTextFilter();
     method public void deferNotifyDataSetChanged();
@@ -28661,6 +30813,7 @@
     method protected void layoutChildren();
     method public void onFilterComplete(int);
     method public void onGlobalLayout();
+    method public void onInitializeAccessibilityNodeInfoForItem(android.view.View, int, android.view.accessibility.AccessibilityNodeInfo);
     method public boolean onRemoteAdapterConnected();
     method public void onRemoteAdapterDisconnected();
     method public void onRestoreInstanceState(android.os.Parcelable);
@@ -28670,6 +30823,7 @@
     method public int pointToPosition(int, int);
     method public long pointToRowId(int, int);
     method public void reclaimViews(java.util.List<android.view.View>);
+    method public void scrollListBy(int);
     method public void setAdapter(android.widget.ListAdapter);
     method public void setCacheColorHint(int);
     method public void setChoiceMode(int);
@@ -29390,6 +31544,7 @@
     ctor public FrameLayout.LayoutParams(int, int, int);
     ctor public FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     ctor public FrameLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
     field public int gravity;
   }
 
@@ -29652,6 +31807,7 @@
     ctor public LinearLayout.LayoutParams(int, int, float);
     ctor public LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     ctor public LinearLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
     method public java.lang.String debug(java.lang.String);
     field public int gravity;
     field public float weight;
@@ -29668,6 +31824,7 @@
     ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
     ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
     method public void clearListSelection();
+    method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
     method public void dismiss();
     method public android.view.View getAnchorView();
     method public int getAnimationStyle();
@@ -29697,6 +31854,7 @@
     method public void setAnimationStyle(int);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setContentWidth(int);
+    method public void setDropDownGravity(int);
     method public void setHeight(int);
     method public void setHorizontalOffset(int);
     method public void setInputMethodMode(int);
@@ -29729,6 +31887,8 @@
     method public void addFooterView(android.view.View);
     method public void addHeaderView(android.view.View, java.lang.Object, boolean);
     method public void addHeaderView(android.view.View);
+    method public boolean areFooterDividersEnabled();
+    method public boolean areHeaderDividersEnabled();
     method protected android.view.View findViewTraversal(int);
     method protected android.view.View findViewWithTagTraversal(java.lang.Object);
     method public android.widget.ListAdapter getAdapter();
@@ -29876,7 +32036,9 @@
 
   public class PopupMenu {
     ctor public PopupMenu(android.content.Context, android.view.View);
+    ctor public PopupMenu(android.content.Context, android.view.View, int);
     method public void dismiss();
+    method public android.view.View.OnTouchListener getDragToOpenListener();
     method public android.view.Menu getMenu();
     method public android.view.MenuInflater getMenuInflater();
     method public void inflate(int);
@@ -29938,6 +32100,7 @@
     method public void setWindowLayoutMode(int, int);
     method public void showAsDropDown(android.view.View);
     method public void showAsDropDown(android.view.View, int, int);
+    method public void showAsDropDown(android.view.View, int, int, int);
     method public void showAtLocation(android.view.View, int, int, int);
     method public void update();
     method public void update(int, int);
@@ -30082,6 +32245,7 @@
     ctor public RelativeLayout.LayoutParams(int, int);
     ctor public RelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     ctor public RelativeLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams);
     method public void addRule(int);
     method public void addRule(int, int);
     method public java.lang.String debug(java.lang.String);
@@ -30883,6 +33047,7 @@
     ctor public VideoView(android.content.Context);
     ctor public VideoView(android.content.Context, android.util.AttributeSet);
     ctor public VideoView(android.content.Context, android.util.AttributeSet, int);
+    method public void addSubtitleSource(java.io.InputStream, android.media.MediaFormat);
     method public boolean canPause();
     method public boolean canSeekBackward();
     method public boolean canSeekForward();
diff --git a/cmds/am/am b/cmds/am/am
index c823634..1d426bc 100755
--- a/cmds/am/am
+++ b/cmds/am/am
@@ -1,3 +1,5 @@
+#!/system/bin/sh
+#
 # Script to start "am" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 61fe340..c18f542 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,6 +19,7 @@
 package com.android.commands.am;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManagerNative;
 import android.app.IActivityController;
 import android.app.IActivityManager;
@@ -75,6 +76,7 @@
         (new Am()).run(args);
     }
 
+    @Override
     public void onShowUsage(PrintStream out) {
         out.println(
                 "usage: am [subcommand] [options]\n" +
@@ -82,6 +84,7 @@
                 "               [--R COUNT] [-S] [--opengl-trace]\n" +
                 "               [--user <USER_ID> | current] <INTENT>\n" +
                 "       am startservice [--user <USER_ID> | current] <INTENT>\n" +
+                "       am stopservice [--user <USER_ID> | current] <INTENT>\n" +
                 "       am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" +
                 "       am kill [--user <USER_ID> | all | current] <PACKAGE>\n" +
                 "       am kill-all\n" +
@@ -96,11 +99,18 @@
                 "       am clear-debug-app\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am hang [--allow-restart]\n" +
+                "       am restart\n" +
+                "       am idle-maintenance\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
                 "       am to-uri [INTENT]\n" +
                 "       am to-intent-uri [INTENT]\n" +
                 "       am switch-user <USER_ID>\n" +
                 "       am stop-user <USER_ID>\n" +
+                "       am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
+                "       am stack movetask <STACK_ID> <TASK_ID> [true|false]\n" +
+                "       am stack resize <STACK_ID> <WEIGHT>\n" +
+                "       am stack boxes\n" +
+                "       am stack box <STACK_BOX_ID>\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -118,6 +128,10 @@
                 "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
                 "        specified then run as the current user.\n" +
                 "\n" +
+                "am stopservice: stop a Service.  Options are:\n" +
+                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
+                "        specified then run as the current user.\n" +
+                "\n" +
                 "am force-stop: force stop everything associated with <PACKAGE>.\n" +
                 "    --user <USER_ID> | all | current: Specify user to force stop;\n" +
                 "        all users if not specified.\n" +
@@ -146,7 +160,7 @@
                 "        test runners.\n" +
                 "    --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
                 "        current user if not specified.\n" +
-                "    --no-window-animation: turn off window animations will running.\n" +
+                "    --no-window-animation: turn off window animations while running.\n" +
                 "\n" +
                 "am profile: start and stop profiler on a process.  The given <PROCESS> argument\n" +
                 "  may be either a process name or pid.  Options are:\n" +
@@ -174,6 +188,10 @@
                 "am hang: hang the system.\n" +
                 "    --allow-restart: allow watchdog to perform normal system restart\n" +
                 "\n" +
+                "am restart: restart the user-space system.\n" +
+                "\n" +
+                "am idle-maintenance: perform idle maintenance now.\n" +
+                "\n" +
                 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
                 "\n" +
                 "am to-uri: print the given Intent specification as a URI.\n" +
@@ -186,6 +204,25 @@
                 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
                 "  code until a later explicit switch to it.\n" +
                 "\n" +
+                "am stack create: create a new stack relative to an existing one.\n" +
+                "   <TASK_ID>: the task to populate the new stack with. Must exist.\n" +
+                "   <RELATIVE_STACK_BOX_ID>: existing stack box's id.\n" +
+                "   <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
+                "               1: after <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
+                "               2: to left of <RELATIVE_STACK_BOX_ID>,\n" +
+                "               3: to right of <RELATIVE_STACK_BOX_ID>," +
+                "               4: above <RELATIVE_STACK_BOX_ID>, 5: below <RELATIVE_STACK_BOX_ID>\n" +
+                "   <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" +
+                "\n" +
+                "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
+                "   bottom (false) of <STACK_ID>.\n" +
+                "\n" +
+                "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" +
+                "\n" +
+                "am stack boxes: list the hierarchy of stack boxes and their contents.\n" +
+                "\n" +
+                "am stack box: list the hierarchy of stack boxes rooted at <STACK_BOX_ID>.\n" +
+                "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                 "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
@@ -218,6 +255,7 @@
                 );
     }
 
+    @Override
     public void onRun() throws Exception {
 
         mAm = ActivityManagerNative.getDefault();
@@ -232,6 +270,8 @@
             runStart();
         } else if (op.equals("startservice")) {
             runStartService();
+        } else if (op.equals("stopservice")) {
+            runStopService();
         } else if (op.equals("force-stop")) {
             runForceStop();
         } else if (op.equals("kill")) {
@@ -256,6 +296,10 @@
             runMonitor();
         } else if (op.equals("hang")) {
             runHang();
+        } else if (op.equals("restart")) {
+            runRestart();
+        } else if (op.equals("idle-maintenance")) {
+            runIdleMaintenance();
         } else if (op.equals("screen-compat")) {
             runScreenCompat();
         } else if (op.equals("to-uri")) {
@@ -266,6 +310,8 @@
             runSwitchUser();
         } else if (op.equals("stop-user")) {
             runStopUser();
+        } else if (op.equals("stack")) {
+            runStack();
         } else {
             showError("Error: unknown command '" + op + "'");
         }
@@ -545,6 +591,23 @@
         }
     }
 
+    private void runStopService() throws Exception {
+        Intent intent = makeIntent(UserHandle.USER_CURRENT);
+        if (mUserId == UserHandle.USER_ALL) {
+            System.err.println("Error: Can't stop activity with user 'all'");
+            return;
+        }
+        System.out.println("Stopping service: " + intent);
+        int result = mAm.stopService(null, intent, intent.getType(), mUserId);
+        if (result == 0) {
+            System.err.println("Service not stopped: was not running.");
+        } else if (result == 1) {
+            System.err.println("Service stopped");
+        } else if (result == -1) {
+            System.err.println("Error stopping service");
+        }
+    }
+
     private void runStart() throws Exception {
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
 
@@ -1036,7 +1099,7 @@
         }
 
         @Override
-        public boolean activityResuming(String pkg) throws RemoteException {
+        public boolean activityResuming(String pkg) {
             synchronized (this) {
                 System.out.println("** Activity resuming: " + pkg);
             }
@@ -1044,7 +1107,7 @@
         }
 
         @Override
-        public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
+        public boolean activityStarting(Intent intent, String pkg) {
             synchronized (this) {
                 System.out.println("** Activity starting: " + pkg);
             }
@@ -1053,7 +1116,7 @@
 
         @Override
         public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
-                long timeMillis, String stackTrace) throws RemoteException {
+                long timeMillis, String stackTrace) {
             synchronized (this) {
                 System.out.println("** ERROR: PROCESS CRASHED");
                 System.out.println("processName: " + processName);
@@ -1070,8 +1133,7 @@
         }
 
         @Override
-        public int appEarlyNotResponding(String processName, int pid, String annotation)
-                throws RemoteException {
+        public int appEarlyNotResponding(String processName, int pid, String annotation) {
             synchronized (this) {
                 System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING");
                 System.out.println("processName: " + processName);
@@ -1084,8 +1146,7 @@
         }
 
         @Override
-        public int appNotResponding(String processName, int pid, String processStats)
-                throws RemoteException {
+        public int appNotResponding(String processName, int pid, String processStats) {
             synchronized (this) {
                 System.out.println("** ERROR: PROCESS NOT RESPONDING");
                 System.out.println("processName: " + processName);
@@ -1101,8 +1162,7 @@
         }
 
         @Override
-        public int systemNotResponding(String message)
-                throws RemoteException {
+        public int systemNotResponding(String message) {
             synchronized (this) {
                 System.out.println("** ERROR: PROCESS NOT RESPONDING");
                 System.out.println("message: " + message);
@@ -1327,6 +1387,31 @@
         mAm.hang(new Binder(), allowRestart);
     }
 
+    private void runRestart() throws Exception {
+        String opt;
+        while ((opt=nextOption()) != null) {
+            System.err.println("Error: Unknown option: " + opt);
+            return;
+        }
+
+        System.out.println("Restart the system...");
+        mAm.restart();
+    }
+
+    private void runIdleMaintenance() throws Exception {
+        String opt;
+        while ((opt=nextOption()) != null) {
+            System.err.println("Error: Unknown option: " + opt);
+            return;
+        }
+
+        System.out.println("Performing idle maintenance...");
+        Intent intent = new Intent(
+                "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
+        mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
+                android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
+    }
+
     private void runScreenCompat() throws Exception {
         String mode = nextArgRequired();
         boolean enabled;
@@ -1361,7 +1446,7 @@
 
         @Override
         public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
-                boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
+                boolean ordered, boolean sticky, int sendingUser) {
             String line = "Broadcast completed: result=" + resultCode;
             if (data != null) line = line + ", data=\"" + data + "\"";
             if (extras != null) line = line + ", extras: " + extras;
@@ -1394,6 +1479,7 @@
             mRawMode = rawMode;
         }
 
+        @Override
         public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
             synchronized (this) {
                 // pretty printer mode?
@@ -1416,6 +1502,7 @@
             }
         }
 
+        @Override
         public void instrumentationFinished(ComponentName name, int resultCode,
                 Bundle results) {
             synchronized (this) {
@@ -1456,4 +1543,93 @@
             return true;
         }
     }
+
+    private void runStack() throws Exception {
+        String op = nextArgRequired();
+        if (op.equals("create")) {
+            runStackCreate();
+        } else if (op.equals("movetask")) {
+            runStackMoveTask();
+        } else if (op.equals("resize")) {
+            runStackBoxResize();
+        } else if (op.equals("boxes")) {
+            runStackBoxes();
+        } else if (op.equals("box")) {
+            runStackBoxInfo();
+        } else {
+            showError("Error: unknown command '" + op + "'");
+            return;
+        }
+    }
+
+    private void runStackCreate() throws Exception {
+        String taskIdStr = nextArgRequired();
+        int taskId = Integer.valueOf(taskIdStr);
+        String relativeToStr = nextArgRequired();
+        int relativeTo = Integer.valueOf(relativeToStr);
+        String positionStr = nextArgRequired();
+        int position = Integer.valueOf(positionStr);
+        String weightStr = nextArgRequired();
+        float weight = Float.valueOf(weightStr);
+
+        try {
+            int stackId = mAm.createStack(taskId, relativeTo, position, weight);
+            System.out.println("createStack returned new stackId=" + stackId + "\n\n");
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runStackMoveTask() throws Exception {
+        String taskIdStr = nextArgRequired();
+        int taskId = Integer.valueOf(taskIdStr);
+        String stackIdStr = nextArgRequired();
+        int stackId = Integer.valueOf(stackIdStr);
+        String toTopStr = nextArgRequired();
+        final boolean toTop;
+        if ("true".equals(toTopStr)) {
+            toTop = true;
+        } else if ("false".equals(toTopStr)) {
+            toTop = false;
+        } else {
+            System.err.println("Error: bad toTop arg: " + toTopStr);
+            return;
+        }
+
+        try {
+            mAm.moveTaskToStack(taskId, stackId, toTop);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runStackBoxResize() throws Exception {
+        String stackBoxIdStr = nextArgRequired();
+        int stackBoxId = Integer.valueOf(stackBoxIdStr);
+        String weightStr = nextArgRequired();
+        float weight = Float.valueOf(weightStr);
+
+        try {
+            mAm.resizeStackBox(stackBoxId, weight);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runStackBoxes() throws Exception {
+        try {
+            List<StackBoxInfo> stackBoxes = mAm.getStackBoxes();
+            for (StackBoxInfo info : stackBoxes) {
+                System.out.println(info);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runStackBoxInfo() throws Exception {
+        try {
+            String stackBoxIdStr = nextArgRequired();
+            int stackBoxId = Integer.valueOf(stackBoxIdStr);
+            StackBoxInfo stackBoxInfo = mAm.getStackBoxInfo(stackBoxId); 
+            System.out.println(stackBoxInfo);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/cmds/backup/Android.mk b/cmds/backup/Android.mk
index 73af0bc..42e5133 100644
--- a/cmds/backup/Android.mk
+++ b/cmds/backup/Android.mk
@@ -10,6 +10,6 @@
 LOCAL_MODULE:= btool
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8511735..ad4e4c8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -44,7 +44,7 @@
 
 #include <core/SkBitmap.h>
 #include <core/SkStream.h>
-#include <images/SkImageDecoder.h>
+#include <core/SkImageDecoder.h>
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 80ac539..2a7c79b 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -24,6 +24,9 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Command that sends key events to the device, either by their keycode, or by
  * desired character output.
@@ -31,6 +34,21 @@
 
 public class Input {
     private static final String TAG = "Input";
+    private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
+
+    private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
+        put("keyboard", InputDevice.SOURCE_KEYBOARD);
+        put("dpad", InputDevice.SOURCE_DPAD);
+        put("gamepad", InputDevice.SOURCE_GAMEPAD);
+        put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN);
+        put("mouse", InputDevice.SOURCE_MOUSE);
+        put("stylus", InputDevice.SOURCE_STYLUS);
+        put("trackball", InputDevice.SOURCE_TRACKBALL);
+        put("touchpad", InputDevice.SOURCE_TOUCHPAD);
+        put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
+        put("joystick", InputDevice.SOURCE_JOYSTICK);
+    }};
+
 
     /**
      * Command-line entry point.
@@ -47,82 +65,71 @@
             return;
         }
 
-        String command = args[0];
+        int index = 0;
+        String command = args[index];
+        int inputSource = InputDevice.SOURCE_UNKNOWN;
+        if (SOURCES.containsKey(command)) {
+            inputSource = SOURCES.get(command);
+            index++;
+            command = args[index];
+        }
+        final int length = args.length - index;
 
         try {
             if (command.equals("text")) {
-                if (args.length == 2) {
-                    sendText(args[1]);
+                if (length == 2) {
+                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
+                    sendText(inputSource, args[index+1]);
                     return;
                 }
             } else if (command.equals("keyevent")) {
-                if (args.length >= 2) {
-                    for (int i=1; i < args.length; i++) {
-                        int keyCode = KeyEvent.keyCodeFromString(args[i]);
-                        if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
-                            keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
+                if (length >= 2) {
+                    final boolean longpress = "--longpress".equals(args[index + 1]);
+                    final int start = longpress ? index + 2 : index + 1;
+                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
+                    if (length > start) {
+                        for (int i = start; i < length; i++) {
+                            int keyCode = KeyEvent.keyCodeFromString(args[i]);
+                            if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+                                keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
+                            }
+                            sendKeyEvent(inputSource, keyCode, longpress);
                         }
-                        sendKeyEvent(keyCode);
+                        return;
                     }
-                    return;
                 }
             } else if (command.equals("tap")) {
-                if (args.length == 3) {
-                    sendTap(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]));
+                if (length == 3) {
+                    inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+                    sendTap(inputSource, Float.parseFloat(args[index+1]),
+                            Float.parseFloat(args[index+2]));
                     return;
                 }
             } else if (command.equals("swipe")) {
-                if (args.length == 5) {
-                    sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]),
-                            Float.parseFloat(args[3]), Float.parseFloat(args[4]), -1);
+                int duration = -1;
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+                switch (length) {
+                    case 6:
+                        duration = Integer.parseInt(args[index+5]);
+                    case 5:
+                        sendSwipe(inputSource,
+                                Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
+                                Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
+                                duration);
+                        return;
+                }
+            } else if (command.equals("press")) {
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+                if (length == 1) {
+                    sendTap(inputSource, 0.0f, 0.0f);
                     return;
                 }
-            } else if (command.equals("touchscreen") || command.equals("touchpad")
-                    || command.equals("touchnavigation")) {
-                // determine input source
-                int inputSource = InputDevice.SOURCE_TOUCHSCREEN;
-                if (command.equals("touchpad")) {
-                    inputSource = InputDevice.SOURCE_TOUCHPAD;
-                } else if (command.equals("touchnavigation")) {
-                    inputSource = InputDevice.SOURCE_TOUCH_NAVIGATION;
-                }
-                // determine subcommand
-                if (args.length > 1) {
-                    String subcommand = args[1];
-                    if (subcommand.equals("tap")) {
-                        if (args.length == 4) {
-                            sendTap(inputSource, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]));
-                            return;
-                        }
-                    } else if (subcommand.equals("swipe")) {
-                        if (args.length == 6) {
-                            sendSwipe(inputSource, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]), Float.parseFloat(args[4]),
-                                    Float.parseFloat(args[5]), -1);
-                            return;
-                        } else if (args.length == 7) {
-                            sendSwipe(inputSource, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]), Float.parseFloat(args[4]),
-                                    Float.parseFloat(args[5]), Integer.parseInt(args[6]));
-                            return;
-                        }
-                    }
-                }
-            } else if (command.equals("trackball")) {
-                // determine subcommand
-                if (args.length > 1) {
-                    String subcommand = args[1];
-                    if (subcommand.equals("press")) {
-                        sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f);
-                        return;
-                    } else if (subcommand.equals("roll")) {
-                        if (args.length == 4) {
-                            sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]));
-                            return;
-                        }
-                    }
+            } else if (command.equals("roll")) {
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+                if (length == 3) {
+                    sendMove(inputSource, Float.parseFloat(args[index+1]),
+                            Float.parseFloat(args[index+2]));
+                    return;
                 }
             } else {
                 System.err.println("Error: Unknown command: " + command);
@@ -131,7 +138,7 @@
             }
         } catch (NumberFormatException ex) {
         }
-        System.err.println("Error: Invalid arguments for command: " + command);
+        System.err.println(INVALID_ARGUMENTS + command);
         showUsage();
     }
 
@@ -141,7 +148,7 @@
      *
      * @param text is a string of characters you want to input to the device.
      */
-    private void sendText(String text) {
+    private void sendText(int source, String text) {
 
         StringBuffer buff = new StringBuffer(text);
 
@@ -153,7 +160,7 @@
                     buff.setCharAt(i, ' ');
                     buff.deleteCharAt(--i);
                 }
-            } 
+            }
             if (buff.charAt(i) == '%') {
                 escapeFlag = true;
             }
@@ -164,16 +171,25 @@
         KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         KeyEvent[] events = kcm.getEvents(chars);
         for(int i = 0; i < events.length; i++) {
-            injectKeyEvent(events[i]);
+            KeyEvent e = events[i];
+            if (source != e.getSource()) {
+                e.setSource(source);
+            }
+            injectKeyEvent(e);
         }
     }
 
-    private void sendKeyEvent(int keyCode) {
+    private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
         long now = SystemClock.uptimeMillis();
         injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
+        if (longpress) {
+            injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
+                    inputSource));
+        }
         injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
     }
 
     private void sendTap(int inputSource, float x, float y) {
@@ -197,7 +213,7 @@
                     lerp(y1, y2, alpha), 1.0f);
             now = SystemClock.uptimeMillis();
         }
-        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f);
+        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
     }
 
     /**
@@ -248,14 +264,26 @@
         return (b - a) * alpha + a;
     }
 
+    private static final int getSource(int inputSource, int defaultSource) {
+        return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
+    }
+
     private void showUsage() {
-        System.err.println("usage: input ...");
-        System.err.println("       input text <string>");
-        System.err.println("       input keyevent <key code number or name> ...");
-        System.err.println("       input [touchscreen|touchpad|touchnavigation] tap <x> <y>");
-        System.err.println("       input [touchscreen|touchpad|touchnavigation] swipe "
-                + "<x1> <y1> <x2> <y2> [duration(ms)]");
-        System.err.println("       input trackball press");
-        System.err.println("       input trackball roll <dx> <dy>");
+        System.err.println("Usage: input [<source>] <command> [<arg>...]");
+        System.err.println();
+        System.err.println("The sources are: ");
+        for (String src : SOURCES.keySet()) {
+            System.err.println("      " + src);
+        }
+        System.err.println();
+        System.err.println("The commands and default sources are:");
+        System.err.println("      text <string> (Default: touchscreen)");
+        System.err.println("      keyevent [--longpress] <key code number or name> ..."
+                + " (Default: keyboard)");
+        System.err.println("      tap <x> <y> (Default: touchscreen)");
+        System.err.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+                + " (Default: touchscreen)");
+        System.err.println("      press (Default: trackball)");
+        System.err.println("      roll <dx> <dy> (Default: trackball)");
     }
 }
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 224945a..d1ded10 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -16,8 +16,7 @@
 
 package com.android.commands.pm;
 
-import com.android.internal.content.PackageHelper;
-
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
@@ -46,6 +45,7 @@
 import android.os.UserManager;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.InvalidAlgorithmParameterException;
@@ -59,6 +59,8 @@
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
+import com.android.internal.content.PackageHelper;
+
 public final class Pm {
     IPackageManager mPm;
     IUserManager mUm;
@@ -105,6 +107,11 @@
             return;
         }
 
+        if ("dump".equals(op)) {
+            runDump();
+            return;
+        }
+
         if ("install".equals(op)) {
             runInstall();
             return;
@@ -140,6 +147,16 @@
             return;
         }
 
+        if ("block".equals(op)) {
+            runSetBlockedSetting(true);
+            return;
+        }
+
+        if ("unblock".equals(op)) {
+            runSetBlockedSetting(false);
+            return;
+        }
+
         if ("grant".equals(op)) {
             runGrantRevokePermission(true);
             return;
@@ -672,6 +689,15 @@
         displayPackageFilePath(pkg);
     }
 
+    private void runDump() {
+        String pkg = nextArg();
+        if (pkg == null) {
+            System.err.println("Error: no package specified");
+            return;
+        }
+        ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
+    }
+
     class PackageInstallObserver extends IPackageInstallObserver.Stub {
         boolean finished;
         int result;
@@ -1240,6 +1266,36 @@
         }
     }
 
+    private void runSetBlockedSetting(boolean state) {
+        int userId = 0;
+        String option = nextOption();
+        if (option != null && option.equals("--user")) {
+            String optionData = nextOptionData();
+            if (optionData == null || !isNumber(optionData)) {
+                System.err.println("Error: no USER_ID specified");
+                showUsage();
+                return;
+            } else {
+                userId = Integer.parseInt(optionData);
+            }
+        }
+
+        String pkg = nextArg();
+        if (pkg == null) {
+            System.err.println("Error: no package or component specified");
+            showUsage();
+            return;
+        }
+        try {
+            mPm.setApplicationBlockedSettingAsUser(pkg, state, userId);
+            System.err.println("Package " + pkg + " new blocked state: "
+                    + mPm.getApplicationBlockedSettingAsUser(pkg, userId));
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(PM_NOT_RUNNING_ERR);
+        }
+    }
+
     private void runGrantRevokePermission(boolean grant) {
         String pkg = nextArg();
         if (pkg == null) {
@@ -1456,6 +1512,7 @@
         System.err.println("       pm list libraries");
         System.err.println("       pm list users");
         System.err.println("       pm path PACKAGE");
+        System.err.println("       pm dump PACKAGE");
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
         System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
         System.err.println("                  [--originating-uri <URI>] [--referrer <URI>] PATH");
@@ -1465,6 +1522,8 @@
         System.err.println("       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
+        System.err.println("       pm block [--user USER_ID] PACKAGE_OR_COMPONENT");
+        System.err.println("       pm unblock [--user USER_ID] PACKAGE_OR_COMPONENT");
         System.err.println("       pm grant PACKAGE PERMISSION");
         System.err.println("       pm revoke PACKAGE PERMISSION");
         System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
@@ -1506,6 +1565,8 @@
         System.err.println("");
         System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
         System.err.println("");
+        System.err.println("pm dump: print system state associated w ith the given PACKAGE.");
+        System.err.println("");
         System.err.println("pm install: installs a package to the system.  Options:");
         System.err.println("    -l: install the package with FORWARD_LOCK.");
         System.err.println("    -r: reinstall an exisiting app, keeping its data.");
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index be32355..a57de01 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -55,12 +55,8 @@
 static SkBitmap::Config flinger2skia(PixelFormat f)
 {
     switch (f) {
-        case PIXEL_FORMAT_A_8:
-            return SkBitmap::kA8_Config;
         case PIXEL_FORMAT_RGB_565:
             return SkBitmap::kRGB_565_Config;
-        case PIXEL_FORMAT_RGBA_4444:
-            return SkBitmap::kARGB_4444_Config;
         default:
             return SkBitmap::kARGB_8888_Config;
     }
diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk
deleted file mode 100644
index 3083e31..0000000
--- a/cmds/system_server/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	system_main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libutils \
-	libbinder \
-	libsystem_server \
-	liblog
-
-LOCAL_C_INCLUDES := \
-	$(JNI_H_INCLUDE)
-
-LOCAL_MODULE:= system_server
-
-include $(BUILD_EXECUTABLE)
-
-include $(LOCAL_PATH)/library/Android.mk
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
deleted file mode 100644
index d78474e..0000000
--- a/cmds/system_server/library/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	system_init.cpp
-
-base = $(LOCAL_PATH)/../../..
-native = $(LOCAL_PATH)/../../../../native
-
-LOCAL_C_INCLUDES := \
-	$(native)/services/sensorservice \
-	$(native)/services/surfaceflinger \
-	$(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := \
-	libandroid_runtime \
-	libsensorservice \
-	libsurfaceflinger \
-	libinput \
-	libutils \
-	libbinder \
-	libcutils \
-	liblog
-
-LOCAL_MODULE:= libsystem_server
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
deleted file mode 100644
index 745c34a..0000000
--- a/cmds/system_server/library/system_init.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * System server main initialization.
- *
- * The system server is responsible for becoming the Binder
- * context manager, supplying the root ServiceManager object
- * through which other services can be found.
- */
-
-#define LOG_TAG "sysproc"
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <utils/TextOutput.h>
-#include <utils/Log.h>
-
-#include <SurfaceFlinger.h>
-#include <SensorService.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <cutils/properties.h>
-
-using namespace android;
-
-namespace android {
-/**
- * This class is used to kill this process when the runtime dies.
- */
-class GrimReaper : public IBinder::DeathRecipient {
-public:
-    GrimReaper() { }
-
-    virtual void binderDied(const wp<IBinder>& who)
-    {
-        ALOGI("Grim Reaper killing system_server...");
-        kill(getpid(), SIGKILL);
-    }
-};
-
-} // namespace android
-
-
-
-extern "C" status_t system_init()
-{
-    ALOGI("Entered system_init()");
-
-    sp<ProcessState> proc(ProcessState::self());
-
-    sp<IServiceManager> sm = defaultServiceManager();
-    ALOGI("ServiceManager: %p\n", sm.get());
-
-    sp<GrimReaper> grim = new GrimReaper();
-    sm->asBinder()->linkToDeath(grim, grim.get(), 0);
-
-    char propBuf[PROPERTY_VALUE_MAX];
-    property_get("system_init.startsurfaceflinger", propBuf, "1");
-    if (strcmp(propBuf, "1") == 0) {
-        // Start the SurfaceFlinger
-        SurfaceFlinger::instantiate();
-    }
-
-    property_get("system_init.startsensorservice", propBuf, "1");
-    if (strcmp(propBuf, "1") == 0) {
-        // Start the sensor service
-        SensorService::instantiate();
-    }
-
-    // And now start the Android runtime.  We have to do this bit
-    // of nastiness because the Android runtime initialization requires
-    // some of the core system services to already be started.
-    // All other servers should just start the Android runtime at
-    // the beginning of their processes's main(), before calling
-    // the init function.
-    ALOGI("System server: starting Android runtime.\n");
-    AndroidRuntime* runtime = AndroidRuntime::getRuntime();
-
-    ALOGI("System server: starting Android services.\n");
-    JNIEnv* env = runtime->getJNIEnv();
-    if (env == NULL) {
-        return UNKNOWN_ERROR;
-    }
-    jclass clazz = env->FindClass("com/android/server/SystemServer");
-    if (clazz == NULL) {
-        return UNKNOWN_ERROR;
-    }
-    jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
-    if (methodId == NULL) {
-        return UNKNOWN_ERROR;
-    }
-    env->CallStaticVoidMethod(clazz, methodId);
-
-    ALOGI("System server: entering thread pool.\n");
-    ProcessState::self()->startThreadPool();
-    IPCThreadState::self()->joinThreadPool();
-    ALOGI("System server: exiting thread pool.\n");
-
-    return NO_ERROR;
-}
diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp
deleted file mode 100644
index ddff065..0000000
--- a/cmds/system_server/system_main.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Main entry of system server process.
- * 
- * Calls the standard system initialization function, and then
- * puts the main thread into the thread pool so it can handle
- * incoming transactions.
- * 
- */
-
-#define LOG_TAG "sysproc"
-
-#include <binder/IPCThreadState.h>
-#include <utils/Log.h>
-
-#include <private/android_filesystem_config.h>
-
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <signal.h>
-#include <stdio.h>
-#include <unistd.h>
-
-using namespace android;
-
-extern "C" status_t system_init();
-
-bool finish_system_init()
-{
-    return true;
-}
-
-static void blockSignals()
-{
-    sigset_t mask;
-    int cc;
-    
-    sigemptyset(&mask);
-    sigaddset(&mask, SIGQUIT);
-    sigaddset(&mask, SIGUSR1);
-    cc = sigprocmask(SIG_BLOCK, &mask, NULL);
-    assert(cc == 0);
-}
-
-int main(int argc, const char* const argv[])
-{
-    ALOGI("System server is starting with pid=%d.\n", getpid());
-
-    blockSignals();
-    
-    // You can trust me, honestly!
-    ALOGW("*** Current priority: %d\n", getpriority(PRIO_PROCESS, 0));
-    setpriority(PRIO_PROCESS, 0, -1);
-
-    system_init();    
-}
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 58eb66f..82c2159 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -29,6 +29,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
+import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
@@ -127,6 +128,7 @@
     private int mCallingUid;
     private String mCallingPackage;
     private boolean mDisallowAddAccounts;
+    private boolean mDontShowPicker;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -189,11 +191,23 @@
         mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
         mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false);
         mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
+
+        // Need to do this once here to request the window feature. Can't do it in onResume
+        mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
+        if (mAccounts.isEmpty()
+                && mDisallowAddAccounts) {
+            requestWindowFeature(Window.FEATURE_NO_TITLE);
+            setContentView(R.layout.app_not_authorized);
+            mDontShowPicker = true;
+        }
     }
 
     @Override
     protected void onResume() {
         super.onResume();
+
+        if (mDontShowPicker) return;
+
         final AccountManager accountManager = AccountManager.get(this);
 
         mAccounts = getAcceptableAccountChoices(accountManager);
@@ -206,11 +220,6 @@
             // If there are no relevant accounts and only one relevant account type go directly to
             // add account. Otherwise let the user choose.
             if (mAccounts.isEmpty()) {
-                if (mDisallowAddAccounts) {
-                    setContentView(R.layout.app_not_authorized);
-                    setTitle(R.string.error_message_title);
-                    return;
-                }
                 if (mSetOfRelevantAccountTypes.size() == 1) {
                     runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
                 } else {
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 39eb8d6..129e52c 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -30,6 +30,17 @@
     ArrayList<AnimatorListener> mListeners = null;
 
     /**
+     * The set of listeners to be sent pause/resume events through the life
+     * of an animation.
+     */
+    ArrayList<AnimatorPauseListener> mPauseListeners = null;
+
+    /**
+     * Whether this animator is currently in a paused state.
+     */
+    boolean mPaused = false;
+
+    /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
      * value(s) set immediately, followed by calls to
@@ -69,6 +80,66 @@
     }
 
     /**
+     * Pauses a running animation. This method should only be called on the same thread on
+     * which the animation was started. If the animation has not yet been {@link
+     * #isStarted() started} or has since ended, then the call is ignored. Paused
+     * animations can be resumed by calling {@link #resume()}.
+     *
+     * @see #resume()
+     * @see #isPaused()
+     * @see AnimatorPauseListener
+     */
+    public void pause() {
+        if (isStarted() && !mPaused) {
+            mPaused = true;
+            if (mPauseListeners != null) {
+                ArrayList<AnimatorPauseListener> tmpListeners =
+                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onAnimationPause(this);
+                }
+            }
+        }
+    }
+
+    /**
+     * Resumes a paused animation, causing the animator to pick up where it left off
+     * when it was paused. This method should only be called on the same thread on
+     * which the animation was started. Calls to resume() on an animator that is
+     * not currently paused will be ignored.
+     *
+     * @see #pause()
+     * @see #isPaused()
+     * @see AnimatorPauseListener
+     */
+    public void resume() {
+        if (mPaused) {
+            mPaused = false;
+            if (mPauseListeners != null) {
+                ArrayList<AnimatorPauseListener> tmpListeners =
+                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onAnimationResume(this);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns whether this animator is currently in a paused state.
+     *
+     * @return True if the animator is currently paused, false otherwise.
+     *
+     * @see #pause()
+     * @see #resume()
+     */
+    public boolean isPaused() {
+        return mPaused;
+    }
+
+    /**
      * The amount of time, in milliseconds, to delay processing the animation
      * after {@link #start()} is called.
      *
@@ -180,15 +251,48 @@
     }
 
     /**
-     * Removes all listeners from this object. This is equivalent to calling
-     * <code>getListeners()</code> followed by calling <code>clear()</code> on the
-     * returned list of listeners.
+     * Adds a pause listener to this animator.
+     *
+     * @param listener the listener to be added to the current set of pause listeners
+     * for this animation.
+     */
+    public void addPauseListener(AnimatorPauseListener listener) {
+        if (mPauseListeners == null) {
+            mPauseListeners = new ArrayList<AnimatorPauseListener>();
+        }
+        mPauseListeners.add(listener);
+    }
+
+    /**
+     * Removes a pause listener from the set listening to this animation.
+     *
+     * @param listener the listener to be removed from the current set of pause
+     * listeners for this animation.
+     */
+    public void removePauseListener(AnimatorPauseListener listener) {
+        if (mPauseListeners == null) {
+            return;
+        }
+        mPauseListeners.remove(listener);
+        if (mPauseListeners.size() == 0) {
+            mPauseListeners = null;
+        }
+    }
+
+    /**
+     * Removes all {@link #addListener(android.animation.Animator.AnimatorListener) listeners}
+     * and {@link #addPauseListener(android.animation.Animator.AnimatorPauseListener)
+     * pauseListeners} from this object.
      */
     public void removeAllListeners() {
         if (mListeners != null) {
             mListeners.clear();
             mListeners = null;
         }
+        if (mPauseListeners != null) {
+            mPauseListeners.clear();
+            mPauseListeners = null;
+        }
     }
 
     @Override
@@ -203,6 +307,14 @@
                     anim.mListeners.add(oldListeners.get(i));
                 }
             }
+            if (mPauseListeners != null) {
+                ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
+                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
+                int numListeners = oldListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    anim.mPauseListeners.add(oldListeners.get(i));
+                }
+            }
             return anim;
         } catch (CloneNotSupportedException e) {
            throw new AssertionError();
@@ -280,4 +392,29 @@
          */
         void onAnimationRepeat(Animator animation);
     }
+
+    /**
+     * A pause listener receives notifications from an animation when the
+     * animation is {@link #pause() paused} or {@link #resume() resumed}.
+     *
+     * @see #addPauseListener(AnimatorPauseListener)
+     */
+    public static interface AnimatorPauseListener {
+        /**
+         * <p>Notifies that the animation was paused.</p>
+         *
+         * @param animation The animaton being paused.
+         * @see #pause()
+         */
+        void onAnimationPause(Animator animation);
+
+        /**
+         * <p>Notifies that the animation was resumed, after being
+         * previously paused.</p>
+         *
+         * @param animation The animation being resumed.
+         * @see #resume()
+         */
+        void onAnimationResume(Animator animation);
+    }
 }
diff --git a/core/java/android/animation/AnimatorListenerAdapter.java b/core/java/android/animation/AnimatorListenerAdapter.java
index e5d70a4..2ecb8c3 100644
--- a/core/java/android/animation/AnimatorListenerAdapter.java
+++ b/core/java/android/animation/AnimatorListenerAdapter.java
@@ -21,7 +21,8 @@
  * Any custom listener that cares only about a subset of the methods of this listener can
  * simply subclass this adapter class instead of implementing the interface directly.
  */
-public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
+public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
+        Animator.AnimatorPauseListener {
 
     /**
      * {@inheritDoc}
@@ -51,4 +52,17 @@
     public void onAnimationStart(Animator animation) {
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationPause(Animator animation) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationResume(Animator animation) {
+    }
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index b48853b..018a2d6 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -455,6 +455,36 @@
         }
     }
 
+    @Override
+    public void pause() {
+        boolean previouslyPaused = mPaused;
+        super.pause();
+        if (!previouslyPaused && mPaused) {
+            if (mDelayAnim != null) {
+                mDelayAnim.pause();
+            } else {
+                for (Node node : mNodes) {
+                    node.animation.pause();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void resume() {
+        boolean previouslyPaused = mPaused;
+        super.resume();
+        if (previouslyPaused && !mPaused) {
+            if (mDelayAnim != null) {
+                mDelayAnim.resume();
+            } else {
+                for (Node node : mNodes) {
+                    node.animation.resume();
+                }
+            }
+        }
+    }
+
     /**
      * {@inheritDoc}
      *
@@ -467,6 +497,7 @@
     public void start() {
         mTerminated = false;
         mStarted = true;
+        mPaused = false;
 
         if (mDuration >= 0) {
             // If the duration was set on this AnimatorSet, pass it along to all child animations
@@ -549,6 +580,7 @@
                             mPlayingSet.add(node.animation);
                         }
                     }
+                    mDelayAnim = null;
                 }
             });
             mDelayAnim.start();
@@ -787,6 +819,7 @@
                         }
                     }
                     mAnimatorSet.mStarted = false;
+                    mAnimatorSet.mPaused = false;
                 }
             }
         }
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 173ee73..9c88ccf 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -123,9 +123,37 @@
      * in a call to the function <code>setFoo()</code> on the target object. If either
      * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
      * also be derived and called.
+     *
+     * <p>If this animator was created with a {@link Property} object instead of the
+     * string name of a property, then this method will return the {@link
+     * Property#getName() name} of that Property object instead. If this animator was
+     * created with one or more {@link PropertyValuesHolder} objects, then this method
+     * will return the {@link PropertyValuesHolder#getPropertyName() name} of that
+     * object (if there was just one) or a comma-separated list of all of the
+     * names (if there are more than one).</p>
      */
     public String getPropertyName() {
-        return mPropertyName;
+        String propertyName = null;
+        if (mPropertyName != null) {
+            propertyName = mPropertyName;
+        } else if (mProperty != null) {
+            propertyName = mProperty.getName();
+        } else if (mValues != null && mValues.length > 0) {
+            for (int i = 0; i < mValues.length; ++i) {
+                if (i == 0) {
+                    propertyName = "";
+                } else {
+                    propertyName += ",";
+                }
+                propertyName += mValues[i].getPropertyName();
+            }
+        }
+        return propertyName;
+    }
+
+    @Override
+    String getNameForTrace() {
+        return "animator:" + getPropertyName();
     }
 
     /**
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 5b1a7cf..43014ad 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -636,7 +636,7 @@
     }
 
     /**
-     * The TypeEvaluator will the automatically determined based on the type of values
+     * The TypeEvaluator will be automatically determined based on the type of values
      * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
      * desired. This may be important in cases where either the type of the values supplied
      * do not match the way that they should be interpolated between, or if the values
diff --git a/core/java/android/animation/TypeEvaluator.java b/core/java/android/animation/TypeEvaluator.java
index e738da1..2640457 100644
--- a/core/java/android/animation/TypeEvaluator.java
+++ b/core/java/android/animation/TypeEvaluator.java
@@ -19,7 +19,7 @@
 /**
  * Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
  * allow developers to create animations on arbitrary property types, by allowing them to supply
- * custom evaulators for types that are not automatically understood and used by the animation
+ * custom evaluators for types that are not automatically understood and used by the animation
  * system.
  *
  * @see ValueAnimator#setEvaluator(TypeEvaluator)
@@ -41,4 +41,4 @@
      */
     public T evaluate(float fraction, T startValue, T endValue);
 
-}
\ No newline at end of file
+}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index cb44264..86da673 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -80,6 +80,20 @@
      */
     long mSeekTime = -1;
 
+    /**
+     * Set on the next frame after pause() is called, used to calculate a new startTime
+     * or delayStartTime which allows the animator to continue from the point at which
+     * it was paused. If negative, has not yet been set.
+     */
+    private long mPauseTime;
+
+    /**
+     * Set when an animator is resumed. This triggers logic in the next frame which
+     * actually resumes the animator.
+     */
+    private boolean mResumed = false;
+
+
     // The static sAnimationHandler processes the internal timing loop on which all animations
     // are based
     /**
@@ -147,7 +161,7 @@
     private boolean mStarted = false;
 
     /**
-     * Tracks whether we've notified listeners of the onAnimationSTart() event. This can be
+     * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
      * complex to keep track of since we notify listeners at different times depending on
      * startDelay and whether start() was called before end().
      */
@@ -869,7 +883,7 @@
      *
      * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
      * will be used for that set. If there are several sets of values being animated, which is
-     * the case if PropertyValuesHOlder objects were set on the ValueAnimator, then the evaluator
+     * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator
      * is assigned just to the first PropertyValuesHolder object.</p>
      *
      * @param value the evaluator to be used this animation
@@ -914,6 +928,7 @@
         mPlayingState = STOPPED;
         mStarted = true;
         mStartedDelay = false;
+        mPaused = false;
         AnimationHandler animationHandler = getOrCreateAnimationHandler();
         animationHandler.mPendingAnimations.add(this);
         if (mStartDelay == 0) {
@@ -971,6 +986,24 @@
     }
 
     @Override
+    public void resume() {
+        if (mPaused) {
+            mResumed = true;
+        }
+        super.resume();
+    }
+
+    @Override
+    public void pause() {
+        boolean previouslyPaused = mPaused;
+        super.pause();
+        if (!previouslyPaused && mPaused) {
+            mPauseTime = -1;
+            mResumed = false;
+        }
+    }
+
+    @Override
     public boolean isRunning() {
         return (mPlayingState == RUNNING || mRunning);
     }
@@ -994,6 +1027,8 @@
             long currentPlayTime = currentTime - mStartTime;
             long timeLeft = mDuration - currentPlayTime;
             mStartTime = currentTime - timeLeft;
+        } else if (mStarted) {
+            end();
         } else {
             start(true);
         }
@@ -1008,6 +1043,7 @@
         handler.mPendingAnimations.remove(this);
         handler.mDelayedAnims.remove(this);
         mPlayingState = STOPPED;
+        mPaused = false;
         if ((mStarted || mRunning) && mListeners != null) {
             if (!mRunning) {
                 // If it's not yet running, then start listeners weren't called. Call them now.
@@ -1024,8 +1060,10 @@
         mStarted = false;
         mStartListenersCalled = false;
         mPlayingBackwards = false;
-        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "animator",
-                System.identityHashCode(this));
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
+                    System.identityHashCode(this));
+        }
     }
 
     /**
@@ -1033,8 +1071,10 @@
      * called on the UI thread.
      */
     private void startAnimation(AnimationHandler handler) {
-        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "animator",
-                System.identityHashCode(this));
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
+                    System.identityHashCode(this));
+        }
         initAnimation();
         handler.mAnimations.add(this);
         if (mStartDelay > 0 && mListeners != null) {
@@ -1045,6 +1085,14 @@
     }
 
     /**
+     * Returns the name of this animator for debugging purposes.
+     */
+    String getNameForTrace() {
+        return "animator";
+    }
+
+
+    /**
      * Internal function called to process an animation frame on an animation that is currently
      * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
      * should be woken up and put on the active animations queue.
@@ -1059,6 +1107,18 @@
             mStartedDelay = true;
             mDelayStartTime = currentTime;
         } else {
+            if (mPaused) {
+                if (mPauseTime < 0) {
+                    mPauseTime = currentTime;
+                }
+                return false;
+            } else if (mResumed) {
+                mResumed = false;
+                if (mPauseTime > 0) {
+                    // Offset by the duration that the animation was paused
+                    mDelayStartTime += (currentTime - mPauseTime);
+                }
+            }
             long deltaTime = currentTime - mDelayStartTime;
             if (deltaTime > mStartDelay) {
                 // startDelay ended - start the anim and record the
@@ -1081,7 +1141,7 @@
      *
      * @param currentTime The current time, as tracked by the static timing handler
      * @return true if the animation's duration, including any repetitions due to
-     * <code>repeatCount</code> has been exceeded and the animation should be ended.
+     * <code>repeatCount</code>, has been exceeded and the animation should be ended.
      */
     boolean animationFrame(long currentTime) {
         boolean done = false;
@@ -1136,6 +1196,18 @@
                 mSeekTime = -1;
             }
         }
+        if (mPaused) {
+            if (mPauseTime < 0) {
+                mPauseTime = frameTime;
+            }
+            return false;
+        } else if (mResumed) {
+            mResumed = false;
+            if (mPauseTime > 0) {
+                // Offset by the duration that the animation was paused
+                mStartTime += (frameTime - mPauseTime);
+            }
+        }
         // The frame time might be before the start time during the first frame of
         // an animation.  The "current time" must always be on or after the start
         // time to avoid animating frames at negative time intervals.  In practice, this
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6b5df7f..a38fbbf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.util.ArrayMap;
+import android.util.SuperNotCalledException;
 import com.android.internal.app.ActionBarImpl;
 import com.android.internal.policy.PolicyManager;
 
@@ -686,6 +688,7 @@
     boolean mFinished;
     boolean mStartedActivity;
     private boolean mDestroyed;
+    private boolean mDoReportFullyDrawn = true;
     /** true if the activity is going through a transient pause */
     /*package*/ boolean mTemporaryPause = false;
     /** true if the activity is being destroyed in order to recreate it with a new configuration */
@@ -699,7 +702,7 @@
         Object activity;
         HashMap<String, Object> children;
         ArrayList<Fragment> fragments;
-        HashMap<String, LoaderManagerImpl> loaders;
+        ArrayMap<String, LoaderManagerImpl> loaders;
     }
     /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
     
@@ -724,7 +727,7 @@
         }
     };
     
-    HashMap<String, LoaderManagerImpl> mAllLoaderManagers;
+    ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
     LoaderManagerImpl mLoaderManager;
     
     private static final class ManagedCursor {
@@ -744,6 +747,8 @@
     // protected by synchronized (this) 
     int mResultCode = RESULT_CANCELED;
     Intent mResultData = null;
+    private TranslucentConversionListener mTranslucentCallback;
+    private boolean mChangeCanvasToTranslucent;
 
     private boolean mTitleReady = false;
 
@@ -817,13 +822,13 @@
             return mLoaderManager;
         }
         mCheckedForLoaderManager = true;
-        mLoaderManager = getLoaderManager(null, mLoadersStarted, true);
+        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
         return mLoaderManager;
     }
     
     LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
         if (mAllLoaderManagers == null) {
-            mAllLoaderManagers = new HashMap<String, LoaderManagerImpl>();
+            mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();
         }
         LoaderManagerImpl lm = mAllLoaderManagers.get(who);
         if (lm == null) {
@@ -1034,7 +1039,7 @@
             if (mLoaderManager != null) {
                 mLoaderManager.doStart();
             } else if (!mCheckedForLoaderManager) {
-                mLoaderManager = getLoaderManager(null, mLoadersStarted, false);
+                mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
             }
             mCheckedForLoaderManager = true;
         }
@@ -1381,6 +1386,7 @@
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
         getApplication().dispatchActivityStopped(this);
+        mTranslucentCallback = null;
         mCalled = true;
     }
 
@@ -1449,6 +1455,27 @@
     }
 
     /**
+     * Report to the system that your app is now fully drawn.  This is only used
+     * to help instrument app launch times, so that the app can report when it is
+     * fully in a usable state; without this, all the system can determine is when
+     * its window is first drawn and displayed.  To participate in app launch time
+     * measurement, you should always call this method after first launch (when
+     * {@link #onCreate(android.os.Bundle)} is called) at the point where you have
+     * entirely drawn your UI and populated with all of the significant data.  You
+     * can safely call this method any time after first launch as well, in which case
+     * it will simply be ignored.
+     */
+    public void reportFullyDrawn() {
+        if (mDoReportFullyDrawn) {
+            mDoReportFullyDrawn = false;
+            try {
+                ActivityManagerNative.getDefault().reportActivityFullyDrawn(mToken);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
      * Called by the system when the device configuration changes while your
      * activity is running.  Note that this will <em>only</em> be called if
      * you have selected configurations you would like to handle with the
@@ -1624,17 +1651,18 @@
         if (mAllLoaderManagers != null) {
             // prune out any loader managers that were already stopped and so
             // have nothing useful to retain.
-            LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
-            mAllLoaderManagers.values().toArray(loaders);
-            if (loaders != null) {
-                for (int i=0; i<loaders.length; i++) {
-                    LoaderManagerImpl lm = loaders[i];
-                    if (lm.mRetaining) {
-                        retainLoaders = true;
-                    } else {
-                        lm.doDestroy();
-                        mAllLoaderManagers.remove(lm.mWho);
-                    }
+            final int N = mAllLoaderManagers.size();
+            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+            for (int i=N-1; i>=0; i--) {
+                loaders[i] = mAllLoaderManagers.valueAt(i);
+            }
+            for (int i=0; i<N; i++) {
+                LoaderManagerImpl lm = loaders[i];
+                if (lm.mRetaining) {
+                    retainLoaders = true;
+                } else {
+                    lm.doDestroy();
+                    mAllLoaderManagers.remove(lm.mWho);
                 }
             }
         }
@@ -1877,9 +1905,12 @@
         if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
             return;
         }
-        
+
         mActionBar = new ActionBarImpl(this);
         mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
+
+        mWindow.setDefaultIcon(mActivityInfo.getIconResource());
+        mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
     }
     
     /**
@@ -3406,6 +3437,12 @@
                 // activity is finished, no matter what happens to it.
                 mStartedActivity = true;
             }
+
+            final View decor = mWindow != null ? mWindow.peekDecorView() : null;
+            if (decor != null) {
+                decor.cancelPendingInputEvents();
+            }
+            // TODO Consider clearing/flushing other event sources and events for child windows.
         } else {
             if (options != null) {
                 mParent.startActivityFromChild(this, intent, requestCode, options);
@@ -4859,6 +4896,74 @@
     }
 
     /**
+     * Convert a translucent themed Activity {@link android.R.attr#windowIsTranslucent} to a
+     * fullscreen opaque Activity.
+     * <p>
+     * Call this whenever the background of a translucent Activity has changed to become opaque.
+     * Doing so will allow the {@link android.view.Surface} of the Activity behind to be released.
+     * <p>
+     * This call has no effect on non-translucent activities or on activities with the
+     * {@link android.R.attr#windowIsFloating} attribute.
+     *
+     * @see #convertToTranslucent(TranslucentConversionListener)
+     * @see TranslucentConversionListener
+     *
+     * @hide
+     */
+    public void convertFromTranslucent() {
+        try {
+            mTranslucentCallback = null;
+            if (ActivityManagerNative.getDefault().convertFromTranslucent(mToken)) {
+                WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, true);
+            }
+        } catch (RemoteException e) {
+            // pass
+        }
+    }
+
+    /**
+     * Convert a translucent themed Activity {@link android.R.attr#windowIsTranslucent} back from
+     * opaque to translucent following a call to {@link #convertFromTranslucent()}.
+     * <p>
+     * Calling this allows the Activity behind this one to be seen again. Once all such Activities
+     * have been redrawn {@link TranslucentConversionListener#onTranslucentConversionComplete} will
+     * be called indicating that it is safe to make this activity translucent again. Until
+     * {@link TranslucentConversionListener#onTranslucentConversionComplete} is called the image
+     * behind the frontmost Activity will be indeterminate.
+     * <p>
+     * This call has no effect on non-translucent activities or on activities with the
+     * {@link android.R.attr#windowIsFloating} attribute.
+     *
+     * @param callback the method to call when all visible Activities behind this one have been
+     * drawn and it is safe to make this Activity translucent again.
+     *
+     * @see #convertFromTranslucent()
+     * @see TranslucentConversionListener
+     *
+     * @hide
+     */
+    public void convertToTranslucent(TranslucentConversionListener callback) {
+        try {
+            mTranslucentCallback = callback;
+            mChangeCanvasToTranslucent =
+                    ActivityManagerNative.getDefault().convertToTranslucent(mToken);
+        } catch (RemoteException e) {
+            // pass
+        }
+    }
+
+    /** @hide */
+    void onTranslucentConversionComplete(boolean drawComplete) {
+        if (mTranslucentCallback != null) {
+            mTranslucentCallback.onTranslucentConversionComplete(drawComplete);
+            mTranslucentCallback = null;
+        }
+        if (mChangeCanvasToTranslucent) {
+            WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false);
+        }
+    }
+
+    /**
      * Adjust the current immersive mode setting.
      *
      * Note that changing this value will have no effect on the activity's
@@ -4903,6 +5008,7 @@
      * @return The new action mode, or <code>null</code> if the activity does not want to
      *         provide special handling for this action mode. (It will be handled by the system.)
      */
+    @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         initActionBar();
         if (mActionBar != null) {
@@ -4917,6 +5023,7 @@
      *
      * @param mode The new action mode.
      */
+    @Override
     public void onActionModeStarted(ActionMode mode) {
     }
 
@@ -4926,6 +5033,7 @@
      *
      * @param mode The action mode that just finished.
      */
+    @Override
     public void onActionModeFinished(ActionMode mode) {
     }
 
@@ -5148,14 +5256,15 @@
         }
         mFragments.dispatchStart();
         if (mAllLoaderManagers != null) {
-            LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
-            mAllLoaderManagers.values().toArray(loaders);
-            if (loaders != null) {
-                for (int i=0; i<loaders.length; i++) {
-                    LoaderManagerImpl lm = loaders[i];
-                    lm.finishRetain();
-                    lm.doReportStart();
-                }
+            final int N = mAllLoaderManagers.size();
+            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+            for (int i=N-1; i>=0; i--) {
+                loaders[i] = mAllLoaderManagers.valueAt(i);
+            }
+            for (int i=0; i<N; i++) {
+                LoaderManagerImpl lm = loaders[i];
+                lm.finishRetain();
+                lm.doReportStart();
             }
         }
     }
@@ -5230,6 +5339,7 @@
     }
 
     final void performPause() {
+        mDoReportFullyDrawn = false;
         mFragments.dispatchPause();
         mCalled = false;
         onPause();
@@ -5249,6 +5359,7 @@
     }
     
     final void performStop() {
+        mDoReportFullyDrawn = false;
         if (mLoadersStarted) {
             mLoadersStarted = false;
             if (mLoaderManager != null) {
@@ -5327,4 +5438,28 @@
             }
         }
     }
+
+    /**
+     * Interface for informing a translucent {@link Activity} once all visible activities below it
+     * have completed drawing. This is necessary only after an {@link Activity} has been made
+     * opaque using {@link Activity#convertFromTranslucent()} and before it has been drawn
+     * translucent again following a call to {@link
+     * Activity#convertToTranslucent(TranslucentConversionListener)}.
+     *
+     * @hide
+     */
+    public interface TranslucentConversionListener {
+        /**
+         * Callback made following {@link Activity#convertToTranslucent} once all visible Activities
+         * below the top one have been redrawn. Following this callback it is safe to make the top
+         * Activity translucent because the underlying Activity has been drawn.
+         *
+         * @param drawComplete True if the background Activity has drawn itself. False if a timeout
+         * occurred waiting for the Activity to complete drawing.
+         *
+         * @see Activity#convertFromTranslucent()
+         * @see Activity#convertToTranslucent(TranslucentConversionListener)
+         */
+        public void onTranslucentConversionComplete(boolean drawComplete);
+    }
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a25e311..1e65098 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,10 +16,13 @@
 
 package android.app;
 
-import android.R;
+import android.os.BatteryStats;
+import android.os.IBinder;
 import com.android.internal.app.IUsageStats;
+import com.android.internal.app.ProcessStats;
 import com.android.internal.os.PkgUsageStats;
-import com.android.internal.util.MemInfoReader;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.util.FastPrintWriter;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -31,10 +34,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.os.Binder;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -49,8 +49,10 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
-import android.view.Display;
 
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -66,6 +68,13 @@
     private final Handler mHandler;
 
     /**
+     * <meta-data> string for a 'home' Activity that names a package that is to be
+     * uninstalled in lieu of the declaring one.  The package named here must be
+     * signed with the same certificate as the one declaring the <meta-data>.
+     */
+    public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
+
+    /**
      * Result for IActivityManager.startActivity: an error where the
      * start had to be canceled.
      * @hide
@@ -222,6 +231,56 @@
     /** @hide User operation call: given user id is the current user, can't be stopped. */
     public static final int USER_OP_IS_CURRENT = -2;
 
+    /** @hide Process is a persistent system process. */
+    public static final int PROCESS_STATE_PERSISTENT = 0;
+
+    /** @hide Process is a persistent system process and is doing UI. */
+    public static final int PROCESS_STATE_PERSISTENT_UI = 1;
+
+    /** @hide Process is hosting the current top activities.  Note that this covers
+     * all activities that are visible to the user. */
+    public static final int PROCESS_STATE_TOP = 2;
+
+    /** @hide Process is important to the user, and something they are aware of. */
+    public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
+
+    /** @hide Process is important to the user, but not something they are aware of. */
+    public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
+
+    /** @hide Process is in the background running a backup/restore operation. */
+    public static final int PROCESS_STATE_BACKUP = 5;
+
+    /** @hide Process is in the background, but it can't restore its state so we want
+     * to try to avoid killing it. */
+    public static final int PROCESS_STATE_HEAVY_WEIGHT = 6;
+
+    /** @hide Process is in the background running a service.  Unlike oom_adj, this level
+     * is used for both the normal running in background state and the executing
+     * operations state. */
+    public static final int PROCESS_STATE_SERVICE = 7;
+
+    /** @hide Process is in the background running a receiver.   Note that from the
+     * perspective of oom_adj receivers run at a higher foreground level, but for our
+     * prioritization here that is not necessary and putting them below services means
+     * many fewer changes in some process states as they receive broadcasts. */
+    public static final int PROCESS_STATE_RECEIVER = 8;
+
+    /** @hide Process is in the background but hosts the home activity. */
+    public static final int PROCESS_STATE_HOME = 9;
+
+    /** @hide Process is in the background but hosts the last shown activity. */
+    public static final int PROCESS_STATE_LAST_ACTIVITY = 10;
+
+    /** @hide Process is being cached for later use and contains activities. */
+    public static final int PROCESS_STATE_CACHED_ACTIVITY = 11;
+
+    /** @hide Process is being cached for later use and is a client of another cached
+     * process that contains activities. */
+    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12;
+
+    /** @hide Process is being cached for later use and is empty. */
+    public static final int PROCESS_STATE_CACHED_EMPTY = 13;
+
     /*package*/ ActivityManager(Context context, Handler handler) {
         mContext = context;
         mHandler = handler;
@@ -370,7 +429,23 @@
         // Really brain dead right now -- just take this from the configured
         // vm heap size, and assume it is in megabytes and thus ends with "m".
         String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");
-        return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length() - 1));
+        return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
+    }
+
+    /**
+     * Returns true if this is a low-RAM device.  Exactly whether a device is low-RAM
+     * is ultimately up to the device configuration, but currently it generally means
+     * something in the class of a 512MB device with about a 800x480 or less screen.
+     * This is mostly intended to be used by apps to determine whether they should turn
+     * off certain features that require more RAM.
+     */
+    public boolean isLowRamDevice() {
+        return isLowRamDeviceStatic();
+    }
+
+    /** @hide */
+    public static boolean isLowRamDeviceStatic() {
+        return "true".equals(SystemProperties.get("ro.config.low_ram", "false"));
     }
 
     /**
@@ -380,43 +455,8 @@
      * @hide
      */
     static public boolean isHighEndGfx() {
-        MemInfoReader reader = new MemInfoReader();
-        reader.readMemInfo();
-        if (reader.getTotalSize() >= (512*1024*1024)) {
-            // If the device has at least 512MB RAM available to the kernel,
-            // we can afford the overhead of graphics acceleration.
-            return true;
-        }
-
-        Display display = DisplayManagerGlobal.getInstance().getRealDisplay(
-                Display.DEFAULT_DISPLAY);
-        Point p = new Point();
-        display.getRealSize(p);
-        int pixels = p.x * p.y;
-        if (pixels >= (1024*600)) {
-            // If this is a sufficiently large screen, then there are enough
-            // pixels on it that we'd really like to use hw drawing.
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Use to decide whether the running device can be considered a "large
-     * RAM" device.  Exactly what memory limit large RAM is will vary, but
-     * it essentially means there is plenty of RAM to have lots of background
-     * processes running under decent loads.
-     * @hide
-     */
-    static public boolean isLargeRAM() {
-        MemInfoReader reader = new MemInfoReader();
-        reader.readMemInfo();
-        if (reader.getTotalSize() >= (640*1024*1024)) {
-            // Currently 640MB RAM available to the kernel is the point at
-            // which we have plenty of RAM to spare.
-            return true;
-        }
-        return false;
+        return !isLowRamDeviceStatic() &&
+                !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel);
     }
 
     /**
@@ -454,14 +494,22 @@
          * Description of the task's last state.
          */
         public CharSequence description;
-        
+
+        /**
+         * The id of the ActivityStack this Task was on most recently.
+         * @hide
+         */
+        public int stackId;
+
         public RecentTaskInfo() {
         }
 
+        @Override
         public int describeContents() {
             return 0;
         }
 
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(id);
             dest.writeInt(persistentId);
@@ -474,6 +522,7 @@
             ComponentName.writeToParcel(origActivity, dest);
             TextUtils.writeToParcel(description, dest,
                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+            dest.writeInt(stackId);
         }
 
         public void readFromParcel(Parcel source) {
@@ -486,8 +535,9 @@
             }
             origActivity = ComponentName.readFromParcel(source);
             description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            stackId = source.readInt();
         }
-        
+
         public static final Creator<RecentTaskInfo> CREATOR
                 = new Creator<RecentTaskInfo>() {
             public RecentTaskInfo createFromParcel(Parcel source) {
@@ -629,6 +679,12 @@
          */
         public int numRunning;
 
+        /**
+         * Last time task was run. For sorting.
+         * @hide
+         */
+        public long lastActiveTime;
+
         public RunningTaskInfo() {
         }
 
@@ -1230,7 +1286,169 @@
         } catch (RemoteException e) {
         }
     }
-    
+
+    /**
+     * Information you can retrieve about the WindowManager StackBox hierarchy.
+     * @hide
+     */
+    public static class StackBoxInfo implements Parcelable {
+        public int stackBoxId;
+        public float weight;
+        public boolean vertical;
+        public Rect bounds;
+        public StackBoxInfo[] children;
+        public int stackId;
+        public StackInfo stack;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(stackBoxId);
+            dest.writeFloat(weight);
+            dest.writeInt(vertical ? 1 : 0);
+            bounds.writeToParcel(dest, flags);
+            dest.writeInt(stackId);
+            if (children != null) {
+                children[0].writeToParcel(dest, flags);
+                children[1].writeToParcel(dest, flags);
+            } else {
+                stack.writeToParcel(dest, flags);
+            }
+        }
+
+        public void readFromParcel(Parcel source) {
+            stackBoxId = source.readInt();
+            weight = source.readFloat();
+            vertical = source.readInt() == 1;
+            bounds = Rect.CREATOR.createFromParcel(source);
+            stackId = source.readInt();
+            if (stackId == -1) {
+                children = new StackBoxInfo[2];
+                children[0] = StackBoxInfo.CREATOR.createFromParcel(source);
+                children[1] = StackBoxInfo.CREATOR.createFromParcel(source);
+            } else {
+                stack = StackInfo.CREATOR.createFromParcel(source);
+            }
+        }
+
+        public static final Creator<StackBoxInfo> CREATOR =
+                new Creator<ActivityManager.StackBoxInfo>() {
+
+            @Override
+            public StackBoxInfo createFromParcel(Parcel source) {
+                return new StackBoxInfo(source);
+            }
+
+            @Override
+            public StackBoxInfo[] newArray(int size) {
+                return new StackBoxInfo[size];
+            }
+        };
+
+        public StackBoxInfo() {
+        }
+
+        public StackBoxInfo(Parcel source) {
+            readFromParcel(source);
+        }
+
+        public String toString(String prefix) {
+            StringBuilder sb = new StringBuilder(256);
+            sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight);
+            sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString());
+            sb.append("\n");
+            if (children != null) {
+                sb.append(prefix); sb.append("First child=\n");
+                sb.append(children[0].toString(prefix + "  "));
+                sb.append(prefix); sb.append("Second child=\n");
+                sb.append(children[1].toString(prefix + "  "));
+            } else {
+                sb.append(prefix); sb.append("Stack=\n");
+                sb.append(stack.toString(prefix + "  "));
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public String toString() {
+            return toString("");
+        }
+    }
+
+    /**
+     * Information you can retrieve about an ActivityStack in the system.
+     * @hide
+     */
+    public static class StackInfo implements Parcelable {
+        public int stackId;
+        public Rect bounds;
+        public int[] taskIds;
+        public String[] taskNames;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(stackId);
+            dest.writeInt(bounds.left);
+            dest.writeInt(bounds.top);
+            dest.writeInt(bounds.right);
+            dest.writeInt(bounds.bottom);
+            dest.writeIntArray(taskIds);
+            dest.writeStringArray(taskNames);
+        }
+
+        public void readFromParcel(Parcel source) {
+            stackId = source.readInt();
+            bounds = new Rect(
+                    source.readInt(), source.readInt(), source.readInt(), source.readInt());
+            taskIds = source.createIntArray();
+            taskNames = source.createStringArray();
+        }
+
+        public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
+            @Override
+            public StackInfo createFromParcel(Parcel source) {
+                return new StackInfo(source);
+            }
+            @Override
+            public StackInfo[] newArray(int size) {
+                return new StackInfo[size];
+            }
+        };
+
+        public StackInfo() {
+        }
+
+        private StackInfo(Parcel source) {
+            readFromParcel(source);
+        }
+
+        public String toString(String prefix) {
+            StringBuilder sb = new StringBuilder(256);
+            sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
+                    sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n");
+            prefix = prefix + "  ";
+            for (int i = 0; i < taskIds.length; ++i) {
+                sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
+                        sb.append(": "); sb.append(taskNames[i]); sb.append("\n");
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public String toString() {
+            return toString("");
+        }
+    }
+
     /**
      * @hide
      */
@@ -1242,7 +1460,18 @@
             return false;
         }
     }
-    
+
+    /**
+     * Permits an application to erase its own data from disk.  This is equivalent to
+     * the user choosing to clear the app's data from within the device settings UI.
+     *
+     * @return {@code true} if the application successfully requested that the application's
+     *     data be erased; {@code false} otherwise.
+     */
+    public boolean clearApplicationUserData() {
+        return clearApplicationUserData(mContext.getPackageName(), null);
+    }
+
     /**
      * Information you can retrieve about any processes that are in an error condition.
      */
@@ -1304,10 +1533,12 @@
         public ProcessErrorStateInfo() {
         }
 
+        @Override
         public int describeContents() {
             return 0;
         }
 
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(condition);
             dest.writeString(processName);
@@ -1318,7 +1549,7 @@
             dest.writeString(longMsg);
             dest.writeString(stackTrace);
         }
-        
+
         public void readFromParcel(Parcel source) {
             condition = source.readInt();
             processName = source.readString();
@@ -1538,7 +1769,7 @@
         public ComponentName importanceReasonComponent;
         
         /**
-         * When {@link importanceReasonPid} is non-0, this is the importance
+         * When {@link #importanceReasonPid} is non-0, this is the importance
          * of the other pid. @hide
          */
         public int importanceReasonImportance;
@@ -1888,7 +2119,12 @@
         }
         // If the target is not exported, then nobody else can get to it.
         if (!exported) {
-            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
+            /*
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
+                    here);
+            */
             return PackageManager.PERMISSION_DENIED;
         }
         if (permission == null) {
@@ -2010,4 +2246,58 @@
             return false;
         }
     }
+
+    /**
+     * Perform a system dump of various state associated with the given application
+     * package name.  This call blocks while the dump is being performed, so should
+     * not be done on a UI thread.  The data will be written to the given file
+     * descriptor as text.  An application must hold the
+     * {@link android.Manifest.permission#DUMP} permission to make this call.
+     * @param fd The file descriptor that the dump should be written to.
+     * @param packageName The name of the package that is to be dumped.
+     */
+    public void dumpPackageState(FileDescriptor fd, String packageName) {
+        dumpPackageStateStatic(fd, packageName);
+    }
+
+    /**
+     * @hide
+     */
+    public static void dumpPackageStateStatic(FileDescriptor fd, String packageName) {
+        FileOutputStream fout = new FileOutputStream(fd);
+        PrintWriter pw = new FastPrintWriter(fout);
+        dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName });
+        pw.println();
+        dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName });
+        pw.println();
+        dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName });
+        pw.println();
+        dumpService(pw, fd, "package", new String[] { packageName });
+        pw.println();
+        dumpService(pw, fd, BatteryStats.SERVICE_NAME, new String[] { packageName });
+        pw.flush();
+    }
+
+    private static void dumpService(PrintWriter pw, FileDescriptor fd, String name, String[] args) {
+        pw.print("DUMP OF SERVICE "); pw.print(name); pw.println(":");
+        IBinder service = ServiceManager.checkService(name);
+        if (service == null) {
+            pw.println("  (Service not found)");
+            return;
+        }
+        TransferPipe tp = null;
+        try {
+            pw.flush();
+            tp = new TransferPipe();
+            tp.setBufferPrefix("  ");
+            service.dump(tp.getWriteFd().getFileDescriptor(), args);
+            tp.go(fd);
+        } catch (Throwable e) {
+            if (tp != null) {
+                tp.kill();
+            }
+            pw.println("Failure dumping service:");
+            e.printStackTrace(pw);
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d4478bf..961ee57 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,15 +16,18 @@
 
 package android.app;
 
+import android.app.ActivityManager.StackBoxInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.UriPermission;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -107,7 +110,8 @@
     public ActivityManagerNative() {
         attachInterface(this, descriptor);
     }
-    
+
+    @Override
     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
             throws RemoteException {
         switch (code) {
@@ -150,7 +154,7 @@
             int startFlags = data.readInt();
             String profileFile = data.readString();
             ParcelFileDescriptor profileFd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             Bundle options = data.readInt() != 0
                     ? Bundle.CREATOR.createFromParcel(data) : null;
             int userId = data.readInt();
@@ -176,7 +180,7 @@
             int startFlags = data.readInt();
             String profileFile = data.readString();
             ParcelFileDescriptor profileFd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             Bundle options = data.readInt() != 0
                     ? Bundle.CREATOR.createFromParcel(data) : null;
             int userId = data.readInt();
@@ -197,7 +201,7 @@
             Intent intent = Intent.CREATOR.createFromParcel(data);
             String resolvedType = data.readString();
             IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();    
+            String resultWho = data.readString();
             int requestCode = data.readInt();
             int startFlags = data.readInt();
             Configuration config = Configuration.CREATOR.createFromParcel(data);
@@ -223,7 +227,7 @@
             }
             String resolvedType = data.readString();
             IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();    
+            String resultWho = data.readString();
             int requestCode = data.readInt();
             int flagsMask = data.readInt();
             int flagsValues = data.readInt();
@@ -236,7 +240,7 @@
             reply.writeInt(result);
             return true;
         }
-        
+
         case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -267,7 +271,7 @@
         case FINISH_SUB_ACTIVITY_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            String resultWho = data.readString();    
+            String resultWho = data.readString();
             int requestCode = data.readInt();
             finishSubActivity(token, resultWho, requestCode);
             reply.writeNoException();
@@ -478,14 +482,13 @@
             IThumbnailReceiver receiver = receiverBinder != null
                 ? IThumbnailReceiver.Stub.asInterface(receiverBinder)
                 : null;
-            List list = getTasks(maxNum, fl, receiver);
+            List<ActivityManager.RunningTaskInfo> list = getTasks(maxNum, fl, receiver);
             reply.writeNoException();
             int N = list != null ? list.size() : -1;
             reply.writeInt(N);
             int i;
             for (i=0; i<N; i++) {
-                ActivityManager.RunningTaskInfo info =
-                        (ActivityManager.RunningTaskInfo)list.get(i);
+                ActivityManager.RunningTaskInfo info = list.get(i);
                 info.writeToParcel(reply, 0);
             }
             return true;
@@ -535,14 +538,13 @@
             data.enforceInterface(IActivityManager.descriptor);
             int maxNum = data.readInt();
             int fl = data.readInt();
-            List list = getServices(maxNum, fl);
+            List<ActivityManager.RunningServiceInfo> list = getServices(maxNum, fl);
             reply.writeNoException();
             int N = list != null ? list.size() : -1;
             reply.writeInt(N);
             int i;
             for (i=0; i<N; i++) {
-                ActivityManager.RunningServiceInfo info =
-                        (ActivityManager.RunningServiceInfo)list.get(i);
+                ActivityManager.RunningServiceInfo info = list.get(i);
                 info.writeToParcel(reply, 0);
             }
             return true;
@@ -555,7 +557,7 @@
             reply.writeTypedList(list);
             return true;
         }
-        
+
         case GET_RUNNING_APP_PROCESSES_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             List<ActivityManager.RunningAppProcessInfo> list = getRunningAppProcesses();
@@ -609,6 +611,67 @@
             return true;
         }
 
+        case CREATE_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            int relativeStackId = data.readInt();
+            int position = data.readInt();
+            float weight = data.readFloat();
+            int res = createStack(taskId, relativeStackId, position, weight);
+            reply.writeNoException();
+            reply.writeInt(res);
+            return true;
+        }
+
+        case MOVE_TASK_TO_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            int stackId = data.readInt();
+            boolean toTop = data.readInt() != 0;
+            moveTaskToStack(taskId, stackId, toTop);
+            reply.writeNoException();
+            return true;
+        }
+
+        case RESIZE_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int stackBoxId = data.readInt();
+            float weight = data.readFloat();
+            resizeStackBox(stackBoxId, weight);
+            reply.writeNoException();
+            return true;
+        }
+
+        case GET_STACK_BOXES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            List<StackBoxInfo> list = getStackBoxes();
+            reply.writeNoException();
+            reply.writeTypedList(list);
+            return true;
+        }
+
+        case GET_STACK_BOX_INFO_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int stackBoxId = data.readInt();
+            StackBoxInfo info = getStackBoxInfo(stackBoxId);
+            reply.writeNoException();
+            if (info != null) {
+                reply.writeInt(1);
+                info.writeToParcel(reply, 0);
+            } else {
+                reply.writeInt(0);
+            }
+            return true;
+        }
+
+        case SET_FOCUSED_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int stackId = data.readInt();
+            setFocusedStack(stackId);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_TASK_FOR_ACTIVITY_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -695,6 +758,14 @@
             return true;
         }
 
+        case APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder b = data.readStrongBinder();
+            appNotRespondingViaProvider(b);
+            reply.writeNoException();
+            return true;
+        }
+
         case REMOVE_CONTENT_PROVIDER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -1033,9 +1104,9 @@
             reply.writeInt(res);
             return true;
         }
-        
+
         case CLEAR_APP_DATA_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);            
+            data.enforceInterface(IActivityManager.descriptor);
             String packageName = data.readString();
             IPackageDataObserver observer = IPackageDataObserver.Stub.asInterface(
                     data.readStrongBinder());
@@ -1045,7 +1116,7 @@
             reply.writeInt(res ? 1 : 0);
             return true;
         }
-        
+
         case GRANT_URI_PERMISSION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -1057,7 +1128,7 @@
             reply.writeNoException();
             return true;
         }
-        
+
         case REVOKE_URI_PERMISSION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -1068,7 +1139,33 @@
             reply.writeNoException();
             return true;
         }
-        
+
+        case TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            Uri uri = Uri.CREATOR.createFromParcel(data);
+            int mode = data.readInt();
+            takePersistableUriPermission(uri, mode);
+            reply.writeNoException();
+            return true;
+        }
+
+        case RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            Uri uri = Uri.CREATOR.createFromParcel(data);
+            int mode = data.readInt();
+            releasePersistableUriPermission(uri, mode);
+            reply.writeNoException();
+            return true;
+        }
+
+        case GET_PERSISTED_URI_PERMISSIONS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final ParceledListSlice<UriPermission> perms = getPersistedUriPermissions();
+            reply.writeNoException();
+            perms.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+            return true;
+        }
+
         case SHOW_WAITING_FOR_DEBUGGER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -1257,7 +1354,7 @@
             reply.writeNoException();
             return true;
         }
-        
+
         case FORCE_STOP_PACKAGE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String packageName = data.readString();
@@ -1293,7 +1390,7 @@
             int profileType = data.readInt();
             String path = data.readString();
             ParcelFileDescriptor fd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             boolean res = profileControl(process, userId, start, path, fd, profileType);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
@@ -1363,7 +1460,8 @@
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
             int appid = data.readInt();
-            killApplicationWithAppId(pkg, appid);
+            String reason = data.readString();
+            killApplicationWithAppId(pkg, appid, reason);
             reply.writeNoException();
             return true;
         }
@@ -1437,6 +1535,24 @@
             return true;
         }
 
+        case CONVERT_FROM_TRANSLUCENT_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            boolean converted = convertFromTranslucent(token);
+            reply.writeNoException();
+            reply.writeInt(converted ? 1 : 0);
+            return true;
+        }
+
+        case CONVERT_TO_TRANSLUCENT_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            boolean converted = convertToTranslucent(token);
+            reply.writeNoException();
+            reply.writeInt(converted ? 1 : 0);
+            return true;
+        }
+
         case SET_IMMERSIVE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -1528,7 +1644,7 @@
             boolean managed = data.readInt() != 0;
             String path = data.readString();
             ParcelFileDescriptor fd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             boolean res = dumpHeap(process, userId, managed, path, fd);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
@@ -1837,26 +1953,27 @@
             data.enforceInterface(IActivityManager.descriptor);
             int pid = data.readInt();
             boolean aboveSystem = data.readInt() != 0;
-            long res = inputDispatchingTimedOut(pid, aboveSystem);
+            String reason = data.readString();
+            long res = inputDispatchingTimedOut(pid, aboveSystem, reason);
             reply.writeNoException();
             reply.writeLong(res);
             return true;
         }
 
-        case GET_TOP_ACTIVITY_EXTRAS_TRANSACTION: {
+        case GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int requestType = data.readInt();
-            Bundle res = getTopActivityExtras(requestType);
+            Bundle res = getAssistContextExtras(requestType);
             reply.writeNoException();
             reply.writeBundle(res);
             return true;
         }
 
-        case REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION: {
+        case REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
             Bundle extras = data.readBundle();
-            reportTopActivityExtras(token, extras);
+            reportAssistContextExtras(token, extras);
             reply.writeNoException();
             return true;
         }
@@ -1879,6 +1996,35 @@
             return true;
         }
 
+        case REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            reportActivityFullyDrawn(token);
+            reply.writeNoException();
+            return true;
+        }
+
+        case NOTIFY_ACTIVITY_DRAWN_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            notifyActivityDrawn(token);
+            reply.writeNoException();
+            return true;
+        }
+
+        case RESTART_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            restart();
+            reply.writeNoException();
+            return true;
+        }
+
+        case PERFORM_IDLE_MAINTENANCE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            performIdleMaintenance();
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -2565,6 +2711,94 @@
         data.recycle();
         reply.recycle();
     }
+    @Override
+    public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
+            throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        data.writeInt(relativeStackBoxId);
+        data.writeInt(position);
+        data.writeFloat(weight);
+        mRemote.transact(CREATE_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+    @Override
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        data.writeInt(stackId);
+        data.writeInt(toTop ? 1 : 0);
+        mRemote.transact(MOVE_TASK_TO_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    @Override
+    public void resizeStackBox(int stackBoxId, float weight) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(stackBoxId);
+        data.writeFloat(weight);
+        mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    @Override
+    public List<StackBoxInfo> getStackBoxes() throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_STACK_BOXES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        ArrayList<StackBoxInfo> list = reply.createTypedArrayList(StackBoxInfo.CREATOR);
+        data.recycle();
+        reply.recycle();
+        return list;
+    }
+    @Override
+    public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(stackBoxId);
+        mRemote.transact(GET_STACK_BOX_INFO_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        StackBoxInfo info = null;
+        if (res != 0) {
+            info = StackBoxInfo.CREATOR.createFromParcel(reply);
+        }
+        data.recycle();
+        reply.recycle();
+        return info;
+    }
+    @Override
+    public void setFocusedStack(int stackId) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(stackId);
+        mRemote.transact(SET_FOCUSED_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -2665,6 +2899,7 @@
         reply.recycle();
         return res;
     }
+
     public void unstableProviderDied(IBinder connection) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2676,6 +2911,18 @@
         reply.recycle();
     }
 
+    @Override
+    public void appNotRespondingViaProvider(IBinder connection) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(connection);
+        mRemote.transact(APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -3173,7 +3420,7 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
-        data.writeStrongBinder(observer.asBinder());
+        data.writeStrongBinder((observer != null) ? observer.asBinder() : null);
         data.writeInt(userId);
         mRemote.transact(CLEAR_APP_DATA_TRANSACTION, data, reply, 0);
         reply.readException();
@@ -3225,6 +3472,47 @@
         data.recycle();
         reply.recycle();
     }
+
+    @Override
+    public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        uri.writeToParcel(data, 0);
+        data.writeInt(mode);
+        mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        uri.writeToParcel(data, 0);
+        data.writeInt(mode);
+        mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public ParceledListSlice<UriPermission> getPersistedUriPermissions() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_PERSISTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel(
+                reply);
+        data.recycle();
+        reply.recycle();
+        return perms;
+    }
+
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -3575,12 +3863,14 @@
         data.recycle();
     }
     
-    public void killApplicationWithAppId(String pkg, int appid) throws RemoteException {
+    public void killApplicationWithAppId(String pkg, int appid, String reason)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(pkg);
         data.writeInt(appid);
+        data.writeString(reason);
         mRemote.transact(KILL_APPLICATION_WITH_APPID_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -3671,7 +3961,35 @@
         data.recycle();
         reply.recycle();
     }
-    
+
+    public boolean convertFromTranslucent(IBinder token)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(CONVERT_FROM_TRANSLUCENT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean res = reply.readInt() != 0;
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
+    public boolean convertToTranslucent(IBinder token)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean res = reply.readInt() != 0;
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     public void setImmersive(IBinder token, boolean immersive)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -4228,12 +4546,14 @@
         reply.recycle();
     }
 
-    public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException {
+    public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(pid);
         data.writeInt(aboveSystem ? 1 : 0);
+        data.writeString(reason);
         mRemote.transact(INPUT_DISPATCHING_TIMED_OUT_TRANSACTION, data, reply, 0);
         reply.readException();
         long res = reply.readInt();
@@ -4242,12 +4562,12 @@
         return res;
     }
 
-    public Bundle getTopActivityExtras(int requestType) throws RemoteException {
+    public Bundle getAssistContextExtras(int requestType) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(requestType);
-        mRemote.transact(GET_TOP_ACTIVITY_EXTRAS_TRANSACTION, data, reply, 0);
+        mRemote.transact(GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         Bundle res = reply.readBundle();
         data.recycle();
@@ -4255,13 +4575,14 @@
         return res;
     }
 
-    public void reportTopActivityExtras(IBinder token, Bundle extras) throws RemoteException {
+    public void reportAssistContextExtras(IBinder token, Bundle extras)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         data.writeBundle(extras);
-        mRemote.transact(REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION, data, reply, 0);
+        mRemote.transact(REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -4291,5 +4612,47 @@
         reply.recycle();
     }
 
+    public void reportActivityFullyDrawn(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void notifyActivityDrawn(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(NOTIFY_ACTIVITY_DRAWN_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void restart() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(RESTART_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void performIdleMaintenance() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(PERFORM_IDLE_MAINTENANCE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4268fa6..02faeac 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -69,13 +69,14 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
-import android.view.CompatibilityInfoHolder;
+import android.util.SuperNotCalledException;
 import android.view.Display;
 import android.view.HardwareRenderer;
 import android.view.View;
@@ -91,6 +92,7 @@
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.os.SamplingProfilerIntegration;
+import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.Objects;
 import com.android.org.conscrypt.OpenSSLSocketImpl;
 
@@ -103,8 +105,6 @@
 import java.net.InetAddress;
 import java.security.Security;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -117,12 +117,6 @@
 
 import dalvik.system.CloseGuard;
 
-final class SuperNotCalledException extends AndroidRuntimeException {
-    public SuperNotCalledException(String msg) {
-        super(msg);
-    }
-}
-
 final class RemoteServiceException extends AndroidRuntimeException {
     public RemoteServiceException(String msg) {
         super(msg);
@@ -147,7 +141,7 @@
     public static final boolean DEBUG_BROADCAST = false;
     private static final boolean DEBUG_RESULTS = false;
     private static final boolean DEBUG_BACKUP = false;
-    private static final boolean DEBUG_CONFIGURATION = false;
+    public static final boolean DEBUG_CONFIGURATION = false;
     private static final boolean DEBUG_SERVICE = false;
     private static final boolean DEBUG_MEMORY_TRIM = false;
     private static final boolean DEBUG_PROVIDER = false;
@@ -164,28 +158,26 @@
     final ApplicationThread mAppThread = new ApplicationThread();
     final Looper mLooper = Looper.myLooper();
     final H mH = new H();
-    final HashMap<IBinder, ActivityClientRecord> mActivities
-            = new HashMap<IBinder, ActivityClientRecord>();
+    final ArrayMap<IBinder, ActivityClientRecord> mActivities
+            = new ArrayMap<IBinder, ActivityClientRecord>();
     // List of new activities (via ActivityRecord.nextIdle) that should
     // be reported when next we idle.
     ActivityClientRecord mNewActivities = null;
     // Number of activities that are currently visible on-screen.
     int mNumVisibleActivities = 0;
-    final HashMap<IBinder, Service> mServices
-            = new HashMap<IBinder, Service>();
+    final ArrayMap<IBinder, Service> mServices
+            = new ArrayMap<IBinder, Service>();
     AppBindData mBoundApplication;
     Profiler mProfiler;
     int mCurDefaultDisplayDpi;
     boolean mDensityCompatMode;
     Configuration mConfiguration;
     Configuration mCompatConfiguration;
-    Configuration mResConfiguration;
-    CompatibilityInfo mResCompatibilityInfo;
     Application mInitialApplication;
     final ArrayList<Application> mAllApplications
             = new ArrayList<Application>();
     // set of instantiated backup agents, keyed by package name
-    final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
+    final ArrayMap<String, BackupAgent> mBackupAgents = new ArrayMap<String, BackupAgent>();
     /** Reference to singleton {@link ActivityThread} */
     private static ActivityThread sCurrentActivityThread;
     Instrumentation mInstrumentation;
@@ -205,18 +197,16 @@
     // which means this lock gets held while the activity and window managers
     // holds their own lock.  Thus you MUST NEVER call back into the activity manager
     // or window manager or anything that depends on them while holding this lock.
-    final HashMap<String, WeakReference<LoadedApk>> mPackages
-            = new HashMap<String, WeakReference<LoadedApk>>();
-    final HashMap<String, WeakReference<LoadedApk>> mResourcePackages
-            = new HashMap<String, WeakReference<LoadedApk>>();
-    final HashMap<CompatibilityInfo, DisplayMetrics> mDefaultDisplayMetrics
-            = new HashMap<CompatibilityInfo, DisplayMetrics>();
-    final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
-            = new HashMap<ResourcesKey, WeakReference<Resources> >();
+    final ArrayMap<String, WeakReference<LoadedApk>> mPackages
+            = new ArrayMap<String, WeakReference<LoadedApk>>();
+    final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages
+            = new ArrayMap<String, WeakReference<LoadedApk>>();
     final ArrayList<ActivityClientRecord> mRelaunchingActivities
             = new ArrayList<ActivityClientRecord>();
     Configuration mPendingConfiguration = null;
 
+    private final ResourcesManager mResourcesManager;
+
     private static final class ProviderKey {
         final String authority;
         final int userId;
@@ -242,17 +232,17 @@
     }
 
     // The lock of mProviderMap protects the following variables.
-    final HashMap<ProviderKey, ProviderClientRecord> mProviderMap
-        = new HashMap<ProviderKey, ProviderClientRecord>();
-    final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap
-        = new HashMap<IBinder, ProviderRefCount>();
-    final HashMap<IBinder, ProviderClientRecord> mLocalProviders
-        = new HashMap<IBinder, ProviderClientRecord>();
-    final HashMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
-            = new HashMap<ComponentName, ProviderClientRecord>();
+    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
+        = new ArrayMap<ProviderKey, ProviderClientRecord>();
+    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
+        = new ArrayMap<IBinder, ProviderRefCount>();
+    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
+        = new ArrayMap<IBinder, ProviderClientRecord>();
+    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
+            = new ArrayMap<ComponentName, ProviderClientRecord>();
 
-    final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
-        = new HashMap<Activity, ArrayList<OnActivityPausedListener>>();
+    final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
+        = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
 
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
@@ -534,25 +524,28 @@
         CompatibilityInfo info;
     }
 
-    static final class RequestActivityExtras {
+    static final class RequestAssistContextExtras {
         IBinder activityToken;
         IBinder requestToken;
         int requestType;
     }
-    
+
     private native void dumpGraphicsInfo(FileDescriptor fd);
 
     private class ApplicationThread extends ApplicationThreadNative {
-        private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
+        private static final String HEAP_FULL_COLUMN = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s";
+        private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s %8s";
         private static final String ONE_COUNT_COLUMN = "%21s %8d";
         private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
         // Formatting for checkin service - update version if row format changes
-        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
+        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
+
+        private int mLastProcessState = -1;
 
         private void updatePendingConfiguration(Configuration config) {
-            synchronized (mPackages) {
+            synchronized (mResourcesManager) {
                 if (mPendingConfiguration == null ||
                         mPendingConfiguration.isOtherSeqNewer(config)) {
                     mPendingConfiguration = config;
@@ -586,7 +579,9 @@
             queueOrSendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
         }
 
-        public final void scheduleResumeActivity(IBinder token, boolean isForward) {
+        public final void scheduleResumeActivity(IBinder token, int processState,
+                boolean isForward) {
+            updateProcessState(processState, false);
             queueOrSendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
         }
 
@@ -601,9 +596,12 @@
         // activity itself back to the activity manager. (matters more with ipc)
         public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                 ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-                Bundle state, List<ResultInfo> pendingResults,
+                int procState, Bundle state, List<ResultInfo> pendingResults,
                 List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                 String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+
+            updateProcessState(procState, false);
+
             ActivityClientRecord r = new ActivityClientRecord();
 
             r.token = token;
@@ -651,7 +649,8 @@
 
         public final void scheduleReceiver(Intent intent, ActivityInfo info,
                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
-                boolean sync, int sendingUser) {
+                boolean sync, int sendingUser, int processState) {
+            updateProcessState(processState, false);
             ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                     sync, false, mAppThread.asBinder(), sendingUser);
             r.info = info;
@@ -679,7 +678,8 @@
         }
 
         public final void scheduleCreateService(IBinder token,
-                ServiceInfo info, CompatibilityInfo compatInfo) {
+                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
+            updateProcessState(processState, false);
             CreateServiceData s = new CreateServiceData();
             s.token = token;
             s.info = info;
@@ -689,7 +689,8 @@
         }
 
         public final void scheduleBindService(IBinder token, Intent intent,
-                boolean rebind) {
+                boolean rebind, int processState) {
+            updateProcessState(processState, false);
             BindServiceData s = new BindServiceData();
             s.token = token;
             s.intent = intent;
@@ -788,8 +789,8 @@
             InetAddress.clearDnsCache();
         }
 
-        public void setHttpProxy(String host, String port, String exclList) {
-            Proxy.setHttpProxySystemProperty(host, port, exclList);
+        public void setHttpProxy(String host, String port, String exclList, String pacFileUrl) {
+            Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
         }
 
         public void processInBackground() {
@@ -814,7 +815,8 @@
         // applies transaction ordering per object for such calls.
         public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                 int resultCode, String dataStr, Bundle extras, boolean ordered,
-                boolean sticky, int sendingUser) throws RemoteException {
+                boolean sticky, int sendingUser, int processState) throws RemoteException {
+            updateProcessState(processState, false);
             receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                     sticky, sendingUser);
         }
@@ -854,10 +856,6 @@
             }
         }
 
-        public void getMemoryInfo(Debug.MemoryInfo outInfo) {
-            Debug.getMemoryInfo(outInfo);
-        }
-
         public void dispatchPackageBroadcast(int cmd, String[] packages) {
             queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
         }
@@ -894,29 +892,23 @@
         }
 
         @Override
-        public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin,
-                boolean all, String[] args) {
+        public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
+                boolean dumpFullInfo, boolean dumpDalvik, String[] args) {
             FileOutputStream fout = new FileOutputStream(fd);
-            PrintWriter pw = new PrintWriter(fout);
+            PrintWriter pw = new FastPrintWriter(fout);
             try {
-                return dumpMemInfo(pw, checkin, all);
+                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik);
             } finally {
                 pw.flush();
             }
         }
 
-        private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, boolean checkin, boolean all) {
+        private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
+                boolean dumpFullInfo, boolean dumpDalvik) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
 
-            Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
-            Debug.getMemoryInfo(memInfo);
-
-            if (!all) {
-                return memInfo;
-            }
-
             Runtime runtime = Runtime.getRuntime();
 
             long dalvikMax = runtime.totalMemory() / 1024;
@@ -968,21 +960,48 @@
                 pw.print(memInfo.nativePss); pw.print(',');
                 pw.print(memInfo.dalvikPss); pw.print(',');
                 pw.print(memInfo.otherPss); pw.print(',');
-                pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
+                pw.print(memInfo.getTotalPss()); pw.print(',');
 
-                // Heap info - shared
+                // Heap info - swappable set size
+                pw.print(memInfo.nativeSwappablePss); pw.print(',');
+                pw.print(memInfo.dalvikSwappablePss); pw.print(',');
+                pw.print(memInfo.otherSwappablePss); pw.print(',');
+                pw.print(memInfo.getTotalSwappablePss()); pw.print(',');
+
+                // Heap info - shared dirty
                 pw.print(memInfo.nativeSharedDirty); pw.print(',');
                 pw.print(memInfo.dalvikSharedDirty); pw.print(',');
                 pw.print(memInfo.otherSharedDirty); pw.print(',');
-                pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
-                        + memInfo.otherSharedDirty); pw.print(',');
+                pw.print(memInfo.getTotalSharedDirty()); pw.print(',');
 
-                // Heap info - private
+                // Heap info - shared clean
+                pw.print(memInfo.nativeSharedClean); pw.print(',');
+                pw.print(memInfo.dalvikSharedClean); pw.print(',');
+                pw.print(memInfo.otherSharedClean); pw.print(',');
+                pw.print(memInfo.getTotalSharedClean()); pw.print(',');
+
+                // Heap info - private Dirty
                 pw.print(memInfo.nativePrivateDirty); pw.print(',');
                 pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
                 pw.print(memInfo.otherPrivateDirty); pw.print(',');
-                pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
-                        + memInfo.otherPrivateDirty); pw.print(',');
+                pw.print(memInfo.getTotalPrivateDirty()); pw.print(',');
+
+                // Heap info - private Clean
+                pw.print(memInfo.nativePrivateClean); pw.print(',');
+                pw.print(memInfo.dalvikPrivateClean); pw.print(',');
+                pw.print(memInfo.otherPrivateClean); pw.print(',');
+                pw.print(memInfo.getTotalPrivateClean()); pw.print(',');
+
+                // Heap info - other areas
+                for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+                    pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
+                    pw.print(memInfo.getOtherPss(i)); pw.print(',');
+                    pw.print(memInfo.getOtherSwappablePss(i)); pw.print(',');
+                    pw.print(memInfo.getOtherSharedDirty(i)); pw.print(',');
+                    pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
+                    pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
+                    pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
+                }
 
                 // Object counts
                 pw.print(viewInstanceCount); pw.print(',');
@@ -1014,38 +1033,124 @@
                 }
                 pw.println();
 
-                return memInfo;
+                return;
             }
 
             // otherwise, show human-readable format
-            printRow(pw, HEAP_COLUMN, "", "", "Shared", "Private", "Heap", "Heap", "Heap");
-            printRow(pw, HEAP_COLUMN, "", "Pss", "Dirty", "Dirty", "Size", "Alloc", "Free");
-            printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
-                    "------");
-            printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSharedDirty,
-                    memInfo.nativePrivateDirty, nativeMax, nativeAllocated, nativeFree);
-            printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSharedDirty,
-                    memInfo.dalvikPrivateDirty, dalvikMax, dalvikAllocated, dalvikFree);
-
-            int otherPss = memInfo.otherPss;
-            int otherSharedDirty = memInfo.otherSharedDirty;
-            int otherPrivateDirty = memInfo.otherPrivateDirty;
-
-            for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
-                printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
-                        memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
-                        memInfo.getOtherPrivateDirty(i), "", "", "");
-                otherPss -= memInfo.getOtherPss(i);
-                otherSharedDirty -= memInfo.getOtherSharedDirty(i);
-                otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
+            if (dumpFullInfo) {
+                printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
+                        "Shared", "Private", "Heap", "Heap", "Heap");
+                printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
+                        "Clean", "Clean", "Size", "Alloc", "Free");
+                printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
+                        "------", "------", "------", "------", "------");
+                printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
+                        memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
+                        memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
+                        memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
+                printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+                        memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+                        memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
+                        memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+            } else {
+                printRow(pw, HEAP_COLUMN, "", "Pss", "Pss", "Private",
+                        "Private", "Heap", "Heap", "Heap");
+                printRow(pw, HEAP_COLUMN, "", "Total", "Clean", "Dirty",
+                        "Clean", "Size", "Alloc", "Free");
+                printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
+                        "------", "------", "------", "------");
+                printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
+                        memInfo.nativeSwappablePss,
+                        memInfo.nativePrivateDirty,
+                        memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
+                printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+                        memInfo.dalvikSwappablePss,
+                        memInfo.dalvikPrivateDirty,
+                        memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
             }
 
-            printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSharedDirty,
-                    otherPrivateDirty, "", "", "");
-            printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
-                    memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
-                    nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
-                    nativeFree+dalvikFree);
+            int otherPss = memInfo.otherPss;
+            int otherSwappablePss = memInfo.otherSwappablePss;
+            int otherSharedDirty = memInfo.otherSharedDirty;
+            int otherPrivateDirty = memInfo.otherPrivateDirty;
+            int otherSharedClean = memInfo.otherSharedClean;
+            int otherPrivateClean = memInfo.otherPrivateClean;
+
+            for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+                final int myPss = memInfo.getOtherPss(i);
+                final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+                final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+                final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+                final int mySharedClean = memInfo.getOtherSharedClean(i);
+                final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+                if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+                        || mySharedClean != 0 || myPrivateClean != 0) {
+                    if (dumpFullInfo) {
+                        printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+                                mySharedClean, myPrivateClean, "", "", "");
+                    } else {
+                        printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                myPss, mySwappablePss, myPrivateDirty,
+                                myPrivateClean, "", "", "");
+                    }
+                    otherPss -= myPss;
+                    otherSwappablePss -= mySwappablePss;
+                    otherSharedDirty -= mySharedDirty;
+                    otherPrivateDirty -= myPrivateDirty;
+                    otherSharedClean -= mySharedClean;
+                    otherPrivateClean -= myPrivateClean;
+                }
+            }
+
+            if (dumpFullInfo) {
+                printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
+                        otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
+                        "", "", "");
+                printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                        memInfo.getTotalSwappablePss(),
+                        memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+                        memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
+                        nativeMax+dalvikMax,
+                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+            } else {
+                printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSwappablePss,
+                        otherPrivateDirty, otherPrivateClean,
+                        "", "", "");
+                printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                        memInfo.getTotalSwappablePss(),
+                        memInfo.getTotalPrivateDirty(),
+                        memInfo.getTotalPrivateClean(),
+                        nativeMax+dalvikMax,
+                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+            }
+
+            if (dumpDalvik) {
+                pw.println(" ");
+                pw.println(" Dalvik Details");
+
+                for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
+                     i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
+                    final int myPss = memInfo.getOtherPss(i);
+                    final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+                    final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+                    final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+                    final int mySharedClean = memInfo.getOtherSharedClean(i);
+                    final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+                    if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+                            || mySharedClean != 0 || myPrivateClean != 0) {
+                        if (dumpFullInfo) {
+                            printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                    myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+                                    mySharedClean, myPrivateClean, "", "", "");
+                        } else {
+                            printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                    myPss, mySwappablePss, myPrivateDirty,
+                                    myPrivateClean, "", "", "");
+                        }
+                    }
+                }
+            }
 
             pw.println(" ");
             pw.println(" Objects");
@@ -1093,8 +1198,6 @@
                 pw.println(" Asset Allocations");
                 pw.print(assetAlloc);
             }
-
-            return memInfo;
         }
 
         @Override
@@ -1105,7 +1208,7 @@
 
         @Override
         public void dumpDbInfo(FileDescriptor fd, String[] args) {
-            PrintWriter pw = new PrintWriter(new FileOutputStream(fd));
+            PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
             PrintWriterPrinter printer = new PrintWriterPrinter(pw);
             SQLiteDebug.dump(printer, args);
             pw.flush();
@@ -1117,13 +1220,13 @@
         }
 
         @Override
-        public void requestActivityExtras(IBinder activityToken, IBinder requestToken,
+        public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
                 int requestType) {
-            RequestActivityExtras cmd = new RequestActivityExtras();
+            RequestAssistContextExtras cmd = new RequestAssistContextExtras();
             cmd.activityToken = activityToken;
             cmd.requestToken = requestToken;
             cmd.requestType = requestType;
-            queueOrSendMessage(H.REQUEST_ACTIVITY_EXTRAS, cmd);
+            queueOrSendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
         }
 
         private void printRow(PrintWriter pw, String format, Object...objs) {
@@ -1145,6 +1248,27 @@
             queueOrSendMessage(H.TRIM_MEMORY, null, level);
         }
 
+        public void scheduleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
+            queueOrSendMessage(H.TRANSLUCENT_CONVERSION_COMPLETE, token, drawComplete ? 1 : 0);
+        }
+
+        public void setProcessState(int state) {
+            updateProcessState(state, true);
+        }
+
+        public void updateProcessState(int processState, boolean fromIpc) {
+            synchronized (this) {
+                if (mLastProcessState != processState) {
+                    mLastProcessState = processState;
+
+                    // Update Dalvik state here based on ActivityManager.PROCESS_STATE_* constants.
+                    if (false) {
+                        Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState
+                                + (fromIpc ? " (from ipc": ""));
+                    }
+                }
+            }
+        }
     }
 
     private class H extends Handler {
@@ -1191,7 +1315,8 @@
         public static final int TRIM_MEMORY             = 140;
         public static final int DUMP_PROVIDER           = 141;
         public static final int UNSTABLE_PROVIDER_DIED  = 142;
-        public static final int REQUEST_ACTIVITY_EXTRAS = 143;
+        public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
+        public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
                 switch (code) {
@@ -1238,7 +1363,8 @@
                     case TRIM_MEMORY: return "TRIM_MEMORY";
                     case DUMP_PROVIDER: return "DUMP_PROVIDER";
                     case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
-                    case REQUEST_ACTIVITY_EXTRAS: return "REQUEST_ACTIVITY_EXTRAS";
+                    case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
+                    case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
                 }
             }
             return Integer.toString(code);
@@ -1450,8 +1576,11 @@
                 case UNSTABLE_PROVIDER_DIED:
                     handleUnstableProviderDied((IBinder)msg.obj, false);
                     break;
-                case REQUEST_ACTIVITY_EXTRAS:
-                    handleRequestActivityExtras((RequestActivityExtras)msg.obj);
+                case REQUEST_ASSIST_CONTEXT_EXTRAS:
+                    handleRequestAssistContextExtras((RequestAssistContextExtras)msg.obj);
+                    break;
+                case TRANSLUCENT_CONVERSION_COMPLETE:
+                    handleTranslucentConversionComplete((IBinder)msg.obj, msg.arg1 == 1);
                     break;
             }
             if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
@@ -1485,6 +1614,7 @@
     }
 
     private class Idler implements MessageQueue.IdleHandler {
+        @Override
         public final boolean queueIdle() {
             ActivityClientRecord a = mNewActivities;
             boolean stopProfiling = false;
@@ -1523,70 +1653,13 @@
     }
 
     final class GcIdler implements MessageQueue.IdleHandler {
+        @Override
         public final boolean queueIdle() {
             doGcIfNeeded();
             return false;
         }
     }
 
-    private static class ResourcesKey {
-        final private String mResDir;
-        final private int mDisplayId;
-        final private Configuration mOverrideConfiguration;
-        final private float mScale;
-        final private int mHash;
-
-        ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration, float scale) {
-            mResDir = resDir;
-            mDisplayId = displayId;
-            if (overrideConfiguration != null) {
-                if (Configuration.EMPTY.equals(overrideConfiguration)) {
-                    overrideConfiguration = null;
-                }
-            }
-            mOverrideConfiguration = overrideConfiguration;
-            mScale = scale;
-            int hash = 17;
-            hash = 31 * hash + mResDir.hashCode();
-            hash = 31 * hash + mDisplayId;
-            hash = 31 * hash + (mOverrideConfiguration != null
-                    ? mOverrideConfiguration.hashCode() : 0);
-            hash = 31 * hash + Float.floatToIntBits(mScale);
-            mHash = hash;
-        }
-
-        @Override
-        public int hashCode() {
-            return mHash;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ResourcesKey)) {
-                return false;
-            }
-            ResourcesKey peer = (ResourcesKey) obj;
-            if (!mResDir.equals(peer.mResDir)) {
-                return false;
-            }
-            if (mDisplayId != peer.mDisplayId) {
-                return false;
-            }
-            if (mOverrideConfiguration != peer.mOverrideConfiguration) {
-                if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
-                    return false;
-                }
-                if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
-                    return false;
-                }
-            }
-            if (mScale != peer.mScale) {
-                return false;
-            }
-            return true;
-        }
-    }
-
     public static ActivityThread currentActivityThread() {
         return sCurrentActivityThread;
     }
@@ -1620,54 +1693,13 @@
         return sPackageManager;
     }
 
-    private void flushDisplayMetricsLocked() {
-        mDefaultDisplayMetrics.clear();
-    }
-
-    DisplayMetrics getDisplayMetricsLocked(int displayId, CompatibilityInfo ci) {
-        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-        DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(ci) : null;
-        if (dm != null) {
-            return dm;
-        }
-        dm = new DisplayMetrics();
-
-        DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
-        if (displayManager == null) {
-            // may be null early in system startup
-            dm.setToDefaults();
-            return dm;
-        }
-
-        if (isDefaultDisplay) {
-            mDefaultDisplayMetrics.put(ci, dm);
-        }
-
-        CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
-        cih.set(ci);
-        Display d = displayManager.getCompatibleDisplay(displayId, cih);
-        if (d != null) {
-            d.getMetrics(dm);
-        } else {
-            // Display no longer exists
-            // FIXME: This would not be a problem if we kept the Display object around
-            // instead of using the raw display id everywhere.  The Display object caches
-            // its information even after the display has been removed.
-            dm.setToDefaults();
-        }
-        //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
-        //        + metrics.heightPixels + " den=" + metrics.density
-        //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
-        return dm;
-    }
-
     private Configuration mMainThreadConfig = new Configuration();
     Configuration applyConfigCompatMainThread(int displayDensity, Configuration config,
             CompatibilityInfo compat) {
         if (config == null) {
             return null;
         }
-        if (compat != null && !compat.supportsScreen()) {
+        if (!compat.supportsScreen()) {
             mMainThreadConfig.setTo(config);
             config = mMainThreadConfig;
             compat.applyToConfiguration(displayDensity, config);
@@ -1676,93 +1708,13 @@
     }
 
     /**
-     * Creates the top level Resources for applications with the given compatibility info.
-     *
-     * @param resDir the resource directory.
-     * @param compInfo the compability info. It will use the default compatibility info when it's
-     * null.
-     */
-    Resources getTopLevelResources(String resDir,
-            int displayId, Configuration overrideConfiguration,
-            CompatibilityInfo compInfo) {
-        ResourcesKey key = new ResourcesKey(resDir,
-                displayId, overrideConfiguration,
-                compInfo.applicationScale);
-        Resources r;
-        synchronized (mPackages) {
-            // Resources is app scale dependent.
-            if (false) {
-                Slog.w(TAG, "getTopLevelResources: " + resDir + " / "
-                        + compInfo.applicationScale);
-            }
-            WeakReference<Resources> wr = mActiveResources.get(key);
-            r = wr != null ? wr.get() : null;
-            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
-            if (r != null && r.getAssets().isUpToDate()) {
-                if (false) {
-                    Slog.w(TAG, "Returning cached resources " + r + " " + resDir
-                            + ": appScale=" + r.getCompatibilityInfo().applicationScale);
-                }
-                return r;
-            }
-        }
-
-        //if (r != null) {
-        //    Slog.w(TAG, "Throwing away out-of-date resources!!!! "
-        //            + r + " " + resDir);
-        //}
-
-        AssetManager assets = new AssetManager();
-        if (assets.addAssetPath(resDir) == 0) {
-            return null;
-        }
-
-        //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
-        DisplayMetrics dm = getDisplayMetricsLocked(displayId, null);
-        Configuration config;
-        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-        if (!isDefaultDisplay || key.mOverrideConfiguration != null) {
-            config = new Configuration(getConfiguration());
-            if (!isDefaultDisplay) {
-                applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
-            }
-            if (key.mOverrideConfiguration != null) {
-                config.updateFrom(key.mOverrideConfiguration);
-            }
-        } else {
-            config = getConfiguration();
-        }
-        r = new Resources(assets, dm, config, compInfo);
-        if (false) {
-            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
-                    + r.getConfiguration() + " appScale="
-                    + r.getCompatibilityInfo().applicationScale);
-        }
-
-        synchronized (mPackages) {
-            WeakReference<Resources> wr = mActiveResources.get(key);
-            Resources existing = wr != null ? wr.get() : null;
-            if (existing != null && existing.getAssets().isUpToDate()) {
-                // Someone else already created the resources while we were
-                // unlocked; go ahead and use theirs.
-                r.getAssets().close();
-                return existing;
-            }
-            
-            // XXX need to remove entries when weak references go away
-            mActiveResources.put(key, new WeakReference<Resources>(r));
-            return r;
-        }
-    }
-
-    /**
      * Creates the top level resources for the given package.
      */
     Resources getTopLevelResources(String resDir,
             int displayId, Configuration overrideConfiguration,
             LoadedApk pkgInfo) {
-        return getTopLevelResources(resDir, displayId, overrideConfiguration,
-                pkgInfo.mCompatibilityInfo.get());
+        return mResourcesManager.getTopLevelResources(resDir, displayId, overrideConfiguration,
+                pkgInfo.getCompatibilityInfo(), null);
     }
 
     final Handler getHandler() {
@@ -1776,7 +1728,7 @@
 
     public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
             int flags, int userId) {
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             WeakReference<LoadedApk> ref;
             if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
                 ref = mPackages.get(packageName);
@@ -1846,7 +1798,7 @@
     }
 
     public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             WeakReference<LoadedApk> ref;
             if (includeCode) {
                 ref = mPackages.get(packageName);
@@ -1859,7 +1811,7 @@
 
     private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
             ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             WeakReference<LoadedApk> ref;
             if (includeCode) {
                 ref = mPackages.get(aInfo.packageName);
@@ -1891,6 +1843,7 @@
     }
 
     ActivityThread() {
+        mResourcesManager = ResourcesManager.getInstance();
     }
 
     public ApplicationThread getApplicationThread()
@@ -1903,10 +1856,6 @@
         return mInstrumentation;
     }
 
-    public Configuration getConfiguration() {
-        return mResConfiguration;
-    }
-
     public boolean isProfiling() {
         return mProfiler != null && mProfiler.profileFile != null
                 && mProfiler.profileFd == null;
@@ -1936,10 +1885,8 @@
                 LoadedApk info = new LoadedApk(this, "android", context, null,
                         CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
                 context.init(info, null, this);
-                context.getResources().updateConfiguration(
-                        getConfiguration(), getDisplayMetricsLocked(
-                                Display.DEFAULT_DISPLAY,
-                                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO));
+                context.getResources().updateConfiguration(mResourcesManager.getConfiguration(),
+                        mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
                 mSystemContext = context;
                 //Slog.i(TAG, "Created system resources " + context.getResources()
                 //        + ": " + context.getResources().getConfiguration());
@@ -1965,7 +1912,7 @@
             dalvik.system.VMRuntime.getRuntime().startJitCompilation();
         }
     }
-    
+
     void scheduleGcIdler() {
         if (!mGcIdlerScheduled) {
             mGcIdlerScheduled = true;
@@ -2232,7 +2179,7 @@
             DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
             for (int displayId : dm.getDisplayIds()) {
                 if (displayId != Display.DEFAULT_DISPLAY) {
-                    Display display = dm.getRealDisplay(displayId);
+                    Display display = dm.getRealDisplay(displayId, r.token);
                     baseContext = appContext.createDisplayContext(display);
                     break;
                 }
@@ -2351,7 +2298,7 @@
         performNewIntents(data.token, data.intents);
     }
 
-    public void handleRequestActivityExtras(RequestActivityExtras cmd) {
+    public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
         Bundle data = new Bundle();
         ActivityClientRecord r = mActivities.get(cmd.activityToken);
         if (r != null) {
@@ -2363,11 +2310,18 @@
         }
         IActivityManager mgr = ActivityManagerNative.getDefault();
         try {
-            mgr.reportTopActivityExtras(cmd.requestToken, data);
+            mgr.reportAssistContextExtras(cmd.requestToken, data);
         } catch (RemoteException e) {
         }
     }
-    
+
+    public void handleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
+        ActivityClientRecord r = mActivities.get(token);
+        if (r != null) {
+            r.activity.onTranslucentConversionComplete(drawComplete);
+        }
+    }
+
     private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
 
     /**
@@ -2651,7 +2605,8 @@
         try {
             Service s = mServices.get(info.token);
             if (s != null) {
-                PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
+                PrintWriter pw = new FastPrintWriter(new FileOutputStream(
+                        info.fd.getFileDescriptor()));
                 s.dump(info.fd.getFileDescriptor(), pw, info.args);
                 pw.flush();
             }
@@ -2666,7 +2621,8 @@
         try {
             ActivityClientRecord r = mActivities.get(info.token);
             if (r != null && r.activity != null) {
-                PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
+                PrintWriter pw = new FastPrintWriter(new FileOutputStream(
+                        info.fd.getFileDescriptor()));
                 r.activity.dump(info.prefix, info.fd.getFileDescriptor(), pw, info.args);
                 pw.flush();
             }
@@ -2681,7 +2637,8 @@
         try {
             ProviderClientRecord r = mLocalProviders.get(info.token);
             if (r != null && r.mLocalProvider != null) {
-                PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
+                PrintWriter pw = new FastPrintWriter(new FileOutputStream(
+                        info.fd.getFileDescriptor()));
                 r.mLocalProvider.dump(info.fd.getFileDescriptor(), pw, info.args);
                 pw.flush();
             }
@@ -3331,7 +3288,7 @@
     }
 
     private void handleSetCoreSettings(Bundle coreSettings) {
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             mCoreSettings = coreSettings;
         }
     }
@@ -3339,11 +3296,11 @@
     private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) {
         LoadedApk apk = peekPackageInfo(data.pkg, false);
         if (apk != null) {
-            apk.mCompatibilityInfo.set(data.info);
+            apk.setCompatibilityInfo(data.info);
         }
         apk = peekPackageInfo(data.pkg, true);
         if (apk != null) {
-            apk.mCompatibilityInfo.set(data.info);
+            apk.setCompatibilityInfo(data.info);
         }
         handleConfigurationChanged(mConfiguration, data.info);
         WindowManagerGlobal.getInstance().reportNewConfiguration(mConfiguration);
@@ -3421,7 +3378,7 @@
     private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
             int configChanges, boolean getNonConfigInstance) {
         ActivityClientRecord r = mActivities.get(token);
-        Class activityClass = null;
+        Class<? extends Activity> activityClass = null;
         if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
         if (r != null) {
             activityClass = r.activity.getClass();
@@ -3576,7 +3533,7 @@
             boolean fromServer) {
         ActivityClientRecord target = null;
 
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             for (int i=0; i<mRelaunchingActivities.size(); i++) {
                 ActivityClientRecord r = mRelaunchingActivities.get(i);
                 if (r.token == token) {
@@ -3637,7 +3594,7 @@
         // First: make sure we have the most recent configuration and most
         // recent version of the activity, or skip it if some previous call
         // had taken a more recent version.
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             int N = mRelaunchingActivities.size();
             IBinder token = tmp.token;
             tmp = null;
@@ -3766,47 +3723,46 @@
         ArrayList<ComponentCallbacks2> callbacks
                 = new ArrayList<ComponentCallbacks2>();
 
-        synchronized (mPackages) {
-            final int N = mAllApplications.size();
-            for (int i=0; i<N; i++) {
+        synchronized (mResourcesManager) {
+            final int NAPP = mAllApplications.size();
+            for (int i=0; i<NAPP; i++) {
                 callbacks.add(mAllApplications.get(i));
             }
-            if (mActivities.size() > 0) {
-                for (ActivityClientRecord ar : mActivities.values()) {
-                    Activity a = ar.activity;
-                    if (a != null) {
-                        Configuration thisConfig = applyConfigCompatMainThread(mCurDefaultDisplayDpi,
-                                newConfig, ar.packageInfo.mCompatibilityInfo.getIfNeeded());
-                        if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
-                            // If the activity is currently resumed, its configuration
-                            // needs to change right now.
-                            callbacks.add(a);
-                        } else if (thisConfig != null) {
-                            // Otherwise, we will tell it about the change
-                            // the next time it is resumed or shown.  Note that
-                            // the activity manager may, before then, decide the
-                            // activity needs to be destroyed to handle its new
-                            // configuration.
-                            if (DEBUG_CONFIGURATION) {
-                                Slog.v(TAG, "Setting activity "
-                                        + ar.activityInfo.name + " newConfig=" + thisConfig);
-                            }
-                            ar.newConfig = thisConfig;
+            final int NACT = mActivities.size();
+            for (int i=0; i<NACT; i++) {
+                ActivityClientRecord ar = mActivities.valueAt(i);
+                Activity a = ar.activity;
+                if (a != null) {
+                    Configuration thisConfig = applyConfigCompatMainThread(
+                            mCurDefaultDisplayDpi, newConfig,
+                            ar.packageInfo.getCompatibilityInfo());
+                    if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
+                        // If the activity is currently resumed, its configuration
+                        // needs to change right now.
+                        callbacks.add(a);
+                    } else if (thisConfig != null) {
+                        // Otherwise, we will tell it about the change
+                        // the next time it is resumed or shown.  Note that
+                        // the activity manager may, before then, decide the
+                        // activity needs to be destroyed to handle its new
+                        // configuration.
+                        if (DEBUG_CONFIGURATION) {
+                            Slog.v(TAG, "Setting activity "
+                                    + ar.activityInfo.name + " newConfig=" + thisConfig);
                         }
+                        ar.newConfig = thisConfig;
                     }
                 }
             }
-            if (mServices.size() > 0) {
-                for (Service service : mServices.values()) {
-                    callbacks.add(service);
-                }
+            final int NSVC = mServices.size();
+            for (int i=0; i<NSVC; i++) {
+                callbacks.add(mServices.valueAt(i));
             }
         }
         synchronized (mProviderMap) {
-            if (mLocalProviders.size() > 0) {
-                for (ProviderClientRecord providerClientRecord : mLocalProviders.values()) {
-                    callbacks.add(providerClientRecord.mLocalProvider);
-                }
+            final int NPRV = mLocalProviders.size();
+            for (int i=0; i<NPRV; i++) {
+                callbacks.add(mLocalProviders.valueAt(i).mLocalProvider);
             }
         }
 
@@ -3859,115 +3815,18 @@
     }
 
     public final void applyConfigurationToResources(Configuration config) {
-        synchronized (mPackages) {
-            applyConfigurationToResourcesLocked(config, null);
+        synchronized (mResourcesManager) {
+            mResourcesManager.applyConfigurationToResourcesLocked(config, null);
         }
     }
 
-    final boolean applyConfigurationToResourcesLocked(Configuration config,
-            CompatibilityInfo compat) {
-        if (mResConfiguration == null) {
-            mResConfiguration = new Configuration();
-        }
-        if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
-            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
-                    + mResConfiguration.seq + ", newSeq=" + config.seq);
-            return false;
-        }
-        int changes = mResConfiguration.updateFrom(config);
-        flushDisplayMetricsLocked();
-        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked(
-                Display.DEFAULT_DISPLAY, null);
-
-        if (compat != null && (mResCompatibilityInfo == null ||
-                !mResCompatibilityInfo.equals(compat))) {
-            mResCompatibilityInfo = compat;
-            changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
-                    | ActivityInfo.CONFIG_SCREEN_SIZE
-                    | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
-        }
-
-        // set it for java, this also affects newly created Resources
-        if (config.locale != null) {
-            Locale.setDefault(config.locale);
-        }
-
-        Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
-
-        ApplicationPackageManager.configurationChanged();
-        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
-
-        Configuration tmpConfig = null;
-
-        Iterator<Map.Entry<ResourcesKey, WeakReference<Resources>>> it =
-                mActiveResources.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry<ResourcesKey, WeakReference<Resources>> entry = it.next();
-            Resources r = entry.getValue().get();
-            if (r != null) {
-                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
-                        + r + " config to: " + config);
-                int displayId = entry.getKey().mDisplayId;
-                boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-                DisplayMetrics dm = defaultDisplayMetrics;
-                Configuration overrideConfig = entry.getKey().mOverrideConfiguration;
-                if (!isDefaultDisplay || overrideConfig != null) {
-                    if (tmpConfig == null) {
-                        tmpConfig = new Configuration();
-                    }
-                    tmpConfig.setTo(config);
-                    if (!isDefaultDisplay) {
-                        dm = getDisplayMetricsLocked(displayId, null);
-                        applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
-                    }
-                    if (overrideConfig != null) {
-                        tmpConfig.updateFrom(overrideConfig);
-                    }
-                    r.updateConfiguration(tmpConfig, dm, compat);
-                } else {
-                    r.updateConfiguration(config, dm, compat);
-                }
-                //Slog.i(TAG, "Updated app resources " + v.getKey()
-                //        + " " + r + ": " + r.getConfiguration());
-            } else {
-                //Slog.i(TAG, "Removing old resources " + v.getKey());
-                it.remove();
-            }
-        }
-        
-        return changes != 0;
-    }
-
-    final void applyNonDefaultDisplayMetricsToConfigurationLocked(
-            DisplayMetrics dm, Configuration config) {
-        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-        config.densityDpi = dm.densityDpi;
-        config.screenWidthDp = (int)(dm.widthPixels / dm.density);
-        config.screenHeightDp = (int)(dm.heightPixels / dm.density);
-        int sl = Configuration.resetScreenLayout(config.screenLayout);
-        if (dm.widthPixels > dm.heightPixels) {
-            config.orientation = Configuration.ORIENTATION_LANDSCAPE;
-            config.screenLayout = Configuration.reduceScreenLayout(sl,
-                    config.screenWidthDp, config.screenHeightDp);
-        } else {
-            config.orientation = Configuration.ORIENTATION_PORTRAIT;
-            config.screenLayout = Configuration.reduceScreenLayout(sl,
-                    config.screenHeightDp, config.screenWidthDp);
-        }
-        config.smallestScreenWidthDp = config.screenWidthDp; // assume screen does not rotate
-        config.compatScreenWidthDp = config.screenWidthDp;
-        config.compatScreenHeightDp = config.screenHeightDp;
-        config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp;
-    }
-
     final Configuration applyCompatConfiguration(int displayDensity) {
         Configuration config = mConfiguration;
         if (mCompatConfiguration == null) {
             mCompatConfiguration = new Configuration();
         }
         mCompatConfiguration.setTo(mConfiguration);
-        if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) {
-            mResCompatibilityInfo.applyToConfiguration(displayDensity, mCompatConfiguration);
+        if (mResourcesManager.applyCompatConfiguration(displayDensity, mCompatConfiguration)) {
             config = mCompatConfiguration;
         }
         return config;
@@ -3977,7 +3836,7 @@
 
         int configDiff = 0;
 
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             if (mPendingConfiguration != null) {
                 if (!mPendingConfiguration.isOtherSeqNewer(config)) {
                     config = mPendingConfiguration;
@@ -3993,9 +3852,9 @@
             
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
                     + config);
-        
-            applyConfigurationToResourcesLocked(config, compat);
-            
+
+            mResourcesManager.applyConfigurationToResourcesLocked(config, compat);
+
             if (mConfiguration == null) {
                 mConfiguration = new Configuration();
             }
@@ -4022,7 +3881,7 @@
         }
     }
 
-    final void freeTextLayoutCachesIfNeeded(int configDiff) {
+    static void freeTextLayoutCachesIfNeeded(int configDiff) {
         if (configDiff != 0) {
             // Ask text layout engine to free its caches if there is a locale change
             boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
@@ -4245,7 +4104,7 @@
          * reflect configuration changes. The configuration object passed
          * in AppBindData can be safely assumed to be up to date
          */
-        applyConfigurationToResourcesLocked(data.config, data.compatInfo);
+        mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
         mCurDefaultDisplayDpi = data.config.densityDpi;
         applyCompatConfiguration(mCurDefaultDisplayDpi);
 
@@ -4736,12 +4595,11 @@
                 mProviderRefCountMap.remove(jBinder);
             }
 
-            Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator();
-            while (iter.hasNext()) {
-                ProviderClientRecord pr = iter.next();
+            for (int i=mProviderMap.size()-1; i>=0; i--) {
+                ProviderClientRecord pr = mProviderMap.valueAt(i);
                 IBinder myBinder = pr.mProvider.asBinder();
                 if (myBinder == jBinder) {
-                    iter.remove();
+                    mProviderMap.removeAt(i);
                 }
             }
         }
@@ -4795,6 +4653,19 @@
         }
     }
 
+    final void appNotRespondingViaProvider(IBinder provider) {
+        synchronized (mProviderMap) {
+            ProviderRefCount prc = mProviderRefCountMap.get(provider);
+            if (prc != null) {
+                try {
+                    ActivityManagerNative.getDefault()
+                            .appNotRespondingViaProvider(prc.holder.connection);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+    }
+
     private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
             ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
         final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
@@ -4957,6 +4828,7 @@
         mSystemThread = system;
         if (!system) {
             ViewRootImpl.addFirstDrawHandler(new Runnable() {
+                @Override
                 public void run() {
                     ensureJitEnabled();
                 }
@@ -4993,12 +4865,13 @@
         DropBox.setReporter(new DropBoxReporter());
 
         ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
+            @Override
             public void onConfigurationChanged(Configuration newConfig) {
-                synchronized (mPackages) {
+                synchronized (mResourcesManager) {
                     // We need to apply this change to the resources
                     // immediately, because upon returning the view
                     // hierarchy will be informed about it.
-                    if (applyConfigurationToResourcesLocked(newConfig, null)) {
+                    if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                         // This actually changed the resources!  Tell
                         // everyone about it.
                         if (mPendingConfiguration == null ||
@@ -5010,8 +4883,10 @@
                     }
                 }
             }
+            @Override
             public void onLowMemory() {
             }
+            @Override
             public void onTrimMemory(int level) {
             }
         });
@@ -5031,12 +4906,11 @@
     }
 
     public int getIntCoreSetting(String key, int defaultValue) {
-        synchronized (mPackages) {
+        synchronized (mResourcesManager) {
             if (mCoreSettings != null) {
                 return mCoreSettings.getInt(key, defaultValue);
-            } else {
-                return defaultValue;
             }
+            return defaultValue;
         }
     }
 
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 2fe682d..5c3a3e5 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -16,8 +16,11 @@
 
 package android.app;
 
+import android.content.Context;
 import android.content.Intent;
+import android.os.Build;
 import android.os.RemoteException;
+import android.os.WorkSource;
 
 /**
  * This class provides access to the system alarm services.  These allow you
@@ -52,6 +55,8 @@
  */
 public class AlarmManager
 {
+    private static final String TAG = "AlarmManager";
+
     /**
      * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
      * (wall clock time in UTC), which will wake up the device when
@@ -80,17 +85,33 @@
      */
     public static final int ELAPSED_REALTIME = 3;
 
+    /** @hide */
+    public static final long WINDOW_EXACT = 0;
+    /** @hide */
+    public static final long WINDOW_HEURISTIC = -1;
+
     private final IAlarmManager mService;
+    private final boolean mAlwaysExact;
+
 
     /**
      * package private on purpose
      */
-    AlarmManager(IAlarmManager service) {
+    AlarmManager(IAlarmManager service, Context ctx) {
         mService = service;
+
+        final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
+        mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
     }
-    
+
+    private long legacyExactLength() {
+        return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC);
+    }
+
     /**
-     * Schedule an alarm.  <b>Note: for timing operations (ticks, timeouts,
+     * TBW: discussion of fuzzy nature of alarms in KLP+.
+     *
+     * <p>Schedule an alarm.  <b>Note: for timing operations (ticks, timeouts,
      * etc) it is easier and much more efficient to use
      * {@link android.os.Handler}.</b>  If there is already an alarm scheduled
      * for the same IntentSender, it will first be canceled.
@@ -122,7 +143,9 @@
      * IntentSender.getBroadcast()}.
      *
      * @see android.os.Handler
+     * @see #setExact
      * @see #setRepeating
+     * @see #setWindow
      * @see #cancel
      * @see android.content.Context#sendBroadcast
      * @see android.content.Context#registerReceiver
@@ -133,10 +156,7 @@
      * @see #RTC_WAKEUP
      */
     public void set(int type, long triggerAtMillis, PendingIntent operation) {
-        try {
-            mService.set(type, triggerAtMillis, operation);
-        } catch (RemoteException ex) {
-        }
+        setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null);
     }
 
     /**
@@ -177,6 +197,8 @@
      *
      * @see android.os.Handler
      * @see #set
+     * @see #setExact
+     * @see #setWindow
      * @see #cancel
      * @see android.content.Context#sendBroadcast
      * @see android.content.Context#registerReceiver
@@ -188,22 +210,113 @@
      */
     public void setRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
+        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, operation, null);
+    }
+
+    /**
+     * Schedule an alarm to be delivered within a given window of time.
+     *
+     * TBW: clean up these docs
+     *
+     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
+     *        RTC_WAKEUP.
+     * @param windowStartMillis The earliest time, in milliseconds, that the alarm should
+     *        be delivered, expressed in the appropriate clock's units (depending on the alarm
+     *        type).
+     * @param windowLengthMillis The length of the requested delivery window,
+     *        in milliseconds.  The alarm will be delivered no later than this many
+     *        milliseconds after the windowStartMillis time.  Note that this parameter
+     *        is a <i>duration,</i> not the timestamp of the end of the window.
+     * @param operation Action to perform when the alarm goes off;
+     *        typically comes from {@link PendingIntent#getBroadcast
+     *        IntentSender.getBroadcast()}.
+     *
+     * @see #set
+     * @see #setExact
+     * @see #setRepeating
+     * @see #cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see #ELAPSED_REALTIME
+     * @see #ELAPSED_REALTIME_WAKEUP
+     * @see #RTC
+     * @see #RTC_WAKEUP
+     */
+    public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
+            PendingIntent operation) {
+        setImpl(type, windowStartMillis, windowLengthMillis, 0, operation, null);
+    }
+
+    /**
+     * TBW: new 'exact' alarm that must be delivered as nearly as possible
+     * to the precise time specified.
+     */
+    public void setExact(int type, long triggerAtMillis, PendingIntent operation) {
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, operation, null);
+    }
+
+    /** @hide */
+    public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
+            PendingIntent operation, WorkSource workSource) {
+        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource);
+    }
+
+    private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
+            PendingIntent operation, WorkSource workSource) {
+        if (triggerAtMillis < 0) {
+            /* NOTYET
+            if (mAlwaysExact) {
+                // Fatal error for KLP+ apps to use negative trigger times
+                throw new IllegalArgumentException("Invalid alarm trigger time "
+                        + triggerAtMillis);
+            }
+            */
+            triggerAtMillis = 0;
+        }
+
         try {
-            mService.setRepeating(type, triggerAtMillis, intervalMillis, operation);
+            mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
+                    workSource);
         } catch (RemoteException ex) {
         }
     }
 
     /**
-     * Available inexact recurrence intervals recognized by
-     * {@link #setInexactRepeating(int, long, long, PendingIntent)} 
+     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
+     * repeating alarms are inexact.
      */
+    @Deprecated
     public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;
+
+    /**
+     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
+     * repeating alarms are inexact.
+     */
+    @Deprecated
     public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;
+
+    /**
+     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
+     * repeating alarms are inexact.
+     */
+    @Deprecated
     public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;
+
+    /**
+     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
+     * repeating alarms are inexact.
+     */
+    @Deprecated
     public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;
+
+    /**
+     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
+     * repeating alarms are inexact.
+     */
+    @Deprecated
     public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;
-    
+
     /**
      * Schedule a repeating alarm that has inexact trigger time requirements;
      * for example, an alarm that repeats every hour, but not necessarily at
@@ -236,6 +349,8 @@
      * typically comes from {@link PendingIntent#getBroadcast
      * IntentSender.getBroadcast()}.
      *
+     * @deprecated As of API 19, all repeating alarms are inexact.
+     *
      * @see android.os.Handler
      * @see #set
      * @see #cancel
@@ -252,12 +367,10 @@
      * @see #INTERVAL_HALF_DAY
      * @see #INTERVAL_DAY
      */
+    @Deprecated
     public void setInexactRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        try {
-            mService.setInexactRepeating(type, triggerAtMillis, intervalMillis, operation);
-        } catch (RemoteException ex) {
-        }
+        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, operation, null);
     }
     
     /**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4fcb18a..dce8cab 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,7 +16,9 @@
 
 package android.app;
 
-import android.Manifest;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.ArrayMap;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsCallback;
 
@@ -31,79 +33,179 @@
 import android.os.RemoteException;
 
 /**
- * API for interacting with "application operation" tracking.  Allows you to:
+ * API for interacting with "application operation" tracking.
  *
- * - Note when operations are happening, and find out if they are allowed for the current caller.
- * - Disallow specific apps from doing specific operations.
- * - Collect all of the current information about operations that have been executed or are not
- * being allowed.
- * - Monitor for changes in whether an operation is allowed.
- *
- * Each operation is identified by a single integer; these integers are a fixed set of
- * operations, enumerated by the OP_* constants.
- *
- * When checking operations, the result is a "mode" integer indicating the current setting
- * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
- * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
- * SecurityException back to the caller; the normal operation calls will do this for you).
- *
- * @hide
+ * <p>This API is not generally intended for third party application developers; most
+ * features are only available to system applicatins.  Obtain an instance of it through
+ * {@link Context#getSystemService(String) Context.getSystemService} with
+ * {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p>
  */
 public class AppOpsManager {
+    /**
+     * <p>App ops allows callers to:</p>
+     *
+     * <ul>
+     * <li> Note when operations are happening, and find out if they are allowed for the current
+     * caller.</li>
+     * <li> Disallow specific apps from doing specific operations.</li>
+     * <li> Collect all of the current information about operations that have been executed or
+     * are not being allowed.</li>
+     * <li> Monitor for changes in whether an operation is allowed.</li>
+     * </ul>
+     *
+     * <p>Each operation is identified by a single integer; these integers are a fixed set of
+     * operations, enumerated by the OP_* constants.
+     *
+     * <p></p>When checking operations, the result is a "mode" integer indicating the current
+     * setting for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute
+     * the operation but fake its behavior enough so that the caller doesn't crash),
+     * MODE_ERRORED (throw a SecurityException back to the caller; the normal operation calls
+     * will do this for you).
+     */
+
     final Context mContext;
     final IAppOpsService mService;
-    final HashMap<Callback, IAppOpsCallback> mModeWatchers
-            = new HashMap<Callback, IAppOpsCallback>();
+    final ArrayMap<OnOpChangedListener, IAppOpsCallback> mModeWatchers
+            = new ArrayMap<OnOpChangedListener, IAppOpsCallback>();
 
+    static IBinder sToken;
+
+    /**
+     * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
+     * allowed to perform the given operation.
+     */
     public static final int MODE_ALLOWED = 0;
+
+    /**
+     * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
+     * not allowed to perform the given operation, and this attempt should
+     * <em>silently fail</em> (it should not cause the app to crash).
+     */
     public static final int MODE_IGNORED = 1;
+
+    /**
+     * Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the
+     * given caller is not allowed to perform the given operation, and this attempt should
+     * cause it to have a fatal error, typically a {@link SecurityException}.
+     */
     public static final int MODE_ERRORED = 2;
 
     // when adding one of these:
     //  - increment _NUM_OP
-    //  - add rows to sOpToSwitch, sOpNames, sOpPerms
+    //  - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode
     //  - add descriptive strings to Settings/res/values/arrays.xml
+    //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
+
+    /** @hide No operation specified. */
     public static final int OP_NONE = -1;
+    /** @hide Access to coarse location information. */
     public static final int OP_COARSE_LOCATION = 0;
+    /** @hide Access to fine location information. */
     public static final int OP_FINE_LOCATION = 1;
+    /** @hide Causing GPS to run. */
     public static final int OP_GPS = 2;
+    /** @hide */
     public static final int OP_VIBRATE = 3;
+    /** @hide */
     public static final int OP_READ_CONTACTS = 4;
+    /** @hide */
     public static final int OP_WRITE_CONTACTS = 5;
+    /** @hide */
     public static final int OP_READ_CALL_LOG = 6;
+    /** @hide */
     public static final int OP_WRITE_CALL_LOG = 7;
+    /** @hide */
     public static final int OP_READ_CALENDAR = 8;
+    /** @hide */
     public static final int OP_WRITE_CALENDAR = 9;
+    /** @hide */
     public static final int OP_WIFI_SCAN = 10;
+    /** @hide */
     public static final int OP_POST_NOTIFICATION = 11;
+    /** @hide */
     public static final int OP_NEIGHBORING_CELLS = 12;
+    /** @hide */
     public static final int OP_CALL_PHONE = 13;
+    /** @hide */
     public static final int OP_READ_SMS = 14;
+    /** @hide */
     public static final int OP_WRITE_SMS = 15;
+    /** @hide */
     public static final int OP_RECEIVE_SMS = 16;
+    /** @hide */
     public static final int OP_RECEIVE_EMERGECY_SMS = 17;
+    /** @hide */
     public static final int OP_RECEIVE_MMS = 18;
+    /** @hide */
     public static final int OP_RECEIVE_WAP_PUSH = 19;
+    /** @hide */
     public static final int OP_SEND_SMS = 20;
+    /** @hide */
     public static final int OP_READ_ICC_SMS = 21;
+    /** @hide */
     public static final int OP_WRITE_ICC_SMS = 22;
+    /** @hide */
     public static final int OP_WRITE_SETTINGS = 23;
+    /** @hide */
     public static final int OP_SYSTEM_ALERT_WINDOW = 24;
+    /** @hide */
     public static final int OP_ACCESS_NOTIFICATIONS = 25;
+    /** @hide */
     public static final int OP_CAMERA = 26;
+    /** @hide */
     public static final int OP_RECORD_AUDIO = 27;
+    /** @hide */
     public static final int OP_PLAY_AUDIO = 28;
+    /** @hide */
     public static final int OP_READ_CLIPBOARD = 29;
+    /** @hide */
     public static final int OP_WRITE_CLIPBOARD = 30;
     /** @hide */
-    public static final int _NUM_OP = 31;
+    public static final int OP_TAKE_MEDIA_BUTTONS = 31;
+    /** @hide */
+    public static final int OP_TAKE_AUDIO_FOCUS = 32;
+    /** @hide */
+    public static final int OP_AUDIO_MASTER_VOLUME = 33;
+    /** @hide */
+    public static final int OP_AUDIO_VOICE_VOLUME = 34;
+    /** @hide */
+    public static final int OP_AUDIO_RING_VOLUME = 35;
+    /** @hide */
+    public static final int OP_AUDIO_MEDIA_VOLUME = 36;
+    /** @hide */
+    public static final int OP_AUDIO_ALARM_VOLUME = 37;
+    /** @hide */
+    public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
+    /** @hide */
+    public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
+    /** @hide */
+    public static final int OP_WAKE_LOCK = 40;
+    /** @hide Continually monitoring location data. */
+    public static final int OP_MONITOR_LOCATION = 41;
+    /** @hide Continually monitoring location data with a relatively high power request. */
+    public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
+    /** @hide */
+    public static final int _NUM_OP = 43;
+
+    /** Access to coarse location information. */
+    public static final String OPSTR_COARSE_LOCATION =
+            "android:coarse_location";
+    /** Access to fine location information. */
+    public static final String OPSTR_FINE_LOCATION =
+            "android:fine_location";
+    /** Continually monitoring location data. */
+    public static final String OPSTR_MONITOR_LOCATION
+            = "android:monitor_location";
+    /** Continually monitoring location data with a relatively high power request. */
+    public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION
+            = "android:monitor_location_high_power";
 
     /**
      * This maps each operation to the operation that serves as the
      * switch to determine whether it is allowed.  Generally this is
      * a 1:1 mapping, but for some things (like location) that have
      * multiple low-level operations being tracked that should be
-     * presented to hte user as one switch then this can be used to
+     * presented to the user as one switch then this can be used to
      * make them all controlled by the same single operation.
      */
     private static int[] sOpToSwitch = new int[] {
@@ -123,11 +225,11 @@
             OP_CALL_PHONE,
             OP_READ_SMS,
             OP_WRITE_SMS,
-            OP_READ_SMS,
-            OP_READ_SMS,
-            OP_READ_SMS,
-            OP_READ_SMS,
-            OP_WRITE_SMS,
+            OP_RECEIVE_SMS,
+            OP_RECEIVE_SMS,
+            OP_RECEIVE_SMS,
+            OP_RECEIVE_SMS,
+            OP_SEND_SMS,
             OP_READ_SMS,
             OP_WRITE_SMS,
             OP_WRITE_SETTINGS,
@@ -138,6 +240,68 @@
             OP_PLAY_AUDIO,
             OP_READ_CLIPBOARD,
             OP_WRITE_CLIPBOARD,
+            OP_TAKE_MEDIA_BUTTONS,
+            OP_TAKE_AUDIO_FOCUS,
+            OP_AUDIO_MASTER_VOLUME,
+            OP_AUDIO_VOICE_VOLUME,
+            OP_AUDIO_RING_VOLUME,
+            OP_AUDIO_MEDIA_VOLUME,
+            OP_AUDIO_ALARM_VOLUME,
+            OP_AUDIO_NOTIFICATION_VOLUME,
+            OP_AUDIO_BLUETOOTH_VOLUME,
+            OP_WAKE_LOCK,
+            OP_COARSE_LOCATION,
+            OP_COARSE_LOCATION,
+    };
+
+    /**
+     * This maps each operation to the public string constant for it.
+     * If it doesn't have a public string constant, it maps to null.
+     */
+    private static String[] sOpToString = new String[] {
+            OPSTR_COARSE_LOCATION,
+            OPSTR_FINE_LOCATION,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            OPSTR_MONITOR_LOCATION,
+            OPSTR_MONITOR_HIGH_POWER_LOCATION,
     };
 
     /**
@@ -176,6 +340,18 @@
             "PLAY_AUDIO",
             "READ_CLIPBOARD",
             "WRITE_CLIPBOARD",
+            "TAKE_MEDIA_BUTTONS",
+            "TAKE_AUDIO_FOCUS",
+            "AUDIO_MASTER_VOLUME",
+            "AUDIO_VOICE_VOLUME",
+            "AUDIO_RING_VOLUME",
+            "AUDIO_MEDIA_VOLUME",
+            "AUDIO_ALARM_VOLUME",
+            "AUDIO_NOTIFICATION_VOLUME",
+            "AUDIO_BLUETOOTH_VOLUME",
+            "WAKE_LOCK",
+            "MONITOR_LOCATION",
+            "MONITOR_HIGH_POWER_LOCATION",
     };
 
     /**
@@ -214,10 +390,159 @@
             null, // no permission for playing audio
             null, // no permission for reading clipboard
             null, // no permission for writing clipboard
+            null, // no permission for taking media buttons
+            null, // no permission for taking audio focus
+            null, // no permission for changing master volume
+            null, // no permission for changing voice volume
+            null, // no permission for changing ring volume
+            null, // no permission for changing media volume
+            null, // no permission for changing alarm volume
+            null, // no permission for changing notification volume
+            null, // no permission for changing bluetooth volume
+            android.Manifest.permission.WAKE_LOCK,
+            null, // no permission for generic location monitoring
+            null, // no permission for high power location monitoring
     };
 
     /**
+     * This specifies the default mode for each operation.
+     */
+    private static int[] sOpDefaultMode = new int[] {
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+    };
+
+    /**
+     * This specifies whether each option is allowed to be reset
+     * when resetting all app preferences.  Disable reset for
+     * app ops that are under strong control of some part of the
+     * system (such as OP_WRITE_SMS, which should be allowed only
+     * for whichever app is selected as the current SMS app).
+     */
+    private static boolean[] sOpDisableReset = new boolean[] {
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            true,      // OP_WRITE_SMS
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+            false,
+    };
+
+    private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
+
+    static {
+        if (sOpToSwitch.length != _NUM_OP) {
+            throw new IllegalStateException("sOpToSwitch length " + sOpToSwitch.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpToString.length != _NUM_OP) {
+            throw new IllegalStateException("sOpToString length " + sOpToString.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpNames.length != _NUM_OP) {
+            throw new IllegalStateException("sOpNames length " + sOpNames.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpPerms.length != _NUM_OP) {
+            throw new IllegalStateException("sOpPerms length " + sOpPerms.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpDefaultMode.length != _NUM_OP) {
+            throw new IllegalStateException("sOpDefaultMode length " + sOpDefaultMode.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpDisableReset.length != _NUM_OP) {
+            throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
+                    + " should be " + _NUM_OP);
+        }
+        for (int i=0; i<_NUM_OP; i++) {
+            if (sOpToString[i] != null) {
+                sOpStrToOp.put(sOpToString[i], i);
+            }
+        }
+    }
+
+    /**
      * Retrieve the op switch that controls the given operation.
+     * @hide
      */
     public static int opToSwitch(int op) {
         return sOpToSwitch[op];
@@ -225,6 +550,7 @@
 
     /**
      * Retrieve a non-localized name for the operation, for debugging output.
+     * @hide
      */
     public static String opToName(int op) {
         if (op == OP_NONE) return "NONE";
@@ -233,13 +559,31 @@
 
     /**
      * Retrieve the permission associated with an operation, or null if there is not one.
+     * @hide
      */
     public static String opToPermission(int op) {
         return sOpPerms[op];
     }
 
     /**
+     * Retrieve the default mode for the operation.
+     * @hide
+     */
+    public static int opToDefaultMode(int op) {
+        return sOpDefaultMode[op];
+    }
+
+    /**
+     * Retrieve whether the op allows itself to be reset.
+     * @hide
+     */
+    public static boolean opAllowsReset(int op) {
+        return !sOpDisableReset[op];
+    }
+
+    /**
      * Class holding all of the operation information associated with an app.
+     * @hide
      */
     public static class PackageOps implements Parcelable {
         private final String mPackageName;
@@ -302,6 +646,7 @@
 
     /**
      * Class holding the information about one unique operation of an application.
+     * @hide
      */
     public static class OpEntry implements Parcelable {
         private final int mOp;
@@ -378,11 +723,21 @@
     /**
      * Callback for notification of changes to operation state.
      */
-    public interface Callback {
-        public void opChanged(int op, String packageName);
+    public interface OnOpChangedListener {
+        public void onOpChanged(String op, String packageName);
     }
 
-    public AppOpsManager(Context context, IAppOpsService service) {
+    /**
+     * Callback for notification of changes to operation state.
+     * This allows you to see the raw op codes instead of strings.
+     * @hide
+     */
+    public static class OnOpChangedInternalListener implements OnOpChangedListener {
+        public void onOpChanged(String op, String packageName) { }
+        public void onOpChanged(int op, String packageName) { }
+    }
+
+    AppOpsManager(Context context, IAppOpsService service) {
         mContext = context;
         mService = service;
     }
@@ -391,6 +746,7 @@
      * Retrieve current operation state for all applications.
      *
      * @param ops The set of operations you are interested in, or null if you want all of them.
+     * @hide
      */
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
         try {
@@ -406,6 +762,7 @@
      * @param uid The uid of the application of interest.
      * @param packageName The name of the application of interest.
      * @param ops The set of operations you are interested in, or null if you want all of them.
+     * @hide
      */
     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
         try {
@@ -415,6 +772,7 @@
         return null;
     }
 
+    /** @hide */
     public void setMode(int code, int uid, String packageName, int mode) {
         try {
             mService.setMode(code, uid, packageName, mode);
@@ -430,13 +788,24 @@
         }
     }
 
-    public void startWatchingMode(int op, String packageName, final Callback callback) {
+    /**
+     * Monitor for changes to the operating mode for the given op in the given app package.
+     * @param op The operation to monitor, one of OP_*.
+     * @param packageName The name of the application to monitor.
+     * @param callback Where to report changes.
+     */
+    public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
         synchronized (mModeWatchers) {
             IAppOpsCallback cb = mModeWatchers.get(callback);
             if (cb == null) {
                 cb = new IAppOpsCallback.Stub() {
                     public void opChanged(int op, String packageName) {
-                        callback.opChanged(op, packageName);
+                        if (callback instanceof OnOpChangedInternalListener) {
+                            ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName);
+                        }
+                        if (sOpToString[op] != null) {
+                            callback.onOpChanged(sOpToString[op], packageName);
+                        }
                     }
                 };
                 mModeWatchers.put(callback, cb);
@@ -448,7 +817,11 @@
         }
     }
 
-    public void stopWatchingMode(Callback callback) {
+    /**
+     * Stop monitoring that was previously started with {@link #startWatchingMode}.  All
+     * monitoring associated with this callback will be removed.
+     */
+    public void stopWatchingMode(OnOpChangedListener callback) {
         synchronized (mModeWatchers) {
             IAppOpsCallback cb = mModeWatchers.get(callback);
             if (cb != null) {
@@ -460,11 +833,132 @@
         }
     }
 
+    private String buildSecurityExceptionMsg(int op, int uid, String packageName) {
+        return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
+    }
+
+    private int strOpToOp(String op) {
+        Integer val = sOpStrToOp.get(op);
+        if (val == null) {
+            throw new IllegalArgumentException("Unknown operation string: " + op);
+        }
+        return val;
+    }
+
+    /**
+     * Do a quick check for whether an application might be able to perform an operation.
+     * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String)}
+     * or {@link #startOp(String, int, String)} for your actual security checks, which also
+     * ensure that the given uid and package name are consistent.  This function can just be
+     * used for a quick check to see if an operation has been disabled for the application,
+     * as an early reject of some work.  This does not modify the time stamp or other data
+     * about the operation.
+     * @param op The operation to check.  One of the OPSTR_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     */
+    public int checkOp(String op, int uid, String packageName) {
+        return checkOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Like {@link #checkOp but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     */
+    public int checkOpNoThrow(String op, int uid, String packageName) {
+        return checkOpNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Make note of an application performing an operation.  Note that you must pass
+     * in both the uid and name of the application to be checked; this function will verify
+     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
+     * succeeds, the last execution time of the operation for this app will be updated to
+     * the current time.
+     * @param op The operation to note.  One of the OPSTR_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     */
+    public int noteOp(String op, int uid, String packageName) {
+        return noteOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     */
+    public int noteOpNoThrow(String op, int uid, String packageName) {
+        return noteOpNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Report that an application has started executing a long-running operation.  Note that you
+     * must pass in both the uid and name of the application to be checked; this function will
+     * verify that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
+     * succeeds, the last execution time of the operation for this app will be updated to
+     * the current time and the operation will be marked as "running".  In this case you must
+     * later call {@link #finishOp(String, int, String)} to report when the application is no
+     * longer performing the operation.
+     * @param op The operation to start.  One of the OPSTR_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     */
+    public int startOp(String op, int uid, String packageName) {
+        return startOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     */
+    public int startOpNoThrow(String op, int uid, String packageName) {
+        return startOpNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Report that an application is no longer performing an operation that had previously
+     * been started with {@link #startOp(String, int, String)}.  There is no validation of input
+     * or result; the parameters supplied here must be the exact same ones previously passed
+     * in when starting the operation.
+     */
+    public void finishOp(String op, int uid, String packageName) {
+        finishOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Do a quick check for whether an application might be able to perform an operation.
+     * This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
+     * or {@link #startOp(int, int, String)} for your actual security checks, which also
+     * ensure that the given uid and package name are consistent.  This function can just be
+     * used for a quick check to see if an operation has been disabled for the application,
+     * as an early reject of some work.  This does not modify the time stamp or other data
+     * about the operation.
+     * @param op The operation to check.  One of the OP_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     * @hide
+     */
     public int checkOp(int op, int uid, String packageName) {
         try {
             int mode = mService.checkOperation(op, uid, packageName);
             if (mode == MODE_ERRORED) {
-                throw new SecurityException("Operation not allowed");
+                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
             }
             return mode;
         } catch (RemoteException e) {
@@ -472,6 +966,11 @@
         return MODE_IGNORED;
     }
 
+    /**
+     * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     * @hide
+     */
     public int checkOpNoThrow(int op, int uid, String packageName) {
         try {
             return mService.checkOperation(op, uid, packageName);
@@ -480,11 +979,43 @@
         return MODE_IGNORED;
     }
 
+    /**
+     * Do a quick check to validate if a package name belongs to a UID.
+     *
+     * @throws SecurityException if the package name doesn't belong to the given
+     *             UID, or if ownership cannot be verified.
+     */
+    public void checkPackage(int uid, String packageName) {
+        try {
+            if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
+                throw new SecurityException(
+                        "Package " + packageName + " does not belong to " + uid);
+            }
+        } catch (RemoteException e) {
+            throw new SecurityException("Unable to verify package ownership", e);
+        }
+    }
+
+    /**
+     * Make note of an application performing an operation.  Note that you must pass
+     * in both the uid and name of the application to be checked; this function will verify
+     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
+     * succeeds, the last execution time of the operation for this app will be updated to
+     * the current time.
+     * @param op The operation to note.  One of the OP_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     * @hide
+     */
     public int noteOp(int op, int uid, String packageName) {
         try {
             int mode = mService.noteOperation(op, uid, packageName);
             if (mode == MODE_ERRORED) {
-                throw new SecurityException("Operation not allowed");
+                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
             }
             return mode;
         } catch (RemoteException e) {
@@ -492,6 +1023,11 @@
         return MODE_IGNORED;
     }
 
+    /**
+     * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     * @hide
+     */
     public int noteOpNoThrow(int op, int uid, String packageName) {
         try {
             return mService.noteOperation(op, uid, packageName);
@@ -500,15 +1036,48 @@
         return MODE_IGNORED;
     }
 
+    /** @hide */
     public int noteOp(int op) {
-        return noteOp(op, Process.myUid(), mContext.getBasePackageName());
+        return noteOp(op, Process.myUid(), mContext.getOpPackageName());
     }
 
+    /** @hide */
+    public static IBinder getToken(IAppOpsService service) {
+        synchronized (AppOpsManager.class) {
+            if (sToken != null) {
+                return sToken;
+            }
+            try {
+                sToken = service.getToken(new Binder());
+            } catch (RemoteException e) {
+                // System is dead, whatevs.
+            }
+            return sToken;
+        }
+    }
+
+    /**
+     * Report that an application has started executing a long-running operation.  Note that you
+     * must pass in both the uid and name of the application to be checked; this function will
+     * verify that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
+     * succeeds, the last execution time of the operation for this app will be updated to
+     * the current time and the operation will be marked as "running".  In this case you must
+     * later call {@link #finishOp(int, int, String)} to report when the application is no
+     * longer performing the operation.
+     * @param op The operation to start.  One of the OP_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     * @hide
+     */
     public int startOp(int op, int uid, String packageName) {
         try {
-            int mode = mService.startOperation(op, uid, packageName);
+            int mode = mService.startOperation(getToken(mService), op, uid, packageName);
             if (mode == MODE_ERRORED) {
-                throw new SecurityException("Operation not allowed");
+                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
             }
             return mode;
         } catch (RemoteException e) {
@@ -516,26 +1085,40 @@
         return MODE_IGNORED;
     }
 
+    /**
+     * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     * @hide
+     */
     public int startOpNoThrow(int op, int uid, String packageName) {
         try {
-            return mService.startOperation(op, uid, packageName);
+            return mService.startOperation(getToken(mService), op, uid, packageName);
         } catch (RemoteException e) {
         }
         return MODE_IGNORED;
     }
 
+    /** @hide */
     public int startOp(int op) {
-        return startOp(op, Process.myUid(), mContext.getBasePackageName());
+        return startOp(op, Process.myUid(), mContext.getOpPackageName());
     }
 
+    /**
+     * Report that an application is no longer performing an operation that had previously
+     * been started with {@link #startOp(int, int, String)}.  There is no validation of input
+     * or result; the parameters supplied here must be the exact same ones previously passed
+     * in when starting the operation.
+     * @hide
+     */
     public void finishOp(int op, int uid, String packageName) {
         try {
-            mService.finishOperation(op, uid, packageName);
+            mService.finishOperation(getToken(mService), op, uid, packageName);
         } catch (RemoteException e) {
         }
     }
 
+    /** @hide */
     public void finishOp(int op) {
-        finishOp(op, Process.myUid(), mContext.getBasePackageName());
+        finishOp(op, Process.myUid(), mContext.getOpPackageName());
     }
 }
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 954476d..c117486 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -28,6 +28,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Printer;
+import com.android.internal.util.FastPrintWriter;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -327,7 +328,9 @@
          */
         public CrashInfo(Throwable tr) {
             StringWriter sw = new StringWriter();
-            tr.printStackTrace(new PrintWriter(sw));
+            PrintWriter pw = new FastPrintWriter(sw, false, 256);
+            tr.printStackTrace(pw);
+            pw.flush();
             stackTrace = sw.toString();
             exceptionMessage = tr.getMessage();
 
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index a26b88c..413c369 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -17,11 +17,9 @@
 package android.app;
 
 import android.os.Trace;
+import android.util.ArrayMap;
 import dalvik.system.PathClassLoader;
 
-import java.util.HashMap;
-import java.util.Map;
-
 class ApplicationLoaders
 {
     public static ApplicationLoaders getDefault()
@@ -71,7 +69,7 @@
         }
     }
 
-    private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>();
+    private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>();
 
     private static final ApplicationLoaders gApplicationLoaders
         = new ApplicationLoaders();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 271494f..55c66726 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -51,6 +51,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
 
@@ -859,26 +860,20 @@
             boolean needCleanup = false;
             for (String ssp : pkgList) {
                 synchronized (sSync) {
-                    if (sIconCache.size() > 0) {
-                        Iterator<ResourceName> it = sIconCache.keySet().iterator();
-                        while (it.hasNext()) {
-                            ResourceName nm = it.next();
-                            if (nm.packageName.equals(ssp)) {
-                                //Log.i(TAG, "Removing cached drawable for " + nm);
-                                it.remove();
-                                needCleanup = true;
-                            }
+                    for (int i=sIconCache.size()-1; i>=0; i--) {
+                        ResourceName nm = sIconCache.keyAt(i);
+                        if (nm.packageName.equals(ssp)) {
+                            //Log.i(TAG, "Removing cached drawable for " + nm);
+                            sIconCache.removeAt(i);
+                            needCleanup = true;
                         }
                     }
-                    if (sStringCache.size() > 0) {
-                        Iterator<ResourceName> it = sStringCache.keySet().iterator();
-                        while (it.hasNext()) {
-                            ResourceName nm = it.next();
-                            if (nm.packageName.equals(ssp)) {
-                                //Log.i(TAG, "Removing cached string for " + nm);
-                                it.remove();
-                                needCleanup = true;
-                            }
+                    for (int i=sStringCache.size()-1; i>=0; i--) {
+                        ResourceName nm = sStringCache.keyAt(i);
+                        if (nm.packageName.equals(ssp)) {
+                            //Log.i(TAG, "Removing cached string for " + nm);
+                            sStringCache.removeAt(i);
+                            needCleanup = true;
                         }
                     }
                 }
@@ -1256,6 +1251,16 @@
     }
 
     @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+        try {
+            return mPM.getHomeActivities(outActivities);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+        return null;
+    }
+
+    @Override
     public void setComponentEnabledSetting(ComponentName componentName,
                                            int newState, int flags) {
         try {
@@ -1280,7 +1285,7 @@
                                              int newState, int flags) {
         try {
             mPM.setApplicationEnabledSetting(packageName, newState, flags,
-                    mContext.getUserId(), mContext.getBasePackageName());
+                    mContext.getUserId(), mContext.getOpPackageName());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1296,6 +1301,28 @@
         return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
     }
 
+    @Override
+    public boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked,
+            UserHandle user) {
+        try {
+            return mPM.setApplicationBlockedSettingAsUser(packageName, blocked,
+                    user.getIdentifier());
+        } catch (RemoteException re) {
+            // Should never happen!
+        }
+        return false;
+    }
+
+    @Override
+    public boolean getApplicationBlockedSettingAsUser(String packageName, UserHandle user) {
+        try {
+            return mPM.getApplicationBlockedSettingAsUser(packageName, user.getIdentifier());
+        } catch (RemoteException re) {
+            // Should never happen!
+        }
+        return false;
+    }
+
     /**
      * @hide
      */
@@ -1313,8 +1340,8 @@
     private final IPackageManager mPM;
 
     private static final Object sSync = new Object();
-    private static HashMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache
-            = new HashMap<ResourceName, WeakReference<Drawable.ConstantState>>();
-    private static HashMap<ResourceName, WeakReference<CharSequence>> sStringCache
-            = new HashMap<ResourceName, WeakReference<CharSequence>>();
+    private static ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache
+            = new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>();
+    private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache
+            = new ArrayMap<ResourceName, WeakReference<CharSequence>>();
 }
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index b1c58f2..e40a04b 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -111,8 +111,9 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder b = data.readStrongBinder();
+            int procState = data.readInt();
             boolean isForward = data.readInt() != 0;
-            scheduleResumeActivity(b, isForward);
+            scheduleResumeActivity(b, procState, isForward);
             return true;
         }
         
@@ -134,6 +135,7 @@
             ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
             Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+            int procState = data.readInt();
             Bundle state = data.readBundle();
             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
             List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
@@ -141,10 +143,10 @@
             boolean isForward = data.readInt() != 0;
             String profileName = data.readString();
             ParcelFileDescriptor profileFd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             boolean autoStopProfiler = data.readInt() != 0;
-            scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, state, ri, pi,
-                    notResumed, isForward, profileName, profileFd, autoStopProfiler);
+            scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, procState, state,
+                    ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler);
             return true;
         }
         
@@ -194,8 +196,9 @@
             Bundle resultExtras = data.readBundle();
             boolean sync = data.readInt() != 0;
             int sendingUser = data.readInt();
+            int processState = data.readInt();
             scheduleReceiver(intent, info, compatInfo, resultCode, resultData,
-                    resultExtras, sync, sendingUser);
+                    resultExtras, sync, sendingUser, processState);
             return true;
         }
 
@@ -204,7 +207,8 @@
             IBinder token = data.readStrongBinder();
             ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data);
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
-            scheduleCreateService(token, info, compatInfo);
+            int processState = data.readInt();
+            scheduleCreateService(token, info, compatInfo, processState);
             return true;
         }
 
@@ -213,7 +217,8 @@
             IBinder token = data.readStrongBinder();
             Intent intent = Intent.CREATOR.createFromParcel(data);
             boolean rebind = data.readInt() != 0;
-            scheduleBindService(token, intent, rebind);
+            int processState = data.readInt();
+            scheduleBindService(token, intent, rebind, processState);
             return true;
         }
 
@@ -262,7 +267,7 @@
                 ? new ComponentName(data) : null;
             String profileName = data.readString();
             ParcelFileDescriptor profileFd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             boolean autoStopProfiler = data.readInt() != 0;
             Bundle testArgs = data.readBundle();
             IBinder binder = data.readStrongBinder();
@@ -333,7 +338,8 @@
             final String proxy = data.readString();
             final String port = data.readString();
             final String exclList = data.readString();
-            setHttpProxy(proxy, port, exclList);
+            final String pacFileUrl = data.readString();
+            setHttpProxy(proxy, port, exclList, pacFileUrl);
             return true;
         }
 
@@ -384,8 +390,9 @@
             boolean ordered = data.readInt() != 0;
             boolean sticky = data.readInt() != 0;
             int sendingUser = data.readInt();
+            int processState = data.readInt();
             scheduleRegisteredReceiver(receiver, intent,
-                    resultCode, dataStr, extras, ordered, sticky, sendingUser);
+                    resultCode, dataStr, extras, ordered, sticky, sendingUser, processState);
             return true;
         }
 
@@ -411,7 +418,7 @@
             int profileType = data.readInt();
             String path = data.readString();
             ParcelFileDescriptor fd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             profilerControl(start, path, fd, profileType);
             return true;
         }
@@ -443,16 +450,6 @@
             return true;
         }
 
-        case GET_MEMORY_INFO_TRANSACTION:
-        {
-            data.enforceInterface(IApplicationThread.descriptor);
-            Debug.MemoryInfo mi = new Debug.MemoryInfo();
-            getMemoryInfo(mi);
-            reply.writeNoException();
-            mi.writeToParcel(reply, 0);
-            return true;
-        }
-
         case DISPATCH_PACKAGE_BROADCAST_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
@@ -476,7 +473,7 @@
             boolean managed = data.readInt() != 0;
             String path = data.readString();
             ParcelFileDescriptor fd = data.readInt() != 0
-                    ? data.readFileDescriptor() : null;
+                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             dumpHeap(managed, path, fd);
             return true;
         }
@@ -523,13 +520,14 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             ParcelFileDescriptor fd = data.readFileDescriptor();
+            Debug.MemoryInfo mi = Debug.MemoryInfo.CREATOR.createFromParcel(data);
             boolean checkin = data.readInt() != 0;
-            boolean all = data.readInt() != 0;
+            boolean dumpInfo = data.readInt() != 0;
+            boolean dumpDalvik = data.readInt() != 0;
             String[] args = data.readStringArray();
-            Debug.MemoryInfo mi = null;
             if (fd != null) {
                 try {
-                    mi = dumpMemInfo(fd.getFileDescriptor(), checkin, all, args);
+                    dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo, dumpDalvik, args);
                 } finally {
                     try {
                         fd.close();
@@ -539,7 +537,6 @@
                 }
             }
             reply.writeNoException();
-            mi.writeToParcel(reply, 0);
             return true;
         }
 
@@ -592,13 +589,32 @@
             return true;
         }
 
-        case REQUEST_ACTIVITY_EXTRAS_TRANSACTION:
+        case REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder activityToken = data.readStrongBinder();
             IBinder requestToken = data.readStrongBinder();
             int requestType = data.readInt();
-            requestActivityExtras(activityToken, requestToken, requestType);
+            requestAssistContextExtras(activityToken, requestToken, requestType);
+            reply.writeNoException();
+            return true;
+        }
+
+        case SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            IBinder token = data.readStrongBinder();
+            boolean timeout = data.readInt() == 1;
+            scheduleTranslucentConversionComplete(token, timeout);
+            reply.writeNoException();
+            return true;
+        }
+
+        case SET_PROCESS_STATE_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            int state = data.readInt();
+            setProcessState(state);
             reply.writeNoException();
             return true;
         }
@@ -671,11 +687,12 @@
         data.recycle();
     }
 
-    public final void scheduleResumeActivity(IBinder token, boolean isForward)
+    public final void scheduleResumeActivity(IBinder token, int procState, boolean isForward)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
+        data.writeInt(procState);
         data.writeInt(isForward ? 1 : 0);
         mRemote.transact(SCHEDULE_RESUME_ACTIVITY_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
@@ -695,7 +712,7 @@
 
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            Bundle state, List<ResultInfo> pendingResults,
+            int procState, Bundle state, List<ResultInfo> pendingResults,
     		List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
     		String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
     		throws RemoteException {
@@ -707,6 +724,7 @@
         info.writeToParcel(data, 0);
         curConfig.writeToParcel(data, 0);
         compatInfo.writeToParcel(data, 0);
+        data.writeInt(procState);
         data.writeBundle(state);
         data.writeTypedList(pendingResults);
         data.writeTypedList(pendingNewIntents);
@@ -772,7 +790,7 @@
     
     public final void scheduleReceiver(Intent intent, ActivityInfo info,
             CompatibilityInfo compatInfo, int resultCode, String resultData,
-            Bundle map, boolean sync, int sendingUser) throws RemoteException {
+            Bundle map, boolean sync, int sendingUser, int processState) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         intent.writeToParcel(data, 0);
@@ -783,6 +801,7 @@
         data.writeBundle(map);
         data.writeInt(sync ? 1 : 0);
         data.writeInt(sendingUser);
+        data.writeInt(processState);
         mRemote.transact(SCHEDULE_RECEIVER_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
@@ -812,24 +831,26 @@
     }
     
     public final void scheduleCreateService(IBinder token, ServiceInfo info,
-            CompatibilityInfo compatInfo) throws RemoteException {
+            CompatibilityInfo compatInfo, int processState) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
         info.writeToParcel(data, 0);
         compatInfo.writeToParcel(data, 0);
+        data.writeInt(processState);
         mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 
-    public final void scheduleBindService(IBinder token, Intent intent, boolean rebind)
-            throws RemoteException {
+    public final void scheduleBindService(IBinder token, Intent intent, boolean rebind,
+            int processState) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
         intent.writeToParcel(data, 0);
         data.writeInt(rebind ? 1 : 0);
+        data.writeInt(processState);
         mRemote.transact(SCHEDULE_BIND_SERVICE_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
@@ -970,12 +991,14 @@
         data.recycle();
     }
 
-    public void setHttpProxy(String proxy, String port, String exclList) throws RemoteException {
+    public void setHttpProxy(String proxy, String port, String exclList,
+            String pacFileUrl) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeString(proxy);
         data.writeString(port);
         data.writeString(exclList);
+        data.writeString(pacFileUrl);
         mRemote.transact(SET_HTTP_PROXY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
         data.recycle();
     }
@@ -1012,7 +1035,7 @@
 
     public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
             int resultCode, String dataStr, Bundle extras, boolean ordered,
-            boolean sticky, int sendingUser) throws RemoteException {
+            boolean sticky, int sendingUser, int processState) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(receiver.asBinder());
@@ -1023,6 +1046,7 @@
         data.writeInt(ordered ? 1 : 0);
         data.writeInt(sticky ? 1 : 0);
         data.writeInt(sendingUser);
+        data.writeInt(processState);
         mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
@@ -1073,17 +1097,6 @@
         data.recycle();
     }
     
-    public void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IApplicationThread.descriptor);
-        mRemote.transact(GET_MEMORY_INFO_TRANSACTION, data, reply, 0);
-        reply.readException();
-        outInfo.readFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-    }
-    
     public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1159,22 +1172,21 @@
                 IBinder.FLAG_ONEWAY);
     }
 
-    public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all,
-            String[] args) throws RemoteException {
+    public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
+            boolean dumpInfo, boolean dumpDalvik, String[] args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeFileDescriptor(fd);
+        mem.writeToParcel(data, 0);
         data.writeInt(checkin ? 1 : 0);
-        data.writeInt(all ? 1 : 0);
+        data.writeInt(dumpInfo ? 1 : 0);
+        data.writeInt(dumpDalvik ? 1 : 0);
         data.writeStringArray(args);
         mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
-        Debug.MemoryInfo info = new Debug.MemoryInfo();
-        info.readFromParcel(reply);
         data.recycle();
         reply.recycle();
-        return info;
     }
 
     public void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException {
@@ -1195,6 +1207,7 @@
         data.recycle();
     }
 
+    @Override
     public void unstableProviderDied(IBinder provider) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1203,14 +1216,36 @@
         data.recycle();
     }
 
-    public void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType)
-            throws RemoteException {
+    @Override
+    public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
+            int requestType) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(activityToken);
         data.writeStrongBinder(requestToken);
         data.writeInt(requestType);
-        mRemote.transact(REQUEST_ACTIVITY_EXTRAS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
+
+    @Override
+    public void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeStrongBinder(token);
+        data.writeInt(timeout ? 1 : 0);
+        mRemote.transact(SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
+
+    @Override
+    public void setProcessState(int state) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeInt(state);
+        mRemote.transact(SET_PROCESS_STATE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 }
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 1b1d341..89ee145 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -21,6 +21,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.LogWriter;
+import com.android.internal.util.FastPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -583,8 +584,9 @@
         if (FragmentManagerImpl.DEBUG) {
             Log.v(TAG, "Commit: " + this);
             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
-            PrintWriter pw = new PrintWriter(logw);
+            PrintWriter pw = new FastPrintWriter(logw, false, 1024);
             dump("  ", null, pw, null);
+            pw.flush();
         }
         mCommitted = true;
         if (mAddToBackStack) {
@@ -691,8 +693,9 @@
         if (FragmentManagerImpl.DEBUG) {
             Log.v(TAG, "popFromBackStack: " + this);
             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
-            PrintWriter pw = new PrintWriter(logw);
+            PrintWriter pw = new FastPrintWriter(logw, false, 1024);
             dump("  ", null, pw, null);
+            pw.flush();
         }
 
         bumpBackStackNesting(-1);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3fc82fa..300424c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.os.Build;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.Preconditions;
 
@@ -46,9 +47,11 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.hardware.ConsumerIrManager;
 import android.hardware.ISerialManager;
 import android.hardware.SerialManager;
 import android.hardware.SystemSensorManager;
+import android.hardware.camera2.CameraManager;
 import android.hardware.display.DisplayManager;
 import android.hardware.input.InputManager;
 import android.hardware.usb.IUsbManager;
@@ -89,23 +92,29 @@
 import android.os.UserHandle;
 import android.os.SystemVibrator;
 import android.os.UserManager;
+import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
+import android.print.IPrintManager;
+import android.print.PrintManager;
 import android.telephony.TelephonyManager;
 import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
-import android.view.CompatibilityInfoHolder;
+import android.view.DisplayAdjustments;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
 import android.view.inputmethod.InputMethodManager;
 import android.view.textservice.TextServicesManager;
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.app.admin.DevicePolicyManager;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.os.IDropBoxManagerService;
 
@@ -169,11 +178,14 @@
     private final static String TAG = "ContextImpl";
     private final static boolean DEBUG = false;
 
-    private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
-            new HashMap<String, SharedPreferencesImpl>();
+    /**
+     * Map from package name, to preference name, to cached preferences.
+     */
+    private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;
 
     /*package*/ LoadedApk mPackageInfo;
     private String mBasePackageName;
+    private String mOpPackageName;
     private Resources mResources;
     /*package*/ ActivityThread mMainThread;
     private Context mOuterContext;
@@ -186,19 +198,30 @@
     private Context mReceiverRestrictedContext = null;
     private boolean mRestricted;
     private UserHandle mUser;
+    private ResourcesManager mResourcesManager;
 
     private final Object mSync = new Object();
 
+    @GuardedBy("mSync")
     private File mDatabasesDir;
+    @GuardedBy("mSync")
     private File mPreferencesDir;
+    @GuardedBy("mSync")
     private File mFilesDir;
+    @GuardedBy("mSync")
     private File mCacheDir;
-    private File mObbDir;
-    private File mExternalFilesDir;
-    private File mExternalCacheDir;
+
+    @GuardedBy("mSync")
+    private File[] mExternalObbDirs;
+    @GuardedBy("mSync")
+    private File[] mExternalFilesDirs;
+    @GuardedBy("mSync")
+    private File[] mExternalCacheDirs;
 
     private static final String[] EMPTY_FILE_LIST = {};
 
+    final private DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+
     /**
      * Override this class when the system service constructor needs a
      * ContextImpl.  Else, use StaticServiceFetcher below.
@@ -288,6 +311,11 @@
                     return AccessibilityManager.getInstance(ctx);
                 }});
 
+        registerService(CAPTIONING_SERVICE, new ServiceFetcher() {
+                public Object getService(ContextImpl ctx) {
+                    return new CaptioningManager(ctx);
+                }});
+
         registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
@@ -300,11 +328,11 @@
                     return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
                 }});
 
-        registerService(ALARM_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
+        registerService(ALARM_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(ALARM_SERVICE);
                     IAlarmManager service = IAlarmManager.Stub.asInterface(b);
-                    return new AlarmManager(service);
+                    return new AlarmManager(service, ctx);
                 }});
 
         registerService(AUDIO_SERVICE, new ServiceFetcher() {
@@ -513,12 +541,16 @@
                 }});
 
         registerService(WINDOW_SERVICE, new ServiceFetcher() {
+                Display mDefaultDisplay;
                 public Object getService(ContextImpl ctx) {
                     Display display = ctx.mDisplay;
                     if (display == null) {
-                        DisplayManager dm = (DisplayManager)ctx.getOuterContext().getSystemService(
-                                Context.DISPLAY_SERVICE);
-                        display = dm.getDisplay(Display.DEFAULT_DISPLAY);
+                        if (mDefaultDisplay == null) {
+                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
+                                    getSystemService(Context.DISPLAY_SERVICE);
+                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
+                        }
+                        display = mDefaultDisplay;
                     }
                     return new WindowManagerImpl(display);
                 }});
@@ -536,6 +568,25 @@
                 IAppOpsService service = IAppOpsService.Stub.asInterface(b);
                 return new AppOpsManager(ctx, service);
             }});
+
+        registerService(CAMERA_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                return new CameraManager(ctx);
+            }
+        });
+
+        registerService(PRINT_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
+                IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
+                return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
+                        UserHandle.getAppId(Process.myUid()));
+            }});
+
+        registerService(CONSUMER_IR_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                return new ConsumerIrManager(ctx);
+            }});
     }
 
     static ContextImpl getImpl(Context context) {
@@ -636,6 +687,12 @@
         return mBasePackageName != null ? mBasePackageName : getPackageName();
     }
 
+    /** @hide */
+    @Override
+    public String getOpPackageName() {
+        return mOpPackageName != null ? mOpPackageName : getBasePackageName();
+    }
+
     @Override
     public ApplicationInfo getApplicationInfo() {
         if (mPackageInfo != null) {
@@ -667,12 +724,33 @@
     @Override
     public SharedPreferences getSharedPreferences(String name, int mode) {
         SharedPreferencesImpl sp;
-        synchronized (sSharedPrefs) {
-            sp = sSharedPrefs.get(name);
+        synchronized (ContextImpl.class) {
+            if (sSharedPrefs == null) {
+                sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
+            }
+
+            final String packageName = getPackageName();
+            ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
+            if (packagePrefs == null) {
+                packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();
+                sSharedPrefs.put(packageName, packagePrefs);
+            }
+
+            // At least one application in the world actually passes in a null
+            // name.  This happened to work because when we generated the file name
+            // we would stringify it to "null.xml".  Nice.
+            if (mPackageInfo.getApplicationInfo().targetSdkVersion <
+                    Build.VERSION_CODES.KITKAT) {
+                if (name == null) {
+                    name = "null";
+                }
+            }
+
+            sp = packagePrefs.get(name);
             if (sp == null) {
                 File prefsFile = getSharedPrefsFile(name);
                 sp = new SharedPreferencesImpl(prefsFile, mode);
-                sSharedPrefs.put(name, sp);
+                packagePrefs.put(name, sp);
                 return sp;
             }
         }
@@ -753,44 +831,43 @@
 
     @Override
     public File getExternalFilesDir(String type) {
+        // Operates on primary external storage
+        return getExternalFilesDirs(type)[0];
+    }
+
+    @Override
+    public File[] getExternalFilesDirs(String type) {
         synchronized (mSync) {
-            if (mExternalFilesDir == null) {
-                mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
-                        getPackageName());
+            if (mExternalFilesDirs == null) {
+                mExternalFilesDirs = Environment.buildExternalStorageAppFilesDirs(getPackageName());
             }
-            if (!mExternalFilesDir.exists()) {
-                try {
-                    (new File(Environment.getExternalStorageAndroidDataDir(),
-                            ".nomedia")).createNewFile();
-                } catch (IOException e) {
-                }
-                if (!mExternalFilesDir.mkdirs()) {
-                    Log.w(TAG, "Unable to create external files directory");
-                    return null;
-                }
+
+            // Splice in requested type, if any
+            File[] dirs = mExternalFilesDirs;
+            if (type != null) {
+                dirs = Environment.buildPaths(dirs, type);
             }
-            if (type == null) {
-                return mExternalFilesDir;
-            }
-            File dir = new File(mExternalFilesDir, type);
-            if (!dir.exists()) {
-                if (!dir.mkdirs()) {
-                    Log.w(TAG, "Unable to create external media directory " + dir);
-                    return null;
-                }
-            }
-            return dir;
+
+            // Create dirs if needed
+            return ensureDirsExistOrFilter(dirs);
         }
     }
 
     @Override
     public File getObbDir() {
+        // Operates on primary external storage
+        return getObbDirs()[0];
+    }
+
+    @Override
+    public File[] getObbDirs() {
         synchronized (mSync) {
-            if (mObbDir == null) {
-                mObbDir = Environment.getExternalStorageAppObbDirectory(
-                        getPackageName());
+            if (mExternalObbDirs == null) {
+                mExternalObbDirs = Environment.buildExternalStorageAppObbDirs(getPackageName());
             }
-            return mObbDir;
+
+            // Create dirs if needed
+            return ensureDirsExistOrFilter(mExternalObbDirs);
         }
     }
 
@@ -816,23 +893,19 @@
 
     @Override
     public File getExternalCacheDir() {
+        // Operates on primary external storage
+        return getExternalCacheDirs()[0];
+    }
+
+    @Override
+    public File[] getExternalCacheDirs() {
         synchronized (mSync) {
-            if (mExternalCacheDir == null) {
-                mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
-                        getPackageName());
+            if (mExternalCacheDirs == null) {
+                mExternalCacheDirs = Environment.buildExternalStorageAppCacheDirs(getPackageName());
             }
-            if (!mExternalCacheDir.exists()) {
-                try {
-                    (new File(Environment.getExternalStorageAndroidDataDir(),
-                            ".nomedia")).createNewFile();
-                } catch (IOException e) {
-                }
-                if (!mExternalCacheDir.mkdirs()) {
-                    Log.w(TAG, "Unable to create external cache directory");
-                    return null;
-                }
-            }
-            return mExternalCacheDir;
+
+            // Create dirs if needed
+            return ensureDirsExistOrFilter(mExternalCacheDirs);
         }
     }
 
@@ -1395,6 +1468,14 @@
     @Override
     public ComponentName startServiceAsUser(Intent service, UserHandle user) {
         try {
+            if (service.getComponent() == null && service.getPackage() == null) {
+                if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
+                    IllegalArgumentException ex = new IllegalArgumentException(
+                            "Service Intent must be explicit: " + service);
+                    Log.e(TAG, "This will become an error", ex);
+                    //throw ex;
+                }
+            }
             service.prepareToLeaveProcess();
             ComponentName cn = ActivityManagerNative.getDefault().startService(
                 mMainThread.getApplicationThread(), service,
@@ -1419,6 +1500,14 @@
     @Override
     public boolean stopServiceAsUser(Intent service, UserHandle user) {
         try {
+            if (service.getComponent() == null && service.getPackage() == null) {
+                if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
+                    IllegalArgumentException ex = new IllegalArgumentException(
+                            "Service Intent must be explicit: " + service);
+                    Log.e(TAG, "This will become an error", ex);
+                    //throw ex;
+                }
+            }
             service.prepareToLeaveProcess();
             int res = ActivityManagerNative.getDefault().stopService(
                 mMainThread.getApplicationThread(), service,
@@ -1454,6 +1543,14 @@
         } else {
             throw new RuntimeException("Not supported in system context");
         }
+        if (service.getComponent() == null && service.getPackage() == null) {
+            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
+                IllegalArgumentException ex = new IllegalArgumentException(
+                        "Service Intent must be explicit: " + service);
+                Log.e(TAG, "This will become an error", ex);
+                //throw ex;
+            }
+        }
         try {
             IBinder token = getActivityToken();
             if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
@@ -1746,6 +1843,11 @@
                       message);
     }
 
+    /**
+     * Logs a warning if the system process directly called a method such as
+     * {@link #startService(Intent)} instead of {@link #startServiceAsUser(Intent, UserHandle)}.
+     * The "AsUser" variants allow us to properly enforce the user's restrictions.
+     */
     private void warnIfCallingFromSystemProcess() {
         if (Process.myUid() == Process.SYSTEM_UID) {
             Slog.w(TAG, "Calling a method in the system process without a qualified user: "
@@ -1795,10 +1897,9 @@
 
         ContextImpl c = new ContextImpl();
         c.init(mPackageInfo, null, mMainThread);
-        c.mResources = mMainThread.getTopLevelResources(
-                mPackageInfo.getResDir(),
-                getDisplayId(), overrideConfiguration,
-                mResources.getCompatibilityInfo());
+        c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
+                getDisplayId(), overrideConfiguration, mResources.getCompatibilityInfo(),
+                mActivityToken);
         return c;
     }
 
@@ -1809,17 +1910,13 @@
         }
 
         int displayId = display.getDisplayId();
-        CompatibilityInfo ci = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-        CompatibilityInfoHolder cih = getCompatibilityInfo(displayId);
-        if (cih != null) {
-            ci = cih.get();
-        }
 
         ContextImpl context = new ContextImpl();
         context.init(mPackageInfo, null, mMainThread);
         context.mDisplay = display;
-        context.mResources = mMainThread.getTopLevelResources(
-                mPackageInfo.getResDir(), displayId, null, ci);
+        DisplayAdjustments daj = getDisplayAdjustments(displayId);
+        context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
+                displayId, null, daj.getCompatibilityInfo(), null);
         return context;
     }
 
@@ -1833,8 +1930,8 @@
     }
 
     @Override
-    public CompatibilityInfoHolder getCompatibilityInfo(int displayId) {
-        return displayId == Display.DEFAULT_DISPLAY ? mPackageInfo.mCompatibilityInfo : null;
+    public DisplayAdjustments getDisplayAdjustments(int displayId) {
+        return mDisplayAdjustments;
     }
 
     private File getDataDirFile() {
@@ -1880,12 +1977,14 @@
     public ContextImpl(ContextImpl context) {
         mPackageInfo = context.mPackageInfo;
         mBasePackageName = context.mBasePackageName;
+        mOpPackageName = context.mOpPackageName;
         mResources = context.mResources;
         mMainThread = context.mMainThread;
         mContentResolver = context.mContentResolver;
         mUser = context.mUser;
         mDisplay = context.mDisplay;
         mOuterContext = this;
+        mDisplayAdjustments.setCompatibilityInfo(mPackageInfo.getCompatibilityInfo());
     }
 
     final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) {
@@ -1895,19 +1994,44 @@
     final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,
             Resources container, String basePackageName, UserHandle user) {
         mPackageInfo = packageInfo;
-        mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
+        if (basePackageName != null) {
+            mBasePackageName = mOpPackageName = basePackageName;
+        } else {
+            mBasePackageName = packageInfo.mPackageName;
+            ApplicationInfo ainfo = packageInfo.getApplicationInfo();
+            if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
+                // Special case: system components allow themselves to be loaded in to other
+                // processes.  For purposes of app ops, we must then consider the context as
+                // belonging to the package of this process, not the system itself, otherwise
+                // the package+uid verifications in app ops will fail.
+                mOpPackageName = ActivityThread.currentPackageName();
+            } else {
+                mOpPackageName = mBasePackageName;
+            }
+        }
         mResources = mPackageInfo.getResources(mainThread);
+        mResourcesManager = ResourcesManager.getInstance();
 
-        if (mResources != null && container != null
-                && container.getCompatibilityInfo().applicationScale !=
-                        mResources.getCompatibilityInfo().applicationScale) {
+        CompatibilityInfo compatInfo =
+                container == null ? null : container.getCompatibilityInfo();
+        if (mResources != null &&
+                ((compatInfo != null && compatInfo.applicationScale !=
+                        mResources.getCompatibilityInfo().applicationScale)
+                || activityToken != null)) {
             if (DEBUG) {
                 Log.d(TAG, "loaded context has different scaling. Using container's" +
                         " compatiblity info:" + container.getDisplayMetrics());
             }
-            mResources = mainThread.getTopLevelResources(
-                    mPackageInfo.getResDir(), Display.DEFAULT_DISPLAY,
-                    null, container.getCompatibilityInfo());
+            if (compatInfo == null) {
+                compatInfo = packageInfo.getCompatibilityInfo();
+            }
+            mDisplayAdjustments.setCompatibilityInfo(compatInfo);
+            mDisplayAdjustments.setActivityToken(activityToken);
+            mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
+                    Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
+        } else {
+            mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
+            mDisplayAdjustments.setActivityToken(activityToken);
         }
         mMainThread = mainThread;
         mActivityToken = activityToken;
@@ -1918,6 +2042,7 @@
     final void init(Resources resources, ActivityThread mainThread, UserHandle user) {
         mPackageInfo = null;
         mBasePackageName = null;
+        mOpPackageName = null;
         mResources = resources;
         mMainThread = mainThread;
         mContentResolver = new ApplicationContentResolver(this, mainThread, user);
@@ -2001,6 +2126,36 @@
                 "File " + name + " contains a path separator");
     }
 
+    /**
+     * Ensure that given directories exist, trying to create them if missing. If
+     * unable to create, they are filtered by replacing with {@code null}.
+     */
+    private File[] ensureDirsExistOrFilter(File[] dirs) {
+        File[] result = new File[dirs.length];
+        for (int i = 0; i < dirs.length; i++) {
+            File dir = dirs[i];
+            if (!dir.exists()) {
+                if (!dir.mkdirs()) {
+                    // Failing to mkdir() may be okay, since we might not have
+                    // enough permissions; ask vold to create on our behalf.
+                    final IMountService mount = IMountService.Stub.asInterface(
+                            ServiceManager.getService("mount"));
+                    int res = -1;
+                    try {
+                        res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
+                    } catch (RemoteException e) {
+                    }
+                    if (res != 0) {
+                        Log.w(TAG, "Failed to ensure directory: " + dir);
+                        dir = null;
+                    }
+                }
+            }
+            result[i] = dir;
+        }
+        return result;
+    }
+
     // ----------------------------------------------------------------------
     // ----------------------------------------------------------------------
     // ----------------------------------------------------------------------
@@ -2045,5 +2200,10 @@
         public void unstableProviderDied(IContentProvider icp) {
             mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
         }
+
+        @Override
+        public void appNotRespondingViaProvider(IContentProvider icp) {
+            mMainThread.appNotRespondingViaProvider(icp.asBinder());
+        }
     }
 }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index b3d99c5..cda2c5f 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import com.android.internal.app.ActionBarImpl;
 import com.android.internal.policy.PolicyManager;
 
@@ -264,6 +266,9 @@
         mDecor = mWindow.getDecorView();
 
         if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
+            final ApplicationInfo info = mContext.getApplicationInfo();
+            mWindow.setDefaultIcon(info.icon);
+            mWindow.setDefaultLogo(info.logo);
             mActionBar = new ActionBarImpl(this);
         }
 
@@ -301,6 +306,7 @@
      * method to do cleanup when the dialog is dismissed, instead implement
      * that in {@link #onStop}.
      */
+    @Override
     public void dismiss() {
         if (Looper.myLooper() == mHandler.getLooper()) {
             dismissDialog();
@@ -320,7 +326,7 @@
         }
 
         try {
-            mWindowManager.removeView(mDecor);
+            mWindowManager.removeViewImmediate(mDecor);
         } finally {
             if (mActionMode != null) {
                 mActionMode.finish();
@@ -329,7 +335,7 @@
             mWindow.closeAllPanels();
             onStop();
             mShowing = false;
-            
+
             sendDismissMessage();
         }
     }
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 165c3db..b741cc5 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -150,6 +152,11 @@
     public static final String COLUMN_MEDIAPROVIDER_URI = Downloads.Impl.COLUMN_MEDIAPROVIDER_URI;
 
     /**
+     * @hide
+     */
+    public final static String COLUMN_ALLOW_WRITE = Downloads.Impl.COLUMN_ALLOW_WRITE;
+
+    /**
      * Value of {@link #COLUMN_STATUS} when the download is waiting to start.
      */
     public final static int STATUS_PENDING = 1 << 0;
@@ -262,18 +269,21 @@
     /**
      * Broadcast intent action sent by the download manager when a download completes.
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
 
     /**
      * Broadcast intent action sent by the download manager when the user clicks on a running
      * download, either from a system notification or from the downloads UI.
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public final static String ACTION_NOTIFICATION_CLICKED =
             "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
 
     /**
      * Intent action to launch an activity to display all downloads.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public final static String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS";
 
     /**
@@ -315,6 +325,7 @@
         Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + COLUMN_TOTAL_SIZE_BYTES,
         Downloads.Impl.COLUMN_LAST_MODIFICATION + " AS " + COLUMN_LAST_MODIFIED_TIMESTAMP,
         Downloads.Impl.COLUMN_CURRENT_BYTES + " AS " + COLUMN_BYTES_DOWNLOADED_SO_FAR,
+        Downloads.Impl.COLUMN_ALLOW_WRITE,
         /* add the following 'computed' columns to the cursor.
          * they are not 'returned' by the database, but their inclusion
          * eliminates need to have lot of methods in CursorTranslator
@@ -1185,6 +1196,14 @@
     public long addCompletedDownload(String title, String description,
             boolean isMediaScannerScannable, String mimeType, String path, long length,
             boolean showNotification) {
+        return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
+                length, showNotification, false);
+    }
+
+    /** {@hide} */
+    public long addCompletedDownload(String title, String description,
+            boolean isMediaScannerScannable, String mimeType, String path, long length,
+            boolean showNotification, boolean allowWrite) {
         // make sure the input args are non-null/non-zero
         validateArgumentIsNonEmpty("title", title);
         validateArgumentIsNonEmpty("description", description);
@@ -1210,12 +1229,14 @@
                         Request.SCANNABLE_VALUE_NO);
         values.put(Downloads.Impl.COLUMN_VISIBILITY, (showNotification) ?
                 Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION : Request.VISIBILITY_HIDDEN);
+        values.put(Downloads.Impl.COLUMN_ALLOW_WRITE, allowWrite ? 1 : 0);
         Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
         if (downloadUri == null) {
             return -1;
         }
         return Long.parseLong(downloadUri.getLastPathSegment());
     }
+
     private static final String NON_DOWNLOADMANAGER_DOWNLOAD =
             "non-dwnldmngr-download-dont-retry2download";
 
@@ -1227,8 +1248,10 @@
 
     /**
      * Get the DownloadProvider URI for the download with the given ID.
+     *
+     * @hide
      */
-    Uri getDownloadUri(long id) {
+    public Uri getDownloadUri(long id) {
         return ContentUris.withAppendedId(mBaseUri, id);
     }
 
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index b6aeb84..d626e5f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -26,10 +26,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DebugUtils;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.SuperNotCalledException;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.LayoutInflater;
@@ -43,7 +45,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.HashMap;
 
 final class FragmentState implements Parcelable {
     final String mClassName;
@@ -342,8 +343,8 @@
  * the activity UI was in.
  */
 public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
-    private static final HashMap<String, Class<?>> sClassMap =
-            new HashMap<String, Class<?>>();
+    private static final ArrayMap<String, Class<?>> sClassMap =
+            new ArrayMap<String, Class<?>>();
     
     static final int INVALID_STATE = -1;   // Invalid state used as a null value.
     static final int INITIALIZING = 0;     // Not yet created.
@@ -580,6 +581,10 @@
             if (clazz == null) {
                 // Class not found in the cache, see if it's real, and try to add it
                 clazz = context.getClassLoader().loadClass(fname);
+                if (!Fragment.class.isAssignableFrom(clazz)) {
+                    throw new InstantiationException("Trying to instantiate a class " + fname
+                            + " that is not a Fragment", new ClassCastException());
+                }
                 sClassMap.put(fname, clazz);
             }
             Fragment f = (Fragment)clazz.newInstance();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index d564b4c..bf2a629 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -31,11 +31,13 @@
 import android.util.Log;
 import android.util.LogWriter;
 import android.util.SparseArray;
+import android.util.SuperNotCalledException;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import com.android.internal.util.FastPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -445,12 +447,13 @@
     private void throwException(RuntimeException ex) {
         Log.e(TAG, ex.getMessage());
         LogWriter logw = new LogWriter(Log.ERROR, TAG);
-        PrintWriter pw = new PrintWriter(logw);
+        PrintWriter pw = new FastPrintWriter(logw, false, 1024);
         if (mActivity != null) {
             Log.e(TAG, "Activity state:");
             try {
                 mActivity.dump("  ", null, pw, new String[] { });
             } catch (Exception e) {
+                pw.flush();
                 Log.e(TAG, "Failed dumping state", e);
             }
         } else {
@@ -458,9 +461,11 @@
             try {
                 dump("  ", null, pw, new String[] { });
             } catch (Exception e) {
+                pw.flush();
                 Log.e(TAG, "Failed dumping state", e);
             }
         }
+        pw.flush();
         throw ex;
     }
 
@@ -1324,12 +1329,19 @@
         }
     }
 
+    /**
+     * Adds an action to the queue of pending actions.
+     *
+     * @param action the action to add
+     * @param allowStateLoss whether to allow loss of state information
+     * @throws IllegalStateException if the activity has been destroyed
+     */
     public void enqueueAction(Runnable action, boolean allowStateLoss) {
         if (!allowStateLoss) {
             checkStateLoss();
         }
         synchronized (this) {
-            if (mActivity == null) {
+            if (mDestroyed || mActivity == null) {
                 throw new IllegalStateException("Activity has been destroyed");
             }
             if (mPendingActions == null) {
@@ -1806,8 +1818,9 @@
                     Log.v(TAG, "restoreAllState: back stack #" + i
                         + " (index " + bse.mIndex + "): " + bse);
                     LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
-                    PrintWriter pw = new PrintWriter(logw);
+                    PrintWriter pw = new FastPrintWriter(logw, false, 1024);
                     bse.dump("  ", pw, false);
+                    pw.flush();
                 }
                 mBackStack.add(bse);
                 if (bse.mIndex >= 0) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a21caee..dfea736 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -16,6 +16,9 @@
 
 package android.app;
 
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.app.ActivityManager.StackBoxInfo;
 import android.content.ComponentName;
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
@@ -24,9 +27,11 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.UriPermission;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
@@ -99,19 +104,26 @@
     public void activityDestroyed(IBinder token) throws RemoteException;
     public String getCallingPackage(IBinder token) throws RemoteException;
     public ComponentName getCallingActivity(IBinder token) throws RemoteException;
-    public List getTasks(int maxNum, int flags,
+    public List<RunningTaskInfo> getTasks(int maxNum, int flags,
                          IThumbnailReceiver receiver) throws RemoteException;
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
             int flags, int userId) throws RemoteException;
     public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException;
     public Bitmap getTaskTopThumbnail(int taskId) throws RemoteException;
-    public List getServices(int maxNum, int flags) throws RemoteException;
+    public List<RunningServiceInfo> getServices(int maxNum, int flags) throws RemoteException;
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
             throws RemoteException;
     public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException;
     public void moveTaskToBack(int task) throws RemoteException;
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
+    public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
+            throws RemoteException;
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
+    public void resizeStackBox(int stackBoxId, float weight) throws RemoteException;
+    public List<StackBoxInfo> getStackBoxes() throws RemoteException;
+    public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException;
+    public void setFocusedStack(int stackId) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
     /* oneway */
     public void reportThumbnail(IBinder token,
@@ -127,6 +139,7 @@
     public boolean refContentProvider(IBinder connection, int stableDelta, int unstableDelta)
             throws RemoteException;
     public void unstableProviderDied(IBinder connection) throws RemoteException;
+    public void appNotRespondingViaProvider(IBinder connection) throws RemoteException;
     public PendingIntent getRunningServiceControlPanel(ComponentName service)
             throws RemoteException;
     public ComponentName startService(IApplicationThread caller, Intent service,
@@ -149,14 +162,14 @@
     public void serviceDoneExecuting(IBinder token, int type, int startId,
             int res) throws RemoteException;
     public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
-    
+
     public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
             throws RemoteException;
     public void clearPendingBackup() throws RemoteException;
     public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
     public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;
     public void killApplicationProcess(String processName, int uid) throws RemoteException;
-    
+
     public boolean startInstrumentation(ComponentName className, String profileFile,
             int flags, Bundle arguments, IInstrumentationWatcher watcher,
             IUiAutomationConnection connection, int userId) throws RemoteException;
@@ -168,7 +181,7 @@
     public void setRequestedOrientation(IBinder token,
             int requestedOrientation) throws RemoteException;
     public int getRequestedOrientation(IBinder token) throws RemoteException;
-    
+
     public ComponentName getActivityClassForToken(IBinder token) throws RemoteException;
     public String getPackageForToken(IBinder token) throws RemoteException;
 
@@ -181,16 +194,16 @@
             final IPackageDataObserver observer, int userId) throws RemoteException;
     public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
     public int getUidForIntentSender(IIntentSender sender) throws RemoteException;
-    
+
     public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
             boolean requireFull, String name, String callerPackage) throws RemoteException;
 
     public void setProcessLimit(int max) throws RemoteException;
     public int getProcessLimit() throws RemoteException;
-    
+
     public void setProcessForeground(IBinder token, int pid,
             boolean isForeground) throws RemoteException;
-    
+
     public int checkPermission(String permission, int pid, int uid)
             throws RemoteException;
 
@@ -200,7 +213,10 @@
             Uri uri, int mode) throws RemoteException;
     public void revokeUriPermission(IApplicationThread caller, Uri uri,
             int mode) throws RemoteException;
-    
+    public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
+    public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
+    public ParceledListSlice<UriPermission> getPersistedUriPermissions() throws RemoteException;
+
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
             throws RemoteException;
     
@@ -248,7 +264,7 @@
             StrictMode.ViolationInfo crashInfo) throws RemoteException;
 
     /*
-     * This will deliver the specified signal to all the persistent processes. Currently only 
+     * This will deliver the specified signal to all the persistent processes. Currently only
      * SIGUSR1 is delivered. All others are ignored.
      */
     public void signalPersistentProcesses(int signal) throws RemoteException;
@@ -274,7 +290,8 @@
     public void stopAppSwitches() throws RemoteException;
     public void resumeAppSwitches() throws RemoteException;
     
-    public void killApplicationWithAppId(String pkg, int appid) throws RemoteException;
+    public void killApplicationWithAppId(String pkg, int appid, String reason)
+            throws RemoteException;
     
     public void closeSystemDialogs(String reason) throws RemoteException;
     
@@ -290,6 +307,10 @@
 
     public void finishHeavyWeightApp() throws RemoteException;
 
+    public boolean convertFromTranslucent(IBinder token) throws RemoteException;
+    public boolean convertToTranslucent(IBinder token) throws RemoteException;
+    public void notifyActivityDrawn(IBinder token) throws RemoteException;
+
     public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
     public boolean isImmersive(IBinder token) throws RemoteException;
     public boolean isTopActivityImmersive() throws RemoteException;
@@ -369,16 +390,23 @@
 
     public void requestBugReport() throws RemoteException;
 
-    public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException;
+    public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
+            throws RemoteException;
 
-    public Bundle getTopActivityExtras(int requestType) throws RemoteException;
+    public Bundle getAssistContextExtras(int requestType) throws RemoteException;
 
-    public void reportTopActivityExtras(IBinder token, Bundle extras) throws RemoteException;
+    public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException;
 
     public void killUid(int uid, String reason) throws RemoteException;
 
     public void hang(IBinder who, boolean allowRestart) throws RemoteException;
 
+    public void reportActivityFullyDrawn(IBinder token) throws RemoteException;
+
+    public void restart() throws RemoteException;
+
+    public void performIdleMaintenance() throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -395,10 +423,12 @@
             info = _info;
         }
 
+        @Override
         public int describeContents() {
             return 0;
         }
 
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             info.writeToParcel(dest, 0);
             if (provider != null) {
@@ -412,10 +442,12 @@
 
         public static final Parcelable.Creator<ContentProviderHolder> CREATOR
                 = new Parcelable.Creator<ContentProviderHolder>() {
+            @Override
             public ContentProviderHolder createFromParcel(Parcel source) {
                 return new ContentProviderHolder(source);
             }
 
+            @Override
             public ContentProviderHolder[] newArray(int size) {
                 return new ContentProviderHolder[size];
             }
@@ -441,10 +473,12 @@
         public WaitResult() {
         }
 
+        @Override
         public int describeContents() {
             return 0;
         }
 
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(result);
             dest.writeInt(timeout ? 1 : 0);
@@ -455,10 +489,12 @@
 
         public static final Parcelable.Creator<WaitResult> CREATOR
                 = new Parcelable.Creator<WaitResult>() {
+            @Override
             public WaitResult createFromParcel(Parcel source) {
                 return new WaitResult(source);
             }
 
+            @Override
             public WaitResult[] newArray(int size) {
                 return new WaitResult[size];
             }
@@ -471,7 +507,7 @@
             thisTime = source.readLong();
             totalTime = source.readLong();
         }
-    };
+    }
 
     String descriptor = "android.app.IActivityManager";
 
@@ -635,10 +671,26 @@
     int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
     int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
     int GET_INTENT_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+160;
-    int GET_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+161;
-    int REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
+    int GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+161;
+    int REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
     int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163;
     int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
     int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
     int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166;
+    int CREATE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
+    int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168;
+    int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
+    int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
+    int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
+    int GET_STACK_BOX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
+    int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
+    int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
+    int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
+    int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
+    int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
+    int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
+    int TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
+    int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180;
+    int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
+    int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
 }
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index edb40ed..8476609 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.app.PendingIntent;
+import android.os.WorkSource;
 
 /**
  * System private API for talking with the alarm manager service.
@@ -24,9 +25,9 @@
  * {@hide}
  */
 interface IAlarmManager {
-    void set(int type, long triggerAtTime, in PendingIntent operation);
-    void setRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation);
-    void setInexactRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation);
+	/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
+    void set(int type, long triggerAtTime, long windowLength,
+            long interval, in PendingIntent operation, in WorkSource workSource);
     void setTime(long millis);
     void setTimeZone(String zone);
     void remove(in PendingIntent operation);
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 3189b31a..43a5fbd 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -50,11 +50,12 @@
             int configChanges) throws RemoteException;
     void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException;
     void scheduleSleeping(IBinder token, boolean sleeping) throws RemoteException;
-    void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException;
+    void scheduleResumeActivity(IBinder token, int procState, boolean isForward)
+            throws RemoteException;
     void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
     void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            Bundle state, List<ResultInfo> pendingResults,
+            int procState, Bundle state, List<ResultInfo> pendingResults,
     		List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
     		String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
     		throws RemoteException;
@@ -66,7 +67,7 @@
             int configChanges) throws RemoteException;
     void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
             int resultCode, String data, Bundle extras, boolean sync,
-            int sendingUser) throws RemoteException;
+            int sendingUser, int processState) throws RemoteException;
     static final int BACKUP_MODE_INCREMENTAL = 0;
     static final int BACKUP_MODE_FULL = 1;
     static final int BACKUP_MODE_RESTORE = 2;
@@ -76,9 +77,9 @@
     void scheduleDestroyBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo)
             throws RemoteException;
     void scheduleCreateService(IBinder token, ServiceInfo info,
-            CompatibilityInfo compatInfo) throws RemoteException;
+            CompatibilityInfo compatInfo, int processState) throws RemoteException;
     void scheduleBindService(IBinder token,
-            Intent intent, boolean rebind) throws RemoteException;
+            Intent intent, boolean rebind, int processState) throws RemoteException;
     void scheduleUnbindService(IBinder token,
             Intent intent) throws RemoteException;
     void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
@@ -100,7 +101,8 @@
     void scheduleConfigurationChanged(Configuration config) throws RemoteException;
     void updateTimeZone() throws RemoteException;
     void clearDnsCache() throws RemoteException;
-    void setHttpProxy(String proxy, String port, String exclList) throws RemoteException;
+    void setHttpProxy(String proxy, String port, String exclList,
+            String pacFileUrl) throws RemoteException;
     void processInBackground() throws RemoteException;
     void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args)
             throws RemoteException;
@@ -108,7 +110,7 @@
             throws RemoteException;
     void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
             int resultCode, String data, Bundle extras, boolean ordered,
-            boolean sticky, int sendingUser) throws RemoteException;
+            boolean sticky, int sendingUser, int processState) throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
     void profilerControl(boolean start, String path, ParcelFileDescriptor fd, int profileType)
@@ -116,7 +118,6 @@
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
-    void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
     static final int PACKAGE_REMOVED = 0;
     static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
     void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
@@ -126,13 +127,16 @@
     void setCoreSettings(Bundle coreSettings) throws RemoteException;
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
     void scheduleTrimMemory(int level) throws RemoteException;
-    Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all,
-            String[] args) throws RemoteException;
+    void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo,
+            boolean dumpDalvik, String[] args) throws RemoteException;
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void unstableProviderDied(IBinder provider) throws RemoteException;
-    void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType)
+    void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, int requestType)
             throws RemoteException;
+    void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
+            throws RemoteException;
+    void setProcessState(int state) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -166,7 +170,7 @@
     int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
     int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
     int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
-    int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
+
     int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
     int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
     int SCHEDULE_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
@@ -182,5 +186,7 @@
     int DUMP_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+44;
     int DUMP_DB_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+45;
     int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+46;
-    int REQUEST_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+47;
+    int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+47;
+    int SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+48;
+    int SET_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49;
 }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 2224490..4239a5d 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.util.ArrayMap;
 import com.android.internal.util.ArrayUtils;
 
 import android.content.BroadcastReceiver;
@@ -40,7 +41,7 @@
 import android.os.UserHandle;
 import android.util.AndroidRuntimeException;
 import android.util.Slog;
-import android.view.CompatibilityInfoHolder;
+import android.view.DisplayAdjustments;
 import android.view.Display;
 
 import java.io.File;
@@ -49,8 +50,6 @@
 import java.lang.ref.WeakReference;
 import java.net.URL;
 import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
 
 final class IntentReceiverLeaked extends AndroidRuntimeException {
     public IntentReceiverLeaked(String msg) {
@@ -84,19 +83,19 @@
     private final ClassLoader mBaseClassLoader;
     private final boolean mSecurityViolation;
     private final boolean mIncludeCode;
-    public final CompatibilityInfoHolder mCompatibilityInfo = new CompatibilityInfoHolder();
+    private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
     Resources mResources;
     private ClassLoader mClassLoader;
     private Application mApplication;
 
-    private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers
-        = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
-    private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
-    = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
-    private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
-        = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
-    private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
-        = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
+    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
+        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
+    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
+        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
+    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
+        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
+    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
+        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
 
     int mClientCount = 0;
 
@@ -132,17 +131,17 @@
         mBaseClassLoader = baseLoader;
         mSecurityViolation = securityViolation;
         mIncludeCode = includeCode;
-        mCompatibilityInfo.set(compatInfo);
+        mDisplayAdjustments.setCompatibilityInfo(compatInfo);
 
         if (mAppDir == null) {
             if (ActivityThread.mSystemContext == null) {
                 ActivityThread.mSystemContext =
                     ContextImpl.createSystemContext(mainThread);
+                ResourcesManager resourcesManager = ResourcesManager.getInstance();
                 ActivityThread.mSystemContext.getResources().updateConfiguration(
-                         mainThread.getConfiguration(),
-                         mainThread.getDisplayMetricsLocked(
-                                 Display.DEFAULT_DISPLAY, compatInfo),
-                         compatInfo);
+                        resourcesManager.getConfiguration(),
+                        resourcesManager.getDisplayMetricsLocked(
+                                 Display.DEFAULT_DISPLAY, mDisplayAdjustments), compatInfo);
                 //Slog.i(TAG, "Created system resources "
                 //        + mSystemContext.getResources() + ": "
                 //        + mSystemContext.getResources().getConfiguration());
@@ -169,7 +168,7 @@
         mIncludeCode = true;
         mClassLoader = systemContext.getClassLoader();
         mResources = systemContext.getResources();
-        mCompatibilityInfo.set(compatInfo);
+        mDisplayAdjustments.setCompatibilityInfo(compatInfo);
     }
 
     public String getPackageName() {
@@ -184,6 +183,14 @@
         return mSecurityViolation;
     }
 
+    public CompatibilityInfo getCompatibilityInfo() {
+        return mDisplayAdjustments.getCompatibilityInfo();
+    }
+
+    public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
+        mDisplayAdjustments.setCompatibilityInfo(compatInfo);
+    }
+
     /**
      * Gets the array of shared libraries that are listed as
      * used by the given package.
@@ -532,12 +539,11 @@
     public void removeContextRegistrations(Context context,
             String who, String what) {
         final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
-        HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
-            mReceivers.remove(context);
+        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
+                mReceivers.remove(context);
         if (rmap != null) {
-            Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator();
-            while (it.hasNext()) {
-                LoadedApk.ReceiverDispatcher rd = it.next();
+            for (int i=0; i<rmap.size(); i++) {
+                LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
                 IntentReceiverLeaked leak = new IntentReceiverLeaked(
                         what + " " + who + " has leaked IntentReceiver "
                         + rd.getIntentReceiver() + " that was " +
@@ -558,12 +564,11 @@
         }
         mUnregisteredReceivers.remove(context);
         //Slog.i(TAG, "Receiver registrations: " + mReceivers);
-        HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
+        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
             mServices.remove(context);
         if (smap != null) {
-            Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator();
-            while (it.hasNext()) {
-                LoadedApk.ServiceDispatcher sd = it.next();
+            for (int i=0; i<smap.size(); i++) {
+                LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
                 ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
                         what + " " + who + " has leaked ServiceConnection "
                         + sd.getServiceConnection() + " that was originally bound here");
@@ -590,7 +595,7 @@
             Instrumentation instrumentation, boolean registered) {
         synchronized (mReceivers) {
             LoadedApk.ReceiverDispatcher rd = null;
-            HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
+            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
             if (registered) {
                 map = mReceivers.get(context);
                 if (map != null) {
@@ -602,7 +607,7 @@
                         instrumentation, registered);
                 if (registered) {
                     if (map == null) {
-                        map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
+                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                         mReceivers.put(context, map);
                     }
                     map.put(r, rd);
@@ -618,7 +623,7 @@
     public IIntentReceiver forgetReceiverDispatcher(Context context,
             BroadcastReceiver r) {
         synchronized (mReceivers) {
-            HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
+            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
             LoadedApk.ReceiverDispatcher rd = null;
             if (map != null) {
                 rd = map.get(r);
@@ -628,10 +633,10 @@
                         mReceivers.remove(context);
                     }
                     if (r.getDebugUnregister()) {
-                        HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
+                        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
                                 = mUnregisteredReceivers.get(context);
                         if (holder == null) {
-                            holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
+                            holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                             mUnregisteredReceivers.put(context, holder);
                         }
                         RuntimeException ex = new IllegalArgumentException(
@@ -644,7 +649,7 @@
                     return rd.getIIntentReceiver();
                 }
             }
-            HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
+            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
                     = mUnregisteredReceivers.get(context);
             if (holder != null) {
                 rd = holder.get(r);
@@ -860,14 +865,14 @@
             Context context, Handler handler, int flags) {
         synchronized (mServices) {
             LoadedApk.ServiceDispatcher sd = null;
-            HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
+            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
             if (map != null) {
                 sd = map.get(c);
             }
             if (sd == null) {
                 sd = new ServiceDispatcher(c, context, handler, flags);
                 if (map == null) {
-                    map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
+                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                     mServices.put(context, map);
                 }
                 map.put(c, sd);
@@ -881,7 +886,7 @@
     public final IServiceConnection forgetServiceDispatcher(Context context,
             ServiceConnection c) {
         synchronized (mServices) {
-            HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
+            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
                     = mServices.get(context);
             LoadedApk.ServiceDispatcher sd = null;
             if (map != null) {
@@ -893,10 +898,10 @@
                         mServices.remove(context);
                     }
                     if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
-                        HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
+                        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
                                 = mUnboundServices.get(context);
                         if (holder == null) {
-                            holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
+                            holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                             mUnboundServices.put(context, holder);
                         }
                         RuntimeException ex = new IllegalArgumentException(
@@ -908,7 +913,7 @@
                     return sd.getIServiceConnection();
                 }
             }
-            HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
+            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
                     = mUnboundServices.get(context);
             if (holder != null) {
                 sd = holder.get(c);
@@ -961,8 +966,8 @@
             }
         }
 
-        private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
-            = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
+        private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
+            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
 
         ServiceDispatcher(ServiceConnection conn,
                 Context context, Handler activityThread, int flags) {
@@ -992,9 +997,8 @@
 
         void doForget() {
             synchronized(this) {
-                Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator();
-                while (it.hasNext()) {
-                    ServiceDispatcher.ConnectionInfo ci = it.next();
+                for (int i=0; i<mActiveConnections.size(); i++) {
+                    ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
                     ci.binder.unlinkToDeath(ci.deathMonitor, 0);
                 }
                 mActiveConnections.clear();
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 267555a..b13b24a 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -204,13 +204,13 @@
     // These are the currently active loaders.  A loader is here
     // from the time its load is started until it has been explicitly
     // stopped or restarted by the application.
-    final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>();
+    final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
 
     // These are previously run loaders.  This list is maintained internally
     // to avoid destroying a loader while an application is still using it.
     // It allows an application to restart a loader, but continue using its
     // previously run loader until the new loader's data is available.
-    final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();
+    final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);
 
     final String mWho;
 
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 63c6acd..4ca3747 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app;
 
 import android.content.Context;
@@ -23,17 +24,15 @@
 import android.graphics.PixelFormat;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.AttributeSet;
 import android.view.InputQueue;
-import android.view.KeyEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.View;
-import android.view.WindowManager;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 
 import java.io.File;
@@ -176,16 +175,20 @@
                 ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
 
         mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
-                 getFilesDir().toString(), getObbDir().toString(),
-                 Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
-                 Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
-        
+                getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
+                getAbsolutePath(getExternalFilesDir(null)),
+                Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
+
         if (mNativeHandle == 0) {
             throw new IllegalArgumentException("Unable to load native library: " + path);
         }
         super.onCreate(savedInstanceState);
     }
 
+    private static String getAbsolutePath(File file) {
+        return (file != null) ? file.getAbsolutePath() : null;
+    }
+
     @Override
     protected void onDestroy() {
         mDestroyed = true;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b66e95b..c63e586 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -432,58 +432,176 @@
 
     /**
      * Additional semantic data to be carried around with this Notification.
-     * @hide
+     * <p>
+     * The extras keys defined here are intended to capture the original inputs to {@link Builder}
+     * APIs, and are intended to be used by
+     * {@link android.service.notification.NotificationListenerService} implementations to extract
+     * detailed information from notification objects.
      */
     public Bundle extras = new Bundle();
 
-    // extras keys for Builder inputs
-    /** @hide */
+    /**
+     * {@link #extras} key: this is the title of the notification,
+     * as supplied to {@link Builder#setContentTitle(CharSequence)}.
+     */
     public static final String EXTRA_TITLE = "android.title";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is the title of the notification when shown in expanded form,
+     * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}.
+     */
     public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is the main text payload, as supplied to
+     * {@link Builder#setContentText(CharSequence)}.
+     */
     public static final String EXTRA_TEXT = "android.text";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is a third line of text, as supplied to
+     * {@link Builder#setSubText(CharSequence)}.
+     */
     public static final String EXTRA_SUB_TEXT = "android.subText";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is a small piece of additional text as supplied to
+     * {@link Builder#setContentInfo(CharSequence)}.
+     */
     public static final String EXTRA_INFO_TEXT = "android.infoText";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is a line of summary information intended to be shown
+     * alongside expanded notifications, as supplied to (e.g.)
+     * {@link BigTextStyle#setSummaryText(CharSequence)}.
+     */
     public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is the resource ID of the notification's main small icon, as
+     * supplied to {@link Builder#setSmallIcon(int)}.
+     */
     public static final String EXTRA_SMALL_ICON = "android.icon";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is a bitmap to be used instead of the small icon when showing the
+     * notification payload, as
+     * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
+     */
     public static final String EXTRA_LARGE_ICON = "android.largeIcon";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is a bitmap to be used instead of the one from
+     * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is
+     * shown in its expanded form, as supplied to
+     * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}.
+     */
     public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is the progress value supplied to
+     * {@link Builder#setProgress(int, int, boolean)}.
+     */
     public static final String EXTRA_PROGRESS = "android.progress";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: this is the maximum value supplied to
+     * {@link Builder#setProgress(int, int, boolean)}.
+     */
     public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: whether the progress bar is indeterminate, supplied to
+     * {@link Builder#setProgress(int, int, boolean)}.
+     */
     public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: whether {@link #when} should be shown as a count-up timer (specifically
+     * a {@link android.widget.Chronometer}) instead of a timestamp, as supplied to
+     * {@link Builder#setUsesChronometer(boolean)}.
+     */
     public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
-    /** @hide */
+
+    /**
+     * {@link #extras} key: whether {@link #when} should be shown,
+     * as supplied to {@link Builder#setShowWhen(boolean)}.
+     */
     public static final String EXTRA_SHOW_WHEN = "android.showWhen";
-    /** @hide from BigPictureStyle */
+
+    /**
+     * {@link #extras} key: this is a bitmap to be shown in {@link BigPictureStyle} expanded
+     * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}.
+     */
     public static final String EXTRA_PICTURE = "android.picture";
-    /** @hide from InboxStyle */
+
+    /**
+     * {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
+     * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
+     */
     public static final String EXTRA_TEXT_LINES = "android.textLines";
 
-    // extras keys for other interesting pieces of information
-    /** @hide */
+    /**
+     * {@link #extras} key: An array of people that this notification relates to, specified
+     * by contacts provider contact URI.
+     */
     public static final String EXTRA_PEOPLE = "android.people";
 
     /**
-     * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
+     * @hide
+     * Extra added by NotificationManagerService to indicate whether a NotificationScorer
+     * modified the Notifications's score.
+     */
+    public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified";
+
+    /**
+     * Not used.
      * @hide
      */
+    public static final String EXTRA_AS_HEADS_UP = "headsup";
+
+    /**
+     * Value for {@link #EXTRA_AS_HEADS_UP}.
+     * @hide
+     */
+    public static final int HEADS_UP_NEVER = 0;
+
+    /**
+     * Default value for {@link #EXTRA_AS_HEADS_UP}.
+     * @hide
+     */
+    public static final int HEADS_UP_ALLOWED = 1;
+
+    /**
+     * Value for {@link #EXTRA_AS_HEADS_UP}.
+     * @hide
+     */
+    public static final int HEADS_UP_REQUESTED = 2;
+
+    /**
+     * Structure to encapsulate a named action that can be shown as part of this notification.
+     * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
+     * selected by the user.
+     * <p>
+     * Apps should use {@link Builder#addAction(int, CharSequence, PendingIntent)} to create and
+     * attach actions.
+     */
     public static class Action implements Parcelable {
+        /**
+         * Small icon representing the action.
+         */
         public int icon;
+        /**
+         * Title of the action.
+         */
         public CharSequence title;
+        /**
+         * Intent to send when the user invokes this action. May be null, in which case the action
+         * may be rendered in a disabled presentation by the system UI.
+         */
         public PendingIntent actionIntent;
-        @SuppressWarnings("unused")
-        public Action() { }
+ 
+        private Action() { }
         private Action(Parcel in) {
             icon = in.readInt();
             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -491,16 +609,20 @@
                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
             }
         }
-        public Action(int icon_, CharSequence title_, PendingIntent intent_) {
-            this.icon = icon_;
-            this.title = title_;
-            this.actionIntent = intent_;
+        /**
+         * Use {@link Builder#addAction(int, CharSequence, PendingIntent)}.
+         */
+        public Action(int icon, CharSequence title, PendingIntent intent) {
+            this.icon = icon;
+            this.title = title;
+            this.actionIntent = intent;
         }
+
         @Override
         public Action clone() {
             return new Action(
                 this.icon,
-                this.title.toString(),
+                this.title,
                 this.actionIntent // safe to alias
             );
         }
@@ -531,7 +653,10 @@
     }
 
     /**
-     * @hide
+     * Array of all {@link Action} structures attached to this notification by
+     * {@link Builder#addAction(int, CharSequence, PendingIntent)}. Mostly useful for instances of
+     * {@link android.service.notification.NotificationListenerService} that provide an alternative
+     * interface for invoking actions.
      */
     public Action[] actions;
 
@@ -1450,7 +1575,6 @@
          * called.
          *
          * @see Notification#extras
-         * @hide
          */
         public Builder setExtras(Bundle bag) {
             mExtras = bag;
@@ -1460,8 +1584,15 @@
         /**
          * Add an action to this notification. Actions are typically displayed by
          * the system as a button adjacent to the notification content.
-         * <br>
-         * A notification displays up to 3 actions, from left to right in the order they were added.
+         * <p>
+         * Every action must have an icon (32dp square and matching the
+         * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
+         * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
+         * <p>
+         * A notification in its expanded form can display up to 3 actions, from left to right in
+         * the order they were added. Actions will not be displayed when the notification is
+         * collapsed, however, so be sure that any essential functions may be accessed by the user
+         * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
          *
          * @param icon Resource ID of a drawable that represents the action.
          * @param title Text describing the action.
@@ -1658,8 +1789,9 @@
 
         /**
          * Apply the unstyled operations and return a new {@link Notification} object.
+         * @hide
          */
-        private Notification buildUnstyled() {
+        public Notification buildUnstyled() {
             Notification n = new Notification();
             n.when = mWhen;
             n.icon = mSmallIcon;
@@ -1737,12 +1869,10 @@
          * object.
          */
         public Notification build() {
-            final Notification n;
+            Notification n = buildUnstyled();
 
             if (mStyle != null) {
-                n = mStyle.build();
-            } else {
-                n = buildUnstyled();
+                n = mStyle.buildStyled(n);
             }
 
             n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
@@ -1852,7 +1982,21 @@
             }
         }
 
-        public abstract Notification build();
+        /**
+         * @hide
+         */
+        public abstract Notification buildStyled(Notification wip);
+
+        /**
+         * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is
+         * attached to.
+         *
+         * @return the fully constructed Notification.
+         */
+        public Notification build() {
+            checkBuilder();
+            return mBuilder.build();
+        }
     }
 
     /**
@@ -1938,10 +2082,11 @@
             extras.putParcelable(EXTRA_PICTURE, mPicture);
         }
 
+        /**
+         * @hide
+         */
         @Override
-        public Notification build() {
-            checkBuilder();
-            Notification wip = mBuilder.buildUnstyled();
+        public Notification buildStyled(Notification wip) {
             if (mBigLargeIconSet ) {
                 mBuilder.mLargeIcon = mBigLargeIcon;
             }
@@ -2031,10 +2176,11 @@
             return contentView;
         }
 
+        /**
+         * @hide
+         */
         @Override
-        public Notification build() {
-            checkBuilder();
-            Notification wip = mBuilder.buildUnstyled();
+        public Notification buildStyled(Notification wip) {
             wip.bigContentView = makeBigContentView();
 
             wip.extras.putCharSequence(EXTRA_TEXT, mBigText);
@@ -2142,10 +2288,11 @@
             return contentView;
         }
 
+        /**
+         * @hide
+         */
         @Override
-        public Notification build() {
-            checkBuilder();
-            Notification wip = mBuilder.buildUnstyled();
+        public Notification buildStyled(Notification wip) {
             wip.bigContentView = makeBigContentView();
 
             return wip;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index dbafc78..3ee4306 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -133,7 +133,7 @@
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
         try {
-            service.enqueueNotificationWithTag(pkg, mContext.getBasePackageName(), tag, id,
+            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                     notification, idOut, UserHandle.myUserId());
             if (id != idOut[0]) {
                 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
@@ -158,7 +158,7 @@
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
         try {
-            service.enqueueNotificationWithTag(pkg, mContext.getBasePackageName(), tag, id,
+            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                     notification, idOut, user.getIdentifier());
             if (id != idOut[0]) {
                 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
new file mode 100644
index 0000000..f55dba4
--- /dev/null
+++ b/core/java/android/app/ResourcesManager.java
@@ -0,0 +1,293 @@
+/*
+ * 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 android.app;
+
+import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+
+import android.content.pm.ActivityInfo;
+import android.content.res.AssetManager;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.ResourcesKey;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.util.ArrayMap;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayAdjustments;
+
+import java.lang.ref.WeakReference;
+import java.util.Locale;
+
+/** @hide */
+public class ResourcesManager {
+    static final String TAG = "ResourcesManager";
+    static final boolean DEBUG_CACHE = false;
+    static final boolean DEBUG_STATS = true;
+
+    private static ResourcesManager sResourcesManager;
+    final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources
+            = new ArrayMap<ResourcesKey, WeakReference<Resources> >();
+
+    final ArrayMap<DisplayAdjustments, DisplayMetrics> mDefaultDisplayMetrics
+            = new ArrayMap<DisplayAdjustments, DisplayMetrics>();
+
+    CompatibilityInfo mResCompatibilityInfo;
+
+    Configuration mResConfiguration;
+    final Configuration mTmpConfig = new Configuration();
+
+    public static ResourcesManager getInstance() {
+        synchronized (ResourcesManager.class) {
+            if (sResourcesManager == null) {
+                sResourcesManager = new ResourcesManager();
+            }
+            return sResourcesManager;
+        }
+    }
+
+    public Configuration getConfiguration() {
+        return mResConfiguration;
+    }
+
+    public void flushDisplayMetricsLocked() {
+        mDefaultDisplayMetrics.clear();
+    }
+
+    public DisplayMetrics getDisplayMetricsLocked(int displayId) {
+        return getDisplayMetricsLocked(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+    }
+
+    public DisplayMetrics getDisplayMetricsLocked(int displayId, DisplayAdjustments daj) {
+        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+        DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(daj) : null;
+        if (dm != null) {
+            return dm;
+        }
+        dm = new DisplayMetrics();
+
+        DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
+        if (displayManager == null) {
+            // may be null early in system startup
+            dm.setToDefaults();
+            return dm;
+        }
+
+        if (isDefaultDisplay) {
+            mDefaultDisplayMetrics.put(daj, dm);
+        }
+
+        Display d = displayManager.getCompatibleDisplay(displayId, daj);
+        if (d != null) {
+            d.getMetrics(dm);
+        } else {
+            // Display no longer exists
+            // FIXME: This would not be a problem if we kept the Display object around
+            // instead of using the raw display id everywhere.  The Display object caches
+            // its information even after the display has been removed.
+            dm.setToDefaults();
+        }
+        //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
+        //        + metrics.heightPixels + " den=" + metrics.density
+        //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
+        return dm;
+    }
+
+    final void applyNonDefaultDisplayMetricsToConfigurationLocked(
+            DisplayMetrics dm, Configuration config) {
+        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+        config.densityDpi = dm.densityDpi;
+        config.screenWidthDp = (int)(dm.widthPixels / dm.density);
+        config.screenHeightDp = (int)(dm.heightPixels / dm.density);
+        int sl = Configuration.resetScreenLayout(config.screenLayout);
+        if (dm.widthPixels > dm.heightPixels) {
+            config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+            config.screenLayout = Configuration.reduceScreenLayout(sl,
+                    config.screenWidthDp, config.screenHeightDp);
+        } else {
+            config.orientation = Configuration.ORIENTATION_PORTRAIT;
+            config.screenLayout = Configuration.reduceScreenLayout(sl,
+                    config.screenHeightDp, config.screenWidthDp);
+        }
+        config.smallestScreenWidthDp = config.screenWidthDp; // assume screen does not rotate
+        config.compatScreenWidthDp = config.screenWidthDp;
+        config.compatScreenHeightDp = config.screenHeightDp;
+        config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp;
+    }
+
+    public boolean applyCompatConfiguration(int displayDensity,
+            Configuration compatConfiguration) {
+        if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) {
+            mResCompatibilityInfo.applyToConfiguration(displayDensity, compatConfiguration);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Creates the top level Resources for applications with the given compatibility info.
+     *
+     * @param resDir the resource directory.
+     * @param compatInfo the compability info. Must not be null.
+     * @param token the application token for determining stack bounds.
+     */
+    public Resources getTopLevelResources(String resDir, int displayId,
+            Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
+        final float scale = compatInfo.applicationScale;
+        ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
+                token);
+        Resources r;
+        synchronized (this) {
+            // Resources is app scale dependent.
+            if (false) {
+                Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
+            }
+            WeakReference<Resources> wr = mActiveResources.get(key);
+            r = wr != null ? wr.get() : null;
+            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
+            if (r != null && r.getAssets().isUpToDate()) {
+                if (false) {
+                    Slog.w(TAG, "Returning cached resources " + r + " " + resDir
+                            + ": appScale=" + r.getCompatibilityInfo().applicationScale);
+                }
+                return r;
+            }
+        }
+
+        //if (r != null) {
+        //    Slog.w(TAG, "Throwing away out-of-date resources!!!! "
+        //            + r + " " + resDir);
+        //}
+
+        AssetManager assets = new AssetManager();
+        if (assets.addAssetPath(resDir) == 0) {
+            return null;
+        }
+
+        //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
+        DisplayMetrics dm = getDisplayMetricsLocked(displayId);
+        Configuration config;
+        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+        final boolean hasOverrideConfig = key.hasOverrideConfiguration();
+        if (!isDefaultDisplay || hasOverrideConfig) {
+            config = new Configuration(getConfiguration());
+            if (!isDefaultDisplay) {
+                applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
+            }
+            if (hasOverrideConfig) {
+                config.updateFrom(key.mOverrideConfiguration);
+            }
+        } else {
+            config = getConfiguration();
+        }
+        r = new Resources(assets, dm, config, compatInfo, token);
+        if (false) {
+            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+                    + r.getConfiguration() + " appScale="
+                    + r.getCompatibilityInfo().applicationScale);
+        }
+
+        synchronized (this) {
+            WeakReference<Resources> wr = mActiveResources.get(key);
+            Resources existing = wr != null ? wr.get() : null;
+            if (existing != null && existing.getAssets().isUpToDate()) {
+                // Someone else already created the resources while we were
+                // unlocked; go ahead and use theirs.
+                r.getAssets().close();
+                return existing;
+            }
+
+            // XXX need to remove entries when weak references go away
+            mActiveResources.put(key, new WeakReference<Resources>(r));
+            return r;
+        }
+    }
+
+    public final boolean applyConfigurationToResourcesLocked(Configuration config,
+            CompatibilityInfo compat) {
+        if (mResConfiguration == null) {
+            mResConfiguration = new Configuration();
+        }
+        if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+                    + mResConfiguration.seq + ", newSeq=" + config.seq);
+            return false;
+        }
+        int changes = mResConfiguration.updateFrom(config);
+        flushDisplayMetricsLocked();
+        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+
+        if (compat != null && (mResCompatibilityInfo == null ||
+                !mResCompatibilityInfo.equals(compat))) {
+            mResCompatibilityInfo = compat;
+            changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+                    | ActivityInfo.CONFIG_SCREEN_SIZE
+                    | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+        }
+
+        // set it for java, this also affects newly created Resources
+        if (config.locale != null) {
+            Locale.setDefault(config.locale);
+        }
+
+        Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
+
+        ApplicationPackageManager.configurationChanged();
+        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+
+        Configuration tmpConfig = null;
+
+        for (int i=mActiveResources.size()-1; i>=0; i--) {
+            ResourcesKey key = mActiveResources.keyAt(i);
+            Resources r = mActiveResources.valueAt(i).get();
+            if (r != null) {
+                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+                        + r + " config to: " + config);
+                int displayId = key.mDisplayId;
+                boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+                DisplayMetrics dm = defaultDisplayMetrics;
+                final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+                if (!isDefaultDisplay || hasOverrideConfiguration) {
+                    if (tmpConfig == null) {
+                        tmpConfig = new Configuration();
+                    }
+                    tmpConfig.setTo(config);
+                    if (!isDefaultDisplay) {
+                        dm = getDisplayMetricsLocked(displayId);
+                        applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
+                    }
+                    if (hasOverrideConfiguration) {
+                        tmpConfig.updateFrom(key.mOverrideConfiguration);
+                    }
+                    r.updateConfiguration(tmpConfig, dm, compat);
+                } else {
+                    r.updateConfiguration(config, dm, compat);
+                }
+                //Slog.i(TAG, "Updated app resources " + v.getKey()
+                //        + " " + r + ": " + r.getConfiguration());
+            } else {
+                //Slog.i(TAG, "Removing old resources " + v.getKey());
+                mActiveResources.removeAt(i);
+            }
+        }
+
+        return changes != 0;
+    }
+
+}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 7dfc589f..f9c245e 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -869,7 +869,7 @@
             intent.setComponent(comp);
             if (inclContext) {
                 IActivityManager am = ActivityManagerNative.getDefault();
-                Bundle extras = am.getTopActivityExtras(0);
+                Bundle extras = am.getAssistContextExtras(0);
                 if (extras != null) {
                     intent.replaceExtras(extras);
                 }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 829b80c..7bcf43e 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -63,6 +63,13 @@
     public static final int NAVIGATION_HINT_RECENT_NOP    = 1 << 2;
     public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 3;
 
+    public static final int WINDOW_STATUS_BAR = 1;
+    public static final int WINDOW_NAVIGATION_BAR = 2;
+
+    public static final int WINDOW_STATE_SHOWING = 0;
+    public static final int WINDOW_STATE_HIDING = 1;
+    public static final int WINDOW_STATE_HIDDEN = 2;
+
     private Context mContext;
     private IStatusBarService mService;
     private IBinder mToken = new Binder();
@@ -179,4 +186,12 @@
             throw new RuntimeException(ex);
         }
     }
+
+    /** @hide */
+    public static String windowStateToString(int state) {
+        if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
+        if (state == WINDOW_STATE_HIDDEN) return "WINDOW_STATE_HIDDEN";
+        if (state == WINDOW_STATE_SHOWING) return "WINDOW_STATE_SHOWING";
+        return "WINDOW_STATE_UNKNOWN";
+    }
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 3342068..2bc7cbf 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,8 +16,11 @@
 
 package android.app;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -30,7 +33,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Binder;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -41,13 +44,13 @@
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 
 /**
  * Provides access to the system wallpaper. With WallpaperManager, you can
@@ -62,6 +65,15 @@
     private float mWallpaperYStep = -1;
 
     /**
+     * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
+     * an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
+     * <p>Input:  {@link Intent#getData} is the URI of the image to crop and set as wallpaper.
+     * <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
+     */
+    public static final String ACTION_CROP_AND_SET_WALLPAPER =
+            "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
+
+    /**
      * Launch an activity for the user to pick the current global live
      * wallpaper.
      */
@@ -463,7 +475,39 @@
             return null;
         }
     }
-    
+
+    /**
+     * Gets an Intent that will launch an activity that crops the given
+     * image and sets the device's wallpaper. If there is a default HOME activity
+     * that supports cropping wallpapers, it will be preferred as the default.
+     * Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
+     * intent.
+     */
+    public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+        final PackageManager packageManager = mContext.getPackageManager();
+        Intent cropAndSetWallpaperIntent =
+                new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
+        cropAndSetWallpaperIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        // Find out if the default HOME activity supports CROP_AND_SET_WALLPAPER
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+        ResolveInfo resolvedHome = packageManager.resolveActivity(homeIntent,
+                PackageManager.MATCH_DEFAULT_ONLY);
+        if (resolvedHome != null) {
+            cropAndSetWallpaperIntent.setPackage(resolvedHome.activityInfo.packageName);
+
+            List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
+                    cropAndSetWallpaperIntent, 0);
+            if (cropAppList.size() > 0) {
+                return cropAndSetWallpaperIntent;
+            }
+        }
+
+        // fallback crop activity
+        cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
+        return cropAndSetWallpaperIntent;
+    }
+
     /**
      * Change the current system wallpaper to the bitmap in the given resource.
      * The resource is opened as a raw data stream and copied into the
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 17e8dd9..ab82531 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -32,10 +32,17 @@
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.org.conscrypt.TrustedCertificateStore;
+
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Public interface for managing policies enforced on a device.  Most clients
@@ -1328,6 +1335,70 @@
     }
 
     /**
+     * Installs the given certificate as a User CA.
+     *
+     * @return false if the certBuffer cannot be parsed or installation is
+     *         interrupted, otherwise true
+     * @hide
+     */
+    public boolean installCaCert(byte[] certBuffer) {
+        if (mService != null) {
+            try {
+                return mService.installCaCert(certBuffer);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Uninstalls the given certificate from the list of User CAs, if present.
+     *
+     * @hide
+     */
+    public void uninstallCaCert(byte[] certBuffer) {
+        if (mService != null) {
+            try {
+                mService.uninstallCaCert(certBuffer);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Returns whether there are any user-installed CA certificates.
+     *
+     * @hide
+     */
+    public static boolean hasAnyCaCertsInstalled() {
+        TrustedCertificateStore certStore = new TrustedCertificateStore();
+        Set<String> aliases = certStore.userAliases();
+        return aliases != null && !aliases.isEmpty();
+    }
+
+    /**
+     * Returns whether this certificate has been installed as a User CA.
+     *
+     * @hide
+     */
+    public boolean hasCaCertInstalled(byte[] certBuffer) {
+        TrustedCertificateStore certStore = new TrustedCertificateStore();
+        String alias;
+        byte[] pemCert;
+        try {
+            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            X509Certificate cert = (X509Certificate) certFactory.generateCertificate(
+                            new ByteArrayInputStream(certBuffer));
+            return certStore.getCertificateAlias(cert) != null;
+        } catch (CertificateException ce) {
+            Log.w(TAG, "Could not parse certificate", ce);
+        }
+        return false;
+    }
+
+    /**
      * Called by an application that is administering the device to disable all cameras
      * on the device.  After setting this, no applications will be able to access any cameras
      * on the device.
@@ -1527,9 +1598,26 @@
      */
     public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
             IllegalStateException {
+        return setDeviceOwner(packageName, null);
+    }
+
+    /**
+     * @hide
+     * Sets the given package as the device owner. The package must already be installed and there
+     * shouldn't be an existing device owner registered, for this call to succeed. Also, this
+     * method must be called before the device is provisioned.
+     * @param packageName the package name of the application to be registered as the device owner.
+     * @param ownerName the human readable name of the institution that owns this device.
+     * @return whether the package was successfully registered as the device owner.
+     * @throws IllegalArgumentException if the package name is null or invalid
+     * @throws IllegalStateException if a device owner is already registered or the device has
+     *         already been provisioned.
+     */
+    public boolean setDeviceOwner(String packageName, String ownerName)
+            throws IllegalArgumentException, IllegalStateException {
         if (mService != null) {
             try {
-                return mService.setDeviceOwner(packageName);
+                return mService.setDeviceOwner(packageName, ownerName);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to set device owner");
             }
@@ -1581,4 +1669,16 @@
         }
         return null;
     }
+
+    /** @hide */
+    public String getDeviceOwnerName() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwnerName();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get device owner");
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b2a65bf..172c47c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -98,7 +98,11 @@
     void reportFailedPasswordAttempt(int userHandle);
     void reportSuccessfulPasswordAttempt(int userHandle);
 
-    boolean setDeviceOwner(String packageName);
+    boolean setDeviceOwner(String packageName, String ownerName);
     boolean isDeviceOwner(String packageName);
     String getDeviceOwner();
+    String getDeviceOwnerName();
+
+    boolean installCaCert(in byte[] certBuffer);
+    void uninstallCaCert(in byte[] certBuffer);
 }
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 8aae45a..f104d71 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -198,7 +198,6 @@
      * @return a appWidgetId
      */
     public int allocateAppWidgetId() {
-
         try {
             if (mPackageName == null) {
                 mPackageName = mContext.getPackageName();
@@ -211,20 +210,17 @@
     }
 
     /**
-     * Get a appWidgetId for a host in the calling process.
+     * Get a appWidgetId for a host in the given package.
      *
      * @return a appWidgetId
      * @hide
      */
-    public static int allocateAppWidgetIdForSystem(int hostId, int userId) {
+    public static int allocateAppWidgetIdForPackage(int hostId, int userId, String packageName) {
         checkCallerIsSystem();
         try {
             if (sService == null) {
                 bindService();
             }
-            Context systemContext =
-                    (Context) ActivityThread.currentActivityThread().getSystemContext();
-            String packageName = systemContext.getPackageName();
             return sService.allocateAppWidgetId(packageName, hostId, userId);
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 6fdf3b4..e7e4a0f 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -128,9 +128,7 @@
                             try {
                                 if (mService == null) {
                                     if (VDBG) Log.d(TAG,"Binding service...");
-                                    if (!mContext.bindService(new Intent(IBluetoothA2dp.class.getName()), mConnection, 0)) {
-                                        Log.e(TAG, "Could not bind to Bluetooth A2DP Service");
-                                    }
+                                    doBind();
                                 }
                             } catch (Exception re) {
                                 Log.e(TAG,"",re);
@@ -157,9 +155,18 @@
             }
         }
 
-        if (!context.bindService(new Intent(IBluetoothA2dp.class.getName()), mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth A2DP Service");
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothA2dp.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
+            return false;
         }
+        return true;
     }
 
     /*package*/ void close() {
@@ -381,6 +388,66 @@
     }
 
     /**
+     * Checks if Avrcp device supports the absolute volume feature.
+     *
+     * @return true if device supports absolute volume
+     * @hide
+     */
+    public boolean isAvrcpAbsoluteVolumeSupported() {
+        if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.isAvrcpAbsoluteVolumeSupported();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Tells remote device to adjust volume. Only if absolute volume is supported.
+     *
+     * @param direction 1 to increase volume, or -1 to decrease volume
+     * @hide
+     */
+    public void adjustAvrcpAbsoluteVolume(int direction) {
+        if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
+        if (mService != null && isEnabled()) {
+            try {
+                mService.adjustAvrcpAbsoluteVolume(direction);
+                return;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
+                return;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+    }
+
+    /**
+     * Tells remote device to set an absolute volume. Only if absolute volume is supported
+     *
+     * @param volume Absolute volume to be set on AVRCP side
+     * @hide
+     */
+    public void setAvrcpAbsoluteVolume(int volume) {
+        if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
+        if (mService != null && isEnabled()) {
+            try {
+                mService.setAvrcpAbsoluteVolume(volume);
+                return;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
+                return;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+    }
+
+    /**
      * Check if A2DP profile is streaming music.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 79bb476..e2bc80a 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -27,7 +27,6 @@
 import android.os.ServiceManager;
 import android.util.Log;
 import android.util.Pair;
-
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -36,6 +35,7 @@
 import java.util.HashSet;
 import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
@@ -50,7 +50,7 @@
  * devices, and start a scan for Bluetooth LE devices.
  *
  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
- * adapter, when running on JELLY_BEAN_MR1 and below, call the 
+ * adapter, when running on JELLY_BEAN_MR1 and below, call the
  * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
  * higher, retrieve it through
  * {@link android.content.Context#getSystemService} with
@@ -433,7 +433,7 @@
         if (address == null || address.length != 6) {
             throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
         }
-        return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X",
+        return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
                 address[0], address[1], address[2], address[3], address[4], address[5]));
     }
 
@@ -599,6 +599,25 @@
     }
 
     /**
+     * enable or disable Bluetooth HCI snoop log.
+     *
+     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     * permission
+     *
+     * @return true to indicate configure HCI log successfully, or false on
+     *         immediate error
+     * @hide
+     */
+    public boolean configHciSnoopLog(boolean enable) {
+        try {
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.configHciSnoopLog(enable);
+            }
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
      * Get the UUIDs supported by the local Bluetooth adapter.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
@@ -1173,6 +1192,9 @@
         } else if (profile == BluetoothProfile.HEALTH) {
             BluetoothHealth health = new BluetoothHealth(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.MAP) {
+            BluetoothMap map = new BluetoothMap(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -1221,6 +1243,10 @@
                 BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
                 gattServer.close();
                 break;
+            case BluetoothProfile.MAP:
+                BluetoothMap map = (BluetoothMap)proxy;
+                map.close();
+                break;
         }
     }
 
@@ -1684,7 +1710,7 @@
         public void onGetDescriptor(String address, int srvcType,
                                     int srvcInstId, ParcelUuid srvcUuid,
                                     int charInstId, ParcelUuid charUuid,
-                                    ParcelUuid descUuid) {
+                                    int descInstId, ParcelUuid descUuid) {
             // no op
         }
 
@@ -1714,14 +1740,14 @@
         public void onDescriptorRead(String address, int status, int srvcType,
                                      int srvcInstId, ParcelUuid srvcUuid,
                                      int charInstId, ParcelUuid charUuid,
-                                     ParcelUuid descrUuid, byte[] value) {
+                                     int descInstId, ParcelUuid descrUuid, byte[] value) {
             // no op
         }
 
         public void onDescriptorWrite(String address, int status, int srvcType,
                                       int srvcInstId, ParcelUuid srvcUuid,
                                       int charInstId, ParcelUuid charUuid,
-                                      ParcelUuid descrUuid) {
+                                      int descInstId, ParcelUuid descrUuid) {
             // no op
         }
 
@@ -1732,6 +1758,10 @@
         public void onReadRemoteRssi(String address, int rssi, int status) {
             // no op
         }
+
+        public void onListen(int status) {
+            // no op
+        }
     }
 
 }
diff --git a/core/java/android/bluetooth/BluetoothAssignedNumbers.java b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
index 580e9ff..124bdc1 100644
--- a/core/java/android/bluetooth/BluetoothAssignedNumbers.java
+++ b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
@@ -513,6 +513,656 @@
     public static final int RIVIERAWAVES = 0x0060;
 
     /*
+     * RDA Microelectronics.
+     */
+    public static final int RDA_MICROELECTRONICS = 0x0061;
+
+    /*
+     * Gibson Guitars.
+     */
+    public static final int GIBSON_GUITARS = 0x0062;
+
+    /*
+     * MiCommand Inc.
+     */
+    public static final int MICOMMAND = 0x0063;
+
+    /*
+     * Band XI International, LLC.
+     */
+    public static final int BAND_XI_INTERNATIONAL = 0x0064;
+
+    /*
+     * Hewlett-Packard Company.
+     */
+    public static final int HEWLETT_PACKARD = 0x0065;
+
+    /*
+     * 9Solutions Oy.
+     */
+    public static final int NINE_SOLUTIONS = 0x0066;
+
+    /*
+     * GN Netcom A/S.
+     */
+    public static final int GN_NETCOM = 0x0067;
+
+    /*
+     * General Motors.
+     */
+    public static final int GENERAL_MOTORS = 0x0068;
+
+    /*
+     * A&D Engineering, Inc.
+     */
+    public static final int A_AND_D_ENGINEERING = 0x0069;
+
+    /*
+     * MindTree Ltd.
+     */
+    public static final int MINDTREE = 0x006A;
+
+    /*
+     * Polar Electro OY.
+     */
+    public static final int POLAR_ELECTRO = 0x006B;
+
+    /*
+     * Beautiful Enterprise Co., Ltd.
+     */
+    public static final int BEAUTIFUL_ENTERPRISE = 0x006C;
+
+    /*
+     * BriarTek, Inc.
+     */
+    public static final int BRIARTEK = 0x006D;
+
+    /*
+     * Summit Data Communications, Inc.
+     */
+    public static final int SUMMIT_DATA_COMMUNICATIONS = 0x006E;
+
+    /*
+     * Sound ID.
+     */
+    public static final int SOUND_ID = 0x006F;
+
+    /*
+     * Monster, LLC.
+     */
+    public static final int MONSTER = 0x0070;
+
+    /*
+     * connectBlue AB.
+     */
+    public static final int CONNECTBLUE = 0x0071;
+
+    /*
+     * ShangHai Super Smart Electronics Co. Ltd.
+     */
+    public static final int SHANGHAI_SUPER_SMART_ELECTRONICS = 0x0072;
+
+    /*
+     * Group Sense Ltd.
+     */
+    public static final int GROUP_SENSE = 0x0073;
+
+    /*
+     * Zomm, LLC.
+     */
+    public static final int ZOMM = 0x0074;
+
+    /*
+     * Samsung Electronics Co. Ltd.
+     */
+    public static final int SAMSUNG_ELECTRONICS = 0x0075;
+
+    /*
+     * Creative Technology Ltd.
+     */
+    public static final int CREATIVE_TECHNOLOGY = 0x0076;
+
+    /*
+     * Laird Technologies.
+     */
+    public static final int LAIRD_TECHNOLOGIES = 0x0077;
+
+    /*
+     * Nike, Inc.
+     */
+    public static final int NIKE = 0x0078;
+
+    /*
+     * lesswire AG.
+     */
+    public static final int LESSWIRE = 0x0079;
+
+    /*
+     * MStar Semiconductor, Inc.
+     */
+    public static final int MSTAR_SEMICONDUCTOR = 0x007A;
+
+    /*
+     * Hanlynn Technologies.
+     */
+    public static final int HANLYNN_TECHNOLOGIES = 0x007B;
+
+    /*
+     * A & R Cambridge.
+     */
+    public static final int A_AND_R_CAMBRIDGE = 0x007C;
+
+    /*
+     * Seers Technology Co. Ltd.
+     */
+    public static final int SEERS_TECHNOLOGY = 0x007D;
+
+    /*
+     * Sports Tracking Technologies Ltd.
+     */
+    public static final int SPORTS_TRACKING_TECHNOLOGIES = 0x007E;
+
+    /*
+     * Autonet Mobile.
+     */
+    public static final int AUTONET_MOBILE = 0x007F;
+
+    /*
+     * DeLorme Publishing Company, Inc.
+     */
+    public static final int DELORME_PUBLISHING_COMPANY = 0x0080;
+
+    /*
+     * WuXi Vimicro.
+     */
+    public static final int WUXI_VIMICRO = 0x0081;
+
+    /*
+     * Sennheiser Communications A/S.
+     */
+    public static final int SENNHEISER_COMMUNICATIONS = 0x0082;
+
+    /*
+     * TimeKeeping Systems, Inc.
+     */
+    public static final int TIMEKEEPING_SYSTEMS = 0x0083;
+
+    /*
+     * Ludus Helsinki Ltd.
+     */
+    public static final int LUDUS_HELSINKI = 0x0084;
+
+    /*
+     * BlueRadios, Inc.
+     */
+    public static final int BLUERADIOS = 0x0085;
+
+    /*
+     * equinox AG.
+     */
+    public static final int EQUINOX_AG = 0x0086;
+
+    /*
+     * Garmin International, Inc.
+     */
+    public static final int GARMIN_INTERNATIONAL = 0x0087;
+
+    /*
+     * Ecotest.
+     */
+    public static final int ECOTEST = 0x0088;
+
+    /*
+     * GN ReSound A/S.
+     */
+    public static final int GN_RESOUND = 0x0089;
+
+    /*
+     * Jawbone.
+     */
+    public static final int JAWBONE = 0x008A;
+
+    /*
+     * Topcorn Positioning Systems, LLC.
+     */
+    public static final int TOPCORN_POSITIONING_SYSTEMS = 0x008B;
+
+    /*
+     * Qualcomm Labs, Inc.
+     */
+    public static final int QUALCOMM_LABS = 0x008C;
+
+    /*
+     * Zscan Software.
+     */
+    public static final int ZSCAN_SOFTWARE = 0x008D;
+
+    /*
+     * Quintic Corp.
+     */
+    public static final int QUINTIC = 0x008E;
+
+    /*
+     * Stollman E+V GmbH.
+     */
+    public static final int STOLLMAN_E_PLUS_V = 0x008F;
+
+    /*
+     * Funai Electric Co., Ltd.
+     */
+    public static final int FUNAI_ELECTRIC = 0x0090;
+
+    /*
+     * Advanced PANMOBIL Systems GmbH & Co. KG.
+     */
+    public static final int ADVANCED_PANMOBIL_SYSTEMS = 0x0091;
+
+    /*
+     * ThinkOptics, Inc.
+     */
+    public static final int THINKOPTICS = 0x0092;
+
+    /*
+     * Universal Electronics, Inc.
+     */
+    public static final int UNIVERSAL_ELECTRONICS = 0x0093;
+
+    /*
+     * Airoha Technology Corp.
+     */
+    public static final int AIROHA_TECHNOLOGY = 0x0094;
+
+    /*
+     * NEC Lighting, Ltd.
+     */
+    public static final int NEC_LIGHTING = 0x0095;
+
+    /*
+     * ODM Technology, Inc.
+     */
+    public static final int ODM_TECHNOLOGY = 0x0096;
+
+    /*
+     * Bluetrek Technologies Limited.
+     */
+    public static final int BLUETREK_TECHNOLOGIES = 0x0097;
+
+    /*
+     * zer01.tv GmbH.
+     */
+    public static final int ZER01_TV = 0x0098;
+
+    /*
+     * i.Tech Dynamic Global Distribution Ltd.
+     */
+    public static final int I_TECH_DYNAMIC_GLOBAL_DISTRIBUTION = 0x0099;
+
+    /*
+     * Alpwise.
+     */
+    public static final int ALPWISE = 0x009A;
+
+    /*
+     * Jiangsu Toppower Automotive Electronics Co., Ltd.
+     */
+    public static final int JIANGSU_TOPPOWER_AUTOMOTIVE_ELECTRONICS = 0x009B;
+
+    /*
+     * Colorfy, Inc.
+     */
+    public static final int COLORFY = 0x009C;
+
+    /*
+     * Geoforce Inc.
+     */
+    public static final int GEOFORCE = 0x009D;
+
+    /*
+     * Bose Corporation.
+     */
+    public static final int BOSE = 0x009E;
+
+    /*
+     * Suunto Oy.
+     */
+    public static final int SUUNTO = 0x009F;
+
+    /*
+     * Kensington Computer Products Group.
+     */
+    public static final int KENSINGTON_COMPUTER_PRODUCTS_GROUP = 0x00A0;
+
+    /*
+     * SR-Medizinelektronik.
+     */
+    public static final int SR_MEDIZINELEKTRONIK = 0x00A1;
+
+    /*
+     * Vertu Corporation Limited.
+     */
+    public static final int VERTU = 0x00A2;
+
+    /*
+     * Meta Watch Ltd.
+     */
+    public static final int META_WATCH = 0x00A3;
+
+    /*
+     * LINAK A/S.
+     */
+    public static final int LINAK = 0x00A4;
+
+    /*
+     * OTL Dynamics LLC.
+     */
+    public static final int OTL_DYNAMICS = 0x00A5;
+
+    /*
+     * Panda Ocean Inc.
+     */
+    public static final int PANDA_OCEAN = 0x00A6;
+
+    /*
+     * Visteon Corporation.
+     */
+    public static final int VISTEON = 0x00A7;
+
+    /*
+     * ARP Devices Limited.
+     */
+    public static final int ARP_DEVICES = 0x00A8;
+
+    /*
+     * Magneti Marelli S.p.A.
+     */
+    public static final int MAGNETI_MARELLI = 0x00A9;
+
+    /*
+     * CAEN RFID srl.
+     */
+    public static final int CAEN_RFID = 0x00AA;
+
+    /*
+     * Ingenieur-Systemgruppe Zahn GmbH.
+     */
+    public static final int INGENIEUR_SYSTEMGRUPPE_ZAHN = 0x00AB;
+
+    /*
+     * Green Throttle Games.
+     */
+    public static final int GREEN_THROTTLE_GAMES = 0x00AC;
+
+    /*
+     * Peter Systemtechnik GmbH.
+     */
+    public static final int PETER_SYSTEMTECHNIK = 0x00AD;
+
+    /*
+     * Omegawave Oy.
+     */
+    public static final int OMEGAWAVE = 0x00AE;
+
+    /*
+     * Cinetix.
+     */
+    public static final int CINETIX = 0x00AF;
+
+    /*
+     * Passif Semiconductor Corp.
+     */
+    public static final int PASSIF_SEMICONDUCTOR = 0x00B0;
+
+    /*
+     * Saris Cycling Group, Inc.
+     */
+    public static final int SARIS_CYCLING_GROUP = 0x00B1;
+
+    /*
+     * Bekey A/S.
+     */
+    public static final int BEKEY = 0x00B2;
+
+    /*
+     * Clarinox Technologies Pty. Ltd.
+     */
+    public static final int CLARINOX_TECHNOLOGIES = 0x00B3;
+
+    /*
+     * BDE Technology Co., Ltd.
+     */
+    public static final int BDE_TECHNOLOGY = 0x00B4;
+
+    /*
+     * Swirl Networks.
+     */
+    public static final int SWIRL_NETWORKS = 0x00B5;
+
+    /*
+     * Meso international.
+     */
+    public static final int MESO_INTERNATIONAL = 0x00B6;
+
+    /*
+     * TreLab Ltd.
+     */
+    public static final int TRELAB = 0x00B7;
+
+    /*
+     * Qualcomm Innovation Center, Inc. (QuIC).
+     */
+    public static final int QUALCOMM_INNOVATION_CENTER = 0x00B8;
+
+    /*
+     * Johnson Controls, Inc.
+     */
+    public static final int JOHNSON_CONTROLS = 0x00B9;
+
+    /*
+     * Starkey Laboratories Inc.
+     */
+    public static final int STARKEY_LABORATORIES = 0x00BA;
+
+    /*
+     * S-Power Electronics Limited.
+     */
+    public static final int S_POWER_ELECTRONICS = 0x00BB;
+
+    /*
+     * Ace Sensor Inc.
+     */
+    public static final int ACE_SENSOR = 0x00BC;
+
+    /*
+     * Aplix Corporation.
+     */
+    public static final int APLIX = 0x00BD;
+
+    /*
+     * AAMP of America.
+     */
+    public static final int AAMP_OF_AMERICA = 0x00BE;
+
+    /*
+     * Stalmart Technology Limited.
+     */
+    public static final int STALMART_TECHNOLOGY = 0x00BF;
+
+    /*
+     * AMICCOM Electronics Corporation.
+     */
+    public static final int AMICCOM_ELECTRONICS = 0x00C0;
+
+    /*
+     * Shenzhen Excelsecu Data Technology Co.,Ltd.
+     */
+    public static final int SHENZHEN_EXCELSECU_DATA_TECHNOLOGY = 0x00C1;
+
+    /*
+     * Geneq Inc.
+     */
+    public static final int GENEQ = 0x00C2;
+
+    /*
+     * adidas AG.
+     */
+    public static final int ADIDAS = 0x00C3;
+
+    /*
+     * LG Electronics.
+     */
+    public static final int LG_ELECTRONICS = 0x00C4;
+
+    /*
+     * Onset Computer Corporation.
+     */
+    public static final int ONSET_COMPUTER = 0x00C5;
+
+    /*
+     * Selfly BV.
+     */
+    public static final int SELFLY = 0x00C6;
+
+    /*
+     * Quuppa Oy.
+     */
+    public static final int QUUPPA = 0x00C7;
+
+    /*
+     * GeLo Inc.
+     */
+    public static final int GELO = 0x00C8;
+
+    /*
+     * Evluma.
+     */
+    public static final int EVLUMA = 0x00C9;
+
+    /*
+     * MC10.
+     */
+    public static final int MC10 = 0x00CA;
+
+    /*
+     * Binauric SE.
+     */
+    public static final int BINAURIC = 0x00CB;
+
+    /*
+     * Beats Electronics.
+     */
+    public static final int BEATS_ELECTRONICS = 0x00CC;
+
+    /*
+     * Microchip Technology Inc.
+     */
+    public static final int MICROCHIP_TECHNOLOGY = 0x00CD;
+
+    /*
+     * Elgato Systems GmbH.
+     */
+    public static final int ELGATO_SYSTEMS = 0x00CE;
+
+    /*
+     * ARCHOS SA.
+     */
+    public static final int ARCHOS = 0x00CF;
+
+    /*
+     * Dexcom, Inc.
+     */
+    public static final int DEXCOM = 0x00D0;
+
+    /*
+     * Polar Electro Europe B.V.
+     */
+    public static final int POLAR_ELECTRO_EUROPE = 0x00D1;
+
+    /*
+     * Dialog Semiconductor B.V.
+     */
+    public static final int DIALOG_SEMICONDUCTOR = 0x00D2;
+
+    /*
+     * Taixingbang Technology (HK) Co,. LTD.
+     */
+    public static final int TAIXINGBANG_TECHNOLOGY = 0x00D3;
+
+    /*
+     * Kawantech.
+     */
+    public static final int KAWANTECH = 0x00D4;
+
+    /*
+     * Austco Communication Systems.
+     */
+    public static final int AUSTCO_COMMUNICATION_SYSTEMS = 0x00D5;
+
+    /*
+     * Timex Group USA, Inc.
+     */
+    public static final int TIMEX_GROUP_USA = 0x00D6;
+
+    /*
+     * Qualcomm Technologies, Inc.
+     */
+    public static final int QUALCOMM_TECHNOLOGIES = 0x00D7;
+
+    /*
+     * Qualcomm Connected Experiences, Inc.
+     */
+    public static final int QUALCOMM_CONNECTED_EXPERIENCES = 0x00D8;
+
+    /*
+     * Voyetra Turtle Beach.
+     */
+    public static final int VOYETRA_TURTLE_BEACH = 0x00D9;
+
+    /*
+     * txtr GmbH.
+     */
+    public static final int TXTR = 0x00DA;
+
+    /*
+     * Biosentronics.
+     */
+    public static final int BIOSENTRONICS = 0x00DB;
+
+    /*
+     * Procter & Gamble.
+     */
+    public static final int PROCTER_AND_GAMBLE = 0x00DC;
+
+    /*
+     * Hosiden Corporation.
+     */
+    public static final int HOSIDEN = 0x00DD;
+
+    /*
+     * Muzik LLC.
+     */
+    public static final int MUZIK = 0x00DE;
+
+    /*
+     * Misfit Wearables Corp.
+     */
+    public static final int MISFIT_WEARABLES = 0x00DF;
+
+    /*
+     * Google.
+     */
+    public static final int GOOGLE = 0x00E0;
+
+    /*
+     * Danlers Ltd.
+     */
+    public static final int DANLERS = 0x00E1;
+
+    /*
+     * Semilink Inc.
+     */
+    public static final int SEMILINK = 0x00E2;
+
+    /*
      * You can't instantiate one of these.
      */
     private BluetoothAssignedNumbers() {
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 3ee7142..5eb642c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -219,7 +219,7 @@
      * {@link #BOND_NONE},
      * {@link #BOND_BONDING},
      * {@link #BOND_BONDED}.
-      */
+     */
     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
     /**
      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
@@ -228,7 +228,7 @@
      * {@link #BOND_NONE},
      * {@link #BOND_BONDING},
      * {@link #BOND_BONDED}.
-      */
+     */
     public static final String EXTRA_PREVIOUS_BOND_STATE =
             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
     /**
@@ -253,12 +253,26 @@
      */
     public static final int BOND_BONDED = 12;
 
-    /** @hide */
+    /**
+     * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
+     * intents for unbond reason.
+     * @hide
+     */
     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
-    /** @hide */
+
+    /**
+     * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
+     * intents to indicate pairing method used. Possible values are:
+     * {@link #PAIRING_VARIANT_PIN},
+     * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
+     */
     public static final String EXTRA_PAIRING_VARIANT =
             "android.bluetooth.device.extra.PAIRING_VARIANT";
-    /** @hide */
+
+    /**
+     * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
+     * intents as the value of passkey.
+     */
     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
 
     /**
@@ -306,7 +320,10 @@
     public static final String ACTION_NAME_FAILED =
             "android.bluetooth.device.action.NAME_FAILED";
 
-    /** @hide */
+    /**
+     * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PAIRING_REQUEST =
             "android.bluetooth.device.action.PAIRING_REQUEST";
@@ -343,6 +360,9 @@
     /**@hide*/
     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
 
+    /**@hide*/
+    public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
+
     /**
      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
      * Contains package name to return reply intent to.
@@ -443,8 +463,8 @@
     public static final int UNBOND_REASON_REMOVED = 9;
 
     /**
-     * The user will be prompted to enter a pin
-     * @hide
+     * The user will be prompted to enter a pin or
+     * a privileged app will enter a pin for user.
      */
     public static final int PAIRING_VARIANT_PIN = 0;
 
@@ -455,8 +475,8 @@
     public static final int PAIRING_VARIANT_PASSKEY = 1;
 
     /**
-     * The user will be prompted to confirm the passkey displayed on the screen
-     * @hide
+     * The user will be prompted to confirm the passkey displayed on the screen or
+     * a privileged app will confirm the passkey for the user.
      */
     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
 
@@ -704,10 +724,9 @@
      * the bonding process completes, and its result.
      * <p>Android system services will handle the necessary user interactions
      * to confirm and complete the bonding process.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
      *
      * @return false on immediate error, true if bonding will begin
-     * @hide
      */
     public boolean createBond() {
         if (sService == null) {
@@ -943,7 +962,13 @@
          return BluetoothDevice.ERROR;
     }
 
-    /** @hide */
+    /**
+     * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     *
+     * @return true pin has been set
+     *         false for error
+     */
     public boolean setPin(byte[] pin) {
         if (sService == null) {
             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
@@ -965,7 +990,13 @@
         return false;
     }
 
-    /** @hide */
+    /**
+     * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     *
+     * @return true confirmation has been sent out
+     *         false for error
+     */
     public boolean setPairingConfirmation(boolean confirm) {
         if (sService == null) {
             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 0752df8..a2bb78c 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -167,7 +167,7 @@
                 try {
                     mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
 
                 synchronized(mStateLock) {
@@ -261,7 +261,7 @@
             public void onGetDescriptor(String address, int srvcType,
                              int srvcInstId, ParcelUuid srvcUuid,
                              int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descUuid) {
+                             int descrInstId, ParcelUuid descUuid) {
                 if (DBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid);
 
                 if (!address.equals(mDevice.getAddress())) {
@@ -276,7 +276,7 @@
                 if (characteristic == null) return;
 
                 characteristic.addDescriptor(new BluetoothGattDescriptor(
-                    characteristic, descUuid.getUuid(), 0));
+                    characteristic, descUuid.getUuid(), descrInstId, 0));
             }
 
             /**
@@ -294,7 +294,7 @@
                 try {
                     mCallback.onServicesDiscovered(BluetoothGatt.this, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -341,7 +341,7 @@
                 try {
                     mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -387,7 +387,7 @@
                 try {
                     mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -418,7 +418,7 @@
                 try {
                     mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -429,7 +429,8 @@
             public void onDescriptorRead(String address, int status, int srvcType,
                              int srvcInstId, ParcelUuid srvcUuid,
                              int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descrUuid, byte[] value) {
+                             int descrInstId, ParcelUuid descrUuid,
+                             byte[] value) {
                 if (DBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid);
 
                 if (!address.equals(mDevice.getAddress())) {
@@ -444,7 +445,7 @@
                 if (characteristic == null) return;
 
                 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
-                        descrUuid.getUuid());
+                        descrUuid.getUuid(), descrInstId);
                 if (descriptor == null) return;
 
                 if (status == 0) descriptor.setValue(value);
@@ -456,7 +457,7 @@
                         mAuthRetry = true;
                         mService.readDescriptor(mClientIf, address,
                             srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
-                            descrUuid, AUTHENTICATION_MITM);
+                            descrInstId, descrUuid, AUTHENTICATION_MITM);
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
                     }
@@ -467,7 +468,7 @@
                 try {
                     mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -478,7 +479,7 @@
             public void onDescriptorWrite(String address, int status, int srvcType,
                              int srvcInstId, ParcelUuid srvcUuid,
                              int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descrUuid) {
+                             int descrInstId, ParcelUuid descrUuid) {
                 if (DBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid);
 
                 if (!address.equals(mDevice.getAddress())) {
@@ -493,7 +494,7 @@
                 if (characteristic == null) return;
 
                 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
-                        descrUuid.getUuid());
+                        descrUuid.getUuid(), descrInstId);
                 if (descriptor == null) return;
 
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
@@ -503,7 +504,7 @@
                         mAuthRetry = true;
                         mService.writeDescriptor(mClientIf, address,
                             srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
-                            descrUuid, characteristic.getWriteType(),
+                            descrInstId, descrUuid, characteristic.getWriteType(),
                             AUTHENTICATION_MITM, descriptor.getValue());
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
@@ -515,7 +516,7 @@
                 try {
                     mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -532,7 +533,7 @@
                 try {
                     mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -549,9 +550,17 @@
                 try {
                     mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
+
+            /**
+             * Listen command status callback
+             * @hide
+             */
+            public void onListen(int status) {
+                if (DBG) Log.d(TAG, "onListen() - status=" + status);
+            }
         };
 
     /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
@@ -684,6 +693,71 @@
         return true;
     }
 
+   /**
+     * Starts or stops sending of advertisement packages to listen for connection
+     * requests from a central devices.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param start Start or stop advertising
+     */
+    /*package*/ void listen(boolean start) {
+        if (mContext == null || !mContext.getResources().
+            getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) {
+            throw new UnsupportedOperationException("BluetoothGatt#listen is blocked");
+        }
+        if (DBG) Log.d(TAG, "listen() - start: " + start);
+        if (mService == null || mClientIf == 0) return;
+
+        try {
+            mService.clientListen(mClientIf, start);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+    }
+
+    /**
+     * Sets the advertising data contained in the adv. response packet.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param advData true to set adv. data, false to set scan response
+     * @param includeName Inlucde the name in the adv. response
+     * @param includeTxPower Include TX power value
+     * @param minInterval Minimum desired scan interval (optional)
+     * @param maxInterval Maximum desired scan interval (optional)
+     * @param appearance The appearance flags for the device (optional)
+     * @param manufacturerData Manufacturer specific data including company ID (optional)
+     */
+    /*package*/ void setAdvData(boolean advData, boolean includeName, boolean includeTxPower,
+                           Integer minInterval, Integer maxInterval,
+                           Integer appearance, Byte[] manufacturerData) {
+        if (mContext == null || !mContext.getResources().
+            getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) {
+            throw new UnsupportedOperationException("BluetoothGatt#setAdvData is blocked");
+        }
+        if (DBG) Log.d(TAG, "setAdvData()");
+        if (mService == null || mClientIf == 0) return;
+
+        byte[] data = new byte[0];
+        if (manufacturerData != null) {
+            data = new byte[manufacturerData.length];
+            for(int i = 0; i != manufacturerData.length; ++i) {
+                data[i] = manufacturerData[i];
+            }
+        }
+
+        try {
+            mService.setAdvData(mClientIf, !advData,
+                includeName, includeTxPower,
+                minInterval != null ? minInterval : 0,
+                maxInterval != null ? maxInterval : 0,
+                appearance != null ? appearance : 0, data);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+    }
+
     /**
      * Disconnects an established connection, or cancels a connection attempt
      * currently in progress.
@@ -915,11 +989,11 @@
         if (device == null) return false;
 
         try {
-            mService.readDescriptor(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()),
-                new ParcelUuid(descriptor.getUuid()), AUTHENTICATION_NONE);
+            mService.readDescriptor(mClientIf, device.getAddress(), service.getType(),
+                service.getInstanceId(), new ParcelUuid(service.getUuid()),
+                characteristic.getInstanceId(), new ParcelUuid(characteristic.getUuid()),
+                descriptor.getInstanceId(), new ParcelUuid(descriptor.getUuid()),
+                AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -953,11 +1027,10 @@
         if (device == null) return false;
 
         try {
-            mService.writeDescriptor(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()),
-                new ParcelUuid(descriptor.getUuid()),
+            mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(),
+                service.getInstanceId(), new ParcelUuid(service.getUuid()),
+                characteristic.getInstanceId(), new ParcelUuid(characteristic.getUuid()),
+                descriptor.getInstanceId(), new ParcelUuid(descriptor.getUuid()),
                 characteristic.getWriteType(), AUTHENTICATION_NONE,
                 descriptor.getValue());
         } catch (RemoteException e) {
@@ -1037,7 +1110,7 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      */
-    public void abortReliableWrite(BluetoothDevice mDevice) {
+    public void abortReliableWrite() {
         if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return;
 
@@ -1049,6 +1122,13 @@
     }
 
     /**
+     * @deprecated Use {@link #abortReliableWrite()}
+     */
+    public void abortReliableWrite(BluetoothDevice mDevice) {
+        abortReliableWrite();
+    }
+
+    /**
      * Enable or disable notifications/indications for a given characteristic.
      *
      * <p>Once notifications are enabled for a characteristic, a
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 033f079..f0ecbb4 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -283,6 +283,20 @@
     }
 
     /**
+     * Get a descriptor by UUID and isntance id.
+     * @hide
+     */
+    /*package*/  BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) {
+        for(BluetoothGattDescriptor descriptor : mDescriptors) {
+            if (descriptor.getUuid().equals(uuid)
+             && descriptor.getInstanceId() == instanceId) {
+                return descriptor;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the service this characteristic belongs to.
      * @return The asscociated service
      */
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 1cd6878..5f525dc 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -91,6 +91,12 @@
     protected UUID mUuid;
 
     /**
+     * Instance ID for this descriptor.
+     * @hide
+     */
+    protected int mInstance;
+
+    /**
      * Permissions for this descriptor
      * @hide
      */
@@ -116,7 +122,7 @@
      * @param permissions Permissions for this descriptor
      */
     public BluetoothGattDescriptor(UUID uuid, int permissions) {
-        initDescriptor(null, uuid, permissions);
+        initDescriptor(null, uuid, 0, permissions);
     }
 
     /**
@@ -128,14 +134,15 @@
      * @param permissions Permissions for this descriptor
      */
     /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
-                                    int permissions) {
-        initDescriptor(characteristic, uuid, permissions);
+                                    int instance, int permissions) {
+        initDescriptor(characteristic, uuid, instance, permissions);
     }
 
     private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
-                                int permissions) {
+                                int instance, int permissions) {
         mCharacteristic = characteristic;
         mUuid = uuid;
+        mInstance = instance;
         mPermissions = permissions;
     }
 
@@ -165,6 +172,21 @@
     }
 
     /**
+     * Returns the instance ID for this descriptor.
+     *
+     * <p>If a remote device offers multiple descriptors with the same UUID,
+     * the instance ID is used to distuinguish between descriptors.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @return Instance ID of this descriptor
+     * @hide
+     */
+    public int getInstanceId() {
+        return mInstance;
+    }
+
+    /**
      * Returns the permissions for this descriptor.
      *
      * @return Permissions of this descriptor
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 78d536b..58ee54f 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -108,7 +108,7 @@
                                                       connected ? BluetoothProfile.STATE_CONNECTED :
                                                       BluetoothProfile.STATE_DISCONNECTED);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -128,7 +128,7 @@
                 try {
                     mCallback.onServiceAdded((int)status, service);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -154,7 +154,7 @@
                 try {
                     mCallback.onCharacteristicReadRequest(device, transId, offset, characteristic);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -186,7 +186,7 @@
                 try {
                     mCallback.onDescriptorReadRequest(device, transId, offset, descriptor);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -214,7 +214,7 @@
                     mCallback.onCharacteristicWriteRequest(device, transId, characteristic,
                                                            isPrep, needRsp, offset, value);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
 
             }
@@ -250,7 +250,7 @@
                     mCallback.onDescriptorWriteRequest(device, transId, descriptor,
                                                        isPrep, needRsp, offset, value);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
 
@@ -270,7 +270,7 @@
                 try {
                     mCallback.onExecuteWrite(device, transId, execWrite);
                 } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
         };
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 39a435b..1e66369 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -152,8 +152,8 @@
      */
     /*package*/ BluetoothGattCharacteristic getCharacteristic(UUID uuid, int instanceId) {
         for(BluetoothGattCharacteristic characteristic : mCharacteristics) {
-            if (uuid.equals(characteristic.getUuid()) &&
-                    mInstanceId == instanceId)
+            if (uuid.equals(characteristic.getUuid())
+             && characteristic.getInstanceId() == instanceId)
                 return characteristic;
         }
         return null;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 793d798..1962514 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -193,6 +193,11 @@
             "android.bluetooth.headset.intent.category.companyid";
 
     /**
+     * A vendor-specific command for unsolicited result code.
+     */
+    public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
+
+    /**
      * Headset state when SCO audio is not connected.
      * This state can be one of
      * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
@@ -241,9 +246,7 @@
                             try {
                                 if (mService == null) {
                                     if (VDBG) Log.d(TAG,"Binding service...");
-                                    if (!mContext.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
-                                        Log.e(TAG, "Could not bind to Bluetooth Headset Service");
-                                    }
+                                    doBind();
                                 }
                             } catch (Exception re) {
                                 Log.e(TAG,"",re);
@@ -270,9 +273,18 @@
             }
         }
 
-        if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth Headset Service");
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothHeadset.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent);
+            return false;
         }
+        return true;
     }
 
     /**
@@ -815,27 +827,6 @@
     }
 
     /**
-     * Notify Headset of phone roam state change.
-     * This is a backdoor for phone app to call BluetoothHeadset since
-     * there is currently not a good way to get roaming state change outside
-     * of phone app.
-     *
-     * @hide
-     */
-    public void roamChanged(boolean roaming) {
-        if (mService != null && isEnabled()) {
-            try {
-                mService.roamChanged(roaming);
-            } 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()));
-        }
-    }
-
-    /**
      * Send Headset of CLCC response
      *
      * @hide
@@ -854,6 +845,46 @@
         }
     }
 
+    /**
+     * Sends a vendor-specific unsolicited result code to the headset.
+     *
+     * <p>The actual string to be sent is <code>command + ": " + arg</code>.
+     * For example, if {@code command} is {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} and {@code arg}
+     * is {@code "0"}, the string <code>"+ANDROID: 0"</code> will be sent.
+     *
+     * <p>Currently only {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} is allowed as {@code command}.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device Bluetooth headset.
+     * @param command A vendor-specific command.
+     * @param arg The argument that will be attached to the command.
+     * @return {@code false} if there is no headset connected, or if the command is not an allowed
+     *         vendor-specific unsolicited result code, or on error. {@code true} otherwise.
+     * @throws IllegalArgumentException if {@code command} is {@code null}.
+     */
+    public boolean sendVendorSpecificResultCode(BluetoothDevice device, String command,
+            String arg) {
+        if (DBG) {
+            log("sendVendorSpecificResultCode()");
+        }
+        if (command == null) {
+            throw new IllegalArgumentException("command is null");
+        }
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.sendVendorSpecificResultCode(device, command, arg);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return false;
+    }
+
     private ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index cb23662..b1a084a 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -117,9 +117,7 @@
                             try {
                                 if (mService == null) {
                                     if (VDBG) Log.d(TAG,"Binding service...");
-                                    if (!mContext.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
-                                        Log.e(TAG, "Could not bind to Bluetooth Health Service");
-                                    }
+                                    doBind();
                                 }
                             } catch (Exception re) {
                                 Log.e(TAG,"",re);
@@ -483,9 +481,18 @@
             }
         }
 
-        if (!context.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth Health Service");
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothHealth.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent);
+            return false;
         }
+        return true;
     }
 
     /*package*/ void close() {
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index db7e424..f9c789c 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -206,9 +206,7 @@
                             try {
                                 if (mService == null) {
                                     if (VDBG) Log.d(TAG,"Binding service...");
-                                    if (!mContext.bindService(new Intent(IBluetoothInputDevice.class.getName()), mConnection, 0)) {
-                                        Log.e(TAG, "Could not bind to Bluetooth HID Service");
-                                    }
+                                    doBind();
                                 }
                             } catch (Exception re) {
                                 Log.e(TAG,"",re);
@@ -237,10 +235,18 @@
             }
         }
 
-        if (!context.bindService(new Intent(IBluetoothInputDevice.class.getName()),
-                                 mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth HID Service");
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothInputDevice.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
+            return false;
         }
+        return true;
     }
 
     /*package*/ void close() {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
new file mode 100644
index 0000000..fac8fd5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -0,0 +1,408 @@
+/*
+ * 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.bluetooth;
+
+import java.util.List;
+import java.util.ArrayList;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * This class provides the APIs to control the Bluetooth MAP
+ * Profile.
+ *@hide
+ */
+public final class BluetoothMap implements BluetoothProfile {
+
+    private static final String TAG = "BluetoothMap";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
+
+    private IBluetoothMap mService;
+    private final Context mContext;
+    private ServiceListener mServiceListener;
+    private BluetoothAdapter mAdapter;
+
+    /** There was an error trying to obtain the state */
+    public static final int STATE_ERROR        = -1;
+
+    public static final int RESULT_FAILURE = 0;
+    public static final int RESULT_SUCCESS = 1;
+    /** Connection canceled before completion. */
+    public static final int RESULT_CANCELED = 2;
+
+    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 BluetoothMap proxy object.
+     */
+    /*package*/ BluetoothMap(Context context, ServiceListener l) {
+        if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
+        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(IBluetoothMap.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
+            return false;
+        }
+        return true;
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Close the connection to the backing service.
+     * Other public functions of BluetoothMap will return default error
+     * results once close() has been called. Multiple invocations of close()
+     * are ok.
+     */
+    public synchronized void 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);
+                    mConnection = null;
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
+        mServiceListener = null;
+    }
+
+    /**
+     * Get the current state of the BluetoothMap service.
+     * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
+     *         object is currently not connected to the Map service.
+     */
+    public int getState() {
+        if (VDBG) log("getState()");
+        if (mService != null) {
+            try {
+                return mService.getState();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) log(Log.getStackTraceString(new Throwable()));
+        }
+        return BluetoothMap.STATE_ERROR;
+    }
+
+    /**
+     * Get the currently connected remote Bluetooth device (PCE).
+     * @return The remote Bluetooth device, or null if not in connected or
+     *         connecting state, or if this proxy object is not connected to
+     *         the Map service.
+     */
+    public BluetoothDevice getClient() {
+        if (VDBG) log("getClient()");
+        if (mService != null) {
+            try {
+                return mService.getClient();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) log(Log.getStackTraceString(new Throwable()));
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if the specified Bluetooth device is connected.
+     * Returns false if not connected, or if this proxy object is not
+     * currently connected to the Map service.
+     */
+    public boolean isConnected(BluetoothDevice device) {
+        if (VDBG) log("isConnected(" + device + ")");
+        if (mService != null) {
+            try {
+                return mService.isConnected(device);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) log(Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Initiate connection. Initiation of outgoing connections is not
+     * supported for MAP server.
+     */
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
+        return false;
+    }
+
+    /**
+     * Initiate disconnect.
+     *
+     * @param device Remote Bluetooth Device
+     * @return false on error,
+     *               true otherwise
+     */
+    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;
+    }
+
+    /**
+     * Check class bits for possible Map support.
+     * This is a simple heuristic that tries to guess if a device with the
+     * given class bits might support Map. It is not accurate for all
+     * devices. It tries to err on the side of false positives.
+     * @return True if this device might support Map.
+     */
+    public static boolean doesClassMatchSink(BluetoothClass btClass) {
+        // TODO optimize the rule
+        switch (btClass.getDeviceClass()) {
+        case BluetoothClass.Device.COMPUTER_DESKTOP:
+        case BluetoothClass.Device.COMPUTER_LAPTOP:
+        case BluetoothClass.Device.COMPUTER_SERVER:
+        case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    /**
+     * Get the list of connected devices. Currently at most one.
+     *
+     * @return list of connected devices
+     */
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (DBG) 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>();
+    }
+
+    /**
+     * Get the list of devices matching specified states. Currently at most one.
+     *
+     * @return list of matching devices
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) 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>();
+    }
+
+    /**
+     * Get connection state of device
+     *
+     * @return device connection state
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) 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
+     *
+     * <p> The device should already be paired.
+     *  Priority can be one of {@link #PRIORITY_ON} or
+     * {@link #PRIORITY_OFF},
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     */
+    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.
+     *
+     * <p> The priority can be any of:
+     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     */
+    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;
+    }
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) log("Proxy object connected");
+            mService = IBluetoothMap.Stub.asInterface(service);
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) log("Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
+            }
+        }
+    };
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+
+   private boolean isEnabled() {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
+        log("Bluetooth is Not enabled");
+        return false;
+    }
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
+    }
+
+
+}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index e25ec86..83d4329 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -137,12 +137,20 @@
         } catch (RemoteException re) {
             Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re);
         }
-        Log.d(TAG, "BluetoothPan() call bindService");
-        if (!context.bindService(new Intent(IBluetoothPan.class.getName()),
-                                 mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth HID Service");
+        if (VDBG) Log.d(TAG, "BluetoothPan() call bindService");
+        doBind();
+        if (VDBG) Log.d(TAG, "BluetoothPan(), bindService called");
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothPan.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth Pan Service with " + intent);
+            return false;
         }
-        Log.d(TAG, "BluetoothPan(), bindService called");
+        return true;
     }
 
     /*package*/ void close() {
@@ -170,11 +178,8 @@
             //Handle enable request to bind again.
             if (on) {
                 Log.d(TAG, "onBluetoothStateChange(on) call bindService");
-                if (!mContext.bindService(new Intent(IBluetoothPan.class.getName()),
-                                     mConnection, 0)) {
-                    Log.e(TAG, "Could not bind to Bluetooth HID Service");
-                }
-                Log.d(TAG, "BluetoothPan(), bindService called");
+                doBind();
+                if (VDBG) Log.d(TAG, "BluetoothPan(), bindService called");
             } else {
                 if (VDBG) Log.d(TAG,"Unbinding service...");
                 synchronized (mConnection) {
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index b5280e5..c42251f 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -129,11 +129,7 @@
                             try {
                                 if (mService == null) {
                                     if (VDBG) Log.d(TAG,"Binding service...");
-                                    if (!mContext.bindService(
-                                                        new Intent(IBluetoothPbap.class.getName()),
-                                                        mConnection, 0)) {
-                                        Log.e(TAG, "Could not bind to Bluetooth PBAP Service");
-                                    }
+                                    doBind();
                                 }
                             } catch (Exception re) {
                                 Log.e(TAG,"",re);
@@ -158,9 +154,18 @@
                 Log.e(TAG,"",e);
             }
         }
-        if (!context.bindService(new Intent(IBluetoothPbap.class.getName()), mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth Pbap Service");
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothPbap.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent);
+            return false;
         }
+        return true;
     }
 
     protected void finalize() throws Throwable {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 43079f4..1574090 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -98,6 +98,12 @@
     static public final int GATT_SERVER = 8;
 
     /**
+     * MAP Profile
+     * @hide
+     */
+    public static final int MAP = 9;
+
+    /**
      * 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/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index a19341c..d10eaea 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -31,6 +31,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
+import java.util.Locale;
 import java.util.UUID;
 import android.net.LocalSocket;
 import java.nio.ByteOrder;
@@ -473,7 +474,7 @@
         return mPort;
     }
     private String convertAddr(final byte[] addr)  {
-        return String.format("%02X:%02X:%02X:%02X:%02X:%02X",
+        return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
                 addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]);
     }
     private String waitSocketSignal(InputStream is) throws IOException {
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 81c0a6a..a9b7176 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -16,6 +16,7 @@
 
 package android.bluetooth;
 
+import android.net.BaseNetworkStateTracker;
 import android.os.IBinder;
 import android.os.ServiceManager;
 import android.os.INetworkManagementService;
@@ -54,7 +55,7 @@
  *
  * @hide
  */
-public class BluetoothTetheringDataTracker implements NetworkStateTracker {
+public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
     private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
     private static final String TAG = "BluetoothTethering";
     private static final boolean DBG = true;
@@ -66,18 +67,12 @@
     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
 
     private final Object mLinkPropertiesLock = new Object();
-    private LinkProperties mLinkProperties;
-
-    private LinkCapabilities mLinkCapabilities;
-
     private final Object mNetworkInfoLock = new Object();
-    private NetworkInfo mNetworkInfo;
 
     private BluetoothPan mBluetoothPan;
     private static String mRevTetheredIface;
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
-    protected Context mContext;
     private static BluetoothTetheringDataTracker sInstance;
     private BtdtHandler mBtdtHandler;
     private AtomicReference<AsyncChannel> mAsyncChannel = new AtomicReference<AsyncChannel>(null);
@@ -152,6 +147,11 @@
         // not implemented
     }
 
+    @Override
+    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+        // not implemented
+    }
+
     /**
      * Re-enable connectivity to a network after a {@link #teardown()}.
      */
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 5962235..abdf949e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -56,6 +56,8 @@
             ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
     public static final ParcelUuid Hid =
             ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
+    public static final ParcelUuid Hogp =
+            ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
     public static final ParcelUuid PANU =
             ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid NAP =
@@ -64,10 +66,17 @@
             ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid PBAP_PSE =
             ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid MAP =
+            ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid MNS =
+            ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid MAS =
+            ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+
 
     public static final ParcelUuid[] RESERVED_UUIDS = {
         AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
-        ObexObjectPush, PANU, NAP};
+        ObexObjectPush, PANU, NAP, MAP, MNS, MAS};
 
     public static boolean isAudioSource(ParcelUuid uuid) {
         return uuid.equals(AudioSource);
@@ -112,6 +121,16 @@
     public static boolean isBnep(ParcelUuid uuid) {
         return uuid.equals(BNEP);
     }
+    public static boolean isMap(ParcelUuid uuid) {
+        return uuid.equals(MAP);
+    }
+    public static boolean isMns(ParcelUuid uuid) {
+        return uuid.equals(MNS);
+    }
+    public static boolean isMas(ParcelUuid uuid) {
+        return uuid.equals(MAS);
+    }
+
     /**
      * Returns true if ParcelUuid is present in uuidArray
      *
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 80806f9..07db8cc 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -80,4 +80,6 @@
     // For Socket
     ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in ParcelUuid uuid, int port, int flag);
     ParcelFileDescriptor createSocketChannel(int type, in String serviceName, in ParcelUuid uuid, int port, int flag);
+
+    boolean configHciSnoopLog(boolean enable);
 }
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 1f10998..26ff9e27 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -32,5 +32,8 @@
     int getConnectionState(in BluetoothDevice device);
     boolean setPriority(in BluetoothDevice device, int priority);
     int getPriority(in BluetoothDevice device);
+    boolean isAvrcpAbsoluteVolumeSupported();
+    oneway void adjustAvrcpAbsoluteVolume(int direction);
+    oneway void setAvrcpAbsoluteVolume(int volume);
     boolean isA2dpPlaying(in BluetoothDevice device);
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index c89d132..df393db 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -37,6 +37,10 @@
     void unregisterClient(in int clientIf);
     void clientConnect(in int clientIf, in String address, in boolean isDirect);
     void clientDisconnect(in int clientIf, in String address);
+    void clientListen(in int clientIf, in boolean start);
+    void setAdvData(in int clientIf, in boolean setScanRsp, in boolean inclName,
+                            in boolean inclTxPower, in int minInterval, in int maxInterval,
+                            in int appearance, in byte[] manufacturerData);
     void refreshDevice(in int clientIf, in String address);
     void discoverServices(in int clientIf, in String address);
     void readCharacteristic(in int clientIf, in String address, in int srvcType,
@@ -50,12 +54,13 @@
     void readDescriptor(in int clientIf, in String address, in int srvcType,
                             in int srvcInstanceId, in ParcelUuid srvcId,
                             in int charInstanceId, in ParcelUuid charId,
-                            in ParcelUuid descrUuid, in int authReq);
+                            in int descrInstanceId, in ParcelUuid descrUuid,
+                            in int authReq);
     void writeDescriptor(in int clientIf, in String address, in int srvcType,
                             in int srvcInstanceId, in ParcelUuid srvcId,
                             in int charInstanceId, in ParcelUuid charId,
-                            in ParcelUuid descrId, in int writeType,
-                            in int authReq, in byte[] value);
+                            in int descrInstanceId, in ParcelUuid descrId,
+                            in int writeType, in int authReq, in byte[] value);
     void registerForNotification(in int clientIf, in String address, in int srvcType,
                             in int srvcInstanceId, in ParcelUuid srvcId,
                             in int charInstanceId, in ParcelUuid charId,
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index fc52172..60c297b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -39,7 +39,7 @@
     void onGetDescriptor(in String address, in int srvcType,
                              in int srvcInstId, in ParcelUuid srvcUuid,
                              in int charInstId, in ParcelUuid charUuid,
-                             in ParcelUuid descrUuid);
+                             in int descrInstId, in ParcelUuid descrUuid);
     void onSearchComplete(in String address, in int status);
     void onCharacteristicRead(in String address, in int status, in int srvcType,
                              in int srvcInstId, in ParcelUuid srvcUuid,
@@ -52,14 +52,16 @@
     void onDescriptorRead(in String address, in int status, in int srvcType,
                              in int srvcInstId, in ParcelUuid srvcUuid,
                              in int charInstId, in ParcelUuid charUuid,
-                             in ParcelUuid descrUuid, in byte[] value);
+                             in int descrInstId, in ParcelUuid descrUuid,
+                             in byte[] value);
     void onDescriptorWrite(in String address, in int status, in int srvcType,
                              in int srvcInstId, in ParcelUuid srvcUuid,
                              in int charInstId, in ParcelUuid charUuid,
-                             in ParcelUuid descrUuid);
+                             in int descrInstId, in ParcelUuid descrUuid);
     void onNotify(in String address, in int srvcType,
                              in int srvcInstId, in ParcelUuid srvcUuid,
                              in int charInstId, in ParcelUuid charUuid,
                              in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
+    void onListen(in int status);
 }
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
old mode 100644
new mode 100755
index fc7627a..524ca6f
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -35,6 +35,9 @@
     boolean startVoiceRecognition(in BluetoothDevice device);
     boolean stopVoiceRecognition(in BluetoothDevice device);
     boolean isAudioConnected(in BluetoothDevice device);
+    boolean sendVendorSpecificResultCode(in BluetoothDevice device,
+                                         in String command,
+                                         in String arg);
 
     // APIs that can be made public in future
     int getBatteryUsageHint(in BluetoothDevice device);
@@ -50,7 +53,6 @@
     boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device);
     boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device);
     void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
-    void roamChanged(boolean roam);
     void clccResponse(int index, int direction, int status, int mode, boolean mpty,
                       String number, int type);
 }
diff --git a/core/java/android/bluetooth/IBluetoothMap.aidl b/core/java/android/bluetooth/IBluetoothMap.aidl
new file mode 100644
index 0000000..d4af63d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothMap.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth MAP service
+ *
+ * {@hide}
+ */
+interface IBluetoothMap {
+    int getState();
+    BluetoothDevice getClient();
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    boolean isConnected(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);
+}
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 898cc4e..809f900 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -147,6 +147,7 @@
     }
 
     private class ISyncAdapterImpl extends ISyncAdapter.Stub {
+        @Override
         public void startSync(ISyncContext syncContext, String authority, Account account,
                 Bundle extras) {
             final SyncContext syncContextClient = new SyncContext(syncContext);
@@ -187,6 +188,7 @@
             }
         }
 
+        @Override
         public void cancelSync(ISyncContext syncContext) {
             // synchronize to make sure that mSyncThreads doesn't change between when we
             // check it and when we use it
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 612c67f..eb7426e 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -26,6 +26,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 
 /**
  * Abstract Loader that provides an {@link AsyncTask} to do the work.  See
@@ -123,6 +124,8 @@
         }
     }
 
+    private final Executor mExecutor;
+
     volatile LoadTask mTask;
     volatile LoadTask mCancellingTask;
 
@@ -131,7 +134,13 @@
     Handler mHandler;
 
     public AsyncTaskLoader(Context context) {
+        this(context, AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    /** {@hide} */
+    public AsyncTaskLoader(Context context, Executor executor) {
         super(context);
+        mExecutor = executor;
     }
 
     /**
@@ -223,7 +232,7 @@
                 }
             }
             if (DEBUG) Slog.v(TAG, "Executing: " + mTask);
-            mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+            mTask.executeOnExecutor(mExecutor, (Void[]) null);
         }
     }
 
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 69f9d4a..73e6fd0 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -122,7 +122,7 @@
             if (clip != null) {
                 clip.prepareToLeaveProcess();
             }
-            getService().setPrimaryClip(clip, mContext.getBasePackageName());
+            getService().setPrimaryClip(clip, mContext.getOpPackageName());
         } catch (RemoteException e) {
         }
     }
@@ -132,7 +132,7 @@
      */
     public ClipData getPrimaryClip() {
         try {
-            return getService().getPrimaryClip(mContext.getBasePackageName());
+            return getService().getPrimaryClip(mContext.getOpPackageName());
         } catch (RemoteException e) {
             return null;
         }
@@ -144,7 +144,7 @@
      */
     public ClipDescription getPrimaryClipDescription() {
         try {
-            return getService().getPrimaryClipDescription(mContext.getBasePackageName());
+            return getService().getPrimaryClipDescription(mContext.getOpPackageName());
         } catch (RemoteException e) {
             return null;
         }
@@ -155,7 +155,7 @@
      */
     public boolean hasPrimaryClip() {
         try {
-            return getService().hasPrimaryClip(mContext.getBasePackageName());
+            return getService().hasPrimaryClip(mContext.getOpPackageName());
         } catch (RemoteException e) {
             return false;
         }
@@ -166,7 +166,7 @@
             if (mPrimaryClipChangedListeners.size() == 0) {
                 try {
                     getService().addPrimaryClipChangedListener(
-                            mPrimaryClipChangedServiceListener, mContext.getBasePackageName());
+                            mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
                 } catch (RemoteException e) {
                 }
             }
@@ -213,7 +213,7 @@
      */
     public boolean hasText() {
         try {
-            return getService().hasClipboardText(mContext.getBasePackageName());
+            return getService().hasClipboardText(mContext.getOpPackageName());
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index dad60b0..b96c8d3 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -22,6 +22,11 @@
  * The set of callback APIs that are common to all application components
  * ({@link android.app.Activity}, {@link android.app.Service},
  * {@link ContentProvider}, and {@link android.app.Application}).
+ *
+ * <p class="note"><strong>Note:</strong> You should also implement the {@link
+ * ComponentCallbacks2} interface, which provides the {@link
+ * ComponentCallbacks2#onTrimMemory} callback to help your app manage its memory usage more
+ * effectively.</p>
  */
 public interface ComponentCallbacks {
     /**
@@ -29,26 +34,35 @@
      * component is running.  Note that, unlike activities, other components
      * are never restarted when a configuration changes: they must always deal
      * with the results of the change, such as by re-retrieving resources.
-     * 
+     *
      * <p>At the time that this function has been called, your Resources
      * object will have been updated to return resource values matching the
      * new configuration.
-     * 
+     *
+     * <p>For more information, read <a href="{@docRoot}guide/topics/resources/runtime-changes.html"
+     * >Handling Runtime Changes</a>.
+     *
      * @param newConfig The new device configuration.
      */
     void onConfigurationChanged(Configuration newConfig);
-    
+
     /**
      * This is called when the overall system is running low on memory, and
-     * would like actively running process to try to tighten their belt.  While
+     * actively running processes should trim their memory usage.  While
      * the exact point at which this will be called is not defined, generally
-     * it will happen around the time all background process have been killed,
-     * that is before reaching the point of killing processes hosting
+     * it will happen when all background process have been killed.
+     * That is, before reaching the point of killing processes hosting
      * service and foreground UI that we would like to avoid killing.
-     * 
-     * <p>Applications that want to be nice can implement this method to release
-     * any caches or other unnecessary resources they may be holding on to.
-     * The system will perform a gc for you after returning from this method.
+     *
+     * <p>You should implement this method to release
+     * any caches or other unnecessary resources you may be holding on to.
+     * The system will perform a garbage collection for you after returning from this method.
+     * <p>Preferably, you should implement {@link ComponentCallbacks2#onTrimMemory} from
+     * {@link ComponentCallbacks2} to incrementally unload your resources based on various
+     * levels of memory demands.  That API is available for API level 14 and higher, so you should
+     * only use this {@link #onLowMemory} method as a fallback for older versions, which can be
+     * treated the same as {@link ComponentCallbacks2#onTrimMemory} with the {@link
+     * ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.</p>
      */
     void onLowMemory();
 }
diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java
index a3b4e5e..b78548b 100644
--- a/core/java/android/content/ComponentCallbacks2.java
+++ b/core/java/android/content/ComponentCallbacks2.java
@@ -18,7 +18,68 @@
 
 /**
  * Extended {@link ComponentCallbacks} interface with a new callback for
- * finer-grained memory management.
+ * finer-grained memory management. This interface is available in all application components
+ * ({@link android.app.Activity}, {@link android.app.Service},
+ * {@link ContentProvider}, and {@link android.app.Application}).
+ *
+ * <p>You should implement {@link #onTrimMemory} to incrementally release memory based on current
+ * system constraints. Using this callback to release your resources helps provide a more
+ * responsive system overall, but also directly benefits the user experience for
+ * your app by allowing the system to keep your process alive longer. That is,
+ * if you <em>don't</em> trim your resources based on memory levels defined by this callback,
+ * the system is more likely to kill your process while it is cached in the least-recently used
+ * (LRU) list, thus requiring your app to restart and restore all state when the user returns to it.
+ *
+ * <p>The values provided by {@link #onTrimMemory} do not represent a single linear progression of
+ * memory limits, but provide you different types of clues about memory availability:</p>
+ * <ul>
+ * <li>When your app is running:
+ *  <ol>
+ *  <li>{@link #TRIM_MEMORY_RUNNING_MODERATE} <br>The device is beginning to run low on memory.
+ * Your app is running and not killable.
+ *  <li>{@link #TRIM_MEMORY_RUNNING_LOW} <br>The device is running much lower on memory.
+ * Your app is running and not killable, but please release unused resources to improve system
+ * performance (which directly impacts your app's performance).
+ *  <li>{@link #TRIM_MEMORY_RUNNING_CRITICAL} <br>The device is running extremely low on memory.
+ * Your app is not yet considered a killable process, but the system will begin killing
+ * background processes if apps do not release resources, so you should release non-critical
+ * resources now to prevent performance degradation.
+ *  </ol>
+ * </li>
+ * <li>When your app's visibility changes:
+ *  <ol>
+ *  <li>{@link #TRIM_MEMORY_UI_HIDDEN} <br>Your app's UI is no longer visible, so this is a good
+ * time to release large resources that are used only by your UI.
+ *  </ol>
+ * </li>
+ * <li>When your app's process resides in the background LRU list:
+ *  <ol>
+ *  <li>{@link #TRIM_MEMORY_BACKGROUND} <br>The system is running low on memory and your process is
+ * near the beginning of the LRU list. Although your app process is not at a high risk of being
+ * killed, the system may already be killing processes in the LRU list, so you should release
+ * resources that are easy to recover so your process will remain in the list and resume
+ * quickly when the user returns to your app.
+ *  <li>{@link #TRIM_MEMORY_MODERATE} <br>The system is running low on memory and your process is
+ * near the middle of the LRU list. If the system becomes further constrained for memory, there's a
+ * chance your process will be killed.
+ *  <li>{@link #TRIM_MEMORY_COMPLETE} <br>The system is running low on memory and your process is
+ * one of the first to be killed if the system does not recover memory now. You should release
+ * absolutely everything that's not critical to resuming your app state.
+ *   <p>To support API levels lower than 14, you can use the {@link #onLowMemory} method as a
+ * fallback that's roughly equivalent to the {@link ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.
+ *  </li>
+ *  </ol>
+ * <p class="note"><strong>Note:</strong> When the system begins
+ * killing processes in the LRU list, although it primarily works bottom-up, it does give some
+ * consideration to which processes are consuming more memory and will thus provide more gains in
+ * memory if killed. So the less memory you consume while in the LRU list overall, the better
+ * your chances are to remain in the list and be able to quickly resume.</p>
+ * </li>
+ * </ul>
+ * <p>More information about the different stages of a process lifecycle (such as what it means
+ * to be placed in the background LRU list) is provided in the <a
+ * href="{@docRoot}guide/components/processes-and-threads.html#Lifecycle">Processes and Threads</a>
+ * document.
  */
 public interface ComponentCallbacks2 extends ComponentCallbacks {
 
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 7ca0f01..547a2c3 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -18,6 +18,8 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+
+import java.io.PrintWriter;
 import java.lang.Comparable;
 
 /**
@@ -109,6 +111,32 @@
         return mClass;
     }
     
+    private static void appendShortClassName(StringBuilder sb, String packageName,
+            String className) {
+        if (className.startsWith(packageName)) {
+            int PN = packageName.length();
+            int CN = className.length();
+            if (CN > PN && className.charAt(PN) == '.') {
+                sb.append(className, PN, CN);
+                return;
+            }
+        }
+        sb.append(className);
+    }
+
+    private static void printShortClassName(PrintWriter pw, String packageName,
+            String className) {
+        if (className.startsWith(packageName)) {
+            int PN = packageName.length();
+            int CN = className.length();
+            if (CN > PN && className.charAt(PN) == '.') {
+                pw.write(className, PN, CN-PN);
+                return;
+            }
+        }
+        pw.print(className);
+    }
+
     /**
      * Return a String that unambiguously describes both the package and
      * class names contained in the ComponentName.  You can later recover
@@ -137,9 +165,29 @@
      * @see #unflattenFromString(String)
      */
     public String flattenToShortString() {
-        return mPackage + "/" + getShortClassName();
+        StringBuilder sb = new StringBuilder(mPackage.length() + mClass.length());
+        appendShortString(sb, mPackage, mClass);
+        return sb.toString();
     }
-    
+
+    /** @hide */
+    public void appendShortString(StringBuilder sb) {
+        appendShortString(sb, mPackage, mClass);
+    }
+
+    /** @hide */
+    public static void appendShortString(StringBuilder sb, String packageName, String className) {
+        sb.append(packageName).append('/');
+        appendShortClassName(sb, packageName, className);
+    }
+
+    /** @hide */
+    public static void printShortString(PrintWriter pw, String packageName, String className) {
+        pw.print(packageName);
+        pw.print('/');
+        printShortClassName(pw, packageName, className);
+    }
+
     /**
      * Recover a ComponentName from a String that was previously created with
      * {@link #flattenToString()}.  It splits the string at the first '/',
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index cf627d7..461dc1d 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -16,11 +16,9 @@
 
 package android.content;
 
-import static android.content.pm.PackageManager.GET_PROVIDERS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.app.AppOpsManager;
-import android.content.pm.PackageManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.res.AssetFileDescriptor;
@@ -36,7 +34,6 @@
 import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
 
@@ -104,6 +101,8 @@
     private boolean mExported;
     private boolean mNoPerms;
 
+    private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
+
     private Transport mTransport = new Transport();
 
     /**
@@ -196,8 +195,14 @@
                 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                         CancellationSignal.fromTransport(cancellationSignal));
             }
-            return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
-                    CancellationSignal.fromTransport(cancellationSignal));
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.query(
+                        uri, projection, selection, selectionArgs, sortOrder,
+                        CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
@@ -210,7 +215,12 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return rejectInsert(uri, initialValues);
             }
-            return ContentProvider.this.insert(uri, initialValues);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.insert(uri, initialValues);
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
@@ -218,7 +228,12 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
-            return ContentProvider.this.bulkInsert(uri, initialValues);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.bulkInsert(uri, initialValues);
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
@@ -240,7 +255,12 @@
                     }
                 }
             }
-            return ContentProvider.this.applyBatch(operations);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.applyBatch(operations);
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
@@ -248,7 +268,12 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
-            return ContentProvider.this.delete(uri, selection, selectionArgs);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.delete(uri, selection, selectionArgs);
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
@@ -257,26 +282,50 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
-            return ContentProvider.this.update(uri, values, selection, selectionArgs);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.update(uri, values, selection, selectionArgs);
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
-        public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode)
+        public ParcelFileDescriptor openFile(
+                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
-            return ContentProvider.this.openFile(uri, mode);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.openFile(
+                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode)
+        public AssetFileDescriptor openAssetFile(
+                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
-            return ContentProvider.this.openAssetFile(uri, mode);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.openAssetFile(
+                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
         public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
-            return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.call(method, arg, extras);
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
@@ -286,16 +335,48 @@
 
         @Override
         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
-                Bundle opts) throws FileNotFoundException {
+                Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, "r");
-            return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.openTypedAssetFile(
+                        uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                setCallingPackage(original);
+            }
         }
 
         @Override
-        public ICancellationSignal createCancellationSignal() throws RemoteException {
+        public ICancellationSignal createCancellationSignal() {
             return CancellationSignal.createTransport();
         }
 
+        @Override
+        public Uri canonicalize(String callingPkg, Uri uri) {
+            if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+                return null;
+            }
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.canonicalize(uri);
+            } finally {
+                setCallingPackage(original);
+            }
+        }
+
+        @Override
+        public Uri uncanonicalize(String callingPkg, Uri uri) {
+            if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+                return null;
+            }
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.uncanonicalize(uri);
+            } finally {
+                setCallingPackage(original);
+            }
+        }
+
         private void enforceFilePermission(String callingPkg, Uri uri, String mode)
                 throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
@@ -458,6 +539,38 @@
     }
 
     /**
+     * Set the calling package, returning the current value (or {@code null})
+     * which can be used later to restore the previous state.
+     */
+    private String setCallingPackage(String callingPackage) {
+        final String original = mCallingPackage.get();
+        mCallingPackage.set(callingPackage);
+        return original;
+    }
+
+    /**
+     * Return the package name of the caller that initiated the request being
+     * processed on the current thread. The returned package will have been
+     * verified to belong to the calling UID. Returns {@code null} if not
+     * currently processing a request.
+     * <p>
+     * This will always return {@code null} when processing
+     * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+     *
+     * @see Binder#getCallingUid()
+     * @see Context#grantUriPermission(String, Uri, int)
+     * @throws SecurityException if the calling package doesn't belong to the
+     *             calling UID.
+     */
+    public final String getCallingPackage() {
+        final String pkg = mCallingPackage.get();
+        if (pkg != null) {
+            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+        }
+        return pkg;
+    }
+
+    /**
      * Change the permission required to read data from the content
      * provider.  This is normally set for you from its manifest information
      * when the provider is first created.
@@ -526,8 +639,6 @@
     /** @hide */
     public final void setAppOps(int readOp, int writeOp) {
         if (!mNoPerms) {
-            mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
-                    Context.APP_OPS_SERVICE);
             mTransport.mReadOp = readOp;
             mTransport.mWriteOp = writeOp;
         }
@@ -765,6 +876,58 @@
     public abstract String getType(Uri uri);
 
     /**
+     * Implement this to support canonicalization of URIs that refer to your
+     * content provider.  A canonical URI is one that can be transported across
+     * devices, backup/restore, and other contexts, and still be able to refer
+     * to the same data item.  Typically this is implemented by adding query
+     * params to the URI allowing the content provider to verify that an incoming
+     * canonical URI references the same data as it was originally intended for and,
+     * if it doesn't, to find that data (if it exists) in the current environment.
+     *
+     * <p>For example, if the content provider holds people and a normal URI in it
+     * is created with a row index into that people database, the cananical representation
+     * may have an additional query param at the end which specifies the name of the
+     * person it is intended for.  Later calls into the provider with that URI will look
+     * up the row of that URI's base index and, if it doesn't match or its entry's
+     * name doesn't match the name in the query param, perform a query on its database
+     * to find the correct row to operate on.</p>
+     *
+     * <p>If you implement support for canonical URIs, <b>all</b> incoming calls with
+     * URIs (including this one) must perform this verification and recovery of any
+     * canonical URIs they receive.  In addition, you must also implement
+     * {@link #uncanonicalize} to strip the canonicalization of any of these URIs.</p>
+     *
+     * <p>The default implementation of this method returns null, indicating that
+     * canonical URIs are not supported.</p>
+     *
+     * @param url The Uri to canonicalize.
+     *
+     * @return Return the canonical representation of <var>url</var>, or null if
+     * canonicalization of that Uri is not supported.
+     */
+    public Uri canonicalize(Uri url) {
+        return null;
+    }
+
+    /**
+     * Remove canonicalization from canonical URIs previously returned by
+     * {@link #canonicalize}.  For example, if your implementation is to add
+     * a query param to canonicalize a URI, this method can simply trip any
+     * query params on the URI.  The default implementation always returns the
+     * same <var>url</var> that was passed in.
+     *
+     * @param url The Uri to remove any canonicalization from.
+     *
+     * @return Return the non-canonical representation of <var>url</var>, return
+     * the <var>url</var> as-is if there is nothing to do, or return null if
+     * the data identified by the canonical representation can not be found in
+     * the current environment.
+     */
+    public Uri uncanonicalize(Uri url) {
+        return url;
+    }
+
+    /**
      * @hide
      * Implementation when a caller has performed an insert on the content
      * provider, but that call has been rejected for the operation given
@@ -874,6 +1037,18 @@
      * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
      * their responsibility to close it when done.  That is, the implementation
      * of this method should create a new ParcelFileDescriptor for each call.
+     * <p>
+     * If opened with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
+     * supports seeking.
+     * <p>
+     * If you need to detect when the returned ParcelFileDescriptor has been
+     * closed, or if the remote process has crashed or encountered some other
+     * error, you can use {@link ParcelFileDescriptor#open(File, int,
+     * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
+     * {@link ParcelFileDescriptor#createReliablePipe()}, or
+     * {@link ParcelFileDescriptor#createReliableSocketPair()}.
      *
      * <p class="note">For use in Intents, you will want to implement {@link #getType}
      * to return the appropriate MIME type for the data returned here with
@@ -911,6 +1086,74 @@
     }
 
     /**
+     * Override this to handle requests to open a file blob.
+     * The default implementation always throws {@link FileNotFoundException}.
+     * This method can be called from multiple threads, as described in
+     * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+     * and Threads</a>.
+     *
+     * <p>This method returns a ParcelFileDescriptor, which is returned directly
+     * to the caller.  This way large data (such as images and documents) can be
+     * returned without copying the content.
+     *
+     * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
+     * their responsibility to close it when done.  That is, the implementation
+     * of this method should create a new ParcelFileDescriptor for each call.
+     * <p>
+     * If opened with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
+     * supports seeking.
+     * <p>
+     * If you need to detect when the returned ParcelFileDescriptor has been
+     * closed, or if the remote process has crashed or encountered some other
+     * error, you can use {@link ParcelFileDescriptor#open(File, int,
+     * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
+     * {@link ParcelFileDescriptor#createReliablePipe()}, or
+     * {@link ParcelFileDescriptor#createReliableSocketPair()}.
+     *
+     * <p class="note">For use in Intents, you will want to implement {@link #getType}
+     * to return the appropriate MIME type for the data returned here with
+     * the same URI.  This will allow intent resolution to automatically determine the data MIME
+     * type and select the appropriate matching targets as part of its operation.</p>
+     *
+     * <p class="note">For better interoperability with other applications, it is recommended
+     * that for any URIs that can be opened, you also support queries on them
+     * containing at least the columns specified by {@link android.provider.OpenableColumns}.
+     * You may also want to support other common columns if you have additional meta-data
+     * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
+     * in {@link android.provider.MediaStore.MediaColumns}.</p>
+     *
+     * @param uri The URI whose file is to be opened.
+     * @param mode Access mode for the file. May be "r" for read-only access,
+     *            "w" for write-only access, "rw" for read and write access, or
+     *            "rwt" for read and write access that truncates any existing
+     *            file.
+     * @param signal A signal to cancel the operation in progress, or
+     *            {@code null} if none. For example, if you are downloading a
+     *            file from the network to service a "rw" mode request, you
+     *            should periodically call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether
+     *            the client has canceled the request and abort the download.
+     *
+     * @return Returns a new ParcelFileDescriptor which you can use to access
+     * the file.
+     *
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     * no file associated with the given URI or the mode is invalid.
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not have permission to access the file.
+     *
+     * @see #openAssetFile(Uri, String)
+     * @see #openFileHelper(Uri, String)
+     * @see #getType(android.net.Uri)
+     */
+    public ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openFile(uri, mode);
+    }
+
+    /**
      * This is like {@link #openFile}, but can be implemented by providers
      * that need to be able to return sub-sections of files, often assets
      * inside of their .apk.
@@ -924,11 +1167,14 @@
      * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
      * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
      * methods.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
      *
      * <p class="note">If you are implementing this to return a full file, you
      * should create the AssetFileDescriptor with
      * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
-     * applications that can not handle sub-sections of files.</p>
+     * applications that cannot handle sub-sections of files.</p>
      *
      * <p class="note">For use in Intents, you will want to implement {@link #getType}
      * to return the appropriate MIME type for the data returned here with
@@ -965,6 +1211,68 @@
     }
 
     /**
+     * This is like {@link #openFile}, but can be implemented by providers
+     * that need to be able to return sub-sections of files, often assets
+     * inside of their .apk.
+     * This method can be called from multiple threads, as described in
+     * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+     * and Threads</a>.
+     *
+     * <p>If you implement this, your clients must be able to deal with such
+     * file slices, either directly with
+     * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
+     * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
+     * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
+     * methods.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
+     *
+     * <p class="note">If you are implementing this to return a full file, you
+     * should create the AssetFileDescriptor with
+     * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
+     * applications that cannot handle sub-sections of files.</p>
+     *
+     * <p class="note">For use in Intents, you will want to implement {@link #getType}
+     * to return the appropriate MIME type for the data returned here with
+     * the same URI.  This will allow intent resolution to automatically determine the data MIME
+     * type and select the appropriate matching targets as part of its operation.</p>
+     *
+     * <p class="note">For better interoperability with other applications, it is recommended
+     * that for any URIs that can be opened, you also support queries on them
+     * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
+     *
+     * @param uri The URI whose file is to be opened.
+     * @param mode Access mode for the file.  May be "r" for read-only access,
+     * "w" for write-only access (erasing whatever data is currently in
+     * the file), "wa" for write-only access to append to any existing data,
+     * "rw" for read and write access on any existing data, and "rwt" for read
+     * and write access that truncates any existing file.
+     * @param signal A signal to cancel the operation in progress, or
+     *            {@code null} if none. For example, if you are downloading a
+     *            file from the network to service a "rw" mode request, you
+     *            should periodically call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether
+     *            the client has canceled the request and abort the download.
+     *
+     * @return Returns a new AssetFileDescriptor which you can use to access
+     * the file.
+     *
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     * no file associated with the given URI or the mode is invalid.
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not have permission to access the file.
+     *
+     * @see #openFile(Uri, String)
+     * @see #openFileHelper(Uri, String)
+     * @see #getType(android.net.Uri)
+     */
+    public AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openAssetFile(uri, mode);
+    }
+
+    /**
      * Convenience for subclasses that wish to implement {@link #openFile}
      * by looking up a column named "_data" at the given URI.
      *
@@ -1002,7 +1310,7 @@
             throw new FileNotFoundException("Column _data not found.");
         }
 
-        int modeBits = ContentResolver.modeToMode(uri, mode);
+        int modeBits = ParcelFileDescriptor.parseMode(mode);
         return ParcelFileDescriptor.open(new File(path), modeBits);
     }
 
@@ -1041,6 +1349,9 @@
      *
      * <p>See {@link ClipData} for examples of the use and implementation
      * of this method.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
      *
      * <p class="note">For better interoperability with other applications, it is recommended
      * that for any URIs that can be opened, you also support queries on them
@@ -1086,6 +1397,64 @@
         throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter);
     }
 
+
+    /**
+     * Called by a client to open a read-only stream containing data of a
+     * particular MIME type.  This is like {@link #openAssetFile(Uri, String)},
+     * except the file can only be read-only and the content provider may
+     * perform data conversions to generate data of the desired type.
+     *
+     * <p>The default implementation compares the given mimeType against the
+     * result of {@link #getType(Uri)} and, if they match, simply calls
+     * {@link #openAssetFile(Uri, String)}.
+     *
+     * <p>See {@link ClipData} for examples of the use and implementation
+     * of this method.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
+     *
+     * <p class="note">For better interoperability with other applications, it is recommended
+     * that for any URIs that can be opened, you also support queries on them
+     * containing at least the columns specified by {@link android.provider.OpenableColumns}.
+     * You may also want to support other common columns if you have additional meta-data
+     * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
+     * in {@link android.provider.MediaStore.MediaColumns}.</p>
+     *
+     * @param uri The data in the content provider being queried.
+     * @param mimeTypeFilter The type of data the client desires.  May be
+     * a pattern, such as *\/*, if the caller does not have specific type
+     * requirements; in this case the content provider will pick its best
+     * type matching the pattern.
+     * @param opts Additional options from the client.  The definitions of
+     * these are specific to the content provider being called.
+     * @param signal A signal to cancel the operation in progress, or
+     *            {@code null} if none. For example, if you are downloading a
+     *            file from the network to service a "rw" mode request, you
+     *            should periodically call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether
+     *            the client has canceled the request and abort the download.
+     *
+     * @return Returns a new AssetFileDescriptor from which the client can
+     * read data of the desired type.
+     *
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     * no file associated with the given URI or the mode is invalid.
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not have permission to access the data.
+     * @throws IllegalArgumentException Throws IllegalArgumentException if the
+     * content provider does not support the requested MIME type.
+     *
+     * @see #getStreamTypes(Uri, String)
+     * @see #openAssetFile(Uri, String)
+     * @see ClipDescription#compareMimeTypes(String, String)
+     */
+    public AssetFileDescriptor openTypedAssetFile(
+            Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openTypedAssetFile(uri, mimeTypeFilter, opts);
+    }
+
     /**
      * Interface to write a stream of data to a pipe.  Use with
      * {@link ContentProvider#openPipeHelper}.
@@ -1204,6 +1573,10 @@
          */
         if (mContext == null) {
             mContext = context;
+            if (context != null) {
+                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
+                        Context.APP_OPS_SERVICE);
+            }
             mMyUid = Process.myUid();
             if (info != null) {
                 setReadPermission(info.readPermission);
@@ -1243,15 +1616,6 @@
     }
 
     /**
-     * @hide
-     * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
-     * of the calling package.
-     */
-    public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
-        return call(method, arg, extras);
-    }
-
-    /**
      * Call a provider-defined method.  This can be used to implement
      * interfaces that are cheaper and/or unnatural for a table-like
      * model.
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 8dffac7..cefc27f 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -16,15 +16,22 @@
 
 package android.content;
 
+import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.DeadObjectException;
+import android.os.Handler;
 import android.os.ICancellationSignal;
-import android.os.RemoteException;
+import android.os.Looper;
 import android.os.ParcelFileDescriptor;
-import android.content.res.AssetFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.CloseGuard;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
@@ -43,58 +50,96 @@
  * until you are finished with the data they have returned.
  */
 public class ContentProviderClient {
-    private final IContentProvider mContentProvider;
+    private static final String TAG = "ContentProviderClient";
+
+    @GuardedBy("ContentProviderClient.class")
+    private static Handler sAnrHandler;
+
     private final ContentResolver mContentResolver;
+    private final IContentProvider mContentProvider;
     private final String mPackageName;
     private final boolean mStable;
+
+    private final CloseGuard mGuard = CloseGuard.get();
+
+    private long mAnrTimeout;
+    private NotRespondingRunnable mAnrRunnable;
+
     private boolean mReleased;
 
-    /**
-     * @hide
-     */
-    ContentProviderClient(ContentResolver contentResolver,
-            IContentProvider contentProvider, boolean stable) {
-        mContentProvider = contentProvider;
+    /** {@hide} */
+    ContentProviderClient(
+            ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
         mContentResolver = contentResolver;
+        mContentProvider = contentProvider;
         mPackageName = contentResolver.mPackageName;
         mStable = stable;
+
+        mGuard.open("release");
+    }
+
+    /** {@hide} */
+    public void setDetectNotResponding(long timeoutMillis) {
+        synchronized (ContentProviderClient.class) {
+            mAnrTimeout = timeoutMillis;
+
+            if (timeoutMillis > 0) {
+                if (mAnrRunnable == null) {
+                    mAnrRunnable = new NotRespondingRunnable();
+                }
+                if (sAnrHandler == null) {
+                    sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */);
+                }
+            } else {
+                mAnrRunnable = null;
+            }
+        }
+    }
+
+    private void beforeRemote() {
+        if (mAnrRunnable != null) {
+            sAnrHandler.postDelayed(mAnrRunnable, mAnrTimeout);
+        }
+    }
+
+    private void afterRemote() {
+        if (mAnrRunnable != null) {
+            sAnrHandler.removeCallbacks(mAnrRunnable);
+        }
     }
 
     /** See {@link ContentProvider#query ContentProvider.query} */
     public Cursor query(Uri url, String[] projection, String selection,
             String[] selectionArgs, String sortOrder) throws RemoteException {
-        try {
-            return query(url, projection, selection,  selectionArgs, sortOrder, null);
-        } catch (DeadObjectException e) {
-            if (!mStable) {
-                mContentResolver.unstableProviderDied(mContentProvider);
-            }
-            throw e;
-        }
+        return query(url, projection, selection,  selectionArgs, sortOrder, null);
     }
 
     /** See {@link ContentProvider#query ContentProvider.query} */
-    public Cursor query(Uri url, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
-                    throws RemoteException {
-        ICancellationSignal remoteCancellationSignal = null;
-        if (cancellationSignal != null) {
-            remoteCancellationSignal = mContentProvider.createCancellationSignal();
-            cancellationSignal.setRemote(remoteCancellationSignal);
-        }
+    public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder, CancellationSignal cancellationSignal) throws RemoteException {
+        beforeRemote();
         try {
-            return mContentProvider.query(mPackageName, url, projection, selection,  selectionArgs,
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = mContentProvider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
+            }
+            return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
                     sortOrder, remoteCancellationSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#getType ContentProvider.getType} */
     public String getType(Uri url) throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.getType(url);
         } catch (DeadObjectException e) {
@@ -102,11 +147,14 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.getStreamTypes(url, mimeTypeFilter);
         } catch (DeadObjectException e) {
@@ -114,12 +162,44 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
+        }
+    }
+
+    /** See {@link ContentProvider#canonicalize} */
+    public final Uri canonicalize(Uri url) throws RemoteException {
+        beforeRemote();
+        try {
+            return mContentProvider.canonicalize(mPackageName, url);
+        } catch (DeadObjectException e) {
+            if (!mStable) {
+                mContentResolver.unstableProviderDied(mContentProvider);
+            }
+            throw e;
+        } finally {
+            afterRemote();
+        }
+    }
+
+    /** See {@link ContentProvider#uncanonicalize} */
+    public final Uri uncanonicalize(Uri url) throws RemoteException {
+        beforeRemote();
+        try {
+            return mContentProvider.uncanonicalize(mPackageName, url);
+        } catch (DeadObjectException e) {
+            if (!mStable) {
+                mContentResolver.unstableProviderDied(mContentProvider);
+            }
+            throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#insert ContentProvider.insert} */
-    public Uri insert(Uri url, ContentValues initialValues)
-            throws RemoteException {
+    public Uri insert(Uri url, ContentValues initialValues) throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.insert(mPackageName, url, initialValues);
         } catch (DeadObjectException e) {
@@ -127,11 +207,14 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
     public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.bulkInsert(mPackageName, url, initialValues);
         } catch (DeadObjectException e) {
@@ -139,12 +222,15 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#delete ContentProvider.delete} */
     public int delete(Uri url, String selection, String[] selectionArgs)
             throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
         } catch (DeadObjectException e) {
@@ -152,12 +238,15 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#update ContentProvider.update} */
     public int update(Uri url, ContentValues values, String selection,
             String[] selectionArgs) throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
         } catch (DeadObjectException e) {
@@ -165,6 +254,8 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
@@ -177,13 +268,34 @@
      */
     public ParcelFileDescriptor openFile(Uri url, String mode)
             throws RemoteException, FileNotFoundException {
+        return openFile(url, mode, null);
+    }
+
+    /**
+     * See {@link ContentProvider#openFile ContentProvider.openFile}.  Note that
+     * this <em>does not</em>
+     * take care of non-content: URIs such as file:.  It is strongly recommended
+     * you use the {@link ContentResolver#openFileDescriptor
+     * ContentResolver.openFileDescriptor} API instead.
+     */
+    public ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal)
+            throws RemoteException, FileNotFoundException {
+        beforeRemote();
         try {
-            return mContentProvider.openFile(mPackageName, url, mode);
+            ICancellationSignal remoteSignal = null;
+            if (signal != null) {
+                signal.throwIfCanceled();
+                remoteSignal = mContentProvider.createCancellationSignal();
+                signal.setRemote(remoteSignal);
+            }
+            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
@@ -196,33 +308,71 @@
      */
     public AssetFileDescriptor openAssetFile(Uri url, String mode)
             throws RemoteException, FileNotFoundException {
+        return openAssetFile(url, mode, null);
+    }
+
+    /**
+     * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
+     * Note that this <em>does not</em>
+     * take care of non-content: URIs such as file:.  It is strongly recommended
+     * you use the {@link ContentResolver#openAssetFileDescriptor
+     * ContentResolver.openAssetFileDescriptor} API instead.
+     */
+    public AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal)
+            throws RemoteException, FileNotFoundException {
+        beforeRemote();
         try {
-            return mContentProvider.openAssetFile(mPackageName, url, mode);
+            ICancellationSignal remoteSignal = null;
+            if (signal != null) {
+                signal.throwIfCanceled();
+                remoteSignal = mContentProvider.createCancellationSignal();
+                signal.setRemote(remoteSignal);
+            }
+            return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
     public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
-            String mimeType, Bundle opts)
+            String mimeType, Bundle opts) throws RemoteException, FileNotFoundException {
+        return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
+    }
+
+    /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
+    public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
+            String mimeType, Bundle opts, CancellationSignal signal)
             throws RemoteException, FileNotFoundException {
+        beforeRemote();
         try {
-            return mContentProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
+            ICancellationSignal remoteSignal = null;
+            if (signal != null) {
+                signal.throwIfCanceled();
+                remoteSignal = mContentProvider.createCancellationSignal();
+                signal.setRemote(remoteSignal);
+            }
+            return mContentProvider.openTypedAssetFile(
+                    mPackageName, uri, mimeType, opts, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
             throws RemoteException, OperationApplicationException {
+        beforeRemote();
         try {
             return mContentProvider.applyBatch(mPackageName, operations);
         } catch (DeadObjectException e) {
@@ -230,12 +380,14 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
     /** See {@link ContentProvider#call(String, String, Bundle)} */
-    public Bundle call(String method, String arg, Bundle extras)
-            throws RemoteException {
+    public Bundle call(String method, String arg, Bundle extras) throws RemoteException {
+        beforeRemote();
         try {
             return mContentProvider.call(mPackageName, method, arg, extras);
         } catch (DeadObjectException e) {
@@ -243,6 +395,8 @@
                 mContentResolver.unstableProviderDied(mContentProvider);
             }
             throw e;
+        } finally {
+            afterRemote();
         }
     }
 
@@ -257,6 +411,7 @@
                 throw new IllegalStateException("Already released");
             }
             mReleased = true;
+            mGuard.close();
             if (mStable) {
                 return mContentResolver.releaseProvider(mContentProvider);
             } else {
@@ -265,6 +420,13 @@
         }
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        if (mGuard != null) {
+            mGuard.warnIfOpen();
+        }
+    }
+
     /**
      * Get a reference to the {@link ContentProvider} that is associated with this
      * client. If the {@link ContentProvider} is running in a different process then
@@ -277,4 +439,22 @@
     public ContentProvider getLocalContentProvider() {
         return ContentProvider.coerceToLocalContentProvider(mContentProvider);
     }
+
+    /** {@hide} */
+    public static void releaseQuietly(ContentProviderClient client) {
+        if (client != null) {
+            try {
+                client.release();
+            } catch (Exception ignored) {
+            }
+        }
+    }
+
+    private class NotRespondingRunnable implements Runnable {
+        @Override
+        public void run() {
+            Log.w(TAG, "Detected provider not responding: " + mContentProvider);
+            mContentResolver.appNotRespondingViaProvider(mContentProvider);
+        }
+    }
 }
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 6f822c1..bcf0b63 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -18,22 +18,20 @@
 
 import android.content.res.AssetFileDescriptor;
 import android.database.BulkCursorDescriptor;
-import android.database.BulkCursorNative;
 import android.database.BulkCursorToCursorAdaptor;
 import android.database.Cursor;
 import android.database.CursorToBulkCursorAdaptor;
 import android.database.DatabaseUtils;
-import android.database.IBulkCursor;
 import android.database.IContentObserver;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.RemoteException;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
@@ -227,9 +225,11 @@
                     String callingPkg = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
                     ParcelFileDescriptor fd;
-                    fd = openFile(callingPkg, url, mode);
+                    fd = openFile(callingPkg, url, mode, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -247,9 +247,11 @@
                     String callingPkg = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openAssetFile(callingPkg, url, mode);
+                    fd = openAssetFile(callingPkg, url, mode, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -296,9 +298,11 @@
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mimeType = data.readString();
                     Bundle opts = data.readBundle();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openTypedAssetFile(callingPkg, url, mimeType, opts);
+                    fd = openTypedAssetFile(callingPkg, url, mimeType, opts, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -319,6 +323,30 @@
                     reply.writeStrongBinder(cancellationSignal.asBinder());
                     return true;
                 }
+
+                case CANONICALIZE_TRANSACTION:
+                {
+                    data.enforceInterface(IContentProvider.descriptor);
+                    String callingPkg = data.readString();
+                    Uri url = Uri.CREATOR.createFromParcel(data);
+
+                    Uri out = canonicalize(callingPkg, url);
+                    reply.writeNoException();
+                    Uri.writeToParcel(reply, out);
+                    return true;
+                }
+
+                case UNCANONICALIZE_TRANSACTION:
+                {
+                    data.enforceInterface(IContentProvider.descriptor);
+                    String callingPkg = data.readString();
+                    Uri url = Uri.CREATOR.createFromParcel(data);
+
+                    Uri out = uncanonicalize(callingPkg, url);
+                    reply.writeNoException();
+                    Uri.writeToParcel(reply, out);
+                    return true;
+                }
             }
         } catch (Exception e) {
             DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -538,7 +566,9 @@
         }
     }
 
-    public ParcelFileDescriptor openFile(String callingPkg, Uri url, String mode)
+    @Override
+    public ParcelFileDescriptor openFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -548,6 +578,7 @@
             data.writeString(callingPkg);
             url.writeToParcel(data, 0);
             data.writeString(mode);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
 
             mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
 
@@ -561,7 +592,9 @@
         }
     }
 
-    public AssetFileDescriptor openAssetFile(String callingPkg, Uri url, String mode)
+    @Override
+    public AssetFileDescriptor openAssetFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -571,6 +604,7 @@
             data.writeString(callingPkg);
             url.writeToParcel(data, 0);
             data.writeString(mode);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
 
             mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
 
@@ -629,8 +663,9 @@
         }
     }
 
+    @Override
     public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts) throws RemoteException, FileNotFoundException {
+            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
@@ -640,6 +675,7 @@
             url.writeToParcel(data, 0);
             data.writeString(mimeType);
             data.writeBundle(opts);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
 
             mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0);
 
@@ -673,5 +709,46 @@
         }
     }
 
+    public Uri canonicalize(String callingPkg, Uri url) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        try {
+            data.writeInterfaceToken(IContentProvider.descriptor);
+
+            data.writeString(callingPkg);
+            url.writeToParcel(data, 0);
+
+            mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0);
+
+            DatabaseUtils.readExceptionFromParcel(reply);
+            Uri out = Uri.CREATOR.createFromParcel(reply);
+            return out;
+        } finally {
+            data.recycle();
+            reply.recycle();
+        }
+    }
+
+    public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        try {
+            data.writeInterfaceToken(IContentProvider.descriptor);
+
+            data.writeString(callingPkg);
+            url.writeToParcel(data, 0);
+
+            mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0);
+
+            DatabaseUtils.readExceptionFromParcel(reply);
+            Uri out = Uri.CREATOR.createFromParcel(reply);
+            return out;
+        } finally {
+            data.recycle();
+            reply.recycle();
+        }
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index fefd343..916a6cd 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -16,8 +16,6 @@
 
 package android.content;
 
-import dalvik.system.CloseGuard;
-
 import android.accounts.Account;
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
@@ -45,6 +43,8 @@
 import android.util.EventLog;
 import android.util.Log;
 
+import dalvik.system.CloseGuard;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -55,7 +55,6 @@
 import java.util.List;
 import java.util.Random;
 
-
 /**
  * This class provides applications access to the content model.
  *
@@ -72,7 +71,13 @@
      */
     @Deprecated
     public static final String SYNC_EXTRAS_ACCOUNT = "account";
+
+    /**
+     * If this extra is set to true, the sync request will be scheduled
+     * at the front of the sync request queue and without any delay
+     */
     public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
+
     /**
      * @deprecated instead use
      * {@link #SYNC_EXTRAS_MANUAL}
@@ -104,10 +109,40 @@
      */
     public static final String SYNC_EXTRAS_MANUAL = "force";
 
+    /**
+     * Indicates that this sync is intended to only upload local changes to the server.
+     * For example, this will be set to true if the sync is initiated by a call to
+     * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
+     */
     public static final String SYNC_EXTRAS_UPLOAD = "upload";
+
+    /**
+     * Indicates that the sync adapter should proceed with the delete operations,
+     * even if it determines that there are too many.
+     * See {@link SyncResult#tooManyDeletions}
+     */
     public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
+
+    /**
+     * Indicates that the sync adapter should not proceed with the delete operations,
+     * if it determines that there are too many.
+     * See {@link SyncResult#tooManyDeletions}
+     */
     public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
 
+    /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
+    /** {@hide} User-specified flag for expected upload size. */
+    public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
+
+    /** {@hide} User-specified flag for expected download size. */
+    public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
+
+    /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
+    public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
+
+    /** {@hide} Flag to allow sync to occur on metered network. */
+    public static final String SYNC_EXTRAS_DISALLOW_METERED = "disallow_metered";
+
     /**
      * Set by the SyncManager to request that the SyncAdapter initialize itself for
      * the given account/authority pair. One required initialization step is to
@@ -220,22 +255,29 @@
 
     // Always log queries which take 500ms+; shorter queries are
     // sampled accordingly.
+    private static final boolean ENABLE_CONTENT_SAMPLE = false;
     private static final int SLOW_THRESHOLD_MILLIS = 500;
     private final Random mRandom = new Random();  // guarded by itself
 
     public ContentResolver(Context context) {
         mContext = context != null ? context : ActivityThread.currentApplication();
-        mPackageName = mContext.getBasePackageName();
+        mPackageName = mContext.getOpPackageName();
     }
 
     /** @hide */
     protected abstract IContentProvider acquireProvider(Context c, String name);
-    /** Providing a default implementation of this, to avoid having to change
-     * a lot of other things, but implementations of ContentResolver should
-     * implement it. @hide */
+
+    /**
+     * Providing a default implementation of this, to avoid having to change a
+     * lot of other things, but implementations of ContentResolver should
+     * implement it.
+     *
+     * @hide
+     */
     protected IContentProvider acquireExistingProvider(Context c, String name) {
         return acquireProvider(c, name);
     }
+
     /** @hide */
     public abstract boolean releaseProvider(IContentProvider icp);
     /** @hide */
@@ -245,6 +287,11 @@
     /** @hide */
     public abstract void unstableProviderDied(IContentProvider icp);
 
+    /** @hide */
+    public void appNotRespondingViaProvider(IContentProvider icp) {
+        throw new UnsupportedOperationException("appNotRespondingViaProvider");
+    }
+
     /**
      * Return the MIME type of the given content URL.
      *
@@ -291,7 +338,7 @@
      * content URL can be returned when opened as as stream with
      * {@link #openTypedAssetFileDescriptor}.  Note that the types here are
      * not necessarily a superset of the type returned by {@link #getType} --
-     * many content providers can not return a raw stream for the structured
+     * many content providers cannot return a raw stream for the structured
      * data that they contain.
      *
      * @param url A Uri identifying content (either a list or specific type),
@@ -448,6 +495,9 @@
             if (qCursor != null) {
                 qCursor.close();
             }
+            if (cancellationSignal != null) {
+                cancellationSignal.setRemote(null);
+            }
             if (unstableProvider != null) {
                 releaseUnstableProvider(unstableProvider);
             }
@@ -458,6 +508,88 @@
     }
 
     /**
+     * Transform the given <var>url</var> to a canonical representation of
+     * its referenced resource, which can be used across devices, persisted,
+     * backed up and restored, etc.  The returned Uri is still a fully capable
+     * Uri for use with its content provider, allowing you to do all of the
+     * same content provider operations as with the original Uri --
+     * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc.  The
+     * only difference in behavior between the original and new Uris is that
+     * the content provider may need to do some additional work at each call
+     * using it to resolve it to the correct resource, especially if the
+     * canonical Uri has been moved to a different environment.
+     *
+     * <p>If you are moving a canonical Uri between environments, you should
+     * perform another call to {@link #canonicalize} with that original Uri to
+     * re-canonicalize it for the current environment.  Alternatively, you may
+     * want to use {@link #uncanonicalize} to transform it to a non-canonical
+     * Uri that works only in the current environment but potentially more
+     * efficiently than the canonical representation.</p>
+     *
+     * @param url The {@link Uri} that is to be transformed to a canonical
+     * representation.  Like all resolver calls, the input can be either
+     * a non-canonical or canonical Uri.
+     *
+     * @return Returns the official canonical representation of <var>url</var>,
+     * or null if the content provider does not support a canonical representation
+     * of the given Uri.  Many providers may not support canonicalization of some
+     * or all of their Uris.
+     *
+     * @see #uncanonicalize
+     */
+    public final Uri canonicalize(Uri url) {
+        IContentProvider provider = acquireProvider(url);
+        if (provider == null) {
+            return null;
+        }
+
+        try {
+            return provider.canonicalize(mPackageName, url);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            releaseProvider(provider);
+        }
+    }
+
+    /**
+     * Given a canonical Uri previously generated by {@link #canonicalize}, convert
+     * it to its local non-canonical form.  This can be useful in some cases where
+     * you know that you will only be using the Uri in the current environment and
+     * want to avoid any possible overhead when using it with the content
+     * provider or want to verify that the referenced data exists at all in the
+     * new environment.
+     *
+     * @param url The canonical {@link Uri} that is to be convered back to its
+     * non-canonical form.
+     *
+     * @return Returns the non-canonical representation of <var>url</var>.  This will
+     * return null if data identified by the canonical Uri can not be found in
+     * the current environment; callers must always check for null and deal with
+     * that by appropriately falling back to an alternative.
+     *
+     * @see #canonicalize
+     */
+    public final Uri uncanonicalize(Uri url) {
+        IContentProvider provider = acquireProvider(url);
+        if (provider == null) {
+            return null;
+        }
+
+        try {
+            return provider.uncanonicalize(mPackageName, url);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            releaseProvider(provider);
+        }
+    }
+
+    /**
      * Open a stream on to the content associated with a content URI.  If there
      * is no data associated with the URI, FileNotFoundException is thrown.
      *
@@ -494,7 +626,7 @@
             // with sufficient testing.
             return new FileInputStream(uri.getPath());
         } else {
-            AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r");
+            AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
             try {
                 return fd != null ? fd.createInputStream() : null;
             } catch (IOException e) {
@@ -534,7 +666,7 @@
      */
     public final OutputStream openOutputStream(Uri uri, String mode)
             throws FileNotFoundException {
-        AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode);
+        AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
         try {
             return fd != null ? fd.createOutputStream() : null;
         } catch (IOException e) {
@@ -560,6 +692,15 @@
      *
      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
      * on these schemes.
+     * <p>
+     * If opening with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" mode implies a file on disk that supports
+     * seeking. If possible, always use an exclusive mode to give the underlying
+     * {@link ContentProvider} the most flexibility.
+     * <p>
+     * If you are writing a file, and need to communicate an error to the
+     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
      *
      * @param uri The desired URI to open.
      * @param mode The file mode to use, as per {@link ContentProvider#openFile
@@ -570,9 +711,54 @@
      * file exists under the URI or the mode is invalid.
      * @see #openAssetFileDescriptor(Uri, String)
      */
+    public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
+            throws FileNotFoundException {
+        return openFileDescriptor(uri, mode, null);
+    }
+
+    /**
+     * Open a raw file descriptor to access data under a URI.  This
+     * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
+     * underlying {@link ContentProvider#openFile}
+     * ContentProvider.openFile()} method, so will <em>not</em> work with
+     * providers that return sub-sections of files.  If at all possible,
+     * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
+     * will receive a FileNotFoundException exception if the provider returns a
+     * sub-section of a file.
+     *
+     * <h5>Accepts the following URI schemes:</h5>
+     * <ul>
+     * <li>content ({@link #SCHEME_CONTENT})</li>
+     * <li>file ({@link #SCHEME_FILE})</li>
+     * </ul>
+     *
+     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
+     * on these schemes.
+     * <p>
+     * If opening with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" mode implies a file on disk that supports
+     * seeking. If possible, always use an exclusive mode to give the underlying
+     * {@link ContentProvider} the most flexibility.
+     * <p>
+     * If you are writing a file, and need to communicate an error to the
+     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
+     *
+     * @param uri The desired URI to open.
+     * @param mode The file mode to use, as per {@link ContentProvider#openFile
+     * ContentProvider.openFile}.
+     * @param cancellationSignal A signal to cancel the operation in progress,
+     *         or null if none. If the operation is canceled, then
+     *         {@link OperationCanceledException} will be thrown.
+     * @return Returns a new ParcelFileDescriptor pointing to the file.  You
+     * own this descriptor and are responsible for closing it when done.
+     * @throws FileNotFoundException Throws FileNotFoundException if no
+     * file exists under the URI or the mode is invalid.
+     * @see #openAssetFileDescriptor(Uri, String)
+     */
     public final ParcelFileDescriptor openFileDescriptor(Uri uri,
-            String mode) throws FileNotFoundException {
-        AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode);
+            String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
+        AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
         if (afd == null) {
             return null;
         }
@@ -640,8 +826,64 @@
      * @throws FileNotFoundException Throws FileNotFoundException of no
      * file exists under the URI or the mode is invalid.
      */
+    public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
+            throws FileNotFoundException {
+        return openAssetFileDescriptor(uri, mode, null);
+    }
+
+    /**
+     * Open a raw file descriptor to access data under a URI.  This
+     * interacts with the underlying {@link ContentProvider#openAssetFile}
+     * method of the provider associated with the given URI, to retrieve any file stored there.
+     *
+     * <h5>Accepts the following URI schemes:</h5>
+     * <ul>
+     * <li>content ({@link #SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
+     * <li>file ({@link #SCHEME_FILE})</li>
+     * </ul>
+     * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
+     * <p>
+     * A Uri object can be used to reference a resource in an APK file.  The
+     * Uri should be one of the following formats:
+     * <ul>
+     * <li><code>android.resource://package_name/id_number</code><br/>
+     * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
+     * For example <code>com.example.myapp</code><br/>
+     * <code>id_number</code> is the int form of the ID.<br/>
+     * The easiest way to construct this form is
+     * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
+     * </li>
+     * <li><code>android.resource://package_name/type/name</code><br/>
+     * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
+     * For example <code>com.example.myapp</code><br/>
+     * <code>type</code> is the string form of the resource type.  For example, <code>raw</code>
+     * or <code>drawable</code>.
+     * <code>name</code> is the string form of the resource name.  That is, whatever the file
+     * name was in your res directory, without the type extension.
+     * The easiest way to construct this form is
+     * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
+     * </li>
+     * </ul>
+     *
+     * <p>Note that if this function is called for read-only input (mode is "r")
+     * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
+     * for you with a MIME type of "*\/*".  This allows such callers to benefit
+     * from any built-in data conversion that a provider implements.
+     *
+     * @param uri The desired URI to open.
+     * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
+     * ContentProvider.openAssetFile}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if
+     *            none. If the operation is canceled, then
+     *            {@link OperationCanceledException} will be thrown.
+     * @return Returns a new ParcelFileDescriptor pointing to the file.  You
+     * own this descriptor and are responsible for closing it when done.
+     * @throws FileNotFoundException Throws FileNotFoundException of no
+     * file exists under the URI or the mode is invalid.
+     */
     public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
-            String mode) throws FileNotFoundException {
+            String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
         String scheme = uri.getScheme();
         if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
             if (!"r".equals(mode)) {
@@ -655,11 +897,11 @@
             }
         } else if (SCHEME_FILE.equals(scheme)) {
             ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
-                    new File(uri.getPath()), modeToMode(uri, mode));
+                    new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
             return new AssetFileDescriptor(pfd, 0, -1);
         } else {
             if ("r".equals(mode)) {
-                return openTypedAssetFileDescriptor(uri, "*/*", null);
+                return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
             } else {
                 IContentProvider unstableProvider = acquireUnstableProvider(uri);
                 if (unstableProvider == null) {
@@ -669,8 +911,16 @@
                 AssetFileDescriptor fd = null;
 
                 try {
+                    ICancellationSignal remoteCancellationSignal = null;
+                    if (cancellationSignal != null) {
+                        cancellationSignal.throwIfCanceled();
+                        remoteCancellationSignal = unstableProvider.createCancellationSignal();
+                        cancellationSignal.setRemote(remoteCancellationSignal);
+                    }
+
                     try {
-                        fd = unstableProvider.openAssetFile(mPackageName, uri, mode);
+                        fd = unstableProvider.openAssetFile(
+                                mPackageName, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -684,7 +934,8 @@
                         if (stableProvider == null) {
                             throw new FileNotFoundException("No content provider: " + uri);
                         }
-                        fd = stableProvider.openAssetFile(mPackageName, uri, mode);
+                        fd = stableProvider.openAssetFile(
+                                mPackageName, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -712,6 +963,9 @@
                 } catch (FileNotFoundException e) {
                     throw e;
                 } finally {
+                    if (cancellationSignal != null) {
+                        cancellationSignal.setRemote(null);
+                    }
                     if (stableProvider != null) {
                         releaseProvider(stableProvider);
                     }
@@ -751,8 +1005,45 @@
      * @throws FileNotFoundException Throws FileNotFoundException of no
      * data of the desired type exists under the URI.
      */
+    public final AssetFileDescriptor openTypedAssetFileDescriptor(
+            Uri uri, String mimeType, Bundle opts) throws FileNotFoundException {
+        return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
+    }
+
+    /**
+     * Open a raw file descriptor to access (potentially type transformed)
+     * data from a "content:" URI.  This interacts with the underlying
+     * {@link ContentProvider#openTypedAssetFile} method of the provider
+     * associated with the given URI, to retrieve retrieve any appropriate
+     * data stream for the data stored there.
+     *
+     * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
+     * with "content:" URIs, because content providers are the only facility
+     * with an associated MIME type to ensure that the returned data stream
+     * is of the desired type.
+     *
+     * <p>All text/* streams are encoded in UTF-8.
+     *
+     * @param uri The desired URI to open.
+     * @param mimeType The desired MIME type of the returned data.  This can
+     * be a pattern such as *\/*, which will allow the content provider to
+     * select a type, though there is no way for you to determine what type
+     * it is returning.
+     * @param opts Additional provider-dependent options.
+     * @param cancellationSignal A signal to cancel the operation in progress,
+     *         or null if none. If the operation is canceled, then
+     *         {@link OperationCanceledException} will be thrown.
+     * @return Returns a new ParcelFileDescriptor from which you can read the
+     * data stream from the provider.  Note that this may be a pipe, meaning
+     * you can't seek in it.  The only seek you should do is if the
+     * AssetFileDescriptor contains an offset, to move to that offset before
+     * reading.  You own this descriptor and are responsible for closing it when done.
+     * @throws FileNotFoundException Throws FileNotFoundException of no
+     * data of the desired type exists under the URI.
+     */
     public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
-            String mimeType, Bundle opts) throws FileNotFoundException {
+            String mimeType, Bundle opts, CancellationSignal cancellationSignal)
+            throws FileNotFoundException {
         IContentProvider unstableProvider = acquireUnstableProvider(uri);
         if (unstableProvider == null) {
             throw new FileNotFoundException("No content provider: " + uri);
@@ -761,8 +1052,16 @@
         AssetFileDescriptor fd = null;
 
         try {
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = unstableProvider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
+            }
+
             try {
-                fd = unstableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
+                fd = unstableProvider.openTypedAssetFile(
+                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -776,7 +1075,8 @@
                 if (stableProvider == null) {
                     throw new FileNotFoundException("No content provider: " + uri);
                 }
-                fd = stableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
+                fd = stableProvider.openTypedAssetFile(
+                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -804,6 +1104,9 @@
         } catch (FileNotFoundException e) {
             throw e;
         } finally {
+            if (cancellationSignal != null) {
+                cancellationSignal.setRemote(null);
+            }
             if (stableProvider != null) {
                 releaseProvider(stableProvider);
             }
@@ -866,33 +1169,6 @@
         return res;
     }
 
-    /** @hide */
-    static public int modeToMode(Uri uri, String mode) throws FileNotFoundException {
-        int modeBits;
-        if ("r".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
-        } else if ("w".equals(mode) || "wt".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_TRUNCATE;
-        } else if ("wa".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_APPEND;
-        } else if ("rw".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
-                    | ParcelFileDescriptor.MODE_CREATE;
-        } else if ("rwt".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_TRUNCATE;
-        } else {
-            throw new FileNotFoundException("Bad mode for " + uri + ": "
-                    + mode);
-        }
-        return modeBits;
-    }
-
     /**
      * Inserts a row into a table at the given URL.
      *
@@ -1351,6 +1627,54 @@
     }
 
     /**
+     * Take a persistable Uri permission grant that has been offered. Once
+     * taken, the permission grant will be remembered across device reboots.
+     * Only Uri permissions granted with
+     * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
+     * the grant has already been persisted, taking it again will touch
+     * {@link UriPermission#getPersistedTime()}.
+     *
+     * @see #getPersistedUriPermissions()
+     */
+    public void takePersistableUriPermission(Uri uri, int modeFlags) {
+        try {
+            ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Relinquish a persisted Uri permission grant. The Uri must have been
+     * previously made persistent with
+     * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
+     * grants to the calling package will remain intact.
+     *
+     * @see #getPersistedUriPermissions()
+     */
+    public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+        try {
+            ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Return list of all Uri permission grants that have been persisted for the
+     * calling app. Only persistable grants taken with
+     * {@link #takePersistableUriPermission(Uri, int)} are returned.
+     *
+     * @see #takePersistableUriPermission(Uri, int)
+     * @see #releasePersistableUriPermission(Uri, int)
+     */
+    public List<UriPermission> getPersistedUriPermissions() {
+        try {
+            return ActivityManagerNative.getDefault().getPersistedUriPermissions().getList();
+        } catch (RemoteException e) {
+            throw new RuntimeException("Activity manager has died", e);
+        }
+    }
+
+    /**
      * Start an asynchronous sync operation. If you want to monitor the progress
      * of the sync you may register a SyncObserver. Only values of the following
      * types may be used in the extras bundle:
@@ -1361,6 +1685,8 @@
      * <li>Float</li>
      * <li>Double</li>
      * <li>String</li>
+     * <li>Account</li>
+     * <li>null</li>
      * </ul>
      *
      * @param uri the uri of the provider to sync or null to sync all providers.
@@ -1392,6 +1718,8 @@
      * <li>Float</li>
      * <li>Double</li>
      * <li>String</li>
+     * <li>Account</li>
+     * <li>null</li>
      * </ul>
      *
      * @param account which account should be synced
@@ -1399,10 +1727,30 @@
      * @param extras any extras to pass to the SyncAdapter.
      */
     public static void requestSync(Account account, String authority, Bundle extras) {
-        validateSyncExtrasBundle(extras);
+        if (extras == null) {
+            throw new IllegalArgumentException("Must specify extras.");
+        }
+        SyncRequest request =
+            new SyncRequest.Builder()
+                .setSyncAdapter(account, authority)
+                .setExtras(extras)
+                .syncOnce()
+                .build();
+        requestSync(request);
+    }
+
+    /**
+     * Register a sync with the SyncManager. These requests are built using the
+     * {@link SyncRequest.Builder}.
+     *
+     * @param request The immutable SyncRequest object containing the sync parameters. Use
+     * {@link SyncRequest.Builder} to construct these.
+     */
+    public static void requestSync(SyncRequest request) {
         try {
-            getContentService().requestSync(account, authority, extras);
-        } catch (RemoteException e) {
+            getContentService().sync(request);
+        } catch(RemoteException e) {
+            // Shouldn't happen.
         }
     }
 
@@ -1532,6 +1880,9 @@
      * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
      * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
      * If any are supplied then an {@link IllegalArgumentException} will be thrown.
+     * <p>As of API level 19 this function introduces a default flexibility of ~4% (up to a maximum
+     * of one hour in the day) into the requested period. Use
+     * {@link SyncRequest.Builder#syncPeriodic(long, long)} to set this flexibility manually.
      *
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
@@ -1562,7 +1913,7 @@
             throw new IllegalArgumentException("illegal extras were set");
         }
         try {
-            getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
+             getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
         } catch (RemoteException e) {
             // exception ignored; if this is thrown then it means the runtime is in the midst of
             // being restarted
@@ -1832,6 +2183,7 @@
     private void maybeLogQueryToEventLog(long durationMillis,
                                          Uri uri, String[] projection,
                                          String selection, String sortOrder) {
+        if (!ENABLE_CONTENT_SAMPLE) return;
         int samplePercent = samplePercentForDuration(durationMillis);
         if (samplePercent < 100) {
             synchronized (mRandom) {
@@ -1871,6 +2223,7 @@
 
     private void maybeLogUpdateToEventLog(
         long durationMillis, Uri uri, String operation, String selection) {
+        if (!ENABLE_CONTENT_SAMPLE) return;
         int samplePercent = samplePercentForDuration(durationMillis);
         if (samplePercent < 100) {
             synchronized (mRandom) {
@@ -1935,7 +2288,7 @@
 
     private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
         private final IContentProvider mContentProvider;
-        private boolean mReleaseProviderFlag = false;
+        private boolean mProviderReleased;
 
         ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
             super(pfd);
@@ -1943,18 +2296,10 @@
         }
 
         @Override
-        public void close() throws IOException {
-            if(!mReleaseProviderFlag) {
-                super.close();
+        public void releaseResources() {
+            if (!mProviderReleased) {
                 ContentResolver.this.releaseProvider(mContentProvider);
-                mReleaseProviderFlag = true;
-            }
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            if (!mReleaseProviderFlag) {
-                close();
+                mProviderReleased = true;
             }
         }
     }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5bd28b9..02ccaa5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -35,7 +35,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AttributeSet;
-import android.view.CompatibilityInfoHolder;
+import android.view.DisplayAdjustments;
 import android.view.Display;
 import android.view.WindowManager;
 
@@ -45,7 +45,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.List;
 
 /**
  * Interface to global information about an application environment.  This is
@@ -231,7 +230,15 @@
      * tries to balance such requests from one app vs. the importantance of
      * keeping other apps around.
      */
-    public static final int BIND_VISIBLE = 0x0100;
+    public static final int BIND_VISIBLE = 0x10000000;
+
+    /**
+     * @hide
+     * Flag for {@link #bindService}: Consider this binding to be causing the target
+     * process to be showing UI, so it will be do a UI_HIDDEN memory trim when it goes
+     * away.
+     */
+    public static final int BIND_SHOWING_UI = 0x20000000;
 
     /**
      * Flag for {@link #bindService}: Don't consider the bound service to be
@@ -307,7 +314,7 @@
     }
 
     /**
-     * Remove a {@link ComponentCallbacks} objec that was previously registered
+     * Remove a {@link ComponentCallbacks} object that was previously registered
      * with {@link #registerComponentCallbacks(ComponentCallbacks)}.
      */
     public void unregisterComponentCallbacks(ComponentCallbacks callback) {
@@ -428,6 +435,13 @@
     /** @hide Return the name of the base context this context is derived from. */
     public abstract String getBasePackageName();
 
+    /** @hide Return the package name that should be used for app ops calls from
+     * this context.  This is the same as {@link #getBasePackageName()} except in
+     * cases where system components are loaded into other app processes, in which
+     * case this will be the name of the primary package in that process (so that app
+     * ops uid verification will work with the name). */
+    public abstract String getOpPackageName();
+
     /** Return the full application info for this context's package. */
     public abstract ApplicationInfo getApplicationInfo();
 
@@ -482,7 +496,7 @@
      * is always on in apps targetting Gingerbread (Android 2.3) and below, and
      * off by default in later versions.
      *
-     * @return Returns the single SharedPreferences instance that can be used
+     * @return The single {@link SharedPreferences} instance that can be used
      *         to retrieve and modify the preference values.
      *
      * @see #MODE_PRIVATE
@@ -500,7 +514,7 @@
      * @param name The name of the file to open; can not contain path
      *             separators.
      *
-     * @return FileInputStream Resulting input stream.
+     * @return The resulting {@link FileInputStream}.
      *
      * @see #openFileOutput
      * @see #fileList
@@ -521,7 +535,7 @@
      * {@link #MODE_WORLD_READABLE} and {@link #MODE_WORLD_WRITEABLE} to control
      * permissions.
      *
-     * @return FileOutputStream Resulting output stream.
+     * @return The resulting {@link FileOutputStream}.
      *
      * @see #MODE_APPEND
      * @see #MODE_PRIVATE
@@ -542,8 +556,8 @@
      * @param name The name of the file to delete; can not contain path
      *             separators.
      *
-     * @return True if the file was successfully deleted; else
-     *         false.
+     * @return {@code true} if the file was successfully deleted; else
+     *         {@code false}.
      *
      * @see #openFileInput
      * @see #openFileOutput
@@ -559,7 +573,7 @@
      * @param name The name of the file for which you would like to get
      *          its path.
      *
-     * @return Returns an absolute path to the given file.
+     * @return An absolute path to the given file.
      *
      * @see #openFileOutput
      * @see #getFilesDir
@@ -571,7 +585,7 @@
      * Returns the absolute path to the directory on the filesystem where
      * files created with {@link #openFileOutput} are stored.
      *
-     * @return Returns the path of the directory holding application files.
+     * @return The path of the directory holding application files.
      *
      * @see #openFileOutput
      * @see #getFileStreamPath
@@ -583,7 +597,7 @@
      * Returns the absolute path to the directory on the external filesystem
      * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
      * Environment.getExternalStorageDirectory()}) where the application can
-     * place persistent files it owns.  These files are private to the
+     * place persistent files it owns.  These files are internal to the
      * applications, and not typically visible to the user as media.
      *
      * <p>This is like {@link #getFilesDir()} in that these
@@ -630,9 +644,11 @@
      *
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * private_picture}
-     *
-     * <p>Writing to this path requires the
-     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.</p>
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
+     * permissions are required for the owning application to read or write to
+     * this path. Otherwise, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
+     * or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
      *
      * @param type The type of files directory to return.  May be null for
      * the root of the files directory or one of
@@ -645,7 +661,7 @@
      * {@link android.os.Environment#DIRECTORY_PICTURES}, or
      * {@link android.os.Environment#DIRECTORY_MOVIES}.
      *
-     * @return Returns the path of the directory holding application files
+     * @return The path of the directory holding application files
      * on external storage.  Returns null if external storage is not currently
      * mounted so it could not ensure the path exists; you will need to call
      * this method again when it is available.
@@ -656,18 +672,66 @@
     public abstract File getExternalFilesDir(String type);
 
     /**
-     * Return the directory where this application's OBB files (if there
-     * are any) can be found.  Note if the application does not have any OBB
-     * files, this directory may not exist.
+     * Returns absolute paths to application-specific directories on all
+     * external storage devices where the application can place persistent files
+     * it owns. These files are internal to the application, and not typically
+     * visible to the user as media.
+     * <p>
+     * External storage devices returned here are considered a permanent part of
+     * the device, including both emulated external storage and physical media
+     * slots. This does not include transient devices, such as USB flash drives.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
+     * permissions are required for the owning application to read or write to
+     * these paths.
+     * <p>
+     * The returned paths include any path that would be returned by
+     * {@link #getExternalFilesDir(String)}.
      *
-     * <p>On devices with multiple users (as described by {@link UserManager}),
+     * @see #getExternalFilesDir(String)
+     */
+    public abstract File[] getExternalFilesDirs(String type);
+
+    /**
+     * Return the directory where this application's OBB files (if there are
+     * any) can be found. Note if the application does not have any OBB files,
+     * this directory may not exist.
+     * <p>
+     * On devices with multiple users (as described by {@link UserManager}),
      * multiple users may share the same OBB storage location. Applications
-     * should ensure that multiple instances running under different users
-     * don't interfere with each other.</p>
+     * should ensure that multiple instances running under different users don't
+     * interfere with each other.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
+     * permissions are required for the owning application to read or write to
+     * this path. Otherwise,
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} or
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
      */
     public abstract File getObbDir();
 
     /**
+     * Returns absolute paths to application-specific directories on all
+     * external storage devices where the application's OBB files (if there are
+     * any) can be found. Note if the application does not have any OBB files,
+     * these directories may not exist.
+     * <p>
+     * External storage devices returned here are considered a permanent part of
+     * the device, including both emulated external storage and physical media
+     * slots. This does not include transient devices, such as USB flash drives.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
+     * permissions are required for the owning application to read or write to
+     * this path.
+     * <p>
+     * The returned paths include any path that would be returned by
+     * {@link #getObbDir()}
+     *
+     * @see #getObbDir()
+     */
+    public abstract File[] getObbDirs();
+
+    /**
      * Returns the absolute path to the application specific cache directory
      * on the filesystem. These files will be ones that get deleted first when the
      * device runs low on storage.
@@ -678,7 +742,7 @@
      * for the amount of space you consume with cache files, and prune those
      * files when exceeding that space.</strong>
      *
-     * @return Returns the path of the directory holding application cache files.
+     * @return The path of the directory holding application cache files.
      *
      * @see #openFileOutput
      * @see #getFileStreamPath
@@ -690,7 +754,8 @@
      * Returns the absolute path to the directory on the external filesystem
      * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
      * Environment.getExternalStorageDirectory()} where the application can
-     * place cache files it owns.
+     * place cache files it owns. These files are internal to the application, and
+     * not typically visible to the user as media.
      *
      * <p>This is like {@link #getCacheDir()} in that these
      * files will be deleted when the application is uninstalled, however there
@@ -715,11 +780,14 @@
      * <p>On devices with multiple users (as described by {@link UserManager}),
      * each user has their own isolated external storage. Applications only
      * have access to the external storage for the user they're running as.</p>
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
+     * permissions are required for the owning application to read or write to
+     * this path. Otherwise,
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} or
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
      *
-     * <p>Writing to this path requires the
-     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.</p>
-     *
-     * @return Returns the path of the directory holding application cache files
+     * @return The path of the directory holding application cache files
      * on external storage.  Returns null if external storage is not currently
      * mounted so it could not ensure the path exists; you will need to call
      * this method again when it is available.
@@ -729,6 +797,27 @@
     public abstract File getExternalCacheDir();
 
     /**
+     * Returns absolute paths to application-specific directories on all
+     * external storage devices where the application can place cache files it
+     * owns. These files are internal to the application, and not typically
+     * visible to the user as media.
+     * <p>
+     * External storage devices returned here are considered a permanent part of
+     * the device, including both emulated external storage and physical media
+     * slots. This does not include transient devices, such as USB flash drives.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
+     * permissions are required for the owning application to read or write to
+     * these paths.
+     * <p>
+     * The returned paths include any path that would be returned by
+     * {@link #getExternalCacheDir()}.
+     *
+     * @see #getExternalCacheDir()
+     */
+    public abstract File[] getExternalCacheDirs();
+
+    /**
      * Returns an array of strings naming the private files associated with
      * this Context's application package.
      *
@@ -754,7 +843,7 @@
      * default operation, {@link #MODE_WORLD_READABLE} and
      * {@link #MODE_WORLD_WRITEABLE} to control permissions.
      *
-     * @return Returns a File object for the requested directory.  The directory
+     * @return A {@link File} object for the requested directory.  The directory
      * will have been created if it does not already exist.
      *
      * @see #openFileOutput(String, int)
@@ -820,7 +909,7 @@
      * @param name The name (unique in the application package) of the
      *             database.
      *
-     * @return True if the database was successfully deleted; else false.
+     * @return {@code true} if the database was successfully deleted; else {@code false}.
      *
      * @see #openOrCreateDatabase
      */
@@ -833,7 +922,7 @@
      * @param name The name of the database for which you would like to get
      *          its path.
      *
-     * @return Returns an absolute path to the given database.
+     * @return An absolute path to the given database.
      *
      * @see #openOrCreateDatabase
      */
@@ -911,9 +1000,9 @@
      *
      * @param intent The description of the activity to start.
      *
-     * @throws ActivityNotFoundException
+     * @throws ActivityNotFoundException &nbsp;
      *
-     * @see {@link #startActivity(Intent, Bundle)}
+     * @see #startActivity(Intent, Bundle)
      * @see PackageManager#resolveActivity
      */
     public abstract void startActivity(Intent intent);
@@ -925,7 +1014,7 @@
      * the INTERACT_ACROSS_USERS_FULL permission.
      * @param intent The description of the activity to start.
      * @param user The UserHandle of the user to start this activity for.
-     * @throws ActivityNotFoundException
+     * @throws ActivityNotFoundException &nbsp;
      * @hide
      */
     public void startActivityAsUser(Intent intent, UserHandle user) {
@@ -952,7 +1041,7 @@
      * for how to build the Bundle supplied here; there are no supported definitions
      * for building it manually.
      *
-     * @throws ActivityNotFoundException
+     * @throws ActivityNotFoundException &nbsp;
      *
      * @see #startActivity(Intent)
      * @see PackageManager#resolveActivity
@@ -969,8 +1058,8 @@
      * May be null if there are no options.  See {@link android.app.ActivityOptions}
      * for how to build the Bundle supplied here; there are no supported definitions
      * for building it manually.
-     * @param user The UserHandle of the user to start this activity for.
-     * @throws ActivityNotFoundException
+     * @param userId The UserHandle of the user to start this activity for.
+     * @throws ActivityNotFoundException &nbsp;
      * @hide
      */
     public void startActivityAsUser(Intent intent, Bundle options, UserHandle userId) {
@@ -983,9 +1072,9 @@
      *
      * @param intents An array of Intents to be started.
      *
-     * @throws ActivityNotFoundException
+     * @throws ActivityNotFoundException &nbsp;
      *
-     * @see {@link #startActivities(Intent[], Bundle)}
+     * @see #startActivities(Intent[], Bundle)
      * @see PackageManager#resolveActivity
      */
     public abstract void startActivities(Intent[] intents);
@@ -1009,9 +1098,9 @@
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
      *
-     * @throws ActivityNotFoundException
+     * @throws ActivityNotFoundException &nbsp;
      *
-     * @see {@link #startActivities(Intent[])}
+     * @see #startActivities(Intent[])
      * @see PackageManager#resolveActivity
      */
     public abstract void startActivities(Intent[] intents, Bundle options);
@@ -1037,9 +1126,9 @@
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
      *
-     * @throws ActivityNotFoundException
+     * @throws ActivityNotFoundException &nbsp;
      *
-     * @see {@link #startActivities(Intent[])}
+     * @see #startActivities(Intent[])
      * @see PackageManager#resolveActivity
      */
     public void startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
@@ -1566,9 +1655,11 @@
 
     /**
      * Request that a given application service be started.  The Intent
-     * can either contain the complete class name of a specific service
-     * implementation to start, or an abstract definition through the
-     * action and other fields of the kind of service to start.  If this service
+     * should contain either contain the complete class name of a specific service
+     * implementation to start or a specific package name to target.  If the
+     * Intent is less specified, it will either throw an {@link IllegalArgumentException}
+     * (if the caller targets {@link android.os.Build.VERSION_CODES#KITKAT} or later),
+     * or which of multiple matching services it finds and uses will be undefined.  If this service
      * is not already running, it will be instantiated and started (creating a
      * process for it if needed); if it is running then it remains running.
      *
@@ -1594,10 +1685,9 @@
      * <p>This function will throw {@link SecurityException} if you do not
      * have permission to start the given service.
      *
-     * @param service Identifies the service to be started.  The Intent may
-     *      specify either an explicit component name to start, or a logical
-     *      description (action, category, etc) to match an
-     *      {@link IntentFilter} published by a service.  Additional values
+     * @param service Identifies the service to be started.  The Intent must be either
+     *      fully explicit (supplying a component name) or specify a specific package
+     *      name it is targetted to.  Additional values
      *      may be included in the Intent extras to supply arguments along with
      *      this specific start call.
      *
@@ -1605,7 +1695,7 @@
      * {@link ComponentName} of the actual service that was started is
      * returned; else if the service does not exist null is returned.
      *
-     * @throws SecurityException
+     * @throws SecurityException &nbsp;
      *
      * @see #stopService
      * @see #bindService
@@ -1627,15 +1717,14 @@
      * <p>This function will throw {@link SecurityException} if you do not
      * have permission to stop the given service.
      *
-     * @param service Description of the service to be stopped.  The Intent may
-     *      specify either an explicit component name to start, or a logical
-     *      description (action, category, etc) to match an
-     *      {@link IntentFilter} published by a service.
+     * @param service Description of the service to be stopped.  The Intent must be either
+     *      fully explicit (supplying a component name) or specify a specific package
+     *      name it is targetted to.
      *
      * @return If there is a service matching the given Intent that is already
-     * running, then it is stopped and true is returned; else false is returned.
+     * running, then it is stopped and {@code true} is returned; else {@code false} is returned.
      *
-     * @throws SecurityException
+     * @throws SecurityException &nbsp;
      *
      * @see #startService
      */
@@ -1686,11 +1775,11 @@
      *          {@link #BIND_NOT_FOREGROUND}, {@link #BIND_ABOVE_CLIENT},
      *          {@link #BIND_ALLOW_OOM_MANAGEMENT}, or
      *          {@link #BIND_WAIVE_PRIORITY}.
-     * @return If you have successfully bound to the service, true is returned;
-     *         false is returned if the connection is not made so you will not
+     * @return If you have successfully bound to the service, {@code true} is returned;
+     *         {@code false} is returned if the connection is not made so you will not
      *         receive the service object.
      *
-     * @throws SecurityException
+     * @throws SecurityException &nbsp;
      *
      * @see #unbindService
      * @see #startService
@@ -1742,8 +1831,8 @@
      * @param arguments Additional optional arguments to pass to the
      * instrumentation, or null.
      *
-     * @return Returns true if the instrumentation was successfully started,
-     * else false if it could not be found.
+     * @return {@code true} if the instrumentation was successfully started,
+     * else {@code false} if it could not be found.
      */
     public abstract boolean startInstrumentation(ComponentName className,
             String profileFile, Bundle arguments);
@@ -1929,6 +2018,17 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.view.accessibility.CaptioningManager} for obtaining
+     * captioning properties and listening for changes in captioning
+     * preferences.
+     *
+     * @see #getSystemService
+     * @see android.view.accessibility.CaptioningManager
+     */
+    public static final String CAPTIONING_SERVICE = "captioning";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.app.NotificationManager} for controlling keyguard.
      *
      * @see #getSystemService
@@ -2032,13 +2132,8 @@
     public static final String UPDATE_LOCK_SERVICE = "updatelock";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
-     * android.net.NetworkManagementService} for handling management of
-     * system network services
-     *
+     * Constant for the internal network management service, not really a Context service.
      * @hide
-     * @see #getSystemService
-     * @see android.net.NetworkManagementService
      */
     public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
 
@@ -2218,7 +2313,7 @@
      * and for controlling this device's behavior as a USB device.
      *
      * @see #getSystemService
-     * @see android.harware.usb.UsbManager
+     * @see android.hardware.usb.UsbManager
      */
     public static final String USB_SERVICE = "usb";
 
@@ -2227,7 +2322,7 @@
      * android.hardware.SerialManager} for access to serial ports.
      *
      * @see #getSystemService
-     * @see android.harware.SerialManager
+     * @see android.hardware.SerialManager
      *
      * @hide
      */
@@ -2253,17 +2348,6 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.os.SchedulingPolicyService} for managing scheduling policy.
-     *
-     * @see #getSystemService
-     * @see android.os.SchedulingPolicyService
-     *
-     * @hide
-     */
-    public static final String SCHEDULING_POLICY_SERVICE = "scheduling_policy";
-
-    /**
-     * Use with {@link #getSystemService} to retrieve a
      * {@link android.os.UserManager} for managing users on devices that support multiple users.
      *
      * @see #getSystemService
@@ -2278,12 +2362,39 @@
      *
      * @see #getSystemService
      * @see android.app.AppOpsManager
-     *
-     * @hide
      */
     public static final String APP_OPS_SERVICE = "appops";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.hardware.camera2.CameraManager} for interacting with
+     * camera devices.
+     *
+     * @see #getSystemService
+     * @see android.hardware.camera2.CameraManager
+     */
+    public static final String CAMERA_SERVICE = "camera";
+
+    /**
+     * {@link android.print.PrintManager} for printing and managing
+     * printers and print tasks.
+     *
+     * @see #getSystemService
+     * @see android.print.PrintManager
+     */
+    public static final String PRINT_SERVICE = "print";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.hardware.ConsumerIrManager} for transmitting infrared
+     * signals from the device.
+     *
+     * @see #getSystemService
+     * @see android.hardware.ConsumerIrManager
+     */
+    public static final String CONSUMER_IR_SERVICE = "consumer_ir";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
@@ -2292,7 +2403,7 @@
      * @param uid The user ID being checked against.  A uid of 0 is the root
      * user, which will pass every permission check.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the given
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the given
      * pid/uid is allowed that permission, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      *
@@ -2314,7 +2425,7 @@
      *
      * @param permission The name of the permission being checked.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the calling
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the calling
      * pid/uid is allowed that permission, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      *
@@ -2332,7 +2443,7 @@
      *
      * @param permission The name of the permission being checked.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the calling
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the calling
      * pid/uid is allowed that permission, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      *
@@ -2434,7 +2545,7 @@
      * Remove all permissions to access a particular content provider Uri
      * that were previously added with {@link #grantUriPermission}.  The given
      * Uri will match all previously granted Uris that are the same or a
-     * sub-path of the given Uri.  That is, revoking "content://foo/one" will
+     * sub-path of the given Uri.  That is, revoking "content://foo/target" will
      * revoke both "content://foo/target" and "content://foo/target/sub", but not
      * "content://foo".
      *
@@ -2464,7 +2575,7 @@
      * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION} or
      * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION Intent.FLAG_GRANT_WRITE_URI_PERMISSION}.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the given
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the given
      * pid/uid is allowed to access that uri, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      *
@@ -2487,7 +2598,7 @@
      * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION} or
      * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION Intent.FLAG_GRANT_WRITE_URI_PERMISSION}.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the caller
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the caller
      * is allowed to access that uri, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      *
@@ -2506,7 +2617,7 @@
      * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION} or
      * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION Intent.FLAG_GRANT_WRITE_URI_PERMISSION}.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the caller
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the caller
      * is allowed to access that uri, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      *
@@ -2532,7 +2643,7 @@
      * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION} or
      * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION Intent.FLAG_GRANT_WRITE_URI_PERMISSION}.
      *
-     * @return Returns {@link PackageManager#PERMISSION_GRANTED} if the caller
+     * @return {@link PackageManager#PERMISSION_GRANTED} if the caller
      * is allowed to access that uri or holds one of the given permissions, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      */
@@ -2676,11 +2787,11 @@
      * @param flags Option flags, one of {@link #CONTEXT_INCLUDE_CODE}
      *              or {@link #CONTEXT_IGNORE_SECURITY}.
      *
-     * @return A Context for the application.
+     * @return A {@link Context} for the application.
      *
-     * @throws java.lang.SecurityException
+     * @throws SecurityException &nbsp;
      * @throws PackageManager.NameNotFoundException if there is no application with
-     * the given package name
+     * the given package name.
      */
     public abstract Context createPackageContext(String packageName,
             int flags) throws PackageManager.NameNotFoundException;
@@ -2717,7 +2828,7 @@
      * orientation change), the resources of this context will also change except
      * for those that have been explicitly overridden with a value here.
      *
-     * @return A Context with the given configuration override.
+     * @return A {@link Context} with the given configuration override.
      */
     public abstract Context createConfigurationContext(Configuration overrideConfiguration);
 
@@ -2737,25 +2848,25 @@
      * for whose metrics the Context's resources should be tailored and upon which
      * new windows should be shown.
      *
-     * @return A Context for the display.
+     * @return A {@link Context} for the display.
      */
     public abstract Context createDisplayContext(Display display);
 
     /**
-     * Gets the compatibility info holder for this context.  This information
-     * is provided on a per-application basis and is used to simulate lower density
-     * display metrics for legacy applications.
+     * Gets the display adjustments holder for this context.  This information
+     * is provided on a per-application or activity basis and is used to simulate lower density
+     * display metrics for legacy applications and restricted screen sizes.
      *
      * @param displayId The display id for which to get compatibility info.
      * @return The compatibility info holder, or null if not required by the application.
      * @hide
      */
-    public abstract CompatibilityInfoHolder getCompatibilityInfo(int displayId);
+    public abstract DisplayAdjustments getDisplayAdjustments(int displayId);
 
     /**
      * Indicates whether this Context is restricted.
      *
-     * @return True if this Context is restricted, false otherwise.
+     * @return {@code true} if this Context is restricted, {@code false} otherwise.
      *
      * @see #CONTEXT_RESTRICTED
      */
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 2f1bf8c..a708dad 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -35,7 +35,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.view.CompatibilityInfoHolder;
+import android.view.DisplayAdjustments;
 import android.view.Display;
 
 import java.io.File;
@@ -141,6 +141,12 @@
         return mBase.getBasePackageName();
     }
 
+    /** @hide */
+    @Override
+    public String getOpPackageName() {
+        return mBase.getOpPackageName();
+    }
+
     @Override
     public ApplicationInfo getApplicationInfo() {
         return mBase.getApplicationInfo();
@@ -203,12 +209,22 @@
     public File getExternalFilesDir(String type) {
         return mBase.getExternalFilesDir(type);
     }
-    
+
+    @Override
+    public File[] getExternalFilesDirs(String type) {
+        return mBase.getExternalFilesDirs(type);
+    }
+
     @Override
     public File getObbDir() {
         return mBase.getObbDir();
     }
-    
+
+    @Override
+    public File[] getObbDirs() {
+        return mBase.getObbDirs();
+    }
+
     @Override
     public File getCacheDir() {
         return mBase.getCacheDir();
@@ -220,6 +236,11 @@
     }
 
     @Override
+    public File[] getExternalCacheDirs() {
+        return mBase.getExternalCacheDirs();
+    }
+
+    @Override
     public File getDir(String name, int mode) {
         return mBase.getDir(name, mode);
     }
@@ -646,7 +667,7 @@
 
     /** @hide */
     @Override
-    public CompatibilityInfoHolder getCompatibilityInfo(int displayId) {
-        return mBase.getCompatibilityInfo(displayId);
+    public DisplayAdjustments getDisplayAdjustments(int displayId) {
+        return mBase.getDisplayAdjustments(displayId);
     }
 }
diff --git a/core/java/android/content/IAnonymousSyncAdapter.aidl b/core/java/android/content/IAnonymousSyncAdapter.aidl
new file mode 100644
index 0000000..a80cea3
--- /dev/null
+++ b/core/java/android/content/IAnonymousSyncAdapter.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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 android.content;
+import android.os.Bundle;
+import android.content.ISyncContext;
+
+/**
+ * Interface to define an anonymous service that is extended by developers
+ * in order to perform anonymous syncs (syncs without an Account or Content
+ * Provider specified). See {@link android.content.AbstractThreadedSyncAdapter}.
+ * {@hide}
+ */
+oneway interface IAnonymousSyncAdapter {
+
+    /**
+     * Initiate a sync. SyncAdapter-specific parameters may be specified in
+     * extras, which is guaranteed to not be null.
+     *
+     * @param syncContext the ISyncContext used to indicate the progress of the sync. When
+     *   the sync is finished (successfully or not) ISyncContext.onFinished() must be called.
+     * @param extras SyncAdapter-specific parameters.
+     *
+     */
+    void startSync(ISyncContext syncContext, in Bundle extras);
+
+    /**
+     * Cancel the currently ongoing sync.
+     */
+    void cancelSync(ISyncContext syncContext);
+
+}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 62b79f0..f92a404 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -46,9 +46,11 @@
             throws RemoteException;
     public int update(String callingPkg, Uri url, ContentValues values, String selection,
             String[] selectionArgs) throws RemoteException;
-    public ParcelFileDescriptor openFile(String callingPkg, Uri url, String mode)
+    public ParcelFileDescriptor openFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException;
-    public AssetFileDescriptor openAssetFile(String callingPkg, Uri url, String mode)
+    public AssetFileDescriptor openAssetFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException;
     public ContentProviderResult[] applyBatch(String callingPkg,
             ArrayList<ContentProviderOperation> operations)
@@ -57,10 +59,13 @@
             throws RemoteException;
     public ICancellationSignal createCancellationSignal() throws RemoteException;
 
+    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
+    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;
+
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
     public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts) throws RemoteException, FileNotFoundException;
+            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
     static final String descriptor = "android.content.IContentProvider";
@@ -78,4 +83,6 @@
     static final int GET_STREAM_TYPES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 21;
     static final int OPEN_TYPED_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 22;
     static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
+    static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24;
+    static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25;
 }
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index f956bcf..9ad5a19 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -20,6 +20,7 @@
 import android.content.SyncInfo;
 import android.content.ISyncStatusObserver;
 import android.content.SyncAdapterType;
+import android.content.SyncRequest;
 import android.content.SyncStatusInfo;
 import android.content.PeriodicSync;
 import android.net.Uri;
@@ -54,6 +55,7 @@
             int userHandle);
 
     void requestSync(in Account account, String authority, in Bundle extras);
+    void sync(in SyncRequest request);
     void cancelSync(in Account account, String authority);
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 330b7e5..047f175 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import android.content.pm.ApplicationInfo;
+import android.util.ArraySet;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -33,6 +35,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
+import android.provider.DocumentsContract;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -42,8 +45,8 @@
 import java.io.Serializable;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 
@@ -1150,9 +1153,9 @@
     /**
      * Activity Action: Perform assist action.
      * <p>
-     * Input: {@link #EXTRA_ASSIST_PACKAGE} and {@link #EXTRA_ASSIST_CONTEXT} can provide
-     * additional optional contextual information about where the user was when they requested
-     * the assist.
+     * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT}, can provide
+     * additional optional contextual information about where the user was when they
+     * requested the assist.
      * Output: nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -1161,9 +1164,9 @@
     /**
      * Activity Action: Perform voice assist action.
      * <p>
-     * Input: {@link #EXTRA_ASSIST_PACKAGE} and {@link #EXTRA_ASSIST_CONTEXT} can provide
-     * additional optional contextual information about where the user was when they requested
-     * the voice assist.
+     * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT}, can provide
+     * additional optional contextual information about where the user was when they
+     * requested the voice assist.
      * Output: nothing.
      * @hide
      */
@@ -1171,18 +1174,16 @@
     public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
 
     /**
-     * An optional field on {@link #ACTION_ASSIST}
-     * containing the name of the current foreground application package at the time
-     * the assist was invoked.
+     * An optional field on {@link #ACTION_ASSIST} containing the name of the current foreground
+     * application package at the time the assist was invoked.
      */
     public static final String EXTRA_ASSIST_PACKAGE
             = "android.intent.extra.ASSIST_PACKAGE";
 
     /**
-     * An optional field on {@link #ACTION_ASSIST}
-     * containing additional contextual information supplied by the current
-     * foreground app at the time of the assist request.  This is a {@link Bundle} of
-     * additional data.
+     * An optional field on {@link #ACTION_ASSIST} and containing additional contextual
+     * information supplied by the current foreground app at the time of the assist request.
+     * This is a {@link Bundle} of additional data.
      */
     public static final String EXTRA_ASSIST_CONTEXT
             = "android.intent.extra.ASSIST_CONTEXT";
@@ -1459,7 +1460,7 @@
     /**
      * Broadcast Action: The current time has changed.  Sent every
      * minute.  You can <em>not</em> receive this through components declared
-     * in manifests, only by exlicitly registering for it with
+     * in manifests, only by explicitly registering for it with
      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
      * Context.registerReceiver()}.
      *
@@ -1897,6 +1898,11 @@
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
+     * <p>May include the following extras:
+     * <ul>
+     * <li> {@link #EXTRA_SHUTDOWN_USERSPACE_ONLY} a boolean that is set to true if this
+     * shutdown is only for userspace processes.  If not set, assumed to be false.
+     * </ul>
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
@@ -2441,6 +2447,21 @@
             "android.intent.action.GET_RESTRICTION_ENTRIES";
 
     /**
+     * @hide
+     * Activity to challenge the user for a PIN that was configured when setting up
+     * restrictions. Restrictions include blocking of apps and preventing certain user operations,
+     * controlled by {@link android.os.UserManager#setUserRestrictions(Bundle).
+     * Launch the activity using
+     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check if the
+     * result is {@link android.app.Activity#RESULT_OK} for a successful response to the
+     * challenge.<p/>
+     * Before launching this activity, make sure that there is a PIN in effect, by calling
+     * {@link android.os.UserManager#hasRestrictionsChallenge()}.
+     */
+    public static final String ACTION_RESTRICTIONS_CHALLENGE =
+            "android.intent.action.RESTRICTIONS_CHALLENGE";
+
+    /**
      * Sent the first time a user is starting, to allow system apps to
      * perform one time initialization.  (This will not be seen by third
      * party applications because a newly initialized user does not have any
@@ -2599,6 +2620,54 @@
      */
     public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
 
+    /**
+     * Activity Action: Allow the user to select and open one or more existing
+     * documents. Both read and write access to the documents will be granted
+     * until explicitly revoked by the user.
+     * <p>
+     * Callers can restrict selection to a specific kind of data, such as
+     * photos, by setting one or more MIME types in {@link #EXTRA_MIME_TYPES}.
+     * <p>
+     * If the caller can handle multiple returned items (the user performing
+     * multiple selection), then it can specify {@link #EXTRA_ALLOW_MULTIPLE} to
+     * indicate this.
+     * <p>
+     * Callers must include {@link #CATEGORY_OPENABLE} in the Intent so that
+     * returned URIs can be opened with
+     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
+     * <p>
+     * Output: The URI of the item that was picked. This must be a content: URI
+     * so that any receiver can access it. If multiple documents were selected,
+     * they are returned in {@link #getClipData()}.
+     *
+     * @see DocumentsContract
+     * @see DocumentsContract#getOpenDocuments(Context)
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
+
+    /**
+     * Activity Action: Allow the user to create a new document. Both read and
+     * write access to the document will be granted until explicitly revoked by
+     * the user.
+     * <p>
+     * Callers can provide a hint document name by setting {@link #EXTRA_TITLE},
+     * but the user may change this value before creating the file. Callers can
+     * optionally hint at the MIME type being created by setting
+     * {@link #setType(String)}.
+     * <p>
+     * Callers must include {@link #CATEGORY_OPENABLE} in the Intent so that
+     * returned URIs can be opened with
+     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
+     * <p>
+     * Output: The URI of the item that was created. This must be a content: URI
+     * so that any receiver can access it.
+     *
+     * @see DocumentsContract
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
@@ -2607,7 +2676,7 @@
      * Set if the activity should be an option for the default action
      * (center press) to perform on a piece of data.  Setting this will
      * hide from the user any activities without it set when performing an
-     * action on some data.  Note that this is normal -not- set in the
+     * action on some data.  Note that this is normally -not- set in the
      * Intent when initiating an action -- it is for use in intent filters
      * specified in packages.
      */
@@ -3202,6 +3271,24 @@
     public static final String EXTRA_RESTRICTIONS_INTENT =
             "android.intent.extra.restrictions_intent";
 
+    /**
+     * Extra used to communicate set of acceptable MIME types for
+     * {@link #ACTION_GET_CONTENT} or {@link #ACTION_OPEN_DOCUMENT}. The type of the
+     * extra is <code>ArrayList&lt;String&gt;</code>.
+     */
+    public static final String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
+
+    /**
+     * Optional extra for {@link #ACTION_SHUTDOWN} that allows the sender to qualify that
+     * this shutdown is only for the user space of the system, not a complete shutdown.
+     * When this is true, hardware devices can use this information to determine that
+     * they shouldn't do a complete shutdown of their device since this is not a
+     * complete shutdown down to the kernel, but only user space restarting.
+     * The default if not supplied is false.
+     */
+    public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY
+            = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
@@ -3251,6 +3338,21 @@
     public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;
 
     /**
+     * When combined with {@link #FLAG_GRANT_READ_URI_PERMISSION} and/or
+     * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, the Uri permission grant can be
+     * persisted across device reboots until explicitly revoked with
+     * {@link Context#revokeUriPermission(Uri, int)}. This flag only offers the
+     * grant for possible persisting; the receiving application must call
+     * {@link ContentResolver#takePersistableUriPermission(Uri, int)} to
+     * actually persist.
+     *
+     * @see ContentResolver#takePersistableUriPermission(Uri, int)
+     * @see ContentResolver#releasePersistableUriPermission(Uri, int)
+     * @see ContentResolver#getPersistedUriPermissions()
+     */
+    public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 0x00000040;
+
+    /**
      * If set, the new activity is not kept in the history stack.  As soon as
      * the user navigates away from it, the activity is finished.  This may also
      * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
@@ -3492,6 +3594,12 @@
      */
     public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
     /**
+     * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
+     * They can still propagate results through to later receivers, but they can not prevent
+     * later receivers from seeing the broadcast.
+     */
+    public static final int FLAG_RECEIVER_NO_ABORT = 0x08000000;
+    /**
      * If set, when sending a broadcast <i>before boot has completed</i> only
      * registered receivers will be called -- no BroadcastReceiver components
      * will be launched.  Sticky intent state will be recorded properly even
@@ -3504,14 +3612,14 @@
      *
      * @hide
      */
-    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
+    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x04000000;
     /**
      * Set when this broadcast is for a boot upgrade, a special mode that
      * allows the broadcast to be sent before the system is ready and launches
      * the app process with no providers running in it.
      * @hide
      */
-    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
+    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
 
     /**
      * @hide Flags that can't be changed with PendingIntent.
@@ -3542,7 +3650,7 @@
     private String mPackage;
     private ComponentName mComponent;
     private int mFlags;
-    private HashSet<String> mCategories;
+    private ArraySet<String> mCategories;
     private Bundle mExtras;
     private Rect mSourceBounds;
     private Intent mSelector;
@@ -3567,7 +3675,7 @@
         this.mComponent = o.mComponent;
         this.mFlags = o.mFlags;
         if (o.mCategories != null) {
-            this.mCategories = new HashSet<String>(o.mCategories);
+            this.mCategories = new ArraySet<String>(o.mCategories);
         }
         if (o.mExtras != null) {
             this.mExtras = new Bundle(o.mExtras);
@@ -3595,7 +3703,7 @@
         this.mPackage = o.mPackage;
         this.mComponent = o.mComponent;
         if (o.mCategories != null) {
-            this.mCategories = new HashSet<String>(o.mCategories);
+            this.mCategories = new ArraySet<String>(o.mCategories);
         }
     }
 
@@ -4953,6 +5061,39 @@
     }
 
     /**
+     * Special function for use by the system to resolve service
+     * intents to system apps.  Throws an exception if there are
+     * multiple potential matches to the Intent.  Returns null if
+     * there are no matches.
+     * @hide
+     */
+    public ComponentName resolveSystemService(PackageManager pm, int flags) {
+        if (mComponent != null) {
+            return mComponent;
+        }
+
+        List<ResolveInfo> results = pm.queryIntentServices(this, flags);
+        if (results == null) {
+            return null;
+        }
+        ComponentName comp = null;
+        for (int i=0; i<results.size(); i++) {
+            ResolveInfo ri = results.get(i);
+            if ((ri.serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                continue;
+            }
+            ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,
+                    ri.serviceInfo.name);
+            if (comp != null) {
+                throw new IllegalStateException("Multiple system services handle " + this
+                        + ": " + comp + ", " + foundComp);
+            }
+            comp = foundComp;
+        }
+        return comp;
+    }
+
+    /**
      * Set the general action to be performed.
      *
      * @param action An action name, such as ACTION_VIEW.  Application-specific
@@ -4987,7 +5128,7 @@
      *
      * @see #getData
      * @see #setDataAndNormalize
-     * @see android.net.Intent#normalize
+     * @see android.net.Uri#normalizeScheme()
      */
     public Intent setData(Uri data) {
         mData = data;
@@ -5159,7 +5300,7 @@
      */
     public Intent addCategory(String category) {
         if (mCategories == null) {
-            mCategories = new HashSet<String>();
+            mCategories = new ArraySet<String>();
         }
         mCategories.add(category.intern());
         return this;
@@ -6303,7 +6444,7 @@
         if (other.mCategories != null
                 && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) {
             if (other.mCategories != null) {
-                mCategories = new HashSet<String>(other.mCategories);
+                mCategories = new ArraySet<String>(other.mCategories);
             }
             changes |= FILL_IN_CATEGORIES;
         }
@@ -6574,12 +6715,9 @@
             }
             first = false;
             b.append("cat=[");
-            Iterator<String> i = mCategories.iterator();
-            boolean didone = false;
-            while (i.hasNext()) {
-                if (didone) b.append(",");
-                didone = true;
-                b.append(i.next());
+            for (int i=0; i<mCategories.size(); i++) {
+                if (i > 0) b.append(',');
+                b.append(mCategories.valueAt(i));
             }
             b.append("]");
         }
@@ -6737,8 +6875,8 @@
             uri.append("action=").append(Uri.encode(mAction)).append(';');
         }
         if (mCategories != null) {
-            for (String category : mCategories) {
-                uri.append("category=").append(Uri.encode(category)).append(';');
+            for (int i=0; i<mCategories.size(); i++) {
+                uri.append("category=").append(Uri.encode(mCategories.valueAt(i))).append(';');
             }
         }
         if (mType != null) {
@@ -6806,9 +6944,10 @@
         }
 
         if (mCategories != null) {
-            out.writeInt(mCategories.size());
-            for (String category : mCategories) {
-                out.writeString(category);
+            final int N = mCategories.size();
+            out.writeInt(N);
+            for (int i=0; i<N; i++) {
+                out.writeString(mCategories.valueAt(i));
             }
         } else {
             out.writeInt(0);
@@ -6860,7 +6999,7 @@
 
         int N = in.readInt();
         if (N > 0) {
-            mCategories = new HashSet<String>();
+            mCategories = new ArraySet<String>();
             int i;
             for (i=0; i<N; i++) {
                 mCategories.add(in.readString().intern());
@@ -7039,7 +7178,8 @@
                     // and flags to ourselves to grant.
                     setClipData(target.getClipData());
                     addFlags(target.getFlags()
-                            & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION));
+                            & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION
+                                    | FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
                     return true;
                 } else {
                     return false;
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 5e65b59..5760a5d 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -50,8 +50,8 @@
  * <em>action</em>, <em>data</em>, and <em>categories</em>.  For each of these
  * characteristics you can provide
  * multiple possible matching values (via {@link #addAction},
- * {@link #addDataType}, {@link #addDataScheme} {@link #addDataAuthority},
- * {@link #addDataPath}, and {@link #addCategory}, respectively).
+ * {@link #addDataType}, {@link #addDataScheme}, {@link #addDataSchemeSpecificPart},
+ * {@link #addDataAuthority}, {@link #addDataPath}, and {@link #addCategory}, respectively).
  * For actions, the field
  * will not be tested if no values have been given (treating it as a wildcard);
  * if no data characteristics are specified, however, then the filter will
@@ -106,8 +106,15 @@
  * formal RFC schemes!</em>  You should thus always use lower case letters
  * for your schemes.
  *
+ * <p><strong>Data Scheme Specific Part</strong> matches if any of the given values match
+ * the Intent's data scheme specific part <em>and</em> one of the data schemes in the filter
+ * has matched the Intent, <em>or</em> no scheme specific parts were supplied in the filter.
+ * The Intent scheme specific part is determined by calling
+ * {@link Intent#getData} and {@link android.net.Uri#getSchemeSpecificPart} on that URI.
+ * <em>Note that scheme specific part matching is <b>case sensitive</b>.</em>
+ *
  * <p><strong>Data Authority</strong> matches if any of the given values match
- * the Intent's data authority <em>and</em> one of the data scheme's in the filter
+ * the Intent's data authority <em>and</em> one of the data schemes in the filter
  * has matched the Intent, <em>or</em> no authories were supplied in the filter.
  * The Intent authority is determined by calling
  * {@link Intent#getData} and {@link android.net.Uri#getAuthority} on that URI.
@@ -135,6 +142,7 @@
     private static final String PORT_STR = "port";
     private static final String HOST_STR = "host";
     private static final String AUTH_STR = "auth";
+    private static final String SSP_STR = "ssp";
     private static final String SCHEME_STR = "scheme";
     private static final String TYPE_STR = "type";
     private static final String CAT_STR = "cat";
@@ -164,8 +172,8 @@
     /**
      * The part of a match constant that describes the category of match
      * that occurred.  May be either {@link #MATCH_CATEGORY_EMPTY},
-     * {@link #MATCH_CATEGORY_SCHEME}, {@link #MATCH_CATEGORY_HOST},
-     * {@link #MATCH_CATEGORY_PORT},
+     * {@link #MATCH_CATEGORY_SCHEME}, {@link #MATCH_CATEGORY_SCHEME_SPECIFIC_PART},
+     * {@link #MATCH_CATEGORY_HOST}, {@link #MATCH_CATEGORY_PORT},
      * {@link #MATCH_CATEGORY_PATH}, or {@link #MATCH_CATEGORY_TYPE}.  Higher
      * values indicate a better match.
      */
@@ -210,6 +218,11 @@
      */
     public static final int MATCH_CATEGORY_PATH = 0x0500000;
     /**
+     * The filter matched an intent with the same data URI scheme and
+     * scheme specific part.
+     */
+    public static final int MATCH_CATEGORY_SCHEME_SPECIFIC_PART = 0x0580000;
+    /**
      * The filter matched an intent with the same data MIME type.
      */
     public static final int MATCH_CATEGORY_TYPE = 0x0600000;
@@ -236,6 +249,7 @@
     private final ArrayList<String> mActions;
     private ArrayList<String> mCategories = null;
     private ArrayList<String> mDataSchemes = null;
+    private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
     private ArrayList<AuthorityEntry> mDataAuthorities = null;
     private ArrayList<PatternMatcher> mDataPaths = null;
     private ArrayList<String> mDataTypes = null;
@@ -395,6 +409,9 @@
         if (o.mDataSchemes != null) {
             mDataSchemes = new ArrayList<String>(o.mDataSchemes);
         }
+        if (o.mDataSchemeSpecificParts != null) {
+            mDataSchemeSpecificParts = new ArrayList<PatternMatcher>(o.mDataSchemeSpecificParts);
+        }
         if (o.mDataAuthorities != null) {
             mDataAuthorities = new ArrayList<AuthorityEntry>(o.mDataAuthorities);
         }
@@ -699,6 +716,80 @@
     };
 
     /**
+     * Add a new Intent data "scheme specific part" to match against.  The filter must
+     * include one or more schemes (via {@link #addDataScheme}) for the
+     * scheme specific part to be considered.  If any scheme specific parts are
+     * included in the filter, then an Intent's data must match one of
+     * them.  If no scheme specific parts are included, then only the scheme must match.
+     *
+     * @param ssp Either a raw string that must exactly match the scheme specific part
+     * path, or a simple pattern, depending on <var>type</var>.
+     * @param type Determines how <var>ssp</var> will be compared to
+     * determine a match: either {@link PatternMatcher#PATTERN_LITERAL},
+     * {@link PatternMatcher#PATTERN_PREFIX}, or
+     * {@link PatternMatcher#PATTERN_SIMPLE_GLOB}.
+     *
+     * @see #matchData
+     * @see #addDataScheme
+     */
+    public final void addDataSchemeSpecificPart(String ssp, int type) {
+        addDataSchemeSpecificPart(new PatternMatcher(ssp, type));
+    }
+
+    /** @hide */
+    public final void addDataSchemeSpecificPart(PatternMatcher ssp) {
+        if (mDataSchemeSpecificParts == null) {
+            mDataSchemeSpecificParts = new ArrayList<PatternMatcher>();
+        }
+        mDataSchemeSpecificParts.add(ssp);
+    }
+
+    /**
+     * Return the number of data scheme specific parts in the filter.
+     */
+    public final int countDataSchemeSpecificParts() {
+        return mDataSchemeSpecificParts != null ? mDataSchemeSpecificParts.size() : 0;
+    }
+
+    /**
+     * Return a data scheme specific part in the filter.
+     */
+    public final PatternMatcher getDataSchemeSpecificPart(int index) {
+        return mDataSchemeSpecificParts.get(index);
+    }
+
+    /**
+     * Is the given data scheme specific part included in the filter?  Note that if the
+     * filter does not include any scheme specific parts, false will <em>always</em> be
+     * returned.
+     *
+     * @param data The scheme specific part that is being looked for.
+     *
+     * @return Returns true if the data string matches a scheme specific part listed in the
+     *         filter.
+     */
+    public final boolean hasDataSchemeSpecificPart(String data) {
+        if (mDataSchemeSpecificParts == null) {
+            return false;
+        }
+        final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
+        for (int i = 0; i < numDataSchemeSpecificParts; i++) {
+            final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
+            if (pe.match(data)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return an iterator over the filter's data scheme specific parts.
+     */
+    public final Iterator<PatternMatcher> schemeSpecificPartsIterator() {
+        return mDataSchemeSpecificParts != null ? mDataSchemeSpecificParts.iterator() : null;
+    }
+
+    /**
      * Add a new Intent data authority to match against.  The filter must
      * include one or more schemes (via {@link #addDataScheme}) for the
      * authority to be considered.  If any authorities are
@@ -720,10 +811,15 @@
      * @see #addDataScheme
      */
     public final void addDataAuthority(String host, String port) {
+        if (port != null) port = port.intern();
+        addDataAuthority(new AuthorityEntry(host.intern(), port));
+    }
+
+    /** @hide */
+    public final void addDataAuthority(AuthorityEntry ent) {
         if (mDataAuthorities == null) mDataAuthorities =
                 new ArrayList<AuthorityEntry>();
-        if (port != null) port = port.intern();
-        mDataAuthorities.add(new AuthorityEntry(host.intern(), port));
+        mDataAuthorities.add(ent);
     }
 
     /**
@@ -788,8 +884,13 @@
      * @see #addDataAuthority
      */
     public final void addDataPath(String path, int type) {
+        addDataPath(new PatternMatcher(path.intern(), type));
+    }
+
+    /** @hide */
+    public final void addDataPath(PatternMatcher path) {
         if (mDataPaths == null) mDataPaths = new ArrayList<PatternMatcher>();
-        mDataPaths.add(new PatternMatcher(path.intern(), type));
+        mDataPaths.add(path);
     }
 
     /**
@@ -900,8 +1001,6 @@
     public final int matchData(String type, String scheme, Uri data) {
         final ArrayList<String> types = mDataTypes;
         final ArrayList<String> schemes = mDataSchemes;
-        final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
-        final ArrayList<PatternMatcher> paths = mDataPaths;
 
         int match = MATCH_CATEGORY_EMPTY;
 
@@ -917,20 +1016,34 @@
                 return NO_MATCH_DATA;
             }
 
-            if (authorities != null) {
-                int authMatch = matchDataAuthority(data);
-                if (authMatch >= 0) {
-                    if (paths == null) {
-                        match = authMatch;
-                    } else if (hasDataPath(data.getPath())) {
-                        match = MATCH_CATEGORY_PATH;
+            final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
+            if (schemeSpecificParts != null) {
+                match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
+                        ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
+            }
+            if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
+                // If there isn't any matching ssp, we need to match an authority.
+                final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
+                if (authorities != null) {
+                    int authMatch = matchDataAuthority(data);
+                    if (authMatch >= 0) {
+                        final ArrayList<PatternMatcher> paths = mDataPaths;
+                        if (paths == null) {
+                            match = authMatch;
+                        } else if (hasDataPath(data.getPath())) {
+                            match = MATCH_CATEGORY_PATH;
+                        } else {
+                            return NO_MATCH_DATA;
+                        }
                     } else {
                         return NO_MATCH_DATA;
                     }
-                } else {
-                    return NO_MATCH_DATA;
                 }
             }
+            // If neither an ssp nor an authority matched, we're done.
+            if (match == NO_MATCH_DATA) {
+                return NO_MATCH_DATA;
+            }
         } else {
             // Special case: match either an Intent with no data URI,
             // or with a scheme: URI.  This is to give a convenience for
@@ -1173,6 +1286,23 @@
             serializer.attribute(null, NAME_STR, mDataSchemes.get(i));
             serializer.endTag(null, SCHEME_STR);
         }
+        N = countDataSchemeSpecificParts();
+        for (int i=0; i<N; i++) {
+            serializer.startTag(null, SSP_STR);
+            PatternMatcher pe = mDataSchemeSpecificParts.get(i);
+            switch (pe.getType()) {
+                case PatternMatcher.PATTERN_LITERAL:
+                    serializer.attribute(null, LITERAL_STR, pe.getPath());
+                    break;
+                case PatternMatcher.PATTERN_PREFIX:
+                    serializer.attribute(null, PREFIX_STR, pe.getPath());
+                    break;
+                case PatternMatcher.PATTERN_SIMPLE_GLOB:
+                    serializer.attribute(null, SGLOB_STR, pe.getPath());
+                    break;
+            }
+            serializer.endTag(null, SSP_STR);
+        }
         N = countDataAuthorities();
         for (int i=0; i<N; i++) {
             serializer.startTag(null, AUTH_STR);
@@ -1238,6 +1368,15 @@
                 if (name != null) {
                     addDataScheme(name);
                 }
+            } else if (tagName.equals(SSP_STR)) {
+                String ssp = parser.getAttributeValue(null, LITERAL_STR);
+                if (ssp != null) {
+                    addDataSchemeSpecificPart(ssp, PatternMatcher.PATTERN_LITERAL);
+                } else if ((ssp=parser.getAttributeValue(null, PREFIX_STR)) != null) {
+                    addDataSchemeSpecificPart(ssp, PatternMatcher.PATTERN_PREFIX);
+                } else if ((ssp=parser.getAttributeValue(null, SGLOB_STR)) != null) {
+                    addDataSchemeSpecificPart(ssp, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
             } else if (tagName.equals(AUTH_STR)) {
                 String host = parser.getAttributeValue(null, HOST_STR);
                 String port = parser.getAttributeValue(null, PORT_STR);
@@ -1289,6 +1428,16 @@
                 du.println(sb.toString());
             }
         }
+        if (mDataSchemeSpecificParts != null) {
+            Iterator<PatternMatcher> it = mDataSchemeSpecificParts.iterator();
+            while (it.hasNext()) {
+                PatternMatcher pe = it.next();
+                sb.setLength(0);
+                sb.append(prefix); sb.append("Ssp: \"");
+                        sb.append(pe); sb.append("\"");
+                du.println(sb.toString());
+            }
+        }
         if (mDataAuthorities != null) {
             Iterator<AuthorityEntry> it = mDataAuthorities.iterator();
             while (it.hasNext()) {
@@ -1363,6 +1512,15 @@
         } else {
             dest.writeInt(0);
         }
+        if (mDataSchemeSpecificParts != null) {
+            final int N = mDataSchemeSpecificParts.size();
+            dest.writeInt(N);
+            for (int i=0; i<N; i++) {
+                mDataSchemeSpecificParts.get(i).writeToParcel(dest, flags);
+            }
+        } else {
+            dest.writeInt(0);
+        }
         if (mDataAuthorities != null) {
             final int N = mDataAuthorities.size();
             dest.writeInt(N);
@@ -1376,7 +1534,7 @@
             final int N = mDataPaths.size();
             dest.writeInt(N);
             for (int i=0; i<N; i++) {
-                mDataPaths.get(i).writeToParcel(dest, 0);
+                mDataPaths.get(i).writeToParcel(dest, flags);
             }
         } else {
             dest.writeInt(0);
@@ -1428,14 +1586,21 @@
         }
         int N = source.readInt();
         if (N > 0) {
-            mDataAuthorities = new ArrayList<AuthorityEntry>();
+            mDataSchemeSpecificParts = new ArrayList<PatternMatcher>(N);
+            for (int i=0; i<N; i++) {
+                mDataSchemeSpecificParts.add(new PatternMatcher(source));
+            }
+        }
+        N = source.readInt();
+        if (N > 0) {
+            mDataAuthorities = new ArrayList<AuthorityEntry>(N);
             for (int i=0; i<N; i++) {
                 mDataAuthorities.add(new AuthorityEntry(source));
             }
         }
         N = source.readInt();
         if (N > 0) {
-            mDataPaths = new ArrayList<PatternMatcher>();
+            mDataPaths = new ArrayList<PatternMatcher>(N);
             for (int i=0; i<N; i++) {
                 mDataPaths.add(new PatternMatcher(source));
             }
diff --git a/core/java/android/content/PeriodicSync.java b/core/java/android/content/PeriodicSync.java
index 513a556..b586eec 100644
--- a/core/java/android/content/PeriodicSync.java
+++ b/core/java/android/content/PeriodicSync.java
@@ -22,67 +22,120 @@
 import android.accounts.Account;
 
 /**
- * Value type that contains information about a periodic sync. Is parcelable, making it suitable
- * for passing in an IPC.
+ * Value type that contains information about a periodic sync.
  */
 public class PeriodicSync implements Parcelable {
-    /** The account to be synced */
+    /** The account to be synced. Can be null. */
     public final Account account;
-    /** The authority of the sync */
+    /** The authority of the sync. Can be null. */
     public final String authority;
     /** Any extras that parameters that are to be passed to the sync adapter. */
     public final Bundle extras;
-    /** How frequently the sync should be scheduled, in seconds. */
+    /** How frequently the sync should be scheduled, in seconds. Kept around for API purposes. */
     public final long period;
+    /**
+     * {@hide}
+     * How much flexibility can be taken in scheduling the sync, in seconds.
+     */
+    public final long flexTime;
 
-    /** Creates a new PeriodicSync, copying the Bundle */
-    public PeriodicSync(Account account, String authority, Bundle extras, long period) {
+      /**
+       * Creates a new PeriodicSync, copying the Bundle. SM no longer uses this ctor - kept around
+       * becuse it is part of the API.
+       * Note - even calls to the old API will not use this ctor, as
+       * they are given a default flex time.
+       */
+    public PeriodicSync(Account account, String authority, Bundle extras, long periodInSeconds) {
+        this.account = account;
+        this.authority = authority;
+        if (extras == null) {
+            this.extras = new Bundle();
+        } else {
+            this.extras = new Bundle(extras);
+        }
+        this.period = periodInSeconds;
+        // Initialise to a sane value.
+        this.flexTime = 0L;
+    }
+
+    /**
+     * {@hide}
+     * Create a copy of a periodic sync.
+     */
+    public PeriodicSync(PeriodicSync other) {
+        this.account = other.account;
+        this.authority = other.authority;
+        this.extras = new Bundle(other.extras);
+        this.period = other.period;
+        this.flexTime = other.flexTime;
+    }
+
+    /**
+     * {@hide}
+     * A PeriodicSync for a sync with a specified provider.
+     */
+    public PeriodicSync(Account account, String authority, Bundle extras,
+            long period, long flexTime) {
         this.account = account;
         this.authority = authority;
         this.extras = new Bundle(extras);
         this.period = period;
+        this.flexTime = flexTime;
     }
 
+    private PeriodicSync(Parcel in) {
+        this.account = in.readParcelable(null);
+        this.authority = in.readString();
+        this.extras = in.readBundle();
+        this.period = in.readLong();
+        this.flexTime = in.readLong();
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
-        account.writeToParcel(dest, flags);
+        dest.writeParcelable(account, flags);
         dest.writeString(authority);
         dest.writeBundle(extras);
         dest.writeLong(period);
+        dest.writeLong(flexTime);
     }
 
     public static final Creator<PeriodicSync> CREATOR = new Creator<PeriodicSync>() {
+        @Override
         public PeriodicSync createFromParcel(Parcel source) {
-            return new PeriodicSync(Account.CREATOR.createFromParcel(source),
-                    source.readString(), source.readBundle(), source.readLong());
+            return new PeriodicSync(source);
         }
 
+        @Override
         public PeriodicSync[] newArray(int size) {
             return new PeriodicSync[size];
         }
     };
 
+    @Override
     public boolean equals(Object o) {
         if (o == this) {
             return true;
         }
-
         if (!(o instanceof PeriodicSync)) {
             return false;
         }
-
         final PeriodicSync other = (PeriodicSync) o;
-
         return account.equals(other.account)
-                && authority.equals(other.authority)
-                && period == other.period
-                && syncExtrasEquals(extras, other.extras);
+            && authority.equals(other.authority)
+            && period == other.period
+            && syncExtrasEquals(extras, other.extras);
     }
 
-    /** {@hide} */
+    /**
+     * Periodic sync extra comparison function.
+     * {@hide}
+     */
     public static boolean syncExtrasEquals(Bundle b1, Bundle b2) {
         if (b1.size() != b2.size()) {
             return false;
@@ -100,4 +153,12 @@
         }
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "account: " + account +
+               ", authority: " + authority +
+               ". period: " + period + "s " +
+               ", flex: " + flexTime;
+    }
 }
diff --git a/core/java/android/content/SyncRequest.aidl b/core/java/android/content/SyncRequest.aidl
new file mode 100644
index 0000000..8321fac
--- /dev/null
+++ b/core/java/android/content/SyncRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.content;
+
+parcelable SyncRequest;
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
new file mode 100644
index 0000000..d4e0c2a
--- /dev/null
+++ b/core/java/android/content/SyncRequest.java
@@ -0,0 +1,622 @@
+/*
+ * 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 android.content;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class SyncRequest implements Parcelable {
+    private static final String TAG = "SyncRequest";
+    /** Account to pass to the sync adapter. May be null. */
+    private final Account mAccountToSync;
+    /** Authority string that corresponds to a ContentProvider. */
+    private final String mAuthority;
+    /** Sync service identifier. May be null.*/
+    private final ComponentName mComponentInfo;
+    /** Bundle containing user info as well as sync settings. */
+    private final Bundle mExtras;
+    /** Disallow this sync request on metered networks. */
+    private final boolean mDisallowMetered;
+    /**
+     * Anticipated upload size in bytes.
+     * TODO: Not yet used - we put this information into the bundle for simplicity.
+     */
+    private final long mTxBytes;
+    /**
+     * Anticipated download size in bytes.
+     * TODO: Not yet used - we put this information into the bundle.
+     */
+    private final long mRxBytes;
+    /**
+     * Amount of time before {@link #mSyncRunTimeSecs} from which the sync may optionally be
+     * started.
+     */
+    private final long mSyncFlexTimeSecs;
+    /**
+     * Specifies a point in the future at which the sync must have been scheduled to run.
+     */
+    private final long mSyncRunTimeSecs;
+    /** Periodic versus one-off. */
+    private final boolean mIsPeriodic;
+    /** Service versus provider. */
+    private final boolean mIsAuthority;
+    /** Sync should be run in lieu of other syncs. */
+    private final boolean mIsExpedited;
+
+    /**
+     * {@hide}
+     * @return whether this sync is periodic or one-time. A Sync Request must be
+     *         either one of these or an InvalidStateException will be thrown in
+     *         Builder.build().
+     */
+    public boolean isPeriodic() {
+        return mIsPeriodic;
+    }
+
+    /**
+     * {@hide}
+     * @return whether this is an expedited sync.
+     */
+    public boolean isExpedited() {
+        return mIsExpedited;
+    }
+
+    /**
+     * {@hide}
+     * @return true if this sync uses an account/authority pair, or false if this sync is bound to
+     * a Sync Service.
+     */
+    public boolean hasAuthority() {
+        return mIsAuthority;
+    }
+
+    /**
+     * {@hide}
+     * @return account object for this sync.
+     * @throws IllegalArgumentException if this function is called for a request that does not
+     * specify an account/provider authority.
+     */
+    public Account getAccount() {
+        if (!hasAuthority()) {
+            throw new IllegalArgumentException("Cannot getAccount() for a sync that does not"
+                    + "specify an authority.");
+        }
+        return mAccountToSync;
+    }
+
+    /**
+     * {@hide}
+     * @return provider for this sync.
+     * @throws IllegalArgumentException if this function is called for a request that does not
+     * specify an account/provider authority.
+     */
+    public String getProvider() {
+        if (!hasAuthority()) {
+            throw new IllegalArgumentException("Cannot getProvider() for a sync that does not"
+                    + "specify a provider.");
+        }
+        return mAuthority;
+    }
+
+    /**
+     * {@hide}
+     * Retrieve bundle for this SyncRequest. Will not be null.
+     */
+    public Bundle getBundle() {
+        return mExtras;
+    }
+
+    /**
+     * {@hide}
+     * @return the earliest point in time that this sync can be scheduled.
+     */
+    public long getSyncFlexTime() {
+        return mSyncFlexTimeSecs;
+    }
+
+    /**
+     * {@hide}
+     * @return the last point in time at which this sync must scheduled.
+     */
+    public long getSyncRunTime() {
+        return mSyncRunTimeSecs;
+    }
+
+    public static final Creator<SyncRequest> CREATOR = new Creator<SyncRequest>() {
+
+        @Override
+        public SyncRequest createFromParcel(Parcel in) {
+            return new SyncRequest(in);
+        }
+
+        @Override
+        public SyncRequest[] newArray(int size) {
+            return new SyncRequest[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeBundle(mExtras);
+        parcel.writeLong(mSyncFlexTimeSecs);
+        parcel.writeLong(mSyncRunTimeSecs);
+        parcel.writeInt((mIsPeriodic ? 1 : 0));
+        parcel.writeInt((mDisallowMetered ? 1 : 0));
+        parcel.writeLong(mTxBytes);
+        parcel.writeLong(mRxBytes);
+        parcel.writeInt((mIsAuthority ? 1 : 0));
+        parcel.writeInt((mIsExpedited? 1 : 0));
+        if (mIsAuthority) {
+            parcel.writeParcelable(mAccountToSync, flags);
+            parcel.writeString(mAuthority);
+        } else {
+            parcel.writeParcelable(mComponentInfo, flags);
+        }
+    }
+
+    private SyncRequest(Parcel in) {
+        mExtras = in.readBundle();
+        mSyncFlexTimeSecs = in.readLong();
+        mSyncRunTimeSecs = in.readLong();
+        mIsPeriodic = (in.readInt() != 0);
+        mDisallowMetered = (in.readInt() != 0);
+        mTxBytes = in.readLong();
+        mRxBytes = in.readLong();
+        mIsAuthority = (in.readInt() != 0);
+        mIsExpedited = (in.readInt() != 0);
+        if (mIsAuthority) {
+            mComponentInfo = null;
+            mAccountToSync = in.readParcelable(null);
+            mAuthority = in.readString();
+        } else {
+            mComponentInfo = in.readParcelable(null);
+            mAccountToSync = null;
+            mAuthority = null;
+        }
+    }
+
+    /** {@hide} Protected ctor to instantiate anonymous SyncRequest. */
+    protected SyncRequest(SyncRequest.Builder b) {
+        mSyncFlexTimeSecs = b.mSyncFlexTimeSecs;
+        mSyncRunTimeSecs = b.mSyncRunTimeSecs;
+        mAccountToSync = b.mAccount;
+        mAuthority = b.mAuthority;
+        mComponentInfo = b.mComponentName;
+        mIsPeriodic = (b.mSyncType == Builder.SYNC_TYPE_PERIODIC);
+        mIsAuthority = (b.mSyncTarget == Builder.SYNC_TARGET_ADAPTER);
+        mIsExpedited = b.mExpedited;
+        mExtras = new Bundle(b.mCustomExtras);
+        // For now we merge the sync config extras & the custom extras into one bundle.
+        // TODO: pass the configuration extras through separately.
+        mExtras.putAll(b.mSyncConfigExtras);
+        mDisallowMetered = b.mDisallowMetered;
+        mTxBytes = b.mTxBytes;
+        mRxBytes = b.mRxBytes;
+    }
+
+    /**
+     * Builder class for a {@link SyncRequest}. As you build your SyncRequest this class will also
+     * perform validation.
+     */
+    public static class Builder {
+        /** Unknown sync type. */
+        private static final int SYNC_TYPE_UNKNOWN = 0;
+        /** Specify that this is a periodic sync. */
+        private static final int SYNC_TYPE_PERIODIC = 1;
+        /** Specify that this is a one-time sync. */
+        private static final int SYNC_TYPE_ONCE = 2;
+        /** Unknown sync target. */
+        private static final int SYNC_TARGET_UNKNOWN = 0;
+        /** Specify that this is an anonymous sync. */
+        private static final int SYNC_TARGET_SERVICE = 1;
+        /** Specify that this is a sync with a provider. */
+        private static final int SYNC_TARGET_ADAPTER = 2;
+        /** Earliest point of displacement into the future at which this sync can occur. */
+        private long mSyncFlexTimeSecs;
+        /** Latest point of displacement into the future at which this sync must occur. */
+        private long mSyncRunTimeSecs;
+        /**
+         * Sync configuration information - custom user data explicitly provided by the developer.
+         * This data is handed over to the sync operation.
+         */
+        private Bundle mCustomExtras;
+        /**
+         * Sync system configuration -  used to store system sync configuration. Corresponds to
+         * ContentResolver.SYNC_EXTRAS_* flags.
+         * TODO: Use this instead of dumping into one bundle. Need to decide if these flags should
+         * 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.
+         */
+        private int mSyncType = SYNC_TYPE_UNKNOWN;
+        /** Whether this will go to a sync adapter or to a sync service. */
+        private int mSyncTarget = SYNC_TARGET_UNKNOWN;
+        /** Whether this is a user-activated sync. */
+        private boolean mIsManual;
+        /**
+         * Whether to retry this one-time sync if the sync fails. Not valid for
+         * periodic syncs. See {@link ContentResolver#SYNC_EXTRAS_DO_NOT_RETRY}.
+         */
+        private boolean mNoRetry;
+        /**
+         * Whether to respect back-off for this one-time sync. Not valid for
+         * periodic syncs. See
+         * {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF};
+         */
+        private boolean mIgnoreBackoff;
+
+        /** Ignore sync system settings and perform sync anyway. */
+        private boolean mIgnoreSettings;
+
+        /** This sync will run in preference to other non-expedited syncs. */
+        private boolean mExpedited;
+
+        /**
+         * The sync component that contains the sync logic if this is a provider-less sync,
+         * otherwise null.
+         */
+        private ComponentName mComponentName;
+        /**
+         * The Account object that together with an Authority name define the SyncAdapter (if
+         * this sync is bound to a provider), otherwise null.
+         */
+        private Account mAccount;
+        /**
+         * The Authority name that together with an Account define the SyncAdapter (if
+         * this sync is bound to a provider), otherwise null.
+         */
+        private String mAuthority;
+
+        public Builder() {
+        }
+
+        /**
+         * Request that a sync occur immediately.
+         *
+         * Example
+         * <pre>
+         *     SyncRequest.Builder builder = (new SyncRequest.Builder()).syncOnce();
+         * </pre>
+         */
+        public Builder syncOnce() {
+            if (mSyncType != SYNC_TYPE_UNKNOWN) {
+                throw new IllegalArgumentException("Sync type has already been defined.");
+            }
+            mSyncType = SYNC_TYPE_ONCE;
+            setupInterval(0, 0);
+            return this;
+        }
+
+        /**
+         * Build a periodic sync. Either this or syncOnce() <b>must</b> be called for this builder.
+         * Syncs are identified by target {@link android.provider}/{@link android.accounts.Account}
+         * and by the contents of the extras bundle.
+         * You cannot reuse the same builder for one-time syncs (by calling this function) after
+         * having specified a periodic sync. If you do, an <code>IllegalArgumentException</code>
+         * will be thrown.
+         *
+         * Example usage.
+         *
+         * <pre>
+         *     Request a periodic sync every 5 hours with 20 minutes of flex.
+         *     SyncRequest.Builder builder =
+         *         (new SyncRequest.Builder()).syncPeriodic(5 * HOUR_IN_SECS, 20 * MIN_IN_SECS);
+         *
+         *     Schedule a periodic sync every hour at any point in time during that hour.
+         *     SyncRequest.Builder builder =
+         *         (new SyncRequest.Builder()).syncPeriodic(1 * HOUR_IN_SECS, 1 * HOUR_IN_SECS);
+         * </pre>
+         *
+         * N.B.: Periodic syncs are not allowed to have any of
+         * {@link ContentResolver#SYNC_EXTRAS_DO_NOT_RETRY},
+         * {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF},
+         * {@link ContentResolver#SYNC_EXTRAS_IGNORE_SETTINGS},
+         * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE},
+         * {@link ContentResolver#SYNC_EXTRAS_FORCE},
+         * {@link ContentResolver#SYNC_EXTRAS_EXPEDITED},
+         * {@link ContentResolver#SYNC_EXTRAS_MANUAL}
+         * set to true. If any are supplied then an <code>IllegalArgumentException</code> will
+         * be thrown.
+         *
+         * @param pollFrequency the amount of time in seconds that you wish
+         *            to elapse between periodic syncs.
+         * @param beforeSeconds the amount of flex time in seconds before
+         *            {@code pollFrequency} that you permit for the sync to take
+         *            place. Must be less than {@code pollFrequency}.
+         */
+        public Builder syncPeriodic(long pollFrequency, long beforeSeconds) {
+            if (mSyncType != SYNC_TYPE_UNKNOWN) {
+                throw new IllegalArgumentException("Sync type has already been defined.");
+            }
+            mSyncType = SYNC_TYPE_PERIODIC;
+            setupInterval(pollFrequency, beforeSeconds);
+            return this;
+        }
+
+        /** {@hide} */
+        private void setupInterval(long at, long before) {
+            if (before > at) {
+                throw new IllegalArgumentException("Specified run time for the sync must be" +
+                    " after the specified flex time.");
+            }
+            mSyncRunTimeSecs = at;
+            mSyncFlexTimeSecs = before;
+        }
+
+        /**
+         * {@hide}
+         * Developer can provide insight into their payload size; optional. -1 specifies unknown,
+         * so that you are not restricted to defining both fields.
+         *
+         * @param rxBytes Bytes expected to be downloaded.
+         * @param txBytes Bytes expected to be uploaded.
+         */
+        public Builder setTransferSize(long rxBytes, long txBytes) {
+            mRxBytes = rxBytes;
+            mTxBytes = txBytes;
+            return this;
+        }
+
+        /**
+         * @see android.net.ConnectivityManager#isActiveNetworkMetered()
+         * @param disallow true to enforce that this transfer not occur on metered networks.
+         *                 Default false.
+         */
+        public Builder setDisallowMetered(boolean disallow) {
+            mDisallowMetered = disallow;
+            return this;
+        }
+
+        /**
+         * Specify an authority and account for this transfer.
+         *
+         * @param authority String identifying which content provider to sync.
+         * @param account Account to sync. Can be null unless this is a periodic sync.
+         */
+        public Builder setSyncAdapter(Account account, String authority) {
+            if (mSyncTarget != SYNC_TARGET_UNKNOWN) {
+                throw new IllegalArgumentException("Sync target has already been defined.");
+            }
+            mSyncTarget = SYNC_TARGET_ADAPTER;
+            mAccount = account;
+            mAuthority = authority;
+            mComponentName = null;
+            return this;
+        }
+
+        /**
+         * Optional developer-provided extras handed back in
+         * {@link AbstractThreadedSyncAdapter#onPerformSync(Account, Bundle, String,
+         * ContentProviderClient, SyncResult)} occurs. This bundle is copied into the SyncRequest
+         * returned by {@link #build()}.
+         *
+         * Example:
+         * <pre>
+         *   String[] syncItems = {"dog", "cat", "frog", "child"};
+         *   SyncRequest.Builder builder =
+         *     new SyncRequest.Builder()
+         *       .setSyncAdapter(dummyAccount, dummyProvider)
+         *       .syncOnce(5 * MINUTES_IN_SECS);
+         *
+         *   for (String syncData : syncItems) {
+         *     Bundle extras = new Bundle();
+         *     extras.setString("data", syncData);
+         *     builder.setExtras(extras);
+         *     ContentResolver.sync(builder.build()); // Each sync() request is for a unique sync.
+         *   }
+         * </pre>
+         * Only values of the following types may be used in the extras bundle:
+         * <ul>
+         * <li>Integer</li>
+         * <li>Long</li>
+         * <li>Boolean</li>
+         * <li>Float</li>
+         * <li>Double</li>
+         * <li>String</li>
+         * <li>Account</li>
+         * <li>null</li>
+         * </ul>
+         * If any data is present in the bundle not of this type, build() will
+         * throw a runtime exception.
+         *
+         * @param bundle extras bundle to set.
+         */
+        public Builder setExtras(Bundle bundle) {
+            mCustomExtras = bundle;
+            return this;
+        }
+
+        /**
+         * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_DO_NOT_RETRY}.
+         *
+         * A one-off sync operation that fails will be retried with exponential back-off unless
+         * this is set to false. Not valid for periodic sync and will throw an
+         * <code>IllegalArgumentException</code> in build().
+         *
+         * @param noRetry true to not retry a failed sync. Default false.
+         */
+        public Builder setNoRetry(boolean noRetry) {
+            mNoRetry = noRetry;
+            return this;
+        }
+
+        /**
+         * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_IGNORE_SETTINGS}.
+         *
+         * A sync can specify that system sync settings be ignored (user has turned sync off). Not
+         * valid for periodic sync and will throw an <code>IllegalArgumentException</code> in
+         * {@link #build()}.
+         *
+         * @param ignoreSettings true to ignore the sync automatically settings. Default false.
+         */
+        public Builder setIgnoreSettings(boolean ignoreSettings) {
+            mIgnoreSettings = ignoreSettings;
+            return this;
+        }
+
+        /**
+         * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF}.
+         *
+         * Force the sync scheduling process to ignore any back-off that was the result of a failed
+         * sync, as well as to invalidate any {@link SyncResult#delayUntil} value that may have
+         * been set by the adapter. Successive failures will not honor this flag. Not valid for
+         * periodic sync and will throw an <code>IllegalArgumentException</code> in
+         * {@link #build()}.
+         *
+         * @param ignoreBackoff ignore back-off settings. Default false.
+         */
+        public Builder setIgnoreBackoff(boolean ignoreBackoff) {
+            mIgnoreBackoff = ignoreBackoff;
+            return this;
+        }
+
+        /**
+         * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_MANUAL}.
+         *
+         * A manual sync is functionally equivalent to calling {@link #setIgnoreBackoff(boolean)}
+         * and {@link #setIgnoreSettings(boolean)}. Not valid for periodic sync and will throw an
+         * <code>IllegalArgumentException</code> in {@link #build()}.
+         *
+         * @param isManual User-initiated sync or not. Default false.
+         */
+        public Builder setManual(boolean isManual) {
+            mIsManual = isManual;
+            return this;
+        }
+
+        /**
+         * An expedited sync runs immediately and will preempt another non-expedited running sync.
+         *
+         * Not valid for periodic sync and will throw an <code>IllegalArgumentException</code> in
+         * {@link #build()}.
+         *
+         * @param expedited whether to run expedited. Default false.
+         */
+        public Builder setExpedited(boolean expedited) {
+            mExpedited = expedited;
+            return this;
+        }
+
+        /**
+         * {@hide}
+         * @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.
+         *
+         * @return a SyncRequest with the information contained within this
+         *         builder.
+         */
+        public SyncRequest build() {
+            if (mCustomExtras == null) {
+                mCustomExtras = new Bundle();
+            }
+            // Validate the extras bundle
+            ContentResolver.validateSyncExtrasBundle(mCustomExtras);
+            // Combine builder extra flags into the config bundle.
+            mSyncConfigExtras = new Bundle();
+            if (mIgnoreBackoff) {
+                mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
+            }
+            if (mDisallowMetered) {
+                mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, true);
+            }
+            if (mIgnoreSettings) {
+                mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+            }
+            if (mNoRetry) {
+                mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
+            }
+            if (mExpedited) {
+                mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+            }
+            if (mIsManual) {
+                mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, 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.
+                validatePeriodicExtras(mCustomExtras);
+                validatePeriodicExtras(mSyncConfigExtras);
+                // Verify that account and provider are not null.
+                if (mAccount == null) {
+                    throw new IllegalArgumentException("Account must not be null for periodic"
+                            + " sync.");
+                }
+                if (mAuthority == null) {
+                    throw new IllegalArgumentException("Authority must not be null for periodic"
+                            + " sync.");
+                }
+            } else if (mSyncType == SYNC_TYPE_UNKNOWN) {
+                throw new IllegalArgumentException("Must call either syncOnce() or syncPeriodic()");
+            }
+            // Ensure that a target for the sync has been set.
+            if (mSyncTarget == SYNC_TARGET_UNKNOWN) {
+                throw new IllegalArgumentException("Must specify an adapter with "
+                        + "setSyncAdapter(Account, String");
+            }
+            return new SyncRequest(this);
+        }
+
+        /**
+         * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
+         * extras were set for a periodic sync.
+         *
+         * @param extras bundle to validate.
+         */
+        private void validatePeriodicExtras(Bundle extras) {
+            if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
+                    || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
+                    || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
+                    || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
+                    || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
+                    || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
+                    || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
+                throw new IllegalArgumentException("Illegal extras were set");
+            }
+        }
+    }
+}
diff --git a/core/java/android/content/SyncResult.java b/core/java/android/content/SyncResult.java
index 8b0afbd..4f86af9 100644
--- a/core/java/android/content/SyncResult.java
+++ b/core/java/android/content/SyncResult.java
@@ -56,7 +56,7 @@
 
     /**
      * Used to indicate that the SyncAdapter experienced a hard error due to an error it
-     * received from interacting with the storage later. The SyncManager will record that
+     * received from interacting with the storage layer. The SyncManager will record that
      * the sync request failed and it will not reschedule the request.
      */
     public boolean databaseError;
@@ -181,7 +181,7 @@
      * <li> {@link SyncStats#numIoExceptions} > 0
      * <li> {@link #syncAlreadyInProgress}
      * </ul>
-     * @return true if a hard error is indicated
+     * @return true if a soft error is indicated
      */
     public boolean hasSoftError() {
         return syncAlreadyInProgress || stats.numIoExceptions > 0;
@@ -195,6 +195,11 @@
         return hasSoftError() || hasHardError();
     }
 
+    /**
+     * Convenience method for determining if the Sync should be rescheduled after failing for some
+     * reason.
+     * @return true if the SyncManager should reschedule this sync.
+     */
     public boolean madeSomeProgress() {
         return ((stats.numDeletes > 0) && !tooManyDeletions)
                 || stats.numInserts > 0
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index ff628d9..bb24ccd 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -42,7 +42,10 @@
     public long initialFailureTime;
     public boolean pending;
     public boolean initialize;
-    public ArrayList<Long> periodicSyncTimes;
+    
+  // Warning: It is up to the external caller to ensure there are
+  // no race conditions when accessing this list
+  private ArrayList<Long> periodicSyncTimes;
 
     private static final String TAG = "Sync";
 
@@ -126,11 +129,59 @@
         }
     }
 
+    public SyncStatusInfo(SyncStatusInfo other) {
+        authorityId = other.authorityId;
+        totalElapsedTime = other.totalElapsedTime;
+        numSyncs = other.numSyncs;
+        numSourcePoll = other.numSourcePoll;
+        numSourceServer = other.numSourceServer;
+        numSourceLocal = other.numSourceLocal;
+        numSourceUser = other.numSourceUser;
+        numSourcePeriodic = other.numSourcePeriodic;
+        lastSuccessTime = other.lastSuccessTime;
+        lastSuccessSource = other.lastSuccessSource;
+        lastFailureTime = other.lastFailureTime;
+        lastFailureSource = other.lastFailureSource;
+        lastFailureMesg = other.lastFailureMesg;
+        initialFailureTime = other.initialFailureTime;
+        pending = other.pending;
+        initialize = other.initialize;
+        if (other.periodicSyncTimes != null) {
+            periodicSyncTimes = new ArrayList<Long>(other.periodicSyncTimes);
+        }
+    }
+
     public void setPeriodicSyncTime(int index, long when) {
+        // The list is initialized lazily when scheduling occurs so we need to make sure
+        // we initialize elements < index to zero (zero is ignore for scheduling purposes)
         ensurePeriodicSyncTimeSize(index);
         periodicSyncTimes.set(index, when);
     }
 
+    public long getPeriodicSyncTime(int index) {
+        if (periodicSyncTimes != null && index < periodicSyncTimes.size()) {
+            return periodicSyncTimes.get(index);
+        } else {
+            return 0;
+        }
+    }
+
+    public void removePeriodicSyncTime(int index) {
+        if (periodicSyncTimes != null && index < periodicSyncTimes.size()) {
+            periodicSyncTimes.remove(index);
+        }
+    }
+
+    public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {
+        public SyncStatusInfo createFromParcel(Parcel in) {
+            return new SyncStatusInfo(in);
+        }
+
+        public SyncStatusInfo[] newArray(int size) {
+            return new SyncStatusInfo[size];
+        }
+    };
+
     private void ensurePeriodicSyncTimeSize(int index) {
         if (periodicSyncTimes == null) {
             periodicSyncTimes = new ArrayList<Long>(0);
@@ -143,26 +194,4 @@
             }
         }
     }
-
-    public long getPeriodicSyncTime(int index) {
-        if (periodicSyncTimes == null || periodicSyncTimes.size() < (index + 1)) {
-            return 0;
-        }
-        return periodicSyncTimes.get(index);
-    }
-
-    public void removePeriodicSyncTime(int index) {
-        ensurePeriodicSyncTimeSize(index);
-        periodicSyncTimes.remove(index);
-    }
-
-    public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {
-        public SyncStatusInfo createFromParcel(Parcel in) {
-            return new SyncStatusInfo(in);
-        }
-
-        public SyncStatusInfo[] newArray(int size) {
-            return new SyncStatusInfo[size];
-        }
-    };
 }
\ No newline at end of file
diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java
new file mode 100644
index 0000000..e9ec5a4
--- /dev/null
+++ b/core/java/android/content/UndoManager.java
@@ -0,0 +1,934 @@
+/*
+ * 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 android.content;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelableParcel;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Top-level class for managing and interacting with the global undo state for
+ * a document or application.  This class supports both undo and redo and has
+ * helpers for merging undoable operations together as they are performed.
+ *
+ * <p>A single undoable operation is represented by {@link UndoOperation} which
+ * apps implement to define their undo/redo behavior.  The UndoManager keeps
+ * a stack of undo states; each state can have one or more undo operations
+ * inside of it.</p>
+ *
+ * <p>Updates to the stack must be done inside of a {@link #beginUpdate}/{@link #endUpdate()}
+ * pair.  During this time you can add new operations to the stack with
+ * {@link #addOperation}, retrieve and modify existing operations with
+ * {@link #getLastOperation}, control the label shown to the user for this operation
+ * with {@link #setUndoLabel} and {@link #suggestUndoLabel}, etc.</p>
+ *
+ * <p>Every {link UndoOperation} is associated with an {@link UndoOwner}, which identifies
+ * the data it belongs to.  The owner is used to indicate how operations are dependent
+ * on each other -- operations with the same owner are dependent on others with the
+ * same owner.  For example, you may have a document with multiple embedded objects.  If the
+ * document itself and each embedded object use different owners, then you
+ * can provide undo semantics appropriate to the user's context: while within
+ * an embedded object, only edits to that object are seen and the user can
+ * undo/redo them without needing to impact edits in other objects; while
+ * within the larger document, all edits can be seen and the user must
+ * undo/redo them as a single stream.</p>
+ *
+ * @hide
+ */
+public class UndoManager {
+    private final HashMap<String, UndoOwner> mOwners = new HashMap<String, UndoOwner>();
+    private final ArrayList<UndoState> mUndos = new ArrayList<UndoState>();
+    private final ArrayList<UndoState> mRedos = new ArrayList<UndoState>();
+    private int mUpdateCount;
+    private int mHistorySize = 20;
+    private UndoState mWorking;
+    private int mCommitId = 1;
+    private boolean mInUndo;
+    private boolean mMerged;
+
+    private int mStateSeq;
+    private int mNextSavedIdx;
+    private UndoOwner[] mStateOwners;
+
+    /**
+     * Never merge with the last undo state.
+     */
+    public static final int MERGE_MODE_NONE = 0;
+
+    /**
+     * Allow merge with the last undo state only if it contains
+     * operations with the caller's owner.
+     */
+    public static final int MERGE_MODE_UNIQUE = 1;
+
+    /**
+     * Always allow merge with the last undo state, if possible.
+     */
+    public static final int MERGE_MODE_ANY = 2;
+
+    public UndoOwner getOwner(String tag, Object data) {
+        if (tag == null) {
+            throw new NullPointerException("tag can't be null");
+        }
+        if (data == null) {
+            throw new NullPointerException("data can't be null");
+        }
+        UndoOwner owner = mOwners.get(tag);
+        if (owner != null) {
+            if (owner.mData != data) {
+                if (owner.mData != null) {
+                    throw new IllegalStateException("Owner " + owner + " already exists with data "
+                            + owner.mData + " but giving different data " + data);
+                }
+                owner.mData = data;
+            }
+            return owner;
+        }
+
+        owner = new UndoOwner(tag);
+        owner.mManager = this;
+        owner.mData = data;
+        mOwners.put(tag, owner);
+        return owner;
+    }
+
+    void removeOwner(UndoOwner owner) {
+        // XXX need to figure out how to prune.
+        if (false) {
+            mOwners.remove(owner.mTag);
+            owner.mManager = null;
+        }
+    }
+
+    /**
+     * Flatten the current undo state into a Parcelable object, which can later be restored
+     * with {@link #restoreInstanceState(android.os.Parcelable)}.
+     */
+    public Parcelable saveInstanceState() {
+        if (mUpdateCount > 0) {
+            throw new IllegalStateException("Can't save state while updating");
+        }
+        ParcelableParcel pp = new ParcelableParcel(getClass().getClassLoader());
+        Parcel p = pp.getParcel();
+        mStateSeq++;
+        if (mStateSeq <= 0) {
+            mStateSeq = 0;
+        }
+        mNextSavedIdx = 0;
+        p.writeInt(mHistorySize);
+        p.writeInt(mOwners.size());
+        // XXX eventually we need to be smart here about limiting the
+        // number of undo states we write to not exceed X bytes.
+        int i = mUndos.size();
+        while (i > 0) {
+            p.writeInt(1);
+            i--;
+            mUndos.get(i).writeToParcel(p);
+        }
+        i = mRedos.size();
+        p.writeInt(i);
+        while (i > 0) {
+            p.writeInt(2);
+            i--;
+            mRedos.get(i).writeToParcel(p);
+        }
+        p.writeInt(0);
+        return pp;
+    }
+
+    void saveOwner(UndoOwner owner, Parcel out) {
+        if (owner.mStateSeq == mStateSeq) {
+            out.writeInt(owner.mSavedIdx);
+        } else {
+            owner.mStateSeq = mStateSeq;
+            owner.mSavedIdx = mNextSavedIdx;
+            out.writeInt(owner.mSavedIdx);
+            out.writeString(owner.mTag);
+            mNextSavedIdx++;
+        }
+    }
+
+    /**
+     * Restore an undo state previously created with {@link #saveInstanceState()}.  This will
+     * restore the UndoManager's state to almost exactly what it was at the point it had
+     * been previously saved; the only information not restored is the data object
+     * associated with each {@link UndoOwner}, which requires separate calls to
+     * {@link #getOwner(String, Object)} to re-associate the owner with its data.
+     */
+    public void restoreInstanceState(Parcelable state) {
+        if (mUpdateCount > 0) {
+            throw new IllegalStateException("Can't save state while updating");
+        }
+        forgetUndos(null, -1);
+        forgetRedos(null, -1);
+        ParcelableParcel pp = (ParcelableParcel)state;
+        Parcel p = pp.getParcel();
+        mHistorySize = p.readInt();
+        mStateOwners = new UndoOwner[p.readInt()];
+
+        int stype;
+        while ((stype=p.readInt()) != 0) {
+            UndoState ustate = new UndoState(this, p, pp.getClassLoader());
+            if (stype == 1) {
+                mUndos.add(0, ustate);
+            } else {
+                mRedos.add(0, ustate);
+            }
+        }
+    }
+
+    UndoOwner restoreOwner(Parcel in) {
+        int idx = in.readInt();
+        UndoOwner owner = mStateOwners[idx];
+        if (owner == null) {
+            String tag = in.readString();
+            owner = new UndoOwner(tag);
+            mStateOwners[idx] = owner;
+            mOwners.put(tag, owner);
+        }
+        return owner;
+    }
+
+    /**
+     * Set the maximum number of undo states that will be retained.
+     */
+    public void setHistorySize(int size) {
+        mHistorySize = size;
+        if (mHistorySize >= 0 && countUndos(null) > mHistorySize) {
+            forgetUndos(null, countUndos(null) - mHistorySize);
+        }
+    }
+
+    /**
+     * Return the current maximum number of undo states.
+     */
+    public int getHistorySize() {
+        return mHistorySize;
+    }
+
+    /**
+     * Perform undo of last/top <var>count</var> undo states.  The states impacted
+     * by this can be limited through <var>owners</var>.
+     * @param owners Optional set of owners that should be impacted.  If null, all
+     * undo states will be visible and available for undo.  If non-null, only those
+     * states that contain one of the owners specified here will be visible.
+     * @param count Number of undo states to pop.
+     * @return Returns the number of undo states that were actually popped.
+     */
+    public int undo(UndoOwner[] owners, int count) {
+        if (mWorking != null) {
+            throw new IllegalStateException("Can't be called during an update");
+        }
+
+        int num = 0;
+        int i = -1;
+
+        mInUndo = true;
+
+        UndoState us = getTopUndo(null);
+        if (us != null) {
+            us.makeExecuted();
+        }
+
+        while (count > 0 && (i=findPrevState(mUndos, owners, i)) >= 0) {
+            UndoState state = mUndos.remove(i);
+            state.undo();
+            mRedos.add(state);
+            count--;
+            num++;
+        }
+
+        mInUndo = false;
+
+        return num;
+    }
+
+    /**
+     * Perform redo of last/top <var>count</var> undo states in the transient redo stack.
+     * The states impacted by this can be limited through <var>owners</var>.
+     * @param owners Optional set of owners that should be impacted.  If null, all
+     * undo states will be visible and available for undo.  If non-null, only those
+     * states that contain one of the owners specified here will be visible.
+     * @param count Number of undo states to pop.
+     * @return Returns the number of undo states that were actually redone.
+     */
+    public int redo(UndoOwner[] owners, int count) {
+        if (mWorking != null) {
+            throw new IllegalStateException("Can't be called during an update");
+        }
+
+        int num = 0;
+        int i = -1;
+
+        mInUndo = true;
+
+        while (count > 0 && (i=findPrevState(mRedos, owners, i)) >= 0) {
+            UndoState state = mRedos.remove(i);
+            state.redo();
+            mUndos.add(state);
+            count--;
+            num++;
+        }
+
+        mInUndo = false;
+
+        return num;
+    }
+
+    /**
+     * Returns true if we are currently inside of an undo/redo operation.  This is
+     * useful for editors to know whether they should be generating new undo state
+     * when they see edit operations happening.
+     */
+    public boolean isInUndo() {
+        return mInUndo;
+    }
+
+    public int forgetUndos(UndoOwner[] owners, int count) {
+        if (count < 0) {
+            count = mUndos.size();
+        }
+
+        int removed = 0;
+        for (int i=0; i<mUndos.size() && removed < count; i++) {
+            UndoState state = mUndos.get(i);
+            if (count > 0 && matchOwners(state, owners)) {
+                state.destroy();
+                mUndos.remove(i);
+                removed++;
+            }
+        }
+
+        return removed;
+    }
+
+    public int forgetRedos(UndoOwner[] owners, int count) {
+        if (count < 0) {
+            count = mRedos.size();
+        }
+
+        int removed = 0;
+        for (int i=0; i<mRedos.size() && removed < count; i++) {
+            UndoState state = mRedos.get(i);
+            if (count > 0 && matchOwners(state, owners)) {
+                state.destroy();
+                mRedos.remove(i);
+                removed++;
+            }
+        }
+
+        return removed;
+    }
+
+    /**
+     * Return the number of undo states on the undo stack.
+     * @param owners If non-null, only those states containing an operation with one of
+     * the owners supplied here will be counted.
+     */
+    public int countUndos(UndoOwner[] owners) {
+        if (owners == null) {
+            return mUndos.size();
+        }
+
+        int count=0;
+        int i=0;
+        while ((i=findNextState(mUndos, owners, i)) >= 0) {
+            count++;
+            i++;
+        }
+        return count;
+    }
+
+    /**
+     * Return the number of redo states on the undo stack.
+     * @param owners If non-null, only those states containing an operation with one of
+     * the owners supplied here will be counted.
+     */
+    public int countRedos(UndoOwner[] owners) {
+        if (owners == null) {
+            return mRedos.size();
+        }
+
+        int count=0;
+        int i=0;
+        while ((i=findNextState(mRedos, owners, i)) >= 0) {
+            count++;
+            i++;
+        }
+        return count;
+    }
+
+    /**
+     * Return the user-visible label for the top undo state on the stack.
+     * @param owners If non-null, will select the top-most undo state containing an
+     * operation with one of the owners supplied here.
+     */
+    public CharSequence getUndoLabel(UndoOwner[] owners) {
+        UndoState state = getTopUndo(owners);
+        return state != null ? state.getLabel() : null;
+    }
+
+    /**
+     * Return the user-visible label for the top redo state on the stack.
+     * @param owners If non-null, will select the top-most undo state containing an
+     * operation with one of the owners supplied here.
+     */
+    public CharSequence getRedoLabel(UndoOwner[] owners) {
+        UndoState state = getTopRedo(owners);
+        return state != null ? state.getLabel() : null;
+    }
+
+    /**
+     * Start creating a new undo state.  Multiple calls to this function will nest until
+     * they are all matched by a later call to {@link #endUpdate}.
+     * @param label Optional user-visible label for this new undo state.
+     */
+    public void beginUpdate(CharSequence label) {
+        if (mInUndo) {
+            throw new IllegalStateException("Can't being update while performing undo/redo");
+        }
+        if (mUpdateCount <= 0) {
+            createWorkingState();
+            mMerged = false;
+            mUpdateCount = 0;
+        }
+
+        mWorking.updateLabel(label);
+        mUpdateCount++;
+    }
+
+    private void createWorkingState() {
+        mWorking = new UndoState(this, mCommitId++);
+        if (mCommitId < 0) {
+            mCommitId = 1;
+        }
+    }
+
+    /**
+     * Returns true if currently inside of a {@link #beginUpdate}.
+     */
+    public boolean isInUpdate() {
+        return mUpdateCount > 0;
+    }
+
+    /**
+     * Forcibly set a new for the new undo state being built within a {@link #beginUpdate}.
+     * Any existing label will be replaced with this one.
+     */
+    public void setUndoLabel(CharSequence label) {
+        if (mWorking == null) {
+            throw new IllegalStateException("Must be called during an update");
+        }
+        mWorking.setLabel(label);
+    }
+
+    /**
+     * Set a new for the new undo state being built within a {@link #beginUpdate}, but
+     * only if there is not a label currently set for it.
+     */
+    public void suggestUndoLabel(CharSequence label) {
+        if (mWorking == null) {
+            throw new IllegalStateException("Must be called during an update");
+        }
+        mWorking.updateLabel(label);
+    }
+
+    /**
+     * Return the number of times {@link #beginUpdate} has been called without a matching
+     * {@link #endUpdate} call.
+     */
+    public int getUpdateNestingLevel() {
+        return mUpdateCount;
+    }
+
+    /**
+     * Check whether there is an {@link UndoOperation} in the current {@link #beginUpdate}
+     * undo state.
+     * @param owner Optional owner of the operation to look for.  If null, will succeed
+     * if there is any operation; if non-null, will only succeed if there is an operation
+     * with the given owner.
+     * @return Returns true if there is a matching operation in the current undo state.
+     */
+    public boolean hasOperation(UndoOwner owner) {
+        if (mWorking == null) {
+            throw new IllegalStateException("Must be called during an update");
+        }
+        return mWorking.hasOperation(owner);
+    }
+
+    /**
+     * Return the most recent {@link UndoOperation} that was added to the update.
+     * @param mergeMode May be either {@link #MERGE_MODE_NONE} or {@link #MERGE_MODE_ANY}.
+     */
+    public UndoOperation<?> getLastOperation(int mergeMode) {
+        return getLastOperation(null, null, mergeMode);
+    }
+
+    /**
+     * Return the most recent {@link UndoOperation} that was added to the update and
+     * has the given owner.
+     * @param owner Optional owner of last operation to retrieve.  If null, the last
+     * operation regardless of owner will be retrieved; if non-null, the last operation
+     * matching the given owner will be retrieved.
+     * @param mergeMode May be either {@link #MERGE_MODE_NONE}, {@link #MERGE_MODE_UNIQUE},
+     * or {@link #MERGE_MODE_ANY}.
+     */
+    public UndoOperation<?> getLastOperation(UndoOwner owner, int mergeMode) {
+        return getLastOperation(null, owner, mergeMode);
+    }
+
+    /**
+     * Return the most recent {@link UndoOperation} that was added to the update and
+     * has the given owner.
+     * @param clazz Optional class of the last operation to retrieve.  If null, the
+     * last operation regardless of class will be retrieved; if non-null, the last
+     * operation whose class is the same as the given class will be retrieved.
+     * @param owner Optional owner of last operation to retrieve.  If null, the last
+     * operation regardless of owner will be retrieved; if non-null, the last operation
+     * matching the given owner will be retrieved.
+     * @param mergeMode May be either {@link #MERGE_MODE_NONE}, {@link #MERGE_MODE_UNIQUE},
+     * or {@link #MERGE_MODE_ANY}.
+     */
+    public <T extends UndoOperation> T getLastOperation(Class<T> clazz, UndoOwner owner,
+            int mergeMode) {
+        if (mWorking == null) {
+            throw new IllegalStateException("Must be called during an update");
+        }
+        if (mergeMode != MERGE_MODE_NONE && !mMerged && !mWorking.hasData()) {
+            UndoState state = getTopUndo(null);
+            UndoOperation<?> last;
+            if (state != null && (mergeMode == MERGE_MODE_ANY || !state.hasMultipleOwners())
+                    && state.canMerge() && (last=state.getLastOperation(clazz, owner)) != null) {
+                if (last.allowMerge()) {
+                    mWorking.destroy();
+                    mWorking = state;
+                    mUndos.remove(state);
+                    mMerged = true;
+                    return (T)last;
+                }
+            }
+        }
+
+        return mWorking.getLastOperation(clazz, owner);
+    }
+
+    /**
+     * Add a new UndoOperation to the current update.
+     * @param op The new operation to add.
+     * @param mergeMode May be either {@link #MERGE_MODE_NONE}, {@link #MERGE_MODE_UNIQUE},
+     * or {@link #MERGE_MODE_ANY}.
+     */
+    public void addOperation(UndoOperation<?> op, int mergeMode) {
+        if (mWorking == null) {
+            throw new IllegalStateException("Must be called during an update");
+        }
+        UndoOwner owner = op.getOwner();
+        if (owner.mManager != this) {
+            throw new IllegalArgumentException(
+                    "Given operation's owner is not in this undo manager.");
+        }
+        if (mergeMode != MERGE_MODE_NONE && !mMerged && !mWorking.hasData()) {
+            UndoState state = getTopUndo(null);
+            if (state != null && (mergeMode == MERGE_MODE_ANY || !state.hasMultipleOwners())
+                    && state.canMerge() && state.hasOperation(op.getOwner())) {
+                mWorking.destroy();
+                mWorking = state;
+                mUndos.remove(state);
+                mMerged = true;
+            }
+        }
+        mWorking.addOperation(op);
+    }
+
+    /**
+     * Finish the creation of an undo state, matching a previous call to
+     * {@link #beginUpdate}.
+     */
+    public void endUpdate() {
+        if (mWorking == null) {
+            throw new IllegalStateException("Must be called during an update");
+        }
+        mUpdateCount--;
+
+        if (mUpdateCount == 0) {
+            pushWorkingState();
+        }
+    }
+
+    private void pushWorkingState() {
+        int N = mUndos.size() + 1;
+
+        if (mWorking.hasData()) {
+            mUndos.add(mWorking);
+            forgetRedos(null, -1);
+            mWorking.commit();
+            if (N >= 2) {
+                // The state before this one can no longer be merged, ever.
+                // The only way to get back to it is for the user to perform
+                // an undo.
+                mUndos.get(N-2).makeExecuted();
+            }
+        } else {
+            mWorking.destroy();
+        }
+        mWorking = null;
+
+        if (mHistorySize >= 0 && N > mHistorySize) {
+            forgetUndos(null, N - mHistorySize);
+        }
+    }
+
+    /**
+     * Commit the last finished undo state.  This undo state can no longer be
+     * modified with further {@link #MERGE_MODE_UNIQUE} or
+     * {@link #MERGE_MODE_ANY} merge modes.  If called while inside of an update,
+     * this will push any changes in the current update on to the undo stack
+     * and result with a fresh undo state, behaving as if {@link #endUpdate()}
+     * had been called enough to unwind the current update, then the last state
+     * committed, and {@link #beginUpdate} called to restore the update nesting.
+     * @param owner The optional owner to determine whether to perform the commit.
+     * If this is non-null, the commit will only execute if the current top undo
+     * state contains an operation with the given owner.
+     * @return Returns an integer identifier for the committed undo state, which
+     * can later be used to try to uncommit the state to perform further edits on it.
+     */
+    public int commitState(UndoOwner owner) {
+        if (mWorking != null && mWorking.hasData()) {
+            if (owner == null || mWorking.hasOperation(owner)) {
+                mWorking.setCanMerge(false);
+                int commitId = mWorking.getCommitId();
+                pushWorkingState();
+                createWorkingState();
+                mMerged = true;
+                return commitId;
+            }
+        } else {
+            UndoState state = getTopUndo(null);
+            if (state != null && (owner == null || state.hasOperation(owner))) {
+                state.setCanMerge(false);
+                return state.getCommitId();
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Attempt to undo a previous call to {@link #commitState}.  This will work
+     * if the undo state at the top of the stack has the given id, and has not been
+     * involved in an undo operation.  Otherwise false is returned.
+     * @param commitId The identifier for the state to be uncommitted, as returned
+     * by {@link #commitState}.
+     * @param owner Optional owner that must appear in the committed state.
+     * @return Returns true if the uncommit is successful, else false.
+     */
+    public boolean uncommitState(int commitId, UndoOwner owner) {
+        if (mWorking != null && mWorking.getCommitId() == commitId) {
+            if (owner == null || mWorking.hasOperation(owner)) {
+                return mWorking.setCanMerge(true);
+            }
+        } else {
+            UndoState state = getTopUndo(null);
+            if (state != null && (owner == null || state.hasOperation(owner))) {
+                if (state.getCommitId() == commitId) {
+                    return state.setCanMerge(true);
+                }
+            }
+        }
+        return false;
+    }
+
+    UndoState getTopUndo(UndoOwner[] owners) {
+        if (mUndos.size() <= 0) {
+            return null;
+        }
+        int i = findPrevState(mUndos, owners, -1);
+        return i >= 0 ? mUndos.get(i) : null;
+    }
+
+    UndoState getTopRedo(UndoOwner[] owners) {
+        if (mRedos.size() <= 0) {
+            return null;
+        }
+        int i = findPrevState(mRedos, owners, -1);
+        return i >= 0 ? mRedos.get(i) : null;
+    }
+
+    boolean matchOwners(UndoState state, UndoOwner[] owners) {
+        if (owners == null) {
+            return true;
+        }
+        for (int i=0; i<owners.length; i++) {
+            if (state.matchOwner(owners[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    int findPrevState(ArrayList<UndoState> states, UndoOwner[] owners, int from) {
+        final int N = states.size();
+
+        if (from == -1) {
+            from = N-1;
+        }
+        if (from >= N) {
+            return -1;
+        }
+        if (owners == null) {
+            return from;
+        }
+
+        while (from >= 0) {
+            UndoState state = states.get(from);
+            if (matchOwners(state, owners)) {
+                return from;
+            }
+            from--;
+        }
+
+        return -1;
+    }
+
+    int findNextState(ArrayList<UndoState> states, UndoOwner[] owners, int from) {
+        final int N = states.size();
+
+        if (from < 0) {
+            from = 0;
+        }
+        if (from >= N) {
+            return -1;
+        }
+        if (owners == null) {
+            return from;
+        }
+
+        while (from < N) {
+            UndoState state = states.get(from);
+            if (matchOwners(state, owners)) {
+                return from;
+            }
+            from++;
+        }
+
+        return -1;
+    }
+
+    final static class UndoState {
+        private final UndoManager mManager;
+        private final int mCommitId;
+        private final ArrayList<UndoOperation<?>> mOperations = new ArrayList<UndoOperation<?>>();
+        private ArrayList<UndoOperation<?>> mRecent;
+        private CharSequence mLabel;
+        private boolean mCanMerge = true;
+        private boolean mExecuted;
+
+        UndoState(UndoManager manager, int commitId) {
+            mManager = manager;
+            mCommitId = commitId;
+        }
+
+        UndoState(UndoManager manager, Parcel p, ClassLoader loader) {
+            mManager = manager;
+            mCommitId = p.readInt();
+            mCanMerge = p.readInt() != 0;
+            mExecuted = p.readInt() != 0;
+            mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+            final int N = p.readInt();
+            for (int i=0; i<N; i++) {
+                UndoOwner owner = mManager.restoreOwner(p);
+                UndoOperation op = (UndoOperation)p.readParcelable(loader);
+                op.mOwner = owner;
+                mOperations.add(op);
+            }
+        }
+
+        void writeToParcel(Parcel p) {
+            if (mRecent != null) {
+                throw new IllegalStateException("Can't save state before committing");
+            }
+            p.writeInt(mCommitId);
+            p.writeInt(mCanMerge ? 1 : 0);
+            p.writeInt(mExecuted ? 1 : 0);
+            TextUtils.writeToParcel(mLabel, p, 0);
+            final int N = mOperations.size();
+            p.writeInt(N);
+            for (int i=0; i<N; i++) {
+                UndoOperation op = mOperations.get(i);
+                mManager.saveOwner(op.mOwner, p);
+                p.writeParcelable(op, 0);
+            }
+        }
+
+        int getCommitId() {
+            return mCommitId;
+        }
+
+        void setLabel(CharSequence label) {
+            mLabel = label;
+        }
+
+        void updateLabel(CharSequence label) {
+            if (mLabel != null) {
+                mLabel = label;
+            }
+        }
+
+        CharSequence getLabel() {
+            return mLabel;
+        }
+
+        boolean setCanMerge(boolean state) {
+            // Don't allow re-enabling of merging if state has been executed.
+            if (state && mExecuted) {
+                return false;
+            }
+            mCanMerge = state;
+            return true;
+        }
+
+        void makeExecuted() {
+            mExecuted = true;
+        }
+
+        boolean canMerge() {
+            return mCanMerge && !mExecuted;
+        }
+
+        int countOperations() {
+            return mOperations.size();
+        }
+
+        boolean hasOperation(UndoOwner owner) {
+            final int N = mOperations.size();
+            if (owner == null) {
+                return N != 0;
+            }
+            for (int i=0; i<N; i++) {
+                if (mOperations.get(i).getOwner() == owner) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean hasMultipleOwners() {
+            final int N = mOperations.size();
+            if (N <= 1) {
+                return false;
+            }
+            UndoOwner owner = mOperations.get(0).getOwner();
+            for (int i=1; i<N; i++) {
+                if (mOperations.get(i).getOwner() != owner) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        void addOperation(UndoOperation<?> op) {
+            if (mOperations.contains(op)) {
+                throw new IllegalStateException("Already holds " + op);
+            }
+            mOperations.add(op);
+            if (mRecent == null) {
+                mRecent = new ArrayList<UndoOperation<?>>();
+                mRecent.add(op);
+            }
+            op.mOwner.mOpCount++;
+        }
+
+        <T extends UndoOperation> T getLastOperation(Class<T> clazz, UndoOwner owner) {
+            final int N = mOperations.size();
+            if (clazz == null && owner == null) {
+                return N > 0 ? (T)mOperations.get(N-1) : null;
+            }
+            // First look for the top-most operation with the same owner.
+            for (int i=N-1; i>=0; i--) {
+                UndoOperation<?> op = mOperations.get(i);
+                if (owner != null && op.getOwner() != owner) {
+                    continue;
+                }
+                // Return this operation if it has the same class that the caller wants.
+                // Note that we don't search deeper for the class, because we don't want
+                // to end up with a different order of operations for the same owner.
+                if (clazz != null && op.getClass() != clazz) {
+                    return null;
+                }
+                return (T)op;
+            }
+
+            return null;
+        }
+
+        boolean matchOwner(UndoOwner owner) {
+            for (int i=mOperations.size()-1; i>=0; i--) {
+                if (mOperations.get(i).matchOwner(owner)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean hasData() {
+            for (int i=mOperations.size()-1; i>=0; i--) {
+                if (mOperations.get(i).hasData()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        void commit() {
+            final int N = mRecent != null ? mRecent.size() : 0;
+            for (int i=0; i<N; i++) {
+                mRecent.get(i).commit();
+            }
+            mRecent = null;
+        }
+
+        void undo() {
+            for (int i=mOperations.size()-1; i>=0; i--) {
+                mOperations.get(i).undo();
+            }
+        }
+
+        void redo() {
+            final int N = mOperations.size();
+            for (int i=0; i<N; i++) {
+                mOperations.get(i).redo();
+            }
+        }
+
+        void destroy() {
+            for (int i=mOperations.size()-1; i>=0; i--) {
+                UndoOwner owner = mOperations.get(i).mOwner;
+                owner.mOpCount--;
+                if (owner.mOpCount <= 0) {
+                    if (owner.mOpCount < 0) {
+                        throw new IllegalStateException("Underflow of op count on owner " + owner
+                                + " in op " + mOperations.get(i));
+                    }
+                    mManager.removeOwner(owner);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/content/UndoOperation.java b/core/java/android/content/UndoOperation.java
new file mode 100644
index 0000000..1ff32d4
--- /dev/null
+++ b/core/java/android/content/UndoOperation.java
@@ -0,0 +1,112 @@
+/*
+ * 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 android.content;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A single undoable operation.  You must subclass this to implement the state
+ * and behavior for your operation.  Instances of this class are placed and
+ * managed in an {@link UndoManager}.
+ *
+ * @hide
+ */
+public abstract class UndoOperation<DATA> implements Parcelable {
+    UndoOwner mOwner;
+
+    /**
+     * Create a new instance of the operation.
+     * @param owner Who owns the data being modified by this undo state; must be
+     * returned by {@link UndoManager#getOwner(String, Object) UndoManager.getOwner}.
+     */
+    public UndoOperation(UndoOwner owner) {
+        mOwner = owner;
+    }
+
+    /**
+     * Construct from a Parcel.
+     */
+    protected UndoOperation(Parcel src, ClassLoader loader) {
+    }
+
+    /**
+     * Owning object as given to {@link #UndoOperation(UndoOwner)}.
+     */
+    public UndoOwner getOwner() {
+        return mOwner;
+    }
+
+    /**
+     * Synonym for {@link #getOwner()}.{@link android.content.UndoOwner#getData()}.
+     */
+    public DATA getOwnerData() {
+        return (DATA)mOwner.getData();
+    }
+
+    /**
+     * Return true if this undo operation is a member of the given owner.
+     * The default implementation is <code>owner == getOwner()</code>.  You
+     * can override this to provide more sophisticated dependencies between
+     * owners.
+     */
+    public boolean matchOwner(UndoOwner owner) {
+        return owner == getOwner();
+    }
+
+    /**
+     * Return true if this operation actually contains modification data.  The
+     * default implementation always returns true.  If you return false, the
+     * operation will be dropped when the final undo state is being built.
+     */
+    public boolean hasData() {
+        return true;
+    }
+
+    /**
+     * Return true if this operation can be merged with a later operation.
+     * The default implementation always returns true.
+     */
+    public boolean allowMerge() {
+        return true;
+    }
+
+    /**
+     * Called when this undo state is being committed to the undo stack.
+     * The implementation should perform the initial edits and save any state that
+     * may be needed to undo them.
+     */
+    public abstract void commit();
+
+    /**
+     * Called when this undo state is being popped off the undo stack (in to
+     * the temporary redo stack).  The implementation should remove the original
+     * edits and thus restore the target object to its prior value.
+     */
+    public abstract void undo();
+
+    /**
+     * Called when this undo state is being pushed back from the transient
+     * redo stack to the main undo stack.  The implementation should re-apply
+     * the edits that were previously removed by {@link #undo}.
+     */
+    public abstract void redo();
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/content/UndoOwner.java b/core/java/android/content/UndoOwner.java
new file mode 100644
index 0000000..d0cdc95
--- /dev/null
+++ b/core/java/android/content/UndoOwner.java
@@ -0,0 +1,57 @@
+/*
+ * 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 android.content;
+
+/**
+ * Representation of an owner of {@link UndoOperation} objects in an {@link UndoManager}.
+ *
+ * @hide
+ */
+public class UndoOwner {
+    final String mTag;
+
+    UndoManager mManager;
+    Object mData;
+    int mOpCount;
+
+    // For saving/restoring state.
+    int mStateSeq;
+    int mSavedIdx;
+
+    UndoOwner(String tag) {
+        mTag = tag;
+    }
+
+    /**
+     * Return the unique tag name identifying this owner.  This is the tag
+     * supplied to {@link UndoManager#getOwner(String, Object) UndoManager.getOwner}
+     * and is immutable.
+     */
+    public String getTag() {
+        return mTag;
+    }
+
+    /**
+     * Return the actual data object of the owner.  This is the data object
+     * supplied to {@link UndoManager#getOwner(String, Object) UndoManager.getOwner}.  An
+     * owner may have a null data if it was restored from a previously saved state with
+     * no getOwner call to associate it with its data.
+     */
+    public Object getData() {
+        return mData;
+    }
+}
diff --git a/core/java/android/content/UriPermission.java b/core/java/android/content/UriPermission.java
new file mode 100644
index 0000000..df9200d
--- /dev/null
+++ b/core/java/android/content/UriPermission.java
@@ -0,0 +1,117 @@
+/*
+ * 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 android.content;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Description of a single Uri permission grant. This grants may have been
+ * created via {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc when sending
+ * an {@link Intent}, or explicitly through
+ * {@link Context#grantUriPermission(String, android.net.Uri, int)}.
+ *
+ * @see ContentResolver#getPersistedUriPermissions()
+ */
+public final class UriPermission implements Parcelable {
+    private final Uri mUri;
+    private final int mModeFlags;
+    private final long mPersistedTime;
+
+    /**
+     * Value returned when a permission has not been persisted.
+     */
+    public static final long INVALID_TIME = Long.MIN_VALUE;
+
+    /** {@hide} */
+    public UriPermission(Uri uri, int modeFlags, long persistedTime) {
+        mUri = uri;
+        mModeFlags = modeFlags;
+        mPersistedTime = persistedTime;
+    }
+
+    /** {@hide} */
+    public UriPermission(Parcel in) {
+        mUri = in.readParcelable(null);
+        mModeFlags = in.readInt();
+        mPersistedTime = in.readLong();
+    }
+
+    /**
+     * Return the Uri this permission pertains to.
+     */
+    public Uri getUri() {
+        return mUri;
+    }
+
+    /**
+     * Returns if this permission offers read access.
+     */
+    public boolean isReadPermission() {
+        return (mModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0;
+    }
+
+    /**
+     * Returns if this permission offers write access.
+     */
+    public boolean isWritePermission() {
+        return (mModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0;
+    }
+
+    /**
+     * Return the time when this permission was first persisted, in milliseconds
+     * since January 1, 1970 00:00:00.0 UTC. Returns {@link #INVALID_TIME} if
+     * not persisted.
+     *
+     * @see ContentResolver#takePersistableUriPermission(Uri, int)
+     * @see System#currentTimeMillis()
+     */
+    public long getPersistedTime() {
+        return mPersistedTime;
+    }
+
+    @Override
+    public String toString() {
+        return "UriPermission {uri=" + mUri + ", modeFlags=" + mModeFlags + ", persistedTime="
+                + mPersistedTime + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mUri, flags);
+        dest.writeInt(mModeFlags);
+        dest.writeLong(mPersistedTime);
+    }
+
+    public static final Creator<UriPermission> CREATOR = new Creator<UriPermission>() {
+        @Override
+        public UriPermission createFromParcel(Parcel source) {
+            return new UriPermission(source);
+        }
+
+        @Override
+        public UriPermission[] newArray(int size) {
+            return new UriPermission[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 8154bca..b8ac3bf 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Printer;
@@ -437,20 +438,20 @@
      * native side given the bit we have assigned in ActivityInfo.
      */
     public static int[] CONFIG_NATIVE_BITS = new int[] {
-        0x0001, // MNC
-        0x0002, // MCC
-        0x0004, // LOCALE
-        0x0008, // TOUCH SCREEN
-        0x0010, // KEYBOARD
-        0x0020, // KEYBOARD HIDDEN
-        0x0040, // NAVIGATION
-        0x0080, // ORIENTATION
-        0x0800, // SCREEN LAYOUT
-        0x1000, // UI MODE
-        0x0200, // SCREEN SIZE
-        0x2000, // SMALLEST SCREEN SIZE
-        0x0100, // DENSITY
-        0x4000, // LAYOUT DIRECTION
+        Configuration.NATIVE_CONFIG_MNC,                    // MNC
+        Configuration.NATIVE_CONFIG_MCC,                    // MCC
+        Configuration.NATIVE_CONFIG_LOCALE,                 // LOCALE
+        Configuration.NATIVE_CONFIG_TOUCHSCREEN,            // TOUCH SCREEN
+        Configuration.NATIVE_CONFIG_KEYBOARD,               // KEYBOARD
+        Configuration.NATIVE_CONFIG_KEYBOARD_HIDDEN,        // KEYBOARD HIDDEN
+        Configuration.NATIVE_CONFIG_NAVIGATION,             // NAVIGATION
+        Configuration.NATIVE_CONFIG_ORIENTATION,            // ORIENTATION
+        Configuration.NATIVE_CONFIG_SCREEN_LAYOUT,          // SCREEN LAYOUT
+        Configuration.NATIVE_CONFIG_UI_MODE,                // UI MODE
+        Configuration.NATIVE_CONFIG_SCREEN_SIZE,            // SCREEN SIZE
+        Configuration.NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,   // SMALLEST SCREEN SIZE
+        Configuration.NATIVE_CONFIG_DENSITY,                // DENSITY
+        Configuration.NATIVE_CONFIG_LAYOUTDIR,              // LAYOUT DIRECTION
     };
     /** @hide
      * Convert Java change bits to native.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 02401dc..9c46d96 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -315,6 +315,14 @@
     public static final int FLAG_IS_DATA_ONLY = 1<<24;
 
     /**
+     * Value for {@link #flags}: set to {@code true} if the application
+     * is permitted to hold privileged permissions.
+     *
+     * {@hide}
+     */
+    public static final int FLAG_PRIVILEGED = 1<<30;
+
+    /**
      * Value for {@link #flags}: Set to true if the application has been
      * installed using the forward lock option.
      *
@@ -338,6 +346,13 @@
     public static final int FLAG_CANT_SAVE_STATE = 1<<28;
 
     /**
+     * Value for {@link #flags}: true if the application is blocked via restrictions and for
+     * most purposes is considered as not installed.
+     * {@hide}
+     */
+    public static final int FLAG_BLOCKED = 1<<27;
+
+    /**
      * Flags associated with the application.  Any combination of
      * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
@@ -351,7 +366,7 @@
      * {@link #FLAG_INSTALLED}.
      */
     public int flags = 0;
-    
+
     /**
      * The required smallest screen width the application can run on.  If 0,
      * nothing has been specified.  Comes from
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 2812477..4dbcf23 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -116,6 +116,17 @@
     public final int getIconResource() {
         return icon != 0 ? icon : applicationInfo.icon;
     }
+
+    /**
+     * Return the logo resource identifier to use for this component.  If
+     * the component defines a logo, that is used; else, the application
+     * logo is used.
+     *
+     * @return The logo associated with this component.
+     */
+    public final int getLogoResource() {
+        return logo != 0 ? logo : applicationInfo.logo;
+    }
     
     protected void dumpFront(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a0e1555..acd4ffa 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -101,7 +101,9 @@
     String getNameForUid(int uid);
     
     int getUidForSharedUser(String sharedUserName);
-    
+
+    int getFlagsForUid(int uid);
+
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
@@ -214,6 +216,12 @@
 
     void resetPreferredActivities(int userId);
 
+    ResolveInfo getLastChosenActivity(in Intent intent,
+            String resolvedType, int flags);
+
+    void setLastChosenActivity(in Intent intent, String resolvedType, int flags,
+            in IntentFilter filter, int match, in ComponentName activity);
+
     void addPreferredActivity(in IntentFilter filter, int match,
             in ComponentName[] set, in ComponentName activity, int userId);
 
@@ -224,7 +232,13 @@
 
     int getPreferredActivities(out List<IntentFilter> outFilters,
             out List<ComponentName> outActivities, String packageName);
-    
+
+    /**
+     * Report the set of 'Home' activity candidates, plus (if any) which of them
+     * is the current "always use this one" setting.
+     */
+     ComponentName getHomeActivities(out List<ResolveInfo> outHomeCandidates);
+
     /**
      * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
      */
@@ -399,4 +413,7 @@
 
     /** Reflects current DeviceStorageMonitorService state */
     boolean isStorageLow();
+
+    boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked, int userId);
+    boolean getApplicationBlockedSettingAsUser(String packageName, int userId);
 }
diff --git a/core/java/android/content/pm/KeySet.java b/core/java/android/content/pm/KeySet.java
new file mode 100644
index 0000000..0ef09a4
--- /dev/null
+++ b/core/java/android/content/pm/KeySet.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Binder;
+
+/** @hide */
+public class KeySet {
+
+    private Binder token;
+
+    /** @hide */
+    public KeySet(Binder token) {
+        this.token = token;
+    }
+
+    Binder getToken() {
+        return token;
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4266d85..9203af9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -955,6 +955,26 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports host-
+     * based NFC card emulation.
+     *
+     * TODO remove when depending apps have moved to new constant.
+     * @hide
+     * @deprecated
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports host-
+     * based NFC card emulation.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device includes an accelerometer.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1176,6 +1196,13 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports device policy enforcement via device admins.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -3007,6 +3034,13 @@
             List<ComponentName> outActivities, String packageName);
 
     /**
+     * Ask for the set of available 'home' activities and the current explicit
+     * default, if any.
+     * @hide
+     */
+    public abstract ComponentName getHomeActivities(List<ResolveInfo> outActivities);
+
+    /**
      * Set the enabled setting for a package component (activity, receiver, service, provider).
      * This setting will override any enabled state which may have been set by the component in its
      * manifest.
@@ -3083,6 +3117,23 @@
     public abstract int getApplicationEnabledSetting(String packageName);
 
     /**
+     * Puts the package in a blocked state, which is almost like an uninstalled state,
+     * making the package unavailable, but it doesn't remove the data or the actual
+     * package file.
+     * @hide
+     */
+    public abstract boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked,
+            UserHandle userHandle);
+
+    /**
+     * Returns the blocked state of a package.
+     * @see #setApplicationBlockedSettingAsUser(String, boolean, UserHandle)
+     * @hide
+     */
+    public abstract boolean getApplicationBlockedSettingAsUser(String packageName,
+            UserHandle userHandle);
+
+    /**
      * Return whether the device has been booted into safe mode.
      */
     public abstract boolean isSafeMode();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 34e0c12..b489ee9e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -39,6 +39,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
@@ -50,9 +51,12 @@
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.zip.ZipEntry;
@@ -153,7 +157,8 @@
     private static WeakReference<byte[]> mReadBuffer;
 
     private static boolean sCompatibilityModeEnabled = true;
-    private static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+            PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
 
     static class ParsePackageItemArgs {
         final Package owner;
@@ -268,15 +273,20 @@
                 grantedPermissions, state, UserHandle.getCallingUserId());
     }
 
-    private static boolean checkUseInstalled(int flags, PackageUserState state) {
-        return state.installed || ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0);
+    /**
+     * Returns true if the package is installed and not blocked, or if the caller
+     * explicitly wanted all uninstalled and blocked packages as well.
+     */
+    private static boolean checkUseInstalledOrBlocked(int flags, PackageUserState state) {
+        return (state.installed && !state.blocked)
+                || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
     }
 
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             HashSet<String> grantedPermissions, PackageUserState state, int userId) {
 
-        if (!checkUseInstalled(flags, state)) {
+        if (!checkUseInstalledOrBlocked(flags, state)) {
             return null;
         }
         PackageInfo pi = new PackageInfo();
@@ -470,6 +480,7 @@
     public final static int PARSE_FORWARD_LOCK = 1<<4;
     public final static int PARSE_ON_SDCARD = 1<<5;
     public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
+    public final static int PARSE_IS_PRIVILEGED = 1<<7;
 
     public int getParseError() {
         return mParseError;
@@ -714,6 +725,13 @@
                 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
                 return false;
             }
+
+            // Add the signing KeySet to the system
+            pkg.mSigningKeys = new HashSet<PublicKey>();
+            for (int i=0; i < certs.length; i++) {
+                pkg.mSigningKeys.add(certs[i].getPublicKey());
+            }
+
         } catch (CertificateEncodingException e) {
             Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
             mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
@@ -1027,6 +1045,10 @@
                 if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
                     return null;
                 }
+            } else if (tagName.equals("keys")) {
+                if (!parseKeys(pkg, res, parser, attrs, outError)) {
+                    return null;
+                }
             } else if (tagName.equals("permission-group")) {
                 if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
                     return null;
@@ -1290,6 +1312,9 @@
                 // Just skip this tag
                 XmlUtils.skipCurrentTag(parser);
                 continue;
+            } else if (tagName.equals("supports-input")) {
+                XmlUtils.skipCurrentTag(parser);
+                continue;
                 
             } else if (tagName.equals("eat-comment")) {
                 // Just skip this tag
@@ -1417,18 +1442,29 @@
 */
         boolean required = true; // Optional <uses-permission> not supported
 
+        int maxSdkVersion = 0;
+        TypedValue val = sa.peekValue(
+                com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+        if (val != null) {
+            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+                maxSdkVersion = val.data;
+            }
+        }
+
         sa.recycle();
 
-        if (name != null) {
-            int index = pkg.requestedPermissions.indexOf(name);
-            if (index == -1) {
-                pkg.requestedPermissions.add(name.intern());
-                pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
-            } else {
-                if (pkg.requestedPermissionsRequired.get(index) != required) {
-                    outError[0] = "conflicting <uses-permission> entries";
-                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-                    return false;
+        if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
+            if (name != null) {
+                int index = pkg.requestedPermissions.indexOf(name);
+                if (index == -1) {
+                    pkg.requestedPermissions.add(name.intern());
+                    pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+                } else {
+                    if (pkg.requestedPermissionsRequired.get(index) != required) {
+                        outError[0] = "conflicting <uses-permission> entries";
+                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                        return false;
+                    }
                 }
             }
         }
@@ -1519,7 +1555,88 @@
         }
         return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
     }
-    
+
+    private boolean parseKeys(Package owner, Resources res,
+            XmlPullParser parser, AttributeSet attrs, String[] outError)
+            throws XmlPullParserException, IOException {
+        // we've encountered the 'keys' tag
+        // all the keys and keysets that we want must be defined here
+        // so we're going to iterate over the parser and pull out the things we want
+        int outerDepth = parser.getDepth();
+
+        int type;
+        PublicKey currentKey = null;
+        int currentKeyDepth = -1;
+        Map<PublicKey, Set<String>> definedKeySets = new HashMap<PublicKey, Set<String>>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG) {
+                if (parser.getDepth() == currentKeyDepth) {
+                    currentKey = null;
+                    currentKeyDepth = -1;
+                }
+                continue;
+            }
+            String tagname = parser.getName();
+            if (tagname.equals("publicKey")) {
+                final TypedArray sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.PublicKey);
+                final String encodedKey = sa.getNonResourceString(
+                    com.android.internal.R.styleable.PublicKey_value);
+                currentKey = parsePublicKey(encodedKey);
+                if (currentKey == null) {
+                    Slog.w(TAG, "No valid key in 'publicKey' tag at "
+                            + parser.getPositionDescription());
+                    sa.recycle();
+                    continue;
+                }
+                currentKeyDepth = parser.getDepth();
+                definedKeySets.put(currentKey, new HashSet<String>());
+                sa.recycle();
+            } else if (tagname.equals("keyset")) {
+                if (currentKey == null) {
+                    Slog.i(TAG, "'keyset' not in 'publicKey' tag at "
+                            + parser.getPositionDescription());
+                    continue;
+                }
+                final TypedArray sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.KeySet);
+                final String name = sa.getNonResourceString(
+                    com.android.internal.R.styleable.KeySet_name);
+                definedKeySets.get(currentKey).add(name);
+                sa.recycle();
+            } else if (RIGID_PARSER) {
+                Slog.w(TAG, "Bad element under <keys>: " + parser.getName()
+                        + " at " + mArchiveSourcePath + " "
+                        + parser.getPositionDescription());
+                return false;
+            } else {
+                Slog.w(TAG, "Unknown element under <keys>: " + parser.getName()
+                        + " at " + mArchiveSourcePath + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+            }
+        }
+
+        owner.mKeySetMapping = new HashMap<String, Set<PublicKey>>();
+        for (Map.Entry<PublicKey, Set<String>> e : definedKeySets.entrySet()) {
+            PublicKey key = e.getKey();
+            Set<String> keySetNames = e.getValue();
+            for (String alias : keySetNames) {
+                if (owner.mKeySetMapping.containsKey(alias)) {
+                    owner.mKeySetMapping.get(alias).add(key);
+                } else {
+                    Set<PublicKey> keys = new HashSet<PublicKey>();
+                    keys.add(key);
+                    owner.mKeySetMapping.put(alias, keys);
+                }
+            }
+        }
+
+        return true;
+    }
+
     private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
             XmlPullParser parser, AttributeSet attrs, String[] outError)
         throws XmlPullParserException, IOException {
@@ -1759,7 +1876,8 @@
         }
 
         String manageSpaceActivity = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 0);
+                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
+                Configuration.NATIVE_CONFIG_VERSION);
         if (manageSpaceActivity != null) {
             ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
                     outError);
@@ -1773,7 +1891,8 @@
             // backupAgent, killAfterRestore, and restoreAnyVersion are only relevant
             // if backup is possible for the given application.
             String backupAgent = sa.getNonConfigurationString(
-                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 0);
+                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
+                    Configuration.NATIVE_CONFIG_VERSION);
             if (backupAgent != null) {
                 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
                 if (DEBUG_BACKUP) {
@@ -1894,7 +2013,8 @@
 
         if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
             str = sa.getNonConfigurationString(
-                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 0);
+                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
+                    Configuration.NATIVE_CONFIG_VERSION);
         } else {
             // Some older apps have been seen to use a resource reference
             // here that on older builds was ignored (with a warning).  We
@@ -1909,7 +2029,8 @@
             CharSequence pname;
             if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
                 pname = sa.getNonConfigurationString(
-                        com.android.internal.R.styleable.AndroidManifestApplication_process, 0);
+                        com.android.internal.R.styleable.AndroidManifestApplication_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
             } else {
                 // Some older apps have been seen to use a resource reference
                 // here that on older builds was ignored (with a warning).  We
@@ -2173,7 +2294,8 @@
                 a.info.applicationInfo.uiOptions);
 
         String parentName = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName, 0);
+                com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName,
+                Configuration.NATIVE_CONFIG_VERSION);
         if (parentName != null) {
             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
             if (outError[0] == null) {
@@ -2195,7 +2317,8 @@
         }
 
         str = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 0);
+                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
+                Configuration.NATIVE_CONFIG_VERSION);
         a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
                 owner.applicationInfo.taskAffinity, str, outError);
 
@@ -2335,7 +2458,7 @@
 
             if (parser.getName().equals("intent-filter")) {
                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
-                if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) {
+                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                     return null;
                 }
                 if (intent.countActions() == 0) {
@@ -2345,6 +2468,21 @@
                 } else {
                     a.intents.add(intent);
                 }
+            } else if (!receiver && parser.getName().equals("preferred")) {
+                ActivityIntentInfo intent = new ActivityIntentInfo(a);
+                if (!parseIntent(res, parser, attrs, false, intent, outError)) {
+                    return null;
+                }
+                if (intent.countActions() == 0) {
+                    Slog.w(TAG, "No actions in preferred at "
+                            + mArchiveSourcePath + " "
+                            + parser.getPositionDescription());
+                } else {
+                    if (owner.preferredActivityFilters == null) {
+                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
+                    }
+                    owner.preferredActivityFilters.add(intent);
+                }
             } else if (parser.getName().equals("meta-data")) {
                 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
                         outError)) == null) {
@@ -2389,7 +2527,8 @@
                 com.android.internal.R.styleable.AndroidManifestActivityAlias);
 
         String targetActivity = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 0);
+                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
+                Configuration.NATIVE_CONFIG_VERSION);
         if (targetActivity == null) {
             outError[0] = "<activity-alias> does not specify android:targetActivity";
             sa.recycle();
@@ -2479,7 +2618,7 @@
 
         String parentName = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
-                0);
+                Configuration.NATIVE_CONFIG_VERSION);
         if (parentName != null) {
             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
             if (outError[0] == null) {
@@ -2508,7 +2647,7 @@
 
             if (parser.getName().equals("intent-filter")) {
                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
-                if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) {
+                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                     return null;
                 }
                 if (intent.countActions() == 0) {
@@ -2932,7 +3071,7 @@
 
             if (parser.getName().equals("intent-filter")) {
                 ServiceIntentInfo intent = new ServiceIntentInfo(s);
-                if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) {
+                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                     return null;
                 }
 
@@ -3083,20 +3222,28 @@
             Slog.i(TAG, "verifier " + packageName + " public key was null; skipping");
         }
 
+        PublicKey publicKey = parsePublicKey(encodedPublicKey);
+        if (publicKey != null) {
+            return new VerifierInfo(packageName, publicKey);
+        }
+
+        return null;
+    }
+
+    public static final PublicKey parsePublicKey(String encodedPublicKey) {
         EncodedKeySpec keySpec;
         try {
             final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
             keySpec = new X509EncodedKeySpec(encoded);
         } catch (IllegalArgumentException e) {
-            Slog.i(TAG, "Could not parse verifier " + packageName + " public key; invalid Base64");
+            Slog.i(TAG, "Could not parse verifier public key; invalid Base64");
             return null;
         }
 
         /* First try the key as an RSA key. */
         try {
             final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
-            final PublicKey publicKey = keyFactory.generatePublic(keySpec);
-            return new VerifierInfo(packageName, publicKey);
+            return keyFactory.generatePublic(keySpec);
         } catch (NoSuchAlgorithmException e) {
             Log.wtf(TAG, "Could not parse public key because RSA isn't included in build");
             return null;
@@ -3107,8 +3254,7 @@
         /* Now try it as a DSA key. */
         try {
             final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
-            final PublicKey publicKey = keyFactory.generatePublic(keySpec);
-            return new VerifierInfo(packageName, publicKey);
+            return keyFactory.generatePublic(keySpec);
         } catch (NoSuchAlgorithmException e) {
             Log.wtf(TAG, "Could not parse public key because DSA isn't included in build");
             return null;
@@ -3122,9 +3268,8 @@
     private static final String ANDROID_RESOURCES
             = "http://schemas.android.com/apk/res/android";
 
-    private boolean parseIntent(Resources res,
-            XmlPullParser parser, AttributeSet attrs, int flags,
-            IntentInfo outInfo, String[] outError, boolean isActivity)
+    private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs,
+            boolean allowGlobs, IntentInfo outInfo, String[] outError)
             throws XmlPullParserException, IOException {
 
         TypedArray sa = res.obtainAttributes(attrs,
@@ -3200,6 +3345,28 @@
                     outInfo.addDataScheme(str);
                 }
 
+                str = sa.getNonConfigurationString(
+                        com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
+                if (str != null) {
+                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
+                if (str != null) {
+                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "sspPattern not allowed here; ssp must be literal";
+                        return false;
+                    }
+                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
                 String host = sa.getNonConfigurationString(
                         com.android.internal.R.styleable.AndroidManifestData_host, 0);
                 String port = sa.getNonConfigurationString(
@@ -3223,6 +3390,10 @@
                 str = sa.getNonConfigurationString(
                         com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
                 if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "pathPattern not allowed here; path must be literal";
+                        return false;
+                    }
                     outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
                 }
 
@@ -3284,6 +3455,8 @@
         public ArrayList<String> usesOptionalLibraries = null;
         public String[] usesLibraryFiles = null;
 
+        public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
+
         public ArrayList<String> mOriginalPackages = null;
         public String mRealPackage = null;
         public ArrayList<String> mAdoptPermissions = null;
@@ -3360,6 +3533,12 @@
          */
         public ManifestDigest manifestDigest;
 
+        /**
+         * Data used to feed the KeySetManager
+         */
+        public Set<PublicKey> mSigningKeys;
+        public Map<String, Set<PublicKey>> mKeySetMapping;
+
         public Package(String _name) {
             packageName = _name;
             applicationInfo.packageName = _name;
@@ -3491,7 +3670,8 @@
             if (args.processRes != 0) {
                 CharSequence pname;
                 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
-                    pname = args.sa.getNonConfigurationString(args.processRes, 0);
+                    pname = args.sa.getNonConfigurationString(args.processRes,
+                            Configuration.NATIVE_CONFIG_VERSION);
                 } else {
                     // Some older apps have been seen to use a resource reference
                     // here that on older builds was ignored (with a warning).  We
@@ -3528,18 +3708,15 @@
             }
             return componentName;
         }
-        
-        public String getComponentShortName() {
-            if (componentShortName != null) {
-                return componentShortName;
-            }
-            ComponentName component = getComponentName();
-            if (component != null) {
-                componentShortName = component.flattenToShortString();
-            }
-            return componentShortName;
+
+        public void appendComponentShortName(StringBuilder sb) {
+            ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
         }
-        
+
+        public void printComponentShortName(PrintWriter pw) {
+            ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
+        }
+
         public void setPackageName(String packageName) {
             componentName = null;
             componentShortName = null;
@@ -3611,7 +3788,7 @@
                 return true;
             }
         }
-        if (!state.installed) {
+        if (!state.installed || state.blocked) {
             return true;
         }
         if (state.stopped) {
@@ -3644,6 +3821,11 @@
         } else {
             ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
+        if (state.blocked) {
+            ai.flags |= ApplicationInfo.FLAG_BLOCKED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_BLOCKED;
+        }
         if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
         } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
@@ -3658,7 +3840,7 @@
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!checkUseInstalled(flags, state)) {
+        if (!checkUseInstalledOrBlocked(flags, state)) {
             return null;
         }
         if (!copyNeeded(flags, p, state, null, userId)
@@ -3733,16 +3915,20 @@
         }
 
         public String toString() {
-            return "Activity{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + getComponentShortName() + "}";
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Activity{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            appendComponentShortName(sb);
+            sb.append('}');
+            return sb.toString();
         }
     }
 
     public static final ActivityInfo generateActivityInfo(Activity a, int flags,
             PackageUserState state, int userId) {
         if (a == null) return null;
-        if (!checkUseInstalled(flags, state)) {
+        if (!checkUseInstalledOrBlocked(flags, state)) {
             return null;
         }
         if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
@@ -3770,16 +3956,20 @@
         }
 
         public String toString() {
-            return "Service{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + getComponentShortName() + "}";
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Service{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            appendComponentShortName(sb);
+            sb.append('}');
+            return sb.toString();
         }
     }
 
     public static final ServiceInfo generateServiceInfo(Service s, int flags,
             PackageUserState state, int userId) {
         if (s == null) return null;
-        if (!checkUseInstalled(flags, state)) {
+        if (!checkUseInstalledOrBlocked(flags, state)) {
             return null;
         }
         if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
@@ -3815,16 +4005,20 @@
         }
 
         public String toString() {
-            return "Provider{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + info.name + "}";
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Provider{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            appendComponentShortName(sb);
+            sb.append('}');
+            return sb.toString();
         }
     }
 
     public static final ProviderInfo generateProviderInfo(Provider p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!checkUseInstalled(flags, state)) {
+        if (!checkUseInstalledOrBlocked(flags, state)) {
             return null;
         }
         if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
@@ -3856,9 +4050,13 @@
         }
 
         public String toString() {
-            return "Instrumentation{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + getComponentShortName() + "}";
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Instrumentation{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            appendComponentShortName(sb);
+            sb.append('}');
+            return sb.toString();
         }
     }
 
@@ -3879,6 +4077,7 @@
         public CharSequence nonLocalizedLabel;
         public int icon;
         public int logo;
+        public int preferred;
     }
 
     public final static class ActivityIntentInfo extends IntentInfo {
@@ -3889,9 +4088,13 @@
         }
 
         public String toString() {
-            return "ActivityIntentInfo{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + activity.info.name + "}";
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ActivityIntentInfo{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            activity.appendComponentShortName(sb);
+            sb.append('}');
+            return sb.toString();
         }
     }
 
@@ -3903,9 +4106,13 @@
         }
 
         public String toString() {
-            return "ServiceIntentInfo{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + service.info.name + "}";
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ServiceIntentInfo{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            service.appendComponentShortName(sb);
+            sb.append('}');
+            return sb.toString();
         }
     }
 
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index dcd54fc..94e3f79 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -28,6 +28,7 @@
     public boolean stopped;
     public boolean notLaunched;
     public boolean installed;
+    public boolean blocked; // Is the app restricted by owner / admin
     public int enabled;
 
     public String lastDisableAppCaller;
@@ -37,6 +38,7 @@
 
     public PackageUserState() {
         installed = true;
+        blocked = false;
         enabled = COMPONENT_ENABLED_STATE_DEFAULT;
     }
 
@@ -45,6 +47,7 @@
         stopped = o.stopped;
         notLaunched = o.notLaunched;
         enabled = o.enabled;
+        blocked = o.blocked;
         lastDisableAppCaller = o.lastDisableAppCaller;
         disabledComponents = o.disabledComponents != null
                 ? new HashSet<String>(o.disabledComponents) : null;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 288d55f..875e8de 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -82,7 +82,7 @@
     @GuardedBy("mServicesLock")
     private boolean mPersistentServicesFileDidNotExist;
     @GuardedBy("mServicesLock")
-    private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>();
+    private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
 
     private static class UserServices<V> {
         @GuardedBy("mServicesLock")
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 07117fe..e360e40 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.ComponentName;
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
@@ -247,10 +248,23 @@
 
     public String toString() {
         ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
-        return "ResolveInfo{"
-            + Integer.toHexString(System.identityHashCode(this))
-            + " " + ci.name + " p=" + priority + " o="
-            + preferredOrder + " m=0x" + Integer.toHexString(match) + "}";
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("ResolveInfo{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        ComponentName.appendShortString(sb, ci.packageName, ci.name);
+        if (priority != 0) {
+            sb.append(" p=");
+            sb.append(priority);
+        }
+        if (preferredOrder != 0) {
+            sb.append(" o=");
+            sb.append(preferredOrder);
+        }
+        sb.append(" m=0x");
+        sb.append(Integer.toHexString(match));
+        sb.append('}');
+        return sb.toString();
     }
 
     public int describeContents() {
@@ -328,6 +342,7 @@
             implements Comparator<ResolveInfo> {
         public DisplayNameComparator(PackageManager pm) {
             mPM = pm;
+            mCollator.setStrength(Collator.PRIMARY);
         }
 
         public final int compare(ResolveInfo a, ResolveInfo b) {
@@ -336,10 +351,10 @@
             CharSequence  sb = b.loadLabel(mPM);
             if (sb == null) sb = b.activityInfo.name;
             
-            return sCollator.compare(sa.toString(), sb.toString());
+            return mCollator.compare(sa.toString(), sb.toString());
         }
 
-        private final Collator   sCollator = Collator.getInstance();
+        private final Collator   mCollator = Collator.getInstance();
         private PackageManager   mPM;
     }
 }
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index 7d46710..e4cc77f 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -20,6 +20,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 
+import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -30,7 +31,7 @@
  * opened FileDescriptor that can be used to read the data, as well as the
  * offset and length of that entry's data in the file.
  */
-public class AssetFileDescriptor implements Parcelable {
+public class AssetFileDescriptor implements Parcelable, Closeable {
     /**
      * Length used with {@link #AssetFileDescriptor(ParcelFileDescriptor, long, long)}
      * and {@link #getDeclaredLength} when a length has not been declared.  This means
@@ -122,6 +123,7 @@
     /**
      * Convenience for calling <code>getParcelFileDescriptor().close()</code>.
      */
+    @Override
     public void close() throws IOException {
         mFd.close();
     }
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 28c751c..da35ee9 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -471,8 +471,7 @@
      * Compute the frame Rect for applications runs under compatibility mode.
      *
      * @param dm the display metrics used to compute the frame size.
-     * @param orientation the orientation of the screen.
-     * @param outRect the output parameter which will contain the result.
+     * @param outDm If non-null the width and height will be set to their scaled values.
      * @return Returns the scaling factor for the window.
      */
     public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) {
@@ -518,6 +517,9 @@
 
     @Override
     public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
         try {
             CompatibilityInfo oc = (CompatibilityInfo)o;
             if (mCompatibilityFlags != oc.mCompatibilityFlags) return false;
@@ -579,10 +581,12 @@
 
     public static final Parcelable.Creator<CompatibilityInfo> CREATOR
             = new Parcelable.Creator<CompatibilityInfo>() {
+        @Override
         public CompatibilityInfo createFromParcel(Parcel source) {
             return new CompatibilityInfo(source);
         }
 
+        @Override
         public CompatibilityInfo[] newArray(int size) {
             return new CompatibilityInfo[size];
         }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6318e38..48b6fca 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -544,7 +544,40 @@
      * @hide Internal book-keeping.
      */
     public int seq;
-    
+
+    /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_MCC = 0x0001;
+    /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_MNC = 0x0002;
+    /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_LOCALE = 0x0004;
+    /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008;
+    /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_KEYBOARD = 0x0010;
+    /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU
+     * ARE SURE. */
+    public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020;
+    /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_NAVIGATION = 0x0040;
+    /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_ORIENTATION = 0x0080;
+    /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_DENSITY = 0x0100;
+    /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200;
+    /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_VERSION = 0x0400;
+    /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800;
+    /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */
+    public static final int NATIVE_CONFIG_UI_MODE = 0x1000;
+    /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU
+     * ARE SURE. */
+    public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
+    /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
+    public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
+
     /**
      * Construct an invalid Configuration.  You must call {@link #setToDefaults}
      * for this object to be valid.  {@more}
@@ -786,10 +819,16 @@
             // 2 most significant bits in screenLayout).
             setLayoutDirection(locale);
         }
+        final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
+        if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
+                deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
+            screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir;
+            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+        }
         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
         {
-            userSetLocale = true;
             changed |= ActivityInfo.CONFIG_LOCALE;
+            userSetLocale = true;
         }
         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
                 && touchscreen != delta.touchscreen) {
@@ -933,6 +972,11 @@
             changed |= ActivityInfo.CONFIG_LOCALE;
             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
         }
+        final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
+        if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
+                deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
+            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+        }
         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
                 && touchscreen != delta.touchscreen) {
             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
@@ -1005,7 +1049,7 @@
     public static boolean needNewResources(int configChanges, int interestingChanges) {
         return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
     }
-    
+
     /**
      * @hide Return true if the sequence of 'other' is better than this.  Assumes
      * that 'this' is your current sequence and 'other' is a new one you have
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 42f4faf..cd5b5d2f 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,8 +16,6 @@
 
 package android.content.res;
 
-import android.os.Trace;
-import android.view.View;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -30,12 +28,15 @@
 import android.graphics.drawable.Drawable.ConstantState;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TypedValue;
 import android.util.LongSparseArray;
+import android.view.DisplayAdjustments;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -100,11 +101,11 @@
     /*package*/ final Configuration mTmpConfig = new Configuration();
     /*package*/ TypedValue mTmpValue = new TypedValue();
     /*package*/ final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
-            = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
+            = new LongSparseArray<WeakReference<Drawable.ConstantState> >(0);
     /*package*/ final LongSparseArray<WeakReference<ColorStateList> > mColorStateListCache
-            = new LongSparseArray<WeakReference<ColorStateList> >();
+            = new LongSparseArray<WeakReference<ColorStateList> >(0);
     /*package*/ final LongSparseArray<WeakReference<Drawable.ConstantState> > mColorDrawableCache
-            = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
+            = new LongSparseArray<WeakReference<Drawable.ConstantState> >(0);
     /*package*/ boolean mPreloading;
 
     /*package*/ TypedArray mCachedStyledAttributes = null;
@@ -118,8 +119,9 @@
     private final Configuration mConfiguration = new Configuration();
     /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
     private NativePluralRules mPluralRule;
-    
-    private CompatibilityInfo mCompatibilityInfo;
+
+    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+    private WeakReference<IBinder> mToken;
 
     static {
         sPreloadedDrawables = new LongSparseArray[2];
@@ -174,7 +176,7 @@
      *               selecting/computing resource values (optional).
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
-        this(assets, metrics, config, null);
+        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
     }
 
     /**
@@ -185,15 +187,18 @@
      *                selecting/computing resource values.
      * @param config Desired device configuration to consider when 
      *               selecting/computing resource values (optional).
-     * @param compInfo this resource's compatibility info. It will use the default compatibility
-     *  info when it's null.
+     * @param compatInfo this resource's compatibility info. Must not be null.
+     * @param token The Activity token for determining stack affiliation. Usually null.
      * @hide
      */
-    public Resources(AssetManager assets, DisplayMetrics metrics,
-            Configuration config, CompatibilityInfo compInfo) {
+    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
+            CompatibilityInfo compatInfo, IBinder token) {
         mAssets = assets;
         mMetrics.setToDefaults();
-        mCompatibilityInfo = compInfo;
+        if (compatInfo != null) {
+            mCompatibilityInfo = compatInfo;
+        }
+        mToken = new WeakReference<IBinder>(token);
         updateConfiguration(config, metrics);
         assets.ensureStringBlocks();
     }
@@ -1533,9 +1538,8 @@
             // it would be cleaner and more maintainble to just be
             // consistently dealing with a compatible display everywhere in
             // the framework.
-            if (mCompatibilityInfo != null) {
-                mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
-            }
+            mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
+
             int configChanges = 0xfffffff;
             if (config != null) {
                 mTmpConfig.setTo(config);
@@ -1543,9 +1547,9 @@
                 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
                     density = mMetrics.noncompatDensityDpi;
                 }
-                if (mCompatibilityInfo != null) {
-                    mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
-                }
+
+                mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+
                 if (mTmpConfig.locale == null) {
                     mTmpConfig.locale = Locale.getDefault();
                     mTmpConfig.setLayoutDirection(mTmpConfig.locale);
@@ -1665,13 +1669,6 @@
     }
 
     /**
-     * @hide
-     */
-    public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
-        updateSystemConfiguration(config, metrics, null);
-    }
-    
-    /**
      * Return the current display metrics that are in effect for this resource 
      * object.  The returned object should be treated as read-only.
      * 
@@ -1701,8 +1698,7 @@
      * @hide
      */
     public CompatibilityInfo getCompatibilityInfo() {
-        return mCompatibilityInfo != null ? mCompatibilityInfo
-                : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+        return mCompatibilityInfo;
     }
 
     /**
@@ -1710,8 +1706,10 @@
      * @hide
      */
     public void setCompatibilityInfo(CompatibilityInfo ci) {
-        mCompatibilityInfo = ci;
-        updateConfiguration(mConfiguration, mMetrics);
+        if (ci != null) {
+            mCompatibilityInfo = ci;
+            updateConfiguration(mConfiguration, mMetrics);
+        }
     }
     
     /**
@@ -1985,6 +1983,13 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
+        return sPreloadedDrawables[0];
+    }
+
     private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
             int resourceId, String name) {
         // We allow preloading of resources even if they vary by font scale (which
@@ -2404,6 +2409,5 @@
         mMetrics.setToDefaults();
         updateConfiguration(null, null);
         mAssets.ensureStringBlocks();
-        mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
     }
 }
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
new file mode 100644
index 0000000..53e0f2c
--- /dev/null
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -0,0 +1,89 @@
+/*
+ * 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 android.content.res;
+
+import android.os.IBinder;
+
+/** @hide */
+public final class ResourcesKey {
+    final String mResDir;
+    final float mScale;
+    private final int mHash;
+    private final IBinder mToken;
+
+    public final int mDisplayId;
+    public final Configuration mOverrideConfiguration = new Configuration();
+
+    public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
+            float scale, IBinder token) {
+        mResDir = resDir;
+        mDisplayId = displayId;
+        if (overrideConfiguration != null) {
+            mOverrideConfiguration.setTo(overrideConfiguration);
+        }
+        mScale = scale;
+        mToken = token;
+
+        int hash = 17;
+        hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
+        hash = 31 * hash + mDisplayId;
+        hash = 31 * hash + (mOverrideConfiguration != null
+                ? mOverrideConfiguration.hashCode() : 0);
+        hash = 31 * hash + Float.floatToIntBits(mScale);
+        mHash = hash;
+    }
+
+    public boolean hasOverrideConfiguration() {
+        return !Configuration.EMPTY.equals(mOverrideConfiguration);
+    }
+
+    @Override
+    public int hashCode() {
+        return mHash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof ResourcesKey)) {
+            return false;
+        }
+        ResourcesKey peer = (ResourcesKey) obj;
+        if (!mResDir.equals(peer.mResDir)) {
+            return false;
+        }
+        if (mDisplayId != peer.mDisplayId) {
+            return false;
+        }
+        if (mOverrideConfiguration != peer.mOverrideConfiguration) {
+            if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
+                return false;
+            }
+            if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
+                return false;
+            }
+        }
+        if (mScale != peer.mScale) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return Integer.toHexString(mHash);
+    }
+}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 27dddd4..83d48aa 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import android.content.pm.ActivityInfo;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -170,8 +171,8 @@
      * 
      * @param index Index of attribute to retrieve.
      * @param allowedChangingConfigs Bit mask of configurations from
-     * ActivityInfo that are allowed to change.
-     * 
+     * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
+     *
      * @return String holding string data.  Any styling information is
      * removed.  Returns null if the attribute is not defined.
      */
diff --git a/core/java/android/content/res/XmlResourceParser.java b/core/java/android/content/res/XmlResourceParser.java
index c59e6d4..5af49d4 100644
--- a/core/java/android/content/res/XmlResourceParser.java
+++ b/core/java/android/content/res/XmlResourceParser.java
@@ -26,7 +26,7 @@
  * an additional close() method on this interface for the client to indicate
  * when it is done reading the resource.
  */
-public interface XmlResourceParser extends XmlPullParser, AttributeSet {
+public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
     /**
      * Close this interface to the resource.  Calls on the interface are no
      * longer value after this call.
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 300b4d1..b5b89dd 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -369,7 +369,9 @@
     }
 
     public Uri getNotificationUri() {
-        return mNotifyUri;
+        synchronized (mSelfObserverLock) {
+            return mNotifyUri;
+        }
     }
 
     public boolean getWantsAllOnMoveCalls() {
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index 907833d..fc2a885 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -25,9 +25,12 @@
 /**
  * This interface provides random read-write access to the result set returned
  * by a database query.
- *
+ * <p>
  * Cursor implementations are not required to be synchronized so code using a Cursor from multiple
  * threads should perform its own synchronization when using the Cursor.
+ * </p><p>
+ * Implementations should subclass {@link AbstractCursor}.
+ * </p>
  */
 public interface Cursor extends Closeable {
     /*
@@ -425,6 +428,16 @@
     void setNotificationUri(ContentResolver cr, Uri uri);
 
     /**
+     * Return the URI at which notifications of changes in this Cursor's data
+     * will be delivered, as previously set by {@link #setNotificationUri}.
+     * @return Returns a URI that can be used with
+     * {@link ContentResolver#registerContentObserver(android.net.Uri, boolean, ContentObserver)
+     * ContentResolver.registerContentObserver} to find out about changes to this Cursor's
+     * data.  May be null if no notification URI has been set.
+     */
+    Uri getNotificationUri();
+
+    /**
      * onMove() will only be called across processes if this method returns true.
      * @return whether all cursor movement should result in a call to onMove().
      */
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 7baeb8c..d8fcb17 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -194,6 +194,10 @@
         mCursor.setNotificationUri(cr, uri);        
     }
 
+    public Uri getNotificationUri() {
+        return mCursor.getNotificationUri();
+    }
+
     public void unregisterContentObserver(ContentObserver observer) {
         mCursor.unregisterContentObserver(observer);        
     }
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index 6e68b6b..5e107f2 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -83,11 +83,10 @@
      *  row
      */
     public RowBuilder newRow() {
-        rowCount++;
-        int endIndex = rowCount * columnCount;
+        final int row = rowCount++;
+        final int endIndex = rowCount * columnCount;
         ensureCapacity(endIndex);
-        int start = endIndex - columnCount;
-        return new RowBuilder(start, endIndex);
+        return new RowBuilder(row);
     }
 
     /**
@@ -180,18 +179,29 @@
     }
 
     /**
-     * Builds a row, starting from the left-most column and adding one column
-     * value at a time. Follows the same ordering as the column names specified
-     * at cursor construction time.
+     * Builds a row of values using either of these approaches:
+     * <ul>
+     * <li>Values can be added with explicit column ordering using
+     * {@link #add(Object)}, which starts from the left-most column and adds one
+     * column value at a time. This follows the same ordering as the column
+     * names specified at cursor construction time.
+     * <li>Column and value pairs can be offered for possible inclusion using
+     * {@link #add(String, Object)}. If the cursor includes the given column,
+     * the value will be set for that column, otherwise the value is ignored.
+     * This approach is useful when matching data to a custom projection.
+     * </ul>
+     * Undefined values are left as {@code null}.
      */
     public class RowBuilder {
-
-        private int index;
+        private final int row;
         private final int endIndex;
 
-        RowBuilder(int index, int endIndex) {
-            this.index = index;
-            this.endIndex = endIndex;
+        private int index;
+
+        RowBuilder(int row) {
+            this.row = row;
+            this.index = row * columnCount;
+            this.endIndex = index + columnCount;
         }
 
         /**
@@ -210,6 +220,21 @@
             data[index++] = columnValue;
             return this;
         }
+
+        /**
+         * Offer value for possible inclusion if this cursor defines the given
+         * column. Columns not defined by the cursor are silently ignored.
+         *
+         * @return this builder to support chaining
+         */
+        public RowBuilder add(String columnName, Object value) {
+            for (int i = 0; i < columnNames.length; i++) {
+                if (columnName.equals(columnNames[i])) {
+                    data[(row * columnCount) + i] = value;
+                }
+            }
+            return this;
+        }
     }
 
     // AbstractCursor implementation.
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index b6c260f..2d47f28 100644
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -486,6 +486,7 @@
 
     @Override
     protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
         cancelClearAnimation();
     }
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 4e51080..feb47aa 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -31,6 +31,11 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.RSIllegalArgumentException;
+import android.renderscript.Type;
 import android.util.Log;
 import android.text.TextUtils;
 import android.view.Surface;
@@ -152,6 +157,7 @@
     private PictureCallback mRawImageCallback;
     private PictureCallback mJpegCallback;
     private PreviewCallback mPreviewCallback;
+    private boolean mUsingPreviewAllocation;
     private PictureCallback mPostviewCallback;
     private AutoFocusCallback mAutoFocusCallback;
     private AutoFocusMoveCallback mAutoFocusMoveCallback;
@@ -327,6 +333,7 @@
         mJpegCallback = null;
         mPreviewCallback = null;
         mPostviewCallback = null;
+        mUsingPreviewAllocation = false;
         mZoomListener = null;
 
         Looper looper;
@@ -587,6 +594,9 @@
         mPreviewCallback = cb;
         mOneShot = false;
         mWithBuffer = false;
+        if (cb != null) {
+            mUsingPreviewAllocation = false;
+        }
         // Always use one-shot mode. We fake camera preview mode by
         // doing one-shot preview continuously.
         setHasPreviewCallback(cb != null, false);
@@ -610,6 +620,9 @@
         mPreviewCallback = cb;
         mOneShot = true;
         mWithBuffer = false;
+        if (cb != null) {
+            mUsingPreviewAllocation = false;
+        }
         setHasPreviewCallback(cb != null, false);
     }
 
@@ -645,6 +658,9 @@
         mPreviewCallback = cb;
         mOneShot = false;
         mWithBuffer = true;
+        if (cb != null) {
+            mUsingPreviewAllocation = false;
+        }
         setHasPreviewCallback(cb != null, true);
     }
 
@@ -744,6 +760,134 @@
     private native final void _addCallbackBuffer(
                                 byte[] callbackBuffer, int msgType);
 
+    /**
+     * <p>Create a {@link android.renderscript RenderScript}
+     * {@link android.renderscript.Allocation Allocation} to use as a
+     * destination of preview callback frames. Use
+     * {@link #setPreviewCallbackAllocation setPreviewCallbackAllocation} to use
+     * the created Allocation as a destination for camera preview frames.</p>
+     *
+     * <p>The Allocation will be created with a YUV type, and its contents must
+     * be accessed within Renderscript with the {@code rsGetElementAtYuv_*}
+     * accessor methods. Its size will be based on the current
+     * {@link Parameters#getPreviewSize preview size} configured for this
+     * camera.</p>
+     *
+     * @param rs the RenderScript context for this Allocation.
+     * @param usage additional usage flags to set for the Allocation. The usage
+     *   flag {@link android.renderscript.Allocation#USAGE_IO_INPUT} will always
+     *   be set on the created Allocation, but additional flags may be provided
+     *   here.
+     * @return a new YUV-type Allocation with dimensions equal to the current
+     *   preview size.
+     * @throws RSIllegalArgumentException if the usage flags are not compatible
+     *   with an YUV Allocation.
+     * @see #setPreviewCallbackAllocation
+     * @hide
+     */
+    public final Allocation createPreviewAllocation(RenderScript rs, int usage)
+            throws RSIllegalArgumentException {
+        Parameters p = getParameters();
+        Size previewSize = p.getPreviewSize();
+        Type.Builder yuvBuilder = new Type.Builder(rs,
+                Element.createPixel(rs,
+                        Element.DataType.UNSIGNED_8,
+                        Element.DataKind.PIXEL_YUV));
+        // Use YV12 for wide compatibility. Changing this requires also
+        // adjusting camera service's format selection.
+        yuvBuilder.setYuvFormat(ImageFormat.YV12);
+        yuvBuilder.setX(previewSize.width);
+        yuvBuilder.setY(previewSize.height);
+
+        Allocation a = Allocation.createTyped(rs, yuvBuilder.create(),
+                usage | Allocation.USAGE_IO_INPUT);
+
+        return a;
+    }
+
+    /**
+     * <p>Set an {@link android.renderscript.Allocation Allocation} as the
+     * target of preview callback data. Use this method for efficient processing
+     * of camera preview data with RenderScript. The Allocation must be created
+     * with the {@link #createPreviewAllocation createPreviewAllocation }
+     * method.</p>
+     *
+     * <p>Setting a preview allocation will disable any active preview callbacks
+     * set by {@link #setPreviewCallback setPreviewCallback} or
+     * {@link #setPreviewCallbackWithBuffer setPreviewCallbackWithBuffer}, and
+     * vice versa. Using a preview allocation still requires an active standard
+     * preview target to be set, either with
+     * {@link #setPreviewTexture setPreviewTexture} or
+     * {@link #setPreviewDisplay setPreviewDisplay}.</p>
+     *
+     * <p>To be notified when new frames are available to the Allocation, use
+     * {@link android.renderscript.Allocation#setIoInputNotificationHandler Allocation.setIoInputNotificationHandler}. To
+     * update the frame currently accessible from the Allocation to the latest
+     * preview frame, call
+     * {@link android.renderscript.Allocation#ioReceive Allocation.ioReceive}.</p>
+     *
+     * <p>To disable preview into the Allocation, call this method with a
+     * {@code null} parameter.</p>
+     *
+     * <p>Once a preview allocation is set, the preview size set by
+     * {@link Parameters#setPreviewSize setPreviewSize} cannot be changed. If
+     * you wish to change the preview size, first remove the preview allocation
+     * by calling {@code setPreviewCallbackAllocation(null)}, then change the
+     * preview size, create a new preview Allocation with
+     * {@link #createPreviewAllocation createPreviewAllocation}, and set it as
+     * the new preview callback allocation target.</p>
+     *
+     * <p>If you are using the preview data to create video or still images,
+     * strongly consider using {@link android.media.MediaActionSound} to
+     * properly indicate image capture or recording start/stop to the user.</p>
+     *
+     * @param previewAllocation the allocation to use as destination for preview
+     * @throws IOException if configuring the camera to use the Allocation for
+     *   preview fails.
+     * @throws IllegalArgumentException if the Allocation's dimensions or other
+     *   parameters don't meet the requirements.
+     * @see #createPreviewAllocation
+     * @see #setPreviewCallback
+     * @see #setPreviewCallbackWithBuffer
+     * @hide
+     */
+    public final void setPreviewCallbackAllocation(Allocation previewAllocation)
+            throws IOException {
+        Surface previewSurface = null;
+        if (previewAllocation != null) {
+             Parameters p = getParameters();
+             Size previewSize = p.getPreviewSize();
+             if (previewSize.width != previewAllocation.getType().getX() ||
+                     previewSize.height != previewAllocation.getType().getY()) {
+                 throw new IllegalArgumentException(
+                     "Allocation dimensions don't match preview dimensions: " +
+                     "Allocation is " +
+                     previewAllocation.getType().getX() +
+                     ", " +
+                     previewAllocation.getType().getY() +
+                     ". Preview is " + previewSize.width + ", " +
+                     previewSize.height);
+             }
+             if ((previewAllocation.getUsage() &
+                             Allocation.USAGE_IO_INPUT) == 0) {
+                 throw new IllegalArgumentException(
+                     "Allocation usage does not include USAGE_IO_INPUT");
+             }
+             if (previewAllocation.getType().getElement().getDataKind() !=
+                     Element.DataKind.PIXEL_YUV) {
+                 throw new IllegalArgumentException(
+                     "Allocation is not of a YUV type");
+             }
+             previewSurface = previewAllocation.getSurface();
+             mUsingPreviewAllocation = true;
+         } else {
+             mUsingPreviewAllocation = false;
+         }
+         setPreviewCallbackSurface(previewSurface);
+    }
+
+    private native final void setPreviewCallbackSurface(Surface s);
+
     private class EventHandler extends Handler
     {
         private Camera mCamera;
@@ -1492,6 +1636,17 @@
      * @see #getParameters()
      */
     public void setParameters(Parameters params) {
+        // If using preview allocations, don't allow preview size changes
+        if (mUsingPreviewAllocation) {
+            Size newPreviewSize = params.getPreviewSize();
+            Size currentPreviewSize = getParameters().getPreviewSize();
+            if (newPreviewSize.width != currentPreviewSize.width ||
+                    newPreviewSize.height != currentPreviewSize.height) {
+                throw new IllegalStateException("Cannot change preview size" +
+                        " while a preview allocation is configured.");
+            }
+        }
+
         native_setParameters(params.flatten());
     }
 
@@ -2614,21 +2769,24 @@
          * JPEG {@link PictureCallback}. The camera driver may set orientation
          * in the EXIF header without rotating the picture. Or the driver may
          * rotate the picture and the EXIF thumbnail. If the Jpeg picture is
-         * rotated, the orientation in the EXIF header will be missing or 1
-         * (row #0 is top and column #0 is left side).
+         * rotated, the orientation in the EXIF header will be missing or 1 (row
+         * #0 is top and column #0 is left side).
          *
-         * <p>If applications want to rotate the picture to match the orientation
-         * of what users see, apps should use {@link
-         * android.view.OrientationEventListener} and {@link CameraInfo}.
-         * The value from OrientationEventListener is relative to the natural
-         * orientation of the device. CameraInfo.orientation is the angle
-         * between camera orientation and natural device orientation. The sum
-         * of the two is the rotation angle for back-facing camera. The
-         * difference of the two is the rotation angle for front-facing camera.
-         * Note that the JPEG pictures of front-facing cameras are not mirrored
-         * as in preview display.
+         * <p>
+         * If applications want to rotate the picture to match the orientation
+         * of what users see, apps should use
+         * {@link android.view.OrientationEventListener} and
+         * {@link android.hardware.Camera.CameraInfo}. The value from
+         * OrientationEventListener is relative to the natural orientation of
+         * the device. CameraInfo.orientation is the angle between camera
+         * orientation and natural device orientation. The sum of the two is the
+         * rotation angle for back-facing camera. The difference of the two is
+         * the rotation angle for front-facing camera. Note that the JPEG
+         * pictures of front-facing cameras are not mirrored as in preview
+         * display.
          *
-         * <p>For example, suppose the natural orientation of the device is
+         * <p>
+         * For example, suppose the natural orientation of the device is
          * portrait. The device is rotated 270 degrees clockwise, so the device
          * orientation is 270. Suppose a back-facing camera sensor is mounted in
          * landscape and the top side of the camera sensor is aligned with the
diff --git a/core/java/android/hardware/CameraInfo.aidl b/core/java/android/hardware/CameraInfo.aidl
new file mode 100644
index 0000000..e21e694
--- /dev/null
+++ b/core/java/android/hardware/CameraInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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 android.hardware;
+
+/** @hide */
+parcelable CameraInfo;
diff --git a/core/java/android/hardware/CameraInfo.java b/core/java/android/hardware/CameraInfo.java
new file mode 100644
index 0000000..53da0ce
--- /dev/null
+++ b/core/java/android/hardware/CameraInfo.java
@@ -0,0 +1,63 @@
+/*
+ * 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 android.hardware;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about a camera
+ *
+ * @hide
+ */
+public class CameraInfo implements Parcelable {
+    // Can't parcel nested classes, so make this a top level class that composes
+    // CameraInfo.
+    public Camera.CameraInfo info = new Camera.CameraInfo();
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(info.facing);
+        out.writeInt(info.orientation);
+    }
+
+    public void readFromParcel(Parcel in) {
+        info.facing = in.readInt();
+        info.orientation = in.readInt();
+    }
+
+    public static final Parcelable.Creator<CameraInfo> CREATOR =
+            new Parcelable.Creator<CameraInfo>() {
+        @Override
+        public CameraInfo createFromParcel(Parcel in) {
+            CameraInfo info = new CameraInfo();
+            info.readFromParcel(in);
+
+            return info;
+        }
+
+        @Override
+        public CameraInfo[] newArray(int size) {
+            return new CameraInfo[size];
+        }
+    };
+};
diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
new file mode 100644
index 0000000..77087814
--- /dev/null
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -0,0 +1,156 @@
+/*
+ * 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 android.hardware;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * Class that operates consumer infrared on the device.
+ *
+ * <p>
+ * To obtain an instance of the system infrared transmitter, call
+ * {@link android.content.Context#getSystemService(java.lang.String)
+ * Context.getSystemService()} with
+ * {@link android.content.Context#CONSUMER_IR_SERVICE} as the argument.
+ * </p>
+ */
+public final class ConsumerIrManager {
+    private static final String TAG = "ConsumerIr";
+
+    private final String mPackageName;
+    private final IConsumerIrService mService;
+
+    /**
+     * @hide to prevent subclassing from outside of the framework
+     */
+    public ConsumerIrManager(Context context) {
+        mPackageName = context.getPackageName();
+        mService = IConsumerIrService.Stub.asInterface(
+                ServiceManager.getService(Context.CONSUMER_IR_SERVICE));
+    }
+
+    /**
+     * Check whether the device has an infrared emitter.
+     *
+     * @return true if the device has an infrared emitter, else false.
+     */
+    public boolean hasIrEmitter() {
+        if (mService == null) {
+            Log.w(TAG, "no consumer ir service.");
+            return false;
+        }
+
+        try {
+            return mService.hasIrEmitter();
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Tansmit and infrared pattern
+     * <p>
+     * This method is synchronous; when it returns the pattern has
+     * been transmitted. Only patterns shorter than 2 seconds will
+     * be transmitted.
+     * </p>
+     *
+     * @param carrierFrequency The IR carrier frequency in Hertz.
+     * @param pattern The alternating on/off pattern in microseconds to transmit.
+     */
+    public void transmit(int carrierFrequency, int[] pattern) {
+        if (mService == null) {
+            Log.w(TAG, "failed to transmit; no consumer ir service.");
+            return;
+        }
+
+        try {
+            mService.transmit(mPackageName, carrierFrequency, pattern);
+        } catch (RemoteException e) {
+            Log.w(TAG, "failed to transmit.", e);
+        }
+    }
+
+    /**
+     * Represents a range of carrier frequencies (inclusive) on which the
+     * infrared transmitter can transmit
+     */
+    public final class CarrierFrequencyRange {
+        private final int mMinFrequency;
+        private final int mMaxFrequency;
+
+        /**
+         * Create a segment of a carrier frequency range.
+         *
+         * @param min The minimum transmittable frequency in this range segment.
+         * @param max The maximum transmittable frequency in this range segment.
+         */
+        public CarrierFrequencyRange(int min, int max) {
+            mMinFrequency = min;
+            mMaxFrequency = max;
+        }
+
+        /**
+         * Get the minimum (inclusive) frequency in this range segment.
+         */
+        public int getMinFrequency() {
+            return mMinFrequency;
+        }
+
+        /**
+         * Get the maximum (inclusive) frequency in this range segment.
+         */
+        public int getMaxFrequency() {
+            return mMaxFrequency;
+        }
+    };
+
+    /**
+     * Query the infrared transmitter's supported carrier frequencies
+     *
+     * @return an array of
+     * {@link android.hardware.ConsumerIrManager.CarrierFrequencyRange}
+     * objects representing the ranges that the transmitter can support, or
+     * null if there was an error communicating with the Consumer IR Service.
+     */
+    public CarrierFrequencyRange[] getCarrierFrequencies() {
+        if (mService == null) {
+            Log.w(TAG, "no consumer ir service.");
+            return null;
+        }
+
+        try {
+            int[] freqs = mService.getCarrierFrequencies();
+            if (freqs.length % 2 != 0) {
+                Log.w(TAG, "consumer ir service returned an uneven number of frequencies.");
+                return null;
+            }
+            CarrierFrequencyRange[] range = new CarrierFrequencyRange[freqs.length / 2];
+
+            for (int i = 0; i < freqs.length; i += 2) {
+                range[i / 2] = new CarrierFrequencyRange(freqs[i], freqs[i+1]);
+            }
+            return range;
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+}
diff --git a/core/java/android/hardware/FlushCompleteListener.java b/core/java/android/hardware/FlushCompleteListener.java
new file mode 100644
index 0000000..fbdf4c8
--- /dev/null
+++ b/core/java/android/hardware/FlushCompleteListener.java
@@ -0,0 +1,34 @@
+/*
+ * 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.hardware;
+
+/**
+ * Used for receiving a notification when a flush() has been successfully completed.
+ */
+public interface FlushCompleteListener {
+    /**
+     * Called after flush() is completed. This flush() could have been initiated by this application
+     * or some other application. All the events in the batch at the point when the flush was called
+     * have been delivered to the applications registered for those sensor events.
+     * <p>
+     *
+     * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called.
+     *
+     * @see android.hardware.SensorManager#flush(Sensor)
+     */
+    public void onFlushCompleted(Sensor sensor);
+}
diff --git a/core/java/android/hardware/ICamera.aidl b/core/java/android/hardware/ICamera.aidl
new file mode 100644
index 0000000..d4f64f8
--- /dev/null
+++ b/core/java/android/hardware/ICamera.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.hardware;
+
+/** @hide */
+interface ICamera
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/ICamera.h
+     */
+    void disconnect();
+}
diff --git a/core/java/android/hardware/ICameraClient.aidl b/core/java/android/hardware/ICameraClient.aidl
new file mode 100644
index 0000000..d7877b4
--- /dev/null
+++ b/core/java/android/hardware/ICameraClient.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.hardware;
+
+/** @hide */
+interface ICameraClient
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/ICameraClient.h
+     */
+    // TODO: consider implementing this.
+}
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
new file mode 100644
index 0000000..542af6a
--- /dev/null
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -0,0 +1,64 @@
+/*
+ * 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 android.hardware;
+
+import android.hardware.ICamera;
+import android.hardware.ICameraClient;
+import android.hardware.IProCameraUser;
+import android.hardware.IProCameraCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.BinderHolder;
+import android.hardware.ICameraServiceListener;
+import android.hardware.CameraInfo;
+
+/** @hide */
+interface ICameraService
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/ICameraService.h
+     */
+    int getNumberOfCameras();
+
+    // rest of 'int' return values in this file are actually status_t
+
+    int getCameraInfo(int cameraId, out CameraInfo info);
+
+    int connect(ICameraClient client, int cameraId,
+                    String clientPackageName,
+                    int clientUid,
+                    // Container for an ICamera object
+                    out BinderHolder device);
+
+    int connectPro(IProCameraCallbacks callbacks, int cameraId,
+                              String clientPackageName,
+                              int clientUid,
+                              // Container for an IProCameraUser object
+                              out BinderHolder device);
+
+    int connectDevice(ICameraDeviceCallbacks callbacks, int cameraId,
+                              String clientPackageName,
+                              int clientUid,
+                              // Container for an ICameraDeviceUser object
+                              out BinderHolder device);
+
+    int addListener(ICameraServiceListener listener);
+    int removeListener(ICameraServiceListener listener);
+
+    int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
+}
diff --git a/core/java/android/hardware/ICameraServiceListener.aidl b/core/java/android/hardware/ICameraServiceListener.aidl
new file mode 100644
index 0000000..c5484965
--- /dev/null
+++ b/core/java/android/hardware/ICameraServiceListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.hardware;
+
+/** @hide */
+interface ICameraServiceListener
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
+     */
+    void onStatusChanged(int status, int cameraId);
+}
diff --git a/core/java/android/hardware/IConsumerIrService.aidl b/core/java/android/hardware/IConsumerIrService.aidl
new file mode 100644
index 0000000..c79bd19
--- /dev/null
+++ b/core/java/android/hardware/IConsumerIrService.aidl
@@ -0,0 +1,26 @@
+/**
+ * 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 android.hardware;
+
+/** {@hide} */
+interface IConsumerIrService
+{
+    boolean hasIrEmitter();
+    void transmit(String packageName, int carrierFrequency, in int[] pattern);
+    int[] getCarrierFrequencies();
+}
+
diff --git a/core/java/android/hardware/IProCameraCallbacks.aidl b/core/java/android/hardware/IProCameraCallbacks.aidl
new file mode 100644
index 0000000..a09b452
--- /dev/null
+++ b/core/java/android/hardware/IProCameraCallbacks.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.hardware;
+
+/** @hide */
+interface IProCameraCallbacks
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/IProCameraCallbacks.h
+     */
+    // TODO: consider implementing this.
+}
diff --git a/core/java/android/hardware/IProCameraUser.aidl b/core/java/android/hardware/IProCameraUser.aidl
new file mode 100644
index 0000000..eacb0f4
--- /dev/null
+++ b/core/java/android/hardware/IProCameraUser.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.hardware;
+
+/** @hide */
+interface IProCameraUser
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/IProCameraUser.h
+     */
+    void disconnect();
+}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 5cc1150..89a5819 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -129,7 +129,7 @@
      * due to distortions that arise from magnetized iron, steel or permanent magnets on the
      * device) is not considered in the given sensor values. However, such hard iron bias values
      * are returned to you separately in the result {@link android.hardware.SensorEvent#values}
-     * so you may use them for custom calibrations. 
+     * so you may use them for custom calibrations.
      * <p>Also, no periodic calibration is performed
      * (i.e. there are no discontinuities in the data stream while using this sensor) and
      * assumptions that the magnetic field is due to the Earth's poles is avoided, but
@@ -174,7 +174,7 @@
     public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
 
     /**
-     * A constant describing the significant motion trigger sensor.
+     * A constant describing a significant motion trigger sensor.
      * <p>
      * It triggers when an event occurs and then automatically disables
      * itself. The sensor continues to operate while the device is asleep
@@ -186,6 +186,42 @@
     public static final int TYPE_SIGNIFICANT_MOTION = 17;
 
     /**
+     * A constant describing a step detector sensor.
+     * <p>
+     * A sensor of this type triggers an event each time a step is taken by the user. The only
+     * allowed value to return is 1.0 and an event is generated for each step. Like with any other
+     * event, the timestamp indicates when the event (here the step) occurred, this corresponds to
+     * when the foot hit the ground, generating a high variation in acceleration.
+     * <p>
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     */
+    public static final int TYPE_STEP_DETECTOR = 18;
+
+    /**
+     * A constant describing a step counter sensor.
+     * <p>
+     * A sensor of this type returns the number of steps taken by the user since the last reboot
+     * while activated. The value is returned as a float (with the fractional part set to zero) and
+     * is reset to zero only on a system reboot. The timestamp of the event is set to the time when
+     * the first step for that event was taken. This sensor is implemented in hardware and is
+     * expected to be low power.
+     * <p>
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     */
+    public static final int TYPE_STEP_COUNTER = 19;
+
+    /**
+     * A constant describing the geo-magnetic rotation vector.
+     * <p>
+     * Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
+     * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
+     * use the gyroscope. However, it is more noisy and will work best outdoors.
+     * <p>
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     */
+    public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
+
+    /**
      * A constant describing all sensor types.
      */
     public static final int TYPE_ALL = -1;
@@ -204,37 +240,71 @@
     // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
 
     // Note: This needs to be updated, whenever a new sensor is added.
-    private static int[] sSensorReportingModes = {
-            REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS,
-            REPORTING_MODE_CONTINUOUS, REPORTING_MODE_ON_CHANGE, REPORTING_MODE_CONTINUOUS,
-            REPORTING_MODE_ON_CHANGE, REPORTING_MODE_ON_CHANGE, REPORTING_MODE_CONTINUOUS,
-            REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS, REPORTING_MODE_ON_CHANGE,
-            REPORTING_MODE_ON_CHANGE, REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS,
-            REPORTING_MODE_CONTINUOUS, REPORTING_MODE_ONE_SHOT };
-
-    // Note: This needs to be updated, whenever a new sensor is added.
-    // Holds the maximum length of the values array associated with {@link SensorEvent} or
-    // {@link TriggerEvent} for the Sensor
-    private static int[] sMaxLengthValuesArray = {
-            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3,
-            6, 4, 6, 1 };
+    // Holds the reporting mode and maximum length of the values array
+    // 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
+    };
 
     static int getReportingMode(Sensor sensor) {
-        // mType starts from offset 1.
-        return sSensorReportingModes[sensor.mType - 1];
+        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];
     }
 
     static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
-        // mType starts from offset 1.
-        int len = sMaxLengthValuesArray[sensor.mType - 1];
-
+        int type = sensor.mType;
         // RotationVector length has changed to 3 to 5 for API level 18
         // Set it to 3 for backward compatibility.
-        if (sensor.getType() == Sensor.TYPE_ROTATION_VECTOR &&
+        if (type == Sensor.TYPE_ROTATION_VECTOR &&
                 sdkLevel <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            len = 3;
+            return 3;
         }
-        return len;
+        int offset = type * 2 + 1;
+        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
+            // it has
+            // so we return the maximum and assume the app will know.
+            // FIXME: sensor HAL should advertise how much data is returned per
+            // sensor
+            return 16;
+        }
+        return sSensorReportingModes[offset];
     }
 
     /* Some of these fields are set only by the native bindings in
@@ -249,6 +319,8 @@
     private float   mResolution;
     private float   mPower;
     private int     mMinDelay;
+    private int     mFifoReservedEventCount;
+    private int     mFifoMaxEventCount;
 
     Sensor() {
     }
@@ -311,6 +383,24 @@
         return mMinDelay;
     }
 
+    /**
+     * @return Number of events reserved for this sensor in the batch mode FIFO. This gives a
+     * guarantee on the minimum number of events that can be batched.
+     */
+    public int getFifoReservedEventCount() {
+        return mFifoReservedEventCount;
+    }
+
+    /**
+     * @return Maximum number of events of this sensor that could be batched. If this value is zero
+     * it indicates that batch mode is not supported for this sensor. If other applications
+     * registered to batched sensors, the actual number of events that can be batched might be
+     * smaller because the hardware FiFo will be partially used to batch the other sensors.
+     */
+    public int getFifoMaxEventCount() {
+        return mFifoMaxEventCount;
+    }
+
     /** @hide */
     public int getHandle() {
         return mHandle;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 30118f9..8a4aa1d 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -582,7 +582,7 @@
      * @param sensor
      *        The {@link android.hardware.Sensor Sensor} to register to.
      *
-     * @param rate
+     * @param rateUs
      *        The rate {@link android.hardware.SensorEvent sensor events} are
      *        delivered at. This is only a hint to the system. Events may be
      *        received faster or slower than the specified rate. Usually events
@@ -603,13 +603,78 @@
      *
      * @throws IllegalArgumentException when sensor is null or a trigger sensor
      */
-    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) {
-        return registerListener(listener, sensor, rate, null);
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs) {
+        return registerListener(listener, sensor, rateUs, null);
     }
 
     /**
-     * Registers a {@link android.hardware.SensorEventListener
-     * SensorEventListener} for the given sensor.
+     * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the
+     * underlying hardware does not support batch mode, this defaults to
+     * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are
+     * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected.
+     * While in batch mode, sensor events do not need to be reported as soon as they are detected.
+     * They can be temporarily stored in batches and reported in batches, as long as no event is
+     * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the
+     * previous batch are recorded and returned all at once. This allows to reduce the amount of
+     * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while
+     * the sensor is capturing and batching data.
+     * <p>
+     * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In
+     * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the
+     * FIFO gets full before the AP wakes up again, some events will be lost, as the older events
+     * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake
+     * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events
+     * will be lost, as the events will be reported before the FIFO gets full.
+     * </p>
+     * <p>
+     * Batching is always best effort. If a different application requests updates in continuous
+     * mode, this application will also get events in continuous mode. Batch mode updates can be
+     * unregistered by calling {@link #unregisterListener(SensorEventListener)}.
+     * </p>
+     * <p class="note">
+     * </p>
+     * Note: Don't use this method with a one shot trigger sensor such as
+     * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
+     * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
+     *
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
+     *            that will receive the sensor events.
+     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+     * @param rateUs The desired delay between two consecutive events in microseconds. This is only
+     *            a hint to the system. Events may be received faster or slower than the specified
+     *            rate. Usually events are received faster. Can be one of
+     *            {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *            {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
+     *            microseconds.
+     * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
+     *            maxBatchReportLatency microseconds. More events can be batched if this value is
+     *            large. If this is set to zero, batch mode is disabled and events are delivered in
+     *            continuous mode as soon as they are available which is equivalent to calling
+     *            {@link #registerListener(SensorEventListener, Sensor, int)}.
+     * @param reservedFlags Always set to Zero.
+     * @param flushCompleteListener A {@link android.hardware.FlushCompleteListener
+     *            FlushCompleteListener} object which is called when any application calls flush()
+     *            on this sensor and all the events in the batch at the time of calling flush() are
+     *            successfully delivered to the listeners.
+     * @return true if batch mode is successfully enabled for this sensor, false otherwise.
+     * @see #registerListener(SensorEventListener, Sensor, int)
+     * @see #unregisterListener(SensorEventListener)
+     * @see #flush(Sensor)
+     * @throws IllegalArgumentException when sensor or listener is null or a trigger sensor.
+     */
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
+            int maxBatchReportLatencyUs, int reservedFlags,
+            FlushCompleteListener flushCompleteListener) {
+        int delay = getDelay(rateUs);
+        return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs,
+                                        reservedFlags, flushCompleteListener);
+    }
+
+    /**
+     * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+     * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the
+     * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int, int,
+     * FlushCompleteListener)} which enables batch mode for the sensor.
      *
      * <p class="note"></p>
      * Note: Don't use this method with a one shot trigger sensor such as
@@ -624,7 +689,7 @@
      * @param sensor
      *        The {@link android.hardware.Sensor Sensor} to register to.
      *
-     * @param rate
+     * @param rateUs
      *        The rate {@link android.hardware.SensorEvent sensor events} are
      *        delivered at. This is only a hint to the system. Events may be
      *        received faster or slower than the specified rate. Usually events
@@ -649,37 +714,59 @@
      *
      * @throws IllegalArgumentException when sensor is null or a trigger sensor
      */
-    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
             Handler handler) {
         if (listener == null || sensor == null) {
             return false;
         }
 
-        int delay = -1;
-        switch (rate) {
-            case SENSOR_DELAY_FASTEST:
-                delay = 0;
-                break;
-            case SENSOR_DELAY_GAME:
-                delay = 20000;
-                break;
-            case SENSOR_DELAY_UI:
-                delay = 66667;
-                break;
-            case SENSOR_DELAY_NORMAL:
-                delay = 200000;
-                break;
-            default:
-                delay = rate;
-                break;
-        }
+        int delay = getDelay(rateUs);
+        return registerListenerImpl(listener, sensor, delay, handler, 0, 0, null);
+    }
 
-        return registerListenerImpl(listener, sensor, delay, handler);
+    /**
+     * Enables batch mode for a sensor with the given rate and maxBatchReportLatency.
+     * @param handler
+     *        The {@link android.os.Handler Handler} the
+     *        {@link android.hardware.SensorEvent sensor events} will be
+     *        delivered to.
+     *
+     * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener)
+     */
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
+            int maxBatchReportLatencyUs, int reservedFlags, Handler handler,
+            FlushCompleteListener flushCompleteListener) {
+        int delayUs = getDelay(rateUs);
+        return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs,
+                                        reservedFlags, flushCompleteListener);
     }
 
     /** @hide */
     protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
-            int delay, Handler handler);
+            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags,
+            FlushCompleteListener flushCompleteListener);
+
+
+    /**
+     * Flushes the batch FIFO of the given sensor. If there are events in the FIFO of this sensor,
+     * they are returned as if the batch timeout has expired. Events are returned in the
+     * usual way through the SensorEventListener. This call doesn't effect the batch timeout for
+     * this sensor. This call is asynchronous and returns immediately. FlushCompleteListener is
+     * called after all the events in the batch at the time of calling this method have been
+     * delivered successfully.
+     * @param sensor
+     *        The {@link android.hardware.Sensor Sensor} to flush.
+     * @return true if the flush is initiated successfully. false if the sensor isn't active
+     *         i.e no application is registered for updates from this sensor.
+     * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener)
+     * @throws IllegalArgumentException when sensor is null or a trigger sensor.
+     */
+    public boolean flush(Sensor sensor) {
+        return flushImpl(sensor);
+    }
+
+    /** @hide */
+    protected abstract boolean flushImpl(Sensor sensor);
 
     /**
      * <p>
@@ -1079,15 +1166,15 @@
      * <p>
      * All three angles above are in <b>radians</b> and <b>positive</b> in the
      * <b>counter-clockwise</b> direction.
-     * 
+     *
      * @param R
      *        rotation matrix see {@link #getRotationMatrix}.
-     * 
+     *
      * @param values
      *        an array of 3 floats to hold the result.
-     * 
+     *
      * @return The array values passed as argument.
-     * 
+     *
      * @see #getRotationMatrix(float[], float[], float[], float[])
      * @see GeomagneticField
      */
@@ -1407,4 +1494,26 @@
             return mLegacySensorManager;
         }
     }
+
+    private static int getDelay(int rate) {
+        int delay = -1;
+        switch (rate) {
+            case SENSOR_DELAY_FASTEST:
+                delay = 0;
+                break;
+            case SENSOR_DELAY_GAME:
+                delay = 20000;
+                break;
+            case SENSOR_DELAY_UI:
+                delay = 66667;
+                break;
+            case SENSOR_DELAY_NORMAL:
+                delay = 200000;
+                break;
+            default:
+                delay = rate;
+                break;
+        }
+        return delay;
+    }
 }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 852cf4a..9747f0d 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -93,30 +93,35 @@
     /** @hide */
     @Override
     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
-            int delay, Handler handler)
-    {
+            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags,
+            FlushCompleteListener flushCompleteListener) {
+        if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
+        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+        if (reservedFlags != 0) throw new IllegalArgumentException("reservedFlags should be zero");
+        if (delayUs < 0) throw new IllegalArgumentException("rateUs should be positive");
+        if (maxBatchReportLatencyUs < 0)
+            throw new IllegalArgumentException("maxBatchReportLatencyUs should be positive");
+        // Trigger Sensors should use the requestTriggerSensor call.
+        if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT)
+            throw new IllegalArgumentException("Trigger Sensors cannot use registerListener");
+
         // Invariants to preserve:
         // - one Looper per SensorEventListener
         // - one Looper per SensorEventQueue
         // We map SensorEventListener to a SensorEventQueue, which holds the looper
-        if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
-
-        // Trigger Sensors should use the requestTriggerSensor call.
-        if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false;
-
         synchronized (mSensorListeners) {
             SensorEventQueue queue = mSensorListeners.get(listener);
             if (queue == null) {
                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
-                queue = new SensorEventQueue(listener, looper, this);
-                if (!queue.addSensor(sensor, delay)) {
+                queue = new SensorEventQueue(listener, looper, this, flushCompleteListener);
+                if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
                     queue.dispose();
                     return false;
                 }
                 mSensorListeners.put(listener, queue);
                 return true;
             } else {
-                return queue.addSensor(sensor, delay);
+                return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags);
             }
         }
     }
@@ -157,14 +162,14 @@
             TriggerEventQueue queue = mTriggerListeners.get(listener);
             if (queue == null) {
                 queue = new TriggerEventQueue(listener, mMainLooper, this);
-                if (!queue.addSensor(sensor, 0)) {
+                if (!queue.addSensor(sensor, 0, 0, 0)) {
                     queue.dispose();
                     return false;
                 }
                 mTriggerListeners.put(listener, queue);
                 return true;
             } else {
-                return queue.addSensor(sensor, 0);
+                return queue.addSensor(sensor, 0, 0, 0);
             }
         }
     }
@@ -195,6 +200,18 @@
         }
     }
 
+    protected boolean flushImpl(Sensor sensor) {
+        if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
+        if(Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT)
+            throw new IllegalArgumentException("Trigger Sensors cannot call flush");
+
+        FlushEventQueue queue = new FlushEventQueue(mMainLooper, this);
+        if (queue.flushSensor(sensor) != 0) {
+            return false;
+        }
+        return true;
+    }
+
     /*
      * BaseEventQueue is the communication channel with the sensor service,
      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
@@ -202,11 +219,12 @@
      */
     private static abstract class BaseEventQueue {
         private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
-
                 float[] scratch);
-        private static native int nativeEnableSensor(int eventQ, int handle, int us);
+        private static native int nativeEnableSensor(int eventQ, int handle, int rateUs,
+                int maxBatchReportLatencyUs, int reservedFlags);
         private static native int nativeDisableSensor(int eventQ, int handle);
         private static native void nativeDestroySensorEventQueue(int eventQ);
+        private static native int nativeFlushSensor(int eventQ, int handle);
         private int nSensorEventQueue;
         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
@@ -225,7 +243,8 @@
             dispose(false);
         }
 
-        public boolean addSensor(Sensor sensor, int delay) {
+        public boolean addSensor(
+                Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) {
             // Check if already present.
             int handle = sensor.getHandle();
             if (mActiveSensors.get(handle)) return false;
@@ -233,9 +252,13 @@
             // Get ready to receive events before calling enable.
             mActiveSensors.put(handle, true);
             addSensorEvent(sensor);
-            if (enableSensor(sensor, delay) != 0) {
-                removeSensor(sensor, false);
-                return false;
+            if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) {
+                // Try continuous mode if batching fails.
+                if (maxBatchReportLatencyUs == 0 ||
+                    maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) {
+                  removeSensor(sensor, false);
+                  return false;
+                }
             }
             return true;
         }
@@ -268,6 +291,12 @@
             return false;
         }
 
+        public int flushSensor(Sensor sensor) {
+            if (nSensorEventQueue == 0) throw new NullPointerException();
+            if (sensor == null) throw new NullPointerException();
+            return nativeFlushSensor(nSensorEventQueue, sensor.getHandle());
+        }
+
         public boolean hasSensors() {
             // no more sensors are set
             return mActiveSensors.indexOfValue(true) >= 0;
@@ -295,11 +324,14 @@
             }
         }
 
-        private int enableSensor(Sensor sensor, int us) {
+        private int enableSensor(
+                Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) {
             if (nSensorEventQueue == 0) throw new NullPointerException();
             if (sensor == null) throw new NullPointerException();
-            return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us);
+            return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
+                    maxBatchReportLatencyUs, reservedFlags);
         }
+
         private int disableSensor(Sensor sensor) {
             if (nSensorEventQueue == 0) throw new NullPointerException();
             if (sensor == null) throw new NullPointerException();
@@ -307,6 +339,7 @@
         }
         protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
                 long timestamp);
+        protected abstract void dispatchFlushCompleteEvent(int handle);
 
         protected abstract void addSensorEvent(Sensor sensor);
         protected abstract void removeSensorEvent(Sensor sensor);
@@ -314,12 +347,14 @@
 
     static final class SensorEventQueue extends BaseEventQueue {
         private final SensorEventListener mListener;
+        private final FlushCompleteListener mFlushCompleteListener;
         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
 
         public SensorEventQueue(SensorEventListener listener, Looper looper,
-                SystemSensorManager manager) {
+                SystemSensorManager manager, FlushCompleteListener flushCompleteListener) {
             super(looper, manager);
             mListener = listener;
+            mFlushCompleteListener = flushCompleteListener;
         }
 
         public void addSensorEvent(Sensor sensor) {
@@ -370,6 +405,15 @@
             }
             mListener.onSensorChanged(t);
         }
+
+        @SuppressWarnings("unused")
+        protected void dispatchFlushCompleteEvent(int handle) {
+            final Sensor sensor = sHandleToSensor.get(handle);
+            if (mFlushCompleteListener != null) {
+                mFlushCompleteListener.onFlushCompleted(sensor);
+            }
+            return;
+        }
     }
 
     static final class TriggerEventQueue extends BaseEventQueue {
@@ -415,5 +459,35 @@
 
             mListener.onTrigger(t);
         }
+
+        @SuppressWarnings("unused")
+        protected void dispatchFlushCompleteEvent(int handle) {
+        }
+    }
+
+    static final class FlushEventQueue extends BaseEventQueue {
+        public FlushEventQueue(Looper looper, SystemSensorManager manager) {
+            super(looper, manager);
+        }
+
+        @SuppressWarnings("unused")
+        @Override
+        protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
+                long timestamp) {
+        }
+
+        @Override
+        @SuppressWarnings("unused")
+        protected void addSensorEvent(Sensor sensor) {
+        }
+
+        @Override
+        @SuppressWarnings("unused")
+        protected void removeSensorEvent(Sensor sensor) {
+        }
+
+        @SuppressWarnings("unused")
+        protected void dispatchFlushCompleteEvent(int handle) {
+        }
     }
 }
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
new file mode 100644
index 0000000..1af575f
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -0,0 +1,137 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.util.AndroidException;
+
+/**
+ * <p><code>CameraAccessException</code> is thrown if a camera device could not
+ * be queried or opened by the {@link CameraManager}, or if the connection to an
+ * opened {@link CameraDevice} is no longer valid.</p>
+ *
+ * @see CameraManager
+ * @see CameraDevice
+ */
+public class CameraAccessException extends AndroidException {
+    /**
+     * The camera device is in use already
+     * @hide
+     */
+    public static final int CAMERA_IN_USE = 4;
+
+    /**
+     * The system-wide limit for number of open cameras has been reached,
+     * and more camera devices cannot be opened until previous instances are
+     * closed.
+     * @hide
+     */
+    public static final int MAX_CAMERAS_IN_USE = 5;
+
+    /**
+     * The camera is disabled due to a device policy, and cannot be opened.
+     *
+     * @see android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName, boolean)
+     */
+    public static final int CAMERA_DISABLED = 1;
+
+    /**
+     * The camera device is removable and has been disconnected from the Android
+     * device, or the camera id used with {@link android.hardware.camera2.CameraManager#openCamera}
+     * is no longer valid, or the camera service has shut down the connection due to a
+     * higher-priority access request for the camera device.
+     */
+    public static final int CAMERA_DISCONNECTED = 2;
+
+    /**
+     * The camera device is currently in the error state.
+     *
+     * <p>The camera has failed to open or has failed at a later time
+     * as a result of some non-user interaction. Refer to
+     * {@link CameraDevice.StateListener#onError} for the exact
+     * nature of the error.</p>
+     *
+     * <p>No further calls to the camera will succeed. Clean up
+     * the camera with {@link CameraDevice#close} and try
+     * handling the error in order to successfully re-open the camera.
+     * </p>
+     *
+     */
+    public static final int CAMERA_ERROR = 3;
+
+    /**
+     * A deprecated HAL version is in use.
+     * @hide
+     */
+    public static final int CAMERA_DEPRECATED_HAL = 1000;
+
+    // Make the eclipse warning about serializable exceptions go away
+    private static final long serialVersionUID = 5630338637471475675L; // randomly generated
+
+    private final int mReason;
+
+    /**
+     * The reason for the failure to access the camera.
+     *
+     * @see #CAMERA_DISABLED
+     * @see #CAMERA_DISCONNECTED
+     * @see #CAMERA_ERROR
+     */
+    public final int getReason() {
+        return mReason;
+    }
+
+    public CameraAccessException(int problem) {
+        super(getDefaultMessage(problem));
+        mReason = problem;
+    }
+
+    public CameraAccessException(int problem, String message) {
+        super(message);
+        mReason = problem;
+    }
+
+    public CameraAccessException(int problem, String message, Throwable cause) {
+        super(message, cause);
+        mReason = problem;
+    }
+
+    public CameraAccessException(int problem, Throwable cause) {
+        super(getDefaultMessage(problem), cause);
+        mReason = problem;
+    }
+
+    private static String getDefaultMessage(int problem) {
+        switch (problem) {
+            case CAMERA_IN_USE:
+                return "The camera device is in use already";
+            case MAX_CAMERAS_IN_USE:
+                return "The system-wide limit for number of open cameras has been reached, " +
+                       "and more camera devices cannot be opened until previous instances " +
+                       "are closed.";
+            case CAMERA_DISCONNECTED:
+                return "The camera device is removable and has been disconnected from the " +
+                        "Android device, or the camera service has shut down the connection due " +
+                        "to a higher-priority access request for the camera device.";
+            case CAMERA_DISABLED:
+                return "The camera is disabled due to a device policy, and cannot be opened.";
+            case CAMERA_ERROR:
+                return "The camera device is currently in the error state; " +
+                       "no further calls to it will succeed.";
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
new file mode 100644
index 0000000..85fa7d6
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -0,0 +1,592 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>The properties describing a
+ * {@link CameraDevice CameraDevice}.</p>
+ *
+ * <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>
+ *
+ * @see CameraDevice
+ * @see CameraManager
+ */
+public final class CameraCharacteristics extends CameraMetadata {
+
+    private final CameraMetadataNative mProperties;
+    private List<Key<?>> mAvailableRequestKeys;
+    private List<Key<?>> mAvailableResultKeys;
+
+    /**
+     * Takes ownership of the passed-in properties object
+     * @hide
+     */
+    public CameraCharacteristics(CameraMetadataNative properties) {
+        mProperties = properties;
+    }
+
+    @Override
+    public <T> T get(Key<T> key) {
+        return mProperties.get(key);
+    }
+
+    /**
+     * Returns the list of keys supported by this {@link CameraDevice} for querying
+     * with a {@link CaptureRequest}.
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+     *
+     * <p>Note that there is no {@code getAvailableCameraCharacteristicsKeys()} -- use
+     * {@link #getKeys()} instead.</p>
+     *
+     * @return List of keys supported by this CameraDevice for CaptureRequests.
+     */
+    public List<Key<?>> getAvailableCaptureRequestKeys() {
+        if (mAvailableRequestKeys == null) {
+            mAvailableRequestKeys = getAvailableKeyList(CaptureRequest.class);
+        }
+        return mAvailableRequestKeys;
+    }
+
+    /**
+     * Returns the list of keys supported by this {@link CameraDevice} for querying
+     * with a {@link CaptureResult}.
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+     *
+     * <p>Note that there is no {@code getAvailableCameraCharacteristicsKeys()} -- use
+     * {@link #getKeys()} instead.</p>
+     *
+     * @return List of keys supported by this CameraDevice for CaptureResults.
+     */
+    public List<Key<?>> getAvailableCaptureResultKeys() {
+        if (mAvailableResultKeys == null) {
+            mAvailableResultKeys = getAvailableKeyList(CaptureResult.class);
+        }
+        return mAvailableResultKeys;
+    }
+
+    /**
+     * Returns the list of keys supported by this {@link CameraDevice} by metadataClass.
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+     *
+     * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
+     *
+     * @return List of keys supported by this CameraDevice for metadataClass.
+     *
+     * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
+     */
+    private <T extends CameraMetadata> List<Key<?>> getAvailableKeyList(Class<T> metadataClass) {
+
+        if (metadataClass.equals(CameraMetadata.class)) {
+            throw new AssertionError(
+                    "metadataClass must be a strict subclass of CameraMetadata");
+        } else if (!CameraMetadata.class.isAssignableFrom(metadataClass)) {
+            throw new AssertionError(
+                    "metadataClass must be a subclass of CameraMetadata");
+        }
+
+        return Collections.unmodifiableList(getKeysStatic(metadataClass, /*instance*/null));
+    }
+
+    /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * The key entries below this point are generated from metadata
+     * definitions in /system/media/camera/docs. Do not modify by hand or
+     * modify the comment blocks at the start or end.
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+    /**
+     * <p>
+     * Which set of antibanding modes are
+     * supported
+     * </p>
+     */
+    public static final Key<byte[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES =
+            new Key<byte[]>("android.control.aeAvailableAntibandingModes", byte[].class);
+
+    /**
+     * <p>
+     * List of frame rate ranges supported by the
+     * AE algorithm/hardware
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =
+            new Key<int[]>("android.control.aeAvailableTargetFpsRanges", int[].class);
+
+    /**
+     * <p>
+     * Maximum and minimum exposure compensation
+     * setting, in counts of
+     * android.control.aeCompensationStepSize
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AE_COMPENSATION_RANGE =
+            new Key<int[]>("android.control.aeCompensationRange", int[].class);
+
+    /**
+     * <p>
+     * Smallest step by which exposure compensation
+     * can be changed
+     * </p>
+     */
+    public static final Key<Rational> CONTROL_AE_COMPENSATION_STEP =
+            new Key<Rational>("android.control.aeCompensationStep", Rational.class);
+
+    /**
+     * <p>
+     * List of AF modes that can be
+     * selected
+     * </p>
+     */
+    public static final Key<byte[]> CONTROL_AF_AVAILABLE_MODES =
+            new Key<byte[]>("android.control.afAvailableModes", byte[].class);
+
+    /**
+     * <p>
+     * what subset of the full color effect enum
+     * list is supported
+     * </p>
+     */
+    public static final Key<byte[]> CONTROL_AVAILABLE_EFFECTS =
+            new Key<byte[]>("android.control.availableEffects", byte[].class);
+
+    /**
+     * <p>
+     * what subset of the scene mode enum list is
+     * supported.
+     * </p>
+     */
+    public static final Key<byte[]> CONTROL_AVAILABLE_SCENE_MODES =
+            new Key<byte[]>("android.control.availableSceneModes", byte[].class);
+
+    /**
+     * <p>
+     * List of video stabilization modes that can
+     * be supported
+     * </p>
+     */
+    public static final Key<byte[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES =
+            new Key<byte[]>("android.control.availableVideoStabilizationModes", byte[].class);
+
+    /**
+     */
+    public static final Key<byte[]> CONTROL_AWB_AVAILABLE_MODES =
+            new Key<byte[]>("android.control.awbAvailableModes", byte[].class);
+
+    /**
+     * <p>
+     * For AE, AWB, and AF, how many individual
+     * regions can be listed for metering?
+     * </p>
+     */
+    public static final Key<Integer> CONTROL_MAX_REGIONS =
+            new Key<Integer>("android.control.maxRegions", int.class);
+
+    /**
+     * <p>
+     * Whether this camera has a
+     * flash
+     * </p>
+     * <p>
+     * If no flash, none of the flash controls do
+     * anything. All other metadata should return 0
+     * </p>
+     */
+    public static final Key<Byte> FLASH_INFO_AVAILABLE =
+            new Key<Byte>("android.flash.info.available", byte.class);
+
+    /**
+     * <p>
+     * Supported resolutions for the JPEG
+     * thumbnail
+     * </p>
+     */
+    public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
+            new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
+
+    /**
+     * <p>
+     * List of supported aperture
+     * values
+     * </p>
+     * <p>
+     * If variable aperture not available, only setting
+     * should be for the fixed aperture
+     * </p>
+     */
+    public static final Key<float[]> LENS_INFO_AVAILABLE_APERTURES =
+            new Key<float[]>("android.lens.info.availableApertures", float[].class);
+
+    /**
+     * <p>
+     * List of supported ND filter
+     * values
+     * </p>
+     * <p>
+     * If not available, only setting is 0. Otherwise,
+     * lists the available exposure index values for dimming
+     * (2 would mean the filter is set to reduce incoming
+     * light by two stops)
+     * </p>
+     */
+    public static final Key<float[]> LENS_INFO_AVAILABLE_FILTER_DENSITIES =
+            new Key<float[]>("android.lens.info.availableFilterDensities", float[].class);
+
+    /**
+     * <p>
+     * If fitted with optical zoom, what focal
+     * lengths are available. If not, the static focal
+     * length
+     * </p>
+     * <p>
+     * If optical zoom not supported, only one value
+     * should be reported
+     * </p>
+     */
+    public static final Key<float[]> LENS_INFO_AVAILABLE_FOCAL_LENGTHS =
+            new Key<float[]>("android.lens.info.availableFocalLengths", float[].class);
+
+    /**
+     * <p>
+     * List of supported optical image
+     * stabilization modes
+     * </p>
+     */
+    public static final Key<byte[]> LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION =
+            new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class);
+
+    /**
+     * <p>
+     * Hyperfocal distance for this lens; set to
+     * 0 if fixed focus
+     * </p>
+     * <p>
+     * The hyperfocal distance is used for the old
+     * API's 'fixed' setting
+     * </p>
+     */
+    public static final Key<Float> LENS_INFO_HYPERFOCAL_DISTANCE =
+            new Key<Float>("android.lens.info.hyperfocalDistance", float.class);
+
+    /**
+     * <p>
+     * Shortest distance from frontmost surface
+     * of the lens that can be focused correctly
+     * </p>
+     * <p>
+     * If the lens is fixed-focus, this should be
+     * 0
+     * </p>
+     */
+    public static final Key<Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE =
+            new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
+
+    /**
+     * <p>
+     * Dimensions of lens shading
+     * map
+     * </p>
+     */
+    public static final Key<android.hardware.camera2.Size> LENS_INFO_SHADING_MAP_SIZE =
+            new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
+
+    /**
+     * <p>
+     * Direction the camera faces relative to
+     * device screen
+     * </p>
+     * @see #LENS_FACING_FRONT
+     * @see #LENS_FACING_BACK
+     */
+    public static final Key<Integer> LENS_FACING =
+            new Key<Integer>("android.lens.facing", int.class);
+
+    /**
+     * <p>
+     * How many output streams can be allocated at
+     * the same time for each type of stream
+     * </p>
+     * <p>
+     * Video snapshot with preview callbacks requires 3
+     * processed streams (preview, record, app callbacks) and
+     * one JPEG stream (snapshot)
+     * </p>
+     */
+    public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
+            new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
+
+    /**
+     * <p>
+     * List of app-visible formats
+     * </p>
+     */
+    public static final Key<int[]> SCALER_AVAILABLE_FORMATS =
+            new Key<int[]>("android.scaler.availableFormats", int[].class);
+
+    /**
+     * <p>
+     * The minimum frame duration that is supported
+     * for each resolution in availableJpegSizes. Should
+     * correspond to the frame duration when only that JPEG
+     * stream is active and captured in a burst, with all
+     * processing set to FAST
+     * </p>
+     * <p>
+     * When multiple streams are configured, the minimum
+     * frame duration will be >= max(individual stream min
+     * durations)
+     * </p>
+     */
+    public static final Key<long[]> SCALER_AVAILABLE_JPEG_MIN_DURATIONS =
+            new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class);
+
+    /**
+     * <p>
+     * The resolutions available for output from
+     * the JPEG block. Listed as width x height
+     * </p>
+     */
+    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
+            new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.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>
+     */
+    public static final Key<Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM =
+            new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
+
+    /**
+     * <p>
+     * The minimum frame duration that is supported
+     * for each resolution in availableProcessedSizes. Should
+     * correspond to the frame duration when only that processed
+     * stream is active, with all processing set to
+     * FAST
+     * </p>
+     * <p>
+     * When multiple streams are configured, the minimum
+     * frame duration will be >= max(individual stream min
+     * durations)
+     * </p>
+     */
+    public static final Key<long[]> SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS =
+            new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
+
+    /**
+     * <p>
+     * The resolutions available for use with
+     * processed output streams, such as YV12, NV12, and
+     * platform opaque YUV/RGB streams to the GPU or video
+     * encoders. Listed as width, height
+     * </p>
+     * <p>
+     * The actual supported resolution list may be limited by
+     * consumer end points for different use cases. For example, for
+     * recording use case, the largest supported resolution may be
+     * limited by max supported size from encoder, for preview use
+     * case, the largest supported resolution may be limited by max
+     * resolution SurfaceTexture/SurfaceView can support.
+     * </p>
+     */
+    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
+            new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
+
+    /**
+     * <p>
+     * Area of raw data which corresponds to only
+     * active pixels; smaller or equal to
+     * pixelArraySize.
+     * </p>
+     */
+    public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE =
+            new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
+
+    /**
+     * <p>
+     * Range of valid sensitivities
+     * </p>
+     */
+    public static final Key<int[]> SENSOR_INFO_SENSITIVITY_RANGE =
+            new Key<int[]>("android.sensor.info.sensitivityRange", int[].class);
+
+    /**
+     * <p>
+     * Range of valid exposure
+     * times
+     * </p>
+     */
+    public static final Key<long[]> SENSOR_INFO_EXPOSURE_TIME_RANGE =
+            new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
+
+    /**
+     * <p>
+     * Maximum possible frame duration (minimum frame
+     * rate)
+     * </p>
+     * <p>
+     * Minimum duration is a function of resolution,
+     * processing settings. See
+     * android.scaler.availableProcessedMinDurations
+     * android.scaler.availableJpegMinDurations
+     * android.scaler.availableRawMinDurations
+     * </p>
+     */
+    public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
+            new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
+
+    /**
+     * <p>
+     * The physical dimensions of the full pixel
+     * array
+     * </p>
+     * <p>
+     * Needed for FOV calculation for old API
+     * </p>
+     */
+    public static final Key<float[]> SENSOR_INFO_PHYSICAL_SIZE =
+            new Key<float[]>("android.sensor.info.physicalSize", float[].class);
+
+    /**
+     * <p>
+     * Gain factor from electrons to raw units when
+     * ISO=100
+     * </p>
+     */
+    public static final Key<Rational> SENSOR_BASE_GAIN_FACTOR =
+            new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
+
+    /**
+     * <p>
+     * Maximum sensitivity that is implemented
+     * purely through analog gain
+     * </p>
+     * <p>
+     * For android.sensor.sensitivity values less than or
+     * equal to this, all applied gain must be analog. For
+     * values above this, it can be a mix of analog and
+     * digital
+     * </p>
+     */
+    public static final Key<Integer> SENSOR_MAX_ANALOG_SENSITIVITY =
+            new Key<Integer>("android.sensor.maxAnalogSensitivity", int.class);
+
+    /**
+     * <p>
+     * Clockwise angle through which the output
+     * image needs to be rotated to be upright on the device
+     * screen in its native orientation. Also defines the
+     * direction of rolling shutter readout, which is from top
+     * to bottom in the sensor's coordinate system
+     * </p>
+     */
+    public static final Key<Integer> SENSOR_ORIENTATION =
+            new Key<Integer>("android.sensor.orientation", 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>
+     * SIMPLE means the device supports the
+     * android.statistics.faceRectangles and
+     * android.statistics.faceScores outputs.
+     * </p><p>
+     * FULL means the device additionally supports the
+     * android.statistics.faceIds and
+     * android.statistics.faceLandmarks outputs.
+     * </p>
+     */
+    public static final Key<byte[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
+            new Key<byte[]>("android.statistics.info.availableFaceDetectModes", byte[].class);
+
+    /**
+     * <p>
+     * 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);
+
+    /**
+     * <p>
+     * Maximum number of supported points in the
+     * tonemap curve
+     * </p>
+     */
+    public static final Key<Integer> TONEMAP_MAX_CURVE_POINTS =
+            new Key<Integer>("android.tonemap.maxCurvePoints", int.class);
+
+    /**
+     * <p>
+     * A list of camera LEDs that are available on this system.
+     * </p>
+     * @see #LED_AVAILABLE_LEDS_TRANSMIT
+     *
+     * @hide
+     */
+    public static final Key<int[]> LED_AVAILABLE_LEDS =
+            new Key<int[]>("android.led.availableLeds", int[].class);
+
+    /**
+     * <p>
+     * The camera 3 HAL device can implement one of two possible
+     * operational modes; limited and full. Full support is
+     * expected from new higher-end devices. Limited mode has
+     * hardware requirements roughly in line with those for a
+     * camera HAL device v1 implementation, and is expected from
+     * older or inexpensive devices. Full is a strict superset of
+     * limited, and they share the same essential operational flow.
+     * </p><p>
+     * For full details refer to "S3. Operational Modes" in camera3.h
+     * </p>
+     * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+     * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
+     */
+    public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
+            new Key<Integer>("android.info.supportedHardwareLevel", int.class);
+
+    /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * End generated code
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
new file mode 100644
index 0000000..a9a72b0
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -0,0 +1,993 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.os.Handler;
+import android.view.Surface;
+
+import java.util.List;
+
+/**
+ * <p>The CameraDevice class is an interface to a single camera connected to an
+ * Android device, allowing for fine-grain control of image capture and
+ * post-processing at high frame rates.</p>
+ *
+ * <p>Your application must declare the
+ * {@link android.Manifest.permission#CAMERA Camera} permission in its manifest
+ * in order to access camera devices.</p>
+ *
+ * <p>A given camera device may provide support at one of two levels: limited or
+ * full. If a device only supports the limited level, then Camera2 exposes a
+ * feature set that is roughly equivalent to the older
+ * {@link android.hardware.Camera Camera} API, although with a cleaner and more
+ * efficient interface.  Devices that implement the full level of support
+ * provide substantially improved capabilities over the older camera
+ * API. Applications that target the limited level devices will run unchanged on
+ * the full-level devices; if your application requires a full-level device for
+ * proper operation, declare the "android.hardware.camera2.full" feature in your
+ * manifest.</p>
+ *
+ * @see CameraManager#openCamera
+ * @see android.Manifest.permission#CAMERA
+ */
+public interface CameraDevice extends AutoCloseable {
+
+    /**
+     * 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.
+     *
+     * @see #createCaptureRequest
+     */
+    public static final int TEMPLATE_PREVIEW = 1;
+
+    /**
+     * 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.
+     *
+     * @see #createCaptureRequest
+     */
+    public static final int TEMPLATE_STILL_CAPTURE = 2;
+
+    /**
+     * 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.
+     *
+     * @see #createCaptureRequest
+     */
+    public static final int TEMPLATE_RECORD  = 3;
+
+    /**
+     * 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}.
+     *
+     * @see #createCaptureRequest
+     */
+    public static final int TEMPLATE_VIDEO_SNAPSHOT = 4;
+
+    /**
+     * Create a request suitable for zero shutter lag still capture. This means
+     * means maximizing image quality without compromising preview frame rate.
+     * AE/AWB/AF should be on auto mode.
+     *
+     * @see #createCaptureRequest
+     * @hide
+     */
+    public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5;
+
+    /**
+     * A basic template for direct application control of capture
+     * parameters. All automatic control is disabled (auto-exposure, auto-white
+     * balance, auto-focus), and post-processing parameters are set to preview
+     * quality. The manual capture parameters (exposure, sensitivity, and so on)
+     * are set to reasonable defaults, but should be overriden by the
+     * application depending on the intended use case.
+     *
+     * @see #createCaptureRequest
+     * @hide
+     */
+    public static final int TEMPLATE_MANUAL = 6;
+
+    /**
+     * Get the ID of this camera device.
+     *
+     * <p>This matches the ID given to {@link CameraManager#openCamera} to instantiate this
+     * this camera device.</p>
+     *
+     * <p>This ID can be used to query the camera device's {@link
+     * CameraCharacteristics fixed properties} with {@link
+     * CameraManager#getCameraCharacteristics}.</p>
+     *
+     * <p>This method can be called even if the device has been closed or has encountered
+     * a serious error.</p>
+     *
+     * @return the ID for this camera device
+     *
+     * @see CameraManager#getCameraCharacteristics
+     * @see CameraManager#getCameraIdList
+     */
+    public String getId();
+
+    /**
+     * <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 CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES 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 CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES 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 CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES 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 CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}. Then
+     *   obtain the Surface with
+     *   {@link android.renderscript.Allocation#getSurface}.</li>
+     *
+     * <li>For access to uncompressed or JPEG data in the application: Create a
+     *   {@link android.media.ImageReader} object with the desired
+     *   {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS image format}, and a
+     *   size from the matching
+     *   {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed},
+     *   {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES jpeg}. Then obtain
+     *   a 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 android.scaler.availableFormats;
+     * and the size must be one of android.scaler.available[Processed|Jpeg]Sizes).</p>
+     *
+     * <p>To change the output, the camera device must be idle. The device is considered
+     * to be idle once all in-flight and pending capture requests have been processed,
+     * and all output image buffers from the captures have been sent to their destination
+     * Surfaces.</p>
+     *
+     * <p>To reach an idle state without cancelling any submitted captures, first
+     * stop any repeating request/burst with {@link #stopRepeating}, and then
+     * wait for the {@link StateListener#onIdle} callback to be
+     * called. To idle as fast as possible, use {@link #flush} and wait for the
+     * idle callback.</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}.
+     * </p>
+     *
+     * <p>Calling configureOutputs with the same arguments as the last call to
+     * configureOutputs has no effect.</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#onIdle
+     * @see #stopRepeating
+     * @see #flush
+     */
+    public void configureOutputs(List<Surface> outputs) throws CameraAccessException;
+
+    /**
+     * <p>Create a {@link CaptureRequest.Builder} for new capture requests,
+     * initialized with template for a target use case. The settings are chosen
+     * to be the best options for the specific camera device, so it is not
+     * recommended to reuse the same request for a different camera device;
+     * create a builder specific for that device and template and override the
+     * settings as desired, instead.</p>
+     *
+     * @param templateType An enumeration selecting the use case for this
+     * request; one of the CameraDevice.TEMPLATE_ values.
+     * @return a builder for a capture request, initialized with default
+     * settings for that template, and no output streams
+     *
+     * @throws IllegalArgumentException if the templateType is not in the list
+     * of supported templates.
+     * @throws CameraAccessException if the camera device is no longer connected or has
+     *                               encountered a fatal error
+     * @throws IllegalStateException if the camera device has been closed
+     *
+     * @see #TEMPLATE_PREVIEW
+     * @see #TEMPLATE_RECORD
+     * @see #TEMPLATE_STILL_CAPTURE
+     * @see #TEMPLATE_VIDEO_SNAPSHOT
+     * @see #TEMPLATE_MANUAL
+     */
+    public CaptureRequest.Builder createCaptureRequest(int templateType)
+            throws CameraAccessException;
+
+    /**
+     * <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
+     */
+    public 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.
+     *
+     * <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.
+     *
+     * @see #capture
+     * @see #setRepeatingRequest
+     * @see #setRepeatingBurst
+     */
+    public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
+            Handler handler) throws CameraAccessException;
+
+    /**
+     * 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
+     */
+    public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
+            Handler handler) throws CameraAccessException;
+
+    /**
+     * <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.
+     *
+     * @see #capture
+     * @see #captureBurst
+     * @see #setRepeatingRequest
+     * @see #stopRepeating
+     * @see #flush
+     */
+    public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
+            Handler handler) throws CameraAccessException;
+
+    /**
+     * <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>
+     *
+     * <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
+     */
+    public void stopRepeating() throws CameraAccessException;
+
+    /**
+     * <p>Wait until all the submitted requests have finished processing</p>
+     *
+     * <p>This method blocks until all the requests that have been submitted to
+     * the camera device, either through {@link #capture capture},
+     * {@link #captureBurst captureBurst},
+     * {@link #setRepeatingRequest setRepeatingRequest}, or
+     * {@link #setRepeatingBurst setRepeatingBurst}, have completed their
+     * processing.</p>
+     *
+     * <p>Once this call returns successfully, the device is in an idle state,
+     * and can be reconfigured with {@link #configureOutputs configureOutputs}.</p>
+     *
+     * <p>This method cannot be used if there is an active repeating request or
+     * burst, set with {@link #setRepeatingRequest setRepeatingRequest} or
+     * {@link #setRepeatingBurst setRepeatingBurst}. Call
+     * {@link #stopRepeating stopRepeating} before calling this method.</p>
+     *
+     * @throws CameraAccessException if the camera device is no longer connected
+     * @throws IllegalStateException if the camera device has been closed, the
+     * device has encountered a fatal error, or if there is an active repeating
+     * request or burst.
+     */
+    public void waitUntilIdle() throws CameraAccessException;
+
+    /**
+     * Set the listener object to call when an asynchronous device event occurs,
+     * such as errors or idle notifications.
+     *
+     * <p>The events reported here are device-wide; notifications about
+     * individual capture requests or capture results are reported through
+     * {@link CaptureListener}.</p>
+     *
+     * <p>If the camera device is idle when the listener is set, then the
+     * {@link StateListener#onIdle} method will be immediately called,
+     * even if the device has never been active before.
+     * </p>
+     *
+     * @param listener the CameraDeviceListener to send device-level event
+     * notifications to. Setting this to null will stop notifications.
+     * @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}.
+     *
+     * @throws IllegalArgumentException if handler is null, the listener is
+     * not null, and the calling thread has no looper
+     *
+     * @hide
+     */
+    public void setDeviceListener(StateListener listener, Handler handler);
+
+    /**
+     * 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
+     */
+    public void flush() throws CameraAccessException;
+
+    /**
+     * Close the connection to this camera device. After this call, all calls to
+     * the camera device interface will throw a {@link IllegalStateException},
+     * except for calls to close().
+     */
+    @Override
+    public void close();
+    // TODO: We should decide on the behavior of in-flight requests should be on close.
+
+    /**
+     * <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
+     */
+    public static abstract class CaptureListener {
+
+        /**
+         * 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,
+                CaptureRequest request, long timestamp) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called when an image capture has completed and the
+         * result metadata is available.
+         *
+         * <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 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, CaptureResult result) {
+            // default empty implementation
+        }
+
+        /**
+         * 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>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) {
+            // default empty implementation
+        }
+
+        /**
+         * 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.
+         *
+         * @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()
+         */
+        public void onCaptureSequenceCompleted(CameraDevice camera,
+                int sequenceId, int frameNumber) {
+            // default empty implementation
+        }
+    }
+
+    /**
+     * A listener for notifications about the state of a camera
+     * device.
+     *
+     * <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>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.
+     *
+     * @see #setDeviceListener
+     */
+    public static abstract class StateListener {
+       /**
+         * An error code that can be reported by {@link #onError}
+         * indicating that the camera device is in use already.
+         *
+         * <p>
+         * This error can be produced when opening the camera fails.
+         * </p>
+         *
+         * @see #onError
+         */
+        public static final int ERROR_CAMERA_IN_USE = 1;
+
+        /**
+         * An error code that can be reported by {@link #onError}
+         * indicating that the camera device could not be opened
+         * because there are too many other open camera devices.
+         *
+         * <p>
+         * The system-wide limit for number of open cameras has been reached,
+         * and more camera devices cannot be opened until previous instances are
+         * closed.
+         * </p>
+         *
+         * <p>
+         * This error can be produced when opening the camera fails.
+         * </p>
+         *
+         * @see #onError
+         */
+        public static final int ERROR_MAX_CAMERAS_IN_USE = 2;
+
+        /**
+         * An error code that can be reported by {@link #onError}
+         * indicating that the camera device could not be opened due to a device
+         * policy.
+         *
+         * @see android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName, boolean)
+         * @see #onError
+         */
+        public static final int ERROR_CAMERA_DISABLED = 3;
+
+       /**
+         * An error code that can be reported by {@link #onError}
+         * indicating that the camera device has encountered a fatal error.
+         *
+         * <p>The camera device needs to be re-opened to be used again.</p>
+         *
+         * @see #onError
+         */
+        public static final int ERROR_CAMERA_DEVICE = 4;
+
+        /**
+         * An error code that can be reported by {@link #onError}
+         * indicating that the camera service has encountered a fatal error.
+         *
+         * <p>The Android device may need to be shut down and restarted to restore
+         * camera function, or there may be a persistent hardware problem.</p>
+         *
+         * <p>An attempt at recovery <i>may</i> be possible by closing the
+         * CameraDevice and the CameraManager, and trying to acquire all resources
+         * again from scratch.</p>
+         *
+         * @see #onError
+         */
+        public static final int ERROR_CAMERA_SERVICE = 5;
+
+        /**
+         * The method called when a camera device has finished opening.
+         *
+         * <p>An opened camera will immediately afterwards transition into
+         * {@link #onUnconfigured}.</p>
+         *
+         * @param camera the camera device that has become opened
+         */
+        public abstract void onOpened(CameraDevice camera); // Must implement
+
+        /**
+         * 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
+         */
+        public void onUnconfigured(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * 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
+         */
+        public void onActive(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * 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
+         */
+        public void onBusy(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * The method called when a camera device has been closed with
+         * {@link CameraDevice#close}.
+         *
+         * <p>Any attempt to call methods on this CameraDevice in the
+         * future will throw a {@link IllegalStateException}.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param camera the camera device that has become closed
+         */
+        public void onClosed(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * 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
+         */
+        public void onIdle(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * The method called when a camera device is no longer available for
+         * use.
+         *
+         * <p>This callback may be called instead of {@link #onOpened}
+         * if opening the camera fails.</p>
+         *
+         * <p>Any attempt to call methods on this CameraDevice will throw a
+         * {@link CameraAccessException}. The disconnection could be due to a
+         * change in security policy or permissions; the physical disconnection
+         * of a removable camera device; or the camera being needed for a
+         * higher-priority use case.</p>
+         *
+         * <p>There may still be capture listener callbacks that are called
+         * after this method is called, or new image buffers that are delivered
+         * to active outputs.</p>
+         *
+         * <p>The default implementation logs a notice to the system log
+         * about the disconnection.</p>
+         *
+         * <p>You should clean up the camera with {@link CameraDevice#close} after
+         * this happens, as it is not recoverable until opening the camera again
+         * after it becomes {@link CameraManager.AvailabilityListener#onCameraAvailable available}.
+         * </p>
+         *
+         * @param camera the device that has been disconnected
+         */
+        public abstract void onDisconnected(CameraDevice camera); // Must implement
+
+        /**
+         * The method called when a camera device has encountered a serious error.
+         *
+         * <p>This callback may be called instead of {@link #onOpened}
+         * if opening the camera fails.</p>
+         *
+         * <p>This indicates a failure of the camera device or camera service in
+         * some way. Any attempt to call methods on this CameraDevice in the
+         * future will throw a {@link CameraAccessException} with the
+         * {@link CameraAccessException#CAMERA_ERROR CAMERA_ERROR} reason.
+         * </p>
+         *
+         * <p>There may still be capture completion or camera stream listeners
+         * that will be called after this error is received.</p>
+         *
+         * <p>You should clean up the camera with {@link CameraDevice#close} after
+         * this happens. Further attempts at recovery are error-code specific.</p>
+         *
+         * @param camera The device reporting the error
+         * @param error The error code, one of the
+         *     {@code CameraDeviceListener.ERROR_*} values.
+         *
+         * @see #ERROR_CAMERA_DEVICE
+         * @see #ERROR_CAMERA_SERVICE
+         * @see #ERROR_CAMERA_DISABLED
+         * @see #ERROR_CAMERA_IN_USE
+         */
+        public abstract void onError(CameraDevice camera, int error); // Must implement
+    }
+}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
new file mode 100644
index 0000000..f5ee367
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -0,0 +1,523 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.content.Context;
+import android.hardware.ICameraService;
+import android.hardware.ICameraServiceListener;
+import android.hardware.IProCameraUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.BinderHolder;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+
+/**
+ * <p>An interface for iterating, listing, and connecting to
+ * {@link CameraDevice CameraDevices}.</p>
+ *
+ * <p>You can get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(String) Context.getSystemService()}.</p>
+ *
+ * <pre>CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);</pre>
+ *
+ * <p>For more details about communicating with camera devices, read the Camera
+ * developer guide or the {@link android.hardware.camera2 camera2}
+ * package documentation.</p>
+ */
+public final class CameraManager {
+
+    /**
+     * This should match the ICameraService definition
+     */
+    private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
+    private static final int USE_CALLING_UID = -1;
+
+    private final ICameraService mCameraService;
+    private ArrayList<String> mDeviceIdList;
+
+    private final ArrayMap<AvailabilityListener, Handler> mListenerMap =
+            new ArrayMap<AvailabilityListener, Handler>();
+
+    private final Context mContext;
+    private final Object mLock = new Object();
+
+    /**
+     * @hide
+     */
+    public CameraManager(Context context) {
+        mContext = context;
+
+        IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
+        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
+
+        /**
+         * Wrap the camera service in a decorator which automatically translates return codes
+         * into exceptions, and RemoteExceptions into other exceptions.
+         */
+        mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw);
+
+        try {
+            mCameraService.addListener(new CameraServiceListener());
+        } catch(CameraRuntimeException e) {
+            throw new IllegalStateException("Failed to register a camera service listener",
+                    e.asChecked());
+        } catch (RemoteException e) {
+            // impossible
+        }
+    }
+
+    /**
+     * Return the list of currently connected camera devices by
+     * identifier.
+     *
+     * <p>Non-removable cameras use integers starting at 0 for their
+     * identifiers, while removable cameras have a unique identifier for each
+     * individual device, even if they are the same model.</p>
+     *
+     * @return The list of currently connected camera devices.
+     */
+    public String[] getCameraIdList() throws CameraAccessException {
+        synchronized (mLock) {
+            try {
+                return getOrCreateDeviceIdListLocked().toArray(new String[0]);
+            } catch(CameraAccessException e) {
+                // this should almost never happen, except if mediaserver crashes
+                throw new IllegalStateException(
+                        "Failed to query camera service for device ID list", e);
+            }
+        }
+    }
+
+    /**
+     * Register a listener to be notified about camera device availability.
+     *
+     * <p>Registering the same listener again will replace the handler with the
+     * new one provided.</p>
+     *
+     * @param listener The new listener to send camera availability notices to
+     * @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}.
+     */
+    public void addAvailabilityListener(AvailabilityListener listener, Handler handler) {
+        if (handler == null) {
+            Looper looper = Looper.myLooper();
+            if (looper == null) {
+                throw new IllegalArgumentException(
+                        "No handler given, and current thread has no looper!");
+            }
+            handler = new Handler(looper);
+        }
+
+        synchronized (mLock) {
+            mListenerMap.put(listener, handler);
+        }
+    }
+
+    /**
+     * Remove a previously-added listener; the listener will no longer receive
+     * connection and disconnection callbacks.
+     *
+     * <p>Removing a listener that isn't registered has no effect.</p>
+     *
+     * @param listener The listener to remove from the notification list
+     */
+    public void removeAvailabilityListener(AvailabilityListener listener) {
+        synchronized (mLock) {
+            mListenerMap.remove(listener);
+        }
+    }
+
+    /**
+     * <p>Query the capabilities of a camera device. These capabilities are
+     * immutable for a given camera.</p>
+     *
+     * @param cameraId The id of the camera device to query
+     * @return The properties of the given camera
+     *
+     * @throws IllegalArgumentException if the cameraId does not match any
+     * currently connected camera device.
+     * @throws CameraAccessException if the camera is disabled by device policy.
+     * @throws SecurityException if the application does not have permission to
+     * access the camera
+     *
+     * @see #getCameraIdList
+     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
+     */
+    public CameraCharacteristics getCameraCharacteristics(String cameraId)
+            throws CameraAccessException {
+
+        synchronized (mLock) {
+            if (!getOrCreateDeviceIdListLocked().contains(cameraId)) {
+                throw new IllegalArgumentException(String.format("Camera id %s does not match any" +
+                        " currently connected camera device", cameraId));
+            }
+        }
+
+        CameraMetadataNative info = new CameraMetadataNative();
+        try {
+            mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info);
+        } catch(CameraRuntimeException e) {
+            throw e.asChecked();
+        } catch(RemoteException e) {
+            // impossible
+            return null;
+        }
+
+        return new CameraCharacteristics(info);
+    }
+
+    /**
+     * Open a connection to a camera with the given ID. Use
+     * {@link #getCameraIdList} to get the list of available camera
+     * devices. Note that even if an id is listed, open may fail if the device
+     * is disconnected between the calls to {@link #getCameraIdList} and
+     * {@link #openCamera}.
+     *
+     * @param cameraId The unique identifier of the camera device to open
+     *
+     * @throws CameraAccessException if the camera is disabled by device policy,
+     * or too many camera devices are already open, or the cameraId does not match
+     * any currently available camera device.
+     *
+     * @throws SecurityException if the application does not have permission to
+     * access the camera
+     *
+     * @see #getCameraIdList
+     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
+     */
+    private CameraDevice openCamera(String cameraId) throws CameraAccessException {
+        try {
+
+            synchronized (mLock) {
+
+                ICameraDeviceUser cameraUser;
+
+                android.hardware.camera2.impl.CameraDevice device =
+                        new android.hardware.camera2.impl.CameraDevice(cameraId);
+
+                BinderHolder holder = new BinderHolder();
+                mCameraService.connectDevice(device.getCallbacks(),
+                        Integer.parseInt(cameraId),
+                        mContext.getPackageName(), USE_CALLING_UID, holder);
+                cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+
+                // TODO: factor out listener to be non-nested, then move setter to constructor
+                device.setRemoteDevice(cameraUser);
+
+                return device;
+
+            }
+
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+                    + cameraId);
+        } catch (CameraRuntimeException e) {
+            throw e.asChecked();
+        } catch (RemoteException e) {
+            // impossible
+            return null;
+        }
+    }
+
+    /**
+     * Open a connection to a camera with the given ID.
+     *
+     * <p>Use {@link #getCameraIdList} to get the list of available camera
+     * devices. Note that even if an id is listed, open may fail if the device
+     * is disconnected between the calls to {@link #getCameraIdList} and
+     * {@link #openCamera}.</p>
+     *
+     * <p>If the camera successfully opens after this function call returns,
+     * {@link CameraDevice.StateListener#onOpened} will be invoked with the
+     * newly opened {@link CameraDevice} in the unconfigured state.</p>
+     *
+     * <p>If the camera becomes disconnected during initialization
+     * after this function call returns,
+     * {@link CameraDevice.StateListener#onDisconnected} with a
+     * {@link CameraDevice} in the disconnected state (and
+     * {@link CameraDevice.StateListener#onOpened} will be skipped).</p>
+     *
+     * <p>If the camera fails to initialize after this function call returns,
+     * {@link CameraDevice.StateListener#onError} will be invoked with a
+     * {@link CameraDevice} in the error state (and
+     * {@link CameraDevice.StateListener#onOpened} will be skipped).</p>
+     *
+     * @param cameraId
+     *             The unique identifier of the camera device to open
+     * @param listener
+     *             The listener which is invoked once the camera is opened
+     * @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}.
+     *
+     * @throws CameraAccessException if the camera is disabled by device policy,
+     * or the camera has become or was disconnected.
+     *
+     * @throws IllegalArgumentException if cameraId or the listener was null,
+     * or the cameraId does not match any currently or previously available
+     * camera device.
+     *
+     * @throws SecurityException if the application does not have permission to
+     * access the camera
+     *
+     * @see #getCameraIdList
+     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
+     */
+    public void openCamera(String cameraId, final CameraDevice.StateListener listener,
+            Handler handler)
+            throws CameraAccessException {
+
+        if (cameraId == null) {
+            throw new IllegalArgumentException("cameraId was null");
+        } else if (listener == null) {
+            throw new IllegalArgumentException("listener was null");
+        } else if (handler == null) {
+            if (Looper.myLooper() != null) {
+                handler = new Handler();
+            } else {
+                throw new IllegalArgumentException(
+                        "Looper doesn't exist in the calling thread");
+            }
+        }
+
+        final CameraDevice camera = openCamera(cameraId);
+        camera.setDeviceListener(listener, handler);
+
+        // TODO: make truly async in the camera service
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                listener.onOpened(camera);
+            }
+        });
+    }
+
+    /**
+     * Interface for listening to camera devices becoming available or
+     * unavailable.
+     *
+     * <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>
+     *
+     * @see addAvailabilityListener
+     */
+    public static abstract class AvailabilityListener {
+
+        /**
+         * A new camera has become available to use.
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param cameraId The unique identifier of the new camera.
+         */
+        public void onCameraAvailable(String cameraId) {
+            // default empty implementation
+        }
+
+        /**
+         * A previously-available camera has become unavailable for use.
+         *
+         * <p>If an application had an active CameraDevice instance for the
+         * now-disconnected camera, that application will receive a
+         * {@link CameraDevice.StateListener#onDisconnected disconnection error}.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param cameraId The unique identifier of the disconnected camera.
+         */
+        public void onCameraUnavailable(String cameraId) {
+            // default empty implementation
+        }
+    }
+
+    private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
+        if (mDeviceIdList == null) {
+            int numCameras = 0;
+
+            try {
+                numCameras = mCameraService.getNumberOfCameras();
+            } catch(CameraRuntimeException e) {
+                throw e.asChecked();
+            } catch (RemoteException e) {
+                // impossible
+                return null;
+            }
+
+            mDeviceIdList = new ArrayList<String>();
+            CameraMetadataNative info = new CameraMetadataNative();
+            for (int i = 0; i < numCameras; ++i) {
+                // Non-removable cameras use integers starting at 0 for their
+                // identifiers
+                boolean isDeviceSupported = false;
+                try {
+                    mCameraService.getCameraCharacteristics(i, info);
+                    if (!info.isEmpty()) {
+                        isDeviceSupported = true;
+                    } else {
+                        throw new AssertionError("Expected to get non-empty characteristics");
+                    }
+                } catch(IllegalArgumentException  e) {
+                    // Got a BAD_VALUE from service, meaning that this
+                    // device is not supported.
+                } catch(CameraRuntimeException e) {
+                    throw e.asChecked();
+                } catch(RemoteException e) {
+                    // impossible
+                }
+
+                if (isDeviceSupported) {
+                    mDeviceIdList.add(String.valueOf(i));
+                }
+            }
+
+        }
+        return mDeviceIdList;
+    }
+
+    // TODO: this class needs unit tests
+    // TODO: extract class into top level
+    private class CameraServiceListener extends ICameraServiceListener.Stub {
+
+        // Keep up-to-date with ICameraServiceListener.h
+
+        // Device physically unplugged
+        public static final int STATUS_NOT_PRESENT = 0;
+        // Device physically has been plugged in
+        // and the camera can be used exclusively
+        public static final int STATUS_PRESENT = 1;
+        // Device physically has been plugged in
+        // but it will not be connect-able until enumeration is complete
+        public static final int STATUS_ENUMERATING = 2;
+        // Camera is in use by another app and cannot be used exclusively
+        public static final int STATUS_NOT_AVAILABLE = 0x80000000;
+
+        // Camera ID -> Status map
+        private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
+
+        private static final String TAG = "CameraServiceListener";
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        private boolean isAvailable(int status) {
+            switch (status) {
+                case STATUS_PRESENT:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        private boolean validStatus(int status) {
+            switch (status) {
+                case STATUS_NOT_PRESENT:
+                case STATUS_PRESENT:
+                case STATUS_ENUMERATING:
+                case STATUS_NOT_AVAILABLE:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        @Override
+        public void onStatusChanged(int status, int cameraId) throws RemoteException {
+            synchronized(CameraManager.this.mLock) {
+
+                Log.v(TAG,
+                        String.format("Camera id %d has status changed to 0x%x", cameraId, status));
+
+                final String id = String.valueOf(cameraId);
+
+                if (!validStatus(status)) {
+                    Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId,
+                            status));
+                    return;
+                }
+
+                Integer oldStatus = mDeviceStatus.put(id, status);
+
+                if (oldStatus != null && oldStatus == status) {
+                    Log.v(TAG, String.format(
+                            "Device status changed to 0x%x, which is what it already was",
+                            status));
+                    return;
+                }
+
+                // TODO: consider abstracting out this state minimization + transition
+                // into a separate
+                // more easily testable class
+                // i.e. (new State()).addState(STATE_AVAILABLE)
+                //                   .addState(STATE_NOT_AVAILABLE)
+                //                   .addTransition(STATUS_PRESENT, STATE_AVAILABLE),
+                //                   .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE)
+                //                   .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE);
+                //                   .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE);
+
+                // Translate all the statuses to either 'available' or 'not available'
+                //  available -> available         => no new update
+                //  not available -> not available => no new update
+                if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) {
+
+                    Log.v(TAG,
+                            String.format(
+                                    "Device status was previously available (%d), " +
+                                            " and is now again available (%d)" +
+                                            "so no new client visible update will be sent",
+                                    isAvailable(status), isAvailable(status)));
+                    return;
+                }
+
+                final int listenerCount = mListenerMap.size();
+                for (int i = 0; i < listenerCount; i++) {
+                    Handler handler = mListenerMap.valueAt(i);
+                    final AvailabilityListener listener = mListenerMap.keyAt(i);
+                    if (isAvailable(status)) {
+                        handler.post(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    listener.onCameraAvailable(id);
+                                }
+                            });
+                    } else {
+                        handler.post(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    listener.onCameraUnavailable(id);
+                                }
+                            });
+                    }
+                } // for
+            } // synchronized
+        } // onStatusChanged
+    } // CameraServiceListener
+} // CameraManager
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
new file mode 100644
index 0000000..1d6ff7d
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -0,0 +1,1251 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The base class for camera controls and information.
+ *
+ * <p>
+ * This class defines the basic key/value map used for querying for camera
+ * characteristics or capture results, and for setting camera request
+ * parameters.
+ * </p>
+ *
+ * <p>
+ * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()}
+ * never changes, nor do the values returned by any key with {@link #get} throughout
+ * the lifetime of the object.
+ * </p>
+ *
+ * @see CameraDevice
+ * @see CameraManager
+ * @see CameraCharacteristics
+ **/
+public abstract class CameraMetadata {
+
+    /**
+     * Set a camera metadata field to a value. The field definitions can be
+     * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
+     * {@link CaptureRequest}.
+     *
+     * @param key The metadata field to write.
+     * @param value The value to set the field to, which must be of a matching
+     * type to the key.
+     *
+     * @hide
+     */
+    protected CameraMetadata() {
+    }
+
+    /**
+     * Get a camera metadata field value.
+     *
+     * <p>The field definitions can be
+     * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
+     * {@link CaptureRequest}.</p>
+     *
+     * <p>Querying the value for the same key more than once will return a value
+     * which is equal to the previous queried value.</p>
+     *
+     * @throws IllegalArgumentException if the key was not valid
+     *
+     * @param key The metadata field to read.
+     * @return The value of that key, or {@code null} if the field is not set.
+     */
+    public abstract <T> T get(Key<T> key);
+
+    /**
+     * Returns a list of the keys contained in this map.
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>All values retrieved by a key from this list with {@link #get} are guaranteed to be
+     * non-{@code null}. Each key is only listed once in the list. The order of the keys
+     * is undefined.</p>
+     *
+     * @return List of the keys contained in this map.
+     */
+    public List<Key<?>> getKeys() {
+        return Collections.unmodifiableList(getKeysStatic(this.getClass(), this));
+    }
+
+    /**
+     * Return a list of all the Key<?> that are declared as a field inside of the class
+     * {@code type}.
+     *
+     * <p>
+     * Optionally, if {@code instance} is not null, then filter out any keys with null values.
+     * </p>
+     */
+    /*package*/ static ArrayList<Key<?>> getKeysStatic(Class<? extends CameraMetadata> type,
+            CameraMetadata instance) {
+        ArrayList<Key<?>> keyList = new ArrayList<Key<?>>();
+
+        Field[] fields = type.getDeclaredFields();
+        for (Field field : fields) {
+            // Filter for Keys that are public
+            if (field.getType().isAssignableFrom(Key.class) &&
+                    (field.getModifiers() & Modifier.PUBLIC) != 0) {
+                Key<?> key;
+                try {
+                    key = (Key<?>) field.get(instance);
+                } catch (IllegalAccessException e) {
+                    throw new AssertionError("Can't get IllegalAccessException", e);
+                } catch (IllegalArgumentException e) {
+                    throw new AssertionError("Can't get IllegalArgumentException", e);
+                }
+                if (instance == null || instance.get(key) != null) {
+                    keyList.add(key);
+                }
+            }
+        }
+
+        return keyList;
+    }
+
+    public static class Key<T> {
+
+        private boolean mHasTag;
+        private int mTag;
+        private final Class<T> mType;
+        private final String mName;
+
+        /**
+         * @hide
+         */
+        public Key(String name, Class<T> type) {
+            if (name == null) {
+                throw new NullPointerException("Key needs a valid name");
+            } else if (type == null) {
+                throw new NullPointerException("Type needs to be non-null");
+            }
+            mName = name;
+            mType = type;
+        }
+
+        public final String getName() {
+            return mName;
+        }
+
+        @Override
+        public final int hashCode() {
+            return mName.hashCode();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public final boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            if (!(o instanceof Key)) {
+                return false;
+            }
+
+            Key lhs = (Key) o;
+
+            return mName.equals(lhs.mName);
+        }
+
+        /**
+         * <p>
+         * Get the tag corresponding to this key. This enables insertion into the
+         * native metadata.
+         * </p>
+         *
+         * <p>This value is looked up the first time, and cached subsequently.</p>
+         *
+         * @return The tag numeric value corresponding to the string
+         *
+         * @hide
+         */
+        public final int getTag() {
+            if (!mHasTag) {
+                mTag = CameraMetadataNative.getTag(mName);
+                mHasTag = true;
+            }
+            return mTag;
+        }
+
+        /**
+         * @hide
+         */
+        public final Class<T> getType() {
+            return mType;
+        }
+    }
+
+    /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * The enum values below this point are generated from metadata
+     * definitions in /system/media/camera/docs. Do not modify by hand or
+     * modify the comment blocks at the start or end.
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+    //
+    // Enumeration values for CameraCharacteristics#LENS_FACING
+    //
+
+    /**
+     * @see CameraCharacteristics#LENS_FACING
+     */
+    public static final int LENS_FACING_FRONT = 0;
+
+    /**
+     * @see CameraCharacteristics#LENS_FACING
+     */
+    public static final int LENS_FACING_BACK = 1;
+
+    //
+    // Enumeration values for CameraCharacteristics#LED_AVAILABLE_LEDS
+    //
+
+    /**
+     * <p>
+     * android.led.transmit control is used
+     * </p>
+     * @see CameraCharacteristics#LED_AVAILABLE_LEDS
+     * @hide
+     */
+    public static final int LED_AVAILABLE_LEDS_TRANSMIT = 0;
+
+    //
+    // Enumeration values for CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+    //
+
+    /**
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
+
+    /**
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
+
+    //
+    // Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE
+    //
+
+    /**
+     * <p>
+     * Use the android.colorCorrection.transform matrix
+     * and android.colorCorrection.gains to do color conversion
+     * </p>
+     * @see CaptureRequest#COLOR_CORRECTION_MODE
+     */
+    public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0;
+
+    /**
+     * <p>
+     * Must not slow down frame rate relative to raw
+     * bayer output
+     * </p>
+     * @see CaptureRequest#COLOR_CORRECTION_MODE
+     */
+    public static final int COLOR_CORRECTION_MODE_FAST = 1;
+
+    /**
+     * <p>
+     * Frame rate may be reduced by high
+     * quality
+     * </p>
+     * @see CaptureRequest#COLOR_CORRECTION_MODE
+     */
+    public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+    //
+
+    /**
+     * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+     */
+    public static final int CONTROL_AE_ANTIBANDING_MODE_OFF = 0;
+
+    /**
+     * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+     */
+    public static final int CONTROL_AE_ANTIBANDING_MODE_50HZ = 1;
+
+    /**
+     * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+     */
+    public static final int CONTROL_AE_ANTIBANDING_MODE_60HZ = 2;
+
+    /**
+     * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+     */
+    public static final int CONTROL_AE_ANTIBANDING_MODE_AUTO = 3;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_AE_MODE
+    //
+
+    /**
+     * <p>
+     * Autoexposure is disabled; sensor.exposureTime,
+     * sensor.sensitivity and sensor.frameDuration are used
+     * </p>
+     * @see CaptureRequest#CONTROL_AE_MODE
+     */
+    public static final int CONTROL_AE_MODE_OFF = 0;
+
+    /**
+     * <p>
+     * Autoexposure is active, no flash
+     * control
+     * </p>
+     * @see CaptureRequest#CONTROL_AE_MODE
+     */
+    public static final int CONTROL_AE_MODE_ON = 1;
+
+    /**
+     * <p>
+     * if flash exists Autoexposure is active, auto
+     * flash control; flash may be fired when precapture
+     * trigger is activated, and for captures for which
+     * captureIntent = STILL_CAPTURE
+     * </p>
+     * @see CaptureRequest#CONTROL_AE_MODE
+     */
+    public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2;
+
+    /**
+     * <p>
+     * if flash exists Autoexposure is active, auto
+     * flash control for precapture trigger and always flash
+     * when captureIntent = STILL_CAPTURE
+     * </p>
+     * @see CaptureRequest#CONTROL_AE_MODE
+     */
+    public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3;
+
+    /**
+     * <p>
+     * optional Automatic red eye reduction with flash.
+     * If deemed necessary, red eye reduction sequence should
+     * fire when precapture trigger is activated, and final
+     * flash should fire when captureIntent =
+     * STILL_CAPTURE
+     * </p>
+     * @see CaptureRequest#CONTROL_AE_MODE
+     */
+    public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+    //
+
+    /**
+     * <p>
+     * The trigger is idle.
+     * </p>
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     */
+    public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0;
+
+    /**
+     * <p>
+     * The precapture metering sequence
+     * must be started. 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;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_AF_MODE
+    //
+
+    /**
+     * <p>
+     * The 3A routines do not control the lens;
+     * android.lens.focusDistance is controlled by the
+     * application
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_MODE
+     */
+    public static final int CONTROL_AF_MODE_OFF = 0;
+
+    /**
+     * <p>
+     * if lens is not fixed focus.
+     * </p><p>
+     * Use android.lens.minimumFocusDistance to determine if lens
+     * is fixed focus 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
+     * the outcome of the scan (FOCUSED or
+     * NOT_FOCUSED).
+     * </p><p>
+     * Triggering cancel AF resets the lens position to default,
+     * and sets the AF state to INACTIVE.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_MODE
+     */
+    public static final int CONTROL_AF_MODE_AUTO = 1;
+
+    /**
+     * <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
+     * ACTIVE_SCAN, then to the outcome of the scan (FOCUSED or
+     * NOT_FOCUSED).  Triggering cancel AF resets the lens
+     * position to default, and sets the AF state to
+     * INACTIVE.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_MODE
+     */
+    public static final int CONTROL_AF_MODE_MACRO = 2;
+
+    /**
+     * <p>
+     * In this mode, the AF algorithm modifies the lens
+     * position continually to attempt to provide a
+     * constantly-in-focus image stream.
+     * </p><p>
+     * The focusing behavior should be suitable for good quality
+     * video recording; typically this means slower focus
+     * movement and no overshoots. When the AF trigger is not
+     * involved, the AF algorithm should start in INACTIVE state,
+     * and then transition into PASSIVE_SCAN and PASSIVE_FOCUSED
+     * states as appropriate. When the AF trigger is activated,
+     * the algorithm should immediately transition into
+     * AF_FOCUSED or AF_NOT_FOCUSED as appropriate, and lock the
+     * lens position until a cancel AF trigger is received.
+     * </p><p>
+     * Once cancel is received, the algorithm should transition
+     * back to INACTIVE and resume passive scan. Note that this
+     * behavior is not identical to CONTINUOUS_PICTURE, since an
+     * ongoing PASSIVE_SCAN must immediately be
+     * canceled.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_MODE
+     */
+    public static final int CONTROL_AF_MODE_CONTINUOUS_VIDEO = 3;
+
+    /**
+     * <p>
+     * In this mode, the AF algorithm modifies the lens
+     * position continually to attempt to provide a
+     * constantly-in-focus image stream.
+     * </p><p>
+     * The focusing behavior should be suitable for still image
+     * capture; typically this means focusing as fast as
+     * possible. When the AF trigger is not involved, the AF
+     * algorithm should start in INACTIVE state, and then
+     * transition into PASSIVE_SCAN and PASSIVE_FOCUSED states as
+     * appropriate as it attempts to maintain focus. When the AF
+     * trigger is activated, the algorithm should finish its
+     * PASSIVE_SCAN if active, and then transition into
+     * AF_FOCUSED or AF_NOT_FOCUSED as appropriate, and lock the
+     * lens position until a cancel AF trigger is received.
+     * </p><p>
+     * When the AF cancel trigger is activated, the algorithm
+     * should transition back to INACTIVE and then act as if it
+     * has just been started.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_MODE
+     */
+    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
+     * INACTIVE.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_MODE
+     */
+    public static final int CONTROL_AF_MODE_EDOF = 5;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_AF_TRIGGER
+    //
+
+    /**
+     * <p>
+     * The trigger is idle.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
+     */
+    public static final int CONTROL_AF_TRIGGER_IDLE = 0;
+
+    /**
+     * <p>
+     * Autofocus must trigger now.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
+     */
+    public static final int CONTROL_AF_TRIGGER_START = 1;
+
+    /**
+     * <p>
+     * Autofocus must return to initial
+     * state, and cancel any active trigger.
+     * </p>
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
+     */
+    public static final int CONTROL_AF_TRIGGER_CANCEL = 2;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_AWB_MODE
+    //
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_OFF = 0;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_AUTO = 1;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_INCANDESCENT = 2;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_FLUORESCENT = 3;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_WARM_FLUORESCENT = 4;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_DAYLIGHT = 5;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_TWILIGHT = 7;
+
+    /**
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     */
+    public static final int CONTROL_AWB_MODE_SHADE = 8;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_CAPTURE_INTENT
+    //
+
+    /**
+     * <p>
+     * This request doesn't fall into the other
+     * categories. 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>
+     * @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>
+     * @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>
+     * @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>
+     * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+     */
+    public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
+
+    /**
+     * <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>
+     * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+     */
+    public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_EFFECT_MODE
+    //
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_OFF = 0;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_MONO = 1;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_NEGATIVE = 2;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_SOLARIZE = 3;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_SEPIA = 4;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_POSTERIZE = 5;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_WHITEBOARD = 6;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_BLACKBOARD = 7;
+
+    /**
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     */
+    public static final int CONTROL_EFFECT_MODE_AQUA = 8;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_MODE
+    //
+
+    /**
+     * <p>
+     * Full application control of pipeline. All 3A
+     * routines are disabled, no other settings in
+     * android.control.* have any effect
+     * </p>
+     * @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
+     * controls in android.control.* besides sceneMode take
+     * 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 HAL must 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 availableSceneModes !=
+     * UNSUPPORTED
+     * </p>
+     * @see CaptureRequest#CONTROL_MODE
+     */
+    public static final int CONTROL_MODE_USE_SCENE_MODE = 2;
+
+    //
+    // Enumeration values for CaptureRequest#CONTROL_SCENE_MODE
+    //
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_UNSUPPORTED = 0;
+
+    /**
+     * <p>
+     * if face detection support exists Use face
+     * detection data to drive 3A routines. If face detection
+     * statistics are disabled, should still operate correctly
+     * (but not return face detection statistics to the
+     * framework).
+     * </p><p>
+     * Unlike the other scene modes, aeMode, awbMode, and afMode
+     * remain active when FACE_PRIORITY is set. This is due to
+     * compatibility concerns with the old camera
+     * API
+     * </p>
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_ACTION = 2;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_PORTRAIT = 3;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_LANDSCAPE = 4;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_NIGHT = 5;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_THEATRE = 7;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_BEACH = 8;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_SNOW = 9;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_SUNSET = 10;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_STEADYPHOTO = 11;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_FIREWORKS = 12;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_SPORTS = 13;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_PARTY = 14;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15;
+
+    /**
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_BARCODE = 16;
+
+    //
+    // Enumeration values for CaptureRequest#EDGE_MODE
+    //
+
+    /**
+     * <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 raw
+     * bayer output
+     * </p>
+     * @see CaptureRequest#EDGE_MODE
+     */
+    public static final int EDGE_MODE_FAST = 1;
+
+    /**
+     * <p>
+     * Frame rate may be reduced by high
+     * quality
+     * </p>
+     * @see CaptureRequest#EDGE_MODE
+     */
+    public static final int EDGE_MODE_HIGH_QUALITY = 2;
+
+    //
+    // Enumeration values for CaptureRequest#FLASH_MODE
+    //
+
+    /**
+     * <p>
+     * Do not fire the flash for this
+     * capture
+     * </p>
+     * @see CaptureRequest#FLASH_MODE
+     */
+    public static final int FLASH_MODE_OFF = 0;
+
+    /**
+     * <p>
+     * if android.flash.available is true Fire flash
+     * for this capture based on firingPower,
+     * firingTime.
+     * </p>
+     * @see CaptureRequest#FLASH_MODE
+     */
+    public static final int FLASH_MODE_SINGLE = 1;
+
+    /**
+     * <p>
+     * if android.flash.available is true Flash
+     * continuously on, power set by
+     * firingPower
+     * </p>
+     * @see CaptureRequest#FLASH_MODE
+     */
+    public static final int FLASH_MODE_TORCH = 2;
+
+    //
+    // Enumeration values for CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
+    //
+
+    /**
+     * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
+     */
+    public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0;
+
+    /**
+     * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
+     */
+    public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1;
+
+    //
+    // Enumeration values for CaptureRequest#NOISE_REDUCTION_MODE
+    //
+
+    /**
+     * <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 raw
+     * bayer 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>
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     */
+    public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
+
+    //
+    // Enumeration values for CaptureRequest#STATISTICS_FACE_DETECT_MODE
+    //
+
+    /**
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     */
+    public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0;
+
+    /**
+     * <p>
+     * Optional Return rectangle and confidence
+     * only
+     * </p>
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     */
+    public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1;
+
+    /**
+     * <p>
+     * Optional Return all face
+     * metadata
+     * </p>
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     */
+    public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
+
+    //
+    // Enumeration values for CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+    //
+
+    /**
+     * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+     */
+    public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0;
+
+    /**
+     * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+     */
+    public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
+
+    //
+    // Enumeration values for CaptureRequest#TONEMAP_MODE
+    //
+
+    /**
+     * <p>
+     * Use the tone mapping curve specified in
+     * android.tonemap.curve
+     * </p>
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
+
+    /**
+     * <p>
+     * Must not slow down frame rate relative to raw
+     * bayer output
+     * </p>
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_FAST = 1;
+
+    /**
+     * <p>
+     * Frame rate may be reduced by high
+     * quality
+     * </p>
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
+
+    //
+    // Enumeration values for CaptureResult#CONTROL_AE_STATE
+    //
+
+    /**
+     * <p>
+     * AE is off.  When a camera device is opened, it starts in
+     * this state.
+     * </p>
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final int CONTROL_AE_STATE_INACTIVE = 0;
+
+    /**
+     * <p>
+     * AE doesn't yet have a good set of control values
+     * for the current scene
+     * </p>
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final int CONTROL_AE_STATE_SEARCHING = 1;
+
+    /**
+     * <p>
+     * AE has a good set of control values for the
+     * current scene
+     * </p>
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final int CONTROL_AE_STATE_CONVERGED = 2;
+
+    /**
+     * <p>
+     * AE has been locked (aeMode =
+     * LOCKED)
+     * </p>
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final int CONTROL_AE_STATE_LOCKED = 3;
+
+    /**
+     * <p>
+     * AE has a good set of control values, but flash
+     * needs to be fired for good quality still
+     * capture
+     * </p>
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final int CONTROL_AE_STATE_FLASH_REQUIRED = 4;
+
+    /**
+     * <p>
+     * AE has been asked to do a precapture sequence
+     * (through the
+     * trigger_action(CAMERA2_TRIGGER_PRECAPTURE_METERING)
+     * call), and is currently executing it. Once PRECAPTURE
+     * completes, AE will transition to CONVERGED or
+     * FLASH_REQUIRED as appropriate
+     * </p>
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final int CONTROL_AE_STATE_PRECAPTURE = 5;
+
+    //
+    // Enumeration values for CaptureResult#CONTROL_AF_STATE
+    //
+
+    /**
+     * <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.
+     * </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
+     * </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.
+     * </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
+     * </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>
+     * @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>
+     * @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.
+     * </p>
+     * @see CaptureResult#CONTROL_AF_STATE
+     */
+    public static final int CONTROL_AF_STATE_PASSIVE_UNFOCUSED = 6;
+
+    //
+    // Enumeration values for CaptureResult#CONTROL_AWB_STATE
+    //
+
+    /**
+     * <p>
+     * AWB is not in auto mode.  When a camera device is opened, it
+     * starts in this state.
+     * </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
+     * </p>
+     * @see CaptureResult#CONTROL_AWB_STATE
+     */
+    public static final int CONTROL_AWB_STATE_SEARCHING = 1;
+
+    /**
+     * <p>
+     * AWB has a good set of control values for the
+     * current scene
+     * </p>
+     * @see CaptureResult#CONTROL_AWB_STATE
+     */
+    public static final int CONTROL_AWB_STATE_CONVERGED = 2;
+
+    /**
+     * <p>
+     * AE has been locked (aeMode =
+     * LOCKED)
+     * </p>
+     * @see CaptureResult#CONTROL_AWB_STATE
+     */
+    public static final int CONTROL_AWB_STATE_LOCKED = 3;
+
+    //
+    // Enumeration values for CaptureResult#FLASH_STATE
+    //
+
+    /**
+     * <p>
+     * No flash on camera
+     * </p>
+     * @see CaptureResult#FLASH_STATE
+     */
+    public static final int FLASH_STATE_UNAVAILABLE = 0;
+
+    /**
+     * <p>
+     * if android.flash.available is true Flash is
+     * charging and cannot be fired
+     * </p>
+     * @see CaptureResult#FLASH_STATE
+     */
+    public static final int FLASH_STATE_CHARGING = 1;
+
+    /**
+     * <p>
+     * if android.flash.available is true Flash is
+     * ready to fire
+     * </p>
+     * @see CaptureResult#FLASH_STATE
+     */
+    public static final int FLASH_STATE_READY = 2;
+
+    /**
+     * <p>
+     * if android.flash.available is true Flash fired
+     * for this capture
+     * </p>
+     * @see CaptureResult#FLASH_STATE
+     */
+    public static final int FLASH_STATE_FIRED = 3;
+
+    //
+    // Enumeration values for CaptureResult#LENS_STATE
+    //
+
+    /**
+     * @see CaptureResult#LENS_STATE
+     */
+    public static final int LENS_STATE_STATIONARY = 0;
+
+    /**
+     * @see CaptureResult#LENS_STATE
+     */
+    public static final int LENS_STATE_MOVING = 1;
+
+    //
+    // Enumeration values for CaptureResult#STATISTICS_SCENE_FLICKER
+    //
+
+    /**
+     * @see CaptureResult#STATISTICS_SCENE_FLICKER
+     */
+    public static final int STATISTICS_SCENE_FLICKER_NONE = 0;
+
+    /**
+     * @see CaptureResult#STATISTICS_SCENE_FLICKER
+     */
+    public static final int STATISTICS_SCENE_FLICKER_50HZ = 1;
+
+    /**
+     * @see CaptureResult#STATISTICS_SCENE_FLICKER
+     */
+    public static final int STATISTICS_SCENE_FLICKER_60HZ = 2;
+
+    /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * End generated code
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+}
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
new file mode 100644
index 0000000..3b408cf
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -0,0 +1,144 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.hardware.camera2.CameraDevice.CaptureListener;
+
+/**
+ * A report of failed capture for a single image capture from the image sensor.
+ *
+ * <p>CaptureFailures are produced by a {@link CameraDevice} if processing a
+ * {@link CaptureRequest} fails, either partially or fully. Use {@link #getReason}
+ * to determine the specific nature of the failed capture.</p>
+ *
+ * <p>Receiving a CaptureFailure means that the metadata associated with that frame number
+ * has been dropped -- no {@link CaptureResult} with the same frame number will be
+ * produced.</p>
+ */
+public class CaptureFailure {
+    /**
+     * The {@link CaptureResult} has been dropped this frame only due to an error
+     * in the framework.
+     *
+     * @see #getReason()
+     */
+    public static final int REASON_ERROR = 0;
+
+    /**
+     * The capture has failed due to a {@link CameraDevice#flush} call from the application.
+     *
+     * @see #getReason()
+     */
+    public static final int REASON_FLUSHED = 1;
+
+    private final CaptureRequest mRequest;
+    private final int mReason;
+    private final boolean mDropped;
+    private final int mSequenceId;
+    private final int mFrameNumber;
+
+    /**
+     * @hide
+     */
+    public CaptureFailure(CaptureRequest request, int reason, boolean dropped, int sequenceId,
+            int frameNumber) {
+        mRequest = request;
+        mReason = reason;
+        mDropped = dropped;
+        mSequenceId = sequenceId;
+        mFrameNumber = frameNumber;
+    }
+
+    /**
+     * Get the request associated with this failed capture.
+     *
+     * <p>Whenever a request is unsuccessfully captured, with
+     * {@link CameraDevice.CaptureListener#onCaptureFailed},
+     * the {@code failed capture}'s {@code getRequest()} will return that {@code request}.
+     * </p>
+     *
+     * <p>In particular,
+     * <code><pre>cameraDevice.capture(someRequest, new CaptureListener() {
+     *     {@literal @}Override
+     *     void onCaptureFailed(CaptureRequest myRequest, CaptureFailure myFailure) {
+     *         assert(myFailure.getRequest.equals(myRequest) == true);
+     *     }
+     * };
+     * </code></pre>
+     * </p>
+     *
+     * @return The request associated with this failed capture. Never {@code null}.
+     */
+    public CaptureRequest getRequest() {
+        return mRequest;
+    }
+
+    /**
+     * Get the frame number associated with this failed capture.
+     *
+     * <p>Whenever a request has been processed, regardless of failed capture or success,
+     * it gets a unique frame number assigned to its future result/failed capture.</p>
+     *
+     * <p>This value monotonically increments, starting with 0,
+     * for every new result or failure; and the scope is the lifetime of the
+     * {@link CameraDevice}.</p>
+     *
+     * @return int frame number
+     */
+    public int getFrameNumber() {
+        return mFrameNumber;
+    }
+
+    /**
+     * Determine why the request was dropped, whether due to an error or to a user
+     * action.
+     *
+     * @return int One of {@code REASON_*} integer constants.
+     *
+     * @see #REASON_ERROR
+     * @see #REASON_FLUSHED
+     */
+    public int getReason() {
+        return mReason;
+    }
+
+    /**
+     * Determine if the image was captured from the camera.
+     *
+     * <p>If the image was not captured, no image buffers will be available.
+     * If the image was captured, then image buffers may be available.</p>
+     *
+     * @return boolean True if the image was captured, false otherwise.
+     */
+    public boolean wasImageCaptured() {
+        return !mDropped;
+    }
+
+    /**
+     * The sequence ID for this failed capture that was returned by the
+     * {@link CameraDevice#capture} family of functions.
+     *
+     * <p>The sequence ID is a unique monotonically increasing value starting from 0,
+     * incremented every time a new group of requests is submitted to the CameraDevice.</p>
+     *
+     * @return int The ID for the sequence of requests that this capture failure is the result of
+     *
+     * @see CameraDevice.CaptureListener#onCaptureSequenceCompleted
+     */
+    public int getSequenceId() {
+        return mSequenceId;
+    }
+}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.aidl b/core/java/android/hardware/camera2/CaptureRequest.aidl
new file mode 100644
index 0000000..0b7d5ba
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureRequest.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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 android.hardware.camera2;
+
+/** @hide */
+parcelable CaptureRequest;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
new file mode 100644
index 0000000..f30bcc5
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -0,0 +1,1125 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.CameraDevice.CaptureListener;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.Surface;
+
+import java.util.HashSet;
+import java.util.Objects;
+
+
+/**
+ * <p>An immutable package of settings and outputs needed to capture a single
+ * image from the camera device.</p>
+ *
+ * <p>Contains the configuration for the capture hardware (sensor, lens, flash),
+ * the processing pipeline, the control algorithms, and the output buffers. Also
+ * contains the list of target Surfaces to send image data to for this
+ * capture.</p>
+ *
+ * <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>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>
+ *
+ * <p>For example, a request meant for repeating preview might only include the
+ * Surface for the preview SurfaceView or SurfaceTexture, while a
+ * high-resolution still capture would also include a Surface from a ImageReader
+ * configured for high-resolution JPEG images.</p>
+ *
+ * @see CameraDevice#capture
+ * @see CameraDevice#setRepeatingRequest
+ * @see CameraDevice#createCaptureRequest
+ */
+public final class CaptureRequest extends CameraMetadata implements Parcelable {
+
+    private final HashSet<Surface> mSurfaceSet;
+    private final CameraMetadataNative mSettings;
+
+    private Object mUserTag;
+
+    /**
+     * Construct empty request.
+     *
+     * Used by Binder to unparcel this object only.
+     */
+    private CaptureRequest() {
+        mSettings = new CameraMetadataNative();
+        mSurfaceSet = new HashSet<Surface>();
+    }
+
+    /**
+     * Clone from source capture request.
+     *
+     * Used by the Builder to create an immutable copy.
+     */
+    @SuppressWarnings("unchecked")
+    private CaptureRequest(CaptureRequest source) {
+        mSettings = new CameraMetadataNative(source.mSettings);
+        mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone();
+    }
+
+    /**
+     * Take ownership of passed-in settings.
+     *
+     * Used by the Builder to create a mutable CaptureRequest.
+     */
+    private CaptureRequest(CameraMetadataNative settings) {
+        mSettings = settings;
+        mSurfaceSet = new HashSet<Surface>();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T get(Key<T> key) {
+        return mSettings.get(key);
+    }
+
+    /**
+     * Retrieve the tag for this request, if any.
+     *
+     * <p>This tag is not used for anything by the camera device, but can be
+     * used by an application to easily identify a CaptureRequest when it is
+     * returned by
+     * {@link CameraDevice.CaptureListener#onCaptureCompleted CaptureListener.onCaptureCompleted}
+     * </p>
+     *
+     * @return the last tag Object set on this request, or {@code null} if
+     *     no tag has been set.
+     * @see Builder#setTag
+     */
+    public Object getTag() {
+        return mUserTag;
+    }
+
+    /**
+     * Determine whether this CaptureRequest is equal to another CaptureRequest.
+     *
+     * <p>A request is considered equal to another is if it's set of key/values is equal, it's
+     * list of output surfaces is equal, and the user tag is equal.</p>
+     *
+     * @param other Another instance of CaptureRequest.
+     *
+     * @return True if the requests are the same, false otherwise.
+     */
+    @Override
+    public boolean equals(Object other) {
+        return other instanceof CaptureRequest
+                && equals((CaptureRequest)other);
+    }
+
+    private boolean equals(CaptureRequest other) {
+        return other != null
+                && Objects.equals(mUserTag, other.mUserTag)
+                && mSurfaceSet.equals(other.mSurfaceSet)
+                && mSettings.equals(other.mSettings);
+    }
+
+    @Override
+    public int hashCode() {
+        return mSettings.hashCode();
+    }
+
+    public static final Parcelable.Creator<CaptureRequest> CREATOR =
+            new Parcelable.Creator<CaptureRequest>() {
+        @Override
+        public CaptureRequest createFromParcel(Parcel in) {
+            CaptureRequest request = new CaptureRequest();
+            request.readFromParcel(in);
+
+            return request;
+        }
+
+        @Override
+        public CaptureRequest[] newArray(int size) {
+            return new CaptureRequest[size];
+        }
+    };
+
+    /**
+     * Expand this object from a Parcel.
+     * Hidden since this breaks the immutability of CaptureRequest, but is
+     * needed to receive CaptureRequests with aidl.
+     *
+     * @param in The parcel from which the object should be read
+     * @hide
+     */
+    public void readFromParcel(Parcel in) {
+        mSettings.readFromParcel(in);
+
+        mSurfaceSet.clear();
+
+        Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader());
+
+        if (parcelableArray == null) {
+            return;
+        }
+
+        for (Parcelable p : parcelableArray) {
+            Surface s = (Surface) p;
+            mSurfaceSet.add(s);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        mSettings.writeToParcel(dest, flags);
+        dest.writeParcelableArray(mSurfaceSet.toArray(new Surface[mSurfaceSet.size()]), flags);
+    }
+
+    /**
+     * A builder for capture requests.
+     *
+     * <p>To obtain a builder instance, use the
+     * {@link CameraDevice#createCaptureRequest} method, which initializes the
+     * 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
+     */
+    public final static class Builder {
+
+        private final CaptureRequest mRequest;
+
+        /**
+         * Initialize the builder using the template; the request takes
+         * ownership of the template.
+         *
+         * @hide
+         */
+        public Builder(CameraMetadataNative template) {
+            mRequest = new CaptureRequest(template);
+        }
+
+        /**
+         * <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
+         * request is given to the camera device.</p>
+         *
+         * <p>Adding a target more than once has no effect.</p>
+         *
+         * @param outputTarget Surface to use as an output target for this request
+         */
+        public void addTarget(Surface outputTarget) {
+            mRequest.mSurfaceSet.add(outputTarget);
+        }
+
+        /**
+         * <p>Remove a surface from the list of targets for this request.</p>
+         *
+         * <p>Removing a target that is not currently added has no effect.</p>
+         *
+         * @param outputTarget Surface to use as an output target for this request
+         */
+        public void removeTarget(Surface outputTarget) {
+            mRequest.mSurfaceSet.remove(outputTarget);
+        }
+
+        /**
+         * Set a capture request field to a value. The field definitions can be
+         * found in {@link CaptureRequest}.
+         *
+         * @param key The metadata field to write.
+         * @param value The value to set the field to, which must be of a matching
+         * type to the key.
+         */
+        public <T> void set(Key<T> key, T value) {
+            mRequest.mSettings.set(key, value);
+        }
+
+        /**
+         * Get a capture request field value. The field definitions can be
+         * found in {@link CaptureRequest}.
+         *
+         * @throws IllegalArgumentException if the key was not valid
+         *
+         * @param key The metadata field to read.
+         * @return The value of that key, or {@code null} if the field is not set.
+         */
+        public <T> T get(Key<T> key) {
+            return mRequest.mSettings.get(key);
+        }
+
+        /**
+         * Set a tag for this request.
+         *
+         * <p>This tag is not used for anything by the camera device, but can be
+         * used by an application to easily identify a CaptureRequest when it is
+         * returned by
+         * {@link CameraDevice.CaptureListener#onCaptureCompleted CaptureListener.onCaptureCompleted}
+         *
+         * @param tag an arbitrary Object to store with this request
+         * @see CaptureRequest#getTag
+         */
+        public void setTag(Object tag) {
+            mRequest.mUserTag = tag;
+        }
+
+        /**
+         * Build a request using the current target Surfaces and settings.
+         *
+         * @return A new capture request instance, ready for submission to the
+         * camera device.
+         */
+        public CaptureRequest build() {
+            return new CaptureRequest(mRequest);
+        }
+
+
+        /**
+         * @hide
+         */
+        public boolean isEmpty() {
+            return mRequest.mSettings.isEmpty();
+        }
+
+    }
+
+    /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * The key entries below this point are generated from metadata
+     * definitions in /system/media/camera/docs. Do not modify by hand or
+     * modify the comment blocks at the start or end.
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+    /**
+     * <p>
+     * When android.control.awbMode is not OFF, TRANSFORM_MATRIX
+     * should be ignored.
+     * </p>
+     * @see #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX
+     * @see #COLOR_CORRECTION_MODE_FAST
+     * @see #COLOR_CORRECTION_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> COLOR_CORRECTION_MODE =
+            new Key<Integer>("android.colorCorrection.mode", int.class);
+
+    /**
+     * <p>
+     * A color transform matrix to use to transform
+     * from sensor RGB color space to output linear sRGB color space
+     * </p>
+     * <p>
+     * This matrix is either set by HAL when the request
+     * android.colorCorrection.mode is not TRANSFORM_MATRIX, or
+     * directly by the application in the request when the
+     * android.colorCorrection.mode is TRANSFORM_MATRIX.
+     * </p><p>
+     * In the latter case, the HAL may round the matrix to account
+     * for precision issues; the final rounded matrix should be
+     * reported back in this matrix result metadata.
+     * </p>
+     */
+    public static final Key<Rational[]> COLOR_CORRECTION_TRANSFORM =
+            new Key<Rational[]>("android.colorCorrection.transform", Rational[].class);
+
+    /**
+     * <p>
+     * Gains applying to Bayer color channels for
+     * white-balance
+     * </p>
+     * <p>
+     * The 4-channel white-balance gains are defined in
+     * the order of [R G_even G_odd B], where G_even is the gain
+     * for green pixels on even rows of the output, and G_odd
+     * is the gain for greenpixels on the odd rows. if a HAL
+     * does not support a separate gain for even/odd green channels,
+     * it should use the G_even value,and write G_odd equal to
+     * G_even in the output result metadata.
+     * </p><p>
+     * This array is either set by HAL when the request
+     * android.colorCorrection.mode is not TRANSFORM_MATRIX, or
+     * directly by the application in the request when the
+     * android.colorCorrection.mode is TRANSFORM_MATRIX.
+     * </p><p>
+     * The ouput should be the gains actually applied by the HAL to
+     * the current frame.
+     * </p>
+     */
+    public static final Key<float[]> COLOR_CORRECTION_GAINS =
+            new Key<float[]>("android.colorCorrection.gains", float[].class);
+
+    /**
+     * <p>
+     * Enum for controlling
+     * antibanding
+     * </p>
+     * @see #CONTROL_AE_ANTIBANDING_MODE_OFF
+     * @see #CONTROL_AE_ANTIBANDING_MODE_50HZ
+     * @see #CONTROL_AE_ANTIBANDING_MODE_60HZ
+     * @see #CONTROL_AE_ANTIBANDING_MODE_AUTO
+     */
+    public static final Key<Integer> CONTROL_AE_ANTIBANDING_MODE =
+            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
+     * </p>
+     */
+    public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
+            new Key<Integer>("android.control.aeExposureCompensation", int.class);
+
+    /**
+     * <p>
+     * Whether 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 AE mode is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
+     * ON_AUTO_FLASH_REDEYE.
+     * </p>
+     */
+    public static final Key<Boolean> CONTROL_AE_LOCK =
+            new Key<Boolean>("android.control.aeLock", boolean.class);
+
+    /**
+     * <p>
+     * Whether AE is currently updating the sensor
+     * exposure and sensitivity fields
+     * </p>
+     * <p>
+     * Only effective if android.control.mode =
+     * AUTO
+     * </p>
+     * @see #CONTROL_AE_MODE_OFF
+     * @see #CONTROL_AE_MODE_ON
+     * @see #CONTROL_AE_MODE_ON_AUTO_FLASH
+     * @see #CONTROL_AE_MODE_ON_ALWAYS_FLASH
+     * @see #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
+     */
+    public static final Key<Integer> CONTROL_AE_MODE =
+            new Key<Integer>("android.control.aeMode", int.class);
+
+    /**
+     * <p>
+     * List of areas to use for
+     * metering
+     * </p>
+     * <p>
+     * Each area is a rectangle plus weight: xmin, ymin,
+     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * specified coordinates.
+     * </p><p>
+     * The coordinate system is based on the active pixel array,
+     * with (0,0) being the top-left pixel in the active pixel array, and
+     * (android.sensor.info.activeArraySize.width - 1,
+     * android.sensor.info.activeArraySize.height - 1) being the
+     * bottom-right pixel in the active pixel array. The weight
+     * should be nonnegative.
+     * </p><p>
+     * If all regions have 0 weight, then no specific metering area
+     * needs to be used by the HAL. If the metering region is
+     * outside the current android.scaler.cropRegion, the HAL
+     * should ignore the sections outside the region and output the
+     * used sections in the frame metadata
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AE_REGIONS =
+            new Key<int[]>("android.control.aeRegions", int[].class);
+
+    /**
+     * <p>
+     * Range over which fps can be adjusted to
+     * maintain exposure
+     * </p>
+     * <p>
+     * Only constrains AE algorithm, not manual control
+     * of android.sensor.exposureTime
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
+            new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
+
+    /**
+     * <p>
+     * Whether the HAL must trigger precapture
+     * metering.
+     * </p>
+     * <p>
+     * This entry is normally set to IDLE, or is not
+     * included at all in the request settings. When included and
+     * set to START, the HAL must trigger the autoexposure
+     * precapture metering sequence.
+     * </p><p>
+     * The effect of AE precapture trigger depends on the current
+     * AE mode and state; see the camera HAL device v3 header for
+     * details.
+     * </p>
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+     */
+    public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
+            new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
+
+    /**
+     * <p>
+     * Whether AF is currently enabled, and what
+     * mode it is set to
+     * </p>
+     * @see #CONTROL_AF_MODE_OFF
+     * @see #CONTROL_AF_MODE_AUTO
+     * @see #CONTROL_AF_MODE_MACRO
+     * @see #CONTROL_AF_MODE_CONTINUOUS_VIDEO
+     * @see #CONTROL_AF_MODE_CONTINUOUS_PICTURE
+     * @see #CONTROL_AF_MODE_EDOF
+     */
+    public static final Key<Integer> CONTROL_AF_MODE =
+            new Key<Integer>("android.control.afMode", int.class);
+
+    /**
+     * <p>
+     * List of areas to use for focus
+     * estimation
+     * </p>
+     * <p>
+     * Each area is a rectangle plus weight: xmin, ymin,
+     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * specified coordinates.
+     * </p><p>
+     * The coordinate system is based on the active pixel array,
+     * with (0,0) being the top-left pixel in the active pixel array, and
+     * (android.sensor.info.activeArraySize.width - 1,
+     * android.sensor.info.activeArraySize.height - 1) being the
+     * bottom-right pixel in the active pixel array. The weight
+     * should be nonnegative.
+     * </p><p>
+     * If all regions have 0 weight, then no specific focus area
+     * needs to be used by the HAL. If the focusing region is
+     * outside the current android.scaler.cropRegion, the HAL
+     * should ignore the sections outside the region and output the
+     * used sections in the frame metadata
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AF_REGIONS =
+            new Key<int[]>("android.control.afRegions", int[].class);
+
+    /**
+     * <p>
+     * Whether the HAL must trigger autofocus.
+     * </p>
+     * <p>
+     * This entry is normally set to IDLE, or is not
+     * included at all in the request settings.
+     * </p><p>
+     * When included and set to START, the HAL must trigger the
+     * autofocus algorithm. The effect of AF trigger depends on the
+     * current AF mode and state; see the camera HAL device v3
+     * header for details. When set to CANCEL, the HAL must cancel
+     * any active trigger, and return to initial AF state.
+     * </p>
+     * @see #CONTROL_AF_TRIGGER_IDLE
+     * @see #CONTROL_AF_TRIGGER_START
+     * @see #CONTROL_AF_TRIGGER_CANCEL
+     */
+    public static final Key<Integer> CONTROL_AF_TRIGGER =
+            new Key<Integer>("android.control.afTrigger", int.class);
+
+    /**
+     * <p>
+     * Whether 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>
+     */
+    public static final Key<Boolean> CONTROL_AWB_LOCK =
+            new Key<Boolean>("android.control.awbLock", boolean.class);
+
+    /**
+     * <p>
+     * Whether AWB is currently setting the color
+     * transform fields, and what its illumination target
+     * is
+     * </p>
+     * <p>
+     * [BC - AWB lock,AWB modes]
+     * </p>
+     * @see #CONTROL_AWB_MODE_OFF
+     * @see #CONTROL_AWB_MODE_AUTO
+     * @see #CONTROL_AWB_MODE_INCANDESCENT
+     * @see #CONTROL_AWB_MODE_FLUORESCENT
+     * @see #CONTROL_AWB_MODE_WARM_FLUORESCENT
+     * @see #CONTROL_AWB_MODE_DAYLIGHT
+     * @see #CONTROL_AWB_MODE_CLOUDY_DAYLIGHT
+     * @see #CONTROL_AWB_MODE_TWILIGHT
+     * @see #CONTROL_AWB_MODE_SHADE
+     */
+    public static final Key<Integer> CONTROL_AWB_MODE =
+            new Key<Integer>("android.control.awbMode", int.class);
+
+    /**
+     * <p>
+     * List of areas to use for illuminant
+     * estimation
+     * </p>
+     * <p>
+     * Only used in AUTO mode.
+     * </p><p>
+     * Each area is a rectangle plus weight: xmin, ymin,
+     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * specified coordinates.
+     * </p><p>
+     * The coordinate system is based on the active pixel array,
+     * with (0,0) being the top-left pixel in the active pixel array, and
+     * (android.sensor.info.activeArraySize.width - 1,
+     * android.sensor.info.activeArraySize.height - 1) being the
+     * bottom-right pixel in the active pixel array. The weight
+     * should be nonnegative.
+     * </p><p>
+     * If all regions have 0 weight, then no specific metering area
+     * needs to be used by the HAL. If the metering region is
+     * outside the current android.scaler.cropRegion, the HAL
+     * should ignore the sections outside the region and output the
+     * used sections in the frame metadata
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AWB_REGIONS =
+            new Key<int[]>("android.control.awbRegions", int[].class);
+
+    /**
+     * <p>
+     * Information to 3A routines about the purpose
+     * of this capture, to help decide optimal 3A
+     * strategy
+     * </p>
+     * <p>
+     * Only used if android.control.mode != OFF.
+     * </p>
+     * @see #CONTROL_CAPTURE_INTENT_CUSTOM
+     * @see #CONTROL_CAPTURE_INTENT_PREVIEW
+     * @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE
+     * @see #CONTROL_CAPTURE_INTENT_VIDEO_RECORD
+     * @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
+     * @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
+     */
+    public static final Key<Integer> CONTROL_CAPTURE_INTENT =
+            new Key<Integer>("android.control.captureIntent", int.class);
+
+    /**
+     * <p>
+     * Whether any special color effect is in use.
+     * Only used if android.control.mode != OFF
+     * </p>
+     * @see #CONTROL_EFFECT_MODE_OFF
+     * @see #CONTROL_EFFECT_MODE_MONO
+     * @see #CONTROL_EFFECT_MODE_NEGATIVE
+     * @see #CONTROL_EFFECT_MODE_SOLARIZE
+     * @see #CONTROL_EFFECT_MODE_SEPIA
+     * @see #CONTROL_EFFECT_MODE_POSTERIZE
+     * @see #CONTROL_EFFECT_MODE_WHITEBOARD
+     * @see #CONTROL_EFFECT_MODE_BLACKBOARD
+     * @see #CONTROL_EFFECT_MODE_AQUA
+     */
+    public static final Key<Integer> CONTROL_EFFECT_MODE =
+            new Key<Integer>("android.control.effectMode", int.class);
+
+    /**
+     * <p>
+     * Overall mode of 3A control
+     * routines
+     * </p>
+     * @see #CONTROL_MODE_OFF
+     * @see #CONTROL_MODE_AUTO
+     * @see #CONTROL_MODE_USE_SCENE_MODE
+     */
+    public static final Key<Integer> CONTROL_MODE =
+            new Key<Integer>("android.control.mode", int.class);
+
+    /**
+     * <p>
+     * Which scene mode is active when
+     * android.control.mode = SCENE_MODE
+     * </p>
+     * @see #CONTROL_SCENE_MODE_UNSUPPORTED
+     * @see #CONTROL_SCENE_MODE_FACE_PRIORITY
+     * @see #CONTROL_SCENE_MODE_ACTION
+     * @see #CONTROL_SCENE_MODE_PORTRAIT
+     * @see #CONTROL_SCENE_MODE_LANDSCAPE
+     * @see #CONTROL_SCENE_MODE_NIGHT
+     * @see #CONTROL_SCENE_MODE_NIGHT_PORTRAIT
+     * @see #CONTROL_SCENE_MODE_THEATRE
+     * @see #CONTROL_SCENE_MODE_BEACH
+     * @see #CONTROL_SCENE_MODE_SNOW
+     * @see #CONTROL_SCENE_MODE_SUNSET
+     * @see #CONTROL_SCENE_MODE_STEADYPHOTO
+     * @see #CONTROL_SCENE_MODE_FIREWORKS
+     * @see #CONTROL_SCENE_MODE_SPORTS
+     * @see #CONTROL_SCENE_MODE_PARTY
+     * @see #CONTROL_SCENE_MODE_CANDLELIGHT
+     * @see #CONTROL_SCENE_MODE_BARCODE
+     */
+    public static final Key<Integer> CONTROL_SCENE_MODE =
+            new Key<Integer>("android.control.sceneMode", int.class);
+
+    /**
+     * <p>
+     * Whether video stabilization is
+     * active
+     * </p>
+     * <p>
+     * If enabled, video stabilization can modify the
+     * android.scaler.cropRegion to keep the video stream
+     * stabilized
+     * </p>
+     */
+    public static final Key<Boolean> CONTROL_VIDEO_STABILIZATION_MODE =
+            new Key<Boolean>("android.control.videoStabilizationMode", boolean.class);
+
+    /**
+     * <p>
+     * Operation mode for edge
+     * enhancement
+     * </p>
+     * @see #EDGE_MODE_OFF
+     * @see #EDGE_MODE_FAST
+     * @see #EDGE_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> EDGE_MODE =
+            new Key<Integer>("android.edge.mode", int.class);
+
+    /**
+     * <p>
+     * Select flash operation mode
+     * </p>
+     * @see #FLASH_MODE_OFF
+     * @see #FLASH_MODE_SINGLE
+     * @see #FLASH_MODE_TORCH
+     */
+    public static final Key<Integer> FLASH_MODE =
+            new Key<Integer>("android.flash.mode", int.class);
+
+    /**
+     * <p>
+     * GPS coordinates to include in output JPEG
+     * EXIF
+     * </p>
+     */
+    public static final Key<double[]> JPEG_GPS_COORDINATES =
+            new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
+
+    /**
+     * <p>
+     * 32 characters describing GPS algorithm to
+     * include in EXIF
+     * </p>
+     */
+    public static final Key<String> JPEG_GPS_PROCESSING_METHOD =
+            new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
+
+    /**
+     * <p>
+     * Time GPS fix was made to include in
+     * EXIF
+     * </p>
+     */
+    public static final Key<Long> JPEG_GPS_TIMESTAMP =
+            new Key<Long>("android.jpeg.gpsTimestamp", long.class);
+
+    /**
+     * <p>
+     * Orientation of JPEG image to
+     * write
+     * </p>
+     */
+    public static final Key<Integer> JPEG_ORIENTATION =
+            new Key<Integer>("android.jpeg.orientation", int.class);
+
+    /**
+     * <p>
+     * Compression quality of the final JPEG
+     * 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>
+     */
+    public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
+            new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
+
+    /**
+     * <p>
+     * Resolution of embedded JPEG
+     * thumbnail
+     * </p>
+     */
+    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+
+    /**
+     * <p>
+     * Size of the lens aperture
+     * </p>
+     * <p>
+     * Will not be supported on most devices. Can only
+     * pick from supported list
+     * </p>
+     */
+    public static final Key<Float> LENS_APERTURE =
+            new Key<Float>("android.lens.aperture", float.class);
+
+    /**
+     * <p>
+     * State of lens neutral density
+     * filter(s)
+     * </p>
+     * <p>
+     * Will not be supported on most devices. Can only
+     * pick from supported list
+     * </p>
+     */
+    public static final Key<Float> LENS_FILTER_DENSITY =
+            new Key<Float>("android.lens.filterDensity", float.class);
+
+    /**
+     * <p>
+     * Lens optical zoom setting
+     * </p>
+     * <p>
+     * Will not be supported on most devices.
+     * </p>
+     */
+    public static final Key<Float> LENS_FOCAL_LENGTH =
+            new Key<Float>("android.lens.focalLength", float.class);
+
+    /**
+     * <p>
+     * Distance to plane of sharpest focus,
+     * measured from frontmost surface of the lens
+     * </p>
+     * <p>
+     * 0 = infinity focus. Used value should be clamped
+     * to (0,minimum focus distance)
+     * </p>
+     */
+    public static final Key<Float> LENS_FOCUS_DISTANCE =
+            new Key<Float>("android.lens.focusDistance", float.class);
+
+    /**
+     * <p>
+     * Whether optical image stabilization is
+     * enabled.
+     * </p>
+     * <p>
+     * Will not be supported on most devices.
+     * </p>
+     * @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
+     * @see #LENS_OPTICAL_STABILIZATION_MODE_ON
+     */
+    public static final Key<Integer> LENS_OPTICAL_STABILIZATION_MODE =
+            new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
+
+    /**
+     * <p>
+     * Mode of operation for the noise reduction
+     * algorithm
+     * </p>
+     * @see #NOISE_REDUCTION_MODE_OFF
+     * @see #NOISE_REDUCTION_MODE_FAST
+     * @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> NOISE_REDUCTION_MODE =
+            new Key<Integer>("android.noiseReduction.mode", int.class);
+
+    /**
+     * <p>
+     * An application-specified ID for the current
+     * request. Must be maintained unchanged in output
+     * frame
+     * </p>
+     *
+     * @hide
+     */
+    public static final Key<Integer> REQUEST_ID =
+            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>
+     * Any additional per-stream cropping must 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
+     * (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
+     * 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 /
+     * android.scaler.maxDigitalZoom ) and floor(
+     * activeArraySize.height / android.scaler.maxDigitalZoom),
+     * respectively.
+     * </p>
+     */
+    public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
+            new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
+
+    /**
+     * <p>
+     * Duration each pixel is exposed to
+     * light.
+     * </p><p>
+     * If the sensor can't expose this exact duration, it should shorten the
+     * duration exposed to the nearest possible value (rather than expose longer).
+     * </p>
+     * <p>
+     * 1/10000 - 30 sec range. No bulb mode
+     * </p>
+     */
+    public static final Key<Long> SENSOR_EXPOSURE_TIME =
+            new Key<Long>("android.sensor.exposureTime", long.class);
+
+    /**
+     * <p>
+     * Duration from start of frame exposure to
+     * start of next frame exposure
+     * </p>
+     * <p>
+     * Exposure time has priority, so duration is set to
+     * max(duration, exposure time + overhead)
+     * </p>
+     */
+    public static final Key<Long> SENSOR_FRAME_DURATION =
+            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>
+     */
+    public static final Key<Integer> SENSOR_SENSITIVITY =
+            new Key<Integer>("android.sensor.sensitivity", int.class);
+
+    /**
+     * <p>
+     * State of 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
+     * android.statistics.info.availableFaceDetectModes.
+     * </p>
+     * @see #STATISTICS_FACE_DETECT_MODE_OFF
+     * @see #STATISTICS_FACE_DETECT_MODE_SIMPLE
+     * @see #STATISTICS_FACE_DETECT_MODE_FULL
+     */
+    public static final Key<Integer> STATISTICS_FACE_DETECT_MODE =
+            new Key<Integer>("android.statistics.faceDetectMode", int.class);
+
+    /**
+     * <p>
+     * Whether the HAL needs to output the lens
+     * shading map in output result metadata
+     * </p>
+     * <p>
+     * When set to ON,
+     * android.statistics.lensShadingMap must be provided in
+     * the output result metdata.
+     * </p>
+     * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
+     * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
+     */
+    public static final Key<Integer> STATISTICS_LENS_SHADING_MAP_MODE =
+            new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
+
+    /**
+     * <p>
+     * Table mapping blue input values to output
+     * values
+     * </p>
+     * <p>
+     * Tonemapping / contrast / gamma curve for the blue
+     * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
+     * </p><p>
+     * See android.tonemap.curveRed for more details.
+     * </p>
+     */
+    public static final Key<float[]> TONEMAP_CURVE_BLUE =
+            new Key<float[]>("android.tonemap.curveBlue", float[].class);
+
+    /**
+     * <p>
+     * Table mapping green input values to output
+     * values
+     * </p>
+     * <p>
+     * Tonemapping / contrast / gamma curve for the green
+     * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
+     * </p><p>
+     * See android.tonemap.curveRed for more details.
+     * </p>
+     */
+    public static final Key<float[]> TONEMAP_CURVE_GREEN =
+            new Key<float[]>("android.tonemap.curveGreen", float[].class);
+
+    /**
+     * <p>
+     * Table mapping red input values to output
+     * values
+     * </p>
+     * <p>
+     * Tonemapping / contrast / gamma curve for the red
+     * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
+     * </p><p>
+     * Since the input and output ranges may vary depending on
+     * the camera pipeline, the input and output pixel values
+     * are represented by normalized floating-point values
+     * between 0 and 1, with 0 == black and 1 == white.
+     * </p><p>
+     * The curve should be linearly interpolated between the
+     * defined points. The points will be listed in increasing
+     * order of P_IN. For example, if the array is: [0.0, 0.0,
+     * 0.3, 0.5, 1.0, 1.0], then the input->output mapping
+     * for a few sample points would be: 0 -> 0, 0.15 ->
+     * 0.25, 0.3 -> 0.5, 0.5 -> 0.64
+     * </p>
+     */
+    public static final Key<float[]> TONEMAP_CURVE_RED =
+            new Key<float[]>("android.tonemap.curveRed", float[].class);
+
+    /**
+     * @see #TONEMAP_MODE_CONTRAST_CURVE
+     * @see #TONEMAP_MODE_FAST
+     * @see #TONEMAP_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> TONEMAP_MODE =
+            new Key<Integer>("android.tonemap.mode", int.class);
+
+    /**
+     * <p>
+     * This LED is nominally used to indicate to the user
+     * that the camera is powered on and may be streaming images back to the
+     * Application Processor. In certain rare circumstances, the OS may
+     * disable this when video is processed locally and not transmitted to
+     * any untrusted applications.
+     * </p><p>
+     * In particular, the LED *must* always be on when the data could be
+     * transmitted off the device. The LED *should* always be on whenever
+     * data is stored locally on the device.
+     * </p><p>
+     * The LED *may* be off if a trusted application is using the data that
+     * doesn't violate the above rules.
+     * </p>
+     *
+     * @hide
+     */
+    public static final Key<Boolean> LED_TRANSMIT =
+            new Key<Boolean>("android.led.transmit", boolean.class);
+
+    /**
+     * <p>
+     * Whether black-level compensation is locked
+     * to its current values, or is free to vary
+     * </p>
+     * <p>
+     * When set to ON, the values used for black-level
+     * compensation must not change until the lock is set to
+     * OFF
+     * </p><p>
+     * Since changes to certain capture parameters (such as
+     * exposure time) may require resetting of black level
+     * compensation, the HAL must report whether setting the
+     * black level lock was successful in the output result
+     * metadata.
+     * </p><p>
+     * The black level locking must happen at the sensor, and not at the ISP.
+     * If for some reason black level locking is no longer legal (for example,
+     * the analog gain has changed, which forces black levels to be
+     * recalculated), then the HAL is free to override this request (and it
+     * must report 'OFF' when this does happen) until the next time locking
+     * is legal again.
+     * </p>
+     */
+    public static final Key<Boolean> BLACK_LEVEL_LOCK =
+            new Key<Boolean>("android.blackLevel.lock", boolean.class);
+
+    /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * End generated code
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+}
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
new file mode 100644
index 0000000..c9626f1
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/**
+ * <p>The results of a single image capture from the image sensor.</p>
+ *
+ * <p>Contains the final configuration for the capture hardware (sensor, lens,
+ * flash), the processing pipeline, the control algorithms, and the output
+ * buffers.</p>
+ *
+ * <p>CaptureResults are produced by a {@link CameraDevice} after processing a
+ * {@link CaptureRequest}. All properties listed for capture requests can also
+ * be queried on the capture result, to determine the final values used for
+ * capture. The result also includes additional metadata about the state of the
+ * camera device during the capture.</p>
+ *
+ */
+public final class CaptureResult extends CameraMetadata {
+
+    private final CameraMetadataNative mResults;
+    private final CaptureRequest mRequest;
+    private final int mSequenceId;
+
+    /**
+     * Takes ownership of the passed-in properties object
+     * @hide
+     */
+    public CaptureResult(CameraMetadataNative results, CaptureRequest parent, int sequenceId) {
+        if (results == null) {
+            throw new IllegalArgumentException("results was null");
+        }
+
+        if (parent == null) {
+            throw new IllegalArgumentException("parent was null");
+        }
+
+        mResults = results;
+        mRequest = parent;
+        mSequenceId = sequenceId;
+    }
+
+    @Override
+    public <T> T get(Key<T> key) {
+        if (key == STATISTICS_FACES) { // Don't throw IllegalArgumentException
+            // TODO: Implement android.statistics.faces
+            return null;
+        }
+
+        return mResults.get(key);
+    }
+
+    /**
+     * Get the request associated with this result.
+     *
+     * <p>Whenever a request is successfully captured, with
+     * {@link CameraDevice.CaptureListener#onCaptureCompleted},
+     * the {@code result}'s {@code getRequest()} will return that {@code request}.
+     * </p>
+     *
+     * <p>In particular,
+     * <code><pre>cameraDevice.capture(someRequest, new CaptureListener() {
+     *     {@literal @}Override
+     *     void onCaptureCompleted(CaptureRequest myRequest, CaptureResult myResult) {
+     *         assert(myResult.getRequest.equals(myRequest) == true);
+     *     }
+     * };
+     * </code></pre>
+     * </p>
+     *
+     * @return The request associated with this result. Never {@code null}.
+     */
+    public CaptureRequest getRequest() {
+        return mRequest;
+    }
+
+    /**
+     * Get the frame number associated with this result.
+     *
+     * <p>Whenever a request has been processed, regardless of failure or success,
+     * it gets a unique frame number assigned to its future result/failure.</p>
+     *
+     * <p>This value monotonically increments, starting with 0,
+     * for every new result or failure; and the scope is the lifetime of the
+     * {@link CameraDevice}.</p>
+     *
+     * @return int frame number
+     */
+    public int getFrameNumber() {
+        return get(REQUEST_FRAME_COUNT);
+    }
+
+    /**
+     * The sequence ID for this failure that was returned by the
+     * {@link CameraDevice#capture} family of functions.
+     *
+     * <p>The sequence ID is a unique monotonically increasing value starting from 0,
+     * incremented every time a new group of requests is submitted to the CameraDevice.</p>
+     *
+     * @return int The ID for the sequence of requests that this capture result is a part of
+     *
+     * @see CameraDevice.CaptureListener#onCaptureSequenceCompleted
+     */
+    public int getSequenceId() {
+        return mSequenceId;
+    }
+
+    /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * The key entries below this point are generated from metadata
+     * definitions in /system/media/camera/docs. Do not modify by hand or
+     * modify the comment blocks at the start or end.
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+    /**
+     * <p>
+     * A color transform matrix to use to transform
+     * from sensor RGB color space to output linear sRGB color space
+     * </p>
+     * <p>
+     * This matrix is either set by HAL when the request
+     * android.colorCorrection.mode is not TRANSFORM_MATRIX, or
+     * directly by the application in the request when the
+     * android.colorCorrection.mode is TRANSFORM_MATRIX.
+     * </p><p>
+     * In the latter case, the HAL may round the matrix to account
+     * for precision issues; the final rounded matrix should be
+     * reported back in this matrix result metadata.
+     * </p>
+     */
+    public static final Key<Rational[]> COLOR_CORRECTION_TRANSFORM =
+            new Key<Rational[]>("android.colorCorrection.transform", Rational[].class);
+
+    /**
+     * <p>
+     * Gains applying to Bayer color channels for
+     * white-balance
+     * </p>
+     * <p>
+     * The 4-channel white-balance gains are defined in
+     * the order of [R G_even G_odd B], where G_even is the gain
+     * for green pixels on even rows of the output, and G_odd
+     * is the gain for greenpixels on the odd rows. if a HAL
+     * does not support a separate gain for even/odd green channels,
+     * it should use the G_even value,and write G_odd equal to
+     * G_even in the output result metadata.
+     * </p><p>
+     * This array is either set by HAL when the request
+     * android.colorCorrection.mode is not TRANSFORM_MATRIX, or
+     * directly by the application in the request when the
+     * android.colorCorrection.mode is TRANSFORM_MATRIX.
+     * </p><p>
+     * The ouput should be the gains actually applied by the HAL to
+     * the current frame.
+     * </p>
+     */
+    public static final Key<float[]> COLOR_CORRECTION_GAINS =
+            new Key<float[]>("android.colorCorrection.gains", float[].class);
+
+    /**
+     * <p>
+     * The ID sent with the latest
+     * CAMERA2_TRIGGER_PRECAPTURE_METERING call
+     * </p>
+     * <p>
+     * Must be 0 if no
+     * CAMERA2_TRIGGER_PRECAPTURE_METERING trigger received yet
+     * by HAL. Always updated even if AE algorithm ignores the
+     * trigger
+     * </p>
+     *
+     * @hide
+     */
+    public static final Key<Integer> CONTROL_AE_PRECAPTURE_ID =
+            new Key<Integer>("android.control.aePrecaptureId", int.class);
+
+    /**
+     * <p>
+     * List of areas to use for
+     * metering
+     * </p>
+     * <p>
+     * Each area is a rectangle plus weight: xmin, ymin,
+     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * specified coordinates.
+     * </p><p>
+     * The coordinate system is based on the active pixel array,
+     * with (0,0) being the top-left pixel in the active pixel array, and
+     * (android.sensor.info.activeArraySize.width - 1,
+     * android.sensor.info.activeArraySize.height - 1) being the
+     * bottom-right pixel in the active pixel array. The weight
+     * should be nonnegative.
+     * </p><p>
+     * If all regions have 0 weight, then no specific metering area
+     * needs to be used by the HAL. If the metering region is
+     * outside the current android.scaler.cropRegion, the HAL
+     * should ignore the sections outside the region and output the
+     * used sections in the frame metadata
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AE_REGIONS =
+            new Key<int[]>("android.control.aeRegions", int[].class);
+
+    /**
+     * <p>
+     * Current state of AE algorithm
+     * </p>
+     * <p>
+     * Whenever the AE algorithm state changes, a
+     * MSG_AUTOEXPOSURE notification must be send if a
+     * notification callback is registered.
+     * </p>
+     * @see #CONTROL_AE_STATE_INACTIVE
+     * @see #CONTROL_AE_STATE_SEARCHING
+     * @see #CONTROL_AE_STATE_CONVERGED
+     * @see #CONTROL_AE_STATE_LOCKED
+     * @see #CONTROL_AE_STATE_FLASH_REQUIRED
+     * @see #CONTROL_AE_STATE_PRECAPTURE
+     */
+    public static final Key<Integer> CONTROL_AE_STATE =
+            new Key<Integer>("android.control.aeState", int.class);
+
+    /**
+     * <p>
+     * Whether AF is currently enabled, and what
+     * mode it is set to
+     * </p>
+     * @see #CONTROL_AF_MODE_OFF
+     * @see #CONTROL_AF_MODE_AUTO
+     * @see #CONTROL_AF_MODE_MACRO
+     * @see #CONTROL_AF_MODE_CONTINUOUS_VIDEO
+     * @see #CONTROL_AF_MODE_CONTINUOUS_PICTURE
+     * @see #CONTROL_AF_MODE_EDOF
+     */
+    public static final Key<Integer> CONTROL_AF_MODE =
+            new Key<Integer>("android.control.afMode", int.class);
+
+    /**
+     * <p>
+     * List of areas to use for focus
+     * estimation
+     * </p>
+     * <p>
+     * Each area is a rectangle plus weight: xmin, ymin,
+     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * specified coordinates.
+     * </p><p>
+     * The coordinate system is based on the active pixel array,
+     * with (0,0) being the top-left pixel in the active pixel array, and
+     * (android.sensor.info.activeArraySize.width - 1,
+     * android.sensor.info.activeArraySize.height - 1) being the
+     * bottom-right pixel in the active pixel array. The weight
+     * should be nonnegative.
+     * </p><p>
+     * If all regions have 0 weight, then no specific focus area
+     * needs to be used by the HAL. If the focusing region is
+     * outside the current android.scaler.cropRegion, the HAL
+     * should ignore the sections outside the region and output the
+     * used sections in the frame metadata
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AF_REGIONS =
+            new Key<int[]>("android.control.afRegions", int[].class);
+
+    /**
+     * <p>
+     * Current state of AF algorithm
+     * </p>
+     * <p>
+     * Whenever the AF algorithm state changes, a
+     * MSG_AUTOFOCUS notification must be send if a notification
+     * callback is registered.
+     * </p>
+     * @see #CONTROL_AF_STATE_INACTIVE
+     * @see #CONTROL_AF_STATE_PASSIVE_SCAN
+     * @see #CONTROL_AF_STATE_PASSIVE_FOCUSED
+     * @see #CONTROL_AF_STATE_ACTIVE_SCAN
+     * @see #CONTROL_AF_STATE_FOCUSED_LOCKED
+     * @see #CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
+     * @see #CONTROL_AF_STATE_PASSIVE_UNFOCUSED
+     */
+    public static final Key<Integer> CONTROL_AF_STATE =
+            new Key<Integer>("android.control.afState", int.class);
+
+    /**
+     * <p>
+     * The ID sent with the latest
+     * CAMERA2_TRIGGER_AUTOFOCUS call
+     * </p>
+     * <p>
+     * Must be 0 if no CAMERA2_TRIGGER_AUTOFOCUS trigger
+     * received yet by HAL. Always updated even if AF algorithm
+     * ignores the trigger
+     * </p>
+     *
+     * @hide
+     */
+    public static final Key<Integer> CONTROL_AF_TRIGGER_ID =
+            new Key<Integer>("android.control.afTriggerId", int.class);
+
+    /**
+     * <p>
+     * Whether AWB is currently setting the color
+     * transform fields, and what its illumination target
+     * is
+     * </p>
+     * <p>
+     * [BC - AWB lock,AWB modes]
+     * </p>
+     * @see #CONTROL_AWB_MODE_OFF
+     * @see #CONTROL_AWB_MODE_AUTO
+     * @see #CONTROL_AWB_MODE_INCANDESCENT
+     * @see #CONTROL_AWB_MODE_FLUORESCENT
+     * @see #CONTROL_AWB_MODE_WARM_FLUORESCENT
+     * @see #CONTROL_AWB_MODE_DAYLIGHT
+     * @see #CONTROL_AWB_MODE_CLOUDY_DAYLIGHT
+     * @see #CONTROL_AWB_MODE_TWILIGHT
+     * @see #CONTROL_AWB_MODE_SHADE
+     */
+    public static final Key<Integer> CONTROL_AWB_MODE =
+            new Key<Integer>("android.control.awbMode", int.class);
+
+    /**
+     * <p>
+     * List of areas to use for illuminant
+     * estimation
+     * </p>
+     * <p>
+     * Only used in AUTO mode.
+     * </p><p>
+     * Each area is a rectangle plus weight: xmin, ymin,
+     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * specified coordinates.
+     * </p><p>
+     * The coordinate system is based on the active pixel array,
+     * with (0,0) being the top-left pixel in the active pixel array, and
+     * (android.sensor.info.activeArraySize.width - 1,
+     * android.sensor.info.activeArraySize.height - 1) being the
+     * bottom-right pixel in the active pixel array. The weight
+     * should be nonnegative.
+     * </p><p>
+     * If all regions have 0 weight, then no specific metering area
+     * needs to be used by the HAL. If the metering region is
+     * outside the current android.scaler.cropRegion, the HAL
+     * should ignore the sections outside the region and output the
+     * used sections in the frame metadata
+     * </p>
+     */
+    public static final Key<int[]> CONTROL_AWB_REGIONS =
+            new Key<int[]>("android.control.awbRegions", int[].class);
+
+    /**
+     * <p>
+     * Current state of AWB algorithm
+     * </p>
+     * <p>
+     * Whenever the AWB algorithm state changes, a
+     * MSG_AUTOWHITEBALANCE notification must be send if a
+     * notification callback is registered.
+     * </p>
+     * @see #CONTROL_AWB_STATE_INACTIVE
+     * @see #CONTROL_AWB_STATE_SEARCHING
+     * @see #CONTROL_AWB_STATE_CONVERGED
+     * @see #CONTROL_AWB_STATE_LOCKED
+     */
+    public static final Key<Integer> CONTROL_AWB_STATE =
+            new Key<Integer>("android.control.awbState", int.class);
+
+    /**
+     * <p>
+     * Overall mode of 3A control
+     * routines
+     * </p>
+     * @see #CONTROL_MODE_OFF
+     * @see #CONTROL_MODE_AUTO
+     * @see #CONTROL_MODE_USE_SCENE_MODE
+     */
+    public static final Key<Integer> CONTROL_MODE =
+            new Key<Integer>("android.control.mode", int.class);
+
+    /**
+     * <p>
+     * Operation mode for edge
+     * enhancement
+     * </p>
+     * @see #EDGE_MODE_OFF
+     * @see #EDGE_MODE_FAST
+     * @see #EDGE_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> EDGE_MODE =
+            new Key<Integer>("android.edge.mode", int.class);
+
+    /**
+     * <p>
+     * Select flash operation mode
+     * </p>
+     * @see #FLASH_MODE_OFF
+     * @see #FLASH_MODE_SINGLE
+     * @see #FLASH_MODE_TORCH
+     */
+    public static final Key<Integer> FLASH_MODE =
+            new Key<Integer>("android.flash.mode", int.class);
+
+    /**
+     * <p>
+     * Current state of the flash
+     * unit
+     * </p>
+     * @see #FLASH_STATE_UNAVAILABLE
+     * @see #FLASH_STATE_CHARGING
+     * @see #FLASH_STATE_READY
+     * @see #FLASH_STATE_FIRED
+     */
+    public static final Key<Integer> FLASH_STATE =
+            new Key<Integer>("android.flash.state", int.class);
+
+    /**
+     * <p>
+     * GPS coordinates to include in output JPEG
+     * EXIF
+     * </p>
+     */
+    public static final Key<double[]> JPEG_GPS_COORDINATES =
+            new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
+
+    /**
+     * <p>
+     * 32 characters describing GPS algorithm to
+     * include in EXIF
+     * </p>
+     */
+    public static final Key<String> JPEG_GPS_PROCESSING_METHOD =
+            new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
+
+    /**
+     * <p>
+     * Time GPS fix was made to include in
+     * EXIF
+     * </p>
+     */
+    public static final Key<Long> JPEG_GPS_TIMESTAMP =
+            new Key<Long>("android.jpeg.gpsTimestamp", long.class);
+
+    /**
+     * <p>
+     * Orientation of JPEG image to
+     * write
+     * </p>
+     */
+    public static final Key<Integer> JPEG_ORIENTATION =
+            new Key<Integer>("android.jpeg.orientation", int.class);
+
+    /**
+     * <p>
+     * Compression quality of the final JPEG
+     * 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>
+     */
+    public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
+            new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
+
+    /**
+     * <p>
+     * Resolution of embedded JPEG
+     * thumbnail
+     * </p>
+     */
+    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+
+    /**
+     * <p>
+     * Size of the lens aperture
+     * </p>
+     * <p>
+     * Will not be supported on most devices. Can only
+     * pick from supported list
+     * </p>
+     */
+    public static final Key<Float> LENS_APERTURE =
+            new Key<Float>("android.lens.aperture", float.class);
+
+    /**
+     * <p>
+     * State of lens neutral density
+     * filter(s)
+     * </p>
+     * <p>
+     * Will not be supported on most devices. Can only
+     * pick from supported list
+     * </p>
+     */
+    public static final Key<Float> LENS_FILTER_DENSITY =
+            new Key<Float>("android.lens.filterDensity", float.class);
+
+    /**
+     * <p>
+     * Lens optical zoom setting
+     * </p>
+     * <p>
+     * Will not be supported on most devices.
+     * </p>
+     */
+    public static final Key<Float> LENS_FOCAL_LENGTH =
+            new Key<Float>("android.lens.focalLength", float.class);
+
+    /**
+     * <p>
+     * Distance to plane of sharpest focus,
+     * 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 =
+            new Key<Float>("android.lens.focusDistance", float.class);
+
+    /**
+     * <p>
+     * The range of scene distances that are in
+     * sharp focus (depth of field)
+     * </p>
+     * <p>
+     * If variable focus not supported, can still report
+     * fixed depth of field range
+     * </p>
+     */
+    public static final Key<float[]> LENS_FOCUS_RANGE =
+            new Key<float[]>("android.lens.focusRange", float[].class);
+
+    /**
+     * <p>
+     * Whether optical image stabilization is
+     * enabled.
+     * </p>
+     * <p>
+     * Will not be supported on most devices.
+     * </p>
+     * @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
+     * @see #LENS_OPTICAL_STABILIZATION_MODE_ON
+     */
+    public static final Key<Integer> LENS_OPTICAL_STABILIZATION_MODE =
+            new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
+
+    /**
+     * <p>
+     * Current lens status
+     * </p>
+     * @see #LENS_STATE_STATIONARY
+     * @see #LENS_STATE_MOVING
+     */
+    public static final Key<Integer> LENS_STATE =
+            new Key<Integer>("android.lens.state", int.class);
+
+    /**
+     * <p>
+     * Mode of operation for the noise reduction
+     * algorithm
+     * </p>
+     * @see #NOISE_REDUCTION_MODE_OFF
+     * @see #NOISE_REDUCTION_MODE_FAST
+     * @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> NOISE_REDUCTION_MODE =
+            new Key<Integer>("android.noiseReduction.mode", int.class);
+
+    /**
+     * <p>
+     * A frame counter set by the framework. This value monotonically
+     * increases with every new result (that is, each new result has a unique
+     * frameCount value).
+     * </p>
+     * <p>
+     * Reset on release()
+     * </p>
+     */
+    public static final Key<Integer> REQUEST_FRAME_COUNT =
+            new Key<Integer>("android.request.frameCount", int.class);
+
+    /**
+     * <p>
+     * An application-specified ID for the current
+     * request. Must be maintained unchanged in output
+     * frame
+     * </p>
+     *
+     * @hide
+     */
+    public static final Key<Integer> REQUEST_ID =
+            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>
+     * Any additional per-stream cropping must 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
+     * (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
+     * 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 /
+     * android.scaler.maxDigitalZoom ) and floor(
+     * activeArraySize.height / android.scaler.maxDigitalZoom),
+     * respectively.
+     * </p>
+     */
+    public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
+            new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
+
+    /**
+     * <p>
+     * Duration each pixel is exposed to
+     * light.
+     * </p><p>
+     * If the sensor can't expose this exact duration, it should shorten the
+     * duration exposed to the nearest possible value (rather than expose longer).
+     * </p>
+     * <p>
+     * 1/10000 - 30 sec range. No bulb mode
+     * </p>
+     */
+    public static final Key<Long> SENSOR_EXPOSURE_TIME =
+            new Key<Long>("android.sensor.exposureTime", long.class);
+
+    /**
+     * <p>
+     * Duration from start of frame exposure to
+     * start of next frame exposure
+     * </p>
+     * <p>
+     * Exposure time has priority, so duration is set to
+     * max(duration, exposure time + overhead)
+     * </p>
+     */
+    public static final Key<Long> SENSOR_FRAME_DURATION =
+            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>
+     */
+    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>
+     */
+    public static final Key<Long> SENSOR_TIMESTAMP =
+            new Key<Long>("android.sensor.timestamp", long.class);
+
+    /**
+     * <p>
+     * The temperature of the sensor, sampled at the time
+     * exposure began for this frame.
+     * </p><p>
+     * The thermal diode being queried should be inside the sensor PCB, or
+     * somewhere close to it.
+     * </p>
+     */
+    public static final Key<Float> SENSOR_TEMPERATURE =
+            new Key<Float>("android.sensor.temperature", float.class);
+
+    /**
+     * <p>
+     * State of 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
+     * android.statistics.info.availableFaceDetectModes.
+     * </p>
+     * @see #STATISTICS_FACE_DETECT_MODE_OFF
+     * @see #STATISTICS_FACE_DETECT_MODE_SIMPLE
+     * @see #STATISTICS_FACE_DETECT_MODE_FULL
+     */
+    public static final Key<Integer> STATISTICS_FACE_DETECT_MODE =
+            new Key<Integer>("android.statistics.faceDetectMode", int.class);
+
+    /**
+     * <p>
+     * List of unique IDs for detected
+     * faces
+     * </p>
+     * <p>
+     * Only available if faceDetectMode == FULL
+     * </p>
+     */
+    public static final Key<int[]> STATISTICS_FACE_IDS =
+            new Key<int[]>("android.statistics.faceIds", int[].class);
+
+    /**
+     * <p>
+     * List of landmarks for detected
+     * faces
+     * </p>
+     * <p>
+     * Only available if faceDetectMode == FULL
+     * </p>
+     */
+    public static final Key<int[]> STATISTICS_FACE_LANDMARKS =
+            new Key<int[]>("android.statistics.faceLandmarks", int[].class);
+
+    /**
+     * <p>
+     * List of the bounding rectangles for detected
+     * faces
+     * </p>
+     * <p>
+     * Only available if faceDetectMode != OFF
+     * </p>
+     */
+    public static final Key<android.graphics.Rect[]> STATISTICS_FACE_RECTANGLES =
+            new Key<android.graphics.Rect[]>("android.statistics.faceRectangles", android.graphics.Rect[].class);
+
+    /**
+     * <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>
+     */
+    public static final Key<byte[]> STATISTICS_FACE_SCORES =
+            new Key<byte[]>("android.statistics.faceScores", byte[].class);
+
+    /**
+     * <p>
+     * A low-resolution map of lens shading, per
+     * color channel
+     * </p>
+     * <p>
+     * Assume bilinear interpolation of map. The least
+     * shaded section of the image should have a gain factor
+     * of 1; all other sections should have gains above 1.
+     * the map should be on the order of 30-40 rows, and
+     * must be smaller than 64x64.
+     * </p><p>
+     * When android.colorCorrection.mode = TRANSFORM_MATRIX, the map
+     * must take into account the colorCorrection settings.
+     * </p>
+     */
+    public static final Key<float[]> STATISTICS_LENS_SHADING_MAP =
+            new Key<float[]>("android.statistics.lensShadingMap", float[].class);
+
+    /**
+     * <p>
+     * The best-fit color channel gains calculated
+     * by the HAL's statistics units for the current output frame
+     * </p>
+     * <p>
+     * This may be different than the gains used for this frame,
+     * since statistics processing on data from a new frame
+     * typically completes after the transform has already been
+     * applied to that frame.
+     * </p><p>
+     * The 4 channel gains are defined in Bayer domain,
+     * see android.colorCorrection.gains for details.
+     * </p><p>
+     * This value should always be calculated by the AWB block,
+     * regardless of the android.control.* current values.
+     * </p>
+     */
+    public static final Key<float[]> STATISTICS_PREDICTED_COLOR_GAINS =
+            new Key<float[]>("android.statistics.predictedColorGains", float[].class);
+
+    /**
+     * <p>
+     * The best-fit color transform matrix estimate
+     * calculated by the HAL's statistics units for the current
+     * output frame
+     * </p>
+     * <p>
+     * The HAL must provide the estimate from its
+     * statistics unit on the white balance transforms to use
+     * for the next frame. These are the values the HAL believes
+     * are the best fit for the current output frame. This may
+     * be different than the transform used for this frame, since
+     * statistics processing on data from a new frame typically
+     * completes after the transform has already been applied to
+     * 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,
+     * regardless of the android.control.* current values.
+     * </p>
+     */
+    public static final Key<Rational[]> STATISTICS_PREDICTED_COLOR_TRANSFORM =
+            new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class);
+
+    /**
+     * <p>
+     * The HAL estimated scene illumination lighting
+     * frequency
+     * </p>
+     * <p>
+     * Report NONE if there doesn't appear to be flickering
+     * illumination
+     * </p>
+     * @see #STATISTICS_SCENE_FLICKER_NONE
+     * @see #STATISTICS_SCENE_FLICKER_50HZ
+     * @see #STATISTICS_SCENE_FLICKER_60HZ
+     */
+    public static final Key<Integer> STATISTICS_SCENE_FLICKER =
+            new Key<Integer>("android.statistics.sceneFlicker", int.class);
+
+    /**
+     * <p>
+     * Table mapping blue input values to output
+     * values
+     * </p>
+     * <p>
+     * Tonemapping / contrast / gamma curve for the blue
+     * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
+     * </p><p>
+     * See android.tonemap.curveRed for more details.
+     * </p>
+     */
+    public static final Key<float[]> TONEMAP_CURVE_BLUE =
+            new Key<float[]>("android.tonemap.curveBlue", float[].class);
+
+    /**
+     * <p>
+     * Table mapping green input values to output
+     * values
+     * </p>
+     * <p>
+     * Tonemapping / contrast / gamma curve for the green
+     * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
+     * </p><p>
+     * See android.tonemap.curveRed for more details.
+     * </p>
+     */
+    public static final Key<float[]> TONEMAP_CURVE_GREEN =
+            new Key<float[]>("android.tonemap.curveGreen", float[].class);
+
+    /**
+     * <p>
+     * Table mapping red input values to output
+     * values
+     * </p>
+     * <p>
+     * Tonemapping / contrast / gamma curve for the red
+     * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
+     * </p><p>
+     * Since the input and output ranges may vary depending on
+     * the camera pipeline, the input and output pixel values
+     * are represented by normalized floating-point values
+     * between 0 and 1, with 0 == black and 1 == white.
+     * </p><p>
+     * The curve should be linearly interpolated between the
+     * defined points. The points will be listed in increasing
+     * order of P_IN. For example, if the array is: [0.0, 0.0,
+     * 0.3, 0.5, 1.0, 1.0], then the input->output mapping
+     * for a few sample points would be: 0 -> 0, 0.15 ->
+     * 0.25, 0.3 -> 0.5, 0.5 -> 0.64
+     * </p>
+     */
+    public static final Key<float[]> TONEMAP_CURVE_RED =
+            new Key<float[]>("android.tonemap.curveRed", float[].class);
+
+    /**
+     * @see #TONEMAP_MODE_CONTRAST_CURVE
+     * @see #TONEMAP_MODE_FAST
+     * @see #TONEMAP_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> TONEMAP_MODE =
+            new Key<Integer>("android.tonemap.mode", int.class);
+
+    /**
+     * <p>
+     * This LED is nominally used to indicate to the user
+     * that the camera is powered on and may be streaming images back to the
+     * Application Processor. In certain rare circumstances, the OS may
+     * disable this when video is processed locally and not transmitted to
+     * any untrusted applications.
+     * </p><p>
+     * In particular, the LED *must* always be on when the data could be
+     * transmitted off the device. The LED *should* always be on whenever
+     * data is stored locally on the device.
+     * </p><p>
+     * The LED *may* be off if a trusted application is using the data that
+     * doesn't violate the above rules.
+     * </p>
+     *
+     * @hide
+     */
+    public static final Key<Boolean> LED_TRANSMIT =
+            new Key<Boolean>("android.led.transmit", boolean.class);
+
+    /**
+     * <p>
+     * Whether black-level compensation is locked
+     * to its current values, or is free to vary
+     * </p>
+     * <p>
+     * When set to ON, the values used for black-level
+     * compensation must not change until the lock is set to
+     * OFF
+     * </p><p>
+     * Since changes to certain capture parameters (such as
+     * exposure time) may require resetting of black level
+     * compensation, the HAL must report whether setting the
+     * black level lock was successful in the output result
+     * metadata.
+     * </p><p>
+     * The black level locking must happen at the sensor, and not at the ISP.
+     * If for some reason black level locking is no longer legal (for example,
+     * the analog gain has changed, which forces black levels to be
+     * recalculated), then the HAL is free to override this request (and it
+     * must report 'OFF' when this does happen) until the next time locking
+     * is legal again.
+     * </p>
+     */
+    public static final Key<Boolean> BLACK_LEVEL_LOCK =
+            new Key<Boolean>("android.blackLevel.lock", boolean.class);
+
+    /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+     * End generated code
+     *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+    /**
+     * <p>
+     * List of the {@link Face Faces} detected through camera face detection
+     * in this result.
+     * </p>
+     * <p>
+     * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
+     * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
+     * </p>
+     *
+     * @see Face
+     */
+    public static final Key<Face[]> STATISTICS_FACES =
+            new Key<Face[]>("android.statistics.faces", Face[].class);
+}
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/Face.java
new file mode 100644
index 0000000..ef068ca
--- /dev/null
+++ b/core/java/android/hardware/camera2/Face.java
@@ -0,0 +1,252 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Describes a face detected in an image.
+ */
+public final class Face {
+
+    /**
+     * The ID is {@code -1} when the optional set of fields is unsupported.
+     *
+     * @see Face#Face(Rect, int)
+     * @see #getId()
+     */
+    public static final int ID_UNSUPPORTED = -1;
+
+    /**
+     * The minimum possible value for the confidence level.
+     *
+     * @see #getScore()
+     */
+    public static final int SCORE_MIN = 1;
+
+    /**
+     * The maximum possible value for the confidence level.
+     *
+     * @see #getScore()
+     */
+    public static final int SCORE_MAX = 100;
+
+    private final Rect mBounds;
+    private final int mScore;
+    private final int mId;
+    private final Point mLeftEye;
+    private final Point mRightEye;
+    private final Point mMouth;
+
+    /**
+     * Create a new face with all fields set.
+     *
+     * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+     * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+     * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+     * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+     *
+     * @param bounds Bounds of the face.
+     * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+     * @param id A unique ID per face visible to the tracker.
+     * @param leftEyePosition The position of the left eye.
+     * @param rightEyePosition The position of the right eye.
+     * @param mouthPosition The position of the mouth.
+     *
+     * @throws IllegalArgumentException
+     *             if bounds is {@code null},
+     *             or if the confidence is not in the range of
+     *             {@value #SCORE_MIN}-{@value #SCORE_MAX},
+     *             or if id is {@value #ID_UNSUPPORTED} and
+     *               leftEyePosition/rightEyePosition/mouthPosition aren't all null,
+     *             or else if id is negative.
+     *
+     * @hide
+     */
+    public Face(Rect bounds, int score, int id,
+            Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
+        checkNotNull("bounds", bounds);
+        if (score < SCORE_MIN || score > SCORE_MAX) {
+            throw new IllegalArgumentException("Confidence out of range");
+        } else if (id < 0 && id != ID_UNSUPPORTED) {
+            throw new IllegalArgumentException("Id out of range");
+        }
+        if (id == ID_UNSUPPORTED) {
+            checkNull("leftEyePosition", leftEyePosition);
+            checkNull("rightEyePosition", rightEyePosition);
+            checkNull("mouthPosition", mouthPosition);
+        }
+
+        mBounds = bounds;
+        mScore = score;
+        mId = id;
+        mLeftEye = leftEyePosition;
+        mRightEye = rightEyePosition;
+        mMouth = mouthPosition;
+    }
+
+    /**
+     * Create a new face without the optional fields.
+     *
+     * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+     * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+     * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+     * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+     *
+     * @param bounds Bounds of the face.
+     * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+     *
+     * @throws IllegalArgumentException
+     *             if bounds is {@code null},
+     *             or if the confidence is not in the range of
+     *             {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+     *
+     * @hide
+     */
+    public Face(Rect bounds, int score) {
+        this(bounds, score, ID_UNSUPPORTED,
+                /*leftEyePosition*/null, /*rightEyePosition*/null, /*mouthPosition*/null);
+    }
+
+    /**
+     * Bounds of the face.
+     *
+     * <p>A rectangle relative to the sensor's
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
+     * representing the top-left corner of the active array rectangle.</p>
+     *
+     * <p>There is no constraints on the the Rectangle value other than it
+     * is not-{@code null}.</p>
+     */
+    public Rect getBounds() {
+        return mBounds;
+    }
+
+    /**
+     * The confidence level for the detection of the face.
+     *
+     * <p>The range is {@value #SCORE_MIN} to {@value #SCORE_MAX}.
+     * {@value #SCORE_MAX} is the highest confidence.</p>
+     *
+     * <p>Depending on the device, even very low-confidence faces may be
+     * listed, so applications should filter out faces with low confidence,
+     * depending on the use case. For a typical point-and-shoot camera
+     * application that wishes to display rectangles around detected faces,
+     * filtering out faces with confidence less than half of {@value #SCORE_MAX}
+     * is recommended.</p>
+     *
+     * @see #SCORE_MAX
+     * @see #SCORE_MIN
+     */
+    public int getScore() {
+        return mScore;
+    }
+
+    /**
+     * An unique id per face while the face is visible to the tracker.
+     *
+     * <p>
+     * If the face leaves the field-of-view and comes back, it will get a new
+     * id.</p>
+     *
+     * <p>This is an optional field, may not be supported on all devices.
+     * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+     * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+     * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+     *
+     * <p>This value will either be {@value #ID_UNSUPPORTED} or
+     * otherwise greater than {@code 0}.</p>
+     *
+     * @see #ID_UNSUPPORTED
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * The coordinates of the center of the left eye.
+     *
+     * <p>The coordinates are in
+     * the same space as the ones for {@link #getBounds}. This is an
+     * optional field, may not be supported on all devices. If not
+     * supported, the value will always be set to null.
+     * This value will  always be null only if {@link #getId()} returns
+     * {@value #ID_UNSUPPORTED}.</p>
+     *
+     * @return The left eye position, or {@code null} if unknown.
+     */
+    public Point getLeftEyePosition() {
+        return mLeftEye;
+    }
+
+    /**
+     * The coordinates of the center of the right eye.
+     *
+     * <p>The coordinates are
+     * in the same space as the ones for {@link #getBounds}.This is an
+     * optional field, may not be supported on all devices. If not
+     * supported, the value will always be set to null.
+     * This value will  always be null only if {@link #getId()} returns
+     * {@value #ID_UNSUPPORTED}.</p>
+     *
+     * @return The right eye position, or {@code null} if unknown.
+     */
+    public Point getRightEyePosition() {
+        return mRightEye;
+    }
+
+    /**
+     * The coordinates of the center of the mouth.
+     *
+     * <p>The coordinates are in
+     * the same space as the ones for {@link #getBounds}. This is an optional
+     * field, may not be supported on all devices. If not
+     * supported, the value will always be set to null.
+     * This value will  always be null only if {@link #getId()} returns
+     * {@value #ID_UNSUPPORTED}.</p> them are.
+     * </p>
+     *
+     * @return The mouth position, or {@code null} if unknown.
+     */
+    public Point getMouthPosition() {
+        return mMouth;
+    }
+
+    /**
+     * Represent the Face as a string for debugging purposes.
+     */
+    @Override
+    public String toString() {
+        return String.format("{ bounds: %s, score: %s, id: %d, " +
+                "leftEyePosition: %s, rightEyePosition: %s, mouthPosition: %s }",
+                mBounds, mScore, mId, mLeftEye, mRightEye, mMouth);
+    }
+
+    private static void checkNotNull(String name, Object obj) {
+        if (obj == null) {
+            throw new IllegalArgumentException(name + " was required, but it was null");
+        }
+    }
+
+    private static void checkNull(String name, Object obj) {
+        if (obj != null) {
+            throw new IllegalArgumentException(name + " was required to be null, but it wasn't");
+        }
+    }
+}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
new file mode 100644
index 0000000..4054a92
--- /dev/null
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+interface ICameraDeviceCallbacks
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
+     */
+
+    oneway void notifyCallback(int msgType, int ext1, int ext2);
+    oneway void onResultReceived(int frameId, in CameraMetadataNative result);
+}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
new file mode 100644
index 0000000..1936963
--- /dev/null
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.view.Surface;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.CaptureRequest;
+
+/** @hide */
+interface ICameraDeviceUser
+{
+    /**
+     * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceUser.h
+     */
+    void disconnect();
+
+    // ints here are status_t
+
+    // non-negative value is the requestId. negative value is status_t
+    int submitRequest(in CaptureRequest request, boolean streaming);
+
+    int cancelRequest(int requestId);
+
+    int deleteStream(int streamId);
+
+    // non-negative value is the stream ID. negative value is status_t
+    int createStream(int width, int height, int format, in Surface surface);
+
+    int createDefaultRequest(int templateId, out CameraMetadataNative request);
+
+    int getCameraInfo(out CameraMetadataNative info);
+
+    int waitUntilIdle();
+
+    int flush();
+}
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/hardware/camera2/Rational.java
new file mode 100644
index 0000000..77b8c26
--- /dev/null
+++ b/core/java/android/hardware/camera2/Rational.java
@@ -0,0 +1,201 @@
+/*
+ * 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 android.hardware.camera2;
+
+/**
+ * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the
+ * numerator and denominator of a Rational number. This type is immutable.
+ */
+public final class Rational {
+    private final int mNumerator;
+    private final int mDenominator;
+
+    /**
+     * <p>Create a 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>
+     *
+     * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
+     * as float NaN and INF values. The int getter functions return 0 in this case.</p>
+     *
+     * @param numerator the numerator of the rational
+     * @param denominator the denominator of the rational
+     */
+    public Rational(int numerator, int denominator) {
+
+        if (denominator < 0) {
+            numerator = -numerator;
+            denominator = -denominator;
+        }
+
+        mNumerator = numerator;
+        mDenominator = denominator;
+    }
+
+    /**
+     * Gets the numerator of the rational.
+     */
+    public int getNumerator() {
+        if (mDenominator == 0) {
+            return 0;
+        }
+        return mNumerator;
+    }
+
+    /**
+     * Gets the denominator of the rational
+     */
+    public int getDenominator() {
+        return mDenominator;
+    }
+
+    private boolean isNaN() {
+        return mDenominator == 0 && mNumerator == 0;
+    }
+
+    private boolean isInf() {
+        return mDenominator == 0 && mNumerator > 0;
+    }
+
+    private boolean isNegInf() {
+        return mDenominator == 0 && mNumerator < 0;
+    }
+
+    /**
+     * <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 is considered equal to another Rational object if and only if one of
+     * the following holds</p>:
+     * <ul><li>Both are 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>
+     *
+     * <p>A reduced form of a Rational is calculated by dividing both the numerator and the
+     * denominator by their greatest common divisor.</p>
+     *
+     * <pre>
+     *      (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
+     *
+     * @return A boolean that determines whether or not the two Rational objects are equal.
+     */
+    @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;
+    }
+
+    @Override
+    public String toString() {
+        if (isNaN()) {
+            return "NaN";
+        } else if (isInf()) {
+            return "Infinity";
+        } else if (isNegInf()) {
+            return "-Infinity";
+        } else {
+            return mNumerator + "/" + mDenominator;
+        }
+    }
+
+    /**
+     * <p>Convert to a floating point representation.</p>
+     *
+     * @return The floating point representation of this rational number.
+     * @hide
+     */
+    public float toFloat() {
+        return (float) mNumerator / (float) mDenominator;
+    }
+
+    @Override
+    public int hashCode() {
+        final long INT_MASK = 0xffffffffL;
+
+        long asLong = INT_MASK & mNumerator;
+        asLong <<= 32;
+
+        asLong |= (INT_MASK & mDenominator);
+
+        return ((Long)asLong).hashCode();
+    }
+
+    /**
+     * Calculates the greatest common divisor using Euclid's algorithm.
+     *
+     * @return An int value representing the gcd. Always positive.
+     * @hide
+     */
+    public int gcd() {
+        /**
+         * 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;
+
+        while (b != 0) {
+            int oldB = b;
+
+            b = a % b;
+            a = oldB;
+        }
+
+        return Math.abs(a);
+    }
+}
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
new file mode 100644
index 0000000..45aaeae
--- /dev/null
+++ b/core/java/android/hardware/camera2/Size.java
@@ -0,0 +1,77 @@
+/*
+ * 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 android.hardware.camera2;
+
+/**
+ * A simple immutable class for describing the dimensions of camera image
+ * buffers.
+ */
+public final class Size {
+    /**
+     * Create a new immutable Size instance
+     *
+     * @param width The width to store in the Size instance
+     * @param height The height to store in the Size instance
+     */
+    public Size(int width, int height) {
+        mWidth = width;
+        mHeight = height;
+    }
+
+    public final int getWidth() {
+        return mWidth;
+    }
+
+    public final int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Size) {
+            Size other = (Size) obj;
+            return mWidth == other.mWidth && mHeight == other.mHeight;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return mWidth + "x" + mHeight;
+    }
+
+    @Override
+    public int hashCode() {
+        final long INT_MASK = 0xffffffffL;
+
+        long asLong = INT_MASK & mWidth;
+        asLong <<= 32;
+
+        asLong |= (INT_MASK & mHeight);
+
+        return ((Long)asLong).hashCode();
+    }
+
+    private final int mWidth;
+    private final int mHeight;
+};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
new file mode 100644
index 0000000..70a6f44
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -0,0 +1,437 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.camera2.utils.CameraRuntimeException;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
+ */
+public class CameraDevice implements android.hardware.camera2.CameraDevice {
+
+    private final String TAG;
+    private final boolean DEBUG;
+
+    // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
+    private ICameraDeviceUser mRemoteDevice;
+
+    private final Object mLock = new Object();
+    private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
+
+    private StateListener mDeviceListener;
+    private Handler mDeviceHandler;
+
+    private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
+            new SparseArray<CaptureListenerHolder>();
+
+    private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
+    // Map stream IDs to Surfaces
+    private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
+
+    private final String mCameraId;
+
+    public CameraDevice(String cameraId) {
+        mCameraId = cameraId;
+        TAG = String.format("CameraDevice-%s-JV", mCameraId);
+        DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    }
+
+    public CameraDeviceCallbacks getCallbacks() {
+        return mCallbacks;
+    }
+
+    public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
+        // TODO: Move from decorator to direct binder-mediated exceptions
+        mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
+    }
+
+    @Override
+    public String getId() {
+        return mCameraId;
+    }
+
+    @Override
+    public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
+        synchronized (mLock) {
+            HashSet<Surface> addSet = new HashSet<Surface>(outputs);    // Streams to create
+            List<Integer> deleteList = new ArrayList<Integer>();        // Streams to delete
+
+            // Determine which streams need to be created, which to be deleted
+            for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
+                int streamId = mConfiguredOutputs.keyAt(i);
+                Surface s = mConfiguredOutputs.valueAt(i);
+
+                if (!outputs.contains(s)) {
+                    deleteList.add(streamId);
+                } else {
+                    addSet.remove(s);  // Don't create a stream previously created
+                }
+            }
+
+            try {
+                // TODO: mRemoteDevice.beginConfigure
+
+                // Delete all streams first (to free up HW resources)
+                for (Integer streamId : deleteList) {
+                    mRemoteDevice.deleteStream(streamId);
+                    mConfiguredOutputs.delete(streamId);
+                }
+
+                // Add all new streams
+                for (Surface s : addSet) {
+                    // TODO: remove width,height,format since we are ignoring
+                    // it.
+                    int streamId = mRemoteDevice.createStream(0, 0, 0, s);
+                    mConfiguredOutputs.put(streamId, s);
+                }
+
+                // TODO: mRemoteDevice.endConfigure
+            } catch (CameraRuntimeException e) {
+                if (e.getReason() == CAMERA_IN_USE) {
+                    throw new IllegalStateException("The camera is currently busy." +
+                            " You must call waitUntilIdle before trying to reconfigure.");
+                }
+
+                throw e.asChecked();
+            } catch (RemoteException e) {
+                // impossible
+                return;
+            }
+        }
+    }
+
+    @Override
+    public CaptureRequest.Builder createCaptureRequest(int templateType)
+            throws CameraAccessException {
+        synchronized (mLock) {
+
+            CameraMetadataNative templatedRequest = new CameraMetadataNative();
+
+            try {
+                mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
+            } catch (CameraRuntimeException e) {
+                throw e.asChecked();
+            } catch (RemoteException e) {
+                // impossible
+                return null;
+            }
+
+            CaptureRequest.Builder builder =
+                    new CaptureRequest.Builder(templatedRequest);
+
+            return builder;
+        }
+    }
+
+    @Override
+    public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
+            throws CameraAccessException {
+        return submitCaptureRequest(request, listener, handler, /*streaming*/false);
+    }
+
+    @Override
+    public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
+            Handler handler) throws CameraAccessException {
+        if (requests.isEmpty()) {
+            Log.w(TAG, "Capture burst request list is empty, do nothing!");
+            return -1;
+        }
+        // TODO
+        throw new UnsupportedOperationException("Burst capture implemented yet");
+
+    }
+
+    private int submitCaptureRequest(CaptureRequest request, CaptureListener listener,
+            Handler handler, boolean repeating) throws CameraAccessException {
+
+        // Need a valid handler, or current thread needs to have a looper, if
+        // listener is valid
+        if (handler == null && listener != null) {
+            Looper looper = Looper.myLooper();
+            if (looper == null) {
+                throw new IllegalArgumentException(
+                        "No handler given, and current thread has no looper!");
+            }
+            handler = new Handler(looper);
+        }
+
+        synchronized (mLock) {
+
+            int requestId;
+
+            try {
+                requestId = mRemoteDevice.submitRequest(request, repeating);
+            } catch (CameraRuntimeException e) {
+                throw e.asChecked();
+            } catch (RemoteException e) {
+                // impossible
+                return -1;
+            }
+            if (listener != null) {
+                mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
+                        handler, repeating));
+            }
+
+            if (repeating) {
+                mRepeatingRequestIdStack.add(requestId);
+            }
+
+            return requestId;
+        }
+    }
+
+    @Override
+    public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
+            Handler handler) throws CameraAccessException {
+        return submitCaptureRequest(request, listener, handler, /*streaming*/true);
+    }
+
+    @Override
+    public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
+            Handler handler) throws CameraAccessException {
+        if (requests.isEmpty()) {
+            Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
+            return -1;
+        }
+        // TODO
+        throw new UnsupportedOperationException("Burst capture implemented yet");
+    }
+
+    @Override
+    public void stopRepeating() throws CameraAccessException {
+
+        synchronized (mLock) {
+
+            while (!mRepeatingRequestIdStack.isEmpty()) {
+                int requestId = mRepeatingRequestIdStack.pop();
+
+                try {
+                    mRemoteDevice.cancelRequest(requestId);
+                } catch (CameraRuntimeException e) {
+                    throw e.asChecked();
+                } catch (RemoteException e) {
+                    // impossible
+                    return;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void waitUntilIdle() throws CameraAccessException {
+
+        synchronized (mLock) {
+            checkIfCameraClosed();
+            if (!mRepeatingRequestIdStack.isEmpty()) {
+                throw new IllegalStateException("Active repeating request ongoing");
+            }
+
+            try {
+                mRemoteDevice.waitUntilIdle();
+            } catch (CameraRuntimeException e) {
+                throw e.asChecked();
+            } catch (RemoteException e) {
+                // impossible
+                return;
+            }
+      }
+    }
+
+    @Override
+    public void setDeviceListener(StateListener listener, Handler handler) {
+        synchronized (mLock) {
+            mDeviceListener = listener;
+            mDeviceHandler = handler;
+        }
+    }
+
+    @Override
+    public void flush() throws CameraAccessException {
+        synchronized (mLock) {
+            try {
+                mRemoteDevice.flush();
+            } catch (CameraRuntimeException e) {
+                throw e.asChecked();
+            } catch (RemoteException e) {
+                // impossible
+                return;
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+
+        // TODO: every method should throw IllegalStateException after close has been called
+
+        synchronized (mLock) {
+
+            try {
+                if (mRemoteDevice != null) {
+                    mRemoteDevice.disconnect();
+                }
+            } catch (CameraRuntimeException e) {
+                Log.e(TAG, "Exception while closing: ", e.asChecked());
+            } catch (RemoteException e) {
+                // impossible
+            }
+
+            mRemoteDevice = null;
+
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        }
+        finally {
+            super.finalize();
+        }
+    }
+
+    static class CaptureListenerHolder {
+
+        private final boolean mRepeating;
+        private final CaptureListener mListener;
+        private final CaptureRequest mRequest;
+        private final Handler mHandler;
+
+        CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
+                boolean repeating) {
+            if (listener == null || handler == null) {
+                throw new UnsupportedOperationException(
+                    "Must have a valid handler and a valid listener");
+            }
+            mRepeating = repeating;
+            mHandler = handler;
+            mRequest = request;
+            mListener = listener;
+        }
+
+        public boolean isRepeating() {
+            return mRepeating;
+        }
+
+        public CaptureListener getListener() {
+            return mListener;
+        }
+
+        public CaptureRequest getRequest() {
+            return mRequest;
+        }
+
+        public Handler getHandler() {
+            return mHandler;
+        }
+
+    }
+
+    // TODO: unit tests
+    public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        // TODO: consider rename to onMessageReceived
+        @Override
+        public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
+            }
+            // TODO implement rest
+        }
+
+        @Override
+        public void onResultReceived(int requestId, CameraMetadataNative result)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "Received result for id " + requestId);
+            }
+            final CaptureListenerHolder holder;
+
+            synchronized (mLock) {
+                // TODO: move this whole map into this class to make it more testable,
+                //        exposing the methods necessary like subscribeToRequest, unsubscribe..
+                // TODO: make class static class
+
+                holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
+
+                // Clean up listener once we no longer expect to see it.
+
+                // TODO: how to handle repeating listeners?
+                // we probably want cancelRequest to return # of times it already enqueued and
+                // keep a counter.
+                if (holder != null && !holder.isRepeating()) {
+                    CameraDevice.this.mCaptureListenerMap.remove(requestId);
+                }
+            }
+
+            // Check if we have a listener for this
+            if (holder == null) {
+                return;
+            }
+
+            final CaptureRequest request = holder.getRequest();
+            final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
+
+            holder.getHandler().post(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        holder.getListener().onCaptureCompleted(
+                            CameraDevice.this,
+                            request,
+                            resultAsCapture);
+                    }
+                });
+        }
+
+    }
+
+    private void checkIfCameraClosed() {
+        if (mRemoteDevice == null) {
+            throw new IllegalStateException("CameraDevice was already closed");
+        }
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
new file mode 100644
index 0000000..4a89129
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+/** @hide */
+parcelable CameraMetadataNative;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
new file mode 100644
index 0000000..6d7b03e
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -0,0 +1,668 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.Rational;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Implementation of camera metadata marshal/unmarshal across Binder to
+ * the camera service
+ */
+public class CameraMetadataNative extends CameraMetadata implements Parcelable {
+
+    private static final String TAG = "CameraMetadataJV";
+
+    public CameraMetadataNative() {
+        super();
+        mMetadataPtr = nativeAllocate();
+        if (mMetadataPtr == 0) {
+            throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+        }
+    }
+
+    /**
+     * Copy constructor - clone metadata
+     */
+    public CameraMetadataNative(CameraMetadataNative other) {
+        super();
+        mMetadataPtr = nativeAllocateCopy(other);
+        if (mMetadataPtr == 0) {
+            throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+        }
+    }
+
+    public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
+            new Parcelable.Creator<CameraMetadataNative>() {
+        @Override
+        public CameraMetadataNative createFromParcel(Parcel in) {
+            CameraMetadataNative metadata = new CameraMetadataNative();
+            metadata.readFromParcel(in);
+            return metadata;
+        }
+
+        @Override
+        public CameraMetadataNative[] newArray(int size) {
+            return new CameraMetadataNative[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        nativeWriteToParcel(dest);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T get(Key<T> key) {
+        int tag = key.getTag();
+        byte[] values = readValues(tag);
+        if (values == null) {
+            return null;
+        }
+
+        int nativeType = getNativeType(tag);
+
+        ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
+        return unpackSingle(buffer, key.getType(), nativeType);
+    }
+
+    public void readFromParcel(Parcel in) {
+        nativeReadFromParcel(in);
+    }
+
+    /**
+     * Set a camera metadata field to a value. The field definitions can be
+     * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
+     * {@link CaptureRequest}.
+     *
+     * @param key The metadata field to write.
+     * @param value The value to set the field to, which must be of a matching
+     * type to the key.
+     */
+    public <T> void set(Key<T> key, T value) {
+        int tag = key.getTag();
+
+        if (value == null) {
+            writeValues(tag, null);
+            return;
+        }
+
+        int nativeType = getNativeType(tag);
+
+        int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true);
+
+        // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
+        byte[] values = new byte[size];
+
+        ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
+        packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false);
+
+        writeValues(tag, values);
+    }
+
+    // Keep up-to-date with camera_metadata.h
+    /**
+     * @hide
+     */
+    public static final int TYPE_BYTE = 0;
+    /**
+     * @hide
+     */
+    public static final int TYPE_INT32 = 1;
+    /**
+     * @hide
+     */
+    public static final int TYPE_FLOAT = 2;
+    /**
+     * @hide
+     */
+    public static final int TYPE_INT64 = 3;
+    /**
+     * @hide
+     */
+    public static final int TYPE_DOUBLE = 4;
+    /**
+     * @hide
+     */
+    public static final int TYPE_RATIONAL = 5;
+    /**
+     * @hide
+     */
+    public static final int NUM_TYPES = 6;
+
+    private void close() {
+        // this sets mMetadataPtr to 0
+        nativeClose();
+        mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
+    }
+
+    private static int getTypeSize(int nativeType) {
+        switch(nativeType) {
+            case TYPE_BYTE:
+                return 1;
+            case TYPE_INT32:
+            case TYPE_FLOAT:
+                return 4;
+            case TYPE_INT64:
+            case TYPE_DOUBLE:
+            case TYPE_RATIONAL:
+                return 8;
+        }
+
+        throw new UnsupportedOperationException("Unknown type, can't get size "
+                + nativeType);
+    }
+
+    private static Class<?> getExpectedType(int nativeType) {
+        switch(nativeType) {
+            case TYPE_BYTE:
+                return Byte.TYPE;
+            case TYPE_INT32:
+                return Integer.TYPE;
+            case TYPE_FLOAT:
+                return Float.TYPE;
+            case TYPE_INT64:
+                return Long.TYPE;
+            case TYPE_DOUBLE:
+                return Double.TYPE;
+            case TYPE_RATIONAL:
+                return Rational.class;
+        }
+
+        throw new UnsupportedOperationException("Unknown type, can't map to Java type "
+                + nativeType);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
+            int nativeType, boolean sizeOnly) {
+
+        if (!sizeOnly) {
+            /**
+             * Rewrite types when the native type doesn't match the managed type
+             *  - Boolean -> Byte
+             *  - Integer -> Byte
+             */
+
+            if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
+                // Since a boolean can't be cast to byte, and we don't want to use putBoolean
+                boolean asBool = (Boolean) value;
+                byte asByte = (byte) (asBool ? 1 : 0);
+                value = (T) (Byte) asByte;
+            } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
+                int asInt = (Integer) value;
+                byte asByte = (byte) asInt;
+                value = (T) (Byte) asByte;
+            } else if (type != getExpectedType(nativeType)) {
+                throw new UnsupportedOperationException("Tried to pack a type of " + type +
+                        " but we expected the type to be " + getExpectedType(nativeType));
+            }
+
+            if (nativeType == TYPE_BYTE) {
+                buffer.put((Byte) value);
+            } else if (nativeType == TYPE_INT32) {
+                buffer.putInt((Integer) value);
+            } else if (nativeType == TYPE_FLOAT) {
+                buffer.putFloat((Float) value);
+            } else if (nativeType == TYPE_INT64) {
+                buffer.putLong((Long) value);
+            } else if (nativeType == TYPE_DOUBLE) {
+                buffer.putDouble((Double) value);
+            } else if (nativeType == TYPE_RATIONAL) {
+                Rational r = (Rational) value;
+                buffer.putInt(r.getNumerator());
+                buffer.putInt(r.getDenominator());
+            }
+
+        }
+
+        return getTypeSize(nativeType);
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+            boolean sizeOnly) {
+
+        int size = 0;
+
+        if (type.isPrimitive() || type == Rational.class) {
+            size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
+        } else if (type.isEnum()) {
+            size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
+        } else if (type.isArray()) {
+            size = packArray(value, buffer, type, nativeType, sizeOnly);
+        } else {
+            size = packClass(value, buffer, type, nativeType, sizeOnly);
+        }
+
+        return size;
+    }
+
+    private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
+            int nativeType, boolean sizeOnly) {
+
+        // TODO: add support for enums with their own values.
+        return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+            boolean sizeOnly) {
+
+        MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+        if (marshaler == null) {
+            throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
+        }
+
+        return marshaler.marshal(value, buffer, nativeType, sizeOnly);
+    }
+
+    private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+            boolean sizeOnly) {
+
+        int size = 0;
+        int arrayLength = Array.getLength(value);
+
+        @SuppressWarnings("unchecked")
+        Class<Object> componentType = (Class<Object>)type.getComponentType();
+
+        for (int i = 0; i < arrayLength; ++i) {
+            size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
+        }
+
+        return size;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+        T val;
+
+        if (nativeType == TYPE_BYTE) {
+            val = (T) (Byte) buffer.get();
+        } else if (nativeType == TYPE_INT32) {
+            val = (T) (Integer) buffer.getInt();
+        } else if (nativeType == TYPE_FLOAT) {
+            val = (T) (Float) buffer.getFloat();
+        } else if (nativeType == TYPE_INT64) {
+            val = (T) (Long) buffer.getLong();
+        } else if (nativeType == TYPE_DOUBLE) {
+            val = (T) (Double) buffer.getDouble();
+        } else if (nativeType == TYPE_RATIONAL) {
+            val = (T) new Rational(buffer.getInt(), buffer.getInt());
+        } else {
+            throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
+                + nativeType);
+        }
+
+        /**
+         * Rewrite types when the native type doesn't match the managed type
+         *  - Byte -> Boolean
+         *  - Byte -> Integer
+         */
+
+        if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
+            // Since a boolean can't be cast to byte, and we don't want to use getBoolean
+            byte asByte = (Byte) val;
+            boolean asBool = asByte != 0;
+            val = (T) (Boolean) asBool;
+        } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
+            byte asByte = (Byte) val;
+            int asInt = asByte;
+            val = (T) (Integer) asInt;
+        } else if (type != getExpectedType(nativeType)) {
+            throw new UnsupportedOperationException("Tried to unpack a type of " + type +
+                    " but we expected the type to be " + getExpectedType(nativeType));
+        }
+
+        return val;
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+        if (type.isPrimitive() || type == Rational.class) {
+            return unpackSingleNative(buffer, type, nativeType);
+        }
+
+        if (type.isEnum()) {
+            return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
+        }
+
+        if (type.isArray()) {
+            return unpackArray(buffer, type, nativeType);
+        }
+
+        T instance = unpackClass(buffer, type, nativeType);
+
+        return instance;
+    }
+
+    private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
+            int nativeType) {
+        int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
+        return getEnumFromValue(type, ordinal);
+    }
+
+    private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+        MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+        if (marshaler == null) {
+            throw new IllegalArgumentException("Unknown class type: " + type);
+        }
+
+        return marshaler.unmarshal(buffer, nativeType);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+        Class<?> componentType = type.getComponentType();
+        Object array;
+
+        int elementSize = getTypeSize(nativeType);
+
+        MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
+        if (marshaler != null) {
+            elementSize = marshaler.getNativeSize(nativeType);
+        }
+
+        if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
+            int remaining = buffer.remaining();
+            int arraySize = remaining / elementSize;
+
+            Log.v(TAG,
+                    String.format(
+                            "Attempting to unpack array (count = %d, element size = %d, bytes " +
+                                    "remaining = %d) for type %s",
+                            arraySize, elementSize, remaining, type));
+
+            array = Array.newInstance(componentType, arraySize);
+            for (int i = 0; i < arraySize; ++i) {
+               Object elem = unpackSingle(buffer, componentType, nativeType);
+               Array.set(array, i, elem);
+            }
+        } else {
+            // Dynamic size, use an array list.
+            ArrayList<Object> arrayList = new ArrayList<Object>();
+
+            int primitiveSize = getTypeSize(nativeType);
+            while (buffer.remaining() >= primitiveSize) {
+                Object elem = unpackSingle(buffer, componentType, nativeType);
+                arrayList.add(elem);
+            }
+
+            array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
+        }
+
+        if (buffer.remaining() != 0) {
+            Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
+                    + type);
+        }
+
+        return (T) array;
+    }
+
+    private long mMetadataPtr; // native CameraMetadata*
+
+    private native long nativeAllocate();
+    private native long nativeAllocateCopy(CameraMetadataNative other)
+            throws NullPointerException;
+
+    private native synchronized void nativeWriteToParcel(Parcel dest);
+    private native synchronized void nativeReadFromParcel(Parcel source);
+    private native synchronized void nativeSwap(CameraMetadataNative other)
+            throws NullPointerException;
+    private native synchronized void nativeClose();
+    private native synchronized boolean nativeIsEmpty();
+    private native synchronized int nativeGetEntryCount();
+
+    private native synchronized byte[] nativeReadValues(int tag);
+    private native synchronized void nativeWriteValues(int tag, byte[] src);
+
+    private static native int nativeGetTagFromKey(String keyName)
+            throws IllegalArgumentException;
+    private static native int nativeGetTypeFromTag(int tag)
+            throws IllegalArgumentException;
+    private static native void nativeClassInit();
+
+    /**
+     * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
+     *
+     * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
+     *
+     * @param other Metadata to swap with
+     * @throws NullPointerException if other was null
+     * @hide
+     */
+    public void swap(CameraMetadataNative other) {
+        nativeSwap(other);
+    }
+
+    /**
+     * @hide
+     */
+    public int getEntryCount() {
+        return nativeGetEntryCount();
+    }
+
+    /**
+     * Does this metadata contain at least 1 entry?
+     *
+     * @hide
+     */
+    public boolean isEmpty() {
+        return nativeIsEmpty();
+    }
+
+    /**
+     * Convert a key string into the equivalent native tag.
+     *
+     * @throws IllegalArgumentException if the key was not recognized
+     * @throws NullPointerException if the key was null
+     *
+     * @hide
+     */
+    public static int getTag(String key) {
+        return nativeGetTagFromKey(key);
+    }
+
+    /**
+     * Get the underlying native type for a tag.
+     *
+     * @param tag An integer tag, see e.g. {@link #getTag}
+     * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
+     *
+     * @hide
+     */
+    public static int getNativeType(int tag) {
+        return nativeGetTypeFromTag(tag);
+    }
+
+    /**
+     * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
+     * the entry if src was null.</p>
+     *
+     * <p>An empty array can be passed in to update the entry to 0 elements.</p>
+     *
+     * @param tag An integer tag, see e.g. {@link #getTag}
+     * @param src An array of bytes, or null to erase the entry
+     *
+     * @hide
+     */
+    public void writeValues(int tag, byte[] src) {
+        nativeWriteValues(tag, src);
+    }
+
+    /**
+     * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
+     * the data properly.</p>
+     *
+     * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
+     *
+     * @param tag An integer tag, see e.g. {@link #getTag}
+     *
+     * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
+     * @hide
+     */
+    public byte[] readValues(int tag) {
+     // TODO: Optimization. Native code returns a ByteBuffer instead.
+        return nativeReadValues(tag);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
+            new HashMap<Class<? extends Enum>, int[]>();
+    /**
+     * Register a non-sequential set of values to be used with the pack/unpack functions.
+     * This enables get/set to correctly marshal the enum into a value that is C-compatible.
+     *
+     * @param enumType The class for an enum
+     * @param values A list of values mapping to the ordinals of the enum
+     *
+     * @hide
+     */
+    public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
+        if (enumType.getEnumConstants().length != values.length) {
+            throw new IllegalArgumentException(
+                    "Expected values array to be the same size as the enumTypes values "
+                            + values.length + " for type " + enumType);
+        }
+
+        Log.v(TAG, "Registered enum values for type " + enumType + " values");
+
+        sEnumValues.put(enumType, values);
+    }
+
+    /**
+     * Get the numeric value from an enum. This is usually the same as the ordinal value for
+     * enums that have fully sequential values, although for C-style enums the range of values
+     * may not map 1:1.
+     *
+     * @param enumValue Enum instance
+     * @return Int guaranteed to be ABI-compatible with the C enum equivalent
+     */
+    private static <T extends Enum<T>> int getEnumValue(T enumValue) {
+        int[] values;
+        values = sEnumValues.get(enumValue.getClass());
+
+        int ordinal = enumValue.ordinal();
+        if (values != null) {
+            return values[ordinal];
+        }
+
+        return ordinal;
+    }
+
+    /**
+     * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
+     *
+     * @param enumType Class of the enum we want to find
+     * @param value The numeric value of the enum
+     * @return An instance of the enum
+     */
+    private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
+        int ordinal;
+
+        int[] registeredValues = sEnumValues.get(enumType);
+        if (registeredValues != null) {
+            ordinal = -1;
+
+            for (int i = 0; i < registeredValues.length; ++i) {
+                if (registeredValues[i] == value) {
+                    ordinal = i;
+                    break;
+                }
+            }
+        } else {
+            ordinal = value;
+        }
+
+        T[] values = enumType.getEnumConstants();
+
+        if (ordinal < 0 || ordinal >= values.length) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "Argument 'value' (%d) was not a valid enum value for type %s "
+                                    + "(registered? %b)",
+                            value,
+                            enumType, (registeredValues != null)));
+        }
+
+        return values[ordinal];
+    }
+
+    static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
+            HashMap<Class<?>, MetadataMarshalClass<?>>();
+
+    private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
+        sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
+        MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
+
+        if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
+            throw new UnsupportedOperationException("Unsupported type " + nativeType +
+                    " to be marshalled to/from a " + type);
+        }
+
+        return marshaler;
+    }
+
+    /**
+     * We use a class initializer to allow the native code to cache some field offsets
+     */
+    static {
+        System.loadLibrary("media_jni");
+        nativeClassInit();
+
+        Log.v(TAG, "Shall register metadata marshalers");
+
+        // load built-in marshallers
+        registerMarshaler(new MetadataMarshalRect());
+        registerMarshaler(new MetadataMarshalSize());
+        registerMarshaler(new MetadataMarshalString());
+
+        Log.v(TAG, "Registered metadata marshalers");
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
new file mode 100644
index 0000000..6d224ef
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
@@ -0,0 +1,67 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+import java.nio.ByteBuffer;
+
+public interface MetadataMarshalClass<T> {
+
+    /**
+     * Marshal the specified object instance (value) into a byte buffer.
+     *
+     * @param value the value of type T that we wish to write into the byte buffer
+     * @param buffer the byte buffer into which the marshalled object will be written
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
+     *        Guaranteed to be one for which isNativeTypeSupported returns true.
+     * @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
+     * @return the size that needs to be written to the byte buffer
+     */
+    int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly);
+
+    /**
+     * Unmarshal a new object instance from the byte buffer.
+     * @param buffer the byte buffer, from which we will read the object
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
+     *        Guaranteed to be one for which isNativeTypeSupported returns true.
+     * @return a new instance of type T read from the byte buffer
+     */
+    T unmarshal(ByteBuffer buffer, int nativeType);
+
+    Class<T> getMarshalingClass();
+
+    /**
+     * Determines whether or not this marshaller supports this native type. Most marshallers
+     * will are likely to only support one type.
+     *
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
+     * @return true if it supports, false otherwise
+     */
+    boolean isNativeTypeSupported(int nativeType);
+
+    public static int NATIVE_SIZE_DYNAMIC = -1;
+
+    /**
+     * How many bytes T will take up if marshalled to/from nativeType
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
+     * @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
+     */
+    int getNativeSize(int nativeType);
+}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
new file mode 100644
index 0000000..ab72c4f
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
@@ -0,0 +1,67 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+import android.graphics.Rect;
+
+import java.nio.ByteBuffer;
+
+public class MetadataMarshalRect implements MetadataMarshalClass<Rect> {
+    private static final int SIZE = 16;
+
+    @Override
+    public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
+        if (sizeOnly) {
+            return SIZE;
+        }
+
+        buffer.putInt(value.left);
+        buffer.putInt(value.top);
+        buffer.putInt(value.width());
+        buffer.putInt(value.height());
+
+        return SIZE;
+    }
+
+    @Override
+    public Rect unmarshal(ByteBuffer buffer, int nativeType) {
+
+        int left = buffer.getInt();
+        int top = buffer.getInt();
+        int width = buffer.getInt();
+        int height = buffer.getInt();
+
+        int right = left + width;
+        int bottom = top + height;
+
+        return new Rect(left, top, right, bottom);
+    }
+
+    @Override
+    public Class<Rect> getMarshalingClass() {
+        return Rect.class;
+    }
+
+    @Override
+    public boolean isNativeTypeSupported(int nativeType) {
+        return nativeType == CameraMetadataNative.TYPE_INT32;
+    }
+
+    @Override
+    public int getNativeSize(int nativeType) {
+        return SIZE;
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
new file mode 100644
index 0000000..e8143e0
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
@@ -0,0 +1,60 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+import android.hardware.camera2.Size;
+
+import java.nio.ByteBuffer;
+
+public class MetadataMarshalSize implements MetadataMarshalClass<Size> {
+
+    private static final int SIZE = 8;
+
+    @Override
+    public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
+        if (sizeOnly) {
+            return SIZE;
+        }
+
+        buffer.putInt(value.getWidth());
+        buffer.putInt(value.getHeight());
+
+        return SIZE;
+    }
+
+    @Override
+    public Size unmarshal(ByteBuffer buffer, int nativeType) {
+        int width = buffer.getInt();
+        int height = buffer.getInt();
+
+        return new Size(width, height);
+    }
+
+    @Override
+    public Class<Size> getMarshalingClass() {
+        return Size.class;
+    }
+
+    @Override
+    public boolean isNativeTypeSupported(int nativeType) {
+        return nativeType == CameraMetadataNative.TYPE_INT32;
+    }
+
+    @Override
+    public int getNativeSize(int nativeType) {
+        return SIZE;
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
new file mode 100644
index 0000000..b61b8d3
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
@@ -0,0 +1,79 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+public class MetadataMarshalString implements MetadataMarshalClass<String> {
+
+    private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+
+    @Override
+    public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
+        byte[] arr = value.getBytes(UTF8_CHARSET);
+
+        if (!sizeOnly) {
+            buffer.put(arr);
+            buffer.put((byte)0); // metadata strings are NULL-terminated
+        }
+
+        return arr.length + 1;
+    }
+
+    @Override
+    public String unmarshal(ByteBuffer buffer, int nativeType) {
+
+        buffer.mark(); // save the current position
+
+        boolean foundNull = false;
+        int stringLength = 0;
+        while (buffer.hasRemaining()) {
+            if (buffer.get() == (byte)0) {
+                foundNull = true;
+                break;
+            }
+
+            stringLength++;
+        }
+        if (!foundNull) {
+            throw new IllegalArgumentException("Strings must be null-terminated");
+        }
+
+        buffer.reset(); // go back to the previously marked position
+
+        byte[] strBytes = new byte[stringLength + 1];
+        buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
+
+        // not including null character
+        return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
+    }
+
+    @Override
+    public Class<String> getMarshalingClass() {
+        return String.class;
+    }
+
+    @Override
+    public boolean isNativeTypeSupported(int nativeType) {
+        return nativeType == CameraMetadataNative.TYPE_BYTE;
+    }
+
+    @Override
+    public int getNativeSize(int nativeType) {
+        return NATIVE_SIZE_DYNAMIC;
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/package.html b/core/java/android/hardware/camera2/impl/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/hardware/camera2/package.html b/core/java/android/hardware/camera2/package.html
new file mode 100644
index 0000000..9f6c2a9
--- /dev/null
+++ b/core/java/android/hardware/camera2/package.html
@@ -0,0 +1,84 @@
+<!-- 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.
+-->
+<HTML>
+<BODY>
+<p>The android.hardware.camera2 package provides an interface to
+individual camera devices connected to an Android device. It replaces
+the deprecated {@link android.hardware.Camera} class.</p>
+
+<p>This package models a camera device as a pipeline, which takes in
+input requests for capturing a single frame, captures the single image
+per the request, and then outputs one capture result metadata packet,
+plus a set of output image buffers for the request. The requests are
+processed in-order, and multiple requests can be in flight at
+once. Since the camera device is a pipeline with multiple stages,
+having multiple requests in flight is required to maintain full
+framerate on most Android devices.</p>
+
+<p>To enumerate, query, and open available camera devices, obtain a
+{@link android.hardware.camera2.CameraManager} instance.</p>
+
+<p>Individual {@link android.hardware.camera2.CameraDevice
+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>
+
+<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}.
+</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>
+
+<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
+through <code>capture()</code> while there's a repeating request
+configured will be captured as soon as the current repeat (burst)
+capture completes.</p>
+
+<p>After processing a request, the camera device will produce a {@link
+android.hardware.camera2.CaptureResult} 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
+asynchronously relative to the output CaptureResult, sometimes
+substantially later.</p>
+
+</BODY>
+</HTML>
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.aidl b/core/java/android/hardware/camera2/utils/BinderHolder.aidl
new file mode 100644
index 0000000..f39d645
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/BinderHolder.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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 android.hardware.camera2.utils;
+
+/** @hide */
+parcelable BinderHolder;
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.java b/core/java/android/hardware/camera2/utils/BinderHolder.java
new file mode 100644
index 0000000..9eea390
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/BinderHolder.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.hardware.camera2.utils;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+public class BinderHolder implements Parcelable {
+    private IBinder mBinder = null;
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mBinder);
+    }
+
+    public void readFromParcel(Parcel src) {
+        mBinder = src.readStrongBinder();
+    }
+
+    public static final Parcelable.Creator<BinderHolder> CREATOR =
+             new Parcelable.Creator<BinderHolder>() {
+         @Override
+         public BinderHolder createFromParcel(Parcel in) {
+             return new BinderHolder(in);
+         }
+
+         @Override
+         public BinderHolder[] newArray(int size) {
+             return new BinderHolder[size];
+         }
+    };
+
+    public IBinder getBinder() {
+        return mBinder;
+    }
+
+    public void setBinder(IBinder binder) {
+        mBinder = binder;
+    }
+
+    public BinderHolder() {}
+
+    public BinderHolder(IBinder binder) {
+        mBinder = binder;
+    }
+
+    private BinderHolder(Parcel in) {
+        mBinder = in.readStrongBinder();
+    }
+}
+
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
new file mode 100644
index 0000000..e535e00
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -0,0 +1,155 @@
+/*
+ * 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 android.hardware.camera2.utils;
+
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
+
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+
+import java.lang.reflect.Method;
+
+/**
+ * Translate camera service status_t return values into exceptions.
+ *
+ * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
+ * @hide
+ */
+public class CameraBinderDecorator {
+
+    public static final int NO_ERROR = 0;
+    public static final int PERMISSION_DENIED = -1;
+    public static final int ALREADY_EXISTS = -17;
+    public static final int BAD_VALUE = -22;
+    public static final int DEAD_OBJECT = -32;
+
+    /**
+     * TODO: add as error codes in Errors.h
+     * - POLICY_PROHIBITS
+     * - RESOURCE_BUSY
+     * - NO_SUCH_DEVICE
+     */
+    public static final int EACCES = -13;
+    public static final int EBUSY = -16;
+    public static final int ENODEV = -19;
+    public static final int EOPNOTSUPP = -95;
+    public static final int EUSERS = -87;
+
+    private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
+
+        @Override
+        public void onBeforeInvocation(Method m, Object[] args) {
+        }
+
+        @Override
+        public void onAfterInvocation(Method m, Object[] args, Object result) {
+            // int return type => status_t => convert to exception
+            if (m.getReturnType() == Integer.TYPE) {
+                int returnValue = (Integer) result;
+
+                switch (returnValue) {
+                    case NO_ERROR:
+                        return;
+                    case PERMISSION_DENIED:
+                        throw new SecurityException("Lacking privileges to access camera service");
+                    case ALREADY_EXISTS:
+                        // This should be handled at the call site. Typically this isn't bad,
+                        // just means we tried to do an operation that already completed.
+                        return;
+                    case BAD_VALUE:
+                        throw new IllegalArgumentException("Bad argument passed to camera service");
+                    case DEAD_OBJECT:
+                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                                CAMERA_DISCONNECTED));
+                    case EACCES:
+                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                                CAMERA_DISABLED));
+                    case EBUSY:
+                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                                CAMERA_IN_USE));
+                    case EUSERS:
+                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                                MAX_CAMERAS_IN_USE));
+                    case ENODEV:
+                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                                CAMERA_DISCONNECTED));
+                    case EOPNOTSUPP:
+                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                                CAMERA_DEPRECATED_HAL));
+                }
+
+                /**
+                 * Trap the rest of the negative return values. If we have known
+                 * error codes i.e. ALREADY_EXISTS that aren't really runtime
+                 * errors, then add them to the top switch statement
+                 */
+                if (returnValue < 0) {
+                    throw new UnsupportedOperationException(String.format("Unknown error %d",
+                            returnValue));
+                }
+            }
+        }
+
+        @Override
+        public boolean onCatchException(Method m, Object[] args, Throwable t) {
+
+            if (t instanceof DeadObjectException) {
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        CAMERA_DISCONNECTED,
+                        "Process hosting the camera service has died unexpectedly",
+                        t));
+            } else if (t instanceof RemoteException) {
+                throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
+                        " which should never happen.", t);
+            }
+
+            return false;
+        }
+
+        @Override
+        public void onFinally(Method m, Object[] args) {
+        }
+
+    }
+
+    /**
+     * <p>
+     * Wraps the type T with a proxy that will check 'status_t' return codes
+     * from the native side of the camera service, and throw Java exceptions
+     * automatically based on the code.
+     * </p>
+     * <p>
+     * In addition it also rewrites binder's RemoteException into either a
+     * CameraAccessException or an UnsupportedOperationException.
+     * </p>
+     * <p>
+     * As a result of calling any method on the proxy, RemoteException is
+     * guaranteed never to be thrown.
+     * </p>
+     *
+     * @param obj object that will serve as the target for all method calls
+     * @param <T> the type of the element you want to wrap. This must be an interface.
+     * @return a proxy that will intercept all invocations to obj
+     */
+    public static <T> T newInstance(T obj) {
+        return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
+    }
+}
diff --git a/core/java/android/hardware/camera2/utils/CameraRuntimeException.java b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
new file mode 100644
index 0000000..9ed88a9
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
@@ -0,0 +1,63 @@
+package android.hardware.camera2.utils;
+
+import android.hardware.camera2.CameraAccessException;
+
+/**
+ * @hide
+ */
+public class CameraRuntimeException extends RuntimeException {
+
+    private final int mReason;
+    private String mMessage;
+    private Throwable mCause;
+
+    public final int getReason() {
+        return mReason;
+    }
+
+    public CameraRuntimeException(int problem) {
+        super();
+        mReason = problem;
+    }
+
+    public CameraRuntimeException(int problem, String message) {
+        super(message);
+        mReason = problem;
+        mMessage = message;
+    }
+
+    public CameraRuntimeException(int problem, String message, Throwable cause) {
+        super(message, cause);
+        mReason = problem;
+        mMessage = message;
+        mCause = cause;
+    }
+
+    public CameraRuntimeException(int problem, Throwable cause) {
+        super(cause);
+        mReason = problem;
+        mCause = cause;
+    }
+
+    /**
+     * Recreate this exception as the CameraAccessException equivalent.
+     * @return CameraAccessException
+     */
+    public CameraAccessException asChecked() {
+        CameraAccessException e;
+
+        if (mMessage != null && mCause != null) {
+            e = new CameraAccessException(mReason, mMessage, mCause);
+        } else if (mMessage != null) {
+            e = new CameraAccessException(mReason, mMessage);
+        } else if (mCause != null) {
+            e = new CameraAccessException(mReason, mCause);
+        } else {
+            e = new CameraAccessException(mReason);
+        }
+        // throw and catch, so java has a chance to fill out the stack trace
+        e.setStackTrace(this.getStackTrace());
+
+        return e;
+    }
+}
diff --git a/core/java/android/hardware/camera2/utils/Decorator.java b/core/java/android/hardware/camera2/utils/Decorator.java
new file mode 100644
index 0000000..5826497
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/Decorator.java
@@ -0,0 +1,92 @@
+
+package android.hardware.camera2.utils;
+
+import java.lang.reflect.*;
+
+/**
+ * This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
+ *
+ * @see android.hardware.camera2.utils.Decorator#newInstance
+ *
+ * @hide
+ */
+public class Decorator<T> implements InvocationHandler {
+
+    public interface DecoratorListener {
+        /**
+         * This method is called before the target method is invoked
+         * @param args arguments to target method
+         * @param m Method being called
+         */
+        void onBeforeInvocation(Method m, Object[] args);
+        /**
+         * This function is called after the target method is invoked
+         * if there were no uncaught exceptions
+         * @param args arguments to target method
+         * @param m Method being called
+         * @param result return value of target method
+         */
+        void onAfterInvocation(Method m, Object[] args, Object result);
+        /**
+         * This method is called only if there was an exception thrown by the target method
+         * during its invocation.
+         *
+         * @param args arguments to target method
+         * @param m Method being called
+         * @param t Throwable that was thrown
+         * @return false to rethrow exception, true if the exception was handled
+         */
+        boolean onCatchException(Method m, Object[] args, Throwable t);
+        /**
+         * This is called after the target method is invoked, regardless of whether or not
+         * there were any exceptions.
+         * @param args arguments to target method
+         * @param m Method being called
+         */
+        void onFinally(Method m, Object[] args);
+    }
+
+    private final T mObject;
+    private final DecoratorListener mListener;
+
+    /**
+     * Create a decorator wrapping the specified object's method calls.
+     *
+     * @param obj the object whose method calls you want to intercept
+     * @param listener the decorator handler for intercepted method calls
+     * @param <T> the type of the element you want to wrap. This must be an interface.
+     * @return a wrapped interface-compatible T
+     */
+    @SuppressWarnings("unchecked")
+    public static<T> T newInstance(T obj, DecoratorListener listener) {
+        return (T)java.lang.reflect.Proxy.newProxyInstance(
+                obj.getClass().getClassLoader(),
+                obj.getClass().getInterfaces(),
+                new Decorator<T>(obj, listener));
+    }
+
+    private Decorator(T obj, DecoratorListener listener) {
+        this.mObject = obj;
+        this.mListener = listener;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method m, Object[] args)
+            throws Throwable
+    {
+        Object result = null;
+        try {
+            mListener.onBeforeInvocation(m, args);
+            result = m.invoke(mObject, args);
+            mListener.onAfterInvocation(m, args, result);
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            if (!mListener.onCatchException(m, args, t)) {
+                throw t;
+            }
+        } finally {
+            mListener.onFinally(m, args);
+        }
+        return result;
+    }
+}
diff --git a/core/java/android/hardware/camera2/utils/UncheckedThrow.java b/core/java/android/hardware/camera2/utils/UncheckedThrow.java
new file mode 100644
index 0000000..8224fed
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/UncheckedThrow.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.hardware.camera2.utils;
+
+/**
+ * @hide
+ */
+public class UncheckedThrow {
+
+    /**
+     * Throw any kind of exception without needing it to be checked
+     * @param e any instance of a Exception
+     */
+    public static void throwAnyException(Exception e) {
+        /**
+         *  Abuse type erasure by making the compiler think we are throwing RuntimeException,
+         *  which is unchecked, but then inserting any exception in there.
+         */
+        UncheckedThrow.<RuntimeException>throwAnyImpl(e);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static<T extends Exception> void throwAnyImpl(Exception e) throws T {
+        throw (T) e;
+    }
+}
diff --git a/core/java/android/hardware/camera2/utils/package.html b/core/java/android/hardware/camera2/utils/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 0a7a2e7..f12be5f 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.Surface;
 
 import java.util.ArrayList;
 
@@ -68,16 +69,108 @@
      * Display category: Presentation displays.
      * <p>
      * This category can be used to identify secondary displays that are suitable for
-     * use as presentation displays.
+     * use as presentation displays such as HDMI or Wireless displays.  Applications
+     * may automatically project their content to presentation displays to provide
+     * richer second screen experiences.
      * </p>
      *
-     * @see android.app.Presentation for information about presenting content
-     * on secondary displays.
+     * @see android.app.Presentation
+     * @see Display#FLAG_PRESENTATION
      * @see #getDisplays(String)
      */
     public static final String DISPLAY_CATEGORY_PRESENTATION =
             "android.hardware.display.category.PRESENTATION";
 
+    /**
+     * Virtual display flag: Create a public display.
+     *
+     * <h3>Public virtual displays</h3>
+     * <p>
+     * When this flag is set, the virtual display is public.
+     * </p><p>
+     * A public virtual display behaves just like most any other display that is connected
+     * to the system such as an HDMI or Wireless display.  Applications can open
+     * windows on the display and the system may mirror the contents of other displays
+     * onto it.
+     * </p><p>
+     * Creating a public virtual display requires the
+     * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
+     * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
+     * These permissions are reserved for use by system components and are not available to
+     * third-party applications.
+     * </p>
+     *
+     * <h3>Private virtual displays</h3>
+     * <p>
+     * When this flag is not set, the virtual display is private as defined by the
+     * {@link Display#FLAG_PRIVATE} display flag.
+     * </p>
+     * A private virtual display belongs to the application that created it.
+     * Only the a owner of a private virtual display is allowed to place windows upon it.
+     * The private virtual display also does not participate in display mirroring: it will
+     * neither receive mirrored content from another display nor allow its own content to
+     * be mirrored elsewhere.  More precisely, the only processes that are allowed to
+     * enumerate or interact with the private display are those that have the same UID as the
+     * application that originally created the private virtual display.
+      * </p>
+     *
+     * @see #createVirtualDisplay
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
+
+    /**
+     * Virtual display flag: Create a presentation display.
+     *
+     * <h3>Presentation virtual displays</h3>
+     * <p>
+     * When this flag is set, the virtual display is registered as a presentation
+     * display in the {@link #DISPLAY_CATEGORY_PRESENTATION presentation display category}.
+     * Applications may automatically project their content to presentation displays
+     * to provide richer second screen experiences.
+     * </p>
+     *
+     * <h3>Non-presentation virtual displays</h3>
+     * <p>
+     * When this flag is not set, the virtual display is not registered as a presentation
+     * display.  Applications can still project their content on the display but they
+     * will typically not do so automatically.  This option is appropriate for
+     * more special-purpose displays.
+     * </p>
+     *
+     * @see android.app.Presentation
+     * @see #createVirtualDisplay
+     * @see #DISPLAY_CATEGORY_PRESENTATION
+     * @see Display#FLAG_PRESENTATION
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
+
+    /**
+     * Virtual display flag: Create a secure display.
+     *
+     * <h3>Secure virtual displays</h3>
+     * <p>
+     * When this flag is set, the virtual display is considered secure as defined
+     * by the {@link Display#FLAG_SECURE} display flag.  The caller promises to take
+     * reasonable measures, such as over-the-air encryption, to prevent the contents
+     * of the display from being intercepted or recorded on a persistent medium.
+     * </p><p>
+     * Creating a secure virtual display requires the
+     * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
+     * This permission is reserved for use by system components and is not available to
+     * third-party applications.
+     * </p>
+     *
+     * <h3>Non-secure virtual displays</h3>
+     * <p>
+     * When this flag is not set, the virtual display is considered unsecure.
+     * The content of secure windows will be blanked if shown on this display.
+     * </p>
+     *
+     * @see Display#FLAG_SECURE
+     * @see #createVirtualDisplay
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
+
     /** @hide */
     public DisplayManager(Context context) {
         mContext = context;
@@ -129,11 +222,12 @@
         synchronized (mLock) {
             try {
                 if (category == null) {
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, -1);
+                    addAllDisplaysLocked(mTempDisplays, displayIds);
                 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
                 }
                 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
             } finally {
@@ -142,12 +236,22 @@
         }
     }
 
-    private void addMatchingDisplaysLocked(
+    private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
+        for (int i = 0; i < displayIds.length; i++) {
+            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
+            if (display != null) {
+                displays.add(display);
+            }
+        }
+    }
+
+    private void addPresentationDisplaysLocked(
             ArrayList<Display> displays, int[] displayIds, int matchType) {
         for (int i = 0; i < displayIds.length; i++) {
             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
             if (display != null
-                    && (matchType < 0 || display.getType() == matchType)) {
+                    && (display.getFlags() & Display.FLAG_PRESENTATION) != 0
+                    && display.getType() == matchType) {
                 displays.add(display);
             }
         }
@@ -157,7 +261,7 @@
         Display display = mDisplays.get(displayId);
         if (display == null) {
             display = mGlobal.getCompatibleDisplay(displayId,
-                    mContext.getCompatibilityInfo(displayId));
+                    mContext.getDisplayAdjustments(displayId));
             if (display != null) {
                 mDisplays.put(displayId, display);
             }
@@ -219,6 +323,16 @@
         mGlobal.connectWifiDisplay(deviceAddress);
     }
 
+    /** @hide */
+    public void pauseWifiDisplay() {
+        mGlobal.pauseWifiDisplay();
+    }
+
+    /** @hide */
+    public void resumeWifiDisplay() {
+        mGlobal.resumeWifiDisplay();
+    }
+
     /**
      * Disconnects from the current Wifi display.
      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
@@ -275,6 +389,43 @@
     }
 
     /**
+     * Creates a virtual display.
+     * <p>
+     * The content of a virtual display is rendered to a {@link Surface} provided
+     * by the application.
+     * </p><p>
+     * The virtual display should be {@link VirtualDisplay#release released}
+     * when no longer needed.  Because a virtual display renders to a surface
+     * provided by the application, it will be released automatically when the
+     * process terminates and all remaining windows on it will be forcibly removed.
+     * </p><p>
+     * The behavior of the virtual display depends on the flags that are provided
+     * to this method.  By default, virtual displays are created to be private,
+     * non-presentation and unsecure.  Permissions may be required to use certain flags.
+     * </p>
+     *
+     * @param name The name of the virtual display, must be non-empty.
+     * @param width The width of the virtual display in pixels, must be greater than 0.
+     * @param height The height of the virtual display in pixels, must be greater than 0.
+     * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
+     * @param surface The surface to which the content of the virtual display should
+     * be rendered, must be non-null.
+     * @param flags A combination of virtual display flags:
+     * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}
+     * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}.
+     * @return The newly created virtual display, or null if the application could
+     * not create the virtual display.
+     *
+     * @throws SecurityException if the caller does not have permission to create
+     * a virtual display with the specified flags.
+     */
+    public VirtualDisplay createVirtualDisplay(String name,
+            int width, int height, int densityDpi, Surface surface, int flags) {
+        return mGlobal.createVirtualDisplay(mContext,
+                name, width, height, densityDpi, surface, flags);
+    }
+
+    /**
      * Listens for changes in available display devices.
      */
     public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index a858681..936a086 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -18,17 +18,20 @@
 
 import android.content.Context;
 import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.CompatibilityInfoHolder;
+import android.view.DisplayAdjustments;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Surface;
 
 import java.util.ArrayList;
 
@@ -161,18 +164,18 @@
      * Gets information about a logical display.
      *
      * The display metrics may be adjusted to provide compatibility
-     * for legacy applications.
+     * for legacy applications or limited screen areas.
      *
      * @param displayId The logical display id.
-     * @param cih The compatibility info, or null if none is required.
+     * @param daj The compatibility info and activityToken.
      * @return The display object, or null if there is no display with the given id.
      */
-    public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
+    public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
         DisplayInfo displayInfo = getDisplayInfo(displayId);
         if (displayInfo == null) {
             return null;
         }
-        return new Display(this, displayId, displayInfo, cih);
+        return new Display(this, displayId, displayInfo, daj);
     }
 
     /**
@@ -182,7 +185,18 @@
      * @return The display object, or null if there is no display with the given id.
      */
     public Display getRealDisplay(int displayId) {
-        return getCompatibleDisplay(displayId, null);
+        return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+    }
+
+    /**
+     * Gets information about a logical display without applying any compatibility metrics.
+     *
+     * @param displayId The logical display id.
+     * @param IBinder the activity token for this display.
+     * @return The display object, or null if there is no display with the given id.
+     */
+    public Display getRealDisplay(int displayId, IBinder token) {
+        return getCompatibleDisplay(displayId, new DisplayAdjustments(token));
     }
 
     public void registerDisplayListener(DisplayListener listener, Handler handler) {
@@ -273,6 +287,22 @@
         }
     }
 
+    public void pauseWifiDisplay() {
+        try {
+            mDm.pauseWifiDisplay();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to pause Wifi display.", ex);
+        }
+    }
+
+    public void resumeWifiDisplay() {
+        try {
+            mDm.resumeWifiDisplay();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to resume Wifi display.", ex);
+        }
+    }
+
     public void disconnectWifiDisplay() {
         try {
             mDm.disconnectWifiDisplay();
@@ -315,6 +345,53 @@
         }
     }
 
+    public VirtualDisplay createVirtualDisplay(Context context, String name,
+            int width, int height, int densityDpi, Surface surface, int flags) {
+        if (TextUtils.isEmpty(name)) {
+            throw new IllegalArgumentException("name must be non-null and non-empty");
+        }
+        if (width <= 0 || height <= 0 || densityDpi <= 0) {
+            throw new IllegalArgumentException("width, height, and densityDpi must be "
+                    + "greater than 0");
+        }
+        if (surface == null) {
+            throw new IllegalArgumentException("surface must not be null");
+        }
+
+        Binder token = new Binder();
+        int displayId;
+        try {
+            displayId = mDm.createVirtualDisplay(token, context.getPackageName(),
+                    name, width, height, densityDpi, surface, flags);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Could not create virtual display: " + name, ex);
+            return null;
+        }
+        if (displayId < 0) {
+            Log.e(TAG, "Could not create virtual display: " + name);
+            return null;
+        }
+        Display display = getRealDisplay(displayId);
+        if (display == null) {
+            Log.wtf(TAG, "Could not obtain display info for newly created "
+                    + "virtual display: " + name);
+            try {
+                mDm.releaseVirtualDisplay(token);
+            } catch (RemoteException ex) {
+            }
+            return null;
+        }
+        return new VirtualDisplay(this, display, token);
+    }
+
+    public void releaseVirtualDisplay(IBinder token) {
+        try {
+            mDm.releaseVirtualDisplay(token);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to release virtual display.", ex);
+        }
+    }
+
     private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
         @Override
         public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 79aad78..6b2c887 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -20,6 +20,7 @@
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
 import android.view.DisplayInfo;
+import android.view.Surface;
 
 /** @hide */
 interface IDisplayManager {
@@ -46,4 +47,18 @@
 
     // No permissions required.
     WifiDisplayStatus getWifiDisplayStatus();
+
+    // Requires CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT for certain
+    // combinations of flags.
+    int createVirtualDisplay(IBinder token, String packageName,
+            String name, int width, int height, int densityDpi, in Surface surface, int flags);
+
+    // No permissions required but must be same Uid as the creator.
+    void releaseVirtualDisplay(in IBinder token);
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void pauseWifiDisplay();
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void resumeWifiDisplay();
 }
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
new file mode 100644
index 0000000..908aadd
--- /dev/null
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.hardware.display;
+
+import android.os.IBinder;
+import android.view.Display;
+
+/**
+ * Represents a virtual display.
+ *
+ * @see DisplayManager#createVirtualDisplay
+ */
+public final class VirtualDisplay {
+    private final DisplayManagerGlobal mGlobal;
+    private final Display mDisplay;
+    private IBinder mToken;
+
+    VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token) {
+        mGlobal = global;
+        mDisplay = display;
+        mToken = token;
+    }
+
+    /**
+     * Gets the virtual display.
+     */
+    public Display getDisplay() {
+        return mDisplay;
+    }
+
+    /**
+     * Releases the virtual display and destroys its underlying surface.
+     * <p>
+     * All remaining windows on the virtual display will be forcibly removed
+     * as part of releasing the virtual display.
+     * </p>
+     */
+    public void release() {
+        if (mToken != null) {
+            mGlobal.releaseVirtualDisplay(mToken);
+            mToken = null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken + "}";
+    }
+}
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
index 2fd52b8..af5a84e 100644
--- a/core/java/android/hardware/display/WifiDisplay.java
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -33,6 +33,9 @@
     private final String mDeviceAddress;
     private final String mDeviceName;
     private final String mDeviceAlias;
+    private final boolean mIsAvailable;
+    private final boolean mCanConnect;
+    private final boolean mIsRemembered;
 
     public static final WifiDisplay[] EMPTY_ARRAY = new WifiDisplay[0];
 
@@ -41,7 +44,11 @@
             String deviceAddress = in.readString();
             String deviceName = in.readString();
             String deviceAlias = in.readString();
-            return new WifiDisplay(deviceAddress, deviceName, deviceAlias);
+            boolean isAvailable = (in.readInt() != 0);
+            boolean canConnect = (in.readInt() != 0);
+            boolean isRemembered = (in.readInt() != 0);
+            return new WifiDisplay(deviceAddress, deviceName, deviceAlias,
+                    isAvailable, canConnect, isRemembered);
         }
 
         public WifiDisplay[] newArray(int size) {
@@ -49,7 +56,8 @@
         }
     };
 
-    public WifiDisplay(String deviceAddress, String deviceName, String deviceAlias) {
+    public WifiDisplay(String deviceAddress, String deviceName, String deviceAlias,
+            boolean available, boolean canConnect, boolean remembered) {
         if (deviceAddress == null) {
             throw new IllegalArgumentException("deviceAddress must not be null");
         }
@@ -60,6 +68,9 @@
         mDeviceAddress = deviceAddress;
         mDeviceName = deviceName;
         mDeviceAlias = deviceAlias;
+        mIsAvailable = available;
+        mCanConnect = canConnect;
+        mIsRemembered = remembered;
     }
 
     /**
@@ -88,6 +99,27 @@
     }
 
     /**
+     * Returns true if device is available, false otherwise.
+     */
+    public boolean isAvailable() {
+        return mIsAvailable;
+    }
+
+    /**
+     * Returns true if device can be connected to (not in use), false otherwise.
+     */
+    public boolean canConnect() {
+        return mCanConnect;
+    }
+
+    /**
+     * Returns true if device has been remembered, false otherwise.
+     */
+    public boolean isRemembered() {
+        return mIsRemembered;
+    }
+
+    /**
      * Gets the name to show in the UI.
      * Uses the device alias if available, otherwise uses the device name.
      */
@@ -100,6 +132,10 @@
         return o instanceof WifiDisplay && equals((WifiDisplay)o);
     }
 
+    /**
+     * Returns true if the two displays have the same identity (address, name and alias).
+     * This method does not compare the current status of the displays.
+     */
     public boolean equals(WifiDisplay other) {
         return other != null
                 && mDeviceAddress.equals(other.mDeviceAddress)
@@ -127,6 +163,9 @@
         dest.writeString(mDeviceAddress);
         dest.writeString(mDeviceName);
         dest.writeString(mDeviceAlias);
+        dest.writeInt(mIsAvailable ? 1 : 0);
+        dest.writeInt(mCanConnect ? 1 : 0);
+        dest.writeInt(mIsRemembered ? 1 : 0);
     }
 
     @Override
@@ -141,6 +180,8 @@
         if (mDeviceAlias != null) {
             result += ", alias " + mDeviceAlias;
         }
+        result += ", isAvailable " + mIsAvailable + ", canConnect " + mCanConnect
+                + ", isRemembered " + mIsRemembered;
         return result;
     }
 }
diff --git a/core/java/android/hardware/display/WifiDisplaySessionInfo.java b/core/java/android/hardware/display/WifiDisplaySessionInfo.java
new file mode 100644
index 0000000..33d2725
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplaySessionInfo.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information regarding a wifi display session
+ * (such as session id, source ip address, etc.). This is needed for
+ * Wifi Display Certification process.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class WifiDisplaySessionInfo implements Parcelable {
+    private final boolean mClient;
+    private final int mSessionId;
+    private final String mGroupId;
+    private final String mPassphrase;
+    private final String mIP;
+
+    public static final Creator<WifiDisplaySessionInfo> CREATOR =
+            new Creator<WifiDisplaySessionInfo>() {
+        @Override
+        public WifiDisplaySessionInfo createFromParcel(Parcel in) {
+            boolean client = (in.readInt() != 0);
+            int session = in.readInt();
+            String group = in.readString();
+            String pp = in.readString();
+            String ip = in.readString();
+
+            return new WifiDisplaySessionInfo(client, session, group, pp, ip);
+        }
+
+        @Override
+        public WifiDisplaySessionInfo[] newArray(int size) {
+            return new WifiDisplaySessionInfo[size];
+        }
+    };
+
+    public WifiDisplaySessionInfo() {
+        this(true, 0, "", "", "");
+    }
+
+    public WifiDisplaySessionInfo(
+            boolean client, int session, String group, String pp, String ip) {
+        mClient = client;
+        mSessionId = session;
+        mGroupId = group;
+        mPassphrase = pp;
+        mIP = ip;
+    }
+
+    public boolean isClient() {
+        return mClient;
+    }
+
+    public int getSessionId() {
+        return mSessionId;
+    }
+
+    public String getGroupId() {
+        return mGroupId;
+    }
+
+    public String getPassphrase() {
+        return mPassphrase;
+    }
+
+    public String getIP() {
+        return mIP;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mClient ? 1 : 0);
+        dest.writeInt(mSessionId);
+        dest.writeString(mGroupId);
+        dest.writeString(mPassphrase);
+        dest.writeString(mIP);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // For debugging purposes only.
+    @Override
+    public String toString() {
+        return "WifiDisplaySessionInfo:"
+                +"\n    Client/Owner: " + (mClient ? "Client":"Owner")
+                +"\n    GroupId: " + mGroupId
+                +"\n    Passphrase: " + mPassphrase
+                +"\n    SessionId: " + mSessionId
+                +"\n    IP Address: " + mIP
+                ;
+    }
+}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
index f7e72c4..5216727 100644
--- a/core/java/android/hardware/display/WifiDisplayStatus.java
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Describes the current global state of Wifi display connectivity, including the
@@ -35,8 +37,10 @@
     private final int mScanState;
     private final int mActiveDisplayState;
     private final WifiDisplay mActiveDisplay;
-    private final WifiDisplay[] mAvailableDisplays;
-    private final WifiDisplay[] mRememberedDisplays;
+    private final WifiDisplay[] mDisplays;
+
+    /** Session info needed for Miracast Certification */
+    private final WifiDisplaySessionInfo mSessionInfo;
 
     /** Feature state: Wifi display is not available on this device. */
     public static final int FEATURE_STATE_UNAVAILABLE = 0;
@@ -70,18 +74,16 @@
                 activeDisplay = WifiDisplay.CREATOR.createFromParcel(in);
             }
 
-            WifiDisplay[] availableDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
-            for (int i = 0; i < availableDisplays.length; i++) {
-                availableDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+            WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(in.readInt());
+            for (int i = 0; i < displays.length; i++) {
+                displays[i] = WifiDisplay.CREATOR.createFromParcel(in);
             }
 
-            WifiDisplay[] rememberedDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
-            for (int i = 0; i < rememberedDisplays.length; i++) {
-                rememberedDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
-            }
+            WifiDisplaySessionInfo sessionInfo =
+                    WifiDisplaySessionInfo.CREATOR.createFromParcel(in);
 
             return new WifiDisplayStatus(featureState, scanState, activeDisplayState,
-                    activeDisplay, availableDisplays, rememberedDisplays);
+                    activeDisplay, displays, sessionInfo);
         }
 
         public WifiDisplayStatus[] newArray(int size) {
@@ -91,25 +93,22 @@
 
     public WifiDisplayStatus() {
         this(FEATURE_STATE_UNAVAILABLE, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
-                null, WifiDisplay.EMPTY_ARRAY, WifiDisplay.EMPTY_ARRAY);
+                null, WifiDisplay.EMPTY_ARRAY, null);
     }
 
-    public WifiDisplayStatus(int featureState, int scanState,
-            int activeDisplayState, WifiDisplay activeDisplay,
-            WifiDisplay[] availableDisplays, WifiDisplay[] rememberedDisplays) {
-        if (availableDisplays == null) {
-            throw new IllegalArgumentException("availableDisplays must not be null");
-        }
-        if (rememberedDisplays == null) {
-            throw new IllegalArgumentException("rememberedDisplays must not be null");
+    public WifiDisplayStatus(int featureState, int scanState, int activeDisplayState,
+            WifiDisplay activeDisplay, WifiDisplay[] displays, WifiDisplaySessionInfo sessionInfo) {
+        if (displays == null) {
+            throw new IllegalArgumentException("displays must not be null");
         }
 
         mFeatureState = featureState;
         mScanState = scanState;
         mActiveDisplayState = activeDisplayState;
         mActiveDisplay = activeDisplay;
-        mAvailableDisplays = availableDisplays;
-        mRememberedDisplays = rememberedDisplays;
+        mDisplays = displays;
+
+        mSessionInfo = (sessionInfo != null) ? sessionInfo : new WifiDisplaySessionInfo();
     }
 
     /**
@@ -152,24 +151,19 @@
     }
 
     /**
-     * Gets the list of all available Wifi displays as reported by the most recent
-     * scan, never null.
-     * <p>
-     * Some of these displays may already be remembered, others may be unknown.
-     * </p>
+     * Gets the list of Wifi displays, returns a combined list of all available
+     * Wifi displays as reported by the most recent scan, and all remembered
+     * Wifi displays (not necessarily available at the time).
      */
-    public WifiDisplay[] getAvailableDisplays() {
-        return mAvailableDisplays;
+    public WifiDisplay[] getDisplays() {
+        return mDisplays;
     }
 
     /**
-     * Gets the list of all remembered Wifi displays, never null.
-     * <p>
-     * Not all remembered displays will necessarily be available.
-     * </p>
+     * Gets the Wifi display session info (required for certification only)
      */
-    public WifiDisplay[] getRememberedDisplays() {
-        return mRememberedDisplays;
+    public WifiDisplaySessionInfo getSessionInfo() {
+        return mSessionInfo;
     }
 
     @Override
@@ -185,15 +179,12 @@
             dest.writeInt(0);
         }
 
-        dest.writeInt(mAvailableDisplays.length);
-        for (WifiDisplay display : mAvailableDisplays) {
+        dest.writeInt(mDisplays.length);
+        for (WifiDisplay display : mDisplays) {
             display.writeToParcel(dest, flags);
         }
 
-        dest.writeInt(mRememberedDisplays.length);
-        for (WifiDisplay display : mRememberedDisplays) {
-            display.writeToParcel(dest, flags);
-        }
+        mSessionInfo.writeToParcel(dest, flags);
     }
 
     @Override
@@ -208,8 +199,8 @@
                 + ", scanState=" + mScanState
                 + ", activeDisplayState=" + mActiveDisplayState
                 + ", activeDisplay=" + mActiveDisplay
-                + ", availableDisplays=" + Arrays.toString(mAvailableDisplays)
-                + ", rememberedDisplays=" + Arrays.toString(mRememberedDisplays)
+                + ", displays=" + Arrays.toString(mDisplays)
+                + ", sessionInfo=" + mSessionInfo
                 + "}";
     }
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 761faaf..30e69a6 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -579,15 +579,33 @@
      * @hide
      */
     public boolean[] deviceHasKeys(int[] keyCodes) {
+        return deviceHasKeys(-1, keyCodes);
+    }
+
+    /**
+     * Queries the framework about whether any physical keys exist on the
+     * any keyboard attached to the device that are capable of producing the given
+     * array of key codes.
+     *
+     * @param id The id of the device to query.
+     * @param keyCodes The array of key codes to query.
+     * @return A new array of the same size as the key codes array whose elements are set to true
+     * if the given device could produce the corresponding key code at the same index in the key
+     * codes array.
+     *
+     * @hide
+     */
+    public boolean[] deviceHasKeys(int id, int[] keyCodes) {
         boolean[] ret = new boolean[keyCodes.length];
         try {
-            mIm.hasKeys(-1, InputDevice.SOURCE_ANY, keyCodes, ret);
+            mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
         } catch (RemoteException e) {
             // no fallback; just return the empty array
         }
         return ret;
     }
 
+
     /**
      * Injects an input event into the event system on behalf of an application.
      * The synchronization mode determines whether the method blocks while waiting for
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index e67d0d7..21de9f5 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -15,16 +15,11 @@
  */
 package android.hardware.location;
 
-import android.content.Context;
 import android.location.Location;
 import android.os.RemoteException;
-import android.util.Log;
 
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
 
 /**
  * This class handles geofences managed by various hardware subsystems. It contains
@@ -52,7 +47,7 @@
     private IGeofenceHardware mService;
 
     // Hardware systems that do geofence monitoring.
-    static final int NUM_MONITORS = 1;
+    static final int NUM_MONITORS = 2;
 
     /**
      * Constant for geofence monitoring done by the GPS hardware.
@@ -60,6 +55,13 @@
     public static final int MONITORING_TYPE_GPS_HARDWARE = 0;
 
     /**
+     * Constant for geofence monitoring done by the Fused hardware.
+     *
+     * @hide
+     */
+    public static final int MONITORING_TYPE_FUSED_HARDWARE = 1;
+
+    /**
      * Constant to indiciate that the monitoring system is currently
      * available for monitoring geofences.
      */
@@ -124,8 +126,12 @@
      */
     public static final int GEOFENCE_FAILURE = 5;
 
-    static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
-    static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
+    /**
+     * The constant used to indicate that the operation failed due to insufficient memory.
+     *
+     * @hide
+     */
+    public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6;
 
     private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
             mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 77e3143..6b61690 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -18,23 +18,18 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.location.IFusedGeofenceHardware;
 import android.location.IGpsGeofenceHardware;
 import android.location.Location;
-import android.location.LocationManager;
-import android.os.Binder;
-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.ServiceManager;
-import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseArray;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 
 /**
  * This class manages the geofences which are handled by hardware.
@@ -54,6 +49,7 @@
             new ArrayList[GeofenceHardware.NUM_MONITORS];
     private final ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
 
+    private IFusedGeofenceHardware mFusedService;
     private IGpsGeofenceHardware mGpsService;
 
     private int[] mSupportedMonitorTypes = new int[GeofenceHardware.NUM_MONITORS];
@@ -67,7 +63,7 @@
     private static final int GEOFENCE_CALLBACK_BINDER_DIED = 6;
 
     // mCallbacksHandler message types
-    private static final int GPS_GEOFENCE_STATUS = 1;
+    private static final int GEOFENCE_STATUS = 1;
     private static final int CALLBACK_ADD = 2;
     private static final int CALLBACK_REMOVE = 3;
     private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
@@ -91,16 +87,6 @@
     private static final int RESOLUTION_LEVEL_COARSE = 2;
     private static final int RESOLUTION_LEVEL_FINE = 3;
 
-    // GPS Geofence errors. Should match gps.h constants.
-    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
-    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
-    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
-    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
-    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
-    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
-
-
-
     public synchronized static GeofenceHardwareImpl getInstance(Context context) {
         if (sInstance == null) {
             sInstance = new GeofenceHardwareImpl(context);
@@ -113,6 +99,9 @@
         // Init everything to unsupported.
         setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
                 GeofenceHardware.MONITOR_UNSUPPORTED);
+        setMonitorAvailability(
+                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
+                GeofenceHardware.MONITOR_UNSUPPORTED);
 
     }
 
@@ -147,6 +136,22 @@
         }
     }
 
+    private void updateFusedHardwareAvailability() {
+        boolean fusedSupported;
+        try {
+            fusedSupported = mFusedService.isSupported();
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException calling LocationManagerService");
+            fusedSupported = false;
+        }
+
+        if(fusedSupported) {
+            setMonitorAvailability(
+                    GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
+                    GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE);
+        }
+    }
+
     public void setGpsHardwareGeofence(IGpsGeofenceHardware service) {
         if (mGpsService == null) {
             mGpsService = service;
@@ -159,12 +164,39 @@
         }
     }
 
+    public void setFusedGeofenceHardware(IFusedGeofenceHardware service) {
+        if(mFusedService == null) {
+            mFusedService = service;
+            updateFusedHardwareAvailability();
+        } else if(service == null) {
+            mFusedService = null;
+            Log.w(TAG, "Fused Geofence Hardware service seems to have crashed");
+        } else {
+            Log.e(TAG, "Error: FusedService being set again");
+        }
+    }
+
     public int[] getMonitoringTypes() {
+        boolean gpsSupported;
+        boolean fusedSupported;
         synchronized (mSupportedMonitorTypes) {
-            if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
-                        GeofenceHardware.MONITOR_UNSUPPORTED) {
-                return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE};
+            gpsSupported = mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE]
+                    != GeofenceHardware.MONITOR_UNSUPPORTED;
+            fusedSupported = mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE]
+                    != GeofenceHardware.MONITOR_UNSUPPORTED;
+        }
+
+        if(gpsSupported) {
+            if(fusedSupported) {
+                return new int[] {
+                        GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                        GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE };
+            } else {
+                return new int[] { GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE };
             }
+        } else if (fusedSupported) {
+            return new int[] { GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE };
+        } else {
             return new int[0];
         }
     }
@@ -213,6 +245,30 @@
                     result = false;
                 }
                 break;
+            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
+                if(mFusedService == null) {
+                    return false;
+                }
+                GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence(
+                        latitude,
+                        longitude,
+                        radius);
+                request.setUnknownTimer(unknownTimer);
+                request.setNotificationResponsiveness(notificationResponsivenes);
+                request.setMonitorTransitions(monitorTransitions);
+                request.setLastTransition(lastTransition);
+
+                GeofenceHardwareRequestParcelable parcelableRequest =
+                        new GeofenceHardwareRequestParcelable(geofenceId, request);
+                try {
+                    mFusedService.addGeofences(
+                            new GeofenceHardwareRequestParcelable[] { parcelableRequest });
+                    result = true;
+                } catch(RemoteException e) {
+                    Log.e(TAG, "AddGeofence: RemoteException calling LocationManagerService");
+                    result = false;
+                }
+                break;
             default:
                 result = false;
         }
@@ -251,6 +307,18 @@
                     result = false;
                 }
                 break;
+            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
+                if(mFusedService == null) {
+                    return false;
+                }
+                try {
+                    mFusedService.removeGeofences(new int[] { geofenceId });
+                    result = true;
+                } catch(RemoteException e) {
+                    Log.e(TAG, "RemoveGeofence: RemoteException calling LocationManagerService");
+                    result = false;
+                }
+                break;
             default:
                 result = false;
         }
@@ -278,6 +346,18 @@
                     result = false;
                 }
                 break;
+            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
+                if(mFusedService == null) {
+                    return false;
+                }
+                try {
+                    mFusedService.pauseMonitoringGeofence(geofenceId);
+                    result = true;
+                } catch(RemoteException e) {
+                    Log.e(TAG, "PauseGeofence: RemoteException calling LocationManagerService");
+                    result = false;
+                }
+                break;
             default:
                 result = false;
         }
@@ -306,6 +386,18 @@
                     result = false;
                 }
                 break;
+            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
+                if(mFusedService == null) {
+                    return false;
+                }
+                try {
+                    mFusedService.resumeMonitoringGeofence(geofenceId, monitorTransition);
+                    result = true;
+                } catch(RemoteException e) {
+                    Log.e(TAG, "ResumeGeofence: RemoteException calling LocationManagerService");
+                    result = false;
+                }
+                break;
             default:
                 result = false;
         }
@@ -334,127 +426,106 @@
         return true;
     }
 
-    private Location getLocation(int flags, double latitude,
-            double longitude, double altitude, float speed, float bearing, float accuracy,
-            long timestamp) {
-        if (DEBUG) Log.d(TAG, "GetLocation: " + flags + ":" + latitude);
-        Location location = new Location(LocationManager.GPS_PROVIDER);
-        if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
-            location.setLatitude(latitude);
-            location.setLongitude(longitude);
-            location.setTime(timestamp);
-            // It would be nice to push the elapsed real-time timestamp
-            // further down the stack, but this is still useful
-            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+    /**
+     * Used to report geofence transitions
+     */
+    public void reportGeofenceTransition(
+            int geofenceId,
+            Location location,
+            int transition,
+            long transitionTimestamp,
+            int monitoringType,
+            int sourcesUsed) {
+        if(location == null) {
+            Log.e(TAG, String.format("Invalid Geofence Transition: location=%p", location));
+            return;
         }
-        if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
-            location.setAltitude(altitude);
-        } else {
-            location.removeAltitude();
+        if(DEBUG) {
+            Log.d(
+                    TAG,
+                    "GeofenceTransition| " + location + ", transition:" + transition +
+                    ", transitionTimestamp:" + transitionTimestamp + ", monitoringType:" +
+                    monitoringType + ", sourcesUsed:" + sourcesUsed);
         }
-        if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
-            location.setSpeed(speed);
-        } else {
-            location.removeSpeed();
-        }
-        if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
-            location.setBearing(bearing);
-        } else {
-            location.removeBearing();
-        }
-        if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
-            location.setAccuracy(accuracy);
-        } else {
-            location.removeAccuracy();
-        }
-        return location;
+
+        GeofenceTransition geofenceTransition = new GeofenceTransition(
+                geofenceId,
+                transition,
+                transitionTimestamp,
+                location,
+                monitoringType,
+                sourcesUsed);
+        acquireWakeLock();
+
+        Message message = mGeofenceHandler.obtainMessage(
+                GEOFENCE_TRANSITION_CALLBACK,
+                geofenceTransition);
+        message.sendToTarget();
     }
 
     /**
-     * called from GpsLocationProvider to report geofence transition
+     * Used to report Monitor status changes.
      */
-    public void reportGpsGeofenceTransition(int geofenceId, int flags, double latitude,
-            double longitude, double altitude, float speed, float bearing, float accuracy,
-            long timestamp, int transition, long transitionTimestamp) {
-        if (DEBUG) Log.d(TAG, "GeofenceTransition: Flags: " + flags + " Lat: " + latitude +
-            " Long: " + longitude + " Altitude: " + altitude + " Speed: " + speed + " Bearing: " +
-            bearing + " Accuracy: " + accuracy + " Timestamp: " + timestamp + " Transition: " +
-            transition + " TransitionTimestamp: " + transitionTimestamp);
-        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
-                accuracy, timestamp);
-        GeofenceTransition t = new GeofenceTransition(geofenceId, transition, timestamp, location);
+    public void reportGeofenceMonitorStatus(
+            int monitoringType,
+            int monitoringStatus,
+            Location location,
+            int source) {
+        // TODO: use the source if needed in the future
+        setMonitorAvailability(monitoringType, monitoringStatus);
         acquireWakeLock();
-        Message m = mGeofenceHandler.obtainMessage(GEOFENCE_TRANSITION_CALLBACK, t);
-        mGeofenceHandler.sendMessage(m);
+        Message message = mCallbacksHandler.obtainMessage(GEOFENCE_STATUS, location);
+        message.arg1 = monitoringStatus;
+        message.arg2 = monitoringType;
+        message.sendToTarget();
     }
 
     /**
-     * called from GpsLocationProvider to report GPS status change.
+     * Internal generic status report function for Geofence operations.
+     *
+     * @param operation The operation to be reported as defined internally.
+     * @param geofenceId The id of the geofence the operation is related to.
+     * @param operationStatus The status of the operation as defined in GeofenceHardware class. This
+     *                        status is independent of the statuses reported by different HALs.
      */
-    public void reportGpsGeofenceStatus(int status, int flags, double latitude,
-            double longitude, double altitude, float speed, float bearing, float accuracy,
-            long timestamp) {
-        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
-                accuracy, timestamp);
-        boolean available = false;
-        if (status == GeofenceHardware.GPS_GEOFENCE_AVAILABLE) available = true;
-
-        int val = (available ? GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE :
-                GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE);
-        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, val);
-
+    private void reportGeofenceOperationStatus(int operation, int geofenceId, int operationStatus) {
         acquireWakeLock();
-        Message m = mCallbacksHandler.obtainMessage(GPS_GEOFENCE_STATUS, location);
-        m.arg1 = val;
-        mCallbacksHandler.sendMessage(m);
+        Message message = mGeofenceHandler.obtainMessage(operation);
+        message.arg1 = geofenceId;
+        message.arg2 = operationStatus;
+        message.sendToTarget();
     }
 
     /**
-     * called from GpsLocationProvider add geofence callback.
+     * Used to report the status of a Geofence Add operation.
      */
-    public void reportGpsGeofenceAddStatus(int geofenceId, int status) {
-        if (DEBUG) Log.d(TAG, "Add Callback: GPS : Id: " + geofenceId + " Status: " + status);
-        acquireWakeLock();
-        Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE_CALLBACK);
-        m.arg1 = geofenceId;
-        m.arg2 = getGeofenceStatus(status);
-        mGeofenceHandler.sendMessage(m);
+    public void reportGeofenceAddStatus(int geofenceId, int status) {
+        if(DEBUG) Log.d(TAG, "AddCallback| id:" + geofenceId + ", status:" + status);
+        reportGeofenceOperationStatus(ADD_GEOFENCE_CALLBACK, geofenceId, status);
     }
 
     /**
-     * called from GpsLocationProvider remove geofence callback.
+     * Used to report the status of a Geofence Remove operation.
      */
-    public void reportGpsGeofenceRemoveStatus(int geofenceId, int status) {
-        if (DEBUG) Log.d(TAG, "Remove Callback: GPS : Id: " + geofenceId + " Status: " + status);
-        acquireWakeLock();
-        Message m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE_CALLBACK);
-        m.arg1 = geofenceId;
-        m.arg2 = getGeofenceStatus(status);
-        mGeofenceHandler.sendMessage(m);
+    public void reportGeofenceRemoveStatus(int geofenceId, int status) {
+        if(DEBUG) Log.d(TAG, "RemoveCallback| id:" + geofenceId + ", status:" + status);
+        reportGeofenceOperationStatus(REMOVE_GEOFENCE_CALLBACK, geofenceId, status);
     }
 
     /**
-     * called from GpsLocationProvider pause geofence callback.
+     * Used to report the status of a Geofence Pause operation.
      */
-    public void reportGpsGeofencePauseStatus(int geofenceId, int status) {
-        if (DEBUG) Log.d(TAG, "Pause Callback: GPS : Id: " + geofenceId + " Status: " + status);
-        acquireWakeLock();
-        Message m = mGeofenceHandler.obtainMessage(PAUSE_GEOFENCE_CALLBACK);
-        m.arg1 = geofenceId;
-        m.arg2 = getGeofenceStatus(status);
-        mGeofenceHandler.sendMessage(m);
+    public void reportGeofencePauseStatus(int geofenceId, int status) {
+        if(DEBUG) Log.d(TAG, "PauseCallbac| id:" + geofenceId + ", status" + status);
+        reportGeofenceOperationStatus(PAUSE_GEOFENCE_CALLBACK, geofenceId, status);
     }
 
     /**
-     * called from GpsLocationProvider resume geofence callback.
+     * Used to report the status of a Geofence Resume operation.
      */
-    public void reportGpsGeofenceResumeStatus(int geofenceId, int status) {
-        if (DEBUG) Log.d(TAG, "Resume Callback: GPS : Id: " + geofenceId + " Status: " + status);
-        acquireWakeLock();
-        Message m = mGeofenceHandler.obtainMessage(RESUME_GEOFENCE_CALLBACK);
-        m.arg1 = geofenceId;
-        m.arg2 = getGeofenceStatus(status);
-        mGeofenceHandler.sendMessage(m);
+    public void reportGeofenceResumeStatus(int geofenceId, int status) {
+        if(DEBUG) Log.d(TAG, "ResumeCallback| id:" + geofenceId + ", status:" + status);
+        reportGeofenceOperationStatus(RESUME_GEOFENCE_CALLBACK, geofenceId, status);
     }
 
     // All operations on mGeofences
@@ -527,19 +598,20 @@
                     GeofenceTransition geofenceTransition = (GeofenceTransition)(msg.obj);
                     synchronized (mGeofences) {
                         callback = mGeofences.get(geofenceTransition.mGeofenceId);
-                    }
 
-                    if (DEBUG) Log.d(TAG, "GeofenceTransistionCallback: GPS : GeofenceId: " +
-                            geofenceTransition.mGeofenceId +
-                            " Transition: " + geofenceTransition.mTransition +
-                            " Location: " + geofenceTransition.mLocation + ":" + mGeofences);
+                        // need to keep access to mGeofences synchronized at all times
+                        if (DEBUG) Log.d(TAG, "GeofenceTransistionCallback: GPS : GeofenceId: " +
+                                geofenceTransition.mGeofenceId +
+                                " Transition: " + geofenceTransition.mTransition +
+                                " Location: " + geofenceTransition.mLocation + ":" + mGeofences);
+                    }
 
                     if (callback != null) {
                         try {
                             callback.onGeofenceTransition(
                                     geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
                                     geofenceTransition.mLocation, geofenceTransition.mTimestamp,
-                                    GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
+                                    geofenceTransition.mMonitoringType);
                         } catch (RemoteException e) {}
                     }
                     releaseWakeLock();
@@ -571,21 +643,20 @@
             IGeofenceHardwareMonitorCallback callback;
 
             switch (msg.what) {
-                case GPS_GEOFENCE_STATUS:
+                case GEOFENCE_STATUS:
                     Location location = (Location) msg.obj;
                     int val = msg.arg1;
+                    monitoringType = msg.arg2;
                     boolean available;
                     available = (val == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE ?
                             true : false);
-                    callbackList = mCallbacks[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE];
+                    callbackList = mCallbacks[monitoringType];
                     if (callbackList != null) {
                         if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
 
                         for (IGeofenceHardwareMonitorCallback c: callbackList) {
                             try {
-                                c.onMonitoringSystemChange(
-                                        GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
-                                        location);
+                                c.onMonitoringSystemChange(monitoringType, available, location);
                             } catch (RemoteException e) {}
                         }
                     }
@@ -666,12 +737,22 @@
         private int mGeofenceId, mTransition;
         private long mTimestamp;
         private Location mLocation;
+        private int mMonitoringType;
+        private int mSourcesUsed;
 
-        GeofenceTransition(int geofenceId, int transition, long timestamp, Location location) {
+        GeofenceTransition(
+                int geofenceId,
+                int transition,
+                long timestamp,
+                Location location,
+                int monitoringType,
+                int sourcesUsed) {
             mGeofenceId = geofenceId;
             mTransition = transition;
             mTimestamp = timestamp;
             mLocation = location;
+            mMonitoringType = monitoringType;
+            mSourcesUsed = sourcesUsed;
         }
     }
 
@@ -686,6 +767,8 @@
         switch (monitoringType) {
             case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
                 return RESOLUTION_LEVEL_FINE;
+            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
+                return RESOLUTION_LEVEL_FINE;
         }
         return RESOLUTION_LEVEL_NONE;
     }
@@ -752,22 +835,4 @@
             return RESOLUTION_LEVEL_NONE;
         }
     }
-
-    private int getGeofenceStatus(int status) {
-        switch (status) {
-            case GPS_GEOFENCE_OPERATION_SUCCESS:
-                return GeofenceHardware.GEOFENCE_SUCCESS;
-            case GPS_GEOFENCE_ERROR_GENERIC:
-                return GeofenceHardware.GEOFENCE_FAILURE;
-            case GPS_GEOFENCE_ERROR_ID_EXISTS:
-                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
-            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
-                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
-            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
-                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
-            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
-                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
-        }
-        return -1;
-    }
 }
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl
new file mode 100644
index 0000000..b599d44
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.location;
+
+parcelable GeofenceHardwareRequestParcelable;
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
new file mode 100644
index 0000000..40e7fc4
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
@@ -0,0 +1,151 @@
+/*
+ * 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 android.hardware.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Geofence Hardware Request used for internal location services communication.
+ *
+ * @hide
+ */
+public final class GeofenceHardwareRequestParcelable implements Parcelable {
+    private GeofenceHardwareRequest mRequest;
+    private int mId;
+
+    public GeofenceHardwareRequestParcelable(int id, GeofenceHardwareRequest request) {
+        mId = id;
+        mRequest = request;
+    }
+
+    /**
+     * Returns the id of this request.
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the latitude of this geofence.
+     */
+    public double getLatitude() {
+        return mRequest.getLatitude();
+    }
+
+    /**
+     * Returns the longitude of this geofence.
+     */
+    public double getLongitude() {
+        return mRequest.getLongitude();
+    }
+
+    /**
+     * Returns the radius of this geofence.
+     */
+    public double getRadius() {
+        return mRequest.getRadius();
+    }
+
+    /**
+     * Returns transitions monitored for this geofence.
+     */
+    public int getMonitorTransitions() {
+        return mRequest.getMonitorTransitions();
+    }
+
+    /**
+     * Returns the unknownTimer of this geofence.
+     */
+    public int getUnknownTimer() {
+        return mRequest.getUnknownTimer();
+    }
+
+    /**
+     * Returns the notification responsiveness of this geofence.
+     */
+    public int getNotificationResponsiveness() {
+        return mRequest.getNotificationResponsiveness();
+    }
+
+    /**
+     * Returns the last transition of this geofence.
+     */
+    public int getLastTransition() {
+        return mRequest.getLastTransition();
+    }
+
+    /**
+     * Returns the type of the geofence for the current request.
+     */
+    int getType() {
+        return mRequest.getType();
+    }
+
+    /**
+     * Method definitions to support Parcelable operations.
+     */
+    public static final Parcelable.Creator<GeofenceHardwareRequestParcelable> CREATOR = 
+            new Parcelable.Creator<GeofenceHardwareRequestParcelable>() {
+        @Override
+        public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) {
+            int geofenceType = parcel.readInt();
+            if(geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+                Log.e(
+                        "GeofenceHardwareRequest",
+                        String.format("Invalid Geofence type: %d", geofenceType));
+                return null;
+            }
+
+            GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence(
+                    parcel.readDouble(),
+                    parcel.readDouble(),
+                    parcel.readDouble());
+            request.setLastTransition(parcel.readInt());
+            request.setMonitorTransitions(parcel.readInt());
+            request.setUnknownTimer(parcel.readInt());
+            request.setNotificationResponsiveness(parcel.readInt());
+            
+            int id = parcel.readInt();
+            return new GeofenceHardwareRequestParcelable(id, request);
+        }
+
+        @Override
+        public GeofenceHardwareRequestParcelable[] newArray(int size) {
+            return new GeofenceHardwareRequestParcelable[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(getType());
+        parcel.writeDouble(getLatitude());
+        parcel.writeDouble(getLongitude());
+        parcel.writeDouble(getRadius());
+        parcel.writeInt(getLastTransition());
+        parcel.writeInt(getMonitorTransitions());
+        parcel.writeInt(getUnknownTimer());
+        parcel.writeInt(getNotificationResponsiveness());
+        parcel.writeInt(getId());
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index 3bc70ee..fb238bd 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -20,6 +20,7 @@
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.location.IFusedGeofenceHardware;
 import android.location.IGpsGeofenceHardware;
 import android.os.Binder;
 import android.os.IBinder;
@@ -68,6 +69,10 @@
             mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
         }
 
+        public void setFusedGeofenceHardware(IFusedGeofenceHardware service) {
+            mGeofenceHardwareImpl.setFusedGeofenceHardware(service);
+        }
+
         public int[] getMonitoringTypes() {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl
new file mode 100644
index 0000000..382c12c
--- /dev/null
+++ b/core/java/android/hardware/location/IFusedLocationHardware.aidl
@@ -0,0 +1,117 @@
+/*
+ * 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/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.FusedBatchOptions;
+
+/**
+ * Fused Location hardware interface.
+ * This interface is the basic set of supported functionality by Fused Hardware
+ * modules that offer Location batching capabilities.
+ *
+ * @hide
+ */
+interface IFusedLocationHardware {
+    /**
+     * Registers a sink with the Location Hardware object.
+     *
+     * @param eventSink     The sink to register.
+     */
+    void registerSink(in IFusedLocationHardwareSink eventSink);
+
+    /**
+     * Unregisters a sink with the Location Hardware object.
+     *
+     * @param eventSink     The sink to unregister.
+     */
+    void unregisterSink(in IFusedLocationHardwareSink eventSink);
+
+    /**
+     * Provides access to the batch size available in Hardware.
+     *
+     * @return The batch size the hardware supports.
+     */
+    int getSupportedBatchSize();
+
+    /**
+     * Requests the Hardware to start batching locations.
+     *
+     * @param id            An Id associated with the request.
+     * @param batchOptions  The options required for batching.
+     *
+     * @throws RuntimeException if the request Id exists.
+     */
+    void startBatching(in int id, in FusedBatchOptions batchOptions);
+
+    /**
+     * Requests the Hardware to stop batching for the given Id.
+     *
+     * @param id    The request that needs to be stopped.
+     * @throws RuntimeException if the request Id is unknown.
+     */
+    void stopBatching(in int id);
+
+    /**
+     * Updates a batching operation in progress.
+     *
+     * @param id                The Id of the operation to update.
+     * @param batchOptions     The options to apply to the given operation.
+     *
+     * @throws RuntimeException if the Id of the request is unknown.
+     */
+    void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions);
+
+    /**
+     * Requests the most recent locations available in Hardware.
+     * This operation does not dequeue the locations, so still other batching
+     * events will continue working.
+     *
+     * @param batchSizeRequested    The number of locations requested.
+     */
+    void requestBatchOfLocations(in int batchSizeRequested);
+
+    /**
+     * Flags if the Hardware supports injection of diagnostic data.
+     *
+     * @return True if data injection is supported, false otherwise.
+     */
+    boolean supportsDiagnosticDataInjection();
+
+    /**
+     * Injects diagnostic data into the Hardware subsystem.
+     *
+     * @param data  The data to inject.
+     * @throws RuntimeException if injection is not supported.
+     */
+    void injectDiagnosticData(in String data);
+
+    /**
+     * Flags if the Hardware supports injection of device context information.
+     *
+     * @return True if device context injection is supported, false otherwise.
+     */
+    boolean supportsDeviceContextInjection();
+
+    /**
+     * Injects device context information into the Hardware subsystem.
+     *
+     * @param deviceEnabledContext  The context to inject.
+     * @throws RuntimeException if injection is not supported.
+     */
+    void injectDeviceContext(in int deviceEnabledContext);
+}
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
new file mode 100644
index 0000000..a11d8ab
--- /dev/null
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.location.Location;
+
+/**
+ * Fused Location hardware event sink interface.
+ * This interface defines the set of events that the FusedLocationHardware provides.
+ *
+ * @hide
+ */
+interface IFusedLocationHardwareSink {
+    /**
+     * Event generated when a batch of location information is available.
+     *
+     * @param locations     The batch of location information available.
+     */
+    void onLocationAvailable(in Location[] locations);
+
+    /**
+     * Event generated from FLP HAL to provide diagnostic data to the platform.
+     *
+     * @param data      The diagnostic data provided by FLP HAL.
+     */
+    void onDiagnosticDataAvailable(in String data);
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 6900070..8900166 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.location;
 
+import android.location.IFusedGeofenceHardware;
 import android.location.IGpsGeofenceHardware;
 import android.hardware.location.IGeofenceHardwareCallback;
 import android.hardware.location.IGeofenceHardwareMonitorCallback;
@@ -23,6 +24,7 @@
 /** @hide */
 interface IGeofenceHardware {
     void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
+    void setFusedGeofenceHardware(in IFusedGeofenceHardware service);
     int[] getMonitoringTypes();
     int getStatusOfMonitoringType(int monitoringType);
     boolean addCircularFence(int id,  int monitoringType, double lat, double longitude,
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 9306373..06d8e4a 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -279,6 +279,10 @@
         try {
             InputMethodSession ls = ((IInputMethodSessionWrapper)
                     session).getInternalInputMethodSession();
+            if (ls == null) {
+                Log.w(TAG, "Session is already finished: " + session);
+                return;
+            }
             mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
                     DO_SET_SESSION_ENABLED, enabled ? 1 : 0, ls));
         } catch (ClassCastException e) {
@@ -291,6 +295,10 @@
         try {
             InputMethodSession ls = ((IInputMethodSessionWrapper)
                     session).getInternalInputMethodSession();
+            if (ls == null) {
+                Log.w(TAG, "Session is already finished: " + session);
+                return;
+            }
             mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REVOKE_SESSION, ls));
         } catch (ClassCastException e) {
             Log.w(TAG, "Incoming session not of correct type: " + session, e);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4881d14..9319d4a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -381,7 +381,6 @@
             if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
                     + " ic=" + mInputConnection);
             onUnbindInput();
-            mInputStarted = false;
             mInputBinding = null;
             mInputConnection = null;
         }
@@ -719,7 +718,7 @@
         super.onDestroy();
         mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
                 mInsetsComputer);
-        finishViews();
+        doFinishInput();
         if (mWindowAdded) {
             // Disable exit animation for the current IME window
             // to avoid the race condition between the exit and enter animations
@@ -1651,6 +1650,11 @@
      * the text.  This is called whether or not the input method has requested
      * extracted text updates, although if so it will not receive this call
      * if the extracted text has changed as well.
+     *
+     * <p>Be careful about changing the text in reaction to this call with
+     * methods such as setComposingText, commitText or
+     * deleteSurroundingText. If the cursor moves as a result, this method
+     * will be called again, which may result in an infinite loop.
      * 
      * <p>The default implementation takes care of updating the cursor in
      * the extract text, if it is being shown.
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index 1165281..476fefe 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -57,6 +57,10 @@
         mLinkCapabilities = new LinkCapabilities();
     }
 
+    protected BaseNetworkStateTracker() {
+        // By default, let the sub classes construct everything
+    }
+
     @Deprecated
     protected Handler getTargetHandler() {
         return mTarget;
@@ -73,35 +77,47 @@
     }
 
     @Override
-    public final void startMonitoring(Context context, Handler target) {
+    public void startMonitoring(Context context, Handler target) {
         mContext = Preconditions.checkNotNull(context);
         mTarget = Preconditions.checkNotNull(target);
         startMonitoringInternal();
     }
 
-    protected abstract void startMonitoringInternal();
+    protected void startMonitoringInternal() {
+
+    }
 
     @Override
-    public final NetworkInfo getNetworkInfo() {
+    public NetworkInfo getNetworkInfo() {
         return new NetworkInfo(mNetworkInfo);
     }
 
     @Override
-    public final LinkProperties getLinkProperties() {
+    public LinkProperties getLinkProperties() {
         return new LinkProperties(mLinkProperties);
     }
 
     @Override
-    public final LinkCapabilities getLinkCapabilities() {
+    public LinkCapabilities getLinkCapabilities() {
         return new LinkCapabilities(mLinkCapabilities);
     }
 
     @Override
+    public LinkQualityInfo getLinkQualityInfo() {
+        return null;
+    }
+
+    @Override
     public void captivePortalCheckComplete() {
         // not implemented
     }
 
     @Override
+    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+        // not implemented
+    }
+
+    @Override
     public boolean setRadio(boolean turnOn) {
         // Base tracker doesn't handle radios
         return true;
@@ -171,4 +187,23 @@
     public void supplyMessenger(Messenger messenger) {
         // not supported on this network
     }
+
+    @Override
+    public String getNetworkInterfaceName() {
+        if (mLinkProperties != null) {
+            return mLinkProperties.getInterfaceName();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
+        // nothing to do
+    }
+
+    @Override
+    public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
+        // nothing to do
+    }
 }
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index 21995c0..01977cd 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -16,23 +16,29 @@
 
 package android.net;
 
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
 import android.os.Handler;
-import android.os.UserHandle;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.provider.Settings;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityWcdma;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.util.State;
@@ -42,30 +48,45 @@
 import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.Inet4Address;
+import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.net.UnknownHostException;
-
-import com.android.internal.R;
+import java.util.List;
 
 /**
  * This class allows captive portal detection on a network.
  * @hide
  */
 public class CaptivePortalTracker extends StateMachine {
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
     private static final String TAG = "CaptivePortalTracker";
 
     private static final String DEFAULT_SERVER = "clients3.google.com";
-    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
 
     private static final int SOCKET_TIMEOUT_MS = 10000;
 
+    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
+            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
+    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
+    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
+    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
+    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
+    public static final String EXTRA_CELL_ID = "extra_cellid";
+    public static final String EXTRA_SSID = "extra_ssid";
+    public static final String EXTRA_BSSID = "extra_bssid";
+    /** real time since boot */
+    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
+    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
+
+    private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
+            "android.permission.ACCESS_NETWORK_CONDITIONS";
+
     private String mServer;
     private String mUrl;
-    private boolean mNotificationShown = false;
     private boolean mIsCaptivePortalCheckEnabled = false;
     private IConnectivityManager mConnService;
     private TelephonyManager mTelephonyManager;
+    private WifiManager mWifiManager;
     private Context mContext;
     private NetworkInfo mNetworkInfo;
 
@@ -92,6 +113,7 @@
         mContext = context;
         mConnService = cs;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
         mProvisioningObserver = new ProvisioningObserver();
 
         IntentFilter filter = new IntentFilter();
@@ -159,12 +181,12 @@
     private class DefaultState extends State {
         @Override
         public void enter() {
-            if (DBG) log(getName() + "\n");
+            setNotificationOff();
         }
 
         @Override
         public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString() + "\n");
+            if (DBG) log(getName() + message.toString());
             switch (message.what) {
                 case CMD_DETECT_PORTAL:
                     NetworkInfo info = (NetworkInfo) message.obj;
@@ -186,23 +208,24 @@
     private class NoActiveNetworkState extends State {
         @Override
         public void enter() {
-            if (DBG) log(getName() + "\n");
             mNetworkInfo = null;
-            /* Clear any previous notification */
-            setNotificationVisible(false);
         }
 
         @Override
         public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString() + "\n");
+            if (DBG) log(getName() + message.toString());
             InetAddress server;
             NetworkInfo info;
             switch (message.what) {
                 case CMD_CONNECTIVITY_CHANGE:
                     info = (NetworkInfo) message.obj;
-                    if (info.isConnected() && isActiveNetwork(info)) {
-                        mNetworkInfo = info;
-                        transitionTo(mDelayedCaptiveCheckState);
+                    if (info.getType() == ConnectivityManager.TYPE_WIFI) {
+                        if (info.isConnected() && isActiveNetwork(info)) {
+                            mNetworkInfo = info;
+                            transitionTo(mDelayedCaptiveCheckState);
+                        }
+                    } else {
+                        log(getName() + " not a wifi connectivity change, ignore");
                     }
                     break;
                 default:
@@ -215,7 +238,7 @@
     private class ActiveNetworkState extends State {
         @Override
         public void enter() {
-            if (DBG) log(getName() + "\n");
+            setNotificationOff();
         }
 
         @Override
@@ -248,7 +271,6 @@
     private class DelayedCaptiveCheckState extends State {
         @Override
         public void enter() {
-            if (DBG) log(getName() + "\n");
             Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
             if (mDeviceProvisioned) {
                 sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
@@ -259,7 +281,7 @@
 
         @Override
         public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString() + "\n");
+            if (DBG) log(getName() + message.toString());
             switch (message.what) {
                 case CMD_DELAYED_CAPTIVE_CHECK:
                     if (message.arg1 == mDelayedCheckToken) {
@@ -270,11 +292,17 @@
                         } else {
                             if (DBG) log("Not captive network " + mNetworkInfo);
                         }
+                        notifyPortalCheckCompleted(mNetworkInfo, captive);
                         if (mDeviceProvisioned) {
                             if (captive) {
                                 // Setup Wizard will assist the user in connecting to a captive
                                 // portal, so make the notification visible unless during setup
-                                setNotificationVisible(true);
+                                try {
+                                    mConnService.setProvisioningNotificationVisible(true,
+                                        mNetworkInfo.getType(), mNetworkInfo.getExtraInfo(), mUrl);
+                                } catch(RemoteException e) {
+                                    e.printStackTrace();
+                                }
                             }
                         } else {
                             Intent intent = new Intent(
@@ -300,12 +328,26 @@
             return;
         }
         try {
+            if (DBG) log("notifyPortalCheckComplete: ni=" + info);
             mConnService.captivePortalCheckComplete(info);
         } catch(RemoteException e) {
             e.printStackTrace();
         }
     }
 
+    private void notifyPortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
+        if (info == null) {
+            loge("notifyPortalCheckComplete on null");
+            return;
+        }
+        try {
+            if (DBG) log("notifyPortalCheckCompleted: captive=" + isCaptivePortal + " ni=" + info);
+            mConnService.captivePortalCheckCompleted(info, isCaptivePortal);
+        } catch(RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
     private boolean isActiveNetwork(NetworkInfo info) {
         try {
             NetworkInfo active = mConnService.getActiveNetworkInfo();
@@ -318,8 +360,18 @@
         return false;
     }
 
+    private void setNotificationOff() {
+        try {
+            mConnService.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_NONE,
+                    null, null);
+        } catch (RemoteException e) {
+            log("setNotificationOff: " + e);
+        }
+    }
+
     /**
-     * Do a URL fetch on a known server to see if we get the data we expect
+     * Do a URL fetch on a known server to see if we get the data we expect.
+     * Measure the response time and broadcast that.
      */
     private boolean isCaptivePortal(InetAddress server) {
         HttpURLConnection urlConnection = null;
@@ -327,6 +379,7 @@
 
         mUrl = "http://" + server.getHostAddress() + "/generate_204";
         if (DBG) log("Checking " + mUrl);
+        long requestTimestamp = -1;
         try {
             URL url = new URL(mUrl);
             urlConnection = (HttpURLConnection) url.openConnection();
@@ -334,11 +387,29 @@
             urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setUseCaches(false);
+
+            // Time how long it takes to get a response to our request
+            requestTimestamp = SystemClock.elapsedRealtime();
+
             urlConnection.getInputStream();
+
+            // Time how long it takes to get a response to our request
+            long responseTimestamp = SystemClock.elapsedRealtime();
+
             // we got a valid response, but not from the real google
-            return urlConnection.getResponseCode() != 204;
+            int rspCode = urlConnection.getResponseCode();
+            boolean isCaptivePortal = rspCode != 204;
+
+            sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal,
+                    requestTimestamp, responseTimestamp);
+
+            if (DBG) log("isCaptivePortal: ret=" + isCaptivePortal + " rspCode=" + rspCode);
+            return isCaptivePortal;
         } catch (IOException e) {
             if (DBG) log("Probably not a portal: exception " + e);
+            if (requestTimestamp != -1) {
+                sendFailedCaptivePortalCheckBroadcast(requestTimestamp);
+            } // else something went wrong with setting up the urlConnection
             return false;
         } finally {
             if (urlConnection != null) {
@@ -352,66 +423,91 @@
         try {
             inetAddress = InetAddress.getAllByName(hostname);
         } catch (UnknownHostException e) {
+            sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
             return null;
         }
 
         for (InetAddress a : inetAddress) {
             if (a instanceof Inet4Address) return a;
         }
+
+        sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
         return null;
     }
 
-    private void setNotificationVisible(boolean visible) {
-        // if it should be hidden and it is already hidden, then noop
-        if (!visible && !mNotificationShown) {
+    private void sendFailedCaptivePortalCheckBroadcast(long requestTimestampMs) {
+        sendNetworkConditionsBroadcast(false /* response received */, false /* ignored */,
+                requestTimestampMs, 0 /* ignored */);
+    }
+
+    /**
+     * @param responseReceived - whether or not we received a valid HTTP response to our request.
+     * If false, isCaptivePortal and responseTimestampMs are ignored
+     */
+    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
+            long requestTimestampMs, long responseTimestampMs) {
+        if (Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
+            if (DBG) log("Don't send network conditions - lacking user consent.");
             return;
         }
 
-        Resources r = Resources.getSystem();
-        NotificationManager notificationManager = (NotificationManager) mContext
-            .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        if (visible) {
-            CharSequence title;
-            CharSequence details;
-            int icon;
-            switch (mNetworkInfo.getType()) {
-                case ConnectivityManager.TYPE_WIFI:
-                    title = r.getString(R.string.wifi_available_sign_in, 0);
-                    details = r.getString(R.string.network_available_sign_in_detailed,
-                            mNetworkInfo.getExtraInfo());
-                    icon = R.drawable.stat_notify_wifi_in_range;
-                    break;
-                case ConnectivityManager.TYPE_MOBILE:
-                    title = r.getString(R.string.network_available_sign_in, 0);
-                    // TODO: Change this to pull from NetworkInfo once a printable
-                    // name has been added to it
-                    details = mTelephonyManager.getNetworkOperatorName();
-                    icon = R.drawable.stat_notify_rssi_in_range;
-                    break;
-                default:
-                    title = r.getString(R.string.network_available_sign_in, 0);
-                    details = r.getString(R.string.network_available_sign_in_detailed,
-                            mNetworkInfo.getExtraInfo());
-                    icon = R.drawable.stat_notify_rssi_in_range;
-                    break;
-            }
-
-            Notification notification = new Notification();
-            notification.when = 0;
-            notification.icon = icon;
-            notification.flags = Notification.FLAG_AUTO_CANCEL;
-            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl));
-            intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
-                    Intent.FLAG_ACTIVITY_NEW_TASK);
-            notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
-            notification.tickerText = title;
-            notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
-
-            notificationManager.notify(NOTIFICATION_ID, 1, notification);
-        } else {
-            notificationManager.cancel(NOTIFICATION_ID, 1);
+        Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
+        switch (mNetworkInfo.getType()) {
+            case ConnectivityManager.TYPE_WIFI:
+                WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
+                if (currentWifiInfo != null) {
+                    latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
+                    latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
+                } else {
+                    if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
+                    return;
+                }
+                break;
+            case ConnectivityManager.TYPE_MOBILE:
+                latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
+                List<CellInfo> info = mTelephonyManager.getAllCellInfo();
+                if (info == null) return;
+                StringBuffer uniqueCellId = new StringBuffer();
+                int numRegisteredCellInfo = 0;
+                for (CellInfo cellInfo : info) {
+                    if (cellInfo.isRegistered()) {
+                        numRegisteredCellInfo++;
+                        if (numRegisteredCellInfo > 1) {
+                            if (DBG) log("more than one registered CellInfo.  Can't " +
+                                    "tell which is active.  Bailing.");
+                            return;
+                        }
+                        if (cellInfo instanceof CellInfoCdma) {
+                            CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else if (cellInfo instanceof CellInfoGsm) {
+                            CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else if (cellInfo instanceof CellInfoLte) {
+                            CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else if (cellInfo instanceof CellInfoWcdma) {
+                            CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else {
+                            if (DBG) logw("Registered cellinfo is unrecognized");
+                            return;
+                        }
+                    }
+                }
+                break;
+            default:
+                return;
         }
-        mNotificationShown = visible;
+        latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkInfo.getType());
+        latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
+        latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
+
+        if (responseReceived) {
+            latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
+            latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
+        }
+        mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS);
     }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 697bde9..c78a973 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -355,11 +355,17 @@
      */
     public static final int TYPE_WIFI_P2P    = 13;
 
-    /** {@hide} */
-    public static final int MAX_RADIO_TYPE   = TYPE_WIFI_P2P;
+    /**
+     * The network to use for initially attaching to the network
+     * {@hide}
+     */
+    public static final int TYPE_MOBILE_IA = 14;
 
     /** {@hide} */
-    public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P;
+    public static final int MAX_RADIO_TYPE   = TYPE_MOBILE_IA;
+
+    /** {@hide} */
+    public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA;
 
     /**
      * If you want to set the default network preference,you can directly
@@ -436,6 +442,8 @@
                 return "MOBILE_CBS";
             case TYPE_WIFI_P2P:
                 return "WIFI_P2P";
+            case TYPE_MOBILE_IA:
+                return "MOBILE_IA";
             default:
                 return Integer.toString(type);
         }
@@ -458,6 +466,39 @@
             case TYPE_MOBILE_FOTA:
             case TYPE_MOBILE_IMS:
             case TYPE_MOBILE_CBS:
+            case TYPE_MOBILE_IA:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Checks if the given network type is backed by a Wi-Fi radio.
+     *
+     * @hide
+     */
+    public static boolean isNetworkTypeWifi(int networkType) {
+        switch (networkType) {
+            case TYPE_WIFI:
+            case TYPE_WIFI_P2P:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Checks if the given network type should be exempt from VPN routing rules
+     *
+     * @hide
+     */
+    public static boolean isNetworkTypeExempt(int networkType) {
+        switch (networkType) {
+            case TYPE_MOBILE_MMS:
+            case TYPE_MOBILE_SUPL:
+            case TYPE_MOBILE_HIPRI:
+            case TYPE_MOBILE_IA:
                 return true;
             default:
                 return false;
@@ -583,6 +624,29 @@
     }
 
     /**
+     * Returns details about the Provisioning or currently active default data network. When
+     * connected, this network is the default route for outgoing connections.
+     * You should always check {@link NetworkInfo#isConnected()} before initiating
+     * network traffic. This may return {@code null} when there is no default
+     * network.
+     *
+     * @return a {@link NetworkInfo} object for the current default network
+     *        or {@code null} if no network default network is currently active
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * {@hide}
+     */
+    public NetworkInfo getProvisioningOrActiveNetworkInfo() {
+        try {
+            return mService.getProvisioningOrActiveNetworkInfo();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns the IP information for the current default network.
      *
      * @return a {@link LinkProperties} object describing the IP info
@@ -1283,6 +1347,25 @@
     }
 
     /**
+     * Signal that the captive portal check on the indicated network
+     * is complete and whether its a captive portal or not.
+     *
+     * @param info the {@link NetworkInfo} object for the networkType
+     *        in question.
+     * @param isCaptivePortal true/false.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
+     * {@hide}
+     */
+    public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
+        try {
+            mService.captivePortalCheckCompleted(info, isCaptivePortal);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Supply the backend messenger for a network tracker
      *
      * @param type NetworkType to set
@@ -1297,70 +1380,26 @@
     }
 
     /**
-     * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
-     */
-
-    /**
-     * No connection was possible to the network.
-     * {@hide}
-     */
-    public static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
-
-    /**
-     * A connection was made to the internet, all is well.
-     * {@hide}
-     */
-    public static final int CMP_RESULT_CODE_CONNECTABLE = 1;
-
-    /**
-     * A connection was made but there was a redirection, we appear to be in walled garden.
-     * This is an indication of a warm sim on a mobile network.
-     * {@hide}
-     */
-    public static final int CMP_RESULT_CODE_REDIRECTED = 2;
-
-    /**
-     * A connection was made but no dns server was available to resolve a name to address.
-     * This is an indication of a warm sim on a mobile network.
+     * Check mobile provisioning.
      *
-     * {@hide}
-     */
-    public static final int CMP_RESULT_CODE_NO_DNS = 3;
-
-    /**
-     * A connection was made but could not open a TCP connection.
-     * This is an indication of a warm sim on a mobile network.
-     * {@hide}
-     */
-    public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4;
-
-    /**
-     * Check mobile provisioning. The resultCode passed to
-     * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above.
-     * This may take a minute or more to complete.
-     *
-     * @param sendNotificaiton, when true a notification will be sent to user.
      * @param suggestedTimeOutMs, timeout in milliseconds
-     * @param resultReceiver needs to  be supplied to receive the result
      *
      * @return time out that will be used, maybe less that suggestedTimeOutMs
      * -1 if an error.
      *
      * {@hide}
      */
-    public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
-            ResultReceiver resultReceiver) {
+    public int checkMobileProvisioning(int suggestedTimeOutMs) {
         int timeOutMs = -1;
         try {
-            timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs,
-                    resultReceiver);
+            timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
         } catch (RemoteException e) {
         }
         return timeOutMs;
     }
 
     /**
-     * Get the carrier provisioning url.
+     * Get the mobile provisioning url.
      * {@hide}
      */
     public String getMobileProvisioningUrl() {
@@ -1370,4 +1409,87 @@
         }
         return null;
     }
+
+    /**
+     * Get the mobile redirected provisioning url.
+     * {@hide}
+     */
+    public String getMobileRedirectedProvisioningUrl() {
+        try {
+            return mService.getMobileRedirectedProvisioningUrl();
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    /**
+     * get the information about a specific network link
+     * @hide
+     */
+    public LinkQualityInfo getLinkQualityInfo(int networkType) {
+        try {
+            LinkQualityInfo li = mService.getLinkQualityInfo(networkType);
+            return li;
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * get the information of currently active network link
+     * @hide
+     */
+    public LinkQualityInfo getActiveLinkQualityInfo() {
+        try {
+            LinkQualityInfo li = mService.getActiveLinkQualityInfo();
+            return li;
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * get the information of all network links
+     * @hide
+     */
+    public LinkQualityInfo[] getAllLinkQualityInfo() {
+        try {
+            LinkQualityInfo[] li = mService.getAllLinkQualityInfo();
+            return li;
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Set sign in error notification to visible or in visible
+     *
+     * @param visible
+     * @param networkType
+     *
+     * {@hide}
+     */
+    public void setProvisioningNotificationVisible(boolean visible, int networkType,
+            String extraInfo, String url) {
+        try {
+            mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Set the value for enabling/disabling airplane mode
+     *
+     * @param enable whether to enable airplane mode or not
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
+     * @hide
+     */
+    public void setAirplaneMode(boolean enable) {
+        try {
+            mService.setAirplaneMode(enable);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index 1ebf393..5151a04 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -374,7 +374,7 @@
                 //Do it a bit earlier than half the lease duration time
                 //to beat the native DHCP client and avoid extra packets
                 //48% for one hour lease time = 29 minutes
-                mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                         SystemClock.elapsedRealtime() +
                         leaseDuration * 480, //in milliseconds
                         mDhcpRenewalIntent);
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index 15a81f3..51a1191 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -29,18 +29,14 @@
  *
  * {@hide}
  */
-public class DummyDataStateTracker implements NetworkStateTracker {
+public class DummyDataStateTracker extends BaseNetworkStateTracker {
 
     private static final String TAG = "DummyDataStateTracker";
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    private NetworkInfo mNetworkInfo;
     private boolean mTeardownRequested = false;
     private Handler mTarget;
-    private Context mContext;
-    private LinkProperties mLinkProperties;
-    private LinkCapabilities mLinkCapabilities;
     private boolean mPrivateDnsRouteSet = false;
     private boolean mDefaultRouteSet = false;
 
@@ -120,10 +116,16 @@
         return true;
     }
 
+    @Override
     public void captivePortalCheckComplete() {
         // not implemented
     }
 
+    @Override
+    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+        // not implemented
+    }
+
     /**
      * Record the detailed state of a network, and if it is a
      * change from the previous state, send a notification to
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 7b803a8..501484c 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -27,6 +27,8 @@
 import android.os.ServiceManager;
 import android.util.Log;
 
+import com.android.server.net.BaseNetworkObserver;
+
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -36,7 +38,7 @@
  * ConnectivityService.
  * @hide
  */
-public class EthernetDataTracker implements NetworkStateTracker {
+public class EthernetDataTracker extends BaseNetworkStateTracker {
     private static final String NETWORKTYPE = "ETHERNET";
     private static final String TAG = "Ethernet";
 
@@ -46,15 +48,11 @@
     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
 
     private static boolean mLinkUp;
-    private LinkProperties mLinkProperties;
-    private LinkCapabilities mLinkCapabilities;
-    private NetworkInfo mNetworkInfo;
     private InterfaceObserver mInterfaceObserver;
     private String mHwAddr;
 
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
-    private Context mContext;
 
     private static EthernetDataTracker sInstance;
     private static String sIfaceMatch = "";
@@ -62,7 +60,7 @@
 
     private INetworkManagementService mNMService;
 
-    private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
+    private static class InterfaceObserver extends BaseNetworkObserver {
         private EthernetDataTracker mTracker;
 
         InterfaceObserver(EthernetDataTracker tracker) {
@@ -70,10 +68,12 @@
             mTracker = tracker;
         }
 
+        @Override
         public void interfaceStatusChanged(String iface, boolean up) {
             Log.d(TAG, "Interface status changed: " + iface + (up ? "up" : "down"));
         }
 
+        @Override
         public void interfaceLinkStateChanged(String iface, boolean up) {
             if (mIface.equals(iface)) {
                 Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
@@ -89,21 +89,15 @@
             }
         }
 
+        @Override
         public void interfaceAdded(String iface) {
             mTracker.interfaceAdded(iface);
         }
 
+        @Override
         public void interfaceRemoved(String iface) {
             mTracker.interfaceRemoved(iface);
         }
-
-        public void limitReached(String limitName, String iface) {
-            // Ignored.
-        }
-
-        public void interfaceClassDataActivityChanged(String label, boolean active) {
-            // Ignored.
-        }
     }
 
     private EthernetDataTracker() {
@@ -280,6 +274,11 @@
         // not implemented
     }
 
+    @Override
+    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+        // not implemented
+    }
+
     /**
      * Turn the wireless radio off for a network.
      * @param turnOn {@code true} to turn the radio on, {@code false}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4600c1a..c1da2e3 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.net.LinkQualityInfo;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.NetworkQuotaInfo;
@@ -37,6 +38,9 @@
 /** {@hide} */
 interface IConnectivityManager
 {
+    // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h
+    void markSocketAsUser(in ParcelFileDescriptor socket, int uid);
+
     void setNetworkPreference(int pref);
 
     int getNetworkPreference();
@@ -46,6 +50,8 @@
     NetworkInfo getNetworkInfo(int networkType);
     NetworkInfo[] getAllNetworkInfo();
 
+    NetworkInfo getProvisioningOrActiveNetworkInfo();
+
     boolean isNetworkSupported(int networkType);
 
     LinkProperties getActiveLinkProperties();
@@ -87,12 +93,6 @@
 
     String[] getTetheredIfaces();
 
-    /**
-     * Return list of interface pairs that are actively tethered.  Even indexes are
-     * remote interface, and odd indexes are corresponding local interfaces.
-     */
-    String[] getTetheredIfacePairs();
-
     String[] getTetheringErroredIfaces();
 
     String[] getTetherableUsbRegexs();
@@ -121,6 +121,8 @@
 
     ParcelFileDescriptor establishVpn(in VpnConfig config);
 
+    VpnConfig getVpnConfig();
+
     void startLegacyVpn(in VpnProfile profile);
 
     LegacyVpnInfo getLegacyVpnInfo();
@@ -129,11 +131,25 @@
 
     void captivePortalCheckComplete(in NetworkInfo info);
 
+    void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal);
+
     void supplyMessenger(int networkType, in Messenger messenger);
 
     int findConnectionTypeForIface(in String iface);
 
-    int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
+    int checkMobileProvisioning(int suggestedTimeOutMs);
 
     String getMobileProvisioningUrl();
+
+    String getMobileRedirectedProvisioningUrl();
+
+    LinkQualityInfo getLinkQualityInfo(int networkType);
+
+    LinkQualityInfo getActiveLinkQualityInfo();
+
+    LinkQualityInfo[] getAllLinkQualityInfo();
+
+    void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
+
+    void setAirplaneMode(boolean enable);
 }
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index 6f4dd5f..b76e4c2 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -53,6 +53,27 @@
      */
     void interfaceRemoved(String iface);
 
+
+    /**
+     * An interface address has been added or updated
+     *
+     * @param address The address.
+     * @param iface The interface.
+     * @param flags The address flags.
+     * @param scope The address scope.
+     */
+    void addressUpdated(String address, String iface, int flags, int scope);
+
+    /**
+     * An interface address has been removed
+     *
+     * @param address The address.
+     * @param iface The interface.
+     * @param flags The address flags.
+     * @param scope The address scope.
+     */
+    void addressRemoved(String address, String iface, int flags, int scope);
+
     /**
      * A networking quota limit has been reached. The quota might not
      * be specific to an interface.
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index f6a114c..a390add 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -32,27 +32,56 @@
     /**
      * IPv4 or IPv6 address.
      */
-    private final InetAddress address;
+    private InetAddress address;
 
     /**
      * Network prefix length
      */
-    private final int prefixLength;
+    private int prefixLength;
 
-    public LinkAddress(InetAddress address, int prefixLength) {
+    private void init(InetAddress address, int prefixLength) {
         if (address == null || prefixLength < 0 ||
                 ((address instanceof Inet4Address) && prefixLength > 32) ||
                 (prefixLength > 128)) {
             throw new IllegalArgumentException("Bad LinkAddress params " + address +
-                    prefixLength);
+                    "/" + prefixLength);
         }
         this.address = address;
         this.prefixLength = prefixLength;
     }
 
+    public LinkAddress(InetAddress address, int prefixLength) {
+        init(address, prefixLength);
+    }
+
     public LinkAddress(InterfaceAddress interfaceAddress) {
-        this.address = interfaceAddress.getAddress();
-        this.prefixLength = interfaceAddress.getNetworkPrefixLength();
+        init(interfaceAddress.getAddress(),
+             interfaceAddress.getNetworkPrefixLength());
+    }
+
+    /**
+     * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
+     * "2001:db8::1/64".
+     * @param string The string to parse.
+     */
+    public LinkAddress(String address) {
+        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);
     }
 
     @Override
diff --git a/core/java/android/net/LinkProperties.aidl b/core/java/android/net/LinkProperties.aidl
index 9cd06d5..3cb9525 100644
--- a/core/java/android/net/LinkProperties.aidl
+++ b/core/java/android/net/LinkProperties.aidl
@@ -18,4 +18,3 @@
 package android.net;
 
 parcelable LinkProperties;
-
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 75f8b59..b4d07a1 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -23,6 +23,7 @@
 
 import java.net.InetAddress;
 import java.net.Inet4Address;
+import java.net.Inet6Address;
 
 import java.net.UnknownHostException;
 import java.util.ArrayList;
@@ -65,6 +66,7 @@
     private String mDomains;
     private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
     private ProxyProperties mHttpProxy;
+    private int mMtu;
 
     // Stores the properties of links that are "stacked" above this link.
     // Indexed by interface name to allow modification and to prevent duplicates being added.
@@ -103,6 +105,7 @@
             for (LinkProperties l: source.mStackedLinks.values()) {
                 addStackedLink(l);
             }
+            setMtu(source.getMtu());
         }
     }
 
@@ -128,6 +131,9 @@
         return interfaceNames;
     }
 
+    /**
+     * Returns all the addresses on this link.
+     */
     public Collection<InetAddress> getAddresses() {
         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
         for (LinkAddress linkAddress : mLinkAddresses) {
@@ -136,14 +142,73 @@
         return Collections.unmodifiableCollection(addresses);
     }
 
-    public void addLinkAddress(LinkAddress address) {
-        if (address != null) mLinkAddresses.add(address);
+    /**
+     * Returns all the addresses on this link and all the links stacked above it.
+     */
+    public Collection<InetAddress> getAllAddresses() {
+        Collection<InetAddress> addresses = new ArrayList<InetAddress>();
+        for (LinkAddress linkAddress : mLinkAddresses) {
+            addresses.add(linkAddress.getAddress());
+        }
+        for (LinkProperties stacked: mStackedLinks.values()) {
+            addresses.addAll(stacked.getAllAddresses());
+        }
+        return addresses;
     }
 
+    /**
+     * Adds a link address if it does not exist, or update it if it does.
+     * @param address The {@code LinkAddress} to add.
+     * @return true if the address was added, false if it already existed.
+     */
+    public boolean addLinkAddress(LinkAddress address) {
+        // TODO: when the LinkAddress has other attributes beyond the
+        // address and the prefix length, update them here.
+        if (address != null && !mLinkAddresses.contains(address)) {
+            mLinkAddresses.add(address);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes a link address.
+     * @param address The {@code LinkAddress} to remove.
+     * @return true if the address was removed, false if it did not exist.
+     */
+    public boolean removeLinkAddress(LinkAddress toRemove) {
+        return mLinkAddresses.remove(toRemove);
+    }
+
+    /**
+     * Returns all the addresses on this link.
+     */
     public Collection<LinkAddress> getLinkAddresses() {
         return Collections.unmodifiableCollection(mLinkAddresses);
     }
 
+    /**
+     * Returns all the addresses on this link and all the links stacked above it.
+     */
+    public Collection<LinkAddress> getAllLinkAddresses() {
+        Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
+        addresses.addAll(mLinkAddresses);
+        for (LinkProperties stacked: mStackedLinks.values()) {
+            addresses.addAll(stacked.getAllLinkAddresses());
+        }
+        return addresses;
+    }
+
+    /**
+     * Replaces the LinkAddresses on this link with the given collection of addresses.
+     */
+    public void setLinkAddresses(Collection<LinkAddress> addresses) {
+        mLinkAddresses.clear();
+        for (LinkAddress address: addresses) {
+            addLinkAddress(address);
+        }
+    }
+
     public void addDns(InetAddress dns) {
         if (dns != null) mDnses.add(dns);
     }
@@ -160,6 +225,14 @@
         mDomains = domains;
     }
 
+    public void setMtu(int mtu) {
+        mMtu = mtu;
+    }
+
+    public int getMtu() {
+        return mMtu;
+    }
+
     private RouteInfo routeWithInterface(RouteInfo route) {
         return new RouteInfo(
             route.getDestination(),
@@ -213,11 +286,14 @@
      * of stacked links. If link is null, nothing changes.
      *
      * @param link The link to add.
+     * @return true if the link was stacked, false otherwise.
      */
-    public void addStackedLink(LinkProperties link) {
+    public boolean addStackedLink(LinkProperties link) {
         if (link != null && link.getInterfaceName() != null) {
             mStackedLinks.put(link.getInterfaceName(), link);
+            return true;
         }
+        return false;
     }
 
     /**
@@ -226,12 +302,15 @@
      * If there a stacked link with the same interfacename as link, it is
      * removed. Otherwise, nothing changes.
      *
-     * @param link The link to add.
+     * @param link The link to remove.
+     * @return true if the link was removed, false otherwise.
      */
-    public void removeStackedLink(LinkProperties link) {
+    public boolean removeStackedLink(LinkProperties link) {
         if (link != null && link.getInterfaceName() != null) {
-            mStackedLinks.remove(link.getInterfaceName());
+            LinkProperties removed = mStackedLinks.remove(link.getInterfaceName());
+            return removed != null;
         }
+        return false;
     }
 
     /**
@@ -253,6 +332,7 @@
         mRoutes.clear();
         mHttpProxy = null;
         mStackedLinks.clear();
+        mMtu = 0;
     }
 
     /**
@@ -277,6 +357,8 @@
 
         String domainName = "Domains: " + mDomains;
 
+        String mtu = "MTU: " + mMtu;
+
         String routes = " Routes: [";
         for (RouteInfo route : mRoutes) routes += route.toString() + ",";
         routes += "] ";
@@ -290,7 +372,8 @@
             }
             stacked += "] ";
         }
-        return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}";
+        return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu
+            + proxy + stacked + "}";
     }
 
     /**
@@ -308,6 +391,20 @@
     }
 
     /**
+     * Returns true if this link has an IPv6 address.
+     *
+     * @return {@code true} if there is an IPv6 address, {@code false} otherwise.
+     */
+    public boolean hasIPv6Address() {
+        for (LinkAddress address : mLinkAddresses) {
+          if (address.getAddress() instanceof Inet6Address) {
+            return true;
+          }
+        }
+        return false;
+    }
+
+    /**
      * Compares this {@code LinkProperties} interface name against the target
      *
      * @param target LinkProperties to compare.
@@ -391,6 +488,16 @@
         return true;
     }
 
+    /**
+     * Compares this {@code LinkProperties} MTU against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalMtu(LinkProperties target) {
+        return getMtu() == target.getMtu();
+    }
+
     @Override
     /**
      * Compares this {@code LinkProperties} instance against the target
@@ -422,17 +529,16 @@
                 isIdenticalDnses(target) &&
                 isIdenticalRoutes(target) &&
                 isIdenticalHttpProxy(target) &&
-                isIdenticalStackedLinks(target);
+                isIdenticalStackedLinks(target) &&
+                isIdenticalMtu(target);
     }
 
     /**
-     * Return two lists, a list of addresses that would be removed from
-     * mLinkAddresses and a list of addresses that would be added to
-     * mLinkAddress which would then result in target and mLinkAddresses
-     * being the same list.
+     * Compares the addresses in this LinkProperties with another
+     * LinkProperties, examining only addresses on the base link.
      *
-     * @param target is a LinkProperties with the new list of addresses
-     * @return the removed and added lists.
+     * @param target a LinkProperties with the new list of addresses
+     * @return the differences between the addresses.
      */
     public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
         /*
@@ -456,13 +562,11 @@
     }
 
     /**
-     * Return two lists, a list of dns addresses that would be removed from
-     * mDnses and a list of addresses that would be added to
-     * mDnses which would then result in target and mDnses
-     * being the same list.
+     * Compares the DNS addresses in this LinkProperties with another
+     * LinkProperties, examining only DNS addresses on the base link.
      *
-     * @param target is a LinkProperties with the new list of dns addresses
-     * @return the removed and added lists.
+     * @param target a LinkProperties with the new list of dns addresses
+     * @return the differences between the DNS addresses.
      */
     public CompareResult<InetAddress> compareDnses(LinkProperties target) {
         /*
@@ -487,15 +591,13 @@
     }
 
     /**
-     * Return two lists, a list of routes that would be removed from
-     * mRoutes and a list of routes that would be added to
-     * mRoutes which would then result in target and mRoutes
-     * being the same list.
+     * Compares all routes in this LinkProperties with another LinkProperties,
+     * examining both the the base link and all stacked links.
      *
-     * @param target is a LinkProperties with the new list of routes
-     * @return the removed and added lists.
+     * @param target a LinkProperties with the new list of routes
+     * @return the differences between the routes.
      */
-    public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
+    public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
         /*
          * Duplicate the RouteInfos into removed, we will be removing
          * routes which are common between mRoutes and target
@@ -530,7 +632,8 @@
                 + ((null == mDomains) ? 0 : mDomains.hashCode())
                 + mRoutes.size() * 41
                 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
-                + mStackedLinks.hashCode() * 47);
+                + mStackedLinks.hashCode() * 47)
+                + mMtu * 51;
     }
 
     /**
@@ -548,7 +651,7 @@
             dest.writeByteArray(d.getAddress());
         }
         dest.writeString(mDomains);
-
+        dest.writeInt(mMtu);
         dest.writeInt(mRoutes.size());
         for(RouteInfo route : mRoutes) {
             dest.writeParcelable(route, flags);
@@ -587,6 +690,7 @@
                     } catch (UnknownHostException e) { }
                 }
                 netProp.setDomains(in.readString());
+                netProp.setMtu(in.readInt());
                 addressCount = in.readInt();
                 for (int i=0; i<addressCount; i++) {
                     netProp.addRoute((RouteInfo)in.readParcelable(null));
diff --git a/core/java/android/net/LinkQualityInfo.aidl b/core/java/android/net/LinkQualityInfo.aidl
new file mode 100644
index 0000000..5e072bf
--- /dev/null
+++ b/core/java/android/net/LinkQualityInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.net;
+
+parcelable LinkQualityInfo;
diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java
new file mode 100644
index 0000000..9c8e61d
--- /dev/null
+++ b/core/java/android/net/LinkQualityInfo.java
@@ -0,0 +1,286 @@
+/*
+ * 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 android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  Class that represents useful attributes of generic network links
+ *  such as the upload/download throughput or packet error rate.
+ *  Generally speaking, you should be dealing with instances of
+ *  LinkQualityInfo subclasses, such as {@link android.net.#WifiLinkQualityInfo}
+ *  or {@link android.net.#MobileLinkQualityInfo} which provide additional
+ *  information.
+ *  @hide
+ */
+public class LinkQualityInfo implements Parcelable {
+
+    /**
+     * Represents a value that you can use to test if an integer field is set to a good value
+     */
+    public static final int UNKNOWN_INT = Integer.MAX_VALUE;
+
+    /**
+     * Represents a value that you can use to test if a long field is set to a good value
+     */
+    public static final long UNKNOWN_LONG = Long.MAX_VALUE;
+
+    public static final int NORMALIZED_MIN_SIGNAL_STRENGTH = 0;
+
+    public static final int NORMALIZED_MAX_SIGNAL_STRENGTH = 99;
+
+    public static final int NORMALIZED_SIGNAL_STRENGTH_RANGE =
+            NORMALIZED_MAX_SIGNAL_STRENGTH - NORMALIZED_MIN_SIGNAL_STRENGTH + 1;
+
+    /* Network type as defined by ConnectivityManager */
+    private int mNetworkType = ConnectivityManager.TYPE_NONE;
+
+    private int mNormalizedSignalStrength = UNKNOWN_INT;
+
+    private long mPacketCount = UNKNOWN_LONG;
+    private long mPacketErrorCount = UNKNOWN_LONG;
+    private int mTheoreticalTxBandwidth = UNKNOWN_INT;
+    private int mTheoreticalRxBandwidth = UNKNOWN_INT;
+    private int mTheoreticalLatency = UNKNOWN_INT;
+
+    /* Timestamp when last sample was made available */
+    private long mLastDataSampleTime = UNKNOWN_LONG;
+
+    /* Sample duration in millisecond */
+    private int mDataSampleDuration = UNKNOWN_INT;
+
+    public LinkQualityInfo() {
+
+    }
+
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     */
+
+    protected static final int OBJECT_TYPE_LINK_QUALITY_INFO = 1;
+    protected static final int OBJECT_TYPE_WIFI_LINK_QUALITY_INFO = 2;
+    protected static final int OBJECT_TYPE_MOBILE_LINK_QUALITY_INFO = 3;
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        writeToParcel(dest, flags, OBJECT_TYPE_LINK_QUALITY_INFO);
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(Parcel dest, int flags, int objectType) {
+        dest.writeInt(objectType);
+        dest.writeInt(mNetworkType);
+        dest.writeInt(mNormalizedSignalStrength);
+        dest.writeLong(mPacketCount);
+        dest.writeLong(mPacketErrorCount);
+        dest.writeInt(mTheoreticalTxBandwidth);
+        dest.writeInt(mTheoreticalRxBandwidth);
+        dest.writeInt(mTheoreticalLatency);
+        dest.writeLong(mLastDataSampleTime);
+        dest.writeInt(mDataSampleDuration);
+    }
+
+    /**
+     * @hide
+     */
+    public static final Creator<LinkQualityInfo> CREATOR =
+            new Creator<LinkQualityInfo>() {
+                public LinkQualityInfo createFromParcel(Parcel in) {
+                    int objectType = in.readInt();
+                    if (objectType == OBJECT_TYPE_LINK_QUALITY_INFO) {
+                        LinkQualityInfo li = new LinkQualityInfo();
+                        li.initializeFromParcel(in);
+                        return li;
+                    } else if (objectType == OBJECT_TYPE_WIFI_LINK_QUALITY_INFO) {
+                        return WifiLinkQualityInfo.createFromParcelBody(in);
+                    } else if (objectType == OBJECT_TYPE_MOBILE_LINK_QUALITY_INFO) {
+                        return MobileLinkQualityInfo.createFromParcelBody(in);
+                    } else {
+                        return null;
+                    }
+                }
+
+                public LinkQualityInfo[] newArray(int size) {
+                    return new LinkQualityInfo[size];
+                }
+            };
+
+    /**
+     * @hide
+     */
+    protected void initializeFromParcel(Parcel in) {
+        mNetworkType = in.readInt();
+        mNormalizedSignalStrength = in.readInt();
+        mPacketCount = in.readLong();
+        mPacketErrorCount = in.readLong();
+        mTheoreticalTxBandwidth = in.readInt();
+        mTheoreticalRxBandwidth = in.readInt();
+        mTheoreticalLatency = in.readInt();
+        mLastDataSampleTime = in.readLong();
+        mDataSampleDuration = in.readInt();
+    }
+
+    /**
+     * returns the type of network this link is connected to
+     * @return network type as defined by {@link android.net.ConnectivityManager} or
+     * {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * @hide
+     */
+    public void setNetworkType(int networkType) {
+        mNetworkType = networkType;
+    }
+
+    /**
+     * returns the signal strength normalized across multiple types of networks
+     * @return an integer value from 0 - 99 or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getNormalizedSignalStrength() {
+        return mNormalizedSignalStrength;
+    }
+
+    /**
+     * @hide
+     */
+    public void setNormalizedSignalStrength(int normalizedSignalStrength) {
+        mNormalizedSignalStrength = normalizedSignalStrength;
+    }
+
+    /**
+     * returns the total number of packets sent or received in sample duration
+     * @return number of packets or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+     */
+    public long getPacketCount() {
+        return mPacketCount;
+    }
+
+    /**
+     * @hide
+     */
+    public void setPacketCount(long packetCount) {
+        mPacketCount = packetCount;
+    }
+
+    /**
+     * returns the total number of packets errors encountered in sample duration
+     * @return number of errors or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+     */
+    public long getPacketErrorCount() {
+        return mPacketErrorCount;
+    }
+
+    /**
+     * @hide
+     */
+    public void setPacketErrorCount(long packetErrorCount) {
+        mPacketErrorCount = packetErrorCount;
+    }
+
+    /**
+     * returns the theoretical upload bandwidth of this network
+     * @return bandwidth in Kbps or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getTheoreticalTxBandwidth() {
+        return mTheoreticalTxBandwidth;
+    }
+
+    /**
+     * @hide
+     */
+    public void setTheoreticalTxBandwidth(int theoreticalTxBandwidth) {
+        mTheoreticalTxBandwidth = theoreticalTxBandwidth;
+    }
+
+    /**
+     * returns the theoretical download bandwidth of this network
+     * @return bandwidth in Kbps or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getTheoreticalRxBandwidth() {
+        return mTheoreticalRxBandwidth;
+    }
+
+    /**
+     * @hide
+     */
+    public void setTheoreticalRxBandwidth(int theoreticalRxBandwidth) {
+        mTheoreticalRxBandwidth = theoreticalRxBandwidth;
+    }
+
+    /**
+     * returns the theoretical latency of this network
+     * @return latency in milliseconds or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getTheoreticalLatency() {
+        return mTheoreticalLatency;
+    }
+
+    /**
+     * @hide
+     */
+    public void setTheoreticalLatency(int theoreticalLatency) {
+        mTheoreticalLatency = theoreticalLatency;
+    }
+
+    /**
+     * returns the time stamp of the last sample
+     * @return milliseconds elapsed since start and sample time or
+     * {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+     */
+    public long getLastDataSampleTime() {
+        return mLastDataSampleTime;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLastDataSampleTime(long lastDataSampleTime) {
+        mLastDataSampleTime = lastDataSampleTime;
+    }
+
+    /**
+     * returns the sample duration used
+     * @return duration in milliseconds or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getDataSampleDuration() {
+        return mDataSampleDuration;
+    }
+
+    /**
+     * @hide
+     */
+    public void setDataSampleDuration(int dataSampleDuration) {
+        mDataSampleDuration = dataSampleDuration;
+    }
+}
diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java
index 2b93fc2..a36203b 100644
--- a/core/java/android/net/LocalServerSocket.java
+++ b/core/java/android/net/LocalServerSocket.java
@@ -46,7 +46,7 @@
     {
         impl = new LocalSocketImpl();
 
-        impl.create(true);
+        impl.create(LocalSocket.SOCKET_STREAM);
 
         localAddress = new LocalSocketAddress(name);
         impl.bind(localAddress);
@@ -93,7 +93,7 @@
 
         impl.accept (acceptedImpl);
 
-        return new LocalSocket(acceptedImpl);
+        return new LocalSocket(acceptedImpl, LocalSocket.SOCKET_UNKNOWN);
     }
 
     /**
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index 14a8094..31bc20b 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -34,21 +34,42 @@
     private LocalSocketAddress localAddress;
     private boolean isBound;
     private boolean isConnected;
+    private final int sockType;
+
+    /** unknown socket type (used for constructor with existing file descriptor) */
+    /* package */ static final int SOCKET_UNKNOWN = 0;
+    /** Datagram socket type */
+    public static final int SOCKET_DGRAM = 1;
+    /** Stream socket type */
+    public static final int SOCKET_STREAM = 2;
+    /** Sequential packet socket type */
+    public static final int SOCKET_SEQPACKET = 3;
 
     /**
      * Creates a AF_LOCAL/UNIX domain stream socket.
      */
     public LocalSocket() {
-        this(new LocalSocketImpl());
+        this(SOCKET_STREAM);
+    }
+
+    /**
+     * Creates a AF_LOCAL/UNIX domain stream socket with given socket type
+     *
+     * @param sockType either {@link #SOCKET_DGRAM}, {@link #SOCKET_STREAM}
+     * or {@link #SOCKET_SEQPACKET}
+     */
+    public LocalSocket(int sockType) {
+        this(new LocalSocketImpl(), sockType);
         isBound = false;
         isConnected = false;
     }
+
     /**
      * Creates a AF_LOCAL/UNIX domain stream socket with FileDescriptor.
      * @hide
      */
     public LocalSocket(FileDescriptor fd) throws IOException {
-        this(new LocalSocketImpl(fd));
+        this(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
         isBound = true;
         isConnected = true;
     }
@@ -57,8 +78,9 @@
      * for use with AndroidServerSocket
      * @param impl a SocketImpl
      */
-    /*package*/ LocalSocket(LocalSocketImpl impl) {
+    /*package*/ LocalSocket(LocalSocketImpl impl, int sockType) {
         this.impl = impl;
+        this.sockType = sockType;
         this.isConnected = false;
         this.isBound = false;
     }
@@ -81,7 +103,7 @@
             synchronized (this) {
                 if (!implCreated) {
                     try {
-                        impl.create(true);
+                        impl.create(sockType);
                     } finally {
                         implCreated = true;
                     }
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 3b43c36..b2ee50a 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -22,6 +22,10 @@
 import java.io.FileDescriptor;
 import java.net.SocketOptions;
 
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.OsConstants;
+
 /**
  * Socket implementation used for android.net.LocalSocket and
  * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
@@ -35,6 +39,8 @@
 
     /** null if closed or not yet created */
     private FileDescriptor fd;
+    /** whether fd is created internally */
+    private boolean mFdCreatedInternally;
 
     // These fields are accessed by native code;
     /** file descriptor array received during a previous read */
@@ -159,7 +165,6 @@
 
     private native int pending_native(FileDescriptor fd) throws IOException;
     private native int available_native(FileDescriptor fd) throws IOException;
-    private native void close_native(FileDescriptor fd) throws IOException;
     private native int read_native(FileDescriptor fd) throws IOException;
     private native int readba_native(byte[] b, int off, int len,
             FileDescriptor fd) throws IOException;
@@ -171,8 +176,6 @@
             int namespace) throws IOException;
     private native void bindLocal(FileDescriptor fd, String name, int namespace)
             throws IOException;
-    private native FileDescriptor create_native(boolean stream)
-            throws IOException;
     private native void listen_native(FileDescriptor fd, int backlog)
             throws IOException;
     private native void shutdown(FileDescriptor fd, boolean shutdownInput);
@@ -222,15 +225,34 @@
     /**
      * Creates a socket in the underlying OS.
      *
-     * @param stream true if this should be a stream socket, false for
-     * datagram.
+     * @param sockType either {@link LocalSocket#SOCKET_DGRAM}, {@link LocalSocket#SOCKET_STREAM}
+     * or {@link LocalSocket#SOCKET_SEQPACKET}
      * @throws IOException
      */
-    public void create (boolean stream) throws IOException {
+    public void create (int sockType) throws IOException {
         // no error if socket already created
         // need this for LocalServerSocket.accept()
         if (fd == null) {
-            fd = create_native(stream);
+            int osType;
+            switch (sockType) {
+                case LocalSocket.SOCKET_DGRAM:
+                    osType = OsConstants.SOCK_DGRAM;
+                    break;
+                case LocalSocket.SOCKET_STREAM:
+                    osType = OsConstants.SOCK_STREAM;
+                    break;
+                case LocalSocket.SOCKET_SEQPACKET:
+                    osType = OsConstants.SOCK_SEQPACKET;
+                    break;
+                default:
+                    throw new IllegalStateException("unknown sockType");
+            }
+            try {
+                fd = Libcore.os.socket(OsConstants.AF_UNIX, osType, 0);
+                mFdCreatedInternally = true;
+            } catch (ErrnoException e) {
+                e.rethrowAsIOException();
+            }
         }
     }
 
@@ -241,8 +263,15 @@
      */
     public void close() throws IOException {
         synchronized (LocalSocketImpl.this) {
-            if (fd == null) return;
-            close_native(fd);
+            if ((fd == null) || (mFdCreatedInternally == false)) {
+                fd = null;
+                return;
+            }
+            try {
+                Libcore.os.close(fd);
+            } catch (ErrnoException e) {
+                e.rethrowAsIOException();
+            }
             fd = null;
         }
     }
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 5a1daed..c106514 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -28,6 +28,8 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -40,6 +42,7 @@
 
 import java.io.CharArrayWriter;
 import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Track the state of mobile data connectivity. This is done by
@@ -48,10 +51,10 @@
  *
  * {@hide}
  */
-public class MobileDataStateTracker implements NetworkStateTracker {
+public class MobileDataStateTracker extends BaseNetworkStateTracker {
 
     private static final String TAG = "MobileDataStateTracker";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
     private PhoneConstants.DataState mMobileDataState;
@@ -75,6 +78,14 @@
     private Handler mHandler;
     private AsyncChannel mDataConnectionTrackerAc;
 
+    private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false);
+
+    private SignalStrength mSignalStrength;
+
+    private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
+
+    private static final int UNKNOWN = LinkQualityInfo.UNKNOWN_INT;
+
     /**
      * Create a new MobileDataStateTracker
      * @param netType the ConnectivityManager network type
@@ -101,12 +112,24 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+        filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
         filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
 
         mContext.registerReceiver(new MobileDataStateReceiver(), filter);
         mMobileDataState = PhoneConstants.DataState.DISCONNECTED;
+
+        TelephonyManager tm = (TelephonyManager)mContext.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
     }
 
+    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            mSignalStrength = signalStrength;
+        }
+    };
+
     static class MdstHandler extends Handler {
         private MobileDataStateTracker mMdst;
 
@@ -168,10 +191,47 @@
     public void releaseWakeLock() {
     }
 
+    private void updateLinkProperitesAndCapatilities(Intent intent) {
+        mLinkProperties = intent.getParcelableExtra(
+                PhoneConstants.DATA_LINK_PROPERTIES_KEY);
+        if (mLinkProperties == null) {
+            loge("CONNECTED event did not supply link properties.");
+            mLinkProperties = new LinkProperties();
+        }
+        mLinkProperties.setMtu(mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_mobile_mtu));
+        mLinkCapabilities = intent.getParcelableExtra(
+                PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
+        if (mLinkCapabilities == null) {
+            loge("CONNECTED event did not supply link capabilities.");
+            mLinkCapabilities = new LinkCapabilities();
+        }
+    }
+
     private class MobileDataStateReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(TelephonyIntents.
+                    ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) {
+                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
+                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
+                if (!TextUtils.equals(mApnType, apnType)) {
+                    return;
+                }
+                if (DBG) {
+                    log("Broadcast received: " + intent.getAction() + " apnType=" + apnType
+                            + " apnName=" + apnName);
+                }
+
+                // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING
+                mMobileDataState = PhoneConstants.DataState.CONNECTING;
+                updateLinkProperitesAndCapatilities(intent);
+                mNetworkInfo.setIsConnectedToProvisioningNetwork(true);
+
+                // Change state to SUSPENDED so setDetailedState
+                // sends EVENT_STATE_CHANGED to connectivityService
+                setDetailedState(DetailedState.SUSPENDED, "", apnName);
+            } else if (intent.getAction().equals(TelephonyIntents.
                     ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
                 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
                 if (VDBG) {
@@ -182,6 +242,11 @@
                 if (!TextUtils.equals(apnType, mApnType)) {
                     return;
                 }
+                // Assume this isn't a provisioning network.
+                mNetworkInfo.setIsConnectedToProvisioningNetwork(false);
+                if (DBG) {
+                    log("Broadcast received: " + intent.getAction() + " apnType=" + apnType);
+                }
 
                 int oldSubtype = mNetworkInfo.getSubtype();
                 int newSubType = TelephonyManager.getDefault().getNetworkType();
@@ -233,21 +298,34 @@
                             setDetailedState(DetailedState.SUSPENDED, reason, apnName);
                             break;
                         case CONNECTED:
-                            mLinkProperties = intent.getParcelableExtra(
-                                    PhoneConstants.DATA_LINK_PROPERTIES_KEY);
-                            if (mLinkProperties == null) {
-                                loge("CONNECTED event did not supply link properties.");
-                                mLinkProperties = new LinkProperties();
-                            }
-                            mLinkCapabilities = intent.getParcelableExtra(
-                                    PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
-                            if (mLinkCapabilities == null) {
-                                loge("CONNECTED event did not supply link capabilities.");
-                                mLinkCapabilities = new LinkCapabilities();
-                            }
+                            updateLinkProperitesAndCapatilities(intent);
                             setDetailedState(DetailedState.CONNECTED, reason, apnName);
                             break;
                     }
+
+                    if (VDBG) {
+                        Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged");
+                        if (mNetworkInfo != null) {
+                            Slog.d(TAG, "NetworkInfo = " + mNetworkInfo.toString());
+                            Slog.d(TAG, "subType = " + String.valueOf(mNetworkInfo.getSubtype()));
+                            Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName());
+                        }
+                        if (mLinkProperties != null) {
+                            Slog.d(TAG, "LinkProperties = " + mLinkProperties.toString());
+                        } else {
+                            Slog.d(TAG, "LinkProperties = " );
+                        }
+
+                        if (mLinkCapabilities != null) {
+                            Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities.toString());
+                        } else {
+                            Slog.d(TAG, "LinkCapabilities = " );
+                        }
+                    }
+
+
+                    /* lets not sample traffic data across state changes */
+                    mSamplingDataTracker.resetSamplingData();
                 } else {
                     // There was no state change. Check if LinkProperties has been updated.
                     if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
@@ -276,11 +354,13 @@
                     }
                     return;
                 }
+                // Assume this isn't a provisioning network.
+                mNetworkInfo.setIsConnectedToProvisioningNetwork(false);
                 String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
                 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
                 if (DBG) {
-                    log("Received " + intent.getAction() +
-                                " broadcast" + reason == null ? "" : "(" + reason + ")");
+                    log("Broadcast received: " + intent.getAction() +
+                                " reason=" + reason == null ? "null" : reason);
                 }
                 setDetailedState(DetailedState.FAILED, reason, apnName);
             } else {
@@ -372,11 +452,27 @@
         return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED);
     }
 
+    /**
+     * @return true if this is ready to operate
+     */
+    public boolean isReady() {
+        return mDataConnectionTrackerAc != null;
+    }
+
     @Override
     public void captivePortalCheckComplete() {
         // not implemented
     }
 
+    @Override
+    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+        if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) {
+            // Captive portal change enable/disable failing fast
+            setEnableFailFastMobileData(
+                    isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED);
+        }
+    }
+
     /**
      * Record the detailed state of a network, and if it is a
      * change from the previous state, send a notification to
@@ -525,6 +621,40 @@
         }
     }
 
+    /**
+     *  Inform DCT mobile provisioning has started, it ends when provisioning completes.
+     */
+    public void enableMobileProvisioning(String url) {
+        if (DBG) log("enableMobileProvisioning(url=" + url + ")");
+        final AsyncChannel channel = mDataConnectionTrackerAc;
+        if (channel != null) {
+            Message msg = Message.obtain();
+            msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING;
+            msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url));
+            channel.sendMessage(msg);
+        }
+    }
+
+    /**
+     * Return if this network is the provisioning network. Valid only if connected.
+     * @param met
+     */
+    public boolean isProvisioningNetwork() {
+        boolean retVal;
+        try {
+            Message msg = Message.obtain();
+            msg.what = DctConstants.CMD_IS_PROVISIONING_APN;
+            msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType));
+            Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg);
+            retVal = result.arg1 == DctConstants.ENABLED;
+        } catch (NullPointerException e) {
+            loge("isProvisioningNetwork: X " + e);
+            retVal = false;
+        }
+        if (DBG) log("isProvisioningNetwork: retVal=" + retVal);
+        return retVal;
+    }
+
     @Override
     public void addStackedLink(LinkProperties link) {
         mLinkProperties.addStackedLink(link);
@@ -545,7 +675,7 @@
         return writer.toString();
     }
 
-   /**
+    /**
      * Internal method supporting the ENABLE_MMS feature.
      * @param apnType the type of APN to be enabled or disabled (e.g., mms)
      * @param enable {@code true} to enable the specified APN type,
@@ -597,15 +727,19 @@
                 return PhoneConstants.APN_TYPE_IMS;
             case ConnectivityManager.TYPE_MOBILE_CBS:
                 return PhoneConstants.APN_TYPE_CBS;
+            case ConnectivityManager.TYPE_MOBILE_IA:
+                return PhoneConstants.APN_TYPE_IA;
             default:
                 sloge("Error mapping networkType " + netType + " to apnType.");
                 return null;
         }
     }
 
+
     /**
      * @see android.net.NetworkStateTracker#getLinkProperties()
      */
+    @Override
     public LinkProperties getLinkProperties() {
         return new LinkProperties(mLinkProperties);
     }
@@ -613,6 +747,7 @@
     /**
      * @see android.net.NetworkStateTracker#getLinkCapabilities()
      */
+    @Override
     public LinkCapabilities getLinkCapabilities() {
         return new LinkCapabilities(mLinkCapabilities);
     }
@@ -634,4 +769,152 @@
     static private void sloge(String s) {
         Slog.e(TAG, s);
     }
+
+    @Override
+    public LinkQualityInfo getLinkQualityInfo() {
+        if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) {
+            // no data available yet; just return
+            return null;
+        }
+
+        MobileLinkQualityInfo li = new MobileLinkQualityInfo();
+
+        li.setNetworkType(mNetworkInfo.getType());
+
+        mSamplingDataTracker.setCommonLinkQualityInfoFields(li);
+
+        if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+            li.setMobileNetworkType(mNetworkInfo.getSubtype());
+
+            NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype());
+            if (entry != null) {
+                li.setTheoreticalRxBandwidth(entry.downloadBandwidth);
+                li.setTheoreticalRxBandwidth(entry.uploadBandwidth);
+                li.setTheoreticalLatency(entry.latency);
+            }
+
+            if (mSignalStrength != null) {
+                li.setNormalizedSignalStrength(getNormalizedSignalStrength(
+                        li.getMobileNetworkType(), mSignalStrength));
+            }
+        }
+
+        SignalStrength ss = mSignalStrength;
+        if (ss != null) {
+
+            li.setRssi(ss.getGsmSignalStrength());
+            li.setGsmErrorRate(ss.getGsmBitErrorRate());
+            li.setCdmaDbm(ss.getCdmaDbm());
+            li.setCdmaEcio(ss.getCdmaEcio());
+            li.setEvdoDbm(ss.getEvdoDbm());
+            li.setEvdoEcio(ss.getEvdoEcio());
+            li.setEvdoSnr(ss.getEvdoSnr());
+            li.setLteSignalStrength(ss.getLteSignalStrength());
+            li.setLteRsrp(ss.getLteRsrp());
+            li.setLteRsrq(ss.getLteRsrq());
+            li.setLteRssnr(ss.getLteRssnr());
+            li.setLteCqi(ss.getLteCqi());
+        }
+
+        if (VDBG) {
+            Slog.d(TAG, "Returning LinkQualityInfo with"
+                    + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType())
+                    + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth())
+                    + " gsm Signal Strength = " + String.valueOf(li.getRssi())
+                    + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm())
+                    + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm())
+                    + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength()));
+        }
+
+        return li;
+    }
+
+    static class NetworkDataEntry {
+        public int networkType;
+        public int downloadBandwidth;               // in kbps
+        public int uploadBandwidth;                 // in kbps
+        public int latency;                         // in millisecond
+
+        NetworkDataEntry(int i1, int i2, int i3, int i4) {
+            networkType = i1;
+            downloadBandwidth = i2;
+            uploadBandwidth = i3;
+            latency = i4;
+        }
+    }
+
+    private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] {
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE,      237,     118, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS,       48,      40, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS,      384,      64, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA,   14400, UNKNOWN, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA,   14400,    5760, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA,    14400,    5760, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP,   21000,    5760, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA,  UNKNOWN, UNKNOWN, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0,   2468,     153, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A,   3072,    1800, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B,  14700,    1800, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN,  UNKNOWN, UNKNOWN, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE,    100000,   50000, UNKNOWN),
+            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN),
+    };
+
+    private static NetworkDataEntry getNetworkDataEntry(int networkType) {
+        for (NetworkDataEntry entry : mTheoreticalBWTable) {
+            if (entry.networkType == networkType) {
+                return entry;
+            }
+        }
+
+        Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType));
+        return null;
+    }
+
+    private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) {
+
+        int level;
+
+        switch(networkType) {
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+                level = ss.getGsmLevel();
+                break;
+            case TelephonyManager.NETWORK_TYPE_CDMA:
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+                level = ss.getCdmaLevel();
+                break;
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                level = ss.getEvdoLevel();
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                level = ss.getLteLevel();
+                break;
+            case TelephonyManager.NETWORK_TYPE_IDEN:
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
+            default:
+                return UNKNOWN;
+        }
+
+        return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) /
+                SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+    }
+
+    @Override
+    public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
+        mSamplingDataTracker.startSampling(s);
+    }
+
+    @Override
+    public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
+        mSamplingDataTracker.stopSampling(s);
+    }
 }
diff --git a/core/java/android/net/MobileLinkQualityInfo.java b/core/java/android/net/MobileLinkQualityInfo.java
new file mode 100644
index 0000000..a01fc80
--- /dev/null
+++ b/core/java/android/net/MobileLinkQualityInfo.java
@@ -0,0 +1,286 @@
+/*
+ * 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 android.net;
+
+import android.os.Parcel;
+
+/**
+ *  Class that represents useful attributes of mobile network links
+ *  such as the upload/download throughput or error rate etc.
+ *  @hide
+ */
+public class MobileLinkQualityInfo extends LinkQualityInfo {
+    // Represents TelephonyManager.NetworkType
+    private int mMobileNetworkType = UNKNOWN_INT;
+    private int mRssi = UNKNOWN_INT;
+    private int mGsmErrorRate = UNKNOWN_INT;
+    private int mCdmaDbm = UNKNOWN_INT;
+    private int mCdmaEcio = UNKNOWN_INT;
+    private int mEvdoDbm = UNKNOWN_INT;
+    private int mEvdoEcio = UNKNOWN_INT;
+    private int mEvdoSnr = UNKNOWN_INT;
+    private int mLteSignalStrength = UNKNOWN_INT;
+    private int mLteRsrp = UNKNOWN_INT;
+    private int mLteRsrq = UNKNOWN_INT;
+    private int mLteRssnr = UNKNOWN_INT;
+    private int mLteCqi = UNKNOWN_INT;
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags, OBJECT_TYPE_MOBILE_LINK_QUALITY_INFO);
+
+        dest.writeInt(mMobileNetworkType);
+        dest.writeInt(mRssi);
+        dest.writeInt(mGsmErrorRate);
+        dest.writeInt(mCdmaDbm);
+        dest.writeInt(mCdmaEcio);
+        dest.writeInt(mEvdoDbm);
+        dest.writeInt(mEvdoEcio);
+        dest.writeInt(mEvdoSnr);
+        dest.writeInt(mLteSignalStrength);
+        dest.writeInt(mLteRsrp);
+        dest.writeInt(mLteRsrq);
+        dest.writeInt(mLteRssnr);
+        dest.writeInt(mLteCqi);
+    }
+
+    /* Un-parceling helper */
+    /**
+     * @hide
+     */
+    public static MobileLinkQualityInfo createFromParcelBody(Parcel in) {
+
+        MobileLinkQualityInfo li = new MobileLinkQualityInfo();
+
+        li.initializeFromParcel(in);
+
+        li.mMobileNetworkType = in.readInt();
+        li.mRssi = in.readInt();
+        li.mGsmErrorRate = in.readInt();
+        li.mCdmaDbm = in.readInt();
+        li.mCdmaEcio = in.readInt();
+        li.mEvdoDbm = in.readInt();
+        li.mEvdoEcio = in.readInt();
+        li.mEvdoSnr = in.readInt();
+        li.mLteSignalStrength = in.readInt();
+        li.mLteRsrp = in.readInt();
+        li.mLteRsrq = in.readInt();
+        li.mLteRssnr = in.readInt();
+        li.mLteCqi = in.readInt();
+
+        return li;
+    }
+
+    /**
+     * returns mobile network type as defined by {@link android.telephony.TelephonyManager}
+     * @return network type or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getMobileNetworkType() {
+        return mMobileNetworkType;
+    }
+
+    /**
+     * @hide
+     */
+    public void setMobileNetworkType(int mobileNetworkType) {
+        mMobileNetworkType = mobileNetworkType;
+    }
+
+    /**
+     * returns signal strength for GSM networks
+     * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
+     * @hide
+     */
+    public void setRssi(int Rssi) {
+        mRssi = Rssi;
+    }
+
+    /**
+     * returns error rates for GSM networks
+     * @return error rate or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getGsmErrorRate() {
+        return mGsmErrorRate;
+    }
+
+    /**
+     * @hide
+     */
+    public void setGsmErrorRate(int gsmErrorRate) {
+        mGsmErrorRate = gsmErrorRate;
+    }
+
+    /**
+     * returns signal strength for CDMA networks
+     * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getCdmaDbm() {
+        return mCdmaDbm;
+    }
+
+    /**
+     * @hide
+     */
+    public void setCdmaDbm(int cdmaDbm) {
+        mCdmaDbm = cdmaDbm;
+    }
+
+    /**
+     * returns signal to noise ratio for CDMA networks
+     * @return signal to noise ratio in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getCdmaEcio() {
+        return mCdmaEcio;
+    }
+
+    /**
+     * @hide
+     */
+    public void setCdmaEcio(int cdmaEcio) {
+        mCdmaEcio = cdmaEcio;
+    }
+
+    /**
+     * returns signal strength for EVDO networks
+     * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getEvdoDbm() {
+        return mEvdoDbm;
+    }
+
+    /**
+     * @hide
+     */
+    public void setEvdoDbm(int evdoDbm) {
+        mEvdoDbm = evdoDbm;
+    }
+
+    /**
+     * returns signal to noise ratio for EVDO spectrum
+     * @return signal to noise ration in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getEvdoEcio() {
+        return mEvdoEcio;
+    }
+
+    /**
+     * @hide
+     */
+    public void setEvdoEcio(int evdoEcio) {
+        mEvdoEcio = evdoEcio;
+    }
+
+    /**
+     * returns end-to-end signal to noise ratio for EVDO networks
+     * @return signal to noise ration in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getEvdoSnr() {
+        return mEvdoSnr;
+    }
+
+    /**
+     * @hide
+     */
+    public void setEvdoSnr(int evdoSnr) {
+        mEvdoSnr = evdoSnr;
+    }
+
+    /**
+     * returns signal strength for LTE network
+     * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getLteSignalStrength() {
+        return mLteSignalStrength;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLteSignalStrength(int lteSignalStrength) {
+        mLteSignalStrength = lteSignalStrength;
+    }
+
+    /**
+     * returns RSRP (Reference Signal Received Power) for LTE network
+     * @return RSRP in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getLteRsrp() {
+        return mLteRsrp;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLteRsrp(int lteRsrp) {
+        mLteRsrp = lteRsrp;
+    }
+
+    /**
+     * returns RSRQ (Reference Signal Received Quality) for LTE network
+     * @return RSRQ ??? or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getLteRsrq() {
+        return mLteRsrq;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLteRsrq(int lteRsrq) {
+        mLteRsrq = lteRsrq;
+    }
+
+    /**
+     * returns signal to noise ratio for LTE networks
+     * @return signal to noise ration in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getLteRssnr() {
+        return mLteRssnr;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLteRssnr(int lteRssnr) {
+        mLteRssnr = lteRssnr;
+    }
+
+    /**
+     * returns channel quality indicator for LTE networks
+     * @return CQI or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getLteCqi() {
+        return mLteCqi;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLteCqi(int lteCqi) {
+        mLteCqi = lteCqi;
+    }
+}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 689dae5..4d2a70d 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -83,7 +83,7 @@
         /** Link has poor connectivity. */
         VERIFYING_POOR_LINK,
         /** Checking if network is a captive portal */
-        CAPTIVE_PORTAL_CHECK,
+        CAPTIVE_PORTAL_CHECK
     }
 
     /**
@@ -120,6 +120,8 @@
     private String mExtraInfo;
     private boolean mIsFailover;
     private boolean mIsRoaming;
+    private boolean mIsConnectedToProvisioningNetwork;
+
     /**
      * Indicates whether network connectivity is possible:
      */
@@ -148,6 +150,7 @@
         mState = State.UNKNOWN;
         mIsAvailable = false; // until we're told otherwise, assume unavailable
         mIsRoaming = false;
+        mIsConnectedToProvisioningNetwork = false;
     }
 
     /** {@hide} */
@@ -164,6 +167,7 @@
             mIsFailover = source.mIsFailover;
             mIsRoaming = source.mIsRoaming;
             mIsAvailable = source.mIsAvailable;
+            mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork;
         }
     }
 
@@ -322,6 +326,22 @@
         }
     }
 
+    /** {@hide} */
+    @VisibleForTesting
+    public boolean isConnectedToProvisioningNetwork() {
+        synchronized (this) {
+            return mIsConnectedToProvisioningNetwork;
+        }
+    }
+
+    /** {@hide} */
+    @VisibleForTesting
+    public void setIsConnectedToProvisioningNetwork(boolean val) {
+        synchronized (this) {
+            mIsConnectedToProvisioningNetwork = val;
+        }
+    }
+
     /**
      * Reports the current coarse-grained state of the network.
      * @return the coarse-grained state
@@ -405,7 +425,9 @@
             append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
             append(", roaming: ").append(mIsRoaming).
             append(", failover: ").append(mIsFailover).
-            append(", isAvailable: ").append(mIsAvailable);
+            append(", isAvailable: ").append(mIsAvailable).
+            append(", isConnectedToProvisioningNetwork: ").
+                    append(mIsConnectedToProvisioningNetwork);
             return builder.toString();
         }
     }
@@ -433,6 +455,7 @@
             dest.writeInt(mIsFailover ? 1 : 0);
             dest.writeInt(mIsAvailable ? 1 : 0);
             dest.writeInt(mIsRoaming ? 1 : 0);
+            dest.writeInt(mIsConnectedToProvisioningNetwork ? 1 : 0);
             dest.writeString(mReason);
             dest.writeString(mExtraInfo);
         }
@@ -455,6 +478,7 @@
                 netInfo.mIsFailover = in.readInt() != 0;
                 netInfo.mIsAvailable = in.readInt() != 0;
                 netInfo.mIsRoaming = in.readInt() != 0;
+                netInfo.mIsConnectedToProvisioningNetwork = in.readInt() != 0;
                 netInfo.mReason = in.readString();
                 netInfo.mExtraInfo = in.readString();
                 return netInfo;
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index cf77a1c..1ca9255 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -83,7 +83,6 @@
      */
     public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5;
 
-
     /**
      * -------------------------------------------------------------
      * Control Interface
@@ -120,6 +119,12 @@
     public LinkCapabilities getLinkCapabilities();
 
     /**
+     * Get interesting information about this network link
+     * @return a copy of link information, null if not available
+     */
+    public LinkQualityInfo getLinkQualityInfo();
+
+    /**
      * Return the system properties name associated with the tcp buffer sizes
      * for this network.
      */
@@ -144,6 +149,11 @@
     public void captivePortalCheckComplete();
 
     /**
+     * Captive portal check has completed
+     */
+    public void captivePortalCheckCompleted(boolean isCaptive);
+
+    /**
      * Turn the wireless radio off for a network.
      * @param turnOn {@code true} to turn the radio on, {@code false}
      */
@@ -229,4 +239,20 @@
      * the underlying network specific code.
      */
     public void supplyMessenger(Messenger messenger);
+
+    /*
+     * Network interface name that we'll lookup for sampling data
+     */
+    public String getNetworkInterfaceName();
+
+    /*
+     * Save the starting sample
+     */
+    public void startSampling(SamplingDataTracker.SamplingSnapshot s);
+
+    /*
+     * Save the ending sample
+     */
+    public void stopSampling(SamplingDataTracker.SamplingSnapshot s);
+
 }
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4ab479e..b24d396 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -21,6 +21,7 @@
 import java.net.Inet6Address;
 import java.net.UnknownHostException;
 import java.util.Collection;
+import java.util.Locale;
 
 import android.util.Log;
 
@@ -103,6 +104,11 @@
     public native static String getDhcpError();
 
     /**
+     * Set the SO_MARK of {@code socketfd} to {@code mark}
+     */
+    public native static void markSocket(int socketfd, int mark);
+
+    /**
      * Convert a IPv4 address from an integer to an InetAddress.
      * @param hostAddress an int corresponding to the IPv4 address in network byte order
      */
@@ -223,7 +229,7 @@
     public static InetAddress hexToInet6Address(String addrHexString)
             throws IllegalArgumentException {
         try {
-            return numericToInetAddress(String.format("%s:%s:%s:%s:%s:%s:%s:%s",
+            return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
                     addrHexString.substring(0,4),   addrHexString.substring(4,8),
                     addrHexString.substring(8,12),  addrHexString.substring(12,16),
                     addrHexString.substring(16,20), addrHexString.substring(20,24),
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
new file mode 100644
index 0000000..b674324
--- /dev/null
+++ b/core/java/android/net/PacProxySelector.java
@@ -0,0 +1,114 @@
+/*
+ * 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 android.net;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.net.IProxyService;
+import com.google.android.collect.Lists;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.Proxy.Type;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class PacProxySelector extends ProxySelector {
+    private static final String TAG = "PacProxySelector";
+    public static final String PROXY_SERVICE = "com.android.net.IProxyService";
+    private IProxyService mProxyService;
+    private final List<Proxy> mDefaultList;
+
+    public PacProxySelector() {
+        mProxyService = IProxyService.Stub.asInterface(
+                ServiceManager.getService(PROXY_SERVICE));
+        if (mProxyService == null) {
+            // Added because of b10267814 where mako is restarting.
+            Log.e(TAG, "PacManager: no proxy service");
+        }
+        mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY);
+    }
+
+    @Override
+    public List<Proxy> select(URI uri) {
+        if (mProxyService == null) {
+            mProxyService = IProxyService.Stub.asInterface(
+                    ServiceManager.getService(PROXY_SERVICE));
+        }
+        if (mProxyService == null) {
+            Log.e(TAG, "select: no proxy service return NO_PROXY");
+            return Lists.newArrayList(java.net.Proxy.NO_PROXY);
+        }
+        String response = null;
+        String urlString;
+        try {
+            urlString = uri.toURL().toString();
+        } catch (MalformedURLException e) {
+            urlString = uri.getHost();
+        }
+        try {
+            response = mProxyService.resolvePacFile(uri.getHost(), urlString);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        if (response == null) {
+            return mDefaultList;
+        }
+
+        return parseResponse(response);
+    }
+
+    private static List<Proxy> parseResponse(String response) {
+        String[] split = response.split(";");
+        List<Proxy> ret = Lists.newArrayList();
+        for (String s : split) {
+            String trimmed = s.trim();
+            if (trimmed.equals("DIRECT")) {
+                ret.add(java.net.Proxy.NO_PROXY);
+            } else if (trimmed.startsWith("PROXY ")) {
+                String[] hostPort = trimmed.substring(6).split(":");
+                String host = hostPort[0];
+                int port;
+                try {
+                    port = Integer.parseInt(hostPort[1]);
+                } catch (Exception e) {
+                    port = 8080;
+                }
+                ret.add(new Proxy(Type.HTTP, new InetSocketAddress(host, port)));
+            }
+        }
+        if (ret.size() == 0) {
+            ret.add(java.net.Proxy.NO_PROXY);
+        }
+        return ret;
+    }
+
+    @Override
+    public void connectFailed(URI uri, SocketAddress address, IOException failure) {
+
+    }
+
+}
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index a408ea0..c3e1438 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -18,38 +18,25 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.database.ContentObserver;
-import android.net.ProxyProperties;
-import android.os.Handler;
-import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.provider.Settings;
 import android.util.Log;
 
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ProxySelector;
-import java.net.SocketAddress;
-import java.net.URI;
-import java.net.UnknownHostException;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import junit.framework.Assert;
-
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.conn.routing.HttpRoutePlanner;
 import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
 import org.apache.http.protocol.HttpContext;
 
+import java.net.InetSocketAddress;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * A convenience class for accessing the user and default proxy
  * settings.
@@ -60,6 +47,8 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "Proxy";
 
+    private static final ProxySelector sDefaultProxySelector;
+
     /**
      * Used to notify an app that's caching the default connection proxy
      * that either the default connection or its proxy has changed.
@@ -96,6 +85,7 @@
     static {
         HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
         EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
+        sDefaultProxySelector = ProxySelector.getDefault();
     }
 
     /**
@@ -325,16 +315,19 @@
         String host = null;
         String port = null;
         String exclList = null;
+        String pacFileUrl = null;
         if (p != null) {
             host = p.getHost();
             port = Integer.toString(p.getPort());
             exclList = p.getExclusionList();
+            pacFileUrl = p.getPacFileUrl();
         }
-        setHttpProxySystemProperty(host, port, exclList);
+        setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
     }
 
     /** @hide */
-    public static final void setHttpProxySystemProperty(String host, String port, String exclList) {
+    public static final void setHttpProxySystemProperty(String host, String port, String exclList,
+            String pacFileUrl) {
         if (exclList != null) exclList = exclList.replace(",", "|");
         if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
         if (host != null) {
@@ -358,5 +351,10 @@
             System.clearProperty("http.nonProxyHosts");
             System.clearProperty("https.nonProxyHosts");
         }
+        if (!TextUtils.isEmpty(pacFileUrl)) {
+            ProxySelector.setDefault(new PacProxySelector());
+        } else {
+            ProxySelector.setDefault(sDefaultProxySelector);
+        }
     }
 }
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 9c4772b..648a4b3 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -20,9 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
-import android.util.Log;
 
-import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.Locale;
@@ -38,17 +36,38 @@
     private String mExclusionList;
     private String[] mParsedExclusionList;
 
+    private String mPacFileUrl;
+    public static final String LOCAL_EXCL_LIST = "";
+    public static final int LOCAL_PORT = -1;
+    public static final String LOCAL_HOST = "localhost";
+
     public ProxyProperties(String host, int port, String exclList) {
         mHost = host;
         mPort = port;
         setExclusionList(exclList);
     }
 
+    public ProxyProperties(String pacFileUrl) {
+        mHost = LOCAL_HOST;
+        mPort = LOCAL_PORT;
+        setExclusionList(LOCAL_EXCL_LIST);
+        mPacFileUrl = pacFileUrl;
+    }
+
+    // Only used in PacManager after Local Proxy is bound.
+    public ProxyProperties(String pacFileUrl, int localProxyPort) {
+        mHost = LOCAL_HOST;
+        mPort = localProxyPort;
+        setExclusionList(LOCAL_EXCL_LIST);
+        mPacFileUrl = pacFileUrl;
+    }
+
     private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
         mHost = host;
         mPort = port;
         mExclusionList = exclList;
         mParsedExclusionList = parsedExclList;
+        mPacFileUrl = null;
     }
 
     // copy constructor instead of clone
@@ -56,6 +75,7 @@
         if (source != null) {
             mHost = source.getHost();
             mPort = source.getPort();
+            mPacFileUrl = source.getPacFileUrl();
             mExclusionList = source.getExclusionList();
             mParsedExclusionList = source.mParsedExclusionList;
         }
@@ -69,6 +89,10 @@
         return inetSocketAddress;
     }
 
+    public String getPacFileUrl() {
+        return mPacFileUrl;
+    }
+
     public String getHost() {
         return mHost;
     }
@@ -130,7 +154,10 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        if (mHost != null) {
+        if (mPacFileUrl != null) {
+            sb.append("PAC Script: ");
+            sb.append(mPacFileUrl);
+        } else if (mHost != null) {
             sb.append("[");
             sb.append(mHost);
             sb.append("] ");
@@ -148,6 +175,14 @@
     public boolean equals(Object o) {
         if (!(o instanceof ProxyProperties)) return false;
         ProxyProperties p = (ProxyProperties)o;
+        // If PAC URL is present in either then they must be equal.
+        // Other parameters will only be for fall back.
+        if (!TextUtils.isEmpty(mPacFileUrl)) {
+            return mPacFileUrl.equals(p.getPacFileUrl());
+        }
+        if (!TextUtils.isEmpty(p.getPacFileUrl())) {
+            return false;
+        }
         if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
         if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
             return false;
@@ -181,6 +216,13 @@
      * @hide
      */
     public void writeToParcel(Parcel dest, int flags) {
+        if (mPacFileUrl != null) {
+            dest.writeByte((byte)1);
+            dest.writeString(mPacFileUrl);
+            return;
+        } else {
+            dest.writeByte((byte)0);
+        }
         if (mHost != null) {
             dest.writeByte((byte)1);
             dest.writeString(mHost);
@@ -201,7 +243,10 @@
             public ProxyProperties createFromParcel(Parcel in) {
                 String host = null;
                 int port = 0;
-                if (in.readByte() == 1) {
+                if (in.readByte() != 0) {
+                    return new ProxyProperties(in.readString());
+                }
+                if (in.readByte() != 0) {
                     host = in.readString();
                     port = in.readInt();
                 }
diff --git a/core/java/android/net/SamplingDataTracker.java b/core/java/android/net/SamplingDataTracker.java
new file mode 100644
index 0000000..acd56f2
--- /dev/null
+++ b/core/java/android/net/SamplingDataTracker.java
@@ -0,0 +1,300 @@
+/*
+ * 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 android.net;
+
+
+import android.os.SystemClock;
+import android.util.Slog;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public class SamplingDataTracker
+{
+    private static final boolean DBG = false;
+    private static final String  TAG = "SamplingDataTracker";
+
+    public static class SamplingSnapshot
+    {
+        public long mTxByteCount;
+        public long mRxByteCount;
+        public long mTxPacketCount;
+        public long mRxPacketCount;
+        public long mTxPacketErrorCount;
+        public long mRxPacketErrorCount;
+        public long mTimestamp;
+    }
+
+    public static void getSamplingSnapshots(Map<String, SamplingSnapshot> mapIfaceToSample) {
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new FileReader("/proc/net/dev"));
+
+            // Skip over the line bearing column titles (there are 2 lines)
+            String line;
+            reader.readLine();
+            reader.readLine();
+
+            while ((line = reader.readLine()) != null) {
+
+                // remove leading whitespace
+                line = line.trim();
+
+                String[] tokens = line.split("[ ]+");
+                if (tokens.length < 17) {
+                    continue;
+                }
+
+                /* column format is
+                 * Interface  (Recv)bytes packets errs drop fifo frame compressed multicast \
+                 *            (Transmit)bytes packets errs drop fifo colls carrier compress
+                */
+
+                String currentIface = tokens[0].split(":")[0];
+                if (DBG) Slog.d(TAG, "Found data for interface " + currentIface);
+                if (mapIfaceToSample.containsKey(currentIface)) {
+
+                    try {
+                        SamplingSnapshot ss = new SamplingSnapshot();
+
+                        ss.mTxByteCount        = Long.parseLong(tokens[1]);
+                        ss.mTxPacketCount      = Long.parseLong(tokens[2]);
+                        ss.mTxPacketErrorCount = Long.parseLong(tokens[3]);
+                        ss.mRxByteCount        = Long.parseLong(tokens[9]);
+                        ss.mRxPacketCount      = Long.parseLong(tokens[10]);
+                        ss.mRxPacketErrorCount = Long.parseLong(tokens[11]);
+
+                        ss.mTimestamp          = SystemClock.elapsedRealtime();
+
+                        if (DBG) {
+                            Slog.d(TAG, "Interface = " + currentIface);
+                            Slog.d(TAG, "ByteCount = " + String.valueOf(ss.mTxByteCount));
+                            Slog.d(TAG, "TxPacketCount = " + String.valueOf(ss.mTxPacketCount));
+                            Slog.d(TAG, "TxPacketErrorCount = "
+                                    + String.valueOf(ss.mTxPacketErrorCount));
+                            Slog.d(TAG, "RxByteCount = " + String.valueOf(ss.mRxByteCount));
+                            Slog.d(TAG, "RxPacketCount = " + String.valueOf(ss.mRxPacketCount));
+                            Slog.d(TAG, "RxPacketErrorCount = "
+                                    + String.valueOf(ss.mRxPacketErrorCount));
+                            Slog.d(TAG, "Timestamp = " + String.valueOf(ss.mTimestamp));
+                            Slog.d(TAG, "---------------------------");
+                        }
+
+                        mapIfaceToSample.put(currentIface, ss);
+
+                    } catch (NumberFormatException e) {
+                        // just ignore this data point
+                    }
+                }
+            }
+
+            if (DBG) {
+                Iterator it = mapIfaceToSample.entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry kvpair = (Map.Entry)it.next();
+                    if (kvpair.getValue() == null) {
+                        Slog.d(TAG, "could not find snapshot for interface " + kvpair.getKey());
+                    }
+                }
+            }
+        } catch(FileNotFoundException e) {
+            Slog.e(TAG, "could not find /proc/net/dev");
+        } catch (IOException e) {
+            Slog.e(TAG, "could not read /proc/net/dev");
+        } finally {
+            try {
+                if (reader != null) {
+                    reader.close();
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "could not close /proc/net/dev");
+            }
+        }
+    }
+
+    // Snapshots from previous sampling interval
+    private SamplingSnapshot mBeginningSample;
+    private SamplingSnapshot mEndingSample;
+
+    // Starting snapshot of current interval
+    private SamplingSnapshot mLastSample;
+
+    // Protects sampling data from concurrent access
+    public final Object mSamplingDataLock = new Object();
+
+    // We need long enough time for a good sample
+    private final int MINIMUM_SAMPLING_INTERVAL = 15 * 1000;
+
+    // statistics is useless unless we have enough data
+    private final int MINIMUM_SAMPLED_PACKETS   = 30;
+
+    public void startSampling(SamplingSnapshot s) {
+        synchronized(mSamplingDataLock) {
+            mLastSample = s;
+        }
+    }
+
+    public void stopSampling(SamplingSnapshot s) {
+        synchronized(mSamplingDataLock) {
+            if (mLastSample != null) {
+                if (s.mTimestamp - mLastSample.mTimestamp > MINIMUM_SAMPLING_INTERVAL
+                        && getSampledPacketCount(mLastSample, s) > MINIMUM_SAMPLED_PACKETS) {
+                    mBeginningSample = mLastSample;
+                    mEndingSample = s;
+                    mLastSample = null;
+                } else {
+                    if (DBG) Slog.d(TAG, "Throwing current sample away because it is too small");
+                }
+            }
+        }
+    }
+
+    public void resetSamplingData() {
+        if (DBG) Slog.d(TAG, "Resetting sampled network data");
+        synchronized(mSamplingDataLock) {
+
+            // We could just take another sample here and treat it as an
+            // 'ending sample' effectively shortening sampling interval, but that
+            // requires extra work (specifically, reading the sample needs to be
+            // done asynchronously)
+
+            mLastSample = null;
+        }
+    }
+
+    public long getSampledTxByteCount() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public long getSampledTxPacketCount() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public long getSampledTxPacketErrorCount() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public long getSampledRxByteCount() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public long getSampledRxPacketCount() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public long getSampledPacketCount() {
+        return getSampledPacketCount(mBeginningSample, mEndingSample);
+    }
+
+    public long getSampledPacketCount(SamplingSnapshot begin, SamplingSnapshot end) {
+        if (begin != null && end != null) {
+            long rxPacketCount = end.mRxPacketCount - begin.mRxPacketCount;
+            long txPacketCount = end.mTxPacketCount - begin.mTxPacketCount;
+            return rxPacketCount + txPacketCount;
+        } else {
+            return LinkQualityInfo.UNKNOWN_LONG;
+        }
+    }
+
+    public long getSampledPacketErrorCount() {
+        if (mBeginningSample != null && mEndingSample != null) {
+            long rxPacketErrorCount = getSampledRxPacketErrorCount();
+            long txPacketErrorCount = getSampledTxPacketErrorCount();
+            return rxPacketErrorCount + txPacketErrorCount;
+        } else {
+            return LinkQualityInfo.UNKNOWN_LONG;
+        }
+    }
+
+    public long getSampledRxPacketErrorCount() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public long getSampleTimestamp() {
+        synchronized(mSamplingDataLock) {
+            if (mEndingSample != null) {
+                return mEndingSample.mTimestamp;
+            } else {
+                return LinkQualityInfo.UNKNOWN_LONG;
+            }
+        }
+    }
+
+    public int getSampleDuration() {
+        synchronized(mSamplingDataLock) {
+            if (mBeginningSample != null && mEndingSample != null) {
+                return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp);
+            } else {
+                return LinkQualityInfo.UNKNOWN_INT;
+            }
+        }
+    }
+
+    public void setCommonLinkQualityInfoFields(LinkQualityInfo li) {
+        synchronized(mSamplingDataLock) {
+            li.setLastDataSampleTime(getSampleTimestamp());
+            li.setDataSampleDuration(getSampleDuration());
+            li.setPacketCount(getSampledPacketCount());
+            li.setPacketErrorCount(getSampledPacketErrorCount());
+        }
+    }
+}
+
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 132173d..a7a8a0a 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -19,7 +19,6 @@
 import android.os.Environment;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Environment.UserEnvironment;
 import android.os.StrictMode;
 import android.util.Log;
 import java.io.File;
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 65d3f2b..d7dc7f5 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -17,8 +17,8 @@
 package android.net;
 
 import android.app.Activity;
-import android.app.Service;
 import android.app.PendingIntent;
+import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
@@ -30,12 +30,13 @@
 
 import com.android.internal.net.VpnConfig;
 
-import java.net.InetAddress;
+import java.net.DatagramSocket;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
-import java.net.DatagramSocket;
+import java.net.InetAddress;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * VpnService is a base class for applications to extend and build their
@@ -253,8 +254,8 @@
     public class Builder {
 
         private final VpnConfig mConfig = new VpnConfig();
-        private final StringBuilder mAddresses = new StringBuilder();
-        private final StringBuilder mRoutes = new StringBuilder();
+        private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
+        private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
 
         public Builder() {
             mConfig.user = VpnService.this.getClass().getName();
@@ -328,8 +329,7 @@
             if (address.isAnyLocalAddress()) {
                 throw new IllegalArgumentException("Bad address");
             }
-
-            mAddresses.append(' ' + address.getHostAddress() + '/' +  prefixLength);
+            mAddresses.add(new LinkAddress(address, prefixLength));
             return this;
         }
 
@@ -363,8 +363,7 @@
                     }
                 }
             }
-
-            mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
+            mRoutes.add(new RouteInfo(new LinkAddress(address, prefixLength), null));
             return this;
         }
 
@@ -465,8 +464,8 @@
          * @see VpnService
          */
         public ParcelFileDescriptor establish() {
-            mConfig.addresses = mAddresses.toString();
-            mConfig.routes = mRoutes.toString();
+            mConfig.addresses = mAddresses;
+            mConfig.routes = mRoutes;
 
             try {
                 return getService().establishVpn(mConfig);
diff --git a/core/java/android/net/WifiLinkQualityInfo.java b/core/java/android/net/WifiLinkQualityInfo.java
new file mode 100644
index 0000000..20ec9a7
--- /dev/null
+++ b/core/java/android/net/WifiLinkQualityInfo.java
@@ -0,0 +1,149 @@
+/*
+ * 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 android.net;
+
+import android.os.Parcel;
+
+/**
+ *  Class that represents useful attributes of wifi network links
+ *  such as the upload/download throughput or error rate etc.
+ *  @hide
+ */
+public class WifiLinkQualityInfo extends LinkQualityInfo {
+
+    /* Indicates Wifi network type such as b/g etc*/
+    private int  mType = UNKNOWN_INT;
+
+    private String mBssid;
+
+    /* Rssi found by scans */
+    private int  mRssi = UNKNOWN_INT;
+
+    /* packet statistics */
+    private long mTxGood = UNKNOWN_LONG;
+    private long mTxBad = UNKNOWN_LONG;
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags, OBJECT_TYPE_WIFI_LINK_QUALITY_INFO);
+
+        dest.writeInt(mType);
+        dest.writeInt(mRssi);
+        dest.writeLong(mTxGood);
+        dest.writeLong(mTxBad);
+
+        dest.writeString(mBssid);
+    }
+
+    /* Un-parceling helper */
+    /**
+     * @hide
+     */
+    public static WifiLinkQualityInfo createFromParcelBody(Parcel in) {
+        WifiLinkQualityInfo li = new WifiLinkQualityInfo();
+
+        li.initializeFromParcel(in);
+
+        li.mType =  in.readInt();
+        li.mRssi =  in.readInt();
+        li.mTxGood =  in.readLong();
+        li.mTxBad =  in.readLong();
+
+        li.mBssid =  in.readString();
+
+        return li;
+    }
+
+    /**
+     * returns Wifi network type
+     * @return network type or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * @hide
+     */
+    public void setType(int type) {
+        mType = type;
+    }
+
+    /**
+     * returns BSSID of the access point
+     * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX} or null
+     */
+    public String getBssid() {
+        return mBssid;
+    }
+
+    /**
+     * @hide
+     */
+    public void setBssid(String bssid) {
+        mBssid = bssid;
+    }
+
+    /**
+     * returns RSSI of the network in raw form
+     * @return un-normalized RSSI or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+     */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
+     * @hide
+     */
+    public void setRssi(int rssi) {
+        mRssi = rssi;
+    }
+
+    /**
+     * returns number of packets transmitted without error
+     * @return number of packets or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+     */
+    public long getTxGood() {
+        return mTxGood;
+    }
+
+    /**
+     * @hide
+     */
+    public void setTxGood(long txGood) {
+        mTxGood = txGood;
+    }
+
+    /**
+     * returns number of transmitted packets that encountered errors
+     * @return number of packets or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+     */
+    public long getTxBad() {
+        return mTxBad;
+    }
+
+    /**
+     * @hide
+     */
+    public void setTxBad(long txBad) {
+        mTxBad = txBad;
+    }
+}
diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
new file mode 100644
index 0000000..9599308
--- /dev/null
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.nfc;
+
+import android.nfc.BeamShareData;
+import android.nfc.Tag;
+
+/**
+ * @hide
+ */
+interface IAppCallback
+{
+    BeamShareData createBeamShareData();
+    void onNdefPushComplete();
+    void onTagDiscovered(in Tag tag);
+}
diff --git a/core/java/android/nfc/INdefPushCallback.aidl b/core/java/android/nfc/INdefPushCallback.aidl
deleted file mode 100644
index 16771dc..0000000
--- a/core/java/android/nfc/INdefPushCallback.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.
- */
-
-package android.nfc;
-
-import android.nfc.BeamShareData;
-
-/**
- * @hide
- */
-interface INdefPushCallback
-{
-    BeamShareData createBeamShareData();
-    void onNdefPushComplete();
-}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 39810ba..8414738 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -21,9 +21,11 @@
 import android.nfc.NdefMessage;
 import android.nfc.Tag;
 import android.nfc.TechListParcel;
-import android.nfc.INdefPushCallback;
+import android.nfc.IAppCallback;
 import android.nfc.INfcAdapterExtras;
 import android.nfc.INfcTag;
+import android.nfc.INfcCardEmulation;
+import android.os.Bundle;
 
 /**
  * @hide
@@ -31,6 +33,7 @@
 interface INfcAdapter
 {
     INfcTag getNfcTagInterface();
+    INfcCardEmulation getNfcCardEmulationInterface();
     INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
 
     int getState();
@@ -42,9 +45,10 @@
 
     void setForegroundDispatch(in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
-    void setNdefPushCallback(in INdefPushCallback callback);
+    void setAppCallback(in IAppCallback callback);
 
     void dispatch(in Tag tag);
 
+    void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
     void setP2pModes(int initatorModes, int targetModes);
 }
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
new file mode 100644
index 0000000..b8a5ba7
--- /dev/null
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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 android.nfc;
+
+import android.content.ComponentName;
+import android.nfc.cardemulation.ApduServiceInfo;
+import android.os.RemoteCallback;
+
+/**
+ * @hide
+ */
+interface INfcCardEmulation
+{
+    boolean isDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
+    boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
+    boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
+    boolean setDefaultForNextTap(int userHandle, in ComponentName service);
+    List<ApduServiceInfo> getServices(int userHandle, in String category);
+}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 10183c0..77c0234 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -19,6 +19,8 @@
 import android.app.Activity;
 import android.app.Application;
 import android.net.Uri;
+import android.nfc.NfcAdapter.ReaderCallback;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
@@ -35,7 +37,7 @@
  *
  * @hide
  */
-public final class NfcActivityManager extends INdefPushCallback.Stub
+public final class NfcActivityManager extends IAppCallback.Stub
         implements Application.ActivityLifecycleCallbacks {
     static final String TAG = NfcAdapter.TAG;
     static final Boolean DBG = false;
@@ -111,6 +113,11 @@
         NfcAdapter.CreateBeamUrisCallback uriCallback = null;
         Uri[] uris = null;
         int flags = 0;
+        int readerModeFlags = 0;
+        NfcAdapter.ReaderCallback readerCallback = null;
+        Bundle readerModeExtras = null;
+        Binder token;
+
         public NfcActivityState(Activity activity) {
             if (activity.getWindow().isDestroyed()) {
                 throw new IllegalStateException("activity is already destroyed");
@@ -120,6 +127,7 @@
             resumed = activity.isResumed();
 
             this.activity = activity;
+            this.token = new Binder();
             registerApplication(activity.getApplication());
         }
         public void destroy() {
@@ -131,6 +139,8 @@
             onNdefPushCompleteCallback = null;
             uriCallback = null;
             uris = null;
+            readerModeFlags = 0;
+            token = null;
         }
         @Override
         public String toString() {
@@ -190,6 +200,49 @@
         mDefaultEvent = new NfcEvent(mAdapter);
     }
 
+    public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
+            Bundle extras) {
+        boolean isResumed;
+        Binder token;
+        synchronized (NfcActivityManager.this) {
+            NfcActivityState state = getActivityState(activity);
+            state.readerCallback = callback;
+            state.readerModeFlags = flags;
+            state.readerModeExtras = extras;
+            token = state.token;
+            isResumed = state.resumed;
+        }
+        if (isResumed) {
+            setReaderMode(token, flags, extras);
+        }
+    }
+
+    public void disableReaderMode(Activity activity) {
+        boolean isResumed;
+        Binder token;
+        synchronized (NfcActivityManager.this) {
+            NfcActivityState state = getActivityState(activity);
+            state.readerCallback = null;
+            state.readerModeFlags = 0;
+            state.readerModeExtras = null;
+            token = state.token;
+            isResumed = state.resumed;
+        }
+        if (isResumed) {
+            setReaderMode(token, 0, null);
+        }
+
+    }
+
+    public void setReaderMode(Binder token, int flags, Bundle extras) {
+        if (DBG) Log.d(TAG, "Setting reader mode");
+        try {
+            NfcAdapter.sService.setReaderMode(token, this, flags, extras);
+        } catch (RemoteException e) {
+            mAdapter.attemptDeadServiceRecovery(e);
+        }
+    }
+
     public void setNdefPushContentUri(Activity activity, Uri[] uris) {
         boolean isResumed;
         synchronized (NfcActivityManager.this) {
@@ -257,12 +310,12 @@
     }
 
     /**
-     * Request or unrequest NFC service callbacks for NDEF push.
+     * Request or unrequest NFC service callbacks.
      * Makes IPC call - do not hold lock.
      */
     void requestNfcServiceCallback() {
         try {
-            NfcAdapter.sService.setNdefPushCallback(this);
+            NfcAdapter.sService.setAppCallback(this);
         } catch (RemoteException e) {
             mAdapter.attemptDeadServiceRecovery(e);
         }
@@ -330,6 +383,22 @@
         }
     }
 
+    @Override
+    public void onTagDiscovered(Tag tag) throws RemoteException {
+        NfcAdapter.ReaderCallback callback;
+        synchronized (NfcActivityManager.this) {
+            NfcActivityState state = findResumedActivityState();
+            if (state == null) return;
+
+            callback = state.readerCallback;
+        }
+
+        // Make callback without lock
+        if (callback != null) {
+            callback.onTagDiscovered(tag);
+        }
+
+    }
     /** Callback from Activity life-cycle, on main thread */
     @Override
     public void onActivityCreated(Activity activity, Bundle savedInstanceState) { /* NO-OP */ }
@@ -341,11 +410,20 @@
     /** Callback from Activity life-cycle, on main thread */
     @Override
     public void onActivityResumed(Activity activity) {
+        int readerModeFlags = 0;
+        Bundle readerModeExtras = null;
+        Binder token;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = findActivityState(activity);
             if (DBG) Log.d(TAG, "onResume() for " + activity + " " + state);
             if (state == null) return;
             state.resumed = true;
+            token = state.token;
+            readerModeFlags = state.readerModeFlags;
+            readerModeExtras = state.readerModeExtras;
+        }
+        if (readerModeFlags != 0) {
+            setReaderMode(token, readerModeFlags, readerModeExtras);
         }
         requestNfcServiceCallback();
     }
@@ -353,11 +431,19 @@
     /** Callback from Activity life-cycle, on main thread */
     @Override
     public void onActivityPaused(Activity activity) {
+        boolean readerModeFlagsSet;
+        Binder token;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = findActivityState(activity);
             if (DBG) Log.d(TAG, "onPause() for " + activity + " " + state);
             if (state == null) return;
             state.resumed = false;
+            token = state.token;
+            readerModeFlagsSet = state.readerModeFlags != 0;
+        }
+        if (readerModeFlagsSet) {
+            // Restore default p2p modes
+            setReaderMode(token, 0, null);
         }
     }
 
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index ca4a7d6..486e75a 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -33,6 +33,7 @@
 import android.nfc.tech.Ndef;
 import android.nfc.tech.NfcA;
 import android.nfc.tech.NfcF;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -195,6 +196,67 @@
     public static final int STATE_ON = 3;
     public static final int STATE_TURNING_OFF = 4;
 
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag enables polling for Nfc-A technology.
+     */
+    public static final int FLAG_READER_NFC_A = 0x1;
+
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag enables polling for Nfc-B technology.
+     */
+    public static final int FLAG_READER_NFC_B = 0x2;
+
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag enables polling for Nfc-F technology.
+     */
+    public static final int FLAG_READER_NFC_F = 0x4;
+
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag enables polling for Nfc-V (ISO15693) technology.
+     */
+    public static final int FLAG_READER_NFC_V = 0x8;
+
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag enables polling for NfcBarcode technology.
+     */
+    public static final int FLAG_READER_NFC_BARCODE = 0x10;
+
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag allows the caller to prevent the
+     * platform from performing an NDEF check on the tags it
+     * finds.
+     */
+    public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
+
+    /**
+     * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this flag allows the caller to prevent the
+     * platform from playing sounds when it discovers a tag.
+     */
+    public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
+
+    /**
+     * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+     * <p>
+     * Setting this integer extra allows the calling application to specify
+     * the delay that the platform will use for performing presence checks
+     * on any discovered tag.
+     */
+    public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
+
     /** @hide */
     public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
 
@@ -227,6 +289,7 @@
     // recovery
     static INfcAdapter sService;
     static INfcTag sTagService;
+    static INfcCardEmulation sCardEmulationService;
 
     /**
      * The NfcAdapter object for each application context.
@@ -246,6 +309,14 @@
     final Context mContext;
 
     /**
+     * A callback to be invoked when the system has found a tag in
+     * reader mode.
+     */
+    public interface ReaderCallback {
+        public void onTagDiscovered(Tag tag);
+    }
+
+    /**
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
      * to another device.
      * @see #setOnNdefPushCompleteCallback
@@ -348,6 +419,13 @@
                 throw new UnsupportedOperationException();
             }
 
+            try {
+                sCardEmulationService = sService.getNfcCardEmulationInterface();
+            } catch (RemoteException e) {
+                Log.e(TAG, "could not retrieve card emulation service");
+                throw new UnsupportedOperationException();
+            }
+
             sIsInitialized = true;
         }
         if (context == null) {
@@ -456,6 +534,15 @@
     }
 
     /**
+     * Returns the binder interface to the card emulation service.
+     * @hide
+     */
+    public INfcCardEmulation getCardEmulationService() {
+        isEnabled();
+        return sCardEmulationService;
+    }
+
+    /**
      * NFC service dead - attempt best effort recovery
      * @hide
      */
@@ -477,6 +564,13 @@
             Log.e(TAG, "could not retrieve NFC tag service during service recovery");
             // nothing more can be done now, sService is still stale, we'll hit
             // this recovery path again later
+            return;
+        }
+
+        try {
+            sCardEmulationService = service.getNfcCardEmulationInterface();
+        } catch (RemoteException ee) {
+            Log.e(TAG, "could not retrieve NFC card emulation service during service recovery");
         }
 
         return;
@@ -1088,6 +1182,43 @@
     }
 
     /**
+     * Limit the NFC controller to reader mode while this Activity is in the foreground.
+     *
+     * <p>In this mode the NFC controller will only act as an NFC tag reader/writer,
+     * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of
+     * the NFC adapter on this device.
+     *
+     * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from
+     * performing any NDEF checks in reader mode. Note that this will prevent the
+     * {@link Ndef} tag technology from being enumerated on the tag, and that
+     * NDEF-based tag dispatch will not be functional.
+     *
+     * <p>For interacting with tags that are emulated on another Android device
+     * using Android's host-based card-emulation, the recommended flags are
+     * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
+     *
+     * @param activity the Activity that requests the adapter to be in reader mode
+     * @param callback the callback to be called when a tag is discovered
+     * @param flags Flags indicating poll technologies and other optional parameters
+     * @param extras Additional extras for configuring reader mode.
+     */
+    public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
+            Bundle extras) {
+        mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
+    }
+
+    /**
+     * Restore the NFC adapter to normal mode of operation: supporting
+     * peer-to-peer (Android Beam), card emulation, and polling for
+     * all supported tag technologies.
+     *
+     * @param activity the Activity that currently has reader mode enabled
+     */
+    public void disableReaderMode(Activity activity) {
+        mNfcActivityManager.disableReaderMode(activity);
+    }
+
+    /**
      * Enable NDEF message push over NFC while this Activity is in the foreground.
      *
      * <p>You must explicitly call this method every time the activity is
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl b/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl
new file mode 100644
index 0000000..a62fdd6
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.nfc.cardemulation;
+
+parcelable ApduServiceInfo;
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
new file mode 100644
index 0000000..d7ef4bc
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -0,0 +1,442 @@
+/*
+ * 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 android.nfc.cardemulation;
+
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+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.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public final class ApduServiceInfo implements Parcelable {
+    static final String TAG = "ApduServiceInfo";
+
+    /**
+     * The service that implements this
+     */
+    final ResolveInfo mService;
+
+    /**
+     * Description of the service
+     */
+    final String mDescription;
+
+    /**
+     * Convenience AID list
+     */
+    final ArrayList<String> mAids;
+
+    /**
+     * Whether this service represents AIDs running on the host CPU
+     */
+    final boolean mOnHost;
+
+    /**
+     * All AID groups this service handles
+     */
+    final ArrayList<AidGroup> mAidGroups;
+
+    /**
+     * Convenience hashmap
+     */
+    final HashMap<String, AidGroup> mCategoryToGroup;
+
+    /**
+     * Whether this service should only be started when the device is unlocked.
+     */
+    final boolean mRequiresDeviceUnlock;
+
+    /**
+     * The id of the service banner specified in XML.
+     */
+    final int mBannerResourceId;
+
+    /**
+     * @hide
+     */
+    public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
+            ArrayList<AidGroup> aidGroups, boolean requiresUnlock, int bannerResource) {
+        this.mService = info;
+        this.mDescription = description;
+        this.mAidGroups = aidGroups;
+        this.mAids = new ArrayList<String>();
+        this.mCategoryToGroup = new HashMap<String, AidGroup>();
+        this.mOnHost = onHost;
+        this.mRequiresDeviceUnlock = requiresUnlock;
+        for (AidGroup aidGroup : aidGroups) {
+            this.mCategoryToGroup.put(aidGroup.category, aidGroup);
+            this.mAids.addAll(aidGroup.aids);
+        }
+        this.mBannerResourceId = bannerResource;
+    }
+
+    public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost)
+            throws XmlPullParserException, IOException {
+        ServiceInfo si = info.serviceInfo;
+        XmlResourceParser parser = null;
+        try {
+            if (onHost) {
+                parser = si.loadXmlMetaData(pm, HostApduService.SERVICE_META_DATA);
+                if (parser == null) {
+                    throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
+                            " meta-data");
+                }
+            } else {
+                parser = si.loadXmlMetaData(pm, OffHostApduService.SERVICE_META_DATA);
+                if (parser == null) {
+                    throw new XmlPullParserException("No " + OffHostApduService.SERVICE_META_DATA +
+                            " meta-data");
+                }
+            }
+
+            int eventType = parser.getEventType();
+            while (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_DOCUMENT) {
+                eventType = parser.next();
+            }
+
+            String tagName = parser.getName();
+            if (onHost && !"host-apdu-service".equals(tagName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with <host-apdu-service> tag");
+            } else if (!onHost && !"offhost-apdu-service".equals(tagName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with <offhost-apdu-service> tag");
+            }
+
+            Resources res = pm.getResourcesForApplication(si.applicationInfo);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            if (onHost) {
+                TypedArray sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.HostApduService);
+                mService = info;
+                mDescription = sa.getString(
+                        com.android.internal.R.styleable.HostApduService_description);
+                mRequiresDeviceUnlock = sa.getBoolean(
+                        com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
+                        false);
+                mBannerResourceId = sa.getResourceId(
+                        com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
+                sa.recycle();
+            } else {
+                TypedArray sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.OffHostApduService);
+                mService = info;
+                mDescription = sa.getString(
+                        com.android.internal.R.styleable.OffHostApduService_description);
+                mRequiresDeviceUnlock = false;
+                mBannerResourceId = sa.getResourceId(
+                        com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
+                sa.recycle();
+            }
+
+            mAidGroups = new ArrayList<AidGroup>();
+            mCategoryToGroup = new HashMap<String, AidGroup>();
+            mAids = new ArrayList<String>();
+            mOnHost = onHost;
+            final int depth = parser.getDepth();
+            AidGroup currentGroup = null;
+
+            // Parsed values for the current AID group
+            while (((eventType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                    && eventType != XmlPullParser.END_DOCUMENT) {
+                tagName = parser.getName();
+                if (eventType == XmlPullParser.START_TAG && "aid-group".equals(tagName) &&
+                        currentGroup == null) {
+                    final TypedArray groupAttrs = res.obtainAttributes(attrs,
+                            com.android.internal.R.styleable.AidGroup);
+                    // Get category of AID group
+                    String groupDescription = groupAttrs.getString(
+                            com.android.internal.R.styleable.AidGroup_description);
+                    String groupCategory = groupAttrs.getString(
+                            com.android.internal.R.styleable.AidGroup_category);
+                    if (!CardEmulation.CATEGORY_PAYMENT.equals(groupCategory)) {
+                        groupCategory = CardEmulation.CATEGORY_OTHER;
+                    }
+                    currentGroup = mCategoryToGroup.get(groupCategory);
+                    if (currentGroup != null) {
+                        if (!CardEmulation.CATEGORY_OTHER.equals(groupCategory)) {
+                            Log.e(TAG, "Not allowing multiple aid-groups in the " +
+                                    groupCategory + " category");
+                            currentGroup = null;
+                        }
+                    } else {
+                        currentGroup = new AidGroup(groupCategory, groupDescription);
+                    }
+                    groupAttrs.recycle();
+                } else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
+                        currentGroup != null) {
+                    if (currentGroup.aids.size() > 0) {
+                        if (!mCategoryToGroup.containsKey(currentGroup.category)) {
+                            mAidGroups.add(currentGroup);
+                            mCategoryToGroup.put(currentGroup.category, currentGroup);
+                        }
+                    } else {
+                        Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
+                    }
+                    currentGroup = null;
+                } else if (eventType == XmlPullParser.START_TAG && "aid-filter".equals(tagName) &&
+                        currentGroup != null) {
+                    final TypedArray a = res.obtainAttributes(attrs,
+                            com.android.internal.R.styleable.AidFilter);
+                    String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
+                            toUpperCase();
+                    if (isValidAid(aid) && !currentGroup.aids.contains(aid)) {
+                        currentGroup.aids.add(aid);
+                        mAids.add(aid);
+                    } else {
+                        Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
+                    }
+                    a.recycle();
+                }
+            }
+        } catch (NameNotFoundException e) {
+            throw new XmlPullParserException("Unable to create context for: " + si.packageName);
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    public ComponentName getComponent() {
+        return new ComponentName(mService.serviceInfo.packageName,
+                mService.serviceInfo.name);
+    }
+
+    public ArrayList<String> getAids() {
+        return mAids;
+    }
+
+    public ArrayList<AidGroup> getAidGroups() {
+        return mAidGroups;
+    }
+
+    public boolean hasCategory(String category) {
+        return mCategoryToGroup.containsKey(category);
+    }
+
+    public boolean isOnHost() {
+        return mOnHost;
+    }
+
+    public boolean requiresUnlock() {
+        return mRequiresDeviceUnlock;
+    }
+
+    public String getDescription() {
+        return mDescription;
+    }
+
+    public CharSequence loadLabel(PackageManager pm) {
+        return mService.loadLabel(pm);
+    }
+
+    public Drawable loadIcon(PackageManager pm) {
+        return mService.loadIcon(pm);
+    }
+
+    public Drawable loadBanner(PackageManager pm) {
+        Resources res;
+        try {
+            res = pm.getResourcesForApplication(mService.serviceInfo.packageName);
+            Drawable banner = res.getDrawable(mBannerResourceId);
+            return banner;
+        } catch (NotFoundException e) {
+            Log.e(TAG, "Could not load banner.");
+            return null;
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Could not load banner.");
+            return null;
+        }
+    }
+
+    static boolean isValidAid(String aid) {
+        if (aid == null)
+            return false;
+
+        int aidLength = aid.length();
+        if (aidLength == 0 || (aidLength % 2) != 0) {
+            Log.e(TAG, "AID " + aid + " is not correctly formatted.");
+            return false;
+        }
+        // Minimum AID length is 5 bytes, 10 hex chars
+        if (aidLength < 10) {
+            Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder out = new StringBuilder("ApduService: ");
+        out.append(getComponent());
+        out.append(", description: " + mDescription);
+        out.append(", AID Groups: ");
+        for (AidGroup aidGroup : mAidGroups) {
+            out.append(aidGroup.toString());
+        }
+        return out.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ApduServiceInfo)) return false;
+        ApduServiceInfo thatService = (ApduServiceInfo) o;
+
+        return thatService.getComponent().equals(this.getComponent());
+    }
+
+    @Override
+    public int hashCode() {
+        return getComponent().hashCode();
+    }
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        mService.writeToParcel(dest, flags);
+        dest.writeString(mDescription);
+        dest.writeInt(mOnHost ? 1 : 0);
+        dest.writeInt(mAidGroups.size());
+        if (mAidGroups.size() > 0) {
+            dest.writeTypedList(mAidGroups);
+        }
+        dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
+        dest.writeInt(mBannerResourceId);
+    };
+
+    public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
+            new Parcelable.Creator<ApduServiceInfo>() {
+        @Override
+        public ApduServiceInfo createFromParcel(Parcel source) {
+            ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
+            String description = source.readString();
+            boolean onHost = (source.readInt() != 0) ? true : false;
+            ArrayList<AidGroup> aidGroups = new ArrayList<AidGroup>();
+            int numGroups = source.readInt();
+            if (numGroups > 0) {
+                source.readTypedList(aidGroups, AidGroup.CREATOR);
+            }
+            boolean requiresUnlock = (source.readInt() != 0) ? true : false;
+            int bannerResource = source.readInt();
+            return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock, bannerResource);
+        }
+
+        @Override
+        public ApduServiceInfo[] newArray(int size) {
+            return new ApduServiceInfo[size];
+        }
+    };
+
+    public static class AidGroup implements Parcelable {
+        final ArrayList<String> aids;
+        final String category;
+        final String description;
+
+        AidGroup(ArrayList<String> aids, String category, String description) {
+            this.aids = aids;
+            this.category = category;
+            this.description = description;
+        }
+
+        AidGroup(String category, String description) {
+            this.aids = new ArrayList<String>();
+            this.category = category;
+            this.description = description;
+        }
+
+        public String getCategory() {
+            return category;
+        }
+
+        public ArrayList<String> getAids() {
+            return aids;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder out = new StringBuilder("Category: " + category +
+                      ", description: " + description + ", AIDs:");
+            for (String aid : aids) {
+                out.append(aid);
+                out.append(", ");
+            }
+            return out.toString();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(category);
+            dest.writeString(description);
+            dest.writeInt(aids.size());
+            if (aids.size() > 0) {
+                dest.writeStringList(aids);
+            }
+        }
+
+        public static final Parcelable.Creator<ApduServiceInfo.AidGroup> CREATOR =
+                new Parcelable.Creator<ApduServiceInfo.AidGroup>() {
+
+            @Override
+            public AidGroup createFromParcel(Parcel source) {
+                String category = source.readString();
+                String description = source.readString();
+                int listSize = source.readInt();
+                ArrayList<String> aidList = new ArrayList<String>();
+                if (listSize > 0) {
+                    source.readStringList(aidList);
+                }
+                return new AidGroup(aidList, category, description);
+            }
+
+            @Override
+            public AidGroup[] newArray(int size) {
+                return new AidGroup[size];
+            }
+        };
+    }
+}
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
new file mode 100644
index 0000000..3cd7863
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -0,0 +1,343 @@
+/*
+ * 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 android.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.ActivityThread;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.nfc.INfcCardEmulation;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.List;
+
+public final class CardEmulation {
+    static final String TAG = "CardEmulation";
+
+    /**
+     * Activity action: ask the user to change the default
+     * card emulation service for a certain category. This will
+     * show a dialog that asks the user whether he wants to
+     * replace the current default service with the service
+     * identified with the ComponentName specified in
+     * {@link #EXTRA_SERVICE_COMPONENT}, for the category
+     * specified in {@link #EXTRA_CATEGORY}
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CHANGE_DEFAULT =
+            "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
+
+    /**
+     * The category extra for {@link #ACTION_CHANGE_DEFAULT}
+     *
+     * @see #ACTION_CHANGE_DEFAULT
+     */
+    public static final String EXTRA_CATEGORY = "category";
+
+    /**
+     * The ComponentName object passed in as a parcelable
+     * extra for {@link #ACTION_CHANGE_DEFAULT}
+     *
+     * @see #ACTION_CHANGE_DEFAULT
+     */
+    public static final String EXTRA_SERVICE_COMPONENT = "component";
+
+    /**
+     * The payment category can be used to indicate that an AID
+     * represents a payment application.
+     */
+    public static final String CATEGORY_PAYMENT = "payment";
+
+    /**
+     * If an AID group does not contain a category, or the
+     * specified category is not defined by the platform version
+     * that is parsing the AID group, all AIDs in the group will
+     * automatically be categorized under the {@link #CATEGORY_OTHER}
+     * category.
+     */
+    public static final String CATEGORY_OTHER = "other";
+
+    /**
+     * Return value for {@link #getSelectionModeForCategory(String)}.
+     *
+     * <p>In this mode, the user has set a default service for this
+     *    AID category. If a remote reader selects any of the AIDs
+     *    that the default service has registered in this category,
+     *    that service will automatically be bound to to handle
+     *    the transaction.
+     *
+     * <p>There are still cases where a service that is
+     *    not the default for a category can selected:
+     *    <p>
+     *    If a remote reader selects an AID in this category
+     *    that is not handled by the default service, and there is a set
+     *    of other services {S} that do handle this AID, the
+     *    user is asked if he wants to use any of the services in
+     *    {S} instead.
+     *    <p>
+     *    As a special case, if the size of {S} is one, containing a single service X,
+     *    and all AIDs X has registered in this category are not
+     *    registered by any other service, then X will be
+     *    selected automatically without asking the user.
+     *    <p>Example:
+     *    <ul>
+     *    <li>Service A registers AIDs "1", "2" and "3" in the category
+     *    <li>Service B registers AIDs "3" and "4" in the category
+     *    <li>Service C registers AIDs "5" and "6" in the category
+     *    </ul>
+     *    In this case, the following will happen when service A
+     *    is the default:
+     *    <ul>
+     *    <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
+     *    <li>Reader selects AID "4": the user is asked to confirm he
+     *        wants to use service B, because its AIDs overlap with service A.
+     *    <li>Reader selects AID "5" or "6": service C is invoked automatically,
+     *        because all AIDs it has asked for are only registered by C,
+     *        and there is no overlap.
+     *    </ul>
+     *
+     */
+    public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
+
+    /**
+     * Return value for {@link #getSelectionModeForCategory(String)}.
+     *
+     * <p>In this mode, whenever an AID of this category is selected,
+     *    the user is asked which service he wants to use to handle
+     *    the transaction, even if there is only one matching service.
+     */
+    public static final int SELECTION_MODE_ALWAYS_ASK = 1;
+
+    /**
+     * Return value for {@link #getSelectionModeForCategory(String)}.
+     *
+     * <p>In this mode, the user will only be asked to select a service
+     *    if the selected AID has been registered by multiple applications.
+     */
+    public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
+
+    static boolean sIsInitialized = false;
+    static HashMap<Context, CardEmulation> sCardEmus = new HashMap();
+    static INfcCardEmulation sService;
+
+    final Context mContext;
+
+    private CardEmulation(Context context, INfcCardEmulation service) {
+        mContext = context.getApplicationContext();
+        sService = service;
+    }
+
+    public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
+        if (adapter == null) throw new NullPointerException("NfcAdapter is null");
+        Context context = adapter.getContext();
+        if (context == null) {
+            Log.e(TAG, "NfcAdapter context is null.");
+            throw new UnsupportedOperationException();
+        }
+        if (!sIsInitialized) {
+            IPackageManager pm = ActivityThread.getPackageManager();
+            if (pm == null) {
+                Log.e(TAG, "Cannot get PackageManager");
+                throw new UnsupportedOperationException();
+            }
+            try {
+                if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
+                    Log.e(TAG, "This device does not support card emulation");
+                    throw new UnsupportedOperationException();
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "PackageManager query failed.");
+                throw new UnsupportedOperationException();
+            }
+            sIsInitialized = true;
+        }
+        CardEmulation manager = sCardEmus.get(context);
+        if (manager == null) {
+            // Get card emu service
+            INfcCardEmulation service = adapter.getCardEmulationService();
+            manager = new CardEmulation(context, service);
+            sCardEmus.put(context, manager);
+        }
+        return manager;
+    }
+
+    /**
+     * Allows an application to query whether a service is currently
+     * the default service to handle a card emulation category.
+     *
+     * <p>Note that if {@link #getSelectionModeForCategory(String)}
+     * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
+     * return false.
+     *
+     * @param service The ComponentName of the service
+     * @param category The category
+     * @return whether service is currently the default service for the category.
+     */
+    public boolean isDefaultServiceForCategory(ComponentName service, String category) {
+        try {
+            return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
+                        category);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     *
+     * Allows an application to query whether a service is currently
+     * the default handler for a specified ISO7816-4 Application ID.
+     *
+     * @param service The ComponentName of the service
+     * @param aid The ISO7816-4 Application ID
+     * @return
+     */
+    public boolean isDefaultServiceForAid(ComponentName service, String aid) {
+        try {
+            return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Returns the application selection mode for the passed in category.
+     * Valid return values are:
+     * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
+     *    application for this category, which will be preferred.
+     * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
+     *    every time what app he would like to use in this category.
+     * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
+     *    to pick a service if there is a conflict.
+     * @param category The category, for example {@link #CATEGORY_PAYMENT}
+     * @return
+     */
+    public int getSelectionModeForCategory(String category) {
+        if (CATEGORY_PAYMENT.equals(category)) {
+            String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
+                    Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
+            if (defaultComponent != null) {
+                return SELECTION_MODE_PREFER_DEFAULT;
+            } else {
+                return SELECTION_MODE_ALWAYS_ASK;
+            }
+        } else {
+            // All other categories are in "only ask if conflict" mode
+            return SELECTION_MODE_ASK_IF_CONFLICT;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public boolean setDefaultServiceForCategory(ComponentName service, String category) {
+        try {
+            return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service,
+                        category);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public boolean setDefaultForNextTap(ComponentName service) {
+        try {
+            return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+    /**
+     * @hide
+     */
+    public List<ApduServiceInfo> getServices(String category) {
+        try {
+            return sService.getServices(UserHandle.myUserId(), category);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                return sService.getServices(UserHandle.myUserId(), category);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    void recoverService() {
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        sService = adapter.getCardEmulationService();
+    }
+}
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
new file mode 100644
index 0000000..e2c3ca6
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -0,0 +1,278 @@
+package android.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * <p>A convenience class that can be extended to implement
+ * a service that processes ISO7816-4 commands on top of
+ * the ISO14443-4 / IsoDep protocol (T=CL).
+ *
+ * <p>To tell the platform which ISO7816 application ID (AIDs)
+ * are implemented by this service, a {@link #SERVICE_META_DATA}
+ * entry must be included in the declaration of the service. An
+ * example of such a service declaration is shown below:
+ * <pre> &lt;service android:name=".MyHostApduService"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.nfc.HostApduService"/&gt;
+ *     &lt;/intent-filter&gt;
+ *     &lt;meta-data android:name="android.nfc.HostApduService" android:resource="@xml/apduservice.xml"/&gt;
+ * &lt;/service&gt;</pre>
+ * <p>For more details refer to {@link #SERVICE_META_DATA},
+ * <code>&lt;{@link android.R.styleable#HostApduService host-apdu-service}&gt;</code>,
+ * <code>&lt;{@link android.R.styleable#AidGroup aid-group}&gt;</code> and
+ * <code>&lt;{@link android.R.styleable#AidFilter aid-filter}&gt;</code>.
+ * <p class="note">The Android platform currently only supports a single
+ * logical channel.
+ */
+public abstract class HostApduService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
+
+    /**
+     * The name of the meta-data element that contains
+     * more information about this service.
+     */
+    public static final String SERVICE_META_DATA =
+            "android.nfc.cardemulation.host_apdu_service";
+
+    /**
+     * Reason for {@link #onDeactivated(int)}.
+     * Indicates deactivation was due to the NFC link
+     * being lost.
+     */
+    public static final int DEACTIVATION_LINK_LOSS = 0;
+
+    /**
+     * Reason for {@link #onDeactivated(int)}.
+     *
+     * <p>Indicates deactivation was due to a different AID
+     * being selected (which implicitly deselects the AID
+     * currently active on the logical channel).
+     *
+     * <p>Note that this next AID may still be resolved to this
+     * service, in which case {@link #processCommandApdu(byte[], Bundle)}
+     * will be called again.
+     */
+    public static final int DEACTIVATION_DESELECTED = 1;
+
+    static final String TAG = "ApduService";
+
+    /**
+     * MSG_COMMAND_APDU is sent by NfcService when
+     * a 7816-4 command APDU has been received.
+     *
+     * @hide
+     */
+    public static final int MSG_COMMAND_APDU = 0;
+
+    /**
+     * MSG_RESPONSE_APDU is sent to NfcService to send
+     * a response APDU back to the remote device.
+     *
+     * @hide
+     */
+    public static final int MSG_RESPONSE_APDU = 1;
+
+    /**
+     * MSG_DEACTIVATED is sent by NfcService when
+     * the current session is finished; either because
+     * another AID was selected that resolved to
+     * another service, or because the NFC link
+     * was deactivated.
+     *
+     * @hide
+     */
+    public static final int MSG_DEACTIVATED = 2;
+
+    /**
+     *
+     * @hide
+     */
+    public static final int MSG_UNHANDLED = 3;
+
+    /**
+     * @hide
+     */
+    public static final String KEY_DATA = "data";
+
+    /**
+     * Messenger interface to NfcService for sending responses.
+     * Only accessed on main thread by the message handler.
+     *
+     * @hide
+     */
+    Messenger mNfcService = null;
+
+    final Messenger mMessenger = new Messenger(new MsgHandler());
+
+    final class MsgHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_COMMAND_APDU:
+                Bundle dataBundle = msg.getData();
+                if (dataBundle == null) {
+                    return;
+                }
+                if (mNfcService == null) mNfcService = msg.replyTo;
+
+                byte[] apdu = dataBundle.getByteArray(KEY_DATA);
+                if (apdu != null) {
+                    byte[] responseApdu = processCommandApdu(apdu, null);
+                    if (responseApdu != null) {
+                        if (mNfcService == null) {
+                            Log.e(TAG, "Response not sent; service was deactivated.");
+                            return;
+                        }
+                        Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU);
+                        Bundle responseBundle = new Bundle();
+                        responseBundle.putByteArray(KEY_DATA, responseApdu);
+                        responseMsg.setData(responseBundle);
+                        responseMsg.replyTo = mMessenger;
+                        try {
+                            mNfcService.send(responseMsg);
+                        } catch (RemoteException e) {
+                            Log.e("TAG", "Response not sent; RemoteException calling into " +
+                                    "NfcService.");
+                        }
+                    }
+                } else {
+                    Log.e(TAG, "Received MSG_COMMAND_APDU without data.");
+                }
+                break;
+            case MSG_RESPONSE_APDU:
+                if (mNfcService == null) {
+                    Log.e(TAG, "Response not sent; service was deactivated.");
+                    return;
+                }
+                try {
+                    msg.replyTo = mMessenger;
+                    mNfcService.send(msg);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException calling into NfcService.");
+                }
+                break;
+            case MSG_DEACTIVATED:
+                // Make sure we won't call into NfcService again
+                mNfcService = null;
+                onDeactivated(msg.arg1);
+                break;
+            case MSG_UNHANDLED:
+                if (mNfcService == null) {
+                    Log.e(TAG, "notifyUnhandled not sent; service was deactivated.");
+                    return;
+                }
+                try {
+                    msg.replyTo = mMessenger;
+                    mNfcService.send(msg);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException calling into NfcService.");
+                }
+                break;
+            default:
+                super.handleMessage(msg);
+            }
+        }
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    /**
+     * Sends a response APDU back to the remote device.
+     *
+     * <p>Note: this method may be called from any thread and will not block.
+     * @param responseApdu A byte-array containing the reponse APDU.
+     */
+    public final void sendResponseApdu(byte[] responseApdu) {
+        Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU);
+        Bundle dataBundle = new Bundle();
+        dataBundle.putByteArray(KEY_DATA, responseApdu);
+        responseMsg.setData(dataBundle);
+        try {
+            mMessenger.send(responseMsg);
+        } catch (RemoteException e) {
+            Log.e("TAG", "Local messenger has died.");
+        }
+    }
+
+    /**
+     * Calling this method allows the service to tell the OS
+     * that it won't be able to complete this transaction -
+     * for example, because it requires data connectivity
+     * that is not present at that moment.
+     *
+     * The OS may use this indication to give the user a list
+     * of alternative applications that can handle the last
+     * AID that was selected. If the user would select an
+     * application from the list, that action by itself
+     * will not cause the default to be changed; the selected
+     * application will be invoked for the next tap only.
+     *
+     * If there are no other applications that can handle
+     * this transaction, the OS will show an error dialog
+     * indicating your service could not complete the
+     * transaction.
+     *
+     * <p>Note: this method may be called anywhere between
+     *    the first {@link #processCommandApdu(byte[], Bundle)}
+     *    call and a {@link #onDeactivated(int)} call.
+     */
+    public final void notifyUnhandled() {
+        Message unhandledMsg = Message.obtain(null, MSG_UNHANDLED);
+        try {
+            mMessenger.send(unhandledMsg);
+        } catch (RemoteException e) {
+            Log.e("TAG", "Local messenger has died.");
+        }
+    }
+
+
+    /**
+     * <p>This method will be called when a command APDU has been received
+     * from a remote device. A response APDU can be provided directly
+     * by returning a byte-array in this method. Note that in general
+     * response APDUs must be sent as quickly as possible, given the fact
+     * that the user is likely holding his device over an NFC reader
+     * when this method is called.
+     *
+     * <p class="note">If there are multiple services that have registered for the same
+     * AIDs in their meta-data entry, you will only get called if the user has
+     * explicitly selected your service, either as a default or just for the next tap.
+     *
+     * <p class="note">This method is running on the main thread of your application.
+     * If you cannot return a response APDU immediately, return null
+     * and use the {@link #sendResponseApdu(byte[])} method later.
+     *
+     * @param commandApdu The APDU that received from the remote device
+     * @param extras A bundle containing extra data. May be null.
+     * @return a byte-array containing the response APDU, or null if no
+     *         response APDU can be sent at this point.
+     */
+    public abstract byte[] processCommandApdu(byte[] commandApdu, Bundle extras);
+
+    /**
+     * This method will be called in two possible scenarios:
+     * <li>The NFC link has been deactivated or lost
+     * <li>A different AID has been selected and was resolved to a different
+     *     service component
+     * @param reason Either {@link #DEACTIVATION_LINK_LOSS} or {@link #DEACTIVATION_DESELECTED}
+     */
+    public abstract void onDeactivated(int reason);
+}
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
new file mode 100644
index 0000000..15f63f9
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -0,0 +1,69 @@
+package android.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * <p>A convenience class that can be extended to implement
+ * a service that registers ISO7814-4 AIDs that reside off-host,
+ * for example on an embedded secure element or UICC.
+ *
+ * <p>This registration will allow the service to be included
+ * as an option for handling these AIDs on non-host execution
+ * environments. The Operating System will take care of correctly
+ * routing the AIDs, based on which service the user has selected
+ * to be the handler for an AID.
+ *
+ * <p>The service may define additional actions outside of the
+ * Android namespace that provide further interaction with
+ * the off-host execution environment.
+ *
+ * <p>To tell the platform which ISO7816 application ID (AIDs)
+ * are present and handled by the app containing this service,
+ * a {@link #SERVICE_META_DATA} entry must be included in the declaration
+ * of the service. An example of such a service declaration is shown below:
+ * <pre> &lt;service android:name=".MyOffHostApduService"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.nfc.OffHostApduService"/&gt;
+ *     &lt;/intent-filter&gt;
+ *     &lt;meta-data android:name="android.nfc.OffHostApduService" android:resource="@xml/apduservice.xml"/&gt;
+ * &lt;/service&gt;</pre>
+ * <p>For more details refer to {@link #SERVICE_META_DATA},
+ * <code>&lt;{@link android.R.styleable#OffHostApduService offhost-apdu-service}&gt;</code>,
+ * <code>&lt;{@link android.R.styleable#AidGroup aid-group}&gt;</code> and
+ * <code>&lt;{@link android.R.styleable#AidFilter aid-filter}&gt;</code>.
+ */
+public abstract class OffHostApduService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
+
+    /**
+     * The name of the meta-data element that contains
+     * more information about this service.
+     */
+    public static final String SERVICE_META_DATA =
+            "android.nfc.cardemulation.off_host_apdu_service";
+
+    /**
+     * The Android platform itself will not bind to this service,
+     * but merely uses its declaration to keep track of what AIDs
+     * the service is interested in. This information is then used
+     * to present the user with a list of applications that can handle
+     * an AID, as well as correctly route those AIDs either to the host (in case
+     * the user preferred a {@link HostApduService}), or to an off-host
+     * execution environment (in case the user preferred a {@link OffHostApduService}.
+     *
+     * Implementers may define additional actions outside of the
+     * Android namespace that allow further interactions with
+     * the off-host execution environment. Such implementations
+     * would need to override this method.
+     */
+    public abstract IBinder onBind(Intent intent);
+}
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index ce5f163..d4a3006 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -177,8 +177,9 @@
 public abstract class AsyncTask<Params, Progress, Result> {
     private static final String LOG_TAG = "AsyncTask";
 
-    private static final int CORE_POOL_SIZE = 5;
-    private static final int MAXIMUM_POOL_SIZE = 128;
+    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
+    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
     private static final int KEEP_ALIVE = 1;
 
     private static final ThreadFactory sThreadFactory = new ThreadFactory() {
@@ -190,7 +191,7 @@
     };
 
     private static final BlockingQueue<Runnable> sPoolWorkQueue =
-            new LinkedBlockingQueue<Runnable>(10);
+            new LinkedBlockingQueue<Runnable>(128);
 
     /**
      * An {@link Executor} that can be used to execute tasks in parallel.
diff --git a/core/java/android/os/BatteryProperties.aidl b/core/java/android/os/BatteryProperties.aidl
new file mode 100644
index 0000000..31fa7b8
--- /dev/null
+++ b/core/java/android/os/BatteryProperties.aidl
@@ -0,0 +1,19 @@
+/*
+** 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 android.os;
+
+parcelable BatteryProperties;
diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java
new file mode 100644
index 0000000..5df5214
--- /dev/null
+++ b/core/java/android/os/BatteryProperties.java
@@ -0,0 +1,87 @@
+/* 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 android.os;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class BatteryProperties implements Parcelable {
+    public boolean chargerAcOnline;
+    public boolean chargerUsbOnline;
+    public boolean chargerWirelessOnline;
+    public int batteryStatus;
+    public int batteryHealth;
+    public boolean batteryPresent;
+    public int batteryLevel;
+    public int batteryVoltage;
+    public int batteryCurrentNow;
+    public int batteryChargeCounter;
+    public int batteryTemperature;
+    public String batteryTechnology;
+
+    /*
+     * Parcel read/write code must be kept in sync with
+     * frameworks/native/services/batteryservice/BatteryProperties.cpp
+     */
+
+    private BatteryProperties(Parcel p) {
+        chargerAcOnline = p.readInt() == 1 ? true : false;
+        chargerUsbOnline = p.readInt() == 1 ? true : false;
+        chargerWirelessOnline = p.readInt() == 1 ? true : false;
+        batteryStatus = p.readInt();
+        batteryHealth = p.readInt();
+        batteryPresent = p.readInt() == 1 ? true : false;
+        batteryLevel = p.readInt();
+        batteryVoltage = p.readInt();
+        batteryCurrentNow = p.readInt();
+        batteryChargeCounter = p.readInt();
+        batteryTemperature = p.readInt();
+        batteryTechnology = p.readString();
+    }
+
+    public void writeToParcel(Parcel p, int flags) {
+        p.writeInt(chargerAcOnline ? 1 : 0);
+        p.writeInt(chargerUsbOnline ? 1 : 0);
+        p.writeInt(chargerWirelessOnline ? 1 : 0);
+        p.writeInt(batteryStatus);
+        p.writeInt(batteryHealth);
+        p.writeInt(batteryPresent ? 1 : 0);
+        p.writeInt(batteryLevel);
+        p.writeInt(batteryVoltage);
+        p.writeInt(batteryCurrentNow);
+        p.writeInt(batteryChargeCounter);
+        p.writeInt(batteryTemperature);
+        p.writeString(batteryTechnology);
+    }
+
+    public static final Parcelable.Creator<BatteryProperties> CREATOR
+        = new Parcelable.Creator<BatteryProperties>() {
+        public BatteryProperties createFromParcel(Parcel p) {
+            return new BatteryProperties(p);
+        }
+
+        public BatteryProperties[] newArray(int size) {
+            return new BatteryProperties[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 499ec77..dbaa325 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -41,7 +41,10 @@
 public abstract class BatteryStats implements Parcelable {
 
     private static final boolean LOCAL_LOGV = false;
-    
+
+    /** @hide */
+    public static final String SERVICE_NAME = "batterystats";
+
     /**
      * A constant indicating a partial wake lock timer.
      */
@@ -98,6 +101,11 @@
     public static final int VIBRATOR_ON = 9;
 
     /**
+     * A constant indicating a foreground activity timer
+     */
+    public static final int FOREGROUND_ACTIVITY = 10;
+
+    /**
      * Include all of the data in the stats, including previously saved data.
      */
     public static final int STATS_SINCE_CHARGED = 0;
@@ -125,7 +133,7 @@
     /**
      * Bump the version on this if the checkin format changes.
      */
-    private static final int BATTERY_STATS_CHECKIN_VERSION = 5;
+    private static final int BATTERY_STATS_CHECKIN_VERSION = 7;
     
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -137,6 +145,7 @@
     private static final String PROCESS_DATA = "pr";
     private static final String SENSOR_DATA = "sr";
     private static final String VIBRATOR_DATA = "vib";
+    private static final String FOREGROUND_DATA = "fg";
     private static final String WAKELOCK_DATA = "wl";
     private static final String KERNEL_WAKELOCK_DATA = "kwl";
     private static final String NETWORK_DATA = "nt";
@@ -146,6 +155,7 @@
     private static final String BATTERY_LEVEL_DATA = "lv";
     private static final String WIFI_DATA = "wfl";
     private static final String MISC_DATA = "m";
+    private static final String HISTORY_DATA = "h";
     private static final String SCREEN_BRIGHTNESS_DATA = "br";
     private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt";
     private static final String SIGNAL_SCANNING_TIME_DATA = "sst";
@@ -253,17 +263,7 @@
          * {@hide}
          */
         public abstract int getUid();
-        
-        /**
-         * {@hide}
-         */
-        public abstract long getTcpBytesReceived(int which);
-        
-        /**
-         * {@hide}
-         */
-        public abstract long getTcpBytesSent(int which);
-        
+
         public abstract void noteWifiRunningLocked();
         public abstract void noteWifiStoppedLocked();
         public abstract void noteFullWifiLockAcquiredLocked();
@@ -276,6 +276,8 @@
         public abstract void noteAudioTurnedOffLocked();
         public abstract void noteVideoTurnedOnLocked();
         public abstract void noteVideoTurnedOffLocked();
+        public abstract void noteActivityResumedLocked();
+        public abstract void noteActivityPausedLocked();
         public abstract long getWifiRunningTime(long batteryRealtime, int which);
         public abstract long getFullWifiLockTime(long batteryRealtime, int which);
         public abstract long getWifiScanTime(long batteryRealtime, int which);
@@ -283,6 +285,7 @@
                                                   int which);
         public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
         public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
+        public abstract Timer getForegroundActivityTimer();
         public abstract Timer getVibratorOnTimer();
 
         /**
@@ -295,11 +298,14 @@
         };
         
         public static final int NUM_USER_ACTIVITY_TYPES = 3;
-        
+
         public abstract void noteUserActivityLocked(int type);
         public abstract boolean hasUserActivity();
         public abstract int getUserActivityCount(int type, int which);
-        
+
+        public abstract boolean hasNetworkActivity();
+        public abstract long getNetworkActivityCount(int type, int which);
+
         public static abstract class Sensor {
             /*
              * FIXME: it's not correct to use this magic value because it
@@ -920,6 +926,15 @@
      */
     public abstract long getBluetoothOnTime(long batteryRealtime, int which);
     
+    public static final int NETWORK_MOBILE_RX_BYTES = 0;
+    public static final int NETWORK_MOBILE_TX_BYTES = 1;
+    public static final int NETWORK_WIFI_RX_BYTES = 2;
+    public static final int NETWORK_WIFI_TX_BYTES = 3;
+
+    public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_TX_BYTES + 1;
+
+    public abstract long getNetworkActivityCount(int type, int which);
+
     /**
      * Return whether we are currently running on battery.
      */
@@ -1194,13 +1209,13 @@
         pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
         pw.print(uid); pw.print(',');
         pw.print(category); pw.print(',');
-        pw.print(type); 
+        pw.print(type);
         
         for (Object arg : args) {  
-            pw.print(','); 
-            pw.print(arg); 
+            pw.print(',');
+            pw.print(arg);
         }
-        pw.print('\n');
+        pw.println();
     }
     
     /**
@@ -1229,7 +1244,7 @@
         final int NU = uidStats.size();
         
         String category = STAT_NAMES[which];
-        
+
         // Dump "battery" stat
         dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, 
                 which == STATS_SINCE_CHARGED ? getStartCount() : "N/A",
@@ -1237,16 +1252,20 @@
                 totalRealtime / 1000, totalUptime / 1000); 
         
         // Calculate total network and wakelock times across all uids.
-        long rxTotal = 0;
-        long txTotal = 0;
+        long mobileRxTotal = 0;
+        long mobileTxTotal = 0;
+        long wifiRxTotal = 0;
+        long wifiTxTotal = 0;
         long fullWakeLockTimeTotal = 0;
         long partialWakeLockTimeTotal = 0;
         
         for (int iu = 0; iu < NU; iu++) {
             Uid u = uidStats.valueAt(iu);
-            rxTotal += u.getTcpBytesReceived(which);
-            txTotal += u.getTcpBytesSent(which);
-            
+            mobileRxTotal += u.getNetworkActivityCount(NETWORK_MOBILE_RX_BYTES, which);
+            mobileTxTotal += u.getNetworkActivityCount(NETWORK_MOBILE_TX_BYTES, which);
+            wifiRxTotal += u.getNetworkActivityCount(NETWORK_WIFI_RX_BYTES, which);
+            wifiTxTotal += u.getNetworkActivityCount(NETWORK_WIFI_TX_BYTES, which);
+
             Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
             if (wakelocks.size() > 0) {
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 
@@ -1270,7 +1289,8 @@
         // Dump misc stats
         dumpLine(pw, 0 /* uid */, category, MISC_DATA,
                 screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000,
-                wifiRunningTime / 1000, bluetoothOnTime / 1000, rxTotal, txTotal, 
+                wifiRunningTime / 1000, bluetoothOnTime / 1000,
+                mobileRxTotal, mobileTxTotal, wifiRxTotal, wifiTxTotal,
                 fullWakeLockTimeTotal, partialWakeLockTimeTotal,
                 getInputEventCount(which));
         
@@ -1341,14 +1361,18 @@
             }
             Uid u = uidStats.valueAt(iu);
             // Dump Network stats per uid, if any
-            long rx = u.getTcpBytesReceived(which);
-            long tx = u.getTcpBytesSent(which);
+            long mobileRx = u.getNetworkActivityCount(NETWORK_MOBILE_RX_BYTES, which);
+            long mobileTx = u.getNetworkActivityCount(NETWORK_MOBILE_TX_BYTES, which);
+            long wifiRx = u.getNetworkActivityCount(NETWORK_WIFI_RX_BYTES, which);
+            long wifiTx = u.getNetworkActivityCount(NETWORK_WIFI_TX_BYTES, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
             long wifiScanTime = u.getWifiScanTime(batteryRealtime, which);
             long uidWifiRunningTime = u.getWifiRunningTime(batteryRealtime, which);
-            
-            if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
-            
+
+            if (mobileRx > 0 || mobileTx > 0 || wifiRx > 0 || wifiTx > 0) {
+                dumpLine(pw, uid, category, NETWORK_DATA, mobileRx, mobileTx, wifiRx, wifiTx);
+            }
+
             if (fullWifiLockOnTime != 0 || wifiScanTime != 0
                     || uidWifiRunningTime != 0) {
                 dumpLine(pw, uid, category, WIFI_DATA,
@@ -1384,7 +1408,11 @@
                     
                     // Only log if we had at lease one wakelock...
                     if (sb.length() > 0) {
-                       dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString());
+                        String name = ent.getKey();
+                        if (name.indexOf(',') >= 0) {
+                            name = name.replace(',', '_');
+                        }
+                        dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
                     }
                 }
             }
@@ -1417,22 +1445,31 @@
                 }
             }
 
+            Timer fgTimer = u.getForegroundActivityTimer();
+            if (fgTimer != null) {
+                // Convert from microseconds to milliseconds with rounding
+                long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                int count = fgTimer.getCountLocked(which);
+                if (totalTime != 0) {
+                    dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
+                }
+            }
+
             Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
             if (processStats.size() > 0) {
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
                         : processStats.entrySet()) {
                     Uid.Proc ps = ent.getValue();
-    
-                    long userTime = ps.getUserTime(which);
-                    long systemTime = ps.getSystemTime(which);
-                    int starts = ps.getStarts(which);
-    
-                    if (userTime != 0 || systemTime != 0 || starts != 0) {
-                        dumpLine(pw, uid, category, PROCESS_DATA, 
-                                ent.getKey(), // proc
-                                userTime * 10, // cpu time in ms
-                                systemTime * 10, // user time in ms
-                                starts); // process starts
+
+                    final long userMillis = ps.getUserTime(which) * 10;
+                    final long systemMillis = ps.getSystemTime(which) * 10;
+                    final long foregroundMillis = ps.getForegroundTime(which) * 10;
+                    final long starts = ps.getStarts(which);
+
+                    if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
+                            || starts != 0) {
+                        dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
+                                systemMillis, foregroundMillis, starts);
                     }
                 }
             }
@@ -1551,8 +1588,10 @@
         pw.println(sb.toString());
         
         // Calculate total network and wakelock times across all uids.
-        long rxTotal = 0;
-        long txTotal = 0;
+        long mobileRxTotal = 0;
+        long mobileTxTotal = 0;
+        long wifiRxTotal = 0;
+        long wifiTxTotal = 0;
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
 
@@ -1605,9 +1644,11 @@
 
         for (int iu = 0; iu < NU; iu++) {
             Uid u = uidStats.valueAt(iu);
-            rxTotal += u.getTcpBytesReceived(which);
-            txTotal += u.getTcpBytesSent(which);
-            
+            mobileRxTotal += u.getNetworkActivityCount(NETWORK_MOBILE_RX_BYTES, which);
+            mobileTxTotal += u.getNetworkActivityCount(NETWORK_MOBILE_TX_BYTES, which);
+            wifiRxTotal += u.getNetworkActivityCount(NETWORK_WIFI_RX_BYTES, which);
+            wifiTxTotal += u.getNetworkActivityCount(NETWORK_WIFI_TX_BYTES, which);
+
             Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
             if (wakelocks.size() > 0) {
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 
@@ -1640,8 +1681,11 @@
         }
         
         pw.print(prefix);
-                pw.print("  Total received: "); pw.print(formatBytesLocked(rxTotal));
-                pw.print(", Total sent: "); pw.println(formatBytesLocked(txTotal));
+                pw.print("  Mobile total received: "); pw.print(formatBytesLocked(mobileRxTotal));
+                pw.print(", Total sent: "); pw.println(formatBytesLocked(mobileTxTotal));
+        pw.print(prefix);
+                pw.print("  Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotal));
+                pw.print(", Total sent: "); pw.println(formatBytesLocked(wifiTxTotal));
         sb.setLength(0);
         sb.append(prefix);
                 sb.append("  Total full wakelock time: "); formatTimeMs(sb,
@@ -1760,8 +1804,8 @@
             for (int i=0; i<timers.size(); i++) {
                 TimerEntry timer = timers.get(i);
                 sb.setLength(0);
-                sb.append("  Wake lock #");
-                sb.append(timer.mId);
+                sb.append("  Wake lock ");
+                UserHandle.formatUid(sb, timer.mId);
                 sb.append(" ");
                 sb.append(timer.mName);
                 printWakeLock(sb, timer.mTimer, batteryRealtime, null, which, ": ");
@@ -1779,22 +1823,32 @@
             }
             
             Uid u = uidStats.valueAt(iu);
-            
-            pw.println(prefix + "  #" + uid + ":");
+
+            pw.print(prefix);
+            pw.print("  ");
+            UserHandle.formatUid(pw, uid);
+            pw.println(":");
             boolean uidActivity = false;
             
-            long tcpReceived = u.getTcpBytesReceived(which);
-            long tcpSent = u.getTcpBytesSent(which);
+            long mobileRxBytes = u.getNetworkActivityCount(NETWORK_MOBILE_RX_BYTES, which);
+            long mobileTxBytes = u.getNetworkActivityCount(NETWORK_MOBILE_TX_BYTES, which);
+            long wifiRxBytes = u.getNetworkActivityCount(NETWORK_WIFI_RX_BYTES, which);
+            long wifiTxBytes = u.getNetworkActivityCount(NETWORK_WIFI_TX_BYTES, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
             long wifiScanTime = u.getWifiScanTime(batteryRealtime, which);
             long uidWifiRunningTime = u.getWifiRunningTime(batteryRealtime, which);
-            
-            if (tcpReceived != 0 || tcpSent != 0) {
-                pw.print(prefix); pw.print("    Network: ");
-                        pw.print(formatBytesLocked(tcpReceived)); pw.print(" received, ");
-                        pw.print(formatBytesLocked(tcpSent)); pw.println(" sent");
+
+            if (mobileRxBytes > 0 || mobileTxBytes > 0) {
+                pw.print(prefix); pw.print("    Mobile network: ");
+                        pw.print(formatBytesLocked(mobileRxBytes)); pw.print(" received, ");
+                        pw.print(formatBytesLocked(mobileTxBytes)); pw.println(" sent");
             }
-            
+            if (wifiRxBytes > 0 || wifiTxBytes > 0) {
+                pw.print(prefix); pw.print("    Wi-Fi network: ");
+                        pw.print(formatBytesLocked(wifiRxBytes)); pw.print(" received, ");
+                        pw.print(formatBytesLocked(wifiTxBytes)); pw.println(" sent");
+            }
+
             if (u.hasUserActivity()) {
                 boolean hasData = false;
                 for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
@@ -1961,6 +2015,24 @@
                 }
             }
 
+            Timer fgTimer = u.getForegroundActivityTimer();
+            if (fgTimer != null) {
+                // Convert from microseconds to milliseconds with rounding
+                long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                int count = fgTimer.getCountLocked(which);
+                if (totalTime != 0) {
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    Foreground activities: ");
+                    formatTimeMs(sb, totalTime);
+                    sb.append("realtime (");
+                    sb.append(count);
+                    sb.append(" times)");
+                    pw.println(sb.toString());
+                    uidActivity = true;
+                }
+            }
+
             Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
             if (processStats.size() > 0) {
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
@@ -1968,23 +2040,26 @@
                     Uid.Proc ps = ent.getValue();
                     long userTime;
                     long systemTime;
+                    long foregroundTime;
                     int starts;
                     int numExcessive;
 
                     userTime = ps.getUserTime(which);
                     systemTime = ps.getSystemTime(which);
+                    foregroundTime = ps.getForegroundTime(which);
                     starts = ps.getStarts(which);
                     numExcessive = which == STATS_SINCE_CHARGED
                             ? ps.countExcessivePowers() : 0;
 
-                    if (userTime != 0 || systemTime != 0 || starts != 0
+                    if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
                             || numExcessive != 0) {
                         sb.setLength(0);
                         sb.append(prefix); sb.append("    Proc ");
                                 sb.append(ent.getKey()); sb.append(":\n");
                         sb.append(prefix); sb.append("      CPU: ");
                                 formatTime(sb, userTime); sb.append("usr + ");
-                                formatTime(sb, systemTime); sb.append("krn");
+                                formatTime(sb, systemTime); sb.append("krn ; ");
+                                formatTime(sb, foregroundTime); sb.append("fg");
                         if (starts != 0) {
                             sb.append("\n"); sb.append(prefix); sb.append("      ");
                                     sb.append(starts); sb.append(" proc starts");
@@ -2042,7 +2117,7 @@
                                         sb.append(sent.getKey()); sb.append(":\n");
                                 sb.append(prefix); sb.append("        Created for: ");
                                         formatTimeMs(sb, startTime / 1000);
-                                        sb.append(" uptime\n");
+                                        sb.append("uptime\n");
                                 sb.append(prefix); sb.append("        Starts: ");
                                         sb.append(starts);
                                         sb.append(", launches: "); sb.append(launches);
@@ -2207,6 +2282,30 @@
             }
             oldState = rec.states;
         }
+
+        public void printNextItemCheckin(PrintWriter pw, HistoryItem rec, long now) {
+            pw.print(rec.time-now);
+            pw.print(",");
+            if (rec.cmd == HistoryItem.CMD_START) {
+                pw.print("start");
+            } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
+                pw.print("overflow");
+            } else {
+                pw.print(rec.batteryLevel);
+                pw.print(",");
+                pw.print(rec.states);
+                pw.print(",");
+                pw.print(rec.batteryStatus);
+                pw.print(",");
+                pw.print(rec.batteryHealth);
+                pw.print(",");
+                pw.print(rec.batteryPlugType);
+                pw.print(",");
+                pw.print((int)rec.batteryTemperature);
+                pw.print(",");
+                pw.print((int)rec.batteryVoltage);
+            }
+        }
     }
 
     /**
@@ -2215,7 +2314,7 @@
      * @param pw a Printer to receive the dump output.
      */
     @SuppressWarnings("unused")
-    public void dumpLocked(PrintWriter pw) {
+    public void dumpLocked(PrintWriter pw, boolean isUnpluggedOnly, int reqUid) {
         prepareForDumpLocked();
 
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
@@ -2267,29 +2366,41 @@
         if (didPid) {
             pw.println("");
         }
-        
-        pw.println("Statistics since last charge:");
-        pw.println("  System starts: " + getStartCount()
-                + ", currently on battery: " + getIsOnBattery());
-        dumpLocked(pw, "", STATS_SINCE_CHARGED, -1);
-        pw.println("");
+
+        if (!isUnpluggedOnly) {
+            pw.println("Statistics since last charge:");
+            pw.println("  System starts: " + getStartCount()
+                    + ", currently on battery: " + getIsOnBattery());
+            dumpLocked(pw, "", STATS_SINCE_CHARGED, reqUid);
+            pw.println("");
+        }
         pw.println("Statistics since last unplugged:");
-        dumpLocked(pw, "", STATS_SINCE_UNPLUGGED, -1);
+        dumpLocked(pw, "", STATS_SINCE_UNPLUGGED, reqUid);
     }
     
     @SuppressWarnings("unused")
-    public void dumpCheckinLocked(PrintWriter pw, String[] args, List<ApplicationInfo> apps) {
+    public void dumpCheckinLocked(
+            PrintWriter pw, List<ApplicationInfo> apps, boolean isUnpluggedOnly,
+            boolean includeHistory) {
         prepareForDumpLocked();
-
-        boolean isUnpluggedOnly = false;
         
-        for (String arg : args) {
-            if ("-u".equals(arg)) {
-                if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data");
-                isUnpluggedOnly = true;
+        long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
+
+        if (includeHistory) {
+            final HistoryItem rec = new HistoryItem();
+            if (startIteratingHistoryLocked()) {
+                HistoryPrinter hprinter = new HistoryPrinter();
+                while (getNextHistoryLocked(rec)) {
+                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                    pw.print(0); pw.print(',');
+                    pw.print(HISTORY_DATA); pw.print(',');
+                    hprinter.printNextItemCheckin(pw, rec, now);
+                    pw.println();
+                }
+                finishIteratingHistoryLocked();
             }
         }
-        
+
         if (apps != null) {
             SparseArray<ArrayList<String>> uids = new SparseArray<ArrayList<String>>();
             for (int i=0; i<apps.size(); i++) {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 7ffd30b..f4a8391 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.util.Log;
+import com.android.internal.util.FastPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
@@ -288,14 +289,27 @@
      */
     public void dump(FileDescriptor fd, String[] args) {
         FileOutputStream fout = new FileOutputStream(fd);
-        PrintWriter pw = new PrintWriter(fout);
+        PrintWriter pw = new FastPrintWriter(fout);
         try {
             final String disabled;
             synchronized (Binder.class) {
                 disabled = sDumpDisabled;
             }
             if (disabled == null) {
-                dump(fd, pw, args);
+                try {
+                    dump(fd, pw, args);
+                } catch (SecurityException e) {
+                    pw.println("Security exception: " + e.getMessage());
+                    throw e;
+                } catch (Throwable e) {
+                    // Unlike usual calls, in this case if an exception gets thrown
+                    // back to us we want to print it back in to the dump data, since
+                    // that is where the caller expects all interesting information to
+                    // go.
+                    pw.println();
+                    pw.println("Exception occurred while dumping:");
+                    e.printStackTrace(pw);
+                }
             } else {
                 pw.println(sDumpDisabled);
             }
@@ -310,7 +324,7 @@
      */
     public void dumpAsync(final FileDescriptor fd, final String[] args) {
         final FileOutputStream fout = new FileOutputStream(fd);
-        final PrintWriter pw = new PrintWriter(fout);
+        final PrintWriter pw = new FastPrintWriter(fout);
         Thread thr = new Thread("Binder.dumpAsync") {
             public void run() {
                 try {
@@ -384,17 +398,27 @@
         // but all that does is rewind it, and we just got these from an IPC,
         // so we'll just call it directly.
         boolean res;
+        // Log any exceptions as warnings, don't silently suppress them.
+        // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
         try {
             res = onTransact(code, data, reply, flags);
         } catch (RemoteException e) {
+            if ((flags & FLAG_ONEWAY) != 0) {
+                Log.w(TAG, "Binder call failed.", e);
+            }
             reply.setDataPosition(0);
             reply.writeException(e);
             res = true;
         } catch (RuntimeException e) {
+            if ((flags & FLAG_ONEWAY) != 0) {
+                Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
+            }
             reply.setDataPosition(0);
             reply.writeException(e);
             res = true;
         } catch (OutOfMemoryError e) {
+            // Unconditionally log this, since this is generally unrecoverable.
+            Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e);
             RuntimeException re = new RuntimeException("Out of memory", e);
             reply.setDataPosition(0);
             reply.writeException(re);
@@ -442,7 +466,6 @@
         data.writeStringArray(args);
         try {
             transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
-            reply.readException();
         } finally {
             data.recycle();
             reply.recycle();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6c9f2d1..88eb280 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -436,6 +436,19 @@
          * Android 4.3: Jelly Bean MR2, the revenge of the beans.
          */
         public static final int JELLY_BEAN_MR2 = 18;
+
+        /**
+         * Android X.X: KitKat, another tasty treat.
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>It is no longer allowed to use implicit intents with
+         * {@link android.content.Context#startService} or
+         * {@link android.content.Context#bindService}.
+         * </ul>
+         */
+        public static final int KITKAT = CUR_DEVELOPMENT;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index b8769b4..f47ac4e 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -16,15 +16,13 @@
 
 package android.os;
 
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -35,15 +33,17 @@
     private static final String LOG_TAG = "Bundle";
     public static final Bundle EMPTY;
 
+    static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+
     static {
         EMPTY = new Bundle();
-        EMPTY.mMap = Collections.unmodifiableMap(new HashMap<String, Object>());
+        EMPTY.mMap = ArrayMap.EMPTY;
     }
 
     // Invariant - exactly one of mMap / mParcelledData will be null
     // (except inside a call to unparcel)
 
-    /* package */ Map<String, Object> mMap = null;
+    /* package */ ArrayMap<String, Object> mMap = null;
 
     /*
      * If mParcelledData is non-null, then mMap will be null and the
@@ -65,7 +65,7 @@
      * Constructs a new, empty Bundle.
      */
     public Bundle() {
-        mMap = new HashMap<String, Object>();
+        mMap = new ArrayMap<String, Object>();
         mClassLoader = getClass().getClassLoader();
     }
 
@@ -91,7 +91,7 @@
      * inside of the Bundle.
      */
     public Bundle(ClassLoader loader) {
-        mMap = new HashMap<String, Object>();
+        mMap = new ArrayMap<String, Object>();
         mClassLoader = loader;
     }
 
@@ -102,7 +102,7 @@
      * @param capacity the initial capacity of the Bundle
      */
     public Bundle(int capacity) {
-        mMap = new HashMap<String, Object>(capacity);
+        mMap = new ArrayMap<String, Object>(capacity);
         mClassLoader = getClass().getClassLoader();
     }
 
@@ -122,7 +122,7 @@
         }
 
         if (b.mMap != null) {
-            mMap = new HashMap<String, Object>(b.mMap);
+            mMap = new ArrayMap<String, Object>(b.mMap);
         } else {
             mMap = null;
         }
@@ -162,7 +162,7 @@
         if (size == 0) {
             return null;
         }
-        Object o = mMap.values().iterator().next();
+        Object o = mMap.valueAt(0);
         try {
             return (String) o;
         } catch (ClassCastException e) {
@@ -218,9 +218,12 @@
             return;
         }
         if (mMap == null) {
-            mMap = new HashMap<String, Object>(N);
+            mMap = new ArrayMap<String, Object>(N);
+        } else {
+            mMap.erase();
+            mMap.ensureCapacity(N);
         }
-        mParcelledData.readMapInternal(mMap, N, mClassLoader);
+        mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
         mParcelledData.recycle();
         mParcelledData = null;
     }
@@ -331,9 +334,8 @@
                 }
             } else {
                 // It's been unparcelled, so we need to walk the map
-                Iterator<Map.Entry<String, Object>> iter = mMap.entrySet().iterator();
-                while (!fdFound && iter.hasNext()) {
-                    Object obj = iter.next().getValue();
+                for (int i=mMap.size()-1; i>=0; i--) {
+                    Object obj = mMap.valueAt(i);
                     if (obj instanceof Parcelable) {
                         if ((((Parcelable)obj).describeContents()
                                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
@@ -546,6 +548,13 @@
         mFdsKnown = false;
     }
 
+    /** {@hide} */
+    public void putParcelableList(String key, List<? extends Parcelable> value) {
+        unparcel();
+        mMap.put(key, value);
+        mFdsKnown = false;
+    }
+
     /**
      * Inserts a SparceArray of Parcelable values into the mapping of this
      * Bundle, replacing any existing value for the given key.  Either key
@@ -1636,14 +1645,14 @@
             if (mParcelledData != null) {
                 int length = mParcelledData.dataSize();
                 parcel.writeInt(length);
-                parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+                parcel.writeInt(BUNDLE_MAGIC);
                 parcel.appendFrom(mParcelledData, 0, length);
             } else {
                 parcel.writeInt(-1); // dummy, will hold length
-                parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+                parcel.writeInt(BUNDLE_MAGIC);
     
                 int oldPos = parcel.dataPosition();
-                parcel.writeMapInternal(mMap);
+                parcel.writeArrayMapInternal(mMap);
                 int newPos = parcel.dataPosition();
     
                 // Backpatch length
@@ -1672,11 +1681,10 @@
 
     void readFromParcelInner(Parcel parcel, int length) {
         int magic = parcel.readInt();
-        if (magic != 0x4C444E42) {
+        if (magic != BUNDLE_MAGIC) {
             //noinspection ThrowableInstanceNeverThrown
-            String st = Log.getStackTraceString(new RuntimeException());
-            Log.e("Bundle", "readBundle: bad magic number");
-            Log.e("Bundle", "readBundle: trace = " + st);
+            throw new IllegalStateException("Bad magic number for Bundle: 0x"
+                    + Integer.toHexString(magic));
         }
 
         // Advance within this Parcel
@@ -1687,10 +1695,23 @@
         p.setDataPosition(0);
         p.appendFrom(parcel, offset, length);
         p.setDataPosition(0);
-        
-        mParcelledData = p;
-        mHasFds = p.hasFileDescriptors();
-        mFdsKnown = true;
+
+        if (mMap != null) {
+            // It is not allowed to have a Bundle with both a map and a parcel, so if we
+            // already have a map then we need to immediately unparcel into it.  This also
+            // lets us know we need to go through the slow path of unparceling, since the
+            // map may already contains some data so the two need to be merged.
+            if (mFdsKnown) {
+                mHasFds |= p.hasFileDescriptors();
+            }
+            int N = p.readInt();
+            p.readArrayMapSafelyInternal(mMap, N, mClassLoader);
+            p.recycle();
+        } else {
+            mParcelledData = p;
+            mHasFds = p.hasFileDescriptors();
+            mFdsKnown = true;
+        }
     }
 
     @Override
diff --git a/core/java/android/os/CancellationSignal.java b/core/java/android/os/CancellationSignal.java
index dcba9b7..e8053d5 100644
--- a/core/java/android/os/CancellationSignal.java
+++ b/core/java/android/os/CancellationSignal.java
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.os.ICancellationSignal;
-import android.os.ICancellationSignal.Stub;
 
 /**
  * Provides the ability to cancel an operation in progress.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 989bd2c..ea9fd06 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.TypedProperties;
 
 import android.util.Log;
@@ -108,31 +109,78 @@
      * process. The returns info broken down by dalvik, native, and other. All results are in kB.
      */
     public static class MemoryInfo implements Parcelable {
-        /** The proportional set size for dalvik. */
+        /** The proportional set size for dalvik heap.  (Doesn't include other Dalvik overhead.) */
         public int dalvikPss;
-        /** The private dirty pages used by dalvik. */
+        /** The proportional set size that is swappable for dalvik heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int dalvikSwappablePss;
+        /** The private dirty pages used by dalvik heap. */
         public int dalvikPrivateDirty;
-        /** The shared dirty pages used by dalvik. */
+        /** The shared dirty pages used by dalvik heap. */
         public int dalvikSharedDirty;
+        /** The private clean pages used by dalvik heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int dalvikPrivateClean;
+        /** The shared clean pages used by dalvik heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int dalvikSharedClean;
 
         /** The proportional set size for the native heap. */
         public int nativePss;
+        /** The proportional set size that is swappable for the native heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int nativeSwappablePss;
         /** The private dirty pages used by the native heap. */
         public int nativePrivateDirty;
         /** The shared dirty pages used by the native heap. */
         public int nativeSharedDirty;
+        /** The private clean pages used by the native heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int nativePrivateClean;
+        /** The shared clean pages used by the native heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int nativeSharedClean;
 
         /** The proportional set size for everything else. */
         public int otherPss;
+        /** The proportional set size that is swappable for everything else. */
+        /** @hide We may want to expose this, eventually. */
+        public int otherSwappablePss;
         /** The private dirty pages used by everything else. */
         public int otherPrivateDirty;
         /** The shared dirty pages used by everything else. */
         public int otherSharedDirty;
+        /** The private clean pages used by everything else. */
+        /** @hide We may want to expose this, eventually. */
+        public int otherPrivateClean;
+        /** The shared clean pages used by everything else. */
+        /** @hide We may want to expose this, eventually. */
+        public int otherSharedClean;
 
         /** @hide */
-        public static final int NUM_OTHER_STATS = 10;
+        public static final int NUM_OTHER_STATS = 16;
 
-        private int[] otherStats = new int[NUM_OTHER_STATS*3];
+        /** @hide */
+        public static final int NUM_DVK_STATS = 5;
+
+        /** @hide */
+        public static final int NUM_CATEGORIES = 6;
+
+        /** @hide */
+        public static final int offsetPss = 0;
+        /** @hide */
+        public static final int offsetSwappablePss = 1;
+        /** @hide */
+        public static final int offsetPrivateDirty = 2;
+        /** @hide */
+        public static final int offsetSharedDirty = 3;
+        /** @hide */
+        public static final int offsetPrivateClean = 4;
+        /** @hide */
+        public static final int offsetSharedClean = 5;
+
+
+        private int[] otherStats = new int[(NUM_OTHER_STATS+NUM_DVK_STATS)*NUM_CATEGORIES];
 
         public MemoryInfo() {
         }
@@ -145,6 +193,22 @@
         }
 
         /**
+         * @hide Return total PSS memory usage in kB.
+         */
+        public int getTotalUss() {
+            return dalvikPrivateClean + dalvikPrivateDirty
+                    + nativePrivateClean + nativePrivateDirty
+                    + otherPrivateClean + otherPrivateDirty;
+        }
+
+        /**
+         * Return total PSS memory usage in kB.
+         */
+        public int getTotalSwappablePss() {
+            return dalvikSwappablePss + nativeSwappablePss + otherSwappablePss;
+        }
+
+        /**
          * Return total private dirty memory usage in kB.
          */
         public int getTotalPrivateDirty() {
@@ -158,35 +222,77 @@
             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
         }
 
-        /* @hide */
+        /**
+         * Return total shared clean memory usage in kB.
+         */
+        public int getTotalPrivateClean() {
+            return dalvikPrivateClean + nativePrivateClean + otherPrivateClean;
+        }
+
+        /**
+         * Return total shared clean memory usage in kB.
+         */
+        public int getTotalSharedClean() {
+            return dalvikSharedClean + nativeSharedClean + otherSharedClean;
+        }
+
+        /** @hide */
         public int getOtherPss(int which) {
-            return otherStats[which*3];
+            return otherStats[which*NUM_CATEGORIES + offsetPss];
         }
 
-        /* @hide */
+
+        /** @hide */
+        public int getOtherSwappablePss(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetSwappablePss];
+        }
+
+
+        /** @hide */
         public int getOtherPrivateDirty(int which) {
-            return otherStats[which*3 + 1];
+            return otherStats[which*NUM_CATEGORIES + offsetPrivateDirty];
         }
 
-        /* @hide */
+        /** @hide */
         public int getOtherSharedDirty(int which) {
-            return otherStats[which*3 + 2];
+            return otherStats[which*NUM_CATEGORIES + offsetSharedDirty];
+        }
+
+        /** @hide */
+        public int getOtherPrivateClean(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetPrivateClean];
         }
 
 
-        /* @hide */
+        /** @hide */
+        public int getOtherSharedClean(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetSharedClean];
+        }
+
+        /** @hide */
         public static String getOtherLabel(int which) {
             switch (which) {
-                case 0: return "Stack";
-                case 1: return "Cursor";
-                case 2: return "Ashmem";
-                case 3: return "Other dev";
-                case 4: return ".so mmap";
-                case 5: return ".jar mmap";
-                case 6: return ".apk mmap";
-                case 7: return ".ttf mmap";
-                case 8: return ".dex mmap";
-                case 9: return "Other mmap";
+                case 0: return "Dalvik Other";
+                case 1: return "Stack";
+                case 2: return "Cursor";
+                case 3: return "Ashmem";
+                case 4: return "Other dev";
+                case 5: return ".so mmap";
+                case 6: return ".jar mmap";
+                case 7: return ".apk mmap";
+                case 8: return ".ttf mmap";
+                case 9: return ".dex mmap";
+                case 10: return "code mmap";
+                case 11: return "image mmap";
+                case 12: return "Other mmap";
+                case 13: return "Graphics";
+                case 14: return "GL";
+                case 15: return "Other memtrack";
+                case 16: return ".Heap";
+                case 17: return ".LOS";
+                case 18: return ".LinearAlloc";
+                case 19: return ".GC";
+                case 20: return ".JITCache";
                 default: return "????";
             }
         }
@@ -197,27 +303,45 @@
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(dalvikPss);
+            dest.writeInt(dalvikSwappablePss);
             dest.writeInt(dalvikPrivateDirty);
             dest.writeInt(dalvikSharedDirty);
+            dest.writeInt(dalvikPrivateClean);
+            dest.writeInt(dalvikSharedClean);
             dest.writeInt(nativePss);
+            dest.writeInt(nativeSwappablePss);
             dest.writeInt(nativePrivateDirty);
             dest.writeInt(nativeSharedDirty);
+            dest.writeInt(nativePrivateClean);
+            dest.writeInt(nativeSharedClean);
             dest.writeInt(otherPss);
+            dest.writeInt(otherSwappablePss);
             dest.writeInt(otherPrivateDirty);
             dest.writeInt(otherSharedDirty);
+            dest.writeInt(otherPrivateClean);
+            dest.writeInt(otherSharedClean);
             dest.writeIntArray(otherStats);
         }
 
         public void readFromParcel(Parcel source) {
             dalvikPss = source.readInt();
+            dalvikSwappablePss = source.readInt();
             dalvikPrivateDirty = source.readInt();
             dalvikSharedDirty = source.readInt();
+            dalvikPrivateClean = source.readInt();
+            dalvikSharedClean = source.readInt();
             nativePss = source.readInt();
+            nativeSwappablePss = source.readInt();
             nativePrivateDirty = source.readInt();
             nativeSharedDirty = source.readInt();
+            nativePrivateClean = source.readInt();
+            nativeSharedClean = source.readInt();
             otherPss = source.readInt();
+            otherSwappablePss = source.readInt();
             otherPrivateDirty = source.readInt();
             otherSharedDirty = source.readInt();
+            otherPrivateClean = source.readInt();
+            otherSharedClean = source.readInt();
             otherStats = source.createIntArray();
         }
 
@@ -364,7 +488,7 @@
         PrintWriter outStream = null;
         try {
             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
-            outStream = new PrintWriter(new OutputStreamWriter(fos));
+            outStream = new FastPrintWriter(fos);
             outStream.println("1");
         } catch (Exception e) {
         } finally {
@@ -392,7 +516,7 @@
         PrintWriter outStream = null;
         try {
             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
-            outStream = new PrintWriter(new OutputStreamWriter(fos));
+            outStream = new FastPrintWriter(fos);
             outStream.println("0");
         } catch (Exception e) {
             // We could print an error message here but we probably want
@@ -611,7 +735,7 @@
 
     /**
      * Clears the global size of objects allocated.
-     * @see #getGlobalAllocCountSize()
+     * @see #getGlobalAllocSize()
      */
     public static void resetGlobalAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
@@ -891,9 +1015,38 @@
 
     /**
      * Retrieves the PSS memory used by the process as given by the
-     * smaps. @hide
+     * smaps.  Optionally supply a long array of 1 entry to also
+     * receive the uss of the process.  @hide
      */
-    public static native long getPss(int pid);
+    public static native long getPss(int pid, long[] outUss);
+
+    /** @hide */
+    public static final int MEMINFO_TOTAL = 0;
+    /** @hide */
+    public static final int MEMINFO_FREE = 1;
+    /** @hide */
+    public static final int MEMINFO_BUFFERS = 2;
+    /** @hide */
+    public static final int MEMINFO_CACHED = 3;
+    /** @hide */
+    public static final int MEMINFO_SHMEM = 4;
+    /** @hide */
+    public static final int MEMINFO_SLAB = 5;
+    /** @hide */
+    public static final int MEMINFO_SWAP_TOTAL = 6;
+    /** @hide */
+    public static final int MEMINFO_SWAP_FREE = 7;
+    /** @hide */
+    public static final int MEMINFO_ZRAM_TOTAL = 8;
+    /** @hide */
+    public static final int MEMINFO_COUNT = 9;
+
+    /**
+     * Retrieves /proc/meminfo.  outSizes is filled with fields
+     * as defined by MEMINFO_* offsets.
+     * @hide
+     */
+    public static native void getMemInfo(long[] outSizes);
 
     /**
      * Establish an object allocation limit in the current thread.
@@ -1400,7 +1553,7 @@
 
     /**
      * Return a String describing the calling method and location at a particular stack depth.
-     * @param callStack the Thread stack 
+     * @param callStack the Thread stack
      * @param depth the depth of stack to return information for.
      * @return the String describing the caller at that depth.
      */
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 61eef1f..fc53580 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.content.Context;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
@@ -40,7 +41,16 @@
     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
 
     /** {@hide} */
-    public static String DIRECTORY_ANDROID = "Android";
+    public static final String DIR_ANDROID = "Android";
+    private static final String DIR_DATA = "data";
+    private static final String DIR_MEDIA = "media";
+    private static final String DIR_OBB = "obb";
+    private static final String DIR_FILES = "files";
+    private static final String DIR_CACHE = "cache";
+
+    /** {@hide} */
+    @Deprecated
+    public static final String DIRECTORY_ANDROID = DIR_ANDROID;
 
     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
     private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media");
@@ -59,6 +69,10 @@
     private static volatile StorageVolume sPrimaryVolume;
 
     private static StorageVolume getPrimaryVolume() {
+        if (SystemProperties.getBoolean("config.disable_storage", false)) {
+            return null;
+        }
+
         if (sPrimaryVolume == null) {
             synchronized (sLock) {
                 if (sPrimaryVolume == null) {
@@ -93,33 +107,38 @@
     /** {@hide} */
     public static class UserEnvironment {
         // TODO: generalize further to create package-specific environment
+        // TODO: add support for secondary external storage
 
-        private final File mExternalStorage;
-        private final File mExternalStorageAndroidData;
-        private final File mExternalStorageAndroidMedia;
-        private final File mExternalStorageAndroidObb;
-        private final File mMediaStorage;
+        /** External storage dirs, as visible to vold */
+        private final File[] mExternalDirsForVold;
+        /** External storage dirs, as visible to apps */
+        private final File[] mExternalDirsForApp;
+        /** Primary emulated storage dir for direct access */
+        private final File mEmulatedDirForDirect;
 
         public UserEnvironment(int userId) {
             // See storage config details at http://source.android.com/tech/storage/
             String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
-            String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
+            String rawEmulatedSource = System.getenv(ENV_EMULATED_STORAGE_SOURCE);
+            String rawEmulatedTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
             String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);
             if (TextUtils.isEmpty(rawMediaStorage)) {
                 rawMediaStorage = "/data/media";
             }
 
-            if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
+            if (!TextUtils.isEmpty(rawEmulatedTarget)) {
                 // Device has emulated storage; external storage paths should have
                 // userId burned into them.
                 final String rawUserId = Integer.toString(userId);
-                final File emulatedBase = new File(rawEmulatedStorageTarget);
+                final File emulatedSourceBase = new File(rawEmulatedSource);
+                final File emulatedTargetBase = new File(rawEmulatedTarget);
                 final File mediaBase = new File(rawMediaStorage);
 
                 // /storage/emulated/0
-                mExternalStorage = buildPath(emulatedBase, rawUserId);
+                mExternalDirsForVold = new File[] { buildPath(emulatedSourceBase, rawUserId) };
+                mExternalDirsForApp = new File[] { buildPath(emulatedTargetBase, rawUserId) };
                 // /data/media/0
-                mMediaStorage = buildPath(mediaBase, rawUserId);
+                mEmulatedDirForDirect = buildPath(mediaBase, rawUserId);
 
             } else {
                 // Device has physical external storage; use plain paths.
@@ -129,54 +148,73 @@
                 }
 
                 // /storage/sdcard0
-                mExternalStorage = new File(rawExternalStorage);
+                mExternalDirsForVold = new File[] { new File(rawExternalStorage) };
+                mExternalDirsForApp = new File[] { new File(rawExternalStorage) };
                 // /data/media
-                mMediaStorage = new File(rawMediaStorage);
+                mEmulatedDirForDirect = new File(rawMediaStorage);
             }
-
-            mExternalStorageAndroidObb = buildPath(mExternalStorage, DIRECTORY_ANDROID, "obb");
-            mExternalStorageAndroidData = buildPath(mExternalStorage, DIRECTORY_ANDROID, "data");
-            mExternalStorageAndroidMedia = buildPath(mExternalStorage, DIRECTORY_ANDROID, "media");
         }
 
+        @Deprecated
         public File getExternalStorageDirectory() {
-            return mExternalStorage;
+            return mExternalDirsForApp[0];
         }
 
-        public File getExternalStorageObbDirectory() {
-            return mExternalStorageAndroidObb;
-        }
-
+        @Deprecated
         public File getExternalStoragePublicDirectory(String type) {
-            return new File(mExternalStorage, type);
+            return buildExternalStoragePublicDirs(type)[0];
         }
 
-        public File getExternalStorageAndroidDataDir() {
-            return mExternalStorageAndroidData;
+        public File[] getExternalDirsForVold() {
+            return mExternalDirsForVold;
         }
 
-        public File getExternalStorageAppDataDirectory(String packageName) {
-            return new File(mExternalStorageAndroidData, packageName);
+        public File[] getExternalDirsForApp() {
+            return mExternalDirsForApp;
         }
 
-        public File getExternalStorageAppMediaDirectory(String packageName) {
-            return new File(mExternalStorageAndroidMedia, packageName);
+        public File getMediaDir() {
+            return mEmulatedDirForDirect;
         }
 
-        public File getExternalStorageAppObbDirectory(String packageName) {
-            return new File(mExternalStorageAndroidObb, packageName);
+        public File[] buildExternalStoragePublicDirs(String type) {
+            return buildPaths(mExternalDirsForApp, type);
         }
 
-        public File getExternalStorageAppFilesDirectory(String packageName) {
-            return new File(new File(mExternalStorageAndroidData, packageName), "files");
+        public File[] buildExternalStorageAndroidDataDirs() {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA);
         }
 
-        public File getExternalStorageAppCacheDirectory(String packageName) {
-            return new File(new File(mExternalStorageAndroidData, packageName), "cache");
+        public File[] buildExternalStorageAndroidObbDirs() {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB);
         }
 
-        public File getMediaStorageDirectory() {
-            return mMediaStorage;
+        public File[] buildExternalStorageAppDataDirs(String packageName) {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName);
+        }
+
+        public File[] buildExternalStorageAppDataDirsForVold(String packageName) {
+            return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_DATA, packageName);
+        }
+
+        public File[] buildExternalStorageAppMediaDirs(String packageName) {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_MEDIA, packageName);
+        }
+
+        public File[] buildExternalStorageAppObbDirs(String packageName) {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB, packageName);
+        }
+
+        public File[] buildExternalStorageAppObbDirsForVold(String packageName) {
+            return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_OBB, packageName);
+        }
+
+        public File[] buildExternalStorageAppFilesDirs(String packageName) {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
+        }
+
+        public File[] buildExternalStorageAppCacheDirs(String packageName) {
+            return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
         }
     }
 
@@ -225,7 +263,7 @@
      */
     public static File getMediaStorageDirectory() {
         throwIfUserRequired();
-        return sCurrentUser.getMediaStorageDirectory();
+        return sCurrentUser.getMediaDir();
     }
 
     /**
@@ -261,58 +299,64 @@
     private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
 
     /**
-     * Gets the Android data directory.
+     * Return the user data directory.
      */
     public static File getDataDirectory() {
         return DATA_DIRECTORY;
     }
 
     /**
-     * Gets the Android external storage directory.  This directory may not
+     * Return the primary external storage directory. This directory may not
      * currently be accessible if it has been mounted by the user on their
      * computer, has been removed from the device, or some other problem has
-     * happened.  You can determine its current state with
+     * happened. You can determine its current state with
      * {@link #getExternalStorageState()}.
-     * 
-     * <p><em>Note: don't be confused by the word "external" here.  This
-     * directory can better be thought as media/shared storage.  It is a
-     * filesystem that can hold a relatively large amount of data and that
-     * is shared across all applications (does not enforce permissions).
-     * Traditionally this is an SD card, but it may also be implemented as
-     * built-in storage in a device that is distinct from the protected
-     * internal storage and can be mounted as a filesystem on a computer.</em></p>
-     *
-     * <p>On devices with multiple users (as described by {@link UserManager}),
-     * each user has their own isolated external storage. Applications only
-     * have access to the external storage for the user they're running as.</p>
-     *
-     * <p>In devices with multiple "external" storage directories (such as
-     * both secure app storage and mountable shared storage), this directory
+     * <p>
+     * <em>Note: don't be confused by the word "external" here. This directory
+     * can better be thought as media/shared storage. It is a filesystem that
+     * can hold a relatively large amount of data and that is shared across all
+     * applications (does not enforce permissions). Traditionally this is an SD
+     * card, but it may also be implemented as built-in storage in a device that
+     * is distinct from the protected internal storage and can be mounted as a
+     * filesystem on a computer.</em>
+     * <p>
+     * On devices with multiple users (as described by {@link UserManager}),
+     * each user has their own isolated external storage. Applications only have
+     * access to the external storage for the user they're running as.
+     * <p>
+     * In devices with multiple "external" storage directories, this directory
      * represents the "primary" external storage that the user will interact
-     * with.</p>
-     *
-     * <p>Applications should not directly use this top-level directory, in
-     * order to avoid polluting the user's root namespace.  Any files that are
-     * private to the application should be placed in a directory returned
-     * by {@link android.content.Context#getExternalFilesDir
+     * with. Access to secondary storage is available through
+     * <p>
+     * Applications should not directly use this top-level directory, in order
+     * to avoid polluting the user's root namespace. Any files that are private
+     * to the application should be placed in a directory returned by
+     * {@link android.content.Context#getExternalFilesDir
      * Context.getExternalFilesDir}, which the system will take care of deleting
-     * if the application is uninstalled.  Other shared files should be placed
-     * in one of the directories returned by
-     * {@link #getExternalStoragePublicDirectory}.</p>
-     *
-     * <p>Writing to this path requires the
-     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission. In
-     * a future platform release, access to this path will require the
+     * if the application is uninstalled. Other shared files should be placed in
+     * one of the directories returned by
+     * {@link #getExternalStoragePublicDirectory}.
+     * <p>
+     * Writing to this path requires the
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
+     * and starting in read access requires the
      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
-     * which is automatically granted if you hold the write permission.</p>
-     *
-     * <p>This path may change between platform versions, so applications
-     * should only persist relative paths.</p>
-     * 
-     * <p>Here is an example of typical code to monitor the state of
-     * external storage:</p>
-     * 
-     * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
+     * which is automatically granted if you hold the write permission.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
+     * application only needs to store internal data, consider using
+     * {@link Context#getExternalFilesDir(String)} or
+     * {@link Context#getExternalCacheDir()}, which require no permissions to
+     * read or write.
+     * <p>
+     * This path may change between platform versions, so applications should
+     * only persist relative paths.
+     * <p>
+     * Here is an example of typical code to monitor the state of external
+     * storage:
+     * <p>
+     * {@sample
+     * development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * monitor_storage}
      *
      * @see #getExternalStorageState()
@@ -320,7 +364,7 @@
      */
     public static File getExternalStorageDirectory() {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageDirectory();
+        return sCurrentUser.getExternalDirsForApp()[0];
     }
 
     /** {@hide} */
@@ -330,7 +374,7 @@
 
     /** {@hide} */
     public static File getLegacyExternalStorageObbDirectory() {
-        return buildPath(getLegacyExternalStorageDirectory(), DIRECTORY_ANDROID, "obb");
+        return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
     }
 
     /** {@hide} */
@@ -342,7 +386,7 @@
     /** {@hide} */
     public static File getEmulatedStorageObbSource() {
         // /mnt/shell/emulated/obb
-        return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), "obb");
+        return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), DIR_OBB);
     }
 
     /**
@@ -436,7 +480,13 @@
      * top-level public directory, as this convention makes no sense elsewhere.
      */
     public static String DIRECTORY_DCIM = "DCIM";
-    
+
+    /**
+     * Standard directory in which to place documents that have been created by
+     * the user.
+     */
+    public static String DIRECTORY_DOCUMENTS = "Documents";
+
     /**
      * Get a top-level public external storage directory for placing files of
      * a particular type.  This is where the user will typically place and
@@ -467,139 +517,192 @@
      */
     public static File getExternalStoragePublicDirectory(String type) {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStoragePublicDirectory(type);
+        return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
     }
 
     /**
      * Returns the path for android-specific data on the SD card.
      * @hide
      */
-    public static File getExternalStorageAndroidDataDir() {
+    public static File[] buildExternalStorageAndroidDataDirs() {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageAndroidDataDir();
+        return sCurrentUser.buildExternalStorageAndroidDataDirs();
     }
-    
+
     /**
      * Generates the raw path to an application's data
      * @hide
      */
-    public static File getExternalStorageAppDataDirectory(String packageName) {
+    public static File[] buildExternalStorageAppDataDirs(String packageName) {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageAppDataDirectory(packageName);
+        return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
     }
     
     /**
      * Generates the raw path to an application's media
      * @hide
      */
-    public static File getExternalStorageAppMediaDirectory(String packageName) {
+    public static File[] buildExternalStorageAppMediaDirs(String packageName) {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageAppMediaDirectory(packageName);
+        return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
     }
     
     /**
      * Generates the raw path to an application's OBB files
      * @hide
      */
-    public static File getExternalStorageAppObbDirectory(String packageName) {
+    public static File[] buildExternalStorageAppObbDirs(String packageName) {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageAppObbDirectory(packageName);
+        return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
     }
     
     /**
      * Generates the path to an application's files.
      * @hide
      */
-    public static File getExternalStorageAppFilesDirectory(String packageName) {
+    public static File[] buildExternalStorageAppFilesDirs(String packageName) {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageAppFilesDirectory(packageName);
+        return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
     }
 
     /**
      * Generates the path to an application's cache.
      * @hide
      */
-    public static File getExternalStorageAppCacheDirectory(String packageName) {
+    public static File[] buildExternalStorageAppCacheDirs(String packageName) {
         throwIfUserRequired();
-        return sCurrentUser.getExternalStorageAppCacheDirectory(packageName);
+        return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
     }
     
     /**
-     * Gets the Android download/cache content directory.
+     * Return the download/cache content directory.
      */
     public static File getDownloadCacheDirectory() {
         return DOWNLOAD_CACHE_DIRECTORY;
     }
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_REMOVED if the media is not present.
+     * Unknown storage state, such as when a path isn't backed by known storage
+     * media.
+     *
+     * @see #getStorageState(File)
+     */
+    public static final String MEDIA_UNKNOWN = "unknown";
+
+    /**
+     * Storage state if the media is not present.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_REMOVED = "removed";
-     
+
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTED if the media is present
-     * but not mounted. 
+     * Storage state if the media is present but not mounted.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_UNMOUNTED = "unmounted";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_CHECKING if the media is present
-     * and being disk-checked
+     * Storage state if the media is present and being disk-checked.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_CHECKING = "checking";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_NOFS if the media is present
-     * but is blank or is using an unsupported filesystem
+     * Storage state if the media is present but is blank or is using an
+     * unsupported filesystem.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_NOFS = "nofs";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_MOUNTED if the media is present
-     * and mounted at its mount point with read/write access. 
+     * Storage state if the media is present and mounted at its mount point with
+     * read/write access.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_MOUNTED = "mounted";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_MOUNTED_READ_ONLY if the media is present
-     * and mounted at its mount point with read only access. 
+     * Storage state if the media is present and mounted at its mount point with
+     * read-only access.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_SHARED if the media is present
-     * not mounted, and shared via USB mass storage. 
+     * Storage state if the media is present not mounted, and shared via USB
+     * mass storage.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_SHARED = "shared";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_BAD_REMOVAL if the media was
-     * removed before it was unmounted. 
+     * Storage state if the media was removed before it was unmounted.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_BAD_REMOVAL = "bad_removal";
 
     /**
-     * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTABLE if the media is present
-     * but cannot be mounted.  Typically this happens if the file system on the
-     * media is corrupted. 
+     * Storage state if the media is present but cannot be mounted. Typically
+     * this happens if the file system on the media is corrupted.
+     *
+     * @see #getStorageState(File)
      */
     public static final String MEDIA_UNMOUNTABLE = "unmountable";
 
     /**
-     * Gets the current state of the primary "external" storage device.
+     * Returns the current state of the primary "external" storage device.
      * 
      * @see #getExternalStorageDirectory()
+     * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
+     *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
+     *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
+     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
+     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
      */
     public static String getExternalStorageState() {
+        return getStorageState(getExternalStorageDirectory());
+    }
+
+    /**
+     * Returns the current state of the storage device that provides the given
+     * path.
+     *
+     * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
+     *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
+     *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
+     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
+     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
+     */
+    public static String getStorageState(File path) {
+        final String rawPath;
         try {
-            IMountService mountService = IMountService.Stub.asInterface(ServiceManager
-                    .getService("mount"));
-            final StorageVolume primary = getPrimaryVolume();
-            return mountService.getVolumeState(primary.getPath());
-        } catch (RemoteException rex) {
-            Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex);
-            return Environment.MEDIA_REMOVED;
+            rawPath = path.getCanonicalPath();
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to resolve target path: " + e);
+            return Environment.MEDIA_UNKNOWN;
         }
+
+        try {
+            final IMountService mountService = IMountService.Stub.asInterface(
+                    ServiceManager.getService("mount"));
+            final StorageVolume[] volumes = mountService.getVolumeList();
+            for (StorageVolume volume : volumes) {
+                if (rawPath.startsWith(volume.getPath())) {
+                    return mountService.getVolumeState(volume.getPath());
+                }
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to find external storage state: " + e);
+        }
+        return Environment.MEDIA_UNKNOWN;
     }
 
     /**
@@ -663,7 +766,25 @@
         }
     }
 
-    private static File buildPath(File base, String... segments) {
+    /**
+     * Append path segments to each given base path, returning result.
+     *
+     * @hide
+     */
+    public static File[] buildPaths(File[] base, String... segments) {
+        File[] result = new File[base.length];
+        for (int i = 0; i < base.length; i++) {
+            result[i] = buildPath(base[i], segments);
+        }
+        return result;
+    }
+
+    /**
+     * Append path segments to given base path, returning result.
+     *
+     * @hide
+     */
+    public static File buildPath(File base, String... segments) {
         File cur = base;
         for (String segment : segments) {
             if (cur == null) {
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 9666d9a..4d48fd4 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -17,10 +17,17 @@
 package android.os;
 
 import android.util.Log;
+import android.util.Slog;
+
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.OsConstants;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -58,7 +65,84 @@
     /** Regular expression for safe filenames: no spaces or metacharacters */
     private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
 
-    public static native int setPermissions(String file, int mode, int uid, int gid);
+    /**
+     * Set owner and mode of of given {@link File}.
+     *
+     * @param mode to apply through {@code chmod}
+     * @param uid to apply through {@code chown}, or -1 to leave unchanged
+     * @param gid to apply through {@code chown}, or -1 to leave unchanged
+     * @return 0 on success, otherwise errno.
+     */
+    public static int setPermissions(File path, int mode, int uid, int gid) {
+        return setPermissions(path.getAbsolutePath(), mode, uid, gid);
+    }
+
+    /**
+     * Set owner and mode of of given path.
+     *
+     * @param mode to apply through {@code chmod}
+     * @param uid to apply through {@code chown}, or -1 to leave unchanged
+     * @param gid to apply through {@code chown}, or -1 to leave unchanged
+     * @return 0 on success, otherwise errno.
+     */
+    public static int setPermissions(String path, int mode, int uid, int gid) {
+        try {
+            Libcore.os.chmod(path, mode);
+        } catch (ErrnoException e) {
+            Slog.w(TAG, "Failed to chmod(" + path + "): " + e);
+            return e.errno;
+        }
+
+        if (uid >= 0 || gid >= 0) {
+            try {
+                Libcore.os.chown(path, uid, gid);
+            } catch (ErrnoException e) {
+                Slog.w(TAG, "Failed to chown(" + path + "): " + e);
+                return e.errno;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Set owner and mode of of given {@link FileDescriptor}.
+     *
+     * @param mode to apply through {@code chmod}
+     * @param uid to apply through {@code chown}, or -1 to leave unchanged
+     * @param gid to apply through {@code chown}, or -1 to leave unchanged
+     * @return 0 on success, otherwise errno.
+     */
+    public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
+        try {
+            Libcore.os.fchmod(fd, mode);
+        } catch (ErrnoException e) {
+            Slog.w(TAG, "Failed to fchmod(): " + e);
+            return e.errno;
+        }
+
+        if (uid >= 0 || gid >= 0) {
+            try {
+                Libcore.os.fchown(fd, uid, gid);
+            } catch (ErrnoException e) {
+                Slog.w(TAG, "Failed to fchown(): " + e);
+                return e.errno;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Return owning UID of given path, otherwise -1.
+     */
+    public static int getUid(String path) {
+        try {
+            return Libcore.os.stat(path).st_uid;
+        } catch (ErrnoException e) {
+            return -1;
+        }
+    }
 
     /** returns the FAT file system volume ID for the volume mounted 
      * at the given mount point, or -1 for failure
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 14d8f07..e6886c4 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -73,6 +73,9 @@
     /**
      * Callback interface you can use when instantiating a Handler to avoid
      * having to implement your own subclass of Handler.
+     *
+     * @param msg A {@link android.os.Message Message} object
+     * @return True if no further handling is desired
      */
     public interface Callback {
         public boolean handleMessage(Message msg);
diff --git a/core/java/android/os/IBatteryPropertiesListener.aidl b/core/java/android/os/IBatteryPropertiesListener.aidl
new file mode 100644
index 0000000..7e23924
--- /dev/null
+++ b/core/java/android/os/IBatteryPropertiesListener.aidl
@@ -0,0 +1,27 @@
+/*
+** 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 android.os;
+
+import android.os.BatteryProperties;
+
+/**
+ * {@hide}
+ */
+
+oneway interface IBatteryPropertiesListener {
+    void batteryPropertiesChanged(in BatteryProperties props);
+}
diff --git a/core/java/android/os/IBatteryPropertiesRegistrar.aidl b/core/java/android/os/IBatteryPropertiesRegistrar.aidl
new file mode 100644
index 0000000..376f6c9
--- /dev/null
+++ b/core/java/android/os/IBatteryPropertiesRegistrar.aidl
@@ -0,0 +1,28 @@
+/*
+** 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 android.os;
+
+import android.os.IBatteryPropertiesListener;
+
+/**
+ * {@hide}
+ */
+
+interface IBatteryPropertiesRegistrar {
+    void registerListener(IBatteryPropertiesListener listener);
+    void unregisterListener(IBatteryPropertiesListener listener);
+}
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index b7bc45f..a2432d6 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -238,7 +238,7 @@
      * <p>You will only receive death notifications for remote binders,
      * as local binders by definition can't die without you dying as well.
      * 
-     * @throws Throws {@link RemoteException} if the target IBinder's
+     * @throws RemoteException if the target IBinder's
      * process has already died.
      * 
      * @see #unlinkToDeath
@@ -251,13 +251,13 @@
      * The recipient will no longer be called if this object
      * dies.
      * 
-     * @return Returns true if the <var>recipient</var> is successfully
+     * @return {@code true} if the <var>recipient</var> is successfully
      * unlinked, assuring you that its
      * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
-     * will not be called.  Returns false if the target IBinder has already
+     * will not be called;  {@code false} if the target IBinder has already
      * died, meaning the method has been (or soon will be) called.
      * 
-     * @throws Throws {@link java.util.NoSuchElementException} if the given
+     * @throws java.util.NoSuchElementException if the given
      * <var>recipient</var> has not been registered with the IBinder, and
      * the IBinder is still alive.  Note that if the <var>recipient</var>
      * was never registered, but the IBinder has already died, then this
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 45524c8..21b8ae5 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@
 
 import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
+import android.net.LinkAddress;
 import android.net.NetworkStats;
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
@@ -117,6 +118,11 @@
     void removeSecondaryRoute(String iface, in RouteInfo route);
 
     /**
+     * Set the specified MTU size
+     */
+    void setMtu(String iface, int mtu);
+
+    /**
      * Shuts down the service
      */
     void shutdown();
@@ -254,11 +260,9 @@
     NetworkStats getNetworkStatsUidDetail(int uid);
 
     /**
-     * Return summary of network statistics for the requested pairs of
-     * tethering interfaces.  Even indexes are remote interface, and odd
-     * indexes are corresponding local interfaces.
+     * Return summary of network statistics all tethering interfaces.
      */
-    NetworkStats getNetworkStatsTethering(in String[] ifacePairs);
+    NetworkStats getNetworkStatsTethering();
 
     /**
      * Set quota for an interface.
@@ -344,6 +348,61 @@
     void setFirewallUidRule(int uid, boolean allow);
 
     /**
+     * Set all packets from users [uid_start,uid_end] to go through interface iface
+     * iface must already be set for marked forwarding by {@link setMarkedForwarding}
+     */
+    void setUidRangeRoute(String iface, int uid_start, int uid_end);
+
+    /**
+     * Clears the special routing rules for users [uid_start,uid_end]
+     */
+    void clearUidRangeRoute(String iface, int uid_start, int uid_end);
+
+    /**
+     * Setup an interface for routing packets marked by {@link setUidRangeRoute}
+     *
+     * This sets up a dedicated routing table for packets marked for {@code iface} and adds
+     * source-NAT rules so that the marked packets have the correct source address.
+     */
+    void setMarkedForwarding(String iface);
+
+    /**
+     * Removes marked forwarding for an interface
+     */
+    void clearMarkedForwarding(String iface);
+
+    /**
+     * Get the SO_MARK associated with routing packets for user {@code uid}
+     */
+    int getMarkForUid(int uid);
+
+    /**
+     * Get the SO_MARK associated with protecting packets from VPN routing rules
+     */
+    int getMarkForProtect();
+
+    /**
+     * Route all traffic in {@code route} to {@code iface} setup for marked forwarding
+     */
+    void setMarkedForwardingRoute(String iface, in RouteInfo route);
+
+    /**
+     * Clear routes set by {@link setMarkedForwardingRoute}
+     */
+    void clearMarkedForwardingRoute(String iface, in RouteInfo route);
+
+    /**
+     * Exempts {@code host} from the routing set up by {@link setMarkedForwardingRoute}
+     * All connects to {@code host} will use the global routing table
+     */
+    void setHostExemption(in LinkAddress host);
+
+    /**
+     * Clears an exemption set by {@link setHostExemption}
+     */
+    void clearHostExemption(in LinkAddress host);
+
+    /**
      * Set a process (pid) to use the name servers associated with the specified interface.
      */
     void setDnsInterfaceForPid(String iface, int pid);
@@ -354,6 +413,21 @@
     void clearDnsInterfaceForPid(int pid);
 
     /**
+    * Set a range of user ids to use the name servers associated with the specified interface.
+    */
+    void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end);
+
+    /**
+    * Clear a user range from being associated with an interface.
+    */
+    void clearDnsInterfaceForUidRange(int uid_start, int uid_end);
+
+    /**
+    * Clear the mappings from pid to Dns interface and from uid range to Dns interface.
+    */
+    void clearDnsInterfaceMaps();
+
+    /**
      * Start the clatd (464xlat) service
      */
     void startClatd(String interfaceName);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 6d6d147..23492ff 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -25,7 +25,7 @@
 {
     // WARNING: The first two methods must remain the first two methods because their
     // transaction numbers must not change unless IPowerManager.cpp is also updated.
-    void acquireWakeLock(IBinder lock, int flags, String tag, in WorkSource ws);
+    void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws);
     void releaseWakeLock(IBinder lock, int flags);
 
     void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index a11358a..3c9d0d9 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -46,4 +46,8 @@
             int userHandle);
     Bundle getApplicationRestrictions(in String packageName);
     Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
+    boolean setRestrictionsChallenge(in String newPin);
+    int checkRestrictionsChallenge(in String pin);
+    boolean hasRestrictionsChallenge();
+    void removeRestrictions();
 }
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index d5cf771..78c859e 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -289,6 +289,16 @@
         return mQueue;
     }
 
+    /**
+     * Return whether this looper's thread is currently idle, waiting for new work
+     * to do.  This is intrinsically racy, since its state can change before you get
+     * the result back.
+     * @hide
+     */
+    public boolean isIdling() {
+        return mQueue.isIdling();
+    }
+
     public void dump(Printer pw, String prefix) {
         pw = PrefixPrinter.create(pw, prefix);
         pw.println(this.toString());
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index bf7e5ca..d1b8213 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -39,7 +39,7 @@
     Message mMessages;
     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
     private IdleHandler[] mPendingIdleHandlers;
-    private boolean mQuiting;
+    private boolean mQuitting;
 
     // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
     private boolean mBlocked;
@@ -52,6 +52,7 @@
     private native static void nativeDestroy(int ptr);
     private native static void nativePollOnce(int ptr, int timeoutMillis);
     private native static void nativeWake(int ptr);
+    private native static boolean nativeIsIdling(int ptr);
 
     /**
      * Callback interface for discovering when a thread is going to block
@@ -114,6 +115,8 @@
         }
     }
 
+    // Disposes of the underlying message queue.
+    // Must only be called on the looper thread or the finalizer.
     private void dispose() {
         if (mPtr != 0) {
             nativeDestroy(mPtr);
@@ -124,11 +127,13 @@
     Message next() {
         int pendingIdleHandlerCount = -1; // -1 only during first iteration
         int nextPollTimeoutMillis = 0;
-
         for (;;) {
             if (nextPollTimeoutMillis != 0) {
                 Binder.flushPendingCommands();
             }
+
+            // We can assume mPtr != 0 because the loop is obviously still running.
+            // The looper will not call this method after the loop quits.
             nativePollOnce(mPtr, nextPollTimeoutMillis);
 
             synchronized (this) {
@@ -166,7 +171,7 @@
                 }
 
                 // Process the quit message now that all pending messages have been handled.
-                if (mQuiting) {
+                if (mQuitting) {
                     dispose();
                     return null;
                 }
@@ -225,18 +230,20 @@
         }
 
         synchronized (this) {
-            if (mQuiting) {
+            if (mQuitting) {
                 return;
             }
-            mQuiting = true;
+            mQuitting = true;
 
             if (safe) {
                 removeAllFutureMessagesLocked();
             } else {
                 removeAllMessagesLocked();
             }
+
+            // We can assume mPtr != 0 because mQuitting was previously false.
+            nativeWake(mPtr);
         }
-        nativeWake(mPtr);
     }
 
     int enqueueSyncBarrier(long when) {
@@ -269,7 +276,6 @@
     void removeSyncBarrier(int token) {
         // Remove a sync barrier token from the queue.
         // If the queue is no longer stalled by a barrier then wake it.
-        final boolean needWake;
         synchronized (this) {
             Message prev = null;
             Message p = mMessages;
@@ -281,6 +287,7 @@
                 throw new IllegalStateException("The specified message queue synchronization "
                         + " barrier token has not been posted or has already been removed.");
             }
+            final boolean needWake;
             if (prev != null) {
                 prev.next = p.next;
                 needWake = false;
@@ -289,9 +296,12 @@
                 needWake = mMessages == null || mMessages.target != null;
             }
             p.recycle();
-        }
-        if (needWake) {
-            nativeWake(mPtr);
+
+            // If the loop is quitting then it is already awake.
+            // We can assume mPtr != 0 when mQuitting is false.
+            if (needWake && !mQuitting) {
+                nativeWake(mPtr);
+            }
         }
     }
 
@@ -303,9 +313,8 @@
             throw new AndroidRuntimeException("Message must have a target.");
         }
 
-        boolean needWake;
         synchronized (this) {
-            if (mQuiting) {
+            if (mQuitting) {
                 RuntimeException e = new RuntimeException(
                         msg.target + " sending message to a Handler on a dead thread");
                 Log.w("MessageQueue", e.getMessage(), e);
@@ -314,6 +323,7 @@
 
             msg.when = when;
             Message p = mMessages;
+            boolean needWake;
             if (p == null || when == 0 || when < p.when) {
                 // New head, wake up the event queue if blocked.
                 msg.next = p;
@@ -338,9 +348,11 @@
                 msg.next = p; // invariant: p == prev.next
                 prev.next = msg;
             }
-        }
-        if (needWake) {
-            nativeWake(mPtr);
+
+            // We can assume mPtr != 0 because mQuitting is false.
+            if (needWake) {
+                nativeWake(mPtr);
+            }
         }
         return true;
     }
@@ -379,6 +391,14 @@
         }
     }
 
+    boolean isIdling() {
+        synchronized (this) {
+            // If the loop is quitting then it must not be idling.
+            // We can assume mPtr != 0 when mQuitting is false.
+            return !mQuitting && nativeIsIdling(mPtr);
+        }
+    }
+
     void removeMessages(Handler h, int what, Object object) {
         if (h == null) {
             return;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 0916ea9..5f3a81c 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -177,6 +178,7 @@
  */
 public final class Parcel {
     private static final boolean DEBUG_RECYCLE = false;
+    private static final boolean DEBUG_ARRAY_MAP = false;
     private static final String TAG = "Parcel";
 
     @SuppressWarnings({"UnusedDeclaration"})
@@ -227,6 +229,7 @@
     private static final int EX_ILLEGAL_ARGUMENT = -3;
     private static final int EX_NULL_POINTER = -4;
     private static final int EX_ILLEGAL_STATE = -5;
+    private static final int EX_NETWORK_MAIN_THREAD = -6;
     private static final int EX_HAS_REPLY_HEADER = -128;  // special; see below
 
     private static native int nativeDataSize(int nativePtr);
@@ -572,7 +575,7 @@
      * allows you to avoid mysterious type errors at the point of marshalling.
      */
     public final void writeMap(Map val) {
-        writeMapInternal((Map<String,Object>) val);
+        writeMapInternal((Map<String, Object>) val);
     }
 
     /**
@@ -593,6 +596,30 @@
     }
 
     /**
+     * Flatten an ArrayMap into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.  The Map keys must be String objects.
+     */
+    /* package */ void writeArrayMapInternal(ArrayMap<String,Object> val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        final int N = val.size();
+        writeInt(N);
+        if (DEBUG_ARRAY_MAP) {
+            RuntimeException here =  new RuntimeException("here");
+            here.fillInStackTrace();
+            Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
+        }
+        for (int i=0; i<N; i++) {
+            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Write #" + i + ": key=0x"
+                    + (val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0) + " " + val.keyAt(i));
+            writeValue(val.keyAt(i));
+            writeValue(val.valueAt(i));
+        }
+    }
+
+    /**
      * Flatten a Bundle into the parcel at the current dataPosition(),
      * growing dataCapacity() if needed.
      */
@@ -1303,6 +1330,7 @@
      * <li>{@link IllegalStateException}
      * <li>{@link NullPointerException}
      * <li>{@link SecurityException}
+     * <li>{@link NetworkOnMainThreadException}
      * </ul>
      * 
      * @param e The Exception to be written.
@@ -1322,6 +1350,8 @@
             code = EX_NULL_POINTER;
         } else if (e instanceof IllegalStateException) {
             code = EX_ILLEGAL_STATE;
+        } else if (e instanceof NetworkOnMainThreadException) {
+            code = EX_NETWORK_MAIN_THREAD;
         }
         writeInt(code);
         StrictMode.clearGatheredViolations();
@@ -1437,6 +1467,8 @@
                 throw new NullPointerException(msg);
             case EX_ILLEGAL_STATE:
                 throw new IllegalStateException(msg);
+            case EX_NETWORK_MAIN_THREAD:
+                throw new NetworkOnMainThreadException();
         }
         throw new RuntimeException("Unknown exception code: " + code
                 + " msg " + msg);
@@ -1502,6 +1534,11 @@
         return fd != null ? new ParcelFileDescriptor(fd) : null;
     }
 
+    /** {@hide} */
+    public final FileDescriptor readRawFileDescriptor() {
+        return nativeReadFileDescriptor(mNativePtr);
+    }
+
     /*package*/ static native FileDescriptor openFileDescriptor(String file,
             int mode) throws FileNotFoundException;
     /*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig)
@@ -2258,6 +2295,40 @@
         }
     }
 
+    /* package */ void readArrayMapInternal(ArrayMap outVal, int N,
+        ClassLoader loader) {
+        if (DEBUG_ARRAY_MAP) {
+            RuntimeException here =  new RuntimeException("here");
+            here.fillInStackTrace();
+            Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
+        }
+        while (N > 0) {
+            Object key = readValue(loader);
+            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read #" + (N-1) + ": key=0x"
+                    + (key != null ? key.hashCode() : 0) + " " + key);
+            Object value = readValue(loader);
+            outVal.append(key, value);
+            N--;
+        }
+    }
+
+    /* package */ void readArrayMapSafelyInternal(ArrayMap outVal, int N,
+        ClassLoader loader) {
+        if (DEBUG_ARRAY_MAP) {
+            RuntimeException here =  new RuntimeException("here");
+            here.fillInStackTrace();
+            Log.d(TAG, "Reading safely " + N + " ArrayMap entries", here);
+        }
+        while (N > 0) {
+            Object key = readValue(loader);
+            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read safe #" + (N-1) + ": key=0x"
+                    + (key != null ? key.hashCode() : 0) + " " + key);
+            Object value = readValue(loader);
+            outVal.put(key, value);
+            N--;
+        }
+    }
+
     private void readListInternal(List outVal, int N,
         ClassLoader loader) {
         while (N > 0) {
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3de362c..55c083b 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -16,8 +16,25 @@
 
 package android.os;
 
+import static libcore.io.OsConstants.AF_UNIX;
+import static libcore.io.OsConstants.SEEK_SET;
+import static libcore.io.OsConstants.SOCK_STREAM;
+import static libcore.io.OsConstants.S_ISLNK;
+import static libcore.io.OsConstants.S_ISREG;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
+import android.util.Log;
+
 import dalvik.system.CloseGuard;
 
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.Memory;
+import libcore.io.OsConstants;
+import libcore.io.StructStat;
+
 import java.io.Closeable;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -27,36 +44,80 @@
 import java.io.IOException;
 import java.net.DatagramSocket;
 import java.net.Socket;
+import java.nio.ByteOrder;
 
 /**
  * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
  * you to close it when done with it.
  */
 public class ParcelFileDescriptor implements Parcelable, Closeable {
-    private final FileDescriptor mFileDescriptor;
+    private static final String TAG = "ParcelFileDescriptor";
+
+    private final FileDescriptor mFd;
+
+    /**
+     * Optional socket used to communicate close events, status at close, and
+     * detect remote process crashes.
+     */
+    private FileDescriptor mCommFd;
 
     /**
      * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
-     * double-closing {@link #mFileDescriptor}.
+     * double-closing {@link #mFd}.
      */
     private final ParcelFileDescriptor mWrapped;
 
+    /**
+     * Maximum {@link #mStatusBuf} size; longer status messages will be
+     * truncated.
+     */
+    private static final int MAX_STATUS = 1024;
+
+    /**
+     * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
+     * allocated on-demand.
+     */
+    private byte[] mStatusBuf;
+
+    /**
+     * Status read by {@link #checkError()}, or null if not read yet.
+     */
+    private Status mStatus;
+
     private volatile boolean mClosed;
 
     private final CloseGuard mGuard = CloseGuard.get();
 
     /**
-     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
-     * and this file doesn't already exist, then create the file with
-     * permissions such that any application can read it.
+     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
+     * this file doesn't already exist, then create the file with permissions
+     * such that any application can read it.
+     *
+     * @deprecated Creating world-readable files is very dangerous, and likely
+     *             to cause security holes in applications. It is strongly
+     *             discouraged; instead, applications should use more formal
+     *             mechanism for interactions such as {@link ContentProvider},
+     *             {@link BroadcastReceiver}, and {@link android.app.Service}.
+     *             There are no guarantees that this access mode will remain on
+     *             a file, such as when it goes through a backup and restore.
      */
+    @Deprecated
     public static final int MODE_WORLD_READABLE = 0x00000001;
 
     /**
-     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
-     * and this file doesn't already exist, then create the file with
-     * permissions such that any application can write it.
+     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
+     * this file doesn't already exist, then create the file with permissions
+     * such that any application can write it.
+     *
+     * @deprecated Creating world-writable files is very dangerous, and likely
+     *             to cause security holes in applications. It is strongly
+     *             discouraged; instead, applications should use more formal
+     *             mechanism for interactions such as {@link ContentProvider},
+     *             {@link BroadcastReceiver}, and {@link android.app.Service}.
+     *             There are no guarantees that this access mode will remain on
+     *             a file, such as when it goes through a backup and restore.
      */
+    @Deprecated
     public static final int MODE_WORLD_WRITEABLE = 0x00000002;
 
     /**
@@ -90,32 +151,102 @@
     public static final int MODE_APPEND = 0x02000000;
 
     /**
+     * Create a new ParcelFileDescriptor wrapped around another descriptor. By
+     * default all method calls are delegated to the wrapped descriptor.
+     */
+    public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
+        // We keep a strong reference to the wrapped PFD, and rely on its
+        // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
+        mWrapped = wrapped;
+        mFd = null;
+        mCommFd = null;
+        mClosed = true;
+    }
+
+    /** {@hide} */
+    public ParcelFileDescriptor(FileDescriptor fd) {
+        this(fd, null);
+    }
+
+    /** {@hide} */
+    public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
+        if (fd == null) {
+            throw new NullPointerException("FileDescriptor must not be null");
+        }
+        mWrapped = null;
+        mFd = fd;
+        mCommFd = commChannel;
+        mGuard.open("close");
+    }
+
+    /**
      * Create a new ParcelFileDescriptor accessing a given file.
      *
      * @param file The file to be opened.
      * @param mode The desired access mode, must be one of
-     * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
-     * {@link #MODE_READ_WRITE}; may also be any combination of
-     * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
-     * {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
-     *
-     * @return Returns a new ParcelFileDescriptor pointing to the given
-     * file.
-     *
-     * @throws FileNotFoundException Throws FileNotFoundException if the given
-     * file does not exist or can not be opened with the requested mode.
+     *            {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
+     *            {@link #MODE_READ_WRITE}; may also be any combination of
+     *            {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
+     *            {@link #MODE_WORLD_READABLE}, and
+     *            {@link #MODE_WORLD_WRITEABLE}.
+     * @return a new ParcelFileDescriptor pointing to the given file.
+     * @throws FileNotFoundException if the given file does not exist or can not
+     *             be opened with the requested mode.
      */
-    public static ParcelFileDescriptor open(File file, int mode)
-            throws FileNotFoundException {
-        String path = file.getPath();
+    public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
+        final FileDescriptor fd = openInternal(file, mode);
+        if (fd == null) return null;
 
-        if ((mode&MODE_READ_WRITE) == 0) {
+        return new ParcelFileDescriptor(fd);
+    }
+
+    /**
+     * Create a new ParcelFileDescriptor accessing a given file.
+     *
+     * @param file The file to be opened.
+     * @param mode The desired access mode, must be one of
+     *            {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
+     *            {@link #MODE_READ_WRITE}; may also be any combination of
+     *            {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
+     *            {@link #MODE_WORLD_READABLE}, and
+     *            {@link #MODE_WORLD_WRITEABLE}.
+     * @param handler to call listener from; must not be null.
+     * @param listener to be invoked when the returned descriptor has been
+     *            closed; must not be null.
+     * @return a new ParcelFileDescriptor pointing to the given file.
+     * @throws FileNotFoundException if the given file does not exist or can not
+     *             be opened with the requested mode.
+     */
+    public static ParcelFileDescriptor open(
+            File file, int mode, Handler handler, OnCloseListener listener) throws IOException {
+        if (handler == null) {
+            throw new IllegalArgumentException("Handler must not be null");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener must not be null");
+        }
+
+        final FileDescriptor fd = openInternal(file, mode);
+        if (fd == null) return null;
+
+        final FileDescriptor[] comm = createCommSocketPair(true);
+        final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
+
+        // Kick off thread to watch for status updates
+        final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
+        bridge.start();
+
+        return pfd;
+    }
+
+    private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
+        if ((mode & MODE_READ_WRITE) == 0) {
             throw new IllegalArgumentException(
                     "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
         }
 
-        FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        final String path = file.getPath();
+        return Parcel.openFileDescriptor(path, mode);
     }
 
     /**
@@ -125,8 +256,12 @@
      * original file descriptor.
      */
     public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
-        FileDescriptor fd = Parcel.dupFileDescriptor(orig);
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        try {
+            final FileDescriptor fd = Libcore.os.dup(orig);
+            return new ParcelFileDescriptor(fd);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
     }
 
     /**
@@ -136,7 +271,11 @@
      * original file descriptor.
      */
     public ParcelFileDescriptor dup() throws IOException {
-        return dup(getFileDescriptor());
+        if (mWrapped != null) {
+            return mWrapped.dup();
+        } else {
+            return dup(getFileDescriptor());
+        }
     }
 
     /**
@@ -150,12 +289,16 @@
      * for a dup of the given fd.
      */
     public static ParcelFileDescriptor fromFd(int fd) throws IOException {
-        FileDescriptor fdesc = getFileDescriptorFromFd(fd);
-        return new ParcelFileDescriptor(fdesc);
-    }
+        final FileDescriptor original = new FileDescriptor();
+        original.setInt$(fd);
 
-    // Extracts the file descriptor from the specified socket and returns it untouched
-    private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException;
+        try {
+            final FileDescriptor dup = Libcore.os.dup(original);
+            return new ParcelFileDescriptor(dup);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
 
     /**
      * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
@@ -168,13 +311,12 @@
      * for the given fd.
      */
     public static ParcelFileDescriptor adoptFd(int fd) {
-        FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd);
+        final FileDescriptor fdesc = new FileDescriptor();
+        fdesc.setInt$(fd);
+
         return new ParcelFileDescriptor(fdesc);
     }
 
-    // Extracts the file descriptor from the specified socket and returns it untouched
-    private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd);
-
     /**
      * Create a new ParcelFileDescriptor from the specified Socket.  The new
      * ParcelFileDescriptor holds a dup of the original FileDescriptor in
@@ -212,15 +354,90 @@
      * is the write side.
      */
     public static ParcelFileDescriptor[] createPipe() throws IOException {
-        FileDescriptor[] fds = new FileDescriptor[2];
-        createPipeNative(fds);
-        ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
-        pfds[0] = new ParcelFileDescriptor(fds[0]);
-        pfds[1] = new ParcelFileDescriptor(fds[1]);
-        return pfds;
+        try {
+            final FileDescriptor[] fds = Libcore.os.pipe();
+            return new ParcelFileDescriptor[] {
+                    new ParcelFileDescriptor(fds[0]),
+                    new ParcelFileDescriptor(fds[1]) };
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
     }
 
-    private static native void createPipeNative(FileDescriptor[] outFds) throws IOException;
+    /**
+     * Create two ParcelFileDescriptors structured as a data pipe. The first
+     * ParcelFileDescriptor in the returned array is the read side; the second
+     * is the write side.
+     * <p>
+     * The write end has the ability to deliver an error message through
+     * {@link #closeWithError(String)} which can be handled by the read end
+     * calling {@link #checkError()}, usually after detecting an EOF.
+     * This can also be used to detect remote crashes.
+     */
+    public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
+        try {
+            final FileDescriptor[] comm = createCommSocketPair(false);
+            final FileDescriptor[] fds = Libcore.os.pipe();
+            return new ParcelFileDescriptor[] {
+                    new ParcelFileDescriptor(fds[0], comm[0]),
+                    new ParcelFileDescriptor(fds[1], comm[1]) };
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
+
+    /**
+     * Create two ParcelFileDescriptors structured as a pair of sockets
+     * connected to each other. The two sockets are indistinguishable.
+     */
+    public static ParcelFileDescriptor[] createSocketPair() throws IOException {
+        try {
+            final FileDescriptor fd0 = new FileDescriptor();
+            final FileDescriptor fd1 = new FileDescriptor();
+            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+            return new ParcelFileDescriptor[] {
+                    new ParcelFileDescriptor(fd0),
+                    new ParcelFileDescriptor(fd1) };
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
+
+    /**
+     * Create two ParcelFileDescriptors structured as a pair of sockets
+     * connected to each other. The two sockets are indistinguishable.
+     * <p>
+     * Both ends have the ability to deliver an error message through
+     * {@link #closeWithError(String)} which can be detected by the other end
+     * calling {@link #checkError()}, usually after detecting an EOF.
+     * This can also be used to detect remote crashes.
+     */
+    public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
+        try {
+            final FileDescriptor[] comm = createCommSocketPair(false);
+            final FileDescriptor fd0 = new FileDescriptor();
+            final FileDescriptor fd1 = new FileDescriptor();
+            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+            return new ParcelFileDescriptor[] {
+                    new ParcelFileDescriptor(fd0, comm[0]),
+                    new ParcelFileDescriptor(fd1, comm[1]) };
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
+
+    private static FileDescriptor[] createCommSocketPair(boolean blocking) throws IOException {
+        try {
+            final FileDescriptor comm1 = new FileDescriptor();
+            final FileDescriptor comm2 = new FileDescriptor();
+            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
+            IoUtils.setBlocking(comm1, blocking);
+            IoUtils.setBlocking(comm2, blocking);
+            return new FileDescriptor[] { comm1, comm2 };
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
 
     /**
      * @hide Please use createPipe() or ContentProvider.openPipeHelper().
@@ -245,26 +462,89 @@
     }
 
     /**
+     * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
+     * with {@link #open}.
+     * <p>
+     * @param mode The string representation of the file mode.
+     * @return A bitmask representing the given file mode.
+     * @throws IllegalArgumentException if the given string does not match a known file mode.
+     */
+    public static int parseMode(String mode) {
+        final int modeBits;
+        if ("r".equals(mode)) {
+            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
+        } else if ("w".equals(mode) || "wt".equals(mode)) {
+            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
+                    | ParcelFileDescriptor.MODE_CREATE
+                    | ParcelFileDescriptor.MODE_TRUNCATE;
+        } else if ("wa".equals(mode)) {
+            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
+                    | ParcelFileDescriptor.MODE_CREATE
+                    | ParcelFileDescriptor.MODE_APPEND;
+        } else if ("rw".equals(mode)) {
+            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
+                    | ParcelFileDescriptor.MODE_CREATE;
+        } else if ("rwt".equals(mode)) {
+            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
+                    | ParcelFileDescriptor.MODE_CREATE
+                    | ParcelFileDescriptor.MODE_TRUNCATE;
+        } else {
+            throw new IllegalArgumentException("Bad mode '" + mode + "'");
+        }
+        return modeBits;
+    }
+
+    /**
      * Retrieve the actual FileDescriptor associated with this object.
      *
      * @return Returns the FileDescriptor associated with this object.
      */
     public FileDescriptor getFileDescriptor() {
-        return mFileDescriptor;
+        if (mWrapped != null) {
+            return mWrapped.getFileDescriptor();
+        } else {
+            return mFd;
+        }
     }
 
     /**
-     * Return the total size of the file representing this fd, as determined
-     * by stat().  Returns -1 if the fd is not a file.
+     * Return the total size of the file representing this fd, as determined by
+     * {@code stat()}. Returns -1 if the fd is not a file.
      */
-    public native long getStatSize();
+    public long getStatSize() {
+        if (mWrapped != null) {
+            return mWrapped.getStatSize();
+        } else {
+            try {
+                final StructStat st = Libcore.os.fstat(mFd);
+                if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+                    return st.st_size;
+                } else {
+                    return -1;
+                }
+            } catch (ErrnoException e) {
+                Log.w(TAG, "fstat() failed: " + e);
+                return -1;
+            }
+        }
+    }
 
     /**
      * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
      * and I really don't think we want it to be public.
      * @hide
      */
-    public native long seekTo(long pos);
+    public long seekTo(long pos) throws IOException {
+        if (mWrapped != null) {
+            return mWrapped.seekTo(pos);
+        } else {
+            try {
+                return Libcore.os.lseek(mFd, pos, SEEK_SET);
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        }
+    }
 
     /**
      * Return the native fd int for this ParcelFileDescriptor.  The
@@ -272,34 +552,39 @@
      * through this API.
      */
     public int getFd() {
-        if (mClosed) {
-            throw new IllegalStateException("Already closed");
+        if (mWrapped != null) {
+            return mWrapped.getFd();
+        } else {
+            if (mClosed) {
+                throw new IllegalStateException("Already closed");
+            }
+            return mFd.getInt$();
         }
-        return getFdNative();
     }
 
-    private native int getFdNative();
-
     /**
-     * Return the native fd int for this ParcelFileDescriptor and detach it
-     * from the object here.  You are now responsible for closing the fd in
-     * native code.
+     * Return the native fd int for this ParcelFileDescriptor and detach it from
+     * the object here. You are now responsible for closing the fd in native
+     * code.
+     * <p>
+     * You should not detach when the original creator of the descriptor is
+     * expecting a reliable signal through {@link #close()} or
+     * {@link #closeWithError(String)}.
+     *
+     * @see #canDetectErrors()
      */
     public int detachFd() {
-        if (mClosed) {
-            throw new IllegalStateException("Already closed");
-        }
         if (mWrapped != null) {
-            int fd = mWrapped.detachFd();
-            mClosed = true;
-            mGuard.close();
+            return mWrapped.detachFd();
+        } else {
+            if (mClosed) {
+                throw new IllegalStateException("Already closed");
+            }
+            final int fd = getFd();
+            Parcel.clearFileDescriptor(mFd);
+            writeCommStatusAndClose(Status.DETACHED, null);
             return fd;
         }
-        int fd = getFd();
-        mClosed = true;
-        mGuard.close();
-        Parcel.clearFileDescriptor(mFileDescriptor);
-        return fd;
     }
 
     /**
@@ -311,16 +596,187 @@
      */
     @Override
     public void close() throws IOException {
+        if (mWrapped != null) {
+            try {
+                mWrapped.close();
+            } finally {
+                releaseResources();
+            }
+        } else {
+            closeWithStatus(Status.OK, null);
+        }
+    }
+
+    /**
+     * Close the ParcelFileDescriptor, informing any peer that an error occurred
+     * while processing. If the creator of this descriptor is not observing
+     * errors, it will close normally.
+     *
+     * @param msg describing the error; must not be null.
+     */
+    public void closeWithError(String msg) throws IOException {
+        if (mWrapped != null) {
+            try {
+                mWrapped.closeWithError(msg);
+            } finally {
+                releaseResources();
+            }
+        } else {
+            if (msg == null) {
+                throw new IllegalArgumentException("Message must not be null");
+            }
+            closeWithStatus(Status.ERROR, msg);
+        }
+    }
+
+    private void closeWithStatus(int status, String msg) {
         if (mClosed) return;
         mClosed = true;
         mGuard.close();
+        // Status MUST be sent before closing actual descriptor
+        writeCommStatusAndClose(status, msg);
+        IoUtils.closeQuietly(mFd);
+        releaseResources();
+    }
 
+    /**
+     * Called when the fd is being closed, for subclasses to release any other resources
+     * associated with it, such as acquired providers.
+     * @hide
+     */
+    public void releaseResources() {
+    }
+
+    private byte[] getOrCreateStatusBuffer() {
+        if (mStatusBuf == null) {
+            mStatusBuf = new byte[MAX_STATUS];
+        }
+        return mStatusBuf;
+    }
+
+    private void writeCommStatusAndClose(int status, String msg) {
+        if (mCommFd == null) {
+            // Not reliable, or someone already sent status
+            if (msg != null) {
+                Log.w(TAG, "Unable to inform peer: " + msg);
+            }
+            return;
+        }
+
+        if (status == Status.DETACHED) {
+            Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
+        }
+
+        try {
+            try {
+                if (status != Status.SILENCE) {
+                    final byte[] buf = getOrCreateStatusBuffer();
+                    int writePtr = 0;
+
+                    Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
+                    writePtr += 4;
+
+                    if (msg != null) {
+                        final byte[] rawMsg = msg.getBytes();
+                        final int len = Math.min(rawMsg.length, buf.length - writePtr);
+                        System.arraycopy(rawMsg, 0, buf, writePtr, len);
+                        writePtr += len;
+                    }
+
+                    Libcore.os.write(mCommFd, buf, 0, writePtr);
+                }
+            } catch (ErrnoException e) {
+                // Reporting status is best-effort
+                Log.w(TAG, "Failed to report status: " + e);
+            }
+
+            if (status != Status.SILENCE) {
+                // Since we're about to close, read off any remote status. It's
+                // okay to remember missing here.
+                mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
+            }
+
+        } finally {
+            IoUtils.closeQuietly(mCommFd);
+            mCommFd = null;
+        }
+    }
+
+    private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
+        try {
+            final int n = Libcore.os.read(comm, buf, 0, buf.length);
+            if (n == 0) {
+                // EOF means they're dead
+                return new Status(Status.DEAD);
+            } else {
+                final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
+                if (status == Status.ERROR) {
+                    final String msg = new String(buf, 4, n - 4);
+                    return new Status(status, msg);
+                }
+                return new Status(status);
+            }
+        } catch (ErrnoException e) {
+            if (e.errno == OsConstants.EAGAIN) {
+                // Remote is still alive, but no status written yet
+                return null;
+            } else {
+                Log.d(TAG, "Failed to read status; assuming dead: " + e);
+                return new Status(Status.DEAD);
+            }
+        }
+    }
+
+    /**
+     * Indicates if this ParcelFileDescriptor can communicate and detect remote
+     * errors/crashes.
+     *
+     * @see #checkError()
+     */
+    public boolean canDetectErrors() {
         if (mWrapped != null) {
-            // If this is a proxy to another file descriptor, just call through to its
-            // close method.
-            mWrapped.close();
+            return mWrapped.canDetectErrors();
         } else {
-            Parcel.closeFileDescriptor(mFileDescriptor);
+            return mCommFd != null;
+        }
+    }
+
+    /**
+     * Detect and throw if the other end of a pipe or socket pair encountered an
+     * error or crashed. This allows a reader to distinguish between a valid EOF
+     * and an error/crash.
+     * <p>
+     * If this ParcelFileDescriptor is unable to detect remote errors, it will
+     * return silently.
+     *
+     * @throws IOException for normal errors.
+     * @throws FileDescriptorDetachedException
+     *            if the remote side called {@link #detachFd()}. Once detached, the remote
+     *            side is unable to communicate any errors through
+     *            {@link #closeWithError(String)}.
+     * @see #canDetectErrors()
+     */
+    public void checkError() throws IOException {
+        if (mWrapped != null) {
+            mWrapped.checkError();
+        } else {
+            if (mStatus == null) {
+                if (mCommFd == null) {
+                    Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
+                    return;
+                }
+
+                // Try reading status; it might be null if nothing written yet.
+                // Either way, we keep comm open to write our status later.
+                mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
+            }
+
+            if (mStatus == null || mStatus.status == Status.OK) {
+                // No status yet, or everything is peachy!
+                return;
+            } else {
+                throw mStatus.asIOException();
+            }
         }
     }
 
@@ -330,17 +786,17 @@
      * ParcelFileDescriptor.close()} for you when the stream is closed.
      */
     public static class AutoCloseInputStream extends FileInputStream {
-        private final ParcelFileDescriptor mFd;
+        private final ParcelFileDescriptor mPfd;
 
-        public AutoCloseInputStream(ParcelFileDescriptor fd) {
-            super(fd.getFileDescriptor());
-            mFd = fd;
+        public AutoCloseInputStream(ParcelFileDescriptor pfd) {
+            super(pfd.getFileDescriptor());
+            mPfd = pfd;
         }
 
         @Override
         public void close() throws IOException {
             try {
-                mFd.close();
+                mPfd.close();
             } finally {
                 super.close();
             }
@@ -353,17 +809,17 @@
      * ParcelFileDescriptor.close()} for you when the stream is closed.
      */
     public static class AutoCloseOutputStream extends FileOutputStream {
-        private final ParcelFileDescriptor mFd;
+        private final ParcelFileDescriptor mPfd;
 
-        public AutoCloseOutputStream(ParcelFileDescriptor fd) {
-            super(fd.getFileDescriptor());
-            mFd = fd;
+        public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
+            super(pfd.getFileDescriptor());
+            mPfd = pfd;
         }
 
         @Override
         public void close() throws IOException {
             try {
-                mFd.close();
+                mPfd.close();
             } finally {
                 super.close();
             }
@@ -372,42 +828,37 @@
 
     @Override
     public String toString() {
-        return "{ParcelFileDescriptor: " + mFileDescriptor + "}";
+        if (mWrapped != null) {
+            return mWrapped.toString();
+        } else {
+            return "{ParcelFileDescriptor: " + mFd + "}";
+        }
     }
 
     @Override
     protected void finalize() throws Throwable {
+        if (mWrapped != null) {
+            releaseResources();
+        }
         if (mGuard != null) {
             mGuard.warnIfOpen();
         }
         try {
             if (!mClosed) {
-                close();
+                closeWithStatus(Status.LEAKED, null);
             }
         } finally {
             super.finalize();
         }
     }
 
-    public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
-        mWrapped = descriptor;
-        mFileDescriptor = mWrapped.mFileDescriptor;
-        mGuard.open("close");
-    }
-
-    /** {@hide} */
-    public ParcelFileDescriptor(FileDescriptor descriptor) {
-        if (descriptor == null) {
-            throw new NullPointerException("descriptor must not be null");
-        }
-        mWrapped = null;
-        mFileDescriptor = descriptor;
-        mGuard.open("close");
-    }
-
     @Override
     public int describeContents() {
-        return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+        if (mWrapped != null) {
+            return mWrapped.describeContents();
+        } else {
+            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+        }
     }
 
     /**
@@ -417,12 +868,23 @@
      */
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeFileDescriptor(mFileDescriptor);
-        if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
+        if (mWrapped != null) {
             try {
-                close();
-            } catch (IOException e) {
-                // Empty
+                mWrapped.writeToParcel(out, flags);
+            } finally {
+                releaseResources();
+            }
+        } else {
+            out.writeFileDescriptor(mFd);
+            if (mCommFd != null) {
+                out.writeInt(1);
+                out.writeFileDescriptor(mCommFd);
+            } else {
+                out.writeInt(0);
+            }
+            if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
+                // Not a real close, so emit no status
+                closeWithStatus(Status.SILENCE, null);
             }
         }
     }
@@ -431,7 +893,12 @@
             = new Parcelable.Creator<ParcelFileDescriptor>() {
         @Override
         public ParcelFileDescriptor createFromParcel(Parcel in) {
-            return in.readFileDescriptor();
+            final FileDescriptor fd = in.readRawFileDescriptor();
+            FileDescriptor commChannel = null;
+            if (in.readInt() != 0) {
+                commChannel = in.readRawFileDescriptor();
+            }
+            return new ParcelFileDescriptor(fd, commChannel);
         }
 
         @Override
@@ -439,4 +906,118 @@
             return new ParcelFileDescriptor[size];
         }
     };
+
+    /**
+     * Callback indicating that a ParcelFileDescriptor has been closed.
+     */
+    public interface OnCloseListener {
+        /**
+         * Event indicating the ParcelFileDescriptor to which this listener was
+         * attached has been closed.
+         *
+         * @param e error state, or {@code null} if closed cleanly.
+         *        If the close event was the result of
+         *        {@link ParcelFileDescriptor#detachFd()}, this will be a
+         *        {@link FileDescriptorDetachedException}. After detach the
+         *        remote side may continue reading/writing to the underlying
+         *        {@link FileDescriptor}, but they can no longer deliver
+         *        reliable close/error events.
+         */
+        public void onClose(IOException e);
+    }
+
+    /**
+     * Exception that indicates that the file descriptor was detached.
+     */
+    public static class FileDescriptorDetachedException extends IOException {
+
+        private static final long serialVersionUID = 0xDe7ac4edFdL;
+
+        public FileDescriptorDetachedException() {
+            super("Remote side is detached");
+        }
+    }
+
+    /**
+     * Internal class representing a remote status read by
+     * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
+     */
+    private static class Status {
+        /** Special value indicating remote side died. */
+        public static final int DEAD = -2;
+        /** Special value indicating no status should be written. */
+        public static final int SILENCE = -1;
+
+        /** Remote reported that everything went better than expected. */
+        public static final int OK = 0;
+        /** Remote reported error; length and message follow. */
+        public static final int ERROR = 1;
+        /** Remote reported {@link #detachFd()} and went rogue. */
+        public static final int DETACHED = 2;
+        /** Remote reported their object was finalized. */
+        public static final int LEAKED = 3;
+
+        public final int status;
+        public final String msg;
+
+        public Status(int status) {
+            this(status, null);
+        }
+
+        public Status(int status, String msg) {
+            this.status = status;
+            this.msg = msg;
+        }
+
+        public IOException asIOException() {
+            switch (status) {
+                case DEAD:
+                    return new IOException("Remote side is dead");
+                case OK:
+                    return null;
+                case ERROR:
+                    return new IOException("Remote error: " + msg);
+                case DETACHED:
+                    return new FileDescriptorDetachedException();
+                case LEAKED:
+                    return new IOException("Remote side was leaked");
+                default:
+                    return new IOException("Unknown status: " + status);
+            }
+        }
+    }
+
+    /**
+     * Bridge to watch for remote status, and deliver to listener. Currently
+     * requires that communication socket is <em>blocking</em>.
+     */
+    private static final class ListenerBridge extends Thread {
+        // TODO: switch to using Looper to avoid burning a thread
+
+        private FileDescriptor mCommFd;
+        private final Handler mHandler;
+
+        public ListenerBridge(FileDescriptor comm, Looper looper, final OnCloseListener listener) {
+            mCommFd = comm;
+            mHandler = new Handler(looper) {
+                @Override
+                public void handleMessage(Message msg) {
+                    final Status s = (Status) msg.obj;
+                    listener.onClose(s != null ? s.asIOException() : null);
+                }
+            };
+        }
+
+        @Override
+        public void run() {
+            try {
+                final byte[] buf = new byte[MAX_STATUS];
+                final Status status = readCommStatus(mCommFd, buf);
+                mHandler.obtainMessage(0, status).sendToTarget();
+            } finally {
+                IoUtils.closeQuietly(mCommFd);
+                mCommFd = null;
+            }
+        }
+    }
 }
diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java
new file mode 100644
index 0000000..11785f1
--- /dev/null
+++ b/core/java/android/os/ParcelableParcel.java
@@ -0,0 +1,75 @@
+/*
+ * 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 android.os;
+
+/**
+ * Parcelable containing a raw Parcel of data.
+ * @hide
+ */
+public class ParcelableParcel implements Parcelable {
+    final Parcel mParcel;
+    final ClassLoader mClassLoader;
+
+    public ParcelableParcel(ClassLoader loader) {
+        mParcel = Parcel.obtain();
+        mClassLoader = loader;
+    }
+
+    public ParcelableParcel(Parcel src, ClassLoader loader) {
+        mParcel = Parcel.obtain();
+        mClassLoader = loader;
+        int size = src.readInt();
+        int pos = src.dataPosition();
+        mParcel.appendFrom(src, src.dataPosition(), size);
+        src.setDataPosition(pos + size);
+    }
+
+    public Parcel getParcel() {
+        mParcel.setDataPosition(0);
+        return mParcel;
+    }
+
+    public ClassLoader getClassLoader() {
+        return mClassLoader;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mParcel.dataSize());
+        dest.appendFrom(mParcel, 0, mParcel.dataSize());
+    }
+
+    public static final Parcelable.ClassLoaderCreator<ParcelableParcel> CREATOR
+            = new Parcelable.ClassLoaderCreator<ParcelableParcel>() {
+        public ParcelableParcel createFromParcel(Parcel in) {
+            return new ParcelableParcel(in, null);
+        }
+
+        public ParcelableParcel createFromParcel(Parcel in, ClassLoader loader) {
+            return new ParcelableParcel(in, loader);
+        }
+
+        public ParcelableParcel[] newArray(int size) {
+            return new ParcelableParcel[size];
+        }
+    };
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 736762f..5e0d489 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -224,7 +224,7 @@
 
     /**
      * Flag for {@link WakeLock#release release(int)} to defer releasing a
-     * {@link #WAKE_BIT_PROXIMITY_SCREEN_OFF} wake lock until the proximity sensor returns
+     * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
      * a negative value.
      *
      * {@hide}
@@ -407,7 +407,7 @@
      */
     public WakeLock newWakeLock(int levelAndFlags, String tag) {
         validateWakeLockParameters(levelAndFlags, tag);
-        return new WakeLock(levelAndFlags, tag);
+        return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
     }
 
     /** @hide */
@@ -624,6 +624,7 @@
     public final class WakeLock {
         private final int mFlags;
         private final String mTag;
+        private final String mPackageName;
         private final IBinder mToken;
         private int mCount;
         private boolean mRefCounted = true;
@@ -636,9 +637,10 @@
             }
         };
 
-        WakeLock(int flags, String tag) {
+        WakeLock(int flags, String tag, String packageName) {
             mFlags = flags;
             mTag = tag;
+            mPackageName = packageName;
             mToken = new Binder();
         }
 
@@ -714,7 +716,7 @@
                 // been explicitly released by the keyguard.
                 mHandler.removeCallbacks(mReleaser);
                 try {
-                    mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);
+                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource);
                 } catch (RemoteException e) {
                 }
                 mHeld = true;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d940004..631edd6 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -100,12 +100,6 @@
     public static final int DRM_UID = 1019;
 
     /**
-     * Defines the GID for the group that allows write access to the SD card.
-     * @hide
-     */
-    public static final int SDCARD_RW_GID = 1015;
-
-    /**
      * Defines the UID/GID for the group that controls VPN services.
      * @hide
      */
@@ -130,11 +124,18 @@
     public static final int MEDIA_RW_GID = 1023;
 
     /**
+     * Access to installed package details
+     * @hide
+     */
+    public static final int PACKAGE_INFO_GID = 1032;
+
+    /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
      * to applications.
      */
     public static final int FIRST_APPLICATION_UID = 10000;
+
     /**
      * Last of application-specific UIDs starting at
      * {@link #FIRST_APPLICATION_UID}.
@@ -654,6 +655,14 @@
     }
 
     /**
+     * Returns the identifier of this process' parent.
+     * @hide
+     */
+    public static final int myPpid() {
+        return Libcore.os.getppid();
+    }
+
+    /**
      * Returns the identifier of the calling thread, which be used with
      * {@link #setThreadPriority(int, int)}.
      */
@@ -896,6 +905,19 @@
     public static final native boolean setOomAdj(int pid, int amt);
 
     /**
+     * Adjust the swappiness level for a process.
+     *
+     * @param pid The process identifier to set.
+     * @param is_increased Whether swappiness should be increased or default.
+     *
+     * @return Returns true if the underlying system supports this
+     *         feature, else false.
+     *
+     * {@hide}
+     */
+    public static final native boolean setSwappiness(int pid, boolean is_increased);
+
+    /**
      * Change this process's argv[0] parameter.  This can be useful to show
      * more descriptive information in things like the 'ps' command.
      * 
@@ -978,6 +1000,8 @@
     /** @hide */
     public static final int PROC_PARENS = 0x200;
     /** @hide */
+    public static final int PROC_QUOTES = 0x400;
+    /** @hide */
     public static final int PROC_OUT_STRING = 0x1000;
     /** @hide */
     public static final int PROC_OUT_LONG = 0x2000;
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 480fe7d..5e20dec 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -244,12 +244,17 @@
             // The signature cert matches a trusted key.  Now verify that
             // the digest in the cert matches the actual file data.
 
-            // The verifier in recovery *only* handles SHA1withRSA
-            // signatures.  SignApk.java always uses SHA1withRSA, no
-            // matter what the cert says to use.  Ignore
-            // cert.getSigAlgName(), and instead use whatever
-            // algorithm is used by the signature (which should be
-            // SHA1withRSA).
+            // The verifier in recovery only handles SHA1withRSA and
+            // SHA256withRSA signatures.  SignApk chooses which to use
+            // based on the signature algorithm of the cert:
+            //
+            //    "SHA256withRSA" cert -> "SHA256withRSA" signature
+            //    "SHA1withRSA" cert   -> "SHA1withRSA" signature
+            //    "MD5withRSA" cert    -> "SHA1withRSA" signature (for backwards compatibility)
+            //    any other cert       -> SignApk fails
+            //
+            // Here we ignore whatever the cert says, and instead use
+            // whatever algorithm is used by the signature.
 
             String da = sigInfo.getDigestAlgorithm();
             String dea = sigInfo.getDigestEncryptionAlgorithm();
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index d02a320..d2a9cdc 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import java.util.HashMap;
+import android.util.ArrayMap;
 
 /**
  * Takes care of the grunt work of maintaining a list of remote interfaces,
@@ -47,8 +47,8 @@
  * implements the {@link #onCallbackDied} method.
  */
 public class RemoteCallbackList<E extends IInterface> {
-    /*package*/ HashMap<IBinder, Callback> mCallbacks
-            = new HashMap<IBinder, Callback>();
+    /*package*/ ArrayMap<IBinder, Callback> mCallbacks
+            = new ArrayMap<IBinder, Callback>();
     private Object[] mActiveBroadcast;
     private int mBroadcastCount = -1;
     private boolean mKilled = false;
@@ -159,7 +159,8 @@
      */
     public void kill() {
         synchronized (mCallbacks) {
-            for (Callback cb : mCallbacks.values()) {
+            for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) {
+                Callback cb = mCallbacks.valueAt(cbi);
                 cb.mCallback.asBinder().unlinkToDeath(cb, 0);
             }
             mCallbacks.clear();
@@ -238,11 +239,10 @@
             if (active == null || active.length < N) {
                 mActiveBroadcast = active = new Object[N];
             }
-            int i=0;
-            for (Callback cb : mCallbacks.values()) {
-                active[i++] = cb;
+            for (int i=0; i<N; i++) {
+                active[i] = mCallbacks.valueAt(i);
             }
-            return i;
+            return N;
         }
     }
 
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3267939..d794ca6 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Printer;
 import android.util.Singleton;
@@ -31,6 +32,7 @@
 
 import com.android.internal.os.RuntimeInit;
 
+import com.android.internal.util.FastPrintWriter;
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
 import dalvik.system.VMDebug;
@@ -782,13 +784,15 @@
             BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
             return;
         }
-        BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
-        if (!(policy instanceof AndroidBlockGuardPolicy)) {
-            BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask));
+        final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+        final AndroidBlockGuardPolicy androidPolicy;
+        if (policy instanceof AndroidBlockGuardPolicy) {
+            androidPolicy = (AndroidBlockGuardPolicy) policy;
         } else {
-            AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy;
-            androidPolicy.setPolicyMask(policyMask);
+            androidPolicy = threadAndroidPolicy.get();
+            BlockGuard.setThreadPolicy(androidPolicy);
         }
+        androidPolicy.setPolicyMask(policyMask);
     }
 
     // Sets up CloseGuard in Dalvik/libcore
@@ -1059,6 +1063,14 @@
         }
     };
 
+    private static final ThreadLocal<AndroidBlockGuardPolicy>
+            threadAndroidPolicy = new ThreadLocal<AndroidBlockGuardPolicy>() {
+        @Override
+        protected AndroidBlockGuardPolicy initialValue() {
+            return new AndroidBlockGuardPolicy(0);
+        }
+    };
+
     private static boolean tooManyViolationsThisLoop() {
         return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
     }
@@ -1069,7 +1081,7 @@
         // Map from violation stacktrace hashcode -> uptimeMillis of
         // last violation.  No locking needed, as this is only
         // accessed by the same thread.
-        private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>();
+        private ArrayMap<Integer, Long> mLastViolationTime;
 
         public AndroidBlockGuardPolicy(final int policyMask) {
             mPolicyMask = policyMask;
@@ -1279,8 +1291,13 @@
             // Not perfect, but fast and good enough for dup suppression.
             Integer crashFingerprint = info.hashCode();
             long lastViolationTime = 0;
-            if (mLastViolationTime.containsKey(crashFingerprint)) {
-                lastViolationTime = mLastViolationTime.get(crashFingerprint);
+            if (mLastViolationTime != null) {
+                Long vtime = mLastViolationTime.get(crashFingerprint);
+                if (vtime != null) {
+                    lastViolationTime = vtime;
+                }
+            } else {
+                mLastViolationTime = new ArrayMap<Integer, Long>(1);
             }
             long now = SystemClock.uptimeMillis();
             mLastViolationTime.put(crashFingerprint, now);
@@ -1684,7 +1701,9 @@
     /* package */ static void readAndHandleBinderCallViolations(Parcel p) {
         // Our own stack trace to append
         StringWriter sw = new StringWriter();
-        new LogStackTrace().printStackTrace(new PrintWriter(sw));
+        PrintWriter pw = new FastPrintWriter(sw, false, 256);
+        new LogStackTrace().printStackTrace(pw);
+        pw.flush();
         String ourStack = sw.toString();
 
         int policyMask = getThreadPolicyMask();
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index e66fb285..700f80d 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -39,7 +39,7 @@
     }
 
     public SystemVibrator(Context context) {
-        mPackageName = context.getBasePackageName();
+        mPackageName = context.getOpPackageName();
         mService = IVibratorService.Stub.asInterface(
                 ServiceManager.getService("vibrator"));
     }
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index e53cb5e..bb3d296 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -67,6 +67,8 @@
     public static final long TRACE_TAG_RESOURCES = 1L << 13;
     /** @hide */
     public static final long TRACE_TAG_DALVIK = 1L << 14;
+    /** @hide */
+    public static final long TRACE_TAG_RS = 1L << 15;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index d205253..6e693a4 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -168,8 +168,11 @@
             if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
                 sb.append('i');
                 sb.append(appId - Process.FIRST_ISOLATED_UID);
-            } else {
+            } else if (appId >= Process.FIRST_APPLICATION_UID) {
                 sb.append('a');
+                sb.append(appId - Process.FIRST_APPLICATION_UID);
+            } else {
+                sb.append('s');
                 sb.append(appId);
             }
         }
@@ -190,8 +193,11 @@
             if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
                 pw.print('i');
                 pw.print(appId - Process.FIRST_ISOLATED_UID);
-            } else {
+            } else if (appId >= Process.FIRST_APPLICATION_UID) {
                 pw.print('a');
+                pw.print(appId - Process.FIRST_APPLICATION_UID);
+            } else {
+                pw.print('s');
                 pw.print(appId);
             }
         }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index cb5ed4f..a3752a1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -140,6 +140,13 @@
      */
     public static final String DISALLOW_REMOVE_USER = "no_remove_user";
 
+    /** @hide */
+    public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
+    /** @hide */
+    public static final int PIN_VERIFICATION_FAILED_NOT_SET = -2;
+    /** @hide */
+    public static final int PIN_VERIFICATION_SUCCESS = -1;
+
     private static UserManager sInstance = null;
 
     /** @hide */
@@ -340,7 +347,18 @@
      * @param restrictionKey the string key representing the restriction
      */
     public boolean hasUserRestriction(String restrictionKey) {
-        return getUserRestrictions().getBoolean(restrictionKey, false);
+        return hasUserRestriction(restrictionKey, Process.myUserHandle());
+    }
+
+    /**
+     * @hide
+     * Returns whether the given user has been disallowed from performing certain actions
+     * or setting certain settings.
+     * @param restrictionKey the string key representing the restriction
+     * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+     */
+    public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
+        return getUserRestrictions(userHandle).getBoolean(restrictionKey, false);
     }
 
     /**
@@ -620,4 +638,64 @@
             Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
         }
     }
+
+    /**
+     * Sets a new challenge PIN for restrictions. This is only for use by pre-installed
+     * apps and requires the MANAGE_USERS permission.
+     * @param newPin the PIN to use for challenge dialogs.
+     * @return Returns true if the challenge PIN was set successfully.
+     */
+    public boolean setRestrictionsChallenge(String newPin) {
+        try {
+            return mService.setRestrictionsChallenge(newPin);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not change restrictions pin");
+        }
+        return false;
+    }
+
+    /**
+     * @hide
+     * @param pin The PIN to verify, or null to get the number of milliseconds to wait for before
+     * allowing the user to enter the PIN.
+     * @return Returns a positive number (including zero) for how many milliseconds before
+     * you can accept another PIN, when the input is null or the input doesn't match the saved PIN.
+     * Returns {@link #PIN_VERIFICATION_SUCCESS} if the input matches the saved PIN. Returns
+     * {@link #PIN_VERIFICATION_FAILED_NOT_SET} if there is no PIN set.
+     */
+    public int checkRestrictionsChallenge(String pin) {
+        try {
+            return mService.checkRestrictionsChallenge(pin);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not check restrictions pin");
+        }
+        return PIN_VERIFICATION_FAILED_INCORRECT;
+    }
+
+    /**
+     * @hide
+     * Checks whether the user has restrictions that are PIN-protected. An application that
+     * participates in restrictions can check if the owner has requested a PIN challenge for
+     * any restricted operations. If there is a PIN in effect, the application should launch
+     * the PIN challenge activity {@link android.content.Intent#ACTION_RESTRICTIONS_CHALLENGE}.
+     * @see android.content.Intent#ACTION_RESTRICTIONS_CHALLENGE
+     * @return whether a restrictions PIN is in effect.
+     */
+    public boolean hasRestrictionsChallenge() {
+        try {
+            return mService.hasRestrictionsChallenge();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not change restrictions pin");
+        }
+        return false;
+    }
+
+    /** @hide */
+    public void removeRestrictions() {
+        try {
+            mService.removeRestrictions();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not change restrictions pin");
+        }
+    }
 }
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index b79bdee..f8da87a 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -97,6 +97,30 @@
     }
 
     /**
+     * Clear names from this WorkSource.  Uids are left intact.
+     *
+     * <p>Useful when combining with another WorkSource that doesn't have names.
+     * @hide
+     */
+    public void clearNames() {
+        if (mNames != null) {
+            mNames = null;
+            // Clear out any duplicate uids now that we don't have names to disambiguate them.
+            int destIndex = 1;
+            int newNum = mNum;
+            for (int sourceIndex = 1; sourceIndex < mNum; sourceIndex++) {
+                if (mUids[sourceIndex] == mUids[sourceIndex - 1]) {
+                    newNum--;
+                } else {
+                    mUids[destIndex] = mUids[sourceIndex];
+                    destIndex++;
+                }
+            }
+            mNum = newNum;
+        }
+    }
+
+    /**
      * Clear this WorkSource to be empty.
      */
     public void clear() {
@@ -199,7 +223,6 @@
         }
         mUids[0] = uid;
         mNames[0] = name;
-        mNames = null;
     }
 
     /** @hide */
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index fc18617..51ba2f6 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -20,9 +20,7 @@
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.RemoteException;
-import android.os.storage.StorageVolume;
 
 /**
  * WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -737,7 +735,25 @@
                     _data.recycle();
                 }
                 return _result;
+            }
 
+            @Override
+            public int mkdirs(String callingPkg, String path) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(callingPkg);
+                    _data.writeString(path);
+                    mRemote.transact(Stub.TRANSACTION_mkdirs, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
             }
         }
 
@@ -811,6 +827,8 @@
 
         static final int TRANSACTION_fixPermissionsSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 33;
 
+        static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34;
+
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -1154,6 +1172,15 @@
                     reply.writeInt(resultCode);
                     return true;
                 }
+                case TRANSACTION_mkdirs: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String callingPkg = data.readString();
+                    String path = data.readString();
+                    int result = mkdirs(callingPkg, path);
+                    reply.writeNoException();
+                    reply.writeInt(result);
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -1376,4 +1403,13 @@
      */
     public int fixPermissionsSecureContainer(String id, int gid, String filename)
             throws RemoteException;
+
+    /**
+     * Ensure that all directories along given path exist, creating parent
+     * directories as needed. Validates that given path is absolute and that it
+     * contains no relative "." or ".." paths or symlinks. Also ensures that
+     * path belongs to a volume managed by vold, and that path is either
+     * external storage data or OBB directory belonging to calling app.
+     */
+    public int mkdirs(String callingPkg, String path) throws RemoteException;
 }
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index f44cbe4..9edf112 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -16,13 +16,13 @@
 
 package android.preference;
 
-
 import android.app.AlertDialog.Builder;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 
 /**
@@ -41,6 +41,7 @@
     private String mValue;
     private String mSummary;
     private int mClickedDialogEntryIndex;
+    private boolean mValueSet;
     
     public ListPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -130,9 +131,16 @@
      * @param value The value to set for the key.
      */
     public void setValue(String value) {
-        mValue = value;
-        
-        persistString(value);
+        // Always persist/notify the first time.
+        final boolean changed = !TextUtils.equals(mValue, value);
+        if (changed || !mValueSet) {
+            mValue = value;
+            mValueSet = true;
+            persistString(value);
+            if (changed) {
+                notifyChanged();
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/preference/OnDependencyChangeListener.java b/core/java/android/preference/OnDependencyChangeListener.java
deleted file mode 100644
index ce25e34..0000000
--- a/core/java/android/preference/OnDependencyChangeListener.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.preference;
-
-/**
- * Interface definition for a callback to be invoked when this
- * {@link Preference} changes with respect to enabling/disabling
- * dependents.
- */
-interface OnDependencyChangeListener {
-    /**
-     * Called when this preference has changed in a way that dependents should
-     * care to change their state.
-     * 
-     * @param disablesDependent Whether the dependent should be disabled.
-     */
-    void onDependencyChanged(Preference dependency, boolean disablesDependent);
-}
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 6c02965..37a8102 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -77,7 +77,7 @@
  * @attr ref android.R.styleable#Preference_defaultValue
  * @attr ref android.R.styleable#Preference_shouldDisableView
  */
-public class Preference implements Comparable<Preference>, OnDependencyChangeListener { 
+public class Preference implements Comparable<Preference> {
     /**
      * Specify for {@link #setOrder(int)} if a specific order is not required.
      */
@@ -115,6 +115,7 @@
     private String mDependencyKey;
     private Object mDefaultValue;
     private boolean mDependencyMet = true;
+    private boolean mParentDependencyMet = true;
     
     /**
      * @see #setShouldDisableView(boolean)
@@ -123,7 +124,7 @@
     
     private int mLayoutResId = com.android.internal.R.layout.preference;
     private int mWidgetLayoutResId;
-    private boolean mHasSpecifiedLayout = false;
+    private boolean mCanRecycleLayout = true;
     
     private OnPreferenceChangeInternalListener mListener;
     
@@ -274,9 +275,10 @@
         }
         a.recycle();
 
-        if (!getClass().getName().startsWith("android.preference")) {
-            // For subclasses not in this package, assume the worst and don't cache views
-            mHasSpecifiedLayout = true;
+        if (!getClass().getName().startsWith("android.preference")
+                && !getClass().getName().startsWith("com.android")) {
+            // For non-framework subclasses, assume the worst and don't cache views.
+            mCanRecycleLayout = false;
         }
     }
     
@@ -398,7 +400,7 @@
     public void setLayoutResource(int layoutResId) {
         if (layoutResId != mLayoutResId) {
             // Layout changed
-            mHasSpecifiedLayout = true;
+            mCanRecycleLayout = false;
         }
 
         mLayoutResId = layoutResId;
@@ -414,7 +416,7 @@
     }
     
     /**
-     * Sets The layout for the controllable widget portion of this Preference. This
+     * Sets the layout for the controllable widget portion of this Preference. This
      * is inflated into the main layout. For example, a {@link CheckBoxPreference}
      * would specify a custom layout (consisting of just the CheckBox) here,
      * instead of creating its own main layout.
@@ -426,7 +428,7 @@
     public void setWidgetLayoutResource(int widgetLayoutResId) {
         if (widgetLayoutResId != mWidgetLayoutResId) {
             // Layout changed
-            mHasSpecifiedLayout = true;
+            mCanRecycleLayout = false;
         }
         mWidgetLayoutResId = widgetLayoutResId;
     }
@@ -733,7 +735,7 @@
      * @return True if this Preference is enabled, false otherwise.
      */
     public boolean isEnabled() {
-        return mEnabled && mDependencyMet;
+        return mEnabled && mDependencyMet && mParentDependencyMet;
     }
 
     /**
@@ -1259,7 +1261,24 @@
             notifyChanged();
         }
     }
-    
+
+    /**
+     * Called when the implicit parent dependency changes.
+     *
+     * @param parent The Preference that this Preference depends on.
+     * @param disableChild Set true to disable this Preference.
+     */
+    public void onParentChanged(Preference parent, boolean disableChild) {
+        if (mParentDependencyMet == disableChild) {
+            mParentDependencyMet = !disableChild;
+
+            // Enabled state can change dependent preferences' states, so notify
+            notifyDependencyChange(shouldDisableDependents());
+
+            notifyChanged();
+        }
+    }
+
     /**
      * Checks whether this preference's dependents should currently be
      * disabled.
@@ -1641,8 +1660,8 @@
         return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
     }
     
-    boolean hasSpecifiedLayout() {
-        return mHasSpecifiedLayout;
+    boolean canRecycleLayout() {
+        return mCanRecycleLayout;
     }
     
     @Override
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index a9ee96e..2ab5a91 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -33,6 +33,7 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.LayoutInflater;
@@ -124,6 +125,8 @@
         PreferenceManager.OnPreferenceTreeClickListener,
         PreferenceFragment.OnPreferenceStartFragmentCallback {
 
+    private static final String TAG = "PreferenceActivity";
+
     // Constants for state save/restore
     private static final String HEADERS_TAG = ":android:headers";
     private static final String CUR_HEADER_TAG = ":android:cur_header";
@@ -132,6 +135,9 @@
     /**
      * When starting this activity, the invoking Intent can contain this extra
      * string to specify which fragment should be initially displayed.
+     * <p/>Starting from Key Lime Pie, when this argument is passed in, the PreferenceActivity
+     * will call isValidFragment() to confirm that the fragment class name is valid for this
+     * activity.
      */
     public static final String EXTRA_SHOW_FRAGMENT = ":android:show_fragment";
 
@@ -299,7 +305,7 @@
      * are valid.
      */
     public static final long HEADER_ID_UNDEFINED = -1;
-    
+
     /**
      * Description of a single Header item that the user can select.
      */
@@ -877,7 +883,25 @@
         } finally {
             if (parser != null) parser.close();
         }
+    }
 
+    /**
+     * Subclasses should override this method and verify that the given fragment is a valid type
+     * to be attached to this activity. The default implementation returns <code>true</code> for
+     * apps built for <code>android:targetSdkVersion</code> older than
+     * {@link android.os.Build.VERSION_CODES#KITKAT}. For later versions, it will throw an exception.
+     * @param fragmentName the class name of the Fragment about to be attached to this activity.
+     * @return true if the fragment class name is valid for this Activity and false otherwise.
+     */
+    protected boolean isValidFragment(String fragmentName) {
+        if (getApplicationInfo().targetSdkVersion  >= android.os.Build.VERSION_CODES.KITKAT) {
+            throw new RuntimeException(
+                    "Subclasses of PreferenceActivity must override isValidFragment(String)"
+                    + " to verify that the Fragment class is valid! " + this.getClass().getName()
+                    + " has not checked if fragment " + fragmentName + " is valid.");
+        } else {
+            return true;
+        }
     }
 
     /**
@@ -973,6 +997,9 @@
 
     @Override
     protected void onListItemClick(ListView l, View v, int position, long id) {
+        if (!isResumed()) {
+            return;
+        }
         super.onListItemClick(l, v, position, id);
 
         if (mAdapter != null) {
@@ -1083,6 +1110,7 @@
             try {
                 mFragmentBreadCrumbs = (FragmentBreadCrumbs)crumbs;
             } catch (ClassCastException e) {
+                setTitle(title);
                 return;
             }
             if (mFragmentBreadCrumbs == null) {
@@ -1096,12 +1124,17 @@
                 // Hide the breadcrumb section completely for single-pane
                 View bcSection = findViewById(com.android.internal.R.id.breadcrumb_section);
                 if (bcSection != null) bcSection.setVisibility(View.GONE);
+                setTitle(title);
             }
             mFragmentBreadCrumbs.setMaxVisible(2);
             mFragmentBreadCrumbs.setActivity(this);
         }
-        mFragmentBreadCrumbs.setTitle(title, shortTitle);
-        mFragmentBreadCrumbs.setParentTitle(null, null, null);
+        if (mFragmentBreadCrumbs.getVisibility() != View.VISIBLE) {
+            setTitle(title);
+        } else {
+            mFragmentBreadCrumbs.setTitle(title, shortTitle);
+            mFragmentBreadCrumbs.setParentTitle(null, null, null);
+        }
     }
 
     /**
@@ -1143,6 +1176,10 @@
     private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
         getFragmentManager().popBackStack(BACK_STACK_PREFS,
                 FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        if (!isValidFragment(fragmentName)) {
+            throw new IllegalArgumentException("Invalid fragment for this activity: "
+                    + fragmentName);
+        }
         Fragment f = Fragment.instantiate(this, fragmentName, args);
         FragmentTransaction transaction = getFragmentManager().beginTransaction();
         transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
@@ -1249,7 +1286,7 @@
     }
 
     /**
-     * Start a new fragment containing a preference panel.  If the prefences
+     * Start a new fragment containing a preference panel.  If the preferences
      * are being displayed in multi-pane mode, the given fragment class will
      * be instantiated and placed in the appropriate pane.  If running in
      * single-pane mode, a new activity will be launched in which to show the
@@ -1288,7 +1325,7 @@
             transaction.commitAllowingStateLoss();
         }
     }
-    
+
     /**
      * Called by a preference panel fragment to finish itself.
      * 
diff --git a/core/java/android/preference/PreferenceCategory.java b/core/java/android/preference/PreferenceCategory.java
index d8af324..229a96a 100644
--- a/core/java/android/preference/PreferenceCategory.java
+++ b/core/java/android/preference/PreferenceCategory.java
@@ -62,4 +62,8 @@
         return false;
     }
     
+    @Override
+    public boolean shouldDisableDependents() {
+        return !super.isEnabled();
+    }
 }
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index f33a6be..5f8c78d 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -210,10 +210,7 @@
      * @return Whether to allow adding the preference (true), or not (false).
      */
     protected boolean onPrepareAddPreference(Preference preference) {
-        if (!super.isEnabled()) {
-            preference.setEnabled(false);
-        }
-        
+        preference.onParentChanged(this, shouldDisableDependents());
         return true;
     }
 
@@ -290,13 +287,14 @@
     }
 
     @Override
-    public void setEnabled(boolean enabled) {
-        super.setEnabled(enabled);
-        
-        // Dispatch to all contained preferences
+    public void notifyDependencyChange(boolean disableDependents) {
+        super.notifyDependencyChange(disableDependents);
+
+        // Child preferences have an implicit dependency on their containing
+        // group. Dispatch dependency change to all contained preferences.
         final int preferenceCount = getPreferenceCount();
         for (int i = 0; i < preferenceCount; i++) {
-            getPreference(i).setEnabled(enabled);
+            getPreference(i).onParentChanged(this, disableDependents);
         }
     }
     
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index a908ecd..23d0a19 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -153,7 +153,7 @@
             
             preferences.add(preference);
             
-            if (!mHasReturnedViewTypeCount && !preference.hasSpecifiedLayout()) {
+            if (!mHasReturnedViewTypeCount && preference.canRecycleLayout()) {
                 addPreferenceClassName(preference);
             }
             
@@ -255,7 +255,7 @@
         }
         
         final Preference preference = this.getItem(position);
-        if (preference.hasSpecifiedLayout()) {
+        if (!preference.canRecycleLayout()) {
             return IGNORE_ITEM_VIEW_TYPE;
         }
 
diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java
index c649879..af83953 100644
--- a/core/java/android/preference/TwoStatePreference.java
+++ b/core/java/android/preference/TwoStatePreference.java
@@ -21,6 +21,7 @@
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -215,17 +216,17 @@
         TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
         if (summaryView != null) {
             boolean useDefaultSummary = true;
-            if (mChecked && mSummaryOn != null) {
+            if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
                 summaryView.setText(mSummaryOn);
                 useDefaultSummary = false;
-            } else if (!mChecked && mSummaryOff != null) {
+            } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
                 summaryView.setText(mSummaryOff);
                 useDefaultSummary = false;
             }
 
             if (useDefaultSummary) {
                 final CharSequence summary = getSummary();
-                if (summary != null) {
+                if (!TextUtils.isEmpty(summary)) {
                     summaryView.setText(summary);
                     useDefaultSummary = false;
                 }
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index caf55d7..dc683a6 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -25,11 +25,14 @@
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Settings;
 import android.provider.Settings.System;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.SeekBar;
@@ -115,7 +118,7 @@
 
     public void onActivityStop() {
         if (mSeekBarVolumizer != null) {
-            mSeekBarVolumizer.stopSample();
+            mSeekBarVolumizer.postStopSample();
         }
     }
 
@@ -220,10 +223,10 @@
     /**
      * Turns a {@link SeekBar} into a volume control.
      */
-    public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable {
+    public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
 
         private Context mContext;
-        private Handler mHandler = new Handler();
+        private Handler mHandler;
 
         private AudioManager mAudioManager;
         private int mStreamType;
@@ -234,6 +237,11 @@
         private SeekBar mSeekBar;
         private int mVolumeBeforeMute = -1;
 
+        private static final int MSG_SET_STREAM_VOLUME = 0;
+        private static final int MSG_START_SAMPLE = 1;
+        private static final int MSG_STOP_SAMPLE = 2;
+        private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+
         private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
@@ -255,6 +263,10 @@
             mStreamType = streamType;
             mSeekBar = seekBar;
 
+            HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
+            thread.start();
+            mHandler = new Handler(thread.getLooper(), this);
+
             initSeekBar(seekBar, defaultUri);
         }
 
@@ -285,8 +297,54 @@
             }
         }
 
+        @Override
+        public boolean handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_STREAM_VOLUME:
+                    mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+                    break;
+                case MSG_START_SAMPLE:
+                    onStartSample();
+                    break;
+                case MSG_STOP_SAMPLE:
+                    onStopSample();
+                    break;
+                default:
+                    Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
+            }
+            return true;
+        }
+
+        private void postStartSample() {
+            mHandler.removeMessages(MSG_START_SAMPLE);
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
+                    isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
+        }
+
+        private void onStartSample() {
+            if (!isSamplePlaying()) {
+                onSampleStarting(this);
+                if (mRingtone != null) {
+                    mRingtone.play();
+                }
+            }
+        }
+
+        private void postStopSample() {
+            // remove pending delayed start messages
+            mHandler.removeMessages(MSG_START_SAMPLE);
+            mHandler.removeMessages(MSG_STOP_SAMPLE);
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
+        }
+
+        private void onStopSample() {
+            if (mRingtone != null) {
+                mRingtone.stop();
+            }
+        }
+
         public void stop() {
-            stopSample();
+            postStopSample();
             mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
             mSeekBar.setOnSeekBarChangeListener(null);
         }
@@ -307,21 +365,15 @@
         void postSetVolume(int progress) {
             // Do the volume changing separately to give responsive UI
             mLastProgress = progress;
-            mHandler.removeCallbacks(this);
-            mHandler.post(this);
+            mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
         }
 
         public void onStartTrackingTouch(SeekBar seekBar) {
         }
 
         public void onStopTrackingTouch(SeekBar seekBar) {
-            if (!isSamplePlaying()) {
-                startSample();
-            }
-        }
-
-        public void run() {
-            mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+            postStartSample();
         }
 
         public boolean isSamplePlaying() {
@@ -329,16 +381,11 @@
         }
 
         public void startSample() {
-            onSampleStarting(this);
-            if (mRingtone != null) {
-                mRingtone.play();
-            }
+            postStartSample();
         }
 
         public void stopSample() {
-            if (mRingtone != null) {
-                mRingtone.stop();
-            }
+            postStopSample();
         }
 
         public SeekBar getSeekBar() {
@@ -347,23 +394,21 @@
 
         public void changeVolumeBy(int amount) {
             mSeekBar.incrementProgressBy(amount);
-            if (!isSamplePlaying()) {
-                startSample();
-            }
             postSetVolume(mSeekBar.getProgress());
+            postStartSample();
             mVolumeBeforeMute = -1;
         }
 
         public void muteVolume() {
             if (mVolumeBeforeMute != -1) {
                 mSeekBar.setProgress(mVolumeBeforeMute);
-                startSample();
                 postSetVolume(mVolumeBeforeMute);
+                postStartSample();
                 mVolumeBeforeMute = -1;
             } else {
                 mVolumeBeforeMute = mSeekBar.getProgress();
                 mSeekBar.setProgress(0);
-                stopSample();
+                postStopSample();
                 postSetVolume(0);
             }
         }
diff --git a/core/java/android/print/ILayoutResultCallback.aidl b/core/java/android/print/ILayoutResultCallback.aidl
new file mode 100644
index 0000000..43b8c30
--- /dev/null
+++ b/core/java/android/print/ILayoutResultCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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 android.print;
+
+import android.print.PrintDocumentInfo;
+
+/**
+ * Callback for observing the result of android.print.PrintAdapter#onLayout.
+ *
+ * @hide
+ */
+oneway interface ILayoutResultCallback {
+    void onLayoutFinished(in PrintDocumentInfo info, boolean changed, int sequence);
+    void onLayoutFailed(CharSequence error, int sequence);
+}
diff --git a/core/java/android/print/IPrintClient.aidl b/core/java/android/print/IPrintClient.aidl
new file mode 100644
index 0000000..3f39d08
--- /dev/null
+++ b/core/java/android/print/IPrintClient.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 android.print;
+
+import android.content.IntentSender;
+
+/**
+ * Interface for communication with a printing app.
+ *
+ * @see android.print.IPrintClientCallback
+ *
+ * @hide
+ */
+oneway interface IPrintClient {
+    void startPrintJobConfigActivity(in IntentSender intent);
+}
diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
new file mode 100644
index 0000000..b12c922
--- /dev/null
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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 android.print;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.print.ILayoutResultCallback;
+import android.print.IWriteResultCallback;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+
+/**
+ * Interface for communication with the print adapter object.
+ *
+ * @hide
+ */
+oneway interface IPrintDocumentAdapter {
+    void start();
+    void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes,
+            ILayoutResultCallback callback, in Bundle metadata, int sequence);
+    void write(in PageRange[] pages, in ParcelFileDescriptor fd,
+            IWriteResultCallback callback, int sequence);
+    void finish();
+}
diff --git a/core/java/android/print/IPrintJobStateChangeListener.aidl b/core/java/android/print/IPrintJobStateChangeListener.aidl
new file mode 100644
index 0000000..c1d39f0
--- /dev/null
+++ b/core/java/android/print/IPrintJobStateChangeListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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 android.print;
+
+import android.print.PrintJobId;
+
+/**
+ * Interface for observing print job state changes.
+ *
+ * @hide
+ */
+oneway interface IPrintJobStateChangeListener {
+    void onPrintJobStateChanged(in PrintJobId printJobId);
+}
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
new file mode 100644
index 0000000..3bd515b
--- /dev/null
+++ b/core/java/android/print/IPrintManager.aidl
@@ -0,0 +1,60 @@
+/*
+ * 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 android.print;
+
+import android.print.IPrinterDiscoveryObserver;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintClient;
+import android.print.PrintJobId;
+import android.print.IPrintJobStateChangeListener;
+import android.print.PrinterId;
+import android.print.PrintJobInfo;
+import android.print.PrintAttributes;
+import android.printservice.PrintServiceInfo;
+
+/**
+ * Interface for communication with the core print manager service.
+ *
+ * @hide
+ */
+interface IPrintManager {
+    List<PrintJobInfo> getPrintJobInfos(int appId, int userId);
+    PrintJobInfo getPrintJobInfo(in PrintJobId printJobId, int appId, int userId);
+    PrintJobInfo print(String printJobName, in IPrintClient client,
+            in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
+            int appId, int userId);
+    void cancelPrintJob(in PrintJobId printJobId, int appId, int userId);
+    void restartPrintJob(in PrintJobId printJobId, int appId, int userId);
+
+    void addPrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
+            int appId, int userId);
+    void removePrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
+            int userId);
+
+    List<PrintServiceInfo> getInstalledPrintServices(int userId);
+    List<PrintServiceInfo> getEnabledPrintServices(int userId);
+
+    void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
+    void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
+            in List<PrinterId> priorityList, int userId);
+    void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
+    void validatePrinters(in List<PrinterId> printerIds, int userId);
+    void startPrinterStateTracking(in PrinterId printerId, int userId);
+    void stopPrinterStateTracking(in PrinterId printerId, int userId);
+    void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
+            int userId);
+}
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
new file mode 100644
index 0000000..96b168d
--- /dev/null
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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 android.print;
+
+import android.content.ComponentName;
+import android.os.ParcelFileDescriptor;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintClient;
+import android.print.IPrintSpoolerClient;
+import android.print.IPrintSpoolerCallbacks;
+import android.print.PrinterInfo;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+
+/**
+ * Interface for communication with the print spooler service.
+ *
+ * @see android.print.IPrintSpoolerCallbacks
+ *
+ * @hide
+ */
+oneway interface IPrintSpooler {
+    void removeObsoletePrintJobs();
+    void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName,
+            int state, int appId, int sequence);
+    void getPrintJobInfo(in PrintJobId printJobId, IPrintSpoolerCallbacks callback,
+            int appId, int sequence);
+    void createPrintJob(in PrintJobInfo printJob, in IPrintClient client,
+            in IPrintDocumentAdapter printAdapter);
+    void setPrintJobState(in PrintJobId printJobId, int status, String stateReason,
+            IPrintSpoolerCallbacks callback, int sequence);
+    void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
+            int sequence);
+    void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
+    void setClient(IPrintSpoolerClient client);
+}
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
new file mode 100644
index 0000000..45c5332
--- /dev/null
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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 android.print;
+
+import android.print.PrintJobInfo;
+import java.util.List;
+
+/**
+ * Callbacks for communication with the print spooler service.
+ *
+ * @see android.print.IPrintSpoolerService
+ *
+ * @hide
+ */
+oneway interface IPrintSpoolerCallbacks {
+    void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence);
+    void onCancelPrintJobResult(boolean canceled, int sequence);
+    void onSetPrintJobStateResult(boolean success, int sequence);
+    void onSetPrintJobTagResult(boolean success, int sequence);
+    void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence);
+}
diff --git a/core/java/android/print/IPrintSpoolerClient.aidl b/core/java/android/print/IPrintSpoolerClient.aidl
new file mode 100644
index 0000000..8270812
--- /dev/null
+++ b/core/java/android/print/IPrintSpoolerClient.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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 android.print;
+
+import android.content.ComponentName;
+import android.print.PrintJobInfo;
+import android.print.PrintJobId;
+
+/**
+ * Interface for receiving interesting state updates from the print spooler.
+ *
+ * @hide
+ */
+oneway interface IPrintSpoolerClient {
+    void onPrintJobQueued(in PrintJobInfo printJob);
+    void onAllPrintJobsForServiceHandled(in ComponentName printService);
+    void onAllPrintJobsHandled();
+    void onPrintJobStateChanged(in PrintJobInfo printJob);
+}
diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl
new file mode 100644
index 0000000..2be7b6b
--- /dev/null
+++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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 android.print;
+
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * Interface for observing discovered printers by a discovery session.
+ *
+ * @hide
+ */
+oneway interface IPrinterDiscoveryObserver {
+    void onPrintersAdded(in ParceledListSlice printers);
+    void onPrintersRemoved(in ParceledListSlice printerIds);
+}
diff --git a/core/java/android/print/IWriteResultCallback.aidl b/core/java/android/print/IWriteResultCallback.aidl
new file mode 100644
index 0000000..8281c4e
--- /dev/null
+++ b/core/java/android/print/IWriteResultCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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 android.print;
+
+import android.print.PageRange;
+
+/**
+ * Callback for observing the result of android.print.DocuemntAdapter#onWrite.
+ *
+ * @hide
+ */
+oneway interface IWriteResultCallback {
+    void onWriteFinished(in PageRange[] pages, int sequence);
+    void onWriteFailed(CharSequence error, int sequence);
+}
diff --git a/core/java/android/print/PageRange.aidl b/core/java/android/print/PageRange.aidl
new file mode 100644
index 0000000..b1ae14f
--- /dev/null
+++ b/core/java/android/print/PageRange.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PageRange;
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
new file mode 100644
index 0000000..cdcd0c7
--- /dev/null
+++ b/core/java/android/print/PageRange.java
@@ -0,0 +1,149 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a range of pages. The start and end page indices of
+ * the range are zero based and inclusive.
+ */
+public final class PageRange implements Parcelable {
+
+    /**
+     * Constant for specifying all pages.
+     */
+    public static final PageRange ALL_PAGES = new PageRange(0, Integer.MAX_VALUE);
+
+    private final int mStart;
+    private final int mEnd;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param start The start page index (zero based and inclusive).
+     * @param end The end page index (zero based and inclusive).
+     *
+     * @throws IllegalArgumentException If start is less than zero.
+     * @throws IllegalArgumentException If end is less than zero.
+     * @throws IllegalArgumentException If start greater than end.
+     */
+    public PageRange(int start, int end) {
+        if (start < 0) {
+            throw new IllegalArgumentException("start cannot be less than zero.");
+        }
+        if (end < 0) {
+            throw new IllegalArgumentException("end cannot be less than zero.");
+        }
+        if (start > end) {
+            throw new IllegalArgumentException("start must be lesser than end.");
+        }
+        mStart = start;
+        mEnd = end;
+    }
+
+    private PageRange (Parcel parcel) {
+        this(parcel.readInt(), parcel.readInt());
+    }
+
+    /**
+     * Gets the start page index (zero based and inclusive).
+     *
+     * @return The start page index.
+     */
+    public int getStart() {
+        return mStart;
+    }
+
+    /**
+     * Gets the end page index (zero based and inclusive).
+     *
+     * @return The end page index.
+     */
+    public int getEnd() {
+        return mEnd;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mStart);
+        parcel.writeInt(mEnd);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mEnd;
+        result = prime * result + mStart;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PageRange other = (PageRange) obj;
+        if (mEnd != other.mEnd) {
+            return false;
+        }
+        if (mStart != other.mStart) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        if (mStart == 0 && mEnd == Integer.MAX_VALUE) {
+            return "PageRange[<all pages>]";
+        }
+        StringBuilder builder = new StringBuilder();
+        builder.append("PageRange[")
+            .append(mStart)
+            .append(" - ")
+            .append(mEnd)
+            .append("]");
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<PageRange> CREATOR =
+            new Creator<PageRange>() {
+        @Override
+        public PageRange createFromParcel(Parcel parcel) {
+            return new PageRange(parcel);
+        }
+
+        @Override
+        public PageRange[] newArray(int size) {
+            return new PageRange[size];
+        }
+    };
+}
diff --git a/core/java/android/print/PrintAttributes.aidl b/core/java/android/print/PrintAttributes.aidl
new file mode 100644
index 0000000..0b765a2
--- /dev/null
+++ b/core/java/android/print/PrintAttributes.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrintAttributes;
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
new file mode 100644
index 0000000..959380d
--- /dev/null
+++ b/core/java/android/print/PrintAttributes.java
@@ -0,0 +1,1234 @@
+/*
+ * 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 android.print;
+
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources.NotFoundException;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+
+/**
+ * This class represents the attributes of a print job.
+ */
+public final class PrintAttributes implements Parcelable {
+    /** Color mode: Monochrome color scheme, for example one color is used. */
+    public static final int COLOR_MODE_MONOCHROME = 1 << 0;
+    /** Color mode: Color color scheme, for example many colors are used. */
+    public static final int COLOR_MODE_COLOR = 1 << 1;
+
+    private static final int VALID_COLOR_MODES =
+            COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
+
+    private MediaSize mMediaSize;
+    private Resolution mResolution;
+    private Margins mMinMargins;
+
+    private int mColorMode;
+
+    PrintAttributes() {
+        /* hide constructor */
+    }
+
+    private PrintAttributes(Parcel parcel) {
+        mMediaSize = (parcel.readInt() ==  1) ? MediaSize.createFromParcel(parcel) : null;
+        mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
+        mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
+        mColorMode = parcel.readInt();
+    }
+
+    /**
+     * Gets the media size.
+     *
+     * @return The media size or <code>null</code> if not set.
+     */
+    public MediaSize getMediaSize() {
+        return mMediaSize;
+    }
+
+    /**
+     * Sets the media size.
+     *
+     * @param The media size.
+     *
+     * @hide
+     */
+    public void setMediaSize(MediaSize mediaSize) {
+        mMediaSize = mediaSize;
+    }
+
+    /**
+     * Gets the resolution.
+     *
+     * @return The resolution or <code>null</code> if not set.
+     */
+    public Resolution getResolution() {
+        return mResolution;
+    }
+
+    /**
+     * Sets the resolution.
+     *
+     * @param The resolution.
+     *
+     * @hide
+     */
+    public void setResolution(Resolution resolution) {
+        mResolution = resolution;
+    }
+
+    /**
+     * Gets the minimal margins. If the content does not fit
+     * these margins it will be clipped.
+     *
+     * @return The margins or <code>null</code> if not set.
+     */
+    public Margins getMinMargins() {
+        return mMinMargins;
+    }
+
+    /**
+     * Sets the minimal margins. If the content does not fit
+     * these margins it will be clipped.
+     *
+     * @param The margins.
+     *
+     * @hide
+     */
+    public void setMinMargins(Margins margins) {
+        mMinMargins = margins;
+    }
+
+    /**
+     * Gets the color mode.
+     *
+     * @return The color mode or zero if not set.
+     *
+     * @see #COLOR_MODE_COLOR
+     * @see #COLOR_MODE_MONOCHROME
+     */
+    public int getColorMode() {
+        return mColorMode;
+    }
+
+    /**
+     * Sets the color mode.
+     *
+     * @param The color mode.
+     *
+     * @see #COLOR_MODE_MONOCHROME
+     * @see #COLOR_MODE_COLOR
+     *
+     * @hide
+     */
+    public void setColorMode(int colorMode) {
+        enforceValidColorMode(colorMode);
+        mColorMode = colorMode;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        if (mMediaSize != null) {
+            parcel.writeInt(1);
+            mMediaSize.writeToParcel(parcel);
+        } else {
+            parcel.writeInt(0);
+        }
+        if (mResolution != null) {
+            parcel.writeInt(1);
+            mResolution.writeToParcel(parcel);
+        } else {
+            parcel.writeInt(0);
+        }
+        if (mMinMargins != null) {
+            parcel.writeInt(1);
+            mMinMargins.writeToParcel(parcel);
+        } else {
+            parcel.writeInt(0);
+        }
+        parcel.writeInt(mColorMode);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mColorMode;
+        result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
+        result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
+        result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrintAttributes other = (PrintAttributes) obj;
+        if (mColorMode != other.mColorMode) {
+            return false;
+        }
+        if (mMinMargins == null) {
+            if (other.mMinMargins != null) {
+                return false;
+            }
+        } else if (!mMinMargins.equals(other.mMinMargins)) {
+            return false;
+        }
+        if (mMediaSize == null) {
+            if (other.mMediaSize != null) {
+                return false;
+            }
+        } else if (!mMediaSize.equals(other.mMediaSize)) {
+            return false;
+        }
+        if (mResolution == null) {
+            if (other.mResolution != null) {
+                return false;
+            }
+        } else if (!mResolution.equals(other.mResolution)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrintAttributes{");
+        builder.append("mediaSize: ").append(mMediaSize);
+        if (mMediaSize != null) {
+            builder.append(", orientation: ").append(mMediaSize.isPortrait()
+                    ? "portrait" : "landscape");
+        } else {
+            builder.append(", orientation: ").append("null");
+        }
+        builder.append(", resolution: ").append(mResolution);
+        builder.append(", minMargins: ").append(mMinMargins);
+        builder.append(", colorMode: ").append(colorModeToString(mColorMode));
+        builder.append("}");
+        return builder.toString();
+    }
+
+    /** @hide */
+    public void clear() {
+        mMediaSize = null;
+        mResolution = null;
+        mMinMargins = null;
+        mColorMode = 0;
+    }
+
+    /**
+     * @hide
+     */
+    public void copyFrom(PrintAttributes other) {
+        mMediaSize = other.mMediaSize;
+        mResolution = other.mResolution;
+        mMinMargins = other.mMinMargins;
+        mColorMode = other.mColorMode;
+    }
+
+    /**
+     * This class specifies a supported media size. Media size is the
+     * dimension of the media on which the content is printed. For
+     * example, the {@link #NA_LETTER} media size designates a page
+     * with size 8.5" x 11".
+     */
+    public static final class MediaSize {
+        private static final String LOG_TAG = "MediaSize";
+
+        /**
+         * Unknown media size in portrait mode.
+         * <p>
+         * <strong>Note: </strong>This is for specifying orientation without media
+         * size. You should not use the dimensions reported by this class.
+         * </p>
+         */
+        public static final MediaSize UNKNOWN_PORTRAIT =
+                new MediaSize("UNKNOWN_PORTRAIT", "android",
+                        R.string.mediasize_unknown_portrait, Integer.MAX_VALUE, 1);
+
+        /**
+         * Unknown media size in landscape mode.
+         * <p>
+         * <strong>Note: </strong>This is for specifying orientation without media
+         * size. You should not use the dimensions reported by this class.
+         * </p>
+         */
+        public static final MediaSize UNKNOWN_LANDSCAPE =
+                new MediaSize("UNKNOWN_LANDSCAPE", "android",
+                        R.string.mediasize_unknown_landscape, 1, Integer.MAX_VALUE);
+
+        // ISO sizes
+
+        /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */
+        public static final MediaSize ISO_A0 =
+                new MediaSize("ISO_A0", "android", R.string.mediasize_iso_a0, 33110, 46810);
+        /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */
+        public static final MediaSize ISO_A1 =
+                new MediaSize("ISO_A1", "android", R.string.mediasize_iso_a1, 23390, 33110);
+        /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */
+        public static final MediaSize ISO_A2 =
+                new MediaSize("ISO_A2", "android", R.string.mediasize_iso_a2, 16540, 23390);
+        /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */
+        public static final MediaSize ISO_A3 =
+                new MediaSize("ISO_A3", "android", R.string.mediasize_iso_a3, 11690, 16540);
+        /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */
+        public static final MediaSize ISO_A4 =
+                new MediaSize("ISO_A4", "android", R.string.mediasize_iso_a4, 8270, 11690);
+        /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */
+        public static final MediaSize ISO_A5 =
+                new MediaSize("ISO_A5", "android", R.string.mediasize_iso_a5, 5830, 8270);
+        /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */
+        public static final MediaSize ISO_A6 =
+                new MediaSize("ISO_A6", "android", R.string.mediasize_iso_a6, 4130, 5830);
+        /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */
+        public static final MediaSize ISO_A7 =
+                new MediaSize("ISO_A7", "android", R.string.mediasize_iso_a7, 2910, 4130);
+        /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */
+        public static final MediaSize ISO_A8 =
+                new MediaSize("ISO_A8", "android", R.string.mediasize_iso_a8, 2050, 2910);
+        /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */
+        public static final MediaSize ISO_A9 =
+                new MediaSize("ISO_A9", "android", R.string.mediasize_iso_a9, 1460, 2050);
+        /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */
+        public static final MediaSize ISO_A10 =
+                new MediaSize("ISO_A10", "android", R.string.mediasize_iso_a10, 1020, 1460);
+
+        /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */
+        public static final MediaSize ISO_B0 =
+                new MediaSize("ISO_B0", "android", R.string.mediasize_iso_b0, 39370, 55670);
+        /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */
+        public static final MediaSize ISO_B1 =
+                new MediaSize("ISO_B1", "android", R.string.mediasize_iso_b1, 27830, 39370);
+        /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */
+        public static final MediaSize ISO_B2 =
+                new MediaSize("ISO_B2", "android", R.string.mediasize_iso_b2, 19690, 27830);
+        /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */
+        public static final MediaSize ISO_B3 =
+                new MediaSize("ISO_B3", "android", R.string.mediasize_iso_b3, 13900, 19690);
+        /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */
+        public static final MediaSize ISO_B4 =
+                new MediaSize("ISO_B4", "android", R.string.mediasize_iso_b4, 9840, 13900);
+        /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */
+        public static final MediaSize ISO_B5 =
+                new MediaSize("ISO_B5", "android", R.string.mediasize_iso_b5, 6930, 9840);
+        /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */
+        public static final MediaSize ISO_B6 =
+                new MediaSize("ISO_B6", "android", R.string.mediasize_iso_b6, 4920, 6930);
+        /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */
+        public static final MediaSize ISO_B7 =
+                new MediaSize("ISO_B7", "android", R.string.mediasize_iso_b7, 3460, 4920);
+        /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */
+        public static final MediaSize ISO_B8 =
+                new MediaSize("ISO_B8", "android", R.string.mediasize_iso_b8, 2440, 3460);
+        /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */
+        public static final MediaSize ISO_B9 =
+                new MediaSize("ISO_B9", "android", R.string.mediasize_iso_b9, 1730, 2440);
+        /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */
+        public static final MediaSize ISO_B10 =
+                new MediaSize("ISO_B10", "android", R.string.mediasize_iso_b10, 1220, 1730);
+
+        /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */
+        public static final MediaSize ISO_C0 =
+                new MediaSize("ISO_C0", "android", R.string.mediasize_iso_c0, 36100, 51060);
+        /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */
+        public static final MediaSize ISO_C1 =
+                new MediaSize("ISO_C1", "android", R.string.mediasize_iso_c1, 25510, 36100);
+        /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */
+        public static final MediaSize ISO_C2 =
+                new MediaSize("ISO_C2", "android", R.string.mediasize_iso_c2, 18030, 25510);
+        /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */
+        public static final MediaSize ISO_C3 =
+                new MediaSize("ISO_C3", "android", R.string.mediasize_iso_c3, 12760, 18030);
+        /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */
+        public static final MediaSize ISO_C4 =
+                new MediaSize("ISO_C4", "android", R.string.mediasize_iso_c4, 9020, 12760);
+        /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */
+        public static final MediaSize ISO_C5 =
+                new MediaSize("ISO_C5", "android", R.string.mediasize_iso_c5, 6380, 9020);
+        /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */
+        public static final MediaSize ISO_C6 =
+                new MediaSize("ISO_C6", "android", R.string.mediasize_iso_c6, 4490, 6380);
+        /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */
+        public static final MediaSize ISO_C7 =
+                new MediaSize("ISO_C7", "android", R.string.mediasize_iso_c7, 3190, 4490);
+        /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */
+        public static final MediaSize ISO_C8 =
+                new MediaSize("ISO_C8", "android", R.string.mediasize_iso_c8, 2240, 3190);
+        /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */
+        public static final MediaSize ISO_C9 =
+                new MediaSize("ISO_C9", "android", R.string.mediasize_iso_c9, 1570, 2240);
+        /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */
+        public static final MediaSize ISO_C10 =
+                new MediaSize("ISO_C10", "android", R.string.mediasize_iso_c10, 1100, 1570);
+
+        // North America
+
+        /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
+        public static final MediaSize NA_LETTER =
+                new MediaSize("NA_LETTER", "android", R.string.mediasize_na_letter, 8500, 11000);
+        /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
+        public static final MediaSize NA_GOVT_LETTER =
+                new MediaSize("NA_GOVT_LETTER", "android",
+                        R.string.mediasize_na_gvrnmt_letter, 8000, 10500);
+        /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
+        public static final MediaSize NA_LEGAL =
+                new MediaSize("NA_LEGAL", "android", R.string.mediasize_na_legal, 8500, 14000);
+        /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
+        public static final MediaSize NA_JUNIOR_LEGAL =
+                new MediaSize("NA_JUNIOR_LEGAL", "android",
+                        R.string.mediasize_na_junior_legal, 8000, 5000);
+        /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
+        public static final MediaSize NA_LEDGER =
+                new MediaSize("NA_LEDGER", "android", R.string.mediasize_na_ledger, 17000, 11000);
+        /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
+        public static final MediaSize NA_TABLOID =
+                new MediaSize("NA_TABLOID", "android",
+                        R.string.mediasize_na_tabloid, 11000, 17000);
+        /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
+        public static final MediaSize NA_INDEX_3X5 =
+                new MediaSize("NA_INDEX_3X5", "android",
+                        R.string.mediasize_na_index_3x5, 3000, 5000);
+        /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
+        public static final MediaSize NA_INDEX_4X6 =
+                new MediaSize("NA_INDEX_4X6", "android",
+                        R.string.mediasize_na_index_4x6, 4000, 6000);
+        /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
+        public static final MediaSize NA_INDEX_5X8 =
+                new MediaSize("NA_INDEX_5X8", "android",
+                        R.string.mediasize_na_index_5x8, 5000, 8000);
+        /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
+        public static final MediaSize NA_MONARCH =
+                new MediaSize("NA_MONARCH", "android",
+                        R.string.mediasize_na_monarch, 7250, 10500);
+        /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
+        public static final MediaSize NA_QUARTO =
+                new MediaSize("NA_QUARTO", "android",
+                        R.string.mediasize_na_quarto, 8000, 10000);
+        /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
+        public static final MediaSize NA_FOOLSCAP =
+                new MediaSize("NA_FOOLSCAP", "android",
+                        R.string.mediasize_na_foolscap, 8000, 13000);
+
+        // Chinese
+
+        /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
+        public static final MediaSize ROC_8K =
+                new MediaSize("ROC_8K", "android",
+                        R.string.mediasize_chinese_roc_8k, 10629, 15354);
+        /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
+        public static final MediaSize ROC_16K =
+                new MediaSize("ROC_16K", "android",
+                        R.string.mediasize_chinese_roc_16k, 7677, 10629);
+
+        /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
+        public static final MediaSize PRC_1 =
+                new MediaSize("PRC_1", "android",
+                        R.string.mediasize_chinese_prc_1, 4015, 6496);
+        /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
+        public static final MediaSize PRC_2 =
+                new MediaSize("PRC_2", "android",
+                        R.string.mediasize_chinese_prc_2, 4015, 6929);
+        /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
+        public static final MediaSize PRC_3 =
+                new MediaSize("PRC_3", "android",
+                        R.string.mediasize_chinese_prc_3, 4921, 6929);
+        /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
+        public static final MediaSize PRC_4 =
+                new MediaSize("PRC_4", "android",
+                        R.string.mediasize_chinese_prc_4, 4330, 8189);
+        /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
+        public static final MediaSize PRC_5 =
+                new MediaSize("PRC_5", "android",
+                        R.string.mediasize_chinese_prc_5, 4330, 8661);
+        /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
+        public static final MediaSize PRC_6 =
+                new MediaSize("PRC_6", "android",
+                        R.string.mediasize_chinese_prc_6, 4724, 12599);
+        /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
+        public static final MediaSize PRC_7 =
+                new MediaSize("PRC_7", "android",
+                        R.string.mediasize_chinese_prc_7, 6299, 9055);
+        /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
+        public static final MediaSize PRC_8 =
+                new MediaSize("PRC_8", "android",
+                        R.string.mediasize_chinese_prc_8, 4724, 12165);
+        /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
+        public static final MediaSize PRC_9 =
+                new MediaSize("PRC_9", "android",
+                        R.string.mediasize_chinese_prc_9, 9016, 12756);
+        /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
+        public static final MediaSize PRC_10 =
+                new MediaSize("PRC_10", "android",
+                        R.string.mediasize_chinese_prc_10, 12756, 18032);
+
+        /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
+        public static final MediaSize PRC_16k =
+                new MediaSize("PRC_16k", "android",
+                        R.string.mediasize_chinese_prc_16k, 5749, 8465);
+        /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
+        public static final MediaSize OM_PA_KAI =
+                new MediaSize("OM_PA_KAI", "android",
+                        R.string.mediasize_chinese_om_pa_kai, 10512, 15315);
+        /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
+        public static final MediaSize OM_DAI_PA_KAI =
+                new MediaSize("OM_DAI_PA_KAI", "android",
+                        R.string.mediasize_chinese_om_dai_pa_kai, 10827, 15551);
+        /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
+        public static final MediaSize OM_JUURO_KU_KAI =
+                new MediaSize("OM_JUURO_KU_KAI", "android",
+                        R.string.mediasize_chinese_om_jurro_ku_kai, 7796, 10827);
+
+        // Japanese
+
+        /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
+        public static final MediaSize JIS_B10 =
+                new MediaSize("JIS_B10", "android",
+                        R.string.mediasize_japanese_jis_b10, 1259, 1772);
+        /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
+        public static final MediaSize JIS_B9 =
+                new MediaSize("JIS_B9", "android",
+                        R.string.mediasize_japanese_jis_b9, 1772, 2520);
+        /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
+        public static final MediaSize JIS_B8 =
+                new MediaSize("JIS_B8", "android",
+                        R.string.mediasize_japanese_jis_b8, 2520, 3583);
+        /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
+        public static final MediaSize JIS_B7 =
+                new MediaSize("JIS_B7", "android",
+                        R.string.mediasize_japanese_jis_b7, 3583, 5049);
+        /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
+        public static final MediaSize JIS_B6 =
+                new MediaSize("JIS_B6", "android",
+                        R.string.mediasize_japanese_jis_b6, 5049, 7165);
+        /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
+        public static final MediaSize JIS_B5 =
+                new MediaSize("JIS_B5", "android",
+                        R.string.mediasize_japanese_jis_b5, 7165, 10118);
+        /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
+        public static final MediaSize JIS_B4 =
+                new MediaSize("JIS_B4", "android",
+                        R.string.mediasize_japanese_jis_b4, 10118, 14331);
+        /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
+        public static final MediaSize JIS_B3 =
+                new MediaSize("JIS_B3", "android",
+                        R.string.mediasize_japanese_jis_b3, 14331, 20276);
+        /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
+        public static final MediaSize JIS_B2 =
+                new MediaSize("JIS_B2", "android",
+                        R.string.mediasize_japanese_jis_b2, 20276, 28661);
+        /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
+        public static final MediaSize JIS_B1 =
+                new MediaSize("JIS_B1", "android",
+                        R.string.mediasize_japanese_jis_b1, 28661, 40551);
+        /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
+        public static final MediaSize JIS_B0 =
+                new MediaSize("JIS_B0", "android",
+                        R.string.mediasize_japanese_jis_b0, 40551, 57323);
+
+        /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
+        public static final MediaSize JIS_EXEC =
+                new MediaSize("JIS_EXEC", "android",
+                        R.string.mediasize_japanese_jis_exec, 8504, 12992);
+
+        /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
+        public static final MediaSize JPN_CHOU4 =
+                new MediaSize("JPN_CHOU4", "android",
+                        R.string.mediasize_japanese_chou4, 3543, 8071);
+        /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
+        public static final MediaSize JPN_CHOU3 =
+                new MediaSize("JPN_CHOU3", "android",
+                        R.string.mediasize_japanese_chou3, 4724, 9252);
+        /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
+        public static final MediaSize JPN_CHOU2 =
+                new MediaSize("JPN_CHOU2", "android",
+                        R.string.mediasize_japanese_chou2, 4374, 5748);
+
+        /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
+        public static final MediaSize JPN_HAGAKI =
+                new MediaSize("JPN_HAGAKI", "android",
+                        R.string.mediasize_japanese_hagaki, 3937, 5827);
+        /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
+        public static final MediaSize JPN_OUFUKU =
+                new MediaSize("JPN_OUFUKU", "android",
+                        R.string.mediasize_japanese_oufuku, 5827, 7874);
+
+        /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
+        public static final MediaSize JPN_KAHU =
+                new MediaSize("JPN_KAHU", "android",
+                        R.string.mediasize_japanese_kahu, 9449, 12681);
+        /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
+        public static final MediaSize JPN_KAKU2 =
+                new MediaSize("JPN_KAKU2", "android",
+                        R.string.mediasize_japanese_kaku2, 9449, 13071);
+
+        /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
+        public static final MediaSize JPN_YOU4 =
+                new MediaSize("JPN_YOU4", "android",
+                        R.string.mediasize_japanese_you4, 4134, 9252);
+
+        private final String mId;
+        /**@hide */
+        public final String mLabel;
+        /**@hide */
+        public final String mPackageName;
+        /**@hide */
+        public final int mLabelResId;
+        private final int mWidthMils;
+        private final int mHeightMils;
+
+        /**
+         * Creates a new instance. This is the preferred constructor since
+         * it enables the media size label to be shown in a localized fashion
+         * on a locale change.
+         *
+         * @param id The unique media size id.
+         * @param packageName The name of the creating package.
+         * @param labelResId The resource if of a human readable label.
+         * @param widthMils The width in mils (thousands of an inch).
+         * @param heightMils The height in mils (thousands of an inch).
+         *
+         * @throws IllegalArgumentException If the id is empty.
+         * @throws IllegalArgumentException If the label is empty.
+         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
+         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+         *
+         * @hide
+         */
+        public MediaSize(String id, String packageName, int labelResId,
+                int widthMils, int heightMils) {
+            if (TextUtils.isEmpty(id)) {
+                throw new IllegalArgumentException("id cannot be empty.");
+            }
+            if (TextUtils.isEmpty(packageName)) {
+                throw new IllegalArgumentException("packageName cannot be empty.");
+            }
+            if (labelResId <= 0) {
+                throw new IllegalArgumentException("labelResId must be greater than zero.");
+            }
+            if (widthMils <= 0) {
+                throw new IllegalArgumentException("widthMils "
+                        + "cannot be less than or equal to zero.");
+            }
+            if (heightMils <= 0) {
+                throw new IllegalArgumentException("heightMils "
+                       + "cannot be less than or euqual to zero.");
+            }
+            mPackageName = packageName;
+            mId = id;
+            mLabelResId = labelResId;
+            mWidthMils = widthMils;
+            mHeightMils = heightMils;
+            mLabel = null;
+        }
+
+        /**
+         * Creates a new instance.
+         *
+         * @param id The unique media size id. It is unique amongst other media sizes
+         *        supported by the printer.
+         * @param label The <strong>internationalized</strong> human readable label.
+         * @param widthMils The width in mils (thousands of an inch).
+         * @param heightMils The height in mils (thousands of an inch).
+         *
+         * @throws IllegalArgumentException If the id is empty.
+         * @throws IllegalArgumentException If the label is empty.
+         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
+         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+         */
+        public MediaSize(String id, String label, int widthMils, int heightMils) {
+            if (TextUtils.isEmpty(id)) {
+                throw new IllegalArgumentException("id cannot be empty.");
+            }
+            if (TextUtils.isEmpty(label)) {
+                throw new IllegalArgumentException("label cannot be empty.");
+            }
+            if (widthMils <= 0) {
+                throw new IllegalArgumentException("widthMils "
+                        + "cannot be less than or equal to zero.");
+            }
+            if (heightMils <= 0) {
+                throw new IllegalArgumentException("heightMils "
+                       + "cannot be less than or euqual to zero.");
+            }
+            mId = id;
+            mLabel = label;
+            mWidthMils = widthMils;
+            mHeightMils = heightMils;
+            mLabelResId = 0;
+            mPackageName = null;
+        }
+
+        /** @hide */
+        public MediaSize(String id, String label, String packageName,
+                int widthMils, int heightMils, int labelResId) {
+            mPackageName = packageName;
+            mId = id;
+            mLabelResId = labelResId;
+            mWidthMils = widthMils;
+            mHeightMils = heightMils;
+            mLabel = label;
+        }
+
+        /**
+         * Gets the unique media size id. It is unique amongst other media sizes
+         * supported by the printer.
+         * <p>
+         * This id is defined by the client that generated the media size
+         * instance and should not be interpreted by other parties.
+         * </p>
+         *
+         * @return The unique media size id.
+         */
+        public String getId() {
+            return mId;
+        }
+
+        /**
+         * Gets the human readable media size label.
+         *
+         * @param packageManager The package manager for loading the label.
+         * @return The human readable label.
+         */
+        public String getLabel(PackageManager packageManager) {
+            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
+                try {
+                    return packageManager.getResourcesForApplication(
+                            mPackageName).getString(mLabelResId);
+                } catch (NotFoundException nfe) {
+                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+                            + " from package " + mPackageName);
+                } catch (NameNotFoundException nnfee) {
+                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+                            + " from package " + mPackageName);
+                }
+            }
+            return mLabel;
+        }
+
+        /**
+         * Gets the media width in mils (thousands of an inch).
+         *
+         * @return The media width.
+         */
+        public int getWidthMils() {
+            return mWidthMils;
+        }
+
+        /**
+         * Gets the media height in mils (thousands of an inch).
+         *
+         * @return The media height.
+         */
+        public int getHeightMils() {
+            return mHeightMils;
+        }
+
+        /**
+         * Gets whether this media size is in portrait which is the
+         * height is greater or equal to the width.
+         *
+         * @return True if the media size is in portrait, false if
+         * it is in landscape.
+         */
+        public boolean isPortrait() {
+            return mHeightMils >= mWidthMils;
+        }
+
+        /**
+         * Returns a new media size in a portrait orientation
+         * which is the height is the greater dimension.
+         *
+         * @return New instance in landscape orientation.
+         */
+        public MediaSize asPortrait() {
+            return new MediaSize(mId, mLabel, mPackageName,
+                    Math.min(mWidthMils, mHeightMils),
+                    Math.max(mWidthMils, mHeightMils),
+                    mLabelResId);
+        }
+
+        /**
+         * Returns a new media size in a landscape orientation
+         * which is the height is the lesser dimension.
+         *
+         * @return New instance in landscape orientation.
+         */
+        public MediaSize asLandscape() {
+            return new MediaSize(mId, mLabel, mPackageName,
+                    Math.max(mWidthMils, mHeightMils),
+                    Math.min(mWidthMils, mHeightMils),
+                    mLabelResId);
+        }
+
+        void writeToParcel(Parcel parcel) {
+            parcel.writeString(mId);
+            parcel.writeString(mLabel);
+            parcel.writeString(mPackageName);
+            parcel.writeInt(mWidthMils);
+            parcel.writeInt(mHeightMils);
+            parcel.writeInt(mLabelResId);
+        }
+
+        static MediaSize createFromParcel(Parcel parcel) {
+            return new MediaSize(
+                    parcel.readString(),
+                    parcel.readString(),
+                    parcel.readString(),
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt());
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + mWidthMils;
+            result = prime * result + mHeightMils;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            MediaSize other = (MediaSize) obj;
+            if (mWidthMils != other.mWidthMils) {
+                return false;
+            }
+            if (mHeightMils != other.mHeightMils) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("MediaSize{");
+            builder.append("id: ").append(mId);
+            builder.append(", label: ").append(mLabel);
+            builder.append(", packageName: ").append(mPackageName);
+            builder.append(", heightMils: ").append(mHeightMils);
+            builder.append(", widthMils: ").append(mWidthMils);
+            builder.append(", labelResId: ").append(mLabelResId);
+            builder.append("}");
+            return builder.toString();
+        }
+    }
+
+    /**
+     * This class specifies a supported resolution in DPI (dots per inch).
+     * Resolution defines how many points with different color can be placed
+     * on one inch in horizontal or vertical direction of the target media.
+     * For example, a printer with 600DIP can produce higher quality images
+     * the one with 300DPI resolution.
+     */
+    public static final class Resolution {
+        private final String mId;
+        private final String mLabel;
+        private final int mHorizontalDpi;
+        private final int mVerticalDpi;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param id The unique resolution id. It is unique amongst other resolutions
+         *        supported by the printer.
+         * @param label The <strong>internationalized</strong> human readable label.
+         * @param horizontalDpi The horizontal resolution in DPI (dots per inch).
+         * @param verticalDpi The vertical resolution in DPI (dots per inch).
+         *
+         * @throws IllegalArgumentException If the id is empty.
+         * @throws IllegalArgumentException If the label is empty.
+         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
+         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
+         */
+        public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
+            if (TextUtils.isEmpty(id)) {
+                throw new IllegalArgumentException("id cannot be empty.");
+            }
+            if (TextUtils.isEmpty(label)) {
+                throw new IllegalArgumentException("label cannot be empty.");
+            }
+            if (horizontalDpi <= 0) {
+                throw new IllegalArgumentException("horizontalDpi "
+                        + "cannot be less than or equal to zero.");
+            }
+            if (verticalDpi <= 0) {
+                throw new IllegalArgumentException("verticalDpi"
+                       + " cannot be less than or equal to zero.");
+            }
+            mId = id;
+            mLabel = label;
+            mHorizontalDpi = horizontalDpi;
+            mVerticalDpi = verticalDpi;
+        }
+
+        /**
+         * Gets the unique resolution id. It is unique amongst other resolutions
+         * supported by the printer.
+         * <p>
+         * This id is defined by the client that generated the resolution
+         * instance and should not be interpreted by other parties.
+         * </p>
+         *
+         * @return The unique resolution id.
+         */
+        public String getId() {
+            return mId;
+        }
+
+        /**
+         * Gets the resolution human readable label.
+         *
+         * @return The human readable label.
+         */
+        public String getLabel() {
+            return mLabel;
+        }
+
+        /**
+         * Gets the horizontal resolution in DPI (dots per inch).
+         *
+         * @return The horizontal resolution.
+         */
+        public int getHorizontalDpi() {
+            return mHorizontalDpi;
+        }
+
+        /**
+         * Gets the vertical resolution in DPI (dots per inch).
+         *
+         * @return The vertical resolution.
+         */
+        public int getVerticalDpi() {
+            return mVerticalDpi;
+        }
+
+        void writeToParcel(Parcel parcel) {
+            parcel.writeString(mId);
+            parcel.writeString(mLabel);
+            parcel.writeInt(mHorizontalDpi);
+            parcel.writeInt(mVerticalDpi);
+        }
+
+        static Resolution createFromParcel(Parcel parcel) {
+            return new Resolution(
+                    parcel.readString(),
+                    parcel.readString(),
+                    parcel.readInt(),
+                    parcel.readInt());
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + mHorizontalDpi;
+            result = prime * result + mVerticalDpi;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            Resolution other = (Resolution) obj;
+            if (mHorizontalDpi != other.mHorizontalDpi) {
+                return false;
+            }
+            if (mVerticalDpi != other.mVerticalDpi) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("Resolution{");
+            builder.append("id: ").append(mId);
+            builder.append(", label: ").append(mLabel);
+            builder.append(", horizontalDpi: ").append(mHorizontalDpi);
+            builder.append(", verticalDpi: ").append(mVerticalDpi);
+            builder.append("}");
+            return builder.toString();
+        }
+    }
+
+    /**
+     * This class specifies content margins. Margins define the white space
+     * around the content where the left margin defines the amount of white
+     * space on the left of the content and so on.
+     */
+    public static final class Margins {
+        public static final Margins NO_MARGINS = new Margins(0,  0,  0,  0);
+
+        private final int mLeftMils;
+        private final int mTopMils;
+        private final int mRightMils;
+        private final int mBottomMils;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param leftMils The left margin in mils (thousands of an inch).
+         * @param topMils The top margin in mils (thousands of an inch).
+         * @param rightMils The right margin in mils (thousands of an inch).
+         * @param bottomMils The bottom margin in mils (thousands of an inch).
+         */
+        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
+            mTopMils = topMils;
+            mLeftMils = leftMils;
+            mRightMils = rightMils;
+            mBottomMils = bottomMils;
+        }
+
+        /**
+         * Gets the left margin in mils (thousands of an inch).
+         *
+         * @return The left margin.
+         */
+        public int getLeftMils() {
+            return mLeftMils;
+        }
+
+        /**
+         * Gets the top margin in mils (thousands of an inch).
+         *
+         * @return The top margin.
+         */
+        public int getTopMils() {
+            return mTopMils;
+        }
+
+        /**
+         * Gets the right margin in mils (thousands of an inch).
+         *
+         * @return The right margin.
+         */
+        public int getRightMils() {
+            return mRightMils;
+        }
+
+        /**
+         * Gets the bottom margin in mils (thousands of an inch).
+         *
+         * @return The bottom margin.
+         */
+        public int getBottomMils() {
+            return mBottomMils;
+        }
+
+        void writeToParcel(Parcel parcel) {
+            parcel.writeInt(mLeftMils);
+            parcel.writeInt(mTopMils);
+            parcel.writeInt(mRightMils);
+            parcel.writeInt(mBottomMils);
+        }
+
+        static Margins createFromParcel(Parcel parcel) {
+            return new Margins(
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt());
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + mBottomMils;
+            result = prime * result + mLeftMils;
+            result = prime * result + mRightMils;
+            result = prime * result + mTopMils;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            Margins other = (Margins) obj;
+            if (mBottomMils != other.mBottomMils) {
+                return false;
+            }
+            if (mLeftMils != other.mLeftMils) {
+                return false;
+            }
+            if (mRightMils != other.mRightMils) {
+                return false;
+            }
+            if (mTopMils != other.mTopMils) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("Margins{");
+            builder.append("leftMils: ").append(mLeftMils);
+            builder.append(", topMils: ").append(mTopMils);
+            builder.append(", rightMils: ").append(mRightMils);
+            builder.append(", bottomMils: ").append(mBottomMils);
+            builder.append("}");
+            return builder.toString();
+        }
+    }
+
+    static String colorModeToString(int colorMode) {
+        switch (colorMode) {
+            case COLOR_MODE_MONOCHROME: {
+                return "COLOR_MODE_MONOCHROME";
+            }
+            case COLOR_MODE_COLOR: {
+                return "COLOR_MODE_COLOR";
+            }
+            default:
+                return "COLOR_MODE_UNKNOWN";
+        }
+    }
+
+    static void enforceValidColorMode(int colorMode) {
+        if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
+            throw new IllegalArgumentException("invalid color mode: " + colorMode);
+        }
+    }
+
+    /**
+     * Builder for creating {@link PrintAttributes}.
+     */
+    public static final class Builder {
+        private final PrintAttributes mAttributes = new PrintAttributes();
+
+        /**
+         * Sets the media size.
+         *
+         * @param mediaSize The media size.
+         * @return This builder.
+         */
+        public Builder setMediaSize(MediaSize mediaSize) {
+            mAttributes.setMediaSize(mediaSize);
+            return this;
+        }
+
+        /**
+         * Sets the resolution.
+         *
+         * @param resolution The resolution.
+         * @return This builder.
+         */
+        public Builder setResolution(Resolution resolution) {
+            mAttributes.setResolution(resolution);
+            return this;
+        }
+
+        /**
+         * Sets the minimal margins. If the content does not fit
+         * these margins it will be clipped.
+         *
+         * @param margins The margins.
+         * @return This builder.
+         */
+        public Builder setMinMargins(Margins margins) {
+            mAttributes.setMinMargins(margins);
+            return this;
+        }
+
+        /**
+         * Sets the color mode.
+         *
+         * @param colorMode A valid color mode or zero.
+         * @return This builder.
+         *
+         * @see PrintAttributes#COLOR_MODE_MONOCHROME
+         * @see PrintAttributes#COLOR_MODE_COLOR
+         */
+        public Builder setColorMode(int colorMode) {
+            if (Integer.bitCount(colorMode) > 1) {
+                throw new IllegalArgumentException("can specify at most one colorMode bit.");
+            }
+            mAttributes.setColorMode(colorMode);
+            return this;
+        }
+
+        /**
+         * Creates a new {@link PrintAttributes} instance.
+         *
+         * @return The new instance.
+         */
+        public PrintAttributes build() {
+            return mAttributes;
+        }
+    }
+
+    public static final Parcelable.Creator<PrintAttributes> CREATOR =
+            new Creator<PrintAttributes>() {
+        @Override
+        public PrintAttributes createFromParcel(Parcel parcel) {
+            return new PrintAttributes(parcel);
+        }
+
+        @Override
+        public PrintAttributes[] newArray(int size) {
+            return new PrintAttributes[size];
+        }
+    };
+}
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
new file mode 100644
index 0000000..4113ac7
--- /dev/null
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -0,0 +1,246 @@
+/*
+ * 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 android.print;
+
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Base class that provides the content of a document to be printed.
+ *
+ * <h3>Lifecycle</h3>
+ * <p>
+ * <ul>
+ * <li>
+ * Initially, you will receive a call to {@link #onStart()}. This callback
+ * can be used to allocate resources.
+ * </li>
+ * <li>
+ * Next, you will get one or more calls to {@link #onLayout(PrintAttributes,
+ * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} to
+ * inform you that the print attributes (page size, density, etc) changed
+ * giving you an opportunity to layout the content to match the new constraints.
+ * </li>
+ * <li>
+ * After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
+ * CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
+ * {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal, WriteResultCallback)}
+ * asking you to write a PDF file with the content for specific pages.
+ * </li>
+ * <li>
+ * Finally, you will receive a call to {@link #onFinish()}. You can use this
+ * callback to release resources allocated in {@link #onStart()}.
+ * </li>
+ * </ul>
+ * </p>
+ * <h3>Implementation</h3>
+ * <p>
+ * The APIs defined in this class are designed to enable doing part or all
+ * of the work on an arbitrary thread. For example, if the printed content
+ * does not depend on the UI state, i.e. on what is shown on the screen, then
+ * you can offload the entire work on a dedicated thread, thus making your
+ * application interactive while the print work is being performed.
+ * </p>
+ * <p>
+ * You can also do work on different threads, for example if you print UI
+ * content, you can handle {@link #onStart()} and {@link #onLayout(PrintAttributes,
+ * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on
+ * the UI thread (assuming onStart initializes resources needed for layout).
+ * This will ensure that the UI does not change while you are laying out the
+ * printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
+ * CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
+ * thread. This will ensure that the UI is frozen for the minimal amount of
+ * time. Also this assumes that you will generate the printed content in
+ * {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)} which is not mandatory. If you use multiple
+ * threads, you are responsible for proper synchronization.
+ * </p>
+ */
+public abstract class PrintDocumentAdapter {
+
+    /**
+     * Extra: mapped to a boolean value that is <code>true</code> if
+     * the current layout is for a print preview, <code>false</code> otherwise.
+     */
+    public static final String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
+
+    /**
+     * Called when printing starts. You can use this callback to allocate
+     * resources. This method is invoked on the main thread.
+     */
+    public void onStart() {
+        /* do nothing - stub */
+    }
+
+    /**
+     * Called when the print attributes (page size, density, etc) changed
+     * giving you a chance to layout the content such that it matches the
+     * new constraints. This method is invoked on the main thread.
+     * <p>
+     * After you are done laying out, you <strong>must</strong> invoke: {@link
+     * LayoutResultCallback#onLayoutFinished(PrintDocumentInfo, boolean)} with
+     * the last argument <code>true</code> or <code>false</code> depending on
+     * whether the layout changed the content or not, respectively; and {@link
+     * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred.
+     * Note that you must call one of the methods of the given callback.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> If the content is large and a layout will be
+     * performed, it is a good practice to schedule the work on a dedicated
+     * thread and register an observer in the provided {@link
+     * CancellationSignal} upon invocation of which you should stop the
+     * layout. The cancellation callback will not be made on the main
+     * thread.
+     * </p>
+     *
+     * @param oldAttributes The old print attributes.
+     * @param newAttributes The new print attributes.
+     * @param cancellationSignal Signal for observing cancel layout requests.
+     * @param callback Callback to inform the system for the layout result.
+     * @param extras Additional information about how to layout the content.
+     *
+     * @see LayoutResultCallback
+     * @see CancellationSignal
+     * @see #EXTRA_PRINT_PREVIEW
+     */
+    public abstract void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+            CancellationSignal cancellationSignal, LayoutResultCallback callback,
+            Bundle extras);
+
+    /**
+     * Called when specific pages of the content should be written in the
+     * form of a PDF file to the given file descriptor. This method is invoked
+     * on the main thread.
+     *<p>
+     * After you are done writing, you should close the file descriptor and
+     * invoke {@link WriteResultCallback #onWriteFinished(PageRange[]), if writing
+     * completed successfully; or {@link WriteResultCallback#onWriteFailed(
+     * CharSequence)}, if an error occurred. Note that you must call one of
+     * the methods of the given callback.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> If the printed content is large, it is a good
+     * practice to schedule writing it on a dedicated thread and register an
+     * observer in the provided {@link CancellationSignal} upon invocation of
+     * which you should stop writing. The cancellation callback will not be
+     * made on the main thread.
+     * </p>
+     *
+     * @param pages The pages whose content to print - non-overlapping in ascending order.
+     * @param destination The destination file descriptor to which to write.
+     * @param cancellationSignal Signal for observing cancel writing requests.
+     * @param callback Callback to inform the system for the write result.
+     *
+     * @see WriteResultCallback
+     * @see CancellationSignal
+     */
+    public abstract void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+            CancellationSignal cancellationSignal, WriteResultCallback callback);
+
+    /**
+     * Called when printing finishes. You can use this callback to release
+     * resources acquired in {@link #onStart()}. This method is invoked on
+     * the main thread.
+     */
+    public void onFinish() {
+        /* do nothing - stub */
+    }
+
+    /**
+     * Base class for implementing a callback for the result of {@link
+     * PrintDocumentAdapter#onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
+     * WriteResultCallback)}.
+     */
+    public static abstract class WriteResultCallback {
+
+        /**
+         * @hide
+         */
+        public WriteResultCallback() {
+            /* do nothing - hide constructor */
+        }
+
+        /**
+         * Notifies that all the data was written.
+         *
+         * @param pages The pages that were written. Cannot be null or empty.
+         */
+        public void onWriteFinished(PageRange[] pages) {
+            /* do nothing - stub */
+        }
+
+        /**
+         * Notifies that an error occurred while writing the data.
+         *
+         * @param error Error message. May be null if error is unknown.
+         */
+        public void onWriteFailed(CharSequence error) {
+            /* do nothing - stub */
+        }
+
+        /**
+         * Notifies that write was cancelled as a result of a cancellation request.
+         */
+        public void onWriteCancelled() {
+            /* do nothing - stub */
+        }
+    }
+
+    /**
+     * Base class for implementing a callback for the result of {@link
+     * PrintDocumentAdapter#onLayout(PrintAttributes, PrintAttributes,
+     * CancellationSignal, LayoutResultCallback, Bundle)}.
+     */
+    public static abstract class LayoutResultCallback {
+
+        /**
+         * @hide
+         */
+        public LayoutResultCallback() {
+            /* do nothing - hide constructor */
+        }
+
+        /**
+         * Notifies that the layout finished and whether the content changed.
+         *
+         * @param info An info object describing the document. Cannot be null.
+         * @param changed Whether the layout changed.
+         *
+         * @see PrintDocumentInfo
+         */
+        public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+            /* do nothing - stub */
+        }
+
+        /**
+         * Notifies that an error occurred while laying out the document.
+         *
+         * @param error Error message. May be null if error is unknown.
+         */
+        public void onLayoutFailed(CharSequence error) {
+            /* do nothing - stub */
+        }
+
+        /**
+         * Notifies that layout was cancelled as a result of a cancellation request.
+         */
+        public void onLayoutCancelled() {
+            /* do nothing - stub */
+        }
+    }
+}
diff --git a/core/java/android/print/PrintDocumentInfo.aidl b/core/java/android/print/PrintDocumentInfo.aidl
new file mode 100644
index 0000000..831dcb7
--- /dev/null
+++ b/core/java/android/print/PrintDocumentInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrintDocumentInfo;
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
new file mode 100644
index 0000000..f094962
--- /dev/null
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -0,0 +1,297 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * This class encapsulates information about a printed document.
+ */
+public final class PrintDocumentInfo implements Parcelable {
+
+    /**
+     * Constant for unknown page count..
+     */
+    public static final int PAGE_COUNT_UNKNOWN = -1;
+
+    /**
+     * Content type: unknown.
+     */
+    public static final int CONTENT_TYPE_UNKNOWN = -1;
+
+    /**
+     * Content type: document.
+     */
+    public static final int CONTENT_TYPE_DOCUMENT = 0;
+
+    /**
+     * Content type: photo.
+     */
+    public static final int CONTENT_TYPE_PHOTO = 1;
+
+    private String mName;
+    private int mPageCount;
+    private int mContentType;
+    private long mDataSize;
+
+    /**
+     * Creates a new instance.
+     */
+    private PrintDocumentInfo() {
+        /* do nothing */
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param Prototype from which to clone.
+     */
+    private PrintDocumentInfo(PrintDocumentInfo prototype) {
+        mName = prototype.mName;
+        mPageCount = prototype.mPageCount;
+        mContentType = prototype.mContentType;
+        mDataSize = prototype.mDataSize;
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param parcel Data from which to initialize.
+     */
+    private PrintDocumentInfo(Parcel parcel) {
+        mName = parcel.readString();
+        mPageCount = parcel.readInt();
+        mContentType = parcel.readInt();
+        mDataSize = parcel.readLong();
+    }
+
+    /**
+     * Gets the document name.
+     *
+     * @return The document name.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Gets the total number of pages.
+     *
+     * @return The number of pages.
+     *
+     * @see #PAGE_COUNT_UNKNOWN
+     */
+    public int getPageCount() {
+        return mPageCount;
+    }
+
+    /**
+     * Gets the content type.
+     *
+     * @return The content type.
+     *
+     * @see #CONTENT_TYPE_UNKNOWN
+     * @see #CONTENT_TYPE_DOCUMENT
+     * @see #CONTENT_TYPE_PHOTO
+     */
+    public int getContentType() {
+        return mContentType;
+    }
+
+    /**
+     * Gets the document data size in bytes.
+     *
+     * @return The data size.
+     */
+    public long getDataSize() {
+        return mDataSize;
+    }
+
+    /**
+     * Sets the document data size in bytes.
+     *
+     * @param dataSize The data size.
+     *
+     * @hide
+     */
+    public void setDataSize(long dataSize) {
+        mDataSize = dataSize;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mName);
+        parcel.writeInt(mPageCount);
+        parcel.writeInt(mContentType);
+        parcel.writeLong(mDataSize);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mName != null) ? mName.hashCode() : 0);
+        result = prime * result + mContentType;
+        result = prime * result + mPageCount;
+        result = prime * result + (int) mDataSize;
+        result = prime * result + (int) mDataSize >> 32;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrintDocumentInfo other = (PrintDocumentInfo) obj;
+        if (!TextUtils.equals(mName, other.mName)) {
+            return false;
+        }
+        if (mContentType != other.mContentType) {
+            return false;
+        }
+        if (mPageCount != other.mPageCount) {
+            return false;
+        }
+        if (mDataSize != other.mDataSize) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrintDocumentInfo{");
+        builder.append("name=").append(mName);
+        builder.append(", pageCount=").append(mPageCount);
+        builder.append(", contentType=").append(contentTyepToString(mContentType));
+        builder.append(", size=").append(mDataSize);
+        builder.append("}");
+        return builder.toString();
+    }
+
+    private String contentTyepToString(int contentType) {
+        switch (contentType) {
+            case CONTENT_TYPE_DOCUMENT: {
+                return "CONTENT_TYPE_DOCUMENT";
+            }
+            case CONTENT_TYPE_PHOTO: {
+                return "CONTENT_TYPE_PHOTO";
+            }
+            default: {
+                return "CONTENT_TYPE_UNKNOWN";
+            }
+        }
+    }
+
+    /**
+     * Builder for creating an {@link PrintDocumentInfo}.
+     */
+    public static final class Builder {
+        private final PrintDocumentInfo mPrototype;
+
+        /**
+         * Constructor.
+         * <p>
+         * The values of the relevant properties are initialized with default
+         * values. Please refer to the documentation of the individual setters
+         * for information about the default values.
+         * </p>
+         *
+         * @param name The document name. Cannot be empty. 
+         */
+        public Builder(String name) {
+            if (TextUtils.isEmpty(name)) {
+                throw new IllegalArgumentException("name cannot be empty");
+            }
+            mPrototype = new PrintDocumentInfo();
+            mPrototype.mName = name;
+        }
+
+        /**
+         * Sets the total number of pages.
+         * <p>
+         * <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
+         * </p>
+         *
+         * @param pageCount The number of pages. Must be greater than
+         * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+         */
+        public Builder setPageCount(int pageCount) {
+            if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
+                throw new IllegalArgumentException("pageCount"
+                        + " must be greater than or euqal to zero or"
+                        + " DocumentInfo#PAGE_COUNT_UNKNOWN");
+            }
+            mPrototype.mPageCount = pageCount;
+            return this;
+        }
+
+        /**
+         * Sets the content type.
+         * <p>
+         * <strong>Default: </strong> {@link #CONTENT_TYPE_UNKNOWN}
+         * </p>
+         *
+         * @param type The content type.
+         *
+         * @see #CONTENT_TYPE_UNKNOWN
+         * @see #CONTENT_TYPE_DOCUMENT
+         * @see #CONTENT_TYPE_PHOTO
+         */
+        public Builder setContentType(int type) {
+            mPrototype.mContentType = type;
+            return this;
+        }
+
+        /**
+         * Creates a new {@link PrintDocumentInfo} instance.
+         *
+         * @return The new instance.
+         */
+        public PrintDocumentInfo build() {
+            return new PrintDocumentInfo(mPrototype);
+        }
+    }
+
+    public static final Parcelable.Creator<PrintDocumentInfo> CREATOR =
+            new Creator<PrintDocumentInfo>() {
+        @Override
+        public PrintDocumentInfo createFromParcel(Parcel parcel) {
+            return new PrintDocumentInfo(parcel);
+        }
+
+        @Override
+        public PrintDocumentInfo[] newArray(int size) {
+            return new PrintDocumentInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
new file mode 100644
index 0000000..c3a23a5
--- /dev/null
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -0,0 +1,153 @@
+/*
+ * 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 android.print;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CancellationSignal.OnCancelListener;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.R;
+
+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;
+
+/**
+ * Adapter for printing PDF files. This class could be useful if you
+ * want to print a file and intercept when the system is ready
+ * spooling the data, so you can delete the file if it is a
+ * temporary one. To achieve this one must override {@link #onFinish()}
+ * and delete the file yourself.
+ */
+public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
+
+    private static final String LOG_TAG = "PrintedFileDocumentAdapter";
+
+    private final Context mContext;
+
+    private final File mFile;
+
+    private final PrintDocumentInfo mDocumentInfo;
+
+    private WriteFileAsyncTask mWriteFileAsyncTask;
+
+    /**
+     * Constructor.
+     *
+     * @param context Context for accessing resources.
+     * @param file The PDF file to print.
+     * @param documentInfo The information about the printed file.
+     */
+    public PrintFileDocumentAdapter(Context context, File file,
+            PrintDocumentInfo documentInfo) {
+        if (file == null) {
+            throw new IllegalArgumentException("File cannot be null!");
+        }
+        if (documentInfo == null) {
+            throw new IllegalArgumentException("documentInfo cannot be null!");
+        }
+        mContext = context;
+        mFile = file;
+        mDocumentInfo = documentInfo;
+    }
+
+    @Override
+    public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+            CancellationSignal cancellationSignal, LayoutResultCallback callback,
+            Bundle metadata) {
+        callback.onLayoutFinished(mDocumentInfo, false);
+    }
+
+    @Override
+    public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+            CancellationSignal cancellationSignal, WriteResultCallback callback) {
+        mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
+        mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
+                (Void[]) null);
+    }
+
+    private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
+
+        private final ParcelFileDescriptor mDestination;
+
+        private final WriteResultCallback mResultCallback;
+
+        private final CancellationSignal mCancellationSignal;
+
+        public WriteFileAsyncTask(ParcelFileDescriptor destination,
+                CancellationSignal cancellationSignal, WriteResultCallback callback) {
+            mDestination = destination;
+            mResultCallback = callback;
+            mCancellationSignal = cancellationSignal;
+            mCancellationSignal.setOnCancelListener(new OnCancelListener() {
+                @Override
+                public void onCancel() {
+                    cancel(true);
+                }
+            });
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            InputStream in = null;
+            OutputStream out = new FileOutputStream(mDestination.getFileDescriptor());
+            final byte[] buffer = new byte[8192];
+            try {
+                in = new FileInputStream(mFile);
+                while (true) {
+                    if (isCancelled()) {
+                        break;
+                    }
+                    final int readByteCount = in.read(buffer);
+                    if (readByteCount < 0) {
+                        break;
+                    }
+                    out.write(buffer, 0, readByteCount);
+                }
+             } catch (IOException ioe) {
+                 Log.e(LOG_TAG, "Error writing data!", ioe);
+                 mResultCallback.onWriteFailed(mContext.getString(
+                         R.string.write_fail_reason_cannot_write));
+             } finally {
+                IoUtils.closeQuietly(in);
+                IoUtils.closeQuietly(out);
+            }
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            mResultCallback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
+        }
+
+        @Override
+        protected void onCancelled(Void result) {
+            mResultCallback.onWriteFailed(mContext.getString(
+                    R.string.write_fail_reason_cancelled));
+        }
+    }
+}
+
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
new file mode 100644
index 0000000..535ae43
--- /dev/null
+++ b/core/java/android/print/PrintJob.java
@@ -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.
+ */
+
+package android.print;
+
+/**
+ * This class represents a print job from the perspective of
+ * an application.
+ */
+public final class PrintJob {
+
+    private final PrintManager mPrintManager;
+
+    private PrintJobInfo mCachedInfo;
+
+    PrintJob(PrintJobInfo info, PrintManager printManager) {
+        mCachedInfo = info;
+        mPrintManager = printManager;
+    }
+
+    /**
+     * Gets the unique print job id.
+     *
+     * @return The id.
+     */
+    public PrintJobId getId() {
+        return mCachedInfo.getId();
+    }
+
+    /**
+     * Gets the {@link PrintJobInfo} that describes this job.
+     * <p>
+     * <strong>Node:</strong>The returned info object is a snapshot of the
+     * current print job state. Every call to this method returns a fresh
+     * info object that reflects the current print job state.
+     * </p>
+     *
+     * @return The print job info.
+     */
+    public PrintJobInfo getInfo() {
+        if (isInImmutableState()) {
+            return mCachedInfo;
+        }
+        PrintJobInfo info = mPrintManager.getPrintJobInfo(mCachedInfo.getId());
+        if (info != null) {
+            mCachedInfo = info;
+        }
+        return mCachedInfo;
+    }
+
+    /**
+     * Cancels this print job. You can request cancellation of a
+     * queued, started, blocked, or failed print job.
+     *
+     * @see #isQueued()
+     * @see #isStarted()
+     * @see #isBlocked()
+     * @see #isFailed()
+     */
+    public void cancel() {
+        final int state = getInfo().getState();
+        if (state == PrintJobInfo.STATE_QUEUED
+                || state == PrintJobInfo.STATE_STARTED
+                || state == PrintJobInfo.STATE_BLOCKED
+                || state == PrintJobInfo.STATE_FAILED) {
+            mPrintManager.cancelPrintJob(mCachedInfo.getId());
+        }
+    }
+
+    /**
+     * Restarts this print job. You can request restart of a failed
+     * print job.
+     *
+     * @see #isFailed()
+     */
+    public void restart() {
+        if (isFailed()) {
+            mPrintManager.restartPrintJob(mCachedInfo.getId());
+        }
+    }
+
+    /**
+     * Gets whether this print job is queued. Such a print job is
+     * ready to be printed. You can request a cancellation via
+     * {@link #cancel()}.
+     *
+     * @return Whether the print job is queued.
+     *
+     * @see #cancel()
+     */
+    public boolean isQueued() {
+        return getInfo().getState() == PrintJobInfo.STATE_QUEUED;
+    }
+
+    /**
+     * Gets whether this print job is started. Such a print job is
+     * being printed. You can request a cancellation via
+     * {@link #cancel()}.
+     *
+     * @return Whether the print job is started.
+     *
+     * @see #cancel()
+     */
+    public boolean isStarted() {
+        return getInfo().getState() == PrintJobInfo.STATE_STARTED;
+    }
+
+    /**
+     * Gets whether this print job is blocked. Such a print job is halted
+     * due to an abnormal condition. You can request a cancellation via
+     * {@link #cancel()}.
+     *
+     * @return Whether the print job is blocked.
+     *
+     * @see #cancel()
+     */
+    public boolean isBlocked() {
+        return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
+    }
+
+    /**
+     * Gets whether this print job is completed. Such a print job
+     * is successfully printed. You can neither cancel nor restart
+     * such a print job.
+     *
+     * @return Whether the print job is completed.
+     */
+    public boolean isCompleted() {
+        return getInfo().getState() == PrintJobInfo.STATE_COMPLETED;
+    }
+
+    /**
+     * Gets whether this print job is failed. Such a print job is
+     * not successfully printed due to an error. You can request
+     * a restart via {@link #restart()}.
+     *
+     * @return Whether the print job is failed.
+     *
+     * @see #restart()
+     */
+    public boolean isFailed() {
+        return getInfo().getState() == PrintJobInfo.STATE_FAILED;
+    }
+
+    /**
+     * Gets whether this print job is cancelled. Such a print job was
+     * cancelled as a result of a user request. This is a final state.
+     * You cannot restart such a print job.
+     *
+     * @return Whether the print job is cancelled.
+     */
+    public boolean isCancelled() {
+        return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
+    }
+
+    private boolean isInImmutableState() {
+        final int state = mCachedInfo.getState();
+        return state == PrintJobInfo.STATE_COMPLETED
+                || state == PrintJobInfo.STATE_CANCELED;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrintJob other = (PrintJob) obj;
+        return mCachedInfo.getId().equals(other.mCachedInfo.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return mCachedInfo.getId().hashCode();
+    }
+}
diff --git a/core/java/android/print/PrintJobId.aidl b/core/java/android/print/PrintJobId.aidl
new file mode 100644
index 0000000..759f25f
--- /dev/null
+++ b/core/java/android/print/PrintJobId.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrintJobId;
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
new file mode 100644
index 0000000..01550e2
--- /dev/null
+++ b/core/java/android/print/PrintJobId.java
@@ -0,0 +1,122 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.UUID;
+
+/**
+ * This class represents the id of a print job.
+ */
+public final class PrintJobId implements Parcelable {
+    private final String mValue;
+
+    /**
+     * Creates a new instance.
+     *
+     * @hide
+     */
+    public PrintJobId() {
+        this(UUID.randomUUID().toString());
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param value The internal value.
+     *
+     * @hide
+     */
+    public PrintJobId(String value) {
+        mValue = value;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrintJobId other = (PrintJobId) obj;
+        if (!TextUtils.equals(mValue, other.mValue)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mValue);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Flattens this id to a string.
+     *
+     * @return The flattened id.
+     *
+     * @hide
+     */
+    public String flattenToString() {
+        return mValue;
+    }
+
+    /**
+     * Unflattens a print job id from a string.
+     *
+     * @string The string.
+     * @return The unflattened id, or null if the string is malformed.
+     *
+     * @hide
+     */
+    public static PrintJobId unflattenFromString(String string) {
+        return new PrintJobId(string);
+    }
+
+    public static final Parcelable.Creator<PrintJobId> CREATOR =
+            new Parcelable.Creator<PrintJobId>() {
+        @Override
+        public PrintJobId createFromParcel(Parcel parcel) {
+            return new PrintJobId(parcel.readString());
+        }
+
+        @Override
+        public PrintJobId[] newArray(int size) {
+            return new PrintJobId[size];
+        }
+    };
+}
diff --git a/core/java/android/print/PrintJobInfo.aidl b/core/java/android/print/PrintJobInfo.aidl
new file mode 100644
index 0000000..fbca99c
--- /dev/null
+++ b/core/java/android/print/PrintJobInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrintJobInfo;
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
new file mode 100644
index 0000000..e5d06a2
--- /dev/null
+++ b/core/java/android/print/PrintJobInfo.java
@@ -0,0 +1,605 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * This class represents the description of a print job.
+ */
+public final class PrintJobInfo implements Parcelable {
+
+    /** Undefined print job id. */
+    public static final int PRINT_JOB_ID_UNDEFINED = -1;
+
+    /**
+     * Constant for matching any print job state.
+     *
+     * @hide
+     */
+    public static final int STATE_ANY = -1;
+
+    /**
+     * Constant for matching any print job state.
+     *
+     * @hide
+     */
+    public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2;
+
+    /**
+     * Constant for matching any active print job state.
+     *
+     * @hide
+     */
+    public static final int STATE_ANY_ACTIVE = -3;
+
+    /**
+     * Print job state: The print job is being created but not yet
+     * ready to be printed.
+     * <p>
+     * Next valid states: {@link #STATE_QUEUED}
+     * </p>
+     */
+    public static final int STATE_CREATED = 1;
+
+    /**
+     * Print job state: The print jobs is created, it is ready
+     * to be printed and should be processed.
+     * <p>
+     * Next valid states: {@link #STATE_STARTED}, {@link #STATE_FAILED},
+     * {@link #STATE_CANCELED}
+     * </p>
+     */
+    public static final int STATE_QUEUED = 2;
+
+    /**
+     * Print job state: The print job is being printed.
+     * <p>
+     * Next valid states: {@link #STATE_COMPLETED}, {@link #STATE_FAILED},
+     * {@link #STATE_CANCELED}, {@link #STATE_BLOCKED}
+     * </p>
+     */
+    public static final int STATE_STARTED = 3;
+
+    /**
+     * Print job state: The print job is blocked.
+     * <p>
+     * Next valid states: {@link #STATE_FAILED}, {@link #STATE_CANCELED},
+     * {@link #STATE_STARTED}
+     * </p>
+     */
+    public static final int STATE_BLOCKED = 4;
+
+    /**
+     * Print job state: The print job was successfully printed.
+     * This is a terminal state.
+     * <p>
+     * Next valid states: None
+     * </p>
+     */
+    public static final int STATE_COMPLETED = 5;
+
+    /**
+     * Print job state: The print job was printing but printing failed.
+     * This is a terminal state.
+     * <p>
+     * Next valid states: None
+     * </p>
+     */
+    public static final int STATE_FAILED = 6;
+
+    /**
+     * Print job state: The print job was canceled.
+     * This is a terminal state.
+     * <p>
+     * Next valid states: None
+     * </p>
+     */
+    public static final int STATE_CANCELED = 7;
+
+    /** The unique print job id. */
+    private PrintJobId mId;
+
+    /** The human readable print job label. */
+    private String mLabel;
+
+    /** The unique id of the printer. */
+    private PrinterId mPrinterId;
+
+    /** The name of the printer - internally used */
+    private String mPrinterName;
+
+    /** The status of the print job. */
+    private int mState;
+
+    /** The id of the app that created the job. */
+    private int mAppId;
+
+    /** The id of the user that created the job. */
+    private int mUserId;
+
+    /** Optional tag assigned by a print service.*/
+    private String mTag;
+
+    /** The wall time when the print job was created. */
+    private long mCreationTime;
+
+    /** How many copies to print. */
+    private int mCopies;
+
+    /** Reason for the print job being in its current state. */
+    private String mStateReason;
+
+    /** The pages to print */
+    private PageRange[] mPageRanges;
+
+    /** The print job attributes size. */
+    private PrintAttributes mAttributes;
+
+    /** Information about the printed document. */
+    private PrintDocumentInfo mDocumentInfo;
+
+    /** @hide*/
+    public PrintJobInfo() {
+        /* do nothing */
+    }
+
+    /** @hide */
+    public PrintJobInfo(PrintJobInfo other) {
+        mId = other.mId;
+        mLabel = other.mLabel;
+        mPrinterId = other.mPrinterId;
+        mPrinterName = other.mPrinterName;
+        mState = other.mState;
+        mAppId = other.mAppId;
+        mUserId = other.mUserId;
+        mTag = other.mTag;
+        mCreationTime = other.mCreationTime;
+        mCopies = other.mCopies;
+        mStateReason = other.mStateReason;
+        mPageRanges = other.mPageRanges;
+        mAttributes = other.mAttributes;
+        mDocumentInfo = other.mDocumentInfo;
+    }
+
+    private PrintJobInfo(Parcel parcel) {
+        mId = parcel.readParcelable(null);
+        mLabel = parcel.readString();
+        mPrinterId = parcel.readParcelable(null);
+        mPrinterName = parcel.readString();
+        mState = parcel.readInt();
+        mAppId = parcel.readInt();
+        mUserId = parcel.readInt();
+        mTag = parcel.readString();
+        mCreationTime = parcel.readLong();
+        mCopies = parcel.readInt();
+        mStateReason = parcel.readString();
+        if (parcel.readInt() == 1) {
+            Parcelable[] parcelables = parcel.readParcelableArray(null);
+            mPageRanges = new PageRange[parcelables.length];
+            for (int i = 0; i < parcelables.length; i++) {
+                mPageRanges[i] = (PageRange) parcelables[i];
+            }
+        }
+        if (parcel.readInt() == 1) {
+            mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel);
+        }
+        if (parcel.readInt() == 1) {
+            mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel);
+        }
+    }
+
+    /**
+     * Gets the unique print job id.
+     *
+     * @return The id.
+     */
+    public PrintJobId getId() {
+        return mId;
+    }
+
+    /**
+     * Sets the unique print job id.
+     *
+     * @param The job id.
+     *
+     * @hide
+     */
+    public void setId(PrintJobId id) {
+        this.mId = id;
+    }
+
+    /**
+     * Gets the human readable job label.
+     *
+     * @return The label.
+     */
+    public String getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Sets the human readable job label.
+     *
+     * @param label The label.
+     *
+     * @hide
+     */
+    public void setLabel(String label) {
+        mLabel = label;
+    }
+
+    /**
+     * Gets the unique target printer id.
+     *
+     * @return The target printer id.
+     */
+    public PrinterId getPrinterId() {
+        return mPrinterId;
+    }
+
+    /**
+     * Sets the unique target pritner id.
+     *
+     * @param printerId The target printer id.
+     *
+     * @hide
+     */
+    public void setPrinterId(PrinterId printerId) {
+        mPrinterId = printerId;
+    }
+
+    /**
+     * Gets the name of the target printer.
+     *
+     * @return The printer name.
+     *
+     * @hide
+     */
+    public String getPrinterName() {
+        return mPrinterName;
+    }
+
+    /**
+     * Sets the name of the target printer.
+     *
+     * @param printerName The printer name.
+     *
+     * @hide
+     */
+    public void setPrinterName(String printerName) {
+        mPrinterName = printerName;
+    }
+
+    /**
+     * Gets the current job state.
+     *
+     * @return The job state.
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Sets the current job state.
+     *
+     * @param state The job state.
+     *
+     * @hide
+     */
+    public void setState(int state) {
+        mState = state;
+    }
+
+    /**
+     * Sets the owning application id.
+     *
+     * @return The owning app id.
+     *
+     * @hide
+     */
+    public int getAppId() {
+        return mAppId;
+    }
+
+    /**
+     * Sets the owning application id.
+     *
+     * @param appId The owning app id.
+     *
+     * @hide
+     */
+    public void setAppId(int appId) {
+        mAppId = appId;
+    }
+
+    /**
+     * Gets the owning user id.
+     *
+     * @return The user id.
+     *
+     * @hide
+     */
+    public int getUserId() {
+        return mUserId;
+    }
+
+    /**
+     * Sets the owning user id.
+     *
+     * @param userId The user id.
+     *
+     * @hide
+     */
+    public void setUserId(int userId) {
+        mUserId = userId;
+    }
+
+    /**
+     * Gets the optional tag assigned by a print service.
+     *
+     * @return The tag.
+     */
+    public String getTag() {
+        return mTag;
+    }
+
+    /**
+     * Sets the optional tag assigned by a print service.
+     *
+     * @param tag The tag.
+     *
+     * @hide
+     */
+    public void setTag(String tag) {
+        mTag = tag;
+    }
+
+    /**
+     * Gets the wall time in millisecond when this print job was created.
+     *
+     * @return The creation time in milliseconds.
+     */
+    public long getCreationTime() {
+        return mCreationTime;
+    }
+
+    /**
+     * Sets the wall time in milliseconds when this print job was created.
+     *
+     * @param creationTime The creation time in milliseconds.
+     *
+     * @hide
+     */
+    public void setCreationTime(long creationTime) {
+        if (creationTime < 0) {
+            throw new IllegalArgumentException("creationTime must be non-negative.");
+        }
+        mCreationTime = creationTime;
+    }
+
+    /**
+     * Gets the number of copies.
+     *
+     * @return The number of copies or zero if not set.
+     */
+    public int getCopies() {
+        return mCopies;
+    }
+
+    /**
+     * Sets the number of copies.
+     *
+     * @param copyCount The number of copies.
+     *
+     * @hide
+     */
+    public void setCopies(int copyCount) {
+        if (copyCount < 1) {
+            throw new IllegalArgumentException("Copies must be more than one.");
+        }
+        mCopies = copyCount;
+    }
+
+    /**
+     * Gets the reason for the print job being in the current state.
+     *
+     * @return The reason, or null if there is no reason or the
+     * reason is unknown.
+     *
+     * @hide
+     */
+    public String getStateReason() {
+        return mStateReason;
+    }
+
+    /**
+     * Sets the reason for the print job being in the current state.
+     *
+     * @param stateReason The reason, or null if there is no reason
+     * or the reason is unknown.
+     *
+     * @hide
+     */
+    public void setStateReason(String stateReason) {
+        mStateReason = stateReason;
+    }
+
+    /**
+     * Gets the included pages.
+     *
+     * @return The included pages or <code>null</code> if not set.
+     */
+    public PageRange[] getPages() {
+        return mPageRanges;
+    }
+
+    /**
+     * Sets the included pages.
+     *
+     * @return The included pages.
+     *
+     * @hide
+     */
+    public void setPages(PageRange[] pageRanges) {
+        mPageRanges = pageRanges;
+    }
+
+    /**
+     * Gets the print job attributes.
+     *
+     * @return The attributes.
+     */
+    public PrintAttributes getAttributes() {
+        return mAttributes;
+    }
+
+    /**
+     * Sets the print job attributes.
+     *
+     * @param attributes The attributes.
+     *
+     * @hide
+     */
+    public void setAttributes(PrintAttributes attributes) {
+        mAttributes = attributes;
+    }
+
+    /**
+     * Gets the info describing the printed document.
+     *
+     * @return The document info.
+     *
+     * @hide
+     */
+    public PrintDocumentInfo getDocumentInfo() {
+        return mDocumentInfo;
+    }
+
+    /**
+     * Sets the info describing the printed document.
+     *
+     * @param info The document info.
+     *
+     * @hide
+     */
+    public void setDocumentInfo(PrintDocumentInfo info) {
+        mDocumentInfo = info;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mId, flags);
+        parcel.writeString(mLabel);
+        parcel.writeParcelable(mPrinterId, flags);
+        parcel.writeString(mPrinterName);
+        parcel.writeInt(mState);
+        parcel.writeInt(mAppId);
+        parcel.writeInt(mUserId);
+        parcel.writeString(mTag);
+        parcel.writeLong(mCreationTime);
+        parcel.writeInt(mCopies);
+        parcel.writeString(mStateReason);
+        if (mPageRanges != null) {
+            parcel.writeInt(1);
+            parcel.writeParcelableArray(mPageRanges, flags);
+        } else {
+            parcel.writeInt(0);
+        }
+        if (mAttributes != null) {
+            parcel.writeInt(1);
+            mAttributes.writeToParcel(parcel, flags);
+        } else {
+            parcel.writeInt(0);
+        }
+        if (mDocumentInfo != null) {
+            parcel.writeInt(1);
+            mDocumentInfo.writeToParcel(parcel, flags);
+        } else {
+            parcel.writeInt(0);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrintJobInfo{");
+        builder.append("label: ").append(mLabel);
+        builder.append(", id: ").append(mId);
+        builder.append(", status: ").append(stateToString(mState));
+        builder.append(", printer: " + mPrinterId);
+        builder.append(", tag: ").append(mTag);
+        builder.append(", creationTime: " + mCreationTime);
+        builder.append(", copies: ").append(mCopies);
+        builder.append(", attributes: " + (mAttributes != null
+                ? mAttributes.toString() : null));
+        builder.append(", documentInfo: " + (mDocumentInfo != null
+                ? mDocumentInfo.toString() : null));
+        builder.append(", pages: " + (mPageRanges != null
+                ? Arrays.toString(mPageRanges) : null));
+        builder.append("}");
+        return builder.toString();
+    }
+
+    /** @hide */
+    public static String stateToString(int state) {
+        switch (state) {
+            case STATE_CREATED: {
+                return "STATE_CREATED";
+            }
+            case STATE_QUEUED: {
+                return "STATE_QUEUED";
+            }
+            case STATE_STARTED: {
+                return "STATE_STARTED";
+            }
+            case STATE_FAILED: {
+                return "STATE_FAILED";
+            }
+            case STATE_COMPLETED: {
+                return "STATE_COMPLETED";
+            }
+            case STATE_CANCELED: {
+                return "STATE_CANCELED";
+            }
+            default: {
+                return "STATE_UNKNOWN";
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<PrintJobInfo> CREATOR =
+            new Creator<PrintJobInfo>() {
+        @Override
+        public PrintJobInfo createFromParcel(Parcel parcel) {
+            return new PrintJobInfo(parcel);
+        }
+
+        @Override
+        public PrintJobInfo[] newArray(int size) {
+            return new PrintJobInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
new file mode 100644
index 0000000..0859fdd
--- /dev/null
+++ b/core/java/android/print/PrintManager.java
@@ -0,0 +1,621 @@
+/*
+ * 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 android.print;
+
+import android.content.Context;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.printservice.PrintServiceInfo;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.os.SomeArgs;
+
+import libcore.io.IoUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * System level service for accessing the printing capabilities of the platform.
+ * <p>
+ * To obtain a handle to the print manager do the following:
+ * </p>
+ * <pre>
+ * PrintManager printManager =
+ *         (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
+ * </pre>
+ */
+public final class PrintManager {
+
+    private static final String LOG_TAG = "PrintManager";
+
+    /** @hide */
+    public static final int APP_ID_ANY = -2;
+
+    private final Context mContext;
+
+    private final IPrintManager mService;
+
+    private final int mUserId;
+
+    private final int mAppId;
+
+    private final PrintClient mPrintClient;
+
+    private final Handler mHandler;
+
+    private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper> mPrintJobStateChangeListeners;
+
+    /** @hide */
+    public interface PrintJobStateChangeListener {
+
+        /**
+         * Callback notifying that a print job state changed.
+         *
+         * @param printJobId The print job id.
+         */
+        public void onPrintJobsStateChanged(PrintJobId printJobId);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context The current context in which to operate.
+     * @param service The backing system service.
+     *
+     * @hide
+     */
+    public PrintManager(Context context, IPrintManager service, int userId, int appId) {
+        mContext = context;
+        mService = service;
+        mUserId = userId;
+        mAppId = appId;
+        mPrintClient = new PrintClient(this);
+        mHandler = new Handler(context.getMainLooper(), null, false) {
+            @Override
+            public void handleMessage(Message message) {
+                SomeArgs args = (SomeArgs) message.obj;
+                Context context = (Context) args.arg1;
+                IntentSender intent = (IntentSender) args.arg2;
+                args.recycle();
+                try {
+                    context.startIntentSender(intent, null, 0, 0, 0);
+                } catch (SendIntentException sie) {
+                    Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates an instance that can access all print jobs.
+     *
+     * @param userId The user id for which to get all print jobs.
+     * @return An instance if the caller has the permission to access
+     * all print jobs, null otherwise.
+     * @hide
+     */
+    public PrintManager getGlobalPrintManagerForUser(int userId) {
+        return new PrintManager(mContext, mService, userId, APP_ID_ANY);
+    }
+
+    PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
+        try {
+            return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting a print job info:" + printJobId, re);
+        }
+        return null;
+    }
+
+    /**
+     * Adds a listener for observing the state of print jobs.
+     *
+     * @param listener The listener to add.
+     *
+     * @hide
+     */
+    public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+        if (mPrintJobStateChangeListeners == null) {
+            mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener,
+                    PrintJobStateChangeListenerWrapper>();
+        }
+        PrintJobStateChangeListenerWrapper wrappedListener =
+                new PrintJobStateChangeListenerWrapper(listener);
+        try {
+            mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId);
+            mPrintJobStateChangeListeners.put(listener, wrappedListener);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error adding print job state change listener", re);
+        }
+    }
+
+    /**
+     * Removes a listener for observing the state of print jobs.
+     *
+     * @param listener The listener to remove.
+     *
+     * @hide
+     */
+    public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+        if (mPrintJobStateChangeListeners == null) {
+            return;
+        }
+        PrintJobStateChangeListenerWrapper wrappedListener =
+                mPrintJobStateChangeListeners.remove(listener);
+        if (wrappedListener == null) {
+            return;
+        }
+        if (mPrintJobStateChangeListeners.isEmpty()) {
+            mPrintJobStateChangeListeners = null;
+        }
+        try {
+            mService.removePrintJobStateChangeListener(wrappedListener, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error removing print job state change listener", re);
+        }
+    }
+
+    /**
+     * Gets a print job given its id.
+     *
+     * @return The print job list.
+     *
+     * @see PrintJob
+     *
+     * @hide
+     */
+    public PrintJob getPrintJob(PrintJobId printJobId) {
+        try {
+            PrintJobInfo printJob = mService.getPrintJobInfo(printJobId, mAppId, mUserId);
+            if (printJob != null) {
+                return new PrintJob(printJob, this);
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting print job", re);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the print jobs for this application.
+     *
+     * @return The print job list.
+     *
+     * @see PrintJob
+     */
+    public List<PrintJob> getPrintJobs() {
+        try {
+            List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId);
+            if (printJobInfos == null) {
+                return Collections.emptyList();
+            }
+            final int printJobCount = printJobInfos.size();
+            List<PrintJob> printJobs = new ArrayList<PrintJob>(printJobCount);
+            for (int i = 0; i < printJobCount; i++) {
+                printJobs.add(new PrintJob(printJobInfos.get(i), this));
+            }
+            return printJobs;
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting print jobs", re);
+        }
+        return Collections.emptyList();
+    }
+
+    void cancelPrintJob(PrintJobId printJobId) {
+        try {
+            mService.cancelPrintJob(printJobId, mAppId, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error cancleing a print job: " + printJobId, re);
+        }
+    }
+
+    void restartPrintJob(PrintJobId printJobId) {
+        try {
+            mService.restartPrintJob(printJobId, mAppId, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error restarting a print job: " + printJobId, re);
+        }
+    }
+
+    /**
+     * Creates a print job for printing a {@link PrintDocumentAdapter} with default print
+     * attributes.
+     *
+     * @param printJobName A name for the new print job.
+     * @param documentAdapter An adapter that emits the document to print.
+     * @param attributes The default print job attributes.
+     * @return The created print job on success or null on failure.
+     * @see PrintJob
+     */
+    public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
+            PrintAttributes attributes) {
+        if (TextUtils.isEmpty(printJobName)) {
+            throw new IllegalArgumentException("priintJobName cannot be empty");
+        }
+        PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
+                mContext.getMainLooper());
+        try {
+            PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate,
+                    attributes, mAppId, mUserId);
+            if (printJob != null) {
+                return new PrintJob(printJob, this);
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error creating a print job", re);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the list of enabled print services.
+     *
+     * @return The enabled service list or an empty list.
+     *
+     * @hide
+     */
+    public List<PrintServiceInfo> getEnabledPrintServices() {
+        try {
+            List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
+            if (enabledServices != null) {
+                return enabledServices;
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting the enabled print services", re);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Gets the list of installed print services.
+     *
+     * @return The installed service list or an empty list.
+     *
+     * @hide
+     */
+    public List<PrintServiceInfo> getInstalledPrintServices() {
+        try {
+            List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
+            if (installedServices != null) {
+                return installedServices;
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting the installed print services", re);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * @hide
+     */
+    public PrinterDiscoverySession createPrinterDiscoverySession() {
+        return new PrinterDiscoverySession(mService, mContext, mUserId);
+    }
+
+    private static final class PrintClient extends IPrintClient.Stub {
+
+        private final WeakReference<PrintManager> mWeakPrintManager;
+
+        public PrintClient(PrintManager manager) {
+            mWeakPrintManager = new WeakReference<PrintManager>(manager);
+        }
+
+        @Override
+        public void startPrintJobConfigActivity(IntentSender intent) {
+            PrintManager manager = mWeakPrintManager.get();
+            if (manager != null) {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = manager.mContext;
+                args.arg2 = intent;
+                manager.mHandler.obtainMessage(0, args).sendToTarget();
+            }
+        }
+    }
+
+    private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
+
+        private final Object mLock = new Object();
+
+        private CancellationSignal mLayoutOrWriteCancellation;
+
+        private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish()
+
+        private Handler mHandler; // Strong reference OK - cleared in finish()
+
+        public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
+            mDocumentAdapter = documentAdapter;
+            mHandler = new MyHandler(looper);
+        }
+
+        @Override
+        public void start() {
+            mHandler.sendEmptyMessage(MyHandler.MSG_START);
+        }
+
+        @Override
+        public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+                ILayoutResultCallback callback, Bundle metadata, int sequence) {
+            synchronized (mLock) {
+                if (mLayoutOrWriteCancellation != null) {
+                    mLayoutOrWriteCancellation.cancel();
+                }
+            }
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = oldAttributes;
+            args.arg2 = newAttributes;
+            args.arg3 = callback;
+            args.arg4 = metadata;
+            args.argi1 = sequence;
+            mHandler.removeMessages(MyHandler.MSG_LAYOUT);
+            mHandler.obtainMessage(MyHandler.MSG_LAYOUT, args).sendToTarget();
+        }
+
+        @Override
+        public void write(PageRange[] pages, ParcelFileDescriptor fd,
+                IWriteResultCallback callback, int sequence) {
+            synchronized (mLock) {
+                if (mLayoutOrWriteCancellation != null) {
+                    mLayoutOrWriteCancellation.cancel();
+                }
+            }
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = pages;
+            args.arg2 = fd;
+            args.arg3 = callback;
+            args.argi1 = sequence;
+            mHandler.removeMessages(MyHandler.MSG_WRITE);
+            mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget();
+        }
+
+        @Override
+        public void finish() {
+            mHandler.sendEmptyMessage(MyHandler.MSG_FINISH);
+        }
+
+        private boolean isFinished() {
+            return mDocumentAdapter == null;
+        }
+
+        private void doFinish() {
+            mDocumentAdapter = null;
+            mHandler = null;
+            mLayoutOrWriteCancellation = null;
+        }
+
+        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 MyHandler(Looper looper) {
+                super(looper, null, true);
+            }
+
+            @Override
+            public void handleMessage(Message message) {
+                if (isFinished()) {
+                    return;
+                }
+                switch (message.what) {
+                    case MSG_START: {
+                        mDocumentAdapter.onStart();
+                    } break;
+
+                    case MSG_LAYOUT: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
+                        PrintAttributes newAttributes = (PrintAttributes) args.arg2;
+                        ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
+                        Bundle metadata = (Bundle) args.arg4;
+                        final int sequence = args.argi1;
+                        args.recycle();
+
+                        CancellationSignal cancellation = new CancellationSignal();
+                        synchronized (mLock) {
+                            mLayoutOrWriteCancellation = cancellation;
+                        }
+
+                        mDocumentAdapter.onLayout(oldAttributes, newAttributes, cancellation,
+                                new MyLayoutResultCallback(callback, sequence), metadata);
+                    } break;
+
+                    case MSG_WRITE: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        PageRange[] pages = (PageRange[]) args.arg1;
+                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args.arg2;
+                        IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
+                        final int sequence = args.argi1;
+                        args.recycle();
+
+                        CancellationSignal cancellation = new CancellationSignal();
+                        synchronized (mLock) {
+                            mLayoutOrWriteCancellation = cancellation;
+                        }
+
+                        mDocumentAdapter.onWrite(pages, fd, cancellation,
+                                new MyWriteResultCallback(callback, fd, sequence));
+                    } break;
+
+                    case MSG_FINISH: {
+                        mDocumentAdapter.onFinish();
+                        doFinish();
+                    } break;
+
+                    default: {
+                        throw new IllegalArgumentException("Unknown message: "
+                                + message.what);
+                    }
+                }
+            }
+        }
+
+        private final class MyLayoutResultCallback extends LayoutResultCallback {
+            private ILayoutResultCallback mCallback;
+            private final int mSequence;
+
+            public MyLayoutResultCallback(ILayoutResultCallback callback,
+                    int sequence) {
+                mCallback = callback;
+                mSequence = sequence;
+            }
+
+            @Override
+            public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+                if (info == null) {
+                    throw new NullPointerException("document info cannot be null");
+                }
+                final ILayoutResultCallback callback;
+                synchronized (mLock) {
+                    callback = mCallback;
+                    clearLocked();
+                }
+                if (callback != null) {
+                    try {
+                        callback.onLayoutFinished(info, changed, mSequence);
+                    } catch (RemoteException re) {
+                        Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
+                    }
+                }
+            }
+
+            @Override
+            public void onLayoutFailed(CharSequence error) {
+                final ILayoutResultCallback callback;
+                synchronized (mLock) {
+                    callback = mCallback;
+                    clearLocked();
+                }
+                if (callback != null) {
+                    try {
+                        callback.onLayoutFailed(error, mSequence);
+                    } catch (RemoteException re) {
+                        Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
+                    }
+                }
+            }
+
+            @Override
+            public void onLayoutCancelled() {
+                synchronized (mLock) {
+                    clearLocked();
+                }
+            }
+
+            private void clearLocked() {
+                mLayoutOrWriteCancellation = null;
+                mCallback = null;
+            }
+        }
+
+        private final class MyWriteResultCallback extends WriteResultCallback {
+            private ParcelFileDescriptor mFd;
+            private int mSequence;
+            private IWriteResultCallback mCallback;
+
+            public MyWriteResultCallback(IWriteResultCallback callback,
+                    ParcelFileDescriptor fd, int sequence) {
+                mFd = fd;
+                mSequence = sequence;
+                mCallback = callback;
+            }
+
+            @Override
+            public void onWriteFinished(PageRange[] pages) {
+                final IWriteResultCallback callback;
+                synchronized (mLock) {
+                    callback = mCallback;
+                    clearLocked();
+                }
+                if (pages == null) {
+                    throw new IllegalArgumentException("pages cannot be null");
+                }
+                if (pages.length == 0) {
+                    throw new IllegalArgumentException("pages cannot be empty");
+                }
+                if (callback != null) {
+                    try {
+                        callback.onWriteFinished(pages, mSequence);
+                    } catch (RemoteException re) {
+                        Log.e(LOG_TAG, "Error calling onWriteFinished", re);
+                    }
+                }
+            }
+
+            @Override
+            public void onWriteFailed(CharSequence error) {
+                final IWriteResultCallback callback;
+                synchronized (mLock) {
+                    callback = mCallback;
+                    clearLocked();
+                }
+                if (callback != null) {
+                    try {
+                        callback.onWriteFailed(error, mSequence);
+                    } catch (RemoteException re) {
+                        Log.e(LOG_TAG, "Error calling onWriteFailed", re);
+                    }
+                }
+            }
+
+            @Override
+            public void onWriteCancelled() {
+                synchronized (mLock) {
+                    clearLocked();
+                }
+            }
+
+            private void clearLocked() {
+                mLayoutOrWriteCancellation = null;
+                IoUtils.closeQuietly(mFd);
+                mCallback = null;
+                mFd = null;
+            }
+        }
+    }
+
+    private static final class PrintJobStateChangeListenerWrapper extends
+            IPrintJobStateChangeListener.Stub {
+        private final WeakReference<PrintJobStateChangeListener> mWeakListener;
+
+        public PrintJobStateChangeListenerWrapper(PrintJobStateChangeListener listener) {
+            mWeakListener = new WeakReference<PrintJobStateChangeListener>(listener);
+        }
+
+        @Override
+        public void onPrintJobStateChanged(PrintJobId printJobId) {
+            PrintJobStateChangeListener listener = mWeakListener.get();
+            if (listener != null) {
+                listener.onPrintJobsStateChanged(printJobId);
+            }
+        }
+    }
+}
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.aidl b/core/java/android/print/PrinterCapabilitiesInfo.aidl
new file mode 100644
index 0000000..0f5fb6b
--- /dev/null
+++ b/core/java/android/print/PrinterCapabilitiesInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrinterCapabilitiesInfo;
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
new file mode 100644
index 0000000..df51ec1
--- /dev/null
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -0,0 +1,547 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class represents the capabilities of a printer.
+ */
+public final class PrinterCapabilitiesInfo implements Parcelable {
+    /**
+     * Undefined default value.
+     *
+     * @hide
+     */
+    public static final int DEFAULT_UNDEFINED = -1;
+
+    private static final int PROPERTY_MEDIA_SIZE = 0;
+    private static final int PROPERTY_RESOLUTION = 1;
+    private static final int PROPERTY_COLOR_MODE = 2;
+    private static final int PROPERTY_COUNT = 3;
+
+    private static final Margins DEFAULT_MARGINS = new Margins(0,  0,  0,  0);
+
+    private Margins mMinMargins = DEFAULT_MARGINS;
+    private List<MediaSize> mMediaSizes;
+    private List<Resolution> mResolutions;
+
+    private int mColorModes;
+
+    private final int[] mDefaults = new int[PROPERTY_COUNT];
+
+    /**
+     * @hide
+     */
+    public PrinterCapabilitiesInfo() {
+        Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
+    }
+
+    /**
+     * @hide
+     */
+    public PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype) {
+        copyFrom(prototype);
+    }
+
+    /**
+     * @hide
+     */
+    public void copyFrom(PrinterCapabilitiesInfo other) {
+        if (this == other) {
+            return;
+        }
+
+        mMinMargins = other.mMinMargins;
+
+        if (other.mMediaSizes != null) {
+            if (mMediaSizes != null) {
+                mMediaSizes.clear();
+                mMediaSizes.addAll(other.mMediaSizes);
+            } else {
+                mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
+            }
+        } else {
+            mMediaSizes = null;
+        }
+
+        if (other.mResolutions != null) {
+            if (mResolutions != null) {
+                mResolutions.clear();
+                mResolutions.addAll(other.mResolutions);
+            } else {
+                mResolutions = new ArrayList<Resolution>(other.mResolutions);
+            }
+        } else {
+            mResolutions = null;
+        }
+
+        mColorModes = other.mColorModes;
+
+        final int defaultCount = other.mDefaults.length;
+        for (int i = 0; i < defaultCount; i++) {
+            mDefaults[i] = other.mDefaults[i];
+        }
+    }
+
+    /**
+     * Gets the supported media sizes.
+     *
+     * @return The media sizes.
+     */
+    public List<MediaSize> getMediaSizes() {
+        return mMediaSizes;
+    }
+
+    /**
+     * Gets the supported resolutions.
+     *
+     * @return The resolutions.
+     */
+    public List<Resolution> getResolutions() {
+        return mResolutions;
+    }
+
+    /**
+     * Gets the minimal margins. These are the minimal margins
+     * the printer physically supports.
+     *
+     * @return The minimal margins.
+     */
+    public Margins getMinMargins() {
+        return mMinMargins;
+    }
+
+    /**
+     * Gets the supported color modes.
+     *
+     * @return The color modes.
+     *
+     * @see PrintAttributes#COLOR_MODE_COLOR
+     * @see PrintAttributes#COLOR_MODE_MONOCHROME
+     */
+    public int getColorModes() {
+        return mColorModes;
+    }
+
+    /**
+     * Gets the default print attributes.
+     *
+     * @return The default attributes.
+     */
+    public PrintAttributes getDefaults() {
+        PrintAttributes.Builder builder = new PrintAttributes.Builder();
+
+        builder.setMinMargins(mMinMargins);
+
+        final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
+        if (mediaSizeIndex >= 0) {
+            builder.setMediaSize(mMediaSizes.get(mediaSizeIndex));
+        }
+
+        final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
+        if (resolutionIndex >= 0) {
+            builder.setResolution(mResolutions.get(resolutionIndex));
+        }
+
+        final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
+        if (colorMode > 0) {
+            builder.setColorMode(colorMode);
+        }
+
+        return builder.build();
+    }
+
+    private PrinterCapabilitiesInfo(Parcel parcel) {
+        mMinMargins = readMargins(parcel);
+        readMediaSizes(parcel);
+        readResolutions(parcel);
+
+        mColorModes = parcel.readInt();
+
+        readDefaults(parcel);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        writeMargins(mMinMargins, parcel);
+        writeMediaSizes(parcel);
+        writeResolutions(parcel);
+
+        parcel.writeInt(mColorModes);
+
+        writeDefaults(parcel);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
+        result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
+        result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
+        result = prime * result + mColorModes;
+        result = prime * result + Arrays.hashCode(mDefaults);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrinterCapabilitiesInfo other = (PrinterCapabilitiesInfo) obj;
+        if (mMinMargins == null) {
+            if (other.mMinMargins != null) {
+                return false;
+            }
+        } else if (!mMinMargins.equals(other.mMinMargins)) {
+            return false;
+        }
+        if (mMediaSizes == null) {
+            if (other.mMediaSizes != null) {
+                return false;
+            }
+        } else if (!mMediaSizes.equals(other.mMediaSizes)) {
+            return false;
+        }
+        if (mResolutions == null) {
+            if (other.mResolutions != null) {
+                return false;
+            }
+        } else if (!mResolutions.equals(other.mResolutions)) {
+            return false;
+        }
+        if (mColorModes != other.mColorModes) {
+            return false;
+        }
+        if (!Arrays.equals(mDefaults, other.mDefaults)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrinterInfo{");
+        builder.append("minMargins=").append(mMinMargins);
+        builder.append(", mediaSizes=").append(mMediaSizes);
+        builder.append(", resolutions=").append(mResolutions);
+        builder.append(", colorModes=").append(colorModesToString());
+        builder.append("\"}");
+        return builder.toString();
+    }
+
+    private String colorModesToString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append('[');
+        int colorModes = mColorModes;
+        while (colorModes != 0) {
+            final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
+            colorModes &= ~colorMode;
+            if (builder.length() > 1) {
+                builder.append(", ");
+            }
+            builder.append(PrintAttributes.colorModeToString(colorMode));
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
+    private void writeMediaSizes(Parcel parcel) {
+        if (mMediaSizes == null) {
+            parcel.writeInt(0);
+            return;
+        }
+        final int mediaSizeCount = mMediaSizes.size();
+        parcel.writeInt(mediaSizeCount);
+        for (int i = 0; i < mediaSizeCount; i++) {
+            mMediaSizes.get(i).writeToParcel(parcel);
+        }
+    }
+
+    private void readMediaSizes(Parcel parcel) {
+        final int mediaSizeCount = parcel.readInt();
+        if (mediaSizeCount > 0 && mMediaSizes == null) {
+            mMediaSizes = new ArrayList<MediaSize>();
+        }
+        for (int i = 0; i < mediaSizeCount; i++) {
+            mMediaSizes.add(MediaSize.createFromParcel(parcel));
+        }
+    }
+
+    private void writeResolutions(Parcel parcel) {
+        if (mResolutions == null) {
+            parcel.writeInt(0);
+            return;
+        }
+        final int resolutionCount = mResolutions.size();
+        parcel.writeInt(resolutionCount);
+        for (int i = 0; i < resolutionCount; i++) {
+            mResolutions.get(i).writeToParcel(parcel);
+        }
+    }
+
+    private void readResolutions(Parcel parcel) {
+        final int resolutionCount = parcel.readInt();
+        if (resolutionCount > 0 && mResolutions == null) {
+            mResolutions = new ArrayList<Resolution>();
+        }
+        for (int i = 0; i < resolutionCount; i++) {
+            mResolutions.add(Resolution.createFromParcel(parcel));
+        }
+    }
+
+    private void writeMargins(Margins margins, Parcel parcel) {
+        if (margins == null) {
+            parcel.writeInt(0);
+        } else {
+            parcel.writeInt(1);
+            margins.writeToParcel(parcel);
+        }
+    }
+
+    private Margins readMargins(Parcel parcel) {
+        return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
+    }
+
+    private void readDefaults(Parcel parcel) {
+        final int defaultCount = parcel.readInt();
+        for (int i = 0; i < defaultCount; i++) {
+            mDefaults[i] = parcel.readInt();
+        }
+    }
+
+    private void writeDefaults(Parcel parcel) {
+        final int defaultCount = mDefaults.length;
+        parcel.writeInt(defaultCount);
+        for (int i = 0; i < defaultCount; i++) {
+            parcel.writeInt(mDefaults[i]);
+        }
+    }
+
+    /**
+     * Builder for creating of a {@link PrinterInfo}. This class is responsible
+     * to enforce that all required attributes have at least one default value.
+     * In other words, this class creates only well-formed {@link PrinterInfo}s.
+     * <p>
+     * Look at the individual methods for a reference whether a property is
+     * required or if it is optional.
+     * </p>
+     */
+    public static final class Builder {
+        private final PrinterCapabilitiesInfo mPrototype;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param printerId The printer id. Cannot be null.
+         *
+         * @throws IllegalArgumentException If the printer id is null.
+         */
+        public Builder(PrinterId printerId) {
+            if (printerId == null) {
+                throw new IllegalArgumentException("printerId cannot be null.");
+            }
+            mPrototype = new PrinterCapabilitiesInfo();
+        }
+
+        /**
+         * Adds a supported media size.
+         * <p>
+         * <strong>Required:</strong> Yes
+         * </p>
+         *
+         * @param mediaSize A media size.
+         * @param isDefault Whether this is the default.
+         * @return This builder.
+         * @throws IllegalArgumentException If set as default and there
+         *     is already a default.
+         *
+         * @see PrintAttributes.MediaSize
+         */
+        public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
+            if (mPrototype.mMediaSizes == null) {
+                mPrototype.mMediaSizes = new ArrayList<MediaSize>();
+            }
+            final int insertionIndex = mPrototype.mMediaSizes.size();
+            mPrototype.mMediaSizes.add(mediaSize);
+            if (isDefault) {
+                throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
+                mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
+            }
+            return this;
+        }
+
+        /**
+         * Adds a supported resolution.
+         * <p>
+         * <strong>Required:</strong> Yes
+         * </p>
+         *
+         * @param resolution A resolution.
+         * @param isDefault Whether this is the default.
+         * @return This builder.
+         *
+         * @throws IllegalArgumentException If set as default and there
+         *     is already a default.
+         *
+         * @see PrintAttributes.Resolution
+         */
+        public Builder addResolution(Resolution resolution, boolean isDefault) {
+            if (mPrototype.mResolutions == null) {
+                mPrototype.mResolutions = new ArrayList<Resolution>();
+            }
+            final int insertionIndex = mPrototype.mResolutions.size();
+            mPrototype.mResolutions.add(resolution);
+            if (isDefault) {
+                throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
+                mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the minimal margins. These are the minimal margins
+         * the printer physically supports.
+         *
+         * <p>
+         * <strong>Required:</strong> Yes
+         * </p>
+         *
+         * @param margins The margins.
+         * @return This builder.
+         *
+         * @throws IllegalArgumentException If margins are <code>null</code>.
+         *
+         * @see PrintAttributes.Margins
+         */
+        public Builder setMinMargins(Margins margins) {
+            if (margins == null) {
+                throw new IllegalArgumentException("margins cannot be null");
+            }
+            mPrototype.mMinMargins = margins;
+            return this;
+        }
+
+        /**
+         * Sets the color modes.
+         * <p>
+         * <strong>Required:</strong> Yes
+         * </p>
+         *
+         * @param colorModes The color mode bit mask.
+         * @param defaultColorMode The default color mode.
+         * @return This builder.
+         *
+         * @throws IllegalArgumentException If color modes contains an invalid
+         *         mode bit or if the default color mode is invalid.
+         *
+         * @see PrintAttributes#COLOR_MODE_COLOR
+         * @see PrintAttributes#COLOR_MODE_MONOCHROME
+         */
+        public Builder setColorModes(int colorModes, int defaultColorMode) {
+            int currentModes = colorModes;
+            while (currentModes > 0) {
+                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
+                currentModes &= ~currentMode;
+                PrintAttributes.enforceValidColorMode(currentMode);
+            }
+            if ((colorModes & defaultColorMode) == 0) {
+                throw new IllegalArgumentException("Default color mode not in color modes.");
+            }
+            PrintAttributes.enforceValidColorMode(colorModes);
+            mPrototype.mColorModes = colorModes;
+            mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
+            return this;
+        }
+
+        /**
+         * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
+         * required properties have need specified. See individual methods
+         * in this class for reference about required attributes.
+         *
+         * @return A new {@link PrinterCapabilitiesInfo}.
+         *
+         * @throws IllegalStateException If a required attribute was not specified.
+         */
+        public PrinterCapabilitiesInfo build() {
+            if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
+                throw new IllegalStateException("No media size specified.");
+            }
+            if (mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] == DEFAULT_UNDEFINED) {
+                throw new IllegalStateException("No default media size specified.");
+            }
+            if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
+                throw new IllegalStateException("No resolution specified.");
+            }
+            if (mPrototype.mDefaults[PROPERTY_RESOLUTION] == DEFAULT_UNDEFINED) {
+                throw new IllegalStateException("No default resolution specified.");
+            }
+            if (mPrototype.mColorModes == 0) {
+                throw new IllegalStateException("No color mode specified.");
+            }
+            if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
+                throw new IllegalStateException("No default color mode specified.");
+            }
+            if (mPrototype.mMinMargins == null) {
+                throw new IllegalArgumentException("margins cannot be null");
+            }
+            return new PrinterCapabilitiesInfo(mPrototype);
+        }
+
+        private void throwIfDefaultAlreadySpecified(int propertyIndex) {
+            if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
+                throw new IllegalArgumentException("Default already specified.");
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<PrinterCapabilitiesInfo> CREATOR =
+            new Parcelable.Creator<PrinterCapabilitiesInfo>() {
+        @Override
+        public PrinterCapabilitiesInfo createFromParcel(Parcel parcel) {
+            return new PrinterCapabilitiesInfo(parcel);
+        }
+
+        @Override
+        public PrinterCapabilitiesInfo[] newArray(int size) {
+            return new PrinterCapabilitiesInfo[size];
+        }
+    };
+}
+
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
new file mode 100644
index 0000000..d32b71b
--- /dev/null
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -0,0 +1,316 @@
+/*
+ * 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 android.print;
+
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class PrinterDiscoverySession {
+
+    private static final String LOG_TAG ="PrinterDiscoverySession";
+
+    private static final int MSG_PRINTERS_ADDED = 1;
+    private static final int MSG_PRINTERS_REMOVED = 2;
+
+    private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
+            new LinkedHashMap<PrinterId, PrinterInfo>();
+
+    private final IPrintManager mPrintManager;
+
+    private final int mUserId;
+
+    private final Handler mHandler;
+
+    private IPrinterDiscoveryObserver mObserver;
+
+    private OnPrintersChangeListener mListener;
+
+    private boolean mIsPrinterDiscoveryStarted;
+
+    public static interface OnPrintersChangeListener {
+        public void onPrintersChanged();
+    }
+
+    PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
+        mPrintManager = printManager;
+        mUserId = userId;
+        mHandler = new SessionHandler(context.getMainLooper());
+        mObserver = new PrinterDiscoveryObserver(this);
+        try {
+            mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error creating printer discovery session", re);
+        }
+    }
+
+    public final void startPrinterDisovery(List<PrinterId> priorityList) {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring start printers dsicovery - session destroyed");
+            return;
+        }
+        if (!mIsPrinterDiscoveryStarted) {
+            mIsPrinterDiscoveryStarted = true;
+            try {
+                mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error starting printer discovery", re);
+            }
+        }
+    }
+
+    public final void stopPrinterDiscovery() {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
+            return;
+        }
+        if (mIsPrinterDiscoveryStarted) {
+            mIsPrinterDiscoveryStarted = false;
+            try {
+                mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error stopping printer discovery", re);
+            }
+        }
+    }
+
+    public final void startPrinterStateTracking(PrinterId printerId) {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
+            return;
+        }
+        try {
+            mPrintManager.startPrinterStateTracking(printerId, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error starting printer state tracking", re);
+        }
+    }
+
+    public final void stopPrinterStateTracking(PrinterId printerId) {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
+            return;
+        }
+        try {
+            mPrintManager.stopPrinterStateTracking(printerId, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error stoping printer state tracking", re);
+        }
+    }
+
+    public final void validatePrinters(List<PrinterId> printerIds) {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
+            return;
+        }
+        try {
+            mPrintManager.validatePrinters(printerIds, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error validating printers", re);
+        }
+    }
+
+    public final void destroy() {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
+        }
+        destroyNoCheck();
+    }
+
+    public final List<PrinterInfo> getPrinters() {
+        if (isDestroyed()) {
+            Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
+            return Collections.emptyList();
+        }
+        return new ArrayList<PrinterInfo>(mPrinters.values());
+    }
+
+    public final boolean isDestroyed() {
+        throwIfNotCalledOnMainThread();
+        return isDestroyedNoCheck();
+    }
+
+    public final boolean isPrinterDiscoveryStarted() {
+        throwIfNotCalledOnMainThread();
+        return mIsPrinterDiscoveryStarted;
+    }
+
+    public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
+        throwIfNotCalledOnMainThread();
+        mListener = listener;
+    }
+
+    @Override
+    protected final void finalize() throws Throwable {
+        if (!isDestroyedNoCheck()) {
+            Log.e(LOG_TAG, "Destroying leaked printer discovery session");
+            destroyNoCheck();
+        }
+        super.finalize();
+    }
+
+    private boolean isDestroyedNoCheck() {
+        return (mObserver == null);
+    }
+
+    private void destroyNoCheck() {
+        stopPrinterDiscovery();
+        try {
+            mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error destroying printer discovery session", re);
+        } finally {
+            mObserver = null;
+            mPrinters.clear();
+        }
+    }
+
+    private void handlePrintersAdded(List<PrinterInfo> addedPrinters) {
+        if (isDestroyed()) {
+            return;
+        }
+
+        // No old printers - do not bother keeping their position.
+        if (mPrinters.isEmpty()) {
+            final int printerCount = addedPrinters.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterInfo printer = addedPrinters.get(i);
+                mPrinters.put(printer.getId(), printer);
+            }
+            notifyOnPrintersChanged();
+            return;
+        }
+
+        // Add the printers to a map.
+        ArrayMap<PrinterId, PrinterInfo> addedPrintersMap =
+                new ArrayMap<PrinterId, PrinterInfo>();
+        final int printerCount = addedPrinters.size();
+        for (int i = 0; i < printerCount; i++) {
+            PrinterInfo printer = addedPrinters.get(i);
+            addedPrintersMap.put(printer.getId(), printer);
+        }
+
+        // Update printers we already have.
+        for (PrinterId oldPrinterId : mPrinters.keySet()) {
+            PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
+            if (updatedPrinter != null) {
+                mPrinters.put(oldPrinterId, updatedPrinter);
+            }
+        }
+
+        // Add the new printers, i.e. what is left.
+        mPrinters.putAll(addedPrintersMap);
+
+        // Announce the change.
+        notifyOnPrintersChanged();
+    }
+
+    private void handlePrintersRemoved(List<PrinterId> printerIds) {
+        if (isDestroyed()) {
+            return;
+        }
+        boolean printersChanged = false;
+        final int removedPrinterIdCount = printerIds.size();
+        for (int i = 0; i < removedPrinterIdCount; i++) {
+            PrinterId removedPrinterId = printerIds.get(i);
+            if (mPrinters.remove(removedPrinterId) != null) {
+                printersChanged = true;
+            }
+        }
+        if (printersChanged) {
+            notifyOnPrintersChanged();
+        }
+    }
+
+    private void notifyOnPrintersChanged() {
+        if (mListener != null) {
+            mListener.onPrintersChanged();
+        }
+    }
+
+    private static void throwIfNotCalledOnMainThread() {
+        if (!Looper.getMainLooper().isCurrentThread()) {
+            throw new IllegalAccessError("must be called from the main thread");
+        }
+    }
+
+    private final class SessionHandler extends Handler {
+
+        public SessionHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_PRINTERS_ADDED: {
+                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
+                    handlePrintersAdded(printers);
+                } break;
+
+                case MSG_PRINTERS_REMOVED: {
+                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+                    handlePrintersRemoved(printerIds);
+                } break;
+            }
+        }
+    }
+
+    private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
+
+        private final WeakReference<PrinterDiscoverySession> mWeakSession;
+
+        public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
+            mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        public void onPrintersAdded(ParceledListSlice printers) {
+            PrinterDiscoverySession session = mWeakSession.get();
+            if (session != null) {
+                session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
+                        printers.getList()).sendToTarget();
+            }
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        public void onPrintersRemoved(ParceledListSlice printerIds) {
+            PrinterDiscoverySession session = mWeakSession.get();
+            if (session != null) {
+                session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
+                        printerIds.getList()).sendToTarget();
+            }
+        }
+    }
+}
diff --git a/core/java/android/print/PrinterId.aidl b/core/java/android/print/PrinterId.aidl
new file mode 100644
index 0000000..84f422f
--- /dev/null
+++ b/core/java/android/print/PrinterId.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrinterId;
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
new file mode 100644
index 0000000..a3f3b2bf
--- /dev/null
+++ b/core/java/android/print/PrinterId.java
@@ -0,0 +1,140 @@
+/*
+ * 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 android.print;
+
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * This class represents the unique id of a printer.
+ */
+public final class PrinterId implements Parcelable {
+
+    private final ComponentName mServiceName;
+
+    private final String mLocalId;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param serviceName The managing print service.
+     * @param localId The locally unique id within the managing service.
+     *
+     * @hide
+     */
+    public PrinterId(ComponentName serviceName, String localId) {
+        mServiceName = serviceName;
+        mLocalId = localId;
+    }
+
+    private PrinterId(Parcel parcel) {
+        mServiceName = parcel.readParcelable(null);
+        mLocalId = parcel.readString();
+    }
+
+    /**
+     * The id of the print service this printer is managed by.
+     *
+     * @return The print service component name.
+     *
+     * @hide
+     */
+    public ComponentName getServiceName() {
+        return mServiceName;
+    }
+
+    /**
+     * Gets the id of this printer which is unique in the context
+     * of the print service that manages it.
+     *
+     * @return The printer name.
+     */
+    public String getLocalId() {
+        return mLocalId;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mServiceName, flags);
+        parcel.writeString(mLocalId);
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object == null) {
+            return false;
+        }
+        if (getClass() != object.getClass()) {
+            return false;
+        }
+        PrinterId other = (PrinterId) object;
+        if (mServiceName == null) {
+            if (other.mServiceName != null) {
+                return false;
+            }
+        } else if (!mServiceName.equals(other.mServiceName)) {
+            return false;
+        }
+        if (!TextUtils.equals(mLocalId, other.mLocalId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int hashCode = 1;
+        hashCode = prime * hashCode + ((mServiceName != null)
+                ? mServiceName.hashCode() : 1);
+        hashCode = prime * hashCode + mLocalId.hashCode();
+        return hashCode;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrinterId{");
+        builder.append("serviceName=").append(mServiceName.flattenToString());
+        builder.append(", localId=").append(mLocalId);
+        builder.append('}');
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<PrinterId> CREATOR =
+            new Creator<PrinterId>() {
+        @Override
+        public PrinterId createFromParcel(Parcel parcel) {
+            return new PrinterId(parcel);
+        }
+
+        @Override
+        public PrinterId[] newArray(int size) {
+            return new PrinterId[size];
+        }
+    };
+}
diff --git a/core/java/android/print/PrinterInfo.aidl b/core/java/android/print/PrinterInfo.aidl
new file mode 100644
index 0000000..6ec5a58
--- /dev/null
+++ b/core/java/android/print/PrinterInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.print;
+
+parcelable PrinterInfo;
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
new file mode 100644
index 0000000..ad79a38
--- /dev/null
+++ b/core/java/android/print/PrinterInfo.java
@@ -0,0 +1,322 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * This class represents the description of a printer.
+ */
+public final class PrinterInfo implements Parcelable {
+
+    /** Printer status: the printer is idle and ready to print. */
+    public static final int STATUS_IDLE = 1;
+
+    /** Printer status: the printer is busy printing. */
+    public static final int STATUS_BUSY = 2;
+
+    /** Printer status: the printer is not available. */
+    public static final int STATUS_UNAVAILABLE = 3;
+
+    private PrinterId mId;
+
+    private String mName;
+
+    private int mStatus;
+
+    private String mDescription;
+
+    private PrinterCapabilitiesInfo mCapabilities;
+
+    private PrinterInfo() {
+        /* do nothing */
+    }
+
+    private PrinterInfo(PrinterInfo prototype) {
+        copyFrom(prototype);
+    }
+
+    /**
+     * @hide
+     */
+    public void copyFrom(PrinterInfo other) {
+        if (this == other) {
+            return;
+        }
+        mId = other.mId;
+        mName = other.mName;
+        mStatus = other.mStatus;
+        mDescription = other.mDescription;
+        if (other.mCapabilities != null) {
+            if (mCapabilities != null) {
+                mCapabilities.copyFrom(other.mCapabilities);
+            } else {
+                mCapabilities = new PrinterCapabilitiesInfo(other.mCapabilities);
+            }
+        } else {
+            mCapabilities = null;
+        }
+    }
+
+    /**
+     * Get the globally unique printer id.
+     *
+     * @return The printer id.
+     */
+    public PrinterId getId() {
+        return mId;
+    }
+
+    /**
+     * Get the printer name.
+     *
+     * @return The printer name.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Gets the printer status.
+     *
+     * @return The status.
+     */
+    public int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Gets the  printer description.
+     *
+     * @return The description.
+     */
+    public String getDescription() {
+        return mDescription;
+    }
+
+    /**
+     * Gets the printer capabilities.
+     *
+     * @return The capabilities.
+     */
+    public PrinterCapabilitiesInfo getCapabilities() {
+        return mCapabilities;
+    }
+
+    private PrinterInfo(Parcel parcel) {
+        mId = parcel.readParcelable(null);
+        mName = parcel.readString();
+        mStatus = parcel.readInt();
+        mDescription = parcel.readString();
+        mCapabilities = parcel.readParcelable(null);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mId, flags);
+        parcel.writeString(mName);
+        parcel.writeInt(mStatus);
+        parcel.writeString(mDescription);
+        parcel.writeParcelable(mCapabilities, flags);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mId != null) ? mId.hashCode() : 0);
+        result = prime * result + ((mName != null) ? mName.hashCode() : 0);
+        result = prime * result + mStatus;
+        result = prime * result + ((mDescription != null) ? mDescription.hashCode() : 0);
+        result = prime * result + ((mCapabilities != null) ? mCapabilities.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrinterInfo other = (PrinterInfo) obj;
+        if (mId == null) {
+            if (other.mId != null) {
+                return false;
+            }
+        } else if (!mId.equals(other.mId)) {
+            return false;
+        }
+        if (!TextUtils.equals(mName, other.mName)) {
+            return false;
+        }
+        if (mStatus != other.mStatus) {
+            return false;
+        }
+        if (!TextUtils.equals(mDescription, other.mDescription)) {
+            return false;
+        }
+        if (mCapabilities == null) {
+            if (other.mCapabilities != null) {
+                return false;
+            }
+        } else if (!mCapabilities.equals(other.mCapabilities)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrinterInfo{");
+        builder.append("id=").append(mId);
+        builder.append(", name=").append(mName);
+        builder.append(", status=").append(mStatus);
+        builder.append(", description=").append(mDescription);
+        builder.append(", capabilities=").append(mCapabilities);
+        builder.append("\"}");
+        return builder.toString();
+    }
+
+    /**
+     * Builder for creating of a {@link PrinterInfo}.
+     */
+    public static final class Builder {
+        private final PrinterInfo mPrototype;
+
+        /**
+         * Constructor.
+         *
+         * @param printerId The printer id. Cannot be null.
+         * @param name The printer name. Cannot be empty.
+         * @param status The printer status. Must be a valid status.
+         */
+        public Builder(PrinterId printerId, String name, int status) {
+            if (printerId == null) {
+                throw new IllegalArgumentException("printerId cannot be null.");
+            }
+            if (TextUtils.isEmpty(name)) {
+                throw new IllegalArgumentException("name cannot be empty.");
+            }
+            if (!isValidStatus(status)) {
+                throw new IllegalArgumentException("status is invalid.");
+            }
+            mPrototype = new PrinterInfo();
+            mPrototype.mId = printerId;
+            mPrototype.mName = name;
+            mPrototype.mStatus = status;
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param other Other info from which to start building.
+         */
+        public Builder(PrinterInfo other) {
+            mPrototype = new PrinterInfo();
+            mPrototype.copyFrom(other);
+        }
+
+        /**
+         * Sets the printer status.
+         *
+         * @param status The status.
+         * @return This builder.
+         *
+         * @see PrinterInfo#STATUS_IDLE
+         * @see PrinterInfo#STATUS_BUSY
+         * @see PrinterInfo#STATUS_UNAVAILABLE
+         */
+        public Builder setStatus(int status) {
+            mPrototype.mStatus = status;
+            return this;
+        }
+
+        /**
+         * Sets the printer name.
+         *
+         * @param name The name.
+         * @return This builder.
+         */
+        public Builder setName(String name) {
+            mPrototype.mName = name;
+            return this;
+        }
+
+        /**
+         * Sets the printer description.
+         *
+         * @param description The description.
+         * @return This builder.
+         */
+        public Builder setDescription(String description) {
+            mPrototype.mDescription = description;
+            return this;
+        }
+
+        /**
+         * Sets the printer capabilities.
+         *
+         * @param capabilities The capabilities.
+         * @return This builder.
+         */
+        public Builder setCapabilities(PrinterCapabilitiesInfo capabilities) {
+            mPrototype.mCapabilities = capabilities;
+            return this;
+        }
+
+        /**
+         * Crates a new {@link PrinterInfo}.
+         *
+         * @return A new {@link PrinterInfo}.
+         */
+        public PrinterInfo build() {
+            return new PrinterInfo(mPrototype);
+        }
+
+        private boolean isValidStatus(int status) {
+            return (status == STATUS_IDLE
+                    || status == STATUS_BUSY
+                    || status == STATUS_UNAVAILABLE);
+        }
+    }
+
+    public static final Parcelable.Creator<PrinterInfo> CREATOR =
+            new Parcelable.Creator<PrinterInfo>() {
+        @Override
+        public PrinterInfo createFromParcel(Parcel parcel) {
+            return new PrinterInfo(parcel);
+        }
+
+        @Override
+        public PrinterInfo[] newArray(int size) {
+            return new PrinterInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java
new file mode 100644
index 0000000..2d8aafa
--- /dev/null
+++ b/core/java/android/print/pdf/PrintedPdfDocument.java
@@ -0,0 +1,164 @@
+/*
+ * 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 android.print.pdf;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.pdf.PdfDocument;
+import android.graphics.pdf.PdfDocument.Page;
+import android.graphics.pdf.PdfDocument.PageInfo;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+
+/**
+ * This class is a helper for creating a PDF file for given print
+ * attributes. It is useful for implementing printing via the native
+ * Android graphics APIs.
+ * <p>
+ * This class computes the page width, page height, and content rectangle
+ * from the provided print attributes and these precomputed values can be
+ * accessed via {@link #getPageWidth()}, {@link #getPageHeight()}, and
+ * {@link #getPageContentRect()}, respectively. The {@link #startPage(int)}
+ * methods creates pages whose {@link PageInfo} is initialized with the
+ * precomputed values for width, height, and content rectangle.
+ * <p>
+ * A typical use of the APIs looks like this:
+ * </p>
+ * <pre>
+ * // open a new document
+ * PrintedPdfDocument document = new PrintedPdfDocument(context,
+ *         printAttributes);
+ *
+ * // start a page
+ * Page page = document.startPage(0);
+ *
+ * // draw something on the page
+ * View content = getContentView();
+ * content.draw(page.getCanvas());
+ *
+ * // finish the page
+ * document.finishPage(page);
+ * . . .
+ * // add more pages
+ * . . .
+ * // write the document content
+ * document.writeTo(getOutputStream());
+ *
+ * //close the document
+ * document.close();
+ * </pre>
+ */
+public class PrintedPdfDocument extends PdfDocument {
+    private static final int MILS_PER_INCH = 1000;
+    private static final int POINTS_IN_INCH = 72;
+
+    private final int mPageWidth;
+    private final int mPageHeight;
+    private final Rect mContentRect;
+
+    /**
+     * Creates a new document.
+     * <p>
+     * <strong>Note:</strong> You must close the document after you are
+     * done by calling {@link #close()}.
+     * </p>
+     *
+     * @param context Context instance for accessing resources.
+     * @param attributes The print attributes.
+     */
+    public PrintedPdfDocument(Context context, PrintAttributes attributes) {
+        MediaSize mediaSize = attributes.getMediaSize();
+
+        // Compute the size of the target canvas from the attributes.
+        mPageWidth = (int) (((float) mediaSize.getWidthMils() / MILS_PER_INCH)
+                * POINTS_IN_INCH);
+        mPageHeight = (int) (((float) mediaSize.getHeightMils() / MILS_PER_INCH)
+                * POINTS_IN_INCH);
+
+        // Compute the content size from the attributes.
+        Margins minMargins = attributes.getMinMargins();
+        final int marginLeft = (int) (((float) minMargins.getLeftMils() / MILS_PER_INCH)
+                * POINTS_IN_INCH);
+        final int marginTop = (int) (((float) minMargins.getTopMils() / MILS_PER_INCH)
+                * POINTS_IN_INCH);
+        final int marginRight = (int) (((float) minMargins.getRightMils() / MILS_PER_INCH)
+                * POINTS_IN_INCH);
+        final int marginBottom = (int) (((float) minMargins.getBottomMils() / MILS_PER_INCH)
+                * POINTS_IN_INCH);
+        mContentRect = new Rect(marginLeft, marginTop, mPageWidth - marginRight,
+                mPageHeight - marginBottom);
+    }
+
+    /**
+     * Starts a new page. The page is created using width, height  and content
+     * rectangle computed from the print attributes passed in the constructor
+     * and the given page number to create an appropriate {@link PageInfo}.
+     * <p>
+     * After the page is created you can draw arbitrary content on the page's
+     * canvas which you can get by calling {@link Page#getCanvas() Page.getCanvas()}.
+     * After you are done drawing the content you should finish the page by calling
+     * {@link #finishPage(Page)}. After the page is finished you should no longer
+     * access the page or its canvas.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> Do not call this method after {@link #close()}.
+     * Also do not call this method if the last page returned by this method
+     * is not finished by calling {@link #finishPage(Page)}.
+     * </p>
+     *
+     * @param pageNumber The page number. Must be a positive value.
+     * @return A blank page.
+     *
+     * @see #finishPage(Page)
+     */
+    public Page startPage(int pageNumber) {
+        PageInfo pageInfo = new PageInfo
+                .Builder(mPageWidth, mPageHeight, pageNumber)
+                .setContentRect(mContentRect)
+                .create();
+        return startPage(pageInfo);
+    }
+
+    /**
+     * Gets the page width.
+     *
+     * @return The page width in PostScript points (1/72th of an inch).
+     */
+    public int getPageWidth() {
+        return mPageWidth;
+    }
+
+    /**
+     * Gets the page height.
+     *
+     * @return The page height in PostScript points (1/72th of an inch).
+     */
+    public int getPageHeight() {
+        return mPageHeight;
+    }
+
+    /**
+     * Gets the content rectangle. This is the area of the page that
+     * contains printed data and is relative to the page top left.
+     *
+     * @return The content rectangle.
+     */
+    public Rect getPageContentRect() {
+        return mContentRect;
+    }
+}
diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl
new file mode 100644
index 0000000..ee36619
--- /dev/null
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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 languagÿe governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice;
+
+import android.print.PrinterId;
+import android.print.PrintJobInfo;
+import android.printservice.IPrintServiceClient;
+
+/**
+ * Top-level interface to a print service component.
+ *
+ * @hide
+ */
+oneway interface IPrintService {
+    void setClient(IPrintServiceClient client);
+    void requestCancelPrintJob(in PrintJobInfo printJobInfo);
+    void onPrintJobQueued(in PrintJobInfo printJobInfo);
+
+    void createPrinterDiscoverySession();
+    void startPrinterDiscovery(in List<PrinterId> priorityList);
+    void stopPrinterDiscovery();
+    void validatePrinters(in List<PrinterId> printerIds);
+    void startPrinterStateTracking(in PrinterId printerId);
+    void stopPrinterStateTracking(in PrinterId printerId);
+    void destroyPrinterDiscoverySession();
+}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
new file mode 100644
index 0000000..c2dfc30
--- /dev/null
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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 android.printservice;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.PrintJobId;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * The top-level interface from a print service to the system.
+ *
+ * @hide
+ */
+interface IPrintServiceClient {
+    List<PrintJobInfo> getPrintJobInfos();
+    PrintJobInfo getPrintJobInfo(in PrintJobId printJobId);
+    boolean setPrintJobState(in PrintJobId printJobId, int state, String error);
+    boolean setPrintJobTag(in PrintJobId printJobId, String tag);
+    oneway void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
+
+    void onPrintersAdded(in ParceledListSlice printers);
+    void onPrintersRemoved(in ParceledListSlice printerIds);
+}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
new file mode 100644
index 0000000..e43f2a8
--- /dev/null
+++ b/core/java/android/printservice/PrintDocument.java
@@ -0,0 +1,97 @@
+/*
+ * 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 android.printservice;
+
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * This class represents a printed document from the perspective of a print
+ * service. It exposes APIs to query the document and obtain its data.
+ * <p>
+ * <strong>Note: </strong> All methods of this class must be executed on the
+ * main application thread.
+ * </p>
+ */
+public final class PrintDocument {
+
+    private static final String LOG_TAG = "PrintDocument";
+
+    private final PrintJobId mPrintJobId;
+
+    private final IPrintServiceClient mPrintServiceClient;
+
+    private final PrintDocumentInfo mInfo;
+
+    PrintDocument(PrintJobId printJobId, IPrintServiceClient printServiceClient,
+            PrintDocumentInfo info) {
+        mPrintJobId = printJobId;
+        mPrintServiceClient = printServiceClient;
+        mInfo = info;
+    }
+
+    /**
+     * Gets the {@link PrintDocumentInfo} that describes this document.
+     *
+     * @return The document info.
+     */
+    public PrintDocumentInfo getInfo() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return mInfo;
+    }
+
+    /**
+     * Gets the data associated with this document.
+     * <p>
+     * <strong>Note: </strong> It is a responsibility of the client to open a
+     * stream to the returned file descriptor, fully read the data, and close
+     * the file descriptor.
+     * </p>
+     *
+     * @return A file descriptor for reading the data.
+     */
+    public ParcelFileDescriptor getData() {
+        PrintService.throwIfNotCalledOnMainThread();
+        ParcelFileDescriptor source = null;
+        ParcelFileDescriptor sink = null;
+        try {
+            ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+            source = fds[0];
+            sink = fds[1];
+            mPrintServiceClient.writePrintJobData(sink, mPrintJobId);
+            return source;
+        } catch (IOException ioe) {
+            Log.e(LOG_TAG, "Error calling getting print job data!", ioe);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error calling getting print job data!", re);
+        } finally {
+            if (sink != null) {
+                try {
+                    sink.close();
+                } catch (IOException ioe) {
+                    /* ignore */
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
new file mode 100644
index 0000000..721e31e
--- /dev/null
+++ b/core/java/android/printservice/PrintJob.java
@@ -0,0 +1,346 @@
+/*
+ * 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 android.printservice;
+
+import android.os.RemoteException;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * This class represents a print job from the perspective of a print
+ * service. It provides APIs for observing the print job state and
+ * performing operations on the print job.
+ * <p>
+ * <strong>Note: </strong> All methods of this class must be invoked on
+ * the main application thread.
+ * </p>
+ */
+public final class PrintJob {
+
+    private static final String LOG_TAG = "PrintJob";
+
+    private final IPrintServiceClient mPrintServiceClient;
+
+    private final PrintDocument mDocument;
+
+    private PrintJobInfo mCachedInfo;
+
+    PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) {
+        mCachedInfo = jobInfo;
+        mPrintServiceClient = client;
+        mDocument = new PrintDocument(mCachedInfo.getId(), client,
+                jobInfo.getDocumentInfo());
+    }
+
+    /**
+     * Gets the unique print job id.
+     *
+     * @return The id.
+     */
+    public PrintJobId getId() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return mCachedInfo.getId();
+    }
+
+    /**
+     * Gets the {@link PrintJobInfo} that describes this job.
+     * <p>
+     * <strong>Node:</strong>The returned info object is a snapshot of the
+     * current print job state. Every call to this method returns a fresh
+     * info object that reflects the current print job state.
+     * </p>
+     *
+     * @return The print job info.
+     */
+    public PrintJobInfo getInfo() {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (isInImmutableState()) {
+            return mCachedInfo;
+        }
+        PrintJobInfo info = null;
+        try {
+            info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId());
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Couldn't get info for job: " + mCachedInfo.getId(), re);
+        }
+        if (info != null) {
+            mCachedInfo = info;
+        }
+        return mCachedInfo;
+    }
+
+    /**
+     * Gets the printed document.
+     *
+     * @return The document.
+     */
+    public PrintDocument getDocument() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return mDocument;
+    }
+
+    /**
+     * Gets whether this print job is queued. Such a print job is
+     * ready to be printed and can be started or cancelled.
+     *
+     * @return Whether the print job is queued.
+     *
+     * @see #start()
+     * @see #cancel()
+     */
+    public boolean isQueued() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return getInfo().getState() == PrintJobInfo.STATE_QUEUED;
+    }
+
+    /**
+     * Gets whether this print job is started. Such a print job is
+     * being printed and can be completed or canceled or failed.
+     *
+     * @return Whether the print job is started.
+     *
+     * @see #complete()
+     * @see #cancel()
+     * @see #fail(CharSequence)
+     */
+    public boolean isStarted() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return getInfo().getState() == PrintJobInfo.STATE_STARTED;
+    }
+
+    /**
+     * Gets whether this print job is blocked. Such a print job is halted
+     * due to an abnormal condition and can be started or canceled or failed.
+     *
+     * @return Whether the print job is blocked.
+     *
+     * @see #start()
+     * @see #cancel()
+     * @see #fail(CharSequence)
+     */
+    public boolean isBlocked() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
+    }
+
+    /**
+     * Gets whether this print job is completed. Such a print job
+     * is successfully printed. This is a final state.
+     *
+     * @return Whether the print job is completed.
+     *
+     * @see #complete()
+     */
+    public boolean isCompleted() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return getInfo().getState() == PrintJobInfo.STATE_COMPLETED;
+    }
+
+    /**
+     * Gets whether this print job is failed. Such a print job is
+     * not successfully printed due to an error. This is a final state.
+     *
+     * @return Whether the print job is failed.
+     *
+     * @see #fail(CharSequence)
+     */
+    public boolean isFailed() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return getInfo().getState() == PrintJobInfo.STATE_FAILED;
+    }
+
+    /**
+     * Gets whether this print job is cancelled. Such a print job was
+     * cancelled as a result of a user request. This is a final state.
+     *
+     * @return Whether the print job is cancelled.
+     *
+     * @see #cancel()
+     */
+    public boolean isCancelled() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
+    }
+
+    /**
+     * Starts the print job. You should call this method if {@link
+     * #isQueued()} or {@link #isBlocked()} returns true and you started
+     * resumed printing.
+     *
+     * @return Whether the job was started.
+     *
+     * @see #isQueued()
+     * @see #isBlocked()
+     */
+    public boolean start() {
+        PrintService.throwIfNotCalledOnMainThread();
+        final int state = getInfo().getState();
+        if (state == PrintJobInfo.STATE_QUEUED
+                || state == PrintJobInfo.STATE_BLOCKED) {
+            return setState(PrintJobInfo.STATE_STARTED, null);
+        }
+        return false;
+    }
+
+    /**
+     * Blocks the print job. You should call this method if {@link
+     * #isStarted()} or {@link #isBlocked()} returns true and you need
+     * to block the print job. For example, the user has to add some
+     * paper to continue printing. To resume the print job call {@link
+     * #start()}.
+     *
+     * @return Whether the job was blocked.
+     *
+     * @see #isStarted()
+     * @see #isBlocked()
+     */
+    public boolean block(String reason) {
+        PrintService.throwIfNotCalledOnMainThread();
+        PrintJobInfo info = getInfo();
+        final int state = info.getState();
+        if (state == PrintJobInfo.STATE_STARTED
+                || (state == PrintJobInfo.STATE_BLOCKED
+                        && !TextUtils.equals(info.getStateReason(), reason))) {
+            return setState(PrintJobInfo.STATE_BLOCKED, reason);
+        }
+        return false;
+    }
+
+    /**
+     * Completes the print job. You should call this method if {@link
+     * #isStarted()} returns true and you are done printing.
+     *
+     * @return Whether the job as completed.
+     *
+     * @see #isStarted()
+     */
+    public boolean complete() {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (isStarted()) {
+            return setState(PrintJobInfo.STATE_COMPLETED, null);
+        }
+        return false;
+    }
+
+    /**
+     * Fails the print job. You should call this method if {@link
+     * #isQueued()} or {@link #isStarted()} or {@link #isBlocked()}
+     * returns true you failed while printing.
+     *
+     * @param error The human readable, short, and translated reason
+     * for the failure.
+     * @return Whether the job was failed.
+     *
+     * @see #isQueued()
+     * @see #isStarted()
+     * @see #isBlocked()
+     */
+    public boolean fail(String error) {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (!isInImmutableState()) {
+            return setState(PrintJobInfo.STATE_FAILED, error);
+        }
+        return false;
+    }
+
+    /**
+     * Cancels the print job. You should call this method if {@link
+     * #isQueued()} or {@link #isStarted() or #isBlocked()} returns
+     * true and you canceled the print job as a response to a call to
+     * {@link PrintService#onRequestCancelPrintJob(PrintJob)}.
+     *
+     * @return Whether the job is canceled.
+     *
+     * @see #isStarted()
+     * @see #isQueued()
+     * @see #isBlocked()
+     */
+    public boolean cancel() {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (!isInImmutableState()) {
+            return setState(PrintJobInfo.STATE_CANCELED, null);
+        }
+        return false;
+    }
+
+    /**
+     * Sets a tag that is valid in the context of a {@link PrintService}
+     * and is not interpreted by the system. For example, a print service
+     * may set as a tag the key of the print job returned by a remote
+     * print server, if the printing is off handed to a cloud based service.
+     *
+     * @param tag The tag.
+     * @return True if the tag was set, false otherwise.
+     */
+    public boolean setTag(String tag) {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (isInImmutableState()) {
+            return false;
+        }
+        try {
+            return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error setting tag for job: " + mCachedInfo.getId(), re);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrintJob other = (PrintJob) obj;
+        return (mCachedInfo.getId().equals(other.mCachedInfo.getId()));
+    }
+
+    @Override
+    public int hashCode() {
+        return mCachedInfo.getId().hashCode();
+    }
+
+    private boolean isInImmutableState() {
+        final int state = mCachedInfo.getState();
+        return state == PrintJobInfo.STATE_COMPLETED
+                || state == PrintJobInfo.STATE_CANCELED
+                || state == PrintJobInfo.STATE_FAILED;
+    }
+
+    private boolean setState(int state, String error) {
+        try {
+            if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state, error)) {
+                // Best effort - update the state of the cached info since
+                // we may not be able to re-fetch it later if the job gets
+                // removed from the spooler as a result of the state change.
+                mCachedInfo.setState(state);
+                mCachedInfo.setStateReason(error);
+                return true;
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error setting the state of job: " + mCachedInfo.getId(), re);
+        }
+        return false;
+    }
+}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
new file mode 100644
index 0000000..e73a53b
--- /dev/null
+++ b/core/java/android/printservice/PrintService.java
@@ -0,0 +1,507 @@
+/*
+ * 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 android.printservice;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+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.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>
+ * This is the base class for implementing print services. A print service knows
+ * how to discover and interact one or more printers via one or more protocols.
+ * </p>
+ * <h3>Printer discovery</h3>
+ * <p>
+ * A print service is responsible for discovering printers, adding discovered printers,
+ * removing added printers, and updating added printers. When the system is interested
+ * in printers managed by your service it will call {@link
+ * #onCreatePrinterDiscoverySession()} from which you must return a new {@link
+ * PrinterDiscoverySession} instance. The returned session encapsulates the interaction
+ * between the system and your service during printer discovery. For description of this
+ * interaction refer to the documentation for {@link PrinterDiscoverySession}.
+ * </p>
+ * <p>
+ * For every printer discovery session all printers have to be added since system does
+ * not retain printers across sessions. Hence, each printer known to this print service
+ * should be added only once during a discovery session. Only an already added printer
+ * can be removed or updated. Removed printers can be added again.
+ * </p>
+ * <h3>Print jobs</h3>
+ * <p>
+ * When a new print job targeted to a printer managed by this print service is is queued,
+ * i.e. ready for processing by the print service, you will receive a call to {@link
+ * #onPrintJobQueued(PrintJob)}. The print service may handle the print job immediately
+ * or schedule that for an appropriate time in the future. The list of all active print
+ * jobs for this service is obtained by calling {@link #getActivePrintJobs()}. Active
+ * print jobs are ones that are queued or started.
+ * </p>
+ * <p>
+ * A print service is responsible for setting a print job's state as appropriate
+ * while processing it. Initially, a print job is queued, i.e. {@link PrintJob#isQueued()
+ * PrintJob.isQueued()} returns true, which means that the document to be printed is
+ * spooled by the system and the print service can begin processing it. You can obtain
+ * the printed document by calling {@link PrintJob#getDocument() PrintJob.getDocument()}
+ * whose data is accessed via {@link PrintDocument#getData() PrintDocument.getData()}.
+ * After the print service starts printing the data it should set the print job's
+ * state to started by calling {@link PrintJob#start()} after which
+ * {@link PrintJob#isStarted() PrintJob.isStarted()} would return true. Upon successful
+ * completion, the print job should be marked as completed by calling {@link
+ * PrintJob#complete() PrintJob.complete()} after which {@link PrintJob#isCompleted()
+ * PrintJob.isCompleted()} would return true. In case of a failure, the print job should
+ * be marked as failed by calling {@link PrintJob#fail(String) PrintJob.fail(
+ * String)} after which {@link PrintJob#isFailed() PrintJob.isFailed()} would
+ * return true.
+ * </p>
+ * <p>
+ * If a print job is queued or started and the user requests to cancel it, the print
+ * service will receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which
+ * requests from the service to do best effort in canceling the job. In case the job
+ * is successfully canceled, its state has to be marked as cancelled by calling {@link
+ * PrintJob#cancel() PrintJob.cancel()} after which {@link PrintJob#isCancelled()
+ * PrintJob.isCacnelled()} would return true.
+ * </p>
+ * <h3>Lifecycle</h3>
+ * <p>
+ * The lifecycle of a print service is managed exclusively by the system and follows
+ * the established service lifecycle. Additionally, starting or stopping a print service
+ * is triggered exclusively by an explicit user action through enabling or disabling it
+ * in the device settings. After the system binds to a print service, it calls {@link
+ * #onConnected()}. This method can be overriden by clients to perform post binding setup.
+ * Also after the system unbinds from a print service, it calls {@link #onDisconnected()}.
+ * This method can be overriden by clients to perform post unbinding cleanup. Your should
+ * not do any work after the system disconnected from your print service since the
+ * service can be killed at any time to reclaim memory. The system will not disconnect
+ * from a print service if there are active print jobs for the printers managed by it.
+ * </p>
+ * <h3>Declaration</h3>
+ * <p>
+ * A print service is declared as any other service in an AndroidManifest.xml but it must
+ * also specify that it handles the {@link android.content.Intent} with action {@link
+ * #SERVICE_INTERFACE android.printservice.PrintService}. Failure to declare this intent
+ * will cause the system to ignore the print service. Additionally, a print service must
+ * request the {@link android.Manifest.permission#BIND_PRINT_SERVICE
+ * android.permission.BIND_PRINT_SERVICE} permission to ensure that only the system can
+ * bind to it. Failure to declare this intent will cause the system to ignore the print
+ * service. Following is an example declaration:
+ * </p>
+ * <pre>
+ * &lt;service android:name=".MyPrintService"
+ *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.printservice.PrintService" /&gt;
+ *     &lt;/intent-filter&gt;
+ *     . . .
+ * &lt;/service&gt;
+ * </pre>
+ * <h3>Configuration</h3>
+ * <p>
+ * A print service can be configured by specifying an optional settings activity which
+ * exposes service specific settings, an optional add printers activity which is used for
+ * manual addition of printers, vendor name ,etc. It is a responsibility of the system
+ * to launch the settings and add printers activities when appropriate.
+ * </p>
+ * <p>
+ * A print service is configured by providing a {@link #SERVICE_META_DATA meta-data}
+ * entry in the manifest when declaring the service. A service declaration with a meta-data
+ * tag is presented below:
+ * <pre> &lt;service android:name=".MyPrintService"
+ *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.printservice.PrintService" /&gt;
+ *     &lt;/intent-filter&gt;
+ *     &lt;meta-data android:name="android.printservice" android:resource="@xml/printservice" /&gt;
+ * &lt;/service&gt;</pre>
+ * </p>
+ * <p>
+ * For more details for how to configure your print service via the meta-data refer to
+ * {@link #SERVICE_META_DATA} and <code>&lt;{@link android.R.styleable#PrintService
+ * print-service}&gt;</code>.
+ * </p>
+ * <p>
+ * <strong>Note: </strong> All callbacks in this class are executed on the main
+ * application thread. You should also invoke any method of this class on the main
+ * application thread.
+ * </p>
+ */
+public abstract class PrintService extends Service {
+
+    private static final String LOG_TAG = "PrintService";
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * The {@link Intent} action that must be declared as handled by a service
+     * in its manifest for the system to recognize it as a print service.
+     */
+    public static final String SERVICE_INTERFACE = "android.printservice.PrintService";
+
+    /**
+     * Name under which a {@link PrintService} component publishes additional information
+     * about itself. This meta-data must reference a XML resource containing a <code>
+     * &lt;{@link android.R.styleable#PrintService print-service}&gt;</code> tag. This is
+     * a sample XML file configuring a print service:
+     * <pre> &lt;print-service
+     *     android:vendor="SomeVendor"
+     *     android:settingsActivity="foo.bar.MySettingsActivity"
+     *     andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
+     *     . . .
+     * /&gt;</pre>
+     * <p>
+     * For detailed configuration options that can be specified via the meta-data
+     * refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
+     * </p>
+     * <p>
+     * If you declare a settings or add a printers activity, they have to be exported,
+     * by setting the {@link android.R.attr#exported} activity attribute to <code>true
+     * </code>. Also in case you want only the system to be able to start any of these
+     * activities you can specify that they request the android.permission
+     * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
+     * {@link android.R.attr#permission} activity attribute.
+     * </p>
+     */
+    public static final String SERVICE_META_DATA = "android.printservice";
+
+    private Handler mHandler;
+
+    private IPrintServiceClient mClient;
+
+    private int mLastSessionId = -1;
+
+    private PrinterDiscoverySession mDiscoverySession;
+
+    @Override
+    protected final void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new ServiceHandler(base.getMainLooper());
+    }
+
+    /**
+     * The system has connected to this service.
+     */
+    protected void onConnected() {
+        /* do nothing */
+    }
+
+    /**
+     * The system has disconnected from this service.
+     */
+    protected void onDisconnected() {
+        /* do nothing */
+    }
+
+    /**
+     * Callback asking you to create a new {@link PrinterDiscoverySession}.
+     *
+     * @see PrinterDiscoverySession
+     */
+    protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
+
+    /**
+     * Called when cancellation of a print job is requested. The service
+     * should do best effort to fulfill the request. After the cancellation
+     * is performed, the print job should be marked as cancelled state by
+     * calling {@link PrintJob#cancel()}.
+     *
+     * @param printJob The print job to cancel.
+     *
+     * @see PrintJob#cancel() PrintJob.cancel()
+     * @see PrintJob#isCancelled() PrintJob.isCancelled()
+     */
+    protected abstract void onRequestCancelPrintJob(PrintJob printJob);
+
+    /**
+     * Called when there is a queued print job for one of the printers
+     * managed by this print service.
+     *
+     * @param printJob The new queued print job.
+     *
+     * @see PrintJob#isQueued() PrintJob.isQueued()
+     * @see #getActivePrintJobs()
+     */
+    protected abstract void onPrintJobQueued(PrintJob printJob);
+
+    /**
+     * Gets the active print jobs for the printers managed by this service.
+     * Active print jobs are ones that are not in a final state, i.e. whose
+     * state is queued or started.
+     *
+     * @return The active print jobs.
+     *
+     * @see PrintJob#isQueued() PrintJob.isQueued()
+     * @see PrintJob#isStarted() PrintJob.isStarted()
+     */
+    public final List<PrintJob> getActivePrintJobs() {
+        throwIfNotCalledOnMainThread();
+        if (mClient == null) {
+            return Collections.emptyList();
+        }
+        try {
+            List<PrintJob> printJobs = null;
+            List<PrintJobInfo> printJobInfos = mClient.getPrintJobInfos();
+            if (printJobInfos != null) {
+                final int printJobInfoCount = printJobInfos.size();
+                printJobs = new ArrayList<PrintJob>(printJobInfoCount);
+                for (int i = 0; i < printJobInfoCount; i++) {
+                    printJobs.add(new PrintJob(printJobInfos.get(i), mClient));
+                }
+            }
+            if (printJobs != null) {
+                return printJobs;
+            }
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Generates a global printer id given the printer's locally unique one.
+     *
+     * @param localId A locally unique id in the context of your print service.
+     * @return Global printer id.
+     */
+    public final PrinterId generatePrinterId(String localId) {
+        throwIfNotCalledOnMainThread();
+        return new PrinterId(new ComponentName(getPackageName(),
+                getClass().getName()), localId);
+    }
+
+    static void throwIfNotCalledOnMainThread() {
+        if (!Looper.getMainLooper().isCurrentThread()) {
+            throw new IllegalAccessError("must be called from the main thread");
+        }
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return new IPrintService.Stub() {
+            @Override
+            public void createPrinterDiscoverySession() {
+                mHandler.sendEmptyMessage(ServiceHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
+            }
+
+            @Override
+            public void destroyPrinterDiscoverySession() {
+                mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
+            }
+
+            public void startPrinterDiscovery(List<PrinterId> priorityList) {
+                mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
+                        priorityList).sendToTarget();
+            }
+
+            @Override
+            public void stopPrinterDiscovery() {
+                mHandler.sendEmptyMessage(ServiceHandler.MSG_STOP_PRINTER_DISCOVERY);
+            }
+
+            @Override
+            public void validatePrinters(List<PrinterId> printerIds) {
+                mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
+                        printerIds).sendToTarget();
+            }
+
+            @Override
+            public void startPrinterStateTracking(PrinterId printerId) {
+                mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
+                        printerId).sendToTarget();
+            }
+
+            @Override
+            public void stopPrinterStateTracking(PrinterId printerId) {
+                mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
+                        printerId).sendToTarget();
+            }
+
+            @Override
+            public void setClient(IPrintServiceClient client) {
+                mHandler.obtainMessage(ServiceHandler.MSG_SET_CLEINT, client)
+                        .sendToTarget();
+            }
+
+            @Override
+            public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
+                mHandler.obtainMessage(ServiceHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB,
+                        printJobInfo).sendToTarget();
+            }
+
+            @Override
+            public void onPrintJobQueued(PrintJobInfo printJobInfo) {
+                mHandler.obtainMessage(ServiceHandler.MSG_ON_PRINTJOB_QUEUED,
+                        printJobInfo).sendToTarget();
+            }
+        };
+    }
+
+    private final class ServiceHandler extends Handler {
+        public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
+        public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
+        public static final int MSG_START_PRINTER_DISCOVERY = 3;
+        public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
+        public static final int MSG_VALIDATE_PRINTERS = 5;
+        public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
+        public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
+        public static final int MSG_ON_PRINTJOB_QUEUED = 8;
+        public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
+        public static final int MSG_SET_CLEINT = 10;
+
+        public ServiceHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void handleMessage(Message message) {
+            final int action = message.what;
+            switch (action) {
+                case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_CREATE_PRINTER_DISCOVERY_SESSION "
+                                + getPackageName());
+                    }
+                    PrinterDiscoverySession session = onCreatePrinterDiscoverySession();
+                    if (session == null) {
+                        throw new NullPointerException("session cannot be null");
+                    }
+                    if (session.getId() == mLastSessionId) {
+                        throw new IllegalStateException("cannot reuse session instances");
+                    }
+                    mDiscoverySession = session;
+                    mLastSessionId = session.getId();
+                    session.setObserver(mClient);
+                } break;
+
+                case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_DESTROY_PRINTER_DISCOVERY_SESSION "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        mDiscoverySession.destroy();
+                        mDiscoverySession = null;
+                    }
+                } break;
+
+                case MSG_START_PRINTER_DISCOVERY: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_START_PRINTER_DISCOVERY "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
+                        mDiscoverySession.startPrinterDiscovery(priorityList);
+                    }
+                } break;
+
+                case MSG_STOP_PRINTER_DISCOVERY: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_STOP_PRINTER_DISCOVERY "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        mDiscoverySession.stopPrinterDiscovery();
+                    }
+                } break;
+
+                case MSG_VALIDATE_PRINTERS: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_VALIDATE_PRINTERS "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+                        mDiscoverySession.validatePrinters(printerIds);
+                    }
+                } break;
+
+                case MSG_START_PRINTER_STATE_TRACKING: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_START_PRINTER_STATE_TRACKING "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        PrinterId printerId = (PrinterId) message.obj;
+                        mDiscoverySession.startPrinterStateTracking(printerId);
+                    }
+                } break;
+
+                case MSG_STOP_PRINTER_STATE_TRACKING: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        PrinterId printerId = (PrinterId) message.obj;
+                        mDiscoverySession.stopPrinterStateTracking(printerId);
+                    }
+                } break;
+
+                case MSG_ON_REQUEST_CANCEL_PRINTJOB: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_ON_REQUEST_CANCEL_PRINTJOB "
+                                + getPackageName());
+                    }
+                    PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
+                    onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
+                } break;
+
+                case MSG_ON_PRINTJOB_QUEUED: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_ON_PRINTJOB_QUEUED "
+                                + getPackageName());
+                    }
+                    PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Queued: " + printJobInfo);
+                    }
+                    onPrintJobQueued(new PrintJob(printJobInfo, mClient));
+                } break;
+
+                case MSG_SET_CLEINT: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_SET_CLEINT "
+                                + getPackageName());
+                    }
+                    mClient = (IPrintServiceClient) message.obj;
+                    if (mClient != null) {
+                        onConnected();
+                     } else {
+                        onDisconnected();
+                     }
+                } break;
+
+                default: {
+                    throw new IllegalArgumentException("Unknown message: " + action);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/printservice/PrintServiceInfo.aidl b/core/java/android/printservice/PrintServiceInfo.aidl
new file mode 100644
index 0000000..95b67f2
--- /dev/null
+++ b/core/java/android/printservice/PrintServiceInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.printservice;
+
+parcelable PrintServiceInfo;
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
new file mode 100644
index 0000000..8e9636c
--- /dev/null
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -0,0 +1,260 @@
+/*
+ * 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 android.printservice;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * This class describes a {@link PrintService}. A print service knows
+ * how to communicate with one or more printers over one or more protocols
+ * and exposes printers for use by the applications via the platform print
+ * APIs.
+ *
+ * @see PrintService
+ * @see android.print.PrintManager
+ *
+ * @hide
+ */
+public final class PrintServiceInfo implements Parcelable {
+
+    private static final String LOG_TAG = PrintServiceInfo.class.getSimpleName();
+
+    private static final String TAG_PRINT_SERVICE = "print-service";
+
+    private final String mId;
+
+    private final ResolveInfo mResolveInfo;
+
+    private final String mSettingsActivityName;
+
+    private final String mAddPrintersActivityName;
+
+    /**
+     * Creates a new instance.
+     *
+     * @hide
+     */
+    public PrintServiceInfo(Parcel parcel) {
+        mId = parcel.readString();
+        mResolveInfo = parcel.readParcelable(null);
+        mSettingsActivityName = parcel.readString();
+        mAddPrintersActivityName = parcel.readString();
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param resolveInfo The service resolve info.
+     * @param settingsActivityName Optional settings activity name.
+     * @param addPrintersActivityName Optional add printers activity name.
+     */
+    public PrintServiceInfo(ResolveInfo resolveInfo, String settingsActivityName,
+            String addPrintersActivityName) {
+        mId = new ComponentName(resolveInfo.serviceInfo.packageName,
+                resolveInfo.serviceInfo.name).flattenToString();
+        mResolveInfo = resolveInfo;
+        mSettingsActivityName = settingsActivityName;
+        mAddPrintersActivityName = addPrintersActivityName;
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param resolveInfo The service resolve info.
+     * @param context Context for accessing resources.
+     * @throws XmlPullParserException If a XML parsing error occurs.
+     * @throws IOException If a I/O error occurs.
+     */
+    public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
+        String settingsActivityName = null;
+        String addPrintersActivityName = null;
+
+        XmlResourceParser parser = null;
+        PackageManager packageManager = context.getPackageManager();
+        parser = resolveInfo.serviceInfo.loadXmlMetaData(packageManager,
+                PrintService.SERVICE_META_DATA);
+        if (parser != null) {
+            try {
+                int type = 0;
+                while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
+                    type = parser.next();
+                }
+
+                String nodeName = parser.getName();
+                if (!TAG_PRINT_SERVICE.equals(nodeName)) {
+                    Log.e(LOG_TAG, "Ignoring meta-data that does not start with "
+                            + TAG_PRINT_SERVICE + " tag");
+                } else {
+                    Resources resources = packageManager.getResourcesForApplication(
+                            resolveInfo.serviceInfo.applicationInfo);
+                    AttributeSet allAttributes = Xml.asAttributeSet(parser);
+                    TypedArray attributes = resources.obtainAttributes(allAttributes,
+                            com.android.internal.R.styleable.PrintService);
+
+                    settingsActivityName = attributes.getString(
+                            com.android.internal.R.styleable.PrintService_settingsActivity);
+
+                    addPrintersActivityName = attributes.getString(
+                            com.android.internal.R.styleable.PrintService_addPrintersActivity);
+
+                    attributes.recycle();
+                }
+            } catch (IOException ioe) {
+                Log.w(LOG_TAG, "Error reading meta-data:" + ioe);
+            } catch (XmlPullParserException xppe) {
+                Log.w(LOG_TAG, "Error reading meta-data:" + xppe);
+            } catch (NameNotFoundException e) {
+                Log.e(LOG_TAG, "Unable to load resources for: "
+                        + resolveInfo.serviceInfo.packageName);
+            } finally {
+                if (parser != null) {
+                    parser.close();
+                }
+            }
+        }
+
+        return new PrintServiceInfo(resolveInfo, settingsActivityName, addPrintersActivityName);
+    }
+
+    /**
+     * The accessibility service id.
+     * <p>
+     * <strong>Generated by the system.</strong>
+     * </p>
+     *
+     * @return The id.
+     */
+    public String getId() {
+        return mId;
+    }
+
+    /**
+     * The service {@link ResolveInfo}.
+     *
+     * @return The info.
+     */
+    public ResolveInfo getResolveInfo() {
+        return mResolveInfo;
+    }
+
+    /**
+     * The settings activity name.
+     * <p>
+     * <strong>Statically set from
+     * {@link PrintService#SERVICE_META_DATA meta-data}.</strong>
+     * </p>
+     *
+     * @return The settings activity name.
+     */
+    public String getSettingsActivityName() {
+        return mSettingsActivityName;
+    }
+
+    /**
+     * The add printers activity name.
+     * <p>
+     * <strong>Statically set from
+     * {@link PrintService#SERVICE_META_DATA meta-data}.</strong>
+     * </p>
+     *
+     * @return The add printers activity name.
+     */
+    public String getAddPrintersActivityName() {
+        return mAddPrintersActivityName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel parcel, int flagz) {
+        parcel.writeString(mId);
+        parcel.writeParcelable(mResolveInfo, 0);
+        parcel.writeString(mSettingsActivityName);
+        parcel.writeString(mAddPrintersActivityName);
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 + ((mId == null) ? 0 : mId.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PrintServiceInfo other = (PrintServiceInfo) obj;
+        if (mId == null) {
+            if (other.mId != null) {
+                return false;
+            }
+        } else if (!mId.equals(other.mId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrintServiceInfo{");
+        builder.append("id=").append(mId);
+        builder.append(", resolveInfo=").append(mResolveInfo);
+        builder.append(", settingsActivityName=").append(mSettingsActivityName);
+        builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
+        builder.append("}");
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<PrintServiceInfo> CREATOR =
+            new Parcelable.Creator<PrintServiceInfo>() {
+        public PrintServiceInfo createFromParcel(Parcel parcel) {
+            return new PrintServiceInfo(parcel);
+        }
+
+        public PrintServiceInfo[] newArray(int size) {
+            return new PrintServiceInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
new file mode 100644
index 0000000..17cb68f
--- /dev/null
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -0,0 +1,528 @@
+/*
+ * 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 android.printservice;
+
+import android.content.pm.ParceledListSlice;
+import android.os.RemoteException;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class encapsulates the interaction between a print service and the
+ * system during printer discovery. During printer discovery you are responsible
+ * for adding discovered printers, removing previously added printers that
+ * disappeared, and updating already added printers.
+ * <p>
+ * During the lifetime of this session you may be asked to start and stop
+ * performing printer discovery multiple times. You will receive a call to {@link
+ * PrinterDiscoverySession#onStartPrinterDiscovery(List)} to start printer
+ * discovery and a call to {@link PrinterDiscoverySession#onStopPrinterDiscovery()}
+ * to stop printer discovery. When the system is no longer interested in printers
+ * discovered by this session you will receive a call to {@link #onDestroy()} at
+ * which point the system will no longer call into the session and all the session
+ * methods will do nothing.
+ * </p>
+ * <p>
+ * Discovered printers are added by invoking {@link
+ * PrinterDiscoverySession#addPrinters(List)}. Added printers that disappeared are
+ * removed by invoking {@link PrinterDiscoverySession#removePrinters(List)}. Added
+ * printers whose properties or capabilities changed are updated through a call to
+ * {@link PrinterDiscoverySession#addPrinters(List)}. The printers added in this
+ * session can be acquired via {@link #getPrinters()} where the returned printers
+ * will be an up-to-date snapshot of the printers that you reported during the
+ * session. Printers are <strong>not</strong> persisted across sessions.
+ * </p>
+ * <p>
+ * The system will make a call to {@link #onValidatePrinters(List)} if you
+ * need to update some printers. It is possible that you add a printer without
+ * specifying its capabilities. This enables you to avoid querying all discovered
+ * printers for their capabilities, rather querying the capabilities of a printer
+ * only if necessary. For example, the system will request that you update a printer
+ * if it gets selected by the user. When validating printers you do not need to
+ * provide the printers' capabilities but may do so.
+ * </p>
+ * <p>
+ * If the system is interested in being constantly updated for the state of a
+ * printer you will receive a call to {@link #onStartPrinterStateTracking(PrinterId)}
+ * after which you will have to do a best effort to keep the system updated for
+ * changes in the printer state and capabilities. You also <strong>must</strong>
+ * update the printer capabilities if you did not provide them when adding it, or
+ * the printer will be ignored. When the system is no longer interested in getting
+ * updates for a printer you will receive a call to {@link #onStopPrinterStateTracking(
+ * PrinterId)}.
+ * </p>
+ * <p>
+ * <strong>Note: </strong> All callbacks in this class are executed on the main
+ * application thread. You also have to invoke any method of this class on the main
+ * application thread.
+ * </p>
+ */
+public abstract class PrinterDiscoverySession {
+    private static final String LOG_TAG = "PrinterDiscoverySession";
+
+    private static int sIdCounter = 0;
+
+    private final int mId;
+
+    private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
+            new ArrayMap<PrinterId, PrinterInfo>();
+
+    private final List<PrinterId> mTrackedPrinters =
+            new ArrayList<PrinterId>();
+
+    private ArrayMap<PrinterId, PrinterInfo> mLastSentPrinters;
+
+    private IPrintServiceClient mObserver;
+
+    private boolean mIsDestroyed;
+
+    private boolean mIsDiscoveryStarted;
+
+    /**
+     * Constructor.
+     */
+    public PrinterDiscoverySession() {
+        mId = sIdCounter++;
+    }
+
+    void setObserver(IPrintServiceClient observer) {
+        mObserver = observer;
+        // If some printers were added in the method that
+        // created the session, send them over.
+        if (!mPrinters.isEmpty()) {
+            try {
+                mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(getPrinters()));
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending added printers", re);
+            }
+        }
+    }
+
+    int getId() {
+        return mId;
+    }
+
+    /**
+     * Gets the printers reported in this session. For example, if you add two
+     * printers and remove one of them, the returned list will contain only
+     * the printer that was added but not removed.
+     * <p>
+     * <strong>Note: </strong> Calls to this method after the session is
+     * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
+     * </p>
+     *
+     * @return The printers.
+     *
+     * @see #addPrinters(List)
+     * @see #removePrinters(List)
+     * @see #isDestroyed()
+     */
+    public final List<PrinterInfo> getPrinters() {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (mIsDestroyed) {
+            return Collections.emptyList();
+        }
+        return new ArrayList<PrinterInfo>(mPrinters.values());
+    }
+
+    /**
+     * Adds discovered printers. Adding an already added printer updates it.
+     * Removed printers can be added again. You can call this method multiple
+     * times during the life of this session. Duplicates will be ignored.
+     * <p>
+     * <strong>Note: </strong> Calls to this method after the session is
+     * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
+     * </p>
+     *
+     * @param printers The printers to add.
+     *
+     * @see #removePrinters(List)
+     * @see #getPrinters()
+     * @see #isDestroyed()
+     */
+    public final void addPrinters(List<PrinterInfo> printers) {
+        PrintService.throwIfNotCalledOnMainThread();
+
+        // If the session is destroyed - nothing do to.
+        if (mIsDestroyed) {
+            Log.w(LOG_TAG, "Not adding printers - session destroyed.");
+            return;
+        }
+
+        if (mIsDiscoveryStarted) {
+            // If during discovery, add the new printers and send them.
+            List<PrinterInfo> addedPrinters = null;
+            final int addedPrinterCount = printers.size();
+            for (int i = 0; i < addedPrinterCount; i++) {
+                PrinterInfo addedPrinter = printers.get(i);
+                PrinterInfo oldPrinter = mPrinters.put(addedPrinter.getId(), addedPrinter);
+                if (oldPrinter == null || !oldPrinter.equals(addedPrinter)) {
+                    if (addedPrinters == null) {
+                        addedPrinters = new ArrayList<PrinterInfo>();
+                    }
+                    addedPrinters.add(addedPrinter);
+                }
+            }
+
+            // Send the added printers, if such.
+            if (addedPrinters != null) {
+                try {
+                    mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+                } catch (RemoteException re) {
+                    Log.e(LOG_TAG, "Error sending added printers", re);
+                }
+            }
+        } else {
+            // Remember the last sent printers if needed.
+            if (mLastSentPrinters == null) {
+                mLastSentPrinters = new ArrayMap<PrinterId, PrinterInfo>(mPrinters);
+            }
+
+            // Update the printers.
+            final int addedPrinterCount = printers.size();
+            for (int i = 0; i < addedPrinterCount; i++) {
+                PrinterInfo addedPrinter = printers.get(i);
+                if (mPrinters.get(addedPrinter.getId()) == null) {
+                    mPrinters.put(addedPrinter.getId(), addedPrinter);
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes added printers. Removing an already removed or never added
+     * printer has no effect. Removed printers can be added again. You can
+     * call this method multiple times during the lifetime of this session.
+     * <p>
+     * <strong>Note: </strong> Calls to this method after the session is
+     * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
+     * </p>
+     *
+     * @param printerIds The ids of the removed printers.
+     *
+     * @see #addPrinters(List)
+     * @see #getPrinters()
+     * @see #isDestroyed()
+     */
+    public final void removePrinters(List<PrinterId> printerIds) {
+        PrintService.throwIfNotCalledOnMainThread();
+
+        // If the session is destroyed - nothing do to.
+        if (mIsDestroyed) {
+            Log.w(LOG_TAG, "Not removing printers - session destroyed.");
+            return;
+        }
+
+        if (mIsDiscoveryStarted) {
+            // If during discovery, remove existing printers and send them.
+            List<PrinterId> removedPrinterIds = new ArrayList<PrinterId>();
+            final int removedPrinterIdCount = printerIds.size();
+            for (int i = 0; i < removedPrinterIdCount; i++) {
+                PrinterId removedPrinterId = printerIds.get(i);
+                if (mPrinters.remove(removedPrinterId) != null) {
+                    removedPrinterIds.add(removedPrinterId);
+                }
+            }
+
+            // Send the removed printers, if such.
+            if (!removedPrinterIds.isEmpty()) {
+                try {
+                    mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(
+                            removedPrinterIds));
+                } catch (RemoteException re) {
+                    Log.e(LOG_TAG, "Error sending removed printers", re);
+                }
+            }
+        } else {
+            // Remember the last sent printers if needed.
+            if (mLastSentPrinters == null) {
+                mLastSentPrinters = new ArrayMap<PrinterId, PrinterInfo>(mPrinters);
+            }
+
+            // Update the printers.
+            final int removedPrinterIdCount = printerIds.size();
+            for (int i = 0; i < removedPrinterIdCount; i++) {
+                PrinterId removedPrinterId = printerIds.get(i);
+                mPrinters.remove(removedPrinterId);
+            }
+        }
+    }
+
+    private void sendOutOfDiscoveryPeriodPrinterChanges() {
+        // Noting changed since the last discovery period - nothing to do.
+        if (mLastSentPrinters == null || mLastSentPrinters.isEmpty()) {
+            mLastSentPrinters = null;
+            return;
+        }
+
+        // Determine the added printers.
+        List<PrinterInfo> addedPrinters = null;
+        for (PrinterInfo printer : mPrinters.values()) {
+            PrinterInfo sentPrinter = mLastSentPrinters.get(printer.getId());
+            if (sentPrinter == null || !sentPrinter.equals(printer)) {
+                if (addedPrinters == null) {
+                    addedPrinters = new ArrayList<PrinterInfo>();
+                }
+                addedPrinters.add(printer);
+            }
+        }
+
+        // Send the added printers, if such.
+        if (addedPrinters != null) {
+            try {
+                mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending added printers", re);
+            }
+        }
+
+        // Determine the removed printers.
+        List<PrinterId> removedPrinterIds = null;
+        for (PrinterInfo sentPrinter : mLastSentPrinters.values()) {
+            if (!mPrinters.containsKey(sentPrinter.getId())) {
+                if (removedPrinterIds == null) {
+                    removedPrinterIds = new ArrayList<PrinterId>();
+                }
+                removedPrinterIds.add(sentPrinter.getId());
+            }
+        }
+
+        // Send the removed printers, if such.
+        if (removedPrinterIds != null) {
+            try {
+                mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(removedPrinterIds));
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending removed printers", re);
+            }
+        }
+
+        mLastSentPrinters = null;
+    }
+
+    /**
+     * Callback asking you to start printer discovery. Discovered printers should be
+     * added via calling {@link #addPrinters(List)}. Added printers that disappeared
+     * should be removed via calling {@link #removePrinters(List)}. Added printers
+     * whose properties or capabilities changed should be updated via calling {@link
+     * #addPrinters(List)}. You will receive a call to {@link #onStopPrinterDiscovery()}
+     * when you should stop printer discovery.
+     * <p>
+     * During the lifetime of this session all printers that are known to your print
+     * service have to be added. The system does not retain any printers across sessions.
+     * However, if you were asked to start and then stop performing printer discovery
+     * in this session, then a subsequent discovering should not re-discover already
+     * discovered printers. You can get the printers reported during this session by
+     * calling {@link #getPrinters()}.
+     * </p>
+     * <p>
+     * <strong>Note: </strong>You are also given a list of printers whose availability
+     * has to be checked first. For example, these printers could be the user's favorite
+     * ones, therefore they have to be verified first. You do <strong>not need</strong>
+     * to provide the capabilities of the printers, rather verify whether they exist
+     * similarly to {@link #onValidatePrinters(List)}.
+     * </p>
+     *
+     * @param priorityList The list of printers to validate first. Never null.
+     *
+     * @see #onStopPrinterDiscovery()
+     * @see #addPrinters(List)
+     * @see #removePrinters(List)
+     * @see #isPrinterDiscoveryStarted()
+     */
+    public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+
+    /**
+     * Callback notifying you that you should stop printer discovery.
+     *
+     * @see #onStartPrinterDiscovery(List)
+     * @see #isPrinterDiscoveryStarted()
+     */
+    public abstract void onStopPrinterDiscovery();
+
+    /**
+     * Callback asking you to validate that the given printers are valid, that
+     * is they exist. You are responsible for checking whether these printers
+     * exist and for the ones that do exist notify the system via calling
+     * {@link #addPrinters(List)}.
+     * <p>
+     * <strong>Note: </strong> You are <strong>not required</strong> to provide
+     * the printer capabilities when updating the printers that do exist.
+     * <p>
+     *
+     * @param printerIds The printers to validate.
+     *
+     * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+     *      PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
+     */
+    public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+    /**
+     * Callback asking you to start tracking the state of a printer. Tracking
+     * the state means that you should do a best effort to observe the state
+     * of this printer and notify the system if that state changes via calling
+     * {@link #addPrinters(List)}.
+     * <p>
+     * <strong>Note: </strong> A printer can be initially added without its
+     * capabilities to avoid polling printers that the user will not select.
+     * However, after this method is called you are expected to update the
+     * printer <strong>including</strong> its capabilities. Otherwise, the
+     * printer will be ignored.
+     * <p>
+     * <p>
+     * A scenario when you may be requested to track a printer's state is if
+     * the user selects that printer and the system has to present print
+     * options UI based on the printer's capabilities. In this case the user
+     * should be promptly informed if, for example, the printer becomes
+     * unavailable.
+     * </p>
+     *
+     * @param printerId The printer to start tracking.
+     *
+     * @see #onStopPrinterStateTracking(PrinterId)
+     * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+     *      PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
+     */
+    public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+    /**
+     * Callback asking you to stop tracking the state of a printer. The passed
+     * in printer id is the one for which you received a call to {@link
+     * #onStartPrinterStateTracking(PrinterId)}.
+     *
+     * @param printerId The printer to stop tracking.
+     *
+     * @see #onStartPrinterStateTracking(PrinterId)
+     */
+    public abstract void onStopPrinterStateTracking(PrinterId printerId);
+
+    /**
+     * Gets the printers that should be tracked. These are printers that are
+     * important to the user and for which you received a call to {@link
+     * #onStartPrinterStateTracking(PrinterId)} asking you to observer their
+     * state and reporting it to the system via {@link #addPrinters(List)}.
+     * You will receive a call to {@link #onStopPrinterStateTracking(PrinterId)}
+     * if you should stop tracking a printer.
+     * <p>
+     * <strong>Note: </strong> Calls to this method after the session is
+     * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
+     * </p>
+     *
+     * @return The printers.
+     *
+     * @see #onStartPrinterStateTracking(PrinterId)
+     * @see #onStopPrinterStateTracking(PrinterId)
+     * @see #isDestroyed()
+     */
+    public final List<PrinterId> getTrackedPrinters() {
+        PrintService.throwIfNotCalledOnMainThread();
+        if (mIsDestroyed) {
+            return Collections.emptyList();
+        }
+        return new ArrayList<PrinterId>(mTrackedPrinters);
+    }
+
+    /**
+     * Notifies you that the session is destroyed. After this callback is invoked
+     * any calls to the methods of this class will be ignored, {@link #isDestroyed()}
+     * will return true and you will also no longer receive callbacks.
+     *
+     * @see #isDestroyed()
+     */
+    public abstract void onDestroy();
+
+    /**
+     * Gets whether the session is destroyed.
+     *
+     * @return Whether the session is destroyed.
+     *
+     * @see #onDestroy()
+     */
+    public final boolean isDestroyed() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return mIsDestroyed;
+    }
+
+    /**
+     * Gets whether printer discovery is started.
+     *
+     * @return Whether printer discovery is destroyed.
+     *
+     * @see #onStartPrinterDiscovery(List)
+     * @see #onStopPrinterDiscovery()
+     */
+    public final boolean isPrinterDiscoveryStarted() {
+        PrintService.throwIfNotCalledOnMainThread();
+        return mIsDiscoveryStarted;
+    }
+
+    void startPrinterDiscovery(List<PrinterId> priorityList) {
+        if (!mIsDestroyed) {
+            mIsDiscoveryStarted = true;
+            sendOutOfDiscoveryPeriodPrinterChanges();
+            if (priorityList == null) {
+                priorityList = Collections.emptyList();
+            }
+            onStartPrinterDiscovery(priorityList);
+        }
+    }
+
+    void stopPrinterDiscovery() {
+        if (!mIsDestroyed) {
+            mIsDiscoveryStarted = false;
+            onStopPrinterDiscovery();
+        }
+    }
+
+    void validatePrinters(List<PrinterId> printerIds) {
+        if (!mIsDestroyed && mObserver != null) {
+            onValidatePrinters(printerIds);
+        }
+    }
+
+    void startPrinterStateTracking(PrinterId printerId) {
+        if (!mIsDestroyed && mObserver != null
+                && !mTrackedPrinters.contains(printerId)) {
+            mTrackedPrinters.add(printerId);
+            onStartPrinterStateTracking(printerId);
+        }
+    }
+
+    void stopPrinterStateTracking(PrinterId printerId) {
+        if (!mIsDestroyed && mObserver != null
+                && mTrackedPrinters.remove(printerId)) {
+            onStopPrinterStateTracking(printerId);
+        }
+    }
+
+    void destroy() {
+        if (!mIsDestroyed) {
+            mIsDestroyed = true;
+            mIsDiscoveryStarted = false;
+            mPrinters.clear();
+            mLastSentPrinters = null;
+            mObserver = null;
+            onDestroy();
+        }
+    }
+}
diff --git a/core/java/android/printservice/package.html b/core/java/android/printservice/package.html
new file mode 100644
index 0000000..2fb06bd
--- /dev/null
+++ b/core/java/android/printservice/package.html
@@ -0,0 +1,23 @@
+<HTML>
+<BODY>
+<p>
+Provides classes for implementing print services. Print services are plug-in components
+that know how to talk to printers via some standard protocols. These services serve as a
+bridge between the system and the printers. Hence, the printer and print protocol specific
+implementation is factored out of the system and can be independently developed and updated.
+</p>
+<p>
+A print service implementation should extend {@link android.printservice.PrintService}
+and implement its abstract methods. Also the print service has to follow the contract for
+managing {@link android.printservice.PrintJob}s.
+<p/>
+<p>
+The system is responsible for starting and stopping a print service depending on whether
+there are active print jobs for the printers managed by the service. The print service
+should also perform printer discovery in a timely fashion to ensure good user experience.
+The interaction between the system and the print service during printer discovery is
+encapsulated by a {@link android.printservice.PrinterDiscoverySession} instance created
+by the print service when requested by the system.
+</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java
index 3401cb1..724d76d 100644
--- a/core/java/android/provider/AlarmClock.java
+++ b/core/java/android/provider/AlarmClock.java
@@ -21,12 +21,12 @@
 
 /**
  * The AlarmClock provider contains an Intent action and extras that can be used
- * to start an Activity to set a new alarm in an alarm clock application.
+ * to start an Activity to set a new alarm or timer in an alarm clock application.
  *
- * Applications that wish to receive the ACTION_SET_ALARM Intent should create
- * an activity to handle the Intent that requires the permission
+ * Applications that wish to receive the ACTION_SET_ALARM  and ACTION_SET_TIMER Intents
+ * should create an activity to handle the Intent that requires the permission
  * com.android.alarm.permission.SET_ALARM.  Applications that wish to create a
- * new alarm should use
+ * new alarm or timer should use
  * {@link android.content.Context#startActivity Context.startActivity()} so that
  * the user has the option of choosing which alarm clock application to use.
  */
@@ -34,49 +34,203 @@
     /**
      * Activity Action: Set an alarm.
      * <p>
-     * Input: Nothing.
-     * <p>
-     * Output: Nothing.
+     * Activates an existing alarm or creates a new one.
+     * </p><p>
+     * This action requests an alarm to be set for a given time of day. If no time of day is
+     * specified, an implementation should start an activity that is capable of setting an alarm
+     * ({@link #EXTRA_SKIP_UI} is ignored in this case). If a time of day is specified, and
+     * {@link #EXTRA_SKIP_UI} is {@code true}, and the alarm is not repeating, the implementation
+     * should remove this alarm after it has been dismissed. If an identical alarm exists matching
+     * all parameters, the implementation may re-use it instead of creating a new one (in this case,
+     * the alarm should not be removed after dismissal).
+     *
+     * This action always enables the alarm.
+     * </p>
+     * <h3>Request parameters</h3>
+     * <ul>
+     * <li>{@link #EXTRA_HOUR} <em>(optional)</em>: The hour of the alarm being set.
+     * <li>{@link #EXTRA_MINUTES} <em>(optional)</em>: The minutes of the alarm being set.
+     * <li>{@link #EXTRA_DAYS} <em>(optional)</em>: Weekdays for repeating alarm.
+     * <li>{@link #EXTRA_MESSAGE} <em>(optional)</em>: A custom message for the alarm.
+     * <li>{@link #EXTRA_RINGTONE} <em>(optional)</em>: A ringtone to play with this alarm.
+     * <li>{@link #EXTRA_VIBRATE} <em>(optional)</em>: Whether or not to activate the device
+     * vibrator for this alarm.
+     * <li>{@link #EXTRA_SKIP_UI} <em>(optional)</em>: Whether or not to display an activity for
+     * setting this alarm.
+     * </ul>
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
 
     /**
-     * Activity Extra: Provide a custom message for the alarm.
+     * Activity Action: Set a timer.
      * <p>
-     * This can be passed as an extra field in the Intent created with
-     * ACTION_SET_ALARM.
+     * Activates an existing timer or creates a new one.
+     * </p><p>
+     * This action requests a timer to be started for a specific {@link #EXTRA_LENGTH length} of
+     * time. If no {@link #EXTRA_LENGTH length} is specified, the implementation should start an
+     * activity that is capable of setting a timer ({@link #EXTRA_SKIP_UI} is ignored in this case).
+     * If a {@link #EXTRA_LENGTH length} is specified, and {@link #EXTRA_SKIP_UI} is {@code true},
+     * the implementation should remove this timer after it has been dismissed. If an identical,
+     * unused timer exists matching both parameters, an implementation may re-use it instead of
+     * creating a new one (in this case, the timer should not be removed after dismissal).
+     *
+     * This action always starts the timer.
+     * </p>
+     *
+     * <h3>Request parameters</h3>
+     * <ul>
+     * <li>{@link #EXTRA_LENGTH} <em>(optional)</em>: The length of the timer being set.
+     * <li>{@link #EXTRA_MESSAGE} <em>(optional)</em>: A custom message for the timer.
+     * <li>{@link #EXTRA_SKIP_UI} <em>(optional)</em>: Whether or not to display an activity for
+     * setting this timer.
+     * </ul>
      */
-    public static final String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
 
     /**
-     * Activity Extra: The hour of the alarm being set.
+     * Activity Action: Show the alarms.
      * <p>
-     * This value can be passed as an extra field to the Intent created with
-     * ACTION_SET_ALARM.  If it is not provided, the behavior is undefined and
-     * is up to the application.  The value is an integer and ranges from 0 to
-     * 23.
+     * This action opens the alarms page.
+     * </p>
+     */
+     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+     public static final String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
+
+    /**
+     * Bundle extra: Weekdays for repeating alarm.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM}.
+     * </p><p>
+     * The value is an {@code ArrayList<Integer>}. Each item can be:
+     * </p>
+     * <ul>
+     * <li> {@link java.util.Calendar#SUNDAY},
+     * <li> {@link java.util.Calendar#MONDAY},
+     * <li> {@link java.util.Calendar#TUESDAY},
+     * <li> {@link java.util.Calendar#WEDNESDAY},
+     * <li> {@link java.util.Calendar#THURSDAY},
+     * <li> {@link java.util.Calendar#FRIDAY},
+     * <li> {@link java.util.Calendar#SATURDAY}
+     * </ul>
+     */
+    public static final String EXTRA_DAYS = "android.intent.extra.alarm.DAYS";
+
+    /**
+     * Bundle extra: The hour of the alarm.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM}.
+     * </p><p>
+     * This extra is optional. If not provided, an implementation should open an activity
+     * that allows a user to set an alarm with user provided time.
+     * </p><p>
+     * The value is an {@link Integer} and ranges from 0 to 23.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #EXTRA_MINUTES
+     * @see #EXTRA_DAYS
      */
     public static final String EXTRA_HOUR = "android.intent.extra.alarm.HOUR";
 
     /**
-     * Activity Extra: The minutes of the alarm being set.
+     * Bundle extra: The length of the timer in seconds.
      * <p>
-     * This value can be passed as an extra field to the Intent created with
-     * ACTION_SET_ALARM.  If it is not provided, the behavior is undefined and
-     * is up to the application.  The value is an integer and ranges from 0 to
-     * 59.
+     * Used by {@link #ACTION_SET_TIMER}.
+     * </p><p>
+     * This extra is optional. If not provided, an implementation should open an activity
+     * that allows a user to set a timer with user provided length.
+     * </p><p>
+     * The value is an {@link Integer} and ranges from 1 to 86400 (24 hours).
+     * </p>
+     *
+     * @see #ACTION_SET_TIMER
+     */
+    public static final String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH";
+
+    /**
+     * Bundle extra: A custom message for the alarm or timer.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM} and {@link #ACTION_SET_TIMER}.
+     * </p><p>
+     * The value is a {@link String}.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #ACTION_SET_TIMER
+     */
+    public static final String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
+
+    /**
+     * Bundle extra: The minutes of the alarm.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM}.
+     * </p><p>
+     * The value is an {@link Integer} and ranges from 0 to 59. If not provided, it defaults to 0.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #EXTRA_HOUR
+     * @see #EXTRA_DAYS
      */
     public static final String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES";
 
     /**
-     * Activity Extra: Optionally skip the application UI.
+     * Bundle extra: A ringtone to be played with this alarm.
      * <p>
-     * This value can be passed as an extra field to the Intent created with
-     * ACTION_SET_ALARM.  If true, the application is asked to bypass any
-     * intermediate UI and instead pop a toast indicating the result then
-     * finish the Activity.  If false, the application may display intermediate
-     * UI like a confirmation dialog or alarm settings.  The default is false.
+     * Used by {@link #ACTION_SET_ALARM}.
+     * </p><p>
+     * This value is a {@link String} and can either be set to {@link #VALUE_RINGTONE_SILENT} or
+     * to a content URI of the media to be played. If not specified or the URI doesn't exist,
+     * {@code "content://settings/system/alarm_alert} will be used.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #VALUE_RINGTONE_SILENT
+     * @see #EXTRA_VIBRATE
+     */
+    public static final String EXTRA_RINGTONE = "android.intent.extra.alarm.RINGTONE";
+
+    /**
+     * Bundle extra: Whether or not to display an activity after performing the action.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM} and {@link #ACTION_SET_TIMER}.
+     * </p><p>
+     * If true, the application is asked to bypass any intermediate UI. If false, the application
+     * may display intermediate UI like a confirmation dialog or settings.
+     * </p><p>
+     * The value is a {@link Boolean}. The default is {@code false}.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #ACTION_SET_TIMER
      */
     public static final String EXTRA_SKIP_UI = "android.intent.extra.alarm.SKIP_UI";
+
+    /**
+     * Bundle extra: Whether or not to activate the device vibrator.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM}.
+     * </p><p>
+     * The value is a {@link Boolean}. The default is {@code true}.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #EXTRA_RINGTONE
+     * @see #VALUE_RINGTONE_SILENT
+     */
+    public static final String EXTRA_VIBRATE = "android.intent.extra.alarm.VIBRATE";
+
+    /**
+     * Bundle extra value: Indicates no ringtone should be played.
+     * <p>
+     * Used by {@link #ACTION_SET_ALARM}, passed in through {@link #EXTRA_RINGTONE}.
+     * </p>
+     *
+     * @see #ACTION_SET_ALARM
+     * @see #EXTRA_RINGTONE
+     * @see #EXTRA_VIBRATE
+     */
+    public static final String VALUE_RINGTONE_SILENT = "silent";
 }
diff --git a/core/java/android/provider/Applications.java b/core/java/android/provider/Applications.java
deleted file mode 100644
index 7aabc50..0000000
--- a/core/java/android/provider/Applications.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.provider;
-
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
-
-import java.util.List;
-
-/**
- * The Applications provider gives information about installed applications.
- *
- * @hide Only used by ApplicationsProvider so far.
- */
-public class Applications {
-
-    /**
-     * The content authority for this provider.
-     */
-    public static final String AUTHORITY = "applications";
-
-    /**
-     * The content:// style URL for this provider
-     */
-    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
-
-    /**
-     * The content path for application component URIs.
-     */
-    public static final String APPLICATION_PATH = "applications";
-
-    /**
-     * The content path for application search.
-     */
-    public static final String SEARCH_PATH = "search";
-
-    private static final String APPLICATION_SUB_TYPE = "vnd.android.application";
-
-    /**
-     * The MIME type for a single application item.
-     */
-    public static final String APPLICATION_ITEM_TYPE =
-            ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + APPLICATION_SUB_TYPE;
-
-    /**
-     * The MIME type for a list of application items.
-     */
-    public static final String APPLICATION_DIR_TYPE =
-            ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + APPLICATION_SUB_TYPE;
-
-    /**
-     * no public constructor since this is a utility class
-     */
-    private Applications() {}
-
-    /**
-     * Gets a cursor with application search results.
-     * See {@link ApplicationColumns} for the columns available in the returned cursor.
-     */
-    public static Cursor search(ContentResolver resolver, String query) {
-        Uri searchUri = CONTENT_URI.buildUpon().appendPath(SEARCH_PATH).appendPath(query).build();
-        return resolver.query(searchUri, null, null, null, null);
-    }
-
-    /**
-     * Gets the application component name from an application URI.
-     *
-     * @param appUri A URI of the form
-     * "content://applications/applications/&lt;packageName&gt;/&lt;className&gt;".
-     * @return The component name for the application, or
-     * <code>null</code> if the given URI was <code>null</code>
-     * or malformed.
-     */
-    public static ComponentName uriToComponentName(Uri appUri) {
-        if (appUri == null) return null;
-        if (!ContentResolver.SCHEME_CONTENT.equals(appUri.getScheme())) return null;
-        if (!AUTHORITY.equals(appUri.getAuthority())) return null;
-        List<String> pathSegments = appUri.getPathSegments();
-        if (pathSegments.size() != 3) return null;
-        if (!APPLICATION_PATH.equals(pathSegments.get(0))) return null;
-        String packageName = pathSegments.get(1);
-        String name = pathSegments.get(2);
-        return new ComponentName(packageName, name);
-    }
-
-    /**
-     * Gets the URI for an application component.
-     *
-     * @param packageName The name of the application's package.
-     * @param className The class name of the application.
-     * @return A URI of the form
-     * "content://applications/applications/&lt;packageName&gt;/&lt;className&gt;".
-     */
-    public static Uri componentNameToUri(String packageName, String className) {
-        return Applications.CONTENT_URI.buildUpon()
-                .appendEncodedPath(APPLICATION_PATH)
-                .appendPath(packageName)
-                .appendPath(className)
-                .build();
-    }
-
-    /**
-     * The columns in application cursors, like those returned by
-     * {@link Applications#search(ContentResolver, String)}.
-     */
-    public interface ApplicationColumns extends BaseColumns {
-        public static final String NAME = "name";
-        public static final String ICON = "icon";
-        public static final String URI = "uri";
-    }
-}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 25af209..d743484 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -2393,7 +2393,7 @@
             intent.setData(ContentUris.withAppendedId(CalendarContract.CONTENT_URI, alarmTime));
             intent.putExtra(ALARM_TIME, alarmTime);
             PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
-            manager.set(AlarmManager.RTC_WAKEUP, alarmTime, pi);
+            manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pi);
         }
 
         /**
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 5dca67f..a6f23a8 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -137,6 +137,32 @@
         public static final String NUMBER = "number";
 
         /**
+         * The number presenting rules set by the network.
+         *
+         * <p>
+         * Allowed values:
+         * <ul>
+         * <li>{@link #PRESENTATION_ALLOWED}</li>
+         * <li>{@link #PRESENTATION_RESTRICTED}</li>
+         * <li>{@link #PRESENTATION_UNKNOWN}</li>
+         * <li>{@link #PRESENTATION_PAYPHONE}</li>
+         * </ul>
+         * </p>
+         *
+         * <P>Type: INTEGER</P>
+         */
+        public static final String NUMBER_PRESENTATION = "presentation";
+
+        /** Number is allowed to display for caller id. */
+        public static final int PRESENTATION_ALLOWED = 1;
+        /** Number is blocked by user. */
+        public static final int PRESENTATION_RESTRICTED = 2;
+        /** Number is not specified or unknown by network. */
+        public static final int PRESENTATION_UNKNOWN = 3;
+        /** Number is a pay phone. */
+        public static final int PRESENTATION_PAYPHONE = 4;
+
+        /**
          * The ISO 3166-1 two letters country code of the country where the
          * user received or made the call.
          * <P>
@@ -267,7 +293,8 @@
          * if the contact is unknown.
          * @param context the context used to get the ContentResolver
          * @param number the phone number to be added to the calls db
-         * @param presentation the number presenting rules set by the network for
+         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+         *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
          * @param callType enumerated values for "incoming", "outgoing", or "missed"
          * @param start time stamp for the call in milliseconds
@@ -278,24 +305,32 @@
         public static Uri addCall(CallerInfo ci, Context context, String number,
                 int presentation, int callType, long start, int duration) {
             final ContentResolver resolver = context.getContentResolver();
+            int numberPresentation = PRESENTATION_ALLOWED;
 
-            // If this is a private number then set the number to Private, otherwise check
-            // if the number field is empty and set the number to Unavailable
+            // Remap network specified number presentation types
+            // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
+            // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
+            // from any future radio changes.
+            // If the number field is empty set the presentation type to Unknown.
             if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
-                number = CallerInfo.PRIVATE_NUMBER;
-                if (ci != null) ci.name = "";
+                numberPresentation = PRESENTATION_RESTRICTED;
             } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
-                number = CallerInfo.PAYPHONE_NUMBER;
-                if (ci != null) ci.name = "";
+                numberPresentation = PRESENTATION_PAYPHONE;
             } else if (TextUtils.isEmpty(number)
                     || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
-                number = CallerInfo.UNKNOWN_NUMBER;
-                if (ci != null) ci.name = "";
+                numberPresentation = PRESENTATION_UNKNOWN;
+            }
+            if (numberPresentation != PRESENTATION_ALLOWED) {
+                number = "";
+                if (ci != null) {
+                    ci.name = "";
+                }
             }
 
-            ContentValues values = new ContentValues(5);
+            ContentValues values = new ContentValues(6);
 
             values.put(NUMBER, number);
+            values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
             values.put(TYPE, Integer.valueOf(callType));
             values.put(DATE, Long.valueOf(start));
             values.put(DURATION, Long.valueOf(duration));
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 220b997..b16df28 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -825,6 +825,14 @@
         public static final String STARRED = "starred";
 
         /**
+         * The position at which the contact is pinned. If {@link PinnedPositions.UNPINNED},
+         * the contact is not pinned. Also see {@link PinnedPositions}.
+         * <P>Type: INTEGER </P>
+         * @hide
+         */
+        public static final String PINNED = "pinned";
+
+        /**
          * URI for a custom ringtone associated with the contact. If null or missing,
          * the default ringtone is used.
          * <P>Type: TEXT (URI to the ringtone)</P>
@@ -5105,9 +5113,8 @@
          * Value of 1 implies true, 0 implies false when 0 is the default.
          * When a cursor is returned to the client, it should check for an extra with the name
          * {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
-         * should do its own snippeting using {@link ContactsContract#snippetize}. If
-         * it doesn't exist, the snippet column in the cursor should already contain a snippetized
-         * string.
+         * should do its own snippeting. If it doesn't exist, the snippet column in the cursor
+         * should already contain a snippetized string.
          *
          * @hide
          */
@@ -7715,6 +7722,138 @@
     }
 
     /**
+     * <p>
+     * API allowing applications to send pinning information for specified contacts to the
+     * Contacts Provider.
+     * </p>
+     *
+     * <p>
+     * This pinning information can be used by individual applications to customize how
+     * they order particular pinned contacts. For example, a Dialer application could
+     * use pinned information to order user-pinned contacts in a top row of favorites.
+     * </p>
+     *
+     * <p>
+     * It is possible for two or more contacts to occupy the same pinned position (due
+     * to aggregation and sync), so this pinning information should be used on a best-effort
+     * basis to order contacts in-application rather than an absolute guide on where a contact
+     * should be positioned. Contacts returned by the ContactsProvider will not be ordered based
+     * on this information, so it is up to the client application to reorder these contacts within
+     * their own UI adhering to (or ignoring as appropriate) information stored in the pinned
+     * column.
+     * </p>
+     *
+     * <p>
+     * By default, unpinned contacts will have a pinned position of
+     * {@link PinnedPositions#UNPINNED}, or {@link Integer#MAX_VALUE} (2^31 - 1). Client-provided
+     * pinned positions can be positive integers that range anywhere from 0 to
+     * {@link PinnedPositions#UNPINNED}.
+     * </p>
+     *
+     * <p>
+     * When using {@link PinnedPositions#UPDATE_URI} to update the pinned positions of
+     * certain contacts, it may make sense for your application to star any pinned contacts
+     * by default. To specify this behavior, set the boolean query parameter
+     * {@link PinnedPositions#STAR_WHEN_PINNING} to true to force all pinned and unpinned
+     * contacts to be automatically starred and unstarred.
+     * </p>
+     * @hide
+     */
+    public static final class PinnedPositions {
+
+        /**
+         * <p>
+         * This URI allows applications to update pinned positions for a provided set of contacts.
+         * </p>
+         *
+         * <p>
+         * The list of contactIds to pin and their corresponding pinned positions should be
+         * provided in key-value pairs stored in a {@link ContentValues} object where the key
+         * is a valid contactId, while each pinned position is a positive integer.
+         * </p>
+         *
+         * <p>
+         * Example:
+         * <pre>
+         * ContentValues values = new ContentValues();
+         * values.put("10", 20);
+         * values.put("12", 2);
+         * values.put("15", PinnedPositions.UNPINNED);
+         * int count = resolver.update(PinnedPositions.UPDATE_URI, values, null, null);
+         * </pre>
+         *
+         * This pins the contact with id 10 at position 20, the contact with id 12 at position 2,
+         * and unpins the contact with id 15.
+         * </p>
+         */
+        public static final Uri UPDATE_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "pinned_position_update");
+
+        /**
+         * Default value for the pinned position of an unpinned contact. Also equal to
+         * {@link Integer#MAX_VALUE}.
+         */
+        public static final int UNPINNED = 0x7FFFFFFF;
+
+        /**
+         * Value of pinned position for a contact that a user has indicated should be considered
+         * of the lowest priority. It is up to the client application to determine how to present
+         * such a contact - for example all the way at the bottom of a contact list, or simply
+         * just hidden from view.
+         */
+        public static final int DEMOTED = -1;
+
+        /**
+         * <p> Clients can provide this value as a pinned position to undemote a formerly demoted
+         * contact. If the contact was formerly demoted, it will be restored to an
+         * {@link #UNPINNED} position. If it was otherwise already pinned at another position,
+         * it will not be affected.
+         * </p>
+         *
+         * <p>
+         * Example:
+         * <pre>
+         * ContentValues values = new ContentValues();
+         * values.put("15", PinnedPositions.UNDEMOTE);
+         * int count = resolver.update(ContactsContract.PinnedPositions.UPDATE_URI.buildUpon()
+         *          .build(), values, null, null);
+         * </pre>
+         *
+         * This restores the contact with id 15 to an {@link #UNPINNED} position, meaning that
+         * other apps (e.g. the Dialer) that were formerly hiding this contact from view based on
+         * its {@link #DEMOTED} position will start displaying it again.
+         * </p>
+         */
+        public static final String UNDEMOTE = "undemote";
+
+        /**
+         * <p>
+         * A boolean query parameter that can be used with {@link #UPDATE_URI}.
+         * If "1" or "true", any contact that is pinned or unpinned will be correspondingly
+         * starred or unstarred. Otherwise, starring information will not be affected by pinned
+         * updates. This is false by default.
+         * </p>
+         *
+         * <p>
+         * Example:
+         * <pre>
+         * ContentValues values = new ContentValues();
+         * values.put("10", 20);
+         * values.put("15", PinnedPositions.UNPINNED);
+         * int count = resolver.update(ContactsContract.PinnedPositions.UPDATE_URI.buildUpon()
+         *          .appendQueryParameter(PinnedPositions.FORCE_STAR_WHEN_PINNING, "true").build(),
+         *          values, null, null);
+         * </pre>
+         *
+         * This will pin the contact with id 10 at position 20 and star it automatically if not
+         * already starred, and unpin the contact with id 15, and unstar it automatically if not
+         * already unstarred.
+         * </p>
+         */
+        public static final String STAR_WHEN_PINNING = "star_when_pinning";
+    }
+
+    /**
      * Helper methods to display QuickContact dialogs that allow users to pivot on
      * a specific {@link Contacts} entry.
      */
@@ -8463,138 +8602,4 @@
             public static final String DATA_SET = "com.android.contacts.extra.DATA_SET";
         }
     }
-
-    /**
-     * Creates a snippet out of the given content that matches the given query.
-     * @param content - The content to use to compute the snippet.
-     * @param displayName - Display name for the contact - if this already contains the search
-     *        content, no snippet should be shown.
-     * @param query - String to search for in the content.
-     * @param snippetStartMatch - Marks the start of the matching string in the snippet.
-     * @param snippetEndMatch - Marks the end of the matching string in the snippet.
-     * @param snippetEllipsis - Ellipsis string appended to the end of the snippet (if too long).
-     * @param snippetMaxTokens - Maximum number of words from the snippet that will be displayed.
-     * @return The computed snippet, or null if the snippet could not be computed or should not be
-     *         shown.
-     *
-     *  @hide
-     */
-    public static String snippetize(String content, String displayName, String query,
-            char snippetStartMatch, char snippetEndMatch, String snippetEllipsis,
-            int snippetMaxTokens) {
-
-        String lowerQuery = query != null ? query.toLowerCase() : null;
-        if (TextUtils.isEmpty(content) || TextUtils.isEmpty(query) ||
-                TextUtils.isEmpty(displayName) || !content.toLowerCase().contains(lowerQuery)) {
-            return null;
-        }
-
-        // If the display name already contains the query term, return empty - snippets should
-        // not be needed in that case.
-        String lowerDisplayName = displayName != null ? displayName.toLowerCase() : "";
-        List<String> nameTokens = new ArrayList<String>();
-        List<Integer> nameTokenOffsets = new ArrayList<Integer>();
-        split(lowerDisplayName.trim(), nameTokens, nameTokenOffsets);
-        for (String nameToken : nameTokens) {
-            if (nameToken.startsWith(lowerQuery)) {
-                return null;
-            }
-        }
-
-        String[] contentLines = content.split("\n");
-
-        // Locate the lines of the content that contain the query term.
-        for (String contentLine : contentLines) {
-            if (contentLine.toLowerCase().contains(lowerQuery)) {
-
-                // Line contains the query string - now search for it at the start of tokens.
-                List<String> lineTokens = new ArrayList<String>();
-                List<Integer> tokenOffsets = new ArrayList<Integer>();
-                split(contentLine, lineTokens, tokenOffsets);
-
-                // As we find matches against the query, we'll populate this list with the marked
-                // (or unchanged) tokens.
-                List<String> markedTokens = new ArrayList<String>();
-
-                int firstToken = -1;
-                int lastToken = -1;
-                for (int i = 0; i < lineTokens.size(); i++) {
-                    String token = lineTokens.get(i);
-                    String lowerToken = token.toLowerCase();
-                    if (lowerToken.startsWith(lowerQuery)) {
-
-                        // Query term matched; surround the token with match markers.
-                        markedTokens.add(snippetStartMatch + token + snippetEndMatch);
-
-                        // If this is the first token found with a match, mark the token
-                        // positions to use for assembling the snippet.
-                        if (firstToken == -1) {
-                            firstToken =
-                                    Math.max(0, i - (int) Math.floor(
-                                            Math.abs(snippetMaxTokens)
-                                            / 2.0));
-                            lastToken =
-                                    Math.min(lineTokens.size(), firstToken +
-                                            Math.abs(snippetMaxTokens));
-                        }
-                    } else {
-                        markedTokens.add(token);
-                    }
-                }
-
-                // Assemble the snippet by piecing the tokens back together.
-                if (firstToken > -1) {
-                    StringBuilder sb = new StringBuilder();
-                    if (firstToken > 0) {
-                        sb.append(snippetEllipsis);
-                    }
-                    for (int i = firstToken; i < lastToken; i++) {
-                        String markedToken = markedTokens.get(i);
-                        String originalToken = lineTokens.get(i);
-                        sb.append(markedToken);
-                        if (i < lastToken - 1) {
-                            // Add the characters that appeared between this token and the next.
-                            sb.append(contentLine.substring(
-                                    tokenOffsets.get(i) + originalToken.length(),
-                                    tokenOffsets.get(i + 1)));
-                        }
-                    }
-                    if (lastToken < lineTokens.size()) {
-                        sb.append(snippetEllipsis);
-                    }
-                    return sb.toString();
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Pattern for splitting a line into tokens.  This matches e-mail addresses as a single token,
-     * otherwise splitting on any group of non-alphanumeric characters.
-     *
-     * @hide
-     */
-    private static Pattern SPLIT_PATTERN =
-        Pattern.compile("([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
-
-    /**
-     * Helper method for splitting a string into tokens.  The lists passed in are populated with the
-     * tokens and offsets into the content of each token.  The tokenization function parses e-mail
-     * addresses as a single token; otherwise it splits on any non-alphanumeric character.
-     * @param content Content to split.
-     * @param tokens List of token strings to populate.
-     * @param offsets List of offsets into the content for each token returned.
-     *
-     * @hide
-     */
-    private static void split(String content, List<String> tokens, List<Integer> offsets) {
-        Matcher matcher = SPLIT_PATTERN.matcher(content);
-        while (matcher.find()) {
-            tokens.add(matcher.group());
-            offsets.add(matcher.start());
-        }
-    }
-
-
 }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
new file mode 100644
index 0000000..8bf6e4f
--- /dev/null
+++ b/core/java/android/provider/DocumentsContract.java
@@ -0,0 +1,767 @@
+/*
+ * 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 android.provider;
+
+import static android.net.TrafficStats.KB_IN_BYTES;
+import static libcore.io.OsConstants.SEEK_SET;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.OnCloseListener;
+import android.os.RemoteException;
+import android.util.Log;
+
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.BufferedInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Defines the contract between a documents provider and the platform.
+ * <p>
+ * To create a document provider, extend {@link DocumentsProvider}, which
+ * provides a foundational implementation of this contract.
+ *
+ * @see DocumentsProvider
+ */
+public final class DocumentsContract {
+    private static final String TAG = "Documents";
+
+    // content://com.example/root/
+    // content://com.example/root/sdcard/
+    // content://com.example/root/sdcard/recent/
+    // content://com.example/root/sdcard/search/?query=pony
+    // content://com.example/document/12/
+    // content://com.example/document/12/children/
+
+    private DocumentsContract() {
+    }
+
+    /** {@hide} */
+    public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
+
+    /** {@hide} */
+    public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
+    /** {@hide} */
+    public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
+
+    /**
+     * Buffer is large enough to rewind past any EXIF headers.
+     */
+    private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES);
+
+    /**
+     * Constants related to a document, including {@link Cursor} columns names
+     * and flags.
+     * <p>
+     * A document can be either an openable file (with a specific MIME type), or
+     * a directory containing additional documents (with the
+     * {@link #MIME_TYPE_DIR} MIME type).
+     * <p>
+     * All columns are <em>read-only</em> to client applications.
+     */
+    public final static class Document {
+        private Document() {
+        }
+
+        /**
+         * Unique ID of a document. This ID is both provided by and interpreted
+         * by a {@link DocumentsProvider}, and should be treated as an opaque
+         * value by client applications. This column is required.
+         * <p>
+         * Each document must have a unique ID within a provider, but that
+         * single document may be included as a child of multiple directories.
+         * <p>
+         * A provider must always return durable IDs, since they will be used to
+         * issue long-term Uri permission grants when an application interacts
+         * with {@link Intent#ACTION_OPEN_DOCUMENT} and
+         * {@link Intent#ACTION_CREATE_DOCUMENT}.
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_DOCUMENT_ID = "document_id";
+
+        /**
+         * Concrete MIME type of a document. For example, "image/png" or
+         * "application/pdf" for openable files. A document can also be a
+         * directory containing additional documents, which is represented with
+         * the {@link #MIME_TYPE_DIR} MIME type. This column is required.
+         * <p>
+         * Type: STRING
+         *
+         * @see #MIME_TYPE_DIR
+         */
+        public static final String COLUMN_MIME_TYPE = "mime_type";
+
+        /**
+         * Display name of a document, used as the primary title displayed to a
+         * user. This column is required.
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_DISPLAY_NAME = OpenableColumns.DISPLAY_NAME;
+
+        /**
+         * Summary of a document, which may be shown to a user. This column is
+         * optional, and may be {@code null}.
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_SUMMARY = "summary";
+
+        /**
+         * Timestamp when a document was last modified, in milliseconds since
+         * January 1, 1970 00:00:00.0 UTC. This column is required, and may be
+         * {@code null} if unknown. A {@link DocumentsProvider} can update this
+         * field using events from {@link OnCloseListener} or other reliable
+         * {@link ParcelFileDescriptor} transports.
+         * <p>
+         * Type: INTEGER (long)
+         *
+         * @see System#currentTimeMillis()
+         */
+        public static final String COLUMN_LAST_MODIFIED = "last_modified";
+
+        /**
+         * Specific icon resource ID for a document. This column is optional,
+         * and may be {@code null} to use a platform-provided default icon based
+         * on {@link #COLUMN_MIME_TYPE}.
+         * <p>
+         * Type: INTEGER (int)
+         */
+        public static final String COLUMN_ICON = "icon";
+
+        /**
+         * Flags that apply to a document. This column is required.
+         * <p>
+         * Type: INTEGER (int)
+         *
+         * @see #FLAG_SUPPORTS_WRITE
+         * @see #FLAG_SUPPORTS_DELETE
+         * @see #FLAG_SUPPORTS_THUMBNAIL
+         * @see #FLAG_DIR_PREFERS_GRID
+         * @see #FLAG_DIR_PREFERS_LAST_MODIFIED
+         */
+        public static final String COLUMN_FLAGS = "flags";
+
+        /**
+         * Size of a document, in bytes, or {@code null} if unknown. This column
+         * is required.
+         * <p>
+         * Type: INTEGER (long)
+         */
+        public static final String COLUMN_SIZE = OpenableColumns.SIZE;
+
+        /**
+         * MIME type of a document which is a directory that may contain
+         * additional documents.
+         *
+         * @see #COLUMN_MIME_TYPE
+         */
+        public static final String MIME_TYPE_DIR = "vnd.android.document/directory";
+
+        /**
+         * Flag indicating that a document can be represented as a thumbnail.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#getDocumentThumbnail(ContentResolver, Uri,
+         *      Point, CancellationSignal)
+         * @see DocumentsProvider#openDocumentThumbnail(String, Point,
+         *      android.os.CancellationSignal)
+         */
+        public static final int FLAG_SUPPORTS_THUMBNAIL = 1;
+
+        /**
+         * Flag indicating that a document supports writing.
+         * <p>
+         * When a document is opened with {@link Intent#ACTION_OPEN_DOCUMENT},
+         * the calling application is granted both
+         * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and
+         * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}. However, the actual
+         * writability of a document may change over time, for example due to
+         * remote access changes. This flag indicates that a document client can
+         * expect {@link ContentResolver#openOutputStream(Uri)} to succeed.
+         * 
+         * @see #COLUMN_FLAGS
+         */
+        public static final int FLAG_SUPPORTS_WRITE = 1 << 1;
+
+        /**
+         * Flag indicating that a document is deletable.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#deleteDocument(ContentResolver, Uri)
+         * @see DocumentsProvider#deleteDocument(String)
+         */
+        public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
+
+        /**
+         * Flag indicating that a document is a directory that supports creation
+         * of new files within it. Only valid when {@link #COLUMN_MIME_TYPE} is
+         * {@link #MIME_TYPE_DIR}.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#createDocument(ContentResolver, Uri, String,
+         *      String)
+         * @see DocumentsProvider#createDocument(String, String, String)
+         */
+        public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3;
+
+        /**
+         * Flag indicating that a directory prefers its contents be shown in a
+         * larger format grid. Usually suitable when a directory contains mostly
+         * pictures. Only valid when {@link #COLUMN_MIME_TYPE} is
+         * {@link #MIME_TYPE_DIR}.
+         *
+         * @see #COLUMN_FLAGS
+         */
+        public static final int FLAG_DIR_PREFERS_GRID = 1 << 4;
+
+        /**
+         * Flag indicating that a directory prefers its contents be sorted by
+         * {@link #COLUMN_LAST_MODIFIED}. Only valid when
+         * {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
+         *
+         * @see #COLUMN_FLAGS
+         */
+        public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 5;
+
+        /**
+         * Flag indicating that document titles should be hidden when viewing
+         * this directory in a larger format grid. For example, a directory
+         * containing only images may want the image thumbnails to speak for
+         * themselves. Only valid when {@link #COLUMN_MIME_TYPE} is
+         * {@link #MIME_TYPE_DIR}.
+         *
+         * @see #COLUMN_FLAGS
+         * @see #FLAG_DIR_PREFERS_GRID
+         * @hide
+         */
+        public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 16;
+    }
+
+    /**
+     * Constants related to a root of documents, including {@link Cursor}
+     * columns names and flags.
+     * <p>
+     * All columns are <em>read-only</em> to client applications.
+     */
+    public final static class Root {
+        private Root() {
+        }
+
+        /**
+         * Unique ID of a root. This ID is both provided by and interpreted by a
+         * {@link DocumentsProvider}, and should be treated as an opaque value
+         * by client applications. This column is required.
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_ROOT_ID = "root_id";
+
+        /**
+         * Flags that apply to a root. This column is required.
+         * <p>
+         * Type: INTEGER (int)
+         *
+         * @see #FLAG_LOCAL_ONLY
+         * @see #FLAG_SUPPORTS_CREATE
+         * @see #FLAG_SUPPORTS_RECENTS
+         * @see #FLAG_SUPPORTS_SEARCH
+         */
+        public static final String COLUMN_FLAGS = "flags";
+
+        /**
+         * Icon resource ID for a root. This column is required.
+         * <p>
+         * Type: INTEGER (int)
+         */
+        public static final String COLUMN_ICON = "icon";
+
+        /**
+         * Title for a root, which will be shown to a user. This column is
+         * required.
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_TITLE = "title";
+
+        /**
+         * Summary for this root, which may be shown to a user. This column is
+         * optional, and may be {@code null}.
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_SUMMARY = "summary";
+
+        /**
+         * Document which is a directory that represents the top directory of
+         * this root. This column is required.
+         * <p>
+         * Type: STRING
+         *
+         * @see Document#COLUMN_DOCUMENT_ID
+         */
+        public static final String COLUMN_DOCUMENT_ID = "document_id";
+
+        /**
+         * Number of bytes available in this root. This column is optional, and
+         * may be {@code null} if unknown or unbounded.
+         * <p>
+         * Type: INTEGER (long)
+         */
+        public static final String COLUMN_AVAILABLE_BYTES = "available_bytes";
+
+        /**
+         * MIME types supported by this root. This column is optional, and if
+         * {@code null} the root is assumed to support all MIME types. Multiple
+         * MIME types can be separated by a newline. For example, a root
+         * supporting audio might return "audio/*\napplication/x-flac".
+         * <p>
+         * Type: STRING
+         */
+        public static final String COLUMN_MIME_TYPES = "mime_types";
+
+        /** {@hide} */
+        public static final String MIME_TYPE_ITEM = "vnd.android.document/root";
+
+        /**
+         * Flag indicating that at least one directory under this root supports
+         * creating content. Roots with this flag will be shown when an
+         * application interacts with {@link Intent#ACTION_CREATE_DOCUMENT}.
+         *
+         * @see #COLUMN_FLAGS
+         */
+        public static final int FLAG_SUPPORTS_CREATE = 1;
+
+        /**
+         * Flag indicating that this root offers content that is strictly local
+         * on the device. That is, no network requests are made for the content.
+         *
+         * @see #COLUMN_FLAGS
+         * @see Intent#EXTRA_LOCAL_ONLY
+         */
+        public static final int FLAG_LOCAL_ONLY = 1 << 1;
+
+        /**
+         * Flag indicating that this root can report recently modified
+         * documents.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#buildRecentDocumentsUri(String, String)
+         */
+        public static final int FLAG_SUPPORTS_RECENTS = 1 << 2;
+
+        /**
+         * Flag indicating that this root supports search.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsProvider#querySearchDocuments(String, String,
+         *      String[])
+         */
+        public static final int FLAG_SUPPORTS_SEARCH = 1 << 3;
+
+        /**
+         * Flag indicating that this root is currently empty. This may be used
+         * to hide the root when opening documents, but the root will still be
+         * shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
+         * also set. If the value of this flag changes, such as when a root
+         * becomes non-empty, you must send a content changed notification for
+         * {@link DocumentsContract#buildRootsUri(String)}.
+         *
+         * @see #COLUMN_FLAGS
+         * @see ContentResolver#notifyChange(Uri,
+         *      android.database.ContentObserver, boolean)
+         * @hide
+         */
+        public static final int FLAG_EMPTY = 1 << 16;
+
+        /**
+         * Flag indicating that this root should only be visible to advanced
+         * users.
+         *
+         * @see #COLUMN_FLAGS
+         * @hide
+         */
+        public static final int FLAG_ADVANCED = 1 << 17;
+    }
+
+    /**
+     * Optional boolean flag included in a directory {@link Cursor#getExtras()}
+     * indicating that a document provider is still loading data. For example, a
+     * provider has returned some results, but is still waiting on an
+     * outstanding network request. The provider must send a content changed
+     * notification when loading is finished.
+     *
+     * @see ContentResolver#notifyChange(Uri, android.database.ContentObserver,
+     *      boolean)
+     */
+    public static final String EXTRA_LOADING = "loading";
+
+    /**
+     * Optional string included in a directory {@link Cursor#getExtras()}
+     * providing an informational message that should be shown to a user. For
+     * example, a provider may wish to indicate that not all documents are
+     * available.
+     */
+    public static final String EXTRA_INFO = "info";
+
+    /**
+     * Optional string included in a directory {@link Cursor#getExtras()}
+     * providing an error message that should be shown to a user. For example, a
+     * provider may wish to indicate that a network error occurred. The user may
+     * choose to retry, resulting in a new query.
+     */
+    public static final String EXTRA_ERROR = "error";
+
+    /** {@hide} */
+    public static final String METHOD_CREATE_DOCUMENT = "android:createDocument";
+    /** {@hide} */
+    public static final String METHOD_DELETE_DOCUMENT = "android:deleteDocument";
+
+    /** {@hide} */
+    public static final String EXTRA_THUMBNAIL_SIZE = "thumbnail_size";
+
+    private static final String PATH_ROOT = "root";
+    private static final String PATH_RECENT = "recent";
+    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 PARAM_QUERY = "query";
+    private static final String PARAM_MANAGE = "manage";
+
+    /**
+     * Build Uri representing the roots of a document provider. When queried, a
+     * provider will return one or more rows with columns defined by
+     * {@link Root}.
+     *
+     * @see DocumentsProvider#queryRoots(String[])
+     */
+    public static Uri buildRootsUri(String authority) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).appendPath(PATH_ROOT).build();
+    }
+
+    /**
+     * Build Uri representing the given {@link Root#COLUMN_ROOT_ID} in a
+     * document provider.
+     *
+     * @see #getRootId(Uri)
+     */
+    public static Uri buildRootUri(String authority, String rootId) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).appendPath(PATH_ROOT).appendPath(rootId).build();
+    }
+
+    /**
+     * Build Uri representing the recently modified documents of a specific root
+     * in a document provider. When queried, a provider will return zero or more
+     * rows with columns defined by {@link Document}.
+     *
+     * @see DocumentsProvider#queryRecentDocuments(String, String[])
+     * @see #getRootId(Uri)
+     */
+    public static Uri buildRecentDocumentsUri(String authority, String rootId) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).appendPath(PATH_ROOT).appendPath(rootId)
+                .appendPath(PATH_RECENT).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}.
+     *
+     * @see DocumentsProvider#queryDocument(String, String[])
+     * @see #getDocumentId(Uri)
+     */
+    public static Uri buildDocumentUri(String authority, String documentId) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).appendPath(PATH_DOCUMENT).appendPath(documentId).build();
+    }
+
+    /**
+     * Build Uri representing the children of the given directory in a document
+     * provider. When queried, a provider will return zero or more rows with
+     * columns defined by {@link Document}.
+     *
+     * @param parentDocumentId the document to return children for, which must
+     *            be a directory with MIME type of
+     *            {@link Document#MIME_TYPE_DIR}.
+     * @see DocumentsProvider#queryChildDocuments(String, String[], String)
+     * @see #getDocumentId(Uri)
+     */
+    public static Uri buildChildDocumentsUri(String authority, String parentDocumentId) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
+                .appendPath(PATH_DOCUMENT).appendPath(parentDocumentId).appendPath(PATH_CHILDREN)
+                .build();
+    }
+
+    /**
+     * Build Uri representing a search for matching documents under a specific
+     * root in a document provider. When queried, a provider will return zero or
+     * more rows with columns defined by {@link Document}.
+     *
+     * @see DocumentsProvider#querySearchDocuments(String, String, String[])
+     * @see #getRootId(Uri)
+     * @see #getSearchDocumentsQuery(Uri)
+     */
+    public static Uri buildSearchDocumentsUri(
+            String authority, String rootId, String query) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
+                .appendPath(PATH_ROOT).appendPath(rootId).appendPath(PATH_SEARCH)
+                .appendQueryParameter(PARAM_QUERY, query).build();
+    }
+
+    /**
+     * Test if the given Uri represents a {@link Document} backed by a
+     * {@link DocumentsProvider}.
+     */
+    public static boolean isDocumentUri(Context context, Uri uri) {
+        final List<String> paths = uri.getPathSegments();
+        if (paths.size() < 2) {
+            return false;
+        }
+        if (!PATH_DOCUMENT.equals(paths.get(0))) {
+            return false;
+        }
+
+        final ProviderInfo info = context.getPackageManager()
+                .resolveContentProvider(uri.getAuthority(), PackageManager.GET_META_DATA);
+        if (info.metaData != null && info.metaData.containsKey(
+                DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Extract the {@link Root#COLUMN_ROOT_ID} from the given Uri.
+     */
+    public static String getRootId(Uri rootUri) {
+        final List<String> paths = rootUri.getPathSegments();
+        if (paths.size() < 2) {
+            throw new IllegalArgumentException("Not a root: " + rootUri);
+        }
+        if (!PATH_ROOT.equals(paths.get(0))) {
+            throw new IllegalArgumentException("Not a root: " + rootUri);
+        }
+        return paths.get(1);
+    }
+
+    /**
+     * Extract the {@link Document#COLUMN_DOCUMENT_ID} from the given Uri.
+     */
+    public static String getDocumentId(Uri documentUri) {
+        final List<String> paths = documentUri.getPathSegments();
+        if (paths.size() < 2) {
+            throw new IllegalArgumentException("Not a document: " + documentUri);
+        }
+        if (!PATH_DOCUMENT.equals(paths.get(0))) {
+            throw new IllegalArgumentException("Not a document: " + documentUri);
+        }
+        return paths.get(1);
+    }
+
+    /**
+     * Extract the search query from a Uri built by
+     * {@link #buildSearchDocumentsUri(String, String, String)}.
+     */
+    public static String getSearchDocumentsQuery(Uri searchDocumentsUri) {
+        return searchDocumentsUri.getQueryParameter(PARAM_QUERY);
+    }
+
+    /** {@hide} */
+    public static Uri setManageMode(Uri uri) {
+        return uri.buildUpon().appendQueryParameter(PARAM_MANAGE, "true").build();
+    }
+
+    /** {@hide} */
+    public static boolean isManageMode(Uri uri) {
+        return uri.getBooleanQueryParameter(PARAM_MANAGE, false);
+    }
+
+    /**
+     * Return thumbnail representing the document at the given Uri. Callers are
+     * responsible for their own in-memory caching.
+     *
+     * @param documentUri document to return thumbnail for, which must have
+     *            {@link Document#FLAG_SUPPORTS_THUMBNAIL} set.
+     * @param size optimal thumbnail size desired. A provider may return a
+     *            thumbnail of a different size, but never more than double the
+     *            requested size.
+     * @param signal signal used to indicate that caller is no longer interested
+     *            in the thumbnail.
+     * @return decoded thumbnail, or {@code null} if problem was encountered.
+     * @see DocumentsProvider#openDocumentThumbnail(String, Point,
+     *      android.os.CancellationSignal)
+     */
+    public static Bitmap getDocumentThumbnail(
+            ContentResolver resolver, Uri documentUri, Point size, CancellationSignal signal) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                documentUri.getAuthority());
+        try {
+            return getDocumentThumbnail(client, documentUri, size, signal);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
+            return null;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /** {@hide} */
+    public static Bitmap getDocumentThumbnail(
+            ContentProviderClient client, Uri documentUri, Point size, CancellationSignal signal)
+            throws RemoteException, IOException {
+        final Bundle openOpts = new Bundle();
+        openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size);
+
+        AssetFileDescriptor afd = null;
+        try {
+            afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal);
+
+            final FileDescriptor fd = afd.getFileDescriptor();
+            final long offset = afd.getStartOffset();
+
+            // Try seeking on the returned FD, since it gives us the most
+            // optimal decode path; otherwise fall back to buffering.
+            BufferedInputStream is = null;
+            try {
+                Libcore.os.lseek(fd, offset, SEEK_SET);
+            } catch (ErrnoException e) {
+                is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE);
+                is.mark(THUMBNAIL_BUFFER_SIZE);
+            }
+
+            // We requested a rough thumbnail size, but the remote size may have
+            // returned something giant, so defensively scale down as needed.
+            final BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inJustDecodeBounds = true;
+            if (is != null) {
+                BitmapFactory.decodeStream(is, null, opts);
+            } else {
+                BitmapFactory.decodeFileDescriptor(fd, null, opts);
+            }
+
+            final int widthSample = opts.outWidth / size.x;
+            final int heightSample = opts.outHeight / size.y;
+
+            opts.inJustDecodeBounds = false;
+            opts.inSampleSize = Math.min(widthSample, heightSample);
+            Log.d(TAG, "Decoding with sample size " + opts.inSampleSize);
+            if (is != null) {
+                is.reset();
+                return BitmapFactory.decodeStream(is, null, opts);
+            } else {
+                try {
+                    Libcore.os.lseek(fd, offset, SEEK_SET);
+                } catch (ErrnoException e) {
+                    e.rethrowAsIOException();
+                }
+                return BitmapFactory.decodeFileDescriptor(fd, null, opts);
+            }
+        } finally {
+            IoUtils.closeQuietly(afd);
+        }
+    }
+
+    /**
+     * Create a new document with given MIME type and display name.
+     *
+     * @param parentDocumentUri directory with
+     *            {@link Document#FLAG_DIR_SUPPORTS_CREATE}
+     * @param mimeType MIME type of new document
+     * @param displayName name of new document
+     * @return newly created document, or {@code null} if failed
+     * @hide
+     */
+    public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
+            String mimeType, String displayName) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                parentDocumentUri.getAuthority());
+        try {
+            return createDocument(client, parentDocumentUri, mimeType, displayName);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to create document", e);
+            return null;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /** {@hide} */
+    public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri,
+            String mimeType, String displayName) throws RemoteException {
+        final Bundle in = new Bundle();
+        in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(parentDocumentUri));
+        in.putString(Document.COLUMN_MIME_TYPE, mimeType);
+        in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
+
+        final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in);
+        return buildDocumentUri(
+                parentDocumentUri.getAuthority(), out.getString(Document.COLUMN_DOCUMENT_ID));
+    }
+
+    /**
+     * Delete the given document.
+     *
+     * @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE}
+     * @return if the document was deleted successfully.
+     */
+    public static boolean deleteDocument(ContentResolver resolver, Uri documentUri) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                documentUri.getAuthority());
+        try {
+            deleteDocument(client, documentUri);
+            return true;
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to delete document", e);
+            return false;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /** {@hide} */
+    public static void deleteDocument(ContentProviderClient client, Uri documentUri)
+            throws RemoteException {
+        final Bundle in = new Bundle();
+        in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(documentUri));
+
+        client.call(METHOD_DELETE_DOCUMENT, null, in);
+    }
+}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
new file mode 100644
index 0000000..337b735
--- /dev/null
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -0,0 +1,463 @@
+/*
+ * 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 android.provider;
+
+import static android.provider.DocumentsContract.EXTRA_THUMBNAIL_SIZE;
+import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT;
+import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
+import static android.provider.DocumentsContract.getDocumentId;
+import static android.provider.DocumentsContract.getRootId;
+import static android.provider.DocumentsContract.getSearchDocumentsQuery;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.UriMatcher;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.OnCloseListener;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+
+/**
+ * Base class for a document provider. A document provider should extend this
+ * class and implement the abstract methods.
+ * <p>
+ * Each document provider expresses one or more "roots" which each serve as the
+ * top-level of a tree. For example, a root could represent an account, or a
+ * physical storage device. Under each root, documents are referenced by
+ * {@link Document#COLUMN_DOCUMENT_ID}, which must not change once returned.
+ * <p>
+ * Documents can be either an openable file (with a specific MIME type), or a
+ * directory containing additional documents (with the
+ * {@link Document#MIME_TYPE_DIR} MIME type). Each document can have different
+ * capabilities, as described by {@link Document#COLUMN_FLAGS}. The same
+ * {@link Document#COLUMN_DOCUMENT_ID} can be included in multiple directories.
+ * <p>
+ * Document providers must be protected with the
+ * {@link android.Manifest.permission#MANAGE_DOCUMENTS} permission, which can
+ * only be requested by the system. The system-provided UI then issues narrow
+ * Uri permission grants for individual documents when the user explicitly picks
+ * documents.
+ *
+ * @see Intent#ACTION_OPEN_DOCUMENT
+ * @see Intent#ACTION_CREATE_DOCUMENT
+ */
+public abstract class DocumentsProvider extends ContentProvider {
+    private static final String TAG = "DocumentsProvider";
+
+    private static final int MATCH_ROOTS = 1;
+    private static final int MATCH_ROOT = 2;
+    private static final int MATCH_RECENT = 3;
+    private static final int MATCH_SEARCH = 4;
+    private static final int MATCH_DOCUMENT = 5;
+    private static final int MATCH_CHILDREN = 6;
+
+    private String mAuthority;
+
+    private UriMatcher mMatcher;
+
+    /**
+     * Implementation is provided by the parent class.
+     */
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        mAuthority = info.authority;
+
+        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+        mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
+        mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
+        mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
+        mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH);
+        mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
+        mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
+
+        // Sanity check our setup
+        if (!info.exported) {
+            throw new SecurityException("Provider must be exported");
+        }
+        if (!info.grantUriPermissions) {
+            throw new SecurityException("Provider must grantUriPermissions");
+        }
+        if (!android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.readPermission)
+                || !android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.writePermission)) {
+            throw new SecurityException("Provider must be protected by MANAGE_DOCUMENTS");
+        }
+
+        super.attachInfo(context, info);
+    }
+
+    /**
+     * Create a new document and return its {@link Document#COLUMN_DOCUMENT_ID}.
+     * A provider must allocate a new {@link Document#COLUMN_DOCUMENT_ID} to
+     * represent the document, which must not change once returned.
+     *
+     * @param documentId the parent directory to create the new document under.
+     * @param mimeType the MIME type associated with the new document.
+     * @param displayName the display name of the new document.
+     */
+    @SuppressWarnings("unused")
+    public String createDocument(String documentId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("Create not supported");
+    }
+
+    /**
+     * Delete the given document. Upon returning, any Uri permission grants for
+     * the given document will be revoked. If additional documents were deleted
+     * as a side effect of this call, such as documents inside a directory, the
+     * implementor is responsible for revoking those permissions.
+     *
+     * @param documentId the document to delete.
+     */
+    @SuppressWarnings("unused")
+    public void deleteDocument(String documentId) throws FileNotFoundException {
+        throw new UnsupportedOperationException("Delete not supported");
+    }
+
+    public abstract Cursor queryRoots(String[] projection) throws FileNotFoundException;
+
+    @SuppressWarnings("unused")
+    public Cursor queryRecentDocuments(String rootId, String[] projection)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("Recent not supported");
+    }
+
+    /**
+     * Return metadata for the given document. A provider should avoid making
+     * network requests to keep this request fast.
+     *
+     * @param documentId the document to return.
+     */
+    public abstract Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException;
+
+    /**
+     * Return the children of the given document which is a directory.
+     *
+     * @param parentDocumentId the directory to return children for.
+     */
+    public abstract Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException;
+
+    /** {@hide} */
+    @SuppressWarnings("unused")
+    public Cursor queryChildDocumentsForManage(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("Manage not supported");
+    }
+
+    /**
+     * Return documents that that match the given query.
+     *
+     * @param rootId the root to search under.
+     */
+    @SuppressWarnings("unused")
+    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("Search not supported");
+    }
+
+    /**
+     * Return MIME type for the given document. Must match the value of
+     * {@link Document#COLUMN_MIME_TYPE} for this document.
+     */
+    public String getDocumentType(String documentId) throws FileNotFoundException {
+        final Cursor cursor = queryDocument(documentId, null);
+        try {
+            if (cursor.moveToFirst()) {
+                return cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE));
+            } else {
+                return null;
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+    }
+
+    /**
+     * Open and return the requested document. A provider should return a
+     * reliable {@link ParcelFileDescriptor} to detect when the remote caller
+     * has finished reading or writing the document. A provider may return a
+     * pipe or socket pair if the mode is exclusively
+     * {@link ParcelFileDescriptor#MODE_READ_ONLY} or
+     * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, but complex modes like
+     * {@link ParcelFileDescriptor#MODE_READ_WRITE} require a normal file on
+     * disk. If a provider blocks while downloading content, it should
+     * periodically check {@link CancellationSignal#isCanceled()} to abort
+     * abandoned open requests.
+     *
+     * @param docId the document to return.
+     * @param mode the mode to open with, such as 'r', 'w', or 'rw'.
+     * @param signal used by the caller to signal if the request should be
+     *            cancelled.
+     * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
+     *      OnCloseListener)
+     * @see ParcelFileDescriptor#createReliablePipe()
+     * @see ParcelFileDescriptor#createReliableSocketPair()
+     */
+    public abstract ParcelFileDescriptor openDocument(
+            String docId, String mode, CancellationSignal signal) throws FileNotFoundException;
+
+    /**
+     * Open and return a thumbnail of the requested document. A provider should
+     * return a thumbnail closely matching the hinted size, attempting to serve
+     * from a local cache if possible. A provider should never return images
+     * more than double the hinted size. If a provider performs expensive
+     * operations to download or generate a thumbnail, it should periodically
+     * check {@link CancellationSignal#isCanceled()} to abort abandoned
+     * thumbnail requests.
+     *
+     * @param docId the document to return.
+     * @param sizeHint hint of the optimal thumbnail dimensions.
+     * @param signal used by the caller to signal if the request should be
+     *            cancelled.
+     * @see Document#FLAG_SUPPORTS_THUMBNAIL
+     */
+    @SuppressWarnings("unused")
+    public AssetFileDescriptor openDocumentThumbnail(
+            String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
+        throw new UnsupportedOperationException("Thumbnails not supported");
+    }
+
+    /**
+     * Implementation is provided by the parent class. Cannot be overriden.
+     *
+     * @see #queryRoots(String[])
+     * @see #queryRecentDocuments(String, String[])
+     * @see #queryDocument(String, String[])
+     * @see #queryChildDocuments(String, String[], String)
+     * @see #querySearchDocuments(String, String, String[])
+     */
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        try {
+            switch (mMatcher.match(uri)) {
+                case MATCH_ROOTS:
+                    return queryRoots(projection);
+                case MATCH_RECENT:
+                    return queryRecentDocuments(getRootId(uri), projection);
+                case MATCH_SEARCH:
+                    return querySearchDocuments(
+                            getRootId(uri), getSearchDocumentsQuery(uri), projection);
+                case MATCH_DOCUMENT:
+                    return queryDocument(getDocumentId(uri), projection);
+                case MATCH_CHILDREN:
+                    if (DocumentsContract.isManageMode(uri)) {
+                        return queryChildDocumentsForManage(
+                                getDocumentId(uri), projection, sortOrder);
+                    } else {
+                        return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
+                    }
+                default:
+                    throw new UnsupportedOperationException("Unsupported Uri " + uri);
+            }
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "Failed during query", e);
+            return null;
+        }
+    }
+
+    /**
+     * Implementation is provided by the parent class. Cannot be overriden.
+     *
+     * @see #getDocumentType(String)
+     */
+    @Override
+    public final String getType(Uri uri) {
+        try {
+            switch (mMatcher.match(uri)) {
+                case MATCH_ROOT:
+                    return DocumentsContract.Root.MIME_TYPE_ITEM;
+                case MATCH_DOCUMENT:
+                    return getDocumentType(getDocumentId(uri));
+                default:
+                    return null;
+            }
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "Failed during getType", e);
+            return null;
+        }
+    }
+
+    /**
+     * Implementation is provided by the parent class. Throws by default, and
+     * cannot be overriden.
+     *
+     * @see #createDocument(String, String, String)
+     */
+    @Override
+    public final Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException("Insert not supported");
+    }
+
+    /**
+     * Implementation is provided by the parent class. Throws by default, and
+     * cannot be overriden.
+     *
+     * @see #deleteDocument(String)
+     */
+    @Override
+    public final int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("Delete not supported");
+    }
+
+    /**
+     * Implementation is provided by the parent class. Throws by default, and
+     * cannot be overriden.
+     */
+    @Override
+    public final int update(
+            Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("Update not supported");
+    }
+
+    /**
+     * Implementation is provided by the parent class. Can be overridden to
+     * provide additional functionality, but subclasses <em>must</em> always
+     * call the superclass. If the superclass returns {@code null}, the subclass
+     * may implement custom behavior.
+     *
+     * @see #openDocument(String, String, CancellationSignal)
+     * @see #deleteDocument(String)
+     */
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        final Context context = getContext();
+
+        if (!method.startsWith("android:")) {
+            // Let non-platform methods pass through
+            return super.call(method, arg, extras);
+        }
+
+        final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
+        final Uri documentUri = DocumentsContract.buildDocumentUri(mAuthority, documentId);
+
+        // Require that caller can manage given document
+        final boolean callerHasManage =
+                context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS)
+                == PackageManager.PERMISSION_GRANTED;
+        if (!callerHasManage) {
+            getContext().enforceCallingOrSelfUriPermission(
+                    documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method);
+        }
+
+        final Bundle out = new Bundle();
+        try {
+            if (METHOD_CREATE_DOCUMENT.equals(method)) {
+                final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
+                final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
+
+                final String newDocumentId = createDocument(documentId, mimeType, displayName);
+                out.putString(Document.COLUMN_DOCUMENT_ID, newDocumentId);
+
+                // Extend permission grant towards caller if needed
+                if (!callerHasManage) {
+                    final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
+                            mAuthority, newDocumentId);
+                    context.grantUriPermission(getCallingPackage(), newDocumentUri,
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION
+                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                            | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+                }
+
+            } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
+                deleteDocument(documentId);
+
+                // Document no longer exists, clean up any grants
+                context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                        | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+
+            } else {
+                throw new UnsupportedOperationException("Method not supported " + method);
+            }
+        } catch (FileNotFoundException e) {
+            throw new IllegalStateException("Failed call " + method, e);
+        }
+        return out;
+    }
+
+    /**
+     * Implementation is provided by the parent class.
+     *
+     * @see #openDocument(String, String, CancellationSignal)
+     */
+    @Override
+    public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        return openDocument(getDocumentId(uri), mode, null);
+    }
+
+    /**
+     * Implementation is provided by the parent class.
+     *
+     * @see #openDocument(String, String, CancellationSignal)
+     */
+    @Override
+    public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openDocument(getDocumentId(uri), mode, signal);
+    }
+
+    /**
+     * Implementation is provided by the parent class.
+     *
+     * @see #openDocumentThumbnail(String, Point, CancellationSignal)
+     */
+    @Override
+    public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
+            throws FileNotFoundException {
+        if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
+            final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
+            return openDocumentThumbnail(getDocumentId(uri), sizeHint, null);
+        } else {
+            return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
+        }
+    }
+
+    /**
+     * Implementation is provided by the parent class.
+     *
+     * @see #openDocumentThumbnail(String, Point, CancellationSignal)
+     */
+    @Override
+    public final AssetFileDescriptor openTypedAssetFile(
+            Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
+            throws FileNotFoundException {
+        if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
+            final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
+            return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal);
+        } else {
+            return super.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
+        }
+    }
+}
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 9999760..b2d9b934 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -410,6 +410,8 @@
         /** The column that is used to count retries */
         public static final String COLUMN_FAILED_CONNECTIONS = "numfailed";
 
+        public static final String COLUMN_ALLOW_WRITE = "allow_write";
+
         /**
          * default value for {@link #COLUMN_LAST_UPDATESRC}.
          * This value is used when this column's value is not relevant.
diff --git a/core/java/android/provider/DrmStore.java b/core/java/android/provider/DrmStore.java
deleted file mode 100644
index 34f2f0d..0000000
--- a/core/java/android/provider/DrmStore.java
+++ /dev/null
@@ -1,211 +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.provider;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.drm.mobile1.DrmRawContent;
-import android.drm.mobile1.DrmRights;
-import android.drm.mobile1.DrmRightsManager;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * The DRM provider contains forward locked DRM content.
- *
- * @hide
- */
-public final class DrmStore
-{
-    private static final String TAG = "DrmStore";
-
-    public static final String AUTHORITY = "drm";
-
-    /**
-     * This is in the Manifest class of the drm provider, but that isn't visible
-     * in the framework.
-     */
-    private static final String ACCESS_DRM_PERMISSION = "android.permission.ACCESS_DRM";
-
-    /**
-     * Fields for DRM database
-     */
-
-    public interface Columns extends BaseColumns {
-        /**
-         * The data stream for the file
-         * <P>Type: DATA STREAM</P>
-         */
-        public static final String DATA = "_data";
-
-        /**
-         * The size of the file in bytes
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String SIZE = "_size";
-
-        /**
-         * The title of the file content
-         * <P>Type: TEXT</P>
-         */
-        public static final String TITLE = "title";
-
-        /**
-         * The MIME type of the file
-         * <P>Type: TEXT</P>
-         */
-        public static final String MIME_TYPE = "mime_type";
-
-    }
-
-    public interface Images extends Columns {
-
-        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/images");
-    }
-
-    public interface Audio extends Columns {
-
-        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/audio");
-    }
-
-    /**
-     * Utility function for inserting a file into the DRM content provider.
-     *
-     * @param cr The content resolver to use
-     * @param file The file to insert
-     * @param title The title for the content (or null)
-     * @return uri to the DRM record or null
-     */
-    public static final Intent addDrmFile(ContentResolver cr, File file, String title) {
-        FileInputStream fis = null;
-        Intent result = null;
-
-        try {
-            fis = new FileInputStream(file);
-            if (title == null) {
-                title = file.getName();
-                int lastDot = title.lastIndexOf('.');
-                if (lastDot > 0) {
-                    title = title.substring(0, lastDot);
-                }
-            }
-            result = addDrmFile(cr, fis, title);
-        } catch (Exception e) {
-            Log.e(TAG, "pushing file failed", e);
-        } finally {
-            try {
-                if (fis != null)
-                    fis.close();
-            } catch (IOException e) {
-                Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Utility function for inserting a file stream into the DRM content provider.
-     *
-     * @param cr The content resolver to use
-     * @param fis The FileInputStream to insert
-     * @param title The title for the content (or null)
-     * @return uri to the DRM record or null
-     */
-    public static final Intent addDrmFile(ContentResolver cr, FileInputStream fis, String title) {
-        OutputStream os = null;
-        Intent result = null;
-
-        try {
-            DrmRawContent content = new DrmRawContent(fis, (int) fis.available(),
-                    DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING);
-            String mimeType = content.getContentType();
-            long size = fis.getChannel().size();
-
-            DrmRightsManager manager = manager = DrmRightsManager.getInstance();
-            DrmRights rights = manager.queryRights(content);
-            InputStream stream = content.getContentInputStream(rights);
-
-            Uri contentUri = null;
-            if (mimeType.startsWith("audio/")) {
-                contentUri = DrmStore.Audio.CONTENT_URI;
-            } else if (mimeType.startsWith("image/")) {
-                contentUri = DrmStore.Images.CONTENT_URI;
-            } else {
-                Log.w(TAG, "unsupported mime type " + mimeType);
-            }
-
-            if (contentUri != null) {
-                ContentValues values = new ContentValues(3);
-                values.put(DrmStore.Columns.TITLE, title);
-                values.put(DrmStore.Columns.SIZE, size);
-                values.put(DrmStore.Columns.MIME_TYPE, mimeType);
-
-                Uri uri = cr.insert(contentUri, values);
-                if (uri != null) {
-                    os = cr.openOutputStream(uri);
-
-                    byte[] buffer = new byte[1000];
-                    int count;
-
-                    while ((count = stream.read(buffer)) != -1) {
-                        os.write(buffer, 0, count);
-                    }
-                    result = new Intent();
-                    result.setDataAndType(uri, mimeType);
-
-                }
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "pushing file failed", e);
-        } finally {
-            try {
-                if (fis != null)
-                    fis.close();
-                if (os != null)
-                    os.close();
-            } catch (IOException e) {
-                Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Utility function to enforce any permissions required to access DRM
-     * content.
-     *
-     * @param context A context used for checking calling permission.
-     */
-    public static void enforceAccessDrmPermission(Context context) {
-        if (context.checkCallingOrSelfPermission(ACCESS_DRM_PERMISSION) !=
-                PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires DRM permission");
-        }
-    }
-
-}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index cb6300f..f69cad0 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -19,8 +19,8 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.ContentUris;
+import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
@@ -118,6 +118,7 @@
      * sense for apps that can support large-scale search of music, such as services connected
      * to an online database of music which can be streamed and played on the device.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
             "android.media.action.MEDIA_PLAY_FROM_SEARCH";
 
@@ -134,6 +135,7 @@
      * sense for apps that can support large-scale search of text media, such as services connected
      * to an online database of books and/or magazines which can be read on the device.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH =
             "android.media.action.TEXT_OPEN_FROM_SEARCH";
 
@@ -150,6 +152,7 @@
      * sense for apps that can support large-scale search of video, such as services connected to an
      * online database of videos which can be streamed and played on the device.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH =
             "android.media.action.VIDEO_PLAY_FROM_SEARCH";
 
@@ -202,6 +205,7 @@
     /**
      * The name of the Intent action used to launch a camera in still image mode.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
 
     /**
@@ -216,12 +220,14 @@
      * this flag is used, so launching more than one activity is strongly
      * discouraged.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
             "android.media.action.STILL_IMAGE_CAMERA_SECURE";
 
     /**
      * The name of the Intent action used to launch a camera in video mode.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
 
     /**
@@ -235,6 +241,7 @@
      * value of EXTRA_OUTPUT.
      * @see #EXTRA_OUTPUT
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
 
     /**
@@ -256,6 +263,7 @@
      * @see #ACTION_IMAGE_CAPTURE
      * @see #EXTRA_OUTPUT
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_IMAGE_CAPTURE_SECURE =
             "android.media.action.IMAGE_CAPTURE_SECURE";
 
@@ -274,6 +282,7 @@
      * @see #EXTRA_SIZE_LIMIT
      * @see #EXTRA_DURATION_LIMIT
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
 
     /**
@@ -532,7 +541,8 @@
         private static final Object sThumbBufLock = new Object();
         private static byte[] sThumbBuf;
 
-        private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
+        private static Bitmap getMiniThumbFromFile(
+                Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
             Bitmap bitmap = null;
             Uri thumbUri = null;
             try {
@@ -577,6 +587,7 @@
                 if (c != null) c.close();
             }
         }
+
         /**
          * This method ensure thumbnails associated with origId are generated and decode the byte
          * stream from database (MICRO_KIND) or file (MINI_KIND).
diff --git a/core/java/android/provider/OpenableColumns.java b/core/java/android/provider/OpenableColumns.java
index f548bae..faf96b7 100644
--- a/core/java/android/provider/OpenableColumns.java
+++ b/core/java/android/provider/OpenableColumns.java
@@ -16,11 +16,17 @@
 
 package android.provider;
 
+import android.content.ContentResolver;
+import android.content.Intent;
+
 /**
- * These are standard columns for openable URIs. (See
- * {@link android.content.Intent#CATEGORY_OPENABLE}.) If possible providers that have openable URIs
- * should support these columns. To find the content type of a URI use
- * {@link android.content.ContentResolver#getType(android.net.Uri)} as normal.
+ * These are standard columns for openable URIs. Providers that serve openable
+ * URIs <em>must</em> support at least these columns when queried.
+ * <p>
+ * To find the content type of a URI, use
+ * {@link ContentResolver#getType(android.net.Uri)}.
+ *
+ * @see Intent#CATEGORY_OPENABLE
  */
 public interface OpenableColumns {
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 81e76ab..3769e1e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -33,6 +33,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.SQLException;
+import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -159,6 +160,38 @@
             "android.settings.SECURITY_SETTINGS";
 
     /**
+     * Activity Action: Show trusted credentials settings, opening to the user tab,
+     * to allow management of installed credentials.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_TRUSTED_CREDENTIALS_USER =
+            "com.android.settings.TRUSTED_CREDENTIALS_USER";
+
+    /**
+     * Activity Action: Show dialog explaining that an installed CA cert may enable
+     * monitoring of encrypted network traffic.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MONITORING_CERT_INFO =
+            "com.android.settings.MONITORING_CERT_INFO";
+
+    /**
      * Activity Action: Show settings to allow configuration of privacy options.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -342,8 +375,9 @@
     /**
      * Activity Action: Show settings to manage the user input dictionary.
      * <p>
-     * In some cases, a matching Activity may not exist, so ensure you
-     * safeguard against this.
+     * Starting with {@link android.os.Build.VERSION_CODES#KITKAT},
+     * it is guaranteed there will always be an appropriate implementation for this Intent action.
+     * In prior releases of the platform this was optional, so ensure you safeguard against it.
      * <p>
      * Input: Nothing.
      * <p>
@@ -642,6 +676,23 @@
         "android.settings.NFCSHARING_SETTINGS";
 
     /**
+     * Activity Action: Show NFC Tap & Pay settings
+     * <p>
+     * This shows UI that allows the user to configure Tap&Pay
+     * settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_NFC_PAYMENT_SETTINGS =
+        "android.settings.NFC_PAYMENT_SETTINGS";
+
+    /**
      * Activity Action: Show Daydream settings.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -671,6 +722,33 @@
     public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS
             = "android.settings.NOTIFICATION_LISTENER_SETTINGS";
 
+    /**
+     * Activity Action: Show settings for video captioning.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
+
+    /**
+     * Activity Action: Show the top level print settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PRINT_SETTINGS =
+            "android.settings.ACTION_PRINT_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -736,6 +814,10 @@
     private static final String TAG = "Settings";
     private static final boolean LOCAL_LOGV = false;
 
+    // Lock ensures that when enabling/disabling the master location switch, we don't end up
+    // with a partial enable/disable state in multi-threaded situations.
+    private static final Object mLocationSettingsLock = new Object();
+
     public static class SettingNotFoundException extends AndroidException {
         public SettingNotFoundException(String msg) {
             super(msg);
@@ -1011,6 +1093,14 @@
             MOVED_TO_GLOBAL.add(Settings.Global.WAIT_FOR_DEBUGGER);
             MOVED_TO_GLOBAL.add(Settings.Global.SHOW_PROCESSES);
             MOVED_TO_GLOBAL.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
+            MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_CONTENT_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_METADATA_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.SELINUX_UPDATE_CONTENT_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.SELINUX_UPDATE_METADATA_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_CONTENT_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
         }
 
         /** @hide */
@@ -2381,7 +2471,9 @@
             SIP_CALL_OPTIONS,
             SIP_RECEIVE_CALLS,
             POINTER_SPEED,
-            VIBRATE_WHEN_RINGING
+            VIBRATE_WHEN_RINGING,
+            RINGTONE,
+            NOTIFICATION_SOUND
         };
 
         // Settings moved to Settings.Secure
@@ -2705,7 +2797,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
             MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
-            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_IDLE_MS);
@@ -2864,6 +2955,11 @@
 
         /** @hide */
         public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+            if (LOCATION_MODE.equals(name)) {
+                // HACK ALERT: temporary hack to work around b/10491283.
+                // TODO: once b/10491283 fixed, remove this hack
+                return getLocationModeForUser(cr, userHandle);
+            }
             String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Integer.parseInt(v) : def;
@@ -2898,6 +2994,11 @@
         /** @hide */
         public static int getIntForUser(ContentResolver cr, String name, int userHandle)
                 throws SettingNotFoundException {
+            if (LOCATION_MODE.equals(name)) {
+                // HACK ALERT: temporary hack to work around b/10491283.
+                // TODO: once b/10491283 fixed, remove this hack
+                return getLocationModeForUser(cr, userHandle);
+            }
             String v = getStringForUser(cr, name, userHandle);
             try {
                 return Integer.parseInt(v);
@@ -2926,6 +3027,11 @@
         /** @hide */
         public static boolean putIntForUser(ContentResolver cr, String name, int value,
                 int userHandle) {
+            if (LOCATION_MODE.equals(name)) {
+                // HACK ALERT: temporary hack to work around b/10491283.
+                // TODO: once b/10491283 fixed, remove this hack
+                return setLocationModeForUser(cr, value, userHandle);
+            }
             return putStringForUser(cr, name, Integer.toString(value), userHandle);
         }
 
@@ -3184,6 +3290,13 @@
                 "input_method_selector_visibility";
 
         /**
+         * bluetooth HCI snoop log configuration
+         * @hide
+         */
+        public static final String BLUETOOTH_HCI_LOG =
+                "bluetooth_hci_log";
+
+        /**
          * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
          */
         @Deprecated
@@ -3227,10 +3340,43 @@
 
         /**
          * Comma-separated list of location providers that activities may access.
+         *
+         * @deprecated use {@link #LOCATION_MODE}
          */
+        @Deprecated
         public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
 
         /**
+         * The degree of location access enabled by the user.
+         * <p/>
+         * When used with {@link #putInt(ContentResolver, String, int)}, must be one of {@link
+         * #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY}, {@link
+         * #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}. When used with {@link
+         * #getInt(ContentResolver, String)}, the caller must gracefully handle additional location
+         * modes that might be added in the future.
+         */
+        public static final String LOCATION_MODE = "location_mode";
+
+        /**
+         * Location access disabled.
+         */
+        public static final int LOCATION_MODE_OFF = 0;
+        /**
+         * Network Location Provider disabled, but GPS and other sensors enabled.
+         */
+        public static final int LOCATION_MODE_SENSORS_ONLY = 1;
+        /**
+         * Reduced power usage, such as limiting the number of GPS updates per hour. Requests
+         * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to
+         * {@link android.location.Criteria#POWER_MEDIUM}.
+         */
+        public static final int LOCATION_MODE_BATTERY_SAVING = 2;
+        /**
+         * Best-effort location computation allowed.
+         */
+        public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
+
+        /**
          * A flag containing settings used for biometric weak
          * @hide
          */
@@ -3494,12 +3640,139 @@
                 "accessibility_display_magnification_auto_update";
 
         /**
+         * Setting that specifies whether timed text (captions) should be
+         * displayed in video content. Text display properties are controlled by
+         * the following settings:
+         * <ul>
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_LOCALE}
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR}
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR}
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_EDGE_COLOR}
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_EDGE_TYPE}
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_TYPEFACE}
+         * <li>{@link #ACCESSIBILITY_CAPTIONING_FONT_SCALE}
+         * </ul>
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_ENABLED =
+                "accessibility_captioning_enabled";
+
+        /**
+         * Setting that specifies the language for captions as a locale string,
+         * e.g. en_US.
+         *
+         * @see java.util.Locale#toString
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_LOCALE =
+                "accessibility_captioning_locale";
+
+        /**
+         * Integer property that specifies the preset style for captions, one
+         * of:
+         * <ul>
+         * <li>{@link android.view.accessibility.CaptioningManager.CaptionStyle#PRESET_CUSTOM}
+         * <li>a valid index of {@link android.view.accessibility.CaptioningManager.CaptionStyle#PRESETS}
+         * </ul>
+         *
+         * @see java.util.Locale#toString
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_PRESET =
+                "accessibility_captioning_preset";
+
+        /**
+         * Integer property that specifes the background color for captions as a
+         * packed 32-bit color.
+         *
+         * @see android.graphics.Color#argb
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR =
+                "accessibility_captioning_background_color";
+
+        /**
+         * Integer property that specifes the foreground color for captions as a
+         * packed 32-bit color.
+         *
+         * @see android.graphics.Color#argb
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR =
+                "accessibility_captioning_foreground_color";
+
+        /**
+         * Integer property that specifes the edge type for captions, one of:
+         * <ul>
+         * <li>{@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_NONE}
+         * <li>{@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_OUTLINE}
+         * <li>{@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_DROP_SHADOW}
+         * </ul>
+         *
+         * @see #ACCESSIBILITY_CAPTIONING_EDGE_COLOR
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_EDGE_TYPE =
+                "accessibility_captioning_edge_type";
+
+        /**
+         * Integer property that specifes the edge color for captions as a
+         * packed 32-bit color.
+         *
+         * @see #ACCESSIBILITY_CAPTIONING_EDGE_TYPE
+         * @see android.graphics.Color#argb
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_EDGE_COLOR =
+                "accessibility_captioning_edge_color";
+
+        /**
+         * String property that specifies the typeface for captions, one of:
+         * <ul>
+         * <li>DEFAULT
+         * <li>MONOSPACE
+         * <li>SANS_SERIF
+         * <li>SERIF
+         * </ul>
+         *
+         * @see android.graphics.Typeface
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_TYPEFACE =
+                "accessibility_captioning_typeface";
+
+        /**
+         * Floating point property that specifies font scaling for captions.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_CAPTIONING_FONT_SCALE =
+                "accessibility_captioning_font_scale";
+
+        /**
          * The timout for considering a press to be a long press in milliseconds.
          * @hide
          */
         public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
 
         /**
+         * List of the enabled print services.
+         * @hide
+         */
+        public static final String ENABLED_PRINT_SERVICES =
+            "enabled_print_services";
+
+        /**
+         * List of the system print services we enabled on first boot. On
+         * first boot we enable all system, i.e. bundled print services,
+         * once, so they work out-of-the-box.
+         * @hide
+         */
+        public static final String ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES =
+            "enabled_on_first_boot_system_print_services";
+
+        /**
          * Setting to always use the default text-to-speech settings regardless
          * of the application settings.
          * 1 = override application settings,
@@ -3968,6 +4241,14 @@
          */
         public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
 
+        /**
+         * Stores whether an user has consented to have apps verified through PAM.
+         * The value is boolean (1 or 0).
+         *
+         * @hide
+         */
+        public static final String PACKAGE_VERIFIER_USER_CONSENT =
+            "package_verifier_user_consent";
 
         /**
          * The {@link ComponentName} string of the selected spell checker service which is
@@ -4067,6 +4348,18 @@
         public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
 
         /**
+         * The default NFC payment component
+         * @hide
+         */
+        public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
+
+        /**
+         * Specifies the package name currently configured to be the primary sms application
+         * @hide
+         */
+        public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
+
+        /**
          * Name of a package that the current user has explicitly allowed to see all of that
          * user's notifications.
          *
@@ -4074,12 +4367,25 @@
          */
         public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
 
+        /** @hide */
+        public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
+
+        /** @hide */
+        public static final String TRANSIENT_NAV_CONFIRMATIONS = "transient_nav_confirmations";
+
         /**
-         * Whether or not to enable the dial pad autocomplete functionality.
+         * This is the query URI for finding a print service to install.
          *
          * @hide
          */
-        public static final String DIALPAD_AUTOCOMPLETE = "dialpad_autocomplete";
+        public static final String PRINT_SERVICE_SEARCH_URI = "print_service_search_uri";
+
+        /**
+         * This is the query URI for finding a NFC payment service to install.
+         *
+         * @hide
+         */
+        public static final String PAYMENT_SERVICE_SEARCH_URI = "payment_service_search_uri";
 
         /**
          * This are the settings to be backed up.
@@ -4106,6 +4412,14 @@
             TOUCH_EXPLORATION_ENABLED,
             ACCESSIBILITY_ENABLED,
             ACCESSIBILITY_SPEAK_PASSWORD,
+            ACCESSIBILITY_CAPTIONING_ENABLED,
+            ACCESSIBILITY_CAPTIONING_LOCALE,
+            ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
+            ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
+            ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
+            ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
+            ACCESSIBILITY_CAPTIONING_TYPEFACE,
+            ACCESSIBILITY_CAPTIONING_FONT_SCALE,
             TTS_USE_DEFAULTS,
             TTS_DEFAULT_RATE,
             TTS_DEFAULT_PITCH,
@@ -4121,16 +4435,20 @@
             MOUNT_UMS_AUTOSTART,
             MOUNT_UMS_PROMPT,
             MOUNT_UMS_NOTIFY_ENABLED,
-            UI_NIGHT_MODE,
-            DIALPAD_AUTOCOMPLETE
+            UI_NIGHT_MODE
         };
 
         /**
          * Helper method for determining if a location provider is enabled.
+         *
          * @param cr the content resolver to use
          * @param provider the location provider to query
          * @return true if the provider is enabled
+         *
+         * @deprecated use {@link #LOCATION_MODE} or
+         *             {@link LocationManager#isProviderEnabled(String)}
          */
+        @Deprecated
         public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
             return isLocationProviderEnabledForUser(cr, provider, UserHandle.myUserId());
         }
@@ -4141,8 +4459,11 @@
          * @param provider the location provider to query
          * @param userId the userId to query
          * @return true if the provider is enabled
+         * @deprecated use {@link #LOCATION_MODE} or
+         *             {@link LocationManager#isProviderEnabled(String)}
          * @hide
          */
+        @Deprecated
         public static final boolean isLocationProviderEnabledForUser(ContentResolver cr, String provider, int userId) {
             String allowedProviders = Settings.Secure.getStringForUser(cr,
                     LOCATION_PROVIDERS_ALLOWED, userId);
@@ -4154,7 +4475,9 @@
          * @param cr the content resolver to use
          * @param provider the location provider to enable or disable
          * @param enabled true if the provider should be enabled
+         * @deprecated use {@link #putInt(ContentResolver, String, int)} and {@link #LOCATION_MODE}
          */
+        @Deprecated
         public static final void setLocationProviderEnabled(ContentResolver cr,
                 String provider, boolean enabled) {
             setLocationProviderEnabledForUser(cr, provider, enabled, UserHandle.myUserId());
@@ -4162,24 +4485,99 @@
 
         /**
          * Thread-safe method for enabling or disabling a single location provider.
+         *
          * @param cr the content resolver to use
          * @param provider the location provider to enable or disable
          * @param enabled true if the provider should be enabled
          * @param userId the userId for which to enable/disable providers
+         * @return true if the value was set, false on database errors
+         * @deprecated use {@link #putIntForUser(ContentResolver, String, int, int)} and
+         *             {@link #LOCATION_MODE}
          * @hide
          */
-        public static final void setLocationProviderEnabledForUser(ContentResolver cr,
+        @Deprecated
+        public static final boolean setLocationProviderEnabledForUser(ContentResolver cr,
                 String provider, boolean enabled, int userId) {
-            // to ensure thread safety, we write the provider name with a '+' or '-'
-            // and let the SettingsProvider handle it rather than reading and modifying
-            // the list of enabled providers.
-            if (enabled) {
-                provider = "+" + provider;
-            } else {
-                provider = "-" + provider;
+            synchronized (mLocationSettingsLock) {
+                // to ensure thread safety, we write the provider name with a '+' or '-'
+                // and let the SettingsProvider handle it rather than reading and modifying
+                // the list of enabled providers.
+                if (enabled) {
+                    provider = "+" + provider;
+                } else {
+                    provider = "-" + provider;
+                }
+                return putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider,
+                        userId);
             }
-            putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider,
-                    userId);
+        }
+
+        /**
+         * Thread-safe method for setting the location mode to one of
+         * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
+         * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
+         *
+         * @param cr the content resolver to use
+         * @param mode such as {@link #LOCATION_MODE_HIGH_ACCURACY}
+         * @param userId the userId for which to change mode
+         * @return true if the value was set, false on database errors
+         *
+         * @throws IllegalArgumentException if mode is not one of the supported values
+         */
+        private static final boolean setLocationModeForUser(ContentResolver cr, int mode,
+                int userId) {
+            synchronized (mLocationSettingsLock) {
+                boolean gps = false;
+                boolean network = false;
+                switch (mode) {
+                    case LOCATION_MODE_OFF:
+                        break;
+                    case LOCATION_MODE_SENSORS_ONLY:
+                        gps = true;
+                        break;
+                    case LOCATION_MODE_BATTERY_SAVING:
+                        network = true;
+                        break;
+                    case LOCATION_MODE_HIGH_ACCURACY:
+                        gps = true;
+                        network = true;
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Invalid location mode: " + mode);
+                }
+                boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
+                        cr, LocationManager.GPS_PROVIDER, gps, userId);
+                boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser(
+                        cr, LocationManager.NETWORK_PROVIDER, network, userId);
+                return gpsSuccess && nlpSuccess;
+            }
+        }
+
+        /**
+         * Thread-safe method for reading the location mode, returns one of
+         * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
+         * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
+         *
+         * @param cr the content resolver to use
+         * @param userId the userId for which to read the mode
+         * @return the location mode
+         */
+        private static final int getLocationModeForUser(ContentResolver cr, int userId) {
+            synchronized (mLocationSettingsLock) {
+                boolean gpsEnabled = Settings.Secure.isLocationProviderEnabledForUser(
+                        cr, LocationManager.GPS_PROVIDER, userId);
+                boolean networkEnabled = Settings.Secure.isLocationProviderEnabledForUser(
+                        cr, LocationManager.NETWORK_PROVIDER, userId);
+                if (gpsEnabled && networkEnabled) {
+                    return LOCATION_MODE_HIGH_ACCURACY;
+                } else if (gpsEnabled) {
+                    return LOCATION_MODE_SENSORS_ONLY;
+                } else if (networkEnabled) {
+                    return LOCATION_MODE_BATTERY_SAVING;
+                } else {
+                    return LOCATION_MODE_OFF;
+                }
+            }
         }
     }
 
@@ -4776,6 +5174,29 @@
        public static final String WIFI_DISPLAY_ON = "wifi_display_on";
 
        /**
+        * Whether Wifi display certification mode is enabled/disabled
+        * 0=disabled. 1=enabled.
+        * @hide
+        */
+       public static final String WIFI_DISPLAY_CERTIFICATION_ON =
+               "wifi_display_certification_on";
+
+       /**
+        * WPS Configuration method used by Wifi display, this setting only
+        * takes effect when WIFI_DISPLAY_CERTIFICATION_ON is 1 (enabled).
+        *
+        * Possible values are:
+        *
+        * WpsInfo.INVALID: use default WPS method chosen by framework
+        * WpsInfo.PBC    : use Push button
+        * WpsInfo.KEYPAD : use Keypad
+        * WpsInfo.DISPLAY: use Display
+        * @hide
+        */
+       public static final String WIFI_DISPLAY_WPS_CONFIG =
+           "wifi_display_wps_config";
+
+       /**
         * Whether to notify the user of open networks.
         * <p>
         * If not connected and the scan results have an open network, we will
@@ -4800,12 +5221,6 @@
                "wifi_networks_available_repeat_delay";
 
        /**
-        * 802.11 country code in ISO 3166 format
-        * @hide
-        */
-       public static final String WIFI_COUNTRY_CODE = "wifi_country_code";
-
-       /**
         * The interval in milliseconds to issue wake up scans when wifi needs
         * to connect. This is necessary to connect to an access point when
         * device is on the move and the screen is off.
@@ -4937,6 +5352,13 @@
                "data_stall_alarm_aggressive_delay_in_ms";
 
        /**
+        * The number of milliseconds to allow the provisioning apn to remain active
+        * @hide
+        */
+       public static final String PROVISIONING_APN_ALARM_DELAY_IN_MS =
+               "provisioning_apn_alarm_delay_in_ms";
+
+       /**
         * The interval in milliseconds at which to check gprs registration
         * after the first registration mismatch of gprs and voice service,
         * to detect possible data network registration problems.
@@ -5124,6 +5546,25 @@
          */
         public static final String CONNECTIVITY_CHANGE_DELAY = "connectivity_change_delay";
 
+
+        /**
+         * Network sampling interval, in seconds. We'll generate link information
+         * about bytes/packets sent and error rates based on data sampled in this interval
+         *
+         * @hide
+         */
+
+        public static final String CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS =
+                "connectivity_sampling_interval_in_seconds";
+
+        /**
+         * The series of successively longer delays used in retrying to download PAC file.
+         * Last delay is used between successful PAC downloads.
+         *
+         * @hide
+         */
+        public static final String PAC_CHANGE_DELAY = "pac_change_delay";
+
         /**
          * Setting to turn off captive portal detection. Feature is enabled by
          * default and the setting needs to be set to 0 to disable it.
@@ -5219,6 +5660,13 @@
                 GLOBAL_HTTP_PROXY_EXCLUSION_LIST = "global_http_proxy_exclusion_list";
 
         /**
+         * The location PAC File for the proxy.
+         * @hide
+         */
+        public static final String
+                GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
+
+        /**
          * Enables the UI setting to allow the user to specify the global HTTP
          * proxy and associated exclusion list.
          *
@@ -5242,6 +5690,9 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
+        /** {@hide} */
+        public static final String
+                BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
 
         /**
          * Get the key that retrieves a bluetooth headset's priority.
@@ -5268,6 +5719,13 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth map priority.
+         * @hide
+         */
+        public static final String getBluetoothMapPriorityKey(String address) {
+            return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+        /**
          * Scaling factor for normal window animations. Setting to 0 will
          * disable window animations.
          */
@@ -5442,6 +5900,12 @@
         public static final String SELINUX_STATUS = "selinux_status";
 
         /**
+         * Developer setting to force RTL layout.
+         * @hide
+         */
+        public static final String DEVELOPMENT_FORCE_RTL = "debug.force_rtl";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index bfea9ca..2e0e59b 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -164,11 +164,19 @@
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn) {
-            NotificationListenerService.this.onNotificationPosted(sbn);
+            try {
+                NotificationListenerService.this.onNotificationPosted(sbn);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationPosted", t);
+            }
         }
         @Override
         public void onNotificationRemoved(StatusBarNotification sbn) {
-            NotificationListenerService.this.onNotificationRemoved(sbn);
+            try {
+                NotificationListenerService.this.onNotificationRemoved(sbn);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationRemoved", t);
+            }
         }
     }
 }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 19f8678..b5b9e14 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -33,23 +33,12 @@
     private final int uid;
     private final String basePkg;
     private final int initialPid;
-    // TODO: make this field private and move callers to an accessor that
-    // ensures sourceUser is applied.
-
     private final Notification notification;
     private final UserHandle user;
     private final long postTime;
 
     private final int score;
 
-    /** This is temporarily needed for the JB MR1 PDK.
-     * @hide */
-    @Deprecated
-    public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
-            Notification notification) {
-        this(pkg, id, tag, uid, initialPid, score, notification, UserHandle.OWNER);
-    }
-
     /** @hide */
     public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
             Notification notification, UserHandle user) {
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 457e66c..e991d84 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -55,7 +55,10 @@
      * <p>Starting this intent with just {@link Activity#startActivity(Intent)} is not supported.
      * You must either use {@link Activity#startActivityForResult(Intent, int)}, or provide a
      * PendingIntent, to receive recognition results.
-     * 
+     *
+     * <p>The implementation of this API is likely to stream audio to remote servers to perform
+     * speech recognition which can use a substantial amount of bandwidth.
+     *
      * <p>Required extras:
      * <ul>
      *   <li>{@link #EXTRA_LANGUAGE_MODEL}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 8fee41d..94aedbd 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -39,8 +39,14 @@
  * This class provides access to the speech recognition service. This service allows access to the
  * speech recognizer. Do not instantiate this class directly, instead, call
  * {@link SpeechRecognizer#createSpeechRecognizer(Context)}. This class's methods must be
- * invoked only from the main application thread. Please note that the application must have
- * {@link android.Manifest.permission#RECORD_AUDIO} permission to use this class.
+ * invoked only from the main application thread. 
+ *
+ * <p>The implementation of this API is likely to stream audio to remote servers to perform speech
+ * recognition. As such this API is not intended to be used for continuous recognition, which would
+ * consume a significant amount of battery and bandwidth.
+ *
+ * <p>Please note that the application must have {@link android.Manifest.permission#RECORD_AUDIO}
+ * permission to use this class.
  */
 public class SpeechRecognizer {
     /** DEBUG value to enable verbose debug prints */
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
index 6398d3d..12a026b 100644
--- a/core/java/android/speech/tts/SynthesisRequest.java
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -30,7 +30,7 @@
  * </ul>
  *
  * Any additional parameters sent to the text to speech service are passed in
- * uninterpreted, see the @code{params} argument in {@link TextToSpeech#speak}
+ * uninterpreted, see the {@code params} argument in {@link TextToSpeech#speak}
  * and {@link TextToSpeech#synthesizeToFile}.
  */
 public final class SynthesisRequest {
@@ -41,6 +41,7 @@
     private String mVariant;
     private int mSpeechRate;
     private int mPitch;
+    private int mCallerUid;
 
     public SynthesisRequest(String text, Bundle params) {
         mText = text;
@@ -98,6 +99,13 @@
     }
 
     /**
+     * Gets the request caller Uid.
+     */
+    public int getCallerUid() {
+        return mCallerUid;
+    }
+
+    /**
      * Sets the locale for the request.
      */
     void setLanguage(String language, String country, String variant) {
@@ -119,4 +127,11 @@
     void setPitch(int pitch) {
         mPitch = pitch;
     }
+
+    /**
+     * Sets Caller Uid
+     */
+    void setCallerUid(int uid) {
+        mCallerUid = uid;
+    }
 }
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 578a86e..b808363 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -561,7 +561,8 @@
      *            The context this instance is running in.
      * @param listener
      *            The {@link TextToSpeech.OnInitListener} that will be called when the
-     *            TextToSpeech engine has initialized.
+     *            TextToSpeech engine has initialized. In a case of a failure the listener
+     *            may be called immediately, before TextToSpeech instance is fully constructed.
      */
     public TextToSpeech(Context context, OnInitListener listener) {
         this(context, listener, null);
@@ -575,7 +576,8 @@
      *            The context this instance is running in.
      * @param listener
      *            The {@link TextToSpeech.OnInitListener} that will be called when the
-     *            TextToSpeech engine has initialized.
+     *            TextToSpeech engine has initialized. In a case of a failure the listener
+     *            may be called immediately, before TextToSpeech instance is fully constructed.
      * @param engine Package name of the TTS engine to use.
      */
     public TextToSpeech(Context context, OnInitListener listener, String engine) {
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 703dcff..575855c 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -557,11 +557,13 @@
         // guarded by 'this'.
         private AbstractSynthesisCallback mSynthesisCallback;
         private final EventLogger mEventLogger;
+        private final int mCallerUid;
 
         public SynthesisSpeechItem(Object callerIdentity, int callerUid, int callerPid,
                 Bundle params, String text) {
             super(callerIdentity, callerUid, callerPid, params);
             mText = text;
+            mCallerUid = callerUid;
             mSynthesisRequest = new SynthesisRequest(mText, mParams);
             mDefaultLocale = getSettingsLocale();
             setRequestParams(mSynthesisRequest);
@@ -611,7 +613,7 @@
         private void setRequestParams(SynthesisRequest request) {
             request.setLanguage(getLanguage(), getCountry(), getVariant());
             request.setSpeechRate(getSpeechRate());
-
+            request.setCallerUid(mCallerUid);
             request.setPitch(getPitch());
         }
 
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 2706bc7..5fbd22e 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -355,7 +355,18 @@
         return v1Locale;
     }
 
-    private String getDefaultLocale() {
+    /**
+     * Return the default device locale in form of 3 letter codes delimited by
+     * {@link #LOCALE_DELIMITER}:
+     * <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>
+     * </ul>
+     */
+    public String getDefaultLocale() {
         final Locale locale = Locale.getDefault();
 
         // Note that the default locale might have an empty variant
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java
index eacd40d..b1c07f5 100644
--- a/core/java/android/text/AndroidBidi.java
+++ b/core/java/android/text/AndroidBidi.java
@@ -60,6 +60,9 @@
      */
     public static Directions directions(int dir, byte[] levels, int lstart,
             char[] chars, int cstart, int len) {
+        if (len == 0) {
+            return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+        }
 
         int baseLevel = dir == Layout.DIR_LEFT_TO_RIGHT ? 0 : 1;
         int curLevel = levels[lstart];
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index a6e8c70..9dfd383 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1115,7 +1115,7 @@
 
         float dist = Math.abs(getPrimaryHorizontal(max) - horiz);
 
-        if (dist < bestdist) {
+        if (dist <= bestdist) {
             bestdist = dist;
             best = max;
         }
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 8929930..6efde05 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1288,6 +1288,47 @@
         return mFilters;
     }
 
+    // Same as SpannableStringInternal
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Spanned &&
+                toString().equals(o.toString())) {
+            // Check span data
+            Object[] otherSpans = ((Spanned) o).getSpans(0,
+                    ((Spanned) o).length(), Object.class);
+            if (mSpanCount == otherSpans.length) {
+                for (int i = 0; i < mSpanCount; ++i) {
+                    Object thisSpan = mSpans[i];
+                    Object otherSpan = otherSpans[i];
+                    if (!thisSpan.equals(otherSpan) ||
+                            getSpanStart(thisSpan) != getSpanStart(otherSpan) ||
+                            getSpanEnd(thisSpan) != getSpanEnd(otherSpan) ||
+                            getSpanFlags(thisSpan) != getSpanFlags(otherSpan)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    // Same as SpannableStringInternal
+    @Override
+    public int hashCode() {
+        int hash = toString().hashCode();
+        hash = hash * 31 + mSpanCount;
+        for (int i = 0; i < mSpanCount; ++i) {
+            Object span = mSpans[i];
+            hash = hash * 31 + span.hashCode();
+            hash = hash * 31 + getSpanStart(span);
+            hash = hash * 31 + getSpanEnd(span);
+            hash = hash * 31 + getSpanFlags(span);
+        }
+        return hash;
+    }
+
     private static final InputFilter[] NO_FILTERS = new InputFilter[0];
     private InputFilter[] mFilters = NO_FILTERS;
 
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 0825bf3..9b24a2e 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -358,6 +358,47 @@
         }
     }
 
+    // Same as SpannableStringBuilder
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Spanned &&
+                toString().equals(o.toString())) {
+            // Check span data
+            Object[] otherSpans = ((Spanned) o).getSpans(0,
+                    ((Spanned) o).length(), Object.class);
+            if (mSpanCount == otherSpans.length) {
+                for (int i = 0; i < mSpanCount; ++i) {
+                    Object thisSpan = mSpans[i];
+                    Object otherSpan = otherSpans[i];
+                    if (!thisSpan.equals(otherSpan) ||
+                            getSpanStart(thisSpan) != getSpanStart(otherSpan) ||
+                            getSpanEnd(thisSpan) != getSpanEnd(otherSpan) ||
+                            getSpanFlags(thisSpan) != getSpanFlags(otherSpan)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    // Same as SpannableStringBuilder
+    @Override
+    public int hashCode() {
+        int hash = toString().hashCode();
+        hash = hash * 31 + mSpanCount;
+        for (int i = 0; i < mSpanCount; ++i) {
+            Object span = mSpans[i];
+            hash = hash * 31 + span.hashCode();
+            hash = hash * 31 + getSpanStart(span);
+            hash = hash * 31 + getSpanEnd(span);
+            hash = hash * 31 + getSpanFlags(span);
+        }
+        return hash;
+    }
+
     private String mText;
     private Object[] mSpans;
     private int[] mSpanData;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 1291279..e7d6fda 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -474,6 +474,8 @@
                 mLineCount < mMaximumVisibleLineCount) {
             // Log.e("text", "output last " + bufEnd);
 
+            measured.setPara(source, bufStart, bufEnd, textDir);
+
             paint.getFontMetricsInt(fm);
 
             v = out(source,
@@ -482,7 +484,7 @@
                     v,
                     spacingmult, spacingadd, null,
                     null, fm, false,
-                    needMultiply, null, DEFAULT_DIR, true, bufEnd,
+                    needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
                     includepad, trackpad, null,
                     null, bufStart, ellipsize,
                     ellipsizedWidth, 0, paint, false);
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index e2035c2..596ca8c 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -19,6 +19,8 @@
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemProperties;
+import android.provider.Settings;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.AlignmentSpan;
 import android.text.style.BackgroundColorSpan;
@@ -1743,8 +1745,10 @@
                 return View.LAYOUT_DIRECTION_RTL;
             }
         }
-
-        return View.LAYOUT_DIRECTION_LTR;
+        // If forcing into RTL layout mode, return RTL as default, else LTR
+        return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false)
+                ? View.LAYOUT_DIRECTION_RTL
+                : View.LAYOUT_DIRECTION_LTR;
     }
 
     /**
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 30bb447..ba6f1d4 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -56,7 +56,7 @@
                     if (event.getAction() == KeyEvent.ACTION_DOWN
                             && event.getRepeatCount() == 0
                             && MetaKeyKeyListener.getMetaState(buffer,
-                                        MetaKeyKeyListener.META_SELECTING) != 0) {
+                                        MetaKeyKeyListener.META_SELECTING, event) != 0) {
                         return widget.showContextMenu();
                     }
                 }
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 4fede32..63607fa 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -75,7 +75,7 @@
         }
 
         // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
-        if (event.isAltPressed() || getMetaState(content, META_ALT_ON) == 1) {
+        if (getMetaState(content, META_ALT_ON, event) == 1) {
             if (deleteLine(view, content)) {
                 return true;
             }
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 113a4be..155a2c4 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -135,7 +135,7 @@
      */
     protected int getMovementMetaState(Spannable buffer, KeyEvent event) {
         // We ignore locked modifiers and SHIFT.
-        int metaState = (event.getMetaState() | MetaKeyKeyListener.getMetaState(buffer))
+        int metaState = MetaKeyKeyListener.getMetaState(buffer, event)
                 & ~(MetaKeyKeyListener.META_ALT_LOCKED | MetaKeyKeyListener.META_SYM_LOCKED);
         return KeyEvent.normalizeMetaState(metaState) & ~KeyEvent.META_SHIFT_MASK;
     }
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index ce51fae..bb8b0de 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -53,7 +53,7 @@
      * from the KeyEvent.
      */
     protected int lookup(KeyEvent event, Spannable content) {
-        int meta = event.getMetaState() | getMetaState(content);
+        int meta = getMetaState(content, event);
         int number = event.getNumber();
 
         /*
diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java
index aff233d..3855ff3 100644
--- a/core/java/android/text/method/LinkMovementMethod.java
+++ b/core/java/android/text/method/LinkMovementMethod.java
@@ -36,6 +36,11 @@
     private static final int DOWN = 3;
 
     @Override
+    public boolean canSelectArbitrarily() {
+        return true;
+    }
+
+    @Override
     protected boolean handleMovementKey(TextView widget, Spannable buffer, int keyCode,
             int movementMetaState, KeyEvent event) {
         switch (keyCode) {
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index 0a097f9..e9db5fd 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -135,6 +135,9 @@
     private static final Object SYM = new NoCopySpan.Concrete();
     private static final Object SELECTING = new NoCopySpan.Concrete();
 
+    private static final int PRESSED_RETURN_VALUE = 1;
+    private static final int LOCKED_RETURN_VALUE = 2;
+
     /**
      * Resets all meta state to inactive.
      */
@@ -161,9 +164,34 @@
     }
 
     /**
+     * Gets the state of the meta keys for a specific key event.
+     *
+     * For input devices that use toggled key modifiers, the `toggled' state
+     * is stored into the text buffer. This method retrieves the meta state
+     * for this event, accounting for the stored state. If the event has been
+     * created by a device that does not support toggled key modifiers, like
+     * a virtual device for example, the stored state is ignored.
+     *
+     * @param text the buffer in which the meta key would have been pressed.
+     * @param event the event for which to evaluate the meta state.
+     * @return an integer in which each bit set to one represents a pressed
+     *         or locked meta key.
+     */
+    public static final int getMetaState(final CharSequence text, final KeyEvent event) {
+        int metaState = event.getMetaState();
+        if (event.getKeyCharacterMap().getModifierBehavior()
+                == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
+            metaState |= getMetaState(text);
+        }
+        return metaState;
+    }
+
+    // As META_SELECTING is @hide we should not mention it in public comments, hence the
+    // omission in @param meta
+    /**
      * Gets the state of a particular meta key.
      *
-     * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON, or META_SELECTING
+     * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON
      * @param text the buffer in which the meta key would have been pressed.
      *
      * @return 0 if inactive, 1 if active, 2 if locked.
@@ -171,22 +199,53 @@
     public static final int getMetaState(CharSequence text, int meta) {
         switch (meta) {
             case META_SHIFT_ON:
-                return getActive(text, CAP, 1, 2);
+                return getActive(text, CAP, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE);
 
             case META_ALT_ON:
-                return getActive(text, ALT, 1, 2);
+                return getActive(text, ALT, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE);
 
             case META_SYM_ON:
-                return getActive(text, SYM, 1, 2);
+                return getActive(text, SYM, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE);
 
             case META_SELECTING:
-                return getActive(text, SELECTING, 1, 2);
+                return getActive(text, SELECTING, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE);
 
             default:
                 return 0;
         }
     }
 
+    /**
+     * Gets the state of a particular meta key to use with a particular key event.
+     *
+     * If the key event has been created by a device that does not support toggled
+     * key modifiers, like a virtual keyboard for example, only the meta state in
+     * the key event is considered.
+     *
+     * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON
+     * @param text the buffer in which the meta key would have been pressed.
+     * @param event the event for which to evaluate the meta state.
+     * @return 0 if inactive, 1 if active, 2 if locked.
+     */
+    public static final int getMetaState(final CharSequence text, final int meta,
+            final KeyEvent event) {
+        int metaState = event.getMetaState();
+        if (event.getKeyCharacterMap().getModifierBehavior()
+                == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
+            metaState |= getMetaState(text);
+        }
+        if (META_SELECTING == meta) {
+            // #getMetaState(long, int) does not support META_SELECTING, but we want the same
+            // behavior as #getMetaState(CharSequence, int) so we need to do it here
+            if ((metaState & META_SELECTING) != 0) {
+                // META_SELECTING is only ever set to PRESSED and can't be LOCKED, so return 1
+                return 1;
+            }
+            return 0;
+        }
+        return getMetaState(metaState, meta);
+    }
+
     private static int getActive(CharSequence text, Object meta,
                                  int on, int lock) {
         if (!(text instanceof Spanned)) {
@@ -430,18 +489,18 @@
     public static final int getMetaState(long state, int meta) {
         switch (meta) {
             case META_SHIFT_ON:
-                if ((state & META_CAP_LOCKED) != 0) return 2;
-                if ((state & META_SHIFT_ON) != 0) return 1;
+                if ((state & META_CAP_LOCKED) != 0) return LOCKED_RETURN_VALUE;
+                if ((state & META_SHIFT_ON) != 0) return PRESSED_RETURN_VALUE;
                 return 0;
 
             case META_ALT_ON:
-                if ((state & META_ALT_LOCKED) != 0) return 2;
-                if ((state & META_ALT_ON) != 0) return 1;
+                if ((state & META_ALT_LOCKED) != 0) return LOCKED_RETURN_VALUE;
+                if ((state & META_ALT_ON) != 0) return PRESSED_RETURN_VALUE;
                 return 0;
 
             case META_SYM_ON:
-                if ((state & META_SYM_LOCKED) != 0) return 2;
-                if ((state & META_SYM_ON) != 0) return 1;
+                if ((state & META_SYM_LOCKED) != 0) return LOCKED_RETURN_VALUE;
+                if ((state & META_SYM_ON) != 0) return PRESSED_RETURN_VALUE;
                 return 0;
 
             default:
@@ -599,4 +658,3 @@
     private static final int LOCKED = 
         Spannable.SPAN_MARK_MARK | (4 << Spannable.SPAN_USER_SHIFT);
 }
-
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 5d4c732..988d566 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -41,7 +41,7 @@
     protected abstract char[] getAcceptedChars();
 
     protected int lookup(KeyEvent event, Spannable content) {
-        return event.getMatch(getAcceptedChars(), event.getMetaState() | getMetaState(content));
+        return event.getMatch(getAcceptedChars(), getMetaState(content, event));
     }
 
     public CharSequence filter(CharSequence source, int start, int end,
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 98316ae..0bd46bc 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -108,7 +108,7 @@
 
         // QWERTY keyboard normal case
 
-        int i = event.getUnicodeChar(event.getMetaState() | getMetaState(content));
+        int i = event.getUnicodeChar(getMetaState(content, event));
 
         if (!mFullKeyboard) {
             int count = event.getRepeatCount();
diff --git a/core/java/android/transition/AutoTransition.java b/core/java/android/transition/AutoTransition.java
new file mode 100644
index 0000000..6e46021
--- /dev/null
+++ b/core/java/android/transition/AutoTransition.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.transition;
+
+/**
+ * Utility class for creating a default transition that automatically fades,
+ * moves, and resizes views during a scene change.
+ *
+ * <p>An AutoTransition can be described in a resource file by using the
+ * tag <code>autoTransition</code>, along with the other standard
+ * attributes of {@link android.R.styleable#Transition}.</p>
+ */
+public class AutoTransition extends TransitionSet {
+
+    /**
+     * Constructs an AutoTransition object, which is a TransitionSet which
+     * first fades out disappearing targets, then moves and resizes existing
+     * targets, and finally fades in appearing targets.
+     *
+     */
+    public AutoTransition() {
+        setOrdering(ORDERING_SEQUENTIAL);
+        addTransition(new Fade(Fade.OUT)).
+                addTransition(new ChangeBounds()).
+                addTransition(new Fade(Fade.IN));
+    }
+}
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
new file mode 100644
index 0000000..8053bff
--- /dev/null
+++ b/core/java/android/transition/ChangeBounds.java
@@ -0,0 +1,310 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Map;
+
+/**
+ * This transition captures the layout bounds of target views before and after
+ * the scene change and animates those changes during the transition.
+ *
+ * <p>A ChangeBounds transition can be described in a resource file by using the
+ * tag <code>changeBounds</code>, along with the other standard
+ * attributes of {@link android.R.styleable#Transition}.</p>
+ */
+public class ChangeBounds extends Transition {
+
+    private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
+    private static final String PROPNAME_PARENT = "android:changeBounds:parent";
+    private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX";
+    private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY";
+    private static final String[] sTransitionProperties = {
+            PROPNAME_BOUNDS,
+            PROPNAME_PARENT,
+            PROPNAME_WINDOW_X,
+            PROPNAME_WINDOW_Y
+    };
+
+    int[] tempLocation = new int[2];
+    boolean mResizeClip = false;
+    boolean mReparent = false;
+    private static final String LOG_TAG = "ChangeBounds";
+
+    private static RectEvaluator sRectEvaluator = new RectEvaluator();
+
+    @Override
+    public String[] getTransitionProperties() {
+        return sTransitionProperties;
+    }
+
+    public void setResizeClip(boolean resizeClip) {
+        mResizeClip = resizeClip;
+    }
+
+    /**
+     * Setting this flag tells ChangeBounds to track the before/after parent
+     * of every view using this transition. The flag is not enabled by
+     * default because it requires the parent instances to be the same
+     * in the two scenes or else all parents must use ids to allow
+     * the transition to determine which parents are the same.
+     *
+     * @param reparent true if the transition should track the parent
+     * container of target views and animate parent changes.
+     */
+    public void setReparent(boolean reparent) {
+        mReparent = reparent;
+    }
+
+    private void captureValues(TransitionValues values) {
+        View view = values.view;
+        values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
+                view.getRight(), view.getBottom()));
+        values.values.put(PROPNAME_PARENT, values.view.getParent());
+        values.view.getLocationInWindow(tempLocation);
+        values.values.put(PROPNAME_WINDOW_X, tempLocation[0]);
+        values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]);
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null || endValues == null) {
+            return null;
+        }
+        Map<String, Object> startParentVals = startValues.values;
+        Map<String, Object> endParentVals = endValues.values;
+        ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT);
+        ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT);
+        if (startParent == null || endParent == null) {
+            return null;
+        }
+        final View view = endValues.view;
+        boolean parentsEqual = (startParent == endParent) ||
+                (startParent.getId() == endParent.getId());
+        // TODO: Might want reparenting to be separate/subclass transition, or at least
+        // triggered by a property on ChangeBounds. Otherwise, we're forcing the requirement that
+        // all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect
+        // of reparenting the views.
+        if (!mReparent || parentsEqual) {
+            Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+            Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+            int startLeft = startBounds.left;
+            int endLeft = endBounds.left;
+            int startTop = startBounds.top;
+            int endTop = endBounds.top;
+            int startRight = startBounds.right;
+            int endRight = endBounds.right;
+            int startBottom = startBounds.bottom;
+            int endBottom = endBounds.bottom;
+            int startWidth = startRight - startLeft;
+            int startHeight = startBottom - startTop;
+            int endWidth = endRight - endLeft;
+            int endHeight = endBottom - endTop;
+            int numChanges = 0;
+            if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
+                if (startLeft != endLeft) ++numChanges;
+                if (startTop != endTop) ++numChanges;
+                if (startRight != endRight) ++numChanges;
+                if (startBottom != endBottom) ++numChanges;
+            }
+            if (numChanges > 0) {
+                if (!mResizeClip) {
+                    PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
+                    int pvhIndex = 0;
+                    if (startLeft != endLeft) view.setLeft(startLeft);
+                    if (startTop != endTop) view.setTop(startTop);
+                    if (startRight != endRight) view.setRight(startRight);
+                    if (startBottom != endBottom) view.setBottom(startBottom);
+                    if (startLeft != endLeft) {
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("left", startLeft, endLeft);
+                    }
+                    if (startTop != endTop) {
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("top", startTop, endTop);
+                    }
+                    if (startRight != endRight) {
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("right",
+                                startRight, endRight);
+                    }
+                    if (startBottom != endBottom) {
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("bottom",
+                                startBottom, endBottom);
+                    }
+                    ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
+                    if (view.getParent() instanceof ViewGroup) {
+                        final ViewGroup parent = (ViewGroup) view.getParent();
+                        parent.suppressLayout(true);
+                        TransitionListener transitionListener = new TransitionListenerAdapter() {
+                            boolean mCanceled = false;
+
+                            @Override
+                            public void onTransitionCancel(Transition transition) {
+                                parent.suppressLayout(false);
+                                mCanceled = true;
+                            }
+
+                            @Override
+                            public void onTransitionEnd(Transition transition) {
+                                if (!mCanceled) {
+                                    parent.suppressLayout(false);
+                                }
+                            }
+
+                            @Override
+                            public void onTransitionPause(Transition transition) {
+                                parent.suppressLayout(false);
+                            }
+
+                            @Override
+                            public void onTransitionResume(Transition transition) {
+                                parent.suppressLayout(true);
+                            }
+                        };
+                        addListener(transitionListener);
+                    }
+                    return anim;
+                } else {
+                    if (startWidth != endWidth) view.setRight(endLeft +
+                            Math.max(startWidth, endWidth));
+                    if (startHeight != endHeight) view.setBottom(endTop +
+                            Math.max(startHeight, endHeight));
+                    // TODO: don't clobber TX/TY
+                    if (startLeft != endLeft) view.setTranslationX(startLeft - endLeft);
+                    if (startTop != endTop) view.setTranslationY(startTop - endTop);
+                    // Animate location with translationX/Y and size with clip bounds
+                    float transXDelta = endLeft - startLeft;
+                    float transYDelta = endTop - startTop;
+                    int widthDelta = endWidth - startWidth;
+                    int heightDelta = endHeight - startHeight;
+                    numChanges = 0;
+                    if (transXDelta != 0) numChanges++;
+                    if (transYDelta != 0) numChanges++;
+                    if (widthDelta != 0 || heightDelta != 0) numChanges++;
+                    PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
+                    int pvhIndex = 0;
+                    if (transXDelta != 0) {
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationX",
+                                view.getTranslationX(), 0);
+                    }
+                    if (transYDelta != 0) {
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationY",
+                                view.getTranslationY(), 0);
+                    }
+                    if (widthDelta != 0 || heightDelta != 0) {
+                        Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight);
+                        Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight);
+                        pvh[pvhIndex++] = PropertyValuesHolder.ofObject("clipBounds",
+                                sRectEvaluator, tempStartBounds, tempEndBounds);
+                    }
+                    ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
+                    if (view.getParent() instanceof ViewGroup) {
+                        final ViewGroup parent = (ViewGroup) view.getParent();
+                        parent.suppressLayout(true);
+                        TransitionListener transitionListener = new TransitionListenerAdapter() {
+                            boolean mCanceled = false;
+
+                            @Override
+                            public void onTransitionCancel(Transition transition) {
+                                parent.suppressLayout(false);
+                                mCanceled = true;
+                            }
+
+                            @Override
+                            public void onTransitionEnd(Transition transition) {
+                                if (!mCanceled) {
+                                    parent.suppressLayout(false);
+                                }
+                            }
+
+                            @Override
+                            public void onTransitionPause(Transition transition) {
+                                parent.suppressLayout(false);
+                            }
+
+                            @Override
+                            public void onTransitionResume(Transition transition) {
+                                parent.suppressLayout(true);
+                            }
+                        };
+                        addListener(transitionListener);
+                    }
+                    anim.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            view.setClipBounds(null);
+                        }
+                    });
+                    return anim;
+                }
+            }
+        } else {
+            int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X);
+            int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y);
+            int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X);
+            int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y);
+            // TODO: also handle size changes: check bounds and animate size changes
+            if (startX != endX || startY != endY) {
+                sceneRoot.getLocationInWindow(tempLocation);
+                Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
+                        Bitmap.Config.ARGB_8888);
+                Canvas canvas = new Canvas(bitmap);
+                view.draw(canvas);
+                final BitmapDrawable drawable = new BitmapDrawable(bitmap);
+                view.setVisibility(View.INVISIBLE);
+                sceneRoot.getOverlay().add(drawable);
+                Rect startBounds1 = new Rect(startX - tempLocation[0], startY - tempLocation[1],
+                        startX - tempLocation[0] + view.getWidth(),
+                        startY - tempLocation[1] + view.getHeight());
+                Rect endBounds1 = new Rect(endX - tempLocation[0], endY - tempLocation[1],
+                        endX - tempLocation[0] + view.getWidth(),
+                        endY - tempLocation[1] + view.getHeight());
+                ObjectAnimator anim = ObjectAnimator.ofObject(drawable, "bounds",
+                        sRectEvaluator, startBounds1, endBounds1);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        sceneRoot.getOverlay().remove(drawable);
+                        view.setVisibility(View.VISIBLE);
+                    }
+                });
+                return anim;
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/transition/ChangeText.java b/core/java/android/transition/ChangeText.java
new file mode 100644
index 0000000..b1be70f
--- /dev/null
+++ b/core/java/android/transition/ChangeText.java
@@ -0,0 +1,308 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.Map;
+
+/**
+ * This transition tracks changes to the text in TextView targets. If the text
+ * changes between the start and end scenes, the transition ensures that the
+ * starting text stays until the transition ends, at which point it changes
+ * to the end text.  This is useful in situations where you want to resize a
+ * text view to its new size before displaying the text that goes there.
+ *
+ * @hide
+ */
+public class ChangeText extends Transition {
+
+    private static final String LOG_TAG = "TextChange";
+
+    private static final String PROPNAME_TEXT = "android:textchange:text";
+    private static final String PROPNAME_TEXT_SELECTION_START =
+            "android:textchange:textSelectionStart";
+    private static final String PROPNAME_TEXT_SELECTION_END =
+            "android:textchange:textSelectionEnd";
+    private static final String PROPNAME_TEXT_COLOR = "android:textchange:textColor";
+
+    private int mChangeBehavior = CHANGE_BEHAVIOR_KEEP;
+
+    /**
+     * Flag specifying that the text in affected/changing TextView targets will keep
+     * their original text during the transition, setting it to the final text when
+     * the transition ends. This is the default behavior.
+     *
+     * @see #setChangeBehavior(int)
+     */
+    public static final int CHANGE_BEHAVIOR_KEEP = 0;
+    /**
+     * Flag specifying that the text changing animation should first fade
+     * out the original text completely. The new text is set on the target
+     * view at the end of the fade-out animation. This transition is typically
+     * used with a later {@link #CHANGE_BEHAVIOR_IN} transition, allowing more
+     * flexibility than the {@link #CHANGE_BEHAVIOR_OUT_IN} by allowing other
+     * transitions to be run sequentially or in parallel with these fades.
+     *
+     * @see #setChangeBehavior(int)
+     */
+    public static final int CHANGE_BEHAVIOR_OUT = 1;
+    /**
+     * Flag specifying that the text changing animation should fade in the
+     * end text into the affected target view(s). This transition is typically
+     * used in conjunction with an earlier {@link #CHANGE_BEHAVIOR_OUT}
+     * transition, possibly with other transitions running as well, such as
+     * a sequence to fade out, then resize the view, then fade in.
+     *
+     * @see #setChangeBehavior(int)
+     */
+    public static final int CHANGE_BEHAVIOR_IN = 2;
+    /**
+     * Flag specifying that the text changing animation should first fade
+     * out the original text completely and then fade in the
+     * new text.
+     *
+     * @see #setChangeBehavior(int)
+     */
+    public static final int CHANGE_BEHAVIOR_OUT_IN = 3;
+
+    private static final String[] sTransitionProperties = {
+            PROPNAME_TEXT,
+            PROPNAME_TEXT_SELECTION_START,
+            PROPNAME_TEXT_SELECTION_END
+    };
+
+    /**
+     * Sets the type of changing animation that will be run, one of
+     * {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT},
+     * {@link #CHANGE_BEHAVIOR_IN}, and {@link #CHANGE_BEHAVIOR_OUT_IN}.
+     *
+     * @param changeBehavior The type of fading animation to use when this
+     * transition is run.
+     * @return this textChange object.
+     */
+    public ChangeText setChangeBehavior(int changeBehavior) {
+        if (changeBehavior >= CHANGE_BEHAVIOR_KEEP && changeBehavior <= CHANGE_BEHAVIOR_OUT_IN) {
+            mChangeBehavior = changeBehavior;
+        }
+        return this;
+    }
+
+    @Override
+    public String[] getTransitionProperties() {
+        return sTransitionProperties;
+    }
+
+    /**
+     * Returns the type of changing animation that will be run.
+     *
+     * @return either {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT},
+     * {@link #CHANGE_BEHAVIOR_IN}, or {@link #CHANGE_BEHAVIOR_OUT_IN}.
+     */
+    public int getChangeBehavior() {
+        return mChangeBehavior;
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        if (transitionValues.view instanceof TextView) {
+            TextView textview = (TextView) transitionValues.view;
+            transitionValues.values.put(PROPNAME_TEXT, textview.getText());
+            if (textview instanceof EditText) {
+                transitionValues.values.put(PROPNAME_TEXT_SELECTION_START,
+                        textview.getSelectionStart());
+                transitionValues.values.put(PROPNAME_TEXT_SELECTION_END,
+                        textview.getSelectionEnd());
+            }
+            if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
+                transitionValues.values.put(PROPNAME_TEXT_COLOR, textview.getCurrentTextColor());
+            }
+        }
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null || endValues == null ||
+                !(startValues.view instanceof TextView) || !(endValues.view instanceof TextView)) {
+            return null;
+        }
+        final TextView view = (TextView) endValues.view;
+        Map<String, Object> startVals = startValues.values;
+        Map<String, Object> endVals = endValues.values;
+        final CharSequence startText = startVals.get(PROPNAME_TEXT) != null ?
+                (CharSequence) startVals.get(PROPNAME_TEXT) : "";
+        final CharSequence endText = endVals.get(PROPNAME_TEXT) != null ?
+                (CharSequence) endVals.get(PROPNAME_TEXT) : "";
+        final int startSelectionStart, startSelectionEnd, endSelectionStart, endSelectionEnd;
+        if (view instanceof EditText) {
+            startSelectionStart = startVals.get(PROPNAME_TEXT_SELECTION_START) != null ?
+                    (Integer) startVals.get(PROPNAME_TEXT_SELECTION_START) : -1;
+            startSelectionEnd = startVals.get(PROPNAME_TEXT_SELECTION_END) != null ?
+                    (Integer) startVals.get(PROPNAME_TEXT_SELECTION_END) : startSelectionStart;
+            endSelectionStart = endVals.get(PROPNAME_TEXT_SELECTION_START) != null ?
+                    (Integer) endVals.get(PROPNAME_TEXT_SELECTION_START) : -1;
+            endSelectionEnd = endVals.get(PROPNAME_TEXT_SELECTION_END) != null ?
+                    (Integer) endVals.get(PROPNAME_TEXT_SELECTION_END) : endSelectionStart;
+        } else {
+            startSelectionStart = startSelectionEnd = endSelectionStart = endSelectionEnd = -1;
+        }
+        if (!startText.equals(endText)) {
+            final int startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR);
+            final int endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR);
+            if (mChangeBehavior != CHANGE_BEHAVIOR_IN) {
+                view.setText(startText);
+                if (view instanceof EditText) {
+                    setSelection(((EditText) view), startSelectionStart, startSelectionEnd);
+                }
+            }
+            Animator anim;
+            if (mChangeBehavior == CHANGE_BEHAVIOR_KEEP) {
+                anim = ValueAnimator.ofFloat(0, 1);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        if (startText.equals(view.getText())) {
+                            // Only set if it hasn't been changed since anim started
+                            view.setText(endText);
+                            if (view instanceof EditText) {
+                                setSelection(((EditText) view), endSelectionStart, endSelectionEnd);
+                            }
+                        }
+                    }
+                });
+            } else {
+                // Fade out start text
+                ValueAnimator outAnim = null, inAnim = null;
+                if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN ||
+                        mChangeBehavior == CHANGE_BEHAVIOR_OUT) {
+                    outAnim = ValueAnimator.ofInt(255, 0);
+                    outAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                        @Override
+                        public void onAnimationUpdate(ValueAnimator animation) {
+                            int currAlpha = (Integer) animation.getAnimatedValue();
+                            view.setTextColor(currAlpha << 24 | startColor & 0xff0000 |
+                                    startColor & 0xff00 | startColor & 0xff);
+                        }
+                    });
+                    outAnim.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            if (startText.equals(view.getText())) {
+                                // Only set if it hasn't been changed since anim started
+                                view.setText(endText);
+                                if (view instanceof EditText) {
+                                    setSelection(((EditText) view), endSelectionStart,
+                                            endSelectionEnd);
+                                }
+                            }
+                            // restore opaque alpha and correct end color
+                            view.setTextColor(endColor);
+                        }
+                    });
+                }
+                if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN ||
+                        mChangeBehavior == CHANGE_BEHAVIOR_IN) {
+                    inAnim = ValueAnimator.ofInt(0, 255);
+                    inAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                        @Override
+                        public void onAnimationUpdate(ValueAnimator animation) {
+                            int currAlpha = (Integer) animation.getAnimatedValue();
+                            view.setTextColor(currAlpha << 24 | Color.red(endColor) << 16 |
+                                    Color.green(endColor) << 8 | Color.red(endColor));
+                        }
+                    });
+                    inAnim.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationCancel(Animator animation) {
+                            // restore opaque alpha and correct end color
+                            view.setTextColor(endColor);
+                        }
+                    });
+                }
+                if (outAnim != null && inAnim != null) {
+                    anim = new AnimatorSet();
+                    ((AnimatorSet) anim).playSequentially(outAnim, inAnim);
+                } else if (outAnim != null) {
+                    anim = outAnim;
+                } else {
+                    // Must be an in-only animation
+                    anim = inAnim;
+                }
+            }
+            TransitionListener transitionListener = new TransitionListenerAdapter() {
+                int mPausedColor = 0;
+
+                @Override
+                public void onTransitionPause(Transition transition) {
+                    if (mChangeBehavior != CHANGE_BEHAVIOR_IN) {
+                        view.setText(endText);
+                        if (view instanceof EditText) {
+                            setSelection(((EditText) view), endSelectionStart, endSelectionEnd);
+                        }
+                    }
+                    if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
+                        mPausedColor = view.getCurrentTextColor();
+                        view.setTextColor(endColor);
+                    }
+                }
+
+                @Override
+                public void onTransitionResume(Transition transition) {
+                    if (mChangeBehavior != CHANGE_BEHAVIOR_IN) {
+                        view.setText(startText);
+                        if (view instanceof EditText) {
+                            setSelection(((EditText) view), startSelectionStart, startSelectionEnd);
+                        }
+                    }
+                    if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
+                        view.setTextColor(mPausedColor);
+                    }
+                }
+            };
+            addListener(transitionListener);
+            if (DBG) {
+                Log.d(LOG_TAG, "createAnimator returning " + anim);
+            }
+            return anim;
+        }
+        return null;
+    }
+
+    private void setSelection(EditText editText, int start, int end) {
+        if (start >= 0 && end >= 0) {
+            editText.setSelection(start, end);
+        }
+    }
+}
diff --git a/core/java/android/transition/Crossfade.java b/core/java/android/transition/Crossfade.java
new file mode 100644
index 0000000..69ce872
--- /dev/null
+++ b/core/java/android/transition/Crossfade.java
@@ -0,0 +1,296 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.util.Log;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOverlay;
+
+import java.util.Map;
+
+/**
+ * This transition captures bitmap representations of target views before and
+ * after the scene change and fades between them.
+ *
+ * <p>Note: This transition is not compatible with {@link TextureView}
+ * or {@link SurfaceView}.</p>
+ *
+ * @hide
+ */
+public class Crossfade extends Transition {
+    // TODO: Add a hook that lets a Transition call user code to query whether it should run on
+    // a given target view. This would save bitmap comparisons in this transition, for example.
+
+    private static final String LOG_TAG = "Crossfade";
+
+    private static final String PROPNAME_BITMAP = "android:crossfade:bitmap";
+    private static final String PROPNAME_DRAWABLE = "android:crossfade:drawable";
+    private static final String PROPNAME_BOUNDS = "android:crossfade:bounds";
+
+    private static RectEvaluator sRectEvaluator = new RectEvaluator();
+
+    private int mFadeBehavior = FADE_BEHAVIOR_REVEAL;
+    private int mResizeBehavior = RESIZE_BEHAVIOR_SCALE;
+
+    /**
+     * Flag specifying that the fading animation should cross-fade
+     * between the old and new representation of all affected target
+     * views. This means that the old representation will fade out
+     * while the new one fades in. This effect may work well on views
+     * without solid backgrounds, such as TextViews.
+     *
+     * @see #setFadeBehavior(int)
+     */
+    public static final int FADE_BEHAVIOR_CROSSFADE = 0;
+    /**
+     * Flag specifying that the fading animation should reveal the
+     * new representation of all affected target views. This means
+     * that the old representation will fade out, gradually
+     * revealing the new representation, which remains opaque
+     * the whole time. This effect may work well on views
+     * with solid backgrounds, such as ImageViews.
+     *
+     * @see #setFadeBehavior(int)
+     */
+    public static final int FADE_BEHAVIOR_REVEAL = 1;
+    /**
+     * Flag specifying that the fading animation should first fade
+     * out the original representation completely and then fade in the
+     * new one. This effect may be more suitable than the other
+     * fade behaviors for views with.
+     *
+     * @see #setFadeBehavior(int)
+     */
+    public static final int FADE_BEHAVIOR_OUT_IN = 2;
+
+    /**
+     * Flag specifying that the transition should not animate any
+     * changes in size between the old and new target views.
+     * This means that no scaling will take place as a result of
+     * this transition
+     *
+     * @see #setResizeBehavior(int)
+     */
+    public static final int RESIZE_BEHAVIOR_NONE = 0;
+    /**
+     * Flag specifying that the transition should animate any
+     * changes in size between the old and new target views.
+     * This means that the animation will scale the start/end
+     * representations of affected views from the starting size
+     * to the ending size over the course of the animation.
+     * This effect may work well on images, but is not recommended
+     * for text.
+     *
+     * @see #setResizeBehavior(int)
+     */
+    public static final int RESIZE_BEHAVIOR_SCALE = 1;
+
+    // TODO: Add fade/resize behaviors to xml resources
+
+    /**
+     * Sets the type of fading animation that will be run, one of
+     * {@link #FADE_BEHAVIOR_CROSSFADE} and {@link #FADE_BEHAVIOR_REVEAL}.
+     *
+     * @param fadeBehavior The type of fading animation to use when this
+     * transition is run.
+     */
+    public Crossfade setFadeBehavior(int fadeBehavior) {
+        if (fadeBehavior >= FADE_BEHAVIOR_CROSSFADE && fadeBehavior <= FADE_BEHAVIOR_OUT_IN) {
+            mFadeBehavior = fadeBehavior;
+        }
+        return this;
+    }
+
+    /**
+     * Returns the fading behavior of the animation.
+     *
+     * @return This crossfade object.
+     * @see #setFadeBehavior(int)
+     */
+    public int getFadeBehavior() {
+        return mFadeBehavior;
+    }
+
+    /**
+     * Sets the type of resizing behavior that will be used during the
+     * transition animation, one of {@link #RESIZE_BEHAVIOR_NONE} and
+     * {@link #RESIZE_BEHAVIOR_SCALE}.
+     *
+     * @param resizeBehavior The type of resizing behavior to use when this
+     * transition is run.
+     */
+    public Crossfade setResizeBehavior(int resizeBehavior) {
+        if (resizeBehavior >= RESIZE_BEHAVIOR_NONE && resizeBehavior <= RESIZE_BEHAVIOR_SCALE) {
+            mResizeBehavior = resizeBehavior;
+        }
+        return this;
+    }
+
+    /**
+     * Returns the resizing behavior of the animation.
+     *
+     * @return This crossfade object.
+     * @see #setResizeBehavior(int)
+     */
+    public int getResizeBehavior() {
+        return mResizeBehavior;
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null || endValues == null) {
+            return null;
+        }
+        final boolean useParentOverlay = mFadeBehavior != FADE_BEHAVIOR_REVEAL;
+        final View view = endValues.view;
+        Map<String, Object> startVals = startValues.values;
+        Map<String, Object> endVals = endValues.values;
+        Rect startBounds = (Rect) startVals.get(PROPNAME_BOUNDS);
+        Rect endBounds = (Rect) endVals.get(PROPNAME_BOUNDS);
+        Bitmap startBitmap = (Bitmap) startVals.get(PROPNAME_BITMAP);
+        Bitmap endBitmap = (Bitmap) endVals.get(PROPNAME_BITMAP);
+        final BitmapDrawable startDrawable = (BitmapDrawable) startVals.get(PROPNAME_DRAWABLE);
+        final BitmapDrawable endDrawable = (BitmapDrawable) endVals.get(PROPNAME_DRAWABLE);
+        if (Transition.DBG) {
+            Log.d(LOG_TAG, "StartBitmap.sameAs(endBitmap) = " + startBitmap.sameAs(endBitmap) +
+                    " for start, end: " + startBitmap + ", " + endBitmap);
+        }
+        if (startDrawable != null && endDrawable != null && !startBitmap.sameAs(endBitmap)) {
+            ViewOverlay overlay = useParentOverlay ?
+                    ((ViewGroup) view.getParent()).getOverlay() : view.getOverlay();
+            if (mFadeBehavior == FADE_BEHAVIOR_REVEAL) {
+                overlay.add(endDrawable);
+            }
+            overlay.add(startDrawable);
+            // The transition works by placing the end drawable under the start drawable and
+            // gradually fading out the start drawable. So it's not really a cross-fade, but rather
+            // a reveal of the end scene over time. Also, animate the bounds of both drawables
+            // to mimic the change in the size of the view itself between scenes.
+            ObjectAnimator anim;
+            if (mFadeBehavior == FADE_BEHAVIOR_OUT_IN) {
+                // Fade out completely halfway through the transition
+                anim = ObjectAnimator.ofInt(startDrawable, "alpha", 255, 0, 0);
+            } else {
+                anim = ObjectAnimator.ofInt(startDrawable, "alpha", 0);
+            }
+            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    // TODO: some way to auto-invalidate views based on drawable changes? callbacks?
+                    view.invalidate(startDrawable.getBounds());
+                }
+            });
+            ObjectAnimator anim1 = null;
+            if (mFadeBehavior == FADE_BEHAVIOR_OUT_IN) {
+                // start fading in halfway through the transition
+                anim1 = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 0, 1);
+            } else if (mFadeBehavior == FADE_BEHAVIOR_CROSSFADE) {
+                anim1 = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1);
+            }
+            if (Transition.DBG) {
+                Log.d(LOG_TAG, "Crossfade: created anim " + anim + " for start, end values " +
+                        startValues + ", " + endValues);
+            }
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    ViewOverlay overlay = useParentOverlay ?
+                            ((ViewGroup) view.getParent()).getOverlay() : view.getOverlay();
+                    overlay.remove(startDrawable);
+                    if (mFadeBehavior == FADE_BEHAVIOR_REVEAL) {
+                        overlay.remove(endDrawable);
+                    }
+                }
+            });
+            AnimatorSet set = new AnimatorSet();
+            set.playTogether(anim);
+            if (anim1 != null) {
+                set.playTogether(anim1);
+            }
+            if (mResizeBehavior == RESIZE_BEHAVIOR_SCALE && !startBounds.equals(endBounds)) {
+                if (Transition.DBG) {
+                    Log.d(LOG_TAG, "animating from startBounds to endBounds: " +
+                            startBounds + ", " + endBounds);
+                }
+                Animator anim2 = ObjectAnimator.ofObject(startDrawable, "bounds",
+                        sRectEvaluator, startBounds, endBounds);
+                set.playTogether(anim2);
+                if (mResizeBehavior == RESIZE_BEHAVIOR_SCALE) {
+                    // TODO: How to handle resizing with a CROSSFADE (vs. REVEAL) effect
+                    // when we are animating the view directly?
+                    Animator anim3 = ObjectAnimator.ofObject(endDrawable, "bounds",
+                            sRectEvaluator, startBounds, endBounds);
+                    set.playTogether(anim3);
+                }
+            }
+            return set;
+        } else {
+            return null;
+        }
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        View view = transitionValues.view;
+        Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
+        if (mFadeBehavior != FADE_BEHAVIOR_REVEAL) {
+            bounds.offset(view.getLeft(), view.getTop());
+        }
+        transitionValues.values.put(PROPNAME_BOUNDS, bounds);
+
+        if (Transition.DBG) {
+            Log.d(LOG_TAG, "Captured bounds " + transitionValues.values.get(PROPNAME_BOUNDS));
+        }
+        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
+                Bitmap.Config.ARGB_8888);
+        if (view instanceof TextureView) {
+            bitmap = ((TextureView) view).getBitmap();
+        } else {
+            Canvas c = new Canvas(bitmap);
+            view.draw(c);
+        }
+        transitionValues.values.put(PROPNAME_BITMAP, bitmap);
+        // TODO: I don't have resources, can't call the non-deprecated method?
+        BitmapDrawable drawable = new BitmapDrawable(bitmap);
+        // TODO: lrtb will be wrong if the view has transXY set
+        drawable.setBounds(bounds);
+        transitionValues.values.put(PROPNAME_DRAWABLE, drawable);
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+}
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
new file mode 100644
index 0000000..8edb1ff
--- /dev/null
+++ b/core/java/android/transition/Fade.java
@@ -0,0 +1,342 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition tracks changes to the visibility of target views in the
+ * start and end scenes and fades views in or out when they become visible
+ * or non-visible. Visibility is determined by both the
+ * {@link View#setVisibility(int)} state of the view as well as whether it
+ * is parented in the current view hierarchy.
+ *
+ * <p>The ability of this transition to fade out a particular view, and the
+ * way that that fading operation takes place, is based on
+ * the situation of the view in the view hierarchy. For example, if a view was
+ * simply removed from its parent, then the view will be added into a {@link
+ * android.view.ViewGroupOverlay} while fading. If a visible view is
+ * changed to be {@link View#GONE} or {@link View#INVISIBLE}, then the
+ * visibility will be changed to {@link View#VISIBLE} for the duration of
+ * the animation. However, if a view is in a hierarchy which is also altering
+ * its visibility, the situation can be more complicated. In general, if a
+ * view that is no longer in the hierarchy in the end scene still has a
+ * parent (so its parent hierarchy was removed, but it was not removed from
+ * its parent), then it will be left alone to avoid side-effects from
+ * improperly removing it from its parent. The only exception to this is if
+ * the previous {@link Scene} was
+ * {@link Scene#getSceneForLayout(android.view.ViewGroup, int, android.content.Context)
+ * created from a layout resource file}, then it is considered safe to un-parent
+ * the starting scene view in order to fade it out.</p>
+ *
+ * <p>A Fade transition can be described in a resource file by using the
+ * tag <code>fade</code>, along with the standard
+ * attributes of {@link android.R.styleable#Fade} and
+ * {@link android.R.styleable#Transition}.</p>
+
+ */
+public class Fade extends Visibility {
+
+    private static boolean DBG = Transition.DBG && false;
+
+    private static final String LOG_TAG = "Fade";
+    private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
+    private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
+
+    /**
+     * Fading mode used in {@link #Fade(int)} to make the transition
+     * operate on targets that are appearing. Maybe be combined with
+     * {@link #OUT} to fade both in and out.
+     */
+    public static final int IN = 0x1;
+    /**
+     * Fading mode used in {@link #Fade(int)} to make the transition
+     * operate on targets that are disappearing. Maybe be combined with
+     * {@link #IN} to fade both in and out.
+     */
+    public static final int OUT = 0x2;
+
+    private int mFadingMode;
+
+    /**
+     * Constructs a Fade transition that will fade targets in and out.
+     */
+    public Fade() {
+        this(IN | OUT);
+    }
+
+    /**
+     * Constructs a Fade transition that will fade targets in
+     * and/or out, according to the value of fadingMode.
+     *
+     * @param fadingMode The behavior of this transition, a combination of
+     * {@link #IN} and {@link #OUT}.
+     */
+    public Fade(int fadingMode) {
+        mFadingMode = fadingMode;
+    }
+
+    /**
+     * Utility method to handle creating and running the Animator.
+     */
+    private Animator createAnimation(View view, float startAlpha, float endAlpha,
+            AnimatorListenerAdapter listener) {
+        if (startAlpha == endAlpha) {
+            // run listener if we're noop'ing the animation, to get the end-state results now
+            if (listener != null) {
+                listener.onAnimationEnd(null);
+            }
+            return null;
+        }
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", startAlpha,
+                endAlpha);
+        if (DBG) {
+            Log.d(LOG_TAG, "Created animator " + anim);
+        }
+        if (listener != null) {
+            anim.addListener(listener);
+            anim.addPauseListener(listener);
+        }
+        return anim;
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        int[] loc = new int[2];
+        transitionValues.view.getLocationOnScreen(loc);
+        transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
+        transitionValues.values.put(PROPNAME_SCREEN_Y, loc[1]);
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        super.captureStartValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot,
+            TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        if ((mFadingMode & IN) != IN || endValues == null) {
+            return null;
+        }
+        final View endView = endValues.view;
+        if (DBG) {
+            View startView = (startValues != null) ? startValues.view : null;
+            Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
+                    startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
+        }
+        endView.setTransitionAlpha(0);
+        TransitionListener transitionListener = new TransitionListenerAdapter() {
+            boolean mCanceled = false;
+            float mPausedAlpha;
+
+            @Override
+            public void onTransitionCancel(Transition transition) {
+                endView.setTransitionAlpha(1);
+                mCanceled = true;
+            }
+
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                if (!mCanceled) {
+                    endView.setTransitionAlpha(1);
+                }
+            }
+
+            @Override
+            public void onTransitionPause(Transition transition) {
+                mPausedAlpha = endView.getTransitionAlpha();
+                endView.setTransitionAlpha(1);
+            }
+
+            @Override
+            public void onTransitionResume(Transition transition) {
+                endView.setTransitionAlpha(mPausedAlpha);
+            }
+        };
+        addListener(transitionListener);
+        return createAnimation(endView, 0, 1, null);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot,
+            TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        if ((mFadingMode & OUT) != OUT) {
+            return null;
+        }
+        View view = null;
+        View startView = (startValues != null) ? startValues.view : null;
+        View endView = (endValues != null) ? endValues.view : null;
+        if (DBG) {
+            Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
+                        startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
+        }
+        View overlayView = null;
+        View viewToKeep = null;
+        if (endView == null || endView.getParent() == null) {
+            if (endView != null) {
+                // endView was removed from its parent - add it to the overlay
+                view = overlayView = endView;
+            } else if (startView != null) {
+                // endView does not exist. Use startView only under certain
+                // conditions, because placing a view in an overlay necessitates
+                // it being removed from its current parent
+                if (startView.getParent() == null) {
+                    // no parent - safe to use
+                    view = overlayView = startView;
+                } else if (startView.getParent() instanceof View &&
+                        startView.getParent().getParent() == null) {
+                    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
+                        view = overlayView = startView;
+                    }
+                }
+            }
+        } else {
+            // visibility change
+            if (endVisibility == View.INVISIBLE) {
+                view = endView;
+                viewToKeep = view;
+            } else {
+                // Becoming GONE
+                if (startView == endView) {
+                    view = endView;
+                    viewToKeep = view;
+                } else {
+                    view = startView;
+                    overlayView = view;
+                }
+            }
+        }
+        final int finalVisibility = endVisibility;
+        // TODO: add automatic facility to Visibility superclass for keeping views around
+        if (overlayView != null) {
+            // TODO: Need to do this for general case of adding to overlay
+            int screenX = (Integer) startValues.values.get(PROPNAME_SCREEN_X);
+            int screenY = (Integer) startValues.values.get(PROPNAME_SCREEN_Y);
+            int[] loc = new int[2];
+            sceneRoot.getLocationOnScreen(loc);
+            overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
+            overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
+            sceneRoot.getOverlay().add(overlayView);
+            // TODO: add automatic facility to Visibility superclass for keeping views around
+            final float startAlpha = 1;
+            float endAlpha = 0;
+            final View finalView = view;
+            final View finalOverlayView = overlayView;
+            final View finalViewToKeep = viewToKeep;
+            final ViewGroup finalSceneRoot = sceneRoot;
+            final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    finalView.setTransitionAlpha(startAlpha);
+                    // TODO: restore view offset from overlay repositioning
+                    if (finalViewToKeep != null) {
+                        finalViewToKeep.setVisibility(finalVisibility);
+                    }
+                    if (finalOverlayView != null) {
+                        finalSceneRoot.getOverlay().remove(finalOverlayView);
+                    }
+                }
+
+                @Override
+                public void onAnimationPause(Animator animation) {
+                    if (finalOverlayView != null) {
+                        finalSceneRoot.getOverlay().remove(finalOverlayView);
+                    }
+                }
+
+                @Override
+                public void onAnimationResume(Animator animation) {
+                    if (finalOverlayView != null) {
+                        finalSceneRoot.getOverlay().add(finalOverlayView);
+                    }
+                }
+            };
+            return createAnimation(view, startAlpha, endAlpha, endListener);
+        }
+        if (viewToKeep != null) {
+            // TODO: find a different way to do this, like just changing the view to be
+            // VISIBLE for the duration of the transition
+            viewToKeep.setVisibility((View.VISIBLE));
+            // TODO: add automatic facility to Visibility superclass for keeping views around
+            final float startAlpha = 1;
+            float endAlpha = 0;
+            final View finalView = view;
+            final View finalOverlayView = overlayView;
+            final View finalViewToKeep = viewToKeep;
+            final ViewGroup finalSceneRoot = sceneRoot;
+            final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+                boolean mCanceled = false;
+                float mPausedAlpha = -1;
+
+                @Override
+                public void onAnimationPause(Animator animation) {
+                    if (finalViewToKeep != null && !mCanceled) {
+                        finalViewToKeep.setVisibility(finalVisibility);
+                    }
+                    mPausedAlpha = finalView.getTransitionAlpha();
+                    finalView.setTransitionAlpha(startAlpha);
+                }
+
+                @Override
+                public void onAnimationResume(Animator animation) {
+                    if (finalViewToKeep != null && !mCanceled) {
+                        finalViewToKeep.setVisibility(View.VISIBLE);
+                    }
+                    finalView.setTransitionAlpha(mPausedAlpha);
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mCanceled = true;
+                    if (mPausedAlpha >= 0) {
+                        finalView.setTransitionAlpha(mPausedAlpha);
+                    }
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (!mCanceled) {
+                        finalView.setTransitionAlpha(startAlpha);
+                    }
+                    // TODO: restore view offset from overlay repositioning
+                    if (finalViewToKeep != null && !mCanceled) {
+                        finalViewToKeep.setVisibility(finalVisibility);
+                    }
+                    if (finalOverlayView != null) {
+                        finalSceneRoot.getOverlay().remove(finalOverlayView);
+                    }
+                }
+            };
+            return createAnimation(view, startAlpha, endAlpha, endListener);
+        }
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/android/transition/Recolor.java b/core/java/android/transition/Recolor.java
new file mode 100644
index 0000000..70111d1
--- /dev/null
+++ b/core/java/android/transition/Recolor.java
@@ -0,0 +1,95 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * This transition tracks changes during scene changes to the
+ * {@link View#setBackground(android.graphics.drawable.Drawable) background}
+ * property of its target views (when the background is a
+ * {@link ColorDrawable}, as well as the
+ * {@link TextView#setTextColor(android.content.res.ColorStateList)
+ * color} of the text for target TextViews. If the color changes between
+ * scenes, the color change is animated.
+ *
+ * @hide
+ */
+public class Recolor extends Transition {
+
+    private static final String PROPNAME_BACKGROUND = "android:recolor:background";
+    private static final String PROPNAME_TEXT_COLOR = "android:recolor:textColor";
+
+    private void captureValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROPNAME_BACKGROUND, transitionValues.view.getBackground());
+        if (transitionValues.view instanceof TextView) {
+            transitionValues.values.put(PROPNAME_TEXT_COLOR,
+                    ((TextView)transitionValues.view).getCurrentTextColor());
+        }
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null || endValues == null) {
+            return null;
+        }
+        final View view = endValues.view;
+        Drawable startBackground = (Drawable) startValues.values.get(PROPNAME_BACKGROUND);
+        Drawable endBackground = (Drawable) endValues.values.get(PROPNAME_BACKGROUND);
+        boolean changed = false;
+        if (startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable) {
+            ColorDrawable startColor = (ColorDrawable) startBackground;
+            ColorDrawable endColor = (ColorDrawable) endBackground;
+            if (startColor.getColor() != endColor.getColor()) {
+                endColor.setColor(startColor.getColor());
+                changed = true;
+                return ObjectAnimator.ofObject(endBackground, "color",
+                        new ArgbEvaluator(), startColor.getColor(), endColor.getColor());
+            }
+        }
+        if (view instanceof TextView) {
+            TextView textView = (TextView) view;
+            int start = (Integer) startValues.values.get(PROPNAME_TEXT_COLOR);
+            int end = (Integer) endValues.values.get(PROPNAME_TEXT_COLOR);
+            if (start != end) {
+                textView.setTextColor(end);
+                changed = true;
+                return ObjectAnimator.ofObject(textView, "textColor",
+                        new ArgbEvaluator(), start, end);
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/transition/Rotate.java b/core/java/android/transition/Rotate.java
new file mode 100644
index 0000000..ad1720ca
--- /dev/null
+++ b/core/java/android/transition/Rotate.java
@@ -0,0 +1,60 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition captures the rotation property of targets before and after
+ * the scene change and animates any changes.
+ *
+ * @hide
+ */
+public class Rotate extends Transition {
+
+    private static final String PROPNAME_ROTATION = "android:rotate:rotation";
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROPNAME_ROTATION, transitionValues.view.getRotation());
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROPNAME_ROTATION, transitionValues.view.getRotation());
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null || endValues == null) {
+            return null;
+        }
+        final View view = endValues.view;
+        float startRotation = (Float) startValues.values.get(PROPNAME_ROTATION);
+        float endRotation = (Float) endValues.values.get(PROPNAME_ROTATION);
+        if (startRotation != endRotation) {
+            view.setRotation(startRotation);
+            return ObjectAnimator.ofFloat(view, View.ROTATION,
+                    startRotation, endRotation);
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java
new file mode 100644
index 0000000..d798abe
--- /dev/null
+++ b/core/java/android/transition/Scene.java
@@ -0,0 +1,260 @@
+/*
+ * 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 android.transition;
+
+import android.content.Context;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A scene represents the collection of values that various properties in the
+ * View hierarchy will have when the scene is applied. A Scene can be
+ * configured to automatically run a Transition when it is applied, which will
+ * animate the various property changes that take place during the
+ * scene change.
+ */
+public final class Scene {
+
+    private Context mContext;
+    private int mLayoutId = -1;
+    private ViewGroup mSceneRoot;
+    private ViewGroup mLayout; // alternative to layoutId
+    Runnable mEnterAction, mExitAction;
+    private static ThreadLocal<SparseArray<Scene>> sScenes = new ThreadLocal<SparseArray<Scene>>();
+
+    /**
+     * Returns a Scene described by the resource file associated with the given
+     * <code>layoutId</code> parameter. If such a Scene has already been created,
+     * that same Scene will be returned. This caching of layoutId-based scenes enables
+     * sharing of common scenes between those created in code and those referenced
+     * by {@link TransitionManager} XML resource files.
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     * and transitions will take place.
+     * @param layoutId The id of a standard layout resource file.
+     * @param context The context used in the process of inflating
+     * the layout resource.
+     * @return
+     */
+    public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
+        SparseArray<Scene> scenes = sScenes.get();
+        if (scenes == null) {
+            scenes = new SparseArray<Scene>();
+            sScenes.set(scenes);
+        }
+        Scene scene = scenes.get(layoutId);
+        if (scene != null) {
+            return scene;
+        } else {
+            scene = new Scene(sceneRoot, layoutId, context);
+            scenes.put(layoutId, scene);
+            return scene;
+        }
+    }
+
+    /**
+     * Constructs a Scene with no information about how values will change
+     * when this scene is applied. This constructor might be used when
+     * a Scene is created with the intention of being dynamically configured,
+     * through setting {@link #setEnterAction(Runnable)} and possibly
+     * {@link #setExitAction(Runnable)}.
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     * and transitions will take place.
+     */
+    public Scene(ViewGroup sceneRoot) {
+        mSceneRoot = sceneRoot;
+    }
+
+    /**
+     * Constructs a Scene which, when entered, will remove any
+     * children from the sceneRoot container and will inflate and add
+     * the hierarchy specified by the layoutId resource file.
+     *
+     * <p>This method is hidden because layoutId-based scenes should be
+     * created by the caching factory method {@link Scene#getCurrentScene(View)}.</p>
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     * and transitions will take place.
+     * @param layoutId The id of a resource file that defines the view
+     * hierarchy of this scene.
+     * @param context The context used in the process of inflating
+     * the layout resource.
+     */
+    private Scene(ViewGroup sceneRoot, int layoutId, Context context) {
+        mContext = context;
+        mSceneRoot = sceneRoot;
+        mLayoutId = layoutId;
+    }
+
+    /**
+     * Constructs a Scene which, when entered, will remove any
+     * children from the sceneRoot container and add the layout
+     * object as a new child of that container.
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     * and transitions will take place.
+     * @param layout The view hierarchy of this scene, added as a child
+     * of sceneRoot when this scene is entered.
+     */
+    public Scene(ViewGroup sceneRoot, ViewGroup layout) {
+        mSceneRoot = sceneRoot;
+        mLayout = layout;
+    }
+
+    /**
+     * Gets the root of the scene, which is the root of the view hierarchy
+     * affected by changes due to this scene, and which will be animated
+     * when this scene is entered.
+     *
+     * @return The root of the view hierarchy affected by this scene.
+     */
+    public ViewGroup getSceneRoot() {
+        return mSceneRoot;
+    }
+
+    /**
+     * Exits this scene, if it is the current scene
+     * on the scene's {@link #getSceneRoot() scene root}. The current scene is
+     * set when {@link #enter() entering} a scene.
+     * Exiting a scene runs the {@link #setExitAction(Runnable) exit action}
+     * if there is one.
+     */
+    public void exit() {
+        if (getCurrentScene(mSceneRoot) == this) {
+            if (mExitAction != null) {
+                mExitAction.run();
+            }
+        }
+    }
+
+    /**
+     * Enters this scene, which entails changing all values that
+     * are specified by this scene. These may be values associated
+     * with a layout view group or layout resource file which will
+     * now be added to the scene root, or it may be values changed by
+     * an {@link #setEnterAction(Runnable)} enter action}, or a
+     * combination of the these. No transition will be run when the
+     * scene is entered. To get transition behavior in scene changes,
+     * use one of the methods in {@link TransitionManager} instead.
+     */
+    public void enter() {
+
+        // Apply layout change, if any
+        if (mLayoutId > 0 || mLayout != null) {
+            // empty out parent container before adding to it
+            getSceneRoot().removeAllViews();
+
+            if (mLayoutId > 0) {
+                LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot);
+            } else {
+                mSceneRoot.addView(mLayout);
+            }
+        }
+
+        // Notify next scene that it is entering. Subclasses may override to configure scene.
+        if (mEnterAction != null) {
+            mEnterAction.run();
+        }
+
+        setCurrentScene(mSceneRoot, this);
+    }
+
+    /**
+     * Set the scene that the given view is in. The current scene is set only
+     * on the root view of a scene, not for every view in that hierarchy. This
+     * information is used by Scene to determine whether there is a previous
+     * scene which should be exited before the new scene is entered.
+     *
+     * @param view The view on which the current scene is being set
+     */
+    static void setCurrentScene(View view, Scene scene) {
+        view.setTagInternal(com.android.internal.R.id.current_scene, scene);
+    }
+
+    /**
+     * Gets the current {@link Scene} set on the given view. A scene is set on a view
+     * only if that view is the scene root.
+     *
+     * @return The current Scene set on this view. A value of null indicates that
+     * no Scene is currently set.
+     */
+    static Scene getCurrentScene(View view) {
+        return (Scene) view.getTag(com.android.internal.R.id.current_scene);
+    }
+
+    /**
+     * Scenes that are not defined with layout resources or
+     * hierarchies, or which need to perform additional steps
+     * after those hierarchies are changed to, should set an enter
+     * action, and possibly an exit action as well. An enter action
+     * will cause Scene to call back into application code to do
+     * anything else the application needs after transitions have
+     * captured pre-change values and after any other scene changes
+     * have been applied, such as the layout (if any) being added to
+     * the view hierarchy. After this method is called, Transitions will
+     * be played.
+     *
+     * @param action The runnable whose {@link Runnable#run() run()} method will
+     * be called when this scene is entered
+     * @see #setExitAction(Runnable)
+     * @see Scene#Scene(ViewGroup, int, Context)
+     * @see Scene#Scene(ViewGroup, ViewGroup)
+     */
+    public void setEnterAction(Runnable action) {
+        mEnterAction = action;
+    }
+
+    /**
+     * Scenes that are not defined with layout resources or
+     * hierarchies, or which need to perform additional steps
+     * after those hierarchies are changed to, should set an enter
+     * action, and possibly an exit action as well. An exit action
+     * will cause Scene to call back into application code to do
+     * anything the application needs to do after applicable transitions have
+     * captured pre-change values, but before any other scene changes
+     * have been applied, such as the new layout (if any) being added to
+     * the view hierarchy. After this method is called, the next scene
+     * will be entered, including a call to {@link #setEnterAction(Runnable)}
+     * if an enter action is set.
+     *
+     * @see #setEnterAction(Runnable)
+     * @see Scene#Scene(ViewGroup, int, Context)
+     * @see Scene#Scene(ViewGroup, ViewGroup)
+     */
+    public void setExitAction(Runnable action) {
+        mExitAction = action;
+    }
+
+
+    /**
+     * Returns whether this Scene was created by a layout resource file, determined
+     * by the layoutId passed into
+     * {@link #getSceneForLayout(android.view.ViewGroup, int, android.content.Context)}.
+     * This is called by TransitionManager to determine whether it is safe for views from
+     * this scene to be removed from their parents when the scene is exited, which is
+     * used by {@link Fade} to fade these views out (the views must be removed from
+     * their parent in order to add them to the overlay for fading purposes). If a
+     * Scene is not based on a resource file, then the impact of removing views
+     * arbitrarily is unknown and should be avoided.
+     */
+    boolean isCreatedFromLayoutResource() {
+        return (mLayoutId > 0);
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
new file mode 100644
index 0000000..b38973c
--- /dev/null
+++ b/core/java/android/transition/Slide.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+/**
+ * This transition captures the visibility of target objects before and
+ * after a scene change and animates any changes by sliding the target
+ * objects into or out of place.
+ *
+ * @hide
+ */
+public class Slide extends Visibility {
+
+    // TODO: Add parameter for sliding factor - it's hard-coded below
+
+    private static final TimeInterpolator sAccelerator = new AccelerateInterpolator();
+    private static final TimeInterpolator sDecelerator = new DecelerateInterpolator();
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot,
+            TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        View endView = (endValues != null) ? endValues.view : null;
+        endView.setTranslationY(-2 * endView.getHeight());
+        ObjectAnimator anim = ObjectAnimator.ofFloat(endView, View.TRANSLATION_Y,
+                -2 * endView.getHeight(), 0);
+        anim.setInterpolator(sDecelerator);
+        return anim;
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot,
+            TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        View startView = (startValues != null) ? startValues.view : null;
+        startView.setTranslationY(0);
+        ObjectAnimator anim = ObjectAnimator.ofFloat(startView, View.TRANSLATION_Y, 0,
+                -2 * startView.getHeight());
+        anim.setInterpolator(sAccelerator);
+        return anim;
+    }
+
+}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
new file mode 100644
index 0000000..dcf668b
--- /dev/null
+++ b/core/java/android/transition/Transition.java
@@ -0,0 +1,1681 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOverlay;
+import android.widget.ListView;
+import android.widget.Spinner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Transition holds information about animations that will be run on its
+ * targets during a scene change. Subclasses of this abstract class may
+ * choreograph several child transitions ({@link TransitionSet} or they may
+ * perform custom animations themselves. Any Transition has two main jobs:
+ * (1) capture property values, and (2) play animations based on changes to
+ * captured property values. A custom transition knows what property values
+ * on View objects are of interest to it, and also knows how to animate
+ * changes to those values. For example, the {@link Fade} transition tracks
+ * changes to visibility-related properties and is able to construct and run
+ * animations that fade items in or out based on changes to those properties.
+ *
+ * <p>Note: Transitions may not work correctly with either {@link SurfaceView}
+ * or {@link TextureView}, due to the way that these views are displayed
+ * on the screen. For SurfaceView, the problem is that the view is updated from
+ * a non-UI thread, so changes to the view due to transitions (such as moving
+ * and resizing the view) may be out of sync with the display inside those bounds.
+ * TextureView is more compatible with transitions in general, but some
+ * specific transitions (such as {@link Fade}) may not be compatible
+ * with TextureView because they rely on {@link ViewOverlay} functionality,
+ * which does not currently work with TextureView.</p>
+ *
+ * <p>Transitions can be declared in XML resource files inside the <code>res/transition</code>
+ * directory. Transition resources consist of a tag name for one of the Transition
+ * subclasses along with attributes to define some of the attributes of that transition.
+ * For example, here is a minimal resource file that declares a {@link ChangeBounds} transition:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/transition/changebounds.xml ChangeBounds}
+ *
+ * <p>Note that attributes for the transition are not required, just as they are
+ * optional when declared in code; Transitions created from XML resources will use
+ * the same defaults as their code-created equivalents. Here is a slightly more
+ * elaborate example which declares a {@link TransitionSet} transition with
+ * {@link ChangeBounds} and {@link Fade} child transitions:</p>
+ *
+ * {@sample
+ * development/samples/ApiDemos/res/transition/changebounds_fadeout_sequential.xml TransitionSet}
+ *
+ * <p>In this example, the transitionOrdering attribute is used on the TransitionSet
+ * object to change from the default {@link TransitionSet#ORDERING_TOGETHER} behavior
+ * to be {@link TransitionSet#ORDERING_SEQUENTIAL} instead. Also, the {@link Fade}
+ * transition uses a fadingMode of {@link Fade#OUT} instead of the default
+ * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
+ * takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
+ * of which lists a specific <code>targetId</code> which this transition acts upon.
+ * Use of targets is optional, but can be used to either limit the time spent checking
+ * attributes on unchanging views, or limiting the types of animations run on specific views.
+ * In this case, we know that only the <code>grayscaleContainer</code> will be
+ * disappearing, so we choose to limit the {@link Fade} transition to only that view.</p>
+ *
+ * Further information on XML resource descriptions for transitions can be found for
+ * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
+ * {@link android.R.styleable#TransitionTarget}, and {@link android.R.styleable#Fade}.
+ *
+ */
+public abstract class Transition implements Cloneable {
+
+    private static final String LOG_TAG = "Transition";
+    static final boolean DBG = false;
+
+    private String mName = getClass().getName();
+
+    long mStartDelay = -1;
+    long mDuration = -1;
+    TimeInterpolator mInterpolator = null;
+    ArrayList<Integer> mTargetIds = new ArrayList<Integer>();
+    ArrayList<View> mTargets = new ArrayList<View>();
+    ArrayList<Integer> mTargetIdExcludes = null;
+    ArrayList<View> mTargetExcludes = null;
+    ArrayList<Class> mTargetTypeExcludes = null;
+    ArrayList<Integer> mTargetIdChildExcludes = null;
+    ArrayList<View> mTargetChildExcludes = null;
+    ArrayList<Class> mTargetTypeChildExcludes = null;
+    private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
+    private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
+    TransitionSet mParent = null;
+
+    // Per-animator information used for later canceling when future transitions overlap
+    private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
+            new ThreadLocal<ArrayMap<Animator, AnimationInfo>>();
+
+    // Scene Root is set at createAnimator() time in the cloned Transition
+    ViewGroup mSceneRoot = null;
+
+    // Whether removing views from their parent is possible. This is only for views
+    // in the start scene, which are no longer in the view hierarchy. This property
+    // is determined by whether the previous Scene was created from a layout
+    // resource, and thus the views from the exited scene are going away anyway
+    // and can be removed as necessary to achieve a particular effect, such as
+    // removing them from parents to add them to overlays.
+    boolean mCanRemoveViews = false;
+
+    // Track all animators in use in case the transition gets canceled and needs to
+    // cancel running animators
+    private ArrayList<Animator> mCurrentAnimators = new ArrayList<Animator>();
+
+    // Number of per-target instances of this Transition currently running. This count is
+    // determined by calls to start() and end()
+    int mNumInstances = 0;
+
+    // Whether this transition is currently paused, due to a call to pause()
+    boolean mPaused = false;
+
+    // Whether this transition has ended. Used to avoid pause/resume on transitions
+    // that have completed
+    private boolean mEnded = false;
+
+    // The set of listeners to be sent transition lifecycle events.
+    ArrayList<TransitionListener> mListeners = null;
+
+    // The set of animators collected from calls to createAnimator(),
+    // to be run in runAnimators()
+    ArrayList<Animator> mAnimators = new ArrayList<Animator>();
+
+    /**
+     * Constructs a Transition object with no target objects. A transition with
+     * no targets defaults to running on all target objects in the scene hierarchy
+     * (if the transition is not contained in a TransitionSet), or all target
+     * objects passed down from its parent (if it is in a TransitionSet).
+     */
+    public Transition() {}
+
+    /**
+     * Sets the duration of this transition. By default, there is no duration
+     * (indicated by a negative number), which means that the Animator created by
+     * the transition will have its own specified duration. If the duration of a
+     * Transition is set, that duration will override the Animator duration.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     * @return This transition object.
+     * @attr ref android.R.styleable#Transition_duration
+     */
+    public Transition setDuration(long duration) {
+        mDuration = duration;
+        return this;
+    }
+
+    /**
+     * Returns the duration set on this transition. If no duration has been set,
+     * the returned value will be negative, indicating that resulting animators will
+     * retain their own durations.
+     *
+     * @return The duration set on this transition, in milliseconds, if one has been
+     * set, otherwise returns a negative number.
+     */
+    public long getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * Sets the startDelay of this transition. By default, there is no delay
+     * (indicated by a negative number), which means that the Animator created by
+     * the transition will have its own specified startDelay. If the delay of a
+     * Transition is set, that delay will override the Animator delay.
+     *
+     * @param startDelay The length of the delay, in milliseconds.
+     * @return This transition object.
+     * @attr ref android.R.styleable#Transition_startDelay
+     */
+    public Transition setStartDelay(long startDelay) {
+        mStartDelay = startDelay;
+        return this;
+    }
+
+    /**
+     * Returns the startDelay set on this transition. If no startDelay has been set,
+     * the returned value will be negative, indicating that resulting animators will
+     * retain their own startDelays.
+     *
+     * @return The startDelay set on this transition, in milliseconds, if one has
+     * been set, otherwise returns a negative number.
+     */
+    public long getStartDelay() {
+        return mStartDelay;
+    }
+
+    /**
+     * Sets the interpolator of this transition. By default, the interpolator
+     * is null, which means that the Animator created by the transition
+     * will have its own specified interpolator. If the interpolator of a
+     * Transition is set, that interpolator will override the Animator interpolator.
+     *
+     * @param interpolator The time interpolator used by the transition
+     * @return This transition object.
+     * @attr ref android.R.styleable#Transition_interpolator
+     */
+    public Transition setInterpolator(TimeInterpolator interpolator) {
+        mInterpolator = interpolator;
+        return this;
+    }
+
+    /**
+     * Returns the interpolator set on this transition. If no interpolator has been set,
+     * the returned value will be null, indicating that resulting animators will
+     * retain their own interpolators.
+     *
+     * @return The interpolator set on this transition, if one has been set, otherwise
+     * returns null.
+     */
+    public TimeInterpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    /**
+     * Returns the set of property names used stored in the {@link TransitionValues}
+     * object passed into {@link #captureStartValues(TransitionValues)} that
+     * this transition cares about for the purposes of canceling overlapping animations.
+     * When any transition is started on a given scene root, all transitions
+     * currently running on that same scene root are checked to see whether the
+     * properties on which they based their animations agree with the end values of
+     * the same properties in the new transition. If the end values are not equal,
+     * then the old animation is canceled since the new transition will start a new
+     * animation to these new values. If the values are equal, the old animation is
+     * allowed to continue and no new animation is started for that transition.
+     *
+     * <p>A transition does not need to override this method. However, not doing so
+     * will mean that the cancellation logic outlined in the previous paragraph
+     * will be skipped for that transition, possibly leading to artifacts as
+     * old transitions and new transitions on the same targets run in parallel,
+     * animating views toward potentially different end values.</p>
+     *
+     * @return An array of property names as described in the class documentation for
+     * {@link TransitionValues}. The default implementation returns <code>null</code>.
+     */
+    public String[] getTransitionProperties() {
+        return null;
+    }
+
+    /**
+     * This method creates an animation that will be run for this transition
+     * given the information in the startValues and endValues structures captured
+     * earlier for the start and end scenes. Subclasses of Transition should override
+     * this method. The method should only be called by the transition system; it is
+     * not intended to be called from external classes.
+     *
+     * <p>This method is called by the transition's parent (all the way up to the
+     * topmost Transition in the hierarchy) with the sceneRoot and start/end
+     * values that the transition may need to set up initial target values
+     * and construct an appropriate animation. For example, if an overall
+     * Transition is a {@link TransitionSet} consisting of several
+     * child transitions in sequence, then some of the child transitions may
+     * want to set initial values on target views prior to the overall
+     * Transition commencing, to put them in an appropriate state for the
+     * delay between that start and the child Transition start time. For
+     * example, a transition that fades an item in may wish to set the starting
+     * alpha value to 0, to avoid it blinking in prior to the transition
+     * actually starting the animation. This is necessary because the scene
+     * change that triggers the Transition will automatically set the end-scene
+     * on all target views, so a Transition that wants to animate from a
+     * different value should set that value prior to returning from this method.</p>
+     *
+     * <p>Additionally, a Transition can perform logic to determine whether
+     * the transition needs to run on the given target and start/end values.
+     * For example, a transition that resizes objects on the screen may wish
+     * to avoid running for views which are not present in either the start
+     * or end scenes.</p>
+     *
+     * <p>If there is an animator created and returned from this method, the
+     * transition mechanism will apply any applicable duration, startDelay,
+     * and interpolator to that animation and start it. A return value of
+     * <code>null</code> indicates that no animation should run. The default
+     * implementation returns null.</p>
+     *
+     * <p>The method is called for every applicable target object, which is
+     * stored in the {@link TransitionValues#view} field.</p>
+     *
+     *
+     * @param sceneRoot The root of the transition hierarchy.
+     * @param startValues The values for a specific target in the start scene.
+     * @param endValues The values for the target in the end scene.
+     * @return A Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        return null;
+    }
+
+    /**
+     * This method, essentially a wrapper around all calls to createAnimator for all
+     * possible target views, is called with the entire set of start/end
+     * values. The implementation in Transition iterates through these lists
+     * and calls {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+     * with each set of start/end values on this transition. The
+     * TransitionSet subclass overrides this method and delegates it to
+     * each of its children in succession.
+     *
+     * @hide
+     */
+    protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
+            TransitionValuesMaps endValues) {
+        if (DBG) {
+            Log.d(LOG_TAG, "createAnimators() for " + this);
+        }
+        ArrayMap<View, TransitionValues> endCopy =
+                new ArrayMap<View, TransitionValues>(endValues.viewValues);
+        SparseArray<TransitionValues> endIdCopy =
+                new SparseArray<TransitionValues>(endValues.idValues.size());
+        for (int i = 0; i < endValues.idValues.size(); ++i) {
+            int id = endValues.idValues.keyAt(i);
+            endIdCopy.put(id, endValues.idValues.valueAt(i));
+        }
+        LongSparseArray<TransitionValues> endItemIdCopy =
+                new LongSparseArray<TransitionValues>(endValues.itemIdValues.size());
+        for (int i = 0; i < endValues.itemIdValues.size(); ++i) {
+            long id = endValues.itemIdValues.keyAt(i);
+            endItemIdCopy.put(id, endValues.itemIdValues.valueAt(i));
+        }
+        // Walk through the start values, playing everything we find
+        // Remove from the end set as we go
+        ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
+        ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
+        for (View view : startValues.viewValues.keySet()) {
+            TransitionValues start = null;
+            TransitionValues end = null;
+            boolean isInListView = false;
+            if (view.getParent() instanceof ListView) {
+                isInListView = true;
+            }
+            if (!isInListView) {
+                int id = view.getId();
+                start = startValues.viewValues.get(view) != null ?
+                        startValues.viewValues.get(view) : startValues.idValues.get(id);
+                if (endValues.viewValues.get(view) != null) {
+                    end = endValues.viewValues.get(view);
+                    endCopy.remove(view);
+                } else if (id != View.NO_ID) {
+                    end = endValues.idValues.get(id);
+                    View removeView = null;
+                    for (View viewToRemove : endCopy.keySet()) {
+                        if (viewToRemove.getId() == id) {
+                            removeView = viewToRemove;
+                        }
+                    }
+                    if (removeView != null) {
+                        endCopy.remove(removeView);
+                    }
+                }
+                endIdCopy.remove(id);
+                if (isValidTarget(view, id)) {
+                    startValuesList.add(start);
+                    endValuesList.add(end);
+                }
+            } else {
+                ListView parent = (ListView) view.getParent();
+                if (parent.getAdapter().hasStableIds()) {
+                    int position = parent.getPositionForView(view);
+                    long itemId = parent.getItemIdAtPosition(position);
+                    start = startValues.itemIdValues.get(itemId);
+                    endItemIdCopy.remove(itemId);
+                    // TODO: deal with targetIDs for itemIDs for ListView items
+                    startValuesList.add(start);
+                    endValuesList.add(end);
+                }
+            }
+        }
+        int startItemIdCopySize = startValues.itemIdValues.size();
+        for (int i = 0; i < startItemIdCopySize; ++i) {
+            long id = startValues.itemIdValues.keyAt(i);
+            if (isValidTarget(null, id)) {
+                TransitionValues start = startValues.itemIdValues.get(id);
+                TransitionValues end = endValues.itemIdValues.get(id);
+                endItemIdCopy.remove(id);
+                startValuesList.add(start);
+                endValuesList.add(end);
+            }
+        }
+        // Now walk through the remains of the end set
+        for (View view : endCopy.keySet()) {
+            int id = view.getId();
+            if (isValidTarget(view, id)) {
+                TransitionValues start = startValues.viewValues.get(view) != null ?
+                        startValues.viewValues.get(view) : startValues.idValues.get(id);
+                TransitionValues end = endCopy.get(view);
+                endIdCopy.remove(id);
+                startValuesList.add(start);
+                endValuesList.add(end);
+            }
+        }
+        int endIdCopySize = endIdCopy.size();
+        for (int i = 0; i < endIdCopySize; ++i) {
+            int id = endIdCopy.keyAt(i);
+            if (isValidTarget(null, id)) {
+                TransitionValues start = startValues.idValues.get(id);
+                TransitionValues end = endIdCopy.get(id);
+                startValuesList.add(start);
+                endValuesList.add(end);
+            }
+        }
+        int endItemIdCopySize = endItemIdCopy.size();
+        for (int i = 0; i < endItemIdCopySize; ++i) {
+            long id = endItemIdCopy.keyAt(i);
+            // TODO: Deal with targetIDs and itemIDs
+            TransitionValues start = startValues.itemIdValues.get(id);
+            TransitionValues end = endItemIdCopy.get(id);
+            startValuesList.add(start);
+            endValuesList.add(end);
+        }
+        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        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 +")");
+                                }
+                            }
+                        }
+                    }
+                    // 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) {
+                            AnimationInfo info = new AnimationInfo(view, getName(), infoValues);
+                            runningAnimators.put(animator, info);
+                            mAnimators.add(animator);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Internal utility method for checking whether a given view/id
+     * is valid for this transition, where "valid" means that either
+     * the Transition has no target/targetId list (the default, in which
+     * cause the transition should act on all views in the hiearchy), or
+     * the given view is in the target list or the view id is in the
+     * targetId list. If the target parameter is null, then the target list
+     * is not checked (this is in the case of ListView items, where the
+     * views are ignored and only the ids are used).
+     */
+    boolean isValidTarget(View target, long targetId) {
+        if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) {
+            return false;
+        }
+        if (mTargetExcludes != null && mTargetExcludes.contains(target)) {
+            return false;
+        }
+        if (mTargetTypeExcludes != null && target != null) {
+            int numTypes = mTargetTypeExcludes.size();
+            for (int i = 0; i < numTypes; ++i) {
+                Class type = mTargetTypeExcludes.get(i);
+                if (type.isInstance(target)) {
+                    return false;
+                }
+            }
+        }
+        if (mTargetIds.size() == 0 && mTargets.size() == 0) {
+            return true;
+        }
+        if (mTargetIds.size() > 0) {
+            for (int i = 0; i < mTargetIds.size(); ++i) {
+                if (mTargetIds.get(i) == targetId) {
+                    return true;
+                }
+            }
+        }
+        if (target != null && mTargets.size() > 0) {
+            for (int i = 0; i < mTargets.size(); ++i) {
+                if (mTargets.get(i) == target) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+        ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
+        if (runningAnimators == null) {
+            runningAnimators = new ArrayMap<Animator, AnimationInfo>();
+            sRunningAnimators.set(runningAnimators);
+        }
+        return runningAnimators;
+    }
+
+    /**
+     * This is called internally once all animations have been set up by the
+     * transition hierarchy. \
+     *
+     * @hide
+     */
+    protected void runAnimators() {
+        if (DBG) {
+            Log.d(LOG_TAG, "runAnimators() on " + this);
+        }
+        start();
+        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        // Now start every Animator that was previously created for this transition
+        for (Animator anim : mAnimators) {
+            if (DBG) {
+                Log.d(LOG_TAG, "  anim: " + anim);
+            }
+            if (runningAnimators.containsKey(anim)) {
+                start();
+                runAnimator(anim, runningAnimators);
+            }
+        }
+        mAnimators.clear();
+        end();
+    }
+
+    private void runAnimator(Animator animator,
+            final ArrayMap<Animator, AnimationInfo> runningAnimators) {
+        if (animator != null) {
+            // TODO: could be a single listener instance for all of them since it uses the param
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mCurrentAnimators.add(animation);
+                }
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    runningAnimators.remove(animation);
+                    mCurrentAnimators.remove(animation);
+                }
+            });
+            animate(animator);
+        }
+    }
+
+    /**
+     * Captures the values in the start scene for the properties that this
+     * transition monitors. These values are then passed as the startValues
+     * structure in a later call to
+     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
+     * The main concern for an implementation is what the
+     * properties are that the transition cares about and what the values are
+     * for all of those properties. The start and end values will be compared
+     * later during the
+     * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)}
+     * method to determine what, if any, animations, should be run.
+     *
+     * <p>Subclasses must implement this method. The method should only be called by the
+     * transition system; it is not intended to be called from external classes.</p>
+     *
+     * @param transitionValues The holder for any values that the Transition
+     * wishes to store. Values are stored in the <code>values</code> field
+     * of this TransitionValues object and are keyed from
+     * a String value. For example, to store a view's rotation value,
+     * a transition might call
+     * <code>transitionValues.values.put("appname:transitionname:rotation",
+     * view.getRotation())</code>. The target view will already be stored in
+     * the transitionValues structure when this method is called.
+     *
+     * @see #captureEndValues(TransitionValues)
+     * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+     */
+    public abstract void captureStartValues(TransitionValues transitionValues);
+
+    /**
+     * Captures the values in the end scene for the properties that this
+     * transition monitors. These values are then passed as the endValues
+     * structure in a later call to
+     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
+     * The main concern for an implementation is what the
+     * properties are that the transition cares about and what the values are
+     * for all of those properties. The start and end values will be compared
+     * later during the
+     * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)}
+     * method to determine what, if any, animations, should be run.
+     *
+     * <p>Subclasses must implement this method. The method should only be called by the
+     * transition system; it is not intended to be called from external classes.</p>
+     *
+     * @param transitionValues The holder for any values that the Transition
+     * wishes to store. Values are stored in the <code>values</code> field
+     * of this TransitionValues object and are keyed from
+     * a String value. For example, to store a view's rotation value,
+     * a transition might call
+     * <code>transitionValues.values.put("appname:transitionname:rotation",
+     * view.getRotation())</code>. The target view will already be stored in
+     * the transitionValues structure when this method is called.
+     *
+     * @see #captureStartValues(TransitionValues)
+     * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+     */
+    public abstract void captureEndValues(TransitionValues transitionValues);
+
+    /**
+     * Adds the id of a target view that this Transition is interested in
+     * animating. By default, there are no targetIds, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targetIds constrains
+     * the Transition to only listen for, and act on, views with these IDs.
+     * Views with different IDs, or no IDs whatsoever, will be ignored.
+     *
+     * <p>Note that using ids to specify targets implies that ids should be unique
+     * within the view hierarchy underneat the scene root.</p>
+     *
+     * @see View#getId()
+     * @param targetId The id of a target view, must be a positive number.
+     * @return The Transition to which the targetId is added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(someId);</code>
+     */
+    public Transition addTarget(int targetId) {
+        if (targetId > 0) {
+            mTargetIds.add(targetId);
+        }
+        return this;
+    }
+
+    /**
+     * Removes the given targetId from the list of ids that this Transition
+     * is interested in animating.
+     *
+     * @param targetId The id of a target view, must be a positive number.
+     * @return The Transition from which the targetId is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTargetId(someId);</code>
+     */
+    public Transition removeTarget(int targetId) {
+        if (targetId > 0) {
+            mTargetIds.remove(targetId);
+        }
+        return this;
+    }
+
+    /**
+     * Whether to add the given id to the list of target ids to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeChildren(int, boolean)
+     * @see #excludeTarget(View, boolean)
+     * @see #excludeTarget(Class, boolean)
+     *
+     * @param targetId The id of a target to ignore when running this transition.
+     * @param exclude Whether to add the target to or remove the target from the
+     * current list of excluded targets.
+     * @return This transition object.
+     */
+    public Transition excludeTarget(int targetId, boolean exclude) {
+        mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
+        return this;
+    }
+
+    /**
+     * Whether to add the children of the given id to the list of targets to exclude
+     * from this transition. The <code>exclude</code> parameter specifies whether
+     * the children of the target should be added to or removed from the excluded list.
+     * Excluding children in this way provides a simple mechanism for excluding all
+     * children of specific targets, rather than individually excluding each
+     * child individually.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeChildren(View, boolean)
+     * @see #excludeChildren(Class, boolean)
+     *
+     * @param targetId The id of a target whose children should be ignored when running
+     * this transition.
+     * @param exclude Whether to add the target to or remove the target from the
+     * current list of excluded-child targets.
+     * @return This transition object.
+     */
+    public Transition excludeChildren(int targetId, boolean exclude) {
+        mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
+        return this;
+    }
+
+    /**
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
+        if (targetId > 0) {
+            if (exclude) {
+                list = ArrayListManager.add(list, targetId);
+            } else {
+                list = ArrayListManager.remove(list, targetId);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Whether to add the given target to the list of targets to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeChildren(View, boolean)
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeTarget(Class, boolean)
+     *
+     * @param target The target to ignore when running this transition.
+     * @param exclude Whether to add the target to or remove the target from the
+     * current list of excluded targets.
+     * @return This transition object.
+     */
+    public Transition excludeTarget(View target, boolean exclude) {
+        mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
+        return this;
+    }
+
+    /**
+     * Whether to add the children of given target to the list of target children
+     * to exclude from this transition. The <code>exclude</code> parameter specifies
+     * whether the target should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeTarget(View, boolean)
+     * @see #excludeChildren(int, boolean)
+     * @see #excludeChildren(Class, boolean)
+     *
+     * @param target The target to ignore when running this transition.
+     * @param exclude Whether to add the target to or remove the target from the
+     * current list of excluded targets.
+     * @return This transition object.
+     */
+    public Transition excludeChildren(View target, boolean exclude) {
+        mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
+        return this;
+    }
+
+    /**
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
+        if (target != null) {
+            if (exclude) {
+                list = ArrayListManager.add(list, target);
+            } else {
+                list = ArrayListManager.remove(list, target);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Whether to add the given type to the list of types to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * type should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeChildren(Class, boolean)
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeTarget(View, boolean)
+     *
+     * @param type The type to ignore when running this transition.
+     * @param exclude Whether to add the target type to or remove it from the
+     * current list of excluded target types.
+     * @return This transition object.
+     */
+    public Transition excludeTarget(Class type, boolean exclude) {
+        mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
+        return this;
+    }
+
+    /**
+     * Whether to add the given type to the list of types whose children should
+     * be excluded from this transition. The <code>exclude</code> parameter
+     * specifies whether the target type should be added to or removed from
+     * the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeTarget(Class, boolean)
+     * @see #excludeChildren(int, boolean)
+     * @see #excludeChildren(View, boolean)
+     *
+     * @param type The type to ignore when running this transition.
+     * @param exclude Whether to add the target type to or remove it from the
+     * current list of excluded target types.
+     * @return This transition object.
+     */
+    public Transition excludeChildren(Class type, boolean exclude) {
+        mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
+        return this;
+    }
+
+    /**
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
+        if (type != null) {
+            if (exclude) {
+                list = ArrayListManager.add(list, type);
+            } else {
+                list = ArrayListManager.remove(list, type);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Sets the target view instances that this Transition is interested in
+     * animating. By default, there are no targets, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targets constrains
+     * the Transition to only listen for, and act on, these views.
+     * All other views will be ignored.
+     *
+     * <p>The target list is like the {@link #addTarget(int) targetId}
+     * list except this list specifies the actual View instances, not the ids
+     * of the views. This is an important distinction when scene changes involve
+     * view hierarchies which have been inflated separately; different views may
+     * share the same id but not actually be the same instance. If the transition
+     * should treat those views as the same, then {@link #addTarget(int)} should be used
+     * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve
+     * changes all within the same view hierarchy, among views which do not
+     * necessarily have ids set on them, then the target list of views may be more
+     * convenient.</p>
+     *
+     * @see #addTarget(int)
+     * @param target A View on which the Transition will act, must be non-null.
+     * @return The Transition to which the target is added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(someView);</code>
+     */
+    public Transition addTarget(View target) {
+        mTargets.add(target);
+        return this;
+    }
+
+    /**
+     * Removes the given target from the list of targets that this Transition
+     * is interested in animating.
+     *
+     * @param target The target view, must be non-null.
+     * @return Transition The Transition from which the target is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTarget(someView);</code>
+     */
+    public Transition removeTarget(View target) {
+        if (target != null) {
+            mTargets.remove(target);
+        }
+        return this;
+    }
+
+    /**
+     * Returns the array of target IDs that this transition limits itself to
+     * tracking and animating. If the array is null for both this method and
+     * {@link #getTargets()}, then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
+     *
+     * @return the list of target IDs
+     */
+    public List<Integer> getTargetIds() {
+        return mTargetIds;
+    }
+
+    /**
+     * Returns the array of target views that this transition limits itself to
+     * tracking and animating. If the array is null for both this method and
+     * {@link #getTargetIds()}, then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
+     *
+     * @return the list of target views
+     */
+    public List<View> getTargets() {
+        return mTargets;
+    }
+
+    /**
+     * Recursive method that captures values for the given view and the
+     * hierarchy underneath it.
+     * @param sceneRoot The root of the view hierarchy being captured
+     * @param start true if this capture is happening before the scene change,
+     * false otherwise
+     */
+    void captureValues(ViewGroup sceneRoot, boolean start) {
+        if (start) {
+            mStartValues.viewValues.clear();
+            mStartValues.idValues.clear();
+            mStartValues.itemIdValues.clear();
+        } else {
+            mEndValues.viewValues.clear();
+            mEndValues.idValues.clear();
+            mEndValues.itemIdValues.clear();
+        }
+        if (mTargetIds.size() > 0 || mTargets.size() > 0) {
+            if (mTargetIds.size() > 0) {
+                for (int i = 0; i < mTargetIds.size(); ++i) {
+                    int id = mTargetIds.get(i);
+                    View view = sceneRoot.findViewById(id);
+                    if (view != null) {
+                        TransitionValues values = new TransitionValues();
+                        values.view = view;
+                        if (start) {
+                            captureStartValues(values);
+                        } else {
+                            captureEndValues(values);
+                        }
+                        if (start) {
+                            mStartValues.viewValues.put(view, values);
+                            if (id >= 0) {
+                                mStartValues.idValues.put(id, values);
+                            }
+                        } else {
+                            mEndValues.viewValues.put(view, values);
+                            if (id >= 0) {
+                                mEndValues.idValues.put(id, values);
+                            }
+                        }
+                    }
+                }
+            }
+            if (mTargets.size() > 0) {
+                for (int i = 0; i < mTargets.size(); ++i) {
+                    View view = mTargets.get(i);
+                    if (view != null) {
+                        TransitionValues values = new TransitionValues();
+                        values.view = view;
+                        if (start) {
+                            captureStartValues(values);
+                        } else {
+                            captureEndValues(values);
+                        }
+                        if (start) {
+                            mStartValues.viewValues.put(view, values);
+                        } else {
+                            mEndValues.viewValues.put(view, values);
+                        }
+                    }
+                }
+            }
+        } else {
+            captureHierarchy(sceneRoot, start);
+        }
+    }
+
+    /**
+     * Recursive method which captures values for an entire view hierarchy,
+     * starting at some root view. Transitions without targetIDs will use this
+     * method to capture values for all possible views.
+     *
+     * @param view The view for which to capture values. Children of this View
+     * will also be captured, recursively down to the leaf nodes.
+     * @param start true if values are being captured in the start scene, false
+     * otherwise.
+     */
+    private void captureHierarchy(View view, boolean start) {
+        if (view == null) {
+            return;
+        }
+        boolean isListViewItem = false;
+        if (view.getParent() instanceof ListView) {
+            isListViewItem = true;
+        }
+        if (isListViewItem && !((ListView) view.getParent()).getAdapter().hasStableIds()) {
+            // ignore listview children unless we can track them with stable IDs
+            return;
+        }
+        int id = View.NO_ID;
+        long itemId = View.NO_ID;
+        if (!isListViewItem) {
+            id = view.getId();
+        } else {
+            ListView listview = (ListView) view.getParent();
+            int position = listview.getPositionForView(view);
+            itemId = listview.getItemIdAtPosition(position);
+            view.setHasTransientState(true);
+        }
+        if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
+            return;
+        }
+        if (mTargetExcludes != null && mTargetExcludes.contains(view)) {
+            return;
+        }
+        if (mTargetTypeExcludes != null && view != null) {
+            int numTypes = mTargetTypeExcludes.size();
+            for (int i = 0; i < numTypes; ++i) {
+                if (mTargetTypeExcludes.get(i).isInstance(view)) {
+                    return;
+                }
+            }
+        }
+        TransitionValues values = new TransitionValues();
+        values.view = view;
+        if (start) {
+            captureStartValues(values);
+        } else {
+            captureEndValues(values);
+        }
+        if (start) {
+            if (!isListViewItem) {
+                mStartValues.viewValues.put(view, values);
+                if (id >= 0) {
+                    mStartValues.idValues.put((int) id, values);
+                }
+            } else {
+                mStartValues.itemIdValues.put(itemId, values);
+            }
+        } else {
+            if (!isListViewItem) {
+                mEndValues.viewValues.put(view, values);
+                if (id >= 0) {
+                    mEndValues.idValues.put((int) id, values);
+                }
+            } else {
+                mEndValues.itemIdValues.put(itemId, values);
+            }
+        }
+        if (view instanceof ViewGroup) {
+            // Don't traverse child hierarchy if there are any child-excludes on this view
+            if (mTargetIdChildExcludes != null && mTargetIdChildExcludes.contains(id)) {
+                return;
+            }
+            if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
+                return;
+            }
+            if (mTargetTypeChildExcludes != null && view != null) {
+                int numTypes = mTargetTypeChildExcludes.size();
+                for (int i = 0; i < numTypes; ++i) {
+                    if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
+                        return;
+                    }
+                }
+            }
+            ViewGroup parent = (ViewGroup) view;
+            for (int i = 0; i < parent.getChildCount(); ++i) {
+                captureHierarchy(parent.getChildAt(i), start);
+            }
+        }
+    }
+
+    /**
+     * This method can be called by transitions to get the TransitionValues for
+     * any particular view during the transition-playing process. This might be
+     * necessary, for example, to query the before/after state of related views
+     * for a given transition.
+     */
+    public TransitionValues getTransitionValues(View view, boolean start) {
+        if (mParent != null) {
+            return mParent.getTransitionValues(view, start);
+        }
+        TransitionValuesMaps valuesMaps = start ? mStartValues : mEndValues;
+        TransitionValues values = valuesMaps.viewValues.get(view);
+        if (values == null) {
+            int id = view.getId();
+            if (id >= 0) {
+                values = valuesMaps.idValues.get(id);
+            }
+            if (values == null && view.getParent() instanceof ListView) {
+                ListView listview = (ListView) view.getParent();
+                int position = listview.getPositionForView(view);
+                long itemId = listview.getItemIdAtPosition(position);
+                values = valuesMaps.itemIdValues.get(itemId);
+            }
+            // TODO: Doesn't handle the case where a view was parented to a
+            // ListView (with an itemId), but no longer is
+        }
+        return values;
+    }
+
+    /**
+     * Pauses this transition, sending out calls to {@link
+     * TransitionListener#onTransitionPause(Transition)} to all listeners
+     * and pausing all running animators started by this transition.
+     *
+     * @hide
+     */
+    public void pause() {
+        if (!mEnded) {
+            ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+            int numOldAnims = runningAnimators.size();
+            for (int i = numOldAnims - 1; i >= 0; i--) {
+                Animator anim = runningAnimators.keyAt(i);
+                anim.pause();
+            }
+            if (mListeners != null && mListeners.size() > 0) {
+                ArrayList<TransitionListener> tmpListeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onTransitionPause(this);
+                }
+            }
+            mPaused = true;
+        }
+    }
+
+    /**
+     * Resumes this transition, sending out calls to {@link
+     * TransitionListener#onTransitionPause(Transition)} to all listeners
+     * and pausing all running animators started by this transition.
+     *
+     * @hide
+     */
+    public void resume() {
+        if (mPaused) {
+            if (!mEnded) {
+                ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+                int numOldAnims = runningAnimators.size();
+                for (int i = numOldAnims - 1; i >= 0; i--) {
+                    Animator anim = runningAnimators.keyAt(i);
+                    anim.resume();
+                }
+                if (mListeners != null && mListeners.size() > 0) {
+                    ArrayList<TransitionListener> tmpListeners =
+                            (ArrayList<TransitionListener>) mListeners.clone();
+                    int numListeners = tmpListeners.size();
+                    for (int i = 0; i < numListeners; ++i) {
+                        tmpListeners.get(i).onTransitionResume(this);
+                    }
+                }
+            }
+            mPaused = false;
+        }
+    }
+
+    /**
+     * Called by TransitionManager to play the transition. This calls
+     * createAnimators() to set things up and create all of the animations and then
+     * runAnimations() to actually start the animations.
+     */
+    void playTransition(ViewGroup sceneRoot) {
+        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        int numOldAnims = runningAnimators.size();
+        for (int i = numOldAnims - 1; i >= 0; i--) {
+            Animator anim = runningAnimators.keyAt(i);
+            if (anim != null) {
+                AnimationInfo oldInfo = runningAnimators.get(anim);
+                if (oldInfo != null) {
+                    boolean cancel = false;
+                    TransitionValues oldValues = oldInfo.values;
+                    View oldView = oldInfo.view;
+                    TransitionValues newValues = mEndValues.viewValues != null ?
+                            mEndValues.viewValues.get(oldView) : null;
+                    if (newValues == null) {
+                        newValues = mEndValues.idValues.get(oldView.getId());
+                    }
+                    if (oldValues != null) {
+                        // if oldValues null, then transition didn't care to stash values,
+                        // and won't get canceled
+                        if (newValues != null) {
+                            for (String key : oldValues.values.keySet()) {
+                                Object oldValue = oldValues.values.get(key);
+                                Object newValue = newValues.values.get(key);
+                                if (oldValue != null && newValue != null &&
+                                        !oldValue.equals(newValue)) {
+                                    cancel = true;
+                                    if (DBG) {
+                                        Log.d(LOG_TAG, "Transition.playTransition: " +
+                                                "oldValue != newValue for " + key +
+                                                ": old, new = " + oldValue + ", " + newValue);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    if (cancel) {
+                        if (anim.isRunning() || anim.isStarted()) {
+                            if (DBG) {
+                                Log.d(LOG_TAG, "Canceling anim " + anim);
+                            }
+                            anim.cancel();
+                        } else {
+                            if (DBG) {
+                                Log.d(LOG_TAG, "removing anim from info list: " + anim);
+                            }
+                            runningAnimators.remove(anim);
+                        }
+                    }
+                }
+            }
+        }
+
+        createAnimators(sceneRoot, mStartValues, mEndValues);
+        runAnimators();
+    }
+
+    /**
+     * This is a utility method used by subclasses to handle standard parts of
+     * setting up and running an Animator: it sets the {@link #getDuration()
+     * duration} and the {@link #getStartDelay() startDelay}, starts the
+     * animation, and, when the animator ends, calls {@link #end()}.
+     *
+     * @param animator The Animator to be run during this transition.
+     *
+     * @hide
+     */
+    protected void animate(Animator animator) {
+        // TODO: maybe pass auto-end as a boolean parameter?
+        if (animator == null) {
+            end();
+        } else {
+            if (getDuration() >= 0) {
+                animator.setDuration(getDuration());
+            }
+            if (getStartDelay() >= 0) {
+                animator.setStartDelay(getStartDelay());
+            }
+            if (getInterpolator() != null) {
+                animator.setInterpolator(getInterpolator());
+            }
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    end();
+                    animation.removeListener(this);
+                }
+            });
+            animator.start();
+        }
+    }
+
+    /**
+     * This method is called automatically by the transition and
+     * TransitionSet classes prior to a Transition subclass starting;
+     * subclasses should not need to call it directly.
+     *
+     * @hide
+     */
+    protected void start() {
+        if (mNumInstances == 0) {
+            if (mListeners != null && mListeners.size() > 0) {
+                ArrayList<TransitionListener> tmpListeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onTransitionStart(this);
+                }
+            }
+            mEnded = false;
+        }
+        mNumInstances++;
+    }
+
+    /**
+     * This method is called automatically by the Transition and
+     * TransitionSet classes when a transition finishes, either because
+     * a transition did nothing (returned a null Animator from
+     * {@link Transition#createAnimator(ViewGroup, TransitionValues,
+     * TransitionValues)}) or because the transition returned a valid
+     * Animator and end() was called in the onAnimationEnd()
+     * callback of the AnimatorListener.
+     *
+     * @hide
+     */
+    protected void end() {
+        --mNumInstances;
+        if (mNumInstances == 0) {
+            if (mListeners != null && mListeners.size() > 0) {
+                ArrayList<TransitionListener> tmpListeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onTransitionEnd(this);
+                }
+            }
+            for (int i = 0; i < mStartValues.itemIdValues.size(); ++i) {
+                TransitionValues tv = mStartValues.itemIdValues.valueAt(i);
+                View v = tv.view;
+                if (v.hasTransientState()) {
+                    v.setHasTransientState(false);
+                }
+            }
+            for (int i = 0; i < mEndValues.itemIdValues.size(); ++i) {
+                TransitionValues tv = mEndValues.itemIdValues.valueAt(i);
+                View v = tv.view;
+                if (v.hasTransientState()) {
+                    v.setHasTransientState(false);
+                }
+            }
+            mEnded = true;
+        }
+    }
+
+    /**
+     * This method cancels a transition that is currently running.
+     *
+     * @hide
+     */
+    protected void cancel() {
+        int numAnimators = mCurrentAnimators.size();
+        for (int i = numAnimators - 1; i >= 0; i--) {
+            Animator animator = mCurrentAnimators.get(i);
+            animator.cancel();
+        }
+        if (mListeners != null && mListeners.size() > 0) {
+            ArrayList<TransitionListener> tmpListeners =
+                    (ArrayList<TransitionListener>) mListeners.clone();
+            int numListeners = tmpListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                tmpListeners.get(i).onTransitionCancel(this);
+            }
+        }
+    }
+
+    /**
+     * Adds a listener to the set of listeners that are sent events through the
+     * life of an animation, such as start, repeat, and end.
+     *
+     * @param listener the listener to be added to the current set of listeners
+     * for this animation.
+     * @return This transition object.
+     */
+    public Transition addListener(TransitionListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<TransitionListener>();
+        }
+        mListeners.add(listener);
+        return this;
+    }
+
+    /**
+     * Removes a listener from the set listening to this animation.
+     *
+     * @param listener the listener to be removed from the current set of
+     * listeners for this transition.
+     * @return This transition object.
+     */
+    public Transition removeListener(TransitionListener listener) {
+        if (mListeners == null) {
+            return this;
+        }
+        mListeners.remove(listener);
+        if (mListeners.size() == 0) {
+            mListeners = null;
+        }
+        return this;
+    }
+
+    Transition setSceneRoot(ViewGroup sceneRoot) {
+        mSceneRoot = sceneRoot;
+        return this;
+    }
+
+    void setCanRemoveViews(boolean canRemoveViews) {
+        mCanRemoveViews = canRemoveViews;
+    }
+
+    @Override
+    public String toString() {
+        return toString("");
+    }
+
+    @Override
+    public Transition clone() {
+        Transition clone = null;
+        try {
+            clone = (Transition) super.clone();
+            clone.mAnimators = new ArrayList<Animator>();
+            clone.mStartValues = new TransitionValuesMaps();
+            clone.mEndValues = new TransitionValuesMaps();
+        } catch (CloneNotSupportedException e) {}
+
+        return clone;
+    }
+
+    /**
+     * Returns the name of this Transition. This name is used internally to distinguish
+     * between different transitions to determine when interrupting transitions overlap.
+     * For example, a ChangeBounds running on the same target view as another ChangeBounds
+     * should determine whether the old transition is animating to different end values
+     * and should be canceled in favor of the new transition.
+     *
+     * <p>By default, a Transition's name is simply the value of {@link Class#getName()},
+     * but subclasses are free to override and return something different.</p>
+     *
+     * @return The name of this transition.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    String toString(String indent) {
+        String result = indent + getClass().getSimpleName() + "@" +
+                Integer.toHexString(hashCode()) + ": ";
+        if (mDuration != -1) {
+            result += "dur(" + mDuration + ") ";
+        }
+        if (mStartDelay != -1) {
+            result += "dly(" + mStartDelay + ") ";
+        }
+        if (mInterpolator != null) {
+            result += "interp(" + mInterpolator + ") ";
+        }
+        if (mTargetIds.size() > 0 || mTargets.size() > 0) {
+            result += "tgts(";
+            if (mTargetIds.size() > 0) {
+                for (int i = 0; i < mTargetIds.size(); ++i) {
+                    if (i > 0) {
+                        result += ", ";
+                    }
+                    result += mTargetIds.get(i);
+                }
+            }
+            if (mTargets.size() > 0) {
+                for (int i = 0; i < mTargets.size(); ++i) {
+                    if (i > 0) {
+                        result += ", ";
+                    }
+                    result += mTargets.get(i);
+                }
+            }
+            result += ")";
+        }
+        return result;
+    }
+
+    /**
+     * A transition listener receives notifications from a transition.
+     * Notifications indicate transition lifecycle events.
+     */
+    public static interface TransitionListener {
+        /**
+         * Notification about the start of the transition.
+         *
+         * @param transition The started transition.
+         */
+        void onTransitionStart(Transition transition);
+
+        /**
+         * Notification about the end of the transition. Canceled transitions
+         * will always notify listeners of both the cancellation and end
+         * events. That is, {@link #onTransitionEnd(Transition)} is always called,
+         * regardless of whether the transition was canceled or played
+         * through to completion.
+         *
+         * @param transition The transition which reached its end.
+         */
+        void onTransitionEnd(Transition transition);
+
+        /**
+         * Notification about the cancellation of the transition.
+         * Note that cancel may be called by a parent {@link TransitionSet} on
+         * a child transition which has not yet started. This allows the child
+         * transition to restore state on target objects which was set at
+         * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)
+         * createAnimator()} time.
+         *
+         * @param transition The transition which was canceled.
+         */
+        void onTransitionCancel(Transition transition);
+
+        /**
+         * Notification when a transition is paused.
+         * Note that createAnimator() may be called by a parent {@link TransitionSet} on
+         * a child transition which has not yet started. This allows the child
+         * transition to restore state on target objects which was set at
+         * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)
+         * createAnimator()} time.
+         *
+         * @param transition The transition which was paused.
+         */
+        void onTransitionPause(Transition transition);
+
+        /**
+         * Notification when a transition is resumed.
+         * Note that resume() may be called by a parent {@link TransitionSet} on
+         * a child transition which has not yet started. This allows the child
+         * transition to restore state which may have changed in an earlier call
+         * to {@link #onTransitionPause(Transition)}.
+         *
+         * @param transition The transition which was resumed.
+         */
+        void onTransitionResume(Transition transition);
+    }
+
+    /**
+     * Utility adapter class to avoid having to override all three methods
+     * whenever someone just wants to listen for a single event.
+     *
+     * @hide
+     * */
+    public static class TransitionListenerAdapter implements TransitionListener {
+        @Override
+        public void onTransitionStart(Transition transition) {
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+        }
+
+        @Override
+        public void onTransitionCancel(Transition transition) {
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+        }
+
+        @Override
+        public void onTransitionResume(Transition transition) {
+        }
+    }
+
+    /**
+     * Holds information about each animator used when a new transition starts
+     * while other transitions are still running to determine whether a running
+     * animation should be canceled or a new animation noop'd. The structure holds
+     * information about the state that an animation is going to, to be compared to
+     * end state of a new animation.
+     */
+    private static class AnimationInfo {
+        View view;
+        String name;
+        TransitionValues values;
+
+        AnimationInfo(View view, String name, TransitionValues values) {
+            this.view = view;
+            this.name = name;
+            this.values = values;
+        }
+    }
+
+    /**
+     * Utility class for managing typed ArrayLists efficiently. In particular, this
+     * can be useful for lists that we don't expect to be used often (eg, the exclude
+     * lists), so we'd like to keep them nulled out by default. This causes the code to
+     * become tedious, with constant null checks, code to allocate when necessary,
+     * and code to null out the reference when the list is empty. This class encapsulates
+     * all of that functionality into simple add()/remove() methods which perform the
+     * necessary checks, allocation/null-out as appropriate, and return the
+     * resulting list.
+     */
+    private static class ArrayListManager {
+
+        /**
+         * Add the specified item to the list, returning the resulting list.
+         * The returned list can either the be same list passed in or, if that
+         * list was null, the new list that was created.
+         *
+         * Note that the list holds unique items; if the item already exists in the
+         * list, the list is not modified.
+         */
+        static <T> ArrayList<T> add(ArrayList<T> list, T item) {
+            if (list == null) {
+                list = new ArrayList<T>();
+            }
+            if (!list.contains(item)) {
+                list.add(item);
+            }
+            return list;
+        }
+
+        /**
+         * Remove the specified item from the list, returning the resulting list.
+         * The returned list can either the be same list passed in or, if that
+         * list becomes empty as a result of the remove(), the new list was created.
+         */
+        static <T> ArrayList<T> remove(ArrayList<T> list, T item) {
+            if (list != null) {
+                list.remove(item);
+                if (list.isEmpty()) {
+                    list = null;
+                }
+            }
+            return list;
+        }
+    }
+
+}
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
new file mode 100644
index 0000000..eeb6cba
--- /dev/null
+++ b/core/java/android/transition/TransitionInflater.java
@@ -0,0 +1,327 @@
+/*
+ * 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 android.transition;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.util.Xml;
+import android.view.InflateException;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * This class inflates scenes and transitions from resource files.
+ *
+ * Information on XML resource descriptions for transitions can be found for
+ * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * and {@link android.R.styleable#TransitionManager}.
+ */
+public class TransitionInflater {
+
+    // We only need one inflater for any given context. Also, this allows us to associate
+    // ids with unique instances per-Context, used to avoid re-inflating
+    // already-inflated resources into new/different instances
+    private static final ArrayMap<Context, TransitionInflater> sInflaterMap =
+            new ArrayMap<Context, TransitionInflater>();
+
+    private Context mContext;
+    // TODO: do we need id maps for transitions and transitionMgrs as well?
+    SparseArray<Scene> mScenes = new SparseArray<Scene>();
+
+    private TransitionInflater(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Obtains the TransitionInflater from the given context.
+     */
+    public static TransitionInflater from(Context context) {
+        TransitionInflater inflater = sInflaterMap.get(context);
+        if (inflater != null) {
+            return inflater;
+        }
+        inflater = new TransitionInflater(context);
+        sInflaterMap.put(context, inflater);
+        return inflater;
+    }
+
+    /**
+     * Loads a {@link Transition} object from a resource
+     *
+     * @param resource The resource id of the transition to load
+     * @return The loaded Transition object
+     * @throws android.content.res.Resources.NotFoundException when the
+     * transition cannot be loaded
+     */
+    public Transition inflateTransition(int resource) {
+        XmlResourceParser parser =  mContext.getResources().getXml(resource);
+        try {
+            return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null);
+        } catch (XmlPullParserException e) {
+            InflateException ex = new InflateException(e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        } catch (IOException e) {
+            InflateException ex = new InflateException(
+                    parser.getPositionDescription()
+                            + ": " + e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        } finally {
+            parser.close();
+        }
+    }
+
+    /**
+     * Loads a {@link TransitionManager} object from a resource
+     *
+     *
+     *
+     * @param resource The resource id of the transition manager to load
+     * @return The loaded TransitionManager object
+     * @throws android.content.res.Resources.NotFoundException when the
+     * transition manager cannot be loaded
+     */
+    public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {
+        XmlResourceParser parser =  mContext.getResources().getXml(resource);
+        try {
+            return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot);
+        } catch (XmlPullParserException e) {
+            InflateException ex = new InflateException(e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        } catch (IOException e) {
+            InflateException ex = new InflateException(
+                    parser.getPositionDescription()
+                            + ": " + e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        } finally {
+            parser.close();
+        }
+    }
+
+    //
+    // Transition loading
+    //
+
+    private Transition createTransitionFromXml(XmlPullParser parser,
+            AttributeSet attrs, TransitionSet transitionSet)
+            throws XmlPullParserException, IOException {
+
+        Transition transition = 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) {
+
+            boolean newTransition = false;
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String  name = parser.getName();
+            if ("fade".equals(name)) {
+                TypedArray a = mContext.obtainStyledAttributes(attrs,
+                        com.android.internal.R.styleable.Fade);
+                int fadingMode = a.getInt(com.android.internal.R.styleable.Fade_fadingMode,
+                        Fade.IN | Fade.OUT);
+                transition = new Fade(fadingMode);
+                newTransition = true;
+            } else if ("changeBounds".equals(name)) {
+                transition = new ChangeBounds();
+                newTransition = true;
+            } else if ("slide".equals(name)) {
+                transition = new Slide();
+                newTransition = true;
+            } else if ("autoTransition".equals(name)) {
+                transition = new AutoTransition();
+                newTransition = true;
+            } else if ("recolor".equals(name)) {
+                transition = new Recolor();
+                newTransition = true;
+            } else if ("set".equals(name)) {
+                transition = new TransitionSet();
+                TypedArray a = mContext.obtainStyledAttributes(attrs,
+                        com.android.internal.R.styleable.TransitionSet);
+                int ordering = a.getInt(
+                        com.android.internal.R.styleable.TransitionSet_transitionOrdering,
+                        TransitionSet.ORDERING_TOGETHER);
+                ((TransitionSet) transition).setOrdering(ordering);
+                createTransitionFromXml(parser, attrs, ((TransitionSet) transition));
+                a.recycle();
+                newTransition = true;
+            } else if ("targets".equals(name)) {
+                if (parser.getDepth() - 1 > depth && transition != null) {
+                    // We're inside the child tag - add targets to the child
+                    getTargetIds(parser, attrs, transition);
+                } else if (parser.getDepth() - 1 == depth && transitionSet != null) {
+                    // add targets to the set
+                    getTargetIds(parser, attrs, transitionSet);
+                }
+            }
+            if (transition != null || "targets".equals(name)) {
+                if (newTransition) {
+                    loadTransition(transition, attrs);
+                    if (transitionSet != null) {
+                        transitionSet.addTransition(transition);
+                    }
+                }
+            } else {
+                throw new RuntimeException("Unknown scene name: " + parser.getName());
+            }
+        }
+
+        return transition;
+    }
+
+    private void getTargetIds(XmlPullParser parser,
+            AttributeSet attrs, Transition transition) throws XmlPullParserException, IOException {
+
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+
+        ArrayList<Integer> targetIds = new ArrayList<Integer>();
+        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("target")) {
+                TypedArray a = mContext.obtainStyledAttributes(attrs,
+                        com.android.internal.R.styleable.TransitionTarget);
+                int id = a.getResourceId(
+                        com.android.internal.R.styleable.TransitionTarget_targetId, -1);
+                if (id >= 0) {
+                    targetIds.add(id);
+                }
+            } else {
+                throw new RuntimeException("Unknown scene name: " + parser.getName());
+            }
+        }
+        int numTargets = targetIds.size();
+        if (numTargets > 0) {
+            for (int i = 0; i < numTargets; ++i) {
+                transition.addTarget(targetIds.get(i));
+            }
+        }
+    }
+
+    private Transition loadTransition(Transition transition, AttributeSet attrs)
+            throws Resources.NotFoundException {
+
+        TypedArray a =
+                mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Transition);
+        long duration = a.getInt(com.android.internal.R.styleable.Transition_duration, -1);
+        if (duration >= 0) {
+            transition.setDuration(duration);
+        }
+        long startDelay = a.getInt(com.android.internal.R.styleable.Transition_startDelay, -1);
+        if (startDelay > 0) {
+            transition.setStartDelay(startDelay);
+        }
+        final int resID =
+                a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
+        if (resID > 0) {
+            transition.setInterpolator(AnimationUtils.loadInterpolator(mContext, resID));
+        }
+        a.recycle();
+        return transition;
+    }
+
+    //
+    // TransitionManager loading
+    //
+
+    private TransitionManager createTransitionManagerFromXml(XmlPullParser parser,
+            AttributeSet attrs, ViewGroup sceneRoot) throws XmlPullParserException, IOException {
+
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+        TransitionManager transitionManager = null;
+
+        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("transitionManager")) {
+                transitionManager = new TransitionManager();
+            } else if (name.equals("transition") && (transitionManager != null)) {
+                loadTransition(attrs, sceneRoot, transitionManager);
+            } else {
+                throw new RuntimeException("Unknown scene name: " + parser.getName());
+            }
+        }
+        return transitionManager;
+    }
+
+    private void loadTransition(AttributeSet attrs, ViewGroup sceneRoot,
+            TransitionManager transitionManager) throws Resources.NotFoundException {
+
+        TypedArray a = mContext.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.TransitionManager);
+        int transitionId = a.getResourceId(
+                com.android.internal.R.styleable.TransitionManager_transition, -1);
+        Scene fromScene = null, toScene = null;
+        int fromId = a.getResourceId(
+                com.android.internal.R.styleable.TransitionManager_fromScene, -1);
+        if (fromId >= 0) fromScene = Scene.getSceneForLayout(sceneRoot, fromId, mContext);
+        int toId = a.getResourceId(
+                com.android.internal.R.styleable.TransitionManager_toScene, -1);
+        if (toId >= 0) toScene = Scene.getSceneForLayout(sceneRoot, toId, mContext);
+        if (transitionId >= 0) {
+            Transition transition = inflateTransition(transitionId);
+            if (transition != null) {
+                if (fromScene != null) {
+                    if (toScene == null){
+                        throw new RuntimeException("No matching toScene for given fromScene " +
+                                "for transition ID " + transitionId);
+                    } else {
+                        transitionManager.setTransition(fromScene, toScene, transition);
+                    }
+                } else if (toId >= 0) {
+                    transitionManager.setTransition(toScene, transition);
+                }
+            }
+        }
+        a.recycle();
+    }
+}
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
new file mode 100644
index 0000000..9be91d0
--- /dev/null
+++ b/core/java/android/transition/TransitionManager.java
@@ -0,0 +1,372 @@
+/*
+ * 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 android.transition;
+
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * This class manages the set of transitions that fire when there is a
+ * change of {@link Scene}. To use the manager, add scenes along with
+ * transition objects with calls to {@link #setTransition(Scene, Transition)}
+ * or {@link #setTransition(Scene, Scene, Transition)}. Setting specific
+ * transitions for scene changes is not required; by default, a Scene change
+ * will use {@link AutoTransition} to do something reasonable for most
+ * situations. Specifying other transitions for particular scene changes is
+ * only necessary if the application wants different transition behavior
+ * in these situations.
+ *
+ * <p>TransitionManagers can be declared in XML resource files inside the
+ * <code>res/transition</code> directory. TransitionManager resources consist of
+ * the <code>transitionManager</code>tag name, containing one or more
+ * <code>transition</code> tags, each of which describe the relationship of
+ * that transition to the from/to scene information in that tag.
+ * For example, here is a resource file that declares several scene
+ * transitions:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/transition/transitions_mgr.xml TransitionManager}
+ *
+ * <p>For each of the <code>fromScene</code> and <code>toScene</code> attributes,
+ * there is a reference to a standard XML layout file. This is equivalent to
+ * creating a scene from a layout in code by calling
+ * {@link Scene#getSceneForLayout(ViewGroup, int, Context)}. For the
+ * <code>transition</code> attribute, there is a reference to a resource
+ * file in the <code>res/transition</code> directory which describes that
+ * transition.</p>
+ *
+ * Information on XML resource descriptions for transitions can be found for
+ * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * and {@link android.R.styleable#TransitionManager}.
+ */
+public class TransitionManager {
+    // TODO: how to handle enter/exit?
+
+    private static String LOG_TAG = "TransitionManager";
+
+    private static Transition sDefaultTransition = new AutoTransition();
+
+    ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
+    ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
+            new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
+    private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
+            sRunningTransitions =
+            new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
+    private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
+
+
+    /**
+     * Sets the transition to be used for any scene change for which no
+     * other transition is explicitly set. The initial value is
+     * an {@link AutoTransition} instance.
+     *
+     * @param transition The default transition to be used for scene changes.
+     */
+    public void setDefaultTransition(Transition transition) {
+        sDefaultTransition = transition;
+    }
+
+    /**
+     * Gets the current default transition. The initial value is an {@link
+     * AutoTransition} instance.
+     *
+     * @return The current default transition.
+     * @see #setDefaultTransition(Transition)
+     */
+    public static Transition getDefaultTransition() {
+        return sDefaultTransition;
+    }
+
+    /**
+     * Sets a specific transition to occur when the given scene is entered.
+     *
+     * @param scene The scene which, when applied, will cause the given
+     * transition to run.
+     * @param transition The transition that will play when the given scene is
+     * entered. A value of null will result in the default behavior of
+     * using the {@link #getDefaultTransition() default transition} instead.
+     */
+    public void setTransition(Scene scene, Transition transition) {
+        mSceneTransitions.put(scene, transition);
+    }
+
+    /**
+     * Sets a specific transition to occur when the given pair of scenes is
+     * exited/entered.
+     *
+     * @param fromScene The scene being exited when the given transition will
+     * be run
+     * @param toScene The scene being entered when the given transition will
+     * be run
+     * @param transition The transition that will play when the given scene is
+     * entered. A value of null will result in the default behavior of
+     * using the {@link #getDefaultTransition() default transition} instead.
+     */
+    public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
+        ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
+        if (sceneTransitionMap == null) {
+            sceneTransitionMap = new ArrayMap<Scene, Transition>();
+            mScenePairTransitions.put(toScene, sceneTransitionMap);
+        }
+        sceneTransitionMap.put(fromScene, transition);
+    }
+
+    /**
+     * Returns the Transition for the given scene being entered. The result
+     * depends not only on the given scene, but also the scene which the
+     * {@link Scene#getSceneRoot() sceneRoot} of the Scene is currently in.
+     *
+     * @param scene The scene being entered
+     * @return The Transition to be used for the given scene change. If no
+     * Transition was specified for this scene change, the {@link #getDefaultTransition()
+     * default transition} will be used instead.
+     */
+    private Transition getTransition(Scene scene) {
+        Transition transition = null;
+        ViewGroup sceneRoot = scene.getSceneRoot();
+        if (sceneRoot != null) {
+            // TODO: cached in Scene instead? long-term, cache in View itself
+            Scene currScene = Scene.getCurrentScene(sceneRoot);
+            if (currScene != null) {
+                ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(scene);
+                if (sceneTransitionMap != null) {
+                    transition = sceneTransitionMap.get(currScene);
+                    if (transition != null) {
+                        return transition;
+                    }
+                }
+            }
+        }
+        transition = mSceneTransitions.get(scene);
+        return (transition != null) ? transition : sDefaultTransition;
+    }
+
+    /**
+     * This is where all of the work of a transition/scene-change is
+     * orchestrated. This method captures the start values for the given
+     * transition, exits the current Scene, enters the new scene, captures
+     * the end values for the transition, and finally plays the
+     * resulting values-populated transition.
+     *
+     * @param scene The scene being entered
+     * @param transition The transition to play for this scene change
+     */
+    private static void changeScene(Scene scene, Transition transition) {
+
+        final ViewGroup sceneRoot = scene.getSceneRoot();
+
+        Transition transitionClone = transition.clone();
+        transitionClone.setSceneRoot(sceneRoot);
+
+        Scene oldScene = Scene.getCurrentScene(sceneRoot);
+        if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
+            transitionClone.setCanRemoveViews(true);
+        }
+
+        sceneChangeSetup(sceneRoot, transitionClone);
+
+        scene.enter();
+
+        sceneChangeRunTransition(sceneRoot, transitionClone);
+    }
+
+    private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
+        WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
+                sRunningTransitions.get();
+        if (runningTransitions == null || runningTransitions.get() == null) {
+            ArrayMap<ViewGroup, ArrayList<Transition>> transitions =
+                    new ArrayMap<ViewGroup, ArrayList<Transition>>();
+            runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(
+                    transitions);
+            sRunningTransitions.set(runningTransitions);
+        }
+        return runningTransitions.get();
+    }
+
+    private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
+            final Transition transition) {
+        if (transition != null) {
+            final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
+            final ViewTreeObserver.OnPreDrawListener listener =
+                    new ViewTreeObserver.OnPreDrawListener() {
+                public boolean onPreDraw() {
+                    sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+                    sPendingTransitions.remove(sceneRoot);
+                    // Add to running list, handle end to remove it
+                    final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+                            getRunningTransitions();
+                    ArrayList<Transition> currentTransitions = runningTransitions.get(sceneRoot);
+                    ArrayList<Transition> previousRunningTransitions = null;
+                    if (currentTransitions == null) {
+                        currentTransitions = new ArrayList<Transition>();
+                        runningTransitions.put(sceneRoot, currentTransitions);
+                    } else if (currentTransitions.size() > 0) {
+                        previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
+                    }
+                    currentTransitions.add(transition);
+                    transition.addListener(new Transition.TransitionListenerAdapter() {
+                        @Override
+                        public void onTransitionEnd(Transition transition) {
+                            ArrayList<Transition> currentTransitions =
+                                    runningTransitions.get(sceneRoot);
+                            currentTransitions.remove(transition);
+                        }
+                    });
+                    transition.captureValues(sceneRoot, false);
+                    if (previousRunningTransitions != null) {
+                        for (Transition runningTransition : previousRunningTransitions) {
+                            runningTransition.resume();
+                        }
+                    }
+                    transition.playTransition(sceneRoot);
+
+                    // Returning false from onPreDraw() skips the current frame. This is
+                    // necessary to avoid artifacts caused by resetting target views
+                    // to their proper end states for capturing. Waiting until the next
+                    // frame to draw allows these views to have their mid-transition
+                    // values set on them again and avoid artifacts.
+                    return false;
+                }
+            };
+            observer.addOnPreDrawListener(listener);
+        }
+    }
+
+    private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
+
+        // Capture current values
+        ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
+
+        if (runningTransitions != null && runningTransitions.size() > 0) {
+            for (Transition runningTransition : runningTransitions) {
+                runningTransition.pause();
+            }
+        }
+
+        if (transition != null) {
+            transition.captureValues(sceneRoot, true);
+        }
+
+        // Notify previous scene that it is being exited
+        Scene previousScene = Scene.getCurrentScene(sceneRoot);
+        if (previousScene != null) {
+            previousScene.exit();
+        }
+    }
+
+    /**
+     * Change to the given scene, using the
+     * appropriate transition for this particular scene change
+     * (as specified to the TransitionManager, or the default
+     * if no such transition exists).
+     *
+     * @param scene The Scene to change to
+     */
+    public void transitionTo(Scene scene) {
+        // Auto transition if there is no transition declared for the Scene, but there is
+        // a root or parent view
+        changeScene(scene, getTransition(scene));
+
+    }
+
+    /**
+     * Convenience method to simply change to the given scene using
+     * the default transition for TransitionManager.
+     *
+     * @param scene The Scene to change to
+     */
+    public static void go(Scene scene) {
+        changeScene(scene, sDefaultTransition);
+    }
+
+    /**
+     * Convenience method to simply change to the given scene using
+     * the given transition.
+     *
+     * <p>Passing in <code>null</code> for the transition parameter will
+     * result in the scene changing without any transition running, and is
+     * equivalent to calling {@link Scene#exit()} on the scene root's
+     * current scene, followed by {@link Scene#enter()} on the scene
+     * specified by the <code>scene</code> parameter.</p>
+     *
+     * @param scene The Scene to change to
+     * @param transition The transition to use for this scene change. A
+     * value of null causes the scene change to happen with no transition.
+     */
+    public static void go(Scene scene, Transition transition) {
+        changeScene(scene, transition);
+    }
+
+    /**
+     * Convenience method to animate, using the default transition,
+     * to a new scene defined by all changes within the given scene root between
+     * calling this method and the next rendering frame.
+     * Equivalent to calling {@link #beginDelayedTransition(ViewGroup, Transition)}
+     * with a value of <code>null</code> for the <code>transition</code> parameter.
+     *
+     * @param sceneRoot The root of the View hierarchy to run the transition on.
+     */
+    public static void beginDelayedTransition(final ViewGroup sceneRoot) {
+        beginDelayedTransition(sceneRoot, null);
+    }
+
+    /**
+     * Convenience method to animate to a new scene defined by all changes within
+     * the given scene root between calling this method and the next rendering frame.
+     * Calling this method causes TransitionManager to capture current values in the
+     * scene root and then post a request to run a transition on the next frame.
+     * At that time, the new values in the scene root will be captured and changes
+     * will be animated. There is no need to create a Scene; it is implied by
+     * changes which take place between calling this method and the next frame when
+     * the transition begins.
+     *
+     * <p>Calling this method several times before the next frame (for example, if
+     * unrelated code also wants to make dynamic changes and run a transition on
+     * the same scene root), only the first call will trigger capturing values
+     * and exiting the current scene. Subsequent calls to the method with the
+     * same scene root during the same frame will be ignored.</p>
+     *
+     * <p>Passing in <code>null</code> for the transition parameter will
+     * cause the TransitionManager to use its default transition.</p>
+     *
+     * @param sceneRoot The root of the View hierarchy to run the transition on.
+     * @param transition The transition to use for this change. A
+     * value of null causes the TransitionManager to use the default transition.
+     */
+    public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
+        if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
+            if (Transition.DBG) {
+                Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
+                        sceneRoot + ", " + transition);
+            }
+            sPendingTransitions.add(sceneRoot);
+            if (transition == null) {
+                transition = sDefaultTransition;
+            }
+            final Transition transitionClone = transition.clone();
+            sceneChangeSetup(sceneRoot, transitionClone);
+            Scene.setCurrentScene(sceneRoot, null);
+            sceneChangeRunTransition(sceneRoot, transitionClone);
+        }
+    }
+}
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
new file mode 100644
index 0000000..79cd8b6
--- /dev/null
+++ b/core/java/android/transition/TransitionSet.java
@@ -0,0 +1,371 @@
+/*
+ * 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 android.transition;
+
+import android.animation.TimeInterpolator;
+import android.util.AndroidRuntimeException;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * A TransitionSet is a parent of child transitions (including other
+ * TransitionSets). Using TransitionSets enables more complex
+ * choreography of transitions, where some sets play {@link #ORDERING_TOGETHER} and
+ * others play {@link #ORDERING_SEQUENTIAL}. For example, {@link AutoTransition}
+ * uses a TransitionSet to sequentially play a Fade(Fade.OUT), followed by
+ * a {@link ChangeBounds}, followed by a Fade(Fade.OUT) transition.
+ */
+public class TransitionSet extends Transition {
+
+    ArrayList<Transition> mTransitions = new ArrayList<Transition>();
+    private boolean mPlayTogether = true;
+    int mCurrentListeners;
+    boolean mStarted = false;
+
+    /**
+     * A flag used to indicate that the child transitions of this set
+     * should all start at the same time.
+     */
+    public static final int ORDERING_TOGETHER = 0;
+    /**
+     * A flag used to indicate that the child transitions of this set should
+     * play in sequence; when one child transition ends, the next child
+     * transition begins. Note that a transition does not end until all
+     * instances of it (which are playing on all applicable targets of the
+     * transition) end.
+     */
+    public static final int ORDERING_SEQUENTIAL = 1;
+
+    /**
+     * Constructs an empty transition set. Add child transitions to the
+     * set by calling {@link #addTransition(Transition)} )}. By default,
+     * child transitions will play {@link #ORDERING_TOGETHER together}.
+     */
+    public TransitionSet() {
+    }
+
+    /**
+     * Sets the play order of this set's child transitions.
+     *
+     * @param ordering {@link #ORDERING_TOGETHER} to play this set's child
+     * transitions together, {@link #ORDERING_SEQUENTIAL} to play the child
+     * transitions in sequence.
+     * @return This transitionSet object.
+     */
+    public TransitionSet setOrdering(int ordering) {
+        switch (ordering) {
+            case ORDERING_SEQUENTIAL:
+                mPlayTogether = false;
+                break;
+            case ORDERING_TOGETHER:
+                mPlayTogether = true;
+                break;
+            default:
+                throw new AndroidRuntimeException("Invalid parameter for TransitionSet " +
+                        "ordering: " + ordering);
+        }
+        return this;
+    }
+
+    /**
+     * Returns the ordering of this TransitionSet. By default, the value is
+     * {@link #ORDERING_TOGETHER}.
+     *
+     * @return {@link #ORDERING_TOGETHER} if child transitions will play at the same
+     * time, {@link #ORDERING_SEQUENTIAL} if they will play in sequence.
+     *
+     * @see #setOrdering(int)
+     */
+    public int getOrdering() {
+        return mPlayTogether ? ORDERING_TOGETHER : ORDERING_SEQUENTIAL;
+    }
+
+    /**
+     * Adds child transition to this set. The order in which this child transition
+     * is added relative to other child transitions that are added, in addition to
+     * the {@link #getOrdering() ordering} property, determines the
+     * order in which the transitions are started.
+     *
+     * <p>If this transitionSet has a {@link #getDuration() duration} set on it, the
+     * child transition will inherit that duration. Transitions are assumed to have
+     * a maximum of one transitionSet parent.</p>
+     *
+     * @param transition A non-null child transition to be added to this set.
+     * @return This transitionSet object.
+     */
+    public TransitionSet addTransition(Transition transition) {
+        if (transition != null) {
+            mTransitions.add(transition);
+            transition.mParent = this;
+            if (mDuration >= 0) {
+                transition.setDuration(mDuration);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Setting a non-negative duration on a TransitionSet causes all of the child
+     * transitions (current and future) to inherit this duration.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     * @return This transitionSet object.
+     */
+    @Override
+    public TransitionSet setDuration(long duration) {
+        super.setDuration(duration);
+        if (mDuration >= 0) {
+            int numTransitions = mTransitions.size();
+            for (int i = 0; i < numTransitions; ++i) {
+                mTransitions.get(i).setDuration(duration);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public TransitionSet setStartDelay(long startDelay) {
+        return (TransitionSet) super.setStartDelay(startDelay);
+    }
+
+    @Override
+    public TransitionSet setInterpolator(TimeInterpolator interpolator) {
+        return (TransitionSet) super.setInterpolator(interpolator);
+    }
+
+    @Override
+    public TransitionSet addTarget(View target) {
+        return (TransitionSet) super.addTarget(target);
+    }
+
+    @Override
+    public TransitionSet addTarget(int targetId) {
+        return (TransitionSet) super.addTarget(targetId);
+    }
+
+    @Override
+    public TransitionSet addListener(TransitionListener listener) {
+        return (TransitionSet) super.addListener(listener);
+    }
+
+    @Override
+    public TransitionSet removeTarget(int targetId) {
+        return (TransitionSet) super.removeTarget(targetId);
+    }
+
+    @Override
+    public TransitionSet removeTarget(View target) {
+        return (TransitionSet) super.removeTarget(target);
+    }
+
+    @Override
+    public TransitionSet removeListener(TransitionListener listener) {
+        return (TransitionSet) super.removeListener(listener);
+    }
+
+    /**
+     * Removes the specified child transition from this set.
+     *
+     * @param transition The transition to be removed.
+     * @return This transitionSet object.
+     */
+    public TransitionSet removeTransition(Transition transition) {
+        mTransitions.remove(transition);
+        transition.mParent = null;
+        return this;
+    }
+
+    /**
+     * Sets up listeners for each of the child transitions. This is used to
+     * determine when this transition set is finished (all child transitions
+     * must finish first).
+     */
+    private void setupStartEndListeners() {
+        TransitionSetListener listener = new TransitionSetListener(this);
+        for (Transition childTransition : mTransitions) {
+            childTransition.addListener(listener);
+        }
+        mCurrentListeners = mTransitions.size();
+    }
+
+    /**
+     * This listener is used to detect when all child transitions are done, at
+     * which point this transition set is also done.
+     */
+    static class TransitionSetListener extends TransitionListenerAdapter {
+        TransitionSet mTransitionSet;
+        TransitionSetListener(TransitionSet transitionSet) {
+            mTransitionSet = transitionSet;
+        }
+        @Override
+        public void onTransitionStart(Transition transition) {
+            if (!mTransitionSet.mStarted) {
+                mTransitionSet.start();
+                mTransitionSet.mStarted = true;
+            }
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            --mTransitionSet.mCurrentListeners;
+            if (mTransitionSet.mCurrentListeners == 0) {
+                // All child trans
+                mTransitionSet.mStarted = false;
+                mTransitionSet.end();
+            }
+            transition.removeListener(this);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
+            TransitionValuesMaps endValues) {
+        for (Transition childTransition : mTransitions) {
+            childTransition.createAnimators(sceneRoot, startValues, endValues);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    protected void runAnimators() {
+        setupStartEndListeners();
+        if (!mPlayTogether) {
+            // Setup sequence with listeners
+            // TODO: Need to add listeners in such a way that we can remove them later if canceled
+            for (int i = 1; i < mTransitions.size(); ++i) {
+                Transition previousTransition = mTransitions.get(i - 1);
+                final Transition nextTransition = mTransitions.get(i);
+                previousTransition.addListener(new TransitionListenerAdapter() {
+                    @Override
+                    public void onTransitionEnd(Transition transition) {
+                        nextTransition.runAnimators();
+                        transition.removeListener(this);
+                    }
+                });
+            }
+            Transition firstTransition = mTransitions.get(0);
+            if (firstTransition != null) {
+                firstTransition.runAnimators();
+            }
+        } else {
+            for (Transition childTransition : mTransitions) {
+                childTransition.runAnimators();
+            }
+        }
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        int targetId = transitionValues.view.getId();
+        if (isValidTarget(transitionValues.view, targetId)) {
+            for (Transition childTransition : mTransitions) {
+                if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+                    childTransition.captureStartValues(transitionValues);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        int targetId = transitionValues.view.getId();
+        if (isValidTarget(transitionValues.view, targetId)) {
+            for (Transition childTransition : mTransitions) {
+                if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+                    childTransition.captureEndValues(transitionValues);
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void pause() {
+        super.pause();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).pause();
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void resume() {
+        super.resume();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).resume();
+        }
+    }
+
+    /** @hide */
+    @Override
+    protected void cancel() {
+        super.cancel();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).cancel();
+        }
+    }
+
+    @Override
+    TransitionSet setSceneRoot(ViewGroup sceneRoot) {
+        super.setSceneRoot(sceneRoot);
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).setSceneRoot(sceneRoot);
+        }
+        return (TransitionSet) this;
+    }
+
+    @Override
+    void setCanRemoveViews(boolean canRemoveViews) {
+        super.setCanRemoveViews(canRemoveViews);
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).setCanRemoveViews(canRemoveViews);
+        }
+    }
+
+    @Override
+    String toString(String indent) {
+        String result = super.toString(indent);
+        for (int i = 0; i < mTransitions.size(); ++i) {
+            result += "\n" + mTransitions.get(i).toString(indent + "  ");
+        }
+        return result;
+    }
+
+    @Override
+    public TransitionSet clone() {
+        TransitionSet clone = (TransitionSet) super.clone();
+        clone.mTransitions = new ArrayList<Transition>();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            clone.addTransition((Transition) mTransitions.get(i).clone());
+        }
+        return clone;
+    }
+
+}
diff --git a/core/java/android/transition/TransitionValues.java b/core/java/android/transition/TransitionValues.java
new file mode 100644
index 0000000..8989f89
--- /dev/null
+++ b/core/java/android/transition/TransitionValues.java
@@ -0,0 +1,82 @@
+/*
+ * 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 android.transition;
+
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Map;
+
+/**
+ * Data structure which holds cached values for the transition.
+ * The view field is the target which all of the values pertain to.
+ * The values field is a map which holds information for fields
+ * according to names selected by the transitions. These names should
+ * be unique to avoid clobbering values stored by other transitions,
+ * such as the convention project:transition_name:property_name. For
+ * example, the platform might store a property "alpha" in a transition
+ * "Fader" as "android:fader:alpha".
+ *
+ * <p>These values are cached during the
+ * {@link Transition#captureStartValues(TransitionValues)}
+ * capture} phases of a scene change, once when the start values are captured
+ * and again when the end values are captured. These start/end values are then
+ * passed into the transitions via the
+ * for {@link Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+ * method.</p>
+ */
+public class TransitionValues {
+
+    /**
+     * The View with these values
+     */
+    public View view;
+
+    /**
+     * The set of values tracked by transitions for this scene
+     */
+    public final Map<String, Object> values = new ArrayMap<String, Object>();
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof TransitionValues) {
+            if (view == ((TransitionValues) other).view) {
+                if (values.equals(((TransitionValues) other).values)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return 31*view.hashCode() + values.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        String returnValue = "TransitionValues@" + Integer.toHexString(hashCode()) + ":\n";
+        returnValue += "    view = " + view + "\n";
+        returnValue += "    values:";
+        for (String s : values.keySet()) {
+            returnValue += "    " + s + ": " + values.get(s) + "\n";
+        }
+        return returnValue;
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/transition/TransitionValuesMaps.java b/core/java/android/transition/TransitionValuesMaps.java
new file mode 100644
index 0000000..131596b
--- /dev/null
+++ b/core/java/android/transition/TransitionValuesMaps.java
@@ -0,0 +1,30 @@
+/*
+ * 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 android.transition;
+
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+import android.view.View;
+
+class TransitionValuesMaps {
+    ArrayMap<View, TransitionValues> viewValues =
+            new ArrayMap<View, TransitionValues>();
+    SparseArray<TransitionValues> idValues = new SparseArray<TransitionValues>();
+    LongSparseArray<TransitionValues> itemIdValues =
+            new LongSparseArray<TransitionValues>();
+}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
new file mode 100644
index 0000000..44f92cd
--- /dev/null
+++ b/core/java/android/transition/Visibility.java
@@ -0,0 +1,223 @@
+/*
+ * 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 android.transition;
+
+import android.animation.Animator;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition tracks changes to the visibility of target views in the
+ * start and end scenes. Visibility is determined not just by the
+ * {@link View#setVisibility(int)} state of views, but also whether
+ * views exist in the current view hierarchy. The class is intended to be a
+ * utility for subclasses such as {@link Fade}, which use this visibility
+ * information to determine the specific animations to run when visibility
+ * changes occur. Subclasses should implement one or both of the methods
+ * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
+ * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
+ */
+public abstract class Visibility extends Transition {
+
+    private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
+    private static final String PROPNAME_PARENT = "android:visibility:parent";
+    private static final String[] sTransitionProperties = {
+            PROPNAME_VISIBILITY,
+            PROPNAME_PARENT,
+    };
+
+    private static class VisibilityInfo {
+        boolean visibilityChange;
+        boolean fadeIn;
+        int startVisibility;
+        int endVisibility;
+        ViewGroup startParent;
+        ViewGroup endParent;
+    }
+
+    @Override
+    public String[] getTransitionProperties() {
+        return sTransitionProperties;
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        int visibility = transitionValues.view.getVisibility();
+        transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
+        transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    /**
+     * Returns whether the view is 'visible' according to the given values
+     * object. This is determined by testing the same properties in the values
+     * object that are used to determine whether the object is appearing or
+     * disappearing in the {@link
+     * Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+     * method. This method can be called by, for example, subclasses that want
+     * to know whether the object is visible in the same way that Visibility
+     * determines it for the actual animation.
+     *
+     * @param values The TransitionValues object that holds the information by
+     * which visibility is determined.
+     * @return True if the view reference by <code>values</code> is visible,
+     * false otherwise.
+     */
+    public boolean isVisible(TransitionValues values) {
+        if (values == null) {
+            return false;
+        }
+        int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
+        View parent = (View) values.values.get(PROPNAME_PARENT);
+
+        return visibility == View.VISIBLE && parent != null;
+    }
+
+    private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
+            TransitionValues endValues) {
+        final VisibilityInfo visInfo = new VisibilityInfo();
+        visInfo.visibilityChange = false;
+        visInfo.fadeIn = false;
+        if (startValues != null) {
+            visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
+            visInfo.startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
+        } else {
+            visInfo.startVisibility = -1;
+            visInfo.startParent = null;
+        }
+        if (endValues != null) {
+            visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
+            visInfo.endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
+        } else {
+            visInfo.endVisibility = -1;
+            visInfo.endParent = null;
+        }
+        if (startValues != null && endValues != null) {
+            if (visInfo.startVisibility == visInfo.endVisibility &&
+                    visInfo.startParent == visInfo.endParent) {
+                return visInfo;
+            } else {
+                if (visInfo.startVisibility != visInfo.endVisibility) {
+                    if (visInfo.startVisibility == View.VISIBLE) {
+                        visInfo.fadeIn = false;
+                        visInfo.visibilityChange = true;
+                    } else if (visInfo.endVisibility == View.VISIBLE) {
+                        visInfo.fadeIn = true;
+                        visInfo.visibilityChange = true;
+                    }
+                    // no visibilityChange if going between INVISIBLE and GONE
+                } else if (visInfo.startParent != visInfo.endParent) {
+                    if (visInfo.endParent == null) {
+                        visInfo.fadeIn = false;
+                        visInfo.visibilityChange = true;
+                    } else if (visInfo.startParent == null) {
+                        visInfo.fadeIn = true;
+                        visInfo.visibilityChange = true;
+                    }
+                }
+            }
+        }
+        if (startValues == null) {
+            visInfo.fadeIn = true;
+            visInfo.visibilityChange = true;
+        } else if (endValues == null) {
+            visInfo.fadeIn = false;
+            visInfo.visibilityChange = true;
+        }
+        return visInfo;
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
+        if (visInfo.visibilityChange) {
+            // Only transition views that are either targets of this transition
+            // or whose parent hierarchies remain stable between scenes
+            boolean isTarget = false;
+            if (mTargets.size() > 0 || mTargetIds.size() > 0) {
+                View startView = startValues != null ? startValues.view : null;
+                View endView = endValues != null ? endValues.view : null;
+                int startId = startView != null ? startView.getId() : -1;
+                int endId = endView != null ? endView.getId() : -1;
+                isTarget = isValidTarget(startView, startId) || isValidTarget(endView, endId);
+            }
+            if (isTarget || ((visInfo.startParent != null || visInfo.endParent != null))) {
+                if (visInfo.fadeIn) {
+                    return onAppear(sceneRoot, startValues, visInfo.startVisibility,
+                            endValues, visInfo.endVisibility);
+                } else {
+                    return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
+                            endValues, visInfo.endVisibility
+                    );
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The default implementation of this method does nothing. Subclasses
+     * should override if they need to create an Animator when targets appear.
+     * The method should only be called by the Visibility class; it is
+     * not intended to be called from external classes.
+     *
+     * @param sceneRoot The root of the transition hierarchy
+     * @param startValues The target values in the start scene
+     * @param startVisibility The target visibility in the start scene
+     * @param endValues The target values in the end scene
+     * @param endVisibility The target visibility in the end scene
+     * @return An Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    public Animator onAppear(ViewGroup sceneRoot,
+            TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return null;
+    }
+
+    /**
+     * The default implementation of this method does nothing. Subclasses
+     * should override if they need to create an Animator when targets disappear.
+     * The method should only be called by the Visibility class; it is
+     * not intended to be called from external classes.
+     *
+     *
+     * @param sceneRoot The root of the transition hierarchy
+     * @param startValues The target values in the start scene
+     * @param startVisibility The target visibility in the start scene
+     * @param endValues The target values in the end scene
+     * @param endVisibility The target visibility in the end scene
+     * @return An Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    public Animator onDisappear(ViewGroup sceneRoot,
+            TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return null;
+    }
+}
diff --git a/core/java/android/transition/package.html b/core/java/android/transition/package.html
new file mode 100644
index 0000000..f357d34
--- /dev/null
+++ b/core/java/android/transition/package.html
@@ -0,0 +1,26 @@
+<html>
+<body>
+<p>The classes in this package enable "scenes & transitions" functionality for
+view hiearchies.</p>
+
+<p>A <b>Scene</b> is an encapsulation of the state of a view hierarchy,
+including the views in that hierarchy and the various values (layout-related
+and otherwise) that those views have. A scene can be defined by a layout hierarchy
+directly or by code which sets up the scene dynamically as it is entered.</p>
+
+<p>A <b>Transition</b> is a mechanism to automatically animate changes that occur
+when a new scene is entered. Some transition capabilities are automatic. That
+is, entering a scene may cause animations to run which fade out views that
+go away, changeBounds and resize existing views that change, and fade in views that
+become visible. There are additional transitions that can animate other
+attributes, such as color changes, and which can optionally be specified
+to take place during particular scene changes. Finally, developers can
+define their own Transition subclasses which monitor particular property
+changes and which run custom animations when those properties change values.</p>
+
+<p><b>TransitionManager</b> is used to specify custom transitions for particular
+scene changes, and to cause scene changes with specific transitions to
+take place.</p>
+
+</body>
+</html>
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
new file mode 100644
index 0000000..fa534cc
--- /dev/null
+++ b/core/java/android/util/ArrayMap.java
@@ -0,0 +1,828 @@
+/*
+ * 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 android.util;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ArrayMap is a generic key->value mapping data structure that is
+ * designed to be more memory efficient than a traditional {@link java.util.HashMap}.
+ * It keeps its mappings in an array data structure -- an integer array of hash
+ * codes for each item, and an Object array of the key/value pairs.  This allows it to
+ * avoid having to create an extra object for every entry put in to the map, and it
+ * also tries to control the growth of the size of these arrays more aggressively
+ * (since growing them only requires copying the entries in the array, not rebuilding
+ * a hash map).
+ *
+ * <p>Note that this implementation is not intended to be appropriate for data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>Because this container is intended to better balance memory use, unlike most other
+ * standard Java containers it will shrink its array as items are removed from it.  Currently
+ * you have no control over this shrinking -- if you set a capacity and then remove an
+ * item, it may reduce the capacity to better match the current size.  In the future an
+ * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
+ */
+public final class ArrayMap<K, V> implements Map<K, V> {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "ArrayMap";
+
+    /**
+     * The minimum amount by which the capacity of a ArrayMap will increase.
+     * This is tuned to be relatively space-efficient.
+     */
+    private static final int BASE_SIZE = 4;
+
+    /**
+     * Maximum number of entries to have in array caches.
+     */
+    private static final int CACHE_SIZE = 10;
+
+    /**
+     * @hide Special immutable empty ArrayMap.
+     */
+    public static final ArrayMap EMPTY = new ArrayMap(true);
+
+    /**
+     * Caches of small array objects to avoid spamming garbage.  The cache
+     * Object[] variable is a pointer to a linked list of array objects.
+     * The first entry in the array is a pointer to the next array in the
+     * list; the second entry is a pointer to the int[] hash code array for it.
+     */
+    static Object[] mBaseCache;
+    static int mBaseCacheSize;
+    static Object[] mTwiceBaseCache;
+    static int mTwiceBaseCacheSize;
+
+    /**
+     * Special hash array value that indicates the container is immutable.
+     */
+    static final int[] EMPTY_IMMUTABLE_INTS = new int[0];
+
+    int[] mHashes;
+    Object[] mArray;
+    int mSize;
+    MapCollections<K, V> mCollections;
+
+    int indexOf(Object key, int hash) {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, hash);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (key.equals(mArray[index<<1])) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
+            if (key.equals(mArray[end << 1])) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
+            if (key.equals(mArray[i << 1])) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    int indexOfNull() {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, 0);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (null == mArray[index<<1]) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
+            if (null == mArray[end << 1]) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
+            if (null == mArray[i << 1]) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    private void allocArrays(final int size) {
+        if (mHashes == EMPTY_IMMUTABLE_INTS) {
+            throw new UnsupportedOperationException("ArrayMap is immutable");
+        }
+        if (size == (BASE_SIZE*2)) {
+            synchronized (ArrayMap.class) {
+                if (mTwiceBaseCache != null) {
+                    final Object[] array = mTwiceBaseCache;
+                    mArray = array;
+                    mTwiceBaseCache = (Object[])array[0];
+                    mHashes = (int[])array[1];
+                    array[0] = array[1] = null;
+                    mTwiceBaseCacheSize--;
+                    if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes
+                            + " now have " + mTwiceBaseCacheSize + " entries");
+                    return;
+                }
+            }
+        } else if (size == BASE_SIZE) {
+            synchronized (ArrayMap.class) {
+                if (mBaseCache != null) {
+                    final Object[] array = mBaseCache;
+                    mArray = array;
+                    mBaseCache = (Object[])array[0];
+                    mHashes = (int[])array[1];
+                    array[0] = array[1] = null;
+                    mBaseCacheSize--;
+                    if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
+                            + " now have " + mBaseCacheSize + " entries");
+                    return;
+                }
+            }
+        }
+
+        mHashes = new int[size];
+        mArray = new Object[size<<1];
+    }
+
+    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
+        if (hashes.length == (BASE_SIZE*2)) {
+            synchronized (ArrayMap.class) {
+                if (mTwiceBaseCacheSize < CACHE_SIZE) {
+                    array[0] = mTwiceBaseCache;
+                    array[1] = hashes;
+                    for (int i=(size<<1)-1; i>=2; i--) {
+                        array[i] = null;
+                    }
+                    mTwiceBaseCache = array;
+                    mTwiceBaseCacheSize++;
+                    if (DEBUG) Log.d(TAG, "Storing 2x cache " + array
+                            + " now have " + mTwiceBaseCacheSize + " entries");
+                }
+            }
+        } else if (hashes.length == BASE_SIZE) {
+            synchronized (ArrayMap.class) {
+                if (mBaseCacheSize < CACHE_SIZE) {
+                    array[0] = mBaseCache;
+                    array[1] = hashes;
+                    for (int i=(size<<1)-1; i>=2; i--) {
+                        array[i] = null;
+                    }
+                    mBaseCache = array;
+                    mBaseCacheSize++;
+                    if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
+                            + " now have " + mBaseCacheSize + " entries");
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a new empty ArrayMap.  The default capacity of an array map is 0, and
+     * will grow once items are added to it.
+     */
+    public ArrayMap() {
+        mHashes = ContainerHelpers.EMPTY_INTS;
+        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArrayMap with a given initial capacity.
+     */
+    public ArrayMap(int capacity) {
+        if (capacity == 0) {
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            allocArrays(capacity);
+        }
+        mSize = 0;
+    }
+
+    private ArrayMap(boolean immutable) {
+        mHashes = EMPTY_IMMUTABLE_INTS;
+        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArrayMap with the mappings from the given ArrayMap.
+     */
+    public ArrayMap(ArrayMap map) {
+        this();
+        if (map != null) {
+            putAll(map);
+        }
+    }
+
+    /**
+     * Make the array map empty.  All storage is released.
+     */
+    @Override
+    public void clear() {
+        if (mSize > 0) {
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mSize = 0;
+        }
+    }
+
+    /**
+     * @hide
+     * Like {@link #clear}, but doesn't reduce the capacity of the ArrayMap.
+     */
+    public void erase() {
+        if (mSize > 0) {
+            final int N = mSize<<1;
+            final Object[] array = mArray;
+            for (int i=0; i<N; i++) {
+                array[i] = null;
+            }
+        }
+    }
+
+    /**
+     * Ensure the array map can hold at least <var>minimumCapacity</var>
+     * items.
+     */
+    public void ensureCapacity(int minimumCapacity) {
+        if (mHashes.length < minimumCapacity) {
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(minimumCapacity);
+            if (mSize > 0) {
+                System.arraycopy(ohashes, 0, mHashes, 0, mSize);
+                System.arraycopy(oarray, 0, mArray, 0, mSize<<1);
+            }
+            freeArrays(ohashes, oarray, mSize);
+        }
+    }
+
+    /**
+     * Check whether a key exists in the array.
+     *
+     * @param key The key to search for.
+     * @return Returns true if the key exists, else false.
+     */
+    @Override
+    public boolean containsKey(Object key) {
+        return key == null ? (indexOfNull() >= 0) : (indexOf(key, key.hashCode()) >= 0);
+    }
+
+    int indexOfValue(Object value) {
+        final int N = mSize*2;
+        final Object[] array = mArray;
+        if (value == null) {
+            for (int i=1; i<N; i+=2) {
+                if (array[i] == null) {
+                    return i>>1;
+                }
+            }
+        } else {
+            for (int i=1; i<N; i+=2) {
+                if (value.equals(array[i])) {
+                    return i>>1;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Check whether a value exists in the array.  This requires a linear search
+     * through the entire array.
+     *
+     * @param value The value to search for.
+     * @return Returns true if the value exists, else false.
+     */
+    @Override
+    public boolean containsValue(Object value) {
+        return indexOfValue(value) >= 0;
+    }
+
+    /**
+     * Retrieve a value from the array.
+     * @param key The key of the value to retrieve.
+     * @return Returns the value associated with the given key,
+     * or null if there is no such key.
+     */
+    @Override
+    public V get(Object key) {
+        final int index = key == null ? indexOfNull() : indexOf(key, key.hashCode());
+        return index >= 0 ? (V)mArray[(index<<1)+1] : null;
+    }
+
+    /**
+     * Return the key at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the key stored at the given index.
+     */
+    public K keyAt(int index) {
+        return (K)mArray[index << 1];
+    }
+
+    /**
+     * Return the value at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value stored at the given index.
+     */
+    public V valueAt(int index) {
+        return (V)mArray[(index << 1) + 1];
+    }
+
+    /**
+     * Set the value at a given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @param value The new value to store at this index.
+     * @return Returns the previous value at the given index.
+     */
+    public V setValueAt(int index, V value) {
+        index = (index << 1) + 1;
+        V old = (V)mArray[index];
+        mArray[index] = value;
+        return old;
+    }
+
+    /**
+     * Return true if the array map contains no items.
+     */
+    @Override
+    public boolean isEmpty() {
+        return mSize <= 0;
+    }
+
+    /**
+     * Add a new value to the array map.
+     * @param key The key under which to store the value.  <b>Must not be null.</b>  If
+     * this key already exists in the array, its value will be replaced.
+     * @param value The value to store for the given key.
+     * @return Returns the old value that was stored for the given key, or null if there
+     * was no such key.
+     */
+    @Override
+    public V put(K key, V value) {
+        final int hash;
+        int index;
+        if (key == null) {
+            hash = 0;
+            index = indexOfNull();
+        } else {
+            hash = key.hashCode();
+            index = indexOf(key, hash);
+        }
+        if (index >= 0) {
+            index = (index<<1) + 1;
+            final V old = (V)mArray[index];
+            mArray[index] = value;
+            return old;
+        }
+
+        index = ~index;
+        if (mSize >= mHashes.length) {
+            final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))
+                    : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
+
+            if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n);
+
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(n);
+
+            if (mHashes.length > 0) {
+                if (DEBUG) Log.d(TAG, "put: copy 0-" + mSize + " to 0");
+                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
+                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
+            }
+
+            freeArrays(ohashes, oarray, mSize);
+        }
+
+        if (index < mSize) {
+            if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (mSize-index)
+                    + " to " + (index+1));
+            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);
+            System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
+        }
+
+        mHashes[index] = hash;
+        mArray[index<<1] = key;
+        mArray[(index<<1)+1] = value;
+        mSize++;
+        return null;
+    }
+
+    /**
+     * Special fast path for appending items to the end of the array without validation.
+     * The array must already be large enough to contain the item.
+     * @hide
+     */
+    public void append(K key, V value) {
+        int index = mSize;
+        final int hash = key == null ? 0 : key.hashCode();
+        if (index >= mHashes.length) {
+            throw new IllegalStateException("Array is full");
+        }
+        if (index > 0 && mHashes[index-1] > hash) {
+            RuntimeException e = new RuntimeException("here");
+            e.fillInStackTrace();
+            Log.w(TAG, "New hash " + hash
+                    + " is before end of array hash " + mHashes[index-1]
+                    + " at index " + index + " key " + key, e);
+            put(key, value);
+            return;
+        }
+        mSize = index+1;
+        mHashes[index] = hash;
+        index <<= 1;
+        mArray[index] = key;
+        mArray[index+1] = value;
+    }
+
+    /**
+     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>array</var>
+     * @param array The array whose contents are to be retrieved.
+     */
+    public void putAll(ArrayMap<? extends K, ? extends V> array) {
+        final int N = array.mSize;
+        ensureCapacity(mSize + N);
+        if (mSize == 0) {
+            if (N > 0) {
+                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
+                System.arraycopy(array.mArray, 0, mArray, 0, N<<1);
+                mSize = N;
+            }
+        } else {
+            for (int i=0; i<N; i++) {
+                put(array.keyAt(i), array.valueAt(i));
+            }
+        }
+    }
+
+    /**
+     * Remove an existing key from the array map.
+     * @param key The key of the mapping to remove.
+     * @return Returns the value that was stored under the key, or null if there
+     * was no such key.
+     */
+    @Override
+    public V remove(Object key) {
+        int index = key == null ? indexOfNull() : indexOf(key, key.hashCode());
+        if (index >= 0) {
+            return removeAt(index);
+        }
+
+        return null;
+    }
+
+    /**
+     * Remove the key/value mapping at the given index.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value that was stored at this index.
+     */
+    public V removeAt(int index) {
+        final Object old = mArray[(index << 1) + 1];
+        if (mSize <= 1) {
+            // Now empty.
+            if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mSize = 0;
+        } else {
+            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
+                // Shrunk enough to reduce size of arrays.  We don't allow it to
+                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
+                // that and BASE_SIZE.
+                final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2);
+
+                if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
+
+                final int[] ohashes = mHashes;
+                final Object[] oarray = mArray;
+                allocArrays(n);
+
+                mSize--;
+                if (index > 0) {
+                    if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0");
+                    System.arraycopy(ohashes, 0, mHashes, 0, index);
+                    System.arraycopy(oarray, 0, mArray, 0, index << 1);
+                }
+                if (index < mSize) {
+                    if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + mSize
+                            + " to " + index);
+                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1,
+                            (mSize - index) << 1);
+                }
+            } else {
+                mSize--;
+                if (index < mSize) {
+                    if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + mSize
+                            + " to " + index);
+                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1,
+                            (mSize - index) << 1);
+                }
+                mArray[mSize << 1] = null;
+                mArray[(mSize << 1) + 1] = null;
+            }
+        }
+        return (V)old;
+    }
+
+    /**
+     * Return the number of items in this array map.
+     */
+    @Override
+    public int size() {
+        return mSize;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns false if the object is not a map, or
+     * if the maps have different sizes. Otherwise, for each key in this map,
+     * values of both maps are compared. If the values for any key are not
+     * equal, the method returns false, otherwise it returns true.
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof Map) {
+            Map<?, ?> map = (Map<?, ?>) object;
+            if (size() != map.size()) {
+                return false;
+            }
+
+            try {
+                for (int i=0; i<mSize; i++) {
+                    K key = keyAt(i);
+                    V mine = valueAt(i);
+                    Object theirs = map.get(key);
+                    if (mine == null) {
+                        if (theirs != null || !map.containsKey(key)) {
+                            return false;
+                        }
+                    } else if (!mine.equals(theirs)) {
+                        return false;
+                    }
+                }
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        final int[] hashes = mHashes;
+        final Object[] array = mArray;
+        int result = 0;
+        for (int i = 0, v = 1, s = mSize; i < s; i++, v+=2) {
+            Object value = array[v];
+            result += hashes[i] ^ (value == null ? 0 : value.hashCode());
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings. If
+     * this map contains itself as a key or a value, the string "(this Map)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (isEmpty()) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            Object key = keyAt(i);
+            if (key != this) {
+                buffer.append(key);
+            } else {
+                buffer.append("(this Map)");
+            }
+            buffer.append('=');
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Map)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+
+    // ------------------------------------------------------------------------
+    // Interop with traditional Java containers.  Not as efficient as using
+    // specialized collection APIs.
+    // ------------------------------------------------------------------------
+
+    private MapCollections<K, V> getCollection() {
+        if (mCollections == null) {
+            mCollections = new MapCollections<K, V>() {
+                @Override
+                protected int colGetSize() {
+                    return mSize;
+                }
+
+                @Override
+                protected Object colGetEntry(int index, int offset) {
+                    return mArray[(index<<1) + offset];
+                }
+
+                @Override
+                protected int colIndexOfKey(Object key) {
+                    return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+                }
+
+                @Override
+                protected int colIndexOfValue(Object value) {
+                    return indexOfValue(value);
+                }
+
+                @Override
+                protected Map<K, V> colGetMap() {
+                    return ArrayMap.this;
+                }
+
+                @Override
+                protected void colPut(K key, V value) {
+                    put(key, value);
+                }
+
+                @Override
+                protected V colSetValue(int index, V value) {
+                    return setValueAt(index, value);
+                }
+
+                @Override
+                protected void colRemoveAt(int index) {
+                    removeAt(index);
+                }
+
+                @Override
+                protected void colClear() {
+                    clear();
+                }
+            };
+        }
+        return mCollections;
+    }
+
+    /**
+     * Determine if the array map contains all of the keys in the given collection.
+     * @param collection The collection whose contents are to be checked against.
+     * @return Returns true if this array map contains a key for every entry
+     * in <var>collection</var>, else returns false.
+     */
+    public boolean containsAll(Collection<?> collection) {
+        return MapCollections.containsAllHelper(this, collection);
+    }
+
+    /**
+     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>map</var>
+     * @param map The map whose contents are to be retrieved.
+     */
+    @Override
+    public void putAll(Map<? extends K, ? extends V> map) {
+        ensureCapacity(mSize + map.size());
+        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Remove all keys in the array map that exist in the given collection.
+     * @param collection The collection whose contents are to be used to remove keys.
+     * @return Returns true if any keys were removed from the array map, else false.
+     */
+    public boolean removeAll(Collection<?> collection) {
+        return MapCollections.removeAllHelper(this, collection);
+    }
+
+    /**
+     * Remove all keys in the array map that do <b>not</b> exist in the given collection.
+     * @param collection The collection whose contents are to be used to determine which
+     * keys to keep.
+     * @return Returns true if any keys were removed from the array map, else false.
+     */
+    public boolean retainAll(Collection<?> collection) {
+        return MapCollections.retainAllHelper(this, collection);
+    }
+
+    /**
+     * Return a {@link java.util.Set} for iterating over and interacting with all mappings
+     * in the array map.
+     *
+     * <p><b>Note:</b> this is a very inefficient way to access the array contents, it
+     * requires generating a number of temporary objects.</p>
+     *
+     * <p><b>Note:</b></p> the semantics of this
+     * Set are subtly different than that of a {@link java.util.HashMap}: most important,
+     * the {@link java.util.Map.Entry Map.Entry} object returned by its iterator is a single
+     * object that exists for the entire iterator, so you can <b>not</b> hold on to it
+     * after calling {@link java.util.Iterator#next() Iterator.next}.</p>
+     */
+    @Override
+    public Set<Map.Entry<K, V>> entrySet() {
+        return getCollection().getEntrySet();
+    }
+
+    /**
+     * Return a {@link java.util.Set} for iterating over and interacting with all keys
+     * in the array map.
+     *
+     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+     * requires generating a number of temporary objects.</p>
+     */
+    @Override
+    public Set<K> keySet() {
+        return getCollection().getKeySet();
+    }
+
+    /**
+     * Return a {@link java.util.Collection} for iterating over and interacting with all values
+     * in the array map.
+     *
+     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+     * requires generating a number of temporary objects.</p>
+     */
+    @Override
+    public Collection<V> values() {
+        return getCollection().getValues();
+    }
+}
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
new file mode 100644
index 0000000..3c695e9
--- /dev/null
+++ b/core/java/android/util/ArraySet.java
@@ -0,0 +1,670 @@
+/*
+ * 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 android.util;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ArraySet is a generic set data structure that is designed to be more memory efficient than a
+ * traditional {@link java.util.HashSet}.  The design is very similar to
+ * {@link ArrayMap}, with all of the caveats described there.  This implementation is
+ * separate from ArrayMap, however, so the Object array contains only one item for each
+ * entry in the set (instead of a pair for a mapping).
+ *
+ * <p>Note that this implementation is not intended to be appropriate for data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashSet, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>Because this container is intended to better balance memory use, unlike most other
+ * standard Java containers it will shrink its array as items are removed from it.  Currently
+ * you have no control over this shrinking -- if you set a capacity and then remove an
+ * item, it may reduce the capacity to better match the current size.  In the future an
+ * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
+ *
+ * @hide
+ */
+public final class ArraySet<E> implements Collection<E>, Set<E> {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "ArraySet";
+
+    /**
+     * The minimum amount by which the capacity of a ArraySet will increase.
+     * This is tuned to be relatively space-efficient.
+     */
+    private static final int BASE_SIZE = 4;
+
+    /**
+     * Maximum number of entries to have in array caches.
+     */
+    private static final int CACHE_SIZE = 10;
+
+    /**
+     * Caches of small array objects to avoid spamming garbage.  The cache
+     * Object[] variable is a pointer to a linked list of array objects.
+     * The first entry in the array is a pointer to the next array in the
+     * list; the second entry is a pointer to the int[] hash code array for it.
+     */
+    static Object[] mBaseCache;
+    static int mBaseCacheSize;
+    static Object[] mTwiceBaseCache;
+    static int mTwiceBaseCacheSize;
+
+    int[] mHashes;
+    Object[] mArray;
+    int mSize;
+    MapCollections<E, E> mCollections;
+
+    private int indexOf(Object key, int hash) {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, hash);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (key.equals(mArray[index])) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
+            if (key.equals(mArray[end])) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
+            if (key.equals(mArray[i])) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    private int indexOfNull() {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, 0);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (null == mArray[index]) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
+            if (null == mArray[end]) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
+            if (null == mArray[i]) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    private void allocArrays(final int size) {
+        if (size == (BASE_SIZE*2)) {
+            synchronized (ArraySet.class) {
+                if (mTwiceBaseCache != null) {
+                    final Object[] array = mTwiceBaseCache;
+                    mArray = array;
+                    mTwiceBaseCache = (Object[])array[0];
+                    mHashes = (int[])array[1];
+                    array[0] = array[1] = null;
+                    mTwiceBaseCacheSize--;
+                    if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes
+                            + " now have " + mTwiceBaseCacheSize + " entries");
+                    return;
+                }
+            }
+        } else if (size == BASE_SIZE) {
+            synchronized (ArraySet.class) {
+                if (mBaseCache != null) {
+                    final Object[] array = mBaseCache;
+                    mArray = array;
+                    mBaseCache = (Object[])array[0];
+                    mHashes = (int[])array[1];
+                    array[0] = array[1] = null;
+                    mBaseCacheSize--;
+                    if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
+                            + " now have " + mBaseCacheSize + " entries");
+                    return;
+                }
+            }
+        }
+
+        mHashes = new int[size];
+        mArray = new Object[size];
+    }
+
+    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
+        if (hashes.length == (BASE_SIZE*2)) {
+            synchronized (ArraySet.class) {
+                if (mTwiceBaseCacheSize < CACHE_SIZE) {
+                    array[0] = mTwiceBaseCache;
+                    array[1] = hashes;
+                    for (int i=size-1; i>=2; i--) {
+                        array[i] = null;
+                    }
+                    mTwiceBaseCache = array;
+                    mTwiceBaseCacheSize++;
+                    if (DEBUG) Log.d(TAG, "Storing 2x cache " + array
+                            + " now have " + mTwiceBaseCacheSize + " entries");
+                }
+            }
+        } else if (hashes.length == BASE_SIZE) {
+            synchronized (ArraySet.class) {
+                if (mBaseCacheSize < CACHE_SIZE) {
+                    array[0] = mBaseCache;
+                    array[1] = hashes;
+                    for (int i=size-1; i>=2; i--) {
+                        array[i] = null;
+                    }
+                    mBaseCache = array;
+                    mBaseCacheSize++;
+                    if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
+                            + " now have " + mBaseCacheSize + " entries");
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a new empty ArraySet.  The default capacity of an array map is 0, and
+     * will grow once items are added to it.
+     */
+    public ArraySet() {
+        mHashes = ContainerHelpers.EMPTY_INTS;
+        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArraySet with a given initial capacity.
+     */
+    public ArraySet(int capacity) {
+        if (capacity == 0) {
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            allocArrays(capacity);
+        }
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArraySet with the mappings from the given ArraySet.
+     */
+    public ArraySet(ArraySet set) {
+        this();
+        if (set != null) {
+            addAll(set);
+        }
+    }
+
+
+    /**
+     * Make the array map empty.  All storage is released.
+     */
+    @Override
+    public void clear() {
+        if (mSize != 0) {
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mSize = 0;
+        }
+    }
+
+    /**
+     * Ensure the array map can hold at least <var>minimumCapacity</var>
+     * items.
+     */
+    public void ensureCapacity(int minimumCapacity) {
+        if (mHashes.length < minimumCapacity) {
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(minimumCapacity);
+            if (mSize > 0) {
+                System.arraycopy(ohashes, 0, mHashes, 0, mSize);
+                System.arraycopy(oarray, 0, mArray, 0, mSize);
+            }
+            freeArrays(ohashes, oarray, mSize);
+        }
+    }
+
+    /**
+     * Check whether a value exists in the set.
+     *
+     * @param key The value to search for.
+     * @return Returns true if the value exists, else false.
+     */
+    @Override
+    public boolean contains(Object key) {
+        return key == null ? (indexOfNull() >= 0) : (indexOf(key, key.hashCode()) >= 0);
+    }
+
+    /**
+     * Return the value at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value stored at the given index.
+     */
+    public E valueAt(int index) {
+        return (E)mArray[index];
+    }
+
+    /**
+     * Return true if the array map contains no items.
+     */
+    @Override
+    public boolean isEmpty() {
+        return mSize <= 0;
+    }
+
+    /**
+     * Adds the specified object to this set. The set is not modified if it
+     * already contains the object.
+     *
+     * @param value the object to add.
+     * @return {@code true} if this set is modified, {@code false} otherwise.
+     * @throws ClassCastException
+     *             when the class of the object is inappropriate for this set.
+     */
+    @Override
+    public boolean add(E value) {
+        final int hash;
+        int index;
+        if (value == null) {
+            hash = 0;
+            index = indexOfNull();
+        } else {
+            hash = value.hashCode();
+            index = indexOf(value, hash);
+        }
+        if (index >= 0) {
+            return false;
+        }
+
+        index = ~index;
+        if (mSize >= mHashes.length) {
+            final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))
+                    : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
+
+            if (DEBUG) Log.d(TAG, "add: grow from " + mHashes.length + " to " + n);
+
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(n);
+
+            if (mHashes.length > 0) {
+                if (DEBUG) Log.d(TAG, "add: copy 0-" + mSize + " to 0");
+                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
+                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
+            }
+
+            freeArrays(ohashes, oarray, mSize);
+        }
+
+        if (index < mSize) {
+            if (DEBUG) Log.d(TAG, "add: move " + index + "-" + (mSize-index)
+                    + " to " + (index+1));
+            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);
+            System.arraycopy(mArray, index, mArray, index + 1, mSize - index);
+        }
+
+        mHashes[index] = hash;
+        mArray[index] = value;
+        mSize++;
+        return true;
+    }
+
+    /**
+     * Perform a {@link #add(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be retrieved.
+     */
+    public void putAll(ArraySet<? extends E> array) {
+        final int N = array.mSize;
+        ensureCapacity(mSize + N);
+        if (mSize == 0) {
+            if (N > 0) {
+                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
+                System.arraycopy(array.mArray, 0, mArray, 0, N);
+                mSize = N;
+            }
+        } else {
+            for (int i=0; i<N; i++) {
+                add(array.valueAt(i));
+            }
+        }
+    }
+
+    /**
+     * Removes the specified object from this set.
+     *
+     * @param object the object to remove.
+     * @return {@code true} if this set was modified, {@code false} otherwise.
+     */
+    @Override
+    public boolean remove(Object object) {
+        int index = object == null ? indexOfNull() : indexOf(object, object.hashCode());
+        if (index >= 0) {
+            removeAt(index);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Remove the key/value mapping at the given index.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value that was stored at this index.
+     */
+    public E removeAt(int index) {
+        final Object old = mArray[index];
+        if (mSize <= 1) {
+            // Now empty.
+            if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mSize = 0;
+        } else {
+            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
+                // Shrunk enough to reduce size of arrays.  We don't allow it to
+                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
+                // that and BASE_SIZE.
+                final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2);
+
+                if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
+
+                final int[] ohashes = mHashes;
+                final Object[] oarray = mArray;
+                allocArrays(n);
+
+                mSize--;
+                if (index > 0) {
+                    if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0");
+                    System.arraycopy(ohashes, 0, mHashes, 0, index);
+                    System.arraycopy(oarray, 0, mArray, 0, index);
+                }
+                if (index < mSize) {
+                    if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + mSize
+                            + " to " + index);
+                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(oarray, index + 1, mArray, index, mSize - index);
+                }
+            } else {
+                mSize--;
+                if (index < mSize) {
+                    if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + mSize
+                            + " to " + index);
+                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(mArray, index + 1, mArray, index, mSize - index);
+                }
+                mArray[mSize] = null;
+            }
+        }
+        return (E)old;
+    }
+
+    /**
+     * Return the number of items in this array map.
+     */
+    @Override
+    public int size() {
+        return mSize;
+    }
+
+    @Override
+    public Object[] toArray() {
+        Object[] result = new Object[mSize];
+        System.arraycopy(mArray, 0, result, 0, mSize);
+        return result;
+    }
+
+    @Override
+    public <T> T[] toArray(T[] array) {
+        if (array.length < mSize) {
+            @SuppressWarnings("unchecked") T[] newArray
+                = (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);
+            array = newArray;
+        }
+        System.arraycopy(mArray, 0, array, 0, mSize);
+        if (array.length > mSize) {
+            array[mSize] = null;
+        }
+        return array;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns false if the object is not a set, or
+     * if the sets have different sizes.  Otherwise, for each value in this
+     * set, it checks to make sure the value also exists in the other set.
+     * If any value doesn't exist, the method returns false; otherwise, it
+     * returns true.
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof Set) {
+            Set<?> set = (Set<?>) object;
+            if (size() != set.size()) {
+                return false;
+            }
+
+            try {
+                for (int i=0; i<mSize; i++) {
+                    E mine = valueAt(i);
+                    if (!set.contains(mine)) {
+                        return false;
+                    }
+                }
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        final int[] hashes = mHashes;
+        int result = 0;
+        for (int i = 0, s = mSize; i < s; i++) {
+            result += hashes[i];
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its values. If
+     * this set contains itself as a value, the string "(this Set)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (isEmpty()) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 14);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Set)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+
+    // ------------------------------------------------------------------------
+    // Interop with traditional Java containers.  Not as efficient as using
+    // specialized collection APIs.
+    // ------------------------------------------------------------------------
+
+    private MapCollections<E, E> getCollection() {
+        if (mCollections == null) {
+            mCollections = new MapCollections<E, E>() {
+                @Override
+                protected int colGetSize() {
+                    return mSize;
+                }
+
+                @Override
+                protected Object colGetEntry(int index, int offset) {
+                    return mArray[index];
+                }
+
+                @Override
+                protected int colIndexOfKey(Object key) {
+                    return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+                }
+
+                @Override
+                protected int colIndexOfValue(Object value) {
+                    return value == null ? indexOfNull() : indexOf(value, value.hashCode());
+                }
+
+                @Override
+                protected Map<E, E> colGetMap() {
+                    throw new UnsupportedOperationException("not a map");
+                }
+
+                @Override
+                protected void colPut(E key, E value) {
+                    add(key);
+                }
+
+                @Override
+                protected E colSetValue(int index, E value) {
+                    throw new UnsupportedOperationException("not a map");
+                }
+
+                @Override
+                protected void colRemoveAt(int index) {
+                    removeAt(index);
+                }
+
+                @Override
+                protected void colClear() {
+                    clear();
+                }
+            };
+        }
+        return mCollections;
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return getCollection().getKeySet().iterator();
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> collection) {
+        Iterator<?> it = collection.iterator();
+        while (it.hasNext()) {
+            if (!contains(it.next())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> collection) {
+        ensureCapacity(mSize + collection.size());
+        boolean added = false;
+        for (E value : collection) {
+            added |= add(value);
+        }
+        return added;
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> collection) {
+        boolean removed = false;
+        for (Object value : collection) {
+            removed |= remove(value);
+        }
+        return removed;
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> collection) {
+        boolean removed = false;
+        for (int i=mSize-1; i>=0; i--) {
+            if (!collection.contains(mArray[i])) {
+                removeAt(i);
+                removed = true;
+            }
+        }
+        return removed;
+    }
+}
diff --git a/core/java/android/util/ContainerHelpers.java b/core/java/android/util/ContainerHelpers.java
new file mode 100644
index 0000000..624c4bd
--- /dev/null
+++ b/core/java/android/util/ContainerHelpers.java
@@ -0,0 +1,63 @@
+/*
+ * 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 android.util;
+
+class ContainerHelpers {
+    static final boolean[] EMPTY_BOOLEANS = new boolean[0];
+    static final int[] EMPTY_INTS = new int[0];
+    static final long[] EMPTY_LONGS = new long[0];
+    static final Object[] EMPTY_OBJECTS = new Object[0];
+
+    // This is Arrays.binarySearch(), but doesn't do any argument validation.
+    static int binarySearch(int[] array, int size, int value) {
+        int lo = 0;
+        int hi = size - 1;
+
+        while (lo <= hi) {
+            final int mid = (lo + hi) >>> 1;
+            final int midVal = array[mid];
+
+            if (midVal < value) {
+                lo = mid + 1;
+            } else if (midVal > value) {
+                hi = mid - 1;
+            } else {
+                return mid;  // value found
+            }
+        }
+        return ~lo;  // value not present
+    }
+
+    static int binarySearch(long[] array, int size, long value) {
+        int lo = 0;
+        int hi = size - 1;
+
+        while (lo <= hi) {
+            final int mid = (lo + hi) >>> 1;
+            final long midVal = array[mid];
+
+            if (midVal < value) {
+                lo = mid + 1;
+            } else if (midVal > value) {
+                hi = mid - 1;
+            } else {
+                return mid;  // value found
+            }
+        }
+        return ~lo;  // value not present
+    }
+}
diff --git a/core/java/android/util/LayoutDirection.java b/core/java/android/util/LayoutDirection.java
new file mode 100644
index 0000000..20af20b
--- /dev/null
+++ b/core/java/android/util/LayoutDirection.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.util;
+
+/**
+ * A class for defining layout directions. A layout direction can be left-to-right (LTR)
+ * or right-to-left (RTL). It can also be inherited (from a parent) or deduced from the default
+ * language script of a locale.
+ */
+public final class LayoutDirection {
+
+    // No instantiation
+    private LayoutDirection() {}
+
+    /**
+     * Horizontal layout direction is from Left to Right.
+     */
+    public static final int LTR = 0;
+
+    /**
+     * Horizontal layout direction is from Right to Left.
+     */
+    public static final int RTL = 1;
+
+    /**
+     * Horizontal layout direction is inherited.
+     */
+    public static final int INHERIT = 2;
+
+    /**
+     * Horizontal layout direction is deduced from the default language script for the locale.
+     */
+    public static final int LOCALE = 3;
+}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 1c3709f..8c1cf5f 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -17,6 +17,7 @@
 package android.util;
 
 import com.android.internal.os.RuntimeInit;
+import com.android.internal.util.FastPrintWriter;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -83,14 +84,14 @@
     public static final int ASSERT = 7;
 
     /**
-     * Exception class used to capture a stack trace in {@link #wtf()}.
+     * Exception class used to capture a stack trace in {@link #wtf}.
      */
     private static class TerribleFailure extends Exception {
         TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
     }
 
     /**
-     * Interface to handle terrible failures from {@link #wtf()}.
+     * Interface to handle terrible failures from {@link #wtf}.
      *
      * @hide
      */
@@ -256,6 +257,15 @@
     }
 
     /**
+     * Like {@link #wtf(String, String)}, but also writes to the log the full
+     * call stack.
+     * @hide
+     */
+    public static int wtfStack(String tag, String msg) {
+        return wtfStack(LOG_ID_MAIN, tag, msg);
+    }
+
+    /**
      * What a Terrible Failure: Report an exception that should never happen.
      * Similar to {@link #wtf(String, String)}, with an exception to log.
      * @param tag Used to identify the source of a log message.
@@ -273,8 +283,18 @@
      * @param tr An exception to log.  May be null.
      */
     public static int wtf(String tag, String msg, Throwable tr) {
+        return wtf(LOG_ID_MAIN, tag, msg, tr);
+    }
+
+    static int wtfStack(int logId, String tag, String msg) {
+        TerribleFailure here = new TerribleFailure("here", null);
+        here.fillInStackTrace();
+        return wtf(logId, tag, msg, here);
+    }
+
+    static int wtf(int logId, String tag, String msg, Throwable tr) {
         TerribleFailure what = new TerribleFailure(msg, tr);
-        int bytes = println_native(LOG_ID_MAIN, ASSERT, tag, msg + '\n' + getStackTraceString(tr));
+        int bytes = println_native(logId, ASSERT, tag, msg + '\n' + getStackTraceString(tr));
         sWtfHandler.onTerribleFailure(tag, what);
         return bytes;
     }
@@ -315,8 +335,9 @@
         }
 
         StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
+        PrintWriter pw = new FastPrintWriter(sw, false, 256);
         tr.printStackTrace(pw);
+        pw.flush();
         return sw.toString();
     }
 
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 630e5f3..d6e116f 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -20,8 +20,31 @@
 
 /**
  * SparseArray mapping longs to Objects.  Unlike a normal array of Objects,
- * there can be gaps in the indices.  It is intended to be more efficient
- * than using a HashMap to map Longs to Objects.
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Longs to Objects, both because it avoids
+ * auto-boxing keys and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>To help with performance, the container includes an optimization when removing
+ * keys: instead of compacting its array immediately, it leaves the removed entry marked
+ * as deleted.  The entry can then be re-used for the same key, or compacted later in
+ * a single garbage collection step of all removed entries.  This garbage collection will
+ * need to be performed at any time the array needs to be grown or the the map size or
+ * entry values are retrieved.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
  */
 public class LongSparseArray<E> implements Cloneable {
     private static final Object DELETED = new Object();
@@ -41,13 +64,19 @@
     /**
      * Creates a new LongSparseArray containing no mappings that will not
      * require any additional memory allocation to store the specified
-     * number of mappings.
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
      */
     public LongSparseArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-
-        mKeys = new long[initialCapacity];
-        mValues = new Object[initialCapacity];
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_LONGS;
+            mValues = ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
+            mKeys = new long[initialCapacity];
+            mValues = new Object[initialCapacity];
+        }
         mSize = 0;
     }
 
@@ -79,7 +108,7 @@
      */
     @SuppressWarnings("unchecked")
     public E get(long key, E valueIfKeyNotFound) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i < 0 || mValues[i] == DELETED) {
             return valueIfKeyNotFound;
@@ -92,7 +121,7 @@
      * Removes the mapping from the specified key, if there was any.
      */
     public void delete(long key) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             if (mValues[i] != DELETED) {
@@ -153,7 +182,7 @@
      * was one.
      */
     public void put(long key, E value) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             mValues[i] = value;
@@ -170,7 +199,7 @@
                 gc();
 
                 // Search again because indices may have changed.
-                i = ~binarySearch(mKeys, 0, mSize, key);
+                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
             }
 
             if (mSize >= mKeys.length) {
@@ -215,6 +244,11 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
      * LongSparseArray stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to
+     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+     * smallest key and <code>keyAt(size()-1)</code> will return the largest
+     * key.</p>
      */
     public long keyAt(int index) {
         if (mGarbage) {
@@ -228,6 +262,12 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
      * LongSparseArray stores.
+     *
+     * <p>The values corresponding to indices in ascending order are guaranteed
+     * to be associated with keys in ascending order, e.g.,
+     * <code>valueAt(0)</code> will return the value associated with the
+     * smallest key and <code>valueAt(size()-1)</code> will return the value
+     * associated with the largest key.</p>
      */
     @SuppressWarnings("unchecked")
     public E valueAt(int index) {
@@ -261,7 +301,7 @@
             gc();
         }
 
-        return binarySearch(mKeys, 0, mSize, key);
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
 
     /**
@@ -333,23 +373,36 @@
         mSize = pos + 1;
     }
 
-    private static int binarySearch(long[] a, int start, int len, long key) {
-        int high = start + len, low = start - 1, guess;
-
-        while (high - low > 1) {
-            guess = (high + low) / 2;
-
-            if (a[guess] < key)
-                low = guess;
-            else
-                high = guess;
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings. If
+     * this map contains itself as a value, the string "(this Map)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
         }
 
-        if (high == start + len)
-            return ~(start + len);
-        else if (a[high] == key)
-            return high;
-        else
-            return ~high;
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            long key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Map)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
     }
 }
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index 34b6126..87d868b 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -22,8 +22,24 @@
 
 /**
  * Map of {@code long} to {@code long}. Unlike a normal array of longs, there
- * can be gaps in the indices. It is intended to be more efficient than using a
- * {@code HashMap}.
+ * can be gaps in the indices. It is intended to be more memory efficient than using a
+ * {@code HashMap}, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
  *
  * @hide
  */
@@ -42,13 +58,19 @@
     /**
      * Creates a new SparseLongArray containing no mappings that will not
      * require any additional memory allocation to store the specified
-     * number of mappings.
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
      */
     public LongSparseLongArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-
-        mKeys = new long[initialCapacity];
-        mValues = new long[initialCapacity];
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_LONGS;
+            mValues = ContainerHelpers.EMPTY_LONGS;
+        } else {
+            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
+            mKeys = new long[initialCapacity];
+            mValues = new long[initialCapacity];
+        }
         mSize = 0;
     }
 
@@ -78,7 +100,7 @@
      * if no such mapping has been made.
      */
     public long get(long key, long valueIfKeyNotFound) {
-        int i = Arrays.binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i < 0) {
             return valueIfKeyNotFound;
@@ -91,7 +113,7 @@
      * Removes the mapping from the specified key, if there was any.
      */
     public void delete(long key) {
-        int i = Arrays.binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             removeAt(i);
@@ -113,7 +135,7 @@
      * was one.
      */
     public void put(long key, long value) {
-        int i = Arrays.binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             mValues[i] = value;
@@ -147,6 +169,11 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
      * SparseLongArray stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to
+     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+     * smallest key and <code>keyAt(size()-1)</code> will return the largest
+     * key.</p>
      */
     public long keyAt(int index) {
         return mKeys[index];
@@ -156,6 +183,12 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
      * SparseLongArray stores.
+     *
+     * <p>The values corresponding to indices in ascending order are guaranteed
+     * to be associated with keys in ascending order, e.g.,
+     * <code>valueAt(0)</code> will return the value associated with the
+     * smallest key and <code>valueAt(size()-1)</code> will return the value
+     * associated with the largest key.</p>
      */
     public long valueAt(int index) {
         return mValues[index];
@@ -167,7 +200,7 @@
      * key is not mapped.
      */
     public int indexOfKey(long key) {
-        return Arrays.binarySearch(mKeys, 0, mSize, key);
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
 
     /**
@@ -225,4 +258,31 @@
         mKeys = nkeys;
         mValues = nvalues;
     }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            long key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            long value = valueAt(i);
+            buffer.append(value);
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
 }
diff --git a/core/java/android/util/MapCollections.java b/core/java/android/util/MapCollections.java
new file mode 100644
index 0000000..f4a9b0b
--- /dev/null
+++ b/core/java/android/util/MapCollections.java
@@ -0,0 +1,559 @@
+/*
+ * 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 android.util;
+
+import libcore.util.Objects;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Helper for writing standard Java collection interfaces to a data
+ * structure like {@link ArrayMap}.
+ * @hide
+ */
+abstract class MapCollections<K, V> {
+    EntrySet mEntrySet;
+    KeySet mKeySet;
+    ValuesCollection mValues;
+
+    final class ArrayIterator<T> implements Iterator<T> {
+        final int mOffset;
+        int mSize;
+        int mIndex;
+        boolean mCanRemove = false;
+
+        ArrayIterator(int offset) {
+            mOffset = offset;
+            mSize = colGetSize();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return mIndex < mSize;
+        }
+
+        @Override
+        public T next() {
+            Object res = colGetEntry(mIndex, mOffset);
+            mIndex++;
+            mCanRemove = true;
+            return (T)res;
+        }
+
+        @Override
+        public void remove() {
+            if (!mCanRemove) {
+                throw new IllegalStateException();
+            }
+            mIndex--;
+            mSize--;
+            mCanRemove = false;
+            colRemoveAt(mIndex);
+        }
+    }
+
+    final class MapIterator implements Iterator<Map.Entry<K, V>>, Map.Entry<K, V> {
+        int mEnd;
+        int mIndex;
+        boolean mEntryValid = false;
+
+        MapIterator() {
+            mEnd = colGetSize() - 1;
+            mIndex = -1;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return mIndex < mEnd;
+        }
+
+        @Override
+        public Map.Entry<K, V> next() {
+            mIndex++;
+            mEntryValid = true;
+            return this;
+        }
+
+        @Override
+        public void remove() {
+            if (!mEntryValid) {
+                throw new IllegalStateException();
+            }
+            mIndex--;
+            mEnd--;
+            mEntryValid = false;
+            colRemoveAt(mIndex);
+        }
+
+        @Override
+        public K getKey() {
+            if (!mEntryValid) {
+                throw new IllegalStateException(
+                        "This container does not support retaining Map.Entry objects");
+            }
+            return (K)colGetEntry(mIndex, 0);
+        }
+
+        @Override
+        public V getValue() {
+            if (!mEntryValid) {
+                throw new IllegalStateException(
+                        "This container does not support retaining Map.Entry objects");
+            }
+            return (V)colGetEntry(mIndex, 1);
+        }
+
+        @Override
+        public V setValue(V object) {
+            if (!mEntryValid) {
+                throw new IllegalStateException(
+                        "This container does not support retaining Map.Entry objects");
+            }
+            return colSetValue(mIndex, object);
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (!mEntryValid) {
+                throw new IllegalStateException(
+                        "This container does not support retaining Map.Entry objects");
+            }
+            if (!(o instanceof Map.Entry)) {
+                return false;
+            }
+            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
+            return Objects.equal(e.getKey(), colGetEntry(mIndex, 0))
+                    && Objects.equal(e.getValue(), colGetEntry(mIndex, 1));
+        }
+
+        @Override
+        public final int hashCode() {
+            if (!mEntryValid) {
+                throw new IllegalStateException(
+                        "This container does not support retaining Map.Entry objects");
+            }
+            final Object key = colGetEntry(mIndex, 0);
+            final Object value = colGetEntry(mIndex, 1);
+            return (key == null ? 0 : key.hashCode()) ^
+                    (value == null ? 0 : value.hashCode());
+        }
+
+        @Override
+        public final String toString() {
+            return getKey() + "=" + getValue();
+        }
+    }
+
+    final class EntrySet implements Set<Map.Entry<K, V>> {
+        @Override
+        public boolean add(Map.Entry<K, V> object) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends Map.Entry<K, V>> collection) {
+            int oldSize = colGetSize();
+            for (Map.Entry<K, V> entry : collection) {
+                colPut(entry.getKey(), entry.getValue());
+            }
+            return oldSize != colGetSize();
+        }
+
+        @Override
+        public void clear() {
+            colClear();
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
+            int index = colIndexOfKey(e.getKey());
+            if (index < 0) {
+                return false;
+            }
+            Object foundVal = colGetEntry(index, 1);
+            return Objects.equal(foundVal, e.getValue());
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> collection) {
+            Iterator<?> it = collection.iterator();
+            while (it.hasNext()) {
+                if (!contains(it.next())) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return colGetSize() == 0;
+        }
+
+        @Override
+        public Iterator<Map.Entry<K, V>> iterator() {
+            return new MapIterator();
+        }
+
+        @Override
+        public boolean remove(Object object) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> collection) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> collection) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int size() {
+            return colGetSize();
+        }
+
+        @Override
+        public Object[] toArray() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> T[] toArray(T[] array) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            return equalsSetHelper(this, object);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 0;
+            for (int i=colGetSize()-1; i>=0; i--) {
+                final Object key = colGetEntry(i, 0);
+                final Object value = colGetEntry(i, 1);
+                result += ( (key == null ? 0 : key.hashCode()) ^
+                        (value == null ? 0 : value.hashCode()) );
+            }
+            return result;
+        }
+    };
+
+    final class KeySet implements Set<K> {
+
+        @Override
+        public boolean add(K object) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends K> collection) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void clear() {
+            colClear();
+        }
+
+        @Override
+        public boolean contains(Object object) {
+            return colIndexOfKey(object) >= 0;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> collection) {
+            return containsAllHelper(colGetMap(), collection);
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return colGetSize() == 0;
+        }
+
+        @Override
+        public Iterator<K> iterator() {
+            return new ArrayIterator<K>(0);
+        }
+
+        @Override
+        public boolean remove(Object object) {
+            int index = colIndexOfKey(object);
+            if (index >= 0) {
+                colRemoveAt(index);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> collection) {
+            return removeAllHelper(colGetMap(), collection);
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> collection) {
+            return retainAllHelper(colGetMap(), collection);
+        }
+
+        @Override
+        public int size() {
+            return colGetSize();
+        }
+
+        @Override
+        public Object[] toArray() {
+            return toArrayHelper(0);
+        }
+
+        @Override
+        public <T> T[] toArray(T[] array) {
+            return toArrayHelper(array, 0);
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            return equalsSetHelper(this, object);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 0;
+            for (int i=colGetSize()-1; i>=0; i--) {
+                Object obj = colGetEntry(i, 0);
+                result += obj == null ? 0 : obj.hashCode();
+            }
+            return result;
+        }
+    };
+
+    final class ValuesCollection implements Collection<V> {
+
+        @Override
+        public boolean add(V object) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends V> collection) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void clear() {
+            colClear();
+        }
+
+        @Override
+        public boolean contains(Object object) {
+            return colIndexOfValue(object) >= 0;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> collection) {
+            Iterator<?> it = collection.iterator();
+            while (it.hasNext()) {
+                if (!contains(it.next())) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return colGetSize() == 0;
+        }
+
+        @Override
+        public Iterator<V> iterator() {
+            return new ArrayIterator<V>(1);
+        }
+
+        @Override
+        public boolean remove(Object object) {
+            int index = colIndexOfValue(object);
+            if (index >= 0) {
+                colRemoveAt(index);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> collection) {
+            int N = colGetSize();
+            boolean changed = false;
+            for (int i=0; i<N; i++) {
+                Object cur = colGetEntry(i, 1);
+                if (collection.contains(cur)) {
+                    colRemoveAt(i);
+                    i--;
+                    N--;
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> collection) {
+            int N = colGetSize();
+            boolean changed = false;
+            for (int i=0; i<N; i++) {
+                Object cur = colGetEntry(i, 1);
+                if (!collection.contains(cur)) {
+                    colRemoveAt(i);
+                    i--;
+                    N--;
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        @Override
+        public int size() {
+            return colGetSize();
+        }
+
+        @Override
+        public Object[] toArray() {
+            return toArrayHelper(1);
+        }
+
+        @Override
+        public <T> T[] toArray(T[] array) {
+            return toArrayHelper(array, 1);
+        }
+    };
+
+    public static <K, V> boolean containsAllHelper(Map<K, V> map, Collection<?> collection) {
+        Iterator<?> it = collection.iterator();
+        while (it.hasNext()) {
+            if (!map.containsKey(it.next())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static <K, V> boolean removeAllHelper(Map<K, V> map, Collection<?> collection) {
+        int oldSize = map.size();
+        Iterator<?> it = collection.iterator();
+        while (it.hasNext()) {
+            map.remove(it.next());
+        }
+        return oldSize != map.size();
+    }
+
+    public static <K, V> boolean retainAllHelper(Map<K, V> map, Collection<?> collection) {
+        int oldSize = map.size();
+        Iterator<K> it = map.keySet().iterator();
+        while (it.hasNext()) {
+            if (!collection.contains(it.next())) {
+                it.remove();
+            }
+        }
+        return oldSize != map.size();
+    }
+
+    public Object[] toArrayHelper(int offset) {
+        final int N = colGetSize();
+        Object[] result = new Object[N];
+        for (int i=0; i<N; i++) {
+            result[i] = colGetEntry(i, offset);
+        }
+        return result;
+    }
+
+    public <T> T[] toArrayHelper(T[] array, int offset) {
+        final int N  = colGetSize();
+        if (array.length < N) {
+            @SuppressWarnings("unchecked") T[] newArray
+                = (T[]) Array.newInstance(array.getClass().getComponentType(), N);
+            array = newArray;
+        }
+        for (int i=0; i<N; i++) {
+            array[i] = (T)colGetEntry(i, offset);
+        }
+        if (array.length > N) {
+            array[N] = null;
+        }
+        return array;
+    }
+
+    public static <T> boolean equalsSetHelper(Set<T> set, Object object) {
+        if (set == object) {
+            return true;
+        }
+        if (object instanceof Set) {
+            Set<?> s = (Set<?>) object;
+
+            try {
+                return set.size() == s.size() && set.containsAll(s);
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    public Set<Map.Entry<K, V>> getEntrySet() {
+        if (mEntrySet == null) {
+            mEntrySet = new EntrySet();
+        }
+        return mEntrySet;
+    }
+
+    public Set<K> getKeySet() {
+        if (mKeySet == null) {
+            mKeySet = new KeySet();
+        }
+        return mKeySet;
+    }
+
+    public Collection<V> getValues() {
+        if (mValues == null) {
+            mValues = new ValuesCollection();
+        }
+        return mValues;
+    }
+
+    protected abstract int colGetSize();
+    protected abstract Object colGetEntry(int index, int offset);
+    protected abstract int colIndexOfKey(Object key);
+    protected abstract int colIndexOfValue(Object key);
+    protected abstract Map<K, V> colGetMap();
+    protected abstract void colPut(K key, V value);
+    protected abstract V colSetValue(int index, V value);
+    protected abstract void colRemoveAt(int index);
+    protected abstract void colClear();
+}
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index ecf5ea1..a5c22ff 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -78,6 +78,22 @@
                 msg + '\n' + Log.getStackTraceString(tr));
     }
 
+    public static int wtf(String tag, String msg) {
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null);
+    }
+
+    public static int wtfStack(String tag, String msg) {
+        return Log.wtfStack(Log.LOG_ID_SYSTEM, tag, msg);
+    }
+
+    public static int wtf(String tag, Throwable tr) {
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr);
+    }
+
+    public static int wtf(String tag, String msg, Throwable tr) {
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr);
+    }
+
     public static int println(int priority, String tag, String msg) {
         return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg);
     }
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 7e8fee5..6e168a8 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -20,8 +20,31 @@
 
 /**
  * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
- * there can be gaps in the indices.  It is intended to be more efficient
- * than using a HashMap to map Integers to Objects.
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Objects, both because it avoids
+ * auto-boxing keys and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>To help with performance, the container includes an optimization when removing
+ * keys: instead of compacting its array immediately, it leaves the removed entry marked
+ * as deleted.  The entry can then be re-used for the same key, or compacted later in
+ * a single garbage collection step of all removed entries.  This garbage collection will
+ * need to be performed at any time the array needs to be grown or the the map size or
+ * entry values are retrieved.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
  */
 public class SparseArray<E> implements Cloneable {
     private static final Object DELETED = new Object();
@@ -41,13 +64,19 @@
     /**
      * Creates a new SparseArray containing no mappings that will not
      * require any additional memory allocation to store the specified
-     * number of mappings.
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
      */
     public SparseArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
-
-        mKeys = new int[initialCapacity];
-        mValues = new Object[initialCapacity];
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_INTS;
+            mValues = ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+            mKeys = new int[initialCapacity];
+            mValues = new Object[initialCapacity];
+        }
         mSize = 0;
     }
 
@@ -79,7 +108,7 @@
      */
     @SuppressWarnings("unchecked")
     public E get(int key, E valueIfKeyNotFound) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i < 0 || mValues[i] == DELETED) {
             return valueIfKeyNotFound;
@@ -92,7 +121,7 @@
      * Removes the mapping from the specified key, if there was any.
      */
     public void delete(int key) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             if (mValues[i] != DELETED) {
@@ -119,6 +148,19 @@
         }
     }
 
+    /**
+     * Remove a range of mappings as a batch.
+     *
+     * @param index Index to begin at
+     * @param size Number of mappings to remove
+     */
+    public void removeAtRange(int index, int size) {
+        final int end = Math.min(mSize, index + size);
+        for (int i = index; i < end; i++) {
+            removeAt(i);
+        }
+    }
+
     private void gc() {
         // Log.e("SparseArray", "gc start with " + mSize);
 
@@ -153,7 +195,7 @@
      * was one.
      */
     public void put(int key, E value) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             mValues[i] = value;
@@ -170,7 +212,7 @@
                 gc();
 
                 // Search again because indices may have changed.
-                i = ~binarySearch(mKeys, 0, mSize, key);
+                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
             }
 
             if (mSize >= mKeys.length) {
@@ -215,6 +257,11 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
      * SparseArray stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to
+     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+     * smallest key and <code>keyAt(size()-1)</code> will return the largest
+     * key.</p>
      */
     public int keyAt(int index) {
         if (mGarbage) {
@@ -228,6 +275,12 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
      * SparseArray stores.
+     *
+     * <p>The values corresponding to indices in ascending order are guaranteed
+     * to be associated with keys in ascending order, e.g.,
+     * <code>valueAt(0)</code> will return the value associated with the
+     * smallest key and <code>valueAt(size()-1)</code> will return the value
+     * associated with the largest key.</p>
      */
     @SuppressWarnings("unchecked")
     public E valueAt(int index) {
@@ -261,7 +314,7 @@
             gc();
         }
 
-        return binarySearch(mKeys, 0, mSize, key);
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
 
     /**
@@ -335,23 +388,36 @@
         mSize = pos + 1;
     }
 
-    private static int binarySearch(int[] a, int start, int len, int key) {
-        int high = start + len, low = start - 1, guess;
-
-        while (high - low > 1) {
-            guess = (high + low) / 2;
-
-            if (a[guess] < key)
-                low = guess;
-            else
-                high = guess;
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings. If
+     * this map contains itself as a value, the string "(this Map)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
         }
 
-        if (high == start + len)
-            return ~(start + len);
-        else if (a[high] == key)
-            return high;
-        else
-            return ~high;
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            int key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Map)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
     }
 }
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 76c47c6..68487e3 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -21,8 +21,24 @@
 /**
  * SparseBooleanArrays map integers to booleans.
  * Unlike a normal array of booleans
- * there can be gaps in the indices.  It is intended to be more efficient
- * than using a HashMap to map Integers to Booleans.
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Booleans, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
  */
 public class SparseBooleanArray implements Cloneable {
     /**
@@ -35,13 +51,19 @@
     /**
      * Creates a new SparseBooleanArray containing no mappings that will not
      * require any additional memory allocation to store the specified
-     * number of mappings.
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
      */
     public SparseBooleanArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
-
-        mKeys = new int[initialCapacity];
-        mValues = new boolean[initialCapacity];
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_INTS;
+            mValues = ContainerHelpers.EMPTY_BOOLEANS;
+        } else {
+            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+            mKeys = new int[initialCapacity];
+            mValues = new boolean[initialCapacity];
+        }
         mSize = 0;
     }
 
@@ -71,7 +93,7 @@
      * if no such mapping has been made.
      */
     public boolean get(int key, boolean valueIfKeyNotFound) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i < 0) {
             return valueIfKeyNotFound;
@@ -84,7 +106,7 @@
      * Removes the mapping from the specified key, if there was any.
      */
     public void delete(int key) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             System.arraycopy(mKeys, i + 1, mKeys, i, mSize - (i + 1));
@@ -99,7 +121,7 @@
      * was one.
      */
     public void put(int key, boolean value) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             mValues[i] = value;
@@ -143,16 +165,27 @@
     /**
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
-     * SparseBooleanArray stores.  
+     * SparseBooleanArray stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to
+     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+     * smallest key and <code>keyAt(size()-1)</code> will return the largest
+     * key.</p>
      */
     public int keyAt(int index) {
         return mKeys[index];
     }
-    
+
     /**
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
-     * SparseBooleanArray stores.  
+     * SparseBooleanArray stores.
+     *
+     * <p>The values corresponding to indices in ascending order are guaranteed
+     * to be associated with keys in ascending order, e.g.,
+     * <code>valueAt(0)</code> will return the value associated with the
+     * smallest key and <code>valueAt(size()-1)</code> will return the value
+     * associated with the largest key.</p>
      */
     public boolean valueAt(int index) {
         return mValues[index];
@@ -164,7 +197,7 @@
      * key is not mapped.
      */
     public int indexOfKey(int key) {
-        return binarySearch(mKeys, 0, mSize, key);
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
 
     /**
@@ -219,25 +252,32 @@
         mValues[pos] = value;
         mSize = pos + 1;
     }
-    
-    private static int binarySearch(int[] a, int start, int len, int key) {
-        int high = start + len, low = start - 1, guess;
 
-        while (high - low > 1) {
-            guess = (high + low) / 2;
-
-            if (a[guess] < key)
-                low = guess;
-            else
-                high = guess;
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
         }
 
-        if (high == start + len)
-            return ~(start + len);
-        else if (a[high] == key)
-            return high;
-        else
-            return ~high;
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            int key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            boolean value = valueAt(i);
+            buffer.append(value);
+        }
+        buffer.append('}');
+        return buffer.toString();
     }
 
     private int[] mKeys;
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 8d11177..0835cb0 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -20,11 +20,26 @@
 
 /**
  * SparseIntArrays map integers to integers.  Unlike a normal array of integers,
- * there can be gaps in the indices.  It is intended to be more efficient
- * than using a HashMap to map Integers to Integers.
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Integers, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
  */
 public class SparseIntArray implements Cloneable {
-
     private int[] mKeys;
     private int[] mValues;
     private int mSize;
@@ -39,13 +54,19 @@
     /**
      * Creates a new SparseIntArray containing no mappings that will not
      * require any additional memory allocation to store the specified
-     * number of mappings.
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
      */
     public SparseIntArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
-
-        mKeys = new int[initialCapacity];
-        mValues = new int[initialCapacity];
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_INTS;
+            mValues = ContainerHelpers.EMPTY_INTS;
+        } else {
+            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+            mKeys = new int[initialCapacity];
+            mValues = new int[initialCapacity];
+        }
         mSize = 0;
     }
 
@@ -75,7 +96,7 @@
      * if no such mapping has been made.
      */
     public int get(int key, int valueIfKeyNotFound) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i < 0) {
             return valueIfKeyNotFound;
@@ -88,7 +109,7 @@
      * Removes the mapping from the specified key, if there was any.
      */
     public void delete(int key) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             removeAt(i);
@@ -110,7 +131,7 @@
      * was one.
      */
     public void put(int key, int value) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             mValues[i] = value;
@@ -154,16 +175,27 @@
     /**
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
-     * SparseIntArray stores.  
+     * SparseIntArray stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to
+     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+     * smallest key and <code>keyAt(size()-1)</code> will return the largest
+     * key.</p>
      */
     public int keyAt(int index) {
         return mKeys[index];
     }
-    
+
     /**
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
-     * SparseIntArray stores.  
+     * SparseIntArray stores.
+     *
+     * <p>The values corresponding to indices in ascending order are guaranteed
+     * to be associated with keys in ascending order, e.g.,
+     * <code>valueAt(0)</code> will return the value associated with the
+     * smallest key and <code>valueAt(size()-1)</code> will return the value
+     * associated with the largest key.</p>
      */
     public int valueAt(int index) {
         return mValues[index];
@@ -175,7 +207,7 @@
      * key is not mapped.
      */
     public int indexOfKey(int key) {
-        return binarySearch(mKeys, 0, mSize, key);
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
 
     /**
@@ -230,24 +262,31 @@
         mValues[pos] = value;
         mSize = pos + 1;
     }
-    
-    private static int binarySearch(int[] a, int start, int len, int key) {
-        int high = start + len, low = start - 1, guess;
 
-        while (high - low > 1) {
-            guess = (high + low) / 2;
-
-            if (a[guess] < key)
-                low = guess;
-            else
-                high = guess;
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
         }
 
-        if (high == start + len)
-            return ~(start + len);
-        else if (a[high] == key)
-            return high;
-        else
-            return ~high;
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            int key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            int value = valueAt(i);
+            buffer.append(value);
+        }
+        buffer.append('}');
+        return buffer.toString();
     }
 }
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 2f7a6fe..62c1c0d 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -20,11 +20,26 @@
 
 /**
  * SparseLongArrays map integers to longs.  Unlike a normal array of longs,
- * there can be gaps in the indices.  It is intended to be more efficient
- * than using a HashMap to map Integers to Longs.
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Longs, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
  */
 public class SparseLongArray implements Cloneable {
-
     private int[] mKeys;
     private long[] mValues;
     private int mSize;
@@ -39,13 +54,19 @@
     /**
      * Creates a new SparseLongArray containing no mappings that will not
      * require any additional memory allocation to store the specified
-     * number of mappings.
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
      */
     public SparseLongArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-
-        mKeys = new int[initialCapacity];
-        mValues = new long[initialCapacity];
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_INTS;
+            mValues = ContainerHelpers.EMPTY_LONGS;
+        } else {
+            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
+            mKeys = new int[initialCapacity];
+            mValues = new long[initialCapacity];
+        }
         mSize = 0;
     }
 
@@ -75,7 +96,7 @@
      * if no such mapping has been made.
      */
     public long get(int key, long valueIfKeyNotFound) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i < 0) {
             return valueIfKeyNotFound;
@@ -88,7 +109,7 @@
      * Removes the mapping from the specified key, if there was any.
      */
     public void delete(int key) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             removeAt(i);
@@ -110,7 +131,7 @@
      * was one.
      */
     public void put(int key, long value) {
-        int i = binarySearch(mKeys, 0, mSize, key);
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
 
         if (i >= 0) {
             mValues[i] = value;
@@ -144,6 +165,11 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
      * SparseLongArray stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to
+     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+     * smallest key and <code>keyAt(size()-1)</code> will return the largest
+     * key.</p>
      */
     public int keyAt(int index) {
         return mKeys[index];
@@ -153,6 +179,12 @@
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
      * SparseLongArray stores.
+     *
+     * <p>The values corresponding to indices in ascending order are guaranteed
+     * to be associated with keys in ascending order, e.g.,
+     * <code>valueAt(0)</code> will return the value associated with the
+     * smallest key and <code>valueAt(size()-1)</code> will return the value
+     * associated with the largest key.</p>
      */
     public long valueAt(int index) {
         return mValues[index];
@@ -164,7 +196,7 @@
      * key is not mapped.
      */
     public int indexOfKey(int key) {
-        return binarySearch(mKeys, 0, mSize, key);
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
 
     /**
@@ -223,23 +255,30 @@
         mValues = nvalues;
     }
 
-    private static int binarySearch(int[] a, int start, int len, long key) {
-        int high = start + len, low = start - 1, guess;
-
-        while (high - low > 1) {
-            guess = (high + low) / 2;
-
-            if (a[guess] < key)
-                low = guess;
-            else
-                high = guess;
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
         }
 
-        if (high == start + len)
-            return ~(start + len);
-        else if (a[high] == key)
-            return high;
-        else
-            return ~high;
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            int key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            long value = valueAt(i);
+            buffer.append(value);
+        }
+        buffer.append('}');
+        return buffer.toString();
     }
 }
diff --git a/core/java/android/util/SuperNotCalledException.java b/core/java/android/util/SuperNotCalledException.java
new file mode 100644
index 0000000..1836142
--- /dev/null
+++ b/core/java/android/util/SuperNotCalledException.java
@@ -0,0 +1,27 @@
+/*
+ * 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 android.util;
+
+/**
+ * @hide
+ */
+public final class SuperNotCalledException extends AndroidRuntimeException {
+    public SuperNotCalledException(String msg) {
+        super(msg);
+    }
+}
diff --git a/core/java/android/util/TimedRemoteCaller.java b/core/java/android/util/TimedRemoteCaller.java
new file mode 100644
index 0000000..abb2b64
--- /dev/null
+++ b/core/java/android/util/TimedRemoteCaller.java
@@ -0,0 +1,134 @@
+/*
+ * 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 android.util;
+
+import android.os.SystemClock;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is a helper class for making an async one way call and
+ * its async one way response response in a sync fashion within
+ * a timeout. The key idea is to call the remote method with a
+ * sequence number and a callback and then starting to wait for
+ * the response. The remote method calls back with the result and
+ * the sequence number. If the response comes within the timeout
+ * and its sequence number is the one sent in the method invocation,
+ * then the call succeeded. If the response does not come within
+ * the timeout then the call failed. Older result received when
+ * waiting for the result are ignored.
+ * <p>
+ * Typical usage is:
+ * </p>
+ * <p><pre><code>
+ * public class MyMethodCaller extends TimeoutRemoteCallHelper<Object> {
+ *     // The one way remote method to call.
+ *     private final IRemoteInterface mTarget;
+ *
+ *     // One way callback invoked when the remote method is done.
+ *     private final IRemoteCallback mCallback = new IRemoteCallback.Stub() {
+ *         public void onCompleted(Object result, int sequence) {
+ *             onRemoteMethodResult(result, sequence);
+ *         }
+ *     };
+ *
+ *     public MyMethodCaller(IRemoteInterface target) {
+ *         mTarget = target;
+ *     }
+ *
+ *     public Object onCallMyMethod(Object arg) throws RemoteException {
+ *         final int sequence = onBeforeRemoteCall();
+ *         mTarget.myMethod(arg, sequence);
+ *         return getResultTimed(sequence);
+ *     }
+ * }
+ * </code></pre></p>
+ *
+ * @param <T> The type of the expected result.
+ *
+ * @hide
+ */
+public abstract class TimedRemoteCaller<T> {
+
+    public static final long DEFAULT_CALL_TIMEOUT_MILLIS = 5000;
+
+    private static final int UNDEFINED_SEQUENCE = -1;
+
+    private final Object mLock = new Object();
+
+    private final long mCallTimeoutMillis;
+
+    private int mSequenceCounter;
+
+    private int mReceivedSequence = UNDEFINED_SEQUENCE;
+
+    private int mAwaitedSequence = UNDEFINED_SEQUENCE;
+
+    private T mResult;
+
+    public TimedRemoteCaller(long callTimeoutMillis) {
+        mCallTimeoutMillis = callTimeoutMillis;
+    }
+
+    public final int onBeforeRemoteCall() {
+        synchronized (mLock) {
+            mAwaitedSequence = mSequenceCounter++;
+            return mAwaitedSequence;
+        }
+    }
+
+    public final T getResultTimed(int sequence) throws TimeoutException {
+        synchronized (mLock) {
+            final boolean success = waitForResultTimedLocked(sequence);
+            if (!success) {
+                throw new TimeoutException("No reponse for sequence: " + sequence);
+            }
+            T result = mResult;
+            mResult = null;
+            return result;
+        }
+    }
+
+    public final void onRemoteMethodResult(T result, int sequence) {
+        synchronized (mLock) {
+            if (sequence == mAwaitedSequence) {
+                mReceivedSequence = sequence;
+                mResult = result;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    private boolean waitForResultTimedLocked(int sequence) {
+        final long startMillis = SystemClock.uptimeMillis();
+        while (true) {
+            try {
+                if (mReceivedSequence == sequence) {
+                    return true;
+                }
+                final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
+                final long waitMillis = mCallTimeoutMillis - elapsedMillis;
+                if (waitMillis <= 0) {
+                    return false;
+                }
+                mLock.wait(waitMillis);
+            } catch (InterruptedException ie) {
+                /* ignore */
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 2d6453e..41d3700 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -406,6 +406,10 @@
                         if (host == null || !ViewRootImpl.isViewDescendantOf(host, root)) {
                             break;
                         }
+                        // The focused view not shown, we failed.
+                        if (!isShown(host)) {
+                            break;
+                        }
                         // If the host has a provider ask this provider to search for the
                         // focus instead fetching all provider nodes to do the search here.
                         AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
@@ -419,9 +423,15 @@
                         }
                     } break;
                     case AccessibilityNodeInfo.FOCUS_INPUT: {
-                        // Input focus cannot go to virtual views.
                         View target = root.findFocus();
-                        if (target != null && isShown(target)) {
+                        if (target == null || !isShown(target)) {
+                            break;
+                        }
+                        AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
+                        if (provider != null) {
+                            focused = provider.findFocus(focusType);
+                        }
+                        if (focused == null) {
                             focused = target.createAccessibilityNodeInfo();
                         }
                     } break;
diff --git a/core/java/android/view/CompatibilityInfoHolder.java b/core/java/android/view/CompatibilityInfoHolder.java
deleted file mode 100644
index fc8d684..0000000
--- a/core/java/android/view/CompatibilityInfoHolder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.
- */
-
-package android.view;
-
-import android.content.res.CompatibilityInfo;
-
-/** @hide */
-public class CompatibilityInfoHolder {
-    private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-
-    public void set(CompatibilityInfo compatInfo) {
-        if (compatInfo != null && (compatInfo.isScalingRequired()
-                || !compatInfo.supportsScreen())) {
-            mCompatInfo = compatInfo;
-        } else {
-            mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-        }
-    }
-
-    public CompatibilityInfo get() {
-        return mCompatInfo;
-    }
-
-    public CompatibilityInfo getIfNeeded() {
-        CompatibilityInfo ci = mCompatInfo;
-        if (ci == null || ci  == CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO) {
-            return null;
-        }
-        return ci;
-    }
-}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e6a7950..354ea66 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -16,10 +16,12 @@
 
 package android.view;
 
+import android.content.res.CompatibilityInfo;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Process;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -57,7 +59,9 @@
     private final int mFlags;
     private final int mType;
     private final String mAddress;
-    private final CompatibilityInfoHolder mCompatibilityInfo;
+    private final int mOwnerUid;
+    private final String mOwnerPackageName;
+    private final DisplayAdjustments mDisplayAdjustments;
 
     private DisplayInfo mDisplayInfo; // never null
     private boolean mIsValid;
@@ -143,6 +147,27 @@
     public static final int FLAG_SECURE = 1 << 1;
 
     /**
+     * Display flag: Indicates that the display is private.  Only the application that
+     * owns the display can create windows on it.
+     *
+     * @see #getFlags
+     */
+    public static final int FLAG_PRIVATE = 1 << 2;
+
+    /**
+     * Display flag: Indicates that the display is a presentation display.
+     * <p>
+     * This flag identifies secondary displays that are suitable for
+     * use as presentation displays such as HDMI or Wireless displays.  Applications
+     * may automatically project their content to presentation displays to provide
+     * richer second screen experiences.
+     * </p>
+     *
+     * @see #getFlags
+     */
+    public static final int FLAG_PRESENTATION = 1 << 3;
+
+    /**
      * Display type: Unknown display type.
      * @hide
      */
@@ -173,6 +198,12 @@
     public static final int TYPE_OVERLAY = 4;
 
     /**
+     * Display type: Virtual display.
+     * @hide
+     */
+    public static final int TYPE_VIRTUAL = 5;
+
+    /**
      * Internal method to create a display.
      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
      * or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -182,11 +213,11 @@
      */
     public Display(DisplayManagerGlobal global,
             int displayId, DisplayInfo displayInfo /*not null*/,
-            CompatibilityInfoHolder compatibilityInfo) {
+            DisplayAdjustments daj) {
         mGlobal = global;
         mDisplayId = displayId;
         mDisplayInfo = displayInfo;
-        mCompatibilityInfo = compatibilityInfo;
+        mDisplayAdjustments = new DisplayAdjustments(daj);
         mIsValid = true;
 
         // Cache properties that cannot change as long as the display is valid.
@@ -194,6 +225,8 @@
         mFlags = displayInfo.flags;
         mType = displayInfo.type;
         mAddress = displayInfo.address;
+        mOwnerUid = displayInfo.ownerUid;
+        mOwnerPackageName = displayInfo.ownerPackageName;
     }
 
     /**
@@ -262,6 +295,7 @@
      *
      * @see #FLAG_SUPPORTS_PROTECTED_BUFFERS
      * @see #FLAG_SECURE
+     * @see #FLAG_PRIVATE
      */
     public int getFlags() {
         return mFlags;
@@ -277,6 +311,7 @@
      * @see #TYPE_HDMI
      * @see #TYPE_WIFI
      * @see #TYPE_OVERLAY
+     * @see #TYPE_VIRTUAL
      * @hide
      */
     public int getType() {
@@ -295,13 +330,39 @@
     }
 
     /**
-     * Gets the compatibility info used by this display instance.
+     * Gets the UID of the application that owns this display, or zero if it is
+     * owned by the system.
+     * <p>
+     * If the display is private, then only the owner can use it.
+     * </p>
      *
-     * @return The compatibility info holder, or null if none is required.
      * @hide
      */
-    public CompatibilityInfoHolder getCompatibilityInfo() {
-        return mCompatibilityInfo;
+    public int getOwnerUid() {
+        return mOwnerUid;
+    }
+
+    /**
+     * Gets the package name of the application that owns this display, or null if it is
+     * owned by the system.
+     * <p>
+     * If the display is private, then only the owner can use it.
+     * </p>
+     *
+     * @hide
+     */
+    public String getOwnerPackageName() {
+        return mOwnerPackageName;
+    }
+
+    /**
+     * Gets the compatibility info used by this display instance.
+     *
+     * @return The display adjustments holder, or null if none is required.
+     * @hide
+     */
+    public DisplayAdjustments getDisplayAdjustments() {
+        return mDisplayAdjustments;
     }
 
     /**
@@ -342,7 +403,7 @@
     public void getSize(Point outSize) {
         synchronized (this) {
             updateDisplayInfoLocked();
-            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
+            mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
             outSize.x = mTempMetrics.widthPixels;
             outSize.y = mTempMetrics.heightPixels;
         }
@@ -357,7 +418,7 @@
     public void getRectSize(Rect outSize) {
         synchronized (this) {
             updateDisplayInfoLocked();
-            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
+            mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
             outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels);
         }
     }
@@ -522,7 +583,7 @@
     public void getMetrics(DisplayMetrics outMetrics) {
         synchronized (this) {
             updateDisplayInfoLocked();
-            mDisplayInfo.getAppMetrics(outMetrics, mCompatibilityInfo);
+            mDisplayInfo.getAppMetrics(outMetrics, mDisplayAdjustments);
         }
     }
 
@@ -560,10 +621,28 @@
     public void getRealMetrics(DisplayMetrics outMetrics) {
         synchronized (this) {
             updateDisplayInfoLocked();
-            mDisplayInfo.getLogicalMetrics(outMetrics, null);
+            mDisplayInfo.getLogicalMetrics(outMetrics,
+                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,
+                    mDisplayAdjustments.getActivityToken());
         }
     }
 
+    /**
+     * Returns true if the specified UID has access to this display.
+     * @hide
+     */
+    public boolean hasAccess(int uid) {
+        return Display.hasAccess(uid, mFlags, mOwnerUid);
+    }
+
+    /** @hide */
+    public static boolean hasAccess(int uid, int flags, int ownerUid) {
+        return (flags & Display.FLAG_PRIVATE) == 0
+                || uid == ownerUid
+                || uid == Process.SYSTEM_UID
+                || uid == 0;
+    }
+
     private void updateDisplayInfoLocked() {
         // Note: The display manager caches display info objects on our behalf.
         DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
@@ -591,7 +670,7 @@
         long now = SystemClock.uptimeMillis();
         if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) {
             updateDisplayInfoLocked();
-            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
+            mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
             mCachedAppWidthCompat = mTempMetrics.widthPixels;
             mCachedAppHeightCompat = mTempMetrics.heightPixels;
             mLastCachedAppSizeUpdate = now;
@@ -603,7 +682,7 @@
     public String toString() {
         synchronized (this) {
             updateDisplayInfoLocked();
-            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
+            mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
             return "Display id " + mDisplayId + ": " + mDisplayInfo
                     + ", " + mTempMetrics + ", isValid=" + mIsValid;
         }
@@ -624,6 +703,8 @@
                 return "WIFI";
             case TYPE_OVERLAY:
                 return "OVERLAY";
+            case TYPE_VIRTUAL:
+                return "VIRTUAL";
             default:
                 return Integer.toString(type);
         }
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
new file mode 100644
index 0000000..041d9e0
--- /dev/null
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+package android.view;
+
+import android.content.res.CompatibilityInfo;
+import android.os.IBinder;
+
+import com.android.internal.util.Objects;
+
+/** @hide */
+public class DisplayAdjustments {
+    public static final boolean DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN = false;
+
+    public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments();
+
+    private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+    private volatile IBinder mActivityToken;
+
+    public DisplayAdjustments() {
+    }
+
+    public DisplayAdjustments(IBinder token) {
+        mActivityToken = token;
+    }
+
+    public DisplayAdjustments(DisplayAdjustments daj) {
+        this (daj.getCompatibilityInfo(), daj.getActivityToken());
+    }
+
+    public DisplayAdjustments(CompatibilityInfo compatInfo, IBinder token) {
+        setCompatibilityInfo(compatInfo);
+        mActivityToken = token;
+    }
+
+    public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
+        if (this == DEFAULT_DISPLAY_ADJUSTMENTS) {
+            throw new IllegalArgumentException(
+                    "setCompatbilityInfo: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
+        }
+        if (compatInfo != null && (compatInfo.isScalingRequired()
+                || !compatInfo.supportsScreen())) {
+            mCompatInfo = compatInfo;
+        } else {
+            mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+        }
+    }
+
+    public CompatibilityInfo getCompatibilityInfo() {
+        return mCompatInfo;
+    }
+
+    public void setActivityToken(IBinder token) {
+        if (this == DEFAULT_DISPLAY_ADJUSTMENTS) {
+            throw new IllegalArgumentException(
+                    "setActivityToken: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
+        }
+        mActivityToken = token;
+    }
+
+    public IBinder getActivityToken() {
+        return mActivityToken;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 17;
+        hash = hash * 31 + mCompatInfo.hashCode();
+        if (DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN) {
+            hash = hash * 31 + (mActivityToken == null ? 0 : mActivityToken.hashCode());
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof DisplayAdjustments)) {
+            return false;
+        }
+        DisplayAdjustments daj = (DisplayAdjustments)o;
+        return Objects.equal(daj.mCompatInfo, mCompatInfo) &&
+                Objects.equal(daj.mActivityToken, mActivityToken);
+    }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 9fcd9b1..8944207 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -17,8 +17,10 @@
 package android.view;
 
 import android.content.res.CompatibilityInfo;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.util.DisplayMetrics;
 
 import libcore.util.Objects;
@@ -177,6 +179,23 @@
      */
     public float physicalYDpi;
 
+    /**
+     * The UID of the application that owns this display, or zero if it is owned by the system.
+     * <p>
+     * If the display is private, then only the owner can use it.
+     * </p>
+     */
+    public int ownerUid;
+
+    /**
+     * The package name of the application that owns this display, or null if it is
+     * owned by the system.
+     * <p>
+     * If the display is private, then only the owner can use it.
+     * </p>
+     */
+    public String ownerPackageName;
+
     public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
         @Override
         public DisplayInfo createFromParcel(Parcel source) {
@@ -228,7 +247,9 @@
                 && refreshRate == other.refreshRate
                 && logicalDensityDpi == other.logicalDensityDpi
                 && physicalXDpi == other.physicalXDpi
-                && physicalYDpi == other.physicalYDpi;
+                && physicalYDpi == other.physicalYDpi
+                && ownerUid == other.ownerUid
+                && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
 
     @Override
@@ -259,6 +280,8 @@
         logicalDensityDpi = other.logicalDensityDpi;
         physicalXDpi = other.physicalXDpi;
         physicalYDpi = other.physicalYDpi;
+        ownerUid = other.ownerUid;
+        ownerPackageName = other.ownerPackageName;
     }
 
     public void readFromParcel(Parcel source) {
@@ -284,6 +307,8 @@
         logicalDensityDpi = source.readInt();
         physicalXDpi = source.readFloat();
         physicalYDpi = source.readFloat();
+        ownerUid = source.readInt();
+        ownerPackageName = source.readString();
     }
 
     @Override
@@ -310,6 +335,8 @@
         dest.writeInt(logicalDensityDpi);
         dest.writeFloat(physicalXDpi);
         dest.writeFloat(physicalYDpi);
+        dest.writeInt(ownerUid);
+        dest.writeString(ownerPackageName);
     }
 
     @Override
@@ -317,12 +344,22 @@
         return 0;
     }
 
-    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfoHolder cih) {
-        getMetricsWithSize(outMetrics, cih, appWidth, appHeight);
+    public void getAppMetrics(DisplayMetrics outMetrics) {
+        getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
     }
 
-    public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfoHolder cih) {
-        getMetricsWithSize(outMetrics, cih, logicalWidth, logicalHeight);
+    public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
+        getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
+                displayAdjustments.getActivityToken(), appWidth, appHeight);
+    }
+
+    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, IBinder token) {
+        getMetricsWithSize(outMetrics, ci, token, appWidth, appHeight);
+    }
+
+    public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
+            IBinder token) {
+        getMetricsWithSize(outMetrics, compatInfo, token, logicalWidth, logicalHeight);
     }
 
     public int getNaturalWidth() {
@@ -335,8 +372,15 @@
                 logicalHeight : logicalWidth;
     }
 
-    private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfoHolder cih,
-            int width, int height) {
+    /**
+     * Returns true if the specified UID has access to this display.
+     */
+    public boolean hasAccess(int uid) {
+        return Display.hasAccess(uid, flags, ownerUid);
+    }
+
+    private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
+            IBinder token, int width, int height) {
         outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
         outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
         outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
@@ -347,11 +391,8 @@
         outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
         outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
 
-        if (cih != null) {
-            CompatibilityInfo ci = cih.getIfNeeded();
-            if (ci != null) {
-                ci.applyToDisplayMetrics(outMetrics);
-            }
+        if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
+            compatInfo.applyToDisplayMetrics(outMetrics);
         }
     }
 
@@ -402,8 +443,13 @@
         sb.append(layerStack);
         sb.append(", type ");
         sb.append(Display.typeToString(type));
-        sb.append(", address ");
-        sb.append(address);
+        if (address != null) {
+            sb.append(", address ").append(address);
+        }
+        if (ownerUid != 0 || ownerPackageName != null) {
+            sb.append(", owner ").append(ownerPackageName);
+            sb.append(" (uid ").append(ownerUid).append(")");
+        }
         sb.append(flagsToString(flags));
         sb.append("}");
         return sb.toString();
@@ -417,6 +463,12 @@
         if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
             result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
         }
+        if ((flags & Display.FLAG_PRIVATE) != 0) {
+            result.append(", FLAG_PRIVATE");
+        }
+        if ((flags & Display.FLAG_PRESENTATION) != 0) {
+            result.append(", FLAG_PRESENTATION");
+        }
         return result.toString();
     }
 }
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 2d24c1e..43fd628 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -208,9 +208,22 @@
      * {@link #isValid()} will return false.
      *
      * @see #isValid()
+     * @see #reset()
      */
     public abstract void clear();
 
+
+    /**
+     * Reset native resources. This is called when cleaning up the state of display lists
+     * during destruction of hardware resources, to ensure that we do not hold onto
+     * obsolete resources after related resources are gone.
+     *
+     * @see #clear()
+     *
+     * @hide
+     */
+    public abstract void reset();
+
     /**
      * Sets the dirty flag. When a display list is dirty, {@link #clear()} should
      * be invoked whenever possible.
@@ -670,13 +683,4 @@
      * @see View#offsetTopAndBottom(int)
      */
     public abstract void offsetTopAndBottom(float offset);
-
-    /**
-     * Reset native resources. This is called when cleaning up the state of display lists
-     * during destruction of hardware resources, to ensure that we do not hold onto
-     * obsolete resources after related resources are gone.
-     *
-     * @hide
-     */
-    public abstract void reset();
 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 2ec9a7d..beefc21 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -21,6 +21,7 @@
 import android.graphics.ColorFilter;
 import android.graphics.DrawFilter;
 import android.graphics.Matrix;
+import android.graphics.NinePatch;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Path;
@@ -58,11 +59,11 @@
     private int mWidth;
     private int mHeight;
     
-    private final float[] mPoint = new float[2];
-    private final float[] mLine = new float[4];
+    private float[] mPoint;
+    private float[] mLine;
     
-    private final Rect mClipBounds = new Rect();
-    private final RectF mPathBounds = new RectF();
+    private Rect mClipBounds;
+    private RectF mPathBounds;
 
     private DrawFilter mFilter;
 
@@ -162,6 +163,16 @@
     }
 
     @Override
+    void cancelLayerUpdate(HardwareLayer layer) {
+        nCancelLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
+    }
+
+    @Override
+    void flushLayerUpdates() {
+        nFlushLayerUpdates(mRenderer);
+    }
+
+    @Override
     void clearLayerUpdates() {
         nClearLayerUpdates(mRenderer);
     }
@@ -183,7 +194,9 @@
     static native boolean nCopyLayer(int layerId, int bitmap);
 
     private static native void nClearLayerUpdates(int renderer);
+    private static native void nFlushLayerUpdates(int renderer);
     private static native void nPushLayerUpdate(int renderer, int layer);
+    private static native void nCancelLayerUpdate(int renderer, int layer);
 
     ///////////////////////////////////////////////////////////////////////////
     // Canvas management
@@ -273,6 +286,18 @@
 
     private static native int nGetStencilSize();
 
+    void setCountOverdrawEnabled(boolean enabled) {
+        nSetCountOverdrawEnabled(mRenderer, enabled);
+    }
+
+    static native void nSetCountOverdrawEnabled(int renderer, boolean enabled);
+
+    float getOverdraw() {
+        return nGetOverdraw(mRenderer);
+    }
+
+    static native float nGetOverdraw(int renderer);
+
     ///////////////////////////////////////////////////////////////////////////
     // Functor
     ///////////////////////////////////////////////////////////////////////////
@@ -314,21 +339,21 @@
      * 
      * @see #flushCaches(int) 
      */
-    public static final int FLUSH_CACHES_LAYERS = 0;
+    static final int FLUSH_CACHES_LAYERS = 0;
     
     /**
      * Must match Caches::FlushMode values
      * 
      * @see #flushCaches(int) 
      */
-    public static final int FLUSH_CACHES_MODERATE = 1;
+    static final int FLUSH_CACHES_MODERATE = 1;
 
     /**
      * Must match Caches::FlushMode values
      * 
      * @see #flushCaches(int) 
      */
-    public static final int FLUSH_CACHES_FULL = 2;
+    static final int FLUSH_CACHES_FULL = 2;
 
     /**
      * Flush caches to reclaim as much memory as possible. The amount of memory
@@ -338,10 +363,8 @@
      * {@link #FLUSH_CACHES_FULL}.
      * 
      * @param level Hint about the amount of memory to reclaim
-     * 
-     * @hide
      */
-    public static void flushCaches(int level) {
+    static void flushCaches(int level) {
         nFlushCaches(level);
     }
 
@@ -353,21 +376,28 @@
      * 
      * @hide
      */
-    public static void terminateCaches() {
+    static void terminateCaches() {
         nTerminateCaches();
     }
 
     private static native void nTerminateCaches();
 
-    /**
-     * @hide
-     */
-    public static void initCaches() {
-        nInitCaches();
+    static boolean initCaches() {
+        return nInitCaches();
     }
 
-    private static native void nInitCaches();
-    
+    private static native boolean nInitCaches();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Atlas
+    ///////////////////////////////////////////////////////////////////////////
+
+    static void initAtlas(GraphicBuffer buffer, int[] map) {
+        nInitAtlas(buffer, map, map.length);
+    }
+
+    private static native void nInitAtlas(GraphicBuffer buffer, int[] map, int count);
+
     ///////////////////////////////////////////////////////////////////////////
     // Display list
     ///////////////////////////////////////////////////////////////////////////
@@ -419,6 +449,31 @@
     private static native void nResume(int renderer);
 
     ///////////////////////////////////////////////////////////////////////////
+    // Support
+    ///////////////////////////////////////////////////////////////////////////
+
+    private Rect getInternalClipBounds() {
+        if (mClipBounds == null) mClipBounds = new Rect();
+        return mClipBounds;
+    }
+
+
+    private RectF getPathBounds() {
+        if (mPathBounds == null) mPathBounds = new RectF();
+        return mPathBounds;
+    }
+
+    private float[] getPointStorage() {
+        if (mPoint == null) mPoint = new float[2];
+        return mPoint;
+    }
+
+    private float[] getLineStorage() {
+        if (mLine == null) mLine = new float[4];
+        return mLine;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
     // Clipping
     ///////////////////////////////////////////////////////////////////////////
 
@@ -506,9 +561,10 @@
 
     @Override
     public boolean quickReject(Path path, EdgeType type) {
-        path.computeBounds(mPathBounds, true);
-        return nQuickReject(mRenderer, mPathBounds.left, mPathBounds.top,
-                mPathBounds.right, mPathBounds.bottom);
+        RectF pathBounds = getPathBounds();
+        path.computeBounds(pathBounds, true);
+        return nQuickReject(mRenderer, pathBounds.left, pathBounds.top,
+                pathBounds.right, pathBounds.bottom);
     }
 
     @Override
@@ -565,7 +621,7 @@
 
     @Override
     public void concat(Matrix matrix) {
-        nConcatMatrix(mRenderer, matrix.native_instance);
+        if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance);
     }
     
     private static native void nConcatMatrix(int renderer, int matrix);
@@ -718,25 +774,41 @@
     }
 
     @Override
-    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
-        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+        Bitmap bitmap = patch.getBitmap();
+        throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing patches
         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
         try {
             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
+            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
                     dst.left, dst.top, dst.right, dst.bottom, nativePaint);
         } finally {
             if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
         }
     }
 
-    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
+    @Override
+    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
+        Bitmap bitmap = patch.getBitmap();
+        throwIfCannotDraw(bitmap);
+        // Shaders are ignored when drawing patches
+        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
+                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+        } finally {
+            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        }
+    }
+
+    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, int chunk,
             float left, float top, float right, float bottom, int paint);
 
     @Override
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
-        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+        throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
@@ -747,12 +819,12 @@
         }
     }
 
-    private static native void nDrawBitmap(
-            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
+    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
+            float left, float top, int paint);
 
     @Override
     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
-        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+        throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
@@ -764,12 +836,12 @@
         }
     }
 
-    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
+    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
             int matrix, int paint);
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
-        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+        throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
@@ -796,7 +868,7 @@
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
-        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+        throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
@@ -872,7 +944,7 @@
     @Override
     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
             int vertOffset, int[] colors, int colorOffset, Paint paint) {
-        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+        throwIfCannotDraw(bitmap);
         if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
             throw new ArrayIndexOutOfBoundsException();
         }
@@ -890,7 +962,7 @@
 
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
-            final int nativePaint = paint == null ? 0 : paint.mNativePaint;        
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
             nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
                     verts, vertOffset, colors, colorOffset, nativePaint);
         } finally {
@@ -929,11 +1001,12 @@
 
     @Override
     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
-        mLine[0] = startX;
-        mLine[1] = startY;
-        mLine[2] = stopX;
-        mLine[3] = stopY;
-        drawLines(mLine, 0, 4, paint);
+        float[] line = getLineStorage();
+        line[0] = startX;
+        line[1] = startY;
+        line[2] = stopX;
+        line[3] = stopY;
+        drawLines(line, 0, 4, paint);
     }
 
     @Override
@@ -974,7 +1047,7 @@
 
     @Override
     public void drawPaint(Paint paint) {
-        final Rect r = mClipBounds;
+        final Rect r = getInternalClipBounds();
         nGetClipBounds(mRenderer, r);
         drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
@@ -1051,9 +1124,10 @@
 
     @Override
     public void drawPoint(float x, float y, Paint paint) {
-        mPoint[0] = x;
-        mPoint[1] = y;
-        drawPoints(mPoint, 0, 2, paint);
+        float[] point = getPointStorage();
+        point[0] = x;
+        point[1] = y;
+        drawPoints(point, 0, 2, paint);
     }
 
     @Override
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 3272504..c652bac 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.graphics.Bitmap;
 import android.graphics.Matrix;
 
 import java.util.ArrayList;
@@ -25,12 +24,7 @@
  * An implementation of display list for OpenGL ES 2.0.
  */
 class GLES20DisplayList extends DisplayList {
-    // These lists ensure that any Bitmaps and DisplayLists recorded by a DisplayList are kept
-    // alive as long as the DisplayList is alive.  The Bitmap and DisplayList lists
-    // are populated by the GLES20RecordingCanvas during appropriate drawing calls and are
-    // cleared at the start of a new drawing frame or when the view is detached from the window.
-    final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
-    final ArrayList<DisplayList> mChildDisplayLists = new ArrayList<DisplayList>();
+    private ArrayList<DisplayList> mChildDisplayLists;
 
     private GLES20RecordingCanvas mCanvas;
     private boolean mValid;
@@ -83,8 +77,16 @@
         }
         mValid = false;
 
-        mBitmaps.clear();
-        mChildDisplayLists.clear();
+        clearReferences();
+    }
+
+    void clearReferences() {
+        if (mChildDisplayLists != null) mChildDisplayLists.clear();
+    }
+
+    ArrayList<DisplayList> getChildDisplayLists() {
+        if (mChildDisplayLists == null) mChildDisplayLists = new ArrayList<DisplayList>();
+        return mChildDisplayLists;
     }
 
     @Override
@@ -92,6 +94,7 @@
         if (hasNativeDisplayList()) {
             nReset(mFinalizer.mNativeDisplayList);
         }
+        clear();
     }
 
     @Override
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 7ee628b..0e3311c 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -59,6 +59,9 @@
 
     @Override
     public void destroy() {
+        if (mDisplayList != null) {
+            mDisplayList.reset();
+        }
         if (mFinalizer != null) {
             mFinalizer.destroy();
             mFinalizer = null;
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 7da2451..b6fc38d 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -16,14 +16,7 @@
 
 package android.view;
 
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
 import android.util.Pools.SynchronizedPool;
 
 /**
@@ -62,229 +55,17 @@
     }
 
     void start() {
-        mDisplayList.mBitmaps.clear();
-        mDisplayList.mChildDisplayLists.clear();
+        mDisplayList.clearReferences();
     }
 
     int end(int nativeDisplayList) {
         return getDisplayList(nativeDisplayList);
     }
 
-    private void recordShaderBitmap(Paint paint) {
-        if (paint != null) {
-            final Shader shader = paint.getShader();
-            if (shader instanceof BitmapShader) {
-                mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap);
-            }
-        }
-    }
-
-    @Override
-    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
-        super.drawPatch(bitmap, chunks, dst, paint);
-        mDisplayList.mBitmaps.add(bitmap);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
-        super.drawBitmap(bitmap, left, top, paint);
-        mDisplayList.mBitmaps.add(bitmap);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
-        super.drawBitmap(bitmap, matrix, paint);
-        mDisplayList.mBitmaps.add(bitmap);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
-        super.drawBitmap(bitmap, src, dst, paint);
-        mDisplayList.mBitmaps.add(bitmap);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
-        super.drawBitmap(bitmap, src, dst, paint);
-        mDisplayList.mBitmaps.add(bitmap);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width,
-            int height, boolean hasAlpha, Paint paint) {
-        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
-            int height, boolean hasAlpha, Paint paint) {
-        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
-            int vertOffset, int[] colors, int colorOffset, Paint paint) {
-        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset,
-                colors, colorOffset, paint);
-        mDisplayList.mBitmaps.add(bitmap);
-        // Shaders in the Paint are ignored when drawing a Bitmap
-    }
-
-    @Override
-    public void drawCircle(float cx, float cy, float radius, Paint paint) {
-        super.drawCircle(cx, cy, radius, paint);
-        recordShaderBitmap(paint);
-    }
-
     @Override
     public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
         int status = super.drawDisplayList(displayList, dirty, flags);
-        mDisplayList.mChildDisplayLists.add(displayList);
+        mDisplayList.getChildDisplayLists().add(displayList);
         return status;
     }
-
-    @Override
-    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
-        super.drawLine(startX, startY, stopX, stopY, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawLines(float[] pts, int offset, int count, Paint paint) {
-        super.drawLines(pts, offset, count, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawLines(float[] pts, Paint paint) {
-        super.drawLines(pts, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawOval(RectF oval, Paint paint) {
-        super.drawOval(oval, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPaint(Paint paint) {
-        super.drawPaint(paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPath(Path path, Paint paint) {
-        super.drawPath(path, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPoint(float x, float y, Paint paint) {
-        super.drawPoint(x, y, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
-        super.drawPoints(pts, offset, count, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPoints(float[] pts, Paint paint) {
-        super.drawPoints(pts, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
-        super.drawPosText(text, index, count, pos, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawPosText(String text, float[] pos, Paint paint) {
-        super.drawPosText(text, pos, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
-        super.drawRect(left, top, right, bottom, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
-        super.drawRoundRect(rect, rx, ry, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
-        super.drawText(text, index, count, x, y, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
-        super.drawText(text, start, end, x, y, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
-        super.drawText(text, start, end, x, y, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawText(String text, float x, float y, Paint paint) {
-        super.drawText(text, x, y, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
-            float vOffset, Paint paint) {
-        super.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
-        super.drawTextOnPath(text, path, hOffset, vOffset, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, int dir, Paint paint) {
-        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    public void drawTextRun(CharSequence text, int start, int end, int contextStart,
-            int contextEnd, float x, float y, int dir, Paint paint) {
-        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
-        recordShaderBitmap(paint);
-    }
-
-    @Override
-    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) {
-        super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors,
-                colorOffset, indices, indexOffset, indexCount, paint);
-        recordShaderBitmap(paint);
-    }
 }
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
index 685dc70..68ba77c 100644
--- a/core/java/android/view/GLES20RenderLayer.java
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -100,12 +100,17 @@
 
     @Override
     HardwareCanvas start(Canvas currentCanvas) {
+        return start(currentCanvas, null);
+    }
+
+    @Override
+    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
         if (currentCanvas instanceof GLES20Canvas) {
             ((GLES20Canvas) currentCanvas).interrupt();
         }
         HardwareCanvas canvas = getCanvas();
         canvas.setViewport(mWidth, mHeight);
-        canvas.onPreDraw(null);
+        canvas.onPreDraw(dirty);
         return canvas;
     }
 
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index e863e49..bb5a6eb 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -63,12 +63,17 @@
     }
 
     @Override
+    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
+        return null;
+    }
+
+    @Override
     void end(Canvas currentCanvas) {
     }
 
     SurfaceTexture getSurfaceTexture() {
         if (mSurface == null) {
-            mSurface = new SurfaceTexture(mTexture, false);
+            mSurface = new SurfaceTexture(mTexture);
         }
         return mSurface;
     }
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 28c1058..2351548 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -17,7 +17,6 @@
 package android.view;
 
 import android.content.Context;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 
@@ -202,6 +201,7 @@
     private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
     private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
     private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
+    private static final int DOUBLE_TAP_MIN_TIME = ViewConfiguration.getDoubleTapMinTime();
 
     // constants for Message.what used by GestureHandler below
     private static final int SHOW_PRESS = 1;
@@ -323,7 +323,7 @@
 
     /**
      * Creates a GestureDetector with the supplied listener.
-     * You may only use this constructor from a UI thread (this is the usual situation).
+     * You may only use this constructor from a {@link android.os.Looper} thread.
      * @see android.os.Handler#Handler()
      *
      * @param context the application's context
@@ -337,14 +337,14 @@
     }
 
     /**
-     * Creates a GestureDetector with the supplied listener.
-     * You may only use this constructor from a UI thread (this is the usual situation).
+     * Creates a GestureDetector with the supplied listener that runs deferred events on the
+     * thread associated with the supplied {@link android.os.Handler}.
      * @see android.os.Handler#Handler()
      *
      * @param context the application's context
      * @param listener the listener invoked for all the callbacks, this must
      * not be null.
-     * @param handler the handler to use     
+     * @param handler the handler to use for running deferred listener events.
      *
      * @throws NullPointerException if {@code listener} is null.
      */
@@ -362,14 +362,15 @@
     }
     
     /**
-     * Creates a GestureDetector with the supplied listener.
-     * You may only use this constructor from a UI thread (this is the usual situation).
+     * Creates a GestureDetector with the supplied listener that runs deferred events on the
+     * thread associated with the supplied {@link android.os.Handler}.
      * @see android.os.Handler#Handler()
      *
      * @param context the application's context
      * @param listener the listener invoked for all the callbacks, this must
      * not be null.
-     * @param handler the handler to use
+     * @param handler the handler to use for running deferred listener events.
+     * @param unused currently not used.
      *
      * @throws NullPointerException if {@code listener} is null.
      */
@@ -672,7 +673,8 @@
             return false;
         }
 
-        if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) {
+        final long deltaTime = secondDown.getEventTime() - firstUp.getEventTime();
+        if (deltaTime > DOUBLE_TAP_TIMEOUT || deltaTime < DOUBLE_TAP_MIN_TIME) {
             return false;
         }
 
diff --git a/core/java/android/view/GraphicBuffer.aidl b/core/java/android/view/GraphicBuffer.aidl
new file mode 100644
index 0000000..6dc6bed
--- /dev/null
+++ b/core/java/android/view/GraphicBuffer.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view;
+
+parcelable GraphicBuffer;
diff --git a/core/java/android/view/GraphicBuffer.java b/core/java/android/view/GraphicBuffer.java
new file mode 100644
index 0000000..30c077c
--- /dev/null
+++ b/core/java/android/view/GraphicBuffer.java
@@ -0,0 +1,292 @@
+/*
+ * 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 android.view;
+
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Simple wrapper for the native GraphicBuffer class.
+ *
+ * @hide
+ */
+@SuppressWarnings("UnusedDeclaration")
+public class GraphicBuffer implements Parcelable {
+    // Note: keep usage flags in sync with GraphicBuffer.h and gralloc.h
+    public static final int USAGE_SW_READ_NEVER = 0x0;
+    public static final int USAGE_SW_READ_RARELY = 0x2;
+    public static final int USAGE_SW_READ_OFTEN = 0x3;
+    public static final int USAGE_SW_READ_MASK = 0xF;
+
+    public static final int USAGE_SW_WRITE_NEVER = 0x0;
+    public static final int USAGE_SW_WRITE_RARELY = 0x20;
+    public static final int USAGE_SW_WRITE_OFTEN = 0x30;
+    public static final int USAGE_SW_WRITE_MASK = 0xF0;
+
+    public static final int USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK | USAGE_SW_WRITE_MASK;
+
+    public static final int USAGE_PROTECTED = 0x4000;
+
+    public static final int USAGE_HW_TEXTURE = 0x100;
+    public static final int USAGE_HW_RENDER = 0x200;
+    public static final int USAGE_HW_2D = 0x400;
+    public static final int USAGE_HW_COMPOSER = 0x800;
+    public static final int USAGE_HW_VIDEO_ENCODER = 0x10000;
+    public static final int USAGE_HW_MASK = 0x71F00;
+
+    private final int mWidth;
+    private final int mHeight;
+    private final int mFormat;
+    private final int mUsage;
+    // Note: do not rename, this field is used by native code
+    private final int mNativeObject;
+
+    // These two fields are only used by lock/unlockCanvas()
+    private Canvas mCanvas;
+    private int mSaveCount;
+
+    // If set to true, this GraphicBuffer instance cannot be used anymore
+    private boolean mDestroyed;
+
+    /**
+     * Creates new <code>GraphicBuffer</code> instance. This method will return null
+     * if the buffer cannot be created.
+     *
+     * @param width The width in pixels of the buffer
+     * @param height The height in pixels of the buffer
+     * @param format The format of each pixel as specified in {@link PixelFormat}
+     * @param usage Hint indicating how the buffer will be used
+     *
+     * @return A <code>GraphicBuffer</code> instance or null
+     */
+    public static GraphicBuffer create(int width, int height, int format, int usage) {
+        int nativeObject = nCreateGraphicBuffer(width, height, format, usage);
+        if (nativeObject != 0) {
+            return new GraphicBuffer(width, height, format, usage, nativeObject);
+        }
+        return null;
+    }
+
+    /**
+     * Private use only. See {@link #create(int, int, int, int)}.
+     */
+    private GraphicBuffer(int width, int height, int format, int usage, int nativeObject) {
+        mWidth = width;
+        mHeight = height;
+        mFormat = format;
+        mUsage = usage;
+        mNativeObject = nativeObject;
+    }
+
+    /**
+     * Returns the width of this buffer in pixels.
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Returns the height of this buffer in pixels.
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Returns the pixel format of this buffer. The pixel format must be one of
+     * the formats defined in {@link PixelFormat}.
+     */
+    public int getFormat() {
+        return mFormat;
+    }
+
+    /**
+     * Returns the usage hint set on this buffer.
+     */
+    public int getUsage() {
+        return mUsage;
+    }
+
+    /**
+     * <p>Start editing the pixels in the buffer. A null is returned if the buffer
+     * cannot be locked for editing.</p>
+     *
+     * <p>The content of the buffer is preserved between unlockCanvas()
+     * and lockCanvas().</p>
+     *
+     * <p>If this method is called after {@link #destroy()}, the return value will
+     * always be null.</p>
+     *
+     * @return A Canvas used to draw into the buffer, or null.
+     *
+     * @see #lockCanvas(android.graphics.Rect)
+     * @see #unlockCanvasAndPost(android.graphics.Canvas)
+     * @see #isDestroyed()
+     */
+    public Canvas lockCanvas() {
+        return lockCanvas(null);
+    }
+
+    /**
+     * Just like {@link #lockCanvas()} but allows specification of a dirty
+     * rectangle.
+     *
+     * <p>If this method is called after {@link #destroy()}, the return value will
+     * always be null.</p>
+     *
+     * @param dirty Area of the buffer that may be modified.
+
+     * @return A Canvas used to draw into the surface, or null.
+     *
+     * @see #lockCanvas()
+     * @see #unlockCanvasAndPost(android.graphics.Canvas)
+     * @see #isDestroyed()
+     */
+    public Canvas lockCanvas(Rect dirty) {
+        if (mDestroyed) {
+            return null;
+        }
+
+        if (mCanvas == null) {
+            mCanvas = new Canvas();
+        }
+
+        if (nLockCanvas(mNativeObject, mCanvas, dirty)) {
+            mSaveCount = mCanvas.save();
+            return mCanvas;
+        }
+
+        return null;
+    }
+
+    /**
+     * Finish editing pixels in the buffer.
+     *
+     * <p>This method doesn't do anything if {@link #destroy()} was
+     * previously called.</p>
+     *
+     * @param canvas The Canvas previously returned by lockCanvas()
+     *
+     * @see #lockCanvas()
+     * @see #lockCanvas(android.graphics.Rect)
+     * @see #isDestroyed()
+     */
+    public void unlockCanvasAndPost(Canvas canvas) {
+        if (!mDestroyed && mCanvas != null && canvas == mCanvas) {
+            canvas.restoreToCount(mSaveCount);
+            mSaveCount = 0;
+
+            nUnlockCanvasAndPost(mNativeObject, mCanvas);
+        }
+    }
+
+    /**
+     * Destroyes this buffer immediately. Calling this method frees up any
+     * underlying native resources. After calling this method, this buffer
+     * must not be used in any way ({@link #lockCanvas()} must not be called,
+     * etc.)
+     *
+     * @see #isDestroyed()
+     */
+    public void destroy() {
+        if (!mDestroyed) {
+            mDestroyed = true;
+            nDestroyGraphicBuffer(mNativeObject);
+        }
+    }
+
+    /**
+     * Indicates whether this buffer has been destroyed. A destroyed buffer
+     * cannot be used in any way: locking a Canvas will return null, the buffer
+     * cannot be written to a parcel, etc.
+     *
+     * @return True if this <code>GraphicBuffer</code> is in a destroyed state,
+     *         false otherwise.
+     *
+     * @see #destroy()
+     */
+    public boolean isDestroyed() {
+        return mDestroyed;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Flatten this object in to a Parcel.
+     *
+     * <p>Calling this method will throw an <code>IllegalStateException</code> if
+     * {@link #destroy()} has been previously called.</p>
+     *
+     * @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_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mDestroyed) {
+            throw new IllegalStateException("This GraphicBuffer has been destroyed and cannot be "
+                    + "written to a parcel.");
+        }
+
+        dest.writeInt(mWidth);
+        dest.writeInt(mHeight);
+        dest.writeInt(mFormat);
+        dest.writeInt(mUsage);
+        nWriteGraphicBufferToParcel(mNativeObject, dest);
+    }
+
+    public static final Parcelable.Creator<GraphicBuffer> CREATOR =
+            new Parcelable.Creator<GraphicBuffer>() {
+        public GraphicBuffer createFromParcel(Parcel in) {
+            int width = in.readInt();
+            int height = in.readInt();
+            int format = in.readInt();
+            int usage = in.readInt();
+            int nativeObject = nReadGraphicBufferFromParcel(in);
+            if (nativeObject != 0) {
+                return new GraphicBuffer(width, height, format, usage, nativeObject);
+            }
+            return null;
+        }
+
+        public GraphicBuffer[] newArray(int size) {
+            return new GraphicBuffer[size];
+        }
+    };
+
+    private static native int nCreateGraphicBuffer(int width, int height, int format, int usage);
+    private static native void nDestroyGraphicBuffer(int nativeObject);
+    private static native void nWriteGraphicBufferToParcel(int nativeObject, Parcel dest);
+    private static native int nReadGraphicBufferFromParcel(Parcel in);
+    private static native boolean nLockCanvas(int nativeObject, Canvas canvas, Rect dirty);
+    private static native boolean nUnlockCanvasAndPost(int nativeObject, Canvas canvas);
+}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 0dfed69..259e1cd 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -202,6 +202,28 @@
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
+     * Cancels a queued layer update. If the specified layer was not
+     * queued for update, this method has no effect.
+     *
+     * @param layer The layer whose update to cancel
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     * @see #clearLayerUpdates()
+     *
+     * @hide
+     */
+    abstract void cancelLayerUpdate(HardwareLayer layer);
+
+    /**
+     * Immediately executes all enqueued layer updates.
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     *
+     * @hide
+     */
+    abstract void flushLayerUpdates();
+
+    /**
      * Removes all enqueued layer updates.
      * 
      * @see #pushLayerUpdate(HardwareLayer)
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 18b838b..23383d9 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -158,14 +158,22 @@
     /**
      * This must be invoked before drawing onto this layer.
      *
-     * @param currentCanvas
+     * @param currentCanvas The canvas whose rendering needs to be interrupted
      */
     abstract HardwareCanvas start(Canvas currentCanvas);
 
     /**
+     * This must be invoked before drawing onto this layer.
+     *
+     * @param dirty The dirty area to repaint
+     * @param currentCanvas The canvas whose rendering needs to be interrupted
+     */
+    abstract HardwareCanvas start(Canvas currentCanvas, Rect dirty);
+
+    /**
      * This must be invoked after drawing onto this layer.
      *
-     * @param currentCanvas
+     * @param currentCanvas The canvas whose rendering needs to be resumed
      */
     abstract void end(Canvas currentCanvas);
 
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 8308459..f215189 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.content.ComponentCallbacks2;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -24,12 +25,17 @@
 import android.opengl.GLUtils;
 import android.opengl.ManagedEGLContext;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.Surface.OutOfResourcesException;
+
 import com.google.android.gles_jni.EGLImpl;
 
 import javax.microedition.khronos.egl.EGL10;
@@ -42,7 +48,6 @@
 
 import java.io.File;
 import java.io.PrintWriter;
-import java.util.Arrays;
 import java.util.concurrent.locks.ReentrantLock;
 
 import static javax.microedition.khronos.egl.EGL10.*;
@@ -71,7 +76,7 @@
      * System property used to enable or disable dirty regions invalidation.
      * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
      * The default value of this property is assumed to be true.
-     * 
+     *
      * Possible values:
      * "true", to enable partial invalidates
      * "false", to disable partial invalidates
@@ -131,7 +136,7 @@
 
     /**
      * System property used to debug EGL configuration choice.
-     * 
+     *
      * Possible values:
      * "choice", print the chosen configuration only
      * "all", print all possible configurations
@@ -144,7 +149,7 @@
      * Possible values:
      * "true", to enable dirty regions debugging
      * "false", to disable dirty regions debugging
-     * 
+     *
      * @hide
      */
     public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
@@ -162,15 +167,32 @@
             "debug.hwui.show_layers_updates";
 
     /**
-     * Turn on to show overdraw level.
+     * Controls overdraw debugging.
      *
      * Possible values:
-     * "true", to enable overdraw debugging
      * "false", to disable overdraw debugging
+     * "show", to show overdraw areas on screen
+     * "count", to display an overdraw counter
      *
      * @hide
      */
-    public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw";
+    public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw";
+
+    /**
+     * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
+     * value, overdraw will be shown on screen by coloring pixels.
+     *
+     * @hide
+     */
+    public static final String OVERDRAW_PROPERTY_SHOW = "show";
+
+    /**
+     * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
+     * value, an overdraw counter will be shown on screen.
+     *
+     * @hide
+     */
+    public static final String OVERDRAW_PROPERTY_COUNT = "count";
 
     /**
      * Turn on to debug non-rectangular clip operations.
@@ -188,14 +210,14 @@
     /**
      * A process can set this flag to false to prevent the use of hardware
      * rendering.
-     * 
+     *
      * @hide
      */
     public static boolean sRendererDisabled = false;
 
     /**
      * Further hardware renderer disabling for the system process.
-     * 
+     *
      * @hide
      */
     public static boolean sSystemRendererDisabled = false;
@@ -215,7 +237,7 @@
 
     /**
      * Invoke this method to disable hardware rendering in the current process.
-     * 
+     *
      * @hide
      */
     public static void disable(boolean system) {
@@ -228,7 +250,7 @@
     /**
      * Indicates whether hardware acceleration is available under any form for
      * the view hierarchy.
-     * 
+     *
      * @return True if the view hierarchy can potentially be hardware accelerated,
      *         false otherwise
      */
@@ -238,30 +260,30 @@
 
     /**
      * Destroys the hardware rendering context.
-     * 
+     *
      * @param full If true, destroys all associated resources.
      */
     abstract void destroy(boolean full);
 
     /**
      * Initializes the hardware renderer for the specified surface.
-     * 
+     *
      * @param surface The surface to hardware accelerate
-     * 
+     *
      * @return True if the initialization was successful, false otherwise.
      */
-    abstract boolean initialize(Surface surface) throws Surface.OutOfResourcesException;
-    
+    abstract boolean initialize(Surface surface) throws OutOfResourcesException;
+
     /**
      * Updates the hardware renderer for the specified surface.
      *
      * @param surface The surface to hardware accelerate
      */
-    abstract void updateSurface(Surface surface) throws Surface.OutOfResourcesException;
+    abstract void updateSurface(Surface surface) throws OutOfResourcesException;
 
     /**
      * Destroys the layers used by the specified view hierarchy.
-     * 
+     *
      * @param view The root of the view hierarchy
      */
     abstract void destroyLayers(View view);
@@ -269,11 +291,11 @@
     /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
-     * 
+     *
      * @param view The root of the view hierarchy
      */
     abstract void destroyHardwareResources(View view);
-    
+
     /**
      * This method should be invoked whenever the current hardware renderer
      * context should be reset.
@@ -286,7 +308,7 @@
      * This method should be invoked to ensure the hardware renderer is in
      * valid state (for instance, to ensure the correct EGL context is bound
      * to the current thread.)
-     * 
+     *
      * @return true if the renderer is now valid, false otherwise
      */
     abstract boolean validate();
@@ -294,7 +316,7 @@
     /**
      * This method ensures the hardware renderer is in a valid state
      * before executing the specified action.
-     * 
+     *
      * This method will attempt to set a valid state even if the window
      * the renderer is attached to was destroyed.
      *
@@ -305,7 +327,7 @@
     /**
      * Setup the hardware renderer for drawing. This is called whenever the
      * size of the target surface changes or when the surface is first created.
-     * 
+     *
      * @param width Width of the drawing surface.
      * @param height Height of the drawing surface.
      */
@@ -364,7 +386,7 @@
     /**
      * Sets the directory to use as a persistent storage for hardware rendering
      * resources.
-     * 
+     *
      * @param cacheDir A directory the current process can write to
      *
      * @hide
@@ -386,6 +408,17 @@
     private static native void nBeginFrame(int[] size);
 
     /**
+     * Returns the current system time according to the renderer.
+     * This method is used for debugging only and should not be used
+     * as a clock.
+     */
+    static long getSystemTime() {
+        return nGetSystemTime();
+    }
+
+    private static native long nGetSystemTime();
+
+    /**
      * Preserves the back buffer of the current surface after a buffer swap.
      * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
      * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
@@ -416,12 +449,32 @@
     /**
      * Indicates that the specified hardware layer needs to be updated
      * as soon as possible.
-     * 
+     *
      * @param layer The hardware layer that needs an update
+     *
+     * @see #flushLayerUpdates()
+     * @see #cancelLayerUpdate(HardwareLayer)
      */
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
+     * Cancels a queued layer update. If the specified layer was not
+     * queued for update, this method has no effect.
+     *
+     * @param layer The layer whose update to cancel
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     */
+    abstract void cancelLayerUpdate(HardwareLayer layer);
+
+    /**
+     * Forces all enqueued layer updates to be executed immediately.
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     */
+    abstract void flushLayerUpdates();
+
+    /**
      * Interface used to receive callbacks whenever a view is drawn by
      * a hardware renderer instance.
      */
@@ -430,7 +483,7 @@
          * Invoked before a view is drawn by a hardware renderer.
          * This method can be used to apply transformations to the
          * canvas but no drawing command should be issued.
-         * 
+         *
          * @param canvas The Canvas used to render the view.
          */
         void onHardwarePreDraw(HardwareCanvas canvas);
@@ -438,7 +491,7 @@
         /**
          * Invoked after a view is drawn by a hardware renderer.
          * It is safe to invoke drawing commands from this method.
-         * 
+         *
          * @param canvas The Canvas used to render the view.
          */
         void onHardwarePostDraw(HardwareCanvas canvas);
@@ -458,9 +511,9 @@
     /**
      * Creates a new display list that can be used to record batches of
      * drawing operations.
-     * 
+     *
      * @param name The name of the display list, used for debugging purpose. May be null.
-     * 
+     *
      * @return A new display list.
      *
      * @hide
@@ -470,20 +523,20 @@
     /**
      * Creates a new hardware layer. A hardware layer built by calling this
      * method will be treated as a texture layer, instead of as a render target.
-     * 
+     *
      * @param isOpaque Whether the layer should be opaque or not
-     * 
+     *
      * @return A hardware layer
      */
     abstract HardwareLayer createHardwareLayer(boolean isOpaque);
 
     /**
      * Creates a new hardware layer.
-     * 
+     *
      * @param width The minimum width of the layer
      * @param height The minimum height of the layer
      * @param isOpaque Whether the layer should be opaque or not
-     * 
+     *
      * @return A hardware layer
      */
     abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
@@ -493,7 +546,7 @@
      * specified hardware layer.
      *
      * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
-     * 
+     *
      * @return A {@link SurfaceTexture}
      */
     abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
@@ -509,11 +562,11 @@
 
     /**
      * Detaches the specified functor from the current functor execution queue.
-     * 
+     *
      * @param functor The native functor to remove from the execution queue.
-     *                
-     * @see HardwareCanvas#callDrawGLFunction(int) 
-     * @see #attachFunctor(android.view.View.AttachInfo, int) 
+     *
+     * @see HardwareCanvas#callDrawGLFunction(int)
+     * @see #attachFunctor(android.view.View.AttachInfo, int)
      */
     abstract void detachFunctor(int functor);
 
@@ -540,12 +593,12 @@
      * @param width The width of the drawing surface.
      * @param height The height of the drawing surface.
      * @param surface The surface to hardware accelerate
-     *                
+     *
      * @return true if the surface was initialized, false otherwise. Returning
      *         false might mean that the surface was already initialized.
      */
     boolean initializeIfNeeded(int width, int height, Surface surface)
-            throws Surface.OutOfResourcesException {
+            throws OutOfResourcesException {
         if (isRequested()) {
             // We lost the gl context, so recreate it.
             if (!isEnabled()) {
@@ -567,10 +620,10 @@
 
     /**
      * Creates a hardware renderer using OpenGL.
-     * 
+     *
      * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
      * @param translucent True if the surface is translucent, false otherwise
-     * 
+     *
      * @return A hardware renderer backed by OpenGL.
      */
     static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
@@ -585,7 +638,7 @@
      * Invoke this method when the system is running out of memory. This
      * method will attempt to recover as much memory as possible, based on
      * the specified hint.
-     * 
+     *
      * @param level Hint about the amount of memory that should be trimmed,
      *              see {@link android.content.ComponentCallbacks}
      */
@@ -598,7 +651,7 @@
      * Starts the process of trimming memory. Usually this call will setup
      * hardware rendering context and reclaim memory.Extra cleanup might
      * be required by calling {@link #endTrimMemory()}.
-     * 
+     *
      * @param level Hint about the amount of memory that should be trimmed,
      *              see {@link android.content.ComponentCallbacks}
      */
@@ -616,7 +669,7 @@
 
     /**
      * Indicates whether hardware acceleration is currently enabled.
-     * 
+     *
      * @return True if hardware acceleration is in use, false otherwise.
      */
     boolean isEnabled() {
@@ -625,7 +678,7 @@
 
     /**
      * Indicates whether hardware acceleration is currently enabled.
-     * 
+     *
      * @param enabled True if the hardware renderer is in use, false otherwise.
      */
     void setEnabled(boolean enabled) {
@@ -635,7 +688,7 @@
     /**
      * Indicates whether hardware acceleration is currently request but not
      * necessarily enabled yet.
-     * 
+     *
      * @return True if requested, false otherwise.
      */
     boolean isRequested() {
@@ -645,7 +698,7 @@
     /**
      * Indicates whether hardware acceleration is currently requested but not
      * necessarily enabled yet.
-     * 
+     *
      * @return True to request hardware acceleration, false otherwise.
      */
     void setRequested(boolean requested) {
@@ -762,6 +815,17 @@
         private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
         private static final int PROFILE_DRAW_DP_PER_MS = 7;
 
+        private static final String[] VISUALIZERS = {
+                PROFILE_PROPERTY_VISUALIZE_BARS,
+                PROFILE_PROPERTY_VISUALIZE_LINES
+        };
+
+        private static final String[] OVERDRAW = {
+                OVERDRAW_PROPERTY_SHOW,
+                OVERDRAW_PROPERTY_COUNT
+        };
+        private static final int OVERDRAW_TYPE_COUNT = 1;
+
         static EGL10 sEgl;
         static EGLDisplay sEglDisplay;
         static EGLConfig sEglConfig;
@@ -775,7 +839,7 @@
         Thread mEglThread;
 
         EGLSurface mEglSurface;
-        
+
         GL mGl;
         HardwareCanvas mCanvas;
 
@@ -807,7 +871,9 @@
         Paint mProfilePaint;
 
         boolean mDebugDirtyRegions;
-        boolean mShowOverdraw;
+        int mDebugOverdraw = -1;
+        HardwareLayer mDebugOverdrawLayer;
+        Paint mDebugOverdrawPaint;
 
         final int mGlVersion;
         final boolean mTranslucent;
@@ -819,6 +885,8 @@
         private final int[] mSurfaceSize = new int[2];
         private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
 
+        private long mDrawDelta = Long.MAX_VALUE;
+
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
             mTranslucent = translucent;
@@ -826,18 +894,13 @@
             loadSystemProperties(null);
         }
 
-        private static final String[] VISUALIZERS = {
-                PROFILE_PROPERTY_VISUALIZE_BARS,
-                PROFILE_PROPERTY_VISUALIZE_LINES
-        };
-
         @Override
         boolean loadSystemProperties(Surface surface) {
             boolean value;
             boolean changed = false;
 
             String profiling = SystemProperties.get(PROFILE_PROPERTY);
-            int graphType = Arrays.binarySearch(VISUALIZERS, profiling);
+            int graphType = search(VISUALIZERS, profiling);
             value = graphType >= 0;
 
             if (graphType != mProfileVisualizerType) {
@@ -894,11 +957,19 @@
                 }
             }
 
-            value = SystemProperties.getBoolean(
-                    HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false);
-            if (value != mShowOverdraw) {
+            String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
+            int debugOverdraw = search(OVERDRAW, overdraw);
+            if (debugOverdraw != mDebugOverdraw) {
                 changed = true;
-                mShowOverdraw = value;
+                mDebugOverdraw = debugOverdraw;
+
+                if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
+                    if (mDebugOverdrawLayer != null) {
+                        mDebugOverdrawLayer.destroy();
+                        mDebugOverdrawLayer = null;
+                        mDebugOverdrawPaint = null;
+                    }
+                }
             }
 
             if (nLoadProperties()) {
@@ -908,6 +979,13 @@
             return changed;
         }
 
+        private static int search(String[] values, String value) {
+            for (int i = 0; i < values.length; i++) {
+                if (values[i].equals(value)) return i;
+            }
+            return -1;
+        }
+
         @Override
         void dumpGfxInfo(PrintWriter pw) {
             if (mProfileEnabled) {
@@ -968,15 +1046,15 @@
             if (fallback) {
                 // we'll try again if it was context lost
                 setRequested(false);
-                Log.w(LOG_TAG, "Mountain View, we've had a problem here. " 
+                Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
                         + "Switching back to software rendering.");
             }
         }
 
         @Override
-        boolean initialize(Surface surface) throws Surface.OutOfResourcesException {
+        boolean initialize(Surface surface) throws OutOfResourcesException {
             if (isRequested() && !isEnabled()) {
-                initializeEgl();
+                boolean contextCreated = initializeEgl();
                 mGl = createEglSurface(surface);
                 mDestroyed = false;
 
@@ -991,6 +1069,10 @@
                             mCanvas.setName(mName);
                         }
                         setEnabled(true);
+
+                        if (contextCreated) {
+                            initAtlas();
+                        }
                     }
 
                     return mCanvas != null;
@@ -998,9 +1080,9 @@
             }
             return false;
         }
-        
+
         @Override
-        void updateSurface(Surface surface) throws Surface.OutOfResourcesException {
+        void updateSurface(Surface surface) throws OutOfResourcesException {
             if (isRequested() && isEnabled()) {
                 createEglSurface(surface);
             }
@@ -1010,19 +1092,19 @@
 
         abstract int[] getConfig(boolean dirtyRegions);
 
-        void initializeEgl() {
+        boolean initializeEgl() {
             synchronized (sEglLock) {
                 if (sEgl == null && sEglConfig == null) {
                     sEgl = (EGL10) EGLContext.getEGL();
-                    
+
                     // Get to the default display.
                     sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-                    
+
                     if (sEglDisplay == EGL_NO_DISPLAY) {
                         throw new RuntimeException("eglGetDisplay failed "
                                 + GLUtils.getEGLErrorString(sEgl.eglGetError()));
                     }
-                    
+
                     // We can now initialize EGL for that display
                     int[] version = new int[2];
                     if (!sEgl.eglInitialize(sEglDisplay, version)) {
@@ -1043,7 +1125,10 @@
             if (mEglContext == null) {
                 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
                 sEglContextStorage.set(createManagedContext(mEglContext));
+                return true;
             }
+
+            return false;
         }
 
         private EGLConfig loadEglConfig() {
@@ -1133,7 +1218,7 @@
             Log.d(LOG_TAG, "  CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
         }
 
-        GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException {
+        GL createEglSurface(Surface surface) throws OutOfResourcesException {
             // Check preconditions.
             if (sEgl == null) {
                 throw new RuntimeException("egl not initialized");
@@ -1145,7 +1230,7 @@
                 throw new RuntimeException("eglConfig not initialized");
             }
             if (Thread.currentThread() != mEglThread) {
-                throw new IllegalStateException("HardwareRenderer cannot be used " 
+                throw new IllegalStateException("HardwareRenderer cannot be used "
                         + "from multiple threads");
             }
 
@@ -1181,6 +1266,7 @@
         }
 
         abstract void initCaches();
+        abstract void initAtlas();
 
         EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
             int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
@@ -1193,6 +1279,7 @@
                         "Could not create an EGL context. eglCreateContext failed with error: " +
                         GLUtils.getEGLErrorString(sEgl.eglGetError()));
             }
+
             return context;
         }
 
@@ -1216,7 +1303,10 @@
 
         void destroySurface() {
             if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
-                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+                if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
+                    sEgl.eglMakeCurrent(sEglDisplay,
+                            EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+                }
                 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
                 mEglSurface = null;
             }
@@ -1272,7 +1362,7 @@
 
         @Override
         boolean validate() {
-            return checkCurrent() != SURFACE_STATE_ERROR;
+            return checkRenderContext() != SURFACE_STATE_ERROR;
         }
 
         @Override
@@ -1306,8 +1396,8 @@
 
         boolean canDraw() {
             return mGl != null && mCanvas != null;
-        }        
-        
+        }
+
         int onPreDraw(Rect dirty) {
             return DisplayList.STATUS_DONE;
         }
@@ -1325,8 +1415,7 @@
                     return;
                 }
 
-                final int surfaceState = checkCurrent();
-                if (surfaceState != SURFACE_STATE_ERROR) {
+                if (checkRenderContext() != SURFACE_STATE_ERROR) {
                     int status = mCanvas.invokeFunctors(mRedrawClip);
                     handleFunctorStatus(attachInfo, status);
                 }
@@ -1345,7 +1434,8 @@
 
                 view.mPrivateFlags |= View.PFLAG_DRAWN;
 
-                final int surfaceState = checkCurrent();
+                // We are already on the correct thread
+                final int surfaceState = checkRenderContextUnsafe();
                 if (surfaceState != SURFACE_STATE_ERROR) {
                     HardwareCanvas canvas = mCanvas;
                     attachInfo.mHardwareCanvas = canvas;
@@ -1358,9 +1448,17 @@
 
                     DisplayList displayList = buildDisplayList(view, canvas);
 
+                    // buildDisplayList() calls into user code which can cause
+                    // an eglMakeCurrent to happen with a different surface/context.
+                    // We must therefore check again here.
+                    if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
+                        return;
+                    }
+
                     int saveCount = 0;
                     int status = DisplayList.STATUS_DONE;
 
+                    long start = getSystemTime();
                     try {
                         status = prepareFrame(dirty);
 
@@ -1380,10 +1478,15 @@
                         canvas.restoreToCount(saveCount);
                         view.mRecreateDisplayList = false;
 
-                        mFrameCount++;
+                        mDrawDelta = getSystemTime() - start;
 
-                        debugDirtyRegions(dirty, canvas);
-                        drawProfileData(attachInfo);
+                        if (mDrawDelta > 0) {
+                            mFrameCount++;
+
+                            debugOverdraw(attachInfo, dirty, canvas, displayList);
+                            debugDirtyRegions(dirty, canvas);
+                            drawProfileData(attachInfo);
+                        }
                     }
 
                     onPostDraw();
@@ -1399,7 +1502,63 @@
             }
         }
 
+        abstract void countOverdraw(HardwareCanvas canvas);
+        abstract float getOverdraw(HardwareCanvas canvas);
+
+        private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
+                HardwareCanvas canvas, DisplayList displayList) {
+
+            if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
+                if (mDebugOverdrawLayer == null) {
+                    mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
+                } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
+                        mDebugOverdrawLayer.getHeight() != mHeight) {
+                    mDebugOverdrawLayer.resize(mWidth, mHeight);
+                }
+
+                if (!mDebugOverdrawLayer.isValid()) {
+                    mDebugOverdraw = -1;
+                    return;
+                }
+
+                HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
+                countOverdraw(layerCanvas);
+                final int restoreCount = layerCanvas.save();
+                layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
+                layerCanvas.restoreToCount(restoreCount);
+                mDebugOverdrawLayer.end(canvas);
+
+                float overdraw = getOverdraw(layerCanvas);
+                DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
+
+                drawOverdrawCounter(canvas, overdraw, metrics.density);
+            }
+        }
+
+        private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
+            final String text = String.format("%.2fx", overdraw);
+            final Paint paint = setupPaint(density);
+            // HSBtoColor will clamp the values in the 0..1 range
+            paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
+
+            canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
+        }
+
+        private Paint setupPaint(float density) {
+            if (mDebugOverdrawPaint == null) {
+                mDebugOverdrawPaint = new Paint();
+                mDebugOverdrawPaint.setAntiAlias(true);
+                mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
+                mDebugOverdrawPaint.setTextSize(density * 20.0f);
+            }
+            return mDebugOverdrawPaint;
+        }
+
         private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
+            if (mDrawDelta <= 0) {
+                return view.mDisplayList;
+            }
+
             view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                     == View.PFLAG_INVALIDATED;
             view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
@@ -1572,21 +1731,39 @@
         }
 
         /**
-         * Ensures the current EGL context is the one we expect.
-         * 
+         * Ensures the current EGL context and surface are the ones we expect.
+         * This method throws an IllegalStateException if invoked from a thread
+         * that did not initialize EGL.
+         *
          * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
          *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
          *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+         *
+         * @see #checkRenderContextUnsafe()
          */
-        int checkCurrent() {
+        int checkRenderContext() {
             if (mEglThread != Thread.currentThread()) {
                 throw new IllegalStateException("Hardware acceleration can only be used with a " +
                         "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
                         "Current thread: " + Thread.currentThread());
             }
 
-            if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
-                    !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
+            return checkRenderContextUnsafe();
+        }
+
+        /**
+         * Ensures the current EGL context and surface are the ones we expect.
+         * This method does not check the current thread.
+         *
+         * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
+         *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
+         *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+         *
+         * @see #checkRenderContext()
+         */
+        private int checkRenderContextUnsafe() {
+            if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
+                    !mEglContext.equals(sEgl.eglGetCurrentContext())) {
                 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                     Log.e(LOG_TAG, "eglMakeCurrent failed " +
                             GLUtils.getEGLErrorString(sEgl.eglGetError()));
@@ -1788,13 +1965,43 @@
 
         @Override
         void initCaches() {
-            GLES20Canvas.initCaches();
+            if (GLES20Canvas.initCaches()) {
+                // Caches were (re)initialized, rebind atlas
+                initAtlas();
+            }
+        }
+
+        @Override
+        void initAtlas() {
+            IBinder binder = ServiceManager.getService("assetatlas");
+            if (binder == null) return;
+
+            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+            try {
+                if (atlas.isCompatible(android.os.Process.myPpid())) {
+                    GraphicBuffer buffer = atlas.getBuffer();
+                    if (buffer != null) {
+                        int[] map = atlas.getMap();
+                        if (map != null) {
+                            GLES20Canvas.initAtlas(buffer, map);
+                        }
+                        // If IAssetAtlas is not the same class as the IBinder
+                        // we are using a remote service and we can safely
+                        // destroy the graphic buffer
+                        if (atlas.getClass() != binder.getClass()) {
+                            buffer.destroy();
+                        }
+                    }
+                }
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Could not acquire atlas", e);
+            }
         }
 
         @Override
         boolean canDraw() {
             return super.canDraw() && mGlCanvas != null;
-        }                
+        }
 
         @Override
         int onPreDraw(Rect dirty) {
@@ -1970,6 +2177,16 @@
         }
 
         @Override
+        void cancelLayerUpdate(HardwareLayer layer) {
+            mGlCanvas.cancelLayerUpdate(layer);
+        }
+
+        @Override
+        void flushLayerUpdates() {
+            mGlCanvas.flushLayerUpdates();
+        }
+
+        @Override
         public DisplayList createDisplayList(String name) {
             return new GLES20DisplayList(name);
         }
@@ -1985,6 +2202,16 @@
         }
 
         @Override
+        void countOverdraw(HardwareCanvas canvas) {
+            ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
+        }
+
+        @Override
+        float getOverdraw(HardwareCanvas canvas) {
+            return ((GLES20Canvas) canvas).getOverdraw();
+        }
+
+        @Override
         public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
             return ((GLES20TextureLayer) layer).getSurfaceTexture();
         }
@@ -1996,8 +2223,7 @@
 
         @Override
         boolean safelyRun(Runnable action) {
-            boolean needsContext = true;
-            if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
+            boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
 
             if (needsContext) {
                 Gl20RendererEglContext managedContext =
diff --git a/core/java/android/view/IApplicationToken.aidl b/core/java/android/view/IApplicationToken.aidl
index 5f0600f..633b40f 100644
--- a/core/java/android/view/IApplicationToken.aidl
+++ b/core/java/android/view/IApplicationToken.aidl
@@ -23,7 +23,7 @@
     void windowsDrawn();
     void windowsVisible();
     void windowsGone();
-    boolean keyDispatchingTimedOut();
+    boolean keyDispatchingTimedOut(String reason);
     long getKeyDispatchingTimeout();
 }
 
diff --git a/core/java/android/view/IAssetAtlas.aidl b/core/java/android/view/IAssetAtlas.aidl
new file mode 100644
index 0000000..5f1e238
--- /dev/null
+++ b/core/java/android/view/IAssetAtlas.aidl
@@ -0,0 +1,54 @@
+/**
+ * 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 android.view;
+
+import android.view.GraphicBuffer;
+
+/**
+ * Programming interface to the system assets atlas. This atlas, when
+ * present, holds preloaded drawable in a single, shareable graphics
+ * buffer. This allows multiple processes to share the same data to
+ * save up on memory.
+ *
+ * @hide
+ */
+interface IAssetAtlas {
+    /**
+     * Indicates whether the atlas is compatible with the specified
+     * parent process id. If the atlas' ppid does not match, this
+     * method will return false.
+     */
+    boolean isCompatible(int ppid);
+
+    /**
+     * Returns the atlas buffer (texture) or null if the atlas is
+     * not available yet.
+     */
+    GraphicBuffer getBuffer();
+
+    /**
+     * Returns the map of the bitmaps stored in the atlas or null
+     * if the atlas is not available yet.
+     *
+     * Each bitmap is represented by several entries in the array:
+     * int0: SkBitmap*, the native bitmap object
+     * int1: x position
+     * int2: y position
+     * int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+     */
+    int[] getMap();
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8ed4a86..caf9c8b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -71,17 +71,14 @@
 
     void setOverscan(int displayId, int left, int top, int right, int bottom);
 
-    // Is the device configured to have a full system bar for larger screens?
-    boolean hasSystemNavBar();
-
     // These can only be called when holding the MANAGE_APP_TOKENS permission.
     void pauseKeyDispatching(IBinder token);
     void resumeKeyDispatching(IBinder token);
     void setEventDispatching(boolean enabled);
     void addWindowToken(IBinder token, int type);
     void removeWindowToken(IBinder token);
-    void addAppToken(int addPos, IApplicationToken token,
-            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked);
+    void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId);
     void setAppGroupId(IBinder token, int groupId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
@@ -97,15 +94,12 @@
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
-            int icon, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
+            int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppWillBeHidden(IBinder token);
     void setAppVisibility(IBinder token, boolean visible);
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
     void removeAppToken(IBinder token);
-    void moveAppToken(int index, IBinder token);
-    void moveAppTokensToTop(in List<IBinder> tokens);
-    void moveAppTokensToBottom(in List<IBinder> tokens);
 
     // Re-evaluate the current orientation from the caller's state.
     // If there is a change, the new Configuration is returned and the
@@ -255,12 +249,6 @@
     boolean isSafeModeEnabled();
 
     /**
-     * Tell keyguard to show the assistant (Intent.ACTION_ASSIST) after asking for the user's
-     * credentials.
-     */
-    void showAssistant();
-
-    /**
      * Sets the display magnification callbacks. These callbacks notify
      * the client for contextual changes related to display magnification.
      *
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 2a761c1..e829116 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -44,13 +44,17 @@
 public final class InputDevice implements Parcelable {
     private final int mId;
     private final int mGeneration;
+    private final int mControllerNumber;
     private final String mName;
+    private final int mVendorId;
+    private final int mProductId;
     private final String mDescriptor;
     private final boolean mIsExternal;
     private final int mSources;
     private final int mKeyboardType;
     private final KeyCharacterMap mKeyCharacterMap;
     private final boolean mHasVibrator;
+    private final boolean mHasButtonUnderPad;
     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
     private Vibrator mVibrator; // guarded by mMotionRanges during initialization
@@ -341,30 +345,38 @@
     };
 
     // Called by native code.
-    private InputDevice(int id, int generation, String name, String descriptor,
-            boolean isExternal, int sources,
-            int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator) {
+    private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
+            int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
+            KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasButtonUnderPad) {
         mId = id;
         mGeneration = generation;
+        mControllerNumber = controllerNumber;
         mName = name;
+        mVendorId = vendorId;
+        mProductId = productId;
         mDescriptor = descriptor;
         mIsExternal = isExternal;
         mSources = sources;
         mKeyboardType = keyboardType;
         mKeyCharacterMap = keyCharacterMap;
         mHasVibrator = hasVibrator;
+        mHasButtonUnderPad = hasButtonUnderPad;
     }
 
     private InputDevice(Parcel in) {
         mId = in.readInt();
         mGeneration = in.readInt();
+        mControllerNumber = in.readInt();
         mName = in.readString();
+        mVendorId = in.readInt();
+        mProductId = in.readInt();
         mDescriptor = in.readString();
         mIsExternal = in.readInt() != 0;
         mSources = in.readInt();
         mKeyboardType = in.readInt();
         mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
         mHasVibrator = in.readInt() != 0;
+        mHasButtonUnderPad = in.readInt() != 0;
 
         for (;;) {
             int axis = in.readInt();
@@ -410,6 +422,25 @@
     }
 
     /**
+     * The controller number for a given input device.
+     * <p>
+     * Each gamepad or joystick is given a unique, positive controller number when initially
+     * configured by the system. This number may change due to events such as device disconnects /
+     * reconnects or user initiated reassignment. Any change in number will trigger an event that
+     * can be observed by registering an {@link InputManager.InputDeviceListener}.
+     * </p>
+     * <p>
+     * All input devices which are not gamepads or joysticks will be assigned a controller number
+     * of 0.
+     * </p>
+     *
+     * @return The controller number of the device.
+     */
+    public int getControllerNumber() {
+        return mControllerNumber;
+    }
+
+    /**
      * Gets a generation number for this input device.
      * The generation number is incremented whenever the device is reconfigured and its
      * properties may have changed.
@@ -423,6 +454,33 @@
     }
 
     /**
+     * Gets the vendor id for the given device, if available.
+     * <p>
+     * A vendor id uniquely identifies the company who manufactured the device. A value of 0 will
+     * be assigned where a vendor id is not available.
+     * </p>
+     *
+     * @return The vendor id of a given device
+     */
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    /**
+     * Gets the product id for the given device, if available.
+     * <p>
+     * A product id uniquely identifies which product within the address space of a given vendor,
+     * identified by the device's vendor id. A value of 0 will be assigned where a product id is
+     * not available.
+     * </p>
+     *
+     * @return The product id of a given device
+     */
+    public int getProductId() {
+        return mProductId;
+    }
+
+    /**
      * Gets the input device descriptor, which is a stable identifier for an input device.
      * <p>
      * An input device descriptor uniquely identifies an input device.  Its value
@@ -521,6 +579,16 @@
     }
 
     /**
+     * Gets whether the device is capable of producing the list of keycodes.
+     * @param keys The list of android keycodes to check for.
+     * @return An array of booleans where each member specifies whether the device is capable of
+     * generating the keycode given by the corresponding value at the same index in the keys array.
+     */
+    public boolean[] hasKeys(int... keys) {
+        return InputManager.getInstance().deviceHasKeys(mId, keys);
+    }
+
+    /**
      * Gets information about the range of values for a particular {@link MotionEvent} axis.
      * If the device supports multiple sources, the same axis may have different meanings
      * for each source.  Returns information about the first axis found for any source.
@@ -612,6 +680,15 @@
     }
 
     /**
+     * Reports whether the device has a button under its touchpad
+     * @return Whether the device has a button under its touchpad
+     * @hide
+     */
+    public boolean hasButtonUnderPad() {
+        return mHasButtonUnderPad;
+    }
+
+    /**
      * Provides information about the range of values for a particular {@link MotionEvent} axis.
      *
      * @see InputDevice#getMotionRange(int)
@@ -726,13 +803,17 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mId);
         out.writeInt(mGeneration);
+        out.writeInt(mControllerNumber);
         out.writeString(mName);
+        out.writeInt(mVendorId);
+        out.writeInt(mProductId);
         out.writeString(mDescriptor);
         out.writeInt(mIsExternal ? 1 : 0);
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
         mKeyCharacterMap.writeToParcel(out, flags);
         out.writeInt(mHasVibrator ? 1 : 0);
+        out.writeInt(mHasButtonUnderPad ? 1 : 0);
 
         final int numRanges = mMotionRanges.size();
         for (int i = 0; i < numRanges; i++) {
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 07a937c..1ecdf30 100644
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -70,6 +70,7 @@
      * Gets the source of the event.
      * 
      * @return The event source or {@link InputDevice#SOURCE_UNKNOWN} if unknown.
+     * @see InputDevice#getSources
      */
     public abstract int getSource();
 
diff --git a/core/java/android/view/InputFilter.java b/core/java/android/view/InputFilter.java
index c25b87b..4aba30c 100644
--- a/core/java/android/view/InputFilter.java
+++ b/core/java/android/view/InputFilter.java
@@ -40,7 +40,7 @@
  * <li>Input events are then asynchronously delivered to the input filter's
  * {@link #onInputEvent(InputEvent)} method instead of being enqueued for dispatch to
  * applications as usual.  The input filter only receives input events that were
- * generated by input device; the input filter will not receive input events that were
+ * generated by an input device; the input filter will not receive input events that were
  * injected into the system by other means, such as by instrumentation.</li>
  * <li>The input filter processes and optionally transforms the stream of events.  For example,
  * it may transform a sequence of motion events representing an accessibility gesture into
@@ -68,7 +68,7 @@
  * The input filter must take into account the fact that the input events coming from different
  * devices or even different sources all consist of distinct streams of input.
  * Use {@link InputEvent#getDeviceId()} and {@link InputEvent#getSource()} to identify
- * the source of the event and its semantics.  There are be multiple sources of keys,
+ * the source of the event and its semantics.  There may be multiple sources of keys,
  * touches and other input: they must be kept separate.
  * </p>
  * <h3>Policy flags</h3>
@@ -88,7 +88,7 @@
  * The input filter should clear its internal state about the gesture and then send key or
  * motion events to the dispatcher to cancel any keys or pointers that are down.
  * </p><p>
- * Corollary: Events that set sent to the dispatcher should usually include the
+ * Corollary: Events that get sent to the dispatcher should usually include the
  * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag.  Otherwise, they will be dropped!
  * </p><p>
  * It may be prudent to disable automatic key repeating for synthetic key events
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 5db3909..5a5fc10 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -629,8 +629,11 @@
     /** Key code constant: Brightness Up key.
      * Adjusts the screen brightness up. */
     public static final int KEYCODE_BRIGHTNESS_UP   = 221;
+    /** Key code constant: Audio Track key
+     * Switches the audio tracks. */
+    public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222;
 
-    private static final int LAST_KEYCODE           = KEYCODE_BRIGHTNESS_UP;
+    private static final int LAST_KEYCODE           = KEYCODE_MEDIA_AUDIO_TRACK;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -874,6 +877,7 @@
         names.append(KEYCODE_ASSIST, "KEYCODE_ASSIST");
         names.append(KEYCODE_BRIGHTNESS_DOWN, "KEYCODE_BRIGHTNESS_DOWN");
         names.append(KEYCODE_BRIGHTNESS_UP, "KEYCODE_BRIGHTNESS_UP");
+        names.append(KEYCODE_MEDIA_AUDIO_TRACK, "KEYCODE_MEDIA_AUDIO_TRACK");
     };
 
     // Symbolic names of all metakeys in bit order from least significant to most significant.
@@ -1833,6 +1837,19 @@
         }
     }
 
+    /** Whether key will, by default, trigger a click on the focused view.
+     * @hide
+     */
+    public static final boolean isConfirmKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_ENTER:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     public final int getDeviceId() {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ee36097..db577f3 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3003,13 +3003,13 @@
     }
 
     /**
-     * Returns a string that represents the symbolic name of the specified action
+     * Returns a string that represents the symbolic name of the specified unmasked action
      * such as "ACTION_DOWN", "ACTION_POINTER_DOWN(3)" or an equivalent numeric constant
      * such as "35" if unknown.
      *
-     * @param action The action.
+     * @param action The unmasked action.
      * @return The symbolic name of the specified action.
-     * @hide
+     * @see #getAction()
      */
     public static String actionToString(int action) {
         switch (action) {
@@ -3047,7 +3047,7 @@
      * Returns a string that represents the symbolic name of the specified axis
      * such as "AXIS_X" or an equivalent numeric constant such as "42" if unknown.
      *
-     * @param axis The axis
+     * @param axis The axis.
      * @return The symbolic name of the specified axis.
      */
     public static String axisToString(int axis) {
@@ -3061,7 +3061,7 @@
      *
      * @param symbolicName The symbolic name of the axis.
      * @return The axis or -1 if not found.
-     * @see KeyEvent#keycodeToString(int)
+     * @see KeyEvent#keyCodeToString(int)
      */
     public static int axisFromString(String symbolicName) {
         if (symbolicName == null) {
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 51c5c7b..f36c78f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Build;
+import android.os.Handler;
 import android.os.SystemClock;
 import android.util.FloatMath;
 
@@ -128,6 +130,8 @@
     private float mFocusX;
     private float mFocusY;
 
+    private boolean mQuickScaleEnabled;
+
     private float mCurrSpan;
     private float mPrevSpan;
     private float mInitialSpan;
@@ -148,9 +152,15 @@
     private int mTouchHistoryDirection;
     private long mTouchHistoryLastAcceptedTime;
     private int mTouchMinMajor;
+    private MotionEvent mDoubleTapEvent;
+    private int mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+    private final Handler mHandler;
 
     private static final long TOUCH_STABILIZE_TIME = 128; // ms
-    private static final int TOUCH_MIN_MAJOR = 48; // dp
+    private static final int DOUBLE_TAP_MODE_NONE = 0;
+    private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;
+    private static final float SCALE_FACTOR = .5f;
+
 
     /**
      * Consistency verifier for debugging purposes.
@@ -158,8 +168,37 @@
     private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
                     new InputEventConsistencyVerifier(this, 0) : null;
+    private GestureDetector mGestureDetector;
 
+    private boolean mEventBeforeOrAboveStartingGestureEvent;
+
+    /**
+     * Creates a ScaleGestureDetector with the supplied listener.
+     * You may only use this constructor from a {@link android.os.Looper Looper} thread.
+     *
+     * @param context the application's context
+     * @param listener the listener invoked for all the callbacks, this must
+     * not be null.
+     *
+     * @throws NullPointerException if {@code listener} is null.
+     */
     public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
+        this(context, listener, null);
+    }
+
+    /**
+     * Creates a ScaleGestureDetector with the supplied listener.
+     * @see android.os.Handler#Handler()
+     *
+     * @param context the application's context
+     * @param listener the listener invoked for all the callbacks, this must
+     * not be null.
+     * @param handler the handler to use for running deferred listener events.
+     *
+     * @throws NullPointerException if {@code listener} is null.
+     */
+    public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
+                                Handler handler) {
         mContext = context;
         mListener = listener;
         mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
@@ -167,8 +206,12 @@
         final Resources res = context.getResources();
         mTouchMinMajor = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.config_minScalingTouchMajor);
-        mMinSpan = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_minScalingSpan);
+        mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
+        mHandler = handler;
+        // Quick scale is enabled by default after JB_MR2
+        if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            setQuickScaleEnabled(true);
+        }
     }
 
     /**
@@ -263,8 +306,14 @@
 
         final int action = event.getActionMasked();
 
+        // Forward the event to check for double tap gesture
+        if (mQuickScaleEnabled) {
+            mGestureDetector.onTouchEvent(event);
+        }
+
         final boolean streamComplete = action == MotionEvent.ACTION_UP ||
                 action == MotionEvent.ACTION_CANCEL;
+
         if (action == MotionEvent.ACTION_DOWN || streamComplete) {
             // Reset any scale in progress with the listener.
             // If it's an ACTION_DOWN we're beginning a new event stream.
@@ -273,6 +322,7 @@
                 mListener.onScaleEnd(this);
                 mInProgress = false;
                 mInitialSpan = 0;
+                mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
             }
 
             if (streamComplete) {
@@ -284,21 +334,37 @@
         final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
                 action == MotionEvent.ACTION_POINTER_UP ||
                 action == MotionEvent.ACTION_POINTER_DOWN;
+
+
         final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
         final int skipIndex = pointerUp ? event.getActionIndex() : -1;
 
         // Determine focal point
         float sumX = 0, sumY = 0;
         final int count = event.getPointerCount();
-        for (int i = 0; i < count; i++) {
-            if (skipIndex == i) continue;
-            sumX += event.getX(i);
-            sumY += event.getY(i);
-        }
         final int div = pointerUp ? count - 1 : count;
-        final float focusX = sumX / div;
-        final float focusY = sumY / div;
+        final float focusX;
+        final float focusY;
+        if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS) {
+            // In double tap mode, the focal pt is always where the double tap
+            // gesture started
+            focusX = mDoubleTapEvent.getX();
+            focusY = mDoubleTapEvent.getY();
+            if (event.getY() < focusY) {
+                mEventBeforeOrAboveStartingGestureEvent = true;
+            } else {
+                mEventBeforeOrAboveStartingGestureEvent = false;
+            }
+        } else {
+            for (int i = 0; i < count; i++) {
+                if (skipIndex == i) continue;
+                sumX += event.getX(i);
+                sumY += event.getY(i);
+            }
 
+            focusX = sumX / div;
+            focusY = sumY / div;
+        }
 
         addTouchHistory(event);
 
@@ -320,7 +386,12 @@
         // the focal point.
         final float spanX = devX * 2;
         final float spanY = devY * 2;
-        final float span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
+        final float span;
+        if (inDoubleTapMode()) {
+            span = spanY;
+        } else {
+            span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
+        }
 
         // Dispatch begin/end events as needed.
         // If the configuration changes, notify the app to reset its current state by beginning
@@ -328,17 +399,20 @@
         final boolean wasInProgress = mInProgress;
         mFocusX = focusX;
         mFocusY = focusY;
-        if (mInProgress && (span < mMinSpan || configChanged)) {
+        if (!inDoubleTapMode() && mInProgress && (span < mMinSpan || configChanged)) {
             mListener.onScaleEnd(this);
             mInProgress = false;
             mInitialSpan = span;
+            mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
         }
         if (configChanged) {
             mPrevSpanX = mCurrSpanX = spanX;
             mPrevSpanY = mCurrSpanY = spanY;
             mInitialSpan = mPrevSpan = mCurrSpan = span;
         }
-        if (!mInProgress && span >= mMinSpan &&
+
+        final int minSpan = inDoubleTapMode() ? mSpanSlop : mMinSpan;
+        if (!mInProgress && span >=  minSpan &&
                 (wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
             mPrevSpanX = mCurrSpanX = spanX;
             mPrevSpanY = mCurrSpanY = spanY;
@@ -354,6 +428,7 @@
             mCurrSpan = span;
 
             boolean updatePrev = true;
+
             if (mInProgress) {
                 updatePrev = mListener.onScale(this);
             }
@@ -369,6 +444,42 @@
         return true;
     }
 
+
+    private boolean inDoubleTapMode() {
+        return mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS;
+    }
+
+    /**
+     * Set whether the associated {@link OnScaleGestureListener} should receive onScale callbacks
+     * when the user performs a doubleTap followed by a swipe. Note that this is enabled by default
+     * if the app targets API 19 and newer.
+     * @param scales true to enable quick scaling, false to disable
+     */
+    public void setQuickScaleEnabled(boolean scales) {
+        mQuickScaleEnabled = scales;
+        if (mQuickScaleEnabled && mGestureDetector == null) {
+            GestureDetector.SimpleOnGestureListener gestureListener =
+                    new GestureDetector.SimpleOnGestureListener() {
+                        @Override
+                        public boolean onDoubleTap(MotionEvent e) {
+                            // Double tap: start watching for a swipe
+                            mDoubleTapEvent = e;
+                            mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
+                            return true;
+                        }
+                    };
+            mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler);
+        }
+    }
+
+  /**
+   * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+   * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+   */
+    public boolean isQuickScaleEnabled() {
+        return mQuickScaleEnabled;
+    }
+
     /**
      * Returns {@code true} if a scale gesture is in progress.
      */
@@ -472,6 +583,16 @@
      * @return The current scaling factor.
      */
     public float getScaleFactor() {
+        if (inDoubleTapMode()) {
+            // Drag is moving up; the further away from the gesture
+            // start, the smaller the span should be, the closer,
+            // the larger the span, and therefore the larger the scale
+            final boolean scaleUp =
+                    (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) ||
+                    (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan));
+            final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR);
+            return mPrevSpan <= 0 ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff);
+        }
         return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
     }
 
@@ -493,4 +614,4 @@
     public long getEventTime() {
         return mCurrTime;
     }
-}
+}
\ No newline at end of file
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ae4005b..1bfda2d 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -36,7 +36,7 @@
             throws OutOfResourcesException;
     private static native int nativeCreateFromSurfaceControl(int surfaceControlNativeObject);
 
-    private static native void nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)
+    private static native int nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)
             throws OutOfResourcesException;
     private static native void nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas);
 
@@ -71,8 +71,9 @@
     // Guarded state.
     final Object mLock = new Object(); // protects the native state
     private String mName;
-    int mNativeSurface; // package scope only for SurfaceControl access
-    private int mGenerationId; // incremented each time mNativeSurface changes
+    int mNativeObject; // package scope only for SurfaceControl access
+    private int mLockedObject;
+    private int mGenerationId; // incremented each time mNativeObject changes
     private final Canvas mCanvas = new CompatibleCanvas();
 
     // A matrix to scale the matrix set by application. This is set to null for
@@ -115,6 +116,7 @@
      *
      * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
      * Surface.
+     * @throws OutOfResourcesException if the surface could not be created.
      */
     public Surface(SurfaceTexture surfaceTexture) {
         if (surfaceTexture == null) {
@@ -123,12 +125,7 @@
 
         synchronized (mLock) {
             mName = surfaceTexture.toString();
-            try {
-                setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
-            } catch (OutOfResourcesException ex) {
-                // We can't throw OutOfResourcesException because it would be an API change.
-                throw new RuntimeException(ex);
-            }
+            setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
         }
     }
 
@@ -158,8 +155,8 @@
      */
     public void release() {
         synchronized (mLock) {
-            if (mNativeSurface != 0) {
-                nativeRelease(mNativeSurface);
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
                 setNativeObjectLocked(0);
             }
         }
@@ -183,8 +180,8 @@
      */
     public boolean isValid() {
         synchronized (mLock) {
-            if (mNativeSurface == 0) return false;
-            return nativeIsValid(mNativeSurface);
+            if (mNativeObject == 0) return false;
+            return nativeIsValid(mNativeObject);
         }
     }
 
@@ -210,7 +207,7 @@
     public boolean isConsumerRunningBehind() {
         synchronized (mLock) {
             checkNotReleasedLocked();
-            return nativeIsConsumerRunningBehind(mNativeSurface);
+            return nativeIsConsumerRunningBehind(mNativeObject);
         }
     }
 
@@ -228,12 +225,22 @@
      * The caller may also pass <code>null</code> instead, in the case where the
      * entire surface should be redrawn.
      * @return A canvas for drawing into the surface.
+     *
+     * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
+     * @throws OutOfResourcesException If the canvas cannot be locked.
      */
     public Canvas lockCanvas(Rect inOutDirty)
-            throws OutOfResourcesException, IllegalArgumentException {
+            throws Surface.OutOfResourcesException, IllegalArgumentException {
         synchronized (mLock) {
             checkNotReleasedLocked();
-            nativeLockCanvas(mNativeSurface, mCanvas, inOutDirty);
+            if (mLockedObject != 0) {
+                // Ideally, nativeLockCanvas() would throw in this situation and prevent the
+                // double-lock, but that won't happen if mNativeObject was updated.  We can't
+                // abandon the old mLockedObject because it might still be in use, so instead
+                // we just refuse to re-lock the Surface.
+                throw new IllegalStateException("Surface was already locked");
+            }
+            mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
             return mCanvas;
         }
     }
@@ -252,11 +259,21 @@
 
         synchronized (mLock) {
             checkNotReleasedLocked();
-            nativeUnlockCanvasAndPost(mNativeSurface, canvas);
+            if (mNativeObject != mLockedObject) {
+                Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
+                        Integer.toHexString(mNativeObject) + ") != mLockedObject (0x" +
+                        Integer.toHexString(mLockedObject) +")");
+            }
+            if (mLockedObject == 0) {
+                throw new IllegalStateException("Surface was not locked");
+            }
+            nativeUnlockCanvasAndPost(mLockedObject, canvas);
+            nativeRelease(mLockedObject);
+            mLockedObject = 0;
         }
     }
 
-    /** 
+    /**
      * @deprecated This API has been removed and is not supported.  Do not use.
      */
     @Deprecated
@@ -298,8 +315,8 @@
         int newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
 
         synchronized (mLock) {
-            if (mNativeSurface != 0) {
-                nativeRelease(mNativeSurface);
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
             }
             setNativeObjectLocked(newNativeObject);
         }
@@ -319,13 +336,13 @@
         if (other != this) {
             final int newPtr;
             synchronized (other.mLock) {
-                newPtr = other.mNativeSurface;
+                newPtr = other.mNativeObject;
                 other.setNativeObjectLocked(0);
             }
 
             synchronized (mLock) {
-                if (mNativeSurface != 0) {
-                    nativeRelease(mNativeSurface);
+                if (mNativeObject != 0) {
+                    nativeRelease(mNativeObject);
                 }
                 setNativeObjectLocked(newPtr);
             }
@@ -343,8 +360,12 @@
         }
 
         synchronized (mLock) {
+            // nativeReadFromParcel() will either return mNativeObject, or
+            // create a new native Surface and return it after reducing
+            // the reference count on mNativeObject.  Either way, it is
+            // not necessary to call nativeRelease() here.
             mName = source.readString();
-            setNativeObjectLocked(nativeReadFromParcel(mNativeSurface, source));
+            setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
         }
     }
 
@@ -355,7 +376,7 @@
         }
         synchronized (mLock) {
             dest.writeString(mName);
-            nativeWriteToParcel(mNativeSurface, dest);
+            nativeWriteToParcel(mNativeObject, dest);
         }
         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
             release();
@@ -365,32 +386,35 @@
     @Override
     public String toString() {
         synchronized (mLock) {
-            return "Surface(name=" + mName + ")";
+            return "Surface(name=" + mName + ")/@0x" +
+                    Integer.toHexString(System.identityHashCode(this));
         }
     }
 
     private void setNativeObjectLocked(int ptr) {
-        if (mNativeSurface != ptr) {
-            if (mNativeSurface == 0 && ptr != 0) {
+        if (mNativeObject != ptr) {
+            if (mNativeObject == 0 && ptr != 0) {
                 mCloseGuard.open("release");
-            } else if (mNativeSurface != 0 && ptr == 0) {
+            } else if (mNativeObject != 0 && ptr == 0) {
                 mCloseGuard.close();
             }
-            mNativeSurface = ptr;
+            mNativeObject = ptr;
             mGenerationId += 1;
         }
     }
 
     private void checkNotReleasedLocked() {
-        if (mNativeSurface == 0) {
+        if (mNativeObject == 0) {
             throw new IllegalStateException("Surface has already been released.");
         }
     }
 
     /**
-     * Exception thrown when a surface couldn't be created or resized.
+     * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
+     * when a SurfaceTexture could not successfully be allocated.
      */
-    public static class OutOfResourcesException extends Exception {
+    @SuppressWarnings("serial")
+    public static class OutOfResourcesException extends RuntimeException {
         public OutOfResourcesException() {
         }
         public OutOfResourcesException(String name) {
@@ -463,7 +487,7 @@
         public void getMatrix(Matrix m) {
             super.getMatrix(m);
             if (mOrigMatrix == null) {
-                mOrigMatrix = new Matrix(); 
+                mOrigMatrix = new Matrix();
             }
             mOrigMatrix.set(m);
         }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c6da84f..b22d5cf 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -24,6 +24,7 @@
 import android.os.IBinder;
 import android.os.SystemProperties;
 import android.util.Log;
+import android.view.Surface.OutOfResourcesException;
 
 /**
  * SurfaceControl
@@ -59,13 +60,14 @@
 
     private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name, boolean secure);
+    private static native void nativeDestroyDisplay(IBinder displayToken);
     private static native void nativeSetDisplaySurface(
             IBinder displayToken, int nativeSurfaceObject);
     private static native void nativeSetDisplayLayerStack(
             IBinder displayToken, int layerStack);
     private static native void nativeSetDisplayProjection(
             IBinder displayToken, int orientation,
-            int l, int t, int r, int b, 
+            int l, int t, int r, int b,
             int L, int T, int R, int B);
     private static native boolean nativeGetDisplayInfo(
             IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo);
@@ -74,23 +76,12 @@
 
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
-    private String mName;
+    private final String mName;
     int mNativeObject; // package visibility only for Surface.java access
 
     private static final boolean HEADLESS = "1".equals(
         SystemProperties.get("ro.config.headless", "0"));
 
-    /**
-     * Exception thrown when a surface couldn't be created or resized.
-     */
-    public static class OutOfResourcesException extends Exception {
-        public OutOfResourcesException() {
-        }
-        public OutOfResourcesException(String name) {
-            super(name);
-        }
-    }
-
     /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
 
     /**
@@ -103,7 +94,7 @@
      * measures will be taken to disallow the surface's content to be copied
      * from another process. In particular, screenshots and VNC servers will
      * be disabled, but other measures can take place, for instance the
-     * surface might not be hardware accelerated. 
+     * surface might not be hardware accelerated.
      *
      */
     public static final int SECURE = 0x00000080;
@@ -219,6 +210,8 @@
      * @param h The surface initial height.
      * @param flags The surface creation flags.  Should always include {@link #HIDDEN}
      * in the creation flags.
+     *
+     * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
      */
     public SurfaceControl(SurfaceSession session,
             String name, int w, int h, int format, int flags)
@@ -247,10 +240,10 @@
             throw new OutOfResourcesException(
                     "Couldn't allocate SurfaceControl native object");
         }
-        
+
         mCloseGuard.open("release");
     }
-    
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -300,7 +293,7 @@
         if (mNativeObject == 0) throw new NullPointerException(
                 "mNativeObject is null. Have you called release() already?");
     }
-    
+
     /*
      * set surface parameters.
      * needs to be inside open/closeTransaction block
@@ -369,7 +362,7 @@
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
         if (crop != null) {
-            nativeSetWindowCrop(mNativeObject, 
+            nativeSetWindowCrop(mNativeObject,
                 crop.left, crop.top, crop.right, crop.bottom);
         } else {
             nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0);
@@ -397,19 +390,19 @@
         public float xDpi;
         public float yDpi;
         public boolean secure;
-    
+
         public PhysicalDisplayInfo() {
         }
-    
+
         public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
             copyFrom(other);
         }
-    
+
         @Override
         public boolean equals(Object o) {
             return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
         }
-    
+
         public boolean equals(PhysicalDisplayInfo other) {
             return other != null
                     && width == other.width
@@ -420,12 +413,12 @@
                     && yDpi == other.yDpi
                     && secure == other.secure;
         }
-    
+
         @Override
         public int hashCode() {
             return 0; // don't care
         }
-    
+
         public void copyFrom(PhysicalDisplayInfo other) {
             width = other.width;
             height = other.height;
@@ -435,7 +428,7 @@
             yDpi = other.yDpi;
             secure = other.secure;
         }
-    
+
         // For debugging purposes
         @Override
         public String toString() {
@@ -481,7 +474,7 @@
             throw new IllegalArgumentException("displayRect must not be null");
         }
         nativeSetDisplayProjection(displayToken, orientation,
-                layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, 
+                layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom,
                 displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
     }
 
@@ -499,7 +492,7 @@
 
         if (surface != null) {
             synchronized (surface.mLock) {
-                nativeSetDisplaySurface(displayToken, surface.mNativeSurface);
+                nativeSetDisplaySurface(displayToken, surface.mNativeObject);
             }
         } else {
             nativeSetDisplaySurface(displayToken, 0);
@@ -513,6 +506,13 @@
         return nativeCreateDisplay(name, secure);
     }
 
+    public static void destroyDisplay(IBinder displayToken) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        nativeDestroyDisplay(displayToken);
+    }
+
     public static IBinder getBuiltInDisplay(int builtInDisplayId) {
         return nativeGetBuiltInDisplay(builtInDisplayId);
     }
@@ -608,7 +608,7 @@
                 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
         return nativeScreenshot(displayToken, width, height, 0, 0, true);
     }
-    
+
     private static void screenshot(IBinder display, Surface consumer,
             int width, int height, int minLayer, int maxLayer, boolean allLayers) {
         if (display == null) {
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 015a78e..99fa2a4 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -277,9 +277,6 @@
      * 
      * <p>This method is intended to be used by frameworks which often need
      * direct access to the Surface object (usually to pass it to native code).
-     * When designing APIs always use SurfaceHolder to pass surfaces around
-     * as opposed to the Surface object itself. A rule of thumb is that
-     * application code should never have to call this method.
      * 
      * @return Surface The surface.
      */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 793fb5e..4366fb7 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -43,7 +43,7 @@
  * You can control the format of this surface and, if you like, its size; the
  * SurfaceView takes care of placing the surface at the correct location on the
  * screen
- * 
+ *
  * <p>The surface is Z ordered so that it is behind the window holding its
  * SurfaceView; the SurfaceView punches a hole in its window to allow its
  * surface to be displayed. The view hierarchy will take care of correctly
@@ -52,7 +52,7 @@
  * buttons on top of the Surface, though note however that it can have an
  * impact on performance since a full alpha-blended composite will be performed
  * each time the Surface changes.
- * 
+ *
  * <p> The transparent region that makes the surface visible is based on the
  * layout positions in the view hierarchy. If the post-layout transform
  * properties are used to draw a sibling view on top of the SurfaceView, the
@@ -60,16 +60,16 @@
  *
  * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
  * which can be retrieved by calling {@link #getHolder}.
- * 
+ *
  * <p>The Surface will be created for you while the SurfaceView's window is
  * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
  * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
  * Surface is created and destroyed as the window is shown and hidden.
- * 
+ *
  * <p>One of the purposes of this class is to provide a surface in which a
  * secondary thread can render into the screen. If you are going to use it
  * this way, you need to be aware of some threading semantics:
- * 
+ *
  * <ul>
  * <li> All SurfaceView and
  * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
@@ -91,7 +91,7 @@
             = new ArrayList<SurfaceHolder.Callback>();
 
     final int[] mLocation = new int[2];
-    
+
     final ReentrantLock mSurfaceLock = new ReentrantLock();
     final Surface mSurface = new Surface();       // Current surface in use
     final Surface mNewSurface = new Surface();    // New surface we are switching to
@@ -106,13 +106,13 @@
     final Rect mOverscanInsets = new Rect();
     final Rect mContentInsets = new Rect();
     final Configuration mConfiguration = new Configuration();
-    
+
     static final int KEEP_SCREEN_ON_MSG = 1;
     static final int GET_NEW_SURFACE_MSG = 2;
     static final int UPDATE_WINDOW_MSG = 3;
-    
+
     int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-    
+
     boolean mIsCreating = false;
 
     final Handler mHandler = new Handler() {
@@ -131,14 +131,15 @@
             }
         }
     };
-    
+
     final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
             = new ViewTreeObserver.OnScrollChangedListener() {
+                    @Override
                     public void onScrollChanged() {
                         updateWindow(false, false);
                     }
             };
-            
+
     boolean mRequestedVisible = false;
     boolean mWindowVisibility = false;
     boolean mViewVisibility = false;
@@ -152,7 +153,7 @@
     boolean mHaveFrame = false;
     boolean mSurfaceCreated = false;
     long mLastLockTime = 0;
-    
+
     boolean mVisible = false;
     int mLeft = -1;
     int mTop = -1;
@@ -160,7 +161,6 @@
     int mHeight = -1;
     int mFormat = -1;
     final Rect mSurfaceFrame = new Rect();
-    Rect mTmpDirty;
     int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
     boolean mUpdateWindowNeeded;
     boolean mReportDrawNeeded;
@@ -170,7 +170,7 @@
             new ViewTreeObserver.OnPreDrawListener() {
                 @Override
                 public boolean onPreDraw() {
-                    // reposition ourselves where the surface is 
+                    // reposition ourselves where the surface is
                     mHaveFrame = getWidth() > 0 && getHeight() > 0;
                     updateWindow(false, false);
                     return true;
@@ -182,7 +182,7 @@
         super(context);
         init();
     }
-    
+
     public SurfaceView(Context context, AttributeSet attrs) {
         super(context, attrs);
         init();
@@ -196,11 +196,11 @@
     private void init() {
         setWillNotDraw(true);
     }
-    
+
     /**
      * Return the SurfaceHolder providing access and control over this
      * SurfaceView's underlying surface.
-     * 
+     *
      * @return SurfaceHolder The holder of the surface.
      */
     public SurfaceHolder getHolder() {
@@ -286,7 +286,7 @@
                 : getDefaultSize(0, heightMeasureSpec);
         setMeasuredDimension(width, height);
     }
-    
+
     /** @hide */
     @Override
     protected boolean setFrame(int left, int top, int right, int bottom) {
@@ -300,7 +300,7 @@
         if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
             return super.gatherTransparentRegion(region);
         }
-        
+
         boolean opaque = true;
         if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
             // this view draws, remove it from the transparent region
@@ -351,10 +351,10 @@
      * regular surface view in the window (but still behind the window itself).
      * This is typically used to place overlays on top of an underlying media
      * surface view.
-     * 
+     *
      * <p>Note that this must be set before the surface view's containing
      * window is attached to the window manager.
-     * 
+     *
      * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
      */
     public void setZOrderMediaOverlay(boolean isMediaOverlay) {
@@ -362,7 +362,7 @@
                 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
                 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
     }
-    
+
     /**
      * Control whether the surface view's surface is placed on top of its
      * window.  Normally it is placed behind the window, to allow it to
@@ -370,10 +370,10 @@
      * hierarchy.  By setting this, you cause it to be placed above the
      * window.  This means that none of the contents of the window this
      * SurfaceView is in will be visible on top of its surface.
-     * 
+     *
      * <p>Note that this must be set before the surface view's containing
      * window is attached to the window manager.
-     * 
+     *
      * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
      */
     public void setZOrderOnTop(boolean onTop) {
@@ -428,7 +428,7 @@
         if (mTranslator != null) {
             mSurface.setCompatibilityTranslator(mTranslator);
         }
-        
+
         int myWidth = mRequestedWidth;
         if (myWidth <= 0) myWidth = getWidth();
         int myHeight = mRequestedHeight;
@@ -459,7 +459,7 @@
                 mFormat = mRequestedFormat;
 
                 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
-                
+
                 // Places the window relative
                 mLayout.x = mLeft;
                 mLayout.y = mTop;
@@ -468,7 +468,7 @@
                 if (mTranslator != null) {
                     mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
                 }
-                
+
                 mLayout.format = mRequestedFormat;
                 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                               | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -478,7 +478,7 @@
                               | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                               ;
                 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
-                    mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                    mLayout.flags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                 }
                 mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 
@@ -490,7 +490,7 @@
                     mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
                             mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets);
                 }
-                
+
                 boolean realSizeChanged;
                 boolean reportDrawNeeded;
 
@@ -502,7 +502,7 @@
                     reportDrawNeeded = mReportDrawNeeded;
                     mReportDrawNeeded = false;
                     mDrawingStopped = !visible;
-    
+
                     if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
 
                     relayoutResult = mSession.relayout(
@@ -528,7 +528,7 @@
                         mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
                         mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
                     }
-                    
+
                     final int surfaceWidth = mSurfaceFrame.right;
                     final int surfaceHeight = mSurfaceFrame.bottom;
                     realSizeChanged = mLastSurfaceWidth != surfaceWidth
@@ -668,10 +668,12 @@
             }
         }
 
+        @Override
         public void dispatchAppVisibility(boolean visible) {
             // The point of SurfaceView is to let the app control the surface.
         }
 
+        @Override
         public void dispatchGetNewSurface() {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
@@ -680,10 +682,12 @@
             }
         }
 
+        @Override
         public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
             Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
         }
 
+        @Override
         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
         }
 
@@ -691,30 +695,34 @@
         int mCurHeight = -1;
     }
 
-    private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-        
+    private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
+
         private static final String LOG_TAG = "SurfaceHolder";
-        
+
+        @Override
         public boolean isCreating() {
             return mIsCreating;
         }
 
+        @Override
         public void addCallback(Callback callback) {
             synchronized (mCallbacks) {
-                // This is a linear search, but in practice we'll 
+                // This is a linear search, but in practice we'll
                 // have only a couple callbacks, so it doesn't matter.
-                if (mCallbacks.contains(callback) == false) {      
+                if (mCallbacks.contains(callback) == false) {
                     mCallbacks.add(callback);
                 }
             }
         }
 
+        @Override
         public void removeCallback(Callback callback) {
             synchronized (mCallbacks) {
                 mCallbacks.remove(callback);
             }
         }
-        
+
+        @Override
         public void setFixedSize(int width, int height) {
             if (mRequestedWidth != width || mRequestedHeight != height) {
                 mRequestedWidth = width;
@@ -723,6 +731,7 @@
             }
         }
 
+        @Override
         public void setSizeFromLayout() {
             if (mRequestedWidth != -1 || mRequestedHeight != -1) {
                 mRequestedWidth = mRequestedHeight = -1;
@@ -730,6 +739,7 @@
             }
         }
 
+        @Override
         public void setFormat(int format) {
 
             // for backward compatibility reason, OPAQUE always
@@ -746,15 +756,17 @@
         /**
          * @deprecated setType is now ignored.
          */
+        @Override
         @Deprecated
         public void setType(int type) { }
 
+        @Override
         public void setKeepScreenOn(boolean screenOn) {
             Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
             msg.arg1 = screenOn ? 1 : 0;
             mHandler.sendMessage(msg);
         }
-        
+
         /**
          * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
          *
@@ -764,6 +776,7 @@
          * The caller must redraw the entire surface.
          * @return A canvas for drawing into the surface.
          */
+        @Override
         public Canvas lockCanvas() {
             return internalLockCanvas(null);
         }
@@ -783,6 +796,7 @@
          * entire surface should be redrawn.
          * @return A canvas for drawing into the surface.
          */
+        @Override
         public Canvas lockCanvas(Rect inOutDirty) {
             return internalLockCanvas(inOutDirty);
         }
@@ -795,14 +809,6 @@
 
             Canvas c = null;
             if (!mDrawingStopped && mWindow != null) {
-                if (dirty == null) {
-                    if (mTmpDirty == null) {
-                        mTmpDirty = new Rect();
-                    }
-                    mTmpDirty.set(mSurfaceFrame);
-                    dirty = mTmpDirty;
-                }
-
                 try {
                     c = mSurface.lockCanvas(dirty);
                 } catch (Exception e) {
@@ -815,7 +821,7 @@
                 mLastLockTime = SystemClock.uptimeMillis();
                 return c;
             }
-            
+
             // If the Surface is not ready to be drawn, then return null,
             // but throttle calls to this function so it isn't called more
             // than every 100ms.
@@ -830,7 +836,7 @@
             }
             mLastLockTime = now;
             mSurfaceLock.unlock();
-            
+
             return null;
         }
 
@@ -840,15 +846,18 @@
          *
          * @param canvas The canvas previously obtained from {@link #lockCanvas}.
          */
+        @Override
         public void unlockCanvasAndPost(Canvas canvas) {
             mSurface.unlockCanvasAndPost(canvas);
             mSurfaceLock.unlock();
         }
 
+        @Override
         public Surface getSurface() {
             return mSurface;
         }
 
+        @Override
         public Rect getSurfaceFrame() {
             return mSurfaceFrame;
         }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 244dc33..47f7628 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -213,8 +213,8 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        if (mLayer != null && mAttachInfo != null && mAttachInfo.mHardwareRenderer != null) {
-            boolean success = mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
+        if (mLayer != null) {
+            boolean success = executeHardwareAction(new Runnable() {
                 @Override
                 public void run() {
                     destroySurface();
@@ -322,7 +322,7 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         if (mSurface != null) {
-            nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+            mSurface.setDefaultBufferSize(getWidth(), getHeight());
             updateLayer();
             if (mListener != null) {
                 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
@@ -362,7 +362,7 @@
                 // Create a new SurfaceTexture for the layer.
                 mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
             }
-            nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+            mSurface.setDefaultBufferSize(getWidth(), getHeight());
             nCreateNativeWindow(mSurface);
 
             mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@@ -399,7 +399,7 @@
             mMatrixChanged = true;
 
             mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
-            nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+            mSurface.setDefaultBufferSize(getWidth(), getHeight());
         }
 
         applyUpdate();
@@ -656,13 +656,19 @@
      * rectangle. Every pixel within that rectangle must be written; however
      * pixels outside the dirty rectangle will be preserved by the next call
      * to lockCanvas().
+     *
+     * This method can return null if the underlying surface texture is not
+     * available (see {@link #isAvailable()} or if the surface texture is
+     * already connected to an image producer (for instance: the camera,
+     * OpenGL, a media player, etc.)
      * 
      * @param dirty Area of the surface that will be modified.
 
      * @return A Canvas used to draw into the surface.
      * 
      * @see #lockCanvas() 
-     * @see #unlockCanvasAndPost(android.graphics.Canvas) 
+     * @see #unlockCanvasAndPost(android.graphics.Canvas)
+     * @see #isAvailable()
      */
     public Canvas lockCanvas(Rect dirty) {
         if (!isAvailable()) return null;
@@ -672,7 +678,9 @@
         }
 
         synchronized (mNativeWindowLock) {
-            nLockCanvas(mNativeWindow, mCanvas, dirty);
+            if (!nLockCanvas(mNativeWindow, mCanvas, dirty)) {
+                return null;
+            }
         }
         mSaveCount = mCanvas.save();
 
@@ -808,9 +816,6 @@
     private native void nCreateNativeWindow(SurfaceTexture surface);
     private native void nDestroyNativeWindow();
 
-    private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
-            int width, int height);
-
-    private static native void nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
+    private static native boolean nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
     private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 50638aa..06f00f7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,7 +40,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -52,10 +51,13 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.util.LayoutDirection;
 import android.util.Log;
+import android.util.LongSparseLongArray;
 import android.util.Pools.SynchronizedPool;
 import android.util.Property;
 import android.util.SparseArray;
+import android.util.SuperNotCalledException;
 import android.util.TypedValue;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -1122,7 +1124,6 @@
      *
      * @see android.graphics.drawable.Drawable
      * @see #getDrawableState()
-     * @hide
      */
     protected static final int[] PRESSED_STATE_SET;
     /**
@@ -1563,6 +1564,8 @@
 
     private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
 
+    SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent;
+
     /**
      * The view's tag.
      * {@hide}
@@ -1797,25 +1800,25 @@
      * Horizontal layout direction of this view is from Left to Right.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_LTR = 0;
+    public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR;
 
     /**
      * Horizontal layout direction of this view is from Right to Left.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_RTL = 1;
+    public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL;
 
     /**
      * Horizontal layout direction of this view is inherited from its parent.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_INHERIT = 2;
+    public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT;
 
     /**
      * Horizontal layout direction of this view is from deduced from the default language
      * script for the locale. Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_LOCALE = 3;
+    public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE;
 
     /**
      * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
@@ -2131,15 +2134,58 @@
         << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
 
     /**
-     * Flag indicating whether a view has accessibility focus.
+     * Shift for the bits in {@link #mPrivateFlags2} related to the
+     * "accessibilityLiveRegion" attribute.
      */
-    static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x00000040 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+    static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 22;
 
     /**
-     * Flag indicating whether a view state for accessibility has changed.
+     * Live region mode specifying that accessibility services should not
+     * automatically announce changes to this view. This is the default live
+     * region mode for most views.
+     * <p>
+     * Use with {@link #setAccessibilityLiveRegion(int)}.
      */
-    static final int PFLAG2_ACCESSIBILITY_STATE_CHANGED = 0x00000080
-            << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+    public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000;
+
+    /**
+     * Live region mode specifying that accessibility services should announce
+     * changes to this view.
+     * <p>
+     * Use with {@link #setAccessibilityLiveRegion(int)}.
+     */
+    public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001;
+
+    /**
+     * Live region mode specifying that accessibility services should interrupt
+     * ongoing speech to immediately announce changes to this view.
+     * <p>
+     * Use with {@link #setAccessibilityLiveRegion(int)}.
+     */
+    public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002;
+
+    /**
+     * The default whether the view is important for accessibility.
+     */
+    static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE;
+
+    /**
+     * Mask for obtaining the bits which specify a view's accessibility live
+     * region mode.
+     */
+    static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE
+            | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE)
+            << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
+
+    /**
+     * Flag indicating whether a view has accessibility focus.
+     */
+    static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000;
+
+    /**
+     * Flag whether the accessibility state of the subtree rooted at this view changed.
+     */
+    static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000;
 
     /**
      * Flag indicating whether a view failed the quickReject() check in draw(). This condition
@@ -2191,6 +2237,24 @@
      */
     static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2;
 
+    /**
+     * Flag indicating that the view has been through at least one layout since it
+     * was last attached to a window.
+     */
+    static final int PFLAG3_IS_LAID_OUT = 0x4;
+
+    /**
+     * Flag indicating that a call to measure() was skipped and should be done
+     * instead when layout() is invoked.
+     */
+    static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8;
+
+    /**
+     * Flag indicating that an overridden method correctly  called down to
+     * the superclass implementation as required by the API spec.
+     */
+    static final int PFLAG3_CALLED_SUPER = 0x10;
+
 
     /* End of masks for mPrivateFlags3 */
 
@@ -2341,7 +2405,7 @@
      * allows it to avoid artifacts when switching in and out of that mode, at
      * the expense that some of its user interface may be covered by screen
      * decorations when they are shown.  You can perform layout of your inner
-     * UI elements to account for the navagation system UI through the
+     * UI elements to account for the navigation system UI through the
      * {@link #fitSystemWindows(Rect)} method.
      */
     public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
@@ -2359,6 +2423,42 @@
     public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
 
     /**
+     * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when
+     * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation
+     * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.  Use this flag to create an immersive
+     * experience while also hiding the system bars.  If this flag is not set,
+     * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user
+     * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system
+     * if the user swipes from the top of the screen.
+     * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with
+     * system gestures, such as swiping from the top of the screen.  These transient system bars
+     * will overlay app’s content, may have some degree of transparency, and will automatically
+     * hide after a short timeout.
+     * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and
+     * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination
+     * with one or both of those flags.</p>
+     */
+    public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800;
+
+    /**
+     * Flag for {@link #setSystemUiVisibility(int)}: View would like the status bar to have
+     * transparency.
+     *
+     * <p>The transparency request may be denied if the bar is in another mode with a specific
+     * style, like {@link #SYSTEM_UI_FLAG_IMMERSIVE immersive mode}.
+     */
+    public static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 0x00001000;
+
+    /**
+     * Flag for {@link #setSystemUiVisibility(int)}: View would like the navigation bar to have
+     * transparency.
+     *
+     * <p>The transparency request may be denied if the bar is in another mode with a specific
+     * style, like {@link #SYSTEM_UI_FLAG_IMMERSIVE immersive mode}.
+     */
+    public static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 0x00002000;
+
+    /**
      * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead.
      */
     public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE;
@@ -2479,6 +2579,46 @@
 
     /**
      * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the status bar is displayed in transient mode.
+     */
+    public static final int STATUS_BAR_TRANSIENT = 0x04000000;
+
+    /**
+     * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the navigation bar is displayed in transient mode.
+     */
+    public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000;
+
+    /**
+     * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the hidden status bar would like to be shown.
+     */
+    public static final int STATUS_BAR_UNHIDE = 0x10000000;
+
+    /**
+     * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the hidden navigation bar would like to be shown.
+     */
+    public static final int NAVIGATION_BAR_UNHIDE = 0x20000000;
+
+    /**
+     * @hide
      */
     public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
 
@@ -2754,6 +2894,13 @@
          */
         @ViewDebug.ExportedProperty
         float mAlpha = 1f;
+
+        /**
+         * The opacity of the view as manipulated by the Fade transition. This is a hidden
+         * property only used by transitions, which is composited with the other alpha
+         * values to calculate the final visual alpha value.
+         */
+        float mTransitionAlpha = 1f;
     }
 
     TransformationInfo mTransformationInfo;
@@ -2938,6 +3085,8 @@
      */
     int mOldHeightMeasureSpec = Integer.MIN_VALUE;
 
+    private LongSparseLongArray mMeasureCache;
+
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
     private Drawable mBackground;
 
@@ -3012,18 +3161,6 @@
     private int[] mDrawableState = null;
 
     /**
-     * Set to true when drawing cache is enabled and cannot be created.
-     *
-     * @hide
-     */
-    public boolean mCachingFailed;
-
-    private Bitmap mDrawingCache;
-    private Bitmap mUnscaledDrawingCache;
-    private HardwareLayer mHardwareLayer;
-    DisplayList mDisplayList;
-
-    /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
      * the user may specify which view to go to next.
      */
@@ -3215,6 +3352,18 @@
     int mLayerType = LAYER_TYPE_NONE;
     Paint mLayerPaint;
     Rect mLocalDirtyRect;
+    private HardwareLayer mHardwareLayer;
+
+    /**
+     * Set to true when drawing cache is enabled and cannot be created.
+     *
+     * @hide
+     */
+    public boolean mCachingFailed;
+    private Bitmap mDrawingCache;
+    private Bitmap mUnscaledDrawingCache;
+
+    DisplayList mDisplayList;
 
     /**
      * Set to true when the view is sending hover accessibility events because it
@@ -3266,8 +3415,8 @@
         mUserPaddingStart = UNDEFINED_PADDING;
         mUserPaddingEnd = UNDEFINED_PADDING;
 
-        if (!sUseBrokenMakeMeasureSpec && context.getApplicationInfo().targetSdkVersion <=
-                Build.VERSION_CODES.JELLY_BEAN_MR1 ) {
+        if (!sUseBrokenMakeMeasureSpec && context != null &&
+                context.getApplicationInfo().targetSdkVersion <= JELLY_BEAN_MR1) {
             // Older apps may need this compatibility hack for measurement.
             sUseBrokenMakeMeasureSpec = true;
         }
@@ -3305,17 +3454,16 @@
      * @param context The Context the view is running in, through which it can
      *        access the current theme, resources, etc.
      * @param attrs The attributes of the XML tag that is inflating the view.
-     * @param defStyle The default style to apply to this view. If 0, no style
-     *        will be applied (beyond what is included in the theme). This may
-     *        either be an attribute resource, whose value will be retrieved
-     *        from the current theme, or an explicit style resource.
+     * @param defStyleAttr An attribute in the current theme that contains a
+     *        reference to a style resource to apply to this view. If 0, no
+     *        default style will be applied.
      * @see #View(Context, AttributeSet)
      */
-    public View(Context context, AttributeSet attrs, int defStyle) {
+    public View(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context);
 
         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View,
-                defStyle, 0);
+                defStyleAttr, 0);
 
         Drawable background = null;
 
@@ -3666,6 +3814,9 @@
                     setImportantForAccessibility(a.getInt(attr,
                             IMPORTANT_FOR_ACCESSIBILITY_DEFAULT));
                     break;
+                case R.styleable.View_accessibilityLiveRegion:
+                    setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
+                    break;
             }
         }
 
@@ -4418,10 +4569,6 @@
 
             onFocusChanged(true, direction, previouslyFocusedRect);
             refreshDrawableState();
-
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                notifyAccessibilityStateChanged();
-            }
         }
     }
 
@@ -4511,10 +4658,23 @@
             System.out.println(this + " clearFocus()");
         }
 
+        clearFocusInternal(true, true);
+    }
+
+    /**
+     * Clears focus from the view, optionally propagating the change up through
+     * the parent hierarchy and requesting that the root view place new focus.
+     *
+     * @param propagate whether to propagate the change up through the parent
+     *            hierarchy
+     * @param refocus when propagate is true, specifies whether to request the
+     *            root view place new focus
+     */
+    void clearFocusInternal(boolean propagate, boolean refocus) {
         if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
             mPrivateFlags &= ~PFLAG_FOCUSED;
 
-            if (mParent != null) {
+            if (propagate && mParent != null) {
                 mParent.clearChildFocus(this);
             }
 
@@ -4522,13 +4682,9 @@
 
             refreshDrawableState();
 
-            if (!rootViewRequestFocus()) {
+            if (propagate && (!refocus || !rootViewRequestFocus())) {
                 notifyGlobalFocusCleared(this);
             }
-
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                notifyAccessibilityStateChanged();
-            }
         }
     }
 
@@ -4539,32 +4695,24 @@
     }
 
     boolean rootViewRequestFocus() {
-        View root = getRootView();
-        if (root != null) {
-            return root.requestFocus();
-        }
-        return false;
+        final View root = getRootView();
+        return root != null && root.requestFocus();
     }
 
     /**
      * Called internally by the view system when a new view is getting focus.
      * This is what clears the old focus.
+     * <p>
+     * <b>NOTE:</b> The parent view's focused child must be updated manually
+     * after calling this method. Otherwise, the view hierarchy may be left in
+     * an inconstent state.
      */
     void unFocus() {
         if (DBG) {
             System.out.println(this + " unFocus()");
         }
 
-        if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
-            mPrivateFlags &= ~PFLAG_FOCUSED;
-
-            onFocusChanged(false, 0, null);
-            refreshDrawableState();
-
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                notifyAccessibilityStateChanged();
-            }
-        }
+        clearFocusInternal(false, false);
     }
 
     /**
@@ -4614,9 +4762,10 @@
      */
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         if (gainFocus) {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-            }
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        } else {
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
 
         InputMethodManager imm = InputMethodManager.peekInstance();
@@ -4673,6 +4822,10 @@
      * @see AccessibilityDelegate
      */
     public void sendAccessibilityEvent(int eventType) {
+        // Excluded views do not send accessibility events.
+        if (!includeForAccessibility()) {
+            return;
+        }
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
         } else {
@@ -4840,7 +4993,6 @@
      * Note: Called from the default {@link AccessibilityDelegate}.
      */
     void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
-
     }
 
     /**
@@ -5097,6 +5249,7 @@
         info.setAccessibilityFocused(isAccessibilityFocused());
         info.setSelected(isSelected());
         info.setLongClickable(isLongClickable());
+        info.setLiveRegion(getAccessibilityLiveRegion());
 
         // TODO: These make sense only if we are in an AdapterView but all
         // views can be selected. Maybe from accessibility perspective
@@ -5190,7 +5343,8 @@
                 View view = (View) current;
                 // We have attach info so this view is attached and there is no
                 // need to check whether we reach to ViewRootImpl on the way up.
-                if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) {
+                if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
+                        view.getVisibility() != VISIBLE) {
                     return false;
                 }
                 current = view.mParent;
@@ -5331,9 +5485,12 @@
         mContentDescription = contentDescription;
         final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0;
         if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            notifySubtreeAccessibilityStateChangedIfNeeded();
+        } else {
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION);
         }
-        notifyAccessibilityStateChanged();
     }
 
     /**
@@ -5657,7 +5814,7 @@
      * which you would like to ensure are not being covered.
      *
      * <p>The default implementation of this method simply applies the content
-     * inset's to the view's padding, consuming that content (modifying the
+     * insets to the view's padding, consuming that content (modifying the
      * insets to be 0), and returning true.  This behavior is off by default, but can
      * be enabled through {@link #setFitsSystemWindows(boolean)}.
      *
@@ -5694,8 +5851,8 @@
      * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify
      * the insets or else you and Android will be unhappy.
      *
-     * @return Return true if this view applied the insets and it should not
-     * continue propagating further down the hierarchy, false otherwise.
+     * @return {@code true} if this view applied the insets and it should not
+     * continue propagating further down the hierarchy, {@code false} otherwise.
      * @see #getFitsSystemWindows()
      * @see #setFitsSystemWindows(boolean) 
      * @see #setSystemUiVisibility(int)
@@ -5766,15 +5923,15 @@
     }
 
     /**
-     * Check for state of {@link #setFitsSystemWindows(boolean). If this method
-     * returns true, the default implementation of {@link #fitSystemWindows(Rect)}
+     * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method
+     * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)}
      * will be executed.
      *
-     * @return Returns true if the default implementation of
+     * @return {@code true} if the default implementation of
      * {@link #fitSystemWindows(Rect)} will be executed.
      *
      * @attr ref android.R.styleable#View_fitsSystemWindows
-     * @see #setFitsSystemWindows()
+     * @see #setFitsSystemWindows(boolean)
      * @see #fitSystemWindows(Rect)
      * @see #setSystemUiVisibility(int)
      */
@@ -5863,6 +6020,10 @@
         // Invalidate too, since the default behavior for views is to be
         // be drawn at 50% alpha rather than to change the drawable.
         invalidate(true);
+
+        if (!enabled) {
+            cancelPendingInputEvents();
+        }
     }
 
     /**
@@ -6110,6 +6271,21 @@
     }
 
     /**
+     * Returns true if this view is currently attached to a window.
+     */
+    public boolean isAttachedToWindow() {
+        return mAttachInfo != null;
+    }
+
+    /**
+     * Returns true if this view has been through at least one layout since it
+     * was last attached to or detached from a window.
+     */
+    public boolean isLaidOut() {
+        return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT;
+    }
+
+    /**
      * If this view doesn't do any drawing on its own, set this flag to
      * allow further optimizations. By default, this flag is not set on
      * View, but could be set on some View subclasses such as ViewGroup.
@@ -6578,8 +6754,9 @@
      * Returns whether this View is accessibility focused.
      *
      * @return True if this View is accessibility focused.
+     * @hide
      */
-    boolean isAccessibilityFocused() {
+    public boolean isAccessibilityFocused() {
         return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0;
     }
 
@@ -6613,7 +6790,6 @@
             }
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
-            notifyAccessibilityStateChanged();
             return true;
         }
         return false;
@@ -6676,7 +6852,6 @@
             mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED;
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
-            notifyAccessibilityStateChanged();
         }
     }
 
@@ -6837,6 +7012,58 @@
     }
 
     /**
+     * Sets the live region mode for this view. This indicates to accessibility
+     * services whether they should automatically notify the user about changes
+     * to the view's content description or text, or to the content descriptions
+     * or text of the view's children (where applicable).
+     * <p>
+     * For example, in a login screen with a TextView that displays an "incorrect
+     * password" notification, that view should be marked as a live region with
+     * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
+     * <p>
+     * To disable change notifications for this view, use
+     * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region
+     * mode for most views.
+     * <p>
+     * To indicate that the user should be notified of changes, use
+     * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
+     * <p>
+     * If the view's changes should interrupt ongoing speech and notify the user
+     * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}.
+     *
+     * @param mode The live region mode for this view, one of:
+     *        <ul>
+     *        <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE}
+     *        <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE}
+     *        <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}
+     *        </ul>
+     * @attr ref android.R.styleable#View_accessibilityLiveRegion
+     */
+    public void setAccessibilityLiveRegion(int mode) {
+        if (mode != getAccessibilityLiveRegion()) {
+            mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
+            mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT)
+                    & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+        }
+    }
+
+    /**
+     * Gets the live region mode for this View.
+     *
+     * @return The live region mode for the view.
+     *
+     * @attr ref android.R.styleable#View_accessibilityLiveRegion
+     *
+     * @see #setAccessibilityLiveRegion(int)
+     */
+    public int getAccessibilityLiveRegion() {
+        return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
+                >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
+    }
+
+    /**
      * Sets how to determine whether this view is important for accessibility
      * which is if it fires accessibility events and if it is reported to
      * accessibility services that query the screen.
@@ -6850,11 +7077,17 @@
      * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
      */
     public void setImportantForAccessibility(int mode) {
+        final boolean oldIncludeForAccessibility = includeForAccessibility();
         if (mode != getImportantForAccessibility()) {
             mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
             mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
                     & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
-            notifyAccessibilityStateChanged();
+            if (oldIncludeForAccessibility != includeForAccessibility()) {
+                notifySubtreeAccessibilityStateChangedIfNeeded();
+            } else {
+                notifyViewAccessibilityStateChangedIfNeeded(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+            }
         }
     }
 
@@ -6875,7 +7108,8 @@
                 return false;
             case IMPORTANT_FOR_ACCESSIBILITY_AUTO:
                 return isActionableForAccessibility() || hasListenersForAccessibility()
-                        || getAccessibilityNodeProvider() != null;
+                        || getAccessibilityNodeProvider() != null
+                        || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE;
             default:
                 throw new IllegalArgumentException("Unknow important for accessibility mode: "
                         + mode);
@@ -6926,6 +7160,7 @@
      * @hide
      */
     public boolean includeForAccessibility() {
+        //noinspection SimplifiableIfStatement
         if (mAttachInfo != null) {
             return (mAttachInfo.mAccessibilityFetchFlags
                     & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
@@ -6961,39 +7196,62 @@
     }
 
     /**
-     * Notifies accessibility services that some view's important for
-     * accessibility state has changed. Note that such notifications
-     * are made at most once every
+     * Notifies that the accessibility state of this view changed. The change
+     * is local to this view and does not represent structural changes such
+     * as children and parent. For example, the view became focusable. The
+     * notification is at at most once every
      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
-     * to avoid unnecessary load to the system. Also once a view has
-     * made a notifucation this method is a NOP until the notification has
-     * been sent to clients.
+     * 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.
      *
      * @hide
-     *
-     * TODO: Makse sure this method is called for any view state change
-     *       that is interesting for accessilility purposes.
      */
-    public void notifyAccessibilityStateChanged() {
+    public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) {
         if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
             return;
         }
-        if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_STATE_CHANGED) == 0) {
-            mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_STATE_CHANGED;
+        if (mSendViewStateChangedAccessibilityEvent == null) {
+            mSendViewStateChangedAccessibilityEvent =
+                    new SendViewStateChangedAccessibilityEvent();
+        }
+        mSendViewStateChangedAccessibilityEvent.runOrPost(changeType);
+    }
+
+    /**
+     * Notifies that the accessibility state of this view changed. The change
+     * is *not* local to this view and does represent structural changes such
+     * as children and parent. For example, the view size changed. The
+     * 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.
+     *
+     * @hide
+     */
+    public void notifySubtreeAccessibilityStateChangedIfNeeded() {
+        if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+            return;
+        }
+        if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
+            mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
             if (mParent != null) {
-                mParent.childAccessibilityStateChanged(this);
+                try {
+                    mParent.notifySubtreeAccessibilityStateChanged(
+                            this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+                } catch (AbstractMethodError e) {
+                    Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                            " does not fully implement ViewParent", e);
+                }
             }
         }
     }
 
     /**
-     * Reset the state indicating the this view has requested clients
-     * interested in its accessibility state to be notified.
-     *
-     * @hide
+     * Reset the flag indicating the accessibility state of the subtree rooted
+     * at this view changed.
      */
-    public void resetAccessibilityStateChanged() {
-        mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_STATE_CHANGED;
+    void resetSubtreeAccessibilityStateChanged() {
+        mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
     }
 
     /**
@@ -7106,7 +7364,8 @@
                         || getAccessibilitySelectionEnd() != end)
                         && (start == end)) {
                     setAccessibilitySelection(start, end);
-                    notifyAccessibilityStateChanged();
+                    notifyViewAccessibilityStateChangedIfNeeded(
+                            AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                     return true;
                 }
             } break;
@@ -7261,7 +7520,6 @@
      * @hide
      */
     public void dispatchStartTemporaryDetach() {
-        clearAccessibilityFocus();
         clearDisplayList();
 
         onStartTemporaryDetach();
@@ -7497,8 +7755,8 @@
      * @return True if the event was handled by the view, false otherwise.
      */
     protected boolean dispatchHoverEvent(MotionEvent event) {
-        //noinspection SimplifiableIfStatement
         ListenerInfo li = mListenerInfo;
+        //noinspection SimplifiableIfStatement
         if (li != null && li.mOnHoverListener != null
                 && (mViewFlags & ENABLED_MASK) == ENABLED
                 && li.mOnHoverListener.onHover(this, event)) {
@@ -7864,21 +8122,17 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         boolean result = false;
 
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_ENTER: {
-                if ((mViewFlags & ENABLED_MASK) == DISABLED) {
-                    return true;
-                }
-                // Long clickable items don't necessarily have to be clickable
-                if (((mViewFlags & CLICKABLE) == CLICKABLE ||
-                        (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
-                        (event.getRepeatCount() == 0)) {
-                    setPressed(true);
-                    checkForLongClick(0);
-                    return true;
-                }
-                break;
+        if (KeyEvent.isConfirmKey(keyCode)) {
+            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
+                return true;
+            }
+            // Long clickable items don't necessarily have to be clickable
+            if (((mViewFlags & CLICKABLE) == CLICKABLE ||
+                    (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
+                    (event.getRepeatCount() == 0)) {
+                setPressed(true);
+                checkForLongClick(0);
+                return true;
             }
         }
         return result;
@@ -7910,28 +8164,21 @@
      * @param event   The KeyEvent object that defines the button action.
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        boolean result = false;
+        if (KeyEvent.isConfirmKey(keyCode)) {
+            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
+                return true;
+            }
+            if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
+                setPressed(false);
 
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_ENTER: {
-                if ((mViewFlags & ENABLED_MASK) == DISABLED) {
-                    return true;
+                if (!mHasPerformedLongPress) {
+                    // This is a tap, so remove the longpress check
+                    removeLongPressCallback();
+                    return performClick();
                 }
-                if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
-                    setPressed(false);
-
-                    if (!mHasPerformedLongPress) {
-                        // This is a tap, so remove the longpress check
-                        removeLongPressCallback();
-
-                        result = performClick();
-                    }
-                }
-                break;
             }
         }
-        return result;
+        return false;
     }
 
     /**
@@ -8295,6 +8542,17 @@
 
     /**
      * Implement this method to handle touch screen motion events.
+     * <p>
+     * If this method is used to detect click actions, it is recommended that
+     * the actions be performed by implementing and calling
+     * {@link #performClick()}. This will ensure consistent system behavior,
+     * including:
+     * <ul>
+     * <li>obeying click sound preferences
+     * <li>dispatching OnClickListener calls
+     * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
+     * accessibility features are enabled
+     * </ul>
      *
      * @param event The motion event.
      * @return True if the event was handled, false otherwise.
@@ -8527,6 +8785,10 @@
      * @param mask Constant indicating the bit range that should be changed
      */
     void setFlags(int flags, int mask) {
+        final boolean accessibilityEnabled =
+                AccessibilityManager.getInstance(mContext).isEnabled();
+        final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility();
+
         int old = mViewFlags;
         mViewFlags = (mViewFlags & ~mask) | (flags & mask);
 
@@ -8551,12 +8813,10 @@
                  */
                 if (mParent != null) mParent.focusableViewAvailable(this);
             }
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                notifyAccessibilityStateChanged();
-            }
         }
 
-        if ((flags & VISIBILITY_MASK) == VISIBLE) {
+        final int newVisibility = flags & VISIBILITY_MASK;
+        if (newVisibility == VISIBLE) {
             if ((changed & VISIBILITY_MASK) != 0) {
                 /*
                  * If this view is becoming visible, invalidate it in case it changed while
@@ -8622,14 +8882,19 @@
         }
 
         if ((changed & VISIBILITY_MASK) != 0) {
+            // If the view is invisible, cleanup its display list to free up resources
+            if (newVisibility != VISIBLE) {
+                cleanupDraw();
+            }
+
             if (mParent instanceof ViewGroup) {
                 ((ViewGroup) mParent).onChildVisibilityChanged(this,
-                        (changed & VISIBILITY_MASK), (flags & VISIBILITY_MASK));
+                        (changed & VISIBILITY_MASK), newVisibility);
                 ((View) mParent).invalidate(true);
             } else if (mParent != null) {
                 mParent.invalidateChild(this, null);
             }
-            dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK));
+            dispatchVisibilityChanged(this, newVisibility);
         }
 
         if ((changed & WILL_NOT_CACHE_DRAWING) != 0) {
@@ -8668,19 +8933,30 @@
             }
         }
 
-        if (AccessibilityManager.getInstance(mContext).isEnabled()
-                && ((changed & FOCUSABLE) != 0 || (changed & CLICKABLE) != 0
-                        || (changed & LONG_CLICKABLE) != 0 || (changed & ENABLED) != 0)) {
-            notifyAccessibilityStateChanged();
+        if (accessibilityEnabled) {
+            if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0
+                    || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0) {
+                if (oldIncludeForAccessibility != includeForAccessibility()) {
+                    notifySubtreeAccessibilityStateChangedIfNeeded();
+                } else {
+                    notifyViewAccessibilityStateChangedIfNeeded(
+                            AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                }
+            } else if ((changed & ENABLED_MASK) != 0) {
+                notifyViewAccessibilityStateChangedIfNeeded(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+            }
         }
     }
 
     /**
      * Change the view's z order in the tree, so it's on top of other sibling
      * views. This ordering change may affect layout, if the parent container
-     * uses an order-dependent layout scheme (e.g., LinearLayout). This
+     * uses an order-dependent layout scheme (e.g., LinearLayout). Prior
+     * to {@link android.os.Build.VERSION_CODES#KITKAT} this
      * method should be followed by calls to {@link #requestLayout()} and
-     * {@link View#invalidate()} on the parent.
+     * {@link View#invalidate()} on the view's parent to force the parent to redraw
+     * with the new child ordering.
      *
      * @see ViewGroup#bringChildToFront(View)
      */
@@ -9378,9 +9654,11 @@
      */
     public void setPivotX(float pivotX) {
         ensureTransformationInfo();
-        mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
         final TransformationInfo info = mTransformationInfo;
-        if (info.mPivotX != pivotX) {
+        boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
+                PFLAG_PIVOT_EXPLICITLY_SET;
+        if (info.mPivotX != pivotX || !pivotSet) {
+            mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
             invalidateViewProperty(true, false);
             info.mPivotX = pivotX;
             info.mMatrixDirty = true;
@@ -9428,9 +9706,11 @@
      */
     public void setPivotY(float pivotY) {
         ensureTransformationInfo();
-        mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
         final TransformationInfo info = mTransformationInfo;
-        if (info.mPivotY != pivotY) {
+        boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
+                PFLAG_PIVOT_EXPLICITLY_SET;
+        if (info.mPivotY != pivotY || !pivotSet) {
+            mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
             invalidateViewProperty(true, false);
             info.mPivotY = pivotY;
             info.mMatrixDirty = true;
@@ -9515,7 +9795,7 @@
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9542,7 +9822,7 @@
             } else {
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9550,6 +9830,51 @@
     }
 
     /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public void setTransitionAlpha(float alpha) {
+        ensureTransformationInfo();
+        if (mTransformationInfo.mTransitionAlpha != alpha) {
+            mTransformationInfo.mTransitionAlpha = alpha;
+            mPrivateFlags &= ~PFLAG_ALPHA_SET;
+            invalidateViewProperty(true, false);
+            if (mDisplayList != null) {
+                mDisplayList.setAlpha(getFinalAlpha());
+            }
+        }
+    }
+
+    /**
+     * Calculates the visual alpha of this view, which is a combination of the actual
+     * alpha value and the transitionAlpha value (if set).
+     */
+    private float getFinalAlpha() {
+        if (mTransformationInfo != null) {
+            return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
+        }
+        return 1;
+    }
+
+    /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public float getTransitionAlpha() {
+        return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
+    }
+
+    /**
      * Top position of this view relative to its parent.
      *
      * @return The top of this view, in pixels.
@@ -9981,8 +10306,10 @@
      * is inside the view, where the area of the view is expanded by the slop factor.
      * This method is called while processing touch-move events to determine if the event
      * is still within the view.
+     *
+     * @hide
      */
-    private boolean pointInView(float localX, float localY, float slop) {
+    public boolean pointInView(float localX, float localY, float slop) {
         return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
                 localY < ((mBottom - mTop) + slop);
     }
@@ -10640,7 +10967,7 @@
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
         return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
-                ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
+                getFinalAlpha() >= 1.0f;
     }
 
     /**
@@ -11715,9 +12042,12 @@
             mPrivateFlags &= ~PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH;
         }
 
+        mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
+
         jumpDrawablesToCurrentState();
 
-        clearAccessibilityFocus();
+        resetSubtreeAccessibilityStateChanged();
+
         if (isFocused()) {
             InputMethodManager imm = InputMethodManager.peekInstance();
             imm.focusIn(this);
@@ -11855,10 +12185,15 @@
                     if (!canResolveLayoutDirection()) return false;
 
                     // Parent has not yet resolved, LTR is still the default
-                    if (!mParent.isLayoutDirectionResolved()) return false;
+                    try {
+                        if (!mParent.isLayoutDirectionResolved()) return false;
 
-                    if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                        mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
+                        if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                            mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
+                        }
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
                     }
                     break;
                 case LAYOUT_DIRECTION_RTL:
@@ -11884,13 +12219,20 @@
      * Check if layout direction resolution can be done.
      *
      * @return true if layout direction resolution can be done otherwise return false.
-     *
-     * @hide
      */
     public boolean canResolveLayoutDirection() {
         switch (getRawLayoutDirection()) {
             case LAYOUT_DIRECTION_INHERIT:
-                return (mParent != null) && mParent.canResolveLayoutDirection();
+                if (mParent != null) {
+                    try {
+                        return mParent.canResolveLayoutDirection();
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                    }
+                }
+                return false;
+
             default:
                 return true;
         }
@@ -11918,7 +12260,6 @@
 
     /**
      * @return true if layout direction has been resolved.
-     * @hide
      */
     public boolean isLayoutDirectionResolved() {
         return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED;
@@ -11934,17 +12275,19 @@
     }
 
     /**
-     * Resolve padding depending on layout direction.
+     * Resolves padding depending on layout direction, if applicable, and
+     * recomputes internal padding values to adjust for scroll bars.
      *
      * @hide
      */
     public void resolvePadding() {
+        final int resolvedLayoutDirection = getLayoutDirection();
+
         if (!isRtlCompatibilityMode()) {
             // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account.
             // If start / end padding are defined, they will be resolved (hence overriding) to
             // left / right or right / left depending on the resolved layout direction.
             // If start / end padding are not defined, use the left / right ones.
-            int resolvedLayoutDirection = getLayoutDirection();
             switch (resolvedLayoutDirection) {
                 case LAYOUT_DIRECTION_RTL:
                     if (mUserPaddingStart != UNDEFINED_PADDING) {
@@ -11973,12 +12316,11 @@
             }
 
             mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
-
-            internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight,
-                    mUserPaddingBottom);
-            onRtlPropertiesChanged(resolvedLayoutDirection);
         }
 
+        internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom);
+        onRtlPropertiesChanged(resolvedLayoutDirection);
+
         mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED;
     }
 
@@ -11999,6 +12341,7 @@
      */
     protected void onDetachedFromWindow() {
         mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
+        mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
 
         removeUnsetPressCallback();
         removeLongPressCallback();
@@ -12006,9 +12349,14 @@
         removeSendViewScrolledAccessibilityEventCallback();
 
         destroyDrawingCache();
-
         destroyLayer(false);
 
+        cleanupDraw();
+
+        mCurrentAnimation = null;
+    }
+
+    private void cleanupDraw() {
         if (mAttachInfo != null) {
             if (mDisplayList != null) {
                 mDisplayList.markDirty();
@@ -12017,12 +12365,38 @@
             mAttachInfo.mViewRootImpl.cancelInvalidate(this);
         } else {
             // Should never happen
-            clearDisplayList();
+            resetDisplayList();
         }
+    }
 
-        mCurrentAnimation = null;
+    /**
+     * This method ensures the hardware renderer is in a valid state
+     * before executing the specified action.
+     *
+     * This method will attempt to set a valid state even if the window
+     * the renderer is attached to was destroyed.
+     *
+     * This method is not guaranteed to work. If the hardware renderer
+     * does not exist or cannot be put in a valid state, this method
+     * will not executed the specified action.
+     *
+     * The specified action is executed synchronously.
+     *
+     * @param action The action to execute after the renderer is in a valid state
+     *
+     * @return True if the specified Runnable was executed, false otherwise
+     *
+     * @hide
+     */
+    public boolean executeHardwareAction(Runnable action) {
+        //noinspection SimplifiableIfStatement
+        if (mAttachInfo != null && mAttachInfo.mHardwareRenderer != null) {
+            return mAttachInfo.mHardwareRenderer.safelyRun(action);
+        }
+        return false;
+    }
 
-        resetAccessibilityStateChanged();
+    void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
     }
 
     /**
@@ -12185,6 +12559,61 @@
     }
 
     /**
+     * Cancel any deferred high-level input events that were previously posted to the event queue.
+     *
+     * <p>Many views post high-level events such as click handlers to the event queue
+     * to run deferred in order to preserve a desired user experience - clearing visible
+     * pressed states before executing, etc. This method will abort any events of this nature
+     * that are currently in flight.</p>
+     *
+     * <p>Custom views that generate their own high-level deferred input events should override
+     * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p>
+     *
+     * <p>This will also cancel pending input events for any child views.</p>
+     *
+     * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases.
+     * This will not impact newer events posted after this call that may occur as a result of
+     * lower-level input events still waiting in the queue. If you are trying to prevent
+     * double-submitted  events for the duration of some sort of asynchronous transaction
+     * you should also take other steps to protect against unexpected double inputs e.g. calling
+     * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when
+     * the transaction completes, tracking already submitted transaction IDs, etc.</p>
+     */
+    public final void cancelPendingInputEvents() {
+        dispatchCancelPendingInputEvents();
+    }
+
+    /**
+     * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight.
+     * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling.
+     */
+    void dispatchCancelPendingInputEvents() {
+        mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER;
+        onCancelPendingInputEvents();
+        if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) {
+            throw new SuperNotCalledException("View " + getClass().getSimpleName() +
+                    " did not call through to super.onCancelPendingInputEvents()");
+        }
+    }
+
+    /**
+     * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or
+     * a parent view.
+     *
+     * <p>This method is responsible for removing any pending high-level input events that were
+     * posted to the event queue to run later. Custom view classes that post their own deferred
+     * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or
+     * {@link android.os.Handler} should override this method, call
+     * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate.
+     * </p>
+     */
+    public void onCancelPendingInputEvents() {
+        removePerformClickCallback();
+        cancelLongPress();
+        mPrivateFlags3 |= PFLAG3_CALLED_SUPER;
+    }
+
+    /**
      * Store this view hierarchy's frozen state into the given container.
      *
      * @param container The SparseArray in which to save the view's state.
@@ -12519,16 +12948,26 @@
     public void buildLayer() {
         if (mLayerType == LAYER_TYPE_NONE) return;
 
-        if (mAttachInfo == null) {
+        final AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo == null) {
             throw new IllegalStateException("This view must be attached to a window first");
         }
 
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                if (mAttachInfo.mHardwareRenderer != null &&
-                        mAttachInfo.mHardwareRenderer.isEnabled() &&
-                        mAttachInfo.mHardwareRenderer.validate()) {
+                if (attachInfo.mHardwareRenderer != null &&
+                        attachInfo.mHardwareRenderer.isEnabled() &&
+                        attachInfo.mHardwareRenderer.validate()) {
                     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();
+                    }
                 }
                 break;
             case LAYER_TYPE_SOFTWARE:
@@ -12614,12 +13053,11 @@
             if (info != null && info.mHardwareRenderer != null &&
                     info.mHardwareRenderer.isEnabled() &&
                     (valid || info.mHardwareRenderer.validate())) {
+
+                info.mHardwareRenderer.cancelLayerUpdate(mHardwareLayer);
                 mHardwareLayer.destroy();
                 mHardwareLayer = null;
 
-                if (mDisplayList != null) {
-                    mDisplayList.reset();
-                }
                 invalidate(true);
                 invalidateParentCaches();
             }
@@ -12640,6 +13078,7 @@
      * @hide
      */
     protected void destroyHardwareResources() {
+        resetDisplayList();
         destroyLayer(true);
     }
 
@@ -12784,8 +13223,7 @@
                 mRecreateDisplayList = true;
             }
             if (displayList == null) {
-                final String name = getClass().getSimpleName();
-                displayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
+                displayList = mAttachInfo.mHardwareRenderer.createDisplayList(getClass().getName());
                 // If we're creating a new display list, make sure our parent gets invalidated
                 // since they will need to recreate their display list to account for this
                 // new child display list.
@@ -12888,6 +13326,12 @@
         }
     }
 
+    private void resetDisplayList() {
+        if (mDisplayList != null) {
+            mDisplayList.reset();
+        }
+    }
+
     /**
      * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
      *
@@ -13060,14 +13504,8 @@
                     // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
                     switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
                         case DRAWING_CACHE_QUALITY_AUTO:
-                            quality = Bitmap.Config.ARGB_8888;
-                            break;
                         case DRAWING_CACHE_QUALITY_LOW:
-                            quality = Bitmap.Config.ARGB_8888;
-                            break;
                         case DRAWING_CACHE_QUALITY_HIGH:
-                            quality = Bitmap.Config.ARGB_8888;
-                            break;
                         default:
                             quality = Bitmap.Config.ARGB_8888;
                             break;
@@ -13222,6 +13660,9 @@
         // Fast path for layouts with no backgrounds
         if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
             dispatchDraw(canvas);
+            if (mOverlay != null && !mOverlay.isEmpty()) {
+                mOverlay.getOverlayView().draw(canvas);
+            }
         } else {
             draw(canvas);
         }
@@ -13432,7 +13873,8 @@
             onAnimationStart();
         }
 
-        boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
+        final Transformation t = parent.getChildTransformation();
+        boolean more = a.getTransformation(drawingTime, t, 1f);
         if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
             if (parent.mInvalidationTransformation == null) {
                 parent.mInvalidationTransformation = new Transformation();
@@ -13440,7 +13882,7 @@
             invalidationTransform = parent.mInvalidationTransformation;
             a.getTransformation(drawingTime, invalidationTransform, 1f);
         } else {
-            invalidationTransform = parent.mChildTransformation;
+            invalidationTransform = t;
         }
 
         if (more) {
@@ -13493,23 +13935,21 @@
             if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
                     ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
                 ViewGroup parentVG = (ViewGroup) mParent;
-                final boolean hasTransform =
-                        parentVG.getChildStaticTransformation(this, parentVG.mChildTransformation);
-                if (hasTransform) {
-                    Transformation transform = parentVG.mChildTransformation;
-                    final int transformType = parentVG.mChildTransformation.getTransformationType();
+                final Transformation t = parentVG.getChildTransformation();
+                if (parentVG.getChildStaticTransformation(this, t)) {
+                    final int transformType = t.getTransformationType();
                     if (transformType != Transformation.TYPE_IDENTITY) {
                         if ((transformType & Transformation.TYPE_ALPHA) != 0) {
-                            alpha = transform.getAlpha();
+                            alpha = t.getAlpha();
                         }
                         if ((transformType & Transformation.TYPE_MATRIX) != 0) {
-                            displayList.setMatrix(transform.getMatrix());
+                            displayList.setMatrix(t.getMatrix());
                         }
                     }
                 }
             }
             if (mTransformationInfo != null) {
-                alpha *= mTransformationInfo.mAlpha;
+                alpha *= getFinalAlpha();
                 if (alpha < 1) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (onSetAlpha(multipliedAlpha)) {
@@ -13548,7 +13988,7 @@
         final int flags = parent.mGroupFlags;
 
         if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) {
-            parent.mChildTransformation.clear();
+            parent.getChildTransformation().clear();
             parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
         }
 
@@ -13576,7 +14016,7 @@
             if (concatMatrix) {
                 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
             }
-            transformToApply = parent.mChildTransformation;
+            transformToApply = parent.getChildTransformation();
         } else {
             if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) ==
                     PFLAG3_VIEW_IS_ANIMATING_TRANSFORM && mDisplayList != null) {
@@ -13586,12 +14026,11 @@
             }
             if (!useDisplayListProperties &&
                     (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
-                final boolean hasTransform =
-                        parent.getChildStaticTransformation(this, parent.mChildTransformation);
+                final Transformation t = parent.getChildTransformation();
+                final boolean hasTransform = parent.getChildStaticTransformation(this, t);
                 if (hasTransform) {
-                    final int transformType = parent.mChildTransformation.getTransformationType();
-                    transformToApply = transformType != Transformation.TYPE_IDENTITY ?
-                            parent.mChildTransformation : null;
+                    final int transformType = t.getTransformationType();
+                    transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null;
                     concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
                 }
             }
@@ -13699,8 +14138,8 @@
             }
         }
 
-        float alpha = useDisplayListProperties ? 1 : getAlpha();
-        if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
+        float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
+        if (transformToApply != null || alpha < 1 ||  !hasIdentityMatrix() ||
                 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
@@ -13757,7 +14196,7 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (useDisplayListProperties) {
-                            displayList.setAlpha(alpha * getAlpha());
+                            displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
                             final int scrollY = hasDisplayList ? 0 : sy;
@@ -13867,10 +14306,6 @@
         }
 
         if (more && hardwareAccelerated) {
-            // invalidation is the trigger to recreate display lists, so if we're using
-            // display lists to render, force an invalidate to allow the animation to
-            // continue drawing another frame
-            parent.invalidate(true);
             if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
                 // alpha animations should cause the child to recreate its display list
                 invalidate(true);
@@ -14280,12 +14715,19 @@
      */
     @SuppressWarnings({"unchecked"})
     public void layout(int l, int t, int r, int b) {
+        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
+            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
+            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
+        }
+
         int oldL = mLeft;
         int oldT = mTop;
         int oldB = mBottom;
         int oldR = mRight;
+
         boolean changed = isLayoutModeOptical(mParent) ?
                 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
+
         if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
             onLayout(changed, l, t, r, b);
             mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
@@ -14300,7 +14742,9 @@
                 }
             }
         }
+
         mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
+        mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
     }
 
     /**
@@ -14393,6 +14837,8 @@
             mPrivateFlags |= drawn;
 
             mBackgroundSizeChanged = true;
+
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
         return changed;
     }
@@ -14503,13 +14949,26 @@
      * @hide
      */
     protected void resolveDrawables() {
-        if (canResolveLayoutDirection()) {
-            if (mBackground != null) {
-                mBackground.setLayoutDirection(getLayoutDirection());
-            }
-            mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
-            onResolveDrawables(getLayoutDirection());
+        // Drawables resolution may need to happen before resolving the layout direction (which is
+        // done only during the measure() call).
+        // If the layout direction is not resolved yet, we cannot resolve the Drawables except in
+        // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT.
+        // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or
+        // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout
+        // direction to be resolved as its resolved value will be the same as its raw value.
+        if (!isLayoutDirectionResolved() &&
+                getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) {
+            return;
         }
+
+        final int layoutDirection = isLayoutDirectionResolved() ?
+                getLayoutDirection() : getRawLayoutDirection();
+
+        if (mBackground != null) {
+            mBackground.setLayoutDirection(layoutDirection);
+        }
+        mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
+        onResolveDrawables(layoutDirection);
     }
 
     /**
@@ -15151,15 +15610,15 @@
      * @param selected true if the view must be selected, false otherwise
      */
     public void setSelected(boolean selected) {
+        //noinspection DoubleNegation
         if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) {
             mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0);
             if (!selected) resetPressedState();
             invalidate(true);
             refreshDrawableState();
             dispatchSetSelected(selected);
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                notifyAccessibilityStateChanged();
-            }
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
 
@@ -15197,6 +15656,7 @@
      * @param activated true if the view must be activated, false otherwise
      */
     public void setActivated(boolean activated) {
+        //noinspection DoubleNegation
         if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) {
             mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0);
             invalidate(true);
@@ -15270,6 +15730,90 @@
     }
 
     /**
+     * Transforms a motion event from view-local coordinates to on-screen
+     * coordinates.
+     *
+     * @param ev the view-local motion event
+     * @return false if the transformation could not be applied
+     * @hide
+     */
+    public boolean toGlobalMotionEvent(MotionEvent ev) {
+        final AttachInfo info = mAttachInfo;
+        if (info == null) {
+            return false;
+        }
+
+        transformMotionEventToGlobal(ev);
+        ev.offsetLocation(info.mWindowLeft, info.mWindowTop);
+        return true;
+    }
+
+    /**
+     * Transforms a motion event from on-screen coordinates to view-local
+     * coordinates.
+     *
+     * @param ev the on-screen motion event
+     * @return false if the transformation could not be applied
+     * @hide
+     */
+    public boolean toLocalMotionEvent(MotionEvent ev) {
+        final AttachInfo info = mAttachInfo;
+        if (info == null) {
+            return false;
+        }
+
+        ev.offsetLocation(-info.mWindowLeft, -info.mWindowTop);
+        transformMotionEventToLocal(ev);
+        return true;
+    }
+
+    /**
+     * Recursive helper method that applies transformations in post-order.
+     *
+     * @param ev the on-screen motion event
+     */
+    private void transformMotionEventToLocal(MotionEvent ev) {
+        final ViewParent parent = mParent;
+        if (parent instanceof View) {
+            final View vp = (View) parent;
+            vp.transformMotionEventToLocal(ev);
+            ev.offsetLocation(vp.mScrollX, vp.mScrollY);
+        } else if (parent instanceof ViewRootImpl) {
+            final ViewRootImpl vr = (ViewRootImpl) parent;
+            ev.offsetLocation(0, vr.mCurScrollY);
+        }
+
+        ev.offsetLocation(-mLeft, -mTop);
+
+        if (!hasIdentityMatrix()) {
+            ev.transform(getInverseMatrix());
+        }
+    }
+
+    /**
+     * Recursive helper method that applies transformations in pre-order.
+     *
+     * @param ev the on-screen motion event
+     */
+    private void transformMotionEventToGlobal(MotionEvent ev) {
+        if (!hasIdentityMatrix()) {
+            ev.transform(getMatrix());
+        }
+
+        ev.offsetLocation(mLeft, mTop);
+
+        final ViewParent parent = mParent;
+        if (parent instanceof View) {
+            final View vp = (View) parent;
+            ev.offsetLocation(-vp.mScrollX, -vp.mScrollY);
+            vp.transformMotionEventToGlobal(ev);
+        } else if (parent instanceof ViewRootImpl) {
+            final ViewRootImpl vr = (ViewRootImpl) parent;
+            ev.offsetLocation(0, -vr.mCurScrollY);
+        }
+    }
+
+    /**
      * <p>Computes the coordinates of this view on the screen. The argument
      * must be an array of two integers. After the method returns, the array
      * contains the x and y location in that order.</p>
@@ -15637,7 +16181,7 @@
 
     private void setKeyedTag(int key, Object tag) {
         if (mKeyedTags == null) {
-            mKeyedTags = new SparseArray<Object>();
+            mKeyedTags = new SparseArray<Object>(2);
         }
 
         mKeyedTags.put(key, tag);
@@ -15774,6 +16318,8 @@
      * handle possible request-during-layout errors correctly.</p>
      */
     public void requestLayout() {
+        if (mMeasureCache != null) mMeasureCache.clear();
+
         if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
             // Only trigger request-during-layout logic if this is the view requesting it,
             // not the views in its parent hierarchy
@@ -15803,6 +16349,8 @@
      * on the parent.
      */
     public void forceLayout() {
+        if (mMeasureCache != null) mMeasureCache.clear();
+
         mPrivateFlags |= PFLAG_FORCE_LAYOUT;
         mPrivateFlags |= PFLAG_INVALIDATED;
     }
@@ -15836,6 +16384,11 @@
             widthMeasureSpec  = MeasureSpec.adjust(widthMeasureSpec,  optical ? -oWidth  : oWidth);
             heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
         }
+
+        // Suppress sign extension for the low bytes
+        long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
+        if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
+
         if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
                 widthMeasureSpec != mOldWidthMeasureSpec ||
                 heightMeasureSpec != mOldHeightMeasureSpec) {
@@ -15845,8 +16398,18 @@
 
             resolveRtlPropertiesIfNeeded();
 
-            // measure ourselves, this should set the measured dimension flag back
-            onMeasure(widthMeasureSpec, heightMeasureSpec);
+            int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
+                    mMeasureCache.indexOfKey(key);
+            if (cacheIndex < 0) {
+                // measure ourselves, this should set the measured dimension flag back
+                onMeasure(widthMeasureSpec, heightMeasureSpec);
+                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
+            } else {
+                long value = mMeasureCache.valueAt(cacheIndex);
+                // Casting a long to int drops the high 32 bits, no mask needed
+                setMeasuredDimension((int) (value >> 32), (int) value);
+                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
+            }
 
             // flag not set, setMeasuredDimension() was not invoked, we raise
             // an exception to warn the developer
@@ -15861,6 +16424,9 @@
 
         mOldWidthMeasureSpec = widthMeasureSpec;
         mOldHeightMeasureSpec = heightMeasureSpec;
+
+        mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
+                (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
     }
 
     /**
@@ -16352,7 +16918,9 @@
      * @param visibility  Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
      * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
      * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
-     * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+     * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
+     * {@link #SYSTEM_UI_FLAG_TRANSPARENT_STATUS},
+     * and {@link #SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION}.
      */
     public void setSystemUiVisibility(int visibility) {
         if (visibility != mSystemUiVisibility) {
@@ -16364,11 +16932,13 @@
     }
 
     /**
-     * Returns the last {@link #setSystemUiVisibility(int) that this view has requested.
+     * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested.
      * @return  Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
      * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
      * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
-     * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+     * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
+     * {@link #SYSTEM_UI_FLAG_TRANSPARENT_STATUS},
+     * and {@link #SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION}.
      */
     public int getSystemUiVisibility() {
         return mSystemUiVisibility;
@@ -16387,7 +16957,7 @@
     /**
      * Override to find out when the window's requested system UI visibility
      * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}.
-     * This is different from the callbacks recieved through
+     * This is different from the callbacks received through
      * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)}
      * in that this is only telling you about the local request of the window,
      * not the actual values applied by the system.
@@ -16706,8 +17276,8 @@
      * </p>
      */
     public boolean dispatchDragEvent(DragEvent event) {
-        //noinspection SimplifiableIfStatement
         ListenerInfo li = mListenerInfo;
+        //noinspection SimplifiableIfStatement
         if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                 && li.mOnDragListener.onDrag(this, event)) {
             return true;
@@ -17072,14 +17642,29 @@
                     }
 
                     // Parent has not yet resolved, so we still return the default
-                    if (!mParent.isTextDirectionResolved()) {
-                        mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
-                        // Resolution will need to happen again later
-                        return false;
+                    try {
+                        if (!mParent.isTextDirectionResolved()) {
+                            mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
+                            // Resolution will need to happen again later
+                            return false;
+                        }
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                        mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED |
+                                PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
+                        return true;
                     }
 
                     // Set current resolved direction to the same value as the parent's one
-                    final int parentResolvedDirection = mParent.getTextDirection();
+                    int parentResolvedDirection;
+                    try {
+                        parentResolvedDirection = mParent.getTextDirection();
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                        parentResolvedDirection = TEXT_DIRECTION_LTR;
+                    }
                     switch (parentResolvedDirection) {
                         case TEXT_DIRECTION_FIRST_STRONG:
                         case TEXT_DIRECTION_ANY_RTL:
@@ -17120,13 +17705,20 @@
      * Check if text direction resolution can be done.
      *
      * @return true if text direction resolution can be done otherwise return false.
-     *
-     * @hide
      */
     public boolean canResolveTextDirection() {
         switch (getRawTextDirection()) {
             case TEXT_DIRECTION_INHERIT:
-                return (mParent != null) && mParent.canResolveTextDirection();
+                if (mParent != null) {
+                    try {
+                        return mParent.canResolveTextDirection();
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                    }
+                }
+                return false;
+
             default:
                 return true;
         }
@@ -17156,8 +17748,6 @@
 
     /**
      * @return true if text direction is resolved.
-     *
-     * @hide
      */
     public boolean isTextDirectionResolved() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED;
@@ -17284,13 +17874,28 @@
                     }
 
                     // Parent has not yet resolved, so we still return the default
-                    if (!mParent.isTextAlignmentResolved()) {
-                        mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
-                        // Resolution will need to happen again later
-                        return false;
+                    try {
+                        if (!mParent.isTextAlignmentResolved()) {
+                            mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+                            // Resolution will need to happen again later
+                            return false;
+                        }
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                        mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED |
+                                PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+                        return true;
                     }
 
-                    final int parentResolvedTextAlignment = mParent.getTextAlignment();
+                    int parentResolvedTextAlignment;
+                    try {
+                        parentResolvedTextAlignment = mParent.getTextAlignment();
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                        parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY;
+                    }
                     switch (parentResolvedTextAlignment) {
                         case TEXT_ALIGNMENT_GRAVITY:
                         case TEXT_ALIGNMENT_TEXT_START:
@@ -17335,13 +17940,20 @@
      * Check if text alignment resolution can be done.
      *
      * @return true if text alignment resolution can be done otherwise return false.
-     *
-     * @hide
      */
     public boolean canResolveTextAlignment() {
         switch (getRawTextAlignment()) {
             case TEXT_DIRECTION_INHERIT:
-                return (mParent != null) && mParent.canResolveTextAlignment();
+                if (mParent != null) {
+                    try {
+                        return mParent.canResolveTextAlignment();
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                                " does not fully implement ViewParent", e);
+                    }
+                }
+                return false;
+
             default:
                 return true;
         }
@@ -17371,8 +17983,6 @@
 
     /**
      * @return true if text alignment is resolved.
-     *
-     * @hide
      */
     public boolean isTextAlignmentResolved() {
         return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED;
@@ -18116,6 +18726,11 @@
                 = new ViewTreeObserver.InternalInsetsInfo();
 
         /**
+         * Set to true when mGivenInternalInsets is non-empty.
+         */
+        boolean mHasNonEmptyGivenInternalInsets;
+
+        /**
          * All views in the window's hierarchy that serve as scroll containers,
          * used to determine if the window can be resized or must be panned
          * to adjust for a soft input area.
@@ -18749,6 +19364,79 @@
         }
     }
 
+    private class SendViewStateChangedAccessibilityEvent implements Runnable {
+        private int mChangeTypes = 0;
+        private boolean mPosted;
+        private boolean mPostedWithDelay;
+        private long mLastEventTimeMillis;
+
+        @Override
+        public void run() {
+            mPosted = false;
+            mPostedWithDelay = false;
+            mLastEventTimeMillis = SystemClock.uptimeMillis();
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                final AccessibilityEvent event = AccessibilityEvent.obtain();
+                event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+                event.setContentChangeTypes(mChangeTypes);
+                sendAccessibilityEventUnchecked(event);
+            }
+            mChangeTypes = 0;
+        }
+
+        public void runOrPost(int changeType) {
+            mChangeTypes |= changeType;
+
+            // If this is a live region or the child of a live region, collect
+            // all events from this frame and send them on the next frame.
+            if (inLiveRegion()) {
+                // If we're already posted with a delay, remove that.
+                if (mPostedWithDelay) {
+                    removeCallbacks(this);
+                    mPostedWithDelay = false;
+                }
+                // Only post if we're not already posted.
+                if (!mPosted) {
+                    post(this);
+                    mPosted = true;
+                }
+                return;
+            }
+
+            if (mPosted) {
+                return;
+            }
+            final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
+            final long minEventIntevalMillis =
+                    ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
+            if (timeSinceLastMillis >= minEventIntevalMillis) {
+                removeCallbacks(this);
+                run();
+            } else {
+                postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
+                mPosted = true;
+                mPostedWithDelay = true;
+            }
+        }
+    }
+
+    private boolean inLiveRegion() {
+        if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) {
+            return true;
+        }
+
+        ViewParent parent = getParent();
+        while (parent instanceof View) {
+            if (((View) parent).getAccessibilityLiveRegion()
+                    != View.ACCESSIBILITY_LIVE_REGION_NONE) {
+                return true;
+            }
+            parent = parent.getParent();
+        }
+
+        return false;
+    }
+
     /**
      * Dump all private flags in readable format, useful for documentation and
      * sanity checking.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 499075e..c3f064f 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -97,6 +97,13 @@
     private static final int DOUBLE_TAP_TIMEOUT = 300;
 
     /**
+     * Defines the minimum duration in milliseconds between the first tap's up event and
+     * the second tap's down event for an interaction to be considered a
+     * double-tap.
+     */
+    private static final int DOUBLE_TAP_MIN_TIME = 40;
+
+    /**
      * Defines the maximum duration in milliseconds between a touch pad
      * touch and release for a given touch to be considered a tap (click) as
      * opposed to a hover movement gesture.
@@ -291,7 +298,7 @@
         if (!sHasPermanentMenuKeySet) {
             IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
             try {
-                sHasPermanentMenuKey = !wm.hasSystemNavBar() && !wm.hasNavigationBar();
+                sHasPermanentMenuKey = !wm.hasNavigationBar();
                 sHasPermanentMenuKeySet = true;
             } catch (RemoteException ex) {
                 sHasPermanentMenuKey = false;
@@ -436,6 +443,17 @@
     }
 
     /**
+     * @return the minimum duration in milliseconds between the first tap's
+     * up event and the second tap's down event for an interaction to be considered a
+     * double-tap.
+     *
+     * @hide
+     */
+    public static int getDoubleTapMinTime() {
+        return DOUBLE_TAP_MIN_TIME;
+    }
+
+    /**
      * @return the maximum duration in milliseconds between a touch pad
      * touch and release for a given touch to be considered a tap (click) as
      * opposed to a hover movement gesture.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index ed128b0..92e5e96 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -698,6 +698,11 @@
                 captureViewLayer(group.getChildAt(i), clientStream, localVisible);
             }
         }
+
+        if (view.mOverlay != null) {
+            ViewGroup overlayContainer = view.getOverlay().mOverlayViewGroup;
+            captureViewLayer(overlayContainer, clientStream, localVisible);
+        }
     }
 
     private static void outputDisplayList(View root, String parameter) throws IOException {
@@ -743,7 +748,7 @@
         }
     }
 
-    private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) {
+    private static Bitmap performViewCapture(final View captureView, final boolean skipChildren) {
         if (captureView != null) {
             final CountDownLatch latch = new CountDownLatch(1);
             final Bitmap[] cache = new Bitmap[1];
@@ -752,7 +757,7 @@
                 public void run() {
                     try {
                         cache[0] = captureView.createSnapshot(
-                                Bitmap.Config.ARGB_8888, 0, skpiChildren);
+                                Bitmap.Config.ARGB_8888, 0, skipChildren);
                     } catch (OutOfMemoryError e) {
                         Log.w("View", "Out of memory for bitmap");
                     } finally {
@@ -815,6 +820,13 @@
             } else if (isRequestedView(view, className, hashCode)) {
                 return view;
             }
+            if (view.mOverlay != null) {
+                final View found = findView((ViewGroup) view.mOverlay.mOverlayViewGroup,
+                        className, hashCode);
+                if (found != null) {
+                    return found;
+                }
+            }
             if (view instanceof HierarchyHandler) {
                 final View found = ((HierarchyHandler)view)
                         .findHierarchyView(className, hashCode);
@@ -823,12 +835,19 @@
                 }
             }
         }
-
         return null;
     }
 
     private static boolean isRequestedView(View view, String className, int hashCode) {
-        return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
+        if (view.hashCode() == hashCode) {
+            String viewClassName = view.getClass().getName();
+            if (className.equals("ViewOverlay")) {
+                return viewClassName.equals("android.view.ViewOverlay$OverlayViewGroup");
+            } else {
+                return className.equals(viewClassName);
+            }
+        }
+        return false;
     }
 
     private static void dumpViewHierarchy(Context context, ViewGroup group,
@@ -850,6 +869,12 @@
             } else {
                 dumpView(context, view, out, level + 1, includeProperties);
             }
+            if (view.mOverlay != null) {
+                ViewOverlay overlay = view.getOverlay();
+                ViewGroup overlayContainer = overlay.mOverlayViewGroup;
+                dumpViewHierarchy(context, overlayContainer, out, level + 2, skipChildren,
+                        includeProperties);
+            }
         }
         if (group instanceof HierarchyHandler) {
             ((HierarchyHandler)group).dumpViewHierarchyWithProperties(out, level + 1);
@@ -863,7 +888,11 @@
             for (int i = 0; i < level; i++) {
                 out.write(' ');
             }
-            out.write(view.getClass().getName());
+            String className = view.getClass().getName();
+            if (className.equals("android.view.ViewOverlay$OverlayViewGroup")) {
+                className = "ViewOverlay";
+            }
+            out.write(className);
             out.write('@');
             out.write(Integer.toHexString(view.hashCode()));
             out.write(' ');
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 3aa4cfb..9414237 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -38,6 +38,7 @@
 import android.util.Pools.SynchronizedPool;
 import android.util.SparseArray;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -130,7 +131,7 @@
      * A Transformation used when drawing children, to
      * apply on the child being drawn.
      */
-    final Transformation mChildTransformation = new Transformation();
+    private Transformation mChildTransformation;
 
     /**
      * Used to track the current invalidation region.
@@ -154,7 +155,7 @@
     private boolean mChildAcceptsDrag;
 
     // Used during drag dispatch
-    private final PointF mLocalPoint = new PointF();
+    private PointF mLocalPoint;
 
     // Layout animation
     private LayoutAnimationController mLayoutAnimationController;
@@ -206,7 +207,7 @@
     /**
      * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
      */
-    private int mLayoutMode = DEFAULT_LAYOUT_MODE;
+    private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
 
     /**
      * NOTE: If you change the flags below make sure to reflect the changes
@@ -347,6 +348,14 @@
     private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
 
     /**
+     * When true, indicates that a layoutMode has been explicitly set, either with
+     * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
+     * This distinguishes the situation in which a layout mode was inherited from
+     * one of the ViewGroup's ancestors and cached locally.
+     */
+    private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
+
+    /**
      * Indicates which types of drawing caches are to be kept in memory.
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
@@ -375,6 +384,8 @@
 
     // Layout Modes
 
+    private static final int LAYOUT_MODE_UNDEFINED = -1;
+
     /**
      * This constant is a {@link #setLayoutMode(int) layoutMode}.
      * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
@@ -391,7 +402,7 @@
     public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
 
     /** @hide */
-    public static int DEFAULT_LAYOUT_MODE = LAYOUT_MODE_CLIP_BOUNDS;
+    public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
 
     /**
      * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
@@ -533,7 +544,7 @@
                     }
                     break;
                 case R.styleable.ViewGroup_layoutMode:
-                    setLayoutMode(a.getInt(attr, DEFAULT_LAYOUT_MODE));
+                    setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
                     break;
             }
         }
@@ -732,8 +743,6 @@
 
     /**
      * Called when a child view has changed whether or not it is tracking transient state.
-     *
-     * @hide
      */
     public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
         final boolean oldHasTransientState = hasTransientState();
@@ -754,9 +763,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     @Override
     public boolean hasTransientState() {
         return mChildCountWithTransientState > 0 || super.hasTransientState();
@@ -1118,9 +1124,16 @@
             removeFromArray(index);
             addInArray(child, mChildrenCount);
             child.mParent = this;
+            requestLayout();
+            invalidate();
         }
     }
 
+    private PointF getLocalPoint() {
+        if (mLocalPoint == null) mLocalPoint = new PointF();
+        return mLocalPoint;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -1134,6 +1147,8 @@
         ViewRootImpl root = getViewRootImpl();
 
         // Dispatch down the view hierarchy
+        final PointF localPoint = getLocalPoint();
+
         switch (event.mAction) {
         case DragEvent.ACTION_DRAG_STARTED: {
             // clear state to recalculate which views we drag over
@@ -1194,7 +1209,7 @@
 
         case DragEvent.ACTION_DRAG_LOCATION: {
             // Find the [possibly new] drag target
-            final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
+            final View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
 
             // If we've changed apparent drag target, tell the view root which view
             // we're over now [for purposes of the eventual drag-recipient-changed
@@ -1228,8 +1243,8 @@
 
             // Dispatch the actual drag location notice, localized into its coordinates
             if (target != null) {
-                event.mX = mLocalPoint.x;
-                event.mY = mLocalPoint.y;
+                event.mX = localPoint.x;
+                event.mY = localPoint.y;
 
                 retval = target.dispatchDragEvent(event);
 
@@ -1263,11 +1278,11 @@
 
         case DragEvent.ACTION_DROP: {
             if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
-            View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
+            View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
             if (target != null) {
                 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "   dispatch drop to " + target);
-                event.mX = mLocalPoint.x;
-                event.mY = mLocalPoint.y;
+                event.mX = localPoint.x;
+                event.mY = localPoint.y;
                 retval = target.dispatchDragEvent(event);
                 event.mX = tx;
                 event.mY = ty;
@@ -1690,16 +1705,6 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public void childAccessibilityStateChanged(View child) {
-        if (mParent != null) {
-            mParent.childAccessibilityStateChanged(child);
-        }
-    }
-
-    /**
      * Implement this method to intercept hover events before they are handled
      * by child views.
      * <p>
@@ -2523,17 +2528,29 @@
         event.setClassName(ViewGroup.class.getName());
     }
 
-    /**
-     * @hide
-     */
     @Override
-    public void resetAccessibilityStateChanged() {
-        super.resetAccessibilityStateChanged();
+    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
+        // If this is a live region, we should send a subtree change event
+        // from this view. Otherwise, we can let it propagate up.
+        if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
+            notifyViewAccessibilityStateChangedIfNeeded(changeType);
+        } else if (mParent != null) {
+            try {
+                mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
+            } catch (AbstractMethodError e) {
+                Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                        " does not fully implement ViewParent", e);
+            }
+        }
+    }
+
+    @Override
+    void resetSubtreeAccessibilityStateChanged() {
+        super.resetSubtreeAccessibilityStateChanged();
         View[] children = mChildren;
         final int childCount = mChildrenCount;
         for (int i = 0; i < childCount; i++) {
-            View child = children[i];
-            child.resetAccessibilityStateChanged();
+            children[i].resetSubtreeAccessibilityStateChanged();
         }
     }
 
@@ -2773,8 +2790,8 @@
         return (int) (dips * scale + 0.5f);
     }
 
-    private void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
-                                 int lineLength, int lineWidth) {
+    private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
+            int lineLength, int lineWidth) {
         drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
         drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
         drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
@@ -3170,6 +3187,17 @@
         }
     }
 
+    @Override
+    void dispatchCancelPendingInputEvents() {
+        super.dispatchCancelPendingInputEvents();
+
+        final View[] children = mChildren;
+        final int count = mChildrenCount;
+        for (int i = 0; i < count; i++) {
+            children[i].dispatchCancelPendingInputEvents();
+        }
+    }
+
     /**
      * When this property is set to true, this ViewGroup supports static transformations on
      * children; this causes
@@ -3204,6 +3232,13 @@
         return false;
     }
 
+    Transformation getChildTransformation() {
+        if (mChildTransformation == null) {
+            mChildTransformation = new Transformation();
+        }
+        return mChildTransformation;
+    }
+
     /**
      * {@hide}
      */
@@ -3451,6 +3486,24 @@
         }
     }
 
+    private void clearCachedLayoutMode() {
+        if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
+           mLayoutMode = LAYOUT_MODE_UNDEFINED;
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        clearCachedLayoutMode();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        clearCachedLayoutMode();
+    }
+
     /**
      * Adds a view during layout. This is useful if in your onLayout() method,
      * you need to add more views (as does the list view for example).
@@ -3565,6 +3618,10 @@
         if (child.hasTransientState()) {
             childHasTransientStateChanged(child, true);
         }
+
+        if (child.isImportantForAccessibility() && child.getVisibility() != View.GONE) {
+            notifySubtreeAccessibilityStateChangedIfNeeded();
+        }
     }
 
     private void addInArray(View child, int index) {
@@ -3804,6 +3861,10 @@
         }
 
         onViewRemoved(view);
+
+        if (view.isImportantForAccessibility() && view.getVisibility() != View.GONE) {
+            notifySubtreeAccessibilityStateChangedIfNeeded();
+        }
     }
 
     /**
@@ -3812,13 +3873,19 @@
      * the ViewGroup will be animated according to the animations defined in that LayoutTransition
      * object. By default, the transition object is null (so layout changes are not animated).
      *
+     * <p>Replacing a non-null transition will cause that previous transition to be
+     * canceled, if it is currently running, to restore this container to
+     * its correct post-transition state.</p>
+     *
      * @param transition The LayoutTransition object that will animated changes in layout. A value
      * of <code>null</code> means no transition will run on layout changes.
      * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
      */
     public void setLayoutTransition(LayoutTransition transition) {
         if (mTransition != null) {
-            mTransition.removeTransitionListener(mLayoutTransitionListener);
+            LayoutTransition previousTransition = mTransition;
+            previousTransition.cancel();
+            previousTransition.removeTransitionListener(mLayoutTransitionListener);
         }
         mTransition = transition;
         if (mTransition != null) {
@@ -4380,8 +4447,10 @@
     /**
      * Quick invalidation method that simply transforms the dirty rect into the parent's
      * coordinate system, pruning the invalidation if the parent has already been invalidated.
+     *
+     * @hide
      */
-    private ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
+    protected ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
         if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
                 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
             dirty.offset(left - mScrollX, top - mScrollY);
@@ -4754,6 +4823,10 @@
         setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
     }
 
+    private boolean hasBooleanFlag(int flag) {
+        return (mGroupFlags & flag) == flag;
+    }
+
     private void setBooleanFlag(int flag, boolean value) {
         if (value) {
             mGroupFlags |= flag;
@@ -4797,24 +4870,63 @@
         mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
     }
 
+    private void setLayoutMode(int layoutMode, boolean explicitly) {
+        mLayoutMode = layoutMode;
+        setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
+    }
+
     /**
-     * Returns the basis of alignment during layout operations on this view group:
+     * Recursively traverse the view hierarchy, resetting the layoutMode of any
+     * descendants that had inherited a different layoutMode from a previous parent.
+     * Recursion terminates when a descendant's mode is:
+     * <ul>
+     *     <li>Undefined</li>
+     *     <li>The same as the root node's</li>
+     *     <li>A mode that had been explicitly set</li>
+     * <ul/>
+     * The first two clauses are optimizations.
+     * @param layoutModeOfRoot
+     */
+    @Override
+    void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
+        if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
+            mLayoutMode == layoutModeOfRoot ||
+            hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
+            return;
+        }
+        setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
+
+        // apply recursively
+        for (int i = 0, N = getChildCount(); i < N; i++) {
+            getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
+        }
+    }
+
+    /**
+     * Returns the basis of alignment during layout operations on this ViewGroup:
      * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
+     * <p>
+     * If no layoutMode was explicitly set, either programmatically or in an XML resource,
+     * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
+     * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
      *
      * @return the layout mode to use during layout operations
      *
      * @see #setLayoutMode(int)
      */
     public int getLayoutMode() {
+        if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
+            int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
+                    ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
+            setLayoutMode(inheritedLayoutMode, false);
+        }
         return mLayoutMode;
     }
 
     /**
-     * Sets the basis of alignment during the layout of this view group.
+     * Sets the basis of alignment during the layout of this ViewGroup.
      * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
      * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
-     * <p>
-     * The default is {@link #LAYOUT_MODE_CLIP_BOUNDS}.
      *
      * @param layoutMode the layout mode to use during layout operations
      *
@@ -4823,7 +4935,8 @@
      */
     public void setLayoutMode(int layoutMode) {
         if (mLayoutMode != layoutMode) {
-            mLayoutMode = layoutMode;
+            invalidateInheritedLayoutMode(layoutMode);
+            setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
             requestLayout();
         }
     }
@@ -5268,6 +5381,18 @@
     }
 
     /**
+     * Returns whether layout calls on this container are currently being
+     * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
+     *
+     * @return true if layout calls are currently suppressed, false otherwise.
+     *
+     * @hide
+     */
+    public boolean isLayoutSuppressed() {
+        return mSuppressLayout;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -6343,7 +6468,7 @@
      */
     private static final class TouchTarget {
         private static final int MAX_RECYCLED = 32;
-        private static final Object sRecycleLock = new Object();
+        private static final Object sRecycleLock = new Object[0];
         private static TouchTarget sRecycleBin;
         private static int sRecycledCount;
 
@@ -6395,7 +6520,7 @@
     /* Describes a hovered view. */
     private static final class HoverTarget {
         private static final int MAX_RECYCLED = 32;
-        private static final Object sRecycleLock = new Object();
+        private static final Object sRecycleLock = new Object[0];
         private static HoverTarget sRecycleBin;
         private static int sRecycledCount;
 
@@ -6614,8 +6739,9 @@
         return sDebugPaint;
     }
 
-    private void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
+    private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
         if (sDebugLines== null) {
+            // TODO: This won't work with multiple UI threads in a single process
             sDebugLines = new float[16];
         }
 
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 5510939..975931a 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -15,6 +15,7 @@
  */
 package android.view;
 
+import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -169,6 +170,14 @@
                     child.offsetTopAndBottom(parentLocation[1] - hostViewLocation[1]);
                 }
                 parent.removeView(child);
+                if (parent.getLayoutTransition() != null) {
+                    // LayoutTransition will cause the child to delay removal - cancel it
+                    parent.getLayoutTransition().cancel(LayoutTransition.DISAPPEARING);
+                }
+                // fail-safe if view is still attached for any reason
+                if (child.getParent() != null) {
+                    child.mParent = null;
+                }
             }
             super.addView(child);
         }
@@ -291,6 +300,17 @@
             }
         }
 
+        /**
+         * @hide
+         */
+        @Override
+        protected ViewParent invalidateChildInParentFast(int left, int top, Rect dirty) {
+            if (mHostView instanceof ViewGroup) {
+                return ((ViewGroup) mHostView).invalidateChildInParentFast(left, top, dirty);
+            }
+            return null;
+        }
+
         @Override
         public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
             if (mHostView != null) {
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index d79aa7e..01376934 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -148,9 +148,11 @@
     /**
      * Change the z order of the child so it's on top of all other children.
      * This ordering change may affect layout, if this container
-     * uses an order-dependent layout scheme (e.g., LinearLayout). This
+     * uses an order-dependent layout scheme (e.g., LinearLayout). Prior
+     * to {@link android.os.Build.VERSION_CODES#KITKAT} this
      * method should be followed by calls to {@link #requestLayout()} and
-     * {@link View#invalidate()} on this parent.
+     * {@link View#invalidate()} on this parent to force the parent to redraw
+     * with the new child ordering.
      * 
      * @param child The child to bring to the top of the z order
      */
@@ -269,10 +271,25 @@
     /**
      * Called when a child view now has or no longer is tracking transient state.
      *
+     * <p>"Transient state" is any state that a View might hold that is not expected to
+     * be reflected in the data model that the View currently presents. This state only
+     * affects the presentation to the user within the View itself, such as the current
+     * state of animations in progress or the state of a text selection operation.</p>
+     *
+     * <p>Transient state is useful for hinting to other components of the View system
+     * that a particular view is tracking something complex but encapsulated.
+     * A <code>ListView</code> for example may acknowledge that list item Views
+     * with transient state should be preserved within their position or stable item ID
+     * instead of treating that view as trivially replaceable by the backing adapter.
+     * This allows adapter implementations to be simpler instead of needing to track
+     * the state of item view animations in progress such that they could be restored
+     * in the event of an unexpected recycling and rebinding of attached item views.</p>
+     *
+     * <p>This method is called on a parent view when a child view or a view within
+     * its subtree begins or ends tracking of internal transient state.</p>
+     *
      * @param child Child view whose state has changed
      * @param hasTransientState true if this child has transient state
-     *
-     * @hide
      */
     public void childHasTransientStateChanged(View child, boolean hasTransientState);
 
@@ -292,21 +309,27 @@
     public ViewParent getParentForAccessibility();
 
     /**
-     * A child notifies its parent that its state for accessibility has changed.
-     * That is some of the child properties reported to accessibility services has
-     * changed, hence the interested services have to be notified for the new state.
-     *
-     * @hide
+     * Notifies a view parent that the accessibility state of one of its
+     * descendants has changed and that the structure of the subtree is
+     * different.
+     * @param child The direct child whose subtree has changed.
+     * @param source The descendant view that changed.
+     * @param changeType A bit mask of the types of changes that occurred. One
+     *            or more of:
+     *            <ul>
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
+     *            </ul>
      */
-    public void childAccessibilityStateChanged(View child);
+    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType);
 
     /**
      * Tells if this view parent can resolve the layout direction.
      * See {@link View#setLayoutDirection(int)}
      *
      * @return True if this view parent can resolve the layout direction.
-     *
-     * @hide
      */
     public boolean canResolveLayoutDirection();
 
@@ -315,8 +338,6 @@
      * See {@link View#setLayoutDirection(int)}
      *
      * @return True if this view parent layout direction is resolved.
-     *
-     * @hide
      */
     public boolean isLayoutDirectionResolved();
 
@@ -325,8 +346,6 @@
      *
      * @return {@link View#LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
      * {@link View#LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
-     *
-     * @hide
      */
     public int getLayoutDirection();
 
@@ -335,8 +354,6 @@
      * See {@link View#setTextDirection(int)}
      *
      * @return True if this view parent can resolve the text direction.
-     *
-     * @hide
      */
     public boolean canResolveTextDirection();
 
@@ -345,8 +362,6 @@
      * See {@link View#setTextDirection(int)}
      *
      * @return True if this view parent text direction is resolved.
-     *
-     * @hide
      */
     public boolean isTextDirectionResolved();
 
@@ -360,8 +375,6 @@
      * {@link View#TEXT_DIRECTION_LTR},
      * {@link View#TEXT_DIRECTION_RTL},
      * {@link View#TEXT_DIRECTION_LOCALE}
-     *
-     * @hide
      */
     public int getTextDirection();
 
@@ -370,8 +383,6 @@
      * See {@link View#setTextAlignment(int)}
      *
      * @return True if this view parent can resolve the text alignment.
-     *
-     * @hide
      */
     public boolean canResolveTextAlignment();
 
@@ -380,8 +391,6 @@
      * See {@link View#setTextAlignment(int)}
      *
      * @return True if this view parent text alignment is resolved.
-     *
-     * @hide
      */
     public boolean isTextAlignmentResolved();
 
@@ -396,8 +405,6 @@
      * {@link View#TEXT_ALIGNMENT_TEXT_END},
      * {@link View#TEXT_ALIGNMENT_VIEW_START},
      * {@link View#TEXT_ALIGNMENT_VIEW_END}
-     *
-     * @hide
      */
     public int getTextAlignment();
 }
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index e6bf420..67a94be 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -93,11 +93,16 @@
     private boolean mInterpolatorSet = false;
 
     /**
-     * Listener for the lifecycle events of the underlying 
+     * Listener for the lifecycle events of the underlying ValueAnimator object.
      */
     private Animator.AnimatorListener mListener = null;
 
     /**
+     * Listener for the update events of the underlying ValueAnimator object.
+     */
+    private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
+
+    /**
      * A lazily-created ValueAnimator used in order to get some default animator properties
      * (duration, start delay, interpolator, etc.).
      */
@@ -353,7 +358,10 @@
      * Sets a listener for events in the underlying Animators that run the property
      * animations.
      *
-     * @param listener The listener to be called with AnimatorListener events.
+     * @see Animator.AnimatorListener
+     *
+     * @param listener The listener to be called with AnimatorListener events. A value of
+     * <code>null</code> removes any existing listener.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
@@ -362,6 +370,25 @@
     }
 
     /**
+     * Sets a listener for update events in the underlying ValueAnimator that runs
+     * the property animations. Note that the underlying animator is animating between
+     * 0 and 1 (these values are then turned into the actual property values internally
+     * by ViewPropertyAnimator). So the animator cannot give information on the current
+     * values of the properties being animated by this ViewPropertyAnimator, although
+     * the view object itself can be queried to get the current values.
+     *
+     * @see android.animation.ValueAnimator.AnimatorUpdateListener
+     *
+     * @param listener The listener to be called with update events. A value of
+     * <code>null</code> removes any existing listener.
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
+        mUpdateListener = listener;
+        return this;
+    }
+
+    /**
      * Starts the currently pending property animations immediately. Calling <code>start()</code>
      * is optional because all animations start automatically at the next opportunity. However,
      * if the animations are needed to start immediately and synchronously (not at the time when
@@ -675,6 +702,9 @@
             @Override
             public void run() {
                 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                if (mView.isAttachedToWindow()) {
+                    mView.buildLayer();
+                }
             }
         };
         final int currentLayerType = mView.getLayerType();
@@ -1073,6 +1103,9 @@
             } else {
                 mView.invalidateViewProperty(false, false);
             }
+            if (mUpdateListener != null) {
+                mUpdateListener.onAnimationUpdate(animation);
+            }
         }
     }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6b2ed91..89c74f1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -23,7 +23,6 @@
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -69,6 +68,7 @@
 import android.view.animation.Interpolator;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.Surface.OutOfResourcesException;
 import android.widget.Scroller;
 
 import com.android.internal.R;
@@ -108,13 +108,12 @@
     private static final boolean DEBUG_FPS = false;
     private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
 
-    private static final boolean USE_RENDER_THREAD = false;
-
     /**
      * Set this system property to true to force the view hierarchy to render
      * at 60 Hz. This can be used to measure the potential framerate.
      */
-    private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
+    private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
+    private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
 
     /**
      * Maximum time we allow the user to roll the trackball enough to generate
@@ -126,14 +125,10 @@
 
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
     static boolean sFirstDrawComplete = false;
-    
+
     static final ArrayList<ComponentCallbacks> sConfigCallbacks
             = new ArrayList<ComponentCallbacks>();
 
-    private static boolean sUseRenderThread = false;
-    private static boolean sRenderThreadQueried = false;
-    private static final Object[] sRenderThreadQueryLock = new Object[0];
-
     final Context mContext;
     final IWindowSession mWindowSession;
     final Display mDisplay;
@@ -167,14 +162,14 @@
     // Set to true if the owner of this window is in the stopped state,
     // so the window should no longer be active.
     boolean mStopped = false;
-    
+
     boolean mLastInCompatMode = false;
 
     SurfaceHolder.Callback2 mSurfaceHolderCallback;
     BaseSurfaceHolder mSurfaceHolder;
     boolean mIsCreating;
     boolean mDrawingAllowed;
-    
+
     final Region mTransparentRegion;
     final Region mPreviousTransparentRegion;
 
@@ -192,7 +187,7 @@
     InputQueue mInputQueue;
     FallbackEventHandler mFallbackEventHandler;
     Choreographer mChoreographer;
-    
+
     final Rect mTempRect; // used in the transaction to not thrash the heap.
     final Rect mVisRect; // used to retrieve visible rect of focused view.
 
@@ -235,6 +230,8 @@
     InputStage mFirstInputStage;
     InputStage mFirstPostImeInputStage;
 
+    boolean mFlipControllerFallbackKeys;
+
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
 
@@ -245,7 +242,7 @@
     boolean mAdded;
     boolean mAddedTouchMode;
 
-    final CompatibilityInfoHolder mCompatibilityInfo;
+    final DisplayAdjustments mDisplayAdjustments;
 
     // These are accessed by multiple threads.
     final Rect mWinFrame; // frame given by window manager.
@@ -281,18 +278,20 @@
     volatile Object mLocalDragState;
     final PointF mDragPoint = new PointF();
     final PointF mLastTouchPoint = new PointF();
-    
-    private boolean mProfileRendering;    
+
+    private boolean mProfileRendering;
     private Choreographer.FrameCallback mRenderProfiler;
     private boolean mRenderProfilingEnabled;
 
+    private boolean mMediaDisabled;
+
     // Variables to track frames per second, enabled via DEBUG_FPS flag
     private long mFpsStartTime = -1;
     private long mFpsPrevTime = -1;
     private int mFpsNumFrames;
 
     private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
-    
+
     /**
      * see {@link #playSoundEffect(int)}
      */
@@ -317,6 +316,9 @@
 
     private int mViewLayoutDirectionInitial;
 
+    /** Set to true once doDie() has been called. */
+    private boolean mRemoved;
+
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -330,15 +332,14 @@
         int localValue;
         int localChanges;
     }
-    
+
     public ViewRootImpl(Context context, Display display) {
         mContext = context;
         mWindowSession = WindowManagerGlobal.getWindowSession();
         mDisplay = display;
         mBasePackageName = context.getBasePackageName();
 
-        CompatibilityInfoHolder cih = display.getCompatibilityInfo();
-        mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();
+        mDisplayAdjustments = display.getDisplayAdjustments();
 
         mThread = Thread.currentThread();
         mLocation = new WindowLeaked(null);
@@ -367,41 +368,14 @@
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
         mChoreographer = Choreographer.getInstance();
+        mFlipControllerFallbackKeys =
+            context.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
 
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mAttachInfo.mScreenOn = powerManager.isScreenOn();
         loadSystemProperties();
     }
 
-    /**
-     * @return True if the application requests the use of a separate render thread,
-     *         false otherwise
-     */
-    private static boolean isRenderThreadRequested(Context context) {
-        if (USE_RENDER_THREAD) {
-            synchronized (sRenderThreadQueryLock) {
-                if (!sRenderThreadQueried) {
-                    final PackageManager packageManager = context.getPackageManager();
-                    final String packageName = context.getApplicationInfo().packageName;
-                    try {
-                        ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
-                                PackageManager.GET_META_DATA);
-                        if (applicationInfo.metaData != null) {
-                            sUseRenderThread = applicationInfo.metaData.getBoolean(
-                                    "android.graphics.renderThread", false);
-                        }
-                    } catch (PackageManager.NameNotFoundException e) {
-                    } finally {
-                        sRenderThreadQueried = true;
-                    }
-                }
-                return sUseRenderThread;
-            }
-        } else {
-            return false;
-        }
-    }
-
     public static void addFirstDrawHandler(Runnable callback) {
         synchronized (sFirstDrawHandlers) {
             if (!sFirstDrawComplete) {
@@ -409,13 +383,13 @@
             }
         }
     }
-    
+
     public static void addConfigCallback(ComponentCallbacks callback) {
         synchronized (sConfigCallbacks) {
             sConfigCallbacks.add(callback);
         }
     }
-    
+
     // FIXME for perf testing only
     private boolean mProfile = false;
 
@@ -474,12 +448,13 @@
                     }
                 }
 
-                CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
+                CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
+                mDisplayAdjustments.setActivityToken(attrs.token);
 
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
-                    enableHardwareAcceleration(mView.getContext(), attrs);
+                    enableHardwareAcceleration(attrs);
                 }
 
                 boolean restore = false;
@@ -492,7 +467,7 @@
                 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
 
                 if (!compatibilityInfo.supportsScreen()) {
-                    attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                    attrs.flags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                     mLastInCompatMode = true;
                 }
 
@@ -539,7 +514,7 @@
                         attrs.restore();
                     }
                 }
-                
+
                 if (mTranslator != null) {
                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
                 }
@@ -619,8 +594,8 @@
 
                 // Set up the input pipeline.
                 CharSequence counterSuffix = attrs.getTitle();
-                InputStage syntheticStage = new SyntheticInputStage();
-                InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticStage);
+                InputStage syntheticInputStage = new SyntheticInputStage();
+                InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                         "aq:native-post-ime:" + counterSuffix);
                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
@@ -637,16 +612,13 @@
         }
     }
 
-    void destroyHardwareResources() {
-        if (mAttachInfo.mHardwareRenderer != null) {
-            if (mAttachInfo.mHardwareRenderer.isEnabled()) {
-                mAttachInfo.mHardwareRenderer.destroyLayers(mView);
-            }
-            mAttachInfo.mHardwareRenderer.destroy(false);
-        }
+    /** Whether the window is in local focus mode or not */
+    private boolean isInLocalFocusMode() {
+        return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
     }
 
-    void terminateHardwareResources() {
+    void destroyHardwareResources() {
+        invalidateDisplayLists();
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
             mAttachInfo.mHardwareRenderer.destroy(false);
@@ -660,6 +632,7 @@
                 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
             }
         } else {
+            invalidateDisplayLists();
             if (mAttachInfo.mHardwareRenderer != null &&
                     mAttachInfo.mHardwareRenderer.isEnabled()) {
                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
@@ -673,6 +646,18 @@
         }
     }
 
+    void flushHardwareLayerUpdates() {
+        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
+                mAttachInfo.mHardwareRenderer.validate()) {
+            mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+        }
+    }
+
+    void dispatchFlushHardwareLayerUpdates() {
+        mHandler.removeMessages(MSG_FLUSH_LAYER_UPDATES);
+        mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
+    }
+
     public boolean attachFunctor(int functor) {
         //noinspection SimplifiableIfStatement
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
@@ -687,7 +672,7 @@
         }
     }
 
-    private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
+    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
 
@@ -695,7 +680,7 @@
         if (mTranslator != null) return;
 
         // Try to enable hardware acceleration if requested
-        final boolean hardwareAccelerated = 
+        final boolean hardwareAccelerated =
                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
 
         if (hardwareAccelerated) {
@@ -722,16 +707,11 @@
                 // Don't enable hardware acceleration when we're not on the main thread
                 if (!HardwareRenderer.sSystemRendererDisabled &&
                         Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " 
+                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
                             + "acceleration outside of the main thread, aborting");
                     return;
                 }
 
-                final boolean renderThread = isRenderThreadRequested(context);
-                if (renderThread) {
-                    Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
-                }
-
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.destroy(true);
                 }
@@ -769,7 +749,7 @@
             mClientWindowLayoutFlags = attrs.flags;
             // preserve compatible window flag if exists.
             int compatibleWindowFlag =
-                mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                mWindowAttributes.flags & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
             // transfer over system UI visibility values as they carry current state.
             attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
             attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
@@ -865,6 +845,7 @@
         invalidateChildInParent(null, dirty);
     }
 
+    @Override
     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
         checkThread();
         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
@@ -922,10 +903,12 @@
         }
     }
 
+    @Override
     public ViewParent getParent() {
         return null;
     }
 
+    @Override
     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
         if (child != mView) {
             throw new RuntimeException("child is not mine, honest!");
@@ -935,6 +918,7 @@
         return r.intersect(0, 0, mWidth, mHeight);
     }
 
+    @Override
     public void bringChildToFront(View child) {
     }
 
@@ -943,9 +927,14 @@
     }
 
     void disposeResizeBuffer() {
-        if (mResizeBuffer != null) {
-            mResizeBuffer.destroy();
-            mResizeBuffer = null;
+        if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
+                @Override
+                public void run() {
+                    mResizeBuffer.destroy();
+                    mResizeBuffer = null;
+                }
+            });
         }
     }
 
@@ -1151,22 +1140,22 @@
             surfaceChanged = true;
             params = lp;
         }
-        CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
+        CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
         if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
             params = lp;
             mFullRedrawNeeded = true;
             mLayoutRequested = true;
             if (mLastInCompatMode) {
-                params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                params.flags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                 mLastInCompatMode = false;
             } else {
-                params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                params.flags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                 mLastInCompatMode = true;
             }
         }
-        
+
         mWindowAttributesChangesFlag = 0;
-        
+
         Rect frame = mWinFrame;
         if (mFirst) {
             mFullRedrawNeeded = true;
@@ -1358,8 +1347,12 @@
                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
 
+        // Determine whether to compute insets.
+        // If there are no inset listeners remaining then we may still need to compute
+        // insets in case the old insets were non-empty and must be reset.
         final boolean computesInternalInsets =
-                attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
+                attachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
+                || attachInfo.mHasNonEmptyGivenInternalInsets;
 
         boolean insetsPending = false;
         int relayoutResult = 0;
@@ -1465,7 +1458,7 @@
                             }
 
                             DisplayList displayList = mView.mDisplayList;
-                            if (displayList != null) {
+                            if (displayList != null && displayList.isValid()) {
                                 layerCanvas.drawDisplayList(displayList, null,
                                         DisplayList.FLAG_CLIP_CHILDREN);
                             } else {
@@ -1486,8 +1479,7 @@
                             if (mResizeBuffer != null) {
                                 mResizeBuffer.end(hwRendererCanvas);
                                 if (!completed) {
-                                    mResizeBuffer.destroy();
-                                    mResizeBuffer = null;
+                                    disposeResizeBuffer();
                                 }
                             }
                         }
@@ -1535,7 +1527,7 @@
                             try {
                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
                                         mHolder.getSurface());
-                            } catch (Surface.OutOfResourcesException e) {
+                            } catch (OutOfResourcesException e) {
                                 handleOutOfResourcesException(e);
                                 return;
                             }
@@ -1562,7 +1554,7 @@
                     mFullRedrawNeeded = true;
                     try {
                         mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
-                    } catch (Surface.OutOfResourcesException e) {
+                    } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
                         return;
                     }
@@ -1657,23 +1649,23 @@
                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
-    
+
                     if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                             + " mHeight=" + mHeight
                             + " measuredHeight=" + host.getMeasuredHeight()
                             + " coveredInsetsChanged=" + contentInsetsChanged);
-    
+
                      // Ask host how big it wants to be
                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
-    
+
                     // Implementation of weights from WindowManager.LayoutParams
                     // We just grow the dimensions as needed and re-measure if
                     // needs be
                     int width = host.getMeasuredWidth();
                     int height = host.getMeasuredHeight();
                     boolean measureAgain = false;
-    
+
                     if (lp.horizontalWeight > 0.0f) {
                         width += (int) ((mWidth - width) * lp.horizontalWeight);
                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
@@ -1686,14 +1678,14 @@
                                 MeasureSpec.EXACTLY);
                         measureAgain = true;
                     }
-    
+
                     if (measureAgain) {
                         if (DEBUG_LAYOUT) Log.v(TAG,
                                 "And hey let's measure once more: width=" + width
                                 + " height=" + height);
                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                     }
-    
+
                     layoutRequested = true;
                 }
             }
@@ -1766,10 +1758,6 @@
         if (triggerGlobalLayoutListener) {
             attachInfo.mRecomputeGlobalAttributes = false;
             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
-
-            if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
-                postSendWindowContentChangedCallback(mView);
-            }
         }
 
         if (computesInternalInsets) {
@@ -1779,6 +1767,7 @@
 
             // Compute new insets in place.
             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
+            attachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
 
             // Tell the window manager.
             if (insetsPending || !mLastGivenInsets.equals(insets)) {
@@ -1837,7 +1826,7 @@
         mNewSurfaceNeeded = false;
         mViewVisibility = viewVisibility;
 
-        if (mAttachInfo.mHasWindowFocus) {
+        if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
             final boolean imTarget = WindowManager.LayoutParams
                     .mayUseInputMethod(mWindowAttributes.flags);
             if (imTarget != mLastWasImTarget) {
@@ -1868,7 +1857,7 @@
                     }
                     mPendingTransitions.clear();
                 }
-    
+
                 performDraw();
             }
         } else {
@@ -2095,6 +2084,7 @@
         return validLayoutRequesters;
     }
 
+    @Override
     public void requestTransparentRegion(View child) {
         // the test below should not fail unless someone is messing with us
         checkThread();
@@ -2145,10 +2135,12 @@
     int mResizeAlpha;
     final Paint mResizePaint = new Paint();
 
+    @Override
     public void onHardwarePreDraw(HardwareCanvas canvas) {
         canvas.translate(0, -mHardwareYOffset);
     }
 
+    @Override
     public void onHardwarePostDraw(HardwareCanvas canvas) {
         if (mResizeBuffer != null) {
             mResizePaint.setAlpha(mResizeAlpha);
@@ -2382,7 +2374,7 @@
                     try {
                         attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
                                 mHolder.getSurface());
-                    } catch (Surface.OutOfResourcesException e) {
+                    } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
                         return;
                     }
@@ -2568,7 +2560,7 @@
         for (int i = 0; i < count; i++) {
             final DisplayList displayList = displayLists.get(i);
             if (displayList.isDirty()) {
-                displayList.clear();
+                displayList.reset();
             }
         }
 
@@ -2758,6 +2750,7 @@
         mAccessibilityFocusedVirtualView = node;
     }
 
+    @Override
     public void requestChildFocus(View child, View focused) {
         if (DEBUG_INPUT_RESIZE) {
             Log.v(TAG, "Request child focus: focus now " + focused);
@@ -2766,6 +2759,7 @@
         scheduleTraversals();
     }
 
+    @Override
     public void clearChildFocus(View child) {
         if (DEBUG_INPUT_RESIZE) {
             Log.v(TAG, "Clearing child focus");
@@ -2779,6 +2773,7 @@
         return null;
     }
 
+    @Override
     public void focusableViewAvailable(View v) {
         checkThread();
         if (mView != null) {
@@ -2800,6 +2795,7 @@
         }
     }
 
+    @Override
     public void recomputeViewAttributes(View child) {
         checkThread();
         if (mView == child) {
@@ -2867,8 +2863,8 @@
                 + mWindowAttributes.getTitle()
                 + ": " + config);
 
-        CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
-        if (ci != null) {
+        CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
+        if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
             config = new Configuration(config);
             ci.applyToConfiguration(mNoncompatDensity, config);
         }
@@ -2894,8 +2890,11 @@
                 mView.dispatchConfigurationChanged(config);
             }
         }
+
+        mFlipControllerFallbackKeys =
+            mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
     }
-    
+
     /**
      * Return true if child is an ancestor of parent, (or equal to the parent).
      */
@@ -2925,7 +2924,7 @@
     private final static int MSG_RESIZED = 4;
     private final static int MSG_RESIZED_REPORT = 5;
     private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
-    private final static int MSG_DISPATCH_KEY = 7;
+    private final static int MSG_DISPATCH_INPUT_EVENT = 7;
     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
@@ -2942,6 +2941,7 @@
     private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
     private final static int MSG_INVALIDATE_WORLD = 23;
     private final static int MSG_WINDOW_MOVED = 24;
+    private final static int MSG_FLUSH_LAYER_UPDATES = 25;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -2959,8 +2959,8 @@
                     return "MSG_RESIZED_REPORT";
                 case MSG_WINDOW_FOCUS_CHANGED:
                     return "MSG_WINDOW_FOCUS_CHANGED";
-                case MSG_DISPATCH_KEY:
-                    return "MSG_DISPATCH_KEY";
+                case MSG_DISPATCH_INPUT_EVENT:
+                    return "MSG_DISPATCH_INPUT_EVENT";
                 case MSG_DISPATCH_APP_VISIBILITY:
                     return "MSG_DISPATCH_APP_VISIBILITY";
                 case MSG_DISPATCH_GET_NEW_SURFACE:
@@ -2991,6 +2991,8 @@
                     return "MSG_DISPATCH_DONE_ANIMATING";
                 case MSG_WINDOW_MOVED:
                     return "MSG_WINDOW_MOVED";
+                case MSG_FLUSH_LAYER_UPDATES:
+                    return "MSG_FLUSH_LAYER_UPDATES";
             }
             return super.getMessageName(message);
         }
@@ -3087,7 +3089,7 @@
                             try {
                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
                                         mWidth, mHeight, mHolder.getSurface());
-                            } catch (Surface.OutOfResourcesException e) {
+                            } catch (OutOfResourcesException e) {
                                 Log.e(TAG, "OutOfResourcesException locking surface", e);
                                 try {
                                     if (!mWindowSession.outOfMemory(mWindow)) {
@@ -3108,7 +3110,8 @@
 
                     InputMethodManager imm = InputMethodManager.peekInstance();
                     if (mView != null) {
-                        if (hasWindowFocus && imm != null && mLastWasImTarget) {
+                        if (hasWindowFocus && imm != null && mLastWasImTarget &&
+                                !isInLocalFocusMode()) {
                             imm.startGettingWindowFocus(mView);
                         }
                         mAttachInfo.mKeyDispatchState.reset();
@@ -3119,7 +3122,7 @@
                     // Note: must be done after the focus change callbacks,
                     // so all of the view state is set up correctly.
                     if (hasWindowFocus) {
-                        if (imm != null && mLastWasImTarget) {
+                        if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
                             imm.onWindowFocus(mView, mView.findFocus(),
                                     mWindowAttributes.softInputMode,
                                     !mHasHadWindowFocus, mWindowAttributes.flags);
@@ -3147,8 +3150,8 @@
             case MSG_DIE:
                 doDie();
                 break;
-            case MSG_DISPATCH_KEY: {
-                KeyEvent event = (KeyEvent)msg.obj;
+            case MSG_DISPATCH_INPUT_EVENT: {
+                InputEvent event = (InputEvent)msg.obj;
                 enqueueInputEvent(event, null, 0, true);
             } break;
             case MSG_DISPATCH_KEY_FROM_IME: {
@@ -3213,6 +3216,9 @@
                     invalidateWorld(mView);
                 }
             } break;
+            case MSG_FLUSH_LAYER_UPDATES: {
+                flushHardwareLayerUpdates();
+            } break;
             }
         }
     }
@@ -3235,7 +3241,9 @@
 
         // tell the window manager
         try {
-            mWindowSession.setInTouchMode(inTouchMode);
+            if (!isInLocalFocusMode()) {
+                mWindowSession.setInTouchMode(inTouchMode);
+            }
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -3263,24 +3271,23 @@
     }
 
     private boolean enterTouchMode() {
-        if (mView != null) {
-            if (mView.hasFocus()) {
-                // note: not relying on mFocusedView here because this could
-                // be when the window is first being added, and mFocused isn't
-                // set yet.
-                final View focused = mView.findFocus();
-                if (focused != null && !focused.isFocusableInTouchMode()) {
-                    final ViewGroup ancestorToTakeFocus =
-                            findAncestorToTakeFocusInTouchMode(focused);
-                    if (ancestorToTakeFocus != null) {
-                        // there is an ancestor that wants focus after its descendants that
-                        // is focusable in touch mode.. give it focus
-                        return ancestorToTakeFocus.requestFocus();
-                    } else {
-                        // nothing appropriate to have focus in touch mode, clear it out
-                        focused.unFocus();
-                        return true;
-                    }
+        if (mView != null && mView.hasFocus()) {
+            // note: not relying on mFocusedView here because this could
+            // be when the window is first being added, and mFocused isn't
+            // set yet.
+            final View focused = mView.findFocus();
+            if (focused != null && !focused.isFocusableInTouchMode()) {
+                final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
+                if (ancestorToTakeFocus != null) {
+                    // there is an ancestor that wants focus after its
+                    // descendants that is focusable in touch mode.. give it
+                    // focus
+                    return ancestorToTakeFocus.requestFocus();
+                } else {
+                    // There's nothing to focus. Clear and propagate through the
+                    // hierarchy, but don't attempt to place new focus.
+                    focused.clearFocusInternal(true, false);
+                    return true;
                 }
             }
         }
@@ -3638,7 +3645,7 @@
 
         @Override
         protected int onProcess(QueuedInputEvent q) {
-            if (mLastWasImTarget) {
+            if (mLastWasImTarget && !isInLocalFocusMode()) {
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null) {
                     final InputEvent event = q.mEvent;
@@ -3914,6 +3921,7 @@
         private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
         private final SyntheticTouchNavigationHandler mTouchNavigation =
                 new SyntheticTouchNavigationHandler();
+        private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler();
 
         public SyntheticInputStage() {
             super(null);
@@ -3936,7 +3944,12 @@
                     mTouchNavigation.process(event);
                     return FINISH_HANDLED;
                 }
+            } else if (q.mEvent instanceof KeyEvent) {
+                if (mKeys.process((KeyEvent) q.mEvent)) {
+                    return FINISH_HANDLED;
+                }
             }
+
             return FORWARD;
         }
 
@@ -4386,12 +4399,6 @@
 
         /* TODO: These constants should eventually be moved to ViewConfiguration. */
 
-        // Tap timeout in milliseconds.
-        private static final int TAP_TIMEOUT = 250;
-
-        // The maximum distance traveled for a gesture to be considered a tap in millimeters.
-        private static final int TAP_SLOP_MILLIMETERS = 5;
-
         // The nominal distance traveled to move by one unit.
         private static final int TICK_DISTANCE_MILLIMETERS = 12;
 
@@ -4419,10 +4426,6 @@
 
         /* Configuration for the current input device. */
 
-        // The tap timeout and scaled slop.
-        private int mConfigTapTimeout;
-        private float mConfigTapSlop;
-
         // The scaled tick distance.  A movement of this amount should generally translate
         // into a single dpad event in a given direction.
         private float mConfigTickDistance;
@@ -4468,6 +4471,9 @@
         private boolean mFlinging;
         private float mFlingVelocity;
 
+        // The last time a confirm key was pressed on the touch nav device
+        private long mLastConfirmKeyTime = Long.MAX_VALUE;
+
         public SyntheticTouchNavigationHandler() {
             super(true);
         }
@@ -4504,8 +4510,6 @@
                         float nominalRes = (xRes + yRes) * 0.5f;
 
                         // Precompute all of the configuration thresholds we will need.
-                        mConfigTapTimeout = TAP_TIMEOUT;
-                        mConfigTapSlop = TAP_SLOP_MILLIMETERS * nominalRes;
                         mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
                         mConfigMinFlingVelocity =
                                 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
@@ -4515,8 +4519,6 @@
                         if (LOCAL_DEBUG) {
                             Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
                                     + " (" + Integer.toHexString(mCurrentSource) + "): "
-                                    + "mConfigTapTimeout=" + mConfigTapTimeout
-                                    + ", mConfigTapSlop=" + mConfigTapSlop
                                     + ", mConfigTickDistance=" + mConfigTickDistance
                                     + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
                                     + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
@@ -4578,15 +4580,7 @@
 
                     // Detect taps and flings.
                     if (action == MotionEvent.ACTION_UP) {
-                        if (!mConsumedMovement
-                                && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop
-                                && time <= mStartTime + mConfigTapTimeout) {
-                            // It's a tap!
-                            finishKeys(time);
-                            sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
-                            sendKeyUp(time);
-                        } else if (mConsumedMovement
-                                && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                        if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
                             // It might be a fling.
                             mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
                             final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
@@ -4785,6 +4779,63 @@
         };
     }
 
+    final class SyntheticKeyHandler {
+
+        public boolean process(KeyEvent event) {
+            // In some locales (like Japan) controllers use B for confirm and A for back, rather
+            // than vice versa, so we need to special case this here since the input system itself
+            // is not locale-aware.
+            int keyCode;
+            switch(event.getKeyCode()) {
+                case KeyEvent.KEYCODE_BUTTON_A:
+                case KeyEvent.KEYCODE_BUTTON_C:
+                case KeyEvent.KEYCODE_BUTTON_X:
+                case KeyEvent.KEYCODE_BUTTON_Z:
+                    keyCode = mFlipControllerFallbackKeys ?
+                        KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER;
+                    break;
+                case KeyEvent.KEYCODE_BUTTON_B:
+                case KeyEvent.KEYCODE_BUTTON_Y:
+                    keyCode = mFlipControllerFallbackKeys ?
+                        KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK;
+                    break;
+                case KeyEvent.KEYCODE_BUTTON_THUMBL:
+                case KeyEvent.KEYCODE_BUTTON_THUMBR:
+                case KeyEvent.KEYCODE_BUTTON_START:
+                case KeyEvent.KEYCODE_BUTTON_1:
+                case KeyEvent.KEYCODE_BUTTON_2:
+                case KeyEvent.KEYCODE_BUTTON_3:
+                case KeyEvent.KEYCODE_BUTTON_4:
+                case KeyEvent.KEYCODE_BUTTON_5:
+                case KeyEvent.KEYCODE_BUTTON_6:
+                case KeyEvent.KEYCODE_BUTTON_7:
+                case KeyEvent.KEYCODE_BUTTON_8:
+                case KeyEvent.KEYCODE_BUTTON_9:
+                case KeyEvent.KEYCODE_BUTTON_10:
+                case KeyEvent.KEYCODE_BUTTON_11:
+                case KeyEvent.KEYCODE_BUTTON_12:
+                case KeyEvent.KEYCODE_BUTTON_13:
+                case KeyEvent.KEYCODE_BUTTON_14:
+                case KeyEvent.KEYCODE_BUTTON_15:
+                case KeyEvent.KEYCODE_BUTTON_16:
+                    keyCode = KeyEvent.KEYCODE_DPAD_CENTER;
+                    break;
+                case KeyEvent.KEYCODE_BUTTON_SELECT:
+                case KeyEvent.KEYCODE_BUTTON_MODE:
+                    keyCode = KeyEvent.KEYCODE_MENU;
+                default:
+                    return false;
+            }
+
+            enqueueInputEvent(new KeyEvent(event.getDownTime(), event.getEventTime(),
+                        event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(),
+                        event.getDeviceId(), event.getScanCode(),
+                        event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource()));
+            return true;
+        }
+
+    }
+
     /**
      * Returns true if the key is used for keyboard navigation.
      * @param keyEvent The key event.
@@ -4952,7 +5003,7 @@
             // most recent data.
             mSeq = args.seq;
             mAttachInfo.mForceReportNewAttributes = true;
-            scheduleTraversals();            
+            scheduleTraversals();
         }
         if (mView == null) return;
         if (args.localChanges != 0) {
@@ -5042,7 +5093,7 @@
         if (restore) {
             params.restore();
         }
-        
+
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
             mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
@@ -5055,9 +5106,14 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void playSoundEffect(int effectId) {
         checkThread();
 
+        if (mMediaDisabled) {
+            return;
+        }
+
         try {
             final AudioManager audioManager = getAudioManager();
 
@@ -5091,6 +5147,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean performHapticFeedback(int effectId, boolean always) {
         try {
             return mWindowSession.performHapticFeedback(mWindow, effectId, always);
@@ -5102,6 +5159,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public View focusSearch(View focused, int direction) {
         checkThread();
         if (!(mView instanceof ViewGroup)) {
@@ -5113,7 +5171,7 @@
     public void debug() {
         mView.debug();
     }
-    
+
     public void dumpGfxInfo(int[] info) {
         info[0] = info[1] = 0;
         if (mView != null) {
@@ -5138,26 +5196,36 @@
         }
     }
 
-    public void die(boolean immediate) {
+    /**
+     * @param immediate True, do now if not in traversal. False, put on queue and do later.
+     * @return True, request has been queued. False, request has been completed.
+     */
+    boolean die(boolean immediate) {
         // Make sure we do execute immediately if we are in the middle of a traversal or the damage
         // done by dispatchDetachedFromWindow will cause havoc on return.
         if (immediate && !mIsInTraversal) {
             doDie();
-        } else {
-            if (!mIsDrawing) {
-                destroyHardwareRenderer();
-            } else {
-                Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
-                        "  window=" + this + ", title=" + mWindowAttributes.getTitle());
-            }
-            mHandler.sendEmptyMessage(MSG_DIE);
+            return false;
         }
+
+        if (!mIsDrawing) {
+            destroyHardwareRenderer();
+        } else {
+            Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
+                    "  window=" + this + ", title=" + mWindowAttributes.getTitle());
+        }
+        mHandler.sendEmptyMessage(MSG_DIE);
+        return true;
     }
 
     void doDie() {
         checkThread();
         if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
         synchronized (this) {
+            if (mRemoved) {
+                return;
+            }
+            mRemoved = true;
             if (mAdded) {
                 dispatchDetachedFromWindow();
             }
@@ -5181,13 +5249,14 @@
                         } catch (RemoteException e) {
                         }
                     }
-    
+
                     mSurface.release();
                 }
             }
 
             mAdded = false;
         }
+        WindowManagerGlobal.getInstance().doRemoveView(this);
     }
 
     public void requestUpdateConfiguration(Configuration config) {
@@ -5203,6 +5272,9 @@
                 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
                 profileRendering(mAttachInfo.mHasWindowFocus);
 
+                // Media (used by sound effects)
+                mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
+
                 // Hardware rendering
                 if (mAttachInfo.mHardwareRenderer != null) {
                     if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mHolder.getSurface())) {
@@ -5518,8 +5590,8 @@
 
     final class InvalidateOnAnimationRunnable implements Runnable {
         private boolean mPosted;
-        private ArrayList<View> mViews = new ArrayList<View>();
-        private ArrayList<AttachInfo.InvalidateInfo> mViewRects =
+        private final ArrayList<View> mViews = new ArrayList<View>();
+        private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
                 new ArrayList<AttachInfo.InvalidateInfo>();
         private View[] mTempViews;
         private AttachInfo.InvalidateInfo[] mTempViewRects;
@@ -5632,8 +5704,8 @@
         mInvalidateOnAnimationRunnable.removeView(view);
     }
 
-    public void dispatchKey(KeyEvent event) {
-        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
+    public void dispatchInputEvent(InputEvent event) {
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
         msg.setAsynchronous(true);
         mHandler.sendMessage(msg);
     }
@@ -5663,7 +5735,7 @@
                         flags, event.getSource(), null);
                 fallbackAction.recycle();
 
-                dispatchKey(fallbackEvent);
+                dispatchInputEvent(fallbackEvent);
             }
         }
     }
@@ -5739,20 +5811,12 @@
      * This event is send at most once every
      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
      */
-    private void postSendWindowContentChangedCallback(View source) {
+    private void postSendWindowContentChangedCallback(View source, int changeType) {
         if (mSendWindowContentChangedAccessibilityEvent == null) {
             mSendWindowContentChangedAccessibilityEvent =
                 new SendWindowContentChangedAccessibilityEvent();
         }
-        View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource;
-        if (oldSource == null) {
-            mSendWindowContentChangedAccessibilityEvent.mSource = source;
-            mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
-                    ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
-        } else {
-            mSendWindowContentChangedAccessibilityEvent.mSource =
-                    getCommonPredecessor(oldSource, source);
-        }
+        mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
     }
 
     /**
@@ -5765,20 +5829,25 @@
         }
     }
 
+    @Override
     public boolean showContextMenuForChild(View originalView) {
         return false;
     }
 
+    @Override
     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
         return null;
     }
 
+    @Override
     public void createContextMenu(ContextMenu menu) {
     }
 
+    @Override
     public void childDrawableStateChanged(View child) {
     }
 
+    @Override
     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
         if (mView == null) {
             return false;
@@ -5819,8 +5888,8 @@
     }
 
     @Override
-    public void childAccessibilityStateChanged(View child) {
-        postSendWindowContentChangedCallback(child);
+    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
+        postSendWindowContentChangedCallback(source, changeType);
     }
 
     @Override
@@ -5910,10 +5979,12 @@
         }
     }
 
+    @Override
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
         // ViewAncestor never intercepts touch event, so this can be a no-op
     }
 
+    @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
         if (rectangle != null) {
@@ -5929,10 +6000,16 @@
         return scrolled;
     }
 
+    @Override
     public void childHasTransientStateChanged(View child, boolean hasTransientState) {
         // Do nothing.
     }
 
+    void changeCanvasOpacity(boolean opaque) {
+        // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
+        Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+    }
+
     class TakenSurfaceHolder extends BaseSurfaceHolder {
         @Override
         public boolean onAllowLockCanvas() {
@@ -5944,20 +6021,23 @@
             // Not currently interesting -- from changing between fixed and layout size.
         }
 
+        @Override
         public void setFormat(int format) {
             ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
         }
 
+        @Override
         public void setType(int type) {
             ((RootViewSurfaceTaker)mView).setSurfaceType(type);
         }
-        
+
         @Override
         public void onUpdateSurface() {
             // We take care of format and type changes on our own.
             throw new IllegalStateException("Shouldn't be here");
         }
 
+        @Override
         public boolean isCreating() {
             return mIsCreating;
         }
@@ -5967,7 +6047,8 @@
             throw new UnsupportedOperationException(
                     "Currently only support sizing from layout");
         }
-        
+
+        @Override
         public void setKeepScreenOn(boolean screenOn) {
             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
         }
@@ -5982,6 +6063,7 @@
             mWindowSession = viewAncestor.mWindowSession;
         }
 
+        @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
@@ -5999,6 +6081,7 @@
             }
         }
 
+        @Override
         public void dispatchAppVisibility(boolean visible) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6006,6 +6089,7 @@
             }
         }
 
+        @Override
         public void dispatchScreenState(boolean on) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6013,6 +6097,7 @@
             }
         }
 
+        @Override
         public void dispatchGetNewSurface() {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6020,6 +6105,7 @@
             }
         }
 
+        @Override
         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6036,6 +6122,7 @@
             }
         }
 
+        @Override
         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6066,14 +6153,16 @@
                 }
             }
         }
-        
+
+        @Override
         public void closeSystemDialogs(String reason) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchCloseSystemDialogs(reason);
             }
         }
-        
+
+        @Override
         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
                 boolean sync) {
             if (sync) {
@@ -6084,6 +6173,7 @@
             }
         }
 
+        @Override
         public void dispatchWallpaperCommand(String action, int x, int y,
                 int z, Bundle extras, boolean sync) {
             if (sync) {
@@ -6095,6 +6185,7 @@
         }
 
         /* Drag/drop */
+        @Override
         public void dispatchDragEvent(DragEvent event) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6102,6 +6193,7 @@
             }
         }
 
+        @Override
         public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
                 int localValue, int localChanges) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
@@ -6111,6 +6203,7 @@
             }
         }
 
+        @Override
         public void doneAnimating() {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
@@ -6125,50 +6218,63 @@
         }
     }
 
-    private SurfaceHolder mHolder = new SurfaceHolder() {
+    private final SurfaceHolder mHolder = new SurfaceHolder() {
         // we only need a SurfaceHolder for opengl. it would be nice
         // to implement everything else though, especially the callback
         // support (opengl doesn't make use of it right now, but eventually
         // will).
+        @Override
         public Surface getSurface() {
             return mSurface;
         }
 
+        @Override
         public boolean isCreating() {
             return false;
         }
 
+        @Override
         public void addCallback(Callback callback) {
         }
 
+        @Override
         public void removeCallback(Callback callback) {
         }
 
+        @Override
         public void setFixedSize(int width, int height) {
         }
 
+        @Override
         public void setSizeFromLayout() {
         }
 
+        @Override
         public void setFormat(int format) {
         }
 
+        @Override
         public void setType(int type) {
         }
 
+        @Override
         public void setKeepScreenOn(boolean screenOn) {
         }
 
+        @Override
         public Canvas lockCanvas() {
             return null;
         }
 
+        @Override
         public Canvas lockCanvas(Rect dirty) {
             return null;
         }
 
+        @Override
         public void unlockCanvasAndPost(Canvas canvas) {
         }
+        @Override
         public Rect getSurfaceFrame() {
             return null;
         }
@@ -6263,6 +6369,7 @@
      */
     final class AccessibilityInteractionConnectionManager
             implements AccessibilityStateChangeListener {
+        @Override
         public void onAccessibilityStateChanged(boolean enabled) {
             if (enabled) {
                 ensureConnection();
@@ -6435,13 +6542,48 @@
     }
 
     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
-        public View mSource;
+        private int mChangeTypes = 0;
 
+        public View mSource;
+        public long mLastEventTimeMillis;
+
+        @Override
         public void run() {
+            // The accessibility may be turned off while we were waiting so check again.
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                mLastEventTimeMillis = SystemClock.uptimeMillis();
+                AccessibilityEvent event = AccessibilityEvent.obtain();
+                event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+                event.setContentChangeTypes(mChangeTypes);
+                mSource.sendAccessibilityEventUnchecked(event);
+            } else {
+                mLastEventTimeMillis = 0;
+            }
+            // In any case reset to initial state.
+            mSource.resetSubtreeAccessibilityStateChanged();
+            mSource = null;
+            mChangeTypes = 0;
+        }
+
+        public void runOrPost(View source, int changeType) {
             if (mSource != null) {
-                mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-                mSource.resetAccessibilityStateChanged();
-                mSource = null;
+                // If there is no common predecessor, then mSource points to
+                // a removed view, hence in this case always prefer the source.
+                View predecessor = getCommonPredecessor(mSource, source);
+                mSource = (predecessor != null) ? predecessor : source;
+                mChangeTypes |= changeType;
+                return;
+            }
+            mSource = source;
+            mChangeTypes = changeType;
+            final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
+            final long minEventIntevalMillis =
+                    ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
+            if (timeSinceLastMillis >= minEventIntevalMillis) {
+                mSource.removeCallbacks(this);
+                run();
+            } else {
+                mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
             }
         }
     }
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 072c95f..a9444b4 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -241,11 +241,18 @@
             mTouchableInsets = TOUCHABLE_INSETS_FRAME;
         }
 
+        boolean isEmpty() {
+            return contentInsets.isEmpty()
+                    && visibleInsets.isEmpty()
+                    && touchableRegion.isEmpty()
+                    && mTouchableInsets == TOUCHABLE_INSETS_FRAME;
+        }
+
         @Override
         public int hashCode() {
-            int result = contentInsets != null ? contentInsets.hashCode() : 0;
-            result = 31 * result + (visibleInsets != null ? visibleInsets.hashCode() : 0);
-            result = 31 * result + (touchableRegion != null ? touchableRegion.hashCode() : 0);
+            int result = contentInsets.hashCode();
+            result = 31 * result + visibleInsets.hashCode();
+            result = 31 * result + touchableRegion.hashCode();
             result = 31 * result + mTouchableInsets;
             return result;
         }
@@ -814,6 +821,13 @@
     }
 
     /**
+     * Returns whether there are listeners for on pre-draw events.
+     */
+    final boolean hasOnPreDrawListeners() {
+        return mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0;
+    }
+
+    /**
      * Notifies registered listeners that the drawing pass is about to start. If a
      * listener returns true, then the drawing pass is canceled and rescheduled. This can
      * be called manually if you are forcing the drawing on a View or a hierarchy of Views
@@ -983,6 +997,8 @@
             mStart = false;
             if (mDataCopy != null) {
                 mData = mDataCopy;
+                mAccess.mData.clear();
+                mAccess.mSize = 0;
             }
             mDataCopy = null;
         }
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 9c00b7f..f0e6677 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -32,6 +32,7 @@
 import android.media.AudioSystem;
 import android.media.RingtoneManager;
 import android.media.ToneGenerator;
+import android.media.VolumeController;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
@@ -55,7 +56,8 @@
  *
  * @hide
  */
-public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener
+public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener,
+        VolumeController
 {
     private static final String TAG = "VolumePanel";
     private static boolean LOGD = false;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 06974d3..7a24243 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1256,4 +1256,52 @@
      * @param mask Flags specifying which options should be modified. Others will remain unchanged.
      */
     public void setUiOptions(int uiOptions, int mask) { }
+
+    /**
+     * Set the primary icon for this window.
+     *
+     * @param resId resource ID of a drawable to set
+     */
+    public void setIcon(int resId) { }
+
+    /**
+     * Set the default icon for this window.
+     * This will be overridden by any other icon set operation which could come from the
+     * theme or another explicit set.
+     *
+     * @hide
+     */
+    public void setDefaultIcon(int resId) { }
+
+    /**
+     * Set the logo for this window. A logo is often shown in place of an
+     * {@link #setIcon(int) icon} but is generally wider and communicates window title information
+     * as well.
+     *
+     * @param resId resource ID of a drawable to set
+     */
+    public void setLogo(int resId) { }
+
+    /**
+     * Set the default logo for this window.
+     * This will be overridden by any other logo set operation which could come from the
+     * theme or another explicit set.
+     *
+     * @hide
+     */
+    public void setDefaultLogo(int resId) { }
+
+    /**
+     * Set focus locally. The window should have the
+     * {@link WindowManager.LayoutParams#FLAG_LOCAL_FOCUS_MODE} flag set already.
+     * @param hasFocus Whether this window has focus or not.
+     * @param inTouchMode Whether this window is in touch mode or not.
+     */
+    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) { }
+
+    /**
+     * Inject an event to window locally.
+     * @param event A key or touch event to inject to this window.
+     */
+    public void injectInputEvent(InputEvent event) { }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 541c503..53f4d77 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -219,7 +219,8 @@
             @ViewDebug.IntToString(from = TYPE_DREAM, to = "TYPE_DREAM"),
             @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"),
             @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY"),
-            @ViewDebug.IntToString(from = TYPE_MAGNIFICATION_OVERLAY, to = "TYPE_MAGNIFICATION_OVERLAY")
+            @ViewDebug.IntToString(from = TYPE_MAGNIFICATION_OVERLAY, to = "TYPE_MAGNIFICATION_OVERLAY"),
+            @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION")
         })
         public int type;
     
@@ -527,6 +528,20 @@
          */
         public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28;
 
+
+        /**
+         * Window type: keyguard scrim window. Shows if keyguard needs to be restarted.
+         * In multiuser systems shows on all users' windows.
+         * @hide
+         */
+        public static final int TYPE_KEYGUARD_SCRIM           = FIRST_SYSTEM_WINDOW+29;
+
+        /**
+         * Window type: Window for Presentation on top of private
+         * virtual display.
+         */
+        public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
+
         /**
          * End of types of system windows.
          */
@@ -826,6 +841,15 @@
         // ----- HIDDEN FLAGS.
         // These start at the high bit and go down.
 
+        /**
+         * Flag for a window in local focus mode.
+         * Window in local focus mode can control focus independent of window manager using
+         * {@link Window#setLocalFocus(boolean, boolean)}.
+         * Usually window in this mode will not get touch/key events from window manager, but will
+         * get events only via local injection using {@link Window#injectInputEvent(InputEvent)}.
+         */
+        public static final int FLAG_LOCAL_FOCUS_MODE = 0x10000000;
+
         /** Window flag: Enable touches to slide out of a window into neighboring
          * windows in mid-gesture instead of being captured for the duration of
          * the gesture.
@@ -836,7 +860,7 @@
          *
          * {@hide}
          */
-        public static final int FLAG_SLIPPERY = 0x04000000;
+        public static final int FLAG_SLIPPERY = 0x20000000;
 
         /**
          * Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU}
@@ -849,20 +873,8 @@
          *
          * {@hide}
          */
-        public static final int FLAG_NEEDS_MENU_KEY = 0x08000000;
+        public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
 
-        /** Window flag: special flag to limit the size of the window to be
-         * original size ([320x480] x density). Used to create window for applications
-         * running under compatibility mode.
-         *
-         * {@hide} */
-        public static final int FLAG_COMPATIBLE_WINDOW = 0x20000000;
-
-        /** Window flag: a special option intended for system dialogs.  When
-         * this flag is set, the window will demand focus unconditionally when
-         * it is created.
-         * {@hide} */
-        public static final int FLAG_SYSTEM_ERROR = 0x40000000;
 
         /**
          * Various behavioral options/flags.  Default is none.
@@ -890,6 +902,7 @@
          * @see #FLAG_DISMISS_KEYGUARD
          * @see #FLAG_SPLIT_TOUCH
          * @see #FLAG_HARDWARE_ACCELERATED
+         * @see #FLAG_LOCAL_FOCUS_MODE
          */
         @ViewDebug.ExportedProperty(flagMapping = {
             @ViewDebug.FlagToString(mask = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, equals = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
@@ -941,7 +954,9 @@
             @ViewDebug.FlagToString(mask = FLAG_SPLIT_TOUCH, equals = FLAG_SPLIT_TOUCH,
                     name = "FLAG_SPLIT_TOUCH"),
             @ViewDebug.FlagToString(mask = FLAG_HARDWARE_ACCELERATED, equals = FLAG_HARDWARE_ACCELERATED,
-                    name = "FLAG_HARDWARE_ACCELERATED")
+                    name = "FLAG_HARDWARE_ACCELERATED"),
+            @ViewDebug.FlagToString(mask = FLAG_LOCAL_FOCUS_MODE, equals = FLAG_LOCAL_FOCUS_MODE,
+                    name = "FLAG_LOCAL_FOCUS_MODE")
         })
         public int flags;
 
@@ -1018,6 +1033,19 @@
          * {@hide} */
         public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
 
+        /** Window flag: special flag to limit the size of the window to be
+         * original size ([320x480] x density). Used to create window for applications
+         * running under compatibility mode.
+         *
+         * {@hide} */
+        public static final int PRIVATE_FLAG_COMPATIBLE_WINDOW = 0x00000080;
+
+        /** Window flag: a special option intended for system dialogs.  When
+         * this flag is set, the window will demand focus unconditionally when
+         * it is created.
+         * {@hide} */
+        public static final int PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100;
+
         /**
          * Control flags that are private to the platform.
          * @hide
@@ -1756,7 +1784,7 @@
                 sb.append(" rotAnim=");
                 sb.append(rotationAnimation);
             }
-            if ((flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+            if ((flags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0) {
                 sb.append(" compatible=true");
             }
             if (systemUiVisibility != 0) {
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 0ff46e9..96c0ed2 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -22,17 +22,19 @@
 import android.content.res.Configuration;
 import android.opengl.ManagedEGLContext;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.util.AndroidRuntimeException;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
+import com.android.internal.util.FastPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 /**
  * Provides low-level communication with the system window manager for
@@ -107,9 +109,11 @@
 
     private final Object mLock = new Object();
 
-    private View[] mViews;
-    private ViewRootImpl[] mRoots;
-    private WindowManager.LayoutParams[] mParams;
+    private final ArrayList<View> mViews = new ArrayList<View>();
+    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
+    private final ArrayList<WindowManager.LayoutParams> mParams =
+            new ArrayList<WindowManager.LayoutParams>();
+    private final ArraySet<View> mDyingViews = new ArraySet<View>();
     private boolean mNeedsEglTerminate;
 
     private Runnable mSystemPropertyUpdater;
@@ -162,11 +166,10 @@
 
     public String[] getViewRootNames() {
         synchronized (mLock) {
-            if (mRoots == null) return new String[0];
-            String[] mViewRoots = new String[mRoots.length];
-            int i = 0;
-            for (ViewRootImpl root : mRoots) {
-                mViewRoots[i++] = getWindowName(root);
+            final int numRoots = mRoots.size();
+            String[] mViewRoots = new String[numRoots];
+            for (int i = 0; i < numRoots; ++i) {
+                mViewRoots[i] = getWindowName(mRoots.get(i));
             }
             return mViewRoots;
         }
@@ -174,8 +177,8 @@
 
     public View getRootView(String name) {
         synchronized (mLock) {
-            if (mRoots == null) return null;
-            for (ViewRootImpl root : mRoots) {
+            for (int i = mRoots.size() - 1; i >= 0; --i) {
+                final ViewRootImpl root = mRoots.get(i);
                 if (name.equals(getWindowName(root))) return root.getView();
             }
         }
@@ -209,8 +212,8 @@
                 mSystemPropertyUpdater = new Runnable() {
                     @Override public void run() {
                         synchronized (mLock) {
-                            for (ViewRootImpl viewRoot : mRoots) {
-                                viewRoot.loadSystemProperties();
+                            for (int i = mRoots.size() - 1; i >= 0; --i) {
+                                mRoots.get(i).loadSystemProperties();
                             }
                         }
                     }
@@ -220,18 +223,24 @@
 
             int index = findViewLocked(view, false);
             if (index >= 0) {
-                throw new IllegalStateException("View " + view
-                        + " has already been added to the window manager.");
+                if (mDyingViews.contains(view)) {
+                    // Don't wait for MSG_DIE to make it's way through root's queue.
+                    mRoots.get(index).doDie();
+                } else {
+                    throw new IllegalStateException("View " + view
+                            + " has already been added to the window manager.");
+                }
+                // The previous removeView() had not completed executing. Now it has.
             }
 
             // If this is a panel window, then find the window it is being
             // attached to for future reference.
             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                     wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-                final int count = mViews != null ? mViews.length : 0;
-                for (int i=0; i<count; i++) {
-                    if (mRoots[i].mWindow.asBinder() == wparams.token) {
-                        panelParentView = mViews[i];
+                final int count = mViews.size();
+                for (int i = 0; i < count; i++) {
+                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
+                        panelParentView = mViews.get(i);
                     }
                 }
             }
@@ -240,28 +249,9 @@
 
             view.setLayoutParams(wparams);
 
-            if (mViews == null) {
-                index = 1;
-                mViews = new View[1];
-                mRoots = new ViewRootImpl[1];
-                mParams = new WindowManager.LayoutParams[1];
-            } else {
-                index = mViews.length + 1;
-                Object[] old = mViews;
-                mViews = new View[index];
-                System.arraycopy(old, 0, mViews, 0, index-1);
-                old = mRoots;
-                mRoots = new ViewRootImpl[index];
-                System.arraycopy(old, 0, mRoots, 0, index-1);
-                old = mParams;
-                mParams = new WindowManager.LayoutParams[index];
-                System.arraycopy(old, 0, mParams, 0, index-1);
-            }
-            index--;
-
-            mViews[index] = view;
-            mRoots[index] = root;
-            mParams[index] = wparams;
+            mViews.add(view);
+            mRoots.add(root);
+            mParams.add(wparams);
         }
 
         // do this last because it fires off messages to start doing things
@@ -293,8 +283,9 @@
 
         synchronized (mLock) {
             int index = findViewLocked(view, true);
-            ViewRootImpl root = mRoots[index];
-            mParams[index] = wparams;
+            ViewRootImpl root = mRoots.get(index);
+            mParams.remove(index);
+            mParams.add(index, wparams);
             root.setLayoutParams(wparams, false);
         }
     }
@@ -306,7 +297,8 @@
 
         synchronized (mLock) {
             int index = findViewLocked(view, true);
-            View curView = removeViewLocked(index, immediate);
+            View curView = mRoots.get(index).getView();
+            removeViewLocked(index, immediate);
             if (curView == view) {
                 return;
             }
@@ -318,16 +310,13 @@
 
     public void closeAll(IBinder token, String who, String what) {
         synchronized (mLock) {
-            if (mViews == null)
-                return;
-
-            int count = mViews.length;
+            int count = mViews.size();
             //Log.i("foo", "Closing all windows of " + token);
-            for (int i=0; i<count; i++) {
+            for (int i = 0; i < count; i++) {
                 //Log.i("foo", "@ " + i + " token " + mParams[i].token
                 //        + " view " + mRoots[i].getView());
-                if (token == null || mParams[i].token == token) {
-                    ViewRootImpl root = mRoots[i];
+                if (token == null || mParams.get(i).token == token) {
+                    ViewRootImpl root = mRoots.get(i);
 
                     //Log.i("foo", "Force closing " + root);
                     if (who != null) {
@@ -335,77 +324,52 @@
                                 what + " " + who + " has leaked window "
                                 + root.getView() + " that was originally added here");
                         leak.setStackTrace(root.getLocation().getStackTrace());
-                        Log.e(TAG, leak.getMessage(), leak);
+                        Log.e(TAG, "", leak);
                     }
 
                     removeViewLocked(i, false);
-                    i--;
-                    count--;
                 }
             }
         }
     }
 
-    private View removeViewLocked(int index, boolean immediate) {
-        ViewRootImpl root = mRoots[index];
+    private void removeViewLocked(int index, boolean immediate) {
+        ViewRootImpl root = mRoots.get(index);
         View view = root.getView();
 
         if (view != null) {
             InputMethodManager imm = InputMethodManager.getInstance();
             if (imm != null) {
-                imm.windowDismissed(mViews[index].getWindowToken());
+                imm.windowDismissed(mViews.get(index).getWindowToken());
             }
         }
-        root.die(immediate);
-
-        final int count = mViews.length;
-
-        // remove it from the list
-        View[] tmpViews = new View[count-1];
-        removeItem(tmpViews, mViews, index);
-        mViews = tmpViews;
-
-        ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1];
-        removeItem(tmpRoots, mRoots, index);
-        mRoots = tmpRoots;
-
-        WindowManager.LayoutParams[] tmpParams
-                = new WindowManager.LayoutParams[count-1];
-        removeItem(tmpParams, mParams, index);
-        mParams = tmpParams;
-
+        boolean deferred = root.die(immediate);
         if (view != null) {
             view.assignParent(null);
-            // func doesn't allow null...  does it matter if we clear them?
-            //view.setLayoutParams(null);
+            if (deferred) {
+                mDyingViews.add(view);
+            }
         }
-        return view;
     }
 
-    private static void removeItem(Object[] dst, Object[] src, int index) {
-        if (dst.length > 0) {
-            if (index > 0) {
-                System.arraycopy(src, 0, dst, 0, index);
-            }
-            if (index < dst.length) {
-                System.arraycopy(src, index+1, dst, index, src.length-index-1);
+    void doRemoveView(ViewRootImpl root) {
+        synchronized (mLock) {
+            final int index = mRoots.indexOf(root);
+            if (index >= 0) {
+                mRoots.remove(index);
+                mParams.remove(index);
+                final View view = mViews.remove(index);
+                mDyingViews.remove(view);
             }
         }
     }
 
     private int findViewLocked(View view, boolean required) {
-        if (mViews != null) {
-            final int count = mViews.length;
-            for (int i = 0; i < count; i++) {
-                if (mViews[i] == view) {
-                    return i;
-                }
-            }
+        final int index = mViews.indexOf(view);
+        if (required && index < 0) {
+            throw new IllegalArgumentException("View=" + view + " not attached to window manager");
         }
-        if (required) {
-            throw new IllegalArgumentException("View not attached to window manager");
-        }
-        return -1;
+        return index;
     }
 
     public void startTrimMemory(int level) {
@@ -418,10 +382,8 @@
                 // Destroy all hardware surfaces and resources associated to
                 // known windows
                 synchronized (mLock) {
-                    if (mViews == null) return;
-                    int count = mViews.length;
-                    for (int i = 0; i < count; i++) {
-                        mRoots[i].terminateHardwareResources();
+                    for (int i = mRoots.size() - 1; i >= 0; --i) {
+                        mRoots.get(i).destroyHardwareResources();
                     }
                 }
                 // Force a full memory flush
@@ -445,64 +407,60 @@
 
     public void trimLocalMemory() {
         synchronized (mLock) {
-            if (mViews == null) return;
-            int count = mViews.length;
-            for (int i = 0; i < count; i++) {
-                mRoots[i].destroyHardwareLayers();
+            for (int i = mRoots.size() - 1; i >= 0; --i) {
+                mRoots.get(i).destroyHardwareLayers();
             }
         }
     }
 
     public void dumpGfxInfo(FileDescriptor fd) {
         FileOutputStream fout = new FileOutputStream(fd);
-        PrintWriter pw = new PrintWriter(fout);
+        PrintWriter pw = new FastPrintWriter(fout);
         try {
             synchronized (mLock) {
-                if (mViews != null) {
-                    final int count = mViews.length;
+                final int count = mViews.size();
 
-                    pw.println("Profile data in ms:");
+                pw.println("Profile data in ms:");
 
-                    for (int i = 0; i < count; i++) {
-                        ViewRootImpl root = mRoots[i];
-                        String name = getWindowName(root);
-                        pw.printf("\n\t%s", name);
+                for (int i = 0; i < count; i++) {
+                    ViewRootImpl root = mRoots.get(i);
+                    String name = getWindowName(root);
+                    pw.printf("\n\t%s", name);
 
-                        HardwareRenderer renderer =
-                                root.getView().mAttachInfo.mHardwareRenderer;
-                        if (renderer != null) {
-                            renderer.dumpGfxInfo(pw);
-                        }
+                    HardwareRenderer renderer =
+                            root.getView().mAttachInfo.mHardwareRenderer;
+                    if (renderer != null) {
+                        renderer.dumpGfxInfo(pw);
                     }
-
-                    pw.println("\nView hierarchy:\n");
-
-                    int viewsCount = 0;
-                    int displayListsSize = 0;
-                    int[] info = new int[2];
-
-                    for (int i = 0; i < count; i++) {
-                        ViewRootImpl root = mRoots[i];
-                        root.dumpGfxInfo(info);
-
-                        String name = getWindowName(root);
-                        pw.printf("  %s\n  %d views, %.2f kB of display lists",
-                                name, info[0], info[1] / 1024.0f);
-                        HardwareRenderer renderer =
-                                root.getView().mAttachInfo.mHardwareRenderer;
-                        if (renderer != null) {
-                            pw.printf(", %d frames rendered", renderer.getFrameCount());
-                        }
-                        pw.printf("\n\n");
-
-                        viewsCount += info[0];
-                        displayListsSize += info[1];
-                    }
-
-                    pw.printf("\nTotal ViewRootImpl: %d\n", count);
-                    pw.printf("Total Views:        %d\n", viewsCount);
-                    pw.printf("Total DisplayList:  %.2f kB\n\n", displayListsSize / 1024.0f);
                 }
+
+                pw.println("\nView hierarchy:\n");
+
+                int viewsCount = 0;
+                int displayListsSize = 0;
+                int[] info = new int[2];
+
+                for (int i = 0; i < count; i++) {
+                    ViewRootImpl root = mRoots.get(i);
+                    root.dumpGfxInfo(info);
+
+                    String name = getWindowName(root);
+                    pw.printf("  %s\n  %d views, %.2f kB of display lists",
+                            name, info[0], info[1] / 1024.0f);
+                    HardwareRenderer renderer =
+                            root.getView().mAttachInfo.mHardwareRenderer;
+                    if (renderer != null) {
+                        pw.printf(", %d frames rendered", renderer.getFrameCount());
+                    }
+                    pw.printf("\n\n");
+
+                    viewsCount += info[0];
+                    displayListsSize += info[1];
+                }
+
+                pw.printf("\nTotal ViewRootImpl: %d\n", count);
+                pw.printf("Total Views:        %d\n", viewsCount);
+                pw.printf("Total DisplayList:  %.2f kB\n\n", displayListsSize / 1024.0f);
             }
         } finally {
             pw.flush();
@@ -516,13 +474,11 @@
 
     public void setStoppedState(IBinder token, boolean stopped) {
         synchronized (mLock) {
-            if (mViews != null) {
-                int count = mViews.length;
-                for (int i=0; i < count; i++) {
-                    if (token == null || mParams[i].token == token) {
-                        ViewRootImpl root = mRoots[i];
-                        root.setStopped(stopped);
-                    }
+            int count = mViews.size();
+            for (int i = 0; i < count; i++) {
+                if (token == null || mParams.get(i).token == token) {
+                    ViewRootImpl root = mRoots.get(i);
+                    root.setStopped(stopped);
                 }
             }
         }
@@ -530,12 +486,25 @@
 
     public void reportNewConfiguration(Configuration config) {
         synchronized (mLock) {
-            if (mViews != null) {
-                int count = mViews.length;
-                config = new Configuration(config);
-                for (int i=0; i < count; i++) {
-                    ViewRootImpl root = mRoots[i];
-                    root.requestUpdateConfiguration(config);
+            int count = mViews.size();
+            config = new Configuration(config);
+            for (int i=0; i < count; i++) {
+                ViewRootImpl root = mRoots.get(i);
+                root.requestUpdateConfiguration(config);
+            }
+        }
+    }
+
+    /** @hide */
+    public void changeCanvasOpacity(IBinder token, boolean opaque) {
+        if (token == null) {
+            return;
+        }
+        synchronized (mLock) {
+            for (int i = mParams.size() - 1; i >= 0; --i) {
+                if (mParams.get(i).token == token) {
+                    mRoots.get(i).changeCanvasOpacity(opaque);
+                    return;
                 }
             }
         }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c0044b6..79c0b3c 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -408,11 +408,6 @@
         public int getLidState();
 
         /**
-         * Creates an input channel that will receive all input from the input dispatcher.
-         */
-        public InputChannel monitorInput(String name);
-
-        /**
          * Switch the keyboard layout for the given device.
          * Direction should be +1 or -1 to go to the next or previous keyboard layout.
          */
@@ -420,6 +415,26 @@
 
         public void shutdown(boolean confirm);
         public void rebootSafeMode(boolean confirm);
+
+        /**
+         * Return the window manager lock needed to correctly call "Lw" methods.
+         */
+        public Object getWindowManagerLock();
+
+        /** Register a system listener for touch events */
+        void registerPointerEventListener(PointerEventListener listener);
+
+        /** Unregister a system listener for touch events */
+        void unregisterPointerEventListener(PointerEventListener listener);
+    }
+
+    public interface PointerEventListener {
+        /**
+         * 1. onPointerEvent will be called on the service.UiThread.
+         * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
+         * copy() must be made and the copy must be recycled.
+         **/
+        public void onPointerEvent(MotionEvent motionEvent);
     }
 
     /** Window has been added to the screen. */
@@ -463,6 +478,11 @@
             WindowManagerFuncs windowManagerFuncs);
 
     /**
+     * @return true if com.android.internal.R.bool#config_forceDefaultOrientation is true.
+     */
+    public boolean isDefaultOrientationForced();
+
+    /**
      * Called by window manager once it has the initial, default native
      * display dimensions.
      */
@@ -563,12 +583,6 @@
     public int getAboveUniverseLayer();
 
     /**
-     * Return true if the policy desires a full unified system nav bar.  Otherwise,
-     * it is a phone-style status bar with optional nav bar.
-     */
-    public boolean hasSystemNavBar();
-
-    /**
      * Return the display width available after excluding any screen
      * decorations that can never be removed.  That is, system bar or
      * button bar.
@@ -637,7 +651,7 @@
      */
     public View addStartingWindow(IBinder appToken, String packageName,
             int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel,
-            int labelRes, int icon, int windowFlags);
+            int labelRes, int icon, int logo, int windowFlags);
 
     /**
      * Called when the first window of an application has been displayed, while
@@ -816,6 +830,14 @@
     public int getSystemDecorRectLw(Rect systemRect);
 
     /**
+     * Return the rectangle of the screen that is available for applications to run in.
+     * This will be called immediately after {@link #beginLayoutLw}.
+     *
+     * @param r The rectangle to be filled with the boundaries available to applications.
+     */
+    public void getContentRectLw(Rect r);
+
+    /**
      * Called for each window attached to the window manager as layout is
      * proceeding.  The implementation of this function must take care of
      * setting the window's frame, either here or in finishLayout().
@@ -1154,12 +1176,6 @@
     public void dump(String prefix, PrintWriter writer, String[] args);
 
     /**
-     * Ask keyguard to invoke the assist intent after dismissing keyguard
-     * {@link android.content.Intent#ACTION_ASSIST}
-     */
-    public void showAssistant();
-
-    /**
      * Returns whether a given window type can be magnified.
      *
      * @param windowType The window type.
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index dbeca1f..7e2bffa 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -326,6 +326,7 @@
  * <em>Properties:</em></br>
  * <ul>
  *   <li>{@link #getEventType()} - The type of the event.</li>
+ *   <li>{@link #getContentChangeTypes()} - The type of content changes.</li>
  *   <li>{@link #getSource()} - The source info (for registered clients).</li>
  *   <li>{@link #getClassName()} - The class name of the source.</li>
  *   <li>{@link #getPackageName()} - The package name of the source.</li>
@@ -661,6 +662,30 @@
     public static final int TYPE_TOUCH_INTERACTION_END = 0x00200000;
 
     /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * The type of change is not defined.
+     */
+    public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * A node in the subtree rooted at the source node was added or removed.
+     */
+    public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0x00000001;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * The node's text changed.
+     */
+    public static final int CONTENT_CHANGE_TYPE_TEXT = 0x00000002;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * The node's content description changed.
+     */
+    public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004;
+
+    /**
      * Mask for {@link AccessibilityEvent} all types.
      *
      * @see #TYPE_VIEW_CLICKED
@@ -695,6 +720,7 @@
     private long mEventTime;
     int mMovementGranularity;
     int mAction;
+    int mContentChangeTypes;
 
     private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
 
@@ -714,6 +740,7 @@
         mEventType = event.mEventType;
         mMovementGranularity = event.mMovementGranularity;
         mAction = event.mAction;
+        mContentChangeTypes = event.mContentChangeTypes;
         mEventTime = event.mEventTime;
         mPackageName = event.mPackageName;
     }
@@ -777,6 +804,36 @@
     }
 
     /**
+     * Gets the bit mask of change types signaled by an
+     * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. A single event may represent
+     * multiple change types.
+     *
+     * @return The bit mask of change types. One or more of:
+     *         <ul>
+     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
+     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
+     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
+     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
+     *         </ul>
+     */
+    public int getContentChangeTypes() {
+        return mContentChangeTypes;
+    }
+
+    /**
+     * Sets the bit mask of node tree changes signaled by an
+     * {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
+     *
+     * @param changeTypes The bit mask of change types.
+     * @throws IllegalStateException If called from an AccessibilityService.
+     * @see #getContentChangeTypes()
+     */
+    public void setContentChangeTypes(int changeTypes) {
+        enforceNotSealed();
+        mContentChangeTypes = changeTypes;
+    }
+
+    /**
      * Sets the event type.
      *
      * @param eventType The event type.
@@ -943,6 +1000,7 @@
         mEventType = 0;
         mMovementGranularity = 0;
         mAction = 0;
+        mContentChangeTypes = 0;
         mPackageName = null;
         mEventTime = 0;
         while (!mRecords.isEmpty()) {
@@ -961,6 +1019,7 @@
         mEventType = parcel.readInt();
         mMovementGranularity = parcel.readInt();
         mAction = parcel.readInt();
+        mContentChangeTypes = parcel.readInt();
         mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         mEventTime = parcel.readLong();
         mConnectionId = parcel.readInt();
@@ -1013,6 +1072,7 @@
         parcel.writeInt(mEventType);
         parcel.writeInt(mMovementGranularity);
         parcel.writeInt(mAction);
+        parcel.writeInt(mContentChangeTypes);
         TextUtils.writeToParcel(mPackageName, parcel, 0);
         parcel.writeLong(mEventTime);
         parcel.writeInt(mConnectionId);
@@ -1074,6 +1134,7 @@
         builder.append(super.toString());
         if (DEBUG) {
             builder.append("\n");
+            builder.append("; ContentChangeTypes: ").append(mContentChangeTypes);
             builder.append("; sourceWindowId: ").append(mSourceWindowId);
             builder.append("; mSourceNodeId: ").append(mSourceNodeId);
             for (int i = 0; i < mRecords.size(); i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 84d7e72..139df3e 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -163,7 +163,7 @@
     public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) {
         return findAccessibilityNodeInfoByAccessibilityId(connectionId,
                 AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+                false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
     }
 
     /**
@@ -177,18 +177,22 @@
      *     where to start the search. Use
      *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
      *     to start from the root.
+     * @param bypassCache Whether to bypass the cache while looking for the node.
      * @param prefetchFlags flags to guide prefetching.
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
      */
     public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
-            int accessibilityWindowId, long accessibilityNodeId, int prefetchFlags) {
+            int accessibilityWindowId, long accessibilityNodeId, boolean bypassCache,
+            int prefetchFlags) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(
-                        accessibilityNodeId);
-                if (cachedInfo != null) {
-                    return cachedInfo;
+                if (!bypassCache) {
+                    AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(
+                            accessibilityNodeId);
+                    if (cachedInfo != null) {
+                        return cachedInfo;
+                    }
                 }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
@@ -350,7 +354,7 @@
             }
         } catch (RemoteException re) {
             if (DEBUG) {
-                Log.w(LOG_TAG, "Error while calling remote findAccessibilityFocus", re);
+                Log.w(LOG_TAG, "Error while calling remote findFocus", re);
             }
         }
         return null;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 732699b..04ce7e2 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -16,14 +16,17 @@
 
 package android.view.accessibility;
 
+import android.Manifest;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -132,29 +135,6 @@
     }
 
     /**
-     * Creates the singleton AccessibilityManager to be shared across users. This
-     * has to be called before the local AccessibilityManager is created to ensure
-     * it registers itself in the system correctly.
-     * <p>
-     * Note: Calling this method requires INTERACT_ACROSS_USERS_FULL or
-     *       INTERACT_ACROSS_USERS permission.
-     * </p>
-     * @param context Context in which this manager operates.
-     * @throws IllegalStateException if not called before the local
-     *     AccessibilityManager is instantiated.
-     *
-     * @hide
-     */
-    public static void createAsSharedAcrossUsers(Context context) {
-        synchronized (sInstanceSync) {
-            if (sInstance != null) {
-                throw new IllegalStateException("AccessibilityManager already created.");
-            }
-            createSingletonInstance(context, UserHandle.USER_CURRENT);
-        }
-    }
-
-    /**
      * Get an AccessibilityManager instance (create one if necessary).
      *
      * @param context Context in which this manager operates.
@@ -164,25 +144,27 @@
     public static AccessibilityManager getInstance(Context context) {
         synchronized (sInstanceSync) {
             if (sInstance == null) {
-                createSingletonInstance(context, UserHandle.myUserId());
+                final int userId;
+                if (Binder.getCallingUid() == Process.SYSTEM_UID
+                        || context.checkCallingOrSelfPermission(
+                                Manifest.permission.INTERACT_ACROSS_USERS)
+                                        == PackageManager.PERMISSION_GRANTED
+                        || context.checkCallingOrSelfPermission(
+                                Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                                        == PackageManager.PERMISSION_GRANTED) {
+                    userId = UserHandle.USER_CURRENT;
+                } else {
+                    userId = UserHandle.myUserId();
+                }
+                IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+                IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
+                sInstance = new AccessibilityManager(context, service, userId);
             }
         }
         return sInstance;
     }
 
     /**
-     * Creates the singleton instance.
-     *
-     * @param context Context in which this manager operates.
-     * @param userId The user id under which to operate.
-     */
-    private static void createSingletonInstance(Context context, int userId) {
-        IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
-        IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
-        sInstance = new AccessibilityManager(context, service, userId);
-    }
-
-    /**
      * Create an instance.
      *
      * @param context A {@link Context}.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d9c9b69..9fc37cf 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.InputType;
 import android.util.Pools.SynchronizedPool;
 import android.util.SparseLongArray;
 import android.view.View;
@@ -267,6 +268,23 @@
     public static final int ACTION_SET_SELECTION = 0x00020000;
 
     /**
+     * Action to expand an expandable node.
+     */
+    public static final int ACTION_EXPAND = 0x00040000;
+
+    /**
+     * Action to collapse an expandable node.
+     */
+    public static final int ACTION_COLLAPSE = 0x00080000;
+
+    /**
+     * Action to dismiss a dismissable node.
+     */
+    public static final int ACTION_DISMISS = 0x00100000;
+
+    // Action arguments
+
+    /**
      * Argument for which movement granularity to be used when traversing the node text.
      * <p>
      * <strong>Type:</strong> int<br>
@@ -333,6 +351,8 @@
     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
             "ACTION_ARGUMENT_SELECTION_END_INT";
 
+    // Focus types
+
     /**
      * The input focus.
      */
@@ -398,6 +418,14 @@
 
     private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
 
+    private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
+
+    private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
+
+    private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
+
+    private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -482,9 +510,17 @@
 
     private int mTextSelectionStart = UNDEFINED;
     private int mTextSelectionEnd = UNDEFINED;
+    private int mInputType = InputType.TYPE_NULL;
+    private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
+
+    private Bundle mExtras;
 
     private int mConnectionId = UNDEFINED;
 
+    private RangeInfo mRangeInfo;
+    private CollectionInfo mCollectionInfo;
+    private CollectionItemInfo mCollectionItemInfo;
+
     /**
      * Hide constructor from clients.
      */
@@ -594,16 +630,20 @@
      * since it represents a view that is no longer in the view tree and should
      * be recycled.
      * </p>
+     *
+     * @param bypassCache Whether to bypass the cache.
      * @return Whether the refresh succeeded.
+     *
+     * @hide
      */
-    public boolean refresh() {
+    public boolean refresh(boolean bypassCache) {
         enforceSealed();
         if (!canPerformRequestOverConnection(mSourceNodeId)) {
             return false;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
-                mConnectionId, mWindowId, mSourceNodeId, 0);
+                mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
         if (refreshedInfo == null) {
             return false;
         }
@@ -613,6 +653,19 @@
     }
 
     /**
+     * Refreshes this info with the latest state of the view it represents.
+     * <p>
+     * <strong>Note:</strong> If this method returns false this info is obsolete
+     * since it represents a view that is no longer in the view tree and should
+     * be recycled.
+     * </p>
+     * @return Whether the refresh succeeded.
+     */
+    public boolean refresh() {
+        return refresh(false);
+    }
+
+    /**
      * @return The ids of the children.
      *
      * @hide
@@ -652,7 +705,7 @@
         final long childId = mChildNodeIds.get(index);
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
-                childId, FLAG_PREFETCH_DESCENDANTS);
+                childId, false, FLAG_PREFETCH_DESCENDANTS);
     }
 
     /**
@@ -878,7 +931,7 @@
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, mParentNodeId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+                mWindowId, mParentNodeId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
     }
 
     /**
@@ -1283,7 +1336,6 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setScrollable(boolean scrollable) {
-        enforceNotSealed();
         setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
     }
 
@@ -1313,6 +1365,216 @@
     }
 
     /**
+     * Gets the collection info if the node is a collection. A collection
+     * child is always a collection item.
+     *
+     * @return The collection info.
+     */
+    public CollectionInfo getCollectionInfo() {
+        return mCollectionInfo;
+    }
+
+    /**
+     * Sets the collection info if the node is a collection. A collection
+     * child is always a collection item.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param collectionInfo The collection info.
+     */
+    public void setCollectionInfo(CollectionInfo collectionInfo) {
+        enforceNotSealed();
+        mCollectionInfo = collectionInfo;
+    }
+
+    /**
+     * Gets the collection item info if the node is a collection item. A collection
+     * item is always a child of a collection.
+     *
+     * @return The collection item info.
+     */
+    public CollectionItemInfo getCollectionItemInfo() {
+        return mCollectionItemInfo;
+    }
+
+    /**
+     * Sets the collection item info if the node is a collection item. A collection
+     * item is always a child of a collection.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @return collectionItem True if the node is an item.
+     */
+    public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
+        enforceNotSealed();
+        mCollectionItemInfo = collectionItemInfo;
+    }
+
+    /**
+     * Gets the range info if this node is a range.
+     *
+     * @return The range.
+     */
+    public RangeInfo getRangeInfo() {
+        return mRangeInfo;
+    }
+
+    /**
+     * Sets the range info if this node is a range.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param rangeInfo The range info.
+     */
+    public void setRangeInfo(RangeInfo rangeInfo) {
+        enforceNotSealed();
+        mRangeInfo = rangeInfo;
+    }
+
+    /**
+     * Gets if the content of this node is invalid. For example,
+     * a date is not well-formed.
+     *
+     * @return If the node content is invalid.
+     */
+    public boolean isContentInvalid() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
+    }
+
+    /**
+     * Sets if the content of this node is invalid. For example,
+     * a date is not well-formed.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param contentInvalid If the node content is invalid.
+     */
+    public void setContentInvalid(boolean contentInvalid) {
+        setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
+    }
+
+    /**
+     * Gets the node's live region mode.
+     * <p>
+     * A live region is a node that contains information that is important for
+     * the user and when it changes the user should be notified. For example,
+     * in a login screen with a TextView that displays an "incorrect password"
+     * notification, that view should be marked as a live region with mode
+     * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
+     * <p>
+     * It is the responsibility of the accessibility service to monitor
+     * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
+     * changes to live region nodes and their children.
+     *
+     * @return The live region mode, or
+     *         {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
+     *         live region.
+     * @see android.view.View#getAccessibilityLiveRegion()
+     */
+    public int getLiveRegion() {
+        return mLiveRegion;
+    }
+
+    /**
+     * Sets the node's live region mode.
+     * <p>
+     * <strong>Note:</strong> Cannot be called from an
+     * {@link android.accessibilityservice.AccessibilityService}. This class is
+     * made immutable before being delivered to an AccessibilityService.
+     *
+     * @param mode The live region mode, or
+     *        {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
+     *        live region.
+     * @see android.view.View#setAccessibilityLiveRegion(int)
+     */
+    public void setLiveRegion(int mode) {
+        enforceNotSealed();
+        mLiveRegion = mode;
+    }
+
+    /**
+     * Gets if the node is a multi line editable text.
+     *
+     * @return True if the node is multi line.
+     */
+    public boolean isMultiLine() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
+    }
+
+    /**
+     * Sets if the node is a multi line editable text.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param multiLine True if the node is multi line.
+     */
+    public void setMultiLine(boolean multiLine) {
+        setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
+    }
+
+    /**
+     * Gets if this node opens a popup or a dialog.
+     *
+     * @return If the the node opens a popup.
+     */
+    public boolean canOpenPopup() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
+    }
+
+    /**
+     * Sets if this node opens a popup or a dialog.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param opensPopup If the the node opens a popup.
+     */
+    public void setCanOpenPopup(boolean opensPopup) {
+        enforceNotSealed();
+        setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
+    }
+
+    /**
+     * Gets if the node can be dismissed.
+     *
+     * @return If the node can be dismissed.
+     */
+    public boolean isDismissable() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
+    }
+
+    /**
+     * Sets if the node can be dismissed.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param dismissable If the node can be dismissed.
+     */
+    public void setDismissable(boolean dismissable) {
+        setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
+    }
+
+    /**
      * Gets the package this node comes from.
      *
      * @return The package name.
@@ -1470,7 +1732,7 @@
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, mLabelForId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+                mWindowId, mLabelForId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
     }
 
     /**
@@ -1527,7 +1789,7 @@
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, mLabeledById, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+                mWindowId, mLabeledById, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
     }
 
     /**
@@ -1600,6 +1862,53 @@
     }
 
     /**
+     * Gets the input type of the source as defined by {@link InputType}.
+     *
+     * @return The input type.
+     */
+    public int getInputType() {
+        return mInputType;
+    }
+
+    /**
+     * Sets the input type of the source as defined by {@link InputType}.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an
+     *   AccessibilityService.
+     * </p>
+     *
+     * @param inputType The input type.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setInputType(int inputType) {
+        enforceNotSealed();
+        mInputType = inputType;
+    }
+
+    /**
+     * Gets an optional bundle with extra data. The bundle
+     * is lazily created and never <code>null</code>.
+     * <p>
+     * <strong>Note:</strong> It is recommended to use the package
+     * name of your application as a prefix for the keys to avoid
+     * collisions which may confuse an accessibility service if the
+     * same key has different meaning when emitted from different
+     * applications.
+     * </p>
+     *
+     * @return The bundle.
+     */
+    public Bundle getExtras() {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        return mExtras;
+    }
+
+    /**
      * Gets the value of a boolean property.
      *
      * @param property The property.
@@ -1845,6 +2154,45 @@
 
         parcel.writeInt(mTextSelectionStart);
         parcel.writeInt(mTextSelectionEnd);
+        parcel.writeInt(mInputType);
+        parcel.writeInt(mLiveRegion);
+
+        if (mExtras != null) {
+            parcel.writeInt(1);
+            parcel.writeBundle(mExtras);
+        } else {
+            parcel.writeInt(0);
+        }
+
+        if (mRangeInfo != null) {
+            parcel.writeInt(1);
+            parcel.writeInt(mRangeInfo.getType());
+            parcel.writeFloat(mRangeInfo.getMin());
+            parcel.writeFloat(mRangeInfo.getMax());
+            parcel.writeFloat(mRangeInfo.getCurrent());
+        } else {
+            parcel.writeInt(0);
+        }
+
+        if (mCollectionInfo != null) {
+            parcel.writeInt(1);
+            parcel.writeInt(mCollectionInfo.getRowCount());
+            parcel.writeInt(mCollectionInfo.getColumnCount());
+            parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
+        } else {
+            parcel.writeInt(0);
+        }
+
+        if (mCollectionItemInfo != null) {
+            parcel.writeInt(1);
+            parcel.writeInt(mCollectionItemInfo.getColumnIndex());
+            parcel.writeInt(mCollectionItemInfo.getColumnSpan());
+            parcel.writeInt(mCollectionItemInfo.getRowIndex());
+            parcel.writeInt(mCollectionItemInfo.getRowSpan());
+            parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
+        } else {
+            parcel.writeInt(0);
+        }
 
         // Since instances of this class are fetched via synchronous i.e. blocking
         // calls in IPCs we always recycle as soon as the instance is marshaled.
@@ -1876,10 +2224,21 @@
         mMovementGranularities = other.mMovementGranularities;
         final int otherChildIdCount = other.mChildNodeIds.size();
         for (int i = 0; i < otherChildIdCount; i++) {
-            mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));    
+            mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
         }
         mTextSelectionStart = other.mTextSelectionStart;
         mTextSelectionEnd = other.mTextSelectionEnd;
+        mInputType = other.mInputType;
+        mLiveRegion = other.mLiveRegion;
+        if (other.mExtras != null && !other.mExtras.isEmpty()) {
+            getExtras().putAll(other.mExtras);
+        }
+        mRangeInfo = (other.mRangeInfo != null)
+                ? RangeInfo.obtain(other.mRangeInfo) : null;
+        mCollectionInfo = (other.mCollectionInfo != null)
+                ? CollectionInfo.obtain(other.mCollectionInfo) : null;
+        mCollectionItemInfo =  (other.mCollectionItemInfo != null)
+                ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
     }
 
     /**
@@ -1927,6 +2286,37 @@
 
         mTextSelectionStart = parcel.readInt();
         mTextSelectionEnd = parcel.readInt();
+
+        mInputType = parcel.readInt();
+        mLiveRegion = parcel.readInt();
+
+        if (parcel.readInt() == 1) {
+            getExtras().putAll(parcel.readBundle());
+        }
+
+        if (parcel.readInt() == 1) {
+            mRangeInfo = RangeInfo.obtain(
+                    parcel.readInt(),
+                    parcel.readFloat(),
+                    parcel.readFloat(),
+                    parcel.readFloat());
+        }
+
+        if (parcel.readInt() == 1) {
+            mCollectionInfo = CollectionInfo.obtain(
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt() == 1);
+        }
+
+        if (parcel.readInt() == 1) {
+            mCollectionItemInfo = CollectionItemInfo.obtain(
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt(),
+                    parcel.readInt() == 1);
+        }
     }
 
     /**
@@ -1953,6 +2343,23 @@
         mActions = 0;
         mTextSelectionStart = UNDEFINED;
         mTextSelectionEnd = UNDEFINED;
+        mInputType = InputType.TYPE_NULL;
+        mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
+        if (mExtras != null) {
+            mExtras.clear();
+        }
+        if (mRangeInfo != null) {
+            mRangeInfo.recycle();
+            mRangeInfo = null;
+        }
+        if (mCollectionInfo != null) {
+            mCollectionInfo.recycle();
+            mCollectionInfo = null;
+        }
+        if (mCollectionItemInfo != null) {
+            mCollectionItemInfo.recycle();
+            mCollectionItemInfo = null;
+        }
     }
 
     /**
@@ -2132,6 +2539,360 @@
     }
 
     /**
+     * Class with information if a node is a range. Use
+     * {@link RangeInfo#obtain(int, float, float, float) to get an instance.
+     */
+    public static final class RangeInfo {
+        private static final int MAX_POOL_SIZE = 10;
+
+        /** Range type: integer. */
+        public static final int RANGE_TYPE_INT = 0;
+        /** Range type: float. */
+        public static final int RANGE_TYPE_FLOAT = 1;
+        /** Range type: percent with values from zero to one.*/
+        public static final int RANGE_TYPE_PERCENT = 2;
+
+        private static final SynchronizedPool<RangeInfo> sPool =
+                new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
+
+        private int mType;
+        private float mMin;
+        private float mMax;
+        private float mCurrent;
+
+        /**
+         * Obtains a pooled instance that is a clone of another one.
+         *
+         * @param other The instance to clone.
+         *
+         * @hide
+         */
+        public static RangeInfo obtain(RangeInfo other) {
+            return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
+        }
+
+        /**
+         * Obtains a pooled instance.
+         *
+         * @param type The type of the range.
+         * @param min The min value.
+         * @param max The max value.
+         * @param current The current value.
+         */
+        public static RangeInfo obtain(int type, float min, float max, float current) {
+            RangeInfo info = sPool.acquire();
+            return (info != null) ? info : new RangeInfo(type, min, max, current);
+        }
+
+        /**
+         * Creates a new range.
+         *
+         * @param type The type of the range.
+         * @param min The min value.
+         * @param max The max value.
+         * @param current The current value.
+         */
+        private RangeInfo(int type, float min, float max, float current) {
+            mType = type;
+            mMin = min;
+            mMax = max;
+            mCurrent = current;
+        }
+
+        /**
+         * Gets the range type.
+         *
+         * @return The range type.
+         *
+         * @see #RANGE_TYPE_INT
+         * @see #RANGE_TYPE_FLOAT
+         * @see #RANGE_TYPE_PERCENT
+         */
+        public int getType() {
+            return mType;
+        }
+
+        /**
+         * Gets the min value.
+         *
+         * @return The min value.
+         */
+        public float getMin() {
+            return mMin;
+        }
+
+        /**
+         * Gets the max value.
+         *
+         * @return The max value.
+         */
+        public float getMax() {
+            return mMax;
+        }
+
+        /**
+         * Gets the current value.
+         *
+         * @return The current value.
+         */
+        public float getCurrent() {
+            return mCurrent;
+        }
+
+        /**
+         * Recycles this instance.
+         */
+        void recycle() {
+            clear();
+            sPool.release(this);
+        }
+
+        private void clear() {
+            mType = 0;
+            mMin = 0;
+            mMax = 0;
+            mCurrent = 0;
+        }
+    }
+
+    /**
+     * Class with information if a node is a collection. Use
+     * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance.
+     * <p>
+     * A collection of items has rows and columns and may be hierarchical.
+     * For example, a horizontal list is a collection with one column, as
+     * many rows as the list items, and is not hierarchical; A table is a
+     * collection with several rows, several columns, and is not hierarchical;
+     * A vertical tree is a hierarchical collection with one column and
+     * as many rows as the first level children.
+     * </p>
+     */
+    public static final class CollectionInfo {
+        private static final int MAX_POOL_SIZE = 20;
+
+        private static final SynchronizedPool<CollectionInfo> sPool =
+                new SynchronizedPool<CollectionInfo>(MAX_POOL_SIZE);
+
+        private int mRowCount;
+        private int mColumnCount;
+        private boolean mHierarchical;
+
+        /**
+         * Obtains a pooled instance that is a clone of another one.
+         *
+         * @param other The instance to clone.
+         *
+         * @hide
+         */
+        public static CollectionInfo obtain(CollectionInfo other) {
+            return CollectionInfo.obtain(other.mRowCount, other.mColumnCount,
+                    other.mHierarchical);
+        }
+
+        /**
+         * Obtains a pooled instance.
+         *
+         * @param rowCount The number of rows.
+         * @param columnCount The number of columns.
+         * @param hierarchical Whether the collection is hierarchical.
+         */
+        public static CollectionInfo obtain(int rowCount, int columnCount,
+                boolean hierarchical) {
+            CollectionInfo info = sPool.acquire();
+            return (info != null) ? info : new CollectionInfo(rowCount,
+                    columnCount, hierarchical);
+        }
+
+        /**
+         * Creates a new instance.
+         *
+         * @param rowCount The number of rows.
+         * @param columnCount The number of columns.
+         * @param hierarchical Whether the collection is hierarchical.
+         */
+        private CollectionInfo(int rowCount, int columnCount,
+                boolean hierarchical) {
+            mRowCount = rowCount;
+            mColumnCount = columnCount;
+            mHierarchical = hierarchical;
+        }
+
+        /**
+         * Gets the number of rows.
+         *
+         * @return The row count.
+         */
+        public int getRowCount() {
+            return mRowCount;
+        }
+
+        /**
+         * Gets the number of columns.
+         *
+         * @return The column count.
+         */
+        public int getColumnCount() {
+            return mColumnCount;
+        }
+
+        /**
+         * Gets if the collection is a hierarchically ordered.
+         *
+         * @return Whether the collection is hierarchical.
+         */
+        public boolean isHierarchical() {
+            return mHierarchical;
+        }
+
+        /**
+         * Recycles this instance.
+         */
+        void recycle() {
+            clear();
+            sPool.release(this);
+        }
+
+        private void clear() {
+            mRowCount = 0;
+            mColumnCount = 0;
+            mHierarchical = false;
+        }
+    }
+
+    /**
+     * Class with information if a node is a collection item. Use
+     * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
+     * to get an instance.
+     * <p>
+     * A collection item is contained in a collection, it starts at
+     * a given row and column in the collection, and spans one or
+     * more rows and columns. For example, a header of two related
+     * table columns starts at the first row and the first column,
+     * spans one row and two columns.
+     * </p>
+     */
+    public static final class CollectionItemInfo {
+        private static final int MAX_POOL_SIZE = 20;
+
+        private static final SynchronizedPool<CollectionItemInfo> sPool =
+                new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
+
+        /**
+         * Obtains a pooled instance that is a clone of another one.
+         *
+         * @param other The instance to clone.
+         *
+         * @hide
+         */
+        public static CollectionItemInfo obtain(CollectionItemInfo other) {
+            return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan,
+                    other.mColumnIndex, other.mColumnSpan, other.mHeading);
+        }
+
+        /**
+         * Obtains a pooled instance.
+         *
+         * @param rowIndex The row index at which the item is located.
+         * @param rowSpan The number of rows the item spans.
+         * @param columnIndex The column index at which the item is located.
+         * @param columnSpan The number of columns the item spans.
+         * @param heading Whether the item is a heading.
+         */
+        public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
+                int columnIndex, int columnSpan, boolean heading) {
+            CollectionItemInfo info = sPool.acquire();
+            return (info != null) ? info : new CollectionItemInfo(rowIndex,
+                    rowSpan, columnIndex, columnSpan, heading);
+        }
+
+        private boolean mHeading;
+        private int mColumnIndex;
+        private int mRowIndex;
+        private int mColumnSpan;
+        private int mRowSpan;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param rowIndex The row index at which the item is located.
+         * @param rowSpan The number of rows the item spans.
+         * @param columnIndex The column index at which the item is located.
+         * @param columnSpan The number of columns the item spans.
+         * @param heading Whether the item is a heading.
+         */
+        private CollectionItemInfo(int rowIndex, int rowSpan,
+                int columnIndex, int columnSpan, boolean heading) {
+            mRowIndex = rowIndex;
+            mRowSpan = rowSpan;
+            mColumnIndex = columnIndex;
+            mColumnSpan = columnSpan;
+            mHeading = heading;
+        }
+
+        /**
+         * Gets the column index at which the item is located.
+         *
+         * @return The column index.
+         */
+        public int getColumnIndex() {
+            return mColumnIndex;
+        }
+
+        /**
+         * Gets the row index at which the item is located.
+         *
+         * @return The row index.
+         */
+        public int getRowIndex() {
+            return mRowIndex;
+        }
+
+        /**
+         * Gets the number of columns the item spans.
+         *
+         * @return The column span.
+         */
+        public int getColumnSpan() {
+            return mColumnSpan;
+        }
+
+        /**
+         * Gets the number of rows the item spans.
+         *
+         * @return The row span.
+         */
+        public int getRowSpan() {
+            return mRowSpan;
+        }
+
+        /**
+         * Gets if the collection item is a heading. For example, section
+         * heading, table header, etc.
+         *
+         * @return If the item is a heading.
+         */
+        public boolean isHeading() {
+            return mHeading;
+        }
+
+        /**
+         * Recycles this instance.
+         */
+        void recycle() {
+            clear();
+            sPool.release(this);
+        }
+
+        private void clear() {
+            mColumnIndex = 0;
+            mColumnSpan = 0;
+            mRowIndex = 0;
+            mRowSpan = 0;
+            mHeading = false;
+        }
+    }
+
+    /**
      * @see Parcelable.Creator
      */
     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index 28518aa..6bef78e 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -41,7 +41,7 @@
 
     private static final boolean DEBUG = false;
 
-    private static final boolean CHECK_INTEGRITY = true;
+    private static final boolean CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD = true;
 
     private final Object mLock = new Object();
 
@@ -67,16 +67,12 @@
         if (ENABLED) {
             final int eventType = event.getEventType();
             switch (eventType) {
-                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
-                    // New window so we clear the cache.
-                    mWindowId = event.getWindowId();
-                    clear();
-                } break;
+                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
                 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
                     final int windowId = event.getWindowId();
+                    // If a new window, we clear the cache.
                     if (mWindowId != windowId) {
-                        // New window so we clear the cache.
                         mWindowId = windowId;
                         clear();
                     }
@@ -87,34 +83,48 @@
                 case AccessibilityEvent.TYPE_VIEW_SELECTED:
                 case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
                 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
-                    // Since we prefetch the descendants of a node we
-                    // just remove the entire subtree since when the node
-                    // is fetched we will gets its descendant anyway.
+                    refreshCachedNode(event.getSourceNodeId());
+                } break;
+                case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
+                    clearSubTreeLocked(event.getSourceNodeId());
+                } break;
+                case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
                     synchronized (mLock) {
                         final long sourceId = event.getSourceNodeId();
-                        clearSubTreeLocked(sourceId);
-                        if (eventType == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
-                            clearSubtreeWithOldInputFocusLocked(sourceId);
+                        if ((event.getContentChangeTypes()
+                                & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0) {
+                            clearSubTreeLocked(sourceId);
+                        } else {
+                            refreshCachedNode(sourceId);
                         }
-                        if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
-                            clearSubtreeWithOldAccessibilityFocusLocked(sourceId);
-                        }
-                    }
-                } break;
-                case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
-                case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
-                    synchronized (mLock) {
-                        final long accessibilityNodeId = event.getSourceNodeId();
-                        clearSubTreeLocked(accessibilityNodeId);
                     }
                 } break;
             }
-            if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY) {
+            if (CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD && Build.IS_DEBUGGABLE) {
                 checkIntegrity();
             }
         }
     }
 
+    private void refreshCachedNode(long sourceId) {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "Refreshing cached node.");
+        }
+        synchronized (mLock) {
+            AccessibilityNodeInfo cachedInfo = mCacheImpl.get(sourceId);
+            // If the source is not in the cache - nothing to do.
+            if (cachedInfo == null) {
+                return;
+            }
+            // The node changed so we will just refresh it right now.
+            if (cachedInfo.refresh(true)) {
+                return;
+            }
+            // Weird, we could not refresh. Just evict the entire sub-tree.
+            clearSubTreeLocked(sourceId);
+        }
+    }
+
     /**
      * Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
      *
@@ -212,6 +222,13 @@
      * @param rootNodeId The root id.
      */
     private void clearSubTreeLocked(long rootNodeId) {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "Clearing cached subtree.");
+        }
+        clearSubTreeRecursiveLocked(rootNodeId);
+    }
+
+    private void clearSubTreeRecursiveLocked(long rootNodeId) {
         AccessibilityNodeInfo current = mCacheImpl.get(rootNodeId);
         if (current == null) {
             return;
@@ -221,41 +238,7 @@
         final int childCount = childNodeIds.size();
         for (int i = 0; i < childCount; i++) {
             final long childNodeId = childNodeIds.valueAt(i);
-            clearSubTreeLocked(childNodeId);
-        }
-    }
-
-    /**
-     * We are enforcing the invariant for a single input focus.
-     *
-     * @param currentInputFocusId The current input focused node.
-     */
-    private void clearSubtreeWithOldInputFocusLocked(long currentInputFocusId) {
-        final int cacheSize = mCacheImpl.size();
-        for (int i = 0; i < cacheSize; i++) {
-            AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
-            final long infoSourceId = info.getSourceNodeId();
-            if (infoSourceId != currentInputFocusId && info.isFocused()) {
-                clearSubTreeLocked(infoSourceId);
-                return;
-            }
-        }
-    }
-
-    /**
-     * We are enforcing the invariant for a single accessibility focus.
-     *
-     * @param currentAccessibilityFocusId The current input focused node.
-     */
-    private void clearSubtreeWithOldAccessibilityFocusLocked(long currentAccessibilityFocusId) {
-        final int cacheSize = mCacheImpl.size();
-        for (int i = 0; i < cacheSize; i++) {
-            AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
-            final long infoSourceId = info.getSourceNodeId();
-            if (infoSourceId != currentAccessibilityFocusId && info.isAccessibilityFocused()) {
-                clearSubTreeLocked(infoSourceId);
-                return;
-            }
+            clearSubTreeRecursiveLocked(childNodeId);
         }
     }
 
@@ -327,12 +310,11 @@
             }
 
             // Check for disconnected nodes or ones from another window.
-            final int cacheSize = mCacheImpl.size();
-            for (int i = 0; i < cacheSize; i++) {
+            for (int i = 0; i < mCacheImpl.size(); i++) {
                 AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
                 if (!seen.contains(info)) {
                     if (info.getWindowId() == windowId) {
-                        Log.e(LOG_TAG, "Disconneced node: ");
+                        Log.e(LOG_TAG, "Disconneced node: " + info);
                     } else {
                         Log.e(LOG_TAG, "Node from: " + info.getWindowId() + " not from:"
                                 + windowId + " " + info);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index 688cbdf..718c32f 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -132,4 +132,19 @@
             int virtualViewId) {
         return null;
     }
+
+    /**
+     * Find the virtual view, i.e. a descendant of the host View, that has the
+     * specified focus type.
+     *
+     * @param focus The focus to find. One of
+     *            {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+     *            {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     * @see AccessibilityNodeInfo#FOCUS_INPUT
+     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+     */
+    public AccessibilityNodeInfo findFocus(int focus) {
+        return null;
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 7147c57..3fcd218 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -164,7 +164,7 @@
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId,
-                mSourceNodeId, GET_SOURCE_PREFETCH_FLAGS);
+                mSourceNodeId, false, GET_SOURCE_PREFETCH_FLAGS);
     }
 
     /**
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
new file mode 100644
index 0000000..557239f
--- /dev/null
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -0,0 +1,405 @@
+/*
+ * 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 android.view.accessibility;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * Contains methods for accessing and monitoring preferred video captioning state and visual
+ * properties.
+ * <p>
+ * To obtain a handle to the captioning manager, do the following:
+ * <p>
+ * <code>
+ * <pre>CaptioningManager captioningManager =
+ *        (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);</pre>
+ * </code>
+ */
+public class CaptioningManager {
+    /** Default captioning enabled value. */
+    private static final int DEFAULT_ENABLED = 0;
+
+    /** Default style preset as an index into {@link CaptionStyle#PRESETS}. */
+    private static final int DEFAULT_PRESET = 0;
+
+    /** Default scaling value for caption fonts. */
+    private static final float DEFAULT_FONT_SCALE = 1;
+
+    private final ArrayList<CaptioningChangeListener>
+            mListeners = new ArrayList<CaptioningChangeListener>();
+    private final Handler mHandler = new Handler();
+
+    private final ContentResolver mContentResolver;
+
+    /**
+     * Creates a new captioning manager for the specified context.
+     *
+     * @hide
+     */
+    public CaptioningManager(Context context) {
+        mContentResolver = context.getContentResolver();
+    }
+
+    /**
+     * @return the user's preferred captioning enabled state
+     */
+    public final boolean isEnabled() {
+        return Secure.getInt(
+                mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_ENABLED, DEFAULT_ENABLED) == 1;
+    }
+
+    /**
+     * @return the raw locale string for the user's preferred captioning
+     *         language
+     * @hide
+     */
+    public final String getRawLocale() {
+        return Secure.getString(mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_LOCALE);
+    }
+
+    /**
+     * @return the locale for the user's preferred captioning language, or null
+     *         if not specified
+     */
+    public final Locale getLocale() {
+        final String rawLocale = getRawLocale();
+        if (!TextUtils.isEmpty(rawLocale)) {
+            final String[] splitLocale = rawLocale.split("_");
+            switch (splitLocale.length) {
+                case 3:
+                    return new Locale(splitLocale[0], splitLocale[1], splitLocale[2]);
+                case 2:
+                    return new Locale(splitLocale[0], splitLocale[1]);
+                case 1:
+                    return new Locale(splitLocale[0]);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @return the user's preferred font scaling factor for video captions, or 1 if not
+     *         specified
+     */
+    public final float getFontScale() {
+        return Secure.getFloat(
+                mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, DEFAULT_FONT_SCALE);
+    }
+
+    /**
+     * @return the raw preset number, or the first preset if not specified
+     * @hide
+     */
+    public int getRawUserStyle() {
+        return Secure.getInt(
+                mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_PRESET, DEFAULT_PRESET);
+    }
+
+    /**
+     * @return the user's preferred visual properties for captions as a
+     *         {@link CaptionStyle}, or the default style if not specified
+     */
+    public CaptionStyle getUserStyle() {
+        final int preset = getRawUserStyle();
+        if (preset == CaptionStyle.PRESET_CUSTOM) {
+            return CaptionStyle.getCustomStyle(mContentResolver);
+        }
+
+        return CaptionStyle.PRESETS[preset];
+    }
+
+    /**
+     * Adds a listener for changes in the user's preferred captioning enabled
+     * state and visual properties.
+     *
+     * @param listener the listener to add
+     */
+    public void addCaptioningChangeListener(CaptioningChangeListener listener) {
+        synchronized (mListeners) {
+            if (mListeners.isEmpty()) {
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_ENABLED);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE);
+                registerObserver(Secure.ACCESSIBILITY_CAPTIONING_LOCALE);
+            }
+
+            mListeners.add(listener);
+        }
+    }
+
+    private void registerObserver(String key) {
+        mContentResolver.registerContentObserver(Secure.getUriFor(key), false, mContentObserver);
+    }
+
+    /**
+     * Removes a listener previously added using
+     * {@link #addCaptioningChangeListener}.
+     *
+     * @param listener the listener to remove
+     */
+    public void removeCaptioningChangeListener(CaptioningChangeListener listener) {
+        synchronized (mListeners) {
+            mListeners.remove(listener);
+
+            if (mListeners.isEmpty()) {
+                mContentResolver.unregisterContentObserver(mContentObserver);
+            }
+        }
+    }
+
+    private void notifyEnabledChanged() {
+        final boolean enabled = isEnabled();
+        synchronized (mListeners) {
+            for (CaptioningChangeListener listener : mListeners) {
+                listener.onEnabledChanged(enabled);
+            }
+        }
+    }
+
+    private void notifyUserStyleChanged() {
+        final CaptionStyle userStyle = getUserStyle();
+        synchronized (mListeners) {
+            for (CaptioningChangeListener listener : mListeners) {
+                listener.onUserStyleChanged(userStyle);
+            }
+        }
+    }
+
+    private void notifyLocaleChanged() {
+        final Locale locale = getLocale();
+        synchronized (mListeners) {
+            for (CaptioningChangeListener listener : mListeners) {
+                listener.onLocaleChanged(locale);
+            }
+        }
+    }
+
+    private void notifyFontScaleChanged() {
+        final float fontScale = getFontScale();
+        synchronized (mListeners) {
+            for (CaptioningChangeListener listener : mListeners) {
+                listener.onFontScaleChanged(fontScale);
+            }
+        }
+    }
+
+    private final ContentObserver mContentObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            final String uriPath = uri.getPath();
+            final String name = uriPath.substring(uriPath.lastIndexOf('/') + 1);
+            if (Secure.ACCESSIBILITY_CAPTIONING_ENABLED.equals(name)) {
+                notifyEnabledChanged();
+            } else if (Secure.ACCESSIBILITY_CAPTIONING_LOCALE.equals(name)) {
+                notifyLocaleChanged();
+            } else if (Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE.equals(name)) {
+                notifyFontScaleChanged();
+            } else {
+                // We only need a single callback when multiple style properties
+                // change in rapid succession.
+                mHandler.removeCallbacks(mStyleChangedRunnable);
+                mHandler.post(mStyleChangedRunnable);
+            }
+        }
+    };
+
+    /**
+     * Runnable posted when user style properties change. This is used to
+     * prevent unnecessary change notifications when multiple properties change
+     * in rapid succession.
+     */
+    private final Runnable mStyleChangedRunnable = new Runnable() {
+        @Override
+        public void run() {
+            notifyUserStyleChanged();
+        }
+    };
+
+    /**
+     * Specifies visual properties for video captions, including foreground and
+     * background colors, edge properties, and typeface.
+     */
+    public static final class CaptionStyle {
+        private static final CaptionStyle WHITE_ON_BLACK;
+        private static final CaptionStyle BLACK_ON_WHITE;
+        private static final CaptionStyle YELLOW_ON_BLACK;
+        private static final CaptionStyle YELLOW_ON_BLUE;
+        private static final CaptionStyle DEFAULT_CUSTOM;
+
+        /** @hide */
+        public static final CaptionStyle[] PRESETS;
+
+        /** @hide */
+        public static final int PRESET_CUSTOM = -1;
+
+        /** Edge type value specifying no character edges. */
+        public static final int EDGE_TYPE_NONE = 0;
+
+        /** Edge type value specifying uniformly outlined character edges. */
+        public static final int EDGE_TYPE_OUTLINE = 1;
+
+        /** Edge type value specifying drop-shadowed character edges. */
+        public static final int EDGE_TYPE_DROP_SHADOW = 2;
+
+        /** The preferred foreground color for video captions. */
+        public final int foregroundColor;
+
+        /** The preferred background color for video captions. */
+        public final int backgroundColor;
+
+        /**
+         * The preferred edge type for video captions, one of:
+         * <ul>
+         * <li>{@link #EDGE_TYPE_NONE}
+         * <li>{@link #EDGE_TYPE_OUTLINE}
+         * <li>{@link #EDGE_TYPE_DROP_SHADOW}
+         * </ul>
+         */
+        public final int edgeType;
+
+        /**
+         * The preferred edge color for video captions, if using an edge type
+         * other than {@link #EDGE_TYPE_NONE}.
+         */
+        public final int edgeColor;
+
+        /**
+         * @hide
+         */
+        public final String mRawTypeface;
+
+        private Typeface mParsedTypeface;
+
+        private CaptionStyle(int foregroundColor, int backgroundColor, int edgeType, int edgeColor,
+                String rawTypeface) {
+            this.foregroundColor = foregroundColor;
+            this.backgroundColor = backgroundColor;
+            this.edgeType = edgeType;
+            this.edgeColor = edgeColor;
+
+            mRawTypeface = rawTypeface;
+        }
+
+        /**
+         * @return the preferred {@link Typeface} for video captions, or null if
+         *         not specified
+         */
+        public Typeface getTypeface() {
+            if (mParsedTypeface == null && !TextUtils.isEmpty(mRawTypeface)) {
+                mParsedTypeface = Typeface.create(mRawTypeface, Typeface.NORMAL);
+            }
+            return mParsedTypeface;
+        }
+
+        /**
+         * @hide
+         */
+        public static CaptionStyle getCustomStyle(ContentResolver cr) {
+            final CaptionStyle defStyle = CaptionStyle.DEFAULT_CUSTOM;
+            final int foregroundColor = Secure.getInt(
+                    cr, Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, defStyle.foregroundColor);
+            final int backgroundColor = Secure.getInt(
+                    cr, Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, defStyle.backgroundColor);
+            final int edgeType = Secure.getInt(
+                    cr, Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE, defStyle.edgeType);
+            final int edgeColor = Secure.getInt(
+                    cr, Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, defStyle.edgeColor);
+
+            String rawTypeface = Secure.getString(cr, Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE);
+            if (rawTypeface == null) {
+                rawTypeface = defStyle.mRawTypeface;
+            }
+
+            return new CaptionStyle(
+                    foregroundColor, backgroundColor, edgeType, edgeColor, rawTypeface);
+        }
+
+        static {
+            WHITE_ON_BLACK = new CaptionStyle(
+                    Color.WHITE, Color.BLACK, EDGE_TYPE_NONE, Color.BLACK, null);
+            BLACK_ON_WHITE = new CaptionStyle(
+                    Color.BLACK, Color.WHITE, EDGE_TYPE_NONE, Color.BLACK, null);
+            YELLOW_ON_BLACK = new CaptionStyle(
+                    Color.YELLOW, Color.BLACK, EDGE_TYPE_NONE, Color.BLACK, null);
+            YELLOW_ON_BLUE = new CaptionStyle(
+                    Color.YELLOW, Color.BLUE, EDGE_TYPE_NONE, Color.BLACK, null);
+
+            PRESETS = new CaptionStyle[] {
+                    WHITE_ON_BLACK, BLACK_ON_WHITE, YELLOW_ON_BLACK, YELLOW_ON_BLUE
+            };
+
+            DEFAULT_CUSTOM = WHITE_ON_BLACK;
+        }
+    }
+
+    /**
+     * Listener for changes in captioning properties, including enabled state
+     * and user style preferences.
+     */
+    public static abstract class CaptioningChangeListener {
+        /**
+         * Called when the captioning enabled state changes.
+         *
+         * @param enabled the user's new preferred captioning enabled state
+         */
+        public void onEnabledChanged(boolean enabled) {
+        }
+
+        /**
+         * Called when the captioning user style changes.
+         *
+         * @param userStyle the user's new preferred style
+         * @see CaptioningManager#getUserStyle()
+         */
+        public void onUserStyleChanged(CaptionStyle userStyle) {
+        }
+
+        /**
+         * Called when the captioning locale changes.
+         *
+         * @param locale the preferred captioning locale
+         * @see CaptioningManager#getLocale()
+         */
+        public void onLocaleChanged(Locale locale) {
+        }
+
+        /**
+         * Called when the captioning font scaling factor changes.
+         *
+         * @param fontScale the preferred font scaling factor
+         * @see CaptioningManager#getFontScale()
+         */
+        public void onFontScaleChanged(float fontScale) {
+        }
+    }
+}
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 14d3d19..71c7450 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -114,7 +114,7 @@
      * Constructor to use when building an AnimationSet from code
      * 
      * @param shareInterpolator Pass true if all of the animations in this set
-     *        should use the interpolator assocciated with this AnimationSet.
+     *        should use the interpolator associated with this AnimationSet.
      *        Pass false if each animation should use its own interpolator.
      */
     public AnimationSet(boolean shareInterpolator) {
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index e8c1d23..890909b 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -29,19 +29,19 @@
     /**
      * Indicates a transformation that has no effect (alpha = 1 and identity matrix.)
      */
-    public static int TYPE_IDENTITY = 0x0;
+    public static final int TYPE_IDENTITY = 0x0;
     /**
      * Indicates a transformation that applies an alpha only (uses an identity matrix.)
      */
-    public static int TYPE_ALPHA = 0x1;
+    public static final int TYPE_ALPHA = 0x1;
     /**
      * Indicates a transformation that applies a matrix only (alpha = 1.)
      */
-    public static int TYPE_MATRIX = 0x2;
+    public static final int TYPE_MATRIX = 0x2;
     /**
      * Indicates a transformation that applies an alpha and a matrix.
      */
-    public static int TYPE_BOTH = TYPE_ALPHA | TYPE_MATRIX;
+    public static final int TYPE_BOTH = TYPE_ALPHA | TYPE_MATRIX;
 
     protected Matrix mMatrix;
     protected float mAlpha;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index d6b973e..f730cf7 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -269,8 +269,9 @@
         if (content != null) {
             beginBatchEdit();
             removeComposingSpans(content);
-            endBatchEdit();
+            // Note: sendCurrentText does nothing unless mDummyMode is set
             sendCurrentText();
+            endBatchEdit();
         }
         return true;
     }
@@ -467,8 +468,9 @@
             content.setSpan(COMPOSING, a, b,
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
 
-            endBatchEdit();
+            // Note: sendCurrentText does nothing unless mDummyMode is set
             sendCurrentText();
+            endBatchEdit();
         }
         return true;
     }
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index e7d84c2..59330ca 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -337,14 +337,17 @@
     public boolean deleteSurroundingText(int beforeLength, int afterLength);
 
     /**
-     * Set composing text around the current cursor position with the
-     * given text, and set the new cursor position. Any composing text
-     * set previously will be removed automatically.
+     * Replace the currently composing text with the given text, and
+     * set the new cursor position. Any composing text set previously
+     * will be removed automatically.
      *
      * <p>If there is any composing span currently active, all
      * characters that it comprises are removed. The passed text is
      * added in its place, and a composing span is added to this
-     * text. Finally, the cursor is moved to the location specified by
+     * text. If there is no composing span active, the passed text is
+     * added at the cursor position (removing selected characters
+     * first if any), and a composing span is added on the new text.
+     * Finally, the cursor is moved to the location specified by
      * <code>newCursorPosition</code>.</p>
      *
      * <p>This is usually called by IMEs to add or remove or change
@@ -447,8 +450,10 @@
      *
      * <p>This method removes the contents of the currently composing
      * text and replaces it with the passed CharSequence, and then
-     * moves the cursor according to {@code newCursorPosition}.
-     * This behaves like calling
+     * moves the cursor according to {@code newCursorPosition}. If there
+     * is no composing text when this method is called, the new text is
+     * inserted at the cursor position, removing text inside the selection
+     * if any. This behaves like calling
      * {@link #setComposingText(CharSequence, int) setComposingText(text, newCursorPosition)}
      * then {@link #finishComposingText()}.</p>
      *
@@ -461,15 +466,16 @@
      * but be careful to wait until the batch edit is over if one is
      * in progress.</p>
      *
-     * @param text The committed text. This may include styles.
-     * @param newCursorPosition The new cursor position around the text. If
-     *        > 0, this is relative to the end of the text - 1; if <= 0, this
-     *        is relative to the start of the text. So a value of 1 will
-     *        always advance you to the position after the full text being
-     *        inserted. Note that this means you can't position the cursor
-     *        within the text, because the editor can make modifications to
-     *        the text you are providing so it is not possible to correctly
-     *        specify locations there.
+     * @param text The text to commit. This may include styles.
+     * @param newCursorPosition The new cursor position around the text,
+     *        in Java characters. If > 0, this is relative to the end
+     *        of the text - 1; if <= 0, this is relative to the start
+     *        of the text. So a value of 1 will always advance the cursor
+     *        to the position after the full text being inserted. Note that
+     *        this means you can't position the cursor within the text,
+     *        because the editor can make modifications to the text
+     *        you are providing so it is not possible to correctly specify
+     *        locations there.
      * @return true on success, false if the input connection is no longer
      * valid.
      */
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 54c2ba5..c440c7b 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -36,6 +36,7 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.Xml;
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -78,14 +79,19 @@
      */
     private final ArrayList<InputMethodSubtype> mSubtypes = new ArrayList<InputMethodSubtype>();
 
-    private boolean mIsAuxIme;
+    private final boolean mIsAuxIme;
 
     /**
-     * Cavert: mForceDefault must be false for production. This flag is only for test.
+     * Caveat: mForceDefault must be false for production. This flag is only for test.
      */
     private final boolean mForceDefault;
 
     /**
+     * The flag whether this IME supports ways to switch to a next input method (e.g. globe key.)
+     */
+    private final boolean mSupportsSwitchingToNextInputMethod;
+
+    /**
      * Constructor.
      *
      * @param context The Context in which we are parsing the input method.
@@ -112,7 +118,8 @@
         mService = service;
         ServiceInfo si = service.serviceInfo;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
-        mIsAuxIme = true;
+        boolean isAuxIme = true;
+        boolean supportsSwitchingToNextInputMethod = false; // false as default
         mForceDefault = false;
 
         PackageManager pm = context.getPackageManager();
@@ -148,6 +155,9 @@
                     com.android.internal.R.styleable.InputMethod_settingsActivity);
             isDefaultResId = sa.getResourceId(
                     com.android.internal.R.styleable.InputMethod_isDefault, 0);
+            supportsSwitchingToNextInputMethod = sa.getBoolean(
+                    com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod,
+                    false);
             sa.recycle();
 
             final int depth = parser.getDepth();
@@ -162,26 +172,28 @@
                     }
                     final TypedArray a = res.obtainAttributes(
                             attrs, com.android.internal.R.styleable.InputMethod_Subtype);
-                    InputMethodSubtype subtype = new InputMethodSubtype(
-                            a.getResourceId(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_label, 0),
-                            a.getResourceId(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_icon, 0),
-                            a.getString(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_imeSubtypeLocale),
-                            a.getString(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_imeSubtypeMode),
-                            a.getString(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_imeSubtypeExtraValue),
-                            a.getBoolean(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_isAuxiliary, false),
-                            a.getBoolean(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false),
-                            a.getInt(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */)
-                            );
+                    final InputMethodSubtype subtype = new InputMethodSubtypeBuilder()
+                            .setSubtypeNameResId(a.getResourceId(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_label, 0))
+                            .setSubtypeIconResId(a.getResourceId(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_icon, 0))
+                            .setSubtypeLocale(a.getString(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_imeSubtypeLocale))
+                            .setSubtypeMode(a.getString(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_imeSubtypeMode))
+                            .setSubtypeExtraValue(a.getString(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_imeSubtypeExtraValue))
+                            .setIsAuxiliary(a.getBoolean(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_isAuxiliary, false))
+                            .setOverridesImplicitlyEnabledSubtype(a.getBoolean(
+                                    com.android.internal.R.styleable
+                                    .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false))
+                            .setSubtypeId(a.getInt(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */))
+                            .setIsAsciiCapable(a.getBoolean(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_isAsciiCapable, false)).build();
                     if (!subtype.isAuxiliary()) {
-                        mIsAuxIme = false;
+                        isAuxIme = false;
                     }
                     mSubtypes.add(subtype);
                 }
@@ -194,7 +206,7 @@
         }
 
         if (mSubtypes.size() == 0) {
-            mIsAuxIme = false;
+            isAuxIme = false;
         }
 
         if (additionalSubtypesMap != null && additionalSubtypesMap.containsKey(mId)) {
@@ -212,6 +224,8 @@
         }
         mSettingsActivityName = settingsActivityComponent;
         mIsDefaultResId = isDefaultResId;
+        mIsAuxIme = isAuxIme;
+        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
     }
 
     InputMethodInfo(Parcel source) {
@@ -219,6 +233,7 @@
         mSettingsActivityName = source.readString();
         mIsDefaultResId = source.readInt();
         mIsAuxIme = source.readInt() == 1;
+        mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
         mService = ResolveInfo.CREATOR.createFromParcel(source);
         source.readTypedList(mSubtypes, InputMethodSubtype.CREATOR);
         mForceDefault = false;
@@ -250,6 +265,7 @@
             mSubtypes.addAll(subtypes);
         }
         mForceDefault = forceDefault;
+        mSupportsSwitchingToNextInputMethod = true;
     }
 
     private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
@@ -431,6 +447,14 @@
     }
 
     /**
+     * @return true if this input method supports ways to switch to a next input method.
+     * @hide
+     */
+    public boolean supportsSwitchingToNextInputMethod() {
+        return mSupportsSwitchingToNextInputMethod;
+    }
+
+    /**
      * Used to package this object into a {@link Parcel}.
      * 
      * @param dest The {@link Parcel} to be written.
@@ -442,6 +466,7 @@
         dest.writeString(mSettingsActivityName);
         dest.writeInt(mIsDefaultResId);
         dest.writeInt(mIsAuxIme ? 1 : 0);
+        dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
         mService.writeToParcel(dest, flags);
         dest.writeTypedList(mSubtypes);
     }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4df4734..53f7c79 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -613,7 +613,8 @@
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
             boolean allowsImplicitlySelectedSubtypes) {
         try {
-            return mService.getEnabledInputMethodSubtypeList(imi, allowsImplicitlySelectedSubtypes);
+            return mService.getEnabledInputMethodSubtypeList(
+                    imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -1411,12 +1412,17 @@
 
                 try {
                     if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
-                    mCurMethod.updateSelection(mCursorSelStart, mCursorSelEnd,
-                            selStart, selEnd, candidatesStart, candidatesEnd);
+                    final int oldSelStart = mCursorSelStart;
+                    final int oldSelEnd = mCursorSelEnd;
+                    // Update internal values before sending updateSelection to the IME, because
+                    // if it changes the text within its onUpdateSelection handler in a way that
+                    // does not move the cursor we don't want to call it again with the same values.
                     mCursorSelStart = selStart;
                     mCursorSelEnd = selEnd;
                     mCursorCandStart = candidatesStart;
                     mCursorCandEnd = candidatesEnd;
+                    mCurMethod.updateSelection(oldSelStart, oldSelEnd,
+                            selStart, selEnd, candidatesStart, candidatesEnd);
                 } catch (RemoteException e) {
                     Log.w(TAG, "IME died: " + mCurId, e);
                 }
@@ -1875,6 +1881,28 @@
     }
 
     /**
+     * Returns true if the current IME needs to offer the users ways to switch to a next input
+     * method (e.g. a globe key.).
+     * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
+     * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
+     * <p> Note that the system determines the most appropriate next input method
+     * and subtype in order to provide the consistent user experience in switching
+     * between IMEs and subtypes.
+     * @param imeToken Supplies the identifying token given to an input method when it was started,
+     * which allows it to perform this operation on itself.
+     */
+    public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
+        synchronized (mH) {
+            try {
+                return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+                return false;
+            }
+        }
+    }
+
+    /**
      * Set additional input method subtypes. Only a process which shares the same uid with the IME
      * can add additional input method subtypes to the IME.
      * Please note that a subtype's status is stored in the system.
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 7895e6f..88b2977 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -52,6 +52,7 @@
 
     private final boolean mIsAuxiliary;
     private final boolean mOverridesImplicitlyEnabledSubtype;
+    private final boolean mIsAsciiCapable;
     private final int mSubtypeHashCode;
     private final int mSubtypeIconResId;
     private final int mSubtypeNameResId;
@@ -62,24 +63,145 @@
     private volatile HashMap<String, String> mExtraValueHashMapCache;
 
     /**
+     * InputMethodSubtypeBuilder is a builder class of InputMethodSubtype.
+     * This class is designed to be used with
+     * {@link android.view.inputmethod.InputMethodManager#setAdditionalInputMethodSubtypes}.
+     * The developer needs to be aware of what each parameter means.
+     */
+    public static class InputMethodSubtypeBuilder {
+        /**
+         * @param isAuxiliary should true when this subtype is auxiliary, false otherwise.
+         * An auxiliary subtype has the following differences with a regular subtype:
+         * - An auxiliary subtype cannot be chosen as the default IME in Settings.
+         * - The framework will never switch to this subtype through
+         *   {@link android.view.inputmethod.InputMethodManager#switchToLastInputMethod}.
+         * Note that the subtype will still be available in the IME switcher.
+         * The intent is to allow for IMEs to specify they are meant to be invoked temporarily
+         * in a one-shot way, and to return to the previous IME once finished (e.g. voice input).
+         */
+        public InputMethodSubtypeBuilder setIsAuxiliary(boolean isAuxiliary) {
+            mIsAuxiliary = isAuxiliary;
+            return this;
+        }
+        private boolean mIsAuxiliary = false;
+
+        /**
+         * @param overridesImplicitlyEnabledSubtype should be true if this subtype should be
+         * enabled by default if no other subtypes in the IME are enabled explicitly. Note that a
+         * subtype with this parameter set will not be shown in the list of subtypes in each IME's
+         * subtype enabler. A canonical use of this would be for an IME to supply an "automatic"
+         * subtype that adapts to the current system language.
+         */
+        public InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(
+                boolean overridesImplicitlyEnabledSubtype) {
+            mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
+            return this;
+        }
+        private boolean mOverridesImplicitlyEnabledSubtype = false;
+
+        /**
+         * @param isAsciiCapable should be true if this subtype is ASCII capable. If the subtype
+         * is ASCII capable, it should guarantee that the user can input ASCII characters with
+         * this subtype. This is important because many password fields only allow
+         * ASCII-characters.
+         */
+        public InputMethodSubtypeBuilder setIsAsciiCapable(boolean isAsciiCapable) {
+            mIsAsciiCapable = isAsciiCapable;
+            return this;
+        }
+        private boolean mIsAsciiCapable = false;
+
+        /**
+         * @param subtypeIconResId is a resource ID of the subtype icon drawable.
+         */
+        public InputMethodSubtypeBuilder setSubtypeIconResId(int subtypeIconResId) {
+            mSubtypeIconResId = subtypeIconResId;
+            return this;
+        }
+        private int mSubtypeIconResId = 0;
+
+        /**
+         * @param subtypeNameResId is the resource ID of the subtype name string.
+         * The string resource may have exactly one %s in it. If present,
+         * the %s part will be replaced with the locale's display name by
+         * the formatter. Please refer to {@link #getDisplayName} for details.
+         */
+        public InputMethodSubtypeBuilder setSubtypeNameResId(int subtypeNameResId) {
+            mSubtypeNameResId = subtypeNameResId;
+            return this;
+        }
+        private int mSubtypeNameResId = 0;
+
+        /**
+         * @param subtypeId is the unique ID for this subtype. The input method framework keeps
+         * track of enabled subtypes by ID. When the IME package gets upgraded, enabled IDs will
+         * stay enabled even if other attributes are different. If the ID is unspecified or 0,
+         * Arrays.hashCode(new Object[] {locale, mode, extraValue,
+         * isAuxiliary, overridesImplicitlyEnabledSubtype}) will be used instead.
+         */
+        public InputMethodSubtypeBuilder setSubtypeId(int subtypeId) {
+            mSubtypeId = subtypeId;
+            return this;
+        }
+        private int mSubtypeId = 0;
+
+        /**
+         * @param subtypeLocale is the locale supported by this subtype.
+         */
+        public InputMethodSubtypeBuilder setSubtypeLocale(String subtypeLocale) {
+            mSubtypeLocale = subtypeLocale == null ? "" : subtypeLocale;
+            return this;
+        }
+        private String mSubtypeLocale = "";
+
+        /**
+         * @param subtypeMode is the mode supported by this subtype.
+         */
+        public InputMethodSubtypeBuilder setSubtypeMode(String subtypeMode) {
+            mSubtypeMode = subtypeMode == null ? "" : subtypeMode;
+            return this;
+        }
+        private String mSubtypeMode = "";
+        /**
+         * @param subtypeExtraValue is the extra value of the subtype. This string is free-form,
+         * but the API supplies tools to deal with a key-value comma-separated list; see
+         * {@link #containsExtraValueKey} and {@link #getExtraValueOf}.
+         */
+        public InputMethodSubtypeBuilder setSubtypeExtraValue(String subtypeExtraValue) {
+            mSubtypeExtraValue = subtypeExtraValue == null ? "" : subtypeExtraValue;
+            return this;
+        }
+        private String mSubtypeExtraValue = "";
+
+        /**
+         * @return InputMethodSubtype using parameters in this InputMethodSubtypeBuilder.
+         */
+        public InputMethodSubtype build() {
+            return new InputMethodSubtype(this);
+        }
+     }
+
+     private static InputMethodSubtypeBuilder getBuilder(int nameId, int iconId, String locale,
+             String mode, String extraValue, boolean isAuxiliary,
+             boolean overridesImplicitlyEnabledSubtype, int id, boolean isAsciiCapable) {
+         final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
+         builder.mSubtypeNameResId = nameId;
+         builder.mSubtypeIconResId = iconId;
+         builder.mSubtypeLocale = locale;
+         builder.mSubtypeMode = mode;
+         builder.mSubtypeExtraValue = extraValue;
+         builder.mIsAuxiliary = isAuxiliary;
+         builder.mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
+         builder.mSubtypeId = id;
+         builder.mIsAsciiCapable = isAsciiCapable;
+         return builder;
+     }
+
+    /**
      * Constructor with no subtype ID specified, overridesImplicitlyEnabledSubtype not specified.
-     * @param nameId Resource ID of the subtype name string. The string resource may have exactly
-     * one %s in it. If there is, the %s part will be replaced with the locale's display name by
-     * the formatter. Please refer to {@link #getDisplayName} for details.
-     * @param iconId Resource ID of the subtype icon drawable.
-     * @param locale The locale supported by the subtype
-     * @param mode The mode supported by the subtype
-     * @param extraValue The extra value of the subtype. This string is free-form, but the API
-     * supplies tools to deal with a key-value comma-separated list; see
-     * {@link #containsExtraValueKey} and {@link #getExtraValueOf}.
-     * @param isAuxiliary true when this subtype is auxiliary, false otherwise. An auxiliary
-     * subtype will not be shown in the list of enabled IMEs for choosing the current IME in
-     * the Settings even when this subtype is enabled. Please note that this subtype will still
-     * be shown in the list of IMEs in the IME switcher to allow the user to tentatively switch
-     * to this subtype while an IME is shown. The framework will never switch the current IME to
-     * this subtype by {@link android.view.inputmethod.InputMethodManager#switchToLastInputMethod}.
-     * The intent of having this flag is to allow for IMEs that are invoked in a one-shot way as
-     * auxiliary input mode, and return to the previous IME once it is finished (e.g. voice input).
+     * Arguments for this constructor have the same meanings as
+     * {@link InputMethodSubtype#InputMethodSubtype(int, int, String, String, String, boolean,
+     * boolean, int)} except "id" and "overridesImplicitlyEnabledSubtype".
      * @hide
      */
     public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
@@ -89,27 +211,10 @@
 
     /**
      * Constructor with no subtype ID specified.
-     * @param nameId Resource ID of the subtype name string. The string resource may have exactly
-     * one %s in it. If there is, the %s part will be replaced with the locale's display name by
-     * the formatter. Please refer to {@link #getDisplayName} for details.
-     * @param iconId Resource ID of the subtype icon drawable.
-     * @param locale The locale supported by the subtype
-     * @param mode The mode supported by the subtype
-     * @param extraValue The extra value of the subtype. This string is free-form, but the API
-     * supplies tools to deal with a key-value comma-separated list; see
-     * {@link #containsExtraValueKey} and {@link #getExtraValueOf}.
-     * @param isAuxiliary true when this subtype is auxiliary, false otherwise. An auxiliary
-     * subtype will not be shown in the list of enabled IMEs for choosing the current IME in
-     * the Settings even when this subtype is enabled. Please note that this subtype will still
-     * be shown in the list of IMEs in the IME switcher to allow the user to tentatively switch
-     * to this subtype while an IME is shown. The framework will never switch the current IME to
-     * this subtype by {@link android.view.inputmethod.InputMethodManager#switchToLastInputMethod}.
-     * The intent of having this flag is to allow for IMEs that are invoked in a one-shot way as
-     * auxiliary input mode, and return to the previous IME once it is finished (e.g. voice input).
-     * @param overridesImplicitlyEnabledSubtype true when this subtype should be enabled by default
-     * if no other subtypes in the IME are enabled explicitly. Note that a subtype with this
-     * parameter being true will not be shown in the list of subtypes in each IME's subtype enabler.
-     * Having an "automatic" subtype is an example use of this flag.
+     * @deprecated use {@link InputMethodSubtypeBuilder} instead.
+     * Arguments for this constructor have the same meanings as
+     * {@link InputMethodSubtype#InputMethodSubtype(int, int, String, String, String, boolean,
+     * boolean, int)} except "id".
      */
     public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
@@ -119,6 +224,8 @@
 
     /**
      * Constructor.
+     * @deprecated use {@link InputMethodSubtypeBuilder} instead.
+     * "isAsciiCapable" is "false" in this constructor.
      * @param nameId Resource ID of the subtype name string. The string resource may have exactly
      * one %s in it. If there is, the %s part will be replaced with the locale's display name by
      * the formatter. Please refer to {@link #getDisplayName} for details.
@@ -148,18 +255,29 @@
      */
     public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, int id) {
-        mSubtypeNameResId = nameId;
-        mSubtypeIconResId = iconId;
-        mSubtypeLocale = locale != null ? locale : "";
-        mSubtypeMode = mode != null ? mode : "";
-        mSubtypeExtraValue = extraValue != null ? extraValue : "";
-        mIsAuxiliary = isAuxiliary;
-        mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
+        this(getBuilder(nameId, iconId, locale, mode, extraValue, isAuxiliary,
+                overridesImplicitlyEnabledSubtype, id, false));
+    }
+
+    /**
+     * Constructor.
+     * @param builder Builder for InputMethodSubtype
+     */
+    private InputMethodSubtype(InputMethodSubtypeBuilder builder) {
+        mSubtypeNameResId = builder.mSubtypeNameResId;
+        mSubtypeIconResId = builder.mSubtypeIconResId;
+        mSubtypeLocale = builder.mSubtypeLocale;
+        mSubtypeMode = builder.mSubtypeMode;
+        mSubtypeExtraValue = builder.mSubtypeExtraValue;
+        mIsAuxiliary = builder.mIsAuxiliary;
+        mOverridesImplicitlyEnabledSubtype = builder.mOverridesImplicitlyEnabledSubtype;
+        mSubtypeId = builder.mSubtypeId;
+        mIsAsciiCapable = builder.mIsAsciiCapable;
         // If hashCode() of this subtype is 0 and you want to specify it as an id of this subtype,
         // just specify 0 as this subtype's id. Then, this subtype's id is treated as 0.
-        mSubtypeHashCode = id != 0 ? id : hashCodeInternal(mSubtypeLocale, mSubtypeMode,
-                mSubtypeExtraValue, mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
-        mSubtypeId = id;
+        mSubtypeHashCode = mSubtypeId != 0 ? mSubtypeId : hashCodeInternal(mSubtypeLocale,
+                mSubtypeMode, mSubtypeExtraValue, mIsAuxiliary, mOverridesImplicitlyEnabledSubtype,
+                mIsAsciiCapable);
     }
 
     InputMethodSubtype(Parcel source) {
@@ -176,6 +294,7 @@
         mOverridesImplicitlyEnabledSubtype = (source.readInt() == 1);
         mSubtypeHashCode = source.readInt();
         mSubtypeId = source.readInt();
+        mIsAsciiCapable = (source.readInt() == 1);
     }
 
     /**
@@ -239,6 +358,15 @@
     }
 
     /**
+     * @return true if this subtype is Ascii capable, false otherwise. If the subtype is ASCII
+     * capable, it should guarantee that the user can input ASCII characters with this subtype.
+     * This is important because many password fields only allow ASCII-characters.
+     */
+    public boolean isAsciiCapable() {
+        return mIsAsciiCapable;
+    }
+
+    /**
      * @param context Context will be used for getting Locale and PackageManager.
      * @param packageName The package name of the IME
      * @param appInfo The application info of the IME
@@ -336,7 +464,8 @@
                 && (subtype.getIconResId() == getIconResId())
                 && (subtype.getLocale().equals(getLocale()))
                 && (subtype.getExtraValue().equals(getExtraValue()))
-                && (subtype.isAuxiliary() == isAuxiliary());
+                && (subtype.isAuxiliary() == isAuxiliary())
+                && (subtype.isAsciiCapable() == isAsciiCapable());
         }
         return false;
     }
@@ -357,6 +486,7 @@
         dest.writeInt(mOverridesImplicitlyEnabledSubtype ? 1 : 0);
         dest.writeInt(mSubtypeHashCode);
         dest.writeInt(mSubtypeId);
+        dest.writeInt(mIsAsciiCapable ? 1 : 0);
     }
 
     public static final Parcelable.Creator<InputMethodSubtype> CREATOR
@@ -389,9 +519,10 @@
     }
 
     private static int hashCodeInternal(String locale, String mode, String extraValue,
-            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
+            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
+            boolean isAsciiCapable) {
         return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
-                overridesImplicitlyEnabledSubtype});
+                overridesImplicitlyEnabledSubtype, isAsciiCapable});
     }
 
     /**
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index fea6be6..7707392 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -50,7 +50,9 @@
  */
 class CallbackProxy extends Handler {
     // Logging tag
-    private static final String LOGTAG = "CallbackProxy";
+    static final String LOGTAG = "WebViewCallback";
+    // Enables API callback tracing
+    private static final boolean TRACE = DebugFlags.TRACE_CALLBACK;
     // Instance of WebViewClient that is the client callback.
     private volatile WebViewClient mWebViewClient;
     // Instance of WebChromeClient for handling all chrome functions.
@@ -258,6 +260,7 @@
         }
         boolean override = false;
         if (mWebViewClient != null) {
+            if (TRACE) Log.d(LOGTAG, "shouldOverrideUrlLoading=" + overrideUrl);
             override = mWebViewClient.shouldOverrideUrlLoading(mWebView.getWebView(),
                     overrideUrl);
         } else {
@@ -307,6 +310,7 @@
                 String startedUrl = msg.getData().getString("url");
                 mWebView.onPageStarted(startedUrl);
                 if (mWebViewClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onPageStarted=" + startedUrl);
                     mWebViewClient.onPageStarted(mWebView.getWebView(), startedUrl,
                             (Bitmap) msg.obj);
                 }
@@ -316,18 +320,21 @@
                 String finishedUrl = (String) msg.obj;
                 mWebView.onPageFinished(finishedUrl);
                 if (mWebViewClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onPageFinished=" + finishedUrl);
                     mWebViewClient.onPageFinished(mWebView.getWebView(), finishedUrl);
                 }
                 break;
 
             case RECEIVED_ICON:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onReceivedIcon");
                     mWebChromeClient.onReceivedIcon(mWebView.getWebView(), (Bitmap) msg.obj);
                 }
                 break;
 
             case RECEIVED_TOUCH_ICON_URL:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onReceivedTouchIconUrl");
                     mWebChromeClient.onReceivedTouchIconUrl(mWebView.getWebView(),
                             (String) msg.obj, msg.arg1 == 1);
                 }
@@ -335,6 +342,7 @@
 
             case RECEIVED_TITLE:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onReceivedTitle");
                     mWebChromeClient.onReceivedTitle(mWebView.getWebView(),
                             (String) msg.obj);
                 }
@@ -345,6 +353,7 @@
                     int reasonCode = msg.arg1;
                     final String description  = msg.getData().getString("description");
                     final String failUrl  = msg.getData().getString("failingUrl");
+                    if (TRACE) Log.d(LOGTAG, "onReceivedError=" + failUrl);
                     mWebViewClient.onReceivedError(mWebView.getWebView(), reasonCode,
                             description, failUrl);
                 }
@@ -356,6 +365,7 @@
                 Message dontResend =
                         (Message) msg.getData().getParcelable("dontResend");
                 if (mWebViewClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onFormResubmission");
                     mWebViewClient.onFormResubmission(mWebView.getWebView(), dontResend,
                             resend);
                 } else {
@@ -379,6 +389,7 @@
                     HttpAuthHandler handler = (HttpAuthHandler) msg.obj;
                     String host = msg.getData().getString("host");
                     String realm = msg.getData().getString("realm");
+                    if (TRACE) Log.d(LOGTAG, "onReceivedHttpAuthRequest");
                     mWebViewClient.onReceivedHttpAuthRequest(mWebView.getWebView(), handler,
                             host, realm);
                 }
@@ -388,6 +399,7 @@
                 if (mWebViewClient != null) {
                     HashMap<String, Object> map =
                         (HashMap<String, Object>) msg.obj;
+                    if (TRACE) Log.d(LOGTAG, "onReceivedSslError");
                     mWebViewClient.onReceivedSslError(mWebView.getWebView(),
                             (SslErrorHandler) map.get("handler"),
                             (SslError) map.get("error"));
@@ -396,6 +408,7 @@
 
             case PROCEEDED_AFTER_SSL_ERROR:
                 if (mWebViewClient != null && mWebViewClient instanceof WebViewClientClassicExt) {
+                    if (TRACE) Log.d(LOGTAG, "onProceededAfterSslError");
                     ((WebViewClientClassicExt) mWebViewClient).onProceededAfterSslError(
                             mWebView.getWebView(),
                             (SslError) msg.obj);
@@ -404,6 +417,7 @@
 
             case CLIENT_CERT_REQUEST:
                 if (mWebViewClient != null  && mWebViewClient instanceof WebViewClientClassicExt) {
+                    if (TRACE) Log.d(LOGTAG, "onReceivedClientCertRequest");
                     HashMap<String, Object> map = (HashMap<String, Object>) msg.obj;
                     ((WebViewClientClassicExt) mWebViewClient).onReceivedClientCertRequest(
                             mWebView.getWebView(),
@@ -418,6 +432,7 @@
                 // changed.
                 synchronized (this) {
                     if (mWebChromeClient != null) {
+                        if (TRACE) Log.d(LOGTAG, "onProgressChanged=" + mLatestProgress);
                         mWebChromeClient.onProgressChanged(mWebView.getWebView(),
                                 mLatestProgress);
                     }
@@ -427,14 +442,18 @@
 
             case UPDATE_VISITED:
                 if (mWebViewClient != null) {
+                    String url = (String) msg.obj;
+                    if (TRACE) Log.d(LOGTAG, "doUpdateVisitedHistory=" + url);
                     mWebViewClient.doUpdateVisitedHistory(mWebView.getWebView(),
-                            (String) msg.obj, msg.arg1 != 0);
+                            url, msg.arg1 != 0);
                 }
                 break;
 
             case LOAD_RESOURCE:
                 if (mWebViewClient != null) {
-                    mWebViewClient.onLoadResource(mWebView.getWebView(), (String) msg.obj);
+                    String url = (String) msg.obj;
+                    if (TRACE) Log.d(LOGTAG, "onLoadResource=" + url);
+                    mWebViewClient.onLoadResource(mWebView.getWebView(), url);
                 }
                 break;
 
@@ -448,6 +467,7 @@
                     String referer = msg.getData().getString("referer");
                     Long contentLength = msg.getData().getLong("contentLength");
 
+                    if (TRACE) Log.d(LOGTAG, "onDownloadStart");
                     if (mDownloadListener instanceof BrowserDownloadListener) {
                         ((BrowserDownloadListener) mDownloadListener).onDownloadStart(url,
                              userAgent, contentDisposition, mimetype, referer, contentLength);
@@ -460,6 +480,7 @@
 
             case CREATE_WINDOW:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onCreateWindow");
                     if (!mWebChromeClient.onCreateWindow(mWebView.getWebView(),
                                 msg.arg1 == 1, msg.arg2 == 1,
                                 (Message) msg.obj)) {
@@ -473,12 +494,14 @@
 
             case REQUEST_FOCUS:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onRequestFocus");
                     mWebChromeClient.onRequestFocus(mWebView.getWebView());
                 }
                 break;
 
             case CLOSE_WINDOW:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onCloseWindow");
                     mWebChromeClient.onCloseWindow(((WebViewClassic) msg.obj).getWebView());
                 }
                 break;
@@ -500,6 +523,7 @@
 
             case ASYNC_KEYEVENTS:
                 if (mWebViewClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onUnhandledKeyEvent");
                     mWebViewClient.onUnhandledKeyEvent(mWebView.getWebView(),
                             (KeyEvent) msg.obj);
                 }
@@ -521,6 +545,7 @@
                     WebStorage.QuotaUpdater quotaUpdater =
                         (WebStorage.QuotaUpdater) map.get("quotaUpdater");
 
+                    if (TRACE) Log.d(LOGTAG, "onExceededDatabaseQuota");
                     mWebChromeClient.onExceededDatabaseQuota(url,
                             databaseIdentifier, quota, estimatedDatabaseSize,
                             totalQuota, quotaUpdater);
@@ -538,6 +563,7 @@
                     WebStorage.QuotaUpdater quotaUpdater =
                         (WebStorage.QuotaUpdater) map.get("quotaUpdater");
 
+                    if (TRACE) Log.d(LOGTAG, "onReachedMaxAppCacheSize");
                     mWebChromeClient.onReachedMaxAppCacheSize(requiredStorage,
                             quota, quotaUpdater);
                 }
@@ -551,6 +577,7 @@
                     GeolocationPermissions.Callback callback =
                             (GeolocationPermissions.Callback)
                             map.get("callback");
+                    if (TRACE) Log.d(LOGTAG, "onGeolocationPermissionsShowPrompt");
                     mWebChromeClient.onGeolocationPermissionsShowPrompt(origin,
                             callback);
                 }
@@ -558,6 +585,7 @@
 
             case GEOLOCATION_PERMISSIONS_HIDE_PROMPT:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onGeolocationPermissionsHidePrompt");
                     mWebChromeClient.onGeolocationPermissionsHidePrompt();
                 }
                 break;
@@ -566,6 +594,7 @@
                 if (mWebChromeClient != null) {
                     final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
                     JsDialogHelper helper = new JsDialogHelper(receiver.mJsResult, msg);
+                    if (TRACE) Log.d(LOGTAG, "onJsAlert");
                     if (!helper.invokeCallback(mWebChromeClient, mWebView.getWebView())) {
                         helper.showDialog(mContext);
                     }
@@ -577,6 +606,7 @@
                 if(mWebChromeClient != null) {
                     final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
                     final JsResult res = receiver.mJsResult;
+                    if (TRACE) Log.d(LOGTAG, "onJsTimeout");
                     if (mWebChromeClient.onJsTimeout()) {
                         res.confirm();
                     } else {
@@ -598,6 +628,7 @@
 
             case SCALE_CHANGED:
                 if (mWebViewClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onScaleChanged");
                     mWebViewClient.onScaleChanged(mWebView.getWebView(), msg.getData()
                             .getFloat("old"), msg.getData().getFloat("new"));
                 }
@@ -624,6 +655,7 @@
                 ConsoleMessage.MessageLevel messageLevel =
                         ConsoleMessage.MessageLevel.values()[msgLevel];
 
+                if (TRACE) Log.d(LOGTAG, "onConsoleMessage");
                 if (!mWebChromeClient.onConsoleMessage(new ConsoleMessage(message, sourceID,
                         lineNumber, messageLevel))) {
                     // If false was returned the user did not provide their own console function so
@@ -654,12 +686,14 @@
 
             case GET_VISITED_HISTORY:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "getVisitedHistory");
                     mWebChromeClient.getVisitedHistory((ValueCallback<String[]>)msg.obj);
                 }
                 break;
 
             case OPEN_FILE_CHOOSER:
                 if (mWebChromeClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "openFileChooser");
                     UploadFileMessageData data = (UploadFileMessageData)msg.obj;
                     mWebChromeClient.openFileChooser(data.getUploadFile(), data.getAcceptType(),
                             data.getCapture());
@@ -668,6 +702,7 @@
 
             case ADD_HISTORY_ITEM:
                 if (mWebBackForwardListClient != null) {
+                    if (TRACE) Log.d(LOGTAG, "onNewHistoryItem");
                     mWebBackForwardListClient.onNewHistoryItem(
                             (WebHistoryItem) msg.obj);
                 }
@@ -693,6 +728,7 @@
                     String realm = msg.getData().getString("realm");
                     String account = msg.getData().getString("account");
                     String args = msg.getData().getString("args");
+                    if (TRACE) Log.d(LOGTAG, "onReceivedLoginRequest");
                     mWebViewClient.onReceivedLoginRequest(mWebView.getWebView(), realm,
                             account, args);
                 }
@@ -910,6 +946,7 @@
             return null;
         }
         // Note: This method does _not_ send a message.
+        if (TRACE) Log.d(LOGTAG, "shouldInterceptRequest=" + url);
         WebResourceResponse r =
                 mWebViewClient.shouldInterceptRequest(mWebView.getWebView(), url);
         if (r == null) {
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 349113e..524f610 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -24,25 +24,33 @@
  * The name of each flags maps directly to the name of the class in which that
  * flag is used.
  *
+ * @hide Only used by WebView implementations.
  */
-class DebugFlags {
+public class DebugFlags {
 
+    public static final boolean COOKIE_SYNC_MANAGER = false;
+    public static final boolean TRACE_API = false;
+    public static final boolean TRACE_CALLBACK = false;
+    public static final boolean TRACE_JAVASCRIPT_BRIDGE = false;
+    public static final boolean URL_UTIL = false;
+    public static final boolean WEB_SYNC_MANAGER = false;
+
+    // TODO: Delete these when WebViewClassic is moved
     public static final boolean BROWSER_FRAME = false;
     public static final boolean CACHE_MANAGER = false;
     public static final boolean CALLBACK_PROXY = false;
     public static final boolean COOKIE_MANAGER = false;
-    public static final boolean COOKIE_SYNC_MANAGER = false;
     public static final boolean FRAME_LOADER = false;
     public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
     public static final boolean LOAD_LISTENER = false;
+    public static final boolean MEASURE_PAGE_SWAP_FPS = false;
     public static final boolean NETWORK = false;
     public static final boolean SSL_ERROR_HANDLER = false;
     public static final boolean STREAM_LOADER = false;
-    public static final boolean URL_UTIL = false;
     public static final boolean WEB_BACK_FORWARD_LIST = false;
     public static final boolean WEB_SETTINGS = false;
-    public static final boolean WEB_SYNC_MANAGER = false;
     public static final boolean WEB_VIEW = false;
     public static final boolean WEB_VIEW_CORE = false;
-    public static final boolean MEASURE_PAGE_SWAP_FPS = false;
+
+
 }
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index b52218d..6fb32c8 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.media.MediaPlayer;
 import android.media.Metadata;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
@@ -293,12 +294,16 @@
         mLayout.setVisibility(View.VISIBLE);
         WebChromeClient client = webView.getWebChromeClient();
         if (client != null) {
+            if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onShowCustomView");
             client.onShowCustomView(mLayout, mCallback);
             // Plugins like Flash will draw over the video so hide
             // them while we're playing.
             if (webView.getViewManager() != null)
                 webView.getViewManager().hideAll();
 
+            if (DebugFlags.TRACE_CALLBACK) {
+                Log.d(CallbackProxy.LOGTAG, "getVideoLoadingProgressView");
+            }
             mProgressView = client.getVideoLoadingProgressView();
             if (mProgressView != null) {
                 mLayout.addView(mProgressView, layoutParams);
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index a3d62ae..e8538f6 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -180,6 +180,7 @@
             if (!mHTML5VideoView.fullScreenExited() && mHTML5VideoView.isFullScreenMode()) {
                 WebChromeClient client = webView.getWebChromeClient();
                 if (client != null) {
+                    if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onHideCustomView");
                     client.onHideCustomView();
                 }
             }
@@ -405,6 +406,7 @@
             case ERROR: {
                 WebChromeClient client = mWebView.getWebChromeClient();
                 if (client != null) {
+                    if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onHideCustomView");
                     client.onHideCustomView();
                 }
                 break;
@@ -412,6 +414,9 @@
             case LOAD_DEFAULT_POSTER: {
                 WebChromeClient client = mWebView.getWebChromeClient();
                 if (client != null) {
+                    if (DebugFlags.TRACE_CALLBACK) {
+                        Log.d(CallbackProxy.LOGTAG, "getDefaultVideoPoster");
+                    }
                     doSetPoster(client.getDefaultVideoPoster());
                 }
                 break;
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
     * @param totalQuota The total quota for all origins, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onExceededDatabaseQuota(String url, String databaseIdentifier,
             long quota, long estimatedDatabaseSize, long totalQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
     * @param quota the current maximum Application Cache size, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
             WebStorage.QuotaUpdater quotaUpdater) {
         quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 8ae0021..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
     /**
      * Enum for controlling the layout of html.
      * <ul>
-     *   <li>NORMAL means no rendering changes.</li>
+     *   <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+     *       compatibility across different platforms and Android versions.</li>
      *   <li>SINGLE_COLUMN moves all content into one column that is the width of the
      *       view.</li>
-     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+     *       this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
      *   <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
      *       the text readable when viewing a wide-viewport layout in the overview mode.
      *       It is recommended to enable zoom support {@link #setSupportZoom} when
-     *       using this mode.</li>
+     *       using this mode. Supported from API level
+     *       {@link android.os.Build.VERSION_CODES#KITKAT}</li>
      * </ul>
      */
     // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
          */
         @Deprecated
         SINGLE_COLUMN,
-        NARROW_COLUMNS,
         /**
-         * @hide
+         * @deprecated This algorithm is now obsolete.
          */
+        @Deprecated
+        NARROW_COLUMNS,
         TEXT_AUTOSIZING
     }
 
@@ -333,8 +337,11 @@
     }
 
     /**
-     * Sets whether the WebView loads pages in overview mode. The default is
-     * false.
+     * Sets whether the WebView loads pages in overview mode, that is,
+     * zooms out the content to fit on screen by width. This setting is
+     * taken into account when the content width is greater than the width
+     * of the WebView control, for example, when {@link #getUseWideViewPort}
+     * is enabled. The default is false.
      */
     public void setLoadWithOverviewMode(boolean overview) {
         throw new MustOverrideException();
@@ -500,8 +507,17 @@
      * Sets the default zoom density of the page. This must be called from the UI
      * thread. The default is {@link ZoomDensity#MEDIUM}.
      *
+     * This setting is not recommended for use in new applications.  If the WebView
+     * is utilized to display mobile-oriented pages, the desired effect can be achieved by
+     * adjusting 'width' and 'initial-scale' attributes of page's 'meta viewport'
+     * tag. For pages lacking the tag, {@link android.webkit.WebView#setInitialScale}
+     * and {@link #setUseWideViewPort} can be used.
+     *
      * @param zoom the zoom density
+     * @deprecated This method is no longer supported, see the function documentation for
+     *             recommended alternatives.
      */
+    @Deprecated
     public void setDefaultZoom(ZoomDensity zoom) {
         throw new MustOverrideException();
     }
@@ -510,8 +526,11 @@
      * Gets the default zoom density of the page. This should be called from
      * the UI thread.
      *
+     * This setting is not recommended for use in new applications.
+     *
      * @return the zoom density
      * @see #setDefaultZoom
+     * @deprecated Will only return the default value.
      */
     public ZoomDensity getDefaultZoom() {
         throw new MustOverrideException();
@@ -1048,10 +1067,13 @@
      *
      * @param databasePath a path to the directory where databases should be
      *                     saved.
+     * @deprecated Database paths are managed by the implementation and calling this method
+     *             will have no effect.
      */
     // This will update WebCore when the Sync runs in the C++ side.
     // Note that the WebCore Database Tracker only allows the path to be set
     // once.
+    @Deprecated
     public synchronized void setDatabasePath(String databasePath) {
         throw new MustOverrideException();
     }
@@ -1150,7 +1172,9 @@
      *
      * @return the String path to the database storage API databases
      * @see #setDatabasePath
+     * @deprecated Database paths are managed by the implementation this method is obsolete.
      */
+    @Deprecated
     public synchronized String getDatabasePath() {
         throw new MustOverrideException();
     }
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
      * See
      * {@link WebChromeClient#onExceededDatabaseQuota} and
      * {@link WebChromeClient#onReachedMaxAppCacheSize}.
+     * @deprecated This class is obsolete and no longer used.
      */
-    // We primarily want this to allow us to call back the sleeping WebCore
-    // thread from outside the WebViewCore class (as the native call is
-    // private). It is imperative that the setDatabaseQuota method is
-    // executed after a decision to either allow or deny new quota is made,
-    // otherwise the WebCore thread will remain asleep.
+    @Deprecated
     public interface QuotaUpdater {
         /**
          * Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4998742..90cc72e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -28,9 +28,11 @@
 import android.net.http.SslCertificate;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.Looper;
 import android.os.Message;
 import android.os.StrictMode;
+import android.print.PrintDocumentAdapter;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -41,6 +43,7 @@
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.widget.AbsoluteLayout;
@@ -55,9 +58,6 @@
  * It uses the WebKit rendering engine to display
  * web pages and includes methods to navigate forward and backward
  * through a history, zoom in and out, perform text searches and more.</p>
- * <p>To enable the built-in zoom, set
- * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
- * (introduced in API level {@link android.os.Build.VERSION_CODES#CUPCAKE}).
  * <p>Note that, in order for your Activity to access the Internet and load web pages
  * in a WebView, you must add the {@code INTERNET} permissions to your
  * Android Manifest file:</p>
@@ -158,9 +158,18 @@
  *   }
  * });
  *
- * webview.loadUrl("http://slashdot.org/");
+ * webview.loadUrl("http://developer.android.com/");
  * </pre>
  *
+ * <h3>Zoom</h3>
+ *
+ * <p>To enable the built-in zoom, set
+ * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
+ * (introduced in API level {@link android.os.Build.VERSION_CODES#CUPCAKE}).</p>
+ * <p>NOTE: Using zoom if either the height or width is set to
+ * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} may lead to undefined behavior
+ * and should be avoided.</p>
+ *
  * <h3>Cookie and window management</h3>
  *
  * <p>For obvious security reasons, your application has its own
@@ -219,6 +228,7 @@
  * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5,
  * which is the high density pixel ratio.</p>
  * </li>
+ * </ul>
  *
  * <h3>HTML5 Video support</h3>
  *
@@ -240,7 +250,7 @@
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
         ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
 
-    private static final String LOGTAG = "webview_proxy";
+    private static final String LOGTAG = "WebView";
 
     // Throwing an exception for incorrect thread usage if the
     // build target is JB MR2 or newer. Defaults to false, and is
@@ -492,9 +502,12 @@
         sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
                 Build.VERSION_CODES.JELLY_BEAN_MR2;
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "WebView<init>");
 
         ensureProviderCreated();
         mProvider.init(javaScriptInterfaces, privateBrowsing);
+        // Post condition of creating a webview is the CookieSyncManager instance exists.
+        CookieSyncManager.createInstance(getContext());
     }
 
     /**
@@ -504,6 +517,7 @@
      */
     public void setHorizontalScrollbarOverlay(boolean overlay) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setHorizontalScrollbarOverlay=" + overlay);
         mProvider.setHorizontalScrollbarOverlay(overlay);
     }
 
@@ -514,6 +528,7 @@
      */
     public void setVerticalScrollbarOverlay(boolean overlay) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setVerticalScrollbarOverlay=" + overlay);
         mProvider.setVerticalScrollbarOverlay(overlay);
     }
 
@@ -568,6 +583,7 @@
     @Deprecated
     public void setCertificate(SslCertificate certificate) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setCertificate=" + certificate);
         mProvider.setCertificate(certificate);
     }
 
@@ -591,6 +607,7 @@
     @Deprecated
     public void savePassword(String host, String username, String password) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "savePassword=" + host);
         mProvider.savePassword(host, username, password);
     }
 
@@ -610,6 +627,7 @@
     public void setHttpAuthUsernamePassword(String host, String realm,
             String username, String password) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setHttpAuthUsernamePassword=" + host);
         mProvider.setHttpAuthUsernamePassword(host, realm, username, password);
     }
 
@@ -639,6 +657,7 @@
      */
     public void destroy() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "destroy");
         mProvider.destroy();
     }
 
@@ -677,6 +696,7 @@
      */
     public void setNetworkAvailable(boolean networkUp) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setNetworkAvailable=" + networkUp);
         mProvider.setNetworkAvailable(networkUp);
     }
 
@@ -693,6 +713,7 @@
      */
     public WebBackForwardList saveState(Bundle outState) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "saveState");
         return mProvider.saveState(outState);
     }
 
@@ -709,6 +730,7 @@
     @Deprecated
     public boolean savePicture(Bundle b, final File dest) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "savePicture=" + dest.getName());
         return mProvider.savePicture(b, dest);
     }
 
@@ -726,6 +748,7 @@
     @Deprecated
     public boolean restorePicture(Bundle b, File src) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "restorePicture=" + src.getName());
         return mProvider.restorePicture(b, src);
     }
 
@@ -743,6 +766,7 @@
      */
     public WebBackForwardList restoreState(Bundle inState) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "restoreState");
         return mProvider.restoreState(inState);
     }
 
@@ -759,6 +783,7 @@
      */
     public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadUrl(extra headers)=" + url);
         mProvider.loadUrl(url, additionalHttpHeaders);
     }
 
@@ -769,6 +794,7 @@
      */
     public void loadUrl(String url) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadUrl=" + url);
         mProvider.loadUrl(url);
     }
 
@@ -778,10 +804,12 @@
      * {@link #loadUrl(String)} instead.
      *
      * @param url the URL of the resource to load
-     * @param postData the data will be passed to "POST" request
+     * @param postData the data will be passed to "POST" request, which must be
+     *     be "application/x-www-form-urlencoded" encoded.
      */
     public void postUrl(String url, byte[] postData) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "postUrl=" + url);
         mProvider.postUrl(url, postData);
     }
 
@@ -816,6 +844,7 @@
      */
     public void loadData(String data, String mimeType, String encoding) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadData");
         mProvider.loadData(data, mimeType, encoding);
     }
 
@@ -831,7 +860,10 @@
      * <p>
      * If the base URL uses the data scheme, this method is equivalent to
      * calling {@link #loadData(String,String,String) loadData()} and the
-     * historyUrl is ignored.
+     * historyUrl is ignored, and the data will be treated as part of a data: URL.
+     * If the base URL uses any other scheme, then the data will be loaded into
+     * the WebView as a plain string (i.e. not part of a data URL) and any URL-encoded
+     * entities in the string will not be decoded.
      *
      * @param baseUrl the URL to use as the page's base URL. If null defaults to
      *                'about:blank'.
@@ -845,16 +877,35 @@
     public void loadDataWithBaseURL(String baseUrl, String data,
             String mimeType, String encoding, String historyUrl) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadDataWithBaseURL=" + baseUrl);
         mProvider.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
     }
 
     /**
+     * Asynchronously evaluates JavaScript in the context of the currently displayed page.
+     * If non-null, |resultCallback| will be invoked with any result returned from that
+     * execution. This method must be called on the UI thread and the callback will
+     * be made on the UI thread.
+     *
+     * @param script the JavaScript to execute.
+     * @param resultCallback A callback to be invoked when the script execution
+     *                       completes with the result of the execution (if any).
+     *                       May be null if no notificaion of the result is required.
+     */
+    public void evaluateJavascript(String script, ValueCallback<String> resultCallback) {
+        checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "evaluateJavascript=" + script);
+        mProvider.evaluateJavaScript(script, resultCallback);
+    }
+
+    /**
      * Saves the current view as a web archive.
      *
      * @param filename the filename where the archive should be placed
      */
     public void saveWebArchive(String filename) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "saveWebArchive=" + filename);
         mProvider.saveWebArchive(filename);
     }
 
@@ -872,6 +923,7 @@
      */
     public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "saveWebArchive(auto)=" + basename);
         mProvider.saveWebArchive(basename, autoname, callback);
     }
 
@@ -880,6 +932,7 @@
      */
     public void stopLoading() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "stopLoading");
         mProvider.stopLoading();
     }
 
@@ -888,6 +941,7 @@
      */
     public void reload() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "reload");
         mProvider.reload();
     }
 
@@ -906,6 +960,7 @@
      */
     public void goBack() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "goBack");
         mProvider.goBack();
     }
 
@@ -924,6 +979,7 @@
      */
     public void goForward() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "goForward");
         mProvider.goForward();
     }
 
@@ -949,6 +1005,7 @@
      */
     public void goBackOrForward(int steps) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "goBackOrForwad=" + steps);
         mProvider.goBackOrForward(steps);
     }
 
@@ -968,6 +1025,7 @@
      */
     public boolean pageUp(boolean top) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "pageUp");
         return mProvider.pageUp(top);
     }
 
@@ -979,6 +1037,7 @@
      */
     public boolean pageDown(boolean bottom) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "pageDown");
         return mProvider.pageDown(bottom);
     }
 
@@ -991,6 +1050,7 @@
     @Deprecated
     public void clearView() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearView");
         mProvider.clearView();
     }
 
@@ -1005,15 +1065,45 @@
      * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
      * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
      * picture does not include fixed position elements or scrollable divs.
+     * <p>
+     * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+     * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+     * additional conversion at a cost in memory and performance. Also the
+     * {@link android.graphics.Picture#createFromStream} and
+     * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+     * returned object.
+     *
+     * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+     * {@link #saveWebArchive} to save the content to a file.
      *
      * @return a picture that captures the current contents of this WebView
      */
+    @Deprecated
     public Picture capturePicture() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
         return mProvider.capturePicture();
     }
 
     /**
+     * Creates a PrintDocumentAdapter that provides the content of this Webview for printing.
+     * Only supported for API levels
+     * {@link android.os.Build.VERSION_CODES#KITKAT} and above.
+     *
+     * The adapter works by converting the Webview contents to a PDF stream. The Webview cannot
+     * be drawn during the conversion process - any such draws are undefined. It is recommended
+     * to use a dedicated off screen Webview for the printing. If necessary, an application may
+     * temporarily hide a visible WebView by using a custom PrintDocumentAdapter instance
+     * wrapped around the object returned and observing the onStart and onFinish methods. See
+     * {@link android.print.PrintDocumentAdapter} for more information.
+     */
+    public PrintDocumentAdapter createPrintDocumentAdapter() {
+        checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "createPrintDocumentAdapter");
+        return mProvider.createPrintDocumentAdapter();
+    }
+
+    /**
      * Gets the current scale of this WebView.
      *
      * @return the current scale
@@ -1030,10 +1120,18 @@
     }
 
     /**
-     * Sets the initial scale for this WebView. 0 means default. If
-     * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
-     * way. Otherwise it starts with 100%. If initial scale is greater than 0,
-     * WebView starts with this value as initial scale.
+     * Sets the initial scale for this WebView. 0 means default.
+     * The behavior for the default scale depends on the state of
+     * {@link WebSettings#getUseWideViewPort()} and
+     * {@link WebSettings#getLoadWithOverviewMode()}.
+     * If the content fits into the WebView control by width, then
+     * the zoom is set to 100%. For wide content, the behavor
+     * depends on the state of {@link WebSettings#getLoadWithOverviewMode()}.
+     * If its value is true, the content will be zoomed out to be fit
+     * by width into the WebView control, otherwise not.
+     *
+     * If initial scale is greater than 0, WebView starts with this value
+     * as initial scale.
      * Please note that unlike the scale properties in the viewport meta tag,
      * this method doesn't take the screen density into account.
      *
@@ -1041,6 +1139,7 @@
      */
     public void setInitialScale(int scaleInPercent) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setInitialScale=" + scaleInPercent);
         mProvider.setInitialScale(scaleInPercent);
     }
 
@@ -1051,6 +1150,7 @@
      */
     public void invokeZoomPicker() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "invokeZoomPicker");
         mProvider.invokeZoomPicker();
     }
 
@@ -1074,6 +1174,7 @@
      */
     public HitTestResult getHitTestResult() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "getHitTestResult");
         return mProvider.getHitTestResult();
     }
 
@@ -1092,6 +1193,7 @@
      */
     public void requestFocusNodeHref(Message hrefMsg) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "requestFocusNodeHref");
         mProvider.requestFocusNodeHref(hrefMsg);
     }
 
@@ -1104,6 +1206,7 @@
      */
     public void requestImageRef(Message msg) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "requestImageRef");
         mProvider.requestImageRef(msg);
     }
 
@@ -1208,6 +1311,7 @@
      */
     public void pauseTimers() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "pauseTimers");
         mProvider.pauseTimers();
     }
 
@@ -1217,6 +1321,7 @@
      */
     public void resumeTimers() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "resumeTimers");
         mProvider.resumeTimers();
     }
 
@@ -1229,6 +1334,7 @@
      */
     public void onPause() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "onPause");
         mProvider.onPause();
     }
 
@@ -1237,6 +1343,7 @@
      */
     public void onResume() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "onResume");
         mProvider.onResume();
     }
 
@@ -1253,9 +1360,13 @@
     /**
      * Informs this WebView that memory is low so that it can free any available
      * memory.
+     * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+     *             to system memory pressure.
      */
+    @Deprecated
     public void freeMemory() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
         mProvider.freeMemory();
     }
 
@@ -1267,6 +1378,7 @@
      */
     public void clearCache(boolean includeDiskFiles) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearCache");
         mProvider.clearCache(includeDiskFiles);
     }
 
@@ -1278,6 +1390,7 @@
      */
     public void clearFormData() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearFormData");
         mProvider.clearFormData();
     }
 
@@ -1286,6 +1399,7 @@
      */
     public void clearHistory() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearHistory");
         mProvider.clearHistory();
     }
 
@@ -1295,6 +1409,7 @@
      */
     public void clearSslPreferences() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearSslPreferences");
         mProvider.clearSslPreferences();
     }
 
@@ -1336,6 +1451,7 @@
      */
     public void findNext(boolean forward) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "findNext");
         mProvider.findNext(forward);
     }
 
@@ -1351,6 +1467,7 @@
     @Deprecated
     public int findAll(String find) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "findAll");
         StrictMode.noteSlowCall("findAll blocks UI: prefer findAllAsync");
         return mProvider.findAll(find);
     }
@@ -1365,6 +1482,7 @@
      */
     public void findAllAsync(String find) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "findAllAsync");
         mProvider.findAllAsync(find);
     }
 
@@ -1385,6 +1503,7 @@
     @Deprecated
     public boolean showFindDialog(String text, boolean showIme) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "showFindDialog");
         return mProvider.showFindDialog(text, showIme);
     }
 
@@ -1420,6 +1539,7 @@
      */
     public void clearMatches() {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearMatches");
         mProvider.clearMatches();
     }
 
@@ -1480,6 +1600,7 @@
     @Deprecated
     public void setPictureListener(PictureListener listener) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setPictureListener=" + listener);
         mProvider.setPictureListener(listener);
     }
 
@@ -1529,6 +1650,7 @@
      */
     public void addJavascriptInterface(Object object, String name) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "addJavascriptInterface=" + name);
         mProvider.addJavascriptInterface(object, name);
     }
 
@@ -1541,6 +1663,7 @@
      */
     public void removeJavascriptInterface(String name) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "removeJavascriptInterface=" + name);
         mProvider.removeJavascriptInterface(name);
     }
 
@@ -1557,6 +1680,22 @@
     }
 
     /**
+     * Enables debugging of web contents (HTML / CSS / JavaScript)
+     * loaded into any WebViews of this application. This flag can be enabled
+     * in order to facilitate debugging of web layouts and JavaScript
+     * code running inside WebViews. Please refer to WebView documentation
+     * for the debugging guide.
+     *
+     * The default is false.
+     *
+     * @param enabled whether to enable web contents debugging
+     */
+    public static void setWebContentsDebuggingEnabled(boolean enabled) {
+        checkThread();
+        getFactory().getStatics().setWebContentsDebuggingEnabled(enabled);
+    }
+
+    /**
      * Gets the list of currently loaded plugins.
      *
      * @return the list of currently loaded plugins
@@ -1630,6 +1769,7 @@
 
     public void flingScroll(int vx, int vy) {
         checkThread();
+        if (DebugFlags.TRACE_API) Log.d(LOGTAG, "flingScroll");
         mProvider.flingScroll(vx, vy);
     }
 
@@ -1832,6 +1972,11 @@
             return WebView.this.getHorizontalScrollbarHeight();
         }
 
+        public void super_onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar,
+                int l, int t, int r, int b) {
+            WebView.super.onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b);
+        }
+
         // ---- Access to (non-public) fields ----
         /** Raw setter for the scroll X value, without invoking onScrollChanged handlers etc. */
         public void setScrollXRaw(int scrollX) {
@@ -2051,6 +2196,13 @@
     }
     */
 
+    @Override
+    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
+        AccessibilityNodeProvider provider =
+                mProvider.getViewDelegate().getAccessibilityNodeProvider();
+        return provider == null ? super.getAccessibilityNodeProvider() : provider;
+    }
+
     @Deprecated
     @Override
     public boolean shouldDelayChildPressedState() {
@@ -2163,7 +2315,6 @@
         return mProvider.getViewDelegate().requestFocus(direction, previouslyFocusedRect);
     }
 
-    @Deprecated
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index a324502..3c377d3 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -57,15 +57,18 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.print.PrintDocumentAdapter;
 import android.security.KeyChain;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.TextUtils;
+import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -89,6 +92,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -1293,6 +1297,19 @@
     // WebViewProvider bindings
 
     static class Factory implements WebViewFactoryProvider,  WebViewFactoryProvider.Statics {
+        Factory() {
+            // Touch JniUtil and WebViewCore in case this is being called from
+            // WebViewFactory.Preloader, to ensure that the JNI libraries that they use are
+            // preloaded in the zygote.
+            try {
+                Class.forName("android.webkit.JniUtil");
+                Class.forName("android.webkit.WebViewCore");
+            } catch (ClassNotFoundException e) {
+                Log.e(LOGTAG, "failed to load JNI libraries");
+                throw new AndroidRuntimeException(e);
+            }
+        }
+
         @Override
         public String findAddress(String addr) {
             return WebViewClassic.findAddress(addr);
@@ -1344,6 +1361,11 @@
             return WebSettingsClassic.getDefaultUserAgentForLocale(context,
                     Locale.getDefault());
         }
+
+        @Override
+        public void setWebContentsDebuggingEnabled(boolean enable) {
+            // no-op for WebViewClassic.
+        }
     }
 
     private void onHandleUiEvent(MotionEvent event, int eventType, int flags) {
@@ -1755,6 +1777,11 @@
     }
 
     @Override
+    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
+      return null;
+    }
+
+    @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         if (!mWebView.isEnabled()) {
             // Only default actions are supported while disabled.
@@ -2636,6 +2663,12 @@
         clearHelpers();
     }
 
+    @Override
+    public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) {
+        // K-only API not implemented in WebViewClassic.
+        throw new IllegalStateException("This API not supported on Android 4.3 and earlier");
+    }
+
     /**
      * See {@link WebView#saveWebArchive(String)}
      */
@@ -2866,6 +2899,15 @@
     }
 
     /**
+     * See {@link WebView#createPrintDocumentAdapter()}
+     */
+    @Override
+    public PrintDocumentAdapter createPrintDocumentAdapter() {
+        // K-only API not implemented in WebViewClassic.
+        throw new IllegalStateException("This API not supported on Android 4.3 and earlier");
+    }
+
+    /**
      * See {@link WebView#getScale()}
      */
     @Override
@@ -7912,6 +7954,7 @@
             // triggered in setNewPicture
             Picture picture = mContext.getApplicationInfo().targetSdkVersion <
                     Build.VERSION_CODES.JELLY_BEAN_MR2 ? capturePicture() : null;
+            if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onNewPicture");
             mPictureListener.onNewPicture(getWebView(), picture);
         }
     }
@@ -7999,6 +8042,7 @@
                 // triggered in pageSwapCallback
                 Picture picture = mContext.getApplicationInfo().targetSdkVersion <
                         Build.VERSION_CODES.JELLY_BEAN_MR2 ? capturePicture() : null;
+                if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onNewPicture");
                 mPictureListener.onNewPicture(getWebView(), picture);
             }
         }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 00d87bd..0fd4e33 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -19,37 +19,86 @@
 import android.os.Build;
 import android.os.StrictMode;
 import android.os.SystemProperties;
+import android.util.AndroidRuntimeException;
 import android.util.Log;
 
-import dalvik.system.PathClassLoader;
-
 /**
  * Top level factory, used creating all the main WebView implementation classes.
  *
  * @hide
  */
 public final class WebViewFactory {
-    public static final String WEBVIEW_EXPERIMENTAL_PROPERTY = "persist.sys.webview.exp";
-    private static final String DEPRECATED_CHROMIUM_PROPERTY = "webview.use_chromium";
+    private static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = true;
+    // REMEMBER: property names must be <= 31 chars total.
+    private static final String EXPERIMENTAL_PROPERTY_DEFAULT_OFF = "persist.sys.webview.exp";
+    private static final String EXPERIMENTAL_PROPERTY_DEFAULT_ON =
+            "persist.sys.webview." + Build.ID;
+
+    // Modify the persisted property name when the new webview is on-by-default, so that any user
+    // setting override only lives as long as that build.
+    private static final String LONG_PROPERTY_NAME = DEFAULT_TO_EXPERIMENTAL_WEBVIEW ?
+            EXPERIMENTAL_PROPERTY_DEFAULT_ON : EXPERIMENTAL_PROPERTY_DEFAULT_OFF;
+    private static final String WEBVIEW_EXPERIMENTAL_PROPERTY =
+            LONG_PROPERTY_NAME.length() > SystemProperties.PROP_NAME_MAX ?
+            LONG_PROPERTY_NAME.substring(0, SystemProperties.PROP_NAME_MAX) : LONG_PROPERTY_NAME;
+
+    private static final String FORCE_PROVIDER_PROPERTY = "webview.force_provider";
+    private static final String FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM = "chromium";
+    private static final String FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC = "classic";
 
     // Default Provider factory class name.
     // TODO: When the Chromium powered WebView is ready, it should be the default factory class.
     private static final String DEFAULT_WEBVIEW_FACTORY = "android.webkit.WebViewClassic$Factory";
     private static final String CHROMIUM_WEBVIEW_FACTORY =
             "com.android.webview.chromium.WebViewChromiumFactoryProvider";
-    private static final String CHROMIUM_WEBVIEW_JAR = "/system/framework/webviewchromium.jar";
 
     private static final String LOGTAG = "WebViewFactory";
 
     private static final boolean DEBUG = false;
 
+    private static class Preloader {
+        static WebViewFactoryProvider sPreloadedProvider;
+        static {
+            try {
+                sPreloadedProvider = getFactoryClass().newInstance();
+            } catch (Exception e) {
+                Log.w(LOGTAG, "error preloading provider", e);
+            }
+        }
+    }
+
     // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
     // same provider.
     private static WebViewFactoryProvider sProviderInstance;
     private static final Object sProviderLock = new Object();
 
     public static boolean isExperimentalWebViewAvailable() {
-        return Build.IS_DEBUGGABLE && (new java.io.File(CHROMIUM_WEBVIEW_JAR).exists());
+        try {
+            // Pass false so we don't initialize the class at this point, as this will be wasted if
+            // it's not enabled.
+            Class.forName(CHROMIUM_WEBVIEW_FACTORY, false, WebViewFactory.class.getClassLoader());
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
+    /** @hide */
+    public static void setUseExperimentalWebView(boolean enable) {
+        SystemProperties.set(WEBVIEW_EXPERIMENTAL_PROPERTY, enable ? "true" : "false");
+        Log.i(LOGTAG, "Use Experimental WebView changed: "
+                + SystemProperties.get(WebViewFactory.WEBVIEW_EXPERIMENTAL_PROPERTY, ""));
+    }
+
+    /** @hide */
+    public static boolean useExperimentalWebView() {
+        return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY,
+            DEFAULT_TO_EXPERIMENTAL_WEBVIEW);
+    }
+
+    /** @hide */
+    public static boolean isUseExperimentalWebViewSet() {
+        return !SystemProperties.get(WEBVIEW_EXPERIMENTAL_PROPERTY).isEmpty();
     }
 
     static WebViewFactoryProvider getProvider() {
@@ -58,66 +107,57 @@
             // us honest and minimize usage of WebViewClassic internals when binding the proxy.
             if (sProviderInstance != null) return sProviderInstance;
 
-            if (isExperimentalWebViewEnabled()) {
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                try {
-                    sProviderInstance = loadChromiumProvider();
-                    if (DEBUG) Log.v(LOGTAG, "Loaded Chromium provider: " + sProviderInstance);
-                } finally {
-                    StrictMode.setThreadPolicy(oldPolicy);
-                }
+            Class<WebViewFactoryProvider> providerClass;
+            try {
+                providerClass = getFactoryClass();
+            } catch (ClassNotFoundException e) {
+                Log.e(LOGTAG, "error loading provider", e);
+                throw new AndroidRuntimeException(e);
             }
 
-            if (sProviderInstance == null) {
-                if (DEBUG) Log.v(LOGTAG, "Falling back to default provider: "
-                        + DEFAULT_WEBVIEW_FACTORY);
-                sProviderInstance = getFactoryByName(DEFAULT_WEBVIEW_FACTORY,
-                        WebViewFactory.class.getClassLoader());
-                if (sProviderInstance == null) {
-                    if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
-                    sProviderInstance = new WebViewClassic.Factory();
-                }
+            // This implicitly loads Preloader even if it wasn't preloaded at boot.
+            if (Preloader.sPreloadedProvider != null &&
+                Preloader.sPreloadedProvider.getClass() == providerClass) {
+                sProviderInstance = Preloader.sPreloadedProvider;
+                if (DEBUG) Log.v(LOGTAG, "Using preloaded provider: " + sProviderInstance);
+                return sProviderInstance;
             }
-            return sProviderInstance;
+
+            // The preloaded provider isn't the one we wanted; construct our own.
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            try {
+                sProviderInstance = providerClass.newInstance();
+                if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
+                return sProviderInstance;
+            } catch (Exception e) {
+                Log.e(LOGTAG, "error instantiating provider", e);
+                throw new AndroidRuntimeException(e);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
         }
     }
 
-    // For debug builds, we allow a system property to specify that we should use the
-    // experimtanl Chromium powered WebView. This enables us to switch between
-    // implementations at runtime. For user (release) builds, don't allow this.
+    // We allow a system property to specify that we should use the experimental Chromium powered
+    // WebView. This enables us to switch between implementations at runtime.
     private static boolean isExperimentalWebViewEnabled() {
-        if (!isExperimentalWebViewAvailable())
-            return false;
-        if (SystemProperties.getBoolean(DEPRECATED_CHROMIUM_PROPERTY, false)) {
-            Log.w(LOGTAG, String.format("The property %s has been deprecated. Please use %s.",
-                    DEPRECATED_CHROMIUM_PROPERTY, WEBVIEW_EXPERIMENTAL_PROPERTY));
-            return true;
-        }
-        return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY, false);
+        if (!isExperimentalWebViewAvailable()) return false;
+        String forceProviderName = SystemProperties.get(FORCE_PROVIDER_PROPERTY);
+        if (forceProviderName.isEmpty()) return useExperimentalWebView();
+
+        Log.i(LOGTAG, String.format("Provider overridden by property: %s=%s",
+                FORCE_PROVIDER_PROPERTY, forceProviderName));
+        if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM)) return true;
+        if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC)) return false;
+        Log.e(LOGTAG, String.format("Unrecognized provider: %s", forceProviderName));
+        return useExperimentalWebView();
     }
 
-    // TODO: This allows us to have the legacy and Chromium WebView coexist for development
-    // and side-by-side testing. After transition, remove this when no longer required.
-    private static WebViewFactoryProvider loadChromiumProvider() {
-        ClassLoader clazzLoader = new PathClassLoader(CHROMIUM_WEBVIEW_JAR, null,
-                WebViewFactory.class.getClassLoader());
-        return getFactoryByName(CHROMIUM_WEBVIEW_FACTORY, clazzLoader);
-    }
-
-    private static WebViewFactoryProvider getFactoryByName(String providerName,
-            ClassLoader loader) {
-        try {
-            if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName);
-            Class<?> c = Class.forName(providerName, true, loader);
-            if (DEBUG) Log.v(LOGTAG, "instantiating factory");
-            return (WebViewFactoryProvider) c.newInstance();
-        } catch (ClassNotFoundException e) {
-            Log.e(LOGTAG, "error loading " + providerName, e);
-        } catch (IllegalAccessException e) {
-            Log.e(LOGTAG, "error loading " + providerName, e);
-        } catch (InstantiationException e) {
-            Log.e(LOGTAG, "error loading " + providerName, e);
+    private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
+        if (isExperimentalWebViewEnabled()) {
+            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+        } else  {
+            return (Class<WebViewFactoryProvider>) Class.forName(DEFAULT_WEBVIEW_FACTORY);
         }
-        return null;
     }
 }
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 934ef83..9d9d882 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -48,6 +48,12 @@
          * {@link android.webkit.WebSettings#getDefaultUserAgent(Context) }
          */
         String getDefaultUserAgent(Context context);
+
+        /**
+         * Implements the API method:
+         * {@link android.webkit.WebView#setWebContentsDebuggingEnabled(boolean) }
+         */
+        void setWebContentsDebuggingEnabled(boolean enable);
     }
 
     Statics getStatics();
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index fa17ab9..696aad4 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -26,12 +26,14 @@
 import android.net.http.SslCertificate;
 import android.os.Bundle;
 import android.os.Message;
+import android.print.PrintDocumentAdapter;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.webkit.WebView.HitTestResult;
@@ -113,6 +115,8 @@
     public void loadDataWithBaseURL(String baseUrl, String data,
             String mimeType, String encoding, String historyUrl);
 
+    public void evaluateJavaScript(String script, ValueCallback<String> resultCallback);
+
     public void saveWebArchive(String filename);
 
     public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback);
@@ -143,6 +147,8 @@
 
     public Picture capturePicture();
 
+    public PrintDocumentAdapter createPrintDocumentAdapter();
+
     public float getScale();
 
     public void setInitialScale(int scaleInPercent);
@@ -279,6 +285,8 @@
     interface ViewDelegate {
         public boolean shouldDelayChildPressedState();
 
+        public AccessibilityNodeProvider getAccessibilityNodeProvider();
+
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
 
         public void onInitializeAccessibilityEvent(AccessibilityEvent event);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index c36ecc8..2e77578 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -25,11 +25,12 @@
 import android.graphics.drawable.TransitionDrawable;
 import android.os.Bundle;
 import android.os.Debug;
-import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
+import android.os.Trace;
 import android.text.Editable;
+import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
@@ -61,9 +62,12 @@
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionWrapper;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.RemoteViews.OnClickHandler;
 
@@ -219,6 +223,11 @@
     public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
 
     /**
+     * The thread that created this view.
+     */
+    private final Thread mOwnerThread;
+
+    /**
      * Controls if/how the user may choose/check items in the list
      */
     int mChoiceMode = CHOICE_MODE_NONE;
@@ -434,6 +443,11 @@
     boolean mFastScrollEnabled;
 
     /**
+     * Whether or not to always show the fast scroll feature on this list
+     */
+    boolean mFastScrollAlwaysVisible;
+
+    /**
      * Optional callback to notify client when scroll position has changed
      */
     private OnScrollListener mOnScrollListener;
@@ -661,11 +675,6 @@
     private int mLastAccessibilityScrollEventToIndex;
 
     /**
-     * Track if we are currently attached to a window.
-     */
-    boolean mIsAttached;
-
-    /**
      * Track the item count from the last time we handled a data change.
      */
     private int mLastHandledItemCount;
@@ -752,6 +761,8 @@
         super(context);
         initAbsListView();
 
+        mOwnerThread = Thread.currentThread();
+
         setVerticalScrollBarEnabled(true);
         TypedArray a = context.obtainStyledAttributes(R.styleable.View);
         initializeScrollbars(a);
@@ -766,6 +777,8 @@
         super(context, attrs, defStyle);
         initAbsListView();
 
+        mOwnerThread = Thread.currentThread();
+
         TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.AbsListView, defStyle, 0);
 
@@ -1151,10 +1164,10 @@
         }
         if (mChoiceMode != CHOICE_MODE_NONE) {
             if (mCheckStates == null) {
-                mCheckStates = new SparseBooleanArray();
+                mCheckStates = new SparseBooleanArray(0);
             }
             if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
-                mCheckedIdStates = new LongSparseArray<Integer>();
+                mCheckedIdStates = new LongSparseArray<Integer>(0);
             }
             // Modal multi-choice mode only has choices when the mode is active. Clear them.
             if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
@@ -1193,79 +1206,135 @@
     }
 
     /**
-     * Enables fast scrolling by letting the user quickly scroll through lists by
-     * dragging the fast scroll thumb. The adapter attached to the list may want
-     * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
-     * jump between sections of the list.
+     * Specifies whether fast scrolling is enabled or disabled.
+     * <p>
+     * When fast scrolling is enabled, the user can quickly scroll through lists
+     * by dragging the fast scroll thumb.
+     * <p>
+     * If the adapter backing this list implements {@link SectionIndexer}, the
+     * fast scroller will display section header previews as the user scrolls.
+     * Additionally, the user will be able to quickly jump between sections by
+     * tapping along the length of the scroll bar.
+     *
      * @see SectionIndexer
      * @see #isFastScrollEnabled()
-     * @param enabled whether or not to enable fast scrolling
+     * @param enabled true to enable fast scrolling, false otherwise
      */
-    public void setFastScrollEnabled(boolean enabled) {
-        mFastScrollEnabled = enabled;
-        if (enabled) {
-            if (mFastScroller == null) {
-                mFastScroller = new FastScroller(getContext(), this);
-            }
-        } else {
-            if (mFastScroller != null) {
-                mFastScroller.stop();
-                mFastScroller = null;
+    public void setFastScrollEnabled(final boolean enabled) {
+        if (mFastScrollEnabled != enabled) {
+            mFastScrollEnabled = enabled;
+
+            if (isOwnerThread()) {
+                setFastScrollerEnabledUiThread(enabled);
+            } else {
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        setFastScrollerEnabledUiThread(enabled);
+                    }
+                });
             }
         }
     }
 
+    private void setFastScrollerEnabledUiThread(boolean enabled) {
+        if (mFastScroller != null) {
+            mFastScroller.setEnabled(enabled);
+        } else if (enabled) {
+            mFastScroller = new FastScroller(this);
+            mFastScroller.setEnabled(true);
+        }
+
+        resolvePadding();
+
+        if (mFastScroller != null) {
+            mFastScroller.updateLayout();
+        }
+    }
+
     /**
-     * Set whether or not the fast scroller should always be shown in place of the
-     * standard scrollbars. Fast scrollers shown in this way will not fade out and will
-     * be a permanent fixture within the list. Best combined with an inset scroll bar style
-     * that will ensure enough padding. This will enable fast scrolling if it is not
+     * Set whether or not the fast scroller should always be shown in place of
+     * the standard scroll bars. This will enable fast scrolling if it is not
      * already enabled.
+     * <p>
+     * Fast scrollers shown in this way will not fade out and will be a
+     * permanent fixture within the list. This is best combined with an inset
+     * scroll bar style to ensure the scroll bar does not overlap content.
      *
-     * @param alwaysShow true if the fast scroller should always be displayed.
+     * @param alwaysShow true if the fast scroller should always be displayed,
+     *            false otherwise
      * @see #setScrollBarStyle(int)
      * @see #setFastScrollEnabled(boolean)
      */
-    public void setFastScrollAlwaysVisible(boolean alwaysShow) {
-        if (alwaysShow && !mFastScrollEnabled) {
-            setFastScrollEnabled(true);
-        }
+    public void setFastScrollAlwaysVisible(final boolean alwaysShow) {
+        if (mFastScrollAlwaysVisible != alwaysShow) {
+            if (alwaysShow && !mFastScrollEnabled) {
+                setFastScrollEnabled(true);
+            }
 
+            mFastScrollAlwaysVisible = alwaysShow;
+
+            if (isOwnerThread()) {
+                setFastScrollerAlwaysVisibleUiThread(alwaysShow);
+            } else {
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        setFastScrollerAlwaysVisibleUiThread(alwaysShow);
+                    }
+                });
+            }
+        }
+    }
+
+    private void setFastScrollerAlwaysVisibleUiThread(boolean alwaysShow) {
         if (mFastScroller != null) {
             mFastScroller.setAlwaysShow(alwaysShow);
         }
-
-        computeOpaqueFlags();
-        recomputePadding();
     }
 
     /**
-     * Returns true if the fast scroller is set to always show on this view rather than
-     * fade out when not in use.
+     * @return whether the current thread is the one that created the view
+     */
+    private boolean isOwnerThread() {
+        return mOwnerThread == Thread.currentThread();
+    }
+
+    /**
+     * Returns true if the fast scroller is set to always show on this view.
      *
-     * @return true if the fast scroller will always show.
+     * @return true if the fast scroller will always show
      * @see #setFastScrollAlwaysVisible(boolean)
      */
     public boolean isFastScrollAlwaysVisible() {
-        return mFastScrollEnabled && mFastScroller.isAlwaysShowEnabled();
+        if (mFastScroller == null) {
+            return mFastScrollEnabled && mFastScrollAlwaysVisible;
+        } else {
+            return mFastScroller.isEnabled() && mFastScroller.isAlwaysShowEnabled();
+        }
     }
 
     @Override
     public int getVerticalScrollbarWidth() {
-        if (isFastScrollAlwaysVisible()) {
+        if (mFastScroller != null && mFastScroller.isEnabled()) {
             return Math.max(super.getVerticalScrollbarWidth(), mFastScroller.getWidth());
         }
         return super.getVerticalScrollbarWidth();
     }
 
     /**
-     * Returns the current state of the fast scroll feature.
+     * Returns true if the fast scroller is enabled.
+     *
      * @see #setFastScrollEnabled(boolean)
      * @return true if fast scroll is enabled, false otherwise
      */
     @ViewDebug.ExportedProperty
     public boolean isFastScrollEnabled() {
-        return mFastScrollEnabled;
+        if (mFastScroller == null) {
+            return mFastScrollEnabled;
+        } else {
+            return mFastScroller.isEnabled();
+        }
     }
 
     @Override
@@ -1276,13 +1345,21 @@
         }
     }
 
+    @Override
+    public void setScrollBarStyle(int style) {
+        super.setScrollBarStyle(style);
+        if (mFastScroller != null) {
+            mFastScroller.setScrollBarStyle(style);
+        }
+    }
+
     /**
-     * If fast scroll is visible, then don't draw the vertical scrollbar.
+     * If fast scroll is enabled, then don't draw the vertical scrollbar.
      * @hide
      */
     @Override
     protected boolean isVerticalScrollBarHidden() {
-        return mFastScroller != null && mFastScroller.isVisible();
+        return isFastScrollEnabled();
     }
 
     /**
@@ -1334,7 +1411,7 @@
      */
     void invokeOnItemScrollListener() {
         if (mFastScroller != null) {
-            mFastScroller.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
+            mFastScroller.onScroll(mFirstPosition, getChildCount(), mItemCount);
         }
         if (mOnScrollListener != null) {
             mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
@@ -1615,10 +1692,12 @@
 
         public static final Parcelable.Creator<SavedState> CREATOR
                 = new Parcelable.Creator<SavedState>() {
+            @Override
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
             }
 
+            @Override
             public SavedState[] newArray(int size) {
                 return new SavedState[size];
             }
@@ -1820,7 +1899,7 @@
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
         if (gainFocus && mSelectedPosition < 0 && !isInTouchMode()) {
-            if (!mIsAttached && mAdapter != null) {
+            if (!isAttachedToWindow() && mAdapter != null) {
                 // Data may have changed while we were detached and it's valid
                 // to change focus while detached. Refresh so we don't die.
                 mDataChanged = true;
@@ -1943,8 +2022,8 @@
             }
 
             final int top = getChildAt(0).getTop();
-            final float fadeLength = (float) getVerticalFadingEdgeLength();
-            return top < mPaddingTop ? (float) -(top - mPaddingTop) / fadeLength : fadeEdge;
+            final float fadeLength = getVerticalFadingEdgeLength();
+            return top < mPaddingTop ? -(top - mPaddingTop) / fadeLength : fadeEdge;
         }
     }
 
@@ -1961,9 +2040,9 @@
 
             final int bottom = getChildAt(count - 1).getBottom();
             final int height = getHeight();
-            final float fadeLength = (float) getVerticalFadingEdgeLength();
+            final float fadeLength = getVerticalFadingEdgeLength();
             return bottom > height - mPaddingBottom ?
-                    (float) (bottom - height + mPaddingBottom) / fadeLength : fadeEdge;
+                    (bottom - height + mPaddingBottom) / fadeLength : fadeEdge;
         }
     }
 
@@ -2004,7 +2083,7 @@
             }
             mRecycler.markChildrenDirty();
         }
-        
+
         if (mFastScroller != null && mItemCount != mOldItemCount) {
             mFastScroller.onItemCountChanged(mOldItemCount, mItemCount);
         }
@@ -2146,16 +2225,16 @@
      * @return A view displaying the data associated with the specified position
      */
     View obtainView(int position, boolean[] isScrap) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView");
+
         isScrap[0] = false;
         View scrapView;
 
         scrapView = mRecycler.getTransientStateView(position);
-        if (scrapView != null) {
-            return scrapView;
+        if (scrapView == null) {
+            scrapView = mRecycler.getScrapView(position);
         }
 
-        scrapView = mRecycler.getScrapView(position);
-
         View child;
         if (scrapView != null) {
             child = mAdapter.getView(position, scrapView, this);
@@ -2171,6 +2250,13 @@
                 }
             } else {
                 isScrap[0] = true;
+
+                // Clear any system-managed transient state so that we can
+                // recycle this view and bind it to different data.
+                if (child.isAccessibilityFocused()) {
+                    child.clearAccessibilityFocus();
+                }
+
                 child.dispatchFinishTemporaryDetach();
             }
         } else {
@@ -2208,6 +2294,8 @@
             }
         }
 
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+
         return child;
     }
 
@@ -2229,33 +2317,7 @@
             super.onInitializeAccessibilityNodeInfo(host, info);
 
             final int position = getPositionForView(host);
-            final ListAdapter adapter = getAdapter();
-
-            if ((position == INVALID_POSITION) || (adapter == null)) {
-                return;
-            }
-
-            if (!isEnabled() || !adapter.isEnabled(position)) {
-                return;
-            }
-
-            if (position == getSelectedItemPosition()) {
-                info.setSelected(true);
-                info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
-            } else {
-                info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
-            }
-
-            if (isClickable()) {
-                info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
-                info.setClickable(true);
-            }
-
-            if (isLongClickable()) {
-                info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
-                info.setLongClickable(true);
-            }
-
+            onInitializeAccessibilityNodeInfoForItem(host, position, info);
         }
 
         @Override
@@ -2308,6 +2370,45 @@
         }
     }
 
+    /**
+     * Initializes an {@link AccessibilityNodeInfo} with information about a
+     * particular item in the list.
+     *
+     * @param view View representing the list item.
+     * @param position Position of the list item within the adapter.
+     * @param info Node info to populate.
+     */
+    public void onInitializeAccessibilityNodeInfoForItem(
+            View view, int position, AccessibilityNodeInfo info) {
+        final ListAdapter adapter = getAdapter();
+        if (position == INVALID_POSITION || adapter == null) {
+            // The item doesn't exist, so there's not much we can do here.
+            return;
+        }
+
+        if (!isEnabled() || !adapter.isEnabled(position)) {
+            info.setEnabled(false);
+            return;
+        }
+
+        if (position == getSelectedItemPosition()) {
+            info.setSelected(true);
+            info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
+        } else {
+            info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
+        }
+
+        if (isClickable()) {
+            info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+            info.setClickable(true);
+        }
+
+        if (isLongClickable()) {
+            info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
+            info.setLongClickable(true);
+        }
+    }
+
     void positionSelector(int position, View sel) {
         if (position != INVALID_POSITION) {
             mSelectorPosition = position;
@@ -2426,7 +2527,7 @@
      * @return True if the selector should be shown
      */
     boolean shouldShowSelector() {
-        return (hasFocus() && !isInTouchMode()) || touchModeDrawsInPressedState();
+        return (!isInTouchMode()) || (touchModeDrawsInPressedState() && isPressed());
     }
 
     private void drawSelector(Canvas canvas) {
@@ -2614,7 +2715,6 @@
             mOldItemCount = mItemCount;
             mItemCount = mAdapter.getCount();
         }
-        mIsAttached = true;
     }
 
     @Override
@@ -2669,7 +2769,6 @@
             removeCallbacks(mTouchModeReset);
             mTouchModeReset.run();
         }
-        mIsAttached = false;
     }
 
     @Override
@@ -2730,7 +2829,6 @@
     @Override
     public void onRtlPropertiesChanged(int layoutDirection) {
         super.onRtlPropertiesChanged(layoutDirection);
-
         if (mFastScroller != null) {
            mFastScroller.setScrollbarPosition(getVerticalScrollbarPosition());
         }
@@ -2751,6 +2849,23 @@
         return new AdapterContextMenuInfo(view, position, id);
     }
 
+    @Override
+    public void onCancelPendingInputEvents() {
+        super.onCancelPendingInputEvents();
+        if (mPerformClick != null) {
+            removeCallbacks(mPerformClick);
+        }
+        if (mPendingCheckForTap != null) {
+            removeCallbacks(mPendingCheckForTap);
+        }
+        if (mPendingCheckForLongPress != null) {
+            removeCallbacks(mPendingCheckForLongPress);
+        }
+        if (mPendingCheckForKeyLongPress != null) {
+            removeCallbacks(mPendingCheckForKeyLongPress);
+        }
+    }
+
     /**
      * A base class for Runnables that will check that their view is still attached to
      * the original window as when the Runnable was created.
@@ -2764,13 +2879,14 @@
         }
 
         public boolean sameWindow() {
-            return hasWindowFocus() && getWindowAttachCount() == mOriginalAttachCount;
+            return getWindowAttachCount() == mOriginalAttachCount;
         }
     }
 
     private class PerformClick extends WindowRunnnable implements Runnable {
         int mClickMotionPosition;
 
+        @Override
         public void run() {
             // The data has changed since we posted this action in the event queue,
             // bail out before bad things happen
@@ -2792,6 +2908,7 @@
     }
 
     private class CheckForLongPress extends WindowRunnnable implements Runnable {
+        @Override
         public void run() {
             final int motionPosition = mMotionPosition;
             final View child = getChildAt(motionPosition - mFirstPosition);
@@ -2815,6 +2932,7 @@
     }
 
     private class CheckForKeyLongPress extends WindowRunnnable implements Runnable {
+        @Override
         public void run() {
             if (isPressed() && mSelectedPosition >= 0) {
                 int index = mSelectedPosition - mFirstPosition;
@@ -2914,9 +3032,7 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-        case KeyEvent.KEYCODE_DPAD_CENTER:
-        case KeyEvent.KEYCODE_ENTER:
+        if (KeyEvent.isConfirmKey(keyCode)) {
             if (!isEnabled()) {
                 return true;
             }
@@ -2932,7 +3048,6 @@
                 setPressed(false);
                 return true;
             }
-            break;
         }
         return super.onKeyUp(keyCode, event);
     }
@@ -2989,6 +3104,7 @@
     }
 
     final class CheckForTap implements Runnable {
+        @Override
         public void run() {
             if (mTouchMode == TOUCH_MODE_DOWN) {
                 mTouchMode = TOUCH_MODE_TAP;
@@ -3049,15 +3165,9 @@
                 mTouchMode = TOUCH_MODE_SCROLL;
                 mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
             }
-            final Handler handler = getHandler();
-            // Handler should not be null unless the AbsListView is not attached to a
-            // window, which would make it very hard to scroll it... but the monkeys
-            // say it's possible.
-            if (handler != null) {
-                handler.removeCallbacks(mPendingCheckForLongPress);
-            }
+            removeCallbacks(mPendingCheckForLongPress);
             setPressed(false);
-            View motionView = getChildAt(mMotionPosition - mFirstPosition);
+            final View motionView = getChildAt(mMotionPosition - mFirstPosition);
             if (motionView != null) {
                 motionView.setPressed(false);
             }
@@ -3239,6 +3349,7 @@
         }
     }
 
+    @Override
     public void onTouchModeChanged(boolean isInTouchMode) {
         if (isInTouchMode) {
             // Get rid of the selection when we enter touch mode
@@ -3284,7 +3395,7 @@
             mPositionScroller.stop();
         }
 
-        if (!mIsAttached) {
+        if (!isAttachedToWindow()) {
             // Something isn't right.
             // Since we rely on being attached to get data set change notifications,
             // don't risk doing anything where we might try to resync and find things
@@ -3299,126 +3410,193 @@
             }
         }
 
-        final int action = ev.getAction();
-
-        View v;
-
         initVelocityTrackerIfNotExists();
         mVelocityTracker.addMovement(ev);
 
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN: {
-            switch (mTouchMode) {
-            case TOUCH_MODE_OVERFLING: {
-                mFlingRunnable.endFling();
-                if (mPositionScroller != null) {
-                    mPositionScroller.stop();
-                }
-                mTouchMode = TOUCH_MODE_OVERSCROLL;
-                mMotionX = (int) ev.getX();
-                mMotionY = mLastY = (int) ev.getY();
-                mMotionCorrection = 0;
-                mActivePointerId = ev.getPointerId(0);
-                mDirection = 0;
+        final int actionMasked = ev.getActionMasked();
+        switch (actionMasked) {
+            case MotionEvent.ACTION_DOWN: {
+                onTouchDown(ev);
                 break;
             }
 
-            default: {
-                mActivePointerId = ev.getPointerId(0);
-                final int x = (int) ev.getX();
-                final int y = (int) ev.getY();
-                int motionPosition = pointToPosition(x, y);
-                if (!mDataChanged) {
-                    if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
-                            && (getAdapter().isEnabled(motionPosition))) {
-                        // User clicked on an actual view (and was not stopping a fling).
-                        // It might be a click or a scroll. Assume it is a click until
-                        // proven otherwise
-                        mTouchMode = TOUCH_MODE_DOWN;
-                        // FIXME Debounce
-                        if (mPendingCheckForTap == null) {
-                            mPendingCheckForTap = new CheckForTap();
-                        }
-                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
-                    } else {
-                        if (mTouchMode == TOUCH_MODE_FLING) {
-                            // Stopped a fling. It is a scroll.
-                            createScrollingCache();
-                            mTouchMode = TOUCH_MODE_SCROLL;
-                            mMotionCorrection = 0;
-                            motionPosition = findMotionRow(y);
-                            mFlingRunnable.flywheelTouch();
-                        }
-                    }
-                }
+            case MotionEvent.ACTION_MOVE: {
+                onTouchMove(ev);
+                break;
+            }
 
+            case MotionEvent.ACTION_UP: {
+                onTouchUp(ev);
+                break;
+            }
+
+            case MotionEvent.ACTION_CANCEL: {
+                onTouchCancel();
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                onSecondaryPointerUp(ev);
+                final int x = mMotionX;
+                final int y = mMotionY;
+                final int motionPosition = pointToPosition(x, y);
                 if (motionPosition >= 0) {
                     // Remember where the motion event started
-                    v = getChildAt(motionPosition - mFirstPosition);
-                    mMotionViewOriginalTop = v.getTop();
+                    final View child = getChildAt(motionPosition - mFirstPosition);
+                    mMotionViewOriginalTop = child.getTop();
+                    mMotionPosition = motionPosition;
                 }
-                mMotionX = x;
-                mMotionY = y;
-                mMotionPosition = motionPosition;
-                mLastY = Integer.MIN_VALUE;
+                mLastY = y;
                 break;
             }
-            }
 
-            if (performButtonActionOnTouchDown(ev)) {
-                if (mTouchMode == TOUCH_MODE_DOWN) {
-                    removeCallbacks(mPendingCheckForTap);
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                // New pointers take over dragging duties
+                final int index = ev.getActionIndex();
+                final int id = ev.getPointerId(index);
+                final int x = (int) ev.getX(index);
+                final int y = (int) ev.getY(index);
+                mMotionCorrection = 0;
+                mActivePointerId = id;
+                mMotionX = x;
+                mMotionY = y;
+                final int motionPosition = pointToPosition(x, y);
+                if (motionPosition >= 0) {
+                    // Remember where the motion event started
+                    final View child = getChildAt(motionPosition - mFirstPosition);
+                    mMotionViewOriginalTop = child.getTop();
+                    mMotionPosition = motionPosition;
                 }
+                mLastY = y;
+                break;
             }
-            break;
         }
 
-        case MotionEvent.ACTION_MOVE: {
-            int pointerIndex = ev.findPointerIndex(mActivePointerId);
-            if (pointerIndex == -1) {
-                pointerIndex = 0;
-                mActivePointerId = ev.getPointerId(pointerIndex);
-            }
-            final int y = (int) ev.getY(pointerIndex);
+        return true;
+    }
 
-            if (mDataChanged) {
-                // Re-sync everything if data has been changed
-                // since the scroll operation can query the adapter.
-                layoutChildren();
+    private void onTouchDown(MotionEvent ev) {
+        mActivePointerId = ev.getPointerId(0);
+
+        if (mTouchMode == TOUCH_MODE_OVERFLING) {
+            // Stopped the fling. It is a scroll.
+            mFlingRunnable.endFling();
+            if (mPositionScroller != null) {
+                mPositionScroller.stop();
+            }
+            mTouchMode = TOUCH_MODE_OVERSCROLL;
+            mMotionX = (int) ev.getX();
+            mMotionY = (int) ev.getY();
+            mLastY = mMotionY;
+            mMotionCorrection = 0;
+            mDirection = 0;
+        } else {
+            final int x = (int) ev.getX();
+            final int y = (int) ev.getY();
+            int motionPosition = pointToPosition(x, y);
+
+            if (!mDataChanged) {
+                if (mTouchMode == TOUCH_MODE_FLING) {
+                    // Stopped a fling. It is a scroll.
+                    createScrollingCache();
+                    mTouchMode = TOUCH_MODE_SCROLL;
+                    mMotionCorrection = 0;
+                    motionPosition = findMotionRow(y);
+                    mFlingRunnable.flywheelTouch();
+                } else if ((motionPosition >= 0) && getAdapter().isEnabled(motionPosition)) {
+                    // User clicked on an actual view (and was not stopping a
+                    // fling). It might be a click or a scroll. Assume it is a
+                    // click until proven otherwise.
+                    mTouchMode = TOUCH_MODE_DOWN;
+
+                    // FIXME Debounce
+                    if (mPendingCheckForTap == null) {
+                        mPendingCheckForTap = new CheckForTap();
+                    }
+
+                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
+                }
             }
 
-            switch (mTouchMode) {
+            if (motionPosition >= 0) {
+                // Remember where the motion event started
+                final View v = getChildAt(motionPosition - mFirstPosition);
+                mMotionViewOriginalTop = v.getTop();
+            }
+
+            mMotionX = x;
+            mMotionY = y;
+            mMotionPosition = motionPosition;
+            mLastY = Integer.MIN_VALUE;
+        }
+
+        if (mTouchMode == TOUCH_MODE_DOWN && mMotionPosition != INVALID_POSITION
+                && performButtonActionOnTouchDown(ev)) {
+            removeCallbacks(mPendingCheckForTap);
+        }
+    }
+
+    private void onTouchMove(MotionEvent ev) {
+        int pointerIndex = ev.findPointerIndex(mActivePointerId);
+        if (pointerIndex == -1) {
+            pointerIndex = 0;
+            mActivePointerId = ev.getPointerId(pointerIndex);
+        }
+
+        if (mDataChanged) {
+            // Re-sync everything if data has been changed
+            // since the scroll operation can query the adapter.
+            layoutChildren();
+        }
+
+        final int y = (int) ev.getY(pointerIndex);
+
+        switch (mTouchMode) {
             case TOUCH_MODE_DOWN:
             case TOUCH_MODE_TAP:
             case TOUCH_MODE_DONE_WAITING:
                 // Check if we have moved far enough that it looks more like a
-                // scroll than a tap
-                startScrollIfNeeded(y);
+                // scroll than a tap. If so, we'll enter scrolling mode.
+                if (startScrollIfNeeded(y)) {
+                    break;
+                }
+                // Otherwise, check containment within list bounds. If we're
+                // outside bounds, cancel any active presses.
+                final float x = ev.getX(pointerIndex);
+                if (!pointInView(x, y, mTouchSlop)) {
+                    setPressed(false);
+                    final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+                    if (motionView != null) {
+                        motionView.setPressed(false);
+                    }
+                    removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ?
+                            mPendingCheckForTap : mPendingCheckForLongPress);
+                    mTouchMode = TOUCH_MODE_DONE_WAITING;
+                    updateSelectorState();
+                }
                 break;
             case TOUCH_MODE_SCROLL:
             case TOUCH_MODE_OVERSCROLL:
                 scrollIfNeeded(y);
                 break;
-            }
-            break;
         }
+    }
 
-        case MotionEvent.ACTION_UP: {
-            switch (mTouchMode) {
-            case TOUCH_MODE_DOWN:
-            case TOUCH_MODE_TAP:
-            case TOUCH_MODE_DONE_WAITING:
-                final int motionPosition = mMotionPosition;
-                final View child = getChildAt(motionPosition - mFirstPosition);
+    private void onTouchUp(MotionEvent ev) {
+        switch (mTouchMode) {
+        case TOUCH_MODE_DOWN:
+        case TOUCH_MODE_TAP:
+        case TOUCH_MODE_DONE_WAITING:
+            final int motionPosition = mMotionPosition;
+            final View child = getChildAt(motionPosition - mFirstPosition);
+            if (child != null) {
+                if (mTouchMode != TOUCH_MODE_DOWN) {
+                    child.setPressed(false);
+                }
 
                 final float x = ev.getX();
                 final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;
-
-                if (child != null && !child.hasFocusable() && inList) {
-                    if (mTouchMode != TOUCH_MODE_DOWN) {
-                        child.setPressed(false);
-                    }
-
+                if (inList && !child.hasFocusable()) {
                     if (mPerformClick == null) {
                         mPerformClick = new PerformClick();
                     }
@@ -3430,11 +3608,8 @@
                     mResurrectToPosition = motionPosition;
 
                     if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {
-                        final Handler handler = getHandler();
-                        if (handler != null) {
-                            handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ?
-                                    mPendingCheckForTap : mPendingCheckForLongPress);
-                        }
+                        removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ?
+                                mPendingCheckForTap : mPendingCheckForLongPress);
                         mLayoutMode = LAYOUT_NORMAL;
                         if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                             mTouchMode = TOUCH_MODE_TAP;
@@ -3459,7 +3634,7 @@
                                     mTouchMode = TOUCH_MODE_REST;
                                     child.setPressed(false);
                                     setPressed(false);
-                                    if (!mDataChanged) {
+                                    if (!mDataChanged && isAttachedToWindow()) {
                                         performClick.run();
                                     }
                                 }
@@ -3470,191 +3645,140 @@
                             mTouchMode = TOUCH_MODE_REST;
                             updateSelectorState();
                         }
-                        return true;
+                        return;
                     } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                         performClick.run();
                     }
                 }
-                mTouchMode = TOUCH_MODE_REST;
-                updateSelectorState();
-                break;
-            case TOUCH_MODE_SCROLL:
-                final int childCount = getChildCount();
-                if (childCount > 0) {
-                    final int firstChildTop = getChildAt(0).getTop();
-                    final int lastChildBottom = getChildAt(childCount - 1).getBottom();
-                    final int contentTop = mListPadding.top;
-                    final int contentBottom = getHeight() - mListPadding.bottom;
-                    if (mFirstPosition == 0 && firstChildTop >= contentTop &&
-                            mFirstPosition + childCount < mItemCount &&
-                            lastChildBottom <= getHeight() - contentBottom) {
-                        mTouchMode = TOUCH_MODE_REST;
-                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                    } else {
-                        final VelocityTracker velocityTracker = mVelocityTracker;
-                        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-
-                        final int initialVelocity = (int)
-                                (velocityTracker.getYVelocity(mActivePointerId) * mVelocityScale);
-                        // Fling if we have enough velocity and we aren't at a boundary.
-                        // Since we can potentially overfling more than we can overscroll, don't
-                        // allow the weird behavior where you can scroll to a boundary then
-                        // fling further.
-                        if (Math.abs(initialVelocity) > mMinimumVelocity &&
-                                !((mFirstPosition == 0 &&
-                                        firstChildTop == contentTop - mOverscrollDistance) ||
-                                  (mFirstPosition + childCount == mItemCount &&
-                                        lastChildBottom == contentBottom + mOverscrollDistance))) {
-                            if (mFlingRunnable == null) {
-                                mFlingRunnable = new FlingRunnable();
-                            }
-                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
-
-                            mFlingRunnable.start(-initialVelocity);
-                        } else {
-                            mTouchMode = TOUCH_MODE_REST;
-                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                            if (mFlingRunnable != null) {
-                                mFlingRunnable.endFling();
-                            }
-                            if (mPositionScroller != null) {
-                                mPositionScroller.stop();
-                            }
-                        }
-                    }
-                } else {
+            }
+            mTouchMode = TOUCH_MODE_REST;
+            updateSelectorState();
+            break;
+        case TOUCH_MODE_SCROLL:
+            final int childCount = getChildCount();
+            if (childCount > 0) {
+                final int firstChildTop = getChildAt(0).getTop();
+                final int lastChildBottom = getChildAt(childCount - 1).getBottom();
+                final int contentTop = mListPadding.top;
+                final int contentBottom = getHeight() - mListPadding.bottom;
+                if (mFirstPosition == 0 && firstChildTop >= contentTop &&
+                        mFirstPosition + childCount < mItemCount &&
+                        lastChildBottom <= getHeight() - contentBottom) {
                     mTouchMode = TOUCH_MODE_REST;
                     reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                }
-                break;
-
-            case TOUCH_MODE_OVERSCROLL:
-                if (mFlingRunnable == null) {
-                    mFlingRunnable = new FlingRunnable();
-                }
-                final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                final int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
-
-                reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
-                if (Math.abs(initialVelocity) > mMinimumVelocity) {
-                    mFlingRunnable.startOverfling(-initialVelocity);
                 } else {
-                    mFlingRunnable.startSpringback();
+                    final VelocityTracker velocityTracker = mVelocityTracker;
+                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+
+                    final int initialVelocity = (int)
+                            (velocityTracker.getYVelocity(mActivePointerId) * mVelocityScale);
+                    // Fling if we have enough velocity and we aren't at a boundary.
+                    // Since we can potentially overfling more than we can overscroll, don't
+                    // allow the weird behavior where you can scroll to a boundary then
+                    // fling further.
+                    if (Math.abs(initialVelocity) > mMinimumVelocity &&
+                            !((mFirstPosition == 0 &&
+                                    firstChildTop == contentTop - mOverscrollDistance) ||
+                              (mFirstPosition + childCount == mItemCount &&
+                                    lastChildBottom == contentBottom + mOverscrollDistance))) {
+                        if (mFlingRunnable == null) {
+                            mFlingRunnable = new FlingRunnable();
+                        }
+                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+
+                        mFlingRunnable.start(-initialVelocity);
+                    } else {
+                        mTouchMode = TOUCH_MODE_REST;
+                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+                        if (mFlingRunnable != null) {
+                            mFlingRunnable.endFling();
+                        }
+                        if (mPositionScroller != null) {
+                            mPositionScroller.stop();
+                        }
+                    }
                 }
-
-                break;
-            }
-
-            setPressed(false);
-
-            if (mEdgeGlowTop != null) {
-                mEdgeGlowTop.onRelease();
-                mEdgeGlowBottom.onRelease();
-            }
-
-            // Need to redraw since we probably aren't drawing the selector anymore
-            invalidate();
-
-            final Handler handler = getHandler();
-            if (handler != null) {
-                handler.removeCallbacks(mPendingCheckForLongPress);
-            }
-
-            recycleVelocityTracker();
-
-            mActivePointerId = INVALID_POINTER;
-
-            if (PROFILE_SCROLLING) {
-                if (mScrollProfilingStarted) {
-                    Debug.stopMethodTracing();
-                    mScrollProfilingStarted = false;
-                }
-            }
-
-            if (mScrollStrictSpan != null) {
-                mScrollStrictSpan.finish();
-                mScrollStrictSpan = null;
-            }
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL: {
-            switch (mTouchMode) {
-            case TOUCH_MODE_OVERSCROLL:
-                if (mFlingRunnable == null) {
-                    mFlingRunnable = new FlingRunnable();
-                }
-                mFlingRunnable.startSpringback();
-                break;
-
-            case TOUCH_MODE_OVERFLING:
-                // Do nothing - let it play out.
-                break;
-
-            default:
+            } else {
                 mTouchMode = TOUCH_MODE_REST;
-                setPressed(false);
-                View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
-                if (motionView != null) {
-                    motionView.setPressed(false);
-                }
-                clearScrollingCache();
+                reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+            }
+            break;
 
-                final Handler handler = getHandler();
-                if (handler != null) {
-                    handler.removeCallbacks(mPendingCheckForLongPress);
-                }
+        case TOUCH_MODE_OVERSCROLL:
+            if (mFlingRunnable == null) {
+                mFlingRunnable = new FlingRunnable();
+            }
+            final VelocityTracker velocityTracker = mVelocityTracker;
+            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+            final int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
 
-                recycleVelocityTracker();
+            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+            if (Math.abs(initialVelocity) > mMinimumVelocity) {
+                mFlingRunnable.startOverfling(-initialVelocity);
+            } else {
+                mFlingRunnable.startSpringback();
             }
 
-            if (mEdgeGlowTop != null) {
-                mEdgeGlowTop.onRelease();
-                mEdgeGlowBottom.onRelease();
-            }
-            mActivePointerId = INVALID_POINTER;
             break;
         }
 
-        case MotionEvent.ACTION_POINTER_UP: {
-            onSecondaryPointerUp(ev);
-            final int x = mMotionX;
-            final int y = mMotionY;
-            final int motionPosition = pointToPosition(x, y);
-            if (motionPosition >= 0) {
-                // Remember where the motion event started
-                v = getChildAt(motionPosition - mFirstPosition);
-                mMotionViewOriginalTop = v.getTop();
-                mMotionPosition = motionPosition;
-            }
-            mLastY = y;
-            break;
+        setPressed(false);
+
+        if (mEdgeGlowTop != null) {
+            mEdgeGlowTop.onRelease();
+            mEdgeGlowBottom.onRelease();
         }
 
-        case MotionEvent.ACTION_POINTER_DOWN: {
-            // New pointers take over dragging duties
-            final int index = ev.getActionIndex();
-            final int id = ev.getPointerId(index);
-            final int x = (int) ev.getX(index);
-            final int y = (int) ev.getY(index);
-            mMotionCorrection = 0;
-            mActivePointerId = id;
-            mMotionX = x;
-            mMotionY = y;
-            final int motionPosition = pointToPosition(x, y);
-            if (motionPosition >= 0) {
-                // Remember where the motion event started
-                v = getChildAt(motionPosition - mFirstPosition);
-                mMotionViewOriginalTop = v.getTop();
-                mMotionPosition = motionPosition;
+        // Need to redraw since we probably aren't drawing the selector anymore
+        invalidate();
+        removeCallbacks(mPendingCheckForLongPress);
+        recycleVelocityTracker();
+
+        mActivePointerId = INVALID_POINTER;
+
+        if (PROFILE_SCROLLING) {
+            if (mScrollProfilingStarted) {
+                Debug.stopMethodTracing();
+                mScrollProfilingStarted = false;
             }
-            mLastY = y;
-            break;
-        }
         }
 
-        return true;
+        if (mScrollStrictSpan != null) {
+            mScrollStrictSpan.finish();
+            mScrollStrictSpan = null;
+        }
+    }
+
+    private void onTouchCancel() {
+        switch (mTouchMode) {
+        case TOUCH_MODE_OVERSCROLL:
+            if (mFlingRunnable == null) {
+                mFlingRunnable = new FlingRunnable();
+            }
+            mFlingRunnable.startSpringback();
+            break;
+
+        case TOUCH_MODE_OVERFLING:
+            // Do nothing - let it play out.
+            break;
+
+        default:
+            mTouchMode = TOUCH_MODE_REST;
+            setPressed(false);
+            final View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
+            if (motionView != null) {
+                motionView.setPressed(false);
+            }
+            clearScrollingCache();
+            removeCallbacks(mPendingCheckForLongPress);
+            recycleVelocityTracker();
+        }
+
+        if (mEdgeGlowTop != null) {
+            mEdgeGlowTop.onRelease();
+            mEdgeGlowBottom.onRelease();
+        }
+        mActivePointerId = INVALID_POINTER;
     }
 
     @Override
@@ -3728,18 +3852,6 @@
                 canvas.restoreToCount(restoreCount);
             }
         }
-        if (mFastScroller != null) {
-            final int scrollY = mScrollY;
-            if (scrollY != 0) {
-                // Pin to the top/bottom during overscroll
-                int restoreCount = canvas.save();
-                canvas.translate(0, (float) scrollY);
-                mFastScroller.draw(canvas);
-                canvas.restoreToCount(restoreCount);
-            } else {
-                mFastScroller.draw(canvas);
-            }
-        }
     }
 
     /**
@@ -3780,6 +3892,15 @@
     }
 
     @Override
+    public boolean onInterceptHoverEvent(MotionEvent event) {
+        if (mFastScroller != null && mFastScroller.onInterceptHoverEvent(event)) {
+            return true;
+        }
+
+        return super.onInterceptHoverEvent(event);
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
         View v;
@@ -3788,7 +3909,7 @@
             mPositionScroller.stop();
         }
 
-        if (!mIsAttached) {
+        if (!isAttachedToWindow()) {
             // Something isn't right.
             // Since we rely on being attached to get data set change notifications,
             // don't risk doing anything where we might try to resync and find things
@@ -3796,11 +3917,8 @@
             return false;
         }
 
-        if (mFastScroller != null) {
-            boolean intercepted = mFastScroller.onInterceptTouchEvent(ev);
-            if (intercepted) {
-                return true;
-            }
+        if (mFastScroller != null && mFastScroller.onInterceptTouchEvent(ev)) {
+            return true;
         }
 
         switch (action & MotionEvent.ACTION_MASK) {
@@ -3945,6 +4063,7 @@
         private int mLastFlingY;
 
         private final Runnable mCheckFlywheel = new Runnable() {
+            @Override
             public void run() {
                 final int activeId = mActivePointerId;
                 final VelocityTracker vt = mVelocityTracker;
@@ -4066,6 +4185,7 @@
             postDelayed(mCheckFlywheel, FLYWHEEL_TIMEOUT);
         }
 
+        @Override
         public void run() {
             switch (mTouchMode) {
             default:
@@ -4455,6 +4575,7 @@
             removeCallbacks(this);
         }
 
+        @Override
         public void run() {
             final int listHeight = getHeight();
             final int firstPos = mFirstPosition;
@@ -4637,9 +4758,6 @@
     /**
      * The amount of friction applied to flings. The default value
      * is {@link ViewConfiguration#getScrollFriction}.
-     *
-     * @return A scalar dimensionless value representing the coefficient of
-     *         friction.
      */
     public void setFriction(float friction) {
         if (mFlingRunnable == null) {
@@ -4806,6 +4924,7 @@
         if (!isHardwareAccelerated()) {
             if (mClearScrollingCache == null) {
                 mClearScrollingCache = new Runnable() {
+                    @Override
                     public void run() {
                         if (mCachingStarted) {
                             mCachingStarted = mCachingActive = false;
@@ -4825,6 +4944,43 @@
     }
 
     /**
+     * Scrolls the list items within the view by a specified number of pixels.
+     *
+     * @param y the amount of pixels to scroll by vertically
+     * @see #canScrollList(int)
+     */
+    public void scrollListBy(int y) {
+        trackMotionScroll(-y, -y);
+    }
+
+    /**
+     * Check if the items in the list can be scrolled in a certain direction.
+     *
+     * @param direction Negative to check scrolling up, positive to check
+     *            scrolling down.
+     * @return true if the list can be scrolled in the specified direction,
+     *         false otherwise.
+     * @see #scrollListBy(int)
+     */
+    public boolean canScrollList(int direction) {
+        final int childCount = getChildCount();
+        if (childCount == 0) {
+            return false;
+        }
+
+        final int firstPosition = mFirstPosition;
+        final Rect listPadding = mListPadding;
+        if (direction > 0) {
+            final int lastBottom = getChildAt(childCount - 1).getBottom();
+            final int lastPosition = firstPosition + childCount;
+            return lastPosition < mItemCount || lastBottom > getHeight() - listPadding.bottom;
+        } else {
+            final int firstTop = getChildAt(0).getTop();
+            return firstPosition > 0 || firstTop < listPadding.top;
+        }
+    }
+
+    /**
      * Track a motion scroll
      *
      * @param deltaY Amount to offset mMotionView. This is the accumulated delta since the motion
@@ -4920,6 +5076,11 @@
                     count++;
                     int position = firstPosition + i;
                     if (position >= headerViewsCount && position < footerViewsStart) {
+                        // The view will be rebound to new data, clear any
+                        // system-managed transient state.
+                        if (child.isAccessibilityFocused()) {
+                            child.clearAccessibilityFocus();
+                        }
                         mRecycler.addScrapView(child, position);
                     }
                 }
@@ -4938,6 +5099,11 @@
                     count++;
                     int position = firstPosition + i;
                     if (position >= headerViewsCount && position < footerViewsStart) {
+                        // The view will be rebound to new data, clear any
+                        // system-managed transient state.
+                        if (child.isAccessibilityFocused()) {
+                            child.clearAccessibilityFocus();
+                        }
                         mRecycler.addScrapView(child, position);
                     }
                 }
@@ -5083,7 +5249,7 @@
         requestLayout();
         invalidate();
     }
-    
+
     /**
      * If there is a selection returns false.
      * Otherwise resurrects the selection and returns true if resurrected.
@@ -5591,54 +5757,157 @@
     @Override
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         if (isTextFilterEnabled()) {
-            // XXX we need to have the text filter created, so we can get an
-            // InputConnection to proxy to.  Unfortunately this means we pretty
-            // much need to make it as soon as a list view gets focus.
-            createTextFilter(false);
             if (mPublicInputConnection == null) {
                 mDefInputConnection = new BaseInputConnection(this, false);
-                mPublicInputConnection = new InputConnectionWrapper(
-                        mTextFilter.onCreateInputConnection(outAttrs), true) {
-                    @Override
-                    public boolean reportFullscreenMode(boolean enabled) {
-                        // Use our own input connection, since it is
-                        // the "real" one the IME is talking with.
-                        return mDefInputConnection.reportFullscreenMode(enabled);
-                    }
-
-                    @Override
-                    public boolean performEditorAction(int editorAction) {
-                        // The editor is off in its own window; we need to be
-                        // the one that does this.
-                        if (editorAction == EditorInfo.IME_ACTION_DONE) {
-                            InputMethodManager imm = (InputMethodManager)
-                                    getContext().getSystemService(
-                                            Context.INPUT_METHOD_SERVICE);
-                            if (imm != null) {
-                                imm.hideSoftInputFromWindow(getWindowToken(), 0);
-                            }
-                            return true;
-                        }
-                        return false;
-                    }
-
-                    @Override
-                    public boolean sendKeyEvent(KeyEvent event) {
-                        // Use our own input connection, since the filter
-                        // text view may not be shown in a window so has
-                        // no ViewAncestor to dispatch events with.
-                        return mDefInputConnection.sendKeyEvent(event);
-                    }
-                };
+                mPublicInputConnection = new InputConnectionWrapper(outAttrs);
             }
-            outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
-                    | EditorInfo.TYPE_TEXT_VARIATION_FILTER;
+            outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_FILTER;
             outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
             return mPublicInputConnection;
         }
         return null;
     }
 
+    private class InputConnectionWrapper implements InputConnection {
+        private final EditorInfo mOutAttrs;
+        private InputConnection mTarget;
+
+        public InputConnectionWrapper(EditorInfo outAttrs) {
+            mOutAttrs = outAttrs;
+        }
+
+        private InputConnection getTarget() {
+            if (mTarget == null) {
+                mTarget = getTextFilterInput().onCreateInputConnection(mOutAttrs);
+            }
+            return mTarget;
+        }
+
+        @Override
+        public boolean reportFullscreenMode(boolean enabled) {
+            // Use our own input connection, since it is
+            // the "real" one the IME is talking with.
+            return mDefInputConnection.reportFullscreenMode(enabled);
+        }
+
+        @Override
+        public boolean performEditorAction(int editorAction) {
+            // The editor is off in its own window; we need to be
+            // the one that does this.
+            if (editorAction == EditorInfo.IME_ACTION_DONE) {
+                InputMethodManager imm = (InputMethodManager)
+                        getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+                if (imm != null) {
+                    imm.hideSoftInputFromWindow(getWindowToken(), 0);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean sendKeyEvent(KeyEvent event) {
+            // Use our own input connection, since the filter
+            // text view may not be shown in a window so has
+            // no ViewAncestor to dispatch events with.
+            return mDefInputConnection.sendKeyEvent(event);
+        }
+
+        @Override
+        public CharSequence getTextBeforeCursor(int n, int flags) {
+            if (mTarget == null) return "";
+            return mTarget.getTextBeforeCursor(n, flags);
+        }
+
+        @Override
+        public CharSequence getTextAfterCursor(int n, int flags) {
+            if (mTarget == null) return "";
+            return mTarget.getTextAfterCursor(n, flags);
+        }
+
+        @Override
+        public CharSequence getSelectedText(int flags) {
+            if (mTarget == null) return "";
+            return mTarget.getSelectedText(flags);
+        }
+
+        @Override
+        public int getCursorCapsMode(int reqModes) {
+            if (mTarget == null) return InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
+            return mTarget.getCursorCapsMode(reqModes);
+        }
+
+        @Override
+        public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+            return getTarget().getExtractedText(request, flags);
+        }
+
+        @Override
+        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+            return getTarget().deleteSurroundingText(beforeLength, afterLength);
+        }
+
+        @Override
+        public boolean setComposingText(CharSequence text, int newCursorPosition) {
+            return getTarget().setComposingText(text, newCursorPosition);
+        }
+
+        @Override
+        public boolean setComposingRegion(int start, int end) {
+            return getTarget().setComposingRegion(start, end);
+        }
+
+        @Override
+        public boolean finishComposingText() {
+            return mTarget == null || mTarget.finishComposingText();
+        }
+
+        @Override
+        public boolean commitText(CharSequence text, int newCursorPosition) {
+            return getTarget().commitText(text, newCursorPosition);
+        }
+
+        @Override
+        public boolean commitCompletion(CompletionInfo text) {
+            return getTarget().commitCompletion(text);
+        }
+
+        @Override
+        public boolean commitCorrection(CorrectionInfo correctionInfo) {
+            return getTarget().commitCorrection(correctionInfo);
+        }
+
+        @Override
+        public boolean setSelection(int start, int end) {
+            return getTarget().setSelection(start, end);
+        }
+
+        @Override
+        public boolean performContextMenuAction(int id) {
+            return getTarget().performContextMenuAction(id);
+        }
+
+        @Override
+        public boolean beginBatchEdit() {
+            return getTarget().beginBatchEdit();
+        }
+
+        @Override
+        public boolean endBatchEdit() {
+            return getTarget().endBatchEdit();
+        }
+
+        @Override
+        public boolean clearMetaKeyStates(int states) {
+            return getTarget().clearMetaKeyStates(states);
+        }
+
+        @Override
+        public boolean performPrivateCommand(String action, Bundle data) {
+            return getTarget().performPrivateCommand(action, data);
+        }
+    }
+
     /**
      * For filtering we proxy an input connection to an internal text editor,
      * and this allows the proxying to happen.
@@ -5655,23 +5924,11 @@
      */
     private void createTextFilter(boolean animateEntrance) {
         if (mPopup == null) {
-            Context c = getContext();
-            PopupWindow p = new PopupWindow(c);
-            LayoutInflater layoutInflater = (LayoutInflater)
-                    c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            mTextFilter = (EditText) layoutInflater.inflate(
-                    com.android.internal.R.layout.typing_filter, null);
-            // For some reason setting this as the "real" input type changes
-            // the text view in some way that it doesn't work, and I don't
-            // want to figure out why this is.
-            mTextFilter.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
-                    | EditorInfo.TYPE_TEXT_VARIATION_FILTER);
-            mTextFilter.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
-            mTextFilter.addTextChangedListener(this);
+            PopupWindow p = new PopupWindow(getContext());
             p.setFocusable(false);
             p.setTouchable(false);
             p.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
-            p.setContentView(mTextFilter);
+            p.setContentView(getTextFilterInput());
             p.setWidth(LayoutParams.WRAP_CONTENT);
             p.setHeight(LayoutParams.WRAP_CONTENT);
             p.setBackgroundDrawable(null);
@@ -5686,12 +5943,28 @@
         }
     }
 
+    private EditText getTextFilterInput() {
+        if (mTextFilter == null) {
+            final LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+            mTextFilter = (EditText) layoutInflater.inflate(
+                    com.android.internal.R.layout.typing_filter, null);
+            // For some reason setting this as the "real" input type changes
+            // the text view in some way that it doesn't work, and I don't
+            // want to figure out why this is.
+            mTextFilter.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
+                    | EditorInfo.TYPE_TEXT_VARIATION_FILTER);
+            mTextFilter.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
+            mTextFilter.addTextChangedListener(this);
+        }
+        return mTextFilter;
+    }
+
     /**
      * Clear the text filter.
      */
     public void clearTextFilter() {
         if (mFiltered) {
-            mTextFilter.setText("");
+            getTextFilterInput().setText("");
             mFiltered = false;
             if (mPopup != null && mPopup.isShowing()) {
                 dismissPopup();
@@ -5706,6 +5979,7 @@
         return mFiltered;
     }
 
+    @Override
     public void onGlobalLayout() {
         if (isShown()) {
             // Show the popup if we are filtered
@@ -5725,6 +5999,7 @@
      * For our text watcher that is associated with the text filter.  Does
      * nothing.
      */
+    @Override
     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
     }
 
@@ -5733,8 +6008,10 @@
      * the actual filtering as the text changes, and takes care of hiding and
      * showing the popup displaying the currently entered filter text.
      */
+    @Override
     public void onTextChanged(CharSequence s, int start, int before, int count) {
-        if (mPopup != null && isTextFilterEnabled()) {
+        if (isTextFilterEnabled()) {
+            createTextFilter(true);
             int length = s.length();
             boolean showing = mPopup.isShowing();
             if (!showing && length > 0) {
@@ -5763,9 +6040,11 @@
      * For our text watcher that is associated with the text filter.  Does
      * nothing.
      */
+    @Override
     public void afterTextChanged(Editable s) {
     }
 
+    @Override
     public void onFilterComplete(int count) {
         if (mSelectedPosition < 0 && count > 0) {
             mResurrectToPosition = INVALID_POSITION;
@@ -5917,9 +6196,9 @@
 
     /**
      * Sets up the onClickHandler to be used by the RemoteViewsAdapter when inflating RemoteViews
-     * 
+     *
      * @param handler The OnClickHandler to use when inflating RemoteViews.
-     * 
+     *
      * @hide
      */
     public void setRemoteViewsOnClickHandler(OnClickHandler handler) {
@@ -5934,6 +6213,7 @@
      * This defers a notifyDataSetChanged on the pending RemoteViewsAdapter if it has not
      * connected yet.
      */
+    @Override
     public void deferNotifyDataSetChanged() {
         mDeferNotifyDataSetChanged = true;
     }
@@ -5941,6 +6221,7 @@
     /**
      * Called back when the adapter connects to the RemoteViewsService.
      */
+    @Override
     public boolean onRemoteAdapterConnected() {
         if (mRemoteAdapter != mAdapter) {
             setAdapter(mRemoteAdapter);
@@ -5959,6 +6240,7 @@
     /**
      * Called back when the adapter disconnects from the RemoteViewsService.
      */
+    @Override
     public void onRemoteAdapterDisconnected() {
         // If the remote adapter disconnects, we keep it around
         // since the currently displayed items are still cached.
@@ -6041,6 +6323,7 @@
             return mWrapped != null;
         }
 
+        @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             if (mWrapped.onCreateActionMode(mode, menu)) {
                 // Initialize checked graphic state?
@@ -6050,14 +6333,17 @@
             return false;
         }
 
+        @Override
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
             return mWrapped.onPrepareActionMode(mode, menu);
         }
 
+        @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
             return mWrapped.onActionItemClicked(mode, item);
         }
 
+        @Override
         public void onDestroyActionMode(ActionMode mode) {
             mWrapped.onDestroyActionMode(mode);
             mChoiceActionMode = null;
@@ -6072,6 +6358,7 @@
             setLongClickable(true);
         }
 
+        @Override
         public void onItemCheckedStateChanged(ActionMode mode,
                 int position, long id, boolean checked) {
             mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
@@ -6296,6 +6583,7 @@
             }
             mFirstActivePosition = firstActivePosition;
 
+            //noinspection MismatchedReadAndWriteOfArray
             final View[] activeViews = mActiveViews;
             for (int i = 0; i < childCount; i++) {
                 View child = getChildAt(i);
@@ -6373,58 +6661,72 @@
         }
 
         /**
-         * Put a view into the ScrapViews list. These views are unordered.
+         * Puts a view into the list of scrap views.
+         * <p>
+         * If the list data hasn't changed or the adapter has stable IDs, views
+         * with transient state will be preserved for later retrieval.
          *
          * @param scrap The view to add
+         * @param position The view's position within its parent
          */
         void addScrapView(View scrap, int position) {
-            AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
+            final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
             if (lp == null) {
                 return;
             }
 
             lp.scrappedFromPosition = position;
 
-            // Don't put header or footer views or views that should be ignored
-            // into the scrap heap
-            int viewType = lp.viewType;
+            // Remove but don't scrap header or footer views, or views that
+            // should otherwise not be recycled.
+            final int viewType = lp.viewType;
+            if (!shouldRecycleViewType(viewType)) {
+                return;
+            }
+
+            scrap.dispatchStartTemporaryDetach();
+
+            // Don't scrap views that have transient state.
             final boolean scrapHasTransientState = scrap.hasTransientState();
-            if (!shouldRecycleViewType(viewType) || scrapHasTransientState) {
-                if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER && scrapHasTransientState) {
+            if (scrapHasTransientState) {
+                if (mAdapter != null && mAdapterHasStableIds) {
+                    // If the adapter has stable IDs, we can reuse the view for
+                    // the same data.
+                    if (mTransientStateViewsById == null) {
+                        mTransientStateViewsById = new LongSparseArray<View>();
+                    }
+                    mTransientStateViewsById.put(lp.itemId, scrap);
+                } else if (!mDataChanged) {
+                    // If the data hasn't changed, we can reuse the views at
+                    // their old positions.
+                    if (mTransientStateViews == null) {
+                        mTransientStateViews = new SparseArray<View>();
+                    }
+                    mTransientStateViews.put(position, scrap);
+                } else {
+                    // Otherwise, we'll have to remove the view and start over.
                     if (mSkippedScrap == null) {
                         mSkippedScrap = new ArrayList<View>();
                     }
                     mSkippedScrap.add(scrap);
                 }
-                if (scrapHasTransientState) {
-                    scrap.dispatchStartTemporaryDetach();
-                    if (mAdapter != null && mAdapterHasStableIds) {
-                        if (mTransientStateViewsById == null) {
-                            mTransientStateViewsById = new LongSparseArray<View>();
-                        }
-                        mTransientStateViewsById.put(lp.itemId, scrap);
-                    } else if (!mDataChanged) {
-                        // avoid putting views on transient state list during a data change;
-                        // the layout positions may be out of sync with the adapter positions
-                        if (mTransientStateViews == null) {
-                            mTransientStateViews = new SparseArray<View>();
-                        }
-                        mTransientStateViews.put(position, scrap);
-                    }
-                }
-                return;
-            }
-
-            scrap.dispatchStartTemporaryDetach();
-            if (mViewTypeCount == 1) {
-                mCurrentScrap.add(scrap);
             } else {
-                mScrapViews[viewType].add(scrap);
-            }
+                if (mViewTypeCount == 1) {
+                    mCurrentScrap.add(scrap);
+                } else {
+                    mScrapViews[viewType].add(scrap);
+                }
 
-            scrap.setAccessibilityDelegate(null);
-            if (mRecyclerListener != null) {
-                mRecyclerListener.onMovedToScrapHeap(scrap);
+                // Clear any system-managed transient state.
+                if (scrap.isAccessibilityFocused()) {
+                    scrap.clearAccessibilityFocus();
+                }
+
+                scrap.setAccessibilityDelegate(null);
+
+                if (mRecyclerListener != null) {
+                    mRecyclerListener.onMovedToScrapHeap(scrap);
+                }
             }
         }
 
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 2037c3a..dff1531 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -29,11 +29,14 @@
 import android.util.AttributeSet;
 import android.view.ActionProvider;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ActivityChooserModel.ActivityChooserModelClient;
+import android.widget.ListPopupWindow.ForwardingListener;
 
 /**
  * This class is a view for choosing an activity for handling a given {@link Intent}.
@@ -227,10 +230,37 @@
         mDefaultActivityButton.setOnLongClickListener(mCallbacks);
         mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
 
-        mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.expand_activities_button);
-        mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
+        final FrameLayout expandButton = (FrameLayout) findViewById(R.id.expand_activities_button);
+        expandButton.setOnClickListener(mCallbacks);
+        expandButton.setAccessibilityDelegate(new AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.setCanOpenPopup(true);
+            }
+        });
+        expandButton.setOnTouchListener(new ForwardingListener(expandButton) {
+            @Override
+            public ListPopupWindow getPopup() {
+                return getListPopupWindow();
+            }
+
+            @Override
+            protected boolean onForwardingStarted() {
+                showPopup();
+                return true;
+            }
+
+            @Override
+            protected boolean onForwardingStopped() {
+                dismissPopup();
+                return true;
+            }
+        });
+        mExpandActivityOverflowButton = expandButton;
+
         mExpandActivityOverflowButtonImage =
-            (ImageView) mExpandActivityOverflowButton.findViewById(R.id.image);
+            (ImageView) expandButton.findViewById(R.id.image);
         mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
 
         mAdapter = new ActivityChooserViewAdapter();
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 502de31..a5fad60 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -31,7 +31,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
 
 /**
  * An AdapterView is a view whose children are determined by an {@link Adapter}.
@@ -281,7 +280,9 @@
     }
 
     /**
-     * Call the OnItemClickListener, if it is defined.
+     * Call the OnItemClickListener, if it is defined. Performs all normal
+     * actions associated with clicking: reporting accessibility event, playing
+     * a sound, etc.
      *
      * @param view The view within the AdapterView that was clicked.
      * @param position The position of the view in the adapter.
@@ -1034,8 +1035,7 @@
             checkSelectionChanged();
         }
 
-        //TODO: Hmm, we do not know the old state so this is sub-optimal
-        notifyAccessibilityStateChanged();
+        notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
     void checkSelectionChanged() {
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 6970cde..0957ab4 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -391,7 +391,7 @@
         mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                 UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics);
 
-        LayoutInflater layoutInflater = (LayoutInflater) mContext
+        LayoutInflater layoutInflater = (LayoutInflater) context
                 .getSystemService(Service.LAYOUT_INFLATER_SERVICE);
         View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
         addView(content);
@@ -874,7 +874,6 @@
         }
         mFirstDayOfWeek = firstDayOfWeek;
         mAdapter.init();
-        mAdapter.notifyDataSetChanged();
         setUpHeader();
     }
 
@@ -937,7 +936,7 @@
     }
 
     private void updateDateTextSize() {
-        TypedArray dateTextAppearance = getContext().obtainStyledAttributes(
+        TypedArray dateTextAppearance = mContext.obtainStyledAttributes(
                 mDateTextAppearanceResId, R.styleable.TextAppearance);
         mDateTextSize = dateTextAppearance.getDimensionPixelSize(
                 R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
@@ -1004,7 +1003,7 @@
      */
     private void setUpAdapter() {
         if (mAdapter == null) {
-            mAdapter = new WeeksAdapter(getContext());
+            mAdapter = new WeeksAdapter();
             mAdapter.registerDataSetObserver(new DataSetObserver() {
                 @Override
                 public void onChanged() {
@@ -1028,26 +1027,29 @@
      * Sets up the strings to be used by the header.
      */
     private void setUpHeader() {
+        final String[] tinyWeekdayNames = LocaleData.get(Locale.getDefault()).tinyWeekdayNames;
         mDayLabels = new String[mDaysPerWeek];
-        for (int i = mFirstDayOfWeek, count = mFirstDayOfWeek + mDaysPerWeek; i < count; i++) {
-            int calendarDay = (i > Calendar.SATURDAY) ? i - Calendar.SATURDAY : i;
-            mDayLabels[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
-                    DateUtils.LENGTH_SHORTEST);
+        for (int i = 0; i < mDaysPerWeek; i++) {
+            final int j = i + mFirstDayOfWeek;
+            final int calendarDay = (j > Calendar.SATURDAY) ? j - Calendar.SATURDAY : j;
+            mDayLabels[i] = tinyWeekdayNames[calendarDay];
         }
-
+        // Deal with week number
         TextView label = (TextView) mDayNamesHeader.getChildAt(0);
         if (mShowWeekNumber) {
             label.setVisibility(View.VISIBLE);
         } else {
             label.setVisibility(View.GONE);
         }
-        for (int i = 1, count = mDayNamesHeader.getChildCount(); i < count; i++) {
-            label = (TextView) mDayNamesHeader.getChildAt(i);
+        // Deal with day labels
+        final int count = mDayNamesHeader.getChildCount();
+        for (int i = 0; i < count - 1; i++) {
+            label = (TextView) mDayNamesHeader.getChildAt(i + 1);
             if (mWeekDayTextAppearanceResId > -1) {
                 label.setTextAppearance(mContext, mWeekDayTextAppearanceResId);
             }
-            if (i < mDaysPerWeek + 1) {
-                label.setText(mDayLabels[i - 1]);
+            if (i < mDaysPerWeek) {
+                label.setText(mDayLabels[i]);
                 label.setVisibility(View.VISIBLE);
             } else {
                 label.setVisibility(View.GONE);
@@ -1330,19 +1332,16 @@
      * </p>
      */
     private class WeeksAdapter extends BaseAdapter implements OnTouchListener {
+        private final Calendar mSelectedDate = Calendar.getInstance();
+        private final GestureDetector mGestureDetector;
 
         private int mSelectedWeek;
 
-        private GestureDetector mGestureDetector;
-
         private int mFocusedMonth;
 
-        private final Calendar mSelectedDate = Calendar.getInstance();
-
         private int mTotalWeekCount;
 
-        public WeeksAdapter(Context context) {
-            mContext = context;
+        public WeeksAdapter() {
             mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
             init();
         }
@@ -1357,6 +1356,7 @@
                 || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) {
                 mTotalWeekCount++;
             }
+            notifyDataSetChanged();
         }
 
         /**
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 3f080d6..5c10a77 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -93,7 +93,8 @@
         if (mChecked != checked) {
             mChecked = checked;
             refreshDrawableState();
-            notifyAccessibilityStateChanged();
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
 
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 452ad1b..082ff3d 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -114,7 +114,8 @@
         if (mChecked != checked) {
             mChecked = checked;
             refreshDrawableState();
-            notifyAccessibilityStateChanged();
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
 
             // Avoid infinite recursions if setChecked() is called from a listener
             if (mBroadcasting) {
@@ -199,10 +200,8 @@
                 unscheduleDrawable(mButtonDrawable);
             }
             d.setCallback(this);
-            d.setState(getDrawableState());
             d.setVisible(getVisibility() == VISIBLE, false);
             mButtonDrawable = d;
-            mButtonDrawable.setState(null);
             setMinHeight(mButtonDrawable.getIntrinsicHeight());
         }
 
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index 6c4c39d..d4c5be0 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -26,9 +26,13 @@
 import android.view.ViewGroup;
 
 /**
- * Adapter that exposes data from a {@link android.database.Cursor Cursor} to a 
- * {@link android.widget.ListView ListView} widget. The Cursor must include 
- * a column named "_id" or this class will not work.
+ * Adapter that exposes data from a {@link android.database.Cursor Cursor} to a
+ * {@link android.widget.ListView ListView} widget.
+ * <p>
+ * The Cursor must include a column named "_id" or this class will not work.
+ * Additionally, using {@link android.database.MergeCursor} with this class will
+ * not work if the merged Cursors have overlapping values in their "_id"
+ * columns.
  */
 public abstract class CursorAdapter extends BaseAdapter implements Filterable,
         CursorFilter.CursorFilterClient {
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index bb4a4cf..30752e0 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -68,6 +68,8 @@
 
     // Minimum velocity that will be absorbed
     private static final int MIN_VELOCITY = 100;
+    // Maximum velocity, clamps at this value
+    private static final int MAX_VELOCITY = 10000;
 
     private static final float EPSILON = 0.001f;
 
@@ -115,7 +117,7 @@
     private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f;
 
     private static final int VELOCITY_EDGE_FACTOR = 8;
-    private static final int VELOCITY_GLOW_FACTOR = 16;
+    private static final int VELOCITY_GLOW_FACTOR = 12;
 
     private int mState = STATE_IDLE;
 
@@ -283,10 +285,10 @@
      */
     public void onAbsorb(int velocity) {
         mState = STATE_ABSORB;
-        velocity = Math.max(MIN_VELOCITY, Math.abs(velocity));
+        velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);
 
         mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        mDuration = 0.1f + (velocity * 0.03f);
+        mDuration = 0.15f + (velocity * 0.02f);
 
         // The edge should always be at least partially visible, regardless
         // of velocity.
@@ -294,7 +296,7 @@
         mEdgeScaleY = mEdgeScaleYStart = 0.f;
         // The glow depends more on the velocity, and therefore starts out
         // nearly invisible.
-        mGlowAlphaStart = 0.5f;
+        mGlowAlphaStart = 0.3f;
         mGlowScaleYStart = 0.f;
 
         // Factor the velocity by 8. Testing on device shows this works best to
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f57f333..2b90281 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,6 +16,13 @@
 
 package android.widget;
 
+import android.content.UndoManager;
+import android.content.UndoOperation;
+import android.content.UndoOwner;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.InputFilter;
+import android.text.SpannableString;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.EditableInputConnection;
 
@@ -107,11 +114,16 @@
  */
 public class Editor {
     private static final String TAG = "Editor";
+    static final boolean DEBUG_UNDO = false;
 
     static final int BLINK = 500;
     private static final float[] TEMP_POSITION = new float[2];
     private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
 
+    UndoManager mUndoManager;
+    UndoOwner mUndoOwner;
+    InputFilter mUndoInputFilter;
+
     // Cursor Controllers.
     InsertionPointCursorController mInsertionPointCursorController;
     SelectionModifierCursorController mSelectionModifierCursorController;
@@ -181,7 +193,10 @@
     // Set when this TextView gained focus with some text selected. Will start selection mode.
     boolean mCreatedWithASelection;
 
-    private EasyEditSpanController mEasyEditSpanController;
+    // The span controller helps monitoring the changes to which the Editor needs to react:
+    // - EasyEditSpans, for which we have some UI to display on attach and on hide
+    // - SelectionSpans, for which we need to call updateSelection if an IME is attached
+    private SpanController mSpanController;
 
     WordIterator mWordIterator;
     SpellChecker mSpellChecker;
@@ -190,8 +205,6 @@
 
     private TextView mTextView;
 
-    private final UserDictionaryListener mUserDictionaryListener = new UserDictionaryListener();
-
     Editor(TextView textView) {
         mTextView = textView;
     }
@@ -466,8 +479,8 @@
     }
 
     private void hideSpanControllers() {
-        if (mEasyEditSpanController != null) {
-            mEasyEditSpanController.hide();
+        if (mSpanController != null) {
+            mSpanController.hide();
         }
     }
 
@@ -484,6 +497,10 @@
      * Create new SpellCheckSpans on the modified region.
      */
     private void updateSpellCheckSpans(int start, int end, boolean createSpellChecker) {
+        // Remove spans whose adjacent characters are text not punctuation
+        mTextView.removeAdjacentSuggestionSpans(start);
+        mTextView.removeAdjacentSuggestionSpans(end);
+
         if (mTextView.isTextEditable() && mTextView.isSuggestionsEnabled() &&
                 !(mTextView instanceof ExtractEditText)) {
             if (mSpellChecker == null && createSpellChecker) {
@@ -1082,9 +1099,12 @@
             mTextView.updateAfterEdit();
             reportExtractedText();
         } else if (ims.mCursorChanged) {
-            // Cheezy way to get us to report the current cursor location.
+            // Cheesy way to get us to report the current cursor location.
             mTextView.invalidateCursor();
         }
+        // sendUpdateSelection knows to avoid sending if the selection did
+        // not actually change.
+        sendUpdateSelection();
     }
 
     static final int EXTRACT_NOTHING = -2;
@@ -1205,6 +1225,27 @@
         return false;
     }
 
+    private void sendUpdateSelection() {
+        if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0) {
+            final InputMethodManager imm = InputMethodManager.peekInstance();
+            if (null != imm) {
+                final int selectionStart = mTextView.getSelectionStart();
+                final int selectionEnd = mTextView.getSelectionEnd();
+                int candStart = -1;
+                int candEnd = -1;
+                if (mTextView.getText() instanceof Spannable) {
+                    final Spannable sp = (Spannable) mTextView.getText();
+                    candStart = EditableInputConnection.getComposingSpanStart(sp);
+                    candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+                }
+                // InputMethodManager#updateSelection skips sending the message if
+                // none of the parameters have changed since the last time we called it.
+                imm.updateSelection(mTextView,
+                        selectionStart, selectionEnd, candStart, candEnd);
+            }
+        }
+    }
+
     void onDraw(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint,
             int cursorOffsetVertical) {
         final int selectionStart = mTextView.getSelectionStart();
@@ -1222,17 +1263,6 @@
                         // input method.
                         reported = reportExtractedText();
                     }
-                    if (!reported && highlight != null) {
-                        int candStart = -1;
-                        int candEnd = -1;
-                        if (mTextView.getText() instanceof Spannable) {
-                            Spannable sp = (Spannable) mTextView.getText();
-                            candStart = EditableInputConnection.getComposingSpanStart(sp);
-                            candEnd = EditableInputConnection.getComposingSpanEnd(sp);
-                        }
-                        imm.updateSelection(mTextView,
-                                selectionStart, selectionEnd, candStart, candEnd);
-                    }
                 }
 
                 if (imm.isWatchingCursor(mTextView) && highlight != null) {
@@ -1859,17 +1889,18 @@
             text.setSpan(mKeyListener, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
         }
 
-        if (mEasyEditSpanController == null) {
-            mEasyEditSpanController = new EasyEditSpanController();
+        if (mSpanController == null) {
+            mSpanController = new SpanController();
         }
-        text.setSpan(mEasyEditSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        text.setSpan(mSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
     }
 
     /**
      * Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
      * pop-up should be displayed.
+     * Also monitors {@link Selection} to call back to the attached input method.
      */
-    class EasyEditSpanController implements SpanWatcher {
+    class SpanController implements SpanWatcher {
 
         private static final int DISPLAY_TIMEOUT_MS = 3000; // 3 secs
 
@@ -1877,9 +1908,18 @@
 
         private Runnable mHidePopup;
 
+        // This function is pure but inner classes can't have static functions
+        private boolean isNonIntermediateSelectionSpan(final Spannable text,
+                final Object span) {
+            return (Selection.SELECTION_START == span || Selection.SELECTION_END == span)
+                    && (text.getSpanFlags(span) & Spanned.SPAN_INTERMEDIATE) == 0;
+        }
+
         @Override
         public void onSpanAdded(Spannable text, Object span, int start, int end) {
-            if (span instanceof EasyEditSpan) {
+            if (isNonIntermediateSelectionSpan(text, span)) {
+                sendUpdateSelection();
+            } else if (span instanceof EasyEditSpan) {
                 if (mPopupWindow == null) {
                     mPopupWindow = new EasyEditPopupWindow();
                     mHidePopup = new Runnable() {
@@ -1903,7 +1943,7 @@
                         int start = editable.getSpanStart(span);
                         int end = editable.getSpanEnd(span);
                         if (start >= 0 && end >= 0) {
-                            sendNotification(EasyEditSpan.TEXT_DELETED, span);
+                            sendEasySpanNotification(EasyEditSpan.TEXT_DELETED, span);
                             mTextView.deleteText_internal(start, end);
                         }
                         editable.removeSpan(span);
@@ -1934,7 +1974,9 @@
 
         @Override
         public void onSpanRemoved(Spannable text, Object span, int start, int end) {
-            if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) {
+            if (isNonIntermediateSelectionSpan(text, span)) {
+                sendUpdateSelection();
+            } else if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) {
                 hide();
             }
         }
@@ -1942,9 +1984,11 @@
         @Override
         public void onSpanChanged(Spannable text, Object span, int previousStart, int previousEnd,
                 int newStart, int newEnd) {
-            if (mPopupWindow != null && span instanceof EasyEditSpan) {
+            if (isNonIntermediateSelectionSpan(text, span)) {
+                sendUpdateSelection();
+            } else if (mPopupWindow != null && span instanceof EasyEditSpan) {
                 EasyEditSpan easyEditSpan = (EasyEditSpan) span;
-                sendNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan);
+                sendEasySpanNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan);
                 text.removeSpan(easyEditSpan);
             }
         }
@@ -1956,7 +2000,7 @@
             }
         }
 
-        private void sendNotification(int textChangedType, EasyEditSpan span) {
+        private void sendEasySpanNotification(int textChangedType, EasyEditSpan span) {
             try {
                 PendingIntent pendingIntent = span.getPendingIntent();
                 if (pendingIntent != null) {
@@ -1984,7 +2028,7 @@
 
     /**
      * Displays the actions associated to an {@link EasyEditSpan}. The pop-up is controlled
-     * by {@link EasyEditSpanController}.
+     * by {@link SpanController}.
      */
     private class EasyEditPopupWindow extends PinnedPopupWindow
             implements OnClickListener {
@@ -2661,9 +2705,6 @@
                 intent.putExtra("locale", mTextView.getTextServicesLocale().toString());
                 // Put a listener to replace the original text with a word which the user
                 // modified in a user dictionary dialog.
-                mUserDictionaryListener.waitForUserDictionaryAdded(
-                        mTextView, originalText, spanStart, spanEnd);
-                intent.putExtra("listener", new Messenger(mUserDictionaryListener));
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                 mTextView.getContext().startActivity(intent);
                 // There is no way to know if the word was indeed added. Re-check.
@@ -3869,64 +3910,165 @@
         int mChangedStart, mChangedEnd, mChangedDelta;
     }
 
-    /**
-     * @hide
-     */
-    public static class UserDictionaryListener extends Handler {
-        public TextView mTextView;
-        public String mOriginalWord;
-        public int mWordStart;
-        public int mWordEnd;
+    public static class UndoInputFilter implements InputFilter {
+        final Editor mEditor;
 
-        public void waitForUserDictionaryAdded(
-                TextView tv, String originalWord, int spanStart, int spanEnd) {
-            mTextView = tv;
-            mOriginalWord = originalWord;
-            mWordStart = spanStart;
-            mWordEnd = spanEnd;
+        public UndoInputFilter(Editor editor) {
+            mEditor = editor;
         }
 
         @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case 0: /* CODE_WORD_ADDED */
-                case 2: /* CODE_ALREADY_PRESENT */
-                    if (!(msg.obj instanceof Bundle)) {
-                        Log.w(TAG, "Illegal message. Abort handling onUserDictionaryAdded.");
-                        return;
-                    }
-                    final Bundle bundle = (Bundle)msg.obj;
-                    final String originalWord = bundle.getString("originalWord");
-                    final String addedWord = bundle.getString("word");
-                    onUserDictionaryAdded(originalWord, addedWord);
-                    return;
-                default:
-                    return;
+        public CharSequence filter(CharSequence source, int start, int end,
+                Spanned dest, int dstart, int dend) {
+            if (DEBUG_UNDO) {
+                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ")");
+                Log.d(TAG, "filter: dest=" + dest + " (" + dstart + "-" + dend + ")");
             }
+            final UndoManager um = mEditor.mUndoManager;
+            if (um.isInUndo()) {
+                if (DEBUG_UNDO) Log.d(TAG, "*** skipping, currently performing undo/redo");
+                return null;
+            }
+
+            um.beginUpdate("Edit text");
+            TextModifyOperation op = um.getLastOperation(
+                    TextModifyOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
+            if (op != null) {
+                if (DEBUG_UNDO) Log.d(TAG, "Last op: range=(" + op.mRangeStart + "-" + op.mRangeEnd
+                        + "), oldText=" + op.mOldText);
+                // See if we can continue modifying this operation.
+                if (op.mOldText == null) {
+                    // The current operation is an add...  are we adding more?  We are adding
+                    // more if we are either appending new text to the end of the last edit or
+                    // completely replacing some or all of the last edit.
+                    if (start < end && ((dstart >= op.mRangeStart && dend <= op.mRangeEnd)
+                            || (dstart == op.mRangeEnd && dend == op.mRangeEnd))) {
+                        op.mRangeEnd = dstart + (end-start);
+                        um.endUpdate();
+                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, mRangeEnd="
+                                + op.mRangeEnd);
+                        return null;
+                    }
+                } else {
+                    // The current operation is a delete...  can we delete more?
+                    if (start == end && dend == op.mRangeStart-1) {
+                        SpannableStringBuilder str;
+                        if (op.mOldText instanceof SpannableString) {
+                            str = (SpannableStringBuilder)op.mOldText;
+                        } else {
+                            str = new SpannableStringBuilder(op.mOldText);
+                        }
+                        str.insert(0, dest, dstart, dend);
+                        op.mRangeStart = dstart;
+                        op.mOldText = str;
+                        um.endUpdate();
+                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, range=("
+                                + op.mRangeStart + "-" + op.mRangeEnd
+                                + "), oldText=" + op.mOldText);
+                        return null;
+                    }
+                }
+
+                // Couldn't add to the current undo operation, need to start a new
+                // undo state for a new undo operation.
+                um.commitState(null);
+                um.setUndoLabel("Edit text");
+            }
+
+            // Create a new undo state reflecting the operation being performed.
+            op = new TextModifyOperation(mEditor.mUndoOwner);
+            op.mRangeStart = dstart;
+            if (start < end) {
+                op.mRangeEnd = dstart + (end-start);
+            } else {
+                op.mRangeEnd = dstart;
+            }
+            if (dstart < dend) {
+                op.mOldText = dest.subSequence(dstart, dend);
+            }
+            if (DEBUG_UNDO) Log.d(TAG, "*** adding new op, range=(" + op.mRangeStart
+                    + "-" + op.mRangeEnd + "), oldText=" + op.mOldText);
+            um.addOperation(op, UndoManager.MERGE_MODE_NONE);
+            um.endUpdate();
+            return null;
+        }
+    }
+
+    public static class TextModifyOperation extends UndoOperation<TextView> {
+        int mRangeStart, mRangeEnd;
+        CharSequence mOldText;
+
+        public TextModifyOperation(UndoOwner owner) {
+            super(owner);
         }
 
-        private void onUserDictionaryAdded(String originalWord, String addedWord) {
-            if (TextUtils.isEmpty(mOriginalWord) || TextUtils.isEmpty(addedWord)) {
-                return;
-            }
-            if (mWordStart < 0 || mWordEnd >= mTextView.length()) {
-                return;
-            }
-            if (!mOriginalWord.equals(originalWord)) {
-                return;
-            }
-            if (originalWord.equals(addedWord)) {
-                return;
-            }
-            final Editable editable = (Editable) mTextView.getText();
-            final String currentWord = editable.toString().substring(mWordStart, mWordEnd);
-            if (!currentWord.equals(originalWord)) {
-                return;
-            }
-            mTextView.replaceText_internal(mWordStart, mWordEnd, addedWord);
-            // Move cursor at the end of the replaced word
-            final int newCursorPosition = mWordStart + addedWord.length();
-            mTextView.setCursorPosition_internal(newCursorPosition, newCursorPosition);
+        public TextModifyOperation(Parcel src, ClassLoader loader) {
+            super(src, loader);
+            mRangeStart = src.readInt();
+            mRangeEnd = src.readInt();
+            mOldText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
         }
+
+        @Override
+        public void commit() {
+        }
+
+        @Override
+        public void undo() {
+            swapText();
+        }
+
+        @Override
+        public void redo() {
+            swapText();
+        }
+
+        private void swapText() {
+            // Both undo and redo involves swapping the contents of the range
+            // in the text view with our local text.
+            TextView tv = getOwnerData();
+            Editable editable = (Editable)tv.getText();
+            CharSequence curText;
+            if (mRangeStart >= mRangeEnd) {
+                curText = null;
+            } else {
+                curText = editable.subSequence(mRangeStart, mRangeEnd);
+            }
+            if (DEBUG_UNDO) {
+                Log.d(TAG, "Swap: range=(" + mRangeStart + "-" + mRangeEnd
+                        + "), oldText=" + mOldText);
+                Log.d(TAG, "Swap: curText=" + curText);
+            }
+            if (mOldText == null) {
+                editable.delete(mRangeStart, mRangeEnd);
+                mRangeEnd = mRangeStart;
+            } else {
+                editable.replace(mRangeStart, mRangeEnd, mOldText);
+                mRangeEnd = mRangeStart + mOldText.length();
+            }
+            mOldText = curText;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mRangeStart);
+            dest.writeInt(mRangeEnd);
+            TextUtils.writeToParcel(mOldText, dest, flags);
+        }
+
+        public static final Parcelable.ClassLoaderCreator<TextModifyOperation> CREATOR
+                = new Parcelable.ClassLoaderCreator<TextModifyOperation>() {
+            public TextModifyOperation createFromParcel(Parcel in) {
+                return new TextModifyOperation(in, null);
+            }
+
+            public TextModifyOperation createFromParcel(Parcel in, ClassLoader loader) {
+                return new TextModifyOperation(in, loader);
+            }
+
+            public TextModifyOperation[] newArray(int size) {
+                return new TextModifyOperation[size];
+            }
+        };
     }
 }
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 10b8cbe..e2f6d7d 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -16,47 +16,66 @@
 
 package android.widget;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.NinePatchDrawable;
-import android.os.Handler;
-import android.os.SystemClock;
+import android.os.Build;
+import android.text.TextUtils.TruncateAt;
+import android.util.IntProperty;
+import android.util.MathUtils;
+import android.util.Property;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.ViewConfiguration;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroupOverlay;
 import android.widget.AbsListView.OnScrollListener;
 
+import com.android.internal.R;
+
 /**
  * Helper class for AbsListView to draw and control the Fast Scroll thumb
  */
 class FastScroller {
-    private static final String TAG = "FastScroller";
-   
-    // Minimum number of pages to justify showing a fast scroll thumb
-    private static int MIN_PAGES = 4;
-    // Scroll thumb not showing
+    /** Duration of fade-out animation. */
+    private static final int DURATION_FADE_OUT = 300;
+
+    /** Duration of fade-in animation. */
+    private static final int DURATION_FADE_IN = 150;
+
+    /** Duration of transition cross-fade animation. */
+    private static final int DURATION_CROSS_FADE = 50;
+
+    /** Duration of transition resize animation. */
+    private static final int DURATION_RESIZE = 100;
+
+    /** Inactivity timeout before fading controls. */
+    private static final long FADE_TIMEOUT = 1500;
+
+    /** Minimum number of pages to justify showing a fast scroll thumb. */
+    private static final int MIN_PAGES = 4;
+
+    /** Scroll thumb and preview not showing. */
     private static final int STATE_NONE = 0;
-    // Not implemented yet - fade-in transition
-    private static final int STATE_ENTER = 1;
-    // Scroll thumb visible and moving along with the scrollbar
-    private static final int STATE_VISIBLE = 2;
-    // Scroll thumb being dragged by user
-    private static final int STATE_DRAGGING = 3;
-    // Scroll thumb fading out due to inactivity timeout
-    private static final int STATE_EXIT = 4;
 
-    private static final int[] PRESSED_STATES = new int[] {
-        android.R.attr.state_pressed
-    };
+    /** Scroll thumb visible and moving along with the scrollbar. */
+    private static final int STATE_VISIBLE = 1;
 
-    private static final int[] DEFAULT_STATES = new int[0];
+    /** Scroll thumb and preview being dragged by user. */
+    private static final int STATE_DRAGGING = 2;
 
+    /** Styleable attributes. */
     private static final int[] ATTRS = new int[] {
         android.R.attr.fastScrollTextColor,
         android.R.attr.fastScrollThumbDrawable,
@@ -66,6 +85,7 @@
         android.R.attr.fastScrollOverlayPosition
     };
 
+    // Styleable attribute indices.
     private static final int TEXT_COLOR = 0;
     private static final int THUMB_DRAWABLE = 1;
     private static final int TRACK_DRAWABLE = 2;
@@ -73,111 +93,317 @@
     private static final int PREVIEW_BACKGROUND_RIGHT = 4;
     private static final int OVERLAY_POSITION = 5;
 
+    // Positions for preview image and text.
     private static final int OVERLAY_FLOATING = 0;
     private static final int OVERLAY_AT_THUMB = 1;
-    
-    private Drawable mThumbDrawable;
-    private Drawable mOverlayDrawable;
-    private Drawable mTrackDrawable;
 
-    private Drawable mOverlayDrawableLeft;
-    private Drawable mOverlayDrawableRight;
+    // Indices for mPreviewResId.
+    private static final int PREVIEW_LEFT = 0;
+    private static final int PREVIEW_RIGHT = 1;
 
-    int mThumbH;
-    int mThumbW;
-    int mThumbY;
+    /** Delay before considering a tap in the thumb area to be a drag. */
+    private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
 
-    private RectF mOverlayPos;
-    private int mOverlaySize;
+    private final Rect mTempBounds = new Rect();
+    private final Rect mTempMargins = new Rect();
+    private final Rect mContainerRect = new Rect();
 
-    AbsListView mList;
-    boolean mScrollCompleted;
-    private int mVisibleItem;
-    private Paint mPaint;
-    private int mListOffset;
-    private int mItemCount = -1;
+    private final AbsListView mList;
+    private final ViewGroupOverlay mOverlay;
+    private final TextView mPrimaryText;
+    private final TextView mSecondaryText;
+    private final ImageView mThumbImage;
+    private final ImageView mTrackImage;
+    private final ImageView mPreviewImage;
+
+    /**
+     * Preview image resource IDs for left- and right-aligned layouts. See
+     * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}.
+     */
+    private final int[] mPreviewResId = new int[2];
+
+    /**
+     * Padding in pixels around the preview text. Applied as layout margins to
+     * the preview text and padding to the preview image.
+     */
+    private final int mPreviewPadding;
+
+    /** Whether there is a track image to display. */
+    private final boolean mHasTrackImage;
+
+    /** Total width of decorations. */
+    private final int mWidth;
+
+    /** Set containing decoration transition animations. */
+    private AnimatorSet mDecorAnimation;
+
+    /** Set containing preview text transition animations. */
+    private AnimatorSet mPreviewAnimation;
+
+    /** Whether the primary text is showing. */
+    private boolean mShowingPrimary;
+
+    /** Whether we're waiting for completion of scrollTo(). */
+    private boolean mScrollCompleted;
+
+    /** The position of the first visible item in the list. */
+    private int mFirstVisibleItem;
+
+    /** The number of headers at the top of the view. */
+    private int mHeaderCount;
+
+    /** The index of the current section. */
+    private int mCurrentSection = -1;
+
+    /** The current scrollbar position. */
+    private int mScrollbarPosition = -1;
+
+    /** Whether the list is long enough to need a fast scroller. */
     private boolean mLongList;
-    
-    private Object [] mSections;
-    private String mSectionText;
-    private boolean mDrawOverlay;
-    private ScrollFade mScrollFade;
-    
+
+    private Object[] mSections;
+
+    /** Whether this view is currently performing layout. */
+    private boolean mUpdatingLayout;
+
+    /**
+     * Current decoration state, one of:
+     * <ul>
+     * <li>{@link #STATE_NONE}, nothing visible
+     * <li>{@link #STATE_VISIBLE}, showing track and thumb
+     * <li>{@link #STATE_DRAGGING}, visible and showing preview
+     * </ul>
+     */
     private int mState;
-    
-    private Handler mHandler = new Handler();
-    
-    BaseAdapter mListAdapter;
+
+    private BaseAdapter mListAdapter;
     private SectionIndexer mSectionIndexer;
 
-    private boolean mChangedBounds;
-    
-    private int mPosition;
+    /** Whether decorations should be laid out from right to left. */
+    private boolean mLayoutFromRight;
 
+    /** Whether the fast scroller is enabled. */
+    private boolean mEnabled;
+
+    /** Whether the scrollbar and decorations should always be shown. */
     private boolean mAlwaysShow;
 
+    /**
+     * Position for the preview image and text. One of:
+     * <ul>
+     * <li>{@link #OVERLAY_AT_THUMB}
+     * <li>{@link #OVERLAY_FLOATING}
+     * </ul>
+     */
     private int mOverlayPosition;
 
+    /** Current scrollbar style, including inset and overlay properties. */
+    private int mScrollBarStyle;
+
+    /** Whether to precisely match the thumb position to the list. */
     private boolean mMatchDragPosition;
 
-    float mInitialTouchY;
-    boolean mPendingDrag;
+    private float mInitialTouchY;
+    private boolean mHasPendingDrag;
     private int mScaledTouchSlop;
 
-    private static final int FADE_TIMEOUT = 1500;
-    private static final int PENDING_DRAG_DELAY = 180;
-
-    private final Rect mTmpRect = new Rect();
-
     private final Runnable mDeferStartDrag = new Runnable() {
+        @Override
         public void run() {
-            if (mList.mIsAttached) {
+            if (mList.isAttachedToWindow()) {
                 beginDrag();
 
-                final int viewHeight = mList.getHeight();
-                // Jitter
-                int newThumbY = (int) mInitialTouchY - mThumbH + 10;
-                if (newThumbY < 0) {
-                    newThumbY = 0;
-                } else if (newThumbY + mThumbH > viewHeight) {
-                    newThumbY = viewHeight - mThumbH;
-                }
-                mThumbY = newThumbY;
-                scrollTo((float) mThumbY / (viewHeight - mThumbH));
+                final float pos = getPosFromMotionEvent(mInitialTouchY);
+                scrollTo(pos);
             }
 
-            mPendingDrag = false;
+            mHasPendingDrag = false;
         }
     };
 
-    public FastScroller(Context context, AbsListView listView) {
+    /**
+     * Used to delay hiding fast scroll decorations.
+     */
+    private final Runnable mDeferHide = new Runnable() {
+        @Override
+        public void run() {
+            setState(STATE_NONE);
+        }
+    };
+
+    /**
+     * Used to effect a transition from primary to secondary text.
+     */
+    private final AnimatorListener mSwitchPrimaryListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mShowingPrimary = !mShowingPrimary;
+        }
+    };
+
+    public FastScroller(AbsListView listView) {
         mList = listView;
-        init(context);
+        mOverlay = listView.getOverlay();
+
+        final Context context = listView.getContext();
+        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+
+        final Resources res = context.getResources();
+        final TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS);
+
+        final ImageView trackImage = new ImageView(context);
+        mTrackImage = trackImage;
+
+        int width = 0;
+
+        // Add track to overlay if it has an image.
+        final Drawable trackDrawable = ta.getDrawable(TRACK_DRAWABLE);
+        if (trackDrawable != null) {
+            mHasTrackImage = true;
+            trackImage.setBackground(trackDrawable);
+            mOverlay.add(trackImage);
+            width = Math.max(width, trackDrawable.getIntrinsicWidth());
+        } else {
+            mHasTrackImage = false;
+        }
+
+        final ImageView thumbImage = new ImageView(context);
+        mThumbImage = thumbImage;
+
+        // Add thumb to overlay if it has an image.
+        final Drawable thumbDrawable = ta.getDrawable(THUMB_DRAWABLE);
+        if (thumbDrawable != null) {
+            thumbImage.setImageDrawable(thumbDrawable);
+            mOverlay.add(thumbImage);
+            width = Math.max(width, thumbDrawable.getIntrinsicWidth());
+        }
+
+        // If necessary, apply minimum thumb width and height.
+        if (thumbDrawable.getIntrinsicWidth() <= 0 || thumbDrawable.getIntrinsicHeight() <= 0) {
+            final int minWidth = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width);
+            thumbImage.setMinimumWidth(minWidth);
+            thumbImage.setMinimumHeight(
+                    res.getDimensionPixelSize(R.dimen.fastscroll_thumb_height));
+            width = Math.max(width, minWidth);
+        }
+
+        mWidth = width;
+
+        final int previewSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size);
+        mPreviewImage = new ImageView(context);
+        mPreviewImage.setMinimumWidth(previewSize);
+        mPreviewImage.setMinimumHeight(previewSize);
+        mPreviewImage.setAlpha(0f);
+        mOverlay.add(mPreviewImage);
+
+        mPreviewPadding = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_padding);
+
+        final int textMinSize = Math.max(0, previewSize - mPreviewPadding);
+        mPrimaryText = createPreviewTextView(context, ta);
+        mPrimaryText.setMinimumWidth(textMinSize);
+        mPrimaryText.setMinimumHeight(textMinSize);
+        mOverlay.add(mPrimaryText);
+        mSecondaryText = createPreviewTextView(context, ta);
+        mSecondaryText.setMinimumWidth(textMinSize);
+        mSecondaryText.setMinimumHeight(textMinSize);
+        mOverlay.add(mSecondaryText);
+
+        mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(PREVIEW_BACKGROUND_LEFT, 0);
+        mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(PREVIEW_BACKGROUND_RIGHT, 0);
+        mOverlayPosition = ta.getInt(OVERLAY_POSITION, OVERLAY_FLOATING);
+        ta.recycle();
+
+        mScrollBarStyle = listView.getScrollBarStyle();
+        mScrollCompleted = true;
+        mState = STATE_VISIBLE;
+        mMatchDragPosition = context.getApplicationInfo().targetSdkVersion
+                >= Build.VERSION_CODES.HONEYCOMB;
+
+        getSectionsFromIndexer();
+        refreshDrawablePressedState();
+        updateLongList(listView.getChildCount(), listView.getCount());
+        setScrollbarPosition(mList.getVerticalScrollbarPosition());
+        postAutoHide();
     }
 
-    public void setAlwaysShow(boolean alwaysShow) {
-        mAlwaysShow = alwaysShow;
-        if (alwaysShow) {
-            mHandler.removeCallbacks(mScrollFade);
-            setState(STATE_VISIBLE);
-        } else if (mState == STATE_VISIBLE) {
-            mHandler.postDelayed(mScrollFade, FADE_TIMEOUT);
+    /**
+     * Removes this FastScroller overlay from the host view.
+     */
+    public void remove() {
+        mOverlay.remove(mTrackImage);
+        mOverlay.remove(mThumbImage);
+        mOverlay.remove(mPreviewImage);
+        mOverlay.remove(mPrimaryText);
+        mOverlay.remove(mSecondaryText);
+    }
+
+    /**
+     * @param enabled Whether the fast scroll thumb is enabled.
+     */
+    public void setEnabled(boolean enabled) {
+        if (mEnabled != enabled) {
+            mEnabled = enabled;
+
+            onStateDependencyChanged();
         }
     }
 
+    /**
+     * @return Whether the fast scroll thumb is enabled.
+     */
+    public boolean isEnabled() {
+        return mEnabled && (mLongList || mAlwaysShow);
+    }
+
+    /**
+     * @param alwaysShow Whether the fast scroll thumb should always be shown
+     */
+    public void setAlwaysShow(boolean alwaysShow) {
+        if (mAlwaysShow != alwaysShow) {
+            mAlwaysShow = alwaysShow;
+
+            onStateDependencyChanged();
+        }
+    }
+
+    /**
+     * @return Whether the fast scroll thumb will always be shown
+     * @see #setAlwaysShow(boolean)
+     */
     public boolean isAlwaysShowEnabled() {
         return mAlwaysShow;
     }
 
-    private void refreshDrawableState() {
-        int[] state = mState == STATE_DRAGGING ? PRESSED_STATES : DEFAULT_STATES;
+    /**
+     * Called when one of the variables affecting enabled state changes.
+     */
+    private void onStateDependencyChanged() {
+        if (isEnabled()) {
+            if (isAlwaysShowEnabled()) {
+                setState(STATE_VISIBLE);
+            } else if (mState == STATE_VISIBLE) {
+                postAutoHide();
+            }
+        } else {
+            stop();
+        }
 
-        if (mThumbDrawable != null && mThumbDrawable.isStateful()) {
-            mThumbDrawable.setState(state);
+        mList.resolvePadding();
+    }
+
+    public void setScrollBarStyle(int style) {
+        if (mScrollBarStyle != style) {
+            mScrollBarStyle = style;
+
+            updateLayout();
         }
-        if (mTrackDrawable != null && mTrackDrawable.isStateful()) {
-            mTrackDrawable.setState(state);
-        }
+    }
+
+    /**
+     * Immediately transitions the fast scroller decorations to a hidden state.
+     */
+    public void stop() {
+        setState(STATE_NONE);
     }
 
     public void setScrollbarPosition(int position) {
@@ -185,362 +411,459 @@
             position = mList.isLayoutRtl() ?
                     View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT;
         }
-        mPosition = position;
-        switch (position) {
-            default:
-            case View.SCROLLBAR_POSITION_RIGHT:
-                mOverlayDrawable = mOverlayDrawableRight;
-                break;
-            case View.SCROLLBAR_POSITION_LEFT:
-                mOverlayDrawable = mOverlayDrawableLeft;
-                break;
+
+        if (mScrollbarPosition != position) {
+            mScrollbarPosition = position;
+            mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT;
+
+            final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT];
+            mPreviewImage.setBackgroundResource(previewResId);
+
+            // Add extra padding for text.
+            final Drawable background = mPreviewImage.getBackground();
+            if (background != null) {
+                final Rect padding = mTempBounds;
+                background.getPadding(padding);
+                padding.offset(mPreviewPadding, mPreviewPadding);
+                mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+            }
+
+            // Requires re-layout.
+            updateLayout();
         }
     }
 
     public int getWidth() {
-        return mThumbW;
+        return mWidth;
     }
 
-    public void setState(int state) {
+    public void onSizeChanged(int w, int h, int oldw, int oldh) {
+        updateLayout();
+    }
+
+    public void onItemCountChanged(int oldTotalItemCount, int totalItemCount) {
+        final int visibleItemCount = mList.getChildCount();
+        final boolean hasMoreItems = totalItemCount - visibleItemCount > 0;
+        if (hasMoreItems && mState != STATE_DRAGGING) {
+            final int firstVisibleItem = mList.getFirstVisiblePosition();
+            setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount));
+        }
+
+        updateLongList(visibleItemCount, totalItemCount);
+    }
+
+    private void updateLongList(int visibleItemCount, int totalItemCount) {
+        final boolean longList = visibleItemCount > 0
+                && totalItemCount / visibleItemCount >= MIN_PAGES;
+        if (mLongList != longList) {
+            mLongList = longList;
+
+            onStateDependencyChanged();
+        }
+    }
+
+    /**
+     * Creates a view into which preview text can be placed.
+     */
+    private TextView createPreviewTextView(Context context, TypedArray ta) {
+        final LayoutParams params = new LayoutParams(
+                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+        final Resources res = context.getResources();
+        final int minSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size);
+        final ColorStateList textColor = ta.getColorStateList(TEXT_COLOR);
+        final float textSize = res.getDimension(R.dimen.fastscroll_overlay_text_size);
+        final TextView textView = new TextView(context);
+        textView.setLayoutParams(params);
+        textView.setTextColor(textColor);
+        textView.setTextSize(textSize);
+        textView.setSingleLine(true);
+        textView.setEllipsize(TruncateAt.MIDDLE);
+        textView.setGravity(Gravity.CENTER);
+        textView.setAlpha(0f);
+
+        // Manually propagate inherited layout direction.
+        textView.setLayoutDirection(mList.getLayoutDirection());
+
+        return textView;
+    }
+
+    /**
+     * Measures and layouts the scrollbar and decorations.
+     */
+    public void updateLayout() {
+        // Prevent re-entry when RTL properties change as a side-effect of
+        // resolving padding.
+        if (mUpdatingLayout) {
+            return;
+        }
+
+        mUpdatingLayout = true;
+
+        updateContainerRect();
+
+        layoutThumb();
+        layoutTrack();
+
+        final Rect bounds = mTempBounds;
+        measurePreview(mPrimaryText, bounds);
+        applyLayout(mPrimaryText, bounds);
+        measurePreview(mSecondaryText, bounds);
+        applyLayout(mSecondaryText, bounds);
+
+        if (mPreviewImage != null) {
+            // Apply preview image padding.
+            bounds.left -= mPreviewImage.getPaddingLeft();
+            bounds.top -= mPreviewImage.getPaddingTop();
+            bounds.right += mPreviewImage.getPaddingRight();
+            bounds.bottom += mPreviewImage.getPaddingBottom();
+            applyLayout(mPreviewImage, bounds);
+        }
+
+        mUpdatingLayout = false;
+    }
+
+    /**
+     * Layouts a view within the specified bounds and pins the pivot point to
+     * the appropriate edge.
+     *
+     * @param view The view to layout.
+     * @param bounds Bounds at which to layout the view.
+     */
+    private void applyLayout(View view, Rect bounds) {
+        view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        view.setPivotX(mLayoutFromRight ? bounds.right - bounds.left : 0);
+    }
+
+    /**
+     * Measures the preview text bounds, taking preview image padding into
+     * account. This method should only be called after {@link #layoutThumb()}
+     * and {@link #layoutTrack()} have both been called at least once.
+     *
+     * @param v The preview text view to measure.
+     * @param out Rectangle into which measured bounds are placed.
+     */
+    private void measurePreview(View v, Rect out) {
+        // Apply the preview image's padding as layout margins.
+        final Rect margins = mTempMargins;
+        margins.left = mPreviewImage.getPaddingLeft();
+        margins.top = mPreviewImage.getPaddingTop();
+        margins.right = mPreviewImage.getPaddingRight();
+        margins.bottom = mPreviewImage.getPaddingBottom();
+
+        if (mOverlayPosition == OVERLAY_AT_THUMB) {
+            measureViewToSide(v, mThumbImage, margins, out);
+        } else {
+            measureFloating(v, margins, out);
+        }
+    }
+
+    /**
+     * Measures the bounds for a view that should be laid out against the edge
+     * of an adjacent view. If no adjacent view is provided, lays out against
+     * the list edge.
+     *
+     * @param view The view to measure for layout.
+     * @param adjacent (Optional) The adjacent view, may be null to align to the
+     *            list edge.
+     * @param margins Layout margins to apply to the view.
+     * @param out Rectangle into which measured bounds are placed.
+     */
+    private void measureViewToSide(View view, View adjacent, Rect margins, Rect out) {
+        final int marginLeft;
+        final int marginTop;
+        final int marginRight;
+        if (margins == null) {
+            marginLeft = 0;
+            marginTop = 0;
+            marginRight = 0;
+        } else {
+            marginLeft = margins.left;
+            marginTop = margins.top;
+            marginRight = margins.right;
+        }
+
+        final Rect container = mContainerRect;
+        final int containerWidth = container.width();
+        final int maxWidth;
+        if (adjacent == null) {
+            maxWidth = containerWidth;
+        } else if (mLayoutFromRight) {
+            maxWidth = adjacent.getLeft();
+        } else {
+            maxWidth = containerWidth - adjacent.getRight();
+        }
+
+        final int adjMaxWidth = maxWidth - marginLeft - marginRight;
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        view.measure(widthMeasureSpec, heightMeasureSpec);
+
+        // Align to the left or right.
+        final int width = view.getMeasuredWidth();
+        final int left;
+        final int right;
+        if (mLayoutFromRight) {
+            right = (adjacent == null ? container.right : adjacent.getLeft()) - marginRight;
+            left = right - width;
+        } else {
+            left = (adjacent == null ? container.left : adjacent.getRight()) + marginLeft;
+            right = left + width;
+        }
+
+        // Don't adjust the vertical position.
+        final int top = marginTop;
+        final int bottom = top + view.getMeasuredHeight();
+        out.set(left, top, right, bottom);
+    }
+
+    private void measureFloating(View preview, Rect margins, Rect out) {
+        final int marginLeft;
+        final int marginTop;
+        final int marginRight;
+        if (margins == null) {
+            marginLeft = 0;
+            marginTop = 0;
+            marginRight = 0;
+        } else {
+            marginLeft = margins.left;
+            marginTop = margins.top;
+            marginRight = margins.right;
+        }
+
+        final Rect container = mContainerRect;
+        final int containerWidth = container.width();
+        final int adjMaxWidth = containerWidth - marginLeft - marginRight;
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        preview.measure(widthMeasureSpec, heightMeasureSpec);
+
+        // Align at the vertical center, 10% from the top.
+        final int containerHeight = container.height();
+        final int width = preview.getMeasuredWidth();
+        final int top = containerHeight / 10 + marginTop + container.top;
+        final int bottom = top + preview.getMeasuredHeight();
+        final int left = (containerWidth - width) / 2 + container.left;
+        final int right = left + width;
+        out.set(left, top, right, bottom);
+    }
+
+    /**
+     * Updates the container rectangle used for layout.
+     */
+    private void updateContainerRect() {
+        final AbsListView list = mList;
+        list.resolvePadding();
+
+        final Rect container = mContainerRect;
+        container.left = 0;
+        container.top = 0;
+        container.right = list.getWidth();
+        container.bottom = list.getHeight();
+
+        final int scrollbarStyle = mScrollBarStyle;
+        if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET
+                || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) {
+            container.left += list.getPaddingLeft();
+            container.top += list.getPaddingTop();
+            container.right -= list.getPaddingRight();
+            container.bottom -= list.getPaddingBottom();
+
+            // In inset mode, we need to adjust for padded scrollbar width.
+            if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) {
+                final int width = getWidth();
+                if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) {
+                    container.right += width;
+                } else {
+                    container.left -= width;
+                }
+            }
+        }
+    }
+
+    /**
+     * Lays out the thumb according to the current scrollbar position.
+     */
+    private void layoutThumb() {
+        final Rect bounds = mTempBounds;
+        measureViewToSide(mThumbImage, null, null, bounds);
+        applyLayout(mThumbImage, bounds);
+    }
+
+    /**
+     * Lays out the track centered on the thumb. Must be called after
+     * {@link #layoutThumb}.
+     */
+    private void layoutTrack() {
+        final View track = mTrackImage;
+        final View thumb = mThumbImage;
+        final Rect container = mContainerRect;
+        final int containerWidth = container.width();
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(containerWidth, MeasureSpec.AT_MOST);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        track.measure(widthMeasureSpec, heightMeasureSpec);
+
+        final int trackWidth = track.getMeasuredWidth();
+        final int thumbHalfHeight = thumb == null ? 0 : thumb.getHeight() / 2;
+        final int left = thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2;
+        final int right = left + trackWidth;
+        final int top = container.top + thumbHalfHeight;
+        final int bottom = container.bottom - thumbHalfHeight;
+        track.layout(left, top, right, bottom);
+    }
+
+    private void setState(int state) {
+        mList.removeCallbacks(mDeferHide);
+
+        if (mAlwaysShow && state == STATE_NONE) {
+            state = STATE_VISIBLE;
+        }
+
+        if (state == mState) {
+            return;
+        }
+
         switch (state) {
             case STATE_NONE:
-                mHandler.removeCallbacks(mScrollFade);
-                mList.invalidate();
+                transitionToHidden();
                 break;
             case STATE_VISIBLE:
-                if (mState != STATE_VISIBLE) { // Optimization
-                    resetThumbPos();
-                }
-                // Fall through
+                transitionToVisible();
+                break;
             case STATE_DRAGGING:
-                mHandler.removeCallbacks(mScrollFade);
-                break;
-            case STATE_EXIT:
-                final int viewWidth = mList.getWidth();
-                final int top = mThumbY;
-                final int bottom = mThumbY + mThumbH;
-                final int left;
-                final int right;
-                switch (mList.getLayoutDirection()) {
-                    case View.LAYOUT_DIRECTION_RTL:
-                        left = 0;
-                        right = mThumbW;
-                        break;
-                    case View.LAYOUT_DIRECTION_LTR:
-                    default:
-                        left = viewWidth - mThumbW;
-                        right = viewWidth;
-                }
-                mList.invalidate(left, top, right, bottom);
-                break;
-        }
-        mState = state;
-        refreshDrawableState();
-    }
-    
-    public int getState() {
-        return mState;
-    }
-    
-    private void resetThumbPos() {
-        final int viewWidth = mList.getWidth();
-        // Bounds are always top right. Y coordinate get's translated during draw
-        switch (mPosition) {
-            case View.SCROLLBAR_POSITION_RIGHT:
-                mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH);
-                break;
-            case View.SCROLLBAR_POSITION_LEFT:
-                mThumbDrawable.setBounds(0, 0, mThumbW, mThumbH);
-                break;
-        }
-        mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX);
-    }
-    
-    private void useThumbDrawable(Context context, Drawable drawable) {
-        mThumbDrawable = drawable;
-        if (drawable instanceof NinePatchDrawable) {
-            mThumbW = context.getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.fastscroll_thumb_width);
-            mThumbH = context.getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.fastscroll_thumb_height);
-        } else {
-            mThumbW = drawable.getIntrinsicWidth();
-            mThumbH = drawable.getIntrinsicHeight();
-        }
-        mChangedBounds = true;
-    }
-
-    private void init(Context context) {
-        // Get both the scrollbar states drawables
-        TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS);
-        useThumbDrawable(context, ta.getDrawable(THUMB_DRAWABLE));
-        mTrackDrawable = ta.getDrawable(TRACK_DRAWABLE);
-        
-        mOverlayDrawableLeft = ta.getDrawable(PREVIEW_BACKGROUND_LEFT);
-        mOverlayDrawableRight = ta.getDrawable(PREVIEW_BACKGROUND_RIGHT);
-        mOverlayPosition = ta.getInt(OVERLAY_POSITION, OVERLAY_FLOATING);
-        
-        mScrollCompleted = true;
-
-        getSectionsFromIndexer();
-
-        mOverlaySize = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.fastscroll_overlay_size);
-        mOverlayPos = new RectF();
-        mScrollFade = new ScrollFade();
-        mPaint = new Paint();
-        mPaint.setAntiAlias(true);
-        mPaint.setTextAlign(Paint.Align.CENTER);
-        mPaint.setTextSize(mOverlaySize / 2);
-
-        ColorStateList textColor = ta.getColorStateList(TEXT_COLOR);
-        int textColorNormal = textColor.getDefaultColor();
-        mPaint.setColor(textColorNormal);
-        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
-        // to show mOverlayDrawable properly
-        if (mList.getWidth() > 0 && mList.getHeight() > 0) {
-            onSizeChanged(mList.getWidth(), mList.getHeight(), 0, 0);
-        }
-        
-        mState = STATE_NONE;
-        refreshDrawableState();
-
-        ta.recycle();
-
-        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-
-        mMatchDragPosition = context.getApplicationInfo().targetSdkVersion >=
-                android.os.Build.VERSION_CODES.HONEYCOMB;
-
-        setScrollbarPosition(mList.getVerticalScrollbarPosition());
-    }
-    
-    void stop() {
-        setState(STATE_NONE);
-    }
-    
-    boolean isVisible() {
-        return !(mState == STATE_NONE);
-    }
-    
-    public void draw(Canvas canvas) {
-        
-        if (mState == STATE_NONE) {
-            // No need to draw anything
-            return;
-        }
-
-        final int y = mThumbY;
-        final int viewWidth = mList.getWidth();
-        final FastScroller.ScrollFade scrollFade = mScrollFade;
-
-        int alpha = -1;
-        if (mState == STATE_EXIT) {
-            alpha = scrollFade.getAlpha();
-            if (alpha < ScrollFade.ALPHA_MAX / 2) {
-                mThumbDrawable.setAlpha(alpha * 2);
-            }
-            int left = 0;
-            switch (mPosition) {
-                case View.SCROLLBAR_POSITION_RIGHT:
-                    left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX;
-                    break;
-                case View.SCROLLBAR_POSITION_LEFT:
-                    left = -mThumbW + (mThumbW * alpha) / ScrollFade.ALPHA_MAX;
-                    break;
-            }
-            mThumbDrawable.setBounds(left, 0, left + mThumbW, mThumbH);
-            mChangedBounds = true;
-        }
-
-        if (mTrackDrawable != null) {
-            final Rect thumbBounds = mThumbDrawable.getBounds();
-            final int left = thumbBounds.left;
-            final int halfThumbHeight = (thumbBounds.bottom - thumbBounds.top) / 2;
-            final int trackWidth = mTrackDrawable.getIntrinsicWidth();
-            final int trackLeft = (left + mThumbW / 2) - trackWidth / 2;
-            mTrackDrawable.setBounds(trackLeft, halfThumbHeight,
-                    trackLeft + trackWidth, mList.getHeight() - halfThumbHeight);
-            mTrackDrawable.draw(canvas);
-        }
-
-        canvas.translate(0, y);
-        mThumbDrawable.draw(canvas);
-        canvas.translate(0, -y);
-
-        // If user is dragging the scroll bar, draw the alphabet overlay
-        if (mState == STATE_DRAGGING && mDrawOverlay) {
-            if (mOverlayPosition == OVERLAY_AT_THUMB) {
-                int left = 0;
-                switch (mPosition) {
-                    default:
-                    case View.SCROLLBAR_POSITION_RIGHT:
-                        left = Math.max(0,
-                                mThumbDrawable.getBounds().left - mThumbW - mOverlaySize);
-                        break;
-                    case View.SCROLLBAR_POSITION_LEFT:
-                        left = Math.min(mThumbDrawable.getBounds().right + mThumbW,
-                                mList.getWidth() - mOverlaySize);
-                        break;
-                }
-
-                int top = Math.max(0,
-                        Math.min(y + (mThumbH - mOverlaySize) / 2, mList.getHeight() - mOverlaySize));
-
-                final RectF pos = mOverlayPos;
-                pos.left = left;
-                pos.right = pos.left + mOverlaySize;
-                pos.top = top;
-                pos.bottom = pos.top + mOverlaySize;
-                if (mOverlayDrawable != null) {
-                    mOverlayDrawable.setBounds((int) pos.left, (int) pos.top,
-                            (int) pos.right, (int) pos.bottom);
-                }
-            }
-            mOverlayDrawable.draw(canvas);
-            final Paint paint = mPaint;
-            float descent = paint.descent();
-            final RectF rectF = mOverlayPos;
-            final Rect tmpRect = mTmpRect;
-            mOverlayDrawable.getPadding(tmpRect);
-            final int hOff = (tmpRect.right - tmpRect.left) / 2;
-            final int vOff = (tmpRect.bottom - tmpRect.top) / 2;
-            canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2 - hOff,
-                    (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent - vOff,
-                    paint);
-        } else if (mState == STATE_EXIT) {
-            if (alpha == 0) { // Done with exit
-                setState(STATE_NONE);
-            } else {
-                final int left, right, top, bottom;
-                if (mTrackDrawable != null) {
-                    top = 0;
-                    bottom = mList.getHeight();
+                if (transitionPreviewLayout(mCurrentSection)) {
+                    transitionToDragging();
                 } else {
-                    top = y;
-                    bottom = y + mThumbH;
+                    transitionToVisible();
                 }
-                switch (mList.getLayoutDirection()) {
-                    case View.LAYOUT_DIRECTION_RTL:
-                        left = 0;
-                        right = mThumbW;
-                        break;
-                    case View.LAYOUT_DIRECTION_LTR:
-                    default:
-                        left = viewWidth - mThumbW;
-                        right = viewWidth;
-                }
-                mList.invalidate(left, top, right, bottom);
-            }
+                break;
         }
+
+        mState = state;
+
+        refreshDrawablePressedState();
     }
 
-    void onSizeChanged(int w, int h, int oldw, int oldh) {
-        if (mThumbDrawable != null) {
-            switch (mPosition) {
-                default:
-                case View.SCROLLBAR_POSITION_RIGHT:
-                    mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH);
-                    break;
-                case View.SCROLLBAR_POSITION_LEFT:
-                    mThumbDrawable.setBounds(0, 0, mThumbW, mThumbH);
-                    break;
-            }
-        }
-        if (mOverlayPosition == OVERLAY_FLOATING) {
-            final RectF pos = mOverlayPos;
-            pos.left = (w - mOverlaySize) / 2;
-            pos.right = pos.left + mOverlaySize;
-            pos.top = h / 10; // 10% from top
-            pos.bottom = pos.top + mOverlaySize;
-            if (mOverlayDrawable != null) {
-                mOverlayDrawable.setBounds((int) pos.left, (int) pos.top,
-                        (int) pos.right, (int) pos.bottom);
-            }
-        }
+    private void refreshDrawablePressedState() {
+        final boolean isPressed = mState == STATE_DRAGGING;
+        mThumbImage.setPressed(isPressed);
+        mTrackImage.setPressed(isPressed);
     }
 
-    void onItemCountChanged(int oldCount, int newCount) {
-        if (mAlwaysShow) {
-            mLongList = true;
+    /**
+     * Shows nothing.
+     */
+    private void transitionToHidden() {
+        if (mDecorAnimation != null) {
+            mDecorAnimation.cancel();
         }
+
+        final Animator fadeOut = groupAnimatorOfFloat(View.ALPHA, 0f, mThumbImage, mTrackImage,
+                mPreviewImage, mPrimaryText, mSecondaryText).setDuration(DURATION_FADE_OUT);
+
+        // Push the thumb and track outside the list bounds.
+        final float offset = mLayoutFromRight ? mThumbImage.getWidth() : -mThumbImage.getWidth();
+        final Animator slideOut = groupAnimatorOfFloat(
+                View.TRANSLATION_X, offset, mThumbImage, mTrackImage)
+                .setDuration(DURATION_FADE_OUT);
+
+        mDecorAnimation = new AnimatorSet();
+        mDecorAnimation.playTogether(fadeOut, slideOut);
+        mDecorAnimation.start();
     }
 
-    void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 
-            int totalItemCount) {
-        // Are there enough pages to require fast scroll? Recompute only if total count changes
-        if (mItemCount != totalItemCount && visibleItemCount > 0) {
-            mItemCount = totalItemCount;
-            mLongList = mItemCount / visibleItemCount >= MIN_PAGES;
+    /**
+     * Shows the thumb and track.
+     */
+    private void transitionToVisible() {
+        if (mDecorAnimation != null) {
+            mDecorAnimation.cancel();
         }
-        if (mAlwaysShow) {
-            mLongList = true;
+
+        final Animator fadeIn = groupAnimatorOfFloat(View.ALPHA, 1f, mThumbImage, mTrackImage)
+                .setDuration(DURATION_FADE_IN);
+        final Animator fadeOut = groupAnimatorOfFloat(
+                View.ALPHA, 0f, mPreviewImage, mPrimaryText, mSecondaryText)
+                .setDuration(DURATION_FADE_OUT);
+        final Animator slideIn = groupAnimatorOfFloat(
+                View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN);
+
+        mDecorAnimation = new AnimatorSet();
+        mDecorAnimation.playTogether(fadeIn, fadeOut, slideIn);
+        mDecorAnimation.start();
+    }
+
+    /**
+     * Shows the thumb, preview, and track.
+     */
+    private void transitionToDragging() {
+        if (mDecorAnimation != null) {
+            mDecorAnimation.cancel();
         }
-        if (!mLongList) {
-            if (mState != STATE_NONE) {
-                setState(STATE_NONE);
-            }
+
+        final Animator fadeIn = groupAnimatorOfFloat(
+                View.ALPHA, 1f, mThumbImage, mTrackImage, mPreviewImage)
+                .setDuration(DURATION_FADE_IN);
+        final Animator slideIn = groupAnimatorOfFloat(
+                View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN);
+
+        mDecorAnimation = new AnimatorSet();
+        mDecorAnimation.playTogether(fadeIn, slideIn);
+        mDecorAnimation.start();
+    }
+
+    private void postAutoHide() {
+        mList.removeCallbacks(mDeferHide);
+        mList.postDelayed(mDeferHide, FADE_TIMEOUT);
+    }
+
+    public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+        if (!isEnabled()) {
+            setState(STATE_NONE);
             return;
         }
-        if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING) {
-            mThumbY = getThumbPositionForListPosition(firstVisibleItem, visibleItemCount,
-                    totalItemCount);
-            if (mChangedBounds) {
-                resetThumbPos();
-                mChangedBounds = false;
-            }
+
+        final boolean hasMoreItems = totalItemCount - visibleItemCount > 0;
+        if (hasMoreItems && mState != STATE_DRAGGING) {
+            setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount));
         }
+
         mScrollCompleted = true;
-        if (firstVisibleItem == mVisibleItem) {
-            return;
-        }
-        mVisibleItem = firstVisibleItem;
-        if (mState != STATE_DRAGGING) {
-            setState(STATE_VISIBLE);
-            if (!mAlwaysShow) {
-                mHandler.postDelayed(mScrollFade, FADE_TIMEOUT);
+
+        if (mFirstVisibleItem != firstVisibleItem) {
+            mFirstVisibleItem = firstVisibleItem;
+
+            // Show the thumb, if necessary, and set up auto-fade.
+            if (mState != STATE_DRAGGING) {
+                setState(STATE_VISIBLE);
+                postAutoHide();
             }
         }
     }
 
-    SectionIndexer getSectionIndexer() {
-        return mSectionIndexer;
-    }
-
-    Object[] getSections() {
-        if (mListAdapter == null && mList != null) {
-            getSectionsFromIndexer();
-        }
-        return mSections;
-    }
-
-    void getSectionsFromIndexer() {
-        Adapter adapter = mList.getAdapter();
+    private void getSectionsFromIndexer() {
         mSectionIndexer = null;
+
+        Adapter adapter = mList.getAdapter();
         if (adapter instanceof HeaderViewListAdapter) {
-            mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount();
-            adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();
+            mHeaderCount = ((HeaderViewListAdapter) adapter).getHeadersCount();
+            adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter();
         }
+
         if (adapter instanceof ExpandableListConnector) {
-            ExpandableListAdapter expAdapter = ((ExpandableListConnector)adapter).getAdapter();
+            final ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter)
+                    .getAdapter();
             if (expAdapter instanceof SectionIndexer) {
                 mSectionIndexer = (SectionIndexer) expAdapter;
                 mListAdapter = (BaseAdapter) adapter;
                 mSections = mSectionIndexer.getSections();
             }
+        } else if (adapter instanceof SectionIndexer) {
+            mListAdapter = (BaseAdapter) adapter;
+            mSectionIndexer = (SectionIndexer) adapter;
+            mSections = mSectionIndexer.getSections();
         } else {
-            if (adapter instanceof SectionIndexer) {
-                mListAdapter = (BaseAdapter) adapter;
-                mSectionIndexer = (SectionIndexer) adapter;
-                mSections = mSectionIndexer.getSections();
-                if (mSections == null) {
-                    mSections = new String[] { " " };
-                }
-            } else {
-                mListAdapter = (BaseAdapter) adapter;
-                mSections = new String[] { " " };
-            }
+            mListAdapter = (BaseAdapter) adapter;
+            mSections = null;
         }
     }
 
@@ -548,21 +871,24 @@
         mListAdapter = null;
     }
 
-    void scrollTo(float position) {
-        int count = mList.getCount();
+    /**
+     * Scrolls to a specific position within the section
+     * @param position
+     */
+    private void scrollTo(float position) {
         mScrollCompleted = false;
-        float fThreshold = (1.0f / count) / 8;
+
+        final int count = mList.getCount();
         final Object[] sections = mSections;
+        final int sectionCount = sections == null ? 0 : sections.length;
         int sectionIndex;
-        if (sections != null && sections.length > 1) {
-            final int nSections = sections.length;
-            int section = (int) (position * nSections);
-            if (section >= nSections) {
-                section = nSections - 1;
-            }
-            int exactSection = section;
-            sectionIndex = section;
-            int index = mSectionIndexer.getPositionForSection(section);
+        if (sections != null && sectionCount > 1) {
+            final int exactSection = MathUtils.constrain(
+                    (int) (position * sectionCount), 0, sectionCount - 1);
+            int targetSection = exactSection;
+            int targetIndex = mSectionIndexer.getPositionForSection(targetSection);
+            sectionIndex = targetSection;
+
             // Given the expected section and index, the following code will
             // try to account for missing sections (no names starting with..)
             // It will compute the scroll space of surrounding empty sections
@@ -570,25 +896,26 @@
             // available space, so that there is always some list movement while
             // the user moves the thumb.
             int nextIndex = count;
-            int prevIndex = index;
-            int prevSection = section;
-            int nextSection = section + 1;
+            int prevIndex = targetIndex;
+            int prevSection = targetSection;
+            int nextSection = targetSection + 1;
+
             // Assume the next section is unique
-            if (section < nSections - 1) {
-                nextIndex = mSectionIndexer.getPositionForSection(section + 1);
+            if (targetSection < sectionCount - 1) {
+                nextIndex = mSectionIndexer.getPositionForSection(targetSection + 1);
             }
-            
+
             // Find the previous index if we're slicing the previous section
-            if (nextIndex == index) {
+            if (nextIndex == targetIndex) {
                 // Non-existent letter
-                while (section > 0) {
-                    section--;
-                    prevIndex = mSectionIndexer.getPositionForSection(section);
-                    if (prevIndex != index) {
-                        prevSection = section;
-                        sectionIndex = section;
+                while (targetSection > 0) {
+                    targetSection--;
+                    prevIndex = mSectionIndexer.getPositionForSection(targetSection);
+                    if (prevIndex != targetIndex) {
+                        prevSection = targetSection;
+                        sectionIndex = targetSection;
                         break;
-                    } else if (section == 0) {
+                    } else if (targetSection == 0) {
                         // When section reaches 0 here, sectionIndex must follow it.
                         // Assuming mSectionIndexer.getPositionForSection(0) == 0.
                         sectionIndex = 0;
@@ -596,136 +923,305 @@
                     }
                 }
             }
+
             // Find the next index, in case the assumed next index is not
-            // unique. For instance, if there is no P, then request for P's 
+            // unique. For instance, if there is no P, then request for P's
             // position actually returns Q's. So we need to look ahead to make
-            // sure that there is really a Q at Q's position. If not, move 
+            // sure that there is really a Q at Q's position. If not, move
             // further down...
             int nextNextSection = nextSection + 1;
-            while (nextNextSection < nSections &&
+            while (nextNextSection < sectionCount &&
                     mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) {
                 nextNextSection++;
                 nextSection++;
             }
+
             // Compute the beginning and ending scroll range percentage of the
-            // currently visible letter. This could be equal to or greater than
-            // (1 / nSections). 
-            float fPrev = (float) prevSection / nSections;
-            float fNext = (float) nextSection / nSections;
-            if (prevSection == exactSection && position - fPrev < fThreshold) {
-                index = prevIndex;
+            // currently visible section. This could be equal to or greater than
+            // (1 / nSections). If the target position is near the previous
+            // position, snap to the previous position.
+            final float prevPosition = (float) prevSection / sectionCount;
+            final float nextPosition = (float) nextSection / sectionCount;
+            final float snapThreshold = (count == 0) ? Float.MAX_VALUE : .125f / count;
+            if (prevSection == exactSection && position - prevPosition < snapThreshold) {
+                targetIndex = prevIndex;
             } else {
-                index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev) 
-                    / (fNext - fPrev));
+                targetIndex = prevIndex + (int) ((nextIndex - prevIndex) * (position - prevPosition)
+                    / (nextPosition - prevPosition));
             }
-            // Don't overflow
-            if (index > count - 1) index = count - 1;
-            
+
+            // Clamp to valid positions.
+            targetIndex = MathUtils.constrain(targetIndex, 0, count - 1);
+
             if (mList instanceof ExpandableListView) {
-                ExpandableListView expList = (ExpandableListView) mList;
+                final ExpandableListView expList = (ExpandableListView) mList;
                 expList.setSelectionFromTop(expList.getFlatListPosition(
-                        ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0);
+                        ExpandableListView.getPackedPositionForGroup(targetIndex + mHeaderCount)),
+                        0);
             } else if (mList instanceof ListView) {
-                ((ListView)mList).setSelectionFromTop(index + mListOffset, 0);
+                ((ListView) mList).setSelectionFromTop(targetIndex + mHeaderCount, 0);
             } else {
-                mList.setSelection(index + mListOffset);
+                mList.setSelection(targetIndex + mHeaderCount);
             }
         } else {
-            int index = (int) (position * count);
-            // Don't overflow
-            if (index > count - 1) index = count - 1;
+            final int index = MathUtils.constrain((int) (position * count), 0, count - 1);
 
             if (mList instanceof ExpandableListView) {
                 ExpandableListView expList = (ExpandableListView) mList;
                 expList.setSelectionFromTop(expList.getFlatListPosition(
-                        ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0);
+                        ExpandableListView.getPackedPositionForGroup(index + mHeaderCount)), 0);
             } else if (mList instanceof ListView) {
-                ((ListView)mList).setSelectionFromTop(index + mListOffset, 0);
+                ((ListView)mList).setSelectionFromTop(index + mHeaderCount, 0);
             } else {
-                mList.setSelection(index + mListOffset);
+                mList.setSelection(index + mHeaderCount);
             }
+
             sectionIndex = -1;
         }
 
-        if (sectionIndex >= 0) {
-            String text = mSectionText = sections[sectionIndex].toString();
-            mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') &&
-                    sectionIndex < sections.length;
-        } else {
-            mDrawOverlay = false;
+        if (mCurrentSection != sectionIndex) {
+            mCurrentSection = sectionIndex;
+
+            if (transitionPreviewLayout(sectionIndex)) {
+                transitionToDragging();
+            } else {
+                transitionToVisible();
+            }
         }
     }
 
-    private int getThumbPositionForListPosition(int firstVisibleItem, int visibleItemCount,
-            int totalItemCount) {
+    /**
+     * Transitions the preview text to a new section. Handles animation,
+     * measurement, and layout. If the new preview text is empty, returns false.
+     *
+     * @param sectionIndex The section index to which the preview should
+     *            transition.
+     * @return False if the new preview text is empty.
+     */
+    private boolean transitionPreviewLayout(int sectionIndex) {
+        final Object[] sections = mSections;
+        String text = null;
+        if (sections != null && sectionIndex >= 0 && sectionIndex < sections.length) {
+            final Object section = sections[sectionIndex];
+            if (section != null) {
+                text = section.toString();
+            }
+        }
+
+        final Rect bounds = mTempBounds;
+        final ImageView preview = mPreviewImage;
+        final TextView showing;
+        final TextView target;
+        if (mShowingPrimary) {
+            showing = mPrimaryText;
+            target = mSecondaryText;
+        } else {
+            showing = mSecondaryText;
+            target = mPrimaryText;
+        }
+
+        // Set and layout target immediately.
+        target.setText(text);
+        measurePreview(target, bounds);
+        applyLayout(target, bounds);
+
+        if (mPreviewAnimation != null) {
+            mPreviewAnimation.cancel();
+        }
+
+        // Cross-fade preview text.
+        final Animator showTarget = animateAlpha(target, 1f).setDuration(DURATION_CROSS_FADE);
+        final Animator hideShowing = animateAlpha(showing, 0f).setDuration(DURATION_CROSS_FADE);
+        hideShowing.addListener(mSwitchPrimaryListener);
+
+        // Apply preview image padding and animate bounds, if necessary.
+        bounds.left -= mPreviewImage.getPaddingLeft();
+        bounds.top -= mPreviewImage.getPaddingTop();
+        bounds.right += mPreviewImage.getPaddingRight();
+        bounds.bottom += mPreviewImage.getPaddingBottom();
+        final Animator resizePreview = animateBounds(preview, bounds);
+        resizePreview.setDuration(DURATION_RESIZE);
+
+        mPreviewAnimation = new AnimatorSet();
+        final AnimatorSet.Builder builder = mPreviewAnimation.play(hideShowing).with(showTarget);
+        builder.with(resizePreview);
+
+        // The current preview size is unaffected by hidden or showing. It's
+        // used to set starting scales for things that need to be scaled down.
+        final int previewWidth = preview.getWidth() - preview.getPaddingLeft()
+                - preview.getPaddingRight();
+
+        // If target is too large, shrink it immediately to fit and expand to
+        // target size. Otherwise, start at target size.
+        final int targetWidth = target.getWidth();
+        if (targetWidth > previewWidth) {
+            target.setScaleX((float) previewWidth / targetWidth);
+            final Animator scaleAnim = animateScaleX(target, 1f).setDuration(DURATION_RESIZE);
+            builder.with(scaleAnim);
+        } else {
+            target.setScaleX(1f);
+        }
+
+        // If showing is larger than target, shrink to target size.
+        final int showingWidth = showing.getWidth();
+        if (showingWidth > targetWidth) {
+            final float scale = (float) targetWidth / showingWidth;
+            final Animator scaleAnim = animateScaleX(showing, scale).setDuration(DURATION_RESIZE);
+            builder.with(scaleAnim);
+        }
+
+        mPreviewAnimation.start();
+
+        return (text != null && text.length() > 0);
+    }
+
+    /**
+     * Positions the thumb and preview widgets.
+     *
+     * @param position The position, between 0 and 1, along the track at which
+     *            to place the thumb.
+     */
+    private void setThumbPos(float position) {
+        final Rect container = mContainerRect;
+        final int top = container.top;
+        final int bottom = container.bottom;
+
+        final ImageView trackImage = mTrackImage;
+        final ImageView thumbImage = mThumbImage;
+        final float min = trackImage.getTop();
+        final float max = trackImage.getBottom();
+        final float offset = min;
+        final float range = max - min;
+        final float thumbMiddle = position * range + offset;
+        thumbImage.setTranslationY(thumbMiddle - thumbImage.getHeight() / 2);
+
+        // Center the preview on the thumb, constrained to the list bounds.
+        final ImageView previewImage = mPreviewImage;
+        final float previewHalfHeight = previewImage.getHeight() / 2f;
+        final float minP = top + previewHalfHeight;
+        final float maxP = bottom - previewHalfHeight;
+        final float previewMiddle = MathUtils.constrain(thumbMiddle, minP, maxP);
+        final float previewTop = previewMiddle - previewHalfHeight;
+        previewImage.setTranslationY(previewTop);
+
+        mPrimaryText.setTranslationY(previewTop);
+        mSecondaryText.setTranslationY(previewTop);
+    }
+
+    private float getPosFromMotionEvent(float y) {
+        final Rect container = mContainerRect;
+        final int top = container.top;
+        final int bottom = container.bottom;
+
+        final ImageView trackImage = mTrackImage;
+        final float min = trackImage.getTop();
+        final float max = trackImage.getBottom();
+        final float offset = min;
+        final float range = max - min;
+
+        // If the list is the same height as the thumbnail or shorter,
+        // effectively disable scrolling.
+        if (range <= 0) {
+            return 0f;
+        }
+
+        return MathUtils.constrain((y - offset) / range, 0f, 1f);
+    }
+
+    private float getPosFromItemCount(
+            int firstVisibleItem, int visibleItemCount, int totalItemCount) {
         if (mSectionIndexer == null || mListAdapter == null) {
             getSectionsFromIndexer();
         }
-        if (mSectionIndexer == null || !mMatchDragPosition) {
-            return ((mList.getHeight() - mThumbH) * firstVisibleItem)
-                    / (totalItemCount - visibleItemCount);
+
+        final boolean hasSections = mSectionIndexer != null && mSections != null
+                && mSections.length > 0;
+        if (!hasSections || !mMatchDragPosition) {
+            return (float) firstVisibleItem / (totalItemCount - visibleItemCount);
         }
 
-        firstVisibleItem -= mListOffset;
+        // Ignore headers.
+        firstVisibleItem -= mHeaderCount;
         if (firstVisibleItem < 0) {
             return 0;
         }
-        totalItemCount -= mListOffset;
+        totalItemCount -= mHeaderCount;
 
-        final int trackHeight = mList.getHeight() - mThumbH;
+        // Hidden portion of the first visible row.
+        final View child = mList.getChildAt(0);
+        final float incrementalPos;
+        if (child == null || child.getHeight() == 0) {
+            incrementalPos = 0;
+        } else {
+            incrementalPos = (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight();
+        }
 
+        // Number of rows in this section.
         final int section = mSectionIndexer.getSectionForPosition(firstVisibleItem);
         final int sectionPos = mSectionIndexer.getPositionForSection(section);
-        final int nextSectionPos;
         final int sectionCount = mSections.length;
-        if (section + 1 < sectionCount) {
-            nextSectionPos = mSectionIndexer.getPositionForSection(section + 1);
+        final int positionsInSection;
+        if (section < sectionCount - 1) {
+            final int nextSectionPos;
+            if (section + 1 < sectionCount) {
+                nextSectionPos = mSectionIndexer.getPositionForSection(section + 1);
+            } else {
+                nextSectionPos = totalItemCount - 1;
+            }
+            positionsInSection = nextSectionPos - sectionPos;
         } else {
-            nextSectionPos = totalItemCount - 1;
-        }
-        final int positionsInSection = nextSectionPos - sectionPos;
-
-        final View child = mList.getChildAt(0);
-        final float incrementalPos = child == null ? 0 : firstVisibleItem +
-                (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight();
-        final float posWithinSection = (incrementalPos - sectionPos) / positionsInSection;
-        int result = (int) ((section + posWithinSection) / sectionCount * trackHeight);
-
-        // Fake out the scrollbar for the last item. Since the section indexer won't
-        // ever actually move the list in this end space, make scrolling across the last item
-        // account for whatever space is remaining.
-        if (firstVisibleItem > 0 && firstVisibleItem + visibleItemCount == totalItemCount) {
-            final View lastChild = mList.getChildAt(visibleItemCount - 1);
-            final float lastItemVisible = (float) (mList.getHeight() - mList.getPaddingBottom()
-                    - lastChild.getTop()) / lastChild.getHeight();
-            result += (trackHeight - result) * lastItemVisible;
+            positionsInSection = totalItemCount - sectionPos;
         }
 
-        return result;
+        // Position within this section.
+        final float posWithinSection;
+        if (positionsInSection == 0) {
+            posWithinSection = 0;
+        } else {
+            posWithinSection = (firstVisibleItem + incrementalPos - sectionPos)
+                    / positionsInSection;
+        }
+
+        return (section + posWithinSection) / sectionCount;
     }
 
+    /**
+     * Cancels an ongoing fling event by injecting a
+     * {@link MotionEvent#ACTION_CANCEL} into the host view.
+     */
     private void cancelFling() {
-        // Cancel the list fling
-        MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+        final MotionEvent cancelFling = MotionEvent.obtain(
+                0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
         mList.onTouchEvent(cancelFling);
         cancelFling.recycle();
     }
-    
-    void cancelPendingDrag() {
+
+    /**
+     * Cancels a pending drag.
+     *
+     * @see #startPendingDrag()
+     */
+    private void cancelPendingDrag() {
         mList.removeCallbacks(mDeferStartDrag);
-        mPendingDrag = false;
+        mHasPendingDrag = false;
     }
 
-    void startPendingDrag() {
-        mPendingDrag = true;
-        mList.postDelayed(mDeferStartDrag, PENDING_DRAG_DELAY);
+    /**
+     * Delays dragging until after the framework has determined that the user is
+     * scrolling, rather than tapping.
+     */
+    private void startPendingDrag() {
+        mHasPendingDrag = true;
+        mList.postDelayed(mDeferStartDrag, TAP_TIMEOUT);
     }
 
-    void beginDrag() {
+    private void beginDrag() {
         setState(STATE_DRAGGING);
+
         if (mListAdapter == null && mList != null) {
             getSectionsFromIndexer();
         }
+
         if (mList != null) {
             mList.requestDisallowInterceptTouchEvent(true);
             mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
@@ -734,87 +1230,101 @@
         cancelFling();
     }
 
-    boolean onInterceptTouchEvent(MotionEvent ev) {
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (!isEnabled()) {
+            return false;
+        }
+
         switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
-                if (mState > STATE_NONE && isPointInside(ev.getX(), ev.getY())) {
+                if (isPointInside(ev.getX(), ev.getY())) {
+                    // If the parent has requested that its children delay
+                    // pressed state (e.g. is a scrolling container) then we
+                    // need to allow the parent time to decide whether it wants
+                    // to intercept events. If it does, we will receive a CANCEL
+                    // event.
                     if (!mList.isInScrollingContainer()) {
                         beginDrag();
                         return true;
                     }
+
                     mInitialTouchY = ev.getY();
                     startPendingDrag();
                 }
                 break;
+            case MotionEvent.ACTION_MOVE:
+                if (!isPointInside(ev.getX(), ev.getY())) {
+                    cancelPendingDrag();
+                }
+                break;
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
                 cancelPendingDrag();
                 break;
         }
+
         return false;
     }
 
-    boolean onTouchEvent(MotionEvent me) {
-        if (mState == STATE_NONE) {
+    public boolean onInterceptHoverEvent(MotionEvent ev) {
+        if (!isEnabled()) {
             return false;
         }
 
-        final int action = me.getAction();
+        final int actionMasked = ev.getActionMasked();
+        if ((actionMasked == MotionEvent.ACTION_HOVER_ENTER
+                || actionMasked == MotionEvent.ACTION_HOVER_MOVE) && mState == STATE_NONE
+                && isPointInside(ev.getX(), ev.getY())) {
+            setState(STATE_VISIBLE);
+            postAutoHide();
+        }
 
-        if (action == MotionEvent.ACTION_DOWN) {
-            if (isPointInside(me.getX(), me.getY())) {
-                if (!mList.isInScrollingContainer()) {
+        return false;
+    }
+
+    public boolean onTouchEvent(MotionEvent me) {
+        if (!isEnabled()) {
+            return false;
+        }
+
+        switch (me.getActionMasked()) {
+            case MotionEvent.ACTION_UP: {
+                if (mHasPendingDrag) {
+                    // Allow a tap to scroll.
                     beginDrag();
+
+                    final float pos = getPosFromMotionEvent(me.getY());
+                    setThumbPos(pos);
+                    scrollTo(pos);
+
+                    cancelPendingDrag();
+                    // Will hit the STATE_DRAGGING check below
+                }
+
+                if (mState == STATE_DRAGGING) {
+                    if (mList != null) {
+                        // ViewGroup does the right thing already, but there might
+                        // be other classes that don't properly reset on touch-up,
+                        // so do this explicitly just in case.
+                        mList.requestDisallowInterceptTouchEvent(false);
+                        mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+                    }
+
+                    setState(STATE_VISIBLE);
+                    postAutoHide();
+
                     return true;
                 }
-                mInitialTouchY = me.getY();
-                startPendingDrag();
-            }
-        } else if (action == MotionEvent.ACTION_UP) { // don't add ACTION_CANCEL here
-            if (mPendingDrag) {
-                // Allow a tap to scroll.
-                beginDrag();
+            } break;
 
-                final int viewHeight = mList.getHeight();
-                // Jitter
-                int newThumbY = (int) me.getY() - mThumbH + 10;
-                if (newThumbY < 0) {
-                    newThumbY = 0;
-                } else if (newThumbY + mThumbH > viewHeight) {
-                    newThumbY = viewHeight - mThumbH;
-                }
-                mThumbY = newThumbY;
-                scrollTo((float) mThumbY / (viewHeight - mThumbH));
-
-                cancelPendingDrag();
-                // Will hit the STATE_DRAGGING check below
-            }
-            if (mState == STATE_DRAGGING) {
-                if (mList != null) {
-                    // ViewGroup does the right thing already, but there might
-                    // be other classes that don't properly reset on touch-up,
-                    // so do this explicitly just in case.
-                    mList.requestDisallowInterceptTouchEvent(false);
-                    mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                }
-                setState(STATE_VISIBLE);
-                final Handler handler = mHandler;
-                handler.removeCallbacks(mScrollFade);
-                if (!mAlwaysShow) {
-                    handler.postDelayed(mScrollFade, 1000);
-                }
-
-                mList.invalidate();
-                return true;
-            }
-        } else if (action == MotionEvent.ACTION_MOVE) {
-            if (mPendingDrag) {
-                final float y = me.getY();
-                if (Math.abs(y - mInitialTouchY) > mScaledTouchSlop) {
+            case MotionEvent.ACTION_MOVE: {
+                if (mHasPendingDrag && Math.abs(me.getY() - mInitialTouchY) > mScaledTouchSlop) {
                     setState(STATE_DRAGGING);
+
                     if (mListAdapter == null && mList != null) {
                         getSectionsFromIndexer();
                     }
+
                     if (mList != null) {
                         mList.requestDisallowInterceptTouchEvent(true);
                         mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
@@ -824,86 +1334,168 @@
                     cancelPendingDrag();
                     // Will hit the STATE_DRAGGING check below
                 }
-            }
-            if (mState == STATE_DRAGGING) {
-                final int viewHeight = mList.getHeight();
-                // Jitter
-                int newThumbY = (int) me.getY() - mThumbH + 10;
-                if (newThumbY < 0) {
-                    newThumbY = 0;
-                } else if (newThumbY + mThumbH > viewHeight) {
-                    newThumbY = viewHeight - mThumbH;
-                }
-                if (Math.abs(mThumbY - newThumbY) < 2) {
+
+                if (mState == STATE_DRAGGING) {
+                    // TODO: Ignore jitter.
+                    final float pos = getPosFromMotionEvent(me.getY());
+                    setThumbPos(pos);
+
+                    // If the previous scrollTo is still pending
+                    if (mScrollCompleted) {
+                        scrollTo(pos);
+                    }
+
                     return true;
                 }
-                mThumbY = newThumbY;
-                // If the previous scrollTo is still pending
-                if (mScrollCompleted) {
-                    scrollTo((float) mThumbY / (viewHeight - mThumbH));
-                }
-                return true;
-            }
-        } else if (action == MotionEvent.ACTION_CANCEL) {
-            cancelPendingDrag();
+            } break;
+
+            case MotionEvent.ACTION_CANCEL: {
+                cancelPendingDrag();
+            } break;
         }
+
         return false;
     }
 
-    boolean isPointInside(float x, float y) {
-        boolean inTrack = false;
-        switch (mPosition) {
-            default:
-            case View.SCROLLBAR_POSITION_RIGHT:
-                inTrack = x > mList.getWidth() - mThumbW;
-                break;
-            case View.SCROLLBAR_POSITION_LEFT:
-                inTrack = x < mThumbW;
-                break;
-        }
-
-        // Allow taps in the track to start moving.
-        return inTrack && (mTrackDrawable != null || y >= mThumbY && y <= mThumbY + mThumbH);
+    /**
+     * Returns whether a coordinate is inside the scroller's activation area. If
+     * there is a track image, touching anywhere within the thumb-width of the
+     * track activates scrolling. Otherwise, the user has to touch inside thumb
+     * itself.
+     *
+     * @param x The x-coordinate.
+     * @param y The y-coordinate.
+     * @return Whether the coordinate is inside the scroller's activation area.
+     */
+    private boolean isPointInside(float x, float y) {
+        return isPointInsideX(x) && (mHasTrackImage || isPointInsideY(y));
     }
 
-    public class ScrollFade implements Runnable {
-        
-        long mStartTime;
-        long mFadeDuration;
-        static final int ALPHA_MAX = 208;
-        static final long FADE_DURATION = 200;
-        
-        void startFade() {
-            mFadeDuration = FADE_DURATION;
-            mStartTime = SystemClock.uptimeMillis();
-            setState(STATE_EXIT);
+    private boolean isPointInsideX(float x) {
+        if (mLayoutFromRight) {
+            return x >= mThumbImage.getLeft();
+        } else {
+            return x <= mThumbImage.getRight();
         }
-        
-        int getAlpha() {
-            if (getState() != STATE_EXIT) {
-                return ALPHA_MAX;
-            }
-            int alpha;
-            long now = SystemClock.uptimeMillis();
-            if (now > mStartTime + mFadeDuration) {
-                alpha = 0;
+    }
+
+    private boolean isPointInsideY(float y) {
+        return y >= mThumbImage.getTop() && y <= mThumbImage.getBottom();
+    }
+
+    /**
+     * Constructs an animator for the specified property on a group of views.
+     * See {@link ObjectAnimator#ofFloat(Object, String, float...)} for
+     * implementation details.
+     *
+     * @param property The property being animated.
+     * @param value The value to which that property should animate.
+     * @param views The target views to animate.
+     * @return An animator for all the specified views.
+     */
+    private static Animator groupAnimatorOfFloat(
+            Property<View, Float> property, float value, View... views) {
+        AnimatorSet animSet = new AnimatorSet();
+        AnimatorSet.Builder builder = null;
+
+        for (int i = views.length - 1; i >= 0; i--) {
+            final Animator anim = ObjectAnimator.ofFloat(views[i], property, value);
+            if (builder == null) {
+                builder = animSet.play(anim);
             } else {
-                alpha = (int) (ALPHA_MAX - ((now - mStartTime) * ALPHA_MAX) / mFadeDuration); 
-            }
-            return alpha;
-        }
-        
-        public void run() {
-            if (getState() != STATE_EXIT) {
-                startFade();
-                return;
-            }
-            
-            if (getAlpha() > 0) {
-                mList.invalidate();
-            } else {
-                setState(STATE_NONE);
+                builder.with(anim);
             }
         }
+
+        return animSet;
+    }
+
+    /**
+     * Returns an animator for the view's scaleX value.
+     */
+    private static Animator animateScaleX(View v, float target) {
+        return ObjectAnimator.ofFloat(v, View.SCALE_X, target);
+    }
+
+    /**
+     * Returns an animator for the view's alpha value.
+     */
+    private static Animator animateAlpha(View v, float alpha) {
+        return ObjectAnimator.ofFloat(v, View.ALPHA, alpha);
+    }
+
+    /**
+     * A Property wrapper around the <code>left</code> functionality handled by the
+     * {@link View#setLeft(int)} and {@link View#getLeft()} methods.
+     */
+    private static Property<View, Integer> LEFT = new IntProperty<View>("left") {
+        @Override
+        public void setValue(View object, int value) {
+            object.setLeft(value);
+        }
+
+        @Override
+        public Integer get(View object) {
+            return object.getLeft();
+        }
+    };
+
+    /**
+     * A Property wrapper around the <code>top</code> functionality handled by the
+     * {@link View#setTop(int)} and {@link View#getTop()} methods.
+     */
+    private static Property<View, Integer> TOP = new IntProperty<View>("top") {
+        @Override
+        public void setValue(View object, int value) {
+            object.setTop(value);
+        }
+
+        @Override
+        public Integer get(View object) {
+            return object.getTop();
+        }
+    };
+
+    /**
+     * A Property wrapper around the <code>right</code> functionality handled by the
+     * {@link View#setRight(int)} and {@link View#getRight()} methods.
+     */
+    private static Property<View, Integer> RIGHT = new IntProperty<View>("right") {
+        @Override
+        public void setValue(View object, int value) {
+            object.setRight(value);
+        }
+
+        @Override
+        public Integer get(View object) {
+            return object.getRight();
+        }
+    };
+
+    /**
+     * A Property wrapper around the <code>bottom</code> functionality handled by the
+     * {@link View#setBottom(int)} and {@link View#getBottom()} methods.
+     */
+    private static Property<View, Integer> BOTTOM = new IntProperty<View>("bottom") {
+        @Override
+        public void setValue(View object, int value) {
+            object.setBottom(value);
+        }
+
+        @Override
+        public Integer get(View object) {
+            return object.getBottom();
+        }
+    };
+
+    /**
+     * Returns an animator for the view's bounds.
+     */
+    private static Animator animateBounds(View v, Rect bounds) {
+        final PropertyValuesHolder left = PropertyValuesHolder.ofInt(LEFT, bounds.left);
+        final PropertyValuesHolder top = PropertyValuesHolder.ofInt(TOP, bounds.top);
+        final PropertyValuesHolder right = PropertyValuesHolder.ofInt(RIGHT, bounds.right);
+        final PropertyValuesHolder bottom = PropertyValuesHolder.ofInt(BOTTOM, bounds.bottom);
+        return ObjectAnimator.ofPropertyValuesHolder(v, left, top, right, bottom);
     }
 }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 738f63b..d9d4ad7 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -267,12 +267,12 @@
         return mForeground;
     }
 
-    private int getPaddingLeftWithForeground() {
+    int getPaddingLeftWithForeground() {
         return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
             mPaddingLeft + mForegroundPaddingLeft;
     }
 
-    private int getPaddingRightWithForeground() {
+    int getPaddingRightWithForeground() {
         return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) :
             mPaddingRight + mForegroundPaddingRight;
     }
@@ -385,6 +385,11 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
+    }
+
+    void layoutChildren(int left, int top, int right, int bottom,
+                                  boolean forceLeftGravity) {
         final int count = getChildCount();
 
         final int parentLeft = getPaddingLeftWithForeground();
@@ -416,16 +421,16 @@
                 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
 
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                    case Gravity.LEFT:
-                        childLeft = parentLeft + lp.leftMargin;
-                        break;
                     case Gravity.CENTER_HORIZONTAL:
                         childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
                         lp.leftMargin - lp.rightMargin;
                         break;
                     case Gravity.RIGHT:
-                        childLeft = parentRight - width - lp.rightMargin;
-                        break;
+                        if (!forceLeftGravity) {
+                            childLeft = parentRight - width - lp.rightMargin;
+                            break;
+                        }
+                    case Gravity.LEFT:
                     default:
                         childLeft = parentLeft + lp.leftMargin;
                 }
@@ -651,5 +656,17 @@
         public LayoutParams(ViewGroup.MarginLayoutParams source) {
             super(source);
         }
+
+        /**
+         * Copy constructor. Clones the width, height, margin values, and
+         * gravity of the source.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.gravity = source.gravity;
+        }
     }
 }
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index c4ef11c..78ba6e0 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1228,13 +1228,9 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-        case KeyEvent.KEYCODE_DPAD_CENTER:
-        case KeyEvent.KEYCODE_ENTER: {
-            
+        if (KeyEvent.isConfirmKey(keyCode)) {
             if (mReceivedInvokeKeyDown) {
                 if (mItemCount > 0) {
-    
                     dispatchPress(mSelectedChild);
                     postDelayed(new Runnable() {
                         @Override
@@ -1242,20 +1238,17 @@
                             dispatchUnpress();
                         }
                     }, ViewConfiguration.getPressedStateDuration());
-    
+
                     int selectedIndex = mSelectedPosition - mFirstPosition;
                     performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter
                             .getItemId(mSelectedPosition));
                 }
             }
-            
+
             // Clear the flag
             mReceivedInvokeKeyDown = false;
-            
             return true;
         }
-        }
-
         return super.onKeyUp(keyCode, event);
     }
     
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 2309001..54cc3f4 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -24,7 +24,9 @@
 import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.LogPrinter;
 import android.util.Pair;
+import android.util.Printer;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -124,6 +126,17 @@
  * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
  * and <em>bottom</em> edges.
  *
+ * <h4>Interpretation of GONE</h4>
+ *
+ * For layout purposes, GridLayout treats views whose visibility status is
+ * {@link View#GONE GONE}, as having zero width and height. This is subtly different from
+ * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked
+ * view was alone in a column, that column would itself collapse to zero width if and only if
+ * no gravity was defined on the view. If gravity was defined, then the gone-marked
+ * view has no effect on the layout and the container should be laid out as if the view
+ * had never been added to it.
+ * These statements apply equally to rows as well as columns, and to groups of rows or columns.
+ *
  * <h5>Limitations</h5>
  *
  * GridLayout does not provide support for the principle of <em>weight</em>, as defined in
@@ -208,10 +221,15 @@
 
     // Misc constants
 
-    static final String TAG = GridLayout.class.getName();
     static final int MAX_SIZE = 100000;
     static final int DEFAULT_CONTAINER_MARGIN = 0;
     static final int UNINITIALIZED_HASH = 0;
+    static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName());
+    static final Printer NO_PRINTER = new Printer() {
+        @Override
+        public void println(String x) {
+        }
+    };
 
     // Defaults
 
@@ -233,13 +251,14 @@
 
     // Instance variables
 
-    final Axis horizontalAxis = new Axis(true);
-    final Axis verticalAxis = new Axis(false);
-    int orientation = DEFAULT_ORIENTATION;
-    boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
-    int alignmentMode = DEFAULT_ALIGNMENT_MODE;
-    int defaultGap;
-    int lastLayoutParamsHashCode = UNINITIALIZED_HASH;
+    final Axis mHorizontalAxis = new Axis(true);
+    final Axis mVerticalAxis = new Axis(false);
+    int mOrientation = DEFAULT_ORIENTATION;
+    boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
+    int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
+    int mDefaultGap;
+    int mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
+    Printer mPrinter = LOG_PRINTER;
 
     // Constructors
 
@@ -248,7 +267,7 @@
      */
     public GridLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        defaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
+        mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
         try {
             setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
@@ -290,7 +309,7 @@
      * @attr ref android.R.styleable#GridLayout_orientation
      */
     public int getOrientation() {
-        return orientation;
+        return mOrientation;
     }
 
     /**
@@ -330,8 +349,8 @@
      * @attr ref android.R.styleable#GridLayout_orientation
      */
     public void setOrientation(int orientation) {
-        if (this.orientation != orientation) {
-            this.orientation = orientation;
+        if (this.mOrientation != orientation) {
+            this.mOrientation = orientation;
             invalidateStructure();
             requestLayout();
         }
@@ -350,7 +369,7 @@
      * @attr ref android.R.styleable#GridLayout_rowCount
      */
     public int getRowCount() {
-        return verticalAxis.getCount();
+        return mVerticalAxis.getCount();
     }
 
     /**
@@ -365,7 +384,7 @@
      * @attr ref android.R.styleable#GridLayout_rowCount
      */
     public void setRowCount(int rowCount) {
-        verticalAxis.setCount(rowCount);
+        mVerticalAxis.setCount(rowCount);
         invalidateStructure();
         requestLayout();
     }
@@ -383,7 +402,7 @@
      * @attr ref android.R.styleable#GridLayout_columnCount
      */
     public int getColumnCount() {
-        return horizontalAxis.getCount();
+        return mHorizontalAxis.getCount();
     }
 
     /**
@@ -398,7 +417,7 @@
      * @attr ref android.R.styleable#GridLayout_columnCount
      */
     public void setColumnCount(int columnCount) {
-        horizontalAxis.setCount(columnCount);
+        mHorizontalAxis.setCount(columnCount);
         invalidateStructure();
         requestLayout();
     }
@@ -414,7 +433,7 @@
      * @attr ref android.R.styleable#GridLayout_useDefaultMargins
      */
     public boolean getUseDefaultMargins() {
-        return useDefaultMargins;
+        return mUseDefaultMargins;
     }
 
     /**
@@ -444,7 +463,7 @@
      * @attr ref android.R.styleable#GridLayout_useDefaultMargins
      */
     public void setUseDefaultMargins(boolean useDefaultMargins) {
-        this.useDefaultMargins = useDefaultMargins;
+        this.mUseDefaultMargins = useDefaultMargins;
         requestLayout();
     }
 
@@ -461,7 +480,7 @@
      * @attr ref android.R.styleable#GridLayout_alignmentMode
      */
     public int getAlignmentMode() {
-        return alignmentMode;
+        return mAlignmentMode;
     }
 
     /**
@@ -480,7 +499,7 @@
      * @attr ref android.R.styleable#GridLayout_alignmentMode
      */
     public void setAlignmentMode(int alignmentMode) {
-        this.alignmentMode = alignmentMode;
+        this.mAlignmentMode = alignmentMode;
         requestLayout();
     }
 
@@ -495,7 +514,7 @@
      * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
      */
     public boolean isRowOrderPreserved() {
-        return verticalAxis.isOrderPreserved();
+        return mVerticalAxis.isOrderPreserved();
     }
 
     /**
@@ -515,7 +534,7 @@
      * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
      */
     public void setRowOrderPreserved(boolean rowOrderPreserved) {
-        verticalAxis.setOrderPreserved(rowOrderPreserved);
+        mVerticalAxis.setOrderPreserved(rowOrderPreserved);
         invalidateStructure();
         requestLayout();
     }
@@ -531,7 +550,7 @@
      * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
      */
     public boolean isColumnOrderPreserved() {
-        return horizontalAxis.isOrderPreserved();
+        return mHorizontalAxis.isOrderPreserved();
     }
 
     /**
@@ -551,11 +570,38 @@
      * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
      */
     public void setColumnOrderPreserved(boolean columnOrderPreserved) {
-        horizontalAxis.setOrderPreserved(columnOrderPreserved);
+        mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
         invalidateStructure();
         requestLayout();
     }
 
+    /**
+     * Return the printer that will log diagnostics from this layout.
+     *
+     * @see #setPrinter(android.util.Printer)
+     *
+     * @return the printer associated with this view
+     *
+     * @hide
+     */
+    public Printer getPrinter() {
+        return mPrinter;
+    }
+
+    /**
+     * Set the printer that will log diagnostics from this layout.
+     * The default value is created by {@link android.util.LogPrinter}.
+     *
+     * @param printer the printer associated with this layout
+     *
+     * @see #getPrinter()
+     *
+     * @hide
+     */
+    public void setPrinter(Printer printer) {
+        this.mPrinter = (printer == null) ? NO_PRINTER : printer;
+    }
+
     // Static utility methods
 
     static int max2(int[] a, int valueIfEmpty) {
@@ -601,7 +647,7 @@
         if (c.getClass() == Space.class) {
             return 0;
         }
-        return defaultGap / 2;
+        return mDefaultGap / 2;
     }
 
     private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
@@ -609,11 +655,11 @@
     }
 
     private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
-        if (!useDefaultMargins) {
+        if (!mUseDefaultMargins) {
             return 0;
         }
         Spec spec = horizontal ? p.columnSpec : p.rowSpec;
-        Axis axis = horizontal ? horizontalAxis : verticalAxis;
+        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
         Interval span = spec.span;
         boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
         boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
@@ -630,10 +676,10 @@
     }
 
     private int getMargin(View view, boolean horizontal, boolean leading) {
-        if (alignmentMode == ALIGN_MARGINS) {
+        if (mAlignmentMode == ALIGN_MARGINS) {
             return getMargin1(view, horizontal, leading);
         } else {
-            Axis axis = horizontal ? horizontalAxis : verticalAxis;
+            Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
             int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
             LayoutParams lp = getLayoutParams(view);
             Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
@@ -680,8 +726,8 @@
 
     // install default indices for cells that don't define them
     private void validateLayoutParams() {
-        final boolean horizontal = (orientation == HORIZONTAL);
-        final Axis axis = horizontal ? horizontalAxis : verticalAxis;
+        final boolean horizontal = (mOrientation == HORIZONTAL);
+        final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
         final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
 
         int major = 0;
@@ -737,9 +783,9 @@
     }
 
     private void invalidateStructure() {
-        lastLayoutParamsHashCode = UNINITIALIZED_HASH;
-        horizontalAxis.invalidateStructure();
-        verticalAxis.invalidateStructure();
+        mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
+        mHorizontalAxis.invalidateStructure();
+        mVerticalAxis.invalidateStructure();
         // This can end up being done twice. Better twice than not at all.
         invalidateValues();
     }
@@ -747,9 +793,9 @@
     private void invalidateValues() {
         // Need null check because requestLayout() is called in View's initializer,
         // before we are set up.
-        if (horizontalAxis != null && verticalAxis != null) {
-            horizontalAxis.invalidateValues();
-            verticalAxis.invalidateValues();
+        if (mHorizontalAxis != null && mVerticalAxis != null) {
+            mHorizontalAxis.invalidateValues();
+            mVerticalAxis.invalidateValues();
         }
     }
 
@@ -780,7 +826,7 @@
         if (span.min != UNDEFINED && span.min < 0) {
             handleInvalidParams(groupName + " indices must be positive");
         }
-        Axis axis = horizontal ? horizontalAxis : verticalAxis;
+        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
         int count = axis.definedCount;
         if (count != UNDEFINED) {
             if (span.max > count) {
@@ -866,7 +912,7 @@
         int right  = getWidth()  - getPaddingRight()  - insets.right;
         int bottom = getHeight() - getPaddingBottom() - insets.bottom;
 
-        int[] xs = horizontalAxis.locations;
+        int[] xs = mHorizontalAxis.locations;
         if (xs != null) {
             for (int i = 0, length = xs.length; i < length; i++) {
                 int x = left + xs[i];
@@ -874,7 +920,7 @@
             }
         }
 
-        int[] ys = verticalAxis.locations;
+        int[] ys = mVerticalAxis.locations;
         if (ys != null) {
             for (int i = 0, length = ys.length; i < length; i++) {
                 int y = top + ys[i];
@@ -915,7 +961,7 @@
     protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
         super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
         if (oldVisibility == GONE || newVisibility == GONE) {
-            invalidateStructure();
+        invalidateStructure();
         }
     }
 
@@ -931,12 +977,12 @@
     }
 
     private void consistencyCheck() {
-        if (lastLayoutParamsHashCode == UNINITIALIZED_HASH) {
+        if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) {
             validateLayoutParams();
-            lastLayoutParamsHashCode = computeLayoutParamsHashCode();
-        } else if (lastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
-            Log.w(TAG, "The fields of some layout parameters were modified in between layout " +
-                    "operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
+            mLastLayoutParamsHashCode = computeLayoutParamsHashCode();
+        } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
+            mPrinter.println("The fields of some layout parameters were modified in between "
+                    + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
             invalidateStructure();
             consistencyCheck();
         }
@@ -963,11 +1009,11 @@
             if (firstPass) {
                 measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
             } else {
-                boolean horizontal = (orientation == HORIZONTAL);
+                boolean horizontal = (mOrientation == HORIZONTAL);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 if (spec.alignment == FILL) {
                     Interval span = spec.span;
-                    Axis axis = horizontal ? horizontalAxis : verticalAxis;
+                    Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
                     int[] locations = axis.getLocations();
                     int cellSize = locations[span.max] - locations[span.min];
                     int viewSize = cellSize - getTotalMargin(c, horizontal);
@@ -1006,14 +1052,14 @@
         int heightSansPadding;
 
         // Use the orientation property to decide which axis should be laid out first.
-        if (orientation == HORIZONTAL) {
-            widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
+        if (mOrientation == HORIZONTAL) {
+            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
             measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
-            heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
+            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
         } else {
-            heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
+            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
             measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
-            widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
+            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
         }
 
         int measuredWidth  = Math.max(widthSansPadding  + hPadding, getSuggestedMinimumWidth());
@@ -1072,11 +1118,11 @@
         int paddingRight = getPaddingRight();
         int paddingBottom = getPaddingBottom();
 
-        horizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
-        verticalAxis.layout(targetHeight - paddingTop - paddingBottom);
+        mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
+        mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
 
-        int[] hLocations = horizontalAxis.getLocations();
-        int[] vLocations = verticalAxis.getLocations();
+        int[] hLocations = mHorizontalAxis.getLocations();
+        int[] vLocations = mVerticalAxis.getLocations();
 
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
@@ -1103,8 +1149,8 @@
             Alignment hAlign = getAlignment(columnSpec.alignment, true);
             Alignment vAlign = getAlignment(rowSpec.alignment, false);
 
-            Bounds boundsX = horizontalAxis.getGroupBounds().getValue(i);
-            Bounds boundsY = verticalAxis.getGroupBounds().getValue(i);
+            Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
+            Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
 
             // Gravity offsets: the location of the alignment group relative to its cell group.
             int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
@@ -1246,6 +1292,7 @@
             Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
+                // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
@@ -1261,6 +1308,7 @@
             }
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
+                // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
@@ -1527,8 +1575,8 @@
                     removed.add(arc);
                 }
             }
-            Log.d(TAG, axisName + " constraints: " + arcsToString(culprits) + " are inconsistent; "
-                    + "permanently removing: " + arcsToString(removed) + ". ");
+            mPrinter.println(axisName + " constraints: " + arcsToString(culprits) +
+                    " are inconsistent; permanently removing: " + arcsToString(removed) + ". ");
         }
 
         /*
@@ -1917,12 +1965,16 @@
         }
 
         /**
-         * {@inheritDoc}
+         * Copy constructor. Clones the width, height, margin values, row spec,
+         * and column spec of the source.
+         *
+         * @param source The layout params to copy from.
          */
-        public LayoutParams(LayoutParams that) {
-            super(that);
-            this.rowSpec = that.rowSpec;
-            this.columnSpec = that.columnSpec;
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.rowSpec = source.rowSpec;
+            this.columnSpec = source.columnSpec;
         }
 
         // AttributeSet constructors
@@ -2666,6 +2718,9 @@
 
         @Override
         public int getAlignmentValue(View view, int viewSize, int mode) {
+            if (view.getVisibility() == GONE) {
+                return 0;
+            }
             int baseline = view.getBaseline();
             return baseline == -1 ? UNDEFINED : baseline;
         }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 63147dd..15daf83 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -29,7 +30,10 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
+import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
 import android.view.animation.GridLayoutAnimationController;
+import android.widget.AbsListView.LayoutParams;
 import android.widget.RemoteViews.RemoteView;
 
 
@@ -1364,6 +1368,8 @@
      */
     private void setupChild(View child, int position, int y, boolean flow, int childrenLeft,
             boolean selected, boolean recycled, int where) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "setupGridItem");
+
         boolean isSelected = selected && shouldShowSelector();
         final boolean updateChildSelected = isSelected != child.isSelected();
         final int mode = mTouchMode;
@@ -1459,6 +1465,8 @@
                 != position) {
             child.jumpDrawablesToCurrentState();
         }
+
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
     }
 
     /**
@@ -2254,5 +2262,37 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(GridView.class.getName());
+
+        final int columnsCount = getNumColumns();
+        final int rowsCount = getCount() / columnsCount;
+        final CollectionInfo collectionInfo = CollectionInfo.obtain(columnsCount, rowsCount, false);
+        info.setCollectionInfo(collectionInfo);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfoForItem(
+            View view, int position, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoForItem(view, position, info);
+
+        final int count = getCount();
+        final int columnsCount = getNumColumns();
+        final int rowsCount = count / columnsCount;
+
+        final int row;
+        final int column;
+        if (!mStackFromBottom) {
+            column = position % columnsCount;
+            row = position / columnsCount;
+        } else {
+            final int invertedIndex = count - 1 - position;
+
+            column = columnsCount - 1 - (invertedIndex % columnsCount);
+            row = rowsCount - 1 - invertedIndex / columnsCount;
+        }
+
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+        final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(column, 1, row, 1, isHeading);
+        info.setCollectionItemInfo(itemInfo);
     }
 }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index ff0579c..dab0962 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -20,7 +20,10 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.FocusFinder;
@@ -133,6 +136,8 @@
      */
     private static final int INVALID_POINTER = -1;
 
+    private SavedState mSavedState;
+
     public HorizontalScrollView(Context context) {
         this(context, null);
     }
@@ -595,12 +600,13 @@
                     final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
                             (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
 
+                    // Calling overScrollBy will call onOverScrolled, which
+                    // calls onScrollChanged if applicable.
                     if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
                             mOverscrollDistance, 0, true)) {
                         // Break our velocity if we hit a scroll barrier.
                         mVelocityTracker.clear();
                     }
-                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
                     if (canOverscroll) {
                         final int pulledToX = oldX + deltaX;
@@ -732,9 +738,12 @@
             boolean clampedX, boolean clampedY) {
         // Treat animating scrolls differently; see #computeScroll() for why.
         if (!mScroller.isFinished()) {
+            final int oldX = mScrollX;
+            final int oldY = mScrollY;
             mScrollX = scrollX;
             mScrollY = scrollY;
             invalidateParentIfNeeded();
+            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
             if (clampedX) {
                 mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0);
             }
@@ -1448,14 +1457,52 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
+        int childWidth = 0;
+        int childMargins = 0;
+
+        if (getChildCount() > 0) {
+            childWidth = getChildAt(0).getMeasuredWidth();
+            LayoutParams childParams = (LayoutParams) getChildAt(0).getLayoutParams();
+            childMargins = childParams.leftMargin + childParams.rightMargin;
+        }
+
+        final int available = r - l - getPaddingLeftWithForeground() -
+                getPaddingRightWithForeground() - childMargins;
+
+        final boolean forceLeftGravity = (childWidth > available);
+
+        layoutChildren(l, t, r, b, forceLeftGravity);
+
         mIsLayoutDirty = false;
         // Give a child focus if it needs it
         if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
-                scrollToChild(mChildToScrollTo);
+            scrollToChild(mChildToScrollTo);
         }
         mChildToScrollTo = null;
 
+        if (!isLaidOut()) {
+            final int scrollRange = Math.max(0,
+                    childWidth - (r - l - mPaddingLeft - mPaddingRight));
+            if (mSavedState != null) {
+                if (isLayoutRtl() == mSavedState.isLayoutRtl) {
+                    mScrollX = mSavedState.scrollPosition;
+                } else {
+                    mScrollX = scrollRange - mSavedState.scrollPosition;
+                }
+                mSavedState = null;
+            } else {
+                if (isLayoutRtl()) {
+                    mScrollX = scrollRange - mScrollX;
+                } // mScrollX default value is "0" for LTR
+            }
+            // Don't forget to clamp
+            if (mScrollX > scrollRange) {
+                mScrollX = scrollRange;
+            } else if (mScrollX < 0) {
+                mScrollX = 0;
+            }
+        }
+
         // Calling this with the present values causes it to re-claim them
         scrollTo(mScrollX, mScrollY);
     }
@@ -1600,4 +1647,73 @@
         }
         return n;
     }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            // Some old apps reused IDs in ways they shouldn't have.
+            // Don't break them, but they don't get scroll state restoration.
+            super.onRestoreInstanceState(state);
+            return;
+        }
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        mSavedState = ss;
+        requestLayout();
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            // Some old apps reused IDs in ways they shouldn't have.
+            // Don't break them, but they don't get scroll state restoration.
+            return super.onSaveInstanceState();
+        }
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.scrollPosition = mScrollX;
+        ss.isLayoutRtl = isLayoutRtl();
+        return ss;
+    }
+
+    static class SavedState extends BaseSavedState {
+        public int scrollPosition;
+        public boolean isLayoutRtl;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public SavedState(Parcel source) {
+            super(source);
+            scrollPosition = source.readInt();
+            isLayoutRtl = (source.readInt() == 0) ? true : false;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(scrollPosition);
+            dest.writeInt(isLayoutRtl ? 1 : 0);
+        }
+
+        @Override
+        public String toString() {
+            return "HorizontalScrollView.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " scrollPosition=" + scrollPosition
+                    + " isLayoutRtl=" + isLayoutRtl + "}";
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
 }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 33fd8ce..3e53b91 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -732,6 +732,15 @@
         }
     }
 
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+
+        if (mDrawable != null) {
+            mDrawable.setLayoutDirection(layoutDirection);
+        }
+    }
+
     private static final Matrix.ScaleToFit[] sS2FArray = {
         Matrix.ScaleToFit.FILL,
         Matrix.ScaleToFit.START,
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index bc57c36e..ad60a95 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1871,10 +1871,23 @@
         /**
          * {@inheritDoc}
          */
-        public LayoutParams(MarginLayoutParams source) {
+        public LayoutParams(ViewGroup.MarginLayoutParams source) {
             super(source);
         }
 
+        /**
+         * Copy constructor. Clones the width, height, margin values, weight,
+         * and gravity of the source.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.weight = source.weight;
+            this.gravity = source.gravity;
+        }
+
         @Override
         public String debug(String output) {
             return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3d6b69e..66fe46f 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -16,6 +16,9 @@
 
 package android.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
@@ -23,14 +26,21 @@
 import android.os.Handler;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.IntProperty;
 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.OnTouchListener;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.animation.AccelerateDecelerateInterpolator;
+
+import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
 
 import java.util.Locale;
 
@@ -67,6 +77,8 @@
     private int mDropDownVerticalOffset;
     private boolean mDropDownVerticalOffsetSet;
 
+    private int mDropDownGravity = Gravity.NO_GRAVITY;
+
     private boolean mDropDownAlwaysVisible = false;
     private boolean mForceIgnoreOutsideTouch = false;
     int mListItemExpandMaximum = Integer.MAX_VALUE;
@@ -430,6 +442,16 @@
     }
 
     /**
+     * Set the gravity of the dropdown list. This is commonly used to
+     * set gravity to START or END for alignment with the anchor.
+     *
+     * @param gravity Gravity value to use
+     */
+    public void setDropDownGravity(int gravity) {
+        mDropDownGravity = gravity;
+    }
+
+    /**
      * @return The width of the popup window in pixels.
      */
     public int getWidth() {
@@ -601,7 +623,7 @@
             mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
             mPopup.setTouchInterceptor(mTouchInterceptor);
             mPopup.showAsDropDown(getAnchorView(),
-                    mDropDownHorizontalOffset, mDropDownVerticalOffset);
+                    mDropDownHorizontalOffset, mDropDownVerticalOffset, mDropDownGravity);
             mDropDownList.setSelection(ListView.INVALID_POSITION);
             
             if (!mModal || mDropDownList.isInTouchMode()) {
@@ -821,8 +843,7 @@
             // to select one of its items
             if (keyCode != KeyEvent.KEYCODE_SPACE
                     && (mDropDownList.getSelectedItemPosition() >= 0
-                            || (keyCode != KeyEvent.KEYCODE_ENTER
-                                    && keyCode != KeyEvent.KEYCODE_DPAD_CENTER))) {
+                            || !KeyEvent.isConfirmKey(keyCode))) {
                 int curIndex = mDropDownList.getSelectedItemPosition();
                 boolean consumed;
 
@@ -910,16 +931,10 @@
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
             boolean consumed = mDropDownList.onKeyUp(keyCode, event);
-            if (consumed) {
-                switch (keyCode) {
-                    // if the list accepts the key events and the key event
-                    // was a click, the text view gets the selected item
-                    // from the drop down as its content
-                    case KeyEvent.KEYCODE_ENTER:
-                    case KeyEvent.KEYCODE_DPAD_CENTER:
-                        dismiss();
-                        break;
-                }
+            if (consumed && KeyEvent.isConfirmKey(keyCode)) {
+                // if the list accepts the key events and the key event was a click, the text view
+                // gets the selected item from the drop down as its content
+                dismiss();
             }
             return consumed;
         }
@@ -963,6 +978,35 @@
     }
 
     /**
+     * Returns an {@link OnTouchListener} that can be added to the source view
+     * to implement drag-to-open behavior. Generally, the source view should be
+     * the same view that was passed to {@link #setAnchorView}.
+     * <p>
+     * When the listener is set on a view, touching that view and dragging
+     * outside of its bounds will open the popup window. Lifting will select the
+     * currently touched list item.
+     * <p>
+     * Example usage:
+     * <pre>
+     * ListPopupWindow myPopup = new ListPopupWindow(context);
+     * myPopup.setAnchor(myAnchor);
+     * OnTouchListener dragListener = myPopup.createDragToOpenListener(myAnchor);
+     * myAnchor.setOnTouchListener(dragListener);
+     * </pre>
+     *
+     * @param src the view on which the resulting listener will be set
+     * @return a touch listener that controls drag-to-open behavior
+     */
+    public OnTouchListener createDragToOpenListener(View src) {
+        return new ForwardingListener(src) {
+            @Override
+            public ListPopupWindow getPopup() {
+                return ListPopupWindow.this;
+            }
+        };
+    }
+
+    /**
      * <p>Builds the popup window's content and returns the height the popup
      * should have. Returns -1 when the content already exists.</p>
      *
@@ -1130,13 +1174,225 @@
     }
 
     /**
+     * Abstract class that forwards touch events to a {@link ListPopupWindow}.
+     *
+     * @hide
+     */
+    public static abstract class ForwardingListener
+            implements View.OnTouchListener, View.OnAttachStateChangeListener {
+        /** Scaled touch slop, used for detecting movement outside bounds. */
+        private final float mScaledTouchSlop;
+
+        /** Timeout before disallowing intercept on the source's parent. */
+        private final int mTapTimeout;
+
+        /** Source view from which events are forwarded. */
+        private final View mSrc;
+
+        /** Runnable used to prevent conflicts with scrolling parents. */
+        private Runnable mDisallowIntercept;
+
+        /** Whether this listener is currently forwarding touch events. */
+        private boolean mForwarding;
+
+        /** The id of the first pointer down in the current event stream. */
+        private int mActivePointerId;
+
+        public ForwardingListener(View src) {
+            mSrc = src;
+            mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
+            mTapTimeout = ViewConfiguration.getTapTimeout();
+
+            src.addOnAttachStateChangeListener(this);
+        }
+
+        /**
+         * Returns the popup to which this listener is forwarding events.
+         * <p>
+         * Override this to return the correct popup. If the popup is displayed
+         * asynchronously, you may also need to override
+         * {@link #onForwardingStopped} to prevent premature cancelation of
+         * forwarding.
+         *
+         * @return the popup to which this listener is forwarding events
+         */
+        public abstract ListPopupWindow getPopup();
+
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            final boolean wasForwarding = mForwarding;
+            final boolean forwarding;
+            if (wasForwarding) {
+                forwarding = onTouchForwarded(event) || !onForwardingStopped();
+            } else {
+                forwarding = onTouchObserved(event) && onForwardingStarted();
+            }
+
+            mForwarding = forwarding;
+            return forwarding || wasForwarding;
+        }
+
+        @Override
+        public void onViewAttachedToWindow(View v) {
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mForwarding = false;
+            mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+            if (mDisallowIntercept != null) {
+                mSrc.removeCallbacks(mDisallowIntercept);
+            }
+        }
+
+        /**
+         * Called when forwarding would like to start.
+         * <p>
+         * By default, this will show the popup returned by {@link #getPopup()}.
+         * It may be overridden to perform another action, like clicking the
+         * source view or preparing the popup before showing it.
+         *
+         * @return true to start forwarding, false otherwise
+         */
+        protected boolean onForwardingStarted() {
+            final ListPopupWindow popup = getPopup();
+            if (popup != null && !popup.isShowing()) {
+                popup.show();
+            }
+            return true;
+        }
+
+        /**
+         * Called when forwarding would like to stop.
+         * <p>
+         * By default, this will dismiss the popup returned by
+         * {@link #getPopup()}. It may be overridden to perform some other
+         * action.
+         *
+         * @return true to stop forwarding, false otherwise
+         */
+        protected boolean onForwardingStopped() {
+            final ListPopupWindow popup = getPopup();
+            if (popup != null && popup.isShowing()) {
+                popup.dismiss();
+            }
+            return true;
+        }
+
+        /**
+         * Observes motion events and determines when to start forwarding.
+         *
+         * @param srcEvent motion event in source view coordinates
+         * @return true to start forwarding motion events, false otherwise
+         */
+        private boolean onTouchObserved(MotionEvent srcEvent) {
+            final View src = mSrc;
+            if (!src.isEnabled()) {
+                return false;
+            }
+
+            final int actionMasked = srcEvent.getActionMasked();
+            switch (actionMasked) {
+                case MotionEvent.ACTION_DOWN:
+                    mActivePointerId = srcEvent.getPointerId(0);
+                    if (mDisallowIntercept == null) {
+                        mDisallowIntercept = new DisallowIntercept();
+                    }
+                    src.postDelayed(mDisallowIntercept, mTapTimeout);
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
+                    if (activePointerIndex >= 0) {
+                        final float x = srcEvent.getX(activePointerIndex);
+                        final float y = srcEvent.getY(activePointerIndex);
+                        if (!src.pointInView(x, y, mScaledTouchSlop)) {
+                            // The pointer has moved outside of the view.
+                            if (mDisallowIntercept != null) {
+                                src.removeCallbacks(mDisallowIntercept);
+                            }
+                            src.getParent().requestDisallowInterceptTouchEvent(true);
+                            return true;
+                        }
+                    }
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_UP:
+                    if (mDisallowIntercept != null) {
+                        src.removeCallbacks(mDisallowIntercept);
+                    }
+                    break;
+            }
+
+            return false;
+        }
+
+        /**
+         * Handled forwarded motion events and determines when to stop
+         * forwarding.
+         *
+         * @param srcEvent motion event in source view coordinates
+         * @return true to continue forwarding motion events, false to cancel
+         */
+        private boolean onTouchForwarded(MotionEvent srcEvent) {
+            final View src = mSrc;
+            final ListPopupWindow popup = getPopup();
+            if (popup == null || !popup.isShowing()) {
+                return false;
+            }
+
+            final DropDownListView dst = popup.mDropDownList;
+            if (dst == null || !dst.isShown()) {
+                return false;
+            }
+
+            // Convert event to destination-local coordinates.
+            final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
+            src.toGlobalMotionEvent(dstEvent);
+            dst.toLocalMotionEvent(dstEvent);
+
+            // Forward converted event to destination view, then recycle it.
+            final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId);
+            dstEvent.recycle();
+            return handled;
+        }
+
+        private class DisallowIntercept implements Runnable {
+            @Override
+            public void run() {
+                final ViewParent parent = mSrc.getParent();
+                parent.requestDisallowInterceptTouchEvent(true);
+            }
+        }
+    }
+
+    /**
      * <p>Wrapper class for a ListView. This wrapper can hijack the focus to
      * make sure the list uses the appropriate drawables and states when
      * displayed on screen within a drop down. The focus is never actually
      * passed to the drop down in this mode; the list only looks focused.</p>
      */
     private static class DropDownListView extends ListView {
-        private static final String TAG = ListPopupWindow.TAG + ".DropDownListView";
+        /** Duration in milliseconds of the drag-to-open click animation. */
+        private static final long CLICK_ANIM_DURATION = 150;
+
+        /** Target alpha value for drag-to-open click animation. */
+        private static final int CLICK_ANIM_ALPHA = 0x80;
+
+        /** Wrapper around Drawable's <code>alpha</code> property. */
+        private static final IntProperty<Drawable> DRAWABLE_ALPHA =
+                new IntProperty<Drawable>("alpha") {
+                    @Override
+                    public void setValue(Drawable object, int value) {
+                        object.setAlpha(value);
+                    }
+
+                    @Override
+                    public Integer get(Drawable object) {
+                        return object.getAlpha();
+                    }
+                };
+
         /*
          * WARNING: This is a workaround for a touch mode issue.
          *
@@ -1172,6 +1428,15 @@
          */
         private boolean mHijackFocus;
 
+        /** Whether to force drawing of the pressed state selector. */
+        private boolean mDrawsInPressedState;
+
+        /** Current drag-to-open click animation, if any. */
+        private Animator mClickAnimation;
+
+        /** Helper for drag-to-open auto scrolling. */
+        private AbsListViewAutoScroller mScrollHelper;
+
         /**
          * <p>Creates a new list view wrapper.</p>
          *
@@ -1185,6 +1450,130 @@
         }
 
         /**
+         * Handles forwarded events.
+         *
+         * @param activePointerId id of the pointer that activated forwarding
+         * @return whether the event was handled
+         */
+        public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
+            boolean handledEvent = true;
+            boolean clearPressedItem = false;
+
+            final int actionMasked = event.getActionMasked();
+            switch (actionMasked) {
+                case MotionEvent.ACTION_CANCEL:
+                    handledEvent = false;
+                    break;
+                case MotionEvent.ACTION_UP:
+                    handledEvent = false;
+                    // $FALL-THROUGH$
+                case MotionEvent.ACTION_MOVE:
+                    final int activeIndex = event.findPointerIndex(activePointerId);
+                    if (activeIndex < 0) {
+                        handledEvent = false;
+                        break;
+                    }
+
+                    final int x = (int) event.getX(activeIndex);
+                    final int y = (int) event.getY(activeIndex);
+                    final int position = pointToPosition(x, y);
+                    if (position == INVALID_POSITION) {
+                        clearPressedItem = true;
+                        break;
+                    }
+
+                    final View child = getChildAt(position - getFirstVisiblePosition());
+                    setPressedItem(child, position);
+                    handledEvent = true;
+
+                    if (actionMasked == MotionEvent.ACTION_UP) {
+                        clickPressedItem(child, position);
+                    }
+                    break;
+            }
+
+            // Failure to handle the event cancels forwarding.
+            if (!handledEvent || clearPressedItem) {
+                clearPressedItem();
+            }
+
+            // Manage automatic scrolling.
+            if (handledEvent) {
+                if (mScrollHelper == null) {
+                    mScrollHelper = new AbsListViewAutoScroller(this);
+                }
+                mScrollHelper.setEnabled(true);
+                mScrollHelper.onTouch(this, event);
+            } else if (mScrollHelper != null) {
+                mScrollHelper.setEnabled(false);
+            }
+
+            return handledEvent;
+        }
+
+        /**
+         * Starts an alpha animation on the selector. When the animation ends,
+         * the list performs a click on the item.
+         */
+        private void clickPressedItem(final View child, final int position) {
+            final long id = getItemIdAtPosition(position);
+            final Animator anim = ObjectAnimator.ofInt(
+                    mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
+            anim.setDuration(CLICK_ANIM_DURATION);
+            anim.setInterpolator(new AccelerateDecelerateInterpolator());
+            anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                public void onAnimationEnd(Animator animation) {
+                    performItemClick(child, position, id);
+                }
+            });
+            anim.start();
+
+            if (mClickAnimation != null) {
+                mClickAnimation.cancel();
+            }
+            mClickAnimation = anim;
+        }
+
+        private void clearPressedItem() {
+            mDrawsInPressedState = false;
+            setPressed(false);
+            updateSelectorState();
+
+            if (mClickAnimation != null) {
+                mClickAnimation.cancel();
+                mClickAnimation = null;
+            }
+        }
+
+        private void setPressedItem(View child, int position) {
+            mDrawsInPressedState = true;
+
+            // Ordering is essential. First update the pressed state and layout
+            // the children. This will ensure the selector actually gets drawn.
+            setPressed(true);
+            layoutChildren();
+
+            // Ensure that keyboard focus starts from the last touched position.
+            setSelectedPositionInt(position);
+            positionSelector(position, child);
+
+            // Refresh the drawable state to reflect the new pressed state,
+            // which will also update the selector state.
+            refreshDrawableState();
+
+            if (mClickAnimation != null) {
+                mClickAnimation.cancel();
+                mClickAnimation = null;
+            }
+        }
+
+        @Override
+        boolean touchModeDrawsInPressedState() {
+            return mDrawsInPressedState || super.touchModeDrawsInPressedState();
+        }
+
+        /**
          * <p>Avoids jarring scrolling effect by ensuring that list elements
          * made of a text view fit on a single line.</p>
          *
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index f42999d..4b00f90 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.os.Trace;
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.google.android.collect.Lists;
@@ -41,7 +42,8 @@
 import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
+import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
 import android.widget.RemoteViews.RemoteView;
 
 import java.util.ArrayList;
@@ -240,35 +242,39 @@
     }
 
     /**
-     * Add a fixed view to appear at the top of the list. If addHeaderView is
+     * Add a fixed view to appear at the top of the list. If this method is
      * called more than once, the views will appear in the order they were
      * added. Views added using this call can take focus if they want.
      * <p>
-     * NOTE: Call this before calling setAdapter. This is so ListView can wrap
-     * the supplied cursor with one that will also account for header and footer
-     * views.
+     * Note: When first introduced, this method could only be called before
+     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
+     * called at any time. If the ListView's adapter does not extend
+     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
+     * instance of {@link WrapperListAdapter}.
      *
      * @param v The view to add.
      * @param data Data to associate with this view
      * @param isSelectable whether the item is selectable
      */
     public void addHeaderView(View v, Object data, boolean isSelectable) {
-
-        if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) {
-            throw new IllegalStateException(
-                    "Cannot add header view to list -- setAdapter has already been called.");
-        }
-
-        FixedViewInfo info = new FixedViewInfo();
+        final FixedViewInfo info = new FixedViewInfo();
         info.view = v;
         info.data = data;
         info.isSelectable = isSelectable;
         mHeaderViewInfos.add(info);
 
-        // in the case of re-adding a header view, or adding one later on,
-        // we need to notify the observer
-        if (mAdapter != null && mDataSetObserver != null) {
-            mDataSetObserver.onChanged();
+        // Wrap the adapter if it wasn't already wrapped.
+        if (mAdapter != null) {
+            if (!(mAdapter instanceof HeaderViewListAdapter)) {
+                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
+            }
+
+            // In the case of re-adding a header view, or adding one later on,
+            // we need to notify the observer.
+            if (mDataSetObserver != null) {
+                mDataSetObserver.onChanged();
+            }
         }
     }
 
@@ -277,9 +283,12 @@
      * called more than once, the views will appear in the order they were
      * added. Views added using this call can take focus if they want.
      * <p>
-     * NOTE: Call this before calling setAdapter. This is so ListView can wrap
-     * the supplied cursor with one that will also account for header and footer
-     * views.
+     * Note: When first introduced, this method could only be called before
+     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
+     * called at any time. If the ListView's adapter does not extend
+     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
+     * instance of {@link WrapperListAdapter}.
      *
      * @param v The view to add.
      */
@@ -330,41 +339,49 @@
      * called more than once, the views will appear in the order they were
      * added. Views added using this call can take focus if they want.
      * <p>
-     * NOTE: Call this before calling setAdapter. This is so ListView can wrap
-     * the supplied cursor with one that will also account for header and footer
-     * views.
+     * Note: When first introduced, this method could only be called before
+     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
+     * called at any time. If the ListView's adapter does not extend
+     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
+     * instance of {@link WrapperListAdapter}.
      *
      * @param v The view to add.
      * @param data Data to associate with this view
      * @param isSelectable true if the footer view can be selected
      */
     public void addFooterView(View v, Object data, boolean isSelectable) {
-
-        // NOTE: do not enforce the adapter being null here, since unlike in
-        // addHeaderView, it was never enforced here, and so existing apps are
-        // relying on being able to add a footer and then calling setAdapter to
-        // force creation of the HeaderViewListAdapter wrapper
-
-        FixedViewInfo info = new FixedViewInfo();
+        final FixedViewInfo info = new FixedViewInfo();
         info.view = v;
         info.data = data;
         info.isSelectable = isSelectable;
         mFooterViewInfos.add(info);
 
-        // in the case of re-adding a footer view, or adding one later on,
-        // we need to notify the observer
-        if (mAdapter != null && mDataSetObserver != null) {
-            mDataSetObserver.onChanged();
+        // Wrap the adapter if it wasn't already wrapped.
+        if (mAdapter != null) {
+            if (!(mAdapter instanceof HeaderViewListAdapter)) {
+                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
+            }
+
+            // In the case of re-adding a footer view, or adding one later on,
+            // we need to notify the observer.
+            if (mDataSetObserver != null) {
+                mDataSetObserver.onChanged();
+            }
         }
     }
 
     /**
-     * Add a fixed view to appear at the bottom of the list. If addFooterView is called more
-     * than once, the views will appear in the order they were added. Views added using
-     * this call can take focus if they want.
-     * <p>NOTE: Call this before calling setAdapter. This is so ListView can wrap the supplied
-     * cursor with one that will also account for header and footer views.
-     *
+     * Add a fixed view to appear at the bottom of the list. If addFooterView is
+     * called more than once, the views will appear in the order they were
+     * added. Views added using this call can take focus if they want.
+     * <p>
+     * Note: When first introduced, this method could only be called before
+     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
+     * called at any time. If the ListView's adapter does not extend
+     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
+     * instance of {@link WrapperListAdapter}.
      *
      * @param v The view to add.
      */
@@ -1462,12 +1479,12 @@
     @Override
     protected void layoutChildren() {
         final boolean blockLayoutRequests = mBlockLayoutRequests;
-        if (!blockLayoutRequests) {
-            mBlockLayoutRequests = true;
-        } else {
+        if (blockLayoutRequests) {
             return;
         }
 
+        mBlockLayoutRequests = true;
+
         try {
             super.layoutChildren();
 
@@ -1479,10 +1496,10 @@
                 return;
             }
 
-            int childrenTop = mListPadding.top;
-            int childrenBottom = mBottom - mTop - mListPadding.bottom;
+            final int childrenTop = mListPadding.top;
+            final int childrenBottom = mBottom - mTop - mListPadding.bottom;
+            final int childCount = getChildCount();
 
-            int childCount = getChildCount();
             int index = 0;
             int delta = 0;
 
@@ -1491,12 +1508,6 @@
             View oldFirst = null;
             View newSel = null;
 
-            View focusLayoutRestoreView = null;
-
-            AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
-            View accessibilityFocusLayoutRestoreView = null;
-            int accessibilityFocusPosition = INVALID_POSITION;
-
             // Remember stuff we will need down below
             switch (mLayoutMode) {
             case LAYOUT_SET_SELECTION:
@@ -1544,49 +1555,36 @@
             } else if (mItemCount != mAdapter.getCount()) {
                 throw new IllegalStateException("The content of the adapter has changed but "
                         + "ListView did not receive a notification. Make sure the content of "
-                        + "your adapter is not modified from a background thread, but only "
-                        + "from the UI thread. [in ListView(" + getId() + ", " + getClass() 
+                        + "your adapter is not modified from a background thread, but only from "
+                        + "the UI thread. Make sure your adapter calls notifyDataSetChanged() "
+                        + "when its content changes. [in ListView(" + getId() + ", " + getClass()
                         + ") with Adapter(" + mAdapter.getClass() + ")]");
             }
 
             setSelectedPositionInt(mNextSelectedPosition);
 
-            // Remember which child, if any, had accessibility focus. This must
-            // occur before recycling any views, since that will clear
-            // accessibility focus.
-            final ViewRootImpl viewRootImpl = getViewRootImpl();
-            if (viewRootImpl != null) {
-                final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost();
-                if (accessFocusedView != null) {
-                    final View accessFocusedChild = findAccessibilityFocusedChild(
-                            accessFocusedView);
-                    if (accessFocusedChild != null) {
-                        if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) {
-                            // If the views won't be changing, try to maintain
-                            // focus on the current view host and (if
-                            // applicable) its virtual view.
-                            accessibilityFocusLayoutRestoreView = accessFocusedView;
-                            accessibilityFocusLayoutRestoreNode = viewRootImpl
-                                    .getAccessibilityFocusedVirtualView();
-                        } else {
-                            // Otherwise, try to maintain focus at the same
-                            // position.
-                            accessibilityFocusPosition = getPositionForView(accessFocusedChild);
-                        }
-                    }
-                }
+            // Remember which child, if any, had accessibility focus.
+            final int accessibilityFocusPosition;
+            final View accessFocusedChild = getAccessibilityFocusedChild();
+            if (accessFocusedChild != null) {
+                accessibilityFocusPosition = getPositionForView(accessFocusedChild);
+                accessFocusedChild.setHasTransientState(true);
+            } else {
+                accessibilityFocusPosition = INVALID_POSITION;
+            }
+
+            // Ensure the child containing focus, if any, has transient state.
+            // If the list data hasn't changed, or if the adapter has stable
+            // IDs, this will maintain focus.
+            final View focusedChild = getFocusedChild();
+            if (focusedChild != null) {
+                focusedChild.setHasTransientState(true);
             }
 
             // Pull all children into the RecycleBin.
             // These views will be reused if possible
             final int firstPosition = mFirstPosition;
             final RecycleBin recycleBin = mRecycler;
-
-            // reset the focus restoration
-            View focusLayoutRestoreDirectChild = null;
-
-            // Don't put header or footer views into the Recycler. Those are
-            // already cached in mHeaderViews;
             if (dataChanged) {
                 for (int i = 0; i < childCount; i++) {
                     recycleBin.addScrapView(getChildAt(i), firstPosition+i);
@@ -1595,28 +1593,6 @@
                 recycleBin.fillActiveViews(childCount, firstPosition);
             }
 
-            // take focus back to us temporarily to avoid the eventual
-            // call to clear focus when removing the focused child below
-            // from messing things up when ViewAncestor assigns focus back
-            // to someone else
-            final View focusedChild = getFocusedChild();
-            if (focusedChild != null) {
-                // TODO: in some cases focusedChild.getParent() == null
-
-                // we can remember the focused view to restore after relayout if the
-                // data hasn't changed, or if the focused position is a header or footer
-                if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) {
-                    focusLayoutRestoreDirectChild = focusedChild;
-                    // remember the specific view that had focus
-                    focusLayoutRestoreView = findFocus();
-                    if (focusLayoutRestoreView != null) {
-                        // tell it we are going to mess with it
-                        focusLayoutRestoreView.onStartTemporaryDetach();
-                    }
-                }
-                requestFocus();
-            }
-
             // Clear out old views
             detachAllViewsFromParent();
             recycleBin.removeSkippedScrap();
@@ -1676,72 +1652,58 @@
             recycleBin.scrapActiveViews();
 
             if (sel != null) {
-                // the current selected item should get focus if items
-                // are focusable
-                if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
-                    final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
-                            focusLayoutRestoreView != null &&
-                            focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
-                    if (!focusWasTaken) {
-                        // selected item didn't take focus, fine, but still want
-                        // to make sure something else outside of the selected view
-                        // has focus
+                final boolean shouldPlaceFocus = mItemsCanFocus && hasFocus();
+                final boolean maintainedFocus = focusedChild != null && focusedChild.hasFocus();
+                if (shouldPlaceFocus && !maintainedFocus && !sel.hasFocus()) {
+                    if (sel.requestFocus()) {
+                        // Successfully placed focus, clear selection.
+                        sel.setSelected(false);
+                        mSelectorRect.setEmpty();
+                    } else {
+                        // Failed to place focus, clear current (invalid) focus.
                         final View focused = getFocusedChild();
                         if (focused != null) {
                             focused.clearFocus();
                         }
                         positionSelector(INVALID_POSITION, sel);
-                    } else {
-                        sel.setSelected(false);
-                        mSelectorRect.setEmpty();
                     }
                 } else {
                     positionSelector(INVALID_POSITION, sel);
                 }
                 mSelectedTop = sel.getTop();
             } else {
-                if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
-                    View child = getChildAt(mMotionPosition - mFirstPosition);
-                    if (child != null) positionSelector(mMotionPosition, child);
+                // If the user's finger is down, select the motion position.
+                // Otherwise, clear selection.
+                if (mTouchMode == TOUCH_MODE_TAP || mTouchMode == TOUCH_MODE_DONE_WAITING) {
+                    final View child = getChildAt(mMotionPosition - mFirstPosition);
+                    if (child != null)  {
+                        positionSelector(mMotionPosition, child);
+                    }
                 } else {
                     mSelectedTop = 0;
                     mSelectorRect.setEmpty();
                 }
+            }
 
-                // even if there is not selected position, we may need to restore
-                // focus (i.e. something focusable in touch mode)
-                if (hasFocus() && focusLayoutRestoreView != null) {
-                    focusLayoutRestoreView.requestFocus();
+            if (accessFocusedChild != null) {
+                accessFocusedChild.setHasTransientState(false);
+
+                // If we failed to maintain accessibility focus on the previous
+                // view, attempt to restore it to the previous position.
+                if (!accessFocusedChild.isAccessibilityFocused()
+                    && accessibilityFocusPosition != INVALID_POSITION) {
+                    // Bound the position within the visible children.
+                    final int position = MathUtils.constrain(
+                            accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1);
+                    final View restoreView = getChildAt(position);
+                    if (restoreView != null) {
+                        restoreView.requestAccessibilityFocus();
+                    }
                 }
             }
 
-            // Attempt to restore accessibility focus.
-            if (accessibilityFocusLayoutRestoreView != null) {
-                final AccessibilityNodeProvider provider =
-                        accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
-                if ((accessibilityFocusLayoutRestoreNode != null) && (provider != null)) {
-                    final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
-                            accessibilityFocusLayoutRestoreNode.getSourceNodeId());
-                    provider.performAction(virtualViewId,
-                            AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
-                } else {
-                    accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
-                }
-            } else if (accessibilityFocusPosition != INVALID_POSITION) {
-                // Bound the position within the visible children.
-                final int position = MathUtils.constrain(
-                        (accessibilityFocusPosition - mFirstPosition), 0, (getChildCount() - 1));
-                final View restoreView = getChildAt(position);
-                if (restoreView != null) {
-                    restoreView.requestAccessibilityFocus();
-                }
-            }
-
-            // tell focus view we are done mucking with it, if it is still in
-            // our view hierarchy.
-            if (focusLayoutRestoreView != null
-                    && focusLayoutRestoreView.getWindowToken() != null) {
-                focusLayoutRestoreView.onFinishTemporaryDetach();
+            if (focusedChild != null) {
+                focusedChild.setHasTransientState(false);
             }
             
             mLayoutMode = LAYOUT_NORMAL;
@@ -1768,45 +1730,34 @@
     }
 
     /**
-     * @param focusedView the view that has accessibility focus.
-     * @return the direct child that contains accessibility focus.
+     * @return the direct child that contains accessibility focus, or null if no
+     *         child contains accessibility focus
      */
-    private View findAccessibilityFocusedChild(View focusedView) {
+    private View getAccessibilityFocusedChild() {
+        final ViewRootImpl viewRootImpl = getViewRootImpl();
+        if (viewRootImpl == null) {
+            return null;
+        }
+
+        View focusedView = viewRootImpl.getAccessibilityFocusedHost();
+        if (focusedView == null) {
+            return null;
+        }
+
         ViewParent viewParent = focusedView.getParent();
         while ((viewParent instanceof View) && (viewParent != this)) {
             focusedView = (View) viewParent;
             viewParent = viewParent.getParent();
         }
+
         if (!(viewParent instanceof View)) {
             return null;
         }
+
         return focusedView;
     }
 
     /**
-     * @param child a direct child of this list.
-     * @return Whether child is a header or footer view.
-     */
-    private boolean isDirectChildHeaderOrFooter(View child) {
-
-        final ArrayList<FixedViewInfo> headers = mHeaderViewInfos;
-        final int numHeaders = headers.size();
-        for (int i = 0; i < numHeaders; i++) {
-            if (child == headers.get(i).view) {
-                return true;
-            }
-        }
-        final ArrayList<FixedViewInfo> footers = mFooterViewInfos;
-        final int numFooters = footers.size();
-        for (int i = 0; i < numFooters; i++) {
-            if (child == footers.get(i).view) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
      * Obtain the view and add it to our list of children. The view can be made
      * fresh, converted from an unused view, or used as is if it was in the
      * recycle bin.
@@ -1861,6 +1812,8 @@
      */
     private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
             boolean selected, boolean recycled) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "setupListItem");
+
         final boolean isSelected = selected && shouldShowSelector();
         final boolean updateChildSelected = isSelected != child.isSelected();
         final int mode = mTouchMode;
@@ -1941,6 +1894,8 @@
                 != position) {
             child.jumpDrawablesToCurrentState();
         }
+
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
     }
 
     @Override
@@ -2058,17 +2013,61 @@
                     position--;
                 }
             }
-
-            if (position < 0 || position >= count) {
-                return INVALID_POSITION;
-            }
-            return position;
-        } else {
-            if (position < 0 || position >= count) {
-                return INVALID_POSITION;
-            }
-            return position;
         }
+
+        if (position < 0 || position >= count) {
+            return INVALID_POSITION;
+        }
+
+        return position;
+    }
+
+    /**
+     * Find a position that can be selected (i.e., is not a separator). If there
+     * are no selectable positions in the specified direction from the starting
+     * position, searches in the opposite direction from the starting position
+     * to the current position.
+     *
+     * @param current the current position
+     * @param position the starting position
+     * @param lookDown whether to look down for other positions
+     * @return the next selectable position, or {@link #INVALID_POSITION} if
+     *         nothing can be found
+     */
+    int lookForSelectablePositionAfter(int current, int position, boolean lookDown) {
+        final ListAdapter adapter = mAdapter;
+        if (adapter == null || isInTouchMode()) {
+            return INVALID_POSITION;
+        }
+
+        // First check after the starting position in the specified direction.
+        final int after = lookForSelectablePosition(position, lookDown);
+        if (after != INVALID_POSITION) {
+            return after;
+        }
+
+        // Then check between the starting position and the current position.
+        final int count = adapter.getCount();
+        current = MathUtils.constrain(current, -1, count - 1);
+        if (lookDown) {
+            position = Math.min(position - 1, count - 1);
+            while ((position > current) && !adapter.isEnabled(position)) {
+                position--;
+            }
+            if (position <= current) {
+                return INVALID_POSITION;
+            }
+        } else {
+            position = Math.max(0, position + 1);
+            while ((position < current) && !adapter.isEnabled(position)) {
+                position++;
+            }
+            if (position >= current) {
+                return INVALID_POSITION;
+            }
+        }
+
+        return position;
     }
 
     /**
@@ -2123,7 +2122,7 @@
     }
 
     private boolean commonKey(int keyCode, int count, KeyEvent event) {
-        if (mAdapter == null || !mIsAttached) {
+        if (mAdapter == null || !isAttachedToWindow()) {
             return false;
         }
 
@@ -2281,27 +2280,30 @@
      * @return whether selection was moved
      */
     boolean pageScroll(int direction) {
-        int nextPage = -1;
-        boolean down = false;
+        final int nextPage;
+        final boolean down;
 
         if (direction == FOCUS_UP) {
             nextPage = Math.max(0, mSelectedPosition - getChildCount() - 1);
+            down = false;
         } else if (direction == FOCUS_DOWN) {
             nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount() - 1);
             down = true;
+        } else {
+            return false;
         }
 
         if (nextPage >= 0) {
-            int position = lookForSelectablePosition(nextPage, down);
+            final int position = lookForSelectablePositionAfter(mSelectedPosition, nextPage, down);
             if (position >= 0) {
                 mLayoutMode = LAYOUT_SPECIFIC;
                 mSpecificTop = mPaddingTop + getVerticalFadingEdgeLength();
 
-                if (down && position > mItemCount - getChildCount()) {
+                if (down && (position > (mItemCount - getChildCount()))) {
                     mLayoutMode = LAYOUT_FORCE_BOTTOM;
                 }
 
-                if (!down && position < getChildCount()) {
+                if (!down && (position < getChildCount())) {
                     mLayoutMode = LAYOUT_FORCE_TOP;
                 }
 
@@ -2319,18 +2321,18 @@
     }
 
     /**
-     * Go to the last or first item if possible (not worrying about panning across or navigating
-     * within the internal focus of the currently selected item.)
+     * Go to the last or first item if possible (not worrying about panning
+     * across or navigating within the internal focus of the currently selected
+     * item.)
      *
      * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
-     *
      * @return whether selection was moved
      */
     boolean fullScroll(int direction) {
         boolean moved = false;
         if (direction == FOCUS_UP) {
             if (mSelectedPosition != 0) {
-                int position = lookForSelectablePosition(0, true);
+                final int position = lookForSelectablePositionAfter(mSelectedPosition, 0, true);
                 if (position >= 0) {
                     mLayoutMode = LAYOUT_FORCE_TOP;
                     setSelectionInt(position);
@@ -2339,8 +2341,10 @@
                 moved = true;
             }
         } else if (direction == FOCUS_DOWN) {
-            if (mSelectedPosition < mItemCount - 1) {
-                int position = lookForSelectablePosition(mItemCount - 1, true);
+            final int lastItem = (mItemCount - 1);
+            if (mSelectedPosition < lastItem) {
+                final int position = lookForSelectablePositionAfter(
+                        mSelectedPosition, lastItem, false);
                 if (position >= 0) {
                     mLayoutMode = LAYOUT_FORCE_BOTTOM;
                     setSelectionInt(position);
@@ -2425,24 +2429,37 @@
 
     /**
      * Used by {@link #arrowScrollImpl(int)} to help determine the next selected position
-     * to move to. This can return a position currently not represented by a view on screen
-     * but only in the direction given.
+     * to move to. This return a position in the direction given if the selected item
+     * is fully visible.
      *
+     * @param selectedView Current selected view to move from
      * @param selectedPos Current selected position to move from
      * @param direction Direction to move in
      * @return Desired selected position after moving in the given direction
      */
-    private final int nextSelectedPositionForDirection(int selectedPos, int direction) {
+    private final int nextSelectedPositionForDirection(
+            View selectedView, int selectedPos, int direction) {
         int nextSelected;
+
         if (direction == View.FOCUS_DOWN) {
-            nextSelected = selectedPos != INVALID_POSITION && selectedPos >= mFirstPosition ?
-                    selectedPos + 1 :
-                    mFirstPosition;
+            final int listBottom = getHeight() - mListPadding.bottom;
+            if (selectedView != null && selectedView.getBottom() <= listBottom) {
+                nextSelected = selectedPos != INVALID_POSITION && selectedPos >= mFirstPosition ?
+                        selectedPos + 1 :
+                        mFirstPosition;
+            } else {
+                return INVALID_POSITION;
+            }
         } else {
-            final int lastPos = mFirstPosition + getChildCount() - 1;
-            nextSelected = selectedPos != INVALID_POSITION && selectedPos <= lastPos ?
-                    selectedPos - 1 :
-                    lastPos;
+            final int listTop = mListPadding.top;
+            if (selectedView != null && selectedView.getTop() >= listTop) {
+                final int lastPos = mFirstPosition + getChildCount() - 1;
+                nextSelected = selectedPos != INVALID_POSITION && selectedPos <= lastPos ?
+                        selectedPos - 1 :
+                        lastPos;
+            } else {
+                return INVALID_POSITION;
+            }
         }
 
         if (nextSelected < 0 || nextSelected >= mAdapter.getCount()) {
@@ -2466,7 +2483,7 @@
         View selectedView = getSelectedView();
         int selectedPos = mSelectedPosition;
 
-        int nextSelectedPosition = nextSelectedPositionForDirection(selectedPos, direction);
+        int nextSelectedPosition = nextSelectedPositionForDirection(selectedView, selectedPos, direction);
         int amountToScroll = amountToScroll(direction, nextSelectedPosition);
 
         // if we are moving focus, we may OVERRIDE the default behavior
@@ -3195,7 +3212,7 @@
             final int count = getChildCount();
             final int headerCount = mHeaderViewInfos.size();
             final int itemCount = mItemCount;
-            final int footerLimit = itemCount - mFooterViewInfos.size() - 1;
+            final int footerLimit = (itemCount - mFooterViewInfos.size());
             final boolean headerDividers = mHeaderDividersEnabled;
             final boolean footerDividers = mFooterDividersEnabled;
             final int first = mFirstPosition;
@@ -3239,17 +3256,25 @@
                 }
 
                 for (int i = 0; i < count; i++) {
-                    if ((headerDividers || first + i >= headerCount) &&
-                            (footerDividers || first + i < footerLimit)) {
-                        View child = getChildAt(i);
+                    final int itemIndex = (first + i);
+                    final boolean isHeader = (itemIndex < headerCount);
+                    final boolean isFooter = (itemIndex >= footerLimit);
+                    if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
+                        final View child = getChildAt(i);
                         bottom = child.getBottom();
-                        // Don't draw dividers next to items that are not enabled
+                        final boolean isLastItem = (i == (count - 1));
 
-                        if (drawDividers &&
-                                (bottom < listBottom && !(drawOverscrollFooter && i == count - 1))) {
-                            if ((areAllItemsSelectable ||
-                                    (adapter.isEnabled(first + i) && (i == count - 1 ||
-                                            adapter.isEnabled(first + i + 1))))) {
+                        if (drawDividers && (bottom < listBottom)
+                                && !(drawOverscrollFooter && isLastItem)) {
+                            final int nextIndex = (itemIndex + 1);
+                            // Draw dividers between enabled items, headers and/or
+                            // footers when enabled, and the end of the list.
+                            if (areAllItemsSelectable || ((adapter.isEnabled(itemIndex)
+                                    || (headerDividers && isHeader)
+                                    || (footerDividers && isFooter)) && (isLastItem
+                                    || adapter.isEnabled(nextIndex)
+                                    || (headerDividers && (nextIndex < headerCount))
+                                    || (footerDividers && (nextIndex >= footerLimit))))) {
                                 bounds.top = bottom;
                                 bounds.bottom = bottom + dividerHeight;
                                 drawDivider(canvas, bounds, i);
@@ -3282,20 +3307,28 @@
 
                 final int start = drawOverscrollHeader ? 1 : 0;
                 for (int i = start; i < count; i++) {
-                    if ((headerDividers || first + i >= headerCount) &&
-                            (footerDividers || first + i < footerLimit)) {
-                        View child = getChildAt(i);
+                    final int itemIndex = (first + i);
+                    final boolean isHeader = (itemIndex < headerCount);
+                    final boolean isFooter = (itemIndex >= footerLimit);
+                    if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
+                        final View child = getChildAt(i);
                         top = child.getTop();
-                        // Don't draw dividers next to items that are not enabled
-                        if (top > effectivePaddingTop) {
-                            if ((areAllItemsSelectable ||
-                                    (adapter.isEnabled(first + i) && (i == count - 1 ||
-                                            adapter.isEnabled(first + i + 1))))) {
+                        if (drawDividers && (top > effectivePaddingTop)) {
+                            final boolean isFirstItem = (i == start);
+                            final int previousIndex = (itemIndex - 1);
+                            // Draw dividers between enabled items, headers and/or
+                            // footers when enabled, and the end of the list.
+                            if (areAllItemsSelectable || ((adapter.isEnabled(itemIndex)
+                                    || (headerDividers && isHeader)
+                                    || (footerDividers && isFooter)) && (isFirstItem
+                                    || adapter.isEnabled(previousIndex)
+                                    || (headerDividers && (previousIndex < headerCount))
+                                    || (footerDividers && (previousIndex >= footerLimit))))) {
                                 bounds.top = top - dividerHeight;
                                 bounds.bottom = top;
-                                // Give the method the child ABOVE the divider, so we
-                                // subtract one from our child
-                                // position. Give -1 when there is no child above the
+                                // Give the method the child ABOVE the divider,
+                                // so we subtract one from our child position.
+                                // Give -1 when there is no child above the
                                 // divider.
                                 drawDivider(canvas, bounds, i - 1);
                             } else if (fillForMissingDividers) {
@@ -3404,6 +3437,7 @@
      * @param headerDividersEnabled True to draw the headers, false otherwise.
      *
      * @see #setFooterDividersEnabled(boolean)
+     * @see #areHeaderDividersEnabled()
      * @see #addHeaderView(android.view.View)
      */
     public void setHeaderDividersEnabled(boolean headerDividersEnabled) {
@@ -3412,17 +3446,36 @@
     }
 
     /**
+     * @return Whether the drawing of the divider for header views is enabled
+     *
+     * @see #setHeaderDividersEnabled(boolean)
+     */
+    public boolean areHeaderDividersEnabled() {
+        return mHeaderDividersEnabled;
+    }
+
+    /**
      * Enables or disables the drawing of the divider for footer views.
      *
      * @param footerDividersEnabled True to draw the footers, false otherwise.
      *
      * @see #setHeaderDividersEnabled(boolean)
+     * @see #areFooterDividersEnabled()
      * @see #addFooterView(android.view.View)
      */
     public void setFooterDividersEnabled(boolean footerDividersEnabled) {
         mFooterDividersEnabled = footerDividersEnabled;
         invalidate();
     }
+
+    /**
+     * @return Whether the drawing of the divider for footer views is enabled
+     *
+     * @see #setFooterDividersEnabled(boolean)
+     */
+    public boolean areFooterDividersEnabled() {
+        return mFooterDividersEnabled;
+    }
     
     /**
      * Sets the drawable that will be drawn above all other list content.
@@ -3728,5 +3781,20 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(ListView.class.getName());
+
+        final int count = getCount();
+        final CollectionInfo collectionInfo = CollectionInfo.obtain(1, count, false);
+        info.setCollectionInfo(collectionInfo);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfoForItem(
+            View view, int position, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoForItem(view, position, info);
+
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+        final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(0, 1, position, 1, isHeading);
+        info.setCollectionItemInfo(itemInfo);
     }
 }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 4a98f66..c0fde2e 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1099,6 +1099,21 @@
     }
 
     @Override
+    protected int computeVerticalScrollOffset() {
+        return mCurrentScrollOffset;
+    }
+
+    @Override
+    protected int computeVerticalScrollRange() {
+        return (mMaxValue - mMinValue + 1) * mSelectorElementHeight;
+    }
+
+    @Override
+    protected int computeVerticalScrollExtent() {
+        return getHeight();
+    }
+
+    @Override
     public int getSolidColor() {
         return mSolidColor;
     }
@@ -1425,6 +1440,7 @@
 
     @Override
     protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
         removeAllCallbacks();
     }
 
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 6a6d767..111dadc 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -22,10 +22,13 @@
 import com.android.internal.view.menu.SubMenuBuilder;
 
 import android.content.Context;
+import android.view.Gravity;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnTouchListener;
+import android.widget.ListPopupWindow.ForwardingListener;
 
 /**
  * A PopupMenu displays a {@link Menu} in a modal popup window anchored to a {@link View}.
@@ -40,6 +43,7 @@
     private MenuPopupHelper mPopup;
     private OnMenuItemClickListener mMenuItemClickListener;
     private OnDismissListener mDismissListener;
+    private OnTouchListener mDragListener;
 
     /**
      * Callback interface used to notify the application that the menu has closed.
@@ -61,16 +65,71 @@
      *               is room, or above it if there is not.
      */
     public PopupMenu(Context context, View anchor) {
+        this(context, anchor, Gravity.NO_GRAVITY);
+    }
+
+    /**
+     * Construct a new PopupMenu.
+     *
+     * @param context Context for the PopupMenu.
+     * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
+     *               is room, or above it if there is not.
+     * @param gravity The {@link Gravity} value for aligning the popup with its anchor
+     */
+    public PopupMenu(Context context, View anchor, int gravity) {
         // TODO Theme?
         mContext = context;
         mMenu = new MenuBuilder(context);
         mMenu.setCallback(this);
         mAnchor = anchor;
         mPopup = new MenuPopupHelper(context, mMenu, anchor);
+        mPopup.setGravity(gravity);
         mPopup.setCallback(this);
     }
 
     /**
+     * Returns an {@link OnTouchListener} that can be added to the anchor view
+     * to implement drag-to-open behavior.
+     * <p>
+     * When the listener is set on a view, touching that view and dragging
+     * outside of its bounds will open the popup window. Lifting will select the
+     * currently touched list item.
+     * <p>
+     * Example usage:
+     * <pre>
+     * PopupMenu myPopup = new PopupMenu(context, myAnchor);
+     * myAnchor.setOnTouchListener(myPopup.getDragToOpenListener());
+     * </pre>
+     *
+     * @return a touch listener that controls drag-to-open behavior
+     */
+    public OnTouchListener getDragToOpenListener() {
+        if (mDragListener == null) {
+            mDragListener = new ForwardingListener(mAnchor) {
+                @Override
+                protected boolean onForwardingStarted() {
+                    show();
+                    return true;
+                }
+
+                @Override
+                protected boolean onForwardingStopped() {
+                    dismiss();
+                    return true;
+                }
+
+                @Override
+                public ListPopupWindow getPopup() {
+                    // This will be null until show() is called.
+                    return mPopup.getPopup();
+                }
+            };
+        }
+
+        return mDragListener;
+    }
+
+    /**
      * @return the {@link Menu} associated with this popup. Populate the returned Menu with
      * items before calling {@link #show()}.
      *
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 1460737..5663959 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -72,7 +72,9 @@
      * screen as needed, regardless of whether this covers the input method.
      */
     public static final int INPUT_METHOD_NOT_NEEDED = 2;
-    
+
+    private static final int DEFAULT_ANCHORED_GRAVITY = Gravity.TOP | Gravity.START;
+
     private Context mContext;
     private WindowManager mWindowManager;
     
@@ -135,12 +137,13 @@
                     WindowManager.LayoutParams p = (WindowManager.LayoutParams)
                             mPopupView.getLayoutParams();
 
-                    updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff));
+                    updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+                            mAnchoredGravity));
                     update(p.x, p.y, -1, -1, true);
                 }
             }
         };
-    private int mAnchorXoff, mAnchorYoff;
+    private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
 
     private boolean mPopupViewInitialLayoutDirectionInherited;
 
@@ -873,15 +876,38 @@
      * location, the popup will be moved correspondingly.</p>
      *
      * @param anchor the view on which to pin the popup window
+     * @param xoff A horizontal offset from the anchor in pixels
+     * @param yoff A vertical offset from the anchor in pixels
      *
      * @see #dismiss()
      */
     public void showAsDropDown(View anchor, int xoff, int yoff) {
+        showAsDropDown(anchor, xoff, yoff, DEFAULT_ANCHORED_GRAVITY);
+    }
+
+    /**
+     * <p>Display the content view in a popup window anchored to the bottom-left
+     * corner of the anchor view offset by the specified x and y coordinates.
+     * If there is not enough room on screen to show
+     * the popup in its entirety, this method tries to find a parent scroll
+     * view to scroll. If no parent scroll view can be scrolled, the bottom-left
+     * corner of the popup is pinned at the top left corner of the anchor view.</p>
+     * <p>If the view later scrolls to move <code>anchor</code> to a different
+     * location, the popup will be moved correspondingly.</p>
+     *
+     * @param anchor the view on which to pin the popup window
+     * @param xoff A horizontal offset from the anchor in pixels
+     * @param yoff A vertical offset from the anchor in pixels
+     * @param gravity Alignment of the popup relative to the anchor
+     *
+     * @see #dismiss()
+     */
+    public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
         if (isShowing() || mContentView == null) {
             return;
         }
 
-        registerForScrollChanged(anchor, xoff, yoff);
+        registerForScrollChanged(anchor, xoff, yoff, gravity);
 
         mIsShowing = true;
         mIsDropdown = true;
@@ -889,7 +915,7 @@
         WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
         preparePopup(p);
 
-        updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff));
+        updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
 
         if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
         if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
@@ -1105,17 +1131,24 @@
      * @return true if the popup is translated upwards to fit on screen
      */
     private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
-            int xoff, int yoff) {
+            int xoff, int yoff, int gravity) {
 
         final int anchorHeight = anchor.getHeight();
         anchor.getLocationInWindow(mDrawingLocation);
         p.x = mDrawingLocation[0] + xoff;
         p.y = mDrawingLocation[1] + anchorHeight + yoff;
+
+        final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection()) &
+                Gravity.HORIZONTAL_GRAVITY_MASK;
+        if (hgrav == Gravity.RIGHT) {
+            // Flip the location to align the right sides of the popup and anchor instead of left
+            p.x -= mPopupWidth - anchor.getWidth();
+        }
         
         boolean onTop = false;
 
-        p.gravity = Gravity.START | Gravity.TOP;
-        
+        p.gravity = Gravity.LEFT | Gravity.TOP;
+
         anchor.getLocationOnScreen(mScreenLocation);
         final Rect displayFrame = new Rect();
         anchor.getWindowVisibleDisplayFrame(displayFrame);
@@ -1141,6 +1174,11 @@
             anchor.getLocationInWindow(mDrawingLocation);
             p.x = mDrawingLocation[0] + xoff;
             p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+
+            // Preserve the gravity adjustment
+            if (hgrav == Gravity.RIGHT) {
+                p.x -= mPopupWidth - anchor.getWidth();
+            }
             
             // determine whether there is more space above or below the anchor
             anchor.getLocationOnScreen(mScreenLocation);
@@ -1148,7 +1186,7 @@
             onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getHeight() - yoff) <
                     (mScreenLocation[1] - yoff - displayFrame.top);
             if (onTop) {
-                p.gravity = Gravity.START | Gravity.BOTTOM;
+                p.gravity = Gravity.LEFT | Gravity.BOTTOM;
                 p.y = root.getHeight() - mDrawingLocation[1] + yoff;
             } else {
                 p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
@@ -1436,7 +1474,7 @@
      * @param height the new height, can be -1 to ignore
      */
     public void update(View anchor, int width, int height) {
-        update(anchor, false, 0, 0, true, width, height);
+        update(anchor, false, 0, 0, true, width, height, mAnchoredGravity);
     }
 
     /**
@@ -1455,11 +1493,11 @@
      * @param height the new height, can be -1 to ignore
      */
     public void update(View anchor, int xoff, int yoff, int width, int height) {
-        update(anchor, true, xoff, yoff, true, width, height);
+        update(anchor, true, xoff, yoff, true, width, height, mAnchoredGravity);
     }
 
     private void update(View anchor, boolean updateLocation, int xoff, int yoff,
-            boolean updateDimension, int width, int height) {
+            boolean updateDimension, int width, int height, int gravity) {
 
         if (!isShowing() || mContentView == null) {
             return;
@@ -1468,11 +1506,12 @@
         WeakReference<View> oldAnchor = mAnchor;
         final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
         if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
-            registerForScrollChanged(anchor, xoff, yoff);
+            registerForScrollChanged(anchor, xoff, yoff, gravity);
         } else if (needsUpdate) {
             // No need to register again if this is a DropDown, showAsDropDown already did.
             mAnchorXoff = xoff;
             mAnchorYoff = yoff;
+            mAnchoredGravity = gravity;
         }
 
         WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
@@ -1494,9 +1533,10 @@
         int y = p.y;
 
         if (updateLocation) {
-            updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff));
+            updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
         } else {
-            updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff));            
+            updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+                    mAnchoredGravity));
         }
 
         update(p.x, p.y, width, height, x != p.x || y != p.y);
@@ -1525,7 +1565,7 @@
         mAnchor = null;
     }
 
-    private void registerForScrollChanged(View anchor, int xoff, int yoff) {
+    private void registerForScrollChanged(View anchor, int xoff, int yoff, int gravity) {
         unregisterForScrollChanged();
 
         mAnchor = new WeakReference<View>(anchor);
@@ -1536,6 +1576,7 @@
 
         mAnchorXoff = xoff;
         mAnchorYoff = yoff;
+        mAnchoredGravity = gravity;
     }
 
     private class PopupViewContainer extends FrameLayout {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index f940226..e03e83d 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -16,22 +16,21 @@
 
 package android.widget;
 
+import android.util.ArrayMap;
 import com.android.internal.R;
 
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.os.Build;
 import android.util.AttributeSet;
-import android.util.Pools.SimplePool;
+import android.util.Pools.SynchronizedPool;
 import android.util.SparseArray;
 import android.view.Gravity;
 import android.view.View;
@@ -42,7 +41,6 @@
 import android.widget.RemoteViews.RemoteView;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-import static android.util.Log.d;
 
 /**
  * A Layout where the positions of the children can be described in relation to each other or to the
@@ -83,10 +81,6 @@
  */
 @RemoteView
 public class RelativeLayout extends ViewGroup {
-    private static final String LOG_TAG = "RelativeLayout";
-
-    private static final boolean DEBUG_GRAPH = false;
-
     public static final int TRUE = -1;
 
     /**
@@ -212,8 +206,8 @@
     private SortedSet<View> mTopToBottomLeftToRightSet = null;
     
     private boolean mDirtyHierarchy;
-    private View[] mSortedHorizontalChildren = new View[0];
-    private View[] mSortedVerticalChildren = new View[0];
+    private View[] mSortedHorizontalChildren;
+    private View[] mSortedVerticalChildren;
     private final DependencyGraph mGraph = new DependencyGraph();
 
     // Compatibility hack. Old versions of the platform had problems
@@ -360,42 +354,26 @@
     }
 
     private void sortChildren() {
-        int count = getChildCount();
-        if (mSortedVerticalChildren.length != count) mSortedVerticalChildren = new View[count];
-        if (mSortedHorizontalChildren.length != count) mSortedHorizontalChildren = new View[count];
+        final int count = getChildCount();
+        if (mSortedVerticalChildren == null || mSortedVerticalChildren.length != count) {
+            mSortedVerticalChildren = new View[count];
+        }
+
+        if (mSortedHorizontalChildren == null || mSortedHorizontalChildren.length != count) {
+            mSortedHorizontalChildren = new View[count];
+        }
 
         final DependencyGraph graph = mGraph;
         graph.clear();
 
         for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            graph.add(child);
-        }
-
-        if (DEBUG_GRAPH) {
-            d(LOG_TAG, "=== Sorted vertical children");
-            graph.log(getResources(), RULES_VERTICAL);
-            d(LOG_TAG, "=== Sorted horizontal children");
-            graph.log(getResources(), RULES_HORIZONTAL);
+            graph.add(getChildAt(i));
         }
 
         graph.getSortedViews(mSortedVerticalChildren, RULES_VERTICAL);
         graph.getSortedViews(mSortedHorizontalChildren, RULES_HORIZONTAL);
-
-        if (DEBUG_GRAPH) {
-            d(LOG_TAG, "=== Ordered list of vertical children");
-            for (View view : mSortedVerticalChildren) {
-                DependencyGraph.printViewId(getResources(), view);
-            }
-            d(LOG_TAG, "=== Ordered list of horizontal children");
-            for (View view : mSortedHorizontalChildren) {
-                DependencyGraph.printViewId(getResources(), view);
-            }
-        }        
     }
 
-    // TODO: we need to find another way to implement RelativeLayout
-    // This implementation cannot handle every case
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (mDirtyHierarchy) {
@@ -484,6 +462,7 @@
 
         views = mSortedVerticalChildren;
         count = views.length;
+        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
 
         for (int i = 0; i < count; i++) {
             View child = views[i];
@@ -498,14 +477,26 @@
 
                 if (isWrapContentWidth) {
                     if (isLayoutRtl()) {
-                        width = Math.max(width, myWidth - params.mLeft);
+                        if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
+                            width = Math.max(width, myWidth - params.mLeft);
+                        } else {
+                            width = Math.max(width, myWidth - params.mLeft - params.leftMargin);
+                        }
                     } else {
-                        width = Math.max(width, params.mRight);
+                        if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
+                            width = Math.max(width, params.mRight);
+                        } else {
+                            width = Math.max(width, params.mRight + params.rightMargin);
+                        }
                     }
                 }
 
                 if (isWrapContentHeight) {
-                    height = Math.max(height, params.mBottom);
+                    if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
+                        height = Math.max(height, params.mBottom);
+                    } else {
+                        height = Math.max(height, params.mBottom + params.bottomMargin);
+                    }
                 }
 
                 if (child != ignore || verticalGravity) {
@@ -545,7 +536,7 @@
             // the right of each child view
             width += mPaddingRight;
 
-            if (mLayoutParams.width >= 0) {
+            if (mLayoutParams != null && mLayoutParams.width >= 0) {
                 width = Math.max(width, mLayoutParams.width);
             }
 
@@ -575,7 +566,7 @@
             // the bottom of each child view
             height += mPaddingBottom;
 
-            if (mLayoutParams.height >= 0) {
+            if (mLayoutParams != null && mLayoutParams.height >= 0) {
                 height = Math.max(height, mLayoutParams.height);
             }
 
@@ -900,8 +891,6 @@
         } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
             if (myWidth >= 0) {
                 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
-            } else {
-                // FIXME uh oh...
             }
         }
 
@@ -926,8 +915,6 @@
         } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
             if (myWidth >= 0) {
                 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
-            } else {
-                // FIXME uh oh...
             }
         }
 
@@ -938,8 +925,6 @@
         if (0 != rules[ALIGN_PARENT_RIGHT]) {
             if (myWidth >= 0) {
                 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
-            } else {
-                // FIXME uh oh...
             }
         }
     }
@@ -958,8 +943,6 @@
         } else if (childParams.alignWithParent && rules[ABOVE] != 0) {
             if (myHeight >= 0) {
                 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
-            } else {
-                // FIXME uh oh...
             }
         }
 
@@ -984,8 +967,6 @@
         } else if (childParams.alignWithParent && rules[ALIGN_BOTTOM] != 0) {
             if (myHeight >= 0) {
                 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
-            } else {
-                // FIXME uh oh...
             }
         }
 
@@ -996,8 +977,6 @@
         if (0 != rules[ALIGN_PARENT_BOTTOM]) {
             if (myHeight >= 0) {
                 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
-            } else {
-                // FIXME uh oh...
             }
         }
 
@@ -1355,6 +1334,24 @@
             super(source);
         }
 
+        /**
+         * Copy constructor. Clones the width, height, margin values, and rules
+         * of the source.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.mIsRtlCompatibilityMode = source.mIsRtlCompatibilityMode;
+            this.mRulesChanged = source.mRulesChanged;
+            this.alignWithParent = source.alignWithParent;
+
+            System.arraycopy(source.mRules, LEFT_OF, this.mRules, LEFT_OF, VERB_COUNT);
+            System.arraycopy(
+                    source.mInitialRules, LEFT_OF, this.mInitialRules, LEFT_OF, VERB_COUNT);
+        }
+
         @Override
         public String debug(String output) {
             return output + "ViewGroup.LayoutParams={ width=" + sizeToString(width) +
@@ -1677,8 +1674,10 @@
 
                 sorted[index++] = view;
 
-                final HashMap<Node, DependencyGraph> dependents = node.dependents;
-                for (Node dependent : dependents.keySet()) {
+                final ArrayMap<Node, DependencyGraph> dependents = node.dependents;
+                final int count = dependents.size();
+                for (int i = 0; i < count; i++) {
+                    final Node dependent = dependents.keyAt(i);
                     final SparseArray<Node> dependencies = dependent.dependencies;
 
                     dependencies.remove(key);
@@ -1756,61 +1755,6 @@
         }
 
         /**
-         * Prints the dependency graph for the specified rules.
-         *
-         * @param resources The context's resources to print the ids.
-         * @param rules The list of rules to take into account.
-         */
-        void log(Resources resources, int... rules) {
-            final ArrayDeque<Node> roots = findRoots(rules);
-            for (Node node : roots) {
-                printNode(resources, node);
-            }
-        }
-
-        static void printViewId(Resources resources, View view) {
-            if (view.getId() != View.NO_ID) {
-                d(LOG_TAG, resources.getResourceEntryName(view.getId()));
-            } else {
-                d(LOG_TAG, "NO_ID");
-            }
-        }
-
-        private static void appendViewId(Resources resources, Node node, StringBuilder buffer) {
-            if (node.view.getId() != View.NO_ID) {
-                buffer.append(resources.getResourceEntryName(node.view.getId()));
-            } else {
-                buffer.append("NO_ID");
-            }
-        }
-
-        private static void printNode(Resources resources, Node node) {
-            if (node.dependents.size() == 0) {
-                printViewId(resources, node.view);
-            } else {
-                for (Node dependent : node.dependents.keySet()) {
-                    StringBuilder buffer = new StringBuilder();
-                    appendViewId(resources, node, buffer);
-                    printdependents(resources, dependent, buffer);
-                }
-            }
-        }
-
-        private static void printdependents(Resources resources, Node node, StringBuilder buffer) {
-            buffer.append(" -> ");
-            appendViewId(resources, node, buffer);
-
-            if (node.dependents.size() == 0) {
-                d(LOG_TAG, buffer.toString());
-            } else {
-                for (Node dependent : node.dependents.keySet()) {
-                    StringBuilder subBuffer = new StringBuilder(buffer);
-                    printdependents(resources, dependent, subBuffer);
-                }
-            }
-        }
-
-        /**
          * A node in the dependency graph. A node is a view, its list of dependencies
          * and its list of dependents.
          *
@@ -1826,7 +1770,8 @@
              * The list of dependents for this node; a dependent is a node
              * that needs this node to be processed first.
              */
-            final HashMap<Node, DependencyGraph> dependents = new HashMap<Node, DependencyGraph>();
+            final ArrayMap<Node, DependencyGraph> dependents =
+                    new ArrayMap<Node, DependencyGraph>();
 
             /**
              * The list of dependencies for this node.
@@ -1839,7 +1784,8 @@
             // The pool is static, so all nodes instances are shared across
             // activities, that's why we give it a rather high limit
             private static final int POOL_LIMIT = 100;
-            private static final SimplePool<Node> sPool = new SimplePool<Node>(POOL_LIMIT);
+            private static final SynchronizedPool<Node> sPool =
+                    new SynchronizedPool<Node>(POOL_LIMIT);
 
             static Node acquire(View view) {
                 Node node = sPool.acquire();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 07e66b7..0d3df51 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -37,6 +37,7 @@
 import android.os.StrictMode;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater.Filter;
@@ -45,6 +46,7 @@
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.AdapterView.OnItemClickListener;
+import libcore.util.Objects;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -136,6 +138,49 @@
 
     private static final OnClickHandler DEFAULT_ON_CLICK_HANDLER = new OnClickHandler();
 
+    private static final Object[] sMethodsLock = new Object[0];
+    private static final ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>> sMethods =
+            new ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>>();
+    private static final ThreadLocal<Object[]> sInvokeArgsTls = new ThreadLocal<Object[]>() {
+        @Override
+        protected Object[] initialValue() {
+            return new Object[1];
+        }
+    };
+
+    /**
+     * Handle with care!
+     */
+    static class MutablePair<F, S> {
+        F first;
+        S second;
+
+        MutablePair(F first, S second) {
+            this.first = first;
+            this.second = second;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof MutablePair)) {
+                return false;
+            }
+            MutablePair<?, ?> p = (MutablePair<?, ?>) o;
+            return Objects.equal(p.first, first) && Objects.equal(p.second, second);
+        }
+
+        @Override
+        public int hashCode() {
+            return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
+        }
+    }
+
+    /**
+     * This pair is used to perform lookups in sMethods without causing allocations.
+     */
+    private final MutablePair<String, Class<?>> mPair =
+            new MutablePair<String, Class<?>>(null, null);
+
     /**
      * This annotation indicates that a subclass of View is alllowed to be used
      * with the {@link RemoteViews} mechanism.
@@ -206,9 +251,8 @@
          * Overridden by each class to report on it's own memory usage
          */
         public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
-            // We currently only calculate Bitmap memory usage, so by default, don't do anything
-            // here
-            return;
+            // We currently only calculate Bitmap memory usage, so by default,
+            // don't do anything here
         }
 
         public void setBitmapCache(BitmapCache bitmapCache) {
@@ -346,7 +390,7 @@
             }
             if (target == root) {
                 target.setTagInternal(com.android.internal.R.id.fillInIntent, fillInIntent);
-            } else if (target != null && fillInIntent != null) {
+            } else if (fillInIntent != null) {
                 OnClickListener listener = new OnClickListener() {
                     public void onClick(View v) {
                         // Insure that this view is a child of an AdapterView
@@ -372,16 +416,7 @@
 
                         PendingIntent pendingIntent = (PendingIntent) parent.getTag();
 
-                        final float appScale = v.getContext().getResources()
-                                .getCompatibilityInfo().applicationScale;
-                        final int[] pos = new int[2];
-                        v.getLocationOnScreen(pos);
-
-                        final Rect rect = new Rect();
-                        rect.left = (int) (pos[0] * appScale + 0.5f);
-                        rect.top = (int) (pos[1] * appScale + 0.5f);
-                        rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
-                        rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+                        final Rect rect = getSourceBounds(v);
 
                         fillInIntent.setSourceBounds(rect);
                         handler.onClickHandler(v, pendingIntent, fillInIntent);
@@ -452,16 +487,7 @@
                             }
                             if (fillInIntent == null) return;
 
-                            final float appScale = view.getContext().getResources()
-                                    .getCompatibilityInfo().applicationScale;
-                            final int[] pos = new int[2];
-                            view.getLocationOnScreen(pos);
-
-                            final Rect rect = new Rect();
-                            rect.left = (int) (pos[0] * appScale + 0.5f);
-                            rect.top = (int) (pos[1] * appScale + 0.5f);
-                            rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f);
-                            rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f);
+                            final Rect rect = getSourceBounds(view);
 
                             final Intent intent = new Intent();
                             intent.setSourceBounds(rect);
@@ -679,33 +705,22 @@
                 }
             }
 
-            if (target != null) {
-                // If the pendingIntent is null, we clear the onClickListener
-                OnClickListener listener = null;
-                if (pendingIntent != null) {
-                    listener = new OnClickListener() {
-                        public void onClick(View v) {
-                            // Find target view location in screen coordinates and
-                            // fill into PendingIntent before sending.
-                            final float appScale = v.getContext().getResources()
-                                    .getCompatibilityInfo().applicationScale;
-                            final int[] pos = new int[2];
-                            v.getLocationOnScreen(pos);
+            // If the pendingIntent is null, we clear the onClickListener
+            OnClickListener listener = null;
+            if (pendingIntent != null) {
+                listener = new OnClickListener() {
+                    public void onClick(View v) {
+                        // Find target view location in screen coordinates and
+                        // fill into PendingIntent before sending.
+                        final Rect rect = getSourceBounds(v);
 
-                            final Rect rect = new Rect();
-                            rect.left = (int) (pos[0] * appScale + 0.5f);
-                            rect.top = (int) (pos[1] * appScale + 0.5f);
-                            rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
-                            rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
-
-                            final Intent intent = new Intent();
-                            intent.setSourceBounds(rect);
-                            handler.onClickHandler(v, pendingIntent, intent);
-                        }
-                    };
-                }
-                target.setOnClickListener(listener);
+                        final Intent intent = new Intent();
+                        intent.setSourceBounds(rect);
+                        handler.onClickHandler(v, pendingIntent, intent);
+                    }
+                };
             }
+            target.setOnClickListener(listener);
         }
 
         public String getActionName() {
@@ -717,6 +732,71 @@
         public final static int TAG = 1;
     }
 
+    private static Rect getSourceBounds(View v) {
+        final float appScale = v.getContext().getResources()
+                .getCompatibilityInfo().applicationScale;
+        final int[] pos = new int[2];
+        v.getLocationOnScreen(pos);
+
+        final Rect rect = new Rect();
+        rect.left = (int) (pos[0] * appScale + 0.5f);
+        rect.top = (int) (pos[1] * appScale + 0.5f);
+        rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
+        rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+        return rect;
+    }
+
+    private Method getMethod(View view, String methodName, Class<?> paramType) {
+        Method method;
+        Class<? extends View> klass = view.getClass();
+
+        synchronized (sMethodsLock) {
+            ArrayMap<MutablePair<String, Class<?>>, Method> methods = sMethods.get(klass);
+            if (methods == null) {
+                methods = new ArrayMap<MutablePair<String, Class<?>>, Method>();
+                sMethods.put(klass, methods);
+            }
+
+            mPair.first = methodName;
+            mPair.second = paramType;
+
+            method = methods.get(mPair);
+            if (method == null) {
+                try {
+                    if (paramType == null) {
+                        method = klass.getMethod(methodName);
+                    } else {
+                        method = klass.getMethod(methodName, paramType);
+                    }
+                } catch (NoSuchMethodException ex) {
+                    throw new ActionException("view: " + klass.getName() + " doesn't have method: "
+                            + methodName + getParameters(paramType));
+                }
+
+                if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
+                    throw new ActionException("view: " + klass.getName()
+                            + " can't use method with RemoteViews: "
+                            + methodName + getParameters(paramType));
+                }
+
+                methods.put(new MutablePair<String, Class<?>>(methodName, paramType), method);
+            }
+        }
+
+        return method;
+    }
+
+    private static String getParameters(Class<?> paramType) {
+        if (paramType == null) return "()";
+        return "(" + paramType + ")";
+    }
+
+    private static Object[] wrapArg(Object value) {
+        Object[] args = sInvokeArgsTls.get();
+        args[0] = value;
+        return args;
+    }
+
     /**
      * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
      * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
@@ -810,8 +890,8 @@
         public final static int TAG = 3;
     }
 
-    private class ReflectionActionWithoutParams extends Action {
-        String methodName;
+    private final class ReflectionActionWithoutParams extends Action {
+        final String methodName;
 
         public final static int TAG = 5;
 
@@ -836,28 +916,10 @@
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
-            Class klass = view.getClass();
-            Method method;
             try {
-                method = klass.getMethod(this.methodName);
-            } catch (NoSuchMethodException ex) {
-                throw new ActionException("view: " + klass.getName() + " doesn't have method: "
-                        + this.methodName + "()");
-            }
-
-            if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
-                throw new ActionException("view: " + klass.getName()
-                        + " can't use method with RemoteViews: "
-                        + this.methodName + "()");
-            }
-
-            try {
-                //noinspection ConstantIfStatement
-                if (false) {
-                    Log.d(LOG_TAG, "view: " + klass.getName() + " calling method: "
-                        + this.methodName + "()");
-                }
-                method.invoke(view);
+                getMethod(view, this.methodName, null).invoke(view);
+            } catch (ActionException e) {
+                throw e;
             } catch (Exception ex) {
                 throw new ActionException(ex);
             }
@@ -990,7 +1052,7 @@
     /**
      * Base class for the reflection actions.
      */
-    private class ReflectionAction extends Action {
+    private final class ReflectionAction extends Action {
         static final int TAG = 2;
 
         static final int BOOLEAN = 1;
@@ -1157,7 +1219,7 @@
             }
         }
 
-        private Class getParameterType() {
+        private Class<?> getParameterType() {
             switch (this.type) {
                 case BOOLEAN:
                     return boolean.class;
@@ -1197,37 +1259,16 @@
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
-            Class param = getParameterType();
+            Class<?> param = getParameterType();
             if (param == null) {
                 throw new ActionException("bad type: " + this.type);
             }
 
-            Class klass = view.getClass();
-            Method method;
             try {
-                method = klass.getMethod(this.methodName, getParameterType());
-            }
-            catch (NoSuchMethodException ex) {
-                throw new ActionException("view: " + klass.getName() + " doesn't have method: "
-                        + this.methodName + "(" + param.getName() + ")");
-            }
-
-            if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
-                throw new ActionException("view: " + klass.getName()
-                        + " can't use method with RemoteViews: "
-                        + this.methodName + "(" + param.getName() + ")");
-            }
-
-            try {
-                //noinspection ConstantIfStatement
-                if (false) {
-                    Log.d(LOG_TAG, "view: " + klass.getName() + " calling method: "
-                        + this.methodName + "(" + param.getName() + ") with "
-                        + (this.value == null ? "null" : this.value.getClass().getName()));
-                }
-                method.invoke(view, this.value);
-            }
-            catch (Exception ex) {
+                getMethod(view, this.methodName, param).invoke(view, wrapArg(this.value));
+            } catch (ActionException e) {
+                throw e;
+            } catch (Exception ex) {
                 throw new ActionException(ex);
             }
         }
@@ -1323,7 +1364,7 @@
         }
 
         public String getActionName() {
-            return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add";
+            return "ViewGroupAction" + (nestedViews == null ? "Remove" : "Add");
         }
 
         public int mergeBehavior() {
@@ -1370,7 +1411,6 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final Context context = root.getContext();
             final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             if (isRelative) {
@@ -1415,7 +1455,6 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final Context context = root.getContext();
             final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             target.setTextSize(units, size);
@@ -1462,7 +1501,6 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final Context context = root.getContext();
             final View target = root.findViewById(viewId);
             if (target == null) return;
             target.setPadding(left, top, right, bottom);
@@ -1494,6 +1532,7 @@
             return mMemoryUsage;
         }
 
+        @SuppressWarnings("deprecation")
         public void addBitmapMemory(Bitmap b) {
             final Bitmap.Config c = b.getConfig();
             // If we don't know, be pessimistic and assume 4
@@ -1597,7 +1636,7 @@
         if (mode == MODE_NORMAL) {
             mPackage = parcel.readString();
             mLayoutId = parcel.readInt();
-            mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false;
+            mIsWidgetCollectionChild = parcel.readInt() == 1;
 
             int count = parcel.readInt();
             if (count > 0) {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index aeee111..3ff0cee 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -22,9 +22,11 @@
 import java.util.HashSet;
 import java.util.LinkedList;
 
+import android.Manifest;
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -34,6 +36,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.MeasureSpec;
@@ -50,9 +53,11 @@
  */
 /** @hide */
 public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback {
+    private static final String MULTI_USER_PERM = Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+
     private static final String TAG = "RemoteViewsAdapter";
 
-    // The max number of items in the cache 
+    // The max number of items in the cache
     private static final int sDefaultCacheSize = 40;
     // The delay (in millis) to wait until attempting to unbind from a service after a request.
     // This ensures that we don't stay continually bound to the service and that it can be destroyed
@@ -63,7 +68,7 @@
     private static final int sDefaultLoadingViewHeight = 50;
 
     // Type defs for controlling different messages across the main and worker message queues
-    private static final int sDefaultMessageType = 0; 
+    private static final int sDefaultMessageType = 0;
     private static final int sUnbindServiceMessageType = 1;
 
     private final Context mContext;
@@ -90,7 +95,7 @@
     private Handler mMainQueue;
 
     // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
-    // structures; 
+    // structures;
     private static final HashMap<RemoteViewsCacheKey,
             FixedSizeRemoteViewsCache> sCachedRemoteViewsCaches
             = new HashMap<RemoteViewsCacheKey,
@@ -155,13 +160,12 @@
                 try {
                     RemoteViewsAdapter adapter;
                     final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
-                    if (Process.myUid() == Process.SYSTEM_UID
-                            && (adapter = mAdapter.get()) != null) {
+                    if ((adapter = mAdapter.get()) != null) {
+                        checkInteractAcrossUsersPermission(context, adapter.mUserId);
                         mgr.bindRemoteViewsService(appWidgetId, intent, asBinder(),
                                 new UserHandle(adapter.mUserId));
                     } else {
-                        mgr.bindRemoteViewsService(appWidgetId, intent, asBinder(),
-                                Process.myUserHandle());
+                        Slog.w(TAG, "bind: adapter was null");
                     }
                     mIsConnecting = true;
                 } catch (Exception e) {
@@ -176,12 +180,12 @@
             try {
                 RemoteViewsAdapter adapter;
                 final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
-                if (Process.myUid() == Process.SYSTEM_UID
-                        && (adapter = mAdapter.get()) != null) {
+                if ((adapter = mAdapter.get()) != null) {
+                    checkInteractAcrossUsersPermission(context, adapter.mUserId);
                     mgr.unbindRemoteViewsService(appWidgetId, intent,
                             new UserHandle(adapter.mUserId));
                 } else {
-                    mgr.unbindRemoteViewsService(appWidgetId, intent, Process.myUserHandle());
+                    Slog.w(TAG, "unbind: adapter was null");
                 }
                 mIsConnecting = false;
             } catch (Exception e) {
@@ -263,7 +267,7 @@
             // Clear the main/worker queues
             final RemoteViewsAdapter adapter = mAdapter.get();
             if (adapter == null) return;
-            
+
             adapter.mMainQueue.post(new Runnable() {
                 @Override
                 public void run() {
@@ -828,11 +832,9 @@
         }
         mRequestedViews = new RemoteViewsFrameLayoutRefSet();
 
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            mUserId = new LockPatternUtils(context).getCurrentUser();
-        } else {
-            mUserId = UserHandle.myUserId();
-        }
+        checkInteractAcrossUsersPermission(context, UserHandle.myUserId());
+        mUserId = context.getUserId();
+
         // Strip the previously injected app widget id from service intent
         if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) {
             intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID);
@@ -876,6 +878,15 @@
         }
     }
 
+    private static void checkInteractAcrossUsersPermission(Context context, int userId) {
+        if (context.getUserId() != userId
+                && context.checkCallingOrSelfPermission(MULTI_USER_PERM)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must have permission " + MULTI_USER_PERM
+                    + " to inflate another user's widget");
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 93a1179..9886bc3 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -226,6 +226,12 @@
     }
 
     @Override
+    public int getAlpha() {
+        // All elements should have same alpha, just return one of them
+        return mVerticalThumb.getAlpha();
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         if (mVerticalTrack != null) {
             mVerticalTrack.setColorFilter(cf);
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index bc41931..6680393 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -16,6 +16,9 @@
 
 package android.widget;
 
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
 import com.android.internal.R;
 
 import android.content.Context;
@@ -149,6 +152,8 @@
      */
     private static final int INVALID_POINTER = -1;
 
+    private SavedState mSavedState;
+
     public ScrollView(Context context) {
         this(context, null);
     }
@@ -631,12 +636,13 @@
                     final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
                             (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
 
+                    // Calling overScrollBy will call onOverScrolled, which
+                    // calls onScrollChanged if applicable.
                     if (overScrollBy(0, deltaY, 0, mScrollY,
                             0, range, 0, mOverscrollDistance, true)) {
                         // Break our velocity if we hit a scroll barrier.
                         mVelocityTracker.clear();
                     }
-                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
                     if (canOverscroll) {
                         final int pulledToY = oldY + deltaY;
@@ -753,9 +759,12 @@
             boolean clampedX, boolean clampedY) {
         // Treat animating scrolls differently; see #computeScroll() for why.
         if (!mScroller.isFinished()) {
+            final int oldX = mScrollX;
+            final int oldY = mScrollY;
             mScrollX = scrollX;
             mScrollY = scrollY;
             invalidateParentIfNeeded();
+            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
             if (clampedY) {
                 mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange());
             }
@@ -1464,6 +1473,24 @@
         }
         mChildToScrollTo = null;
 
+        if (!isLaidOut()) {
+            if (mSavedState != null) {
+                mScrollY = mSavedState.scrollPosition;
+                mSavedState = null;
+            } // mScrollY default value is "0"
+
+            final int childHeight = (getChildCount() > 0) ? getChildAt(0).getMeasuredHeight() : 0;
+            final int scrollRange = Math.max(0,
+                    childHeight - (b - t - mPaddingBottom - mPaddingTop));
+
+            // Don't forget to clamp
+            if (mScrollY > scrollRange) {
+                mScrollY = scrollRange;
+            } else if (mScrollY < 0) {
+                mScrollY = 0;
+            }
+        }
+
         // Calling this with the present values causes it to re-claim them
         scrollTo(mScrollX, mScrollY);
     }
@@ -1633,4 +1660,69 @@
         }
         return n;
     }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            // Some old apps reused IDs in ways they shouldn't have.
+            // Don't break them, but they don't get scroll state restoration.
+            super.onRestoreInstanceState(state);
+            return;
+        }
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        mSavedState = ss;
+        requestLayout();
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            // Some old apps reused IDs in ways they shouldn't have.
+            // Don't break them, but they don't get scroll state restoration.
+            return super.onSaveInstanceState();
+        }
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.scrollPosition = mScrollY;
+        return ss;
+    }
+
+    static class SavedState extends BaseSavedState {
+        public int scrollPosition;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public SavedState(Parcel source) {
+            super(source);
+            scrollPosition = source.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(scrollPosition);
+        }
+
+        @Override
+        public String toString() {
+            return "HorizontalScrollView.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " scrollPosition=" + scrollPosition + "}";
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
 }
diff --git a/core/java/android/widget/SectionIndexer.java b/core/java/android/widget/SectionIndexer.java
index a1c71f4..f6333d1 100644
--- a/core/java/android/widget/SectionIndexer.java
+++ b/core/java/android/widget/SectionIndexer.java
@@ -17,38 +17,62 @@
 package android.widget;
 
 /**
- * Interface that should be implemented on Adapters to enable fast scrolling 
- * in an {@link AbsListView} between sections of the list. A section is a group of list items
- * to jump to that have something in common. For example, they may begin with the
- * same letter or they may be songs from the same artist. ExpandableListAdapters that
- * consider groups and sections as synonymous should account for collapsed groups and return
- * an appropriate section/position.
+ * Interface that may implemented on {@link Adapter}s to enable fast scrolling
+ * between sections of an {@link AbsListView}.
+ * <p>
+ * A section is a group of list items that have something in common. For
+ * example, they may begin with the same letter or they may be songs from the
+ * same artist.
+ * <p>
+ * {@link ExpandableListAdapter}s that consider groups and sections as
+ * synonymous should account for collapsed groups and return an appropriate
+ * section/position.
+ *
+ * @see AbsListView#setFastScrollEnabled(boolean)
  */
 public interface SectionIndexer {
     /**
-     * This provides the list view with an array of section objects. In the simplest
-     * case these are Strings, each containing one letter of the alphabet.
-     * They could be more complex objects that indicate the grouping for the adapter's
-     * consumption. The list view will call toString() on the objects to get the
-     * preview letter to display while scrolling.
-     * @return the array of objects that indicate the different sections of the list.
+     * Returns an array of objects representing sections of the list. The
+     * returned array and its contents should be non-null.
+     * <p>
+     * The list view will call toString() on the objects to get the preview text
+     * to display while scrolling. For example, an adapter may return an array
+     * of Strings representing letters of the alphabet. Or, it may return an
+     * array of objects whose toString() methods return their section titles.
+     *
+     * @return the array of section objects
      */
     Object[] getSections();
-    
+
     /**
-     * Provides the starting index in the list for a given section.
-     * @param section the index of the section to jump to.
-     * @return the starting position of that section. If the section is out of bounds, the
-     * position must be clipped to fall within the size of the list.
+     * Given the index of a section within the array of section objects, returns
+     * the starting position of that section within the adapter.
+     * <p>
+     * If the section's starting position is outside of the adapter bounds, the
+     * position must be clipped to fall within the size of the adapter.
+     *
+     * @param sectionIndex the index of the section within the array of section
+     *            objects
+     * @return the starting position of that section within the adapter,
+     *         constrained to fall within the adapter bounds
      */
-    int getPositionForSection(int section);
-    
+    int getPositionForSection(int sectionIndex);
+
     /**
-     * This is a reverse mapping to fetch the section index for a given position
-     * in the list.
-     * @param position the position for which to return the section
-     * @return the section index. If the position is out of bounds, the section index
+     * Given a position within the adapter, returns the index of the
+     * corresponding section within the array of section objects.
+     * <p>
+     * If the section index is outside of the section array bounds, the index
      * must be clipped to fall within the size of the section array.
+     * <p>
+     * For example, consider an indexer where the section at array index 0
+     * starts at adapter position 100. Calling this method with position 10,
+     * which is before the first section, must return index 0.
+     *
+     * @param position the position within the adapter for which to return the
+     *            corresponding section index
+     * @return the index of the corresponding section within the array of
+     *         section objects, constrained to fall within the array bounds
      */
-    int getSectionForPosition(int position);    
+    int getSectionForPosition(int position);
 }
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 9e7f97e..b204dfd 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -753,4 +753,39 @@
             }
         }
     }
+
+    public static boolean haveWordBoundariesChanged(final Editable editable, final int start,
+            final int end, final int spanStart, final int spanEnd) {
+        final boolean haveWordBoundariesChanged;
+        if (spanEnd != start && spanStart != end) {
+            haveWordBoundariesChanged = true;
+            if (DBG) {
+                Log.d(TAG, "(1) Text inside the span has been modified. Remove.");
+            }
+        } else if (spanEnd == start && start < editable.length()) {
+            final int codePoint = Character.codePointAt(editable, start);
+            haveWordBoundariesChanged = Character.isLetterOrDigit(codePoint);
+            if (DBG) {
+                Log.d(TAG, "(2) Characters have been appended to the spanned text. "
+                        + (haveWordBoundariesChanged ? "Remove.<" : "Keep. <") + (char)(codePoint)
+                        + ">, " + editable + ", " + editable.subSequence(spanStart, spanEnd) + ", "
+                        + start);
+            }
+        } else if (spanStart == end && end > 0) {
+            final int codePoint = Character.codePointBefore(editable, end);
+            haveWordBoundariesChanged = Character.isLetterOrDigit(codePoint);
+            if (DBG) {
+                Log.d(TAG, "(3) Characters have been prepended to the spanned text. "
+                        + (haveWordBoundariesChanged ? "Remove.<" : "Keep.<") + (char)(codePoint)
+                        + ">, " + editable + ", " + editable.subSequence(spanStart, spanEnd) + ", "
+                        + end);
+            }
+        } else {
+            if (DBG) {
+                Log.d(TAG, "(4) Characters adjacent to the spanned text were deleted. Keep.");
+            }
+            haveWordBoundariesChanged = false;
+        }
+        return haveWordBoundariesChanged;
+    }
 }
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index e3de0b9..b75d36f 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -30,12 +30,14 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.ListPopupWindow.ForwardingListener;
 import android.widget.PopupWindow.OnDismissListener;
 
 
@@ -76,7 +78,10 @@
      * Use the theme-supplied value to select the dropdown mode.
      */
     private static final int MODE_THEME = -1;
-    
+
+    /** Forwarding listener used to implement drag-to-open. */
+    private ForwardingListener mForwardingListener;
+
     private SpinnerPopup mPopup;
     private DropDownAdapter mTempAdapter;
     int mDropDownWidth;
@@ -173,7 +178,7 @@
         }
 
         case MODE_DROPDOWN: {
-            DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
+            final DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
 
             mDropDownWidth = a.getLayoutDimension(
                     com.android.internal.R.styleable.Spinner_dropDownWidth,
@@ -193,6 +198,20 @@
             }
 
             mPopup = popup;
+            mForwardingListener = new ForwardingListener(this) {
+                @Override
+                public ListPopupWindow getPopup() {
+                    return popup;
+                }
+
+                @Override
+                public boolean onForwardingStarted() {
+                    if (!mPopup.isShowing()) {
+                        mPopup.show(getTextDirection(), getTextAlignment());
+                    }
+                    return true;
+                }
+            };
             break;
         }
         }
@@ -377,10 +396,24 @@
         return mGravity;
     }
 
+    /**
+     * Sets the Adapter used to provide the data which backs this Spinner.
+     * <p>
+     * Note that Spinner overrides {@link Adapter#getViewTypeCount()} on the
+     * Adapter associated with this view. Calling
+     * {@link Adapter#getItemViewType(int) getItemViewType(int)} on the object
+     * returned from {@link #getAdapter()} will always return 0. Calling
+     * {@link Adapter#getViewTypeCount() getViewTypeCount()} will always return
+     * 1.
+     *
+     * @see AbsSpinner#setAdapter(SpinnerAdapter)
+     */
     @Override
     public void setAdapter(SpinnerAdapter adapter) {
         super.setAdapter(adapter);
 
+        mRecycler.clear();
+
         if (mPopup != null) {
             mPopup.setAdapter(new DropDownAdapter(adapter));
         } else {
@@ -395,9 +428,8 @@
         if (getChildCount() > 0) {
             child = getChildAt(0);
         } else if (mAdapter != null && mAdapter.getCount() > 0) {
-            child = makeAndAddView(0);
+            child = makeView(0, false);
             mRecycler.put(0, child);
-            removeAllViewsInLayout();
         }
 
         if (child != null) {
@@ -437,6 +469,15 @@
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mForwardingListener != null && mForwardingListener.onTouch(this, event)) {
+            return true;
+        }
+
+        return super.onTouchEvent(event);
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
@@ -496,7 +537,7 @@
         mFirstPosition = mSelectedPosition;
 
         if (mAdapter != null) {
-            View sel = makeAndAddView(mSelectedPosition);
+            View sel = makeView(mSelectedPosition, true);
             int width = sel.getMeasuredWidth();
             int selectedOffset = childrenLeft;
             final int layoutDirection = getLayoutDirection();
@@ -531,17 +572,17 @@
      * from the old to new positions.
      *
      * @param position Position in the spinner for the view to obtain
-     * @return A view that has been added to the spinner
+     * @param addChild true to add the child to the spinner, false to obtain and configure only.
+     * @return A view for the given position
      */
-    private View makeAndAddView(int position) {
-
+    private View makeView(int position, boolean addChild) {
         View child;
 
         if (!mDataChanged) {
             child = mRecycler.get(position);
             if (child != null) {
                 // Position the view
-                setUpChild(child);
+                setUpChild(child, addChild);
 
                 return child;
             }
@@ -551,7 +592,7 @@
         child = mAdapter.getView(position, null, this);
 
         // Position the view
-        setUpChild(child);
+        setUpChild(child, addChild);
 
         return child;
     }
@@ -561,8 +602,9 @@
      * and fill out its layout paramters.
      *
      * @param child The view to position
+     * @param addChild true if the child should be added to the Spinner during setup
      */
-    private void setUpChild(View child) {
+    private void setUpChild(View child, boolean addChild) {
 
         // Respect layout params that are already in the view. Otherwise
         // make some up...
@@ -571,7 +613,9 @@
             lp = generateDefaultLayoutParams();
         }
 
-        addViewInLayout(child, 0, lp);
+        if (addChild) {
+            addViewInLayout(child, 0, lp);
+        }
 
         child.setSelected(hasFocus());
         if (mDisableChildrenWhenDisabled) {
@@ -633,6 +677,10 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(Spinner.class.getName());
+
+        if (mAdapter != null) {
+            info.setCanOpenPopup(true);
+        }
     }
 
     /**
@@ -925,6 +973,9 @@
         }
 
         public void show(int textDirection, int textAlignment) {
+            if (mListAdapter == null) {
+                return;
+            }
             AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
             if (mPrompt != null) {
                 builder.setTitle(mPrompt);
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index a564c96..b3b95d9 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -95,6 +95,7 @@
      *
      * @see #setFormat12Hour(CharSequence)
      * @see #getFormat12Hour()
+     *
      * @deprecated Let the system use locale-appropriate defaults instead.
      */
     public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm a";
@@ -108,6 +109,7 @@
      *
      * @see #setFormat24Hour(CharSequence)
      * @see #getFormat24Hour()
+     *
      * @deprecated Let the system use locale-appropriate defaults instead.
      */
     public static final CharSequence DEFAULT_FORMAT_24_HOUR = "H:mm";
@@ -162,9 +164,7 @@
     };
 
     /**
-     * Creates a new clock using the default patterns
-     * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR}
-     * respectively for the 24-hour and 12-hour modes.
+     * Creates a new clock using the default patterns for the current locale.
      *
      * @param context The Context the view is running in, through which it can
      *        access the current theme, resources, etc.
@@ -258,20 +258,26 @@
     }
 
     /**
-     * Specifies the formatting pattern used to display the date and/or time
+     * <p>Specifies the formatting pattern used to display the date and/or time
      * in 12-hour mode. The formatting pattern syntax is described in
-     * {@link DateFormat}.
+     * {@link DateFormat}.</p>
      *
-     * If this pattern is set to null, {@link #getFormat24Hour()} will be used
+     * <p>If this pattern is set to null, {@link #getFormat24Hour()} will be used
      * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
-     * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
-     * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
+     * are set to null, the default pattern for the current locale will be used
+     * instead.</p>
+     *
+     * <p><strong>Note:</strong> if styling is not needed, it is highly recommended
+     * you supply a format string generated by
+     * {@link DateFormat#getBestDateTimePattern(java.util.Locale, String)}. This method
+     * takes care of generating a format string adapted to the desired locale.</p>
+     *
      *
      * @param format A date/time formatting pattern as described in {@link DateFormat}
      *
      * @see #getFormat12Hour()
      * @see #is24HourModeEnabled()
-     * @see #DEFAULT_FORMAT_12_HOUR
+     * @see DateFormat#getBestDateTimePattern(java.util.Locale, String)
      * @see DateFormat
      *
      * @attr ref android.R.styleable#TextClock_format12Hour
@@ -300,20 +306,25 @@
     }
 
     /**
-     * Specifies the formatting pattern used to display the date and/or time
+     * <p>Specifies the formatting pattern used to display the date and/or time
      * in 24-hour mode. The formatting pattern syntax is described in
-     * {@link DateFormat}.
+     * {@link DateFormat}.</p>
      *
-     * If this pattern is set to null, {@link #getFormat12Hour()} will be used
-     * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns
-     * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
-     * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
+     * <p>If this pattern is set to null, {@link #getFormat24Hour()} will be used
+     * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
+     * are set to null, the default pattern for the current locale will be used
+     * instead.</p>
+     *
+     * <p><strong>Note:</strong> if styling is not needed, it is highly recommended
+     * you supply a format string generated by
+     * {@link DateFormat#getBestDateTimePattern(java.util.Locale, String)}. This method
+     * takes care of generating a format string adapted to the desired locale.</p>
      *
      * @param format A date/time formatting pattern as described in {@link DateFormat}
      *
      * @see #getFormat24Hour()
      * @see #is24HourModeEnabled()
-     * @see #DEFAULT_FORMAT_24_HOUR
+     * @see DateFormat#getBestDateTimePattern(java.util.Locale, String)
      * @see DateFormat
      *
      * @attr ref android.R.styleable#TextClock_format24Hour
@@ -334,8 +345,7 @@
      * returned by {@link #getFormat12Hour()} is used instead.
      *
      * If either one of the formats is null, the other format is used. If
-     * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR}
-     * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead.
+     * both formats are null, the default formats for the current locale are used.
      *
      * @return true if time should be displayed in 24-hour format, false if it
      *         should be displayed in 12-hour format.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 04c4070..61e071b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -20,6 +20,7 @@
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
+import android.content.UndoManager;
 import android.content.res.ColorStateList;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Resources;
@@ -291,6 +292,13 @@
 
     private boolean mPreDrawRegistered;
 
+    // A flag to prevent repeated movements from escaping the enclosing text view. The idea here is
+    // that if a user is holding down a movement key to traverse text, we shouldn't also traverse
+    // the view hierarchy. On the other hand, if the user is using the movement key to traverse views
+    // (i.e. the first movement was to traverse out of this view, or this view was traversed into by
+    // the user holding the movement key down) then we shouldn't prevent the focus from changing.
+    private boolean mPreventDefaultMovement;
+
     private TextUtils.TruncateAt mEllipsize;
 
     static class Drawables {
@@ -351,9 +359,7 @@
                             mDrawableRight = mDrawableStart;
                             mDrawableSizeRight = mDrawableSizeStart;
                             mDrawableHeightRight = mDrawableHeightStart;
-                        }
 
-                        if (mOverride) {
                             mDrawableLeft = mDrawableEnd;
                             mDrawableSizeLeft = mDrawableSizeEnd;
                             mDrawableHeightLeft = mDrawableHeightEnd;
@@ -366,9 +372,7 @@
                             mDrawableLeft = mDrawableStart;
                             mDrawableSizeLeft = mDrawableSizeStart;
                             mDrawableHeightLeft = mDrawableHeightStart;
-                        }
 
-                        if (mOverride) {
                             mDrawableRight = mDrawableEnd;
                             mDrawableSizeRight = mDrawableSizeEnd;
                             mDrawableHeightRight = mDrawableHeightEnd;
@@ -547,7 +551,6 @@
     private InputFilter[] mFilters = NO_FILTERS;
 
     private volatile Locale mCurrentSpellCheckerLocaleCache;
-    private final ReentrantLock mCurrentTextServicesLocaleLock = new ReentrantLock();
 
     // It is possible to have a selection even when mEditor is null (programmatically set, like when
     // a link is pressed). These highlight-related fields do not go in mEditor.
@@ -1371,6 +1374,8 @@
             } else {
                 dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
             }
+            resetResolvedDrawables();
+            resolveDrawables();
         }
     }
 
@@ -1510,6 +1515,51 @@
     }
 
     /**
+     * Retrieve the {@link android.content.UndoManager} that is currently associated
+     * with this TextView.  By default there is no associated UndoManager, so null
+     * is returned.  One can be associated with the TextView through
+     * {@link #setUndoManager(android.content.UndoManager, String)}
+     *
+     * @hide
+     */
+    public final UndoManager getUndoManager() {
+        return mEditor == null ? null : mEditor.mUndoManager;
+    }
+
+    /**
+     * Associate an {@link android.content.UndoManager} with this TextView.  Once
+     * done, all edit operations on the TextView will result in appropriate
+     * {@link android.content.UndoOperation} objects pushed on the given UndoManager's
+     * stack.
+     *
+     * @param undoManager The {@link android.content.UndoManager} to associate with
+     * this TextView, or null to clear any existing association.
+     * @param tag String tag identifying this particular TextView owner in the
+     * UndoManager.  This is used to keep the correct association with the
+     * {@link android.content.UndoOwner} of any operations inside of the UndoManager.
+     *
+     * @hide
+     */
+    public final void setUndoManager(UndoManager undoManager, String tag) {
+        if (undoManager != null) {
+            createEditorIfNeeded();
+            mEditor.mUndoManager = undoManager;
+            mEditor.mUndoOwner = undoManager.getOwner(tag, this);
+            mEditor.mUndoInputFilter = new Editor.UndoInputFilter(mEditor);
+            if (!(mText instanceof Editable)) {
+                setText(mText, BufferType.EDITABLE);
+            }
+
+            setFilters((Editable) mText, mFilters);
+        } else if (mEditor != null) {
+            // XXX need to destroy all associated state.
+            mEditor.mUndoManager = null;
+            mEditor.mUndoOwner = null;
+            mEditor.mUndoInputFilter = null;
+        }
+    }
+
+    /**
      * @return the current key listener for this TextView.
      * This will frequently be null for non-EditText TextViews.
      *
@@ -1673,7 +1723,8 @@
         setText(mText);
 
         if (hasPasswordTransformationMethod()) {
-            notifyAccessibilityStateChanged();
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
 
@@ -1994,6 +2045,8 @@
             dr.mDrawableRightInitial = right;
         }
 
+        resetResolvedDrawables();
+        resolveDrawables();
         invalidate();
         requestLayout();
     }
@@ -3774,6 +3827,8 @@
         sendOnTextChanged(text, 0, oldlen, textLength);
         onTextChanged(text, 0, oldlen, textLength);
 
+        notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
+
         if (needEditableForNotification) {
             sendAfterTextChanged((Editable) text);
         }
@@ -4358,6 +4413,8 @@
     public void setError(CharSequence error, Drawable icon) {
         createEditorIfNeeded();
         mEditor.setError(error, icon);
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
     }
 
     @Override
@@ -4401,16 +4458,30 @@
      * and includes mInput in the list if it is an InputFilter.
      */
     private void setFilters(Editable e, InputFilter[] filters) {
-        if (mEditor != null && mEditor.mKeyListener instanceof InputFilter) {
-            InputFilter[] nf = new InputFilter[filters.length + 1];
+        if (mEditor != null) {
+            final boolean undoFilter = mEditor.mUndoInputFilter != null;
+            final boolean keyFilter = mEditor.mKeyListener instanceof InputFilter;
+            int num = 0;
+            if (undoFilter) num++;
+            if (keyFilter) num++;
+            if (num > 0) {
+                InputFilter[] nf = new InputFilter[filters.length + num];
 
-            System.arraycopy(filters, 0, nf, 0, filters.length);
-            nf[filters.length] = (InputFilter) mEditor.mKeyListener;
+                System.arraycopy(filters, 0, nf, 0, filters.length);
+                num = 0;
+                if (undoFilter) {
+                    nf[filters.length] = mEditor.mUndoInputFilter;
+                    num++;
+                }
+                if (keyFilter) {
+                    nf[filters.length + num] = (InputFilter) mEditor.mKeyListener;
+                }
 
-            e.setFilters(nf);
-        } else {
-            e.setFilters(filters);
+                e.setFilters(nf);
+                return;
+            }
         }
+        e.setFilters(filters);
     }
 
     /**
@@ -4608,8 +4679,6 @@
             assumeLayout();
         }
 
-        boolean changed = false;
-
         if (mMovement != null) {
             /* This code also provides auto-scrolling when a cursor is moved using a
              * CursorController (insertion point or selection limits).
@@ -4632,10 +4701,10 @@
             }
 
             if (curs >= 0) {
-                changed = bringPointIntoView(curs);
+                bringPointIntoView(curs);
             }
         } else {
-            changed = bringTextIntoView();
+            bringTextIntoView();
         }
 
         // This has to be checked here since:
@@ -4656,7 +4725,7 @@
         getViewTreeObserver().removeOnPreDrawListener(this);
         mPreDrawRegistered = false;
 
-        return !changed;
+        return true;
     }
 
     @Override
@@ -5282,7 +5351,6 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         int which = doKeyDown(keyCode, event, null);
         if (which == 0) {
-            // Go through default dispatching.
             return super.onKeyDown(keyCode, event);
         }
 
@@ -5380,6 +5448,15 @@
             return 0;
         }
 
+        // If this is the initial keydown, we don't want to prevent a movement away from this view.
+        // While this shouldn't be necessary because any time we're preventing default movement we
+        // should be restricting the focus to remain within this view, thus we'll also receive
+        // the key up event, occasionally key up events will get dropped and we don't want to
+        // prevent the user from traversing out of this on the next key down.
+        if (event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(keyCode)) {
+            mPreventDefaultMovement = false;
+        }
+
         switch (keyCode) {
             case KeyEvent.KEYCODE_ENTER:
                 if (event.hasNoModifiers()) {
@@ -5488,12 +5565,16 @@
                 }
             }
             if (doDown) {
-                if (mMovement.onKeyDown(this, (Spannable)mText, keyCode, event))
+                if (mMovement.onKeyDown(this, (Spannable)mText, keyCode, event)) {
+                    if (event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(keyCode)) {
+                        mPreventDefaultMovement = true;
+                    }
                     return 2;
+                }
             }
         }
 
-        return 0;
+        return mPreventDefaultMovement && !KeyEvent.isModifierKey(keyCode) ? -1 : 0;
     }
 
     /**
@@ -5526,6 +5607,10 @@
             return super.onKeyUp(keyCode, event);
         }
 
+        if (!KeyEvent.isModifierKey(keyCode)) {
+            mPreventDefaultMovement = false;
+        }
+
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_CENTER:
                 if (event.hasNoModifiers()) {
@@ -7240,7 +7325,6 @@
      */
     protected void onSelectionChanged(int selStart, int selEnd) {
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
-        notifyAccessibilityStateChanged();
     }
 
     /**
@@ -7285,27 +7369,42 @@
         }
 
         // The spans that are inside or intersect the modified region no longer make sense
-        removeIntersectingSpans(start, start + before, SpellCheckSpan.class);
-        removeIntersectingSpans(start, start + before, SuggestionSpan.class);
+        removeIntersectingNonAdjacentSpans(start, start + before, SpellCheckSpan.class);
+        removeIntersectingNonAdjacentSpans(start, start + before, SuggestionSpan.class);
     }
 
     // Removes all spans that are inside or actually overlap the start..end range
-    private <T> void removeIntersectingSpans(int start, int end, Class<T> type) {
+    private <T> void removeIntersectingNonAdjacentSpans(int start, int end, Class<T> type) {
         if (!(mText instanceof Editable)) return;
         Editable text = (Editable) mText;
 
         T[] spans = text.getSpans(start, end, type);
         final int length = spans.length;
         for (int i = 0; i < length; i++) {
-            final int s = text.getSpanStart(spans[i]);
-            final int e = text.getSpanEnd(spans[i]);
-            // Spans that are adjacent to the edited region will be handled in
-            // updateSpellCheckSpans. Result depends on what will be added (space or text)
-            if (e == start || s == end) break;
+            final int spanStart = text.getSpanStart(spans[i]);
+            final int spanEnd = text.getSpanEnd(spans[i]);
+            if (spanEnd == start || spanStart == end) break;
             text.removeSpan(spans[i]);
         }
     }
 
+    void removeAdjacentSuggestionSpans(final int pos) {
+        if (!(mText instanceof Editable)) return;
+        final Editable text = (Editable) mText;
+
+        final SuggestionSpan[] spans = text.getSpans(pos, pos, SuggestionSpan.class);
+        final int length = spans.length;
+        for (int i = 0; i < length; i++) {
+            final int spanStart = text.getSpanStart(spans[i]);
+            final int spanEnd = text.getSpanEnd(spans[i]);
+            if (spanEnd == pos || spanStart == pos) {
+                if (SpellChecker.haveWordBoundariesChanged(text, pos, pos, spanStart, spanEnd)) {
+                    text.removeSpan(spans[i]);
+                }
+            }
+        }
+    }
+
     /**
      * Not private so it can be called from an inner class without going
      * through a thunk.
@@ -7737,7 +7836,15 @@
                                 getCompoundPaddingLeft() - getCompoundPaddingRight() -
                                 mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
                     case Gravity.CENTER_HORIZONTAL:
-                        return 0.0f;
+                    case Gravity.FILL_HORIZONTAL:
+                        final int textDirection = mLayout.getParagraphDirection(0);
+                        if (textDirection == Layout.DIR_LEFT_TO_RIGHT) {
+                            return 0.0f;
+                        } else {
+                            return (mLayout.getLineRight(0) - (mRight - mLeft) -
+                                getCompoundPaddingLeft() - getCompoundPaddingRight() -
+                                mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
+                        }
                 }
             }
         }
@@ -7766,9 +7873,14 @@
                         return 0.0f;
                     case Gravity.CENTER_HORIZONTAL:
                     case Gravity.FILL_HORIZONTAL:
-                        return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
+                        final int textDirection = mLayout.getParagraphDirection(0);
+                        if (textDirection == Layout.DIR_RIGHT_TO_LEFT) {
+                            return 0.0f;
+                        } else {
+                            return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
                                 getCompoundPaddingLeft() - getCompoundPaddingRight())) /
                                 getHorizontalFadingEdgeLength();
+                        }
                 }
             }
         }
@@ -7958,16 +8070,13 @@
     }
 
     private void updateTextServicesLocaleAsync() {
+        // AsyncTask.execute() uses a serial executor which means we don't have
+        // to lock around updateTextServicesLocaleLocked() to prevent it from
+        // being executed n times in parallel.
         AsyncTask.execute(new Runnable() {
             @Override
             public void run() {
-                if (mCurrentTextServicesLocaleLock.tryLock()) {
-                    try {
-                        updateTextServicesLocaleLocked();
-                    } finally {
-                        mCurrentTextServicesLocaleLock.unlock();
-                    }
-                }
+                updateTextServicesLocaleLocked();
             }
         });
     }
@@ -8056,6 +8165,14 @@
             info.setEditable(true);
         }
 
+        if (mEditor != null) {
+            info.setInputType(mEditor.mInputType);
+
+            if (mEditor.mError != null) {
+                info.setContentInvalid(true);
+            }
+        }
+
         if (!TextUtils.isEmpty(mText)) {
             info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
             info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
@@ -8080,6 +8197,10 @@
                 info.addAction(AccessibilityNodeInfo.ACTION_CUT);
             }
         }
+
+        if (!isSingleLine()) {
+            info.setMultiLine(true);
+        }
     }
 
     @Override
@@ -8088,7 +8209,6 @@
             case AccessibilityNodeInfo.ACTION_COPY: {
                 if (isFocused() && canCopy()) {
                     if (onTextContextMenuItem(ID_COPY)) {
-                        notifyAccessibilityStateChanged();
                         return true;
                     }
                 }
@@ -8096,7 +8216,6 @@
             case AccessibilityNodeInfo.ACTION_PASTE: {
                 if (isFocused() && canPaste()) {
                     if (onTextContextMenuItem(ID_PASTE)) {
-                        notifyAccessibilityStateChanged();
                         return true;
                     }
                 }
@@ -8104,7 +8223,6 @@
             case AccessibilityNodeInfo.ACTION_CUT: {
                 if (isFocused() && canCut()) {
                     if (onTextContextMenuItem(ID_CUT)) {
-                        notifyAccessibilityStateChanged();
                         return true;
                     }
                 }
@@ -8123,7 +8241,6 @@
                         // No arguments clears the selection.
                         if (start == end && end == -1) {
                             Selection.removeSelection((Spannable) text);
-                            notifyAccessibilityStateChanged();
                             return true;
                         }
                         if (start >= 0 && start <= end && end <= text.length()) {
@@ -8132,7 +8249,6 @@
                             if (mEditor != null) {
                                 mEditor.startSelectionActionMode();
                             }
-                            notifyAccessibilityStateChanged();
                             return true;
                         }
                     }
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index e33c4d4..c26cb24 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -22,10 +22,12 @@
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
@@ -105,6 +107,9 @@
 
     private Locale mCurrentLocale;
 
+    private boolean mHourWithTwoDigit;
+    private char mHourFormat;
+
     /**
      * The callback interface used to indicate the time has been adjusted.
      */
@@ -164,7 +169,7 @@
         // divider (only for the new widget style)
         mDivider = (TextView) findViewById(R.id.divider);
         if (mDivider != null) {
-            mDivider.setText(R.string.time_picker_separator);
+            setDividerText();
         }
 
         // minute
@@ -235,6 +240,24 @@
             mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
         }
 
+        if (isAmPmAtStart()) {
+            // Move the am/pm view to the beginning
+            ViewGroup amPmParent = (ViewGroup) findViewById(R.id.timePickerLayout);
+            amPmParent.removeView(amPmView);
+            amPmParent.addView(amPmView, 0);
+            // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme for
+            // example and not for Holo Theme)
+            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams();
+            final int startMargin = lp.getMarginStart();
+            final int endMargin = lp.getMarginEnd();
+            if (startMargin != endMargin) {
+                lp.setMarginStart(endMargin);
+                lp.setMarginEnd(startMargin);
+            }
+        }
+
+        getHourFormatData();
+
         // update controls to initial state
         updateHourControl();
         updateMinuteControl();
@@ -259,6 +282,35 @@
         }
     }
 
+    private void getHourFormatData() {
+        final Locale defaultLocale = Locale.getDefault();
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final int lengthPattern = bestDateTimePattern.length();
+        mHourWithTwoDigit = false;
+        char hourFormat = '\0';
+        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
+        // the hour format that we found.
+        for (int i = 0; i < lengthPattern; i++) {
+            final char c = bestDateTimePattern.charAt(i);
+            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+                mHourFormat = c;
+                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+                    mHourWithTwoDigit = true;
+                }
+                break;
+            }
+        }
+    }
+
+    private boolean isAmPmAtStart() {
+        final Locale defaultLocale = Locale.getDefault();
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale,
+                "hm" /* skeleton */);
+
+        return bestDateTimePattern.startsWith("a");
+    }
+
     @Override
     public void setEnabled(boolean enabled) {
         if (mIsEnabled == enabled) {
@@ -391,6 +443,10 @@
      * Set the current hour.
      */
     public void setCurrentHour(Integer currentHour) {
+        setCurrentHour(currentHour, true);
+    }
+
+    private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) {
         // why was Integer used in the first place?
         if (currentHour == null || currentHour == getCurrentHour()) {
             return;
@@ -411,7 +467,9 @@
             updateAmPmControl();
         }
         mHourSpinner.setValue(currentHour);
-        onTimeChanged();
+        if (notifyTimeChanged) {
+            onTimeChanged();
+        }
     }
 
     /**
@@ -423,12 +481,16 @@
         if (mIs24HourView == is24HourView) {
             return;
         }
-        mIs24HourView = is24HourView;
-        // cache the current hour since spinner range changes
+        // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!!
         int currentHour = getCurrentHour();
+        // Order is important here.
+        mIs24HourView = is24HourView;
+        getHourFormatData();
         updateHourControl();
-        // set value after spinner range is updated
-        setCurrentHour(currentHour);
+        // set value after spinner range is updated - be aware that because mIs24HourView has
+        // changed then getCurrentHour() is not equal to the currentHour we cached before so
+        // explicitly ask for *not* propagating any onTimeChanged()
+        setCurrentHour(currentHour, false /* no onTimeChanged() */);
         updateMinuteControl();
         updateAmPmControl();
     }
@@ -458,6 +520,38 @@
         onTimeChanged();
     }
 
+    /**
+     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
+     *
+     * See http://unicode.org/cldr/trac/browser/trunk/common/main
+     *
+     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
+     * separator as the character which is just after the hour marker in the returned pattern.
+     */
+    private void setDividerText() {
+        final Locale defaultLocale = Locale.getDefault();
+        final String skeleton = (mIs24HourView) ? "Hm" : "hm";
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale,
+                skeleton);
+        final String separatorText;
+        int hourIndex = bestDateTimePattern.lastIndexOf('H');
+        if (hourIndex == -1) {
+            hourIndex = bestDateTimePattern.lastIndexOf('h');
+        }
+        if (hourIndex == -1) {
+            // Default case
+            separatorText = ":";
+        } else {
+            int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1);
+            if  (minuteIndex == -1) {
+                separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1));
+            } else {
+                separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex);
+            }
+        }
+        mDivider.setText(separatorText);
+    }
+
     @Override
     public int getBaseline() {
         return mHourSpinner.getBaseline();
@@ -500,14 +594,25 @@
 
     private void updateHourControl() {
         if (is24HourView()) {
-            mHourSpinner.setMinValue(0);
-            mHourSpinner.setMaxValue(23);
-            mHourSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
+            // 'k' means 1-24 hour
+            if (mHourFormat == 'k') {
+                mHourSpinner.setMinValue(1);
+                mHourSpinner.setMaxValue(24);
+            } else {
+                mHourSpinner.setMinValue(0);
+                mHourSpinner.setMaxValue(23);
+            }
         } else {
-            mHourSpinner.setMinValue(1);
-            mHourSpinner.setMaxValue(12);
-            mHourSpinner.setFormatter(null);
+            // 'K' means 0-11 hour
+            if (mHourFormat == 'K') {
+                mHourSpinner.setMinValue(0);
+                mHourSpinner.setMaxValue(11);
+            } else {
+                mHourSpinner.setMinValue(1);
+                mHourSpinner.setMaxValue(12);
+            }
         }
+        mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null);
     }
 
     private void updateMinuteControl() {
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 1d85126..4b71e36 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -29,6 +29,7 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -74,6 +75,9 @@
      */
     public static final int LENGTH_LONG = 1;
 
+    /** @hide */
+    public static final int LENGTH_INFINITE = 2;
+
     final Context mContext;
     final TN mTN;
     int mDuration;
@@ -91,6 +95,8 @@
         mTN = new TN();
         mTN.mY = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.toast_y_offset);
+        mTN.mGravity = context.getResources().getInteger(
+                com.android.internal.R.integer.config_toastDefaultGravity);
     }
     
     /**
@@ -288,6 +294,61 @@
         tv.setText(s);
     }
 
+    /** @hide */
+    public static Toast makeBar(Context context, int resId, int duration) {
+        return makeBar(context, context.getResources().getText(resId), duration);
+    }
+
+    /** @hide */
+    public static Toast makeBar(Context context, CharSequence text, int duration) {
+        Toast result = new Toast(context);
+
+        LayoutInflater inflate = (LayoutInflater)
+                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View v = inflate.inflate(com.android.internal.R.layout.toast_bar, null);
+        ((TextView)v.findViewById(android.R.id.message)).setText(text);
+        v.findViewById(android.R.id.button1).setVisibility(View.GONE);
+
+        result.mNextView = v;
+        result.mDuration = duration;
+        result.mTN.mParams.alpha = 0.9f;
+        result.mTN.mParams.windowAnimations = com.android.internal.R.style.Animation_ToastBar;
+
+        return result;
+    }
+
+    /** @hide */
+    public Toast setAction(int resId, Runnable action) {
+        return setAction(mContext.getResources().getText(resId), action);
+    }
+
+    /** @hide */
+    public Toast setAction(CharSequence actionText, final Runnable action) {
+        if (mNextView != null) {
+            TextView text1 = (TextView)mNextView.findViewById(android.R.id.text1);
+            View button1 =  mNextView.findViewById(android.R.id.button1);
+            if (text1 != null && button1 != null) {
+                text1.setText(actionText);
+                button1.setVisibility(View.VISIBLE);
+                button1.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        if (action != null) {
+                            action.run();
+                        }
+                    }});
+                return setInteractive(true);
+            }
+        }
+        throw new RuntimeException("This Toast was not created with Toast.makeBar()");
+    }
+
+    /** @hide */
+    public Toast setInteractive(boolean interactive) {
+        mTN.setInteractive(interactive);
+        return this;
+    }
+
     // =======================================================================================
     // All the gunk below is the interaction with the Notification Service, which handles
     // the proper ordering of these system-wide.
@@ -323,12 +384,12 @@
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
         final Handler mHandler = new Handler();    
 
-        int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+        int mGravity;
         int mX, mY;
         float mHorizontalMargin;
         float mVerticalMargin;
 
-       
+
         View mView;
         View mNextView;
 
@@ -340,13 +401,20 @@
             final WindowManager.LayoutParams params = mParams;
             params.height = WindowManager.LayoutParams.WRAP_CONTENT;
             params.width = WindowManager.LayoutParams.WRAP_CONTENT;
-            params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
             params.format = PixelFormat.TRANSLUCENT;
             params.windowAnimations = com.android.internal.R.style.Animation_Toast;
             params.type = WindowManager.LayoutParams.TYPE_TOAST;
             params.setTitle("Toast");
+            setInteractive(false);
+        }
+
+        private void setInteractive(boolean interactive) {
+            mParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | (interactive
+                            ? (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH)
+                            : WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
         }
 
         /**
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index ebf9fe0..fbdf318 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -21,15 +21,22 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.media.AudioManager;
+import android.media.MediaFormat;
 import android.media.MediaPlayer;
-import android.media.Metadata;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnInfoListener;
+import android.media.Metadata;
+import android.media.SubtitleController;
+import android.media.SubtitleTrack.RenderingWidget;
+import android.media.WebVttRenderer;
 import android.net.Uri;
+import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
@@ -40,7 +47,9 @@
 import android.widget.MediaController.MediaPlayerControl;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Map;
+import java.util.Vector;
 
 /**
  * Displays a video file.  The VideoView class
@@ -49,7 +58,8 @@
  * it can be used in any layout manager, and provides various display options
  * such as scaling and tinting.
  */
-public class VideoView extends SurfaceView implements MediaPlayerControl {
+public class VideoView extends SurfaceView
+        implements MediaPlayerControl, SubtitleController.Anchor {
     private String TAG = "VideoView";
     // settable by the client
     private Uri         mUri;
@@ -91,6 +101,12 @@
     private boolean     mCanSeekBack;
     private boolean     mCanSeekForward;
 
+    /** Subtitle rendering widget overlaid on top of the video. */
+    private RenderingWidget mSubtitleWidget;
+
+    /** Listener for changes to subtitle data, used to redraw when needed. */
+    private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
+
     public VideoView(Context context) {
         super(context);
         initVideoView();
@@ -194,6 +210,7 @@
         setFocusable(true);
         setFocusableInTouchMode(true);
         requestFocus();
+        mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
         mCurrentState = STATE_IDLE;
         mTargetState  = STATE_IDLE;
     }
@@ -218,6 +235,43 @@
         invalidate();
     }
 
+    /**
+     * Adds an external subtitle source file (from the provided input stream.)
+     *
+     * Note that a single external subtitle source may contain multiple or no
+     * supported tracks in it. If the source contained at least one track in
+     * it, one will receive an {@link MediaPlayer#MEDIA_INFO_METADATA_UPDATE}
+     * info message. Otherwise, if reading the source takes excessive time,
+     * one will receive a {@link MediaPlayer#MEDIA_INFO_SUBTITLE_TIMED_OUT}
+     * message. If the source contained no supported track (including an empty
+     * source file or null input stream), one will receive a {@link
+     * MediaPlayer#MEDIA_INFO_UNSUPPORTED_SUBTITLE} message. One can find the
+     * total number of available tracks using {@link MediaPlayer#getTrackInfo()}
+     * to see what additional tracks become available after this method call.
+     *
+     * @param is     input stream containing the subtitle data.  It will be
+     *               closed by the media framework.
+     * @param format the format of the subtitle track(s).  Must contain at least
+     *               the mime type ({@link MediaFormat#KEY_MIME}) and the
+     *               language ({@link MediaFormat#KEY_LANGUAGE}) of the file.
+     *               If the file itself contains the language information,
+     *               specify "und" for the language.
+     */
+    public void addSubtitleSource(InputStream is, MediaFormat format) {
+        if (mMediaPlayer == null) {
+            mPendingSubtitleTracks.add(Pair.create(is, format));
+        } else {
+            try {
+                mMediaPlayer.addSubtitleSource(is, format);
+            } catch (IllegalStateException e) {
+                mInfoListener.onInfo(
+                        mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+            }
+        }
+    }
+
+    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
+
     public void stopPlayback() {
         if (mMediaPlayer != null) {
             mMediaPlayer.stop();
@@ -244,6 +298,14 @@
         release(false);
         try {
             mMediaPlayer = new MediaPlayer();
+            // TODO: create SubtitleController in MediaPlayer, but we need
+            // a context for the subtitle renderers
+            final Context context = getContext();
+            final SubtitleController controller = new SubtitleController(
+                    context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
+            controller.registerRenderer(new WebVttRenderer(context));
+            mMediaPlayer.setSubtitleAnchor(controller, this);
+
             if (mAudioSession != 0) {
                 mMediaPlayer.setAudioSessionId(mAudioSession);
             } else {
@@ -253,7 +315,7 @@
             mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
             mMediaPlayer.setOnCompletionListener(mCompletionListener);
             mMediaPlayer.setOnErrorListener(mErrorListener);
-            mMediaPlayer.setOnInfoListener(mOnInfoListener);
+            mMediaPlayer.setOnInfoListener(mInfoListener);
             mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
             mCurrentBufferPercentage = 0;
             mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
@@ -261,6 +323,16 @@
             mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
             mMediaPlayer.setScreenOnWhilePlaying(true);
             mMediaPlayer.prepareAsync();
+
+            for (Pair<InputStream, MediaFormat> pending: mPendingSubtitleTracks) {
+                try {
+                    mMediaPlayer.addSubtitleSource(pending.first, pending.second);
+                } catch (IllegalStateException e) {
+                    mInfoListener.onInfo(
+                            mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+                }
+            }
+
             // we don't set the target state here either, but preserve the
             // target state that was there before.
             mCurrentState = STATE_PREPARING;
@@ -277,6 +349,8 @@
             mTargetState = STATE_ERROR;
             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
             return;
+        } finally {
+            mPendingSubtitleTracks.clear();
         }
     }
 
@@ -386,6 +460,16 @@
         }
     };
 
+    private MediaPlayer.OnInfoListener mInfoListener =
+        new MediaPlayer.OnInfoListener() {
+        public  boolean onInfo(MediaPlayer mp, int arg1, int arg2) {
+            if (mOnInfoListener != null) {
+                mOnInfoListener.onInfo(mp, arg1, arg2);
+            }
+            return true;
+        }
+    };
+
     private MediaPlayer.OnErrorListener mErrorListener =
         new MediaPlayer.OnErrorListener() {
         public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
@@ -530,6 +614,7 @@
             mMediaPlayer.reset();
             mMediaPlayer.release();
             mMediaPlayer = null;
+            mPendingSubtitleTracks.clear();
             mCurrentState = STATE_IDLE;
             if (cleartargetstate) {
                 mTargetState  = STATE_IDLE;
@@ -702,4 +787,103 @@
         }
         return mAudioSession;
     }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mSubtitleWidget != null) {
+            mSubtitleWidget.onAttachedToWindow();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        if (mSubtitleWidget != null) {
+            mSubtitleWidget.onDetachedFromWindow();
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mSubtitleWidget != null) {
+            measureAndLayoutSubtitleWidget();
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        if (mSubtitleWidget != null) {
+            final int saveCount = canvas.save();
+            canvas.translate(getPaddingLeft(), getPaddingTop());
+            mSubtitleWidget.draw(canvas);
+            canvas.restoreToCount(saveCount);
+        }
+    }
+
+    /**
+     * Forces a measurement and layout pass for all overlaid views.
+     *
+     * @see #setSubtitleWidget(RenderingWidget)
+     */
+    private void measureAndLayoutSubtitleWidget() {
+        final int width = getWidth() - getPaddingLeft() - getPaddingRight();
+        final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+
+        mSubtitleWidget.setSize(width, height);
+    }
+
+    /** @hide */
+    @Override
+    public void setSubtitleWidget(RenderingWidget subtitleWidget) {
+        if (mSubtitleWidget == subtitleWidget) {
+            return;
+        }
+
+        final boolean attachedToWindow = isAttachedToWindow();
+        if (mSubtitleWidget != null) {
+            if (attachedToWindow) {
+                mSubtitleWidget.onDetachedFromWindow();
+            }
+
+            mSubtitleWidget.setOnChangedListener(null);
+        }
+
+        mSubtitleWidget = subtitleWidget;
+
+        if (subtitleWidget != null) {
+            if (mSubtitlesChangedListener == null) {
+                mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() {
+                    @Override
+                    public void onChanged(RenderingWidget renderingWidget) {
+                        invalidate();
+                    }
+                };
+            }
+
+            setWillNotDraw(false);
+            subtitleWidget.setOnChangedListener(mSubtitlesChangedListener);
+
+            if (attachedToWindow) {
+                subtitleWidget.onAttachedToWindow();
+                requestLayout();
+            }
+        } else {
+            setWillNotDraw(true);
+        }
+
+        invalidate();
+    }
+
+    /** @hide */
+    @Override
+    public Looper getSubtitleLooper() {
+        return Looper.getMainLooper();
+    }
 }
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index a89c9c1..50c803b 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -503,7 +503,7 @@
 
             ViewRootImpl viewRoot = mOwnerView.getViewRootImpl();
             if (viewRoot != null) {
-                viewRoot.dispatchKey(event);
+                viewRoot.dispatchInputEvent(event);
             }
 
             // We gave the key to the owner, don't let the container handle this key
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index acbb2b1..066d6c3 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import android.animation.ValueAnimator;
+import android.view.ViewParent;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
@@ -75,7 +77,6 @@
 
     private ActionBarOverlayLayout mOverlayLayout;
     private ActionBarContainer mContainerView;
-    private ViewGroup mTopVisibilityView;
     private ActionBarView mActionView;
     private ActionBarContextView mContextView;
     private ActionBarContainer mSplitView;
@@ -125,12 +126,12 @@
         public void onAnimationEnd(Animator animation) {
             if (mContentAnimations && mContentView != null) {
                 mContentView.setTranslationY(0);
-                mTopVisibilityView.setTranslationY(0);
+                mContainerView.setTranslationY(0);
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setVisibility(View.GONE);
             }
-            mTopVisibilityView.setVisibility(View.GONE);
+            mContainerView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
             mCurrentShowAnim = null;
             completeDeferredDestroyActionMode();
@@ -144,7 +145,16 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             mCurrentShowAnim = null;
-            mTopVisibilityView.requestLayout();
+            mContainerView.requestLayout();
+        }
+    };
+
+    final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            final ViewParent parent = mContainerView.getParent();
+            ((View) parent).invalidate();
         }
     };
 
@@ -153,7 +163,7 @@
         Window window = activity.getWindow();
         View decor = window.getDecorView();
         boolean overlayMode = mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
-        init(decor, overlayMode);
+        init(decor);
         if (!overlayMode) {
             mContentView = decor.findViewById(android.R.id.content);
         }
@@ -161,26 +171,21 @@
 
     public ActionBarImpl(Dialog dialog) {
         mDialog = dialog;
-        init(dialog.getWindow().getDecorView(), false);
+        init(dialog.getWindow().getDecorView());
     }
 
-    private void init(View decor, boolean overlayMode) {
+    private void init(View decor) {
         mContext = decor.getContext();
         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
                 com.android.internal.R.id.action_bar_overlay_layout);
         if (mOverlayLayout != null) {
-            mOverlayLayout.setActionBar(this, overlayMode);
+            mOverlayLayout.setActionBar(this);
         }
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
         mContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.action_bar_container);
-        mTopVisibilityView = (ViewGroup)decor.findViewById(
-                com.android.internal.R.id.top_action_bar);
-        if (mTopVisibilityView == null) {
-            mTopVisibilityView = mContainerView;
-        }
         mSplitView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.split_action_bar);
 
@@ -675,29 +680,30 @@
         if (mCurrentShowAnim != null) {
             mCurrentShowAnim.end();
         }
-        mTopVisibilityView.setVisibility(View.VISIBLE);
+        mContainerView.setVisibility(View.VISIBLE);
 
         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                 || fromSystem)) {
-            mTopVisibilityView.setTranslationY(0); // because we're about to ask its window loc
-            float startingY = -mTopVisibilityView.getHeight();
+            mContainerView.setTranslationY(0); // because we're about to ask its window loc
+            float startingY = -mContainerView.getHeight();
             if (fromSystem) {
                 int topLeft[] = {0, 0};
-                mTopVisibilityView.getLocationInWindow(topLeft);
+                mContainerView.getLocationInWindow(topLeft);
                 startingY -= topLeft[1];
             }
-            mTopVisibilityView.setTranslationY(startingY);
+            mContainerView.setTranslationY(startingY);
             AnimatorSet anim = new AnimatorSet();
-            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
-                    "translationY", 0));
+            ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0);
+            a.addUpdateListener(mUpdateListener);
+            AnimatorSet.Builder b = anim.play(a);
             if (mContentAnimations && mContentView != null) {
-                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
+                b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                         startingY, 0));
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setTranslationY(mSplitView.getHeight());
                 mSplitView.setVisibility(View.VISIBLE);
-                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY", 0));
+                b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y, 0));
             }
             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
                     com.android.internal.R.interpolator.decelerate_cubic));
@@ -713,8 +719,8 @@
             mCurrentShowAnim = anim;
             anim.start();
         } else {
-            mTopVisibilityView.setAlpha(1);
-            mTopVisibilityView.setTranslationY(0);
+            mContainerView.setAlpha(1);
+            mContainerView.setTranslationY(0);
             if (mContentAnimations && mContentView != null) {
                 mContentView.setTranslationY(0);
             }
@@ -737,24 +743,25 @@
 
         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                 || fromSystem)) {
-            mTopVisibilityView.setAlpha(1);
+            mContainerView.setAlpha(1);
             mContainerView.setTransitioning(true);
             AnimatorSet anim = new AnimatorSet();
-            float endingY = -mTopVisibilityView.getHeight();
+            float endingY = -mContainerView.getHeight();
             if (fromSystem) {
                 int topLeft[] = {0, 0};
-                mTopVisibilityView.getLocationInWindow(topLeft);
+                mContainerView.getLocationInWindow(topLeft);
                 endingY -= topLeft[1];
             }
-            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
-                    "translationY", endingY));
+            ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, endingY);
+            a.addUpdateListener(mUpdateListener);
+            AnimatorSet.Builder b = anim.play(a);
             if (mContentAnimations && mContentView != null) {
-                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
+                b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                         0, endingY));
             }
             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                 mSplitView.setAlpha(1);
-                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY",
+                b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y,
                         mSplitView.getHeight()));
             }
             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
@@ -1210,6 +1217,10 @@
         mActionView.setIcon(icon);
     }
 
+    public boolean hasIcon() {
+        return mActionView.hasIcon();
+    }
+
     @Override
     public void setLogo(int resId) {
         mActionView.setLogo(resId);
@@ -1220,6 +1231,10 @@
         mActionView.setLogo(logo);
     }
 
+    public boolean hasLogo() {
+        return mActionView.hasLogo();
+    }
+
     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
         if (!mDisplayHomeAsUpSet) {
             setDisplayHomeAsUpEnabled(enable);
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index 7251256..7456def 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -36,18 +36,18 @@
      * @see #mAlertParams
      */
     protected AlertController mAlert;
-    
+
     /**
      * The parameters for the alert.
      */
     protected AlertController.AlertParams mAlertParams;
-    
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        
+
         mAlert = new AlertController(this, this, getWindow());
-        mAlertParams = new AlertController.AlertParams(this);        
+        mAlertParams = new AlertController.AlertParams(this);
     }
 
     public void cancel() {
@@ -65,7 +65,7 @@
     /**
      * Sets up the alert, including applying the parameters to the alert model,
      * and installing the alert's content.
-     * 
+     *
      * @see #mAlert
      * @see #mAlertParams
      */
@@ -73,7 +73,7 @@
         mAlertParams.apply(mAlert);
         mAlert.installContent();
     }
-    
+
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (mAlert.onKeyDown(keyCode, event)) return true;
@@ -85,6 +85,4 @@
         if (mAlert.onKeyUp(keyCode, event)) return true;
         return super.onKeyUp(keyCode, event);
     }
-    
-    
 }
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index cfd9cc7..16c41f3 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -24,12 +24,14 @@
     // be kept in sync with frameworks/native/include/binder/IAppOpsService.h
     int checkOperation(int code, int uid, String packageName);
     int noteOperation(int code, int uid, String packageName);
-    int startOperation(int code, int uid, String packageName);
-    void finishOperation(int code, int uid, String packageName);
+    int startOperation(IBinder token, int code, int uid, String packageName);
+    void finishOperation(IBinder token, int code, int uid, String packageName);
     void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
     void stopWatchingMode(IAppOpsCallback callback);
+    IBinder getToken(IBinder clientToken);
 
     // Remaining methods are only used in Java.
+    int checkPackage(int uid, String packageName);
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
     void setMode(int code, int uid, String packageName, int mode);
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 823e19f..525517c 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -71,6 +71,7 @@
     void noteWifiMulticastEnabledFromSource(in WorkSource ws);
     void noteWifiMulticastDisabledFromSource(in WorkSource ws);
     void noteNetworkInterfaceType(String iface, int type);
+    void noteNetworkStatsEnabled();
     void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
     long getAwakeTimeBattery();
     long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/app/IProcessStats.aidl b/core/java/com/android/internal/app/IProcessStats.aidl
new file mode 100644
index 0000000..6fadf2f
--- /dev/null
+++ b/core/java/com/android/internal/app/IProcessStats.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.ComponentName;
+import android.os.ParcelFileDescriptor;
+import com.android.internal.app.ProcessStats;
+
+interface IProcessStats {
+    byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
+    ParcelFileDescriptor getStatsOverTime(long minTime);
+    int getCurrentMemoryState();
+}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 3a2b647..76b8579 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,106 +18,147 @@
 
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.Typeface;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.text.method.AllCapsTransformationMethod;
+import android.text.method.TransformationMethod;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
 public class PlatLogoActivity extends Activity {
-    Toast mToast;
-    ImageView mContent;
+    FrameLayout mContent;
     int mCount;
     final Handler mHandler = new Handler();
-
-    private View makeView() {
-        DisplayMetrics metrics = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
-        LinearLayout view = new LinearLayout(this);
-        view.setOrientation(LinearLayout.VERTICAL);
-        view.setLayoutParams(
-                new ViewGroup.LayoutParams(
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT
-                ));
-        final int p = (int)(8 * metrics.density);
-        view.setPadding(p, p, p, p);
-
-        Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
-        Typeface normal = Typeface.create("sans-serif", Typeface.BOLD);
-
-        final float size = 14 * metrics.density;
-        final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                LinearLayout.LayoutParams.WRAP_CONTENT,
-                LinearLayout.LayoutParams.WRAP_CONTENT);
-        lp.gravity = Gravity.CENTER_HORIZONTAL;
-        lp.bottomMargin = (int) (-4*metrics.density);
-
-        TextView tv = new TextView(this);
-        if (light != null) tv.setTypeface(light);
-        tv.setTextSize(1.25f*size);
-        tv.setTextColor(0xFFFFFFFF);
-        tv.setShadowLayer(4*metrics.density, 0, 2*metrics.density, 0x66000000);
-        tv.setText("Android " + Build.VERSION.RELEASE);
-        view.addView(tv, lp);
-   
-        tv = new TextView(this);
-        if (normal != null) tv.setTypeface(normal);
-        tv.setTextSize(size);
-        tv.setTextColor(0xFFFFFFFF);
-        tv.setShadowLayer(4*metrics.density, 0, 2*metrics.density, 0x66000000);
-        tv.setText("JELLY BEAN");
-        view.addView(tv, lp);
-
-        return view;
-    }
+    static final int BGCOLOR = 0xffed1d24;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mToast = Toast.makeText(this, "", Toast.LENGTH_LONG);
-        mToast.setView(makeView());
-
         DisplayMetrics metrics = new DisplayMetrics();
         getWindowManager().getDefaultDisplay().getMetrics(metrics);
 
-        mContent = new ImageView(this);
-        mContent.setImageResource(com.android.internal.R.drawable.platlogo_alt);
-        mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        Typeface bold = Typeface.create("sans-serif", Typeface.BOLD);
+        Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
+
+        mContent = new FrameLayout(this);
+        mContent.setBackgroundColor(0xC0000000);
         
-        final int p = (int)(32 * metrics.density);
-        mContent.setPadding(p, p, p, p);
+        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.WRAP_CONTENT,
+                FrameLayout.LayoutParams.WRAP_CONTENT);
+        lp.gravity = Gravity.CENTER;
+
+        final ImageView logo = new ImageView(this);
+        logo.setImageResource(com.android.internal.R.drawable.platlogo);
+        logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        logo.setVisibility(View.INVISIBLE);
+
+        final View bg = new View(this);
+        bg.setBackgroundColor(BGCOLOR);
+        bg.setAlpha(0f);
+
+        final TextView letter = new TextView(this);
+
+        letter.setTypeface(bold);
+        letter.setTextSize(300);
+        letter.setTextColor(0xFFFFFFFF);
+        letter.setGravity(Gravity.CENTER);
+        letter.setText(String.valueOf(Build.VERSION.RELEASE).substring(0, 1));
+
+        final int p = (int)(4 * metrics.density);
+
+        final TextView tv = new TextView(this);
+        if (light != null) tv.setTypeface(light);
+        tv.setTextSize(30);
+        tv.setPadding(p, p, p, p);
+        tv.setTextColor(0xFFFFFFFF);
+        tv.setGravity(Gravity.CENTER);
+        tv.setTransformationMethod(new AllCapsTransformationMethod(this));
+        tv.setText("Android " + Build.VERSION.RELEASE);
+        tv.setVisibility(View.INVISIBLE);
+
+        mContent.addView(bg);
+        mContent.addView(letter, lp);
+        mContent.addView(logo, lp);
+
+        final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);
+        lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+        lp2.bottomMargin = 10*p;
+
+        mContent.addView(tv, lp2);
 
         mContent.setOnClickListener(new View.OnClickListener() {
+            int clicks;
             @Override
             public void onClick(View v) {
-                mToast.show();
-                mContent.setImageResource(com.android.internal.R.drawable.platlogo);
+                clicks++;
+                if (clicks >= 6) {
+                    mContent.performLongClick();
+                    return;
+                }
+                letter.animate().cancel();
+                final float offset = (int)letter.getRotation() % 360;
+                letter.animate()
+                    .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
+                    .setInterpolator(new DecelerateInterpolator())
+                    .setDuration(700).start();
             }
         });
 
         mContent.setOnLongClickListener(new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
+                if (logo.getVisibility() != View.VISIBLE) {
+                    bg.setScaleX(0.01f);
+                    bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
+                    letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
+                            .rotationBy(360)
+                            .setInterpolator(new AccelerateInterpolator())
+                            .setDuration(1000)
+                            .start();
+                    logo.setAlpha(0f);
+                    logo.setVisibility(View.VISIBLE);
+                    logo.setScaleX(0.5f);
+                    logo.setScaleY(0.5f);
+                    logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
+                        .setDuration(1000).setStartDelay(500)
+                        .setInterpolator(new AnticipateOvershootInterpolator())
+                        .start();
+                    tv.setAlpha(0f);
+                    tv.setVisibility(View.VISIBLE);
+                    tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
+                    return true;
+                }
+                return false;
+            }
+        });
+
+        logo.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
                 try {
                     startActivity(new Intent(Intent.ACTION_MAIN)
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                             | Intent.FLAG_ACTIVITY_CLEAR_TASK
                             | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                         .addCategory("com.android.internal.category.PLATLOGO"));
-                        //.setClassName("com.android.systemui","com.android.systemui.BeanBag"));
                 } catch (ActivityNotFoundException ex) {
-                    android.util.Log.e("PlatLogoActivity", "Couldn't find a bag of beans.");
+                    android.util.Log.e("PlatLogoActivity", "Couldn't find a piece of pie.");
                 }
                 finish();
                 return true;
diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java
new file mode 100644
index 0000000..6ff0304
--- /dev/null
+++ b/core/java/com/android/internal/app/ProcessMap.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.app;
+
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+public class ProcessMap<E> {
+    final ArrayMap<String, SparseArray<E>> mMap
+            = new ArrayMap<String, SparseArray<E>>();
+    
+    public E get(String name, int uid) {
+        SparseArray<E> uids = mMap.get(name);
+        if (uids == null) return null;
+        return uids.get(uid);
+    }
+    
+    public E put(String name, int uid, E value) {
+        SparseArray<E> uids = mMap.get(name);
+        if (uids == null) {
+            uids = new SparseArray<E>(2);
+            mMap.put(name, uids);
+        }
+        uids.put(uid, value);
+        return value;
+    }
+    
+    public void remove(String name, int uid) {
+        SparseArray<E> uids = mMap.get(name);
+        if (uids != null) {
+            uids.remove(uid);
+            if (uids.size() == 0) {
+                mMap.remove(name);
+            }
+        }
+    }
+    
+    public ArrayMap<String, SparseArray<E>> getMap() {
+        return mMap;
+    }
+}
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/core/java/com/android/internal/app/ProcessStats.aidl
new file mode 100644
index 0000000..48b1f85
--- /dev/null
+++ b/core/java/com/android/internal/app/ProcessStats.aidl
@@ -0,0 +1,19 @@
+/*
+** 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.internal.app;
+
+parcelable ProcessStats;
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
new file mode 100644
index 0000000..430e43a
--- /dev/null
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -0,0 +1,3161 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import android.webkit.WebViewFactory;
+import com.android.internal.util.ArrayUtils;
+import dalvik.system.VMRuntime;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ProcessStats implements Parcelable {
+    static final String TAG = "ProcessStats";
+    static final boolean DEBUG = false;
+    static final boolean DEBUG_PARCEL = false;
+
+    public static final String SERVICE_NAME = "procstats";
+
+    // How often the service commits its data, giving the minimum batching
+    // that is done.
+    public static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours
+
+    public static final int STATE_NOTHING = -1;
+    public static final int STATE_PERSISTENT = 0;
+    public static final int STATE_TOP = 1;
+    public static final int STATE_IMPORTANT_FOREGROUND = 2;
+    public static final int STATE_IMPORTANT_BACKGROUND = 3;
+    public static final int STATE_BACKUP = 4;
+    public static final int STATE_HEAVY_WEIGHT = 5;
+    public static final int STATE_SERVICE = 6;
+    public static final int STATE_SERVICE_RESTARTING = 7;
+    public static final int STATE_RECEIVER = 8;
+    public static final int STATE_HOME = 9;
+    public static final int STATE_LAST_ACTIVITY = 10;
+    public static final int STATE_CACHED_ACTIVITY = 11;
+    public static final int STATE_CACHED_ACTIVITY_CLIENT = 12;
+    public static final int STATE_CACHED_EMPTY = 13;
+    public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
+
+    public static final int PSS_SAMPLE_COUNT = 0;
+    public static final int PSS_MINIMUM = 1;
+    public static final int PSS_AVERAGE = 2;
+    public static final int PSS_MAXIMUM = 3;
+    public static final int PSS_USS_MINIMUM = 4;
+    public static final int PSS_USS_AVERAGE = 5;
+    public static final int PSS_USS_MAXIMUM = 6;
+    public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
+
+    public static final int ADJ_NOTHING = -1;
+    public static final int ADJ_MEM_FACTOR_NORMAL = 0;
+    public static final int ADJ_MEM_FACTOR_MODERATE = 1;
+    public static final int ADJ_MEM_FACTOR_LOW = 2;
+    public static final int ADJ_MEM_FACTOR_CRITICAL = 3;
+    public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1;
+    public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT;
+    public static final int ADJ_SCREEN_OFF = 0;
+    public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
+    public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
+
+    public static final int FLAG_COMPLETE = 1<<0;
+    public static final int FLAG_SHUTDOWN = 1<<1;
+    public static final int FLAG_SYSPROPS = 1<<2;
+
+    public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
+            ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
+
+    public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
+
+    public static final int[] NON_CACHED_PROC_STATES = new int[] {
+            STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+            STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
+            STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+    };
+
+    public static final int[] BACKGROUND_PROC_STATES = new int[] {
+            STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+    };
+
+    // Map from process states to the states we track.
+    static final int[] PROCESS_STATE_TO_STATE = new int[] {
+            STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
+            STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+            STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
+            STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+            STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+            STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
+            STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+            STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
+            STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
+            STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
+            STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+            STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+            STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+            STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
+    public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
+            STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
+            STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
+            STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
+    };
+
+    static final String[] STATE_NAMES = new String[] {
+            "Persistent", "Top       ", "Imp Fg    ", "Imp Bg    ",
+            "Backup    ", "Heavy Wght", "Service   ", "Service Rs",
+            "Receiver  ", "Home      ",
+            "Last Act  ", "Cch Act   ", "Cch CliAct", "Cch Empty "
+    };
+
+    public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
+            "off", "on"
+    };
+
+    public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
+            "norm", "mod",  "low", "crit"
+    };
+
+    public static final String[] STATE_NAMES_CSV = new String[] {
+            "pers", "top", "impfg", "impbg", "backup", "heavy",
+            "service", "service-rs", "receiver", "home", "lastact",
+            "cch-activity", "cch-aclient", "cch-empty"
+    };
+
+    static final String[] ADJ_SCREEN_TAGS = new String[] {
+            "0", "1"
+    };
+
+    static final String[] ADJ_MEM_TAGS = new String[] {
+            "n", "m",  "l", "c"
+    };
+
+    static final String[] STATE_TAGS = new String[] {
+            "p", "t", "f", "b", "u", "w",
+            "s", "x", "r", "h", "l", "a", "c", "e"
+    };
+
+    static final String CSV_SEP = "\t";
+
+    // Current version of the parcel format.
+    private static final int PARCEL_VERSION = 13;
+    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
+    private static final int MAGIC = 0x50535453;
+
+    // Where the "type"/"state" part of the data appears in an offset integer.
+    static int OFFSET_TYPE_SHIFT = 0;
+    static int OFFSET_TYPE_MASK = 0xff;
+    // Where the "which array" part of the data appears in an offset integer.
+    static int OFFSET_ARRAY_SHIFT = 8;
+    static int OFFSET_ARRAY_MASK = 0xff;
+    // Where the "index into array" part of the data appears in an offset integer.
+    static int OFFSET_INDEX_SHIFT = 16;
+    static int OFFSET_INDEX_MASK = 0xffff;
+
+    public String mReadError;
+    public String mTimePeriodStartClockStr;
+    public int mFlags;
+
+    public final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>();
+    public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
+
+    public final long[] mMemFactorDurations = new long[ADJ_COUNT];
+    public int mMemFactor = STATE_NOTHING;
+    public long mStartTime;
+
+    public long mTimePeriodStartClock;
+    public long mTimePeriodStartRealtime;
+    public long mTimePeriodEndRealtime;
+    String mRuntime;
+    String mWebView;
+    boolean mRunning;
+
+    static final int LONGS_SIZE = 4096;
+    final ArrayList<long[]> mLongs = new ArrayList<long[]>();
+    int mNextLong;
+
+    int[] mAddLongTable;
+    int mAddLongTableSize;
+
+    // For writing parcels.
+    ArrayMap<String, Integer> mCommonStringToIndex;
+
+    // For reading parcels.
+    ArrayList<String> mIndexToCommonString;
+
+    public ProcessStats(boolean running) {
+        mRunning = running;
+        reset();
+    }
+
+    public ProcessStats(Parcel in) {
+        reset();
+        readFromParcel(in);
+    }
+
+    public void add(ProcessStats other) {
+        ArrayMap<String, SparseArray<PackageState>> pkgMap = other.mPackages.getMap();
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            String pkgName = pkgMap.keyAt(ip);
+            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                PackageState otherState = uids.valueAt(iu);
+                final int NPROCS = otherState.mProcesses.size();
+                final int NSRVS = otherState.mServices.size();
+                for (int iproc=0; iproc<NPROCS; iproc++) {
+                    ProcessState otherProc = otherState.mProcesses.valueAt(iproc);
+                    if (otherProc.mCommonProcess != otherProc) {
+                        if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+                                + " proc " + otherProc.mName);
+                        ProcessState thisProc = getProcessStateLocked(pkgName, uid,
+                                otherProc.mName);
+                        if (thisProc.mCommonProcess == thisProc) {
+                            if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting");
+                            thisProc.mMultiPackage = true;
+                            long now = SystemClock.uptimeMillis();
+                            final PackageState pkgState = getPackageStateLocked(pkgName, uid);
+                            thisProc = thisProc.clone(thisProc.mPackage, now);
+                            pkgState.mProcesses.put(thisProc.mName, thisProc);
+                        }
+                        thisProc.add(otherProc);
+                    }
+                }
+                for (int isvc=0; isvc<NSRVS; isvc++) {
+                    ServiceState otherSvc = otherState.mServices.valueAt(isvc);
+                    if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+                            + " service " + otherSvc.mName);
+                    ServiceState thisSvc = getServiceStateLocked(pkgName, uid,
+                            otherSvc.mProcessName, otherSvc.mName);
+                    thisSvc.add(otherSvc);
+                }
+            }
+        }
+
+        ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
+        for (int ip=0; ip<procMap.size(); ip++) {
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                ProcessState otherProc = uids.valueAt(iu);
+                ProcessState thisProc = mProcesses.get(otherProc.mName, uid);
+                if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + otherProc.mName);
+                if (thisProc == null) {
+                    if (DEBUG) Slog.d(TAG, "Creating new process!");
+                    thisProc = new ProcessState(this, otherProc.mPackage, uid, otherProc.mName);
+                    mProcesses.put(otherProc.mName, uid, thisProc);
+                    PackageState thisState = getPackageStateLocked(otherProc.mPackage, uid);
+                    if (!thisState.mProcesses.containsKey(otherProc.mName)) {
+                        thisState.mProcesses.put(otherProc.mName, thisProc);
+                    }
+                }
+                thisProc.add(otherProc);
+            }
+        }
+
+        for (int i=0; i<ADJ_COUNT; i++) {
+            if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
+                    + other.mMemFactorDurations[i] + " from "
+                    + mMemFactorDurations[i]);
+            mMemFactorDurations[i] += other.mMemFactorDurations[i];
+        }
+
+        if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
+            mTimePeriodStartClock = other.mTimePeriodStartClock;
+            mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
+        }
+        mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
+    }
+
+    public static final Parcelable.Creator<ProcessStats> CREATOR
+            = new Parcelable.Creator<ProcessStats>() {
+        public ProcessStats createFromParcel(Parcel in) {
+            return new ProcessStats(in);
+        }
+
+        public ProcessStats[] newArray(int size) {
+            return new ProcessStats[size];
+        }
+    };
+
+    private static void printScreenLabel(PrintWriter pw, int offset) {
+        switch (offset) {
+            case ADJ_NOTHING:
+                pw.print("             ");
+                break;
+            case ADJ_SCREEN_OFF:
+                pw.print("Screen Off / ");
+                break;
+            case ADJ_SCREEN_ON:
+                pw.print("Screen On  / ");
+                break;
+            default:
+                pw.print("?????????? / ");
+                break;
+        }
+    }
+
+    public static void printScreenLabelCsv(PrintWriter pw, int offset) {
+        switch (offset) {
+            case ADJ_NOTHING:
+                break;
+            case ADJ_SCREEN_OFF:
+                pw.print(ADJ_SCREEN_NAMES_CSV[0]);
+                break;
+            case ADJ_SCREEN_ON:
+                pw.print(ADJ_SCREEN_NAMES_CSV[1]);
+                break;
+            default:
+                pw.print("???");
+                break;
+        }
+    }
+
+    private static void printMemLabel(PrintWriter pw, int offset) {
+        switch (offset) {
+            case ADJ_NOTHING:
+                pw.print("       ");
+                break;
+            case ADJ_MEM_FACTOR_NORMAL:
+                pw.print("Norm / ");
+                break;
+            case ADJ_MEM_FACTOR_MODERATE:
+                pw.print("Mod  / ");
+                break;
+            case ADJ_MEM_FACTOR_LOW:
+                pw.print("Low  / ");
+                break;
+            case ADJ_MEM_FACTOR_CRITICAL:
+                pw.print("Crit / ");
+                break;
+            default:
+                pw.print("???? / ");
+                break;
+        }
+    }
+
+    public static void printMemLabelCsv(PrintWriter pw, int offset) {
+        if (offset >= ADJ_MEM_FACTOR_NORMAL) {
+            if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
+                pw.print(ADJ_MEM_NAMES_CSV[offset]);
+            } else {
+                pw.print("???");
+            }
+        }
+    }
+
+    public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
+            int curState, long curStartTime, long now) {
+        long totalTime = 0;
+        int printedScreen = -1;
+        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+            int printedMem = -1;
+            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+                int state = imem+iscreen;
+                long time = durations[state];
+                String running = "";
+                if (curState == state) {
+                    time += now - curStartTime;
+                    if (pw != null) {
+                        running = " (running)";
+                    }
+                }
+                if (time != 0) {
+                    if (pw != null) {
+                        pw.print(prefix);
+                        printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+                        printedMem = imem;
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                    }
+                    totalTime += time;
+                }
+            }
+        }
+        if (totalTime != 0 && pw != null) {
+            pw.print(prefix);
+            printScreenLabel(pw, STATE_NOTHING);
+            pw.print("TOTAL: ");
+            TimeUtils.formatDuration(totalTime, pw);
+            pw.println();
+        }
+        return totalTime;
+    }
+
+    static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
+            int curState, long curStartTime, long now) {
+        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+                int state = imem+iscreen;
+                long time = durations[state];
+                if (curState == state) {
+                    time += now - curStartTime;
+                }
+                if (time != 0) {
+                    printAdjTagAndValue(pw, state, time);
+                }
+            }
+        }
+    }
+
+    static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName,
+            int uid, String serviceName, ServiceState svc, int serviceType, int opCount,
+            int curState, long curStartTime, long now) {
+        if (opCount <= 0) {
+            return;
+        }
+        pw.print(label);
+        pw.print(",");
+        pw.print(packageName);
+        pw.print(",");
+        pw.print(uid);
+        pw.print(",");
+        pw.print(serviceName);
+        pw.print(",");
+        pw.print(opCount);
+        boolean didCurState = false;
+        for (int i=0; i<svc.mDurationsTableSize; i++) {
+            int off = svc.mDurationsTable[i];
+            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+            int memFactor = type / ServiceState.SERVICE_COUNT;
+            type %= ServiceState.SERVICE_COUNT;
+            if (type != serviceType) {
+                continue;
+            }
+            long time = svc.mStats.getLong(off, 0);
+            if (curState == memFactor) {
+                didCurState = true;
+                time += now - curStartTime;
+            }
+            printAdjTagAndValue(pw, memFactor, time);
+        }
+        if (!didCurState && curState != STATE_NOTHING) {
+            printAdjTagAndValue(pw, curState, now - curStartTime);
+        }
+        pw.println();
+    }
+
+    public static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
+        data.totalTime = 0;
+        data.numPss = data.minPss = data.avgPss = data.maxPss =
+                data.minUss = data.avgUss = data.maxUss = 0;
+        for (int is=0; is<data.screenStates.length; is++) {
+            for (int im=0; im<data.memStates.length; im++) {
+                for (int ip=0; ip<data.procStates.length; ip++) {
+                    int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
+                            + data.procStates[ip];
+                    data.totalTime += proc.getDuration(bucket, now);
+                    long samples = proc.getPssSampleCount(bucket);
+                    if (samples > 0) {
+                        long minPss = proc.getPssMinimum(bucket);
+                        long avgPss = proc.getPssAverage(bucket);
+                        long maxPss = proc.getPssMaximum(bucket);
+                        long minUss = proc.getPssUssMinimum(bucket);
+                        long avgUss = proc.getPssUssAverage(bucket);
+                        long maxUss = proc.getPssUssMaximum(bucket);
+                        if (data.numPss == 0) {
+                            data.minPss = minPss;
+                            data.avgPss = avgPss;
+                            data.maxPss = maxPss;
+                            data.minUss = minUss;
+                            data.avgUss = avgUss;
+                            data.maxUss = maxUss;
+                        } else {
+                            if (minPss < data.minPss) {
+                                data.minPss = minPss;
+                            }
+                            data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
+                                    + (avgPss*(double)samples)) / (data.numPss+samples) );
+                            if (maxPss > data.maxPss) {
+                                data.maxPss = maxPss;
+                            }
+                            if (minUss < data.minUss) {
+                                data.minUss = minUss;
+                            }
+                            data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
+                                    + (avgUss*(double)samples)) / (data.numPss+samples) );
+                            if (maxUss > data.maxUss) {
+                                data.maxUss = maxUss;
+                            }
+                        }
+                        data.numPss += samples;
+                    }
+                }
+            }
+        }
+    }
+
+    static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
+                int[] procStates, long now) {
+        long totalTime = 0;
+        /*
+        for (int i=0; i<proc.mDurationsTableSize; i++) {
+            int val = proc.mDurationsTable[i];
+            totalTime += proc.mState.getLong(val, 0);
+            if ((val&0xff) == proc.mCurState) {
+                totalTime += now - proc.mStartTime;
+            }
+        }
+        */
+        for (int is=0; is<screenStates.length; is++) {
+            for (int im=0; im<memStates.length; im++) {
+                for (int ip=0; ip<procStates.length; ip++) {
+                    int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
+                            + procStates[ip];
+                    totalTime += proc.getDuration(bucket, now);
+                }
+            }
+        }
+        proc.mTmpTotalTime = totalTime;
+        return totalTime;
+    }
+
+    static void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc,
+            int[] screenStates, int[] memStates, int[] procStates, long now) {
+        long totalTime = 0;
+        int printedScreen = -1;
+        for (int is=0; is<screenStates.length; is++) {
+            int printedMem = -1;
+            for (int im=0; im<memStates.length; im++) {
+                for (int ip=0; ip<procStates.length; ip++) {
+                    final int iscreen = screenStates[is];
+                    final int imem = memStates[im];
+                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+                    long time = proc.getDuration(bucket, now);
+                    String running = "";
+                    if (proc.mCurState == bucket) {
+                        running = " (running)";
+                    }
+                    if (time != 0) {
+                        pw.print(prefix);
+                        if (screenStates.length > 1) {
+                            printScreenLabel(pw, printedScreen != iscreen
+                                    ? iscreen : STATE_NOTHING);
+                            printedScreen = iscreen;
+                        }
+                        if (memStates.length > 1) {
+                            printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+                            printedMem = imem;
+                        }
+                        pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                        totalTime += time;
+                    }
+                }
+            }
+        }
+        if (totalTime != 0) {
+            pw.print(prefix);
+            if (screenStates.length > 1) {
+                printScreenLabel(pw, STATE_NOTHING);
+            }
+            if (memStates.length > 1) {
+                printMemLabel(pw, STATE_NOTHING);
+            }
+            pw.print("TOTAL     : ");
+            TimeUtils.formatDuration(totalTime, pw);
+            pw.println();
+        }
+    }
+
+    static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
+            int[] memStates, int[] procStates) {
+        boolean printedHeader = false;
+        int printedScreen = -1;
+        for (int is=0; is<screenStates.length; is++) {
+            int printedMem = -1;
+            for (int im=0; im<memStates.length; im++) {
+                for (int ip=0; ip<procStates.length; ip++) {
+                    final int iscreen = screenStates[is];
+                    final int imem = memStates[im];
+                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+                    long count = proc.getPssSampleCount(bucket);
+                    if (count > 0) {
+                        if (!printedHeader) {
+                            pw.print(prefix);
+                            pw.print("PSS/USS (");
+                            pw.print(proc.mPssTableSize);
+                            pw.println(" entries):");
+                            printedHeader = true;
+                        }
+                        pw.print(prefix);
+                        pw.print("  ");
+                        if (screenStates.length > 1) {
+                            printScreenLabel(pw, printedScreen != iscreen
+                                    ? iscreen : STATE_NOTHING);
+                            printedScreen = iscreen;
+                        }
+                        if (memStates.length > 1) {
+                            printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+                            printedMem = imem;
+                        }
+                        pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
+                        pw.print(count);
+                        pw.print(" samples ");
+                        printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
+                        pw.print(" ");
+                        printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
+                        pw.print(" ");
+                        printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+                        pw.print(" / ");
+                        printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+                        pw.print(" ");
+                        printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+                        pw.print(" ");
+                        printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
+                        pw.println();
+                    }
+                }
+            }
+        }
+        if (proc.mNumExcessiveWake != 0) {
+            pw.print(prefix); pw.print("Killed for excessive wake locks: ");
+                    pw.print(proc.mNumExcessiveWake); pw.println(" times");
+        }
+        if (proc.mNumExcessiveCpu != 0) {
+            pw.print(prefix); pw.print("Killed for excessive CPU use: ");
+                    pw.print(proc.mNumExcessiveCpu); pw.println(" times");
+        }
+        if (proc.mNumCachedKill != 0) {
+            pw.print(prefix); pw.print("Killed from cached state: ");
+                    pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
+                    printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
+                    printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
+                    printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
+        }
+    }
+
+    static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
+            int[] memStates, int[] procStates) {
+        final int NS = screenStates != null ? screenStates.length : 1;
+        final int NM = memStates != null ? memStates.length : 1;
+        final int NP = procStates != null ? procStates.length : 1;
+        for (int is=0; is<NS; is++) {
+            for (int im=0; im<NM; im++) {
+                for (int ip=0; ip<NP; ip++) {
+                    pw.print(sep);
+                    boolean printed = false;
+                    if (screenStates != null && screenStates.length > 1) {
+                        printScreenLabelCsv(pw, screenStates[is]);
+                        printed = true;
+                    }
+                    if (memStates != null && memStates.length > 1) {
+                        if (printed) {
+                            pw.print("-");
+                        }
+                        printMemLabelCsv(pw, memStates[im]);
+                        printed = true;
+                    }
+                    if (procStates != null && procStates.length > 1) {
+                        if (printed) {
+                            pw.print("-");
+                        }
+                        pw.print(STATE_NAMES_CSV[procStates[ip]]);
+                    }
+                }
+            }
+        }
+    }
+
+    static void dumpProcessStateCsv(PrintWriter pw, ProcessState proc,
+            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
+            boolean sepProcStates, int[] procStates, long now) {
+        final int NSS = sepScreenStates ? screenStates.length : 1;
+        final int NMS = sepMemStates ? memStates.length : 1;
+        final int NPS = sepProcStates ? procStates.length : 1;
+        for (int iss=0; iss<NSS; iss++) {
+            for (int ims=0; ims<NMS; ims++) {
+                for (int ips=0; ips<NPS; ips++) {
+                    final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
+                    final int vsmem = sepMemStates ? memStates[ims] : 0;
+                    final int vsproc = sepProcStates ? procStates[ips] : 0;
+                    final int NSA = sepScreenStates ? 1 : screenStates.length;
+                    final int NMA = sepMemStates ? 1 : memStates.length;
+                    final int NPA = sepProcStates ? 1 : procStates.length;
+                    long totalTime = 0;
+                    for (int isa=0; isa<NSA; isa++) {
+                        for (int ima=0; ima<NMA; ima++) {
+                            for (int ipa=0; ipa<NPA; ipa++) {
+                                final int vascreen = sepScreenStates ? 0 : screenStates[isa];
+                                final int vamem = sepMemStates ? 0 : memStates[ima];
+                                final int vaproc = sepProcStates ? 0 : procStates[ipa];
+                                final int bucket = ((vsscreen + vascreen + vsmem + vamem)
+                                        * STATE_COUNT) + vsproc + vaproc;
+                                totalTime += proc.getDuration(bucket, now);
+                            }
+                        }
+                    }
+                    pw.print(CSV_SEP);
+                    pw.print(totalTime);
+                }
+            }
+        }
+    }
+
+    static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
+            int[] screenStates, int[] memStates, int[] procStates, long now) {
+        String innerPrefix = prefix + "  ";
+        for (int i=procs.size()-1; i>=0; i--) {
+            ProcessState proc = procs.get(i);
+            pw.print(prefix);
+            pw.print(proc.mName);
+            pw.print(" / ");
+            UserHandle.formatUid(pw, proc.mUid);
+            pw.print(" (");
+            pw.print(proc.mDurationsTableSize);
+            pw.print(" entries)");
+            pw.println(":");
+            dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now);
+            if (proc.mPssTableSize > 0) {
+                dumpProcessPss(pw, innerPrefix, proc, screenStates, memStates, procStates);
+            }
+        }
+    }
+
+    static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
+            String label, int[] screenStates, int[] memStates, int[] procStates,
+            long now, long totalTime, boolean full) {
+        ProcessDataCollection totals = new ProcessDataCollection(screenStates,
+                memStates, procStates);
+        computeProcessData(proc, totals, now);
+        if (totals.totalTime != 0 || totals.numPss != 0) {
+            if (prefix != null) {
+                pw.print(prefix);
+            }
+            if (label != null) {
+                pw.print(label);
+            }
+            totals.print(pw, totalTime, full);
+            if (prefix != null) {
+                pw.println();
+            }
+        }
+    }
+
+    static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
+            ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
+            long now, long totalTime) {
+        for (int i=procs.size()-1; i>=0; i--) {
+            ProcessState proc = procs.get(i);
+            pw.print(prefix);
+            pw.print("* ");
+            pw.print(proc.mName);
+            pw.print(" / ");
+            UserHandle.formatUid(pw, proc.mUid);
+            pw.println(":");
+            dumpProcessSummaryDetails(pw, proc, prefix, "         TOTAL: ", screenStates, memStates,
+                    procStates, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "    Persistent: ", screenStates, memStates,
+                    new int[] { STATE_PERSISTENT }, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "           Top: ", screenStates, memStates,
+                    new int[] {STATE_TOP}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Fg: ", screenStates, memStates,
+                    new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Bg: ", screenStates, memStates,
+                    new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "        Backup: ", screenStates, memStates,
+                    new int[] {STATE_BACKUP}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "     Heavy Wgt: ", screenStates, memStates,
+                    new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "       Service: ", screenStates, memStates,
+                    new int[] {STATE_SERVICE}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "    Service Rs: ", screenStates, memStates,
+                    new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "      Receiver: ", screenStates, memStates,
+                    new int[] {STATE_RECEIVER}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "          Home: ", screenStates, memStates,
+                    new int[] {STATE_HOME}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "    (Last Act): ", screenStates, memStates,
+                    new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "      (Cached): ", screenStates, memStates,
+                    new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
+                            STATE_CACHED_EMPTY}, now, totalTime, true);
+        }
+    }
+
+    static void printPercent(PrintWriter pw, double fraction) {
+        fraction *= 100;
+        if (fraction < 1) {
+            pw.print(String.format("%.2f", fraction));
+        } else if (fraction < 10) {
+            pw.print(String.format("%.1f", fraction));
+        } else {
+            pw.print(String.format("%.0f", fraction));
+        }
+        pw.print("%");
+    }
+
+    static void printSizeValue(PrintWriter pw, long number) {
+        float result = number;
+        String suffix = "";
+        if (result > 900) {
+            suffix = "KB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "MB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "GB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "TB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "PB";
+            result = result / 1024;
+        }
+        String value;
+        if (result < 1) {
+            value = String.format("%.2f", result);
+        } else if (result < 10) {
+            value = String.format("%.1f", result);
+        } else if (result < 100) {
+            value = String.format("%.0f", result);
+        } else {
+            value = String.format("%.0f", result);
+        }
+        pw.print(value);
+        pw.print(suffix);
+    }
+
+    public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
+            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
+            boolean sepProcStates, int[] procStates, long now) {
+        pw.print("process");
+        pw.print(CSV_SEP);
+        pw.print("uid");
+        dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
+                sepMemStates ? memStates : null,
+                sepProcStates ? procStates : null);
+        pw.println();
+        for (int i=procs.size()-1; i>=0; i--) {
+            ProcessState proc = procs.get(i);
+            pw.print(proc.mName);
+            pw.print(CSV_SEP);
+            UserHandle.formatUid(pw, proc.mUid);
+            dumpProcessStateCsv(pw, proc, sepScreenStates, screenStates,
+                    sepMemStates, memStates, sepProcStates, procStates, now);
+            pw.println();
+        }
+    }
+
+    static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
+        int index = value/mod;
+        if (index >= 0 && index < array.length) {
+            pw.print(array[index]);
+        } else {
+            pw.print('?');
+        }
+        return value - index*mod;
+    }
+
+    static void printProcStateTag(PrintWriter pw, int state) {
+        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
+        state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
+        printArrayEntry(pw, STATE_TAGS,  state, 1);
+    }
+
+    static void printAdjTag(PrintWriter pw, int state) {
+        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
+        printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
+    }
+
+    static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
+        pw.print(',');
+        printProcStateTag(pw, state);
+        pw.print(':');
+        pw.print(value);
+    }
+
+    static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
+        pw.print(',');
+        printAdjTag(pw, state);
+        pw.print(':');
+        pw.print(value);
+    }
+
+    static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
+        boolean didCurState = false;
+        for (int i=0; i<proc.mDurationsTableSize; i++) {
+            int off = proc.mDurationsTable[i];
+            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+            long time = proc.mStats.getLong(off, 0);
+            if (proc.mCurState == type) {
+                didCurState = true;
+                time += now - proc.mStartTime;
+            }
+            printProcStateTagAndValue(pw, type, time);
+        }
+        if (!didCurState && proc.mCurState != STATE_NOTHING) {
+            printProcStateTagAndValue(pw, proc.mCurState, now - proc.mStartTime);
+        }
+    }
+
+    static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
+        for (int i=0; i<proc.mPssTableSize; i++) {
+            int off = proc.mPssTable[i];
+            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+            long count = proc.mStats.getLong(off, PSS_SAMPLE_COUNT);
+            long min = proc.mStats.getLong(off, PSS_MINIMUM);
+            long avg = proc.mStats.getLong(off, PSS_AVERAGE);
+            long max = proc.mStats.getLong(off, PSS_MAXIMUM);
+            long umin = proc.mStats.getLong(off, PSS_USS_MINIMUM);
+            long uavg = proc.mStats.getLong(off, PSS_USS_AVERAGE);
+            long umax = proc.mStats.getLong(off, PSS_USS_MAXIMUM);
+            pw.print(',');
+            printProcStateTag(pw, type);
+            pw.print(':');
+            pw.print(count);
+            pw.print(':');
+            pw.print(min);
+            pw.print(':');
+            pw.print(avg);
+            pw.print(':');
+            pw.print(max);
+            pw.print(':');
+            pw.print(umin);
+            pw.print(':');
+            pw.print(uavg);
+            pw.print(':');
+            pw.print(umax);
+        }
+    }
+
+    public void reset() {
+        if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr);
+        resetCommon();
+        mPackages.getMap().clear();
+        mProcesses.getMap().clear();
+        mMemFactor = STATE_NOTHING;
+        mStartTime = 0;
+        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+    }
+
+    public void resetSafely() {
+        if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr);
+        resetCommon();
+        long now = SystemClock.uptimeMillis();
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int ip=procMap.size()-1; ip>=0; ip--) {
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=uids.size()-1; iu>=0; iu--) {
+                ProcessState ps = uids.valueAt(iu);
+                if (ps.isInUse()) {
+                    uids.valueAt(iu).resetSafely(now);
+                } else {
+                    uids.valueAt(iu).makeDead();
+                    uids.removeAt(iu);
+                }
+            }
+            if (uids.size() <= 0) {
+                procMap.removeAt(ip);
+            }
+        }
+        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        for (int ip=pkgMap.size()-1; ip>=0; ip--) {
+            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            for (int iu=uids.size()-1; iu>=0; iu--) {
+                PackageState pkgState = uids.valueAt(iu);
+                for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
+                    ProcessState ps = pkgState.mProcesses.valueAt(iproc);
+                    if (ps.isInUse() || ps.mCommonProcess.isInUse()) {
+                        pkgState.mProcesses.valueAt(iproc).resetSafely(now);
+                    } else {
+                        pkgState.mProcesses.valueAt(iproc).makeDead();
+                        pkgState.mProcesses.removeAt(iproc);
+                    }
+                }
+                for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
+                    ServiceState ss = pkgState.mServices.valueAt(isvc);
+                    if (ss.isInUse()) {
+                        pkgState.mServices.valueAt(isvc).resetSafely(now);
+                    } else {
+                        pkgState.mServices.removeAt(isvc);
+                    }
+                }
+                if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
+                    uids.removeAt(iu);
+                }
+            }
+            if (uids.size() <= 0) {
+                pkgMap.removeAt(ip);
+            }
+        }
+        mStartTime = now;
+        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+    }
+
+    private void resetCommon() {
+        mTimePeriodStartClock = System.currentTimeMillis();
+        buildTimePeriodStartClockStr();
+        mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+        mLongs.clear();
+        mLongs.add(new long[LONGS_SIZE]);
+        mNextLong = 0;
+        Arrays.fill(mMemFactorDurations, 0);
+        mStartTime = 0;
+        mReadError = null;
+        mFlags = 0;
+        evaluateSystemProperties(true);
+    }
+
+    public boolean evaluateSystemProperties(boolean update) {
+        boolean changed = false;
+        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib",
+                VMRuntime.getRuntime().vmLibrary());
+        if (!Objects.equals(runtime, mRuntime)) {
+            changed = true;
+            if (update) {
+                mRuntime = runtime;
+            }
+        }
+        String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
+        if (!Objects.equals(webview, mWebView)) {
+            changed = true;
+            if (update) {
+                mWebView = webview;
+            }
+        }
+        return changed;
+    }
+
+    private void buildTimePeriodStartClockStr() {
+        mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                mTimePeriodStartClock).toString();
+    }
+
+    static final int[] BAD_TABLE = new int[0];
+
+    private int[] readTableFromParcel(Parcel in, String name, String what) {
+        final int size = in.readInt();
+        if (size < 0) {
+            Slog.w(TAG, "Ignoring existing stats; bad " + what + " table size: " + size);
+            return BAD_TABLE;
+        }
+        if (size == 0) {
+            return null;
+        }
+        final int[] table = new int[size];
+        for (int i=0; i<size; i++) {
+            table[i] = in.readInt();
+            if (DEBUG_PARCEL) Slog.i(TAG, "Reading in " + name + " table #" + i + ": "
+                    + ProcessStats.printLongOffset(table[i]));
+            if (!validateLongOffset(table[i])) {
+                Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: "
+                        + ProcessStats.printLongOffset(table[i]));
+                return null;
+            }
+        }
+        return table;
+    }
+
+    private void writeCompactedLongArray(Parcel out, long[] array, int num) {
+        for (int i=0; i<num; i++) {
+            long val = array[i];
+            if (val < 0) {
+                Slog.w(TAG, "Time val negative: " + val);
+                val = 0;
+            }
+            if (val <= Integer.MAX_VALUE) {
+                out.writeInt((int)val);
+            } else {
+                int top = ~((int)((val>>32)&0x7fffffff));
+                int bottom = (int)(val&0xfffffff);
+                out.writeInt(top);
+                out.writeInt(bottom);
+            }
+        }
+    }
+
+    private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
+        if (version <= 10) {
+            in.readLongArray(array);
+            return;
+        }
+        final int alen = array.length;
+        if (num > alen) {
+            throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
+        }
+        int i;
+        for (i=0; i<num; i++) {
+            int val = in.readInt();
+            if (val >= 0) {
+                array[i] = val;
+            } else {
+                int bottom = in.readInt();
+                array[i] = (((long)~val)<<32) | bottom;
+            }
+        }
+        while (i < alen) {
+            array[i] = 0;
+            i++;
+        }
+    }
+
+    private void writeCommonString(Parcel out, String name) {
+        Integer index = mCommonStringToIndex.get(name);
+        if (index != null) {
+            out.writeInt(index);
+            return;
+        }
+        index = mCommonStringToIndex.size();
+        mCommonStringToIndex.put(name, index);
+        out.writeInt(~index);
+        out.writeString(name);
+    }
+
+    private String readCommonString(Parcel in, int version) {
+        if (version <= 9) {
+            return in.readString();
+        }
+        int index = in.readInt();
+        if (index >= 0) {
+            return mIndexToCommonString.get(index);
+        }
+        index = ~index;
+        String name = in.readString();
+        while (mIndexToCommonString.size() <= index) {
+            mIndexToCommonString.add(null);
+        }
+        mIndexToCommonString.set(index, name);
+        return name;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        long now = SystemClock.uptimeMillis();
+        out.writeInt(MAGIC);
+        out.writeInt(PARCEL_VERSION);
+        out.writeInt(STATE_COUNT);
+        out.writeInt(ADJ_COUNT);
+        out.writeInt(PSS_COUNT);
+        out.writeInt(LONGS_SIZE);
+
+        mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.mMap.size());
+
+        // First commit all running times.
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        final int NPROC = procMap.size();
+        for (int ip=0; ip<NPROC; ip++) {
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            final int NUID = uids.size();
+            for (int iu=0; iu<NUID; iu++) {
+                uids.valueAt(iu).commitStateTime(now);
+            }
+        }
+        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        final int NPKG = pkgMap.size();
+        for (int ip=0; ip<NPKG; ip++) {
+            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            final int NUID = uids.size();
+            for (int iu=0; iu<NUID; iu++) {
+                PackageState pkgState = uids.valueAt(iu);
+                final int NPROCS = pkgState.mProcesses.size();
+                for (int iproc=0; iproc<NPROCS; iproc++) {
+                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                    if (proc.mCommonProcess != proc) {
+                        proc.commitStateTime(now);
+                    }
+                }
+                final int NSRVS = pkgState.mServices.size();
+                for (int isvc=0; isvc<NSRVS; isvc++) {
+                    pkgState.mServices.valueAt(isvc).commitStateTime(now);
+                }
+            }
+        }
+
+        out.writeLong(mTimePeriodStartClock);
+        out.writeLong(mTimePeriodStartRealtime);
+        out.writeLong(mTimePeriodEndRealtime);
+        out.writeString(mRuntime);
+        out.writeString(mWebView);
+        out.writeInt(mFlags);
+
+        out.writeInt(mLongs.size());
+        out.writeInt(mNextLong);
+        for (int i=0; i<(mLongs.size()-1); i++) {
+            long[] array = mLongs.get(i);
+            writeCompactedLongArray(out, array, array.length);
+        }
+        long[] lastLongs = mLongs.get(mLongs.size() - 1);
+        writeCompactedLongArray(out, lastLongs, mNextLong);
+
+        if (mMemFactor != STATE_NOTHING) {
+            mMemFactorDurations[mMemFactor] += now - mStartTime;
+            mStartTime = now;
+        }
+        writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
+
+        out.writeInt(NPROC);
+        for (int ip=0; ip<NPROC; ip++) {
+            writeCommonString(out, procMap.keyAt(ip));
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            final int NUID = uids.size();
+            out.writeInt(NUID);
+            for (int iu=0; iu<NUID; iu++) {
+                out.writeInt(uids.keyAt(iu));
+                ProcessState proc = uids.valueAt(iu);
+                writeCommonString(out, proc.mPackage);
+                proc.writeToParcel(out, now);
+            }
+        }
+        out.writeInt(NPKG);
+        for (int ip=0; ip<NPKG; ip++) {
+            writeCommonString(out, pkgMap.keyAt(ip));
+            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            final int NUID = uids.size();
+            out.writeInt(NUID);
+            for (int iu=0; iu<NUID; iu++) {
+                out.writeInt(uids.keyAt(iu));
+                PackageState pkgState = uids.valueAt(iu);
+                final int NPROCS = pkgState.mProcesses.size();
+                out.writeInt(NPROCS);
+                for (int iproc=0; iproc<NPROCS; iproc++) {
+                    writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
+                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                    if (proc.mCommonProcess == proc) {
+                        // This is the same as the common process we wrote above.
+                        out.writeInt(0);
+                    } else {
+                        // There is separate data for this package's process.
+                        out.writeInt(1);
+                        proc.writeToParcel(out, now);
+                    }
+                }
+                final int NSRVS = pkgState.mServices.size();
+                out.writeInt(NSRVS);
+                for (int isvc=0; isvc<NSRVS; isvc++) {
+                    out.writeString(pkgState.mServices.keyAt(isvc));
+                    ServiceState svc = pkgState.mServices.valueAt(isvc);
+                    writeCommonString(out, svc.mProcessName);
+                    svc.writeToParcel(out, now);
+                }
+            }
+        }
+
+        mCommonStringToIndex = null;
+    }
+
+    private boolean readCheckedInt(Parcel in, int val, String what) {
+        int got;
+        if ((got=in.readInt()) != val) {
+            mReadError = "bad " + what + ": " + got;
+            return false;
+        }
+        return true;
+    }
+
+    static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
+        int pos = 0;
+        final int initialAvail = stream.available();
+        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
+        while (true) {
+            int amt = stream.read(data, pos, data.length-pos);
+            if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
+                    + " of avail " + data.length);
+            if (amt < 0) {
+                if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+                        + " len=" + data.length);
+                outLen[0] = pos;
+                return data;
+            }
+            pos += amt;
+            if (pos >= data.length) {
+                byte[] newData = new byte[pos+16384];
+                if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+                        + newData.length);
+                System.arraycopy(data, 0, newData, 0, pos);
+                data = newData;
+            }
+        }
+    }
+
+    public void read(InputStream stream) {
+        try {
+            int[] len = new int[1];
+            byte[] raw = readFully(stream, len);
+            Parcel in = Parcel.obtain();
+            in.unmarshall(raw, 0, len[0]);
+            in.setDataPosition(0);
+            stream.close();
+
+            readFromParcel(in);
+        } catch (IOException e) {
+            mReadError = "caught exception: " + e;
+        }
+    }
+
+    public void readFromParcel(Parcel in) {
+        final boolean hadData = mPackages.getMap().size() > 0
+                || mProcesses.getMap().size() > 0;
+        if (hadData) {
+            resetSafely();
+        }
+
+        if (!readCheckedInt(in, MAGIC, "magic number")) {
+            return;
+        }
+        int version = in.readInt();
+        if (version != PARCEL_VERSION) {
+            mReadError = "bad version: " + version;
+            return;
+        }
+        if (!readCheckedInt(in, STATE_COUNT, "state count")) {
+            return;
+        }
+        if (!readCheckedInt(in, ADJ_COUNT, "adj count")) {
+            return;
+        }
+        if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
+            return;
+        }
+        if (!readCheckedInt(in, LONGS_SIZE, "longs size")) {
+            return;
+        }
+
+        mIndexToCommonString = new ArrayList<String>();
+
+        mTimePeriodStartClock = in.readLong();
+        buildTimePeriodStartClockStr();
+        mTimePeriodStartRealtime = in.readLong();
+        mTimePeriodEndRealtime = in.readLong();
+        mRuntime = in.readString();
+        mWebView = in.readString();
+        mFlags = in.readInt();
+
+        final int NLONGS = in.readInt();
+        final int NEXTLONG = in.readInt();
+        mLongs.clear();
+        for (int i=0; i<(NLONGS-1); i++) {
+            while (i >= mLongs.size()) {
+                mLongs.add(new long[LONGS_SIZE]);
+            }
+            readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
+        }
+        long[] longs = new long[LONGS_SIZE];
+        mNextLong = NEXTLONG;
+        readCompactedLongArray(in, version, longs, NEXTLONG);
+        mLongs.add(longs);
+
+        readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
+
+        int NPROC = in.readInt();
+        if (NPROC < 0) {
+            mReadError = "bad process count: " + NPROC;
+            return;
+        }
+        while (NPROC > 0) {
+            NPROC--;
+            String procName = readCommonString(in, version);
+            if (procName == null) {
+                mReadError = "bad process name";
+                return;
+            }
+            int NUID = in.readInt();
+            if (NUID < 0) {
+                mReadError = "bad uid count: " + NUID;
+                return;
+            }
+            while (NUID > 0) {
+                NUID--;
+                int uid = in.readInt();
+                if (uid < 0) {
+                    mReadError = "bad uid: " + uid;
+                    return;
+                }
+                String pkgName = readCommonString(in, version);
+                if (pkgName == null) {
+                    mReadError = "bad process package name";
+                    return;
+                }
+                ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
+                if (proc != null) {
+                    if (!proc.readFromParcel(in, false)) {
+                        return;
+                    }
+                } else {
+                    proc = new ProcessState(this, pkgName, uid, procName);
+                    if (!proc.readFromParcel(in, true)) {
+                        return;
+                    }
+                }
+                if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid
+                        + " " + proc);
+                mProcesses.put(procName, uid, proc);
+            }
+        }
+
+        if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
+
+        int NPKG = in.readInt();
+        if (NPKG < 0) {
+            mReadError = "bad package count: " + NPKG;
+            return;
+        }
+        while (NPKG > 0) {
+            NPKG--;
+            String pkgName = readCommonString(in, version);
+            if (pkgName == null) {
+                mReadError = "bad package name";
+                return;
+            }
+            int NUID = in.readInt();
+            if (NUID < 0) {
+                mReadError = "bad uid count: " + NUID;
+                return;
+            }
+            while (NUID > 0) {
+                NUID--;
+                int uid = in.readInt();
+                if (uid < 0) {
+                    mReadError = "bad uid: " + uid;
+                    return;
+                }
+                PackageState pkgState = new PackageState(pkgName, uid);
+                mPackages.put(pkgName, uid, pkgState);
+                int NPROCS = in.readInt();
+                if (NPROCS < 0) {
+                    mReadError = "bad package process count: " + NPROCS;
+                    return;
+                }
+                while (NPROCS > 0) {
+                    NPROCS--;
+                    String procName = readCommonString(in, version);
+                    if (procName == null) {
+                        mReadError = "bad package process name";
+                        return;
+                    }
+                    int hasProc = in.readInt();
+                    if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid
+                            + " process " + procName + " hasProc=" + hasProc);
+                    ProcessState commonProc = mProcesses.get(procName, uid);
+                    if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid
+                            + ": " + commonProc);
+                    if (commonProc == null) {
+                        mReadError = "no common proc: " + procName;
+                        return;
+                    }
+                    if (hasProc != 0) {
+                        // The process for this package is unique to the package; we
+                        // need to load it.  We don't need to do anything about it if
+                        // it is not unique because if someone later looks for it
+                        // they will find and use it from the global procs.
+                        ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
+                        if (proc != null) {
+                            if (!proc.readFromParcel(in, false)) {
+                                return;
+                            }
+                        } else {
+                            proc = new ProcessState(commonProc, pkgName, uid, procName, 0);
+                            if (!proc.readFromParcel(in, true)) {
+                                return;
+                            }
+                        }
+                        if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
+                                + procName + " " + uid + " " + proc);
+                        pkgState.mProcesses.put(procName, proc);
+                    } else {
+                        if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
+                                + procName + " " + uid + " " + commonProc);
+                        pkgState.mProcesses.put(procName, commonProc);
+                    }
+                }
+                int NSRVS = in.readInt();
+                if (NSRVS < 0) {
+                    mReadError = "bad package service count: " + NSRVS;
+                    return;
+                }
+                while (NSRVS > 0) {
+                    NSRVS--;
+                    String serviceName = in.readString();
+                    if (serviceName == null) {
+                        mReadError = "bad package service name";
+                        return;
+                    }
+                    String processName = version > 9 ? readCommonString(in, version) : null;
+                    ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
+                    if (serv == null) {
+                        serv = new ServiceState(this, pkgName, serviceName, processName, null);
+                    }
+                    if (!serv.readFromParcel(in)) {
+                        return;
+                    }
+                    if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: "
+                            + serviceName + " " + uid + " " + serv);
+                    pkgState.mServices.put(serviceName, serv);
+                }
+            }
+        }
+
+        mIndexToCommonString = null;
+
+        if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
+    }
+
+    int addLongData(int index, int type, int num) {
+        int tableLen = mAddLongTable != null ? mAddLongTable.length : 0;
+        if (mAddLongTableSize >= tableLen) {
+            int newSize = ArrayUtils.idealIntArraySize(tableLen + 1);
+            int[] newTable = new int[newSize];
+            if (tableLen > 0) {
+                System.arraycopy(mAddLongTable, 0, newTable, 0, tableLen);
+            }
+            mAddLongTable = newTable;
+        }
+        if (mAddLongTableSize > 0 && mAddLongTableSize - index != 0) {
+            System.arraycopy(mAddLongTable, index, mAddLongTable, index + 1,
+                    mAddLongTableSize - index);
+        }
+        int off = allocLongData(num);
+        mAddLongTable[index] = type | off;
+        mAddLongTableSize++;
+        return off;
+    }
+
+    int allocLongData(int num) {
+        int whichLongs = mLongs.size()-1;
+        long[] longs = mLongs.get(whichLongs);
+        if (mNextLong + num > longs.length) {
+            longs = new long[LONGS_SIZE];
+            mLongs.add(longs);
+            whichLongs++;
+            mNextLong = 0;
+        }
+        int off = (whichLongs<<OFFSET_ARRAY_SHIFT) | (mNextLong<<OFFSET_INDEX_SHIFT);
+        mNextLong += num;
+        return off;
+    }
+
+    boolean validateLongOffset(int off) {
+        int arr = (off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK;
+        if (arr >= mLongs.size()) {
+            return false;
+        }
+        int idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
+        if (idx >= LONGS_SIZE) {
+            return false;
+        }
+        if (DEBUG_PARCEL) Slog.d(TAG, "Validated long " + printLongOffset(off)
+                + ": " + getLong(off, 0));
+        return true;
+    }
+
+    static String printLongOffset(int off) {
+        StringBuilder sb = new StringBuilder(16);
+        sb.append("a"); sb.append((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+        sb.append("i"); sb.append((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK);
+        sb.append("t"); sb.append((off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK);
+        return sb.toString();
+    }
+
+    void setLong(int off, int index, long value) {
+        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+        longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)] = value;
+    }
+
+    long getLong(int off, int index) {
+        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+        return longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)];
+    }
+
+    static int binarySearch(int[] array, int size, int value) {
+        int lo = 0;
+        int hi = size - 1;
+
+        while (lo <= hi) {
+            int mid = (lo + hi) >>> 1;
+            int midVal = (array[mid] >> OFFSET_TYPE_SHIFT) & OFFSET_TYPE_MASK;
+
+            if (midVal < value) {
+                lo = mid + 1;
+            } else if (midVal > value) {
+                hi = mid - 1;
+            } else {
+                return mid;  // value found
+            }
+        }
+        return ~lo;  // value not present
+    }
+
+    public PackageState getPackageStateLocked(String packageName, int uid) {
+        PackageState as = mPackages.get(packageName, uid);
+        if (as != null) {
+            return as;
+        }
+        as = new PackageState(packageName, uid);
+        mPackages.put(packageName, uid, as);
+        return as;
+    }
+
+    public ProcessState getProcessStateLocked(String packageName, int uid, String processName) {
+        final PackageState pkgState = getPackageStateLocked(packageName, uid);
+        ProcessState ps = pkgState.mProcesses.get(processName);
+        if (ps != null) {
+            return ps;
+        }
+        ProcessState commonProc = mProcesses.get(processName, uid);
+        if (commonProc == null) {
+            commonProc = new ProcessState(this, packageName, uid, processName);
+            mProcesses.put(processName, uid, commonProc);
+            if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc);
+        }
+        if (!commonProc.mMultiPackage) {
+            if (packageName.equals(commonProc.mPackage)) {
+                // This common process is not in use by multiple packages, and
+                // is for the calling package, so we can just use it directly.
+                ps = commonProc;
+                if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc);
+            } else {
+                if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!");
+                // This common process has not been in use by multiple packages,
+                // but it was created for a different package than the caller.
+                // We need to convert it to a multi-package process.
+                commonProc.mMultiPackage = true;
+                // To do this, we need to make two new process states, one a copy
+                // of the current state for the process under the original package
+                // name, and the second a free new process state for it as the
+                // new package name.
+                long now = SystemClock.uptimeMillis();
+                // First let's make a copy of the current process state and put
+                // that under the now unique state for its original package name.
+                final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage, uid);
+                if (commonPkgState != null) {
+                    ProcessState cloned = commonProc.clone(commonProc.mPackage, now);
+                    if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.mPackage
+                            + ": " + cloned);
+                    commonPkgState.mProcesses.put(commonProc.mName, cloned);
+                    // If this has active services, we need to update their process pointer
+                    // to point to the new package-specific process state.
+                    for (int i=commonPkgState.mServices.size()-1; i>=0; i--) {
+                        ServiceState ss = commonPkgState.mServices.valueAt(i);
+                        if (ss.mProc == commonProc) {
+                            if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: "
+                                    + ss);
+                            ss.mProc = cloned;
+                        } else if (DEBUG) {
+                            Slog.d(TAG, "GETPROC leaving proc of " + ss);
+                        }
+                    }
+                } else {
+                    Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage
+                            + "/" + uid + " for proc " + commonProc.mName);
+                }
+                // And now make a fresh new process state for the new package name.
+                ps = new ProcessState(commonProc, packageName, uid, processName, now);
+                if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
+            }
+        } else {
+            // The common process is for multiple packages, we need to create a
+            // separate object for the per-package data.
+            ps = new ProcessState(commonProc, packageName, uid, processName,
+                    SystemClock.uptimeMillis());
+            if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
+        }
+        pkgState.mProcesses.put(processName, ps);
+        if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps);
+        return ps;
+    }
+
+    public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
+            String processName, String className) {
+        final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid);
+        ProcessStats.ServiceState ss = as.mServices.get(className);
+        if (ss != null) {
+            if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss);
+            return ss;
+        }
+        final ProcessStats.ProcessState ps = processName != null
+                ? getProcessStateLocked(packageName, uid, processName) : null;
+        ss = new ProcessStats.ServiceState(this, packageName, className, processName, ps);
+        as.mServices.put(className, ss);
+        if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps);
+        return ss;
+    }
+
+    private void dumpProcessInternalLocked(PrintWriter pw, String prefix, ProcessState proc,
+            boolean dumpAll) {
+        if (dumpAll) {
+            pw.print(prefix); pw.print("myID=");
+                    pw.print(Integer.toHexString(System.identityHashCode(proc)));
+                    pw.print(" mCommonProcess=");
+                    pw.print(Integer.toHexString(System.identityHashCode(proc.mCommonProcess)));
+                    pw.print(" mPackage="); pw.println(proc.mPackage);
+            if (proc.mMultiPackage) {
+                pw.print(prefix); pw.print("mMultiPackage="); pw.println(proc.mMultiPackage);
+            }
+            if (proc != proc.mCommonProcess) {
+                pw.print(prefix); pw.print("Common Proc: "); pw.print(proc.mCommonProcess.mName);
+                        pw.print("/"); pw.print(proc.mCommonProcess.mUid);
+                        pw.print(" pkg="); pw.println(proc.mCommonProcess.mPackage);
+            }
+        }
+        pw.print(prefix); pw.print("mActive="); pw.println(proc.mActive);
+        if (proc.mDead) {
+            pw.print(prefix); pw.print("mDead="); pw.println(proc.mDead);
+        }
+        pw.print(prefix); pw.print("mNumActiveServices="); pw.print(proc.mNumActiveServices);
+                pw.print(" mNumStartedServices=");
+                pw.println(proc.mNumStartedServices);
+    }
+
+    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
+            boolean dumpAll, boolean activeOnly) {
+        long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+                mStartTime, now);
+        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        boolean printedHeader = false;
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            String pkgName = pkgMap.keyAt(ip);
+            if (reqPackage != null && !reqPackage.equals(pkgName)) {
+                continue;
+            }
+            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                PackageState pkgState = uids.valueAt(iu);
+                final int NPROCS = pkgState.mProcesses.size();
+                final int NSRVS = pkgState.mServices.size();
+                if (NPROCS > 0 || NSRVS > 0) {
+                    if (!printedHeader) {
+                        pw.println("Per-Package Stats:");
+                        printedHeader = true;
+                    }
+                    pw.print("  * "); pw.print(pkgName); pw.print(" / ");
+                            UserHandle.formatUid(pw, uid); pw.println(":");
+                }
+                if (!dumpSummary || dumpAll) {
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (activeOnly && !proc.isInUse()) {
+                            pw.print("      (Not active: ");
+                                    pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
+                            continue;
+                        }
+                        pw.print("      Process ");
+                        pw.print(pkgState.mProcesses.keyAt(iproc));
+                        pw.print(" (");
+                        pw.print(proc.mDurationsTableSize);
+                        pw.print(" entries)");
+                        pw.println(":");
+                        dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                ALL_PROC_STATES, now);
+                        dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                ALL_PROC_STATES);
+                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
+                    }
+                } else {
+                    ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (activeOnly && !proc.isInUse()) {
+                            continue;
+                        }
+                        procs.add(proc);
+                    }
+                    dumpProcessSummaryLocked(pw, "      ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                            NON_CACHED_PROC_STATES, now, totalTime);
+                }
+                for (int isvc=0; isvc<NSRVS; isvc++) {
+                    ServiceState svc = pkgState.mServices.valueAt(isvc);
+                    if (activeOnly && !svc.isInUse()) {
+                        pw.print("      (Not active: ");
+                                pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
+                        continue;
+                    }
+                    if (dumpAll) {
+                        pw.print("      Service ");
+                    } else {
+                        pw.print("      * ");
+                    }
+                    pw.print(pkgState.mServices.keyAt(isvc));
+                    pw.println(":");
+                    pw.print("        Process: "); pw.println(svc.mProcessName);
+                    dumpServiceStats(pw, "        ", "          ", "    ", "Running", svc,
+                            svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
+                            svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
+                    dumpServiceStats(pw, "        ", "          ", "    ", "Started", svc,
+                            svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
+                            svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
+                    dumpServiceStats(pw, "        ", "          ", "      ", "Bound", svc,
+                            svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
+                            svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
+                    dumpServiceStats(pw, "        ", "          ", "  ", "Executing", svc,
+                            svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
+                            svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
+                    if (dumpAll) {
+                        if (svc.mOwner != null) {
+                            pw.print("        mOwner="); pw.println(svc.mOwner);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (reqPackage == null) {
+            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+            printedHeader = false;
+            int numShownProcs = 0, numTotalProcs = 0;
+            for (int ip=0; ip<procMap.size(); ip++) {
+                String procName = procMap.keyAt(ip);
+                SparseArray<ProcessState> uids = procMap.valueAt(ip);
+                for (int iu=0; iu<uids.size(); iu++) {
+                    int uid = uids.keyAt(iu);
+                    numTotalProcs++;
+                    ProcessState proc = uids.valueAt(iu);
+                    if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
+                            && proc.mPssTableSize == 0) {
+                        continue;
+                    }
+                    numShownProcs++;
+                    if (!printedHeader) {
+                        pw.println();
+                        pw.println("Per-Process Stats:");
+                        printedHeader = true;
+                    }
+                    if (activeOnly && !proc.isInUse()) {
+                        pw.print("      (Not active: "); pw.print(procName); pw.println(")");
+                        continue;
+                    }
+                    pw.print("  * "); pw.print(procName); pw.print(" / ");
+                            UserHandle.formatUid(pw, uid);
+                            pw.print(" ("); pw.print(proc.mDurationsTableSize);
+                            pw.print(" entries)"); pw.println(":");
+                    dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                            ALL_PROC_STATES, now);
+                    dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                            ALL_PROC_STATES);
+                    if (dumpAll) {
+                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
+                    }
+                }
+            }
+            if (dumpAll) {
+                pw.println();
+                pw.print("  Total procs: "); pw.print(numShownProcs);
+                        pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+            }
+
+            pw.println();
+            if (dumpSummary) {
+                pw.println("Summary:");
+                dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+            } else {
+                dumpTotalsLocked(pw, now);
+            }
+        } else {
+            pw.println();
+            dumpTotalsLocked(pw, now);
+        }
+
+        if (dumpAll) {
+            pw.println();
+            pw.println("Internal state:");
+            pw.print("  Num long arrays: "); pw.println(mLongs.size());
+            pw.print("  Next long entry: "); pw.println(mNextLong);
+            pw.print("  mRunning="); pw.println(mRunning);
+        }
+    }
+
+    public static long dumpSingleServiceTime(PrintWriter pw, String prefix, ServiceState service,
+            int serviceType, int curState, long curStartTime, long now) {
+        long totalTime = 0;
+        int printedScreen = -1;
+        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+            int printedMem = -1;
+            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+                int state = imem+iscreen;
+                long time = service.getDuration(serviceType, curState, curStartTime,
+                        state, now);
+                String running = "";
+                if (curState == state && pw != null) {
+                    running = " (running)";
+                }
+                if (time != 0) {
+                    if (pw != null) {
+                        pw.print(prefix);
+                        printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+                        printedMem = imem;
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                    }
+                    totalTime += time;
+                }
+            }
+        }
+        if (totalTime != 0 && pw != null) {
+            pw.print(prefix);
+            printScreenLabel(pw, STATE_NOTHING);
+            pw.print("TOTAL: ");
+            TimeUtils.formatDuration(totalTime, pw);
+            pw.println();
+        }
+        return totalTime;
+    }
+
+    void dumpServiceStats(PrintWriter pw, String prefix, String prefixInner,
+            String headerPrefix, String header, ServiceState service,
+            int count, int serviceType, int state, long startTime, long now, long totalTime,
+            boolean dumpAll) {
+        if (count != 0) {
+            if (dumpAll) {
+                pw.print(prefix); pw.print(header);
+                pw.print(" op count "); pw.print(count); pw.println(":");
+                dumpSingleServiceTime(pw, prefixInner, service, serviceType, state, startTime,
+                        now);
+            } else {
+                long myTime = dumpSingleServiceTime(null, null, service, serviceType, state,
+                        startTime, now);
+                pw.print(prefix); pw.print(headerPrefix); pw.print(header);
+                pw.print(" count "); pw.print(count);
+                pw.print(" / time ");
+                printPercent(pw, (double)myTime/(double)totalTime);
+                pw.println();
+            }
+        }
+    }
+
+    public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) {
+        long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+                mStartTime, now);
+        dumpFilteredSummaryLocked(pw, null, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly);
+        pw.println();
+        dumpTotalsLocked(pw, now);
+    }
+
+    void dumpTotalsLocked(PrintWriter pw, long now) {
+        pw.println("Run time Stats:");
+        dumpSingleTime(pw, "  ", mMemFactorDurations, mMemFactor, mStartTime, now);
+        pw.println();
+        pw.print("          Start time: ");
+        pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
+        pw.println();
+        pw.print("  Total elapsed time: ");
+        TimeUtils.formatDuration(
+                (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
+                        - mTimePeriodStartRealtime, pw);
+        boolean partial = true;
+        if ((mFlags&FLAG_SHUTDOWN) != 0) {
+            pw.print(" (shutdown)");
+            partial = false;
+        }
+        if ((mFlags&FLAG_SYSPROPS) != 0) {
+            pw.print(" (sysprops)");
+            partial = false;
+        }
+        if ((mFlags&FLAG_COMPLETE) != 0) {
+            pw.print(" (complete)");
+            partial = false;
+        }
+        if (partial) {
+            pw.print(" (partial)");
+        }
+        pw.print(' ');
+        pw.print(mRuntime);
+        pw.print(' ');
+        pw.print(mWebView);
+        pw.println();
+    }
+
+    void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
+            int[] screenStates, int[] memStates, int[] procStates,
+            int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) {
+        ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
+                procStates, sortProcStates, now, reqPackage, activeOnly);
+        if (procs.size() > 0) {
+            if (header != null) {
+                pw.println();
+                pw.println(header);
+            }
+            dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
+                    sortProcStates, now, totalTime);
+        }
+    }
+
+    public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
+            int[] procStates, int sortProcStates[], long now, String reqPackage,
+            boolean activeOnly) {
+        ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            if (reqPackage != null && !reqPackage.equals(pkgMap.keyAt(ip))) {
+                continue;
+            }
+            SparseArray<PackageState> procs = pkgMap.valueAt(ip);
+            for (int iu=0; iu<procs.size(); iu++) {
+                PackageState state = procs.valueAt(iu);
+                for (int iproc=0; iproc<state.mProcesses.size(); iproc++) {
+                    ProcessState proc = state.mProcesses.valueAt(iproc);
+                    if (activeOnly && !proc.isInUse()) {
+                        continue;
+                    }
+                    foundProcs.add(proc.mCommonProcess);
+                }
+            }
+        }
+        ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size());
+        for (int i=0; i<foundProcs.size(); i++) {
+            ProcessState proc = foundProcs.valueAt(i);
+            if (computeProcessTimeLocked(proc, screenStates, memStates, procStates, now) > 0) {
+                outProcs.add(proc);
+                if (procStates != sortProcStates) {
+                    computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now);
+                }
+            }
+        }
+        Collections.sort(outProcs, new Comparator<ProcessState>() {
+            @Override
+            public int compare(ProcessState lhs, ProcessState rhs) {
+                if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
+                    return -1;
+                } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
+                    return 1;
+                }
+                return 0;
+            }
+        });
+        return outProcs;
+    }
+
+    String collapseString(String pkgName, String itemName) {
+        if (itemName.startsWith(pkgName)) {
+            final int ITEMLEN = itemName.length();
+            final int PKGLEN = pkgName.length();
+            if (ITEMLEN == PKGLEN) {
+                return "";
+            } else if (ITEMLEN >= PKGLEN) {
+                if (itemName.charAt(PKGLEN) == '.') {
+                    return itemName.substring(PKGLEN);
+                }
+            }
+        }
+        return itemName;
+    }
+
+    public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
+        final long now = SystemClock.uptimeMillis();
+        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        pw.println("vers,3");
+        pw.print("period,"); pw.print(mTimePeriodStartClockStr);
+        pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
+        pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
+        boolean partial = true;
+        if ((mFlags&FLAG_SHUTDOWN) != 0) {
+            pw.print(",shutdown");
+            partial = false;
+        }
+        if ((mFlags&FLAG_SYSPROPS) != 0) {
+            pw.print(",sysprops");
+            partial = false;
+        }
+        if ((mFlags&FLAG_COMPLETE) != 0) {
+            pw.print(",complete");
+            partial = false;
+        }
+        if (partial) {
+            pw.print(",partial");
+        }
+        pw.println();
+        pw.print("config,"); pw.print(mRuntime); pw.print(','); pw.println(mWebView);
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            String pkgName = pkgMap.keyAt(ip);
+            if (reqPackage != null && !reqPackage.equals(pkgName)) {
+                continue;
+            }
+            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                PackageState pkgState = uids.valueAt(iu);
+                final int NPROCS = pkgState.mProcesses.size();
+                final int NSRVS = pkgState.mServices.size();
+                for (int iproc=0; iproc<NPROCS; iproc++) {
+                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                    pw.print("pkgproc,");
+                    pw.print(pkgName);
+                    pw.print(",");
+                    pw.print(uid);
+                    pw.print(",");
+                    pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
+                    dumpAllProcessStateCheckin(pw, proc, now);
+                    pw.println();
+                    if (proc.mPssTableSize > 0) {
+                        pw.print("pkgpss,");
+                        pw.print(pkgName);
+                        pw.print(",");
+                        pw.print(uid);
+                        pw.print(",");
+                        pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
+                        dumpAllProcessPssCheckin(pw, proc);
+                        pw.println();
+                    }
+                    if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0
+                            || proc.mNumCachedKill > 0) {
+                        pw.print("pkgkills,");
+                        pw.print(pkgName);
+                        pw.print(",");
+                        pw.print(uid);
+                        pw.print(",");
+                        pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
+                        pw.print(",");
+                        pw.print(proc.mNumExcessiveWake);
+                        pw.print(",");
+                        pw.print(proc.mNumExcessiveCpu);
+                        pw.print(",");
+                        pw.print(proc.mNumCachedKill);
+                        pw.print(",");
+                        pw.print(proc.mMinCachedKillPss);
+                        pw.print(":");
+                        pw.print(proc.mAvgCachedKillPss);
+                        pw.print(":");
+                        pw.print(proc.mMaxCachedKillPss);
+                        pw.println();
+                    }
+                }
+                for (int isvc=0; isvc<NSRVS; isvc++) {
+                    String serviceName = collapseString(pkgName,
+                            pkgState.mServices.keyAt(isvc));
+                    ServiceState svc = pkgState.mServices.valueAt(isvc);
+                    dumpServiceTimeCheckin(pw, "pkgsvc-run", pkgName, uid, serviceName,
+                            svc, ServiceState.SERVICE_RUN, svc.mRunCount,
+                            svc.mRunState, svc.mRunStartTime, now);
+                    dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, serviceName,
+                            svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
+                            svc.mStartedState, svc.mStartedStartTime, now);
+                    dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, serviceName,
+                            svc, ServiceState.SERVICE_BOUND, svc.mBoundCount,
+                            svc.mBoundState, svc.mBoundStartTime, now);
+                    dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, serviceName,
+                            svc, ServiceState.SERVICE_EXEC, svc.mExecCount,
+                            svc.mExecState, svc.mExecStartTime, now);
+                }
+            }
+        }
+
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int ip=0; ip<procMap.size(); ip++) {
+            String procName = procMap.keyAt(ip);
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                ProcessState procState = uids.valueAt(iu);
+                if (procState.mDurationsTableSize > 0) {
+                    pw.print("proc,");
+                    pw.print(procName);
+                    pw.print(",");
+                    pw.print(uid);
+                    dumpAllProcessStateCheckin(pw, procState, now);
+                    pw.println();
+                }
+                if (procState.mPssTableSize > 0) {
+                    pw.print("pss,");
+                    pw.print(procName);
+                    pw.print(",");
+                    pw.print(uid);
+                    dumpAllProcessPssCheckin(pw, procState);
+                    pw.println();
+                }
+                if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0
+                        || procState.mNumCachedKill > 0) {
+                    pw.print("kills,");
+                    pw.print(procName);
+                    pw.print(",");
+                    pw.print(uid);
+                    pw.print(",");
+                    pw.print(procState.mNumExcessiveWake);
+                    pw.print(",");
+                    pw.print(procState.mNumExcessiveCpu);
+                    pw.print(",");
+                    pw.print(procState.mNumCachedKill);
+                    pw.print(",");
+                    pw.print(procState.mMinCachedKillPss);
+                    pw.print(":");
+                    pw.print(procState.mAvgCachedKillPss);
+                    pw.print(":");
+                    pw.print(procState.mMaxCachedKillPss);
+                    pw.println();
+                }
+            }
+        }
+        pw.print("total");
+        dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
+                mStartTime, now);
+        pw.println();
+    }
+
+    public static class DurationsTable {
+        public final ProcessStats mStats;
+        public final String mName;
+        public int[] mDurationsTable;
+        public int mDurationsTableSize;
+
+        public DurationsTable(ProcessStats stats, String name) {
+            mStats = stats;
+            mName = name;
+        }
+
+        void copyDurationsTo(DurationsTable other) {
+            if (mDurationsTable != null) {
+                mStats.mAddLongTable = new int[mDurationsTable.length];
+                mStats.mAddLongTableSize = 0;
+                for (int i=0; i<mDurationsTableSize; i++) {
+                    int origEnt = mDurationsTable[i];
+                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                    int newOff = mStats.addLongData(i, type, 1);
+                    mStats.mAddLongTable[i] = newOff | type;
+                    mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
+                }
+                other.mDurationsTable = mStats.mAddLongTable;
+                other.mDurationsTableSize = mStats.mAddLongTableSize;
+            } else {
+                other.mDurationsTable = null;
+                other.mDurationsTableSize = 0;
+            }
+        }
+
+        void addDurations(DurationsTable other) {
+            for (int i=0; i<other.mDurationsTableSize; i++) {
+                int ent = other.mDurationsTable[i];
+                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
+                        + other.mStats.getLong(ent, 0));
+                addDuration(state, other.mStats.getLong(ent, 0));
+            }
+        }
+
+        void resetDurationsSafely() {
+            mDurationsTable = null;
+            mDurationsTableSize = 0;
+        }
+
+        void writeDurationsToParcel(Parcel out) {
+            out.writeInt(mDurationsTableSize);
+            for (int i=0; i<mDurationsTableSize; i++) {
+                if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
+                        + printLongOffset(mDurationsTable[i]));
+                out.writeInt(mDurationsTable[i]);
+            }
+        }
+
+        boolean readDurationsFromParcel(Parcel in) {
+            mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
+            if (mDurationsTable == BAD_TABLE) {
+                return false;
+            }
+            mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
+            return true;
+        }
+
+        void addDuration(int state, long dur) {
+            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+            int off;
+            if (idx >= 0) {
+                off = mDurationsTable[idx];
+            } else {
+                mStats.mAddLongTable = mDurationsTable;
+                mStats.mAddLongTableSize = mDurationsTableSize;
+                off = mStats.addLongData(~idx, state, 1);
+                mDurationsTable = mStats.mAddLongTable;
+                mDurationsTableSize = mStats.mAddLongTableSize;
+            }
+            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+            if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
+                    + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
+            longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
+        }
+
+        long getDuration(int state, long now) {
+            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+            return idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+        }
+    }
+
+    public static final class ProcessState extends DurationsTable {
+        public final ProcessState mCommonProcess;
+        public final String mPackage;
+        public final int mUid;
+
+        //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
+        int mCurState = STATE_NOTHING;
+        long mStartTime;
+
+        int mLastPssState = STATE_NOTHING;
+        long mLastPssTime;
+        int[] mPssTable;
+        int mPssTableSize;
+
+        boolean mActive;
+        int mNumActiveServices;
+        int mNumStartedServices;
+
+        int mNumExcessiveWake;
+        int mNumExcessiveCpu;
+
+        int mNumCachedKill;
+        long mMinCachedKillPss;
+        long mAvgCachedKillPss;
+        long mMaxCachedKillPss;
+
+        boolean mMultiPackage;
+        boolean mDead;
+
+        public long mTmpTotalTime;
+
+        /**
+         * Create a new top-level process state, for the initial case where there is only
+         * a single package running in a process.  The initial state is not running.
+         */
+        public ProcessState(ProcessStats processStats, String pkg, int uid, String name) {
+            super(processStats, name);
+            mCommonProcess = this;
+            mPackage = pkg;
+            mUid = uid;
+        }
+
+        /**
+         * Create a new per-package process state for an existing top-level process
+         * state.  The current running state of the top-level process is also copied,
+         * marked as started running at 'now'.
+         */
+        public ProcessState(ProcessState commonProcess, String pkg, int uid, String name,
+                long now) {
+            super(commonProcess.mStats, name);
+            mCommonProcess = commonProcess;
+            mPackage = pkg;
+            mUid = uid;
+            mCurState = commonProcess.mCurState;
+            mStartTime = now;
+        }
+
+        ProcessState clone(String pkg, long now) {
+            ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now);
+            copyDurationsTo(pnew);
+            if (mPssTable != null) {
+                mStats.mAddLongTable = new int[mPssTable.length];
+                mStats.mAddLongTableSize = 0;
+                for (int i=0; i<mPssTableSize; i++) {
+                    int origEnt = mPssTable[i];
+                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                    int newOff = mStats.addLongData(i, type, PSS_COUNT);
+                    mStats.mAddLongTable[i] = newOff | type;
+                    for (int j=0; j<PSS_COUNT; j++) {
+                        mStats.setLong(newOff, j, mStats.getLong(origEnt, j));
+                    }
+                }
+                pnew.mPssTable = mStats.mAddLongTable;
+                pnew.mPssTableSize = mStats.mAddLongTableSize;
+            }
+            pnew.mNumExcessiveWake = mNumExcessiveWake;
+            pnew.mNumExcessiveCpu = mNumExcessiveCpu;
+            pnew.mNumCachedKill = mNumCachedKill;
+            pnew.mMinCachedKillPss = mMinCachedKillPss;
+            pnew.mAvgCachedKillPss = mAvgCachedKillPss;
+            pnew.mMaxCachedKillPss = mMaxCachedKillPss;
+            pnew.mActive = mActive;
+            pnew.mNumActiveServices = mNumActiveServices;
+            pnew.mNumStartedServices = mNumStartedServices;
+            return pnew;
+        }
+
+        void add(ProcessState other) {
+            addDurations(other);
+            for (int i=0; i<other.mPssTableSize; i++) {
+                int ent = other.mPssTable[i];
+                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                addPss(state, (int) other.mStats.getLong(ent, PSS_SAMPLE_COUNT),
+                        other.mStats.getLong(ent, PSS_MINIMUM),
+                        other.mStats.getLong(ent, PSS_AVERAGE),
+                        other.mStats.getLong(ent, PSS_MAXIMUM),
+                        other.mStats.getLong(ent, PSS_USS_MINIMUM),
+                        other.mStats.getLong(ent, PSS_USS_AVERAGE),
+                        other.mStats.getLong(ent, PSS_USS_MAXIMUM));
+            }
+            mNumExcessiveWake += other.mNumExcessiveWake;
+            mNumExcessiveCpu += other.mNumExcessiveCpu;
+            if (other.mNumCachedKill > 0) {
+                addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
+                        other.mAvgCachedKillPss, other.mMaxCachedKillPss);
+            }
+        }
+
+        void resetSafely(long now) {
+            resetDurationsSafely();
+            mStartTime = now;
+            mLastPssState = STATE_NOTHING;
+            mLastPssTime = 0;
+            mPssTable = null;
+            mPssTableSize = 0;
+            mNumExcessiveWake = 0;
+            mNumExcessiveCpu = 0;
+            mNumCachedKill = 0;
+            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+        }
+
+        void makeDead() {
+            mDead = true;
+        }
+
+        private void ensureNotDead() {
+            if (!mDead) {
+                return;
+            }
+            Slog.wtfStack(TAG, "ProcessState dead: name=" + mName
+                    + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+        }
+
+        void writeToParcel(Parcel out, long now) {
+            out.writeInt(mMultiPackage ? 1 : 0);
+            writeDurationsToParcel(out);
+            out.writeInt(mPssTableSize);
+            for (int i=0; i<mPssTableSize; i++) {
+                if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
+                        + printLongOffset(mPssTable[i]));
+                out.writeInt(mPssTable[i]);
+            }
+            out.writeInt(mNumExcessiveWake);
+            out.writeInt(mNumExcessiveCpu);
+            out.writeInt(mNumCachedKill);
+            if (mNumCachedKill > 0) {
+                out.writeLong(mMinCachedKillPss);
+                out.writeLong(mAvgCachedKillPss);
+                out.writeLong(mMaxCachedKillPss);
+            }
+        }
+
+        boolean readFromParcel(Parcel in, boolean fully) {
+            boolean multiPackage = in.readInt() != 0;
+            if (fully) {
+                mMultiPackage = multiPackage;
+            }
+            if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
+            if (!readDurationsFromParcel(in)) {
+                return false;
+            }
+            if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
+            mPssTable = mStats.readTableFromParcel(in, mName, "pss");
+            if (mPssTable == BAD_TABLE) {
+                return false;
+            }
+            mPssTableSize = mPssTable != null ? mPssTable.length : 0;
+            mNumExcessiveWake = in.readInt();
+            mNumExcessiveCpu = in.readInt();
+            mNumCachedKill = in.readInt();
+            if (mNumCachedKill > 0) {
+                mMinCachedKillPss = in.readLong();
+                mAvgCachedKillPss = in.readLong();
+                mMaxCachedKillPss = in.readLong();
+            } else {
+                mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+            }
+            return true;
+        }
+
+        public void makeActive() {
+            ensureNotDead();
+            mActive = true;
+        }
+
+        public void makeInactive() {
+            mActive = false;
+        }
+
+        public boolean isInUse() {
+            return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+                    || mCurState != STATE_NOTHING;
+        }
+
+        /**
+         * Update the current state of the given list of processes.
+         *
+         * @param state Current ActivityManager.PROCESS_STATE_*
+         * @param memFactor Current mem factor constant.
+         * @param now Current time.
+         * @param pkgList Processes to update.
+         */
+        public void setState(int state, int memFactor, long now,
+                ArrayMap<String, ProcessState> pkgList) {
+            if (state < 0) {
+                state = mNumStartedServices > 0
+                        ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
+            } else {
+                state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
+            }
+
+            // First update the common process.
+            mCommonProcess.setState(state, now);
+
+            // If the common process is not multi-package, there is nothing else to do.
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            if (pkgList != null) {
+                for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                    pullFixedProc(pkgList, ip).setState(state, now);
+                }
+            }
+        }
+
+        void setState(int state, long now) {
+            ensureNotDead();
+            if (mCurState != state) {
+                //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
+                commitStateTime(now);
+                mCurState = state;
+            }
+        }
+
+        void commitStateTime(long now) {
+            if (mCurState != STATE_NOTHING) {
+                long dur = now - mStartTime;
+                if (dur > 0) {
+                    addDuration(mCurState, dur);
+                }
+            }
+            mStartTime = now;
+        }
+
+        void incActiveServices(String serviceName) {
+            if (DEBUG && "".equals(mName)) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
+                        + " to " + (mNumActiveServices+1), here);
+            }
+            if (mCommonProcess != this) {
+                mCommonProcess.incActiveServices(serviceName);
+            }
+            mNumActiveServices++;
+        }
+
+        void decActiveServices(String serviceName) {
+            if (DEBUG && "".equals(mName)) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+                        + " to " + (mNumActiveServices-1), here);
+            }
+            if (mCommonProcess != this) {
+                mCommonProcess.decActiveServices(serviceName);
+            }
+            mNumActiveServices--;
+            if (mNumActiveServices < 0) {
+                Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
+                        + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
+                mNumActiveServices = 0;
+            }
+        }
+
+        void incStartedServices(int memFactor, long now) {
+            if (mCommonProcess != this) {
+                mCommonProcess.incStartedServices(memFactor, now);
+            }
+            mNumStartedServices++;
+            if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
+                setState(STATE_NOTHING, memFactor, now, null);
+            }
+        }
+
+        void decStartedServices(int memFactor, long now) {
+            if (mCommonProcess != this) {
+                mCommonProcess.decStartedServices(memFactor, now);
+            }
+            mNumStartedServices--;
+            if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
+                setState(STATE_NOTHING, memFactor, now, null);
+            } else if (mNumStartedServices < 0) {
+                Slog.wtfStack(TAG, "Proc started services underrun: pkg="
+                        + mPackage + " uid=" + mUid + " name=" + mName);
+                mNumStartedServices = 0;
+            }
+        }
+
+        public void addPss(long pss, long uss, boolean always,
+                ArrayMap<String, ProcessState> pkgList) {
+            ensureNotDead();
+            if (!always) {
+                if (mLastPssState == mCurState && SystemClock.uptimeMillis()
+                        < (mLastPssTime+(30*1000))) {
+                    return;
+                }
+            }
+            mLastPssState = mCurState;
+            mLastPssTime = SystemClock.uptimeMillis();
+            if (mCurState != STATE_NOTHING) {
+                // First update the common process.
+                mCommonProcess.addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
+
+                // If the common process is not multi-package, there is nothing else to do.
+                if (!mCommonProcess.mMultiPackage) {
+                    return;
+                }
+
+                if (pkgList != null) {
+                    for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                        pullFixedProc(pkgList, ip).addPss(mCurState, 1,
+                                pss, pss, pss, uss, uss, uss);
+                    }
+                }
+            }
+        }
+
+        void addPss(int state, int inCount, long minPss, long avgPss, long maxPss, long minUss,
+                long avgUss, long maxUss) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            int off;
+            if (idx >= 0) {
+                off = mPssTable[idx];
+            } else {
+                mStats.mAddLongTable = mPssTable;
+                mStats.mAddLongTableSize = mPssTableSize;
+                off = mStats.addLongData(~idx, state, PSS_COUNT);
+                mPssTable = mStats.mAddLongTable;
+                mPssTableSize = mStats.mAddLongTableSize;
+            }
+            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+            idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
+            long count = longs[idx+PSS_SAMPLE_COUNT];
+            if (count == 0) {
+                longs[idx+PSS_SAMPLE_COUNT] = inCount;
+                longs[idx+PSS_MINIMUM] = minPss;
+                longs[idx+PSS_AVERAGE] = avgPss;
+                longs[idx+PSS_MAXIMUM] = maxPss;
+                longs[idx+PSS_USS_MINIMUM] = minUss;
+                longs[idx+PSS_USS_AVERAGE] = avgUss;
+                longs[idx+PSS_USS_MAXIMUM] = maxUss;
+            } else {
+                longs[idx+PSS_SAMPLE_COUNT] = count+inCount;
+                if (longs[idx+PSS_MINIMUM] > minPss) {
+                    longs[idx+PSS_MINIMUM] = minPss;
+                }
+                longs[idx+PSS_AVERAGE] = (long)(
+                        ((longs[idx+PSS_AVERAGE]*(double)count)+(avgPss*(double)inCount))
+                                / (count+inCount) );
+                if (longs[idx+PSS_MAXIMUM] < maxPss) {
+                    longs[idx+PSS_MAXIMUM] = maxPss;
+                }
+                if (longs[idx+PSS_USS_MINIMUM] > minUss) {
+                    longs[idx+PSS_USS_MINIMUM] = minUss;
+                }
+                longs[idx+PSS_USS_AVERAGE] = (long)(
+                        ((longs[idx+PSS_USS_AVERAGE]*(double)count)+(avgUss*(double)inCount))
+                                / (count+inCount) );
+                if (longs[idx+PSS_USS_MAXIMUM] < maxUss) {
+                    longs[idx+PSS_USS_MAXIMUM] = maxUss;
+                }
+            }
+        }
+
+        public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+            ensureNotDead();
+            mCommonProcess.mNumExcessiveWake++;
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                pullFixedProc(pkgList, ip).mNumExcessiveWake++;
+            }
+        }
+
+        public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+            ensureNotDead();
+            mCommonProcess.mNumExcessiveCpu++;
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
+            }
+        }
+
+        private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
+            if (mNumCachedKill <= 0) {
+                mNumCachedKill = num;
+                mMinCachedKillPss = minPss;
+                mAvgCachedKillPss = avgPss;
+                mMaxCachedKillPss = maxPss;
+            } else {
+                if (minPss < mMinCachedKillPss) {
+                    mMinCachedKillPss = minPss;
+                }
+                if (maxPss > mMaxCachedKillPss) {
+                    mMaxCachedKillPss = maxPss;
+                }
+                mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
+                        / (mNumCachedKill+num) );
+                mNumCachedKill += num;
+            }
+        }
+
+        public void reportCachedKill(ArrayMap<String, ProcessState> pkgList, long pss) {
+            ensureNotDead();
+            mCommonProcess.addCachedKill(1, pss, pss, pss);
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
+            }
+        }
+
+        ProcessState pullFixedProc(String pkgName) {
+            if (mMultiPackage) {
+                // The array map is still pointing to a common process state
+                // that is now shared across packages.  Update it to point to
+                // the new per-package state.
+                ProcessState proc = mStats.mPackages.get(pkgName, mUid).mProcesses.get(mName);
+                if (proc == null) {
+                    throw new IllegalStateException("Didn't create per-package process");
+                }
+                return proc;
+            }
+            return this;
+        }
+
+        private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
+            ProcessState proc = pkgList.valueAt(index);
+            if (mDead && proc.mCommonProcess != proc) {
+                // Somehow we are contining to use a process state that is dead, because
+                // it was not being told it was active during the last commit.  We can recover
+                // from this by generating a fresh new state, but this is bad because we
+                // are losing whatever data we had in the old process state.
+                Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
+                        + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+                proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mName);
+            }
+            if (proc.mMultiPackage) {
+                // The array map is still pointing to a common process state
+                // that is now shared across packages.  Update it to point to
+                // the new per-package state.
+                PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid);
+                if (pkg == null) {
+                    throw new IllegalStateException("No existing package "
+                            + pkgList.keyAt(index) + "/" + proc.mUid
+                            + " for multi-proc " + proc.mName);
+                }
+                proc = pkg.mProcesses.get(proc.mName);
+                if (proc == null) {
+                    throw new IllegalStateException("Didn't create per-package process "
+                            + proc.mName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
+                }
+                pkgList.setValueAt(index, proc);
+            }
+            return proc;
+        }
+
+        long getDuration(int state, long now) {
+            long time = super.getDuration(state, now);
+            if (mCurState == state) {
+                time += now - mStartTime;
+            }
+            return time;
+        }
+
+        long getPssSampleCount(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
+        }
+
+        long getPssMinimum(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
+        }
+
+        long getPssAverage(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
+        }
+
+        long getPssMaximum(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
+        }
+
+        long getPssUssMinimum(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
+        }
+
+        long getPssUssAverage(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
+        }
+
+        long getPssUssMaximum(int state) {
+            int idx = binarySearch(mPssTable, mPssTableSize, state);
+            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
+                    .append(" ").append(mName).append("/").append(mUid)
+                    .append(" pkg=").append(mPackage);
+            if (mMultiPackage) sb.append(" (multi)");
+            if (mCommonProcess != this) sb.append(" (sub)");
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+
+    public static final class ServiceState extends DurationsTable {
+        public final String mPackage;
+        public final String mProcessName;
+        ProcessState mProc;
+
+        Object mOwner;
+
+        public static final int SERVICE_RUN = 0;
+        public static final int SERVICE_STARTED = 1;
+        public static final int SERVICE_BOUND = 2;
+        public static final int SERVICE_EXEC = 3;
+        static final int SERVICE_COUNT = 4;
+
+        int mRunCount;
+        public int mRunState = STATE_NOTHING;
+        long mRunStartTime;
+
+        int mStartedCount;
+        public int mStartedState = STATE_NOTHING;
+        long mStartedStartTime;
+
+        int mBoundCount;
+        public int mBoundState = STATE_NOTHING;
+        long mBoundStartTime;
+
+        int mExecCount;
+        public int mExecState = STATE_NOTHING;
+        long mExecStartTime;
+
+        public ServiceState(ProcessStats processStats, String pkg, String name,
+                String processName, ProcessState proc) {
+            super(processStats, name);
+            mPackage = pkg;
+            mProcessName = processName;
+            mProc = proc;
+        }
+
+        public void applyNewOwner(Object newOwner) {
+            if (mOwner != newOwner) {
+                if (mOwner == null) {
+                    mOwner = newOwner;
+                    mProc.incActiveServices(mName);
+                } else {
+                    // There was already an old owner, reset this object for its
+                    // new owner.
+                    mOwner = newOwner;
+                    if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
+                            || mExecState != STATE_NOTHING) {
+                        long now = SystemClock.uptimeMillis();
+                        if (mStartedState != STATE_NOTHING) {
+                            if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+                                    + " from " + mOwner + " while started: pkg="
+                                    + mPackage + " service=" + mName + " proc=" + mProc);
+                            setStarted(false, 0, now);
+                        }
+                        if (mBoundState != STATE_NOTHING) {
+                            if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+                                    + " from " + mOwner + " while bound: pkg="
+                                    + mPackage + " service=" + mName + " proc=" + mProc);
+                            setBound(false, 0, now);
+                        }
+                        if (mExecState != STATE_NOTHING) {
+                            if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+                                    + " from " + mOwner + " while executing: pkg="
+                                    + mPackage + " service=" + mName + " proc=" + mProc);
+                            setExecuting(false, 0, now);
+                        }
+                    }
+                }
+            }
+        }
+
+        public void clearCurrentOwner(Object owner) {
+            if (mOwner == owner) {
+                mOwner = null;
+                mProc.decActiveServices(mName);
+                if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
+                        || mExecState != STATE_NOTHING) {
+                    long now = SystemClock.uptimeMillis();
+                    if (mStartedState != STATE_NOTHING) {
+                        Slog.wtfStack(TAG, "Service owner " + owner + " cleared while started: pkg="
+                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        setStarted(false, 0, now);
+                    }
+                    if (mBoundState != STATE_NOTHING) {
+                        Slog.wtfStack(TAG, "Service owner " + owner + " cleared while bound: pkg="
+                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        setBound(false, 0, now);
+                    }
+                    if (mExecState != STATE_NOTHING) {
+                        Slog.wtfStack(TAG, "Service owner " + owner + " cleared while exec: pkg="
+                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        setExecuting(false, 0, now);
+                    }
+                }
+            }
+        }
+
+        public boolean isInUse() {
+            return mOwner != null;
+        }
+
+        void add(ServiceState other) {
+            addDurations(other);
+            mRunCount += other.mRunCount;
+            mStartedCount += other.mStartedCount;
+            mBoundCount += other.mBoundCount;
+            mExecCount += other.mExecCount;
+        }
+
+        void resetSafely(long now) {
+            resetDurationsSafely();
+            mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
+            mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
+            mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
+            mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
+            mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
+        }
+
+        void writeToParcel(Parcel out, long now) {
+            writeDurationsToParcel(out);
+            out.writeInt(mRunCount);
+            out.writeInt(mStartedCount);
+            out.writeInt(mBoundCount);
+            out.writeInt(mExecCount);
+        }
+
+        boolean readFromParcel(Parcel in) {
+            if (!readDurationsFromParcel(in)) {
+                return false;
+            }
+            mRunCount = in.readInt();
+            mStartedCount = in.readInt();
+            mBoundCount = in.readInt();
+            mExecCount = in.readInt();
+            return true;
+        }
+
+        void commitStateTime(long now) {
+            if (mRunState != STATE_NOTHING) {
+                addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
+                mRunStartTime = now;
+            }
+            if (mStartedState != STATE_NOTHING) {
+                addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+                        now - mStartedStartTime);
+                mStartedStartTime = now;
+            }
+            if (mBoundState != STATE_NOTHING) {
+                addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
+                mBoundStartTime = now;
+            }
+            if (mExecState != STATE_NOTHING) {
+                addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
+                mExecStartTime = now;
+            }
+        }
+
+        private void updateRunning(int memFactor, long now) {
+            final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
+                    || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
+            if (mRunState != state) {
+                if (mRunState != STATE_NOTHING) {
+                    addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+                            now - mRunStartTime);
+                } else if (state != STATE_NOTHING) {
+                    mRunCount++;
+                }
+                mRunState = state;
+                mRunStartTime = now;
+            }
+        }
+
+        public void setStarted(boolean started, int memFactor, long now) {
+            if (mOwner == null) {
+                Slog.wtf(TAG, "Starting service " + this + " without owner");
+            }
+            final boolean wasStarted = mStartedState != STATE_NOTHING;
+            final int state = started ? memFactor : STATE_NOTHING;
+            if (mStartedState != state) {
+                if (mStartedState != STATE_NOTHING) {
+                    addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+                            now - mStartedStartTime);
+                } else if (started) {
+                    mStartedCount++;
+                }
+                mStartedState = state;
+                mStartedStartTime = now;
+                mProc = mProc.pullFixedProc(mPackage);
+                if (wasStarted != started) {
+                    if (started) {
+                        mProc.incStartedServices(memFactor, now);
+                    } else {
+                        mProc.decStartedServices(memFactor, now);
+                    }
+                }
+                updateRunning(memFactor, now);
+            }
+        }
+
+        public void setBound(boolean bound, int memFactor, long now) {
+            if (mOwner == null) {
+                Slog.wtf(TAG, "Binding service " + this + " without owner");
+            }
+            final int state = bound ? memFactor : STATE_NOTHING;
+            if (mBoundState != state) {
+                if (mBoundState != STATE_NOTHING) {
+                    addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+                            now - mBoundStartTime);
+                } else if (bound) {
+                    mBoundCount++;
+                }
+                mBoundState = state;
+                mBoundStartTime = now;
+                updateRunning(memFactor, now);
+            }
+        }
+
+        public void setExecuting(boolean executing, int memFactor, long now) {
+            if (mOwner == null) {
+                Slog.wtf(TAG, "Executing service " + this + " without owner");
+            }
+            final int state = executing ? memFactor : STATE_NOTHING;
+            if (mExecState != state) {
+                if (mExecState != STATE_NOTHING) {
+                    addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
+                } else if (executing) {
+                    mExecCount++;
+                }
+                mExecState = state;
+                mExecStartTime = now;
+                updateRunning(memFactor, now);
+            }
+        }
+
+        private long getDuration(int opType, int curState, long startTime, int memFactor,
+                long now) {
+            int state = opType + (memFactor*SERVICE_COUNT);
+            long time = getDuration(state, now);
+            if (curState == memFactor) {
+                time += now - startTime;
+            }
+            return time;
+        }
+
+        public String toString() {
+            return "ServiceState{" + Integer.toHexString(System.identityHashCode(this))
+                    + " " + mName + " pkg=" + mPackage + " proc="
+                    + Integer.toHexString(System.identityHashCode(this)) + "}";
+        }
+    }
+
+    public static final class PackageState {
+        public final ArrayMap<String, ProcessState> mProcesses
+                = new ArrayMap<String, ProcessState>();
+        public final ArrayMap<String, ServiceState> mServices
+                = new ArrayMap<String, ServiceState>();
+        public final String mPackageName;
+        public final int mUid;
+
+        public PackageState(String packageName, int uid) {
+            mUid = uid;
+            mPackageName = packageName;
+        }
+    }
+
+    public static final class ProcessDataCollection {
+        final int[] screenStates;
+        final int[] memStates;
+        final int[] procStates;
+
+        public long totalTime;
+        public long numPss;
+        public long minPss;
+        public long avgPss;
+        public long maxPss;
+        public long minUss;
+        public long avgUss;
+        public long maxUss;
+
+        public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
+            screenStates = _screenStates;
+            memStates = _memStates;
+            procStates = _procStates;
+        }
+
+        void print(PrintWriter pw, long overallTime, boolean full) {
+            if (totalTime > overallTime) {
+                pw.print("*");
+            }
+            printPercent(pw, (double) totalTime / (double) overallTime);
+            if (numPss > 0) {
+                pw.print(" (");
+                printSizeValue(pw, minPss * 1024);
+                pw.print("-");
+                printSizeValue(pw, avgPss * 1024);
+                pw.print("-");
+                printSizeValue(pw, maxPss * 1024);
+                pw.print("/");
+                printSizeValue(pw, minUss * 1024);
+                pw.print("-");
+                printSizeValue(pw, avgUss * 1024);
+                pw.print("-");
+                printSizeValue(pw, maxUss * 1024);
+                if (full) {
+                    pw.print(" over ");
+                    pw.print(numPss);
+                }
+                pw.print(")");
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index c22cd26..cd853b6 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -16,11 +16,13 @@
 
 package com.android.internal.app;
 
+import android.os.AsyncTask;
 import com.android.internal.R;
 import com.android.internal.content.PackageMonitor;
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -44,7 +46,6 @@
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Button;
-import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -70,13 +71,13 @@
     private PackageManager mPm;
     private boolean mAlwaysUseOption;
     private boolean mShowExtended;
-    private GridView mGrid;
+    private ListView mListView;
     private Button mAlwaysButton;
     private Button mOnceButton;
     private int mIconDpi;
     private int mIconSize;
     private int mMaxColumns;
-    private int mLastSelected = GridView.INVALID_POSITION;
+    private int mLastSelected = ListView.INVALID_POSITION;
 
     private boolean mRegistered;
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -87,6 +88,7 @@
 
     private Intent makeMyIntent() {
         Intent intent = new Intent(getIntent());
+        intent.setComponent(null);
         // The resolver activity is set to be hidden from recent tasks.
         // we don't want this attribute to be propagated to the next activity
         // being launched.  Note that if the original Intent also had this
@@ -98,8 +100,20 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        onCreate(savedInstanceState, makeMyIntent(),
-                getResources().getText(com.android.internal.R.string.whichApplication),
+        // Use a specialized prompt when we're handling the 'Home' app startActivity()
+        final int titleResource;
+        final Intent intent = makeMyIntent();
+        final Set<String> categories = intent.getCategories();
+        if (Intent.ACTION_MAIN.equals(intent.getAction())
+                && categories != null
+                && categories.size() == 1
+                && categories.contains(Intent.CATEGORY_HOME)) {
+            titleResource = com.android.internal.R.string.whichHomeApplication;
+        } else {
+            titleResource = com.android.internal.R.string.whichApplication;
+        }
+
+        onCreate(savedInstanceState, intent, getResources().getText(titleResource),
                 null, null, true);
     }
 
@@ -117,7 +131,6 @@
         mPm = getPackageManager();
         mAlwaysUseOption = alwaysUseOption;
         mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
-        intent.setComponent(null);
 
         AlertController.AlertParams ap = mAlertParams;
 
@@ -138,17 +151,15 @@
             finish();
             return;
         } else if (count > 1) {
-            ap.mView = getLayoutInflater().inflate(R.layout.resolver_grid, null);
-            mGrid = (GridView) ap.mView.findViewById(R.id.resolver_grid);
-            mGrid.setAdapter(mAdapter);
-            mGrid.setOnItemClickListener(this);
-            mGrid.setOnItemLongClickListener(new ItemLongClickListener());
+            ap.mView = getLayoutInflater().inflate(R.layout.resolver_list, null);
+            mListView = (ListView) ap.mView.findViewById(R.id.resolver_list);
+            mListView.setAdapter(mAdapter);
+            mListView.setOnItemClickListener(this);
+            mListView.setOnItemLongClickListener(new ItemLongClickListener());
 
             if (alwaysUseOption) {
-                mGrid.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+                mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
             }
-
-            resizeGrid();
         } else if (count == 1) {
             startActivity(mAdapter.intentForPosition(0));
             mPackageMonitor.unregister();
@@ -171,11 +182,11 @@
                 mAlwaysUseOption = false;
             }
         }
-    }
-
-    void resizeGrid() {
-        final int itemCount = mAdapter.getCount();
-        mGrid.setNumColumns(Math.min(itemCount, mMaxColumns));
+        final int initialHighlight = mAdapter.getInitialHighlight();
+        if (initialHighlight >= 0) {
+            mListView.setItemChecked(initialHighlight, true);
+            onItemClick(null, null, initialHighlight, 0); // Other entries are not used
+        }
     }
 
     Drawable getIcon(Resources res, int resId) {
@@ -246,26 +257,26 @@
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         if (mAlwaysUseOption) {
-            final int checkedPos = mGrid.getCheckedItemPosition();
-            final boolean enabled = checkedPos != GridView.INVALID_POSITION;
+            final int checkedPos = mListView.getCheckedItemPosition();
+            final boolean enabled = checkedPos != ListView.INVALID_POSITION;
             mLastSelected = checkedPos;
             mAlwaysButton.setEnabled(enabled);
             mOnceButton.setEnabled(enabled);
             if (enabled) {
-                mGrid.setSelection(checkedPos);
+                mListView.setSelection(checkedPos);
             }
         }
     }
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        final int checkedPos = mGrid.getCheckedItemPosition();
-        final boolean hasValidSelection = checkedPos != GridView.INVALID_POSITION;
+        final int checkedPos = mListView.getCheckedItemPosition();
+        final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
         if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
             mAlwaysButton.setEnabled(hasValidSelection);
             mOnceButton.setEnabled(hasValidSelection);
             if (hasValidSelection) {
-                mGrid.smoothScrollToPosition(checkedPos);
+                mListView.smoothScrollToPosition(checkedPos);
             }
             mLastSelected = checkedPos;
         } else {
@@ -275,11 +286,14 @@
 
     public void onButtonClick(View v) {
         final int id = v.getId();
-        startSelected(mGrid.getCheckedItemPosition(), id == R.id.button_always);
+        startSelected(mListView.getCheckedItemPosition(), id == R.id.button_always);
         dismiss();
     }
 
     void startSelected(int which, boolean always) {
+        if (isFinishing()) {
+            return;
+        }
         ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
         Intent intent = mAdapter.intentForPosition(which);
         onIntentSelected(ri, intent, always);
@@ -287,7 +301,7 @@
     }
 
     protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
-        if (alwaysCheck) {
+        if (mAlwaysUseOption && mAdapter.mOrigResolveList != null) {
             // Build a reasonable intent filter, based on what matched.
             IntentFilter filter = new IntentFilter();
 
@@ -326,6 +340,17 @@
 
                     // Look through the resolved filter to determine which part
                     // of it matched the original Intent.
+                    Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
+                    if (pIt != null) {
+                        String ssp = data.getSchemeSpecificPart();
+                        while (ssp != null && pIt.hasNext()) {
+                            PatternMatcher p = pIt.next();
+                            if (p.match(ssp)) {
+                                filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
+                                break;
+                            }
+                        }
+                    }
                     Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
                     if (aIt != null) {
                         while (aIt.hasNext()) {
@@ -338,7 +363,7 @@
                             }
                         }
                     }
-                    Iterator<PatternMatcher> pIt = ri.filter.pathsIterator();
+                    pIt = ri.filter.pathsIterator();
                     if (pIt != null) {
                         String path = data.getPath();
                         while (path != null && pIt.hasNext()) {
@@ -353,17 +378,28 @@
             }
 
             if (filter != null) {
-                final int N = mAdapter.mList.size();
+                final int N = mAdapter.mOrigResolveList.size();
                 ComponentName[] set = new ComponentName[N];
                 int bestMatch = 0;
                 for (int i=0; i<N; i++) {
-                    ResolveInfo r = mAdapter.mList.get(i).ri;
+                    ResolveInfo r = mAdapter.mOrigResolveList.get(i);
                     set[i] = new ComponentName(r.activityInfo.packageName,
                             r.activityInfo.name);
                     if (r.match > bestMatch) bestMatch = r.match;
                 }
-                getPackageManager().addPreferredActivity(filter, bestMatch, set,
-                        intent.getComponent());
+                if (alwaysCheck) {
+                    getPackageManager().addPreferredActivity(filter, bestMatch, set,
+                            intent.getComponent());
+                } else {
+                    try {
+                        AppGlobals.getPackageManager().setLastChosenActivity(intent,
+                                intent.resolveTypeIfNeeded(getContentResolver()),
+                                PackageManager.MATCH_DEFAULT_ONLY,
+                                filter, bestMatch, intent.getComponent());
+                    } catch (RemoteException re) {
+                        Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
+                    }
+                }
             }
         }
 
@@ -398,16 +434,19 @@
     private final class ResolveListAdapter extends BaseAdapter {
         private final Intent[] mInitialIntents;
         private final List<ResolveInfo> mBaseResolveList;
+        private ResolveInfo mLastChosen;
         private final Intent mIntent;
         private final int mLaunchedFromUid;
         private final LayoutInflater mInflater;
 
-        private List<DisplayResolveInfo> mList;
+        List<DisplayResolveInfo> mList;
+        List<ResolveInfo> mOrigResolveList;
+
+        private int mInitialHighlight = -1;
 
         public ResolveListAdapter(Context context, Intent intent,
                 Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid) {
             mIntent = new Intent(intent);
-            mIntent.setComponent(null);
             mInitialIntents = initialIntents;
             mBaseResolveList = rList;
             mLaunchedFromUid = launchedFromUid;
@@ -424,19 +463,30 @@
             if (newItemCount == 0) {
                 // We no longer have any items...  just finish the activity.
                 finish();
-            } else if (newItemCount != oldItemCount) {
-                resizeGrid();
             }
         }
 
+        public int getInitialHighlight() {
+            return mInitialHighlight;
+        }
+
         private void rebuildList() {
             List<ResolveInfo> currentResolveList;
 
+            try {
+                mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
+                        mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),
+                        PackageManager.MATCH_DEFAULT_ONLY);
+            } catch (RemoteException re) {
+                Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
+            }
+
             mList.clear();
             if (mBaseResolveList != null) {
                 currentResolveList = mBaseResolveList;
+                mOrigResolveList = null;
             } else {
-                currentResolveList = mPm.queryIntentActivities(
+                currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
                         mIntent, PackageManager.MATCH_DEFAULT_ONLY
                         | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
                 // Filter out any activities that the launched uid does not
@@ -452,6 +502,9 @@
                                 ai.applicationInfo.uid, ai.exported);
                         if (granted != PackageManager.PERMISSION_GRANTED) {
                             // Access not allowed!
+                            if (mOrigResolveList == currentResolveList) {
+                                mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
+                            }
                             currentResolveList.remove(i);
                         }
                     }
@@ -473,6 +526,9 @@
                     if (r0.priority != ri.priority ||
                         r0.isDefault != ri.isDefault) {
                         while (i < N) {
+                            if (mOrigResolveList == currentResolveList) {
+                                mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
+                            }
                             currentResolveList.remove(i);
                             N--;
                         }
@@ -544,6 +600,12 @@
             // Process labels from start to i
             int num = end - start+1;
             if (num == 1) {
+                if (mLastChosen != null
+                        && mLastChosen.activityInfo.packageName.equals(
+                                ro.activityInfo.packageName)
+                        && mLastChosen.activityInfo.name.equals(ro.activityInfo.name)) {
+                    mInitialHighlight = mList.size();
+                }
                 // No duplicate labels. Use label for entry at start
                 mList.add(new DisplayResolveInfo(ro, roLabel, null, null));
             } else {
@@ -573,6 +635,12 @@
                 }
                 for (int k = start; k <= end; k++) {
                     ResolveInfo add = rList.get(k);
+                    if (mLastChosen != null
+                            && mLastChosen.activityInfo.packageName.equals(
+                                    add.activityInfo.packageName)
+                            && mLastChosen.activityInfo.name.equals(add.activityInfo.name)) {
+                        mInitialHighlight = mList.size();
+                    }
                     if (usePkg) {
                         // Use application name for all entries from start to end-1
                         mList.add(new DisplayResolveInfo(add, roLabel,
@@ -621,9 +689,11 @@
                 view = mInflater.inflate(
                         com.android.internal.R.layout.resolve_list_item, parent, false);
 
+                final ViewHolder holder = new ViewHolder(view);
+                view.setTag(holder);
+
                 // Fix the icon size even if we have different sized resources
-                ImageView icon = (ImageView)view.findViewById(R.id.icon);
-                ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) icon.getLayoutParams();
+                ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
                 lp.width = lp.height = mIconSize;
             } else {
                 view = convertView;
@@ -633,20 +703,30 @@
         }
 
         private final void bindView(View view, DisplayResolveInfo info) {
-            TextView text = (TextView)view.findViewById(com.android.internal.R.id.text1);
-            TextView text2 = (TextView)view.findViewById(com.android.internal.R.id.text2);
-            ImageView icon = (ImageView)view.findViewById(R.id.icon);
-            text.setText(info.displayLabel);
+            final ViewHolder holder = (ViewHolder) view.getTag();
+            holder.text.setText(info.displayLabel);
             if (mShowExtended) {
-                text2.setVisibility(View.VISIBLE);
-                text2.setText(info.extendedInfo);
+                holder.text2.setVisibility(View.VISIBLE);
+                holder.text2.setText(info.extendedInfo);
             } else {
-                text2.setVisibility(View.GONE);
+                holder.text2.setVisibility(View.GONE);
             }
             if (info.displayIcon == null) {
-                info.displayIcon = loadIconForResolveInfo(info.ri);
+                new LoadIconTask().execute(info);
             }
-            icon.setImageDrawable(info.displayIcon);
+            holder.icon.setImageDrawable(info.displayIcon);
+        }
+    }
+
+    static class ViewHolder {
+        public TextView text;
+        public TextView text2;
+        public ImageView icon;
+
+        public ViewHolder(View view) {
+            text = (TextView) view.findViewById(com.android.internal.R.id.text1);
+            text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
+            icon = (ImageView) view.findViewById(R.id.icon);
         }
     }
 
@@ -660,5 +740,21 @@
         }
 
     }
+
+    class LoadIconTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
+        @Override
+        protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
+            final DisplayResolveInfo info = params[0];
+            if (info.displayIcon == null) {
+                info.displayIcon = loadIconForResolveInfo(info.ri);
+            }
+            return info;
+        }
+
+        @Override
+        protected void onPostExecute(DisplayResolveInfo info) {
+            mAdapter.notifyDataSetChanged();
+        }
+    }
 }
 
diff --git a/core/java/com/android/internal/app/RestrictionsPinActivity.java b/core/java/com/android/internal/app/RestrictionsPinActivity.java
new file mode 100644
index 0000000..66585c6
--- /dev/null
+++ b/core/java/com/android/internal/app/RestrictionsPinActivity.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import com.android.internal.R;
+
+/**
+ * This activity is launched by Settings and other apps to either create a new PIN or
+ * challenge for an existing PIN. The PIN is maintained by UserManager.
+ */
+public class RestrictionsPinActivity extends AlertActivity
+        implements OnClickListener, TextWatcher, OnEditorActionListener {
+
+    protected UserManager mUserManager;
+    protected boolean mHasRestrictionsPin;
+
+    protected EditText mPinText;
+    protected TextView mPinErrorMessage;
+    private Button mOkButton;
+    private Button mCancelButton;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
+        mHasRestrictionsPin = mUserManager.hasRestrictionsChallenge();
+        initUi();
+        setupAlert();
+    }
+
+    protected void initUi() {
+        AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.restr_pin_enter_admin_pin);
+        LayoutInflater inflater =
+                (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        ap.mView = inflater.inflate(R.layout.restrictions_pin_challenge, null);
+
+        mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message);
+        mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
+        mOkButton = (Button) ap.mView.findViewById(R.id.pin_ok_button);
+        mCancelButton = (Button) ap.mView.findViewById(R.id.pin_cancel_button);
+
+        mPinText.addTextChangedListener(this);
+
+        mOkButton.setOnClickListener(this);
+        mCancelButton.setOnClickListener(this);
+    }
+
+    protected boolean verifyingPin() {
+        return true;
+    }
+
+    public void onResume() {
+        super.onResume();
+
+        setPositiveButtonState(false);
+        boolean hasPin = mUserManager.hasRestrictionsChallenge();
+        if (hasPin) {
+            mPinErrorMessage.setVisibility(View.INVISIBLE);
+            mPinText.setOnEditorActionListener(this);
+            updatePinTimer(-1);
+        } else if (verifyingPin()) {
+            setResult(RESULT_OK);
+            finish();
+        }
+    }
+
+    protected void setPositiveButtonState(boolean enabled) {
+        mOkButton.setEnabled(enabled);
+    }
+
+    private boolean updatePinTimer(int pinTimerMs) {
+        if (pinTimerMs < 0) {
+            pinTimerMs = mUserManager.checkRestrictionsChallenge(null);
+        }
+        boolean enableInput;
+        if (pinTimerMs >= 200) {
+            // Do the count down timer for less than a minute, otherwise just say try again later.
+            if (pinTimerMs <= 60000) {
+                final int seconds = (pinTimerMs + 200) / 1000;
+                final String formatString = getResources().getQuantityString(
+                        R.plurals.restr_pin_countdown,
+                        seconds);
+                mPinErrorMessage.setText(String.format(formatString, seconds));
+            } else {
+                mPinErrorMessage.setText(R.string.restr_pin_try_later);
+            }
+            enableInput = false;
+            mPinErrorMessage.setVisibility(View.VISIBLE);
+            mPinText.setText("");
+            mPinText.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs));
+        } else {
+            enableInput = true;
+            mPinErrorMessage.setText(R.string.restr_pin_incorrect);
+        }
+        mPinText.setEnabled(enableInput);
+        setPositiveButtonState(enableInput);
+        return enableInput;
+    }
+
+    protected void performPositiveButtonAction() {
+        int result = mUserManager.checkRestrictionsChallenge(mPinText.getText().toString());
+        if (result == UserManager.PIN_VERIFICATION_SUCCESS) {
+            setResult(RESULT_OK);
+            finish();
+        } else if (result >= 0) {
+            mPinErrorMessage.setText(R.string.restr_pin_incorrect);
+            mPinErrorMessage.setVisibility(View.VISIBLE);
+            updatePinTimer(result);
+            mPinText.setText("");
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        CharSequence pin = mPinText.getText();
+        setPositiveButtonState(pin != null && pin.length() >= 4);
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+    }
+
+    @Override
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        performPositiveButtonAction();
+        return true;
+    }
+
+    private Runnable mCountdownRunnable = new Runnable() {
+        public void run() {
+            if (updatePinTimer(-1)) {
+                // If we are no longer counting down, clear the message.
+                mPinErrorMessage.setVisibility(View.INVISIBLE);
+            }
+        }
+    };
+
+    @Override
+    public void onClick(View v) {
+        if (v == mOkButton) {
+            performPositiveButtonAction();
+        } else if (v == mCancelButton) {
+            setResult(RESULT_CANCELED);
+            finish();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 424c19b..ab871fb 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -25,6 +25,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.UserHandle;
+import com.android.internal.os.BackgroundThread;
 
 import java.util.HashSet;
 
@@ -37,10 +38,6 @@
     static final IntentFilter sNonDataFilt = new IntentFilter();
     static final IntentFilter sExternalFilt = new IntentFilter();
 
-    static final Object sLock = new Object();
-    static HandlerThread sBackgroundThread;
-    static Handler sBackgroundHandler;
-
     static {
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -79,15 +76,7 @@
         }
         mRegisteredContext = context;
         if (thread == null) {
-            synchronized (sLock) {
-                if (sBackgroundThread == null) {
-                    sBackgroundThread = new HandlerThread("PackageMonitor",
-                            android.os.Process.THREAD_PRIORITY_BACKGROUND);
-                    sBackgroundThread.start();
-                    sBackgroundHandler = new Handler(sBackgroundThread.getLooper());
-                }
-                mRegisteredHandler = sBackgroundHandler;
-            }
+            mRegisteredHandler = BackgroundThread.getHandler();
         } else {
             mRegisteredHandler = new Handler(thread);
         }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 4e21324..63d018f 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -57,6 +57,45 @@
         // This utility class is not publicly instantiable.
     }
 
+    // ----------------------------------------------------------------------
+    // Utilities for debug
+    public static String getStackTrace() {
+        final StringBuilder sb = new StringBuilder();
+        try {
+            throw new RuntimeException();
+        } catch (RuntimeException e) {
+            final StackTraceElement[] frames = e.getStackTrace();
+            // Start at 1 because the first frame is here and we don't care about it
+            for (int j = 1; j < frames.length; ++j) {
+                sb.append(frames[j].toString() + "\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String getApiCallStack() {
+        String apiCallStack = "";
+        try {
+            throw new RuntimeException();
+        } catch (RuntimeException e) {
+            final StackTraceElement[] frames = e.getStackTrace();
+            for (int j = 1; j < frames.length; ++j) {
+                final String tempCallStack = frames[j].toString();
+                if (TextUtils.isEmpty(apiCallStack)) {
+                    // Overwrite apiCallStack if it's empty
+                    apiCallStack = tempCallStack;
+                } else if (tempCallStack.indexOf("Transact(") < 0) {
+                    // Overwrite apiCallStack if it's not a binder call
+                    apiCallStack = tempCallStack;
+                } else {
+                    break;
+                }
+            }
+        }
+        return apiCallStack;
+    }
+    // ----------------------------------------------------------------------
+
     public static boolean isSystemIme(InputMethodInfo inputMethod) {
         return (inputMethod.getServiceInfo().applicationInfo.flags
                 & ApplicationInfo.FLAG_SYSTEM) != 0;
@@ -142,7 +181,7 @@
                 || isSystemImeThatHasEnglishKeyboardSubtype(imi);
     }
 
-    private static boolean containsSubtypeOf(InputMethodInfo imi, String language, String mode) {
+    public static boolean containsSubtypeOf(InputMethodInfo imi, String language, String mode) {
         final int N = imi.getSubtypeCount();
         for (int i = 0; i < N; ++i) {
             if (!imi.getSubtypeAt(i).getLocale().startsWith(language)) {
@@ -432,6 +471,17 @@
         }
     }
 
+    public static CharSequence getImeAndSubtypeDisplayName(Context context, InputMethodInfo imi,
+            InputMethodSubtype subtype) {
+        final CharSequence imiLabel = imi.loadLabel(context.getPackageManager());
+        return subtype != null
+                ? TextUtils.concat(subtype.getDisplayName(context,
+                        imi.getPackageName(), imi.getServiceInfo().applicationInfo),
+                                (TextUtils.isEmpty(imiLabel) ?
+                                        "" : " - " + imiLabel))
+                : imiLabel;
+    }
+
     /**
      * Utility class for putting and getting settings for InputMethod
      * TODO: Move all putters and getters of settings to this class.
@@ -508,7 +558,7 @@
             return InputMethodSubtype.sort(context, 0, imi, enabledSubtypes);
         }
 
-        private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(
+        public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(
                 InputMethodInfo imi) {
             List<Pair<String, ArrayList<String>>> imsList =
                     getEnabledInputMethodsAndSubtypeListLocked();
diff --git a/core/java/com/android/internal/logging/AndroidHandler.java b/core/java/com/android/internal/logging/AndroidHandler.java
index 12f6a4f..f55a31f 100644
--- a/core/java/com/android/internal/logging/AndroidHandler.java
+++ b/core/java/com/android/internal/logging/AndroidHandler.java
@@ -17,6 +17,7 @@
 package com.android.internal.logging;
 
 import android.util.Log;
+import com.android.internal.util.FastPrintWriter;
 import dalvik.system.DalvikLogging;
 import dalvik.system.DalvikLogHandler;
 
@@ -91,7 +92,7 @@
             Throwable thrown = r.getThrown();
             if (thrown != null) {
                 StringWriter sw = new StringWriter();
-                PrintWriter pw = new PrintWriter(sw);
+                PrintWriter pw = new FastPrintWriter(sw, false, 256);
                 sw.write(r.getMessage());
                 sw.write("\n");
                 thrown.printStackTrace(pw);
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 956653b..98599d0 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -21,10 +21,15 @@
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
+import android.net.RouteInfo;
+import android.net.LinkAddress;
 
 import com.android.internal.util.Preconditions;
 
+import java.net.InetAddress;
 import java.util.List;
+import java.util.ArrayList;
 
 /**
  * A simple container used to carry information in VpnBuilder, VpnDialogs,
@@ -46,29 +51,54 @@
         return intent;
     }
 
-    public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) {
-        Preconditions.checkNotNull(config);
-
+    public static PendingIntent getIntentForStatusPanel(Context context) {
         Intent intent = new Intent();
         intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
-        intent.putExtra("config", config);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
                 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+        return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT);
     }
 
     public String user;
     public String interfaze;
     public String session;
     public int mtu = -1;
-    public String addresses;
-    public String routes;
+    public List<LinkAddress> addresses = new ArrayList<LinkAddress>();
+    public List<RouteInfo> routes = new ArrayList<RouteInfo>();
     public List<String> dnsServers;
     public List<String> searchDomains;
     public PendingIntent configureIntent;
     public long startTime = -1;
     public boolean legacy;
 
+    public void addLegacyRoutes(String routesStr) {
+        if (routesStr.trim().equals("")) {
+            return;
+        }
+        String[] routes = routesStr.trim().split(" ");
+        for (String route : routes) {
+            //each route is ip/prefix
+            String[] split = route.split("/");
+            RouteInfo info = new RouteInfo(new LinkAddress
+                    (InetAddress.parseNumericAddress(split[0]), Integer.parseInt(split[1])), null);
+            this.routes.add(info);
+        }
+    }
+
+    public void addLegacyAddresses(String addressesStr) {
+        if (addressesStr.trim().equals("")) {
+            return;
+        }
+        String[] addresses = addressesStr.trim().split(" ");
+        for (String address : addresses) {
+            //each address is ip/prefix
+            String[] split = address.split("/");
+            LinkAddress addr = new LinkAddress(InetAddress.parseNumericAddress(split[0]),
+                    Integer.parseInt(split[1]));
+            this.addresses.add(addr);
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -80,8 +110,8 @@
         out.writeString(interfaze);
         out.writeString(session);
         out.writeInt(mtu);
-        out.writeString(addresses);
-        out.writeString(routes);
+        out.writeTypedList(addresses);
+        out.writeTypedList(routes);
         out.writeStringList(dnsServers);
         out.writeStringList(searchDomains);
         out.writeParcelable(configureIntent, flags);
@@ -98,8 +128,8 @@
             config.interfaze = in.readString();
             config.session = in.readString();
             config.mtu = in.readInt();
-            config.addresses = in.readString();
-            config.routes = in.readString();
+            in.readTypedList(config.addresses, LinkAddress.CREATOR);
+            in.readTypedList(config.routes, RouteInfo.CREATOR);
             config.dnsServers = in.createStringArrayList();
             config.searchDomains = in.createStringArrayList();
             config.configureIntent = in.readParcelable(null);
diff --git a/core/java/com/android/internal/notification/DemoContactNotificationScorer.java b/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
new file mode 100644
index 0000000..f484724
--- /dev/null
+++ b/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
@@ -0,0 +1,188 @@
+/*
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.text.SpannableString;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This NotificationScorer bumps up the priority of notifications that contain references to the
+ * display names of starred contacts. The references it picks up are spannable strings which, in
+ * their entirety, match the display name of some starred contact. The magnitude of the bump ranges
+ * from 0 to 15 (assuming NOTIFICATION_PRIORITY_MULTIPLIER = 10) depending on the initial score, and
+ * the mapping is defined by priorityBumpMap. In a production version of this scorer, a notification
+ * extra will be used to specify contact identifiers.
+ */
+
+public class DemoContactNotificationScorer implements NotificationScorer {
+    private static final String TAG = "DemoContactNotificationScorer";
+    private static final boolean DBG = false;
+
+    protected static final boolean ENABLE_CONTACT_SCORER = true;
+    private static final String SETTING_ENABLE_SCORER = "contact_scorer_enabled";
+    protected boolean mEnabled;
+
+    // see NotificationManagerService
+    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+
+    private Context mContext;
+
+    private static final List<String> RELEVANT_KEYS_LIST = Arrays.asList(
+            Notification.EXTRA_INFO_TEXT, Notification.EXTRA_TEXT, Notification.EXTRA_TEXT_LINES,
+            Notification.EXTRA_SUB_TEXT, Notification.EXTRA_TITLE
+    );
+
+    private static final String[] PROJECTION = new String[] {
+            ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME
+    };
+
+    private static final Uri CONTACTS_URI = ContactsContract.Contacts.CONTENT_URI;
+
+    private static List<String> extractSpannedStrings(CharSequence charSequence) {
+        if (charSequence == null) return Collections.emptyList();
+        if (!(charSequence instanceof SpannableString)) {
+            return Arrays.asList(charSequence.toString());
+        }
+        SpannableString spannableString = (SpannableString)charSequence;
+        // get all spans
+        Object[] ssArr = spannableString.getSpans(0, spannableString.length(), Object.class);
+        // spanned string sequences
+        ArrayList<String> sss = new ArrayList<String>();
+        for (Object spanObj : ssArr) {
+            try {
+                sss.add(spannableString.subSequence(spannableString.getSpanStart(spanObj),
+                        spannableString.getSpanEnd(spanObj)).toString());
+            } catch(StringIndexOutOfBoundsException e) {
+                Slog.e(TAG, "Bad indices when extracting spanned subsequence", e);
+            }
+        }
+        return sss;
+    };
+
+    private static String getQuestionMarksInParens(int n) {
+        StringBuilder sb = new StringBuilder("(");
+        for (int i = 0; i < n; i++) {
+            if (sb.length() > 1) sb.append(',');
+            sb.append('?');
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    private boolean hasStarredContact(Bundle extras) {
+        if (extras == null) return false;
+        ArrayList<String> qStrings = new ArrayList<String>();
+        // build list to query against the database for display names.
+        for (String rk: RELEVANT_KEYS_LIST) {
+            if (extras.get(rk) == null) {
+                continue;
+            } else if (extras.get(rk) instanceof CharSequence) {
+                qStrings.addAll(extractSpannedStrings((CharSequence) extras.get(rk)));
+            } else if (extras.get(rk) instanceof CharSequence[]) {
+                // this is intended for Notification.EXTRA_TEXT_LINES
+                for (CharSequence line: (CharSequence[]) extras.get(rk)){
+                    qStrings.addAll(extractSpannedStrings(line));
+                }
+            } else {
+                Slog.w(TAG, "Strange, the extra " + rk + " is of unexpected type.");
+            }
+        }
+        if (qStrings.isEmpty()) return false;
+        String[] qStringsArr = qStrings.toArray(new String[qStrings.size()]);
+
+        String selection = ContactsContract.Contacts.DISPLAY_NAME + " IN "
+                + getQuestionMarksInParens(qStringsArr.length) + " AND "
+                + ContactsContract.Contacts.STARRED+" ='1'";
+
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(
+                    CONTACTS_URI, PROJECTION, selection, qStringsArr, null);
+            if (c != null) return c.getCount() > 0;
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return false;
+    }
+
+    private final static int clamp(int x, int low, int high) {
+        return (x < low) ? low : ((x > high) ? high : x);
+    }
+
+    private static int priorityBumpMap(int incomingScore) {
+        //assumption is that scale runs from [-2*pm, 2*pm]
+        int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
+        int theScore = incomingScore;
+        // enforce input in range
+        theScore = clamp(theScore, -2 * pm, 2 * pm);
+        if (theScore != incomingScore) return incomingScore;
+        // map -20 -> -20 and -10 -> 5 (when pm = 10)
+        if (theScore <= -pm) {
+            theScore += 1.5 * (theScore + 2 * pm);
+        } else {
+            // map 0 -> 10, 10 -> 15, 20 -> 20;
+            theScore += 0.5 * (2 * pm - theScore);
+        }
+        if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
+                + ", score after " + theScore + ".");
+        return theScore;
+    }
+
+    @Override
+    public void initialize(Context context) {
+        if (DBG) Slog.v(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+        mContext = context;
+        mEnabled = ENABLE_CONTACT_SCORER && 1 == Settings.Global.getInt(
+                mContext.getContentResolver(), SETTING_ENABLE_SCORER, 0);
+    }
+
+    @Override
+    public int getScore(Notification notification, int score) {
+        if (notification == null || !mEnabled) {
+            if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
+            return score;
+        }
+        boolean hasStarredPriority = hasStarredContact(notification.extras);
+
+        if (DBG) {
+            if (hasStarredPriority) {
+                Slog.v(TAG, "Notification references starred contact. Promoted!");
+            } else {
+                Slog.v(TAG, "Notification lacks any starred contact reference. Not promoted!");
+            }
+        }
+        if (hasStarredPriority) score = priorityBumpMap(score);
+        return score;
+    }
+}
+
diff --git a/core/java/com/android/internal/notification/NotificationScorer.java b/core/java/com/android/internal/notification/NotificationScorer.java
new file mode 100644
index 0000000..863c08c
--- /dev/null
+++ b/core/java/com/android/internal/notification/NotificationScorer.java
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.notification;
+
+import android.app.Notification;
+import android.content.Context;
+
+public interface NotificationScorer {
+
+    public void initialize(Context context);
+    public int getScore(Notification notification, int score);
+
+}
diff --git a/core/java/com/android/internal/os/BackgroundThread.java b/core/java/com/android/internal/os/BackgroundThread.java
new file mode 100644
index 0000000..d6f7b20
--- /dev/null
+++ b/core/java/com/android/internal/os/BackgroundThread.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * Shared singleton background thread for each process.
+ */
+public final class BackgroundThread extends HandlerThread {
+    private static BackgroundThread sInstance;
+    private static Handler sHandler;
+
+    private BackgroundThread() {
+        super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new BackgroundThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static BackgroundThread get() {
+        synchronized (BackgroundThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (BackgroundThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6375dbe..e0a154c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.os;
 
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.bluetooth.BluetoothDevice;
@@ -46,7 +45,9 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.JournaledFile;
 import com.google.android.collect.Sets;
 
@@ -83,7 +84,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 64 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 66 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -231,6 +232,9 @@
     final StopwatchTimer[] mPhoneDataConnectionsTimer =
             new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
 
+    final LongSamplingCounter[] mNetworkActivityCounters =
+            new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
+
     boolean mWifiOn;
     StopwatchTimer mWifiOnTimer;
     int mWifiOnUid = -1;
@@ -275,12 +279,6 @@
 
     long mLastWriteTime = 0; // Milliseconds
 
-    // Mobile data transferred while on battery
-    private long[] mMobileDataTx = new long[4];
-    private long[] mMobileDataRx = new long[4];
-    private long[] mTotalDataTx = new long[4];
-    private long[] mTotalDataRx = new long[4];
-
     private long mRadioDataUptime;
     private long mRadioDataStart;
 
@@ -304,7 +302,8 @@
     private static int sKernelWakelockUpdateVersion = 0;
 
     private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
-        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING,                // 0: name
+        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING|                // 0: name
+                              Process.PROC_QUOTES,
         Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 1: count
         Process.PROC_TAB_TERM,
         Process.PROC_TAB_TERM,
@@ -337,9 +336,12 @@
     private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
 
     private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
+    private NetworkStats mLastSnapshot;
 
-    /** Network ifaces that {@link ConnectivityManager} has claimed as mobile. */
+    @GuardedBy("this")
     private HashSet<String> mMobileIfaces = Sets.newHashSet();
+    @GuardedBy("this")
+    private HashSet<String> mWifiIfaces = Sets.newHashSet();
 
     // For debugging
     public BatteryStatsImpl() {
@@ -466,7 +468,6 @@
     }
 
     public static class SamplingCounter extends Counter {
-
         SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
             super(unpluggables, in);
         }
@@ -480,6 +481,93 @@
         }
     }
 
+    public static class LongSamplingCounter implements Unpluggable {
+        final ArrayList<Unpluggable> mUnpluggables;
+        long mCount;
+        long mLoadedCount;
+        long mLastCount;
+        long mUnpluggedCount;
+        long mPluggedCount;
+
+        LongSamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
+            mUnpluggables = unpluggables;
+            mPluggedCount = in.readLong();
+            mCount = mPluggedCount;
+            mLoadedCount = in.readLong();
+            mLastCount = 0;
+            mUnpluggedCount = in.readLong();
+            unpluggables.add(this);
+        }
+
+        LongSamplingCounter(ArrayList<Unpluggable> unpluggables) {
+            mUnpluggables = unpluggables;
+            unpluggables.add(this);
+        }
+
+        public void writeToParcel(Parcel out) {
+            out.writeLong(mCount);
+            out.writeLong(mLoadedCount);
+            out.writeLong(mUnpluggedCount);
+        }
+
+        @Override
+        public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+            mUnpluggedCount = mPluggedCount;
+            mCount = mPluggedCount;
+        }
+
+        @Override
+        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+            mPluggedCount = mCount;
+        }
+
+        public long getCountLocked(int which) {
+            long val;
+            if (which == STATS_LAST) {
+                val = mLastCount;
+            } else {
+                val = mCount;
+                if (which == STATS_SINCE_UNPLUGGED) {
+                    val -= mUnpluggedCount;
+                } else if (which != STATS_SINCE_CHARGED) {
+                    val -= mLoadedCount;
+                }
+            }
+
+            return val;
+        }
+
+        void addCountLocked(long count) {
+            mCount += count;
+        }
+
+        /**
+         * Clear state of this counter.
+         */
+        void reset(boolean detachIfReset) {
+            mCount = 0;
+            mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
+            if (detachIfReset) {
+                detach();
+            }
+        }
+
+        void detach() {
+            mUnpluggables.remove(this);
+        }
+
+        void writeSummaryFromParcelLocked(Parcel out) {
+            out.writeLong(mCount);
+        }
+
+        void readSummaryFromParcelLocked(Parcel in) {
+            mLoadedCount = in.readLong();
+            mCount = mLoadedCount;
+            mLastCount = 0;
+            mUnpluggedCount = mPluggedCount = mLoadedCount;
+        }
+    }
+
     /**
      * State for keeping track of timing information.
      */
@@ -525,7 +613,6 @@
          * Constructs from a parcel.
          * @param type
          * @param unpluggables
-         * @param powerType
          * @param in
          */
         Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
@@ -659,7 +746,7 @@
         }
 
         public void logState(Printer pw, String prefix) {
-            pw.println(prefix + " mCount=" + mCount
+            pw.println(prefix + "mCount=" + mCount
                     + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
                     + " mUnpluggedCount=" + mUnpluggedCount);
             pw.println(prefix + "mTotalTime=" + mTotalTime
@@ -1044,7 +1131,7 @@
 
         public void logState(Printer pw, String prefix) {
             super.logState(pw, prefix);
-            pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
+            pw.println(prefix + "mNesting=" + mNesting + " mUpdateTime=" + mUpdateTime
                     + " mAcquireTime=" + mAcquireTime);
         }
 
@@ -1316,15 +1403,6 @@
         return kwlt;
     }
 
-    private void doDataPlug(long[] dataTransfer, long currentBytes) {
-        dataTransfer[STATS_LAST] = dataTransfer[STATS_SINCE_UNPLUGGED];
-        dataTransfer[STATS_SINCE_UNPLUGGED] = -1;
-    }
-
-    private void doDataUnplug(long[] dataTransfer, long currentBytes) {
-        dataTransfer[STATS_SINCE_UNPLUGGED] = currentBytes;
-    }
-
     /**
      * Radio uptime in microseconds when transferring data. This value is very approximate.
      * @return
@@ -1571,34 +1649,10 @@
     }
 
     public void doUnplugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-        NetworkStats.Entry entry = null;
-
-        // Track UID data usage
-        final NetworkStats uidStats = getNetworkStatsDetailGroupedByUid();
-        final int size = uidStats.size();
-        for (int i = 0; i < size; i++) {
-            entry = uidStats.getValues(i, entry);
-
-            final Uid u = getUidStatsLocked(entry.uid);
-            u.mStartedTcpBytesReceived = entry.rxBytes;
-            u.mStartedTcpBytesSent = entry.txBytes;
-            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
-            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
-        }
-
         for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
             mUnpluggables.get(i).unplug(elapsedRealtime, batteryUptime, batteryRealtime);
         }
 
-        // Track both mobile and total overall data
-        final NetworkStats ifaceStats = getNetworkStatsSummary();
-        entry = ifaceStats.getTotal(entry, mMobileIfaces);
-        doDataUnplug(mMobileDataRx, entry.rxBytes);
-        doDataUnplug(mMobileDataTx, entry.txBytes);
-        entry = ifaceStats.getTotal(entry);
-        doDataUnplug(mTotalDataRx, entry.rxBytes);
-        doDataUnplug(mTotalDataTx, entry.txBytes);
-
         // Track radio awake time
         mRadioDataStart = getCurrentRadioDataUptime();
         mRadioDataUptime = 0;
@@ -1609,32 +1663,10 @@
     }
 
     public void doPlugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-        NetworkStats.Entry entry = null;
-
-        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
-            Uid u = mUidStats.valueAt(iu);
-            if (u.mStartedTcpBytesReceived >= 0) {
-                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
-                u.mStartedTcpBytesReceived = -1;
-            }
-            if (u.mStartedTcpBytesSent >= 0) {
-                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
-                u.mStartedTcpBytesSent = -1;
-            }
-        }
         for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
             mUnpluggables.get(i).plug(elapsedRealtime, batteryUptime, batteryRealtime);
         }
 
-        // Track both mobile and total overall data
-        final NetworkStats ifaceStats = getNetworkStatsSummary();
-        entry = ifaceStats.getTotal(entry, mMobileIfaces);
-        doDataPlug(mMobileDataRx, entry.rxBytes);
-        doDataPlug(mMobileDataTx, entry.txBytes);
-        entry = ifaceStats.getTotal(entry);
-        doDataPlug(mTotalDataRx, entry.rxBytes);
-        doDataPlug(mTotalDataTx, entry.txBytes);
-
         // Track radio awake time
         mRadioDataUptime = getRadioDataUptime();
         mRadioDataStart = -1;
@@ -2234,6 +2266,14 @@
         getUidStatsLocked(uid).noteVideoTurnedOffLocked();
     }
 
+    public void noteActivityResumedLocked(int uid) {
+        getUidStatsLocked(uid).noteActivityResumedLocked();
+    }
+
+    public void noteActivityPausedLocked(int uid) {
+        getUidStatsLocked(uid).noteActivityPausedLocked();
+    }
+
     public void noteVibratorOnLocked(int uid, long durationMillis) {
         getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
     }
@@ -2433,6 +2473,18 @@
         } else {
             mMobileIfaces.remove(iface);
         }
+        if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
+            mWifiIfaces.add(iface);
+        } else {
+            mWifiIfaces.remove(iface);
+        }
+    }
+
+    public void noteNetworkStatsEnabledLocked() {
+        // During device boot, qtaguid isn't enabled until after the inital
+        // loading of battery stats. Now that they're enabled, take our initial
+        // snapshot for future delta calculation.
+        updateNetworkActivityLocked();
     }
 
     @Override public long getScreenOnTime(long batteryRealtime, int which) {
@@ -2491,6 +2543,15 @@
         return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
+    @Override
+    public long getNetworkActivityCount(int type, int which) {
+        if (type >= 0 && type < mNetworkActivityCounters.length) {
+            return mNetworkActivityCounters[type].getCountLocked(which);
+        } else {
+            return 0;
+        }
+    }
+
     @Override public boolean getIsOnBattery() {
         return mOnBattery;
     }
@@ -2505,17 +2566,6 @@
     public final class Uid extends BatteryStats.Uid {
 
         final int mUid;
-        long mLoadedTcpBytesReceived;
-        long mLoadedTcpBytesSent;
-        long mCurrentTcpBytesReceived;
-        long mCurrentTcpBytesSent;
-        long mTcpBytesReceivedAtLastUnplug;
-        long mTcpBytesSentAtLastUnplug;
-
-        // These are not saved/restored when parcelling, since we want
-        // to return from the parcel with a snapshot of the state.
-        long mStartedTcpBytesReceived = -1;
-        long mStartedTcpBytesSent = -1;
 
         boolean mWifiRunning;
         StopwatchTimer mWifiRunningTimer;
@@ -2535,10 +2585,14 @@
         boolean mVideoTurnedOn;
         StopwatchTimer mVideoTurnedOnTimer;
 
+        StopwatchTimer mForegroundActivityTimer;
+
         BatchTimer mVibratorOnTimer;
 
         Counter[] mUserActivityCounters;
 
+        LongSamplingCounter[] mNetworkActivityCounters;
+
         /**
          * The statistics we have collected for this uid's wake locks.
          */
@@ -2602,43 +2656,6 @@
         }
 
         @Override
-        public long getTcpBytesReceived(int which) {
-            if (which == STATS_LAST) {
-                return mLoadedTcpBytesReceived;
-            } else {
-                long current = computeCurrentTcpBytesReceived();
-                if (which == STATS_SINCE_UNPLUGGED) {
-                    current -= mTcpBytesReceivedAtLastUnplug;
-                } else if (which == STATS_SINCE_CHARGED) {
-                    current += mLoadedTcpBytesReceived;
-                }
-                return current;
-            }
-        }
-
-        public long computeCurrentTcpBytesReceived() {
-            final long uidRxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
-                    null, mUid).rxBytes;
-            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
-                    ? (uidRxBytes - mStartedTcpBytesReceived) : 0);
-        }
-
-        @Override
-        public long getTcpBytesSent(int which) {
-            if (which == STATS_LAST) {
-                return mLoadedTcpBytesSent;
-            } else {
-                long current = computeCurrentTcpBytesSent();
-                if (which == STATS_SINCE_UNPLUGGED) {
-                    current -= mTcpBytesSentAtLastUnplug;
-                } else if (which == STATS_SINCE_CHARGED) {
-                    current += mLoadedTcpBytesSent;
-                }
-                return current;
-            }
-        }
-
-        @Override
         public void noteWifiRunningLocked() {
             if (!mWifiRunning) {
                 mWifiRunning = true;
@@ -2770,6 +2787,27 @@
             }
         }
 
+        public StopwatchTimer createForegroundActivityTimerLocked() {
+            if (mForegroundActivityTimer == null) {
+                mForegroundActivityTimer = new StopwatchTimer(
+                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables);
+            }
+            return mForegroundActivityTimer;
+        }
+
+        @Override
+        public void noteActivityResumedLocked() {
+            // We always start, since we want multiple foreground PIDs to nest
+            createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+        }
+
+        @Override
+        public void noteActivityPausedLocked() {
+            if (mForegroundActivityTimer != null) {
+                mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+
         public BatchTimer createVibratorOnTimerLocked() {
             if (mVibratorOnTimer == null) {
                 mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
@@ -2838,6 +2876,11 @@
         }
 
         @Override
+        public Timer getForegroundActivityTimer() {
+            return mForegroundActivityTimer;
+        }
+
+        @Override
         public Timer getVibratorOnTimer() {
             return mVibratorOnTimer;
         }
@@ -2875,11 +2918,38 @@
             }
         }
 
-        public long computeCurrentTcpBytesSent() {
-            final long uidTxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
-                    null, mUid).txBytes;
-            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
-                    ? (uidTxBytes - mStartedTcpBytesSent) : 0);
+        void noteNetworkActivityLocked(int type, long delta) {
+            if (mNetworkActivityCounters == null) {
+                initNetworkActivityLocked();
+            }
+            if (type >= 0 && type < NUM_NETWORK_ACTIVITY_TYPES) {
+                mNetworkActivityCounters[type].addCountLocked(delta);
+            } else {
+                Slog.w(TAG, "Unknown network activity type " + type + " was specified.",
+                        new Throwable());
+            }
+        }
+
+        @Override
+        public boolean hasNetworkActivity() {
+            return mNetworkActivityCounters != null;
+        }
+
+        @Override
+        public long getNetworkActivityCount(int type, int which) {
+            if (mNetworkActivityCounters != null && type >= 0
+                    && type < mNetworkActivityCounters.length) {
+                return mNetworkActivityCounters[type].getCountLocked(which);
+            } else {
+                return 0;
+            }
+        }
+
+        void initNetworkActivityLocked() {
+            mNetworkActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
+            for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
+            }
         }
 
         /**
@@ -2913,6 +2983,9 @@
                 active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
                 active |= mVideoTurnedOn;
             }
+            if (mForegroundActivityTimer != null) {
+                active |= !mForegroundActivityTimer.reset(BatteryStatsImpl.this, false);
+            }
             if (mVibratorOnTimer != null) {
                 if (mVibratorOnTimer.reset(BatteryStatsImpl.this, false)) {
                     mVibratorOnTimer.detach();
@@ -2922,15 +2995,18 @@
                 }
             }
 
-            mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
-            mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
-
             if (mUserActivityCounters != null) {
                 for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
                     mUserActivityCounters[i].reset(false);
                 }
             }
 
+            if (mNetworkActivityCounters != null) {
+                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                    mNetworkActivityCounters[i].reset(false);
+                }
+            }
+
             if (mWakelockStats.size() > 0) {
                 Iterator<Map.Entry<String, Wakelock>> it = mWakelockStats.entrySet().iterator();
                 while (it.hasNext()) {
@@ -3012,11 +3088,20 @@
                     mVideoTurnedOnTimer.detach();
                     mVideoTurnedOnTimer = null;
                 }
+                if (mForegroundActivityTimer != null) {
+                    mForegroundActivityTimer.detach();
+                    mForegroundActivityTimer = null;
+                }
                 if (mUserActivityCounters != null) {
                     for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
                         mUserActivityCounters[i].detach();
                     }
                 }
+                if (mNetworkActivityCounters != null) {
+                    for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                        mNetworkActivityCounters[i].detach();
+                    }
+                }
             }
 
             return !active;
@@ -3051,12 +3136,6 @@
                 pkg.writeToParcelLocked(out);
             }
 
-            out.writeLong(mLoadedTcpBytesReceived);
-            out.writeLong(mLoadedTcpBytesSent);
-            out.writeLong(computeCurrentTcpBytesReceived());
-            out.writeLong(computeCurrentTcpBytesSent());
-            out.writeLong(mTcpBytesReceivedAtLastUnplug);
-            out.writeLong(mTcpBytesSentAtLastUnplug);
             if (mWifiRunningTimer != null) {
                 out.writeInt(1);
                 mWifiRunningTimer.writeToParcel(out, batteryRealtime);
@@ -3093,6 +3172,12 @@
             } else {
                 out.writeInt(0);
             }
+            if (mForegroundActivityTimer != null) {
+                out.writeInt(1);
+                mForegroundActivityTimer.writeToParcel(out, batteryRealtime);
+            } else {
+                out.writeInt(0);
+            }
             if (mVibratorOnTimer != null) {
                 out.writeInt(1);
                 mVibratorOnTimer.writeToParcel(out, batteryRealtime);
@@ -3107,6 +3192,14 @@
             } else {
                 out.writeInt(0);
             }
+            if (mNetworkActivityCounters != null) {
+                out.writeInt(1);
+                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                    mNetworkActivityCounters[i].writeToParcel(out);
+                }
+            } else {
+                out.writeInt(0);
+            }
         }
 
         void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
@@ -3149,12 +3242,6 @@
                 mPackageStats.put(packageName, pkg);
             }
 
-            mLoadedTcpBytesReceived = in.readLong();
-            mLoadedTcpBytesSent = in.readLong();
-            mCurrentTcpBytesReceived = in.readLong();
-            mCurrentTcpBytesSent = in.readLong();
-            mTcpBytesReceivedAtLastUnplug = in.readLong();
-            mTcpBytesSentAtLastUnplug = in.readLong();
             mWifiRunning = false;
             if (in.readInt() != 0) {
                 mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
@@ -3198,6 +3285,12 @@
                 mVideoTurnedOnTimer = null;
             }
             if (in.readInt() != 0) {
+                mForegroundActivityTimer = new StopwatchTimer(
+                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables, in);
+            } else {
+                mForegroundActivityTimer = null;
+            }
+            if (in.readInt() != 0) {
                 mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
                         mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal, in);
             } else {
@@ -3211,6 +3304,14 @@
             } else {
                 mUserActivityCounters = null;
             }
+            if (in.readInt() != 0) {
+                mNetworkActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
+                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                    mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
+                }
+            } else {
+                mNetworkActivityCounters = null;
+            }
         }
 
         /**
@@ -3366,16 +3467,16 @@
             long mSystemTime;
 
             /**
-             * Number of times the process has been started.
-             */
-            int mStarts;
-
-            /**
              * Amount of time the process was running in the foreground.
              */
             long mForegroundTime;
 
             /**
+             * Number of times the process has been started.
+             */
+            int mStarts;
+
+            /**
              * The amount of user time loaded from a previous save.
              */
             long mLoadedUserTime;
@@ -3386,16 +3487,16 @@
             long mLoadedSystemTime;
 
             /**
-             * The number of times the process has started from a previous save.
-             */
-            int mLoadedStarts;
-
-            /**
              * The amount of foreground time loaded from a previous save.
              */
             long mLoadedForegroundTime;
 
             /**
+             * The number of times the process has started from a previous save.
+             */
+            int mLoadedStarts;
+
+            /**
              * The amount of user time loaded from the previous run.
              */
             long mLastUserTime;
@@ -3406,16 +3507,16 @@
             long mLastSystemTime;
 
             /**
-             * The number of times the process has started from the previous run.
-             */
-            int mLastStarts;
-
-            /**
              * The amount of foreground time loaded from the previous run
              */
             long mLastForegroundTime;
 
             /**
+             * The number of times the process has started from the previous run.
+             */
+            int mLastStarts;
+
+            /**
              * The amount of user time when last unplugged.
              */
             long mUnpluggedUserTime;
@@ -3426,15 +3527,15 @@
             long mUnpluggedSystemTime;
 
             /**
-             * The number of times the process has started before unplugged.
-             */
-            int mUnpluggedStarts;
-
-            /**
              * The amount of foreground time since unplugged.
              */
             long mUnpluggedForegroundTime;
 
+            /**
+             * The number of times the process has started before unplugged.
+             */
+            int mUnpluggedStarts;
+
             SamplingCounter[] mSpeedBins;
 
             ArrayList<ExcessivePower> mExcessivePower;
@@ -3447,8 +3548,8 @@
             public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
                 mUnpluggedUserTime = mUserTime;
                 mUnpluggedSystemTime = mSystemTime;
-                mUnpluggedStarts = mStarts;
                 mUnpluggedForegroundTime = mForegroundTime;
+                mUnpluggedStarts = mStarts;
             }
 
             public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
@@ -4285,6 +4386,9 @@
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
         }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
+        }
         mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
         mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
         mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
@@ -4358,12 +4462,13 @@
                 Slog.w(TAG, "New history ends before old history!");
             } else if (!out.same(mHistoryReadTmp)) {
                 long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
-                PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG));
+                PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
                 pw.println("Histories differ!");
                 pw.println("Old history:");
                 (new HistoryPrinter()).printNextItem(pw, out, now);
                 pw.println("New history:");
                 (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now);
+                pw.flush();
             }
         }
         return true;
@@ -4460,6 +4565,9 @@
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             mPhoneDataConnectionsTimer[i].reset(this, false);
         }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkActivityCounters[i].reset(false);
+        }
         mWifiOnTimer.reset(this, false);
         mGlobalWifiRunningTimer.reset(this, false);
         mBluetoothOnTimer.reset(this, false);
@@ -4535,6 +4643,7 @@
                 mDischargeStartLevel = level;
             }
             updateKernelWakelocksLocked();
+            updateNetworkActivityLocked();
             mHistoryCur.batteryLevel = (byte)level;
             mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
@@ -4557,6 +4666,7 @@
             doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
         } else {
             updateKernelWakelocksLocked();
+            updateNetworkActivityLocked();
             mHistoryCur.batteryLevel = (byte)level;
             mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
@@ -4689,6 +4799,52 @@
         }
     }
 
+    private void updateNetworkActivityLocked() {
+        if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
+
+        final NetworkStats snapshot;
+        try {
+            snapshot = mNetworkStatsFactory.readNetworkStatsDetail();
+        } catch (IOException e) {
+            Log.wtf(TAG, "Failed to read network stats", e);
+            return;
+        }
+
+        if (mLastSnapshot == null) {
+            mLastSnapshot = snapshot;
+            return;
+        }
+
+        final NetworkStats delta = snapshot.subtract(mLastSnapshot);
+        mLastSnapshot = snapshot;
+
+        NetworkStats.Entry entry = null;
+        final int size = delta.size();
+        for (int i = 0; i < size; i++) {
+            entry = delta.getValues(i, entry);
+
+            if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+            if (entry.tag != NetworkStats.TAG_NONE) continue;
+
+            final Uid u = getUidStatsLocked(entry.uid);
+
+            if (mMobileIfaces.contains(entry.iface)) {
+                u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_BYTES, entry.rxBytes);
+                u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_BYTES, entry.txBytes);
+
+                mNetworkActivityCounters[NETWORK_MOBILE_RX_BYTES].addCountLocked(entry.rxBytes);
+                mNetworkActivityCounters[NETWORK_MOBILE_TX_BYTES].addCountLocked(entry.txBytes);
+
+            } else if (mWifiIfaces.contains(entry.iface)) {
+                u.noteNetworkActivityLocked(NETWORK_WIFI_RX_BYTES, entry.rxBytes);
+                u.noteNetworkActivityLocked(NETWORK_WIFI_TX_BYTES, entry.txBytes);
+
+                mNetworkActivityCounters[NETWORK_WIFI_RX_BYTES].addCountLocked(entry.rxBytes);
+                mNetworkActivityCounters[NETWORK_WIFI_TX_BYTES].addCountLocked(entry.txBytes);
+            }
+        }
+    }
+
     public long getAwakeTimeBattery() {
         return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
     }
@@ -4779,47 +4935,6 @@
         return getBatteryRealtimeLocked(curTime);
     }
 
-    private long getTcpBytes(long current, long[] dataBytes, int which) {
-        if (which == STATS_LAST) {
-            return dataBytes[STATS_LAST];
-        } else {
-            if (which == STATS_SINCE_UNPLUGGED) {
-                if (dataBytes[STATS_SINCE_UNPLUGGED] < 0) {
-                    return dataBytes[STATS_LAST];
-                } else {
-                    return current - dataBytes[STATS_SINCE_UNPLUGGED];
-                }
-            } else if (which == STATS_SINCE_CHARGED) {
-                return (current - dataBytes[STATS_CURRENT]) + dataBytes[STATS_SINCE_CHARGED];
-            }
-            return current - dataBytes[STATS_CURRENT];
-        }
-    }
-
-    /** Only STATS_UNPLUGGED works properly */
-    public long getMobileTcpBytesSent(int which) {
-        final long mobileTxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).txBytes;
-        return getTcpBytes(mobileTxBytes, mMobileDataTx, which);
-    }
-
-    /** Only STATS_UNPLUGGED works properly */
-    public long getMobileTcpBytesReceived(int which) {
-        final long mobileRxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).rxBytes;
-        return getTcpBytes(mobileRxBytes, mMobileDataRx, which);
-    }
-
-    /** Only STATS_UNPLUGGED works properly */
-    public long getTotalTcpBytesSent(int which) {
-        final long totalTxBytes = getNetworkStatsSummary().getTotal(null).txBytes;
-        return getTcpBytes(totalTxBytes, mTotalDataTx, which);
-    }
-
-    /** Only STATS_UNPLUGGED works properly */
-    public long getTotalTcpBytesReceived(int which) {
-        final long totalRxBytes = getNetworkStatsSummary().getTotal(null).rxBytes;
-        return getTcpBytes(totalRxBytes, mTotalDataRx, which);
-    }
-
     @Override
     public int getDischargeStartLevel() {
         synchronized(this) {
@@ -5299,6 +5414,9 @@
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
         }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkActivityCounters[i].readSummaryFromParcelLocked(in);
+        }
         mWifiOn = false;
         mWifiOnTimer.readSummaryFromParcelLocked(in);
         mGlobalWifiRunning = false;
@@ -5355,6 +5473,9 @@
                 u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
             }
             if (in.readInt() != 0) {
+                u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
+            }
+            if (in.readInt() != 0) {
                 u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
             }
 
@@ -5367,6 +5488,15 @@
                 }
             }
 
+            if (in.readInt() != 0) {
+                if (u.mNetworkActivityCounters == null) {
+                    u.initNetworkActivityLocked();
+                }
+                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                    u.mNetworkActivityCounters[i].readSummaryFromParcelLocked(in);
+                }
+            }
+
             int NW = in.readInt();
             if (NW > 100) {
                 Slog.w(TAG, "File corrupt: too many wake locks " + NW);
@@ -5408,6 +5538,7 @@
                 Uid.Proc p = u.getProcessStatsLocked(procName);
                 p.mUserTime = p.mLoadedUserTime = in.readLong();
                 p.mSystemTime = p.mLoadedSystemTime = in.readLong();
+                p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
                 p.mStarts = p.mLoadedStarts = in.readInt();
                 int NSB = in.readInt();
                 if (NSB > 100) {
@@ -5448,9 +5579,6 @@
                     s.mLaunches = s.mLoadedLaunches = in.readInt();
                 }
             }
-
-            u.mLoadedTcpBytesReceived = in.readLong();
-            u.mLoadedTcpBytesSent = in.readLong();
         }
     }
 
@@ -5463,6 +5591,7 @@
     public void writeSummaryToParcel(Parcel out) {
         // Need to update with current kernel wake lock counts.
         updateKernelWakelocksLocked();
+        updateNetworkActivityLocked();
 
         final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
         final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
@@ -5498,6 +5627,9 @@
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
         }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkActivityCounters[i].writeSummaryFromParcelLocked(out);
+        }
         mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5557,6 +5689,12 @@
             } else {
                 out.writeInt(0);
             }
+            if (u.mForegroundActivityTimer != null) {
+                out.writeInt(1);
+                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+            } else {
+                out.writeInt(0);
+            }
             if (u.mVibratorOnTimer != null) {
                 out.writeInt(1);
                 u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5573,6 +5711,15 @@
                 }
             }
 
+            if (u.mNetworkActivityCounters == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+                    u.mNetworkActivityCounters[i].writeSummaryFromParcelLocked(out);
+                }
+            }
+
             int NW = u.mWakelockStats.size();
             out.writeInt(NW);
             if (NW > 0) {
@@ -5626,6 +5773,7 @@
                     Uid.Proc ps = ent.getValue();
                     out.writeLong(ps.mUserTime);
                     out.writeLong(ps.mSystemTime);
+                    out.writeLong(ps.mForegroundTime);
                     out.writeInt(ps.mStarts);
                     final int N = ps.mSpeedBins.length;
                     out.writeInt(N);
@@ -5664,9 +5812,6 @@
                     }
                 }
             }
-
-            out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED));
-            out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED));
         }
     }
 
@@ -5705,6 +5850,9 @@
             mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
                     null, mUnpluggables, in);
         }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
+        }
         mWifiOn = false;
         mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
         mGlobalWifiRunning = false;
@@ -5735,15 +5883,6 @@
         mDischargeAmountScreenOffSinceCharge = in.readInt();
         mLastWriteTime = in.readLong();
 
-        mMobileDataRx[STATS_LAST] = in.readLong();
-        mMobileDataRx[STATS_SINCE_UNPLUGGED] = -1;
-        mMobileDataTx[STATS_LAST] = in.readLong();
-        mMobileDataTx[STATS_SINCE_UNPLUGGED] = -1;
-        mTotalDataRx[STATS_LAST] = in.readLong();
-        mTotalDataRx[STATS_SINCE_UNPLUGGED] = -1;
-        mTotalDataTx[STATS_LAST] = in.readLong();
-        mTotalDataTx[STATS_SINCE_UNPLUGGED] = -1;
-
         mRadioDataUptime = in.readLong();
         mRadioDataStart = -1;
 
@@ -5793,6 +5932,7 @@
     void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
         // Need to update with current kernel wake lock counts.
         updateKernelWakelocksLocked();
+        updateNetworkActivityLocked();
 
         final long uSecUptime = SystemClock.uptimeMillis() * 1000;
         final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
@@ -5819,6 +5959,9 @@
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
         }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkActivityCounters[i].writeToParcel(out);
+        }
         mWifiOnTimer.writeToParcel(out, batteryRealtime);
         mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
         mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
@@ -5843,11 +5986,6 @@
         out.writeInt(mDischargeAmountScreenOffSinceCharge);
         out.writeLong(mLastWriteTime);
 
-        out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
-        out.writeLong(getMobileTcpBytesSent(STATS_SINCE_UNPLUGGED));
-        out.writeLong(getTotalTcpBytesReceived(STATS_SINCE_UNPLUGGED));
-        out.writeLong(getTotalTcpBytesSent(STATS_SINCE_UNPLUGGED));
-
         // Write radio uptime for data
         out.writeLong(getRadioDataUptime());
 
@@ -5899,9 +6037,10 @@
     public void prepareForDumpLocked() {
         // Need to retrieve current kernel wake lock stats before printing.
         updateKernelWakelocksLocked();
+        updateNetworkActivityLocked();
     }
 
-    public void dumpLocked(PrintWriter pw) {
+    public void dumpLocked(PrintWriter pw, boolean isUnpluggedOnly, int reqUid) {
         if (DEBUG) {
             Printer pr = new PrintWriterPrinter(pw);
             pr.println("*** Screen timer:");
@@ -5930,59 +6069,7 @@
             mGlobalWifiRunningTimer.logState(pr, "  ");
             pr.println("*** Bluetooth timer:");
             mBluetoothOnTimer.logState(pr, "  ");
-            pr.println("*** Mobile ifaces:");
-            pr.println(mMobileIfaces.toString());
         }
-        super.dumpLocked(pw);
-    }
-
-    private NetworkStats mNetworkSummaryCache;
-    private NetworkStats mNetworkDetailCache;
-
-    private NetworkStats getNetworkStatsSummary() {
-        // NOTE: calls from BatteryStatsService already hold this lock
-        synchronized (this) {
-            if (mNetworkSummaryCache == null
-                    || mNetworkSummaryCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
-                mNetworkSummaryCache = null;
-
-                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
-                    try {
-                        mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
-                    } catch (IOException e) {
-                        Log.wtf(TAG, "problem reading network stats", e);
-                    }
-                }
-
-                if (mNetworkSummaryCache == null) {
-                    mNetworkSummaryCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
-                }
-            }
-            return mNetworkSummaryCache;
-        }
-    }
-
-    private NetworkStats getNetworkStatsDetailGroupedByUid() {
-        // NOTE: calls from BatteryStatsService already hold this lock
-        synchronized (this) {
-            if (mNetworkDetailCache == null
-                    || mNetworkDetailCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
-                mNetworkDetailCache = null;
-
-                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
-                    try {
-                        mNetworkDetailCache = mNetworkStatsFactory
-                                .readNetworkStatsDetail().groupedByUid();
-                    } catch (IOException e) {
-                        Log.wtf(TAG, "problem reading network stats", e);
-                    }
-                }
-
-                if (mNetworkDetailCache == null) {
-                    mNetworkDetailCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
-                }
-            }
-            return mNetworkDetailCache;
-        }
+        super.dumpLocked(pw, isUnpluggedOnly, reqUid);
     }
 }
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index b442ff5..d9e3ef6 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -65,7 +65,11 @@
         
         mH.sendMessage(msg);
     }
-    
+
+    public void sendMessageDelayed(Message msg, long delayMillis) {
+        mH.sendMessageDelayed(msg, delayMillis);
+    }
+
     public boolean hasMessages(int what) {
         return mH.hasMessages(what);
     }
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
new file mode 100644
index 0000000..58cd60d
--- /dev/null
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static android.os.Process.*;
+
+import android.os.FileUtils;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.util.Slog;
+import com.android.internal.util.FastPrintWriter;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.StringTokenizer;
+
+public class ProcessCpuTracker {
+    private static final String TAG = "ProcessCpuTracker";
+    private static final boolean DEBUG = false;
+    private static final boolean localLOGV = DEBUG || false;
+
+    private static final int[] PROCESS_STATS_FORMAT = new int[] {
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_PARENS,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
+    };
+
+    static final int PROCESS_STAT_MINOR_FAULTS = 0;
+    static final int PROCESS_STAT_MAJOR_FAULTS = 1;
+    static final int PROCESS_STAT_UTIME = 2;
+    static final int PROCESS_STAT_STIME = 3;
+
+    /** Stores user time and system time in 100ths of a second. */
+    private final long[] mProcessStatsData = new long[4];
+    /** Stores user time and system time in 100ths of a second. */
+    private final long[] mSinglePidStatsData = new long[4];
+
+    private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 2: name
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 23: vsize
+    };
+
+    static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
+    static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
+    static final int PROCESS_FULL_STAT_UTIME = 3;
+    static final int PROCESS_FULL_STAT_STIME = 4;
+    static final int PROCESS_FULL_STAT_VSIZE = 5;
+
+    private final String[] mProcessFullStatsStringData = new String[6];
+    private final long[] mProcessFullStatsData = new long[6];
+
+    private static final int[] SYSTEM_CPU_FORMAT = new int[] {
+        PROC_SPACE_TERM|PROC_COMBINE,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 1: user time
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 2: nice time
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 3: sys time
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 4: idle time
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 5: iowait time
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 6: irq time
+        PROC_SPACE_TERM|PROC_OUT_LONG                   // 7: softirq time
+    };
+
+    private final long[] mSystemCpuData = new long[7];
+
+    private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
+        PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 0: 1 min
+        PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 1: 5 mins
+        PROC_SPACE_TERM|PROC_OUT_FLOAT                  // 2: 15 mins
+    };
+
+    private final float[] mLoadAverageData = new float[3];
+
+    private final boolean mIncludeThreads;
+
+    private float mLoad1 = 0;
+    private float mLoad5 = 0;
+    private float mLoad15 = 0;
+
+    private long mCurrentSampleTime;
+    private long mLastSampleTime;
+
+    private long mCurrentSampleRealTime;
+    private long mLastSampleRealTime;
+
+    private long mBaseUserTime;
+    private long mBaseSystemTime;
+    private long mBaseIoWaitTime;
+    private long mBaseIrqTime;
+    private long mBaseSoftIrqTime;
+    private long mBaseIdleTime;
+    private int mRelUserTime;
+    private int mRelSystemTime;
+    private int mRelIoWaitTime;
+    private int mRelIrqTime;
+    private int mRelSoftIrqTime;
+    private int mRelIdleTime;
+
+    private int[] mCurPids;
+    private int[] mCurThreadPids;
+
+    private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
+    private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
+    private boolean mWorkingProcsSorted;
+
+    private boolean mFirst = true;
+
+    private byte[] mBuffer = new byte[4096];
+
+    /**
+     * The time in microseconds that the CPU has been running at each speed.
+     */
+    private long[] mCpuSpeedTimes;
+
+    /**
+     * The relative time in microseconds that the CPU has been running at each speed.
+     */
+    private long[] mRelCpuSpeedTimes;
+
+    /**
+     * The different speeds that the CPU can be running at.
+     */
+    private long[] mCpuSpeeds;
+
+    public static class Stats {
+        public final int pid;
+        public final int uid;
+        final String statFile;
+        final String cmdlineFile;
+        final String threadsDir;
+        final ArrayList<Stats> threadStats;
+        final ArrayList<Stats> workingThreads;
+
+        public BatteryStatsImpl.Uid.Proc batteryStats;
+
+        public boolean interesting;
+
+        public String baseName;
+        public String name;
+        public int nameWidth;
+
+        // vsize capture when process first detected; can be used to
+        // filter out kernel processes.
+        public long vsize;
+
+        public long base_uptime;
+        public long rel_uptime;
+
+        public long base_utime;
+        public long base_stime;
+        public int rel_utime;
+        public int rel_stime;
+
+        public long base_minfaults;
+        public long base_majfaults;
+        public int rel_minfaults;
+        public int rel_majfaults;
+
+        public boolean active;
+        public boolean working;
+        public boolean added;
+        public boolean removed;
+
+        Stats(int _pid, int parentPid, boolean includeThreads) {
+            pid = _pid;
+            if (parentPid < 0) {
+                final File procDir = new File("/proc", Integer.toString(pid));
+                statFile = new File(procDir, "stat").toString();
+                cmdlineFile = new File(procDir, "cmdline").toString();
+                threadsDir = (new File(procDir, "task")).toString();
+                if (includeThreads) {
+                    threadStats = new ArrayList<Stats>();
+                    workingThreads = new ArrayList<Stats>();
+                } else {
+                    threadStats = null;
+                    workingThreads = null;
+                }
+            } else {
+                final File procDir = new File("/proc", Integer.toString(
+                        parentPid));
+                final File taskDir = new File(
+                        new File(procDir, "task"), Integer.toString(pid));
+                statFile = new File(taskDir, "stat").toString();
+                cmdlineFile = null;
+                threadsDir = null;
+                threadStats = null;
+                workingThreads = null;
+            }
+            uid = FileUtils.getUid(statFile.toString());
+        }
+    }
+
+    private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
+        public final int
+        compare(Stats sta, Stats stb) {
+            int ta = sta.rel_utime + sta.rel_stime;
+            int tb = stb.rel_utime + stb.rel_stime;
+            if (ta != tb) {
+                return ta > tb ? -1 : 1;
+            }
+            if (sta.added != stb.added) {
+                return sta.added ? -1 : 1;
+            }
+            if (sta.removed != stb.removed) {
+                return sta.added ? -1 : 1;
+            }
+            return 0;
+        }
+    };
+
+
+    public ProcessCpuTracker(boolean includeThreads) {
+        mIncludeThreads = includeThreads;
+    }
+
+    public void onLoadChanged(float load1, float load5, float load15) {
+    }
+
+    public int onMeasureProcessName(String name) {
+        return 0;
+    }
+
+    public void init() {
+        if (DEBUG) Slog.v(TAG, "Init: " + this);
+        mFirst = true;
+        update();
+    }
+
+    public void update() {
+        if (DEBUG) Slog.v(TAG, "Update: " + this);
+        mLastSampleTime = mCurrentSampleTime;
+        mCurrentSampleTime = SystemClock.uptimeMillis();
+        mLastSampleRealTime = mCurrentSampleRealTime;
+        mCurrentSampleRealTime = SystemClock.elapsedRealtime();
+
+        final long[] sysCpu = mSystemCpuData;
+        if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
+                null, sysCpu, null)) {
+            // Total user time is user + nice time.
+            final long usertime = sysCpu[0]+sysCpu[1];
+            // Total system time is simply system time.
+            final long systemtime = sysCpu[2];
+            // Total idle time is simply idle time.
+            final long idletime = sysCpu[3];
+            // Total irq time is iowait + irq + softirq time.
+            final long iowaittime = sysCpu[4];
+            final long irqtime = sysCpu[5];
+            final long softirqtime = sysCpu[6];
+
+            mRelUserTime = (int)(usertime - mBaseUserTime);
+            mRelSystemTime = (int)(systemtime - mBaseSystemTime);
+            mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
+            mRelIrqTime = (int)(irqtime - mBaseIrqTime);
+            mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
+            mRelIdleTime = (int)(idletime - mBaseIdleTime);
+
+            if (DEBUG) {
+                Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
+                      + " S:" + sysCpu[2] + " I:" + sysCpu[3]
+                      + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
+                      + " O:" + sysCpu[6]);
+                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
+                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+            }
+
+            mBaseUserTime = usertime;
+            mBaseSystemTime = systemtime;
+            mBaseIoWaitTime = iowaittime;
+            mBaseIrqTime = irqtime;
+            mBaseSoftIrqTime = softirqtime;
+            mBaseIdleTime = idletime;
+        }
+
+        mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
+
+        final float[] loadAverages = mLoadAverageData;
+        if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
+                null, null, loadAverages)) {
+            float load1 = loadAverages[0];
+            float load5 = loadAverages[1];
+            float load15 = loadAverages[2];
+            if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
+                mLoad1 = load1;
+                mLoad5 = load5;
+                mLoad15 = load15;
+                onLoadChanged(load1, load5, load15);
+            }
+        }
+
+        if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
+                + (SystemClock.uptimeMillis()-mCurrentSampleTime));
+
+        mWorkingProcsSorted = false;
+        mFirst = false;
+    }
+
+    private int[] collectStats(String statsFile, int parentPid, boolean first,
+            int[] curPids, ArrayList<Stats> allProcs) {
+
+        int[] pids = Process.getPids(statsFile, curPids);
+        int NP = (pids == null) ? 0 : pids.length;
+        int NS = allProcs.size();
+        int curStatsIndex = 0;
+        for (int i=0; i<NP; i++) {
+            int pid = pids[i];
+            if (pid < 0) {
+                NP = pid;
+                break;
+            }
+            Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
+
+            if (st != null && st.pid == pid) {
+                // Update an existing process...
+                st.added = false;
+                st.working = false;
+                curStatsIndex++;
+                if (DEBUG) Slog.v(TAG, "Existing "
+                        + (parentPid < 0 ? "process" : "thread")
+                        + " pid " + pid + ": " + st);
+
+                if (st.interesting) {
+                    final long uptime = SystemClock.uptimeMillis();
+
+                    final long[] procStats = mProcessStatsData;
+                    if (!Process.readProcFile(st.statFile.toString(),
+                            PROCESS_STATS_FORMAT, null, procStats, null)) {
+                        continue;
+                    }
+
+                    final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
+                    final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
+                    final long utime = procStats[PROCESS_STAT_UTIME];
+                    final long stime = procStats[PROCESS_STAT_STIME];
+
+                    if (utime == st.base_utime && stime == st.base_stime) {
+                        st.rel_utime = 0;
+                        st.rel_stime = 0;
+                        st.rel_minfaults = 0;
+                        st.rel_majfaults = 0;
+                        if (st.active) {
+                            st.active = false;
+                        }
+                        continue;
+                    }
+
+                    if (!st.active) {
+                        st.active = true;
+                    }
+
+                    if (parentPid < 0) {
+                        getName(st, st.cmdlineFile);
+                        if (st.threadStats != null) {
+                            mCurThreadPids = collectStats(st.threadsDir, pid, false,
+                                    mCurThreadPids, st.threadStats);
+                        }
+                    }
+
+                    if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
+                            + " utime=" + utime + "-" + st.base_utime
+                            + " stime=" + stime + "-" + st.base_stime
+                            + " minfaults=" + minfaults + "-" + st.base_minfaults
+                            + " majfaults=" + majfaults + "-" + st.base_majfaults);
+
+                    st.rel_uptime = uptime - st.base_uptime;
+                    st.base_uptime = uptime;
+                    st.rel_utime = (int)(utime - st.base_utime);
+                    st.rel_stime = (int)(stime - st.base_stime);
+                    st.base_utime = utime;
+                    st.base_stime = stime;
+                    st.rel_minfaults = (int)(minfaults - st.base_minfaults);
+                    st.rel_majfaults = (int)(majfaults - st.base_majfaults);
+                    st.base_minfaults = minfaults;
+                    st.base_majfaults = majfaults;
+                    st.working = true;
+                }
+
+                continue;
+            }
+
+            if (st == null || st.pid > pid) {
+                // We have a new process!
+                st = new Stats(pid, parentPid, mIncludeThreads);
+                allProcs.add(curStatsIndex, st);
+                curStatsIndex++;
+                NS++;
+                if (DEBUG) Slog.v(TAG, "New "
+                        + (parentPid < 0 ? "process" : "thread")
+                        + " pid " + pid + ": " + st);
+
+                final String[] procStatsString = mProcessFullStatsStringData;
+                final long[] procStats = mProcessFullStatsData;
+                st.base_uptime = SystemClock.uptimeMillis();
+                if (Process.readProcFile(st.statFile.toString(),
+                        PROCESS_FULL_STATS_FORMAT, procStatsString,
+                        procStats, null)) {
+                    // This is a possible way to filter out processes that
+                    // are actually kernel threads...  do we want to?  Some
+                    // of them do use CPU, but there can be a *lot* that are
+                    // not doing anything.
+                    st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
+                    if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
+                        st.interesting = true;
+                        st.baseName = procStatsString[0];
+                        st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
+                        st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
+                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
+                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
+                    } else {
+                        Slog.i(TAG, "Skipping kernel process pid " + pid
+                                + " name " + procStatsString[0]);
+                        st.baseName = procStatsString[0];
+                    }
+                } else {
+                    Slog.w(TAG, "Skipping unknown process pid " + pid);
+                    st.baseName = "<unknown>";
+                    st.base_utime = st.base_stime = 0;
+                    st.base_minfaults = st.base_majfaults = 0;
+                }
+
+                if (parentPid < 0) {
+                    getName(st, st.cmdlineFile);
+                    if (st.threadStats != null) {
+                        mCurThreadPids = collectStats(st.threadsDir, pid, true,
+                                mCurThreadPids, st.threadStats);
+                    }
+                } else if (st.interesting) {
+                    st.name = st.baseName;
+                    st.nameWidth = onMeasureProcessName(st.name);
+                }
+
+                if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
+                        + " utime=" + st.base_utime + " stime=" + st.base_stime
+                        + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
+
+                st.rel_utime = 0;
+                st.rel_stime = 0;
+                st.rel_minfaults = 0;
+                st.rel_majfaults = 0;
+                st.added = true;
+                if (!first && st.interesting) {
+                    st.working = true;
+                }
+                continue;
+            }
+
+            // This process has gone away!
+            st.rel_utime = 0;
+            st.rel_stime = 0;
+            st.rel_minfaults = 0;
+            st.rel_majfaults = 0;
+            st.removed = true;
+            st.working = true;
+            allProcs.remove(curStatsIndex);
+            NS--;
+            if (DEBUG) Slog.v(TAG, "Removed "
+                    + (parentPid < 0 ? "process" : "thread")
+                    + " pid " + pid + ": " + st);
+            // Decrement the loop counter so that we process the current pid
+            // again the next time through the loop.
+            i--;
+            continue;
+        }
+
+        while (curStatsIndex < NS) {
+            // This process has gone away!
+            final Stats st = allProcs.get(curStatsIndex);
+            st.rel_utime = 0;
+            st.rel_stime = 0;
+            st.rel_minfaults = 0;
+            st.rel_majfaults = 0;
+            st.removed = true;
+            st.working = true;
+            allProcs.remove(curStatsIndex);
+            NS--;
+            if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
+        }
+
+        return pids;
+    }
+
+    /**
+     * Returns the total time (in clock ticks, or 1/100 sec) spent executing in
+     * both user and system code.
+     */
+    public long getCpuTimeForPid(int pid) {
+        final String statFile = "/proc/" + pid + "/stat";
+        final long[] statsData = mSinglePidStatsData;
+        if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
+                null, statsData, null)) {
+            long time = statsData[PROCESS_STAT_UTIME]
+                    + statsData[PROCESS_STAT_STIME];
+            return time;
+        }
+        return 0;
+    }
+
+    /**
+     * Returns the delta time (in clock ticks, or 1/100 sec) spent at each CPU
+     * speed, since the last call to this method. If this is the first call, it
+     * will return 1 for each value.
+     */
+    public long[] getLastCpuSpeedTimes() {
+        if (mCpuSpeedTimes == null) {
+            mCpuSpeedTimes = getCpuSpeedTimes(null);
+            mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
+            for (int i = 0; i < mCpuSpeedTimes.length; i++) {
+                mRelCpuSpeedTimes[i] = 1; // Initialize
+            }
+        } else {
+            getCpuSpeedTimes(mRelCpuSpeedTimes);
+            for (int i = 0; i < mCpuSpeedTimes.length; i++) {
+                long temp = mRelCpuSpeedTimes[i];
+                mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
+                mCpuSpeedTimes[i] = temp;
+            }
+        }
+        return mRelCpuSpeedTimes;
+    }
+
+    private long[] getCpuSpeedTimes(long[] out) {
+        long[] tempTimes = out;
+        long[] tempSpeeds = mCpuSpeeds;
+        final int MAX_SPEEDS = 60;
+        if (out == null) {
+            tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
+            tempSpeeds = new long[MAX_SPEEDS];
+        }
+        int speed = 0;
+        String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
+        // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
+        if (file != null) {
+            StringTokenizer st = new StringTokenizer(file, "\n ");
+            while (st.hasMoreElements()) {
+                String token = st.nextToken();
+                try {
+                    long val = Long.parseLong(token);
+                    tempSpeeds[speed] = val;
+                    token = st.nextToken();
+                    val = Long.parseLong(token);
+                    tempTimes[speed] = val;
+                    speed++;
+                    if (speed == MAX_SPEEDS) break; // No more
+                    if (localLOGV && out == null) {
+                        Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
+                              + "\t" + tempTimes[speed - 1]);
+                    }
+                } catch (NumberFormatException nfe) {
+                    Slog.i(TAG, "Unable to parse time_in_state");
+                }
+            }
+        }
+        if (out == null) {
+            out = new long[speed];
+            mCpuSpeeds = new long[speed];
+            System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
+            System.arraycopy(tempTimes, 0, out, 0, speed);
+        }
+        return out;
+    }
+
+    final public int getLastUserTime() {
+        return mRelUserTime;
+    }
+
+    final public int getLastSystemTime() {
+        return mRelSystemTime;
+    }
+
+    final public int getLastIoWaitTime() {
+        return mRelIoWaitTime;
+    }
+
+    final public int getLastIrqTime() {
+        return mRelIrqTime;
+    }
+
+    final public int getLastSoftIrqTime() {
+        return mRelSoftIrqTime;
+    }
+
+    final public int getLastIdleTime() {
+        return mRelIdleTime;
+    }
+
+    final public float getTotalCpuPercent() {
+        int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
+        if (denom <= 0) {
+            return 0;
+        }
+        return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
+    }
+
+    final void buildWorkingProcs() {
+        if (!mWorkingProcsSorted) {
+            mWorkingProcs.clear();
+            final int N = mProcStats.size();
+            for (int i=0; i<N; i++) {
+                Stats stats = mProcStats.get(i);
+                if (stats.working) {
+                    mWorkingProcs.add(stats);
+                    if (stats.threadStats != null && stats.threadStats.size() > 1) {
+                        stats.workingThreads.clear();
+                        final int M = stats.threadStats.size();
+                        for (int j=0; j<M; j++) {
+                            Stats tstats = stats.threadStats.get(j);
+                            if (tstats.working) {
+                                stats.workingThreads.add(tstats);
+                            }
+                        }
+                        Collections.sort(stats.workingThreads, sLoadComparator);
+                    }
+                }
+            }
+            Collections.sort(mWorkingProcs, sLoadComparator);
+            mWorkingProcsSorted = true;
+        }
+    }
+
+    final public int countStats() {
+        return mProcStats.size();
+    }
+
+    final public Stats getStats(int index) {
+        return mProcStats.get(index);
+    }
+
+    final public int countWorkingStats() {
+        buildWorkingProcs();
+        return mWorkingProcs.size();
+    }
+
+    final public Stats getWorkingStats(int index) {
+        return mWorkingProcs.get(index);
+    }
+
+    final public String printCurrentLoad() {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new FastPrintWriter(sw, false, 128);
+        pw.print("Load: ");
+        pw.print(mLoad1);
+        pw.print(" / ");
+        pw.print(mLoad5);
+        pw.print(" / ");
+        pw.println(mLoad15);
+        pw.flush();
+        return sw.toString();
+    }
+
+    final public String printCurrentState(long now) {
+        buildWorkingProcs();
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new FastPrintWriter(sw, false, 1024);
+
+        pw.print("CPU usage from ");
+        if (now > mLastSampleTime) {
+            pw.print(now-mLastSampleTime);
+            pw.print("ms to ");
+            pw.print(now-mCurrentSampleTime);
+            pw.print("ms ago");
+        } else {
+            pw.print(mLastSampleTime-now);
+            pw.print("ms to ");
+            pw.print(mCurrentSampleTime-now);
+            pw.print("ms later");
+        }
+
+        long sampleTime = mCurrentSampleTime - mLastSampleTime;
+        long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
+        long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0;
+        if (percAwake != 100) {
+            pw.print(" with ");
+            pw.print(percAwake);
+            pw.print("% awake");
+        }
+        pw.println(":");
+
+        final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
+                + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
+
+        if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
+                + (mCurrentSampleTime-mLastSampleTime));
+
+        int N = mWorkingProcs.size();
+        for (int i=0; i<N; i++) {
+            Stats st = mWorkingProcs.get(i);
+            printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
+                    st.pid, st.name, (int)(st.rel_uptime+5)/10,
+                    st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
+            if (!st.removed && st.workingThreads != null) {
+                int M = st.workingThreads.size();
+                for (int j=0; j<M; j++) {
+                    Stats tst = st.workingThreads.get(j);
+                    printProcessCPU(pw,
+                            tst.added ? "   +" : (tst.removed ? "   -": "    "),
+                            tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
+                            tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
+                }
+            }
+        }
+
+        printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
+                mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
+
+        pw.flush();
+        return sw.toString();
+    }
+
+    private void printRatio(PrintWriter pw, long numerator, long denominator) {
+        long thousands = (numerator*1000)/denominator;
+        long hundreds = thousands/10;
+        pw.print(hundreds);
+        if (hundreds < 10) {
+            long remainder = thousands - (hundreds*10);
+            if (remainder != 0) {
+                pw.print('.');
+                pw.print(remainder);
+            }
+        }
+    }
+
+    private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
+            int totalTime, int user, int system, int iowait, int irq, int softIrq,
+            int minFaults, int majFaults) {
+        pw.print(prefix);
+        if (totalTime == 0) totalTime = 1;
+        printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
+        pw.print("% ");
+        if (pid >= 0) {
+            pw.print(pid);
+            pw.print("/");
+        }
+        pw.print(label);
+        pw.print(": ");
+        printRatio(pw, user, totalTime);
+        pw.print("% user + ");
+        printRatio(pw, system, totalTime);
+        pw.print("% kernel");
+        if (iowait > 0) {
+            pw.print(" + ");
+            printRatio(pw, iowait, totalTime);
+            pw.print("% iowait");
+        }
+        if (irq > 0) {
+            pw.print(" + ");
+            printRatio(pw, irq, totalTime);
+            pw.print("% irq");
+        }
+        if (softIrq > 0) {
+            pw.print(" + ");
+            printRatio(pw, softIrq, totalTime);
+            pw.print("% softirq");
+        }
+        if (minFaults > 0 || majFaults > 0) {
+            pw.print(" / faults:");
+            if (minFaults > 0) {
+                pw.print(" ");
+                pw.print(minFaults);
+                pw.print(" minor");
+            }
+            if (majFaults > 0) {
+                pw.print(" ");
+                pw.print(majFaults);
+                pw.print(" major");
+            }
+        }
+        pw.println();
+    }
+
+    private String readFile(String file, char endChar) {
+        // Permit disk reads here, as /proc/meminfo isn't really "on
+        // disk" and should be fast.  TODO: make BlockGuard ignore
+        // /proc/ and /sys/ files perhaps?
+        StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+        FileInputStream is = null;
+        try {
+            is = new FileInputStream(file);
+            int len = is.read(mBuffer);
+            is.close();
+
+            if (len > 0) {
+                int i;
+                for (i=0; i<len; i++) {
+                    if (mBuffer[i] == endChar) {
+                        break;
+                    }
+                }
+                return new String(mBuffer, 0, i);
+            }
+        } catch (java.io.FileNotFoundException e) {
+        } catch (java.io.IOException e) {
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (java.io.IOException e) {
+                }
+            }
+            StrictMode.setThreadPolicy(savedPolicy);
+        }
+        return null;
+    }
+
+    private void getName(Stats st, String cmdlineFile) {
+        String newName = st.name;
+        if (st.name == null || st.name.equals("app_process")
+                || st.name.equals("<pre-initialized>")) {
+            String cmdName = readFile(cmdlineFile, '\0');
+            if (cmdName != null && cmdName.length() > 1) {
+                newName = cmdName;
+                int i = newName.lastIndexOf("/");
+                if (i > 0 && i < newName.length()-1) {
+                    newName = newName.substring(i+1);
+                }
+            }
+            if (newName == null) {
+                newName = st.baseName;
+            }
+        }
+        if (st.name == null || !newName.equals(st.name)) {
+            st.name = newName;
+            st.nameWidth = onMeasureProcessName(st.name);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/ProcessStats.java b/core/java/com/android/internal/os/ProcessStats.java
deleted file mode 100644
index b1bb8c1..0000000
--- a/core/java/com/android/internal/os/ProcessStats.java
+++ /dev/null
@@ -1,859 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import static android.os.Process.*;
-
-import android.os.Process;
-import android.os.StrictMode;
-import android.os.SystemClock;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.StringTokenizer;
-
-public class ProcessStats {
-    private static final String TAG = "ProcessStats";
-    private static final boolean DEBUG = false;
-    private static final boolean localLOGV = DEBUG || false;
-    
-    private static final int[] PROCESS_STATS_FORMAT = new int[] {
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_PARENS,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
-        PROC_SPACE_TERM|PROC_OUT_LONG                   // 14: stime
-    };
-
-    static final int PROCESS_STAT_MINOR_FAULTS = 0;
-    static final int PROCESS_STAT_MAJOR_FAULTS = 1;
-    static final int PROCESS_STAT_UTIME = 2;
-    static final int PROCESS_STAT_STIME = 3;
-    
-    /** Stores user time and system time in 100ths of a second. */
-    private final long[] mProcessStatsData = new long[4];
-    /** Stores user time and system time in 100ths of a second. */
-    private final long[] mSinglePidStatsData = new long[4];
-
-    private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 1: name
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: stime
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 21: vsize
-    };
-
-    static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
-    static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
-    static final int PROCESS_FULL_STAT_UTIME = 3;
-    static final int PROCESS_FULL_STAT_STIME = 4;
-    static final int PROCESS_FULL_STAT_VSIZE = 5;
-
-    private final String[] mProcessFullStatsStringData = new String[6];
-    private final long[] mProcessFullStatsData = new long[6];
-
-    private static final int[] SYSTEM_CPU_FORMAT = new int[] {
-        PROC_SPACE_TERM|PROC_COMBINE,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 1: user time
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 2: nice time
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 3: sys time
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 4: idle time
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 5: iowait time
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 6: irq time
-        PROC_SPACE_TERM|PROC_OUT_LONG                   // 7: softirq time
-    };
-
-    private final long[] mSystemCpuData = new long[7];
-
-    private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
-        PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 0: 1 min
-        PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 1: 5 mins
-        PROC_SPACE_TERM|PROC_OUT_FLOAT                  // 2: 15 mins
-    };
-
-    private final float[] mLoadAverageData = new float[3];
-
-    private final boolean mIncludeThreads;
-    
-    private float mLoad1 = 0;
-    private float mLoad5 = 0;
-    private float mLoad15 = 0;
-    
-    private long mCurrentSampleTime;
-    private long mLastSampleTime;
-    
-    private long mCurrentSampleRealTime;
-    private long mLastSampleRealTime;
-
-    private long mBaseUserTime;
-    private long mBaseSystemTime;
-    private long mBaseIoWaitTime;
-    private long mBaseIrqTime;
-    private long mBaseSoftIrqTime;
-    private long mBaseIdleTime;
-    private int mRelUserTime;
-    private int mRelSystemTime;
-    private int mRelIoWaitTime;
-    private int mRelIrqTime;
-    private int mRelSoftIrqTime;
-    private int mRelIdleTime;
-
-    private int[] mCurPids;
-    private int[] mCurThreadPids;
-    
-    private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
-    private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
-    private boolean mWorkingProcsSorted;
-
-    private boolean mFirst = true;
-
-    private byte[] mBuffer = new byte[4096];
-
-    /**
-     * The time in microseconds that the CPU has been running at each speed.
-     */
-    private long[] mCpuSpeedTimes;
-
-    /**
-     * The relative time in microseconds that the CPU has been running at each speed.
-     */
-    private long[] mRelCpuSpeedTimes;
-
-    /**
-     * The different speeds that the CPU can be running at.
-     */
-    private long[] mCpuSpeeds;
-
-    public static class Stats {
-        public final int pid;
-        final String statFile;
-        final String cmdlineFile;
-        final String threadsDir;
-        final ArrayList<Stats> threadStats;
-        final ArrayList<Stats> workingThreads;
-        
-        public boolean interesting;
-
-        public String baseName;
-        public String name;
-        public int nameWidth;
-
-        public long base_uptime;
-        public long rel_uptime;
-
-        public long base_utime;
-        public long base_stime;
-        public int rel_utime;
-        public int rel_stime;
-
-        public long base_minfaults;
-        public long base_majfaults;
-        public int rel_minfaults;
-        public int rel_majfaults;
-        
-        public boolean active;
-        public boolean working;
-        public boolean added;
-        public boolean removed;
-        
-        Stats(int _pid, int parentPid, boolean includeThreads) {
-            pid = _pid;
-            if (parentPid < 0) {
-                final File procDir = new File("/proc", Integer.toString(pid));
-                statFile = new File(procDir, "stat").toString();
-                cmdlineFile = new File(procDir, "cmdline").toString();
-                threadsDir = (new File(procDir, "task")).toString();
-                if (includeThreads) {
-                    threadStats = new ArrayList<Stats>();
-                    workingThreads = new ArrayList<Stats>();
-                } else {
-                    threadStats = null;
-                    workingThreads = null;
-                }
-            } else {
-                final File procDir = new File("/proc", Integer.toString(
-                        parentPid));
-                final File taskDir = new File(
-                        new File(procDir, "task"), Integer.toString(pid));
-                statFile = new File(taskDir, "stat").toString();
-                cmdlineFile = null;
-                threadsDir = null;
-                threadStats = null;
-                workingThreads = null;
-            }
-        }
-    }
-
-    private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
-        public final int
-        compare(Stats sta, Stats stb) {
-            int ta = sta.rel_utime + sta.rel_stime;
-            int tb = stb.rel_utime + stb.rel_stime;
-            if (ta != tb) {
-                return ta > tb ? -1 : 1;
-            }
-            if (sta.added != stb.added) {
-                return sta.added ? -1 : 1;
-            }
-            if (sta.removed != stb.removed) {
-                return sta.added ? -1 : 1;
-            }
-            return 0;
-        }
-    };
-
-
-    public ProcessStats(boolean includeThreads) {
-        mIncludeThreads = includeThreads;
-    }
-    
-    public void onLoadChanged(float load1, float load5, float load15) {
-    }
-    
-    public int onMeasureProcessName(String name) {
-        return 0;
-    }
-    
-    public void init() {
-        if (DEBUG) Slog.v(TAG, "Init: " + this);
-        mFirst = true;
-        update();
-    }
-    
-    public void update() {
-        if (DEBUG) Slog.v(TAG, "Update: " + this);
-        mLastSampleTime = mCurrentSampleTime;
-        mCurrentSampleTime = SystemClock.uptimeMillis();
-        mLastSampleRealTime = mCurrentSampleRealTime;
-        mCurrentSampleRealTime = SystemClock.elapsedRealtime();
-        
-        final long[] sysCpu = mSystemCpuData;
-        if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
-                null, sysCpu, null)) {
-            // Total user time is user + nice time.
-            final long usertime = sysCpu[0]+sysCpu[1];
-            // Total system time is simply system time.
-            final long systemtime = sysCpu[2];
-            // Total idle time is simply idle time.
-            final long idletime = sysCpu[3];
-            // Total irq time is iowait + irq + softirq time.
-            final long iowaittime = sysCpu[4];
-            final long irqtime = sysCpu[5];
-            final long softirqtime = sysCpu[6];
-
-            mRelUserTime = (int)(usertime - mBaseUserTime);
-            mRelSystemTime = (int)(systemtime - mBaseSystemTime);
-            mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
-            mRelIrqTime = (int)(irqtime - mBaseIrqTime);
-            mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
-            mRelIdleTime = (int)(idletime - mBaseIdleTime);
-
-            if (DEBUG) {
-                Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
-                      + " S:" + sysCpu[2] + " I:" + sysCpu[3]
-                      + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
-                      + " O:" + sysCpu[6]);
-                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
-                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
-            }
-
-            mBaseUserTime = usertime;
-            mBaseSystemTime = systemtime;
-            mBaseIoWaitTime = iowaittime;
-            mBaseIrqTime = irqtime;
-            mBaseSoftIrqTime = softirqtime;
-            mBaseIdleTime = idletime;
-        }
-
-        mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
-
-        final float[] loadAverages = mLoadAverageData;
-        if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
-                null, null, loadAverages)) {
-            float load1 = loadAverages[0];
-            float load5 = loadAverages[1];
-            float load15 = loadAverages[2];
-            if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
-                mLoad1 = load1;
-                mLoad5 = load5;
-                mLoad15 = load15;
-                onLoadChanged(load1, load5, load15);
-            }
-        }
-
-        if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
-                + (SystemClock.uptimeMillis()-mCurrentSampleTime));
-
-        mWorkingProcsSorted = false;
-        mFirst = false;
-    }    
-    
-    private int[] collectStats(String statsFile, int parentPid, boolean first,
-            int[] curPids, ArrayList<Stats> allProcs) {
-        
-        int[] pids = Process.getPids(statsFile, curPids);
-        int NP = (pids == null) ? 0 : pids.length;
-        int NS = allProcs.size();
-        int curStatsIndex = 0;
-        for (int i=0; i<NP; i++) {
-            int pid = pids[i];
-            if (pid < 0) {
-                NP = pid;
-                break;
-            }
-            Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
-            
-            if (st != null && st.pid == pid) {
-                // Update an existing process...
-                st.added = false;
-                st.working = false;
-                curStatsIndex++;
-                if (DEBUG) Slog.v(TAG, "Existing "
-                        + (parentPid < 0 ? "process" : "thread")
-                        + " pid " + pid + ": " + st);
-
-                if (st.interesting) {
-                    final long uptime = SystemClock.uptimeMillis();
-
-                    final long[] procStats = mProcessStatsData;
-                    if (!Process.readProcFile(st.statFile.toString(),
-                            PROCESS_STATS_FORMAT, null, procStats, null)) {
-                        continue;
-                    }
-                    
-                    final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
-                    final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
-                    final long utime = procStats[PROCESS_STAT_UTIME];
-                    final long stime = procStats[PROCESS_STAT_STIME];
-
-                    if (utime == st.base_utime && stime == st.base_stime) {
-                        st.rel_utime = 0;
-                        st.rel_stime = 0;
-                        st.rel_minfaults = 0;
-                        st.rel_majfaults = 0;
-                        if (st.active) {
-                            st.active = false;
-                        }
-                        continue;
-                    }
-
-                    if (!st.active) {
-                        st.active = true;
-                    }
-
-                    if (parentPid < 0) {
-                        getName(st, st.cmdlineFile);
-                        if (st.threadStats != null) {
-                            mCurThreadPids = collectStats(st.threadsDir, pid, false,
-                                    mCurThreadPids, st.threadStats);
-                        }
-                    }
-
-                    if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
-                            + " utime=" + utime + "-" + st.base_utime
-                            + " stime=" + stime + "-" + st.base_stime
-                            + " minfaults=" + minfaults + "-" + st.base_minfaults
-                            + " majfaults=" + majfaults + "-" + st.base_majfaults);
-
-                    st.rel_uptime = uptime - st.base_uptime;
-                    st.base_uptime = uptime;
-                    st.rel_utime = (int)(utime - st.base_utime);
-                    st.rel_stime = (int)(stime - st.base_stime);
-                    st.base_utime = utime;
-                    st.base_stime = stime;
-                    st.rel_minfaults = (int)(minfaults - st.base_minfaults);
-                    st.rel_majfaults = (int)(majfaults - st.base_majfaults);
-                    st.base_minfaults = minfaults;
-                    st.base_majfaults = majfaults;
-                    st.working = true;
-                }
-
-                continue;
-            }
-            
-            if (st == null || st.pid > pid) {
-                // We have a new process!
-                st = new Stats(pid, parentPid, mIncludeThreads);
-                allProcs.add(curStatsIndex, st);
-                curStatsIndex++;
-                NS++;
-                if (DEBUG) Slog.v(TAG, "New "
-                        + (parentPid < 0 ? "process" : "thread")
-                        + " pid " + pid + ": " + st);
-
-                final String[] procStatsString = mProcessFullStatsStringData;
-                final long[] procStats = mProcessFullStatsData;
-                st.base_uptime = SystemClock.uptimeMillis();
-                if (Process.readProcFile(st.statFile.toString(),
-                        PROCESS_FULL_STATS_FORMAT, procStatsString,
-                        procStats, null)) {
-                    // This is a possible way to filter out processes that
-                    // are actually kernel threads...  do we want to?  Some
-                    // of them do use CPU, but there can be a *lot* that are
-                    // not doing anything.
-                    if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
-                        st.interesting = true;
-                        st.baseName = procStatsString[0];
-                        st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
-                        st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
-                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
-                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
-                    } else {
-                        Slog.i(TAG, "Skipping kernel process pid " + pid
-                                + " name " + procStatsString[0]);
-                        st.baseName = procStatsString[0];
-                    }
-                } else {
-                    Slog.w(TAG, "Skipping unknown process pid " + pid);
-                    st.baseName = "<unknown>";
-                    st.base_utime = st.base_stime = 0;
-                    st.base_minfaults = st.base_majfaults = 0;
-                }
-
-                if (parentPid < 0) {
-                    getName(st, st.cmdlineFile);
-                    if (st.threadStats != null) {
-                        mCurThreadPids = collectStats(st.threadsDir, pid, true,
-                                mCurThreadPids, st.threadStats);
-                    }
-                } else if (st.interesting) {
-                    st.name = st.baseName;
-                    st.nameWidth = onMeasureProcessName(st.name);
-                }
-
-                if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
-                        + " utime=" + st.base_utime + " stime=" + st.base_stime
-                        + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
-                
-                st.rel_utime = 0;
-                st.rel_stime = 0;
-                st.rel_minfaults = 0;
-                st.rel_majfaults = 0;
-                st.added = true;
-                if (!first && st.interesting) {
-                    st.working = true;
-                }
-                continue;
-            }
-                
-            // This process has gone away!
-            st.rel_utime = 0;
-            st.rel_stime = 0;
-            st.rel_minfaults = 0;
-            st.rel_majfaults = 0;
-            st.removed = true;
-            st.working = true;
-            allProcs.remove(curStatsIndex);
-            NS--;
-            if (DEBUG) Slog.v(TAG, "Removed "
-                    + (parentPid < 0 ? "process" : "thread")
-                    + " pid " + pid + ": " + st);
-            // Decrement the loop counter so that we process the current pid
-            // again the next time through the loop.
-            i--;
-            continue;
-        }
-
-        while (curStatsIndex < NS) {
-            // This process has gone away!
-            final Stats st = allProcs.get(curStatsIndex);
-            st.rel_utime = 0;
-            st.rel_stime = 0;
-            st.rel_minfaults = 0;
-            st.rel_majfaults = 0;
-            st.removed = true;
-            st.working = true;
-            allProcs.remove(curStatsIndex);
-            NS--;
-            if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
-        }
-        
-        return pids;
-    }
-
-    public long getCpuTimeForPid(int pid) {
-        final String statFile = "/proc/" + pid + "/stat";
-        final long[] statsData = mSinglePidStatsData;
-        if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
-                null, statsData, null)) {
-            long time = statsData[PROCESS_STAT_UTIME]
-                    + statsData[PROCESS_STAT_STIME];
-            return time;
-        }
-        return 0;
-    }
-
-    /**
-     * Returns the times spent at each CPU speed, since the last call to this method. If this
-     * is the first time, it will return 1 for each value.
-     * @return relative times spent at different speed steps.
-     */
-    public long[] getLastCpuSpeedTimes() {
-        if (mCpuSpeedTimes == null) {
-            mCpuSpeedTimes = getCpuSpeedTimes(null);
-            mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
-            for (int i = 0; i < mCpuSpeedTimes.length; i++) {
-                mRelCpuSpeedTimes[i] = 1; // Initialize
-            }
-        } else {
-            getCpuSpeedTimes(mRelCpuSpeedTimes);
-            for (int i = 0; i < mCpuSpeedTimes.length; i++) {
-                long temp = mRelCpuSpeedTimes[i];
-                mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
-                mCpuSpeedTimes[i] = temp;
-            }
-        }
-        return mRelCpuSpeedTimes;
-    }
-
-    private long[] getCpuSpeedTimes(long[] out) {
-        long[] tempTimes = out;
-        long[] tempSpeeds = mCpuSpeeds;
-        final int MAX_SPEEDS = 60;
-        if (out == null) {
-            tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
-            tempSpeeds = new long[MAX_SPEEDS];
-        }
-        int speed = 0;
-        String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
-        // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
-        if (file != null) {
-            StringTokenizer st = new StringTokenizer(file, "\n ");
-            while (st.hasMoreElements()) {
-                String token = st.nextToken();
-                try {
-                    long val = Long.parseLong(token);
-                    tempSpeeds[speed] = val;
-                    token = st.nextToken();
-                    val = Long.parseLong(token);
-                    tempTimes[speed] = val;
-                    speed++;
-                    if (speed == MAX_SPEEDS) break; // No more
-                    if (localLOGV && out == null) {
-                        Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
-                              + "\t" + tempTimes[speed - 1]);
-                    }
-                } catch (NumberFormatException nfe) {
-                    Slog.i(TAG, "Unable to parse time_in_state");
-                }
-            }
-        }
-        if (out == null) {
-            out = new long[speed];
-            mCpuSpeeds = new long[speed];
-            System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
-            System.arraycopy(tempTimes, 0, out, 0, speed);
-        }
-        return out;
-    }
-
-    final public int getLastUserTime() {
-        return mRelUserTime;
-    }
-    
-    final public int getLastSystemTime() {
-        return mRelSystemTime;
-    }
-    
-    final public int getLastIoWaitTime() {
-        return mRelIoWaitTime;
-    }
-    
-    final public int getLastIrqTime() {
-        return mRelIrqTime;
-    }
-    
-    final public int getLastSoftIrqTime() {
-        return mRelSoftIrqTime;
-    }
-    
-    final public int getLastIdleTime() {
-        return mRelIdleTime;
-    }
-    
-    final public float getTotalCpuPercent() {
-        int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
-        if (denom <= 0) {
-            return 0;
-        }
-        return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
-    }
-    
-    final void buildWorkingProcs() {
-        if (!mWorkingProcsSorted) {
-            mWorkingProcs.clear();
-            final int N = mProcStats.size();
-            for (int i=0; i<N; i++) {
-                Stats stats = mProcStats.get(i);
-                if (stats.working) {
-                    mWorkingProcs.add(stats);
-                    if (stats.threadStats != null && stats.threadStats.size() > 1) {
-                        stats.workingThreads.clear();
-                        final int M = stats.threadStats.size();
-                        for (int j=0; j<M; j++) {
-                            Stats tstats = stats.threadStats.get(j);
-                            if (tstats.working) {
-                                stats.workingThreads.add(tstats);
-                            }
-                        }
-                        Collections.sort(stats.workingThreads, sLoadComparator);
-                    }
-                }
-            }
-            Collections.sort(mWorkingProcs, sLoadComparator);
-            mWorkingProcsSorted = true;
-        }
-    }
-
-    final public int countStats() {
-        return mProcStats.size();
-    }
-
-    final public Stats getStats(int index) {
-        return mProcStats.get(index);
-    }
-
-    final public int countWorkingStats() {
-        buildWorkingProcs();
-        return mWorkingProcs.size();
-    }
-
-    final public Stats getWorkingStats(int index) {
-        return mWorkingProcs.get(index);
-    }
-    
-    final public String printCurrentLoad() {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        pw.print("Load: ");
-        pw.print(mLoad1);
-        pw.print(" / ");
-        pw.print(mLoad5);
-        pw.print(" / ");
-        pw.println(mLoad15);
-        return sw.toString();
-    }
-
-    final public String printCurrentState(long now) {
-        buildWorkingProcs();
-        
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        
-        pw.print("CPU usage from ");
-        if (now > mLastSampleTime) {
-            pw.print(now-mLastSampleTime);
-            pw.print("ms to ");
-            pw.print(now-mCurrentSampleTime);
-            pw.print("ms ago");
-        } else {
-            pw.print(mLastSampleTime-now);
-            pw.print("ms to ");
-            pw.print(mCurrentSampleTime-now);
-            pw.print("ms later");
-        }
-
-        long sampleTime = mCurrentSampleTime - mLastSampleTime;
-        long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
-        long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0;
-        if (percAwake != 100) {
-            pw.print(" with ");
-            pw.print(percAwake);
-            pw.print("% awake");
-        }
-        pw.println(":");
-        
-        final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
-                + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
-        
-        if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
-                + (mCurrentSampleTime-mLastSampleTime));
-
-        int N = mWorkingProcs.size();
-        for (int i=0; i<N; i++) {
-            Stats st = mWorkingProcs.get(i);
-            printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
-                    st.pid, st.name, (int)(st.rel_uptime+5)/10,
-                    st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
-            if (!st.removed && st.workingThreads != null) {
-                int M = st.workingThreads.size();
-                for (int j=0; j<M; j++) {
-                    Stats tst = st.workingThreads.get(j);
-                    printProcessCPU(pw,
-                            tst.added ? "   +" : (tst.removed ? "   -": "    "),
-                            tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
-                            tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
-                }
-            }
-        }
-        
-        printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
-                mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
-        
-        return sw.toString();
-    }
-    
-    private void printRatio(PrintWriter pw, long numerator, long denominator) {
-        long thousands = (numerator*1000)/denominator;
-        long hundreds = thousands/10;
-        pw.print(hundreds);
-        if (hundreds < 10) {
-            long remainder = thousands - (hundreds*10);
-            if (remainder != 0) {
-                pw.print('.');
-                pw.print(remainder);
-            }
-        }
-    }
-
-    private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
-            int totalTime, int user, int system, int iowait, int irq, int softIrq,
-            int minFaults, int majFaults) {
-        pw.print(prefix);
-        if (totalTime == 0) totalTime = 1;
-        printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
-        pw.print("% ");
-        if (pid >= 0) {
-            pw.print(pid);
-            pw.print("/");
-        }
-        pw.print(label);
-        pw.print(": ");
-        printRatio(pw, user, totalTime);
-        pw.print("% user + ");
-        printRatio(pw, system, totalTime);
-        pw.print("% kernel");
-        if (iowait > 0) {
-            pw.print(" + ");
-            printRatio(pw, iowait, totalTime);
-            pw.print("% iowait");
-        }
-        if (irq > 0) {
-            pw.print(" + ");
-            printRatio(pw, irq, totalTime);
-            pw.print("% irq");
-        }
-        if (softIrq > 0) {
-            pw.print(" + ");
-            printRatio(pw, softIrq, totalTime);
-            pw.print("% softirq");
-        }
-        if (minFaults > 0 || majFaults > 0) {
-            pw.print(" / faults:");
-            if (minFaults > 0) {
-                pw.print(" ");
-                pw.print(minFaults);
-                pw.print(" minor");
-            }
-            if (majFaults > 0) {
-                pw.print(" ");
-                pw.print(majFaults);
-                pw.print(" major");
-            }
-        }
-        pw.println();
-    }
-    
-    private String readFile(String file, char endChar) {
-        // Permit disk reads here, as /proc/meminfo isn't really "on
-        // disk" and should be fast.  TODO: make BlockGuard ignore
-        // /proc/ and /sys/ files perhaps?
-        StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-        FileInputStream is = null;
-        try {
-            is = new FileInputStream(file);
-            int len = is.read(mBuffer);
-            is.close();
-
-            if (len > 0) {
-                int i;
-                for (i=0; i<len; i++) {
-                    if (mBuffer[i] == endChar) {
-                        break;
-                    }
-                }
-                return new String(mBuffer, 0, i);
-            }
-        } catch (java.io.FileNotFoundException e) {
-        } catch (java.io.IOException e) {
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (java.io.IOException e) {
-                }
-            }
-            StrictMode.setThreadPolicy(savedPolicy);
-        }
-        return null;
-    }
-
-    private void getName(Stats st, String cmdlineFile) {
-        String newName = st.name;
-        if (st.name == null || st.name.equals("app_process")
-                || st.name.equals("<pre-initialized>")) {
-            String cmdName = readFile(cmdlineFile, '\0');
-            if (cmdName != null && cmdName.length() > 1) {
-                newName = cmdName;
-                int i = newName.lastIndexOf("/");
-                if (i > 0 && i < newName.length()-1) {
-                    newName = newName.substring(i+1);
-                }
-            }
-            if (newName == null) {
-                newName = st.baseName;
-            }
-        }
-        if (st.name == null || !newName.equals(st.name)) {
-            st.name = newName;
-            st.nameWidth = onMeasureProcessName(st.name);
-        }
-    }
-}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index cdd2ad1..5538dca 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -17,6 +17,7 @@
 package com.android.internal.os;
 
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
 import android.os.Build;
 import android.os.Debug;
@@ -69,7 +70,14 @@
                 if (mApplicationObject == null) {
                     Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
                 } else {
-                    Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
+                    StringBuilder message = new StringBuilder();
+                    message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
+                    final String processName = ActivityThread.currentProcessName();
+                    if (processName != null) {
+                        message.append("Process: ").append(processName).append(", ");
+                    }
+                    message.append("PID: ").append(Process.myPid());
+                    Slog.e(TAG, message.toString(), e);
                 }
 
                 // Bring up crash dialog, wait for it to be dismissed
@@ -334,6 +342,7 @@
             }
         } catch (Throwable t2) {
             Slog.e(TAG, "Error reporting WTF", t2);
+            Slog.e(TAG, "Original WTF:", t);
         }
     }
 
diff --git a/core/java/com/android/internal/os/TransferPipe.java b/core/java/com/android/internal/os/TransferPipe.java
new file mode 100644
index 0000000..068d914
--- /dev/null
+++ b/core/java/com/android/internal/os/TransferPipe.java
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.os;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+
+/**
+ * Helper for transferring data through a pipe from a client app.
+ */
+public final class TransferPipe implements Runnable {
+    static final String TAG = "TransferPipe";
+    static final boolean DEBUG = false;
+
+    static final long DEFAULT_TIMEOUT = 5000;  // 5 seconds
+
+    final Thread mThread;;
+    final ParcelFileDescriptor[] mFds;
+
+    FileDescriptor mOutFd;
+    long mEndTime;
+    String mFailure;
+    boolean mComplete;
+
+    String mBufferPrefix;
+
+    interface Caller {
+        void go(IInterface iface, FileDescriptor fd, String prefix,
+                String[] args) throws RemoteException;
+    }
+
+    public TransferPipe() throws IOException {
+        mThread = new Thread(this, "TransferPipe");
+        mFds = ParcelFileDescriptor.createPipe();
+    }
+
+    ParcelFileDescriptor getReadFd() {
+        return mFds[0];
+    }
+
+    public ParcelFileDescriptor getWriteFd() {
+        return mFds[1];
+    }
+
+    public void setBufferPrefix(String prefix) {
+        mBufferPrefix = prefix;
+    }
+
+    static void go(Caller caller, IInterface iface, FileDescriptor out,
+            String prefix, String[] args) throws IOException, RemoteException {
+        go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT);
+    }
+
+    static void go(Caller caller, IInterface iface, FileDescriptor out,
+            String prefix, String[] args, long timeout) throws IOException, RemoteException {
+        if ((iface.asBinder()) instanceof Binder) {
+            // This is a local object...  just call it directly.
+            try {
+                caller.go(iface, out, prefix, args);
+            } catch (RemoteException e) {
+            }
+            return;
+        }
+
+        TransferPipe tp = new TransferPipe();
+        try {
+            caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args);
+            tp.go(out, timeout);
+        } finally {
+            tp.kill();
+        }
+    }
+
+    static void goDump(IBinder binder, FileDescriptor out,
+            String[] args) throws IOException, RemoteException {
+        goDump(binder, out, args, DEFAULT_TIMEOUT);
+    }
+
+    static void goDump(IBinder binder, FileDescriptor out,
+            String[] args, long timeout) throws IOException, RemoteException {
+        if (binder instanceof Binder) {
+            // This is a local object...  just call it directly.
+            try {
+                binder.dump(out, args);
+            } catch (RemoteException e) {
+            }
+            return;
+        }
+
+        TransferPipe tp = new TransferPipe();
+        try {
+            binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
+            tp.go(out, timeout);
+        } finally {
+            tp.kill();
+        }
+    }
+
+    public void go(FileDescriptor out) throws IOException {
+        go(out, DEFAULT_TIMEOUT);
+    }
+
+    public void go(FileDescriptor out, long timeout) throws IOException {
+        try {
+            synchronized (this) {
+                mOutFd = out;
+                mEndTime = SystemClock.uptimeMillis() + timeout;
+
+                if (DEBUG) Slog.i(TAG, "read=" + getReadFd() + " write=" + getWriteFd()
+                        + " out=" + out);
+
+                // Close the write fd, so we know when the other side is done.
+                closeFd(1);
+
+                mThread.start();
+
+                while (mFailure == null && !mComplete) {
+                    long waitTime = mEndTime - SystemClock.uptimeMillis();
+                    if (waitTime <= 0) {
+                        if (DEBUG) Slog.i(TAG, "TIMEOUT!");
+                        mThread.interrupt();
+                        throw new IOException("Timeout");
+                    }
+
+                    try {
+                        wait(waitTime);
+                    } catch (InterruptedException e) {
+                    }
+                }
+
+                if (DEBUG) Slog.i(TAG, "Finished: " + mFailure);
+                if (mFailure != null) {
+                    throw new IOException(mFailure);
+                }
+            }
+        } finally {
+            kill();
+        }
+    }
+
+    void closeFd(int num) {
+        if (mFds[num] != null) {
+            if (DEBUG) Slog.i(TAG, "Closing: " + mFds[num]);
+            try {
+                mFds[num].close();
+            } catch (IOException e) {
+            }
+            mFds[num] = null;
+        }
+    }
+
+    public void kill() {
+        closeFd(0);
+        closeFd(1);
+    }
+
+    @Override
+    public void run() {
+        final byte[] buffer = new byte[1024];
+        final FileInputStream fis = new FileInputStream(getReadFd().getFileDescriptor());
+        final FileOutputStream fos = new FileOutputStream(mOutFd);
+
+        if (DEBUG) Slog.i(TAG, "Ready to read pipe...");
+        byte[] bufferPrefix = null;
+        boolean needPrefix = true;
+        if (mBufferPrefix != null) {
+            bufferPrefix = mBufferPrefix.getBytes();
+        }
+
+        int size;
+        try {
+            while ((size=fis.read(buffer)) > 0) {
+                if (DEBUG) Slog.i(TAG, "Got " + size + " bytes");
+                if (bufferPrefix == null) {
+                    fos.write(buffer, 0, size);
+                } else {
+                    int start = 0;
+                    for (int i=0; i<size; i++) {
+                        if (buffer[i] != '\n') {
+                            if (i > start) {
+                                fos.write(buffer, start, i-start);
+                            }
+                            start = i;
+                            if (needPrefix) {
+                                fos.write(bufferPrefix);
+                                needPrefix = false;
+                            }
+                            do {
+                                i++;
+                            } while (i<size && buffer[i] != '\n');
+                            if (i < size) {
+                                needPrefix = true;
+                            }
+                        }
+                    }
+                    if (size > start) {
+                        fos.write(buffer, start, size-start);
+                    }
+                }
+            }
+            if (DEBUG) Slog.i(TAG, "End of pipe: size=" + size);
+            if (mThread.isInterrupted()) {
+                if (DEBUG) Slog.i(TAG, "Interrupted!");
+            }
+        } catch (IOException e) {
+            synchronized (this) {
+                mFailure = e.toString();
+                notifyAll();
+                return;
+            }
+        }
+
+        synchronized (this) {
+            mComplete = true;
+            notifyAll();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index fb22df7..04351da 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -22,9 +22,11 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.net.LocalServerSocket;
+import android.opengl.EGL14;
 import android.os.Debug;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.EventLog;
 import android.util.Log;
@@ -59,9 +61,10 @@
  * @hide
  */
 public class ZygoteInit {
-
     private static final String TAG = "Zygote";
 
+    private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
+
     private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
 
     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
@@ -227,6 +230,13 @@
     static void preload() {
         preloadClasses();
         preloadResources();
+        preloadOpenGL();
+    }
+
+    private static void preloadOpenGL() {
+        if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
+            EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+        }
     }
 
     /**
@@ -479,7 +489,6 @@
             OsConstants.CAP_NET_BIND_SERVICE,
             OsConstants.CAP_NET_BROADCAST,
             OsConstants.CAP_NET_RAW,
-            OsConstants.CAP_SYS_BOOT,
             OsConstants.CAP_SYS_MODULE,
             OsConstants.CAP_SYS_NICE,
             OsConstants.CAP_SYS_RESOURCE,
@@ -490,7 +499,7 @@
         String args[] = {
             "--setuid=1000",
             "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
+            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
             "--capabilities=" + capabilities + "," + capabilities,
             "--runtime-init",
             "--nice-name=system_server",
diff --git a/core/java/com/android/internal/policy/IKeyguardExitCallback.aidl b/core/java/com/android/internal/policy/IKeyguardExitCallback.aidl
new file mode 100644
index 0000000..3702712
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardExitCallback.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.policy;
+
+oneway interface IKeyguardExitCallback {
+    void onKeyguardExitResult(boolean success);
+}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
new file mode 100644
index 0000000..45a38be
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.policy;
+
+import android.view.MotionEvent;
+
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardExitCallback;
+
+import android.os.Bundle;
+
+interface IKeyguardService {
+    boolean isShowing();
+    boolean isSecure();
+    boolean isShowingAndNotHidden();
+    boolean isInputRestricted();
+    boolean isDismissable();
+    oneway void verifyUnlock(IKeyguardExitCallback callback);
+    oneway void keyguardDone(boolean authenticated, boolean wakeup);
+    oneway void setHidden(boolean isHidden);
+    oneway void dismiss();
+    oneway void onDreamingStarted();
+    oneway void onDreamingStopped();
+    oneway void onScreenTurnedOff(int reason);
+    oneway void onScreenTurnedOn(IKeyguardShowCallback callback);
+    oneway void setKeyguardEnabled(boolean enabled);
+    oneway void onSystemReady();
+    oneway void doKeyguardTimeout(in Bundle options);
+    oneway void setCurrentUser(int userId);
+    oneway void showAssistant();
+    oneway void dispatch(in MotionEvent event);
+    oneway void launchCamera();
+}
diff --git a/core/java/com/android/internal/policy/IKeyguardShowCallback.aidl b/core/java/com/android/internal/policy/IKeyguardShowCallback.aidl
new file mode 100644
index 0000000..a2784d9
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardShowCallback.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.policy;
+
+oneway interface IKeyguardShowCallback {
+    void onShown(IBinder windowToken);
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 58b15e2..d1d1a52 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -38,5 +38,6 @@
     void toggleRecentApps();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
+    void setWindowState(int window, int state);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index c98ba8d..97ea7d8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -51,4 +51,5 @@
     void toggleRecentApps();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
+    void setWindowState(int window, int state);
 }
diff --git a/core/java/com/android/internal/transition/ActionBarTransition.java b/core/java/com/android/internal/transition/ActionBarTransition.java
new file mode 100644
index 0000000..c1065e7
--- /dev/null
+++ b/core/java/com/android/internal/transition/ActionBarTransition.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.transition;
+
+import android.transition.ChangeBounds;
+import android.transition.Fade;
+import android.transition.ChangeText;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.view.ViewGroup;
+
+public class ActionBarTransition {
+
+    private static boolean TRANSITIONS_ENABLED = false;
+
+    private static final int TRANSITION_DURATION = 120; // ms
+
+    private static final Transition sTransition;
+
+    static {
+        if (TRANSITIONS_ENABLED) {
+            final ChangeText tc = new ChangeText();
+            tc.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN);
+            final TransitionSet inner = new TransitionSet();
+            inner.addTransition(tc).addTransition(new ChangeBounds());
+            final TransitionSet tg = new TransitionSet();
+            tg.addTransition(new Fade(Fade.OUT)).addTransition(inner).
+                    addTransition(new Fade(Fade.IN));
+            tg.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+            tg.setDuration(TRANSITION_DURATION);
+            sTransition = tg;
+        } else {
+            sTransition = null;
+        }
+    }
+
+    public static void beginDelayedTransition(ViewGroup sceneRoot) {
+        if (TRANSITIONS_ENABLED) {
+            TransitionManager.beginDelayedTransition(sceneRoot, sTransition);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 7b8c582..65b56ec 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -40,7 +40,7 @@
         if (handler.runWithScissors(new Runnable() {
             @Override
             public void run() {
-                PrintWriter lpw = new PrintWriter(sw);
+                PrintWriter lpw = new FastPrintWriter(sw);
                 dump.dump(lpw);
                 lpw.close();
             }
diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java
new file mode 100644
index 0000000..c70a243
--- /dev/null
+++ b/core/java/com/android/internal/util/FastPrintWriter.java
@@ -0,0 +1,661 @@
+package com.android.internal.util;
+
+import android.util.Printer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+public class FastPrintWriter extends PrintWriter {
+    private static Writer sDummyWriter = new Writer() {
+        @Override
+        public void close() throws IOException {
+            UnsupportedOperationException ex
+                    = new UnsupportedOperationException("Shouldn't be here");
+            throw ex;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            close();
+        }
+
+        @Override
+        public void write(char[] buf, int offset, int count) throws IOException {
+            close();
+        }
+    };
+
+    private final int mBufferLen;
+    private final char[] mText;
+    private int mPos;
+
+    final private OutputStream mOutputStream;
+    final private boolean mAutoFlush;
+    final private String mSeparator;
+
+    final private Writer mWriter;
+    final private Printer mPrinter;
+
+    private CharsetEncoder mCharset;
+    final private ByteBuffer mBytes;
+
+    private boolean mIoError;
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code out} as its target
+     * stream. By default, the new print writer does not automatically flush its
+     * contents to the target stream when a newline is encountered.
+     *
+     * @param out
+     *            the target output stream.
+     * @throws NullPointerException
+     *             if {@code out} is {@code null}.
+     */
+    public FastPrintWriter(OutputStream out) {
+        this(out, false, 8192);
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code out} as its target
+     * stream. The parameter {@code autoFlush} determines if the print writer
+     * automatically flushes its contents to the target stream when a newline is
+     * encountered.
+     *
+     * @param out
+     *            the target output stream.
+     * @param autoFlush
+     *            indicates whether contents are flushed upon encountering a
+     *            newline sequence.
+     * @throws NullPointerException
+     *             if {@code out} is {@code null}.
+     */
+    public FastPrintWriter(OutputStream out, boolean autoFlush) {
+        this(out, autoFlush, 8192);
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code out} as its target
+     * stream and a custom buffer size. The parameter {@code autoFlush} determines
+     * if the print writer automatically flushes its contents to the target stream
+     * when a newline is encountered.
+     *
+     * @param out
+     *            the target output stream.
+     * @param autoFlush
+     *            indicates whether contents are flushed upon encountering a
+     *            newline sequence.
+     * @param bufferLen
+     *            specifies the size of the FastPrintWriter's internal buffer; the
+     *            default is 8192.
+     * @throws NullPointerException
+     *             if {@code out} is {@code null}.
+     */
+    public FastPrintWriter(OutputStream out, boolean autoFlush, int bufferLen) {
+        super(sDummyWriter, autoFlush);
+        if (out == null) {
+            throw new NullPointerException("out is null");
+        }
+        mBufferLen = bufferLen;
+        mText = new char[bufferLen];
+        mBytes = ByteBuffer.allocate(mBufferLen);
+        mOutputStream = out;
+        mWriter = null;
+        mPrinter = null;
+        mAutoFlush = autoFlush;
+        mSeparator = System.lineSeparator();
+        initDefaultEncoder();
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code wr} as its target
+     * writer. By default, the new print writer does not automatically flush its
+     * contents to the target writer when a newline is encountered.
+     *
+     * <p>NOTE: Unlike PrintWriter, this version will still do buffering inside of
+     * FastPrintWriter before sending data to the Writer.  This means you must call
+     * flush() before retrieving any data from the Writer.</p>
+     *
+     * @param wr
+     *            the target writer.
+     * @throws NullPointerException
+     *             if {@code wr} is {@code null}.
+     */
+    public FastPrintWriter(Writer wr) {
+        this(wr, false, 8192);
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code wr} as its target
+     * writer. The parameter {@code autoFlush} determines if the print writer
+     * automatically flushes its contents to the target writer when a newline is
+     * encountered.
+     *
+     * @param wr
+     *            the target writer.
+     * @param autoFlush
+     *            indicates whether to flush contents upon encountering a
+     *            newline sequence.
+     * @throws NullPointerException
+     *             if {@code out} is {@code null}.
+     */
+    public FastPrintWriter(Writer wr, boolean autoFlush) {
+        this(wr, autoFlush, 8192);
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code wr} as its target
+     * writer and a custom buffer size. The parameter {@code autoFlush} determines
+     * if the print writer automatically flushes its contents to the target writer
+     * when a newline is encountered.
+     *
+     * @param wr
+     *            the target writer.
+     * @param autoFlush
+     *            indicates whether to flush contents upon encountering a
+     *            newline sequence.
+     * @param bufferLen
+     *            specifies the size of the FastPrintWriter's internal buffer; the
+     *            default is 8192.
+     * @throws NullPointerException
+     *             if {@code wr} is {@code null}.
+     */
+    public FastPrintWriter(Writer wr, boolean autoFlush, int bufferLen) {
+        super(sDummyWriter, autoFlush);
+        if (wr == null) {
+            throw new NullPointerException("wr is null");
+        }
+        mBufferLen = bufferLen;
+        mText = new char[bufferLen];
+        mBytes = null;
+        mOutputStream = null;
+        mWriter = wr;
+        mPrinter = null;
+        mAutoFlush = autoFlush;
+        mSeparator = System.lineSeparator();
+        initDefaultEncoder();
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code pr} as its target
+     * printer and the default buffer size.  Because a {@link Printer} is line-base,
+     * autoflush is always enabled.
+     *
+     * @param pr
+     *            the target writer.
+     * @throws NullPointerException
+     *             if {@code pr} is {@code null}.
+     */
+    public FastPrintWriter(Printer pr) {
+        this(pr, 512);
+    }
+
+    /**
+     * Constructs a new {@code PrintWriter} with {@code pr} as its target
+     * printer and a custom buffer size.  Because a {@link Printer} is line-base,
+     * autoflush is always enabled.
+     *
+     * @param pr
+     *            the target writer.
+     * @param bufferLen
+     *            specifies the size of the FastPrintWriter's internal buffer; the
+     *            default is 512.
+     * @throws NullPointerException
+     *             if {@code pr} is {@code null}.
+     */
+    public FastPrintWriter(Printer pr, int bufferLen) {
+        super(sDummyWriter, true);
+        if (pr == null) {
+            throw new NullPointerException("pr is null");
+        }
+        mBufferLen = bufferLen;
+        mText = new char[bufferLen];
+        mBytes = null;
+        mOutputStream = null;
+        mWriter = null;
+        mPrinter = pr;
+        mAutoFlush = true;
+        mSeparator = System.lineSeparator();
+        initDefaultEncoder();
+    }
+
+    private final void initEncoder(String csn) throws UnsupportedEncodingException {
+        try {
+            mCharset = Charset.forName(csn).newEncoder();
+        } catch (Exception e) {
+            throw new UnsupportedEncodingException(csn);
+        }
+        mCharset.onMalformedInput(CodingErrorAction.REPLACE);
+        mCharset.onUnmappableCharacter(CodingErrorAction.REPLACE);
+    }
+
+    /**
+     * Flushes this writer and returns the value of the error flag.
+     *
+     * @return {@code true} if either an {@code IOException} has been thrown
+     *         previously or if {@code setError()} has been called;
+     *         {@code false} otherwise.
+     * @see #setError()
+     */
+    public boolean checkError() {
+        flush();
+        synchronized (lock) {
+            return mIoError;
+        }
+    }
+
+    /**
+     * Sets the error state of the stream to false.
+     * @since 1.6
+     */
+    protected void clearError() {
+        synchronized (lock) {
+            mIoError = false;
+        }
+    }
+
+    /**
+     * Sets the error flag of this writer to true.
+     */
+    protected void setError() {
+        synchronized (lock) {
+            mIoError = true;
+        }
+    }
+
+    private final void initDefaultEncoder() {
+        mCharset = Charset.defaultCharset().newEncoder();
+        mCharset.onMalformedInput(CodingErrorAction.REPLACE);
+        mCharset.onUnmappableCharacter(CodingErrorAction.REPLACE);
+    }
+
+    private void appendLocked(char c) throws IOException {
+        int pos = mPos;
+        if (pos >= (mBufferLen-1)) {
+            flushLocked();
+            pos = mPos;
+        }
+        mText[pos] = c;
+        mPos = pos+1;
+    }
+
+    private void appendLocked(String str, int i, final int length) throws IOException {
+        final int BUFFER_LEN = mBufferLen;
+        if (length > BUFFER_LEN) {
+            final int end = i + length;
+            while (i < end) {
+                int next = i + BUFFER_LEN;
+                appendLocked(str, i, next < end ? BUFFER_LEN : (end - i));
+                i = next;
+            }
+            return;
+        }
+        int pos = mPos;
+        if ((pos+length) > BUFFER_LEN) {
+            flushLocked();
+            pos = mPos;
+        }
+        str.getChars(i, i + length, mText, pos);
+        mPos = pos + length;
+    }
+
+    private void appendLocked(char[] buf, int i, final int length) throws IOException {
+        final int BUFFER_LEN = mBufferLen;
+        if (length > BUFFER_LEN) {
+            final int end = i + length;
+            while (i < end) {
+                int next = i + BUFFER_LEN;
+                appendLocked(buf, i, next < end ? BUFFER_LEN : (end - i));
+                i = next;
+            }
+            return;
+        }
+        int pos = mPos;
+        if ((pos+length) > BUFFER_LEN) {
+            flushLocked();
+            pos = mPos;
+        }
+        System.arraycopy(buf, i, mText, pos, length);
+        mPos = pos + length;
+    }
+
+    private void flushBytesLocked() throws IOException {
+        int position;
+        if ((position = mBytes.position()) > 0) {
+            mBytes.flip();
+            mOutputStream.write(mBytes.array(), 0, position);
+            mBytes.clear();
+        }
+    }
+
+    private void flushLocked() throws IOException {
+        //Log.i("PackageManager", "flush mPos=" + mPos);
+        if (mPos > 0) {
+            if (mOutputStream != null) {
+                CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
+                CoderResult result = mCharset.encode(charBuffer, mBytes, true);
+                while (true) {
+                    if (result.isError()) {
+                        throw new IOException(result.toString());
+                    } else if (result.isOverflow()) {
+                        flushBytesLocked();
+                        result = mCharset.encode(charBuffer, mBytes, true);
+                        continue;
+                    }
+                    break;
+                }
+                flushBytesLocked();
+                mOutputStream.flush();
+            } else if (mWriter != null) {
+                mWriter.write(mText, 0, mPos);
+                mWriter.flush();
+            } else {
+                int nonEolOff = 0;
+                final int sepLen = mSeparator.length();
+                final int len = sepLen < mPos ? sepLen : mPos;
+                while (nonEolOff < len && mText[mPos-1-nonEolOff]
+                        == mSeparator.charAt(mSeparator.length()-1-nonEolOff)) {
+                    nonEolOff++;
+                }
+                if (nonEolOff >= mPos) {
+                    mPrinter.println("");
+                } else {
+                    mPrinter.println(new String(mText, 0, mPos-nonEolOff));
+                }
+            }
+            mPos = 0;
+        }
+    }
+
+    /**
+     * Ensures that all pending data is sent out to the target. It also
+     * flushes the target. If an I/O error occurs, this writer's error
+     * state is set to {@code true}.
+     */
+    @Override
+    public void flush() {
+        synchronized (lock) {
+            try {
+                flushLocked();
+                if (mOutputStream != null) {
+                    mOutputStream.flush();
+                } else if (mWriter != null) {
+                    mWriter.flush();
+                }
+            } catch (IOException e) {
+                setError();
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        synchronized (lock) {
+            try {
+                flushLocked();
+                if (mOutputStream != null) {
+                    mOutputStream.close();
+                } else if (mWriter != null) {
+                    mWriter.close();
+                }
+            } catch (IOException e) {
+                setError();
+            }
+        }
+    }
+
+    /**
+     * Prints the string representation of the specified character array
+     * to the target.
+     *
+     * @param charArray
+     *            the character array to print to the target.
+     * @see #print(String)
+     */
+    public void print(char[] charArray) {
+        synchronized (lock) {
+            try {
+                appendLocked(charArray, 0, charArray.length);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Prints the string representation of the specified character to the
+     * target.
+     *
+     * @param ch
+     *            the character to print to the target.
+     * @see #print(String)
+     */
+    public void print(char ch) {
+        synchronized (lock) {
+            try {
+                appendLocked(ch);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Prints a string to the target. The string is converted to an array of
+     * bytes using the encoding chosen during the construction of this writer.
+     * The bytes are then written to the target with {@code write(int)}.
+     * <p>
+     * If an I/O error occurs, this writer's error flag is set to {@code true}.
+     *
+     * @param str
+     *            the string to print to the target.
+     * @see #write(int)
+     */
+    public void print(String str) {
+        if (str == null) {
+            str = String.valueOf((Object) null);
+        }
+        synchronized (lock) {
+            try {
+                appendLocked(str, 0, str.length());
+            } catch (IOException e) {
+                setError();
+            }
+        }
+    }
+
+
+    @Override
+    public void print(int inum) {
+        if (inum == 0) {
+            print("0");
+        } else {
+            super.print(inum);
+        }
+    }
+
+    @Override
+    public void print(long lnum) {
+        if (lnum == 0) {
+            print("0");
+        } else {
+            super.print(lnum);
+        }
+    }
+
+    /**
+     * Prints a newline. Flushes this writer if the autoFlush flag is set to {@code true}.
+     */
+    public void println() {
+        synchronized (lock) {
+            try {
+                appendLocked(mSeparator, 0, mSeparator.length());
+                if (mAutoFlush) {
+                    flushLocked();
+                }
+            } catch (IOException e) {
+                setError();
+            }
+        }
+    }
+
+    @Override
+    public void println(int inum) {
+        if (inum == 0) {
+            println("0");
+        } else {
+            super.println(inum);
+        }
+    }
+
+    @Override
+    public void println(long lnum) {
+        if (lnum == 0) {
+            println("0");
+        } else {
+            super.println(lnum);
+        }
+    }
+
+    /**
+     * Prints the string representation of the character array {@code chars} followed by a newline.
+     * Flushes this writer if the autoFlush flag is set to {@code true}.
+     */
+    public void println(char[] chars) {
+        print(chars);
+        println();
+    }
+
+    /**
+     * Prints the string representation of the char {@code c} followed by a newline.
+     * Flushes this writer if the autoFlush flag is set to {@code true}.
+     */
+    public void println(char c) {
+        print(c);
+        println();
+    }
+
+    /**
+     * Writes {@code count} characters from {@code buffer} starting at {@code
+     * offset} to the target.
+     * <p>
+     * This writer's error flag is set to {@code true} if this writer is closed
+     * or an I/O error occurs.
+     *
+     * @param buf
+     *            the buffer to write to the target.
+     * @param offset
+     *            the index of the first character in {@code buffer} to write.
+     * @param count
+     *            the number of characters in {@code buffer} to write.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0} or {@code count < 0}, or if {@code
+     *             offset + count} is greater than the length of {@code buf}.
+     */
+    @Override
+    public void write(char[] buf, int offset, int count) {
+        synchronized (lock) {
+            try {
+                appendLocked(buf, offset, count);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Writes one character to the target. Only the two least significant bytes
+     * of the integer {@code oneChar} are written.
+     * <p>
+     * This writer's error flag is set to {@code true} if this writer is closed
+     * or an I/O error occurs.
+     *
+     * @param oneChar
+     *            the character to write to the target.
+     */
+    @Override
+    public void write(int oneChar) {
+        synchronized (lock) {
+            try {
+                appendLocked((char) oneChar);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Writes the characters from the specified string to the target.
+     *
+     * @param str
+     *            the non-null string containing the characters to write.
+     */
+    @Override
+    public void write(String str) {
+        synchronized (lock) {
+            try {
+                appendLocked(str, 0, str.length());
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Writes {@code count} characters from {@code str} starting at {@code
+     * offset} to the target.
+     *
+     * @param str
+     *            the non-null string containing the characters to write.
+     * @param offset
+     *            the index of the first character in {@code str} to write.
+     * @param count
+     *            the number of characters from {@code str} to write.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0} or {@code count < 0}, or if {@code
+     *             offset + count} is greater than the length of {@code str}.
+     */
+    @Override
+    public void write(String str, int offset, int count) {
+        synchronized (lock) {
+            try {
+                appendLocked(str, offset, count);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Appends a subsequence of the character sequence {@code csq} to the
+     * target. This method works the same way as {@code
+     * PrintWriter.print(csq.subsequence(start, end).toString())}. If {@code
+     * csq} is {@code null}, then the specified subsequence of the string "null"
+     * will be written to the target.
+     *
+     * @param csq
+     *            the character sequence appended to the target.
+     * @param start
+     *            the index of the first char in the character sequence appended
+     *            to the target.
+     * @param end
+     *            the index of the character following the last character of the
+     *            subsequence appended to the target.
+     * @return this writer.
+     * @throws StringIndexOutOfBoundsException
+     *             if {@code start > end}, {@code start < 0}, {@code end < 0} or
+     *             either {@code start} or {@code end} are greater or equal than
+     *             the length of {@code csq}.
+     */
+    @Override
+    public PrintWriter append(CharSequence csq, int start, int end) {
+        if (csq == null) {
+            csq = "null";
+        }
+        String output = csq.subSequence(start, end).toString();
+        write(output, 0, output.length());
+        return this;
+    }
+}
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index d01a817..6fddd09 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -68,6 +68,10 @@
         print(key + "=" + String.valueOf(value) + " ");
     }
 
+    public void printHexPair(String key, int value) {
+        print(key + "=0x" + Integer.toHexString(value) + " ");
+    }
+
     @Override
     public void write(char[] buf, int offset, int count) {
         final int indentLength = mIndentBuilder.length();
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 850e1f0..5f240f7 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -16,46 +16,11 @@
 
 package com.android.internal.util;
 
-import java.io.FileInputStream;
-
+import android.os.Debug;
 import android.os.StrictMode;
 
-public class MemInfoReader {
-    byte[] mBuffer = new byte[1024];
-
-    private long mTotalSize;
-    private long mFreeSize;
-    private long mCachedSize;
-
-    private boolean matchText(byte[] buffer, int index, String text) {
-        int N = text.length();
-        if ((index+N) >= buffer.length) {
-            return false;
-        }
-        for (int i=0; i<N; i++) {
-            if (buffer[index+i] != text.charAt(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private long extractMemValue(byte[] buffer, int index) {
-        while (index < buffer.length && buffer[index] != '\n') {
-            if (buffer[index] >= '0' && buffer[index] <= '9') {
-                int start = index;
-                index++;
-                while (index < buffer.length && buffer[index] >= '0'
-                    && buffer[index] <= '9') {
-                    index++;
-                }
-                String str = new String(buffer, 0, start, index-start);
-                return ((long)Integer.parseInt(str)) * 1024;
-            }
-            index++;
-        }
-        return 0;
-    }
+public final class MemInfoReader {
+    final long[] mInfos = new long[Debug.MEMINFO_COUNT];
 
     public void readMemInfo() {
         // Permit disk reads here, as /proc/meminfo isn't really "on
@@ -63,48 +28,57 @@
         // /proc/ and /sys/ files perhaps?
         StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
         try {
-            mTotalSize = 0;
-            mFreeSize = 0;
-            mCachedSize = 0;
-            FileInputStream is = new FileInputStream("/proc/meminfo");
-            int len = is.read(mBuffer);
-            is.close();
-            final int BUFLEN = mBuffer.length;
-            int count = 0;
-            for (int i=0; i<len && count < 3; i++) {
-                if (matchText(mBuffer, i, "MemTotal")) {
-                    i += 8;
-                    mTotalSize = extractMemValue(mBuffer, i);
-                    count++;
-                } else if (matchText(mBuffer, i, "MemFree")) {
-                    i += 7;
-                    mFreeSize = extractMemValue(mBuffer, i);
-                    count++;
-                } else if (matchText(mBuffer, i, "Cached")) {
-                    i += 6;
-                    mCachedSize = extractMemValue(mBuffer, i);
-                    count++;
-                }
-                while (i < BUFLEN && mBuffer[i] != '\n') {
-                    i++;
-                }
-            }
-        } catch (java.io.FileNotFoundException e) {
-        } catch (java.io.IOException e) {
+            Debug.getMemInfo(mInfos);
         } finally {
             StrictMode.setThreadPolicy(savedPolicy);
         }
     }
 
     public long getTotalSize() {
-        return mTotalSize;
+        return mInfos[Debug.MEMINFO_TOTAL] * 1024;
     }
 
     public long getFreeSize() {
-        return mFreeSize;
+        return mInfos[Debug.MEMINFO_FREE] * 1024;
     }
 
     public long getCachedSize() {
-        return mCachedSize;
+        return mInfos[Debug.MEMINFO_CACHED] * 1024;
+    }
+
+    public long getTotalSizeKb() {
+        return mInfos[Debug.MEMINFO_TOTAL];
+    }
+
+    public long getFreeSizeKb() {
+        return mInfos[Debug.MEMINFO_FREE];
+    }
+
+    public long getCachedSizeKb() {
+        return mInfos[Debug.MEMINFO_CACHED];
+    }
+
+    public long getBuffersSizeKb() {
+        return mInfos[Debug.MEMINFO_BUFFERS];
+    }
+
+    public long getShmemSizeKb() {
+        return mInfos[Debug.MEMINFO_SHMEM];
+    }
+
+    public long getSlabSizeKb() {
+        return mInfos[Debug.MEMINFO_SLAB];
+    }
+
+    public long getSwapTotalSizeKb() {
+        return mInfos[Debug.MEMINFO_SWAP_TOTAL];
+    }
+
+    public long getSwapFreeSizeKb() {
+        return mInfos[Debug.MEMINFO_SWAP_FREE];
+    }
+
+    public long getZramTotalSizeKb() {
+        return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
     }
 }
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index a327adc..a54b364 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -66,4 +66,16 @@
             throw new IllegalStateException();
         }
     }
+
+    /**
+     * Check the requested flags, throwing if any requested flags are outside
+     * the allowed set.
+     */
+    public static void checkFlagsArgument(int requestedFlags, int allowedFlags) {
+        if ((requestedFlags & allowedFlags) != requestedFlags) {
+            throw new IllegalArgumentException("Requested flags 0x"
+                    + Integer.toHexString(requestedFlags) + ", but only 0x"
+                    + Integer.toHexString(allowedFlags) + " are allowed");
+        }
+    }
 }
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index f40f48c..0b74cf3 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -931,6 +931,15 @@
         out.attribute(null, name, Integer.toString(value));
     }
 
+    public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) {
+        final String value = in.getAttributeValue(null, name);
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
     public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
         final String value = in.getAttributeValue(null, name);
         try {
diff --git a/core/java/com/android/internal/view/ActionBarPolicy.java b/core/java/com/android/internal/view/ActionBarPolicy.java
index cf69a9d..25086c5 100644
--- a/core/java/com/android/internal/view/ActionBarPolicy.java
+++ b/core/java/com/android/internal/view/ActionBarPolicy.java
@@ -45,10 +45,7 @@
     }
 
     public boolean showsOverflowMenuButton() {
-        return !ViewConfiguration.get(mContext).hasPermanentMenuKey() ||
-                ((mContext.getResources().getConfiguration().uiMode &
-                        Configuration.UI_MODE_TYPE_TELEVISION) ==
-                        Configuration.UI_MODE_TYPE_TELEVISION);
+        return true;
     }
 
     public int getEmbeddedMenuWidthLimit() {
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 82b2654..12ced68 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -28,11 +28,13 @@
 /**
  * Public interface to the global input method manager, used by all client
  * applications.
+ * You need to update BridgeIInputMethodManager.java as well when changing
+ * this file.
  */
 interface IInputMethodManager {
     List<InputMethodInfo> getInputMethodList();
     List<InputMethodInfo> getEnabledInputMethodList();
-    List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in InputMethodInfo imi,
+    List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
             boolean allowsImplicitlySelectedSubtypes);
     InputMethodSubtype getLastInputMethodSubtype();
     // TODO: We should change the return type from List to List<Parcelable>
@@ -54,7 +56,7 @@
     InputBindResult windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
             int controlFlags, int softInputMode, int windowFlags,
             in EditorInfo attribute, IInputContext inputContext);
-            
+
     void showInputMethodPickerFromClient(in IInputMethodClient client);
     void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
     void setInputMethod(in IBinder token, String id);
@@ -69,6 +71,7 @@
     boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
     boolean switchToLastInputMethod(in IBinder token);
     boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
+    boolean shouldOfferSwitchingToNextInputMethod(in IBinder token);
     boolean setInputMethodEnabled(String id, boolean enabled);
     oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
 }
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 95130c8..70e2bfc 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -17,12 +17,13 @@
 package com.android.internal.view;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
@@ -40,6 +41,21 @@
     }
 
     /**
+     * Gets whether the device supports rotation. In general such a
+     * device has an accelerometer and has the portrait and landscape
+     * features.
+     *
+     * @param context Context for accessing system resources.
+     * @return Whether the device supports rotation.
+     */
+    public static boolean isRotationSupported(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)
+                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT)
+                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE);
+    }
+
+    /**
      * Returns true if the device supports the rotation-lock toggle feature
      * in the system UI or system bar.
      *
@@ -48,7 +64,8 @@
      * settings.
      */
     public static boolean isRotationLockToggleSupported(Context context) {
-        return context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
+        return isRotationSupported(context)
+                && context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
     }
 
     /**
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 4bb6d06..6471e14 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -16,22 +16,28 @@
 
 package com.android.internal.view.menu;
 
-import com.android.internal.view.ActionBarPolicy;
-import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
-
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.transition.Transition;
+import android.transition.TransitionManager;
 import android.util.SparseBooleanArray;
 import android.view.ActionProvider;
+import android.view.Gravity;
 import android.view.MenuItem;
 import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageButton;
+import android.widget.ListPopupWindow;
+import android.widget.ListPopupWindow.ForwardingListener;
+import com.android.internal.transition.ActionBarTransition;
+import com.android.internal.view.ActionBarPolicy;
+import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
 
 import java.util.ArrayList;
 
@@ -151,16 +157,35 @@
     }
 
     @Override
-    public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
+    public View getItemView(final MenuItemImpl item, View convertView, ViewGroup parent) {
         View actionView = item.getActionView();
         if (actionView == null || item.hasCollapsibleActionView()) {
-            if (!(convertView instanceof ActionMenuItemView)) {
-                convertView = null;
-            }
-            actionView = super.getItemView(item, convertView, parent);
+            // Don't recycle existing item views for action buttons; it interferes with transitions.
+            actionView = super.getItemView(item, null, parent);
         }
         actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
 
+        if (item.hasSubMenu()) {
+            actionView.setOnTouchListener(new ForwardingListener(actionView) {
+                @Override
+                public ListPopupWindow getPopup() {
+                    return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
+                }
+
+                @Override
+                protected boolean onForwardingStarted() {
+                    return onSubMenuSelected((SubMenuBuilder) item.getSubMenu());
+                }
+
+                @Override
+                protected boolean onForwardingStopped() {
+                    return dismissPopupMenus();
+                }
+            });
+        } else {
+            actionView.setOnTouchListener(null);
+        }
+
         final ActionMenuView menuParent = (ActionMenuView) parent;
         final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
         if (!menuParent.checkLayoutParams(lp)) {
@@ -185,6 +210,10 @@
 
     @Override
     public void updateMenuView(boolean cleared) {
+        final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent();
+        if (menuViewParent != null) {
+            ActionBarTransition.beginDelayedTransition(menuViewParent);
+        }
         super.updateMenuView(cleared);
 
         if (mMenu != null) {
@@ -343,6 +372,10 @@
         return mOverflowPopup != null && mOverflowPopup.isShowing();
     }
 
+    public boolean isOverflowMenuShowPending() {
+        return mPostedOpenRunnable != null || isOverflowMenuShowing();
+    }
+
     /**
      * @return true if space has been reserved in the action menu for an overflow item.
      */
@@ -559,6 +592,36 @@
             setFocusable(true);
             setVisibility(VISIBLE);
             setEnabled(true);
+
+            setOnTouchListener(new ForwardingListener(this) {
+                @Override
+                public ListPopupWindow getPopup() {
+                    if (mOverflowPopup == null) {
+                        return null;
+                    }
+
+                    return mOverflowPopup.getPopup();
+                }
+
+                @Override
+                public boolean onForwardingStarted() {
+                    showOverflowMenu();
+                    return true;
+                }
+
+                @Override
+                public boolean onForwardingStopped() {
+                    // Displaying the popup occurs asynchronously, so wait for
+                    // the runnable to finish before deciding whether to stop
+                    // forwarding.
+                    if (mPostedOpenRunnable != null) {
+                        return false;
+                    }
+
+                    hideOverflowMenu();
+                    return true;
+                }
+            });
         }
 
         @Override
@@ -572,10 +635,12 @@
             return true;
         }
 
+        @Override
         public boolean needsDividerBefore() {
             return false;
         }
 
+        @Override
         public boolean needsDividerAfter() {
             return false;
         }
@@ -589,12 +654,19 @@
             }
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(info);
+            info.setCanOpenPopup(true);
+        }
     }
 
     private class OverflowPopup extends MenuPopupHelper {
         public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
                 boolean overflowOnly) {
             super(context, menu, anchorView, overflowOnly);
+            setGravity(Gravity.END);
             setCallback(mPopupPresenterCallback);
         }
 
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index df579c6..a2a4acc 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -23,6 +23,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.ImageView;
@@ -269,4 +270,13 @@
         }
         return mInflater;
     }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+
+        if (mItemData != null && mItemData.hasSubMenu()) {
+            info.setCanOpenPopup(true);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 39078ca..4d0a326 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -616,7 +616,7 @@
 
     @Override
     public boolean expandActionView() {
-        if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0 || mActionView == null) {
+        if (!hasCollapsibleActionView()) {
             return false;
         }
 
@@ -653,7 +653,13 @@
     }
 
     public boolean hasCollapsibleActionView() {
-        return (mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0 && mActionView != null;
+        if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0) {
+            if (mActionView == null && mActionProvider != null) {
+                mActionView = mActionProvider.onCreateActionView(this);
+            }
+            return mActionView != null;
+        }
+        return false;
     }
 
     public void setActionViewExpanded(boolean isExpanded) {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index cacc86b..05e9a66 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -18,11 +18,12 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.database.DataSetObserver;
 import android.os.Parcelable;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -47,23 +48,30 @@
 
     static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
 
-    private Context mContext;
-    private LayoutInflater mInflater;
-    private ListPopupWindow mPopup;
-    private MenuBuilder mMenu;
-    private int mPopupMaxWidth;
+    private final Context mContext;
+    private final LayoutInflater mInflater;
+    private final MenuBuilder mMenu;
+    private final MenuAdapter mAdapter;
+    private final boolean mOverflowOnly;
+    private final int mPopupMaxWidth;
+
     private View mAnchorView;
-    private boolean mOverflowOnly;
+    private ListPopupWindow mPopup;
     private ViewTreeObserver mTreeObserver;
-
-    private MenuAdapter mAdapter;
-
     private Callback mPresenterCallback;
 
     boolean mForceShowIcon;
 
     private ViewGroup mMeasureParent;
 
+    /** Whether the cached content width value is valid. */
+    private boolean mHasContentWidth;
+
+    /** Cached content width from {@link #measureContentWidth}. */
+    private int mContentWidth;
+
+    private int mDropDownGravity = Gravity.NO_GRAVITY;
+
     public MenuPopupHelper(Context context, MenuBuilder menu) {
         this(context, menu, null, false);
     }
@@ -77,6 +85,7 @@
         mContext = context;
         mInflater = LayoutInflater.from(context);
         mMenu = menu;
+        mAdapter = new MenuAdapter(mMenu);
         mOverflowOnly = overflowOnly;
 
         final Resources res = context.getResources();
@@ -96,18 +105,24 @@
         mForceShowIcon = forceShow;
     }
 
+    public void setGravity(int gravity) {
+        mDropDownGravity = gravity;
+    }
+
     public void show() {
         if (!tryShow()) {
             throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
         }
     }
 
+    public ListPopupWindow getPopup() {
+        return mPopup;
+    }
+
     public boolean tryShow() {
         mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
         mPopup.setOnDismissListener(this);
         mPopup.setOnItemClickListener(this);
-
-        mAdapter = new MenuAdapter(mMenu);
         mPopup.setAdapter(mAdapter);
         mPopup.setModal(true);
 
@@ -118,11 +133,17 @@
             if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
             anchor.addOnAttachStateChangeListener(this);
             mPopup.setAnchorView(anchor);
+            mPopup.setDropDownGravity(mDropDownGravity);
         } else {
             return false;
         }
 
-        mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth));
+        if (!mHasContentWidth) {
+            mContentWidth = measureContentWidth();
+            mHasContentWidth = true;
+        }
+
+        mPopup.setContentWidth(mContentWidth);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
         mPopup.show();
         mPopup.getListView().setOnKeyListener(this);
@@ -164,15 +185,15 @@
         return false;
     }
 
-    private int measureContentWidth(ListAdapter adapter) {
+    private int measureContentWidth() {
         // Menus don't tend to be long, so this is more sane than it looks.
-        int width = 0;
+        int maxWidth = 0;
         View itemView = null;
         int itemType = 0;
-        final int widthMeasureSpec =
-            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        final int heightMeasureSpec =
-            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
+        final ListAdapter adapter = mAdapter;
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         final int count = adapter.getCount();
         for (int i = 0; i < count; i++) {
             final int positionType = adapter.getItemViewType(i);
@@ -180,14 +201,23 @@
                 itemType = positionType;
                 itemView = null;
             }
+
             if (mMeasureParent == null) {
                 mMeasureParent = new FrameLayout(mContext);
             }
+
             itemView = adapter.getView(i, itemView, mMeasureParent);
             itemView.measure(widthMeasureSpec, heightMeasureSpec);
-            width = Math.max(width, itemView.getMeasuredWidth());
+
+            final int itemWidth = itemView.getMeasuredWidth();
+            if (itemWidth >= mPopupMaxWidth) {
+                return mPopupMaxWidth;
+            } else if (itemWidth > maxWidth) {
+                maxWidth = itemWidth;
+            }
         }
-        return width;
+
+        return maxWidth;
     }
 
     @Override
@@ -228,7 +258,11 @@
 
     @Override
     public void updateMenuView(boolean cleared) {
-        if (mAdapter != null) mAdapter.notifyDataSetChanged();
+        mHasContentWidth = false;
+
+        if (mAdapter != null) {
+            mAdapter.notifyDataSetChanged();
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index ca7f5d0..f3891c7 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -201,6 +201,13 @@
         return false;
     }
 
+    public boolean isOverflowMenuShowPending() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.isOverflowMenuShowPending();
+        }
+        return false;
+    }
+
     public boolean isOverflowReserved() {
         return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
     }
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 6120a09..8a49899 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -296,23 +296,7 @@
         if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
             final int containerHeight = getMeasuredHeight();
             final int tabHeight = mTabContainer.getMeasuredHeight();
-
-            if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
-                // Not showing home, put tabs on top.
-                final int count = getChildCount();
-                for (int i = 0; i < count; i++) {
-                    final View child = getChildAt(i);
-
-                    if (child == mTabContainer) continue;
-
-                    if (!mActionBarView.isCollapsed()) {
-                        child.offsetTopAndBottom(tabHeight);
-                    }
-                }
-                mTabContainer.layout(l, 0, r, tabHeight);
-            } else {
-                mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
-            }
+            mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
         }
 
         boolean needsInvalidate = false;
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index f359146..5469b63 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.widget;
 
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.view.ViewGroup;
 import com.android.internal.app.ActionBarImpl;
 
@@ -31,18 +34,23 @@
  * has request that its layout ignore them.
  */
 public class ActionBarOverlayLayout extends ViewGroup {
+    private static final String TAG = "ActionBarOverlayLayout";
+
     private int mActionBarHeight;
     private ActionBarImpl mActionBar;
     private int mWindowVisibility = View.VISIBLE;
 
     // The main UI elements that we handle the layout of.
     private View mContent;
-    private View mActionBarTop;
     private View mActionBarBottom;
+    private ActionBarContainer mActionBarTop;
 
     // Some interior UI elements.
-    private ActionBarContainer mContainerView;
-    private ActionBarView mActionView;
+    private ActionBarView mActionBarView;
+
+    // Content overlay drawable - generally the action bar's shadow
+    private Drawable mWindowContentOverlay;
+    private boolean mIgnoreWindowContentOverlay;
 
     private boolean mOverlayMode;
     private int mLastSystemUiVisibility;
@@ -53,8 +61,9 @@
     private final Rect mInnerInsets = new Rect();
     private final Rect mLastInnerInsets = new Rect();
 
-    static final int[] mActionBarSizeAttr = new int [] {
-            com.android.internal.R.attr.actionBarSize
+    static final int[] ATTRS = new int [] {
+            com.android.internal.R.attr.actionBarSize,
+            com.android.internal.R.attr.windowContentOverlay
     };
 
     public ActionBarOverlayLayout(Context context) {
@@ -68,14 +77,18 @@
     }
 
     private void init(Context context) {
-        TypedArray ta = getContext().getTheme().obtainStyledAttributes(mActionBarSizeAttr);
+        TypedArray ta = getContext().getTheme().obtainStyledAttributes(ATTRS);
         mActionBarHeight = ta.getDimensionPixelSize(0, 0);
+        mWindowContentOverlay = ta.getDrawable(1);
+        setWillNotDraw(mWindowContentOverlay == null);
         ta.recycle();
+
+        mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
+                Build.VERSION_CODES.KITKAT;
     }
 
-    public void setActionBar(ActionBarImpl impl, boolean overlayMode) {
+    public void setActionBar(ActionBarImpl impl) {
         mActionBar = impl;
-        mOverlayMode = overlayMode;
         if (getWindowToken() != null) {
             // This is being initialized after being added to a window;
             // make sure to update all state now.
@@ -88,6 +101,18 @@
         }
     }
 
+    public void setOverlayMode(boolean overlayMode) {
+        mOverlayMode = overlayMode;
+
+        /*
+         * Drawing the window content overlay was broken before K so starting to draw it
+         * again unexpectedly will cause artifacts in some apps. They should fix it.
+         */
+        mIgnoreWindowContentOverlay = overlayMode &&
+                getContext().getApplicationInfo().targetSdkVersion <
+                        Build.VERSION_CODES.KITKAT;
+    }
+
     public void setShowingForActionMode(boolean showing) {
         if (showing) {
             // Here's a fun hack: if the status bar is currently being hidden,
@@ -253,7 +278,7 @@
             // we can't depend on the size currently reported by it -- this must remain constant.
             topInset = mActionBarHeight;
             if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
-                View tabs = mContainerView.getTabContainer();
+                View tabs = mActionBarTop.getTabContainer();
                 if (tabs != null) {
                     // If tabs are not embedded, increase space on top to account for them.
                     topInset += mActionBarHeight;
@@ -265,7 +290,7 @@
             topInset = mActionBarTop.getMeasuredHeight();
         }
 
-        if (mActionView.isSplitActionBar()) {
+        if (mActionBarView.isSplitActionBar()) {
             // If action bar is split, adjust bottom insets for it.
             if (mActionBarBottom != null) {
                 if (stable) {
@@ -352,6 +377,18 @@
     }
 
     @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+        if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
+            final int top = mActionBarTop.getVisibility() == VISIBLE ?
+                    (int) (mActionBarTop.getBottom() + mActionBarTop.getTranslationY() + 0.5f) : 0;
+            mWindowContentOverlay.setBounds(0, top, getWidth(),
+                    top + mWindowContentOverlay.getIntrinsicHeight());
+            mWindowContentOverlay.draw(c);
+        }
+    }
+
+    @Override
     public boolean shouldDelayChildPressedState() {
         return false;
     }
@@ -359,10 +396,9 @@
     void pullChildren() {
         if (mContent == null) {
             mContent = findViewById(com.android.internal.R.id.content);
-            mActionBarTop = findViewById(com.android.internal.R.id.top_action_bar);
-            mContainerView = (ActionBarContainer)findViewById(
+            mActionBarTop = (ActionBarContainer)findViewById(
                     com.android.internal.R.id.action_bar_container);
-            mActionView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+            mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
             mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
         }
     }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index dda1a10..b5d74e8 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -16,24 +16,12 @@
 
 package com.android.internal.widget;
 
-import com.android.internal.R;
-import com.android.internal.view.menu.ActionMenuItem;
-import com.android.internal.view.menu.ActionMenuPresenter;
-import com.android.internal.view.menu.ActionMenuView;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuItemImpl;
-import com.android.internal.view.menu.MenuPresenter;
-import com.android.internal.view.menu.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
-
 import android.animation.LayoutTransition;
 import android.app.ActionBar;
 import android.app.ActionBar.OnNavigationListener;
-import android.app.Activity;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -42,7 +30,6 @@
 import android.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.CollapsibleActionView;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -62,6 +49,16 @@
 import android.widget.Spinner;
 import android.widget.SpinnerAdapter;
 import android.widget.TextView;
+import com.android.internal.R;
+import com.android.internal.transition.ActionBarTransition;
+import com.android.internal.view.menu.ActionMenuItem;
+import com.android.internal.view.menu.ActionMenuPresenter;
+import com.android.internal.view.menu.ActionMenuView;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.MenuView;
+import com.android.internal.view.menu.SubMenuBuilder;
 
 /**
  * @hide
@@ -101,7 +98,6 @@
     private LinearLayout mTitleLayout;
     private TextView mTitleView;
     private TextView mSubtitleView;
-    private View mTitleUpView;
     private ViewGroup mUpGoerFive;
 
     private Spinner mSpinner;
@@ -188,34 +184,8 @@
                 ActionBar.NAVIGATION_MODE_STANDARD);
         mTitle = a.getText(R.styleable.ActionBar_title);
         mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
-
         mLogo = a.getDrawable(R.styleable.ActionBar_logo);
-        if (mLogo == null) {
-            if (context instanceof Activity) {
-                try {
-                    mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
-                } catch (NameNotFoundException e) {
-                    Log.e(TAG, "Activity component name not found!", e);
-                }
-            }
-            if (mLogo == null) {
-                mLogo = appInfo.loadLogo(pm);
-            }
-        }
-
         mIcon = a.getDrawable(R.styleable.ActionBar_icon);
-        if (mIcon == null) {
-            if (context instanceof Activity) {
-                try {
-                    mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
-                } catch (NameNotFoundException e) {
-                    Log.e(TAG, "Activity component name not found!", e);
-                }
-            }
-            if (mIcon == null) {
-                mIcon = appInfo.loadIcon(pm);
-            }
-        }
 
         final LayoutInflater inflater = LayoutInflater.from(context);
 
@@ -228,7 +198,7 @@
         mHomeLayout = (HomeView) inflater.inflate(homeResId, mUpGoerFive, false);
 
         mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, mUpGoerFive, false);
-        mExpandedHomeLayout.setUp(true);
+        mExpandedHomeLayout.setShowUp(true);
         mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener);
         mExpandedHomeLayout.setContentDescription(getResources().getText(
                 R.string.action_bar_up_description));
@@ -281,7 +251,6 @@
 
         mTitleView = null;
         mSubtitleView = null;
-        mTitleUpView = null;
         if (mTitleLayout != null && mTitleLayout.getParent() == mUpGoerFive) {
             mUpGoerFive.removeView(mTitleLayout);
         }
@@ -505,6 +474,9 @@
 
     public void setCustomNavigationView(View view) {
         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
+        if (showCustom) {
+            ActionBarTransition.beginDelayedTransition(this);
+        }
         if (mCustomNavView != null && showCustom) {
             removeView(mCustomNavView);
         }
@@ -542,6 +514,7 @@
     }
 
     private void setTitleImpl(CharSequence title) {
+        ActionBarTransition.beginDelayedTransition(this);
         mTitle = title;
         if (mTitleView != null) {
             mTitleView.setText(title);
@@ -561,6 +534,7 @@
     }
 
     public void setSubtitle(CharSequence subtitle) {
+        ActionBarTransition.beginDelayedTransition(this);
         mSubtitle = subtitle;
         if (mSubtitleView != null) {
             mSubtitleView.setText(subtitle);
@@ -641,13 +615,11 @@
         mDisplayOptions = options;
 
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
-            final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
-            final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
-            mHomeLayout.setVisibility(vis);
+            ActionBarTransition.beginDelayedTransition(this);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
                 final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
-                mHomeLayout.setUp(setUp);
+                mHomeLayout.setShowUp(setUp);
 
                 // Showing home as up implicitly enables interaction with it.
                 // In honeycomb it was always enabled, so make this transition
@@ -671,11 +643,14 @@
                 }
             }
 
-            if (mTitleLayout != null && (flagsChanged &
-                    (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
-                final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
-                mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
-            }
+            final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
+            final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+            final boolean titleUp = !showHome && homeAsUp;
+            mHomeLayout.setShowIcon(showHome);
+
+            final int homeVis = (showHome || titleUp) && mExpandedActionView == null ?
+                    VISIBLE : GONE;
+            mHomeLayout.setVisibility(homeVis);
 
             if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
                 if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
@@ -729,7 +704,11 @@
     }
 
     public void setIcon(int resId) {
-        setIcon(mContext.getResources().getDrawable(resId));
+        setIcon(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
+    }
+
+    public boolean hasIcon() {
+        return mIcon != null;
     }
 
     public void setLogo(Drawable logo) {
@@ -740,12 +719,17 @@
     }
 
     public void setLogo(int resId) {
-        setLogo(mContext.getResources().getDrawable(resId));
+        setLogo(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
+    }
+
+    public boolean hasLogo() {
+        return mLogo != null;
     }
 
     public void setNavigationMode(int mode) {
         final int oldMode = mNavigationMode;
         if (mode != oldMode) {
+            ActionBarTransition.beginDelayedTransition(this);
             switch (oldMode) {
             case ActionBar.NAVIGATION_MODE_LIST:
                 if (mListNavLayout != null) {
@@ -851,7 +835,6 @@
                     this, false);
             mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
             mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
-            mTitleUpView = (View) mTitleLayout.findViewById(R.id.up);
 
             if (mTitleStyleRes != 0) {
                 mTitleView.setTextAppearance(mContext, mTitleStyleRes);
@@ -867,13 +850,9 @@
                 mSubtitleView.setText(mSubtitle);
                 mSubtitleView.setVisibility(VISIBLE);
             }
-
-            final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
-            final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0;
-            final boolean showTitleUp = !showHome;
-            mTitleUpView.setVisibility(showTitleUp ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
         }
 
+        ActionBarTransition.beginDelayedTransition(this);
         mUpGoerFive.addView(mTitleLayout);
         if (mExpandedActionView != null ||
                 (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) {
@@ -977,25 +956,32 @@
         int leftOfCenter = availableWidth / 2;
         int rightOfCenter = leftOfCenter;
 
+        final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
+                (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
+
         HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
 
-        int homeWidth = 0;
-        if (homeLayout.getVisibility() != GONE && homeLayout.getParent() == mUpGoerFive) {
-            final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams();
-            int homeWidthSpec;
-            if (lp.width < 0) {
-                homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
-            } else {
-                homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-            }
+        final ViewGroup.LayoutParams homeLp = homeLayout.getLayoutParams();
+        int homeWidthSpec;
+        if (homeLp.width < 0) {
+            homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
+        } else {
+            homeWidthSpec = MeasureSpec.makeMeasureSpec(homeLp.width, MeasureSpec.EXACTLY);
+        }
 
-            /*
-             * This is a little weird.
-             * We're only measuring the *home* affordance within the Up container here
-             * on purpose, because we want to give the available space to all other views before
-             * the title text. We'll remeasure the whole up container again later.
-             */
-            homeLayout.measure(homeWidthSpec, exactHeightSpec);
+        /*
+         * This is a little weird.
+         * We're only measuring the *home* affordance within the Up container here
+         * on purpose, because we want to give the available space to all other views before
+         * the title text. We'll remeasure the whole up container again later.
+         * We need to measure this container so we know the right offset for the up affordance
+         * no matter what.
+         */
+        homeLayout.measure(homeWidthSpec, exactHeightSpec);
+
+        int homeWidth = 0;
+        if ((homeLayout.getVisibility() != GONE && homeLayout.getParent() == mUpGoerFive)
+                || showTitle) {
             homeWidth = homeLayout.getMeasuredWidth();
             final int homeOffsetWidth = homeWidth + homeLayout.getStartOffset();
             availableWidth = Math.max(0, availableWidth - homeOffsetWidth);
@@ -1015,9 +1001,6 @@
                     rightOfCenter - mIndeterminateProgressView.getMeasuredWidth());
         }
 
-        final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
-                (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
-
         if (mExpandedActionView == null) {
             switch (mNavigationMode) {
                 case ActionBar.NAVIGATION_MODE_LIST:
@@ -1146,7 +1129,7 @@
         }
 
         final boolean isLayoutRtl = isLayoutRtl();
-        final int direction = isLayoutRtl ? +1 : -1;
+        final int direction = isLayoutRtl ? 1 : -1;
         int menuStart = isLayoutRtl ? getPaddingLeft() : r - l - getPaddingRight();
         // In LTR mode, we start from left padding and go to the right; in RTL mode, we start
         // from the padding right and go to the left (in reverse way)
@@ -1154,8 +1137,16 @@
         final int y = getPaddingTop();
 
         HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
-        final int startOffset = homeLayout.getVisibility() != GONE &&
-                homeLayout.getParent() == mUpGoerFive ? homeLayout.getStartOffset() : 0;
+        final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
+                (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
+        int startOffset = 0;
+        if (homeLayout.getParent() == mUpGoerFive) {
+            if (homeLayout.getVisibility() != GONE) {
+                startOffset = homeLayout.getStartOffset();
+            } else if (showTitle) {
+                startOffset = homeLayout.getUpWidth();
+            }
+        }
 
         // Position the up container based on where the edge of the home layout should go.
         x += positionChild(mUpGoerFive,
@@ -1163,9 +1154,6 @@
         x = next(x, startOffset, isLayoutRtl);
 
         if (mExpandedActionView == null) {
-            final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
-                    (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
-
             switch (mNavigationMode) {
                 case ActionBar.NAVIGATION_MODE_STANDARD:
                     break;
@@ -1396,6 +1384,7 @@
         private ImageView mUpView;
         private ImageView mIconView;
         private int mUpWidth;
+        private int mStartOffset;
         private int mUpIndicatorRes;
         private Drawable mDefaultUpIndicator;
 
@@ -1414,10 +1403,14 @@
             }
         }
 
-        public void setUp(boolean isUp) {
+        public void setShowUp(boolean isUp) {
             mUpView.setVisibility(isUp ? VISIBLE : GONE);
         }
 
+        public void setShowIcon(boolean showIcon) {
+            mIconView.setVisibility(showIcon ? VISIBLE : GONE);
+        }
+
         public void setIcon(Drawable icon) {
             mIconView.setImageDrawable(icon);
         }
@@ -1470,21 +1463,33 @@
         }
 
         public int getStartOffset() {
-            return mUpView.getVisibility() == GONE ? mUpWidth : 0;
+            return mUpView.getVisibility() == GONE ? mStartOffset : 0;
+        }
+
+        public int getUpWidth() {
+            return mUpWidth;
         }
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
             measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
             final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
-            mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
-            int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth;
+            final int upMargins = upLp.leftMargin + upLp.rightMargin;
+            mUpWidth = mUpView.getMeasuredWidth();
+            mStartOffset = mUpWidth + upMargins;
+            int width = mUpView.getVisibility() == GONE ? 0 : mStartOffset;
             int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
-            measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
-            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
-            width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
-            height = Math.max(height,
-                    iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+
+            if (mIconView.getVisibility() != GONE) {
+                measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
+                final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+                width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
+                height = Math.max(height,
+                        iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+            } else if (upMargins < 0) {
+                // Remove the measurement effects of negative margins used for offsets
+                width -= upMargins;
+            }
 
             final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
             final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
@@ -1626,6 +1631,8 @@
 
         @Override
         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            ActionBarTransition.beginDelayedTransition(ActionBarView.this);
+
             mExpandedActionView = item.getActionView();
             mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
             mCurrentExpandedItem = item;
@@ -1653,6 +1660,8 @@
 
         @Override
         public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            ActionBarTransition.beginDelayedTransition(ActionBarView.this);
+
             // Do this before detaching the actionview from the hierarchy, in case
             // it needs to dismiss the soft keyboard, etc.
             if (mExpandedActionView instanceof CollapsibleActionView) {
diff --git a/core/java/com/android/internal/widget/AutoScrollHelper.java b/core/java/com/android/internal/widget/AutoScrollHelper.java
new file mode 100644
index 0000000..7a294aa
--- /dev/null
+++ b/core/java/com/android/internal/widget/AutoScrollHelper.java
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.res.Resources;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.AbsListView;
+
+/**
+ * AutoScrollHelper is a utility class for adding automatic edge-triggered
+ * scrolling to Views.
+ * <p>
+ * <b>Note:</b> Implementing classes are responsible for overriding the
+ * {@link #scrollTargetBy}, {@link #canTargetScrollHorizontally}, and
+ * {@link #canTargetScrollVertically} methods. See
+ * {@link AbsListViewAutoScroller} for an {@link android.widget.AbsListView}
+ * -specific implementation.
+ * <p>
+ * <h1>Activation</h1> Automatic scrolling starts when the user touches within
+ * an activation area. By default, activation areas are defined as the top,
+ * left, right, and bottom 20% of the host view's total area. Touching within
+ * the top activation area scrolls up, left scrolls to the left, and so on.
+ * <p>
+ * As the user touches closer to the extreme edge of the activation area,
+ * scrolling accelerates up to a maximum velocity. When using the default edge
+ * type, {@link #EDGE_TYPE_INSIDE_EXTEND}, moving outside of the view bounds
+ * will scroll at the maximum velocity.
+ * <p>
+ * The following activation properties may be configured:
+ * <ul>
+ * <li>Delay after entering activation area before auto-scrolling begins, see
+ * {@link #setActivationDelay}. Default value is
+ * {@link ViewConfiguration#getTapTimeout()} to avoid conflicting with taps.
+ * <li>Location of activation areas, see {@link #setEdgeType}. Default value is
+ * {@link #EDGE_TYPE_INSIDE_EXTEND}.
+ * <li>Size of activation areas relative to view size, see
+ * {@link #setRelativeEdges}. Default value is 20% for both vertical and
+ * horizontal edges.
+ * <li>Maximum size used to constrain relative size, see
+ * {@link #setMaximumEdges}. Default value is {@link #NO_MAX}.
+ * </ul>
+ * <h1>Scrolling</h1> When automatic scrolling is active, the helper will
+ * repeatedly call {@link #scrollTargetBy} to apply new scrolling offsets.
+ * <p>
+ * The following scrolling properties may be configured:
+ * <ul>
+ * <li>Acceleration ramp-up duration, see {@link #setRampUpDuration}. Default
+ * value is 500 milliseconds.
+ * <li>Acceleration ramp-down duration, see {@link #setRampDownDuration}.
+ * Default value is 500 milliseconds.
+ * <li>Target velocity relative to view size, see {@link #setRelativeVelocity}.
+ * Default value is 100% per second for both vertical and horizontal.
+ * <li>Minimum velocity used to constrain relative velocity, see
+ * {@link #setMinimumVelocity}. When set, scrolling will accelerate to the
+ * larger of either this value or the relative target value. Default value is
+ * approximately 5 centimeters or 315 dips per second.
+ * <li>Maximum velocity used to constrain relative velocity, see
+ * {@link #setMaximumVelocity}. Default value is approximately 25 centimeters or
+ * 1575 dips per second.
+ * </ul>
+ */
+public abstract class AutoScrollHelper implements View.OnTouchListener {
+    /**
+     * Constant passed to {@link #setRelativeEdges} or
+     * {@link #setRelativeVelocity}. Using this value ensures that the computed
+     * relative value is ignored and the absolute maximum value is always used.
+     */
+    public static final float RELATIVE_UNSPECIFIED = 0;
+
+    /**
+     * Constant passed to {@link #setMaximumEdges}, {@link #setMaximumVelocity},
+     * or {@link #setMinimumVelocity}. Using this value ensures that the
+     * computed relative value is always used without constraining to a
+     * particular minimum or maximum value.
+     */
+    public static final float NO_MAX = Float.MAX_VALUE;
+
+    /**
+     * Constant passed to {@link #setMaximumEdges}, or
+     * {@link #setMaximumVelocity}, or {@link #setMinimumVelocity}. Using this
+     * value ensures that the computed relative value is always used without
+     * constraining to a particular minimum or maximum value.
+     */
+    public static final float NO_MIN = 0;
+
+    /**
+     * Edge type that specifies an activation area starting at the view bounds
+     * and extending inward. Moving outside the view bounds will stop scrolling.
+     *
+     * @see #setEdgeType
+     */
+    public static final int EDGE_TYPE_INSIDE = 0;
+
+    /**
+     * Edge type that specifies an activation area starting at the view bounds
+     * and extending inward. After activation begins, moving outside the view
+     * bounds will continue scrolling.
+     *
+     * @see #setEdgeType
+     */
+    public static final int EDGE_TYPE_INSIDE_EXTEND = 1;
+
+    /**
+     * Edge type that specifies an activation area starting at the view bounds
+     * and extending outward. Moving inside the view bounds will stop scrolling.
+     *
+     * @see #setEdgeType
+     */
+    public static final int EDGE_TYPE_OUTSIDE = 2;
+
+    private static final int HORIZONTAL = 0;
+    private static final int VERTICAL = 1;
+
+    /** Scroller used to control acceleration toward maximum velocity. */
+    private final ClampedScroller mScroller = new ClampedScroller();
+
+    /** Interpolator used to scale velocity with touch position. */
+    private final Interpolator mEdgeInterpolator = new AccelerateInterpolator();
+
+    /** The view to auto-scroll. Might not be the source of touch events. */
+    private final View mTarget;
+
+    /** Runnable used to animate scrolling. */
+    private Runnable mRunnable;
+
+    /** Edge insets used to activate auto-scrolling. */
+    private float[] mRelativeEdges = new float[] { RELATIVE_UNSPECIFIED, RELATIVE_UNSPECIFIED };
+
+    /** Clamping values for edge insets used to activate auto-scrolling. */
+    private float[] mMaximumEdges = new float[] { NO_MAX, NO_MAX };
+
+    /** The type of edge being used. */
+    private int mEdgeType;
+
+    /** Delay after entering an activation edge before auto-scrolling begins. */
+    private int mActivationDelay;
+
+    /** Relative scrolling velocity at maximum edge distance. */
+    private float[] mRelativeVelocity = new float[] { RELATIVE_UNSPECIFIED, RELATIVE_UNSPECIFIED };
+
+    /** Clamping values used for scrolling velocity. */
+    private float[] mMinimumVelocity = new float[] { NO_MIN, NO_MIN };
+
+    /** Clamping values used for scrolling velocity. */
+    private float[] mMaximumVelocity = new float[] { NO_MAX, NO_MAX };
+
+    /** Whether to start activation immediately. */
+    private boolean mAlreadyDelayed;
+
+    /** Whether to reset the scroller start time on the next animation. */
+    private boolean mNeedsReset;
+
+    /** Whether to send a cancel motion event to the target view. */
+    private boolean mNeedsCancel;
+
+    /** Whether the auto-scroller is actively scrolling. */
+    private boolean mAnimating;
+
+    /** Whether the auto-scroller is enabled. */
+    private boolean mEnabled;
+
+    /** Whether the auto-scroller consumes events when scrolling. */
+    private boolean mExclusive;
+
+    // Default values.
+    private static final int DEFAULT_EDGE_TYPE = EDGE_TYPE_INSIDE_EXTEND;
+    private static final int DEFAULT_MINIMUM_VELOCITY_DIPS = 315;
+    private static final int DEFAULT_MAXIMUM_VELOCITY_DIPS = 1575;
+    private static final float DEFAULT_MAXIMUM_EDGE = NO_MAX;
+    private static final float DEFAULT_RELATIVE_EDGE = 0.2f;
+    private static final float DEFAULT_RELATIVE_VELOCITY = 1f;
+    private static final int DEFAULT_ACTIVATION_DELAY = ViewConfiguration.getTapTimeout();
+    private static final int DEFAULT_RAMP_UP_DURATION = 500;
+    private static final int DEFAULT_RAMP_DOWN_DURATION = 500;
+
+    /**
+     * Creates a new helper for scrolling the specified target view.
+     * <p>
+     * The resulting helper may be configured by chaining setter calls and
+     * should be set as a touch listener on the target view.
+     * <p>
+     * By default, the helper is disabled and will not respond to touch events
+     * until it is enabled using {@link #setEnabled}.
+     *
+     * @param target The view to automatically scroll.
+     */
+    public AutoScrollHelper(View target) {
+        mTarget = target;
+
+        final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
+        final int maxVelocity = (int) (DEFAULT_MAXIMUM_VELOCITY_DIPS * metrics.density + 0.5f);
+        final int minVelocity = (int) (DEFAULT_MINIMUM_VELOCITY_DIPS * metrics.density + 0.5f);
+        setMaximumVelocity(maxVelocity, maxVelocity);
+        setMinimumVelocity(minVelocity, minVelocity);
+
+        setEdgeType(DEFAULT_EDGE_TYPE);
+        setMaximumEdges(DEFAULT_MAXIMUM_EDGE, DEFAULT_MAXIMUM_EDGE);
+        setRelativeEdges(DEFAULT_RELATIVE_EDGE, DEFAULT_RELATIVE_EDGE);
+        setRelativeVelocity(DEFAULT_RELATIVE_VELOCITY, DEFAULT_RELATIVE_VELOCITY);
+        setActivationDelay(DEFAULT_ACTIVATION_DELAY);
+        setRampUpDuration(DEFAULT_RAMP_UP_DURATION);
+        setRampDownDuration(DEFAULT_RAMP_DOWN_DURATION);
+    }
+
+    /**
+     * Sets whether the scroll helper is enabled and should respond to touch
+     * events.
+     *
+     * @param enabled Whether the scroll helper is enabled.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setEnabled(boolean enabled) {
+        if (mEnabled && !enabled) {
+            requestStop();
+        }
+
+        mEnabled = enabled;
+        return this;
+    }
+
+    /**
+     * @return True if this helper is enabled and responding to touch events.
+     */
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    /**
+     * Enables or disables exclusive handling of touch events during scrolling.
+     * By default, exclusive handling is disabled and the target view receives
+     * all touch events.
+     * <p>
+     * When enabled, {@link #onTouch} will return true if the helper is
+     * currently scrolling and false otherwise.
+     *
+     * @param exclusive True to exclusively handle touch events during scrolling,
+     *            false to allow the target view to receive all touch events.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setExclusive(boolean exclusive) {
+        mExclusive = exclusive;
+        return this;
+    }
+
+    /**
+     * Indicates whether the scroll helper handles touch events exclusively
+     * during scrolling.
+     *
+     * @return True if exclusive handling of touch events during scrolling is
+     *         enabled, false otherwise.
+     * @see #setExclusive(boolean)
+     */
+    public boolean isExclusive() {
+        return mExclusive;
+    }
+
+    /**
+     * Sets the absolute maximum scrolling velocity.
+     * <p>
+     * If relative velocity is not specified, scrolling will always reach the
+     * same maximum velocity. If both relative and maximum velocities are
+     * specified, the maximum velocity will be used to clamp the calculated
+     * relative velocity.
+     *
+     * @param horizontalMax The maximum horizontal scrolling velocity, or
+     *            {@link #NO_MAX} to leave the relative value unconstrained.
+     * @param verticalMax The maximum vertical scrolling velocity, or
+     *            {@link #NO_MAX} to leave the relative value unconstrained.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setMaximumVelocity(float horizontalMax, float verticalMax) {
+        mMaximumVelocity[HORIZONTAL] = horizontalMax / 1000f;
+        mMaximumVelocity[VERTICAL] = verticalMax / 1000f;
+        return this;
+    }
+
+    /**
+     * Sets the absolute minimum scrolling velocity.
+     * <p>
+     * If both relative and minimum velocities are specified, the minimum
+     * velocity will be used to clamp the calculated relative velocity.
+     *
+     * @param horizontalMin The minimum horizontal scrolling velocity, or
+     *            {@link #NO_MIN} to leave the relative value unconstrained.
+     * @param verticalMin The minimum vertical scrolling velocity, or
+     *            {@link #NO_MIN} to leave the relative value unconstrained.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setMinimumVelocity(float horizontalMin, float verticalMin) {
+        mMinimumVelocity[HORIZONTAL] = horizontalMin / 1000f;
+        mMinimumVelocity[VERTICAL] = verticalMin / 1000f;
+        return this;
+    }
+
+    /**
+     * Sets the target scrolling velocity relative to the host view's
+     * dimensions.
+     * <p>
+     * If both relative and maximum velocities are specified, the maximum
+     * velocity will be used to clamp the calculated relative velocity.
+     *
+     * @param horizontal The target horizontal velocity as a fraction of the
+     *            host view width per second, or {@link #RELATIVE_UNSPECIFIED}
+     *            to ignore.
+     * @param vertical The target vertical velocity as a fraction of the host
+     *            view height per second, or {@link #RELATIVE_UNSPECIFIED} to
+     *            ignore.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setRelativeVelocity(float horizontal, float vertical) {
+        mRelativeVelocity[HORIZONTAL] = horizontal / 1000f;
+        mRelativeVelocity[VERTICAL] = vertical / 1000f;
+        return this;
+    }
+
+    /**
+     * Sets the activation edge type, one of:
+     * <ul>
+     * <li>{@link #EDGE_TYPE_INSIDE} for edges that respond to touches inside
+     * the bounds of the host view. If touch moves outside the bounds, scrolling
+     * will stop.
+     * <li>{@link #EDGE_TYPE_INSIDE_EXTEND} for inside edges that continued to
+     * scroll when touch moves outside the bounds of the host view.
+     * <li>{@link #EDGE_TYPE_OUTSIDE} for edges that only respond to touches
+     * that move outside the bounds of the host view.
+     * </ul>
+     *
+     * @param type The type of edge to use.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setEdgeType(int type) {
+        mEdgeType = type;
+        return this;
+    }
+
+    /**
+     * Sets the activation edge size relative to the host view's dimensions.
+     * <p>
+     * If both relative and maximum edges are specified, the maximum edge will
+     * be used to constrain the calculated relative edge size.
+     *
+     * @param horizontal The horizontal edge size as a fraction of the host view
+     *            width, or {@link #RELATIVE_UNSPECIFIED} to always use the
+     *            maximum value.
+     * @param vertical The vertical edge size as a fraction of the host view
+     *            height, or {@link #RELATIVE_UNSPECIFIED} to always use the
+     *            maximum value.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setRelativeEdges(float horizontal, float vertical) {
+        mRelativeEdges[HORIZONTAL] = horizontal;
+        mRelativeEdges[VERTICAL] = vertical;
+        return this;
+    }
+
+    /**
+     * Sets the absolute maximum edge size.
+     * <p>
+     * If relative edge size is not specified, activation edges will always be
+     * the maximum edge size. If both relative and maximum edges are specified,
+     * the maximum edge will be used to constrain the calculated relative edge
+     * size.
+     *
+     * @param horizontalMax The maximum horizontal edge size in pixels, or
+     *            {@link #NO_MAX} to use the unconstrained calculated relative
+     *            value.
+     * @param verticalMax The maximum vertical edge size in pixels, or
+     *            {@link #NO_MAX} to use the unconstrained calculated relative
+     *            value.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setMaximumEdges(float horizontalMax, float verticalMax) {
+        mMaximumEdges[HORIZONTAL] = horizontalMax;
+        mMaximumEdges[VERTICAL] = verticalMax;
+        return this;
+    }
+
+    /**
+     * Sets the delay after entering an activation edge before activation of
+     * auto-scrolling. By default, the activation delay is set to
+     * {@link ViewConfiguration#getTapTimeout()}.
+     * <p>
+     * Specifying a delay of zero will start auto-scrolling immediately after
+     * the touch position enters an activation edge.
+     *
+     * @param delayMillis The activation delay in milliseconds.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setActivationDelay(int delayMillis) {
+        mActivationDelay = delayMillis;
+        return this;
+    }
+
+    /**
+     * Sets the amount of time after activation of auto-scrolling that is takes
+     * to reach target velocity for the current touch position.
+     * <p>
+     * Specifying a duration greater than zero prevents sudden jumps in
+     * velocity.
+     *
+     * @param durationMillis The ramp-up duration in milliseconds.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setRampUpDuration(int durationMillis) {
+        mScroller.setRampUpDuration(durationMillis);
+        return this;
+    }
+
+    /**
+     * Sets the amount of time after de-activation of auto-scrolling that is
+     * takes to slow to a stop.
+     * <p>
+     * Specifying a duration greater than zero prevents sudden jumps in
+     * velocity.
+     *
+     * @param durationMillis The ramp-down duration in milliseconds.
+     * @return The scroll helper, which may used to chain setter calls.
+     */
+    public AutoScrollHelper setRampDownDuration(int durationMillis) {
+        mScroller.setRampDownDuration(durationMillis);
+        return this;
+    }
+
+    /**
+     * Handles touch events by activating automatic scrolling, adjusting scroll
+     * velocity, or stopping.
+     * <p>
+     * If {@link #isExclusive()} is false, always returns false so that
+     * the host view may handle touch events. Otherwise, returns true when
+     * automatic scrolling is active and false otherwise.
+     */
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (!mEnabled) {
+            return false;
+        }
+
+        final int action = event.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mNeedsCancel = true;
+                mAlreadyDelayed = false;
+                // $FALL-THROUGH$
+            case MotionEvent.ACTION_MOVE:
+                final float xTargetVelocity = computeTargetVelocity(
+                        HORIZONTAL, event.getX(), v.getWidth(), mTarget.getWidth());
+                final float yTargetVelocity = computeTargetVelocity(
+                        VERTICAL, event.getY(), v.getHeight(), mTarget.getHeight());
+                mScroller.setTargetVelocity(xTargetVelocity, yTargetVelocity);
+
+                // If the auto scroller was not previously active, but it should
+                // be, then update the state and start animations.
+                if (!mAnimating && shouldAnimate()) {
+                    startAnimating();
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                requestStop();
+                break;
+        }
+
+        return mExclusive && mAnimating;
+    }
+
+    /**
+     * @return whether the target is able to scroll in the requested direction
+     */
+    private boolean shouldAnimate() {
+        final ClampedScroller scroller = mScroller;
+        final int verticalDirection = scroller.getVerticalDirection();
+        final int horizontalDirection = scroller.getHorizontalDirection();
+
+        return verticalDirection != 0 && canTargetScrollVertically(verticalDirection)
+                || horizontalDirection != 0 && canTargetScrollHorizontally(horizontalDirection);
+    }
+
+    /**
+     * Starts the scroll animation.
+     */
+    private void startAnimating() {
+        if (mRunnable == null) {
+            mRunnable = new ScrollAnimationRunnable();
+        }
+
+        mAnimating = true;
+        mNeedsReset = true;
+
+        if (!mAlreadyDelayed && mActivationDelay > 0) {
+            mTarget.postOnAnimationDelayed(mRunnable, mActivationDelay);
+        } else {
+            mRunnable.run();
+        }
+
+        // If we start animating again before the user lifts their finger, we
+        // already know it's not a tap and don't need an activation delay.
+        mAlreadyDelayed = true;
+    }
+
+    /**
+     * Requests that the scroll animation slow to a stop. If there is an
+     * activation delay, this may occur between posting the animation and
+     * actually running it.
+     */
+    private void requestStop() {
+        if (mNeedsReset) {
+            // The animation has been posted, but hasn't run yet. Manually
+            // stopping animation will prevent it from running.
+            mAnimating = false;
+        } else {
+            mScroller.requestStop();
+        }
+    }
+
+    private float computeTargetVelocity(
+            int direction, float coordinate, float srcSize, float dstSize) {
+        final float relativeEdge = mRelativeEdges[direction];
+        final float maximumEdge = mMaximumEdges[direction];
+        final float value = getEdgeValue(relativeEdge, srcSize, maximumEdge, coordinate);
+        if (value == 0) {
+            // The edge in this direction is not activated.
+            return 0;
+        }
+
+        final float relativeVelocity = mRelativeVelocity[direction];
+        final float minimumVelocity = mMinimumVelocity[direction];
+        final float maximumVelocity = mMaximumVelocity[direction];
+        final float targetVelocity = relativeVelocity * dstSize;
+
+        // Target velocity is adjusted for interpolated edge position, then
+        // clamped to the minimum and maximum values. Later, this value will be
+        // adjusted for time-based acceleration.
+        if (value > 0) {
+            return constrain(value * targetVelocity, minimumVelocity, maximumVelocity);
+        } else {
+            return -constrain(-value * targetVelocity, minimumVelocity, maximumVelocity);
+        }
+    }
+
+    /**
+     * Override this method to scroll the target view by the specified number of
+     * pixels.
+     *
+     * @param deltaX The number of pixels to scroll by horizontally.
+     * @param deltaY The number of pixels to scroll by vertically.
+     */
+    public abstract void scrollTargetBy(int deltaX, int deltaY);
+
+    /**
+     * Override this method to return whether the target view can be scrolled
+     * horizontally in a certain direction.
+     *
+     * @param direction Negative to check scrolling left, positive to check
+     *            scrolling right.
+     * @return true if the target view is able to horizontally scroll in the
+     *         specified direction.
+     */
+    public abstract boolean canTargetScrollHorizontally(int direction);
+
+    /**
+     * Override this method to return whether the target view can be scrolled
+     * vertically in a certain direction.
+     *
+     * @param direction Negative to check scrolling up, positive to check
+     *            scrolling down.
+     * @return true if the target view is able to vertically scroll in the
+     *         specified direction.
+     */
+    public abstract boolean canTargetScrollVertically(int direction);
+
+    /**
+     * Returns the interpolated position of a touch point relative to an edge
+     * defined by its relative inset, its maximum absolute inset, and the edge
+     * interpolator.
+     *
+     * @param relativeValue The size of the inset relative to the total size.
+     * @param size Total size.
+     * @param maxValue The maximum size of the inset, used to clamp (relative *
+     *            total).
+     * @param current Touch position within within the total size.
+     * @return Interpolated value of the touch position within the edge.
+     */
+    private float getEdgeValue(float relativeValue, float size, float maxValue, float current) {
+        // For now, leading and trailing edges are always the same size.
+        final float edgeSize = constrain(relativeValue * size, NO_MIN, maxValue);
+        final float valueLeading = constrainEdgeValue(current, edgeSize);
+        final float valueTrailing = constrainEdgeValue(size - current, edgeSize);
+        final float value = (valueTrailing - valueLeading);
+        final float interpolated;
+        if (value < 0) {
+            interpolated = -mEdgeInterpolator.getInterpolation(-value);
+        } else if (value > 0) {
+            interpolated = mEdgeInterpolator.getInterpolation(value);
+        } else {
+            return 0;
+        }
+
+        return constrain(interpolated, -1, 1);
+    }
+
+    private float constrainEdgeValue(float current, float leading) {
+        if (leading == 0) {
+            return 0;
+        }
+
+        switch (mEdgeType) {
+            case EDGE_TYPE_INSIDE:
+            case EDGE_TYPE_INSIDE_EXTEND:
+                if (current < leading) {
+                    if (current >= 0) {
+                        // Movement up to the edge is scaled.
+                        return 1f - current / leading;
+                    } else if (mAnimating && (mEdgeType == EDGE_TYPE_INSIDE_EXTEND)) {
+                        // Movement beyond the edge is always maximum.
+                        return 1f;
+                    }
+                }
+                break;
+            case EDGE_TYPE_OUTSIDE:
+                if (current < 0) {
+                    // Movement beyond the edge is scaled.
+                    return current / -leading;
+                }
+                break;
+        }
+
+        return 0;
+    }
+
+    private static int constrain(int value, int min, int max) {
+        if (value > max) {
+            return max;
+        } else if (value < min) {
+            return min;
+        } else {
+            return value;
+        }
+    }
+
+    private static float constrain(float value, float min, float max) {
+        if (value > max) {
+            return max;
+        } else if (value < min) {
+            return min;
+        } else {
+            return value;
+        }
+    }
+
+    /**
+     * Sends a {@link MotionEvent#ACTION_CANCEL} event to the target view,
+     * canceling any ongoing touch events.
+     */
+    private void cancelTargetTouch() {
+        final long eventTime = SystemClock.uptimeMillis();
+        final MotionEvent cancel = MotionEvent.obtain(
+                eventTime, eventTime, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+        mTarget.onTouchEvent(cancel);
+        cancel.recycle();
+    }
+
+    private class ScrollAnimationRunnable implements Runnable {
+        @Override
+        public void run() {
+            if (!mAnimating) {
+                return;
+            }
+
+            if (mNeedsReset) {
+                mNeedsReset = false;
+                mScroller.start();
+            }
+
+            final ClampedScroller scroller = mScroller;
+            if (scroller.isFinished() || !shouldAnimate()) {
+                mAnimating = false;
+                return;
+            }
+
+            if (mNeedsCancel) {
+                mNeedsCancel = false;
+                cancelTargetTouch();
+            }
+
+            scroller.computeScrollDelta();
+
+            final int deltaX = scroller.getDeltaX();
+            final int deltaY = scroller.getDeltaY();
+            scrollTargetBy(deltaX,  deltaY);
+
+            // Keep going until the scroller has permanently stopped.
+            mTarget.postOnAnimation(this);
+        }
+    }
+
+    /**
+     * Scroller whose velocity follows the curve of an {@link Interpolator} and
+     * is clamped to the interpolated 0f value before starting and the
+     * interpolated 1f value after a specified duration.
+     */
+    private static class ClampedScroller {
+        private int mRampUpDuration;
+        private int mRampDownDuration;
+        private float mTargetVelocityX;
+        private float mTargetVelocityY;
+
+        private long mStartTime;
+
+        private long mDeltaTime;
+        private int mDeltaX;
+        private int mDeltaY;
+
+        private long mStopTime;
+        private float mStopValue;
+        private int mEffectiveRampDown;
+
+        /**
+         * Creates a new ramp-up scroller that reaches full velocity after a
+         * specified duration.
+         */
+        public ClampedScroller() {
+            mStartTime = Long.MIN_VALUE;
+            mStopTime = -1;
+            mDeltaTime = 0;
+            mDeltaX = 0;
+            mDeltaY = 0;
+        }
+
+        public void setRampUpDuration(int durationMillis) {
+            mRampUpDuration = durationMillis;
+        }
+
+        public void setRampDownDuration(int durationMillis) {
+            mRampDownDuration = durationMillis;
+        }
+
+        /**
+         * Starts the scroller at the current animation time.
+         */
+        public void start() {
+            mStartTime = AnimationUtils.currentAnimationTimeMillis();
+            mStopTime = -1;
+            mDeltaTime = mStartTime;
+            mStopValue = 0.5f;
+            mDeltaX = 0;
+            mDeltaY = 0;
+        }
+
+        /**
+         * Stops the scroller at the current animation time.
+         */
+        public void requestStop() {
+            final long currentTime = AnimationUtils.currentAnimationTimeMillis();
+            mEffectiveRampDown = constrain((int) (currentTime - mStartTime), 0, mRampDownDuration);
+            mStopValue = getValueAt(currentTime);
+            mStopTime = currentTime;
+        }
+
+        public boolean isFinished() {
+            return mStopTime > 0
+                    && AnimationUtils.currentAnimationTimeMillis() > mStopTime + mEffectiveRampDown;
+        }
+
+        private float getValueAt(long currentTime) {
+            if (currentTime < mStartTime) {
+                return 0f;
+            } else if (mStopTime < 0 || currentTime < mStopTime) {
+                final long elapsedSinceStart = currentTime - mStartTime;
+                return 0.5f * constrain(elapsedSinceStart / (float) mRampUpDuration, 0, 1);
+            } else {
+                final long elapsedSinceEnd = currentTime - mStopTime;
+                return (1 - mStopValue) + mStopValue
+                        * constrain(elapsedSinceEnd / (float) mEffectiveRampDown, 0, 1);
+            }
+        }
+
+        /**
+         * Interpolates the value along a parabolic curve corresponding to the equation
+         * <code>y = -4x * (x-1)</code>.
+         *
+         * @param value The value to interpolate, between 0 and 1.
+         * @return the interpolated value, between 0 and 1.
+         */
+        private float interpolateValue(float value) {
+            return -4 * value * value + 4 * value;
+        }
+
+        /**
+         * Computes the current scroll deltas. This usually only be called after
+         * starting the scroller with {@link #start()}.
+         *
+         * @see #getDeltaX()
+         * @see #getDeltaY()
+         */
+        public void computeScrollDelta() {
+            if (mDeltaTime == 0) {
+                throw new RuntimeException("Cannot compute scroll delta before calling start()");
+            }
+
+            final long currentTime = AnimationUtils.currentAnimationTimeMillis();
+            final float value = getValueAt(currentTime);
+            final float scale = interpolateValue(value);
+            final long elapsedSinceDelta = currentTime - mDeltaTime;
+
+            mDeltaTime = currentTime;
+            mDeltaX = (int) (elapsedSinceDelta * scale * mTargetVelocityX);
+            mDeltaY = (int) (elapsedSinceDelta * scale * mTargetVelocityY);
+        }
+
+        /**
+         * Sets the target velocity for this scroller.
+         *
+         * @param x The target X velocity in pixels per millisecond.
+         * @param y The target Y velocity in pixels per millisecond.
+         */
+        public void setTargetVelocity(float x, float y) {
+            mTargetVelocityX = x;
+            mTargetVelocityY = y;
+        }
+
+        public int getHorizontalDirection() {
+            return (int) (mTargetVelocityX / Math.abs(mTargetVelocityX));
+        }
+
+        public int getVerticalDirection() {
+            return (int) (mTargetVelocityY / Math.abs(mTargetVelocityY));
+        }
+
+        /**
+         * The distance traveled in the X-coordinate computed by the last call
+         * to {@link #computeScrollDelta()}.
+         */
+        public int getDeltaX() {
+            return mDeltaX;
+        }
+
+        /**
+         * The distance traveled in the Y-coordinate computed by the last call
+         * to {@link #computeScrollDelta()}.
+         */
+        public int getDeltaY() {
+            return mDeltaY;
+        }
+    }
+
+    /**
+     * An implementation of {@link AutoScrollHelper} that knows how to scroll
+     * through an {@link AbsListView}.
+     */
+    public static class AbsListViewAutoScroller extends AutoScrollHelper {
+        private final AbsListView mTarget;
+
+        public AbsListViewAutoScroller(AbsListView target) {
+            super(target);
+
+            mTarget = target;
+        }
+
+        @Override
+        public void scrollTargetBy(int deltaX, int deltaY) {
+            mTarget.scrollListBy(deltaY);
+        }
+
+        @Override
+        public boolean canTargetScrollHorizontally(int direction) {
+            // List do not scroll horizontally.
+            return false;
+        }
+
+        @Override
+        public boolean canTargetScrollVertically(int direction) {
+            final AbsListView target = mTarget;
+            final int itemCount = target.getCount();
+            final int childCount = target.getChildCount();
+            final int firstPosition = target.getFirstVisiblePosition();
+            final int lastPosition = firstPosition + childCount;
+
+            if (direction > 0) {
+                // Are we already showing the entire last item?
+                if (lastPosition >= itemCount) {
+                    final View lastView = target.getChildAt(childCount - 1);
+                    if (lastView.getBottom() <= target.getHeight()) {
+                        return false;
+                    }
+                }
+            } else if (direction < 0) {
+                // Are we already showing the entire first item?
+                if (firstPosition <= 0) {
+                    final View firstView = target.getChildAt(0);
+                    if (firstView.getTop() >= 0) {
+                        return false;
+                    }
+                }
+            } else {
+                // The behavior for direction 0 is undefined and we can return
+                // whatever we want.
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index c72c770..91056f1 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -24,10 +24,10 @@
     boolean getBoolean(in String key, in boolean defaultValue, in int userId);
     long getLong(in String key, in long defaultValue, in int userId);
     String getString(in String key, in String defaultValue, in int userId);
-    void setLockPattern(in byte[] hash, int userId);
-    boolean checkPattern(in byte[] hash, int userId);
-    void setLockPassword(in byte[] hash, int userId);
-    boolean checkPassword(in byte[] hash, int userId);
+    void setLockPattern(in String pattern, int userId);
+    boolean checkPattern(in String pattern, int userId);
+    void setLockPassword(in String password, int userId);
+    boolean checkPassword(in String password, int userId);
     boolean havePattern(int userId);
     boolean havePassword(int userId);
     void removeUser(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d3ead26..8602260 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.Manifest;
 import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetManager;
@@ -31,7 +32,6 @@
 import android.os.UserHandle;
 import android.os.storage.IMountService;
 import android.provider.Settings;
-import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -137,6 +137,7 @@
             = "lockscreen.biometricweakeverchosen";
     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
             = "lockscreen.power_button_instantly_locks";
+    public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
 
     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
 
@@ -149,6 +150,8 @@
     private DevicePolicyManager mDevicePolicyManager;
     private ILockSettings mLockSettingsService;
 
+    private final boolean mMultiUserMode;
+
     // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
     private static volatile int sCurrentUserId = UserHandle.USER_NULL;
 
@@ -170,6 +173,12 @@
     public LockPatternUtils(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
+
+        // If this is being called by the system or by an application like keyguard that
+        // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
+        // mode where calls are for the current user rather than the user of the calling process.
+        mMultiUserMode = context.checkCallingOrSelfPermission(
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
     }
 
     private ILockSettings getLockSettings() {
@@ -264,13 +273,12 @@
     }
 
     private int getCurrentOrCallingUserId() {
-        int callingUid = Binder.getCallingUid();
-        if (callingUid == android.os.Process.SYSTEM_UID) {
+        if (mMultiUserMode) {
             // TODO: This is a little inefficient. See if all users of this are able to
             // handle USER_CURRENT and pass that instead.
             return getCurrentUser();
         } else {
-            return UserHandle.getUserId(callingUid);
+            return UserHandle.getCallingUserId();
         }
     }
 
@@ -283,11 +291,7 @@
     public boolean checkPattern(List<LockPatternView.Cell> pattern) {
         final int userId = getCurrentOrCallingUserId();
         try {
-            final boolean matched = getLockSettings().checkPattern(patternToHash(pattern), userId);
-            if (matched && (userId == UserHandle.USER_OWNER)) {
-                KeyStore.getInstance().password(patternToString(pattern));
-            }
-            return matched;
+            return getLockSettings().checkPattern(patternToString(pattern), userId);
         } catch (RemoteException re) {
             return true;
         }
@@ -302,12 +306,7 @@
     public boolean checkPassword(String password) {
         final int userId = getCurrentOrCallingUserId();
         try {
-            final boolean matched = getLockSettings().checkPassword(passwordToHash(password),
-                    userId);
-            if (matched && (userId == UserHandle.USER_OWNER)) {
-                KeyStore.getInstance().password(password);
-            }
-            return matched;
+            return getLockSettings().checkPassword(password, userId);
         } catch (RemoteException re) {
             return true;
         }
@@ -496,14 +495,10 @@
      * @param isFallback Specifies if this is a fallback to biometric weak
      */
     public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
-        // Compute the hash
-        final byte[] hash = LockPatternUtils.patternToHash(pattern);
         try {
-            getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId());
+            getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
             DevicePolicyManager dpm = getDevicePolicyManager();
-            KeyStore keyStore = KeyStore.getInstance();
             if (pattern != null) {
-                keyStore.password(patternToString(pattern));
                 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
                 if (!isFallback) {
                     deleteGallery();
@@ -519,9 +514,6 @@
                             0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
                 }
             } else {
-                if (keyStore.isEmpty()) {
-                    keyStore.reset();
-                }
                 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
                         0, 0, 0, 0, 0, getCurrentOrCallingUserId());
             }
@@ -628,19 +620,13 @@
      * @param userHandle The userId of the user to change the password for
      */
     public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
-        // Compute the hash
-        final byte[] hash = passwordToHash(password);
         try {
-            getLockSettings().setLockPassword(hash, userHandle);
+            getLockSettings().setLockPassword(password, userHandle);
             DevicePolicyManager dpm = getDevicePolicyManager();
-            KeyStore keyStore = KeyStore.getInstance();
             if (password != null) {
                 if (userHandle == UserHandle.USER_OWNER) {
                     // Update the encryption password.
                     updateEncryptionPassword(password);
-
-                    // Update the keystore password
-                    keyStore.password(password);
                 }
 
                 int computedQuality = computePasswordQuality(password);
@@ -700,6 +686,7 @@
                 if (passwordHistoryLength == 0) {
                     passwordHistory = "";
                 } else {
+                    byte[] hash = passwordToHash(password);
                     passwordHistory = new String(hash) + "," + passwordHistory;
                     // Cut it to contain passwordHistoryLength hashes
                     // and passwordHistoryLength -1 commas.
@@ -709,11 +696,6 @@
                 }
                 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
             } else {
-                // Conditionally reset the keystore if empty. If
-                // non-empty, we are just switching key guard type
-                if (keyStore.isEmpty()) {
-                    keyStore.reset();
-                }
                 dpm.setActivePasswordState(
                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
                         userHandle);
@@ -794,7 +776,7 @@
      * @param pattern the gesture pattern.
      * @return the hash of the pattern in a byte array.
      */
-    private static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
+    public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
         if (pattern == null) {
             return null;
         }
@@ -1045,28 +1027,38 @@
         return nextAlarm;
     }
 
-    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
+    private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
         try {
-            return getLockSettings().getBoolean(secureSettingKey, defaultValue,
-                    getCurrentOrCallingUserId());
+            return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
         } catch (RemoteException re) {
             return defaultValue;
         }
     }
 
-    private void setBoolean(String secureSettingKey, boolean enabled) {
+    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
+        return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
+    }
+
+    private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
         try {
-            getLockSettings().setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
+            getLockSettings().setBoolean(secureSettingKey, enabled, userId);
         } catch (RemoteException re) {
             // What can we do?
             Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
         }
     }
 
+    private void setBoolean(String secureSettingKey, boolean enabled) {
+        setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
+    }
+
     public int[] getAppWidgets() {
+        return getAppWidgets(UserHandle.USER_CURRENT);
+    }
+
+    private int[] getAppWidgets(int userId) {
         String appWidgetIdString = Settings.Secure.getStringForUser(
-                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
-                UserHandle.USER_CURRENT);
+                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
         String delims = ",";
         if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
             String[] appWidgetStringIds = appWidgetIdString.split(delims);
@@ -1268,7 +1260,7 @@
      * @param upperCase if true, converts button label string to upper case
      */
     public void updateEmergencyCallButtonState(Button button, int  phoneState, boolean shown,
-            boolean upperCase, boolean showIcon) {
+            boolean showIcon) {
         if (isEmergencyCallCapable() && shown) {
             button.setVisibility(View.VISIBLE);
         } else {
@@ -1287,23 +1279,7 @@
             int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
             button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
         }
-        if (upperCase) {
-            CharSequence original = mContext.getResources().getText(textId);
-            String upper = original != null ? original.toString().toUpperCase() : null;
-            button.setText(upper);
-        } else {
-            button.setText(textId);
-        }
-    }
-
-    /**
-     * @deprecated
-     * @param button
-     * @param phoneState
-     * @param shown
-     */
-    public void updateEmergencyCallButtonState(Button button, int  phoneState, boolean shown) {
-        updateEmergencyCallButtonState(button, phoneState, shown, false, true);
+        button.setText(textId);
     }
 
     /**
@@ -1353,4 +1329,35 @@
         return false;
     }
 
+    /**
+     * Determine whether the user has selected any non-system widgets in keyguard
+     *
+     * @return true if widgets have been selected
+     */
+    public boolean hasWidgetsEnabledInKeyguard(int userid) {
+        int widgets[] = getAppWidgets(userid);
+        for (int i = 0; i < widgets.length; i++) {
+            if (widgets[i] > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean getWidgetsEnabled() {
+        return getWidgetsEnabled(getCurrentOrCallingUserId());
+    }
+
+    public boolean getWidgetsEnabled(int userId) {
+        return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
+    }
+
+    public void setWidgetsEnabled(boolean enabled) {
+        setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
+    }
+
+    public void setWidgetsEnabled(boolean enabled, int userId) {
+        setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
+    }
+
 }
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index f8332c4..a3df291 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -184,7 +184,7 @@
                 KeyEvent event = events[i];
                 event = KeyEvent.changeFlags(event, event.getFlags()
                         | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
-                viewRootImpl.dispatchKey(event);
+                viewRootImpl.dispatchInputEvent(event);
             }
         }
     }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index f10a2e8..d82831f 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -46,6 +46,7 @@
         // Trace of previous points.
         private float[] mTraceX = new float[32];
         private float[] mTraceY = new float[32];
+        private boolean[] mTraceCurrent = new boolean[32];
         private int mTraceCount;
         
         // True if the pointer is down.
@@ -76,7 +77,7 @@
             mTraceCount = 0;
         }
         
-        public void addTrace(float x, float y) {
+        public void addTrace(float x, float y, boolean current) {
             int traceCapacity = mTraceX.length;
             if (mTraceCount == traceCapacity) {
                 traceCapacity *= 2;
@@ -87,10 +88,15 @@
                 float[] newTraceY = new float[traceCapacity];
                 System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount);
                 mTraceY = newTraceY;
+
+                boolean[] newTraceCurrent = new boolean[traceCapacity];
+                System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount);
+                mTraceCurrent= newTraceCurrent;
             }
             
             mTraceX[mTraceCount] = x;
             mTraceY[mTraceCount] = y;
+            mTraceCurrent[mTraceCount] = current;
             mTraceCount += 1;
         }
     }
@@ -106,6 +112,7 @@
     private final Paint mTextBackgroundPaint;
     private final Paint mTextLevelPaint;
     private final Paint mPaint;
+    private final Paint mCurrentPointPaint;
     private final Paint mTargetPaint;
     private final Paint mPathPaint;
     private final FontMetricsInt mTextMetrics = new FontMetricsInt();
@@ -147,6 +154,11 @@
         mPaint.setARGB(255, 255, 255, 255);
         mPaint.setStyle(Paint.Style.STROKE);
         mPaint.setStrokeWidth(2);
+        mCurrentPointPaint = new Paint();
+        mCurrentPointPaint.setAntiAlias(true);
+        mCurrentPointPaint.setARGB(255, 255, 0, 0);
+        mCurrentPointPaint.setStyle(Paint.Style.STROKE);
+        mCurrentPointPaint.setStrokeWidth(2);
         mTargetPaint = new Paint();
         mTargetPaint.setAntiAlias(false);
         mTargetPaint.setARGB(255, 0, 0, 192);
@@ -294,7 +306,8 @@
                 }
                 if (haveLast) {
                     canvas.drawLine(lastX, lastY, x, y, mPathPaint);
-                    canvas.drawPoint(lastX, lastY, mPaint);
+                    final Paint paint = ps.mTraceCurrent[i] ? mCurrentPointPaint : mPaint;
+                    canvas.drawPoint(lastX, lastY, paint);
                     drawn = true;
                 }
                 lastX = x;
@@ -549,8 +562,9 @@
 
             final PointerState ps = mPointers.get(id);
             ps.mCurDown = true;
-            ps.mHasBoundingBox = (InputDevice.getDevice(event.getDeviceId()).
-                    getMotionRange(MotionEvent.AXIS_GENERIC_1) != null);
+            InputDevice device = InputDevice.getDevice(event.getDeviceId());
+            ps.mHasBoundingBox = device != null &&
+                    device.getMotionRange(MotionEvent.AXIS_GENERIC_1) != null;
         }
 
         final int NI = event.getPointerCount();
@@ -573,7 +587,7 @@
                     logCoords("Pointer", action, i, coords, id, event);
                 }
                 if (ps != null) {
-                    ps.addTrace(coords.x, coords.y);
+                    ps.addTrace(coords.x, coords.y, false);
                 }
             }
         }
@@ -586,7 +600,7 @@
                 logCoords("Pointer", action, i, coords, id, event);
             }
             if (ps != null) {
-                ps.addTrace(coords.x, coords.y);
+                ps.addTrace(coords.x, coords.y, true);
                 ps.mXVelocity = mVelocity.getXVelocity(id);
                 ps.mYVelocity = mVelocity.getYVelocity(id);
                 mVelocity.getEstimator(id, ps.mEstimator);
@@ -625,7 +639,7 @@
                 if (mActivePointerId == id) {
                     mActivePointerId = event.getPointerId(index == 0 ? 1 : 0);
                 }
-                ps.addTrace(Float.NaN, Float.NaN);
+                ps.addTrace(Float.NaN, Float.NaN, false);
             }
         }
 
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
new file mode 100644
index 0000000..e30c1ff
--- /dev/null
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources.Theme;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Join;
+import android.graphics.Paint.Style;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.text.Layout.Alignment;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+
+public class SubtitleView extends View {
+    // Ratio of inner padding to font size.
+    private static final float INNER_PADDING_RATIO = 0.125f;
+
+    // Styled dimensions.
+    private final float mCornerRadius;
+    private final float mOutlineWidth;
+    private final float mShadowRadius;
+    private final float mShadowOffsetX;
+    private final float mShadowOffsetY;
+
+    /** Temporary rectangle used for computing line bounds. */
+    private final RectF mLineBounds = new RectF();
+
+    /** Reusable string builder used for holding text. */
+    private final StringBuilder mText = new StringBuilder();
+
+    private Alignment mAlignment;
+    private TextPaint mTextPaint;
+    private Paint mPaint;
+
+    private int mForegroundColor;
+    private int mBackgroundColor;
+    private int mEdgeColor;
+    private int mEdgeType;
+
+    private boolean mHasMeasurements;
+    private int mLastMeasuredWidth;
+    private StaticLayout mLayout;
+
+    private float mSpacingMult = 1;
+    private float mSpacingAdd = 0;
+    private int mInnerPaddingX = 0;
+
+    public SubtitleView(Context context) {
+        this(context, null);
+    }
+
+    public SubtitleView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SubtitleView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs);
+
+        final Theme theme = context.getTheme();
+        final TypedArray a = theme.obtainStyledAttributes(
+                    attrs, android.R.styleable.TextView, defStyle, 0);
+
+        CharSequence text = "";
+        int textSize = 15;
+
+        final int n = a.getIndexCount();
+        for (int i = 0; i < n; i++) {
+            int attr = a.getIndex(i);
+
+            switch (attr) {
+                case android.R.styleable.TextView_text:
+                    text = a.getText(attr);
+                    break;
+                case android.R.styleable.TextView_lineSpacingExtra:
+                    mSpacingAdd = a.getDimensionPixelSize(attr, (int) mSpacingAdd);
+                    break;
+                case android.R.styleable.TextView_lineSpacingMultiplier:
+                    mSpacingMult = a.getFloat(attr, mSpacingMult);
+                    break;
+                case android.R.styleable.TextAppearance_textSize:
+                    textSize = a.getDimensionPixelSize(attr, textSize);
+                    break;
+            }
+        }
+
+        // Set up density-dependent properties.
+        // TODO: Move these to a default style.
+        final Resources res = getContext().getResources();
+        final DisplayMetrics m = res.getDisplayMetrics();
+        mCornerRadius = res.getDimension(com.android.internal.R.dimen.subtitle_corner_radius);
+        mOutlineWidth = res.getDimension(com.android.internal.R.dimen.subtitle_outline_width);
+        mShadowRadius = res.getDimension(com.android.internal.R.dimen.subtitle_shadow_radius);
+        mShadowOffsetX = res.getDimension(com.android.internal.R.dimen.subtitle_shadow_offset);
+        mShadowOffsetY = mShadowOffsetX;
+
+        mTextPaint = new TextPaint();
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setSubpixelText(true);
+
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+
+        setText(text);
+        setTextSize(textSize);
+    }
+
+    public void setText(int resId) {
+        final CharSequence text = getContext().getText(resId);
+        setText(text);
+    }
+
+    public void setText(CharSequence text) {
+        mText.setLength(0);
+        mText.append(text);
+
+        mHasMeasurements = false;
+
+        requestLayout();
+    }
+
+    public void setForegroundColor(int color) {
+        mForegroundColor = color;
+
+        invalidate();
+    }
+
+    @Override
+    public void setBackgroundColor(int color) {
+        mBackgroundColor = color;
+
+        invalidate();
+    }
+
+    public void setEdgeType(int edgeType) {
+        mEdgeType = edgeType;
+
+        invalidate();
+    }
+
+    public void setEdgeColor(int color) {
+        mEdgeColor = color;
+
+        invalidate();
+    }
+
+    public void setTextSize(float size) {
+        final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+        final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics);
+        if (mTextPaint.getTextSize() != size) {
+            mTextPaint.setTextSize(size);
+            mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
+
+            mHasMeasurements = false;
+            forceLayout();
+        }
+    }
+
+    public void setTypeface(Typeface typeface) {
+        if (mTextPaint.getTypeface() != typeface) {
+            mTextPaint.setTypeface(typeface);
+
+            mHasMeasurements = false;
+            forceLayout();
+        }
+    }
+
+    public void setAlignment(Alignment textAlignment) {
+        if (mAlignment != textAlignment) {
+            mAlignment = textAlignment;
+
+            mHasMeasurements = false;
+            forceLayout();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthSpec = MeasureSpec.getSize(widthMeasureSpec);
+
+        if (computeMeasurements(widthSpec)) {
+            final StaticLayout layout = mLayout;
+
+            // Account for padding.
+            final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
+            final int width = layout.getWidth() + paddingX;
+            final int height = layout.getHeight() + mPaddingTop + mPaddingBottom;
+            setMeasuredDimension(width, height);
+        } else {
+            setMeasuredDimension(MEASURED_STATE_TOO_SMALL, MEASURED_STATE_TOO_SMALL);
+        }
+    }
+
+    @Override
+    public void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int width = r - l;
+
+        computeMeasurements(width);
+    }
+
+    private boolean computeMeasurements(int maxWidth) {
+        if (mHasMeasurements && maxWidth == mLastMeasuredWidth) {
+            return true;
+        }
+
+        // Account for padding.
+        final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
+        maxWidth -= paddingX;
+        if (maxWidth <= 0) {
+            return false;
+        }
+
+        // TODO: Implement minimum-difference line wrapping. Adding the results
+        // of Paint.getTextWidths() seems to return different values than
+        // StaticLayout.getWidth(), so this is non-trivial.
+        mHasMeasurements = true;
+        mLastMeasuredWidth = maxWidth;
+        mLayout = new StaticLayout(
+                mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true);
+
+        return true;
+    }
+
+    public void setStyle(int styleId) {
+        final Context context = mContext;
+        final ContentResolver cr = context.getContentResolver();
+        final CaptionStyle style;
+        if (styleId == CaptionStyle.PRESET_CUSTOM) {
+            style = CaptionStyle.getCustomStyle(cr);
+        } else {
+            style = CaptionStyle.PRESETS[styleId];
+        }
+
+        mForegroundColor = style.foregroundColor;
+        mBackgroundColor = style.backgroundColor;
+        mEdgeType = style.edgeType;
+        mEdgeColor = style.edgeColor;
+        mHasMeasurements = false;
+
+        final Typeface typeface = style.getTypeface();
+        setTypeface(typeface);
+
+        requestLayout();
+    }
+
+    @Override
+    protected void onDraw(Canvas c) {
+        final StaticLayout layout = mLayout;
+        if (layout == null) {
+            return;
+        }
+
+        final int saveCount = c.save();
+        final int innerPaddingX = mInnerPaddingX;
+        c.translate(mPaddingLeft + innerPaddingX, mPaddingTop);
+
+        final int lineCount = layout.getLineCount();
+        final Paint textPaint = mTextPaint;
+        final Paint paint = mPaint;
+        final RectF bounds = mLineBounds;
+
+        if (Color.alpha(mBackgroundColor) > 0) {
+            final float cornerRadius = mCornerRadius;
+            float previousBottom = layout.getLineTop(0);
+
+            paint.setColor(mBackgroundColor);
+            paint.setStyle(Style.FILL);
+
+            for (int i = 0; i < lineCount; i++) {
+                bounds.left = layout.getLineLeft(i) -innerPaddingX;
+                bounds.right = layout.getLineRight(i) + innerPaddingX;
+                bounds.top = previousBottom;
+                bounds.bottom = layout.getLineBottom(i);
+                previousBottom = bounds.bottom;
+
+                c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
+            }
+        }
+
+        if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+            textPaint.setStrokeJoin(Join.ROUND);
+            textPaint.setStrokeWidth(mOutlineWidth);
+            textPaint.setColor(mEdgeColor);
+            textPaint.setStyle(Style.FILL_AND_STROKE);
+
+            for (int i = 0; i < lineCount; i++) {
+                layout.drawText(c, i, i);
+            }
+        } else if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+            textPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
+        }
+
+        textPaint.setColor(mForegroundColor);
+        textPaint.setStyle(Style.FILL);
+
+        for (int i = 0; i < lineCount; i++) {
+            layout.drawText(c, i, i);
+        }
+
+        textPaint.setShadowLayer(0, 0, 0, 0);
+        c.restoreToCount(saveCount);
+    }
+}
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
deleted file mode 100644
index ca797eb..0000000
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.widget;
-
-import java.lang.ref.WeakReference;
-
-import com.android.internal.widget.LockScreenWidgetCallback;
-import com.android.internal.widget.LockScreenWidgetInterface;
-
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.media.AudioManager;
-import android.media.MediaMetadataRetriever;
-import android.media.RemoteControlClient;
-import android.media.IRemoteControlDisplay;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.text.style.ForegroundColorSpan;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-
-import com.android.internal.R;
-
-public class TransportControlView extends FrameLayout implements OnClickListener,
-        LockScreenWidgetInterface {
-
-    private static final int MSG_UPDATE_STATE = 100;
-    private static final int MSG_SET_METADATA = 101;
-    private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
-    private static final int MSG_SET_ARTWORK = 103;
-    private static final int MSG_SET_GENERATION_ID = 104;
-    private static final int MAXDIM = 512;
-    private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
-    protected static final boolean DEBUG = false;
-    protected static final String TAG = "TransportControlView";
-
-    private ImageView mAlbumArt;
-    private TextView mTrackTitle;
-    private ImageView mBtnPrev;
-    private ImageView mBtnPlay;
-    private ImageView mBtnNext;
-    private int mClientGeneration;
-    private Metadata mMetadata = new Metadata();
-    private boolean mAttached;
-    private PendingIntent mClientIntent;
-    private int mTransportControlFlags;
-    private int mCurrentPlayState;
-    private AudioManager mAudioManager;
-    private LockScreenWidgetCallback mWidgetCallbacks;
-    private IRemoteControlDisplayWeak mIRCD;
-
-    /**
-     * The metadata which should be populated into the view once we've been attached
-     */
-    private Bundle mPopulateMetadataWhenAttached = null;
-
-    // This handler is required to ensure messages from IRCD are handled in sequence and on
-    // the UI thread.
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case MSG_UPDATE_STATE:
-                if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2);
-                break;
-
-            case MSG_SET_METADATA:
-                if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj);
-                break;
-
-            case MSG_SET_TRANSPORT_CONTROLS:
-                if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2);
-                break;
-
-            case MSG_SET_ARTWORK:
-                if (mClientGeneration == msg.arg1) {
-                    if (mMetadata.bitmap != null) {
-                        mMetadata.bitmap.recycle();
-                    }
-                    mMetadata.bitmap = (Bitmap) msg.obj;
-                    mAlbumArt.setImageBitmap(mMetadata.bitmap);
-                }
-                break;
-
-            case MSG_SET_GENERATION_ID:
-                if (msg.arg2 != 0) {
-                    // This means nobody is currently registered. Hide the view.
-                    if (mWidgetCallbacks != null) {
-                        mWidgetCallbacks.requestHide(TransportControlView.this);
-                    }
-                }
-                if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
-                mClientGeneration = msg.arg1;
-                mClientIntent = (PendingIntent) msg.obj;
-                break;
-
-            }
-        }
-    };
-
-    /**
-     * This class is required to have weak linkage to the current TransportControlView
-     * because the remote process can hold a strong reference to this binder object and
-     * we can't predict when it will be GC'd in the remote process. Without this code, it
-     * would allow a heavyweight object to be held on this side of the binder when there's
-     * no requirement to run a GC on the other side.
-     */
-    private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub {
-        private WeakReference<Handler> mLocalHandler;
-
-        IRemoteControlDisplayWeak(Handler handler) {
-            mLocalHandler = new WeakReference<Handler>(handler);
-        }
-
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
-                long currentPosMs, float speed) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
-            }
-        }
-
-        public void setMetadata(int generationId, Bundle metadata) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
-            }
-        }
-
-        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
-                        .sendToTarget();
-            }
-        }
-
-        public void setArtwork(int generationId, Bitmap bitmap) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
-            }
-        }
-
-        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
-                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
-            }
-        }
-
-        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
-                boolean clearing) throws RemoteException {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_GENERATION_ID,
-                    clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
-            }
-        }
-    };
-
-    public TransportControlView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        if (DEBUG) Log.v(TAG, "Create TCV " + this);
-        mAudioManager = new AudioManager(mContext);
-        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
-        mIRCD = new IRemoteControlDisplayWeak(mHandler);
-    }
-
-    private void updateTransportControls(int transportControlFlags) {
-        mTransportControlFlags = transportControlFlags;
-    }
-
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-        mTrackTitle = (TextView) findViewById(R.id.title);
-        mTrackTitle.setSelected(true); // enable marquee
-        mAlbumArt = (ImageView) findViewById(R.id.albumart);
-        mBtnPrev = (ImageView) findViewById(R.id.btn_prev);
-        mBtnPlay = (ImageView) findViewById(R.id.btn_play);
-        mBtnNext = (ImageView) findViewById(R.id.btn_next);
-        final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext };
-        for (View view : buttons) {
-            view.setOnClickListener(this);
-        }
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mPopulateMetadataWhenAttached != null) {
-            updateMetadata(mPopulateMetadataWhenAttached);
-            mPopulateMetadataWhenAttached = null;
-        }
-        if (!mAttached) {
-            if (DEBUG) Log.v(TAG, "Registering TCV " + this);
-            mAudioManager.registerRemoteControlDisplay(mIRCD);
-        }
-        mAttached = true;
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mAttached) {
-            if (DEBUG) Log.v(TAG, "Unregistering TCV " + this);
-            mAudioManager.unregisterRemoteControlDisplay(mIRCD);
-        }
-        mAttached = false;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight()));
-//        Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim);
-//        mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
-    }
-
-    class Metadata {
-        private String artist;
-        private String trackTitle;
-        private String albumTitle;
-        private Bitmap bitmap;
-
-        public String toString() {
-            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]";
-        }
-    }
-
-    private String getMdString(Bundle data, int id) {
-        return data.getString(Integer.toString(id));
-    }
-
-    private void updateMetadata(Bundle data) {
-        if (mAttached) {
-            mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
-            mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE);
-            mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM);
-            populateMetadata();
-        } else {
-            mPopulateMetadataWhenAttached = data;
-        }
-    }
-
-    /**
-     * Populates the given metadata into the view
-     */
-    private void populateMetadata() {
-        StringBuilder sb = new StringBuilder();
-        int trackTitleLength = 0;
-        if (!TextUtils.isEmpty(mMetadata.trackTitle)) {
-            sb.append(mMetadata.trackTitle);
-            trackTitleLength = mMetadata.trackTitle.length();
-        }
-        if (!TextUtils.isEmpty(mMetadata.artist)) {
-            if (sb.length() != 0) {
-                sb.append(" - ");
-            }
-            sb.append(mMetadata.artist);
-        }
-        if (!TextUtils.isEmpty(mMetadata.albumTitle)) {
-            if (sb.length() != 0) {
-                sb.append(" - ");
-            }
-            sb.append(mMetadata.albumTitle);
-        }
-        mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE);
-        Spannable str = (Spannable) mTrackTitle.getText();
-        if (trackTitleLength != 0) {
-            str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength,
-                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            trackTitleLength++;
-        }
-        if (sb.length() > trackTitleLength) {
-            str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(),
-                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-        }
-
-        mAlbumArt.setImageBitmap(mMetadata.bitmap);
-        final int flags = mTransportControlFlags;
-        setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
-        setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
-        setVisibilityBasedOnFlag(mBtnPlay, flags,
-                RemoteControlClient.FLAG_KEY_MEDIA_PLAY
-                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
-                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
-                | RemoteControlClient.FLAG_KEY_MEDIA_STOP);
-
-        updatePlayPauseState(mCurrentPlayState);
-    }
-
-    private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
-        if ((flags & flag) != 0) {
-            view.setVisibility(View.VISIBLE);
-        } else {
-            view.setVisibility(View.GONE);
-        }
-    }
-
-    private void updatePlayPauseState(int state) {
-        if (DEBUG) Log.v(TAG,
-                "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
-        if (state == mCurrentPlayState) {
-            return;
-        }
-        final int imageResId;
-        final int imageDescId;
-        boolean showIfHidden = false;
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                imageResId = com.android.internal.R.drawable.stat_sys_warning;
-                // TODO use more specific image description string for warning, but here the "play"
-                //      message is still valid because this button triggers a play command.
-                imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-                imageResId = com.android.internal.R.drawable.ic_media_pause;
-                imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
-                showIfHidden = true;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                imageResId = com.android.internal.R.drawable.ic_media_stop;
-                imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
-                showIfHidden = true;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            default:
-                imageResId = com.android.internal.R.drawable.ic_media_play;
-                imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
-                showIfHidden = false;
-                break;
-        }
-        mBtnPlay.setImageResource(imageResId);
-        mBtnPlay.setContentDescription(getResources().getString(imageDescId));
-        if (showIfHidden && mWidgetCallbacks != null && !mWidgetCallbacks.isVisible(this)) {
-            mWidgetCallbacks.requestShow(this);
-        }
-        mCurrentPlayState = state;
-    }
-
-    static class SavedState extends BaseSavedState {
-        boolean wasShowing;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            this.wasShowing = in.readInt() != 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(this.wasShowing ? 1 : 0);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-        ss.wasShowing = mWidgetCallbacks != null && mWidgetCallbacks.isVisible(this);
-        return ss;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-        if (ss.wasShowing && mWidgetCallbacks != null) {
-            mWidgetCallbacks.requestShow(this);
-        }
-    }
-
-    public void onClick(View v) {
-        int keyCode = -1;
-        if (v == mBtnPrev) {
-            keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
-        } else if (v == mBtnNext) {
-            keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
-        } else if (v == mBtnPlay) {
-            keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
-
-        }
-        if (keyCode != -1) {
-            sendMediaButtonClick(keyCode);
-            if (mWidgetCallbacks != null) {
-                mWidgetCallbacks.userActivity(this);
-            }
-        }
-    }
-
-    private void sendMediaButtonClick(int keyCode) {
-        if (mClientIntent == null) {
-            // Shouldn't be possible because this view should be hidden in this case.
-            Log.e(TAG, "sendMediaButtonClick(): No client is currently registered");
-            return;
-        }
-        // use the registered PendingIntent that will be processed by the registered
-        //    media button event receiver, which is the component of mClientIntent
-        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
-        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        try {
-            mClientIntent.send(getContext(), 0, intent);
-        } catch (CanceledException e) {
-            Log.e(TAG, "Error sending intent for media button down: "+e);
-            e.printStackTrace();
-        }
-
-        keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
-        intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        try {
-            mClientIntent.send(getContext(), 0, intent);
-        } catch (CanceledException e) {
-            Log.e(TAG, "Error sending intent for media button up: "+e);
-            e.printStackTrace();
-        }
-    }
-
-    public void setCallback(LockScreenWidgetCallback callback) {
-        mWidgetCallbacks = callback;
-    }
-
-    public boolean providesClock() {
-        return false;
-    }
-
-    private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                // actively playing or about to play
-                return true;
-            case RemoteControlClient.PLAYSTATE_NONE:
-                return false;
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                // we have stopped playing, check how long ago
-                if (DEBUG) {
-                    if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
-                        Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
-                    } else {
-                        Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
-                    }
-                }
-                return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
-            default:
-                Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
-                return false;
-        }
-    }
-}
diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
index 30f5f2f..16bec16 100644
--- a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
+++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
@@ -46,36 +46,6 @@
     private boolean mEnabled = true;
     private final int mResourceId;
 
-    /* package */ static class DrawableWithAlpha extends Drawable {
-        private float mAlpha = 1.0f;
-        private Drawable mRealDrawable;
-        public DrawableWithAlpha(Drawable realDrawable) {
-            mRealDrawable = realDrawable;
-        }
-        public void setAlpha(float alpha) {
-            mAlpha = alpha;
-        }
-        public float getAlpha() {
-            return mAlpha;
-        }
-        public void draw(Canvas canvas) {
-            mRealDrawable.setAlpha((int) Math.round(mAlpha * 255f));
-            mRealDrawable.draw(canvas);
-        }
-        @Override
-        public void setAlpha(int alpha) {
-            mRealDrawable.setAlpha(alpha);
-        }
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-            mRealDrawable.setColorFilter(cf);
-        }
-        @Override
-        public int getOpacity() {
-            return mRealDrawable.getOpacity();
-        }
-    }
-
     public TargetDrawable(Resources res, int resId) {
         mResourceId = resId;
         setDrawable(res, resId);
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
new file mode 100644
index 0000000..fa54c5f
--- /dev/null
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package com.android.server.net;
+
+import android.net.INetworkManagementEventObserver;
+
+/**
+ * Base {@link INetworkManagementEventObserver} that provides no-op
+ * implementations which can be overridden.
+ *
+ * @hide
+ */
+public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub {
+    @Override
+    public void interfaceStatusChanged(String iface, boolean up) {
+        // default no-op
+    }
+
+    @Override
+    public void interfaceRemoved(String iface) {
+        // default no-op
+    }
+
+    @Override
+    public void addressUpdated(String address, String iface, int flags, int scope) {
+        // default no-op
+    }
+
+    @Override
+    public void addressRemoved(String address, String iface, int flags, int scope) {
+        // default no-op
+    }
+
+    @Override
+    public void interfaceLinkStateChanged(String iface, boolean up) {
+        // default no-op
+    }
+
+    @Override
+    public void interfaceAdded(String iface) {
+        // default no-op
+    }
+
+    @Override
+    public void interfaceClassDataActivityChanged(String label, boolean active) {
+        // default no-op
+    }
+
+    @Override
+    public void limitReached(String limitName, String iface) {
+        // default no-op
+    }
+}
diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java
index d537e0c..fc2c9fe 100644
--- a/core/java/com/google/android/collect/Maps.java
+++ b/core/java/com/google/android/collect/Maps.java
@@ -16,6 +16,8 @@
 
 package com.google.android.collect;
 
+import android.util.ArrayMap;
+
 import java.util.HashMap;
 
 /**
@@ -30,4 +32,11 @@
     public static <K, V> HashMap<K, V> newHashMap() {
         return new HashMap<K, V>();
     }
+
+    /**
+     * Creates a {@code ArrayMap} instance.
+     */
+    public static <K, V> ArrayMap<K, V> newArrayMap() {
+        return new ArrayMap<K, V>();
+    }
 }
diff --git a/core/java/com/google/android/collect/Sets.java b/core/java/com/google/android/collect/Sets.java
index fbfbe50..dd3cab1 100644
--- a/core/java/com/google/android/collect/Sets.java
+++ b/core/java/com/google/android/collect/Sets.java
@@ -16,6 +16,8 @@
 
 package com.google.android.collect;
 
+import android.util.ArraySet;
+
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
@@ -90,4 +92,20 @@
         return set;
     }
 
+    /**
+     * Creates a {@code ArraySet} instance.
+     */
+    public static <E> ArraySet<E> newArraySet() {
+        return new ArraySet<E>();
+    }
+
+    /**
+     * Creates a {@code ArraySet} instance containing the given elements.
+     */
+    public static <E> ArraySet<E> newArraySet(E... elements) {
+        int capacity = elements.length * 4 / 3 + 1;
+        ArraySet<E> set = new ArraySet<E>(capacity);
+        Collections.addAll(set, elements);
+        return set;
+    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 337c1ec..e09fcff 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -51,6 +51,7 @@
 	android_view_KeyEvent.cpp \
 	android_view_KeyCharacterMap.cpp \
 	android_view_HardwareRenderer.cpp \
+	android_view_GraphicBuffer.cpp \
 	android_view_GLES20DisplayList.cpp \
 	android_view_GLES20Canvas.cpp \
 	android_view_MotionEvent.cpp \
@@ -62,7 +63,6 @@
 	android_os_FileUtils.cpp \
 	android_os_MemoryFile.cpp \
 	android_os_MessageQueue.cpp \
-	android_os_ParcelFileDescriptor.cpp \
 	android_os_Parcel.cpp \
 	android_os_SELinux.cpp \
 	android_os_SystemClock.cpp \
@@ -72,7 +72,7 @@
 	android_net_LocalSocketImpl.cpp \
 	android_net_NetUtils.cpp \
 	android_net_TrafficStats.cpp \
-	android_net_wifi_Wifi.cpp \
+	android_net_wifi_WifiNative.cpp \
 	android_nio_utils.cpp \
 	android_text_format_Time.cpp \
 	android_util_AssetManager.cpp \
@@ -105,7 +105,6 @@
 	android/graphics/Path.cpp \
 	android/graphics/PathMeasure.cpp \
 	android/graphics/PathEffect.cpp \
-	android_graphics_PixelFormat.cpp \
 	android/graphics/Picture.cpp \
 	android/graphics/PorterDuff.cpp \
 	android/graphics/BitmapRegionDecoder.cpp \
@@ -119,6 +118,7 @@
 	android/graphics/Utils.cpp \
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
+	android/graphics/pdf/PdfDocument.cpp \
 	android_media_AudioRecord.cpp \
 	android_media_AudioSystem.cpp \
 	android_media_AudioTrack.cpp \
@@ -126,6 +126,7 @@
 	android_media_RemoteDisplay.cpp \
 	android_media_ToneGenerator.cpp \
 	android_hardware_Camera.cpp \
+	android_hardware_camera2_CameraMetadata.cpp \
 	android_hardware_SensorManager.cpp \
 	android_hardware_SerialPort.cpp \
 	android_hardware_UsbDevice.cpp \
@@ -158,11 +159,9 @@
 	$(call include-path-for, libhardware)/hardware \
 	$(call include-path-for, libhardware_legacy)/hardware_legacy \
 	$(TOP)/frameworks/av/include \
-	external/skia/include/core \
-	external/skia/include/effects \
-	external/skia/include/images \
-	external/skia/include/ports \
+	$(TOP)/system/media/camera/include \
 	external/skia/src/core \
+	external/skia/src/pdf \
 	external/skia/src/images \
 	external/skia/include/utils \
 	external/sqlite/dist \
@@ -179,6 +178,7 @@
 	libcore/include
 
 LOCAL_SHARED_LIBRARIES := \
+	libmemtrack \
 	libandroidfw \
 	libexpat \
 	libnativehelper \
@@ -189,10 +189,11 @@
 	libnetutils \
 	libui \
 	libgui \
+	libinput \
 	libcamera_client \
+	libcamera_metadata \
 	libskia \
 	libsqlite \
-	libdvm \
 	libEGL \
 	libGLESv1_CM \
 	libGLESv2 \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index cc58c65..8518101 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -24,7 +24,6 @@
 #include <utils/Log.h>
 #include <utils/misc.h>
 #include <binder/Parcel.h>
-#include <utils/StringArray.h>
 #include <utils/threads.h>
 #include <cutils/properties.h>
 
@@ -34,6 +33,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+#include "JniInvocation.h"
 #include "android_util_Binder.h"
 
 #include <stdio.h>
@@ -53,6 +53,7 @@
 extern int register_android_graphics_BitmapFactory(JNIEnv*);
 extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
 extern int register_android_graphics_Camera(JNIEnv* env);
+extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
 extern int register_android_graphics_Graphics(JNIEnv* env);
 extern int register_android_graphics_Interpolator(JNIEnv* env);
 extern int register_android_graphics_LayerRasterizer(JNIEnv*);
@@ -76,6 +77,7 @@
 extern int register_android_opengl_jni_GLES30(JNIEnv* env);
 
 extern int register_android_hardware_Camera(JNIEnv *env);
+extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
 extern int register_android_hardware_SensorManager(JNIEnv *env);
 extern int register_android_hardware_SerialPort(JNIEnv *env);
 extern int register_android_hardware_UsbDevice(JNIEnv *env);
@@ -115,8 +117,9 @@
 extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
 extern int register_android_graphics_Xfermode(JNIEnv* env);
-extern int register_android_graphics_PixelFormat(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
+extern int register_android_view_GraphicBuffer(JNIEnv* env);
 extern int register_android_view_GLES20DisplayList(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_HardwareRenderer(JNIEnv* env);
@@ -134,7 +137,6 @@
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_MessageQueue(JNIEnv* env);
 extern int register_android_os_Parcel(JNIEnv* env);
-extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
 extern int register_android_os_SELinux(JNIEnv* env);
 extern int register_android_os_SystemProperties(JNIEnv *env);
 extern int register_android_os_SystemClock(JNIEnv* env);
@@ -146,7 +148,7 @@
 extern int register_android_net_LocalSocketImpl(JNIEnv* env);
 extern int register_android_net_NetworkUtils(JNIEnv* env);
 extern int register_android_net_TrafficStats(JNIEnv* env);
-extern int register_android_net_wifi_WifiManager(JNIEnv* env);
+extern int register_android_net_wifi_WifiNative(JNIEnv* env);
 extern int register_android_text_AndroidCharacter(JNIEnv *env);
 extern int register_android_text_AndroidBidi(JNIEnv *env);
 extern int register_android_opengl_classes(JNIEnv *env);
@@ -447,6 +449,7 @@
     char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
     char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
+    char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
     char extraOptsBuf[PROPERTY_VALUE_MAX];
     char* stackTraceFile = NULL;
     bool checkJni = false;
@@ -538,6 +541,14 @@
     opt.optionString = "-XX:mainThreadStackSize=24K";
     mOptions.add(opt);
 
+    // Set the max jit code cache size.  Note: size of 0 will disable the JIT.
+    strcpy(jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
+    property_get("dalvik.vm.jit.codecachesize", jitcodecachesizeOptsBuf+19,  NULL);
+    if (jitcodecachesizeOptsBuf[19] != '\0') {
+      opt.optionString = jitcodecachesizeOptsBuf;
+      mOptions.add(opt);
+    }
+
     strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
     property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");
     if (heapgrowthlimitOptsBuf[20] != '\0') {
@@ -566,6 +577,12 @@
         mOptions.add(opt);
     }
 
+    property_get("ro.config.low_ram", propBuf, "");
+    if (strcmp(propBuf, "true") == 0) {
+      opt.optionString = "-XX:LowMemoryMode";
+      mOptions.add(opt);
+    }
+
     /*
      * Enable or disable dexopt features, such as bytecode verification and
      * calculation of register maps for precise GC.
@@ -816,6 +833,8 @@
     //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
 
     /* start the virtual machine */
+    JniInvocation jni_invocation;
+    jni_invocation.Init(NULL);
     JNIEnv* env;
     if (startVm(&mJavaVM, &env) != 0) {
         return;
@@ -1095,8 +1114,8 @@
     REG_JNI(register_android_os_Parcel),
     REG_JNI(register_android_view_DisplayEventReceiver),
     REG_JNI(register_android_nio_utils),
-    REG_JNI(register_android_graphics_PixelFormat),
     REG_JNI(register_android_graphics_Graphics),
+    REG_JNI(register_android_view_GraphicBuffer),
     REG_JNI(register_android_view_GLES20DisplayList),
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_HardwareRenderer),
@@ -1119,6 +1138,7 @@
     REG_JNI(register_android_graphics_BitmapFactory),
     REG_JNI(register_android_graphics_BitmapRegionDecoder),
     REG_JNI(register_android_graphics_Camera),
+    REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
     REG_JNI(register_android_graphics_Canvas),
     REG_JNI(register_android_graphics_ColorFilter),
     REG_JNI(register_android_graphics_DrawFilter),
@@ -1141,6 +1161,7 @@
     REG_JNI(register_android_graphics_Typeface),
     REG_JNI(register_android_graphics_Xfermode),
     REG_JNI(register_android_graphics_YuvImage),
+    REG_JNI(register_android_graphics_pdf_PdfDocument),
 
     REG_JNI(register_android_database_CursorWindow),
     REG_JNI(register_android_database_SQLiteConnection),
@@ -1150,17 +1171,17 @@
     REG_JNI(register_android_os_FileObserver),
     REG_JNI(register_android_os_FileUtils),
     REG_JNI(register_android_os_MessageQueue),
-    REG_JNI(register_android_os_ParcelFileDescriptor),
     REG_JNI(register_android_os_SELinux),
     REG_JNI(register_android_os_Trace),
     REG_JNI(register_android_os_UEventObserver),
     REG_JNI(register_android_net_LocalSocketImpl),
     REG_JNI(register_android_net_NetworkUtils),
     REG_JNI(register_android_net_TrafficStats),
-    REG_JNI(register_android_net_wifi_WifiManager),
+    REG_JNI(register_android_net_wifi_WifiNative),
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_android_hardware_Camera),
+    REG_JNI(register_android_hardware_camera2_CameraMetadata),
     REG_JNI(register_android_hardware_SensorManager),
     REG_JNI(register_android_hardware_SerialPort),
     REG_JNI(register_android_hardware_UsbDevice),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 63683b4..eea9ee1 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -5,6 +5,7 @@
 #include "GraphicsJNI.h"

 #include "SkDither.h"

 #include "SkUnPreMultiply.h"

+#include "SkStream.h"

 

 #include <binder/Parcel.h>

 #include "android_os_Parcel.h"

@@ -38,6 +39,23 @@
     }

 }

 

+static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,

+                          int, int) {

+    // SkColor's ordering may be different from SkPMColor

+    if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {

+        memcpy(dst, src, width * sizeof(SkColor));

+        return;

+    }

+

+    // order isn't same, repack each pixel manually

+    SkPMColor* d = (SkPMColor*)dst;

+    for (int i = 0; i < width; i++) {

+        SkColor c = *src++;

+        *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),

+                                   SkColorGetG(c), SkColorGetB(c));

+    }

+}

+

 static void FromColor_D565(void* dst, const SkColor src[], int width,

                            int x, int y) {

     uint16_t* d = (uint16_t*)dst;

@@ -56,19 +74,35 @@
 

     DITHER_4444_SCAN(y);

     for (int stop = x + width; x < stop; x++) {

-        SkPMColor c = SkPreMultiplyColor(*src++);

-        *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));

-//        *d++ = SkPixel32ToPixel4444(c);

+        SkPMColor pmc = SkPreMultiplyColor(*src++);

+        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));

+//        *d++ = SkPixel32ToPixel4444(pmc);

+    }

+}

+

+static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,

+                            int x, int y) {

+    SkPMColor16* d = (SkPMColor16*)dst;

+

+    DITHER_4444_SCAN(y);

+    for (int stop = x + width; x < stop; x++) {

+        SkColor c = *src++;

+

+        // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied

+        SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),

+                                            SkColorGetG(c), SkColorGetB(c));

+        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));

+//        *d++ = SkPixel32ToPixel4444(pmc);

     }

 }

 

 // can return NULL

-static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {

+static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {

     switch (config) {

         case SkBitmap::kARGB_8888_Config:

-            return FromColor_D32;

+            return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;

         case SkBitmap::kARGB_4444_Config:

-            return FromColor_D4444;

+            return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;

         case SkBitmap::kRGB_565_Config:

             return FromColor_D565;

         default:

@@ -77,13 +111,12 @@
     return NULL;

 }

 

-bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,

-                            int srcOffset, int srcStride,

-                            int x, int y, int width, int height,

-                            const SkBitmap& dstBitmap) {

+bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,

+        int x, int y, int width, int height,

+        const SkBitmap& dstBitmap, bool isPremultiplied) {

     SkAutoLockPixels alp(dstBitmap);

     void* dst = dstBitmap.getPixels();

-    FromColorProc proc = ChooseFromColorProc(dstBitmap.config());

+    FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);

 

     if (NULL == dst || NULL == proc) {

         return false;

@@ -122,6 +155,17 @@
     } while (--width != 0);

 }

 

+static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,

+                              SkColorTable*) {

+    SkASSERT(width > 0);

+    const SkPMColor* s = (const SkPMColor*)src;

+    do {

+        SkPMColor c = *s++;

+        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),

+                                SkGetPackedG32(c), SkGetPackedB32(c));

+    } while (--width != 0);

+}

+

 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,

                                SkColorTable*) {

     SkASSERT(width > 0);

@@ -142,6 +186,17 @@
     } while (--width != 0);

 }

 

+static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,

+                                SkColorTable*) {

+    SkASSERT(width > 0);

+    const SkPMColor16* s = (const SkPMColor16*)src;

+    do {

+        SkPMColor c = SkPixel4444ToPixel32(*s++);

+        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),

+                                SkGetPackedG32(c), SkGetPackedB32(c));

+    } while (--width != 0);

+}

+

 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,

                                  SkColorTable*) {

     SkASSERT(width > 0);

@@ -175,6 +230,19 @@
     ctable->unlockColors(false);

 }

 

+static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,

+                              SkColorTable* ctable) {

+    SkASSERT(width > 0);

+    const uint8_t* s = (const uint8_t*)src;

+    const SkPMColor* colors = ctable->lockColors();

+    do {

+        SkPMColor c = colors[*s++];

+        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),

+                                SkGetPackedG32(c), SkGetPackedB32(c));

+    } while (--width != 0);

+    ctable->unlockColors(false);

+}

+

 static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,

                                SkColorTable* ctable) {

     SkASSERT(width > 0);

@@ -189,19 +257,22 @@
 }

 

 // can return NULL

-static ToColorProc ChooseToColorProc(const SkBitmap& src) {

+static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {

     switch (src.config()) {

         case SkBitmap::kARGB_8888_Config:

-            return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;

+            if (src.isOpaque()) return ToColor_S32_Opaque;

+            return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;

         case SkBitmap::kARGB_4444_Config:

-            return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;

+            if (src.isOpaque()) return ToColor_S4444_Opaque;

+            return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;

         case SkBitmap::kRGB_565_Config:

             return ToColor_S565;

         case SkBitmap::kIndex8_Config:

             if (src.getColorTable() == NULL) {

                 return NULL;

             }

-            return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;

+            if (src.isOpaque()) return ToColor_SI8_Opaque;

+            return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;

         default:

             break;

     }

@@ -211,6 +282,12 @@
 ///////////////////////////////////////////////////////////////////////////////

 ///////////////////////////////////////////////////////////////////////////////

 

+static int getPremulBitmapCreateFlags(bool isMutable) {

+    int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;

+    if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;

+    return flags;

+}

+

 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,

                               int offset, int stride, int width, int height,

                               SkBitmap::Config config, jboolean isMutable) {

@@ -222,8 +299,12 @@
         }

     }

 

-    SkBitmap bitmap;

+    // ARGB_4444 is a deprecated format, convert automatically to 8888

+    if (config == SkBitmap::kARGB_4444_Config) {

+        config = SkBitmap::kARGB_8888_Config;

+    }

 

+    SkBitmap bitmap;

     bitmap.setConfig(config, width, height);

 

     jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);

@@ -233,10 +314,11 @@
 

     if (jColors != NULL) {

         GraphicsJNI::SetPixels(env, jColors, offset, stride,

-                               0, 0, width, height, bitmap);

+                0, 0, width, height, bitmap, true);

     }

 

-    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL, NULL);

+    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,

+            getPremulBitmapCreateFlags(isMutable), NULL, NULL);

 }

 

 static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,

@@ -247,8 +329,8 @@
     if (!src->copyTo(&result, dstConfig, &allocator)) {

         return NULL;

     }

-

-    return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL, NULL);

+    return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),

+            getPremulBitmapCreateFlags(isMutable), NULL, NULL);

 }

 

 static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {

@@ -271,6 +353,26 @@
     return true;

 }

 

+static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jint bitmapInt,

+        int width, int height, SkBitmap::Config config, int allocSize) {

+    if (width * height * SkBitmap::ComputeBytesPerPixel(config) > 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;

+    }

+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapInt);

+    SkPixelRef* ref = bitmap->pixelRef();

+    SkSafeRef(ref);

+    bitmap->setConfig(config, width, height);

+    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.

+    ref->notifyPixelsChanged();

+    SkSafeUnref(ref);

+}

+

 // These must match the int values in Bitmap.java

 enum JavaEncodeFormat {

     kJPEG_JavaEncodeFormat = 0,

@@ -324,14 +426,6 @@
     bitmap->eraseColor(color);

 }

 

-static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {

-    return bitmap->width();

-}

-

-static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {

-    return bitmap->height();

-}

-

 static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {

     return bitmap->rowBytes();

 }

@@ -426,7 +520,9 @@
     bitmap->unlockPixels();

 

     blob.release();

-    return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, NULL, density);

+

+    return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),

+            NULL, NULL, density);

 }

 

 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,

@@ -504,16 +600,17 @@
         env->ReleaseIntArrayElements(offsetXY, array, 0);

     }

 

-    return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL, NULL);

+    return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),

+            GraphicsJNI::kBitmapCreateFlag_Mutable, NULL, NULL);

 }

 

 ///////////////////////////////////////////////////////////////////////////////

 

 static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,

-                           int x, int y) {

+        int x, int y, bool isPremultiplied) {

     SkAutoLockPixels alp(*bitmap);

 

-    ToColorProc proc = ChooseToColorProc(*bitmap);

+    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);

     if (NULL == proc) {

         return 0;

     }

@@ -528,11 +625,11 @@
 }

 

 static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,

-                             jintArray pixelArray, int offset, int stride,

-                             int x, int y, int width, int height) {

+        jintArray pixelArray, int offset, int stride,

+        int x, int y, int width, int height, bool isPremultiplied) {

     SkAutoLockPixels alp(*bitmap);

 

-    ToColorProc proc = ChooseToColorProc(*bitmap);

+    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);

     if (NULL == proc) {

         return;

     }

@@ -555,13 +652,13 @@
 ///////////////////////////////////////////////////////////////////////////////

 

 static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,

-                            int x, int y, SkColor color) {

+        int x, int y, SkColor color, bool isPremultiplied) {

     SkAutoLockPixels alp(*bitmap);

     if (NULL == bitmap->getPixels()) {

         return;

     }

 

-    FromColorProc proc = ChooseFromColorProc(bitmap->config());

+    FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);

     if (NULL == proc) {

         return;

     }

@@ -571,10 +668,10 @@
 }

 

 static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,

-                             jintArray pixelArray, int offset, int stride,

-                             int x, int y, int width, int height) {

+        jintArray pixelArray, int offset, int stride,

+        int x, int y, int width, int height, bool isPremultiplied) {

     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,

-                           x, y, width, height, *bitmap);

+            x, y, width, height, *bitmap, isPremultiplied);

 }

 

 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,

@@ -666,11 +763,10 @@
         (void*)Bitmap_copy },

     {   "nativeDestructor",         "(I)V", (void*)Bitmap_destructor },

     {   "nativeRecycle",            "(I)Z", (void*)Bitmap_recycle },

+    {   "nativeReconfigure",        "(IIIII)V", (void*)Bitmap_reconfigure },

     {   "nativeCompress",           "(IIILjava/io/OutputStream;[B)Z",

         (void*)Bitmap_compress },

     {   "nativeErase",              "(II)V", (void*)Bitmap_erase },

-    {   "nativeWidth",              "(I)I", (void*)Bitmap_width },

-    {   "nativeHeight",             "(I)I", (void*)Bitmap_height },

     {   "nativeRowBytes",           "(I)I", (void*)Bitmap_rowBytes },

     {   "nativeConfig",             "(I)I", (void*)Bitmap_config },

     {   "nativeHasAlpha",           "(I)Z", (void*)Bitmap_hasAlpha },

@@ -685,10 +781,10 @@
     {   "nativeExtractAlpha",       "(II[I)Landroid/graphics/Bitmap;",

         (void*)Bitmap_extractAlpha },

     {   "nativeGenerationId",       "(I)I", (void*)Bitmap_getGenerationId },

-    {   "nativeGetPixel",           "(III)I", (void*)Bitmap_getPixel },

-    {   "nativeGetPixels",          "(I[IIIIIII)V", (void*)Bitmap_getPixels },

-    {   "nativeSetPixel",           "(IIII)V", (void*)Bitmap_setPixel },

-    {   "nativeSetPixels",          "(I[IIIIIII)V", (void*)Bitmap_setPixels },

+    {   "nativeGetPixel",           "(IIIZ)I", (void*)Bitmap_getPixel },

+    {   "nativeGetPixels",          "(I[IIIIIIIZ)V", (void*)Bitmap_getPixels },

+    {   "nativeSetPixel",           "(IIIIZ)V", (void*)Bitmap_setPixel },

+    {   "nativeSetPixels",          "(I[IIIIIIIZ)V", (void*)Bitmap_setPixels },

     {   "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",

                                             (void*)Bitmap_copyPixelsToBuffer },

     {   "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",

diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index daabce3..0d757f7 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -2,6 +2,8 @@
 
 #include "BitmapFactory.h"
 #include "NinePatchPeeker.h"
+#include "SkData.h"
+#include "SkFrontBufferedStream.h"
 #include "SkImageDecoder.h"
 #include "SkImageRef_ashmem.h"
 #include "SkImageRef_GlobalPool.h"
@@ -13,6 +15,7 @@
 #include "AutoDecodeCancel.h"
 #include "Utils.h"
 #include "JNIHelp.h"
+#include "GraphicsJNI.h"
 
 #include <android_runtime/AndroidRuntime.h>
 #include <androidfw/Asset.h>
@@ -24,11 +27,16 @@
 jfieldID gOptions_justBoundsFieldID;
 jfieldID gOptions_sampleSizeFieldID;
 jfieldID gOptions_configFieldID;
+jfieldID gOptions_premultipliedFieldID;
 jfieldID gOptions_mutableFieldID;
 jfieldID gOptions_ditherFieldID;
 jfieldID gOptions_purgeableFieldID;
 jfieldID gOptions_shareableFieldID;
 jfieldID gOptions_preferQualityOverSpeedFieldID;
+jfieldID gOptions_scaledFieldID;
+jfieldID gOptions_densityFieldID;
+jfieldID gOptions_screenDensityFieldID;
+jfieldID gOptions_targetDensityFieldID;
 jfieldID gOptions_widthFieldID;
 jfieldID gOptions_heightFieldID;
 jfieldID gOptions_mimeFieldID;
@@ -61,6 +69,7 @@
         { SkImageDecoder::kICO_Format,  "image/x-ico" },
         { SkImageDecoder::kJPEG_Format, "image/jpeg" },
         { SkImageDecoder::kPNG_Format,  "image/png" },
+        { SkImageDecoder::kWEBP_Format, "image/webp" },
         { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
     };
 
@@ -112,31 +121,7 @@
     }
 }
 
-static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale,
-        jobject padding) {
-
-    jbyte* array = env->GetByteArrayElements(chunkObject, 0);
-    if (array != NULL) {
-        size_t chunkSize = env->GetArrayLength(chunkObject);
-        void* storage = alloca(chunkSize);
-        android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage);
-        memcpy(chunk, array, chunkSize);
-        android::Res_png_9patch::deserialize(chunk);
-
-        scaleNinePatchChunk(chunk, scale);
-        memcpy(array, chunk, chunkSize);
-
-        if (padding) {
-            GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop,
-                    chunk->paddingRight, chunk->paddingBottom);
-        }
-
-        env->ReleaseByteArrayElements(chunkObject, array, 0);
-    }
-    return chunkObject;
-}
-
-static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
+static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
         int sampleSize, bool ditherImage) {
 
     SkImageRef* pr;
@@ -152,12 +137,80 @@
     return pr;
 }
 
+static SkBitmap::Config configForScaledOutput(SkBitmap::Config config) {
+    switch (config) {
+        case SkBitmap::kNo_Config:
+        case SkBitmap::kIndex8_Config:
+            return SkBitmap::kARGB_8888_Config;
+        default:
+            break;
+    }
+    return config;
+}
+
+class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
+public:
+    ScaleCheckingAllocator(float scale, int size)
+            : mScale(scale), mSize(size) {
+    }
+
+    virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+        // accounts for scale in final allocation, using eventual size and config
+        const int bytesPerPixel = SkBitmap::ComputeBytesPerPixel(
+                configForScaledOutput(bitmap->getConfig()));
+        const int requestedSize = bytesPerPixel *
+                int(bitmap->width() * mScale + 0.5f) *
+                int(bitmap->height() * mScale + 0.5f);
+        if (requestedSize > mSize) {
+            ALOGW("bitmap for alloc reuse (%d bytes) can't fit scaled bitmap (%d bytes)",
+                    mSize, requestedSize);
+            return false;
+        }
+        return SkBitmap::HeapAllocator::allocPixelRef(bitmap, ctable);
+    }
+private:
+    const float mScale;
+    const int mSize;
+};
+
+class RecyclingPixelAllocator : public SkBitmap::Allocator {
+public:
+    RecyclingPixelAllocator(SkPixelRef* pixelRef, unsigned int size)
+            : mPixelRef(pixelRef), mSize(size) {
+        SkSafeRef(mPixelRef);
+    }
+
+    ~RecyclingPixelAllocator() {
+        SkSafeUnref(mPixelRef);
+    }
+
+    virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+        if (!bitmap->getSize64().is32() || bitmap->getSize() > mSize) {
+            ALOGW("bitmap marked for reuse (%d bytes) can't fit new bitmap (%d bytes)",
+                    mSize, bitmap->getSize());
+            return false;
+        }
+
+        // Create a new pixelref with the new ctable that wraps the previous pixelref
+        SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef), ctable);
+
+        bitmap->setPixelRef(pr)->unref();
+        // since we're already allocated, we lockPixels right away
+        // HeapAllocator/JavaPixelAllocator behaves this way too
+        bitmap->lockPixels();
+        return true;
+    }
+
+private:
+    SkPixelRef* const mPixelRef;
+    const unsigned int mSize;
+};
+
 // since we "may" create a purgeable imageref, we require the stream be ref'able
 // i.e. dynamically allocated, since its lifetime may exceed the current stack
 // frame.
-static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
-        jobject options, bool allowPurgeable, bool forcePurgeable = false,
-        bool applyScale = false, float scale = 1.0f) {
+static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding,
+        jobject options, bool allowPurgeable, bool forcePurgeable = false) {
 
     int sampleSize = 1;
 
@@ -166,10 +219,10 @@
 
     bool doDither = true;
     bool isMutable = false;
-    bool willScale = applyScale && scale != 1.0f;
-    bool isPurgeable = !willScale &&
-            (forcePurgeable || (allowPurgeable && optionsPurgeable(env, options)));
+    float scale = 1.0f;
+    bool isPurgeable = forcePurgeable || (allowPurgeable && optionsPurgeable(env, options));
     bool preferQualityOverSpeed = false;
+    bool requireUnpremultiplied = false;
 
     jobject javaBitmap = NULL;
 
@@ -190,12 +243,21 @@
         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
         preferQualityOverSpeed = env->GetBooleanField(options,
                 gOptions_preferQualityOverSpeedFieldID);
+        requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
+
+        if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
+            const int density = env->GetIntField(options, gOptions_densityFieldID);
+            const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
+            const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
+            if (density != 0 && targetDensity != 0 && density != screenDensity) {
+                scale = (float) targetDensity / density;
+            }
+        }
     }
 
-    if (willScale && javaBitmap != NULL) {
-        return nullObjectReturn("Cannot pre-scale a reused bitmap");
-    }
+    const bool willScale = scale != 1.0f;
+    isPurgeable &= !willScale;
 
     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
     if (decoder == NULL) {
@@ -205,39 +267,52 @@
     decoder->setSampleSize(sampleSize);
     decoder->setDitherImage(doDither);
     decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
+    decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
+
+    SkBitmap* outputBitmap = NULL;
+    unsigned int existingBufferSize = 0;
+    if (javaBitmap != NULL) {
+        outputBitmap = (SkBitmap*) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID);
+        if (outputBitmap->isImmutable()) {
+            ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
+            javaBitmap = NULL;
+            outputBitmap = NULL;
+        } else {
+            existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
+        }
+    }
+
+    SkAutoTDelete<SkBitmap> adb(outputBitmap == NULL ? new SkBitmap : NULL);
+    if (outputBitmap == NULL) outputBitmap = adb.get();
 
     NinePatchPeeker peeker(decoder);
-    JavaPixelAllocator javaAllocator(env);
-
-    SkBitmap* bitmap;
-    bool useExistingBitmap = false;
-    if (javaBitmap == NULL) {
-        bitmap = new SkBitmap;
-    } else {
-        if (sampleSize != 1) {
-            return nullObjectReturn("SkImageDecoder: Cannot reuse bitmap with sampleSize != 1");
-        }
-
-        bitmap = (SkBitmap*) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID);
-        // only reuse the provided bitmap if it is immutable
-        if (!bitmap->isImmutable()) {
-            useExistingBitmap = true;
-            // config of supplied bitmap overrules config set in options
-            prefConfig = bitmap->getConfig();
-        } else {
-            ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
-            bitmap = new SkBitmap;
-        }
-    }
-
-    SkAutoTDelete<SkImageDecoder> add(decoder);
-    SkAutoTDelete<SkBitmap> adb(!useExistingBitmap ? bitmap : NULL);
-
     decoder->setPeeker(&peeker);
-    if (!isPurgeable) {
-        decoder->setAllocator(&javaAllocator);
+
+    SkImageDecoder::Mode decodeMode = isPurgeable ? SkImageDecoder::kDecodeBounds_Mode : mode;
+
+    JavaPixelAllocator javaAllocator(env);
+    RecyclingPixelAllocator recyclingAllocator(outputBitmap->pixelRef(), existingBufferSize);
+    ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
+    SkBitmap::Allocator* outputAllocator = (javaBitmap != NULL) ?
+            (SkBitmap::Allocator*)&recyclingAllocator : (SkBitmap::Allocator*)&javaAllocator;
+    if (decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
+        if (!willScale) {
+            // If the java allocator is being used to allocate the pixel memory, the decoder
+            // need not write zeroes, since the memory is initialized to 0.
+            decoder->setSkipWritingZeroes(outputAllocator == &javaAllocator);
+            decoder->setAllocator(outputAllocator);
+        } else if (javaBitmap != NULL) {
+            // check for eventual scaled bounds at allocation time, so we don't decode the bitmap
+            // only to find the scaled result too large to fit in the allocation
+            decoder->setAllocator(&scaleCheckingAllocator);
+        }
     }
 
+    // Only setup the decoder to be deleted after its stack-based, refcounted
+    // components (allocators, peekers, etc) are declared. This prevents RefCnt
+    // asserts from firing due to the order objects are deleted from the stack.
+    SkAutoTDelete<SkImageDecoder> add(decoder);
+
     AutoDecoderCancel adc(options, decoder);
 
     // To fix the race condition in case "requestCancelDecode"
@@ -247,25 +322,13 @@
         return nullObjectReturn("gOptions_mCancelID");
     }
 
-    SkImageDecoder::Mode decodeMode = mode;
-    if (isPurgeable) {
-        decodeMode = SkImageDecoder::kDecodeBounds_Mode;
-    }
-
-    SkBitmap* decoded;
-    if (willScale) {
-        decoded = new SkBitmap;
-    } else {
-        decoded = bitmap;
-    }
-    SkAutoTDelete<SkBitmap> adb2(willScale ? decoded : NULL);
-
-    if (!decoder->decode(stream, decoded, prefConfig, decodeMode, javaBitmap != NULL)) {
+    SkBitmap decodingBitmap;
+    if (!decoder->decode(stream, &decodingBitmap, prefConfig, decodeMode)) {
         return nullObjectReturn("decoder->decode returned false");
     }
 
-    int scaledWidth = decoded->width();
-    int scaledHeight = decoded->height();
+    int scaledWidth = decodingBitmap.width();
+    int scaledHeight = decodingBitmap.height();
 
     if (willScale && mode != SkImageDecoder::kDecodeBounds_Mode) {
         scaledWidth = int(scaledWidth * scale + 0.5f);
@@ -333,33 +396,31 @@
         // Dalvik code has always behaved. We simply recreate the behavior here.
         // The result is slightly different from simply using scale because of
         // the 0.5f rounding bias applied when computing the target image size
-        const float sx = scaledWidth / float(decoded->width());
-        const float sy = scaledHeight / float(decoded->height());
+        const float sx = scaledWidth / float(decodingBitmap.width());
+        const float sy = scaledHeight / float(decodingBitmap.height());
 
-        SkBitmap::Config config = decoded->config();
-        switch (config) {
-            case SkBitmap::kNo_Config:
-            case SkBitmap::kIndex8_Config:
-            case SkBitmap::kRLE_Index8_Config:
-                config = SkBitmap::kARGB_8888_Config;
-                break;
-            default:
-                break;
-        }
-
-        bitmap->setConfig(config, scaledWidth, scaledHeight);
-        bitmap->setIsOpaque(decoded->isOpaque());
-        if (!bitmap->allocPixels(&javaAllocator, NULL)) {
+        // TODO: avoid copying when scaled size equals decodingBitmap size
+        SkBitmap::Config config = configForScaledOutput(decodingBitmap.config());
+        outputBitmap->setConfig(config, scaledWidth, scaledHeight);
+        outputBitmap->setIsOpaque(decodingBitmap.isOpaque());
+        if (!outputBitmap->allocPixels(outputAllocator, NULL)) {
             return nullObjectReturn("allocation failed for scaled bitmap");
         }
-        bitmap->eraseColor(0);
+
+        // If outputBitmap's pixels are newly allocated by Java, there is no need
+        // to erase to 0, since the pixels were initialized to 0.
+        if (outputAllocator != &javaAllocator) {
+            outputBitmap->eraseColor(0);
+        }
 
         SkPaint paint;
         paint.setFilterBitmap(true);
 
-        SkCanvas canvas(*bitmap);
+        SkCanvas canvas(*outputBitmap);
         canvas.scale(sx, sy);
-        canvas.drawBitmap(*decoded, 0.0f, 0.0f, &paint);
+        canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
+    } else {
+        outputBitmap->swap(decodingBitmap);
     }
 
     if (padding) {
@@ -374,17 +435,17 @@
 
     SkPixelRef* pr;
     if (isPurgeable) {
-        pr = installPixelRef(bitmap, stream, sampleSize, doDither);
+        pr = installPixelRef(outputBitmap, stream, sampleSize, doDither);
     } else {
         // if we get here, we're in kDecodePixels_Mode and will therefore
         // already have a pixelref installed.
-        pr = bitmap->pixelRef();
+        pr = outputBitmap->pixelRef();
     }
     if (pr == NULL) {
         return nullObjectReturn("Got null SkPixelRef");
     }
 
-    if (!isMutable && !useExistingBitmap) {
+    if (!isMutable && javaBitmap == NULL) {
         // promise we will never change our pixels (great for sharing and pictures)
         pr->setImmutable();
     }
@@ -392,43 +453,40 @@
     // detach bitmap from its autodeleter, since we want to own it now
     adb.detach();
 
-    if (useExistingBitmap) {
+    if (javaBitmap != NULL) {
+        bool isPremultiplied = !requireUnpremultiplied;
+        GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap, isPremultiplied);
+        outputBitmap->notifyPixelsChanged();
         // If a java bitmap was passed in for reuse, pass it back
         return javaBitmap;
     }
+
+    int bitmapCreateFlags = 0x0;
+    if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
+    if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+
     // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(),
-            isMutable, ninePatchChunk, layoutBounds, -1);
-}
-
-static jobject nativeDecodeStreamScaled(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
-        jobject padding, jobject options, jboolean applyScale, jfloat scale) {
-
-    jobject bitmap = NULL;
-    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0);
-
-    if (stream) {
-        // for now we don't allow purgeable with java inputstreams
-        bitmap = doDecode(env, stream, padding, options, false, false, applyScale, scale);
-        stream->unref();
-    }
-    return bitmap;
+    return GraphicsJNI::createBitmap(env, outputBitmap, javaAllocator.getStorageObj(),
+            bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
 }
 
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
         jobject padding, jobject options) {
 
-    return nativeDecodeStreamScaled(env, clazz, is, storage, padding, options, false, 1.0f);
-}
+    jobject bitmap = NULL;
+    SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
 
-static ssize_t getFDSize(int fd) {
-    off64_t curr = ::lseek64(fd, 0, SEEK_CUR);
-    if (curr < 0) {
-        return 0;
+    if (stream.get()) {
+        // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+        // trying to determine the stream's format. Currently the most is 64, read by
+        // SkImageDecoder_libwebp.
+        // FIXME: Get this number from SkImageDecoder
+        SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+        SkASSERT(bufferedStream.get() != NULL);
+        // for now we don't allow purgeable with java inputstreams
+        bitmap = doDecode(env, bufferedStream, padding, options, false, false);
     }
-    size_t size = ::lseek(fd, 0, SEEK_END);
-    ::lseek64(fd, curr, SEEK_SET);
-    return size;
+    return bitmap;
 }
 
 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
@@ -438,6 +496,12 @@
 
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
+    struct stat fdStat;
+    if (fstat(descriptor, &fdStat) == -1) {
+        doThrowIOE(env, "broken file descriptor");
+        return nullObjectReturn("fstat return -1");
+    }
+
     bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
     bool isShareable = optionsShareable(env, bitmapFactoryOptions);
     bool weOwnTheFD = false;
@@ -449,17 +513,8 @@
         }
     }
 
-    SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
-    SkAutoUnref aur(stream);
-    if (!stream->isValid()) {
-        return NULL;
-    }
-
-    /* Restore our offset when we leave, so we can be called more than once
-       with the same descriptor. This is only required if we didn't dup the
-       file descriptor, but it is OK to do it all the time.
-    */
-    AutoFDSeek as(descriptor);
+    SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor));
+    SkAutoTUnref<SkMemoryStream> stream(new SkMemoryStream(data));
 
     /* Allow purgeable iff we own the FD, i.e., in the puregeable and
        shareable case.
@@ -467,44 +522,16 @@
     return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD);
 }
 
-/*  make a deep copy of the asset, and return it as a stream, or NULL if there
-    was an error.
- */
-static SkStream* copyAssetToStream(Asset* asset) {
-    // if we could "ref/reopen" the asset, we may not need to copy it here
-    off64_t size = asset->seek(0, SEEK_SET);
-    if ((off64_t)-1 == size) {
-        SkDebugf("---- copyAsset: asset rewind failed\n");
-        return NULL;
-    }
+static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset,
+        jobject padding, jobject options) {
 
-    size = asset->getLength();
-    if (size <= 0) {
-        SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size);
-        return NULL;
-    }
-
-    SkStream* stream = new SkMemoryStream(size);
-    void* data = const_cast<void*>(stream->getMemoryBase());
-    off64_t len = asset->read(data, size);
-    if (len != size) {
-        SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len);
-        delete stream;
-        stream = NULL;
-    }
-    return stream;
-}
-
-static jobject nativeDecodeAssetScaled(JNIEnv* env, jobject clazz, jint native_asset,
-        jobject padding, jobject options, jboolean applyScale, jfloat scale) {
-
-    SkStream* stream;
+    SkStreamRewindable* stream;
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     bool forcePurgeable = optionsPurgeable(env, options);
     if (forcePurgeable) {
         // if we could "ref/reopen" the asset, we may not need to copy it here
         // and we could assume optionsShareable, since assets are always RO
-        stream = copyAssetToStream(asset);
+        stream = CopyAssetToStream(asset);
         if (stream == NULL) {
             return NULL;
         }
@@ -514,13 +541,7 @@
         stream = new AssetStreamAdaptor(asset);
     }
     SkAutoUnref aur(stream);
-    return doDecode(env, stream, padding, options, true, forcePurgeable, applyScale, scale);
-}
-
-static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset,
-        jobject padding, jobject options) {
-
-    return nativeDecodeAssetScaled(env, clazz, native_asset, padding, options, false, 1.0f);
+    return doDecode(env, stream, padding, options, forcePurgeable, forcePurgeable);
 }
 
 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
@@ -533,7 +554,7 @@
      */
     bool purgeable = optionsPurgeable(env, options) && !optionsJustBounds(env, options);
     AutoJavaByteArray ar(env, byteArray);
-    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable);
+    SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable);
     SkAutoUnref aur(stream);
     return doDecode(env, stream, NULL, options, purgeable);
 }
@@ -554,10 +575,6 @@
         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeStream
     },
-    {   "nativeDecodeStream",
-        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;ZF)Landroid/graphics/Bitmap;",
-        (void*)nativeDecodeStreamScaled
-    },
 
     {   "nativeDecodeFileDescriptor",
         "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
@@ -569,21 +586,11 @@
         (void*)nativeDecodeAsset
     },
 
-    {   "nativeDecodeAsset",
-        "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;ZF)Landroid/graphics/Bitmap;",
-        (void*)nativeDecodeAssetScaled
-    },
-
     {   "nativeDecodeByteArray",
         "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeByteArray
     },
 
-    {   "nativeScaleNinePatch",
-        "([BFLandroid/graphics/Rect;)[B",
-        (void*)nativeScaleNinePatch
-    },
-
     {   "nativeIsSeekable",
         "(Ljava/io/FileDescriptor;)Z",
         (void*)nativeIsSeekable
@@ -610,12 +617,17 @@
     gOptions_sampleSizeFieldID = getFieldIDCheck(env, options_class, "inSampleSize", "I");
     gOptions_configFieldID = getFieldIDCheck(env, options_class, "inPreferredConfig",
             "Landroid/graphics/Bitmap$Config;");
+    gOptions_premultipliedFieldID = getFieldIDCheck(env, options_class, "inPremultiplied", "Z");
     gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z");
     gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z");
     gOptions_purgeableFieldID = getFieldIDCheck(env, options_class, "inPurgeable", "Z");
     gOptions_shareableFieldID = getFieldIDCheck(env, options_class, "inInputShareable", "Z");
     gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class,
             "inPreferQualityOverSpeed", "Z");
+    gOptions_scaledFieldID = getFieldIDCheck(env, options_class, "inScaled", "Z");
+    gOptions_densityFieldID = getFieldIDCheck(env, options_class, "inDensity", "I");
+    gOptions_screenDensityFieldID = getFieldIDCheck(env, options_class, "inScreenDensity", "I");
+    gOptions_targetDensityFieldID = getFieldIDCheck(env, options_class, "inTargetDensity", "I");
     gOptions_widthFieldID = getFieldIDCheck(env, options_class, "outWidth", "I");
     gOptions_heightFieldID = getFieldIDCheck(env, options_class, "outHeight", "I");
     gOptions_mimeFieldID = getFieldIDCheck(env, options_class, "outMimeType", "Ljava/lang/String;");
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index f2aaab7..97dcc6d 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -7,6 +7,7 @@
 extern jfieldID gOptions_justBoundsFieldID;
 extern jfieldID gOptions_sampleSizeFieldID;
 extern jfieldID gOptions_configFieldID;
+extern jfieldID gOptions_premultipliedFieldID;
 extern jfieldID gOptions_ditherFieldID;
 extern jfieldID gOptions_purgeableFieldID;
 extern jfieldID gOptions_shareableFieldID;
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index b218bcd..ee47ac4 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "BitmapRegionDecoder"
 
 #include "SkBitmap.h"
+#include "SkData.h"
 #include "SkImageEncoder.h"
 #include "GraphicsJNI.h"
 #include "SkUtils.h"
@@ -25,7 +26,6 @@
 #include "SkStream.h"
 #include "BitmapFactory.h"
 #include "AutoDecodeCancel.h"
-#include "SkBitmapRegionDecoder.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "Utils.h"
 #include "JNIHelp.h"
@@ -49,28 +49,34 @@
 
 using namespace android;
 
-static SkMemoryStream* buildSkMemoryStream(SkStream *stream) {
-    size_t bufferSize = 4096;
-    size_t streamLen = 0;
-    size_t len;
-    char* data = (char*)sk_malloc_throw(bufferSize);
-
-    while ((len = stream->read(data + streamLen,
-                    bufferSize - streamLen)) != 0) {
-        streamLen += len;
-        if (streamLen == bufferSize) {
-            bufferSize *= 2;
-            data = (char*)sk_realloc_throw(data, bufferSize);
-        }
+class SkBitmapRegionDecoder {
+public:
+    SkBitmapRegionDecoder(SkImageDecoder* decoder, int width, int height) {
+        fDecoder = decoder;
+        fWidth = width;
+        fHeight = height;
     }
-    data = (char*)sk_realloc_throw(data, streamLen);
+    ~SkBitmapRegionDecoder() {
+        SkDELETE(fDecoder);
+    }
 
-    SkMemoryStream* streamMem = new SkMemoryStream();
-    streamMem->setMemoryOwned(data, streamLen);
-    return streamMem;
-}
+    bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect,
+                      SkBitmap::Config pref, int sampleSize) {
+        fDecoder->setSampleSize(sampleSize);
+        return fDecoder->decodeRegion(bitmap, rect, pref);
+    }
 
-static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
+    SkImageDecoder* getDecoder() const { return fDecoder; }
+    int getWidth() const { return fWidth; }
+    int getHeight() const { return fHeight; }
+
+private:
+    SkImageDecoder* fDecoder;
+    int fWidth;
+    int fHeight;
+};
+
+static jobject createBitmapRegionDecoder(JNIEnv* env, SkStream* stream) {
     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
     int width, height;
     if (NULL == decoder) {
@@ -87,11 +93,11 @@
         snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
                 decoder->getFormatName());
         doThrowIOE(env, msg);
+        SkDELETE(decoder);
         return nullObjectReturn("decoder->buildTileIndex returned false");
     }
 
-    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, stream, width, height);
-
+    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
     return GraphicsJNI::createBitmapRegionDecoder(env, bm);
 }
 
@@ -103,7 +109,10 @@
      */
     AutoJavaByteArray ar(env, byteArray);
     SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
-    return doBuildTileIndex(env, stream);
+
+    jobject brd = createBitmapRegionDecoder(env, stream);
+    SkSafeUnref(stream); // the decoder now holds a reference
+    return brd;
 }
 
 static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
@@ -111,67 +120,48 @@
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    SkStream *stream = NULL;
+
     struct stat fdStat;
-    int newFD;
     if (fstat(descriptor, &fdStat) == -1) {
         doThrowIOE(env, "broken file descriptor");
         return nullObjectReturn("fstat return -1");
     }
 
-    if (isShareable &&
-            S_ISREG(fdStat.st_mode) &&
-            (newFD = ::dup(descriptor)) != -1) {
-        SkFDStream* fdStream = new SkFDStream(newFD, true);
-        if (!fdStream->isValid()) {
-            fdStream->unref();
-            return NULL;
-        }
-        stream = fdStream;
-    } else {
-        /* Restore our offset when we leave, so we can be called more than once
-           with the same descriptor. This is only required if we didn't dup the
-           file descriptor, but it is OK to do it all the time.
-        */
-        AutoFDSeek as(descriptor);
+    SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor));
+    SkMemoryStream* stream = new SkMemoryStream(data);
 
-        SkFDStream* fdStream = new SkFDStream(descriptor, false);
-        if (!fdStream->isValid()) {
-            fdStream->unref();
-            return NULL;
-        }
-        stream = buildSkMemoryStream(fdStream);
-        fdStream->unref();
-    }
-
-    return doBuildTileIndex(env, stream);
+    jobject brd = createBitmapRegionDecoder(env, stream);
+    SkSafeUnref(stream); // the decoder now holds a reference
+    return brd;
 }
 
 static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
                                   jobject is,       // InputStream
                                   jbyteArray storage, // byte[]
                                   jboolean isShareable) {
-    jobject largeBitmap = NULL;
-    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
+    jobject brd = NULL;
+    // for now we don't allow shareable with java inputstreams
+    SkStreamRewindable* stream = CopyJavaInputStream(env, is, storage);
 
     if (stream) {
-        // for now we don't allow shareable with java inputstreams
-        SkMemoryStream *mStream = buildSkMemoryStream(stream);
-        largeBitmap = doBuildTileIndex(env, mStream);
-        stream->unref();
+        brd = createBitmapRegionDecoder(env, stream);
+        stream->unref(); // the decoder now holds a reference
     }
-    return largeBitmap;
+    return brd;
 }
 
 static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
                                  jint native_asset, // Asset
                                  jboolean isShareable) {
-    SkStream* stream, *assStream;
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
-    assStream = new AssetStreamAdaptor(asset);
-    stream = buildSkMemoryStream(assStream);
-    assStream->unref();
-    return doBuildTileIndex(env, stream);
+    SkAutoTUnref<SkMemoryStream> stream(CopyAssetToStream(asset));
+    if (NULL == stream.get()) {
+        return NULL;
+    }
+
+    jobject brd = createBitmapRegionDecoder(env, stream.get());
+    // The decoder now holds a reference to stream.
+    return brd;
 }
 
 /*
@@ -188,6 +178,7 @@
     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
     bool doDither = true;
     bool preferQualityOverSpeed = false;
+    bool requireUnpremultiplied = false;
 
     if (NULL != options) {
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
@@ -203,11 +194,13 @@
                 gOptions_preferQualityOverSpeedFieldID);
         // Get the bitmap for re-use if it exists.
         tileBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
+        requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
     }
 
     decoder->setDitherImage(doDither);
     decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
-    AutoDecoderCancel   adc(options, decoder);
+    decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
+    AutoDecoderCancel adc(options, decoder);
 
     // To fix the race condition in case "requestCancelDecode"
     // happens earlier than AutoDecoderCancel object is added
@@ -257,7 +250,10 @@
 
     JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator();
     jbyteArray buff = allocator->getStorageObjAndReset();
-    return GraphicsJNI::createBitmap(env, bitmap, buff, false, NULL, NULL, -1);
+
+    int bitmapCreateFlags = 0;
+    if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+    return GraphicsJNI::createBitmap(env, bitmap, buff, bitmapCreateFlags, NULL, NULL, -1);
 }
 
 static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3308064..813dd5a 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -35,8 +35,6 @@
 
 #include <utils/Log.h>
 
-#define TIME_DRAWx
-
 static uint32_t get_thread_msec() {
 #if defined(HAVE_POSIX_CLOCKS)
     struct timespec tm;
@@ -463,20 +461,6 @@
         canvas->drawPath(*path, *paint);
     }
  
-    static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
-                            SkPicture* picture) {
-        SkASSERT(canvas);
-        SkASSERT(picture);
-        
-#ifdef TIME_DRAW
-        SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
-#endif
-        canvas->drawPicture(*picture);
-#ifdef TIME_DRAW
-        ALOGD("---- picture playback %d ms\n", get_thread_msec() - now);
-#endif
-    }
-
     static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
                                           SkCanvas* canvas, SkBitmap* bitmap,
                                           jfloat left, jfloat top,
@@ -563,18 +547,17 @@
                                 jboolean hasAlpha, SkPaint* paint)
     {
         SkBitmap    bitmap;
-        
         bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
                          SkBitmap::kRGB_565_Config, width, height);
         if (!bitmap.allocPixels()) {
             return;
         }
-        
+
         if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
-                                    0, 0, width, height, bitmap)) {
+                0, 0, width, height, bitmap, true)) {
             return;
         }
-        
+
         canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
                            paint);
     }
@@ -1103,7 +1086,6 @@
         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
     {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
-    {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
 
     {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches},
 
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index aa4cbde..da8f083 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -1,39 +1,63 @@
 #include "CreateJavaOutputStreamAdaptor.h"
+#include "JNIHelp.h"
+#include "SkData.h"
+#include "SkRefCnt.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+#include "Utils.h"
 
-#define RETURN_NULL_IF_NULL(value) \
-    do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
-
-static jmethodID    gInputStream_resetMethodID;
-static jmethodID    gInputStream_markMethodID;
-static jmethodID    gInputStream_availableMethodID;
 static jmethodID    gInputStream_readMethodID;
 static jmethodID    gInputStream_skipMethodID;
 
+/**
+ *  Wrapper for a Java InputStream.
+ */
 class JavaInputStreamAdaptor : public SkStream {
 public:
     JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
         : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
         SkASSERT(ar);
-        fCapacity   = env->GetArrayLength(ar);
+        fCapacity = env->GetArrayLength(ar);
         SkASSERT(fCapacity > 0);
-        fBytesRead  = 0;
-    }
-
-	virtual bool rewind() {
-        JNIEnv* env = fEnv;
-
         fBytesRead = 0;
-
-        env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
-        if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-            SkDebugf("------- reset threw an exception\n");
-            return false;
-        }
-        return true;
+        fIsAtEnd = false;
     }
 
+    virtual size_t read(void* buffer, size_t size) {
+        JNIEnv* env = fEnv;
+        if (NULL == buffer) {
+            if (0 == size) {
+                return 0;
+            } else {
+                /*  InputStream.skip(n) can return <=0 but still not be at EOF
+                    If we see that value, we need to call read(), which will
+                    block if waiting for more data, or return -1 at EOF
+                 */
+                size_t amountSkipped = 0;
+                do {
+                    size_t amount = this->doSkip(size - amountSkipped);
+                    if (0 == amount) {
+                        char tmp;
+                        amount = this->doRead(&tmp, 1);
+                        if (0 == amount) {
+                            // if read returned 0, we're at EOF
+                            fIsAtEnd = true;
+                            break;
+                        }
+                    }
+                    amountSkipped += amount;
+                } while (amountSkipped < size);
+                return amountSkipped;
+            }
+        }
+        return this->doRead(buffer, size);
+    }
+
+    virtual bool isAtEnd() const {
+        return fIsAtEnd;
+    }
+
+private:
     size_t doRead(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         size_t bytesRead = 0;
@@ -53,6 +77,7 @@
             }
 
             if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
+                fIsAtEnd = true;
                 break;  // eof
             }
 
@@ -92,91 +117,51 @@
         return (size_t)skipped;
     }
 
-    size_t doSize() {
-        JNIEnv* env = fEnv;
-        jint avail = env->CallIntMethod(fJavaInputStream,
-                                        gInputStream_availableMethodID);
-        if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-            SkDebugf("------- available threw an exception\n");
-            avail = 0;
-        }
-        return avail;
-    }
-
-	virtual size_t read(void* buffer, size_t size) {
-        JNIEnv* env = fEnv;
-        if (NULL == buffer) {
-            if (0 == size) {
-                return this->doSize();
-            } else {
-                /*  InputStream.skip(n) can return <=0 but still not be at EOF
-                    If we see that value, we need to call read(), which will
-                    block if waiting for more data, or return -1 at EOF
-                 */
-                size_t amountSkipped = 0;
-                do {
-                    size_t amount = this->doSkip(size - amountSkipped);
-                    if (0 == amount) {
-                        char tmp;
-                        amount = this->doRead(&tmp, 1);
-                        if (0 == amount) {
-                            // if read returned 0, we're at EOF
-                            break;
-                        }
-                    }
-                    amountSkipped += amount;
-                } while (amountSkipped < size);
-                return amountSkipped;
-            }
-        }
-        return this->doRead(buffer, size);
-    }
-
-private:
     JNIEnv*     fEnv;
     jobject     fJavaInputStream;   // the caller owns this object
     jbyteArray  fJavaByteArray;     // the caller owns this object
     size_t      fCapacity;
     size_t      fBytesRead;
+    bool        fIsAtEnd;
 };
 
 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
-                                       jbyteArray storage, int markSize) {
-    static bool gInited;
-
-    if (!gInited) {
-        jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
-        RETURN_NULL_IF_NULL(inputStream_Clazz);
-
-        gInputStream_resetMethodID      = env->GetMethodID(inputStream_Clazz,
-                                                           "reset", "()V");
-        gInputStream_markMethodID       = env->GetMethodID(inputStream_Clazz,
-                                                           "mark", "(I)V");
-        gInputStream_availableMethodID  = env->GetMethodID(inputStream_Clazz,
-                                                           "available", "()I");
-        gInputStream_readMethodID       = env->GetMethodID(inputStream_Clazz,
-                                                           "read", "([BII)I");
-        gInputStream_skipMethodID       = env->GetMethodID(inputStream_Clazz,
-                                                           "skip", "(J)J");
-
-        RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
-        RETURN_NULL_IF_NULL(gInputStream_markMethodID);
-        RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
-        RETURN_NULL_IF_NULL(gInputStream_readMethodID);
-        RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
-
-        gInited = true;
-    }
-
-    if (markSize) {
-        env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
-    }
-
+                                       jbyteArray storage) {
     return new JavaInputStreamAdaptor(env, stream, storage);
 }
 
+
+static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
+    SkASSERT(stream != NULL);
+    size_t bufferSize = 4096;
+    size_t streamLen = 0;
+    size_t len;
+    char* data = (char*)sk_malloc_throw(bufferSize);
+
+    while ((len = stream->read(data + streamLen,
+                               bufferSize - streamLen)) != 0) {
+        streamLen += len;
+        if (streamLen == bufferSize) {
+            bufferSize *= 2;
+            data = (char*)sk_realloc_throw(data, bufferSize);
+        }
+    }
+    data = (char*)sk_realloc_throw(data, streamLen);
+
+    SkMemoryStream* streamMem = new SkMemoryStream();
+    streamMem->setMemoryOwned(data, streamLen);
+    return streamMem;
+}
+
+SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
+                                        jbyteArray storage) {
+    SkAutoTUnref<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
+    if (NULL == adaptor.get()) {
+        return NULL;
+    }
+    return adaptor_to_mem_stream(adaptor.get());
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static jmethodID    gOutputStream_writeMethodID;
@@ -239,18 +224,34 @@
     static bool gInited;
 
     if (!gInited) {
-        jclass outputStream_Clazz = env->FindClass("java/io/OutputStream");
-        RETURN_NULL_IF_NULL(outputStream_Clazz);
-
-        gOutputStream_writeMethodID = env->GetMethodID(outputStream_Clazz,
-                                                       "write", "([BII)V");
-        RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
-        gOutputStream_flushMethodID = env->GetMethodID(outputStream_Clazz,
-                                                       "flush", "()V");
-        RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
 
         gInited = true;
     }
 
     return new SkJavaOutputStream(env, stream, storage);
 }
+
+static jclass findClassCheck(JNIEnv* env, const char classname[]) {
+    jclass clazz = env->FindClass(classname);
+    SkASSERT(!env->ExceptionCheck());
+    return clazz;
+}
+
+static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
+                                  const char methodname[], const char type[]) {
+    jmethodID id = env->GetMethodID(clazz, methodname, type);
+    SkASSERT(!env->ExceptionCheck());
+    return id;
+}
+
+int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
+    jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
+    gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
+    gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
+
+    jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
+    gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
+    gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
+
+    return 0;
+}
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
index c34c96a..ecd270f 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -3,11 +3,39 @@
 
 //#include <android_runtime/AndroidRuntime.h>
 #include "jni.h"
-#include "SkStream.h"
 
+class SkMemoryStream;
+class SkStream;
+class SkStreamRewindable;
+class SkWStream;
+
+/**
+ *  Return an adaptor from a Java InputStream to an SkStream.
+ *  Does not support rewind.
+ *  @param env JNIEnv object.
+ *  @param stream Pointer to Java InputStream.
+ *  @param storage Java byte array for retrieving data from the
+ *      Java InputStream.
+ *  @return SkStream Simple subclass of SkStream which supports its
+ *      basic methods like reading. Only valid until the calling
+ *      function returns, since the Java InputStream is not managed
+ *      by the SkStream.
+ */
 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
-                                       jbyteArray storage, int markSize = 0);
+                                       jbyteArray storage);
+
+/**
+ *  Copy a Java InputStream. The result will be rewindable.
+ *  @param env JNIEnv object.
+ *  @param stream Pointer to Java InputStream.
+ *  @param storage Java byte array for retrieving data from the
+ *      Java InputStream.
+ *  @return SkStreamRewindable The data in stream will be copied
+ *      to a new SkStreamRewindable.
+ */
+SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
+                                        jbyteArray storage);
+
 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
                                          jbyteArray storage);
-
 #endif
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index d4c7600..8cb152d 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -152,6 +152,8 @@
 static jclass   gBitmap_class;
 static jfieldID gBitmap_nativeInstanceID;
 static jmethodID gBitmap_constructorMethodID;
+static jmethodID gBitmap_reinitMethodID;
+static jmethodID gBitmap_getAllocationByteCountMethodID;
 
 static jclass   gBitmapConfig_class;
 static jfieldID gBitmapConfig_nativeInstanceID;
@@ -345,24 +347,38 @@
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer,
-                                  bool isMutable, jbyteArray ninepatch, jintArray layoutbounds,
-                                  int density)
+        int bitmapCreateFlags, jbyteArray ninepatch, jintArray layoutbounds, int density)
 {
     SkASSERT(bitmap);
     SkASSERT(bitmap->pixelRef());
+    bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
+    bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
+
     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
-            static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)),
-            buffer, isMutable, ninepatch, layoutbounds, density);
+            static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)), buffer,
+            bitmap->width(), bitmap->height(), density, isMutable, isPremultiplied,
+            ninepatch, layoutbounds);
     hasException(env); // For the side effect of logging.
     return obj;
 }
 
-jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
-                            jbyteArray ninepatch, int density)
+jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, int bitmapCreateFlags,
+        jbyteArray ninepatch, int density)
 {
-    return createBitmap(env, bitmap, NULL, isMutable, ninepatch, NULL, density);
+    return createBitmap(env, bitmap, NULL, bitmapCreateFlags, ninepatch, NULL, density);
 }
 
+void GraphicsJNI::reinitBitmap(JNIEnv* env, jobject javaBitmap, SkBitmap* bitmap,
+        bool isPremultiplied)
+{
+    env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
+            bitmap->width(), bitmap->height(), isPremultiplied);
+}
+
+int GraphicsJNI::getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
+{
+    return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
+}
 
 jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
 {
@@ -398,7 +414,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,
-        SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
+        SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable, (storageObj == NULL)),
+        fWrappedPixelRef(NULL) {
     SkASSERT(storage);
     SkASSERT(env);
 
@@ -415,28 +432,59 @@
 
 }
 
+AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable) :
+        SkMallocPixelRef(wrappedPixelRef.getAddr(), wrappedPixelRef.getSize(), ctable, false),
+        fWrappedPixelRef(wrappedPixelRef.fWrappedPixelRef ?
+            wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef)
+{
+    SkASSERT(fWrappedPixelRef);
+    SkSafeRef(fWrappedPixelRef);
+
+    // don't need to initialize these, as all the relevant logic delegates to the wrapped ref
+    fStorageObj = NULL;
+    fHasGlobalRef = false;
+    fGlobalRefCnt = 0;
+    fOnJavaHeap = false;
+}
+
 AndroidPixelRef::~AndroidPixelRef() {
-    if (fOnJavaHeap) {
+    if (fWrappedPixelRef) {
+        SkSafeUnref(fWrappedPixelRef);
+    } else if (fOnJavaHeap) {
         JNIEnv* env = vm2env(fVM);
 
         if (fStorageObj && fHasGlobalRef) {
             env->DeleteGlobalRef(fStorageObj);
         }
         fStorageObj = NULL;
-
-        // Set this to NULL to prevent the SkMallocPixelRef destructor
-        // from freeing the memory.
-        fStorage = NULL;
     }
 }
+jbyteArray AndroidPixelRef::getStorageObj() {
+    if (fWrappedPixelRef) {
+        return fWrappedPixelRef->fStorageObj;
+    }
+    return fStorageObj;
+}
 
 void AndroidPixelRef::setLocalJNIRef(jbyteArray arr) {
-    if (!fHasGlobalRef) {
+    if (fWrappedPixelRef) {
+        // delegate java obj management to the wrapped ref
+        fWrappedPixelRef->setLocalJNIRef(arr);
+    } else if (!fHasGlobalRef) {
         fStorageObj = arr;
     }
 }
 
 void AndroidPixelRef::globalRef(void* localref) {
+    if (fWrappedPixelRef) {
+        // delegate java obj management to the wrapped ref
+        fWrappedPixelRef->globalRef(localref);
+
+        // Note: we only ref and unref the wrapped AndroidPixelRef so that
+        // bitmap->pixelRef()->globalRef() and globalUnref() can be used in a pair, even if
+        // the bitmap has its underlying AndroidPixelRef swapped out/wrapped
+        return;
+    }
     if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
         JNIEnv *env = vm2env(fVM);
 
@@ -461,6 +509,11 @@
 }
 
 void AndroidPixelRef::globalUnref() {
+    if (fWrappedPixelRef) {
+        // delegate java obj management to the wrapped ref
+        fWrappedPixelRef->globalUnref();
+        return;
+    }
     if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
         JNIEnv *env = vm2env(fVM);
         if (!fHasGlobalRef) {
@@ -586,8 +639,9 @@
 
     gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
     gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
-    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
-                                            "(I[BZ[B[II)V");
+    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(I[BIIIZZ[B[I)V");
+    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
+    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
     gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
     gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index bdfa37d..f4590b9 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -7,10 +7,10 @@
 #include "SkMallocPixelRef.h"
 #include "SkPoint.h"
 #include "SkRect.h"
-#include "../images/SkBitmapRegionDecoder.h"
-#include "../images/SkImageDecoder.h"
+#include "SkImageDecoder.h"
 #include <jni.h>
 
+class SkBitmapRegionDecoder;
 class SkCanvas;
 class SkPaint;
 class SkPicture;
@@ -59,25 +59,29 @@
         storage array (may be null).
     */
     static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer,
-                                bool isMutable, jbyteArray ninepatch, jintArray layoutbounds,
-                                int density = -1);
+            int bitmapCreateFlags, jbyteArray ninepatch, jintArray layoutbounds, int density = -1);
 
-    static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
-                                jbyteArray ninepatch, int density = -1);
+    static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, int bitmapCreateFlags,
+            jbyteArray ninepatch, int density = -1);
+
+    static void reinitBitmap(JNIEnv* env, jobject javaBitmap, SkBitmap* bitmap,
+            bool isPremultiplied);
+
+    static int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);
 
     static jobject createRegion(JNIEnv* env, SkRegion* region);
 
     static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
 
     static jbyteArray allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
-                                     SkColorTable* ctable);
+            SkColorTable* ctable);
 
     /** Copy the colors in colors[] to the bitmap, convert to the correct
         format along the way.
     */
     static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
-                          int srcStride, int x, int y, int width, int height,
-                          const SkBitmap& dstBitmap);
+            int srcStride, int x, int y, int width, int height,
+            const SkBitmap& dstBitmap, bool isPremultiplied);
 
     static jbyteArray getBitmapStorageObj(SkPixelRef *pixref);
 };
@@ -87,9 +91,16 @@
     AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,
                     SkColorTable* ctable);
 
+    /**
+     * Creates an AndroidPixelRef that wraps (and refs) another to reuse/share
+     * the same storage and java byte array refcounting, yet have a different
+     * color table.
+     */
+    AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable);
+
     virtual ~AndroidPixelRef();
 
-    jbyteArray getStorageObj() { return fStorageObj; }
+    jbyteArray getStorageObj();
 
     void setLocalJNIRef(jbyteArray arr);
 
@@ -106,6 +117,8 @@
     virtual void globalUnref();
 
 private:
+    AndroidPixelRef* const fWrappedPixelRef; // if set, delegate memory management calls to this
+
     JavaVM* fVM;
     bool fOnJavaHeap; // If true, the memory was allocated on the Java heap
 
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index ce31c5b..a75efcf 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -138,16 +138,15 @@
 hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData)
 {
     SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData);
-    SkFontID uniqueID = typeface->uniqueID();
 
-    const size_t tableSize = SkFontHost::GetTableSize(uniqueID, tag);
+    const size_t tableSize = typeface->getTableSize(tag);
     if (!tableSize)
         return 0;
 
     char* buffer = reinterpret_cast<char*>(malloc(tableSize));
     if (!buffer)
         return 0;
-    size_t actualSize = SkFontHost::GetTableData(uniqueID, tag, 0, tableSize, buffer);
+    size_t actualSize = typeface->getTableData(tag, 0, tableSize, buffer);
     if (tableSize != actualSize) {
         free(buffer);
         return 0;
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 4f64ff8..feb2dec 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,8 +1,11 @@
+#include "ScopedLocalRef.h"
+#include "SkFrontBufferedStream.h"
 #include "SkMovie.h"
 #include "SkStream.h"
 #include "GraphicsJNI.h"
 #include "SkTemplates.h"
 #include "SkUtils.h"
+#include "Utils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 
 #include <androidfw/Asset.h>
@@ -79,18 +82,33 @@
     c->drawBitmap(b, sx, sy, p);
 }
 
+static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jint native_asset) {
+    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
+    if (asset == NULL) return NULL;
+    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset));
+    SkMovie* moov = SkMovie::DecodeStream(stream.get());
+    return create_jmovie(env, moov);
+}
+
 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
 
     NPE_CHECK_RETURN_ZERO(env, istream);
 
-    // what is the lifetime of the array? Can the skstream hold onto it?
     jbyteArray byteArray = env->NewByteArray(16*1024);
+    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
     SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
     if (NULL == strm) {
         return 0;
     }
 
-    SkMovie* moov = SkMovie::DecodeStream(strm);
+    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+    // trying to determine the stream's format. The only decoder for movies is GIF, which
+    // will only read 6.
+    // FIXME: Get this number from SkImageDecoder
+    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+    SkASSERT(bufferedStream.get() != NULL);
+
+    SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
     strm->unref();
     return create_jmovie(env, moov);
 }
@@ -128,7 +146,9 @@
     {   "setTime",  "(I)Z", (void*)movie_setTime  },
     {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
                             (void*)movie_draw  },
-    { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
+    { "nativeDecodeAsset", "(I)Landroid/graphics/Movie;",
+                            (void*)movie_decodeAsset },
+    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
                             (void*)movie_decodeStream },
     { "nativeDestructor","(I)V", (void*)movie_destructor },
     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 684b1c1..7e6aeae 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -21,22 +21,30 @@
 #include <androidfw/ResourceTypes.h>
 #include <utils/Log.h>
 
+#include <Caches.h>
+
 #include "SkCanvas.h"
 #include "SkRegion.h"
 #include "GraphicsJNI.h"
 
 #include "JNIHelp.h"
 
-extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
-                const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
-                           const SkPaint* paint, SkRegion** outRegion);
+extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap,
+        const android::Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion);
 
 using namespace android;
 
+/**
+ * IMPORTANT NOTE: 9patch chunks can be manipuated either as an array of bytes
+ * or as a Res_png_9patch instance. It is important to note that the size of the
+ * array required to hold a 9patch chunk is greater than sizeof(Res_png_9patch).
+ * The code below manipulates chunks as Res_png_9patch* types to draw and as
+ * int8_t* to allocate and free the backing storage.
+ */
+
 class SkNinePatchGlue {
 public:
-    static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj)
-    {
+    static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj) {
         if (NULL == obj) {
             return false;
         }
@@ -45,126 +53,110 @@
         }
         const jbyte* array = env->GetByteArrayElements(obj, 0);
         if (array != NULL) {
-            const Res_png_9patch* chunk =
-                                reinterpret_cast<const Res_png_9patch*>(array);
+            const Res_png_9patch* chunk = reinterpret_cast<const Res_png_9patch*>(array);
             int8_t wasDeserialized = chunk->wasDeserialized;
-            env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array),
-                                          JNI_ABORT);
+            env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array), JNI_ABORT);
             return wasDeserialized != -1;
         }
         return false;
     }
 
-    static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj)
-    {
-        if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) {
+    static int8_t* validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj) {
+        size_t chunkSize = env->GetArrayLength(obj);
+        if (chunkSize < (int) (sizeof(Res_png_9patch))) {
             jniThrowRuntimeException(env, "Array too small for chunk.");
-            return;
+            return NULL;
         }
 
-        // XXX Also check that dimensions are correct.
+        int8_t* storage = new int8_t[chunkSize];
+        // This call copies the content of the jbyteArray
+        env->GetByteArrayRegion(obj, 0, chunkSize, reinterpret_cast<jbyte*>(storage));
+        // Deserialize in place, return the array we just allocated
+        return (int8_t*) Res_png_9patch::deserialize(storage);
     }
 
-    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
-                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
-                      jint destDensity, jint srcDensity)
-    {
-        size_t chunkSize = env->GetArrayLength(chunkObj);
-        void* storage = alloca(chunkSize);
-        env->GetByteArrayRegion(chunkObj, 0, chunkSize,
-                                reinterpret_cast<jbyte*>(storage));
-        if (!env->ExceptionCheck()) {
-            // need to deserialize the chunk
-            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
-            assert(chunkSize == chunk->serializedSize());
-            // this relies on deserialization being done in place
-            Res_png_9patch::deserialize(chunk);
+    static void finalize(JNIEnv* env, jobject, int8_t* patch) {
+#ifdef USE_OPENGL_RENDERER
+        if (android::uirenderer::Caches::hasInstance()) {
+            Res_png_9patch* p = (Res_png_9patch*) patch;
+            android::uirenderer::Caches::getInstance().resourceCache.destructor(p);
+            return;
+        }
+#endif // USE_OPENGL_RENDERER
+        delete[] patch;
+    }
 
-            if (destDensity == srcDensity || destDensity == 0
-                    || srcDensity == 0) {
-                ALOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
-                        SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
-                        SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
-                NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
-            } else {
-                canvas->save();
+    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap* bitmap,
+            Res_png_9patch* chunk, const SkPaint* paint, jint destDensity, jint srcDensity) {
+        if (destDensity == srcDensity || destDensity == 0 || srcDensity == 0) {
+            ALOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
+                    SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+                    SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
+            NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
+        } else {
+            canvas->save();
 
-                SkScalar scale = SkFloatToScalar(destDensity / (float)srcDensity);
-                canvas->translate(bounds.fLeft, bounds.fTop);
-                canvas->scale(scale, scale);
+            SkScalar scale = SkFloatToScalar(destDensity / (float)srcDensity);
+            canvas->translate(bounds.fLeft, bounds.fTop);
+            canvas->scale(scale, scale);
 
-                bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale);
-                bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
-                bounds.fLeft = bounds.fTop = 0;
+            bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale);
+            bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
+            bounds.fLeft = bounds.fTop = 0;
 
-                ALOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
-                        SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
-                        SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
-                        srcDensity, destDensity);
+            ALOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
+                    SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+                    SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
+                    srcDensity, destDensity);
 
-                NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
+            NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
 
-                canvas->restore();
-            }
+            canvas->restore();
         }
     }
 
     static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
-                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
-                      jint destDensity, jint srcDensity)
-    {
+            const SkBitmap* bitmap, Res_png_9patch* chunk, const SkPaint* paint,
+            jint destDensity, jint srcDensity) {
         SkASSERT(canvas);
         SkASSERT(boundsRectF);
         SkASSERT(bitmap);
-        SkASSERT(chunkObj);
+        SkASSERT(chunk);
         // paint is optional
 
-        SkRect      bounds;
+        SkRect bounds;
         GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
 
-        draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
+        draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
     }
 
     static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
-                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
-                      jint destDensity, jint srcDensity)
-    {
+            const SkBitmap* bitmap, Res_png_9patch* chunk, const SkPaint* paint,
+            jint destDensity, jint srcDensity) {
         SkASSERT(canvas);
         SkASSERT(boundsRect);
         SkASSERT(bitmap);
-        SkASSERT(chunkObj);
+        SkASSERT(chunk);
         // paint is optional
 
-        SkRect      bounds;
+        SkRect bounds;
         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
-        draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
+        draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
     }
 
-    static jint getTransparentRegion(JNIEnv* env, jobject,
-                    const SkBitmap* bitmap, jbyteArray chunkObj,
-                    jobject boundsRect)
-    {
+    static jint getTransparentRegion(JNIEnv* env, jobject, const SkBitmap* bitmap,
+            Res_png_9patch* chunk, jobject boundsRect) {
         SkASSERT(bitmap);
-        SkASSERT(chunkObj);
+        SkASSERT(chunk);
         SkASSERT(boundsRect);
 
-        SkRect      bounds;
+        SkRect bounds;
         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
-        size_t chunkSize = env->GetArrayLength(chunkObj);
-        void* storage = alloca(chunkSize);
-        env->GetByteArrayRegion(chunkObj, 0, chunkSize,
-                                reinterpret_cast<jbyte*>(storage));
-        if (!env->ExceptionCheck()) {
-            // need to deserialize the chunk
-            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
-            assert(chunkSize == chunk->serializedSize());
-            // this relies on deserialization being done in place
-            Res_png_9patch::deserialize(chunk);
-            SkRegion* region = NULL;
-            NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
-            return (jint)region;
-        }
-        return 0;
+
+        SkRegion* region = NULL;
+        NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
+
+        return (jint) region;
     }
 
 };
@@ -174,18 +166,16 @@
 #include <android_runtime/AndroidRuntime.h>
 
 static JNINativeMethod gNinePatchMethods[] = {
-    { "isNinePatchChunk", "([B)Z",                      (void*)SkNinePatchGlue::isNinePatchChunk   },
-    { "validateNinePatchChunk", "(I[B)V",               (void*)SkNinePatchGlue::validateNinePatchChunk   },
-    { "nativeDraw", "(ILandroid/graphics/RectF;I[BIII)V", (void*)SkNinePatchGlue::drawF   },
-    { "nativeDraw", "(ILandroid/graphics/Rect;I[BIII)V",  (void*)SkNinePatchGlue::drawI   },
-    { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I",
-                                                        (void*)SkNinePatchGlue::getTransparentRegion   }
+    { "isNinePatchChunk", "([B)Z",                        (void*) SkNinePatchGlue::isNinePatchChunk },
+    { "validateNinePatchChunk", "(I[B)I",                 (void*) SkNinePatchGlue::validateNinePatchChunk },
+    { "nativeFinalize", "(I)V",                           (void*) SkNinePatchGlue::finalize },
+    { "nativeDraw", "(ILandroid/graphics/RectF;IIIII)V",  (void*) SkNinePatchGlue::drawF },
+    { "nativeDraw", "(ILandroid/graphics/Rect;IIIII)V",   (void*) SkNinePatchGlue::drawI },
+    { "nativeGetTransparentRegion", "(IILandroid/graphics/Rect;)I",
+                                                          (void*) SkNinePatchGlue::getTransparentRegion }
 };
 
-int register_android_graphics_NinePatch(JNIEnv* env)
-{
+int register_android_graphics_NinePatch(JNIEnv* env) {
     return android::AndroidRuntime::registerNativeMethods(env,
-                                                       "android/graphics/NinePatch",
-                                                       gNinePatchMethods,
-                                                       SK_ARRAY_COUNT(gNinePatchMethods));
+            "android/graphics/NinePatch", gNinePatchMethods, SK_ARRAY_COUNT(gNinePatchMethods));
 }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 5454c08..40e0731 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -58,6 +58,10 @@
 static void defaultSettingsForAndroid(SkPaint* paint) {
     // GlyphID encoding is required because we are using Harfbuzz shaping
     paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+    SkPaintOptionsAndroid paintOpts = paint->getPaintOptionsAndroid();
+    paintOpts.setUseFontFallbacks(true);
+    paint->setPaintOptionsAndroid(paintOpts);
 }
 
 class SkPaintGlue {
@@ -109,7 +113,7 @@
     static void setHinting(JNIEnv* env, jobject paint, jint mode) {
         NPE_CHECK_RETURN_VOID(env, paint);
         GraphicsJNI::getNativePaint(env, paint)->setHinting(
-                mode == 0 ? SkPaint::kNo_Hinting : SkPaint::kSlight_Hinting);
+                mode == 0 ? SkPaint::kNo_Hinting : SkPaint::kNormal_Hinting);
     }
 
     static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
@@ -300,7 +304,10 @@
         ScopedUtfChars localeChars(env, locale);
         char langTag[ULOC_FULLNAME_CAPACITY];
         toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str());
-        obj->setLanguage(SkLanguage(langTag));
+
+        SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid();
+        paintOpts.setLanguage(langTag);
+        obj->setPaintOptionsAndroid(paintOpts);
     }
 
     static jfloat getTextSize(JNIEnv* env, jobject paint) {
@@ -757,8 +764,6 @@
     static void doTextBounds(JNIEnv* env, const jchar* text, int count,
                              jobject bounds, const SkPaint& paint, jint bidiFlags) {
         SkRect  r;
-        r.set(0,0,0,0);
-
         SkIRect ir;
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index eb9e004..ab7f1dc 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -25,6 +25,7 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include "SkPath.h"
+#include "pathops/SkPathOps.h"
 
 #include <Caches.h>
 
@@ -67,8 +68,7 @@
         return obj->getFillType();
     }
  
-    static void setFillType(JNIEnv* env, jobject clazz, SkPath* path,
-                            SkPath::FillType ft) {
+    static void setFillType(JNIEnv* env, jobject clazz, SkPath* path, SkPath::FillType ft) {
         path->setFillType(ft);
     }
  
@@ -200,7 +200,7 @@
     }
  
     static void addRoundRectXY(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect,
-                               jfloat rx, jfloat ry, SkPath::Direction dir) {
+            jfloat rx, jfloat ry, SkPath::Direction dir) {
         SkRect rect_;
         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
         SkScalar rx_ = SkFloatToScalar(rx);
@@ -209,7 +209,7 @@
     }
     
     static void addRoundRect8(JNIEnv* env, jobject, SkPath* obj, jobject rect,
-                              jfloatArray array, SkPath::Direction dir) {
+            jfloatArray array, SkPath::Direction dir) {
         SkRect rect_;
         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
         AutoJavaFloatArray  afa(env, array, 8);
@@ -261,7 +261,10 @@
     static void transform__Matrix(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix) {
         obj->transform(*matrix);
     }
- 
+
+    static jboolean op(JNIEnv* env, jobject clazz, SkPath* p1, SkPath* p2, SkPathOp op, SkPath* r) {
+         return Op(*p1, *p2, op, r);
+     }
 };
 
 static JNINativeMethod methods[] = {
@@ -301,7 +304,8 @@
     {"native_offset","(IFF)V", (void*) SkPathGlue::offset__FF},
     {"native_setLastPoint","(IFF)V", (void*) SkPathGlue::setLastPoint},
     {"native_transform","(III)V", (void*) SkPathGlue::transform__MatrixPath},
-    {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix}
+    {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix},
+    {"native_op","(IIII)Z", (void*) SkPathGlue::op}
 };
 
 int register_android_graphics_Path(JNIEnv* env) {
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index f28fc26..fcf22b8 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -20,6 +20,7 @@
 
 #include "SkCanvas.h"
 #include "SkPicture.h"
+#include "SkStream.h"
 #include "SkTemplates.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 
@@ -40,7 +41,7 @@
         SkPicture* picture = NULL;
         SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
         if (strm) {
-            picture = new SkPicture(strm);
+            picture = SkPicture::CreateFromStream(strm);
             delete strm;
         }
         return picture;
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 753f5dc..0c9b3bc 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -18,6 +18,9 @@
 
 #include <stdio.h>
 
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
@@ -34,12 +37,13 @@
 namespace android {
 
 static const char* const OutOfResourcesException =
-    "android/graphics/SurfaceTexture$OutOfResourcesException";
+    "android/view/Surface$OutOfResourcesException";
 static const char* const IllegalStateException = "java/lang/IllegalStateException";
 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
 
 struct fields_t {
     jfieldID  surfaceTexture;
+    jfieldID  bufferQueue;
     jfieldID  frameAvailableListener;
     jmethodID postEvent;
 };
@@ -61,6 +65,20 @@
     env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
 }
 
+static void SurfaceTexture_setBufferQueue(JNIEnv* env, jobject thiz,
+        const sp<BufferQueue>& bq)
+{
+    BufferQueue* const p =
+        (BufferQueue*)env->GetIntField(thiz, fields.bufferQueue);
+    if (bq.get()) {
+        bq->incStrong((void*)SurfaceTexture_setBufferQueue);
+    }
+    if (p) {
+        p->decStrong((void*)SurfaceTexture_setBufferQueue);
+    }
+    env->SetIntField(thiz, fields.bufferQueue, (int)bq.get());
+}
+
 static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
         jobject thiz, sp<GLConsumer::FrameAvailableListener> listener)
 {
@@ -76,23 +94,22 @@
     env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get());
 }
 
-sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env,
-        jobject thiz)
-{
+sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
     return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
 }
 
-sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
-        JNIEnv* env, jobject thiz)
-{
+sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
+    return (BufferQueue*)env->GetIntField(thiz, fields.bufferQueue);
+}
+
+sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz) {
     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
-    sp<Surface> surfaceTextureClient(surfaceTexture != NULL ?
-            new Surface(surfaceTexture->getBufferQueue()) : NULL);
+    sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
+    sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
     return surfaceTextureClient;
 }
 
-bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz)
-{
+bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
     jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
     return env->IsInstanceOf(thiz, surfaceTextureClass);
 }
@@ -175,6 +192,12 @@
 
 // ----------------------------------------------------------------------------
 
+
+#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
+#define ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID "mBufferQueue"
+#define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \
+                                         "mFrameAvailableListener"
+
 static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
 {
     fields.surfaceTexture = env->GetFieldID(clazz,
@@ -183,6 +206,12 @@
         ALOGE("can't find android/graphics/SurfaceTexture.%s",
                 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
     }
+    fields.bufferQueue = env->GetFieldID(clazz,
+            ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID, "I");
+    if (fields.bufferQueue == NULL) {
+        ALOGE("can't find android/graphics/SurfaceTexture.%s",
+                ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID);
+    }
     fields.frameAvailableListener = env->GetFieldID(clazz,
             ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "I");
     if (fields.frameAvailableListener == NULL) {
@@ -197,16 +226,24 @@
     }
 }
 
-static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
-        jobject weakThiz, jboolean allowSynchronous)
+static void SurfaceTexture_init(JNIEnv* env, jobject thiz,
+        jint texName, jboolean singleBufferMode, jobject weakThiz)
 {
-    sp<GLConsumer> surfaceTexture(new GLConsumer(texName, allowSynchronous));
+    sp<BufferQueue> bq = new BufferQueue();
+
+    if (singleBufferMode) {
+        bq->disableAsyncBuffer();
+        bq->setDefaultMaxBufferCount(1);
+    }
+
+    sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName, GL_TEXTURE_EXTERNAL_OES, true, true));
     if (surfaceTexture == 0) {
         jniThrowException(env, OutOfResourcesException,
                 "Unable to create native SurfaceTexture");
         return;
     }
     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
+    SurfaceTexture_setBufferQueue(env, thiz, bq);
 
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
@@ -227,11 +264,11 @@
     surfaceTexture->setFrameAvailableListener(0);
     SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
     SurfaceTexture_setSurfaceTexture(env, thiz, 0);
+    SurfaceTexture_setBufferQueue(env, thiz, 0);
 }
 
 static void SurfaceTexture_setDefaultBufferSize(
-        JNIEnv* env, jobject thiz, jint width, jint height)
-{
+        JNIEnv* env, jobject thiz, jint width, jint height) {
     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     surfaceTexture->setDefaultBufferSize(width, height);
 }
@@ -248,6 +285,18 @@
     }
 }
 
+static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz)
+{
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    status_t err = surfaceTexture->releaseTexImage();
+    if (err == INVALID_OPERATION) {
+        jniThrowException(env, IllegalStateException, "Unable to release texture contents (see "
+                "logcat for details)");
+    } else if (err < 0) {
+        jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
+    }
+}
+
 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
 {
     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
@@ -285,10 +334,11 @@
 
 static JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
-    {"nativeInit",                 "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
+    {"nativeInit",                 "(IZLjava/lang/Object;)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
     {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
     {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
+    {"nativeReleaseTexImage",      "()V",   (void*)SurfaceTexture_releaseTexImage },
     {"nativeDetachFromGLContext",  "()I",   (void*)SurfaceTexture_detachFromGLContext },
     {"nativeAttachToGLContext",    "(I)I",   (void*)SurfaceTexture_attachToGLContext },
     {"nativeGetTransformMatrix",   "([F)V", (void*)SurfaceTexture_getTransformMatrix },
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index b2cf9c1..73f3639 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -20,7 +20,6 @@
 
 #include "TextLayoutCache.h"
 #include "TextLayout.h"
-#include "SkFontHost.h"
 #include "SkTypeface_android.h"
 #include "HarfBuzzNGFaceSkia.h"
 #include <unicode/unistr.h>
@@ -219,7 +218,8 @@
  */
 TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
         dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
-        hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
+        hinting(SkPaint::kNo_Hinting) {
+    paintOpts.setUseFontFallbacks(true);
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
@@ -233,8 +233,7 @@
     textScaleX = paint->getTextScaleX();
     flags = paint->getFlags();
     hinting = paint->getHinting();
-    variant = paint->getFontVariant();
-    language = paint->getLanguage();
+    paintOpts = paint->getPaintOptionsAndroid();
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
@@ -249,8 +248,7 @@
         textScaleX(other.textScaleX),
         flags(other.flags),
         hinting(other.hinting),
-        variant(other.variant),
-        language(other.language) {
+        paintOpts(other.paintOpts) {
 }
 
 int TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
@@ -284,11 +282,8 @@
     deltaInt = lhs.dirFlags - rhs.dirFlags;
     if (deltaInt) return (deltaInt);
 
-    deltaInt = lhs.variant - rhs.variant;
-    if (deltaInt) return (deltaInt);
-
-    if (lhs.language < rhs.language) return -1;
-    if (lhs.language > rhs.language) return +1;
+    if (lhs.paintOpts != rhs.paintOpts)
+        return memcmp(&lhs.paintOpts, &rhs.paintOpts, sizeof(SkPaintOptionsAndroid));
 
     return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
 }
@@ -307,7 +302,7 @@
     hash = JenkinsHashMix(hash, hash_type(textScaleX));
     hash = JenkinsHashMix(hash, flags);
     hash = JenkinsHashMix(hash, hinting);
-    hash = JenkinsHashMix(hash, variant);
+    hash = JenkinsHashMix(hash, paintOpts.getFontVariant());
     // Note: leaving out language is not problematic, as equality comparisons
     // are still valid - the only bad thing that could happen is collisions.
     hash = JenkinsHashMixShorts(hash, getText(), contextCount);
@@ -319,6 +314,7 @@
  */
 TextLayoutValue::TextLayoutValue(size_t contextCount) :
         mTotalAdvance(0), mElapsedTime(0) {
+    mBounds.setEmpty();
     // Give a hint for advances and glyphs vectors size
     mAdvances.setCapacity(contextCount);
     mGlyphs.setCapacity(contextCount);
@@ -346,11 +342,11 @@
     hb_buffer_destroy(mBuffer);
 }
 
-void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount, int dirFlags) {
-
+void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint,
+        const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags) {
     computeValues(paint, chars, start, count, contextCount, dirFlags,
-            &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
+            &value->mAdvances, &value->mTotalAdvance, &value->mBounds,
+            &value->mGlyphs, &value->mPos);
 #if DEBUG_ADVANCES
     ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
             contextCount, value->mTotalAdvance);
@@ -359,7 +355,7 @@
 
 void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
         size_t start, size_t count, size_t contextCount, int dirFlags,
-        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
+        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
         Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
         *outTotalAdvance = 0;
         if (!count) {
@@ -455,7 +451,7 @@
                                     i, startRun, lengthRun, isRTL);
 #endif
                             computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
-                                    outAdvances, outTotalAdvance, outGlyphs, outPos);
+                                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
 
                         }
                     }
@@ -479,7 +475,7 @@
                     "-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
 #endif
             computeRunValues(paint, chars, start, count, contextCount, isRTL,
-                    outAdvances, outTotalAdvance, outGlyphs, outPos);
+                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
         }
 
 #if DEBUG_GLYPHS
@@ -676,7 +672,7 @@
 
 void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* contextChars,
         size_t start, size_t count, size_t contextCount, bool isRTL,
-        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
+        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
         Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
     if (!count) {
         // We cannot shape an empty run.
@@ -698,8 +694,7 @@
     mShapingPaint.setTextScaleX(paint->getTextScaleX());
     mShapingPaint.setFlags(paint->getFlags());
     mShapingPaint.setHinting(paint->getHinting());
-    mShapingPaint.setFontVariant(paint->getFontVariant());
-    mShapingPaint.setLanguage(paint->getLanguage());
+    mShapingPaint.setPaintOptionsAndroid(paint->getPaintOptionsAndroid());
 
     // Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
     // into the shaperItem
@@ -750,12 +745,22 @@
             size_t cluster = info[i].cluster - start;
             float xAdvance = HBFixedToFloat(positions[i].x_advance);
             outAdvances->replaceAt(outAdvances->itemAt(cluster) + xAdvance, cluster);
-            outGlyphs->add(info[i].codepoint + glyphBaseCount);
+            jchar glyphId = info[i].codepoint + glyphBaseCount;
+            outGlyphs->add(glyphId);
             float xo = HBFixedToFloat(positions[i].x_offset);
             float yo = -HBFixedToFloat(positions[i].y_offset);
-            outPos->add(totalAdvance + xo + yo * skewX);
-            outPos->add(yo);
+
+            float xpos = totalAdvance + xo + yo * skewX;
+            float ypos = yo;
+            outPos->add(xpos);
+            outPos->add(ypos);
             totalAdvance += xAdvance;
+
+            // TODO: consider using glyph cache
+            const SkGlyph& metrics = mShapingPaint.getGlyphMetrics(glyphId, NULL);
+            outBounds->join(xpos + metrics.fLeft, ypos + metrics.fTop,
+                    xpos + metrics.fLeft + metrics.fWidth, ypos + metrics.fTop + metrics.fHeight);
+
         }
     }
 
@@ -839,7 +844,7 @@
         if (typeface) {
             SkSafeRef(typeface);
         } else {
-            typeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
+            typeface = SkTypeface::CreateFromName(NULL, SkTypeface::kNormal);
 #if DEBUG_GLYPHS
             ALOGD("Using Default Typeface (normal style)");
 #endif
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 5414a11..54704ec 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -28,7 +28,6 @@
 #include <utils/Singleton.h>
 
 #include <SkAutoKern.h>
-#include <SkLanguage.h>
 #include <SkPaint.h>
 #include <SkTemplates.h>
 #include <SkTypeface.h>
@@ -104,8 +103,7 @@
     SkScalar textScaleX;
     uint32_t flags;
     SkPaint::Hinting hinting;
-    SkPaint::FontVariant variant;
-    SkLanguage language;
+    SkPaintOptionsAndroid paintOpts;
 
 }; // TextLayoutCacheKey
 
@@ -134,6 +132,7 @@
     inline const jfloat* getAdvances() const { return mAdvances.array(); }
     inline size_t getAdvancesCount() const { return mAdvances.size(); }
     inline jfloat getTotalAdvance() const { return mTotalAdvance; }
+    inline const SkRect& getBounds() const { return mBounds; }
     inline const jchar* getGlyphs() const { return mGlyphs.array(); }
     inline size_t getGlyphsCount() const { return mGlyphs.size(); }
     inline const jfloat* getPos() const { return mPos.array(); }
@@ -150,6 +149,11 @@
     jfloat mTotalAdvance;
 
     /**
+     * Bounds containing all glyphs
+     */
+    SkRect mBounds;
+
+    /**
      * Glyphs vector
      */
     Vector<jchar> mGlyphs;
@@ -208,12 +212,12 @@
 
     void computeValues(const SkPaint* paint, const UChar* chars,
             size_t start, size_t count, size_t contextCount, int dirFlags,
-            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
+            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
     void computeRunValues(const SkPaint* paint, const UChar* chars,
             size_t start, size_t count, size_t contextCount, bool isRTL,
-            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
+            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
     SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style);
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e056b61..a7a0bb2 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -29,20 +29,28 @@
 
 static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name,
                                    SkTypeface::Style style) {
-    SkTypeface* face;
+    SkTypeface* face = NULL;
 
-    if (NULL == name) {
-        face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style);
-    }
-    else {
+    if (NULL != name) {
         AutoJavaStringToUTF8    str(env, name);
         face = SkTypeface::CreateFromName(str.c_str(), style);
     }
+
+    // return the default font at the best style if no exact match exists
+    if (NULL == face) {
+        face = SkTypeface::CreateFromName(NULL, style);
+    }
     return face;
 }
 
 static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) {
-    return SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
+    SkTypeface* face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
+    // return the default font at the best style if the requested style does not
+    // exist in the provided family
+    if (NULL == face) {
+        face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style);
+    }
+    return face;
 }
 
 static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index cf6977e..b7d1f3a 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -28,12 +28,28 @@
     return true;
 }
 
+size_t AssetStreamAdaptor::getLength() const {
+    return fAsset->getLength();
+}
+
+bool AssetStreamAdaptor::isAtEnd() const {
+    return fAsset->getRemainingLength() == 0;
+}
+
+SkStreamRewindable* AssetStreamAdaptor::duplicate() const {
+    SkASSERT(false);
+    // Cannot create a duplicate, since each AssetStreamAdaptor
+    // would be modifying the Asset.
+    //return new AssetStreamAdaptor(fAsset);
+    return NULL;
+}
+
 size_t AssetStreamAdaptor::read(void* buffer, size_t size) {
     ssize_t amount;
 
     if (NULL == buffer) {
-        if (0 == size) {  // caller is asking us for our total length
-            return fAsset->getLength();
+        if (0 == size) {
+            return 0;
         }
         // asset->seek returns new total offset
         // we want to return amount that was skipped
@@ -62,6 +78,34 @@
     return amount;
 }
 
+SkMemoryStream* android::CopyAssetToStream(Asset* asset) {
+    if (NULL == asset) {
+        return NULL;
+    }
+
+    off64_t size = asset->seek(0, SEEK_SET);
+    if ((off64_t)-1 == size) {
+        SkDebugf("---- copyAsset: asset rewind failed\n");
+        return NULL;
+    }
+
+    size = asset->getLength();
+    if (size <= 0) {
+        SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size);
+        return NULL;
+    }
+
+    SkMemoryStream* stream = new SkMemoryStream(size);
+    void* data = const_cast<void*>(stream->getMemoryBase());
+    off64_t len = asset->read(data, size);
+    if (len != size) {
+        SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len);
+        delete stream;
+        stream = NULL;
+    }
+    return stream;
+}
+
 jobject android::nullObjectReturn(const char msg[]) {
     if (msg) {
         SkDebugf("--- %s\n", msg);
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index 75ceaa2..a1ac72a 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -26,16 +26,27 @@
 
 namespace android {
 
-class AssetStreamAdaptor : public SkStream {
+class AssetStreamAdaptor : public SkStreamRewindable {
 public:
     AssetStreamAdaptor(Asset* a) : fAsset(a) {}
     virtual bool rewind();
     virtual size_t read(void* buffer, size_t size);
+    virtual bool hasLength() const { return true; }
+    virtual size_t getLength() const;
+    virtual bool isAtEnd() const;
 
+    virtual SkStreamRewindable* duplicate() const;
 private:
     Asset*  fAsset;
 };
 
+/**
+ *  Make a deep copy of the asset, and return it as a stream, or NULL if there
+ *  was an error.
+ *  FIXME: If we could "ref/reopen" the asset, we may not need to copy it here.
+ */
+
+SkMemoryStream* CopyAssetToStream(Asset*);
 
 /** Restore the file descriptor's offset in our destructor
  */
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
new file mode 100644
index 0000000..b57a0fe
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkCanvas.h"
+#include "SkPDFDevice.h"
+#include "SkPDFDocument.h"
+#include "SkRect.h"
+#include "SkSize.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+#include "JNIHelp.h"
+
+namespace android {
+
+#define LOGD(x...) do { Log::Instance()->printf(Log::ELogD, x); } while(0)
+
+static jint nativeCreateDocument(JNIEnv* env, jobject clazz) {
+    return reinterpret_cast<jint>(new SkPDFDocument());
+}
+
+static void nativeFinalize(JNIEnv* env, jobject thiz, jint documentPtr) {
+    delete reinterpret_cast<SkPDFDocument*>(documentPtr);
+}
+
+static jint nativeCreatePage(JNIEnv* env, jobject thiz, jint pageWidth, jint pageHeight,
+        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
+
+    SkMatrix transformation;
+    transformation.setTranslate(contentLeft, contentTop);
+
+    SkISize skPageSize = SkISize::Make(pageWidth, pageHeight);
+    SkISize skContentSize = SkISize::Make(contentRight - contentLeft, contentBottom - contentTop);
+
+    SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize, skContentSize, transformation);
+    return reinterpret_cast<jint>(new SkCanvas(skPdfDevice));
+}
+
+static void nativeAppendPage(JNIEnv* env, jobject thiz, jint documentPtr, jint pagePtr) {
+    SkCanvas* page = reinterpret_cast<SkCanvas*>(pagePtr);
+    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
+    SkPDFDevice* device = static_cast<SkPDFDevice*>(page->getDevice());
+    document->appendPage(device);
+}
+
+static void nativeWriteTo(JNIEnv* env, jobject clazz, jint documentPtr,
+        jobject out, jbyteArray chunk) {
+    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
+    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
+    document->emitPDF(skWStream);
+    delete skWStream;
+}
+
+static JNINativeMethod gPdfDocument_Methods[] = {
+    {"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
+    {"nativeFinalize", "(I)V", (void*) nativeFinalize},
+    {"nativeCreatePage", "(IIIIII)I",
+            (void*) nativeCreatePage},
+    {"nativeAppendPage", "(II)V", (void*) nativeAppendPage},
+    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo}
+};
+
+int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
+    int result = android::AndroidRuntime::registerNativeMethods(
+            env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
+            NELEM(gPdfDocument_Methods));
+    return result;
+}
+
+};
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 9fc01e1..5418006 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -25,7 +25,7 @@
 #include <android_runtime/android_util_AssetManager.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
 
 #include <gui/Surface.h>
 
@@ -306,19 +306,23 @@
         code->internalDataPath = code->internalDataPathObj.string();
         env->ReleaseStringUTFChars(internalDataDir, dirStr);
     
-        dirStr = env->GetStringUTFChars(externalDataDir, NULL);
-        code->externalDataPathObj = dirStr;
+        if (externalDataDir != NULL) {
+            dirStr = env->GetStringUTFChars(externalDataDir, NULL);
+            code->externalDataPathObj = dirStr;
+            env->ReleaseStringUTFChars(externalDataDir, dirStr);
+        }
         code->externalDataPath = code->externalDataPathObj.string();
-        env->ReleaseStringUTFChars(externalDataDir, dirStr);
 
         code->sdkVersion = sdkVersion;
         
         code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
 
-        dirStr = env->GetStringUTFChars(obbDir, NULL);
-        code->obbPathObj = dirStr;
+        if (obbDir != NULL) {
+            dirStr = env->GetStringUTFChars(obbDir, NULL);
+            code->obbPathObj = dirStr;
+            env->ReleaseStringUTFChars(obbDir, dirStr);
+        }
         code->obbPath = code->obbPathObj.string();
-        env->ReleaseStringUTFChars(obbDir, dirStr);
 
         jbyte* rawSavedState = NULL;
         jsize rawSavedSize = 0;
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index f70f0d1..6e496fd 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -19,6 +19,7 @@
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
 
 #include <utils/Log.h>
 #include <utils/String8.h>
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 4383997..5276934 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -6,6 +6,7 @@
 #include <ScopedUtfChars.h>
 
 #include "EmojiFactory.h"
+#include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
 #include <dlfcn.h>
@@ -92,9 +93,6 @@
 static pthread_once_t g_once = PTHREAD_ONCE_INIT;
 static bool lib_emoji_factory_is_ready;
 
-static jclass    gBitmap_class;
-static jmethodID gBitmap_constructorMethodID;
-
 static jclass    gEmojiFactory_class;
 static jmethodID gEmojiFactory_constructorMethodID;
 
@@ -172,13 +170,8 @@
     return NULL;
   }
 
-  jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
-      static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)), NULL, false, NULL, -1);
-  if (env->ExceptionCheck() != 0) {
-    ALOGE("*** Uncaught exception returned from Java call!\n");
-    env->ExceptionDescribe();
-  }
-  return obj;
+  return GraphicsJNI::createBitmap(env, bitmap,
+      GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
 }
 
 static void android_emoji_EmojiFactory_destructor(
@@ -281,9 +274,6 @@
 }
 
 int register_android_emoji_EmojiFactory(JNIEnv* env) {
-  gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
-  gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
-                                                 "(I[BZ[BI)V");
   gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
   gEmojiFactory_constructorMethodID = env->GetMethodID(
       gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
diff --git a/core/jni/android_graphics_PixelFormat.cpp b/core/jni/android_graphics_PixelFormat.cpp
deleted file mode 100644
index 1fc363b..0000000
--- a/core/jni/android_graphics_PixelFormat.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <assert.h>
-
-#include <ui/PixelFormat.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/misc.h>
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-struct offsets_t {
-    jfieldID bytesPerPixel;
-    jfieldID bitsPerPixel;
-};
-
-static offsets_t offsets;
-
-// ----------------------------------------------------------------------------
-
-static void android_graphics_getPixelFormatInfo(
-        JNIEnv* env, jobject clazz, jint format, jobject pixelFormatObject)
-{
-    PixelFormatInfo info;
-    status_t err;
-
-    // we need this for backward compatibility with PixelFormat's
-    // deprecated constants
-    switch (format) {
-    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-        // defined as the bytes per pixel of the Y plane
-        info.bytesPerPixel = 1;
-        info.bitsPerPixel = 16;
-        goto done;
-    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-        // defined as the bytes per pixel of the Y plane
-        info.bytesPerPixel = 1;
-        info.bitsPerPixel = 12;
-        goto done;
-    case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        // defined as the bytes per pixel of the Y plane
-        info.bytesPerPixel = 1;
-        info.bitsPerPixel = 16;
-        goto done;
-    }
-
-    err = getPixelFormatInfo(format, &info);
-    if (err < 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-done:
-    env->SetIntField(pixelFormatObject, offsets.bytesPerPixel, info.bytesPerPixel);
-    env->SetIntField(pixelFormatObject, offsets.bitsPerPixel,  info.bitsPerPixel);
-}
-// ----------------------------------------------------------------------------
-
-const char* const kClassPathName = "android/graphics/PixelFormat";
-
-static void nativeClassInit(JNIEnv* env, jclass clazz);
-
-static JNINativeMethod gMethods[] = {
-    {   "nativeClassInit", "()V",
-        (void*)nativeClassInit },
-	{   "getPixelFormatInfo", "(ILandroid/graphics/PixelFormat;)V",
-        (void*)android_graphics_getPixelFormatInfo
-    }
-};
-
-void nativeClassInit(JNIEnv* env, jclass clazz)
-{
-    offsets.bytesPerPixel = env->GetFieldID(clazz, "bytesPerPixel", "I");
-    offsets.bitsPerPixel  = env->GetFieldID(clazz, "bitsPerPixel", "I");
-}
-
-int register_android_graphics_PixelFormat(JNIEnv* env)
-{
-    return AndroidRuntime::registerNativeMethods(env,
-            kClassPathName, gMethods, NELEM(gMethods));
-}
-
-};
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 686e4e3..09d8d0f 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -553,7 +553,7 @@
         }
     }
 
-    if (camera->setPreviewTexture(gbp) != NO_ERROR) {
+    if (camera->setPreviewTarget(gbp) != NO_ERROR) {
         jniThrowException(env, "java/io/IOException", "setPreviewTexture failed");
     }
 }
@@ -565,14 +565,10 @@
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
     if (camera == 0) return;
 
-    sp<BufferQueue> bufferQueue = NULL;
+    sp<IGraphicBufferProducer> producer = NULL;
     if (jSurfaceTexture != NULL) {
-        sp<GLConsumer> surfaceTexture =
-            SurfaceTexture_getSurfaceTexture(env, jSurfaceTexture);
-        if (surfaceTexture != NULL) {
-            bufferQueue = surfaceTexture->getBufferQueue();
-        }
-        else {
+        producer = SurfaceTexture_getProducer(env, jSurfaceTexture);
+        if (producer == NULL) {
             jniThrowException(env, "java/lang/IllegalArgumentException",
                     "SurfaceTexture already released in setPreviewTexture");
             return;
@@ -580,12 +576,36 @@
 
     }
 
-    if (camera->setPreviewTexture(bufferQueue) != NO_ERROR) {
+    if (camera->setPreviewTarget(producer) != NO_ERROR) {
         jniThrowException(env, "java/io/IOException",
                 "setPreviewTexture failed");
     }
 }
 
+static void android_hardware_Camera_setPreviewCallbackSurface(JNIEnv *env,
+        jobject thiz, jobject jSurface)
+{
+    ALOGV("setPreviewCallbackSurface");
+    JNICameraContext* context;
+    sp<Camera> camera = get_native_camera(env, thiz, &context);
+    if (camera == 0) return;
+
+    sp<IGraphicBufferProducer> gbp;
+    sp<Surface> surface;
+    if (jSurface) {
+        surface = android_view_Surface_getSurface(env, jSurface);
+        if (surface != NULL) {
+            gbp = surface->getIGraphicBufferProducer();
+        }
+    }
+    // Clear out normal preview callbacks
+    context->setCallbackMode(env, false, false);
+    // Then set up callback surface
+    if (camera->setPreviewCallbackTarget(gbp) != NO_ERROR) {
+        jniThrowException(env, "java/io/IOException", "setPreviewCallbackTarget failed");
+    }
+}
+
 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
 {
     ALOGV("startPreview");
@@ -881,6 +901,9 @@
   { "setPreviewTexture",
     "(Landroid/graphics/SurfaceTexture;)V",
     (void *)android_hardware_Camera_setPreviewTexture },
+  { "setPreviewCallbackSurface",
+    "(Landroid/view/Surface;)V",
+    (void *)android_hardware_Camera_setPreviewCallbackSurface },
   { "startPreview",
     "()V",
     (void *)android_hardware_Camera_startPreview },
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 6374494..4290a6e 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -31,6 +31,7 @@
 static struct {
     jclass clazz;
     jmethodID dispatchSensorEvent;
+    jmethodID dispatchFlushCompleteEvent;
 } gBaseEventQueueClassInfo;
 
 namespace android {
@@ -46,6 +47,8 @@
     jfieldID    resolution;
     jfieldID    power;
     jfieldID    minDelay;
+    jfieldID    fifoReservedEventCount;
+    jfieldID    fifoMaxEventCount;
 } gSensorOffsets;
 
 
@@ -67,6 +70,9 @@
     sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
     sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
     sensorOffsets.minDelay    = _env->GetFieldID(sensorClass, "mMinDelay",  "I");
+    sensorOffsets.fifoReservedEventCount =
+            _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
+    sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
 }
 
 static jint
@@ -78,7 +84,7 @@
     size_t count = mgr.getSensorList(&sensorList);
     if (size_t(next) >= count)
         return -1;
-    
+
     Sensor const* const list = sensorList[next];
     const SensorOffsets& sensorOffsets(gSensorOffsets);
     jstring name = env->NewStringUTF(list->getName().string());
@@ -92,7 +98,9 @@
     env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
     env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
     env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
-    
+    env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
+                     list->getFifoReservedEventCount());
+    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount());
     next++;
     return size_t(next) < count ? next : 0;
 }
@@ -142,14 +150,28 @@
         while ((n = q->read(buffer, 16)) > 0) {
             for (int i=0 ; i<n ; i++) {
 
-                env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
+                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
+                    // step-counter returns a uint64, but the java API only deals with floats
+                    float value = float(buffer[i].u64.step_counter);
+                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
+                } else {
+                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
+                }
 
-                env->CallVoidMethod(mReceiverObject,
-                        gBaseEventQueueClassInfo.dispatchSensorEvent,
-                        buffer[i].sensor,
-                        mScratch,
-                        buffer[i].vector.status,
-                        buffer[i].timestamp);
+                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+                    // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
+                    // method.
+                    env->CallVoidMethod(mReceiverObject,
+                                        gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
+                                        buffer[i].meta_data.sensor);
+                } else {
+                    env->CallVoidMethod(mReceiverObject,
+                                        gBaseEventQueueClassInfo.dispatchSensorEvent,
+                                        buffer[i].sensor,
+                                        mScratch,
+                                        buffer[i].vector.status,
+                                        buffer[i].timestamp);
+                }
 
                 if (env->ExceptionCheck()) {
                     ALOGE("Exception dispatching input event.");
@@ -180,9 +202,11 @@
     return jint(receiver.get());
 }
 
-static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint us) {
+static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint rate_us,
+                               jint maxBatchReportLatency, jint reservedFlags) {
     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
-    return receiver->getSensorEventQueue()->enableSensor(handle, us);
+    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
+                                                         reservedFlags);
 }
 
 static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
@@ -196,6 +220,10 @@
     receiver->decStrong((void*)nativeInitSensorEventQueue);
 }
 
+static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
+    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
+    return receiver->getSensorEventQueue()->flushSensor(handle);
+}
 
 //----------------------------------------------------------------------------
 
@@ -215,7 +243,7 @@
             (void*)nativeInitSensorEventQueue },
 
     {"nativeEnableSensor",
-            "(III)I",
+            "(IIIII)I",
             (void*)nativeEnableSensor },
 
     {"nativeDisableSensor",
@@ -225,6 +253,10 @@
     {"nativeDestroySensorEventQueue",
             "(I)V",
             (void*)nativeDestroySensorEventQueue },
+
+    {"nativeFlushSensor",
+            "(II)I",
+            (void*)nativeFlushSensor },
 };
 
 }; // namespace android
@@ -254,5 +286,9 @@
             gBaseEventQueueClassInfo.clazz,
             "dispatchSensorEvent", "(I[FIJ)V");
 
+    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
+                  gBaseEventQueueClassInfo.clazz,
+                  "dispatchFlushCompleteEvent", "(I)V");
+
     return 0;
 }
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
new file mode 100644
index 0000000..3c7da1e
--- /dev/null
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -0,0 +1,559 @@
+/*
+**
+** 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.
+*/
+
+// #define LOG_NDEBUG 0
+// #define LOG_NNDEBUG 0
+#define LOG_TAG "CameraMetadata-JNI"
+#include <utils/Log.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_os_Parcel.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <camera/CameraMetadata.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+
+#if defined(LOG_NNDEBUG)
+#if !LOG_NNDEBUG
+#define ALOGVV ALOGV
+#endif
+#else
+#define ALOGVV(...)
+#endif
+
+// fully-qualified class name
+#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
+
+using namespace android;
+
+struct fields_t {
+    jfieldID    metadata_ptr;
+};
+
+static fields_t fields;
+
+namespace {
+struct Helpers {
+    static size_t getTypeSize(uint8_t type) {
+        if (type >= NUM_TYPES) {
+            ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
+            return static_cast<size_t>(-1);
+        }
+
+        return camera_metadata_type_size[type];
+    }
+
+    static status_t updateAny(CameraMetadata *metadata,
+                          uint32_t tag,
+                          uint32_t type,
+                          const void *data,
+                          size_t dataBytes) {
+
+        if (type >= NUM_TYPES) {
+            ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
+            return INVALID_OPERATION;
+        }
+
+        size_t typeSize = getTypeSize(type);
+
+        if (dataBytes % typeSize != 0) {
+            ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize "
+                  "(%ud)", __FUNCTION__, dataBytes, typeSize);
+            return BAD_VALUE;
+        }
+
+        size_t dataCount = dataBytes / typeSize;
+
+        switch(type) {
+#define METADATA_UPDATE(runtime_type, compile_type)                            \
+            case runtime_type: {                                               \
+                const compile_type *dataPtr =                                  \
+                        static_cast<const compile_type*>(data);                \
+                return metadata->update(tag, dataPtr, dataCount);              \
+            }                                                                  \
+
+            METADATA_UPDATE(TYPE_BYTE,     uint8_t);
+            METADATA_UPDATE(TYPE_INT32,    int32_t);
+            METADATA_UPDATE(TYPE_FLOAT,    float);
+            METADATA_UPDATE(TYPE_INT64,    int64_t);
+            METADATA_UPDATE(TYPE_DOUBLE,   double);
+            METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
+
+            default: {
+                // unreachable
+                ALOGE("%s: Unreachable", __FUNCTION__);
+                return INVALID_OPERATION;
+            }
+        }
+
+#undef METADATA_UPDATE
+    }
+};
+} // namespace {}
+
+extern "C" {
+
+static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
+static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
+static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
+
+// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
+static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
+
+    if (thiz == NULL) {
+        return NULL;
+    }
+
+    return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
+}
+
+// Safe access to native pointer from object. Throws if not possible to access.
+static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
+                                                 const char* argName = "this") {
+
+    if (thiz == NULL) {
+        ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
+              __FUNCTION__);
+        jniThrowNullPointerException(env, argName);
+        return NULL;
+    }
+
+    CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
+    if (metadata == NULL) {
+        ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
+              __FUNCTION__);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                            "Metadata object was already closed");
+        return NULL;
+    }
+
+    return metadata;
+}
+
+static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
+    ALOGV("%s", __FUNCTION__);
+
+    return reinterpret_cast<jlong>(new CameraMetadata());
+}
+
+static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
+        jobject other) {
+    ALOGV("%s", __FUNCTION__);
+
+    CameraMetadata* otherMetadata =
+            CameraMetadata_getPointerThrow(env, other, "other");
+
+    // In case of exception, return
+    if (otherMetadata == NULL) return NULL;
+
+    // Clone native metadata and return new pointer
+    return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
+}
+
+
+static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
+    ALOGV("%s", __FUNCTION__);
+
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+
+    if (metadata == NULL) {
+        ALOGW("%s: Returning early due to exception being thrown",
+               __FUNCTION__);
+        return JNI_TRUE; // actually throws java exc.
+    }
+
+    jboolean empty = metadata->isEmpty();
+
+    ALOGV("%s: Empty returned %d, entry count was %d",
+          __FUNCTION__, empty, metadata->entryCount());
+
+    return empty;
+}
+
+static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
+    ALOGV("%s", __FUNCTION__);
+
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+
+    if (metadata == NULL) return 0; // actually throws java exc.
+
+    return metadata->entryCount();
+}
+
+// idempotent. calling more than once has no effect.
+static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
+    ALOGV("%s", __FUNCTION__);
+
+    CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
+
+    if (metadata != NULL) {
+        delete metadata;
+        env->SetLongField(thiz, fields.metadata_ptr, 0);
+    }
+
+    LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
+                        "Expected the native ptr to be 0 after #close");
+}
+
+static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
+    ALOGV("%s", __FUNCTION__);
+
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+
+    // order is important: we can't call another JNI method
+    // if there is an exception pending
+    if (metadata == NULL) return;
+
+    CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
+
+    if (otherMetadata == NULL) return;
+
+    metadata->swap(*otherMetadata);
+}
+
+static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
+    ALOGV("%s (tag = %d)", __FUNCTION__, tag);
+
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+    if (metadata == NULL) return NULL;
+
+    int tagType = get_camera_metadata_tag_type(tag);
+    if (tagType == -1) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Tag (%d) did not have a type", tag);
+        return NULL;
+    }
+    size_t tagSize = Helpers::getTypeSize(tagType);
+
+    camera_metadata_entry entry = metadata->find(tag);
+    if (entry.count == 0) {
+         if (!metadata->exists(tag)) {
+             ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
+             return NULL;
+         } else {
+             // OK: we will return a 0-sized array.
+             ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
+                   tag);
+         }
+    }
+
+    jsize byteCount = entry.count * tagSize;
+    jbyteArray byteArray = env->NewByteArray(byteCount);
+    if (env->ExceptionCheck()) return NULL;
+
+    // Copy into java array from native array
+    ScopedByteArrayRW arrayWriter(env, byteArray);
+    memcpy(arrayWriter.get(), entry.data.u8, byteCount);
+
+    return byteArray;
+}
+
+static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
+    ALOGV("%s (tag = %d)", __FUNCTION__, tag);
+
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+    if (metadata == NULL) return;
+
+    int tagType = get_camera_metadata_tag_type(tag);
+    if (tagType == -1) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Tag (%d) did not have a type", tag);
+        return;
+    }
+    size_t tagSize = Helpers::getTypeSize(tagType);
+
+    status_t res;
+
+    if (src == NULL) {
+        // If array is NULL, delete the entry
+        if (metadata->exists(tag)) {
+            res = metadata->erase(tag);
+            ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
+        } else {
+            res = OK;
+            ALOGV("%s: Don't need to erase", __FUNCTION__);
+        }
+    } else {
+        // Copy from java array into native array
+        ScopedByteArrayRO arrayReader(env, src);
+        if (arrayReader.get() == NULL) return;
+
+        res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
+                                 tagType, arrayReader.get(), arrayReader.size());
+
+        ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
+    }
+
+    if (res == OK) {
+        return;
+    } else if (res == BAD_VALUE) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Src byte array was poorly formed");
+    } else if (res == INVALID_OPERATION) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                             "Internal error while trying to update metadata");
+    } else {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                             "Unknown error (%d) while trying to update "
+                            "metadata", res);
+    }
+}
+
+static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
+    ALOGV("%s", __FUNCTION__);
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+    if (metadata == NULL) {
+        return;
+    }
+
+    Parcel* parcelNative = parcelForJavaObject(env, parcel);
+    if (parcelNative == NULL) {
+        jniThrowNullPointerException(env, "parcel");
+        return;
+    }
+
+    status_t err;
+    if ((err = metadata->readFromParcel(parcelNative)) != OK) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                             "Failed to read from parcel (error code %d)", err);
+        return;
+    }
+}
+
+static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
+    ALOGV("%s", __FUNCTION__);
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+    if (metadata == NULL) {
+        return;
+    }
+
+    Parcel* parcelNative = parcelForJavaObject(env, parcel);
+    if (parcelNative == NULL) {
+        jniThrowNullPointerException(env, "parcel");
+        return;
+    }
+
+    status_t err;
+    if ((err = metadata->writeToParcel(parcelNative)) != OK) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                                  "Failed to write to parcel (error code %d)", err);
+        return;
+    }
+}
+
+} // extern "C"
+
+//-------------------------------------------------
+
+static JNINativeMethod gCameraMetadataMethods[] = {
+// static methods
+  { "nativeClassInit",
+    "()V",
+    (void *)CameraMetadata_classInit },
+  { "nativeGetTagFromKey",
+    "(Ljava/lang/String;)I",
+    (void *)CameraMetadata_getTagFromKey },
+  { "nativeGetTypeFromTag",
+    "(I)I",
+    (void *)CameraMetadata_getTypeFromTag },
+// instance methods
+  { "nativeAllocate",
+    "()J",
+    (void*)CameraMetadata_allocate },
+  { "nativeAllocateCopy",
+    "(L" CAMERA_METADATA_CLASS_NAME ";)J",
+    (void *)CameraMetadata_allocateCopy },
+  { "nativeIsEmpty",
+    "()Z",
+    (void*)CameraMetadata_isEmpty },
+  { "nativeGetEntryCount",
+    "()I",
+    (void*)CameraMetadata_getEntryCount },
+  { "nativeClose",
+    "()V",
+    (void*)CameraMetadata_close },
+  { "nativeSwap",
+    "(L" CAMERA_METADATA_CLASS_NAME ";)V",
+    (void *)CameraMetadata_swap },
+  { "nativeReadValues",
+    "(I)[B",
+    (void *)CameraMetadata_readValues },
+  { "nativeWriteValues",
+    "(I[B)V",
+    (void *)CameraMetadata_writeValues },
+// Parcelable interface
+  { "nativeReadFromParcel",
+    "(Landroid/os/Parcel;)V",
+    (void *)CameraMetadata_readFromParcel },
+  { "nativeWriteToParcel",
+    "(Landroid/os/Parcel;)V",
+    (void *)CameraMetadata_writeToParcel },
+};
+
+struct field {
+    const char *class_name;
+    const char *field_name;
+    const char *field_type;
+    jfieldID   *jfield;
+};
+
+static int find_fields(JNIEnv *env, field *fields, int count)
+{
+    for (int i = 0; i < count; i++) {
+        field *f = &fields[i];
+        jclass clazz = env->FindClass(f->class_name);
+        if (clazz == NULL) {
+            ALOGE("Can't find %s", f->class_name);
+            return -1;
+        }
+
+        jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
+        if (field == NULL) {
+            ALOGE("Can't find %s.%s", f->class_name, f->field_name);
+            return -1;
+        }
+
+        *(f->jfield) = field;
+    }
+
+    return 0;
+}
+
+// Get all the required offsets in java class and register native functions
+int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
+{
+    // Register native functions
+    return AndroidRuntime::registerNativeMethods(env,
+            CAMERA_METADATA_CLASS_NAME,
+            gCameraMetadataMethods,
+            NELEM(gCameraMetadataMethods));
+}
+
+extern "C" {
+static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
+    // XX: Why do this separately instead of doing it in the register function?
+    ALOGV("%s", __FUNCTION__);
+
+    field fields_to_find[] = {
+        { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
+    };
+
+    // Do this here instead of in register_native_methods,
+    // since otherwise it will fail to find the fields.
+    if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
+        return;
+
+    jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME);
+}
+
+static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
+
+    ScopedUtfChars keyScoped(env, keyName);
+    const char *key = keyScoped.c_str();
+    if (key == NULL) {
+        // exception thrown by ScopedUtfChars
+        return 0;
+    }
+    size_t keyLength = strlen(key);
+
+    ALOGV("%s (key = '%s')", __FUNCTION__, key);
+
+    // First, find the section by the longest string match
+    const char *section = NULL;
+    size_t sectionIndex = 0;
+    size_t sectionLength = 0;
+    for (size_t i = 0; i < ANDROID_SECTION_COUNT; ++i) {
+        const char *str = camera_metadata_section_names[i];
+        ALOGVV("%s: Trying to match against section '%s'",
+               __FUNCTION__, str);
+        if (strstr(key, str) == key) { // key begins with the section name
+            size_t strLength = strlen(str);
+
+            ALOGVV("%s: Key begins with section name", __FUNCTION__);
+
+            // section name is the longest we've found so far
+            if (section == NULL || sectionLength < strLength) {
+                section = str;
+                sectionIndex = i;
+                sectionLength = strLength;
+
+                ALOGVV("%s: Found new best section (idx %d)", __FUNCTION__, sectionIndex);
+            }
+        }
+    }
+
+    // TODO: vendor ext
+    // TODO: Make above get_camera_metadata_section_from_name ?
+
+    if (section == NULL) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Could not find section name for key '%s')", key);
+        return 0;
+    } else {
+        ALOGV("%s: Found matched section '%s' (%d)",
+              __FUNCTION__, section, sectionIndex);
+    }
+
+    // Get the tag name component of the key
+    const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
+    if (sectionLength + 1 >= keyLength) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Key length too short for key '%s')", key);
+    }
+
+    // Match rest of name against the tag names in that section only
+    uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+    tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+    tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+
+    uint32_t tag;
+    for (tag = tagBegin; tag < tagEnd; ++tag) {
+        const char *tagName = get_camera_metadata_tag_name(tag);
+
+        if (strcmp(keyTagName, tagName) == 0) {
+            ALOGV("%s: Found matched tag '%s' (%d)",
+                  __FUNCTION__, tagName, tag);
+            break;
+        }
+    }
+
+    // TODO: vendor ext
+    // TODO: Make above get_camera_metadata_tag_from_name ?
+
+    if (tag == tagEnd) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Could not find tag name for key '%s')", key);
+        return 0;
+    }
+
+    return tag;
+}
+
+static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
+    int tagType = get_camera_metadata_tag_type(tag);
+    if (tagType == -1) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Tag (%d) did not have a type", tag);
+        return -1;
+    }
+
+    return tagType;
+}
+
+} // extern "C"
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 197d240..1c43cc5 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -18,22 +18,12 @@
 
 #define LOG_TAG "AudioRecord-JNI"
 
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <math.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
 #include <utils/Log.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
 #include <media/AudioRecord.h>
-#include <media/mediarecorder.h>
-
-#include <cutils/bitops.h>
 
 #include <system/audio.h>
 
@@ -47,8 +37,6 @@
 struct fields_t {
     // these fields provide access from C++ to the...
     jmethodID postNativeEventInJava; //... event post callback method
-    int       PCM16;                 //...  format constants
-    int       PCM8;                  //...  format constants
     jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
     jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
 };
@@ -61,6 +49,10 @@
     Condition   cond;
 };
 
+// keep these values in sync with AudioFormat.java
+#define ENCODING_PCM_16BIT 2
+#define ENCODING_PCM_8BIT  3
+
 static Mutex sLock;
 static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
 
@@ -101,14 +93,11 @@
         }
         callbackInfo->busy = true;
     }
-    if (event == AudioRecord::EVENT_MORE_DATA) {
-        // set size to 0 to signal we're not using the callback to read more data
-        AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
-        pBuff->size = 0;
 
-    } else if (event == AudioRecord::EVENT_MARKER) {
+    switch (event) {
+    case AudioRecord::EVENT_MARKER: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user && env) {
+        if (user != NULL && env != NULL) {
             env->CallStaticVoidMethod(
                 callbackInfo->audioRecord_class,
                 javaAudioRecordFields.postNativeEventInJava,
@@ -118,10 +107,11 @@
                 env->ExceptionClear();
             }
         }
+        } break;
 
-    } else if (event == AudioRecord::EVENT_NEW_POS) {
+    case AudioRecord::EVENT_NEW_POS: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user && env) {
+        if (user != NULL && env != NULL) {
             env->CallStaticVoidMethod(
                 callbackInfo->audioRecord_class,
                 javaAudioRecordFields.postNativeEventInJava,
@@ -131,7 +121,9 @@
                 env->ExceptionClear();
             }
         }
+        } break;
     }
+
     {
         Mutex::Autolock l(sLock);
         callbackInfo->busy = false;
@@ -166,28 +158,29 @@
 // ----------------------------------------------------------------------------
 static int
 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jint source, jint sampleRateInHertz, jint channels,
+        jint source, jint sampleRateInHertz, jint channelMask,
+                // Java channel masks map directly to the native definition
         jint audioFormat, jint buffSizeInBytes, jintArray jSession)
 {
     //ALOGV(">> Entering android_media_AudioRecord_setup");
-    //ALOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
-    //     sampleRateInHertz, audioFormat, channels,     buffSizeInBytes);
+    //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
+    //     sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
 
-    if (!audio_is_input_channel(channels)) {
-        ALOGE("Error creating AudioRecord: channel count is not 1 or 2.");
+    if (!audio_is_input_channel(channelMask)) {
+        ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
         return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
     }
-    uint32_t nbChannels = popcount(channels);
+    uint32_t nbChannels = popcount(channelMask);
 
     // compare the format against the Java constants
-    if ((audioFormat != javaAudioRecordFields.PCM16)
-        && (audioFormat != javaAudioRecordFields.PCM8)) {
+    if ((audioFormat != ENCODING_PCM_16BIT)
+        && (audioFormat != ENCODING_PCM_8BIT)) {
         ALOGE("Error creating AudioRecord: unsupported audio format.");
         return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
     }
 
-    int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1;
-    audio_format_t format = audioFormat==javaAudioRecordFields.PCM16 ?
+    int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1;
+    audio_format_t format = audioFormat == ENCODING_PCM_16BIT ?
             AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;
 
     if (buffSizeInBytes == 0) {
@@ -197,7 +190,7 @@
     int frameSize = nbChannels * bytesPerSample;
     size_t frameCount = buffSizeInBytes / frameSize;
 
-    if (uint32_t(source) >= AUDIO_SOURCE_CNT) {
+    if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) {
         ALOGE("Error creating AudioRecord: unknown source.");
         return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
     }
@@ -236,12 +229,12 @@
     lpRecorder->set((audio_source_t) source,
         sampleRateInHertz,
         format,        // word length, PCM
-        channels,
+        channelMask,
         frameCount,
         recorderCallback,// callback_t
         lpCallbackData,// void* user
         0,             // notificationFrames,
-        true,          // threadCanCallJava)
+        true,          // threadCanCallJava
         sessionId);
 
     if (lpRecorder->initCheck() != NO_ERROR) {
@@ -394,6 +387,9 @@
                                             (jint)recorderBuffSize : sizeInBytes );
     env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
 
+    if (readSize < 0) {
+        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+    }
     return (jint) readSize;
 }
 
@@ -402,10 +398,13 @@
                                                         jshortArray javaAudioData,
                                                         jint offsetInShorts, jint sizeInShorts) {
 
-    return (android_media_AudioRecord_readInByteArray(env, thiz,
+    jint read = android_media_AudioRecord_readInByteArray(env, thiz,
                                                         (jbyteArray) javaAudioData,
-                                                        offsetInShorts*2, sizeInShorts*2)
-            / 2);
+                                                        offsetInShorts*2, sizeInShorts*2);
+    if (read > 0) {
+        read /= 2;
+    }
+    return read;
 }
 
 // ----------------------------------------------------------------------------
@@ -431,8 +430,12 @@
     }
 
     // read new data from the recorder
-    return (jint) lpRecorder->read(nativeFromJavaBuf,
+    ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
                                    capacity < sizeInBytes ? capacity : sizeInBytes);
+    if (readSize < 0) {
+        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+    }
+    return (jint)readSize;
 }
 
 
@@ -510,7 +513,7 @@
     size_t frameCount = 0;
     status_t result = AudioRecord::getMinFrameCount(&frameCount,
             sampleRateInHertz,
-            (audioFormat == javaAudioRecordFields.PCM16 ?
+            (audioFormat == ENCODING_PCM_16BIT ?
                 AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT),
             audio_channel_in_mask_from_count(nbChannels));
 
@@ -520,7 +523,7 @@
     if (result != NO_ERROR) {
         return -1;
     }
-    return frameCount * nbChannels * (audioFormat == javaAudioRecordFields.PCM16 ? 2 : 1);
+    return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1);
 }
 
 
@@ -552,18 +555,9 @@
 
 // field names found in android/media/AudioRecord.java
 #define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
-#define JAVA_CONST_PCM16_NAME         "ENCODING_PCM_16BIT"
-#define JAVA_CONST_PCM8_NAME          "ENCODING_PCM_8BIT"
 #define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
 #define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
 
-#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
-
-// ----------------------------------------------------------------------------
-
-extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv,
-                jclass theClass, const char* className, const char* constName, int* constVal);
-
 // ----------------------------------------------------------------------------
 int register_android_media_AudioRecord(JNIEnv *env)
 {
@@ -605,23 +599,6 @@
         return -1;
     }
 
-    // Get the format constants from the AudioFormat class
-    jclass audioFormatClass = NULL;
-    audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
-    if (audioFormatClass == NULL) {
-        ALOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
-        return -1;
-    }
-    if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
-                JAVA_AUDIOFORMAT_CLASS_NAME,
-                JAVA_CONST_PCM16_NAME, &(javaAudioRecordFields.PCM16))
-           || !android_media_getIntConstantFromClass(env, audioFormatClass,
-                JAVA_AUDIOFORMAT_CLASS_NAME,
-                JAVA_CONST_PCM8_NAME, &(javaAudioRecordFields.PCM8)) ) {
-        // error log performed in getIntConstantFromClass()
-        return -1;
-    }
-
     return AndroidRuntime::registerNativeMethods(env,
             kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 67c2cfd..7d99464 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -18,11 +18,6 @@
 #define LOG_TAG "AudioSystem"
 #include <utils/Log.h>
 
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <math.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -46,11 +41,15 @@
 
 static int check_AudioSystem_Command(status_t status)
 {
-    if (status == NO_ERROR) {
+    switch (status) {
+    case DEAD_OBJECT:
+        return kAudioStatusMediaServerDied;
+    case NO_ERROR:
         return kAudioStatusOk;
-    } else {
-        return kAudioStatusError;
+    default:
+        break;
     }
+    return kAudioStatusError;
 }
 
 static int
@@ -127,21 +126,9 @@
 
     jclass clazz = env->FindClass(kClassPathName);
 
-    int error;
-
-    switch (err) {
-    case DEAD_OBJECT:
-        error = kAudioStatusMediaServerDied;
-        break;
-    case NO_ERROR:
-        error = kAudioStatusOk;
-        break;
-    default:
-        error = kAudioStatusError;
-        break;
-    }
-
-    env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
+    env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
+                              "errorCallbackFromNative","(I)V"),
+                              check_AudioSystem_Command(err));
 }
 
 static int
@@ -282,6 +269,18 @@
     return (jint) afLatency;
 }
 
+static jint
+android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
+{
+    return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
+}
+
+static int
+android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
+{
+    return check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -308,6 +307,8 @@
     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
     {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
+    {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
+    {"checkAudioFlinger",    "()I",     (void *)android_media_AudioSystem_checkAudioFlinger},
 };
 
 int register_android_media_AudioSystem(JNIEnv *env)
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 3ff9dda..225bf06 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -17,11 +17,6 @@
 
 #define LOG_TAG "AudioTrack-JNI"
 
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <math.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -33,8 +28,6 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
 
-#include <cutils/bitops.h>
-
 #include <system/audio.h>
 
 // ----------------------------------------------------------------------------
@@ -47,8 +40,6 @@
 struct fields_t {
     // these fields provide access from C++ to the...
     jmethodID postNativeEventInJava; //... event post callback method
-    int       PCM16;                 //...  format constants
-    int       PCM8;                  //...  format constants
     jfieldID  nativeTrackInJavaObj;  // stores in Java the native AudioTrack object
     jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
 };
@@ -64,6 +55,9 @@
 // keep these values in sync with AudioTrack.java
 #define MODE_STATIC 0
 #define MODE_STREAM 1
+// keep these values in sync with AudioFormat.java
+#define ENCODING_PCM_16BIT 2
+#define ENCODING_PCM_8BIT  3
 
 // ----------------------------------------------------------------------------
 class AudioTrackJniStorage {
@@ -137,14 +131,10 @@
         callbackInfo->busy = true;
     }
 
-    if (event == AudioTrack::EVENT_MORE_DATA) {
-        // set size to 0 to signal we're not using the callback to write more data
-        AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
-        pBuff->size = 0;
-
-    } else if (event == AudioTrack::EVENT_MARKER) {
+    switch (event) {
+    case AudioTrack::EVENT_MARKER: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user && env) {
+        if (user != NULL && env != NULL) {
             env->CallStaticVoidMethod(
                 callbackInfo->audioTrack_class,
                 javaAudioTrackFields.postNativeEventInJava,
@@ -154,10 +144,11 @@
                 env->ExceptionClear();
             }
         }
+        } break;
 
-    } else if (event == AudioTrack::EVENT_NEW_POS) {
+    case AudioTrack::EVENT_NEW_POS: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user && env) {
+        if (user != NULL && env != NULL) {
             env->CallStaticVoidMethod(
                 callbackInfo->audioTrack_class,
                 javaAudioTrackFields.postNativeEventInJava,
@@ -167,7 +158,9 @@
                 env->ExceptionClear();
             }
         }
+        } break;
     }
+
     {
         Mutex::Autolock l(sLock);
         callbackInfo->busy = false;
@@ -225,7 +218,7 @@
     uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
 
     if (!audio_is_output_channel(nativeChannelMask)) {
-        ALOGE("Error creating AudioTrack: invalid channel mask.");
+        ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
         return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
     }
 
@@ -251,7 +244,8 @@
 
     // check the format.
     // This function was called from Java, so we compare the format against the Java constants
-    if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) {
+    if ((audioFormat != ENCODING_PCM_16BIT) && (audioFormat != ENCODING_PCM_8BIT)) {
+
         ALOGE("Error creating AudioTrack: unsupported audio format.");
         return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
     }
@@ -259,19 +253,19 @@
     // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
     // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
     // in android_media_AudioTrack_native_write_byte()
-    if ((audioFormat == javaAudioTrackFields.PCM8)
+    if ((audioFormat == ENCODING_PCM_8BIT)
         && (memoryMode == MODE_STATIC)) {
         ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
             buff size of %dbytes, switching to 16bit, buff size of %dbytes",
             buffSizeInBytes, 2*buffSizeInBytes);
-        audioFormat = javaAudioTrackFields.PCM16;
+        audioFormat = ENCODING_PCM_16BIT;
         // we will need twice the memory to store the data
         buffSizeInBytes *= 2;
     }
 
     // compute the frame count
-    int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
-    audio_format_t format = audioFormat == javaAudioTrackFields.PCM16 ?
+    int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1;
+    audio_format_t format = audioFormat == ENCODING_PCM_16BIT ?
             AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;
     int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
 
@@ -520,15 +514,19 @@
     // regular write() or copy the data to the AudioTrack's shared memory?
     if (track->sharedBuffer() == 0) {
         written = track->write(data + offsetInBytes, sizeInBytes);
+        // for compatibility with earlier behavior of write(), return 0 in this case
+        if (written == (ssize_t) WOULD_BLOCK) {
+            written = 0;
+        }
     } else {
-        if (audioFormat == javaAudioTrackFields.PCM16) {
+        if (audioFormat == ENCODING_PCM_16BIT) {
             // writing to shared memory, check for capacity
             if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
                 sizeInBytes = track->sharedBuffer()->size();
             }
             memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
             written = sizeInBytes;
-        } else if (audioFormat == javaAudioTrackFields.PCM8) {
+        } else if (audioFormat == ENCODING_PCM_8BIT) {
             // data contains 8bit data we need to expand to 16bit before copying
             // to the shared memory
             // writing to shared memory, check for capacity,
@@ -597,11 +595,14 @@
                                                   jshortArray javaAudioData,
                                                   jint offsetInShorts, jint sizeInShorts,
                                                   jint javaAudioFormat) {
-    return (android_media_AudioTrack_native_write_byte(env, thiz,
+    jint written = android_media_AudioTrack_native_write_byte(env, thiz,
                                                  (jbyteArray) javaAudioData,
                                                  offsetInShorts*2, sizeInShorts*2,
-                                                 javaAudioFormat)
-            / 2);
+                                                 javaAudioFormat);
+    if (written > 0) {
+        written /= 2;
+    }
+    return written;
 }
 
 
@@ -741,6 +742,30 @@
 
 
 // ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_timestamp(JNIEnv *env,  jobject thiz, jlongArray jTimestamp) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+
+    if (lpTrack == NULL) {
+        ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
+        return AUDIOTRACK_ERROR;
+    }
+    AudioTimestamp timestamp;
+    status_t status = lpTrack->getTimestamp(timestamp);
+    if (status == OK) {
+        jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
+        if (nTimestamp == NULL) {
+            ALOGE("Unable to get array for getTimestamp()");
+            return AUDIOTRACK_ERROR;
+        }
+        nTimestamp[0] = (jlong) timestamp.mPosition;
+        nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
+        env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
+    }
+    return (jint) android_media_translateErrorCode(status);
+}
+
+
+// ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_set_loop(JNIEnv *env,  jobject thiz,
         jint loopStart, jint loopEnd, jint loopCount) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
@@ -809,7 +834,7 @@
             sampleRateInHertz) != NO_ERROR) {
         return -1;
     }
-    return frameCount * nbChannels * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1);
+    return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1);
 }
 
 // ----------------------------------------------------------------------------
@@ -868,6 +893,7 @@
     {"native_set_position",  "(I)I",     (void *)android_media_AudioTrack_set_position},
     {"native_get_position",  "()I",      (void *)android_media_AudioTrack_get_position},
     {"native_get_latency",   "()I",      (void *)android_media_AudioTrack_get_latency},
+    {"native_get_timestamp", "([J)I",    (void *)android_media_AudioTrack_get_timestamp},
     {"native_set_loop",      "(III)I",   (void *)android_media_AudioTrack_set_loop},
     {"native_reload_static", "()I",      (void *)android_media_AudioTrack_reload},
     {"native_get_output_sample_rate",
@@ -883,23 +909,9 @@
 
 // field names found in android/media/AudioTrack.java
 #define JAVA_POSTEVENT_CALLBACK_NAME                    "postEventFromNative"
-#define JAVA_CONST_PCM16_NAME                           "ENCODING_PCM_16BIT"
-#define JAVA_CONST_PCM8_NAME                            "ENCODING_PCM_8BIT"
-#define JAVA_CONST_BUFFER_COUNT_NAME                    "BUFFER_COUNT"
-#define JAVA_CONST_STREAM_VOICE_CALL_NAME               "STREAM_VOICE_CALL"
-#define JAVA_CONST_STREAM_SYSTEM_NAME                   "STREAM_SYSTEM"
-#define JAVA_CONST_STREAM_RING_NAME                     "STREAM_RING"
-#define JAVA_CONST_STREAM_MUSIC_NAME                    "STREAM_MUSIC"
-#define JAVA_CONST_STREAM_ALARM_NAME                    "STREAM_ALARM"
-#define JAVA_CONST_STREAM_NOTIFICATION_NAME             "STREAM_NOTIFICATION"
-#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME            "STREAM_BLUETOOTH_SCO"
-#define JAVA_CONST_STREAM_DTMF_NAME                     "STREAM_DTMF"
 #define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME            "mNativeTrackInJavaObj"
 #define JAVA_JNIDATA_FIELD_NAME                         "mJniData"
 
-#define JAVA_AUDIOFORMAT_CLASS_NAME             "android/media/AudioFormat"
-#define JAVA_AUDIOMANAGER_CLASS_NAME            "android/media/AudioManager"
-
 // ----------------------------------------------------------------------------
 // preconditions:
 //    theClass is valid
@@ -957,23 +969,6 @@
         return -1;
     }
 
-    // Get the format constants from the AudioFormat class
-    jclass audioFormatClass = NULL;
-    audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
-    if (audioFormatClass == NULL) {
-        ALOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
-        return -1;
-    }
-    if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
-                JAVA_AUDIOFORMAT_CLASS_NAME,
-                JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16))
-           || !android_media_getIntConstantFromClass(env, audioFormatClass,
-                JAVA_AUDIOFORMAT_CLASS_NAME,
-                JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) {
-        // error log performed in android_media_getIntConstantFromClass()
-        return -1;
-    }
-
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 80d13be..463be5e 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -24,6 +24,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/Log.h>
 
 #include <binder/IServiceManager.h>
 
@@ -61,7 +62,7 @@
 
 public:
     virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
-            uint32_t width, uint32_t height, uint32_t flags) {
+            uint32_t width, uint32_t height, uint32_t flags, uint32_t session) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
 
         jobject surfaceObj = android_view_Surface_createFromIGraphicBufferProducer(env, bufferProducer);
@@ -73,7 +74,7 @@
 
         env->CallVoidMethod(mRemoteDisplayObjGlobal,
                 gRemoteDisplayClassInfo.notifyDisplayConnected,
-                surfaceObj, width, height, flags);
+                surfaceObj, width, height, flags, session);
         env->DeleteLocalRef(surfaceObj);
         checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
     }
@@ -117,6 +118,14 @@
         mDisplay->dispose();
     }
 
+    void pause() {
+        mDisplay->pause();
+    }
+
+    void resume() {
+        mDisplay->resume();
+    }
+
 private:
     sp<IRemoteDisplay> mDisplay;
     sp<NativeRemoteDisplayClient> mClient;
@@ -149,6 +158,16 @@
     return reinterpret_cast<jint>(wrapper);
 }
 
+static void nativePause(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+    wrapper->pause();
+}
+
+static void nativeResume(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+    wrapper->resume();
+}
+
 static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
     NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
     delete wrapper;
@@ -161,6 +180,10 @@
             (void*)nativeListen },
     {"nativeDispose", "(I)V",
             (void*)nativeDispose },
+    {"nativePause", "(I)V",
+            (void*)nativePause },
+    {"nativeResume", "(I)V",
+            (void*)nativeResume },
 };
 
 int register_android_media_RemoteDisplay(JNIEnv* env)
@@ -171,7 +194,7 @@
     jclass clazz = env->FindClass("android/media/RemoteDisplay");
     gRemoteDisplayClassInfo.notifyDisplayConnected =
             env->GetMethodID(clazz, "notifyDisplayConnected",
-                    "(Landroid/view/Surface;III)V");
+                    "(Landroid/view/Surface;IIII)V");
     gRemoteDisplayClassInfo.notifyDisplayDisconnected =
             env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
     gRemoteDisplayClassInfo.notifyDisplayError =
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index ad21d64..9f79f74 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -45,26 +45,6 @@
 static jclass class_FileDescriptor;
 static jmethodID method_CredentialsInit;
 
-/*
- * private native FileDescriptor
- * create_native(boolean stream)
- *               throws IOException;
- */
-static jobject
-socket_create (JNIEnv *env, jobject object, jboolean stream)
-{
-    int ret;
-
-    ret = socket(PF_LOCAL, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
-
-    if (ret < 0) {
-        jniThrowIOException(env, errno);
-        return NULL;
-    }
-
-    return jniCreateFileDescriptor(env,ret);
-}
-
 /* private native void connectLocal(FileDescriptor fd,
  * String name, int namespace) throws IOException
  */
@@ -440,32 +420,6 @@
 #endif
 }
 
-static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
-{
-    int fd;
-    int err;
-
-    if (fileDescriptor == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return;
-    }
-
-    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
-    if (env->ExceptionOccurred() != NULL) {
-        return;
-    }
-
-    do {
-        err = close(fd);
-    } while (err < 0 && errno == EINTR);
-
-    if (err < 0) {
-        jniThrowIOException(env, errno);
-        return;
-    }
-}
-
 /**
  * Processes ancillary data, handling only
  * SCM_RIGHTS. Creates appropriate objects and sets appropriate
@@ -905,7 +859,6 @@
      /* name, signature, funcPtr */
     {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
     {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
-    {"create_native", "(Z)Ljava/io/FileDescriptor;", (void*)socket_create},
     {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
                                                 (void*)socket_connect_local},
     {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
@@ -914,7 +867,6 @@
     {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown},
     {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available},
     {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending},
-    {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close},
     {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
     {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
     {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index faae11e..6d23c32 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "NetUtils"
 
 #include "jni.h"
+#include "JNIHelp.h"
 #include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
@@ -36,7 +37,8 @@
                     const char *server,
                     uint32_t *lease,
                     const char *vendorInfo,
-                    const char *domains);
+                    const char *domains,
+                    const char *mtu);
 
 int dhcp_do_request_renew(const char * const ifname,
                     const char *ipaddr,
@@ -46,7 +48,8 @@
                     const char *server,
                     uint32_t *lease,
                     const char *vendorInfo,
-                    const char *domains);
+                    const char *domains,
+                    const char *mtu);
 
 int dhcp_stop(const char *ifname);
 int dhcp_release_lease(const char *ifname);
@@ -125,19 +128,20 @@
     uint32_t lease;
     char vendorInfo[PROPERTY_VALUE_MAX];
     char domains[PROPERTY_VALUE_MAX];
+    char mtu[PROPERTY_VALUE_MAX];
 
     const char *nameStr = env->GetStringUTFChars(ifname, NULL);
     if (nameStr == NULL) return (jboolean)false;
 
     if (renew) {
         result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
-                dns, server, &lease, vendorInfo, domains);
+                dns, server, &lease, vendorInfo, domains, mtu);
     } else {
         result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
-                dns, server, &lease, vendorInfo, domains);
+                dns, server, &lease, vendorInfo, domains, mtu);
     }
     if (result != 0) {
-        ALOGD("dhcp_do_request failed");
+        ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
     }
 
     env->ReleaseStringUTFChars(ifname, nameStr);
@@ -239,6 +243,13 @@
     return env->NewStringUTF(::dhcp_get_errmsg());
 }
 
+static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, jint mark)
+{
+    if (setsockopt(socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
+        jniThrowException(env, "java/lang/IllegalStateException", "Error marking socket");
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 /*
@@ -255,6 +266,7 @@
     { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
     { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
+    { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index b4c4a1b..f904b62 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -23,7 +23,6 @@
 #include <sys/types.h>
 
 #include <android_runtime/AndroidRuntime.h>
-#include <cutils/logger.h>
 #include <jni.h>
 #include <ScopedUtfChars.h>
 #include <utils/misc.h>
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
deleted file mode 100644
index 9537ac4..0000000
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "wifi"
-
-#include "jni.h"
-#include <ScopedUtfChars.h>
-#include <utils/misc.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/Log.h>
-#include <utils/String16.h>
-
-#include "wifi.h"
-
-#define WIFI_PKG_NAME "android/net/wifi/WifiNative"
-#define BUF_SIZE 256
-#define EVENT_BUF_SIZE 2048
-
-namespace android {
-
-static jint DBG = false;
-
-static int doCommand(const char *ifname, const char *cmd, char *replybuf, int replybuflen)
-{
-    size_t reply_len = replybuflen - 1;
-
-    if (::wifi_command(ifname, cmd, replybuf, &reply_len) != 0)
-        return -1;
-    else {
-        // Strip off trailing newline
-        if (reply_len > 0 && replybuf[reply_len-1] == '\n')
-            replybuf[reply_len-1] = '\0';
-        else
-            replybuf[reply_len] = '\0';
-        return 0;
-    }
-}
-
-static jint doIntCommand(const char *ifname, const char* fmt, ...)
-{
-    char buf[BUF_SIZE];
-    va_list args;
-    va_start(args, fmt);
-    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
-    va_end(args);
-    if (byteCount < 0 || byteCount >= BUF_SIZE) {
-        return -1;
-    }
-    char reply[BUF_SIZE];
-    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
-        return -1;
-    }
-    return static_cast<jint>(atoi(reply));
-}
-
-static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...)
-{
-    char buf[BUF_SIZE];
-    va_list args;
-    va_start(args, fmt);
-    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
-    va_end(args);
-    if (byteCount < 0 || byteCount >= BUF_SIZE) {
-        return JNI_FALSE;
-    }
-    char reply[BUF_SIZE];
-    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
-        return JNI_FALSE;
-    }
-    return (strcmp(reply, expect) == 0);
-}
-
-// Send a command to the supplicant, and return the reply as a String
-static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, ...) {
-    char buf[BUF_SIZE];
-    va_list args;
-    va_start(args, fmt);
-    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
-    va_end(args);
-    if (byteCount < 0 || byteCount >= BUF_SIZE) {
-        return NULL;
-    }
-    char reply[4096];
-    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
-        return NULL;
-    }
-    // TODO: why not just NewStringUTF?
-    String16 str((char *)reply);
-    return env->NewString((const jchar *)str.string(), str.size());
-}
-
-static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
-{
-    return (jboolean)(::is_wifi_driver_loaded() == 1);
-}
-
-static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
-{
-    return (jboolean)(::wifi_load_driver() == 0);
-}
-
-static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
-{
-    return (jboolean)(::wifi_unload_driver() == 0);
-}
-
-static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
-{
-    return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0);
-}
-
-static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
-{
-    return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0);
-}
-
-static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
-{
-    ScopedUtfChars ifname(env, jIface);
-    return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0);
-}
-
-static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject, jstring jIface)
-{
-    ScopedUtfChars ifname(env, jIface);
-    ::wifi_close_supplicant_connection(ifname.c_str());
-}
-
-static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIface)
-{
-    char buf[EVENT_BUF_SIZE];
-    ScopedUtfChars ifname(env, jIface);
-    int nread = ::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf);
-    if (nread > 0) {
-        return env->NewStringUTF(buf);
-    } else {
-        return NULL;
-    }
-}
-
-static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface,
-        jstring jCommand)
-{
-    ScopedUtfChars ifname(env, jIface);
-    ScopedUtfChars command(env, jCommand);
-
-    if (command.c_str() == NULL) {
-        return JNI_FALSE;
-    }
-    if (DBG) ALOGD("doBoolean: %s", command.c_str());
-    return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str());
-}
-
-static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jIface,
-        jstring jCommand)
-{
-    ScopedUtfChars ifname(env, jIface);
-    ScopedUtfChars command(env, jCommand);
-
-    if (command.c_str() == NULL) {
-        return -1;
-    }
-    if (DBG) ALOGD("doInt: %s", command.c_str());
-    return doIntCommand(ifname.c_str(), "%s", command.c_str());
-}
-
-static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jIface,
-        jstring jCommand)
-{
-    ScopedUtfChars ifname(env, jIface);
-
-    ScopedUtfChars command(env, jCommand);
-    if (command.c_str() == NULL) {
-        return NULL;
-    }
-    if (DBG) ALOGD("doString: %s", command.c_str());
-    return doStringCommand(env, ifname.c_str(), "%s", command.c_str());
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gWifiMethods[] = {
-    /* name, signature, funcPtr */
-
-    { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },
-    { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded },
-    { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
-    { "startSupplicant", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
-    { "killSupplicant", "(Z)Z",  (void *)android_net_wifi_killSupplicant },
-    { "connectToSupplicant", "(Ljava/lang/String;)Z",
-            (void *)android_net_wifi_connectToSupplicant },
-    { "closeSupplicantConnection", "(Ljava/lang/String;)V",
-            (void *)android_net_wifi_closeSupplicantConnection },
-    { "waitForEvent", "(Ljava/lang/String;)Ljava/lang/String;",
-            (void*) android_net_wifi_waitForEvent },
-    { "doBooleanCommand", "(Ljava/lang/String;Ljava/lang/String;)Z",
-            (void*) android_net_wifi_doBooleanCommand },
-    { "doIntCommand", "(Ljava/lang/String;Ljava/lang/String;)I",
-            (void*) android_net_wifi_doIntCommand },
-    { "doStringCommand", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
-            (void*) android_net_wifi_doStringCommand },
-};
-
-int register_android_net_wifi_WifiManager(JNIEnv* env)
-{
-    return AndroidRuntime::registerNativeMethods(env,
-            WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/android_net_wifi_WifiNative.cpp b/core/jni/android_net_wifi_WifiNative.cpp
new file mode 100644
index 0000000..6e11192
--- /dev/null
+++ b/core/jni/android_net_wifi_WifiNative.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "wifi"
+
+#include "jni.h"
+#include <ScopedUtfChars.h>
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+#include "wifi.h"
+
+#define REPLY_BUF_SIZE 4096 // wpa_supplicant's maximum size.
+#define EVENT_BUF_SIZE 2048
+
+namespace android {
+
+static jint DBG = false;
+
+static bool doCommand(JNIEnv* env, jstring javaCommand,
+                      char* reply, size_t reply_len) {
+    ScopedUtfChars command(env, javaCommand);
+    if (command.c_str() == NULL) {
+        return false; // ScopedUtfChars already threw on error.
+    }
+
+    if (DBG) {
+        ALOGD("doCommand: %s", command.c_str());
+    }
+
+    --reply_len; // Ensure we have room to add NUL termination.
+    if (::wifi_command(command.c_str(), reply, &reply_len) != 0) {
+        return false;
+    }
+
+    // Strip off trailing newline.
+    if (reply_len > 0 && reply[reply_len-1] == '\n') {
+        reply[reply_len-1] = '\0';
+    } else {
+        reply[reply_len] = '\0';
+    }
+    return true;
+}
+
+static jint doIntCommand(JNIEnv* env, jstring javaCommand) {
+    char reply[REPLY_BUF_SIZE];
+    if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
+        return -1;
+    }
+    return static_cast<jint>(atoi(reply));
+}
+
+static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) {
+    char reply[REPLY_BUF_SIZE];
+    if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
+        return JNI_FALSE;
+    }
+    return (strcmp(reply, "OK") == 0);
+}
+
+// Send a command to the supplicant, and return the reply as a String.
+static jstring doStringCommand(JNIEnv* env, jstring javaCommand) {
+    char reply[REPLY_BUF_SIZE];
+    if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
+        return NULL;
+    }
+    return env->NewStringUTF(reply);
+}
+
+static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
+{
+    return (::is_wifi_driver_loaded() == 1);
+}
+
+static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
+{
+    return (::wifi_load_driver() == 0);
+}
+
+static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
+{
+    return (::wifi_unload_driver() == 0);
+}
+
+static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
+{
+    return (::wifi_start_supplicant(p2pSupported) == 0);
+}
+
+static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
+{
+    return (::wifi_stop_supplicant(p2pSupported) == 0);
+}
+
+static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
+{
+    return (::wifi_connect_to_supplicant() == 0);
+}
+
+static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
+{
+    ::wifi_close_supplicant_connection();
+}
+
+static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
+{
+    char buf[EVENT_BUF_SIZE];
+    int nread = ::wifi_wait_for_event(buf, sizeof buf);
+    if (nread > 0) {
+        return env->NewStringUTF(buf);
+    } else {
+        return NULL;
+    }
+}
+
+static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring javaCommand) {
+    return doBooleanCommand(env, javaCommand);
+}
+
+static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring javaCommand) {
+    return doIntCommand(env, javaCommand);
+}
+
+static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring javaCommand) {
+    return doStringCommand(env,javaCommand);
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gWifiMethods[] = {
+    /* name, signature, funcPtr */
+
+    { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },
+    { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded },
+    { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
+    { "startSupplicant", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
+    { "killSupplicant", "(Z)Z",  (void *)android_net_wifi_killSupplicant },
+    { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },
+    { "closeSupplicantConnectionNative", "()V",
+            (void *)android_net_wifi_closeSupplicantConnection },
+    { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent },
+    { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
+    { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
+    { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
+            (void*) android_net_wifi_doStringCommand },
+};
+
+int register_android_net_wifi_WifiNative(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env,
+            "android/net/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 48babb3..1fe4b08 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -604,7 +604,7 @@
     jint _remaining;
     EGLint *attrib_list = (EGLint *) 0;
     android::sp<ANativeWindow> window;
-    android::sp<android::GLConsumer> glConsumer;
+    android::sp<android::IGraphicBufferProducer> producer;
 
     if (!attrib_list_ref) {
         _exception = 1;
@@ -625,12 +625,12 @@
         _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface";
         goto exit;
     }
-    glConsumer = android::SurfaceTexture_getSurfaceTexture(_env, win);
+    producer = android::SurfaceTexture_getProducer(_env, win);
 
-    if (glConsumer == NULL)
+    if (producer == NULL)
         goto not_valid_surface;
 
-    window = new android::Surface(glConsumer->getBufferQueue());
+    window = new android::Surface(producer);
 
     if (window == NULL)
         goto not_valid_surface;
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 0c3d0e0..cc34e99 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -294,6 +294,7 @@
     int _needed = 0;
 
     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
     // an array of the right size -- this might happen with extensions
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 15c4fcf..9284384 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -294,6 +294,7 @@
     int _needed = 0;
 
     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
     // an array of the right size -- this might happen with extensions
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 9f00b01..871e84d 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -294,6 +294,7 @@
     int _needed = 0;
 
     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
     // an array of the right size -- this might happen with extensions
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 139d481..3e038ad 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -294,6 +294,7 @@
     int _needed = 0;
 
     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
     // an array of the right size -- this might happen with extensions
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index eb3d819..db03b70 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -294,6 +294,7 @@
     int _needed = 0;
 
     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
     // an array of the right size -- this might happen with extensions
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 081e470..4c62a75 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -294,6 +294,7 @@
     int _needed = 0;
 
     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
     // an array of the right size -- this might happen with extensions
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 2883c10..62f057f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -20,7 +20,9 @@
 #include <utils/String8.h>
 #include "utils/misc.h"
 #include "cutils/debugger.h"
+#include <memtrack/memtrack.h>
 
+#include <cutils/log.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -43,6 +45,7 @@
     HEAP_UNKNOWN,
     HEAP_DALVIK,
     HEAP_NATIVE,
+    HEAP_DALVIK_OTHER,
     HEAP_STACK,
     HEAP_CURSOR,
     HEAP_ASHMEM,
@@ -52,38 +55,61 @@
     HEAP_APK,
     HEAP_TTF,
     HEAP_DEX,
+    HEAP_OAT,
+    HEAP_ART,
     HEAP_UNKNOWN_MAP,
+    HEAP_GRAPHICS,
+    HEAP_GL,
+    HEAP_OTHER_MEMTRACK,
+
+    HEAP_DALVIK_NORMAL,
+    HEAP_DALVIK_LARGE,
+    HEAP_DALVIK_LINEARALLOC,
+    HEAP_DALVIK_ACCOUNTING,
+    HEAP_DALVIK_CODE_CACHE,
 
     _NUM_HEAP,
+    _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
     _NUM_CORE_HEAP = HEAP_NATIVE+1
 };
 
 struct stat_fields {
     jfieldID pss_field;
+    jfieldID pssSwappable_field;
     jfieldID privateDirty_field;
     jfieldID sharedDirty_field;
+    jfieldID privateClean_field;
+    jfieldID sharedClean_field;
 };
 
 struct stat_field_names {
     const char* pss_name;
+    const char* pssSwappable_name;
     const char* privateDirty_name;
     const char* sharedDirty_name;
+    const char* privateClean_name;
+    const char* sharedClean_name;
 };
 
 static stat_fields stat_fields[_NUM_CORE_HEAP];
 
 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
-    { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
-    { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
-    { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
+    { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty", "otherPrivateClean", "otherSharedClean" },
+    { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty", "dalvikPrivateClean", "dalvikSharedClean" },
+    { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty", "nativePrivateClean", "nativeSharedClean" }
 };
 
 jfieldID otherStats_field;
 
+static bool memtrackLoaded;
+
 struct stats_t {
     int pss;
+    int swappablePss;
     int privateDirty;
     int sharedDirty;
+    int privateClean;
+    int sharedClean;
 };
 
 #define BINDER_STATS "/proc/binder/stats"
@@ -118,15 +144,82 @@
 #endif
 }
 
+// Container used to retrieve graphics memory pss
+struct graphics_memory_pss
+{
+    int graphics;
+    int gl;
+    int other;
+};
+
+/*
+ * Uses libmemtrack to retrieve graphics memory that the process is using.
+ * Any graphics memory reported in /proc/pid/smaps is not included here.
+ */
+static int read_memtrack_memory(struct memtrack_proc* p, int pid,
+        struct graphics_memory_pss* graphics_mem)
+{
+    int err = memtrack_proc_get(p, pid);
+    if (err != 0) {
+        ALOGW("failed to get memory consumption info: %d", err);
+        return err;
+    }
+
+    ssize_t pss = memtrack_proc_graphics_pss(p);
+    if (pss < 0) {
+        ALOGW("failed to get graphics pss: %d", pss);
+        return pss;
+    }
+    graphics_mem->graphics = pss / 1024;
+
+    pss = memtrack_proc_gl_pss(p);
+    if (pss < 0) {
+        ALOGW("failed to get gl pss: %d", pss);
+        return pss;
+    }
+    graphics_mem->gl = pss / 1024;
+
+    pss = memtrack_proc_other_pss(p);
+    if (pss < 0) {
+        ALOGW("failed to get other pss: %d", pss);
+        return pss;
+    }
+    graphics_mem->other = pss / 1024;
+
+    return 0;
+}
+
+/*
+ * Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
+ */
+static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
+{
+    if (!memtrackLoaded) {
+        return -1;
+    }
+
+    struct memtrack_proc* p = memtrack_proc_new();
+    if (p == NULL) {
+        ALOGW("failed to create memtrack_proc");
+        return -1;
+    }
+
+    int err = read_memtrack_memory(p, pid, graphics_mem);
+    memtrack_proc_destroy(p);
+    return err;
+}
+
 static void read_mapinfo(FILE *fp, stats_t* stats)
 {
     char line[1024];
     int len, nameLen;
     bool skip, done = false;
 
-    unsigned size = 0, resident = 0, pss = 0;
+    unsigned size = 0, resident = 0, pss = 0, swappable_pss = 0;
+    float sharing_proportion = 0.0;
     unsigned shared_clean = 0, shared_dirty = 0;
     unsigned private_clean = 0, private_dirty = 0;
+    bool is_swappable = false;
     unsigned referenced = 0;
     unsigned temp;
 
@@ -137,6 +230,7 @@
     int name_pos;
 
     int whichHeap = HEAP_UNKNOWN;
+    int subHeap = HEAP_UNKNOWN;
     int prevHeap = HEAP_UNKNOWN;
 
     if(fgets(line, sizeof(line), fp) == 0) return;
@@ -145,7 +239,9 @@
         prevHeap = whichHeap;
         prevEnd = end;
         whichHeap = HEAP_UNKNOWN;
+        subHeap = HEAP_UNKNOWN;
         skip = false;
+        is_swappable = false;
 
         len = strlen(line);
         if (len < 1) return;
@@ -160,30 +256,72 @@
             name = line + name_pos;
             nameLen = strlen(name);
 
-            if ((strstr(name, "[heap]") == name) ||
-                (strstr(name, "/dev/ashmem/libc malloc") == name)) {
+            if ((strstr(name, "[heap]") == name)) {
                 whichHeap = HEAP_NATIVE;
-            } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
-                whichHeap = HEAP_DALVIK;
-            } else if (strstr(name, "[stack") == name) {
+            } else if (strncmp(name, "/dev/ashmem", 11) == 0) {
+                if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
+                    whichHeap = HEAP_DALVIK_OTHER;
+                    if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
+                        subHeap = HEAP_DALVIK_LINEARALLOC;
+                    } else if ((strstr(name, "/dev/ashmem/dalvik-mark") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-allocspace alloc space live-bitmap") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-allocspace alloc space mark-bitmap") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-card table") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-allocation stack") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-live stack") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-imagespace") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-bitmap") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-card-table") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-mark-stack") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-aux-structure") == name)) {
+                        subHeap = HEAP_DALVIK_ACCOUNTING;
+                    } else if (strstr(name, "/dev/ashmem/dalvik-large") == name) {
+                        whichHeap = HEAP_DALVIK;
+                        subHeap = HEAP_DALVIK_LARGE;
+                    } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) {
+                        subHeap = HEAP_DALVIK_CODE_CACHE;
+                    } else {
+                        // This is the regular Dalvik heap.
+                        whichHeap = HEAP_DALVIK;
+                        subHeap = HEAP_DALVIK_NORMAL;
+                    }
+                } else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
+                    whichHeap = HEAP_CURSOR;
+                } else if (strncmp(name, "/dev/ashmem/libc malloc", 23) == 0) {
+                    whichHeap = HEAP_NATIVE;
+                } else {
+                    whichHeap = HEAP_ASHMEM;
+                }
+            } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
+                whichHeap = HEAP_NATIVE;
+            } else if (strncmp(name, "[stack", 6) == 0) {
                 whichHeap = HEAP_STACK;
-            } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
-                whichHeap = HEAP_CURSOR;
-            } else if (strstr(name, "/dev/ashmem/") == name) {
-                whichHeap = HEAP_ASHMEM;
-            } else if (strstr(name, "/dev/") == name) {
+            } else if (strncmp(name, "/dev/", 5) == 0) {
                 whichHeap = HEAP_UNKNOWN_DEV;
             } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
                 whichHeap = HEAP_SO;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
                 whichHeap = HEAP_JAR;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
                 whichHeap = HEAP_APK;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
                 whichHeap = HEAP_TTF;
+                is_swappable = true;
             } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) ||
                        (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
                 whichHeap = HEAP_DEX;
+                is_swappable = true;
+            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
+                whichHeap = HEAP_OAT;
+                is_swappable = true;
+            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
+                whichHeap = HEAP_ART;
+                is_swappable = true;
+            } else if (strncmp(name, "[anon:", 6) == 0) {
+                whichHeap = HEAP_UNKNOWN;
             } else if (nameLen > 0) {
                 whichHeap = HEAP_UNKNOWN_MAP;
             } else if (start == prevEnd && prevHeap == HEAP_SO) {
@@ -225,9 +363,29 @@
         }
 
         if (!skip) {
+            if (is_swappable && (pss > 0)) {
+                sharing_proportion = 0.0;
+                if ((shared_clean > 0) || (shared_dirty > 0)) {
+                    sharing_proportion = (pss - private_clean - private_dirty)/(shared_clean+shared_dirty);
+                }
+                swappable_pss = (sharing_proportion*shared_clean) + private_clean;
+            } else
+                swappable_pss = 0;
+
             stats[whichHeap].pss += pss;
+            stats[whichHeap].swappablePss += swappable_pss;
             stats[whichHeap].privateDirty += private_dirty;
             stats[whichHeap].sharedDirty += shared_dirty;
+            stats[whichHeap].privateClean += private_clean;
+            stats[whichHeap].sharedClean += shared_clean;
+            if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
+                stats[subHeap].pss += pss;
+                stats[subHeap].swappablePss += swappable_pss;
+                stats[subHeap].privateDirty += private_dirty;
+                stats[subHeap].sharedDirty += shared_dirty;
+                stats[subHeap].privateClean += private_clean;
+                stats[subHeap].sharedClean += shared_clean;
+            }
         }
     }
 }
@@ -253,18 +411,35 @@
 
     load_maps(pid, stats);
 
-    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+    struct graphics_memory_pss graphics_mem;
+    if (read_memtrack_memory(pid, &graphics_mem) == 0) {
+        stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
+        stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
+        stats[HEAP_GL].pss = graphics_mem.gl;
+        stats[HEAP_GL].privateDirty = graphics_mem.gl;
+        stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
+        stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
+    }
+
+    for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
         stats[HEAP_UNKNOWN].pss += stats[i].pss;
+        stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
         stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
         stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
+        stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
+        stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
     }
 
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
         env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
+        env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
         env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
         env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
+        env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
+        env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
     }
 
+
     jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
 
     jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
@@ -275,8 +450,11 @@
     int j=0;
     for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
         otherArray[j++] = stats[i].pss;
+        otherArray[j++] = stats[i].swappablePss;
         otherArray[j++] = stats[i].privateDirty;
         otherArray[j++] = stats[i].sharedDirty;
+        otherArray[j++] = stats[i].privateClean;
+        otherArray[j++] = stats[i].sharedClean;
     }
 
     env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
@@ -287,37 +465,178 @@
     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
 }
 
-static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss)
 {
     char line[1024];
     jlong pss = 0;
+    jlong uss = 0;
     unsigned temp;
 
     char tmp[128];
     FILE *fp;
 
-    sprintf(tmp, "/proc/%d/smaps", pid);
-    fp = fopen(tmp, "r");
-    if (fp == 0) return 0;
-
-    while (true) {
-        if (fgets(line, 1024, fp) == 0) {
-            break;
-        }
-
-        if (sscanf(line, "Pss: %d kB", &temp) == 1) {
-            pss += temp;
-        }
+    struct graphics_memory_pss graphics_mem;
+    if (read_memtrack_memory(pid, &graphics_mem) == 0) {
+        pss = uss = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
     }
 
-    fclose(fp);
+    sprintf(tmp, "/proc/%d/smaps", pid);
+    fp = fopen(tmp, "r");
+
+    if (fp != 0) {
+        while (true) {
+            if (fgets(line, 1024, fp) == NULL) {
+                break;
+            }
+
+            if (line[0] == 'P') {
+                if (strncmp(line, "Pss:", 4) == 0) {
+                    char* c = line + 4;
+                    while (*c != 0 && (*c < '0' || *c > '9')) {
+                        c++;
+                    }
+                    pss += atoi(c);
+                } else if (strncmp(line, "Private_Clean:", 14)
+                        || strncmp(line, "Private_Dirty:", 14)) {
+                    char* c = line + 14;
+                    while (*c != 0 && (*c < '0' || *c > '9')) {
+                        c++;
+                    }
+                    uss += atoi(c);
+                }
+            }
+        }
+
+        fclose(fp);
+    }
+
+    if (outUss != NULL) {
+        if (env->GetArrayLength(outUss) >= 1) {
+            jlong* outUssArray = env->GetLongArrayElements(outUss, 0);
+            if (outUssArray != NULL) {
+                outUssArray[0] = uss;
+            }
+            env->ReleaseLongArrayElements(outUss, outUssArray, 0);
+        }
+    }
 
     return pss;
 }
 
 static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
 {
-    return android_os_Debug_getPssPid(env, clazz, getpid());
+    return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
+}
+
+enum {
+    MEMINFO_TOTAL,
+    MEMINFO_FREE,
+    MEMINFO_BUFFERS,
+    MEMINFO_CACHED,
+    MEMINFO_SHMEM,
+    MEMINFO_SLAB,
+    MEMINFO_SWAP_TOTAL,
+    MEMINFO_SWAP_FREE,
+    MEMINFO_ZRAM_TOTAL,
+    MEMINFO_COUNT
+};
+
+static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
+{
+    char buffer[1024];
+    int numFound = 0;
+
+    if (out == NULL) {
+        jniThrowNullPointerException(env, "out == null");
+        return;
+    }
+
+    int fd = open("/proc/meminfo", O_RDONLY);
+
+    if (fd < 0) {
+        ALOGW("Unable to open /proc/meminfo: %s\n", strerror(errno));
+        return;
+    }
+
+    int len = read(fd, buffer, sizeof(buffer)-1);
+    close(fd);
+
+    if (len < 0) {
+        ALOGW("Empty /proc/meminfo");
+        return;
+    }
+    buffer[len] = 0;
+
+    static const char* const tags[] = {
+            "MemTotal:",
+            "MemFree:",
+            "Buffers:",
+            "Cached:",
+            "Shmem:",
+            "Slab:",
+            "SwapTotal:",
+            "SwapFree:",
+            NULL
+    };
+    static const int tagsLen[] = {
+            9,
+            8,
+            8,
+            7,
+            6,
+            5,
+            10,
+            9,
+            0
+    };
+    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+    char* p = buffer;
+    while (*p && numFound < 8) {
+        int i = 0;
+        while (tags[i]) {
+            if (strncmp(p, tags[i], tagsLen[i]) == 0) {
+                p += tagsLen[i];
+                while (*p == ' ') p++;
+                char* num = p;
+                while (*p >= '0' && *p <= '9') p++;
+                if (*p != 0) {
+                    *p = 0;
+                    p++;
+                }
+                mem[i] = atoll(num);
+                numFound++;
+                break;
+            }
+            i++;
+        }
+        while (*p && *p != '\n') {
+            p++;
+        }
+        if (*p) p++;
+    }
+
+    fd = open("/sys/block/zram0/mem_used_total", O_RDONLY);
+    if (fd >= 0) {
+        len = read(fd, buffer, sizeof(buffer)-1);
+        close(fd);
+        if (len > 0) {
+            buffer[len] = 0;
+            mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer)/1024;
+        }
+    }
+
+    int maxNum = env->GetArrayLength(out);
+    if (maxNum > MEMINFO_COUNT) {
+        maxNum = MEMINFO_COUNT;
+    }
+    jlong* outArray = env->GetLongArrayElements(out, 0);
+    if (outArray != NULL) {
+        for (int i=0; i<maxNum; i++) {
+            outArray[i] = mem[i];
+        }
+    }
+    env->ReleaseLongArrayElements(out, outArray, 0);
 }
 
 static jint read_binder_stat(const char* stat)
@@ -592,8 +911,10 @@
             (void*) android_os_Debug_getDirtyPagesPid },
     { "getPss",                 "()J",
             (void*) android_os_Debug_getPss },
-    { "getPss",                 "(I)J",
+    { "getPss",                 "(I[J)J",
             (void*) android_os_Debug_getPssPid },
+    { "getMemInfo",             "([J)V",
+            (void*) android_os_Debug_getMemInfo },
     { "dumpNativeHeap",         "(Ljava/io/FileDescriptor;)V",
             (void*) android_os_Debug_dumpNativeHeap },
     { "getBinderSentTransactions", "()I",
@@ -612,16 +933,26 @@
 
 int register_android_os_Debug(JNIEnv *env)
 {
+    int err = memtrack_init();
+    if (err != 0) {
+        memtrackLoaded = false;
+        ALOGE("failed to load memtrack module: %d", err);
+    } else {
+        memtrackLoaded = true;
+    }
+
     jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
 
     // Sanity check the number of other statistics expected in Java matches here.
     jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
     jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
+    jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
+    jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field);
     int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
-    if (numOtherStats != expectedNumOtherStats) {
+    if ((numOtherStats + numDvkStats) != expectedNumOtherStats) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
-                             "android.os.Debug.Meminfo.NUM_OTHER_STATS=%d expected %d",
-                             numOtherStats, expectedNumOtherStats);
+                             "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d",
+                             numOtherStats+numDvkStats, expectedNumOtherStats);
         return JNI_ERR;
     }
 
@@ -630,10 +961,16 @@
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
         stat_fields[i].pss_field =
                 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
+        stat_fields[i].pssSwappable_field =
+                env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I");
         stat_fields[i].privateDirty_field =
                 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
         stat_fields[i].sharedDirty_field =
                 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
+        stat_fields[i].privateClean_field =
+                env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I");
+        stat_fields[i].sharedClean_field =
+                env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
     }
 
     return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index a07f5b7..d1245da 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -33,28 +33,6 @@
 
 namespace android {
 
-jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
-                                         jstring file, jint mode,
-                                         jint uid, jint gid)
-{
-    const jchar* str = env->GetStringCritical(file, 0);
-    String8 file8;
-    if (str) {
-        file8 = String8(str, env->GetStringLength(file));
-        env->ReleaseStringCritical(file, str);
-    }
-    if (file8.size() <= 0) {
-        return ENOENT;
-    }
-    if (uid >= 0 || gid >= 0) {
-        int res = chown(file8.string(), uid, gid);
-        if (res != 0) {
-            return errno;
-        }
-    }
-    return chmod(file8.string(), mode) == 0 ? 0 : errno;
-}
-
 jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path)
 {
     if (path == NULL) {
@@ -77,7 +55,6 @@
 }
 
 static const JNINativeMethod methods[] = {
-    {"setPermissions",  "(Ljava/lang/String;III)I", (void*)android_os_FileUtils_setPermissions},
     {"getFatVolumeId",  "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getFatVolumeId},
 };
 
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 7540645..c9c3720 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -141,6 +141,11 @@
     return nativeMessageQueue->wake();
 }
 
+static jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jint ptr) {
+    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
+    return nativeMessageQueue->getLooper()->isIdling();
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMessageQueueMethods[] = {
@@ -148,7 +153,8 @@
     { "nativeInit", "()I", (void*)android_os_MessageQueue_nativeInit },
     { "nativeDestroy", "(I)V", (void*)android_os_MessageQueue_nativeDestroy },
     { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
-    { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
+    { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake },
+    { "nativeIsIdling", "(I)Z", (void*)android_os_MessageQueue_nativeIsIdling }
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 858ec79..aa451e3 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -35,7 +35,6 @@
 #include <utils/SystemClock.h>
 #include <utils/List.h>
 #include <utils/KeyedVector.h>
-#include <cutils/logger.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
deleted file mode 100644
index 99a2d04..0000000
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ /dev/null
@@ -1,151 +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.
- */
-
-//#define LOG_NDEBUG 0
-
-#include "JNIHelp.h"
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <stdio.h>
-
-#include <utils/Log.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-namespace android
-{
-
-static struct parcel_file_descriptor_offsets_t
-{
-    jfieldID mFileDescriptor;
-} gParcelFileDescriptorOffsets;
-
-static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFd(JNIEnv* env,
-    jobject clazz, jint origfd)
-{
-    int fd = dup(origfd);
-    if (fd < 0) {
-        jniThrowException(env, "java/io/IOException", strerror(errno));
-        return NULL;
-    }
-    return jniCreateFileDescriptor(env, fd);
-}
-
-static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup(JNIEnv* env,
-    jobject clazz, jint fd)
-{
-    return jniCreateFileDescriptor(env, fd);
-}
-
-static void android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
-    jobject clazz, jobjectArray outFds)
-{
-    int fds[2];
-    if (pipe(fds) < 0) {
-        int therr = errno;
-        jniThrowException(env, "java/io/IOException", strerror(therr));
-        return;
-    }
-
-    for (int i=0; i<2; i++) {
-        jobject fdObj = jniCreateFileDescriptor(env, fds[i]);
-        env->SetObjectArrayElement(outFds, i, fdObj);
-    }
-}
-
-static jint getFd(JNIEnv* env, jobject clazz)
-{
-    jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
-    if (descriptor == NULL) return -1;
-    return jniGetFDFromFileDescriptor(env, descriptor);
-}
-
-static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
-    jobject clazz)
-{
-    jint fd = getFd(env, clazz);
-    if (fd < 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
-        return -1;
-    }
-
-    struct stat st;
-    if (fstat(fd, &st) != 0) {
-        return -1;
-    }
-
-    if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
-        return st.st_size;
-    }
-
-    return -1;
-}
-
-static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
-    jobject clazz, jlong pos)
-{
-    jint fd = getFd(env, clazz);
-    if (fd < 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
-        return -1;
-    }
-
-    return lseek(fd, pos, SEEK_SET);
-}
-
-static jlong android_os_ParcelFileDescriptor_getFdNative(JNIEnv* env, jobject clazz)
-{
-    jint fd = getFd(env, clazz);
-    if (fd < 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
-        return -1;
-    }
-
-    return fd;
-}
-
-static const JNINativeMethod gParcelFileDescriptorMethods[] = {
-    {"getFileDescriptorFromFd", "(I)Ljava/io/FileDescriptor;",
-        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFd},
-    {"getFileDescriptorFromFdNoDup", "(I)Ljava/io/FileDescriptor;",
-        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup},
-    {"createPipeNative", "([Ljava/io/FileDescriptor;)V",
-        (void*)android_os_ParcelFileDescriptor_createPipeNative},
-    {"getStatSize", "()J",
-        (void*)android_os_ParcelFileDescriptor_getStatSize},
-    {"seekTo", "(J)J",
-        (void*)android_os_ParcelFileDescriptor_seekTo},
-    {"getFdNative", "()I",
-        (void*)android_os_ParcelFileDescriptor_getFdNative}
-};
-
-const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
-
-int register_android_os_ParcelFileDescriptor(JNIEnv* env)
-{
-    jclass clazz = env->FindClass(kParcelFileDescriptorPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
-    gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
-    LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
-                 "Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
-
-    return AndroidRuntime::registerNativeMethods(
-        env, kParcelFileDescriptorPathName,
-        gParcelFileDescriptorMethods, NELEM(gParcelFileDescriptorMethods));
-}
-
-}
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index 5c135ee..d20b800 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -19,18 +19,67 @@
  * System clock functions.
  */
 
+#ifdef HAVE_ANDROID_OS
+#include <linux/ioctl.h>
+#include <linux/rtc.h>
+#include <utils/Atomic.h>
+#include <linux/android_alarm.h>
+#endif
+
+#include <sys/time.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
 #include "JNIHelp.h"
 #include "jni.h"
 #include "android_runtime/AndroidRuntime.h"
 
-#include "utils/SystemClock.h"
-
 #include <sys/time.h>
 #include <time.h>
 
+#include <utils/SystemClock.h>
+
 namespace android {
 
 /*
+ * Set the current time.  This only works when running as root.
+ */
+static int setCurrentTimeMillis(int64_t millis)
+{
+    struct timeval tv;
+    struct timespec ts;
+    int fd;
+    int res;
+    int ret = 0;
+
+    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
+        return -1;
+    }
+
+    tv.tv_sec = (time_t) (millis / 1000LL);
+    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
+
+    ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
+
+    fd = open("/dev/alarm", O_RDWR);
+    if(fd < 0) {
+        ALOGW("Unable to open alarm driver: %s\n", strerror(errno));
+        return -1;
+    }
+    ts.tv_sec = tv.tv_sec;
+    ts.tv_nsec = tv.tv_usec * 1000;
+    res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+    if(res < 0) {
+        ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
+        ret = -1;
+    }
+    close(fd);
+    return ret;
+}
+
+/*
  * native public static void setCurrentTimeMillis(long millis)
  *
  * Set the current time.  This only works when running as root.
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 32f6ecf..2c23f9d 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -586,7 +586,7 @@
     }
 
     ResTable::resource_name name;
-    if (!am->getResources().getResourceName(resid, &name)) {
+    if (!am->getResources().getResourceName(resid, true, &name)) {
         return NULL;
     }
 
@@ -594,19 +594,27 @@
     if (name.package != NULL) {
         str.setTo(name.package, name.packageLen);
     }
-    if (name.type != NULL) {
+    if (name.type8 != NULL || name.type != NULL) {
         if (str.size() > 0) {
             char16_t div = ':';
             str.append(&div, 1);
         }
-        str.append(name.type, name.typeLen);
+        if (name.type8 != NULL) {
+            str.append(String16(name.type8, name.typeLen));
+        } else {
+            str.append(name.type, name.typeLen);
+        }
     }
-    if (name.name != NULL) {
+    if (name.name8 != NULL || name.name != NULL) {
         if (str.size() > 0) {
             char16_t div = '/';
             str.append(&div, 1);
         }
-        str.append(name.name, name.nameLen);
+        if (name.name8 != NULL) {
+            str.append(String16(name.name8, name.nameLen));
+        } else {
+            str.append(name.name, name.nameLen);
+        }
     }
 
     return env->NewString((const jchar*)str.string(), str.size());
@@ -621,7 +629,7 @@
     }
 
     ResTable::resource_name name;
-    if (!am->getResources().getResourceName(resid, &name)) {
+    if (!am->getResources().getResourceName(resid, true, &name)) {
         return NULL;
     }
 
@@ -641,10 +649,14 @@
     }
 
     ResTable::resource_name name;
-    if (!am->getResources().getResourceName(resid, &name)) {
+    if (!am->getResources().getResourceName(resid, true, &name)) {
         return NULL;
     }
 
+    if (name.type8 != NULL) {
+        return env->NewStringUTF(name.type8);
+    }
+
     if (name.type != NULL) {
         return env->NewString((const jchar*)name.type, name.typeLen);
     }
@@ -661,10 +673,14 @@
     }
 
     ResTable::resource_name name;
-    if (!am->getResources().getResourceName(resid, &name)) {
+    if (!am->getResources().getResourceName(resid, true, &name)) {
         return NULL;
     }
 
+    if (name.name8 != NULL) {
+        return env->NewStringUTF(name.name8);
+    }
+
     if (name.name != NULL) {
         return env->NewString((const jchar*)name.name, name.nameLen);
     }
@@ -680,7 +696,7 @@
 {
     if (outValue == NULL) {
          jniThrowNullPointerException(env, "outValue");
-         return NULL;
+         return 0;
     }
     AssetManager* am = assetManagerForJavaObject(env, clazz);
     if (am == NULL) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 8766cf9..3ac2225 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -35,7 +35,7 @@
 #include <utils/SystemClock.h>
 #include <utils/List.h>
 #include <utils/KeyedVector.h>
-#include <cutils/logger.h>
+#include <log/logger.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
@@ -986,6 +986,7 @@
 }
 
 // From frameworks/base/core/java/android/content/EventLogTags.logtags:
+#define ENABLE_BINDER_SAMPLE 0
 #define LOGTAG_BINDER_OPERATION 52004
 
 static void conditionally_log_binder_call(int64_t start_millis,
@@ -1063,6 +1064,7 @@
     ALOGV("Java code calling transact on %p in Java object %p with code %d\n",
             target, obj, code);
 
+#if ENABLE_BINDER_SAMPLE
     // Only log the binder call duration for things on the Java-level main thread.
     // But if we don't
     const bool time_binder_calls = should_time_binder_calls();
@@ -1071,12 +1073,15 @@
     if (time_binder_calls) {
         start_millis = uptimeMillis();
     }
+#endif
     //printf("Transact from Java code to %p sending: ", target); data->print();
     status_t err = target->transact(code, *data, reply, flags);
     //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
+#if ENABLE_BINDER_SAMPLE
     if (time_binder_calls) {
         conditionally_log_binder_call(start_millis, target, code);
     }
+#endif
 
     if (err == NO_ERROR) {
         return JNI_TRUE;
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 6ee504d..83d8aa2 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "jni.h"
-#include "cutils/logger.h"
+#include "log/logger.h"
 
 // The size of the tag number comes out of the payload size.
 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 607c429..8325217 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -33,6 +33,7 @@
 #include <sys/errno.h>
 #include <sys/resource.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <grp.h>
@@ -360,6 +361,32 @@
     return false;
 }
 
+jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
+                                          jint pid, jboolean is_increased)
+{
+    char text[64];
+
+    if (is_increased) {
+        strcpy(text, "/sys/fs/cgroup/memory/sw/tasks");
+    } else {
+        strcpy(text, "/sys/fs/cgroup/memory/tasks");
+    }
+
+    struct stat st;
+    if (stat(text, &st) || !S_ISREG(st.st_mode)) {
+        return false;
+    }
+
+    int fd = open(text, O_WRONLY);
+    if (fd >= 0) {
+        sprintf(text, "%d", pid);
+        write(fd, text, strlen(text));
+        close(fd);
+    }
+
+    return true;
+}
+
 void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
 {
     if (name == NULL) {
@@ -657,6 +684,7 @@
     PROC_SPACE_TERM = ' ',
     PROC_COMBINE = 0x100,
     PROC_PARENS = 0x200,
+    PROC_QUOTES = 0x400,
     PROC_OUT_STRING = 0x1000,
     PROC_OUT_LONG = 0x2000,
     PROC_OUT_FLOAT = 0x4000,
@@ -698,9 +726,15 @@
     jboolean res = JNI_TRUE;
 
     for (jsize fi=0; fi<NF; fi++) {
-        const jint mode = formatData[fi];
+        jint mode = formatData[fi];
         if ((mode&PROC_PARENS) != 0) {
             i++;
+        } else if ((mode&PROC_QUOTES != 0)) {
+            if (buffer[i] == '"') {
+                i++;
+            } else {
+                mode &= ~PROC_QUOTES;
+            }
         }
         const char term = (char)(mode&PROC_TERM_MASK);
         const jsize start = i;
@@ -716,6 +750,12 @@
             }
             end = i;
             i++;
+        } else if ((mode&PROC_QUOTES) != 0) {
+            while (buffer[i] != '"' && i < endIndex) {
+                i++;
+            }
+            end = i;
+            i++;
         }
         while (buffer[i] != term && i < endIndex) {
             i++;
@@ -984,6 +1024,7 @@
     {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},
     {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},
     {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
+    {"setSwappiness",   "(IZ)Z", (void*)android_os_Process_setSwappiness},
     {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
     {"setUid", "(I)I", (void*)android_os_Process_setUid},
     {"setGid", "(I)I", (void*)android_os_Process_setGid},
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b87fe27..b720e73 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -16,18 +16,19 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <EGL/egl.h>
-
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
+#include "android_view_GraphicBuffer.h"
+
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
-#include <gui/GLConsumer.h>
 
 #include <androidfw/ResourceTypes.h>
 
+#include <gui/GLConsumer.h>
+
 #include <private/hwui/DrawGlInfo.h>
 
 #include <cutils/properties.h>
@@ -99,10 +100,11 @@
     }
 }
 
-static void android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
+static bool android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
     if (Caches::hasInstance()) {
-        Caches::getInstance().init();
+        return Caches::getInstance().init();
     }
+    return false;
 }
 
 static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) {
@@ -112,6 +114,21 @@
 }
 
 // ----------------------------------------------------------------------------
+// Caching
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20Canvas_initAtlas(JNIEnv* env, jobject clazz,
+        jobject graphicBuffer, jintArray atlasMapArray, jint count) {
+
+    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
+    jint* atlasMap = env->GetIntArrayElements(atlasMapArray, NULL);
+
+    Caches::getInstance().assetAtlas.init(buffer, atlasMap, count);
+
+    env->ReleaseIntArrayElements(atlasMapArray, atlasMap, 0);
+}
+
+// ----------------------------------------------------------------------------
 // Constructors
 // ----------------------------------------------------------------------------
 
@@ -168,6 +185,16 @@
     }
 }
 
+static void android_view_GLES20Canvas_setCountOverdrawEnabled(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, jboolean enabled) {
+    renderer->setCountOverdrawEnabled(enabled);
+}
+
+static jfloat android_view_GLES20Canvas_getOverdraw(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer) {
+    return renderer->getOverdraw();
+}
+
 // ----------------------------------------------------------------------------
 // Functor
 // ----------------------------------------------------------------------------
@@ -271,7 +298,7 @@
 
 static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
-    return renderer->quickReject(left, top, right, bottom);
+    return renderer->quickRejectNoScissor(left, top, right, bottom);
 }
 
 static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
@@ -370,8 +397,8 @@
 }
 
 static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, SkMatrix* matrix,
-        SkPaint* paint) {
+        OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer,
+        SkMatrix* matrix, SkPaint* paint) {
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
@@ -390,7 +417,7 @@
         return;
     }
 
-    if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap)) {
+    if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap, true)) {
         delete bitmap;
         return;
     }
@@ -405,8 +432,8 @@
 
 static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer,
-        jint meshWidth, jint meshHeight, jfloatArray vertices, jint offset,
-        jintArray colors, jint colorOffset, SkPaint* paint) {
+        jint meshWidth, jint meshHeight, jfloatArray vertices, jint offset, jintArray colors,
+        jint colorOffset, SkPaint* paint) {
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
@@ -420,20 +447,12 @@
 }
 
 static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, jbyteArray chunks,
+        OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, Res_png_9patch* patch,
         float left, float top, float right, float bottom, SkPaint* paint) {
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
-    jbyte* storage = env->GetByteArrayElements(chunks, NULL);
-    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage);
-    Res_png_9patch::deserialize(patch);
-
-    renderer->drawPatch(bitmap, &patch->xDivs[0], &patch->yDivs[0],
-            &patch->colors[0], patch->numXDivs, patch->numYDivs, patch->numColors,
-            left, top, right, bottom, paint);
-
-    env->ReleaseByteArrayElements(chunks, storage, 0);
+    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
 }
 
 static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject clazz,
@@ -567,6 +586,20 @@
 // Text
 // ----------------------------------------------------------------------------
 
+static float xOffsetForTextAlign(SkPaint* paint, float totalAdvance) {
+    switch (paint->getTextAlign()) {
+        case SkPaint::kCenter_Align:
+            return -totalAdvance / 2.0f;
+            break;
+        case SkPaint::kRight_Align:
+            return -totalAdvance;
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
@@ -577,10 +610,15 @@
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     jfloat totalAdvance = value->getTotalAdvance();
+    x += xOffsetForTextAlign(paint, totalAdvance);
     const float* positions = value->getPos();
     int bytesCount = glyphsCount * sizeof(jchar);
-    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y,
-            positions, paint, totalAdvance);
+    const SkRect& r = value->getBounds();
+    android::uirenderer::Rect bounds(r.fLeft, r.fTop, r.fRight, r.fBottom);
+    bounds.translate(x, y);
+
+    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
+            x, y, positions, paint, totalAdvance, bounds);
 }
 
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
@@ -608,10 +646,15 @@
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     jfloat totalAdvance = value->getTotalAdvance();
+    x += xOffsetForTextAlign(paint, totalAdvance);
     const float* positions = value->getPos();
     int bytesCount = glyphsCount * sizeof(jchar);
-    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y,
-            positions, paint, totalAdvance);
+    const SkRect& r = value->getBounds();
+    android::uirenderer::Rect bounds(r.fLeft, r.fTop, r.fRight, r.fBottom);
+    bounds.translate(x, y);
+
+    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
+            x, y, positions, paint, totalAdvance, bounds);
 }
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
@@ -835,6 +878,23 @@
     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
 
     if (surfaceTexture->updateTexImage() == NO_ERROR) {
+        int64_t frameNumber = surfaceTexture->getFrameNumber();
+        // If the GLConsumer queue is in synchronous mode, need to discard all
+        // but latest frame, using the frame number to tell when we no longer
+        // have newer frames to target. Since we can't tell which mode it is in,
+        // do this unconditionally.
+        int dropCounter = 0;
+        while (surfaceTexture->updateTexImage() == NO_ERROR) {
+            int64_t newFrameNumber = surfaceTexture->getFrameNumber();
+            if (newFrameNumber == frameNumber) break;
+            frameNumber = newFrameNumber;
+            dropCounter++;
+        }
+        #if DEBUG_RENDERER
+        if (dropCounter > 0) {
+            RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
+        }
+        #endif
         surfaceTexture->getTransformMatrix(transform);
         GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
 
@@ -882,11 +942,21 @@
     renderer->pushLayerUpdate(layer);
 }
 
+static void android_view_GLES20Canvas_cancelLayerUpdate(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, Layer* layer) {
+    renderer->cancelLayerUpdate(layer);
+}
+
 static void android_view_GLES20Canvas_clearLayerUpdates(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->clearLayerUpdates();
 }
 
+static void android_view_GLES20Canvas_flushLayerUpdates(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer) {
+    renderer->flushLayerUpdates();
+}
+
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -932,9 +1002,12 @@
 
 #ifdef USE_OPENGL_RENDERER
     { "nFlushCaches",       "(I)V",            (void*) android_view_GLES20Canvas_flushCaches },
-    { "nInitCaches",        "()V",             (void*) android_view_GLES20Canvas_initCaches },
+    { "nInitCaches",        "()Z",             (void*) android_view_GLES20Canvas_initCaches },
     { "nTerminateCaches",   "()V",             (void*) android_view_GLES20Canvas_terminateCaches },
 
+    { "nInitAtlas",         "(Landroid/view/GraphicBuffer;[II)V",
+            (void*) android_view_GLES20Canvas_initAtlas },
+
     { "nCreateRenderer",    "()I",             (void*) android_view_GLES20Canvas_createRenderer },
     { "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
     { "nSetViewport",       "(III)V",          (void*) android_view_GLES20Canvas_setViewport },
@@ -944,6 +1017,9 @@
     { "nSetName",           "(ILjava/lang/String;)V",
             (void*) android_view_GLES20Canvas_setName },
 
+    { "nSetCountOverdrawEnabled", "(IZ)V",     (void*) android_view_GLES20Canvas_setCountOverdrawEnabled },
+    { "nGetOverdraw",             "(I)F",      (void*) android_view_GLES20Canvas_getOverdraw },
+
     { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
 
     { "nCallDrawGLFunction", "(II)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
@@ -984,7 +1060,7 @@
 
     { "nDrawBitmapMesh",    "(II[BII[FI[III)V",(void*) android_view_GLES20Canvas_drawBitmapMesh },
 
-    { "nDrawPatch",         "(II[B[BFFFFI)V",  (void*) android_view_GLES20Canvas_drawPatch },
+    { "nDrawPatch",         "(II[BIFFFFI)V",   (void*) android_view_GLES20Canvas_drawPatch },
 
     { "nDrawColor",         "(III)V",          (void*) android_view_GLES20Canvas_drawColor },
     { "nDrawRect",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawRect },
@@ -1053,7 +1129,9 @@
     { "nDrawLayer",              "(IIFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(II)Z",      (void*) android_view_GLES20Canvas_copyLayer },
     { "nClearLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
+    { "nFlushLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_flushLayerUpdates },
     { "nPushLayerUpdate",        "(II)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
+    { "nCancelLayerUpdate",      "(II)V",      (void*) android_view_GLES20Canvas_cancelLayerUpdate },
 
     { "nSetTextureLayerTransform", "(II)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
 
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
new file mode 100644
index 0000000..d68c0b2
--- /dev/null
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "GraphicBuffer"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "android_os_Parcel.h"
+#include "android_view_GraphicBuffer.h"
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <binder/Parcel.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
+#include <private/gui/ComposerService.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Defines
+// ----------------------------------------------------------------------------
+
+// Debug
+#define DEBUG_GRAPHIC_BUFFER 0
+
+// Debug
+#if DEBUG_GRAPHIC_BUFFER
+    #define GB_LOGD(...) ALOGD(__VA_ARGS__)
+    #define GB_LOGW(...) ALOGW(__VA_ARGS__)
+#else
+    #define GB_LOGD(...)
+    #define GB_LOGW(...)
+#endif
+
+#define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN
+
+// ----------------------------------------------------------------------------
+// JNI Helpers
+// ----------------------------------------------------------------------------
+
+static struct {
+    jfieldID mNativeObject;
+} gGraphicBufferClassInfo;
+
+static struct {
+    jmethodID set;
+    jfieldID left;
+    jfieldID top;
+    jfieldID right;
+    jfieldID bottom;
+} gRectClassInfo;
+
+static struct {
+    jfieldID mFinalizer;
+    jfieldID mNativeCanvas;
+    jfieldID mSurfaceFormat;
+} gCanvasClassInfo;
+
+static struct {
+    jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
+#define GET_INT(object, field) \
+    env->GetIntField(object, field)
+
+#define SET_INT(object, field, value) \
+    env->SetIntField(object, field, value)
+
+#define INVOKEV(object, method, ...) \
+    env->CallVoidMethod(object, method, __VA_ARGS__)
+
+// ----------------------------------------------------------------------------
+// Types
+// ----------------------------------------------------------------------------
+
+class GraphicBufferWrapper {
+public:
+    GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) {
+    }
+
+    sp<GraphicBuffer> buffer;
+};
+
+// ----------------------------------------------------------------------------
+// GraphicBuffer lifecycle
+// ----------------------------------------------------------------------------
+
+static GraphicBufferWrapper* android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz,
+        jint width, jint height, jint format, jint usage) {
+
+    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+    sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
+    if (alloc == NULL) {
+        GB_LOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
+        return NULL;
+    }
+
+    status_t error;
+    sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error));
+    if (buffer == NULL) {
+        GB_LOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
+        return NULL;
+    }
+
+    return new GraphicBufferWrapper(buffer);
+}
+
+static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz,
+        GraphicBufferWrapper* wrapper) {
+    delete wrapper;
+}
+
+// ----------------------------------------------------------------------------
+// Canvas management
+// ----------------------------------------------------------------------------
+
+static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
+    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
+    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
+            GET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas));
+    SET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas, (int) newCanvas);
+    SET_INT(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int) newCanvas);
+    SkSafeUnref(previousCanvas);
+}
+
+static inline SkBitmap::Config convertPixelFormat(int32_t format) {
+    switch (format) {
+        case PIXEL_FORMAT_RGBA_8888:
+            return SkBitmap::kARGB_8888_Config;
+        case PIXEL_FORMAT_RGBX_8888:
+            return SkBitmap::kARGB_8888_Config;
+        case PIXEL_FORMAT_RGB_565:
+            return SkBitmap::kRGB_565_Config;
+        default:
+            return SkBitmap::kNo_Config;
+    }
+}
+
+static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
+        GraphicBufferWrapper* wrapper, jobject canvas, jobject dirtyRect) {
+
+    if (!wrapper) {
+        return false;
+    }
+
+    sp<GraphicBuffer> buffer(wrapper->buffer);
+
+    Rect rect;
+    if (dirtyRect) {
+        rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
+        rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
+        rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
+        rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
+    } else {
+        rect.set(Rect(buffer->getWidth(), buffer->getHeight()));
+    }
+
+    void* bits = NULL;
+    status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits);
+
+    if (status) return false;
+    if (!bits) {
+        buffer->unlock();
+        return false;
+    }
+
+    ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
+
+    SkBitmap bitmap;
+    bitmap.setConfig(convertPixelFormat(buffer->getPixelFormat()),
+            buffer->getWidth(), buffer->getHeight(), bytesCount);
+
+    if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
+        bitmap.setPixels(bits);
+    } else {
+        bitmap.setPixels(NULL);
+    }
+
+    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
+
+    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
+    swapCanvasPtr(env, canvas, nativeCanvas);
+
+    SkRect clipRect;
+    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
+    nativeCanvas->clipRect(clipRect);
+
+    if (dirtyRect) {
+        INVOKEV(dirtyRect, gRectClassInfo.set,
+                int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
+    }
+
+    return true;
+}
+
+static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
+        GraphicBufferWrapper* wrapper, jobject canvas) {
+
+    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+    swapCanvasPtr(env, canvas, nativeCanvas);
+
+    if (wrapper) {
+        status_t status = wrapper->buffer->unlock();
+        return status == 0;
+    }
+
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+// Serialization
+// ----------------------------------------------------------------------------
+
+static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz,
+        GraphicBufferWrapper* wrapper, jobject dest) {
+    Parcel* parcel = parcelForJavaObject(env, dest);
+    if (parcel) {
+        parcel->write(*wrapper->buffer);
+    }
+}
+
+static GraphicBufferWrapper* android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz,
+        jobject in) {
+
+    Parcel* parcel = parcelForJavaObject(env, in);
+    if (parcel) {
+        sp<GraphicBuffer> buffer = new GraphicBuffer();
+        parcel->read(*buffer);
+        return new GraphicBufferWrapper(buffer);
+    }
+
+    return NULL;
+}
+
+// ----------------------------------------------------------------------------
+// External helpers
+// ----------------------------------------------------------------------------
+
+sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
+    if (obj) {
+        jint nativeObject = env->GetIntField(obj, gGraphicBufferClassInfo.mNativeObject);
+        GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject;
+        if (wrapper != NULL) {
+            sp<GraphicBuffer> buffer(wrapper->buffer);
+            return buffer;
+        }
+    }
+    return NULL;
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(!var, "Unable to find method " methodName);
+
+const char* const kClassPathName = "android/view/GraphicBuffer";
+
+static JNINativeMethod gMethods[] = {
+    { "nCreateGraphicBuffer",  "(IIII)I", (void*) android_view_GraphiceBuffer_create },
+    { "nDestroyGraphicBuffer", "(I)V",    (void*) android_view_GraphiceBuffer_destroy },
+
+    { "nWriteGraphicBufferToParcel",  "(ILandroid/os/Parcel;)V",
+            (void*) android_view_GraphiceBuffer_write },
+    { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)I",
+            (void*) android_view_GraphiceBuffer_read },
+
+    { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
+            (void*) android_view_GraphicBuffer_lockCanvas },
+    { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)Z",
+            (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
+};
+
+int register_android_view_GraphicBuffer(JNIEnv* env) {
+    jclass clazz;
+    FIND_CLASS(clazz, "android/view/GraphicBuffer");
+    GET_FIELD_ID(gGraphicBufferClassInfo.mNativeObject, clazz, "mNativeObject", "I");
+
+    FIND_CLASS(clazz, "android/graphics/Rect");
+    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
+    GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
+    GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
+    GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
+    GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
+
+    FIND_CLASS(clazz, "android/graphics/Canvas");
+    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
+            "Landroid/graphics/Canvas$CanvasFinalizer;");
+    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
+    GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
+
+    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
+    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
+
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_view_GraphicBuffer.h b/core/jni/android_view_GraphicBuffer.h
new file mode 100644
index 0000000..509587c
--- /dev/null
+++ b/core/jni/android_view_GraphicBuffer.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#include <ui/GraphicBuffer.h>
+
+#include "jni.h"
+
+namespace android {
+
+// This function does not perform any type checking, the specified
+// object must be an instance of android.view.GraphicBuffer
+extern sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj);
+
+}
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
index 948a966..479fbe2 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -20,9 +20,14 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <EGL/egl_cache.h>
 
+#include <utils/Timers.h>
+
 #include <Caches.h>
+#include <Extensions.h>
 
 #ifdef USE_OPENGL_RENDERER
     EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@@ -119,6 +124,13 @@
     eglBeginFrame(display, surface);
 }
 
+static jlong android_view_HardwareRenderer_getSystemTime(JNIEnv* env, jobject clazz) {
+    if (uirenderer::Extensions::getInstance().hasNvSystemTime()) {
+        return eglGetSystemTimeNV();
+    }
+    return systemTime(SYSTEM_TIME_MONOTONIC);
+}
+
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -146,6 +158,8 @@
     { "nLoadProperties",        "()Z",   (void*) android_view_HardwareRenderer_loadProperties },
 
     { "nBeginFrame",            "([I)V", (void*) android_view_HardwareRenderer_beginFrame },
+
+    { "nGetSystemTime",         "()J",   (void*) android_view_HardwareRenderer_getSystemTime },
 #endif
 
     { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 9fa9fe4..ce475e0 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -21,7 +21,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <binder/Parcel.h>
 #include <utils/Log.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
 #include "android_view_InputChannel.h"
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h
index 0967021..2ba2dc0 100644
--- a/core/jni/android_view_InputChannel.h
+++ b/core/jni/android_view_InputChannel.h
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
 
 namespace android {
 
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index e3a54a8..bef0f84 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <androidfw/Input.h>
+#include <input/Input.h>
 
 #include <android_runtime/AndroidRuntime.h>
 #include <nativehelper/jni.h>
@@ -53,11 +53,15 @@
         return NULL;
     }
 
+    const InputDeviceIdentifier& ident = deviceInfo.getIdentifier();
+
     ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
-            gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
-            nameObj.get(), descriptorObj.get(), deviceInfo.isExternal(),
-            deviceInfo.getSources(), deviceInfo.getKeyboardType(),
-            kcmObj.get(), deviceInfo.hasVibrator()));
+                gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
+                deviceInfo.getControllerNumber(), nameObj.get(),
+                static_cast<int32_t>(ident.vendor), static_cast<int32_t>(ident.product),
+                descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(),
+                deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
+                deviceInfo.hasButtonUnderPad()));
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
@@ -87,7 +91,8 @@
     gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
 
     GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
-            "<init>", "(IILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;Z)V");
+            "<init>",
+            "(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFFF)V");
diff --git a/core/jni/android_view_InputDevice.h b/core/jni/android_view_InputDevice.h
index 78651ba..ac38eb1 100644
--- a/core/jni/android_view_InputDevice.h
+++ b/core/jni/android_view_InputDevice.h
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 
-#include <androidfw/InputDevice.h>
+#include <input/InputDevice.h>
 
 namespace android {
 
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 8e1e04a..b254de7 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -29,7 +29,7 @@
 #include <utils/Looper.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
 #include "android_os_MessageQueue.h"
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index b46eb4b..e4b65a1 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -29,7 +29,7 @@
 #include <utils/Looper.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
 #include "android_os_MessageQueue.h"
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index ec56afa..7532c9d 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -23,7 +23,7 @@
 #include <android/input.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_InputQueue.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
 #include <utils/Looper.h>
 #include <utils/TypeHelpers.h>
 #include <ScopedLocalRef.h>
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 3e56a89..ffe2dea 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -16,8 +16,8 @@
 
 #include <android_runtime/AndroidRuntime.h>
 
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/Input.h>
+#include <input/KeyCharacterMap.h>
+#include <input/Input.h>
 #include <binder/Parcel.h>
 
 #include <nativehelper/jni.h>
diff --git a/core/jni/android_view_KeyCharacterMap.h b/core/jni/android_view_KeyCharacterMap.h
index 04024f6..e8465c2 100644
--- a/core/jni/android_view_KeyCharacterMap.h
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 
-#include <androidfw/KeyCharacterMap.h>
+#include <input/KeyCharacterMap.h>
 
 namespace android {
 
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 36a98f9..c83541d 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -19,8 +19,9 @@
 #include "JNIHelp.h"
 
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
 #include <utils/Log.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
 #include "android_view_KeyEvent.h"
 
 namespace android {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index e69fb74..f1b90e1 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -18,17 +18,16 @@
 
 #include "JNIHelp.h"
 
+#include <SkMatrix.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
 #include <utils/Log.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
 #include "android_os_Parcel.h"
 #include "android_view_MotionEvent.h"
 #include "android_util_Binder.h"
 #include "android/graphics/Matrix.h"
 
-#include "SkMatrix.h"
-
-
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -680,7 +679,18 @@
         jint nativePtr, jobject matrixObj) {
     SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->transform(matrix);
+
+    float m[9];
+    m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX));
+    m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX));
+    m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX));
+    m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY));
+    m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY));
+    m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY));
+    m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0));
+    m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1));
+    m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2));
+    event->transform(m);
 }
 
 static jint android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 8b6dc60..5e29213 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -21,6 +21,7 @@
 #include "android_view_PointerIcon.h"
 
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
 #include <utils/Log.h>
 #include <android/graphics/GraphicsJNI.h>
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index d9f6be9..1868469 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -26,6 +26,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
+#include <android_runtime/Log.h>
 
 #include <binder/Parcel.h>
 
@@ -107,7 +108,7 @@
         return NULL;
     }
 
-    sp<Surface> surface(new Surface(bufferProducer));
+    sp<Surface> surface(new Surface(bufferProducer, true));
     if (surface == NULL) {
         return NULL;
     }
@@ -135,15 +136,14 @@
 
 static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
         jobject surfaceTextureObj) {
-    sp<GLConsumer> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
-    if (st == NULL) {
+    sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
+    if (producer == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                 "SurfaceTexture has already been released");
         return 0;
     }
 
-    sp<IGraphicBufferProducer> bq = st->getBufferQueue();
-    sp<Surface> surface(new Surface(bq));
+    sp<Surface> surface(new Surface(producer, true));
     if (surface == NULL) {
         jniThrowException(env, OutOfResourcesException, NULL);
         return 0;
@@ -183,9 +183,7 @@
     switch (format) {
     case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
     case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
-    case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
     case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
-    case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;
     default:                        return SkBitmap::kNo_Config;
     }
 }
@@ -199,40 +197,34 @@
   SkSafeUnref(previousCanvas);
 }
 
-static void nativeLockCanvas(JNIEnv* env, jclass clazz,
+static jint nativeLockCanvas(JNIEnv* env, jclass clazz,
         jint nativeObject, jobject canvasObj, jobject dirtyRectObj) {
     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
 
     if (!isSurfaceValid(surface)) {
         doThrowIAE(env);
-        return;
+        return 0;
     }
 
-    // get dirty region
-    Region dirtyRegion;
+    Rect dirtyRect;
+    Rect* dirtyRectPtr = NULL;
+
     if (dirtyRectObj) {
-        Rect dirty;
-        dirty.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
-        dirty.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
-        dirty.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
-        dirty.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
-        if (!dirty.isEmpty()) {
-            dirtyRegion.set(dirty);
-        }
-    } else {
-        dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
+        dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
+        dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
+        dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
+        dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
+        dirtyRectPtr = &dirtyRect;
     }
 
     ANativeWindow_Buffer outBuffer;
-    Rect dirtyBounds(dirtyRegion.getBounds());
-    status_t err = surface->lock(&outBuffer, &dirtyBounds);
-    dirtyRegion.set(dirtyBounds);
+    status_t err = surface->lock(&outBuffer, dirtyRectPtr);
     if (err < 0) {
         const char* const exception = (err == NO_MEMORY) ?
                 OutOfResourcesException :
                 "java/lang/IllegalArgumentException";
         jniThrowException(env, exception, NULL);
-        return;
+        return 0;
     }
 
     // Associate a SkCanvas object to this surface
@@ -254,28 +246,23 @@
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
     swapCanvasPtr(env, canvasObj, nativeCanvas);
 
-    SkRegion clipReg;
-    if (dirtyRegion.isRect()) { // very common case
-        const Rect b(dirtyRegion.getBounds());
-        clipReg.setRect(b.left, b.top, b.right, b.bottom);
-    } else {
-        size_t count;
-        Rect const* r = dirtyRegion.getArray(&count);
-        while (count) {
-            clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
-            r++, count--;
-        }
+    if (dirtyRectPtr) {
+        nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
     }
 
-    nativeCanvas->clipRegion(clipReg);
-
     if (dirtyRectObj) {
-        const Rect& bounds(dirtyRegion.getBounds());
-        env->SetIntField(dirtyRectObj, gRectClassInfo.left, bounds.left);
-        env->SetIntField(dirtyRectObj, gRectClassInfo.top, bounds.top);
-        env->SetIntField(dirtyRectObj, gRectClassInfo.right, bounds.right);
-        env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, bounds.bottom);
+        env->SetIntField(dirtyRectObj, gRectClassInfo.left,   dirtyRect.left);
+        env->SetIntField(dirtyRectObj, gRectClassInfo.top,    dirtyRect.top);
+        env->SetIntField(dirtyRectObj, gRectClassInfo.right,  dirtyRect.right);
+        env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
     }
+
+    // Create another reference to the surface and return it.  This reference
+    // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
+    // because the latter could be replaced while the surface is locked.
+    sp<Surface> lockedSurface(surface);
+    lockedSurface->incStrong(&sRefBaseOwner);
+    return (int) lockedSurface.get();
 }
 
 static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
@@ -337,7 +324,7 @@
     sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
     if (gbp != NULL) {
         // we have a new IGraphicBufferProducer, create a new Surface for it
-        sur = new Surface(gbp);
+        sur = new Surface(gbp, true);
         // and keep a reference before passing to java
         sur->incStrong(&sRefBaseOwner);
     }
@@ -372,7 +359,7 @@
             (void*)nativeIsValid },
     {"nativeIsConsumerRunningBehind", "(I)Z",
             (void*)nativeIsConsumerRunningBehind },
-    {"nativeLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V",
+    {"nativeLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)I",
             (void*)nativeLockCanvas },
     {"nativeUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
             (void*)nativeUnlockCanvasAndPost },
@@ -392,7 +379,7 @@
     jclass clazz = env->FindClass("android/view/Surface");
     gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
     gSurfaceClassInfo.mNativeObject =
-            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeSurface", "I");
+            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "I");
     gSurfaceClassInfo.mLock =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
     gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index ec10536..67eade8 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -155,9 +155,7 @@
     switch (format) {
     case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
     case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
-    case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
     case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
-    case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;
     default:                        return SkBitmap::kNo_Config;
     }
 }
@@ -197,7 +195,8 @@
         bitmap->setPixels(NULL);
     }
 
-    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
+    return GraphicsJNI::createBitmap(env, bitmap,
+            GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
 }
 
 static void nativeScreenshot(JNIEnv* env, jclass clazz,
@@ -335,6 +334,12 @@
     return javaObjectForIBinder(env, token);
 }
 
+static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+    SurfaceComposerClient::destroyDisplay(token);
+}
+
 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
         jobject tokenObj, jint nativeSurfaceObject) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
@@ -443,6 +448,8 @@
             (void*)nativeGetBuiltInDisplay },
     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
             (void*)nativeCreateDisplay },
+    {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
+            (void*)nativeDestroyDisplay },
     {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V",
             (void*)nativeSetDisplaySurface },
     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 5baae84..0f429005 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -69,13 +69,6 @@
 // Native layer
 // ----------------------------------------------------------------------------
 
-static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
-    jobject surface, jint width, jint height) {
-
-    sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
-    glConsumer->setDefaultBufferSize(width, height);
-}
-
 static inline SkBitmap::Config convertPixelFormat(int32_t format) {
     switch (format) {
         case WINDOW_FORMAT_RGBA_8888:
@@ -106,8 +99,8 @@
 static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView,
         jobject surface) {
 
-    sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
-    sp<ANativeWindow> window = new Surface(glConsumer->getBufferQueue());
+    sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surface));
+    sp<ANativeWindow> window = new Surface(producer, true);
 
     window->incStrong((void*)android_view_TextureView_createNativeWindow);
     SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
@@ -126,19 +119,19 @@
 }
 
 static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
+    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
+    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
           env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-  env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
-  env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
-  SkSafeUnref(previousCanvas);
+    env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
+    env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
+    SkSafeUnref(previousCanvas);
 }
 
-static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
+static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
         jint nativeWindow, jobject canvas, jobject dirtyRect) {
 
     if (!nativeWindow) {
-        return;
+        return false;
     }
 
     ANativeWindow_Buffer buffer;
@@ -154,7 +147,8 @@
     }
 
     sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
-    native_window_lock(window.get(), &buffer, &rect);
+    int32_t status = native_window_lock(window.get(), &buffer, &rect);
+    if (status) return false;
 
     ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format);
 
@@ -184,6 +178,8 @@
         INVOKEV(dirtyRect, gRectClassInfo.set,
                 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
     }
+
+    return true;
 }
 
 static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
@@ -205,15 +201,12 @@
 const char* const kClassPathName = "android/view/TextureView";
 
 static JNINativeMethod gMethods[] = {
-    {   "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V",
-            (void*) android_view_TextureView_setDefaultBufferSize },
-
     {   "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
             (void*) android_view_TextureView_createNativeWindow },
     {   "nDestroyNativeWindow", "()V",
             (void*) android_view_TextureView_destroyNativeWindow },
 
-    {   "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V",
+    {   "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
             (void*) android_view_TextureView_lockCanvas },
     {   "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
             (void*) android_view_TextureView_unlockCanvasAndPost },
@@ -241,7 +234,8 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
+    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
+            "Landroid/graphics/Canvas$CanvasFinalizer;");
     GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
     GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
 
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index c2fa3be..90ba2ba 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -20,8 +20,8 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
-#include <androidfw/Input.h>
-#include <androidfw/VelocityTracker.h>
+#include <input/Input.h>
+#include <input/VelocityTracker.h>
 #include "android_view_MotionEvent.h"
 
 #include <ScopedUtfChars.h>
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 8d6fab4..bf5accd 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -20,7 +20,7 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include <utils/Log.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileRO.h>
 #include <ScopedUtfChars.h>
 
 #include <zlib.h>
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 0906593..ec19f0a 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 
 #include <android_runtime/AndroidRuntime.h>
-#include <cutils/logger.h>
 #include <jni.h>
 
 #include <ScopedUtfChars.h>
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 37330ec..50b3302 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -258,7 +258,6 @@
     case SkBitmap::kARGB_8888_Config:   return PIXEL_FORMAT_RGBA_8888;
     case SkBitmap::kARGB_4444_Config:   return PIXEL_FORMAT_RGBA_4444;
     case SkBitmap::kRGB_565_Config:     return PIXEL_FORMAT_RGB_565;
-    case SkBitmap::kA8_Config:          return PIXEL_FORMAT_A_8;
     default:                            return PIXEL_FORMAT_NONE;
     }
 }
@@ -352,10 +351,9 @@
                 "Make sure the SurfaceTexture is valid");
         return 0;
     }
-    
-    sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(_env, native_window));
 
-    window = new Surface(glConsumer->getBufferQueue());
+    sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(_env, native_window));
+    window = new Surface(producer, true);
     if (window == NULL)
         goto not_valid_surface;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4bff536..15e1d0f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -29,8 +29,10 @@
     <protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
     <protected-broadcast android:name="android.intent.action.SCREEN_ON" />
     <protected-broadcast android:name="android.intent.action.USER_PRESENT" />
+    <protected-broadcast android:name="android.intent.action.TIME_SET" />
     <protected-broadcast android:name="android.intent.action.TIME_TICK" />
     <protected-broadcast android:name="android.intent.action.TIMEZONE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.DATE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
@@ -64,6 +66,9 @@
     <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
     <protected-broadcast android:name="android.intent.action.USER_ADDED" />
     <protected-broadcast android:name="android.intent.action.USER_REMOVED" />
+    <protected-broadcast android:name="android.intent.action.USER_STARTING" />
+    <protected-broadcast android:name="android.intent.action.USER_STARTED" />
+    <protected-broadcast android:name="android.intent.action.USER_STOPPING" />
     <protected-broadcast android:name="android.intent.action.USER_STOPPED" />
     <protected-broadcast android:name="android.intent.action.USER_BACKGROUND" />
     <protected-broadcast android:name="android.intent.action.USER_FOREGROUND" />
@@ -89,6 +94,8 @@
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.UUID" />
+    <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
     <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
     <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
@@ -101,6 +108,10 @@
     <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
     <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
     <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" />
+    <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
+    <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
+    <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
+    <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
     <protected-broadcast
         android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
@@ -114,7 +125,30 @@
     <protected-broadcast
         android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
+        android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
+    <protected-broadcast
+        android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
+    <protected-broadcast
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
+    <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
+    <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_HANDOVER_STARTED" />
+    <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
+    <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
+    <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_TRANSFER_PROGRESS" />
+    <protected-broadcast android:name="android.btopp.intent.action.LIST" />
+    <protected-broadcast android:name="android.btopp.intent.action.OPEN_OUTBOUND" />
+    <protected-broadcast android:name="android.btopp.intent.action.HIDE_COMPLETE" />
+    <protected-broadcast android:name="android.btopp.intent.action.CONFIRM" />
+    <protected-broadcast android:name="android.btopp.intent.action.HIDE" />
+    <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_TRANSFER_DONE" />
+    <protected-broadcast android:name="android.btopp.intent.action.RETRY" />
+    <protected-broadcast android:name="android.btopp.intent.action.OPEN" />
+    <protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
+    <protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
+    <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
+    <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
+    <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
 
     <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
 
@@ -131,12 +165,34 @@
     <protected-broadcast android:name="android.intent.action.USB_AUDIO_ACCESSORY_PLUG" />
     <protected-broadcast android:name="android.intent.action.USB_AUDIO_DEVICE_PLUG" />
 
+    <protected-broadcast android:name="android.media.AUDIO_BECOMING_NOISY" />
+    <protected-broadcast android:name="android.media.RINGER_MODE_CHANGED" />
+    <protected-broadcast android:name="android.media.VIBRATE_SETTING_CHANGED" />
+    <protected-broadcast android:name="android.media.VOLUME_CHANGED_ACTION" />
+    <protected-broadcast android:name="android.media.MASTER_VOLUME_CHANGED_ACTION" />
+    <protected-broadcast android:name="android.media.MASTER_MUTE_CHANGED_ACTION" />
+    <protected-broadcast android:name="android.media.SCO_AUDIO_STATE_CHANGED" />
+    <protected-broadcast android:name="android.media.ACTION_SCO_AUDIO_STATE_UPDATED" />
+
+    <protected-broadcast android:name="android.intent.action.MEDIA_REMOVED" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTED" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_CHECKING" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_NOFS" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_MOUNTED" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_SHARED" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_UNSHARED" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTABLE" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_EJECT" />
+
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
     <protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
     <protected-broadcast android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
     <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED" />
 
+    <protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
+
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
@@ -151,6 +207,7 @@
     <protected-broadcast android:name="android.intent.action.DREAMING_STARTED" />
     <protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
     <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+    <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN" />
 
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
@@ -172,6 +229,9 @@
     <protected-broadcast android:name="android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED" />
     <protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
+    <protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
+    <protected-brodcast
+            android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
     <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
     <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
     <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
@@ -181,6 +241,19 @@
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
 
+    <protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" />
+
+    <protected-broadcast android:name="android.intent.action.PHONE_STATE" />
+
+    <protected-broadcast android:name="android.location.GPS_ENABLED_CHANGE" />
+    <protected-broadcast android:name="android.location.PROVIDERS_CHANGED" />
+    <protected-broadcast android:name="android.location.MODE_CHANGED" />
+    <protected-broadcast android:name="android.location.GPS_FIX_CHANGE" />
+    <protected-broadcast android:name="android.net.proxy.PAC_REFRESH" />
+
+    <protected-broadcast
+        android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
@@ -700,6 +773,13 @@
         android:description="@string/permdesc_bluetoothAdmin"
         android:label="@string/permlab_bluetoothAdmin" />
 
+    <!-- Allows applications to pair bluetooth devices without user interaction -->
+    <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
+        android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
+        android:protectionLevel="system|signature"
+        android:description="@string/permdesc_bluetoothPriv"
+        android:label="@string/permlab_bluetoothPriv" />
+
     <!-- Allows bluetooth stack to access files
          @hide This should only be used by Bluetooth apk.
     -->
@@ -826,6 +906,13 @@
         android:label="@string/permlab_wakeLock"
         android:description="@string/permdesc_wakeLock" />
 
+    <!-- Allows using the device's IR transmitter, if available -->
+    <permission android:name="android.permission.TRANSMIT_IR"
+        android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
+        android:protectionLevel="normal"
+        android:label="@string/permlab_transmitIr"
+        android:description="@string/permdesc_transmitIr" />
+
     <!-- ==================================================== -->
     <!-- Permissions related to changing audio settings   -->
     <!-- ==================================================== -->
@@ -1023,6 +1110,13 @@
         android:description="@string/permdesc_use_sip"
         android:label="@string/permlab_use_sip" />
 
+    <!-- Allows an application to request CallHandlerService implementations. -->
+    <permission android:name="android.permission.BIND_CALL_SERVICE"
+        android:permissionGroup="android.permission-group.PHONE_CALLS"
+        android:protectionLevel="system|signature"
+        android:description="@string/permdesc_bind_call_service"
+        android:label="@string/permlab_bind_call_service" />
+
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
@@ -1039,15 +1133,15 @@
     <!-- Allows an application to read from external storage.
          <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
          granted this permission.</p>
-         <p>Currently, this permission is not enforced and all apps still have access to read from
-         external storage without this permission. That will change in a future release and apps
-         will require this permission to read from external storage. So if your
-         app reads from the external storage, you should add this permission to your app now
-         to ensure that it continues to work on future versions of Android.</p>
-         <p>You can test your app with the permission enforced by either running your app on the
-         Android Emulator when running Android 4.1 or higher, or enabling <em>Protect USB
+         <p>This permission is enforced starting in API level 19.  Before API level 19, this
+         permission is not enforced and all apps still have access to read from external storage.
+         You can test your app with the permission enforced by enabling <em>Protect USB
          storage</em> under Developer options in the Settings app on a device running Android 4.1 or
          higher.</p>
+         <p>Also starting in API level 19, this permission is <em>not</em> required to
+         read/write files in your application-specific directories returned by
+         {@link android.content.Context#getExternalFilesDir} and
+         {@link android.content.Context#getExternalCacheDir}.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
          minSdkVersion}</a> and <a
@@ -1070,7 +1164,11 @@
          targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
          grants your app this permission. If you don't need this permission, be sure your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 4 or higher. -->
+         targetSdkVersion}</a> is 4 or higher.
+         <p>Starting in API level 19, this permission is <em>not</em> required to
+         read/write files in your application-specific directories returned by
+         {@link android.content.Context#getExternalFilesDir} and
+         {@link android.content.Context#getExternalCacheDir}. -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardWrite"
@@ -1085,6 +1183,14 @@
         android:description="@string/permdesc_mediaStorageWrite"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows an application to manage access to documents, usually as part
+         of a document picker. -->
+    <permission android:name="android.permission.MANAGE_DOCUMENTS"
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_manageDocs"
+        android:description="@string/permdesc_manageDocs"
+        android:protectionLevel="signature|system" />
+
     <!-- ================================== -->
     <!-- Permissions for screenlock         -->
     <!-- ================================== -->
@@ -1177,6 +1283,13 @@
         android:label="@string/permlab_removeTasks"
         android:description="@string/permdesc_removeTasks" />
 
+    <!-- @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"
+        android:label="@string/permlab_manageActivityStacks"
+        android:description="@string/permdesc_manageActivityStacks" />
+
     <!-- Allows an application to start any activity, regardless of permission
          protection or exported state. @hide -->
     <permission android:name="android.permission.START_ANY_ACTIVITY"
@@ -1297,6 +1410,27 @@
         android:label="@string/permlab_expandStatusBar"
         android:description="@string/permdesc_expandStatusBar" />
 
+    <!-- ============================================================== -->
+    <!-- Permissions related to adding/removing shortcuts from Launcher -->
+    <!-- ============================================================== -->
+    <eat-comment />
+
+    <!-- Allows an application to install a shortcut in Launcher -->
+    <permission
+        android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_install_shortcut"
+        android:description="@string/permdesc_install_shortcut" />
+
+        <!-- Allows an application to uninstall a shortcut in Launcher -->
+    <permission
+        android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_uninstall_shortcut"
+        android:description="@string/permdesc_uninstall_shortcut"/>
+
     <!-- ==================================================== -->
     <!-- Permissions related to accessing sync settings   -->
     <!-- ==================================================== -->
@@ -1560,6 +1694,14 @@
         android:label="@string/permlab_anyCodecForPlayback"
         android:description="@string/permdesc_anyCodecForPlayback" />
 
+    <!-- Allows an application to install and/or uninstall CA certificates on
+         behalf of the user.
+         @hide -->
+    <permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
+        android:protectionLevel="signature|system"
+        android:label="@string/permlab_manageCaCertificates"
+        android:description="@string/permdesc_manageCaCertificates" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
@@ -1805,6 +1947,27 @@
         android:description="@string/permdesc_bindAccessibilityService"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.printservice.PrintService},
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_PRINT_SERVICE"
+        android:label="@string/permlab_bindPrintService"
+        android:description="@string/permdesc_bindPrintService"
+        android:protectionLevel="signature" />
+
+    <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
+         or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
+         the system can bind to it. -->
+    <permission android:name="android.permission.BIND_NFC_SERVICE"
+        android:label="@string/permlab_bindNfcService"
+        android:description="@string/permdesc_bindNfcService"
+        android:protectionLevel="signature" />
+
+    <!-- Must be required by the PrintSpooler to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
+        android:label="@string/permlab_bindPrintSpoolerService"
+        android:description="@string/permdesc_bindPrintSpoolerService"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a TextService (e.g. SpellCheckerService)
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_TEXT_SERVICE"
@@ -1812,7 +1975,7 @@
         android:description="@string/permdesc_bindTextService"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by an {@link android.net.VpnService},
+    <!-- Must be required by a {@link android.net.VpnService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_VPN_SERVICE"
         android:label="@string/permlab_bindVpnService"
@@ -1833,6 +1996,13 @@
         android:description="@string/permdesc_bindDeviceAdmin"
         android:protectionLevel="signature" />
 
+    <!-- Required to add or remove another application as a device admin.
+         <p/>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
+        android:label="@string/permlab_manageDeviceAdmins"
+        android:description="@string/permdesc_manageDeviceAdmins"
+        android:protectionLevel="signature|system" />
+
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.
          <p>Not for use by third-party applications. -->
@@ -1936,6 +2106,42 @@
         android:description="@string/permdesc_controlWifiDisplay"
         android:protectionLevel="signature" />
 
+    <!-- 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.
+         <p>Not for use by third-party applications.</p>
+         @hide -->
+    <permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
+        android:label="@string/permlab_captureAudioHotword"
+        android:description="@string/permdesc_captureAudioHotword"
+        android:protectionLevel="signature|system" />
+
+    <!-- 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.
+         <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.
+         <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"
+        android:description="@string/permdesc_mediaContentControl"
+        android:protectionLevel="signature|system" />
+
     <!-- Required to be able to disable the device (very dangerous!).
     <p>Not for use by third-party applications.. -->
     <permission android:name="android.permission.BRICK"
@@ -2044,7 +2250,7 @@
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:label="@string/permlab_batteryStats"
         android:description="@string/permdesc_batteryStats"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to control the backup and restore process.
     <p>Not for use by third-party applications.
@@ -2191,6 +2397,16 @@
         android:description="@string/permdesc_modifyNetworkAccounting"
         android:protectionLevel="signature|system" />
 
+    <!-- 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
+    -->
+    <permission android:name="android.permission.MARK_NETWORK_SOCKET"
+        android:label="@string/permlab_markNetworkSocket"
+        android:description="@string/permdesc_markNetworkSocket"
+        android:protectionLevel="signature|system" />
+
     <!-- C2DM permission.
          @hide Used internally.
      -->
@@ -2248,6 +2464,20 @@
         android:description="@string/permdesc_accessNotifications"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
+        @hide -->
+    <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_access_keyguard_secure_storage"
+        android:description="@string/permdesc_access_keyguard_secure_storage" />
+
+    <!-- Allows an application to control keyguard.  Only allowed for system processes.
+        @hide -->
+    <permission android:name="android.permission.CONTROL_KEYGUARD"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_control_keyguard"
+        android:description="@string/permdesc_control_keyguard" />
+
     <!-- Must be required by an {@link
          android.service.notification.NotificationListenerService},
          to ensure that only the system can bind to it. -->
@@ -2256,6 +2486,21 @@
         android:description="@string/permdesc_bindNotificationListenerService"
         android:protectionLevel="signature" />
 
+    <!-- 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"
+        android:label="@string/permlab_invokeCarrierSetup"
+        android:description="@string/permdesc_invokeCarrierSetup"
+        android:protectionLevel="signature|system" />
+
+    <!-- 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" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
@@ -2322,8 +2567,7 @@
         <activity android:name="android.accounts.CantAddAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@android:style/Theme.Holo.Dialog"
-                android:label="@string/error_message_title"
+                android:theme="@android:style/Theme.Holo.Dialog.NoActionBar"
                 android:process=":ui">
         </activity>
 
@@ -2359,6 +2603,17 @@
                 android:process=":ui">
         </activity>
 
+        <activity android:name="com.android.internal.app.RestrictionsPinActivity"
+                android:theme="@style/Theme.Holo.Dialog.Alert"
+                android:excludeFromRecents="true"
+                android:windowSoftInputMode="adjustPan"
+                android:process=":ui">
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.RESTRICTIONS_CHALLENGE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <receiver android:name="com.android.server.BootReceiver"
                 android:primaryUserOnly="true">
             <intent-filter>
@@ -2403,9 +2658,9 @@
         </receiver>
 
         <receiver android:name="com.android.server.MasterClearReceiver"
-            android:permission="android.permission.MASTER_CLEAR"
-            android:priority="100" >
-            <intent-filter>
+            android:permission="android.permission.MASTER_CLEAR">
+            <intent-filter
+                    android:priority="100" >
                 <!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
                 <action android:name="android.intent.action.MASTER_CLEAR" />
 
diff --git a/core/res/res/anim/keyguard_security_animate_in.xml b/core/res/res/anim/keyguard_security_animate_in.xml
deleted file mode 100644
index 4ee30c3..0000000
--- a/core/res/res/anim/keyguard_security_animate_in.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false">
-
-    <scale
-        android:interpolator="@android:anim/decelerate_interpolator"
-        android:fromXScale="0.0"
-        android:toXScale="1.0"
-        android:fromYScale="1.0"
-        android:toYScale="1.0"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillAfter="true"
-        android:duration="@integer/kg_security_flip_duration"
-        android:startOffset="@integer/kg_security_flip_duration" />
-
-</set>
-
diff --git a/core/res/res/anim/keyguard_security_animate_out.xml b/core/res/res/anim/keyguard_security_animate_out.xml
deleted file mode 100644
index 76d065c..0000000
--- a/core/res/res/anim/keyguard_security_animate_out.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false">
-
-    <scale
-        android:interpolator="@android:anim/accelerate_interpolator"
-        android:fromXScale="1.0"
-        android:toXScale="0.0"
-        android:fromYScale="1.0"
-        android:toYScale="1.0"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillAfter="true"
-        android:duration="@integer/kg_security_flip_duration" />
-
-</set>
-
diff --git a/core/res/res/anim/keyguard_security_fade_in.xml b/core/res/res/anim/keyguard_security_fade_in.xml
deleted file mode 100644
index 6293432..0000000
--- a/core/res/res/anim/keyguard_security_fade_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:interpolator/decelerate_quad"
-    android:fromAlpha="0.0" android:toAlpha="1.0"
-    android:duration="@*android:integer/kg_security_fade_duration" />
-
-
diff --git a/core/res/res/anim/keyguard_security_fade_out.xml b/core/res/res/anim/keyguard_security_fade_out.xml
deleted file mode 100644
index 4ab0229..0000000
--- a/core/res/res/anim/keyguard_security_fade_out.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:interpolator/accelerate_quad"
-    android:fromAlpha="1.0"
-    android:toAlpha="0.0"
-    android:duration="@*android:integer/kg_security_fade_duration"
-/>
diff --git a/core/res/res/anim/toast_bar_enter.xml b/core/res/res/anim/toast_bar_enter.xml
new file mode 100644
index 0000000..5c0dfcf
--- /dev/null
+++ b/core/res/res/anim/toast_bar_enter.xml
@@ -0,0 +1,27 @@
+<?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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <translate android:fromYDelta="10%" android:toYDelta="0"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <alpha android:fromAlpha="0.5" android:toAlpha="1.0"
+            android:interpolator="@interpolator/decelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/toast_bar_exit.xml b/core/res/res/anim/toast_bar_exit.xml
new file mode 100644
index 0000000..4e3b7da
--- /dev/null
+++ b/core/res/res/anim/toast_bar_exit.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+    <translate android:fromYDelta="0" android:toYDelta="10%"
+            android:interpolator="@interpolator/accelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index e591a7b..0000000
--- a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index ea27290d..0000000
--- a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
index 66adffe..99d60e3 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
index caeff9c..45a0cf0 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
index 584ce05..86b43c1 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
index ed317f7..cdf0078 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
index 40bd746..7de0448 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
index c49bc84..5b916c9 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
index 958d023..fd2b63a 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
index 3464f3d..b7c125b 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
index 3464f3d..bf09b6f 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
index 5dc3673..9fd5b764 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
index c0d8a3d..caff83d 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
index a920132..4cddfda 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
index f6a8b45..e94aabe 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_dark.png
index 17a1051..961b0f7 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_light.png
index ef8320c..503de5c 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_dark.png
index 74e5235..a756e30 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_light.png
index 8c74e06..0d5bbe8 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_dark.png
index 5b3ca5d..c58a841 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_light.png
index 469e9f6..9e018ef 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_dark.png
index d0a5ca5..afaf691 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_light.png
index 08e7553..26adc72 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
index 18c527d..e0cc6c5 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
index 478f2e7..607d1cf 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_dark.png
index 5829969..4791366 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_light.png
index 5efe111..8680012 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_dark.png
index a967836..7dc2567 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_light.png
index 4f10c79..de02ace 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_dark.png
index eb0ef89..9b34307 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_light.png
index d8652d5..fc9af78 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_dark.png
index 2b0e235..c22ac4c 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_light.png
index 06dfad2..b2b0e29 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
index b0be28d..f45882c 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
index ec3c748..d06fbeb 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_dark.png
index 61f9e6b..ce3954f 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_light.png
index 62ac7f9..2e7346a 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_dark.png
index e10d5d1..1a642f7 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_light.png
index 685f8b5..cee608b 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png
index d7ef1a6..0eb9e38 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png
index fcf4623..f396c47 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png
index 9a6fc4d..cbbbfb3 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png
index 3875ac3..c4e1d81 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
index a929e09..97730d1 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
index 013ca85..4350f16 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_dark.png
index 57cfa4d..b7035fd 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_light.png
index 1a37993..852ad55 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_dark.png
index 5694cf7..3d40107 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_light.png
index 6406c06..ee79ed6 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png
index c50efaf..6cad71e 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png
index 1a899c9e..edcb86d 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png
index fecb1af..02013fa 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png
index 37547d2..6689a89 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
index 7b0e089..36f9ad1 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
index 692d705..10d74ce 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
index 677069a..94c0ee7 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
index 677069a..9bef909 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6b5fa5a..469ba9b 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
index 6b5fa5a..40a61ca 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
rename to core/res/res/drawable-hdpi/ic_ab_back_holo_dark_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_light_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
rename to core/res/res/drawable-hdpi/ic_ab_back_holo_light_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_notification.png b/core/res/res/drawable-hdpi/ic_audio_notification_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_notification.png
rename to core/res/res/drawable-hdpi/ic_audio_notification_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_notification_mute.png b/core/res/res/drawable-hdpi/ic_audio_notification_mute_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_notification_mute.png
rename to core/res/res/drawable-hdpi/ic_audio_notification_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_phone.png b/core/res/res/drawable-hdpi/ic_audio_phone_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_phone.png
rename to core/res/res/drawable-hdpi/ic_audio_phone_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_ring_notif.png b/core/res/res/drawable-hdpi/ic_audio_ring_notif_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_ring_notif.png
rename to core/res/res/drawable-hdpi/ic_audio_ring_notif_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-hdpi/ic_audio_ring_notif_mute_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_ring_notif_mute.png
rename to core/res/res/drawable-hdpi/ic_audio_ring_notif_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate.png
rename to core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_vol.png b/core/res/res/drawable-hdpi/ic_audio_vol_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_vol.png
rename to core/res/res/drawable-hdpi/ic_audio_vol_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_vol_mute.png b/core/res/res/drawable-hdpi/ic_audio_vol_mute_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_audio_vol_mute.png
rename to core/res/res/drawable-hdpi/ic_audio_vol_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_contact_picture.png b/core/res/res/drawable-hdpi/ic_contact_picture.png
index 2eef7b5..00d0ec4 100644
--- a/core/res/res/drawable-hdpi/ic_contact_picture.png
+++ b/core/res/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_grayedout_printer.png b/core/res/res/drawable-hdpi/ic_grayedout_printer.png
new file mode 100644
index 0000000..5e54970
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_grayedout_printer.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-hdpi/ic_lock_airplane_mode_off_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lock_airplane_mode_off.png
rename to core/res/res/drawable-hdpi/ic_lock_airplane_mode_off_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cc.png b/core/res/res/drawable-hdpi/ic_menu_cc_am.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_cc.png
rename to core/res/res/drawable-hdpi/ic_menu_cc_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_print.png b/core/res/res/drawable-hdpi/ic_print.png
new file mode 100644
index 0000000..aaff3dd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_print.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_print_error.png b/core/res/res/drawable-hdpi/ic_print_error.png
new file mode 100644
index 0000000..7846a78
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_print_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png
index 449d427..7fe402a 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png
index 14f4ff8..4052eed 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png
index 5cf9086..738d0fe 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_add_widget.png b/core/res/res/drawable-hdpi/kg_add_widget.png
deleted file mode 100644
index 68971a5..0000000
--- a/core/res/res/drawable-hdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_add_widget_pressed.png b/core/res/res/drawable-hdpi/kg_add_widget_pressed.png
deleted file mode 100644
index 55112ca..0000000
--- a/core/res/res/drawable-hdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_security_lock_focused.png b/core/res/res/drawable-hdpi/kg_security_lock_focused.png
deleted file mode 100644
index abcf683..0000000
--- a/core/res/res/drawable-hdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_security_lock_normal.png b/core/res/res/drawable-hdpi/kg_security_lock_normal.png
deleted file mode 100644
index e8cff24..0000000
--- a/core/res/res/drawable-hdpi/kg_security_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_security_lock_pressed.png b/core/res/res/drawable-hdpi/kg_security_lock_pressed.png
deleted file mode 100644
index 3214dcb..0000000
--- a/core/res/res/drawable-hdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_widget_bg_padded.9.png b/core/res/res/drawable-hdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index dff1dfa..0000000
--- a/core/res/res/drawable-hdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..f5cc0ed
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..e9afcc9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
index 5654cd6..596accb 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
index 5654cd6..2054530 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
index e20b02d..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
index e20b02d..c9e662d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/notification_bg_low_pressed.9.png b/core/res/res/drawable-hdpi/notification_bg_low_pressed.9.png
index 1602ab8..9832ace 100644
--- a/core/res/res/drawable-hdpi/notification_bg_low_pressed.9.png
+++ b/core/res/res/drawable-hdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/notification_bg_normal_pressed.9.png b/core/res/res/drawable-hdpi/notification_bg_normal_pressed.9.png
index 6193822..c271b11 100644
--- a/core/res/res/drawable-hdpi/notification_bg_normal_pressed.9.png
+++ b/core/res/res/drawable-hdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/overscroll_edge.png b/core/res/res/drawable-hdpi/overscroll_edge.png
index 08fc022..1952e0e 100644
--- a/core/res/res/drawable-hdpi/overscroll_edge.png
+++ b/core/res/res/drawable-hdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/overscroll_glow.png b/core/res/res/drawable-hdpi/overscroll_glow.png
index 8f0c2cb..45c0135 100644
--- a/core/res/res/drawable-hdpi/overscroll_glow.png
+++ b/core/res/res/drawable-hdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_above.9.png b/core/res/res/drawable-hdpi/popup_inline_error_above_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_inline_error_above.9.png
rename to core/res/res/drawable-hdpi/popup_inline_error_above_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark.9.png
rename to core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-hdpi/popup_inline_error_above_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_inline_error_above_holo_light.9.png
rename to core/res/res/drawable-hdpi/popup_inline_error_above_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error.9.png b/core/res/res/drawable-hdpi/popup_inline_error_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_inline_error.9.png
rename to core/res/res/drawable-hdpi/popup_inline_error_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-hdpi/popup_inline_error_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_inline_error_holo_dark.9.png
rename to core/res/res/drawable-hdpi/popup_inline_error_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-hdpi/popup_inline_error_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_inline_error_holo_light.9.png
rename to core/res/res/drawable-hdpi/popup_inline_error_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_dark.9.png
rename to core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_light.9.png
rename to core/res/res/drawable-hdpi/quickcontact_badge_overlay_focused_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_dark.9.png
rename to core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_light.9.png
rename to core/res/res/drawable-hdpi/quickcontact_badge_overlay_normal_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark.9.png
deleted file mode 100644
index 0c689ff..0000000
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
new file mode 100644
index 0000000..4e40eda
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light.9.png
deleted file mode 100644
index f3999204..0000000
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
new file mode 100644
index 0000000..f1b7036
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_default_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_ab_default_holo_dark.9.png
rename to core/res/res/drawable-hdpi/spinner_ab_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_default_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_ab_default_holo_light.9.png
rename to core/res/res/drawable-hdpi/spinner_ab_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark.9.png
rename to core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light.9.png
rename to core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark.9.png
rename to core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_focused_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_ab_focused_holo_light.9.png
rename to core/res/res/drawable-hdpi/spinner_ab_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark.9.png
deleted file mode 100644
index dc20a8d..0000000
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..66f0d88
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light.9.png
deleted file mode 100644
index 272a2a1..0000000
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..10af163
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_default_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_default_holo_dark.9.png
rename to core/res/res/drawable-hdpi/spinner_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_default_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_default_holo_light.9.png
rename to core/res/res/drawable-hdpi/spinner_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_disabled_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_disabled_holo_dark.9.png
rename to core/res/res/drawable-hdpi/spinner_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_disabled_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_disabled_holo_light.9.png
rename to core/res/res/drawable-hdpi/spinner_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_focused_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_focused_holo_dark.9.png
rename to core/res/res/drawable-hdpi/spinner_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_focused_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_focused_holo_light.9.png
rename to core/res/res/drawable-hdpi/spinner_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark.9.png
deleted file mode 100644
index 84560c5..0000000
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..aca9435
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_light.9.png
deleted file mode 100644
index e101d50..0000000
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..eafd44a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
index 7f87ee7..f8f9503 100644
--- a/core/res/res/drawable-hdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
deleted file mode 100644
index cfbbd8d..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
new file mode 100644
index 0000000..382557e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_certificate_info.png b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3be426c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_secure.png b/core/res/res/drawable-hdpi/stat_sys_secure.png
deleted file mode 100644
index 5e979db..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_secure.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
index 765be61..d5bb37f 100644
--- a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
index ea54380..b6009e6 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
index ea54380..54d813c 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
index 6278eef..956d3c4 100644
--- a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
index aadc6f8..57e57e1 100644
--- a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_bar_bg.9.png b/core/res/res/drawable-hdpi/toast_bar_bg.9.png
new file mode 100644
index 0000000..2396b26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/toast_bar_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index ad2cb5a..ca65994 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
index f8f75db..a804a8a 100644
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldpi/ic_lock_airplane_mode_off_am.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_lock_airplane_mode_off.png
rename to core/res/res/drawable-ldpi/ic_lock_airplane_mode_off_am.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_cc.png b/core/res/res/drawable-ldpi/ic_menu_cc_am.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_cc.png
rename to core/res/res/drawable-ldpi/ic_menu_cc_am.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldpi/popup_inline_error_above_am.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/popup_inline_error_above.9.png
rename to core/res/res/drawable-ldpi/popup_inline_error_above_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/popup_inline_error.9.png b/core/res/res/drawable-ldpi/popup_inline_error_am.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/popup_inline_error.9.png
rename to core/res/res/drawable-ldpi/popup_inline_error_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_notify_call_mute.png b/core/res/res/drawable-ldpi/stat_notify_call_mute.png
index d160009..353ecf2 100644
--- a/core/res/res/drawable-ldpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-ldpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_adb.png b/core/res/res/drawable-ldpi/stat_sys_adb_am.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_adb.png
rename to core/res/res/drawable-ldpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_secure.png b/core/res/res/drawable-ldpi/stat_sys_secure.png
deleted file mode 100644
index 096aa95..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_secure.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_speakerphone.png b/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
index 7fc67a0..22ecd30 100644
--- a/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_dark.9.png
deleted file mode 100644
index 45450e4..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_light.9.png
deleted file mode 100644
index b568989..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_dark.9.png
deleted file mode 100644
index e0434584..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_light.9.png
deleted file mode 100644
index f208c99..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_dark.9.png
deleted file mode 100644
index 94eb994..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_light.9.png
deleted file mode 100644
index 1fee149..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-ldrtl-hdpi/ic_ab_back_holo_dark.png
deleted file mode 100644
index 9beeb0f..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_ab_back_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-ldrtl-hdpi/ic_ab_back_holo_light.png
deleted file mode 100644
index 844e38b..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_ab_back_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification.png
deleted file mode 100644
index 62ef692..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification_mute.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification_mute.png
deleted file mode 100644
index 40123e3..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_phone.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_phone.png
deleted file mode 100644
index 968f5ee..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_phone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif.png
deleted file mode 100644
index e5f0dcf..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_mute.png
deleted file mode 100644
index 371e32f..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_vibrate.png
deleted file mode 100644
index e05e8f5..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol.png
deleted file mode 100644
index 81a8422..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol_mute.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol_mute.png
deleted file mode 100644
index 371e32f..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-hdpi/ic_lock_airplane_mode_off.png
deleted file mode 100644
index 7b1eee6..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_lock_airplane_mode_off.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-hdpi/ic_menu_cc.png
deleted file mode 100644
index aedf9b1..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/ic_menu_cc.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png
deleted file mode 100644
index 8b43f4e..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png
deleted file mode 100644
index 20e9002..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png
deleted file mode 100644
index b5f397c..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png
deleted file mode 100644
index a04d695..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png
deleted file mode 100644
index 8567b1f..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png
deleted file mode 100644
index 7d1754c..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_dark.9.png
deleted file mode 100644
index 7c5826f..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_light.9.png
deleted file mode 100644
index 974a292..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_dark.9.png
deleted file mode 100644
index b3196c9..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_light.9.png
deleted file mode 100644
index 1f833d3..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_dark.9.png
deleted file mode 100644
index e969abc..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_light.9.png
deleted file mode 100644
index 3adbc84..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_dark.9.png
deleted file mode 100644
index 57141d5..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_light.9.png
deleted file mode 100644
index 8e28906..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_dark.9.png
deleted file mode 100644
index efdab73..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_light.9.png
deleted file mode 100644
index 307b86d..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_dark.9.png
deleted file mode 100644
index 2e28431..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_light.9.png
deleted file mode 100644
index 7a83451..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_dark.9.png
deleted file mode 100644
index 9afc912..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_light.9.png
deleted file mode 100644
index 7d03855..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_dark.9.png
deleted file mode 100644
index 21f1e2c..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_light.9.png
deleted file mode 100644
index 600b861..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_dark.9.png
deleted file mode 100644
index c11619c..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_light.9.png
deleted file mode 100644
index 91be10f..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_dark.9.png
deleted file mode 100644
index c921487..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_light.9.png
deleted file mode 100644
index 4da6c6e..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_dark.9.png
deleted file mode 100644
index 9c7d294..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_light.9.png
deleted file mode 100644
index c9f493a..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-hdpi/stat_sys_adb.png
deleted file mode 100644
index a7dc29d..0000000
--- a/core/res/res/drawable-ldrtl-hdpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-ldpi/ic_lock_airplane_mode_off.png
deleted file mode 100644
index c093420..0000000
--- a/core/res/res/drawable-ldrtl-ldpi/ic_lock_airplane_mode_off.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-ldpi/ic_menu_cc.png
deleted file mode 100644
index 1f21884..0000000
--- a/core/res/res/drawable-ldrtl-ldpi/ic_menu_cc.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png
deleted file mode 100644
index d2efb62..0000000
--- a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png
deleted file mode 100644
index 04d200d..0000000
--- a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-ldpi/stat_sys_adb.png
deleted file mode 100644
index d726b7a..0000000
--- a/core/res/res/drawable-ldrtl-ldpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_dark.9.png
deleted file mode 100644
index abffc49..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_light.9.png
deleted file mode 100644
index a369081..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_dark.9.png
deleted file mode 100644
index e33e964..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_light.9.png
deleted file mode 100644
index 0a845dd..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_dark.9.png
deleted file mode 100644
index 74b0352..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_light.9.png
deleted file mode 100644
index bfb4972..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-ldrtl-mdpi/ic_ab_back_holo_dark.png
deleted file mode 100644
index c22dc90..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_ab_back_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-ldrtl-mdpi/ic_ab_back_holo_light.png
deleted file mode 100644
index f49b715..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_ab_back_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification.png
deleted file mode 100644
index d9843e0..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification_mute.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification_mute.png
deleted file mode 100644
index 2159cab..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_phone.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_phone.png
deleted file mode 100644
index b5af351..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_phone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif.png
deleted file mode 100644
index 6341be6..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_mute.png
deleted file mode 100644
index b4c3a54..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_vibrate.png
deleted file mode 100644
index 835773e..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol.png
deleted file mode 100644
index 947d1f9..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol_mute.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol_mute.png
deleted file mode 100644
index b4c3a54..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-mdpi/ic_lock_airplane_mode_off.png
deleted file mode 100644
index cba5500..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_lock_airplane_mode_off.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-mdpi/ic_menu_cc.png
deleted file mode 100644
index 0335dec..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/ic_menu_cc.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png
deleted file mode 100644
index 27e8d4f..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png
deleted file mode 100644
index 4ae2b91..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png
deleted file mode 100644
index 8cc3b69..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png
deleted file mode 100644
index 7a84200..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png
deleted file mode 100644
index 8fc2e2e..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png
deleted file mode 100644
index 687a691..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_dark.9.png
deleted file mode 100644
index a321836..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_light.9.png
deleted file mode 100644
index 4c5d692..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_dark.9.png
deleted file mode 100644
index 6199dc5..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_light.9.png
deleted file mode 100644
index 1b0905a..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_dark.9.png
deleted file mode 100644
index c6d7868..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_light.9.png
deleted file mode 100644
index 179644c..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_dark.9.png
deleted file mode 100644
index 02c799e..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_light.9.png
deleted file mode 100644
index 286157c..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_dark.9.png
deleted file mode 100644
index 030f723..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_light.9.png
deleted file mode 100644
index a5b10d2..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_dark.9.png
deleted file mode 100644
index 10faec10..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_light.9.png
deleted file mode 100644
index 62a70ed..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_dark.9.png
deleted file mode 100644
index 633b8d2..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_light.9.png
deleted file mode 100644
index 59ff556..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_dark.9.png
deleted file mode 100644
index 09d5aa4..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_light.9.png
deleted file mode 100644
index c320ea0..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_dark.9.png
deleted file mode 100644
index a5f28fd..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_light.9.png
deleted file mode 100644
index 9e0d39c..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_dark.9.png
deleted file mode 100644
index 24d928f..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_light.9.png
deleted file mode 100644
index 596ba2d..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_dark.9.png
deleted file mode 100644
index 55b1af7..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_light.9.png
deleted file mode 100644
index bb0486a..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-mdpi/stat_sys_adb.png
deleted file mode 100644
index 265c421..0000000
--- a/core/res/res/drawable-ldrtl-mdpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_dark.9.png
deleted file mode 100644
index d253dd4..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_light.9.png
deleted file mode 100644
index 65f9ec1..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_dark.9.png
deleted file mode 100644
index 105da60..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_light.9.png
deleted file mode 100644
index de53be7..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_dark.9.png
deleted file mode 100644
index 3be0b0c..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_light.9.png
deleted file mode 100644
index 878c702..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-ldrtl-xhdpi/ic_ab_back_holo_dark.png
deleted file mode 100644
index 8dfb7d8..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_ab_back_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-ldrtl-xhdpi/ic_ab_back_holo_light.png
deleted file mode 100644
index 29852ad..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_ab_back_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification.png
deleted file mode 100644
index 43aedea..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification_mute.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification_mute.png
deleted file mode 100644
index 4e87f77..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_phone.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_phone.png
deleted file mode 100644
index 1066d03..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_phone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif.png
deleted file mode 100644
index daf9213..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_mute.png
deleted file mode 100644
index 83d3bdd..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_vibrate.png
deleted file mode 100644
index 4de95aa..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol.png
deleted file mode 100644
index 8132926..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol_mute.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol_mute.png
deleted file mode 100644
index 83d3bdd..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-xhdpi/ic_lock_airplane_mode_off.png
deleted file mode 100644
index 6820a23..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_lock_airplane_mode_off.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-xhdpi/ic_menu_cc.png
deleted file mode 100644
index c8690bd..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/ic_menu_cc.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png
deleted file mode 100644
index db91a56..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png
deleted file mode 100644
index 90820b5..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png
deleted file mode 100644
index 5989975..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png
deleted file mode 100644
index 3b3f87d3..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png
deleted file mode 100644
index 75baba2..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png
deleted file mode 100644
index 6c0203d..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_dark.9.png
deleted file mode 100644
index 039a056..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_light.9.png
deleted file mode 100644
index c8d68c5..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_dark.9.png
deleted file mode 100644
index 1fef1ad..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_light.9.png
deleted file mode 100644
index 6b22d44..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png
deleted file mode 100644
index c219527..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_light.9.png
deleted file mode 100644
index 2a1d508..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_dark.9.png
deleted file mode 100644
index 6f41b24..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_light.9.png
deleted file mode 100644
index 5a96fc1..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_dark.9.png
deleted file mode 100644
index 96a6da5..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_light.9.png
deleted file mode 100644
index 849d795..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_dark.9.png
deleted file mode 100644
index 3d6d0f9..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_light.9.png
deleted file mode 100644
index 1cbaf6c..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_dark.9.png
deleted file mode 100644
index 878e90d..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_light.9.png
deleted file mode 100644
index f25acc2..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_dark.9.png
deleted file mode 100644
index 8d89c86..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_light.9.png
deleted file mode 100644
index 6e3ca08..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_dark.9.png
deleted file mode 100644
index 2204091..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_light.9.png
deleted file mode 100644
index 3e6684e..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_dark.9.png
deleted file mode 100644
index 5129dee..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_light.9.png
deleted file mode 100644
index 0f0289b..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_dark.9.png
deleted file mode 100644
index 795820b..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_light.9.png
deleted file mode 100644
index 830edfd..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-xhdpi/stat_sys_adb.png
deleted file mode 100644
index e342556..0000000
--- a/core/res/res/drawable-ldrtl-xhdpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index 7dfea4c..0000000
--- a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 99b0279..0000000
--- a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
index 85d7aad..f4185d1 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
index f7b01e0..d59219b 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
index 9389a08..47e8b5b 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
index 1109c20..1dc83fa 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
index 3a8cebc..eafc553 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
index e9f5f06..6583e99 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
index eb7a1fd..1940216 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
index 7e4eb5e..ebdc717 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
index 7e4eb5e..c73984e 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
index 194f58e..cebaf6d 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
index 2a7d0d5..7b12bea 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
index dff7c00..eabb9d2 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
index 70c705f..09592355 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_dark.png
index 217aa83..563f609 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_light.png
index 6853157..60e4717 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_dark.png
index 8b6bd93..fa4db4f 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_light.png
index 7992806..73a9d9e 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_dark.png
index fc74193..790251f 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_light.png
index 0b1e231..aa4690f 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_dark.png
index 1360dd0..c08b5c2 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_light.png
index 7e82935..5f0a748 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
index 5985e3c..ba916c1 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
index 2085290..8d0638d 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_dark.png
index 3db345a..9b04c59 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_light.png
index 632f822..291fdb3 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_dark.png
index efd016c..5cc6600 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_light.png
index 484f115..f17edca 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_dark.png
index a314bef..26f5f11 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_light.png
index 4b4a1b9..6346fff 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_dark.png
index d6660cf..14bfde7 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_light.png
index 060bb5b..c5005f1 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
index 4b62750..886d86a 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
index 000a9c4..9f9eb1d 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_dark.png
index f4a1cbc3..690371d 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_light.png
index 79ca527..6d026dc 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_dark.png
index 33d1308..6e368d6 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_light.png
index 9672415..71cb582 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png
index 94d3784..ebc9914 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png
index 9f3ce4e..edc3399 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png
index 05563bff..7dc8089 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png
index ee166bc..a9abdc0 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
index 4bc4a30..360ce61 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
index dd14aec..4884309 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_dark.png
index becc091..3b5901f 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_light.png
index e49dbab4..d61bf39 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_dark.png
index 61837f84..ff9f8881 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_light.png
index 19f139f..0aa36fe 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png
index 9fed6b5..fdd1e95 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png
index d52dbb7..15c9334 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png
index c0c6b49..14183171 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png
index 237f7e7..2e81887 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
index 2f1f004..9083aec 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
index 4bea36b..b5f0542 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
index 045dc9a..626a605 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
index 045dc9a..196c650 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6c4aa16..0536053 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
index 6c4aa16..9fc345b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
rename to core/res/res/drawable-mdpi/ic_ab_back_holo_dark_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_light_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
rename to core/res/res/drawable-mdpi/ic_ab_back_holo_light_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_notification.png b/core/res/res/drawable-mdpi/ic_audio_notification_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_notification.png
rename to core/res/res/drawable-mdpi/ic_audio_notification_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_notification_mute.png b/core/res/res/drawable-mdpi/ic_audio_notification_mute_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_notification_mute.png
rename to core/res/res/drawable-mdpi/ic_audio_notification_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_phone.png b/core/res/res/drawable-mdpi/ic_audio_phone_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_phone.png
rename to core/res/res/drawable-mdpi/ic_audio_phone_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_ring_notif.png b/core/res/res/drawable-mdpi/ic_audio_ring_notif_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_ring_notif.png
rename to core/res/res/drawable-mdpi/ic_audio_ring_notif_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-mdpi/ic_audio_ring_notif_mute_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_ring_notif_mute.png
rename to core/res/res/drawable-mdpi/ic_audio_ring_notif_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate.png
rename to core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_vol.png b/core/res/res/drawable-mdpi/ic_audio_vol_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_vol.png
rename to core/res/res/drawable-mdpi/ic_audio_vol_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_vol_mute.png b/core/res/res/drawable-mdpi/ic_audio_vol_mute_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_audio_vol_mute.png
rename to core/res/res/drawable-mdpi/ic_audio_vol_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_contact_picture.png b/core/res/res/drawable-mdpi/ic_contact_picture.png
index 6c7cb61..771cb6b 100644
--- a/core/res/res/drawable-mdpi/ic_contact_picture.png
+++ b/core/res/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_grayedout_printer.png b/core/res/res/drawable-mdpi/ic_grayedout_printer.png
new file mode 100644
index 0000000..5e54970
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_grayedout_printer.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-mdpi/ic_lock_airplane_mode_off_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lock_airplane_mode_off.png
rename to core/res/res/drawable-mdpi/ic_lock_airplane_mode_off_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_cc.png b/core/res/res/drawable-mdpi/ic_menu_cc_am.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_cc.png
rename to core/res/res/drawable-mdpi/ic_menu_cc_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_print.png b/core/res/res/drawable-mdpi/ic_print.png
new file mode 100644
index 0000000..a3954b5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_print.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_print_error.png b/core/res/res/drawable-mdpi/ic_print_error.png
new file mode 100644
index 0000000..44109eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_print_error.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png
index 4c4adf2..5762e5f 100644
--- a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png
index cb5b31a..bfb0967 100644
--- a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png
index 52c9e3a..8c0386f 100644
--- a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_add_widget.png b/core/res/res/drawable-mdpi/kg_add_widget.png
deleted file mode 100644
index 136ae17..0000000
--- a/core/res/res/drawable-mdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_add_widget_pressed.png b/core/res/res/drawable-mdpi/kg_add_widget_pressed.png
deleted file mode 100644
index 34a7aaa..0000000
--- a/core/res/res/drawable-mdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_security_lock_focused.png b/core/res/res/drawable-mdpi/kg_security_lock_focused.png
deleted file mode 100644
index c567a82..0000000
--- a/core/res/res/drawable-mdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_security_lock_normal.png b/core/res/res/drawable-mdpi/kg_security_lock_normal.png
deleted file mode 100644
index 6fbecc1..0000000
--- a/core/res/res/drawable-mdpi/kg_security_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_security_lock_pressed.png b/core/res/res/drawable-mdpi/kg_security_lock_pressed.png
deleted file mode 100644
index a883258..0000000
--- a/core/res/res/drawable-mdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_widget_bg_padded.9.png b/core/res/res/drawable-mdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index c313df1..0000000
--- a/core/res/res/drawable-mdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..c6c1c02
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..3226ab7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
index 6e77525..fd0e8d7 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
index 6e77525..061904c 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
index 13cb131..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
index 13cb131..779d10e 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/notification_bg_low_pressed.9.png b/core/res/res/drawable-mdpi/notification_bg_low_pressed.9.png
index eaabd93..8a6011e 100644
--- a/core/res/res/drawable-mdpi/notification_bg_low_pressed.9.png
+++ b/core/res/res/drawable-mdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/notification_bg_normal_pressed.9.png b/core/res/res/drawable-mdpi/notification_bg_normal_pressed.9.png
index 62d8622..525120d 100644
--- a/core/res/res/drawable-mdpi/notification_bg_normal_pressed.9.png
+++ b/core/res/res/drawable-mdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/overscroll_edge.png b/core/res/res/drawable-mdpi/overscroll_edge.png
index 4c87a8b..baf2d0c 100644
--- a/core/res/res/drawable-mdpi/overscroll_edge.png
+++ b/core/res/res/drawable-mdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/overscroll_glow.png b/core/res/res/drawable-mdpi/overscroll_glow.png
index 8389ef4..c6cddd4 100644
--- a/core/res/res/drawable-mdpi/overscroll_glow.png
+++ b/core/res/res/drawable-mdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_above.9.png b/core/res/res/drawable-mdpi/popup_inline_error_above_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_inline_error_above.9.png
rename to core/res/res/drawable-mdpi/popup_inline_error_above_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark.9.png
rename to core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-mdpi/popup_inline_error_above_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_inline_error_above_holo_light.9.png
rename to core/res/res/drawable-mdpi/popup_inline_error_above_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error.9.png b/core/res/res/drawable-mdpi/popup_inline_error_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_inline_error.9.png
rename to core/res/res/drawable-mdpi/popup_inline_error_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-mdpi/popup_inline_error_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_inline_error_holo_dark.9.png
rename to core/res/res/drawable-mdpi/popup_inline_error_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-mdpi/popup_inline_error_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_inline_error_holo_light.9.png
rename to core/res/res/drawable-mdpi/popup_inline_error_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_dark.9.png
rename to core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_light.9.png
rename to core/res/res/drawable-mdpi/quickcontact_badge_overlay_focused_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_dark.9.png
rename to core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_light.9.png
rename to core/res/res/drawable-mdpi/quickcontact_badge_overlay_normal_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark.9.png
deleted file mode 100644
index eee058f..0000000
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
new file mode 100644
index 0000000..a70615a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light.9.png
deleted file mode 100644
index 1ac24be..0000000
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
new file mode 100644
index 0000000..e7dd785
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_default_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_ab_default_holo_dark.9.png
rename to core/res/res/drawable-mdpi/spinner_ab_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_default_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_ab_default_holo_light.9.png
rename to core/res/res/drawable-mdpi/spinner_ab_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark.9.png
rename to core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light.9.png
rename to core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark.9.png
rename to core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_focused_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_ab_focused_holo_light.9.png
rename to core/res/res/drawable-mdpi/spinner_ab_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark.9.png
deleted file mode 100644
index 2fa15e7..0000000
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..b21c73c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light.9.png
deleted file mode 100644
index a964b22..0000000
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..58904e8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_default_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_default_holo_dark.9.png
rename to core/res/res/drawable-mdpi/spinner_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_default_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_default_holo_light.9.png
rename to core/res/res/drawable-mdpi/spinner_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_disabled_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_disabled_holo_dark.9.png
rename to core/res/res/drawable-mdpi/spinner_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_disabled_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_disabled_holo_light.9.png
rename to core/res/res/drawable-mdpi/spinner_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_focused_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_focused_holo_dark.9.png
rename to core/res/res/drawable-mdpi/spinner_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_focused_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_focused_holo_light.9.png
rename to core/res/res/drawable-mdpi/spinner_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark.9.png
deleted file mode 100644
index b82d1ac..0000000
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..75fb81e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_light.9.png
deleted file mode 100644
index f9b5f64..0000000
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..fdd88b5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_call_mute.png b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
index 58e0cbc..79683c7 100644
--- a/core/res/res/drawable-mdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_more.png b/core/res/res/drawable-mdpi/stat_notify_more.png
index ca9e09e..52b40f8 100644
--- a/core/res/res/drawable-mdpi/stat_notify_more.png
+++ b/core/res/res/drawable-mdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
deleted file mode 100644
index 4862919..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
new file mode 100644
index 0000000..4380035
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_certificate_info.png b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..e15cf38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_secure.png b/core/res/res/drawable-mdpi/stat_sys_secure.png
deleted file mode 100644
index da3e318..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_secure.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_speakerphone.png b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
index d82704e..df0597f 100644
--- a/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
index 670dc2e..f9f2fc6 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
index 670dc2e..28a57a2 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
index 155c4fc..c98f046 100644
--- a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
index b1223fe..8753459 100644
--- a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_bar_bg.9.png b/core/res/res/drawable-mdpi/toast_bar_bg.9.png
new file mode 100644
index 0000000..291a936
--- /dev/null
+++ b/core/res/res/drawable-mdpi/toast_bar_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index b9105de..9e93fe7 100644
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
index da2d52d..778e4e6 100644
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 63b53b8..6351c2d 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo_alt.png b/core/res/res/drawable-nodpi/platlogo_alt.png
deleted file mode 100644
index f46c6c6..0000000
--- a/core/res/res/drawable-nodpi/platlogo_alt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/view_accessibility_focused.9.png b/core/res/res/drawable-nodpi/view_accessibility_focused.9.png
deleted file mode 100644
index f03f575..0000000
--- a/core/res/res/drawable-nodpi/view_accessibility_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
index b753764..996aadc 100644
--- a/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
index b47a9f6..e440805 100644
--- a/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
index 951197c..5ebf23a 100644
--- a/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
index 5893db9..0228134 100644
--- a/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
index 1d72243..142080a 100644
--- a/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
index 76dee9e..f9563b2 100644
--- a/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
new file mode 100644
index 0000000..dd1b5be
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
new file mode 100644
index 0000000..df9bff1
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index f01a79e..0000000
--- a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 7bea197..0000000
--- a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
index 131d103..d89d5c7 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
index 3e7dcdf..0146156 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
index c85f135..ffb13b1 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
index 50461d2..86eb889 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
index ce4b578..028eed6 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
index 8f03489..61efd3a 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
index a0d64a3..0544d32 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
index 930b5f2..37f30eb 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
index 930b5f2..a4ac0c7 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
index 60aede8..0f5f32f 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
index 614d27a..4097ef2 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
index f402bd1..a3795a0 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
index 041e5cc..f8e3bd4f8 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_dark.png
index 7cc4db2..94d6b6e 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_light.png
index e6d5630bf..68b8e53 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_dark.png
index 3556d13..0968ae1 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_light.png
index 42c6dfc..a444bf3 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_dark.png
index 0373da0..95eee6a 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_light.png
index 51b211c..4489c67 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_normal.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_normal.png
index d17506f..67cbc1a 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_normal.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_dark.png
index c70eeb5..0f46649 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_light.png
index fa1450e..e3c0761 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed.png
index 93a01a5..aaa1c5b 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
index 0804faf..dad564d 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
index c649599..c891ae3 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_selected.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_selected.png
index dea640a..7eed14c 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_selected.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_dark.png
index 3a264a4..a8a7bf8 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_light.png
index 33b0516..e898819 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_dark.png
index b349d10..f3a9d3d 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_light.png
index 47e56f1..92dfd1a 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_dark.png
index 4102fd5..0c9d726 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_light.png
index f60477b..3b2055c 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_normal.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_normal.png
index cf93bfb..1db48b3 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_normal.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_dark.png
index 5780bab..2b9b617 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_light.png
index 7483fbd..386b90a 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed.png
index 0696e04..a8e5d00 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
index 149f90d..530eed2 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
index 4145493..33ee629 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_selected.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_selected.png
index 5f3bec2..8ec2103 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_selected.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_off.png b/core/res/res/drawable-xhdpi/btn_star_big_off.png
index f60eb48..4b2abf1 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_off.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_off_disable.png b/core/res/res/drawable-xhdpi/btn_star_big_off_disable.png
index 8e0858d..c2f8598 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_off_disable.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_off_disable_focused.png b/core/res/res/drawable-xhdpi/btn_star_big_off_disable_focused.png
index f77e08c..1d1a1de 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_off_disable_focused.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_off_pressed.png b/core/res/res/drawable-xhdpi/btn_star_big_off_pressed.png
index 3f9695e..c6bb731 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_off_pressed.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_off_selected.png b/core/res/res/drawable-xhdpi/btn_star_big_off_selected.png
index b2e82da..c25f82e 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_off_selected.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_on.png b/core/res/res/drawable-xhdpi/btn_star_big_on.png
index 7cda089..93606c5 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_on.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_on_disable.png b/core/res/res/drawable-xhdpi/btn_star_big_on_disable.png
index da50266..c78e42c 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_on_disable.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_on_disable_focused.png b/core/res/res/drawable-xhdpi/btn_star_big_on_disable_focused.png
index df07003..6b2a537 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_on_disable_focused.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_on_pressed.png b/core/res/res/drawable-xhdpi/btn_star_big_on_pressed.png
index d56f46d..a25d0de 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_on_pressed.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_big_on_selected.png b/core/res/res/drawable-xhdpi/btn_star_big_on_selected.png
index 5a62f47..4d84628 100644
--- a/core/res/res/drawable-xhdpi/btn_star_big_on_selected.png
+++ b/core/res/res/drawable-xhdpi/btn_star_big_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_dark.png
index f31cf27..13a190d 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_light.png
index 9b28db8..e9953d9 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_dark.png
index bec293c..0f05262 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_light.png
index eec89df..90243a0 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_dark.png
index 757908e..ce667b6 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_light.png
index c58bd5c..fe9cdee 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_dark.png
index c591cae..392c1be 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_light.png
index b3e981a..28869df 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
index 85253f7..07c20fd 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
index efd26b0..aabcec2 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_dark.png
index 25fd6bb..5ffb71b 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_light.png
index fcd06af..22d0cfb 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_dark.png
index 641f79b..fdee7fa 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_light.png
index 9e47d8b..7b6534b 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_dark.png
index 8f14270..b4e438a 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_light.png
index 1d55670..8d19fc9 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_dark.png
index 032e89f..046df69 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_light.png
index ef59ce2..f17d60b 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
index e2305cb..474a25a 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
index 6643deb..f66c059 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 9d16f32..ce3d0d9 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
index 9d16f32..9d07941 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
index fde3ac3..ab794db 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
index fde3ac3..2ea1047 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/default_wallpaper.jpg b/core/res/res/drawable-xhdpi/default_wallpaper.jpg
deleted file mode 100644
index da9fa91..0000000
--- a/core/res/res/drawable-xhdpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-xhdpi/ic_ab_back_holo_dark_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_ab_back_holo_dark.png
rename to core/res/res/drawable-xhdpi/ic_ab_back_holo_dark_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-xhdpi/ic_ab_back_holo_light_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_ab_back_holo_light.png
rename to core/res/res/drawable-xhdpi/ic_ab_back_holo_light_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_notification.png b/core/res/res/drawable-xhdpi/ic_audio_notification_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_notification.png
rename to core/res/res/drawable-xhdpi/ic_audio_notification_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_notification_mute.png b/core/res/res/drawable-xhdpi/ic_audio_notification_mute_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_notification_mute.png
rename to core/res/res/drawable-xhdpi/ic_audio_notification_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_phone.png b/core/res/res/drawable-xhdpi/ic_audio_phone_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_phone.png
rename to core/res/res/drawable-xhdpi/ic_audio_phone_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_ring_notif.png b/core/res/res/drawable-xhdpi/ic_audio_ring_notif_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_ring_notif.png
rename to core/res/res/drawable-xhdpi/ic_audio_ring_notif_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute.png
rename to core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate.png
rename to core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_vol.png b/core/res/res/drawable-xhdpi/ic_audio_vol_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_vol.png
rename to core/res/res/drawable-xhdpi/ic_audio_vol_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_vol_mute.png b/core/res/res/drawable-xhdpi/ic_audio_vol_mute_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_audio_vol_mute.png
rename to core/res/res/drawable-xhdpi/ic_audio_vol_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_contact_picture.png b/core/res/res/drawable-xhdpi/ic_contact_picture.png
index 1a2bfde..bdba57b 100644
--- a/core/res/res/drawable-xhdpi/ic_contact_picture.png
+++ b/core/res/res/drawable-xhdpi/ic_contact_picture.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_grayedout_printer.png b/core/res/res/drawable-xhdpi/ic_grayedout_printer.png
new file mode 100644
index 0000000..5e54970
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_grayedout_printer.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-xhdpi/ic_lock_airplane_mode_off_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lock_airplane_mode_off.png
rename to core/res/res/drawable-xhdpi/ic_lock_airplane_mode_off_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_cc.png b/core/res/res/drawable-xhdpi/ic_menu_cc_am.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_cc.png
rename to core/res/res/drawable-xhdpi/ic_menu_cc_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_print.png b/core/res/res/drawable-xhdpi/ic_print.png
new file mode 100644
index 0000000..6b55a14
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_print.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_print_error.png b/core/res/res/drawable-xhdpi/ic_print_error.png
new file mode 100644
index 0000000..c3faa42
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_print_error.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png
index db1cbe6..6a97445 100644
--- a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png
+++ b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png
index de4ca91..f0e9ab9 100644
--- a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png
+++ b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png
index 853b0f0..170b833 100644
--- a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png
+++ b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_add_widget.png b/core/res/res/drawable-xhdpi/kg_add_widget.png
deleted file mode 100644
index ca48be2..0000000
--- a/core/res/res/drawable-xhdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png b/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png
deleted file mode 100644
index 4b86727..0000000
--- a/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_security_lock_focused.png b/core/res/res/drawable-xhdpi/kg_security_lock_focused.png
deleted file mode 100644
index ee21647..0000000
--- a/core/res/res/drawable-xhdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_security_lock_normal.png b/core/res/res/drawable-xhdpi/kg_security_lock_normal.png
deleted file mode 100644
index eae7d8c..0000000
--- a/core/res/res/drawable-xhdpi/kg_security_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_security_lock_pressed.png b/core/res/res/drawable-xhdpi/kg_security_lock_pressed.png
deleted file mode 100644
index 5e9a52b..0000000
--- a/core/res/res/drawable-xhdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_widget_bg_padded.9.png b/core/res/res/drawable-xhdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index a84bfa3..0000000
--- a/core/res/res/drawable-xhdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..1080244
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..5532e88
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
index e4b3393..29037a0 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
index e4b3393..f4af926 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
index ee5eb6f..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
index ee5eb6f..74e3843 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/notification_bg_low_pressed.9.png b/core/res/res/drawable-xhdpi/notification_bg_low_pressed.9.png
index 32e00be..2159cf5 100644
--- a/core/res/res/drawable-xhdpi/notification_bg_low_pressed.9.png
+++ b/core/res/res/drawable-xhdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/notification_bg_normal_pressed.9.png b/core/res/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
index 5c4da74..3f054fb 100644
--- a/core/res/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
+++ b/core/res/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/overscroll_edge.png b/core/res/res/drawable-xhdpi/overscroll_edge.png
index 4fe6c27..b5e6e61 100644
--- a/core/res/res/drawable-xhdpi/overscroll_edge.png
+++ b/core/res/res/drawable-xhdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/overscroll_glow.png b/core/res/res/drawable-xhdpi/overscroll_glow.png
index 75c3eb4..779c3a5 100644
--- a/core/res/res/drawable-xhdpi/overscroll_glow.png
+++ b/core/res/res/drawable-xhdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_above.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_above_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_inline_error_above.9.png
rename to core/res/res/drawable-xhdpi/popup_inline_error_above_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light.9.png
rename to core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_inline_error.9.png
rename to core/res/res/drawable-xhdpi/popup_inline_error_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_inline_error_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/popup_inline_error_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_inline_error_holo_light.9.png
rename to core/res/res/drawable-xhdpi/popup_inline_error_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_dark.9.png
rename to core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_light.9.png
rename to core/res/res/drawable-xhdpi/quickcontact_badge_overlay_focused_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_dark.9.png
rename to core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_light.9.png
rename to core/res/res/drawable-xhdpi/quickcontact_badge_overlay_normal_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png
deleted file mode 100644
index 75c5996..0000000
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
new file mode 100644
index 0000000..16c1e00
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light.9.png
deleted file mode 100644
index a2d6ca1..0000000
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
new file mode 100644
index 0000000..92a298b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_default_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_ab_default_holo_light.9.png
rename to core/res/res/drawable-xhdpi/spinner_ab_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light.9.png
rename to core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light.9.png
rename to core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark.9.png
deleted file mode 100644
index a3c7711..0000000
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..2dab26f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light.9.png
deleted file mode 100644
index 2a21210..0000000
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..d15cd51
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_default_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_default_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/spinner_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_default_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_default_holo_light.9.png
rename to core/res/res/drawable-xhdpi/spinner_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_disabled_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_disabled_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/spinner_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_disabled_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_disabled_holo_light.9.png
rename to core/res/res/drawable-xhdpi/spinner_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_focused_holo_dark_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_focused_holo_dark.9.png
rename to core/res/res/drawable-xhdpi/spinner_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_focused_holo_light_am.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_focused_holo_light.9.png
rename to core/res/res/drawable-xhdpi/spinner_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark.9.png
deleted file mode 100644
index aecf6bd..0000000
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..2023a9d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light.9.png
deleted file mode 100644
index 3273a22..0000000
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..3b066ae
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_notify_call_mute.png b/core/res/res/drawable-xhdpi/stat_notify_call_mute.png
index adbd7b1..e143366 100644
--- a/core/res/res/drawable-xhdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-xhdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb.png b/core/res/res/drawable-xhdpi/stat_sys_adb.png
deleted file mode 100644
index 576ae24..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_adb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
new file mode 100644
index 0000000..3222a76
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3c93ea0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_secure.png b/core/res/res/drawable-xhdpi/stat_sys_secure.png
deleted file mode 100644
index bef2fd7..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_secure.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png
index 51e648c..f7f7871 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
index 4acb32b..dc69b12 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
index 4acb32b..2370b63 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
index e862cb1..f13a194 100644
--- a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
index f1eb673..358ce26 100644
--- a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_bar_bg.9.png b/core/res/res/drawable-xhdpi/toast_bar_bg.9.png
new file mode 100644
index 0000000..1dc4927
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/toast_bar_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
index 9f39a77..1f63420 100644
--- a/core/res/res/drawable-xhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
index 9cb7c10..77e69c7 100644
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_solid_dark_holo.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_solid_dark_holo.9.png
new file mode 100644
index 0000000..8358392
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_solid_dark_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_solid_inverse_holo.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_solid_inverse_holo.9.png
new file mode 100644
index 0000000..8c6e40c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_solid_inverse_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_solid_light_holo.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_solid_light_holo.9.png
new file mode 100644
index 0000000..f6c33dc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_solid_light_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_transparent_dark_holo.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_dark_holo.9.png
new file mode 100644
index 0000000..f32ca94
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_dark_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_transparent_light_holo.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_light_holo.9.png
new file mode 100644
index 0000000..da69ea5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_light_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-xxhdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..18269a9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-xxhdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..469f736
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_dark_holo.9.png b/core/res/res/drawable-xxhdpi/ab_solid_dark_holo.9.png
new file mode 100644
index 0000000..48be5cc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_dark_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_light_holo.9.png b/core/res/res/drawable-xxhdpi/ab_solid_light_holo.9.png
new file mode 100644
index 0000000..2e49b8d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_light_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_shadow_holo.9.png b/core/res/res/drawable-xxhdpi/ab_solid_shadow_holo.9.png
new file mode 100644
index 0000000..8071886
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_shadow_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_solid_dark_holo.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_solid_dark_holo.9.png
new file mode 100644
index 0000000..086069b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_solid_dark_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_solid_inverse_holo.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_solid_inverse_holo.9.png
new file mode 100644
index 0000000..4074d81
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_solid_inverse_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_solid_light_holo.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_solid_light_holo.9.png
new file mode 100644
index 0000000..8ce58b3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_solid_light_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_transparent_dark_holo.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_dark_holo.9.png
new file mode 100644
index 0000000..fd92764
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_dark_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_transparent_light_holo.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_light_holo.9.png
new file mode 100644
index 0000000..8d64aa7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_light_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_transparent_dark_holo.9.png b/core/res/res/drawable-xxhdpi/ab_transparent_dark_holo.9.png
new file mode 100644
index 0000000..84155ccf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_transparent_dark_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_transparent_light_holo.9.png b/core/res/res/drawable-xxhdpi/ab_transparent_light_holo.9.png
new file mode 100644
index 0000000..d48e27f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_transparent_light_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_default_holo_dark.9.png
new file mode 100644
index 0000000..95475ee
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_default_holo_light.9.png
new file mode 100644
index 0000000..e1c55ad
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_focused_holo_dark.9.png
new file mode 100644
index 0000000..6c49fe7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_focused_holo_light.9.png
new file mode 100644
index 0000000..35a557e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_pressed_holo_dark.9.png
new file mode 100644
index 0000000..65f9009
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_pressed_holo_light.9.png
new file mode 100644
index 0000000..1be216b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..0707776
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_focused_holo_light.png
new file mode 100644
index 0000000..e1553b7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_holo_dark.png
new file mode 100644
index 0000000..e74b8b7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_holo_light.png
new file mode 100644
index 0000000..47a6373
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_focused_holo_dark.png
new file mode 100644
index 0000000..b0353feb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_focused_holo_light.png
new file mode 100644
index 0000000..889a67c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_holo.png b/core/res/res/drawable-xxhdpi/btn_check_off_holo.png
new file mode 100644
index 0000000..cdcfdef
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_holo_dark.png
new file mode 100644
index 0000000..ecfc08c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_holo_light.png
new file mode 100644
index 0000000..b067b58
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
new file mode 100644
index 0000000..4c95f96
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
new file mode 100644
index 0000000..df468e0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..d249372
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_focused_holo_light.png
new file mode 100644
index 0000000..b544001
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_holo_dark.png
new file mode 100644
index 0000000..eff125b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_holo_light.png
new file mode 100644
index 0000000..013c1f6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_focused_holo_dark.png
new file mode 100644
index 0000000..e0d942a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_focused_holo_light.png
new file mode 100644
index 0000000..83f8dfd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_holo.png b/core/res/res/drawable-xxhdpi/btn_check_on_holo.png
new file mode 100644
index 0000000..6193147
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_holo_dark.png
new file mode 100644
index 0000000..1aafc83
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_holo_light.png
new file mode 100644
index 0000000..11598dd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
new file mode 100644
index 0000000..668548b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
new file mode 100644
index 0000000..385350c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_code_lock_default_holo.png b/core/res/res/drawable-xxhdpi/btn_code_lock_default_holo.png
new file mode 100755
index 0000000..1b6c9b5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_code_lock_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_code_lock_touched_holo.png b/core/res/res/drawable-xxhdpi/btn_code_lock_touched_holo.png
new file mode 100755
index 0000000..dd13af8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_code_lock_touched_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..aea519c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_disabled_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..8ec4bf5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_disabled_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_disabled_holo.9.png
new file mode 100644
index 0000000..60732b3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_disabled_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_disabled_holo_dark.9.png
new file mode 100644
index 0000000..12bac53
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_disabled_holo_light.9.png
new file mode 100644
index 0000000..b4c90d4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_focused_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_focused_holo.9.png
new file mode 100644
index 0000000..33c3ebb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_focused_holo_dark.9.png
new file mode 100644
index 0000000..f7bfd78
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_focused_holo_light.9.png
new file mode 100644
index 0000000..7f5432f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_normal_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..c1632c8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_normal_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_normal_holo_dark.9.png
new file mode 100644
index 0000000..6449593
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_normal_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_normal_holo_light.9.png
new file mode 100644
index 0000000..68be3c5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
new file mode 100644
index 0000000..e05017c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
new file mode 100644
index 0000000..016a5ee
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
new file mode 100644
index 0000000..9521603
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_group_disabled_holo_dark.9.png
new file mode 100644
index 0000000..54ff2c0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_group_disabled_holo_light.9.png
new file mode 100644
index 0000000..e3c4945
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_group_focused_holo_dark.9.png
new file mode 100644
index 0000000..bd04226
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_group_focused_holo_light.9.png
new file mode 100644
index 0000000..f7aa79e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_normal_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_group_normal_holo_dark.9.png
new file mode 100644
index 0000000..26f98fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_normal_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_group_normal_holo_light.9.png
new file mode 100644
index 0000000..1ba39f2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_group_pressed_holo_dark.9.png
new file mode 100644
index 0000000..531acc4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_group_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_group_pressed_holo_light.9.png
new file mode 100644
index 0000000..358f546
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_group_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..6c0f6f3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_focused_holo_light.png
new file mode 100644
index 0000000..63ac52b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_holo_dark.png
new file mode 100644
index 0000000..946936e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_holo_light.png
new file mode 100644
index 0000000..06f0cc7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_focused_holo_dark.png
new file mode 100644
index 0000000..abbf1ae
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_focused_holo_light.png
new file mode 100644
index 0000000..28f5843
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_holo.png b/core/res/res/drawable-xxhdpi/btn_radio_off_holo.png
new file mode 100644
index 0000000..c8ac939
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_holo_dark.png
new file mode 100644
index 0000000..a7afd00
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_holo_light.png
new file mode 100644
index 0000000..43fac43
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
new file mode 100644
index 0000000..39ff3d5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
new file mode 100644
index 0000000..702155f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..16b2023
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_focused_holo_light.png
new file mode 100644
index 0000000..f03d07f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_holo_dark.png
new file mode 100644
index 0000000..66b833d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_holo_light.png
new file mode 100644
index 0000000..adb7304
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_focused_holo_dark.png
new file mode 100644
index 0000000..cb7d6c8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_focused_holo_light.png
new file mode 100644
index 0000000..12a0601
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_holo.png b/core/res/res/drawable-xxhdpi/btn_radio_on_holo.png
new file mode 100644
index 0000000..2a11733
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_holo_dark.png
new file mode 100644
index 0000000..f3ce811
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_holo_light.png
new file mode 100644
index 0000000..43142b6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
new file mode 100644
index 0000000..d43a0f9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
new file mode 100644
index 0000000..c05643f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..292c752
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_focused_holo_light.png
new file mode 100644
index 0000000..635c009
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_holo_dark.png
new file mode 100644
index 0000000..fef0797
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_holo_light.png
new file mode 100644
index 0000000..c43977dd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_focused_holo_dark.png
new file mode 100644
index 0000000..521dc80
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_focused_holo_light.png
new file mode 100644
index 0000000..71a367b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_normal_holo_dark.png
new file mode 100644
index 0000000..35f72fa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_normal_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_normal_holo_light.png
new file mode 100644
index 0000000..c8541c3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
new file mode 100644
index 0000000..899e577
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
new file mode 100644
index 0000000..aaa6826
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..e699edc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_focused_holo_light.png
new file mode 100644
index 0000000..a59c23c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_holo_dark.png
new file mode 100644
index 0000000..d2504fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_holo_light.png
new file mode 100644
index 0000000..d514bdd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_focused_holo_dark.png
new file mode 100644
index 0000000..53c7a53
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_focused_holo_light.png
new file mode 100644
index 0000000..f942490
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_normal_holo_dark.png
new file mode 100644
index 0000000..11bae7c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_normal_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_normal_holo_light.png
new file mode 100644
index 0000000..08804b5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
new file mode 100644
index 0000000..e15fc63
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
new file mode 100644
index 0000000..cc82a54
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..853243d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_focused_holo_light.png
new file mode 100644
index 0000000..b5cd0bb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_holo_dark.png
new file mode 100644
index 0000000..bb16a5f7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_holo_light.png
new file mode 100644
index 0000000..c178a9b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_focused_holo_dark.png
new file mode 100644
index 0000000..886f395
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_focused_holo_light.png
new file mode 100644
index 0000000..ab2b334
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_normal_holo_dark.png
new file mode 100644
index 0000000..59a8547
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_normal_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_normal_holo_light.png
new file mode 100644
index 0000000..14cac81
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
new file mode 100644
index 0000000..b756e79
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
new file mode 100644
index 0000000..89bf5b4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..7027cc2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_focused_holo_light.png
new file mode 100644
index 0000000..d491c5b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_holo_dark.png
new file mode 100644
index 0000000..f968b1a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_holo_light.png
new file mode 100644
index 0000000..1999f68
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_focused_holo_dark.png
new file mode 100644
index 0000000..ab4b58c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_focused_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_focused_holo_light.png
new file mode 100644
index 0000000..cd44fa6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_normal_holo_dark.png
new file mode 100644
index 0000000..8847d78
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_normal_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_normal_holo_light.png
new file mode 100644
index 0000000..3ef0498
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
new file mode 100644
index 0000000..50e4940
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
new file mode 100644
index 0000000..0b77905
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..e5ec283
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..5cd267d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_holo_dark.9.png
new file mode 100644
index 0000000..c34c7af
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_holo_light.9.png
new file mode 100644
index 0000000..9b3900a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_focused_holo_dark.9.png
new file mode 100644
index 0000000..345fe9c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_focused_holo_light.9.png
new file mode 100644
index 0000000..b338843
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_normal_holo_dark.9.png
new file mode 100644
index 0000000..3f6ab80
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_normal_holo_light.9.png
new file mode 100644
index 0000000..df71589
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
new file mode 100644
index 0000000..1e675d3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
new file mode 100644
index 0000000..2ceb802
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..ea15883
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..b403039
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_holo_dark.9.png
new file mode 100644
index 0000000..f12643e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_holo_light.9.png
new file mode 100644
index 0000000..3090c9a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_focused_holo_dark.9.png
new file mode 100644
index 0000000..2fb4d91
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_focused_holo_light.9.png
new file mode 100644
index 0000000..5e17dd5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_normal_holo_dark.9.png
new file mode 100644
index 0000000..bf9b997
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_normal_holo_light.9.png
new file mode 100644
index 0000000..b36f670c6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
new file mode 100644
index 0000000..e7a9265
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
new file mode 100644
index 0000000..df58767
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/cab_background_bottom_holo_dark.9.png b/core/res/res/drawable-xxhdpi/cab_background_bottom_holo_dark.9.png
new file mode 100644
index 0000000..8666113
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/cab_background_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/cab_background_bottom_holo_light.9.png b/core/res/res/drawable-xxhdpi/cab_background_bottom_holo_light.9.png
new file mode 100644
index 0000000..805927b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/cab_background_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png
new file mode 100644
index 0000000..418f322
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png
new file mode 100644
index 0000000..a5a59d4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/combobox_disabled.png b/core/res/res/drawable-xxhdpi/combobox_disabled.png
new file mode 100644
index 0000000..d342344
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/combobox_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/combobox_nohighlight.png b/core/res/res/drawable-xxhdpi/combobox_nohighlight.png
new file mode 100644
index 0000000..377fbd3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/combobox_nohighlight.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/create_contact.png b/core/res/res/drawable-xxhdpi/create_contact.png
new file mode 100644
index 0000000..9baf195
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/create_contact.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/day_picker_week_view_dayline_holo.9.png b/core/res/res/drawable-xxhdpi/day_picker_week_view_dayline_holo.9.png
new file mode 100644
index 0000000..6b22972
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/day_picker_week_view_dayline_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-xxhdpi/dialog_bottom_holo_dark.9.png
new file mode 100644
index 0000000..0d2ba50
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-xxhdpi/dialog_bottom_holo_light.9.png
new file mode 100644
index 0000000..13462d1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-xxhdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..b029809
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-xxhdpi/dialog_full_holo_light.9.png
new file mode 100644
index 0000000..63dd192
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_ic_close_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/dialog_ic_close_focused_holo_dark.png
new file mode 100644
index 0000000..ffe7cbf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_ic_close_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_ic_close_focused_holo_light.png b/core/res/res/drawable-xxhdpi/dialog_ic_close_focused_holo_light.png
new file mode 100644
index 0000000..f21e320
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_ic_close_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_ic_close_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/dialog_ic_close_normal_holo_dark.png
new file mode 100644
index 0000000..87cf4d5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_ic_close_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_ic_close_normal_holo_light.png b/core/res/res/drawable-xxhdpi/dialog_ic_close_normal_holo_light.png
new file mode 100644
index 0000000..8d185f4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_ic_close_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_ic_close_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/dialog_ic_close_pressed_holo_dark.png
new file mode 100644
index 0000000..cb2ec6a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_ic_close_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_ic_close_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/dialog_ic_close_pressed_holo_light.png
new file mode 100644
index 0000000..776dbfd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_ic_close_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-xxhdpi/dialog_middle_holo_dark.9.png
new file mode 100644
index 0000000..d922fd6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-xxhdpi/dialog_middle_holo_light.9.png
new file mode 100644
index 0000000..1298194
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-xxhdpi/dialog_top_holo_dark.9.png
new file mode 100644
index 0000000..baf7be3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-xxhdpi/dialog_top_holo_light.9.png
new file mode 100644
index 0000000..f35251f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_angel.png b/core/res/res/drawable-xxhdpi/emo_im_angel.png
new file mode 100644
index 0000000..7d317e2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_angel.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_cool.png b/core/res/res/drawable-xxhdpi/emo_im_cool.png
new file mode 100644
index 0000000..a05fabe
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_cool.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_crying.png b/core/res/res/drawable-xxhdpi/emo_im_crying.png
new file mode 100644
index 0000000..102800d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_crying.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_embarrassed.png b/core/res/res/drawable-xxhdpi/emo_im_embarrassed.png
new file mode 100644
index 0000000..6e5d226
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_embarrassed.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_foot_in_mouth.png b/core/res/res/drawable-xxhdpi/emo_im_foot_in_mouth.png
new file mode 100644
index 0000000..c328f8c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_foot_in_mouth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_happy.png b/core/res/res/drawable-xxhdpi/emo_im_happy.png
new file mode 100644
index 0000000..11e0163
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_happy.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_kissing.png b/core/res/res/drawable-xxhdpi/emo_im_kissing.png
new file mode 100644
index 0000000..b929861
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_kissing.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_laughing.png b/core/res/res/drawable-xxhdpi/emo_im_laughing.png
new file mode 100644
index 0000000..4ed90bc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_laughing.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_lips_are_sealed.png b/core/res/res/drawable-xxhdpi/emo_im_lips_are_sealed.png
new file mode 100644
index 0000000..bcbcf8d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_lips_are_sealed.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_money_mouth.png b/core/res/res/drawable-xxhdpi/emo_im_money_mouth.png
new file mode 100644
index 0000000..e17cf77
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_money_mouth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_sad.png b/core/res/res/drawable-xxhdpi/emo_im_sad.png
new file mode 100644
index 0000000..0696d99
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_sad.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_surprised.png b/core/res/res/drawable-xxhdpi/emo_im_surprised.png
new file mode 100644
index 0000000..bd821d7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_surprised.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_tongue_sticking_out.png b/core/res/res/drawable-xxhdpi/emo_im_tongue_sticking_out.png
new file mode 100644
index 0000000..af21474
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_tongue_sticking_out.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_undecided.png b/core/res/res/drawable-xxhdpi/emo_im_undecided.png
new file mode 100644
index 0000000..c43aa0b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_undecided.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_winking.png b/core/res/res/drawable-xxhdpi/emo_im_winking.png
new file mode 100644
index 0000000..41cdd23
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_winking.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_wtf.png b/core/res/res/drawable-xxhdpi/emo_im_wtf.png
new file mode 100644
index 0000000..36f0b32
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_wtf.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/emo_im_yelling.png b/core/res/res/drawable-xxhdpi/emo_im_yelling.png
new file mode 100644
index 0000000..db210eb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/emo_im_yelling.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/expander_close_holo_dark.9.png b/core/res/res/drawable-xxhdpi/expander_close_holo_dark.9.png
new file mode 100644
index 0000000..fb41e44
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/expander_close_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/expander_close_holo_light.9.png b/core/res/res/drawable-xxhdpi/expander_close_holo_light.9.png
new file mode 100644
index 0000000..f3042a7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/expander_close_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/expander_open_holo_dark.9.png b/core/res/res/drawable-xxhdpi/expander_open_holo_dark.9.png
new file mode 100644
index 0000000..b1f006a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/expander_open_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/expander_open_holo_light.9.png b/core/res/res/drawable-xxhdpi/expander_open_holo_light.9.png
new file mode 100644
index 0000000..bac07f6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/expander_open_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_label_left_holo_dark.9.png b/core/res/res/drawable-xxhdpi/fastscroll_label_left_holo_dark.9.png
new file mode 100644
index 0000000..c9b5893
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_label_left_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_label_left_holo_light.9.png b/core/res/res/drawable-xxhdpi/fastscroll_label_left_holo_light.9.png
new file mode 100644
index 0000000..a1326ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_label_left_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_label_right_holo_dark.9.png b/core/res/res/drawable-xxhdpi/fastscroll_label_right_holo_dark.9.png
new file mode 100644
index 0000000..91152ea
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_label_right_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_label_right_holo_light.9.png b/core/res/res/drawable-xxhdpi/fastscroll_label_right_holo_light.9.png
new file mode 100644
index 0000000..1541e97
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_label_right_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_thumb_default_holo.png b/core/res/res/drawable-xxhdpi/fastscroll_thumb_default_holo.png
new file mode 100644
index 0000000..d8335d5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_thumb_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_thumb_pressed_holo.png b/core/res/res/drawable-xxhdpi/fastscroll_thumb_pressed_holo.png
new file mode 100644
index 0000000..cdc13e1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_thumb_pressed_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_track_default_holo_dark.9.png b/core/res/res/drawable-xxhdpi/fastscroll_track_default_holo_dark.9.png
new file mode 100644
index 0000000..b9455ff
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_track_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_track_default_holo_light.9.png b/core/res/res/drawable-xxhdpi/fastscroll_track_default_holo_light.9.png
new file mode 100644
index 0000000..a5c54dc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_track_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_track_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/fastscroll_track_pressed_holo_dark.9.png
new file mode 100644
index 0000000..eaf0969
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_track_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_track_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/fastscroll_track_pressed_holo_light.9.png
new file mode 100644
index 0000000..9db45c0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/fastscroll_track_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_ab_back_holo_dark_am.png b/core/res/res/drawable-xxhdpi/ic_ab_back_holo_dark_am.png
new file mode 100644
index 0000000..04d1348
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_ab_back_holo_dark_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_ab_back_holo_light_am.png b/core/res/res/drawable-xxhdpi/ic_ab_back_holo_light_am.png
new file mode 100644
index 0000000..962dba3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_ab_back_holo_light_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_action_assist_generic_activated.png b/core/res/res/drawable-xxhdpi/ic_action_assist_generic_activated.png
new file mode 100644
index 0000000..cc38e83
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_action_assist_generic_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_action_assist_generic_normal.png b/core/res/res/drawable-xxhdpi/ic_action_assist_generic_normal.png
new file mode 100644
index 0000000..42f96eb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_action_assist_generic_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_alarm.png b/core/res/res/drawable-xxhdpi/ic_audio_alarm.png
new file mode 100755
index 0000000..c1c3d35
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_alarm_mute.png b/core/res/res/drawable-xxhdpi/ic_audio_alarm_mute.png
new file mode 100644
index 0000000..4bcee68
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_alarm_mute.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_bt.png b/core/res/res/drawable-xxhdpi/ic_audio_bt.png
new file mode 100755
index 0000000..140edac
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_bt.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_bt_mute.png b/core/res/res/drawable-xxhdpi/ic_audio_bt_mute.png
new file mode 100644
index 0000000..97829b4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_bt_mute.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_notification_am.png b/core/res/res/drawable-xxhdpi/ic_audio_notification_am.png
new file mode 100755
index 0000000..fb0e96e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_notification_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_notification_mute_am.png b/core/res/res/drawable-xxhdpi/ic_audio_notification_mute_am.png
new file mode 100644
index 0000000..3aa7b53
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_notification_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_phone_am.png b/core/res/res/drawable-xxhdpi/ic_audio_phone_am.png
new file mode 100644
index 0000000..1fd54a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_phone_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_am.png b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_am.png
new file mode 100644
index 0000000..699711c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_mute_am.png b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_mute_am.png
new file mode 100644
index 0000000..19d92ba
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_vibrate_am.png b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_vibrate_am.png
new file mode 100644
index 0000000..fdcfd56
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_vibrate_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_vol_am.png b/core/res/res/drawable-xxhdpi/ic_audio_vol_am.png
new file mode 100755
index 0000000..15b6311
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_vol_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_vol_mute_am.png b/core/res/res/drawable-xxhdpi/ic_audio_vol_mute_am.png
new file mode 100644
index 0000000..b8f4111
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_audio_vol_mute_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_btn_search_go.png b/core/res/res/drawable-xxhdpi/ic_btn_search_go.png
new file mode 100644
index 0000000..1f4301d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_btn_search_go.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_btn_speak_now.png b/core/res/res/drawable-xxhdpi/ic_btn_speak_now.png
new file mode 100644
index 0000000..b15f385
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_btn_speak_now.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_bullet_key_permission.png b/core/res/res/drawable-xxhdpi/ic_bullet_key_permission.png
new file mode 100644
index 0000000..a74c286
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_bullet_key_permission.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_cab_done_holo.png b/core/res/res/drawable-xxhdpi/ic_cab_done_holo.png
new file mode 100644
index 0000000..a23a3ae
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_cab_done_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_cab_done_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_cab_done_holo_dark.png
new file mode 100644
index 0000000..fdecbe1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_cab_done_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_cab_done_holo_light.png b/core/res/res/drawable-xxhdpi/ic_cab_done_holo_light.png
new file mode 100644
index 0000000..ca93e70
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_cab_done_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_commit_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_commit_search_api_holo_dark.png
new file mode 100644
index 0000000..6e48dc6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_commit_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_commit_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_commit_search_api_holo_light.png
new file mode 100644
index 0000000..d26f75e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_commit_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_contact_picture.png b/core/res/res/drawable-xxhdpi/ic_contact_picture.png
new file mode 100644
index 0000000..b36ec17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_contact_picture.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_contact_picture_180_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_contact_picture_180_holo_dark.png
new file mode 100644
index 0000000..6e057ac
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_contact_picture_180_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_contact_picture_180_holo_light.png b/core/res/res/drawable-xxhdpi/ic_contact_picture_180_holo_light.png
new file mode 100644
index 0000000..4111bc5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_contact_picture_180_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_contact_picture_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_contact_picture_holo_dark.png
new file mode 100644
index 0000000..52a69c3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_contact_picture_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_contact_picture_holo_light.png b/core/res/res/drawable-xxhdpi/ic_contact_picture_holo_light.png
new file mode 100644
index 0000000..5a41c23
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_contact_picture_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_dialog_alert_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_dialog_alert_holo_dark.png
new file mode 100644
index 0000000..cdd6fd8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_dialog_alert_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_dialog_alert_holo_light.png b/core/res/res/drawable-xxhdpi/ic_dialog_alert_holo_light.png
new file mode 100644
index 0000000..24ec28c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_dialog_alert_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_emergency.png b/core/res/res/drawable-xxhdpi/ic_emergency.png
new file mode 100644
index 0000000..d070311d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_input_delete.png b/core/res/res/drawable-xxhdpi/ic_input_delete.png
new file mode 100644
index 0000000..ea047dd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_input_delete.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_airplane_mode.png b/core/res/res/drawable-xxhdpi/ic_lock_airplane_mode.png
new file mode 100644
index 0000000..116b891
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_airplane_mode.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_airplane_mode_off_am.png b/core/res/res/drawable-xxhdpi/ic_lock_airplane_mode_off_am.png
new file mode 100644
index 0000000..5ca72ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_airplane_mode_off_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-xxhdpi/ic_lock_idle_alarm.png
new file mode 100644
index 0000000..ed2d3c5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_lock.png b/core/res/res/drawable-xxhdpi/ic_lock_lock.png
new file mode 100644
index 0000000..1b8882c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_lock.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_power_off.png b/core/res/res/drawable-xxhdpi/ic_lock_power_off.png
new file mode 100644
index 0000000..061dc78
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_power_off.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_silent_mode_off.png b/core/res/res/drawable-xxhdpi/ic_lock_silent_mode_off.png
new file mode 100644
index 0000000..2cca958
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_silent_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_alarm.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_alarm.png
new file mode 100644
index 0000000..f53fa8f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..78a560f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..9c21761
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..9298b61
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_camera_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_camera_activated.png
new file mode 100644
index 0000000..c41fe84
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_camera_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_camera_normal.png
new file mode 100644
index 0000000..3c29157
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_down.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_down.png
new file mode 100644
index 0000000..8b3458b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_down.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..10cad65
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..9fe0601
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_up.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_up.png
new file mode 100644
index 0000000..8e9d6d0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_chevron_up.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..1d114b1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..4db7876
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..89aece4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_emergencycall_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_emergencycall_normal.png
new file mode 100644
index 0000000..4b99bad
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_emergencycall_pressed.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_emergencycall_pressed.png
new file mode 100644
index 0000000..d1bd72e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_forgotpassword_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_forgotpassword_normal.png
new file mode 100644
index 0000000..ece563c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_forgotpassword_pressed.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_forgotpassword_pressed.png
new file mode 100644
index 0000000..ff3dfa1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_glowdot.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..c0edd91
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..d03fc06
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..76124a9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..d0680dc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..a5418d8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..7528064
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_ime.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..cb5d2fa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_player_background.9.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_player_background.9.png
new file mode 100644
index 0000000..6dacccf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_player_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_puk.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_puk.png
new file mode 100644
index 0000000..61db8cd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_puk.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..fd295ec
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..a2e1b69
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..d791ffa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_sim.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_sim.png
new file mode 100644
index 0000000..3ba4331a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_sim.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..e469bf4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..89b3213
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..72bc5ee
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..10cbb7e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..0cf7307
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..304996d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..dbd5d48
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-xxhdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..153bfa9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lockscreens_now_button.png b/core/res/res/drawable-xxhdpi/ic_lockscreens_now_button.png
new file mode 100644
index 0000000..74ad3c8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lockscreens_now_button.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_embed_play.png b/core/res/res/drawable-xxhdpi/ic_media_embed_play.png
new file mode 100644
index 0000000..3bf5a82
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_ff.png b/core/res/res/drawable-xxhdpi/ic_media_ff.png
new file mode 100644
index 0000000..ab9e022
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_ff.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_fullscreen.png b/core/res/res/drawable-xxhdpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..5734f16
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_next.png b/core/res/res/drawable-xxhdpi/ic_media_next.png
new file mode 100644
index 0000000..ce0a143
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_next.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_pause.png b/core/res/res/drawable-xxhdpi/ic_media_pause.png
new file mode 100644
index 0000000..9a36b17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_pause.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_play.png b/core/res/res/drawable-xxhdpi/ic_media_play.png
new file mode 100644
index 0000000..41f76bb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_play.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_previous.png b/core/res/res/drawable-xxhdpi/ic_media_previous.png
new file mode 100644
index 0000000..d468874
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_rew.png b/core/res/res/drawable-xxhdpi/ic_media_rew.png
new file mode 100644
index 0000000..8ebb2cc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_rew.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
new file mode 100644
index 0000000..7b0c383
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
new file mode 100644
index 0000000..efb624e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
new file mode 100644
index 0000000..5ee57e4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
new file mode 100644
index 0000000..6bc2e4a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
new file mode 100644
index 0000000..c13af9c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
new file mode 100644
index 0000000..744fb42
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
new file mode 100644
index 0000000..ca4d59c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
new file mode 100644
index 0000000..fde5688
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
new file mode 100644
index 0000000..b8715c3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
new file mode 100644
index 0000000..668bb25
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
new file mode 100644
index 0000000..7f54a62
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
new file mode 100644
index 0000000..2df924d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_stop.png b/core/res/res/drawable-xxhdpi/ic_media_stop.png
new file mode 100644
index 0000000..c09989a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_stop.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_account_list.png b/core/res/res/drawable-xxhdpi/ic_menu_account_list.png
new file mode 100644
index 0000000..e072523
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_account_list.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_add.png b/core/res/res/drawable-xxhdpi/ic_menu_add.png
new file mode 100644
index 0000000..18a83a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_add.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_agenda.png b/core/res/res/drawable-xxhdpi/ic_menu_agenda.png
new file mode 100644
index 0000000..20f350b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_agenda.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_allfriends.png b/core/res/res/drawable-xxhdpi/ic_menu_allfriends.png
new file mode 100644
index 0000000..c07a7c7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_allfriends.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_always_landscape_portrait.png b/core/res/res/drawable-xxhdpi/ic_menu_always_landscape_portrait.png
new file mode 100644
index 0000000..2decf65
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_always_landscape_portrait.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_archive.png b/core/res/res/drawable-xxhdpi/ic_menu_archive.png
new file mode 100644
index 0000000..a2d93b9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_archive.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_attachment.png b/core/res/res/drawable-xxhdpi/ic_menu_attachment.png
new file mode 100644
index 0000000..a92f66b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_attachment.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_back.png b/core/res/res/drawable-xxhdpi/ic_menu_back.png
new file mode 100644
index 0000000..d3191ca
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_back.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_block.png b/core/res/res/drawable-xxhdpi/ic_menu_block.png
new file mode 100644
index 0000000..6b8f78d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_block.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_blocked_user.png b/core/res/res/drawable-xxhdpi/ic_menu_blocked_user.png
new file mode 100644
index 0000000..096bfe4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_blocked_user.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_btn_add.png b/core/res/res/drawable-xxhdpi/ic_menu_btn_add.png
new file mode 100644
index 0000000..18a83a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_btn_add.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_call.png b/core/res/res/drawable-xxhdpi/ic_menu_call.png
new file mode 100644
index 0000000..3b99ebb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_call.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_camera.png b/core/res/res/drawable-xxhdpi/ic_menu_camera.png
new file mode 100644
index 0000000..e09d050
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_camera.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_cc_am.png b/core/res/res/drawable-xxhdpi/ic_menu_cc_am.png
new file mode 100644
index 0000000..5f1b341
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_cc_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_chat_dashboard.png b/core/res/res/drawable-xxhdpi/ic_menu_chat_dashboard.png
new file mode 100644
index 0000000..92fdd99
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_chat_dashboard.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_clear_playlist.png b/core/res/res/drawable-xxhdpi/ic_menu_clear_playlist.png
new file mode 100644
index 0000000..819e839
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_clear_playlist.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_compass.png b/core/res/res/drawable-xxhdpi/ic_menu_compass.png
new file mode 100644
index 0000000..068678d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_compass.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_compose.png b/core/res/res/drawable-xxhdpi/ic_menu_compose.png
new file mode 100644
index 0000000..f4ccc2d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_compose.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_copy.png b/core/res/res/drawable-xxhdpi/ic_menu_copy.png
new file mode 100644
index 0000000..222e083
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_copy.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_copy_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_copy_holo_dark.png
new file mode 100644
index 0000000..9dd56ef
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_copy_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_copy_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_copy_holo_light.png
new file mode 100644
index 0000000..91043c9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_copy_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_crop.png b/core/res/res/drawable-xxhdpi/ic_menu_crop.png
new file mode 100644
index 0000000..4cc11ca
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_crop.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_cut.png b/core/res/res/drawable-xxhdpi/ic_menu_cut.png
new file mode 100644
index 0000000..81f45c6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_cut.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_cut_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_cut_holo_dark.png
new file mode 100644
index 0000000..1bec21c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_cut_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_cut_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_cut_holo_light.png
new file mode 100644
index 0000000..0dfab90
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_cut_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_day.png b/core/res/res/drawable-xxhdpi/ic_menu_day.png
new file mode 100644
index 0000000..6b92894
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_day.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_delete.png b/core/res/res/drawable-xxhdpi/ic_menu_delete.png
new file mode 100644
index 0000000..8e9e78d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_delete.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_directions.png b/core/res/res/drawable-xxhdpi/ic_menu_directions.png
new file mode 100644
index 0000000..f8a50c5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_directions.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_edit.png b/core/res/res/drawable-xxhdpi/ic_menu_edit.png
new file mode 100644
index 0000000..2b6e967
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_edit.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_emoticons.png b/core/res/res/drawable-xxhdpi/ic_menu_emoticons.png
new file mode 100644
index 0000000..eae564f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_emoticons.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_end_conversation.png b/core/res/res/drawable-xxhdpi/ic_menu_end_conversation.png
new file mode 100644
index 0000000..dd94956
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_end_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_find.png b/core/res/res/drawable-xxhdpi/ic_menu_find.png
new file mode 100644
index 0000000..32fad0a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_find.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_find_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_find_holo_dark.png
new file mode 100644
index 0000000..f15e47a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_find_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_find_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_find_holo_light.png
new file mode 100644
index 0000000..61f6128
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_find_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_forward.png b/core/res/res/drawable-xxhdpi/ic_menu_forward.png
new file mode 100644
index 0000000..ca7eff9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_forward.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_friendslist.png b/core/res/res/drawable-xxhdpi/ic_menu_friendslist.png
new file mode 100644
index 0000000..920d687
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_friendslist.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_gallery.png b/core/res/res/drawable-xxhdpi/ic_menu_gallery.png
new file mode 100644
index 0000000..3140ba9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_gallery.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_goto.png b/core/res/res/drawable-xxhdpi/ic_menu_goto.png
new file mode 100644
index 0000000..0d2109c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_goto.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_help.png b/core/res/res/drawable-xxhdpi/ic_menu_help.png
new file mode 100644
index 0000000..a16ad70
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_help.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_help_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_help_holo_light.png
new file mode 100644
index 0000000..62c9eda
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_help_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_home.png b/core/res/res/drawable-xxhdpi/ic_menu_home.png
new file mode 100644
index 0000000..23c67d0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_home.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_info_details.png b/core/res/res/drawable-xxhdpi/ic_menu_info_details.png
new file mode 100644
index 0000000..4414bea
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_info_details.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_invite.png b/core/res/res/drawable-xxhdpi/ic_menu_invite.png
new file mode 100644
index 0000000..8020fd8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_invite.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_login.png b/core/res/res/drawable-xxhdpi/ic_menu_login.png
new file mode 100644
index 0000000..2ac01e9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_login.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_manage.png b/core/res/res/drawable-xxhdpi/ic_menu_manage.png
new file mode 100644
index 0000000..733b759
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_manage.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_mapmode.png b/core/res/res/drawable-xxhdpi/ic_menu_mapmode.png
new file mode 100644
index 0000000..4d8c185
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_mapmode.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_mark.png b/core/res/res/drawable-xxhdpi/ic_menu_mark.png
new file mode 100644
index 0000000..768aeb3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_mark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_month.png b/core/res/res/drawable-xxhdpi/ic_menu_month.png
new file mode 100644
index 0000000..b591a23
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_month.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_more.png b/core/res/res/drawable-xxhdpi/ic_menu_more.png
new file mode 100644
index 0000000..7e0bb5e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_more.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow.png b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow.png
new file mode 100644
index 0000000..c3a1390
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_focused_holo_dark.png
new file mode 100644
index 0000000..9cddee4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_focused_holo_light.png
new file mode 100644
index 0000000..826e724
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644
index 0000000..498a9ff
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644
index 0000000..d3d3f1a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_my_calendar.png b/core/res/res/drawable-xxhdpi/ic_menu_my_calendar.png
new file mode 100644
index 0000000..a9285fe
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_my_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_mylocation.png b/core/res/res/drawable-xxhdpi/ic_menu_mylocation.png
new file mode 100644
index 0000000..8ea61e1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_mylocation.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_myplaces.png b/core/res/res/drawable-xxhdpi/ic_menu_myplaces.png
new file mode 100644
index 0000000..85b3f20
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_myplaces.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_notifications.png b/core/res/res/drawable-xxhdpi/ic_menu_notifications.png
new file mode 100644
index 0000000..d72a365
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_notifications.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_paste.png b/core/res/res/drawable-xxhdpi/ic_menu_paste.png
new file mode 100644
index 0000000..11f560c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_paste.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_paste_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_paste_holo_dark.png
new file mode 100644
index 0000000..d0b1fdb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_paste_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_paste_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_paste_holo_light.png
new file mode 100644
index 0000000..27d01a69
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_paste_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_play_clip.png b/core/res/res/drawable-xxhdpi/ic_menu_play_clip.png
new file mode 100644
index 0000000..5c3b1e3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_play_clip.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_preferences.png b/core/res/res/drawable-xxhdpi/ic_menu_preferences.png
new file mode 100644
index 0000000..b039537
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_preferences.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_recent_history.png b/core/res/res/drawable-xxhdpi/ic_menu_recent_history.png
new file mode 100644
index 0000000..a3640a6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_recent_history.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_refresh.png b/core/res/res/drawable-xxhdpi/ic_menu_refresh.png
new file mode 100644
index 0000000..580f4cf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_refresh.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_report_image.png b/core/res/res/drawable-xxhdpi/ic_menu_report_image.png
new file mode 100644
index 0000000..b8cf01e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_report_image.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_revert.png b/core/res/res/drawable-xxhdpi/ic_menu_revert.png
new file mode 100644
index 0000000..009cb91
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_revert.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_rotate.png b/core/res/res/drawable-xxhdpi/ic_menu_rotate.png
new file mode 100644
index 0000000..fd6781f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_rotate.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_save.png b/core/res/res/drawable-xxhdpi/ic_menu_save.png
new file mode 100644
index 0000000..800da9a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_save.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_search.png b/core/res/res/drawable-xxhdpi/ic_menu_search.png
new file mode 100644
index 0000000..22bb4c8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_search_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_search_holo_dark.png
new file mode 100644
index 0000000..4ba4314
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_search_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_search_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_search_holo_light.png
new file mode 100644
index 0000000..c69d526
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_search_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_selectall_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_selectall_holo_dark.png
new file mode 100644
index 0000000..9608411
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_selectall_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_selectall_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_selectall_holo_light.png
new file mode 100644
index 0000000..f66ab27
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_selectall_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_send.png b/core/res/res/drawable-xxhdpi/ic_menu_send.png
new file mode 100644
index 0000000..7674d24
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_send.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_set_as.png b/core/res/res/drawable-xxhdpi/ic_menu_set_as.png
new file mode 100644
index 0000000..667d723
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_set_as.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_settings_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_settings_holo_light.png
new file mode 100644
index 0000000..5df7a55
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_settings_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_share.png b/core/res/res/drawable-xxhdpi/ic_menu_share.png
new file mode 100644
index 0000000..7b90639
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_share.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_menu_share_holo_dark.png
new file mode 100644
index 0000000..cc0cdda
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-xxhdpi/ic_menu_share_holo_light.png
new file mode 100644
index 0000000..1e21d9d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_slideshow.png b/core/res/res/drawable-xxhdpi/ic_menu_slideshow.png
new file mode 100644
index 0000000..5db7bc7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_slideshow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_sort_alphabetically.png b/core/res/res/drawable-xxhdpi/ic_menu_sort_alphabetically.png
new file mode 100644
index 0000000..bb925f2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_sort_alphabetically.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_sort_by_size.png b/core/res/res/drawable-xxhdpi/ic_menu_sort_by_size.png
new file mode 100644
index 0000000..da3b4a7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_sort_by_size.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_star.png b/core/res/res/drawable-xxhdpi/ic_menu_star.png
new file mode 100644
index 0000000..63ce68d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_star.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_start_conversation.png b/core/res/res/drawable-xxhdpi/ic_menu_start_conversation.png
new file mode 100644
index 0000000..bb26e49
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_stop.png b/core/res/res/drawable-xxhdpi/ic_menu_stop.png
new file mode 100644
index 0000000..992738d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_stop.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_today.png b/core/res/res/drawable-xxhdpi/ic_menu_today.png
new file mode 100644
index 0000000..b5d58d80
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_today.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_upload.png b/core/res/res/drawable-xxhdpi/ic_menu_upload.png
new file mode 100644
index 0000000..931e6ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_upload.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_upload_you_tube.png b/core/res/res/drawable-xxhdpi/ic_menu_upload_you_tube.png
new file mode 100644
index 0000000..fd8f409
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_upload_you_tube.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_view.png b/core/res/res/drawable-xxhdpi/ic_menu_view.png
new file mode 100644
index 0000000..aff6c86
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_view.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_week.png b/core/res/res/drawable-xxhdpi/ic_menu_week.png
new file mode 100644
index 0000000..8da6b1e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_week.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_zoom.png b/core/res/res/drawable-xxhdpi/ic_menu_zoom.png
new file mode 100644
index 0000000..f6a5c30
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_menu_zoom.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_ime_default.png b/core/res/res/drawable-xxhdpi/ic_notification_ime_default.png
new file mode 100644
index 0000000..6c8222e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_ime_default.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_media_route.png b/core/res/res/drawable-xxhdpi/ic_notification_media_route.png
new file mode 100644
index 0000000..da1a627
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_media_route.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png
new file mode 100644
index 0000000..fea4774
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_accounts.png b/core/res/res/drawable-xxhdpi/ic_perm_group_accounts.png
new file mode 100644
index 0000000..f30fcd4c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_accounts.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_app_info.png b/core/res/res/drawable-xxhdpi/ic_perm_group_app_info.png
new file mode 100644
index 0000000..11f2638
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_app_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_audio_settings.png b/core/res/res/drawable-xxhdpi/ic_perm_group_audio_settings.png
new file mode 100644
index 0000000..aaf8f76
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_audio_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_bluetooth.png b/core/res/res/drawable-xxhdpi/ic_perm_group_bluetooth.png
new file mode 100644
index 0000000..b302cc7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_bookmarks.png b/core/res/res/drawable-xxhdpi/ic_perm_group_bookmarks.png
new file mode 100644
index 0000000..75aee05
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_bookmarks.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_calendar.png b/core/res/res/drawable-xxhdpi/ic_perm_group_calendar.png
new file mode 100644
index 0000000..ad3629c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_camera.png b/core/res/res/drawable-xxhdpi/ic_perm_group_camera.png
new file mode 100644
index 0000000..e22ffb8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_camera.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_device_alarms.png b/core/res/res/drawable-xxhdpi/ic_perm_group_device_alarms.png
new file mode 100644
index 0000000..0b48a24
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_device_alarms.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_display.png b/core/res/res/drawable-xxhdpi/ic_perm_group_display.png
new file mode 100644
index 0000000..29e6332
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_display.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_effects_battery.png b/core/res/res/drawable-xxhdpi/ic_perm_group_effects_battery.png
new file mode 100644
index 0000000..afe137a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_effects_battery.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_location.png b/core/res/res/drawable-xxhdpi/ic_perm_group_location.png
new file mode 100644
index 0000000..7124634
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_location.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_messages.png b/core/res/res/drawable-xxhdpi/ic_perm_group_messages.png
new file mode 100644
index 0000000..9534dcb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_messages.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_microphone.png b/core/res/res/drawable-xxhdpi/ic_perm_group_microphone.png
new file mode 100644
index 0000000..723a2cf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_microphone.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_network.png b/core/res/res/drawable-xxhdpi/ic_perm_group_network.png
new file mode 100644
index 0000000..703b25b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_network.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_personal_info.png b/core/res/res/drawable-xxhdpi/ic_perm_group_personal_info.png
new file mode 100644
index 0000000..2428976
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_personal_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_phone_calls.png b/core/res/res/drawable-xxhdpi/ic_perm_group_phone_calls.png
new file mode 100644
index 0000000..67e523c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_phone_calls.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_screenlock.png b/core/res/res/drawable-xxhdpi/ic_perm_group_screenlock.png
new file mode 100644
index 0000000..d660740
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_screenlock.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_shortrange_network.png b/core/res/res/drawable-xxhdpi/ic_perm_group_shortrange_network.png
new file mode 100644
index 0000000..3aae345
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_shortrange_network.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_social_info.png b/core/res/res/drawable-xxhdpi/ic_perm_group_social_info.png
new file mode 100644
index 0000000..a3d7b26
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_social_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_status_bar.png b/core/res/res/drawable-xxhdpi/ic_perm_group_status_bar.png
new file mode 100644
index 0000000..e260acf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_status_bar.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_storage.png b/core/res/res/drawable-xxhdpi/ic_perm_group_storage.png
new file mode 100644
index 0000000..d3937db
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_storage.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_sync_settings.png b/core/res/res/drawable-xxhdpi/ic_perm_group_sync_settings.png
new file mode 100644
index 0000000..41ef06b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_sync_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_system_clock.png b/core/res/res/drawable-xxhdpi/ic_perm_group_system_clock.png
new file mode 100644
index 0000000..5a89628
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_system_clock.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_system_tools.png b/core/res/res/drawable-xxhdpi/ic_perm_group_system_tools.png
new file mode 100644
index 0000000..cee2b05
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_system_tools.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_user_dictionary.png b/core/res/res/drawable-xxhdpi/ic_perm_group_user_dictionary.png
new file mode 100644
index 0000000..8c2cd17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_user_dictionary.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_user_dictionary_write.png b/core/res/res/drawable-xxhdpi/ic_perm_group_user_dictionary_write.png
new file mode 100644
index 0000000..121d6cf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_user_dictionary_write.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_voicemail.png b/core/res/res/drawable-xxhdpi/ic_perm_group_voicemail.png
new file mode 100644
index 0000000..118c140
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_perm_group_wallpapewr.png b/core/res/res/drawable-xxhdpi/ic_perm_group_wallpapewr.png
new file mode 100644
index 0000000..f95cd9d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_perm_group_wallpapewr.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_suggestions_add.png b/core/res/res/drawable-xxhdpi/ic_suggestions_add.png
new file mode 100644
index 0000000..b880d40
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_suggestions_add.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_suggestions_delete.png b/core/res/res/drawable-xxhdpi/ic_suggestions_delete.png
new file mode 100644
index 0000000..f9e2702
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_suggestions_delete.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_text_dot.png b/core/res/res/drawable-xxhdpi/ic_text_dot.png
new file mode 100644
index 0000000..a74c286
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_text_dot.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_holo.png
new file mode 100644
index 0000000..a11b6dd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_green_holo.png
new file mode 100644
index 0000000..eae7ea8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_red_holo.png
new file mode 100644
index 0000000..f6c3e27
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_input_error.png b/core/res/res/drawable-xxhdpi/indicator_input_error.png
new file mode 100644
index 0000000..b5a6eaf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/indicator_input_error.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_activated_holo.9.png b/core/res/res/drawable-xxhdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..9f08bb0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_activated_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_divider_holo_dark.9.png
new file mode 100644
index 0000000..9678825
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_divider_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_divider_holo_light.9.png
new file mode 100644
index 0000000..c69a6a3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_focused_holo.9.png b/core/res/res/drawable-xxhdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..76cad17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo.9.png
new file mode 100644
index 0000000..8f436ea
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..6eb451f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..230d649
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
new file mode 100644
index 0000000..d4952ea
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..1352a17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_section_divider_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_section_divider_holo_dark.9.png
new file mode 100644
index 0000000..61f8915
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_section_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_section_divider_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_section_divider_holo_light.9.png
new file mode 100644
index 0000000..5ae4882
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_section_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
new file mode 100644
index 0000000..922cff7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
new file mode 100644
index 0000000..0f58325
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selector_background_disabled.9.png b/core/res/res/drawable-xxhdpi/list_selector_background_disabled.9.png
new file mode 100644
index 0000000..e662b69
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_selector_background_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selector_background_focus.9.png b/core/res/res/drawable-xxhdpi/list_selector_background_focus.9.png
new file mode 100644
index 0000000..5167387
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_selector_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selector_background_longpress.9.png b/core/res/res/drawable-xxhdpi/list_selector_background_longpress.9.png
new file mode 100644
index 0000000..4d83885
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_selector_background_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selector_background_pressed.9.png b/core/res/res/drawable-xxhdpi/list_selector_background_pressed.9.png
new file mode 100644
index 0000000..2f93cbf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_selector_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/lockscreen_protection_pattern.png b/core/res/res/drawable-xxhdpi/lockscreen_protection_pattern.png
new file mode 100644
index 0000000..5521eb6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/lockscreen_protection_pattern.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/magnified_region_frame.9.png b/core/res/res/drawable-xxhdpi/magnified_region_frame.9.png
new file mode 100644
index 0000000..09ee1c3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/magnified_region_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-xxhdpi/menu_dropdown_panel_holo_dark.9.png
new file mode 100644
index 0000000..e87e372
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-xxhdpi/menu_dropdown_panel_holo_light.9.png
new file mode 100644
index 0000000..6ca7814
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/menu_hardkey_panel_holo_dark.9.png b/core/res/res/drawable-xxhdpi/menu_hardkey_panel_holo_dark.9.png
new file mode 100644
index 0000000..c933eab
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/menu_hardkey_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/menu_hardkey_panel_holo_light.9.png b/core/res/res/drawable-xxhdpi/menu_hardkey_panel_holo_light.9.png
new file mode 100644
index 0000000..112f939
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/menu_hardkey_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/menu_popup_panel_holo_dark.9.png b/core/res/res/drawable-xxhdpi/menu_popup_panel_holo_dark.9.png
new file mode 100644
index 0000000..90489bc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/menu_popup_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/menu_popup_panel_holo_light.9.png b/core/res/res/drawable-xxhdpi/menu_popup_panel_holo_light.9.png
new file mode 100644
index 0000000..472c3d3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/menu_popup_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/notification_bg_low_pressed.9.png b/core/res/res/drawable-xxhdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..b4e7559
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/notification_bg_normal_pressed.9.png b/core/res/res/drawable-xxhdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..936fbe5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..6f0a88c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_focused_holo_light.png
new file mode 100644
index 0000000..ea965c5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_holo_dark.png
new file mode 100644
index 0000000..822df62
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_holo_light.png
new file mode 100644
index 0000000..b17dd91
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_down_focused_holo_dark.png
new file mode 100644
index 0000000..b558db7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_focused_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_down_focused_holo_light.png
new file mode 100644
index 0000000..5121bc0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_longpressed_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_down_longpressed_holo_dark.png
new file mode 100644
index 0000000..166e08c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_longpressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_longpressed_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_down_longpressed_holo_light.png
new file mode 100644
index 0000000..166e08c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_longpressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_down_normal_holo_dark.png
new file mode 100644
index 0000000..3f2e813
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_normal_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_down_normal_holo_light.png
new file mode 100644
index 0000000..9026c12
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_down_pressed_holo_dark.png
new file mode 100644
index 0000000..2a24398
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_down_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_down_pressed_holo_light.png
new file mode 100644
index 0000000..2a24398
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_down_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_selection_divider.9.png b/core/res/res/drawable-xxhdpi/numberpicker_selection_divider.9.png
new file mode 100644
index 0000000..b7a9940
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_selection_divider.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..a4eb1a5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_focused_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_focused_holo_light.png
new file mode 100644
index 0000000..b43b0c2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_holo_dark.png
new file mode 100644
index 0000000..81b68fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_holo_light.png
new file mode 100644
index 0000000..91b2f2f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_focused_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_up_focused_holo_dark.png
new file mode 100644
index 0000000..82da07e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_focused_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_up_focused_holo_light.png
new file mode 100644
index 0000000..d7c2f34
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_longpressed_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_up_longpressed_holo_dark.png
new file mode 100644
index 0000000..1bc2bf1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_longpressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_longpressed_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_up_longpressed_holo_light.png
new file mode 100644
index 0000000..1bc2bf1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_longpressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_normal_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_up_normal_holo_dark.png
new file mode 100644
index 0000000..0fd9b05
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_normal_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_up_normal_holo_light.png
new file mode 100644
index 0000000..9f6a470
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/numberpicker_up_pressed_holo_dark.png
new file mode 100644
index 0000000..35905ea
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/numberpicker_up_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/numberpicker_up_pressed_holo_light.png
new file mode 100644
index 0000000..35905ea
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/numberpicker_up_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/overscroll_edge.png b/core/res/res/drawable-xxhdpi/overscroll_edge.png
new file mode 100644
index 0000000..734bfa7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/overscroll_glow.png b/core/res/res/drawable-xxhdpi/overscroll_glow.png
new file mode 100644
index 0000000..dc1f279
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/panel_bg_holo_dark.9.png b/core/res/res/drawable-xxhdpi/panel_bg_holo_dark.9.png
new file mode 100644
index 0000000..8993469
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/panel_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/panel_bg_holo_light.9.png b/core/res/res/drawable-xxhdpi/panel_bg_holo_light.9.png
new file mode 100644
index 0000000..38ec76c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/panel_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_arrow.png b/core/res/res/drawable-xxhdpi/pointer_arrow.png
new file mode 100644
index 0000000..65e0320
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/pointer_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/popup_inline_error_above_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/popup_inline_error_above_holo_dark_am.9.png
new file mode 100644
index 0000000..251660a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/popup_inline_error_above_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/popup_inline_error_above_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/popup_inline_error_above_holo_light_am.9.png
new file mode 100644
index 0000000..12b1e64
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/popup_inline_error_above_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/popup_inline_error_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/popup_inline_error_holo_dark_am.9.png
new file mode 100644
index 0000000..5d389af
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/popup_inline_error_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/popup_inline_error_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/popup_inline_error_holo_light_am.9.png
new file mode 100644
index 0000000..5e3c01b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/popup_inline_error_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_audio_away.png b/core/res/res/drawable-xxhdpi/presence_audio_away.png
new file mode 100644
index 0000000..e8e2b1a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_audio_away.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_audio_busy.png b/core/res/res/drawable-xxhdpi/presence_audio_busy.png
new file mode 100644
index 0000000..824b5be
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_audio_busy.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_audio_online.png b/core/res/res/drawable-xxhdpi/presence_audio_online.png
new file mode 100644
index 0000000..6b3cd2d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_audio_online.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_away.png b/core/res/res/drawable-xxhdpi/presence_away.png
new file mode 100644
index 0000000..217f4e9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_away.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_busy.png b/core/res/res/drawable-xxhdpi/presence_busy.png
new file mode 100644
index 0000000..9416720
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_busy.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_invisible.png b/core/res/res/drawable-xxhdpi/presence_invisible.png
new file mode 100644
index 0000000..72ada9c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_invisible.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_offline.png b/core/res/res/drawable-xxhdpi/presence_offline.png
new file mode 100644
index 0000000..bc71d3a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_offline.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_online.png b/core/res/res/drawable-xxhdpi/presence_online.png
new file mode 100644
index 0000000..501a75d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_online.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_video_away.png b/core/res/res/drawable-xxhdpi/presence_video_away.png
new file mode 100644
index 0000000..1379bc0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_video_away.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_video_busy.png b/core/res/res/drawable-xxhdpi/presence_video_busy.png
new file mode 100644
index 0000000..d90297c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_video_busy.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/presence_video_online.png b/core/res/res/drawable-xxhdpi/presence_video_online.png
new file mode 100644
index 0000000..4186408
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/presence_video_online.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_bg_holo_dark.9.png b/core/res/res/drawable-xxhdpi/progress_bg_holo_dark.9.png
new file mode 100644
index 0000000..2e8c2e5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progress_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_bg_holo_light.9.png b/core/res/res/drawable-xxhdpi/progress_bg_holo_light.9.png
new file mode 100644
index 0000000..fb146c3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progress_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_primary_holo_dark.9.png b/core/res/res/drawable-xxhdpi/progress_primary_holo_dark.9.png
new file mode 100644
index 0000000..36078f9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progress_primary_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_primary_holo_light.9.png b/core/res/res/drawable-xxhdpi/progress_primary_holo_light.9.png
new file mode 100644
index 0000000..add4d38
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progress_primary_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_secondary_holo_dark.9.png b/core/res/res/drawable-xxhdpi/progress_secondary_holo_dark.9.png
new file mode 100644
index 0000000..90b56fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progress_secondary_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_secondary_holo_light.9.png b/core/res/res/drawable-xxhdpi/progress_secondary_holo_light.9.png
new file mode 100644
index 0000000..28b53dd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progress_secondary_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo1.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo1.png
new file mode 100644
index 0000000..e751345
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo2.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo2.png
new file mode 100644
index 0000000..663965f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo3.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo3.png
new file mode 100644
index 0000000..3574c9a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo3.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo4.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo4.png
new file mode 100644
index 0000000..a289d33
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo4.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo5.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo5.png
new file mode 100644
index 0000000..6fa2fbb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo5.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo6.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo6.png
new file mode 100644
index 0000000..0117543
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo6.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo7.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo7.png
new file mode 100644
index 0000000..681fe1d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo7.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo8.png b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo8.png
new file mode 100644
index 0000000..bbc3999
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/progressbar_indeterminate_holo8.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_focused_dark_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_focused_dark_am.9.png
new file mode 100644
index 0000000..8eda0f1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_focused_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_focused_light_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_focused_light_am.9.png
new file mode 100644
index 0000000..c7cd27a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_focused_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_normal_dark_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_normal_dark_am.9.png
new file mode 100644
index 0000000..09c8cbd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_normal_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_normal_light_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_normal_light_am.9.png
new file mode 100644
index 0000000..d0a5a71
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_normal_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
new file mode 100644
index 0000000..432436f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
new file mode 100644
index 0000000..b18aed6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_big_half_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_big_half_holo_dark.png
new file mode 100644
index 0000000..ede3db5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_big_half_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_big_half_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_big_half_holo_light.png
new file mode 100644
index 0000000..906dbe1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_big_half_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_big_off_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_big_off_holo_dark.png
new file mode 100644
index 0000000..cff58d3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_big_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_big_off_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_big_off_holo_light.png
new file mode 100644
index 0000000..7e1a770
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_big_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_big_on_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_big_on_holo_dark.png
new file mode 100644
index 0000000..ab3f4d3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_big_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_big_on_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_big_on_holo_light.png
new file mode 100644
index 0000000..ab7a496
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_big_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_med_half_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_med_half_holo_dark.png
new file mode 100644
index 0000000..8bb8aa0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_med_half_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_med_half_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_med_half_holo_light.png
new file mode 100644
index 0000000..44e6696
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_med_half_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_med_off_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_med_off_holo_dark.png
new file mode 100644
index 0000000..94ec824
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_med_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_med_off_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_med_off_holo_light.png
new file mode 100644
index 0000000..0a12fc9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_med_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_med_on_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_med_on_holo_dark.png
new file mode 100644
index 0000000..4894658
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_med_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_med_on_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_med_on_holo_light.png
new file mode 100644
index 0000000..4bb8a73
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_med_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_small_half_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_small_half_holo_dark.png
new file mode 100644
index 0000000..9e215d7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_small_half_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_small_half_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_small_half_holo_light.png
new file mode 100644
index 0000000..e6ce596
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_small_half_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_small_off_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_small_off_holo_dark.png
new file mode 100644
index 0000000..2a9fc21
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_small_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_small_off_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_small_off_holo_light.png
new file mode 100644
index 0000000..42cad5e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_small_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_small_on_holo_dark.png b/core/res/res/drawable-xxhdpi/rate_star_small_on_holo_dark.png
new file mode 100644
index 0000000..0612b25
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_small_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/rate_star_small_on_holo_light.png b/core/res/res/drawable-xxhdpi/rate_star_small_on_holo_light.png
new file mode 100644
index 0000000..aaa3d0f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/rate_star_small_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrollbar_handle_holo_dark.9.png b/core/res/res/drawable-xxhdpi/scrollbar_handle_holo_dark.9.png
new file mode 100644
index 0000000..66b3e9d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrollbar_handle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrollbar_handle_holo_light.9.png b/core/res/res/drawable-xxhdpi/scrollbar_handle_holo_light.9.png
new file mode 100644
index 0000000..5fbd723
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrollbar_handle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_disabled_holo.png b/core/res/res/drawable-xxhdpi/scrubber_control_disabled_holo.png
new file mode 100644
index 0000000..74b7431
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_disabled_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_focused_holo.png b/core/res/res/drawable-xxhdpi/scrubber_control_focused_holo.png
new file mode 100644
index 0000000..2945fbd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_focused_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_normal_holo.png b/core/res/res/drawable-xxhdpi/scrubber_control_normal_holo.png
new file mode 100644
index 0000000..9dde7da
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_normal_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_pressed_holo.png b/core/res/res/drawable-xxhdpi/scrubber_control_pressed_holo.png
new file mode 100644
index 0000000..8afbb6d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_pressed_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_primary_holo.9.png b/core/res/res/drawable-xxhdpi/scrubber_primary_holo.9.png
new file mode 100644
index 0000000..209df49
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_primary_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_secondary_holo.9.png b/core/res/res/drawable-xxhdpi/scrubber_secondary_holo.9.png
new file mode 100644
index 0000000..3dbcc48
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_secondary_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_track_holo_dark.9.png b/core/res/res/drawable-xxhdpi/scrubber_track_holo_dark.9.png
new file mode 100644
index 0000000..4014860
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_track_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_track_holo_light.9.png b/core/res/res/drawable-xxhdpi/scrubber_track_holo_light.9.png
new file mode 100644
index 0000000..1a6f577
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_track_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_16_inner_holo.png b/core/res/res/drawable-xxhdpi/spinner_16_inner_holo.png
new file mode 100644
index 0000000..30f0db3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_16_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_16_outer_holo.png b/core/res/res/drawable-xxhdpi/spinner_16_outer_holo.png
new file mode 100644
index 0000000..d0729da
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_16_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_20_inner_holo.png b/core/res/res/drawable-xxhdpi/spinner_20_inner_holo.png
new file mode 100644
index 0000000..6cbd1f4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_20_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_20_outer_holo.png b/core/res/res/drawable-xxhdpi/spinner_20_outer_holo.png
new file mode 100644
index 0000000..b6af5e7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_20_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_48_inner_holo.png b/core/res/res/drawable-xxhdpi/spinner_48_inner_holo.png
new file mode 100644
index 0000000..eca7a46
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_48_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_48_outer_holo.png b/core/res/res/drawable-xxhdpi/spinner_48_outer_holo.png
new file mode 100644
index 0000000..3511d52
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_48_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_76_inner_holo.png b/core/res/res/drawable-xxhdpi/spinner_76_inner_holo.png
new file mode 100644
index 0000000..21ad59f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_76_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_76_outer_holo.png b/core/res/res/drawable-xxhdpi/spinner_76_outer_holo.png
new file mode 100644
index 0000000..471d78c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_76_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_activated_holo_dark.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_activated_holo_dark.9.png
new file mode 100644
index 0000000..6be9e6b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_activated_holo_light.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_activated_holo_light.9.png
new file mode 100644
index 0000000..0b9a077
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_default_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_default_holo_dark_am.9.png
new file mode 100644
index 0000000..71075a7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_default_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_default_holo_light_am.9.png
new file mode 100644
index 0000000..6aabc3c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_disabled_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_disabled_holo_dark_am.9.png
new file mode 100644
index 0000000..a2045e1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_disabled_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_disabled_holo_light_am.9.png
new file mode 100644
index 0000000..1f4d161
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_focused_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_focused_holo_dark_am.9.png
new file mode 100644
index 0000000..85b0634
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_focused_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_focused_holo_light_am.9.png
new file mode 100644
index 0000000..52e29fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..e78bfd0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..66c80a2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_activated_holo_dark.9.png b/core/res/res/drawable-xxhdpi/spinner_activated_holo_dark.9.png
new file mode 100644
index 0000000..b1a39e1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_activated_holo_light.9.png b/core/res/res/drawable-xxhdpi/spinner_activated_holo_light.9.png
new file mode 100644
index 0000000..052f551
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_default_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_default_holo_dark_am.9.png
new file mode 100644
index 0000000..b0020f2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_default_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_default_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_default_holo_light_am.9.png
new file mode 100644
index 0000000..32139ce
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_default_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_disabled_holo.9.png b/core/res/res/drawable-xxhdpi/spinner_disabled_holo.9.png
new file mode 100644
index 0000000..f666309
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_disabled_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_disabled_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_disabled_holo_dark_am.9.png
new file mode 100644
index 0000000..7c12096
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_disabled_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_disabled_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_disabled_holo_light_am.9.png
new file mode 100644
index 0000000..4cef095
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_disabled_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_focused_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_focused_holo_dark_am.9.png
new file mode 100644
index 0000000..5ab38fd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_focused_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_focused_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_focused_holo_light_am.9.png
new file mode 100644
index 0000000..c40ce17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_focused_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_normal_holo.9.png b/core/res/res/drawable-xxhdpi/spinner_normal_holo.9.png
new file mode 100644
index 0000000..48a23f6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
new file mode 100644
index 0000000..e2212a5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
new file mode 100644
index 0000000..881ce7e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_call_mute.png b/core/res/res/drawable-xxhdpi/stat_notify_call_mute.png
new file mode 100644
index 0000000..8c6176c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_car_mode.png b/core/res/res/drawable-xxhdpi/stat_notify_car_mode.png
new file mode 100755
index 0000000..b01e00f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_chat.png b/core/res/res/drawable-xxhdpi/stat_notify_chat.png
new file mode 100644
index 0000000..960fdd4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_chat.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_disabled.png b/core/res/res/drawable-xxhdpi/stat_notify_disabled.png
new file mode 100644
index 0000000..06d7677b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_disk_full.png b/core/res/res/drawable-xxhdpi/stat_notify_disk_full.png
new file mode 100755
index 0000000..cd790a6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_email_generic.png b/core/res/res/drawable-xxhdpi/stat_notify_email_generic.png
new file mode 100755
index 0000000..ba98c67
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_email_generic.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_error.png b/core/res/res/drawable-xxhdpi/stat_notify_error.png
new file mode 100644
index 0000000..fa5f7a3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_error.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_gmail.png b/core/res/res/drawable-xxhdpi/stat_notify_gmail.png
new file mode 100755
index 0000000..4640e88
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_gmail.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_missed_call.png b/core/res/res/drawable-xxhdpi/stat_notify_missed_call.png
new file mode 100644
index 0000000..904df3b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_more.png b/core/res/res/drawable-xxhdpi/stat_notify_more.png
new file mode 100755
index 0000000..f3a46ec
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_rssi_in_range.png b/core/res/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..86c34ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sdcard.png b/core/res/res/drawable-xxhdpi/stat_notify_sdcard.png
new file mode 100755
index 0000000..87e9d20
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sdcard.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sdcard_prepare.png b/core/res/res/drawable-xxhdpi/stat_notify_sdcard_prepare.png
new file mode 100755
index 0000000..735ccc9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sdcard_prepare.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sdcard_usb.png b/core/res/res/drawable-xxhdpi/stat_notify_sdcard_usb.png
new file mode 100755
index 0000000..e7512ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sdcard_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sim_toolkit.png b/core/res/res/drawable-xxhdpi/stat_notify_sim_toolkit.png
new file mode 100755
index 0000000..d1cf3d7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sim_toolkit.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sync.png b/core/res/res/drawable-xxhdpi/stat_notify_sync.png
new file mode 100755
index 0000000..2a36702
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sync_anim0.png b/core/res/res/drawable-xxhdpi/stat_notify_sync_anim0.png
new file mode 100755
index 0000000..2a36702
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sync_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sync_error.png b/core/res/res/drawable-xxhdpi/stat_notify_sync_error.png
new file mode 100755
index 0000000..db2f0e2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_voicemail.png b/core/res/res/drawable-xxhdpi/stat_notify_voicemail.png
new file mode 100755
index 0000000..71dfe68
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-xxhdpi/stat_notify_wifi_in_range.png
new file mode 100644
index 0000000..47e74fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_notify_wifi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
new file mode 100644
index 0000000..e01ad386
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..d96ef64
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-xxhdpi/stat_sys_data_bluetooth.png
new file mode 100755
index 0000000..6dd4d7f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_data_usb.png b/core/res/res/drawable-xxhdpi/stat_sys_data_usb.png
new file mode 100755
index 0000000..7fcf5cd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_data_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..aeccbd6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-xxhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..3cdc45d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim0.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim0.png
new file mode 100755
index 0000000..836db12
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim1.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim1.png
new file mode 100755
index 0000000..5bc3add4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim2.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim2.png
new file mode 100755
index 0000000..962c450
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim3.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim3.png
new file mode 100755
index 0000000..e1d0d55
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim4.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim4.png
new file mode 100755
index 0000000..84420de
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim5.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim5.png
new file mode 100755
index 0000000..b495943
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png b/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png
new file mode 100755
index 0000000..81fb04a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_phone_call.png b/core/res/res/drawable-xxhdpi/stat_sys_phone_call.png
new file mode 100644
index 0000000..9348384
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-xxhdpi/stat_sys_speakerphone.png
new file mode 100644
index 0000000..a53913f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png b/core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
new file mode 100644
index 0000000..25acfbb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_general.png b/core/res/res/drawable-xxhdpi/stat_sys_tether_general.png
new file mode 100644
index 0000000..5c65601
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png b/core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png
new file mode 100644
index 0000000..28b4b54
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_wifi.png b/core/res/res/drawable-xxhdpi/stat_sys_tether_wifi.png
new file mode 100644
index 0000000..da44e6a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_tether_wifi.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_throttled.png b/core/res/res/drawable-xxhdpi/stat_sys_throttled.png
new file mode 100755
index 0000000..c2189e4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_throttled.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim0.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim0.png
new file mode 100755
index 0000000..9e63fca
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png
new file mode 100755
index 0000000..39dd3b8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png
new file mode 100755
index 0000000..b828430
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim3.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim3.png
new file mode 100755
index 0000000..7834460
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim4.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim4.png
new file mode 100755
index 0000000..34c6f27
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim5.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim5.png
new file mode 100755
index 0000000..1270acf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_warning.png b/core/res/res/drawable-xxhdpi/stat_sys_warning.png
new file mode 100755
index 0000000..907de0f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_warning.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_bg_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_bg_disabled_holo_dark.9.png
new file mode 100644
index 0000000..e80453e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_bg_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_bg_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_bg_disabled_holo_light.9.png
new file mode 100644
index 0000000..0ec08ee
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_bg_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_bg_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_bg_focused_holo_dark.9.png
new file mode 100644
index 0000000..13f852d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_bg_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_bg_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_bg_focused_holo_light.9.png
new file mode 100644
index 0000000..e7767b8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_bg_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_bg_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_bg_holo_dark.9.png
new file mode 100644
index 0000000..d1133bf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_bg_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_bg_holo_light.9.png
new file mode 100644
index 0000000..4532035
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_activated_holo_dark.9.png
new file mode 100644
index 0000000..2b3e151
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_activated_holo_light.9.png
new file mode 100644
index 0000000..77c08a5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_disabled_holo_dark.9.png
new file mode 100644
index 0000000..5f36c04
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_disabled_holo_light.9.png
new file mode 100644
index 0000000..7c16463
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_holo_dark.9.png
new file mode 100644
index 0000000..f14f0d6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_holo_light.9.png
new file mode 100644
index 0000000..9920f54
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_holo_light_v2.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_holo_light_v2.9.png
new file mode 100644
index 0000000..00518ad
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_holo_light_v2.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
new file mode 100644
index 0000000..98c517f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
new file mode 100644
index 0000000..a93ee06
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_def_app_icon.png b/core/res/res/drawable-xxhdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..20a47a0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_delete.png b/core/res/res/drawable-xxhdpi/sym_keyboard_delete.png
new file mode 100644
index 0000000..9230135
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_enter.png b/core/res/res/drawable-xxhdpi/sym_keyboard_enter.png
new file mode 100644
index 0000000..a234cde
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_enter.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num0_no_plus.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num0_no_plus.png
new file mode 100644
index 0000000..da434a4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num0_no_plus.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num1.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num1.png
new file mode 100644
index 0000000..715e9aee
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num2.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num2.png
new file mode 100644
index 0000000..d0cbce2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num3.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num3.png
new file mode 100644
index 0000000..d152442
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num3.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num4.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num4.png
new file mode 100644
index 0000000..9438f47
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num4.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num5.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num5.png
new file mode 100644
index 0000000..0104cfe
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num5.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num6.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num6.png
new file mode 100644
index 0000000..852d0a22
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num6.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num7.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num7.png
new file mode 100644
index 0000000..bdd1e22
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num7.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num8.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num8.png
new file mode 100644
index 0000000..0d9a0f3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num8.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_num9.png b/core/res/res/drawable-xxhdpi/sym_keyboard_num9.png
new file mode 100644
index 0000000..ab87892
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_num9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_keyboard_return_holo.png b/core/res/res/drawable-xxhdpi/sym_keyboard_return_holo.png
new file mode 100644
index 0000000..7d95807
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/sym_keyboard_return_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_selected_focused_holo.9.png b/core/res/res/drawable-xxhdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..619efa4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_selected_holo.9.png b/core/res/res/drawable-xxhdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..bee35ca
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..ffedd02
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_unselected_focused_holo.9.png b/core/res/res/drawable-xxhdpi/tab_unselected_focused_holo.9.png
new file mode 100644
index 0000000..e9a5bf5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/tab_unselected_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_unselected_holo.9.png b/core/res/res/drawable-xxhdpi/tab_unselected_holo.9.png
new file mode 100644
index 0000000..8fcecf7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/tab_unselected_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
new file mode 100644
index 0000000..82c6998
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_edit_paste_window.9.png b/core/res/res/drawable-xxhdpi/text_edit_paste_window.9.png
new file mode 100644
index 0000000..9e247e6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-xxhdpi/text_edit_suggestions_window.9.png
new file mode 100644
index 0000000..9e247e6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/text_edit_suggestions_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left.png b/core/res/res/drawable-xxhdpi/text_select_handle_left.png
new file mode 100644
index 0000000..8497601
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_left.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_middle.png b/core/res/res/drawable-xxhdpi/text_select_handle_middle.png
new file mode 100644
index 0000000..7b74f66
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_middle.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right.png b/core/res/res/drawable-xxhdpi/text_select_handle_right.png
new file mode 100644
index 0000000..25e0780
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_right.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_activated_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_activated_holo_dark.9.png
new file mode 100644
index 0000000..a4c891e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_activated_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_activated_holo_light.9.png
new file mode 100644
index 0000000..a4c891e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_default_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_default_holo_dark.9.png
new file mode 100644
index 0000000..1e8dafa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_default_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_default_holo_light.9.png
new file mode 100644
index 0000000..9ece814
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..e21548e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_disabled_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..5bc20f9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_disabled_holo_dark.9.png
new file mode 100644
index 0000000..5592f76
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_disabled_holo_light.9.png
new file mode 100644
index 0000000..8fda94d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_focused_holo_dark.9.png
new file mode 100644
index 0000000..d557164
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_focused_holo_light.9.png
new file mode 100644
index 0000000..d557164
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_activated_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_activated_holo_dark.9.png
new file mode 100644
index 0000000..a4c891e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_activated_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_activated_holo_light.9.png
new file mode 100644
index 0000000..a4c891e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_default_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_default_holo_dark.9.png
new file mode 100644
index 0000000..1e8dafa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_default_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_default_holo_light.9.png
new file mode 100644
index 0000000..9ece814
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..e21548e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..5bc20f9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_holo_dark.9.png
new file mode 100644
index 0000000..5592f76
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_holo_light.9.png
new file mode 100644
index 0000000..8fda94d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_focused_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_focused_holo_dark.9.png
new file mode 100644
index 0000000..d557164
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_multiline_focused_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_multiline_focused_holo_light.9.png
new file mode 100644
index 0000000..d557164
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_multiline_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_search_default_holo_dark.9.png
new file mode 100644
index 0000000..e634c75
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_search_default_holo_light.9.png
new file mode 100644
index 0000000..ea9dd89
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_search_right_default_holo_dark.9.png
new file mode 100644
index 0000000..6042bcf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_search_right_default_holo_light.9.png
new file mode 100644
index 0000000..b34b536
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_search_right_selected_holo_dark.9.png
new file mode 100644
index 0000000..114acf4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_search_right_selected_holo_light.9.png
new file mode 100644
index 0000000..098475b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-xxhdpi/textfield_search_selected_holo_dark.9.png
new file mode 100644
index 0000000..8fcaadc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-xxhdpi/textfield_search_selected_holo_light.9.png
new file mode 100644
index 0000000..df5c730
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame.9.png b/core/res/res/drawable-xxhdpi/toast_frame.9.png
new file mode 100644
index 0000000..882b9c6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
new file mode 100644
index 0000000..edecb63
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/transportcontrol_bg.9.png b/core/res/res/drawable-xxhdpi/transportcontrol_bg.9.png
new file mode 100644
index 0000000..a5dc6cb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/transportcontrol_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/vpn_connected.png b/core/res/res/drawable-xxhdpi/vpn_connected.png
new file mode 100644
index 0000000..ea4930c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/vpn_disconnected.png b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
new file mode 100644
index 0000000..4cd0dd4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable/activity_picker_bg.xml b/core/res/res/drawable/activity_picker_bg.xml
deleted file mode 100644
index a471c94..0000000
--- a/core/res/res/drawable/activity_picker_bg.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_window_focused="false" android:drawable="@color/transparent" />
-
-    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
-    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
-    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/list_selector_disabled_holo_light" />
-    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
-    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
-    <item android:state_focused="true"                                                             android:drawable="@drawable/activity_picker_bg_focused" />
-    <item android:state_activated="true"                                                             android:drawable="@drawable/activity_picker_bg_activated" />
-    <item android:drawable="@color/transparent" />
-
-</selector>
diff --git a/core/res/res/drawable/btn_cab_done_holo_dark.xml b/core/res/res/drawable/btn_cab_done_holo_dark.xml
index fe42951..f865ddd 100644
--- a/core/res/res/drawable/btn_cab_done_holo_dark.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_dark.xml
@@ -14,9 +14,10 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:autoMirrored="true">
     <item android:state_pressed="true"
-        android:drawable="@drawable/btn_cab_done_pressed_holo_dark" />
+        android:drawable="@drawable/list_pressed_holo_dark" />
     <item android:state_focused="true" android:state_enabled="true"
         android:drawable="@drawable/btn_cab_done_focused_holo_dark" />
     <item android:state_enabled="true"
diff --git a/core/res/res/drawable/btn_cab_done_holo_light.xml b/core/res/res/drawable/btn_cab_done_holo_light.xml
index f362774..6d85fc4 100644
--- a/core/res/res/drawable/btn_cab_done_holo_light.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_light.xml
@@ -14,9 +14,10 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:autoMirrored="true">
     <item android:state_pressed="true"
-        android:drawable="@drawable/btn_cab_done_pressed_holo_light" />
+        android:drawable="@drawable/list_pressed_holo_light" />
     <item android:state_focused="true" android:state_enabled="true"
         android:drawable="@drawable/btn_cab_done_focused_holo_light" />
     <item android:state_enabled="true"
diff --git a/core/res/res/drawable/ic_ab_back_holo_dark.xml b/core/res/res/drawable/ic_ab_back_holo_dark.xml
new file mode 100644
index 0000000..740d3e8
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_ab_back_holo_dark_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_ab_back_holo_light.xml b/core/res/res/drawable/ic_ab_back_holo_light.xml
new file mode 100644
index 0000000..7639f94
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_ab_back_holo_light_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_notification.xml b/core/res/res/drawable/ic_audio_notification.xml
new file mode 100644
index 0000000..b87e4c8
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_notification.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_notification_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_notification_mute.xml b/core/res/res/drawable/ic_audio_notification_mute.xml
new file mode 100644
index 0000000..1caf27c
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_notification_mute.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_notification_mute_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_phone.xml b/core/res/res/drawable/ic_audio_phone.xml
new file mode 100644
index 0000000..e6869fd
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_phone.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_phone_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_ring_notif.xml b/core/res/res/drawable/ic_audio_ring_notif.xml
new file mode 100644
index 0000000..2f48741
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_ring_notif.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_ring_notif_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_ring_notif_mute.xml b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
new file mode 100644
index 0000000..7549f6d
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_ring_notif_mute_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
new file mode 100644
index 0000000..3481e27
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_ring_notif_vibrate_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_vol.xml b/core/res/res/drawable/ic_audio_vol.xml
new file mode 100644
index 0000000..6dd249b
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_vol.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_vol_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_audio_vol_mute.xml b/core/res/res/drawable/ic_audio_vol_mute.xml
new file mode 100644
index 0000000..b093f59
--- /dev/null
+++ b/core/res/res/drawable/ic_audio_vol_mute.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_audio_vol_mute_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_lock_airplane_mode_off.xml b/core/res/res/drawable/ic_lock_airplane_mode_off.xml
new file mode 100644
index 0000000..b344e28
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_airplane_mode_off.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_lock_airplane_mode_off_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/ic_menu_cc.xml b/core/res/res/drawable/ic_menu_cc.xml
new file mode 100644
index 0000000..2bb4ff7
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_cc.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_menu_cc_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
index 7c68426..288c778 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
@@ -16,5 +16,5 @@
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@android:drawable/list_pressed_holo_dark"  />
-    <item android:drawable="@android:drawable/list_longpressed_holo"  />
+    <item android:drawable="@android:drawable/list_longpressed_holo_dark"  />
 </transition>
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_light.xml b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
index fc08a84..b729e1f 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_light.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
@@ -16,5 +16,5 @@
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@android:drawable/list_pressed_holo_light"  />
-    <item android:drawable="@android:drawable/list_longpressed_holo"  />
+    <item android:drawable="@android:drawable/list_longpressed_holo_light"  />
 </transition>
diff --git a/core/res/res/drawable/lockscreen_password_field_dark.xml b/core/res/res/drawable/lockscreen_password_field_dark.xml
deleted file mode 100644
index 92ceb79..0000000
--- a/core/res/res/drawable/lockscreen_password_field_dark.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_bg_default_holo_dark" />
-    <item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_bg_disabled_holo_dark" />
-    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_bg_activated_holo_dark" />
-    <iten android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/textfield_bg_focused_holo_dark" />
-    <item android:state_enabled="true" android:drawable="@drawable/textfield_bg_default_holo_dark" />
-    <item android:state_focused="true" android:drawable="@drawable/textfield_bg_disabled_focused_holo_dark" />
-    <item android:drawable="@drawable/textfield_bg_disabled_holo_dark" />
-</selector>
-
diff --git a/core/res/res/drawable/popup_inline_error.xml b/core/res/res/drawable/popup_inline_error.xml
new file mode 100644
index 0000000..d74678b
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/popup_inline_error_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/popup_inline_error_above.xml b/core/res/res/drawable/popup_inline_error_above.xml
new file mode 100644
index 0000000..4be5a3e
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error_above.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/popup_inline_error_above_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/popup_inline_error_above_holo_dark.xml b/core/res/res/drawable/popup_inline_error_above_holo_dark.xml
new file mode 100644
index 0000000..70511b8
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error_above_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/popup_inline_error_above_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/popup_inline_error_above_holo_light.xml b/core/res/res/drawable/popup_inline_error_above_holo_light.xml
new file mode 100644
index 0000000..0cf8974
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error_above_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/popup_inline_error_above_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/popup_inline_error_holo_dark.xml b/core/res/res/drawable/popup_inline_error_holo_dark.xml
new file mode 100644
index 0000000..16cfe79
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/popup_inline_error_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/popup_inline_error_holo_light.xml b/core/res/res/drawable/popup_inline_error_holo_light.xml
new file mode 100644
index 0000000..1725a22
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/popup_inline_error_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/quickcontact_badge_overlay_focused_dark.xml b/core/res/res/drawable/quickcontact_badge_overlay_focused_dark.xml
new file mode 100644
index 0000000..21fb932
--- /dev/null
+++ b/core/res/res/drawable/quickcontact_badge_overlay_focused_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/quickcontact_badge_overlay_focused_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/quickcontact_badge_overlay_focused_light.xml b/core/res/res/drawable/quickcontact_badge_overlay_focused_light.xml
new file mode 100644
index 0000000..04f97cd
--- /dev/null
+++ b/core/res/res/drawable/quickcontact_badge_overlay_focused_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/quickcontact_badge_overlay_focused_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/quickcontact_badge_overlay_normal_dark.xml b/core/res/res/drawable/quickcontact_badge_overlay_normal_dark.xml
new file mode 100644
index 0000000..ff17781
--- /dev/null
+++ b/core/res/res/drawable/quickcontact_badge_overlay_normal_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/quickcontact_badge_overlay_normal_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/quickcontact_badge_overlay_normal_light.xml b/core/res/res/drawable/quickcontact_badge_overlay_normal_light.xml
new file mode 100644
index 0000000..148354d
--- /dev/null
+++ b/core/res/res/drawable/quickcontact_badge_overlay_normal_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/quickcontact_badge_overlay_normal_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/quickcontact_badge_overlay_pressed_dark.xml b/core/res/res/drawable/quickcontact_badge_overlay_pressed_dark.xml
new file mode 100644
index 0000000..9ca8a88
--- /dev/null
+++ b/core/res/res/drawable/quickcontact_badge_overlay_pressed_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/quickcontact_badge_overlay_pressed_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/quickcontact_badge_overlay_pressed_light.xml b/core/res/res/drawable/quickcontact_badge_overlay_pressed_light.xml
new file mode 100644
index 0000000..d2236e2
--- /dev/null
+++ b/core/res/res/drawable/quickcontact_badge_overlay_pressed_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/quickcontact_badge_overlay_pressed_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_default_holo_dark.xml b/core/res/res/drawable/spinner_ab_default_holo_dark.xml
new file mode 100644
index 0000000..b0cc006
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_default_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_default_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_default_holo_light.xml b/core/res/res/drawable/spinner_ab_default_holo_light.xml
new file mode 100644
index 0000000..48d1fcb
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_default_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_default_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_disabled_holo_dark.xml b/core/res/res/drawable/spinner_ab_disabled_holo_dark.xml
new file mode 100644
index 0000000..60926a7
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_disabled_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_disabled_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_disabled_holo_light.xml b/core/res/res/drawable/spinner_ab_disabled_holo_light.xml
new file mode 100644
index 0000000..668212c
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_disabled_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_disabled_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_focused_holo_dark.xml b/core/res/res/drawable/spinner_ab_focused_holo_dark.xml
new file mode 100644
index 0000000..ff82bce
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_focused_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_focused_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_focused_holo_light.xml b/core/res/res/drawable/spinner_ab_focused_holo_light.xml
new file mode 100644
index 0000000..19ac864
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_focused_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_focused_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_holo_dark.xml b/core/res/res/drawable/spinner_ab_holo_dark.xml
index 0932eff..9b8967c 100644
--- a/core/res/res/drawable/spinner_ab_holo_dark.xml
+++ b/core/res/res/drawable/spinner_ab_holo_dark.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:autoMirrored="true">
     <item android:state_enabled="false"
           android:drawable="@drawable/spinner_ab_disabled_holo_dark" />
     <item android:state_pressed="true"
diff --git a/core/res/res/drawable/spinner_ab_holo_light.xml b/core/res/res/drawable/spinner_ab_holo_light.xml
index e785cf4..a324c08 100644
--- a/core/res/res/drawable/spinner_ab_holo_light.xml
+++ b/core/res/res/drawable/spinner_ab_holo_light.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:autoMirrored="true">
     <item android:state_enabled="false"
           android:drawable="@drawable/spinner_ab_disabled_holo_light" />
     <item android:state_pressed="true"
diff --git a/core/res/res/drawable/spinner_ab_pressed_holo_dark.xml b/core/res/res/drawable/spinner_ab_pressed_holo_dark.xml
new file mode 100644
index 0000000..baad9f0
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_pressed_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_pressed_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_ab_pressed_holo_light.xml b/core/res/res/drawable/spinner_ab_pressed_holo_light.xml
new file mode 100644
index 0000000..b58ee1d
--- /dev/null
+++ b/core/res/res/drawable/spinner_ab_pressed_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_ab_pressed_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_background_holo_dark.xml b/core/res/res/drawable/spinner_background_holo_dark.xml
index eb6b18b..a57f720 100644
--- a/core/res/res/drawable/spinner_background_holo_dark.xml
+++ b/core/res/res/drawable/spinner_background_holo_dark.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:autoMirrored="true">
     <item android:state_enabled="false"
           android:drawable="@drawable/spinner_disabled_holo_dark" />
     <item android:state_pressed="true"
diff --git a/core/res/res/drawable/spinner_background_holo_light.xml b/core/res/res/drawable/spinner_background_holo_light.xml
index 9d17ed0c..899633c 100644
--- a/core/res/res/drawable/spinner_background_holo_light.xml
+++ b/core/res/res/drawable/spinner_background_holo_light.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:autoMirrored="true">
     <item android:state_enabled="false"
           android:drawable="@drawable/spinner_disabled_holo_light" />
     <item android:state_pressed="true"
diff --git a/core/res/res/drawable/spinner_default_holo_dark.xml b/core/res/res/drawable/spinner_default_holo_dark.xml
new file mode 100644
index 0000000..8d0d020
--- /dev/null
+++ b/core/res/res/drawable/spinner_default_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_default_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_default_holo_light.xml b/core/res/res/drawable/spinner_default_holo_light.xml
new file mode 100644
index 0000000..250f2eb
--- /dev/null
+++ b/core/res/res/drawable/spinner_default_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_default_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_disabled_holo_dark.xml b/core/res/res/drawable/spinner_disabled_holo_dark.xml
new file mode 100644
index 0000000..c7efa8b
--- /dev/null
+++ b/core/res/res/drawable/spinner_disabled_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_disabled_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_disabled_holo_light.xml b/core/res/res/drawable/spinner_disabled_holo_light.xml
new file mode 100644
index 0000000..772154b
--- /dev/null
+++ b/core/res/res/drawable/spinner_disabled_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_disabled_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_focused_holo_dark.xml b/core/res/res/drawable/spinner_focused_holo_dark.xml
new file mode 100644
index 0000000..9758fa3
--- /dev/null
+++ b/core/res/res/drawable/spinner_focused_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_focused_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_focused_holo_light.xml b/core/res/res/drawable/spinner_focused_holo_light.xml
new file mode 100644
index 0000000..e3f7108
--- /dev/null
+++ b/core/res/res/drawable/spinner_focused_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_focused_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_pressed_holo_dark.xml b/core/res/res/drawable/spinner_pressed_holo_dark.xml
new file mode 100644
index 0000000..ab98514
--- /dev/null
+++ b/core/res/res/drawable/spinner_pressed_holo_dark.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_pressed_holo_dark_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/spinner_pressed_holo_light.xml b/core/res/res/drawable/spinner_pressed_holo_light.xml
new file mode 100644
index 0000000..6be4785
--- /dev/null
+++ b/core/res/res/drawable/spinner_pressed_holo_light.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/spinner_pressed_holo_light_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/core/res/res/drawable/stat_sys_adb.xml
new file mode 100644
index 0000000..dfc8563
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_adb.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/stat_sys_adb_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
new file mode 100644
index 0000000..0da9a81
--- /dev/null
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <stroke
+        android:width="2dp"
+        android:color="@color/accessibility_focus_highlight" />
+
+    <corners android:radius="2dp"/>
+
+</shape>
diff --git a/core/res/res/layout-land/keyguard_glow_pad_container.xml b/core/res/res/layout-land/keyguard_glow_pad_container.xml
deleted file mode 100644
index f8364f1..0000000
--- a/core/res/res/layout-land/keyguard_glow_pad_container.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/keyguard_glow_pad_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center" />
-</merge>
\ No newline at end of file
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
deleted file mode 100644
index 6b36235..0000000
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.internal.policy.impl.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal">
-
-    <com.android.internal.policy.impl.keyguard.MultiPaneChallengeLayout
-        android:id="@+id/multi_pane_challenge"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false">
-
-        <include layout="@layout/keyguard_widget_remove_drop_target"
-            android:id="@+id/keyguard_widget_pager_delete_target"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            androidprv:layout_childType="pageDeleteDropTarget" />
-
-        <include layout="@layout/keyguard_widget_pager"
-            android:id="@+id/app_widget_container"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            androidprv:layout_centerWithinArea="0.55"
-            androidprv:layout_childType="widget"
-            androidprv:layout_maxWidth="480dp"
-            androidprv:layout_maxHeight="480dp" />
-        <include layout="@layout/keyguard_multi_user_selector"/>
-
-        <View android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              androidprv:layout_childType="scrim"
-              android:background="#99000000" />
-
-        <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
-            android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            androidprv:layout_childType="challenge"
-            androidprv:layout_centerWithinArea="0.55">
-            <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
-                android:id="@+id/view_flipper"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:paddingLeft="@dimen/keyguard_security_view_margin"
-                android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:paddingRight="@dimen/keyguard_security_view_margin"
-                android:paddingBottom="@dimen/keyguard_security_view_margin"
-                android:gravity="center">
-            </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
-        </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
-
-    </com.android.internal.policy.impl.keyguard.MultiPaneChallengeLayout>
-</com.android.internal.policy.impl.keyguard.KeyguardHostView>
-
diff --git a/core/res/res/layout-land/keyguard_status_area.xml b/core/res/res/layout-land/keyguard_status_area.xml
deleted file mode 100644
index 51ee740..0000000
--- a/core/res/res/layout-land/keyguard_status_area.xml
+++ /dev/null
@@ -1,56 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_status_area"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="end"
-    android:layout_marginTop="-16dp"
-    android:orientation="vertical">
-
-    <TextView
-        android:id="@+id/date"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="@dimen/kg_status_date_font_size"
-        />
-
-    <TextView
-        android:id="@+id/alarm_status"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:layout_marginTop="28dp"
-        android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearance"
-        android:textSize="@dimen/kg_status_line_font_size"
-        android:drawablePadding="4dip"
-        />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout-land/keyguard_widget_pager.xml b/core/res/res/layout-land/keyguard_widget_pager.xml
deleted file mode 100644
index 02c6d0e..0000000
--- a/core/res/res/layout-land/keyguard_widget_pager.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.internal.policy.impl.keyguard.KeyguardWidgetCarousel
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:paddingLeft="25dp"
-    android:paddingRight="25dp"
-    android:paddingTop="25dp"
-    android:paddingBottom="25dp"
-    android:clipToPadding="false"
-    androidprv:pageSpacing="10dp">
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetCarousel>
\ No newline at end of file
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
deleted file mode 100644
index fb25f9c..0000000
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.internal.policy.impl.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center_horizontal"
-    android:orientation="vertical">
-
-    <com.android.internal.policy.impl.keyguard.SlidingChallengeLayout
-        android:id="@+id/sliding_layout"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            androidprv:layout_childType="pageDeleteDropTarget">
-            <include layout="@layout/keyguard_widget_remove_drop_target"
-                android:id="@+id/keyguard_widget_pager_delete_target"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="top|center_horizontal" />
-        </FrameLayout>
-
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            androidprv:layout_childType="widgets">
-            <include layout="@layout/keyguard_widget_pager"
-                android:id="@+id/app_widget_container"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_gravity="center"/>
-        </FrameLayout>
-
-        <View android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              androidprv:layout_childType="scrim"
-              android:background="#99000000" />
-
-        <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
-            android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_maxHeight="@dimen/keyguard_security_height"
-            androidprv:layout_childType="challenge"
-            android:padding="0dp"
-            android:gravity="bottom|center_horizontal">
-            <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
-                android:id="@+id/view_flipper"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:gravity="center">
-            </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
-        </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
-
-        <ImageButton
-              android:layout_width="match_parent"
-              android:layout_height="@dimen/kg_widget_pager_bottom_padding"
-              androidprv:layout_childType="expandChallengeHandle"
-              android:focusable="true"
-              android:background="@null"
-              android:src="@drawable/keyguard_expand_challenge_handle"
-              android:scaleType="center"
-              android:contentDescription="@string/keyguard_accessibility_expand_lock_area" />
-
-    </com.android.internal.policy.impl.keyguard.SlidingChallengeLayout>
-</com.android.internal.policy.impl.keyguard.KeyguardHostView>
-
diff --git a/core/res/res/layout-port/keyguard_status_area.xml b/core/res/res/layout-port/keyguard_status_area.xml
deleted file mode 100644
index d274457..0000000
--- a/core/res/res/layout-port/keyguard_status_area.xml
+++ /dev/null
@@ -1,59 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_status_area"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="right"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="0dp"
-        android:layout_gravity="right">
-        <TextView
-            android:id="@+id/date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="@dimen/kg_status_date_font_size"
-            />
-
-        <TextView
-            android:id="@+id/alarm_status"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:textAppearance="?android:attr/textAppearance"
-            android:textSize="@dimen/kg_status_line_font_size"
-            android:drawablePadding="4dip"
-            />
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/core/res/res/layout-port/keyguard_widget_pager.xml b/core/res/res/layout-port/keyguard_widget_pager.xml
deleted file mode 100644
index 7f22709..0000000
--- a/core/res/res/layout-port/keyguard_widget_pager.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/app_widget_container"
-    android:paddingLeft="25dp"
-    android:paddingRight="25dp"
-    android:paddingTop="25dp"
-    android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
-    android:clipToPadding="false"
-    androidprv:pageSpacing="10dp">
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
deleted file mode 100644
index e3d577d..0000000
--- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.internal.policy.impl.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal">
-
-    <com.android.internal.policy.impl.keyguard.MultiPaneChallengeLayout
-        android:id="@+id/multi_pane_challenge"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:orientation="vertical">
-
-        <include layout="@layout/keyguard_widget_remove_drop_target"
-            android:id="@+id/keyguard_widget_pager_delete_target"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            androidprv:layout_childType="pageDeleteDropTarget" />
-
-        <include layout="@layout/keyguard_widget_pager"
-            android:id="@+id/app_widget_container"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            androidprv:layout_centerWithinArea="0.5"
-            androidprv:layout_childType="widget"
-            androidprv:layout_maxWidth="480dp"
-            androidprv:layout_maxHeight="480dp" />
-
-        <include layout="@layout/keyguard_multi_user_selector"/>
-
-        <View android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              androidprv:layout_childType="scrim"
-              android:background="#99000000" />
-
-        <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
-            android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            androidprv:layout_centerWithinArea="0.5"
-            androidprv:layout_childType="challenge"
-            android:layout_gravity="center_horizontal|bottom">
-            <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
-                android:id="@+id/view_flipper"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:paddingLeft="@dimen/keyguard_security_view_margin"
-                android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:paddingRight="@dimen/keyguard_security_view_margin"
-                android:paddingBottom="@dimen/keyguard_security_view_margin"
-                android:gravity="center">
-            </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
-        </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
-
-    </com.android.internal.policy.impl.keyguard.MultiPaneChallengeLayout>
-</com.android.internal.policy.impl.keyguard.KeyguardHostView>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_status_area.xml b/core/res/res/layout-sw600dp-port/keyguard_status_area.xml
deleted file mode 100644
index 88dd760..0000000
--- a/core/res/res/layout-sw600dp-port/keyguard_status_area.xml
+++ /dev/null
@@ -1,56 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_status_area"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="end"
-    android:layout_marginTop="-16dp"
-    android:orientation="vertical">
-
-    <TextView
-        android:id="@+id/date"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="@dimen/kg_status_date_font_size"
-        />
-
-    <TextView
-        android:id="@+id/alarm_status"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:layout_marginTop="28dp"
-        android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearance"
-        android:textSize="@dimen/kg_status_line_font_size"
-        android:drawablePadding="4dip"
-        />
-
-</LinearLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_navigation.xml b/core/res/res/layout-sw600dp/keyguard_navigation.xml
deleted file mode 100644
index 2e6fa37..0000000
--- a/core/res/res/layout-sw600dp/keyguard_navigation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
-*/
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/default_navigation" />
-</merge>
diff --git a/core/res/res/layout-sw600dp/keyguard_sim_puk_pin_navigation.xml b/core/res/res/layout-sw600dp/keyguard_sim_puk_pin_navigation.xml
deleted file mode 100644
index 2e6fa37..0000000
--- a/core/res/res/layout-sw600dp/keyguard_sim_puk_pin_navigation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
-*/
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/default_navigation" />
-</merge>
diff --git a/core/res/res/layout-sw600dp/keyguard_transport_control.xml b/core/res/res/layout-sw600dp/keyguard_transport_control.xml
deleted file mode 100644
index f864339..0000000
--- a/core/res/res/layout-sw600dp/keyguard_transport_control.xml
+++ /dev/null
@@ -1,111 +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.
--->
-
-<!-- *** Note *** This should mirror the file in layout/ with the exception of the background set
-     here for adding a drop shadow on tablets. -->
-
-<com.android.internal.widget.TransportControlView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/transport_controls"
-    android:background="@drawable/transportcontrol_bg">
-
-    <!-- FrameLayout used as scrim to show between album art and buttons -->
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:foreground="@drawable/ic_lockscreen_player_background">
-        <!-- We use ImageView for its cropping features, otherwise could be android:background -->
-        <ImageView
-            android:id="@+id/albumart"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="fill"
-            android:scaleType="centerCrop"
-            android:adjustViewBounds="false"
-        />
-    </FrameLayout>
-
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom">
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dip"
-            android:layout_marginStart="16dip"
-            android:layout_marginEnd="16dip"
-            android:gravity="center_horizontal"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-        />
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layout_marginTop="5dip">
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageView
-                    android:id="@+id/btn_prev"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:src="@drawable/ic_media_previous"
-                    android:clickable="true"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:padding="10dip"
-                    android:contentDescription="@string/lockscreen_transport_prev_description"/>
-            </FrameLayout>
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageView
-                    android:id="@+id/btn_play"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:clickable="true"
-                    android:src="@drawable/ic_media_play"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:padding="10dip"
-                    android:contentDescription="@string/lockscreen_transport_play_description"/>
-            </FrameLayout>
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageView
-                    android:id="@+id/btn_next"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:clickable="true"
-                    android:src="@drawable/ic_media_next"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:padding="10dip"
-                    android:contentDescription="@string/lockscreen_transport_next_description"/>
-            </FrameLayout>
-        </LinearLayout>
-    </LinearLayout>
-
-</com.android.internal.widget.TransportControlView>
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index 4f286780..e495e53 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -28,30 +28,23 @@
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <LinearLayout android:id="@+id/top_action_bar"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
+    <com.android.internal.widget.ActionBarContainer
+        android:id="@+id/action_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?android:attr/actionBarStyle"
+        android:gravity="top">
+        <com.android.internal.widget.ActionBarView
+            android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            style="?android:attr/actionBarStyle"
-            android:gravity="top">
-            <com.android.internal.widget.ActionBarView
-                android:id="@+id/action_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="?android:attr/actionBarStyle" />
-            <com.android.internal.widget.ActionBarContextView
-                android:id="@+id/action_context_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:visibility="gone"
-                style="?android:attr/actionModeStyle" />
-        </com.android.internal.widget.ActionBarContainer>
-        <ImageView android:src="?android:attr/windowContentOverlay"
-                   android:scaleType="fitXY"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content" />
-    </LinearLayout>
+            style="?android:attr/actionBarStyle" />
+        <com.android.internal.widget.ActionBarContextView
+            android:id="@+id/action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?android:attr/actionModeStyle" />
+    </com.android.internal.widget.ActionBarContainer>
 </com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index ccc5b07..fecfded 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -16,33 +16,20 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="wrap_content"
-              android:layout_height="match_parent"
-              android:orientation="horizontal"
-              android:paddingEnd="8dip"
-              android:enabled="false">
-
-    <ImageView android:id="@android:id/up"
-               android:src="?android:attr/homeAsUpIndicator"
-               android:layout_gravity="center_vertical|start"
-               android:visibility="gone"
-               android:layout_width="wrap_content"
-               android:layout_height="wrap_content" />
-
-    <LinearLayout android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:layout_gravity="center_vertical|start"
-                  android:orientation="vertical">
-        <TextView android:id="@+id/action_bar_title"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="end" />
-        <TextView android:id="@+id/action_bar_subtitle"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:layout_marginTop="@dimen/action_bar_subtitle_top_margin"
-                  android:singleLine="true"
-                  android:ellipsize="end"
-                  android:visibility="gone" />
-    </LinearLayout>
+              android:layout_height="wrap_content"
+              android:layout_gravity="center_vertical|start"
+              android:orientation="vertical"
+              android:paddingEnd="8dp">
+    <TextView android:id="@+id/action_bar_title"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:singleLine="true"
+              android:ellipsize="end" />
+    <TextView android:id="@+id/action_bar_subtitle"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_marginTop="@dimen/action_bar_subtitle_top_margin"
+              android:singleLine="true"
+              android:ellipsize="end"
+              android:visibility="gone" />
 </LinearLayout>
diff --git a/core/res/res/layout/keyguard_account_view.xml b/core/res/res/layout/keyguard_account_view.xml
deleted file mode 100644
index fa36371..0000000
--- a/core/res/res/layout/keyguard_account_view.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?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.
-*/
--->
-<com.android.internal.policy.impl.keyguard.KeyguardAccountView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_account_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:orientation="vertical">
-
-    <include layout="@layout/keyguard_message_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-    <RelativeLayout
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1">
-
-        <EditText
-            android:id="@+id/login"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dip"
-            android:layout_marginStart="7dip"
-            android:layout_marginEnd="7dip"
-            android:layout_alignParentTop="true"
-            android:hint="@string/kg_login_username_hint"
-            android:inputType="textEmailAddress"
-            />
-
-        <EditText
-            android:id="@+id/password"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/login"
-            android:layout_toLeftOf="@+id/ok"
-            android:layout_marginTop="15dip"
-            android:layout_marginStart="7dip"
-            android:layout_marginEnd="7dip"
-            android:inputType="textPassword"
-            android:hint="@string/kg_login_password_hint"
-            android:nextFocusRight="@+id/ok"
-            android:nextFocusDown="@+id/ok"
-            />
-
-        <!-- ok below password, aligned to right of screen -->
-        <Button
-            android:id="@+id/ok"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_margin="7dip"
-            android:layout_alignParentEnd="true"
-            android:layout_below="@id/login"
-            android:text="@string/kg_login_submit_button"
-            />
-
-    </RelativeLayout>
-
-    <!--  no room for ECA on this screen right now
-    <include layout="@layout/keyguard_eca"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal" />
-    -->
-
-</com.android.internal.policy.impl.keyguard.KeyguardAccountView>
diff --git a/core/res/res/layout/keyguard_add_widget.xml b/core/res/res/layout/keyguard_add_widget.xml
deleted file mode 100644
index d043fdb..0000000
--- a/core/res/res/layout/keyguard_add_widget.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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_add_widget"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-    <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:contentDescription="@string/keyguard_accessibility_widget_empty_slot"
-            >
-        <ImageView
-            android:id="@+id/keyguard_add_widget_view"
-            android:clickable="true"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:padding="24dp"
-            android:src="@drawable/keyguard_add_widget_button"
-            android:contentDescription="@string/keyguard_accessibility_add_widget"/>
-    </FrameLayout>
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
diff --git a/core/res/res/layout/keyguard_emergency_carrier_area.xml b/core/res/res/layout/keyguard_emergency_carrier_area.xml
deleted file mode 100644
index b8a7654..0000000
--- a/core/res/res/layout/keyguard_emergency_carrier_area.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.internal.policy.impl.keyguard.EmergencyCarrierArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:gravity="center"
-    android:layout_gravity="center_horizontal"
-    android:layout_alignParentBottom="true"
-    android:clickable="true">
-
-    <com.android.internal.policy.impl.keyguard.CarrierText
-        android:id="@+id/carrier_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="@dimen/kg_status_line_font_size"
-        android:textColor="?android:attr/textColorSecondary"/>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="-10dip"
-        style="?android:attr/buttonBarStyle"
-        android:orientation="horizontal"
-        android:gravity="center"
-        android:weightSum="2">
-
-        <com.android.internal.policy.impl.keyguard.EmergencyButton
-            android:id="@+id/emergency_call_button"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
-            android:text="@string/kg_emergency_call_label"
-            style="?android:attr/buttonBarButtonStyle"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="@dimen/kg_status_line_font_size"
-            android:textColor="?android:attr/textColorSecondary"
-            android:drawablePadding="8dip" />
-
-        <Button android:id="@+id/forgot_password_button"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
-            style="?android:attr/buttonBarButtonStyle"
-            android:textSize="@dimen/kg_status_line_font_size"
-            android:textColor="?android:attr/textColorSecondary"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:drawablePadding="8dip"
-            android:visibility="gone"/>
-    </LinearLayout>
-
-</com.android.internal.policy.impl.keyguard.EmergencyCarrierArea>
diff --git a/core/res/res/layout/keyguard_face_unlock_view.xml b/core/res/res/layout/keyguard_face_unlock_view.xml
deleted file mode 100644
index c9f1176..0000000
--- a/core/res/res/layout/keyguard_face_unlock_view.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the screen that allows the user to unlock by showing their face.  -->
-<com.android.internal.policy.impl.keyguard.KeyguardFaceUnlockView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_face_unlock_view"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:contentDescription="@string/keyguard_accessibility_face_unlock">
-
-    <include layout="@layout/keyguard_message_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-
-    <FrameLayout
-       android:id="@+id/keyguard_bouncer_frame"
-       android:background="@*android:drawable/kg_bouncer_bg_white"
-       android:layout_width="match_parent"
-       android:layout_height="0dp"
-       android:layout_weight="1"
-       >
-       <com.android.internal.widget.FaceUnlockView
-           android:id="@+id/face_unlock_area_view"
-           android:layout_width="match_parent"
-           android:layout_height="match_parent"
-           android:layout_gravity="center_horizontal"
-           android:background="@*android:drawable/intro_bg"
-           android:gravity="center">
-
-           <View
-               android:id="@+id/spotlightMask"
-               android:layout_width="match_parent"
-               android:layout_height="match_parent"
-               android:background="@*android:color/facelock_spotlight_mask"
-           />
-
-           <ImageButton
-               android:id="@+id/face_unlock_cancel_button"
-               android:layout_width="wrap_content"
-               android:layout_height="wrap_content"
-               android:padding="5dip"
-               android:layout_alignParentTop="true"
-               android:layout_alignParentEnd="true"
-               android:background="#00000000"
-               android:src="@*android:drawable/ic_facial_backup"
-           />
-       </com.android.internal.widget.FaceUnlockView>
-    </FrameLayout>
-
-    <include layout="@layout/keyguard_eca"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal" />
-</com.android.internal.policy.impl.keyguard.KeyguardFaceUnlockView>
diff --git a/core/res/res/layout/keyguard_glow_pad_container.xml b/core/res/res/layout/keyguard_glow_pad_container.xml
deleted file mode 100644
index d86707f..0000000
--- a/core/res/res/layout/keyguard_glow_pad_container.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
-*/
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/keyguard_glow_pad_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|center_horizontal"
-        android:layout_marginBottom="-60dp"/>
-</merge>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_glow_pad_view.xml b/core/res/res/layout/keyguard_glow_pad_view.xml
deleted file mode 100644
index cfd8160..0000000
--- a/core/res/res/layout/keyguard_glow_pad_view.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.internal.widget.multiwaveview.GlowPadView
-    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/glow_pad_view"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:orientation="horizontal"
-    android:gravity="@integer/kg_selector_gravity"
-    android:contentDescription="@string/keyguard_accessibility_slide_area"
-
-    prvandroid:targetDrawables="@array/lockscreen_targets_unlock_only"
-    prvandroid:targetDescriptions="@array/lockscreen_target_descriptions_unlock_only"
-    prvandroid:directionDescriptions="@*android:array/lockscreen_direction_descriptions"
-    prvandroid:handleDrawable="@*android:drawable/ic_lockscreen_handle"
-    prvandroid:outerRingDrawable="@*android:drawable/ic_lockscreen_outerring"
-    prvandroid:outerRadius="@*android:dimen/glowpadview_target_placement_radius"
-    prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
-    prvandroid:snapMargin="@*android:dimen/glowpadview_snap_margin"
-    prvandroid:firstItemOffset="@integer/kg_glowpad_rotation_offset"
-    prvandroid:magneticTargets="true"
-    prvandroid:feedbackCount="1"
-    prvandroid:vibrationDuration="20"
-    prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
-    prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"
-    prvandroid:allowScaling="true" />
diff --git a/core/res/res/layout/keyguard_message_area.xml b/core/res/res/layout/keyguard_message_area.xml
deleted file mode 100644
index 37463cf..0000000
--- a/core/res/res/layout/keyguard_message_area.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.internal.policy.impl.keyguard.KeyguardMessageArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:id="@+id/keyguard_message_area"
-    android:singleLine="true"
-    android:ellipsize="marquee"
-    android:textAppearance="?android:attr/textAppearance"
-    android:textSize="@dimen/kg_status_line_font_size"
-    android:textColor="?android:attr/textColorSecondary"
-    android:clickable="true" />
-
diff --git a/core/res/res/layout/keyguard_message_area_large.xml b/core/res/res/layout/keyguard_message_area_large.xml
deleted file mode 100644
index 584cec4..0000000
--- a/core/res/res/layout/keyguard_message_area_large.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.internal.policy.impl.keyguard.KeyguardMessageArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:id="@+id/keyguard_message_area"
-    android:maxLines="4"
-    android:textAppearance="?android:attr/textAppearance"
-    android:textSize="@dimen/kg_status_line_font_size"
-    android:textColor="?android:attr/textColorSecondary" />
-
diff --git a/core/res/res/layout/keyguard_multi_user_avatar.xml b/core/res/res/layout/keyguard_multi_user_avatar.xml
deleted file mode 100644
index 2d8f02d..0000000
--- a/core/res/res/layout/keyguard_multi_user_avatar.xml
+++ /dev/null
@@ -1,45 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/keyguard_avatar_size"
-    android:layout_height="@dimen/keyguard_avatar_size"
-    android:background="#00000000"
-    android:gravity="center_horizontal">
-    <ImageView
-        android:id="@+id/keyguard_user_avatar"
-        android:scaleType="center"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"/>
-    <TextView
-       android:id="@+id/keyguard_user_name"
-       android:layout_width="match_parent"
-       android:layout_height="wrap_content"
-       android:layout_gravity="bottom"
-       android:gravity="center"
-       android:textSize="@dimen/keyguard_avatar_name_size"
-       android:textColor="#ffffff"
-       android:singleLine="true"
-       android:ellipsize="end"
-       android:paddingLeft="2dp"
-       android:paddingRight="2dp" />
-</com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar>
diff --git a/core/res/res/layout/keyguard_multi_user_selector.xml b/core/res/res/layout/keyguard_multi_user_selector.xml
deleted file mode 100644
index ee01285..0000000
--- a/core/res/res/layout/keyguard_multi_user_selector.xml
+++ /dev/null
@@ -1,39 +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.
-*/
--->
-<com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    androidprv:layout_childType="userSwitcher"
-    android:id="@+id/keyguard_user_selector"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="bottom"
-    android:contentDescription="@*android:string/keyguard_accessibility_user_selector"
-    android:visibility="gone">
-
-    <com.android.internal.policy.impl.keyguard.KeyguardLinearLayout
-        android:id="@+id/keyguard_users_grid"
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_marginBottom="@dimen/keyguard_muliuser_selector_margin"
-        android:layout_height="@dimen/keyguard_avatar_size"
-        android:layout_gravity="center|bottom" />
-
-</com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView>
diff --git a/core/res/res/layout/keyguard_multi_user_selector_widget.xml b/core/res/res/layout/keyguard_multi_user_selector_widget.xml
deleted file mode 100644
index fc126fe..0000000
--- a/core/res/res/layout/keyguard_multi_user_selector_widget.xml
+++ /dev/null
@@ -1,26 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_multi_user_selector"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_password_view.xml b/core/res/res/layout/keyguard_password_view.xml
deleted file mode 100644
index aab54c3..0000000
--- a/core/res/res/layout/keyguard_password_view.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-<com.android.internal.policy.impl.keyguard.KeyguardPasswordView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_password_view"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="bottom"
-    android:contentDescription="@string/keyguard_accessibility_password_unlock"
-    >
-
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        />
-
-    <include layout="@layout/keyguard_message_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
-
-    <!-- Password entry field -->
-    <!-- Note: the entire container is styled to look like the edit field,
-         since the backspace/IME switcher looks better inside -->
-      <FrameLayout
-         android:id="@+id/keyguard_bouncer_frame"
-         android:background="@*android:drawable/kg_bouncer_bg_white"
-         android:layout_height="wrap_content"
-         android:layout_width="match_parent"
-         >
-         <LinearLayout
-             android:layout_height="wrap_content"
-             android:layout_width="match_parent"
-             android:orientation="horizontal"
-             android:background="#70000000"
-             android:layout_marginTop="8dp"
-             android:layout_marginBottom="8dp"
-             >
-
-             <EditText android:id="@+id/passwordEntry"
-                 android:layout_width="0dip"
-                 android:layout_height="wrap_content"
-                 android:layout_weight="1"
-                 android:gravity="center_horizontal"
-                 android:layout_gravity="center_vertical"
-                 android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-                 android:singleLine="true"
-                 android:textStyle="normal"
-                 android:inputType="textPassword"
-                 android:textSize="36sp"
-                 android:background="@null"
-                 android:textAppearance="?android:attr/textAppearanceMedium"
-                 android:textColor="#ffffffff"
-                 android:imeOptions="flagForceAscii|actionDone"
-                 />
-
-             <ImageView android:id="@+id/switch_ime_button"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:src="@*android:drawable/ic_lockscreen_ime"
-                 android:clickable="true"
-                 android:padding="8dip"
-                 android:layout_gravity="center"
-                 android:background="?android:attr/selectableItemBackground"
-                 android:visibility="gone"
-                 />
-
-            </LinearLayout>
-       </FrameLayout>
-
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        />
-
-    <include layout="@layout/keyguard_eca"
-             android:id="@+id/keyguard_selector_fade_container"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content"
-             android:orientation="vertical"
-             android:layout_gravity="bottom|center_horizontal"
-             android:gravity="center_horizontal" />
-
-</com.android.internal.policy.impl.keyguard.KeyguardPasswordView>
diff --git a/core/res/res/layout/keyguard_pattern_view.xml b/core/res/res/layout/keyguard_pattern_view.xml
deleted file mode 100644
index 1bd3e4e..0000000
--- a/core/res/res/layout/keyguard_pattern_view.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the screen that shows the 9 circle unlock widget and instructs
-     the user how to unlock their device, or make an emergency call.  This
-     is the portrait layout.  -->
-<com.android.internal.policy.impl.keyguard.KeyguardPatternView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_pattern_view"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal"
-    android:contentDescription="@string/keyguard_accessibility_pattern_unlock">
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <LinearLayout
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:orientation="vertical"
-            android:layout_gravity="center">
-
-            <include layout="@layout/keyguard_message_area"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-               />
-
-          <FrameLayout
-             android:id="@+id/keyguard_bouncer_frame"
-             android:background="@*android:drawable/kg_bouncer_bg_white"
-             android:layout_width="match_parent"
-             android:layout_height="0dp"
-             android:layout_weight="1"
-             >
-            <com.android.internal.widget.LockPatternView
-                android:id="@+id/lockPatternView"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:layout_marginEnd="8dip"
-                android:layout_marginBottom="4dip"
-                android:layout_marginStart="8dip"
-                android:layout_gravity="center_horizontal"
-                android:gravity="center"
-                android:contentDescription="@string/keyguard_accessibility_pattern_area" />
-          </FrameLayout>
-          <include layout="@layout/keyguard_eca"
-              android:id="@+id/keyguard_selector_fade_container"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:layout_gravity="bottom|center_horizontal"
-              android:gravity="center_horizontal" />
-        </LinearLayout>
-    </FrameLayout>
-
-</com.android.internal.policy.impl.keyguard.KeyguardPatternView>
diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml
deleted file mode 100644
index 6a3b9e6..0000000
--- a/core/res/res/layout/keyguard_pin_view.xml
+++ /dev/null
@@ -1,224 +0,0 @@
-<?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.
-*/
--->
-
-<com.android.internal.policy.impl.keyguard.KeyguardPINView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_pin_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:orientation="vertical"
-    android:contentDescription="@string/keyguard_accessibility_pin_unlock"
-    >
-    <include layout="@layout/keyguard_message_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-    <LinearLayout
-       android:id="@+id/keyguard_bouncer_frame"
-       android:background="@*android:drawable/kg_bouncer_bg_white"
-       android:layout_width="match_parent"
-       android:layout_height="0dp"
-       android:orientation="vertical"
-       android:layout_weight="1"
-       android:layoutDirection="ltr"
-       >
-       <LinearLayout
-          android:layout_width="match_parent"
-          android:layout_height="0dp"
-          android:orientation="horizontal"
-          android:layout_weight="1"
-          >
-          <TextView android:id="@+id/pinEntry"
-               android:editable="true"
-               android:layout_width="0dip"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:gravity="center"
-               android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-               android:singleLine="true"
-               android:cursorVisible="false"
-               android:background="@null"
-               android:textAppearance="@style/TextAppearance.NumPadKey"
-               android:imeOptions="flagForceAscii|actionDone"
-               />
-           <ImageButton android:id="@+id/delete_button"
-               android:layout_width="wrap_content"
-               android:layout_height="match_parent"
-               android:gravity="center_vertical"
-               android:src="@*android:drawable/ic_input_delete"
-               android:clickable="true"
-               android:paddingTop="8dip"
-               android:paddingBottom="8dip"
-               android:paddingLeft="24dp"
-               android:paddingRight="24dp"
-               android:background="?android:attr/selectableItemBackground"
-               android:contentDescription="@string/keyboardview_keycode_delete"
-               />
-       </LinearLayout>
-       <View
-           android:layout_width="wrap_content"
-           android:layout_height="1dp"
-           android:background="#55FFFFFF"
-           />
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key1"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="1"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key2"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="2"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key3"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="3"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key4"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="4"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key5"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="5"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key6"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="6"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:orientation="horizontal"
-           android:layout_weight="1"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key7"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="7"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key8"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="8"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key9"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="9"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <Space
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key0"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="0"
-               />
-           <ImageButton
-               android:id="@+id/key_enter"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:paddingRight="30dp"
-               android:src="@drawable/sym_keyboard_return_holo"
-               android:contentDescription="@string/keyboardview_keycode_enter"
-               />
-       </LinearLayout>
-    </LinearLayout>
-    <include layout="@layout/keyguard_eca"
-                   android:id="@+id/keyguard_selector_fade_container"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content"
-                   android:orientation="vertical"
-                   android:layout_gravity="bottom|center_horizontal"
-                   android:gravity="center_horizontal" />
-
-</com.android.internal.policy.impl.keyguard.KeyguardPINView>
diff --git a/core/res/res/layout/keyguard_selector_view.xml b/core/res/res/layout/keyguard_selector_view.xml
deleted file mode 100644
index dfacb6a..0000000
--- a/core/res/res/layout/keyguard_selector_view.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.internal.policy.impl.keyguard.KeyguardSelectorView
-    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_selector_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="420dp"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="vertical"
-    android:contentDescription="@string/keyguard_accessibility_slide_unlock">
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:gravity="center">
-
-        <include layout="@layout/keyguard_message_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-        <View
-            android:id="@+id/keyguard_selector_view_frame"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginLeft="16dp"
-            android:layout_marginRight="16dp"
-            android:background="@*android:drawable/kg_bouncer_bg_white"/>
-
-        <include layout="@layout/keyguard_glow_pad_container" />
-
-        <include layout="@layout/keyguard_eca"
-            android:id="@+id/keyguard_selector_fade_container"
-            android:layout_width="match_parent"
-            android:layout_height="48dp"
-            android:layout_gravity="bottom|center_horizontal" />
-    </FrameLayout>
-
-</com.android.internal.policy.impl.keyguard.KeyguardSelectorView>
-
diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml
deleted file mode 100644
index 6e6fe08..0000000
--- a/core/res/res/layout/keyguard_sim_pin_view.xml
+++ /dev/null
@@ -1,230 +0,0 @@
-<?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.
-*/
--->
-<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
-<com.android.internal.policy.impl.keyguard.KeyguardSimPinView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_sim_pin_view"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal">
-
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:src="@drawable/ic_lockscreen_sim"/>
-
-    <include layout="@layout/keyguard_message_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-    <LinearLayout
-       android:id="@+id/keyguard_bouncer_frame"
-       android:background="@*android:drawable/kg_bouncer_bg_white"
-       android:layout_width="match_parent"
-       android:layout_height="0dp"
-       android:orientation="vertical"
-       android:layout_weight="1"
-       android:layoutDirection="ltr"
-       >
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:orientation="horizontal"
-           android:layout_weight="1"
-           >
-           <TextView android:id="@+id/pinEntry"
-               android:editable="true"
-               android:layout_width="0dip"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:gravity="center"
-               android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-               android:singleLine="true"
-               android:cursorVisible="false"
-               android:background="@null"
-               android:textAppearance="@style/TextAppearance.NumPadKey"
-               android:imeOptions="flagForceAscii|actionDone"
-               />
-           <ImageButton android:id="@+id/delete_button"
-               android:layout_width="wrap_content"
-               android:layout_height="match_parent"
-               android:gravity="center_vertical"
-               android:src="@*android:drawable/ic_input_delete"
-               android:clickable="true"
-               android:paddingTop="8dip"
-               android:paddingBottom="8dip"
-               android:paddingLeft="24dp"
-               android:paddingRight="24dp"
-               android:background="?android:attr/selectableItemBackground"
-               android:contentDescription="@string/keyboardview_keycode_delete"
-               />
-       </LinearLayout>
-       <View
-           android:layout_width="wrap_content"
-           android:layout_height="1dp"
-           android:background="#55FFFFFF"
-           />
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key1"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="1"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key2"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="2"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key3"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="3"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key4"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="4"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key5"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="5"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key6"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="6"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:orientation="horizontal"
-           android:layout_weight="1"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key7"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="7"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key8"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="8"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key9"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="9"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <Space
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key0"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="0"
-               />
-           <ImageButton
-               android:id="@+id/key_enter"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:paddingRight="30dp"
-               android:src="@drawable/sym_keyboard_return_holo"
-               android:contentDescription="@string/keyboardview_keycode_enter"
-               />
-       </LinearLayout>
-    </LinearLayout>
-
-    <include layout="@layout/keyguard_eca"
-                   android:id="@+id/keyguard_selector_fade_container"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content"
-                   android:orientation="vertical"
-                   android:layout_gravity="bottom|center_horizontal"
-                   android:gravity="center_horizontal" />
-
-</com.android.internal.policy.impl.keyguard.KeyguardSimPinView>
diff --git a/core/res/res/layout/keyguard_sim_puk_pin_account_navigation.xml b/core/res/res/layout/keyguard_sim_puk_pin_account_navigation.xml
deleted file mode 100644
index 2e6fa37..0000000
--- a/core/res/res/layout/keyguard_sim_puk_pin_account_navigation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
-*/
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/default_navigation" />
-</merge>
diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml
deleted file mode 100644
index 0412fdc..0000000
--- a/core/res/res/layout/keyguard_sim_puk_view.xml
+++ /dev/null
@@ -1,230 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-<!-- This is the SIM PUK view that allows the user to recover their device by entering the
-    carrier-provided PUK code and entering a new SIM PIN for it. -->
-<com.android.internal.policy.impl.keyguard.KeyguardSimPukView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_sim_puk_view"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal">
-
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:src="@drawable/ic_lockscreen_sim"/>
-
-    <include layout="@layout/keyguard_message_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-    <LinearLayout
-       android:id="@+id/keyguard_bouncer_frame"
-       android:background="@*android:drawable/kg_bouncer_bg_white"
-       android:layout_width="match_parent"
-       android:layout_height="0dp"
-       android:orientation="vertical"
-       android:layout_weight="1"
-       android:layoutDirection="ltr"
-       >
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:orientation="horizontal"
-           android:layout_weight="1"
-           >
-           <TextView android:id="@+id/pinEntry"
-               android:editable="true"
-               android:layout_width="0dip"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:gravity="center"
-               android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-               android:singleLine="true"
-               android:cursorVisible="false"
-               android:background="@null"
-               android:textAppearance="@style/TextAppearance.NumPadKey"
-               android:imeOptions="flagForceAscii|actionDone"
-               />
-           <ImageButton android:id="@+id/delete_button"
-               android:layout_width="wrap_content"
-               android:layout_height="match_parent"
-               android:gravity="center_vertical"
-               android:src="@*android:drawable/ic_input_delete"
-               android:clickable="true"
-               android:paddingTop="8dip"
-               android:paddingBottom="8dip"
-               android:paddingLeft="24dp"
-               android:paddingRight="24dp"
-               android:background="?android:attr/selectableItemBackground"
-               android:contentDescription="@string/keyboardview_keycode_delete"
-               />
-       </LinearLayout>
-       <View
-           android:layout_width="wrap_content"
-           android:layout_height="1dp"
-           android:background="#55FFFFFF"
-           />
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key1"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="1"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key2"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="2"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key3"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="3"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key4"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="4"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key5"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="5"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key6"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="6"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:orientation="horizontal"
-           android:layout_weight="1"
-           >
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key7"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="7"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key8"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="8"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key9"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="9"
-               />
-       </LinearLayout>
-       <LinearLayout
-           android:layout_width="match_parent"
-           android:layout_height="0dp"
-           android:layout_weight="1"
-           android:orientation="horizontal"
-           >
-           <Space
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               />
-           <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
-               android:id="@+id/key0"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               androidprv:textView="@+id/pinEntry"
-               androidprv:digit="0"
-               />
-           <ImageButton
-               android:id="@+id/key_enter"
-               style="@style/Widget.Button.NumPadKey"
-               android:layout_width="0px"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:paddingRight="30dp"
-               android:src="@drawable/sym_keyboard_return_holo"
-               android:contentDescription="@string/keyboardview_keycode_enter"
-               />
-       </LinearLayout>
-    </LinearLayout>
-
-    <include layout="@layout/keyguard_eca"
-                   android:id="@+id/keyguard_selector_fade_container"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content"
-                   android:orientation="vertical"
-                   android:layout_gravity="bottom|center_horizontal"
-                   android:gravity="center_horizontal" />
-</com.android.internal.policy.impl.keyguard.KeyguardSimPukView>
diff --git a/core/res/res/layout/keyguard_status_view.xml b/core/res/res/layout/keyguard_status_view.xml
deleted file mode 100644
index 9e36df3..0000000
--- a/core/res/res/layout/keyguard_status_view.xml
+++ /dev/null
@@ -1,67 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_status_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_maxWidth="@dimen/keyguard_security_width"
-    android:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal">
-
-    <com.android.internal.policy.impl.keyguard.KeyguardStatusView
-        android:id="@+id/keyguard_status_view_face_palm"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center_horizontal|top"
-        android:contentDescription="@android:string/keyguard_accessibility_status">
-
-        <LinearLayout android:layout_width="match_parent"
-                      android:layout_height="wrap_content"
-                      android:layout_gravity="center_horizontal|top"
-                      android:orientation="vertical"
-                      android:focusable="true">
-            <com.android.internal.policy.impl.keyguard.ClockView
-                android:id="@+id/clock_view"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
-                android:layout_gravity="right">
-
-                <TextView android:id="@+id/clock_text"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:singleLine="true"
-                          android:ellipsize="none"
-                          android:textSize="@dimen/kg_status_clock_font_size"
-                          android:textAppearance="?android:attr/textAppearanceMedium"
-                          android:textColor="#ffffffff"
-                          android:drawablePadding="2dip"
-                          />
-
-            </com.android.internal.policy.impl.keyguard.ClockView>
-
-            <include layout="@layout/keyguard_status_area" />
-        </LinearLayout>
-
-    </com.android.internal.policy.impl.keyguard.KeyguardStatusView>
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
diff --git a/core/res/res/layout/keyguard_transport_control_view.xml b/core/res/res/layout/keyguard_transport_control_view.xml
deleted file mode 100644
index 532322c..0000000
--- a/core/res/res/layout/keyguard_transport_control_view.xml
+++ /dev/null
@@ -1,112 +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.
--->
-
-<!-- This is a view to control music playback in keyguard. -->
-<com.android.internal.policy.impl.keyguard.KeyguardTransportControlView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center_horizontal"
-    android:id="@+id/keyguard_transport_control">
-
-    <!-- FrameLayout used as scrim to show between album art and buttons -->
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:foreground="@*android:drawable/ic_lockscreen_player_background"
-        android:contentDescription="@*android:string/keygaurd_accessibility_media_controls">
-        <!-- Use ImageView for its cropping features; otherwise could be android:background -->
-        <ImageView
-            android:id="@+id/albumart"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="fill"
-            android:scaleType="centerCrop"
-            android:adjustViewBounds="false"
-        />
-    </FrameLayout>
-
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom">
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dip"
-            android:layout_marginStart="16dip"
-            android:layout_marginEnd="16dip"
-            android:gravity="center_horizontal"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-        />
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layout_marginTop="5dip">
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageView
-                    android:id="@+id/btn_prev"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:src="@*android:drawable/ic_media_previous"
-                    android:clickable="true"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:padding="10dip"
-                    android:contentDescription="@*android:string/lockscreen_transport_prev_description"/>
-            </FrameLayout>
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageView
-                    android:id="@+id/btn_play"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:clickable="true"
-                    android:src="@*android:drawable/ic_media_play"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:padding="10dip"
-                    android:contentDescription="@*android:string/lockscreen_transport_play_description"/>
-            </FrameLayout>
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageView
-                    android:id="@+id/btn_next"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:clickable="true"
-                    android:src="@*android:drawable/ic_media_next"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:padding="10dip"
-                    android:contentDescription="@*android:string/lockscreen_transport_next_description"/>
-            </FrameLayout>
-        </LinearLayout>
-    </LinearLayout>
-
-</com.android.internal.policy.impl.keyguard.KeyguardTransportControlView>
\ No newline at end of file
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 5812053..02cd8cd 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -30,24 +30,19 @@
         android:layout_weight="1">
 
         <LinearLayout
+            style="?attr/preferenceHeaderPanelStyle"
             android:id="@+id/headers"
             android:orientation="vertical"
             android:layout_width="0px"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/preference_screen_side_margin_negative"
-            android:layout_marginStart="@dimen/preference_screen_side_margin"
             android:layout_weight="@integer/preferences_left_pane_weight">
 
             <ListView android:id="@android:id/list"
+                style="?attr/preferenceListStyle"
                 android:layout_width="match_parent"
                 android:layout_height="0px"
                 android:layout_weight="1"
-                android:paddingStart="@dimen/preference_screen_header_padding_side"
-                android:paddingEnd="@dimen/preference_screen_header_padding_side"
-                android:paddingTop="@dimen/preference_screen_header_vertical_padding"
-                android:paddingBottom="@dimen/preference_screen_header_vertical_padding"
                 android:clipToPadding="false"
-                android:scrollbarStyle="@integer/preference_screen_header_scrollbarStyle"
                 android:drawSelectorOnTop="false"
                 android:cacheColorHint="@android:color/transparent"
                 android:listPreferredItemHeight="48dp"
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index abfb1f2..4e895b0 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -25,13 +25,12 @@
     android:layout_removeBorders="true">
 
     <ListView android:id="@android:id/list"
+        style="?attr/preferenceFragmentListStyle"
         android:layout_width="match_parent"
         android:layout_height="0px"
         android:layout_weight="1"
         android:paddingTop="0dip"
         android:paddingBottom="@dimen/preference_fragment_padding_bottom"
-        android:paddingStart="@dimen/preference_fragment_padding_side"
-        android:paddingEnd="@dimen/preference_fragment_padding_side"
         android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
         android:clipToPadding="false"
         android:drawSelectorOnTop="false"
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 61cecae..281541b 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -18,40 +18,40 @@
 */
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:gravity="center"
-              android:orientation="vertical"
+              android:orientation="horizontal"
               android:layout_height="wrap_content"
               android:layout_width="match_parent"
-              android:background="@android:drawable/activity_picker_bg"
-              android:padding="16dp">
-
-    <!-- Extended activity info to distinguish between duplicate activity names -->
-    <TextView android:id="@android:id/text2"
-              android:textAppearance="?android:attr/textAppearance"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:gravity="center"
-              android:minLines="2"
-              android:maxLines="2"
-              android:paddingStart="4dip"
-              android:paddingEnd="4dip" />
+              android:background="?attr/activatedBackgroundIndicator">
 
     <!-- Activity icon when presenting dialog
          Size will be filled in by ResolverActivity -->
     <ImageView android:id="@+id/icon"
                android:layout_width="0dp"
                android:layout_height="0dp"
+               android:layout_marginStart="12dp"
+               android:padding="4dp"
                android:scaleType="fitCenter" />
 
-    <!-- Activity name -->
-    <TextView android:id="@android:id/text1"
-              android:textAppearance="?android:attr/textAppearanceSmall"
-              android:layout_width="wrap_content"
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:gravity="start|center_vertical"
+              android:orientation="vertical"
               android:layout_height="wrap_content"
-              android:gravity="center"
-              android:minLines="2"
-              android:maxLines="2"
-              android:paddingStart="4dip"
-              android:paddingEnd="4dip" />
+              android:layout_width="wrap_content"
+              android:layout_gravity="start|center_vertical"
+              android:layout_marginStart="12dp">
+        <!-- Activity name -->
+        <TextView android:id="@android:id/text1"
+                  android:textAppearance="?android:attr/textAppearanceMedium"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:maxLines="2" />
+        <!-- Extended activity info to distinguish between duplicate activity names -->
+        <TextView android:id="@android:id/text2"
+                  android:textAppearance="?android:attr/textAppearanceSmall"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:maxLines="2"
+                  android:paddingTop="4dip" />
+    </LinearLayout>
 </LinearLayout>
 
diff --git a/core/res/res/layout/resolver_grid.xml b/core/res/res/layout/resolver_grid.xml
deleted file mode 100644
index d271c1a..0000000
--- a/core/res/res/layout/resolver_grid.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?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.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical"
-              android:divider="?android:attr/dividerHorizontal"
-              android:showDividers="middle"
-              android:dividerPadding="0dip">
-    <FrameLayout android:layout_width="match_parent"
-                 android:layout_height="wrap_content"
-                 android:layout_weight="1">
-        <GridView
-            android:layout_gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:id="@+id/resolver_grid"
-            android:numColumns="4"
-            android:columnWidth="128dp"
-            android:padding="16dp"
-            android:clipToPadding="false"
-            android:scrollbarStyle="outsideOverlay" />
-    </FrameLayout>
-    <LinearLayout
-        android:id="@+id/button_bar"
-        android:visibility="gone"
-        style="?android:attr/buttonBarStyle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:layoutDirection="locale"
-        android:measureWithLargestChild="true">
-        <Button android:id="@+id/button_always"
-                android:layout_width="wrap_content"
-                android:layout_gravity="end"
-                android:layout_weight="1"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:layout_height="wrap_content"
-                android:enabled="false"
-                android:text="@string/activity_resolver_use_always"
-                android:onClick="onButtonClick" />
-        <Button android:id="@+id/button_once"
-                android:layout_width="wrap_content"
-                android:layout_gravity="start"
-                android:layout_weight="1"
-                android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content"
-                android:enabled="false"
-                android:text="@string/activity_resolver_use_once"
-                android:onClick="onButtonClick" />
-    </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
new file mode 100644
index 0000000..f88ced1
--- /dev/null
+++ b/core/res/res/layout/resolver_list.xml
@@ -0,0 +1,72 @@
+<?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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical"
+              android:divider="?android:attr/dividerHorizontal"
+              android:showDividers="middle"
+              android:dividerPadding="0dip">
+
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_weight="1">
+
+        <ListView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/resolver_list" />
+
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/button_bar"
+        android:visibility="gone"
+        style="?android:attr/buttonBarStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layoutDirection="locale"
+        android:measureWithLargestChild="true">
+        <Button android:id="@+id/button_always"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content"
+                android:enabled="false"
+                android:text="@string/activity_resolver_use_always"
+                android:onClick="onButtonClick" />
+        <Button android:id="@+id/button_once"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content"
+                android:enabled="false"
+                android:text="@string/activity_resolver_use_once"
+                android:onClick="onButtonClick" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/restrictions_pin_challenge.xml b/core/res/res/layout/restrictions_pin_challenge.xml
new file mode 100644
index 0000000..f41924c
--- /dev/null
+++ b/core/res/res/layout/restrictions_pin_challenge.xml
@@ -0,0 +1,90 @@
+<?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.
+-->
+
+<!-- Layout used as the dialog's content View for EditTextPreference. -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:overScrollMode="ifContentScrolls">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="8dip"
+            android:orientation="vertical">
+
+            <EditText android:id="@+id/pin_text"
+                android:layout_marginLeft="8dip"
+                android:layout_marginStart="8dip"
+                android:layout_marginRight="8dip"
+                android:layout_marginEnd="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:inputType="numberPassword"
+                android:textColor="?android:attr/textColorPrimary" />
+
+            <TextView android:id="@+id/pin_error_message"
+                android:layout_marginTop="8dp"
+                android:layout_marginBottom="8dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/restr_pin_incorrect"
+                android:gravity="center"/>
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/buttonPanel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minHeight="@dimen/alert_dialog_button_bar_height"
+            android:orientation="vertical"
+            android:divider="?android:attr/dividerHorizontal"
+            android:showDividers="beginning"
+            android:dividerPadding="0dip">
+            <LinearLayout
+                style="?android:attr/buttonBarStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:layoutDirection="locale"
+                android:measureWithLargestChild="true">
+                <Button android:id="@+id/pin_cancel_button"
+                    android:layout_width="wrap_content"
+                    android:layout_gravity="start"
+                    android:layout_weight="1"
+                    android:maxLines="2"
+                    android:minHeight="@dimen/alert_dialog_button_bar_height"
+                    style="?android:attr/buttonBarButtonStyle"
+                    android:textSize="14sp"
+                    android:layout_height="wrap_content"
+                    android:text="@string/cancel" />
+                <Button android:id="@+id/pin_ok_button"
+                    android:layout_width="wrap_content"
+                    android:layout_gravity="end"
+                    android:layout_weight="1"
+                    android:maxLines="2"
+                    style="?android:attr/buttonBarButtonStyle"
+                    android:textSize="14sp"
+                    android:minHeight="@dimen/alert_dialog_button_bar_height"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ok" />
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
diff --git a/core/res/res/layout/restrictions_pin_setup.xml b/core/res/res/layout/restrictions_pin_setup.xml
new file mode 100644
index 0000000..03ed696
--- /dev/null
+++ b/core/res/res/layout/restrictions_pin_setup.xml
@@ -0,0 +1,77 @@
+<?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.
+-->
+
+<!-- Layout used as the dialog's content View for EditTextPreference. -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginTop="48dp"
+    android:layout_marginBottom="48dp"
+    android:overScrollMode="ifContentScrolls">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="8dip"
+        android:orientation="vertical">
+
+        <TextView android:id="@+id/pin_message"
+            style="?android:attr/textAppearanceMedium"
+            android:layout_marginTop="16dp"
+            android:layout_marginBottom="16dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/restr_pin_create_pin"
+            android:textColor="?android:attr/textColorSecondary" />
+
+        <EditText android:id="@+id/pin_text"
+            style="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="16dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="@string/restr_pin_enter_old_pin"
+            android:inputType="numberPassword"
+            android:textColor="?android:attr/textColorPrimary" />
+
+        <EditText android:id="@+id/pin_new_text"
+            style="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="16dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="@string/restr_pin_enter_new_pin"
+            android:inputType="numberPassword"
+            android:textColor="?android:attr/textColorPrimary" />
+
+        <EditText android:id="@+id/pin_confirm_text"
+            style="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="16dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="@string/restr_pin_confirm_pin"
+            android:inputType="numberPassword"
+            android:textColor="?android:attr/textColorPrimary" />
+
+        <TextView android:id="@+id/pin_error_message"
+            style="?android:attr/textAppearanceSmall"
+            android:layout_marginBottom="16dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/restr_pin_error_doesnt_match"
+            android:textColor="#FFFF0000" />
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index e310bf5..b1889a2 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -25,34 +25,27 @@
     android:layout_height="match_parent"
     android:splitMotionEvents="false">
     <FrameLayout android:id="@android:id/content"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent" />
+    <com.android.internal.widget.ActionBarContainer
+        android:id="@+id/action_bar_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-    <LinearLayout android:id="@+id/top_action_bar"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?android:attr/actionBarStyle"
+        android:gravity="top">
+        <com.android.internal.widget.ActionBarView
+            android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            style="?android:attr/actionBarStyle"
-            android:gravity="top">
-            <com.android.internal.widget.ActionBarView
-                android:id="@+id/action_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="?android:attr/actionBarStyle" />
-            <com.android.internal.widget.ActionBarContextView
-                android:id="@+id/action_context_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:visibility="gone"
-                style="?android:attr/actionModeStyle" />
-        </com.android.internal.widget.ActionBarContainer>
-        <ImageView android:src="?android:attr/windowContentOverlay"
-                   android:scaleType="fitXY"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content" />
-    </LinearLayout>
+            style="?android:attr/actionBarStyle" />
+        <com.android.internal.widget.ActionBarContextView
+            android:id="@+id/action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?android:attr/actionModeStyle" />
+    </com.android.internal.widget.ActionBarContainer>
     <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml
index 8c6c9d3..63c542b 100644
--- a/core/res/res/layout/simple_list_item_2.xml
+++ b/core/res/res/layout/simple_list_item_2.xml
@@ -19,12 +19,13 @@
     android:layout_height="wrap_content"
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:mode="twoLine"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
 >
     
 	<TextView android:id="@android:id/text1"
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
-    android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
     android:layout_marginTop="8dip"
 		android:textAppearance="?android:attr/textAppearanceListItem"
 	/>
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index a78cd85..4fa94f3 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -20,6 +20,7 @@
 <!-- Layout of time picker-->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/timePickerLayout"
     android:orientation="horizontal"
     android:layout_gravity="center_horizontal"
     android:layout_width="wrap_content"
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index 7d8900e..c6b7d3a 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -20,14 +20,19 @@
 <!-- Layout of time picker -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/timePickerLayout"
     android:orientation="horizontal"
     android:layout_gravity="center_horizontal"
     android:layout_width="wrap_content"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:paddingStart="8dip"
+    android:paddingEnd="8dip">
 
     <LinearLayout android:orientation="horizontal"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingStart="8dip"
+        android:paddingEnd="8dip"
         android:layoutDirection="ltr">
 
         <!-- hour -->
@@ -37,8 +42,6 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="16dip"
             android:layout_marginBottom="16dip"
-            android:layout_marginStart="16dip"
-            android:layout_marginEnd="6dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -48,6 +51,8 @@
             android:id="@+id/divider"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="6dip"
+            android:layout_marginEnd="6dip"
             android:layout_gravity="center_vertical"
             android:importantForAccessibility="no"
             />
@@ -59,8 +64,6 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="16dip"
             android:layout_marginBottom="16dip"
-            android:layout_marginStart="6dip"
-            android:layout_marginEnd="8dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -75,7 +78,7 @@
         android:layout_marginTop="16dip"
         android:layout_marginBottom="16dip"
         android:layout_marginStart="8dip"
-        android:layout_marginEnd="16dip"
+        android:layout_marginEnd="8dip"
         android:focusable="true"
         android:focusableInTouchMode="true"
         />
diff --git a/core/res/res/layout/toast_bar.xml b/core/res/res/layout/toast_bar.xml
new file mode 100644
index 0000000..a31d7cb
--- /dev/null
+++ b/core/res/res/layout/toast_bar.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:background="@drawable/toast_bar_bg"
+        android:layout_height="50dp"
+        android:layout_width="match_parent">
+
+        <TextView
+            android:id="@android:id/message"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:gravity="center_vertical"
+            android:paddingLeft="16dp"
+            android:paddingRight="16dp"
+            android:singleLine="true"
+            android:textColor="@android:color/white"
+            android:textSize="14sp" />
+
+        <LinearLayout
+            android:id="@android:id/button1"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:background="?android:attr/selectableItemBackground"
+            android:clickable="true">
+
+            <View
+                android:layout_width="1dp"
+                android:layout_height="match_parent"
+                android:layout_marginBottom="10dp"
+                android:layout_marginRight="12dp"
+                android:layout_marginTop="10dp"
+                android:background="#aaaaaa" />
+
+            <TextView
+                android:id="@android:id/text1"
+                android:textSize="12sp"
+                android:textColor="#aaaaaa"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:paddingLeft="8dp"
+                android:paddingRight="20dp"
+                android:textAllCaps="true" />
+        </LinearLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/core/res/res/layout/transient_notification.xml b/core/res/res/layout/transient_notification.xml
index 5523807..daa9faf 100644
--- a/core/res/res/layout/transient_notification.xml
+++ b/core/res/res/layout/transient_notification.xml
@@ -30,7 +30,7 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_gravity="center_horizontal"
-        android:textAppearance="@style/TextAppearance.Small"
+        android:textAppearance="@style/TextAppearance.Toast"
         android:textColor="@color/bright_foreground_dark"
         android:shadowColor="#BB000000"
         android:shadowRadius="2.75"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 405a978..980ae05 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Laat die program toe om take na die voorgrond of agtergrond te skuif. Die program kan dit moontlik sonder jou insette doen."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stop lopende programme"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Laat die program toe om take te verwyder en hul programme te dood. Kwaadwillige programme kan die gedrag van ander programme ontwrig."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"bestuur aktiwiteitstapels"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Laat die program toe om by te voeg by die aktiwiteitstapels waarbinne ander programme loop, of dit te verwyder of te wysig. Kwaadwillige programme kan dalk die gedrag van ander programme ontwrig."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"begin enige aktiwiteit"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Laat die program toe om \'n aktiwiteit te begin, ongeag toestemming-beskerming of uitgevoerde status."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"stel skermversoenbaarheid"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n invoermetode te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"verbind aan \'n toeganklikheidsdiens"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Dit laat die houer toe om aan die top-koppelvlak van \'n toeganklikheidsdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"verbind aan \'n drukdiens"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Laat die houer toe om aan die top-koppelvlak van \'n drukdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"kry toegang tot alle druktake"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Gee die houer toegang tot druktake wat deur \'n ander program geskep is. Behoort nooit vir normale programme nodig te wees nie."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind aan \'n teksdiens"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n teksdiens (bv SpellCheckerService) te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind aan \'n VPN-diens"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"voeg \'n toesteladministrateur by of verwyder een"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Laat die houer aktiewe toesteladministrateurs byvoeg of verwyder. Behoort nooit nodig te wees vir normale programme nie."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"verander skermoriëntasie"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Laat die program toe om die skerm se rotasie te eniger tyd te verander. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"verander wyserspoed"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Laat die program toe om SurfaceFlinger se laevlak-kenmerke te gebruik."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lees raambuffer"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Laat die program toe om die inhoud van die raambuffer te lees."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"kry toegang tot InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Laat die program toe om InputFlinger se laevlak-kenmerke te gebruik."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"stel Wi-Fi-skerms op"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Laat die program toe om Wi-Fi-skerms op te stel en daaraan te koppel."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"beheer Wi-Fi-skerms"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Laat die program toe om laevlak-kenmerke van Wi-Fi-skerms te beheer."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"verander jou klankinstellings"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Laat die program toe om globale klankinstellings soos volume en watter luidspreker vir uitvoer gebruik word, te verander."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"neem klank op"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Laat die program toe om na die SD-kaart te skryf."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"verander/vee uit interne mediabergingsinhoud"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Laat die program toe om die inhoud van die interne mediaberging te verander."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"bestuur dokumentberging"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Laat die program toe om dokumentberging te bestuur."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"verkry toegang tot alle gebruikers se eksterne berging"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Laat die program toe om toegang tot eksterne berging vir alle gebruikers te verkry."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"lees die kaslêerstelsel"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Laat die program toe om netwerkbeleide te bestuur en program-spesifieke reëls te definieer."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verander verrekening van netwerkgebruik"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"wysig sokmerke"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Laat die program toe om sokmerke vir roetering te wysig"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"kry toegang tot kennisgewings"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Laat die houer toe om aan die top-koppelvlak van \'n kennisgewingluisteraardiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"roep die opstellingprogram op wat deur die diensverskaffer voorsien is"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die diensverskaffer voorsien word, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Steek \'n SIM-kaart in."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Die SIM-kaart is weg of nie leesbaar nie. Steek \'n SIM-kaart in."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Onbruikbare SIM-kaart."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Jou SIM-kaart is permanent gedeaktiveer."\n" Kontak jou draadlose diensverskaffer vir \'n ander SIM-kaart."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Jou SIM-kaart is permanent gedeaktiveer.\n Kontak jou draadlose diensverskaffer vir \'n ander SIM-kaart."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Vorigesnit-knoppie"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Volgendesnit-knoppie"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Laatwag-knoppie"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Sien die handleiding of kontak kliëntediens."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kaart is gesluit."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Ontsluit tans SIM-kaart…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd geteken. "\n\n"Probeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Jy het jou wagwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingevoer. "\n\n"Probeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Jy het jou wagwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingevoer. "\n\n"Probeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd geteken. Na <xliff:g id="NUMBER_1">%d</xliff:g> nóg onsuksesvolle pogings sal jy gevra word om jou tablet te ontsluit met gebruik van jou Google-aanmelddetails."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou foon te ontsluit met gebruik van jou Google-aanmelddetails."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Jy het jou wagwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingevoer. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Jy het jou wagwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingevoer. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd geteken. Na <xliff:g id="NUMBER_1">%d</xliff:g> nóg onsuksesvolle pogings sal jy gevra word om jou tablet te ontsluit met gebruik van jou Google-aanmelddetails.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou foon te ontsluit met gebruik van jou Google-aanmelddetails.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer probeer om die tablet verkeerde te ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle poging, sal die tablet terug gestel word nia die fabrieksverstek en alle gebruikerdata sal verlore wees."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer probeer om die foon verkeerde te ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle poging sal die foon terug gestel word na die fabrieksverstek en alle gebruikerdata sal verlore wees."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die tablet sal nou terug gestel word na die fabrieksverstek."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wagwoord"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Meld aan"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ongeldige gebruikernaam of wagwoord."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Jou gebruikernaam of wagwoord vergeet?"\n"Besoek "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Jou gebruikernaam of wagwoord vergeet?\nBesoek "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontroleer tans..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Ontsluit"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Klank aan"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Bevestig navigasie"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Verlaat hierdie bladsy"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bly op hierdie bladsy"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Is jy seker dat jy weg van hierdie bladsy af wil navigeer?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nIs jy seker dat jy weg van hierdie bladsy af wil navigeer?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bevestig"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Wenk: Dubbeltik om in en uit te zoem."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Outovul"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Ongelukkig het <xliff:g id="APPLICATION">%1$s</xliff:g> gestop."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Ongelukkig het die proses <xliff:g id="PROCESS">%1$s</xliff:g> gestop."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reageer nie."\n\n"Wil jy dit sluit?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiwiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> reageer nie."\n\n"Wil jy dit afsluit?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reageer nie.\n\nWil jy dit sluit?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiwiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> reageer nie.\n\nWil jy dit afsluit?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reageer nie. Wil jy dit sluit?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> reageer nie."\n\n"Wil jy dit afsluit?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> reageer nie.\n\nWil jy dit afsluit?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Verslag"</string>
     <string name="wait" msgid="7147118217226317732">"Wag"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die bladsy reageer nie meer nie."\n\n"Wil jy dit toemaak?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die bladsy reageer nie meer nie.\n\nWil jy dit toemaak?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Program herlei"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop nou."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> is oorspronklik laat loop."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Laat die program toe om die verstek houerdiens in te roep om inhoud te kopieer. Nie vir gebruik deur normale programme nie."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Roeteer media-uitvoer"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Laat \'n program toe om media-uitvoere na ander eksterne toestelle te roeteer."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Kry toegang tot keyguard se veilige berging"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Laat \'n program toe om toegang tot keyguard se veilige berging te kry."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Beheer wys en versteek van keyguard"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Laat \'n program toe om keyguard te beheer."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Raak twee keer vir zoembeheer"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Kon nie legstuk byvoeg nie."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Gaan"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Klaar"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Vorige"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Voer uit"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Skakel nommer"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Skep kontak"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Skakel nommer\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Skep kontak\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Die volgende een of meer programme versoek toestemming om jou rekening gebruik (nou én in die toekoms)."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Wil jy hierdie versoek toestaan?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Toegangsversoek"</string>
     <string name="allow" msgid="7225948811296386551">"Laat toe"</string>
     <string name="deny" msgid="2081879885755434506">"Weier"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Toestemming versoek"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Toestemming versoek"\n"vir rekening <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Toestemming versoek\nvir rekening <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Invoermetode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinkroniseer"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Toeganklikheid"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Koppel tans..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Beskikbaar"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nie beskikbaar nie"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"In gebruik"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ingeboude skerm"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skerm"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Oorlegger #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", veilig"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Draadlose skerm is gekoppel"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Hierdie skerm word op \'n ander toestel gewys"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Ontkoppel"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Verkeerde patroon"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Verkeerde wagwoord"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Verkeerde PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer weer oor <xliff:g id="NUMBER">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer weer oor <xliff:g id="NUMBER">%1$d</xliff:g> sekondes."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken jou patroon"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Voer SIM-PIN in"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Voer PIN in"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Wagwoord"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Meld aan"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikernaam of wagwoord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Het jy jou gebruikernaam of wagwoord vergeet?"\n"Besoek "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Het jy jou gebruikernaam of wagwoord vergeet?\nBesoek "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontroleer tans rekening..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. "\n\n"Probeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. "\n\n"Probeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. "\n\n"Probeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik gepoog om die tablet te ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal die tablet na die fabrieksverstek teruggestel word en al die gebruikerdata sal verlore wees."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik gepoog om die foon te ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal die foon na die fabrieksverstek teruggestel word en al die gebruikerdata sal verlore wees."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Jy het <xliff:g id="NUMBER">%d</xliff:g> keer verkeerdelik gepoog om die tablet te ontsluit. Die tablet sal nou na fabrieksverstek teruggestel word."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Jy het <xliff:g id="NUMBER">%d</xliff:g> keer verkeerdelik gepoog om die foon te ontsluit. Die foon sal nou na fabrieksverstek teruggestel word."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwyder"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Verhoog volume bo aanbevole vlak?"\n"Deur vir lang tydperke teen hoë volume te luister, kan jou gehoor beskadig word."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Verhoog volume bo aanbevole vlak?\nDeur vir lang tydperke teen hoë volume te luister, kan jou gehoor beskadig word."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou aan met twee vingers inhou om toeganklikheid te aktiveer."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Toeganklikheid geaktiveer."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toeganklikheid gekanselleer."</string>
     <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
     <string name="owner_name" msgid="2716755460376028154">"Eienaar"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Hierdie program werk nie met rekeninge vir beperkte profiele nie"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Hierdie program werk nie met rekeninge vir beperkte profiele nie"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Geen program gevind om hierdie handeling te hanteer nie"</string>
     <string name="revoke" msgid="5404479185228271586">"Herroep"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Gekanselleer"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Kon nie inhoud skryf nie"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Voer PIN in"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Huidige PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nuwe PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Bevestig nuwe PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Skep \'n PIN vir wysigingbeperkings"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'e kom nie ooreen nie. Probeer weer."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is te kort. Moet ten minste 4 syfers wees."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Verkeerde PIN. Probeer weer oor 1 sekonde."</item>
+    <item quantity="other" msgid="8030607343223287654">"Verkeerde PIN. Probeer weer oor <xliff:g id="COUNT">%d</xliff:g> sekondes."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c84c0e2..0683c06 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"መተግበሪያው ተግባሮችን ወደ ቅድመ ገጹ እና ወደ ዳራው እንዲያንቀሳቅስ ይፈቅድለታል። መተግበሪያው ይህንን ያላንተ ግብዓት ሊያደርግ ይችላል።"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"የእንቅስቃሴ ቁልሎችን ማቀናበር"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"መተግበሪያው ሌሎች መተግበሪያዎች በሚያሄዱበት የእንቅስቃሴዎች ቁልሎችን እንዲያክል፣ እንዲያስወግድ እና እንዲቀይር ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች የሌሎች መተግበሪያዎች ባህሪን ሊበጠብጡ ይችላሉ።"</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"ማንኛውም እንቅስቃሴ ጀምር"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"መተግበሪያው ማንኛውም እንቅስቃሴ፣ የፍቃድ ጥበቃም ሆነ ወደ ውጭ የተላከበት ሁኔታ ሳይታይ፣ እንዲጀምር ይፈቅድለታል።"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"የማያ ገጽ ተኳኋኝነት መድብ"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ በይነገጽ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ከአንድ የተደራሽነት አገልግሎት ጋር እሰር"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ያዢው ወደ የአንድ ተደራሽነት አገልግሎት ከፍተኛ-ደረጃ በይነገጽ እንዲያስር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች መቼም ቢሆን ሊያስፈልግ አይገባም።"</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"ከአንድ የህትመት አገልግሎት ጋር ማያያዝ"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ያዢው የህትመት አገልግሎቱን ወደ ከፍተኛ-ደረጃ በይነገጽ እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"ሁሉንም የህትመት ስራዎችን መድረስ"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"ያዢው በሌላ መተግበሪያ የተፈጠሩ የህትመት ስራዎች እንዲደርስባቸው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"ከNFC አገልግሎት ጋር ይሰሩ"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"ያዢው የNFC ካርዶችን የሚያስመስሉ መተግበሪያዎችን እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"ለፅሁፍ አገልግሎት አሰረ"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"ያዡ ግቤት ለከፍተኛ-ደረጃ የፅሁፍ አገልግሎት ገፅታ ለመጠረዝ ይፈቅዳል። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"ለVPN አገልግሎት ተገዛ"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ  ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"የመሣሪያ አስተዳዳሪ ያክሉ ወይም ያስወግዱ"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ያዢው ንቁ የመሣሪያ አስተዳዳሪዎች እንዲያክል ወይም እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች ጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"የማያ ገፀ አቀማመጥን ለውጥ"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"በማንኛውም ጊዜ  የማሳያውን መሽከርከር ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"የጠቋሚ ፍጥነት ለውጥ"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"መተግበሪያውን የSurfaceFlinger ዝቅተኛ ደረጃ ባህሪያትን ለመጠቀም ይፈቅዳል።"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"የንዑስ ክፈፍ ቋት አንብብ"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"የክፈፍ ቋት ይዘት ለማንበብ ለመተግበሪያው ይፈቅዳሉ።"</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger ን መድረስ"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"መተግበሪያው ባለአነስተኛ የInputFlinger ባህሪያት እንዲጠቀም ይፈቅድለታል።"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"የWifi ማሳያዎችን አዋቅር"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"መተግበሪያው የWifi ማሳያዎችን እንዲያዋቅርና ከእነሱ ጋር እንዲገናኝ ይፈቅድለታል።"</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"የWifi ማሳያዎችን ተቆጣጠር"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"መተግበሪያው በዝቅተኛ ደረጃ ላይ ያሉ የWifi ማሳያዎችን እንዲቆጣጠር ይፈቅድለታል።"</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"የድምፅ ቅንብሮችን ለውጥ"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"መተግበሪያው አንደ የድምጽ መጠን እና ለውጽአት የትኛውን የድምጽ ማጉያ ጥቅም ላይ እንደዋለ የመሳሰሉ ሁለንተናዊ የድምጽ ቅንብሮችን እንዲያስተካክል ይፈቅድለታል።"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ኦዲዮ ቅዳ"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"መተግበሪያውን ወደ SD ካርድ ለመፃፍ ይፈቅዳል።"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"የውስጥ ማህደረ መረጃ ማከማቻ ይዘቶችን ቀይር/ሰርዝ"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"የውስጥ ማህደረ መረጃ ማከማቻ ይዘትን ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"የሰነድ ማከማቻን ያስተዳድሩ"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"መተግበሪያው የሰነድ ማከማቻን እንዲያስተዳድር ይፈቅድለታል።"</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"የሁሉም ተጠቃሚዎች ውጫዊ ማከማቻውን ይደርስበታል"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"መተግበሪያውን የሁሉም ተጠቃሚዎች ውጫዊ ማከማቻውን እንዲደርስ ይፈቅድለታል።"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"የመሸጎጫ ስርዓተ ፋይል ድረስ"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"የአውታረመረብ ቋሚ መመሪያዎችን እና ትግበራ ተኮር ደንቦችን ለማደራጀት ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"የአውታረ መረብ አጠቃቀም"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ከመተግበሪያዎች በተለየ መልኩ እንዴት የአውታረ መረብ አጠቃቀም እንደተመዘገበ ለመቀየር ለመተግበሪያው ይፈቅዳሉ።ለመደበኛ መተግበሪያዎች አገልግሎት አይውልም።"</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"የሶኬት ምልክቶችን መቀየር"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"መተግበሪያው መንገድ እንዲፈልግ የሶኬት ምልክቶቹን እንዲቀይር ያስችለዋል"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"ማሳወቂያዎችን ይድረሱ"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"ሲም ካርድ አስገባ፡፡"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM ካርዱ ጠፍቷል ወይም መነበብ አይችልም።እባክህ SIM ካርድ አስገባ።"</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"የማይሰራ ሲም ካርድ።"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM ካርድህ በቋሚነት ቦዝኗል።"\n"  ለሌላ SIM ካርድ  የገመድ አልባ አገልግሎት አቅራቢህ ጋር ተገናኝ።"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM ካርድህ በቋሚነት ቦዝኗል።\n  ለሌላ SIM ካርድ  የገመድ አልባ አገልግሎት አቅራቢህ ጋር ተገናኝ።"</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"የቀድሞ ዝርዝር አዝራር"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"ቀጣይ ዝርዝር አዝራር"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"ለአፍታ አቁም አዝራር"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"እባክህ የተጠቃሚ መመሪያን ተመልከት ወይም የደንበኞች አገልግሎትአግኝ።"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM ካርድ ተዘግቷል።"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"የSIM  ካርድ በመክፈት ላይ..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g>ጊዜ በስህተት ስለውታል።"\n\n"እባክህ እንደገና ከ<xliff:g id="NUMBER_1">%d</xliff:g>ሰከንዶች በኋላ ሞክር።"</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%d</xliff:g>ጊዚያቶች የይለፍ ቃልህን በስህተት ተይበኻል፡፡በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ "\n\n"እንደገና ሞክር፡፡"</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%d</xliff:g>ጊዚያቶች ፒንህን በስህተት ተይበኻል፡፡በ"\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g>ጊዜ በስህተት ስለውታል።\n\nእባክህ እንደገና ከ<xliff:g id="NUMBER_1">%d</xliff:g>ሰከንዶች በኋላ ሞክር።"</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%d</xliff:g>ጊዚያቶች የይለፍ ቃልህን በስህተት ተይበኻል፡፡በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ \n\nእንደገና ሞክር፡፡"</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%d</xliff:g>ጊዚያቶች ፒንህን በስህተት ተይበኻል፡፡በ\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">"ይህን tablet <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ያህል በስህተት ለማስከፈት ሞክረሃል፡፡ ከ <xliff:g id="NUMBER_1">%d</xliff:g> በላይ ያልተሳኩ ሙከራዎች በኋላ፣ ይህ tablet አሁን በፋብሪካ ነባሪ ቅንጅት ዳግም ይቀናበርና ሁሉም የተጠቃሚው ውሂብ ይጠፋል፡፡"</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">"ይህን tablet <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ያህል በስህተት ለማስከፈት ሞክረሃል፡፡ ይህ tablet አሁን በፋብሪካ ነባሪ ቅንጅት ዳግም ይቀናበራል፡፡"</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"የይለፍ ቃል"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ግባ"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ትክክል ያልሆነየተጠቃሚ ሰም ወይም ይለፍቃል።"</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"የተጠቃሚ ስምህን እና የይለፍ ቃልህን ረሳህ?"\n<b>"google.com/accounts/recovery"</b>"ጎብኝ።"</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"የተጠቃሚ ስምህን እና የይለፍ ቃልህን ረሳህ?\n"<b>"google.com/accounts/recovery"</b>"ጎብኝ።"</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"በማረጋገጥ ላይ..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"ክፈት"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ድምፅ አብራ"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"አሰሳን አረጋግጥ"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"ከዚህ ገጽ ውጣ"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"እዚህ ገፅ ላይ ቆይ"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"እርግጠኛ ነዎት ከዚህ ገጽ ወደ ሌላ ቦታ መሄድ ይፈልጋሉ?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nእርግጠኛ ነዎት ከዚህ ገጽ ወደ ሌላ ቦታ መሄድ ይፈልጋሉ?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"አረጋግጥ"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"ጠቃሚ ምክር፦ ለማጉላት እና ለማሳነስ ሁለቴ-መታ አድርግ።"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ራስ ሙላ"</string>
@@ -927,8 +954,8 @@
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"ቦታ"</string>
     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"አሰገባ"</string>
     <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ሰርዝ"</string>
-    <string name="search_go" msgid="8298016669822141719">" ፈልግ"</string>
-    <string name="searchview_description_search" msgid="6749826639098512120">"ፈልግ"</string>
+    <string name="search_go" msgid="8298016669822141719">"ፍለጋ"</string>
+    <string name="searchview_description_search" msgid="6749826639098512120">"ፍለጋ"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"ጥያቄ ፍለጋ"</string>
     <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጥራ"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"መጥፎ ዕድል ሆኖ፣ <xliff:g id="APPLICATION">%1$s</xliff:g> አቁሞዋል፡፡"</string>
     <string name="aerr_process" msgid="4507058997035697579">"መጥፎ ዕድል ሆኖ፣ ይሄ ሂደት <xliff:g id="PROCESS">%1$s</xliff:g> ቆሞዋል፡፡"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>ምላሽ እየሰጠ አይደለም።"\n\n"መዝጋት ትፈልጋለህ?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"እንቅስቃሴ <xliff:g id="ACTIVITY">%1$s</xliff:g>ምላሽ እየሰጠ አይደለም።"\n\n"መዝጋት ትፈልጋለህ?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>ምላሽ እየሰጠ አይደለም።\n\nመዝጋት ትፈልጋለህ?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"እንቅስቃሴ <xliff:g id="ACTIVITY">%1$s</xliff:g>ምላሽ እየሰጠ አይደለም።\n\nመዝጋት ትፈልጋለህ?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g>ምላሽ እየሰጠ አይደለም።መዝጋት ትፈልጋለህ?"</string>
-    <string name="anr_process" msgid="6513209874880517125">" ሂደት<xliff:g id="PROCESS">%1$s</xliff:g> ምላሽ እየሰጠ አይደለም።"\n\n"መዝጋት ትፈልጋለህ?"</string>
+    <string name="anr_process" msgid="6513209874880517125">" ሂደት<xliff:g id="PROCESS">%1$s</xliff:g> ምላሽ እየሰጠ አይደለም።\n\nመዝጋት ትፈልጋለህ?"</string>
     <string name="force_close" msgid="8346072094521265605">"ይሁን"</string>
     <string name="report" msgid="4060218260984795706">"ሪፖርት"</string>
     <string name="wait" msgid="7147118217226317732">"ቆይ"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"ገጹ ምላሽ የማይሰጥ ሆኗል።"\n\n"ልትዘጋው ትፈልጋለህ?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"ገጹ ምላሽ የማይሰጥ ሆኗል።\n\nልትዘጋው ትፈልጋለህ?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"መተግበሪያ አቅጣጫው ተቀይሯል"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> እየሄደ ነው።"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> በዋናነት የተነሳው።"</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"ይዘትን ለመቅዳት ነባሪ መያዣ አገልግሎት እንዲያስነሳ ለመተግበሪው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች ለመጠቀም አይሆንም፡፡"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"የሚዲያ ውፅአት መንገድ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"አንድ መተግበሪያ የሚዲያ ውፅአትን ወደ ሌላ ውጫዊ መሳሪያ እንዲመራ ይፈቅድለታል።"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"ደህንነቱ በቁልፍ የተጠበቀ ማከማቻን ይድረሱ"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"አንድ መተግበሪያ ደህንነቱ በቁልፍ የተጠበቀ ማከማቻ እንዲደርስ ያስችለዋል።"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"የቁልፍ መጠበቂያውን ማሳየት እና መደበቅ ይቆጣጠሩ"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"አንድ መተግበሪያ የቁልፍ መጠበቂያውን እንዲቆጣጠር ያስችለዋል።"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ለአጉላ መቆጣጠሪያ ሁለት ጊዜ ነካ አድርግ"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ምግብር ማከል አልተቻለም።"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"ሂድ"</string>
@@ -1265,8 +1296,8 @@
     <string name="ime_action_done" msgid="8971516117910934605">"ተከናውኗል"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"ያለፈው"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"አከናውን"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>ን በመጠቀም "\n" ደውል"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>ን በመጠቀም "\n" ዕውቂያ ፍጠር"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>ን በመጠቀም \n ደውል"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>ን በመጠቀም \n ዕውቂያ ፍጠር"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"የሚከተለው ወይም ተጨማሪ መተግበሪያዎች ወደ መለያህ ለመድረስ አሁን እና ወደፊት ፈቃድ ትጠይቃለህ።"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"ይህን ጥየቃ መፍቀድ ይፈልጋሉ?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"የመድረሻ ጥያቄ"</string>
@@ -1376,7 +1407,7 @@
     <string name="description_target_camera" msgid="969071997552486814">"ካሜራ"</string>
     <string name="description_target_silent" msgid="893551287746522182">"ፀጥታ"</string>
     <string name="description_target_soundon" msgid="30052466675500172">"ድምፅ አብራ"</string>
-    <string name="description_target_search" msgid="3091587249776033139">"ፈልግ"</string>
+    <string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"ላለመቆለፍ አንሸራት፡፡"</string>
     <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"የይለፍ ቃል ቁልፎች  ሲነገሩ ለመስማት የጆሮ ማዳመጫ ሰካ።"</string>
     <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"ነጥብ."</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"በማገናኘት ላይ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"የሚገኙ"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"አይገኝም"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"በጥቅም ላይ"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"ውስጥ የተሰራ ማያ ገጽ"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI ማያ ገጽ"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ተደራቢ #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>፦ <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>፣ <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"፣ የተጠበቀ"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"ገመድ አልባ ማሳያ ተገናኝቷል"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"ይህ ማያ ገጽ በሌላ መሣሪያ ላይ እያሳየ ነው"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ግንኙነት አቋርጥ"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"የተሳሳተ ስርዓተ ጥለት"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"የተሳሳተ ይለፍ ቃል"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"የተሳሳተ ፒን"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"በ<xliff:g id="NUMBER">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"በ<xliff:g id="NUMBER">%1$d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"ስርዓተ ጥለትዎን ይሳሉ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"የሲም ፒን ያስገቡ"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"ፒን ያስገቡ"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"የይለፍ ቃል"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"ግባ"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"ልክ ያልሆነ የተጠቃሚ ስም ወይም የይለፍ ቃል።"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"የተጠቃሚ ስምዎን ወይም የይለፍ ቃልዎን ረሱት?"\n<b>"google.com/accounts/recovery"</b>"ይጎብኙ።"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"የተጠቃሚ ስምዎን ወይም የይለፍ ቃልዎን ረሱት?\n"<b>"google.com/accounts/recovery"</b>"ይጎብኙ።"</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"መለያውን በማረጋገጥ ላይ…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <xliff:g id="NUMBER_0">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"አስወግድ"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"ድምጽ ከሚመከረው መጠን በላይ ይጨመር?"\n"ለረጅም ጊዜ በከፍተኛ ድምጽ መስማት የመስማት ችሎታዎን ሊጎዳ ይችላል።"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"ድምጽ ከሚመከረው መጠን በላይ ይጨመር?\nለረጅም ጊዜ በከፍተኛ ድምጽ መስማት የመስማት ችሎታዎን ሊጎዳ ይችላል።"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ተደራሽነትን ለማንቃት ሁለት ጣቶችዎን ባሉበት ያቆዩዋቸው።"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"ተደራሽነት ነቅቷል።"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ተደራሽነት ተሰርዟል።"</string>
     <string name="user_switched" msgid="3768006783166984410">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
     <string name="owner_name" msgid="2716755460376028154">"ባለቤት"</string>
     <string name="error_message_title" msgid="4510373083082500195">"ስህተት"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"ይህ መተግበሪያ የተገደቡ መገለጫዎች መለያዎችን አይደግፍም"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"ይህ መተግበሪያ የተገደቡ መገለጫዎች መለያዎችን አይደግፍም"</string>
     <string name="app_not_found" msgid="3429141853498927379">"ይህን እርምጃ የሚያከናውን ምንም መተግበሪያ አልተገኘም"</string>
     <string name="revoke" msgid="5404479185228271586">"ሻር"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"አይ ኤስ ኦ ኤ0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"አይ ኤስ ኦ ኤ1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"አይ ኤስ ኦ ኤ2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"አይ ኤስ ኦ ኤ3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"አይ ኤስ ኦ ኤ4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"አይ ኤስ ኦ ኤ5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"አይ ኤስ ኦ ኤ6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"አይ ኤስ ኦ ኤ7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"አይ ኤስ ኦ ኤ8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"አይ ኤስ ኦ ኤ9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"አይ ኤስ ኦ ኤ10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"አይ ኤስ ኦ ቢ0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"አይ ኤስ ኦ ቢ1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"አይ ኤስ ኦ ቢ2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"አይ ኤስ ኦ ቢ3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"አይ ኤስ ኦ ቢ4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"አይ ኤስ ኦ ቢ5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"አይ ኤስ ኦ ቢ6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"አይ ኤስ ኦ ቢ7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"አይ ኤስ ኦ ቢ8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"አይ ኤስ ኦ ቢ9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"አይ ኤስ ኦ ቢ10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"አይ ኤስ ኦ ሲ0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"አይ ኤስ ኦ ሲ1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"አይ ኤስ ኦ ሲ2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"አይ ኤስ ኦ ሲ3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"አይ ኤስ ኦ ሲ4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"አይ ኤስ ኦ ሲ5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"አይ ኤስ ኦ ሲ6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"አይ ኤስ ኦ ሲ7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"አይ ኤስ ኦ ሲ8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"አይ ኤስ ኦ ሲ9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"አይ ኤስ ኦ ሲ10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"ደብዳቤ"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"የመንግስት ደብዳቤ"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"ሕግ"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"ጁኒየር ህጋዊ"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"የሒሳብ መዝገብ"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"ታብሎይድ"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ተትቷል"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ይዘት መጻፍ ላይ ስህተት"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"ፒን ያስገቡ"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"የአሁኑ ፒን"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"አዲስ ፒን"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"አዲስ ፒን ያረጋግጡ"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"ገደቦችን ለመቀየር ፒን ይፍጠሩ"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ፒኖች አይዛመዱም። እንደገና ይሞክሩ።"</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ፒን በጣም አጭር ነው። ቢያንስ 4 አኃዝ መሆን አለበት።"</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"ትክክል ያልሆነ ፒን። በ1 ሰከንድ ውስጥ እንደገና ይሞክሩ።"</item>
+    <item quantity="other" msgid="8030607343223287654">"ትክክል ያልሆነ ፒን። በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d694917..79d15f7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"للسماح للتطبيق بنقل المهام إلى المقدمة والخلفية. وقد يجري التطبيق ذلك بدون إذنك."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"إدارة حزم الأنشطة"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"للسماح للتطبيق بإضافة حزم الأنشطة التي تعمل بها التطبيقات الأخرى وإزالتها وتعديلها. فقد تعطل التطبيقات الضارة سلوك عمل التطبيقات الأخرى."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"بدء أي نشاط"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"للسماح للتطبيق ببدء أي نشاط، بغض النظر عن حماية الإذن أو حالة التصدير."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تعيين توافق الشاشة"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لأسلوب الإدخال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"الالتزام بخدمة إمكانية الدخول"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إمكانية الدخول. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"الالتزام بخدمة طباعة"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الطباعة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"الدخول إلى جميع وظائف الطباعة"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"للسماح للمالك بالدخول إلى وظائف الطباعة التي أنشأها تطبيق آخر. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"الربط بخدمة NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"للسماح لحامل البطاقة بالربط بالتطبيقات التي تحاكي بطاقات NFC. لا يتوجب استخدامه على الإطلاق للتطبيقات العادية."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"الالتزام بخدمة إدخال النصوص"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إدخال النصوص (على سبيل المثال، SpellCheckerService). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"الالتزام بخدمة VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"إضافة مشرف جهاز أو إزالته"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"للسماح بحامل البطاقة بإضافة مشرفي أجهزة نشطين أو إزالتهم. لا يلزم ذلك أبدًا للتطبيقات العادية."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"للسماح للتطبيق بتغيير تدوير الشاشة في أي وقت. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغيير سرعة المؤشر"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"للسماح للتطبيق باستخدام ميزات SurfaceFlinger ذات المستوى المنخفض."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"قراءة المخزن المؤقت للإطارات"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"للسماح للتطبيق بقراءة محتوى المخزن المؤقت للإطارات."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"الدخول إلى InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"للسماح للتطبيق باستخدام ميزات InputFlinger ذات المستوى المنخفض."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"تهيئة شاشات Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"للسماح للتطبيق بتهيئة شاشات Wi-Fi والاتصال بها."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"التحكم في شاشات Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"للسماح للتطبيق بالتحكم في الميزات ذات المستوى المنخفض في شاشات Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"تغيير إعداداتك الصوتية"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"للسماح للتطبيق بتعديل إعدادات الصوت العامة مثل مستوى الصوت وأي السماعات يتم استخدامها للاستماع."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"تسجيل الصوت"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"للسماح للتطبيق بالكتابة إلى بطاقة SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"تعديل/حذف محتويات وحدة تخزين الوسائط الداخلية"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"للسماح للتطبيق بتعديل محتويات وحدة تخزين الوسائط الداخلية."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"إدارة السعة التخزينية للمستند"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"السماح للتطبيق بإدارة السعة التخزينية للمستند."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"الوصول إلى سعة التخزين الخارجية لجميع المستخدمين"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"للسماح للتطبيق بالدخول إلى سعة التخزين الخارجية لجميع المستخدمين."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"الدخول إلى نظام ملفات ذاكرة التخزين المؤقت"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"للسماح لتطبيق بإدارة سياسات الشبكة وتحديد قواعد متعلقة بالتطبيق."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"تعديل حساب استخدام الشبكة"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"للسماح للتطبيق بتعديل كيفية حساب استخدام الشبكة في التطبيقات. ليس للاستخدام بواسطة التطبيقات العادية."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"تعديل علامات المقابس"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"للسماح للتطبيق بتعديل علامات المقابس لإعادة التوجيه."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"إشعارات الدخول"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"أدخل بطاقة SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"بطاقة SIM مفقودة أو غير قابلة للقراءة. أدخل بطاقة SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"بطاقة SIM غير قابلة للاستخدام."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"تم تعطيل بطاقة SIM بشكل دائم."\n" اتصل بمقدم خدمة اللاسلكي للحصول على بطاقة SIM أخرى."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"تم تعطيل بطاقة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على بطاقة SIM أخرى."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"زر المقطع الصوتي السابق"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"زر المقطع الصوتي التالي"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"زر الإيقاف المؤقت"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"راجع دليل المستخدم أو اتصل بخدمة العملاء."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"بطاقة SIM مؤمّنة."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"جارٍ إلغاء تأمين بطاقة SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة."\n\n"الرجاء إعادة المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"لقد كتبت كلمة المرور <xliff:g id="NUMBER_0">%d</xliff:g> مرة بشكل غير صحيح. "\n\n"أعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"لقد كتبت رقم التعريف الشخصي <xliff:g id="NUMBER_0">%d</xliff:g> مرة بشكل غير صحيح. "\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة.\n\nالرجاء إعادة المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"لقد كتبت كلمة المرور <xliff:g id="NUMBER_0">%d</xliff:g> مرة بشكل غير صحيح. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"لقد كتبت رقم التعريف الشخصي <xliff:g id="NUMBER_0">%d</xliff:g> مرة بشكل غير صحيح. \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_now_wiping" product="tablet" msgid="280873516493934365">"لقد حاولت إلغاء تأمين الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> من المرات بشكل غير صحيح. سيتم الآن إعادة تعيين الجهاز اللوحي إلى الإعدادات الافتراضية للمصنع."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"كلمة المرور"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"تسجيل الدخول"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"اسم المستخدم غير صحيح أو كلمة المرور غير صحيحة."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"هل نسيت اسم المستخدم أو كلمة المرور؟"\n"انتقل إلى "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"هل نسيت اسم المستخدم أو كلمة المرور؟\nانتقل إلى "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"جارٍ التحقق..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"إلغاء تأمين"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"تشغيل الصوت"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"تأكيد الانتقال"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"مغادرة هذه الصفحة"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"البقاء في هذه الصفحة"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"هل تريد بالتأكيد الانتقال بعيدًا عن هذه الصفحة؟"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nهل تريد بالتأكيد الانتقال بعيدًا عن هذه الصفحة؟"</string>
     <string name="save_password_label" msgid="6860261758665825069">"تأكيد"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"نصيحة: اضغط مرتين للتكبير والتصغير."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ملء تلقائي"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"للأسف، توقف <xliff:g id="APPLICATION">%1$s</xliff:g>."</string>
     <string name="aerr_process" msgid="4507058997035697579">"للأسف، توقفت العملية <xliff:g id="PROCESS">%1$s</xliff:g>."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> لا يستجيب."\n\n"هل تريد إغلاقه؟"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"النشاط <xliff:g id="ACTIVITY">%1$s</xliff:g> لا يستجيب."\n\n"هل تريد إغلاقه؟"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> لا يستجيب.\n\nهل تريد إغلاقه؟"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"النشاط <xliff:g id="ACTIVITY">%1$s</xliff:g> لا يستجيب.\n\nهل تريد إغلاقه؟"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> لا يستجيب. هل تريد إغلاقه؟"</string>
-    <string name="anr_process" msgid="6513209874880517125">"العملية <xliff:g id="PROCESS">%1$s</xliff:g> لا تستجيب."\n\n"هل تريد إغلاقها؟"</string>
+    <string name="anr_process" msgid="6513209874880517125">"العملية <xliff:g id="PROCESS">%1$s</xliff:g> لا تستجيب.\n\nهل تريد إغلاقها؟"</string>
     <string name="force_close" msgid="8346072094521265605">"موافق"</string>
     <string name="report" msgid="4060218260984795706">"إرسال تقرير"</string>
     <string name="wait" msgid="7147118217226317732">"انتظار"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"أصبحت الصفحة لا تستجيب."\n\n"هل تريد إغلاقها؟"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"أصبحت الصفحة لا تستجيب.\n\nهل تريد إغلاقها؟"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"تمت إعادة توجيه التطبيق"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل الآن."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"تم تشغيل <xliff:g id="APP_NAME">%1$s</xliff:g> من الأصل."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"للسماح باستدعاء خدمة الحاوية الافتراضية لنسخ المحتوى. ليس للاستخدام بواسطة التطبيقات العادية."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"توجيه إخراج الوسائط"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"للسماح للتطبيق بتوجيه إخراج الوسائط إلى أجهزة خارجية أخرى."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"الدخول إلى التخزين المحمي بقفل المفاتيح"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"السماح لأحد التطبيقات بالدخول إلى التخزين المحمي بقفل المفاتيح."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"التحكم في عرض وإخفاء قفل المفاتيح"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"للسماح لأحد التطبيقات بالتحكم في قفل المفاتيح."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"المس مرتين للتحكم في التكبير/التصغير"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"تعذرت إضافة أداة."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"تنفيذ"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"تم"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"السابق"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"تنفيذ"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"طلب رقم"\n"باستخدام <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"إنشاء جهة اتصال"\n"باستخدام <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"طلب رقم\nباستخدام <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"إنشاء جهة اتصال\nباستخدام <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"يطلب التطبيق أو التطبيقات التالية الإذن للدخول إلى حسابك، الآن وفي المستقبل."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"هل تريد السماح بذلك الطلب؟"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"طلب الدخول"</string>
     <string name="allow" msgid="7225948811296386551">"السماح"</string>
     <string name="deny" msgid="2081879885755434506">"رفض"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"الإذن مطلوب"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"الإذن مطلوب"\n"للحساب <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"الإذن مطلوب\nللحساب <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"طريقة الإرسال"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"مزامنة"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"إمكانية الدخول"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"جارٍ الاتصال..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"متاح"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"غير متاح"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"قيد الاستخدام"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"شاشة مدمجة"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"شاشة HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"المركب #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>، <xliff:g id="DPI">%4$d</xliff:g> نقطة لكل بوصة"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"آمن"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"تم التوصيل بشاشة لاسلكية"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"يتم عرض هذه الشاشة على جهاز آخر"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"قطع الاتصال"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"نقش خاطئ"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"كلمة مرور خاطئة"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"رقم تعريف شخصي خاطئ"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"حاول مرة أخرى خلال <xliff:g id="NUMBER">%d</xliff:g> ثانية."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"حاول مرة أخرى خلال <xliff:g id="NUMBER">%1$d</xliff:g> ثانية."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"ارسم نقشك"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"أدخل رقم التعريف الشخصي لبطاقة SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"أدخل رقم التعريف الشخصي"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"كلمة المرور"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"تسجيل الدخول"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"اسم مستخدم غير صحيح أو كلمة مرور غير صالحة."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"هل نسيت اسم المستخدم أو كلمة المرور؟"\n"انتقل إلى "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"هل نسيت اسم المستخدم أو كلمة المرور؟\nانتقل إلى "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"جارٍ فحص الحساب…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"لقد كتبت رقم التعريف الشخصي بشكل غير صحيح <xliff:g id="NUMBER_0">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"لقد كتبت رقم التعريف الشخصي بشكل غير صحيح <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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"إزالة"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟"\n"قد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"اضغط بإصبعين لأسفل مع الاستمرار لتمكين تسهيل الدخول."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"تم تمكين إمكانية الدخول."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"تم إلغاء تسهيل الدخول."</string>
     <string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"المالك"</string>
     <string name="error_message_title" msgid="4510373083082500195">"خطأ"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"هذا التطبيق لا يتوافق مع حسابات الملفات الشخصية المقيدة"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"لا يتوافق هذا التطبيق مع حسابات الملفات الشخصية المقيدة"</string>
     <string name="app_not_found" msgid="3429141853498927379">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string>
     <string name="revoke" msgid="5404479185228271586">"إلغاء"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ملغاة"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"حدث خطأ أثناء كتابة المحتوى"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"إدخال رقم التعريف الشخصي"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"رقم التعريف الشخصي الحالي"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"رقم التعريف الشخصي الجديد"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"تأكيد رقم التعريف الشخصي الجديد"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"إنشاء رقم تعريف شخصي لتعديل القيود"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"أرقام التعريف الشخصية لا تتطابق، أعد المحاولة."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"رقم التعريف الشخصي أقصر مما يلزم، يجب ألا يقل عن 4 أرقام. "</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد ثانية واحدة."</item>
+    <item quantity="other" msgid="8030607343223287654">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد <xliff:g id="COUNT">%d</xliff:g> من الثواني."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index fe11bb6..99dfcbf 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -279,6 +279,10 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дазваляе прыкладанню перамяшчаць заданні на ​​пярэдні план і ў фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"спыніць запушчаныя прыкладанні"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дазваляе прыкладанням выдаляць заданні і спыняць прыкладанні, якія іх выкарыстоўваюць. Шкоднасныя прыкладаннi могуць перашкодзiць працы іншых прыкладанняў."</string>
+    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
+    <skip />
+    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
+    <skip />
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"пачынаць любы працэс"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Дазваляе прыкладанню пачынаць любы працэс, незалежна ад абароны дазволам ці стану экспарту."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"усталяваць сумяшчальнасць экранаў"</string>
@@ -356,6 +360,18 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню метада ўводу. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"прывязацца да службы доступу"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы доступу. Не патрабуецца для звычайных прыкладанняў."</string>
+    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
+    <skip />
+    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
+    <skip />
+    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
+    <skip />
+    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
+    <skip />
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"звязаць з тэкставай службай"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню тэкставай паслугі (напрыклад, SpellCheckerService). Ніколі не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"звязвацца з VPN сэрвісам"</string>
@@ -366,6 +382,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"узаемадзейнічаць з адміністратарам прылады"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дазваляе ўладальніку адпраўляць намеры да адміністратара прылады. Не патрабуецца для звычайных прыкладанняў."</string>
+    <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
+    <skip />
+    <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
+    <skip />
     <string name="permlab_setOrientation" msgid="3365947717163866844">"змяняць арыентацыю экрана"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дазваляе прыкладанням змяняць паварот экрана ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змена хутк. перамяшч. ўказ."</string>
@@ -458,10 +478,24 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дазваляе прыкладанням выкарыстоўваць нізкаўзроўневыя функцыі SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"чытаць буфер кадраў"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дазваляе прыкладанням счытваць змесціва буферу кадра."</string>
+    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
+    <skip />
+    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
+    <skip />
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"налада дысплеяў Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дазволiць прыкладанню наладжвацца i падключацца да дысплеяў Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"кіраванне дысплеямi Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Прыкладанне зможа кіраваць нізкім узроўнем функцый дысплеяў Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дазваляе прыкладанням змяняць глабальныя налады гуку, такія як моц і тое, што дынамік выкарыстоўваецца для выхаду."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
@@ -613,6 +647,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанням запісваць на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змяніць/выдаліць унутраныя носьбіты змесціва"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранай памяці."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"кіраваць сховішчам для дакументаў"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Дазваляе прыкладанню кіраваць сховішчам для дакументаў."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"доступ да знешніх захоўвання для ўсіх карыстальнікаў"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Дазваляе ўсiм карыстальнiкам прыкладання атрымлiваць доступ да знешнега сховiшча"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"доступ да файлавай сістэмы кэша"</string>
@@ -625,10 +661,18 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+    <skip />
+    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+    <skip />
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прывязка да службы апавяшчэння слухача"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дазваляе ўладальніку прывязвацца да верхняга ўзроўню інтэрфейсу службы  апавяшчэння слухачоў. Ніколі не патрэбнае для звычайных прыкладанняў."</string>
+    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
+    <skip />
+    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
@@ -796,7 +840,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Усталюйце SIM-карту."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-карту немагчыма выкарыстоўваць"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ваша SIM-карта была адключана назаўсёды."\n" Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ваша SIM-карта была адключана назаўсёды.\n Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Кнопка папярэдняй кампазiцыi"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Кнопка наступнай кампазiцыi"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Кнопка паўзы"</string>
@@ -808,11 +852,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Глядзіце \"Інструкцыю для карыстальніка\" або звяжыцеся са службай тэхнiчнай падтрымкі."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблакаваная."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблакаванне SIM-карты..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\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>. Пасля яшчэ некалькiх няўдалых спроб (<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>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакаваць тэлефон з дапамогай уваходу ў Google."\n\n" Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПаўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПаўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. \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>. Пасля яшчэ некалькiх няўдалых спроб (<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>. Пасля яшчэ некалькiх няўдалых спроб (<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">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да заводскіх налад."</string>
@@ -826,7 +870,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Увайсці"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Няправільнае імя карыстальніка ці пароль."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забыліся на імя карыстальніка або пароль?\nНаведайце "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Праверка..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Разблакаваць"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Гук уключаны"</string>
@@ -874,7 +918,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Пацвердзіце пераход"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Пакінуць гэту старонку"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Заставацца на гэтай старонцы"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Вы ўпэўнены, што хочаце пакiнуць гэту старонку?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nВы ўпэўнены, што хочаце пакiнуць гэту старонку?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
@@ -1080,14 +1124,14 @@
     <string name="aerr_application" msgid="932628488013092776">"На жаль, прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> спынілася."</string>
     <string name="aerr_process" msgid="4507058997035697579">"На жаль, працэс <xliff:g id="PROCESS">%1$s</xliff:g> спыніўся."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Прыкладанне <xliff:g id="APPLICATION">%2$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Працэс <xliff:g id="ACTIVITY">%1$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Прыкладанне <xliff:g id="APPLICATION">%2$s</xliff:g> не адказвае.\n\nЗакрыць яго?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Працэс <xliff:g id="ACTIVITY">%1$s</xliff:g> не адказвае.\n\nЗакрыць яго?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> не адказвае. Закрыць яго?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> не адказвае.\n\nЗакрыць яго?"</string>
     <string name="force_close" msgid="8346072094521265605">"ОК"</string>
     <string name="report" msgid="4060218260984795706">"Справаздача"</string>
     <string name="wait" msgid="7147118217226317732">"Чакаць"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Старонка не адказвае на запыты."\n\n"Закрыць яе?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Старонка не адказвае на запыты.\n\nЗакрыць яе?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Прыкл. перанакіраванае"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> зараз запушчанае."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> запушчанае."</string>
@@ -1256,6 +1300,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дазваляе прыкладанням выклікаць службу захавання па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Маршрутны мультымедыйны выхад"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Дазваляе прыкладанням маршрутызаваць мультымедыйны выхад на iншыя знешнiя прылады."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Доступ да блакіроўкі клавіятуры бяспечнага сховішча"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дазваляе прыкладанню атрымліваць доступ да блакіроўкі клавіятуры бяспечнага сховішча."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Кiраванне адлюстраваннем і схаваннем блакiроўкi клавіятуры"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дазваляе прыкладанню кiраваць блакiроўкай клавiятуры."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двойчы дакраніцеся, каб змянiць маштаб"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Немагчыма дадаць віджэт."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Пачаць"</string>
@@ -1265,15 +1313,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Гатова"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Назад"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Выканаць"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Набраць нумар"\n"з выкарыстаннем <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Стварыць кантакт"\n"з дапамогай<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Набраць нумар\nз выкарыстаннем <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Стварыць кантакт\nз дапамогай<xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Гэтыя адно або некалькі прыкладанняў запытваюць дазвол на доступ да вашага ўліковага запісу цяпер і ў будучыні."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Дазволіць гэты запыт?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Запыт на доступ"</string>
     <string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
     <string name="deny" msgid="2081879885755434506">"Забараніць"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Дазвол запытаны"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запытаны дазвол"\n"для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запытаны дазвол\nдля ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Метад уводу"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Сінхранізацыя"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Спецыяльныя магчымасці"</string>
@@ -1441,10 +1489,14 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Падключэнне..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Даступна"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Недаступны"</string>
+    <!-- no translation found for media_route_status_in_use (4533786031090198063) -->
+    <skip />
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Убудаваны экран"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Экран HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Оверлей # <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> кр. на цалю"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Падключаны бесправадны дысплей"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Гэты экран паказваецца на іншай прыладзе"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Адключыць"</string>
@@ -1453,7 +1505,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%1$d</xliff:g> с."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйце ключ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Увядзіце PIN-код SIM-карты"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Увядзіце PIN-код"</string>
@@ -1473,27 +1525,125 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Увайсцi"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Няправільнае імя карыстальніка ці пароль."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыліся на імя карыстальніка або пароль?\nНаведайце "<b>"google.com/accounts/recovery"</b></string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Праверка ўлiковага запiсу..."</string>
-    <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">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <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_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">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <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">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да завадскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Вы няправільна спрабавалі разблакiраваць тэлефон некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Выдалiць"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Павялiчыць гук больш за рэкамендаваны ўзровень?"\n"Доўгае слуханне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Павялiчыць гук больш за рэкамендаваны ўзровень?\nДоўгае слуханне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утрымлiвайце два пальцы, каб уключыць доступ."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Даступнасць уключана."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Даступнасць адменена."</string>
     <string name="user_switched" msgid="3768006783166984410">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Уладальнік"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Памылка"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Гэтае прыкладанне не падтрымлівае уліковыя запісы для карыстальнікаў з абмежаваннямi"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Гэта прыкладанне не падтрымлівае ўліковыя запісы для профiляў з абмежаваннямі"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Прыкладанне для гэтага дзеяння не знойдзенае"</string>
     <string name="revoke" msgid="5404479185228271586">"Ануляваць"</string>
+    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
+    <skip />
+    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
+    <skip />
+    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
+    <skip />
+    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
+    <skip />
+    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
+    <skip />
+    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
+    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 76cab7a..c4f08b5 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Разрешава на приложението да прехвърля задачи на преден и на заден план. То може да направи това без вашето потвърждение."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"спиране на изпълняваните приложения"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Разрешава на приложението да премахва задачи и да прекратява приложенията им. Злонамерените приложения могат да нарушат поведението на други приложения."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"управление на стековете за активност"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Разрешава на приложението да добавя, премахва и променя стековете за активност, в които се изпълняват другите приложения. Работата им може да бъде нарушена от злонамерени приложения."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"започване на дейности"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Разрешава на приложението да започва дейности независимо от защитата на базата на разрешения или състоянието при експортиране."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"задаване на съвместимост на екрана"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на метод на въвеждане. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"обвързване с услуга за достъпност"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за достъпност. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"обвързване с услуга за отпечатване"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за отпечатване. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"достъп до всички задания за отпечатване"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Разрешава на притежателя да осъществява достъп до създадените от друго приложение задания за отпечатване. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"обвързване с текстова услуга"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на текстова услуга (напр. SpellCheckerService). Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"обвързване с услуга за VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"добавяне или премахване на администратор на устройства"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Разрешава на притежателя да добавя или премахва администратори на активни устройства. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Разрешава на приложението да променя ориентацията на екрана по всяко време. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"промяна на скоростта на курсор"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Разрешава на приложението да използва функциите на SurfaceFlinger от ниско ниво."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"четене на кадровия буфер"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Разрешава на приложението да чете съдържанието на кадровия буфер."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"достъп до InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Разрешава на приложението да използва функциите на InputFlinger от ниско ниво."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"конфигуриране на дисплеите през WiFi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Разрешава на приложението да конфигурира и да се свързва с дисплеите през WiFi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контролиране на дисплеите през WiFi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Разрешава на приложението да контролира функциите от ниско ниво на дисплеите през WiFi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"промяна на настройките ви за звука"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Разрешава на приложението да променя глобалните настройки за звука, като например силата и това, кой високоговорител се използва за изход."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"запис на звук"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Разрешава на приложението да записва върху SD картата."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"пром./изтр. на съдърж. на вътр. мултим. хранил."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Разрешава на приложението да променя съдържанието на вътрешното мултимедийно хранилище."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"управл. на хранил. с документи"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Разрешава на приложението да управлява хранилището с документи."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"достъп до външ. хранилище за всички потребители"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Разрешава на приложението достъп до външното хранилище за всички потребители."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"достъп до файловата система на кеша"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Разрешава на приложението да управлява правилата на мрежата и да определя такива за конкретно приложение."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"промяна на отчетността на употребата на мрежа"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"промяна на означенията на сокетите"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Разрешава на приложението да променя означенията на сокетите за маршрутизиране."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"извикване на предоставеното от оператора приложение за конфигуриране"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Поставете SIM карта."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM картата липсва или е нечетлива. Поставете SIM карта."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Неизползваема SIM карта."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM картата ви е деактивирана за постоянно."\n"Свържете се с оператора на безжичната си връзка, за да получите друга."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM картата ви е деактивирана за постоянно.\nСвържете се с оператора на безжичната си връзка, за да получите друга."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Бутон за предишния запис"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Бутон за следващия запис"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Бутон за пауза"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Вижте ръководството за потребителя или се свържете с отдела за поддръжка на клиенти."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM картата е заключена."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM картата се отключва..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \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_now_wiping" product="tablet" msgid="280873516493934365">"Направихте опит да отключите таблета неправилно <xliff:g id="NUMBER">%d</xliff:g> пъти. Сега ще бъдат възстановени стандартните му фабрични настройки."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Парола"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Вход"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Потребителското име или паролата са невалидни."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забравили сте потребителското си име или парола?"\n"Посетете "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забравили сте потребителското си име или парола?\nПосетете "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Проверява се..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Отключване"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Включване на звука"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Потвърждаване на придвижването"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Напускане на тази страница"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Оставане на тази страница"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Наистина ли искате да излезете от тази страница?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nНаистина ли искате да излезете от тази страница?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Потвърждение"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Съвет: Докоснете двукратно, за да увеличите или намалите мащаба."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автопоп."</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"За съжаление <xliff:g id="APPLICATION">%1$s</xliff:g> спря."</string>
     <string name="aerr_process" msgid="4507058997035697579">"За съжаление процесът <xliff:g id="PROCESS">%1$s</xliff:g> спря."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Приложението „<xliff:g id="APPLICATION">%2$s</xliff:g>“ не отговаря."\n\n"Искате ли да го затворите?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Дейността „<xliff:g id="ACTIVITY">%1$s</xliff:g>“ не отговаря."\n\n"Искате ли да я затворите?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Приложението „<xliff:g id="APPLICATION">%2$s</xliff:g>“ не отговаря.\n\nИскате ли да го затворите?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Дейността „<xliff:g id="ACTIVITY">%1$s</xliff:g>“ не отговаря.\n\nИскате ли да я затворите?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ не отговаря. Искате ли да го затворите?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Процесът „<xliff:g id="PROCESS">%1$s</xliff:g>“ не отговаря."\n\n"Искате ли да го затворите?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Процесът „<xliff:g id="PROCESS">%1$s</xliff:g>“ не отговаря.\n\nИскате ли да го затворите?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Подаване на сигнал"</string>
     <string name="wait" msgid="7147118217226317732">"Изчакване"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страницата не отговаря."\n\n"Искате ли да я затворите?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страницата не отговаря.\n\nИскате ли да я затворите?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Приложението се пренасочи"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Първоначално бе стартирано: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Разрешава на приложението да извиква стандартната услуга на контейнера, за да се копира съдържание. Не е предназначено за нормални приложения."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Насочване на изходящата мултимедия"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Разрешава на приложението да насочва изходящата мултимедия към други външни устройства."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Достъп до надеждното хранилище, свързано с функцията за защита на клавишите"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Позволява на приложението да осъществява достъп до надеждното хранилище, свързано с функцията за защита на клавишите."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Контролиране на показването и скриването на функцията за защита на клавишите"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Разрешава на приложението да контролира функцията за защита на клавишите."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Докоснете двукратно за управление на промяната на мащаба"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Приспособлението не можа да бъде добавено."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Старт"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Готово"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Пред."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Изпълнение"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Набиране"\n"с използване на <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Създаване на контакт"\n"с използване на <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Набиране\nс използване на <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Създаване на контакт\nс използване на <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Следните едно или повече приложения искат разрешение за достъп до профила ви сега и в бъдеще."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Разрешавате ли тази заявка?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Заявка за достъп"</string>
     <string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
     <string name="deny" msgid="2081879885755434506">"Отказване"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Иска се разрешение"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Иска се разрешение"\n"за профила <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Иска се разрешение\nза профила <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Метод на въвеждане"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Синхронизиране"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Достъпност"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Установява се връзка..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Налице"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Не е налице"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Използва се"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Вграден екран"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Екран „HDMI“"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наслагване №<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"„<xliff:g id="NAME">%1$s</xliff:g>“: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", защитено"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Безжичният дисплей е свързан"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Този екран се показва на друго устройство"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Прекратяване на връзката"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Грешна фигура"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Грешна парола"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Грешен ПИН код"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Опитайте отново след <xliff:g id="NUMBER">%d</xliff:g> секунди."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Опитайте отново след <xliff:g id="NUMBER">%1$d</xliff:g> секунди."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Начертайте фигурата си"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Въведете ПИН кода за SIM картата"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Въведете ПИН код"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Парола"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Вход"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Невалидно потребителско име или парола."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?"\n"Посетете "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?\nПосетете "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Профилът се проверява…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Премахване"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Да се увеличи ли силата на звука над препоръчаното ниво?"\n"Продължителното слушане при висока сила на звука може да увреди слуха ви."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Да се увеличи ли силата на звука над препоръчаното ниво?\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Продължете да натискате с два пръста, за да активирате функцията за достъпност."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Достъпността е активирана."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Функцията за достъпност е анулирана."</string>
     <string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Собственик"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Грешка"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Това приложение не поддържа профили за потребителски профили с ограничена функционалност"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Това приложение не поддържа профили за потребителски профили с ограничена функционалност"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Няма намерено приложение за извършване на това действие"</string>
     <string name="revoke" msgid="5404479185228271586">"Отмяна"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Анулирано"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Грешка при записване на съдържанието"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Въведете ПИН кода"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Текущ ПИН код"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Нов ПИН код"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Потвърждаване на новия ПИН код"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Създаване на ПИН код за промяна на ограниченията"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ПИН кодовете не са идентични. Опитайте отново."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ПИН кодът е твърде кратък. Трябва да е поне 4 цифри."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Неправилен ПИН код. Опитайте отново след 1 секунда."</item>
+    <item quantity="other" msgid="8030607343223287654">"Неправилен ПИН код. Опитайте отново след <xliff:g id="COUNT">%d</xliff:g> секунди."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8c82e3a..f0878d9 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permet que l\'aplicació desplaci tasques en primer o segon pla. L\'aplicació pot fer-ho sense que tu ho indiquis."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestiona les piles d\'activitats"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permet que l\'aplicació, afegeixi, suprimeixi i modifiqui les piles d\'activitats on s\'executen altres aplicacions. És possible que les aplicacions malicioses interrompin el comportament d\'altres aplicacions."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualsevol activitat"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permet que l\'aplicació iniciï qualsevol activitat, amb independència de la protecció del permís o de l\'estat exportat."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definició de la compatibilitat de pantalla"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permet que el titular vinculi a la interfície de nivell superior d\'un mètode d\'entrada. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular amb un servei d\'accessibilitat"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permet vincular amb la interfície de nivell superior d\'un servei d\'accessibilitat. Les aplicacions normals no haurien de necessitar-ho."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincula amb un servei d\'impressió"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei d\'impressió. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accedeix a totes les tasques d\'impressió"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permet que el propietari accedeixi a les tasques d\'impressió creades per una altra aplicació. Les aplicacions normals no l\'haurien de necessitar mai."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"vincula al servei NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Permet que el titular es vinculi a les aplicacions que emulen les targetes de NFC. No hauria de ser mai necessari per a les aplicacions normals."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincula a un servei de text"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permet al titular vincular amb la interfície de nivell superior d\'un servei de text (per exemple, SpellCheckerService). Les aplicacions normals mai no ho haurien de necessitar."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincula a un servei de VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"afegeix un administrador al dispositiu o suprimeix-lo"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet que el titular afegeixi administradors actius al dispositiu o en suprimeixi. No s\'hauria de necessitar per a les aplicacions normals."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permet que l\'aplicació canviï el gir de la pantalla en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"canvi de velocitat del punter"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permet que l\'aplicació utilitzi funcions SurfaceFlinger de baix nivell."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"llegir la memòria intermèdia de marcs"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permet que l\'aplicació llegeixi el contingut de la memòria intermèdia de marcs."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accedeix a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permet que l\'aplicació utilitzi funcions InputFlinger de baix nivell."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configuració de les pantalles Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet a l\'aplicació configurar-se i connectar-se a les pantalles Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control de les pantalles Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet a l\'aplicació controlar les funcions de baix nivell de les pantalles Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"canviar la configuració d\'àudio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permet que l\'aplicació modifiqui la configuració d\'àudio general, com ara el volum i l\'altaveu de sortida que es fa servir."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrar àudio"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permet a l\'aplicació escriure a la targeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Canvia/esborra emmagatz. intern"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permet que l\'aplicació modifiqui el contingut de l\'emmagatzematge multimèdia intern."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"gestió emmagatzematge docum."</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permet que l\'aplicació gestioni l\'emmagatzematge de documents."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"accedeix a l\'emmagatzematge extern per a tots els usuaris"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permet que l\'aplicació accedeixi a l\'emmagatzematge extern per a tots els usuaris."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accedir al sistema de fitxers de la memòria cau"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet que l\'aplicació gestioni les polítiques de la xarxa i que defineixi les regles específiques d\'aplicació."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificació del càlcul d\'ús de la xarxa"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifica les marques dels sòcols"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet que l\'aplicació modifiqui les marques de sòcols per a l\'encaminament"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei de processament de notificacions"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei de processament de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insereix una targeta SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la targeta SIM o no es pot llegir. Insereix-ne una."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Targeta SIM no utilitzable."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"La targeta SIM està desactivada permanentment."\n" Contacta amb el teu proveïdor de serveis sense fil per obtenir-ne una altra."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"La targeta SIM està desactivada permanentment.\n Contacta amb el teu proveïdor de serveis sense fil per obtenir-ne una altra."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Botó de pista anterior"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Botó de pista següent"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botó de pausa"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la guia de l\'usuari o posa\'t en contacte amb el servei d\'atenció al client."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La targeta SIM està bloquejada."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"S\'està desbloquejant la targeta SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb l\'inici de sessió de Google."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb l\'inici de sessió de Google."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb l\'inici de sessió de Google.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb l\'inici de sessió de Google.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%d</xliff:g> vegades incorrectament. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, la tauleta es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%d</xliff:g> vegades incorrectament. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, la tauleta es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades incorrectament. Ara la tauleta es restablirà a la configuració predeterminada de fàbrica."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contrasenya"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inicia la sessió"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nom d\'usuari o contrasenya no vàlids."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Has oblidat el teu nom d\'usuari o la contrasenya?"\n"Visita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Has oblidat el teu nom d\'usuari o la contrasenya?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"S\'està comprovant..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloqueja"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"So activat"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmació de la navegació"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Surt d\'aquesta pàgina"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Queda\'t en aquesta pàgina"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Estàs segur que vols sortir d\'aquesta pàgina?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nEstàs segur que vols sortir d\'aquesta pàgina?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consell: Pica dos cops per ampliar i per reduir."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Em. aut."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> s\'ha aturat."</string>
     <string name="aerr_process" msgid="4507058997035697579">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> s\'ha aturat."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> no respon."\n\n"Vols tancar-la?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"L\'activitat <xliff:g id="ACTIVITY">%1$s</xliff:g> no respon."\n\n"Vols tancar-la?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> no respon.\n\nVols tancar-la?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"L\'activitat <xliff:g id="ACTIVITY">%1$s</xliff:g> no respon.\n\nVols tancar-la?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> no respon. Vols tancar-la?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> no respon."\n\n"Vols tancar-lo?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> no respon.\n\nVols tancar-lo?"</string>
     <string name="force_close" msgid="8346072094521265605">"D\'acord"</string>
     <string name="report" msgid="4060218260984795706">"Informe"</string>
     <string name="wait" msgid="7147118217226317732">"Espera"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"La pàgina ha deixat de respondre."\n\n"Vols tancar-la?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La pàgina ha deixat de respondre.\n\nVols tancar-la?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicació redirigida"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va iniciar originalment."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permet invocar el servei de contenidor predeterminat per copiar contingut. No indicat per a les aplicacions normals."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Indicació de ruta de sortida de contingut multimèdia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permet que una aplicació indiqui la ruta de sortida de contingut multimèdia a altres dispositius externs."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Accedeix a l\'emmagatzematge protegit per contrasenya"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet que una aplicació accedeixi a l\'emmagatzematge protegit per contrasenya."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Controla si es mostra o s\'amaga el bloqueig de les tecles."</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet que una aplicació controli el bloqueig de les tecles."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos cops per controlar el zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No s\'ha pogut afegir el widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Vés"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Fet"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Anterior"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Executa"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Marca el número"\n"mitjançant <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Crea un contacte"\n"mitjançant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Marca el número\nmitjançant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Crea un contacte\nmitjançant <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Les aplicacions següents sol·liciten permís per accedir al teu compte, ara i en el futur."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Voleu permetre aquesta sol·licitud?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Sol·licitud d\'accés"</string>
     <string name="allow" msgid="7225948811296386551">"Permet"</string>
     <string name="deny" msgid="2081879885755434506">"Denega"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permís sol·licitat"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"S\'ha sol·licitat permís"\n"per al compte <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"S\'ha sol·licitat permís\nper al compte <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Mètode d\'introducció de text"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronització"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"S\'està connectant..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"No disponible"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"En ús"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Pantalla HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposa #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", segur"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"La pantalla sense fil està connectada"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Aquesta pantalla es mostra en un altre dispositiu"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconnecta"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patró incorrecte"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Contrasenya incorrecta"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecte"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER">%1$d</xliff:g> segons."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuixa el patró"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introdueix el PIN de la SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Introdueix el PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Contrasenya"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Inicia la sessió"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'usuari o contrasenya no vàlids."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Has oblidat el teu nom d\'usuari o la contrasenya?"\n"Visita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Has oblidat el teu nom d\'usuari o la contrasenya?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"S\'està comprovant el compte…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, la tauleta es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, el telèfon es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. Ara la tauleta es restablirà a la configuració predeterminada de fàbrica."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. Ara el telèfon es restablirà a la configuració predeterminada de fàbrica."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Elimina"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vols augmentar el volum per sobre del nivell recomanat?"\n"Escoltar sons a un volum alt durant períodes de temps llargs pot danyar l\'oïda."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vols augmentar el volum per sobre del nivell recomanat?\nEscoltar sons a un volum alt durant períodes de temps llargs pot danyar l\'oïda."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén premuts els dos dits per activar l\'accessibilitat."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"S\'ha activat l\'accessibilitat."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilitat cancel·lada."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Propietari"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"L\'aplicació no és compatible amb comptes de perfils restringits."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"L\'aplicació no és compatible amb comptes de perfils restringits"</string>
     <string name="app_not_found" msgid="3429141853498927379">"No s\'ha trobat cap aplicació per processar aquesta acció"</string>
     <string name="revoke" msgid="5404479185228271586">"Revoca"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta governamental"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legal Junior"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Llibre major"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancel·lada"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error en escriure el contingut"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introdueix el PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN actual"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN nou"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirma el PIN nou"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un pin per modificar les restriccions"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Els PIN no coincideixen. Torna-ho a provar."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN és massa curt. Ha de tenir quatre dígits com a mínim."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorrecte. Torna-ho a provar d\'aquí a 1 segon."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorrecte. Torna-ho a provar d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a465d7c..86420cd 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Aplikace tak může činit bez vašeho zásahu."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"spravovat zásobníky aktivit"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Umožňuje aplikaci přidat, odstranit nebo upravit zásobníky aktivit jiných aplikací. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"zahájení libovolné činnosti"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Umožňuje aplikaci zahájit libovolnou aktivitu bez ohledu na ochranu pomocí oprávnění či exportovaný stav."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavit kompatibilitu obrazovky"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"navázat se na službu usnadnění přístupu"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby usnadnění přístupu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"navázat se na tiskovou službu"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Umožňuje navázání na nejvyšší úroveň tiskové služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"přístup ke všem tiskovým úlohám"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Umožňuje přístup k tiskovým úlohám vytvořeným jinou aplikací. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"navázat se na textovou službu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteli připojit se k nejvyšší úrovni rozhraní textové služby (např. SpellCheckerService). Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"navázat se na službu VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"přidat nebo odebrat správce zařízení"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Opravňuje držitele přidávat nebo odebírat aktivní správce zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Umožňuje aplikaci kdykoli změnit otočení obrazovky. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"změna rychlosti kurzoru"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čtení vyrovnávací paměti snímků"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Umožňuje aplikaci číst obsah vyrovnávací paměti snímků."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"přístup k funkci InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Umožňuje aplikaci používat nízkoúrovňové funkce InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurovat displeje přes Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Povoluje aplikaci připojit a konfigurovat displeje přes Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládat displeje přes Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Povoluje aplikaci ovládat základní funkce displejů přes Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"změna nastavení zvuku"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Umožňuje aplikaci změnit globální nastavení zvuku, například hlasitost či reproduktor pro výstup zvuku."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"nahrávání zvuku"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Umožňuje aplikaci zapisovat na kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Upravit/smazat interní úlož."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Umožňuje aplikaci upravovat obsah interního úložiště médií."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"spravovat úložiště dokumentů"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Umožňuje aplikaci spravovat úložiště dokumentů."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"přístup k externímu úložišti všech uživatelů"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Umožňuje aplikaci přistupovat k externímu úložišti pro všechny uživatele."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"přistupovat do souborového systému mezipaměti"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikaci spravovat zásady sítě a definovat pravidla pro konkrétní aplikace."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"upravit kontrolu používání sítě"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"upravit značky soketů"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Umožňuje aplikaci upravit značky soketů pro směrování"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteli navázat se na nejvyšší úroveň služby pro poslouchání oznámení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolat konfigurační aplikaci poskytnutou operátorem"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Vložte SIM kartu."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná karta SIM."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaše SIM karta byla natrvalo zablokována."\n" Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaše SIM karta byla natrvalo zablokována.\n Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Tlačítko Předchozí stopa"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Tlačítko Další stopa"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Tlačítko Pozastavit"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Další informace naleznete v uživatelské příručce; nebo kontaktujte zákaznickou podporu."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM karta je zablokována."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odblokování SIM karty..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste použili nesprávné bezpečnostní gesto. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali kód PIN. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení tabletu pomocí přihlášení Google."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení Google."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste použili nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení tabletu pomocí přihlášení Google.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení Google.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Tablet jste se pokusili nesprávným způsobem odemknout <xliff:g id="NUMBER_0">%d</xliff:g>krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v tabletu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Telefon jste se pokusili nesprávným způsobem odemknout <xliff:g id="NUMBER_0">%d</xliff:g>krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v telefonu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tablet jste se pokusili nesprávným způsobem odemknout <xliff:g id="NUMBER">%d</xliff:g>krát. V tabletu se nyní obnoví výchozí tovární nastavení."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Heslo"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Přihlásit se"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Neplatné uživatelské jméno nebo heslo."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zapomněli jste uživatelské jméno nebo heslo?"\n"Přejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zapomněli jste uživatelské jméno nebo heslo?\nPřejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrola..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Odemknout"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Zapnout zvuk"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potvrďte přechod"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Opustit stránku"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Zůstat na této stránce"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Opravdu tuto stránku chcete opustit?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nOpravdu tuto stránku chcete opustit?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím můžete zobrazení přiblížit nebo oddálit."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.vyp."</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> bohužel přestala pracovat."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> byl bohužel ukončen."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikace <xliff:g id="APPLICATION">%2$s</xliff:g> nereaguje."\n\n"Chcete ji ukončit?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivita <xliff:g id="ACTIVITY">%1$s</xliff:g> nereaguje."\n\n"Chcete ji ukončit?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikace <xliff:g id="APPLICATION">%2$s</xliff:g> nereaguje.\n\nChcete ji ukončit?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivita <xliff:g id="ACTIVITY">%1$s</xliff:g> nereaguje.\n\nChcete ji ukončit?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> nereaguje. Chcete ji ukončit?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nereaguje."\n\n"Chcete jej ukončit?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nereaguje.\n\nChcete jej ukončit?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Hlášení"</string>
     <string name="wait" msgid="7147118217226317732">"Počkat"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje."\n\n"Chcete ji zavřít?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje.\n\nChcete ji zavřít?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Přesměrování aplikace"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Je spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Původně byla spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Umožňuje aplikaci dát výchozí službě kontejneru příkaz ke zkopírování obsahu. Toto oprávnění není určeno pro běžné aplikace."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Směrování výstupu médií"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Umožňuje aplikaci směrovat výstup médií do dalších externích zařízení."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Přístup k bezpečnému úložišti keyguard"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Umožňuje aplikaci přístup k bezpečnému úložišti keyguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Ovládání zobrazování a skrývání zámku obrazovky"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikaci ovládat zámek obrazovky."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dvojitým dotykem můžete ovládat přiblížení"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget nelze přidat."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Přejít"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Hotovo"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Předch."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Spustit"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Vytočit číslo"\n" <xliff:g id="NUMBER">%s</xliff:g>."</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Vytvořit kontakt"\n"pro <xliff:g id="NUMBER">%s</xliff:g>."</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Vytočit číslo\n <xliff:g id="NUMBER">%s</xliff:g>."</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Vytvořit kontakt\npro <xliff:g id="NUMBER">%s</xliff:g>."</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Následující aplikace požadují oprávnění k přístupu do vašeho účtu (nyní i v budoucnu)."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Chcete tento požadavek povolit?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Žádost o přístup"</string>
     <string name="allow" msgid="7225948811296386551">"Povolit"</string>
     <string name="deny" msgid="2081879885755434506">"Odepřít"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Požadováno oprávnění"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Požadováno oprávnění"\n"pro účet <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Požadováno oprávnění\npro účet <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Metoda zadávání dat"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronizace"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Usnadnění"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Připojování…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Dostupná"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Není k dispozici"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Používá se"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integrovaná obrazovka"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Obrazovka HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Překryvná vrstva č. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezdrátový displej je připojen"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tato obrazovka se zobrazuje v jiném zařízení"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojit"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávné gesto"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nesprávné heslo"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Nesprávný kód PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zkuste to znovu za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zkuste to znovu za <xliff:g id="NUMBER">%1$d</xliff:g> s."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Nakreslete gesto"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadejte kód PIN SIM karty"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Zadejte kód PIN"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Přihlásit se"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné uživatelské jméno nebo heslo."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zapomněli jste uživatelské jméno nebo heslo?"\n"Přejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zapomněli jste uživatelské jméno nebo heslo?\nPřejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontrola účtu…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v tabletu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v telefonu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. V tabletu se nyní obnoví výchozí tovární nastavení."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. V telefonu se nyní obnoví výchozí tovární nastavení."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odebrat"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Zvýšit hlasitost nad doporučenou úroveň?"\n"Dlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Zvýšit hlasitost nad doporučenou úroveň?\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Usnadnění zapnete dlouhým stisknutím dvěma prsty."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Usnadnění přístupu je aktivováno."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Usnadnění zrušeno."</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Vlastník"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Chyba"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Tato aplikace nepodporuje účty pro omezené profily."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Tato aplikace nepodporuje účty pro omezené profily"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Aplikace potřebná k provedení této akce nebyla nalezena"</string>
     <string name="revoke" msgid="5404479185228271586">"Zrušit"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Zrušeno"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Při zápisu obsahu došlo k chybě"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Zadejte kód PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Aktuální kód PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nový kód PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrďte nový PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvořit kód PIN pro úpravy omezení"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN se neshodují. Zkuste to znovu."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je příliš krátký. Musí mít alespoň čtyři číslice."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Nesprávný kód PIN. Zkuste to znovu za jednu sekundu."</item>
+    <item quantity="other" msgid="8030607343223287654">"Nesprávný kód PIN. Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 6c9a5f3..8566763 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Appen kan gøre dette uden din bekræftelse."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrere aktivitetsstakke"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Tillader, at appen tilføjer, fjerner og ændrer aktivitetsstakkene, hvori andre apps kører. Skadelige apps kan forstyrre adfærden for andre apps."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"starte en aktivitet"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Tillader, at appen starter en hvilken som helst aktivitet, uanset tilladelsesbeskyttelse eller eksporteret tilstand."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"indstil skærmens kompatibilitet"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Tillader, at brugeren kan forpligter sig til en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind dig til en tilgængelighedstjeneste"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Tillader, at brugeren binder sig til en grænseflade for en tilgængelighedstjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"forbinde til en udskriftstjeneste"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Tillader, at brugeren forbinder til grænsefladen for en udskriftstjeneste på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"få adgang til alle udskriftsjob"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Tillader, at brugeren får adgang til udskriftsjob, der er oprettet af en anden app. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"Knyt til NFC-tjeneste"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Tillader, at indehaveren opretter tilknytninger til applikationer, der efterligner NFC-kort. Dette bør aldrig være nødvendigt for normale apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"forpligte sig til en sms-tjeneste"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillader, at ejeren kan binde en teksttjenestes grænseflade (f. eks. SpellCheckerService) på øverste niveau. Dette bør aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind til en VPN-tjeneste"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tilføje eller fjerne en enhedsadministrator"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillader, at man tilføjer eller fjerner aktive enhedsadministratorer. Dette burde aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Tillader, at appen kan ændre skærmretningen på et hvilket som helst tidspunkt. Bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ændre markørens hastighed"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Tillader, at appen kan bruge SurfaceFlinger-funktioner på lavt niveau."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"læs rammebuffer"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Tillader, at appen kan læse indholdet fra rammebufferen."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"få adgang til InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Giver appen tilladelse til at bruge SurfaceFlinger-funktioner på lavt niveau."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurer Wi-Fi-skærme"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillader, at appen konfigurerer og opretter forbindelse til Wi-Fi-skærme."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollér Wi-Fi-skærme"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillader, at appen kontrollerer Wi-Fi-skærmfunktioner på lavt niveau."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"skift dine lydindstillinger"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Tillader, at appen kan ændre globale lydindstillinger, som f.eks. lydstyrke og hvilken højttaler der bruges til output."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"optage lyd"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillader, at appen kan skrive til SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Rediger/slet internt medielagringsindhold"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Tillader, appen kan ændre indholdet af det interne medielager."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"administrer dokumentlagring"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Tillader, at appen kan administrere dokumentlagring."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"få adgang til alle brugeres eksterne lagre"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Tillader, at appen får adgang til eksterne lagre for alle brugere."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"få adgang til cache-filsystemet"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"ændre socketmærker"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Tillader, at appen ændrer socketmærker ved omdirigering"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder dem, der er sendt af andre apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"aktivere konfigurationsappen, der leveres af mobilselskabet"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er forsynet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Indsæt et SIM-kort."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-kortet mangler eller kan ikke læses. Indsæt et SIM-kort."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Ubrugeligt SIM-kort."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Dit SIM-kort er blevet permanent deaktiveret."\n"Kontakt din tjenesteudbyder for at få et nyt SIM-kort."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Dit SIM-kort er blevet permanent deaktiveret.\nKontakt din tjenesteudbyder for at få et nyt SIM-kort."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Knap til forrige nummer"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Knap til næste nummer"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pause-knap"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Se brugervejledningen, eller kontakt kundeservice."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet er låst."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser SIM-kortet op ..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere forsøg vil du blive bedt om at låse din tablet op ved hjælp af dit Google-login"\n\n"  Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg til vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login."\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere forsøg vil du blive bedt om at låse din tablet op ved hjælp af dit Google-login\n\n  Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg til vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter yderligere <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg nulstilles tabletten til fabriksindstillingerne, og alle brugerdata mistes."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter yderligere <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg, nulstilles telefonen til fabriksindstillingerne, og alle brugerdata mistes."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Tabletten nulstilles til fabriksindstillingerne."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Adgangskode"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Log ind"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Har du glemt dit brugernavn eller din adgangskode?"\n"Besøg "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Har du glemt dit brugernavn eller din adgangskode?\nBesøg "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrollerer..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Lås op"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Lyd slået til"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Bekræft navigation"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Forlad denne side"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bliv på denne side"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Er du sikker på, at du vil navigere væk fra denne side?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nEr du sikker på, at du vil navigere væk fra denne side?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip! Dobbeltklik for at zoome ind eller ud."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyld"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Applikationen <xliff:g id="APPLICATION">%1$s</xliff:g> er desværre stoppet."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> er desværre stoppet."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarer ikke."\n\n"Vil du lukke den?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarer ikke."\n\n"Vil du at lukke den?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarer ikke.\n\nVil du lukke den?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarer ikke.\n\nVil du at lukke den?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> svarer ikke. Vil du lukke den?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke."\n\n"Vil du lukke den?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke.\n\nVil du lukke den?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapportér"</string>
     <string name="wait" msgid="7147118217226317732">"Vent"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke."\n\n"Vil du lukke den?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke.\n\nVil du lukke den?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Appen er omdirigeret"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører nu."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> blev oprindeligt åbnet."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Tillader, at appen kan benytte standardlagertjenesten til at kopiere indhold. Anvendes ikke af almindelige apps."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Viderefør medieoutput"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Tillader, at en applikation viderefører medieoutput til andre eksterne enheder."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Få adgang nøglebeskyttet lager"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Tillader, at en applikation får adgang til et nøglebeskyttet lager."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Administrer, om nøglebeskyttelse skal vises eller skjules"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillader, at en applikation styrer nøglebeskyttelsen."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tryk to gange for zoomstyring"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget kunne ikke tilføjes."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Gå"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Afslut"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Forrige"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Udfør"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Ring til nummer"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Opret kontakt"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Ring til nummer\nved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Opret kontakt\nved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Følgende app eller apps anmoder om at få adgang til din konto nu og fremover."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vil du tillade denne anmodning?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Anmodning om adgang"</string>
     <string name="allow" msgid="7225948811296386551">"Tillad"</string>
     <string name="deny" msgid="2081879885755434506">"Afvis"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Der er anmodet om tilladelse"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Der er anmodet om tilladelse"\n"for kontoen <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Der er anmodet om tilladelse\nfor kontoen <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Inputmetode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synkroniser"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgængelighed"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Opretter forbindelse..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tilgængelig"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ikke tilgængelig"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"I brug"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Indbygget skærm"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skærm"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlejring nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sikker"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Der er tilsluttet en trådløs skærm"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Denne skærm vises på en anden enhed"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Afbryd forbindelsen"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Forkert mønster"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Forkert adgangskode"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%1$d</xliff:g> sekunder."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Adgangskode"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Log ind"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt dit brugernavn eller din adgangskode?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt dit brugernavn eller din adgangskode?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontoen kontrolleres…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg nulstilles tabletten til fabriksindstillingerne, og alle brugerdata mistes."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg, nulstilles telefonen til fabriksindstillingerne, og alle brugerdata mistes."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Tabletten nulstilles til fabriksindstillingerne."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles til fabriksindstillingerne."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto."\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Skal lydstyrken være over det anbefalede niveau?"\n"Du kan skade din hørelse ved at lytte ved høj lydstyrke i længere tid."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Skal lydstyrken være over det anbefalede niveau?\nDu kan skade din hørelse ved at lytte ved høj lydstyrke i længere tid."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hold fortsat to fingre nede for at aktivere tilgængelighed."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tilgængelighed aktiveret."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgængelighed er annulleret."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Ejer"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Fejl"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Denne applikation understøtter ikke konti for begrænsede profiler"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Denne applikation understøtter ikke konti for begrænsede profiler"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Der blev ikke fundet nogen applikation, der kan håndtere denne handling"</string>
     <string name="revoke" msgid="5404479185228271586">"Tilbagekald"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Amerikansk \"Letter\""</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Amerikansk \"Government Letter\""</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Amerikansk \"Legal\""</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Amerikansk \"Junior Legal\""</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Amerikansk \"Ledger\""</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Amerikansk \"Tabloid\""</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annulleret"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fejl ved skrivning af indhold"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Indtast pinkode"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Aktuel pinkode:"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Ny pinkode"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Bekræft den nye pinkode"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Opret en pinkode til ændring af begrænsninger"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Pinkoderne stemmer ikke overens. Prøv igen."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pinkoden er for kort. Den skal være på mindst 4 tal."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Forkert pinkode. Prøv igen om 1 sekund."</item>
+    <item quantity="other" msgid="8030607343223287654">"Forkert pinkode. Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 50a7c8c..85f252a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben, ohne dass dazu ein Eingreifen Ihrerseits notwendig ist."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"Aktivitätsstapel verwalten"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ermöglicht der App das Hinzufügen, Entfernen und Ändern der Aktivitätsstapel, in denen andere Apps ausgeführt werden. Schädliche Apps können das Verhalten anderer Apps beeinträchtigen."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Beliebige Aktivität starten"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ermöglicht der App, ungeachtet der Berechtigungen oder des Exportstatus beliebige Aktivitäten zu starten"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Bildschirmkompatibilität festlegen"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"An eine Bedienungshilfe binden"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ermöglicht dem Halter, sich an die Oberfläche einer Bedienungshilfe auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"An einen Druckdienst binden"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Druckdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"Auf alle Druckaufträge zugreifen"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ermöglicht dem Inhaber den Zugriff auf von einer anderen App erstellte Druckaufträge. Sollte für normale Apps nie benötigt werden."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"An einen Textdienst binden"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ermöglicht dem Halter, sich an die Oberfläche eines Textdienstes auf oberster Ebene zu binden, z. B. eines Rechtschreibprüfungsdienstes. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"An einen VPN-Dienst binden"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Geräteadministrator hinzufügen oder entfernen"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ermöglicht dem Inhaber, aktive Geräteadministratoren hinzuzufügen oder zu entfernen. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ermöglicht der App, die Bildschirmdrehung jederzeit zu ändern. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Zeigergeschwindigkeit ändern"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ermöglicht der App, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ermöglicht der App, den Inhalt des Frame-Puffers zu lesen"</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"Auf InputFlinger zugreifen"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ermöglicht der App, die systemnahen InputFlinger-Funktionen zu verwenden"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"WLAN-Anzeigen konfigurieren"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Erlaubt der App, WLAN-Anzeigen zu konfigurieren und eine Verbindung zu diesen herzustellen"</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WLAN-Anzeigen steuern"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Erlaubt der App, untergeordnete Funktionen von WLAN-Anzeigen zu steuern"</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ermöglicht der App, globale Audio-Einstellungen zu ändern, etwa die Lautstärke und den Lautsprecher für die Ausgabe."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ermöglicht der App, auf die SD-Karte zu schreiben"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Internen Medienspeicher ändern/löschen"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ermöglicht der App, den Inhalt des internen Medienspeichers zu ändern"</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"Dokumentenspeicher verwalten"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"App kann Dokumentenspeicher verwalten"</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Auf externen Speicher aller Nutzer zugreifen"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Ermöglicht der App, auf externen Speicher aller Nutzer zuzugreifen."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Auf das Cache-Dateisystem zugreifen"</string>
@@ -625,22 +651,26 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ermöglicht der App, Netzwerkrichtlinien zu verwalten und anwendungsspezifische Regeln festzulegen"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Zuordnung für Netzwerknutzung ändern"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"Socket-Markierungen ändern"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ermöglicht der App das Ändern von Socket-Markierungen für das Routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Tablet sperren oder alle Daten auf dem Tablet löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Bildschirms überwachen und Telefon sperren oder alle Daten auf dem Telefon löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Displays ändern"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Passwort zum Entsperren des Bildschirms ändern"</string>
+    <string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Bildschirms ändern"</string>
+    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ändern Sie das Passwort zum Entsperren des Bildschirms."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Display sperren"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Legen Sie fest, wie und wann der Bildschirm gesperrt wird."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setzen Sie das Telefon auf Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den bei aktivierter Richtlinie zu verwendenden globalen Proxy des Geräts festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf von Sperr-Passwort festlegen"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Legen Sie eine SIM-Karte ein."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-Karte fehlt oder ist nicht lesbar. Bitte legen Sie eine SIM-Karte ein."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-Karte unbrauchbar"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ihre SIM-Karte wurde dauerhaft deaktiviert."\n" Wenden Sie sich an Ihren Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ihre SIM-Karte wurde dauerhaft deaktiviert.\n Wenden Sie sich an Ihren Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Schaltfläche für vorherigen Track"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Schaltfläche für nächsten Track"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Schaltfläche für Pause"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhalten Sie im Nutzerhandbuch oder beim Kundendienst."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"PIN eingeben"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe Ihrer Google-Anmeldeinformationen zu entsperren."\n\n" Bitte versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren."\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\n Bitte versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden noch einmal."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g> Mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g> Mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passwort"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Anmelden"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ungültiger  Nutzername oder ungültiges Passwort."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nutzernamen oder Passwort vergessen?"\n"Besuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nutzernamen oder Passwort vergessen?\nBesuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Überprüfung..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Entsperren"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ton ein"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Navigation bestätigen"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Diese Seite verlassen"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Auf dieser Seite bleiben"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Möchten Sie diese Seite wirklich verlassen?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchten Sie diese Seite wirklich verlassen?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: Zum Vergrößern und Verkleinern zweimal tippen"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"AutoFill"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"\"<xliff:g id="APPLICATION">%1$s</xliff:g>\" wurde beendet."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Der Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" wurde beendet."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht."\n\n"Möchten Sie die App schließen?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht."\n\n"Möchten Sie sie beenden?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht.\n\nMöchten Sie die App schließen?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht.\n\nMöchten Sie sie beenden?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht. Möchten Sie die App schließen?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht."\n\n"Möchten Sie ihn beenden?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht.\n\nMöchten Sie ihn beenden?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Bericht"</string>
     <string name="wait" msgid="7147118217226317732">"Warten"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr."\n\n"Möchten Sie die Seite schließen?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr.\n\nMöchten Sie die Seite schließen?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App umgeleitet"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird jetzt ausgeführt."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> wurde ursprünglich gestartet."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ermöglicht der App das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalten. Nicht für normale Apps vorgesehen."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medienausgabe umleiten"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht einer App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Zugriff auf mit Keyguard geschützten Speicher"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ermöglicht einer App den Zugriff auf mit Keyguard geschützten Speicher"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Anzeige und Ausblenden des Keyguard steuern"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Apps können den Keyguard steuern."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Für Zoomeinstellung zweimal berühren"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget konnte nicht hinzugefügt werden."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Fertig"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Zurück"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Ausführen"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Nummer"\n"mit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Neuer Kontakt"\n"mit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Nummer\nmit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Neuer Kontakt\nmit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Die folgenden Apps benötigen die Berechtigung zum aktuellen und zukünftigen Zugriff auf Ihr Konto."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Möchten Sie diese Anfrage zulassen?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zugriffsanforderung"</string>
     <string name="allow" msgid="7225948811296386551">"Zulassen"</string>
     <string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Berechtigung angefordert"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Berechtigung angefordert"\n"für Konto <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Berechtigung angefordert\nfür Konto <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Eingabemethode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronisieren"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Bedienungshilfen"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Verbindung wird hergestellt..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Verfügbar"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nicht verfügbar"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"In Verwendung"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integrierter Bildschirm"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-Bildschirm"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay-Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sicher"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Kabellose Übertragung (WiDi) ist aktiviert."</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Dieser Bildschirm wird auf einem anderen Gerät angezeigt."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbindung trennen"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Falsches Muster"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Falsches Passwort"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Falsche PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuchen Sie es in <xliff:g id="NUMBER">%1$d</xliff:g> Sekunden erneut."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Muster zeichnen"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM-PIN eingeben"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN eingeben"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Passwort"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Anmelden"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ungültiger Nutzername oder ungültiges Passwort"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?"\n"Besuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?\nBesuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto wird geprüft…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Lautstärke über den Schwellenwert anheben?"\n"Wenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Lautstärke über den Schwellenwert anheben?\nWenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Drücken Sie mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Bedienungshilfen aktiviert"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Bedienungshilfen abgebrochen"</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Eigentümer"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Fehler"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Diese App unterstützt keine Konten für eingeschränkte Profile."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Diese App unterstützt keine Konten für eingeschränkte Profile."</string>
     <string name="app_not_found" msgid="3429141853498927379">"Für diese Aktion wurde keine App gefunden."</string>
     <string name="revoke" msgid="5404479185228271586">"Aufheben"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Abgebrochen"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fehler beim Schreiben von Inhalten"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN eingeben"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Aktuelle PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Neue PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Neue PIN bestätigen"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuchen Sie es erneut."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens 4 Ziffern umfassen."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Falsche PIN. In 1 Sek. erneut versuchen."</item>
+    <item quantity="other" msgid="8030607343223287654">"Falsche PIN. In <xliff:g id="COUNT">%d</xliff:g> Sek. erneut versuchen."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 968aba9..b0c338b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και το παρασκήνιο. Η εφαρμογή μπορεί να το κάνει αυτό χωρίς να καταχωρίσετε δεδομένα εισόδου."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"διαχείριση στοιβών δραστηριότητας"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την τροποποίηση των στοιβών δραστηριότητας στις οποίες εκτελούνται άλλες εφαρμογές. Οι κακόβουλες εφαρμογές ενδέχεται να προκαλέσουν προβλήματα στη συμπεριφορά άλλων συσκευών."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"έναρξη οποιασδήποτε δραστηριότητας"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Επιτρέπει στην εφαρμογή την έναρξη οποιασδήποτε δραστηριότητας, ανεξάρτητα από την προστασία αδειών ή την κατάσταση εξαγωγής."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ρύθμιση συμβατότητας οθόνης"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"δέσμευση σε υπηρεσία προσβασιμότητας"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανώτατου επιπέδου μιας υπηρεσίας προσβασιμότητας. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"δέσμευση σε υπηρεσία εκτύπωσης"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας εκτύπωσης. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"πρόσβαση σε όλες τις εργασίες εκτύπωσης"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Επιτρέπει στον κάτοχο να αποκτά πρόσβαση σε εργασίες εκτύπωσης από άλλες εφαρμογές. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"σύνδεση με υπηρεσία NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Δίνει στον κάτοχο τη δυνατότητα σύνδεσης με εφαρμογές που προσομοιώνουν κάρτες NFC. Δεν ζητείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Επιτρέπει στον κάτοχο τη σύνδεση με τη διεπαφή ανωτέρου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων (π.χ. SpellCheckerService). Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"δέσμευση σε υπηρεσία VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"προσθήκη ή κατάργηση ενός διαχειριστή συσκευής"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Επιτρέπει στον κάτοχο να προσθέτει ή να καταργεί ενεργούς διαχειριστές συσκευών. Δεν θα πρέπει να ζητείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Επιτρέπει στην εφαρμογή την αλλαγή της περιστροφής της οθόνης ανά πάσα στιγμή. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"αλλαγή ταχύτητας δείκτη"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες SurfaceFlinger χαμηλού επιπέδου."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ανάγνωση προσωρινής μνήμης πλαισίου"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου της προσωρινής μνήμης πλαισίου."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"πρόσβαση στο InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες InputFlinger χαμηλού επιπέδου."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"διαμόρφωση οθονών Wifi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Επιτρέπει τη διαμόρφωση της εφαρμογής και τη σύνδεσης σε οθόνες Wifi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"έλεγχος οθονών Wifi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Επιτρέπει στην εφαρμογή τον έλεγχο των λειτουργιών χαμηλού επιπέδου των οθονών Wifi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλαγή των ρυθμίσεων ήχου"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Επιτρέπει στην εφαρμογή την τροποποίηση καθολικών ρυθμίσεων ήχου, όπως η ένταση και ποιο ηχείο χρησιμοποιείται για έξοδο."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγραφή ήχου"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Επιτρέπει στην εφαρμογή την εγγραφή στην κάρτα SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"τροπ./διαγ. περ. απ. εσ. μνήμ."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Επιτρέπει στην εφαρμογή να τροποποιήσει τα περιεχόμενα των εσωτερικών μέσων αποθήκευσης."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"διαχείριση αποθ.χώρου εγγράφων"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Επιτρέπει στην εφαρμογή τη διαχείριση του αποθηκευτικού χώρου εγγράφων."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"πρόσβ.εξωτ.χωρ. αποθ. όλων των χρηστ."</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση σε εξωτερικό χώρο αποθήκευσης για όλους τους χρήστες."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"πρόσβαση στο σύστημα αρχείων προσωρινής μνήμης"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"τροποποίηση σημείων υποδοχής"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Επιτρέπει στην εφαρμογή την τροποποίηση σημείων υποδοχής για δρομολόγηση"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Τοποθετήστε μια κάρτα SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Η κάρτα SIM δεν υπάρχει ή δεν είναι δυνατή η ανάγνωσή της. Τοποθετήστε μια κάρτα SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Η κάρτα SIM έχει απενεργοποιηθεί οριστικά."\n" Επικοινωνήστε με τον παροχέα υπηρεσιών ασύρματου δικτύου για να λάβετε μια νέα κάρτα SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Η κάρτα SIM έχει απενεργοποιηθεί οριστικά.\n Επικοινωνήστε με τον παροχέα υπηρεσιών ασύρματου δικτύου για να λάβετε μια νέα κάρτα SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Κουμπί προηγούμενου κομματιού"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Κουμπί επόμενου κομματιού"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Κουμπί παύσης"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Ανατρέξτε στον Οδηγό χρήσης ή επικοινωνήστε με την Εξυπηρέτηση πελατών."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Η κάρτα SIM είναι κλειδωμένη."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Ξεκλείδωμα κάρτας SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Έχετε πληκτρολογήσει τον αριθμό σας PIN εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\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> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση της σύνδεσής σας 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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Έχετε πληκτρολογήσει τον αριθμό σας PIN εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \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> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση της σύνδεσής σας 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">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες, το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις και όλα τα δεδομένα χρήστη θα χαθούν."</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">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές. Το tablet θα επαναφερθεί στην εργοστασιακή προεπιλογή."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Κωδικός πρόσβασης"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Σύνδεση"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;"\n"Επισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;\nΕπισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Έλεγχος..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Ξεκλείδωμα"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ενεργοποίηση ήχου"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Επιβεβαίωση πλοήγησης"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Αποχώρηση από αυτήν τη σελίδα"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Παραμονή σε αυτήν τη σελίδα"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Είστε βέβαιοι ότι θέλετε να απομακρυνθείτε από αυτήν τη σελίδα;"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nΕίστε βέβαιοι ότι θέλετε να απομακρυνθείτε από αυτήν τη σελίδα;"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Συμβουλή: Πατήστε δύο φορές για μεγέθυνση και σμίκρυνση."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Αυτόματη συμπλήρωση"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Δυστυχώς, η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> έχει σταματήσει."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Δυστυχώς, η διαδικασία <xliff:g id="PROCESS">%1$s</xliff:g> έχει σταματήσει."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Η εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g> δεν ανταποκρίνεται."\n\n"Θέλετε να την κλείσετε;"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Η δραστηριότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> δεν ανταποκρίνεται."\n\n"Θέλετε να την κλείσετε;"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Η εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g> δεν ανταποκρίνεται.\n\nΘέλετε να την κλείσετε;"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Η δραστηριότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> δεν ανταποκρίνεται.\n\nΘέλετε να την κλείσετε;"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> δεν ανταποκρίνεται. Θέλετε να την κλείσετε;"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Η διεργασία <xliff:g id="PROCESS">%1$s</xliff:g> δεν ανταποκρίνεται."\n\n"Θέλετε να την κλείσετε;"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Η διεργασία <xliff:g id="PROCESS">%1$s</xliff:g> δεν ανταποκρίνεται.\n\nΘέλετε να την κλείσετε;"</string>
     <string name="force_close" msgid="8346072094521265605">"ΟΚ"</string>
     <string name="report" msgid="4060218260984795706">"Αναφορά"</string>
     <string name="wait" msgid="7147118217226317732">"Αναμονή"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Η σελίδα δεν ανταποκρίνεται πια."\n\n"Θέλετε να την κλείσετε;"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Η σελίδα δεν ανταποκρίνεται πια.\n\nΘέλετε να την κλείσετε;"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Ανακατεύθυνση εφαρμογής"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται τώρα."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Έγινε εκκίνηση πρώτα της εφαρμογής <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Επιτρέπει στην εφαρμογή την κλήση της προεπιλεγμένης υπηρεσίας κοντέινερ για την αντιγραφή περιεχομένου. Δεν χρησιμοποιείται από συνήθεις εφαρμογές."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Διαγραφή διαδρομής δεδομένων εξόδου μέσων"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Επιτρέπει σε μια εφαρμογή τη διαγραφή διαδρομής δεδομένων εξόδου μέσων σε άλλες εξωτερικές συσκευές."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Πρόσβαση στον ασφαλή αποθηκευτικό χώρο με κλείδωμα"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Επιτρέπει σε μια εφαρμογή να αποκτήσει πρόσβαση στον ασφαλή αποθηκευτικό χώρο με κλείδωμα."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Έλεγχος εμφάνισης και απόκρυψης κλειδώματος πληκτρολογίου"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Επιτρέπει σε μια εφαρμογή τον έλεγχο του κλειδώματος πληκτρολογίου."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Αγγίξτε δύο φορές για έλεγχο εστίασης"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Δεν ήταν δυνατή η προσθήκη του γραφικού στοιχείου."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Μετάβαση"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Τέλος"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Προηγ."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Εκτέλεση"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Κλήση αριθμού"\n"με τη χρήση <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Δημιουργία επαφής"\n"με τη χρήση του <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Κλήση αριθμού\nμε τη χρήση <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Δημιουργία επαφής\nμε τη χρήση του <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Η παρακάτω εφαρμογή ή οι παρακάτω εφαρμογές ζητούν άδεια για άμεση πρόσβαση στο λογαριασμό σας, η οποία θα ισχύει και για μελλοντική χρήση."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Θέλετε να επιτρέψετε αυτή την αίτηση;"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Αίτημα πρόσβασης"</string>
     <string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
     <string name="deny" msgid="2081879885755434506">"Άρνηση"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Απαιτείται άδεια"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Ζητήθηκε άδεια"\n"για τον λογαριασμό <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Ζητήθηκε άδεια\nγια τον λογαριασμό <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Μέθοδος εισόδου"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Συγχρονισμός"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Προσβασιμότητα"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Σύνδεση…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Διαθέσιμη"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Μη διαθέσιμο"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Σε χρήση"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ενσωματωμένη οθόνη"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Οθόνη HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Επικάλυψη #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ασφαλές"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Έχει συνδεθεί ασύρματη οθόνη"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Αυτή η οθόνη εμφανίζεται σε μια άλλη συσκευή"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Αποσύνδεση"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Εσφαλμένο μοτίβο"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Εσφαλμένος κωδικός πρόσβασης"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Εσφαλμένος κωδικός PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Δοκιμάστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Δοκιμάστε ξανά σε <xliff:g id="NUMBER">%1$d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Σχεδιάστε το μοτίβο σας"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Εισαγωγή PIN SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Πληκτρολογήστε το PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Κωδικός πρόσβασης"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Σύνδεση"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;"\n"Επισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;\nΕπισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Έλεγχος λογαριασμού…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Έχετε πληκτρολογήσει εσφαλμένα τον κωδικό σας 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_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">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες, το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις και όλα τα δεδομένα χρήστη θα χαθούν."</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">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές. Το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις."</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> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου."\n\n" Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <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>
+    <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> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Κατάργηση"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;"\n"Αν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Αγγίξτε παρατεταμένα με δύο δάχτυλα για να ενεργοποιήσετε τη λειτουργία προσβασιμότητας."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Ενεργοποιήθηκε η προσβασιμότητα."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Η λειτουργία προσβασιμότητας ακυρώθηκε."</string>
     <string name="user_switched" msgid="3768006783166984410">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Κάτοχος"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Σφάλμα"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Αυτή η εφαρμογή δεν υποστηρίζει λογαριασμούς για περιορισμένα προφίλ"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Αυτή η εφαρμογή δεν υποστηρίζει λογαριασμούς για περιορισμένα προφίλ"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Δεν υπάρχει εφαρμογή για τη διαχείριση αυτής της ενέργειας"</string>
     <string name="revoke" msgid="5404479185228271586">"Ανάκληση"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Επιστολή"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Κρατική επιστολή"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Νομικό"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Λογιστικό"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Ακυρώθηκε"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Σφάλμα κατά την εγγραφή περιεχομένου"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Εισαγωγή PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Ισχύων κωδικός PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Νέος κωδικός PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Επιβεβαίωση νέου κωδικού PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Δημιουργία PIN για τροποποίηση περιορισμών"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Τα PIN δεν συμφωνούν. Προσπαθήστε ξανά."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Το PIN είναι υπερβολικά μικρό. Πρέπει να έχει μέγεθος τουλάχιστον 4 χαρακτήρων."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Λάθος PIN. Προσπαθήστε ξανά σε 1 δευτερόλεπτο."</item>
+    <item quantity="other" msgid="8030607343223287654">"Λάθος PIN. Προσπαθήστε ξανά σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a37c945..68ef4b1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Allows the app to move tasks to the foreground and background. The app may do this without your input."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"manage activity stacks"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Allows the app to add, remove and modify the activity stacks in which other apps run. Malicious apps may disrupt the behaviour of other apps."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"start any activity"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Allows the app to start any activity, regardless of permission protection or exported state."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"set screen compatibility"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Allows the holder to bind to the top-level interface of an input method. Should never be needed for normal apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind to an accessibility service"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Allows the holder to bind to the top-level interface of an accessibility service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"bind to a print service"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Allows the holder to bind to the top-level interface of a print service. Should never be needed for normal apps."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"access all print jobs"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Allows the holder to access print jobs created by another app. Should never be needed for normal apps."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"bind to NFC service"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Allows the holder to bind to applications that are emulating NFC cards. Should never be needed for normal apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind to a text service"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Allows the holder to bind to the top-level interface of a text service (e.g. SpellCheckerService). Should never be needed for normal applications."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind to a VPN service"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Allows the app to change the rotation of the screen at any time. Should never be needed for normal apps."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"change pointer speed"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Allows the app to use SurfaceFlinger low-level features."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"read frame buffer"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Allows the app to read the content of the frame buffer."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"access InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Allows the app to use InputFlinger low-level features."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configure Wi-Fi displays"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Allows the app to configure and connect to Wi-Fi displays."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control Wi-Fi displays"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"change your audio settings"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"record audio"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Allows the app to write to the SD card."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modify/delete internal media storage contents"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Allows the app to modify the contents of the internal media storage."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"manage document storage"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Allows the app to manage document storage."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"access external storage of all users"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Allows the app to access external storage for all users."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"access the cache file system"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Allows the app to manage network policies and define app-specific rules."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modify network usage accounting"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modify socket marks"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Allows the app to modify socket marks for routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Net Meeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insert a SIM card."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"The SIM card is missing or not readable. Insert a SIM card."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Unusable SIM card."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Your SIM card has been permanently disabled."\n" Contact your wireless service provider for another SIM card."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Your SIM card has been permanently disabled.\n Contact your wireless service provider for another SIM card."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Previous track button"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Next-track button"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pause button"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"See the User Guide or contact Customer Care."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM card is locked."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Unlocking SIM card…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using your Google sign-in."\n\n" Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"You have drawn your unlock pattern incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using your Google sign-in.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"You have drawn your unlock pattern incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in.\n\n Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the tablet will be reset to factory default and all user data will be lost."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the phone will be reset to factory default and all user data will be lost."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The tablet will now be reset to factory default."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Password"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Sign in"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Invalid username or password."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Forgot your username or password?"\n"Visit "<b>"google.co.uk/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Forgot your username or password?\nVisit "<b>"google.co.uk/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Checking…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Unlock"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sound on"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirm Navigation"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Leave this Page"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Stay on this Page"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Are you sure you want to navigate away from this page?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nAre you sure you want to navigate away from this page?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirm"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: double-tap to zoom in and out."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Auto-fill"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Unfortunately, <xliff:g id="APPLICATION">%1$s</xliff:g> has stopped."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Unfortunately, the process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> isn\'t responding."\n\n"Do you want to close it?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> isn\'t responding."\n\n"Do you want to close it?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> isn\'t responding.\n\nDo you want to close it?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> isn\'t responding.\n\nDo you want to close it?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> isn\'t responding. Do you want to close it?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Process <xliff:g id="PROCESS">%1$s</xliff:g> isn\'t responding."\n\n"Do you want to close it?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Process <xliff:g id="PROCESS">%1$s</xliff:g> isn\'t responding.\n\nDo you want to close it?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Report"</string>
     <string name="wait" msgid="7147118217226317732">"Wait"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"The page has become unresponsive."\n\n"Do you want to close it?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"The page has become unresponsive.\n\nDo you want to close it?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App redirected"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is now running."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was originally launched."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Allows the app to invoke default container service to copy content. Not for use by normal apps."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Route media output"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Allows an application to route media output to other external devices."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Access keyguard secure storage"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Allows an application to access keyguard secure storage."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Control displaying and hiding keyguard"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Touch twice for zoom control"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Couldn\'t add widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Go"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Done"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Prev"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Execute"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Dial number"\n" using <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Create contact"\n" using <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Dial number\n using <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Create contact\n using <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"The following one or more applications request permission to access your account, now and in the future."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Do you want to allow this request?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Access request"</string>
     <string name="allow" msgid="7225948811296386551">"Allow"</string>
     <string name="deny" msgid="2081879885755434506">"Deny"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permission requested"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permission requested"\n"for account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permission requested\nfor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Input Method"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sync"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibility"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connecting..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Not available"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"In use"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Built-in Screen"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI Screen"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Wireless display is connected"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"This screen is showing on another device"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnect"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Wrong Password"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Wrong PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Try again in <xliff:g id="NUMBER">%1$d</xliff:g> seconds."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Draw your pattern"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Enter SIM PIN"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Enter PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?"\n"Visit "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?\nVisit "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Checking account…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the tablet will be reset to factory default and all user data will be lost."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the phone will be reset to factory default and all user data will be lost."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The tablet will now be reset to factory default."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The phone will now be reset to factory default."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account."\n\n" Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account."\n\n" Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Raise volume above recommended level?"\n"Listening at high volume for long periods may damage your hearing."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Raise volume above recommended level?\nListening at high volume for long periods may damage your hearing."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Keep holding down two fingers to enable accessibility."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibility enabled."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibility cancelled."</string>
     <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Owner"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"This application does not support accounts for restricted profiles"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"This app doesn\'t support accounts for restricted profiles"</string>
     <string name="app_not_found" msgid="3429141853498927379">"No application found to handle this action"</string>
     <string name="revoke" msgid="5404479185228271586">"Revoke"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelled"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error writing content"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Enter PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Current PIN:"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"New PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirm new PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Create a PIN for modifying restrictions"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINs don\'t match. Try again."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is too short. Must be at least 4 digits."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Incorrect PIN. Try again in 1 second."</item>
+    <item quantity="other" msgid="8030607343223287654">"Incorrect PIN. Try again in <xliff:g id="COUNT">%d</xliff:g> seconds."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a39e61f..16c16bd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que la aplicación mueva tareas a segundo o a primer plano. La aplicación puede utilizar este permiso para realizar estos movimientos sin indicártelo."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrar pilas de actividad"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que la aplicación agregue, elimine y modifique las pilas de actividad en las que se ejecutan otras aplicaciones. Las aplicaciones maliciosas pueden interrumpir el comportamiento de otras aplicaciones."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Iniciar cualquier actividad"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite a la aplicación iniciar una actividad, sin importar si fue exportada ni si se encuentra protegida por permisos."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Definir compatibilidad de pantalla"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a un servicio de accesibilidad"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincular a un servicio de impresión"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de impresión. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acceder a todos los trabajos de impresión"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite al propietario acceder a trabajos de impresión creados con otra aplicación. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a un servicio de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de texto (p. ej., SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular con un servicio de VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"agregar o eliminar un administrador de dispositivos"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite al propietario agregar o eliminar administradores de dispositivos activos. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que la aplicación cambie la rotación de la pantalla en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambiar velocidad del puntero"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación utilice funciones de SurfaceFlinger de bajo nivel."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que la aplicación lea el contenido del búfer de tramas."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acceder a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que la aplicación utilice funciones de InputFlinger de bajo nivel."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar pantallas Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure y se conecte a pantallas Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de las pantallas Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"cambiar tu configuración de audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que la aplicación modifique la configuración de audio global, por ejemplo, el volumen y el altavoz de salida."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"grabar audio"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Admite que la aplicación escriba en la tarjeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar/eliminar los contenidos del almacenamientos de medios internos"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que la aplicación modifique el contenido del almacenamiento de medios interno."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"Administrar almac. de documen."</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permite que la aplicación administre el almacenamiento de documentos."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acceder almacenamiento externo"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que la aplicación acceda al almacenamiento externo de todos los usuarios."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Acceder al sistema de archivos caché"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre las políticas de red y defina reglas específicas de la aplicación."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modificar la administración del uso de redes"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que la aplicación modifique marcas de socket para enrutamiento."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de agente de escucha de notificaciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el proveedor"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Tarjeta SIM inutilizable"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Tu tarjeta SIM se ha inhabilitado de forma permanente."\n" Ponte en contacto con tu proveedor de servicios inalámbricos para obtener otra tarjeta SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Tu tarjeta SIM se ha inhabilitado de forma permanente.\n Ponte en contacto con tu proveedor de servicios inalámbricos para obtener otra tarjeta SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Botón para pista anterior"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Botón para pista siguiente"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botón Pausa"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La tarjeta SIM está bloqueada."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando tarjeta SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Estableciste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu tablet mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu dispositivo mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Estableciste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu tablet mediante el uso de tu información de acceso de Google.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu dispositivo mediante el uso de tu información de acceso de Google.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica de la tablet y se pierdan todos los datos de usuario."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del dispositivo y se pierdan todos los datos de usuario."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica de la tablet."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inicia sesión"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña incorrecta."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"¿Olvidaste tu nombre de usuario o contraseña?"\n"Accede a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"¿Olvidaste tu nombre de usuario o contraseña?\nAccede a "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Comprobando..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloquear"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sonido activado"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmar navegación"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Abandonar esta página"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Quedarme en la página"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"¿Confirmas que quieres salir de esta página?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n¿Confirmas que quieres salir de esta página?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consejo: Toca dos veces para acercar y alejar la imagen."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Lamentablemente, la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> se detuvo."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Lamentablemente, el proceso <xliff:g id="PROCESS">%1$s</xliff:g> se detuvo."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> no responde."\n\n"¿Deseas cerrarla?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> no responde."\n\n"¿Deseas cerrarla?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> no responde.\n\n¿Deseas cerrarla?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> no responde.\n\n¿Deseas cerrarla?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> no responde. ¿Deseas cerrarla?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde."\n\n"¿Deseas cerrarlo?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde.\n\n¿Deseas cerrarlo?"</string>
     <string name="force_close" msgid="8346072094521265605">"Aceptar"</string>
     <string name="report" msgid="4060218260984795706">"Notificar"</string>
     <string name="wait" msgid="7147118217226317732">"Esperar"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde."\n\n"¿Deseas cerrarla?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde.\n\n¿Deseas cerrarla?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicación redireccionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando ahora."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permite que la aplicación ejecute el servicio de contenedor predeterminado para que copie contenido. Las aplicaciones normales no deben utilizar este permiso."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Dirigir salida de medios"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que la aplicación dirija salidas de medios a otros dispositivos externos."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Acceder al almacenamiento seguro de bloqueos"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que una aplicación acceda al almacenamiento seguro de bloqueos."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar cuándo se muestra y se oculta el bloqueo"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos veces para acceder al control de zoom."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No se pudo agregar el widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Listo"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Ant."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Ejecutar"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Marcar el número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Crear contacto "\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Marcar el número\ncon <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Crear contacto \ncon <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Las siguientes aplicaciones solicitan permiso para acceder a tu cuenta ahora y en el futuro."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"¿Deseas permitir esta solicitud?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitud de acceso"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permiso solicitado"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permiso solicitado"\n"para la cuenta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permiso solicitado\npara la cuenta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Método de entrada"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronización"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"No disponible"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"En uso"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Pantalla HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Se conectó la pantalla inalámbrica"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Vuelve a intentarlo en <xliff:g id="NUMBER">%1$d</xliff:g> segundos."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuja tu patrón."</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingresa el PIN de la tarjeta SIM."</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Ingresa el PIN."</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Acceder"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nombre de usuario o contraseña incorrectos"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"¿Olvidaste tu nombre de usuario o contraseña?"\n"Accede a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"¿Olvidaste tu nombre de usuario o contraseña?\nAccede a "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando la cuenta…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica de la tablet y se pierdan todos los datos del usuario."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del dispositivo y se pierdan todos los datos del usuario."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica de la tablet."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del dispositivo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"¿Quieres subir el volumen por encima del nivel recomendado?"\n"Si escuchas música con el volumen alto durante períodos prolongados, puedes dañar tu audición."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"¿Quieres subir el volumen por encima del nivel recomendado?\nSi escuchas música con el volumen alto durante períodos prolongados, puedes dañar tu audición."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén presionado con dos dedos para activar la accesibilidad."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Se activó la accesibilidad."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Se canceló la accesibilidad."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Propietario"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Esta aplicación no admite cuentas de perfiles restringidos."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicación no admite cuentas de perfiles restringidos."</string>
     <string name="app_not_found" msgid="3429141853498927379">"No se encontró una aplicación para manejar esta acción."</string>
     <string name="revoke" msgid="5404479185228271586">"Revocar"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta del gobierno (EE. UU.)"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Oficio"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Oficio Junior"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Doble carta"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelada"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ingresar PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN actual"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN nuevo"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirmar PIN nuevo"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los PIN no coinciden. Vuelve a intentarlo."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorrecto. Reintentar en 1 s"</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorrecto. Reintentar en <xliff:g id="COUNT">%d</xliff:g> s"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8b666d8..f64c0a0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que la aplicación mueva tareas a segundo o a primer plano. La aplicación puede utilizar este permiso para realizar estos movimientos sin que se lo indique el usuario."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrar pilas de actividad"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que la aplicación añada, elimine y modifique las pilas de actividad en las que se ejecutan otras aplicaciones. Las aplicaciones maliciosas pueden interrumpir el comportamiento de otras aplicaciones."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar una actividad"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que la aplicación inicie una actividad, independientemente de la protección de permisos o de si está exportada."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"establecer compatibilidad de pantalla"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite que se enlace con la interfaz de nivel superior de un método de introducción de texto. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"enlazar con un servicio de accesibilidad"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite enlazar con la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"enlazar con un servicio de impresión"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite enlazar con la interfaz de nivel superior de un servicio de impresión. No debe ser necesario para las aplicaciones normales."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acceder a todos los trabajos de impresión"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite acceder a trabajos de impresión creados con otra aplicación. No debe ser necesario para aplicaciones normales."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"enlazar con servicio NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Permite enlazar con aplicaciones que emulen tarjetas NFC. No debe ser necesario para las aplicaciones normales."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"enlazar con un servicio de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite enlazar con la interfaz de nivel superior de un servicio de texto (por ejemplo, SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"enlazar con un servicio VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"añadir o eliminar un administrador de dispositivos"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite añadir o eliminar administradores de dispositivos activos. No debe ser necesario para aplicaciones normales."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que la aplicación cambie la rotación de la pantalla en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambiar velocidad del puntero"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación use funciones de SurfaceFlinger de nivel inferior."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer memoria de almacenamiento intermedio"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que la aplicación lea el contenido de la memoria de almacenamiento intermedio."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acceder a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar pantallas Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure pantallas Wi-Fi y se conecte a ellas."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de pantallas Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"cambiar la configuración de audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que la aplicación modifique la configuración de audio global (por ejemplo, el volumen y el altavoz de salida)."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"grabar sonido"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que la aplicación escriba en la tarjeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar o eliminar el contenido del almacenamiento de medios interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que la aplicación modifique el contenido del almacenamiento multimedia interno."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"administrar el almacenamiento de documentos"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permite que la aplicación administre el almacenamiento de documentos."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acceder al almacenamiento externo de todos los usuarios"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que la aplicación acceda al almacenamiento externo de todos los usuarios."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acceder al sistema de archivos almacenado en caché"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre políticas de red y defina reglas específicas de la aplicación."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar cálculo de uso de red"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que la aplicación modifique marcas de socket para enrutamiento"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversaciones"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Tarjeta SIM inutilizable"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Tu tarjeta SIM se ha inhabilitado permanentemente."\n" Para obtener otra tarjeta SIM, ponte en contacto con tu proveedor de servicios de telefonía."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Tu tarjeta SIM se ha inhabilitado permanentemente.\n Para obtener otra tarjeta SIM, ponte en contacto con tu proveedor de servicios de telefonía."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Botón de canción anterior"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Botón de siguiente canción"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botón de pausa"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la guía del usuario o ponte en contacto con el servicio de atención al cliente."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Introduce el código PIN."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando tarjeta SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras  <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar tus credenciales de acceso de Google para desbloquear el tablet."\n\n" Inténtalo de nuevo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar tus credenciales de acceso de Google para desbloquear el teléfono."\n\n" Inténtalo de nuevo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. \n\nInténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras  <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar tus credenciales de acceso de Google para desbloquear el tablet.\n\n Inténtalo de nuevo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar tus credenciales de acceso de Google para desbloquear el teléfono.\n\n Inténtalo de nuevo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas <xliff:g id="NUMBER_1">%d</xliff:g> veces más, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas <xliff:g id="NUMBER_1">%d</xliff:g> veces más, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Iniciar sesión"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña no válido"</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Si has olvidado tu nombre de usuario o tu contraseña,"\n"accede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Si has olvidado tu nombre de usuario o tu contraseña,\naccede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Comprobando..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloquear"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Activar sonido"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmar navegación"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Salir de esta página"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Permanecer en esta página"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"¿Seguro que quieres salir de esta página?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n¿Seguro que quieres salir de esta página?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sugerencia: toca dos veces para ampliar o reducir el contenido."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Se ha detenido la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Se ha detenido el proceso <xliff:g id="PROCESS">%1$s</xliff:g>."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"La aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> no responde."\n\n"¿Quieres cerrarla?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> no responde."\n\n"¿Quieres cerrarla?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"La aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> no responde.\n\n¿Quieres cerrarla?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> no responde.\n\n¿Quieres cerrarla?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> no responde. ¿Quieres cerrarla?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde."\n\n"¿Quieres cerrarlo?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde.\n\n¿Quieres cerrarlo?"</string>
     <string name="force_close" msgid="8346072094521265605">"Aceptar"</string>
     <string name="report" msgid="4060218260984795706">"Informar"</string>
     <string name="wait" msgid="7147118217226317732">"Esperar"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde."\n\n"¿Quieres cerrarla?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde.\n\n¿Quieres cerrarla?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicación redireccionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Inicialmente, se inició la aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permite que la aplicación ejecute el servicio de contenedor predeterminado para copiar contenido. Las aplicaciones normales no deben usar este permiso."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Dirigir salida de medio"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que la aplicación dirija salidas de medios a otros dispositivos externos."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Acceder al almacenamiento seguro de bloqueos"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que una aplicación acceda al almacenamiento seguro de bloqueos."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar cuándo se muestra y se oculta el bloqueo"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos veces para acceder al control de zoom."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No se ha podido añadir el widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Listo"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Anterior"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Ejecutar"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Marcar número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Crear un contacto"\n"a partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Marcar número\ncon <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Crear un contacto\na partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Las siguientes aplicaciones solicitan permiso para acceder a tu cuenta ahora y en el futuro."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"¿Quieres permitir esta solicitud?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitud de acceso"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permiso solicitado"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permiso solicitado"\n"para la cuenta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permiso solicitado\npara la cuenta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Método de introducción de texto"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronización"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"No disponible"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"En uso"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Pantalla HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", seguro"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Pantalla inalámbrica conectada"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"El patrón es incorrecto"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Inténtalo de nuevo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Inténtalo de nuevo en <xliff:g id="NUMBER">%1$d</xliff:g> segundos."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuja tu patrón de desbloqueo."</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduce el PIN de la tarjeta SIM."</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduce el PIN."</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sesión"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"El nombre de usuario o la contraseña no son válidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Si has olvidado tu nombre de usuario o tu contraseña,"\n"accede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Si has olvidado tu nombre de usuario o tu contraseña,\naccede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando cuenta…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. "\n\n"Inténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"¿Quieres subir el volumen por encima del nivel recomendado?"\n"Escuchar sonidos a alto volumen durante largos períodos de tiempo puede dañar los oídos."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"¿Quieres subir el volumen por encima del nivel recomendado?\nEscuchar sonidos a alto volumen durante largos períodos de tiempo puede dañar los oídos."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén la pantalla pulsada con dos dedos para habilitar las funciones de accesibilidad."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Accesibilidad habilitada"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilidad cancelada"</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Propietario"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Esta aplicación no admite cuentas de perfiles restringidos"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicación no admite cuentas de perfiles restringidos"</string>
     <string name="app_not_found" msgid="3429141853498927379">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string>
     <string name="revoke" msgid="5404479185228271586">"Revocar"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta del gobierno"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Doble carta"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelado"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introducir PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN actual"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN nuevo"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirma tu nuevo PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los números PIN no coinciden. Inténtalo de nuevo."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorrecto. Inténtalo de nuevo dentro de 1 segundo."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorrecto. Inténtalo de nuevo dentro de <xliff:g id="COUNT">%d</xliff:g> segundos."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 92a1e93..71832c8 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Võimaldab rakendusel teisaldada ülesanded esiplaanile ja taustale. Rakendus võib seda teha teie sisendita."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"käitatud rakenduste peatamine"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Võimaldab rakendusel eemaldada ülesanded ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"tegevusvirnade haldamine"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Lubab rakendusel lisada, eemaldada ja muuta tegevusvirnasid, kus teised rakendused töötavad. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"mis tahes toimingu alustamine"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Võimaldab rakendusel käivitada mis tahes toimingu loa kaitsest või eksporditud olekust sõltumata."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"kuva ühilduvuse seadmine"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lubab omanikul siduda sisestusmeetodi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sidumine juurdepääsuteenusega"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lubab omanikul luua sideme juurdepääsuteenuse ülataseme liidesega. Tavarakenduste puhul ei tohiks seda kunagi vaja minna."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"sidumine printimisteenusega"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Lubab omanikul siduda printimisteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"juurdepääs kõikidele printimistöödele"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Lubab omanikule juurdepääsu teise rakenduse loodud printimistöödele. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"NFC-teenusega sidumine"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Lubab kasutajal luua seosed rakendustega, mis jäljendavad NFC-kaarte. Pole kunagi vajalik tavaliste rakenduste korral."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tekstiteenusega sidumine"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"seo VPN-teenusega"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"seadme administraatori lisamine või eemaldamine"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Võimaldab omanikul lisada või eemaldada aktiivseid seadme administraatoreid. Tavarakenduste puhul ei tohiks see kunagi vajalik olla."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"muuda ekraani paigutust"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Võimaldab rakendusel muuta ekraani pööramist mis tahes ajal. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"kursorikiiruse muutmine"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Võimaldab rakendusel kasutada SurfaceFlingeri madalatasemelisi funktsioone."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"loe kaadripuhvrit"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Võimaldab rakendusel kaadripuhvri sisu lugeda."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"juurdepääs InputFlingerile"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Lubab rakendusel kasutada InputFlingeri madalatasemelisi funktsioone."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"WiFi-ekraanide seadistamine"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Lubab rakendusel seadistada WiFi-ekraane ja nendega ühendus luua."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WiFi-ekraanide juhtimine"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lubab rakendusel juhtida WiFi-ekraanide madala taseme funktsioone."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"muuda heliseadeid"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Võimaldab rakendusel muuta üldiseid heliseadeid, näiteks helitugevust ja seda, millist kõlarit kasutatakse väljundiks."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"salvesta heli"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Võimaldab rakendusel kirjutada SD-kaardile."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sisemälu sisu muutm./kustut."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Võimaldab rakendusel muuta sisemise andmekandja sisu."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"dokumendi talletuse haldamine"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Lubab rakendusel hallata dokumendi talletamist."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"juurdepääs välismäluseadmele (kõikidele kasutajatele)"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Võimaldab rakenduse kõikidel kasutajatel pöörduda välismäluseadme poole."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"juurdepääs vahemälu failisüsteemile"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"sokli märkide muutmine"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Lubab rakendusel muuta marsruutimiseks sokli märke"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Võimaldab omanikul siduda märguannete kuulamisteenuse ülemise taseme kasutajaliidese. Seda ei tohiks tavarakenduste puhul kunagi vaja olla."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operaatoripoolse konfiguratsioonirakenduse aktiveerimine"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lubab omanikul aktiveerida operaatoripoolse konfiguratsioonirakenduse. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Sisestage SIM-kaart."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-kaart puudub või on loetamatu. Sisestage SIM-kaart."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Kasutamiskõlbmatu SIM-kaart."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kaart on jäädavalt keelatud."\n" Teise SIM-kaardi saamiseks võtke ühendust oma traadita side teenusepakkujaga."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kaart on jäädavalt keelatud.\n Teise SIM-kaardi saamiseks võtke ühendust oma traadita side teenusepakkujaga."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Eelmise loo nupp"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Nupp Järgmine rada"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Nupp Peata"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Vaadake kasutusjuhendit või võtke ühendust klienditeenindusega."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kaart on lukus."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-kaardi avamine ..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Olete oma avamismustrit <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti koostanud. "\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. "\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. "\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada Google\'i sisselogimisega."\n\n" Proovige <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada Google\'i sisselogimisega."\n\n" Proovige <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Olete oma avamismustrit <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti koostanud. \n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada Google\'i sisselogimisega.\n\n Proovige <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada Google\'i sisselogimisega.\n\n Proovige <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast uuesti."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> edutut katset lähtestatakse tahvelarvuti tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse telefon tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Olete püüdnud tahvelarvutit <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Tahvelarvuti lähtestatakse nüüd tehase vaikeseadetele."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parool"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logi sisse"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Vale kasutajanimi või parool."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Kas unustasite oma kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Kas unustasite oma kasutajanime või parooli?\nKülastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrollimine ..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Ava"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Heli sisse"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Navigeerimise kinnitamine"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Lahku sellelt lehelt"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Jää sellele lehele"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kas soovite kindlasti sellelt lehelt lahkuda?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nKas soovite kindlasti sellelt lehelt lahkuda?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Kinnita"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Kahjuks on rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> peatunud."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Kahjuks on protsess <xliff:g id="PROCESS">%1$s</xliff:g> peatunud."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ei vasta."\n\n"Kas soovite selle sulgeda?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Tegevus <xliff:g id="ACTIVITY">%1$s</xliff:g> ei vasta."\n\n"Kas soovite selle sulgeda?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ei vasta.\n\nKas soovite selle sulgeda?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Tegevus <xliff:g id="ACTIVITY">%1$s</xliff:g> ei vasta.\n\nKas soovite selle sulgeda?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> ei vasta. Kas soovite selle sulgeda?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Protsess <xliff:g id="PROCESS">%1$s</xliff:g> ei vasta."\n\n"Kas soovite selle sulgeda?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Protsess <xliff:g id="PROCESS">%1$s</xliff:g> ei vasta.\n\nKas soovite selle sulgeda?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Teata"</string>
     <string name="wait" msgid="7147118217226317732">"Oodake"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Leht ei reageeri."\n\n"Kas soovite selle sulgeda?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Leht ei reageeri.\n\nKas soovite selle sulgeda?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Rakendus on ümber suunatud"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nüüd käivitunud."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Algselt käivitati rakendus <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Võimaldab rakendusel võtta sisu kopeerimiseks appi vaikekonteinerteenuse. Mitte kasutada tavarakenduste puhul."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Meediaväljundi teekonna koostamine"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Võimaldab rakendusel koostada teekonna meediaväljundist teistesse välistesse seadmetesse."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Juurdepääs võtmekaitsega turvalisele talletusruumile"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lubab rakendusel hankida juurdepääsu võtmekaitsega turvalisele talletusruumile."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Võtmekaitse kuvamise ja peitmise juhtimine"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lubab rakendusel võtmekaitset juhtida."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Suumi juhtimiseks puudutage kaks korda"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidinat ei saanud lisada."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Mine"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Valmis"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Eelm."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Täida"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Vali number"\n" kasutades numbrit <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Loo kontakt"\n"numbriga <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Vali number\n kasutades numbrit <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Loo kontakt\nnumbriga <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Üks või mitu rakendust taotlevad luba pääseda nüüd ja edaspidi teie kontole juurde."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Kas soovite taotluse lubada?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Juurdepääsutaotlus"</string>
     <string name="allow" msgid="7225948811296386551">"Luba"</string>
     <string name="deny" msgid="2081879885755434506">"Keela"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Taotletud luba"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Luba on taotletud"\n"kontole <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Luba on taotletud\nkontole <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Sisestusmeetod"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sünkroonimine"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Juurdepääsetavus"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Ühendan..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Saadaval"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ei ole saadaval"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Kasutusel"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Sisseehitatud ekraan"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-ekraan"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Ülekate nr .<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", turvaline"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Juhtmeta ekraaniühendus on loodud"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ekraan on näha teises seadmes"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Katkesta ühendus"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Vale muster"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Vale parool"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Vale PIN-kood"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Proovige uuesti <xliff:g id="NUMBER">%1$d</xliff:g> sekundi pärast."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Joonistage oma muster"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Sisestage SIM-i PIN-kood"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Sisestage PIN-kood"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Parool"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Logi sisse"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Vale kasutajanimi või parool."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?\nKülastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto kontrollimine ..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud."\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. "\n\n"Proovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti."\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse tahvelarvuti tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse telefon tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Olete püüdnud tahvelarvutit <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Tahvelarvuti lähtestatakse nüüd tehase vaikeseadetele."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Olete püüdnud telefoni <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Telefon lähtestatakse nüüd tehase vaikeseadetele."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Kas suurendada helitugevust üle soovitatud taseme?"\n"Pikaajaline suure helitugevusega muusika kuulamine võib kahjustada kuulmist."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Kas suurendada helitugevust üle soovitatud taseme?\nPikaajaline suure helitugevusega muusika kuulamine võib kahjustada kuulmist."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hõlbustuse lubamiseks hoidke kaht sõrme all."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Hõlbustus on lubatud."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hõlbustus on tühistatud."</string>
     <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Omanik"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Viga"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"See rakendus ei toeta piiratud profiilide kontosid"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"See rakendus ei toeta piiratud profiilide kontosid"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Selle toimingu käsitlemiseks ei leitud ühtegi rakendust"</string>
     <string name="revoke" msgid="5404479185228271586">"Tühista"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Tühistatud"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Viga sisu kirjutamisel"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Sisestage PIN-kood"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Praegune PIN-kood"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Uus PIN-kood"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Kinnitage uus PIN-kood"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Looge PIN-kood piirangute muutmiseks"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-kood ei sobi. Proovige uuesti."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-kood on liiga lühike. Peab olema vähemalt 4-kohaline."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Vale PIN-kood. Proovige 1 s pärast."</item>
+    <item quantity="other" msgid="8030607343223287654">"Vale PIN-kood. Proovige <xliff:g id="COUNT">%d</xliff:g> s pärast."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 459e1c3..9c863cf 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"به برنامه اجازه می‎دهد تا کارها را به پیش‌زمینه و پس‌زمینه منتقل کند. برنامه‎ ممکن است بدون دخالت شما این کار را انجام دهد."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"متوقف کردن برنامه‎های در حال اجرا"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"به برنامه اجازه می‎دهد تا کارها را حذف کند و برنامه‎های آن‌ها را متوقف کند. برنامه‎های مخرب می‌توانند در اجرای برنامه‎های دیگر اختلال ایجاد ‎کنند."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"مدیریت پشته‌های فعالیت"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"به برنامه اجازه می‌دهد پشته‌های فعالیتی که سایر برنامه‌ها در آنها اجرا می‌شوند را اضافه یا حذف کند و تغییر دهد. برنامه‌های مخرب ممکن است فعالیت برنامه‌های دیگر را مختل کنند."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"شروع هر نوع فعالیت"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"به برنامه اجازه می‎دهد هر فعالیتی را شروع کند بدون اینکه وضعیت صادرشده یا حفاظت با مجوز در نظر گرفته شود."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تنظیم سازگاری با صفحهٔ نمایش"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"به دارنده این دستگاه اجازه می‎دهد تا به رابط سطح بالای یک روش ورودی متصل شود. این ویژگی هیچگاه برای برنامه‎های معمولی ضروری نمی‎باشد."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"اتصال به سرویس دسترسی"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس دسترسی متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"اتصال به یک سرویس چاپ"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"به برنامه اجازه می‌دهد که به رابط سطح بالای سرویس چاپ متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"دسترسی به تمام کارهای چاپ"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"به دارنده اجازه دسترسی به کارهای چاپی ایجاد شده توسط برنامه‌ای دیگر را می‌دهد.هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"اتصال به یک سرویس متنی"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"به دارنده اجازه می‌دهد خود را به یک رابط سطح بالای خدمات متنی مرتبط کند (برای مثال SpellCheckerService). هرگز برای برنامه‌های عادی لازم نیست."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"اتصال به یک سرویس VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"به دارنده اجازه می‎دهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامه‎های معمولی هیچگاه به این ویژگی نیازی ندارند."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"اضافه یا حذف سرپرست دستگاه"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"به دارنده اجازه می‌دهد سرپرستان دستگاه فعال را اضافه یا حذف کند.هرگز نباید برای برنامه‌های عادی مورد نیاز باشد."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"به برنامه اجازه می‎دهد تا چرخش صفحه را هر وقت بخواهد تغییر دهد. برای برنامه‎های عادی نیاز نیست."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغییر سرعت اشاره‌گر"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"اجازه می‎دهد برنامه از ویژگی‌های سطح پایین SurfaceFlinger استفاده کند."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"خواندن بافر قاب"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"به برنامه اجازه می‎دهد تا محتوای بافر کادر را بخواند."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"دسترسی به InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"اجازه می‎دهد برنامه از قابلیت‌های سطح پایین InputFlinger استفاده کند."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"پیکربندی صفحه نمایش‌های Wi‑Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"به برنامه اجازه می‌دهد تا اتصال به صفحات نمایش Wi‑Fi را پیکربندی کند."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"کنترل صفحه نمایش‌های Wi‑Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"به برنامه اجازه می‌دهد که ویژگی‌های سطح پایین صفحه‌های نمایش Wi‑Fi را کنترل کند."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"تغییر تنظیمات صوتی"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"به برنامه امکان می‌دهد تنظیمات صوتی کلی مانند میزان صدا و بلندگوی مورد استفاده برای پخش صدا را اصلاح کند."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ضبط صدا"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"به برنامه اجازه می‎دهد تا در کارت SD بنویسد."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"تغییر/حذف محتواهای حافظه رسانه داخلی"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"به برنامه اجازه می‎دهد تا محتویات حافظه رسانه داخلی را تغییر دهد."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"مدیریت فضای ذخیره‌سازی اسناد"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"به برنامه اجازه می‌دهد فضای ذخیره‌سازی اسناد را مدیریت کند."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"دسترسی به دستگاه ذخیره خارجی تمام کاربران"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"به برنامه اجازه می‌دهد به دستگاه ذخیره خارجی برای همه کاربران دسترسی داشته باشد."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"دسترسی به سیستم فایل حافظهٔ پنهان"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"به برنامه اجازه می‎دهد تا خط مشی‎های شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"اصلاح محاسبه استفاده از شبکه"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه می‎دهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامه‎های عادی نیست."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"تغییر علائم سوکت"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"به برنامه اجازه می‌دهد برای مسیریابی علائم سوکت را تغییر دهد."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلان‌های دسترسی"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"لغو برنامه پیکربندی ارائه شده توسط شرکت مخابراتی"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه می‌دهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"سیم کارت را وارد کنید."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"سیم کارت موجود نیست یا قابل خواندن نیست. یک سیم کارت وارد کنید."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"سیم کارت غیرقابل استفاده است."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"سیم کارت شما به طور دائم غیر فعال شده است. "\n"برای داشتن سیم کارت دیگر با ارائه‎دهنده سرویس بی‎سیم خود تماس بگیرید."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"سیم کارت شما به طور دائم غیر فعال شده است. \nبرای داشتن سیم کارت دیگر با ارائه‎دهنده سرویس بی‎سیم خود تماس بگیرید."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"دکمه تراک قبلی"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"دکمه تراک بعدی"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"دکمه مکث"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"لطفاً به راهنمای کاربر مراجعه کرده یا با مرکز پشتیبانی از مشتریان تماس بگیرید."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"سیم کارت قفل شد."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"بازگشایی قفل سیم کارت..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. "\n\n"لطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"گذرواژهٔ خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کرده‌اید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"پین را<xliff:g id="NUMBER_0">%d</xliff:g>  بار اشتباه تایپ کرده‎اید. "\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"گذرواژهٔ خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کرده‌اید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"پین را<xliff:g id="NUMBER_0">%d</xliff:g>  بار اشتباه تایپ کرده‎اید. \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_now_wiping" product="tablet" msgid="280873516493934365">"شما به اشتباه اقدام به باز کردن قفل <xliff:g id="NUMBER">%d</xliff:g> رایانهٔ لوحی کرده‌اید. رایانهٔ لوحی در حال حاضر به پیش‌فرض کارخانه بازنشانی می‌شود."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"رمز ورود"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ورود به سیستم"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"نام کاربر یا رمز ورود نامعتبر است."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"نام کاربری یا گذرواژهٔ خود را فراموش کردید؟"\n"از "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"نام کاربری یا گذرواژهٔ خود را فراموش کردید؟\nاز "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"در حال بررسی..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"بازگشایی قفل"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"صدا روشن"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"تأیید پیمایش"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"ترک این صفحه"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"ماندن در این صفحه"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"مطمئنید می‌خواهید این صفحه را ترک کنید؟"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nمطمئنید می‌خواهید این صفحه را ترک کنید؟"</string>
     <string name="save_password_label" msgid="6860261758665825069">"تأیید"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای بزرگنمایی و کوچکنمایی، دو بار ضربه بزنید."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"تکمیل خودکار"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"متأسفانه، <xliff:g id="APPLICATION">%1$s</xliff:g> متوقف شده است."</string>
     <string name="aerr_process" msgid="4507058997035697579">"متأسفانه، پردازش <xliff:g id="PROCESS">%1$s</xliff:g> متوقف شده است."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمی‎دهد."\n\n"آیا می‎خواهید آنرا ببندید؟"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمی‎دهد."\n\n"آیا می‎خواهید آن را ببندید؟"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمی‎دهد.\n\nآیا می‎خواهید آنرا ببندید؟"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمی‎دهد.\n\nآیا می‎خواهید آن را ببندید؟"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمی‎دهد. آیا می‎خواهید آن را ببندید؟"</string>
-    <string name="anr_process" msgid="6513209874880517125">"روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمی‎دهد. "\n\n"آیا می‎خواهید آن را ببندید؟"</string>
+    <string name="anr_process" msgid="6513209874880517125">"روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمی‎دهد. \n\nآیا می‎خواهید آن را ببندید؟"</string>
     <string name="force_close" msgid="8346072094521265605">"تأیید"</string>
     <string name="report" msgid="4060218260984795706">"گزارش"</string>
     <string name="wait" msgid="7147118217226317732">"منتظر بمانید"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"این صفحه پاسخ نمی‌دهد."\n\n"آیا می‌خواهید آن را ببندید؟"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"این صفحه پاسخ نمی‌دهد.\n\nآیا می‌خواهید آن را ببندید؟"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"برنامه مجدداً هدایت شد"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> اکنون در حال اجرا است."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ابتدا راه‌اندازی شد."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"به برنامه اجازه می‎دهد تا سرویس پیش‌فرض را فراخوانی کند و محتوا را کپی کند. برای استفاده برنامه‎های عادی مورد نیاز نیست."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"تعیین مسیر خروجی رسانه"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"به یک برنامه اجازه می‌دهد خروجی رسانه را به دستگاه‌های خارجی دیگر تعیین مسیر کند."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"دسترسی به فضای ذخیره‌سازی ایمن محافظ کلید"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"به یک برنامه کاربردی برای دسترسی به فضای ذخیره‌سازی ایمن محافظ کلید اجازه می‌دهد."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"کنترل نمایش و پنهان کردن محافظ کلید"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"اجازه می‌دهد برنامه‌ای محافظ کلید را کنترل کند."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"دوبار لمس کنید تا بزرگنمایی کنترل شود"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"افزودن ابزارک انجام نشد."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"برو"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"انجام شد"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"قبلی"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"اجرا کردن"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"شماره گیری "\n"با استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"ایجاد مخاطب"\n"با استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"شماره گیری \nبا استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"ایجاد مخاطب\nبا استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"یک یا چند برنامه زیر برای دسترسی به حساب شما در زمان حال و آینده درخواست مجوز کرده‌اند."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"می‌خواهید به این درخواست اجازه دهید؟"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"درخواست دسترسی"</string>
     <string name="allow" msgid="7225948811296386551">"مجاز"</string>
     <string name="deny" msgid="2081879885755434506">"رد کردن"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"مجوز درخواست شد"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"مجوز"\n"برای حساب <xliff:g id="ACCOUNT">%s</xliff:g> درخواست شد."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"مجوز\nبرای حساب <xliff:g id="ACCOUNT">%s</xliff:g> درخواست شد."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"روش ورودی"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"همگام‌سازی"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"قابلیت دسترسی"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"درحال اتصال…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"در دسترس"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"در دسترس نیست"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"در حال استفاده"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"صفحه نمایش از خود"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"صفحه HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"همپوشانی #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"نمایشگر بی‌سیم متصل است"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"این صفحه در حال نمایش در دستگاه دیگری است"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"قطع اتصال"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"الگوی اشتباه"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"گذرواژه اشتباه"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"پین اشتباه"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"پس از <xliff:g id="NUMBER">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"پس از <xliff:g id="NUMBER">%1$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"الگوی خود را رسم کنید"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"پین سیم کارت را وارد کنید"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"پین را وارد کنید"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"گذرواژه"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"ورود به سیستم"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"نام کاربری یا گذرواژه نامعتبر."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"نام کاربری یا گذرواژه خود را فراموش کردید؟"\n"از "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"نام کاربری یا گذرواژه خود را فراموش کردید؟\nاز "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"درحال بررسی حساب..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <xliff:g id="NUMBER_0">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"حذف"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"صدا به بالاتر از سطح توصیه شده افزایش یابد؟"\n"گوش دادن به صدای بلند برای مدت طولانی می‌تواند به شنوایی شما آسیب برساند."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"صدا به بالاتر از سطح توصیه شده افزایش یابد؟\nگوش دادن به صدای بلند برای مدت طولانی می‌تواند به شنوایی شما آسیب برساند."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"برای فعال کردن قابلیت دسترسی، با دو انگشت خود همچنان به طرف پایین فشار دهید."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"قابلیت دسترسی فعال شد."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"قابلیت دسترسی لغو شد."</string>
     <string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"دارنده"</string>
     <string name="error_message_title" msgid="4510373083082500195">"خطا"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"این برنامه از حساب‌های متعلق به نمایه‌های محدود پشتیبانی نمی‌کند"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"این برنامه از حساب‌های متعلق به نمایه‌های محدود پشتیبانی نمی‌کند"</string>
     <string name="app_not_found" msgid="3429141853498927379">"برنامه‌ای برای انجام این عملکرد موجود نیست"</string>
     <string name="revoke" msgid="5404479185228271586">"لغو"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"لغو شد"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"خطا هنگام نوشتن محتوا"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"پین را وارد کنید"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"پین کنونی"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"پین جدید"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"تأیید پین جدید"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"یک پین برای تغییر محدودیت‌ها ایجاد کنید"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"پین‌ها مطابقت ندارند. دوباره امتحان کنید."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"پین بیش از حد کوتاه است. باید حداقل ۴ رقم باشد."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"پین نادرست است. امتحان در ۱ ثانیه."</item>
+    <item quantity="other" msgid="8030607343223287654">"پین نادرست است. امتحان در <xliff:g id="COUNT">%d</xliff:g> ثانیه."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9740070..d431fcc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Antaa sovelluksen siirtää tehtäviä etualalle ja taustalle. Sovellus ei tarvitse toimiin käyttäjän lupaa."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"käynnissä olevien sovellusten pysäyttäminen"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Antaa sovelluksen poistaa tehtäviä ja lopettaa niiden sovelluksia. Haitalliset sovellukset voivat häiritä muiden sovellusten toimintaa."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"Toimintapinojen hallinta"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Antaa sovelluksen lisätä, poistaa ja muokata niitä toimintapinoja, joissa muut sovellukset suoritetaan. Haitalliset sovellukset voivat häiritä muiden sovellusten toimintaa."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"käynnistä mikä tahansa toiminto"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Antaa sovelluksen käynnistää minkä tahansa toiminnon käyttölupasuojauksesta tai viennin tilasta huolimatta."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"aseta näytön yhteensopivuus"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Antaa sovelluksen sitoutua syötetavan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sitoudu esteettömyyspalveluun"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Antaa sovelluksen sitoutua esteettömyyspalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"Tulostuspalveluun sitoutuminen"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Antaa sovelluksen sitoutua tulostuspalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"Kaikkien tulostustöiden käyttäminen"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Antaa luvanhaltijan käyttää toisen sovelluksen luomia tulostustöitä. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"luo sidos NFC-palveluun"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Sallii oikeuden haltijan luoda sidoksia sovelluksiin, jotka jäljittelevät NFC-kortteja. Tämän ei pitäisi olla tarpeen tavallisille sovelluksille."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tekstipalveluun sitoutuminen"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Antaa sovelluksen sitoutua tekstipalvelun (kuten SpellCheckerServicen) ylätason liittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"sitoudu VPN-palveluun"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lisää tai poista laitteen järjestelmänvalvoja"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Haltija voi lisätä tai poistaa aktiivisen laitteen järjestelmänvalvojia. Tätä ei pitäisi tarvita tavallisille sovelluksille."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Antaa sovelluksen muuttaa näytön kiertoa milloin tahansa. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"muuta osoittimen nopeutta"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Antaa sovelluksen käyttää SurfaceFlingerin matalan tason ominaisuuksia."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lue kehyspuskuria"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Antaa sovelluksen lukea kehyspuskurin sisältöä."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlingerin käyttäminen"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Antaa sovelluksen käyttää InputFlingerin matalan tason ominaisuuksia."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"määritä wifi-näyttöjen asetukset"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Antaa sovelluksen määrittää wifi-näyttöjä ja muodostaa yhteyden niihin."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"hallitse wifi-näyttöjä"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Antaa sovelluksen hallita wifi-näyttöjen matalan tason ominaisuuksia."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"muuta ääniasetuksia"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Antaa sovelluksen muokata yleisiä ääniasetuksia, kuten äänenvoimakkuutta ja käytettävää kaiutinta."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"tallentaa ääntä"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Antaa sovelluksen kirjoittaa SD-kortille."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"muokkaa/poista sisäisen säilytystilan sisältöä"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Antaa sovelluksen muokata sisäisen tallennustilan sisältöä."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"hallinnoi dokum. tallennusta"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Antaa sovelluksen hallinnoida dokumenttien tallennusta."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"käyttää kaikkien käyttäjien ulk. tallennustilaa"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Sallii sovelluksen käyttää ulkoista tallennustilaa kaikille käyttäjille."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"käytä välimuistin tiedostojärjestelmää"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Sallii sovelluksen hallinnoida verkkokäytäntöjä ja määritellä sovelluskohtaisia sääntöjä."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verkon käytön seurannan muokkaaminen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"Pistokemerkkien muokkaaminen"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Antaa sovelluksen muokata reitityksen pistokemerkkejä"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Palveluntarjoajan määrityssovelluksen käynnistäminen"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Antaa luvanhaltijan käynnistää palveluntarjoajan määrityssovelluksen. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Aseta SIM-kortti."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-korttia ei löydy tai ei voi lukea. Kytke SIM-kortti."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-kortti ei kelpaa."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kortti on poistettu pysyvästi käytöstä."\n" Ota yhteyttä operaattoriisi ja hanki uusi SIM-kortti."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kortti on poistettu pysyvästi käytöstä.\n Ota yhteyttä operaattoriisi ja hanki uusi SIM-kortti."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Edellinen kappale -painike"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Seuraava kappale -painike"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Tauko-painike"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Katso ohjeita käyttöoppaasta tai ota yhteyttä asiakaspalveluun."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortti on lukittu."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-kortin lukitusta poistetaan…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus Google-sisäänkirjautumisen avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus Google-sisäänkirjautumisen avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus Google-sisäänkirjautumisen avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus Google-sisäänkirjautumisen avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tablet-laitteeseen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, puhelimeen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Laitteeseen palautetaan nyt tehdasasetukset."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Salasana"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Kirjaudu sisään"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Virheellinen käyttäjänimi tai salasana."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Unohditko käyttäjänimesi tai salasanasi?"\n"Käy osoitteessa "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Unohditko käyttäjänimesi tai salasanasi?\nKäy osoitteessa "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Tarkistetaan..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Poista lukitus"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ääni käytössä"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Vahvista siirtyminen"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Poistu tältä sivulta"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Pysy tällä sivulla"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Haluatko varmasti siirtyä pois tältä sivulta?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nHaluatko varmasti siirtyä pois tältä sivulta?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Vahvista"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Vinkki: lähennä ja loitonna kaksoisnapauttamalla."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut. täyttö"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> on pysähtynyt."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> on pysähtynyt."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ei vastaa."\n\n"Haluatko sulkea sen?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Toiminto <xliff:g id="ACTIVITY">%1$s</xliff:g> ei vastaa."\n\n"Haluatko sulkea sen?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ei vastaa.\n\nHaluatko sulkea sen?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Toiminto <xliff:g id="ACTIVITY">%1$s</xliff:g> ei vastaa.\n\nHaluatko sulkea sen?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> ei vastaa. Haluatko sulkea sen?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> ei vastaa."\n\n"Haluatko sulkea sen?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> ei vastaa.\n\nHaluatko sulkea sen?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Ilmoita"</string>
     <string name="wait" msgid="7147118217226317732">"Odota"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sivu ei vastaa."\n\n"Haluatko sulkea sen?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sivu ei vastaa.\n\nHaluatko sulkea sen?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Sovelluksen uud.ohjaus"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nyt käynnissä."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> käynnistettiin alun perin."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Antaa sovelluksen kutsua oletussäilöpalvelua sisällön kopioimiseen. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Median reititys"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Antaa sovelluksen reitittää mediaa muihin ulkoisiin laitteisiin."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Salasanalla suojatun tallennustilan hallinta"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Sallii sovelluksen käyttää salasanalla suojattua tallennustilaa."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Hallinnoi näppäinvahdin näyttämistä ja piilottamista"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Antaa sovelluksen hallita näppäinvahtia."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ohjaa zoomausta napauttamalla kahdesti"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widgetin lisääminen epäonnistui."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Siirry"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Valmis"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Edell."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Suorita"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Valitse numero"\n" <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Luo yhteystieto"\n"käyttäen numeroa <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Valitse numero\n <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Luo yhteystieto\nkäyttäen numeroa <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Seuraavat sovellukset pyytävät lupaa käyttää tiliäsi nyt ja tulevaisuudessa."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Sallitko tämän pyynnön?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Käyttöoikeuspyyntö"</string>
     <string name="allow" msgid="7225948811296386551">"Salli"</string>
     <string name="deny" msgid="2081879885755434506">"Kiellä"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Lupa pyydetty"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Pyydetään lupaa"\n"tilille <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Pyydetään lupaa\ntilille <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Syöttötapa"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synkronointi"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Esteettömyys"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Yhdistetään..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Käytettävissä"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ei käytettävissä"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Käytössä"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Yhdysrakenteinen näyttö"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-ruutu"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Peittokuva # <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", suojattu"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Langaton näyttö on yhdistetty"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tämä ruutu näkyy toisella laitteella"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Katkaise yhteys"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Väärä kuvio"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Väärä salasana"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Väärä PIN-koodi"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Yritä uudelleen <xliff:g id="NUMBER">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Yritä uudelleen <xliff:g id="NUMBER">%1$d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Piirrä kuvio"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Anna SIM-kortin PIN-koodi"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Anna PIN-koodi"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Salasana"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Kirjaudu sisään"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Virheellinen käyttäjänimi tai salasana."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Unohditko käyttäjänimesi tai salasanasi?"\n"Käy osoitteessa "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Unohditko käyttäjänimesi tai salasanasi?\nKäy osoitteessa "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Tarkistetaan tiliä..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tablet-laitteeseen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, puhelimeen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Laitteeseen palautetaan nyt tehdasasetukset."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Puhelimeen palautetaan nyt tehdasasetukset."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Poista"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Nostetaanko äänenvoimakkuus suositeltua tasoa voimakkaammaksi?"\n"Jos kuuntelet suurella äänenvoimakkuudella pitkiä aikoja, kuulosi voi vahingoittua."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Nostetaanko äänenvoimakkuus suositeltua tasoa voimakkaammaksi?\nJos kuuntelet suurella äänenvoimakkuudella pitkiä aikoja, kuulosi voi vahingoittua."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Ota esteettömyystila käyttöön koskettamalla pitkään kahdella sormella."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Esteettömyystila käytössä."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Esteettömyystila peruutettu."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Omistaja"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Virhe"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Tämä sovellus ei tue rajoitettujen profiilien tilejä"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Tämä sovellus ei tue rajoitettujen profiilien tilejä"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Tätä toimintoa käsittelevää sovellusta ei löydy"</string>
     <string name="revoke" msgid="5404479185228271586">"Peruuta"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Peruutettu"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Sisällön kirjoittamisessa tapahtui virhe"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Anna PIN-koodi"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Nykyinen PIN-koodi"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Uusi PIN-koodi"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Vahvista uusi PIN-koodi"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Luo uusi PIN-koodi rajoitusten muokkaamista varten"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-koodit eivät vastaa toisiaan. Yritä uudelleen."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-koodi on liian lyhyt. Vähimmäispituus on neljä merkkiä."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Väärä PIN. Yritä uudelleen yhden sekunnin kuluttua."</item>
+    <item quantity="other" msgid="8030607343223287654">"Väärä PIN. Yritä uudelleen <xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a1c795f..7409912 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permet à l\'application de déplacer les tâches au premier plan et en arrière-plan. L\'application peut procéder à ces opérations sans votre intervention."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"arrêter les applications en cours d\'exécution"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet à l\'application de supprimer des tâches et de fermer les applications qui les exécutent. Des applications malveillantes peuvent exploiter cette fonctionnalité pour perturber le comportement des autres applications."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gérer les piles d\'activités"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permet à l\'application d\'ajouter, de supprimer et de modifier les piles d\'activités dans lesquelles d\'autres applications fonctionnent. Des applications malveillantes peuvent perturber le comportement d\'autres applications."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"démarrer n\'importe quelle activité"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permet à l\'application de démarrer n\'importe quelle activité, quels que soient l\'état exporté ou le degré de protection appliqué à l\'autorisation."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"définir la compatibilité de l\'écran"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un mode de saisie. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"associer à un service d\'accessibilité"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service d\'accessibilité. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"s\'associer à un service d\'impression"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permet à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un service d\'impression. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accéder à l\'ensemble des tâches d\'impression"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permet à l\'application autorisée d\'accéder aux tâches d\'impression créées via une autre application. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"associer à un service de texte"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permet à l\'application de s\'associer à l\'interface de haut niveau d\'un service de texte (par exemple, SpellCheckerService). Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"associer à un service VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application autorisée d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permet à l\'application de changer l\'orientation de l\'écran à tout moment. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"changer la vitesse du pointeur"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permet à l\'application d\'utiliser les fonctionnalités de bas niveau de SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Lecture de la mémoire tampon graphique"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permet à l\'application de lire le contenu de la mémoire tampon graphique."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accéder à InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permet à l\'application d\'utiliser les fonctionnalités de base d\'InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurer les écrans Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet à l\'application de configurer des écrans Wi-Fi et de s\'y connecter."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"contrôler les écrans Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifier vos paramètres audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"Enregistrer des fichiers audio"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permet à l\'application de modifier le contenu de la carte SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Modifier/Supprimer contenu mémoire interne"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permet à l\'application de modifier le contenu de la mémoire de stockage multimédia interne."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"gérer stockage des documents"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permet à l\'application de gérer le stockage des documents."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Accès stock. ext. tous utilis."</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permet à l\'application d\'accéder à la mémoire de stockage externe pour tous les utilisateurs."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accéder au système de fichiers en cache"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet à l\'application de gérer les stratégies du réseau et de définir celles qui sont spécifiques à l\'application."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifier le système de comptabilisation de l\'utilisation du réseau"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifier les marques de sockets"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet à l\'application de modifier les marques de sockets pour les redirections."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration fournie par l\'opérateur"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par l\'opérateur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insérez une carte SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Carte SIM absente ou illisible. Insérez une carte SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Carte SIM inutilisable."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Votre carte SIM a été définitivement désactivée."\n" Veuillez contacter votre opérateur de téléphonie mobile pour en obtenir une autre."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Votre carte SIM a été définitivement désactivée.\n Veuillez contacter votre opérateur de téléphonie mobile pour en obtenir une autre."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Bouton du titre précédent"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Bouton du titre suivant"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Bouton de pause"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Veuillez consulter le guide utilisateur ou contacter le service client."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La carte SIM est verrouillée."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Déblocage de la carte SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises."\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Vous avez saisi un mot de passe incorrect <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Vous avez saisi un code PIN incorrect <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> échecs supplémentaires, vous devrez déverrouiller votre tablette à l\'aide de votre identifiant Google."\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> échecs supplémentaires, vous devrez déverrouiller votre téléphone à l\'aide de votre identifiant Google."\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Vous avez saisi un mot de passe incorrect <xliff:g id="NUMBER_0">%d</xliff:g> fois. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Vous avez saisi un code PIN incorrect <xliff:g id="NUMBER_0">%d</xliff:g> fois. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> échecs supplémentaires, vous devrez déverrouiller votre tablette à l\'aide de votre identifiant Google.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> échecs supplémentaires, vous devrez déverrouiller votre téléphone à l\'aide de votre identifiant Google.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Mot de passe"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Se connecter"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nom d\'utilisateur ou mot de passe incorrect."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?"\n"Accédez à la page "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?\nAccédez à la page "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Vérification en cours…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Déverrouiller"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Son activé"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Quitter la page"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Quitter cette page"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rester sur cette page"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Voulez-vous vraiment quitter cette page ?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVoulez-vous vraiment quitter cette page ?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Conseil : Appuyez deux fois pour faire un zoom avant ou arrière."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Saisie auto"</string>
@@ -1080,14 +1109,14 @@
     <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_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\n"Voulez-vous quitter ?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> ne répond pas."\n\n"Voulez-vous quitter ?"</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>
+    <string name="anr_activity_process" msgid="5776209883299089767">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> ne répond pas.\n\nVoulez-vous quitter ?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> ne répond pas. Voulez-vous quitter ?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas."\n\n"Voulez-vous quitter ?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas.\n\nVoulez-vous quitter ?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapport"</string>
     <string name="wait" msgid="7147118217226317732">"Attendre"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"La page ne répond pas."\n" "\n"Voulez-vous la fermer ?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La page ne répond pas.\n \nVoulez-vous la fermer ?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Application redirigée"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> est maintenant lancée."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Application lancée initialement : <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permet à l\'application d\'invoquer le service de conteneur par défaut pour copier du contenu. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Diriger la sortie multimédia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permet à une application de diriger la sortie multimédia vers d\'autres appareils externes."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Accéder au stockage sécurisé keyguard"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet à une application d\'accéder au stockage sécurisé keyguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Contrôler l\'affichage et le masquage de la protection des touches"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Appuyez deux fois pour régler le zoom."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Impossible d\'ajouter le widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"OK"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"OK"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Préc."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Exécuter"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Composer le numéro"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Ajouter un contact"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Composer le numéro\nen utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Ajouter un contact\nen utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Les applications suivantes demandent l\'autorisation d\'accéder à votre compte à partir de maintenant."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Voulez-vous autoriser cette demande ?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Demande d\'accès"</string>
     <string name="allow" msgid="7225948811296386551">"Autoriser"</string>
     <string name="deny" msgid="2081879885755434506">"Refuser"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Autorisation demandée"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Autorisation demandée"\n"pour le compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\""</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Autorisation demandée\npour le compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\""</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Mode de saisie"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronisation"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilité"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connexion en cours..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Indisponible"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"En cours d\'utilisation"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Écran intégré"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Écran HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposition n° <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sécurisé"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"L\'affichage sans fil est connecté."</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Cet écran s\'affiche sur un autre appareil."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Déconnecter"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Mot de passe incorrect."</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Code PIN incorrect."</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Réessayez dans <xliff:g id="NUMBER">%1$d</xliff:g> secondes."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Dessinez votre schéma."</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Saisissez le code PIN de la carte SIM."</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Saisissez le code PIN."</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?"\n"Rendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?\nRendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Vérification du compte en cours…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises."\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Augmenter le volume au-dessus du niveau recommandé ?"\n"L\'écoute à un volume élevé pendant des périodes prolongées peut endommager votre audition."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Augmenter le volume au-dessus du niveau recommandé ?\nL\'écoute à un volume élevé pendant des périodes prolongées peut endommager votre audition."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Pour activer l\'accessibilité, appuyez de manière prolongée avec deux doigts."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"L\'accessibilité a bien été activée."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilité annulée."</string>
     <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Propriétaire"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Erreur"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Les comptes des profils limités ne sont pas acceptés pour cette application."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Les comptes des profils en accès limité ne sont pas compatibles avec cette application."</string>
     <string name="app_not_found" msgid="3429141853498927379">"Aucune application trouvée pour gérer cette action."</string>
     <string name="revoke" msgid="5404479185228271586">"Révoquer"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Lettre"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloïd"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Tâche annulée."</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Erreur lors de la modification du contenu."</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Saisir le code PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Code PIN actuel"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nouveau code PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirmer le nouveau code PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Créer un code PIN pour modifier les restrictions"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les codes PIN ne correspondent pas. Veuillez réessayer."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le code PIN est trop court. Il doit comporter au moins 4 chiffres."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN erroné. Réessayez dans 1 seconde."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN erroné. Réessayez dans <xliff:g id="COUNT">%d</xliff:g> secondes."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a2180a8..9f95156 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"एप्लिकेशन को कार्यों को अग्रभूमि और पृष्‍ठभूमि पर ले जाने देता है. एप्लिकेशन आपके इनपुट के बिना यह कर सकता है."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्‍लिकेशन को कार्यों को निकालने और उनके एप्‍लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्‍लिकेशन अन्‍य एप्‍लिकेशन का व्‍यवहार बाधित कर सकते हैं."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"गतिविधि स्टैक प्रबंधित करें"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"एप्लिकेशन को ऐसे गतिविधि स्टैक जोड़ने, निकालने, और बदलने देता है जिनमें अन्य एप्लिकेशन चलते हों. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन के व्यवहार में बाधा डाल सकते हैं."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"कोई गतिविधि प्रारंभ करें"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्‍थिति पर ध्‍यान दिए बिना, एप्‍लिकेशन को कोई गतिविधि प्रारंभ करने देता है."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्‍क्रीन संगतता सेट करें"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"पहुंच-योग्‍यता सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"प्रिंट सेवा से आबद्ध करें"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"सभी प्रिंट कार्य एक्सेस करें"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"धारक को अन्य एप्लिकेशन के द्वारा बनाए गए प्रिंट कार्य एक्सेस करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"NFC सेवा से आबद्ध रहें"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"धारक को ऐसे एप्लिकेशन से आबद्ध रहने देता है जो NFC कार्ड का अनुकरण कर रहे हैं. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"किसी पाठ सेवा पर बने रहें"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्‍तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"किसी VPN सेवा से आबद्ध करें"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्‍यवस्‍थापक के साथ सहभागिता करें"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्‍यवस्‍थापक को उद्देश्य भेजने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण व्यवस्थापक को जोड़ें या निकालें"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"स्‍क्रीन अभिविन्‍यास बदलें"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्‍लिकेशन को किसी भी समय स्‍क्रीन का रोटेशन बदलने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"सूचक गति बदलें"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्‍लिकेशन को SurfaceFlinger निम्‍न-स्‍तर सुविधाएं उपयोग करने देता है."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"फ़्रेम बफ़र पढ़ें"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्‍लिकेशन को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger एक्सेस करें"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"एप्‍लिकेशन को InputFlinger निम्‍न-स्‍तर सुविधाओं का उपयोग करने देता है."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wifi डिस्प्ले को कॉन्फ़िगर करें"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"एप्लिकेशन को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi डिस्प्ले को नियंत्रित करें"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"एप्लिकेशन को Wifi डिस्प्ले की निम्न-स्तर की सुविधाएं नियंत्रित करने देता है."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"अपनी ऑडियो सेटिंग बदलें"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"एप्लिकेशन को वैश्विक ऑडियो सेटिंग, जैसे वॉल्‍यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ऑडियो रिकॉर्ड करें"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"एप्लिकेशन को SD कार्ड पर लिखने देता है."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"आंतरिक मीडिया संग्रहण सामग्रियों को बदलें/हटाएं"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"एप्लिकेशन को आंतरिक मीडिया संग्रहण की सामग्री को संशोधित करने देता है."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"दस्तावेज़ संग्रहण प्रबंधित करें"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"एप्लिकेशन को दस्तावेज़ संग्रहण प्रबंधित करने की अनुमति दें."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचें"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"एप्लिकेशन को सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचने दें."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"कैश फ़ाइल सिस्‍टम में पहंचे"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्‍लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्‍लिकेशन-विशिष्‍ट नियमों को परिभाषित करने देता है."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्‍लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य एप्‍लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"सॉकेट मार्क बदलें"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"एप्लिकेशन को रूटिंग के लिए सॉकेट मार्क बदलने देता है"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करें"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"कोई सिमकार्ड डालें."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"सिम कार्ड गुम है या पढ़ने योग्‍य नहीं है. कोई सिम कार्ड डालें."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"अनुपयोगी SIM कार्ड."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"आपका सिम कार्ड स्‍थायी रूप से अक्षम कर दिया गया है."\n" दूसरे SIM कार्ड के लिए अपने वायरलेस सेवा प्रदाता से संपर्क करें."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"आपका सिम कार्ड स्‍थायी रूप से अक्षम कर दिया गया है.\n दूसरे SIM कार्ड के लिए अपने वायरलेस सेवा प्रदाता से संपर्क करें."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"पिछला ट्रैक बटन"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"अगला ट्रैक बटन"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"पॉज़ करें बटन"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"कृपया उपयोगकर्ता मार्गदर्शिका देखें या ग्राहक सहायता से संपर्क करें."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"सिम कार्ड लॉक किया गया है."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"सिम कार्ड अनलॉक कर रहा है…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. "\n\n" <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपने अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपने अपना पिन <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. "\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपने अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपने अपना पिन <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. \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_now_wiping" product="tablet" msgid="280873516493934365">"आप टेबलेट को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. टेबलेट अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"पासवर्ड"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"साइन इन करें"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?"\n<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n"<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"जांच रहा है…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"अनलॉक करें"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ध्‍वनि चालू करें"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"नेविगेशन की पुष्टि करें"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"इस पृष्ठ को छोड़ें"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"इस पृष्ठ पर बने रहें"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"क्या आप वाकई इस पृष्ठ से दूर नेविगेट करना चाहते हैं?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nक्या आप वाकई इस पृष्ठ से दूर नेविगेट करना चाहते हैं?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"पुष्टि करें"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"युक्ति: ज़ूम इन और आउट करने के लिए डबल-टैप करें."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"स्‍वत: भरण"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"दुर्भाग्‍यवश, <xliff:g id="APPLICATION">%1$s</xliff:g> रुक गया है."</string>
     <string name="aerr_process" msgid="4507058997035697579">"दुर्भाग्‍यवश, <xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रिया रुक गई है."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> प्रतिसाद नहीं दे रहा है."\n\n"क्‍या आप इसे बंद करना चाहते हैं?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"गतिविधि <xliff:g id="ACTIVITY">%1$s</xliff:g> प्रतिसाद नहीं दे रही है."\n\n"क्या आप इसे बंद करना चाहते हैं?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> प्रतिसाद नहीं दे रहा है.\n\nक्‍या आप इसे बंद करना चाहते हैं?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"गतिविधि <xliff:g id="ACTIVITY">%1$s</xliff:g> प्रतिसाद नहीं दे रही है.\n\nक्या आप इसे बंद करना चाहते हैं?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> प्रतिसाद नहीं दे रहा है. क्या आप इसे बंद करना चाहते हैं?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> प्रतिसाद नहीं दे रही है."\n\n"क्‍या आप इसे बंद करना चाहते हैं?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> प्रतिसाद नहीं दे रही है.\n\nक्‍या आप इसे बंद करना चाहते हैं?"</string>
     <string name="force_close" msgid="8346072094521265605">"ठीक"</string>
     <string name="report" msgid="4060218260984795706">"रिपोर्ट करें"</string>
     <string name="wait" msgid="7147118217226317732">"प्रतीक्षा करें"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ प्रतिसाद नहीं दे रहा है."\n\n"क्‍या आप इसे बंद करना चाहते हैं?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ प्रतिसाद नहीं दे रहा है.\n\nक्‍या आप इसे बंद करना चाहते हैं?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"एप्‍लि. रीडायरेक्‍ट किया गया"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अभी चल रहा है."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> को वास्‍तविक रूप से लॉन्‍च किया गया था."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"एप्लिकेशन को सामग्री की प्रतिलिपि बनाने के लिए डिफ़ॉल्ट कंटेनर सेवा शुरू करने देता है. सामान्‍य एप्‍लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"मीडिया आउटपुट को रूट करें"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"एप्लिकेशन को मीडिया आउटपुट को अन्य बाहरी उपकरणों पर रूट करने देता है."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"कीगार्ड सुरक्षित संग्रहण एक्सेस करें"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"एप्लिकेशन को कीगार्ड सुरक्षित संग्रहण एक्सेस करने देती है."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"कीगार्ड दिखाना और छिपाना नियंत्रित करें"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"एप्लिकेशन को कीगार्ड नियंत्रित करने देती है."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ज़ूम नियंत्रण के लिए दो बार स्पर्श करें"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"विजेट नहीं जोड़ा जा सका."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"जाएं"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"पूर्ण"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"पिछला"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"निष्‍पादित करें"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g> के उपयोग द्वारा "\n" नंबर डायल करें"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g> का उपयोग करके"\n" संपर्क बनाएं"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g> के उपयोग द्वारा \n नंबर डायल करें"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g> का उपयोग करके\n संपर्क बनाएं"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"निम्‍न एक या अधिक एप्‍लिकेशन अभी और भविष्‍य में आपके खाते में पहुंच की अनुमति का अनुरोध करते हैं."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"क्या आप इस अनुरोध को अनुमति देना चाहते हैं?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"पहुंच अनुरोध"</string>
     <string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
     <string name="deny" msgid="2081879885755434506">"अस्वीकारें"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"अनुमति अनुरोधित"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> खाते के लिए अनुमति"\n"का अनुरोध किया गया."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> खाते के लिए अनुमति\nका अनुरोध किया गया."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"इनपुट विधि"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"समन्वयन"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"पहुंच-योग्यता"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट हो रहा है..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"उपलब्ध"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"उपलब्‍ध नहीं"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"उपयोग में"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"अंतर्निहित स्क्रीन"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI स्क्रीन"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ओवरले #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", सुरक्षित"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"वायरलेस डिस्प्ले कनेक्ट है"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"यह स्क्रीन अन्य उपकरण पर दिखाई दे रही है"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"डिस्कनेक्ट करें"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करें"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?"\n" "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना 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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"वॉल्यूम को उपरोक्त अनुशंसित स्तर तक बढ़ाएं?"\n"लंबे समय तक अधिक वॉल्यूम पर सुनने से आपकी सुनने की क्षमता को क्षति पहुंच सकती है."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"वॉल्यूम को उपरोक्त अनुशंसित स्तर तक बढ़ाएं?\nलंबे समय तक अधिक वॉल्यूम पर सुनने से आपकी सुनने की क्षमता को क्षति पहुंच सकती है."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"पहुंच-योग्यता को सक्षम करने के लिए दो अंगुलियों से नीचे दबाए रखें."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"पहुंच-योग्यता सक्षम कर दी है."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"पहुंच-योग्यता रद्द की गई."</string>
     <string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"स्वामी"</string>
     <string name="error_message_title" msgid="4510373083082500195">"त्रुटि"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"यह एप्लिकेशन प्रतिबंधित प्रोफ़ाइल के खातों का समर्थन नहीं करता है"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"यह एप्लिकेशन प्रतिबंधित प्रोफ़ाइल के खातों का समर्थन नहीं करता है"</string>
     <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string>
     <string name="revoke" msgid="5404479185228271586">"निरस्‍त करें"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"लेटर"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"गवर्नमेंट लेटर"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"लीगल"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"जूनियर लीगल"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"लेजर"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"टेबलॉइड"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"रद्द कर दी गई"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामग्री लिखने में त्रुटि"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN डालें"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"वर्तमान पिन"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"नया पिन"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"नए पिन की पुष्टि करें"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"प्रतिबंधों को बदलने के लिए PIN बनाएं"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN मिलान नहीं करते हैं. पुनः प्रयास करें."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN बहुत छोटा है. कम से कम 4 अंकों का होना चाहिए."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"गलत PIN. 1 सेकंड में पुनः प्रयास करें."</item>
+    <item quantity="other" msgid="8030607343223287654">"गलत PIN. <xliff:g id="COUNT">%d</xliff:g> सेकंड में पुनः प्रयास करें."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 733a0e3..ca467ec 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Aplikaciji omogućuje premještanje zadataka u prednji plan ili pozadinu. Aplikacija to može napraviti bez vašeg naloga."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"upravljaj snopovima aktivnosti"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Dopušta aplikaciji dodavanje, uklanjanje i izmjenu snopova aktivnosti u kojima se druge aplikacije izvršavaju. Zlonamjerne aplikacije mogu poremetiti ponašanje ostalih aplikacija."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"započni bilo kakvu aktivnost"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Omogućuje aplikaciji da započne bilo koju aktivnost, bez obzira na zaštitu pomoću dozvola ili stanje izvoza."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje kompatibilnosti sa zaslonom"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Nositelju omogućuje povezivanje sučelja najviše razine načina unosa. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vezivanje uz uslugu dostupnosti"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge dostupnosti. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"veži se uz uslugu ispisa"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Dopušta nositelju vezanje uza sučelje usluge ispisa najviše razine. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"pristupi svim zadacima ispisa"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Dopušta nositelju pristup zadacima ispisa koje je izradila neka druga aplikacija. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"povezivanje s NFC uslugom"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Omogućuje nositelju povezivanje s aplikacijama koje emuliraju NFC kartice. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vezanje na tekstualnu uslugu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Omogućuje korisniku povezivanje s najvišom razinom sučelja tekstualne usluge (npr. SpellCheckerService). Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vezanje na VPN uslugu"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodavanje ili uklanjanje administratora uređaja"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Omogućuje nositelju dodavanje ili uklanjanje administratora aktivnih uređaja. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Omogućuje aplikaciji promjenu rotacije zaslona u bilo kojem trenutku. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"promjena brzine pokazivača"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Aplikaciji omogućuje upotrebu značajki niske razine SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čitanje međuspremnika okvira"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Aplikaciji omogućuje čitanje sadržaja međuspremnika okvira."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"pristupi InputFlingeru"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Dopušta aplikaciji upotrebu značajki niske razine InputFlingera."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfiguriraj Wifi zaslone"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogućuje aplikaciji konfiguriranje i povezivanje s Wi-Fi zaslonima."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"upravljaj Wifi zaslonima"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogućuje aplikaciji upravljanje značajkama Wi-Fi zaslona niske razine."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"promjena postavki zvuka"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Aplikaciji omogućuje izmjenu globalnih postavki zvuka, primjerice glasnoće i zvučnika koji se upotrebljava za izlaz."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"snimanje zvuka"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Aplikaciji omogućuje pisanje na SD karticu."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"izmijeni/izbriši sadržaj pohranjen na internim medijima"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Aplikaciji omogućuje izmjenu sadržaja pohranjenog na internim medijima."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"upravljanje pohr. dokumenata"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Omogućuje aplikaciji upravljanje pohranom dokumenata."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"pristup vanjskoj pohrani svima"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Omogućuje aplikaciji pristup vanjskoj pohrani za sve korisnike."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pristup sustavu datoteka predmemorije"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Aplikaciji omogućuje upravljanje mrežnim pravilima i određivanje pravila za aplikacije."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena evidencije mrežne upotrebe"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"izmijeni oznake utičnica"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Dopušta aplikaciji izmjenu oznaka utičnica za usmjeravanje"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge slušatelja obavijesti. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"pozovi operaterovu aplikaciju za konfiguraciju"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju pozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Umetnite SIM karticu."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM kartica nedostaje ili nije čitljiva. Umetnite SIM karticu."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Neupotrebljiva SIM kartica."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaša SIM kartica trajno je onemogućena."\n" Obratite se svom pružatelju bežičnih usluga da biste dobili drugu SIM karticu."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaša SIM kartica trajno je onemogućena.\n Obratite se svom pružatelju bežičnih usluga da biste dobili drugu SIM karticu."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Gumb Prethodni zapis"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Gumb Sljedeći zapis"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Gumb Pauza"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Pogledajte korisnički priručnik ili kontaktirajte korisničku službu."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kartica je zaključana."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Otključavanje SIM kartice…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> zamolit ćemo vas da otključate tabletno računalo putem prijave na Google."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon putem prijave na Google."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> zamolit ćemo vas da otključate tabletno računalo putem prijave na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon putem prijave na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Neispravno ste pokušali otključati tabletno računalo ovoliko puta: <xliff:g id="NUMBER_0">%d</xliff:g>. Ono će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Neispravno ste pokušali otključati telefon ovoliko puta: <xliff:g id="NUMBER_0">%d</xliff:g>. On će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Neispravno ste pokušali otključati tabletno računalo ovoliko puta: <xliff:g id="NUMBER">%d</xliff:g>. Sada će biti vraćeno na tvorničke postavke."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Zaporka"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Prijava"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nevažeće korisničko ime ili zaporka."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zaboravili ste korisničko ime ili zaporku?"\n"Posjetite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zaboravili ste korisničko ime ili zaporku?\nPosjetite "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Provjeravanje..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Otključaj"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Zvuk je uključen"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potvrda kretanja"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Napusti stranicu"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Ostani na ovoj stranici"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jeste li sigurni da želite napustiti ovu stranicu?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nJeste li sigurni da želite napustiti ovu stranicu?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Savjet: Dvaput dotaknite za povećavanje i smanjivanje."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.pop."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Nažalost, aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> prekinula je s radom."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Nažalost, zaustavljen je proces <xliff:g id="PROCESS">%1$s</xliff:g>."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacija <xliff:g id="APPLICATION">%2$s</xliff:g> ne reagira."\n\n"Želite li je zatvoriti?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivnost <xliff:g id="ACTIVITY">%1$s</xliff:g> ne reagira."\n\n"Želite li je zatvoriti?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacija <xliff:g id="APPLICATION">%2$s</xliff:g> ne reagira.\n\nŽelite li je zatvoriti?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivnost <xliff:g id="ACTIVITY">%1$s</xliff:g> ne reagira.\n\nŽelite li je zatvoriti?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> ne reagira. Želite li je zatvoriti?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Postupak <xliff:g id="PROCESS">%1$s</xliff:g> ne reagira."\n\n"Želite li ga zatvoriti?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Postupak <xliff:g id="PROCESS">%1$s</xliff:g> ne reagira.\n\nŽelite li ga zatvoriti?"</string>
     <string name="force_close" msgid="8346072094521265605">"U redu"</string>
     <string name="report" msgid="4060218260984795706">"Izvješće"</string>
     <string name="wait" msgid="7147118217226317732">"Pričekaj"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stranica ne reagira."\n\n"Želite li ju zatvoriti?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stranica ne reagira.\n\nŽelite li ju zatvoriti?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplikacija preusmjerena"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvodi sada."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> pokrenuta je prva."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Omogućuje aplikaciji dozivanje usluge zadanog spremnika radi kopiranja sadržaja. Nije namijenjena uobičajenim aplikacijama."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Usmjeravanje medijskog izlaza"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Aplikaciji omogućuje usmjeravanje medijskog izlaza na druge vanjske uređaje."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Pristup zaključanoj sigurnoj pohrani"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Omogućuje aplikaciji pristupanje zaključanoj sigurnoj pohrani."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Upravljanje prikazivanjem i skrivanjem zaključavanja tipkovnice"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Omogućuje aplikaciji upravljanje zaključavanjem tipkovnice."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput za upravljanje zumiranjem"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget nije moguće dodati."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Idi"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Gotovo"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Preth."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Pokreni"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Biraj broj"\n"koristeći <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Stvori kontakt"\n"koristeći <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Biraj broj\nkoristeći <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Stvori kontakt\nkoristeći <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Sljedeća aplikacija ili više njih zahtijevaju dozvolu za pristup vašem računu, sad i u budućnosti."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Dopuštate li taj zahtjev?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zahtjev za pristup"</string>
     <string name="allow" msgid="7225948811296386551">"Dopusti"</string>
     <string name="deny" msgid="2081879885755434506">"Odbij"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Zatražena je dozvola"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Zatražena je dozvola"\n"za račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Zatražena je dozvola\nza račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Način unosa"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinkronizacija"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Dostupnost"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Povezivanje..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Dostupno"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nije dostupno"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"U upotrebi"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ugrađeni zaslon"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI zaslon"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Preklapanje br. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sigurno"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bežični je prikaz povezan"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ovaj se zaslon prikazuje na nekom drugom uređaju"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Isključi"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan obrazac"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna zaporka"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> s."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Iscrtajte svoj obrazac"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN za SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Zaporka"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili zaporka."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili zaporku?"\n"Posjetite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili zaporku?\nPosjetite "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Provjera računa..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Netočno ste pokušali otključati tabletno računalo <xliff:g id="NUMBER_0">%d</xliff:g> puta. Ono će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Netočno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%d</xliff:g> puta. On će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Netočno ste pokušali otključati tabletno računalo <xliff:g id="NUMBER">%d</xliff:g> puta. Sada će se vratiti na tvorničke postavke."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Netočno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Sada će se vratiti na tvorničke postavke."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Želite li pojačati iznad preporučene razine?"\n"Dulje slušanje preglasne glazbe može vam oštetiti sluh."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Želite li pojačati iznad preporučene razine?\nDulje slušanje preglasne glazbe može vam oštetiti sluh."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Nastavite držati s dva prsta kako biste omogućili pristupačnost."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Dostupnost je omogućena."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost otkazana."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Vlasnik"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Pogreška"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Aplikacija ne podržava račune za ograničene profile"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Aplikacija ne podržava račune za ograničene profile"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena aplikacija za upravljanje ovom radnjom"</string>
     <string name="revoke" msgid="5404479185228271586">"Opozovi"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Otkazano"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Pogreška prilikom pisanja sadržaja"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Unesite PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Trenutačni PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrdite novi PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Izradite PIN za izmjenu ograničenja"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora imati barem 4 znamenke."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN nije točan. Ponovite za 1 s."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN nije točan. Ponovite za <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index dab8941..ac90a93 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Lehetővé teszi az alkalmazás számára, hogy feladatokat helyezzen át az előtérből a háttérbe és fordítva. Az alkalmazás ezt az Ön jóváhagyása nélkül is megteheti."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"futó alkalmazások leállítása"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Lehetővé teszi, hogy az alkalmazás feladatokat távolítson el és leállítsa azok alkalmazásait. Rosszindulatú alkalmazások megzavarhatják más alkalmazások viselkedését."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"tevékenységkötegek kezelése"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Engedélyezi az alkalmazás számára, hogy hozzáadjon, eltávolítson vagy módosítson olyan tevékenységkötegeket, amelyekben más alkalmazások futnak. A rosszindulatú alkalmazások tönkretehetik más alkalmazások működését."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"bármely tevékenység elindítása"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Lehetővé teszi az alkalmazás számára bármely tevékenység elindítását az engedélyektől és exportált állapottól függetlenül."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Képernyő-kompatibilitás beállítása"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy beviteli mód legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"csatlakozás egy kisegítő szolgáltatáshoz"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lehetővé teszi a használó számára, hogy csatlakozzon egy kisegítő 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_bindPrintService" msgid="8462815179572748761">"csatlakozás egy nyomtatási szolgáltatáshoz"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Lehetővé teszi a használó számára, hogy csatlakozzon egy nyomtatási 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_accessAllPrintJobs" msgid="1120792468465711159">"hozzáférés valamennyi nyomtatási feladathoz"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Lehetővé teszi a használó számára, hogy megtekintsen más alkalmazások által létrehozott nyomtatási feladatokat. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"csatlakozás NFC-szolgáltatáshoz"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Az eszköz kezelője csatlakozhat NFC-kártyákat emuláló alkalmazásokhoz. A normál alkalmazásoknak nincs rá szükségük."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"csatlakozás szövegszolgáltatáshoz"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Lehetővé teszi, hogy a tulajdonos egy szöveges szolgáltatás felső szintjéhez kapcsolódjon (pl. SpellCheckerService). A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"csatlakozás egy VPN-szolgáltatáshoz"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Lehetővé teszi az alkalmazás számára a képernyő elforgatásának bármikori módosítását. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"mutató sebességének módosítása"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Lehetővé teszi az alkalmazás számára a SurfaceFlinger alacsony szintű funkciók használatát."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"keretpuffer olvasása"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Lehetővé teszi az alkalmazás számára a keretpuffer tartalmának olvasását."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"hozzáférés az InputFlingerhez"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Lehetővé teszi az alkalmazás számára az InputFlinger alacsony szintű funkciók használatát."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fi kijelzők konfigurálása"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Lehetővé teszi, hogy az alkalmazás Wi-Fi kijelzőket konfiguráljon, és csatlakozzon hozzájuk."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi kijelzők irányítása"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lehetővé teszi, hogy az alkalmazás irányítsa a Wi-Fi kijelzők alacsonyabb szintű funkcióit."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"hangbeállítások módosítása"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Lehetővé teszi az alkalmazás számára az általános hangbeállítások, például a hangerő és a használni kívánt kimeneti hangszóró módosítását."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"hanganyag rögzítése"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lehetővé teszi az alkalmazás számára, hogy írjon az SD-kártyára."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"belső tár tartalmának módosítása/törlése"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Lehetővé teszi az alkalmazás számára, hogy módosítsa a belső háttértár tartalmát."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"dokumentumtárhely kezelése"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Lehetővé teszi az alkalmazás számára a dokumentumtárhely kezelését."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"hozzáf. minden felh. külső tár"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Minden felhasználó számára lehetővé teszi, hogy az alkalmazás hozzáférjen külső tárolókhoz."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"hozzáférés a gyorsítótár fájlrendszeréhez"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lehetővé teszi az alkalmazás számára, hogy kezelje a hálózati irányelveket és meghatározza az alkalmazásspecifikus szabályokat."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"hálózathasználat elszámolásának módosítása"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"szoftvercsatorna-jelölések módosítása"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Lehetővé teszi, hogy az alkalmazás módosítsa az útválasztáshoz használt szoftvercsatorna-jelöléseket"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lehetővé teszi a használó számára, hogy csatlakozzon egy értesítésfigyelő szolgáltatás legfelső szintű felületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"a szolgáltatói konfigurációs alkalmazás hívása"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lehetővé teszi a használó számára a szolgáltató által biztosított konfigurációs alkalmazás hívását. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Helyezzen be egy SIM kártyát."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"A SIM kártya hiányzik vagy nem olvasható. Helyezzen be egy SIM kártyát."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"A SIM kártya nem használható."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kártyája véglegesen letiltva."\n" Forduljon a vezeték nélküli szolgáltatójához másik SIM kártya beszerzése érdekében."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kártyája véglegesen letiltva.\n Forduljon a vezeték nélküli szolgáltatójához másik SIM kártya beszerzése érdekében."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Előző szám gomb"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Következő szám gomb"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Szünet gomb"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Nézze meg a felhasználói útmutatót, vagy vegye fel a kapcsolatot az ügyfélszolgálattal."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"A SIM-kártya le van zárva."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-kártya feloldása..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. "\n\n"Kérjük, <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva próbálja újra."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Ön helytelenül adta meg a jelszót <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. "\n" "\n" Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Ön <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. "\n" "\n" Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Helytelenül rajzolta le a feloldási mintát <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után a Google rendszerében használt bejelentkezési adataival kell feloldania a táblagépét."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Helytelenül rajzolta le a feloldási mintát <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után a Google rendszerében használt bejelentkezési adataival kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nKérjük, <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva próbálja újra."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Ön helytelenül adta meg a jelszót <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. \n \n Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Ön <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n \n Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Helytelenül rajzolta le a feloldási mintát <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után a Google rendszerében használt bejelentkezési adataival kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Helytelenül rajzolta le a feloldási mintát <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után a Google rendszerében használt bejelentkezési adataival kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"A táblagépet <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a táblagép gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"A telefont <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a telefon gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"A táblagépet <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a táblagép gyári alapértelmezett beállításait."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Jelszó"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Bejelentkezés"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Érvénytelen felhasználónév vagy jelszó."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Elfelejtette a felhasználónevét vagy jelszavát?"\n"Keresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Elfelejtette a felhasználónevét vagy jelszavát?\nKeresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Ellenőrzés..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Feloldás"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Hang bekapcsolása"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Navigáció megerősítése"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Oldal elhagyása"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Ezen az oldalon maradok"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Biztosan szeretné elhagyni az oldalt?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nBiztosan szeretné elhagyni az oldalt?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Megerősítés"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: érintse meg kétszer a nagyításhoz és kicsinyítéshez."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Kitöltés"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás sajnos leállt."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Sajnos a <xliff:g id="PROCESS">%1$s</xliff:g> alkalmazás leállt."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"A(z) <xliff:g id="APPLICATION">%2$s</xliff:g> nem válaszol."\n\n"Szeretné bezárni?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> tevékenység nem válaszol."\n\n"Szeretné bezárni?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"A(z) <xliff:g id="APPLICATION">%2$s</xliff:g> nem válaszol.\n\nSzeretné bezárni?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> tevékenység nem válaszol.\n\nSzeretné bezárni?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás nem válaszol. Szeretné bezárni?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"A(z) <xliff:g id="PROCESS">%1$s</xliff:g> folyamat nem válaszol. "\n\n"Szeretné bezárni?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"A(z) <xliff:g id="PROCESS">%1$s</xliff:g> folyamat nem válaszol. \n\nSzeretné bezárni?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Jelentés"</string>
     <string name="wait" msgid="7147118217226317732">"Várakozás"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Az oldal nem válaszol."\n\n"Szeretné bezárni?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Az oldal nem válaszol.\n\nSzeretné bezárni?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Alkalmazás átirányítva"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> éppen fut."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> volt eredetileg elindítva."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Lehetővé teszi az alkalmazás számára az alapértelmezett tárolószolgáltatás használatát tartalom másolásához. Normál alkalmazások nem használhatják."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Médiafájlok kimenetének irányítása"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Lehetővé teszi az alkalmazás számára, hogy más külső eszközökre irányítsa a médiafájlok lejátszását."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Hozzáférés a kóddal védett tárhelyhez"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lehetővé teszi egy alkalmazás számára, hogy hozzáférjen a kóddal védett tárhelyhez."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Billentyűzár megjelenítésének és elrejtésének vezérlése"</string>
+    <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="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Érintse meg kétszer a nagyítás beállításához"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nem sikerült hozzáadni a modult."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ugrás"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Kész"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Előző"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Végrehajtás"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Szám hívása"\n"ezzel: <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Névjegy létrehozása "\n"a(z) <xliff:g id="NUMBER">%s</xliff:g> szám használatával"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Szám hívása\nezzel: <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Névjegy létrehozása \na(z) <xliff:g id="NUMBER">%s</xliff:g> szám használatával"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"A következő egy vagy több alkalmazás hozzáférési engedélyt kér a fiókjához mostanra és a jövőre nézve is."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Engedélyezi ezt a kérelmet?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Hozzáférési kérelem"</string>
     <string name="allow" msgid="7225948811296386551">"Engedélyezés"</string>
     <string name="deny" msgid="2081879885755434506">"Elutasítás"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Az engedélykérés megtörtént"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Az engedélykérés megtörtént"\n"a(z) <xliff:g id="ACCOUNT">%s</xliff:g> fiók számára."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Az engedélykérés megtörtént\na(z) <xliff:g id="ACCOUNT">%s</xliff:g> fiók számára."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Beviteli mód"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Szinkronizálás"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Kisegítő lehetőségek"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Kapcsolódás..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Elérhető"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nem érhető el"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Használatban"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Beépített képernyő"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-képernyő"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>. fedvény"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> képpont"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", biztonságos"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Vezeték nélküli kijelző csatlakoztatva"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ez a kijelző megjelenítést végez egy másik eszközön"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Szétkapcsol"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Helytelen minta"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Helytelen jelszó"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Helytelen PIN kód"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Próbálkozzon újra <xliff:g id="NUMBER">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Próbálkozzon újra <xliff:g id="NUMBER">%1$d</xliff:g> másodperc múlva."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Rajzolja le a mintát"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Adja meg a SIM kártya PIN kódját"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Adja meg a PIN kódot"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Jelszó"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Bejelentkezés"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Érvénytelen felhasználónév vagy jelszó."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Elfelejtette a felhasználónevét vagy jelszavát?"\n"Keresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Elfelejtette a felhasználónevét vagy jelszavát?\nKeresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Fiók ellenőrzése..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. "\n\n"Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. "\n\n" Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. "\n\n"Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. \n\n Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"A táblagépet <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a táblagép gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"A telefont <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a telefon gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"A táblagépet <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a táblagép gyári alapértelmezett beállításait."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"A telefont <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a telefon gyári alapértelmezett beállításait."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eltávolítás"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"A javasolt szint fölé emeli a hangerőt?"\n"Ha hosszú ideig hangosan hallgatja a zenét, az károsíthatja a hallását."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"A javasolt szint fölé emeli a hangerőt?\nHa hosszú ideig hangosan hallgatja a zenét, az károsíthatja a hallását."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Továbbra is tartsa lenyomva két ujját a hozzáférés engedélyezéséhez."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Hozzáférés engedélyezve"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hozzáférés megszakítva."</string>
     <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
     <string name="owner_name" msgid="2716755460376028154">"Tulajdonos"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Hiba"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ez az alkalmazás nem támogatja a korlátozott profilokkal rendelkező fiókokat"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ez az alkalmazás nem támogatja a korlátozott profilokkal rendelkező fiókokat"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nincs megfelelő alkalmazás a művelet elvégzésére."</string>
     <string name="revoke" msgid="5404479185228271586">"Visszavonás"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"„Letter” méret"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"„Government Letter” méret"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"„Legal” méret"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"„Junior Legal\" méret"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"„Ledger” méret"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"„Tabloid” méret"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Törölve"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Hiba történt a tartalomírás közben"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN kód megadása"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Jelenlegi PIN kód"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Új PIN kód"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Új PIN kód megerősítése"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN kód létrehozása a korlátozások módosításához"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"A PIN kódok nem egyeznek. Próbálja újra."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"A PIN kód túl rövid. Legalább 4 számjegyből kell állnia."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Helytelen PIN kód. Próbálja újra 1 másodperc múlva."</item>
+    <item quantity="other" msgid="8030607343223287654">"Helytelen PIN kód. Próbálja újra <xliff:g id="COUNT">%d</xliff:g> másodperc múlva."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3db9137..c197e3b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Memungkinkan aplikasi memindah tugas ke latar depan dan latar belakang. Aplikasi dapat melakukannya tanpa masukan dari Anda."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"menghentikan apl yang berjalan"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Memungkinkan apl menghapus tugas dan menutup aplikasinya. Apl berbahaya dapat mengganggu perilaku apl lain."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"mengelola tumpukan aktivitas"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Memungkinkan aplikasi menambahkan, menghapus, dan mengubah tumpukan aktivitas yang dijalankan oleh aplikasi lain. Aplikasi berbahaya dapat mengganggu perilaku aplikasi lain."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"memulai aktivitas apa pun"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Mengizinkan aplikasi memulai aktivitas apa pun, terlepas dari perlindungan izin atau status yang diekspor."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"menyetel kompatibilitas layar"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu metode masukan. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"mengikat ke layanan aksesibilitas"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Mengizinkan pemegang untuk mengikat antarmuka tingkat tinggi dari suatu layanan. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"mengikat ke layanan pencetakan"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan pencetakan. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"mengakses semua tugas pencetakan"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Memungkinkan pemegang mengakses tugas pencetakan yang dibuat oleh aplikasi lain. Tidak pernah diperlukan aplikasi normal."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"mengikat ke layanan SMS"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan teks (misal: SpellCheckerService). Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"mengikat ke layanan VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"menambah atau menghapus admin perangkat"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Memungkinkan pemegang menambahkan atau menghapus administrator perangkat aktif. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Mengizinkan apl mengubah rotasi layar kapan saja. Tidak pernah dibutuhkan oleh apl normal."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ubah kecepatan penunjuk"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Mengizinkan apl menggunakan fitur tingkat rendah SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"baca buffer frame"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Mengizinkan apl membaca konten penyangga frame."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"mengakses InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Memungkinkan aplikasi menggunakan fitur tingkat rendah InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"mengonfigurasi tampilan Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Izinkan aplikasi mengonfigurasi dan terhubung ke tampilan Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"mengontrol tampilan Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Izinkan aplikasi mengontrol fitur tingkat rendah dari tampilan Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ubah setelan audio Anda"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Memungkinkan aplikasi mengubah setelan audio global, misalnya volume dan pengeras suara mana yang digunakan untuk keluaran."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"rekam audio"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Memungkinkan apl menulis ke kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubah/hapus konten penyimpanan media internal"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Mengizinkan apl memodifikasi konten penyimpanan media internal."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"kelola penyimpanan dokumen"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Mengizinkan aplikasi mengelola penyimpanan dokumen."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"akses penyimpanan eksternal"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Izinkan aplikasi mengakses penyimpanan eksternal untuk semua pengguna."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"akses sistem file cache."</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Mengizinkan apl mengelola kebijakan jaringan dan menentukan peraturan khusus apl."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"mengubah penghitungan penggunaan jaringan"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"mengubah tanda soket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Memungkinkan aplikasi mengubah tanda soket untuk perutean"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Memungkinkan pemegang mengikat antarmuka tingkat teratas dari suatu layanan pendengar pemberitahuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"memanggil aplikasi konfigurasi yang disediakan operator"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Memungkinkan pemegang meminta aplikasi konfigurasi yang disediakan operator. Tidak pernah diperlukan aplikasi normal."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Masukkan kartu SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Kartu SIM tidak ada atau tidak dapat dibaca. Masukkan kartu SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Kartu SIM tidak dapat digunakan."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Kartu SIM Anda telah dinonaktifkan secara permanen."\n" Hubungi penyedia layanan nirkabel Anda untuk kartu SIM lain."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Kartu SIM Anda telah dinonaktifkan secara permanen.\n Hubungi penyedia layanan nirkabel Anda untuk kartu SIM lain."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Tombol trek sebelumnya"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Tombol trek berikutnya"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Tombol jeda"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Lihatlah Panduan Pengguna atau hubungi Layanan Pelanggan."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Kartu SIM terkunci."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Membuka kartu SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan proses masuk Google."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan proses masuk Google."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan proses masuk Google.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan proses masuk Google.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Anda telah gagal mencoba membuka gembok tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> upaya gagal lagi, tablet akan disetel ulang ke setelan default pabrik dan semua data pengguna hilang."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Anda telah gagal mencoba membuka gembok ponsel sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> upaya gagal lagi, ponsel akan disetel ulang ke setelan default pabrik dan semua data pengguna hilang."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Anda telah gagal mencoba membuka gembok tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Kini tablet akan disetel ulang ke setelan default pabrik."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Sandi"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Masuk"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nama pengguna atau sandi tidak valid."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Lupa nama pengguna atau sandi Anda?"\n"Kunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Lupa nama pengguna atau sandi Anda?\nKunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Memeriksa..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Buka kunci"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Suara hidup"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Konfirmasi Navigasi"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Keluar dari Laman ini"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Tetap di Laman ini"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Yakin ingin beranjak dari laman ini?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nYakin ingin beranjak dari laman ini?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Isiotomatis"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Sayangnya, <xliff:g id="APPLICATION">%1$s</xliff:g> telah berhenti."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Sayangnya, proses <xliff:g id="PROCESS">%1$s</xliff:g> telah berhenti."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> tidak menanggapi."\n\n"Anda ingin menutupnya?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivitas <xliff:g id="ACTIVITY">%1$s</xliff:g> tidak menanggapi."\n\n"Anda ingin menutupnya?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> tidak menanggapi.\n\nAnda ingin menutupnya?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivitas <xliff:g id="ACTIVITY">%1$s</xliff:g> tidak menanggapi.\n\nAnda ingin menutupnya?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> tidak menanggapi. Anda ingin menutupnya?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> tidak menanggapi."\n\n"Anda ingin menutupnya?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> tidak menanggapi.\n\nAnda ingin menutupnya?"</string>
     <string name="force_close" msgid="8346072094521265605">"Oke"</string>
     <string name="report" msgid="4060218260984795706">"Laporkan"</string>
     <string name="wait" msgid="7147118217226317732">"Tunggu"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak menanggapi."\n\n"Apakah Anda ingin menutupnya?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak menanggapi.\n\nApakah Anda ingin menutupnya?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Apl dialihkan"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Mengizinkan apl menjalankan layanan kontainer default untuk menyalin konten. Tidak untuk digunakan oleh apl normal."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Menentukan rute keluaran media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Memungkinkan aplikasi menentukan rute keluaran media ke perangkat eksternal lainnya."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Mengakses pengaman penyimpanan aman"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Mengizinkan aplikasi mengakses pengaman penyimpanan aman."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrol untuk menampilkan dan menyembunyikan pengaman"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Izinkan aplikasi untuk mengontrol pengaman."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mengontrol perbesar/perkecil"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Tidak dapat menambahkan widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Buka"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Selesai"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Sebelumnya"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Lakukan"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Panggil nomor "\n"menggunakan<xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Buat kontak "\n"menggunakan <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Panggil nomor \nmenggunakan<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Buat kontak \nmenggunakan <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Satu atau beberapa apl meminta izin untuk mengakses akun Anda, sekarang dan di masa mendatang."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Apakah Anda ingin mengizinkan permintaan ini?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Permintaan akses"</string>
     <string name="allow" msgid="7225948811296386551">"Izinkan"</string>
     <string name="deny" msgid="2081879885755434506">"Tolak"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Izin dimintakan"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Izin dimintakan"\n"untuk akun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Izin dimintakan\nuntuk akun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Metode masukan"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinkron"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Aksesibilitas"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Tidak tersedia"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Sedang digunakan"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Layar Bawaan"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Layar HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", aman"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Layar nirkabel tersambung"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Layar ini ditampilkan di perangkat lain"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Putuskan sambungan"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pola Salah"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Sandi Salah"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Salah"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Coba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Coba lagi dalam <xliff:g id="NUMBER">%1$d</xliff:g> detik."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Gambar pola Anda"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Sandi"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Masuk"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau sandi tidak valid."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau sandi Anda?"\n"Kunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau sandi Anda?\nKunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Memeriksa akun…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, tablet akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali gagal saat berusaha membuka kunci ponsel. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, ponsel akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Kini tablet akan disetel ulang ke setelan default pabrik."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha untuk membuka kunci ponsel. Kini ponsel akan disetel ulang ke setelan default pabrik."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hapus"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Naikkan volume di atas tingkat aman?"\n"Mendengarkan volume tinggi dalam jangka waktu yang lama dapat merusak pendengaran Anda."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Naikkan volume di atas tingkat aman?\nMendengarkan volume tinggi dalam jangka waktu yang lama dapat merusak pendengaran Anda."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tahan terus dua jari untuk mengaktifkan aksesibilitas."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Aksesibilitas diaktifkan."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Aksesibilitas dibatalkan."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Pemilik"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Kesalahan"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Aplikasi ini tidak mendukung akun untuk profil yang dibatasi"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Aplikasi ini tidak mendukung akun untuk profil yang dibatasi"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Tidak ada aplikasi yang ditemukan untuk menangani tindakan ini"</string>
     <string name="revoke" msgid="5404479185228271586">"Cabut"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Dibatalkan"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Terjadi kesalahan saat menulis konten"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Masukkan PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN Saat Ini"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN Baru"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Konfirmasi PIN baru"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Buat PIN untuk mengubah batasan"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN tidak cocok. Coba lagi."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN terlalu pendek. Minimal 4 digit."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN salah. Coba lagi dalam 1 detik."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN salah. Coba lagi dalam <xliff:g id="COUNT">%d</xliff:g> detik."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 416c534..7846956 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Consente all\'applicazione di spostare attività in primo piano e in background. L\'applicazione potrebbe farlo senza un tuo comando."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestione di stack attività"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Consente all\'app di aggiungere, rimuovere e modificare stack attività in cui vengono eseguite altre app. Le app dannose possono alterare il funzionamento delle altre app."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"inizio di un\'attività"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Consente all\'applicazione di iniziare un\'attività, indipendentemente dalla protezione delle autorizzazioni o dallo stato esportato."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"impostazione compatibilità schermo"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Consente l\'associazione di un metodo di inserimento all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"collegamento a un servizio di accessibilità"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di accessibilità. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"collegamento a un servizio di stampa"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di stampa. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accesso a tutti i processi di stampa"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Consente al titolare di accedere ai processi di stampa creati da un\'altra app. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"associazione a servizio NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Consente al titolare di collegarsi alle applicazioni che emulano carte NFC. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"associazione a un servizio di testo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di testo (ad esempio SpellCheckerService). Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"associazione a un servizio VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"aggiungere o rimuovere un amministratore del dispositivo"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Consente al titolare di aggiungere o rimuovere gli amministratori attivi del dispositivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Consente all\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambio velocità del puntatore"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Consente all\'applicazione l\'utilizzo di funzioni di basso livello SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Consente all\'applicazione di leggere i contenuti del buffer di frame."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accesso a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Consente all\'applicazione di utilizzare funzioni di basso livello InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurazione di schermi Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Consente all\'applicazione di configurare schermi Wi-Fi e di collegarsi a essi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controllo di schermi Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Consente all\'applicazione di controllare le funzioni di basso livello di schermi Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Consente all\'applicazione di scrivere sulla scheda SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modifica/eliminaz. contenuti archivio media int."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Consente all\'applicazione di modificare i contenuti dell\'archivio media interno."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"gestione della memorizzazione dei documenti"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Consente all\'app di gestire la memorizzazione dei documenti."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"accesso memoria esterna utenti"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Consente all\'applicazione di accedere alla memoria esterna di tutti gli utenti."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accesso al filesystem nella cache"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Consente all\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifica di contrassegni socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Consente all\'app di modificare i contrassegni socket per il routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserisci una scheda SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Scheda SIM mancante o non leggibile. Inserisci una scheda SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Scheda SIM inutilizzabile."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"La scheda SIM è stata disattivata definitivamente."\n" Contatta il fornitore del tuo servizio wireless per ricevere un\'altra scheda SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"La scheda SIM è stata disattivata definitivamente.\n Contatta il fornitore del tuo servizio wireless per ricevere un\'altra scheda SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Pulsante traccia precedente"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Pulsante traccia successiva"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pulsante Pausa"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la Guida dell\'utente o contatta il servizio clienti."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La SIM è bloccata."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Sblocco SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con i tuoi dati di accesso Google."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con i tuoi dati di accesso Google."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con i tuoi dati di accesso Google.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con i tuoi dati di accesso Google.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Hai erroneamente tentato di sbloccare il tablet <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi non riusciti, il tablet verrà sottoposto a un ripristino dati di fabbrica e tutti i dati utente andranno persi."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Hai erroneamente tentato di sbloccare il telefono <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi non riusciti, il telefono verrà sottoposto a un ripristino dati di fabbrica e tutti i dati utente andranno persi."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Hai erroneamente tentato di sbloccare il tablet <xliff:g id="NUMBER">%d</xliff:g> volte. Il tablet ora verrà sottoposto a un ripristino dati di fabbrica."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Password"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Accedi"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Password o nome utente non valido."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Hai dimenticato il nome utente o la password?"\n"Visita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Hai dimenticato il nome utente o la password?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Verifica..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Sblocca"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Audio attivato"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Conferma navigazione"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Abbandona questa pagina"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rimani su questa pagina"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vuoi abbandonare la pagina?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVuoi abbandonare la pagina?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Suggerimento. Tocca due volte per aumentare e diminuire lo zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Compilazione autom."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> si è bloccata in modo anomalo."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> si è interrotto."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> non risponde."\n\n"Vuoi chiuderla?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> non risponde."\n\n"Vuoi chiuderla?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> non risponde.\n\nVuoi chiuderla?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> non risponde.\n\nVuoi chiuderla?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> non risponde. Vuoi chiuderla?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde."\n\n"Vuoi chiuderlo?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde.\n\nVuoi chiuderlo?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Segnala"</string>
     <string name="wait" msgid="7147118217226317732">"Attendi"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"La pagina non risponde più."\n\n"Vuoi chiuderla?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La pagina non risponde più.\n\nVuoi chiuderla?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Applicazione reindirizzata"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> è ora in esecuzione."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> già avviata."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Consente all\'applicazione di richiamare il servizio container predefinito per la copia di contenuti. Da non usare per normali applicazioni."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Indirizzamento uscita media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Consente a un\'applicazione di indirizzare l\'uscita di media verso altri dispositivi esterni."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Accesso all\'archivio sicuro keyguard"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Consente a un\'applicazione di accedere all\'archivio sicuro keguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Controllo della visualizzazione e dell\'occultamento di keyguard"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Consente a un\'applicazione di controllare keguard."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tocca due volte per il comando dello zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Aggiunta del widget non riuscita."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Vai"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Fine"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Prec."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Esegui"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Componi numero"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Crea contatto"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Componi numero\nutilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Crea contatto\nutilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Le seguenti applicazioni richiedono l\'autorizzazione per accedere al tuo account, adesso e in futuro."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Accettare la richiesta?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Richiesta di accesso"</string>
     <string name="allow" msgid="7225948811296386551">"Consenti"</string>
     <string name="deny" msgid="2081879885755434506">"Nega"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Autorizzazione richiesta"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Autorizzazione richiesta"\n"per l\'account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Autorizzazione richiesta\nper l\'account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Metodo inserimento"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinc"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilità"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connessione..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponibile"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Non disponibili"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"In uso"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Schermo incorporato"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Schermo HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay n. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", opzione sicura"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Il display wireless è connesso"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Questa schermata è mostrata su un altro dispositivo"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnetti"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequenza sbagliata"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Password sbagliata"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN errato"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Riprova fra <xliff:g id="NUMBER">%1$d</xliff:g> secondi."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Inserisci la sequenza"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Inserisci il PIN della SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Inserisci PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Accedi"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome utente o password non validi."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Hai dimenticato il nome utente o la password?"\n"Visita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Hai dimenticato il nome utente o la password?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Controllo account…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di sblocco del tablet. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il tablet verrà sottoposto a un ripristino dei dati di fabbrica e tutti i dati utente andranno persi."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di sblocco del telefono. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il telefono verrà sottoposto a un ripristino dei dati di fabbrica e tutti i dati utente andranno persi."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"<xliff:g id="NUMBER">%d</xliff:g> tentativi errati di sblocco del tablet. Il tablet verrà sottoposto a un ripristino dei dati di fabbrica."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"<xliff:g id="NUMBER">%d</xliff:g> tentativi errati di sblocco del telefono. Il telefono verrà sottoposto a un ripristino dei dati di fabbrica."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentare il volume oltre il livello di sicurezza?"\n"Ascoltare musica ad alto volume per lunghi periodi potrebbe danneggiare l\'udito."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentare il volume oltre il livello di sicurezza?\nAscoltare musica ad alto volume per lunghi periodi potrebbe danneggiare l\'udito."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Continua a tenere premuto con due dita per attivare l\'accessibilità."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibilità attivata."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilità annullata."</string>
     <string name="user_switched" msgid="3768006783166984410">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietario"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Errore"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Questa applicazione non supporta account relativi a profili con limitazioni"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Questa app non supporta account relativi a profili con limitazioni"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nessuna applicazione trovata in grado di gestire questa azione"</string>
     <string name="revoke" msgid="5404479185228271586">"Revoca"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Lettera"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legale"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legale \"junior\""</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annullato"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Errore nella scrittura dei contenuti"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Inserisci PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN corrente"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nuovo PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Conferma il nuovo PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un PIN per la modifica delle limitazioni"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"I PIN non corrispondono. Riprova."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Il PIN è troppo corto. Deve avere almeno quattro cifre."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN errato. Riprova tra 1 s."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN errato. Riprova tra <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7afb72c..c50cc14 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"מאפשר ליישום להעביר משימות לחזית ולרקע. היישום עשוי לעשות זאת ללא התערבותך."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"ניהול של ערימות פעילות"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"ההרשאה הזו מאפשרת לאפליקציה להוסיף, להסיר ולשנות את ערימות הפעילות שבהן רצות אפליקציות אחרות. אפליקציות זדוניות עלולת להפריע להתנהגות של אפליקציות אחרות."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"התחלת פעילות מכל סוג שהוא"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"מאפשר ליישום להתחיל בפעילות מכל סוג שהוא, ללא התחשבות בהגנת הרשאות או במצב מיוצא."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"הגדרת תאימות מסך"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שיטת קלט. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"הכפפה לשירות נגישות"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"מתיר לבעלים להכפיף לממשק ברמה העליונה של שירות זמינות. הרשאה זו אף פעם אינה אמורה להיות נחוצה ליישומים רגילים."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"איגוד לשירות הדפסה"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ההרשאה הזו מאפשרת לבעלים לבצע איגוד לממשק הרמה העליונה של שירות הדפסה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"גישה אל כל עבודות ההדפסה"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"ההרשאה הזו מאפשרת לבעלים לגשת לעבודות הדפסה שנוצרו על ידי אפליקציה אחרת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"איגוד לשירות NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"מאפשרת לבעלים לאגד את האפליקציות המחקות כרטיסיות NFC. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"הכפפה לשירות טקסט"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"מאפשר למשתמש ליצור איגוד לממשק הרמה העליונה של שירות טקסט (למשל, SpellCheckerService). הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"אגד לשירות VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"הוספה או הסרה של מנהלי מכשיר"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"מאפשרת לבעלים להוסיף או להסיר מנהלי מכשיר פעילים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"מאפשר ליישום לשנות את הסיבוב של המסך בכל עת. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"שינוי מהירות המצביע"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"מאפשר ליישום להשתמש בתכונות ברמה הנמוכה של SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"אחסון זמני של מסגרת קריאה"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"מאפשר ליישום לקרוא את התוכן של מאגר הנתונים הזמני של המסגרות."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"גישה אל InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"מאפשרת לאפליקציה להשתמש בתכונות ברמה נמוכה של InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"הגדר תצוגות Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"מאפשר לאפליקציה להגדיר ולהתחבר לתצוגות Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"שלוט בתצוגות Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"מאפשר לאפליקציה לשלוט בתכונות ברמה נמוכה של תצוגות Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"שנה את הגדרות האודיו שלך"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"מאפשר ליישום לשנות הגדרות אודיו גלובליות כמו עוצמת קול ובחירת הרמקול המשמש לפלט."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"הקלט אודיו"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"מאפשר ליישום לכתוב לכרטיס ה-SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"שנה/מחק תוכן של אחסון מדיה פנימי"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"מאפשר ליישום לשנות את התוכן של אמצעי האחסון הפנימי למדיה."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"ניהול של אחסון מסמכים"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"מאפשר ליישום לנהל אחסון מסמכים."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"גישה לאחסון חיצוני, כל המשתמשים"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"מאפשר ליישום לגשת לאחסון חיצוני עבור כל המשתמשים."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"גישה למערכת הקבצים בקובץ השמור"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"מאפשר ליישום לנהל מדיניות הרשת להגדיר כללים ספציפיים-ליישום."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"שנה ניהול חשבונות של שימוש ברשת"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"שינוי של סימני Socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"ההרשאה הזו מאפשרת לאפליקציה לשנות סימני Socket עבור ניתוב"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר ליישום לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי יישומים אחרים."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה ליישומים רגילים."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"הכנס כרטיס SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"כרטיס ה-SIM חסר או שלא ניתן לקרוא אותו. הכנס כרטיס SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"לא ניתן להשתמש בכרטיס SIM זה."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"כרטיס ה-SIM שלך הושבת לצמיתות."\n"פנה לספק השירות האלחוטי שלך לקבלת כרטיס SIM אחר."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"כרטיס ה-SIM שלך הושבת לצמיתות.\nפנה לספק השירות האלחוטי שלך לקבלת כרטיס SIM אחר."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"לחצן הרצועה הקודמת"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"לחצן הרצועה הבאה"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"לחצן ההשהיה"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"עיין במדריך למשתמש או פנה לשירות הלקוחות."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"כרטיס ה-SIM נעול."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"מבטל נעילה של כרטיס SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. "\n\n"נסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%d</xliff:g> פעמים."\n\n"נסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"הקלדת קוד PIN שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים."\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%d</xliff:g> פעמים.\n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"הקלדת קוד PIN שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים.\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_now_wiping" product="tablet" msgid="280873516493934365">"ביצעת <xliff:g id="NUMBER">%d</xliff:g> ניסיונות שגויים לביטול נעילת הטבלט. הטבלט יעבור כעת איפוס לברירת המחדל של היצרן."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"סיסמה"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"כניסה"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"שם משתמש או סיסמה לא חוקיים."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"שכחת את שם המשתמש או הסיסמה?"\n"בקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"שכחת את שם המשתמש או הסיסמה?\nבקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"בודק..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"בטל נעילה"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"קול פועל"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"אישור ניווט"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"צא מדף זה"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"הישאר בדף זה"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"האם אתה בטוח שברצונך לנווט אל מחוץ לדף זה?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nהאם אתה בטוח שברצונך לנווט אל מחוץ לדף זה?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"אשר"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"טיפ: הקש פעמיים כדי להגדיל ולהקטין."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"מילוי אוטומטי"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"לצערנו, פעולת <xliff:g id="APPLICATION">%1$s</xliff:g> הופסקה."</string>
     <string name="aerr_process" msgid="4507058997035697579">"לצערנו, התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הופסק."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> אינו מגיב."\n\n"תרצה לסגור אותו?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"הפעילות <xliff:g id="ACTIVITY">%1$s</xliff:g> אינה מגיבה."\n\n"תרצה לסגור אותה?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> אינו מגיב.\n\nתרצה לסגור אותו?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"הפעילות <xliff:g id="ACTIVITY">%1$s</xliff:g> אינה מגיבה.\n\nתרצה לסגור אותה?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> אינו מגיב. תרצה לסגור אותו?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"תהליך <xliff:g id="PROCESS">%1$s</xliff:g> אינו מגיב."\n\n"תרצה לסגור אותו?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"תהליך <xliff:g id="PROCESS">%1$s</xliff:g> אינו מגיב.\n\nתרצה לסגור אותו?"</string>
     <string name="force_close" msgid="8346072094521265605">"אישור"</string>
     <string name="report" msgid="4060218260984795706">"שלח דוח"</string>
     <string name="wait" msgid="7147118217226317732">"המתן"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"הדף אינו מגיב."\n\n"האם אתה רוצה לסגור אותו?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"הדף אינו מגיב.\n\nהאם אתה רוצה לסגור אותו?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"הפנייה מחדש של יישום"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> פועל כעת."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> הופעל במקור."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"מאפשר ליישום להפעיל שירות גורם מכיל המוגדר כברירת מחדל להעתקת תוכן. לא מיועד לשימוש על ידי יישומים רגילים."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"ניתוב פלט מדיה"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"מאפשר ליישום לנתב פלט מדיה למכשירים חיצוניים אחרים."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"גישה לאחסון המוגן באמצעות מפתח"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"מאפשר ליישום לגשת לאחסון המוגן באמצעות מפתח."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"שלוט בהצגה והסתרה של מגן המקלדת"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"מאפשר ליישום לשלוט במגן המקלדת."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"גע פעמיים לבקרת מרחק מתצוגה"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"לא ניתן להוסיף widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"התחל"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"סיום"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"הקודם"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"בצע"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"חייג למספר"\n"באמצעות <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"צור איש קשר"\n"באמצעות <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"חייג למספר\nבאמצעות <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"צור איש קשר\nבאמצעות <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"היישומים הבאים מבקשים אישור לגשת לחשבונך, כעת ובעתיד."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"האם ברצונך לאפשר בקשה זו?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"בקשת גישה"</string>
     <string name="allow" msgid="7225948811296386551">"אפשר"</string>
     <string name="deny" msgid="2081879885755434506">"דחה"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"בקשת הרשאה"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"נדרשת הרשאה"\n"לחשבון <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"נדרשת הרשאה\nלחשבון <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"שיטת קלט"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"סינכרון"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"נגישות"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"מתחבר..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"זמין"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"לא זמין"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"בשימוש"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"מסך מובנה"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"מסך HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"שכבת על #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: ‎<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>‎, ‏<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", מאובטח"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"מסך אלחוטי מחובר"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"מסך זה מוצג במכשיר אחר"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"נתק"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"קו ביטול נעילה שגוי"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"סיסמה שגויה"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"מספר PIN שגוי"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"נסה שוב בעוד <xliff:g id="NUMBER">%d</xliff:g> שניות."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"נסה שוב בעוד <xliff:g id="NUMBER">%1$d</xliff:g> שניות."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"שרטט את קו ביטול הנעילה"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"הזן מספר PIN ל-SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"הזן מספר PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"סיסמה"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"היכנס"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"שם משתמש או סיסמה לא חוקיים."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"שכחת את שם המשתמש או הסיסמה?"\n"בקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"שכחת את שם המשתמש או הסיסמה?\nבקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"בודק חשבון…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"הקלדת מספר 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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"הסר"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?"\n"האזנה בעוצמת קול גבוהה למשך זמן ארוך עלולה לפגוע בשמיעה."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\nהאזנה בעוצמת קול גבוהה למשך זמן ארוך עלולה לפגוע בשמיעה."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"המשך לגעת בשתי אצבעות כדי להפעיל נגישות."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"נגישות הופעלה."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"נגישות בוטלה."</string>
     <string name="user_switched" msgid="3768006783166984410">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"בעלים"</string>
     <string name="error_message_title" msgid="4510373083082500195">"שגיאה"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"היישום הזה לא תומך בחשבונות עבור פרופילים מוגבלים"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"האפליקציה הזו לא תומכת בחשבונות עבור פרופילים מוגבלים"</string>
     <string name="app_not_found" msgid="3429141853498927379">"לא נמצא יישום שתומך בפעולה זו"</string>
     <string name="revoke" msgid="5404479185228271586">"בטל"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"בוטלה"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"שגיאה בכתיבת תוכן"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"הזן מספר PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"מספר PIN נוכחי"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"מספר PIN חדש"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"אשר את מספר ה-PIN החדש"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"צור מספר PIN לשינוי הגבלות"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"מספרי ה-PIN לא תואמים. נסה שוב."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"מספר ה-PIN קצר מדי. חייב להיות באורך 4 ספרות לפחות."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"מספר PIN שגוי. נסה שוב בעוד שניה."</item>
+    <item quantity="other" msgid="8030607343223287654">"מספר PIN שגוי. נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ja/bools.xml b/core/res/res/values-ja/bools.xml
new file mode 100644
index 0000000..59cf744
--- /dev/null
+++ b/core/res/res/values-ja/bools.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resources>
+    <bool name="flip_controller_fallback_keys">true</bool>
+</resources>
+
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 340774c..ba810bf 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。これにより、アプリがユーザーからの入力なしでこの処理を実行する可能性があります。"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"実行中のアプリの停止"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"タスクの削除とアプリの終了をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリの動作が妨害される恐れがあります。"</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"アクティビティスタックの管理"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"他のアプリを実行するアクティビティスタックを追加、削除、変更することをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリの動作が妨害される恐れがあります。"</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"すべてのアクティビティの開始"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"権限による保護やエクスポートされた状態を問わず、すべてのアクティビティを開始することをアプリに許可します。"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"画面互換性の設定"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"入力方法のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ユーザー補助サービスにバインド"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ユーザー補助サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"印刷サービスへのバインド"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"印刷サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"すべての印刷ジョブへのアクセス"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"別のアプリが作成した印刷ジョブにアクセスすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"NFCサービスへのバインド"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"NFCカードをエミュレートしているアプリにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"テキストサービスにバインド"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"テキストサービス(SpellCheckerServiceなど)のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPNサービスにバインド"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"端末の管理者の追加または削除"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"有効な端末の管理者を追加または削除することを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"いつでも画面の向きを変更することをアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ポインタの速度の変更"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"SurfaceFlingerの低レベルの機能の使用をアプリに許可します。"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"フレームバッファの読み取り"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"フレームバッファの内容の読み取りをアプリに許可します。"</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlingerへのアクセス"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"InputFlingerの低レベルの機能を使用することをアプリに許可します。"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fiディスプレイの設定"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Wi-Fiディスプレイを設定して接続することをアプリに許可します。"</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fiディスプレイの制御"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wi-Fiディスプレイの低レベル機能を制御することをアプリに許可します。"</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"音声設定の変更"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"音声全般の設定(音量、出力に使用するスピーカーなど)の変更をアプリに許可します。"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"録音"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"SDカードへの書き込みをアプリに許可します。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"内部メディアストレージの内容の変更/削除"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"内部メディアストレージの内容を変更することをアプリに許可します。"</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"ドキュメントストレージの管理"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"ドキュメントストレージの管理をアプリに許可します。"</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"全ユーザー外部ストレージへのアクセス"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"すべてのユーザーの外部ストレージへのアクセスをアプリに許可します。"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"キャッシュファイルシステムにアクセス"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"ネットワークポリシーを管理しアプリ固有のルールを定義することをアプリに許可します。"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ネットワークの課金の変更"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"アプリに対するネットワーク利用の計算方法を変更することをアプリに許可します。通常のアプリでは使用しません。"</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"ソケットマークの変更"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"ルーティングのソケットマークを変更することをアプリに許可します。"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"通知にアクセス"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"携帯通信会社が提供する設定アプリの呼び出し"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"ハングアウト"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"SIMカードを挿入してください。"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIMカードが見つからないか読み取れません。SIMカードを挿入してください。"</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIMカードは使用できません。"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"お使いのSIMカードは永久に無効となっています。"\n"ワイヤレスサービスプロバイダに問い合わせて新しいSIMカードを入手してください。"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"お使いのSIMカードは永久に無効となっています。\nワイヤレスサービスプロバイダに問い合わせて新しいSIMカードを入手してください。"</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"前のトラックボタン"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"次のトラックボタン"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"一時停止ボタン"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"ユーザーガイドをご覧いただくか、お客様サポートにお問い合わせください。"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIMカードはロックされています。"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIMカードのロック解除中..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"正しくないパスワードを<xliff:g id="NUMBER_0">%d</xliff:g>回入力しました。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"正しくないPINを<xliff:g id="NUMBER_0">%d</xliff:g>回入力しました。"\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"正しくないパスワードを<xliff:g id="NUMBER_0">%d</xliff:g>回入力しました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"正しくないPINを<xliff:g id="NUMBER_0">%d</xliff:g>回入力しました。\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_now_wiping" product="tablet" msgid="280873516493934365">"タブレットのロック解除を<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。タブレットを工場出荷状態にリセットします。"</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"パスワード"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ログイン"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ユーザー名またはパスワードが正しくありません。"</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"ユーザー名またはパスワードを忘れた場合は"\n" "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"ユーザー名またはパスワードを忘れた場合は\n "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"確認中..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"ロック解除"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"サウンドON"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"ナビゲーションの確認"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"このページから移動"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"このページのまま"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"このページから移動してもよろしいですか?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nこのページから移動してもよろしいですか?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"ヒント: ダブルタップで拡大/縮小できます。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自動入力"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"問題が発生したため、<xliff:g id="APPLICATION">%1$s</xliff:g>を終了します。"</string>
     <string name="aerr_process" msgid="4507058997035697579">"問題が発生したため、プロセス「<xliff:g id="PROCESS">%1$s</xliff:g>」を終了します。"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>は応答していません。"\n\n"このアプリを終了しますか?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"操作「<xliff:g id="ACTIVITY">%1$s</xliff:g>」は応答していません。"\n\n"この操作を終了しますか?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>は応答していません。\n\nこのアプリを終了しますか?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"操作「<xliff:g id="ACTIVITY">%1$s</xliff:g>」は応答していません。\n\nこの操作を終了しますか?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g>は応答していません。このアプリを終了しますか?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"プロセス「<xliff:g id="PROCESS">%1$s</xliff:g>」は応答していません。"\n\n"このプロセスを終了しますか?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"プロセス「<xliff:g id="PROCESS">%1$s</xliff:g>」は応答していません。\n\nこのプロセスを終了しますか?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"レポート"</string>
     <string name="wait" msgid="7147118217226317732">"待機"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"ページが応答しません。"\n\n"ページを閉じますか?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"ページが応答しません。\n\nページを閉じますか?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"アプリのリダイレクト"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>が実行中です。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>が最初に起動していました。"</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"デフォルトのコンテナサービスを呼び出してコンテンツをコピーすることをアプリに許可します。通常のアプリでは使用しません。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"メディア出力のルーティング"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"メディア出力を他の外部デバイスにルーティングすることをアプリに許可します。"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"キーガードセキュアストレージへのアクセス"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"キーガードセキュアストレージへのアクセスをアプリに許可する"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"キーガードの表示/非表示の制御"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"キーガードの制御をアプリに許可します。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ダブルタップでズームコントロール"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ウィジェットを追加できませんでした。"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"移動"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"完了"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"前へ"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"実行"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>を使って"\n"発信"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>を使って"\n"連絡先を新規登録"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>を使って\n発信"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>を使って\n連絡先を新規登録"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"以下のアプリが、お使いのアカウントに今後アクセスする権限をリクエストしています。"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"このリクエストを許可してもよろしいですか?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"アクセスリクエスト"</string>
     <string name="allow" msgid="7225948811296386551">"許可"</string>
     <string name="deny" msgid="2081879885755434506">"拒否"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"権限がリクエストされました"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"次のアカウントにアクセスする権限が"\n"リクエストされました: <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"次のアカウントにアクセスする権限が\nリクエストされました: <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"入力方法"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"同期"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"ユーザー補助"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"接続中..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"利用できます"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"利用できません"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"使用中"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"内蔵スクリーン"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI画面"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"オーバーレイ第<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>、<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"、セキュア"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"ワイヤレスディスプレイが接続されています"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"この画面は別の端末で表示されています"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"切断"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"パターンが正しくありません"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"パスワードが正しくありません"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PINが正しくありません"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g>秒後にもう一度お試しください。"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g>秒後にもう一度お試しください。"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"パターンを入力"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PINを入力"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PINを入力"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"パスワード"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"ログイン"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"ユーザー名またはパスワードが無効です。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ユーザー名またはパスワードを忘れた場合は"\n" "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ユーザー名またはパスワードを忘れた場合は\n "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"アカウントをチェックしています…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"削除"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"推奨レベルを超えるまで音量を上げますか?"\n"大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"推奨レベルを超えるまで音量を上げますか?\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ユーザー補助機能を有効にするには2本の指で押し続けてください。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"ユーザー補助が有効になりました。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ユーザー補助をキャンセルしました。"</string>
     <string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
     <string name="owner_name" msgid="2716755460376028154">"所有者"</string>
     <string name="error_message_title" msgid="4510373083082500195">"エラー"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"このアプリでは制限付きプロフィールのアカウントはサポートしていません"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"このアプリでは制限付きプロフィールのアカウントはサポートしていません"</string>
     <string name="app_not_found" msgid="3429141853498927379">"この操作を行うアプリが見つかりません"</string>
     <string name="revoke" msgid="5404479185228271586">"取り消し"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"レター"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"ガバメントレター"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"リーガル"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"ジュニアリーガル"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"レジャー"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"タブロイド"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"キャンセルされました"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"コンテンツの書き込み中にエラーが発生しました"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PINを入力"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"現在のPIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"新しいPIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"新しいPINの確認"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"制限を変更するためのPINを作成してください"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINが一致しません。もう一度お試しください。"</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PINが短すぎます。4桁以上にしてください。"</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PINが正しくありません。1秒後にもう一度お試しください。"</item>
+    <item quantity="other" msgid="8030607343223287654">"PINが正しくありません。<xliff:g id="COUNT">%d</xliff:g>秒後にもう一度お試しください。"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 73cdb1c..5207c6a 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"앱이 사용자의 입력 없이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"실행 중인 앱 중지"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"애플리케이션이 작업을 삭제하거나 다른 애플리케이션을 중지시킬 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"작업 스택 관리"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"앱이 다른 앱에서 실행하는 작업 스택을 추가, 삭제 또는 수정하도록 합니다. 악성 앱은 다른 앱의 동작을 방해할 수 있습니다."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"원하는 활동 시작"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"권한 보호나 내보낸 상태에 관계없이 앱이 활동을 시작하도록 합니다."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"화면 호환성 설정"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"권한을 가진 프로그램이 입력 방법에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"접근성 서비스와 연결"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"권한을 가진 프로그램이 접근성 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"인쇄 서비스 사용"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"권한을 가진 프로그램이 인쇄 서비스에 대한 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"모든 인쇄 작업에 액세스"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"권한을 가진 프로그램이 다른 앱에서 생성한 인쇄 작업에 액세스하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"텍스트 서비스 연결"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"권한을 가진 프로그램이 텍스트 서비스(예: SpellCheckerService)에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPN 서비스와 연결"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"기기 관리자 추가 또는 삭제"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"권한을 가진 프로그램이 활성화된 기기의 관리자를 추가 또는 삭제하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"앱이 언제든지 화면 회전을 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"포인터 속도 변경"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"앱이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있도록 허용합니다."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"프레임 버퍼 읽기"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"앱이 프레임 버퍼의 내용을 읽을 수 있도록 허용합니다."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger에 액세스"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"앱이 InputFlinger의 하위 수준 기능을 사용하도록 합니다."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fi 디스플레이 설정"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"앱이 Wi-Fi 디스플레이를 설정하고 연결하도록 허용합니다."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi 디스플레이 제어"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"앱이 Wi-Fi 디스플레이의 하위 수준 기능을 제어하도록 허용합니다."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"오디오 설정 변경"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"앱이 음량이나 출력을 위해 사용하는 스피커 등 전체 오디오 설정을 변경할 수 있도록 허용합니다."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"오디오 녹음"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"앱이 SD 카드에 쓸 수 있도록 허용합니다."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"내부 미디어 저장소 콘텐츠 수정/삭제"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"앱이 내부 미디어 저장소의 콘텐츠를 수정할 수 있도록 허용합니다."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"문서 저장공간 관리"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"앱이 문서 저장공간을 관리할 수 있도록 허용합니다."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"모든 사용자의 외부 저장소에 액세스"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"앱이 모든 사용자의 외부 저장소에 액세스하도록 허용합니다."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"캐시 파일시스템 액세스"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"앱이 네트워크 정책을 관리하고 앱별 규칙을 정의할 수 있도록 허용합니다."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"네트워크 사용량 계산 수정"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"소켓 마크 수정"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"앱이 라우팅의 소켓 마크를 수정하도록 합니다."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"알림 액세스"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"이동통신사에서 제공한 구성 앱 호출"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"행아웃"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"SIM 카드를 삽입하세요."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM 카드가 없거나 읽을 수 없습니다. SIM 카드를 삽입하세요."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"사용할 수 없는 SIM 카드입니다."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM 카드 사용이 영구적으로 사용중지되었습니다."\n"다른 SIM 카드를 사용하려면 무선 서비스 제공업체에 문의하시기 바랍니다."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM 카드 사용이 영구적으로 사용중지되었습니다.\n다른 SIM 카드를 사용하려면 무선 서비스 제공업체에 문의하시기 바랍니다."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"이전 트랙 버튼"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"다음 트랙 버튼"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"일시중지 버튼"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"사용자 가이드를 참조하거나 고객지원팀에 문의하세요."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 카드가 잠겨 있습니다."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM 카드 잠금해제 중..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \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_now_wiping" product="tablet" msgid="280873516493934365">"태블릿을 잠금 해제하려는 시도가 <xliff:g id="NUMBER">%d</xliff:g>번 잘못되었습니다. 태블릿이 초기화됩니다."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"비밀번호"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"로그인"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"사용자 이름이나 비밀번호를 잊어버렸습니까?"\n<b>"google.com/accounts/recovery"</b>"를 방문하세요."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"사용자 이름이나 비밀번호를 잊어버렸습니까?\n"<b>"google.com/accounts/recovery"</b>"를 방문하세요."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"확인 중…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"잠금해제"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"사운드 켜기"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"탐색 확인"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"이 페이지 닫기"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"이 페이지에 머무르기"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"다른 페이지로 이동하시겠습니까?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n다른 페이지로 이동하시겠습니까?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"확인"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"도움말: 확대/축소하려면 두 번 탭합니다."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"자동완성"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g>(이)가 중지되었습니다."</string>
     <string name="aerr_process" msgid="4507058997035697579">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 중지되었습니다."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>이(가) 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g>이(가) 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>이(가) 응답하지 않습니다.\n\n닫으시겠습니까?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g>이(가) 응답하지 않습니다.\n\n닫으시겠습니까?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g>이(가) 응답하지 않습니다. 닫으시겠습니까?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다.\n\n닫으시겠습니까?"</string>
     <string name="force_close" msgid="8346072094521265605">"확인"</string>
     <string name="report" msgid="4060218260984795706">"신고"</string>
     <string name="wait" msgid="7147118217226317732">"대기"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"페이지가 응답하지 않습니다."\n\n"페이지를 닫으시겠습니까?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"페이지가 응답하지 않습니다.\n\n페이지를 닫으시겠습니까?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"앱 리디렉션됨"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"원래 <xliff:g id="APP_NAME">%1$s</xliff:g>을(를) 실행했습니다."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"기본 컨테이너 서비스를 호출하여 콘텐츠를 복사할 수 있도록 허용합니다. 일반 앱에서는 사용하지 않습니다."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"미디어 출력 연결"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"앱이 미디어 출력을 기타 외부 기기에 연결할 수 있도록 허용합니다."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"키가드 보안 저장소 액세스"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"애플리케이션에서 키가드 보안 저장소에 액세스하도록 허용합니다."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"키가드 표시 및 숨기기 설정"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"애플리케이션에서 키가드를 제어하도록 허용합니다."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"확대/축소하려면 두 번 터치하세요."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"위젯을 추가할 수 없습니다."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"이동"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"완료"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"이전"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"실행"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"전화하기 "\n"<xliff:g id="NUMBER">%s</xliff:g>에 연결"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"전화번호부에"\n"<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"전화하기 \n<xliff:g id="NUMBER">%s</xliff:g>에 연결"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"전화번호부에\n<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"다음 앱에서 앞으로 계정에 액세스할 수 있도록 권한을 요청합니다."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"요청을 허용하시겠습니까?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"액세스 요청"</string>
     <string name="allow" msgid="7225948811296386551">"허용"</string>
     <string name="deny" msgid="2081879885755434506">"거부"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"권한 요청됨"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> 계정에 대해"\n"권한 요청"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> 계정에 대해\n권한 요청"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"입력 방법"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"동기화"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"접근성"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"연결 중..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"사용 가능"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"사용할 수 없음"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"사용 중"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"기본으로 제공되는 화면"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI 화면"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>번째 오버레이"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"무선 디스플레이가 연결되었습니다."</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"이 화면은 다른 기기에서 표시되고 있습니다."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"연결 해제"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"잘못된 패턴"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"잘못된 비밀번호"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"잘못된 PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"패턴 그리기"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN 입력"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN 입력"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"비밀번호"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"로그인"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"사용자 이름이나 비밀번호를 잊어버렸습니까?"\n<b>"google.com/accounts/recovery"</b>" 페이지를 방문하세요."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"사용자 이름이나 비밀번호를 잊어버렸습니까?\n"<b>"google.com/accounts/recovery"</b>" 페이지를 방문하세요."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"계정 확인 중…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"삭제"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"안전한 수준 이상으로 볼륨을 높이시겠습니까?"\n"높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"안전한 수준 이상으로 볼륨을 높이시겠습니까?\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"두 손가락으로 길게 누르면 접근성을 사용하도록 설정됩니다."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"접근성을 사용 설정했습니다."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"접근성이 취소되었습니다."</string>
     <string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
     <string name="owner_name" msgid="2716755460376028154">"소유자"</string>
     <string name="error_message_title" msgid="4510373083082500195">"오류"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"이 애플리케이션은 제한된 프로필의 계정을 지원하지 않습니다."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"이 앱은 제한된 프로필의 계정을 지원하지 않습니다."</string>
     <string name="app_not_found" msgid="3429141853498927379">"이 작업을 처리하는 애플리케이션을 찾을 수 없습니다."</string>
     <string name="revoke" msgid="5404479185228271586">"취소"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"레터"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"거번먼트 레터"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"리걸"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"주니어 리걸"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"원장"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"타블로이드"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"취소됨"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"콘텐츠 작성 중 오류"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN 입력"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"현재 PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"새 PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"새 PIN 확인"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"제한사항 수정을 위한 PIN 생성"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN이 일치하지 않습니다. 다시 시도하세요."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN이 너무 짧습니다. 최소 4자 이상이어야 합니다."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"잘못된 PIN입니다. 1초 뒤에 다시 시도하세요."</item>
+    <item quantity="other" msgid="8030607343223287654">"잘못된 PIN입니다. <xliff:g id="COUNT">%d</xliff:g>초 뒤에 다시 시도하세요."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-land/alias.xml b/core/res/res/values-land/alias.xml
deleted file mode 100644
index eac5ece..0000000
--- a/core/res/res/values-land/alias.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** 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.
-*/
--->
-<resources>
-    <!-- Alias used to reference one of two possible layouts in keyguard.  -->
-    <item type="layout" name="keyguard_eca">@android:layout/keyguard_emergency_carrier_area_empty</item>
-</resources>
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
index 240b9e4..5602a1c 100644
--- a/core/res/res/values-land/arrays.xml
+++ b/core/res/res/values-land/arrays.xml
@@ -19,54 +19,4 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Resources for GlowPadView in LockScreen -->
-    <array name="lockscreen_targets_when_silent">
-        <item>@null</item>"
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_soundon</item>
-        <item>@drawable/ic_lockscreen_unlock</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_when_silent">
-        <item>@null</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_soundon</item>
-        <item>@string/description_target_unlock</item>
-    </array>
-
-    <array name="lockscreen_direction_descriptions">
-        <item>@null</item>
-        <item>@string/description_direction_up</item>
-        <item>@string/description_direction_left</item>
-        <item>@string/description_direction_down</item>
-    </array>
-
-    <array name="lockscreen_targets_when_soundon">
-        <item>@null</item>
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_silent</item>
-        <item>@drawable/ic_lockscreen_unlock</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_when_soundon">
-        <item>@null</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_silent</item>
-        <item>@string/description_target_unlock</item>
-    </array>
-
-    <array name="lockscreen_targets_with_camera">
-        <item>@null</item>
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_camera</item>
-        <item>@drawable/ic_lockscreen_unlock</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_with_camera">
-        <item>@null</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_camera</item>
-        <item>@string/description_target_unlock</item>
-    </array>
-
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 593316f..c57832e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -138,7 +138,7 @@
     <string name="turn_on_radio" msgid="3912793092339962371">"Įjungti bevielį"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Išjungti bevielį"</string>
     <string name="screen_lock" msgid="799094655496098153">"Ekrano užraktas"</string>
-    <string name="power_off" msgid="4266614107412865048">"Išjungti maitinimą"</string>
+    <string name="power_off" msgid="4266614107412865048">"Išjungiamas maitinimas"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Skambutis išjungtas"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Vibracija skambinant"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Skambutis įjungtas"</string>
@@ -153,7 +153,7 @@
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Planšetinio kompiuterio parinktys"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefono parinktys"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekrano užraktas"</string>
-    <string name="global_action_power_off" msgid="4471879440839879722">"Išjungti maitinimą"</string>
+    <string name="global_action_power_off" msgid="4471879440839879722">"Išjungiamas maitinimas"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie triktį"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie triktį"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie triktį bus paruoštas siųsti; būkite kantrūs."</string>
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Leidžiama programai perkelti užduotis į priekinį planą ir foną. Programa gali tai daryti be jūsų įsikišimo."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"sustabdyti vykdomas programas"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Leidžiama programai pašalinti užduotis ir panaikinti jų programas. Kenkėjiškos programos gali trikdyti kitų programų veikimą."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"tvarkyti veiklos krūvas"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Programai leidžiama pridėti, pašalinti ir modifikuoti veiklos krūvas, kuriose paleistos kitos programos. Kenkėjiškos programos gali trikdyti kitų programų elgseną."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"pradėti bet kokią veiklą"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Programai leidžiama pradėti bet kokią veiklą, nepaisant leidimo apsaugos ar eksportuotos būsenos."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nustatyti ekrano suderinamumo režimą"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Leidžiama savininką susaistyti su įvesties metodo aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"susisaistyti su pasiekiamumo paslauga"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Savininkui leidžiama susisaistyti su aukščiausio lygio pasiekiamumo paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"susisaistyti su spausdinimo paslauga"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Turėtojui leidžiama susisaistyti su spausdinimo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"pasiekti visas spausdinimo užduotis"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Turėtojui leidžiama pasiekti spausdinimo užduotis, sukurtas naudojant kitą programą. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"susaistyti su ALR paslauga"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Savininkui leidžiama susaistyti programas, kurios kopijuoja ALR korteles. Neturėtų prireikti įprastoms programoms."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"priskirti teksto paslaugą"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Leidžiama savininkui priskirti aukščiausio lygio teksto paslaugos (pvz., „SpellCheckerService“) sąsają. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"susaistyti su VPN paslauga"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridėti arba pašalinti įrenginio administratorių"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Savininkui leidžiama pridėti aktyvių įrenginio administratorių arba juos pašalinti. Neturėtų reikėti įprastoms programoms."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Leidžiama programai bet kada kaitalioti ekraną. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"keisti žymiklio greitį"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Leidžiama programai naudoti „SurfaceFlinger“ žemo lygio funkcijas."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"skaityti kadrų buferį"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Leidžiama programai skaityti rėmelio buferio turinį."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"pasiekti „InputFlinger“"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Programai leidžiama naudoti „InputFlinger“ žemo lygio funkcijas."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigūruoti „Wi-Fi“ pateiktis"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Leidžiama programai konfigūruoti ir prisijungti prie „Wi-Fi“ pateikčių."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"valdyti „Wi-Fi“ pateiktis"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Leidžiama programai valdyti „Wi-Fi“ pateikčių žemo lygio funkcijas."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"keisti garso nustatymus"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Leidžiama programai keisti visuotinius garso nustatymus, pvz., garsumą ir tai, kuris garsiakalbis naudojamas išvesčiai."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"įrašyti garsą"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Leidžiama programai rašyti į SD kortelę."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"keisti / ištr. vid. med. atm. tur."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Leidžiama programai keisti vidinės medijos saugyklos turinį."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"tvarkyti dokumentų saugyklą"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Leidžiama programai tvarkyti dokumentų saugyklą."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"pasiekti visų naud. išor. atm."</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Leidžiama programai pasiekti visų naudotojų išorinę atmintinę."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pasiekti talpyklos failų sistemą"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Leidžiama programai valdyti tinklo politiką ir apibrėžti konkrečios programos taisykles."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"keisti tinklo naudojimo apskaitą"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifikuoti lizdų ženklus"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Programai leidžiama modifikuoti maršrutui parinkti skirtus lizdų ženklus"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leidžiama turėtojui susisaistyti su pranešimų skaitymo priemonės paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"iškviesti operatoriaus pateiktą konfigūravimo programą"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Turėtojui leidžiama iškviesti operatoriaus pateiktą konfigūravimo programą. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"„Jabber“"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Įdėkite SIM kortelę."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Trūksta SIM kortelės arba ji neskaitoma. Įdėkite SIM kortelę."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Negalima naudoti SIM kortelės."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kortelė visam laikui neleidžiama."\n" Jei norite gauti kitą SIM kortelę, susisiekite su belaidžio ryšio paslaugos teikėju."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kortelė visam laikui neleidžiama.\n Jei norite gauti kitą SIM kortelę, susisiekite su belaidžio ryšio paslaugos teikėju."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Ankstesnio takelio mygtukas"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Kito takelio mygtukas"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pristabdymo mygtukas"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Žr. naudotojo vadovą arba susisiekite su klientų priežiūros tarnyba."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kortelė užrakinta."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Atrakinama SD kortelė..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Neteisingai apibrėžėte atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN kodą neteisingai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Neteisingai nurodėte savo atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Neteisingai nurodėte savo atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Neteisingai apibrėžėte atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN kodą neteisingai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Neteisingai nurodėte savo atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Neteisingai nurodėte savo atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. bandėte netinkamai atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. bandėte netinkamai atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"<xliff:g id="NUMBER">%d</xliff:g> kart. bandėte netinkamai atrakinti planšetinį kompiuterį. Planšetinis kompiuteris bus iš naujo nustatytas į numatytuosius gamyklos nustatymus."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Slaptažodis"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Prisijungti"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Neteisingas naudotojo vardas ar slaptažodis."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Pamiršote naudotojo vardą ar slaptažodį?"\n"Apsilankykite šiuo adresu: "<b>"google.com/accounts/recovery?hl=lt"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Pamiršote naudotojo vardą ar slaptažodį?\nApsilankykite šiuo adresu: "<b>"google.com/accounts/recovery?hl=lt"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Tikrinama..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Atblokuoti"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Garsas įjungtas"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Patvirtinti išėjimą"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Išeiti iš šio puslapio"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Likti šiame puslapyje"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tikrai norite išeiti iš šio puslapio?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nTikrai norite išeiti iš šio puslapio?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Patvirtinti"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Patarimas: palieskite dukart, kad padidintumėte ar sumažintumėte mastelį."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automatinis pildymas"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Deja, <xliff:g id="APPLICATION">%1$s</xliff:g> sustojo."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Deja, <xliff:g id="PROCESS">%1$s</xliff:g> sustojo."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"„<xliff:g id="APPLICATION">%2$s</xliff:g>“ neatsako."\n\n"Ar norite ją uždaryti?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Veiksmas „<xliff:g id="ACTIVITY">%1$s</xliff:g>“ neatsako."\n\n"Ar norite jį uždaryti?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"„<xliff:g id="APPLICATION">%2$s</xliff:g>“ neatsako.\n\nAr norite ją uždaryti?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Veiksmas „<xliff:g id="ACTIVITY">%1$s</xliff:g>“ neatsako.\n\nAr norite jį uždaryti?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"„<xliff:g id="APPLICATION">%1$s</xliff:g>“ neatsako. Ar norite ją uždaryti?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Procesas „<xliff:g id="PROCESS">%1$s</xliff:g>“ neatsako."\n\n"Ar norite jį uždaryti?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Procesas „<xliff:g id="PROCESS">%1$s</xliff:g>“ neatsako.\n\nAr norite jį uždaryti?"</string>
     <string name="force_close" msgid="8346072094521265605">"Gerai"</string>
     <string name="report" msgid="4060218260984795706">"Ataskaita"</string>
     <string name="wait" msgid="7147118217226317732">"Palaukti"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Puslapis neatsako."\n\n"Ar norite jį uždaryti?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Puslapis neatsako.\n\nAr norite jį uždaryti?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Programa peradresuota"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ dabar vykdoma."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ buvo iš pradžių paleista."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Leidžiama programai iškviesti numatytąją sudėtinio rodinio paslaugą, kad būtų kopijuojamas turinys. Neskirta naudoti įprastoms programoms."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medijos išvesties nukreipimas"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Leidžiama programai nukreipti medijos išvestį į kitus išorinius įrenginius."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Pasiekti „KeyGuard“ saugyklą"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Programai leidžiama pasiekti „KeyGuard“ saugyklą."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Valdyti „KeyGuard“ rodymą ir slėpimą"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Programai leidžiama valdyti „KeyGuard“."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dukart palieskite, kad valdytumėte mastelio keitimą"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nepavyko pridėti."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pradėti"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Atlikta"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Perž."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Vykdyti"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Rinkti numerį "\n"naudojant <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Sukurti adresatą"\n"naudojant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Rinkti numerį \nnaudojant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Sukurti adresatą\nnaudojant <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Pateikta mažiausiai vienos toliau nurodytos programos užklausa dėl leidimo dabar ir ateityje pasiekti jūsų paskyrą."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ar norite leisti šią užklausą?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Užklausa dėl prieigos"</string>
     <string name="allow" msgid="7225948811296386551">"Leisti"</string>
     <string name="deny" msgid="2081879885755434506">"Atmesti"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Pateikta užklausa dėl leidimo"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Pateikta leidimo užklausa"\n"dėl <xliff:g id="ACCOUNT">%s</xliff:g> paskyros"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Pateikta leidimo užklausa\ndėl <xliff:g id="ACCOUNT">%s</xliff:g> paskyros"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Įvesties būdas"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinchronizuoti"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Pasiekiamumas"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Jungiama..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Pasiekiama"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nepasiekiama"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Naudojama"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integruotas ekranas"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI ekranas"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Perdanga nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"„<xliff:g id="NAME">%1$s</xliff:g>“: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> tašk. colyje"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", saugu"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Prijungtas belaidis monitorius"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Šis ekranas rodomas kitame įrenginyje"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Atjungti"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Netinkamas atrakinimo piešinys"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Netinkamas slaptažodis"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Netinkamas PIN kodas"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Bandyti dar kartą po <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Bandyti dar kartą po <xliff:g id="NUMBER">%1$d</xliff:g> sek."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Nupieškite atrakinimo piešinį"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Įveskite SIM PIN kodą"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Įveskite PIN kodą"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Slaptažodis"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Prisijungti"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Netinkamas naudotojo vardas ar slaptažodis."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Pamiršote naudotojo vardą ar slaptažodį?"\n"Apsilankykite šiuo adresu: "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Pamiršote naudotojo vardą ar slaptažodį?\nApsilankykite šiuo adresu: "<b>"google.com/accounts/recovery"</b></string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Tikrinama paskyra…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"<xliff:g id="NUMBER_0">%d</xliff:g> k. bandėte netinkamai atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"<xliff:g id="NUMBER_0">%d</xliff:g> k. bandėte netinkamai atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"<xliff:g id="NUMBER">%d</xliff:g> k. bandėte netinkamai atrakinti planšetinį kompiuterį. Planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"<xliff:g id="NUMBER">%d</xliff:g> k. bandėte netinkamai atrakinti telefoną. Telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Pašalinti"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Padidinti garsumą viršijant saugų lygį?"\n"Ilgai klausantis dideliu garsumu gali sutrikti klausa."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Padidinti garsumą viršijant saugų lygį?\nIlgai klausantis dideliu garsumu gali sutrikti klausa."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Laikykite palietę dviem pirštais, kad įgalintumėte pritaikymo neįgaliesiems režimą."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pritaikymas neįgaliesiems įgalintas."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pritaikymo neįgaliesiems režimas atšauktas."</string>
     <string name="user_switched" msgid="3768006783166984410">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Savininkas"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Klaida"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ši programa nepalaiko apribotų profilių paskyrų"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ši programa nepalaiko apribotų profilių paskyrų"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nerasta programa šiam veiksmui apdoroti"</string>
     <string name="revoke" msgid="5404479185228271586">"Anuliuoti"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO S9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Laiškas"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Oficialus laiškas"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Teisinis"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Mažas teisinis"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Buhalterinis"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Bulvarinė spauda"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Atšaukta"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Klaida rašant turinį"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Įveskite PIN kodą"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Dabartinis PIN kodas"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Naujas PIN kodas"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Patvirtinti naują PIN kodą"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Sukurti modifikavimo apribojimų PIN kodą"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN kodas neatitinka. Bandykite dar kartą."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN kodas per trumpas. Jis turi būti bent 4 skaitmenų."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Netinkamas PIN kodas. Band. po 1 sek."</item>
+    <item quantity="other" msgid="8030607343223287654">"Netinkamas PIN kodas. Band. po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 11e0116..ee63fa8 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ļauj lietotnei pārvietot uzdevumus priekšplānā un fonā. Lietotne var to izdarīt bez jūsu apstiprinājuma."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"apturēt izmantoto lietotņu darbību"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Ļauj lietotnei noņemt uzdevumus un pārtraukt to lietotņu darbību. Ļaunprātīgas lietotnes var traucēt citu lietotņu darbību."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"Darbību kaskāžu pārvaldība"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ļauj lietotnei pievienot, noņemt un mainīt darbību kaskādes, kurās darbojas citas lietotnes. Ļaunprātīgas lietotnes var traucēt citu lietotņu darbību."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"jebkuras darbības sākšana"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ļauj lietotnei sākt jebkuru darbību neatkarīgi no atļaujas aizsardzības vai eksportētā stāvokļa."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Ekrāna saderības noteikšana"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ļauj īpašniekam izveidot saiti ar ievades metodes augstākā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"saistīt ar pieejamības pakalpojumu"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ļauj īpašniekam izveidot saiti ar pieejamības pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm šī atļauja nav nepieciešama."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"Savienojuma izveide ar drukāšanas pakalpojumu"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ļauj īpašniekam izveidot savienojumu ar drukāšanas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"Piekļuve visiem drukas darbiem"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ļauj īpašniekam piekļūt drukas darbiem, kas izveidoti citā lietotnē. Parastām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"Saistīt ar TDLS pakalpojumu"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Ļauj īpašniekam saistīt lietojumprogrammas, kas emulē TDLS kartes. Parastajām lietotnēm šī atļauja nav nepieciešama."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"saistīt ar īsziņu pakalpojumu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ļauj īpašniekam veikt saistīšanu ar īsziņu pakalpojuma augstākā līmeņa saskarni (piem., SpellCheckerService). Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"saistīt ar VPN pakalpojumu"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pievienot vai noņemt ierīces administratoru"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ļauj īpašniekam pievienot vai noņemt aktīvos ierīces administratorus. Nekad nav nepieciešama parastām lietotnēm."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ļauj lietotnei jebkurā laikā mainīt ekrāna pozīciju. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Rādītāja ātruma mainīšana"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ļauj lietotnei lietot SurfaceFlinger zema līmeņa funkcijas."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lasīt kadru buferi"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ļauj lietotnei lasīt kadru bufera saturu."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"Piekļuve InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ļauj lietotnei izmantot InputFlinger zema līmeņa funkcijas."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fi displeju konfigurēšana"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ļauj lietotnei konfigurēt Wi-Fi displejus un veidot savienojumu ar tiem."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi displeju vadība"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Ļauj lietotnei kontrolēt zema līmeņa funkcijas Wi-Fi displejos."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"mainīt audio iestatījumus"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ļauj lietotnei mainīt globālos audio iestatījumus, piemēram, skaļumu un izejai izmantoto skaļruni."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ierakstīt audio"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ļauj lietotnei rakstīt SD kartē."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"pārv./dz.datu n.iekš.atm.sat."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ļauj lietotnei modificēt datu nesēja iekšējās atmiņas saturu."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"Dokumentu krātuves pārvaldība"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Ļauj lietotnei pārvaldīt dokumentu krātuvi."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"piekļ. visu liet. ārējai krāt."</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Ļauj lietotnei piekļūt visu lietotāju ārējai krātuvei."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"piekļūt kešatmiņas failu sistēmai"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ļauj lietotnei pārvaldīt tīkla politikas un noteikt lietotnes kārtulas."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Tīkla lietojuma uzskaites mainīšana"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"Ligzdu atzīmju izmaiņas"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ļauj lietotnei mainīt maršrutēšanai paredzēto ligzdu atzīmes."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ļauj īpašniekam izveidot saiti ar paziņojumu uztvērēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Operatora nodrošinātas konfigurācijas lietotnes izsaukšana"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ļauj īpašniekam izsaukt operatora nodrošināto konfigurācijas lietotni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Ievietojiet SIM karti."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Nav SIM kartes, vai arī to nevar nolasīt. Ievietojiet SIM karti."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nelietojama SIM karte."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Jūsu SIM karte ir neatgriezeniski atspējota."\n"Sazinieties ar savu bezvadu pakalpojumu sniedzēju, lai iegūtu citu SIM karti."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Jūsu SIM karte ir neatgriezeniski atspējota.\nSazinieties ar savu bezvadu pakalpojumu sniedzēju, lai iegūtu citu SIM karti."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Iepriekšējā ieraksta poga"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Nākamā ieraksta poga"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pārtraukšanas poga"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Skatiet lietotāja rokasgrāmatu vai sazinieties ar klientu apkalpošanas dienestu."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM karte ir bloķēta."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Notiek SIM kartes atbloķēšana..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Jūs esat ievadījis nepareizu paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Jūs esat ievadījis nepareizu PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot pierakstīšanos Google kontā."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot pierakstīšanos Google kontā."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Jūs esat ievadījis nepareizu paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Jūs esat ievadījis nepareizu PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot pierakstīšanos Google kontā.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot pierakstīšanos Google kontā.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīga(-iem) mēģinājuma(-iem) planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi, un lietotāja dati tiks zaudēti."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīga(-iem) mēģinājuma(-iem) tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi, un lietotāja dati tiks zaudēti."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parole"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Pierakstīties"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Lietotājvārds vai parole nav derīga."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Vai aizmirsāt lietotājvārdu vai paroli?"\n"Apmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Vai aizmirsāt lietotājvārdu vai paroli?\nApmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Notiek pārbaude..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Atbloķēt"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Skaņa ir ieslēgta"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Navigācijas apstiprināšana"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Pamest šo lapu"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Palikt šajā lapā"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vai tiešām vēlaties pamest šo lapu?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVai tiešām vēlaties pamest šo lapu?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Apstiprināt"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Padoms. Divreiz pieskarieties, lai tuvinātu un tālinātu."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automātiskā aizpilde"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Diemžēl lietojumprogrammas <xliff:g id="APPLICATION">%1$s</xliff:g> darbība ir apturēta."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Diemžēl process <xliff:g id="PROCESS">%1$s</xliff:g> ir apturēts."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Lietojumprogramma <xliff:g id="APPLICATION">%2$s</xliff:g> nereaģē."\n\n"Vai vēlaties to aizvērt?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Darbība <xliff:g id="ACTIVITY">%1$s</xliff:g> nereaģē."\n\n"Vai vēlaties to aizvērt?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Lietojumprogramma <xliff:g id="APPLICATION">%2$s</xliff:g> nereaģē.\n\nVai vēlaties to aizvērt?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Darbība <xliff:g id="ACTIVITY">%1$s</xliff:g> nereaģē.\n\nVai vēlaties to aizvērt?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Lietojumprogramma <xliff:g id="APPLICATION">%1$s</xliff:g> nereaģē. Vai vēlaties to aizvērt?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Process <xliff:g id="PROCESS">%1$s</xliff:g> nereaģē."\n\n"Vai vēlaties to aizvērt?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Process <xliff:g id="PROCESS">%1$s</xliff:g> nereaģē.\n\nVai vēlaties to aizvērt?"</string>
     <string name="force_close" msgid="8346072094521265605">"Labi"</string>
     <string name="report" msgid="4060218260984795706">"Pārskats"</string>
     <string name="wait" msgid="7147118217226317732">"Gaidīt"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"No lapas netiek saņemta atbilde."\n\n"Vai vēlaties to aizvērt?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"No lapas netiek saņemta atbilde.\n\nVai vēlaties to aizvērt?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Lietotne ir novirzīta"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> tagad darbojas."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Sākotnēji tika palaista lietojumprogramma <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ļauj lietotnei izsaukt noklusējuma konteinera pakalpojumu, lai kopētu saturu. Atļauja neattiecas uz parastām lietotnēm."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Multivides datu izejas maršrutēšana"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ļauj lietojumprogrammai maršrutēt multivides datu izeju uz citām ārējām ierīcēm."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Piekļūt krātuvei, kas aizsargāta ar atslēgu"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ļauj lietojumprogrammai piekļūt krātuvei, kas aizsargāta ar atslēgu."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Pārvaldīt krātuves rādīšanu un paslēpšanu."</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ļauj lietojumprogrammai pārvaldīt krātuvi."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Pieskarieties divreiz, lai kontrolētu tālummaiņu."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nevarēja pievienot logrīku."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Doties uz"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Gatavs"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Iepr."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Izpildīt"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Sastādiet numuru"\n"izmantojot <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Izveidot kontaktpersonu"\n"izmantojot šo numuru: <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Sastādiet numuru\nizmantojot <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Izveidot kontaktpersonu\nizmantojot šo numuru: <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Viena vai vairākas no tālāk minētajām lietotnēm pieprasa atļauju piekļūt jūsu kontam tagad un arī turpmāk."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vai vēlaties atļaut šo pieprasījumu?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Piekļuves pieprasījums"</string>
     <string name="allow" msgid="7225948811296386551">"Atļaut"</string>
     <string name="deny" msgid="2081879885755434506">"Noraidīt"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Atļauja ir pieprasīta."</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Atļauja kontam <xliff:g id="ACCOUNT">%s</xliff:g>"\n"ir pieprasīta."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Atļauja kontam <xliff:g id="ACCOUNT">%s</xliff:g>\nir pieprasīta."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Ievades metode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinhronizācija"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Pieejamība"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Notiek savienojuma izveide..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Pieejams"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nav pieejams"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Tiek lietots"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Iebūvēts ekrāns"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI ekrāns"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Pārklājums Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", drošs"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezvadu attēlošanas savienojums ir izveidots."</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Šis ekrāns tiek rādīts citā ierīcē."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Pārtraukt savienojumu"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nepareiza kombinācija"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nepareiza parole"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Nepareizs PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER">%1$d</xliff:g> sekundēm."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Norādiet savu kombināciju"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ievadiet SIM kartes PIN"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Ievadiet PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Parole"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Pierakstīties"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nederīgs lietotājvārds vai parole."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vai aizmirsāt lietotājvārdu vai paroli?"\n"Apmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vai aizmirsāt lietotājvārdu vai paroli?\nApmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Notiek konta pārbaude…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi un lietotāja dati tiks zaudēti."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi un lietotāja dati tiks zaudēti."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">"  — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Noņemt"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vai palielināt skaļumu virs ieteicamā līmeņa?"\n"Ilgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vai palielināt skaļumu virs ieteicamā līmeņa?\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Lai iespējotu pieejamību, turiet nospiestus divus pirkstus."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pieejamības režīms ir iespējots."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pieejamība ir atcelta."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Īpašnieks"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Kļūda"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Šajā lietojumprogrammā netiek atbalstīti ierobežotu profilu konti."</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Šajā lietotnē netiek atbalstīti ierobežotu profilu konti."</string>
     <string name="app_not_found" msgid="3429141853498927379">"Netika atrasta neviena lietojumprogramma, kas var veikt šo darbību."</string>
     <string name="revoke" msgid="5404479185228271586">"Atsaukt"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Atcelts"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Rakstot saturu, radās kļūda."</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ievadiet PIN."</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Pašreizējais PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Jaunais PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Apstipriniet jauno PIN."</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Izveidojiet PIN, lai mainītu ierobežojumus."</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Ievadītie PIN neatbilst. Mēģiniet vēlreiz."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ir pārāk īss. Tam ir jābūt vismaz 4 ciparus garam."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN nav pareizs. Mēģiniet pēc 1 s."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN nav pareizs. Mēģiniet pēc <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-mcc202/config.xml b/core/res/res/values-mcc202/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc202/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
new file mode 100644
index 0000000..7a48342
--- /dev/null
+++ b/core/res/res/values-mcc204-mnc04/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1358</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc204/config.xml b/core/res/res/values-mcc204/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc204/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc206/config.xml b/core/res/res/values-mcc206/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc206/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc208-mnc26/config.xml b/core/res/res/values-mcc208-mnc26/config.xml
new file mode 100644
index 0000000..31d2d0f
--- /dev/null
+++ b/core/res/res/values-mcc208-mnc26/config.xml
@@ -0,0 +1,26 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>20801</item>
+        <item>20810</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc208/config.xml b/core/res/res/values-mcc208/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc208/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc214-mnc04/config.xml b/core/res/res/values-mcc214-mnc04/config.xml
new file mode 100644
index 0000000..71301d5
--- /dev/null
+++ b/core/res/res/values-mcc214-mnc04/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>21407</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc214/config.xml b/core/res/res/values-mcc214/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc214/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc216/config.xml b/core/res/res/values-mcc216/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc216/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc219/config.xml b/core/res/res/values-mcc219/config.xml
index 7ae82fa..80f4e58 100644
--- a/core/res/res/values-mcc219/config.xml
+++ b/core/res/res/values-mcc219/config.xml
@@ -29,4 +29,7 @@
         <item>"96"</item>
     </string-array>
 
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc222/config.xml b/core/res/res/values-mcc222/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc222/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc226/config.xml b/core/res/res/values-mcc226/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc226/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc228/config.xml b/core/res/res/values-mcc228/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc228/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc230/config.xml b/core/res/res/values-mcc230/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc230/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc231/config.xml b/core/res/res/values-mcc231/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc231/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc232/config.xml b/core/res/res/values-mcc232/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc232/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc234-mnc30/config.xml b/core/res/res/values-mcc234-mnc30/config.xml
new file mode 100644
index 0000000..eabdf9a
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc30/config.xml
@@ -0,0 +1,30 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23430</item>
+        <item>23431</item>
+        <item>23432</item>
+        <item>23433</item>
+        <item>23434</item>
+        <item>23486</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc234-mnc31/config.xml b/core/res/res/values-mcc234-mnc31/config.xml
new file mode 100644
index 0000000..eabdf9a
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc31/config.xml
@@ -0,0 +1,30 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23430</item>
+        <item>23431</item>
+        <item>23432</item>
+        <item>23433</item>
+        <item>23434</item>
+        <item>23486</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc234-mnc32/config.xml b/core/res/res/values-mcc234-mnc32/config.xml
new file mode 100644
index 0000000..eabdf9a
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc32/config.xml
@@ -0,0 +1,30 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23430</item>
+        <item>23431</item>
+        <item>23432</item>
+        <item>23433</item>
+        <item>23434</item>
+        <item>23486</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc234-mnc33/config.xml b/core/res/res/values-mcc234-mnc33/config.xml
index d79d212..175f76e 100644
--- a/core/res/res/values-mcc234-mnc33/config.xml
+++ b/core/res/res/values-mcc234-mnc33/config.xml
@@ -35,4 +35,14 @@
          "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">Consumer Broadband,consumerbroadband,,,,,,,,,234,33,,DUN</string>
+
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23430</item>
+        <item>23431</item>
+        <item>23432</item>
+        <item>23433</item>
+        <item>23434</item>
+        <item>23486</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc234-mnc34/config.xml b/core/res/res/values-mcc234-mnc34/config.xml
new file mode 100644
index 0000000..eabdf9a
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc34/config.xml
@@ -0,0 +1,30 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23430</item>
+        <item>23431</item>
+        <item>23432</item>
+        <item>23433</item>
+        <item>23434</item>
+        <item>23486</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc234-mnc86/config.xml b/core/res/res/values-mcc234-mnc86/config.xml
new file mode 100644
index 0000000..eabdf9a
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc86/config.xml
@@ -0,0 +1,30 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23430</item>
+        <item>23431</item>
+        <item>23432</item>
+        <item>23433</item>
+        <item>23434</item>
+        <item>23486</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc234/config.xml b/core/res/res/values-mcc234/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc234/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc238/config.xml b/core/res/res/values-mcc238/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc238/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc240/config.xml b/core/res/res/values-mcc240/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc240/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc242/config.xml b/core/res/res/values-mcc242/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc242/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc244/config.xml b/core/res/res/values-mcc244/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc244/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc246/config.xml b/core/res/res/values-mcc246/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc246/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc247/config.xml b/core/res/res/values-mcc247/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc247/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc248/config.xml b/core/res/res/values-mcc248/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc248/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc260/config.xml b/core/res/res/values-mcc260/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc260/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc262/config.xml b/core/res/res/values-mcc262/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc262/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc268/config.xml b/core/res/res/values-mcc268/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc268/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc270/config.xml b/core/res/res/values-mcc270/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc270/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc272/config.xml b/core/res/res/values-mcc272/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc272/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc274/config.xml b/core/res/res/values-mcc274/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc274/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc278/config.xml b/core/res/res/values-mcc278/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc278/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc280/config.xml b/core/res/res/values-mcc280/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc280/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc284/config.xml b/core/res/res/values-mcc284/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc284/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc286/config.xml b/core/res/res/values-mcc286/config.xml
index d99d051..f73a523 100644
--- a/core/res/res/values-mcc286/config.xml
+++ b/core/res/res/values-mcc286/config.xml
@@ -61,4 +61,7 @@
          to enable use of the new Release 9 tables for Indic languages. -->
     <!-- <integer-array name="config_sms_enabled_locking_shift_tables"></integer-array> -->
 
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc293/config.xml b/core/res/res/values-mcc293/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc293/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc294/config.xml b/core/res/res/values-mcc294/config.xml
new file mode 100644
index 0000000..8d6d3b1
--- /dev/null
+++ b/core/res/res/values-mcc294/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index 3d2ea75..4fb2232 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -36,4 +36,8 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">Fido LTE Tethering,ltedata.apn,,,,,,,,,302,370,,DUN</string>
 
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1410</integer>
+
 </resources>
diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
new file mode 100644
index 0000000..638aa92
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -0,0 +1,30 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1358</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
new file mode 100644
index 0000000..706570c
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc640/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc660/config.xml b/core/res/res/values-mcc302-mnc660/config.xml
index 37853cf..76f7968 100644
--- a/core/res/res/values-mcc302-mnc660/config.xml
+++ b/core/res/res/values-mcc302-mnc660/config.xml
@@ -35,4 +35,9 @@
          "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">MTS -Tethering,internet.mts,,,,,,,,,302,660,,DUN</string>
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1430</integer>
+
 </resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index 680f1a3..4eceffc 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -36,4 +36,8 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">Rogers LTE Tethering,ltedata.apn,,,,,,,,,302,720,,DUN</string>
 
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1430</integer>
+
 </resources>
diff --git a/core/res/res/values-mcc302-mnc780/config.xml b/core/res/res/values-mcc302-mnc780/config.xml
index 42d4956..cd40191 100644
--- a/core/res/res/values-mcc302-mnc780/config.xml
+++ b/core/res/res/values-mcc302-mnc780/config.xml
@@ -37,4 +37,13 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">SaskTel Tethering,inet.stm.sk.ca,,,,,,,,,302,780,,DUN</string>
 
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1358</integer>
+
 </resources>
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
new file mode 100644
index 0000000..62001d9
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc120/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1422</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 56a5d4e..886ecbe 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -37,4 +37,8 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">T-Mobile Tethering,pcweb.tmobile.com,,,,,,,,,310,260,,DUN</string>
 
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
new file mode 100644
index 0000000..73aa1ce
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc410/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1410</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc310/config.xml b/core/res/res/values-mcc310/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc310/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc311/config.xml b/core/res/res/values-mcc311/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc311/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc312/config.xml b/core/res/res/values-mcc312/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc312/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc313/config.xml b/core/res/res/values-mcc313/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc313/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc314/config.xml b/core/res/res/values-mcc314/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc314/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc315/config.xml b/core/res/res/values-mcc315/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc315/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc316/config.xml b/core/res/res/values-mcc316/config.xml
deleted file mode 100644
index df398f9..0000000
--- a/core/res/res/values-mcc316/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">false</bool>
-
-</resources>
diff --git a/core/res/res/values-mcc404-mnc17/config.xml b/core/res/res/values-mcc404-mnc17/config.xml
new file mode 100644
index 0000000..685d012
--- /dev/null
+++ b/core/res/res/values-mcc404-mnc17/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Show roaming icon though same named operators. -->
+    <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
+        <item>40491</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc404-mnc85/config.xml b/core/res/res/values-mcc404-mnc85/config.xml
new file mode 100644
index 0000000..fd780ab
--- /dev/null
+++ b/core/res/res/values-mcc404-mnc85/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Show roaming icon though same named operators. -->
+    <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
+        <item>40483</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc425-mnc07/config.xml b/core/res/res/values-mcc425-mnc07/config.xml
index 890420e..51a9934 100644
--- a/core/res/res/values-mcc425-mnc07/config.xml
+++ b/core/res/res/values-mcc425-mnc07/config.xml
@@ -37,4 +37,8 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">PC HOT mobile,pc.hotm,,,,,,,,,425,07,,DUN</string>
 
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>42503</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc425-mnc08/config.xml b/core/res/res/values-mcc425-mnc08/config.xml
new file mode 100644
index 0000000..8470b86
--- /dev/null
+++ b/core/res/res/values-mcc425-mnc08/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>42502</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc440-mnc20/config.xml b/core/res/res/values-mcc440-mnc20/config.xml
new file mode 100644
index 0000000..ba709fa
--- /dev/null
+++ b/core/res/res/values-mcc440-mnc20/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1340</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc440-mnc50/config.xml b/core/res/res/values-mcc440-mnc50/config.xml
new file mode 100644
index 0000000..fa5cba4
--- /dev/null
+++ b/core/res/res/values-mcc440-mnc50/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1420</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc440-mnc54/config.xml b/core/res/res/values-mcc440-mnc54/config.xml
new file mode 100644
index 0000000..fa5cba4
--- /dev/null
+++ b/core/res/res/values-mcc440-mnc54/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1420</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc450-mnc05/config.xml b/core/res/res/values-mcc450-mnc05/config.xml
new file mode 100644
index 0000000..d602c9f
--- /dev/null
+++ b/core/res/res/values-mcc450-mnc05/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc450-mnc06/config.xml b/core/res/res/values-mcc450-mnc06/config.xml
new file mode 100644
index 0000000..63f9823
--- /dev/null
+++ b/core/res/res/values-mcc450-mnc06/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1428</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc450-mnc08/config.xml b/core/res/res/values-mcc450-mnc08/config.xml
new file mode 100644
index 0000000..950c62b
--- /dev/null
+++ b/core/res/res/values-mcc450-mnc08/config.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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1450</integer>
+
+</resources>
diff --git a/core/res/res/values-mcc505-mnc01/config.xml b/core/res/res/values-mcc505-mnc01/config.xml
index f9d9ac7..7331c50 100644
--- a/core/res/res/values-mcc505-mnc01/config.xml
+++ b/core/res/res/values-mcc505-mnc01/config.xml
@@ -37,4 +37,8 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">Telstra Tethering,telstra.internet,,,,,,,,,505,01,,DUN</string>
 
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1400</integer>
+
 </resources>
diff --git a/core/res/res/values-mcc510-mnc21/config.xml b/core/res/res/values-mcc510-mnc21/config.xml
new file mode 100644
index 0000000..1fd9dfa
--- /dev/null
+++ b/core/res/res/values-mcc510-mnc21/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>51001</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc530-mnc24/config.xml b/core/res/res/values-mcc530-mnc24/config.xml
new file mode 100644
index 0000000..5598e8d
--- /dev/null
+++ b/core/res/res/values-mcc530-mnc24/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Show roaming icon though same named operators. -->
+    <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
+        <item>53001</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 4a0017f..a9fe930 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Membenarkan apl memindahkan tugasan ke latar depan dan latar belakang. Apl boleh melakukan ini tanpa input anda."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"hentikan apl yang sedang dijalankan"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Membenarkan apl untuk mengalih keluar tugasan dan melupuskan aplnya. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"urus tindanan aktiviti"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Membenarkan apl menambah, mengalih keluar dan mengubah suai tindanan aktiviti tempat apl lain berjalan. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"mulakan sebarang aktiviti"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Membenarkan apl untuk memulakan apa-apa aktiviti, tanpa mengira perlindungan kebenaran atau keadaan eksport."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"tetapkan keserasian skrin"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kaedah input itu. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"terikat kepada perkhidmatan yang boleh diakses"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan yang boleh diakses. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"terikat kepada perkhidmatan cetakan"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan cetakan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"akses semua kerja cetakan"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Membenarkan pemegang mengakses kerja cetakan yang dibuat oleh apl lain. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"terikat kepada perkhidmatan teks"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Membenarkan pemegang mengikat kepada antara muka peringkat atasan perkhidmatan teks(mis. PerkhidmatanPenyemakEjaan). Tidak seharusnya diperlukan untuk apl biasa."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"terikat kepada perkhidmatan VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tambah atau alih keluar pentadbir peranti"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Membenarkan pemegang menambah atau mengalih keluar pentadbir peranti aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Membenarkan apl untuk menukar putaran skrin pada bila-bila masa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"tukar kelajuan penuding"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Membenarkan apl menggunakan ciri peringkat rendah SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"baca penimbal bingkai"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Membenarkan apl membaca kandungan penimbal bingkai."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"akses InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Membenarkan apl menggunakan ciri peringkat rendah InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurasikan paparan Wifi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Membenarkan apl mengkonfigurasi dan menyambung ke paparan Wifi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kawal paparan Wifi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Membenarkan apl mengawal ciri tahap rendah paparan Wifi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"tukar tetapan audio anda"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Membenarkan apl untuk mengubah suai tetapan audio global seperti kelantangan dan pembesar suara mana digunakan untuk output."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"rakam audio"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Membenarkan apl menulis ke kad SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubh suai/pdm kdg strn mdia dlm"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Membenarkan apl mengubah suai kandungan storan media dalaman."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"urus storan dokumen"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Membenarkan apl mengurus storan dokumen."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"mengakses storan luaran untuk semua pengguna"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Membenarkan apl untuk mengakses storan luaran untuk semua pengguna."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"akses sistem fail cache"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Membenarkan apl mengurus dasar rangkaian dan menentukan peraturan khusus apl."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ubah suai perakaunan penggunaan rangkaian"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"ubah tanda soket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Membenarkan apl mengubah suai tanda soket untuk laluan"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gunakan apl konfigurasi yang disediakan oleh pembawa"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Masukkan kad SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Kad SIM tiada atau tidak boleh dibaca. Sila masukkan kad SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Kad SIM tidak boleh digunakan."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Kad SIM anda telah dilumpuhkan secara kekal."\n" Hubungi pembekal perkhidmatan wayarles anda untuk mendapatkan kad SIM lain."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Kad SIM anda telah dilumpuhkan secara kekal.\n Hubungi pembekal perkhidmatan wayarles anda untuk mendapatkan kad SIM lain."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Butang lagu sebelumnya"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Butang lagu seterusnya"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Butang Jeda"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Lihat Panduan Pengguna atau hubungi Penjagaan Pelanggan."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Kad SIM dikunci."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Membuka kunci kad SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Sila cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Anda telah tersilap taip menaip kata laluan anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Anda telah tersilap taip PIN anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Sila cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nSila cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Anda telah tersilap taip menaip kata laluan anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Anda telah tersilap taip PIN anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Sila cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Anda telah mencuba untuk membuka kunci tablet dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, tablet akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Anda telah mencuba untuk membuka kunci telefon dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, telefon akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Anda telah mencuba untuk membuka kunci tablet secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet kini akan ditetapkan semula ke tetapan lalai kilang."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Kata laluan"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Log masuk"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nama pengguna atau kata laluan tidak sah."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Lupa nama pengguna atau kata laluan anda?"\n"Lawati "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Lupa nama pengguna atau kata laluan anda?\nLawati "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Menyemak…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Buka kunci"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Bunyi dihidupkan"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Sahkan Navigasi"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Tinggalkan Halaman ini"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Kekal di Halaman ini"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Adakah anda pasti anda mahu menavigasi keluar dari halaman ini?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nAdakah anda pasti anda mahu menavigasi keluar dari halaman ini?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Sahkan"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Petua: Ketik dua kali untuk mengezum masuk dan keluar."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Auto isi"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Malangnya, <xliff:g id="APPLICATION">%1$s</xliff:g> telah berhenti."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Malangnya, proses <xliff:g id="PROCESS">%1$s</xliff:g> telah berhenti."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> tidak bertindak balas."\n\n"Adakah anda mahu menutupnya?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviti <xliff:g id="ACTIVITY">%1$s</xliff:g> tidak bertindak balas. "\n\n" Adakah anda mahu menutupnya?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> tidak bertindak balas.\n\nAdakah anda mahu menutupnya?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviti <xliff:g id="ACTIVITY">%1$s</xliff:g> tidak bertindak balas. \n\n Adakah anda mahu menutupnya?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> tidak bertindak balas. Adakah anda mahu menutupnya?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> tidak bertindak balas. "\n\n"Adakah anda mahu menutupnya?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> tidak bertindak balas. \n\nAdakah anda mahu menutupnya?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Laporkan"</string>
     <string name="wait" msgid="7147118217226317732">"Tunggu"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak bertindak balas. "\n\n"Adakah anda mahu menutupnya?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak bertindak balas. \n\nAdakah anda mahu menutupnya?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Apl diubah hala"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kini sedang berjalan."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> pada asalnya telah dilancarkan."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Membenarkan apl untuk menggunakan perkhidmatan bekas lalai untuk menyalin kandungan. Bukan untuk digunakan oleh apl biasa."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Buat laluan output media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Membenarkan apl untuk membuat laluan output media ke peranti luaran lain."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Akses storan selamat pengawal kekunci"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Membenarkan aplikasi mengakses storan selamat pengawal kekunci."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kawal paparkan dan sembunyikan pengawal kekunci"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Membenarkan aplikasi untuk mengawal pengawal kekunci."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mendapatkan kawalan zum"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Tidak dapat menambahkan widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pergi"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Selesai"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Sblm"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Laksanakan"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Dail nombor"\n"menggunakan <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Wujudkan kenalan"\n"menggunakan <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Dail nombor\nmenggunakan <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Wujudkan kenalan\nmenggunakan <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Satu atau lebih apl berikut meminta kebenaran untuk mengakses akaun anda, sekarang dan pada masa hadapan."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Adakah anda mahu membenarkan permintaan ini?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Permintaan akses"</string>
     <string name="allow" msgid="7225948811296386551">"Benarkan"</string>
     <string name="deny" msgid="2081879885755434506">"Nafi"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Kebenaran diminta"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Kebenaran diminta"\n"untuk akaun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Kebenaran diminta\nuntuk akaun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Kaedah input"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Penyegerakan"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Kebolehaksesan"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Tidak tersedia"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Sedang digunakan"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Skrin Terbina Dalam"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Skrin HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tindih #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Paparan wayarles disambungkan"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Skrin ini ditunjukkan pada peranti lain"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Putus sambungan"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Corak Salah"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Kata Laluan Salah"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN salah"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Cuba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Cuba lagi dalam <xliff:g id="NUMBER">%1$d</xliff:g> saat."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Lukiskan corak anda"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Kata laluan"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?"\n"Lawati"<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?\nLawati"<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Menyemak akaun…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah mencuba untuk membuka kunci tablet dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, tablet akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah mencuba untuk membuka kunci telefon dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, telefon akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah mencuba untuk membuka kunci tablet secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet kini akan ditetapkan semula ke tetapan lalai kilang."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah mencuba untuk membuka kunci telefon secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon kini akan ditetapkan semula ke tetapan lalai kilang."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Tingkatkan kelantangan melebihi aras yang dicadangkan?"\n"Mendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Tingkatkan kelantangan melebihi aras yang dicadangkan?\nMendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Teruskan menahan dengan dua jari untuk mendayakan kebolehcapaian."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Kebolehcapaian didayakan."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Kebolehcapaian dibatalkan."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Pemilik"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Ralat"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Apl ini tidak menyokong akaun untuk profil yang disekat"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Apl ini tidak menyokong akaun untuk profil yang disekat"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Tidak menemui aplikasi untuk mengendalikan tindakan ini"</string>
     <string name="revoke" msgid="5404479185228271586">"Batalkan"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Surat"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Surat Kerajaan"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Undang-undang"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Undang-undang Junior"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Lejar"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Dibatalkan"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Ralat menulis kandungan"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Masukkan PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN semasa"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN baharu"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Sahkan PIN baharu"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Buat PIN untuk mengubah suai sekatan"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN tidak sepadan. Cuba lagi."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN terlalu pendek. Mesti sekurang-kurangnya 4 angka."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN salah. Cuba lagi dalam masa 1 saat."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN salah. Cuba lagi dalam masa <xliff:g id="COUNT">%d</xliff:g> saat."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 74d7702..822c160 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Appen kan gjøre dette uten instruksjoner fra deg."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrering av aktivitetsstabler"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Gir appen tillatelse til å legge til, fjerne og endre aktivitetsstablene som andre apper kjøres i. Skadelige apper kan skape problemer i atferden til andre apper."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"igangsetting av aktiviteter"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Tillater at appen kan starte en aktivitet, uavhengig av tillatelsesbeskyttelse og eksportstatus."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"angi skjermkompatibilitet"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lar innehaveren binde det øverste nivået av grensesnittet til en inndatametode. Skal aldri være nødvendig for normale apper."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"binde seg til en tilgjengelighetstjeneste"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Gir innehaveren tillatelse til å bindes til det øverste nivået av grensesnittet for en tilgjengelighetstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"binding til en utskriftstjeneste"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en utskriftstjeneste. Dette skal ikke være nødvendig for vanlige apper."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"tilgang til alle utskriftsjobber"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Gir innehaveren tillatelse til å åpne utskriftsjobber som er opprettet av andre apper. Dette skal ikke være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"binding til NFC-tjenesten"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Tillater eieren å binde seg til apper som emulerer NFC-kort. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"binde til en teksttjeneste"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Lar innehaveren binde seg til øverste grensesnittnivå for en teksttjeneste (f.eks. SpellCheckerService). Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"binde deg til en VPN-tjeneste"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommuniser med enhetsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Gir appen tillatelse til når som helst å endre rotasjonen av skjermen. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"endre pekerhastighet"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Lar appen bruke grunnleggende SurfaceFlinger-funksjoner."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lese skjermbufferet"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Lar appen lese innholdet i rammebufferen."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"tilgang til InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Lar appen bruke grunnleggende InputFlinger-funksjoner."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurere Wi-Fi-skjermer"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillater appen å konfigurere og koble til Wi-Fi-skjermer."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollere Wi-Fi-skjermer"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillater appen å kontrollere lavnivåfunksjoner i Wi-Fi-skjermer."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"endre lydinnstillinger"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Lar appen endre globale lydinnstillinger slik som volum og hvilken høyttaler som brukes for lydavspilling."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ta opp lyd"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lar appen skrive til SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"endre eller slette innhold på interne medier"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Lar appen endre innholdet i det interne lagringsmediet."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"administrere dokumentlagring"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Lar appen administrere dokumentlagring."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"åpne eksternlagring for alle brukere"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Tillater appen å åpne eksternlagring for alle brukere."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"tilgang til bufrede filer"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lar appen administrere retningslinjene for nettverket og definere appspesifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modifisering av regnskapsføring av nettverksbruk"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"endring av kontaktmerker"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Gir appen tillatelse til å endre kontaktmerker for ruting"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lar innehaveren binde seg til det øverste grensesnittnivået for en varsellyttertjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"starte konfigurasjonsappen som ble levert av operatøren"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"OQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Sett inn et SIM-kort."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-kort mangler eller er uleselig. Sett inn et SIM-kort."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Ubrukelige SIM-kort."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kortet er deaktivert permanent."\n"Ta kontakt med leverandøren av trådløstjenesten for å få et nytt SIM-kort."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kortet er deaktivert permanent.\nTa kontakt med leverandøren av trådløstjenesten for å få et nytt SIM-kort."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Knapp for forrige sang"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Knapp for neste sang"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pause-knappen"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Les i brukerhåndboken eller kontakt brukerstøtten."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet er låst."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser opp SIM-kort…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du har oppgitt feil opplåsingsmønster <xliff:g id="NUMBER_0">%d</xliff:g> ganger."\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du har skrevet inn feil passord <xliff:g id="NUMBER_0">%d</xliff:g> ganger."\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du har skrevet inn feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger."\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du har tegnet inn feil opplåsingsmønster <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøk, blir du bedt om å låse opp nettbrettet ved hjelp av Google-påloggingsinformasjonen din."\n\n"Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du har tegnet inn feil opplåsingsmønster <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøk, blir du bedt om å låse opp telefonen ved hjelp av Google-påloggingsinformasjonen din."\n\n"Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du har oppgitt feil opplåsingsmønster <xliff:g id="NUMBER_0">%d</xliff:g> ganger.\n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du har skrevet inn feil passord <xliff:g id="NUMBER_0">%d</xliff:g> ganger.\n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du har skrevet inn feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger.\n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du har tegnet inn feil opplåsingsmønster <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøk, blir du bedt om å låse opp nettbrettet ved hjelp av Google-påloggingsinformasjonen din.\n\nPrøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du har tegnet inn feil opplåsingsmønster <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøk, blir du bedt om å låse opp telefonen ved hjelp av Google-påloggingsinformasjonen din.\n\nPrøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Du har foretatt <xliff:g id="NUMBER_0">%d</xliff:g> mislykkede opplåsinger av nettbrettet. Etter <xliff:g id="NUMBER_1">%d</xliff:g> flere mislykkede forsøk, blir nettbrettet tilbakestilt til fabrikkinnstillingene, og alle brukerdata går tapt."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Du har foretatt <xliff:g id="NUMBER_0">%d</xliff:g> mislykkede opplåsinger av telefonen. Etter <xliff:g id="NUMBER_1">%d</xliff:g> flere mislykkede forsøk, blir telefonen tilbakestilt til fabrikkinnstillingene, og alle brukerdata går tapt."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Du har foretatt <xliff:g id="NUMBER">%d</xliff:g> mislykkede opplåsinger av nettbrettet. Nettbrettet blir nå tilbakestilt til fabrikkinnstillingene."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passord"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logg på"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ugyldig brukernavn eller passord."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Har du glemt brukernavnet eller passordet ditt?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Har du glemt brukernavnet eller passordet ditt?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrollerer …"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Lås opp"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Lyd på"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Bekreft navigasjon"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Forlat denne siden"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bli værende på denne siden"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Er du sikker på at du vil navigere bort fra denne siden?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nEr du sikker på at du vil navigere bort fra denne siden?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tips: Dobbelttrykk for å zoome inn og ut."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> har dessverre stoppet."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Prosessen <xliff:g id="PROCESS">%1$s</xliff:g> har dessverre stoppet."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarer ikke."\n\n"Vil du lukke appen?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarer ikke."\n\n"Vil du lukke den?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarer ikke.\n\nVil du lukke appen?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarer ikke.\n\nVil du lukke den?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> svarer ikke. Vil du lukke appen?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Prosessen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke."\n\n"Vil du lukke den?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Prosessen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke.\n\nVil du lukke den?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapportér"</string>
     <string name="wait" msgid="7147118217226317732">"Vent"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke."\n\n"Vil du lukke den?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke.\n\nVil du lukke den?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Appen er viderekoblet"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører nå."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ble opprinnelig startet."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Lar appen påkalle standard meldingsbeholdertjeneste for kopiering av innhold. Ikke beregnet på vanlige apper."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Videresending av medieutdata"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Lar en app videresende medieutdata til andre eksterne enheter."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Bruk av sikker lagring via keyguard."</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lar en app bruke sikker lagring via keyguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrollér om tastelåsen er skjult eller vist"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillater at en app kontrollerer tastelåsen."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Trykk to ganger for zoomkontroll"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Kunne ikke legge til modulen."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Utfør"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Utført"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Forrige"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Utfør"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Ring nummeret"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Lag kontakt"\n"med nummeret <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Ring nummeret\n<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Lag kontakt\nmed nummeret <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Følgende app(er) ber om tilgang til kontoen din fra nå av."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vil du tillate dette?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Tilgangsforespørsel"</string>
     <string name="allow" msgid="7225948811296386551">"Tillat"</string>
     <string name="deny" msgid="2081879885755434506">"Avslå"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Tillatelse forespurt"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Tillatelse forespurt"\n"for kontoen <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Tillatelse forespurt\nfor kontoen <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Inndatametode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synkronisering"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgjengelighet"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Kobler til ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tilgjengelig"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ikke tilgjengelig"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"I bruk"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Innebygd skjerm"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skjerm"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlegg #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sikker"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Trådløs skjermdeling er tilkoblet"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Denne skjermen vises på en annen enhet"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Koble fra"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Feil mønster"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Feil passord"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Feil PIN-kode"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv på nytt om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv på nytt om <xliff:g id="NUMBER">%1$d</xliff:g> sekunder."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn mønsteret ditt"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Skriv inn PIN-koden for SIM-kortet"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Skriv inn PIN-koden"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Passord"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Logg på"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldig brukernavn eller passord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Sjekker kontoen ..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har oppgitt feil opplåsningspassord for nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, tilbakestilles nettbrettet til fabrikkstandard og all data går tapt."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har oppgitt feil opplåsningspassord for telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, tilbakestilles telefonen til fabrikkstandard og all data går tapt."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har oppgitt feil opplåsningspassord for nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Telefonen tilbakestilles nå til fabrikkstandard."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har oppgitt feil opplåsningspassord for telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Telefonen tilbakestilles nå til fabrikkstandard."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto."\n\n" Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto."\n\n" Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vil du øke lydnivået over det anbefalte nivået?"\n"Et høyt lydnivå i lengre perioder kan skade hørselen din."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vil du øke lydnivået over det anbefalte nivået?\nEt høyt lydnivå i lengre perioder kan skade hørselen din."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsett å holde nede to fingre for å aktivere tilgjengelighet."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tilgjengelighet er aktivert."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgjengelighetstjenesten ble avbrutt."</string>
     <string name="user_switched" msgid="3768006783166984410">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Eier"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Feil"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Denne appen støtter ikke kontoer for begrensede profiler"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Denne appen støtter ikke kontoer for begrensede profiler"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Finner ingen apper som kan utføre denne handlingen"</string>
     <string name="revoke" msgid="5404479185228271586">"Opphev"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kansellert"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Feil under skriving av innhold"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Skriv inn PIN-koden"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Gjeldende PIN-kode:"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Ny PIN-kode"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Bekreft ny PIN-kode"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Angi en PIN-kode for endring av begrensninger"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-kodene stemmer ikke overens. Prøv på nytt."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-koden er for kort. Den må bestå av minst fire sifre."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Feil PIN-kode. Prøv på nytt om 1 sekund."</item>
+    <item quantity="other" msgid="8030607343223287654">"Feil PIN-kode. Prøv på nytt om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bbdfed3..5c2b315 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. De app kan dit doen zonder om uw bevestiging te vragen."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"activiteitstacks beheren"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Hiermee kan de app de activiteitstacks waarin andere apps worden uitgevoerd, toevoegen, verwijderen en aanpassen. Schadelijke apps kunnen de werking van andere apps verstoren."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"elke activiteit starten"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Toestaan dat de app elke activiteit start, ongeacht rechtenbeveiliging of geëxporteerde status."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"schermcompatibiliteit instellen"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Hiermee kan de houder zich verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"koppelen aan een toegankelijkheidsservice"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een toegankelijkheidsservice. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"koppelen aan een afdrukservice"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Hiermee kan de houder verbinding maken met de hoofdinterface van een afdrukservice. Nooit vereist voor normale apps."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"toegang krijgen tot alle afdruktaken"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Hiermee kan de houder toegang krijgen tot afdruktaken die zijn gemaakt door een andere app. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"koppelen aan NFC-service"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Hiermee kan de houder apps koppelen die NFC-kaarten emuleren. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"koppelen aan een sms-service"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Hiermee kan de gebruiker koppelen met de hoofdinterface van een tekstservice (zoals SpellCheckerService). Dit is niet nodig voor normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"koppelen aan een VPN-service"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"een apparaatbeheerder toevoegen of verwijderen"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Hiermee kan de rechtenhouder actieve apparaatbeheerders toevoegen of verwijderen. Nooit vereist voor normale apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Hiermee kan de app de rotatie van het scherm op elk moment wijzigen. Nooit vereist voor normale apps."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"aanwijzersnelheid wijzigen"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Hiermee kan de app SurfaceFlinger-functies op laag niveau gebruiken."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Hiermee kan de app de inhoud van de framebuffer lezen."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"toegang krijgen tot InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Hiermee kan de app InputFlinger-functies op laag niveau gebruiken."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"wifi-displays configureren"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"De app toestaan wifi-displays te configureren en hiermee verbinding te maken."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"wifi-displays beheren"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"De app toestaan minder belangrijke functies van wifi-displays te beheren."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"uw audio-instellingen wijzigen"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Hiermee kan de app algemene audio-instellingen wijzigen zoals het volume en welke luidspreker wordt gebruikt voor de uitvoer."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"audio opnemen"</string>
@@ -570,7 +592,7 @@
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"wifi-verbindingen weergeven"</string>
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Hiermee kan de app informatie over wifi-netwerken bekijken, zoals of wifi is ingeschakeld en de naam van apparaten waarmee via wifi verbinding is gemaakt."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"wifi-verbinding maken en verbreken"</string>
-    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Hiermee kan de app zich koppelen aan en loskoppelen van wifi-toegangspunten en wijzigingen aanbrengen in de apparaatconfiguratie voor wifi-netwerken."</string>
+    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Hiermee kan de app zich koppelen aan en ontkoppelen van wifi-toegangspunten en wijzigingen aanbrengen in de apparaatconfiguratie voor wifi-netwerken."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wifi Multicast-ontvangst toestaan"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Hiermee kan de app pakketten ontvangen die via multicastadressen naar alle apparaten in een wifi-netwerk worden verzonden, niet alleen naar uw tablet. Het stroomgebruik ligt hierbij hoger dan in de niet-multicastmodus."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Hiermee kan de app pakketten ontvangen die via multicastadressen naar alle apparaten in een wifi-netwerk worden verzonden, niet alleen naar uw telefoon. Het stroomgebruik ligt hierbij hoger dan in de niet-multicastmodus."</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Hiermee kan de app schrijven naar de SD-kaart."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"inh. mediaopsl. wijz./verw."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Hiermee kan de app de inhoud van de interne mediaopslag aanpassen."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"documentopslag beheren"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Hiermee kan de app documentopslag beheren."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"toegang tot externe opslag van alle gebruikers"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Hiermee krijgt de app toegang tot externe opslag van alle gebruikers."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"het cachebestandssysteem openen"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Hiermee kan de app het netwerkbeleid beheren en app-specifieke regels definiëren."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verrekening van netwerkgebruik aanpassen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"socketmarkeringen aanpassen"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Hiermee kan de app socketmarkeringen voor routeren aanpassen"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Hiermee kan de houder koppelen aan de hoofdinterface van een listener-service voor meldingen. Nooit vereist voor normale apps."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"de door de provider geleverde configuratie-app aanroepen"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Plaats een simkaart."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"De simkaart ontbreekt of kan niet worden gelezen. Plaats een simkaart."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Onbruikbare simkaart."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Uw simkaart is permanent uitgeschakeld."\n" Neem contact op met uw mobiele serviceprovider voor een nieuwe simkaart."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Uw simkaart is permanent uitgeschakeld.\n Neem contact op met uw mobiele serviceprovider voor een nieuwe simkaart."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Knop voor vorig nummer"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Knop voor volgend nummer"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Knop voor onderbreken"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Raadpleeg de gebruikershandleiding of neem contact op met de klantenservice."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kaart is vergrendeld."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-kaart ontgrendelen..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen met uw aanmeldingsgegevens voor Google."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen met uw aanmeldingsgegevens voor Google."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen met uw aanmeldingsgegevens voor Google.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen met uw aanmeldingsgegevens voor Google.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de tablet en gaan alle gebruikersgegevens verloren."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"U heeft nu <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de telefoon en gaan alle gebruikersgegevens verloren."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de tablet."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inloggen"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Gebruikersnaam of wachtwoord ongeldig."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"https://www.google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Bent u uw gebruikersnaam of wachtwoord vergeten?\nGa naar "<b>"https://www.google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Controleren…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Ontgrendelen"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Geluid aan"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Navigatie bevestigen"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Deze pagina verlaten"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Op deze pagina blijven"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Weet u zeker dat u deze pagina wilt verlaten?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nWeet u zeker dat u deze pagina wilt verlaten?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: dubbeltik om in en uit te zoomen."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autom. aanvullen"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> is gestopt."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is gestopt."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reageert niet."\n\n"Wilt u deze app sluiten?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> reageert niet."\n\n"Wilt u deze activiteit sluiten?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reageert niet.\n\nWilt u deze app sluiten?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> reageert niet.\n\nWilt u deze activiteit sluiten?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reageert niet. Wilt u deze app sluiten?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."\n\n"Wilt u het sluiten?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet.\n\nWilt u het sluiten?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapport"</string>
     <string name="wait" msgid="7147118217226317732">"Wachten"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"De pagina reageert niet meer."\n\n"Wilt u de pagina sluiten?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"De pagina reageert niet meer.\n\nWilt u de pagina sluiten?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App verplaatst"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Hiermee kan de app de standaard containerservice aanroepen om inhoud te kopiëren. Niet voor gebruik door normale apps."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Media-uitvoer aansturen"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Hiermee kan een app media-uitvoer naar andere externe apparaten doorsturen."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Toegang tot opslag met toetsbeveiliging"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Hiermee krijgt een app toegang tot opslag met toetsbeveiliging."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Weergeven en verbergen van toetsbeveiliging beheren"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Staat toe dat een app de toetsbeveiliging beheert."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Raak twee keer aan voor zoomregeling"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Kan widget niet toevoegen."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ga"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Gereed"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Vorige"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Uitvoeren"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Nummer bellen"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Contact maken"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Nummer bellen\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Contact maken\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"De volgende apps verzoeken om toegang tot uw account, nu en in de toekomst."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Wilt u dit verzoek toestaan?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Verzoek om toegang"</string>
     <string name="allow" msgid="7225948811296386551">"Toestaan"</string>
     <string name="deny" msgid="2081879885755434506">"Weigeren"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Toestemming gevraagd"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Toestemming gevraagd"\n"voor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Toestemming gevraagd\nvoor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Invoermethode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchroniseren"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Toegankelijkheid"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Verbinden..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Beschikbaar"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Niet beschikbaar"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"In gebruik"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ingebouwd scherm"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-scherm"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", beveiligd"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Draadloze display is aangesloten"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Dit scherm wordt op een ander apparaat weergegeven"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbinding verbreken"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Onjuist patroon"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Onjuist wachtwoord"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Onjuiste pincode"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer het over <xliff:g id="NUMBER">%1$d</xliff:g> seconden opnieuw."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken uw patroon"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Geef de pincode van de simkaart op"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Pincode opgeven"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Wachtwoord"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Inloggen"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikersnaam of wachtwoord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?\nGa naar "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Account controleren…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de tablet en gaan alle gebruikersgegevens verloren."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"U heeft nu <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de telefoon en gaan alle gebruikersgegevens verloren."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de tablet."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de telefoon."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Wilt u het volume verhogen tot boven het aanbevolen geluidsniveau?"\n"Te lang luisteren op een te hoog volume kan leiden tot gehoorbeschadiging."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Wilt u het volume verhogen tot boven het aanbevolen geluidsniveau?\nTe lang luisteren op een te hoog volume kan leiden tot gehoorbeschadiging."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Blijf het scherm met twee vingers aanraken om toegankelijkheid in te schakelen."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Toegankelijkheid ingeschakeld."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toegankelijkheid geannuleerd."</string>
     <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Eigenaar"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Deze app biedt geen ondersteuning voor accounts voor beperkte profielen"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Deze app biedt geen ondersteuning voor accounts voor beperkte profielen"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Er is geen app gevonden om deze actie uit te voeren"</string>
     <string name="revoke" msgid="5404479185228271586">"Intrekken"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van inhoud"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Geef de pincode op"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Huidige pincode"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nieuwe pincode"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Nieuwe pincode bevestigen"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Maak een pincode voor het aanpassen van beperkingen"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"De pincodes komen niet overeen. Probeer het opnieuw."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pincode is te kort. Moet ten minste vier cijfers lang zijn."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Onjuiste pincode. Probeer het over één seconde opnieuw."</item>
+    <item quantity="other" msgid="8030607343223287654">"Onjuiste pincode. Probeer het over <xliff:g id="COUNT">%d</xliff:g> seconden opnieuw."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e4e82f9..cbcb059 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Pozwala aplikacji na przenoszenie zadań między tłem a pierwszym planem. Aplikacja może to robić bez Twojego udziału."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"zarządzanie stosami aktywności"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Zezwala aplikacji na dodawanie, usuwanie i zmianę stosów aktywności, w których działają inne aplikacje. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"rozpoczynanie dowolnej czynności"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Zezwala aplikacji na rozpoczynanie dowolnej czynności niezależnie od ochrony uprawnień lub stanu eksportu."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ustaw zgodność ekranu"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Pozwala na powiązanie wybranego sposobu wprowadzania tekstu z interfejsem najwyższego poziomu. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"tworzenie powiązania z usługą ułatwień dostępu"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi ułatwień dostępu. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"tworzenie powiązania z usługą drukowania"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi drukowania. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"dostęp do wszystkich zadań drukowania"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Zezwala na dostęp do zadań drukowania utworzonych przez inną aplikację. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"powiązanie z usługą NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Umożliwia właścicielowi powiązanie z aplikacjami emulującymi karty NFC. Nie powinno być nigdy potrzebne w normalnych aplikacjach."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tworzenie powiązania z usługą tekstową"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi tekstowej (np. SpellCheckerService). Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"tworzenie powiązania z usługą VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodaj lub usuń administratora urządzenia"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umożliwia właścicielowi dodawanie i usuwanie aktywnych administratorów urządzenia. Ta opcja nie jest wykorzystywana w przypadku standardowych aplikacji."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Pozwala aplikacji na zmianę obrotu ekranu w dowolnym momencie. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"zmiana szybkości wskaźnika"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"czytanie bufora ramki"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Pozwala aplikacji na odczyt zawartości bufora ramki."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"dostęp do InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Zezwala aplikacji na wykorzystanie niskopoziomowych funkcji usługi InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurowanie wyświetlaczy Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Zezwala aplikacji na konfigurację wyświetlaczy Wi-Fi i łączenie z nimi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"zarządzanie wyświetlaczami Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Zezwala aplikacji na zarządzanie niskopoziomowymi funkcjami wyświetlaczy Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmienianie ustawień audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Pozwala aplikacji na modyfikowanie globalnych ustawień dźwięku, takich jak głośność oraz urządzenie wyjściowe."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"nagrywanie dźwięku"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pozwala aplikacji na zapis na karcie SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modyfikowanie/usuwanie zawartości pamięci wew."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Pozwala aplikacji na modyfikowanie zawartości pamięci wewnętrznej."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"zarządzaj przechowywaniem dokumentów"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Pozwala aplikacji zarządzać przechowywaniem dokumentów."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"dostęp do zewnętrznej pamięci wszystkich"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Pozwala aplikacji na dostęp do zewnętrznej pamięci masowej dla wszystkich użytkowników."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostęp do systemu plików pamięci podręcznej"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pozwala aplikacji na zarządzanie zasadami dotyczącymi sieci i definiowanie reguł aplikacji."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modyfikowanie sposobu naliczania użycia sieci"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"zmiana oznaczeń gniazd"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Zezwala aplikacji na zmianę oznaczeń gniazd na potrzeby trasowania"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi odbiornika powiadomień. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Zezwala na wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Włóż kartę SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Brak karty SIM lub nie można jej odczytać. Włóż kartę SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Karta SIM bezużyteczna."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Karta SIM jest trwale wyłączona."\n" Skontaktuj się z dostawcą usług bezprzewodowych, aby uzyskać inną kartę SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Karta SIM jest trwale wyłączona.\n Skontaktuj się z dostawcą usług bezprzewodowych, aby uzyskać inną kartę SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Przycisk poprzedniego utworu"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Przycisk następnego utworu"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Przycisk wstrzymania"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Zapoznaj się z instrukcją obsługi lub skontaktuj się z działem obsługi klienta."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Karta SIM jest zablokowana."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odblokowywanie karty SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> zostało wpisane nieprawidłowe hasło. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> został wpisany nieprawidłowy PIN. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Wzór odblokowania został <xliff:g id="NUMBER_0">%d</xliff:g> razy narysowany nieprawidłowo. Po <xliff:g id="NUMBER_1">%d</xliff:g> kolejnych próbach zakończonych niepowodzeniem konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Wzór odblokowania został <xliff:g id="NUMBER_0">%d</xliff:g> razy narysowany nieprawidłowo. Po <xliff:g id="NUMBER_1">%d</xliff:g> kolejnych próbach zakończonych niepowodzeniem konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> zostało wpisane nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> został wpisany nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Wzór odblokowania został <xliff:g id="NUMBER_0">%d</xliff:g> razy narysowany nieprawidłowo. Po <xliff:g id="NUMBER_1">%d</xliff:g> kolejnych próbach zakończonych niepowodzeniem konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Wzór odblokowania został <xliff:g id="NUMBER_0">%d</xliff:g> razy narysowany nieprawidłowo. Po <xliff:g id="NUMBER_1">%d</xliff:g> kolejnych próbach zakończonych niepowodzeniem konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Próbowano <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Próbowano <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Próbowano <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Tablet zostanie teraz zresetowany do ustawień fabrycznych."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Hasło"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Zaloguj się"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Błędna nazwa użytkownika lub hasło."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nie pamiętasz nazwy użytkownika lub hasła?"\n"Odwiedź stronę "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nie pamiętasz nazwy użytkownika lub hasła?\nOdwiedź stronę "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Sprawdzanie…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Odblokuj"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Włącz dźwięk"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potwierdź przejście"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Opuść tę stronę"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Pozostań na tej stronie"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Czy na pewno chcesz opuścić tę stronę?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nCzy na pewno chcesz opuścić tę stronę?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Wskazówka: dotknij dwukrotnie, aby powiększyć lub pomniejszyć."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autouzupełnianie"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Niestety, aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> została zatrzymana."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Niestety, proces <xliff:g id="PROCESS">%1$s</xliff:g> został zatrzymany."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacja <xliff:g id="APPLICATION">%2$s</xliff:g> nie reaguje."\n\n"Czy chcesz ją zamknąć?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> nie odpowiada."\n\n"Czy chcesz je zakończyć?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacja <xliff:g id="APPLICATION">%2$s</xliff:g> nie reaguje.\n\nCzy chcesz ją zamknąć?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> nie odpowiada.\n\nCzy chcesz je zakończyć?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> nie reaguje. Czy chcesz ją zamknąć?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."\n\n"Czy chcesz go zakończyć?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada.\n\nCzy chcesz go zakończyć?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Zgłoś"</string>
     <string name="wait" msgid="7147118217226317732">"Czekaj"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Strona nie odpowiada na żądania."\n\n"Zamknąć ją?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Strona nie odpowiada na żądania.\n\nZamknąć ją?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplikacja przekierowana"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> została pierwotnie uruchomiona."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Pozwala aplikacji na wywoływanie domyślnej usługi kontenera w celu skopiowania zawartości. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Kierowanie wyjścia multimediów"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Pozwala aplikacji na kierowanie wyjściowych danych multimedialnych do innych urządzeń zewnętrznych."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Dostęp do bezpiecznego magazynu kluczy"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Zezwala aplikacji na dostęp do bezpiecznego magazynu kluczy."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontroluj wyświetlanie i ukrywanie zabezpieczenia kluczami"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umożliwia aplikacji kontrolowanie zabezpieczenia kluczami."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dotknij dwukrotnie, aby sterować powiększeniem."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nie można dodać widżetu."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"OK"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Gotowe"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Wstecz"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Wykonaj"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Połącz"\n"z numerem <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Utwórz kontakt"\n"dla numeru <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Połącz\nz numerem <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Utwórz kontakt\ndla numeru <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Co najmniej jedna z następujących aplikacji żąda uprawnień dostępu do Twojego konta – teraz i w przyszłości."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Chcesz zezwolić na to żądanie?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Prośba o dostęp"</string>
     <string name="allow" msgid="7225948811296386551">"Zezwól"</string>
     <string name="deny" msgid="2081879885755434506">"Odmów"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Prośba o pozwolenie"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Prośba o pozwolenie"\n"dotyczące konta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Prośba o pozwolenie\ndotyczące konta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Sposób wprowadzania tekstu"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronizacja"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Ułatwienia dostępu"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Łączę..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Dostępne"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Niedostępne"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"W użyciu"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Wbudowany ekran"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Ekran HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Nakładka nr <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", bezpieczny"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Podłączony jest wyświetlacz bezprzewodowy"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ten ekran jest wyświetlany na innym urządzeniu"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Rozłącz"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nieprawidłowy wzór"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nieprawidłowe hasło"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Nieprawidłowy PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Spróbuj ponownie za <xliff:g id="NUMBER">%1$d</xliff:g> s."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Narysuj wzór"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Podaj PIN karty SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Podaj PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Hasło"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Zaloguj się"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nieprawidłowa nazwa użytkownika lub hasło."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nie pamiętasz nazwy użytkownika lub hasła?"\n"Wejdź na "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nie pamiętasz nazwy użytkownika lub hasła?\nWejdź na "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Sprawdzam konto"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie teraz zresetowany do ustawień fabrycznych."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie teraz zresetowany do ustawień fabrycznych."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Usuń"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Chcesz ustawić głośność powyżej bezpiecznego poziomu?"\n"Słuchanie przy dużym poziomie głośności przez dłuższy czas może doprowadzić do uszkodzenia słuchu."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Chcesz ustawić głośność powyżej bezpiecznego poziomu?\nSłuchanie przy dużym poziomie głośności przez dłuższy czas może doprowadzić do uszkodzenia słuchu."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Aby włączyć ułatwienia dostępu, przytrzymaj dwa palce."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Włączono ułatwienia dostępu."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ułatwienia dostępu zostały anulowane."</string>
     <string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Właściciel"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Błąd"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ta aplikacja nie obsługuje kont w przypadku profili z ograniczeniami"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ta aplikacja nie obsługuje kont w profilach z ograniczeniami"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nie znaleziono aplikacji do obsługi tej akcji"</string>
     <string name="revoke" msgid="5404479185228271586">"Cofnij"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Anulowane"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Błąd podczas zapisu treści"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Podaj PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Bieżący PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nowy PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potwierdź nowy PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Utwórz PIN wymagany przy zmianie ograniczeń"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kody PIN nie są identyczne. Spróbuj ponownie."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN jest za krótki. Musi mieć co najmniej 4 cyfry."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Nieprawidłowy PIN. Spróbuj ponownie za 1 s."</item>
+    <item quantity="other" msgid="8030607343223287654">"Nieprawidłowy PIN. Spróbuj ponownie za <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-port/alias.xml b/core/res/res/values-port/alias.xml
deleted file mode 100644
index bf3eecb..0000000
--- a/core/res/res/values-port/alias.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** 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.
-*/
--->
-<resources>
-    <!-- Alias used to reference one of two possible layouts in keyguard.  -->
-    <item type="layout" name="keyguard_eca">@android:layout/keyguard_emergency_carrier_area</item>
-</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index e5c48bb..4063ebf 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que a aplicação mova tarefas para primeiro e segundo plano. A aplicação poderá fazê-lo sem qualquer entrada do utilizador."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gerir pilhas de atividade"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que a aplicação adicione, remova e modifique as pilhas de atividade em que são executadas outras aplicações. As aplicações maliciosas podem afetar o comportamento de outras aplicações."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualquer atividade"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que a aplicação inicie qualquer atividade, independentemente da proteção de permissão ou do estado exportado."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir compatibilidade de ecrã"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite ao titular vincular-se à interface de nível superior de um método de entrada. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a um serviço de acessibilidade"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite que o titular vincule a interface de nível superior de um serviço de acessibilidade. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincular a um serviço de impressão"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite que o titular vincule a interface de nível superior de um serviço de impressão. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"aceder a todas as tarefas de impressão"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite que o titular aceda a tarefas de impressão criadas por outra aplicação. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"vincular a serviço NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Permite ao titular vincular a aplicações que recriam cartões NFC. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a um serviço de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite ao titular ligar-se à interface de nível superior de um serviço de texto (por exemplo SpellCheckerService). Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular a um serviço VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador de dispositivos"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o titular adicione ou remova administradores de dispositivos ativos. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que a aplicação altere a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"alterar a veloc. do ponteiro"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite à aplicação utilizar funcionalidades de SurfaceFlinger de nível inferior."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler memória intermédia de fotogramas"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite à aplicação ler o conteúdo da memória intermédia de fotogramas."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"aceder a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que a aplicação utilize funcionalidades de InputFlinger de nível inferior."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar visores Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que a aplicação se configure e se ligue a visores Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar visores Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que a aplicação controle funcionalidades de baixo nível em visores Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas definições de áudio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que a aplicação modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que a aplicação escreva no cartão SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./elim. armaz. interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que a aplicação modifique o conteúdo de armazenamento de suportes internos."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"gerir o armaz. de documentos"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permite que a aplicação faça a gestão do armazenamento de documentos."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"aceder ao armazenamento externo de todos os utilizadores"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que a aplicação aceda ao armazenamento externo para todos os utilizadores."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"aceder ao sistema de ficheiros da cache"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contabilização da utilização da rede"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que a aplicação modifique as marcas de socket para encaminhamento"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicação de configuração fornecida pela operadora"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insira um cartão SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"O cartão SIM está em falta ou não é legível. Introduza um cartão SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Cartão SIM inutilizável."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O cartão SIM foi desativado definitivamente. "\n" Contacte o seu fornecedor de serviços de rede sem fios para obter outro cartão SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O cartão SIM foi desativado definitivamente. \n Contacte o seu fornecedor de serviços de rede sem fios para obter outro cartão SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Botão Faixa anterior"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Botão Faixa seguinte"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botão Pausa"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulte o Manual de utilizador ou contacte a Assistência a Clientes."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"A desbloquear cartão SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Escreveu a sua palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n" Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Escreveu o seu número PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n" Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet com as suas credenciais de início de sessão do Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel com as suas credenciais de início de sessão do Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Escreveu a sua palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\n Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Escreveu o seu número PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\n Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet com as suas credenciais de início de sessão do Google.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel com as suas credenciais de início de sessão do Google.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Tentou desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativa(s) sem êxito, as definições de origem do tablet serão repostas e todos os dados de utilizador serão perdidos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativa(s) sem êxito, as definições de origem do telemóvel serão repostas e todos os dados de utilizador serão perdidos."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tentou desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que serão repostas as respetivas definições de origem."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Palavra-passe"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Iniciar sessão"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nome de utilizador ou palavra-passe inválidos."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Esqueceu-se do nome de utilizador ou da palavra-passe?"\n"Visite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Esqueceu-se do nome de utilizador ou da palavra-passe?\nVisite "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"A verificar…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloquear"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Som ativado"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmar Navegação"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Sair desta Página"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Permanecer nesta Página"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tem a certeza de que pretende navegar para outra página?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nTem a certeza de que pretende navegar para outra página?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sugestão: toque duas vezes para aumentar ou diminuir o zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Preenchimento Automático"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Lamentamos, o <xliff:g id="APPLICATION">%1$s</xliff:g> foi interrompido."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Lamentamos, o processo <xliff:g id="PROCESS">%1$s</xliff:g> foi interrompido."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> não está a responder. "\n\n"Pretende fechá-la?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> não está a responder. "\n\n" Pretende fechá-la?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> não está a responder. \n\nPretende fechá-la?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> não está a responder. \n\n Pretende fechá-la?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> não está a responder. Pretende fechá-la?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está a responder. "\n\n" Pretende fechá-lo?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está a responder. \n\n Pretende fechá-lo?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Relatório"</string>
     <string name="wait" msgid="7147118217226317732">"Esperar"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"A página deixou de responder. "\n" "\n" Pretende fechá-la?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"A página deixou de responder. \n \n Pretende fechá-la?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicação redirecionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> está agora a ser executado."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi originalmente iniciado."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permite à aplicação invocar o serviço de contentor predefinido para copiar conteúdo. Não se destina a ser utilizado por aplicações normais."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Encaminhar saída de som multimédia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que a aplicação encaminhe a saída de som multimédia para outros dispositivos externos."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Aceder ao armazenamento seguro de proteção de teclado"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite a uma aplicação aceder ao armazenamento seguro de proteção de teclado."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar apresentação e ocultação de proteção de teclado"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que uma aplicação controle a proteção de teclado."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Concluído"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Ant"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Marcar número"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Criar contacto"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Marcar número\nutilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Criar contacto\nutilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Uma ou várias das aplicações seguintes solicitam permissão para aceder à sua conta, agora e no futuro."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Pretende autorizar este pedido?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Pedido de acesso"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Recusar"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permissão solicitada"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permissão solicitada"\n"para a conta <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permissão solicitada\npara a conta <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Método de entrada"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronização"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"A ligar..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Não disponível"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Em utilização"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ecrã Integrado"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Ecrã HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", protegido"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"O Display sem fios está ligado"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Este ecrã está a ser apresentado noutro dispositivo"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desligar"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequência Incorreta"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Palavra-passe Incorreta"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Incorreto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente dentro de <xliff:g id="NUMBER">%1$d</xliff:g> segundos."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe a sua sequência"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduzir PIN do cartão SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduzir PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Palavra-passe"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sessão"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de utilizador ou palavra-passe inválidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu-se do nome de utilizador ou da palavra-passe?"\n"Aceda a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu-se do nome de utilizador ou da palavra-passe?\nAceda a "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"A verificar a conta…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tentou desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, as definições de origem do telemóvel serão repostas e todos os dados do utilizador serão perdidos."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, as definições de origem do telemóvel serão repostas e todos os dados do utilizador serão perdidos."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tentou desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que será reposta a predefinição de fábrica."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que será reposta a predefinição de fábrica."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentar o volume acima do nível recomendado?"\n"Ouvir em volume alto durante longos períodos de tempo poderá prejudicar a sua audição."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentar o volume acima do nível recomendado?\nOuvir em volume alto durante longos períodos de tempo poderá prejudicar a sua audição."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha os dois dedos para ativar a acessibilidade."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
     <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietário"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Erro"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Esta aplicação não suporta contas de perfis restritos"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicação não suporta contas de perfis restritos"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Não foram encontradas aplicações para executar esta ação"</string>
     <string name="revoke" msgid="5404479185228271586">"Revogar"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelada"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Erro ao escrever conteúdo"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introduzir PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN Atual"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novo PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirme o novo PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crie um PIN para modificar as restrições"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não correspondem. Tente novamente."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é demasiado pequeno. Deve ter, no mínimo, 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorreto. Tente novamente em 1 seg."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorreto. Tente novamente em <xliff:g id="COUNT">%d</xliff:g> seg."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f0f3d60..a228799 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que o aplicativo mova tarefas para o primeiro plano e o plano de fundo, sem sua intervenção."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"parar os aplicativos em execução"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que um aplicativo remova tarefas e elimine seus aplicativos. Aplicativos maliciosos podem interferir no comportamento de outros aplicativos."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gerenciar pilhas de atividades"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que o aplicativo adicione, remova e modifique as pilhas de atividades nas quais outros aplicativos são executados. Aplicativos mal-intencionados podem comprometer o funcionamento de outros aplicativos."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualquer atividade"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que o aplicativo inicie qualquer atividade, independentemente da permissão ou do estado exportado."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir a compatibilidade de tela"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite que o proprietário utilize a interface de nível superior de um método de entrada. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"usar um serviço de acessibilidade"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite que o proprietário use a interface de nível superior de um serviço de acessibilidade. Nunca deve ser necessário para aplicativos comuns."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"associar a um serviço de impressão"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite que o proprietário use a interface de nível superior de um serviço de impressão. Não deve ser necessário para aplicativos comuns."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acessar todos os trabalhos de impressão"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite que o proprietário acesse trabalhos de impressão criados por outro aplicativo. Não deve ser necessário para aplicativos comuns."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"sujeitar-se a um serviço de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite que o proprietário utilize interface de nível superior de um serviço de texto (por exemplo, SpellCheckerService). Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"se ligam a um serviço de VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para aplicativos normais."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador do dispositivo"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o proprietário adicione ou remova administradores do dispositivo ativos. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que o aplicativo gire a tela a qualquer momento. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"alterar velocidade do ponteiro"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que o aplicativo use recursos com baixos níveis de SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler o buffer do frame"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que o aplicativo leia o conteúdo do buffer de frame."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acessar InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que o aplicativo use recursos com baixos níveis de InputFinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar monitores Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que o aplicativo configure e conecte a monitores Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar monitores Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que o aplicativo controle recursos de baixo nível de monitores Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas configurações de áudio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que o aplicativo modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que o aplicativo grave em seu cartão SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar/excluir conteúdos de armazenamento de mídia internos"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que o aplicativo modifique o conteúdo da mídia de armazenamento interno."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"gerenciar armaz. de documentos"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permitir que o aplicativo gerencie o armazenamento de documentos."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acessar arm. ext. dos usuários"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que o aplicativo acesse o armazenamento externo para todos os usuários."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acessar o sistema de arquivos de cache"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que o aplicativo gerencie políticas de rede e definia regras específicas para o aplicativo."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contagem de uso da rede"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de soquetes"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que o aplicativo modifique marcas de soquetes para roteamento"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para aplicativos comuns."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar o aplicativo de configuração fornecido pela operadora"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o proprietário invoque o aplicativo de configuração fornecido pela operadora. Não deve ser necessário para aplicativos comuns."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insera um cartão SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"O cartão SIM não foi inserido ou não é possível lê-lo. Insira um cartão SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Cartão SIM inutilizável."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O cartão SIM foi desativado permanentemente."\n"Entre em contato com seu provedor de serviços sem fio para obter outro cartão SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O cartão SIM foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para obter outro cartão SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Botão \"Faixa anterior\""</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Botão \"Próxima faixa\""</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botão \"Pausar\""</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulte o Guia do usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o cartão SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes."\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes.\n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o tablet será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o telefone será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O tablet será redefinido para o padrão de fábrica."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Senha"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Fazer login"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nome de usuário ou senha inválidos."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Esqueceu seu nome de usuário ou senha?"\n"Acesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Esqueceu seu nome de usuário ou senha?\nAcesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Verificando…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloquear"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Som ativado"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmar navegação"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Sair desta página"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Permanecer nesta página"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tem certeza de que deseja sair desta página?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nTem certeza de que deseja sair desta página?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Preench. aut."</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"O <xliff:g id="APPLICATION">%1$s</xliff:g> parou."</string>
     <string name="aerr_process" msgid="4507058997035697579">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> não está respondendo."\n\n"Deseja fechá-la?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> não está respondendo."\n\n"Deseja fechá-la?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> não está respondendo.\n\nDeseja fechá-la?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> não está respondendo.\n\nDeseja fechá-la?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> não está respondendo. Deseja encerrar o aplicativo?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está respondendo."\n\n"Deseja fechá-lo?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está respondendo.\n\nDeseja fechá-lo?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Informar"</string>
     <string name="wait" msgid="7147118217226317732">"Aguardar"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"A página não responde."\n\n"Deseja fechá-la?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"A página não responde.\n\nDeseja fechá-la?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicativo redirecionado"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> não está em execução."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi iniciado."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permite que o aplicativo invoque serviços contêiner padrão para copiar conteúdo. Não deve ser usado em aplicativos normais."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Rotear saída de mídia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que um aplicativo faça o roteamento de saída de mídia para outros dispositivos externos."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Acessar o armazenamento seguro do bloqueio de teclado"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que o aplicativo acesse o armazenamento seguro do bloqueio de teclado."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar a exibição e ocultação do bloqueio de tela"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que o aplicativo controle o bloqueio de teclado."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Concluído"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Anter."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Discar número"\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Criar contato "\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Discar número\nusando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Criar contato \nusando <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"O aplicativo a seguir ou outros aplicativos solicitam permissão para acessar sua conta, agora e no futuro."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Deseja permitir essa solicitação?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitação de acesso"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Negar"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permissão solicitada"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permissão solicitada"\n"para a conta <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permissão solicitada\npara a conta <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Método de entrada"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronizar"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Não disponível"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Em uso"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Tela integrada"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Tela HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição nº <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", seguro"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"O Display sem fio está conectado"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tela exibida em outro dispositivo."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Padrão incorreto"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Senha incorreta"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorreto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente em <xliff:g id="NUMBER">%1$d</xliff:g> segundos."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe seu padrão"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do cartão SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Digite o PIN"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Senha"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Fazer login"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de usuário ou senha inválidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu seu nome de usuário ou senha?"\n"Acesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu seu nome de usuário ou senha?\nAcesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Verificando a conta..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o tablet será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o telefone será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O tablet será redefinido para o padrão de fábrica."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER">%d</xliff:g> vezes. O telefone será redefinido para o padrão de fábrica."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentar o volume acima do nível recomendado?"\n"A audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentar o volume acima do nível recomendado?\nA audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietário"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Erro"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Este aplicativo não suporta contas para perfis restritos"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Este aplicativo não suporta contas para perfis restritos"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nenhum aplicativo encontrado para executar a ação"</string>
     <string name="revoke" msgid="5404479185228271586">"Revogar"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Ofício"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelado"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Erro ao gravar o conteúdo"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Insira o PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN atual"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novo PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirme o novo PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crie um PIN para modificar restrições"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não coincidem. Tente novamente."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é curto demais. Deve ter pelo menos 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorreto. Tente novamente em 1 segundo."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorreto. Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index cad9d1a..c3eb2e7 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -414,6 +414,10 @@
     <skip />
     <!-- no translation found for permdesc_removeTasks (1394714352062635493) -->
     <skip />
+    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
+    <skip />
+    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
+    <skip />
     <!-- no translation found for permlab_startAnyActivity (2918768238045206456) -->
     <skip />
     <!-- no translation found for permdesc_startAnyActivity (997823695343584001) -->
@@ -553,6 +557,18 @@
     <skip />
     <!-- no translation found for permdesc_bindAccessibilityService (7034615928609331368) -->
     <skip />
+    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
+    <skip />
+    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
+    <skip />
+    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
+    <skip />
+    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
+    <skip />
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <!-- no translation found for permlab_bindTextService (7358378401915287938) -->
     <skip />
     <!-- no translation found for permdesc_bindTextService (8151968910973998670) -->
@@ -571,6 +587,10 @@
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
     <!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
     <skip />
+    <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
+    <skip />
+    <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
+    <skip />
     <string name="permlab_setOrientation" msgid="3365947717163866844">"midar l\'orientaziun dal visur"</string>
     <!-- no translation found for permdesc_setOrientation (3046126619316671476) -->
     <skip />
@@ -745,13 +765,25 @@
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leger il paraculp da frame"</string>
     <!-- no translation found for permdesc_readFrameBuffer (4937405521809454680) -->
     <skip />
+    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
+    <skip />
+    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
+    <skip />
     <!-- no translation found for permlab_configureWifiDisplay (5595661694746742168) -->
     <skip />
     <!-- no translation found for permdesc_configureWifiDisplay (7916815158690218065) -->
     <skip />
-    <!-- no translation found for permlab_controlWifiDisplay (393641276723695496) -->
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
     <skip />
-    <!-- no translation found for permdesc_controlWifiDisplay (4543912292681826986) -->
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
     <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifitgar Voss parameters audio"</string>
     <!-- no translation found for permdesc_modifyAudioSettings (3522565366806248517) -->
@@ -1025,6 +1057,10 @@
     <skip />
     <!-- no translation found for permdesc_mediaStorageWrite (8189160597698529185) -->
     <skip />
+    <!-- no translation found for permlab_manageDocs (5778318598448849829) -->
+    <skip />
+    <!-- no translation found for permdesc_manageDocs (8704323176914121484) -->
+    <skip />
     <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
     <skip />
     <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
@@ -1048,6 +1084,10 @@
     <skip />
     <!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) -->
     <skip />
+    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+    <skip />
+    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+    <skip />
     <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
     <skip />
     <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
@@ -1056,6 +1096,10 @@
     <skip />
     <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
     <skip />
+    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
+    <skip />
+    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
+    <skip />
     <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
     <skip />
     <!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
@@ -1982,6 +2026,14 @@
     <skip />
     <!-- no translation found for permdesc_route_media_output (4932818749547244346) -->
     <skip />
+    <!-- no translation found for permlab_access_keyguard_secure_storage (7565552237977815047) -->
+    <skip />
+    <!-- no translation found for permdesc_access_keyguard_secure_storage (5866245484303285762) -->
+    <skip />
+    <!-- no translation found for permlab_control_keyguard (172195184207828387) -->
+    <skip />
+    <!-- no translation found for permdesc_control_keyguard (3043732290518629061) -->
+    <skip />
     <!-- no translation found for tutorial_double_tap_to_zoom_message_short (4070433208160063538) -->
     <skip />
     <!-- no translation found for gadget_host_error_inflating (4882004314906466162) -->
@@ -1994,8 +2046,8 @@
     <!-- no translation found for ime_action_previous (1443550039250105948) -->
     <skip />
     <string name="ime_action_default" msgid="2840921885558045721">"Exequir"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Cumponer il numer"\n"cun utilisar <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Agiuntar in contact"\n"cun il numer <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Cumponer il numer\ncun utilisar <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Agiuntar in contact\ncun il numer <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <!-- no translation found for grant_credentials_permission_message_header (2106103817937859662) -->
     <skip />
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vulais Vus autorisar questa dumonda?"</string>
@@ -2319,6 +2371,8 @@
     <skip />
     <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
     <skip />
+    <!-- no translation found for media_route_status_in_use (4533786031090198063) -->
+    <skip />
     <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
     <skip />
     <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
@@ -2327,6 +2381,8 @@
     <skip />
     <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <!-- no translation found for wifi_display_notification_title (2223050649240326557) -->
     <skip />
     <!-- no translation found for wifi_display_notification_message (4498802012464170685) -->
@@ -2424,10 +2480,108 @@
     <skip />
     <!-- no translation found for error_message_title (4510373083082500195) -->
     <skip />
-    <!-- no translation found for app_no_restricted_accounts (4011285085817350390) -->
+    <!-- no translation found for app_no_restricted_accounts (5739463249673727736) -->
     <skip />
     <!-- no translation found for app_not_found (3429141853498927379) -->
     <skip />
     <!-- no translation found for revoke (5404479185228271586) -->
     <skip />
+    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
+    <skip />
+    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
+    <skip />
+    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
+    <skip />
+    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
+    <skip />
+    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
+    <skip />
+    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
+    <skip />
+    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
+    <skip />
+    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
+    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 14f9644..6855a06 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite aplicaţiei să mute activităţile în prim-plan şi în fundal. Aplicaţia poate face acest lucru fără aportul dvs."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"oprire aplicaţii care rulează"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite aplicaţiei să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestionarea grupurilor de activități"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite aplicației să adauge, să elimine și să modifice grupuri de activități în care rulează alte aplicații. Aplicațiile rău-intenționate pot perturba comportamentul altor aplicații."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"începe orice activitate"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite aplicaţiei să înceapă orice activitate, indiferent de protecţia permisiunii şi de starea de export."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setaţi compatibilitatea ecranului"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei metode de introducere. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"conectare la un serviciu de accesibilitate"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu de accesibilitate. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"conectarea la un serviciu de printare"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de printare. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acces la toate procesele de printare"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite proprietarului să acceseze procesele de printare create de o altă aplicație. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"conectare la un serviciu text"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite proprietarului să se conecteze la o interfaţă de nivel superior a unui serviciu text (de ex., SpellCheckerService). Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"conectare la un serviciu VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adăugarea sau eliminarea unui administrator de dispozitiv"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite proprietarului să adauge sau să elimine administratorii activi ai dispozitivului. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite aplicaţiei să modifice rotaţia ecranului în orice moment. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"modifică viteza indicatorului"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite aplicaţiei să utilizeze funcţiile de nivel redus SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"citire zonă tampon de cadre"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite aplicaţiei să citească conţinutul zonei-tampon a cadrului."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acces la InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite aplicației să utilizeze funcțiile de nivel redus InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurează afişaje Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite aplicaţiei să configureze şi să se conecteze la afişaje Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlează afişaje Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite aplicaţiei să controleze funcţiile de nivel redus ale afişajelor Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicaţiei să modifice setările audio globale, cum ar fi volumul şi difuzorul care este utilizat pentru ieşire."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistrare audio"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicaţiei să scrie pe cardul SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./şterg. conţinutul media stocat intern"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite aplicaţiei să modifice conţinutul stocării media interne."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"gestionare stocare documente"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Permite aplicației să gestioneze stocarea documentelor."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acces. stoc. ext. pt. toţi utilizat."</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite aplicaţiei să acceseze stocarea externă pentru toţi utilizatorii."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accesare sistem de fişiere cache"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicaţiei să gestioneze politicile de reţea şi să definească regulile specifice aplicaţiilor."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării reţelei"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificarea mărcilor socketurilor"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite aplicației să modifice mărcile socketurilor pentru rutare."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Introduceţi un card SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Cardul SIM lipseşte sau nu poate fi citit. Introduceţi un card SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Card SIM inutilizabil."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Cardul dvs. SIM este dezactivat definitiv."\n" Contactaţi furnizorul de servicii wireless pentru a obţine un alt card SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Cardul dvs. SIM este dezactivat definitiv.\n Contactaţi furnizorul de servicii wireless pentru a obţine un alt card SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Butonul Melodia anterioară"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Butonul Melodia următoare"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Butonul Întrerupeţi"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultaţi Ghidul de utilizare sau contactaţi Serviciul de relaţii cu clienţii."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Cardul SIM este blocat."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Se deblochează cardul SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori."\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul datelor de conectare la Google."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul datelor de conectare la Google.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parolă"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Conectaţi-vă"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nume de utilizator sau parolă nevalide."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Aţi uitat numele de utilizator sau parola?"\n"Accesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Se verifică..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Deblocaţi"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sunet activat"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmați părăsirea paginii"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Părăsiți această pagină"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rămâneți în această pagină"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sigur doriți să părăsiți această pagină?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur doriți să părăsiți această pagină?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmaţi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi şi micşoraţi prin dublă atingere."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Din păcate, <xliff:g id="APPLICATION">%1$s</xliff:g> s-a oprit."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Din păcate, procesul <xliff:g id="PROCESS">%1$s</xliff:g> s-a oprit."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Aplicaţia <xliff:g id="APPLICATION">%2$s</xliff:g> nu răspunde."\n\n"Doriţi să o închideţi?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Activitatea <xliff:g id="ACTIVITY">%1$s</xliff:g> nu răspunde."\n\n"Doriţi să o închideţi?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Aplicaţia <xliff:g id="APPLICATION">%2$s</xliff:g> nu răspunde.\n\nDoriţi să o închideţi?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Activitatea <xliff:g id="ACTIVITY">%1$s</xliff:g> nu răspunde.\n\nDoriţi să o închideţi?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> nu răspunde. Doriţi să o închideţi?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde."\n\n"Doriţi să îl închideţi?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde.\n\nDoriţi să îl închideţi?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Raportaţi"</string>
     <string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă."\n\n"Doriţi să o închideţi?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriţi să o închideţi?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecţionată"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permite aplicaţiei să invoce serviciul containerului prestabilit pentru a copia conţinutul. Nu se utilizează de aplicaţiile obişnuite."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcţionează rezultatele media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicaţii să direcţioneze rezultate media către alte dispozitive externe."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Accesează stocarea securizată când tastatura este blocată"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite unei aplicații să acceseze stocarea securizată când tastatura este blocată."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Stabilește afișarea și ascunderea blocării tastaturii"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite unei aplicații să controleze blocarea tastaturii."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeţi de două ori pentru a mări/micşora"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nu s-a putut adăuga widgetul."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Accesaţi"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Terminat"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Înapoi"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Executaţi"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Formaţi numărul"\n"utilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Creaţi contactul"\n"utilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Formaţi numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Creaţi contactul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Următoarele aplicaţii solicită permisiunea de a accesa contul dvs. acum şi în viitor."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Permiteţi această solicitare?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitare de acces"</string>
     <string name="allow" msgid="7225948811296386551">"Permiteţi"</string>
     <string name="deny" msgid="2081879885755434506">"Refuzaţi"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permisiune solicitată"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permisiune solicitată"\n"pentru contul <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permisiune solicitată\npentru contul <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Metodă de intrare"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronizare"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilitate"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Se conectează..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponibilă"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Indisponibilă"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"În uz"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ecran încorporat"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Ecran HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Suprapunerea <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", securizat"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Ecranul wireless este conectat"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Acest ecran este afişat pe alt gadget"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Deconectaţi-vă"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greşită"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercaţi din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercaţi din nou peste <xliff:g id="NUMBER">%1$d</xliff:g> (de) secunde."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Conectaţi-vă"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?"\n"Accesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Se verifică contul…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori."\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ridicați volumul mai sus de nivelul recomandat?"\n"Ascultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ridicați volumul mai sus de nivelul recomandat?\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Menţineţi două degete pe ecran pentru a activa accesibilitatea."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilitatea a fost anulată"</string>
     <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietar"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Eroare"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Această aplicație nu acceptă conturi pentru profilurile cu permisiuni limitate"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Această aplicație nu acceptă conturi pentru profilurile cu permisiuni limitate"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nicio aplicație pentru gestionarea acestei acțiuni"</string>
     <string name="revoke" msgid="5404479185228271586">"Revocați"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Anulat"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Eroare la scrierea conținutului"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introduceți codul PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Codul PIN actual"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Codul PIN nou"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirmați noul cod PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Creați un cod PIN pentru modificarea restricțiilor"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Codurile PIN nu se potrivesc. Încercați din nou."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Codul PIN este prea scurt. Trebuie să aibă cel puțin 4 cifre."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorect. Reîncercați în 1 sec."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorect. Reîncercați în <xliff:g id="COUNT">%d</xliff:g> sec."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 81366f3..a5e316a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Приложение сможет переключать активный и фоновый режимы выполнения задач без вашего ведома."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Остановка работающих приложений"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Приложение сможет удалять задачи и собственные программы. Вредоносное ПО при этом сможет нарушать работу других приложений."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"Управление стеком действий"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Приложение сможет добавлять, удалять и изменять стек действий, в котором выполняются другие программы. Вредоносные программы смогут влиять на поведение других приложений."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Совершать любые действия"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Приложение сможет совершать любые действия независимо от наличия разрешений и состояния."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Установка режима совместимости"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Приложение сможет подключаться к базовому интерфейсу системы ввода. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"Подключение к службе специальных возможностей"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Приложение сможет подключаться к базовому интерфейсу службы специальных возможностей. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"Подключение к службе печати"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Приложение сможет подключаться к базовому интерфейсу службы печати. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"Доступ к заданиям печати"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Владелец сможет просматривать задания печати, созданные другими приложениями. Это разрешение не используется обычными приложениями."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"Подключение к службе текстовых сообщений"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Позволяет подключаться к базовому интерфейсу службы текстовых сообщений (например, SpellCheckerService). Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"Подключение к VPN-службе"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Добавление/удаление администратора устройства"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Владелец сможет добавлять и удалять администраторов устройства (используется лишь в некоторых приложениях)."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Изменение ориентации экрана"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Приложение сможет менять ориентацию экрана. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Изменение скорости указателя"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Приложение сможет использовать низкоуровневые функции SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Чтение данных в буфере кадров"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Приложение сможет считывать содержание буфера фреймов."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"Доступ к InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Приложение сможет использовать низкоуровневые функции InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"настраивать экраны, подключенные через Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Приложение сможет подключаться к экранам с помощью Wi-Fi и настраивать их."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Управление мониторами, подключенными через Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Приложение сможет управлять низкоуровневыми функциями экранов, подключенных через Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Изменение настроек аудио"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Приложение сможет изменять системные настройки звука, например уровень громкости и активный динамик."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"Запись аудио"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Приложение сможет записывать данные на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Доступ к данным мультимедиа"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Приложение сможет изменять контент внутреннего хранилища мультимедиа."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"управлять хранением документов"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Приложение сможет управлять хранением документов."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Доступ к внешним накопителям из всех аккаунтов"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Приложение сможет обращаться к внешним накопителям из всех аккаунтов."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Доступ к файловой системе кэша"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Приложение сможет управлять сетевыми политиками и определять правила для отдельных приложений."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Изменение учета использования сети"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"Изменение отметок сокетов"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Приложение сможет изменять отметки сокетов для маршрутизации."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"Доступ к уведомлениям"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Запуск приложения настроек, предоставленного оператором"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Вставьте SIM-карту."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта отсутствует или недоступна. Вставьте SIM-карту."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-карта непригодна к использованию."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-карта окончательно заблокирована."\n"Чтобы получить новую, обратитесь к своему оператору."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-карта окончательно заблокирована.\nЧтобы получить новую, обратитесь к своему оператору."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Кнопка перехода к предыдущему треку"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Кнопка перехода к следующему треку"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Кнопка паузы"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Ознакомьтесь с руководством пользователя или свяжитесь со службой поддержки."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблокирована"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблокировка SIM-карты…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. "\n\n"Повтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали пароль. "\n\n"Повтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. \n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали пароль. \n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <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_now_wiping" product="tablet" msgid="280873516493934365">"Вы <xliff:g id="NUMBER">%d</xliff:g> раз не смогли разблокировать планшетный ПК. Будут восстановлены заводские настройки."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Вход"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неверное имя пользователя или пароль."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забыли имя пользователя или пароль?"\n"Перейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забыли имя пользователя или пароль?\nПерейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Проверка…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Разблокировать"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Вкл. звук"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Подтверждение действия"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Покинуть"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Остаться"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Покинуть эту страницу?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nПокинуть эту страницу?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Совет: нажмите дважды, чтобы увеличить и уменьшить масштаб."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автозаполнение"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"В приложении \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" произошла ошибка."</string>
     <string name="aerr_process" msgid="4507058997035697579">"В приложении \"<xliff:g id="PROCESS">%1$s</xliff:g>\" произошла ошибка."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Приложение \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" не отвечает."\n\n"Закрыть его?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Приложение \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" не отвечает."\n\n"Закрыть его?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Приложение \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" не отвечает.\n\nЗакрыть его?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Приложение \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" не отвечает.\n\nЗакрыть его?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" не отвечает. Закрыть его?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Приложение \"<xliff:g id="PROCESS">%1$s</xliff:g>\" не отвечает."\n\n"Закрыть его?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Приложение \"<xliff:g id="PROCESS">%1$s</xliff:g>\" не отвечает.\n\nЗакрыть его?"</string>
     <string name="force_close" msgid="8346072094521265605">"ОК"</string>
     <string name="report" msgid="4060218260984795706">"Отзыв"</string>
     <string name="wait" msgid="7147118217226317732">"Подождать"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает."\n\n"Закрыть ее?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает.\n\nЗакрыть ее?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Приложение перенаправлено"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Изначально было запущено приложение <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Приложение сможет вызывать службу контейнеров по умолчанию для копирования данных. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Перенаправление мультимедийных данных"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Приложение сможет направлять поток мультимедиа на другие внешние устройства."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Доступ к хранилищу ключей"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Приложение сможет получить доступ к хранилищу ключей."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Управлять отображением хранилища ключей"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Приложение сможет управлять хранилищем ключей."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Нажмите дважды для изменения масштаба"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Не удалось добавить виджет."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Выбрать"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Готово"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Пред."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Выполнить"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Набрать номер"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Создать контакт"\n"с номером <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Набрать номер\n<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Создать контакт\nс номером <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Одному или нескольким приложениям требуется разрешение на доступ к вашему аккаунту сейчас и в дальнейшем."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Разрешить доступ?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Запрос доступа"</string>
     <string name="allow" msgid="7225948811296386551">"Разрешить"</string>
     <string name="deny" msgid="2081879885755434506">"Отклонить"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Разрешение запрошено"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Требуется разрешение"\n"для аккаунта <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Требуется разрешение\nдля аккаунта <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Способ ввода"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Синхр."</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Спец. возможности"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Подключение..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Доступен"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Недоступные"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Используется"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Встроенный экран"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Экран HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наложение № <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> х <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> тчк/дюйм"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Беспроводной проектор подключен"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Изображение передается на другое устройство"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Отключить"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильный графический ключ"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Неправильный пароль"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Неправильный PIN-код"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторите попытку через <xliff:g id="NUMBER">%1$d</xliff:g> сек."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Введите графический ключ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введите PIN-код SIM-карты"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Введите PIN"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Войти"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неверное имя пользователя или пароль."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыли имя пользователя или пароль?"\n"Перейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыли имя пользователя или пароль?\nПерейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Проверка данных…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. "\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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. \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_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> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google."\n\n"Повтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <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="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> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <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="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Удалить"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Увеличить громкость до небезопасного уровня?"\n"Долговременное прослушивание на такой громкости может повредить слух."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Увеличить громкость до небезопасного уровня?\nДолговременное прослушивание на такой громкости может повредить слух."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Чтобы включить специальные возможности, удерживайте пальцы на экране."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Специальные возможности включены."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Специальные возможности не будут включены."</string>
     <string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Владелец"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Ошибка"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Это приложение не поддерживается в аккаунтах для профилей с ограниченным доступом"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Это приложение не поддерживается в аккаунтах для профилей с ограниченным доступом"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Невозможно обработать это действие"</string>
     <string name="revoke" msgid="5404479185228271586">"Отменить"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter (216 х 279 мм)"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter (203 х 267 мм)"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal (216 х 356 мм)"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal (203 х 127 мм)"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger (432 х 279 мм)"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid (279 х 432 мм)"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Печать отменена"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Ошибка записи"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Введите PIN-код"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Текущий PIN-код"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Новый PIN-код"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Введите новый PIN-код ещё раз"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Создайте PIN-код для изменения ограничений."</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коды не совпадают. Повторите попытку."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код должен содержать не менее 4 символов."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Неверный PIN-код. Повторите попытку через 1 сек."</item>
+    <item quantity="other" msgid="8030607343223287654">"Неверный PIN-код. Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index b7dcd07..f4e2157 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Umožňuje aplikácii presunúť úlohy do popredia alebo do pozadia. Aplikácia tak môže urobiť bez vášho zásahu."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"spravovanie zoskupení aktivít"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Umožňuje aplikácii pridať, odstrániť alebo upraviť zoskupenia aktivít, v ktorých sú spustené ostatné aplikácie. Škodlivé aplikácie môžu narušiť správanie ostatných aplikácií."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"spustiť ľubovoľnú aktivitu"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Umožňuje aplikácii spustiť ľubovoľnú aktivitu bez ohľadu na ochranu povolení alebo exportovaný stav."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastaviť kompatibilitu obrazovky"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania metódy vstupu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"viazať na službu zjednodušeného ovládania"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby zjednodušeného ovládania. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"viazanie na tlačovú službu"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tlačovej služby. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"prístup ku všetkým tlačovým úlohám"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Umožňuje držiteľovi prístup k tlačovým úlohám vytvoreným inou aplikáciou. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"previazať so službou NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Umožňuje držiteľovi previazať sa s aplikáciami, ktoré vydávajú karty NFC. Bežné aplikácie toto povolenie nikdy nepotrebujú."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"väzba na textovú službu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania textovej služby (napr. SpellCheckerService). Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"Zaviazať k službe VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridanie alebo odstránenie správcu zariadenia"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umožňuje držiteľovi pridať alebo odstrániť správcov aktívnych zariadení. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Umožňuje aplikácii kedykoľvek zmeniť otáčanie obrazovky. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"zmena rýchlosti ukazovateľa"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čítanie vyrovnávacej pamäte snímok"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Umožňuje aplikácii čítať obsah vyrovnávacej pamäte snímok."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"prístup k aplikácii InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurovať displeje cez sieť Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Umožňuje aplikácii konfigurovať displeje a pripojiť sa k nim cez siete Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládať displeje cez sieť Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Umožňuje aplikácii ovládať základné funkcie displejov cez siete Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmeny vašich nastavení zvuku"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Umožňuje aplikácii upraviť globálne nastavenia zvuku, ako je hlasitosť, alebo určiť, z ktorého reproduktora bude zvuk vychádzať."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"záznam zvuku"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Umožňuje aplikácii zápis na kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"úprava alebo odstránenie obsahu interného ukladacieho priestoru média"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Umožňuje aplikácii zmeniť obsah interného ukladacieho priestoru média."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"správa ukladacieho priestoru dokumentov"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Umožňuje aplikácii spravovať ukladací priestor dokumentov."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"pristupovať k externému ukladaciemu priestoru pre všetkých používateľov"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Umožňuje aplikácii pristupovať k externému ukladaciemu priestoru pre všetkých používateľov."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pristupovať do súborového systému vyrovnávacej pamäte"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikácii spravovať pravidlá siete a definovať pravidlá pre konkrétnu aplikáciu."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"zmeniť kontrolu používania siete"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"upravenie značiek soketov"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Umožňuje aplikácii upraviť značky soketov pre smerovanie"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolanie aplikácie pre konfiguráciu poskytnutú operátorom"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Vložte kartu SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Karta SIM chýba alebo sa z nej nedá čítať. Vložte kartu SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Karta SIM je nepoužiteľná."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaša karta SIM bola natrvalo zakázaná."\n"Ak chcete získať inú kartu SIM, kontaktujte svojho operátora."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaša karta SIM bola natrvalo zakázaná.\nAk chcete získať inú kartu SIM, kontaktujte svojho operátora."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Tlačidlo Predchádzajúca stopa"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Tlačidlo Ďalšia stopa"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Tlačidlo Pozastaviť"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Prečítajte si Príručku používateľa alebo kontaktujte podporu zákazníka."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Karta SIM je uzamknutá."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Prebieha odomykanie karty SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších neúspešných pokusoch (<xliff:g id="NUMBER_1">%d</xliff:g>) budete vyzvaní odomknúť tablet pomocou prihlasovacích údajov služby Google."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou prihlasovacích údajov Google."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších neúspešných pokusoch (<xliff:g id="NUMBER_1">%d</xliff:g>) budete vyzvaní odomknúť tablet pomocou prihlasovacích údajov služby Google.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou prihlasovacích údajov Google.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v tablete obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v telefóne obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V tablete sa teraz obnovia predvolené továrenské nastavenia."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Heslo"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Prihlásiť sa"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Neplatné používateľské meno alebo heslo."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zabudli ste používateľské meno alebo heslo?"\n"Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zabudli ste používateľské meno alebo heslo?\nNavštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Prebieha kontrola…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Odomknúť"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Zapnúť zvuk"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potvrďte prechod"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Opustiť stránku"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Zostať na tejto strane"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Naozaj chcete túto stránku opustiť?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nNaozaj chcete túto stránku opustiť?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdiť"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím môžete zobrazenie priblížiť alebo oddialiť."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.dop."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> bohužiaľ prestala pracovať."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> bohužiaľ prestal pracovať."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikácia <xliff:g id="APPLICATION">%2$s</xliff:g> neodpovedá."\n\n"Chcete ju zavrieť?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivita <xliff:g id="ACTIVITY">%1$s</xliff:g> neodpovedá."\n\n"Chcete ju zavrieť?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikácia <xliff:g id="APPLICATION">%2$s</xliff:g> neodpovedá.\n\nChcete ju zavrieť?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivita <xliff:g id="ACTIVITY">%1$s</xliff:g> neodpovedá.\n\nChcete ju zavrieť?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> neodpovedá. Chcete ju zavrieť?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovedá. "\n\n"Chcete ho zavrieť?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovedá. \n\nChcete ho zavrieť?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Prehľad"</string>
     <string name="wait" msgid="7147118217226317732">"Čakajte"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje."\n\n"Chcete ju zavrieť?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje.\n\nChcete ju zavrieť?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Presmerovaná aplikácia"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Je spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Pôvodne bola spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Umožňuje volať predvolenú službu kontajnera na skopírovanie obsahu. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Smerovanie výstupu médií"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Umožňuje aplikácii smerovať výstup médií do ďalších externých zariadení."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Prístup k ukladaciemu priestoru zabezpečenému technológiou keyguard"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Umožňuje aplikácii získať prístup k ukladaciemu priestoru zabezpečenému technológiou keyguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Ovládanie zobrazenia alebo skrytia technológie keyguard"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikácii ovládať technológiu keyguard."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ovládacie prvky lupy zobrazíte dvojitým dotknutím"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Miniaplikáciu sa nepodarilo pridať."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Hľadať"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Hotovo"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Predch."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Vykonať"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Vytočiť číslo"\n" <xliff:g id="NUMBER">%s</xliff:g>."</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Vytvoriť kontakt"\n"pre <xliff:g id="NUMBER">%s</xliff:g>."</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Vytočiť číslo\n <xliff:g id="NUMBER">%s</xliff:g>."</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Vytvoriť kontakt\npre <xliff:g id="NUMBER">%s</xliff:g>."</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Nasledujúce aplikácie vyžadujú povolenie na prístup do vášho účtu (teraz aj v budúcnosti)."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Chcete túto žiadosť povoliť?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Žiadosť o prístup"</string>
     <string name="allow" msgid="7225948811296386551">"Povoliť"</string>
     <string name="deny" msgid="2081879885755434506">"Zamietnuť"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Vyžaduje sa povolenie"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Vyžaduje sa oprávnenie"\n"pre účet <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Vyžaduje sa oprávnenie\npre účet <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Metóda vstupu"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronizovať"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Zjednodušenie"</string>
@@ -1441,10 +1472,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Prebieha pripájanie…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"K dispozícii"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Nie je k dispozícii"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Používa sa"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Vstavaná obrazovka"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Obrazovka HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezdrôtový displej je pripojený"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Táto obrazovka sa zobrazuje na inom zariadení"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojiť"</string>
@@ -1453,7 +1487,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávny vzor"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nesprávne heslo"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Nesprávny kód PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Skúste to znova o <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Skúste to znova o <xliff:g id="NUMBER">%1$d</xliff:g> s."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Nakreslite svoj vzor"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadajte kód PIN karty SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Zadajte kód PIN"</string>
@@ -1473,27 +1507,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Prihlásiť sa"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné používateľské meno alebo heslo."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zabudli ste svoje používateľské meno alebo heslo?"\n" Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zabudli ste svoje používateľské meno alebo heslo?\n Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Prebieha kontrola účtu..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. "\n\n"Skúste to znova o <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>-krát ste použili nesprávny bezpečnostný vzor. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <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>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v tablete obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v telefóne obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V tablete sa teraz obnovia predvolené továrenské nastavenia."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V telefóne sa teraz obnovia predvolené továrenské nastavenia."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrániť"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Zvýšiť hlasitosť nad odporúčanú úroveň?"\n"Dlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Zvýšiť hlasitosť nad odporúčanú úroveň?\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Zjednodušenie ovládania povolíte dlhým stlačením dvoma prstami."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Zjednodušenie ovládania je povolené."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Zjednodušenie ovládania bolo zrušené."</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Vlastník"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Chyba"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Táto aplikácia nepodporuje účty pre profily s obmedzením"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Táto aplikácia nepodporuje účty pre profily s obmedzením"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Aplikácia potrebná na spracovanie tejto akcie sa nenašla"</string>
     <string name="revoke" msgid="5404479185228271586">"Odvolať"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Zrušené"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Pri zapisovaní obsahu došlo ku chybe"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Zadajte kód PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Aktuálny kód PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nový kód PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrďte nový kód PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvoriť kód PIN pre obmedzenia upravovania"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN sa nezhodujú. Skúste to znova."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je príliš krátky. Musí mať minimálne 4 číslice."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Nespr. PIN. Skús. o 1 s"</item>
+    <item quantity="other" msgid="8030607343223287654">"Nespr. PIN. Skús. o <xliff:g id="COUNT">%d</xliff:g> s"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 11dc13d..c90392d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Aplikaciji omogoča premikanje opravil v ospredje in ozadje. Aplikacija lahko to naredi brez vašega nadzora."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"upravljanje skladov dejavnosti"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Aplikaciji omogoča dodajanje, odstranjevanje in spreminjanje skladov dejavnosti, v katerih se izvajajo druge aplikacije. Zlonamerne aplikacije lahko motijo delovanje drugih aplikacij."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"zagon poljubne dejavnosti"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Omogoča aplikaciji zagon poljubne dejavnosti, ne glede na zaščito dovoljenj ali izvoženo stanje."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavitev združljivosti zaslona"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lastniku omogoča, da se poveže z vmesnikom načina vnosa najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"povezovanje s storitvijo za ljudi s posebnimi potrebami"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lastniku omogoča povezovanje z vmesnikom najvišje ravni storitve za ljudi s posebnimi potrebami. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"povezava s storitvijo tiskanja"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Lastniku omogoča povezovanje z vmesnikom storitve tiskanja najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"dostop do vseh tiskalnih poslov"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Lastniku omogoča dostop do tiskalnih poslov, ki jih je ustvarila druga aplikacija. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"povezava s storitvijo NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Dovoljuje, da se lastnik poveže z aplikacijami, ki posnemajo kartice za NFC. Pri navadnih aplikacijah to ne bi smelo biti potrebno."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"poveži z besedilno storitvijo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dovoljuje, da se lastnik poveže z vmesnikom besedilne storitve najvišje ravni (npr. SpellCheckerService). Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"povezava s storitvijo navideznega zasebnega omrežja"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodajanje ali odstranjevanje skrbnikov naprave"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Imetniku omogoča, da doda ali odstrani aktivne skrbnike naprave. Normalne aplikacije tega načeloma ne potrebujejo."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Programu omogoča, da kadar koli zasuka zaslon. Ne uporabljajte za navadne programe."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"spreminjanje hitrosti kazalca"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Programu omogoča uporabo funkcij nizke ravni SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"branje grafičnega/slikovnega medpomnilnika"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Programu omogoča branje vsebine grafičnega/slikovnega medpomnilnika."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"dostop do funkcij InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Aplikaciji dovoljuje uporabo funkcij InputFlinger nizke ravni."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfiguriranje zaslonov Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogoča aplikaciji konfiguriranje zaslonov Wi-Fi in povezovanje z njimi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"nadzor zaslonov Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogoča aplikaciji nadzor osnovnih funkcij zaslonov Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"spreminjanje nastavitev zvoka"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Aplikaciji omogoča spreminjanje splošnih zvočnih nastavitev, na primer glasnost in kateri zvočnik se uporablja."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"snemanje zvoka"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Programu omogoča pisanje na kartico SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"spreminjanje/brisanje vsebine notranje shrambe nosilca podatkov"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Programu omogoča spreminjanje vsebine notranje shrambe nosilca podatkov."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"upravljanje shranjevanja dokumentov"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Aplikaciji omogoči upravljanje shranjevanja dokumentov."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"dostop do zunanje naprave za shranjevanje za vse uporabnike"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Aplikaciji omogoča dostop do zunanje naprave za shranjevanje za vse uporabnike."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostop do datotečnega sistema predpomnilnika"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"spreminjanje oznak vtičnic"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Aplikaciji omogoča spreminjanje oznak vtičnic za usmerjanje"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lastniku omogoča povezovanje z vmesnikom storitve poslušalca obvestil najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"sprožitev operaterjeve aplikacije za konfiguracijo"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Vstavite kartico SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Ni kartice SIM ali je ni mogoče prebrati. Vstavite kartico SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Neuporabna kartica SIM."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Kartica SIM je trajno onemogočena."\n" Če želite dobiti drugo kartico SIM, se obrnite na ponudnika brezžičnih storitev."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Kartica SIM je trajno onemogočena.\n Če želite dobiti drugo kartico SIM, se obrnite na ponudnika brezžičnih storitev."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Gumb za prejšnjo skladbo"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Gumb za naslednjo skladbo"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Gumb »Premor«"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Preberite uporabniški priročnik ali se obrnite na oddelek za skrb za stranke."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Kartica SIM je zaklenjena."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odklepanje kartice SIM ..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. "\n\n"Poskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. "\n\n"Znova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. "\n\n"Znova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Vzorec za odklepanje ste nepravilno vnesli <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Po <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete tablični računalnik z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Vzorec za odklepanje ste nepravilno vnesli <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Po <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Vzorec za odklepanje ste nepravilno vnesli <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Po <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete tablični računalnik z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Vzorec za odklepanje ste nepravilno vnesli <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Po <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Tablični računalnik ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat nepravilno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve, vsi uporabniški podatki pa bodo izbrisani."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Telefon ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat nepravilno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve, vsi uporabniški podatki pa bodo izgubljeni."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tablični računalnik ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat nepravilno odkleniti, zato bo zdaj ponastavljen na privzete tovarniške nastavitve."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Geslo"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Prijava"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Neveljavno uporabniško ime ali geslo."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ali ste pozabili uporabniško ime ali geslo?"\n"Obiščite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ali ste pozabili uporabniško ime ali geslo?\nObiščite "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Preverjanje ..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Odkleni"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Vklopi zvok"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potrditev krmarjenja"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Zapusti to stran"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Ostani na tej strani"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ali res želite zapustiti to stran?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nAli res želite zapustiti to stran?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Potrdi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Nasvet: Tapnite dvakrat, če želite povečati ali pomanjšati."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Samoizp."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Žal se je program <xliff:g id="APPLICATION">%1$s</xliff:g> ustavil."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Žal se je postopek <xliff:g id="PROCESS">%1$s</xliff:g> ustavil."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Program <xliff:g id="APPLICATION">%2$s</xliff:g> se ne odziva."\n\n"Ali ga želite zapreti?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Dejavnost <xliff:g id="ACTIVITY">%1$s</xliff:g> se ne odziva."\n\n"Ali jo želite zapreti?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Program <xliff:g id="APPLICATION">%2$s</xliff:g> se ne odziva.\n\nAli ga želite zapreti?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Dejavnost <xliff:g id="ACTIVITY">%1$s</xliff:g> se ne odziva.\n\nAli jo želite zapreti?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Program <xliff:g id="APPLICATION">%1$s</xliff:g> se ne odziva. Ali ga želite zapreti?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> se ne odziva."\n\n"Ali ga želite zapreti?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> se ne odziva.\n\nAli ga želite zapreti?"</string>
     <string name="force_close" msgid="8346072094521265605">"V redu"</string>
     <string name="report" msgid="4060218260984795706">"Poročaj"</string>
     <string name="wait" msgid="7147118217226317732">"Čakaj"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stran se ne odziva."\n" "\n"Ali jo želite zapreti?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stran se ne odziva.\n \nAli jo želite zapreti?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Program preusmerjen"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Prvotno je bil zagnan program <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Programu omogoča pozivanje privzete storitve vsebnika, da kopira vsebino. Ni za uporabo z navadnimi programi."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Preusmeritev predstavnosti"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Aplikaciji omogoča preusmerjanje predstavnosti v druge zunanje naprave."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Dostop do varne shrambe Keyguard."</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Aplikaciji omogoča dostop do varne shrambe Keyguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Nadzira prikaz in skrivanje zaklepanja tipkovnice"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Aplikaciji omogoča nadzor zaklepanja tipkovnice."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dvakrat se dotaknite za nadzor povečave/pomanjšave"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Pripomočka ni bilo mogoče dodati."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pojdi"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Dokončano"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Nazaj"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Izvedi"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Pokliči številko"\n"s številko <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Ustvari stik"\n"s številko <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Pokliči številko\ns številko <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Ustvari stik\ns številko <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Ti programi zahtevajo dovoljenje za dostop do računa zdaj in v prihodnje."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ali želite to zahtevo dovoliti?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zahteva za dostop"</string>
     <string name="allow" msgid="7225948811296386551">"Dovoli"</string>
     <string name="deny" msgid="2081879885755434506">"Zavrni"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Zahtevano je dovoljenje"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Zahtevano je dovoljenje"\n"za račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Zahtevano je dovoljenje\nza račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Način vnosa"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sinhronizacija"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Pripomočki za osebe s posebnimi potrebami"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Vzpostavljanje povezave ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Na voljo"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ni na voljo"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"V uporabi"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Vgrajen zaslon"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Zaslon HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrivanje #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> pik na palec"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", varen"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Brezžični zaslon je povezan"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ta zaslon je prikazan v drugi napravi"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Prekini povezavo"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Napačen vzorec"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Napačno geslo"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Napačen PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Čez <xliff:g id="NUMBER">%d</xliff:g> sekund poskusite znova."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Čez <xliff:g id="NUMBER">%1$d</xliff:g> sekund poskusite znova."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Narišite vzorec"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Vnesite PIN za kartico SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Vnesite PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Geslo"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neveljavno uporabniško ime ali geslo."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ali ste pozabili uporabniško ime ali geslo?"\n"Obiščite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ali ste pozabili uporabniško ime ali geslo?\nObiščite "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Preverjanje računa ..."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. "\n\n"Znova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. "\n\n"Znova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. "\n\n"Poskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablični računalnik ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve in vsi uporabniški podatki bodo izgubljeni."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefon ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve in vsi uporabniški podatki bodo izgubljeni."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablični računalnik ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat napačno odkleniti, zato bo ponastavljen na privzete tovarniške nastavitve."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat napačno odkleniti, zato bo ponastavljen na privzete tovarniške nastavitve."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Želite povečati glasnost nad varno raven?"\n"Dolgotrajna izpostavljenost glasnemu predvajanju lahko poškoduje sluh."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Želite povečati glasnost nad varno raven?\nDolgotrajna izpostavljenost glasnemu predvajanju lahko poškoduje sluh."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Če želite omogočiti pripomočke za ljudi s posebnimi potrebami, na zaslonu pridržite z dvema prstoma."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pripomočki za ljudi s posebnimi potrebami so omogočeni."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Omogočanje pripomočkov za ljudi s posebnimi potrebami preklicano."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Lastnik"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Napaka"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ta aplikacija ne podpira računov za profile z omejitvami"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ta aplikacija ne podpira računov za profile z omejitvami"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Najdena ni bila nobena aplikacija za izvedbo tega dejanja"</string>
     <string name="revoke" msgid="5404479185228271586">"Prekliči"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Preklicano"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Napaka pri pisanju vsebine"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Vnesite PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Trenutni PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potrdite novi PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Ustvarite PIN za spreminjanje omejitev"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kodi PIN se ne ujemata. Poskusite znova."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratek. Imeti mora vsaj 4 števke."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Napačen PIN. Poskusite znova čez eno sekundo."</item>
+    <item quantity="other" msgid="8030607343223287654">"Napačen PIN. Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d0ebddd..a33e129 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дозвољава апликацији да премешта задатке у први план и у позадину. Апликација може да ради ово без вашег уноса."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"управљање групама активности"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Дозвољава апликацији да додаје, уклања и мења групе активности у којима се покрећу друге апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"покретање било које активности"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Омогућава да апликација покрене било коју активност, без обзира на заштиту дозволе или стање извоза."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"подешавање компатибилности екрана"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Омогућава да се власник обавеже на интерфејс методе уноса највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"повезивање са услугом приступачности"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозвољава власнику да се повеже са интерфејсом услуге приступачности највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"повезивање са услугом штампања"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Дозвољава власнику да се повеже са интерфејсом услуге штампања највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"приступ свим задацима за штампање"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Дозвољава власнику да приступа задацима за штампање које је направила друга апликација. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"повезивање са NFC услугом"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Дозвољава власнику да се повеже са апликацијама које опонашају NFC картице. Никада не би требало да буде потребно за обичне апликације."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"обавезивање на текстуалну услугу"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Омогућава власнику да се обавеже на интерфејс текстуалне услуге највишег нивоа (нпр. SpellCheckerService). Обичне апликације никада не би требало да је користе."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"везивање за VPN услугу"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавање или уклањање администратора уређаја"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозвољава власнику да додаје или уклања активне администраторе уређаја. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дозвољава апликацији да у сваком тренутку промени ротацију екрана. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"промена брзине показивача"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дозвољава апликацији да користи SurfaceFlinger функције ниског нивоа."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"читање бафера кадрова"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дозвољава апликацији да чита садржај међумеморије кадрова."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"приступ InputFlinger функцијама"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Дозвољава апликацији да користи InputFlinger функције ниског нивоа."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"конфигурисање Wi-Fi екрана"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозвољава апликацији да конфигурише Wi-Fi екране и повезује се са њима."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контрола Wi-Fi екрана"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозвољава апликацији да контролише функције Wi-Fi екрана ниског нивоа."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"промена аудио подешавања"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дозвољава апликацији да мења глобална аудио подешавања као што су јачина звука и избор звучника који се користи као излаз."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"снимање аудио записа"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозвољава апликацији да уписује податке на SD картицу."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"измена/брисање интерне меморије медија"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дозвољава апликацији да мења садржај интерне меморије медијума."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"управ. складиштењем докумената"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Дозвољава апликацији да управља складиштењем докумената."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"приступ спољној меморији свих корисника"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Дозвољава апликацији да приступа спољној меморији за све кориснике."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"приступ систему датотека кеша"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозвољава апликацији да управља смерницама за мрежу и одређује посебна правила за апликацију."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"измените обрачунавање коришћења мреже"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"измена ознака утичнице"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Дозвољава апликацији да мења ознаке утичнице за усмеравање"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Уметните SIM картицу."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM недостаје или не може да се прочита. Уметните SIM картицу."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM картица је неупотребљива."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM картица је трајно онемогућена."\n" Обратите се добављачу услуге бежичне мреже да бисте добили другу SIM картицу."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM картица је трајно онемогућена.\n Обратите се добављачу услуге бежичне мреже да бисте добили другу SIM картицу."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Дугме за претходну песму"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Дугме за следећу песму"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Дугме за паузу"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Погледајте Кориснички водич или контактирајте Корисничку подршку."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM картица је закључана."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Откључавање SIM картице…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. "\n\n"Покушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте погрешно унели лозинку. "\n\n"Покушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
-    <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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте погрешно унели лозинку. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
+    <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_now_wiping" product="tablet" msgid="280873516493934365">"Неисправно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Лозинка"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Пријави ме"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неважеће корисничко име или лозинка."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Заборавили сте корисничко име или лозинку?"\n"Посетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Проверавање..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Откључај"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Укључи звук"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Потврда навигације"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Напусти ову страницу"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Остани на овој страници"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Да ли стварно желите да напустите ову страницу?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nДа ли стварно желите да напустите ову страницу?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Потврда"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Савет: Додирните двапут да бисте увећали и умањили приказ."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Аутом. поп."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Нажалост, апликација <xliff:g id="APPLICATION">%1$s</xliff:g> је престала с радом."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Нажалост, процес <xliff:g id="PROCESS">%1$s</xliff:g> је заустављен."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> не реагује."\n\n"Да ли желите да је затворите?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Активност <xliff:g id="ACTIVITY">%1$s</xliff:g> не рeагује."\n\n"Да ли желите да је затворите?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> не реагује.\n\nДа ли желите да је затворите?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Активност <xliff:g id="ACTIVITY">%1$s</xliff:g> не рeагује.\n\nДа ли желите да је затворите?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> не реагује. Да ли желите да је затворите?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> не раегује."\n\n"Да ли желите да га затворите?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> не раегује.\n\nДа ли желите да га затворите?"</string>
     <string name="force_close" msgid="8346072094521265605">"Потврди"</string>
     <string name="report" msgid="4060218260984795706">"Пријави"</string>
     <string name="wait" msgid="7147118217226317732">"Сачекај"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница је престала да се одазива."\n\n" Да ли желите да је затворите?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница је престала да се одазива.\n\n Да ли желите да је затворите?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Апликација је преусмерена"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је сада покренута."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Првобитно је покренута апликација <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дозвољава апликацији да од подразумеване услуге контејнера захтева да копира садржај. Не користе је уобичајене апликације."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Усмеравање излаза медија"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Дозвољава апликацији да усмерава излаз медија на друге спољне уређаје."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Приступај безбедној меморији заштићеној шифром"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дозвољава апликацији да приступа безбедној меморији заштићеној шифром."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Контролиши приказивање и скривање заштите шифром"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозвољава апликацији да контролише заштиту шифром."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Додирните двапут да бисте контролисали зум"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Није могуће додати виџет."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Иди"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Готово"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Претходно"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Изврши"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Бирај број"\n"користећи <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Креирајте контакт"\n"користећи <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Бирај број\nкористећи <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Креирајте контакт\nкористећи <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Следеће апликације захтевају дозволу за приступ налогу, како сада, тако и убудуће."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Желите да одобрите овај захтев?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Захтев за приступ"</string>
     <string name="allow" msgid="7225948811296386551">"Дозволи"</string>
     <string name="deny" msgid="2081879885755434506">"Одбиј"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Затражена је дозвола"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Затражена је дозвола"\n"за налог <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Затражена је дозвола\nза налог <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Метод уноса"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Синхронизација"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Приступачност"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Повезивање..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Доступна"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Нису доступне"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"У употреби"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Уграђени екран"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI екран"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Постављени елемент бр. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>×<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безбедно"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Бежични екран је повезан"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Овај екран се приказује на другом уређају"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Прекини везу"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Унесите PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?"\n"Посетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Провера налога…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте 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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Желите ли да појачате звук преко препорученог нивоа?"\n"Ако слушате гласну музику током дужег периода, може да дође до оштећења слуха."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Желите ли да појачате звук преко препорученог нивоа?\nАко слушате гласну музику током дужег периода, може да дође до оштећења слуха."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Држите са два прста да бисте омогућили приступачност."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Приступачност је омогућена."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Приступачност је отказана."</string>
     <string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Власник"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Грешка"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ова апликација не подржава налоге за ограничене профиле"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ова апликација не подржава налоге за ограничене профиле"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Није пронађена ниједна апликација која би могла да обави ову радњу"</string>
     <string name="revoke" msgid="5404479185228271586">"Опозови"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Отказано је"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Грешка при исписивању садржаја"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Унесите PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Актуелни PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Нови PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Потврдите нови PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Нетачан PIN. Покушајте опет за 1 сек."</item>
+    <item quantity="other" msgid="8030607343223287654">"Нетачан PIN. Покушајте опет за <xliff:g id="COUNT">%d</xliff:g> сек."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 80ab2ae..aaa6b36 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Tillåter att appen flyttar aktiviteter till förgrunden eller bakgrunden. Appen kan göra detta utan åtgärd från dig."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"avsluta appar som körs"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillåter att appen tar bort uppgifter och avslutar appar. Skadliga appar kan störa funktionen i andra appar."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"hantera aktivitetsstaplar"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Appen tillåts att lägga till, ta bort och ändra aktivitetsstaplar som andra appar körs i. Skadliga appar kan störa funktionerna i andra appar."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"starta alla aktiviteter"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Appen tillåts starta alla aktiviteter oavsett behörighetsskydd eller exportstatus."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ange skärmkompatibilitet"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind till en tillgänglighetstjänst"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en tillgänglighetstjänst. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"binda till en utskriftstjänst"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en utskriftstjänst. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"få tillgång till alla utskriftsjobb"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ger innehavaren tillgång till utskriftsjobb som skapas med en annan app. Ska inte behövas för normala appar."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"låsa till NFC-tjänsten"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Innehavaren får låsa appar som fungerar som NFC-kort. Behövs normalt inte för vanliga appar."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind till en texttjänst"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillåter innehavaren att binda mot den högsta gränssnittsnivån i en texttjänst (t.ex. SpellCheckerService). Bör aldrig behövas för normala appar."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind till en VPN-tjänst"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lägga till eller ta bort en enhetsadministratör"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Innehavaren får lägga till eller ta bort aktiva enhetsadministratörer. Detta ska normalt inte behövas för vanliga appar."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Gör att appen när som helst kan ändra skärmläget. Behövs inte för vanliga appar."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ändra markörens hastighet"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Tillåter att appen använder lågnivåfunktioner i SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"läsa rambuffert"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Tillåter att appen läser innehållet i rambufferten."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"få tillgång till InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Tillåter att appen använder lågnivåfunktioner i InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurerar Wi-Fi-skärmar"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillåter att appen konfigurerar och ansluter till Wi-Fi-skärmar."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollerar Wi-Fi-skärmar"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillåter att appen kontrollerar grundläggande funktioner för Wi-Fi-skärmar."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ändra dina ljudinställningar"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Tillåter att appen ändrar globala ljudinställningar som volym och vilken högtalarutgång som används."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"spela in ljud"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillåter att appen skriver till SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ändra/ta bort innehåll"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Tillåter att appen ändrar innehållet på den interna lagringsenheten."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"hantera dokumentlagring"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Tillåter att appen hanterar dokumentlagring."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"åtkomst till lagringsutrymme"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Tillåter att appen får åtkomst till en extern lagringsenhet för alla användare."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"åtkomst till cachefilsystemet"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillåter att appen hanterar nätverkspolicyer och definierar appspecifika regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ändra nätverksredovisningen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"ändra socketmarkeringar"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Appen tillåts att ändra socketmarkeringar för routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en meddelandelyssnare. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"anropa konfigurationsappen från operatören"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Innehavaren tillåts att anropa konfigurationsappen från operatören. Ska inte behövas för vanliga appar."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Sätt i ett SIM-kort."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-kort saknas eller kan inte läsas. Sätt i ett SIM-kort."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Oanvändbart SIM-kort."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kortet har inaktiverats permanent."\n" Beställ ett nytt SIM-kort från din operatör."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM-kortet har inaktiverats permanent.\n Beställ ett nytt SIM-kort från din operatör."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Knapp för föregående spår"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Knapp för nästa spår"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Pausknappen"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Se användarhandboken eller kontakta kundtjänst."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet är låst."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser upp SIM-kort…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till ombeds du att låsa upp surfplattan med din Google-inloggning."\n\n" Försök igen om  <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till ombeds du att låsa upp mobilen med uppgifterna som du använder när du loggar in på Google."\n\n" Försök igen om  <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till ombeds du att låsa upp surfplattan med din Google-inloggning.\n\n Försök igen om  <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till ombeds du att låsa upp mobilen med uppgifterna som du använder när du loggar in på Google.\n\n Försök igen om  <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Du har försökt låsa upp surfplattan på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till kommer surfplattan att återställas till fabriksinställningarna. Du förlorar då alla användardata."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till kommer mobilen att återställas till fabriksinställningarna. Du förlorar då alla användardata."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Du har försökt låsa upp surfplattan på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs nu till fabriksinställningarna."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Lösenord"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logga in"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ogiltigt användarnamn eller lösenord."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Har du glömt ditt användarnamn eller lösenord?"\n"Besök "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Har du glömt ditt användarnamn eller lösenord?\nBesök "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrollerar …"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Lås upp"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ljud på"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Bekräfta navigering"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Lämna den här sidan"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Stanna på den här sidan"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vill du verkligen navigera bort från den här sidan?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVill du verkligen navigera bort från den här sidan?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tips! Dubbelknacka om du vill zooma in eller ut."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> har tyvärr stoppats."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har tyvärr stoppats."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarar inte."\n\n"Vill du stänga den?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarar inte."\n" "\n"Vill du stänga den?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarar inte.\n\nVill du stänga den?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarar inte.\n \nVill du stänga den?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> svarar inte. Vill du stänga den?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."\n\n"Vill du stänga den?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte.\n\nVill du stänga den?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapportera"</string>
     <string name="wait" msgid="7147118217226317732">"Vänta"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sidan har slutat svara."\n\n"Vill du stänga sidan?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sidan har slutat svara.\n\nVill du stänga sidan?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Appen omdirigeras"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> startades först."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Tillåter att appen kopierar innehåll genom att standardbehållartjänsten startas. Används inte av vanliga appar."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Omdirigera medieuppspelning"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Tillåter att appen omdirigerar medieuppspelningar till andra externa enheter."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Åtkomst till säkert keyguard-lagringsutrymme"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Tillåter att en app får åtkomst till säkert keyguard-lagringsutrymme."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrollera hur knapplåset visas och döljs"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillåter att en app kontrollerar knapplåsfunktionen."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tryck två gånger för zoomkontroll"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Det gick inte att lägga till widgeten."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Kör"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Färdig"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Föreg."</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Utför"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Slå nummer "\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Slå nummer \nmed <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Skapa kontakt\nmed <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Följande appar begär åtkomstbehörighet till ditt konto, både nu och i framtiden."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vill du tillåta den här begäran?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Begäran om åtkomst"</string>
     <string name="allow" msgid="7225948811296386551">"Tillåt"</string>
     <string name="deny" msgid="2081879885755434506">"Neka"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Begärd behörighet"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Begärd behörighet"\n"för kontot <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Begärd behörighet\nför kontot <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Indatametod"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synkronisera"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string>
@@ -1441,10 +1472,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Ansluter ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tillgängliga"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ej tillgängligt"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Används"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Inbyggd skärm"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skärm"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Överlagring #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Trådlös anslutning till skärm"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Den här skärmen visas på en annan enhet"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Koppla från"</string>
@@ -1453,7 +1487,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Fel grafiskt lösenord"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Fel lösenord"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Fel PIN-kod"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Försök igen om <xliff:g id="NUMBER">%1$d</xliff:g> sekunder."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Rita ditt grafiska lösenord"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ange PIN-kod för SIM-kortet"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Ange PIN-kod"</string>
@@ -1473,27 +1507,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Lösenord"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Logga in"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ogiltigt användarnamn eller lösenord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glömt ditt användarnamn eller lösenord?"\n"Besök "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glömt ditt användarnamn eller lösenord?\nBesök "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontot kontrolleras …"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök återställs surfplattan till fabriksinställningarna. Du förlorar då alla användardata."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök återställs mobilen till fabriksinställningarna. Du förlorar då alla användardata."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har försökt låsa upp surfplattan på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs nu till fabriksinställningarna."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs nu till fabriksinställningarna."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ta bort"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vill du höja volymen över den rekommenderade nivån?"\n"Om du lyssnar på hög volym under långa perioder kan din hörsel skadas."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vill du höja volymen över den rekommenderade nivån?\nOm du lyssnar på hög volym under långa perioder kan din hörsel skadas."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsätt trycka med två fingrar om du vill aktivera tillgänglighetsläget."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tillgänglighetsläget har aktiverats."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Byte till tillgänglighetsläge avbrutet."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Ägare"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Fel"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Den här appen stöder inte konton för begränsade profiler"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Den här appen stöder inte konton för begränsade profiler"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Ingen app som kan hantera åtgärden hittades"</string>
     <string name="revoke" msgid="5404479185228271586">"Återkalla"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Inställd"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Det gick inte att skriva innehållet"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ange pinkod"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Aktuell pinkod"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Ny pinkod"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Bekräfta din nya pinkod"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Skapa en pinkod om du vill ändra begränsningar"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Pinkoderna stämmer inte överens. Försök igen."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pinkoden är för kort. Måste vara minst fyra siffror."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Fel pinkod. Försök igenom en sekund."</item>
+    <item quantity="other" msgid="8030607343223287654">"Fel pinkod. Försök igenom om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index b066d3a..22c610d 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Inaruhusu programu kusongesha kazi hadi kwenye mandhari-mbele na mandari nyuma. Programu inaweza kufanya haya bila ya maingizo yako."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"dhibiti mabunda ya shughuli"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Inaruhusu programu kuongeza, kuondoa, na kubadilisha bunda za shughuli ambamo programu nyingine huendeshwa. Programu hasidi zinaweza kusitisha tabia ya programu nyingine."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"anzisha shughuli yoyote"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Huruhusu programu kuanzisha shughuli yoyote, pasi kujali ulinzi wa idhini au hali ya nje."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"weka utangamano wa skrini"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Inaruhusu mmiliki kushurutisha kwenye kusano ya kiwango cha juu ya mbinu ya ingizo. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"funga kwa huduma ya ufikiaji"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Inamuruhusu mmiliki kufunga kipengee kinachojitokeza katika nyanja mbalimbali za kiwango cha juu cha huduma ya afikiaji. Hapaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"tundika kwenye huduma ya kuchapisha"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Inaruhusu kishikiliaji kujifungilia kiolesura cha kiwango cha juu cha huduma ya kuchapisha. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"fikia kazi zote za kuchapisha"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Huruhusu mmiliki kufikia kazi za kuchapisha zilizoundwa na programu nyingine. Haipaswi kuhitajika kwa programu za kawaida kamwe."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"Imefungwa kwa huduma ya maandishi"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu ya huduma ya matini(k.m.SpellCheckerService). Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"funga kwa huduma ya VPN"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ongeza au ondoa msimamizi wa kifaa"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Inaruhusu mmiliki kuongeza au kuondoa wasimamizi wa kifaa waliopo. Kamwe kisihitajike kwa ajili ya programu za kawaida."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"badilisha uelekezo wa skrini"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Inaruhusu programu kubadilisha mzunguko wa skrini wakati wowote. Kamwe hazihitajiki kwa programu za kawaida."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Badilisha kasi ya pointa"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Inaruhusu programu kutumia vipengee vya kiwango cha chini vya SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"soma bafa ya fremu"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Inaruhusu programu kusoma maudhui ya fremu ya bafa."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"fikia InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Inaruhusu programu kutumia vipengele vya chini vya InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"sanidi maonyesho ya Wifi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Inaruhusu programu kusanidi na kuunganika kwenye maonyesho ya Wifi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"dhibiti maonyesho ya Wifi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Inaruhusu programu kudhibiti vipengele vya kiwango cha chini vya maonyesho ya Wifi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"badilisha mipangilio yako ya sauti"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Inaruhusu programu kurekebisha mipangilio ya sauti kila mahali kama vile sauti na ni kipaza sauti kipi ambacho kinatumika kwa kutoa."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"rekodi sauti"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Inaruhusu programu kuandikia kadi ya SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"badilisha/futa maudhui ya hifadhi ya media ya ndani."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Inaruhusu programu kurekebisha maudhui ya hifadhi ya ndani vyombo vya habari."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"dhibiti hifadhi ya hati"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Huruhusu programu kudhibiti hifadhi ya hati."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Fikia hifadhi ya nje ya watumiaji wote"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Inaruhusu programu kufikia hifadhi ya nje kwa watumiaji wote."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"fikia faili za mfumo za kache"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Inaruhusu programu kudhibiti sera za mtandao na kufafanua sheria maalum za programu."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"badilisha uthibitishaji wa matumizi ya mtandao"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"rekebisha alama za soketi"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Inaruhusu programu kurekebisha alama za soketi za upelekaji"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"omba programu ya usakinishaji inayotolewa na mtoa huduma."</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Ingiza SIM kadi."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM kadi haipatikani au haisomeki. Tafadhali ingiza SIM kadi."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM kadi isiyotumika."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kadi yako imelemezwa kabisa."\n" Wasiliana na mtoa huduma wako wa pasi waya ili upate SIM kadi nyingine."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kadi yako imelemezwa kabisa.\n Wasiliana na mtoa huduma wako wa pasi waya ili upate SIM kadi nyingine."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Kitufe cha awali cha wimbo"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Kitufe cha wimbo unaofuata"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Kitufe cha kusitisha"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Angalia Mwongozo wa Mtumiaji au wasiliana na Huduma ya Wateja."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kadi imefungwa."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Inafungua SIM kadi..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Umekosea katika kuchora ruwaza yako ya kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena kwa sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Umekosea mara <xliff:g id="NUMBER_0">%d</xliff:g> katika kuingiza nenosiri lako. "\n\n" Jaribu tena katika sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Umekosea katika kuingiza PIN yako mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena katika sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaulizwa kufungua kompyuta yako ndogo kwa kuingia kwa Google."\n\n" Jaribu tena katika sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaulizwa kufungua simu kupitia kuingia Google."\n\n" Jaribu tena katika sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Umekosea katika kuchora ruwaza yako ya kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena kwa sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Umekosea mara <xliff:g id="NUMBER_0">%d</xliff:g> katika kuingiza nenosiri lako. \n\n Jaribu tena katika sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Umekosea katika kuingiza PIN yako mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena katika sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaulizwa kufungua kompyuta yako ndogo kwa kuingia kwa Google.\n\n Jaribu tena katika sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaulizwa kufungua simu kupitia kuingia Google.\n\n Jaribu tena katika sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya zaidi ya <xliff:g id="NUMBER_1">%d</xliff:g> majaribio yasiyofanikiwa, kompyuta ndogo itawekwa upya kwa kiwanda chaguo-msingi na data yote ya mtumiaji itapotea."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofanikiwa, simu itawekwa upya kwa kiwanda chaguo-msingi na data yote ya mtumiaji itapotea."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguo-msingi."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Nenosiri"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ingia"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Jina la mtumiaji au nenosiri batili."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Umesahau jina lako la mtumiaji au nenosiri?"\n"Tembela "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Umesahau jina lako la mtumiaji au nenosiri?\nTembela "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Inakagua..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Fungua"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sauti imewezeshwa"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Thibitisha jinsi ya kuelekea"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Toka kwenye Ukurasa huu"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bakia kwenye Ukurasa huu"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Je, una uhakika unataka kutoka kwenye ukurasa huu?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nJe, una uhakika unataka kutoka kwenye ukurasa huu?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Thibitisha"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kidokezo: Gonga mara mbili ili kukuza ndani na nje."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Kujaza kiotomatiki"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Kwa bahati mbaya, <xliff:g id="APPLICATION">%1$s</xliff:g> imekoma."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Kwa bahati mbaya, mchakato <xliff:g id="PROCESS">%1$s</xliff:g> umekoma."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> haifanyi kazi."\n\n"Unataka kuifunga?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Shughuli <xliff:g id="ACTIVITY">%1$s</xliff:g> haijibu. "\n\n" Unataka kuifunga?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> haifanyi kazi.\n\nUnataka kuifunga?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Shughuli <xliff:g id="ACTIVITY">%1$s</xliff:g> haijibu. \n\n Unataka kuifunga?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> haijibu. Unataka kufunga?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Mchakato <xliff:g id="PROCESS">%1$s</xliff:g> haijibu. "\n\n" Unataka kuifunga?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Mchakato <xliff:g id="PROCESS">%1$s</xliff:g> haijibu. \n\n Unataka kuifunga?"</string>
     <string name="force_close" msgid="8346072094521265605">"Sawa"</string>
     <string name="report" msgid="4060218260984795706">"Ripoti"</string>
     <string name="wait" msgid="7147118217226317732">"Subiri"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Ukurasa umekwama. "\n" "\n" Je, unataka kuufunga?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Ukurasa umekwama. \n \n Je, unataka kuufunga?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Programu imeelekezwa kwingine"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>inaendesha sasa."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilizinduliwa mwanzoni."</string>
@@ -1173,7 +1202,7 @@
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Usiruhusu Kamwe"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM kadi imeondolewa"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na SIM kadi halali iliyoingizwa."</string>
-    <string name="sim_done_button" msgid="827949989369963775">"Kwisha"</string>
+    <string name="sim_done_button" msgid="827949989369963775">"Nimemaliza"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM kadi imeongezwa"</string>
     <string name="sim_added_message" msgid="6599945301141050216">"Anzisha upya kifaa chako ili kufikia mtandao wa simu."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"Anza upya"</string>
@@ -1256,24 +1285,28 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Inaruhusu programu kuomba huduma ya chombo chaguo-msingi kunakili maudhui. Si ya matumizi na programu za kawiada."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Fuatalia utoaji wa habari"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Inaruhusu programu kufuatilia utoaji wa habari kwa vifaa vingine vya nje."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Kufikia hifadhi salama ya ufunguo wa ulinzi"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Inaruhusu programu kufikia hifadhi salama ya ufunguo wa ulinzi."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Dhibiti uonyeshaji na ufichaji wa kilinda-funguo"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Huruhusu programu kudhibiti kilinda-funguo."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Gusa mara mbili kwa udhibiti cha kuza"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Haikuweza kuongeza wijeti."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Nenda"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Tafuta"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Tuma"</string>
     <string name="ime_action_next" msgid="3138843904009813834">"Ifuatayo"</string>
-    <string name="ime_action_done" msgid="8971516117910934605">"Kwisha"</string>
+    <string name="ime_action_done" msgid="8971516117910934605">"Nimemaliza"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Iliyotangulia"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Tekeleza"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Piga nambari "\n" kwa kutumia <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Unda anwani "\n" kwa kutumia <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Piga nambari \n kwa kutumia <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Unda anwani \n kwa kutumia <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Programu moja au zaidi zifuatazo zinaomba ruhusa ya kufikia akaunti yako, sasa na baadaye."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Unataka kuruhusu ombi hili?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Fikia ombi"</string>
     <string name="allow" msgid="7225948811296386551">"Ruhusu"</string>
     <string name="deny" msgid="2081879885755434506">"Kataza"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Idhini imeitishwa"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Idhini imeombwa"\n"ya akaunti<xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Idhini imeombwa\nya akaunti<xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Mbinu ya uingizaji"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sawazisha"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Ufikiaji"</string>
@@ -1309,7 +1342,7 @@
     <item quantity="one" msgid="8167147081136579439">"Linganisho 1"</item>
     <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ya <xliff:g id="TOTAL">%d</xliff:g>"</item>
   </plurals>
-    <string name="action_mode_done" msgid="7217581640461922289">"Kwisha"</string>
+    <string name="action_mode_done" msgid="7217581640461922289">"Nimemaliza"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Inaondoa hifadhi ya USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Inaondoa kadi ya SD..."</string>
     <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Inafuta hifadhi ya USB..."</string>
@@ -1360,7 +1393,7 @@
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Imefanyika"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Nimemaliza"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
@@ -1435,16 +1468,19 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kwisha"</string>
+    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Nimemaliza"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Inatambaza..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Inaunganisha..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Inapatikana"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Haipatikani"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Inatumika"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Skrini Iliyojengwa ndani"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Skrini ya HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Uwekeleaji #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Onyesho pasiwaya limeunganishwa"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Skrini hii inaonyesha kwenye kifaa kingine"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Tenganisha"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Mchoro Usio sahihi"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nenosiri Lisilo sahihi"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN isiyo sahihi"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Jaribu tena baada ya sekunde <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Jaribu tena baada ya sekunde <xliff:g id="NUMBER">%1$d</xliff:g>."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Chora ruwaza yako"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingiza PIN ya SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Ingiza PIN"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Nenosiri"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Ingia"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Jina la mtumiaji au nenosiri batili."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Je, umesahau jina lako la mtumiaji au nenosiri?"\n"Tembela "<b>"Bgoogle.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Je, umesahau jina lako la mtumiaji au nenosiri?\nTembela "<b>"Bgoogle.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Inakagua akaunti…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofaulu, kompyuta ndogo itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani data yote ya mtumiaji itapotea."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofaulu, simu itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani na data yote ya mtumiaji itapotea."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa kompyuta ndogo itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa simu  itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe."\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe."\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ondoa"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ungependa kuongeza sauti kupita kiwango kinachopendekezwa?"\n"Kusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ungependa kuongeza sauti kupita kiwango kinachopendekezwa?\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Endelea kushikilia chini kwa vidole vyako viwili ili kuwezesha ufikivu."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Ufikivu umewezeshwa."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ufikivu umeghairiwa."</string>
     <string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Mmiliki"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Hitilafu"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Programu hii haiwezi kutumiwa na akaunti za wasifu zilizowekewa vikwazo"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Programu hii haiwezi kutumiwa na akaunti za wasifu zilizowekewa vikwazo"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Hakuna programu iliyopatikana ili kushughulikia kitendo hiki"</string>
     <string name="revoke" msgid="5404479185228271586">"Batilisha"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Barua"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Barua ya Serikali"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Kisheria"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Mwanasheria Mdogo"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Leja"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Kijigazeti"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Imeghairiwa"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Hitilafu katika kuandika maudhui"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ingiza PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ya sasa"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN mpya"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Thibitisha PIN mpya"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Unda PIN ya kurekebisha vikwazo"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN hazilingani. Jaribu tena."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ni fupi mno. Lazima iwe angalau tarakimu 4."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN sio sahihi. Jaribu tena baada ya sekunde 1."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN sio sahihi. Jaribu tena baada ya sekunde <xliff:g id="COUNT">%d</xliff:g>."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sw600dp-land/arrays.xml b/core/res/res/values-sw600dp-land/arrays.xml
index 5550216..5602a1c 100644
--- a/core/res/res/values-sw600dp-land/arrays.xml
+++ b/core/res/res/values-sw600dp-land/arrays.xml
@@ -19,54 +19,4 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Resources for GlowPadView in LockScreen -->
-    <array name="lockscreen_targets_when_silent">
-        <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
-        <item>@drawable/ic_lockscreen_soundon</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_when_silent">
-        <item>@string/description_target_unlock</item>
-        <item>@null</item>
-        <item>@string/description_target_soundon</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_direction_descriptions">
-        <item>@string/description_direction_right</item>
-        <item>@null</item>
-        <item>@string/description_direction_left</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_targets_when_soundon">
-        <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
-        <item>@drawable/ic_lockscreen_silent</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_when_soundon">
-        <item>@string/description_target_unlock</item>
-        <item>@null</item>
-        <item>@string/description_target_silent</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_targets_with_camera">
-        <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_camera</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_with_camera">
-        <item>@string/description_target_unlock</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_camera</item>
-        <item>@null</item>
-    </array>
-
 </resources>
diff --git a/core/res/res/values-sw600dp/alias.xml b/core/res/res/values-sw600dp/alias.xml
deleted file mode 100644
index bf3eecb..0000000
--- a/core/res/res/values-sw600dp/alias.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** 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.
-*/
--->
-<resources>
-    <!-- Alias used to reference one of two possible layouts in keyguard.  -->
-    <item type="layout" name="keyguard_eca">@android:layout/keyguard_emergency_carrier_area</item>
-</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3825b40..8f93804 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"อนุญาตให้แอปพลิเคชันย้ายงานไปยังส่วนหน้าและพื้นหลัง แอปพลิเคชันอาจดำเนินการโดยไม่รอคำสั่งจากคุณ"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"หยุดแอปพลิเคชันที่ทำงานอยู่"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"อนุญาตให้แอปพลิเคชันลบงานออกและยุติแอปพลิเคชันต่างๆ ของงานนั้น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นๆ ทำงานได้ไม่ถูกต้อง"</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"จัดการชุดรายการกิจกรรม"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"อนุญาตให้แอปเพิ่ม นำออก และแก้ไขชุดรายการกิจกรรมที่แอปอื่นใช้งาน แอปที่อันตรายอาจรบกวนการทำงานของแอปอื่น"</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"เริ่มต้นกิจกรรมใดๆ"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"อนุญาตให้แอปพลิเคชันเริ่มกิจกรรม ไม่ว่าการอนุญาตหรือสถานะที่ส่งออกจะเป็นอย่างไรก็ตาม"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ตั้งค่าความเข้ากันได้ของหน้าจอ"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวิธีการป้อนข้อมูล ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"เชื่อมโยงกับบริการการเข้าถึง"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อระดับบนสุดของบริการการเข้าถึง ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"เชื่อมโยงกับบริการการพิมพ์"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"อนุญาตให้ผู้ใช้เชื่อมโยงกับอินเทอร์เฟซระดับสูงสุดของบริการการพิมพ์ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"เข้าถึงงานพิมพ์ทั้งหมด"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"อนุญาตให้ผู้ใช้สามารถเข้าถึงงานพิมพ์ที่สร้างโดยแอปอื่นได้ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"เชื่อมโยงกับบริการ NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"อนุญาตให้ผู้ถือเชื่อมโยงกับแอปพลิเคชันที่เลียนแบบการ์ด NFC ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"เชื่อมโยงกับบริการข้อความ"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการข้อความ (เช่น บริการเครื่องตรวจตัวสะกด) ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"เชื่อมโยงกับบริการ VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"เพิ่มหรือลบผู้ดูแลระบบอุปกรณ์"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"อนุญาตให้เจ้าของเพิ่มหรือลบผู้ดูแลระบบอุปกรณ์ที่ใช้งาน ไม่ควรต้องใช้สำหรับแอปปกติ"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"อนุญาตให้แอปพลิเคชันเปลี่ยนการหมุนของหน้าจอได้ตลอดเวลา ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"เปลี่ยนความเร็วของตัวชี้"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"อนุญาตให้แอปพลิเคชันใช้คุณลักษณะระดับต่ำของ SurfaceFlinger"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"อ่านเฟรมบัฟเฟอร์"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"อนุญาตให้แอปพลิเคชันอ่านเนื้อหาในเฟรมบัฟเฟอร์"</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"เข้าถึง InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"อนุญาตให้แอปใช้คุณลักษณะระดับต่ำของ InputFlinger"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"กำหนดค่าการแสดงผลด้วย WiFi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"อนุญาตให้แอปกำหนดค่าและเชื่อมต่อกับจอแสดงผล WiFi ได้"</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ควบคุมการแสดงผลด้วย WiFi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"อนุญาตให้แอปควบคุมคุณลักษณะต่างๆ ในระดับล่างของการแสดงผลด้วย WiFi"</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"เปลี่ยนการตั้งค่าเสียงของคุณ"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"อนุญาตให้แอปพลิเคชันปรับเปลี่ยนการตั้งค่าเสียงทั้งหมดได้ เช่น ระดับเสียงและลำโพงที่จะใช้งาน"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"บันทึกเสียง"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"อนุญาตให้แอปพลิเคชันเขียนลงบนการ์ด SD"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"แก้/ลบเนื้อหาข้อมูลสื่อภายใน"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"อนุญาตให้แอปพลิเคชันแก้ไขเนื้อหาของที่เก็บข้อมูลสื่อภายใน"</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"จัดการที่เก็บเอกสาร"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"อนุญาตให้แอปจัดการที่เก็บเอกสาร"</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"เข้าถึงที่จัดเก็บภายนอกของทุกคน"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"อนุญาตให้แอปพลิเคชันเข้าถึงที่จัดเก็บข้อมูลภายนอกสำหรับผู้ใช้ทั้งหมด"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"เข้าถึงระบบไฟล์แคช"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"อนุญาตให้แอปพลิเคชันจัดการนโยบายเครือข่ายและกำหนดกฎเฉพาะแอปพลิเคชัน"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"แก้ไขการบันทึกบัญชีการใช้งานเครือข่าย"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"แก้ไขเครื่องหมายซ็อกเก็ต"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"อนุญาตให้แอปแก้ไขเครื่องหมายซ็อกเก็ตสำหรับการกำหนดเส้นทาง"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"เรียกใช้แอปการกำหนดค่าของผู้ให้บริการ"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"แฮงเอาท์"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"ใส่ซิมการ์ด"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"ไม่มีซิมการ์ดหรือไม่สามารถอ่านได้ โปรดใส่ซิมการ์ด"</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"ซิมการ์ดใช้ไม่ได้"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"ซิมการ์ดของคุณถูกปิดใช้งานอย่างถาวร"\n"ติดต่อผู้ให้บริการไร้สายของคุณเพื่อรับซิมการ์ดอีกอันหนึ่ง"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"ซิมการ์ดของคุณถูกปิดใช้งานอย่างถาวร\nติดต่อผู้ให้บริการไร้สายของคุณเพื่อรับซิมการ์ดอีกอันหนึ่ง"</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"ปุ่มแทร็กก่อนหน้า"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"ปุ่มแทร็กถัดไป"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"ปุ่มหยุดชั่วคราว"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"ดูคู่มือผู้ใช้หรือติดต่อศูนย์บริการลูกค้า"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"ซิมการ์ดถูกล็อก"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"กำลังปลดล็อกซิมการ์ด…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว"\n\n"โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว"\n\n"ลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"คุณพิมพ์ PIN ไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว"\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว\n\nโปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว\n\nลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"คุณพิมพ์ PIN ไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว\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_now_wiping" product="tablet" msgid="280873516493934365">"คุณพยายามปลดล็อกแท็บเล็ตอย่างไม่ถูกต้องแล้ว <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ขณะนี้แท็บเล็ตจะถูกรีเซ็ตเป็นค่าเริ่มต้นจากโรงงาน"</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"รหัสผ่าน"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ลงชื่อเข้าใช้"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน"\n"โปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน\nโปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"กำลังตรวจสอบ…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"ปลดล็อก"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"เปิดเสียง"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"ยืนยันการนำทาง"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"ออกจากหน้านี้"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"อยู่ในหน้านี้"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"คุณแน่ใจไหมว่าต้องการออกจากหน้านี้"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nคุณแน่ใจไหมว่าต้องการออกจากหน้านี้"</string>
     <string name="save_password_label" msgid="6860261758665825069">"ยืนยัน"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"เคล็ดลับ: แตะสองครั้งเพื่อขยายและย่อ"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ป้อนอัตโนมัติ"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"ขออภัย <xliff:g id="APPLICATION">%1$s</xliff:g> หยุดการทำงานแล้ว"</string>
     <string name="aerr_process" msgid="4507058997035697579">"ขออภัย กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> หยุดการทำงานแล้ว"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ไม่ตอบสนอง"\n\n"คุณต้องการปิดหรือไม่"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"กิจกรรม <xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่ตอบสนอง"\n\n"คุณต้องการปิดหรือไม่"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ไม่ตอบสนอง\n\nคุณต้องการปิดหรือไม่"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"กิจกรรม <xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่ตอบสนอง\n\nคุณต้องการปิดหรือไม่"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> ไม่ตอบสนอง คุณต้องการปิดหรือไม่"</string>
-    <string name="anr_process" msgid="6513209874880517125">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ไม่ตอบสนอง"\n\n"คุณต้องการปิดหรือไม่"</string>
+    <string name="anr_process" msgid="6513209874880517125">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ไม่ตอบสนอง\n\nคุณต้องการปิดหรือไม่"</string>
     <string name="force_close" msgid="8346072094521265605">"ตกลง"</string>
     <string name="report" msgid="4060218260984795706">"รายงาน"</string>
     <string name="wait" msgid="7147118217226317732">"รอ"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"หน้าเว็บนี้ไม่ตอบสนอง"\n\n"คุณต้องการปิดหรือไม่"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"หน้าเว็บนี้ไม่ตอบสนอง\n\nคุณต้องการปิดหรือไม่"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"แอปฯ ที่เปลี่ยนเส้นทาง"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงานอยู่ในขณะนี้"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> เปิดใช้ไว้แล้ว"</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"อนุญาตให้แอปพลิเคชันเรียกใช้บริการที่เก็บค่าเริ่มต้นเพื่อคัดลอกเนื้อหา ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"กำหนดเส้นทางเอาต์พุตของสื่อ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"อนุญาตให้แอปพลิเคชันกำหนดเส้นทางเอาต์พุตของสื่อไปยังอุปกรณ์ภายนอกอื่นๆ"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"เข้าถึงพื้นที่จัดเก็บที่รักษาความปลอดภัยด้วยคีย์การ์ด"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"อนุญาตให้แอปพลิเคชันเข้าถึงพื้นที่จัดเก็บที่รักษาความปลอดภัยด้วยคีย์การ์ด"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"ควบคุมการแสดงผลและการซ่อนตัวล็อกปุ่มกด"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"อนุญาตให้แอปพลิเคชันควบคุมตัวล็อกปุ่มกด"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"แตะสองครั้งเพื่อควบคุมการซูม"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ไม่สามารถเพิ่มวิดเจ็ต"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"ไป"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"เสร็จสิ้น"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"ก่อนหน้า"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"ปฏิบัติ"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"หมุนหมายเลข "\n" โดยใช้ <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"สร้างที่อยู่ติดต่อ "\n"โดยใช้ <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"หมุนหมายเลข \n โดยใช้ <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"สร้างที่อยู่ติดต่อ \nโดยใช้ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"แอปพลิเคชันต่อไปนี้ขอให้มีการอนุญาตให้เข้าถึงบัญชีของคุณในขณะนี้และในอนาคต"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"คุณต้องการอนุญาตหรือไม่"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"คำขอเข้าถึง"</string>
     <string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
     <string name="deny" msgid="2081879885755434506">"ปฏิเสธ"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"การอนุญาตที่ขอ"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"การอนุญาตที่ขอ"\n"สำหรับบัญชี <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"การอนุญาตที่ขอ\nสำหรับบัญชี <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"วิธีป้อนข้อมูล"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"ซิงค์"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"การเข้าถึง"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"กำลังเชื่อมต่อ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"พร้อมใช้งาน"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"ไม่พร้อมใช้งาน"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"กำลังใช้งาน"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"หน้าจอในตัว"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"หน้าจอ HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"การวางซ้อน #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ปลอดภัย"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"เชื่อมต่อการแสดงผลแบบไร้สายอยู่"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"หน้าจอนี้กำลังแสดงบนอุปกรณ์อื่น"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"หยุดเชื่อมต่อ"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"รูปแบบไม่ถูกต้อง"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"รหัสผ่านไม่ถูกต้อง"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN ไม่ถูกต้อง"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ลองอีกครั้งในอีก <xliff:g id="NUMBER">%d</xliff:g> วินาที"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ลองอีกครั้งในอีก <xliff:g id="NUMBER">%1$d</xliff:g> วินาที"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"วาดรูปแบบของคุณ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ป้อน PIN ของซิม"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"ป้อน PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"รหัสผ่าน"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"ลงชื่อเข้าใช้"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน"\n"โปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน\nโปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"กำลังตรวจสอบบัญชี…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"คุณพิมพ์ 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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"นำออก"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"ในกรณีที่ต้องการเพิ่มระดับเสียงจนเกินระดับที่แนะนำ"\n"การฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"ในกรณีที่ต้องการเพิ่มระดับเสียงจนเกินระดับที่แนะนำ\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ใช้สองนิ้วแตะค้างไว้เพื่อเปิดใช้งานการเข้าถึง"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"เปิดใช้งานการเข้าถึงแล้ว"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ยกเลิกการเข้าถึงแล้ว"</string>
     <string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"เจ้าของ"</string>
     <string name="error_message_title" msgid="4510373083082500195">"ข้อผิดพลาด"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"แอปพลิเคชันนี้ไม่สนับสนุนบัญชีที่มีโปรไฟล์ที่ถูกจำกัด"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"แอปนี้ไม่สนับสนุนบัญชีที่โปรไฟล์ถูกจำกัด"</string>
     <string name="app_not_found" msgid="3429141853498927379">"ไม่พบแอปพลิเคชันสำหรับการทำงานนี้"</string>
     <string name="revoke" msgid="5404479185228271586">"เพิกถอน"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"จดหมาย"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ยกเลิก"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ข้อผิดพลาดในการเขียนเนื้อหา"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"ป้อน PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ปัจจุบัน"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN ใหม่"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"ยืนยัน PIN ใหม่"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"สร้าง PIN สำหรับการแก้ไขข้อจำกัด"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN ไม่ตรงกัน โปรดลองอีกครั้ง"</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN สั้นเกินไป ต้องมีอย่างน้อย 4 หลัก"</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN ไม่ถูกต้อง โปรดลองอีกครั้งในอีก 1 วินาที"</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN ไม่ถูกต้อง โปรดลองอีกครั้งในอีก <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 401fa42..d5af6a7 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Pinapayagan ang app na maglipat ng mga gawain sa foreground at background. Maaari itong gawin ng app nang wala ng iyong input."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"ihinto ang pagpapatakbo ng apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Pinapayagan ang app na mag-alis ng mga gawain at i-off ang apps nito. Maaaring maantala ng nakakahamak na apps ang pagkilos ng iba pang apps."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"pamahalaan ang mga stack ng aktibidad"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Nagbibigay-daan sa app na dagdagan, alisin, at baguhin ang mga stack ng aktibidad kung saan gumagana ang iba pang apps. Maaaring makaabala ang nakakahamak na apps sa pagkilos ng iba pang apps."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"magsimula ng anumang aktibidad"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Binibigyang-daan ang app na magsimula ng anumang aktibidad, may proteksyon man ng pahintulot o na-export na katayuan."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"itakda ang pagkakatugma ng screen"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng pamamaraan ng pag-input. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sumailalim sa isang serbisyo sa accessibility"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Binibigyang-daan ang may-ari na sumailalim sa nasa nangungunang antas na interface ng isang serbisyo sa accessibility. Hindi dapat kailanman kailanganin para sa normal na apps."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"sumailalim sa isang serbisyo sa pag-print"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Nagbibigay-daan sa may-ari na sumailalim sa interface sa nangungunang antas ng isang serbisyo sa pag-print. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"i-access ang lahat ng pag-print"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Nagbibigay-daan sa may-ari na i-access ang mga pag-print na ginawa ng ibang app. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"i-bind sa serbisyo ng NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Nagbibigay-daan sa may-ari na mag-bind sa mga application na nag-e-emulate ng mga NFC card. Hindi dapat kailanman kailanganin para sa normal na apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"sumailalim sa serbisyo ng teksto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Pinapayagan ang may-hawak na sumailalim sa nangungunang antas na interface (hal. SpellCheckerService). Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"sumailalim sa isang serbisyo ng VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"magdagdag o mag-alis ng admin ng device"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Pinapayagan ang may-ari na magdagdag o mag-alis ng mga aktibong administrator ng device. Hindi dapat kailanganin kailanman para sa normal na apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Pinapayagan ang app na baguhin ang pag-ikot ng screen anumang oras. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"baguhin ang bilis ng pointer"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Pinapayagan ang app na gamitin ang mababang antas na mga tampok ng SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"basahin ang buffer ng frame"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Pinapayagan ang app na basahin ang nilalaman ng buffer ng frame."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"i-access ang InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Nagbibigay-daan sa app na gumamit ng mga tampok ng InputFlinger sa mababang antas."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"mag-configure ng mga Wifi display"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Pinapayagan ang app na mag-configure at kumonekta sa mga Wifi display."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"magkontrol ng mga Wifi display"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Pinapayagan ang app na magkontrol ng mga tampok sa mababang antas ng mga dispay ng Wifi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"baguhin ang mga setting ng iyong audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Pinapayagan ang app na baguhin ang mga pandaigdigang setting ng audio gaya ng volume at kung aling speaker ang ginagamit para sa output."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"mag-record ng audio"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pinapayagan ang app na magsulat sa SD card."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"baguhin/tanggalin ang mga nilalaman ng panloob na imbakan ng media"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Pinapayagan ang app na baguhin ang mga nilalaman ng panloob na media storage."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"pamahalaan document storage"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Pinapayagan ang app na pamahalaan ang storage ng dokumento."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"i-access panlabas na storage ng user"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Pinapayagan ang app na mag-access ng panlabas na storage para sa lahat ng user."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"i-access ang cache filesystem"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pinapayagan ang app na pamahalaan ang mga patakaran ng network at ilarawan ang mga patakarang tukoy sa app."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"baguhin ang pagkukuwenta sa paggamit ng network"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"baguhin ang mga socket mark"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Nagbibigay-daan sa app na baguhin ang mga socket mark para sa pagruruta"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nagbibigay-daan sa may-ari na mapailalim sa interface sa tuktok na antas ng isang serbisyo ng notification listener. Hindi dapat kailanganin para sa karaniwang apps kahit kailan."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"paganahin ang app ng configuration na ibinigay ng carrier"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Nagbibigay-daan sa may-ari na paganahin ang app ng configuration na ibinigay ng carrier. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Maglagay ng isang SIM card."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Nawawala o hindi nababasa ang SIM card. Maglagay ng isang SIM card."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Hindi nagagamit na SIM card."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ang iyong SIM card ay permanenteng hindi pinagana."\n" Makipag-ugnay sa iyong wireless service provider para sa isa pang SIM card."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ang iyong SIM card ay permanenteng hindi pinagana.\n Makipag-ugnay sa iyong wireless service provider para sa isa pang SIM card."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Button na nakaraang track"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Button na Susunod na track"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Button na I-pause"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Tingnan ang Gabay ng User o makipag-ugnay sa Pangangalaga sa Customer."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Naka-lock ang SIM card."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Ina-unlock ang SIM card…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Mali mong naguhit ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Na-type mo nang mali ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Na-type mo nang mali ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Naiguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang iyong tablet gamit ang iyong pag-sign-in sa Google."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Naguhit mo nang mali ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang iyong telepono gamit ang iyong pag-sign-in sa Google."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Mali mong naguhit ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Na-type mo nang mali ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Na-type mo nang mali ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Naiguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang iyong tablet gamit ang iyong pag-sign-in sa Google.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Naguhit mo nang mali ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang iyong telepono gamit ang iyong pag-sign-in sa Google.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Mali mong tinangkang ma-unlock ang tablet nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang mga hindi matagumpay na pagtatangka, mare-reset ang tablet sa factory default at mawawala ang lahat ng data ng user."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Mali mong tinangkang ma-unlock ang telepono nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang mga hindi matagumpay na pagtatangka, mare-reset ang telepono sa factory default at mawawala ang lahat ng data ng user."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Mali mong tinangkang ma-unlock ang tablet nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Mare-reset na ngayon ang tablet sa factory default."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Password"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Mag-sign in"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Di-wastong username o password."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nakalimutan ang iyong username o password?"\n"Bisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nakalimutan ang iyong username o password?\nBisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Tinitingnan..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"I-unlock"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"I-on ang tunog"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Kumpirmahin ang Pag-navigate"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Umalis sa Pahinang ito"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Manatili sa Pahinang ito"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sigurado ka bang gusto mong mag-navigate paalis sa pahinang ito?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigurado ka bang gusto mong mag-navigate paalis sa pahinang ito?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Kumpirmahin"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Mag-double tap upang mag-zoom in at out."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofill"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Sa kasamaang palad, huminto ang <xliff:g id="APPLICATION">%1$s</xliff:g>."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Sa kasamaang palad, nahinto ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g>."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Hindi tumutugon ang <xliff:g id="APPLICATION">%2$s</xliff:g>."\n\n"Nais mo ba itong isara?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Hindi tumutugon ang aktibidad na <xliff:g id="ACTIVITY">%1$s</xliff:g>."\n\n"Nais mo ba itong isara?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Hindi tumutugon ang <xliff:g id="APPLICATION">%2$s</xliff:g>.\n\nNais mo ba itong isara?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Hindi tumutugon ang aktibidad na <xliff:g id="ACTIVITY">%1$s</xliff:g>.\n\nNais mo ba itong isara?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Hindi tumutugon ang <xliff:g id="APPLICATION">%1$s</xliff:g>. Nais mo ba itong isara?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Hindi tumutugon ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g>."\n\n"Nais mo ba itong isara?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Hindi tumutugon ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g>.\n\nNais mo ba itong isara?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Ulat"</string>
     <string name="wait" msgid="7147118217226317732">"Maghintay"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Hindi na tumutugon ang pahina."\n\n"Nais mo ba itong isara?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Hindi na tumutugon ang pahina.\n\nNais mo ba itong isara?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Na-redirect ang app"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Tumatakbo na ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Orihinal na nalunsad ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Pinapayagan ang app na i-apela ang default na serbisyo ng container upang kopyahin ang nilalaman. Hindi para sa paggamit ng normal na apps."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"I-route ang output ng media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Pinapayagan ang application na mag-route ng output ng media sa iba pang mga panlabas na device."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"I-access ang secure na storage ng keyguard"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Nagbibigay-daan sa isang application na i-access ang secure na storage ng keyguard."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrolin ang pagpapakita at pagtago sa keyguard"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Pinapayagan ang isang application na kontrolin ang keyguard."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Pindutin nang dalawang beses para sa pagkontrol ng zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Hindi maidagdag ang widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pumunta"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Tapos na"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Nkraan"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Isakatuparan"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Mag-dial ng numero"\n"gamit ang <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Lumikha ng contact"\n"gamit ang <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Mag-dial ng numero\ngamit ang <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Lumikha ng contact\ngamit ang <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Ang sumusunod na isa o higit pang mga app ay humihiling ng pahintulot na i-access ang iyong account, ngayon at sa hinaharap."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Gusto mo bang payagan ang kahilingang ito?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Kahilingan sa pag-access"</string>
     <string name="allow" msgid="7225948811296386551">"Payagan"</string>
     <string name="deny" msgid="2081879885755434506">"Tanggihan"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Hiniling ang pahintulot"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Hiniling ang pahintulot"\n"para sa account na <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Hiniling ang pahintulot\npara sa account na <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Pamamaraan ng pag-input"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"I-sync"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Kakayahang Ma-access"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Kumukonekta..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Hindi available"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Ginagamit"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Built-in na Screen"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI Screen"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Nakakonekta ang wireless na display"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Lumalabas ang screen na ito sa isa pang device"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Alisin sa pagkakakonekta"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Maling Pattern"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Maling Password"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Maling PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Subukang muli sa loob ng <xliff:g id="NUMBER">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Subukang muli sa loob ng <xliff:g id="NUMBER">%1$d</xliff:g> (na) segundo."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Iguhit ang iyong pattern"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ilagay ang SIM PIN"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Ilagay ang PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Mag-sign in"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Di-wastong username o password."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nakalimutan ang iyong username o password?"\n"Bisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nakalimutan ang iyong username o password?\nBisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Tinitingnan ang account…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tinangka mo sa hindi tamang paraan na i-unlock ang tabelt nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, ire-reset ang tablet sa factory default at mawawala ang lahat ng data ng user."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Tinangka mo sa hindi tamang paraan na i-unlock ang telepono nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, ire-reset ang telepono sa factory default at mawawala ang lahat ng data ng user."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tinangka mo sa hindi tamang paraan na i-unlock ang tablet nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Ire-reset na ngayon ang tablet sa factory default."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Tinangka mo sa hindi tamang paraan na i-unlock ang telepono nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Ire-reset na ngayon ang telepono sa factory default."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Lakasan ang volume nang lagpas sa ligtas na antas?"\n"Maaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Lakasan ang volume nang lagpas sa ligtas na antas?\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Panatilihing nakapindot nang matagal ang iyong dalawang daliri upang paganahin ang pagiging naa-access."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pinagana ang accessibility."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Nakansela ang pagiging naa-access."</string>
     <string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"May-ari"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Hindi sinusuportahan ng application na ito ang mga account para sa mga pinaghihigpitang profile"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Hindi sinusuportahan ng app na ito ang mga account para sa mga pinaghihigpitang profile"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Walang nakitang application na mangangasiwa sa pagkilos na ito"</string>
     <string name="revoke" msgid="5404479185228271586">"Bawiin"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kinansela"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"May error sa pagsusulat ng nilalaman"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ilagay ang PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Kasalukuyang PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Bagong PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Kumpirmahin ang bagong PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Gumawa ng PIN para sa pagbago sa mga paghihigpit"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Hindi nagtutugma ang mga PIN. Subukang muli."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Masyadong maikli ang PIN. Hindi dapat mas maikli sa 4 na digit."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Mali ang PIN. Subukang muli pagkalipas ng 1 segundo."</item>
+    <item quantity="other" msgid="8030607343223287654">"Mali ang PIN. Subukang muli pagkalipas ng <xliff:g id="COUNT">%d</xliff:g> (na) segundo."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a6d7b2a..bf002e6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Uygulama bunu sizden bir giriş olmadan yapabilir."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"etkinlik yığınlarını yönet"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Uygulamaya, diğer uygulamaların içinde çalıştığı etkinlik yığınlarını ekleme, kaldırma ve değiştirme izni verir. Kötü amaçlı uygulamalar diğer uygulamaların davranışlarını olumsuz etkileyebilir."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"herhangi bir etkinlik başlat"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Uygulamaya, izin koruma veya dışa aktarma durumu ne olursa olsun bir etkinlik başlatma izni verir."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ekran uyumluluğunu ayarla"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Cihazın sahibine, bir giriş yönteminin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"erişilebilirlik hizmetine bağlan"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"İzin sahibine bir erişilebilirlik hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"bir yazdırma hizmetine bağlan"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"İzin sahibine, bir yazdırma hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"tüm yazdırma işlerine eriş"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"İzin sahibine, başka uygulama tarafından oluşturulan yazdırma işlerine erişim izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"kısa mesaj hizmetine bağla"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Cihazın sahibine, bir metin hizmetinin (ör. SpellCheckerService) en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerekmez."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPN hizmetine bağlan"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"cihaz yöneticisi ekle veya kaldır"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"İzin sahibine, etkin cihaz yöneticileri ekleyip kaldırma izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Uygulamaya, istediği zaman ekran dönüşünü değiştirme izni verir. Normal uygulamalar için gerekli değildir."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"işaretçi hızını değiştir"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Uygulamaya, SurfaceFlinger\'a ait düşük düzey özellikleri kullanma izni verir."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"çerçeve arabelleğini oku"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Uygulamaya, çerçeve arabelleğinin içeriğini okuma izni verir."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger\'a eriş"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Uygulamaya, alt düzey InputFlinger özelliklerini kullanma izni verir."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Kablosuz ekranları yapılandır"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Uygulamaya kablosuz ekranları yapılandırma ve bunlara bağlanma izni verir."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Kablosuz ekranları denetle"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uygulamaya kablosuz ekranların alt düzey özelliklerini kontrol etme izni verir."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ses ayarlarınızı değiştirin"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Uygulamaya ses düzeyi ve ses çıkışı için kullanılan hoparlör gibi genel ses ayarlarını değiştirme izni verir."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ses kaydet"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Uygulamaya, SD karta yazma izni verir."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"dahili medya depolama birimi içeriğini değiştir/sil"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Uygulamaya, dahili medya depolama içeriğini değiştirme izni verir."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"doküman deposunu yönet"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Uygulamaya, doküman deposunu yönetme izni verir."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"tüm kullanıcılar için harici depolama eriş"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Uygulamaya tüm kullanıcılar için harici depolamaya erişim izni verir."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"önbellek dosya sistemine eriş"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Uygulamaya, ağ politikalarını yönetme ve uygulamaya özgü kuralları tanımlama izni verir."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ağ kullanım hesaplamasını değiştir"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"yuva işaretlerini değiştir"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Uygulamaya, yönlendirme için yuva işaretlerini değiştirme izni verir"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"İzin sahibine bir bildirim dinleyici hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operatör tarafından sağlanan yapılandırma uygulamasını çalıştır"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"SIM kartı takın."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM kart yok veya okunamıyor. Bir SIM kart takın."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Kullanılamayan SIM kartı"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kartınız kalıcı olarak devre dışı bırakıldı."\n" Başka bir SIM kart için kablosuz servis sağlayıcınıza başvurun."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kartınız kalıcı olarak devre dışı bırakıldı.\n Başka bir SIM kart için kablosuz servis sağlayıcınıza başvurun."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Önceki parça düğmesi"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Sonraki parça düğmesi"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Duraklat düğmesi"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Kullanıcı Rehberi\'ne bakın veya Müşteri Hizmetleri\'ne başvurun."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kart kilitli."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM kart kilidi açılıyor…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi, Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n"<xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi, Google oturum açma bilgilerinizi kullanarak açmanız istenir.\n\n<xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir.\n\n Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Tablet kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, tablet fabrika varsayılanına sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, telefon fabrika varsayılanına sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tablet kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Tablet şimdi fabrika varsayılanına sıfırlanacak."</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Şifre"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Oturum aç"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Geçersiz kullanıcı adı veya şifre."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?"\n<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?\n"<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Denetleniyor…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Kilit Aç"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sesi aç"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Gezinmeyi Onayla"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Bu Sayfadan Ayrıl"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bu sayfada kal"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Bu sayfadan ayrılmak istediğinizden emin misiniz?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nBu sayfadan ayrılmak istediğinizden emin misiniz?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe vurun."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Maalesef <xliff:g id="APPLICATION">%1$s</xliff:g> durdu."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Maalesef <xliff:g id="PROCESS">%1$s</xliff:g> işlemi durdu."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> yanıt vermiyor."\n\n"Kapatmak ister misiniz?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> yanıt vermiyor."\n\n"Kapatmak ister misiniz?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> yanıt vermiyor.\n\nKapatmak ister misiniz?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> yanıt vermiyor.\n\nKapatmak ister misiniz?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> yanıt vermiyor. Kapatmak ister misiniz?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."\n\n"Kapatmak ister misiniz?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor.\n\nKapatmak ister misiniz?"</string>
     <string name="force_close" msgid="8346072094521265605">"Tamam"</string>
     <string name="report" msgid="4060218260984795706">"Bildir"</string>
     <string name="wait" msgid="7147118217226317732">"Bekle"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sayfa yanıt vermiyor."\n\n"Kapatmak ister misiniz?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sayfa yanıt vermiyor.\n\nKapatmak ister misiniz?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Uygulama yönlendirildi"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"İlk olarak <xliff:g id="APP_NAME">%1$s</xliff:g> başlatıldı."</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Uygulamaya, içerik kopyalamak için varsayılan kapsayıcı hizmetini çağırma izni verir. Normal uygulamaların kullanımına yönelik değildir."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medya çıktısını yönlendir"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Uygulamaya medya çıktısını başka harici cihazlara yönlendirme izni verir."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Tuş kilitli güvenli depolamaya erişim"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Bir uygulamanın tuş kilitli güvenli depolamaya erişimine izin verir."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Tuş koruyucuyu görüntülemeyi ve gizlemeyi kontrol et"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Bir uygulamaya tuş koruyucuyu denetleme izni verir."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Yakınlaştırma denetimi için iki kez dokunun"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget eklenemedi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Git"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Bitti"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Önceki"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Çalıştır"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Numarayı çevir:"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>"\n" ile kişi oluştur"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Numarayı çevir:\n<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>\n ile kişi oluştur"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Aşağıdaki bir veya daha fazla uygulama şimdi ve ileride hesabınıza erişmek için izin istiyor."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Bu isteğe izin vermek istiyor musunuz?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Erişim isteği"</string>
     <string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
     <string name="deny" msgid="2081879885755434506">"Reddet"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"İzin istendi"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> hesabı için"\n"izin isteğinde bulunuldu."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> hesabı için\nizin isteğinde bulunuldu."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Giriş yöntemi"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Senkronizasyon"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Erişebilirlik"</string>
@@ -1441,10 +1474,13 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Bağlanılıyor..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Kullanılabilir"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Yok"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Kullanımda"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Yerleşik Ekran"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI Ekran"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Yer Paylaşımı No. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Kablosuz ekrana bağlandı"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Bu ekran başka bir cihazda gösteriliyor"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Bağlantıyı kes"</string>
@@ -1453,7 +1489,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Yanlış Desen"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Yanlış Şifre"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Yanlış PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> saniye içinde yeniden deneyin."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Deseninizi çizin"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN kodunu girin"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN\'i girin"</string>
@@ -1473,27 +1509,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Şifre"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Oturum aç"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Geçersiz kullanıcı adı veya şifre."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?"\n<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?\n"<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Hesap denetleniyor…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, tablet fabrika varsayılan değerine sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, telefon fabrika varsayılan değerine sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Tablet şimdi fabrika varsayılanına sıfırlanacak."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Telefon şimdi fabrika varsayılanına sıfırlanacak."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kaldır"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ses düzeyi önerilen seviyenin üzerine çıkarılsın mı?"\n"Uzun süre yüksek sesle dinlemek işitme duyunuza zarar verebilir."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ses düzeyi önerilen seviyenin üzerine çıkarılsın mı?\nUzun süre yüksek sesle dinlemek işitme duyunuza zarar verebilir."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Erişilebilirliği etkinleştirmek için iki parmağınızı basılı tutmaya devam edin."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Erişilebilirlik etkinleştirildi."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erişilebilirlik iptal edildi."</string>
     <string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Sahibi"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Hata"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Bu uygulama kısıtlanmış profillerin hesaplarını desteklemez"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Bu uygulama, kısıtlanmış profillerin hesaplarını desteklemez"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Bu eylemi gerçekleştirecek bir uygulama bulunamadı"</string>
     <string name="revoke" msgid="5404479185228271586">"İptal et"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"İptal edildi"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"İçerik yazılırken hata oluştu"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN\'i girin"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Mevcut PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Yeni PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Yeni PIN\'i doğrulayın"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Kısıtlamaları değiştirmek için PIN oluşturun"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'ler eşleşmiyor. Tekrar deneyin."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN çok kısa. En az 4 basamaklı olmalı."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Yanlış PIN. 1 saniye içinde tekrar deneyin."</item>
+    <item quantity="other" msgid="8030607343223287654">"Yanlış PIN. <xliff:g id="COUNT">%d</xliff:g> saniye içinde tekrar deneyin."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d2798ad..751de53 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Програма може робити це без вашого відома."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"керувати стеками дій"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Дозволяє програмі додавати, вилучати та змінювати стеки дій, у яких запущено інші програми. Шкідливі програми можуть переривати роботу інших програм."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"розпочинати будь-які дії"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Дозволяє програмі розпочинати будь-які дії, незалежно від захищеного дозволу або стану експорту."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"установити сумісність екрана"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня методу введення. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"прив’язуватися до служби доступності"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби доступності. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"прив’язуватися до служби друку"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби друку. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"отримувати доступ до всіх завдань друку"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Дозволяє власнику отримувати доступ до завдань друку, створених в іншій програмі. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"прив’язуватися до служби NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Дозволяє власникові прив’язуватися до програм, які емулюють картки NFC. Ніколи не використовується звичайними програмами."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"прив’язати до текстової служби"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня текстової служби (напр. SpellCheckerService). Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"прив’язуватися до служби VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дозволяє програмі будь-коли змінювати обертання екрана. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змінювати швидкість указівника"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дозволяє програмі використовувати низькорівневі функції SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"читати фрейм-буфер"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дозволяє програмі читати вміст буфера кадрів."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"отримувати доступ до InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Дозволяє програмі використовувати низькорівневі функції InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"налаштувати екрани Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозволяє програмі налаштовувати екрани Wi-Fi і під’єднуватися до них."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"керувати екранами Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозволяє програмі керувати низькорівневими функціями екранів Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змінювати налаштув-ня звуку"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дозволяє програмі змінювати загальні налаштування звуку, як-от гучність і динамік, який використовується для виводу сигналу."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"запис-ти аудіо"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозволяє програмі записувати на карту SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змінювати/видаляти вміст внутр. сховища даних"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дозволяє програмі змінювати вміст внутрішнього сховища даних."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"керувати зберіганням"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Дозволяє програмі керувати зберіганням документів."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"доступ до зовн. пам’яті всіх корист."</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Дозволяє програмі отримувати доступ до зовнішньої пам’яті всіх користувачів."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"отр. дост. до файл. сист. кешу"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозволяє програмі керувати політикою мережі та визначити спеціальні правила для програм."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змінювати облік використання мережі"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"змінювати мітки сокетів"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Дозволяє програмі змінювати мітки сокетів для маршрутизації"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Вставте SIM-карту."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта відсутня або недоступна для читання. Вставте SIM-карту."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Непридатна SIM-карта."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Вашу SIM-карту вимкнено назавжди."\n" Зверніться до свого постачальника послуг бездротового зв’язку, щоб отримати іншу SIM-карту."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Вашу SIM-карту вимкнено назавжди.\n Зверніться до свого постачальника послуг бездротового зв’язку, щоб отримати іншу SIM-карту."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Кнопка \"Попередня доріжка\""</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Кнопка \"Наступна доріжка\""</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Кнопка \"Призупинити\""</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Перегляньте посібник користувача чи зверніться до служби підтримки."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карту заблок-но."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Розблокув. SIM-карти…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>."\n\n"Повторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>."\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>. Ваш планшетний ПК потрібно буде розблокувати за допомогою входу в Google після ще стількох неуспішних спроб: <xliff:g id="NUMBER_1">%d</xliff:g>."\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>. Ваш телефон потрібно буде розблокувати за допомогою входу в Google після ще стількох неуспішних спроб: <xliff:g id="NUMBER_1">%d</xliff:g>."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>.\n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>.\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>. Ваш планшетний ПК потрібно буде розблокувати за допомогою входу в Google після ще стількох неуспішних спроб: <xliff:g id="NUMBER_1">%d</xliff:g>.\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>. Ваш телефон потрібно буде розблокувати за допомогою входу в Google після ще стількох неуспішних спроб: <xliff:g id="NUMBER_1">%d</xliff:g>.\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_now_wiping" product="tablet" msgid="280873516493934365">"Кількість невдалих спроб розблокувати пристрій: <xliff:g id="NUMBER">%d</xliff:g>. Налаштування пристрою буде змінено на заводські за умовчанням."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Увійти"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Недійсне ім\'я корист. чи пароль."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Не пам’ятаєте ім’я користувача чи пароль?"\n"Відвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Не пам’ятаєте ім’я користувача чи пароль?\nВідвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Перевірка…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Розблок."</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Увімк. звук"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Підтвердити перехід"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Полишити цю сторінку"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Залишитися на цій сторінці"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Справді полишити цю сторінку?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nСправді полишити цю сторінку?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Підтверд."</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Порада: двічі торкніться для збільшення чи зменшення."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автозап."</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"На жаль, програма <xliff:g id="APPLICATION">%1$s</xliff:g> припинила роботу."</string>
     <string name="aerr_process" msgid="4507058997035697579">"На жаль, програма <xliff:g id="PROCESS">%1$s</xliff:g> припинила роботу."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Програма <xliff:g id="APPLICATION">%2$s</xliff:g> не відповідає."\n\n"Закрити її?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Дія <xliff:g id="ACTIVITY">%1$s</xliff:g> не відповідає."\n\n"Закінчити її?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Програма <xliff:g id="APPLICATION">%2$s</xliff:g> не відповідає.\n\nЗакрити її?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Дія <xliff:g id="ACTIVITY">%1$s</xliff:g> не відповідає.\n\nЗакінчити її?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> не відповідає. Закрити її?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> не відповідає."\n\n"Завершити його?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> не відповідає.\n\nЗавершити його?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Повідом."</string>
     <string name="wait" msgid="7147118217226317732">"Чекати"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Сторінка не відповідає."\n\n"Закрити її?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Сторінка не відповідає.\n\nЗакрити її?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Програму переадресовано"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Зараз працює <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Спочатку було запущено <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дозволяє програмі викликати службу контейнерів за умовчанням для копіювання вмісту. Не для використання звичайними програмами."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Скеровувати вивід медіа-даних"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Дозволяє програмі скеровувати вивід медіа-даних на інші зовнішні пристрої."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Отримувати доступ до безпечного сховища через клавіатуру"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дозволяє програмі отримувати доступ до безпечного сховища через клавіатуру."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Керувати відображенням і хованням клавіатури"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозволяє програмі керувати клавіатурою."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двічі торкніться, щоб керувати масштабом"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Не вдалося додати віджет."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Йти"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Готово"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Назад"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Запустити"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Набр. номер"\n" викор. <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Створ. контакт"\n" викор. <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Набр. номер\n викор. <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Створ. контакт\n викор. <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Указані нижче програми запитують дозвіл на доступ до вашого облікового запису зараз і в майбутньому."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Дозволити цей запит?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Запит на доступ"</string>
     <string name="allow" msgid="7225948811296386551">"Дозвол."</string>
     <string name="deny" msgid="2081879885755434506">"Забор."</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Потрібен дозвіл"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запитано дозвіл"\n"для облікового запису <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запитано дозвіл\nдля облікового запису <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Метод введення"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Синхр."</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Доступність"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"З’єднання..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Доступно"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Недоступно"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Використовується"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Вбудований екран"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Екран HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Накладання №<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>х<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", фіксована"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Бездротовий екран під’єднано"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Цей екран відображається на іншому пристрої"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Від’єднати"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильний ключ"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Неправильний пароль"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Неправильний PIN-код"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторіть спробу через <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторіть спробу через <xliff:g id="NUMBER">%1$d</xliff:g> с."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйте ключ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введіть PIN-код SIM-карти"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Введіть PIN-код"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Увійти"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Недійсне ім’я користувача чи пароль."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Не пам’ятаєте ім’я користувача чи пароль?"\n"Відвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Не пам’ятаєте ім’я користувача чи пароль?\nВідвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Перевірка облікового запису…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Вилучити"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Збільшити гучність понад рекомендований рівень?"\n"Якщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Збільшити гучність понад рекомендований рівень?\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утримуйте двома пальцями, щоб увімкнути доступність."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Доступність увімкнено."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Доступність скасовано."</string>
     <string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Власник"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Помилка"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ця програма не підтримує облікові записи для обмежених профілів"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ця програма не підтримує облікові записи для обмежених профілів"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Не знайдено програму для обробки цієї дії"</string>
     <string name="revoke" msgid="5404479185228271586">"Анулювати"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Скасовано"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Помилка записування вмісту"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Введіть PIN-код"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Поточний PIN-код"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Новий PIN-код"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Підтвердьте новий PIN-код"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Створіть PIN-код для змінення обмежень"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Неправильний PIN. Повторіть через 1 с."</item>
+    <item quantity="other" msgid="8030607343223287654">"Неправильний PIN. Повторіть через <xliff:g id="COUNT">%d</xliff:g> с."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index d4d17a6..56f9320 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Cho phép ứng dụng di chuyển công việc sang nền trước và nền sau. Ứng dụng có thể thực hiện việc này mà không cần bạn nhập."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"dừng các ứng dụng đang chạy"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Cho phép ứng dụng xóa công việc và loại bỏ các ứng dụng của chúng. Ứng dụng độc hại có thể làm gián đoạn hoạt động của các ứng dụng khác."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"quản lý ngăn xếp hoạt động"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Cho phép ứng dụng thêm, xóa và sửa đổi ngăn xếp hoạt động nơi các ứng dụng khác chạy. Ứng dụng độc hại có thể làm gián đoạn hoạt động của các ứng dụng khác."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"bắt đầu mọi hoạt động"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Cho phép ứng dụng bắt đầu mọi hoạt động, bất kể tình trạng bảo vệ quyền hay trạng thái xuất."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"đặt độ tương thích màn hình"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của phương thức nhập. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"liên kết với dịch vụ truy cập"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"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ụ truy cập. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"liên kết với dịch vụ in"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"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ụ in. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"truy cập tất cả các lệnh in"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Cho phép chủ sở hữu truy cập các lệnh in được tạo ra bởi ứng dụng khác. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"liên kết với dịch vụ NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Cho phép chủ sở hữu liên kết với ứng dụng đang mô phỏng thẻ NFC. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"liên kết với dịch vụ văn bản"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"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ụ văn bản (ví dụ: SpellCheckerService). Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"liên kết với dịch vụ VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"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ụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"thêm hoặc xóa quản trị viên thiết bị"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Cho phép chủ sở hữu thêm hoặc xóa quản trị viên thiết bị đang hoạt động. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Cho phép ứng dụng thay đổi độ xoay màn hình bất cứ lúc nào. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"thay đổi tốc độ con trỏ"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Cho phép ứng dụng sử dụng các tính năng SurfaceFlinger cấp độ thấp."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"đọc bộ đệm khung"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Cho phép ứng dụng đọc nội dung của bộ đệm khung."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"truy cập InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Cho phép ứng dụng sử dụng các tính năng InputFlinger cấp độ thấp."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"định cấu hình màn hình Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Cho phép ứng dụng định cấu hình và kết nối với màn hình Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kiểm soát màn hình Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Cho phép ứng dụng kiểm soát các tính năng cấp thấp của màn hình Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"thay đổi cài đặt âm thanh của bạn"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Cho phép ứng dụng sửa đổi cài đặt âm thanh chung chẳng hạn như âm lượng và loa nào được sử dụng cho thiết bị ra."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ghi âm"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Cho phép ứng dụng ghi vào thẻ SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sửa đổi/xóa nội dung trên bộ nhớ phương tiện cục bộ"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Cho phép ứng dụng sửa đổi nội dung của bộ lưu trữ phương tiện nội bộ."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"quản lý bộ nhớ tài liệu"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Cho phép ứng dụng quản lý bộ nhớ tài liệu."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"truy cập bộ nhớ ngoài của tất cả người dùng"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Cho phép ứng dụng truy cập bộ nhớ ngoài của tất cả người dùng."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"truy cập hệ thống tệp bộ nhớ cache"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Cho phép ứng dụng quản lý chính sách mạng và xác định quy tắc dành riêng cho ứng dụng."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"sửa đổi hạch toán sử dụng mạng"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Cho phép ứng dụng sửa đổi cách tính mức sử dụng mạng so với ứng dụng. Không dành cho các ứng dụng thông thường."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"sửa đổi nhãn ổ cắm"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Cho phép ứng dụng sửa đổi nhãn ổ cắm để định tuyến"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"truy cập thông báo"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"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ụ trình xử lý thông báo. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Cho phép chủ sở hữu gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Hãy lắp thẻ SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Thẻ SIM bị thiếu hoặc không thể đọc được. Vui lòng lắp thẻ SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Thẻ SIM không sử dụng được."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Thẻ SIM của bạn đã bị vô hiệu hóa vĩnh viễn ."\n" Hãy liên hệ với nhà cung cấp dịch vụ không dây của bạn để lấy thẻ SIM khác."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Thẻ SIM của bạn đã bị vô hiệu hóa vĩnh viễn .\n Hãy liên hệ với nhà cung cấp dịch vụ không dây của bạn để lấy thẻ SIM khác."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Nút bài hát trước"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Nút bài hát tiếp theo"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Nút tạm dừng"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Vui lòng xem Hướng dẫn người dùng hoặc liên hệ với Bộ phận chăm sóc khách hàng."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Thẻ SIM đã bị khóa."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Đang mở khóa thẻ SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. "\n\n"Vui lòng thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Bạn đã nhập sai mã PIN <xliff:g id="NUMBER_0">%d</xliff:g> lần. "\n\n"Hãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng thông tin đăng nhập Google của mình."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng thông tin đăng nhập Google của bạn."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. \n\nVui lòng thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Bạn đã nhập sai mã PIN <xliff:g id="NUMBER_0">%d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng thông tin đăng nhập Google của mình.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng thông tin đăng nhập Google của bạn.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Bạn đã mở khóa máy tính bảng không đúng cách <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Bạn đã mở khóa điện thoại không đúng cách <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, điện thoại sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Bạn đã mở khóa máy tính bảng không đúng cách <xliff:g id="NUMBER">%d</xliff:g> lần. Bây giờ, máy tính bảng sẽ được đặt lại về mặc định ban đầu."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Mật khẩu"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Đăng nhập"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Tên người dùng hoặc mật khẩu không hợp lệ."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Bạn quên tên người dùng hoặc mật khẩu?"\n"Hãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Bạn quên tên người dùng hoặc mật khẩu?\nHãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Đang kiểm tra…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Mở khóa"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Bật âm thanh"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Xác nhận điều hướng"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Rời khỏi trang này"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Ở lại trang này"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Bạn có chắc chắn muốn điều hướng khỏi trang này không?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nBạn có chắc chắn muốn điều hướng khỏi trang này không?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Xác nhận"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Mẹo: Nhấn đúp để phóng to và thu nhỏ."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Tự động điền"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Rất tiếc, <xliff:g id="APPLICATION">%1$s</xliff:g> đã dừng lại."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Rất tiếc, quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã dừng lại."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> hiện không phản hồi."\n\n"Bạn có muốn đóng ứng dụng này không?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Hoạt động <xliff:g id="ACTIVITY">%1$s</xliff:g> không phản hồi."\n\n"Bạn có muốn đóng ứng dụng này không?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> hiện không phản hồi.\n\nBạn có muốn đóng ứng dụng này không?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Hoạt động <xliff:g id="ACTIVITY">%1$s</xliff:g> không phản hồi.\n\nBạn có muốn đóng ứng dụng này không?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> hiện không phản hồi. Bạn có muốn đóng ứng dụng không?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> hiện không phản hồi."\n\n"Bạn có muốn đóng ứng dụng này không?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> hiện không phản hồi.\n\nBạn có muốn đóng ứng dụng này không?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Báo cáo"</string>
     <string name="wait" msgid="7147118217226317732">"Đợi"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Trang không phản hồi."\n\n"Bạn có muốn đóng trang không?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Trang không phản hồi.\n\nBạn có muốn đóng trang không?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Đã chuyển hướng ứng dụng"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Cho phép ứng dụng gọi ra dịch vụ bộ chứa mặc định để sao chép nội dung. Không dành cho ứng dụng thông thường."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Định tuyến thiết bị ra phương tiện"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Cho phép ứng dụng định tuyến thiết bị ra phương tiện đến các thiết bị bên ngoài khác."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Truy cập bộ nhớ an toàn khóa bàn phím"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Cho phép ứng dụng truy cập bộ nhớ an toàn khóa"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Kiểm soát việc hiển thị và ẩn tính năng bảo vệ phím"</string>
+    <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="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Chạm hai lần để kiểm soát thu phóng"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Không thể thêm tiện ích."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Đến"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Xong"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Trước"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Thực hiện"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Quay số"\n"sử dụng <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Tạo liên hệ"\n"sử dụng <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Quay số\nsử dụng <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Tạo liên hệ\nsử dụng <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Một hoặc nhiều ứng dụng sau đây yêu cầu quyền truy cập vào tài khoản của bạn, hiện tại và trong tương lai."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Bạn có muốn cho phép yêu cầu này không?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Yêu cầu truy cập"</string>
     <string name="allow" msgid="7225948811296386551">"Cho phép"</string>
     <string name="deny" msgid="2081879885755434506">"Từ chối"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Đã yêu cầu quyền"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Đã yêu cầu quyền"\n"cho tài khoản <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Đã yêu cầu quyền\ncho tài khoản <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Phương thức nhập"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Đồng bộ hóa"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Khả năng truy cập"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Đang kết nối..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Khả dụng"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Không khả dụng"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Đang được sử dụng"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Màn hình tích hợp"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Màn hình HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Lớp phủ #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", an toàn"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Hiển thị không dây đã được kết nối"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Màn hình này đang hiển thị trên thiết bị khác"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Ngắt kết nối"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Hình sai"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Mật khẩu sai"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN sai"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Hãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Hãy thử lại sau <xliff:g id="NUMBER">%1$d</xliff:g> giây."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Vẽ hình của bạn"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Nhập PIN của SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Nhập PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Mật khẩu"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Đăng nhập"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Tên người dùng hoặc mật khẩu không hợp lệ."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bạn quên tên người dùng hoặc mật khẩu?"\n"Hãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bạn quên tên người dùng hoặc mật khẩu?\nHãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Đang kiểm tra tài khoản…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần mở khóa máy tính bảng không đúng cách. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần mở khóa điện thoại không đúng cách. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, điện thoại sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Bạn đã <xliff:g id="NUMBER">%d</xliff:g> lần mở khóa máy tính bảng không đúng cách. Bây giờ, máy tính bảng sẽ được đặt lại về mặc định ban đầu."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Bạn đã <xliff:g id="NUMBER">%d</xliff:g> lần mở khóa điện thoại không đúng cách. Bây giờ, điện thoại sẽ được đặt lại về mặc định ban đầu."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Xóa"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Tăng âm lượng trên mức được đề xuất?"\n"Nghe ở mức âm lượng cao trong thời gian dài có thể gây hại cho thính giác của bạn."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Tăng âm lượng trên mức được đề xuất?\nNghe ở mức âm lượng cao trong thời gian dài có thể gây hại cho thính giác của bạn."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tiếp tục giữ hai ngón tay để bật trợ năng."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Trợ năng đã được bật."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Đã hủy trợ năng."</string>
     <string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Chủ sở hữu"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Lỗi"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Ứng dụng này không hỗ trợ tài khoản cho các tiểu sử bị hạn chế"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ứng dụng này không hỗ trợ tài khoản đối với các tiểu sử bị hạn chế"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Không tìm thấy ứng dụng nào để xử lý tác vụ này"</string>
     <string name="revoke" msgid="5404479185228271586">"Thu hồi"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Thư"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Thư của chính phủ"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legal khổ nhỏ"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Sổ cái"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Đã hủy"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Lỗi ghi nội dung"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Nhập mã PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Mã PIN hiện tại"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Mã PIN mới"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Xác nhận mã PIN mới"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Tạo mã PIN để hạn chế sửa đổi"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Mã PIN không khớp. Hãy thử lại."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Mã PIN quá ngắn. Phải có ít nhất 4 chữ số."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Mã PIN không đúng. Hãy thử lại sau 1 giây nữa."</item>
+    <item quantity="other" msgid="8030607343223287654">"Mã PIN không đúng. Hãy thử lại sau <xliff:g id="COUNT">%d</xliff:g> giây nữa."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 2c23f8f..161db91 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"允许该应用将任务移动到前台和后台。该应用可能不经您的命令自行执行此操作。"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"停止正在运行的应用"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"允许该应用删除任务并终止这些任务的应用。恶意应用可以籍此影响其他应用的行为。"</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"管理活动栈"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"允许应用添加、删除和修改其他应用的运行活动栈。恶意应用可以籍此影响其他应用的行为。"</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"启动任何活动"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"允许该应用启动任何活动(不考虑权限保护或导出状态)。"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"设置屏幕兼容性"</string>
@@ -356,6 +358,14 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"允许用户绑定至输入法的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"绑定至辅助服务"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"允许应用绑定至辅助服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"绑定至打印服务"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"允许应用绑定至打印服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"查看或修改所有打印作业"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"允许应用查看或修改其他应用创建的打印作业。普通应用绝不需要此权限。"</string>
+    <!-- no translation found for permlab_bindNfcService (2752731300419410724) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNfcService (6120647629174066862) -->
+    <skip />
     <string name="permlab_bindTextService" msgid="7358378401915287938">"绑定至文字服务"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"允许用户绑定至文字服务(如 SpellCheckerService)的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"绑定到 VPN 服务"</string>
@@ -366,6 +376,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许用户将意向发送给设备管理员。普通应用绝不需要此权限。"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"添加或删除设备管理员"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允许应用添加或删除有效的设备管理员。普通应用绝不需要此权限。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"允许应用随时更改屏幕的旋转状态。普通应用绝不需要此权限。"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"更改指针速度"</string>
@@ -458,10 +470,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"允许应用使用 SurfaceFlinger 低级功能。"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"读取帧缓冲区"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"允许应用读取帧缓冲区的内容。"</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"使用 InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"允许应用使用 InputFlinger 底层功能。"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"配置 WLAN 显示设备"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允许应用配置并连接到 WLAN 显示设备。"</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制 WLAN 显示设备"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允许应用控制 WLAN 显示设备的基础功能。"</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"更改您的音频设置"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"允许该应用修改全局音频设置,例如音量和用于输出的扬声器。"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"录音"</string>
@@ -613,6 +637,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"允许应用写入 SD 卡。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"修改/删除内部媒体存储设备的内容"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"允许应用修改内部媒体存储设备的内容。"</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"管理文档存储空间"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"允许应用管理文档存储空间。"</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"访问所有用户的外部存储设备"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"允许应用访问所有用户的外部存储设备。"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"访问缓存文件系统"</string>
@@ -625,10 +651,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允许应用管理网络政策和定义专门针对应用的规则。"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改网络使用情况记录方式"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"修改套接字标记"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"允许应用修改用于路由的套接字标记"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"访问通知"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -738,8 +768,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"雅虎"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"环聊"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -796,7 +825,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"请插入 SIM 卡"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM 卡缺失或无法读取。请插入 SIM 卡。"</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM 卡无法使用。"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的 SIM 卡已永久停用。"\n"请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的 SIM 卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"“上一曲目”按钮"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"“下一曲目”按钮"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"“暂停”按钮"</string>
@@ -808,11 +837,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"请参阅《用户指南》或与客服人员联系。"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡被锁定"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"正在解锁 SIM 卡..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
-    <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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
+    <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_now_wiping" product="tablet" msgid="280873516493934365">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁平板电脑。平板电脑现在将重置为出厂默认设置。"</string>
@@ -826,7 +855,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"密码"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"登录"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"用户名或密码无效。"</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"忘记了用户名或密码?"\n"请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"忘记了用户名或密码?\n请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"正在检查..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"解锁"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"打开声音"</string>
@@ -874,7 +903,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"确认离开"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"离开此页"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"留在此页"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"您确定要离开此页面吗?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n您确定要离开此页面吗?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"确认"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"提示:点按两次可放大或缩小。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自动填充"</string>
@@ -1080,14 +1109,14 @@
     <string name="aerr_application" msgid="932628488013092776">"很抱歉,“<xliff:g id="APPLICATION">%1$s</xliff:g>”已停止运行。"</string>
     <string name="aerr_process" msgid="4507058997035697579">"抱歉,进程“<xliff:g id="PROCESS">%1$s</xliff:g>”已停止运行。"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 无响应。"\n\n"要将其关闭吗?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 活动无响应。"\n\n"要将其关闭吗?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 无响应。\n\n要将其关闭吗?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 活动无响应。\n\n要将其关闭吗?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> 无响应。要将其关闭吗?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> 进程无响应。"\n\n"要将其关闭吗?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> 进程无响应。\n\n要将其关闭吗?"</string>
     <string name="force_close" msgid="8346072094521265605">"确定"</string>
     <string name="report" msgid="4060218260984795706">"报告"</string>
     <string name="wait" msgid="7147118217226317732">"等待"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"该网页已无响应。"\n\n"要将其关闭吗?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"该网页已无响应。\n\n要将其关闭吗?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"应用已重定向"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前正在运行。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>已启动。"</string>
@@ -1256,6 +1285,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"允许应用调用默认的容器服务,以便复制内容。普通应用不应使用此权限。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"更改媒体输出线路"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允许该应用将媒体输出线路更改到其他外部设备。"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"访问密钥保护安全存储空间"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允许应用访问密钥保护安全存储空间。"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"控制是显示还是隐藏锁屏"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"允许应用控制锁屏。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"触摸两次可进行缩放控制"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"无法添加小部件。"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"开始"</string>
@@ -1265,15 +1298,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"完成"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"上一页"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"执行"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"拨打电话"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"创建电话号码为"\n"<xliff:g id="NUMBER">%s</xliff:g> 的联系人"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"拨打电话\n<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"创建电话号码为\n<xliff:g id="NUMBER">%s</xliff:g> 的联系人"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"以下一个或多个应用请求获得相应权限,以便在当前和以后访问您的帐户。"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"您是否同意此请求?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"访问权限请求"</string>
     <string name="allow" msgid="7225948811296386551">"允许"</string>
     <string name="deny" msgid="2081879885755434506">"拒绝"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"权限请求"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"应用对帐户 <xliff:g id="ACCOUNT">%s</xliff:g>"\n" 提出权限请求。"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"应用对帐户 <xliff:g id="ACCOUNT">%s</xliff:g>\n 提出权限请求。"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"输入法"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"同步"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"辅助功能"</string>
@@ -1441,10 +1474,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"正在连接..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"可连接"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"无法连接"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"正在使用"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"内置屏幕"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI 屏幕"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"叠加视图 #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">",安全"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"已连接到无线显示设备"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"此屏幕的内容正显示在另一台设备上"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"断开连接"</string>
@@ -1453,7 +1488,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"图案错误"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"密码错误"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%1$d</xliff:g> 秒后重试。"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string>
@@ -1473,27 +1508,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"密码"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"登录"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"用户名或密码无效。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘记了用户名或密码?"\n"请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘记了用户名或密码?\n请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"正在检查帐户…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。"\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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。\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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"将音量调高到推荐级别以上?"\n"长时间聆听高音量可能会损伤听力。"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"将音量调高到推荐级别以上?\n长时间聆听高音量可能会损伤听力。"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用辅助功能。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"辅助功能已启用。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消辅助功能。"</string>
     <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="owner_name" msgid="2716755460376028154">"机主"</string>
     <string name="error_message_title" msgid="4510373083082500195">"错误"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"此应用不支持受限个人资料的帐户"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"此应用不支持受限个人资料的帐户"</string>
     <string name="app_not_found" msgid="3429141853498927379">"找不到可处理此操作的应用"</string>
     <string name="revoke" msgid="5404479185228271586">"撤消"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"已取消"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"写入内容时出错"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"输入 PIN 码"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"当前 PIN 码"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"新 PIN 码"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"确认新 PIN 码"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"创建 PIN 码,防止他人修改限制条件"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN 码不符,请重试。"</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN 码太短,至少应包含 4 位数字。"</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN 码错误。请在1秒钟后重试。"</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN 码错误。请在<xliff:g id="COUNT">%d</xliff:g>秒钟后重试。"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6bf2bf9..cab9de0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"允許應用程式將工作移至前景或背景。應用程式可以自行處理,不待您操作。"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"停止執行中的應用程式"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"允許應用程式移除工作並終止執行工作的應用程式。請注意,惡意應用程式可能利用此功能干擾其他應用程式的行為。"</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"管理活動堆疊"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"允許應用程式新增、移除及修改可供其他應用程式在其中執行的活動堆疊 (惡意應用程式可能藉此干擾其他應用程式的行為)。"</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"啟動任何活動"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"不論權限保護或匯出狀態為何,一律允許應用程式啟動任何活動。"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"設定螢幕相容性"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"允許應用程式繫結至輸入法的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"繫結至協助工具服務"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"允許應用程式繫結至協助工具服務的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"繫結至列印服務"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"允許應用程式繫結至列印服務的頂層介面 (一般應用程式並不需要)。"</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"存取所有列印工作"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"允許應用程式存取其他應用程式所建立的列印工作 (一般應用程式並不需要)。"</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"繫結至 NFC 服務"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"允許應用程式繫結至模擬 NFC 卡的應用程式 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"繫結至文字服務"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"允許應用程式繫結至文字服務 (例如 SpellCheckerService) 的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"繫結至 VPN 服務"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (一般應用程式並不需要)。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"允許應用程式隨時變更螢幕旋轉狀態 (一般應用程式不需使用)。"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"變更指標速度"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"允許應用程式使用 SurfaceFlinger 的低階功能。"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"讀取框架緩衝"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"允許應用程式讀取畫面緩衝區的內容。"</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"存取 InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"允許應用程式使用 InputFlinger 的低階功能。"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"設定 Wi-Fi 顯示裝置"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允許應用程式設定及連接 Wi-Fi 顯示裝置。"</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制 Wi-Fi 顯示裝置"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 Wi-Fi 顯示裝置的低階功能。"</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"變更音訊設定"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"允許應用程式修改全域音訊設定,例如音量和用來輸出的喇叭。"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"錄製音訊"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"允許應用程式寫入 SD 卡。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"修改/刪除內部媒體儲存裝置內容"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"允許應用程式修改內部媒體儲存空間的內容。"</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"管理文件儲存空間"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"允許應用程式管理文件儲存空間。"</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"存取外部儲存空間 (所有使用者)"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"允許應用程式存取外部儲存空間 (所有使用者)。"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"存取快取檔案系統"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允許應用程式管理網路政策並定義應用程式專用規則。"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改網路使用量計算方式"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允許應用程式修改應用程式網路使用量的計算方式 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"修改通訊端標記"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"允許應用程式修改路由的通訊端標記"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"存取通知"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"叫用行動通訊業者提供的設定應用程式"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"網路會議"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"插入 SIM 卡。"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"找不到或無法讀取 SIM 卡。請插入 SIM 卡。"</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM 卡無法使用。"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的 SIM 卡已遭永久停用。"\n"請與您的無線網路服務供應商聯絡,以取得其他 SIM 卡。"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的 SIM 卡已遭永久停用。\n請與您的無線網路服務供應商聯絡,以取得其他 SIM 卡。"</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"[上一首曲目] 按鈕"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"[下一首曲目] 按鈕"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"[暫停] 按鈕"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"參閱《使用者指南》或與客戶服務中心聯絡。"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡已鎖定。"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"解鎖 SIM 卡中…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n"請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"您的密碼已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n"請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"您的 PIN 已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\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_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"您的密碼已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"您的 PIN 已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\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_now_wiping" product="tablet" msgid="280873516493934365">"您嘗試解除這個平板電腦的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次,平板電腦現在將恢復原廠設定。"</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"密碼"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"登入"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"使用者名稱或密碼錯誤。"</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"忘了使用者名稱或密碼?"\n"請造訪 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"忘了使用者名稱或密碼?\n請造訪 "<b>"google.com/accounts/recovery"</b>"。"</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"檢查中…"</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"解除封鎖"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"開啟音效"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"確認瀏覽"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"離開這一頁"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"停留在這一頁"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"您確定要前往其他網頁瀏覽嗎?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n您確定要前往其他網頁瀏覽嗎?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"提示:輕按兩下即可縮放。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自動填入功能"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g> 已停止。"</string>
     <string name="aerr_process" msgid="4507058997035697579">"很抱歉,處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已停止。"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 沒有回應。"\n\n"您要結束嗎?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 活動沒有回應。"\n\n"您要結束嗎?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 沒有回應。\n\n您要結束嗎?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 活動沒有回應。\n\n您要結束嗎?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> 沒有回應。您要結束嗎?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> 處理程序沒有回應。"\n\n"您要結束嗎?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"<xliff:g id="PROCESS">%1$s</xliff:g> 處理程序沒有回應。\n\n您要結束嗎?"</string>
     <string name="force_close" msgid="8346072094521265605">"確定"</string>
     <string name="report" msgid="4060218260984795706">"回報"</string>
     <string name="wait" msgid="7147118217226317732">"等待"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"網頁沒有回應。"\n\n"您要結束嗎?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"網頁沒有回應。\n\n您要結束嗎?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"應用程式已重新導向"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在正在執行。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」原先已啟動。"</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"允許觸發預設容器服務,以便複製內容 (不建議一般應用程式使用)。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"轉送媒體輸出"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允許應用程式將媒體輸出轉送至其他外部裝置。"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"存取 Keyguard 安全儲存空間"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允許應用程式存取 Keyguard 安全儲存空間。"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"控制鍵盤鎖的顯示和隱藏"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"允許應用程式控制鍵盤鎖。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"輕觸兩下即可控制縮放"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"無法新增小工具。"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"開始"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"完成"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"上一步"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"執行"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"使用 <xliff:g id="NUMBER">%s</xliff:g>"\n"撥號"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"建立手機號碼為 <xliff:g id="NUMBER">%s</xliff:g>"\n"的聯絡人"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"使用 <xliff:g id="NUMBER">%s</xliff:g>\n撥號"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"建立手機號碼為 <xliff:g id="NUMBER">%s</xliff:g>\n的聯絡人"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"下列一或多個應用程式要求取得今後都可存取您帳戶的權限。"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"您確定要允許這個要求嗎?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"存取權限要求"</string>
     <string name="allow" msgid="7225948811296386551">"允許"</string>
     <string name="deny" msgid="2081879885755434506">"拒絕"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"已要求權限"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"帳戶 <xliff:g id="ACCOUNT">%s</xliff:g> 已提出"\n"權限要求。"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"帳戶 <xliff:g id="ACCOUNT">%s</xliff:g> 已提出\n權限要求。"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"輸入法"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"同步處理"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"協助工具"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"連線中…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"可以使用"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"無法使用"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"使用中"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"內建畫面"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI 螢幕"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"第 <xliff:g id="ID">%1$d</xliff:g> 個重疊效果"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"(安全)"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"已連接無線顯示器"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"其他裝置正在顯示這個畫面"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"中斷連線"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖形錯誤"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"密碼錯誤"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 錯誤"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"請在 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"請在 <xliff:g id="NUMBER">%1$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"畫出圖形"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"輸入 SIM PIN"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"輸入 PIN"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"使用者名稱或密碼無效。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘了使用者名稱或密碼?"\n"請前往 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘了使用者名稱或密碼?\n請前往 "<b>"google.com/accounts/recovery"</b>"。"</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您的 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_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_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>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <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>
+    <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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <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>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽高音量可能會損害您的聽力。"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?\n長時間聆聽高音量可能會損害您的聽力。"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持續用兩指按住即可啟用協助工具。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
     <string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="owner_name" msgid="2716755460376028154">"擁有者"</string>
     <string name="error_message_title" msgid="4510373083082500195">"錯誤"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"這個應用程式不支援設有限制的個人資料所屬帳戶"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"這個應用程式不支援設有限制的個人資料所屬帳戶"</string>
     <string name="app_not_found" msgid="3429141853498927379">"找不到支援此操作的應用程式"</string>
     <string name="revoke" msgid="5404479185228271586">"撤銷"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"已取消"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"寫入內容時發生錯誤"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"輸入 PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"目前的 PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"新 PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"確認新 PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"建立修改限制所需的 PIN"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN 不符,請再試一次。"</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN 長度太短,至少必須為 4 位數。"</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN 不正確,請於 1 秒後再試一次。"</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN 不正確,請於 <xliff:g id="COUNT">%d</xliff:g> 秒後再試一次。"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 28cefb8..792d40e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -279,6 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ivumela uhlelo lokusebenza ukugudluza imisebenzi ngaphambili nangasemuva. Uhlelo lokusebenza lungenza lokhu ngaphandle kwakho."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"phatha izitaki zomsebenzi"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ivumela uhlelo lokusebenza ukuthi lingeze, lisuse, noma lilungise izitaki zomsebenzi lapho ezinye izinhlelo zokusebenza ziqalisa khona. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ukuziphatha kwezinye izinhlelo zokusebenza."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"qala noma imuphi umsebenzi"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ivumela uhlelo lokusebenza ukuqala umsebenzi, ngaphandle kokuvukeleka kwemvume noma isimo sokukhishiwe."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string>
@@ -356,6 +358,12 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ivumela isimeli ukuhlanganisa uxhumano nomsebenzisi wezinga eliphezulu lendlela yokufaka. Ayisoze yadingeka kwizinhlelo ezivamile."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"hlanganisa kusevisi yokufinyeleleka"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ivumela isibambi ukuhlanganisa uxhumo nomsebenzisi kwezinga eliphezulu lesevisi yesinqunjwana. Akusoze kwadingekela izinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"bophezela kusevisi yokuphrinta"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ivumela umnikazi ukuthi abophezele isixhumanisi esibonakalayo sezinga eliphezulu sesevisi lokuphrinta. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"finyelela kuyo yonke imisebenzi yokuphrinta"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ivumela umnikazi ukuthi afinyelele imisebenzi yokushicilela edalwe olunye uhlelo lokusebenza. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+    <string name="permlab_bindNfcService" msgid="2752731300419410724">"bophezela kusevisi ye-NFC"</string>
+    <string name="permdesc_bindNfcService" msgid="6120647629174066862">"Ivumela umnikazi ukuthi abophezele izinhlelo zokusebenza ezifana namakhadi we-NFC. Akumele idingeke kuzinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bophezela kunsizakalo yombhalo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwesixhumi esibonakalayo sensizakalo yombhalo(isb. InsizakaloYokuhlolaUkubhala). Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"hlanganisa kwinsizakalo ye-VPN"</string>
@@ -366,6 +374,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string>
+    <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela insiza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinsiza ezejwayelekile."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"guqula isivinini sesikhombi"</string>
@@ -458,10 +468,22 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela insiza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"funda isikhumbuli sesikhashana sendikimba"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela insiza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string>
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"finyelela ku-InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ivumela uhlelo lokusebenza ukuthi lusebenzise izici zezinga eliphansi ze-InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"lungisa ukubukwa kwe-Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ivumela uhlelo lokusebenza ukulungisa nokuxhuma ekubukisweni kwe-Wi-Fi."</string>
-    <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"lawula ukubukwa kwe-Wi-Fi"</string>
-    <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uvumela uhlelo lokusebenza ukulawula izici zeleveli ephansi zokuboniswa kwe-Wi-Fi."</string>
+    <!-- no translation found for permlab_captureAudioOutput (6857134498402346708) -->
+    <skip />
+    <!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
+    <skip />
+    <!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
+    <skip />
+    <!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
+    <skip />
+    <!-- no translation found for permlab_captureSecureVideoOutput (7815398969303382016) -->
+    <skip />
+    <!-- no translation found for permdesc_captureSecureVideoOutput (2779793064709350289) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"shintsha izilungiselelo zakho zomsindo"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ivumela uhlelo lokusebenza ukushintsha izilungiselelo zomsindo we-global njengevolomu nokuthi isiphi isipika esisetshenziselwa okukhiphayo."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"qopha umsindo"</string>
@@ -613,6 +635,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela insiza ukuthi ibhalele ekhadini le-SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"guqula/susa okuqukethwe kwisitoreji semidiya yangaphakathi"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela insiza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
+    <string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"phatha isitoreji sedokhumenti"</string>
+    <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Ivumela uhlelo lokusebenza ukuthi luphathe isitoreji sedokhumenti."</string>
     <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"ukufinyelela isilondolozi sangaphandle sabo bonke abasebenzisi"</string>
     <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Vumela uhlelo lokusebenza ukufinyelela isilondolozi sangaphandle kubo bonke abasebenzisi."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"finyelela kunqolobane yesistimu yefayela"</string>
@@ -625,10 +649,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"shintsha izimpawu zesokhethi"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ivumela uhlelo lokusebenza ukuthi lilungise izimpawu zesokhethi zomzila"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ivumela umbambi ukubophezela kwisixhumi esibonakalayo sezinga eliphezulu lesevisi yomlaleli wesaziso. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"buyisela uhlelo lokusebenza lokulungiselelwa okunikezwe yinkampani yenethiwekhi"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -738,8 +766,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"i-Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"i-Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Ama-Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"i-ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"i-Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Umhlangano we-Net"</string>
@@ -796,7 +823,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Faka ikhadi le-SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Ikhadi le-SIM alitholakali noma alifundeki. Sicela ufake ikhadi le-SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Ikhadi le-SIM elingasetshenzisiwe."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"I-SIM khadi ykho isiyenziwe ukuthi ingasebenzi unomphela."\n" Xhumana nomhlinzeki wakho wokuxhumana okungenazintambo ukuze uthole enye i-SIM khadi."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"I-SIM khadi ykho isiyenziwe ukuthi ingasebenzi unomphela.\n Xhumana nomhlinzeki wakho wokuxhumana okungenazintambo ukuze uthole enye i-SIM khadi."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Inkinombo yengoma yangaphambilini"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Inkinobho yengoma elandelayo"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Inkinobho yokukuma kancane"</string>
@@ -808,11 +835,11 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Sicela ubone Isiqondisi Somsebenzisi noma xhumana Nokunakekela Ikhasimende"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Ikhadi le-SIM livaliwe."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Ivula ikhadi le-SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Udwebe iphathini yakho yokuvula ngendlela engafanele izinkathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Zama futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. "\n\n"Zama futhi <xliff:g id="NUMBER_1">%d</xliff:g> imizuzwna."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Ubhale i-PIN ykho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. "\n\n"Zama futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google."\n\n" Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g> Emumva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google"\n\n" Zame futhi emuva kwamasekhondi angu- <xliff:g id="NUMBER_2">%d</xliff:g>"</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Udwebe iphathini yakho yokuvula ngendlela engafanele izinkathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Zama futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi <xliff:g id="NUMBER_1">%d</xliff:g> imizuzwna."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Ubhale i-PIN ykho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g> Emumva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emuva kwamasekhondi angu- <xliff:g id="NUMBER_2">%d</xliff:g>"</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Uzame ngokusebenzisa indlela engafanele ukuvula izikhathi <xliff:g id="NUMBER_0">%d</xliff:g> ze-tablet. Ngemuva <xliff:g id="NUMBER_1">%d</xliff:g> kokuzama kaningana okuyimpumelelo i-tablet izobuyela kwizimo zasembonini futhi yonke imininingo yomsebenzisi izolahleka."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Uzame ngokusebenzisa indlela engafanele ukuvula izikhathi <xliff:g id="NUMBER_0">%d</xliff:g> zocingo. Ngemuva <xliff:g id="NUMBER_1">%d</xliff:g> kokuzama kaningana ngaphandle kwempumelelo, ucingo luzobiyiselwa kwizimiso zasembonini futhi yonke imininingo yomsebenzisi izolahleka."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Uzame ukuvula ngendlela engafanele izikhathi <xliff:g id="NUMBER">%d</xliff:g> ze-tablet. I-tablet manje seyizosethwa kabusha ibe yizimiso zasembonini."</string>
@@ -826,7 +853,7 @@
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Iphasiwedi"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ngena"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Igama lomsebezisi elingalungile noma iphasiwedi."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?"\n"Vakashela"<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?\nVakashela"<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Iyahlola..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Vula"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Umsindo uvuliwe"</string>
@@ -874,7 +901,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Qinisekisa ukuzulazula"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Phuma kuleli khasi"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Hlala kuleli khasi"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ingabe uqinisekile ukuthi ufuna ukuzulazulela ngokuphuma kuleli khasi?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nIngabe uqinisekile ukuthi ufuna ukuzulazulela ngokuphuma kuleli khasi?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Qinisekisa"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Ithiphu: thepha kabili ukusondeza ngaphandle nangaphakathi."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Ukugcwalisa Ngokuzenzakalelayo"</string>
@@ -1080,14 +1107,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Ngeshwa, <xliff:g id="APPLICATION">%1$s</xliff:g> kumile."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Ngeshwa, uhlelo  <xliff:g id="PROCESS">%1$s</xliff:g> luvele lwama."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ayiphenduli."\n\n"Ingabe ufuna ukuyivala?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Uhlelo <xliff:g id="ACTIVITY">%1$s</xliff:g> aluphenduli."\n\n"Ingabe ufuna ukuluvala?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ayiphenduli.\n\nIngabe ufuna ukuyivala?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Uhlelo <xliff:g id="ACTIVITY">%1$s</xliff:g> aluphenduli.\n\nIngabe ufuna ukuluvala?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> ayiphenduli. Ingabe ufuna ukuyivala?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> ayisabeli."\n\n"Ingabe ufuna ukuyivala?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> ayisabeli.\n\nIngabe ufuna ukuyivala?"</string>
     <string name="force_close" msgid="8346072094521265605">"KULUNGILE"</string>
     <string name="report" msgid="4060218260984795706">"Umbiko"</string>
     <string name="wait" msgid="7147118217226317732">"Linda"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Leli khasi alisaphenduli."\n\n"Ingabe ufuna ukulivala na?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Leli khasi alisaphenduli.\n\nIngabe ufuna ukulivala na?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Insiza idluliselwe phambili"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> iqalisiwe."</string>
@@ -1256,6 +1283,10 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ivumela insiza ukuthi inqabe okutholakala kukhona ukukopisha okuqukethwe. Akusetshenziswa izinsiza ezijwayelekile."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Yenza umzila wemidiya wokukhiphayo"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ivumela uhlelo lokusebenza ukwenza umzila wokukhiphayo wemidiya kuya kumadivayisi angaphandle."</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Finyelela kusitoreji esiqashwa ngesikhiya esiphephile"</string>
+    <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ivumela uhlelo lokusebenza ukuthi lufinyelele kusitoreji esiqashwa ngesikhiya esiphephile."</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"Lawula ukubonisa nokufihla ukhiye wokuqapha"</string>
+    <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ivumela uhlelo lokusebenza ukuthi lulawule ukhiye wokuqapha."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Thinta kabili ukulawula ukusondeza"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Yehlulekile ukwengeza i-widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Iya"</string>
@@ -1265,15 +1296,15 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Kwenziwe"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Okwandulele"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Ukwenza"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Dayela inombolo"\n"usebenzisa <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="4947405226788104538">"Yenza othintana naye"\n" usebenzisa <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Dayela inombolo\nusebenzisa <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Yenza othintana naye\n usebenzisa <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Izinhlelo zokusebenza ezilandelayo zicela imvume yokufinyelela i-akhawunti yakho, manje ngisho nasesikhathini esizayo."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ingabe ufuna ukuvumela lesi sicelo?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Isicelo Sokufinyelela"</string>
     <string name="allow" msgid="7225948811296386551">"Vumela"</string>
     <string name="deny" msgid="2081879885755434506">"Yala"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Imvume Iceliwe"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Imvume Iceliwe "\n" ye-akhawunti <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Imvume Iceliwe \n ye-akhawunti <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Indlela yokufakwayo"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Vumelanisaa"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Ukufinyeleleka"</string>
@@ -1441,10 +1472,12 @@
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Iyaxhuma..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Kuyatholakala"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ayitholakali"</string>
+    <string name="media_route_status_in_use" msgid="4533786031090198063">"Kuyasebenza"</string>
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Okwakhelwe ngaphakathi kwesikrini"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Isikrini se-HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Isendlalelo #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", kuphephile"</string>
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Ukubukeka okungenantambo kuxhunyiwe"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Lesi sikrini siyabonakala kwenye idivayisi"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Nqamula"</string>
@@ -1453,7 +1486,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Iphatheni engalungile"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Iphasiwedi engalungile"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Iphinikhodi engalungile"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zama futhi emasekhondini angu-<xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zama futhi emasekhondini angu-<xliff:g id="NUMBER">%1$d</xliff:g>."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Dweba iphethini"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Faka iphinikhodi ye-SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Faka iphinikhodi"</string>
@@ -1473,27 +1506,79 @@
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Iphasiwedi"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Ngena ngemvume"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Igama lomsebezisi elingalungile noma iphasiwedi."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?"\n"Vakashela"<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?\nVakashela"<b>"google.com/accounts/recovery"</b></string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Ukuhlola i-akhawunti…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. "\n\n"Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Uzame ngokusebenzisa indlela engafanele ukuvula ithebhulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kokuzama ngaphandle kwempumelelo okungu-<xliff:g id="NUMBER_1">%d</xliff:g>, ithebhulethi izobuyiselwa kwizimiso zasembonini futhi yonke imininingwane yomsebenzisi izolahleka."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Uzame ngokusebenzisa indlela engafanele ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kokuzama ngaphandle kwempumelelo okungu-<xliff:g id="NUMBER_1">%d</xliff:g>, ifoni izobuyiselwa kwizimiso zasembonini futhi yonke imininingwane yomsebenzisi izolahleka."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Uzame ukuvula ngendlela engafanele ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Ithebhulethi manje isizosethwa kabusha ibe yizimiso ezizenzakalelayo."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Uzame ukuvula ngendlela engafanele ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Ifoni manje isizosethwa kabusha ibe yizimiso ezizenzakalelayo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google."\n\n" Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google"\n\n" Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Susa"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Khulisa ivolomu ngaphezu kwezinga elinconyiwe?"\n"Ukulalela ngevolomu ephezulu izikhathi ezinde kungalimaza ukuzwa kwakho."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Khulisa ivolomu ngaphezu kwezinga elinconyiwe?\nUkulalela ngevolomu ephezulu izikhathi ezinde kungalimaza ukuzwa kwakho."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Gcina ucindezele iminwe yakho emibili ukuze unike amandla ukufinyelela."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Ukufinyelela kunikwe amandla."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ukufinyelela kukhanseliwe."</string>
     <string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Umnikazi"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Iphutha"</string>
-    <string name="app_no_restricted_accounts" msgid="4011285085817350390">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wamaphrofayela akhawulelwe"</string>
+    <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wamaphrofayela akhawulelwe"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Alukho uhlelo lokusebenza olutholakele lokuphatha lesi senzo"</string>
     <string name="revoke" msgid="5404479185228271586">"Chitha"</string>
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"I-ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"I-ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"I-ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"I-ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"I-ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"I-ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"I-ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"I-ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"I-ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"I-ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"I-ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"I-ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"I-ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"I-ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"I-ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"I-ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"I-ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"I-ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"I-ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"I-ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"I-ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"I-ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"I-ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"I-ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"I-ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"I-ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"I-ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"I-ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"I-ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"I-ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"I-ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"I-ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"I-ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Incwadi"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Incwadi kahulumeni"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Okusemthethweni"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Ezomthetho ezincane"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ileja"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Iphephandaba"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kukhanseliwe"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Iphutha ekubhaleni okuqukethwe"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Faka i-PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"I-PIN yamanje"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"I-PIN entsha"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Qinisekisa i-PIN entsha"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Dala i-PIN yemikhawulo yokushintsha"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Ama-PIN awafani. Zama futhi."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"I-PIN yimfushane kakhulu. Okungenani kumele ibe namadijithi angu-4."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"I-PIN engalungile. Zama futhi esekhondini elingu-1."</item>
+    <item quantity="other" msgid="8030607343223287654">"I-PIN engalungile. Zama futhi emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 146607e..ef30b98 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -346,75 +346,4 @@
         <item>中文 (繁體)</item>
     </string-array>
 
-    <!-- Resources for GlowPadView in LockScreen -->
-    <array name="lockscreen_targets_when_silent">
-        <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_soundon</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_when_silent">
-        <item>@string/description_target_unlock</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_soundon</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_direction_descriptions">
-        <item>@string/description_direction_right</item>
-        <item>@string/description_direction_up</item>
-        <item>@string/description_direction_left</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_targets_when_soundon">
-        <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_silent</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_when_soundon">
-        <item>@string/description_target_unlock</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_silent</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_targets_with_camera">
-        <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@drawable/ic_action_assist_generic</item>
-        <item>@drawable/ic_lockscreen_camera</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_with_camera">
-        <item>@string/description_target_unlock</item>
-        <item>@string/description_target_search</item>
-        <item>@string/description_target_camera</item>
-        <item>@null</item>
-    </array>
-
-    <array name="lockscreen_targets_unlock_only">
-        <item>@*android:drawable/ic_lockscreen_unlock</item>
-    </array>
-
-    <array name="lockscreen_target_descriptions_unlock_only">
-        <item>@*android:string/description_target_unlock</item>
-    </array>
-
-    <!-- list of 3- or 4-letter mnemonics for a 10-key numeric keypad -->
-    <string-array translatable="false" name="lockscreen_num_pad_klondike">
-        <item></item><!-- 0 -->
-        <item></item><!-- 1 -->
-        <item>ABC</item><!-- 2 -->
-        <item>DEF</item><!-- 3 -->
-        <item>GHI</item><!-- 4 -->
-        <item>JKL</item><!-- 5 -->
-        <item>MNO</item><!-- 6 -->
-        <item>PQRS</item><!-- 7 -->
-        <item>TUV</item><!-- 8 -->
-        <item>WXYZ</item><!-- 9 -->
-    </string-array>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4dcbaec..275afb8 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -737,6 +737,14 @@
         <attr name="preferenceLayoutChild" format="reference" />
         <!-- Preference panel style -->
         <attr name="preferencePanelStyle" format="reference" />
+        <!-- Preference headers panel style -->
+        <attr name="preferenceHeaderPanelStyle" format="reference" />
+        <!-- Preference list style -->
+        <attr name="preferenceListStyle" format="reference" />
+        <!-- Preference fragment list style -->
+        <attr name="preferenceFragmentListStyle" format="reference" />
+        <!-- Preference fragment padding side -->
+        <attr name="preferenceFragmentPaddingSide" format="dimension" />
         <!-- Default style for switch preferences. -->
         <attr name="switchPreferenceStyle" format="reference" />
 
@@ -1550,6 +1558,7 @@
         <enum name="KEYCODE_ASSIST" value="219" />
         <enum name="KEYCODE_BRIGHTNESS_DOWN" value="220" />
         <enum name="KEYCODE_BRIGHTNESS_UP" value="221" />
+        <enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -2175,6 +2184,18 @@
             <enum name="no" value="2" />
         </attr>
 
+        <!-- Indicates to accessibility services whether the user should be notified when
+             this view changes. -->
+        <attr name="accessibilityLiveRegion" format="integer">
+            <!-- Accessibility services should not announce changes to this view. -->
+            <enum name="none" value="0" />
+            <!-- Accessibility services should announce changes to this view. -->
+            <enum name="polite" value="1" />
+            <!-- Accessibility services should interrupt ongoing speech to immediately
+                 announce changes to this view. -->
+            <enum name="assertive" value="2" />
+        </attr>
+
         <!-- Specifies the id of a view for which this view serves as a label for
              accessibility purposes. For example, a TextView before an EditText in
              the UI usually specifies what infomation is contained in the EditText.
@@ -2369,6 +2390,15 @@
         <!-- Set to true in all of the configurations for which this input
              method should be considered an option as the default. -->
         <attr name="isDefault" format="boolean" />
+        <!-- Set to true if this input method supports ways to switch to
+             a next input method (e.g. a globe key.). When this is true and
+             InputMethodManager#shouldOfferSwitchingToNextInputMethod() returns true,
+             the IME has to offer ways to to invoke InputMethodManager#switchToNextInputMethod()
+             accordingly.
+             <p> Note that the system determines the most appropriate next input method
+             and subtype in order to provide the consistent user experience in switching
+             between IMEs and subtypes. -->
+        <attr name="supportsSwitchingToNextInputMethod" format="boolean" />
     </declare-styleable>
 
     <!-- This is the subtype of InputMethod. Subtype can describe locales (e.g. en_US, fr_FR...)
@@ -2406,6 +2436,11 @@
              constructor or 0. Arrays.hashCode(new Object[] {locale, mode, extraValue,
              isAuxiliary, overridesImplicitlyEnabledSubtype}) will be used instead. -->
         <attr name="subtypeId" format="integer"/>
+        <!-- Set to true if this subtype is ASCII capable. If the subtype is ASCII
+             capable, it should guarantee that the user can input ASCII characters with
+             this subtype. This is important because many password fields only allow
+             ASCII-characters. -->
+        <attr name="isAsciiCapable" format="boolean" />
     </declare-styleable>
 
     <!-- Use <code>spell-checker</code> as the root tag of the XML resource that
@@ -2562,6 +2597,74 @@
         <attr name="description" />
     </declare-styleable>
 
+    <!-- Use <code>print-service</code> as the root tag of the XML resource that
+         describes an {@link android.printservice.PrintService} service, which is
+         referenced from its {@link android.printservice.PrintService#SERVICE_META_DATA}
+         meta-data entry. -->
+    <declare-styleable name="PrintService">
+        <!-- Fully qualified class name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity" />
+        <!-- Fully qualified class name of an activity that allows the user to manually
+             add printers to this print service. -->
+        <attr name="addPrintersActivity" format="string"/>
+        <!-- The vendor name if this print service is vendor specific. -->
+        <attr name="vendor" format="string"/>
+    </declare-styleable>
+
+    <!-- Use <code>host-apdu-service</code> as the root tag of the XML resource that
+         describes an {@link android.nfc.cardemulation.HostApduService} service, which
+         is referenced from its {@link android.nfc.cardemulation.HostApduService#SERVICE_META_DATA}
+         entry. -->
+    <declare-styleable name="HostApduService">
+        <!-- Short description of the functionality the service implements. This attribute
+             is mandatory.-->
+        <attr name="description" />
+        <!-- Whether the device must be unlocked before routing data to this service.
+             The default is false.-->
+        <attr name="requireDeviceUnlock" format="boolean"/>
+        <!-- A drawable that can be rendered in Android's system UI for representing
+             the service. -->
+        <attr name="apduServiceBanner" format="reference"/>
+    </declare-styleable>
+
+    <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
+         describes an {@link android.nfc.cardemulation.OffHostApduService}
+         service, which is referenced from its
+         {@link android.nfc.cardemulation.OffHostApduService#SERVICE_META_DATA} entry. -->
+    <declare-styleable name="OffHostApduService">
+        <!-- Short description of the functionality the service implements. This attribute
+             is mandatory.-->
+        <attr name="description" />
+        <!-- A drawable that can be rendered in Android's system UI for representing
+             the service. -->
+        <attr name="apduServiceBanner"/>
+    </declare-styleable>
+
+    <!-- Specify one or more <code>aid-group</code> elements inside a
+         <code>host-apdu-service</code> or <code>offhost-apdu-service</code>
+         element to define a group of ISO7816 Application ID (AIDs) that
+         your service can handle.-->
+    <declare-styleable name="AidGroup">
+        <!-- Short description of what the AID group implements. This attribute is mandatory.-->
+        <attr name="description" />
+        <!-- The category attribute will be used by the Android platform to present
+             multiple applications that register ISO 7816 Application IDs (AIDs) in the
+             same category uniformly.
+             Additionally, when a category is specified, Android will ensure that either
+             all AIDs in this group are routed to this application, or none at all.
+             This attribute is optional.-->
+        <attr name="category" format="string" />
+    </declare-styleable>
+
+    <!-- Specify one or more <code>aid-filter</code> elements inside a
+         <code>aid-group</code> element to specify an ISO7816 Application ID (AID)
+         your service can handle. -->
+    <declare-styleable name="AidFilter">
+        <!-- The ISO7816 Application ID. This attribute is mandatory. -->
+        <attr name="name" />
+    </declare-styleable>
+
     <declare-styleable name="ActionMenuItemView">
         <attr name="minWidth" />
     </declare-styleable>
@@ -3852,6 +3955,10 @@
              value is false.  See
              {@link android.graphics.drawable.Drawable#setVisible}. -->
         <attr name="visible" format="boolean" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left).  See
+             {@link android.graphics.drawable.Drawable#setAutoMirrored}. -->
+        <attr name="autoMirrored" format="boolean" />
     </declare-styleable>
 
     <!-- Drawable used to render several states. Each state is represented by
@@ -3879,6 +3986,9 @@
         <attr name="enterFadeDuration" format="integer" />
         <!-- Amount of time (in milliseconds) to fade out an old state drawable. -->
         <attr name="exitFadeDuration" format="integer" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored"/>
     </declare-styleable>
 
     <!-- Drawable used to render several animated frames. -->
@@ -4030,6 +4140,9 @@
             <!-- The layer has translucent pixels. -->
             <enum name="translucent" value="-3" />
         </attr>
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored" />
     </declare-styleable>
 
     <!-- Describes an item (or child) of a LayerDrawable. -->
@@ -4057,10 +4170,6 @@
         <attr name="drawable" />
     </declare-styleable>
 
-    <declare-styleable name="MipmapDrawableItem">
-        <attr name="drawable" />
-    </declare-styleable>
-
     <!-- Drawable used to rotate another drawable. -->
     <declare-styleable name="RotateDrawable">
         <attr name="visible" />
@@ -4123,6 +4232,9 @@
             {@link android.graphics.Bitmap#setHasMipMap(boolean)} for more information.
             Default value is false. -->
         <attr name="mipMap" format="boolean" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored" />
     </declare-styleable>
 
     <!-- Drawable used to draw 9-patches. -->
@@ -4133,6 +4245,9 @@
              same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
              an RGB 565 screen). -->
         <attr name="dither" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored" />
     </declare-styleable>
 
     <!-- Drawable used to draw a single color. -->
@@ -4408,6 +4523,75 @@
     </declare-styleable>
 
     <!-- ========================== -->
+    <!-- Transition attributes -->
+    <!-- ========================== -->
+    <eat-comment />
+
+    <!-- Use specific transition subclass names as the root tag of the XML resource that
+         describes a {@link android.transition.Transition Transition},
+         such as <code>move</code>, <code>fade</code>, and <code>set</code>. -->
+    <declare-styleable name="Transition">
+        <!-- Amount of time (in milliseconds) that the transition should run. -->
+        <attr name="duration" />
+        <!-- Delay in milliseconds before the transition starts. -->
+        <attr name="startDelay" format="integer" />
+        <!-- Interpolator to be used in the animations spawned by this transition. -->
+        <attr name="interpolator" />
+    </declare-styleable>
+
+    <!-- Use <code>fade</code>as the root tag of the XML resource that
+         describes a {@link android.transition.Fade Fade} transition.
+         The attributes of the {@link android.R.styleable#Transition Transition}
+         resource are available in addition to the specific attributes of Fade
+         described here. -->
+    <declare-styleable name="Fade">
+        <attr name="fadingMode">
+            <!-- Fade will only fade appearing items in. -->
+            <enum name="fade_in" value="1" />
+            <!-- Fade will only fade disappearing items out. -->
+            <enum name="fade_out" value="2" />
+            <!-- Fade will fade appearing items in and disappearing items out. -->
+            <enum name="fade_in_out" value="3" />
+        </attr>
+    </declare-styleable>
+
+    <!-- Use <code>target</code> as the root tag of the XML resource that
+     describes a {@link android.transition.Transition#addTarget(int)
+     targetId} of a transition. There can be one or more targets inside
+     a <code>targets</code> tag, which is itself inside an appropriate
+     {@link android.R.styleable#Transition Transition} tag.
+     -->
+    <declare-styleable name="TransitionTarget">
+        <!-- The id of a target on which this transition will animate changes. -->
+        <attr name="targetId" format="reference" />
+    </declare-styleable>
+
+    <!-- Use <code>set</code> as the root tag of the XML resource that
+         describes a {@link android.transition.TransitionSet
+         TransitionSet} transition. -->
+    <declare-styleable name="TransitionSet">
+        <attr name="transitionOrdering">
+            <!-- child transitions should be played together. -->
+            <enum name="together" value="0" />
+            <!-- child transitions should be played sequentially, in the same order
+            as the xml. -->
+            <enum name="sequential" value="1" />
+        </attr>
+    </declare-styleable>
+
+    <!-- Use <code>transitionManager</code> as the root tag of the XML resource that
+         describes a {@link android.transition.TransitionManager
+         TransitionManager}. -->
+    <declare-styleable name="TransitionManager">
+        <!-- The id of a transition to be used in a particular scene change. -->
+        <attr name="transition" format="reference" />
+        <!-- The originating scene in this scene change. -->
+        <attr name="fromScene" format="reference" />
+        <!-- The destination scene in this scene change. -->
+        <attr name="toScene" format="reference" />
+    </declare-styleable>
+
+    <!-- ========================== -->
     <!-- ValueAnimator class attributes -->
     <!-- ========================== -->
     <eat-comment />
@@ -5622,6 +5806,25 @@
     <declare-styleable name="SizeAdaptiveLayout" />
 
     <!-- =============================== -->
+    <!-- Location package class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <!-- Use <code>injected-location-setting</code> as the root tag of the XML resource that
+         describes an injected "Location services" setting. Note that the status value (subtitle)
+         for the setting is specified dynamically by a subclass of SettingInjectorService.
+     -->
+    <declare-styleable name="SettingInjectorService">
+        <!-- The title for the preference. -->
+        <attr name="title"/>
+        <!-- The icon for the preference, should refer to all apps covered by the setting. Typically
+             a generic icon for the developer. -->
+        <attr name="icon"/>
+        <!-- The activity to launch when the setting is clicked on. -->
+        <attr name="settingsActivity"/>
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- LockPatternView class attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -5936,4 +6139,5 @@
         <attr name="digit" format="integer" />
         <attr name="textView" format="reference" />
     </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index e7f6c53..b20f5ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1048,6 +1048,11 @@
         tag; often this is one of the {@link android.Manifest.permission standard
         system permissions}. -->
         <attr name="name" />
+        <!-- Optional: specify the maximum version of the Android OS for which the
+             application wishes to request the permission.  When running on a version
+             of Android higher than the number given here, the permission will not
+             be requested.  -->
+        <attr name="maxSdkVersion" format="integer" />
         <!--  Specify whether this permission is required for the application.
               The default is true, meaning the application requires the
               permission, and it must always be granted when it is installed.
@@ -1129,7 +1134,7 @@
              on.  You can use this to ensure your application is filtered out
              of later versions of the platform when you know you have
              incompatibility with them. -->
-        <attr name="maxSdkVersion" format="integer" />
+        <attr name="maxSdkVersion" />
     </declare-styleable>
     
     <!-- The <code>library</code> tag declares that this apk is providing itself
@@ -1624,6 +1629,27 @@
              case-sensitive, unlike the formal RFC.  As a result,
              schemes here should always use lower case letters.</em></p> -->
         <attr name="scheme" format="string" />
+        <!-- Specify a URI scheme specific part that must exactly match, as per
+             {@link android.content.IntentFilter#addDataSchemeSpecificPart
+             IntentFilter.addDataSchemeSpecificPart()} with
+             {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
+        <attr name="ssp" format="string" />
+        <!-- Specify a URI scheme specific part that must be a prefix to match, as per
+             {@link android.content.IntentFilter#addDataSchemeSpecificPart
+             IntentFilter.addDataSchemeSpecificPart()} with
+             {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
+        <attr name="sspPrefix" format="string" />
+        <!-- Specify a URI scheme specific part that matches a simple pattern, as per
+             {@link android.content.IntentFilter#addDataSchemeSpecificPart
+             IntentFilter.addDataSchemeSpecificPart()} with
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
+             Note that because '\' is used as an escape character when
+             reading the string from XML (before it is parsed as a pattern),
+             you will need to double-escape: for example a literal "*" would
+             be written as "\\*" and a literal "\" would be written as
+             "\\\\".  This is basically the same as what you would need to
+             write if constructing the string in Java code. -->
+        <attr name="sspPattern" format="string" />
         <!-- Specify a URI authority host that is handled, as per
              {@link android.content.IntentFilter#addDataAuthority
              IntentFilter.addDataAuthority()}.
@@ -1638,17 +1664,17 @@
         <attr name="port" format="string" />
         <!-- Specify a URI path that must exactly match, as per
              {@link android.content.IntentFilter#addDataPath
-             IntentFilter.addDataAuthority()} with
+             IntentFilter.addDataPath()} with
              {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
         <attr name="path" />
         <!-- Specify a URI path that must be a prefix to match, as per
              {@link android.content.IntentFilter#addDataPath
-             IntentFilter.addDataAuthority()} with
+             IntentFilter.addDataPath()} with
              {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
         <attr name="pathPrefix" />
         <!-- Specify a URI path that matches a simple pattern, as per
              {@link android.content.IntentFilter#addDataPath
-             IntentFilter.addDataAuthority()} with
+             IntentFilter.addDataPath()} with
              {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}. 
              Note that because '\' is used as an escape character when
              reading the string from XML (before it is parsed as a pattern),
@@ -1694,20 +1720,20 @@
     
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>screen</code> tag, a child of <code>compatible-screens</code>,
-         which is itseld a child of the root
+         which is itself a child of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestCompatibleScreensScreen"
                        parent="AndroidManifest.AndroidManifestCompatibleScreens">
         <!-- Specifies a compatible screen size, as per the device
              configuration screen size bins. -->
         <attr name="screenSize">
-            <!-- A small screen configuration, at least 240x320db. -->
+            <!-- A small screen configuration, at least 240x320dp. -->
             <enum name="small" value="200" />
-            <!-- A normal screen configuration, at least 320x480db. -->
+            <!-- A normal screen configuration, at least 320x480dp. -->
             <enum name="normal" value="300" />
-            <!-- A large screen configuration, at least 400x530db. -->
+            <!-- A large screen configuration, at least 400x530dp. -->
             <enum name="large" value="400" />
-            <!-- An extra large screen configuration, at least 600x800db. -->
+            <!-- An extra large screen configuration, at least 600x800dp. -->
             <enum name="xlarge" value="500" />
         </attr>
         <!-- Specifies a compatible screen density, as per the device
@@ -1724,6 +1750,19 @@
         </attr>
     </declare-styleable>
 
+    <!-- The <code>input-type</code> tag is a child of the <code>supports-input</code> tag, which
+         is itself a child of the root {@link #AndroidManifest manifest} tag. Each
+         <code>input-type</code> tag specifices the name of a specific input device type. When
+         grouped with the other elements of the parent <code>supports-input</code> tag it defines
+         a collection of input devices, which when all used together, are considered a supported
+         input mechanism for the application. There may be multiple <code>supports-input</code>
+         tags defined, each containing a different combination of input device types. -->
+    <declare-styleable name="AndroidManifestSupportsInputInputType"
+                       parent="AndroidManifest.AndroidManifestSupportsInput">
+        <!-- Specifices the name of the input device type -->
+        <attr name="name" />
+    </declare-styleable>
+
     <!-- The attribute that holds a Base64-encoded public key. -->
     <attr name="publicKey" format="string" />
 
@@ -1781,4 +1820,14 @@
         <!-- Concrete value to put for this named extra data. -->
         <attr name="value" />
     </declare-styleable>
+
+    <!-- Groups signing keys into a {@code KeySet} for easier reference in
+            other APIs. However, currently no APIs use this. -->
+    <attr name="keySet" />
+    <declare-styleable name="PublicKey">
+        <attr name="value" />
+    </declare-styleable>
+    <declare-styleable name="KeySet">
+        <attr name="name" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 18e4f2f..10a5d85 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -26,4 +26,5 @@
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="action_bar_expanded_action_views_exclusive">true</bool>
     <bool name="target_honeycomb_needs_options_menu">true</bool>
+    <bool name="flip_controller_fallback_keys">false</bool>
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 604bf4b..81ee3af 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -23,7 +23,7 @@
     <drawable name="status_bar_closed_default_background">#ff000000</drawable>
     <drawable name="status_bar_opened_default_background">#ff000000</drawable>
     <drawable name="notification_item_background_color">#ff111111</drawable>
-    <drawable name="notification_item_background_color_pressed">#ff257390</drawable>
+    <drawable name="notification_item_background_color_pressed">#ff454545</drawable>
     <drawable name="search_bar_default_color">#ff000000</drawable>
     <drawable name="safe_mode_background">#60000000</drawable>
     <!-- Background drawable that can be used for a transparent activity to
@@ -168,6 +168,8 @@
 
     <!-- A light Holo shade of blue -->
     <color name="holo_blue_light">#ff33b5e5</color>
+    <!-- A light Holo shade of gray -->
+    <color name="holo_gray_light">#33999999</color>
     <!-- A light Holo shade of green -->
     <color name="holo_green_light">#ff99cc00</color>
     <!-- A light Holo shade of red -->
@@ -186,6 +188,8 @@
     <color name="holo_orange_dark">#ffff8800</color>
     <!-- A really bright Holo shade of blue -->
     <color name="holo_blue_bright">#ff00ddff</color>
+    <!-- A really bright Holo shade of gray -->
+    <color name="holo_gray_bright">#33CCCCCC</color>
 
     <drawable name="notification_template_icon_bg">#3333B5E5</drawable>
     <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
@@ -195,5 +199,7 @@
     <color name="keyguard_avatar_frame_shadow_color">#80000000</color>
     <color name="keyguard_avatar_nick_color">#ffffffff</color>
     <color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
+
+    <color name="accessibility_focus_highlight">#80ffff00</color>
 </resources>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bbfbe0c..e39fd2a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -26,7 +26,7 @@
        <item><xliff:g id="id">ime</xliff:g></item>
        <item><xliff:g id="id">sync_failing</xliff:g></item>
        <item><xliff:g id="id">sync_active</xliff:g></item>
-       <item><xliff:g id="id">gps</xliff:g></item>
+       <item><xliff:g id="id">location</xliff:g></item>
        <item><xliff:g id="id">bluetooth</xliff:g></item>
        <item><xliff:g id="id">nfc</xliff:g></item>
        <item><xliff:g id="id">tty</xliff:g></item>
@@ -123,6 +123,49 @@
          of them.  This should not normally be modified. -->
     <bool name="config_closeDialogWhenTouchOutside">true</bool>
 
+    <!-- Device configuration indicating whether we should avoid using accelerated graphics
+         in certain places to reduce RAM footprint.  This is ignored if ro.config.low_ram
+         is true (in that case this is assumed true as well).  It can allow you to tune down
+         your device's memory use without going to the point of causing applications to turn
+         off features. -->
+    <bool name="config_avoidGfxAccel">false</bool>
+
+    <!-- Device configuration setting the minfree tunable in the lowmemorykiller in the kernel.
+         A high value will cause the lowmemorykiller to fire earlier, keeping more memory
+         in the file cache and preventing I/O thrashing, but allowing fewer processes to
+         stay in memory.  A low value will keep more processes in memory but may cause
+         thrashing if set too low.  Overrides the default value chosen by ActivityManager
+         based on screen size and total memory for the largest lowmemorykiller bucket, and
+         scaled proportionally to the smaller buckets.  -1 keeps the default. -->
+    <integer name="config_lowMemoryKillerMinFreeKbytesAbsolute">-1</integer>
+
+    <!-- Device configuration adjusting the minfree tunable in the lowmemorykiller in the
+         kernel.  A high value will cause the lowmemorykiller to fire earlier, keeping more
+         memory in the file cache and preventing I/O thrashing, but allowing fewer processes
+         to stay in memory.  A low value will keep more processes in memory but may cause
+         thrashing if set too low.  Directly added to the default value chosen by
+         ActivityManager based on screen size and total memory for the largest lowmemorykiller
+         bucket, and scaled proportionally to the smaller buckets. 0 keeps the default. -->
+    <integer name="config_lowMemoryKillerMinFreeKbytesAdjust">0</integer>
+
+    <!-- Device configuration setting the /proc/sys/vm/extra_free_kbytes tunable in the kernel
+         (if it exists).  A high value will increase the amount of memory that the kernel
+         tries to keep free, reducing allocation time and causing the lowmemorykiller to kill
+         earlier.  A low value allows more memory to be used by processes but may cause more
+         allocations to block waiting on disk I/O or lowmemorykiller.  Overrides the default
+         value chosen by ActivityManager based on screen size.  0 prevents keeping any extra
+         memory over what the kernel keeps by default.  -1 keeps the default. -->
+    <integer name="config_extraFreeKbytesAbsolute">-1</integer>
+
+    <!-- Device configuration adjusting the /proc/sys/vm/extra_free_kbytes tunable in the kernel
+         (if it exists).  0 uses the default value chosen by ActivityManager.  A positive value
+         will increase the amount of memory that the kernel tries to keep free, reducing
+         allocation time and causing the lowmemorykiller to kill earlier.  A negative value
+         allows more memory to be used by processes but may cause more allocations to block
+         waiting on disk I/O or lowmemorykiller.  Directly added to the default value chosen by
+         ActivityManager based on screen size. -->
+    <integer name="config_extraFreeKbytesAdjust">0</integer>
+
     <!-- The duration (in milliseconds) that the radio will scan for a signal
          when there's no network connection. If the scan doesn't timeout, use zero -->
     <integer name="config_radioScanningTimeout">0</integer>
@@ -149,6 +192,7 @@
         <item>"mobile_ims,11,0,2,60000,true"</item>
         <item>"mobile_cbs,12,0,2,60000,true"</item>
         <item>"wifi_p2p,13,1,0,-1,true"</item>
+        <item>"mobile_ia,14,0,2,-1,true"</item>
     </string-array>
 
     <!-- Array of ConnectivityManager.TYPE_xxxx constants for networks that may only
@@ -157,6 +201,7 @@
         <item>10</item>
         <item>11</item>
         <item>12</item>
+        <item>14</item>
     </integer-array>
 
     <!-- This string array should be overridden by the device to present a list of radio
@@ -179,6 +224,7 @@
         <item>10</item> <!-- TYPE_MOBILE_FOTA -->
         <item>11</item> <!-- TYPE_MOBILE_IMS -->
         <item>12</item> <!-- TYPE_MOBILE_CBS -->
+        <item>14</item> <!-- TYPE_MOBILE_IA -->
     </integer-array>
 
     <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
@@ -303,6 +349,13 @@
          Default value is 2 minutes. -->
     <integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
 
+    <!-- Wifi driver supports batched scan -->
+    <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
+
+    <!-- Default wifi country code.  If the device is going to be sold in the US this
+         needs to be US.  Uses ISO 3166 country code -->
+    <string translatable="false" name="config_wifi_default_country_code">US</string>
+
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
@@ -401,6 +454,13 @@
          The default is false. -->
     <bool name="config_lidControlsSleep">false</bool>
 
+    <!-- Indicate whether to allow the device to suspend when the screen is off
+         due to the proximity sensor.  This resource should only be set to true
+         if the sensor HAL correctly handles the proximity sensor as a wake-up source.
+         Otherwise, the device may fail to wake out of suspend reliably.
+         The default is false. -->
+    <bool name="config_suspendWhenScreenOffDueToProximity">false</bool>
+
     <!-- Control the behavior when the user long presses the power button.
             0 - Nothing
             1 - Global actions menu
@@ -526,9 +586,12 @@
     <!-- Don't show lock screen before unlock screen (PIN/pattern/password) -->
     <bool name="config_enableLockBeforeUnlockScreen">false</bool>
 
-    <!-- Diable lockscreen rotation by default -->
+    <!-- Disable lockscreen rotation by default -->
     <bool name="config_enableLockScreenRotation">false</bool>
 
+    <!-- Disable lockscreen transparent bars by default -->
+    <bool name="config_enableLockScreenTransparentBars">false</bool>
+
     <!-- Enable puk unlockscreen by default.
          If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
     <bool name="config_enable_puk_unlock_screen">true</bool>
@@ -725,6 +788,9 @@
          re-validation -->
     <bool name="config_bluetooth_address_validation">false</bool>
 
+    <!-- Boolean indicating if current platform supports BLE peripheral mode -->
+    <bool name="config_bluetooth_le_peripheral_mode_supported">false</bool>
+
     <!-- The default data-use polling period. -->
     <integer name="config_datause_polling_period_sec">600</integer>
 
@@ -741,6 +807,11 @@
     <!-- 2 means give warning -->
     <integer name="config_datause_notification_type">2</integer>
 
+    <!-- If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 this is the value
+         that should be used instead. A value of RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means
+         there is no replacement value and VoLTE is assumed to be supported -->
+    <integer name="config_volte_replacement_rat">0</integer>
+
     <!-- Flag indicating whether the current device is "voice capable".
          If true, this means that the device supports circuit-switched
          (i.e. voice) phone calls over the telephony network, and is
@@ -764,6 +835,13 @@
                cell broadcasting sms, and MMS. -->
     <bool name="config_sms_capable">true</bool>
 
+    <!-- Default SMS Application. This will be the default SMS application when
+         the phone first boots. The user can then change the default app to oe
+         of their choosing.
+         This can be overridden for devices where a different default SMS
+         application is desired. -->
+    <string name="default_sms_application" translatable="false">com.android.mms</string>
+
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
     <bool name="config_bluetooth_default_profiles">true</bool>
@@ -771,6 +849,10 @@
     <!-- IP address of the dns server to use if nobody else suggests one -->
     <string name="config_default_dns_server" translatable="false">8.8.8.8</string>
 
+    <!-- The default mobile provisioning apn. Empty by default, maybe overridden by
+         an mcc/mnc specific config.xml -->
+    <string name="mobile_provisioning_apn" translatable="false"></string>
+
     <!-- The default mobile provisioning url. Empty by default, maybe overridden by
          an mcc/mnc specific config.xml -->
     <string name="mobile_provisioning_url" translatable="false"></string>
@@ -1041,6 +1123,10 @@
     players. -->
     <integer name="config_safe_media_volume_index">10</integer>
 
+    <!-- Configure mobile network MTU. The standard default is set here but each carrier
+         may have a specific value set in an overlay config.xml file. -->
+    <integer name="config_mobile_mtu">1500</integer>
+
     <!-- Whether WiFi display is supported by this device.
          There are many prerequisites for this feature to work correctly.
          Here are a few of them:
@@ -1060,7 +1146,7 @@
     <bool name="config_useDevInputEventForAudioJack">false</bool>
 
     <!-- Whether safe headphone volume is enabled or not (country specific). -->
-    <bool name="config_safe_media_volume_enabled">true</bool>
+    <bool name="config_safe_media_volume_enabled">false</bool>
 
     <!-- Set to true if the wifi display supports compositing content stored
          in gralloc protected buffers.  For this to be true, there must exist
@@ -1118,6 +1204,11 @@
     <string name="config_chooseTypeAndAccountActivity"
             >android/android.accounts.ChooseTypeAndAccountActivity</string>
 
+    <!-- Component name of a custom ResolverActivity (Intent resolver) to be used instead of
+         the default framework version. If left empty, then the framework version will be used.
+         Example: com.google.android.myapp/.resolver.MyResolverActivity  -->
+    <string name="config_customResolverActivity"></string>
+
     <!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
     <string name="config_appsAuthorizedForSharedAccounts">;com.android.settings;</string>
 
@@ -1141,4 +1232,44 @@
         <item>com.android.inputmethod.latin</item>
     </string-array>
 
+    <string-array name="config_notificationScorers">
+        <item>com.android.internal.notification.DemoContactNotificationScorer</item>
+    </string-array>
+
+    <!-- Flag indicating that this device does not rotate and will always remain in its default
+         orientation. Activities that desire to run in a non-compatible orientation will be run
+         from an emulated display within the physical display. -->
+    <bool name="config_forceDefaultOrientation">false</bool>
+
+    <!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM -->
+    <integer name="config_toastDefaultGravity">0x00000051</integer>
+
+    <!-- set to false if we need to show user confirmation
+         when alpha identifier is not provided by the UICC -->
+    <bool name="config_stkNoAlphaUsrCnf">true</bool>
+
+    <!-- Don't use roaming icon for considered operators.
+         Can use mcc or mcc+mnc as item. For example, 302 or 21407.
+         If operators, 21404 and 21407, make roaming agreements, user of 21404 should not see
+         the roaming icon as using 21407 network.
+         To do this, add 21407 item to values-mcc214-mnc04/config.xml -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+    </string-array>
+
+    <!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
+         transient navigation confirmation prompt.-->
+    <integer name="config_transient_navigation_confirmation_panic">5000</integer>
+
+    <!-- For some operators, PDU has garbages. To fix it, need to use valid index -->
+    <integer name="config_valid_wappush_index">-1</integer>
+
+    <!-- Show roaming icon though same named operators.
+         Uses "startsWith" so you can use a leading substring like the mcc or
+         use the complete mcc+mnc string.
+         Though same mcc and same operator name, some operator want to roam.
+         user of 40485 should see the roaming icon as using 40483 network
+         though same Reliance network.
+         To do this, add 40483 item to values-mcc404-mnc85/config.xml -->
+    <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
+    </string-array>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 637128a5..e902354 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -50,8 +50,12 @@
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
     <dimen name="status_bar_edge_ignore">5dp</dimen>
 
-    <!-- Size of the fastscroll hint letter -->
+    <!-- Minimum size of the fastscroll overlay -->
     <dimen name="fastscroll_overlay_size">104dp</dimen>
+    <!-- Text size of the fastscroll overlay -->
+    <dimen name="fastscroll_overlay_text_size">24sp</dimen>
+    <!-- Padding of the fastscroll overlay -->
+    <dimen name="fastscroll_overlay_padding">16dp</dimen>
     <!-- Width of the fastscroll thumb -->
     <dimen name="fastscroll_thumb_width">64dp</dimen>
     <!-- Height of the fastscroll thumb -->
@@ -340,4 +344,16 @@
     security mode. -->
     <dimen name="kg_small_widget_height">160dp</dimen>
 
+    <!-- Rounded corner radius for video subtitles. -->
+    <dimen name="subtitle_corner_radius">2dp</dimen>
+
+    <!-- Shadow radius for video subtitles. -->
+    <dimen name="subtitle_shadow_radius">2dp</dimen>
+
+    <!-- Shadow offset for video subtitles. -->
+    <dimen name="subtitle_shadow_offset">2dp</dimen>
+
+    <!-- Outline width for video subtitles. -->
+    <dimen name="subtitle_outline_width">2dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml
index b49e7bd..a7288e1 100644
--- a/core/res/res/values/donottranslate.xml
+++ b/core/res/res/values/donottranslate.xml
@@ -24,8 +24,6 @@
     <bool name="lockscreen_isPortrait">true</bool>
     <!-- @hide DO NOT TRANSLATE. Control aspect ratio of lock pattern -->
     <string name="lock_pattern_view_aspect">square</string>
-    <!-- @hide DO NOT TRANSLATE. Separator between the hour and minute elements in a TimePicker widget -->
-    <string name="time_picker_separator">:</string>
     <!-- @hide DO NOT TRANSLATE. ICU pattern for "Mon, 14 January" -->
     <string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string>
     <!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.-->
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 21bae04..15df295 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -80,4 +80,5 @@
   <item type="id" name="overflow_menu_presenter" />
   <item type="id" name="popup_submenu_presenter" />
   <item type="id" name="action_bar_spinner" />
+  <item type="id" name="current_scene" />
 </resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index 053fc85..dc90bbf 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -18,7 +18,5 @@
 -->
 <resources>
     <integer name="kg_carousel_angle">75</integer>
-    <integer name="kg_security_flip_duration">100</integer>
-    <integer name="kg_security_fade_duration">100</integer>
     <integer name="kg_glowpad_rotation_offset">0</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 22ef31b..ef7f2b7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2053,4 +2053,30 @@
   <public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" id="0x010301df" />
   <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.Overscan" id="0x010301e0" />
 
+<!-- ===============================================================
+    Resources added in version 19 of the platform
+    =============================================================== -->
+  <eat-comment />
+
+  <public type="attr" name="keySet" />
+  <public type="attr" name="targetId" />
+  <public type="attr" name="fromScene" />
+  <public type="attr" name="toScene" />
+  <public type="attr" name="transition" />
+  <public type="attr" name="transitionOrdering" />
+  <public type="attr" name="fadingMode" />
+  <public type="attr" name="startDelay" />
+  <public type="attr" name="ssp" />
+  <public type="attr" name="sspPrefix" />
+  <public type="attr" name="sspPattern" />
+  <public type="attr" name="addPrintersActivity" />
+  <public type="attr" name="vendor" />
+  <public type="attr" name="category" />
+  <public type="attr" name="isAsciiCapable" />
+  <public type="attr" name="autoMirrored" />
+  <public type="attr" name="supportsSwitchingToNextInputMethod" />
+  <public type="attr" name="requireDeviceUnlock" />
+  <public type="attr" name="apduServiceBanner" />
+  <public type="attr" name="accessibilityLiveRegion" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ef0f01d..d57c232 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -273,6 +273,18 @@
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
     <string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
 
+    <!-- SSL CA cert notification --> <skip />
+    <!-- Shows up when there is a user SSL CA Cert installed on the
+         device.  Indicates to the user that SSL traffic can be intercepted.  [CHAR LIMIT=NONE] -->
+    <string name="ssl_ca_cert_warning">Network may be monitored</string>
+    <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+         i.e.  "Network may be monitored". This says that an unknown party is doing the monitoring.
+         [CHAR LIMIT=100]-->
+    <string name="ssl_ca_cert_noti_by_unknown">By an unknown third party</string>
+    <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+         i.e.  "Network may be monitored". This indicates who is doing the monitoring.
+         [CHAR LIMIT=100]-->
+    <string name="ssl_ca_cert_noti_managed">By <xliff:g id="managing_domain">%s</xliff:g></string>
 
     <!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
     <string name="me">Me</string>
@@ -587,6 +599,22 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_expandStatusBar">Allows the app to expand or collapse the status bar.</string>
 
+    <!-- Title of an application permission, listed so the user can install application shortcuts
+    in their Launcher -->
+    <string name="permlab_install_shortcut">install shortcuts</string>
+    <!-- Description of an application permission, listed so the user can install application shortcuts
+    in their Launcher -->
+    <string name="permdesc_install_shortcut">Allows an application to add
+        Homescreen shortcuts without user intervention.</string>
+
+    <!-- Title of an application permission, listed so the user can uninstall application shortcuts
+    in their Launcher -->
+    <string name="permlab_uninstall_shortcut">uninstall shortcuts</string>
+    <!-- Description of an application permission, listed so the user can install application shortcuts
+    in their Launcher -->
+    <string name="permdesc_uninstall_shortcut">Allows the application to remove
+        Homescreen shortcuts without user intervention.</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_processOutgoingCalls">reroute outgoing calls</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -712,6 +740,15 @@
         tasks and kill their apps. Malicious apps may disrupt
         the behavior of other apps.</string>
 
+    <!-- [CHAR LIMIT=NONE] Title of an application permission, allowing an application to create,
+         change, remove activity stacks. -->
+    <string name="permlab_manageActivityStacks">manage activity stacks</string>
+    <!-- [CHAR LIMIT=NONE] Description of an application permission, allowing an application to create,
+             change, remove activity stacks. -->
+    <string name="permdesc_manageActivityStacks">Allows the app to add, remove, and
+        modify the activity stacks in which other apps run.  Malicious apps may disrupt
+        the behavior of other apps.</string>
+
     <!-- Title of an application permission, allowing an application to start any activity, regardless of permission protection or exported state. -->
     <string name="permlab_startAnyActivity">start any activity</string>
     <!-- Description of an application permission, allowing an application to start any activity, regardless of permission protection or exported state. -->
@@ -823,7 +860,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getTopActivityInfo">Allows the holder to retrieve private information
         about the current application in the foreground of the screen.</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_runSetActivityWatcher">monitor and control all app launching</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -970,6 +1007,26 @@
         interface of an accessibility 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_bindPrintService">bind to a print service</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_bindPrintService">Allows the holder to bind to the top-level
+        interface of a print 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_bindPrintSpoolerService">bind to a print spooler service</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_bindPrintSpoolerService">Allows the holder to bind to the top-level
+        interface of a print spooler 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_bindNfcService">bind to NFC service</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_bindNfcService">Allows the holder to bind to applications
+        that are emulating NFC cards. 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_bindTextService">bind to a text service</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_bindTextService">Allows the holder to bind to the top-level
@@ -1000,6 +1057,12 @@
         a device administrator. 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_manageDeviceAdmins">add or remove a device admin</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_manageDeviceAdmins">Allows the holder to add or remove active device
+        administrators. 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_setOrientation">change screen orientation</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_setOrientation">Allows the app to change
@@ -1094,6 +1157,11 @@
     <string name="permdesc_anyCodecForPlayback">Allows the app to use any installed
         media decoder to decode for playback.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. This permission allows the app to install or uninstall trusted credentials, a.k.a. CA certificates. [CHAR LIMIT=NONE] -->
+    <string name="permlab_manageCaCertificates">manage trusted credentials</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+    <string name="permdesc_manageCaCertificates">Allows the app to install and uninstall CA certificates as trusted credentials.</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>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1360,6 +1428,32 @@
     <string name="permdesc_controlWifiDisplay">Allows the app to control low-level features of Wifi displays.</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_captureAudioOutput">capture audio output</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_captureAudioOutput">Allows the app to capture and redirect audio output.</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_captureAudioHotword">Hotword detection</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_captureAudioHotword">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>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_captureVideoOutput">capture video output</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_captureVideoOutput">Allows the app to capture and redirect video output.</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_captureSecureVideoOutput">capture secure video output</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_captureSecureVideoOutput">Allows the app to capture and redirect secure video output.</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_mediaContentControl">control media playback and metadata access</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_mediaContentControl">Allows the app to control media playback and access the media information (title, author...).</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_modifyAudioSettings">change your audio settings</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_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
@@ -1541,6 +1635,14 @@
     <string name="permdesc_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</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_transmitIr">transmit infrared</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_transmitIr" product="tablet">Allows the app to use the tablet\'s infrared transmitter.</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_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</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_devicePower" product="tablet">power tablet on or off</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_devicePower" product="default">power phone on or off</string>
@@ -1699,6 +1801,15 @@
     <string name="permdesc_bluetoothAdmin" product="default">Allows the app to configure
       the local Bluetooth phone, and to discover and pair with remote devices.</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_bluetoothPriv">allow Bluetooth pairing by Application</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_bluetoothPriv" product="tablet">Allows the app to
+      pair with remote devices without user interaction.</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_bluetoothPriv" product="default">Allows the app to
+      pair with remote devices without user interaction.</string>
+
     <string name="permlab_accessWimaxState">connect and disconnect from WiMAX</string>
     <string name="permdesc_accessWimaxState">Allows the app to determine whether
      WiMAX is enabled and information about any WiMAX networks that are
@@ -1774,13 +1885,13 @@
       user dictionary.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_sdcardRead" product="nosdcard">test access to protected storage</string>
+    <string name="permlab_sdcardRead" product="nosdcard">read the contents of your USB storage</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_sdcardRead" product="default">test access to protected storage</string>
+    <string name="permlab_sdcardRead" product="default">read the contents of your SD card</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permdesc_sdcardRead" product="nosdcard">Allows the app to test a permission for USB storage that will be available on future devices. </string>
+    <string name="permdesc_sdcardRead" product="nosdcard">Allows the app to read the contents of your USB storage.</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_sdcardRead" product="default">Allows the app to test a permission for the SD card that will be available on future devices.</string>
+    <string name="permdesc_sdcardRead" product="default">Allows the app to read the contents of your SD card.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
     <string name="permlab_sdcardWrite" product="nosdcard">modify or delete the contents of your USB storage</string>
@@ -1797,6 +1908,11 @@
     <string name="permdesc_mediaStorageWrite" product="default">Allows the app to modify the contents of the internal media storage.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+    <string name="permlab_manageDocs" product="default">manage document storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_manageDocs" product="default">Allows the app to manage document storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
     <string name="permlab_sdcardAccessAll">access external storage of all users</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_sdcardAccessAll">Allows the app to access external storage for all users.</string>
@@ -1812,6 +1928,11 @@
     <string name="permdesc_use_sip">Allows the app to use the SIP service to make/receive Internet calls.</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_bind_call_service">interact with in-call screen</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_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</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_readNetworkUsageHistory">read historical network usage</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_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -1827,6 +1948,11 @@
     <string name="permdesc_modifyNetworkAccounting">Allows the app to modify how network usage is accounted against apps. Not for use by 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_markNetworkSocket">modify socket marks</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_markNetworkSocket">Allows the app to modify socket marks for routing</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_accessNotifications">access notifications</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_accessNotifications">Allows the app to retrieve, examine, and clear notifications, including those posted by other apps.</string>
@@ -1836,6 +1962,16 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener 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_invokeCarrierSetup">invoke the carrier-provided configuration app</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_invokeCarrierSetup">Allows the holder to invoke the carrier-provided configuration app. 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_accessNetworkConditions">listen for observations on network conditions</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_accessNetworkConditions">Allows an application to listen for observations on network conditions. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
@@ -3046,6 +3182,8 @@
 
     <!-- Title of intent resolver dialog when selecting an application to run. -->
     <string name="whichApplication">Complete action using</string>
+    <!-- Title of intent resolver dialog when selecting a HOME application to run. -->
+    <string name="whichHomeApplication">Select a home app</string>
     <!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title-->
     <string name="alwaysUse">Use by default for this action.</string>
     <!-- Text displayed when the user selects the check box for setting default application.  See the "Use by default for this action" check box. -->
@@ -3469,6 +3607,16 @@
     <!-- Description of an application permission that lets an application route media output. -->
     <string name="permdesc_route_media_output">Allows an application to route media output to other external devices.</string>
 
+    <!-- Title of an application permission that lets an application access keyguard secure storage. -->
+    <string name="permlab_access_keyguard_secure_storage">Access keyguard secure storage</string>
+    <!-- Description of an application permission that lets an application access keyguard secure storage. -->
+    <string name="permdesc_access_keyguard_secure_storage">Allows an application to access keguard secure storage.</string>
+
+    <!-- Title of an application permission that lets it control keyguard. -->
+    <string name="permlab_control_keyguard">Control displaying and hiding keyguard</string>
+    <!-- Description of an application permission that lets it control keyguard. -->
+    <string name="permdesc_control_keyguard">Allows an application to control keguard.</string>
+
     <!-- Shown in the tutorial for tap twice for zoom control. -->
     <string name="tutorial_double_tap_to_zoom_message_short">Touch twice for zoom control</string>
 
@@ -3885,11 +4033,6 @@
     <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] -->
     <string name="share_action_provider_share_with">Share with</string>
 
-    <!-- Status Bar icon descriptions -->
-
-    <!-- Description of for the status bar's icon that the device is locked for accessibility. [CHAR LIMIT=NONE] -->
-    <string name="status_bar_device_locked">Device locked.</string>
-
     <!-- Delimeter used between each item in a textual list; for example "Alpha, Beta". [CHAR LIMIT=3] -->
     <string name="list_delimeter">", "</string>
 
@@ -3955,6 +4098,9 @@
     <!-- Status message for remote routes that are not available for connection right now -->
     <string name="media_route_status_not_available">Not available</string>
 
+    <!-- Status message for a remote route that is in use (and thus unavailabe) right now -->
+    <string name="media_route_status_in_use">In use</string>
+
     <!-- Display manager service -->
 
     <!-- Name of the built-in display.  [CHAR LIMIT=50] -->
@@ -3969,6 +4115,9 @@
     <!-- Title text to show within the overlay.  [CHAR LIMIT=50] -->
     <string name="display_manager_overlay_display_title"><xliff:g id="name">%1$s</xliff:g>: <xliff:g id="width">%2$d</xliff:g>x<xliff:g id="height">%3$d</xliff:g>, <xliff:g id="dpi">%4$d</xliff:g> dpi</string>
 
+    <!-- Title text to append when the display is secure.  [CHAR LIMIT=30] -->
+    <string name="display_manager_overlay_display_secure_suffix">, secure</string>
+
     <!-- Title of the notification to indicate an active wifi display connection.  [CHAR LIMIT=50] -->
     <string name="wifi_display_notification_title">Wireless display is connected</string>
     <!-- Message of the notification to indicate an active wifi display connection.  [CHAR LIMIT=80] -->
@@ -3988,7 +4137,7 @@
     <!-- Message shown when user enters wrong PIN -->
     <string name="kg_wrong_pin">Wrong PIN</string>
     <!-- Countdown message shown after too many failed unlock attempts -->
-    <string name="kg_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>
+    <string name="kg_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%1$d</xliff:g> seconds.</string>
     <!-- Instructions for using the pattern unlock screen -->
     <string name="kg_pattern_instructions">Draw your pattern</string>
     <!-- Instructions for using the SIM PIN unlock screen -->
@@ -4108,8 +4257,236 @@
     <!-- Error message title [CHAR LIMIT=35] -->
     <string name="error_message_title">Error</string>
     <!-- Message informing user that app is not permitted to access accounts. [CHAR LIMIT=none] -->
-    <string name="app_no_restricted_accounts">This application does not support accounts for restricted profiles</string>
+    <string name="app_no_restricted_accounts">This app doesn\'t support accounts for restricted profiles</string>
     <!-- Message informing user that the requested activity could not be found [CHAR LIMIT=none] -->
     <string name="app_not_found">No application found to handle this action</string>
     <string name="revoke">Revoke</string>
+
+    <!-- Printing -->
+
+    <!-- ISO (European standard) A0 media (paper) size: 33.11" × 46.81" -->
+    <string name="mediasize_iso_a0">ISO A0</string>
+    <!-- ISO (European standard) A1 media (paper) size: 23.39" × 33.11" -->
+    <string name="mediasize_iso_a1">ISO A1</string>
+    <!-- ISO (European standard) A2 media (paper) size: 16.54" x 23.39" -->
+    <string name="mediasize_iso_a2">ISO A2</string>
+    <!-- ISO (European standard) A3 media (paper) size: 11.69" x 16.54" -->
+    <string name="mediasize_iso_a3">ISO A3</string>
+    <!-- ISO (European standard) A4 media (paper) size: 8.27" x 11.69" -->
+    <string name="mediasize_iso_a4">ISO A4</string>
+    <!-- ISO (European standard) A5 media (paper) size: 5.83" x 8.27" -->
+    <string name="mediasize_iso_a5">ISO A5</string>
+    <!-- ISO (European standard) A6 media (paper) size: 4.13" x 5.83" -->
+    <string name="mediasize_iso_a6">ISO A6</string>
+    <!-- ISO (European standard) A7 media (paper) size: 2.91" x 4.13" -->
+    <string name="mediasize_iso_a7">ISO A7</string>
+    <!-- ISO (European standard) A8 media (paper) size: 2.05" x 2.91" -->
+    <string name="mediasize_iso_a8">ISO A8</string>
+    <!-- ISO (European standard) A9 media (paper) size: 1.46" x 2.05" -->
+    <string name="mediasize_iso_a9">ISO A9</string>
+    <!-- ISO (European standard) A10 media (paper) size: 1.02" x 1.46" -->
+    <string name="mediasize_iso_a10">ISO A10</string>
+
+    <!-- ISO (European standard) B0 media (paper) size: 39.37" x 55.67" -->
+    <string name="mediasize_iso_b0">ISO B0</string>
+    <!-- ISO (European standard) B1 media (paper) size: 27.83" x 39.37" -->
+    <string name="mediasize_iso_b1">ISO B1</string>
+    <!-- ISO (European standard) B2 media (paper) size - 19.69" x 27.83" -->
+    <string name="mediasize_iso_b2">ISO B2</string>
+    <!-- ISO (European standard) B3 media (paper) size: 13.90" x 19.69" -->
+    <string name="mediasize_iso_b3">ISO B3</string>
+    <!-- ISO (European standard) B4 media (paper) size: 9.84" x 13.90" -->
+    <string name="mediasize_iso_b4">ISO B4</string>
+    <!-- ISO (European standard) B5 media (paper) size: 6.93" x 9.84" -->
+    <string name="mediasize_iso_b5">ISO B5</string>
+    <!-- ISO (European standard) B6 media (paper) size: 4.92" x 6.93" -->
+    <string name="mediasize_iso_b6">ISO B6</string>
+    <!-- ISO (European standard) B7 media (paper) size: 3.46" x 4.92" -->
+    <string name="mediasize_iso_b7">ISO B7</string>
+    <!-- ISO (European standard) B8 media (paper) size: 2.44" x 3.46" -->
+    <string name="mediasize_iso_b8">ISO B8</string>
+    <!-- ISO (European standard) B9 media (paper) size: 1.73" x 2.44" -->
+    <string name="mediasize_iso_b9">ISO B9</string>
+    <!-- ISO (European standard) B10 media (paper) size: 1.22" x 1.73" -->
+    <string name="mediasize_iso_b10">ISO B10</string>
+
+    <!-- ISO (European standard) C0 media (paper) size: 36.10" x 51.06" -->
+    <string name="mediasize_iso_c0">ISO C0</string>
+    <!-- ISO (European standard) C1 media (paper) size: 25.51" x 36.10" -->
+    <string name="mediasize_iso_c1">ISO C1</string>
+    <!-- ISO (European standard) C2 media (paper) size: 18.03" x 25.51" -->
+    <string name="mediasize_iso_c2">ISO C2</string>
+    <!-- ISO (European standard) C3 media (paper) size: 12.76" x 18.03" -->
+    <string name="mediasize_iso_c3">ISO C3</string>
+    <!-- ISO (European standard) C4 media (paper) size: 9.02" x 12.76" -->
+    <string name="mediasize_iso_c4">ISO C4</string>
+    <!-- ISO (European standard) C5 media (paper) size: 6.38" x 9.02" -->
+    <string name="mediasize_iso_c5">ISO C5</string>
+    <!-- ISO (European standard) C6 media (paper) size: 4.49" x 6.38" -->
+    <string name="mediasize_iso_c6">ISO C6</string>
+    <!-- ISO (European standard) C7 media (paper) size: 3.19" x 4.49" -->
+    <string name="mediasize_iso_c7">ISO C7</string>
+    <!-- ISO ISO C8 media (paper) size: 2.24" x 3.19" -->
+    <string name="mediasize_iso_c8">ISO C8</string>
+    <!-- ISO ISO C9 media (paper) size: 1.57" x 2.24" -->
+    <string name="mediasize_iso_c9">ISO C9</string>
+    <!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
+    <string name="mediasize_iso_c10">ISO C10</string>
+
+    <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
+    <string name="mediasize_na_letter">Letter</string>
+    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
+    <string name="mediasize_na_gvrnmt_letter">Government Letter</string>
+    <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
+    <string name="mediasize_na_legal">Legal</string>
+    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
+    <string name="mediasize_na_junior_legal">Junior Legal</string>
+    <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
+    <string name="mediasize_na_ledger">Ledger</string>
+    <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
+    <string name="mediasize_na_tabloid">Tabloid</string>
+
+    <!-- North America Index Card 3x5 media (paper) size: 3" x 5" (76mm x 127mm) -->
+    <string name="mediasize_na_index_3x5">Index Card 3x5</string>
+    <!-- North America Index Card 4x6 media (paper) size: 4" x 6" (102mm x 152mm) -->
+    <string name="mediasize_na_index_4x6">Index Card 4x6</string>
+    <!-- North America Index Card 5x8 media (paper) size: 5" x 8" (127mm x 203mm) -->
+    <string name="mediasize_na_index_5x8">Index Card 5x8</string>
+    <!-- North America Monarch media (paper) size: 7.25" x 10.5" (184mm x 267mm) -->
+    <string name="mediasize_na_monarch">Monarch</string>
+    <!-- North America Quarto media (paper) size: 8" x 10" (203mm x 254mm) -->
+    <string name="mediasize_na_quarto">Quarto</string>
+    <!-- North America Foolscap media (paper) size: 8" x 13" (203mm x 330mm) -->
+    <string name="mediasize_na_foolscap">Foolscap</string>
+
+    <!-- Chinese Roc 8k media (paper) size: 270mm x 390mm (10.629" x 15.3543") -->
+    <string name="mediasize_chinese_roc_8k">ROC 8K</string>
+    <!-- Chinese Roc 16k media (paper) size: 195mm x 270mm (7.677" x 10.629") -->
+    <string name="mediasize_chinese_roc_16k">ROC 16K</string>
+
+    <!-- Chinese PRC 1 media (paper) size: 102mm x 165mm (4.015" x 6.496") -->
+    <string name="mediasize_chinese_prc_1">PRC 1</string>
+    <!-- Chinese PRC 2 media (paper) size: 102mm x 176mm (4.015" x 6.929") -->
+    <string name="mediasize_chinese_prc_2">PRC 2</string>
+    <!-- Chinese PRC 3 media (paper) size: 125mm x 176mm (4.921" x 6.929") -->
+    <string name="mediasize_chinese_prc_3">PRC 3</string>
+    <!-- Chinese PRC 4 media (paper) size: 110mm x 208mm (4.330" x 8.189") -->
+    <string name="mediasize_chinese_prc_4">PRC 4</string>
+    <!-- Chinese PRC 5 media (paper) size: 110mm x 220mm (4.330" x 8.661") -->
+    <string name="mediasize_chinese_prc_5">PRC 5</string>
+    <!-- Chinese PRC 6 media (paper) size: 120mm x 320mm (4.724" x 12.599") -->
+    <string name="mediasize_chinese_prc_6">PRC 6</string>
+    <!-- Chinese PRC 7 media (paper) size: 160mm x 230mm (6.299" x 9.055") -->
+    <string name="mediasize_chinese_prc_7">PRC 7</string>
+    <!-- Chinese PRC 8 media (paper) size: 120mm x 309mm (4.724" x 12.165") -->
+    <string name="mediasize_chinese_prc_8">PRC 8</string>
+    <!-- Chinese PRC 9 media (paper) size: 229mm x 324mm (9.016" x 12.756") -->
+    <string name="mediasize_chinese_prc_9">PRC 9</string>
+    <!-- Chinese PRC 10 media (paper) size: 324mm x 458mm (12.756" x 18.032") -->
+    <string name="mediasize_chinese_prc_10">PRC 10</string>
+
+    <!-- Chinese RPC 16K media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+    <string name="mediasize_chinese_prc_16k">PRC 16K</string>
+    <!-- Chinese Pa Kai media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+    <string name="mediasize_chinese_om_pa_kai">Pa Kai</string>
+    <!-- Chinese Dai Pa Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+    <string name="mediasize_chinese_om_dai_pa_kai">Dai Pa Kai</string>
+    <!-- Chinese Jurro Ku Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+    <string name="mediasize_chinese_om_jurro_ku_kai">Jurro Ku Kai</string>
+
+    <!-- Japanese JIS B10 media (paper) size: 32mm x 45mm (1.259" x 1.772") -->
+    <string name="mediasize_japanese_jis_b10">JIS B10</string>
+    <!-- Japanese JIS B9 media (paper) size: 45mm x 64mm (1.772" x 2.52") -->
+    <string name="mediasize_japanese_jis_b9">JIS B9</string>
+    <!-- Japanese JIS B8 media (paper) size: 64mm x 91mm (2.52" x 3.583") -->
+    <string name="mediasize_japanese_jis_b8">JIS B8</string>
+    <!-- Japanese JIS B7 media (paper) size: 91mm x 128mm (3.583" x 5.049") -->
+    <string name="mediasize_japanese_jis_b7">JIS B7</string>
+    <!-- Japanese JIS B6 media (paper) size: 128mm x 182mm (5.049" x 7.165") -->
+    <string name="mediasize_japanese_jis_b6">JIS B6</string>
+    <!-- Japanese JIS B5 media (paper) size: 182mm x 257mm (7.165" x 10.118") -->
+    <string name="mediasize_japanese_jis_b5">JIS B5</string>
+    <!-- Japanese JIS B4 media (paper) size: 257mm x 364mm (10.118" x 14.331") -->
+    <string name="mediasize_japanese_jis_b4">JIS B4</string>
+    <!-- Japanese JIS B3 media (paper) size: 364mm x 515mm (14.331" x 20.276") -->
+    <string name="mediasize_japanese_jis_b3">JIS B3</string>
+    <!-- Japanese JIS B2 media (paper) size: 515mm x 728mm (20.276" x 28.661") -->
+    <string name="mediasize_japanese_jis_b2">JIS B2</string>
+    <!-- Japanese JIS B1 media (paper) size: 728mm x 1030mm (28.661" x 40.551") -->
+    <string name="mediasize_japanese_jis_b1">JIS B1</string>
+    <!-- Japanese JIS B0 media (paper) size: 1030mm x 1456mm (40.551" x 57.323") -->
+    <string name="mediasize_japanese_jis_b0">JIS B0</string>
+
+    <!-- Japanese JIS Exec media (paper) size: 216mm x 330mm (8.504" x 12.992") -->
+    <string name="mediasize_japanese_jis_exec">JIS Exec</string>
+
+    <!-- Japanese Chou4 media (paper) size: 90mm x 205mm (3.543" x 8.071") -->
+    <string name="mediasize_japanese_chou4">Chou4</string>
+    <!-- Japanese Chou3 media (paper) size: 120mm x 235mm (4.724" x 9.252") -->
+    <string name="mediasize_japanese_chou3">Chou3</string>
+    <!-- Japanese Chou2 media (paper) size: 111.1mm x 146mm (4.374" x 5.748") -->
+    <string name="mediasize_japanese_chou2">Chou2</string>
+
+    <!-- Japanese Hagaki media (paper) size: 100mm x 148mm (3.937" x 5.827") -->
+    <string name="mediasize_japanese_hagaki">Hagaki </string>
+    <!-- Japanese Oufuku media (paper) size: 148mm x 200mm (5.827" x 7.874") -->
+    <string name="mediasize_japanese_oufuku">Oufuku </string>
+    <!-- Japanese Kahu media (paper) size: 240mm x 322.1mm (9.449" x 12.681") -->
+    <string name="mediasize_japanese_kahu">Kahu</string>
+    <!-- Japanese Kaku2 media (paper) size: 240mm x 332mm (9.449" x 13.071") -->
+    <string name="mediasize_japanese_kaku2">Kaku2</string>
+    <!-- Japanese You4 media (paper) size: 105mm x 235mm (4.134" x 9.252") -->
+    <string name="mediasize_japanese_you4">You4</string>
+
+    <!-- Media (paper) size for specifying any paper size in portrait.-->
+    <string name="mediasize_unknown_portrait">Unknown portrait</string>
+    <!-- Media (paper) size for specifying any paper size in landscape.-->
+    <string name="mediasize_unknown_landscape">Unknown landscape</string>
+
+    <!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] -->
+    <string name="write_fail_reason_cancelled">Cancelled</string>
+    <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
+    <string name="write_fail_reason_cannot_write">Error writing content</string>
+
+    <!-- Print fail reason: unknown. [CHAR LIMIT=25] -->
+    <string name="reason_unknown">unknown</string>
+
+    <!-- Print fail reason: the print service that has to process the print job is not available. [CHAR LIMIT=none] -->
+    <string name="reason_service_unavailable">Print service not enabled</string>
+
+    <!-- Title for the notification that a print service was installed. [CHAR LIMIT=50] -->
+    <string name="print_service_installed_title"><xliff:g id="name" example="Cloud Print">%s</xliff:g> service installed</string>
+    <!-- Message for the notification that a print service was installed. [CHAR LIMIT=50] -->
+    <string name="print_service_installed_message">Tap to enable</string>
+
+    <!-- PIN entry dialog title for entering the administrator PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_admin_pin">Enter administrator PIN</string>
+    <!-- PIN entry dialog label/hint for PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_pin">Enter PIN</string>
+    <!-- PIN entry dialog label/hint for incorrect PIN entry [CHAR LIMIT=none] -->
+    <string name="restr_pin_incorrect">Incorrect</string>
+    <!-- PIN entry dialog label/hint for old PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_old_pin">Current PIN</string>
+    <!-- PIN entry dialog label for new PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_new_pin">New PIN</string>
+    <!-- PIN entry dialog label for new PIN confirmation [CHAR LIMIT=none] -->
+    <string name="restr_pin_confirm_pin">Confirm new PIN</string>
+    <!-- PIN creation dialog message [CHAR LIMIT=none] -->
+    <string name="restr_pin_create_pin">Create a PIN for modifying restrictions</string>
+    <!-- PIN entry dialog error when PINs are not the same [CHAR LIMIT=none] -->
+    <string name="restr_pin_error_doesnt_match">PINs don\'t match. Try again.</string>
+    <!-- PIN entry dialog error when PIN is too short [CHAR LIMIT=none] -->
+    <string name="restr_pin_error_too_short">PIN is too short. Must be at least 4 digits.</string>
+    <!-- PIN entry dialog countdown message for next chance to enter the PIN [CHAR LIMIT=none] -->
+    <!-- Phrase describing a time duration using seconds [CHAR LIMIT=none] -->
+    <plurals name="restr_pin_countdown">
+        <item quantity="one">Try again in 1 second</item>
+        <item quantity="other">Try again in <xliff:g id="count">%d</xliff:g> seconds</item>
+    </plurals>
+    <!-- PIN entry dialog tells the user to not enter a PIN for a while. [CHAR LIMIT=none] -->
+    <string name="restr_pin_try_later">Try again later</string>
+
+    <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=45] -->
+    <string name="transient_navigation_confirmation">Swipe down from the top to exit full screen</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f494d8c..c5dab3b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -138,6 +138,12 @@
         <item name="windowExitAnimation">@anim/submenu_exit</item>
     </style>
 
+    <!-- {@hide} -->
+    <style name="Animation.ToastBar">
+        <item name="windowEnterAnimation">@anim/toast_bar_enter</item>
+        <item name="windowExitAnimation">@anim/toast_bar_exit</item>
+    </style>
+
     <style name="Animation.TypingFilter">
         <item name="windowEnterAnimation">@anim/grow_fade_in_center</item>
         <item name="windowExitAnimation">@anim/shrink_fade_out_center</item>
@@ -523,7 +529,6 @@
 
     <style name="Widget.CalendarView">
         <item name="android:showWeekNumber">true</item>
-        <item name="android:firstDayOfWeek">1</item>
         <item name="android:minDate">01/01/1900</item>
         <item name="android:maxDate">12/31/2100</item>
         <item name="android:shownWeekCount">6</item>
@@ -913,6 +918,10 @@
         <item name="android:textSize">30sp</item>
     </style>
 
+    <style name="TextAppearance.Toast">
+        <item name="android:fontFamily">sans-serif-condensed</item>
+    </style>
+
     <style name="Widget.ActivityChooserView">
         <item name="android:gravity">center</item>
         <item name="android:background">@android:drawable/ab_share_pack_holo_dark</item>
@@ -1052,6 +1061,24 @@
         <item name="android:background">@null</item>
     </style>
 
+    <style name="PreferenceHeaderPanel">
+        <item name="android:layout_marginStart">@dimen/preference_screen_side_margin</item>
+        <item name="android:layout_marginEnd">@dimen/preference_screen_side_margin_negative</item>
+        <item name="android:paddingTop">@dimen/preference_screen_header_vertical_padding</item>
+        <item name="android:paddingBottom">@dimen/preference_screen_header_vertical_padding</item>
+    </style>
+
+    <style name="PreferenceHeaderList">
+        <item name="android:paddingStart">@dimen/preference_screen_header_padding_side</item>
+        <item name="android:paddingEnd">@dimen/preference_screen_header_padding_side</item>
+        <item name="android:scrollbarStyle">@integer/preference_screen_header_scrollbarStyle</item>
+    </style>
+
+    <style name="PreferenceFragmentList">
+        <item name="android:paddingStart">@dimen/preference_fragment_padding_side</item>
+        <item name="android:paddingEnd">@dimen/preference_fragment_padding_side</item>
+    </style>
+
     <!-- Other Misc Styles -->
     <eat-comment />
 
@@ -2420,8 +2447,8 @@
     <style name="Widget.Holo.PreferenceFrameLayout">
         <item name="android:borderTop">0dip</item>
         <item name="android:borderBottom">@dimen/preference_fragment_padding_bottom</item>
-        <item name="android:borderLeft">@dimen/preference_fragment_padding_side</item>
-        <item name="android:borderRight">@dimen/preference_fragment_padding_side</item>
+        <item name="android:borderLeft">?attr/preferenceFragmentPaddingSide</item>
+        <item name="android:borderRight">?attr/preferenceFragmentPaddingSide</item>
     </style>
 
     <!-- Pointer styles -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
old mode 100755
new mode 100644
index 2c4ecfd..d483fe0
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -38,16 +38,12 @@
   <java-symbol type="id" name="action_menu_presenter" />
   <java-symbol type="id" name="action_mode_close_button" />
   <java-symbol type="id" name="activity_chooser_view_content" />
-  <java-symbol type="id" name="albumart" />
   <java-symbol type="id" name="alertTitle" />
   <java-symbol type="id" name="allow_button" />
   <java-symbol type="id" name="alwaysUse" />
   <java-symbol type="id" name="amPm" />
   <java-symbol type="id" name="authtoken_type" />
   <java-symbol type="id" name="back_button" />
-  <java-symbol type="id" name="btn_next" />
-  <java-symbol type="id" name="btn_play" />
-  <java-symbol type="id" name="btn_prev" />
   <java-symbol type="id" name="button_bar" />
   <java-symbol type="id" name="buttonPanel" />
   <java-symbol type="id" name="by_common" />
@@ -58,6 +54,7 @@
   <java-symbol type="id" name="characterPicker" />
   <java-symbol type="id" name="clearDefaultHint" />
   <java-symbol type="id" name="contentPanel" />
+  <java-symbol type="id" name="current_scene" />
   <java-symbol type="id" name="customPanel" />
   <java-symbol type="id" name="datePicker" />
   <java-symbol type="id" name="day" />
@@ -179,7 +176,6 @@
   <java-symbol type="id" name="to_common" />
   <java-symbol type="id" name="to_org" />
   <java-symbol type="id" name="to_org_unit" />
-  <java-symbol type="id" name="top_action_bar" />
   <java-symbol type="id" name="topPanel" />
   <java-symbol type="id" name="up" />
   <java-symbol type="id" name="value" />
@@ -217,6 +213,13 @@
   <java-symbol type="id" name="sms_short_code_remember_undo_instruction" />
   <java-symbol type="id" name="breadcrumb_section" />
   <java-symbol type="id" name="action_bar_spinner" />
+  <java-symbol type="id" name="pin_cancel_button" />
+  <java-symbol type="id" name="pin_ok_button" />
+  <java-symbol type="id" name="pin_text" />
+  <java-symbol type="id" name="pin_new_text" />
+  <java-symbol type="id" name="pin_confirm_text" />
+  <java-symbol type="id" name="pin_error_message" />
+  <java-symbol type="id" name="timePickerLayout" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
   <java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -243,9 +246,11 @@
   <java-symbol type="bool" name="action_bar_embed_tabs" />
   <java-symbol type="bool" name="action_bar_embed_tabs_pre_jb" />
   <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
+  <java-symbol type="bool" name="config_avoidGfxAccel" />
   <java-symbol type="bool" name="config_allowActionMenuItemTextWithIcon" />
   <java-symbol type="bool" name="config_bluetooth_address_validation" />
   <java-symbol type="bool" name="config_bluetooth_sco_off_call" />
+  <java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" />
   <java-symbol type="bool" name="config_cellBroadcastAppLinks" />
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
@@ -255,6 +260,7 @@
   <java-symbol type="bool" name="config_sip_wifi_only" />
   <java-symbol type="bool" name="config_sms_capable" />
   <java-symbol type="bool" name="config_sms_utf8_support" />
+  <java-symbol type="bool" name="config_suspendWhenScreenOffDueToProximity" />
   <java-symbol type="bool" name="config_swipeDisambiguation" />
   <java-symbol type="bool" name="config_syncstorageengine_masterSyncAutomatically" />
   <java-symbol type="bool" name="config_telephony_use_own_number_for_voicemail" />
@@ -278,15 +284,24 @@
   <java-symbol type="bool" name="config_dontPreferApn" />
   <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
   <java-symbol type="bool" name="config_useFixedVolume" />
+  <java-symbol type="bool" name="config_forceDefaultOrientation" />
+  <java-symbol type="bool" name="config_wifi_batched_scan_supported" />
+  <java-symbol type="bool" name="flip_controller_fallback_keys" />
 
   <java-symbol type="integer" name="config_cursorWindowSize" />
+  <java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
+  <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
+  <java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAdjust" />
+  <java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_max_pan_devices" />
   <java-symbol type="integer" name="config_ntpPollingInterval" />
   <java-symbol type="integer" name="config_ntpPollingIntervalShorter" />
   <java-symbol type="integer" name="config_ntpRetry" />
   <java-symbol type="integer" name="config_ntpThreshold" />
   <java-symbol type="integer" name="config_ntpTimeout" />
+  <java-symbol type="integer" name="config_toastDefaultGravity" />
+  <java-symbol type="integer" name="config_transient_navigation_confirmation_panic" />
   <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
@@ -299,6 +314,9 @@
   <java-symbol type="integer" name="config_lockSoundVolumeDb" />
   <java-symbol type="integer" name="config_multiuserMaximumUsers" />
   <java-symbol type="integer" name="config_safe_media_volume_index" />
+  <java-symbol type="integer" name="config_mobile_mtu" />
+  <java-symbol type="integer" name="config_volte_replacement_rat"/>
+  <java-symbol type="integer" name="config_valid_wappush_index" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
@@ -313,9 +331,10 @@
   <java-symbol type="dimen" name="dropdownitem_icon_width" />
   <java-symbol type="dimen" name="dropdownitem_text_padding_left" />
   <java-symbol type="dimen" name="fastscroll_overlay_size" />
+  <java-symbol type="dimen" name="fastscroll_overlay_text_size" />
+  <java-symbol type="dimen" name="fastscroll_overlay_padding" />
   <java-symbol type="dimen" name="fastscroll_thumb_height" />
   <java-symbol type="dimen" name="fastscroll_thumb_width" />
-  <java-symbol type="dimen" name="fastscroll_thumb_width" />
   <java-symbol type="dimen" name="password_keyboard_spacebar_vertical_correction" />
   <java-symbol type="dimen" name="search_view_preferred_width" />
   <java-symbol type="dimen" name="textview_error_popup_default_width" />
@@ -478,6 +497,7 @@
   <java-symbol type="string" name="display_manager_built_in_display_name" />
   <java-symbol type="string" name="display_manager_hdmi_display_name" />
   <java-symbol type="string" name="display_manager_overlay_display_name" />
+  <java-symbol type="string" name="display_manager_overlay_display_secure_suffix" />
   <java-symbol type="string" name="display_manager_overlay_display_title" />
   <java-symbol type="string" name="double_tap_toast" />
   <java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" />
@@ -563,26 +583,6 @@
   <java-symbol type="string" name="keyboardview_keycode_enter" />
   <java-symbol type="string" name="keyboardview_keycode_mode_change" />
   <java-symbol type="string" name="keyboardview_keycode_shift" />
-  <java-symbol type="string" name="keyguard_accessibility_add_widget" />
-  <java-symbol type="string" name="keyguard_accessibility_camera" />
-  <java-symbol type="string" name="keyguard_accessibility_expand_lock_area" />
-  <java-symbol type="string" name="keyguard_accessibility_face_unlock" />
-  <java-symbol type="string" name="keygaurd_accessibility_media_controls" />
-  <java-symbol type="string" name="keyguard_accessibility_pattern_area" />
-  <java-symbol type="string" name="keyguard_accessibility_pattern_unlock" />
-  <java-symbol type="string" name="keyguard_accessibility_password_unlock" />
-  <java-symbol type="string" name="keyguard_accessibility_pin_unlock" />
-  <java-symbol type="string" name="keyguard_accessibility_slide_area" />
-  <java-symbol type="string" name="keyguard_accessibility_slide_unlock" />
-  <java-symbol type="string" name="keyguard_accessibility_status" />
-  <java-symbol type="string" name="keyguard_accessibility_user_selector" />
-  <java-symbol type="string" name="keyguard_accessibility_widget" />
-  <java-symbol type="string" name="keyguard_accessibility_widget_deleted" />
-  <java-symbol type="string" name="keyguard_accessibility_widget_empty_slot" />
-  <java-symbol type="string" name="keyguard_accessibility_widget_reorder_start" />
-  <java-symbol type="string" name="keyguard_accessibility_widget_reorder_end" />
-  <java-symbol type="string" name="keyguard_accessibility_unlock_area_collapsed" />
-  <java-symbol type="string" name="keyguard_accessibility_unlock_area_expanded" />
   <java-symbol type="string" name="kilobyteShort" />
   <java-symbol type="string" name="last_month" />
   <java-symbol type="string" name="launchBrowserDefault" />
@@ -592,9 +592,6 @@
   <java-symbol type="string" name="lockscreen_access_pattern_start" />
   <java-symbol type="string" name="lockscreen_emergency_call" />
   <java-symbol type="string" name="lockscreen_return_to_call" />
-  <java-symbol type="string" name="lockscreen_transport_pause_description" />
-  <java-symbol type="string" name="lockscreen_transport_play_description" />
-  <java-symbol type="string" name="lockscreen_transport_stop_description" />
   <java-symbol type="string" name="low_memory" />
   <java-symbol type="string" name="media_bad_removal" />
   <java-symbol type="string" name="media_checking" />
@@ -679,8 +676,11 @@
   <java-symbol type="string" name="power_off" />
   <java-symbol type="string" name="preposition_for_date" />
   <java-symbol type="string" name="preposition_for_time" />
+  <java-symbol type="string" name="print_service_installed_title" />
+  <java-symbol type="string" name="print_service_installed_message" />
   <java-symbol type="string" name="progress_erasing" />
   <java-symbol type="string" name="progress_unmounting" />
+  <java-symbol type="string" name="mobile_provisioning_apn" />
   <java-symbol type="string" name="mobile_provisioning_url" />
   <java-symbol type="string" name="mobile_redirected_provisioning_url" />
   <java-symbol type="string" name="reboot_safemode_confirm" />
@@ -758,6 +758,7 @@
   <java-symbol type="string" name="sipAddressTypeHome" />
   <java-symbol type="string" name="sipAddressTypeOther" />
   <java-symbol type="string" name="sipAddressTypeWork" />
+  <java-symbol type="string" name="default_sms_application" />
   <java-symbol type="string" name="sms_control_message" />
   <java-symbol type="string" name="sms_control_title" />
   <java-symbol type="string" name="sms_control_no" />
@@ -786,7 +787,6 @@
   <java-symbol type="string" name="time_picker_increment_hour_button" />
   <java-symbol type="string" name="time_picker_increment_minute_button" />
   <java-symbol type="string" name="time_picker_increment_set_pm_button" />
-  <java-symbol type="string" name="time_picker_separator" />
   <java-symbol type="string" name="upload_file" />
   <java-symbol type="string" name="user_switched" />
   <java-symbol type="string" name="volume_alarm" />
@@ -800,6 +800,7 @@
   <java-symbol type="string" name="web_user_agent_target_content" />
   <java-symbol type="string" name="webpage_unresponsive" />
   <java-symbol type="string" name="whichApplication" />
+  <java-symbol type="string" name="whichHomeApplication" />
   <java-symbol type="string" name="wifi_available_sign_in" />
   <java-symbol type="string" name="network_available_sign_in" />
   <java-symbol type="string" name="network_available_sign_in_detailed" />
@@ -817,6 +818,7 @@
   <java-symbol type="string" name="wifi_tether_configure_ssid_default" />
   <java-symbol type="string" name="wifi_watchdog_network_disabled" />
   <java-symbol type="string" name="wifi_watchdog_network_disabled_detailed" />
+  <java-symbol type="string" name="config_wifi_default_country_code" />
   <java-symbol type="string" name="imei" />
   <java-symbol type="string" name="meid" />
   <java-symbol type="string" name="granularity_label_character" />
@@ -833,14 +835,111 @@
   <java-symbol type="string" name="media_route_status_connecting" />
   <java-symbol type="string" name="media_route_status_available" />
   <java-symbol type="string" name="media_route_status_not_available" />
+  <java-symbol type="string" name="media_route_status_in_use" />
   <java-symbol type="string" name="owner_name" />
   <java-symbol type="string" name="config_chooseAccountActivity" />
   <java-symbol type="string" name="config_chooseTypeAndAccountActivity" />
+  <java-symbol type="string" name="config_customResolverActivity" />
   <java-symbol type="string" name="config_appsAuthorizedForSharedAccounts" />
   <java-symbol type="string" name="error_message_title" />
   <java-symbol type="string" name="action_bar_home_description_format" />
   <java-symbol type="string" name="action_bar_home_subtitle_description_format" />
   <java-symbol type="string" name="wireless_display_route_description" />
+  <java-symbol type="string" name="mediasize_unknown_portrait" />
+  <java-symbol type="string" name="mediasize_unknown_landscape" />
+  <java-symbol type="string" name="mediasize_iso_a0" />
+  <java-symbol type="string" name="mediasize_iso_a1" />
+  <java-symbol type="string" name="mediasize_iso_a2" />
+  <java-symbol type="string" name="mediasize_iso_a3" />
+  <java-symbol type="string" name="mediasize_iso_a4" />
+  <java-symbol type="string" name="mediasize_iso_a5" />
+  <java-symbol type="string" name="mediasize_iso_a6" />
+  <java-symbol type="string" name="mediasize_iso_a7" />
+  <java-symbol type="string" name="mediasize_iso_a8" />
+  <java-symbol type="string" name="mediasize_iso_a9" />
+  <java-symbol type="string" name="mediasize_iso_a10" />
+  <java-symbol type="string" name="mediasize_iso_b0" />
+  <java-symbol type="string" name="mediasize_iso_b1" />
+  <java-symbol type="string" name="mediasize_iso_b2" />
+  <java-symbol type="string" name="mediasize_iso_b3" />
+  <java-symbol type="string" name="mediasize_iso_b4" />
+  <java-symbol type="string" name="mediasize_iso_b5" />
+  <java-symbol type="string" name="mediasize_iso_b6" />
+  <java-symbol type="string" name="mediasize_iso_b7" />
+  <java-symbol type="string" name="mediasize_iso_b8" />
+  <java-symbol type="string" name="mediasize_iso_b9" />
+  <java-symbol type="string" name="mediasize_iso_b10" />
+  <java-symbol type="string" name="mediasize_iso_c0" />
+  <java-symbol type="string" name="mediasize_iso_c1" />
+  <java-symbol type="string" name="mediasize_iso_c2" />
+  <java-symbol type="string" name="mediasize_iso_c3" />
+  <java-symbol type="string" name="mediasize_iso_c4" />
+  <java-symbol type="string" name="mediasize_iso_c5" />
+  <java-symbol type="string" name="mediasize_iso_c6" />
+  <java-symbol type="string" name="mediasize_iso_c7" />
+  <java-symbol type="string" name="mediasize_iso_c8" />
+  <java-symbol type="string" name="mediasize_iso_c9" />
+  <java-symbol type="string" name="mediasize_iso_c10" />
+  <java-symbol type="string" name="mediasize_na_letter" />
+  <java-symbol type="string" name="mediasize_na_gvrnmt_letter" />
+  <java-symbol type="string" name="mediasize_na_legal" />
+  <java-symbol type="string" name="mediasize_na_junior_legal" />
+  <java-symbol type="string" name="mediasize_na_ledger" />
+  <java-symbol type="string" name="mediasize_na_tabloid" />
+  <java-symbol type="string" name="mediasize_na_index_3x5" />
+  <java-symbol type="string" name="mediasize_na_index_4x6" />
+  <java-symbol type="string" name="mediasize_na_index_5x8" />
+  <java-symbol type="string" name="mediasize_na_monarch" />
+  <java-symbol type="string" name="mediasize_na_quarto" />
+  <java-symbol type="string" name="mediasize_na_foolscap" />
+  <java-symbol type="string" name="mediasize_chinese_roc_8k" />
+  <java-symbol type="string" name="mediasize_chinese_roc_16k" />
+  <java-symbol type="string" name="mediasize_chinese_prc_1" />
+  <java-symbol type="string" name="mediasize_chinese_prc_2" />
+  <java-symbol type="string" name="mediasize_chinese_prc_3" />
+  <java-symbol type="string" name="mediasize_chinese_prc_4" />
+  <java-symbol type="string" name="mediasize_chinese_prc_5" />
+  <java-symbol type="string" name="mediasize_chinese_prc_6" />
+  <java-symbol type="string" name="mediasize_chinese_prc_7" />
+  <java-symbol type="string" name="mediasize_chinese_prc_8" />
+  <java-symbol type="string" name="mediasize_chinese_prc_9" />
+  <java-symbol type="string" name="mediasize_chinese_prc_10" />
+  <java-symbol type="string" name="mediasize_chinese_prc_16k" />
+  <java-symbol type="string" name="mediasize_chinese_om_pa_kai" />
+  <java-symbol type="string" name="mediasize_chinese_om_dai_pa_kai" />
+  <java-symbol type="string" name="mediasize_chinese_om_jurro_ku_kai" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b10" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b9" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b8" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b7" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b6" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b5" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b4" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b3" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b2" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b1" />
+  <java-symbol type="string" name="mediasize_japanese_jis_b0" />
+  <java-symbol type="string" name="mediasize_japanese_jis_exec" />
+  <java-symbol type="string" name="mediasize_japanese_chou4" />
+  <java-symbol type="string" name="mediasize_japanese_chou3" />
+  <java-symbol type="string" name="mediasize_japanese_chou2" />
+  <java-symbol type="string" name="mediasize_japanese_hagaki" />
+  <java-symbol type="string" name="mediasize_japanese_oufuku" />
+  <java-symbol type="string" name="mediasize_japanese_kahu" />
+  <java-symbol type="string" name="mediasize_japanese_kaku2" />
+  <java-symbol type="string" name="mediasize_japanese_you4" />
+  <java-symbol type="string" name="reason_service_unavailable" />
+  <java-symbol type="string" name="reason_unknown" />
+  <java-symbol type="string" name="restr_pin_enter_admin_pin" />
+  <java-symbol type="string" name="restr_pin_enter_pin" />
+  <java-symbol type="string" name="restr_pin_incorrect" />
+  <java-symbol type="string" name="restr_pin_try_later" />
+  <java-symbol type="string" name="write_fail_reason_cancelled" />
+  <java-symbol type="string" name="write_fail_reason_cannot_write" />
+  <java-symbol type="string" name="transient_navigation_confirmation" />
+  <java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
+  <java-symbol type="string" name="ssl_ca_cert_noti_managed" />
+  <java-symbol type="string" name="ssl_ca_cert_warning" />
 
   <java-symbol type="plurals" name="abbrev_in_num_days" />
   <java-symbol type="plurals" name="abbrev_in_num_hours" />
@@ -863,6 +962,7 @@
   <java-symbol type="plurals" name="num_hours_ago" />
   <java-symbol type="plurals" name="num_minutes_ago" />
   <java-symbol type="plurals" name="num_seconds_ago" />
+  <java-symbol type="plurals" name="restr_pin_countdown" />
 
   <java-symbol type="array" name="carrier_properties" />
   <java-symbol type="array" name="config_data_usage_network_types" />
@@ -877,6 +977,8 @@
   <java-symbol type="array" name="config_masterVolumeRamp" />
   <java-symbol type="array" name="config_cdma_dun_supported_types" />
   <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
+  <java-symbol type="array" name="config_operatorConsideredNonRoaming" />
+  <java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
 
   <java-symbol type="drawable" name="default_wallpaper" />
   <java-symbol type="drawable" name="indicator_input_error" />
@@ -938,6 +1040,9 @@
   <java-symbol type="drawable" name="ic_emergency" />
   <java-symbol type="drawable" name="ic_media_stop" />
   <java-symbol type="drawable" name="ic_text_dot" />
+  <java-symbol type="drawable" name="ic_print" />
+  <java-symbol type="drawable" name="ic_print_error" />
+  <java-symbol type="drawable" name="ic_grayedout_printer" />
   <java-symbol type="drawable" name="indicator_code_lock_drag_direction_green_up" />
   <java-symbol type="drawable" name="indicator_code_lock_drag_direction_red_up" />
   <java-symbol type="drawable" name="indicator_code_lock_point_area_default_holo" />
@@ -956,12 +1061,12 @@
   <java-symbol type="drawable" name="jog_tab_target_gray" />
   <java-symbol type="drawable" name="picture_emergency" />
   <java-symbol type="drawable" name="platlogo" />
-  <java-symbol type="drawable" name="platlogo_alt" />
   <java-symbol type="drawable" name="stat_notify_sync_error" />
   <java-symbol type="drawable" name="stat_notify_wifi_in_range" />
   <java-symbol type="drawable" name="stat_notify_rssi_in_range" />
   <java-symbol type="drawable" name="stat_sys_gps_on" />
   <java-symbol type="drawable" name="stat_sys_tether_wifi" />
+  <java-symbol type="drawable" name="stat_sys_certificate_info" />
   <java-symbol type="drawable" name="status_bar_background" />
   <java-symbol type="drawable" name="sym_keyboard_shift" />
   <java-symbol type="drawable" name="sym_keyboard_shift_locked" />
@@ -974,21 +1079,17 @@
   <java-symbol type="drawable" name="text_select_handle_left" />
   <java-symbol type="drawable" name="text_select_handle_middle" />
   <java-symbol type="drawable" name="text_select_handle_right" />
+  <java-symbol type="drawable" name="toast_bar_bg" />
   <java-symbol type="drawable" name="unknown_image" />
   <java-symbol type="drawable" name="unlock_default" />
   <java-symbol type="drawable" name="unlock_halo" />
   <java-symbol type="drawable" name="unlock_ring" />
   <java-symbol type="drawable" name="unlock_wave" />
-  <java-symbol type="drawable" name="ic_lockscreen_camera" />
-  <java-symbol type="drawable" name="ic_lockscreen_silent" />
-  <java-symbol type="drawable" name="ic_lockscreen_unlock" />
   <java-symbol type="drawable" name="ic_action_assist_generic" />
-  <java-symbol type="drawable" name="ic_lockscreen_alarm" />
   <java-symbol type="drawable" name="notification_bg" />
   <java-symbol type="drawable" name="notification_bg_low" />
   <java-symbol type="drawable" name="notification_template_icon_bg" />
   <java-symbol type="drawable" name="notification_template_icon_low_bg" />
-  <java-symbol type="drawable" name="ic_lockscreen_unlock_phantom" />
   <java-symbol type="drawable" name="ic_media_route_on_holo_dark" />
   <java-symbol type="drawable" name="ic_media_route_disabled_holo_dark" />
 
@@ -1067,6 +1168,7 @@
   <java-symbol type="layout" name="textview_hint" />
   <java-symbol type="layout" name="time_picker" />
   <java-symbol type="layout" name="time_picker_dialog" />
+  <java-symbol type="layout" name="toast_bar" />
   <java-symbol type="layout" name="transient_notification" />
   <java-symbol type="layout" name="volume_adjust" />
   <java-symbol type="layout" name="volume_adjust_item" />
@@ -1088,12 +1190,11 @@
   <java-symbol type="layout" name="notification_template_part_time" />
   <java-symbol type="layout" name="notification_template_part_chronometer" />
   <java-symbol type="layout" name="notification_template_inbox" />
-  <java-symbol type="layout" name="keyguard_multi_user_avatar" />
-  <java-symbol type="layout" name="keyguard_multi_user_selector_widget" />
   <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
-  <java-symbol type="layout" name="keyguard_add_widget" />
   <java-symbol type="layout" name="action_bar_up_container" />
   <java-symbol type="layout" name="app_not_authorized" />
+  <java-symbol type="layout" name="restrictions_pin_challenge" />
+  <java-symbol type="layout" name="restrictions_pin_setup" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
@@ -1109,7 +1210,6 @@
   <java-symbol type="xml" name="password_kbd_qwerty_shifted" />
   <java-symbol type="xml" name="password_kbd_symbols" />
   <java-symbol type="xml" name="password_kbd_symbols_shift" />
-  <java-symbol type="xml" name="kg_password_kbd_numeric" />
   <java-symbol type="xml" name="power_profile" />
   <java-symbol type="xml" name="time_zones_by_country" />
   <java-symbol type="xml" name="sms_short_codes" />
@@ -1124,6 +1224,7 @@
   <java-symbol type="style" name="Animation.DropDownUp" />
   <java-symbol type="style" name="Animation.DropDownDown" />
   <java-symbol type="style" name="Animation.PopupWindow" />
+  <java-symbol type="style" name="Animation.ToastBar" />
   <java-symbol type="style" name="Animation.TypingFilter" />
   <java-symbol type="style" name="Animation.TypingFilterRestore" />
   <java-symbol type="style" name="Animation.Dream" />
@@ -1163,8 +1264,6 @@
 
   <!-- From android.policy -->
   <java-symbol type="anim" name="app_starting_exit" />
-  <java-symbol type="anim" name="lock_screen_behind_enter" />
-  <java-symbol type="anim" name="lock_screen_wallpaper_behind_enter" />
   <java-symbol type="anim" name="dock_top_enter" />
   <java-symbol type="anim" name="dock_top_exit" />
   <java-symbol type="anim" name="dock_bottom_enter" />
@@ -1173,22 +1272,12 @@
   <java-symbol type="anim" name="dock_left_exit" />
   <java-symbol type="anim" name="dock_right_enter" />
   <java-symbol type="anim" name="dock_right_exit" />
-  <java-symbol type="anim" name="keyguard_security_animate_in" />
-  <java-symbol type="anim" name="keyguard_security_animate_out" />
-  <java-symbol type="anim" name="keyguard_security_fade_in" />
-  <java-symbol type="anim" name="keyguard_security_fade_out" />
-  <java-symbol type="anim" name="keyguard_action_assist_exit" />
-  <java-symbol type="anim" name="keyguard_action_assist_enter" />
 
   <java-symbol type="array" name="config_keyboardTapVibePattern" />
   <java-symbol type="array" name="config_longPressVibePattern" />
   <java-symbol type="array" name="config_safeModeDisabledVibePattern" />
   <java-symbol type="array" name="config_safeModeEnabledVibePattern" />
   <java-symbol type="array" name="config_virtualKeyVibePattern" />
-  <java-symbol type="array" name="lockscreen_targets_when_silent" />
-  <java-symbol type="array" name="lockscreen_targets_when_soundon" />
-  <java-symbol type="array" name="lockscreen_targets_with_camera" />
-  <java-symbol type="array" name="lockscreen_num_pad_klondike" />
   <java-symbol type="attr" name="actionModePopupWindowStyle" />
   <java-symbol type="attr" name="dialogCustomTitleDecorLayout" />
   <java-symbol type="attr" name="dialogTitleDecorLayout" />
@@ -1200,36 +1289,15 @@
   <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
   <java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
   <java-symbol type="bool" name="config_enableLockScreenRotation" />
+  <java-symbol type="bool" name="config_enableLockScreenTransparentBars" />
   <java-symbol type="bool" name="config_lidControlsSleep" />
   <java-symbol type="bool" name="config_reverseDefaultRotation" />
   <java-symbol type="bool" name="config_showNavigationBar" />
-  <java-symbol type="bool" name="kg_enable_camera_default_widget" />
-  <java-symbol type="bool" name="kg_share_status_area" />
-  <java-symbol type="bool" name="kg_sim_puk_account_full_screen" />
-  <java-symbol type="bool" name="kg_top_align_page_shrink_on_bouncer_visible" />
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
-  <java-symbol type="bool" name="kg_center_small_widgets_vertically" />
-  <java-symbol type="bool" name="kg_show_ime_at_screen_on" />
-  <java-symbol type="color" name="kg_multi_user_text_active" />
-  <java-symbol type="color" name="kg_multi_user_text_inactive" />
-  <java-symbol type="color" name="kg_widget_pager_gradient" />
-  <java-symbol type="color" name="keyguard_avatar_frame_color" />
-  <java-symbol type="color" name="keyguard_avatar_frame_pressed_color" />
-  <java-symbol type="color" name="keyguard_avatar_frame_shadow_color" />
-  <java-symbol type="color" name="keyguard_avatar_nick_color" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
   <java-symbol type="dimen" name="status_bar_height" />
-  <java-symbol type="dimen" name="kg_widget_pager_horizontal_padding" />
-  <java-symbol type="dimen" name="kg_widget_pager_top_padding" />
-  <java-symbol type="dimen" name="kg_widget_pager_bottom_padding" />
-  <java-symbol type="dimen" name="keyguard_avatar_size" />
-  <java-symbol type="dimen" name="keyguard_avatar_frame_stroke_width" />
-  <java-symbol type="dimen" name="keyguard_avatar_frame_shadow_radius" />
-  <java-symbol type="dimen" name="kg_edge_swipe_region_size" />
-  <java-symbol type="dimen" name="kg_squashed_layout_threshold" />
-  <java-symbol type="dimen" name="kg_small_widget_height" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_off" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_on" />
   <java-symbol type="drawable" name="ic_jog_dial_unlock" />
@@ -1247,10 +1315,7 @@
   <java-symbol type="drawable" name="jog_tab_target_yellow" />
   <java-symbol type="drawable" name="magnified_region_frame" />
   <java-symbol type="drawable" name="menu_background" />
-  <java-symbol type="drawable" name="stat_sys_secure" />
-  <java-symbol type="drawable" name="kg_widget_bg_padded" />
   <java-symbol type="id" name="action_mode_bar_stub" />
-  <java-symbol type="id" name="alarm_status" />
   <java-symbol type="id" name="button0" />
   <java-symbol type="id" name="button4" />
   <java-symbol type="id" name="button5" />
@@ -1258,15 +1323,12 @@
   <java-symbol type="id" name="button7" />
   <java-symbol type="id" name="date" />
   <java-symbol type="id" name="eight" />
-  <java-symbol type="id" name="face_unlock_area_view" />
-  <java-symbol type="id" name="face_unlock_cancel_button" />
   <java-symbol type="id" name="five" />
   <java-symbol type="id" name="four" />
   <java-symbol type="id" name="icon_menu_presenter" />
   <java-symbol type="id" name="keyboard" />
   <java-symbol type="id" name="list_menu_presenter" />
   <java-symbol type="id" name="lock_screen" />
-  <java-symbol type="id" name="login" />
   <java-symbol type="id" name="nine" />
   <java-symbol type="id" name="no_applications_message" />
   <java-symbol type="id" name="ok" />
@@ -1274,57 +1336,14 @@
   <java-symbol type="id" name="option1" />
   <java-symbol type="id" name="option2" />
   <java-symbol type="id" name="option3" />
-  <java-symbol type="id" name="password" />
-  <java-symbol type="id" name="passwordEntry" />
-  <java-symbol type="id" name="pinEntry" />
   <java-symbol type="id" name="right_icon" />
   <java-symbol type="id" name="seven" />
   <java-symbol type="id" name="six" />
   <java-symbol type="id" name="status" />
-  <java-symbol type="id" name="switch_ime_button" />
   <java-symbol type="id" name="three" />
   <java-symbol type="id" name="title_container" />
   <java-symbol type="id" name="two" />
   <java-symbol type="id" name="zero" />
-  <java-symbol type="id" name="keyguard_message_area" />
-  <java-symbol type="id" name="keyguard_click_area" />
-  <java-symbol type="id" name="keyguard_selector_view" />
-  <java-symbol type="id" name="keyguard_pattern_view" />
-  <java-symbol type="id" name="keyguard_password_view" />
-  <java-symbol type="id" name="keyguard_pin_view" />
-  <java-symbol type="id" name="keyguard_face_unlock_view" />
-  <java-symbol type="id" name="keyguard_sim_pin_view" />
-  <java-symbol type="id" name="keyguard_sim_puk_view" />
-  <java-symbol type="id" name="keyguard_account_view" />
-  <java-symbol type="id" name="keyguard_selector_fade_container" />
-  <java-symbol type="id" name="keyguard_widget_pager_delete_target" />
-  <java-symbol type="id" name="keyguard_bouncer_frame" />
-  <java-symbol type="id" name="app_widget_container" />
-  <java-symbol type="id" name="view_flipper" />
-  <java-symbol type="id" name="carrier_text" />
-  <java-symbol type="id" name="emergency_call_button" />
-  <java-symbol type="id" name="keyguard_host_view" />
-  <java-symbol type="id" name="delete_button" />
-  <java-symbol type="id" name="lockPatternView" />
-  <java-symbol type="id" name="forgot_password_button" />
-  <java-symbol type="id" name="glow_pad_view" />
-  <java-symbol type="id" name="delete_button" />
-  <java-symbol type="id" name="keyguard_user_avatar" />
-  <java-symbol type="id" name="keyguard_user_name" />
-  <java-symbol type="id" name="keyguard_transport_control" />
-  <java-symbol type="id" name="keyguard_status_view" />
-  <java-symbol type="id" name="keyguard_status_view_face_palm" />
-  <java-symbol type="id" name="keyguard_users_grid" />
-  <java-symbol type="id" name="clock_text" />
-  <java-symbol type="id" name="clock_view" />
-  <java-symbol type="id" name="keyguard_multi_user_selector" />
-  <java-symbol type="id" name="sliding_layout" />
-  <java-symbol type="id" name="keyguard_add_widget" />
-  <java-symbol type="id" name="keyguard_add_widget_view" />
-  <java-symbol type="id" name="multi_pane_challenge" />
-  <java-symbol type="id" name="keyguard_user_selector" />
-  <java-symbol type="id" name="key_enter" />
-  <java-symbol type="id" name="keyguard_selector_view_frame" />
   <java-symbol type="integer" name="config_carDockRotation" />
   <java-symbol type="integer" name="config_defaultUiModeType" />
   <java-symbol type="integer" name="config_deskDockRotation" />
@@ -1333,18 +1352,8 @@
   <java-symbol type="integer" name="config_lidNavigationAccessibility" />
   <java-symbol type="integer" name="config_lidOpenRotation" />
   <java-symbol type="integer" name="config_longPressOnHomeBehavior" />
-  <java-symbol type="integer" name="kg_security_flip_duration" />
-  <java-symbol type="integer" name="kg_carousel_angle" />
   <java-symbol type="layout" name="global_actions_item" />
   <java-symbol type="layout" name="global_actions_silent_mode" />
-  <java-symbol type="layout" name="keyguard_selector_view" />
-  <java-symbol type="layout" name="keyguard_pattern_view" />
-  <java-symbol type="layout" name="keyguard_password_view" />
-  <java-symbol type="layout" name="keyguard_pin_view" />
-  <java-symbol type="layout" name="keyguard_face_unlock_view" />
-  <java-symbol type="layout" name="keyguard_sim_pin_view" />
-  <java-symbol type="layout" name="keyguard_sim_puk_view" />
-  <java-symbol type="layout" name="keyguard_account_view" />
   <java-symbol type="layout" name="recent_apps_dialog" />
   <java-symbol type="layout" name="screen_action_bar" />
   <java-symbol type="layout" name="screen_custom_title" />
@@ -1353,9 +1362,6 @@
   <java-symbol type="layout" name="screen_simple_overlay_action_mode" />
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
-  <java-symbol type="layout" name="keyguard_host_view" />
-  <java-symbol type="layout" name="keyguard_transport_control_view" />
-  <java-symbol type="layout" name="keyguard_status_view" />
   <java-symbol type="string" name="system_ui_date_pattern" />
   <java-symbol type="string" name="android_upgrading_title" />
   <java-symbol type="string" name="bugreport_title" />
@@ -1370,82 +1376,13 @@
   <java-symbol type="string" name="global_action_silent_mode_on_status" />
   <java-symbol type="string" name="global_action_toggle_silent_mode" />
   <java-symbol type="string" name="invalidPuk" />
-  <java-symbol type="string" name="keyguard_password_enter_pin_code" />
-  <java-symbol type="string" name="keyguard_password_enter_puk_code" />
-  <java-symbol type="string" name="keyguard_password_wrong_pin_code" />
   <java-symbol type="string" name="lockscreen_carrier_default" />
-  <java-symbol type="string" name="lockscreen_charged" />
-  <java-symbol type="string" name="lockscreen_failed_attempts_almost_at_wipe" />
-  <java-symbol type="string" name="lockscreen_failed_attempts_almost_glogin" />
-  <java-symbol type="string" name="lockscreen_failed_attempts_now_wiping" />
-  <java-symbol type="string" name="lockscreen_forgot_pattern_button_text" />
-  <java-symbol type="string" name="lockscreen_glogin_checking_password" />
-  <java-symbol type="string" name="lockscreen_glogin_forgot_pattern" />
-  <java-symbol type="string" name="lockscreen_glogin_invalid_input" />
-  <java-symbol type="string" name="lockscreen_glogin_too_many_attempts" />
-  <java-symbol type="string" name="lockscreen_instructions_when_pattern_disabled" />
-  <java-symbol type="string" name="lockscreen_low_battery" />
-  <java-symbol type="string" name="lockscreen_missing_sim_instructions" />
-  <java-symbol type="string" name="lockscreen_missing_sim_instructions_long" />
-  <java-symbol type="string" name="lockscreen_missing_sim_message_short" />
-  <java-symbol type="string" name="lockscreen_network_locked_message" />
-  <java-symbol type="string" name="lockscreen_password_wrong" />
-  <java-symbol type="string" name="lockscreen_pattern_instructions" />
-  <java-symbol type="string" name="lockscreen_pattern_wrong" />
-  <java-symbol type="string" name="lockscreen_permanent_disabled_sim_message_short" />
-  <java-symbol type="string" name="lockscreen_permanent_disabled_sim_instructions" />
-  <java-symbol type="string" name="lockscreen_plugged_in" />
-  <java-symbol type="string" name="lockscreen_sim_locked_message" />
-  <java-symbol type="string" name="lockscreen_sim_puk_locked_message" />
-  <java-symbol type="string" name="lockscreen_sim_unlock_progress_dialog_message" />
-  <java-symbol type="string" name="lockscreen_sound_off_label" />
-  <java-symbol type="string" name="lockscreen_sound_on_label" />
-  <java-symbol type="string" name="lockscreen_too_many_failed_attempts_countdown" />
-  <java-symbol type="string" name="lockscreen_too_many_failed_attempts_dialog_message" />
-  <java-symbol type="string" name="lockscreen_too_many_failed_password_attempts_dialog_message" />
-  <java-symbol type="string" name="lockscreen_too_many_failed_pin_attempts_dialog_message" />
-  <java-symbol type="string" name="lockscreen_unlock_label" />
-  <java-symbol type="string" name="status_bar_device_locked" />
   <java-symbol type="style" name="Animation.LockScreen" />
   <java-symbol type="style" name="Theme.Dialog.RecentApplications" />
   <java-symbol type="style" name="Theme.ExpandedMenu" />
   <java-symbol type="style" name="Widget.Button.NumPadKey" />
   <java-symbol type="style" name="TextAppearance.NumPadKey" />
   <java-symbol type="style" name="TextAppearance.NumPadKey.Klondike" />
-  <java-symbol type="string" name="kg_emergency_call_label" />
-  <java-symbol type="string" name="kg_forgot_pattern_button_text" />
-  <java-symbol type="string" name="kg_wrong_pattern" />
-  <java-symbol type="string" name="kg_wrong_password" />
-  <java-symbol type="string" name="kg_wrong_pin" />
-  <java-symbol type="string" name="kg_too_many_failed_attempts_countdown" />
-  <java-symbol type="string" name="kg_pattern_instructions" />
-  <java-symbol type="string" name="kg_sim_pin_instructions" />
-  <java-symbol type="string" name="kg_pin_instructions" />
-  <java-symbol type="string" name="kg_password_instructions" />
-  <java-symbol type="string" name="kg_puk_enter_puk_hint" />
-  <java-symbol type="string" name="kg_puk_enter_pin_hint" />
-  <java-symbol type="string" name="kg_sim_unlock_progress_dialog_message" />
-  <java-symbol type="string" name="kg_password_wrong_pin_code" />
-  <java-symbol type="string" name="kg_invalid_sim_pin_hint" />
-  <java-symbol type="string" name="kg_invalid_sim_puk_hint" />
-  <java-symbol type="string" name="kg_invalid_puk" />
-  <java-symbol type="string" name="kg_login_too_many_attempts" />
-  <java-symbol type="string" name="kg_login_instructions" />
-  <java-symbol type="string" name="kg_login_username_hint" />
-  <java-symbol type="string" name="kg_login_password_hint" />
-  <java-symbol type="string" name="kg_login_submit_button" />
-  <java-symbol type="string" name="kg_login_invalid_input" />
-  <java-symbol type="string" name="kg_login_account_recovery_hint" />
-  <java-symbol type="string" name="kg_login_checking_password" />
-  <java-symbol type="string" name="kg_too_many_failed_pin_attempts_dialog_message" />
-  <java-symbol type="string" name="kg_too_many_failed_pattern_attempts_dialog_message" />
-  <java-symbol type="string" name="kg_too_many_failed_password_attempts_dialog_message" />
-  <java-symbol type="string" name="kg_failed_attempts_almost_at_wipe" />
-  <java-symbol type="string" name="kg_failed_attempts_now_wiping" />
-  <java-symbol type="string" name="kg_failed_attempts_almost_at_login" />
-  <java-symbol type="string" name="kg_enter_confirm_pin_hint" />
-  <java-symbol type="string" name="kg_invalid_confirm_pin_hint" />
-  <java-symbol type="string" name="kg_text_message_separator" />
 
   <!-- From services -->
   <java-symbol type="anim" name="screen_rotate_0_enter" />
@@ -1661,17 +1598,21 @@
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
 
-  <java-symbol type="layout" name="resolver_grid" />
-  <java-symbol type="id" name="resolver_grid" />
+  <java-symbol type="layout" name="resolver_list" />
+  <java-symbol type="id" name="resolver_list" />
   <java-symbol type="id" name="button_once" />
   <java-symbol type="id" name="button_always" />
   <java-symbol type="integer" name="config_maxResolverActivityColumns" />
+  <java-symbol type="array" name="config_notificationScorers" />
 
   <!-- From SystemUI -->
   <java-symbol type="anim" name="push_down_in" />
   <java-symbol type="anim" name="push_down_out" />
   <java-symbol type="anim" name="push_up_in" />
   <java-symbol type="anim" name="push_up_out" />
+  <java-symbol type="anim" name="lock_screen_wallpaper_behind_enter" />
+  <java-symbol type="anim" name="lock_screen_behind_enter" />
+ 
   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
   <java-symbol type="dimen" name="status_bar_icon_size" />
   <java-symbol type="dimen" name="system_bar_icon_size" />
@@ -1770,6 +1711,7 @@
   <java-symbol type="bool" name="config_sf_slowBlur" />
   <java-symbol type="drawable" name="ic_volume" />
   <java-symbol type="drawable" name="stat_notify_sim_toolkit" />
+  <java-symbol type="bool" name="config_stkNoAlphaUsrCnf" />
 
   <!-- From maps library -->
   <java-symbol type="array" name="maps_starting_lat_lng" />
@@ -1793,4 +1735,9 @@
   <java-symbol type="attr" name="actionModeWebSearchDrawable" />
   <java-symbol type="string" name="websearch" />
 
+  <!-- From SubtitleView -->
+  <java-symbol type="dimen" name="subtitle_corner_radius" />
+  <java-symbol type="dimen" name="subtitle_shadow_radius" />
+  <java-symbol type="dimen" name="subtitle_shadow_offset" />
+  <java-symbol type="dimen" name="subtitle_outline_width" />
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 80f7486..eb39926 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -311,6 +311,10 @@
         <item name="ringtonePreferenceStyle">@android:style/Preference.RingtonePreference</item>
         <item name="preferenceLayoutChild">@android:layout/preference_child</item>
         <item name="preferencePanelStyle">@style/PreferencePanel</item>
+        <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel</item>
+        <item name="preferenceListStyle">@style/PreferenceHeaderList</item>
+        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList</item>
+        <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side</item>
         <item name="detailsElementBackground">@android:drawable/panel_bg_holo_dark</item>
 
         <!-- Search widget styles -->
@@ -905,8 +909,8 @@
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
 
-        <item name="colorPressedHighlight">@color/holo_blue_light</item>
-        <item name="colorLongPressedHighlight">@color/holo_blue_bright</item>
+        <item name="colorPressedHighlight">@color/holo_gray_light</item>
+        <item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
         <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
         <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
         <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
@@ -1220,8 +1224,8 @@
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
 
-        <item name="colorPressedHighlight">@color/holo_blue_light</item>
-        <item name="colorLongPressedHighlight">@color/holo_blue_bright</item>
+        <item name="colorPressedHighlight">@color/holo_gray_light</item>
+        <item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
         <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
         <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
         <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
diff --git a/core/res/res/xml/audio_assets.xml b/core/res/res/xml/audio_assets.xml
index 746dbab..af5798a 100644
--- a/core/res/res/xml/audio_assets.xml
+++ b/core/res/res/xml/audio_assets.xml
@@ -34,5 +34,6 @@
         <asset id="FX_KEYPRESS_SPACEBAR" file="KeypressSpacebar.ogg"/>
         <asset id="FX_KEYPRESS_DELETE" file="KeypressDelete.ogg"/>
         <asset id="FX_KEYPRESS_RETURN" file="KeypressReturn.ogg"/>
+        <asset id="FX_KEYPRESS_INVALID" file="KeypressInvalid.ogg"/>
     </group>
 </audio_assets>
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 54881d5..1649268 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -16,21 +16,13 @@
 
 <!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-  package="com.android.connectivitymanagertest"
-  android:sharedUserId="android.uid.system">
+  package="com.android.connectivitymanagertest">
 
     <!-- We add an application tag here just so that we can indicate that
          this package needs to link against the android.test library,
          which is needed when building test cases. -->
     <application>
         <uses-library android:name="android.test.runner" />
-        <activity android:name="ConnectivityManagerTestActivity"
-          android:label="@string/app_name">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
     </application>
 
     <!--
@@ -80,10 +72,14 @@
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+
 </manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 0461c0b..b942eb6 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -32,13 +32,11 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.RouteInfo;
-import android.util.Log;
 
 import java.io.InputStream;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
deleted file mode 100644
index 463e999..0000000
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.connectivitymanagertest;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.widget.LinearLayout;
-
-import com.android.internal.util.AsyncChannel;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * An activity registered with connectivity manager broadcast
- * provides network connectivity information and
- * can be used to set device states: Cellular, Wifi, Airplane mode.
- */
-public class ConnectivityManagerTestActivity extends Activity {
-
-    public static final String LOG_TAG = "ConnectivityManagerTestActivity";
-    public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
-    public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
-    public static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
-    public static final long LONG_TIMEOUT = 50 * 1000;  // 50 seconds
-    public static final long WIFI_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
-    // 2 minutes timer between wifi stop and start
-    public static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; // 2 minutes
-    // Set ping test timer to be 3 minutes
-    public static final long PING_TIMER = 3 * 60 *1000; // 3 minutes
-    public static final int SUCCESS = 0;  // for Wifi tethering state change
-    public static final int FAILURE = 1;
-    public static final int INIT = -1;
-    private static final String ACCESS_POINT_FILE = "accesspoints.xml";
-    public ConnectivityReceiver mConnectivityReceiver = null;
-    public WifiReceiver mWifiReceiver = null;
-    private AccessPointParserHelper mParseHelper = null;
-    /*
-     * Track network connectivity information
-     */
-    public State mState;
-    public NetworkInfo mNetworkInfo;
-    public NetworkInfo mOtherNetworkInfo;
-    public boolean mIsFailOver;
-    public String mReason;
-    public boolean mScanResultIsAvailable = false;
-    public ConnectivityManager mCM;
-    public Object wifiObject = new Object();
-    public Object connectivityObject = new Object();
-    public int mWifiState;
-    public NetworkInfo mWifiNetworkInfo;
-    public String mBssid;
-    public String mPowerSsid = "opennet"; //Default power SSID
-    private Context mContext;
-    public boolean scanResultAvailable = false;
-
-    /*
-     * Control Wifi States
-     */
-    public WifiManager mWifiManager;
-
-    /*
-     * Verify connectivity state
-     */
-    public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
-    NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
-
-    // For wifi tethering tests
-    private String[] mWifiRegexs;
-    public int mWifiTetherResult = INIT;    // -1 is initialization state
-
-    /**
-     * A wrapper of a broadcast receiver which provides network connectivity information
-     * for all kinds of network: wifi, mobile, etc.
-     */
-    private class ConnectivityReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            log("ConnectivityReceiver: onReceive() is called with " + intent);
-            String action = intent.getAction();
-            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
-                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
-                return;
-            }
-
-            boolean noConnectivity =
-                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-
-            if (noConnectivity) {
-                mState = State.DISCONNECTED;
-            } else {
-                mState = State.CONNECTED;
-            }
-
-            mNetworkInfo = (NetworkInfo)
-                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
-
-            mOtherNetworkInfo = (NetworkInfo)
-                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
-
-            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
-            mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
-
-            log("mNetworkInfo: " + mNetworkInfo.toString());
-            if (mOtherNetworkInfo != null) {
-                log("mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
-            }
-            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
-            if (mOtherNetworkInfo != null) {
-                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
-            }
-            notifyNetworkConnectivityChange();
-        }
-    }
-
-    private class WifiReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
-            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
-                log("scan results are available");
-                notifyScanResult();
-            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                mWifiNetworkInfo =
-                    (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-                log("mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
-                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
-                    mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
-                }
-                notifyWifiState();
-            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                                                WifiManager.WIFI_STATE_UNKNOWN);
-                notifyWifiState();
-            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
-                notifyWifiAPState();
-            } else if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
-                ArrayList<String> available = intent.getStringArrayListExtra(
-                        ConnectivityManager.EXTRA_AVAILABLE_TETHER);
-                ArrayList<String> active = intent.getStringArrayListExtra(
-                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
-                ArrayList<String> errored = intent.getStringArrayListExtra(
-                        ConnectivityManager.EXTRA_ERRORED_TETHER);
-                updateTetherState(available.toArray(), active.toArray(), errored.toArray());
-            }
-            else {
-                return;
-            }
-        }
-    }
-
-    private class WifiServiceHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        //AsyncChannel in msg.obj
-                    } else {
-                        log("Failed to establish AsyncChannel connection");
-                    }
-                    break;
-                default:
-                    //Ignore
-                    break;
-            }
-        }
-    }
-
-    public ConnectivityManagerTestActivity() {
-        mState = State.UNKNOWN;
-        scanResultAvailable = false;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        log("onCreate, inst=" + Integer.toHexString(hashCode()));
-
-        // Create a simple layout
-        LinearLayout contentView = new LinearLayout(this);
-        contentView.setOrientation(LinearLayout.VERTICAL);
-        setContentView(contentView);
-        setTitle("ConnectivityManagerTestActivity");
-
-
-        // register a connectivity receiver for CONNECTIVITY_ACTION;
-        mConnectivityReceiver = new ConnectivityReceiver();
-        registerReceiver(mConnectivityReceiver,
-                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
-
-        mWifiReceiver = new WifiReceiver();
-        IntentFilter mIntentFilter = new IntentFilter();
-        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
-        mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
-        registerReceiver(mWifiReceiver, mIntentFilter);
-
-        // Get an instance of ConnectivityManager
-        mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
-        // Get an instance of WifiManager
-        mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
-        mContext = this;
-
-        if (mWifiManager.isWifiApEnabled()) {
-            // if soft AP is enabled, disable it
-            mWifiManager.setWifiApEnabled(null, false);
-            log("Disable soft ap");
-        }
-
-        initializeNetworkStates();
-        log("Clear Wifi before we start the test.");
-        removeConfiguredNetworksAndDisableWifi();
-        mWifiRegexs = mCM.getTetherableWifiRegexs();
-     }
-
-    public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
-        InputStream in = getAssets().open(ACCESS_POINT_FILE);
-        mParseHelper = new AccessPointParserHelper(in);
-        return mParseHelper.getNetworkConfigurations();
-    }
-
-    // for each network type, initialize network states to UNKNOWN, and no verification flag is set
-    public void initializeNetworkStates() {
-        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
-            connectivityState[networkType] =  new NetworkState();
-            log("Initialize network state for " + networkType + ": " +
-                    connectivityState[networkType].toString());
-        }
-    }
-
-    // deposit a network state
-    public void recordNetworkState(int networkType, State networkState) {
-        log("record network state for network " +  networkType +
-                ", state is " + networkState);
-        connectivityState[networkType].recordState(networkState);
-    }
-
-    // set the state transition criteria
-    public void setStateTransitionCriteria(int networkType, State initState,
-            int transitionDir, State targetState) {
-        connectivityState[networkType].setStateTransitionCriteria(
-                initState, transitionDir, targetState);
-    }
-
-    // Validate the states recorded
-    public boolean validateNetworkStates(int networkType) {
-        log("validate network state for " + networkType + ": ");
-        return connectivityState[networkType].validateStateTransition();
-    }
-
-    // return result from network state validation
-    public String getTransitionFailureReason(int networkType) {
-        log("get network state transition failure reason for " + networkType + ": " +
-                connectivityState[networkType].toString());
-        return connectivityState[networkType].getReason();
-    }
-
-    private void notifyNetworkConnectivityChange() {
-        synchronized(connectivityObject) {
-            log("notify network connectivity changed");
-            connectivityObject.notifyAll();
-        }
-    }
-    private void notifyScanResult() {
-        synchronized (this) {
-            log("notify that scan results are available");
-            scanResultAvailable = true;
-            this.notify();
-        }
-    }
-
-    private void notifyWifiState() {
-        synchronized (wifiObject) {
-            log("notify wifi state changed");
-            wifiObject.notify();
-        }
-    }
-
-    private void notifyWifiAPState() {
-        synchronized (this) {
-            log("notify wifi AP state changed");
-            this.notify();
-        }
-    }
-
-    // Update wifi tethering state
-    private void updateTetherState(Object[] available, Object[] tethered, Object[] errored) {
-        boolean wifiTethered = false;
-        boolean wifiErrored = false;
-
-        synchronized (this) {
-            for (Object obj: tethered) {
-                String str = (String)obj;
-                for (String tethRex: mWifiRegexs) {
-                    log("str: " + str +"tethRex: " + tethRex);
-                    if (str.matches(tethRex)) {
-                        wifiTethered = true;
-                    }
-                }
-            }
-
-            for (Object obj: errored) {
-                String str = (String)obj;
-                for (String tethRex: mWifiRegexs) {
-                    log("error: str: " + str +"tethRex: " + tethRex);
-                    if (str.matches(tethRex)) {
-                        wifiErrored = true;
-                    }
-                }
-            }
-
-            if (wifiTethered) {
-                mWifiTetherResult = SUCCESS;   // wifi tethering is successful
-            } else if (wifiErrored) {
-                mWifiTetherResult = FAILURE;   // wifi tethering failed
-            }
-            log("mWifiTetherResult: " + mWifiTetherResult);
-            this.notify();
-        }
-    }
-
-
-    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
-    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
-    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            if ((System.currentTimeMillis() - startTime) > timeout) {
-                log("waitForNetworkState time out, the state of network type " + networkType +
-                        " is: " + mCM.getNetworkInfo(networkType).getState());
-                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
-                    return false;
-                } else {
-                    // the broadcast has been sent out. the state has been changed.
-                    log("networktype: " + networkType + " state: " +
-                            mCM.getNetworkInfo(networkType));
-                    return true;
-                }
-            }
-            log("Wait for the connectivity state for network: " + networkType +
-                    " to be " + expectedState.toString());
-            synchronized (connectivityObject) {
-                try {
-                    connectivityObject.wait(SHORT_TIMEOUT);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                if ((mNetworkInfo.getType() != networkType) ||
-                    (mNetworkInfo.getState() != expectedState)) {
-                    log("network state for " + mNetworkInfo.getType() +
-                            "is: " + mNetworkInfo.getState());
-                    continue;
-                }
-                return true;
-            }
-        }
-    }
-
-    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
-    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
-    public boolean waitForWifiState(int expectedState, long timeout) {
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            if ((System.currentTimeMillis() - startTime) > timeout) {
-                if (mWifiState != expectedState) {
-                    return false;
-                } else {
-                    return true;
-                }
-            }
-            log("Wait for wifi state to be: " + expectedState);
-            synchronized (wifiObject) {
-                try {
-                    wifiObject.wait(SHORT_TIMEOUT);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                if (mWifiState != expectedState) {
-                    log("Wifi state is: " + mWifiState);
-                    continue;
-                }
-                return true;
-            }
-        }
-    }
-
-    // Wait for Wifi AP state: WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING,
-    //                         WIFI_AP_STATE_ENABLED, WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
-    public boolean waitForWifiAPState(int expectedState, long timeout) {
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            if ((System.currentTimeMillis() - startTime) > timeout) {
-                if (mWifiManager.getWifiApState() != expectedState) {
-                    return false;
-                } else {
-                    return true;
-                }
-            }
-            log("Wait for wifi AP state to be: " + expectedState);
-            synchronized (wifiObject) {
-                try {
-                    wifiObject.wait(SHORT_TIMEOUT);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                if (mWifiManager.getWifiApState() != expectedState) {
-                    log("Wifi state is: " + mWifiManager.getWifiApState());
-                    continue;
-                }
-                return true;
-            }
-        }
-    }
-
-    /**
-     * Wait for the wifi tethering result:
-     * @param timeout is the maximum waiting time
-     * @return SUCCESS if tethering result is successful
-     *         FAILURE if tethering result returns error.
-     */
-    public int waitForTetherStateChange(long timeout) {
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            if ((System.currentTimeMillis() - startTime) > timeout) {
-                return mWifiTetherResult;
-            }
-            log("Wait for wifi tethering result.");
-            synchronized (this) {
-                try {
-                    this.wait(SHORT_TIMEOUT);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                if (mWifiTetherResult == INIT ) {
-                    continue;
-                } else {
-                    return mWifiTetherResult;
-                }
-            }
-        }
-    }
-
-    // Return true if device is currently connected to mobile network
-    public boolean isConnectedToMobile() {
-        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
-    }
-
-    // Return true if device is currently connected to Wifi
-    public boolean isConnectedToWifi() {
-        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
-    }
-
-    public boolean enableWifi() {
-        return mWifiManager.setWifiEnabled(true);
-    }
-
-    // Turn screen off
-    public void turnScreenOff() {
-        log("Turn screen off");
-        PowerManager pm =
-            (PowerManager) getSystemService(Context.POWER_SERVICE);
-        pm.goToSleep(SystemClock.uptimeMillis());
-    }
-
-    // Turn screen on
-    public void turnScreenOn() {
-        log("Turn screen on");
-        PowerManager pm =
-                (PowerManager) getSystemService(Context.POWER_SERVICE);
-        pm.wakeUp(SystemClock.uptimeMillis());
-    }
-
-    /**
-     * @param pingServerList a list of servers that can be used for ping test, can be null
-     * @return true if the ping test is successful, false otherwise.
-     */
-    public boolean pingTest(String[] pingServerList) {
-        String[] hostList = {"www.google.com", "www.yahoo.com",
-                "www.bing.com", "www.facebook.com", "www.ask.com"};
-        if (pingServerList != null) {
-            hostList = pingServerList;
-        }
-
-        long startTime = System.currentTimeMillis();
-        while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
-            try {
-                // assume the chance that all servers are down is very small
-                for (int i = 0; i < hostList.length; i++ ) {
-                    String host = hostList[i];
-                    log("Start ping test, ping " + host);
-                    Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
-                    int status = p.waitFor();
-                    if (status == 0) {
-                        // if any of the ping test is successful, return true
-                        return true;
-                    }
-                }
-            } catch (UnknownHostException e) {
-                log("Ping test Fail: Unknown Host");
-            } catch (IOException e) {
-                log("Ping test Fail:  IOException");
-            } catch (InterruptedException e) {
-                log("Ping test Fail: InterruptedException");
-            }
-        }
-        // ping test timeout
-        return false;
-    }
-
-    /**
-     * Associate the device to given SSID
-     * If the device is already associated with a WiFi, disconnect and forget it,
-     * We don't verify whether the connection is successful or not, leave this to the test
-     */
-    public boolean connectToWifi(String knownSSID) {
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = knownSSID;
-        config.allowedKeyManagement.set(KeyMgmt.NONE);
-        return connectToWifiWithConfiguration(config);
-    }
-
-    /**
-     * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
-     * is pure string, we need to convert it to quoted string.
-     * @param config
-     * @return
-     */
-    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
-        String ssid = config.SSID;
-        config.SSID = convertToQuotedString(ssid);
-
-        // If Wifi is not enabled, enable it
-        if (!mWifiManager.isWifiEnabled()) {
-            log("Wifi is not enabled, enable it");
-            mWifiManager.setWifiEnabled(true);
-            // wait for the wifi state change before start scanning.
-            if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2*SHORT_TIMEOUT)) {
-                log("wait for WIFI_STATE_ENABLED failed");
-                return false;
-            }
-        }
-
-        // Save network configuration and connect to network without scanning
-        mWifiManager.connect(config,
-            new WifiManager.ActionListener() {
-                public void onSuccess() {
-                }
-                public void onFailure(int reason) {
-                    log("connect failure " + reason);
-                }
-            });
-        return true;
-    }
-
-    /*
-     * Disconnect from the current AP and remove configured networks.
-     */
-    public boolean disconnectAP() {
-        // remove saved networks
-        if (!mWifiManager.isWifiEnabled()) {
-            log("Enabled wifi before remove configured networks");
-            mWifiManager.setWifiEnabled(true);
-            sleep(SHORT_TIMEOUT);
-        }
-        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
-        log("size of wifiConfigList: " + wifiConfigList.size());
-        for (WifiConfiguration wifiConfig: wifiConfigList) {
-            log("remove wifi configuration: " + wifiConfig.networkId);
-            int netId = wifiConfig.networkId;
-            mWifiManager.forget(netId, new WifiManager.ActionListener() {
-                    public void onSuccess() {
-                    }
-                    public void onFailure(int reason) {
-                        log("Failed to forget " + reason);
-                    }
-                });
-        }
-        return true;
-    }
-    /**
-     * Disable Wifi
-     * @return true if Wifi is disabled successfully
-     */
-    public boolean disableWifi() {
-        return mWifiManager.setWifiEnabled(false);
-    }
-
-    /**
-     * Remove configured networks and disable wifi
-     */
-    public boolean removeConfiguredNetworksAndDisableWifi() {
-        if (!disconnectAP()) {
-           return false;
-        }
-        sleep(SHORT_TIMEOUT);
-        if (!mWifiManager.setWifiEnabled(false)) {
-            return false;
-        }
-        sleep(SHORT_TIMEOUT);
-        return true;
-    }
-
-    private void sleep(long sleeptime) {
-        try {
-            Thread.sleep(sleeptime);
-        } catch (InterruptedException e) {}
-    }
-
-    /**
-     * Set airplane mode
-     */
-    public void setAirplaneMode(Context context, boolean enableAM) {
-        //set the airplane mode
-        Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
-                enableAM ? 1 : 0);
-        // Post the intent
-        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", enableAM);
-        context.sendBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    protected static String convertToQuotedString(String string) {
-        return "\"" + string + "\"";
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-
-        //Unregister receiver
-        if (mConnectivityReceiver != null) {
-            unregisterReceiver(mConnectivityReceiver);
-        }
-        if (mWifiReceiver != null) {
-            unregisterReceiver(mWifiReceiver);
-        }
-        log("onDestroy, inst=" + Integer.toHexString(hashCode()));
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mContext = this;
-        Bundle bundle = this.getIntent().getExtras();
-        if (bundle != null){
-            mPowerSsid = bundle.getString("power_ssid");
-        }
-    }
-    //A thread to set the device into airplane mode then turn on wifi.
-    Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
-        public void run() {
-            setAirplaneMode(mContext, true);
-            connectToWifi(mPowerSsid);
-        }
-    });
-
-    //A thread to set the device into wifi
-    Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() {
-        public void run() {
-            connectToWifi(mPowerSsid);
-        }
-    });
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-            //This is a tricky way for the scripted monkey to
-            //set the device in wifi and wifi in airplane mode.
-            case KeyEvent.KEYCODE_1:
-                setDeviceWifiAndAirplaneThread.start();
-                break;
-
-            case KeyEvent.KEYCODE_2:
-                setDeviceInWifiOnlyThread.start();
-                break;
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-
-    private void log(String message) {
-        Log.v(LOG_TAG, message);
-    }
-}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
new file mode 100644
index 0000000..30eda75
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.connectivitymanagertest;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.internal.util.AsyncChannel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Base InstrumentationTestCase for Connectivity Manager (CM) test suite
+ *
+ * It registers connectivity manager broadcast and WiFi broadcast to provide
+ * network connectivity information, also provides a set of utility functions
+ * to modify and verify connectivity states.
+ *
+ * A CM test case should extend this base class.
+ */
+public class ConnectivityManagerTestBase extends InstrumentationTestCase {
+
+    public static final String LOG_TAG = "ConnectivityManagerTestBase";
+    public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
+    public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
+    public static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
+    public static final long LONG_TIMEOUT = 50 * 1000;  // 50 seconds
+    public static final long WIFI_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
+    // 2 minutes timer between wifi stop and start
+    public static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; // 2 minutes
+    // Set ping test timer to be 3 minutes
+    public static final long PING_TIMER = 3 * 60 *1000; // 3 minutes
+    public static final int SUCCESS = 0;  // for Wifi tethering state change
+    public static final int FAILURE = 1;
+    public static final int INIT = -1;
+    private static final String ACCESS_POINT_FILE = "accesspoints.xml";
+    public ConnectivityReceiver mConnectivityReceiver = null;
+    public WifiReceiver mWifiReceiver = null;
+    private AccessPointParserHelper mParseHelper = null;
+    /*
+     * Track network connectivity information
+     */
+    public State mState;
+    public NetworkInfo mNetworkInfo;
+    public NetworkInfo mOtherNetworkInfo;
+    public boolean mIsFailOver;
+    public String mReason;
+    public boolean mScanResultIsAvailable = false;
+    public ConnectivityManager mCM;
+    public Object wifiObject = new Object();
+    public Object connectivityObject = new Object();
+    public int mWifiState;
+    public NetworkInfo mWifiNetworkInfo;
+    public String mBssid;
+    public String mPowerSsid = "opennet"; //Default power SSID
+    private Context mContext;
+    public boolean scanResultAvailable = false;
+
+    /* Control Wifi States */
+    public WifiManager mWifiManager;
+    /* Verify connectivity state */
+    public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
+    NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
+
+    // For wifi tethering tests
+    private String[] mWifiRegexs;
+    public int mWifiTetherResult = INIT;    // -1 is initialization state
+
+    /**
+     * A wrapper of a broadcast receiver which provides network connectivity information
+     * for all kinds of network: wifi, mobile, etc.
+     */
+    private class ConnectivityReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            log("ConnectivityReceiver: onReceive() is called with " + intent);
+            String action = intent.getAction();
+            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
+                return;
+            }
+
+            boolean noConnectivity =
+                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+
+            if (noConnectivity) {
+                mState = State.DISCONNECTED;
+            } else {
+                mState = State.CONNECTED;
+            }
+
+            mNetworkInfo = (NetworkInfo)
+                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+
+            mOtherNetworkInfo = (NetworkInfo)
+                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
+
+            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
+            mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
+
+            log("mNetworkInfo: " + mNetworkInfo.toString());
+            if (mOtherNetworkInfo != null) {
+                log("mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
+            }
+            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
+            if (mOtherNetworkInfo != null) {
+                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
+            }
+            notifyNetworkConnectivityChange();
+        }
+    }
+
+    private class WifiReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
+            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                log("scan results are available");
+                notifyScanResult();
+            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                mWifiNetworkInfo =
+                    (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+                log("mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
+                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
+                    mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
+                }
+                notifyWifiState();
+            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                                                WifiManager.WIFI_STATE_UNKNOWN);
+                notifyWifiState();
+            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+                notifyWifiAPState();
+            } else if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
+                ArrayList<String> available = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+                ArrayList<String> active = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
+                ArrayList<String> errored = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_ERRORED_TETHER);
+                updateTetherState(available.toArray(), active.toArray(), errored.toArray());
+            }
+            else {
+                return;
+            }
+        }
+    }
+
+    private class WifiServiceHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        //AsyncChannel in msg.obj
+                    } else {
+                        log("Failed to establish AsyncChannel connection");
+                    }
+                    break;
+                default:
+                    //Ignore
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        mState = State.UNKNOWN;
+        scanResultAvailable = false;
+        mContext = getInstrumentation().getContext();
+
+        // Get an instance of ConnectivityManager
+        mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        // Get an instance of WifiManager
+        mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
+
+        if (mWifiManager.isWifiApEnabled()) {
+            // if soft AP is enabled, disable it
+            mWifiManager.setWifiApEnabled(null, false);
+            log("Disable soft ap");
+        }
+
+        initializeNetworkStates();
+
+        // register a connectivity receiver for CONNECTIVITY_ACTION;
+        mConnectivityReceiver = new ConnectivityReceiver();
+        mContext.registerReceiver(mConnectivityReceiver,
+                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+
+        mWifiReceiver = new WifiReceiver();
+        IntentFilter mIntentFilter = new IntentFilter();
+        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+        mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        mContext.registerReceiver(mWifiReceiver, mIntentFilter);
+
+        log("Clear Wifi before we start the test.");
+        removeConfiguredNetworksAndDisableWifi();
+        mWifiRegexs = mCM.getTetherableWifiRegexs();
+     }
+
+    public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
+        InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE);
+        mParseHelper = new AccessPointParserHelper(in);
+        return mParseHelper.getNetworkConfigurations();
+    }
+
+    // for each network type, initialize network states to UNKNOWN, and no verification flag is set
+    public void initializeNetworkStates() {
+        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
+            connectivityState[networkType] =  new NetworkState();
+            log("Initialize network state for " + networkType + ": " +
+                    connectivityState[networkType].toString());
+        }
+    }
+
+    // deposit a network state
+    public void recordNetworkState(int networkType, State networkState) {
+        log("record network state for network " +  networkType +
+                ", state is " + networkState);
+        if (connectivityState == null) {
+             log("ConnectivityState is null");
+        }
+        if (connectivityState[networkType] == null) {
+             log("connectivityState[networkType] is null");
+        }
+        connectivityState[networkType].recordState(networkState);
+    }
+
+    // set the state transition criteria
+    public void setStateTransitionCriteria(int networkType, State initState,
+            int transitionDir, State targetState) {
+        connectivityState[networkType].setStateTransitionCriteria(
+                initState, transitionDir, targetState);
+    }
+
+    // Validate the states recorded
+    public boolean validateNetworkStates(int networkType) {
+        log("validate network state for " + networkType + ": ");
+        return connectivityState[networkType].validateStateTransition();
+    }
+
+    // return result from network state validation
+    public String getTransitionFailureReason(int networkType) {
+        log("get network state transition failure reason for " + networkType + ": " +
+                connectivityState[networkType].toString());
+        return connectivityState[networkType].getReason();
+    }
+
+    private void notifyNetworkConnectivityChange() {
+        synchronized(connectivityObject) {
+            log("notify network connectivity changed");
+            connectivityObject.notifyAll();
+        }
+    }
+    private void notifyScanResult() {
+        synchronized (this) {
+            log("notify that scan results are available");
+            scanResultAvailable = true;
+            this.notify();
+        }
+    }
+
+    private void notifyWifiState() {
+        synchronized (wifiObject) {
+            log("notify wifi state changed");
+            wifiObject.notify();
+        }
+    }
+
+    private void notifyWifiAPState() {
+        synchronized (this) {
+            log("notify wifi AP state changed");
+            this.notify();
+        }
+    }
+
+    // Update wifi tethering state
+    private void updateTetherState(Object[] available, Object[] tethered, Object[] errored) {
+        boolean wifiTethered = false;
+        boolean wifiErrored = false;
+
+        synchronized (this) {
+            for (Object obj: tethered) {
+                String str = (String)obj;
+                for (String tethRex: mWifiRegexs) {
+                    log("str: " + str +"tethRex: " + tethRex);
+                    if (str.matches(tethRex)) {
+                        wifiTethered = true;
+                    }
+                }
+            }
+
+            for (Object obj: errored) {
+                String str = (String)obj;
+                for (String tethRex: mWifiRegexs) {
+                    log("error: str: " + str +"tethRex: " + tethRex);
+                    if (str.matches(tethRex)) {
+                        wifiErrored = true;
+                    }
+                }
+            }
+
+            if (wifiTethered) {
+                mWifiTetherResult = SUCCESS;   // wifi tethering is successful
+            } else if (wifiErrored) {
+                mWifiTetherResult = FAILURE;   // wifi tethering failed
+            }
+            log("mWifiTetherResult: " + mWifiTetherResult);
+            this.notify();
+        }
+    }
+
+
+    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
+    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
+    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                log("waitForNetworkState time out, the state of network type " + networkType +
+                        " is: " + mCM.getNetworkInfo(networkType).getState());
+                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
+                    return false;
+                } else {
+                    // the broadcast has been sent out. the state has been changed.
+                    log("networktype: " + networkType + " state: " +
+                            mCM.getNetworkInfo(networkType));
+                    return true;
+                }
+            }
+            log("Wait for the connectivity state for network: " + networkType +
+                    " to be " + expectedState.toString());
+            synchronized (connectivityObject) {
+                try {
+                    connectivityObject.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if ((mNetworkInfo.getType() != networkType) ||
+                    (mNetworkInfo.getState() != expectedState)) {
+                    log("network state for " + mNetworkInfo.getType() +
+                            "is: " + mNetworkInfo.getState());
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
+    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
+    public boolean waitForWifiState(int expectedState, long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (mWifiState != expectedState) {
+                    return false;
+                } else {
+                    return true;
+                }
+            }
+            log("Wait for wifi state to be: " + expectedState);
+            synchronized (wifiObject) {
+                try {
+                    wifiObject.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if (mWifiState != expectedState) {
+                    log("Wifi state is: " + mWifiState);
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    // Wait for Wifi AP state: WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING,
+    //                         WIFI_AP_STATE_ENABLED, WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
+    public boolean waitForWifiAPState(int expectedState, long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (mWifiManager.getWifiApState() != expectedState) {
+                    return false;
+                } else {
+                    return true;
+                }
+            }
+            log("Wait for wifi AP state to be: " + expectedState);
+            synchronized (wifiObject) {
+                try {
+                    wifiObject.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if (mWifiManager.getWifiApState() != expectedState) {
+                    log("Wifi state is: " + mWifiManager.getWifiApState());
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Wait for the wifi tethering result:
+     * @param timeout is the maximum waiting time
+     * @return SUCCESS if tethering result is successful
+     *         FAILURE if tethering result returns error.
+     */
+    public int waitForTetherStateChange(long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                return mWifiTetherResult;
+            }
+            log("Wait for wifi tethering result.");
+            synchronized (this) {
+                try {
+                    this.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if (mWifiTetherResult == INIT ) {
+                    continue;
+                } else {
+                    return mWifiTetherResult;
+                }
+            }
+        }
+    }
+
+    // Return true if device is currently connected to mobile network
+    public boolean isConnectedToMobile() {
+        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
+    }
+
+    // Return true if device is currently connected to Wifi
+    public boolean isConnectedToWifi() {
+        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
+    }
+
+    public boolean enableWifi() {
+        return mWifiManager.setWifiEnabled(true);
+    }
+
+    // Turn screen off
+    public void turnScreenOff() {
+        log("Turn screen off");
+        PowerManager pm =
+            (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        pm.goToSleep(SystemClock.uptimeMillis());
+    }
+
+    // Turn screen on
+    public void turnScreenOn() {
+        log("Turn screen on");
+        PowerManager pm =
+                (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        pm.wakeUp(SystemClock.uptimeMillis());
+        // disable lock screen
+        KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        if (km.inKeyguardRestrictedInputMode()) {
+            sendKeys(KeyEvent.KEYCODE_MENU);
+        }
+    }
+
+    /**
+     * @param pingServerList a list of servers that can be used for ping test, can be null
+     * @return true if the ping test is successful, false otherwise.
+     */
+    public boolean pingTest(String[] pingServerList) {
+        String[] hostList = {"www.google.com", "www.yahoo.com",
+                "www.bing.com", "www.facebook.com", "www.ask.com"};
+        if (pingServerList != null) {
+            hostList = pingServerList;
+        }
+
+        long startTime = System.currentTimeMillis();
+        while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
+            try {
+                // assume the chance that all servers are down is very small
+                for (int i = 0; i < hostList.length; i++ ) {
+                    String host = hostList[i];
+                    log("Start ping test, ping " + host);
+                    Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
+                    int status = p.waitFor();
+                    if (status == 0) {
+                        // if any of the ping test is successful, return true
+                        return true;
+                    }
+                }
+            } catch (UnknownHostException e) {
+                log("Ping test Fail: Unknown Host");
+            } catch (IOException e) {
+                log("Ping test Fail:  IOException");
+            } catch (InterruptedException e) {
+                log("Ping test Fail: InterruptedException");
+            }
+        }
+        // ping test timeout
+        return false;
+    }
+
+    /**
+     * Associate the device to given SSID
+     * If the device is already associated with a WiFi, disconnect and forget it,
+     * We don't verify whether the connection is successful or not, leave this to the test
+     */
+    public boolean connectToWifi(String knownSSID) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = knownSSID;
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        return connectToWifiWithConfiguration(config);
+    }
+
+    /**
+     * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
+     * is pure string, we need to convert it to quoted string.
+     * @param config
+     * @return
+     */
+    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
+        String ssid = config.SSID;
+        config.SSID = convertToQuotedString(ssid);
+
+        // If Wifi is not enabled, enable it
+        if (!mWifiManager.isWifiEnabled()) {
+            log("Wifi is not enabled, enable it");
+            mWifiManager.setWifiEnabled(true);
+            // wait for the wifi state change before start scanning.
+            if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2*SHORT_TIMEOUT)) {
+                log("wait for WIFI_STATE_ENABLED failed");
+                return false;
+            }
+        }
+
+        // Save network configuration and connect to network without scanning
+        mWifiManager.connect(config,
+            new WifiManager.ActionListener() {
+                public void onSuccess() {
+                }
+                public void onFailure(int reason) {
+                    log("connect failure " + reason);
+                }
+            });
+        return true;
+    }
+
+    /*
+     * Disconnect from the current AP and remove configured networks.
+     */
+    public boolean disconnectAP() {
+        // remove saved networks
+        if (!mWifiManager.isWifiEnabled()) {
+            log("Enabled wifi before remove configured networks");
+            mWifiManager.setWifiEnabled(true);
+            sleep(SHORT_TIMEOUT);
+        }
+
+        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+        if (wifiConfigList == null) {
+            log("no configuration list is null");
+            return true;
+        }
+        log("size of wifiConfigList: " + wifiConfigList.size());
+        for (WifiConfiguration wifiConfig: wifiConfigList) {
+            log("remove wifi configuration: " + wifiConfig.networkId);
+            int netId = wifiConfig.networkId;
+            mWifiManager.forget(netId, new WifiManager.ActionListener() {
+                    public void onSuccess() {
+                    }
+                    public void onFailure(int reason) {
+                        log("Failed to forget " + reason);
+                    }
+                });
+        }
+        return true;
+    }
+    /**
+     * Disable Wifi
+     * @return true if Wifi is disabled successfully
+     */
+    public boolean disableWifi() {
+        return mWifiManager.setWifiEnabled(false);
+    }
+
+    /**
+     * Remove configured networks and disable wifi
+     */
+    public boolean removeConfiguredNetworksAndDisableWifi() {
+        if (!disconnectAP()) {
+           return false;
+        }
+        sleep(SHORT_TIMEOUT);
+        if (!mWifiManager.setWifiEnabled(false)) {
+            return false;
+        }
+        sleep(SHORT_TIMEOUT);
+        return true;
+    }
+
+    private void sleep(long sleeptime) {
+        try {
+            Thread.sleep(sleeptime);
+        } catch (InterruptedException e) {}
+    }
+
+    protected static String convertToQuotedString(String string) {
+        return "\"" + string + "\"";
+    }
+
+    @Override
+    public void tearDown() throws Exception{
+        //Unregister receiver
+        if (mConnectivityReceiver != null) {
+          mContext.unregisterReceiver(mConnectivityReceiver);
+        }
+        if (mWifiReceiver != null) {
+          mContext.unregisterReceiver(mWifiReceiver);
+        }
+        super.tearDown();
+    }
+
+    private void log(String message) {
+        Log.v(LOG_TAG, message);
+    }
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
index 3a78f26..0e57a00 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
@@ -16,10 +16,8 @@
 
 package com.android.connectivitymanagertest;
 
-import android.os.Bundle;
 import android.test.InstrumentationTestRunner;
 import android.test.InstrumentationTestSuite;
-import android.util.Log;
 import com.android.connectivitymanagertest.unit.WifiClientTest;
 import com.android.connectivitymanagertest.unit.WifiSoftAPTest;
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 3111489..05462b4 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -24,31 +24,24 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.provider.Settings;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
 import com.android.connectivitymanagertest.NetworkState;
 
 public class ConnectivityManagerMobileTest extends
-        ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
-    private static final String LOG_TAG = "ConnectivityManagerMobileTest";
+        ConnectivityManagerTestBase {
+    private static final String TAG = "ConnectivityManagerMobileTest";
 
     private String mTestAccessPoint;
-    private ConnectivityManagerTestActivity cmActivity;
     private WakeLock wl;
     private boolean mWifiOnlyFlag;
 
-    public ConnectivityManagerMobileTest() {
-        super(ConnectivityManagerTestActivity.class);
-    }
-
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        cmActivity = getActivity();
         ConnectivityManagerTestRunner mRunner =
                 (ConnectivityManagerTestRunner)getInstrumentation();
         mTestAccessPoint = mRunner.mTestSsid;
@@ -62,12 +55,12 @@
         if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON) == 1) {
             log("airplane is not disabled, disable it.");
-            cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+            mCM.setAirplaneMode(false);
         }
 
         if (!mWifiOnlyFlag) {
-            if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                    ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
+            if (!waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.CONNECTED, LONG_TIMEOUT)) {
                 // Note: When the test fails in setUp(), tearDown is not called. In that case,
                 // the activity is destroyed which blocks the next test at "getActivity()".
                 // tearDown() is called here to avoid that situation.
@@ -79,29 +72,22 @@
 
     @Override
     public void tearDown() throws Exception {
-        cmActivity.finish();
-        log("tear down ConnectivityManagerTestActivity");
         wl.release();
-        cmActivity.removeConfiguredNetworksAndDisableWifi();
-        // if airplane mode is set, disable it.
-        if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON) == 1) {
-            log("disable airplane mode if it is enabled");
-            cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
-        }
+        removeConfiguredNetworksAndDisableWifi();
+        mCM.setAirplaneMode(false);
         super.tearDown();
     }
 
     // help function to verify 3G connection
     public void verifyCellularConnection() {
-        NetworkInfo extraNetInfo = cmActivity.mCM.getActiveNetworkInfo();
+        NetworkInfo extraNetInfo = mCM.getActiveNetworkInfo();
         assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
                 extraNetInfo.getType());
         assertTrue("not connected to cellular network", extraNetInfo.isConnected());
     }
 
     private void log(String message) {
-        Log.v(LOG_TAG, message);
+        Log.v(TAG, message);
     }
 
     private void sleep(long sleeptime) {
@@ -115,46 +101,46 @@
     @LargeTest
     public void test3GToWifiNotification() {
         if (mWifiOnlyFlag) {
-            Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+            Log.v(TAG, this.getName() + " is excluded for wifi-only test");
             return;
         }
         // Enable Wi-Fi to avoid initial UNKNOWN state
-        cmActivity.enableWifi();
-        sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+        enableWifi();
+        sleep(2 * SHORT_TIMEOUT);
 
         // Wi-Fi is disabled
-        cmActivity.disableWifi();
+        disableWifi();
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.DISCONNECTED,  ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.DISCONNECTED, LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                State.CONNECTED, LONG_TIMEOUT));
         // Wait for 10 seconds for broadcasts to be sent out
         sleep(10 * 1000);
 
         // As Wifi stays in DISCONNETED, Mobile statys in CONNECTED,
         // the connectivity manager will not broadcast any network connectivity event for Wifi
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+        NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                 networkInfo.getState(), NetworkState.DO_NOTHING, State.CONNECTED);
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.DO_NOTHING, State.DISCONNECTED);
         // Eanble Wifi without associating with any AP
-        cmActivity.enableWifi();
-        sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+        enableWifi();
+        sleep(2 * SHORT_TIMEOUT);
 
         // validate state and broadcast
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
             log("the state for WIFI is changed");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue("state validation fail", false);
         }
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
             log("the state for MOBILE is changed");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
             assertTrue("state validation fail", false);
         }
         // Verify that the device is still connected to MOBILE
@@ -168,40 +154,39 @@
         NetworkInfo networkInfo;
         if (!mWifiOnlyFlag) {
             //Prepare for connectivity verification
-            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+            networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                     networkInfo.getState(), NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
         }
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.TO_CONNECTION, State.CONNECTED);
 
         // Enable Wifi and connect to a test access point
         assertTrue("failed to connect to " + mTestAccessPoint,
-                cmActivity.connectToWifi(mTestAccessPoint));
+                connectToWifi(mTestAccessPoint));
 
-        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
         log("wifi state is enabled");
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
         if (!mWifiOnlyFlag) {
-            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, LONG_TIMEOUT));
         }
 
         // validate states
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
             log("Wifi state transition validation failed.");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
         if (!mWifiOnlyFlag) {
-            if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+            if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("Mobile state transition validation failed.");
                 log("reason: " +
-                        cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                        getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
                 assertTrue(false);
             }
         }
@@ -213,61 +198,59 @@
         assertNotNull("SSID is null", mTestAccessPoint);
         // Connect to mTestAccessPoint
         assertTrue("failed to connect to " + mTestAccessPoint,
-                cmActivity.connectToWifi(mTestAccessPoint));
-        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+                connectToWifi(mTestAccessPoint));
+        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
 
-        sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+        sleep(SHORT_TIMEOUT);
         // Disable Wifi
         log("Disable Wifi");
-        if (!cmActivity.disableWifi()) {
+        if (!disableWifi()) {
             log("disable Wifi failed");
             return;
         }
 
         // Wait for the Wifi state to be DISABLED
-        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.DISCONNECTED, LONG_TIMEOUT));
         if (!mWifiOnlyFlag) {
-            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                    State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.CONNECTED, LONG_TIMEOUT));
         }
 
         NetworkInfo networkInfo;
         if (!mWifiOnlyFlag) {
             //Prepare for connectivity state verification
-            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+            networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                                   networkInfo.getState(), NetworkState.DO_NOTHING,
                                                   State.DISCONNECTED);
         }
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.TO_CONNECTION, State.CONNECTED);
 
         // wait for 2 minutes before restart wifi
-        sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL);
+        sleep(WIFI_STOP_START_INTERVAL);
         // Enable Wifi again
         log("Enable Wifi again");
-        cmActivity.enableWifi();
+        enableWifi();
 
         // Wait for Wifi to be connected and mobile to be disconnected
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
         if (!mWifiOnlyFlag) {
-            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, LONG_TIMEOUT));
         }
 
         // validate wifi states
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
             log("Wifi state transition validation failed.");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
     }
@@ -279,48 +262,48 @@
 
         // connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
-                cmActivity.connectToWifi(mTestAccessPoint));
+                connectToWifi(mTestAccessPoint));
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
 
         // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
-        sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+        sleep(SHORT_TIMEOUT);
 
         NetworkInfo networkInfo;
         if (!mWifiOnlyFlag) {
-            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+            networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                                   networkInfo.getState(),
                                                   NetworkState.TO_CONNECTION,
                                                   State.CONNECTED);
         }
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
 
         // clear Wifi
-        cmActivity.removeConfiguredNetworksAndDisableWifi();
+        removeConfiguredNetworksAndDisableWifi();
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.DISCONNECTED, LONG_TIMEOUT));
         if (!mWifiOnlyFlag) {
-            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                    State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.CONNECTED, LONG_TIMEOUT));
         }
 
         // validate states
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
             log("Wifi state transition validation failed.");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
         if (!mWifiOnlyFlag) {
-            if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+            if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("Mobile state transition validation failed.");
                 log("reason: " +
-                        cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                        getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
                 assertTrue(false);
             }
         }
@@ -330,62 +313,62 @@
     @LargeTest
     public void testDataConnectionWith3GToAmTo3G() {
         if (mWifiOnlyFlag) {
-            Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+            Log.v(TAG, this.getName() + " is excluded for wifi-only test");
             return;
         }
         //Prepare for state verification
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+        NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                               networkInfo.getState(),
                                               NetworkState.TO_DISCONNECTION,
                                               State.DISCONNECTED);
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         assertEquals(State.DISCONNECTED, networkInfo.getState());
 
         // Enable airplane mode
         log("Enable airplane mode");
-        cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
-        sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+        mCM.setAirplaneMode(true);
+        sleep(SHORT_TIMEOUT);
 
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         assertEquals(State.DISCONNECTED, networkInfo.getState());
         // wait until mobile is turn off
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                State.DISCONNECTED, LONG_TIMEOUT));
+        if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
             log("Mobile state transition validation failed.");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
             assertTrue(false);
         }
 
         // reset state recorder
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                               networkInfo.getState(),
                                               NetworkState.TO_CONNECTION,
                                               State.CONNECTED);
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.DO_NOTHING, State.DISCONNECTED);
 
         // disable airplane mode
-        cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+        mCM.setAirplaneMode(false);
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                State.CONNECTED, LONG_TIMEOUT));
 
         // Validate the state transition
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
             log("Mobile state transition validation failed.");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
             assertTrue(false);
         }
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
           log("Wifi state transition validation failed.");
           log("reason: " +
-                  cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                  getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
           assertTrue(false);
         }
     }
@@ -394,107 +377,107 @@
     @LargeTest
     public void testDataConnectionOverAMWithWifi() {
         if (mWifiOnlyFlag) {
-            Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+            Log.v(TAG, this.getName() + " is excluded for wifi-only test");
             return;
         }
         assertNotNull("SSID is null", mTestAccessPoint);
         // Eanble airplane mode
         log("Enable airplane mode");
-        cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+        mCM.setAirplaneMode(true);
 
         NetworkInfo networkInfo;
         if (!mWifiOnlyFlag) {
-            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
-            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+            assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, LONG_TIMEOUT));
+            networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                                   networkInfo.getState(),
                                                   NetworkState.DO_NOTHING,
                                                   State.DISCONNECTED);
         }
-        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+        networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                                               NetworkState.TO_CONNECTION, State.CONNECTED);
 
         // Connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
-                cmActivity.connectToWifi(mTestAccessPoint));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+                connectToWifi(mTestAccessPoint));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
 
         // validate state and broadcast
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
             log("state validate for Wifi failed");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue("State validation failed", false);
         }
         if (!mWifiOnlyFlag) {
-            if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+            if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("state validation for Mobile failed");
                 log("reason: " +
-                        cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                        getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
                 assertTrue("state validation failed", false);
             }
         }
-        cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+        mCM.setAirplaneMode(false);
     }
 
     // Test case 7: test connectivity while transit from Wifi->AM->Wifi
     @LargeTest
     public void testDataConnectionWithWifiToAMToWifi () {
         if (mWifiOnlyFlag) {
-            Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+            Log.v(TAG, this.getName() + " is excluded for wifi-only test");
             return;
         }
         // Connect to mTestAccessPoint
         assertNotNull("SSID is null", mTestAccessPoint);
         // Connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
-                cmActivity.connectToWifi(mTestAccessPoint));
+                connectToWifi(mTestAccessPoint));
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
 
         try {
-            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+            Thread.sleep(SHORT_TIMEOUT);
         } catch (Exception e) {
             log("exception: " + e.toString());
         }
 
         // Enable airplane mode without clearing Wifi
-        cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+        mCM.setAirplaneMode(true);
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.DISCONNECTED, LONG_TIMEOUT));
 
         try {
-            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+            Thread.sleep(SHORT_TIMEOUT);
         } catch (Exception e) {
             log("exception: " + e.toString());
         }
 
         // Prepare for state validation
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         assertEquals(State.DISCONNECTED, networkInfo.getState());
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
+        setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
                 networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);
 
         // Disable airplane mode
-        cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+        mCM.setAirplaneMode(false);
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
         if (!mWifiOnlyFlag) {
-            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
-                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, LONG_TIMEOUT));
         }
 
         // validate the state transition
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+        if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
             log("Wifi state transition validation failed.");
             log("reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+                    getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
     }
@@ -505,35 +488,33 @@
         assertNotNull("SSID is null", mTestAccessPoint);
         //Connect to mTestAccessPoint
         assertTrue("failed to connect to " + mTestAccessPoint,
-                cmActivity.connectToWifi(mTestAccessPoint));
-        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+                connectToWifi(mTestAccessPoint));
+        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
         assertNotNull("Not associated with any AP",
-                      cmActivity.mWifiManager.getConnectionInfo().getBSSID());
+                      mWifiManager.getConnectionInfo().getBSSID());
 
         try {
-            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+            Thread.sleep(SHORT_TIMEOUT);
         } catch (Exception e) {
             log("exception: " + e.toString());
         }
 
         // Disconnect from the current AP
         log("disconnect from the AP");
-        if (!cmActivity.disconnectAP()) {
+        if (!disconnectAP()) {
             log("failed to disconnect from " + mTestAccessPoint);
         }
 
         // Verify the connectivity state for Wifi is DISCONNECTED
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.DISCONNECTED, LONG_TIMEOUT));
 
-        if (!cmActivity.disableWifi()) {
+        if (!disableWifi()) {
             log("disable Wifi failed");
             return;
         }
-        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
     }
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index f12e62e..183f2a9 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -16,7 +16,7 @@
 
 package com.android.connectivitymanagertest.functional;
 
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.WifiAssociationTestRunner;
 
 import android.content.Context;
@@ -32,7 +32,6 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.State;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
 /**
@@ -43,30 +42,22 @@
  * -w com.android.connectivitymanagertest/.WifiAssociationTestRunner"
  */
 public class WifiAssociationTest
-    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+        extends ConnectivityManagerTestBase {
     private static final String TAG = "WifiAssociationTest";
-    private ConnectivityManagerTestActivity mAct;
     private String mSsid = null;
     private String mPassword = null;
     private String mSecurityType = null;
     private String mFrequencyBand = null;
     private int mBand;
-    private WifiManager mWifiManager = null;
 
     enum SECURITY_TYPE {
         OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES
-    };
-
-    public WifiAssociationTest() {
-        super(ConnectivityManagerTestActivity.class);
     }
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         WifiAssociationTestRunner mRunner = (WifiAssociationTestRunner)getInstrumentation();
-        mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
-        mAct = getActivity();
         Bundle arguments = mRunner.getArguments();
         mSecurityType = arguments.getString("security-type");
         mSsid = arguments.getString("ssid");
@@ -77,17 +68,15 @@
         assertNotNull("Ssid is empty", mSsid);
         validateFrequencyBand();
         // enable Wifi and verify wpa_supplicant is started
-        assertTrue("enable Wifi failed", mAct.enableWifi());
-        sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
-                "interrupted while waiting for WPA_SUPPLICANT to start");
-        WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+        assertTrue("enable Wifi failed", enableWifi());
+        sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+        WifiInfo mConnection = mWifiManager.getConnectionInfo();
         assertNotNull(mConnection);
-        assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+        assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
     }
 
     @Override
     public void tearDown() throws Exception {
-        log("tearDown()");
         super.tearDown();
     }
 
@@ -107,16 +96,16 @@
     private void connectToWifi(WifiConfiguration config) {
         // step 1: connect to the test access point
         assertTrue("failed to associate with " + config.SSID,
-                mAct.connectToWifiWithConfiguration(config));
+                connectToWifiWithConfiguration(config));
 
         // step 2: verify Wifi state and network state;
         assertTrue("failed to connect with " + config.SSID,
-                mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+                waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
 
         // step 3: verify the current connected network is the given SSID
-        assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
-        assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+        assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
+        assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
     }
 
     private void sleep(long sometime, String errorMsg) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index de0298e..ad73ee1 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -16,35 +16,19 @@
 
 package com.android.connectivitymanagertest.functional;
 
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
 
-import android.R;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
 import android.content.Context;
-import android.content.res.Resources;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.Status;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.ConnectivityManager;
-import android.net.DhcpInfo;
-import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import com.android.internal.util.AsyncChannel;
-
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -56,39 +40,25 @@
  *          -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
  */
 public class WifiConnectionTest
-    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+    extends ConnectivityManagerTestBase {
     private static final String TAG = "WifiConnectionTest";
     private static final boolean DEBUG = false;
     private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
-    private ConnectivityManagerTestActivity mAct;
-    private ConnectivityManagerTestRunner mRunner;
-    private WifiManager mWifiManager = null;
-    private Set<WifiConfiguration> enabledNetworks = null;
-
-    public WifiConnectionTest() {
-        super(ConnectivityManagerTestActivity.class);
-    }
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
-        mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
-
-        mAct = getActivity();
-
-        networks = mAct.loadNetworkConfigurations();
+        networks = loadNetworkConfigurations();
         if (DEBUG) {
             printNetworkConfigurations();
         }
 
         // enable Wifi and verify wpa_supplicant is started
-        assertTrue("enable Wifi failed", mAct.enableWifi());
-        sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
-                "interrupted while waiting for WPA_SUPPLICANT to start");
-        WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+        assertTrue("enable Wifi failed", enableWifi());
+        sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+        WifiInfo mConnection = mWifiManager.getConnectionInfo();
         assertNotNull(mConnection);
-        assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+        assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
     }
 
     private void printNetworkConfigurations() {
@@ -101,8 +71,7 @@
 
     @Override
     public void tearDown() throws Exception {
-        log("tearDown()");
-        mAct.removeConfiguredNetworksAndDisableWifi();
+        removeConfiguredNetworksAndDisableWifi();
         super.tearDown();
     }
 
@@ -114,20 +83,20 @@
     private void connectToWifi(WifiConfiguration config) {
         // step 1: connect to the test access point
         assertTrue("failed to connect to " + config.SSID,
-                mAct.connectToWifiWithConfiguration(config));
+                connectToWifiWithConfiguration(config));
 
         // step 2: verify Wifi state and network state;
-        assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
 
         // step 3: verify the current connected network is the given SSID
-        assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
+        assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
         if (DEBUG) {
             log("config.SSID = " + config.SSID);
-            log("mAct.mWifiManager.getConnectionInfo.getSSID()" +
-                    mAct.mWifiManager.getConnectionInfo().getSSID());
+            log("mWifiManager.getConnectionInfo.getSSID()" +
+                    mWifiManager.getConnectionInfo().getSSID());
         }
-        assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+        assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
     }
 
     private void sleep(long sometime, String errorMsg) {
@@ -149,8 +118,7 @@
             log("-- START Wi-Fi connection test to : " + ssid + " --");
             connectToWifi(networks.get(i));
             // wait for 2 minutes between wifi stop and start
-            sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL,
-                  "interruped while connected to wifi");
+            sleep(WIFI_STOP_START_INTERVAL, "interruped while connected to wifi");
             log("-- END Wi-Fi connection test to " + ssid + " -- ");
         }
     }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 60595fb..790ca38 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -18,19 +18,13 @@
 
 
 import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 
-import android.content.Context;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
 import android.net.wifi.WifiManager;
 import android.os.Environment;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
@@ -42,30 +36,24 @@
  * Stress the wifi driver as access point.
  */
 public class WifiApStress
-    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+    extends ConnectivityManagerTestBase {
     private final static String TAG = "WifiApStress";
     private static String NETWORK_ID = "AndroidAPTest";
     private static String PASSWD = "androidwifi";
     private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
-    private ConnectivityManagerTestActivity mAct;
     private int iterations;
     private BufferedWriter mOutputWriter = null;
     private int mLastIteration = 0;
     private boolean mWifiOnlyFlag;
 
-    public WifiApStress() {
-        super(ConnectivityManagerTestActivity.class);
-    }
-
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mAct = getActivity();
         ConnectivityManagerStressTestRunner mRunner =
             (ConnectivityManagerStressTestRunner)getInstrumentation();
         iterations = mRunner.mSoftapIterations;
         mWifiOnlyFlag = mRunner.mWifiOnlyFlag;
-        mAct.turnScreenOn();
+        turnScreenOn();
     }
 
     @Override
@@ -92,30 +80,28 @@
         config.preSharedKey = PASSWD;
 
         // If Wifi is enabled, disable it
-        if (mAct.mWifiManager.isWifiEnabled()) {
-            mAct.disableWifi();
+        if (mWifiManager.isWifiEnabled()) {
+            disableWifi();
         }
         int i;
         for (i = 0; i < iterations; i++) {
             Log.v(TAG, "iteration: " + i);
             mLastIteration = i;
             // enable Wifi tethering
-            assertTrue(mAct.mWifiManager.setWifiApEnabled(config, true));
+            assertTrue(mWifiManager.setWifiApEnabled(config, true));
             // Wait for wifi ap state to be ENABLED
-            assertTrue(mAct.waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED,
-                    2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            assertTrue(waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED, 2 * LONG_TIMEOUT));
             // Wait for wifi tethering result
-            assertEquals(ConnectivityManagerTestActivity.SUCCESS,
-                    mAct.waitForTetherStateChange(2*ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+            assertEquals(SUCCESS, waitForTetherStateChange(2 * SHORT_TIMEOUT));
             // Allow the wifi tethering to be enabled for 10 seconds
             try {
-                Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+                Thread.sleep(2 * SHORT_TIMEOUT);
             } catch (Exception e) {
                 fail("thread in sleep is interrupted");
             }
-            assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
+            assertTrue("no uplink data connection after Wi-Fi tethering", pingTest(null));
             // Disable soft AP
-            assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
+            assertTrue(mWifiManager.setWifiApEnabled(config, false));
             // Wait for 30 seconds until Wi-Fi tethering is stopped
             try {
                 Thread.sleep(30 * 1000);
@@ -123,7 +109,7 @@
             } catch (Exception e) {
                 fail("thread in sleep is interrupted");
             }
-            assertFalse("Wi-Fi AP disable failed", mAct.mWifiManager.isWifiApEnabled());
+            assertFalse("Wi-Fi AP disable failed", mWifiManager.isWifiApEnabled());
         }
         if (i == iterations) {
             mLastIteration = iterations;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index e3c7cc4..04ce4b7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -29,12 +29,11 @@
 import android.os.PowerManager;
 import android.provider.Settings;
 import android.view.KeyEvent;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
 import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -50,7 +49,7 @@
  *                  -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
  */
 public class WifiStressTest
-    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+        extends ConnectivityManagerTestBase {
     private final static String TAG = "WifiStressTest";
 
     /**
@@ -67,7 +66,6 @@
     private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000;
 
     private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
-    private ConnectivityManagerTestActivity mAct;
     private int mReconnectIterations;
     private int mWifiSleepTime;
     private int mScanIterations;
@@ -77,15 +75,10 @@
     private BufferedWriter mOutputWriter = null;
     private boolean mWifiOnlyFlag;
 
-    public WifiStressTest() {
-        super(ConnectivityManagerTestActivity.class);
-    }
-
     @Override
     public void setUp() throws Exception {
         super.setUp();
 
-        mAct = getActivity();
         mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation();
         mReconnectIterations = mRunner.mReconnectIterations;
         mSsid = mRunner.mReconnectSsid;
@@ -98,15 +91,14 @@
             mPassword, mScanIterations, mWifiSleepTime));
         mOutputWriter = new BufferedWriter(new FileWriter(new File(
                 Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
-        mAct.turnScreenOn();
-        if (!mAct.mWifiManager.isWifiEnabled()) {
+        turnScreenOn();
+        if (!mWifiManager.isWifiEnabled()) {
             log("Enable wi-fi before stress tests.");
-            if (!mAct.enableWifi()) {
+            if (!enableWifi()) {
                 tearDown();
                 fail("enable wifi failed.");
             }
-            sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
-                    "Interruped while waiting for wifi on");
+            sleep(SHORT_TIMEOUT, "Interruped while waiting for wifi on");
         }
     }
 
@@ -166,33 +158,32 @@
             writeOutput(String.format("ssid appear %d out of %d scan iterations",
                     ssidAppearInScanResultsCount, i));
             long startTime = System.currentTimeMillis();
-            mAct.scanResultAvailable = false;
-            assertTrue("start scan failed", mAct.mWifiManager.startScan());
+            scanResultAvailable = false;
+            assertTrue("start scan failed", mWifiManager.startScan());
             while (true) {
                 if ((System.currentTimeMillis() - startTime) >
-                ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
-                    fail("Wifi scanning takes more than " +
-                            ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT + " ms");
+                WIFI_SCAN_TIMEOUT) {
+                    fail("Wifi scanning takes more than " + WIFI_SCAN_TIMEOUT + " ms");
                 }
-                synchronized(mAct) {
+                synchronized(this) {
                     try {
-                        mAct.wait(ConnectivityManagerTestActivity.WAIT_FOR_SCAN_RESULT);
+                        wait(WAIT_FOR_SCAN_RESULT);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
-                    if (mAct.scanResultAvailable) {
+                    if (scanResultAvailable) {
                         long scanTime = (System.currentTimeMillis() - startTime);
                         scanTimeSum += scanTime;
                         break;
                     }
                 }
             }
-            if ((mAct.mWifiManager.getScanResults() == null) ||
-                    (mAct.mWifiManager.getScanResults().size() <= 0)) {
+            if ((mWifiManager.getScanResults() == null) ||
+                    (mWifiManager.getScanResults().size() <= 0)) {
                 fail("Scan results are empty ");
             }
 
-            List<ScanResult> netList = mAct.mWifiManager.getScanResults();
+            List<ScanResult> netList = mWifiManager.getScanResults();
             if (netList != null) {
                 log("size of scan result list: " + netList.size());
                 for (int s = 0; s < netList.size(); s++) {
@@ -244,13 +235,13 @@
         config.proxySettings = ProxySettings.NONE;
 
         assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
-                mAct.connectToWifiWithConfiguration(config));
-        assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
-                ConnectivityManagerTestActivity.SHORT_TIMEOUT));
-        assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+                connectToWifiWithConfiguration(config));
+        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                SHORT_TIMEOUT));
+        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                WIFI_CONNECTION_TIMEOUT));
         // Run ping test to verify the data connection
-        assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
+        assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null));
 
         int i;
         long sum = 0;
@@ -263,33 +254,33 @@
             writeOutput(String.format("iteration %d out of %d",
                     i, mReconnectIterations));
             log("iteration: " + i);
-            mAct.turnScreenOff();
+            turnScreenOff();
             PowerManager pm =
                 (PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
             assertFalse(pm.isScreenOn());
             sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle");
             assertTrue("Wait for Wi-Fi to idle timeout",
-                    mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                    6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+                    waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+                    6 * SHORT_TIMEOUT));
             if (!mWifiOnlyFlag) {
                 // use long timeout as the pppd startup may take several retries.
                 assertTrue("Wait for cellular connection timeout",
-                        mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                        2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                        2 * LONG_TIMEOUT));
             }
             sleep(mWifiSleepTime, "Interrupted while device is in sleep mode");
             // Verify the wi-fi is still off and data connection is on
             assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
-                    mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
+                    mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
 
             if (!mWifiOnlyFlag) {
                 assertEquals("Cellular connection is down", State.CONNECTED,
-                             mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
-                assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+                             mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+                assertTrue("Mobile is connected, but no data connection.", pingTest(null));
             }
 
             // Turn screen on again
-            mAct.turnScreenOn();
+            turnScreenOn();
             // Wait for 2 seconds for the lock screen
             sleep(2 * 1000, "wait 2 seconds for lock screen");
             // Disable lock screen by inject menu key event
@@ -298,16 +289,16 @@
             // Measure the time for Wi-Fi to get connected
             long startTime = System.currentTimeMillis();
             assertTrue("Wait for Wi-Fi enable timeout after wake up",
-                    mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
-                    ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+                    waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                    SHORT_TIMEOUT));
             assertTrue("Wait for Wi-Fi connection timeout after wake up",
-                    mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                    ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+                    waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                    WIFI_CONNECTION_TIMEOUT));
             long connectionTime = System.currentTimeMillis() - startTime;
             sum += connectionTime;
             log("average reconnection time is: " + sum/(i+1));
 
-            assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null));
+            assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
         }
         if (i == mReconnectIterations) {
             writeOutput(String.format("iteration %d out of %d",
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
index e44023b..7a9bc78 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
@@ -20,9 +20,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
 import android.net.NetworkInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiConfiguration;
@@ -33,11 +30,8 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.AndroidTestCase;
 
-import java.util.ArrayList;
 import java.util.List;
 
-import android.util.Log;
-
 /**
  * Test wifi client
  */
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
index 3f43e48..f202862 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
@@ -16,13 +16,7 @@
 
 package com.android.connectivitymanagertest.unit;
 
-import android.content.BroadcastReceiver;
-import android.content.Intent;
 import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -30,8 +24,6 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.AndroidTestCase;
 
-import java.util.ArrayList;
-
 import android.util.Log;
 
 /**
diff --git a/core/tests/benchmarks/src/android/os/StrictModeBenchmark.java b/core/tests/benchmarks/src/android/os/StrictModeBenchmark.java
new file mode 100644
index 0000000..41af3820
--- /dev/null
+++ b/core/tests/benchmarks/src/android/os/StrictModeBenchmark.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.os;
+
+import android.os.StrictMode.ThreadPolicy;
+
+import com.google.caliper.SimpleBenchmark;
+
+public class StrictModeBenchmark extends SimpleBenchmark {
+
+    private ThreadPolicy mOff = new ThreadPolicy.Builder().build();
+    private ThreadPolicy mOn = new ThreadPolicy.Builder().detectAll().build();
+
+    public void timeToggleThreadPolicy(int reps) {
+        for (int i = 0; i < reps; i++) {
+            StrictMode.setThreadPolicy(mOn);
+            StrictMode.setThreadPolicy(mOff);
+        }
+    }
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index f8b26bc..a2cc40c 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -94,7 +94,7 @@
     <uses-permission android:name="android.permission.MOVE_PACKAGE" />
     <uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
 
-    <!--os storage test permissions -->
+    <!-- os storage test permissions -->
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.ASEC_ACCESS" />
     <uses-permission android:name="android.permission.ASEC_CREATE" />
@@ -103,6 +103,10 @@
     <uses-permission android:name="android.permission.ASEC_RENAME" />
     <uses-permission android:name="android.permission.SHUTDOWN" />
 
+    <!-- virtual display test permissions -->
+    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
+    <uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
+
     <!-- accessibility test permissions -->
     <uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
 
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
index d415e4e..7eb32ee 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -37,14 +37,12 @@
         button = (Button) getActivity().findViewById(R.id.animatingButton);
         mAnimator = new AnimatorSet();
         ((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
-
         super.setUp();
     }
 
     @Override
     protected long getTimeout() {
-        return (xAnim.getDuration() + yAnim.getDuration()) +
-                (xAnim.getStartDelay() + yAnim.getStartDelay()) +
+        return (2 * mAnimator.getDuration()) + (2 * mAnimator.getStartDelay()) +
                 ANIM_DELAY + FUTURE_RELEASE_DELAY;
     }
 
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index 8df711b..28cfe3d 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -22,6 +22,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
@@ -42,12 +43,15 @@
     protected static final int ANIM_DELAY = 100;
     protected static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
     protected static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
+    protected static final int ANIM_PAUSE_DURATION = ANIM_DELAY;
+    protected static final int ANIM_PAUSE_DELAY = ANIM_DELAY / 2;
     protected static final int FUTURE_RELEASE_DELAY = 50;
+    protected static final int ANIM_FULL_DURATION_SLOP = 100;
 
     private boolean mStarted;  // tracks whether we've received the onAnimationStart() callback
     protected boolean mRunning;  // tracks whether we've started the animator
-    private boolean mCanceled; // trackes whether we've canceled the animator
-    protected Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
+    private boolean mCanceled; // tracks whether we've canceled the animator
+    protected Animator.AnimatorListener mFutureListener; // mechanism for delaying end of the test
     protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
     private Animator.AnimatorListener mListener; // Listener that handles/tests the events
 
@@ -104,6 +108,48 @@
     };
 
     /**
+     * Pauses the given animator. Used to delay pausing until some later time (after the
+     * animator has started playing).
+     */
+    static class Pauser implements Runnable {
+        Animator mAnim;
+        FutureWaiter mFuture;
+        public Pauser(Animator anim, FutureWaiter future) {
+            mAnim = anim;
+            mFuture = future;
+        }
+        @Override
+        public void run() {
+            try {
+                mAnim.pause();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
+            }
+        }
+    };
+
+    /**
+     * Resumes the given animator. Used to delay resuming until some later time (after the
+     * animator has paused for some duration).
+     */
+    static class Resumer implements Runnable {
+        Animator mAnim;
+        FutureWaiter mFuture;
+        public Resumer(Animator anim, FutureWaiter future) {
+            mAnim = anim;
+            mFuture = future;
+        }
+        @Override
+        public void run() {
+            try {
+                mAnim.resume();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
+            }
+        }
+    };
+
+    /**
      * Releases the given Future object when the listener's end() event is called. Specifically,
      * it releases it after some further delay, to give the test time to do other things right
      * after an animation ends.
@@ -555,4 +601,114 @@
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
      }
 
+    /**
+     * Verify that pausing and resuming an animator ends within
+     * the appropriate timeout duration.
+     */
+    @MediumTest
+    public void testPauseResume() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                    handler.postDelayed(new Resumer(mAnimator, mFuture),
+                            ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(getTimeout() + ANIM_PAUSE_DURATION, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verify that pausing and resuming a startDelayed animator ends within
+     * the appropriate timeout duration.
+     */
+    @MediumTest
+    public void testPauseResumeDelayed() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                    handler.postDelayed(new Resumer(mAnimator, mFuture),
+                            ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
+                TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verify that pausing an animator without resuming it causes a timeout.
+     */
+    @MediumTest
+    public void testPauseTimeout() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        try {
+            mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
+                    TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            // Expected behavior, swallow the exception
+        }
+    }
+
+    /**
+     * Verify that pausing a startDelayed animator without resuming it causes a timeout.
+     */
+    @MediumTest
+    public void testPauseTimeoutDelayed() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        try {
+            mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
+                    TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            // Expected behavior, swallow the exception
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/database/MatrixCursorTest.java b/core/tests/coretests/src/android/database/MatrixCursorTest.java
index cdab638..aa805dc 100644
--- a/core/tests/coretests/src/android/database/MatrixCursorTest.java
+++ b/core/tests/coretests/src/android/database/MatrixCursorTest.java
@@ -128,6 +128,56 @@
         } catch (IllegalArgumentException e) { /* expected */ }
     }
 
+    public void testRowBuilderOffer() {
+        MatrixCursor cursor = newMatrixCursor();
+
+        cursor.newRow()
+                .add("float", 4.2f)
+                .add("string", "foobar")
+                .add("blob", new byte[] {(byte) 0xaa, (byte) 0x55})
+                .add("lolwat", "kittens");
+
+        cursor.newRow();
+
+        cursor.newRow()
+                .add("string", "zero")
+                .add("string", "one")
+                .add("string", "two")
+                .add("lolwat", "kittens");
+
+        assertTrue(cursor.moveToFirst());
+        assertEquals("foobar", cursor.getString(0));
+        assertEquals(null, cursor.getString(1));
+        assertEquals(0, cursor.getShort(1));
+        assertEquals(0, cursor.getInt(2));
+        assertEquals(0, cursor.getLong(3));
+        assertEquals(4.2f, cursor.getFloat(4));
+        assertEquals(0.0d, cursor.getDouble(5));
+        MoreAsserts.assertEquals(new byte[] {(byte) 0xaa, (byte) 0x55}, cursor.getBlob(6));
+
+        assertTrue(cursor.moveToNext());
+        assertEquals(null, cursor.getString(0));
+        assertEquals(0, cursor.getShort(1));
+        assertEquals(0, cursor.getInt(2));
+        assertEquals(0, cursor.getLong(3));
+        assertEquals(0.0f, cursor.getFloat(4));
+        assertEquals(0.0d, cursor.getDouble(5));
+        assertEquals(null, cursor.getBlob(6));
+
+        assertTrue(cursor.moveToNext());
+        assertEquals("two", cursor.getString(0));
+        assertEquals(0, cursor.getShort(1));
+        assertEquals(0, cursor.getInt(2));
+        assertEquals(0, cursor.getLong(3));
+        assertEquals(0.0f, cursor.getFloat(4));
+        assertEquals(0.0d, cursor.getDouble(5));
+        assertEquals(null, cursor.getBlob(6));
+
+        assertTrue(cursor.isLast());
+        assertFalse(cursor.moveToNext());
+        assertTrue(cursor.isAfterLast());
+    }
+
     static class NonIterableArrayList<T> extends ArrayList<T> {
 
         NonIterableArrayList() {}
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
new file mode 100644
index 0000000..a2e9ae8
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -0,0 +1,500 @@
+/*
+ * 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 android.hardware.display;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.drawable.ColorDrawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Tests that applications can create virtual displays and present content on them.
+ *
+ * Contains additional tests that cannot be included in CTS because they require
+ * system permissions.  See also the CTS version of VirtualDisplayTest.
+ */
+public class VirtualDisplayTest extends AndroidTestCase {
+    private static final String TAG = "VirtualDisplayTest";
+
+    private static final String NAME = TAG;
+    private static final int WIDTH = 720;
+    private static final int HEIGHT = 480;
+    private static final int DENSITY = DisplayMetrics.DENSITY_MEDIUM;
+    private static final int TIMEOUT = 10000;
+
+    // Colors that we use as a signal to determine whether some desired content was
+    // drawn.  The colors themselves doesn't matter but we choose them to have with distinct
+    // values for each color channel so as to detect possible RGBA vs. BGRA buffer format issues.
+    // We should only observe RGBA buffers but some graphics drivers might incorrectly
+    // deliver BGRA buffers to virtual displays instead.
+    private static final int BLUEISH = 0xff1122ee;
+    private static final int GREENISH = 0xff33dd44;
+
+    private DisplayManager mDisplayManager;
+    private Handler mHandler;
+    private final Lock mImageReaderLock = new ReentrantLock(true /*fair*/);
+    private ImageReader mImageReader;
+    private Surface mSurface;
+    private ImageListener mImageListener;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDisplayManager = (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
+        mHandler = new Handler(Looper.getMainLooper());
+        mImageListener = new ImageListener();
+
+        mImageReaderLock.lock();
+        try {
+            mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
+            mImageReader.setOnImageAvailableListener(mImageListener, mHandler);
+            mSurface = mImageReader.getSurface();
+        } finally {
+            mImageReaderLock.unlock();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        mImageReaderLock.lock();
+        try {
+            mImageReader.close();
+            mImageReader = null;
+            mSurface = null;
+        } finally {
+            mImageReaderLock.unlock();
+        }
+    }
+
+    /**
+     * Ensures that an application can create a private virtual display and show
+     * its own windows on it.
+     */
+    public void testPrivateVirtualDisplay() throws Exception {
+        VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+                WIDTH, HEIGHT, DENSITY, mSurface, 0);
+        assertNotNull("virtual display must not be null", virtualDisplay);
+
+        Display display = virtualDisplay.getDisplay();
+        try {
+            assertDisplayRegistered(display, Display.FLAG_PRIVATE);
+
+            // Show a private presentation on the display.
+            assertDisplayCanShowPresentation("private presentation window",
+                    display, BLUEISH,
+                    WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, 0);
+        } finally {
+            virtualDisplay.release();
+        }
+        assertDisplayUnregistered(display);
+    }
+
+    /**
+     * Ensures that an application can create a private presentation virtual display and show
+     * its own windows on it.
+     */
+    public void testPrivatePresentationVirtualDisplay() throws Exception {
+        VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+                WIDTH, HEIGHT, DENSITY, mSurface,
+                DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION);
+        assertNotNull("virtual display must not be null", virtualDisplay);
+
+        Display display = virtualDisplay.getDisplay();
+        try {
+            assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION);
+
+            // Show a private presentation on the display.
+            assertDisplayCanShowPresentation("private presentation window",
+                    display, BLUEISH,
+                    WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, 0);
+        } finally {
+            virtualDisplay.release();
+        }
+        assertDisplayUnregistered(display);
+    }
+
+    /**
+     * Ensures that an application can create a public virtual display and show
+     * its own windows on it.  This test requires the CAPTURE_VIDEO_OUTPUT permission.
+     *
+     * Because this test does not have an activity token, we use the TOAST window
+     * type to create the window.  Another choice might be SYSTEM_ALERT_WINDOW but
+     * that requires a permission.
+     */
+    public void testPublicPresentationVirtualDisplay() throws Exception {
+        VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+                WIDTH, HEIGHT, DENSITY, mSurface,
+                DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
+                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION);
+        assertNotNull("virtual display must not be null", virtualDisplay);
+
+        Display display = virtualDisplay.getDisplay();
+        try {
+            assertDisplayRegistered(display, Display.FLAG_PRESENTATION);
+
+            // Mirroring case.
+            // Show a window on the default display.  It should be mirrored to the
+            // virtual display automatically.
+            Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+            assertDisplayCanShowPresentation("mirrored window",
+                    defaultDisplay, GREENISH,
+                    WindowManager.LayoutParams.TYPE_TOAST, 0);
+
+            // Mirroring case with secure window (but display is not secure).
+            // Show a window on the default display.  It should be replaced with black on
+            // the virtual display.
+            assertDisplayCanShowPresentation("mirrored secure window on non-secure display",
+                    defaultDisplay, Color.BLACK,
+                    WindowManager.LayoutParams.TYPE_TOAST,
+                    WindowManager.LayoutParams.FLAG_SECURE);
+
+            // Presentation case.
+            // Show a normal presentation on the display.
+            assertDisplayCanShowPresentation("presentation window",
+                    display, BLUEISH,
+                    WindowManager.LayoutParams.TYPE_TOAST, 0);
+
+            // Presentation case with secure window (but display is not secure).
+            // Show a normal presentation on the display.  It should be replaced with black.
+            assertDisplayCanShowPresentation("secure presentation window on non-secure display",
+                    display, Color.BLACK,
+                    WindowManager.LayoutParams.TYPE_TOAST,
+                    WindowManager.LayoutParams.FLAG_SECURE);
+        } finally {
+            virtualDisplay.release();
+        }
+        assertDisplayUnregistered(display);
+    }
+
+    /**
+     * Ensures that an application can create a secure public virtual display and show
+     * its own windows on it.  This test requires the CAPTURE_SECURE_VIDEO_OUTPUT permission.
+     *
+     * Because this test does not have an activity token, we use the TOAST window
+     * type to create the window.  Another choice might be SYSTEM_ALERT_WINDOW but
+     * that requires a permission.
+     */
+    public void testSecurePublicPresentationVirtualDisplay() throws Exception {
+        VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+                WIDTH, HEIGHT, DENSITY, mSurface,
+                DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE
+                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
+                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION);
+        assertNotNull("virtual display must not be null", virtualDisplay);
+
+        Display display = virtualDisplay.getDisplay();
+        try {
+            assertDisplayRegistered(display, Display.FLAG_PRESENTATION | Display.FLAG_SECURE);
+
+            // Mirroring case with secure window (and display is secure).
+            // Show a window on the default display.  It should be mirrored to the
+            // virtual display automatically.
+            Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+            assertDisplayCanShowPresentation("mirrored secure window on secure display",
+                    defaultDisplay, GREENISH,
+                    WindowManager.LayoutParams.TYPE_TOAST,
+                    WindowManager.LayoutParams.FLAG_SECURE);
+
+            // Presentation case with secure window (and display is secure).
+            // Show a normal presentation on the display.
+            assertDisplayCanShowPresentation("secure presentation window on secure display",
+                    display, BLUEISH,
+                    WindowManager.LayoutParams.TYPE_TOAST,
+                    WindowManager.LayoutParams.FLAG_SECURE);
+        } finally {
+            virtualDisplay.release();
+        }
+        assertDisplayUnregistered(display);
+    }
+
+    private void assertDisplayRegistered(Display display, int flags) {
+        assertNotNull("display object must not be null", display);
+        assertTrue("display must be valid", display.isValid());
+        assertTrue("display id must be unique",
+                display.getDisplayId() != Display.DEFAULT_DISPLAY);
+        assertEquals("display must have correct flags", flags, display.getFlags());
+        assertEquals("display name must match supplied name", NAME, display.getName());
+        Point size = new Point();
+        display.getSize(size);
+        assertEquals("display width must match supplied width", WIDTH, size.x);
+        assertEquals("display height must match supplied height", HEIGHT, size.y);
+        assertEquals("display rotation must be 0",
+                Surface.ROTATION_0, display.getRotation());
+        assertNotNull("display must be registered",
+                findDisplay(mDisplayManager.getDisplays(), NAME));
+
+        if ((flags & Display.FLAG_PRESENTATION) != 0) {
+            assertNotNull("display must be registered as a presentation display",
+                    findDisplay(mDisplayManager.getDisplays(
+                            DisplayManager.DISPLAY_CATEGORY_PRESENTATION), NAME));
+        } else {
+            assertNull("display must not be registered as a presentation display",
+                    findDisplay(mDisplayManager.getDisplays(
+                            DisplayManager.DISPLAY_CATEGORY_PRESENTATION), NAME));
+        }
+    }
+
+    private void assertDisplayUnregistered(Display display) {
+        assertNull("display must no longer be registered after being removed",
+                findDisplay(mDisplayManager.getDisplays(), NAME));
+        assertFalse("display must no longer be valid", display.isValid());
+    }
+
+    private void assertDisplayCanShowPresentation(String message, final Display display,
+            final int color, final int windowType, final int windowFlags) {
+        // At this point, we should not have seen any blue.
+        assertTrue(message + ": display should not show content before window is shown",
+                mImageListener.getColor() != color);
+
+        final TestPresentation[] presentation = new TestPresentation[1];
+        try {
+            // Show the presentation.
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    presentation[0] = new TestPresentation(getContext(), display,
+                            color, windowType, windowFlags);
+                    presentation[0].show();
+                }
+            });
+
+            // Wait for the blue to be seen.
+            assertTrue(message + ": display should show content after window is shown",
+                    mImageListener.waitForColor(color, TIMEOUT));
+        } finally {
+            if (presentation[0] != null) {
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        presentation[0].dismiss();
+                    }
+                });
+            }
+        }
+    }
+
+    private void runOnUiThread(Runnable runnable) {
+        Runnable waiter = new Runnable() {
+            @Override
+            public void run() {
+                synchronized (this) {
+                    notifyAll();
+                }
+            }
+        };
+        synchronized (waiter) {
+            mHandler.post(runnable);
+            mHandler.post(waiter);
+            try {
+                waiter.wait(TIMEOUT);
+            } catch (InterruptedException ex) {
+            }
+        }
+    }
+
+    private Display findDisplay(Display[] displays, String name) {
+        for (int i = 0; i < displays.length; i++) {
+            if (displays[i].getName().equals(name)) {
+                return displays[i];
+            }
+        }
+        return null;
+    }
+
+    private final class TestPresentation extends Presentation {
+        private final int mColor;
+        private final int mWindowType;
+        private final int mWindowFlags;
+
+        public TestPresentation(Context context, Display display,
+                int color, int windowType, int windowFlags) {
+            super(context, display);
+            mColor = color;
+            mWindowType = windowType;
+            mWindowFlags = windowFlags;
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            setTitle(TAG);
+            getWindow().setType(mWindowType);
+            getWindow().addFlags(mWindowFlags);
+
+            // Create a solid color image to use as the content of the presentation.
+            ImageView view = new ImageView(getContext());
+            view.setImageDrawable(new ColorDrawable(mColor));
+            view.setLayoutParams(new LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+            setContentView(view);
+        }
+    }
+
+    /**
+     * Watches for an image with a large amount of some particular solid color to be shown.
+     */
+    private final class ImageListener
+            implements ImageReader.OnImageAvailableListener {
+        private int mColor = -1;
+
+        public int getColor() {
+            synchronized (this) {
+                return mColor;
+            }
+        }
+
+        public boolean waitForColor(int color, long timeoutMillis) {
+            long timeoutTime = SystemClock.uptimeMillis() + timeoutMillis;
+            synchronized (this) {
+                while (mColor != color) {
+                    long now = SystemClock.uptimeMillis();
+                    if (now >= timeoutTime) {
+                        return false;
+                    }
+                    try {
+                        wait(timeoutTime - now);
+                    } catch (InterruptedException ex) {
+                    }
+                }
+                return true;
+            }
+        }
+
+        @Override
+        public void onImageAvailable(ImageReader reader) {
+            mImageReaderLock.lock();
+            try {
+                if (reader != mImageReader) {
+                    return;
+                }
+
+                Log.d(TAG, "New image available from virtual display.");
+
+                // Get the latest buffer.
+                Image image = reader.acquireLatestImage();
+                if (image != null) {
+                    try {
+                        // Scan for colors.
+                        int color = scanImage(image);
+                        synchronized (this) {
+                            if (mColor != color) {
+                                mColor = color;
+                                notifyAll();
+                            }
+                        }
+                    } finally {
+                        image.close();
+                    }
+                }
+            } finally {
+                mImageReaderLock.unlock();
+            }
+        }
+
+        private int scanImage(Image image) {
+            final Image.Plane plane = image.getPlanes()[0];
+            final ByteBuffer buffer = plane.getBuffer();
+            final int width = image.getWidth();
+            final int height = image.getHeight();
+            final int pixelStride = plane.getPixelStride();
+            final int rowStride = plane.getRowStride();
+            final int rowPadding = rowStride - pixelStride * width;
+
+            Log.d(TAG, "- Scanning image: width=" + width + ", height=" + height
+                    + ", pixelStride=" + pixelStride + ", rowStride=" + rowStride);
+
+            int offset = 0;
+            int blackPixels = 0;
+            int bluePixels = 0;
+            int greenPixels = 0;
+            int otherPixels = 0;
+            for (int y = 0; y < height; y++) {
+                for (int x = 0; x < width; x++) {
+                    int pixel = 0;
+                    pixel |= (buffer.get(offset) & 0xff) << 16;     // R
+                    pixel |= (buffer.get(offset + 1) & 0xff) << 8;  // G
+                    pixel |= (buffer.get(offset + 2) & 0xff);       // B
+                    pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
+                    if (pixel == Color.BLACK || pixel == 0) {
+                        blackPixels += 1;
+                    } else if (pixel == BLUEISH) {
+                        bluePixels += 1;
+                    } else if (pixel == GREENISH) {
+                        greenPixels += 1;
+                    } else {
+                        otherPixels += 1;
+                        if (otherPixels < 10) {
+                            Log.d(TAG, "- Found unexpected color: " + Integer.toHexString(pixel));
+                        }
+                    }
+                    offset += pixelStride;
+                }
+                offset += rowPadding;
+            }
+
+            // Return a color if it represents more than one quarter of the pixels.
+            // We use this threshold in case the display is being letterboxed when
+            // mirroring so there might be large black bars on the sides, which is normal.
+            Log.d(TAG, "- Pixels: " + blackPixels + " black, "
+                    + bluePixels + " blue, "
+                    + greenPixels + " green, "
+                    + otherPixels + " other");
+            final int threshold = width * height / 4;
+            if (bluePixels > threshold) {
+                Log.d(TAG, "- Reporting blue.");
+                return BLUEISH;
+            }
+            if (greenPixels > threshold) {
+                Log.d(TAG, "- Reporting green.");
+                return GREENISH;
+            }
+            if (blackPixels > threshold) {
+                Log.d(TAG, "- Reporting black.");
+                return Color.BLACK;
+            }
+            Log.d(TAG, "- Reporting other.");
+            return -1;
+        }
+    }
+}
+
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index d6a7ee2..e63f6b0 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -25,13 +25,18 @@
 import java.util.ArrayList;
 
 public class LinkPropertiesTest extends TestCase {
-    private static String ADDRV4 = "75.208.6.1";
-    private static String ADDRV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
-    private static String DNS1 = "75.208.7.1";
-    private static String DNS2 = "69.78.7.1";
-    private static String GATEWAY1 = "75.208.8.1";
-    private static String GATEWAY2 = "69.78.8.1";
+    private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
+    private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
+            "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+    private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
+    private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
+    private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
+    private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
     private static String NAME = "qmi0";
+    private static int MTU = 1500;
+
+    private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
+    private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
 
     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
         // Check implementation of equals(), element by element.
@@ -53,6 +58,9 @@
         assertTrue(source.isIdenticalStackedLinks(target));
         assertTrue(target.isIdenticalStackedLinks(source));
 
+        assertTrue(source.isIdenticalMtu(target));
+        assertTrue(target.isIdenticalMtu(source));
+
         // Check result of equals().
         assertTrue(source.equals(target));
         assertTrue(target.equals(source));
@@ -76,43 +84,40 @@
             LinkProperties source = new LinkProperties();
             source.setInterfaceName(NAME);
             // set 2 link addresses
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV6);
             // set 2 dnses
-            source.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+            source.addDns(DNS1);
+            source.addDns(DNS2);
             // set 2 gateways
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            source.addRoute(new RouteInfo(GATEWAY1));
+            source.addRoute(new RouteInfo(GATEWAY2));
+            source.setMtu(MTU);
 
             LinkProperties target = new LinkProperties();
 
             // All fields are same
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.setMtu(MTU);
 
             assertLinkPropertiesEqual(source, target);
 
             target.clear();
             // change Interface Name
             target.setInterfaceName("qmi1");
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.setMtu(MTU);
             assertFalse(source.equals(target));
 
             target.clear();
@@ -120,38 +125,48 @@
             // change link addresses
             target.addLinkAddress(new LinkAddress(
                     NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.setMtu(MTU);
             assertFalse(source.equals(target));
 
             target.clear();
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
             // change dnses
             target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.setMtu(MTU);
             assertFalse(source.equals(target));
 
             target.clear();
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
             // change gateway
             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.setMtu(MTU);
+            assertFalse(source.equals(target));
+
+            target.clear();
+            target.setInterfaceName(NAME);
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
+            // change mtu
+            target.setMtu(1440);
             assertFalse(source.equals(target));
 
         } catch (Exception e) {
@@ -166,28 +181,26 @@
             LinkProperties source = new LinkProperties();
             source.setInterfaceName(NAME);
             // set 2 link addresses
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV6);
             // set 2 dnses
-            source.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+            source.addDns(DNS1);
+            source.addDns(DNS2);
             // set 2 gateways
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            source.addRoute(new RouteInfo(GATEWAY1));
+            source.addRoute(new RouteInfo(GATEWAY2));
+            source.setMtu(MTU);
 
             LinkProperties target = new LinkProperties();
             // Exchange order
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            target.addLinkAddress(LINKADDRV6);
+            target.addLinkAddress(LINKADDRV4);
+            target.addDns(DNS2);
+            target.addDns(DNS1);
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.setMtu(MTU);
 
             assertLinkPropertiesEqual(source, target);
         } catch (Exception e) {
@@ -200,21 +213,15 @@
         try {
             LinkProperties source = new LinkProperties();
             // set 3 link addresses, eg, [A, A, B]
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV6);
 
             LinkProperties target = new LinkProperties();
             // set 3 link addresses, eg, [A, B, B]
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addLinkAddress(LINKADDRV6);
 
             assertLinkPropertiesEqual(source, target);
         } catch (Exception e) {
@@ -232,7 +239,7 @@
     public void testRouteInterfaces() {
         LinkAddress prefix = new LinkAddress(
             NetworkUtils.numericToInetAddress("2001:db8::"), 32);
-        InetAddress address = NetworkUtils.numericToInetAddress(ADDRV6);
+        InetAddress address = ADDRV6;
 
         // Add a route with no interface to a LinkProperties with no interface. No errors.
         LinkProperties lp = new LinkProperties();
@@ -265,7 +272,7 @@
         assertAllRoutesHaveInterface("wlan0", lp);
 
         // Routes with null interfaces are converted to wlan0.
-        r = RouteInfo.makeHostRoute(NetworkUtils.numericToInetAddress(ADDRV6), null);
+        r = RouteInfo.makeHostRoute(ADDRV6, null);
         lp.addRoute(r);
         assertEquals(3, lp.getRoutes().size());
         assertAllRoutesHaveInterface("wlan0", lp);
@@ -273,28 +280,45 @@
         // Check comparisons work.
         LinkProperties lp2 = new LinkProperties(lp);
         assertAllRoutesHaveInterface("wlan0", lp);
-        assertEquals(0, lp.compareRoutes(lp2).added.size());
-        assertEquals(0, lp.compareRoutes(lp2).removed.size());
+        assertEquals(0, lp.compareAllRoutes(lp2).added.size());
+        assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
 
         lp2.setInterfaceName("p2p0");
         assertAllRoutesHaveInterface("p2p0", lp2);
-        assertEquals(3, lp.compareRoutes(lp2).added.size());
-        assertEquals(3, lp.compareRoutes(lp2).removed.size());
+        assertEquals(3, lp.compareAllRoutes(lp2).added.size());
+        assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
     }
 
     @SmallTest
     public void testStackedInterfaces() {
         LinkProperties rmnet0 = new LinkProperties();
         rmnet0.setInterfaceName("rmnet0");
+        rmnet0.addLinkAddress(LINKADDRV6);
 
         LinkProperties clat4 = new LinkProperties();
         clat4.setInterfaceName("clat4");
+        clat4.addLinkAddress(LINKADDRV4);
 
         assertEquals(0, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(1, rmnet0.getAllAddresses().size());
+        assertEquals(1, rmnet0.getAllLinkAddresses().size());
+
         rmnet0.addStackedLink(clat4);
         assertEquals(1, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(2, rmnet0.getAllAddresses().size());
+        assertEquals(2, rmnet0.getAllLinkAddresses().size());
+
         rmnet0.addStackedLink(clat4);
         assertEquals(1, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(2, rmnet0.getAllAddresses().size());
+        assertEquals(2, rmnet0.getAllLinkAddresses().size());
+
         assertEquals(0, clat4.getStackedLinks().size());
 
         // Modify an item in the returned collection to see what happens.
@@ -306,5 +330,76 @@
         for (LinkProperties link : rmnet0.getStackedLinks()) {
             assertFalse("newname".equals(link.getInterfaceName()));
         }
+
+        assertTrue(rmnet0.removeStackedLink(clat4));
+        assertEquals(0, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(1, rmnet0.getAllAddresses().size());
+        assertEquals(1, rmnet0.getAllLinkAddresses().size());
+
+        assertFalse(rmnet0.removeStackedLink(clat4));
+    }
+
+    @SmallTest
+    public void testAddressMethods() {
+        LinkProperties lp = new LinkProperties();
+
+        // No addresses.
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasIPv6Address());
+
+        // Addresses on stacked links don't count.
+        LinkProperties stacked = new LinkProperties();
+        stacked.setInterfaceName("stacked");
+        lp.addStackedLink(stacked);
+        stacked.addLinkAddress(LINKADDRV4);
+        stacked.addLinkAddress(LINKADDRV6);
+        assertTrue(stacked.hasIPv4Address());
+        assertTrue(stacked.hasIPv6Address());
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasIPv6Address());
+        lp.removeStackedLink(stacked);
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasIPv6Address());
+
+        // Addresses on the base link.
+        // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
+        // iff something changes.
+        assertTrue(lp.addLinkAddress(LINKADDRV6));
+        assertFalse(lp.hasIPv4Address());
+        assertTrue(lp.hasIPv6Address());
+
+        assertTrue(lp.removeLinkAddress(LINKADDRV6));
+        assertTrue(lp.addLinkAddress(LINKADDRV4));
+        assertTrue(lp.hasIPv4Address());
+        assertFalse(lp.hasIPv6Address());
+
+        assertTrue(lp.addLinkAddress(LINKADDRV6));
+        assertTrue(lp.hasIPv4Address());
+        assertTrue(lp.hasIPv6Address());
+
+        // Adding an address twice has no effect.
+        // Removing an address that's not present has no effect.
+        assertFalse(lp.addLinkAddress(LINKADDRV4));
+        assertTrue(lp.hasIPv4Address());
+        assertTrue(lp.removeLinkAddress(LINKADDRV4));
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.removeLinkAddress(LINKADDRV4));
+    }
+
+    @SmallTest
+    public void testSetLinkAddresses() {
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(LINKADDRV4);
+        lp.addLinkAddress(LINKADDRV6);
+
+        LinkProperties lp2 = new LinkProperties();
+        lp2.addLinkAddress(LINKADDRV6);
+
+        assertFalse(lp.equals(lp2));
+
+        lp2.setLinkAddresses(lp.getLinkAddresses());
+        assertTrue(lp.equals(lp));
     }
 }
diff --git a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
deleted file mode 100644
index 417a85f..0000000
--- a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
+++ /dev/null
@@ -1,1809 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.webkit;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-/**
- * This is a test for the behavior of the {@link AccessibilityInjector}
- * which is used by {@link WebView} to provide basic accessibility support
- * in case JavaScript is disabled.
- * </p>
- * Note: This test works against the generated {@link AccessibilityEvent}s
- *       to so it also checks if the test for announcing navigation axis and
- *       status messages as appropriate.
- */
-public class AccessibilityInjectorTest
-    extends ActivityInstrumentationTestCase2<AccessibilityInjectorTestActivity> {
-
-    /** The timeout to wait for the expected selection. */
-    private static final long TIMEOUT_WAIT_FOR_SELECTION_STRING = 1000;
-
-    /** The timeout to wait for accessibility and the mock service to be enabled. */
-    private static final long TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE = 1000;
-
-    /** The count of tests to detect when to shut down the service. */
-    private static final int TEST_CASE_COUNT = 19;
-
-    /** The meta state for pressed left ALT. */
-    private static final int META_STATE_ALT_LEFT_ON = KeyEvent.META_ALT_ON
-            | KeyEvent.META_ALT_LEFT_ON;
-
-    /** Prefix for the CSS style span appended by WebKit. */
-    private static final String APPLE_SPAN_PREFIX = "<span class=\"Apple-style-span\"";
-
-    /** Suffix for the CSS style span appended by WebKit. */
-    private static final String APPLE_SPAN_SUFFIX = "</span>";
-
-    /** The value for not specified selection string since null is a valid value. */
-    private static final String SELECTION_STRING_UNKNOWN = "Unknown";
-
-    /** Lock for locking the test. */
-    private static final Object sTestLock = new Object();
-
-    /** Key bindings used for testing. */
-    private static final String TEST_KEY_DINDINGS =
-        "0x13=0x01000100;" +
-        "0x14=0x01010100;" +
-        "0x15=0x04000000;" +
-        "0x16=0x04000000;" +
-        "0x200000013=0x03020701:0x03010201:0x03000101:0x03030001:0x03040001:0x03050001:0x03060001;" +
-        "0x200000014=0x03010001:0x03020101:0x03070201:0x03030701:0x03040701:0x03050701:0x03060701;" +
-        "0x200000015=0x03040301:0x03050401:0x03060501:0x03000601:0x03010601:0x03020601:0x03070601;" +
-        "0x200000016=0x03050601:0x03040501:0x03030401:0x03020301:0x03070301:0x03010301:0x03000301;";
-
-    /** Handle to the test for use by the mock service. */
-    private static AccessibilityInjectorTest sInstance;
-
-    /** Flag indicating if the accessibility service is ready to receive events. */
-    private static boolean sIsAccessibilityServiceReady;
-
-    /** The count of executed tests to detect when to toggle accessibility and the service. */
-    private static int sExecutedTestCount;
-
-    /** Worker thread with a handler to perform non test thread processing. */
-    private Worker mWorker;
-
-    /** Handle to the {@link WebView} to load data in. */
-    private WebView mWebView;
-
-    /** Used for caching the default bindings so they can be restored. */
-    private static String sDefaultKeyBindings;
-
-    /** The received selection string for assertion checking. */
-    private static String sReceivedSelectionString = SELECTION_STRING_UNKNOWN;
-
-    public AccessibilityInjectorTest() {
-        super(AccessibilityInjectorTestActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mWorker = new Worker();
-        sInstance = this;
-        if (sExecutedTestCount == 0) {
-            // until JUnit4 comes to play with @BeforeTest
-            disableAccessibilityAndMockAccessibilityService();
-            enableAccessibilityAndMockAccessibilityService();
-            injectTestWebContentKeyBindings();
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        if (mWorker != null) {
-            mWorker.stop();
-        }
-        if (sExecutedTestCount == TEST_CASE_COUNT) {
-            // until JUnit4 comes to play with @AfterTest
-            disableAccessibilityAndMockAccessibilityService();
-            restoreDefaultWebContentKeyBindings();
-        }
-        super.tearDown();
-    }
-
-    /**
-     * Tests navigation by character.
-     */
-    @LargeTest
-    public void testNavigationByCharacter() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<html>" +
-               "<head>" +
-               "</head>" +
-               "<body>" +
-                   "<p>" +
-                      "a<b>b</b>c" +
-                   "</p>" +
-                   "<p>" +
-                     "d" +
-                   "<p/>" +
-                   "e" +
-               "</body>" +
-             "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("1"); // expect the word navigation axis
-
-        // change navigation axis to character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("0"); // expect the character navigation axis
-
-        // go to the first character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("a");
-
-        // go to the second character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<b>b</b>");
-
-        // go to the third character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("c");
-
-        // go to the fourth character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("d");
-
-        // go to the fifth character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("e");
-
-        // try to go past the last character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the fifth character (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("e");
-
-        // go to the fourth character (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("d");
-
-        // go to the third character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("c");
-
-        // go to the second character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<b>b</b>");
-
-        // go to the first character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("a");
-
-        // try to go before the first character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("a");
-
-        // go to the second character (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<b>b</b>");
-    }
-
-    /**
-     * Tests navigation by word.
-     */
-    @LargeTest
-    public void testNavigationByWord() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<html>" +
-               "<head>" +
-               "</head>" +
-               "<body>" +
-                   "<p>" +
-                      "This is <b>a</b> sentence" +
-                   "</p>" +
-                   "<p>" +
-                     " scattered " +
-                     "<p/>" +
-                     " all over " +
-                   "</p>" +
-                   "<div>" +
-                     "<p>the place.</p>" +
-                   "</div>" +
-               "</body>" +
-             "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("1"); // expect the word navigation axis
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This");
-
-        // go to the second word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("is");
-
-        // go to the third word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<b>a</b>");
-
-        // go to the fourth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("sentence");
-
-        // go to the fifth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("scattered");
-
-        // go to the sixth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("all");
-
-        // go to the seventh word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("over");
-
-        // go to the eight word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("the");
-
-        // go to the ninth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("place");
-
-        // NOTE: WebKit selection returns the dot as a word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(".");
-
-        // try to go past the last word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the last word (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("place.");
-
-        // go to the eight word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("the");
-
-        // go to the seventh word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("over");
-
-        // go to the sixth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("all");
-
-        // go to the fifth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("scattered");
-
-        // go to the fourth word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("sentence");
-
-        // go to the third word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<b>a</b>");
-
-        // go to the second word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("is");
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("This");
-
-        // try to go before the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This");
-
-        // go to the second word (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("is");
-    }
-
-    /**
-     * Tests navigation by sentence.
-     */
-    @LargeTest
-    public void testNavigationBySentence() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>" +
-                  "<p>" +
-                    "This is the first sentence of the first paragraph and has an <b>inline bold tag</b>." +
-                    "This is the second sentence of the first paragraph." +
-                  "</p>" +
-                  "<h1>This is a heading</h1>" +
-                  "<p>" +
-                    "This is the first sentence of the second paragraph." +
-                    "This is the second sentence of the second paragraph." +
-                  "</p>" +
-                "</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // Sentence axis is the default
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is the first sentence of the first paragraph and has an "
-                + "<b>inline bold tag</b>.");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is the second sentence of the first paragraph.");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is a heading");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is the first sentence of the second paragraph.");
-
-        // go to the fifth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is the second sentence of the second paragraph.");
-
-        // try to go past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the fifth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("This is the second sentence of the second paragraph.");
-
-        // go to the fourth sentence (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("This is the first sentence of the second paragraph.");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("This is a heading");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("This is the second sentence of the first paragraph.");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("This is the first sentence of the first paragraph and has an "
-                + "<b>inline bold tag</b>.");
-
-        // try to go before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is the first sentence of the first paragraph and has an "
-                + "<b>inline bold tag</b>.");
-
-        // go to the second sentence (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("This is the second sentence of the first paragraph.");
-    }
-
-    /**
-     * Tests navigation by heading.
-     */
-    @LargeTest
-    public void testNavigationByHeading() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<h1>Heading one</h1>" +
-                "<p>" +
-                  "This is some text" +
-                "</p>" +
-                "<h2>Heading two</h2>" +
-                "<p>" +
-                  "This is some text" +
-                "</p>" +
-                "<h3>Heading three</h3>" +
-                "<p>" +
-                  "This is some text" +
-                "</p>" +
-                "<h4>Heading four</h4>" +
-                "<p>" +
-                  "This is some text" +
-                "</p>" +
-                "<h5>Heading five</h5>" +
-                "<p>" +
-                  "This is some text" +
-                "</p>" +
-                "<h6>Heading six</h6>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("3"); // expect the heading navigation axis
-
-        // go to the first heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h1>Heading one</h1>");
-
-        // go to the second heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h2>Heading two</h2>");
-
-        // go to the third heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h3>Heading three</h3>");
-
-        // go to the fourth heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h4>Heading four</h4>");
-
-        // go to the fifth heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h5>Heading five</h5>");
-
-        // go to the sixth heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h6>Heading six</h6>");
-
-        // try to go past the last heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the fifth heading (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<h5>Heading five</h5>");
-
-        // go to the fourth heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<h4>Heading four</h4>");
-
-        // go to the third heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<h3>Heading three</h3>");
-
-        // go to the second heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<h2>Heading two</h2>");
-
-        // go to the first heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<h1>Heading one</h1>");
-
-        // try to go before the first heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the second heading (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h2>Heading two</h2>");
-    }
-
-    /**
-     * Tests navigation by sibling.
-     */
-    @LargeTest
-    public void testNavigationBySibing() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<h1>Heading one</h1>" +
-                "<p>" +
-                  "This is some text" +
-                "</p>" +
-                "<div>" +
-                  "<button>Input</button>" +
-                "</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("3"); // expect the heading navigation axis
-
-        // change navigation axis to sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("4"); // expect the sibling navigation axis
-
-        // change navigation axis to parent/first child
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("5"); // expect the parent/first child navigation axis
-
-        // go to the first child of the body
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<h1>Heading one</h1>");
-
-        // change navigation axis to sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("4"); // expect the sibling navigation axis
-
-        // go to the next sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<p>This is some text</p>");
-
-        // go to the next sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<div><button>Input</button></div>");
-
-        // try to go past the last sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the previous sibling (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<p>This is some text</p>");
-
-        // go to the previous sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<h1>Heading one</h1>");
-
-        // try to go before the previous sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the next sibling (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<p>This is some text</p>");
-    }
-
-    /**
-     * Tests navigation by parent/first child.
-     */
-    @LargeTest
-    public void testNavigationByParentFirstChild() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>" +
-                  "<button>Input</button>" +
-                "</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to document
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("6"); // expect the document navigation axis
-
-        // change navigation axis to parent/first child
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("5"); // expect the parent/first child navigation axis
-
-        // go to the first child
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<div><button>Input</button></div>");
-
-        // go to the first child
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<button>Input</button>");
-
-        // try to go to the first child of a leaf element
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the parent (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<div><button>Input</button></div>");
-
-        // go to the parent
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<body><div><button>Input</button></div></body>");
-
-        // try to go to the body parent
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first child (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<div><button>Input</button></div>");
-    }
-
-    /**
-     * Tests navigation by document.
-     */
-    @LargeTest
-    public void testNavigationByDocument() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<button>Click</button>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to document
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("6"); // expect the document navigation axis
-
-        // go to the bottom of the document
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Click");
-
-        // go to the top of the document (reverse)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<body><button>Click</button></body>");
-
-        // go to the bottom of the document (reverse again)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Click");
-    }
-
-    /**
-     * Tests the sync between the text navigation and navigation by DOM elements.
-     */
-    @LargeTest
-    public void testSyncBetweenTextAndDomNodeNavigation() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<p>" +
-                  "First" +
-                "</p>" +
-                "<button>Second</button>" +
-                "<p>" +
-                  "Third" +
-                "</p>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("1"); // expect the word navigation axis
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // change navigation axis to heading
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("3"); // expect the heading navigation axis
-
-        // change navigation axis to sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("4"); // expect the sibling navigation axis
-
-        // go to the next sibling
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<button>Second</button>");
-
-        // change navigation axis to character
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("0"); // expect the character navigation axis
-
-        // change navigation axis to word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("1"); // expect the word navigation axis
-
-        // go to the next word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Third");
-    }
-
-    /**
-     * Tests that the selection does not cross anchor boundaries. This is a
-     * workaround for the asymmetric and inconsistent handling of text with
-     * links by WebKit while traversing by sentence.
-     */
-    @LargeTest
-    public void testEnforceSelectionDoesNotCrossAnchorBoundary1() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>First</div>" +
-                "<p>" +
-                  "<a href=\"\">Second</a> Third" +
-                "</p>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<div>First</div>");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"\">Second</a>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Third");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Third");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"\">Second</a>");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<div>First</div>");
-    }
-
-    /**
-     * Tests that the selection does not cross anchor boundaries. This is a
-     * workaround for the asymmetric and inconsistent handling of text with
-     * links by WebKit while traversing by sentence.
-     */
-    @LargeTest
-    public void testEnforceSelectionDoesNotCrossAnchorBoundary2() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>First</div>" +
-                "<a href=\"#\">Second</a>" +
-                "&nbsp;" +
-                "<a href=\"#\">Third</a>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\">Second</a>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("&nbsp;");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\">Third</a>");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"#\">Third</a>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("&nbsp;");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"#\">Second</a>");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Tests that the selection does not cross anchor boundaries. This is a
-     * workaround for the asymmetric and inconsistent handling of text with
-     * links by WebKit while traversing by sentence.
-     */
-    @LargeTest
-    public void testEnforceSelectionDoesNotCrossAnchorBoundary3() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>" +
-                  "First" +
-                "<div>" +
-                "<div>" +
-                  "<a href=\"#\">Second</a>" +
-                "</div>" +
-                "<div>" +
-                  "Third" +
-                "</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\">Second</a>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Third");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Third");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"#\">Second</a>");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Tests skipping of content with hidden visibility.
-     */
-    @LargeTest
-    public void testSkipVisibilityHidden() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>First </div>" +
-                "<div style=\"visibility:hidden;\">Second</div>" +
-                "<div> Third</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("1"); // expect the word navigation axis
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the third word (the second is invisible)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Third");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third word (the second is invisible)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Third");
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Tests skipping of content with display none.
-     */
-    @LargeTest
-    public void testSkipDisplayNone() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>First</div>" +
-                "<div style=\"display: none;\">Second</div>" +
-                "<div>Third</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // change navigation axis to word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
-        assertSelectionString("1"); // expect the word navigation axis
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the third word (the second is invisible)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Third");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third word (the second is invisible)
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Third");
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first word
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Tests for the selection not getting stuck.
-     *
-     * Note: The selection always proceeds but if it can
-     * be selecting the same content i.e. between the start
-     * and end are contained the same text nodes.
-     */
-    @LargeTest
-    public void testSelectionTextProceed() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<a href=\"#\">First</a>" +
-                "<span><a href=\"#\"><span>Second</span>&nbsp;<small>a</small></a>" +
-                "</span>&nbsp;<a href=\"#\">Third</a>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\">First</a>");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\"><span>Second&nbsp;<small>a</small></a>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("&nbsp;");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\">Third</a>");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"#\">Third</a>");
-
-        // NOTE: Here we are a bit asymmetric around whitespace but we can live with it
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("&nbsp;");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"#\"><span>Second&nbsp;<small>a</small></a>");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<a href=\"#\">First</a>");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<a href=\"#\">First</a>");
-    }
-
-    /**
-     * Tests if input elements are selected rather skipped.
-     */
-    @LargeTest
-    public void testSelectionOfInputElements() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<p>" +
-                  "First" +
-                "</p>" +
-                "<input type=\"text\"/>" +
-                "<p>" +
-                  "Second" +
-                "</p>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Second");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Second");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Tests traversing of input controls.
-     */
-    @LargeTest
-    public void testSelectionOfInputElements2() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>" +
-                  "First" +
-                  "<input type=\"text\"/>" +
-                  "<span>" +
-                    "<input type=\"text\"/>" +
-                  "</span>" +
-                  "<button type=\"button\">Click Me!</button>" +
-                  "<div>" +
-                    "<input type=\"submit\"/>" +
-                  "</div>" +
-                  "<p>" +
-                    "Second" +
-                  "</p>" +
-                "</div>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<button type=\"button\">Click Me!</button>");
-
-        // go to the fifth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"submit\">");
-
-        // go to the sixth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Second");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the sixth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Second");
-
-        // go to the fifth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"submit\">");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<button type=\"button\">Click Me!</button>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Tests traversing of input controls.
-     */
-    @LargeTest
-    public void testSelectionOfInputElements3() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<input type=\"text\"/>" +
-                "<button type=\"button\">Click Me!</button>" +
-                "<select>" +
-                  "<option value=\"volvo\">Volvo</option>" +
-                  "<option value=\"saab\">Saab</option>" +
-                "</select>" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<button type=\"button\">Click Me!</button>");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<select><option value=\"volvo\">Volvo</option>" +
-                "<option value=\"saab\">Saab</option></select>");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<select><option value=\"volvo\">Volvo</option>" +
-                "<option value=\"saab\">Saab</option></select>");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<button type=\"button\">Click Me!</button>");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\">");
-    }
-
-    /**
-     * Tests traversing of input controls.
-     */
-    @LargeTest
-    public void testSelectionOfInputElements4() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "Start" +
-                "<span>" +
-                  "<span>" +
-                    "<input type=\"submit\">" +
-                  "</span>" +
-                "</span>" +
-                "<input type=\"text\" size=\"30\">" +
-                "<span>" +
-                  "<span>" +
-                    "<input type=\"submit\" size=\"30\">" +
-                  "</span>" +
-                "</span>" +
-                "End" +
-              "</body>" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Start");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"submit\">");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\" size=\"30\">");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"submit\" size=\"30\">");
-
-        // go to the fifth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("End");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the fifth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("End");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"submit\" size=\"30\">");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"text\" size=\"30\">");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"submit\">");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Start");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Start");
-    }
-
-    /**
-     * Tests traversing of input controls.
-     */
-    @LargeTest
-    public void testSelectionOfInputElements5() throws Exception {
-        // a bit ugly but helps detect beginning and end of all tests so accessibility
-        // and the mock service are not toggled on every test (expensive)
-        sExecutedTestCount++;
-
-        String html =
-            "<!DOCTYPE html>" +
-            "<html>" +
-              "<head>" +
-              "</head>" +
-              "<body>" +
-                "<div>" +
-                  "First" +
-                  "<input type=\"hidden\">" +
-                  "<input type=\"hidden\">" +
-                  "<input type=\"hidden\">" +
-                  "<input type=\"hidden\">" +
-                  "<input type=\"text\">" +
-                  "<span>" +
-                    "<span>" +
-                      "<input type=\"submit\">" +
-                    "</span>" +
-                  "</span>" +
-                "</div>" +
-              "</body>" +
-              "Second" +
-            "</html>";
-
-        WebView webView = loadHTML(html);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("<input type=\"submit\">");
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("Second");
-
-        // go to past the last sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString(null);
-
-        // go to the fourth sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("Second");
-
-        // go to the third sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"submit\">");
-
-        // go to the second sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("<input type=\"text\">");
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString("First");
-
-        // go to before the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
-        assertSelectionString(null);
-
-        // go to the first sentence
-        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
-        assertSelectionString("First");
-    }
-
-    /**
-     * Enable accessibility and the mock accessibility service.
-     */
-    private void enableAccessibilityAndMockAccessibilityService() {
-        // make sure the manager is instantiated so the system initializes it
-        AccessibilityManager.getInstance(getActivity());
-
-        // enable accessibility and the mock accessibility service
-        Settings.Secure.putInt(getActivity().getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, 1);
-        String enabledServices = new ComponentName(getActivity().getPackageName(),
-                MockAccessibilityService.class.getName()).flattenToShortString();
-        Settings.Secure.putString(getActivity().getContentResolver(),
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
-
-        // poll within a timeout and let be interrupted in case of success
-        long incrementStep = TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE / 5;
-        long start = SystemClock.uptimeMillis();
-        while (SystemClock.uptimeMillis() - start < TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE &&
-                !sIsAccessibilityServiceReady) {
-            synchronized (sTestLock) {
-                try {
-                    sTestLock.wait(incrementStep);
-                } catch (InterruptedException ie) {
-                    /* ignore */
-                }
-            }
-        }
-
-        if (!sIsAccessibilityServiceReady) {
-            throw new IllegalStateException("MockAccessibilityService not ready. Did you add " +
-                    "tests and forgot to update AccessibilityInjectorTest#TEST_CASE_COUNT?");
-        }
-    }
-
-    @Override
-    protected void scrubClass(Class<?> testCaseClass) {
-        /* do nothing - avoid superclass behavior */
-    }
-
-    /**
-     * Strips the apple span appended by WebKit while generating
-     * the selection markup.
-     *
-     * @param markup The markup.
-     * @return Stripped from apple spans markup.
-     */
-    private static String stripAppleSpanFromMarkup(String markup) {
-        StringBuilder stripped = new StringBuilder(markup);
-        int prefixBegIdx = stripped.indexOf(APPLE_SPAN_PREFIX);
-        while (prefixBegIdx >= 0) {
-            int prefixEndIdx = stripped.indexOf(">", prefixBegIdx) + 1;
-            stripped.replace(prefixBegIdx, prefixEndIdx, "");
-            int suffixBegIdx = stripped.lastIndexOf(APPLE_SPAN_SUFFIX);
-            int suffixEndIdx = suffixBegIdx + APPLE_SPAN_SUFFIX.length();
-            stripped.replace(suffixBegIdx, suffixEndIdx, "");
-            prefixBegIdx = stripped.indexOf(APPLE_SPAN_PREFIX);
-        }
-        return stripped.toString();
-    }
-
-    /**
-     * Disables accessibility and the mock accessibility service.
-     */
-    private void disableAccessibilityAndMockAccessibilityService() {
-        // disable accessibility and the mock accessibility service
-        Settings.Secure.putInt(getActivity().getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, 0);
-        Settings.Secure.putString(getActivity().getContentResolver(),
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
-    }
-
-    /**
-     * Asserts the next <code>expectedSelectionString</code> to be received.
-     */
-    private void assertSelectionString(String expectedSelectionString) {
-        assertTrue("MockAccessibilityService not ready", sIsAccessibilityServiceReady);
-
-        long incrementStep = TIMEOUT_WAIT_FOR_SELECTION_STRING / 5;
-        long start = SystemClock.uptimeMillis();
-        while (SystemClock.uptimeMillis() - start < TIMEOUT_WAIT_FOR_SELECTION_STRING &&
-                sReceivedSelectionString == SELECTION_STRING_UNKNOWN) {
-            synchronized (sTestLock) {
-                try {
-                    sTestLock.wait(incrementStep);
-                } catch (InterruptedException ie) {
-                    /* ignore */
-                }
-            }
-        }
-        try {
-            if (sReceivedSelectionString == SELECTION_STRING_UNKNOWN) {
-                fail("No selection string received. Expected: " + expectedSelectionString);
-            }
-            assertEquals(expectedSelectionString, sReceivedSelectionString);
-        } finally {
-            sReceivedSelectionString = SELECTION_STRING_UNKNOWN;
-        }
-    }
-
-    /**
-     * Sends a {@link KeyEvent} (up and down) to the {@link WebView}.
-     *
-     * @param keyCode The event key code.
-     */
-    private void sendKeyEvent(WebView webView, int keyCode, int metaState) {
-        webView.onKeyDown(keyCode, new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 1, metaState));
-        webView.onKeyUp(keyCode, new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 1, metaState));
-    }
-
-    /**
-     * Loads HTML content in a {@link WebView}.
-     *
-     * @param html The HTML content;
-     * @return The {@link WebView} view.
-     */
-    private WebView loadHTML(final String html) {
-        mWorker.getHandler().post(new Runnable() {
-            public void run() {
-                if (mWebView == null) {
-                    mWebView = getActivity().getWebView();
-                    mWebView.setWebViewClient(new WebViewClient() {
-                        @Override
-                        public void onPageFinished(WebView view, String url) {
-                            mWorker.getHandler().post(new Runnable() {
-                                public void run() {
-                                    synchronized (sTestLock) {
-                                        sTestLock.notifyAll();
-                                    }
-                                }
-                            });
-                        }
-                    });
-                }
-                mWebView.loadData(html, "text/html", null);
-            }
-        });
-        synchronized (sTestLock) {
-            try {
-                sTestLock.wait();
-            } catch (InterruptedException ie) {
-                /* ignore */
-            }
-        }
-        return mWebView;
-    }
-
-    /**
-     * Injects web content key bindings used for testing. This is required
-     * to ensure that this test will be agnostic to changes of the bindings.
-     */
-    private void injectTestWebContentKeyBindings() {
-        ContentResolver contentResolver = getActivity().getContentResolver();
-        sDefaultKeyBindings = Settings.Secure.getString(contentResolver,
-                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
-        Settings.Secure.putString(contentResolver,
-                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS, TEST_KEY_DINDINGS);
-    }
-
-    /**
-     * Restores the default web content key bindings.
-     */
-    private void restoreDefaultWebContentKeyBindings() {
-        Settings.Secure.putString(getActivity().getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
-                sDefaultKeyBindings);
-    }
-
-    /**
-     * This is a worker thread responsible for creating the {@link WebView}.
-     */
-    private class Worker implements Runnable {
-        private final Object mWorkerLock = new Object();
-        private Handler mHandler;
-
-       public Worker() {
-            new Thread(this).start();
-            synchronized (mWorkerLock) {
-                while (mHandler == null) {
-                    try {
-                        mWorkerLock.wait();
-                    } catch (InterruptedException ex) {
-                        /* ignore */
-                    }
-                }
-            }
-        }
-
-        public void run() {
-            synchronized (mWorkerLock) {
-                Looper.prepare();
-                mHandler = new Handler();
-                mWorkerLock.notifyAll();
-            }
-            Looper.loop();
-        }
-
-        public Handler getHandler() {
-            return mHandler;
-        }
-
-        public void stop() {
-            mHandler.getLooper().quit();
-        }
-    }
-
-    /**
-     * Mock accessibility service to receive the accessibility events
-     * with the current {@link WebView} selection.
-     */
-    public static class MockAccessibilityService extends AccessibilityService {
-        private boolean mIsServiceInfoSet;
-
-        @Override
-        protected void onServiceConnected() {
-            if (mIsServiceInfoSet) {
-                return;
-            }
-            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
-            info.eventTypes = AccessibilityEvent.TYPE_VIEW_SELECTED;
-            info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
-            setServiceInfo(info);
-            mIsServiceInfoSet = true;
-
-            sIsAccessibilityServiceReady = true;
-
-            if (sInstance == null) {
-                return;
-            }
-            synchronized (sTestLock) {
-                sTestLock.notifyAll();
-            }
-        }
-
-        @Override
-        public void onAccessibilityEvent(AccessibilityEvent event) {
-            if (sInstance == null) {
-                return;
-            }
-            if (!event.getText().isEmpty()) {
-                CharSequence text = event.getText().get(0);
-                if (text != null) {
-                    sReceivedSelectionString = stripAppleSpanFromMarkup(text.toString());
-                } else {
-                    sReceivedSelectionString = null;
-                }
-            }
-            synchronized (sTestLock) {
-                sTestLock.notifyAll();
-            }
-        }
-
-        @Override
-        public void onInterrupt() {
-            /* do nothing */
-        }
-
-        @Override
-        public boolean onUnbind(Intent intent) {
-            sIsAccessibilityServiceReady = false;
-            return false;
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTestActivity.java b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTestActivity.java
deleted file mode 100644
index 3842df7..0000000
--- a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTestActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-package android.webkit;
-
-import com.android.frameworks.coretests.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class AccessibilityInjectorTestActivity extends Activity {
-
-    private WebView mWebView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        setContentView(R.layout.accessibility_injector_test);
-        mWebView = (WebView) findViewById(R.id.webview);
-    }
-
-    public WebView getWebView() {
-        return mWebView;
-    }
-}
diff --git a/core/tests/coretests/src/android/webkit/UrlInterceptRegistryTest.java b/core/tests/coretests/src/android/webkit/UrlInterceptRegistryTest.java
deleted file mode 100644
index 7504449..0000000
--- a/core/tests/coretests/src/android/webkit/UrlInterceptRegistryTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-import android.test.AndroidTestCase;
-import android.util.Log;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.PluginData;
-import android.webkit.UrlInterceptHandler;
-
-import java.util.LinkedList;
-import java.util.Map;
-
-public class UrlInterceptRegistryTest extends AndroidTestCase {
-
-    /**
-     * To run these tests: $ mmm
-     * frameworks/base/tests/CoreTests/android && adb remount && adb
-     * sync $ adb shell am instrument -w  -e class \
-     * android.webkit.UrlInterceptRegistryTest \
-     * android.core/android.test.InstrumentationTestRunner
-     */
-
-    private static class MockUrlInterceptHandler implements UrlInterceptHandler {
-        private PluginData mData;
-        private String mUrl;
-
-        public MockUrlInterceptHandler(PluginData data, String url) {
-            mData = data;
-            mUrl = url;
-        }
-
-        public CacheResult service(String url, Map<String, String> headers) {
-            return null;
-        }
-
-        public PluginData getPluginData(String url,
-                                        Map<String,
-                                        String> headers) {
-            if (mUrl.equals(url)) {
-                return mData;
-            }
-
-            return null;
-        }
-    }
-
-    public void testGetPluginData() {
-        PluginData data = new PluginData(null, 0 , null, 200);
-        String url = new String("url1");
-        MockUrlInterceptHandler handler1 =
-                new MockUrlInterceptHandler(data, url);
-
-        data = new PluginData(null, 0 , null, 404);
-        url = new String("url2");
-        MockUrlInterceptHandler handler2 =
-                new MockUrlInterceptHandler(data, url);
-
-        assertTrue(UrlInterceptRegistry.registerHandler(handler1));
-        assertTrue(UrlInterceptRegistry.registerHandler(handler2));
-
-        data = UrlInterceptRegistry.getPluginData("url1", null);
-        assertTrue(data != null);
-        assertTrue(data.getStatusCode() == 200);
-
-        data = UrlInterceptRegistry.getPluginData("url2", null);
-        assertTrue(data != null);
-        assertTrue(data.getStatusCode() == 404);
-
-        assertTrue(UrlInterceptRegistry.unregisterHandler(handler1));
-        assertTrue(UrlInterceptRegistry.unregisterHandler(handler2));
-
-    }
-}
diff --git a/core/tests/coretests/src/android/webkit/WebkitTest.java b/core/tests/coretests/src/android/webkit/WebkitTest.java
deleted file mode 100644
index 4685e3c..0000000
--- a/core/tests/coretests/src/android/webkit/WebkitTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-package android.webkit;
-
-import android.test.AndroidTestCase;
-import android.text.format.DateFormat;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
-import android.webkit.DateSorter;
-
-import java.util.Calendar;
-import java.util.Date;
-
-public class WebkitTest extends AndroidTestCase {
-
-    private static final String LOGTAG = WebkitTest.class.getName();
-
-    @MediumTest
-    public void testDateSorter() throws Exception {
-        /**
-         * Note: check the logging output manually to test
-         * nothing automated yet, besides object creation
-         */
-        DateSorter dateSorter = new DateSorter(mContext);
-        Date date = new Date();
-
-        for (int i = 0; i < DateSorter.DAY_COUNT; i++) {
-            Log.i(LOGTAG, "Boundary " + i + " " + dateSorter.getBoundary(i));
-            Log.i(LOGTAG, "Label " + i + " " + dateSorter.getLabel(i));
-        }
-
-        Calendar c = Calendar.getInstance();
-        long time = c.getTimeInMillis();
-        int index;
-        Log.i(LOGTAG, "now: " + dateSorter.getIndex(time));
-        for (int i = 0; i < 20; i++) {
-            time -= 8 * 60 * 60 * 1000; // 8 hours
-            date.setTime(time);
-            c.setTime(date);
-            index = dateSorter.getIndex(time);
-            Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd HH:mm:ss", c).toString() +
-                    " " + index + " " + dateSorter.getLabel(index));
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/webkit/ZoomManagerTest.java b/core/tests/coretests/src/android/webkit/ZoomManagerTest.java
deleted file mode 100644
index 7e0e0b2..0000000
--- a/core/tests/coretests/src/android/webkit/ZoomManagerTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.webkit;
-
-import android.test.AndroidTestCase;
-
-public class ZoomManagerTest extends AndroidTestCase {
-
-    private ZoomManager zoomManager;
-
-    @Override
-    public void setUp() {
-        WebView webView = new WebView(this.getContext());
-        WebViewClassic webViewClassic = WebViewClassic.fromWebView(webView);
-        CallbackProxy callbackProxy = new CallbackProxy(this.getContext(), webViewClassic);
-        zoomManager = new ZoomManager(webViewClassic, callbackProxy);
-
-        zoomManager.init(1.00f);
-    }
-
-    public void testInit() {
-        testInit(0.01f);
-        testInit(1.00f);
-        testInit(1.25f);
-    }
-
-    private void testInit(float density) {
-        zoomManager.init(density);
-        actualScaleTest(density);
-        defaultScaleTest(density);
-        assertEquals(zoomManager.getDefaultMaxZoomScale(), zoomManager.getMaxZoomScale());
-        assertEquals(zoomManager.getDefaultMinZoomScale(), zoomManager.getMinZoomScale());
-        assertEquals(density, zoomManager.getTextWrapScale());
-    }
-
-    public void testUpdateDefaultZoomDensity() {
-        // test the basic case where the actual values are equal to the defaults
-        testUpdateDefaultZoomDensity(0.01f);
-        testUpdateDefaultZoomDensity(1.00f);
-        testUpdateDefaultZoomDensity(1.25f);
-    }
-
-    private void testUpdateDefaultZoomDensity(float density) {
-        zoomManager.updateDefaultZoomDensity(density);
-        defaultScaleTest(density);
-    }
-
-    public void testUpdateDefaultZoomDensityWithSmallMinZoom() {
-        // test the case where the minZoomScale has changed to be < the default
-        float newDefaultScale = 1.50f;
-        float minZoomScale = ZoomManager.DEFAULT_MIN_ZOOM_SCALE_FACTOR * newDefaultScale;
-        WebViewCore.ViewState minViewState = new WebViewCore.ViewState();
-        minViewState.mMinScale = minZoomScale - 0.1f;
-        zoomManager.updateZoomRange(minViewState, 0, 0);
-        zoomManager.updateDefaultZoomDensity(newDefaultScale);
-        defaultScaleTest(newDefaultScale);
-    }
-
-    public void testUpdateDefaultZoomDensityWithLargeMinZoom() {
-        // test the case where the minZoomScale has changed to be > the default
-        float newDefaultScale = 1.50f;
-        float minZoomScale = ZoomManager.DEFAULT_MIN_ZOOM_SCALE_FACTOR * newDefaultScale;
-        WebViewCore.ViewState minViewState = new WebViewCore.ViewState();
-        minViewState.mMinScale = minZoomScale + 0.1f;
-        zoomManager.updateZoomRange(minViewState, 0, 0);
-        zoomManager.updateDefaultZoomDensity(newDefaultScale);
-        defaultScaleTest(newDefaultScale);
-    }
-
-    public void testUpdateDefaultZoomDensityWithSmallMaxZoom() {
-        // test the case where the maxZoomScale has changed to be < the default
-        float newDefaultScale = 1.50f;
-        float maxZoomScale = ZoomManager.DEFAULT_MAX_ZOOM_SCALE_FACTOR * newDefaultScale;
-        WebViewCore.ViewState maxViewState = new WebViewCore.ViewState();
-        maxViewState.mMaxScale = maxZoomScale - 0.1f;
-        zoomManager.updateZoomRange(maxViewState, 0, 0);
-        zoomManager.updateDefaultZoomDensity(newDefaultScale);
-        defaultScaleTest(newDefaultScale);
-    }
-
-    public void testUpdateDefaultZoomDensityWithLargeMaxZoom() {
-        // test the case where the maxZoomScale has changed to be > the default
-        float newDefaultScale = 1.50f;
-        float maxZoomScale = ZoomManager.DEFAULT_MAX_ZOOM_SCALE_FACTOR * newDefaultScale;
-        WebViewCore.ViewState maxViewState = new WebViewCore.ViewState();
-        maxViewState.mMaxScale = maxZoomScale + 0.1f;
-        zoomManager.updateZoomRange(maxViewState, 0, 0);
-        zoomManager.updateDefaultZoomDensity(newDefaultScale);
-        defaultScaleTest(newDefaultScale);
-    }
-
-    public void testComputeScaleWithLimits() {
-        final float maxScale = zoomManager.getMaxZoomScale();
-        final float minScale = zoomManager.getMinZoomScale();
-        assertTrue(maxScale > minScale);
-        assertEquals(maxScale, zoomManager.computeScaleWithLimits(maxScale));
-        assertEquals(maxScale, zoomManager.computeScaleWithLimits(maxScale + .01f));
-        assertEquals(minScale, zoomManager.computeScaleWithLimits(minScale));
-        assertEquals(minScale, zoomManager.computeScaleWithLimits(minScale - .01f));
-    }
-
-    private void actualScaleTest(float actualScale) {
-        assertEquals(actualScale, zoomManager.getScale());
-        assertEquals(1 / actualScale, zoomManager.getInvScale());
-    }
-
-    private void defaultScaleTest(float defaultScale) {
-        final float maxDefault = ZoomManager.DEFAULT_MAX_ZOOM_SCALE_FACTOR * defaultScale;
-        final float minDefault = ZoomManager.DEFAULT_MIN_ZOOM_SCALE_FACTOR * defaultScale;
-        assertEquals(defaultScale, zoomManager.getDefaultScale());
-        assertEquals(1 / defaultScale, zoomManager.getInvDefaultScale());
-        assertEquals(maxDefault, zoomManager.getDefaultMaxZoomScale());
-        assertEquals(minDefault, zoomManager.getDefaultMinZoomScale());
-    }
-}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 1289971..89d102d 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -54,10 +54,6 @@
         <group gid="inet" />
     </permission>
 
-    <permission name="android.permission.CAMERA" >
-        <group gid="camera" />
-    </permission>
-
     <permission name="android.permission.READ_LOGS" >
         <group gid="log" />
     </permission>
@@ -67,9 +63,16 @@
     </permission>
 
     <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
+        <group gid="sdcard_r" />
         <group gid="sdcard_rw" />
     </permission>
 
+    <permission name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" >
+        <group gid="sdcard_r" />
+        <group gid="sdcard_rw" />
+        <group gid="sdcard_all" />
+    </permission>
+
     <permission name="android.permission.WRITE_MEDIA_STORAGE" >
         <group gid="media_rw" />
     </permission>
@@ -123,7 +126,6 @@
          interact with the system. -->
 
     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
-    <assign-permission name="android.permission.ACCESS_DRM" uid="media" />
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
     <assign-permission name="android.permission.WAKE_LOCK" uid="media" />
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 7f8d5f0..0d9a386 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -53,22 +53,6 @@
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := DroidSansTamil-Regular.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := DroidSansTamil-Bold.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
 LOCAL_MODULE := MTLmr3m.ttf
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 LOCAL_MODULE_CLASS := ETC
@@ -81,8 +65,6 @@
 	DroidSans.ttf \
 	DroidSans-Bold.ttf \
 	DroidSansEthiopic-Regular.ttf \
-	DroidSansTamil-Regular.ttf \
-	DroidSansTamil-Bold.ttf \
 	MTLmr3m.ttf
 endif  # SMALLER_FONT_FOOTPRINT
 
@@ -153,10 +135,8 @@
     RobotoCondensed-BoldItalic.ttf \
     DroidNaskh-Regular.ttf \
     DroidNaskhUI-Regular.ttf \
-    DroidSansDevanagari-Regular.ttf \
     DroidSansHebrew-Regular.ttf \
     DroidSansHebrew-Bold.ttf \
-    DroidSansThai.ttf \
     DroidSansArmenian.ttf \
     DroidSansGeorgian.ttf \
     AndroidEmoji.ttf
diff --git a/data/fonts/AndroidEmoji.ttf b/data/fonts/AndroidEmoji.ttf
index 92bf047..98f72e7 100644
--- a/data/fonts/AndroidEmoji.ttf
+++ b/data/fonts/AndroidEmoji.ttf
Binary files differ
diff --git a/data/fonts/DroidSansDevanagari-Regular.ttf b/data/fonts/DroidSansDevanagari-Regular.ttf
deleted file mode 100644
index a25e0e3..0000000
--- a/data/fonts/DroidSansDevanagari-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansTamil-Bold.ttf b/data/fonts/DroidSansTamil-Bold.ttf
deleted file mode 100644
index 8ad0085..0000000
--- a/data/fonts/DroidSansTamil-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansTamil-Regular.ttf b/data/fonts/DroidSansTamil-Regular.ttf
deleted file mode 100644
index 4b8f536..0000000
--- a/data/fonts/DroidSansTamil-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansThai.ttf b/data/fonts/DroidSansThai.ttf
deleted file mode 100644
index 15b00c2..0000000
--- a/data/fonts/DroidSansThai.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index ac99518..ede7ef4 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -52,7 +52,14 @@
     </family>
     <family>
         <fileset>
-            <file>DroidSansThai.ttf</file>
+            <file variant="elegant">NotoSansThai-Regular.ttf</file>
+            <file variant="elegant">NotoSansThai-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansThaiUI-Regular.ttf</file>
+            <file variant="compact">NotoSansThaiUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
@@ -67,13 +74,26 @@
     </family>
     <family>
         <fileset>
-            <file>DroidSansDevanagari-Regular.ttf</file>
+            <file variant="elegant">NotoSansDevanagari-Regular.ttf</file>
+            <file variant="elegant">NotoSansDevanagari-Bold.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file>DroidSansTamil-Regular.ttf</file>
-            <file>DroidSansTamil-Bold.ttf</file>
+            <file variant="compact">NotoSansDevanagariUI-Regular.ttf</file>
+            <file variant="compact">NotoSansDevanagariUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="elegant">NotoSansTamil-Regular.ttf</file>
+            <file variant="elegant">NotoSansTamil-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansTamilUI-Regular.ttf</file>
+            <file variant="compact">NotoSansTamilUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
@@ -126,6 +146,30 @@
     </family>
     <family>
         <fileset>
+            <file variant="elegant">NotoSansKhmer-Regular.ttf</file>
+            <file variant="elegant">NotoSansKhmer-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansKhmerUI-Regular.ttf</file>
+            <file variant="compact">NotoSansKhmerUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="elegant">NotoSansLao-Regular.ttf</file>
+            <file variant="elegant">NotoSansLao-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansLaoUI-Regular.ttf</file>
+            <file variant="compact">NotoSansLaoUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NanumGothic.ttf</file>
         </fileset>
     </family>
@@ -137,11 +181,21 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansSymbols-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>AndroidEmoji.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
+            <file>NotoColorEmoji.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>DroidSansFallback.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 7c2f955..05cca13 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -34,10 +34,8 @@
     RobotoCondensed-BoldItalic.ttf \
     DroidNaskh-Regular.ttf \
     DroidNaskhUI-Regular.ttf \
-    DroidSansDevanagari-Regular.ttf \
     DroidSansHebrew-Regular.ttf \
     DroidSansHebrew-Bold.ttf \
-    DroidSansThai.ttf \
     DroidSerif-Regular.ttf \
     DroidSerif-Bold.ttf \
     DroidSerif-Italic.ttf \
diff --git a/data/keyboards/Android.mk b/data/keyboards/Android.mk
index a66a884..898efe8 100644
--- a/data/keyboards/Android.mk
+++ b/data/keyboards/Android.mk
@@ -21,17 +21,21 @@
 # Validate all key maps.
 include $(CLEAR_VARS)
 
-validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
-files := \
-    $(foreach file,$(keylayouts),frameworks/base/data/keyboards/$(file)) \
-    $(foreach file,$(keycharmaps),frameworks/base/data/keyboards/$(file)) \
-    $(foreach file,$(keyconfigs),frameworks/base/data/keyboards/$(file))
-
 LOCAL_MODULE := validate_framework_keymaps
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := validatekeymaps
+intermediates := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE),,COMMON)
+LOCAL_BUILT_MODULE := $(intermediates)/stamp
 
-validate_framework_keymaps: $(files)
-	$(hide) $(validatekeymaps) $(files)
+validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
+$(LOCAL_BUILT_MODULE): PRIVATE_VALIDATEKEYMAPS := $(validatekeymaps)
+$(LOCAL_BUILT_MODULE) : $(framework_keylayouts) $(framework_keycharmaps) $(framework_keyconfigs) | $(validatekeymaps)
+	$(hide) $(PRIVATE_VALIDATEKEYMAPS) $^
+	$(hide) mkdir -p $(dir $@) && touch $@
 
-include $(BUILD_PHONY_PACKAGE)
+# Run validatekeymaps uncondionally for platform build.
+droidcore all_modules : $(LOCAL_BUILT_MODULE)
+
+# Reset temp vars.
+validatekeymaps :=
+framework_keylayouts :=
+framework_keycharmaps :=
+framework_keyconfigs :=
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 01d22ee..695a74f 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -477,128 +477,4 @@
     ctrl:                               fallback MENU
 }
 
-### Gamepad buttons ###
-
-key BUTTON_A {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_B {
-    base:                               fallback BACK
-}
-
-key BUTTON_C {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_X {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_Y {
-    base:                               fallback BACK
-}
-
-key BUTTON_Z {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_L1 {
-    base:                               none
-}
-
-key BUTTON_R1 {
-    base:                               none
-}
-
-key BUTTON_L2 {
-    base:                               none
-}
-
-key BUTTON_R2 {
-    base:                               none
-}
-
-key BUTTON_THUMBL {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_THUMBR {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_START {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_SELECT {
-    base:                               fallback MENU
-}
-
-key BUTTON_MODE {
-    base:                               fallback MENU
-}
-
-key BUTTON_1 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_2 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_3 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_4 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_5 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_6 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_7 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_8 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_9 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_10 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_11 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_12 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_13 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_14 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_15 {
-    base:                               fallback DPAD_CENTER
-}
-
-key BUTTON_16 {
-    base:                               fallback DPAD_CENTER
-}
+### Gamepad buttons are handled by the view root ###
diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk
index 6fb633b..d75b691 100644
--- a/data/keyboards/common.mk
+++ b/data/keyboards/common.mk
@@ -15,41 +15,8 @@
 # This is the list of framework provided keylayouts and key character maps to include.
 # Used by Android.mk and keyboards.mk.
 
-keylayouts := \
-    Generic.kl \
-    AVRCP.kl \
-    qwerty.kl \
-    Vendor_045e_Product_028e.kl \
-    Vendor_046d_Product_c216.kl \
-    Vendor_046d_Product_c294.kl \
-    Vendor_046d_Product_c299.kl \
-    Vendor_046d_Product_c532.kl \
-    Vendor_054c_Product_0268.kl \
-    Vendor_05ac_Product_0239.kl \
-    Vendor_22b8_Product_093d.kl \
-    Vendor_0079_Product_0011.kl \
-    Vendor_046d_Product_c219.kl \
-    Vendor_046d_Product_c21f.kl \
-    Vendor_0583_Product_2060.kl \
-    Vendor_1038_Product_1412.kl \
-    Vendor_12bd_Product_d015.kl \
-    Vendor_1689_Product_fd00.kl \
-    Vendor_1689_Product_fd01.kl \
-    Vendor_1689_Product_fe00.kl \
-    Vendor_1bad_Product_f016.kl \
-    Vendor_1bad_Product_f023.kl \
-    Vendor_1bad_Product_f027.kl \
-    Vendor_1bad_Product_f036.kl \
-    Vendor_1d79_Product_0009.kl \
-    Vendor_2378_Product_100a.kl
+framework_keylayouts := $(wildcard $(LOCAL_PATH)/*.kl)
 
-keycharmaps := \
-    Generic.kcm \
-    Virtual.kcm \
-    qwerty.kcm \
-    qwerty2.kcm
+framework_keycharmaps := $(wildcard $(LOCAL_PATH)/*.kcm)
 
-keyconfigs := \
-    qwerty.idc \
-    qwerty2.idc
-
+framework_keyconfigs := $(wildcard $(LOCAL_PATH)/*.idc)
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index c964961..68cbd29 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -16,11 +16,11 @@
 
 include $(LOCAL_PATH)/common.mk
 
-PRODUCT_COPY_FILES := $(foreach file,$(keylayouts),\
-    frameworks/base/data/keyboards/$(file):system/usr/keylayout/$(file))
+PRODUCT_COPY_FILES := $(foreach file,$(framework_keylayouts),\
+    $(file):system/usr/keylayout/$(notdir $(file)))
 
-PRODUCT_COPY_FILES += $(foreach file,$(keycharmaps),\
-    frameworks/base/data/keyboards/$(file):system/usr/keychars/$(file))
+PRODUCT_COPY_FILES += $(foreach file,$(framework_keycharmaps),\
+    $(file):system/usr/keychars/$(notdir $(file)))
 
-PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\
-    frameworks/base/data/keyboards/$(file):system/usr/idc/$(file))
+PRODUCT_COPY_FILES += $(foreach file,$(framework_keyconfigs),\
+    $(file):system/usr/idc/$(notdir $(file)))
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index 8b03bf7..ed9bea5 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -221,6 +221,7 @@
     $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
     $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
     $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
     $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
     $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
     $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index 90d8eaa..783e1f8 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -20,6 +20,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index 2897b04..b30be56 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -20,6 +20,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage12.mk b/data/sounds/AudioPackage12.mk
new file mode 100644
index 0000000..af89a82
--- /dev/null
+++ b/data/sounds/AudioPackage12.mk
@@ -0,0 +1,27 @@
+#
+# Audio Package 12 - K
+#
+# Include this file in a product makefile to include these audio files
+#
+#
+
+LOCAL_PATH := frameworks/base/data/sounds
+
+# Simple files that do not require renaming
+ALARM_FILES := Argon Carbon Helium Krypton Neon Oxygen Osmium Platinum
+NOTIFICATION_FILES := Ariel Ceres Carme Elara Europa Iapetus Io Rhea Salacia Titan Tethys
+RINGTONE_FILES := Callisto Dione Ganymede Luna Oberon Phobos Sedna Titania Triton Umbriel
+EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
+	VideoRecord camera_click camera_focus LowBattery Dock Undock Lock Unlock WirelessChargingStarted
+
+PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
+	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
+
+PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
+	$(LOCAL_PATH)/notifications/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg)
+
+PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
+	$(LOCAL_PATH)/ringtones/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg)
+
+PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
+	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
diff --git a/data/sounds/AudioPackage12_48.mk b/data/sounds/AudioPackage12_48.mk
new file mode 100644
index 0000000..636bb9f
--- /dev/null
+++ b/data/sounds/AudioPackage12_48.mk
@@ -0,0 +1,36 @@
+#
+# Audio Package 12 - K (48kHz)
+#
+# Include this file in a product makefile to include these audio files
+#
+#
+
+LOCAL_PATH := frameworks/base/data/sounds
+
+# Simple files that do not require renaming
+ALARM_FILES := Argon Carbon Helium Krypton Neon Oxygen Osmium Platinum
+NOTIFICATION_FILES := Ariel Ceres Carme Elara Europa Iapetus Io Rhea Salacia Titan Tethys
+RINGTONE_FILES := Callisto Dione Ganymede Luna Oberon Phobos Sedna Titania Triton Umbriel
+EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
+	VideoRecord camera_click Lock Unlock
+
+# Alarms not yet available in 48 kHz
+PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
+	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
+
+PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
+	$(LOCAL_PATH)/notifications/ogg/$(fn)_48k.ogg:system/media/audio/notifications/$(fn).ogg)
+
+PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
+	$(LOCAL_PATH)/ringtones/ogg/$(fn)_48k.ogg:system/media/audio/ringtones/$(fn).ogg)
+
+PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
+	$(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg)
+
+# no gold-plated version yet
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
+    $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
+    $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
+    $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index 1a36cba..ea07acd 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -31,6 +31,7 @@
 	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage3.mk b/data/sounds/AudioPackage3.mk
index 146c2e4..a8a3b76 100644
--- a/data/sounds/AudioPackage3.mk
+++ b/data/sounds/AudioPackage3.mk
@@ -31,6 +31,7 @@
 	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage4.mk b/data/sounds/AudioPackage4.mk
index 712d7aa..bde3ba0 100644
--- a/data/sounds/AudioPackage4.mk
+++ b/data/sounds/AudioPackage4.mk
@@ -36,6 +36,7 @@
 	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage5.mk b/data/sounds/AudioPackage5.mk
index 5961f06..077335b 100644
--- a/data/sounds/AudioPackage5.mk
+++ b/data/sounds/AudioPackage5.mk
@@ -17,6 +17,7 @@
 	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index d113a29..2cdd702 100644
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -16,6 +16,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk
index 6ae624e..e909235 100644
--- a/data/sounds/AudioPackage7.mk
+++ b/data/sounds/AudioPackage7.mk
@@ -18,6 +18,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage7alt.mk b/data/sounds/AudioPackage7alt.mk
index 11409f2..1132fa9 100644
--- a/data/sounds/AudioPackage7alt.mk
+++ b/data/sounds/AudioPackage7alt.mk
@@ -18,6 +18,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk
index 93c43da..49b6154 100644
--- a/data/sounds/AudioPackage8.mk
+++ b/data/sounds/AudioPackage8.mk
@@ -20,6 +20,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk
index 73e4fd3..87b7764 100644
--- a/data/sounds/AudioPackage9.mk
+++ b/data/sounds/AudioPackage9.mk
@@ -20,6 +20,7 @@
 	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
 	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/effects/KeypressInvalid.ogg b/data/sounds/effects/KeypressInvalid.ogg
new file mode 100644
index 0000000..24935ad
--- /dev/null
+++ b/data/sounds/effects/KeypressInvalid.ogg
Binary files differ
diff --git a/data/sounds/effects/KeypressInvalid.wav b/data/sounds/effects/KeypressInvalid.wav
new file mode 100644
index 0000000..c4180e35
--- /dev/null
+++ b/data/sounds/effects/KeypressInvalid.wav
Binary files differ
diff --git a/data/sounds/effects/ogg/Effect_Tick.ogg b/data/sounds/effects/ogg/Effect_Tick.ogg
index c8a5c36..42dddb1 100644
--- a/data/sounds/effects/ogg/Effect_Tick.ogg
+++ b/data/sounds/effects/ogg/Effect_Tick.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Effect_Tick_48k.ogg b/data/sounds/effects/ogg/Effect_Tick_48k.ogg
index e1f53d7..eb1847e 100644
--- a/data/sounds/effects/ogg/Effect_Tick_48k.ogg
+++ b/data/sounds/effects/ogg/Effect_Tick_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressDelete.ogg b/data/sounds/effects/ogg/KeypressDelete.ogg
index 38c3244..cf2dce3 100644
--- a/data/sounds/effects/ogg/KeypressDelete.ogg
+++ b/data/sounds/effects/ogg/KeypressDelete.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressDelete_48k.ogg b/data/sounds/effects/ogg/KeypressDelete_48k.ogg
new file mode 100644
index 0000000..9b33f53
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressDelete_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressInvalid.ogg b/data/sounds/effects/ogg/KeypressInvalid.ogg
new file mode 100644
index 0000000..24935ad
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressInvalid.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressInvalid_120.ogg b/data/sounds/effects/ogg/KeypressInvalid_120.ogg
new file mode 100644
index 0000000..24935ad
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressInvalid_120.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressInvalid_120_48k.ogg b/data/sounds/effects/ogg/KeypressInvalid_120_48k.ogg
new file mode 100644
index 0000000..24935ad
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressInvalid_120_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressInvalid_48k.ogg b/data/sounds/effects/ogg/KeypressInvalid_48k.ogg
new file mode 100644
index 0000000..24935ad
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressInvalid_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressReturn.ogg b/data/sounds/effects/ogg/KeypressReturn.ogg
index 1bd5b73..314ed85 100644
--- a/data/sounds/effects/ogg/KeypressReturn.ogg
+++ b/data/sounds/effects/ogg/KeypressReturn.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressReturn_48k.ogg b/data/sounds/effects/ogg/KeypressReturn_48k.ogg
new file mode 100644
index 0000000..04627fc
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressReturn_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressSpacebar.ogg b/data/sounds/effects/ogg/KeypressSpacebar.ogg
index 3a83594..6aca94a 100644
--- a/data/sounds/effects/ogg/KeypressSpacebar.ogg
+++ b/data/sounds/effects/ogg/KeypressSpacebar.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressSpacebar_48k.ogg b/data/sounds/effects/ogg/KeypressSpacebar_48k.ogg
new file mode 100644
index 0000000..9953e56
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressSpacebar_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressStandard.ogg b/data/sounds/effects/ogg/KeypressStandard.ogg
index 4b8d128..9b9747c 100644
--- a/data/sounds/effects/ogg/KeypressStandard.ogg
+++ b/data/sounds/effects/ogg/KeypressStandard.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressStandard_48k.ogg b/data/sounds/effects/ogg/KeypressStandard_48k.ogg
new file mode 100644
index 0000000..3f57438
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressStandard_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Lock.ogg b/data/sounds/effects/ogg/Lock.ogg
index e7928e4..7e98911 100644
--- a/data/sounds/effects/ogg/Lock.ogg
+++ b/data/sounds/effects/ogg/Lock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Lock_48k.ogg b/data/sounds/effects/ogg/Lock_48k.ogg
new file mode 100644
index 0000000..06697ed
--- /dev/null
+++ b/data/sounds/effects/ogg/Lock_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Unlock.ogg b/data/sounds/effects/ogg/Unlock.ogg
index cca9594..851eed5 100644
--- a/data/sounds/effects/ogg/Unlock.ogg
+++ b/data/sounds/effects/ogg/Unlock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Unlock_48k.ogg b/data/sounds/effects/ogg/Unlock_48k.ogg
new file mode 100644
index 0000000..c2cf304
--- /dev/null
+++ b/data/sounds/effects/ogg/Unlock_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Ariel.ogg b/data/sounds/notifications/ogg/Ariel.ogg
new file mode 100644
index 0000000..6a11cbd
--- /dev/null
+++ b/data/sounds/notifications/ogg/Ariel.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Ariel_48k.ogg b/data/sounds/notifications/ogg/Ariel_48k.ogg
new file mode 100644
index 0000000..6a11cbd
--- /dev/null
+++ b/data/sounds/notifications/ogg/Ariel_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Carme.ogg b/data/sounds/notifications/ogg/Carme.ogg
new file mode 100644
index 0000000..afd358f
--- /dev/null
+++ b/data/sounds/notifications/ogg/Carme.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Carme_48k.ogg b/data/sounds/notifications/ogg/Carme_48k.ogg
new file mode 100644
index 0000000..1dd4b41
--- /dev/null
+++ b/data/sounds/notifications/ogg/Carme_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Ceres.ogg b/data/sounds/notifications/ogg/Ceres.ogg
new file mode 100644
index 0000000..fadbe84
--- /dev/null
+++ b/data/sounds/notifications/ogg/Ceres.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Ceres_48k.ogg b/data/sounds/notifications/ogg/Ceres_48k.ogg
new file mode 100644
index 0000000..134842d
--- /dev/null
+++ b/data/sounds/notifications/ogg/Ceres_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Elara.ogg b/data/sounds/notifications/ogg/Elara.ogg
new file mode 100644
index 0000000..c66c9f3
--- /dev/null
+++ b/data/sounds/notifications/ogg/Elara.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Elara_48k.ogg b/data/sounds/notifications/ogg/Elara_48k.ogg
new file mode 100644
index 0000000..80c6195
--- /dev/null
+++ b/data/sounds/notifications/ogg/Elara_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Europa.ogg b/data/sounds/notifications/ogg/Europa.ogg
new file mode 100644
index 0000000..07cc3d9
--- /dev/null
+++ b/data/sounds/notifications/ogg/Europa.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Europa_48k.ogg b/data/sounds/notifications/ogg/Europa_48k.ogg
new file mode 100644
index 0000000..bf27eb1
--- /dev/null
+++ b/data/sounds/notifications/ogg/Europa_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Iapetus.ogg b/data/sounds/notifications/ogg/Iapetus.ogg
new file mode 100644
index 0000000..d4062a8
--- /dev/null
+++ b/data/sounds/notifications/ogg/Iapetus.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Iapetus_48k.ogg b/data/sounds/notifications/ogg/Iapetus_48k.ogg
new file mode 100644
index 0000000..8115239
--- /dev/null
+++ b/data/sounds/notifications/ogg/Iapetus_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Io.ogg b/data/sounds/notifications/ogg/Io.ogg
new file mode 100644
index 0000000..2286d73
--- /dev/null
+++ b/data/sounds/notifications/ogg/Io.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Io_48k.ogg b/data/sounds/notifications/ogg/Io_48k.ogg
new file mode 100644
index 0000000..2286d73
--- /dev/null
+++ b/data/sounds/notifications/ogg/Io_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Rhea.ogg b/data/sounds/notifications/ogg/Rhea.ogg
new file mode 100644
index 0000000..039644f
--- /dev/null
+++ b/data/sounds/notifications/ogg/Rhea.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Rhea_48k.ogg b/data/sounds/notifications/ogg/Rhea_48k.ogg
new file mode 100644
index 0000000..32889f3
--- /dev/null
+++ b/data/sounds/notifications/ogg/Rhea_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Salacia.ogg b/data/sounds/notifications/ogg/Salacia.ogg
new file mode 100644
index 0000000..af07b01
--- /dev/null
+++ b/data/sounds/notifications/ogg/Salacia.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Salacia_48k.ogg b/data/sounds/notifications/ogg/Salacia_48k.ogg
new file mode 100644
index 0000000..3ef7b0b
--- /dev/null
+++ b/data/sounds/notifications/ogg/Salacia_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Tethys.ogg b/data/sounds/notifications/ogg/Tethys.ogg
new file mode 100644
index 0000000..25475d1
--- /dev/null
+++ b/data/sounds/notifications/ogg/Tethys.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Tethys_48k.ogg b/data/sounds/notifications/ogg/Tethys_48k.ogg
new file mode 100644
index 0000000..a9d8bbd
--- /dev/null
+++ b/data/sounds/notifications/ogg/Tethys_48k.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Titan.ogg b/data/sounds/notifications/ogg/Titan.ogg
new file mode 100644
index 0000000..8c10f58
--- /dev/null
+++ b/data/sounds/notifications/ogg/Titan.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Titan_48k.ogg b/data/sounds/notifications/ogg/Titan_48k.ogg
new file mode 100644
index 0000000..45ea524
--- /dev/null
+++ b/data/sounds/notifications/ogg/Titan_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Callisto.ogg b/data/sounds/ringtones/ogg/Callisto.ogg
new file mode 100644
index 0000000..9c982d8
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Callisto.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Callisto_48k.ogg b/data/sounds/ringtones/ogg/Callisto_48k.ogg
new file mode 100644
index 0000000..05ad67b
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Callisto_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Dione.ogg b/data/sounds/ringtones/ogg/Dione.ogg
new file mode 100644
index 0000000..a378520
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Dione.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Dione_48k.ogg b/data/sounds/ringtones/ogg/Dione_48k.ogg
new file mode 100644
index 0000000..a378520
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Dione_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Ganymede.ogg b/data/sounds/ringtones/ogg/Ganymede.ogg
new file mode 100644
index 0000000..01ff573
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Ganymede.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Ganymede_48k.ogg b/data/sounds/ringtones/ogg/Ganymede_48k.ogg
new file mode 100644
index 0000000..aed2e96
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Ganymede_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Luna.ogg b/data/sounds/ringtones/ogg/Luna.ogg
new file mode 100644
index 0000000..87a2463
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Luna.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Luna_48k.ogg b/data/sounds/ringtones/ogg/Luna_48k.ogg
new file mode 100644
index 0000000..c8a61aa
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Luna_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Oberon.ogg b/data/sounds/ringtones/ogg/Oberon.ogg
new file mode 100644
index 0000000..124af10
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Oberon.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Oberon_48k.ogg b/data/sounds/ringtones/ogg/Oberon_48k.ogg
new file mode 100644
index 0000000..ec2cb29
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Oberon_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Phobos.ogg b/data/sounds/ringtones/ogg/Phobos.ogg
new file mode 100644
index 0000000..768ca94
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Phobos.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Phobos_48k.ogg b/data/sounds/ringtones/ogg/Phobos_48k.ogg
new file mode 100644
index 0000000..f926cb0
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Phobos_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Sedna.ogg b/data/sounds/ringtones/ogg/Sedna.ogg
new file mode 100644
index 0000000..522faaf
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Sedna.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Sedna_48k.ogg b/data/sounds/ringtones/ogg/Sedna_48k.ogg
new file mode 100644
index 0000000..522faaf
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Sedna_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Titania.ogg b/data/sounds/ringtones/ogg/Titania.ogg
new file mode 100644
index 0000000..76cc0a5
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Titania.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Titania_48k.ogg b/data/sounds/ringtones/ogg/Titania_48k.ogg
new file mode 100644
index 0000000..4da6636
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Titania_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Triton.ogg b/data/sounds/ringtones/ogg/Triton.ogg
new file mode 100644
index 0000000..542ae16
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Triton.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Triton_48k.ogg b/data/sounds/ringtones/ogg/Triton_48k.ogg
new file mode 100644
index 0000000..0ae7383
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Triton_48k.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Umbriel.ogg b/data/sounds/ringtones/ogg/Umbriel.ogg
new file mode 100644
index 0000000..b21a12e
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Umbriel.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Umbriel_48k.ogg b/data/sounds/ringtones/ogg/Umbriel_48k.ogg
new file mode 100644
index 0000000..99ebcdd
--- /dev/null
+++ b/data/sounds/ringtones/ogg/Umbriel_48k.ogg
Binary files differ
diff --git a/data/videos/VideoPackage1.mk b/data/videos/VideoPackage1.mk
index 0089657..ee3b5ed 100644
--- a/data/videos/VideoPackage1.mk
+++ b/data/videos/VideoPackage1.mk
@@ -19,8 +19,8 @@
 LOCAL_PATH  := frameworks/base/data/videos
 TARGET_PATH := system/media/video
 
-PRODUCT_COPY_FILES += \
-        $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
-        $(LOCAL_PATH)/AndroidInSpace.480p.lq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
-        $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
-        $(LOCAL_PATH)/Sunset.480p.lq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
+#PRODUCT_COPY_FILES += \
+#        $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
+#        $(LOCAL_PATH)/AndroidInSpace.480p.lq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
+#        $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
+#        $(LOCAL_PATH)/Sunset.480p.lq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
diff --git a/data/videos/VideoPackage2.mk b/data/videos/VideoPackage2.mk
index b53fd9f..f799bea 100644
--- a/data/videos/VideoPackage2.mk
+++ b/data/videos/VideoPackage2.mk
@@ -19,8 +19,8 @@
 LOCAL_PATH  := frameworks/base/data/videos
 TARGET_PATH := system/media/video
 
-PRODUCT_COPY_FILES += \
-        $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
-        $(LOCAL_PATH)/AndroidInSpace.480p.mq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
-        $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
-        $(LOCAL_PATH)/Sunset.480p.mq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
+#PRODUCT_COPY_FILES += \
+#        $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
+#        $(LOCAL_PATH)/AndroidInSpace.480p.mq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
+#        $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
+#        $(LOCAL_PATH)/Sunset.480p.mq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
diff --git a/docs/downloads/design/Android_Design_Downloads_20130814.zip b/docs/downloads/design/Android_Design_Downloads_20130814.zip
new file mode 100644
index 0000000..bd29000
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Downloads_20130814.zip
Binary files differ
diff --git a/docs/downloads/design/roboto-1.100141.zip b/docs/downloads/design/roboto-1.100141.zip
new file mode 100644
index 0000000..93dfda7
--- /dev/null
+++ b/docs/downloads/design/roboto-1.100141.zip
Binary files differ
diff --git a/docs/downloads/training/AndroidTestingFun.zip b/docs/downloads/training/AndroidTestingFun.zip
new file mode 100644
index 0000000..dca5812
--- /dev/null
+++ b/docs/downloads/training/AndroidTestingFun.zip
Binary files differ
diff --git a/docs/downloads/training/LocationProvider.zip b/docs/downloads/training/LocationProvider.zip
new file mode 100644
index 0000000..d5ee311
--- /dev/null
+++ b/docs/downloads/training/LocationProvider.zip
Binary files differ
diff --git a/docs/downloads/training/Scheduler.zip b/docs/downloads/training/Scheduler.zip
new file mode 100644
index 0000000..81dfb5f
--- /dev/null
+++ b/docs/downloads/training/Scheduler.zip
Binary files differ
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 6e4a03c..1df2e22 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -30,16 +30,20 @@
 <p>This page provides information about the relative number of devices that share a certain
 characteristic, such as Android version or screen size. This information may
 help you prioritize efforts for <a
-href="{@docRoot}training/basics/supporting-devices/index.html">supporting different devices</a>.</p>
+href="{@docRoot}training/basics/supporting-devices/index.html">supporting different devices</a>
+by revealing which devices are active in the Android and Google Play ecosystem.</p>
 
-<p>Each snapshot of data represents all the devices that visited the Google Play Store in the
-prior 14 days.</p>
+<p>This data reflects devices running the latest Google Play Store app, which is compatible
+with Android 2.2 and higher. Each snapshot of data represents all the devices that visited the
+Google Play Store in the prior 7 days.</p>
 
-<p class="note"><strong>Note:</strong> Beginning in April, 2013, these charts are now built
-using data collected from each device when the user visits the Google Play Store. Previously, the
-data was collected when the device simply checked-in to Google servers. We believe the new
-data more accurately reflects those users who are most engaged in the Android and Google Play
-ecosystem.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Beginning in September, 2013, devices running versions older than Android
+2.2 do not appear in this data because those devices do not support the new Google Play Store
+app. Only the new app is able to measure the number of devices that actively visit Google Play Store
+and we believe this measurement best reflects your potential user-base.</p>
+</div>
 
 
 <h2 id="Platform">Platform Versions</h2>
@@ -57,10 +61,15 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 14-day period ending on August 1, 2013.
+<p style="clear:both"><em>Data collected during a 7-day period ending on October 2, 2013.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
+<p class="note"><strong>Note:</strong> Because this data is gathered from the new Google Play
+Store app, which supports Android 2.2 and above, devices running older versions are not included.
+However, in August, 2013, versions older than Android 2.2 accounted for about 1% of devices that
+<em>checked in</em> to Google servers (not those that actually visited Google Play Store).
+</p>
 
 
 
@@ -83,7 +92,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 14-day period ending on August 1, 2013
+<p style="clear:both"><em>Data collected during a 7-day period ending on October 2, 2013
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -130,7 +139,7 @@
 
 
 
-<p style="clear:both"><em>Data collected during a 14-day period ending on August 1, 2013</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on October 2, 2013</em></p>
 
 
 
@@ -148,32 +157,17 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chl=Eclair%7CFroyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean&chf=bg%2Cs%2C00000000&chd=t%3A1.3%2C2.5%2C33.1%2C0.1%2C22.5%2C40.5&chco=c4df9b%2C6fad0c",
+    "chart": "//chart.googleapis.com/chart?chs=500x250&cht=p&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A2.2%2C28.5%2C0.1%2C20.6%2C48.6&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean",
     "data": [
       {
-        "api": 4,
-        "name": "Donut",
-        "perc": "0.1"
-      },
-      {
-        "api": 7,
-        "name": "Eclair",
-        "perc": "1.2"
-      },
-      {
         "api": 8,
         "name": "Froyo",
-        "perc": "2.5"
-      },
-      {
-        "api": 9,
-        "name": "Gingerbread",
-        "perc": "0.1"
+        "perc": "2.2"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "33.0"
+        "perc": "28.5"
       },
       {
         "api": 13,
@@ -183,17 +177,22 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "22.5"
+        "perc": "20.6"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "34.0"
+        "perc": "36.5"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "6.5"
+        "perc": "10.6"
+      },
+      {
+        "api": 18,
+        "name": "Jelly Bean",
+        "perc": "1.5"
       }
     ]
   }
@@ -208,31 +207,30 @@
   {
     "data": {
       "Large": {
-        "hdpi": "0.4",
-        "ldpi": "0.5",
-        "mdpi": "3.2",
-        "tvdpi": "1.1",
-        "xhdpi": "0.5"
+        "hdpi": "0.5",
+        "ldpi": "0.6",
+        "mdpi": "3.5",
+        "tvdpi": "1.2",
+        "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "34.5",
+        "hdpi": "33.5",
         "ldpi": "0.1",
-        "mdpi": "15.9",
-        "xhdpi": "23.9",
-        "xxhdpi": "5.7"
+        "mdpi": "15.3",
+        "xhdpi": "22.8",
+        "xxhdpi": "7.7"
       },
       "Small": {
-        "hdpi": "0.1",
-        "ldpi": "9.7"
+        "ldpi": "9.4"
       },
       "Xlarge": {
-        "hdpi": "0.2",
-        "mdpi": "4.1",
+        "hdpi": "0.3",
+        "mdpi": "4.4",
         "xhdpi": "0.1"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A10.3%2C23.2%2C1.1%2C35.2%2C24.5%2C5.7&chco=c4df9b%2C6fad0c",
-    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A4.4%2C5.7%2C80.2%2C9.8&chco=c4df9b%2C6fad0c"
+    "densitychart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A10.1%2C23.3%2C1.2%2C34.3%2C23.5%2C7.7&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
+    "layoutchart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.8%2C6.4%2C79.5%2C9.4&chl=Xlarge%7CLarge%7CNormal%7CSmall"
   }
 ];
 
@@ -294,6 +292,11 @@
     "api":17,
     "link":"<a href='/about/versions/android-4.2.html'>4.2.x</a>",
     "codename":"Jelly Bean"
+  },
+  {
+    "api":18,
+    "link":"<a href='/about/versions/android-4.3.html'>4.3</a>",
+    "codename":"Jelly Bean"
   }
 ];
 
diff --git a/docs/html/about/index.jd b/docs/html/about/index.jd
index 1573cc3..215fc3c 100644
--- a/docs/html/about/index.jd
+++ b/docs/html/about/index.jd
@@ -53,7 +53,7 @@
 multitude of device form-factors, chipset architectures, and price points. From
 multicore processing and high-performance graphics to state-of-the-art sensors,
 vibrant touchscreens, and emerging mobile technologies such as Near Field
-Communication (NFC), Wi-Fi Direct, and face tracking.</p> -->
+Communication (NFC), Wi-Fi P2P, and face tracking.</p> -->
 
 <h3>Powerful development framework</h3>
 
diff --git a/docs/html/about/versions/android-4.0-highlights.jd b/docs/html/about/versions/android-4.0-highlights.jd
index 9fdb02c..f2b35ac 100644
--- a/docs/html/about/versions/android-4.0-highlights.jd
+++ b/docs/html/about/versions/android-4.0-highlights.jd
@@ -610,14 +610,17 @@
 unlock, or use a backup PIN or pattern. </p>
 
 
-<p style="margin-top:1em;margin-bottom:.75em;"><strong>Wi-Fi Direct and Bluetooth HDP</strong></p>
+<p style="margin-top:1em;margin-bottom:.75em;"><strong>Wi-Fi P2P and Bluetooth HDP</strong></p>
 
-<p>Support for <strong>Wi-Fi Direct</strong> lets users connect directly to
-nearby peer devices over Wi-Fi, for more reliable, higher-speed communication.
-No internet connection or tethering is needed. Through third-party apps, users
-can connect to compatible devices to take advantage of new features such as
-instant sharing of files, photos, or other media; streaming video or audio from
-another device; or connecting to compatible printers or other devices.</p>
+<p>Support for <strong>Wi-Fi peer-to-peer (P2P)</strong> lets users connect directly to nearby peer
+devices over Wi-Fi, for more reliable, higher-speed communication (in compliance with the Wi-Fi
+Alliance's <a href="http://www.wi-fi.org/discover-and-learn/wi-fi-direct"
+ class="external-link">Wi-Fi Direct&trade;</a>
+certification program). No internet connection or tethering is needed. Through third-party apps,
+users can connect to compatible devices to take advantage of new features such as instant sharing
+of files, photos, or other media; streaming video or audio from another device; or connecting to
+compatible printers or other devices.</p>
+
 
 <p>Android 4.0 also introduces built-in support for connecting to <strong>Bluetooth Health Device Profile (HDP)</strong> devices. With support from third-party apps, users can connect to wireless medical devices and sensors in hospitals, fitness centers, homes, and elsewhere.</p>
 
@@ -868,16 +871,19 @@
 
 <h3 id="connectivity-dev">New types of connectivity</h3>
 
-<p style="margin-top:1em;margin-bottom:.75em;"><strong>Wi-Fi Direct</strong></p>
+<p style="margin-top:1em;margin-bottom:.75em;"><strong>Wi-Fi P2P</strong></p>
 
-<p>Developers can use a framework API to discover and connect directly to nearby
-devices over a high-performance, secure Wi-Fi Direct connection. No internet
-connection or hotspot is needed.</p>
+<p>Developers can use a framework API to discover and connect directly to nearby devices over a
+high-performance, secure Wi-Fi peer-to-peer (P2P) connection. No internet connection or hotspot is
+needed. Android's Wi-Fi P2P framework complies with the Wi-Fi Alliance's <a href=
+"http://www.wi-fi.org/discover-and-learn/wi-fi-direct" class="external-link">Wi-Fi Direct&trade;</a>
+certification program.</p>
 
-<p>Wi-Fi Direct opens new opportunities for developers to add innovative
-features to their applications. Applications can use Wi-Fi Direct to share
+
+<p>Wi-Fi peer-to-peer (P2P) opens new opportunities for developers to add innovative
+features to their applications. Applications can use Wi-Fi P2P to share
 files, photos, or other media between devices or between a desktop computer and
-an Android-powered device. Applications could also use Wi-Fi Direct to stream
+an Android-powered device. Applications could also use Wi-Fi P2P to stream
 media content from a peer device such as a digital television or audio player,
 connect a group of users for gaming, print files, and more.</p>
 
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index 2fa180c..6c4ccb4 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -62,7 +62,7 @@
       <li><a href="#Multimedia">Multimedia</a></li>
       <li><a href="#Camera">Camera</a></li>
       <li><a href="#AndroidBeam">Android Beam (NDEF Push with NFC)</a></li>
-      <li><a href="#WiFiDirect">Wi-Fi Direct</a></li>
+      <li><a href="#WiFiDirect">Wi-Fi P2P</a></li>
       <li><a href="#Bluetooth">Bluetooth Health Devices</a></li>
       <li><a href="#A11y">Accessibility</a></li>
       <li><a href="#SpellChecker">Spell Checker Services</a></li>
@@ -617,13 +617,16 @@
 
 
 
-<h3 id="WiFiDirect">Wi-Fi Direct</h3>
+<h3 id="WiFiDirect">Wi-Fi P2P</h3>
 
-<p>Android now supports Wi-Fi Direct for peer-to-peer (P2P) connections between Android-powered
-devices and other device types without a hotspot or Internet connection. The Android framework
-provides a set of Wi-Fi P2P APIs that allow you to discover and connect to other devices when each
-device supports Wi-Fi Direct, then communicate over a speedy connection across distances much longer
-than a Bluetooth connection.</p>
+<p>Android now supports Wi-Fi peer-to-peer (P2P) connections between Android-powered devices and
+other device types (in compliance with the Wi-Fi Alliance's <a href=
+"http://www.wi-fi.org/discover-and-learn/wi-fi-direct" class="external-link">Wi-Fi Direct&trade;</a>
+certification program) without a hotspot or Internet connection. The Android framework provides a
+set of Wi-Fi P2P APIs that allow you to discover and connect to other devices when each device
+supports Wi-Fi P2P, then communicate over a speedy connection across distances much longer than a
+Bluetooth connection.</p>
+
 
 <p>A new package, {@link android.net.wifi.p2p}, contains all the APIs for performing peer-to-peer
 connections with Wi-Fi. The primary class you need to work with is {@link
@@ -669,7 +672,7 @@
 <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
 <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
 <li>{@link android.Manifest.permission#INTERNET} (although your app doesn’t technically connect
-to the Internet, communicating to Wi-Fi Direct peers with standard java sockets requires Internet
+to the Internet, communicating to Wi-Fi P2P peers with standard java sockets requires Internet
 permission).</li>
 </ul>
 
@@ -696,7 +699,7 @@
 </ul>
 
 <p>See the  {@link android.net.wifi.p2p.WifiP2pManager} documentation for more information. Also
-look at the <a href="{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi Direct Demo</a>
+look at the <a href="{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi P2P Demo</a>
 sample application.</p>
 
 
diff --git a/docs/html/about/versions/android-4.1.jd b/docs/html/about/versions/android-4.1.jd
index d4b9ebf..76b90ac 100644
--- a/docs/html/about/versions/android-4.1.jd
+++ b/docs/html/about/versions/android-4.1.jd
@@ -41,7 +41,7 @@
     <ol>
       <li><a href="#AndroidBeam">Android Beam</a></li>
       <li><a href="#LocalNsd">Network service discovery</a></li>
-      <li><a href="#WiFiNsd">Wi-Fi Direct service discovery</a></li>
+      <li><a href="#WiFiNsd">Wi-Fi P2P service discovery</a></li>
       <li><a href="#NetworkUsage">Network usage</a></li>
     </ol>
   </li>
@@ -506,11 +506,11 @@
 
 
 
-<h3 id="WiFiNsd">Wi-Fi Direct service discovery</h3>
+<h3 id="WiFiNsd">Wi-Fi P2P service discovery</h3>
 
-<p>The Wi-Fi Direct APIs are enhanced in Android 4.1 to support pre-association service discovery in
+<p>The Wi-Fi P2P APIs are enhanced in Android 4.1 to support pre-association service discovery in
 the {@link android.net.wifi.p2p.WifiP2pManager}. This allows you to discover and filter nearby
-devices by services using Wi-Fi Direct before connecting to one, while Network Service
+devices by services using Wi-Fi P2P before connecting to one, while Network Service
 Discovery allows you to discover a service on an existing connected network (such as a local Wi-Fi
 network).</p>
 
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index 5deb190..c7d1941 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -860,13 +860,13 @@
 
 <h3 id="42-wireless-display">Wireless display</h3>
 
-<p>Starting in Android 4.2, users on supported devices can connect to an
-external display over Wi-Fi, using <a
-href="http://www.wi-fi.org/wi-fi-certified-miracast%E2%84%A2">Miracast</a>, a
-peer-to-peer wireless display standard created by the <a
-href="http://www.wi-fi.org/">Wi-Fi Alliance</a>. When a wireless display is
-connected, users can stream any type of content to the big screen, including
-photos, games, maps, and more.</p>
+<p>Starting in Android 4.2, users on supported devices can connect to an external display over
+Wi-Fi, using Wi-Fi Display (a peer-to-peer wireless display solution that complies with the
+<a href="http://www.wi-fi.org/wi-fi-certified-miracast%E2%84%A2"
+ class="external-link">Miracast&trade;</a> certification
+program). When a wireless display is connected, users can stream any type of content to the big
+screen, including photos, games, maps, and more.</p>
+
 
 <p>Apps can take advantage of <strong>wireless displays</strong> in the same way as they do other
 external displays and no extra work is needed. The system manages the network
@@ -1455,15 +1455,22 @@
 
 <p>You can take advantage of this API to build new features into your apps. For example, you could let users connect to a webcam, a printer, or an app on another mobile device that supports Wi-Fi peer-to-peer connections.  </p>
 
-<h3>Wi-Fi Direct Service Discovery</h3>
+<h3>Wi-Fi P2P Service Discovery</h3>
 
-<p>Ice Cream Sandwich introduced support for Wi-Fi Direct, a technology that lets apps <strong>discover and pair directly</strong>, over a high-bandwidth peer-to-peer connection. Wi-Fi Direct is an ideal way to share media, photos, files and other types of data and sessions, even where there is no cell network or Wi-Fi available.</p>
+<p><a href="{@docRoot}about/versions/android-4.0-highlights.html">Ice Cream Sandwich</a> introduced
+support for Wi-Fi Peer-to-Peer (P2P), a technology that lets apps <strong>discover and pair
+directly</strong>, over a high-bandwidth peer-to-peer connection (in compliance with the Wi-Fi
+Alliance's <a href="http://www.wi-fi.org/discover-and-learn/wi-fi-direct"
+ class="external-link">Wi-Fi Direct&trade;</a>
+certification program). Wi-Fi P2P is an ideal way to share media, photos, files and other types of
+data and sessions, even where there is no cell network or Wi-Fi available.</p>
 
-<p>Android 4.1 takes Wi-Fi Direct further, adding API support for <strong>pre-associated service discovery</strong>. Pre-associated service discovery lets your apps get more useful information from nearby devices about the services they support, before they attempt to connect.  Apps can initiate discovery for a specific service and filter the list of discovered devices to those that actually support the target service or application.</p>
 
-<p>For example, this means that your app could discover only devices that are “printers” or that have a specific game available, instead of discovering all nearby Wi-Fi Direct devices. On the other hand, your app can advertise the service it provides to other devices, which can discover it and then negotiate a connection. This greatly simplifies discovery and pairing for users and lets apps take advantage of Wi-Fi Direct more effectively.</p>
+<p>Android 4.1 takes Wi-Fi P2P further, adding API support for <strong>pre-associated service discovery</strong>. Pre-associated service discovery lets your apps get more useful information from nearby devices about the services they support, before they attempt to connect.  Apps can initiate discovery for a specific service and filter the list of discovered devices to those that actually support the target service or application.</p>
 
-<p>With Wi-Fi Direct service discovery, you can create apps and <strong>multiplayer games</strong> that can share photos, videos, gameplay, scores, or almost anything else &mdash; all without requiring any Internet or mobile network. Your users can connect using only a direct p2p connection, which avoids using mobile bandwidth.</p>
+<p>For example, this means that your app could discover only devices that are “printers” or that have a specific game available, instead of discovering all nearby Wi-Fi P2P devices. On the other hand, your app can advertise the service it provides to other devices, which can discover it and then negotiate a connection. This greatly simplifies discovery and pairing for users and lets apps take advantage of Wi-Fi P2P more effectively.</p>
+
+<p>With Wi-Fi P2P service discovery, you can create apps and <strong>multiplayer games</strong> that can share photos, videos, gameplay, scores, or almost anything else &mdash; all without requiring any Internet or mobile network. Your users can connect using only a direct p2p connection, which avoids using mobile bandwidth.</p>
 
 <h3>Network Bandwidth Management</h3>
 
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index 00f4467..5d179a6 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -4,8 +4,10 @@
 <div class="layout-content-row">
   <div class="layout-content-col span-9">
 
-<p>Want everything? We've bundled all the downloads available on Android Design into a single ZIP file.
-You can also download individual files listed below.</p>
+<p>Want everything? We've bundled all the downloads available on Android Design, except for the
+  <a href="#roboto">Roboto</a> font family, into a single ZIP file. You can also download
+  individual files listed below.</p>
+
 <p>You may use these materials without restriction in your apps and to develop your apps.</p>
 
   </div>
@@ -13,7 +15,7 @@
 
 <p>
   <a class="download-button" onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'All Design Assets']);"
-    href="{@docRoot}downloads/design/Android_Design_Downloads_20120823.zip">Download All</a>
+    href="{@docRoot}downloads/design/Android_Design_Downloads_20130814.zip">Download All</a>
 </p>
 
   </div>
@@ -72,7 +74,7 @@
 
 <p>
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Action Bar Icons']);"
-    href="{@docRoot}downloads/design/Android_Design_Icons_20120814.zip">Action Bar Icon Pack</a>
+    href="{@docRoot}downloads/design/Android_Design_Icons_20130926.zip">Action Bar Icon Pack</a>
 </p>
 
   </div>
@@ -83,10 +85,12 @@
 <div class="layout-content-row">
   <div class="layout-content-col span-5">
 
-<h4>Roboto</h4>
+<h4 id="roboto">Roboto</h4>
 <p>Ice Cream Sandwich introduced a new type family named Roboto, created specifically for the
 requirements of UI and high-resolution screens.</p>
-<p><a href="{@docRoot}design/style/typography.html#actionbar">More on Roboto</a></p>
+<p><a href="{@docRoot}design/style/typography.html">More on Roboto</a></p>
+<p><a href="http://www.google.com/fonts/specimen/Roboto" class="external-link">Roboto on Google Fonts</a></p>
+<p><a href="http://www.google.com/fonts/specimen/Roboto+Condensed" class="external-link">Roboto Condensed on Google Fonts</a></p>
 
   </div>
   <div class="layout-content-col span-4">
@@ -98,7 +102,7 @@
 
 <p>
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto ZIP']);"
-    href="{@docRoot}downloads/design/Roboto_Hinted_20120823.zip">Roboto</a>
+    href="{@docRoot}downloads/design/roboto-1.100141.zip">Roboto</a>
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto Specemin Book']);"
     href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a>
 </p>
diff --git a/docs/html/design/media/typography_alphas.png b/docs/html/design/media/typography_alphas.png
deleted file mode 100644
index 4b53bd0..0000000
--- a/docs/html/design/media/typography_alphas.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/design/media/typography_variants.png b/docs/html/design/media/typography_variants.png
new file mode 100644
index 0000000..9b49b20
--- /dev/null
+++ b/docs/html/design/media/typography_variants.png
Binary files differ
diff --git a/docs/html/design/media/typography_variants@2x.png b/docs/html/design/media/typography_variants@2x.png
new file mode 100644
index 0000000..13e7c4f
--- /dev/null
+++ b/docs/html/design/media/typography_variants@2x.png
Binary files differ
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index ceb5a4c..2c59149 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -182,7 +182,7 @@
 <p>
 
 <a onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Action Bar Icons (@actionbar page)']);"
-   href="{@docRoot}downloads/design/Android_Design_Icons_20120814.zip">Download the Action Bar Icon Pack</a>
+   href="{@docRoot}downloads/design/Android_Design_Icons_20130926.zip">Download the Action Bar Icon Pack</a>
 
 </p>
 
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index 0d2cdbb..0ce2faf 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -139,7 +139,7 @@
 </p>
 <p>
 <a onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Action Bar Icons (@iconography page)']);"
-   href="{@docRoot}downloads/design/Android_Design_Icons_20120814.zip">Download the Action Bar Icon Pack</a>
+   href="{@docRoot}downloads/design/Android_Design_Icons_20130926.zip">Download the Action Bar Icon Pack</a>
 </p>
 
 <div class="layout-content-row">
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index 114d13b..818af4c 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -10,17 +10,25 @@
   </div>
   <div class="layout-content-col span-5">
 
+<p>
+  <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto ZIP']);"
+    href="{@docRoot}downloads/design/roboto-1.100141.zip">Download Roboto</a>
+</p>
+
 <p>The Android design language relies on traditional typographic tools such as scale, space, rhythm,
 and alignment with an underlying grid. Successful deployment of these tools is essential to help
 users quickly understand a screen of information. To support such use of typography, Ice Cream
-Sandwich introduced a new type family named Roboto, created specifically for the requirements of UI
-and high-resolution screens. The current TextView framework supports regular, bold, italic, and bold
-italic weights by default.</p>
+Sandwich introduced a new type family named
+<a href="http://www.google.com/fonts/specimen/Roboto" class="external-link">Roboto</a>, created
+specifically for the requirements of UI and high-resolution screens.</p>
 
-    <img src="{@docRoot}design/media/typography_alphas.png">
+<p>The current {@link android.widget.TextView} framework offers Roboto in thin, light, regular and bold
+weights, along with an italic style for each weight. The framework also offers the
+<a href="http://www.google.com/fonts/specimen/Roboto+Condensed" class="external-link">Roboto Condensed</a>
+variant in regular and bold weights, along with an italic style for each weight.</p>
 
-<p><a onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto ZIP (@typography page)']);"
-      href="{@docRoot}downloads/design/Roboto_Hinted_20120823.zip">Download Roboto</a></p>
+    <img src="{@docRoot}design/media/typography_variants@2x.png" width="220">
+
 <p><a onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto Specimen Booke (@typography page)']);"
       href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a></p>
 
diff --git a/docs/html/distribute/googleplay/policies/ads.jd b/docs/html/distribute/googleplay/policies/ads.jd
index 8920499..f2fb0f8 100644
--- a/docs/html/distribute/googleplay/policies/ads.jd
+++ b/docs/html/distribute/googleplay/policies/ads.jd
@@ -9,8 +9,8 @@
     <li><a href="#context">Context and Behavior</a></li>
     <li><a href="#disclosure" style="clear:right">Disclosure</a></li>
     <li><a href="#impersonation">Impersonation of System UI</a></li>
-    <li><a href="#adwalls">Adwalls</a></li>
-    <li><a href="#interfering" style="clear:right;">Interference with Ads and Websites</a></li>
+    <li><a href="#adwalls">Adwalls and Interstitial Ads</a></li>
+    <li><a href="#interfering" style="clear:right;">Interference with Apps and Third-Party Ads</a></li>
   </ol>
 
   <h2>More Resources</h2>
@@ -130,22 +130,20 @@
   </li>
 
   <li>
-    <strong>Make sure app origin is clear</strong>&mdash;When you display an
-    ad, it must be clear to the user that the ad has originated from your app.
-    If you show the ad in your app's UI while your app has focus, the user
-    understands the ad origin without explicit attribution. However, if you
-    display the ad outside of your app, such as in a notification, you must
-    explicitly indicate the origin.
-  </li>
-
-  <li>
     <strong>Don't make changes outside of the app without consent</strong>
    &mdash;Ads must not make changes outside of the app without the user's
-    full knowledge and consent. For example, ads should not install shortcuts,
-    bookmarks, or icons, or change default settings without user consent.
+    full knowledge and consent.
   </li>
 
   <li>
+  <div class="example-block bad" style="width:360px;margin:1em 0 0 2em;">
+    <div class="heading">Ads through system-level notifications</div>
+    <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
+  </div>
+  <div class="example-block good" style="width:360px;margin:.5em 0 0 2em;">
+    <div class="heading">Notification that's part of the app's feature set</div>
+    <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
+  </div>
     <strong>Changes outside the app must be reversible</strong>&mdash;If an
     ad makes changes outside the app as described above, the changes (and
     origin app) must be evident and easily reversible. For example, the user
@@ -154,51 +152,31 @@
   </li>
 
   <li>
-    <strong>Notification ads require user opt-in</strong>&mdash;Your app
-    should not create <a href=
+    <strong>Notification ads are prohibited</strong>&mdash;Your app
+    should not create system-level <a href=
     "{@docRoot}design/patterns/notifications.html">notifications</a>
-    containing ads unless the user has specifically opted-in to this behavior
-    and is able to easily opt-out.
+    containing ads unless the notifications are part of the explicit
+    feature set of the app.
   </li>
 
   <li>
-    <strong>Use low priority for notification ads</strong>&mdash;Always
-    assign your notification ads <a href="
-    {@docRoot}reference/android/app/Notification.html#PRIORITY_LOW">low
-    priority</a> (for API level 16 and above).
+    <strong>Don't add shortcuts, bookmarks, or icons</strong>&mdash;Your app
+    and its ads must not add homescreen shortcuts, browser bookmarks, or icons
+    on the user's device as a service to third parties or for advertising 
+    purposes.
   </li>
 </ul>
 
-<div class="example-block bad" style="width:400px;margin:.5em 0 0 2em;">
-    <div class="heading">Does not fully indicate origin app</div>
-    <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
-</div>
-<div class="example-block good" style="width:400px;margin:.5em 0 0 2em;">
-    <div class="heading">Indicates origin app by name and icon</div>
-    <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
-</div>
-
 <p>
-  In particular, note that notification ads must clearly identify your app as
-  the ad origin. If your app sends notification ads that do not sufficiently
-  identify your app as the origin, the app will be in violation of policy.
+  Above right is an example notification ad that violates ad policy by
+  providing ads through system level notification.
 </p>
-
 <p>
-  To identify your app as the origin, you should display the <strong>app's full
-  name and and icon</strong> in the notification to provide the clearest
-  identification and best policy compliance. Displaying a partial app name can
-  also be sufficient, provided the name unambiguously identifies your app.
+  Below right, the notification ad complies with policy because the
+  nature of the notification is part of the explicit feature set of the app,
+  and it also provides attribution of the origin app. 
 </p>
 
-<p>
-  Above right is an example notification ad that violates ad policy by not
-  providing attribution of the origin app. Below right, the notification ads
-  comply with policy by providing both the app icon and full app name (in this
-  case, "Turtle Test").
-</p>
-
-
 <h2 id="disclosure" style="clear:right">Disclosure of Ads to Users</h2>
 
 <p>
@@ -218,6 +196,14 @@
   </li>
 
   <li>
+    <div class="example-block good" style="width:213px;margin-left:.5em;">
+      <div class="heading">Disclosure in Terms</div>
+      <img src="{@docRoot}images/gp-policy-ads-terms.png">
+    </div>
+    <div class="example-block bad" style="width:213px;">
+      <div class="heading">Disclosure is hidden</div>
+      <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
+    </div>
     <strong>Make sure users know</strong>&mdash;Present your ads disclosure
     is an easy-to-see location, rather than hiding it where users are not
     likely to find it.
@@ -240,53 +226,40 @@
 </p>
 
 <p>
-  If your app adds homescreen icons and/or browser bookmarks, an acceptable
-  practice for revealing that behavior is to provide a disclosure in both the
-  app description and an opt-in EULA on app launch. This ensures that the
-  behaviors are clearly explained to the user up-front and requires the user’s
-  consent in a pop-up EULA to continue using the app.
-</p>
-
-<div class="example-block good" style="width:213px;margin-right:2em;">
-  <div class="heading">Disclosure in Terms</div>
-  <img src="{@docRoot}images/gp-policy-ads-terms.png">
-</div>
-
-<div class="example-block good" style="width:213px;">
-  <div class="heading">Disclosure in EULA</div>
-  <img src="{@docRoot}images/gp-policy-ads-eula.png">
-</div>
-
-<div class="example-block bad" style="width:213px;margin-left:0em;">
-  <div class="heading">Disclosure is hidden</div>
-  <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
-</div>
-
-<p style="clear:right">
   Above left is an example of ads disclosure that is hidden in a long EULA. The
   disclosure information itself is not clearly indicated in the document text
   and it's not visible unless the user happens to scroll down far enough in the
-  EULA. Above middle and right show two alternative approaches that
-  present the disclosure in an obvious and clear manner at the top of a
-  EULA and in a dedicated Terms agreement. 
+  EULA. 
+</p>
+<p>
+  Above right shows an approach that presents the disclosure in an obvious
+  and clear manner in a EULA and a dedicated Terms agreement. 
 </p>
 
 
 <h2 id="impersonation">Impersonation of System UI</h2>
 
-<div class="example-block bad">
-  <div class="heading">Ad impersonates system dialog</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
-</div>
+
+
+
+
+
+
 
 <p>
-  Your app must not display any ad that attempts to impersonate or represent a
+  Ads must not simulate or impersonate the user interface of any app, or
+  notification and warning elements of an operating system. Your app must not
+  display any ad that attempts to impersonate or represent a
   system function or UI component. If such an ad is displayed in your app, your
   app will be in violation of policy and subject to suspension. Here are some
   guidelines:
 </p>
 
-<ul>
+<ul>  
+  <li>
+    <strong>No fake app UI notifications</strong>&mdash;Ads should not impersonate
+    the interface of an application for advertising purposes.
+  </li>
   <li>
     <strong>No fake system dialogs or warnings</strong>&mdash;Any ad that
     presents itself as a system dialog or warning and asks for user input is in
@@ -299,23 +272,26 @@
   </li>
 </ul>
 
-<p>
-  At right is an example of a pop-up ad impersonating a system dialog, warning
-  the user about viruses. This is a violation of policy.
+<div class="example-block bad" style="width:213px;">
+  <div class="heading">Ad impersonates app UI</div>
+  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-app-ui.png">
+</div>
+<div class="example-block bad" style="width:213px;">
+  <div class="heading">Ad impersonates system warning</div>
+  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-sys-warning.png">
+</div>
+<div class="example-block bad" style="width:213px;">
+  <div class="heading">Ad impersonates system dialog</div>
+  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
+</div>
+<p style="clear:both">
+  Above are examples of impersonations &mdash; a pop-up ad that impersonates a
+  system dialog, an ad that impersonates a system warning, and an ad that impersonates
+  an application UI. All of these are in violation of policy.
 </p>
 
 
-<h2 id="adwalls">Adwalls</h2>
-
-<div class="example-block good" style="width:213px;">
-  <div class="heading">Adwall lets user cancel</div>
-  <img src="{@docRoot}images/gp-policy-ads-paywall.png">
-</div>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Adwall forces user action</div>
-  <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
-</div>
+<h2 id="adwalls">Adwalls and Interstitial Ads</h2>
 
 <p>
   If your app uses adwalls to drive affiliate traffic, those adwalls must not
@@ -330,23 +306,45 @@
 
 <p>
   For this reason, <strong>all adwalls must give the user the option to
-  cancel</strong> or otherwise dismiss the ad without penalty.
+  cancel</strong> or otherwise dismiss the ad without penalty. Interstitial ads
+  may only be displayed inside of the app they came with. Forcing the user to
+  click on ads or submit personal information for advertising purposes in order
+  to fully use an app is prohibited.
 </p>
 
-<p>
-  At right is an example of an app that requires the user to click through the
+<div class="example-block bad" style="width:213px;">
+  <div class="heading">Interstitial, modal ad</div>
+  <img src="{@docRoot}images/gp-policy-ads-interstitial-violation.png">
+</div>
+
+<div class="example-block good" style="width:213px;">
+  <div class="heading">Adwall lets user cancel</div>
+  <img src="{@docRoot}images/gp-policy-ads-paywall.png">
+</div>
+
+<div class="example-block bad" style="width:213px;">
+  <div class="heading">Adwall forces user action</div>
+  <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
+</div>
+
+<p style="clear:both">
+  At left is an example of an app that requires the user to click through the
   ad to fully use the app. This is a violation of policy.
 </p>
 
 <p>
-  The adjacent example demonstrates an adequate option to let the user dismiss
-  the ad wall easily by cancelling.
+  The center example demonstrates an adequate option to let the user dismiss
+  the ad wall easily by cancelling. This is not a violation of policy.
 </p>
 
+<p>
+  At right is an example of an interstitial, modal ad that is displayed outside
+  of the app. This is a violation of policy.
+</p>
 
-<h2 id="interfering" style="clear:right;">Interference with Third-party Ads and Websites</h2>
+<h2 id="interfering" style="clear:right;">Interfering with Apps and Third-Party Ads</h2>
 
 <p>
-  Ads associated with your app <strong>must not interfere</strong> with any
-  other ads originating in other applications.
+  Ads associated with your app <strong>must not interfere</strong> with other
+  apps or their ads.
 </p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/spam.jd b/docs/html/distribute/googleplay/policies/spam.jd
index 602c89a..f4d303c 100644
--- a/docs/html/distribute/googleplay/policies/spam.jd
+++ b/docs/html/distribute/googleplay/policies/spam.jd
@@ -251,6 +251,11 @@
 
 <h2 id="ratings">Spam in Ratings and Reviews</h2>
 
+<div class="example-block bad" style="width:440px;">
+  <div class="heading">Inappropriate content in a review</div>
+  <img src="{@docRoot}images/gp-policy-spam-negreview.png">
+</div>
+
 <p>
   Ratings and reviews are benchmarks of app quality and users depend on them to
   be authentic and relevant. As an app developer, you should not attempt to
@@ -276,12 +281,7 @@
   more information.
 </p>
 
-<div class="example-block bad" style="width:440px;">
-  <div class="heading">Inappropriate content in a review</div>
-  <img src="{@docRoot}images/gp-policy-spam-negreview.png">
-</div>
-
-<div class="example-block bad" style="margin-top:3em;">
+<div class="example-block bad" style="margin-top:3em;width:213px;">
   <div class="heading">Soliciting ratings</div>
   <img src="{@docRoot}images/gp-policy-spam-reqrating.png">
 </div>
diff --git a/docs/html/distribute/googleplay/promote/brand.jd b/docs/html/distribute/googleplay/promote/brand.jd
index 265584f..0bda561 100644
--- a/docs/html/distribute/googleplay/promote/brand.jd
+++ b/docs/html/distribute/googleplay/promote/brand.jd
@@ -21,8 +21,8 @@
     <ul>
     <li>Android&trade; should have a trademark symbol the first time it appears in a creative.</li>
     <li>Android should always be capitalized and is never plural or possessive.</li>
-    <li>"Android" by itself cannot be used in the name of an application name or accessory product.
-Instead use "for Android."
+    <li>"Android" cannot be used in names of applications or accessory products,
+    including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
       <ul>
         <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
         <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
diff --git a/docs/html/gms_navtree_data.js b/docs/html/gms_navtree_data.js
index 777773f..a4f7df3 100644
--- a/docs/html/gms_navtree_data.js
+++ b/docs/html/gms_navtree_data.js
@@ -47,8 +47,8 @@
 , null ], [ "com.google.android.gms.panorama", "reference/com/google/android/gms/panorama/package-summary.html", [ [ "Interfaces", null, [ [ "PanoramaClient.OnPanoramaInfoLoadedListener", "reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html", null, null ] ]
 , null ], [ "Classes", null, [ [ "PanoramaClient", "reference/com/google/android/gms/panorama/PanoramaClient.html", null, null ] ]
 , null ] ]
-, null ], [ "com.google.android.gms.plus", "reference/com/google/android/gms/plus/package-summary.html", [ [ "Interfaces", null, [ [ "PlusClient.OnAccessRevokedListener", "reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html", null, null ], [ "PlusClient.OnMomentsLoadedListener", "reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html", null, null ], [ "PlusClient.OnPeopleLoadedListener", "reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html", null, null ], [ "PlusClient.OnPersonLoadedListener", "reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html", null, null ], [ "PlusClient.OrderBy", "reference/com/google/android/gms/plus/PlusClient.OrderBy.html", null, null ], [ "PlusOneButton.OnPlusOneClickListener", "reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html", null, null ] ]
-, null ], [ "Classes", null, [ [ "PlusClient", "reference/com/google/android/gms/plus/PlusClient.html", null, null ], [ "PlusClient.Builder", "reference/com/google/android/gms/plus/PlusClient.Builder.html", null, null ], [ "PlusOneButton", "reference/com/google/android/gms/plus/PlusOneButton.html", null, null ], [ "PlusShare", "reference/com/google/android/gms/plus/PlusShare.html", null, null ], [ "PlusShare.Builder", "reference/com/google/android/gms/plus/PlusShare.Builder.html", null, null ] ]
+, null ], [ "com.google.android.gms.plus", "reference/com/google/android/gms/plus/package-summary.html", [ [ "Interfaces", null, [ [ "PlusClient.OnAccessRevokedListener", "reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html", null, null ], [ "PlusClient.OnMomentsLoadedListener", "reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html", null, null ], [ "PlusClient.OnPeopleLoadedListener", "reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html", null, null ], [ "PlusClient.OrderBy", "reference/com/google/android/gms/plus/PlusClient.OrderBy.html", null, null ], [ "PlusOneButton.OnPlusOneClickListener", "reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html", null, null ] ]
+, null ], [ "Classes", null, [ [ "PlusClient", "reference/com/google/android/gms/plus/PlusClient.html", null, null ], [ "PlusClient.Builder", "reference/com/google/android/gms/plus/PlusClient.Builder.html", null, null ], [ "PlusOneButton", "reference/com/google/android/gms/plus/PlusOneButton.html", null, null ], [ "PlusOneButton.DefaultOnPlusOneClickListener", "reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html", null, null ], [ "PlusOneButtonWithPopup", "reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html", null, null ], [ "PlusOneDummyView", "reference/com/google/android/gms/plus/PlusOneDummyView.html", null, null ], [ "PlusShare", "reference/com/google/android/gms/plus/PlusShare.html", null, null ], [ "PlusShare.Builder", "reference/com/google/android/gms/plus/PlusShare.Builder.html", null, null ] ]
 , null ] ]
 , null ], [ "com.google.android.gms.plus.model.moments", "reference/com/google/android/gms/plus/model/moments/package-summary.html", [ [ "Interfaces", null, [ [ "ItemScope", "reference/com/google/android/gms/plus/model/moments/ItemScope.html", null, null ], [ "Moment", "reference/com/google/android/gms/plus/model/moments/Moment.html", null, null ] ]
 , null ], [ "Classes", null, [ [ "ItemScope.Builder", "reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html", null, null ], [ "Moment.Builder", "reference/com/google/android/gms/plus/model/moments/Moment.Builder.html", null, null ], [ "MomentBuffer", "reference/com/google/android/gms/plus/model/moments/MomentBuffer.html", null, null ] ]
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 9c5961c..0cadbd2 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -29,7 +29,7 @@
 <h2>See Also</h2>
 
 <ol class="toc">
-<li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
+<li><a href="{@docRoot}google/play-services/gcm/gs.html">Getting Started</a></li>
 <li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
 </ol>
 
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index 4020cf4..ce30bce 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -39,6 +39,7 @@
 
 
 
+
 <div style="margin-top:10px">
 <div class="col-6 normal-links" style="margin-left:0">
 
@@ -48,7 +49,7 @@
   </div>
     <h4><a href="{@docRoot}google/play-services/maps.html"
     >Google Maps</a></h4>
-    <p>The power of Google Maps is available to your app
+    <p>Include the power of Google Maps in your app
     with an embeddable map view. You can customize the map with
     markers and overlays, control the user's perspective, draw lines
     and shapes, and much more.</p>
@@ -68,6 +69,17 @@
 
 <div class="landing-cell">
   <div class="cell-icon">
+  <img src="{@docRoot}images/google/cloud-platform.png" width="40" >
+  </div>
+    <h4><a class="external-link" href="https://cloud.google.com/solutions/mobile"
+    >Google Cloud Platform</a></h4>
+    <p>Build and host the backend for your Android app at Google-scale. With an infrastructure
+    that is managed automatically, you can focus on your app. Then, scale to support
+    millions of users.</p>
+</div>
+
+<div class="landing-cell">
+  <div class="cell-icon">
   <img src="{@docRoot}images/google/gcm-cloud.png" width="40" >
   </div>
     <h4><a href="{@docRoot}google/gcm/index.html"
@@ -98,6 +110,18 @@
 
 <div class="landing-cell">
   <div class="cell-icon">
+    <img src="{@docRoot}images/google/wallet.png" width="40" />
+  </div>
+    <h4><a class="external-link" href="https://developers.google.com/commerce/wallet/instant-buy/"
+    >Google Wallet Instant Buy</a></h4>
+    <p>Provide fast and easy checkout in your app when selling physical goods and services.
+    Increase conversions by streamlining your purchase flow and reducing the amount of
+    information your customers need to enter.
+    </p>
+</div>
+
+<div class="landing-cell">
+  <div class="cell-icon">
 <img src="{@docRoot}images/google/analytics.png" width="40" />
   </div>
     <h4><a class="external-link" 
diff --git a/docs/html/google/play/billing/gp-purchase-status-api.jd b/docs/html/google/play/billing/gp-purchase-status-api.jd
index c5b8461..25ef28b 100644
--- a/docs/html/google/play/billing/gp-purchase-status-api.jd
+++ b/docs/html/google/play/billing/gp-purchase-status-api.jd
@@ -88,7 +88,7 @@
 <h3 id="quota">Quota</h3>
 
 <p>Applications using the Google Play Android Developer API are limited to an
-initial courtesy usage quota of <strong>15000 requests per day</strong> (per
+initial courtesy usage quota of <strong>200,000 requests per day</strong> (per
 application). This should provide enough access for normal
 subscription-validation needs, assuming that you follow the recommendation in
 this section.</p>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 2a31374..21d295a 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -408,7 +408,7 @@
         </ul>
       </li>
       <li><a href="<?cs var:toroot?>guide/topics/connectivity/wifip2p.html">
-            <span class="en">Wi-Fi Direct</span></a>
+            <span class="en">Wi-Fi P2P</span></a>
           </li>
       <li class="nav-section">
           <div class="nav-section-header"><a href="<?cs var:toroot?>guide/topics/connectivity/usb/index.html">
diff --git a/docs/html/guide/topics/connectivity/index.jd b/docs/html/guide/topics/connectivity/index.jd
index 322518e..385cf08 100644
--- a/docs/html/guide/topics/connectivity/index.jd
+++ b/docs/html/guide/topics/connectivity/index.jd
@@ -1,6 +1,6 @@
 page.title=Connectivity
 page.landing=true
-page.landing.intro=Android provides rich APIs to let your app connect and interact with other devices over Bluetooth, NFC, Wi-Fi Direct, USB, and SIP, in addition to standard network connections.
+page.landing.intro=Android provides rich APIs to let your app connect and interact with other devices over Bluetooth, NFC, Wi-Fi P2P, USB, and SIP, in addition to standard network connections.
 page.landing.image=images/develop/connectivity.png
 
 @jd:body
diff --git a/docs/html/guide/topics/connectivity/wifip2p.jd b/docs/html/guide/topics/connectivity/wifip2p.jd
index 2167a0f..7cadde1 100644
--- a/docs/html/guide/topics/connectivity/wifip2p.jd
+++ b/docs/html/guide/topics/connectivity/wifip2p.jd
@@ -1,5 +1,5 @@
-page.title=Wi-Fi Direct
-page.tags="wireless","WifiP2pManager"
+page.title=Wi-Fi Peer-to-Peer
+page.tags="wireless","WifiP2pManager","Wi-Fi Direct","WiFi Direct","P2P","Wi-Fi P2P","WiFi P2P"
 
 @jd:body
 
@@ -9,10 +9,10 @@
 
       <ol>
         <li><a href="#api">API Overview</a></li>
-        <li><a href="#creating-br">Creating a Broadcast Receiver for Wi-Fi Direct Intents</a></li>
+        <li><a href="#creating-br">Creating a Broadcast Receiver for Wi-Fi P2P Intents</a></li>
 
         <li>
-          <a href="#creating-app">Creating a Wi-Fi Direct Application</a>
+          <a href="#creating-app">Creating a Wi-Fi P2P Application</a>
 
           <ol>
             <li><a href="#setup">Initial setup</a></li>
@@ -25,21 +25,24 @@
           </ol>
         </li>
       </ol>
-      <h2>Related Samples</h2>
-      <ol>
-        <li><a href="{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi Direct Demo</a></li>
-      </ol>
+    <h2>See also</h2>
+    <ul>
+      <li><a href="{@docRoot}training/connect-devices-wirelessly/wifi-direct.html">Creating
+        P2P Connections with Wi-Fi</a></li>
+    </ul>
     </div>
   </div>
 
-  <p>Wi-Fi Direct allows Android 4.0 (API level 14) or later devices with the appropriate hardware
-  to connect directly to each other via Wi-Fi without an intermediate access point.
-  Using these APIs, you can discover and connect to other devices when each device supports Wi-Fi Direct,
-  then communicate over a speedy connection across distances much longer than a Bluetooth connection.
-  This is useful for applications that share data among users, such as a multiplayer game or
-  a photo sharing application.</p>
 
-  <p>The Wi-Fi Direct APIs consist of the following main parts:</p>
+<p>Wi-Fi peer-to-peer (P2P) allows Android 4.0 (API level 14) or later devices with the appropriate
+hardware to connect directly to each other via Wi-Fi without an intermediate access point (Android's
+Wi-Fi P2P framework complies with the Wi-Fi Alliance's Wi-Fi Direct&trade; certification program).
+Using these APIs, you can discover and connect to other devices when each device supports Wi-Fi P2P,
+then communicate over a speedy connection across distances much longer than a Bluetooth connection.
+This is useful for applications that share data among users, such as a multiplayer game or
+a photo sharing application.</p>
+
+  <p>The Wi-Fi P2P APIs consist of the following main parts:</p>
 
   <ul>
     <li>Methods that allow you to discover, request, and connect to peers are defined
@@ -50,7 +53,7 @@
     android.net.wifi.p2p.WifiP2pManager} methods, each method can receive a specific listener
     passed in as a parameter.</li>
 
-    <li>Intents that notify you of specific events detected by the Wi-Fi Direct framework,
+    <li>Intents that notify you of specific events detected by the Wi-Fi P2P framework,
     such as a dropped connection or a newly discovered peer.</li>
   </ul>
 
@@ -70,7 +73,7 @@
   the Wi-Fi hardware on your device to do things like discover and connect to peers. The following actions
   are available:</p>
 
-<p class="table-caption"><strong>Table 1.</strong>Wi-Fi Direct Methods</p>
+<p class="table-caption"><strong>Table 1.</strong>Wi-Fi P2P Methods</p>
 
    <table>
         <tr>
@@ -80,7 +83,7 @@
 
 	<tr>
 	  <td>{@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()}</td>
-	  <td>Registers the application with the Wi-Fi framework. This must be called before calling any other Wi-Fi Direct method.</td>
+	  <td>Registers the application with the Wi-Fi framework. This must be called before calling any other Wi-Fi P2P method.</td>
 	</tr>
 
 	<tr>
@@ -126,12 +129,12 @@
 
 
  <p>{@link android.net.wifi.p2p.WifiP2pManager} methods let you pass in a listener,
-  so that the Wi-Fi Direct framework can notify your
+  so that the Wi-Fi P2P framework can notify your
   activity of the status of a call. The available listener interfaces and the
   corresponding {@link android.net.wifi.p2p.WifiP2pManager} method calls that use the listeners
   are described in the following table:</p>
 
- <p class="table-caption"><strong>Table 2.</strong> Wi-Fi Direct Listeners</p>
+ <p class="table-caption"><strong>Table 2.</strong> Wi-Fi P2P Listeners</p>
  
  <table>
     <tr>
@@ -168,12 +171,12 @@
     </tr>
   </table>
 
-<p>The Wi-Fi Direct APIs define intents that are broadcast when certain Wi-Fi Direct events happen,
+<p>The Wi-Fi P2P APIs define intents that are broadcast when certain Wi-Fi P2P events happen,
   such as when a new peer is discovered or when a device's Wi-Fi state changes. You can register
   to receive these intents in your application by <a href="#creating-br">creating a broadcast
   receiver</a> that handles these intents:</p>
 
-<p class="table-caption"><strong>Table 3.</strong> Wi-Fi Direct Intents</p>
+<p class="table-caption"><strong>Table 3.</strong> Wi-Fi P2P Intents</p>
 
     <table>
     <tr>
@@ -194,7 +197,7 @@
       </tr>
       <tr>
         <td>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION}</td>
-        <td>Broadcast when Wi-Fi Direct is enabled or disabled on the device.</td>
+        <td>Broadcast when Wi-Fi P2P is enabled or disabled on the device.</td>
       </tr>
       <tr>
         <td>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_THIS_DEVICE_CHANGED_ACTION}</td>
@@ -204,11 +207,11 @@
 
 
 
-  <h2 id="creating-br">Creating a Broadcast Receiver for Wi-Fi Direct Intents</h2>
+  <h2 id="creating-br">Creating a Broadcast Receiver for Wi-Fi P2P Intents</h2>
 
   <p>A broadcast receiver allows you to receive intents broadcast by the Android system,
   so that your application can respond to events that you are interested in. The basic steps
-  for creating a broadcast receiver to handle Wi-Fi Direct intents are as follows:</p>
+  for creating a broadcast receiver to handle Wi-Fi P2P intents are as follows:</p>
 
   <ol>
     <li>Create a class that extends the {@link android.content.BroadcastReceiver} class. For the
@@ -267,17 +270,17 @@
 }
 </pre>
 
-  <h2 id="creating-app">Creating a Wi-Fi Direct Application</h2>
+  <h2 id="creating-app">Creating a Wi-Fi P2P Application</h2>
 
-  <p>Creating a Wi-Fi Direct application involves creating and registering a
+  <p>Creating a Wi-Fi P2P application involves creating and registering a
   broadcast receiver for your application, discovering peers, connecting to a peer, and
   transferring data to a peer. The following sections describe how to do this.</p>
 
   <h3 id="setup">Initial setup</h3>
-  <p>Before using the Wi-Fi Direct APIs, you must ensure that your application can access
-  the hardware and that the device supports the Wi-Fi Direct protocol. If Wi-Fi Direct is supported,
+  <p>Before using the Wi-Fi P2P APIs, you must ensure that your application can access
+  the hardware and that the device supports the Wi-Fi P2P protocol. If Wi-Fi P2P is supported,
   you can obtain an instance of {@link android.net.wifi.p2p.WifiP2pManager}, create and register
-  your broadcast receiver, and begin using the Wi-Fi Direct APIs.</p>
+  your broadcast receiver, and begin using the Wi-Fi P2P APIs.</p>
   <ol>
     <li>
       <p>Request permission to use the Wi-Fi hardware on the device and also declare
@@ -292,10 +295,10 @@
 </pre>
     </li>
 
-    <li>Check to see if Wi-Fi Direct is on and supported. A good place to check this is in your
+    <li>Check to see if Wi-Fi P2P is on and supported. A good place to check this is in your
     broadcast receiver when it receives the {@link
     android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION} intent. Notify your
-    activity of the Wi-Fi Direct state and react accordingly:
+    activity of the Wi-Fi P2P state and react accordingly:
 <pre>
 &#064;Override
 public void onReceive(Context context, Intent intent) {
@@ -304,9 +307,9 @@
     if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
         int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
         if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
-            // Wifi Direct is enabled
+            // Wifi P2P is enabled
         } else {
-            // Wi-Fi Direct is not enabled
+            // Wi-Fi P2P is not enabled
         }
     }
     ...
@@ -315,10 +318,10 @@
     </li>
 
     <li>In your activity's {@link android.app.Activity#onCreate onCreate()} method, obtain an instance of {@link
-    android.net.wifi.p2p.WifiP2pManager} and register your application with the Wi-Fi Direct
+    android.net.wifi.p2p.WifiP2pManager} and register your application with the Wi-Fi P2P
     framework by calling {@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()}. This
     method returns a {@link android.net.wifi.p2p.WifiP2pManager.Channel}, which is used to connect
-    your application to the Wi-Fi Direct framework. You should also create an instance of your
+    your application to the Wi-Fi P2P framework. You should also create an instance of your
     broadcast receiver with the {@link
     android.net.wifi.p2p.WifiP2pManager} and {@link android.net.wifi.p2p.WifiP2pManager.Channel}
     objects along with a reference to your activity. This allows your broadcast receiver to notify
@@ -376,11 +379,11 @@
 </pre>
 
       <p>When you have obtained a {@link android.net.wifi.p2p.WifiP2pManager.Channel} and
-      set up a broadcast receiver, your application can make Wi-Fi Direct method calls and receive
-      Wi-Fi Direct intents.</p>
+      set up a broadcast receiver, your application can make Wi-Fi P2P method calls and receive
+      Wi-Fi P2P intents.</p>
     </li>
 
-    <p>You can now implement your application and use the Wi-Fi Direct features by calling the
+    <p>You can now implement your application and use the Wi-Fi P2P features by calling the
     methods in {@link android.net.wifi.p2p.WifiP2pManager}. The next sections describe how to do common actions
     such as discovering and connecting to peers.</p>
   </ol>
@@ -492,10 +495,10 @@
   </ol>
 
   <p>The following example, modified from the <a href=
-  "{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi Direct Demo</a> sample, shows you how
+  "{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi P2P Demo</a> sample, shows you how
   to create this client-server socket communication and transfer JPEG images from a client
   to a server with a service. For a complete working example, compile and run the <a href=
-  "{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi Direct Demo</a> sample.</p>
+  "{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi P2P Demo</a> sample.</p>
 <pre>
 public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {
 
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index af35540..95f62a5 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -552,8 +552,8 @@
        <td>Bluetooth</td>
        <td><code>android.hardware.bluetooth</td>
        <td>The application uses Bluetooth radio features in the device.</td>
-<td>
-</td>
+       <td>If your app uses Bluetooth Low Energy, also declare
+       {@code android.software.bluetooth_le}.</td>
     </tr>
     <tr>
        <td rowspan="5">Camera</td>
@@ -849,26 +849,49 @@
   <th>Feature</th>
   <th>Attribute Value</th> 
   <th>Description</th>
-  <th>Comments</th>
+</tr>
+<tr>
+  <td>App Widgets</td>
+  <td><code>android.software.app_widgets</code></td>
+  <td>The application uses or provides App Widgets and should be installed only on devices
+  that include a Home screen or similar location where users can embed App Widgets.</td>
+</tr>
+<tr>
+  <td>Bluetooth Low Energy</td>
+  <td><code>android.software.bluetooth_le</code></td>
+  <td><p>The application uses Bluetooth Low Energy APIs and should be installed only on devices
+  that are capable of communicating with other devices via Bluetooth Low Energy.
+   <p>This implicitly also declares the {@code android.hardware.bluetooth} feature.</td>
+</tr>
+<tr>
+  <td>Home Screen</td>
+  <td><code>android.software.home_screen</code></td>
+  <td>The application behaves as a Home screen replacement and should be installed only on
+  devices that support third-party Home screen apps.</td>
+</tr>
+<tr>
+  <td>Input Method</td>
+  <td><code>android.software.input_methods</code></td>
+  <td>The application provides a custom input method and should be installed only on devices that
+  support third-party input methods.</td>
 </tr>
 <tr>
   <td>Live Wallpaper</td>
   <td><code>android.software.live_wallpaper</code></td>
-  <td>The application uses or provides Live Wallpapers.</td>
-  <td></td>
+  <td>The application uses or provides Live Wallpapers and should be installed only on devices that
+  support Live Wallpapers.</td>
 </tr>
 <tr>
   <td rowspan="2">SIP/VOIP</td>
   <td><code>android.software.sip</code></td>
-  <td>The application uses SIP service on the device.
+  <td>The application uses SIP service on the device and should be installed only on devices that
+  support SIP.
   </td>
-  <td></td>
 </tr>
 <tr>
   <td><code>android.software.sip.voip</code></td>
-  <td>Subfeature. The application uses SIP-based VOIP service on the device.
-  </td>
-  <td>This subfeature implicitly declares the <code>android.software.sip</code> parent feature,
+  <td><p>Subfeature. The application uses SIP-based VOIP service on the device.
+  <p>This subfeature implicitly declares the <code>android.software.sip</code> parent feature,
 unless declared with <code>android:required="false"</code>.</td>
 </tr>
   </table>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 18e479f..07b08f6 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -1,4 +1,4 @@
-fpage.title=&lt;uses-sdk&gt;
+page.title=&lt;uses-sdk&gt;
 page.tags="api levels","sdk version","minsdkversion","targetsdkversion","maxsdkversion"
 @jd:body
 
diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
index ebd7c25..6ec1e1b 100644
--- a/docs/html/guide/topics/providers/content-provider-creating.jd
+++ b/docs/html/guide/topics/providers/content-provider-creating.jd
@@ -680,7 +680,7 @@
          * Notice that the database itself isn't created or opened
          * until SQLiteOpenHelper.getWritableDatabase is called
          */
-        mOpenHelper = new SQLiteOpenHelper(
+        mOpenHelper = new MainDatabaseHelper(
             getContext(),        // the application context
             DBNAME,              // the name of the database)
             null,                // uses the default SQLite cursor
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 607d16e..c62510b 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -10,6 +10,11 @@
 
     <ol>
       <li><a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a></li>
+      <li><a href="#access-rs-apis">Accessing RenderScript APIs</a>
+        <ol>
+          <li><a href="#ide-setup">Setting Up Your Development Environment</a></li>
+        </ol>
+      </li>
       <li><a href="#using-rs-from-java">Using RenderScript from Java Code</a></li>
     </ol>
 
@@ -144,9 +149,90 @@
 beneficial on some architectures due to additional optimizations only available with relaxed
 precision (such as SIMD CPU instructions).</p>
 
+
+<h2 id="access-rs-apis">Accessing RenderScript APIs</h2>
+
+<p>When developing an Android application that uses RenderScript, you can access its API in
+  one of two ways:</p>
+
+<ul>
+  <li><strong>{@link android.renderscript}</strong> - The APIs in this class package are
+    available on devices running Android 3.0 (API level 11) and higher. These are the original APIs
+    for RenderScript and are not currently being updated.</li>
+  <li><strong>{@link android.support.v8.renderscript}</strong> - The APIs in this package are
+    available through a <a href="{@docRoot}tools/support-library/features.html#v8">Support
+    Library</a>, which allows you to use them on devices running Android 2.2 (API level 8) and
+    higher.</li>
+</ul>
+
+<p>We strongly recommend using the Support Library APIs for accessing RenderScript because they
+  include the latest improvements to the RenderScript compute framework and provide a wider range
+  of device compatibility.</p>
+
+
+<h3 id="ide-setup">Using the RenderScript Support Library APIs</h3>
+
+<p>In order to use the Support Library RenderScript APIs, you must configure your development
+  environment to be able to access them. The following Android SDK tools are required for using
+  these APIs:</p>
+
+<ul>
+  <li>Android SDK Tools revision 22.2 or higher</li>
+  <li>Android SDK Build-tools revision 18.1.0 or higher</li>
+</ul>
+
+<p>You can check and update the installed version of these tools in the
+  <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</p>
+
+<p class="note">
+  <strong>Note:</strong> Use of Support Library RenderScript APIs is not currently supported with
+  Android Studio or Gradle-based builds.
+</p>
+
+<p>To use the Support Library RenderScript APIs in Eclipse:</p>
+
+<ol>
+  <li>Make sure you have the required Android SDK version and Build Tools version installed.</li>
+  <li>Open the {@code project.properties} file in the root folder of your application project.</li>
+  <li>Add the following lines to the file:
+<pre>
+renderscript.target=18
+renderscript.support.mode=true
+sdk.buildtools=18.1.0
+</pre>
+  </li>
+  <li>In your application classes that use RenderScript, add an import for the Support Library
+    classes:
+<pre>
+import android.support.v8.renderscript.*;
+</pre>
+  </li>
+</ol>
+
+<p>The {@code project.properties} settings listed above control specific behavior in the Android
+  build process:</p>
+
+<ul>
+  <li>{@code renderscript.target} - Specifies the bytecode version to be generated. We
+    recommend you set this value the highest available API level and set {@code
+    renderscript.support.mode} to {@code true}. Valid values for this setting are any integer value
+    from 11 to the most recently released API level. If your minimum SDK version specified in your
+    application manifest is set to a higher value, this value is ignored and the target value is set
+    to the minimum SDK version.</li>
+  <li>{@code renderscript.support.mode} - Specifies that the generated bytecode should fall
+    back to a compatible version if the device it is running on does not support the target version.
+    </li>
+  <li>{@code sdk.buildtools} - The version of the Android SDK build tools to use. This value
+    should be set to {@code 18.1.0} or higher. If this option is not specified, the highest
+    installed build tools version is used. You should always set this value to ensure the
+    consistency of builds across development machines with different configurations.</li>
+</ul>
+
+
 <h2 id="using-rs-from-java">Using RenderScript from Java Code</h2>
 
-<p>Using RenderScript from Java code relies on the {@link android.renderscript} APIs. Most
+<p>Using RenderScript from Java code relies on the API classes located in the
+{@link android.renderscript} or the {@link android.support.v8.renderscript} package. Most
 applications follow the same basic usage patterns:</p>
 
 <ol>
diff --git a/docs/html/guide/topics/ui/controls/checkbox.jd b/docs/html/guide/topics/ui/controls/checkbox.jd
index 99140b5..2a64e38 100644
--- a/docs/html/guide/topics/ui/controls/checkbox.jd
+++ b/docs/html/guide/topics/ui/controls/checkbox.jd
@@ -94,7 +94,7 @@
 android.view.View} that was clicked)</li>
 </ul>
 
-<p class="note"><strong>Tip:</strong> If you need to change the radio button state
+<p class="note"><strong>Tip:</strong> If you need to change the checkbox state
 yourself (such as when loading a saved {@link android.preference.CheckBoxPreference}),
 use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link
 android.widget.CompoundButton#toggle()} method.</p>
\ No newline at end of file
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 09767bf..d934c4b 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -593,7 +593,7 @@
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        // Send the negative button event back to the host activity
-                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
+                       mListener.onDialogNegativeClick(NoticeDialogFragment.this);
                    }
                });
         return builder.create();
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
index 6a8cd86..168f77b 100644
--- a/docs/html/guide/topics/ui/how-android-draws.jd
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -4,15 +4,19 @@
 @jd:body
 
 
-<p>When an Activity receives focus, it will be requested to draw its layout.
-The Android framework will handle the procedure for drawing, but the Activity must provide
+<p>When an {@link android.app.Activity} receives focus, it will be requested to 
+draw its layout.
+The Android framework will handle the procedure for drawing, but the 
+{@link android.app.Activity} must provide
 the root node of its layout hierarchy.</p>
 
 <p>Drawing begins with the root node of the layout. It is requested to measure and 
-draw the layout tree. Drawing is handled by walking the tree and rendering each View that
-   intersects the invalid region. In turn, each View group is responsible for requesting
-each of its children to be drawn (with the <code>{@link android.view.View#draw(Canvas) draw()}</code> method) 
-and each View is responsible for drawing itself.
+draw the layout tree. Drawing is handled by walking the tree and rendering each 
+{@link android.view.View} that intersects the invalid region. In turn, each 
+{@link android.view.ViewGroup} is responsible for requesting
+each of its children to be drawn 
+(with the {@link android.view.View#draw(Canvas) draw()} method) 
+and each {@link android.view.View} is responsible for drawing itself.
  Because the tree is traversed in-order,
    this means that parents will be drawn before (i.e., behind) their children, with
    siblings drawn in the order they appear in the tree.
@@ -20,76 +24,107 @@
 
 <div class="sidebox-wrapper">
 <div class="sidebox">
-  <p>The framework will not draw Views that are not in the invalid region, and also 
-   will take care of drawing the Views background for you.</p>
-   <p>You can force a View to draw, by calling <code>{@link android.view.View#invalidate()}</code>.
+  <p>The framework will not draw {@link android.view.View} objects that are not 
+in the invalid region, and also 
+   will take care of drawing the {@link android.view.View} background for you.</p>
+   <p>You can force a {@link android.view.View} to draw, by calling 
+{@link android.view.View#invalidate()}.
    </p>
 </div>
 </div>
 
 <p>
-   Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring
-   pass is implemented in <code>{@link android.view.View#measure(int, int)}</code> and is a top-down traversal
-   of the View tree. Each View pushes dimension specifications down the tree
-   during the recursion. At the end of the measure pass, every View has stored
+   Drawing the layout is a two pass process: a measure pass and a layout pass. 
+The measuring pass is implemented in {@link android.view.View#measure(int, int)} 
+and is a top-down traversal of the {@link android.view.View} tree. Each {@link android.view.View} 
+pushes dimension specifications down the tree
+   during the recursion. At the end of the measure pass, every 
+{@link android.view.View} has stored
    its measurements. The second pass happens in
-   <code>{@link android.view.View#layout(int,int,int,int)}</code> and is also top-down. During
+   {@link android.view.View#layout(int,int,int,int)} and is also top-down. During
    this pass each parent is responsible for positioning all of its children
    using the sizes computed in the measure pass.
    </p>
    
    <p>
-   When a View's <code>measure()</code> method returns, its <code>{@link android.view.View#getMeasuredWidth()}</code> and
-   <code>{@link android.view.View#getMeasuredHeight()}</code> values must be set, along with those for all of
-   that View's descendants. A View's measured width and measured height values
-   must respect the constraints imposed by the View's parents. This guarantees
+   When a {@link android.view.View} object's 
+{@link android.view.View#measure(int, int) measure()} method 
+returns, its {@link android.view.View#getMeasuredWidth()} and
+   {@link android.view.View#getMeasuredHeight()} values must be set, along 
+   with those for all of that {@link android.view.View} object's descendants. 
+A {@link android.view.View} object's measured width and 
+measured height values must respect the constraints imposed by the 
+{@link android.view.View} object's parents. This guarantees
    that at the end of the measure pass, all parents accept all of their
-   children's measurements. A parent View may call <code>measure()</code> more than once on
+   children's measurements. A parent {@link android.view.View} may call 
+{@link android.view.View#measure(int, int) measure()} more than once on
    its children. For example, the parent may measure each child once with
    unspecified dimensions to find out how big they want to be, then call
-   <code>measure()</code> on them again with actual numbers if the sum of all the children's
-   unconstrained sizes is too big or too small (i.e., if the children don't agree among themselves
-  as to how much space they each get, the parent will intervene and set the rules on the second pass).
+   {@link android.view.View#measure(int, int) measure()} on them again with 
+actual numbers if the sum of all the children's
+   unconstrained sizes is too big or too small (that is, if the children 
+don't agree among themselves
+  as to how much space they each get, the parent will intervene and set 
+the rules on the second pass).
    </p>
    
 <div class="sidebox-wrapper">
 <div class="sidebox"><p>
-   To initiate a layout, call <code>{@link android.view.View#requestLayout}</code>. This method is typically
-   called by a View on itself when it believes that is can no longer fit within
+   To initiate a layout, call {@link android.view.View#requestLayout}. 
+This method is typically
+   called by a {@link android.view.View} on itself 
+when it believes that is can no longer fit within
    its current bounds.</p>
 </div>
 </div>
 
    <p>
    The measure pass uses two classes to communicate dimensions. The
-   {@link android.view.ViewGroup.LayoutParams} class is used by Views to tell their parents how they
-   want to be measured and positioned. The base LayoutParams class just
-   describes how big the View wants to be for both width and height. For each
+   {@link android.view.ViewGroup.LayoutParams} class is used by 
+{@link android.view.View} objects to tell their parents how they
+   want to be measured and positioned. The base 
+{@link android.view.ViewGroup.LayoutParams}  class just
+   describes how big the {@link android.view.View} wants to be for both 
+width and height. For each
    dimension, it can specify one of:</p>
    <ul>
     <li> an exact number
-    <li><var>FILL_PARENT</var>, which means the View wants to be as big as its parent
+    <li>{@link android.view.ViewGroup.LayoutParams#MATCH_PARENT MATCH_PARENT}, 
+which means the {@link android.view.View} wants to be as big as its parent
     (minus padding)</li>
-    <li><var>WRAP_CONTENT</var>, which means that the View wants to be just big enough to
+    <li>{@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT WRAP_CONTENT}, 
+which means that the {@link android.view.View} wants to be just big enough to
     enclose its content (plus padding).</li>
    </ul>
-  <p>There are subclasses of LayoutParams for different subclasses of ViewGroup.
-   For example, RelativeLayout has its own subclass of LayoutParams, which includes
-   the ability to center child Views horizontally and vertically.
+  <p>There are subclasses of {@link android.view.ViewGroup.LayoutParams} for 
+different subclasses of {@link android.view.ViewGroup}.
+   For example, {@link android.widget.RelativeLayout} has its own subclass of 
+{@link android.view.ViewGroup.LayoutParams}, which includes
+   the ability to center child {@link android.view.View} objects 
+horizontally and vertically.
    </p>
    
    <p>
-   MeasureSpecs are used to push requirements down the tree from parent to
-   child. A MeasureSpec can be in one of three modes:</p>
+   {@link android.view.View.MeasureSpec MeasureSpec} objects are used to push 
+requirements down the tree from parent to
+   child. A {@link android.view.View.MeasureSpec MeasureSpec} can be in one of 
+three modes:</p>
    <ul>
-    <li><var>UNSPECIFIED</var>: This is used by a parent to determine the desired dimension
-    of a child View. For example, a LinearLayout may call <code>measure()</code> on its child
-    with the height set to <var>UNSPECIFIED</var> and a width of <var>EXACTLY</var> 240 to find out how
-    tall the child View wants to be given a width of 240 pixels.</li>
-    <li><var>EXACTLY</var>: This is used by the parent to impose an exact size on the
+    <li>{@link android.view.View.MeasureSpec#UNSPECIFIED UNSPECIFIED}: This is 
+used by a parent to determine the desired dimension
+    of a child {@link android.view.View}. For example, a 
+{@link android.widget.LinearLayout} may call 
+{@link android.view.View#measure(int, int) measure()} on its child
+    with the height set to {@link android.view.View.MeasureSpec#UNSPECIFIED UNSPECIFIED} 
+and a width of {@link android.view.View.MeasureSpec#EXACTLY EXACTLY} 240 to 
+find out how tall the child {@link android.view.View} wants to be given a 
+width of 240 pixels.</li>
+    <li>{@link android.view.View.MeasureSpec#EXACTLY EXACTLY}: This is used 
+by the parent to impose an exact size on the
     child. The child must use this size, and guarantee that all of its
     descendants will fit within this size.</li>
-    <li><var>AT_MOST</var>: This is used by the parent to impose a maximum size on the
+    <li>{@link android.view.View.MeasureSpec#AT_MOST AT MOST}: This is used by 
+the parent to impose a maximum size on the
     child. The child must guarantee that it and all of its descendants will fit
     within this size.</li>
    </ul>
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index e0c87d7..3b1292e 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -285,7 +285,7 @@
 <p>
     Starting an {@link android.app.Activity} when the user clicks the notification is the most
     common action scenario. You can also start an {@link android.app.Activity} when the user
-    dismisses an {@link android.app.Activity}. In Android 4.1 and later, you can start an
+    dismisses a notification. In Android 4.1 and later, you can start an
     {@link android.app.Activity} from an action button. To learn more, read the reference guide for
     {@link android.support.v4.app.NotificationCompat.Builder}.
 </p>
diff --git a/docs/html/images/google/cloud-platform.png b/docs/html/images/google/cloud-platform.png
new file mode 100644
index 0000000..90df8ed
--- /dev/null
+++ b/docs/html/images/google/cloud-platform.png
Binary files differ
diff --git a/docs/html/images/google/wallet.png b/docs/html/images/google/wallet.png
new file mode 100644
index 0000000..34cc11e
--- /dev/null
+++ b/docs/html/images/google/wallet.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula-violation.png b/docs/html/images/gp-policy-ads-eula-violation.png
index e8ffa5b..204c320 100644
--- a/docs/html/images/gp-policy-ads-eula-violation.png
+++ b/docs/html/images/gp-policy-ads-eula-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula.png b/docs/html/images/gp-policy-ads-eula.png
deleted file mode 100644
index 68a6b95..0000000
--- a/docs/html/images/gp-policy-ads-eula.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png b/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
new file mode 100644
index 0000000..a2a39a9
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png b/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
new file mode 100644
index 0000000..f323b06
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-interstitial-violation.png b/docs/html/images/gp-policy-ads-interstitial-violation.png
new file mode 100644
index 0000000..4871493
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-interstitial-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr-violation.png b/docs/html/images/gp-policy-ads-notif-attr-violation.png
index af53f10..3d6393b 100644
--- a/docs/html/images/gp-policy-ads-notif-attr-violation.png
+++ b/docs/html/images/gp-policy-ads-notif-attr-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr.png b/docs/html/images/gp-policy-ads-notif-attr.png
index 4934d21..da39cfb 100644
--- a/docs/html/images/gp-policy-ads-notif-attr.png
+++ b/docs/html/images/gp-policy-ads-notif-attr.png
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-reqrating.png b/docs/html/images/gp-policy-spam-reqrating.png
index aaf9e53..20e17c1 100644
--- a/docs/html/images/gp-policy-spam-reqrating.png
+++ b/docs/html/images/gp-policy-spam-reqrating.png
Binary files differ
diff --git a/docs/html/images/training/lesson2_MyFirstTestActivityTest_result.png b/docs/html/images/training/lesson2_MyFirstTestActivityTest_result.png
new file mode 100644
index 0000000..e0e869b
--- /dev/null
+++ b/docs/html/images/training/lesson2_MyFirstTestActivityTest_result.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index bbb6a16..4a6902e 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -2,6 +2,8 @@
 no_footer_links=true
 carousel=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
 
 
diff --git a/docs/html/reference/com/google/android/gms/R.attr.html b/docs/html/reference/com/google/android/gms/R.attr.html
index 896f4d0..2c14e05 100644
--- a/docs/html/reference/com/google/android/gms/R.attr.html
+++ b/docs/html/reference/com/google/android/gms/R.attr.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R.attr | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1171,7 +1178,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1190,7 +1197,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1209,7 +1216,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1238,7 +1245,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1302,7 +1309,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/R.color.html b/docs/html/reference/com/google/android/gms/R.color.html
index 09d6686..f6f619b 100644
--- a/docs/html/reference/com/google/android/gms/R.color.html
+++ b/docs/html/reference/com/google/android/gms/R.color.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R.color | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -962,7 +969,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -981,7 +988,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1000,7 +1007,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1029,7 +1036,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1093,7 +1100,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/R.drawable.html b/docs/html/reference/com/google/android/gms/R.drawable.html
index 98bfa77..6777c6e 100644
--- a/docs/html/reference/com/google/android/gms/R.drawable.html
+++ b/docs/html/reference/com/google/android/gms/R.drawable.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R.drawable | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1036,6 +1043,50 @@
       </tr>
       
     
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.drawable.html#ic_plusone_medium_off_client">ic_plusone_medium_off_client</a></td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.drawable.html#ic_plusone_small_off_client">ic_plusone_small_off_client</a></td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.drawable.html#ic_plusone_standard_off_client">ic_plusone_standard_off_client</a></td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.drawable.html#ic_plusone_tall_off_client">ic_plusone_tall_off_client</a></td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
 
 </table>
 
@@ -1093,7 +1144,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1112,7 +1163,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1131,7 +1182,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1160,7 +1211,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1224,7 +1275,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1990,6 +2041,118 @@
 
 
 
+<A NAME="ic_plusone_medium_off_client"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        ic_plusone_medium_off_client
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    
+    </div>
+</div>
+
+
+
+<A NAME="ic_plusone_small_off_client"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        ic_plusone_small_off_client
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    
+    </div>
+</div>
+
+
+
+<A NAME="ic_plusone_standard_off_client"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        ic_plusone_standard_off_client
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    
+    </div>
+</div>
+
+
+
+<A NAME="ic_plusone_tall_off_client"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        ic_plusone_tall_off_client
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    
+    </div>
+</div>
+
+
+
 
 <!-- Public ctors -->
 
diff --git a/docs/html/reference/com/google/android/gms/R.html b/docs/html/reference/com/google/android/gms/R.html
index 239efc8..239f072 100644
--- a/docs/html/reference/com/google/android/gms/R.html
+++ b/docs/html/reference/com/google/android/gms/R.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -900,7 +907,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -919,7 +926,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -938,7 +945,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -967,7 +974,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1031,7 +1038,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/R.id.html b/docs/html/reference/com/google/android/gms/R.id.html
index fd76dfe..8f22e13 100644
--- a/docs/html/reference/com/google/android/gms/R.id.html
+++ b/docs/html/reference/com/google/android/gms/R.id.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R.id | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1016,7 +1023,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1035,7 +1042,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1054,7 +1061,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1083,7 +1090,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1147,7 +1154,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/R.string.html b/docs/html/reference/com/google/android/gms/R.string.html
index a8ac442..f7afc66 100644
--- a/docs/html/reference/com/google/android/gms/R.string.html
+++ b/docs/html/reference/com/google/android/gms/R.string.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R.string | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -937,6 +944,50 @@
           static
           
           int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.string.html#common_google_play_services_invalid_account_text">common_google_play_services_invalid_account_text</a></td>
+          <td class="jd-descrcol" width="100%">Message in confirmation dialog informing the user that they provided an invalid account.</td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.string.html#common_google_play_services_invalid_account_title">common_google_play_services_invalid_account_title</a></td>
+          <td class="jd-descrcol" width="100%">Title of confirmation dialog informing the user that they provided an invalid account.</td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.string.html#common_google_play_services_network_error_text">common_google_play_services_network_error_text</a></td>
+          <td class="jd-descrcol" width="100%">Message in confirmation dialog informing the user that a network error occurred.</td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
+          <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.string.html#common_google_play_services_network_error_title">common_google_play_services_network_error_title</a></td>
+          <td class="jd-descrcol" width="100%">Title of confirmation dialog informing the user that a network error occurred.</td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          
+          int</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/R.string.html#common_google_play_services_unknown_issue">common_google_play_services_unknown_issue</a></td>
           <td class="jd-descrcol" width="100%">Message in confirmation dialog informing user there is an unknown issue in Google Play
         services [CHAR LIMIT=NONE] 
@@ -1087,7 +1138,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1106,7 +1157,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1125,7 +1176,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1154,7 +1205,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1218,7 +1269,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1701,6 +1752,122 @@
 
 
 
+<A NAME="common_google_play_services_invalid_account_text"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        common_google_play_services_invalid_account_text
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Message in confirmation dialog informing the user that they provided an invalid account. [CHAR LIMIT=NONE] 
+</p></div>
+
+    
+    </div>
+</div>
+
+
+
+<A NAME="common_google_play_services_invalid_account_title"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        common_google_play_services_invalid_account_title
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Title of confirmation dialog informing the user that they provided an invalid account. [CHAR LIMIT=40] 
+</p></div>
+
+    
+    </div>
+</div>
+
+
+
+<A NAME="common_google_play_services_network_error_text"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        common_google_play_services_network_error_text
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Message in confirmation dialog informing the user that a network error occurred. [CHAR LIMIT=NONE] 
+</p></div>
+
+    
+    </div>
+</div>
+
+
+
+<A NAME="common_google_play_services_network_error_title"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+         
+        int
+      </span>
+        common_google_play_services_network_error_title
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Title of confirmation dialog informing the user that a network error occurred. [CHAR LIMIT=40] 
+</p></div>
+
+    
+    </div>
+</div>
+
+
+
 <A NAME="common_google_play_services_unknown_issue"></A>
 
 <div class="jd-details api apilevel-"> 
diff --git a/docs/html/reference/com/google/android/gms/R.styleable.html b/docs/html/reference/com/google/android/gms/R.styleable.html
index 397d0d8..d18e7be 100644
--- a/docs/html/reference/com/google/android/gms/R.styleable.html
+++ b/docs/html/reference/com/google/android/gms/R.styleable.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>R.styleable | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1167,7 +1174,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1186,7 +1193,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1205,7 +1212,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1234,7 +1241,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1298,7 +1305,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/appstate/AppState.html b/docs/html/reference/com/google/android/gms/appstate/AppState.html
index 8fa7007..bc1c240 100644
--- a/docs/html/reference/com/google/android/gms/appstate/AppState.html
+++ b/docs/html/reference/com/google/android/gms/appstate/AppState.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>AppState | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -797,7 +804,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppState.html#getConflictVersion()">getConflictVersion</a></span>()</nobr>
@@ -845,7 +852,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppState.html#getLocalVersion()">getLocalVersion</a></span>()</nobr>
@@ -1031,7 +1038,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getConflictVersion</span>
       <span class="normal">()</span>
@@ -1133,7 +1140,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getLocalVersion</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/appstate/AppStateBuffer.html b/docs/html/reference/com/google/android/gms/appstate/AppStateBuffer.html
index 6f74d48..14740b3 100644
--- a/docs/html/reference/com/google/android/gms/appstate/AppStateBuffer.html
+++ b/docs/html/reference/com/google/android/gms/appstate/AppStateBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>AppStateBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/appstate/AppStateClient.Builder.html b/docs/html/reference/com/google/android/gms/appstate/AppStateClient.Builder.html
index 9f128c4..ff4ab56 100644
--- a/docs/html/reference/com/google/android/gms/appstate/AppStateClient.Builder.html
+++ b/docs/html/reference/com/google/android/gms/appstate/AppStateClient.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>AppStateClient.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -792,7 +799,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html#AppStateClient.Builder(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">AppStateClient.Builder</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html#AppStateClient.Builder(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">AppStateClient.Builder</a></span>(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
         
         <div class="jd-descrdiv">Create a new Builder object to be used to build a corresponding AppStateClient object.</div>
   
@@ -842,7 +849,7 @@
             <a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html">AppStateClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html#setAccountName(java.lang.String)">setAccountName</a></span>(<a href="/reference/java/lang/String.html">String</a> accountName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html#setAccountName(java.lang.String)">setAccountName</a></span>(String accountName)</nobr>
         
         <div class="jd-descrdiv">Specify an account name on the device that should be used.</div>
   
@@ -860,7 +867,7 @@
             <a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html">AppStateClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html#setScopes(java.lang.String...)">setScopes</a></span>(<a href="/reference/java/lang/String.html">String...</a> scopes)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html#setScopes(java.lang.String...)">setScopes</a></span>(String... scopes)</nobr>
         
         <div class="jd-descrdiv">Set the scopes to use when building the AppStateClient object.</div>
   
@@ -890,7 +897,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -909,7 +916,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -928,7 +935,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -957,7 +964,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1021,7 +1028,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1130,7 +1137,7 @@
         
       </span>
       <span class="sympad">AppStateClient.Builder</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1243,7 +1250,7 @@
         <a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html">AppStateClient.Builder</a>
       </span>
       <span class="sympad">setAccountName</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> accountName)</span>
+      <span class="normal">(String accountName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1289,7 +1296,7 @@
         <a href="/reference/com/google/android/gms/appstate/AppStateClient.Builder.html">AppStateClient.Builder</a>
       </span>
       <span class="sympad">setScopes</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String...</a> scopes)</span>
+      <span class="normal">(String... scopes)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/appstate/AppStateClient.html b/docs/html/reference/com/google/android/gms/appstate/AppStateClient.html
index 6c2138f..cd65dc4 100644
--- a/docs/html/reference/com/google/android/gms/appstate/AppStateClient.html
+++ b/docs/html/reference/com/google/android/gms/appstate/AppStateClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>AppStateClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -691,7 +698,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1186,7 +1193,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.html#resolveState(com.google.android.gms.appstate.OnStateLoadedListener, int, java.lang.String, byte[])">resolveState</a></span>(<a href="/reference/com/google/android/gms/appstate/OnStateLoadedListener.html">OnStateLoadedListener</a> listener, int stateKey, <a href="/reference/java/lang/String.html">String</a> resolvedVersion, byte[] resolvedData)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/AppStateClient.html#resolveState(com.google.android.gms.appstate.OnStateLoadedListener, int, java.lang.String, byte[])">resolveState</a></span>(<a href="/reference/com/google/android/gms/appstate/OnStateLoadedListener.html">OnStateLoadedListener</a> listener, int stateKey, String resolvedVersion, byte[] resolvedData)</nobr>
         
         <div class="jd-descrdiv">Resolve a previously detected conflict in app state data.</div>
   
@@ -1324,7 +1331,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1343,7 +1350,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1362,7 +1369,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1391,7 +1398,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1455,7 +1462,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2858,7 +2865,7 @@
         void
       </span>
       <span class="sympad">resolveState</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/appstate/OnStateLoadedListener.html">OnStateLoadedListener</a> listener, int stateKey, <a href="/reference/java/lang/String.html">String</a> resolvedVersion, byte[] resolvedData)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/appstate/OnStateLoadedListener.html">OnStateLoadedListener</a> listener, int stateKey, String resolvedVersion, byte[] resolvedData)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/appstate/OnSignOutCompleteListener.html b/docs/html/reference/com/google/android/gms/appstate/OnSignOutCompleteListener.html
index d2a2de3..a035350 100644
--- a/docs/html/reference/com/google/android/gms/appstate/OnSignOutCompleteListener.html
+++ b/docs/html/reference/com/google/android/gms/appstate/OnSignOutCompleteListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnSignOutCompleteListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/appstate/OnStateDeletedListener.html b/docs/html/reference/com/google/android/gms/appstate/OnStateDeletedListener.html
index 55119e3..7037c3e 100644
--- a/docs/html/reference/com/google/android/gms/appstate/OnStateDeletedListener.html
+++ b/docs/html/reference/com/google/android/gms/appstate/OnStateDeletedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnStateDeletedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/appstate/OnStateListLoadedListener.html b/docs/html/reference/com/google/android/gms/appstate/OnStateListLoadedListener.html
index a742769..3b41c23 100644
--- a/docs/html/reference/com/google/android/gms/appstate/OnStateListLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/appstate/OnStateListLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnStateListLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/appstate/OnStateLoadedListener.html b/docs/html/reference/com/google/android/gms/appstate/OnStateLoadedListener.html
index 96c0af9..57319e4 100644
--- a/docs/html/reference/com/google/android/gms/appstate/OnStateLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/appstate/OnStateLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnStateLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -751,7 +758,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/OnStateLoadedListener.html#onStateConflict(int, java.lang.String, byte[], byte[])">onStateConflict</a></span>(int stateKey, <a href="/reference/java/lang/String.html">String</a> resolvedVersion, byte[] localData, byte[] serverData)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/appstate/OnStateLoadedListener.html#onStateConflict(int, java.lang.String, byte[], byte[])">onStateConflict</a></span>(int stateKey, String resolvedVersion, byte[] localData, byte[] serverData)</nobr>
         
         <div class="jd-descrdiv">Called when a conflict is detected while loading app state.</div>
   
@@ -837,7 +844,7 @@
         void
       </span>
       <span class="sympad">onStateConflict</span>
-      <span class="normal">(int stateKey, <a href="/reference/java/lang/String.html">String</a> resolvedVersion, byte[] localData, byte[] serverData)</span>
+      <span class="normal">(int stateKey, String resolvedVersion, byte[] localData, byte[] serverData)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/appstate/package-summary.html b/docs/html/reference/com/google/android/gms/appstate/package-summary.html
index d87f558..14d6899 100644
--- a/docs/html/reference/com/google/android/gms/appstate/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/appstate/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.appstate | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/auth/GoogleAuthException.html b/docs/html/reference/com/google/android/gms/auth/GoogleAuthException.html
index d9dd2ad..ab9d17a4 100644
--- a/docs/html/reference/com/google/android/gms/auth/GoogleAuthException.html
+++ b/docs/html/reference/com/google/android/gms/auth/GoogleAuthException.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleAuthException | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -703,7 +710,7 @@
   
 
   
-    extends <a href="/reference/java/lang/Exception.html">Exception</a><br/>
+    extends Exception<br/>
   
   
   
@@ -723,7 +730,7 @@
 
     <tr>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -731,7 +738,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Throwable</td>
     </tr>
     
 
@@ -741,7 +748,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Exception.html">java.lang.Exception</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Exception</td>
     </tr>
     
 
@@ -911,7 +918,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthException.html#GoogleAuthException(java.lang.String)">GoogleAuthException</a></span>(<a href="/reference/java/lang/String.html">String</a> err)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthException.html#GoogleAuthException(java.lang.String)">GoogleAuthException</a></span>(String err)</nobr>
         
   </td></tr>
 
@@ -945,7 +952,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a>
+  java.lang.Throwable
 
 <div id="inherited-methods-java.lang.Throwable">
   <div id="inherited-methods-java.lang.Throwable-list"
@@ -964,7 +971,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">fillInStackTrace</span>()</nobr>
@@ -980,7 +987,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getCause</span>()</nobr>
@@ -996,7 +1003,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLocalizedMessage</span>()</nobr>
@@ -1012,7 +1019,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMessage</span>()</nobr>
@@ -1028,7 +1035,7 @@
             
             
             
-            <a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a></nobr>
+            StackTraceElement[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getStackTrace</span>()</nobr>
@@ -1044,10 +1051,10 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initCause</span>(<a href="/reference/java/lang/Throwable.html">Throwable</a> arg0)</nobr>
+        <span class="sympad">initCause</span>(Throwable arg0)</nobr>
         
   </td></tr>
 
@@ -1063,7 +1070,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintWriter arg0)</nobr>
         
   </td></tr>
 
@@ -1079,7 +1086,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintStream.html">PrintStream</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintStream arg0)</nobr>
         
   </td></tr>
 
@@ -1111,7 +1118,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setStackTrace</span>(<a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a> arg0)</nobr>
+        <span class="sympad">setStackTrace</span>(StackTraceElement[] arg0)</nobr>
         
   </td></tr>
 
@@ -1124,7 +1131,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1147,7 +1154,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1166,7 +1173,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1185,7 +1192,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1214,7 +1221,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1278,7 +1285,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1389,7 +1396,7 @@
         
       </span>
       <span class="sympad">GoogleAuthException</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> err)</span>
+      <span class="normal">(String err)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/auth/GoogleAuthUtil.html b/docs/html/reference/com/google/android/gms/auth/GoogleAuthUtil.html
index 370fe09..5db612b 100644
--- a/docs/html/reference/com/google/android/gms/auth/GoogleAuthUtil.html
+++ b/docs/html/reference/com/google/android/gms/auth/GoogleAuthUtil.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleAuthUtil | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -846,22 +853,30 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#GOOGLE_ACCOUNT_TYPE">GOOGLE_ACCOUNT_TYPE</a></td>
         <td class="jd-descrcol" width="100%">Google Account type string.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_VISIBLE_ACTIVITIES">KEY_REQUEST_VISIBLE_ACTIVITIES</a></td>
+        <td class="jd-typecol">String</td>
+        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_ACTIONS">KEY_REQUEST_ACTIONS</a></td>
         <td class="jd-descrcol" width="100%">Bundle key for specifying which user's app activity (moment) types can
  be written to Google.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
+        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_VISIBLE_ACTIVITIES">KEY_REQUEST_VISIBLE_ACTIVITIES</a></td>
+        <td class="jd-descrcol" width="100%">See <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_ACTIONS">KEY_REQUEST_ACTIONS</a></code>
+</td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_SUPPRESS_PROGRESS_SCREEN">KEY_SUPPRESS_PROGRESS_SCREEN</a></td>
         <td class="jd-descrcol" width="100%">Adding KEY_SUPPRESS_PROGRESS will suppress the progress screen shown
  when getting a token when added as a boolean <code>true</code> option while
@@ -900,10 +915,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String)">getToken</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String)">getToken</a></span>(Context context, String accountName, String scope)</nobr>
         
         <div class="jd-descrdiv">See <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getToken(Context, String, String, Bundle)</a></code>.</div>
   
@@ -918,10 +933,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getToken</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getToken</a></span>(Context context, String accountName, String scope, Bundle extras)</nobr>
         
         <div class="jd-descrdiv">Gets a token to be consumed by some specified services on behalf of a
  specified user account.</div>
@@ -937,10 +952,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getTokenWithNotification</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getTokenWithNotification</a></span>(Context context, String accountName, String scope, Bundle extras)</nobr>
         
         <div class="jd-descrdiv">Authenticates the user and returns a valid Google authentication token, or throws an
  <code><a href="/reference/java/lang/Exception.html">Exception</a></code> if there was an error while getting the token.</div>
@@ -956,10 +971,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle, android.content.Intent)">getTokenWithNotification</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras, <a href="/reference/android/content/Intent.html">Intent</a> callback)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle, android.content.Intent)">getTokenWithNotification</a></span>(Context context, String accountName, String scope, Bundle extras, Intent callback)</nobr>
         
         <div class="jd-descrdiv">Authenticates the user and returns a valid Google authentication token, or throws an
  <code><a href="/reference/java/lang/Exception.html">Exception</a></code> if there was an error while getting the token.</div>
@@ -975,10 +990,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle, java.lang.String, android.os.Bundle)">getTokenWithNotification</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras, <a href="/reference/java/lang/String.html">String</a> authority, <a href="/reference/android/os/Bundle.html">Bundle</a> syncBundle)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle, java.lang.String, android.os.Bundle)">getTokenWithNotification</a></span>(Context context, String accountName, String scope, Bundle extras, String authority, Bundle syncBundle)</nobr>
         
         <div class="jd-descrdiv">Authenticates the user and returns a valid Google authentication token, or throws an
  <code><a href="/reference/java/lang/Exception.html">Exception</a></code> if there was an error while getting the token.</div>
@@ -997,7 +1012,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#invalidateToken(android.content.Context, java.lang.String)">invalidateToken</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> token)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#invalidateToken(android.content.Context, java.lang.String)">invalidateToken</a></span>(Context context, String token)</nobr>
         
         <div class="jd-descrdiv">Invalidates the specified token with respect to the <code><a href="/reference/android/content/Context.html">Context</a></code>.</div>
   
@@ -1027,7 +1042,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1046,7 +1061,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1065,7 +1080,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1094,7 +1109,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1158,7 +1173,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1257,7 +1272,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         GOOGLE_ACCOUNT_TYPE
     </h4>
@@ -1287,7 +1302,7 @@
 
 
 
-<A NAME="KEY_REQUEST_VISIBLE_ACTIVITIES"></A>
+<A NAME="KEY_REQUEST_ACTIONS"></A>
 
 <div class="jd-details api apilevel-"> 
     <h4 class="jd-details-title">
@@ -1295,9 +1310,9 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
-        KEY_REQUEST_VISIBLE_ACTIVITIES
+        KEY_REQUEST_ACTIONS
     </h4>
       <div class="api-level">
         
@@ -1320,7 +1335,7 @@
  moments</a> for the full list of valid activity types. Example usage:
  <pre>
      Bundle bundle = new Bundle();
-     bundle.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
+     bundle.putString(GoogleAuthUtil.KEY_REQUEST_ACTIONS,
               "http://schemas.google.com/AddActivity http://schemas.google.com/BuyActivity");
      String token = GoogleAuthUtil.getToken(context, accountName, Scopes.PLUS_LOGIN, bundle);
  </pre>
@@ -1341,6 +1356,44 @@
 
 
 
+<A NAME="KEY_REQUEST_VISIBLE_ACTIVITIES"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+        final 
+        String
+      </span>
+        KEY_REQUEST_VISIBLE_ACTIVITIES
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>See <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_ACTIONS">KEY_REQUEST_ACTIONS</a></code>
+</p></div>
+
+    
+        <div class="jd-tagdata">
+        <span class="jd-tagtitle">Constant Value: </span>
+        <span>
+            
+                "request_visible_actions"
+            
+        </span>
+        </div>
+    
+    </div>
+</div>
+
+
+
 <A NAME="KEY_SUPPRESS_PROGRESS_SCREEN"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1349,7 +1402,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_SUPPRESS_PROGRESS_SCREEN
     </h4>
@@ -1412,10 +1465,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getToken</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope)</span>
+      <span class="normal">(Context context, String accountName, String scope)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1431,7 +1484,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td></td>
         </tr>  
         <tr>
@@ -1459,10 +1512,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getToken</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras)</span>
+      <span class="normal">(Context context, String accountName, String scope, Bundle extras)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1575,11 +1628,11 @@
          authentication error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>signaling a potentially transient error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the method is invoked in the main
          event thread.
 </td>
@@ -1601,10 +1654,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTokenWithNotification</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras)</span>
+      <span class="normal">(Context context, String accountName, String scope, Bundle extras)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1684,11 +1737,11 @@
          authentication error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>signaling a potentially transient error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the method is invoked in the main
          event thread.
 </td>
@@ -1710,10 +1763,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTokenWithNotification</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras, <a href="/reference/android/content/Intent.html">Intent</a> callback)</span>
+      <span class="normal">(Context context, String accountName, String scope, Bundle extras, Intent callback)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1802,11 +1855,11 @@
          authentication error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>signaling a potentially transient error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the method is invoked in the main
          event thread.
 </td>
@@ -1828,10 +1881,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTokenWithNotification</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> accountName, <a href="/reference/java/lang/String.html">String</a> scope, <a href="/reference/android/os/Bundle.html">Bundle</a> extras, <a href="/reference/java/lang/String.html">String</a> authority, <a href="/reference/android/os/Bundle.html">Bundle</a> syncBundle)</span>
+      <span class="normal">(Context context, String accountName, String scope, Bundle extras, String authority, Bundle syncBundle)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1924,11 +1977,11 @@
          authentication error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>signaling a potentially transient error.</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the method is invoked in the main
          event thread.
 </td>
@@ -1953,7 +2006,7 @@
         void
       </span>
       <span class="sympad">invalidateToken</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/java/lang/String.html">String</a> token)</span>
+      <span class="normal">(Context context, String token)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html b/docs/html/reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html
index 85b5c5d..9e8b662 100644
--- a/docs/html/reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html
+++ b/docs/html/reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GooglePlayServicesAvailabilityException | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -743,7 +750,7 @@
 
     <tr>
          	
-        <td colspan="6" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="6" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -751,7 +758,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="5" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Throwable</td>
     </tr>
     
 
@@ -761,7 +768,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Exception.html">java.lang.Exception</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Exception</td>
     </tr>
     
 
@@ -943,7 +950,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/auth/UserRecoverableAuthException.html#getIntent()">getIntent</a></span>()</nobr>
@@ -972,7 +979,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a>
+  java.lang.Throwable
 
 <div id="inherited-methods-java.lang.Throwable">
   <div id="inherited-methods-java.lang.Throwable-list"
@@ -991,7 +998,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">fillInStackTrace</span>()</nobr>
@@ -1007,7 +1014,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getCause</span>()</nobr>
@@ -1023,7 +1030,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLocalizedMessage</span>()</nobr>
@@ -1039,7 +1046,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMessage</span>()</nobr>
@@ -1055,7 +1062,7 @@
             
             
             
-            <a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a></nobr>
+            StackTraceElement[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getStackTrace</span>()</nobr>
@@ -1071,10 +1078,10 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initCause</span>(<a href="/reference/java/lang/Throwable.html">Throwable</a> arg0)</nobr>
+        <span class="sympad">initCause</span>(Throwable arg0)</nobr>
         
   </td></tr>
 
@@ -1090,7 +1097,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintWriter arg0)</nobr>
         
   </td></tr>
 
@@ -1106,7 +1113,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintStream.html">PrintStream</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintStream arg0)</nobr>
         
   </td></tr>
 
@@ -1138,7 +1145,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setStackTrace</span>(<a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a> arg0)</nobr>
+        <span class="sympad">setStackTrace</span>(StackTraceElement[] arg0)</nobr>
         
   </td></tr>
 
@@ -1151,7 +1158,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1174,7 +1181,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1193,7 +1200,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1212,7 +1219,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1241,7 +1248,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1305,7 +1312,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/auth/UserRecoverableAuthException.html b/docs/html/reference/com/google/android/gms/auth/UserRecoverableAuthException.html
index 63a17c8..adb15d1 100644
--- a/docs/html/reference/com/google/android/gms/auth/UserRecoverableAuthException.html
+++ b/docs/html/reference/com/google/android/gms/auth/UserRecoverableAuthException.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>UserRecoverableAuthException | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -735,7 +742,7 @@
 
     <tr>
          	
-        <td colspan="5" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -743,7 +750,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Throwable</td>
     </tr>
     
 
@@ -753,7 +760,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Exception.html">java.lang.Exception</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Exception</td>
     </tr>
     
 
@@ -896,7 +903,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/UserRecoverableAuthException.html#UserRecoverableAuthException(java.lang.String, android.content.Intent)">UserRecoverableAuthException</a></span>(<a href="/reference/java/lang/String.html">String</a> msg, <a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/UserRecoverableAuthException.html#UserRecoverableAuthException(java.lang.String, android.content.Intent)">UserRecoverableAuthException</a></span>(String msg, Intent intent)</nobr>
         
   </td></tr>
 
@@ -922,7 +929,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/auth/UserRecoverableAuthException.html#getIntent()">getIntent</a></span>()</nobr>
@@ -959,7 +966,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a>
+  java.lang.Throwable
 
 <div id="inherited-methods-java.lang.Throwable">
   <div id="inherited-methods-java.lang.Throwable-list"
@@ -978,7 +985,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">fillInStackTrace</span>()</nobr>
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getCause</span>()</nobr>
@@ -1010,7 +1017,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLocalizedMessage</span>()</nobr>
@@ -1026,7 +1033,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMessage</span>()</nobr>
@@ -1042,7 +1049,7 @@
             
             
             
-            <a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a></nobr>
+            StackTraceElement[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getStackTrace</span>()</nobr>
@@ -1058,10 +1065,10 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initCause</span>(<a href="/reference/java/lang/Throwable.html">Throwable</a> arg0)</nobr>
+        <span class="sympad">initCause</span>(Throwable arg0)</nobr>
         
   </td></tr>
 
@@ -1077,7 +1084,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintWriter arg0)</nobr>
         
   </td></tr>
 
@@ -1093,7 +1100,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintStream.html">PrintStream</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintStream arg0)</nobr>
         
   </td></tr>
 
@@ -1125,7 +1132,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setStackTrace</span>(<a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a> arg0)</nobr>
+        <span class="sympad">setStackTrace</span>(StackTraceElement[] arg0)</nobr>
         
   </td></tr>
 
@@ -1138,7 +1145,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1161,7 +1168,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1180,7 +1187,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1199,7 +1206,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1228,7 +1235,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1292,7 +1299,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1403,7 +1410,7 @@
         
       </span>
       <span class="sympad">UserRecoverableAuthException</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> msg, <a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(String msg, Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1444,7 +1451,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getIntent</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html b/docs/html/reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html
index eb1315e..27a831e 100644
--- a/docs/html/reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html
+++ b/docs/html/reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>UserRecoverableNotifiedException | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -732,7 +739,7 @@
 
     <tr>
          	
-        <td colspan="5" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -740,7 +747,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Throwable</td>
     </tr>
     
 
@@ -750,7 +757,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Exception.html">java.lang.Exception</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Exception</td>
     </tr>
     
 
@@ -861,7 +868,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html#UserRecoverableNotifiedException(java.lang.String)">UserRecoverableNotifiedException</a></span>(<a href="/reference/java/lang/String.html">String</a> err)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html#UserRecoverableNotifiedException(java.lang.String)">UserRecoverableNotifiedException</a></span>(String err)</nobr>
         
   </td></tr>
 
@@ -897,7 +904,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a>
+  java.lang.Throwable
 
 <div id="inherited-methods-java.lang.Throwable">
   <div id="inherited-methods-java.lang.Throwable-list"
@@ -916,7 +923,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">fillInStackTrace</span>()</nobr>
@@ -932,7 +939,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getCause</span>()</nobr>
@@ -948,7 +955,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLocalizedMessage</span>()</nobr>
@@ -964,7 +971,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMessage</span>()</nobr>
@@ -980,7 +987,7 @@
             
             
             
-            <a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a></nobr>
+            StackTraceElement[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getStackTrace</span>()</nobr>
@@ -996,10 +1003,10 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initCause</span>(<a href="/reference/java/lang/Throwable.html">Throwable</a> arg0)</nobr>
+        <span class="sympad">initCause</span>(Throwable arg0)</nobr>
         
   </td></tr>
 
@@ -1015,7 +1022,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintWriter arg0)</nobr>
         
   </td></tr>
 
@@ -1031,7 +1038,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintStream.html">PrintStream</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintStream arg0)</nobr>
         
   </td></tr>
 
@@ -1063,7 +1070,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setStackTrace</span>(<a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a> arg0)</nobr>
+        <span class="sympad">setStackTrace</span>(StackTraceElement[] arg0)</nobr>
         
   </td></tr>
 
@@ -1076,7 +1083,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1099,7 +1106,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1118,7 +1125,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1137,7 +1144,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1166,7 +1173,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1230,7 +1237,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1341,7 +1348,7 @@
         
       </span>
       <span class="sympad">UserRecoverableNotifiedException</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> err)</span>
+      <span class="normal">(String err)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/auth/package-summary.html b/docs/html/reference/com/google/android/gms/auth/package-summary.html
index d590cbb..324151a 100644
--- a/docs/html/reference/com/google/android/gms/auth/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/auth/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.auth | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -640,6 +647,11 @@
 <div id="jd-content" class="api apilevel-">
 
 
+  <div class="jd-descr">
+    Contains classes for authenticating Google accounts.
+
+  </div>
+
 
 
 
diff --git a/docs/html/reference/com/google/android/gms/common/AccountPicker.html b/docs/html/reference/com/google/android/gms/common/AccountPicker.html
index 36e7efb..1df9195 100644
--- a/docs/html/reference/com/google/android/gms/common/AccountPicker.html
+++ b/docs/html/reference/com/google/android/gms/common/AccountPicker.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>AccountPicker | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -791,10 +798,10 @@
             
             static
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle)">newChooseAccountIntent</a></span>(<a href="/reference/android/accounts/Account.html">Account</a> selectedAccount, <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/accounts/Account.html">Account</a>&gt; allowableAccounts, <a href="/reference/java/lang/String.html">String[]</a> allowableAccountTypes, boolean alwaysPromptForAccount, <a href="/reference/java/lang/String.html">String</a> descriptionOverrideText, <a href="/reference/java/lang/String.html">String</a> addAccountAuthTokenType, <a href="/reference/java/lang/String.html">String[]</a> addAccountRequiredFeatures, <a href="/reference/android/os/Bundle.html">Bundle</a> addAccountOptions)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle)">newChooseAccountIntent</a></span>(Account selectedAccount, ArrayList&lt;Account&gt; allowableAccounts, String[] allowableAccountTypes, boolean alwaysPromptForAccount, String descriptionOverrideText, String addAccountAuthTokenType, String[] addAccountRequiredFeatures, Bundle addAccountOptions)</nobr>
         
         <div class="jd-descrdiv">Returns an intent to an <code><a href="/reference/android/app/Activity.html">Activity</a></code> that prompts the user to choose from a list of
  accounts.</div>
@@ -825,7 +832,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -844,7 +851,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -863,7 +870,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -892,7 +899,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -956,7 +963,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1070,10 +1077,10 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">newChooseAccountIntent</span>
-      <span class="normal">(<a href="/reference/android/accounts/Account.html">Account</a> selectedAccount, <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/accounts/Account.html">Account</a>&gt; allowableAccounts, <a href="/reference/java/lang/String.html">String[]</a> allowableAccountTypes, boolean alwaysPromptForAccount, <a href="/reference/java/lang/String.html">String</a> descriptionOverrideText, <a href="/reference/java/lang/String.html">String</a> addAccountAuthTokenType, <a href="/reference/java/lang/String.html">String[]</a> addAccountRequiredFeatures, <a href="/reference/android/os/Bundle.html">Bundle</a> addAccountOptions)</span>
+      <span class="normal">(Account selectedAccount, ArrayList&lt;Account&gt; allowableAccounts, String[] allowableAccountTypes, boolean alwaysPromptForAccount, String descriptionOverrideText, String addAccountAuthTokenType, String[] addAccountRequiredFeatures, Bundle addAccountOptions)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/common/ConnectionResult.html b/docs/html/reference/com/google/android/gms/common/ConnectionResult.html
index a4d15c8..c328940 100644
--- a/docs/html/reference/com/google/android/gms/common/ConnectionResult.html
+++ b/docs/html/reference/com/google/android/gms/common/ConnectionResult.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ConnectionResult | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -891,7 +898,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/ConnectionResult.html#ConnectionResult(int, android.app.PendingIntent)">ConnectionResult</a></span>(int statusCode, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/ConnectionResult.html#ConnectionResult(int, android.app.PendingIntent)">ConnectionResult</a></span>(int statusCode, PendingIntent pendingIntent)</nobr>
         
         <div class="jd-descrdiv">Creates a connection result.</div>
   
@@ -937,7 +944,7 @@
             
             
             
-            <a href="/reference/android/app/PendingIntent.html">PendingIntent</a></nobr>
+            PendingIntent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/ConnectionResult.html#getResolution()">getResolution</a></span>()</nobr>
@@ -995,7 +1002,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)">startResolutionForResult</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> activity, int requestCode)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)">startResolutionForResult</a></span>(Activity activity, int requestCode)</nobr>
         
         <div class="jd-descrdiv">Resolves an error by starting any intents requiring user
  interaction.</div>
@@ -1011,7 +1018,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/ConnectionResult.html#toString()">toString</a></span>()</nobr>
@@ -1042,7 +1049,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1061,7 +1068,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1080,7 +1087,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1109,7 +1116,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1173,7 +1180,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1777,7 +1784,7 @@
         
       </span>
       <span class="sympad">ConnectionResult</span>
-      <span class="normal">(int statusCode, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent)</span>
+      <span class="normal">(int statusCode, PendingIntent pendingIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1866,7 +1873,7 @@
          
          
          
-        <a href="/reference/android/app/PendingIntent.html">PendingIntent</a>
+        PendingIntent
       </span>
       <span class="sympad">getResolution</span>
       <span class="normal">()</span>
@@ -1974,7 +1981,7 @@
         void
       </span>
       <span class="sympad">startResolutionForResult</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> activity, int requestCode)</span>
+      <span class="normal">(Activity activity, int requestCode)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2007,7 +2014,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/android/content/IntentSender.SendIntentException.html">IntentSender.SendIntentException</a></td>
+            <th>IntentSender.SendIntentException</td>
             <td>If the resolution intent has been canceled or is
              no longer able to execute the request.
 </td>
@@ -2029,7 +2036,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html
index 09730fa..1a94bdf 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GooglePlayServicesClient.ConnectionCallbacks | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -754,7 +761,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> connectionHint)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected</a></span>(Bundle connectionHint)</nobr>
         
         <div class="jd-descrdiv">After calling <code><a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.html#connect()">connect()</a></code>, this method will be invoked
  asynchronously when the connect request has successfully completed.</div>
@@ -841,7 +848,7 @@
         void
       </span>
       <span class="sympad">onConnected</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> connectionHint)</span>
+      <span class="normal">(Bundle connectionHint)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html
index 8dd96c2..d08ec34 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GooglePlayServicesClient.OnConnectionFailedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
index e768c22..ff860ba 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GooglePlayServicesClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html
index a7ed6db..e62abed 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GooglePlayServicesNotAvailableException | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -706,7 +713,7 @@
   
 
   
-    extends <a href="/reference/java/lang/Exception.html">Exception</a><br/>
+    extends Exception<br/>
   
   
   
@@ -726,7 +733,7 @@
 
     <tr>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -734,7 +741,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Throwable</td>
     </tr>
     
 
@@ -744,7 +751,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Exception.html">java.lang.Exception</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Exception</td>
     </tr>
     
 
@@ -894,7 +901,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a>
+  java.lang.Throwable
 
 <div id="inherited-methods-java.lang.Throwable">
   <div id="inherited-methods-java.lang.Throwable-list"
@@ -913,7 +920,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">fillInStackTrace</span>()</nobr>
@@ -929,7 +936,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getCause</span>()</nobr>
@@ -945,7 +952,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLocalizedMessage</span>()</nobr>
@@ -961,7 +968,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMessage</span>()</nobr>
@@ -977,7 +984,7 @@
             
             
             
-            <a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a></nobr>
+            StackTraceElement[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getStackTrace</span>()</nobr>
@@ -993,10 +1000,10 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initCause</span>(<a href="/reference/java/lang/Throwable.html">Throwable</a> arg0)</nobr>
+        <span class="sympad">initCause</span>(Throwable arg0)</nobr>
         
   </td></tr>
 
@@ -1012,7 +1019,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintWriter arg0)</nobr>
         
   </td></tr>
 
@@ -1028,7 +1035,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintStream.html">PrintStream</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintStream arg0)</nobr>
         
   </td></tr>
 
@@ -1060,7 +1067,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setStackTrace</span>(<a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a> arg0)</nobr>
+        <span class="sympad">setStackTrace</span>(StackTraceElement[] arg0)</nobr>
         
   </td></tr>
 
@@ -1073,7 +1080,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1096,7 +1103,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1115,7 +1122,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1134,7 +1141,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1163,7 +1170,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1227,7 +1234,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesUtil.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesUtil.html
index 12b8b1b..be1e46d 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesUtil.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesUtil.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GooglePlayServicesUtil | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -775,7 +782,7 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#GOOGLE_PLAY_SERVICES_PACKAGE">GOOGLE_PLAY_SERVICES_PACKAGE</a></td>
         <td class="jd-descrcol" width="100%">Package name for Google Play services.</td>
     </tr>
@@ -790,7 +797,7 @@
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#GOOGLE_PLAY_STORE_PACKAGE">GOOGLE_PLAY_STORE_PACKAGE</a></td>
         <td class="jd-descrcol" width="100%">Package name for Google Play services.</td>
     </tr>
@@ -827,10 +834,10 @@
             
             static
             
-            <a href="/reference/android/app/Dialog.html">Dialog</a></nobr>
+            Dialog</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int, android.content.DialogInterface.OnCancelListener)">getErrorDialog</a></span>(int errorCode, <a href="/reference/android/app/Activity.html">Activity</a> activity, int requestCode, <a href="/reference/android/content/DialogInterface.OnCancelListener.html">DialogInterface.OnCancelListener</a> cancelListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int, android.content.DialogInterface.OnCancelListener)">getErrorDialog</a></span>(int errorCode, Activity activity, int requestCode, DialogInterface.OnCancelListener cancelListener)</nobr>
         
         <div class="jd-descrdiv">Returns a dialog to address the provided errorCode.</div>
   
@@ -845,10 +852,10 @@
             
             static
             
-            <a href="/reference/android/app/Dialog.html">Dialog</a></nobr>
+            Dialog</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">getErrorDialog</a></span>(int errorCode, <a href="/reference/android/app/Activity.html">Activity</a> activity, int requestCode)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">getErrorDialog</a></span>(int errorCode, Activity activity, int requestCode)</nobr>
         
         <div class="jd-descrdiv">Returns a dialog to address the provided errorCode.</div>
   
@@ -863,10 +870,10 @@
             
             static
             
-            <a href="/reference/android/app/PendingIntent.html">PendingIntent</a></nobr>
+            PendingIntent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorPendingIntent(int, android.content.Context, int)">getErrorPendingIntent</a></span>(int errorCode, <a href="/reference/android/content/Context.html">Context</a> context, int requestCode)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorPendingIntent(int, android.content.Context, int)">getErrorPendingIntent</a></span>(int errorCode, Context context, int requestCode)</nobr>
         
         <div class="jd-descrdiv">Returns a PendingIntent to address the provided errorCode.</div>
   
@@ -881,7 +888,7 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorString(int)">getErrorString</a></span>(int errorCode)</nobr>
@@ -900,10 +907,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getOpenSourceSoftwareLicenseInfo(android.content.Context)">getOpenSourceSoftwareLicenseInfo</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getOpenSourceSoftwareLicenseInfo(android.content.Context)">getOpenSourceSoftwareLicenseInfo</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Returns the open source software license information for the Google Play services
  application, or null if Google Play services is not available on this device.</div>
@@ -919,10 +926,10 @@
             
             static
             
-            <a href="/reference/android/content/Context.html">Context</a></nobr>
+            Context</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getRemoteContext(android.content.Context)">getRemoteContext</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getRemoteContext(android.content.Context)">getRemoteContext</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">This gets the Context object of the Buddy APK.</div>
   
@@ -937,10 +944,10 @@
             
             static
             
-            <a href="/reference/android/content/res/Resources.html">Resources</a></nobr>
+            Resources</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getRemoteResource(android.content.Context)">getRemoteResource</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getRemoteResource(android.content.Context)">getRemoteResource</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">This gets the Resources object of the Buddy APK.</div>
   
@@ -958,7 +965,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">isGooglePlayServicesAvailable</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">isGooglePlayServicesAvailable</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Verifies that Google Play services is installed and enabled on this device, and that the
  version installed on this device is no older than the one required by this client.</div>
@@ -1007,7 +1014,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1026,7 +1033,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1045,7 +1052,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1074,7 +1081,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1138,7 +1145,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1237,7 +1244,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         GOOGLE_PLAY_SERVICES_PACKAGE
     </h4>
@@ -1296,8 +1303,8 @@
         <span class="jd-tagtitle">Constant Value: </span>
         <span>
             
-                3225000
-                (0x003135a8)
+                3265000
+                (0x0031d1e8)
             
         </span>
         </div>
@@ -1315,7 +1322,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         GOOGLE_PLAY_STORE_PACKAGE
     </h4>
@@ -1375,10 +1382,10 @@
          
          
          
-        <a href="/reference/android/app/Dialog.html">Dialog</a>
+        Dialog
       </span>
       <span class="sympad">getErrorDialog</span>
-      <span class="normal">(int errorCode, <a href="/reference/android/app/Activity.html">Activity</a> activity, int requestCode, <a href="/reference/android/content/DialogInterface.OnCancelListener.html">DialogInterface.OnCancelListener</a> cancelListener)</span>
+      <span class="normal">(int errorCode, Activity activity, int requestCode, DialogInterface.OnCancelListener cancelListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1432,10 +1439,10 @@
          
          
          
-        <a href="/reference/android/app/Dialog.html">Dialog</a>
+        Dialog
       </span>
       <span class="sympad">getErrorDialog</span>
-      <span class="normal">(int errorCode, <a href="/reference/android/app/Activity.html">Activity</a> activity, int requestCode)</span>
+      <span class="normal">(int errorCode, Activity activity, int requestCode)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1484,10 +1491,10 @@
          
          
          
-        <a href="/reference/android/app/PendingIntent.html">PendingIntent</a>
+        PendingIntent
       </span>
       <span class="sympad">getErrorPendingIntent</span>
-      <span class="normal">(int errorCode, <a href="/reference/android/content/Context.html">Context</a> context, int requestCode)</span>
+      <span class="normal">(int errorCode, Context context, int requestCode)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1534,7 +1541,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getErrorString</span>
       <span class="normal">(int errorCode)</span>
@@ -1565,10 +1572,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getOpenSourceSoftwareLicenseInfo</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1596,10 +1603,10 @@
          
          
          
-        <a href="/reference/android/content/Context.html">Context</a>
+        Context
       </span>
       <span class="sympad">getRemoteContext</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1633,10 +1640,10 @@
          
          
          
-        <a href="/reference/android/content/res/Resources.html">Resources</a>
+        Resources
       </span>
       <span class="sympad">getRemoteResource</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1671,7 +1678,7 @@
         int
       </span>
       <span class="sympad">isGooglePlayServicesAvailable</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/common/Scopes.html b/docs/html/reference/com/google/android/gms/common/Scopes.html
index 04d9531..bee6716 100644
--- a/docs/html/reference/com/google/android/gms/common/Scopes.html
+++ b/docs/html/reference/com/google/android/gms/common/Scopes.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Scopes | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -770,21 +777,21 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/common/Scopes.html#APP_STATE">APP_STATE</a></td>
         <td class="jd-descrcol" width="100%">Scope for using the App State service.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/common/Scopes.html#GAMES">GAMES</a></td>
         <td class="jd-descrcol" width="100%">Scope for accessing data from Google Play Games.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_LOGIN">PLUS_LOGIN</a></td>
         <td class="jd-descrcol" width="100%">OAuth 2.0 scope for accessing the user's name, basic profile info, list of people in the
  user's circles, and writing app activities to Google.</td>
@@ -792,7 +799,7 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_PROFILE">PLUS_PROFILE</a></td>
         <td class="jd-descrcol" width="100%">OAuth 2.0 scope for accessing the user's Google+ profile data.</td>
     </tr>
@@ -835,7 +842,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -854,7 +861,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -873,7 +880,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -902,7 +909,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -966,7 +973,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1065,7 +1072,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         APP_STATE
     </h4>
@@ -1103,7 +1110,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         GAMES
     </h4>
@@ -1141,7 +1148,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         PLUS_LOGIN
     </h4>
@@ -1188,7 +1195,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         PLUS_PROFILE
     </h4>
diff --git a/docs/html/reference/com/google/android/gms/common/SignInButton.html b/docs/html/reference/com/google/android/gms/common/SignInButton.html
index f3b4257..c4d73bb 100644
--- a/docs/html/reference/com/google/android/gms/common/SignInButton.html
+++ b/docs/html/reference/com/google/android/gms/common/SignInButton.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>SignInButton | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -771,7 +778,7 @@
   
 
   
-    extends <a href="/reference/android/widget/FrameLayout.html">FrameLayout</a><br/>
+    extends FrameLayout<br/>
   
   
   
@@ -780,7 +787,7 @@
   
       implements 
       
-        <a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> 
+        View.OnClickListener 
       
   
   
@@ -796,7 +803,7 @@
 
     <tr>
          	
-        <td colspan="5" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -804,7 +811,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/android/view/View.html">android.view.View</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">android.view.View</td>
     </tr>
     
 
@@ -814,7 +821,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/android/view/ViewGroup.html">android.view.ViewGroup</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">android.view.ViewGroup</td>
     </tr>
     
 
@@ -826,7 +833,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/android/widget/FrameLayout.html">android.widget.FrameLayout</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">android.widget.FrameLayout</td>
     </tr>
     
 
@@ -1426,7 +1433,7 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol">VIEW_LOG_TAG</td>
         <td class="jd-descrcol" width="100%"></td>
     </tr>
@@ -1499,7 +1506,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ALPHA</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1818,7 +1825,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1829,7 +1836,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1840,7 +1847,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1851,7 +1858,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">SCALE_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1862,7 +1869,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">SCALE_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1895,7 +1902,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">TRANSLATION_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1906,7 +1913,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">TRANSLATION_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1928,7 +1935,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1939,7 +1946,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1986,7 +1993,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#SignInButton(android.content.Context)">SignInButton</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#SignInButton(android.content.Context)">SignInButton</a></span>(Context context)</nobr>
         
   </td></tr>
 
@@ -2002,7 +2009,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#SignInButton(android.content.Context, android.util.AttributeSet)">SignInButton</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#SignInButton(android.content.Context, android.util.AttributeSet)">SignInButton</a></span>(Context context, AttributeSet attrs)</nobr>
         
   </td></tr>
 
@@ -2018,7 +2025,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#SignInButton(android.content.Context, android.util.AttributeSet, int)">SignInButton</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, int defStyle)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#SignInButton(android.content.Context, android.util.AttributeSet, int)">SignInButton</a></span>(Context context, AttributeSet attrs, int defStyle)</nobr>
         
   </td></tr>
 
@@ -2047,7 +2054,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#onClick(android.view.View)">onClick</a></span>(<a href="/reference/android/view/View.html">View</a> view)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#onClick(android.view.View)">onClick</a></span>(View view)</nobr>
         
   </td></tr>
 
@@ -2097,7 +2104,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#setOnClickListener(android.view.View.OnClickListener)">setOnClickListener</a></span>(<a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> listener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/SignInButton.html#setOnClickListener(android.view.View.OnClickListener)">setOnClickListener</a></span>(View.OnClickListener listener)</nobr>
         
   </td></tr>
 
@@ -2161,7 +2168,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/widget/FrameLayout.html">android.widget.FrameLayout</a>
+  android.widget.FrameLayout
 
 <div id="inherited-methods-android.widget.FrameLayout">
   <div id="inherited-methods-android.widget.FrameLayout-list"
@@ -2183,7 +2190,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2199,7 +2206,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">draw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -2231,7 +2238,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">gatherTransparentRegion</span>(<a href="/reference/android/graphics/Region.html">Region</a> arg0)</nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
         
   </td></tr>
 
@@ -2244,7 +2251,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
@@ -2260,10 +2267,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
         
   </td></tr>
 
@@ -2276,10 +2283,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2308,7 +2315,7 @@
             
             
             
-            <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a></nobr>
+            Drawable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getForeground</span>()</nobr>
@@ -2375,7 +2382,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInitializeAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2455,7 +2462,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setForeground</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setForeground</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -2519,7 +2526,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">verifyDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -2539,7 +2546,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/view/ViewGroup.html">android.view.ViewGroup</a>
+  android.view.ViewGroup
 
 <div id="inherited-methods-android.view.ViewGroup">
   <div id="inherited-methods-android.view.ViewGroup-list"
@@ -2561,7 +2568,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addChildrenForAccessibility</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2577,7 +2584,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -2609,7 +2616,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addTouchables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2625,7 +2632,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2641,7 +2648,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -2657,7 +2664,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2673,7 +2680,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">addView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2689,7 +2696,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -2705,7 +2712,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2, boolean arg3)</nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2, boolean arg3)</nobr>
         
   </td></tr>
 
@@ -2721,7 +2728,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2737,7 +2744,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">attachLayoutAnimationParameters</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1, int arg2, int arg3)</nobr>
+        <span class="sympad">attachLayoutAnimationParameters</span>(View arg0, ViewGroup.LayoutParams arg1, int arg2, int arg3)</nobr>
         
   </td></tr>
 
@@ -2753,7 +2760,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">attachViewToParent</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">attachViewToParent</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2769,7 +2776,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">bringChildToFront</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2801,7 +2808,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2817,7 +2824,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">childDrawableStateChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2833,7 +2840,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">cleanupLayoutState</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">cleanupLayoutState</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2849,7 +2856,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clearChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2929,7 +2936,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">detachViewFromParent</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">detachViewFromParent</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2977,7 +2984,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -3025,7 +3032,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -3041,7 +3048,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchFreezeSelfOnly</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchFreezeSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3057,7 +3064,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericFocusedEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3073,7 +3080,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericPointerEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3089,7 +3096,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3105,7 +3112,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3121,7 +3128,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEventPreIme</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3137,7 +3144,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyShortcutEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3153,7 +3160,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchRestoreInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3169,7 +3176,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchSaveInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3249,7 +3256,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchThawSelfOnly</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchThawSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3265,7 +3272,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3281,7 +3288,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3297,7 +3304,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchUnhandledMove</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3313,7 +3320,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3377,7 +3384,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">drawChild</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, long arg2)</nobr>
+        <span class="sympad">drawChild</span>(Canvas arg0, View arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -3409,7 +3416,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">endViewTransition</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">endViewTransition</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3422,7 +3429,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findFocus</span>()</nobr>
@@ -3441,7 +3448,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewsWithText</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, <a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg1, int arg2)</nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -3457,7 +3464,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">fitSystemWindows</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -3470,10 +3477,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusSearch</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3489,7 +3496,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusableViewAvailable</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3505,7 +3512,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">gatherTransparentRegion</span>(<a href="/reference/android/graphics/Region.html">Region</a> arg0)</nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
         
   </td></tr>
 
@@ -3518,7 +3525,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
@@ -3534,10 +3541,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
         
   </td></tr>
 
@@ -3550,10 +3557,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -3566,7 +3573,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getChildAt</span>(int arg0)</nobr>
@@ -3633,7 +3640,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildStaticTransformation</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/animation/Transformation.html">Transformation</a> arg1)</nobr>
+        <span class="sympad">getChildStaticTransformation</span>(View arg0, Transformation arg1)</nobr>
         
   </td></tr>
 
@@ -3649,7 +3656,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildVisibleRect</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, <a href="/reference/android/graphics/Point.html">Point</a> arg2)</nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
         
   </td></tr>
 
@@ -3678,7 +3685,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getFocusedChild</span>()</nobr>
@@ -3694,7 +3701,7 @@
             
             
             
-            <a href="/reference/android/view/animation/LayoutAnimationController.html">LayoutAnimationController</a></nobr>
+            LayoutAnimationController</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutAnimation</span>()</nobr>
@@ -3710,7 +3717,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.AnimationListener.html">Animation.AnimationListener</a></nobr>
+            Animation.AnimationListener</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutAnimationListener</span>()</nobr>
@@ -3793,7 +3800,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">indexOfChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">indexOfChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3809,7 +3816,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3822,10 +3829,10 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChildInParent</span>(int[] arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3953,7 +3960,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">measureChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">measureChild</span>(View arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -3969,7 +3976,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">measureChildWithMargins</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        <span class="sympad">measureChildWithMargins</span>(View arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
         
   </td></tr>
 
@@ -4001,7 +4008,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">offsetDescendantRectToMyCoords</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">offsetDescendantRectToMyCoords</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4017,7 +4024,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">offsetRectIntoDescendantCoords</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">offsetRectIntoDescendantCoords</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4081,7 +4088,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInterceptHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onInterceptHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -4097,7 +4104,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInterceptTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onInterceptTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -4129,7 +4136,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4145,7 +4152,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRequestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">onRequestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -4161,7 +4168,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">recomputeViewAttributes</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4209,7 +4216,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeDetachedView</span>(<a href="/reference/android/view/View.html">View</a> arg0, boolean arg1)</nobr>
+        <span class="sympad">removeDetachedView</span>(View arg0, boolean arg1)</nobr>
         
   </td></tr>
 
@@ -4225,7 +4232,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4257,7 +4264,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeViewInLayout</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4305,7 +4312,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1)</nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
         
   </td></tr>
 
@@ -4321,7 +4328,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildRectangleOnScreen</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, boolean arg2)</nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
         
   </td></tr>
 
@@ -4353,7 +4360,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestFocus</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4369,7 +4376,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -4385,7 +4392,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestTransparentRegion</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4561,7 +4568,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutAnimation</span>(<a href="/reference/android/view/animation/LayoutAnimationController.html">LayoutAnimationController</a> arg0)</nobr>
+        <span class="sympad">setLayoutAnimation</span>(LayoutAnimationController arg0)</nobr>
         
   </td></tr>
 
@@ -4577,7 +4584,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutAnimationListener</span>(<a href="/reference/android/view/animation/Animation.AnimationListener.html">Animation.AnimationListener</a> arg0)</nobr>
+        <span class="sympad">setLayoutAnimationListener</span>(Animation.AnimationListener arg0)</nobr>
         
   </td></tr>
 
@@ -4625,7 +4632,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnHierarchyChangeListener</span>(<a href="/reference/android/view/ViewGroup.OnHierarchyChangeListener.html">ViewGroup.OnHierarchyChangeListener</a> arg0)</nobr>
+        <span class="sympad">setOnHierarchyChangeListener</span>(ViewGroup.OnHierarchyChangeListener arg0)</nobr>
         
   </td></tr>
 
@@ -4705,7 +4712,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">showContextMenuForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4721,7 +4728,7 @@
             ActionMode</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActionModeForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, ActionMode.Callback arg1)</nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
         
   </td></tr>
 
@@ -4753,7 +4760,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startViewTransition</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">startViewTransition</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4769,7 +4776,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">updateViewLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -4789,7 +4796,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/view/View.html">android.view.View</a>
+  android.view.View
 
 <div id="inherited-methods-android.view.View">
   <div id="inherited-methods-android.view.View-list"
@@ -4811,7 +4818,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addChildrenForAccessibility</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -4827,7 +4834,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -4843,7 +4850,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -4891,7 +4898,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addTouchables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -4923,7 +4930,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">announceForAccessibility</span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg0)</nobr>
+        <span class="sympad">announceForAccessibility</span>(CharSequence arg0)</nobr>
         
   </td></tr>
 
@@ -5115,7 +5122,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkInputConnectionProxy</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">checkInputConnectionProxy</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -5307,7 +5314,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">createContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -5339,7 +5346,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -5387,7 +5394,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -5403,7 +5410,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericFocusedEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5419,7 +5426,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericMotionEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericMotionEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5435,7 +5442,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericPointerEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5451,7 +5458,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5467,7 +5474,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5483,7 +5490,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEventPreIme</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5499,7 +5506,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyShortcutEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5515,7 +5522,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5531,7 +5538,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchRestoreInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -5547,7 +5554,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchSaveInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -5627,7 +5634,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5643,7 +5650,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5659,7 +5666,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchUnhandledMove</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -5675,7 +5682,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -5739,7 +5746,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">draw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -5768,7 +5775,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findFocus</span>()</nobr>
@@ -5784,7 +5791,7 @@
             final
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findViewById</span>(int arg0)</nobr>
@@ -5800,10 +5807,10 @@
             final
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewWithTag</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">findViewWithTag</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -5819,7 +5826,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewsWithText</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, <a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg1, int arg2)</nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -5835,7 +5842,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">fitSystemWindows</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -5848,7 +5855,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">focusSearch</span>(int arg0)</nobr>
@@ -5912,7 +5919,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.html">Animation</a></nobr>
+            Animation</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getAnimation</span>()</nobr>
@@ -5928,7 +5935,7 @@
             
             
             
-            <a href="/reference/android/os/IBinder.html">IBinder</a></nobr>
+            IBinder</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getApplicationWindowToken</span>()</nobr>
@@ -5944,7 +5951,7 @@
             
             
             
-            <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a></nobr>
+            Drawable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getBackground</span>()</nobr>
@@ -6040,7 +6047,7 @@
             
             
             
-            <a href="/reference/java/lang/CharSequence.html">CharSequence</a></nobr>
+            CharSequence</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContentDescription</span>()</nobr>
@@ -6056,7 +6063,7 @@
             final
             
             
-            <a href="/reference/android/content/Context.html">Context</a></nobr>
+            Context</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContext</span>()</nobr>
@@ -6072,7 +6079,7 @@
             
             
             
-            <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a></nobr>
+            ContextMenu.ContextMenuInfo</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContextMenuInfo</span>()</nobr>
@@ -6120,7 +6127,7 @@
             
             
             
-            <a href="/reference/android/graphics/Bitmap.html">Bitmap</a></nobr>
+            Bitmap</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getDrawingCache</span>(boolean arg0)</nobr>
@@ -6136,7 +6143,7 @@
             
             
             
-            <a href="/reference/android/graphics/Bitmap.html">Bitmap</a></nobr>
+            Bitmap</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getDrawingCache</span>()</nobr>
@@ -6187,7 +6194,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getDrawingRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getDrawingRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6248,7 +6255,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt;</nobr>
+            ArrayList&lt;View&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getFocusables</span>(int arg0)</nobr>
@@ -6267,7 +6274,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getFocusedRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getFocusedRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6283,7 +6290,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getGlobalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0, <a href="/reference/android/graphics/Point.html">Point</a> arg1)</nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0, Point arg1)</nobr>
         
   </td></tr>
 
@@ -6299,7 +6306,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getGlobalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6312,7 +6319,7 @@
             
             
             
-            <a href="/reference/android/os/Handler.html">Handler</a></nobr>
+            Handler</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getHandler</span>()</nobr>
@@ -6347,7 +6354,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getHitRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getHitRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6440,7 +6447,7 @@
             
             
             
-            <a href="/reference/android/view/KeyEvent.DispatcherState.html">KeyEvent.DispatcherState</a></nobr>
+            KeyEvent.DispatcherState</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getKeyDispatcherState</span>()</nobr>
@@ -6472,7 +6479,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutParams</span>()</nobr>
@@ -6539,7 +6546,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getLocalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getLocalVisibleRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6584,7 +6591,7 @@
             
             
             
-            <a href="/reference/android/graphics/Matrix.html">Matrix</a></nobr>
+            Matrix</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMatrix</span>()</nobr>
@@ -6792,7 +6799,7 @@
             
             
             
-            <a href="/reference/android/view/View.OnFocusChangeListener.html">View.OnFocusChangeListener</a></nobr>
+            View.OnFocusChangeListener</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getOnFocusChangeListener</span>()</nobr>
@@ -6888,7 +6895,7 @@
             final
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParent</span>()</nobr>
@@ -6904,7 +6911,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParentForAccessibility</span>()</nobr>
@@ -6952,7 +6959,7 @@
             
             
             
-            <a href="/reference/android/content/res/Resources.html">Resources</a></nobr>
+            Resources</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getResources</span>()</nobr>
@@ -7016,7 +7023,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getRootView</span>()</nobr>
@@ -7272,7 +7279,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>(int arg0)</nobr>
@@ -7288,7 +7295,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>()</nobr>
@@ -7352,7 +7359,7 @@
             
             
             
-            <a href="/reference/android/view/TouchDelegate.html">TouchDelegate</a></nobr>
+            TouchDelegate</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTouchDelegate</span>()</nobr>
@@ -7368,7 +7375,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt;</nobr>
+            ArrayList&lt;View&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTouchables</span>()</nobr>
@@ -7464,7 +7471,7 @@
             
             
             
-            <a href="/reference/android/view/ViewTreeObserver.html">ViewTreeObserver</a></nobr>
+            ViewTreeObserver</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getViewTreeObserver</span>()</nobr>
@@ -7544,7 +7551,7 @@
             
             
             
-            <a href="/reference/android/os/IBinder.html">IBinder</a></nobr>
+            IBinder</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getWindowToken</span>()</nobr>
@@ -7579,7 +7586,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getWindowVisibleDisplayFrame</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getWindowVisibleDisplayFrame</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -7720,10 +7727,10 @@
             
             static
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">inflate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> arg2)</nobr>
+        <span class="sympad">inflate</span>(Context arg0, int arg1, ViewGroup arg2)</nobr>
         
   </td></tr>
 
@@ -7739,7 +7746,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initializeFadingEdge</span>(<a href="/reference/android/content/res/TypedArray.html">TypedArray</a> arg0)</nobr>
+        <span class="sympad">initializeFadingEdge</span>(TypedArray arg0)</nobr>
         
   </td></tr>
 
@@ -7755,7 +7762,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initializeScrollbars</span>(<a href="/reference/android/content/res/TypedArray.html">TypedArray</a> arg0)</nobr>
+        <span class="sympad">initializeScrollbars</span>(TypedArray arg0)</nobr>
         
   </td></tr>
 
@@ -7771,7 +7778,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidate</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">invalidate</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -7819,7 +7826,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -8475,7 +8482,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -8491,7 +8498,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -8520,10 +8527,10 @@
             
             
             
-            <a href="/reference/android/view/inputmethod/InputConnection.html">InputConnection</a></nobr>
+            InputConnection</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateInputConnection</span>(<a href="/reference/android/view/inputmethod/EditorInfo.html">EditorInfo</a> arg0)</nobr>
+        <span class="sympad">onCreateInputConnection</span>(EditorInfo arg0)</nobr>
         
   </td></tr>
 
@@ -8587,7 +8594,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">onDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -8603,7 +8610,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onDrawScrollBars</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">onDrawScrollBars</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -8619,7 +8626,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onFilterTouchEventForSecurity</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onFilterTouchEventForSecurity</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8667,7 +8674,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, <a href="/reference/android/graphics/Rect.html">Rect</a> arg2)</nobr>
+        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, Rect arg2)</nobr>
         
   </td></tr>
 
@@ -8683,7 +8690,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onGenericMotionEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onGenericMotionEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8715,7 +8722,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8731,7 +8738,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInitializeAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8763,7 +8770,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyDown</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8779,7 +8786,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyLongPress</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8795,7 +8802,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg2)</nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
         
   </td></tr>
 
@@ -8811,7 +8818,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyPreIme</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyPreIme</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8827,7 +8834,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyShortcut</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyShortcut</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8843,7 +8850,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyUp</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8907,7 +8914,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onPopulateAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8923,7 +8930,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRestoreInstanceState</span>(<a href="/reference/android/os/Parcelable.html">Parcelable</a> arg0)</nobr>
+        <span class="sympad">onRestoreInstanceState</span>(Parcelable arg0)</nobr>
         
   </td></tr>
 
@@ -8936,7 +8943,7 @@
             
             
             
-            <a href="/reference/android/os/Parcelable.html">Parcelable</a></nobr>
+            Parcelable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">onSaveInstanceState</span>()</nobr>
@@ -9035,7 +9042,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9051,7 +9058,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9067,7 +9074,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">onVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -9147,7 +9154,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">performAccessibilityAction</span>(int arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">performAccessibilityAction</span>(int arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -9243,7 +9250,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">post</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">post</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9259,7 +9266,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postDelayed</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0, long arg1)</nobr>
+        <span class="sympad">postDelayed</span>(Runnable arg0, long arg1)</nobr>
         
   </td></tr>
 
@@ -9371,7 +9378,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postOnAnimation</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">postOnAnimation</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9387,7 +9394,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postOnAnimationDelayed</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0, long arg1)</nobr>
+        <span class="sympad">postOnAnimationDelayed</span>(Runnable arg0, long arg1)</nobr>
         
   </td></tr>
 
@@ -9419,7 +9426,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeCallbacks</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">removeCallbacks</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9483,7 +9490,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestFocus</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -9563,7 +9570,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestRectangleOnScreen</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -9579,7 +9586,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestRectangleOnScreen</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0, boolean arg1)</nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0, boolean arg1)</nobr>
         
   </td></tr>
 
@@ -9627,7 +9634,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">restoreHierarchyState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">restoreHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -9643,7 +9650,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">saveHierarchyState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">saveHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -9659,7 +9666,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">scheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1, long arg2)</nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -9723,7 +9730,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">sendAccessibilityEventUnchecked</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9787,7 +9794,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setAnimation</span>(<a href="/reference/android/view/animation/Animation.html">Animation</a> arg0)</nobr>
+        <span class="sympad">setAnimation</span>(Animation arg0)</nobr>
         
   </td></tr>
 
@@ -9803,7 +9810,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setBackground</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setBackground</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -9835,7 +9842,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setBackgroundDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setBackgroundDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -9915,7 +9922,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setContentDescription</span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg0)</nobr>
+        <span class="sympad">setContentDescription</span>(CharSequence arg0)</nobr>
         
   </td></tr>
 
@@ -10219,7 +10226,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayerType</span>(int arg0, <a href="/reference/android/graphics/Paint.html">Paint</a> arg1)</nobr>
+        <span class="sympad">setLayerType</span>(int arg0, Paint arg1)</nobr>
         
   </td></tr>
 
@@ -10235,7 +10242,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">setLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -10411,7 +10418,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnClickListener</span>(<a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> arg0)</nobr>
+        <span class="sympad">setOnClickListener</span>(View.OnClickListener arg0)</nobr>
         
   </td></tr>
 
@@ -10427,7 +10434,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnCreateContextMenuListener</span>(<a href="/reference/android/view/View.OnCreateContextMenuListener.html">View.OnCreateContextMenuListener</a> arg0)</nobr>
+        <span class="sympad">setOnCreateContextMenuListener</span>(View.OnCreateContextMenuListener arg0)</nobr>
         
   </td></tr>
 
@@ -10459,7 +10466,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnFocusChangeListener</span>(<a href="/reference/android/view/View.OnFocusChangeListener.html">View.OnFocusChangeListener</a> arg0)</nobr>
+        <span class="sympad">setOnFocusChangeListener</span>(View.OnFocusChangeListener arg0)</nobr>
         
   </td></tr>
 
@@ -10507,7 +10514,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnKeyListener</span>(<a href="/reference/android/view/View.OnKeyListener.html">View.OnKeyListener</a> arg0)</nobr>
+        <span class="sympad">setOnKeyListener</span>(View.OnKeyListener arg0)</nobr>
         
   </td></tr>
 
@@ -10523,7 +10530,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnLongClickListener</span>(<a href="/reference/android/view/View.OnLongClickListener.html">View.OnLongClickListener</a> arg0)</nobr>
+        <span class="sympad">setOnLongClickListener</span>(View.OnLongClickListener arg0)</nobr>
         
   </td></tr>
 
@@ -10555,7 +10562,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnTouchListener</span>(<a href="/reference/android/view/View.OnTouchListener.html">View.OnTouchListener</a> arg0)</nobr>
+        <span class="sympad">setOnTouchListener</span>(View.OnTouchListener arg0)</nobr>
         
   </td></tr>
 
@@ -10955,7 +10962,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTag</span>(int arg0, <a href="/reference/java/lang/Object.html">Object</a> arg1)</nobr>
+        <span class="sympad">setTag</span>(int arg0, Object arg1)</nobr>
         
   </td></tr>
 
@@ -10971,7 +10978,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTag</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">setTag</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -11003,7 +11010,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTouchDelegate</span>(<a href="/reference/android/view/TouchDelegate.html">TouchDelegate</a> arg0)</nobr>
+        <span class="sympad">setTouchDelegate</span>(TouchDelegate arg0)</nobr>
         
   </td></tr>
 
@@ -11211,7 +11218,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startAnimation</span>(<a href="/reference/android/view/animation/Animation.html">Animation</a> arg0)</nobr>
+        <span class="sympad">startAnimation</span>(Animation arg0)</nobr>
         
   </td></tr>
 
@@ -11227,7 +11234,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, <a href="/reference/java/lang/Object.html">Object</a> arg2, int arg3)</nobr>
+        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, Object arg2, int arg3)</nobr>
         
   </td></tr>
 
@@ -11243,7 +11250,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11259,7 +11266,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
         
   </td></tr>
 
@@ -11275,7 +11282,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">verifyDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11327,7 +11334,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -11346,7 +11353,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -11365,7 +11372,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -11394,7 +11401,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -11458,7 +11465,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -11529,7 +11536,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/graphics/drawable/Drawable.Callback.html">android.graphics.drawable.Drawable.Callback</a>
+  android.graphics.drawable.Drawable.Callback
 
 <div id="inherited-methods-android.graphics.drawable.Drawable.Callback">
   <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-list"
@@ -11551,7 +11558,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11567,7 +11574,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">scheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1, long arg2)</nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -11583,7 +11590,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
         
   </td></tr>
 
@@ -11603,7 +11610,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/KeyEvent.Callback.html">android.view.KeyEvent.Callback</a>
+  android.view.KeyEvent.Callback
 
 <div id="inherited-methods-android.view.KeyEvent.Callback">
   <div id="inherited-methods-android.view.KeyEvent.Callback-list"
@@ -11625,7 +11632,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyDown</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11641,7 +11648,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyLongPress</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11657,7 +11664,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg2)</nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
         
   </td></tr>
 
@@ -11673,7 +11680,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyUp</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11693,7 +11700,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/View.OnClickListener.html">android.view.View.OnClickListener</a>
+  android.view.View.OnClickListener
 
 <div id="inherited-methods-android.view.View.OnClickListener">
   <div id="inherited-methods-android.view.View.OnClickListener-list"
@@ -11715,7 +11722,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onClick</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">onClick</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11735,7 +11742,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/ViewManager.html">android.view.ViewManager</a>
+  android.view.ViewManager
 
 <div id="inherited-methods-android.view.ViewManager">
   <div id="inherited-methods-android.view.ViewManager-list"
@@ -11757,7 +11764,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -11773,7 +11780,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11789,7 +11796,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">updateViewLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -11809,7 +11816,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/ViewParent.html">android.view.ViewParent</a>
+  android.view.ViewParent
 
 <div id="inherited-methods-android.view.ViewParent">
   <div id="inherited-methods-android.view.ViewParent-list"
@@ -11831,7 +11838,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">bringChildToFront</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11847,7 +11854,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">childDrawableStateChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11863,7 +11870,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clearChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11879,7 +11886,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">createContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -11892,10 +11899,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusSearch</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -11911,7 +11918,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusableViewAvailable</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11927,7 +11934,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildVisibleRect</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, <a href="/reference/android/graphics/Point.html">Point</a> arg2)</nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
         
   </td></tr>
 
@@ -11940,7 +11947,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParent</span>()</nobr>
@@ -11956,7 +11963,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParentForAccessibility</span>()</nobr>
@@ -11975,7 +11982,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -11988,10 +11995,10 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChildInParent</span>(int[] arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -12023,7 +12030,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">recomputeViewAttributes</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -12039,7 +12046,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1)</nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
         
   </td></tr>
 
@@ -12055,7 +12062,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildRectangleOnScreen</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, boolean arg2)</nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
         
   </td></tr>
 
@@ -12119,7 +12126,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -12135,7 +12142,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestTransparentRegion</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -12151,7 +12158,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">showContextMenuForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -12167,7 +12174,7 @@
             ActionMode</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActionModeForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, ActionMode.Callback arg1)</nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
         
   </td></tr>
 
@@ -12187,7 +12194,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/accessibility/AccessibilityEventSource.html">android.view.accessibility.AccessibilityEventSource</a>
+  android.view.accessibility.AccessibilityEventSource
 
 <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource">
   <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-list"
@@ -12225,7 +12232,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">sendAccessibilityEventUnchecked</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -12485,7 +12492,7 @@
         
       </span>
       <span class="sympad">SignInButton</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12514,7 +12521,7 @@
         
       </span>
       <span class="sympad">SignInButton</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12543,7 +12550,7 @@
         
       </span>
       <span class="sympad">SignInButton</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, int defStyle)</span>
+      <span class="normal">(Context context, AttributeSet attrs, int defStyle)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12587,7 +12594,7 @@
         void
       </span>
       <span class="sympad">onClick</span>
-      <span class="normal">(<a href="/reference/android/view/View.html">View</a> view)</span>
+      <span class="normal">(View view)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12685,7 +12692,7 @@
         void
       </span>
       <span class="sympad">setOnClickListener</span>
-      <span class="normal">(<a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> listener)</span>
+      <span class="normal">(View.OnClickListener listener)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/common/annotation/KeepName.html b/docs/html/reference/com/google/android/gms/common/annotation/KeepName.html
new file mode 100644
index 0000000..23c25cb
--- /dev/null
+++ b/docs/html/reference/com/google/android/gms/common/annotation/KeepName.html
@@ -0,0 +1,962 @@
+<!DOCTYPE html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<html>
+<head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
+
+<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
+<title>KeepName | Android Developers</title>
+
+<!-- STYLESHEETS -->
+<link rel="stylesheet"
+href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
+
+
+
+<!-- JAVASCRIPT -->
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
+<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
+<script type="text/javascript">
+  var toRoot = "/";
+  var devsite = false;
+</script>
+<script src="/assets/js/docs.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-5831155-1']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+</script>
+</head>
+<body class="gc-documentation google
+  develop" itemscope itemtype="http://schema.org/Article">
+  <div id="doc-api-level" class="" style="display:none"></div>
+  <a name="top"></a>
+
+<a name="top"></a>
+
+    <!-- Header -->
+    <div id="header">
+        <div class="wrap" id="header-wrap">
+          <div class="col-3 logo">
+          <a href="/index.html">
+            <img src="/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
+          </a>
+          <div class="btn-quicknav" id="btn-quicknav">
+          	<a href="#" class="arrow-inactive">Quicknav</a>
+			      <a href="#" class="arrow-active">Quicknav</a>
+          </div>
+          </div>
+            <ul class="nav-x col-9">
+                <li class="design">
+                  <a href="/design/index.html"
+                  zh-tw-lang="設計"
+                  zh-cn-lang="设计"
+                  ru-lang="Проектирование"
+                  ko-lang="디자인"
+                  ja-lang="設計"
+                  es-lang="Diseñar"               
+                  >Design</a></li>
+                <li class="develop"><a href="/develop/index.html"
+                  zh-tw-lang="開發"
+                  zh-cn-lang="开发"
+                  ru-lang="Разработка"
+                  ko-lang="개발"
+                  ja-lang="開発"
+                  es-lang="Desarrollar"               
+                  >Develop</a></li>
+                <li class="distribute last"><a href="/distribute/index.html"
+                  zh-tw-lang="發佈"
+                  zh-cn-lang="分发"
+                  ru-lang="Распространение"
+                  ko-lang="배포"
+                  ja-lang="配布"
+                  es-lang="Distribuir"               
+                  >Distribute</a></li>
+            </ul>
+            
+            <!-- New Search -->
+            <div class="menu-container">
+            <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
+  <div class="morehover" id="moremenu">
+    <div class="top"></div>
+    <div class="mid">
+      <div class="header">Links</div>
+      <ul>
+        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
+        <li><a href="/about/index.html">About Android</a></li>
+      </ul>
+      <div class="header">Android Sites</div>
+      <ul>
+        <li><a href="http://www.android.com">Android.com</a></li>
+        <li class="active"><a>Android Developers</a></li>
+        <li><a href="http://source.android.com">Android Open Source Project</a></li>
+      </ul>
+      
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
+
+
+      <br class="clearfix" />
+    </div>
+    <div class="bottom"></div>
+  </div>
+  <div class="search" id="search-container">
+    <div class="search-inner">
+      <div id="search-btn"></div>
+      <div class="left"></div>
+      <form onsubmit="return submit_search()">
+        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
+onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+onkeydown="return search_changed(event, true, '/')" 
+onkeyup="return search_changed(event, false, '/')" />
+      </form>
+      <div class="right"></div>
+        <a class="close hide">close</a>
+        <div class="left"></div>
+        <div class="right"></div>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper reference">
+    <div class="suggest-card reference no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper docs">
+    <div class="suggest-card dummy no-display">&nbsp;</div>
+    <div class="suggest-card develop no-display">
+      <ul class="search_filtered">
+      </ul>
+      <div class="child-card guides no-display">
+      </div>
+      <div class="child-card training no-display">
+      </div>
+    </div>
+    <div class="suggest-card design no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+    <div class="suggest-card distribute no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  </div>
+  <!-- /New Search>
+          
+          
+          <!-- Expanded quicknav -->
+           <div id="quicknav" class="col-9">
+                <ul>
+                    <li class="design">
+                      <ul>
+                        <li><a href="/design/index.html">Get Started</a></li>
+                        <li><a href="/design/style/index.html">Style</a></li>
+                        <li><a href="/design/patterns/index.html">Patterns</a></li>
+                        <li><a href="/design/building-blocks/index.html">Building Blocks</a></li>
+                        <li><a href="/design/downloads/index.html">Downloads</a></li>
+                        <li><a href="/design/videos/index.html">Videos</a></li>
+                      </ul>
+                    </li>
+                    <li class="develop">
+                      <ul>
+                        <li><a href="/training/index.html"
+                          zh-tw-lang="訓練課程"
+                          zh-cn-lang="培训"
+                          ru-lang="Курсы"
+                          ko-lang="교육"
+                          ja-lang="トレーニング"
+                          es-lang="Capacitación"               
+                          >Training</a></li>
+                        <li><a href="/guide/components/index.html"
+                          zh-tw-lang="API 指南"
+                          zh-cn-lang="API 指南"
+                          ru-lang="Руководства по API"
+                          ko-lang="API 가이드"
+                          ja-lang="API ガイド"
+                          es-lang="Guías de la API"               
+                          >API Guides</a></li>
+                        <li><a href="/reference/packages.html"
+                          zh-tw-lang="參考資源"
+                          zh-cn-lang="参考"
+                          ru-lang="Справочник"
+                          ko-lang="참조문서"
+                          ja-lang="リファレンス"
+                          es-lang="Referencia"               
+                          >Reference</a></li>
+                        <li><a href="/tools/index.html"
+                          zh-tw-lang="相關工具"
+                          zh-cn-lang="工具"
+                          ru-lang="Инструменты"
+                          ko-lang="도구"
+                          ja-lang="ツール"
+                          es-lang="Herramientas"               
+                          >Tools</a>
+                          <ul><li><a href="/sdk/index.html">Get the SDK</a></li></ul>
+                        </li>
+                        <li><a href="/google/index.html">Google Services</a>
+                        </li>
+                        
+                      </ul>
+                    </li>
+                    <li class="distribute last">
+                      <ul>
+                        <li><a href="/distribute/index.html">Google Play</a></li>
+                        <li><a href="/distribute/googleplay/publish/index.html">Publishing</a></li>
+                        <li><a href="/distribute/googleplay/promote/index.html">Promoting</a></li>
+                        <li><a href="/distribute/googleplay/quality/index.html">App Quality</a></li>
+                        <li><a href="/distribute/googleplay/spotlight/index.html">Spotlight</a></li>
+                        <li><a href="/distribute/open.html">Open Distribution</a></li>
+                      </ul>
+                    </li>
+                </ul>
+          </div>
+          <!-- /Expanded quicknav -->
+        </div>
+    </div>
+    <!-- /Header -->
+    
+    
+  <div id="searchResults" class="wrap" style="display:none;">
+          <h2 id="searchTitle">Results</h2>
+          <div id="leftSearchControl" class="search-control">Loading...</div>
+  </div>
+    
+    
+  
+    <!-- Secondary x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x col-9 develop" style="width:100%">
+                <li class="training"><a href="/training/index.html"
+                  zh-tw-lang="訓練課程"
+                  zh-cn-lang="培训"
+                  ru-lang="Курсы"
+                  ko-lang="교육"
+                  ja-lang="トレーニング"
+                  es-lang="Capacitación"               
+                  >Training</a></li>
+                <li class="guide"><a href="/guide/components/index.html"
+                  zh-tw-lang="API 指南"
+                  zh-cn-lang="API 指南"
+                  ru-lang="Руководства по API"
+                  ko-lang="API 가이드"
+                  ja-lang="API ガイド"
+                  es-lang="Guías de la API"               
+                  >API Guides</a></li>
+                <li class="reference"><a href="/reference/packages.html"
+                  zh-tw-lang="參考資源"
+                  zh-cn-lang="参考"
+                  ru-lang="Справочник"
+                  ko-lang="참조문서"
+                  ja-lang="リファレンス"
+                  es-lang="Referencia"               
+                  >Reference</a></li>
+                <li class="tools"><a href="/tools/index.html"
+                  zh-tw-lang="相關工具"
+                  zh-cn-lang="工具"
+                  ru-lang="Инструменты"
+                  ko-lang="도구"
+                  ja-lang="ツール"
+                  es-lang="Herramientas"
+                  >Tools</a></li>
+                <li class="google"><a href="/google/index.html"
+                  >Google Services</a>
+                </li>
+                
+            </ul>
+        </div>
+        
+    </div>
+    <!-- /Sendondary x-nav -->
+  
+
+
+
+
+  
+
+
+  
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
+
+
+
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/index.html">
+          <span class="en">Overview</span>
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/games.html">
+          <span class="en">Games</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/location.html">
+          <span class="en">Location</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/plus.html">
+          <span class="en">Google+</span>
+                </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/maps.html">
+          <span class="en">Google Maps</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/auth.html">
+          <span class="en">Authorization</span>
+      </a></div>
+  </li>
+
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play-services/index.html">
+      <span class="en">Google Play Services</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play-services/setup.html">
+          <span class="en">Setup</span></a>
+      </li>
+      <li id="gms-tree-list" class="nav-section">
+        <div class="nav-section-header">
+          <a href="/reference/gms-packages.html">
+            <span class="en">Reference</span>
+          </a>
+        <div>
+      </li>
+    </ul>
+  </li>
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/billing/index.html">
+      <span class="en">Google Play In-app Billing</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/billing/billing_overview.html">
+              <span class="en">Overview</span></a>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/api.html">
+              <span class="en">Version 3 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/v2/api.html">
+              <span class="en">Version 2 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/v2/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li><a href="/google/play/billing/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_best_practices.html">
+              <span class="en">Security and Design</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_testing.html">
+              <span class="en">Testing In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_admin.html">
+              <span class="en">Administering In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/gp-purchase-status-api.html">
+              <span class="en">Purchase Status API</span></a>
+      </li>
+      <li><a href="/google/play/billing/versions.html">
+              <span class="en">Version Notes</span></a>
+      </li>
+    </ul>
+  </li>
+
+
+
+  <li class="nav-section">
+      <div class="nav-section-header"><a href="/google/gcm/index.html">
+        <span class="en">Google Cloud Messaging</span></a>
+      </div>
+      <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
+        <li><a href="/google/gcm/gs.html">
+            <span class="en">Getting Started</span></a>
+        </li>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
+        </li>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
+        </li>
+        <li><a href="/google/gcm/notifications.html">
+              <span class="en">User Notifications</span></a>
+        </li>
+        <li><a href="/google/gcm/adv.html">
+            <span class="en">Advanced Topics</span></a>
+        </li>
+        <li><a href="/google/gcm/c2dm.html">
+            <span class="en">Migration</span></a>
+        </li>
+        <li id="gcm-tree-list" class="nav-section">
+          <div class="nav-section-header">
+            <a href="/reference/gcm-packages.html">
+              <span class="en">Reference</span>
+            </a>
+          <div>
+        </li>
+      </ul>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/dist.html">
+      <span class="en">Google Play Distribution</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/filters.html">
+          <span class="en">Filters on Google Play</span></a>
+      </li>
+
+      <li><a href="/google/play/publishing/multiple-apks.html">
+          <span class="en">Multiple APK Support</span></a>
+      </li>
+      <li><a href="/google/play/expansion-files.html">
+          <span class="en">APK Expansion Files</span></a>
+      </li>
+      <li class="nav-section">
+        <div class="nav-section-header"><a href="/google/play/licensing/index.html">
+          <span class="en">Application Licensing</span></a>
+        </div>
+        <ul>
+          <li><a href="/google/play/licensing/overview.html">
+              <span class="en">Licensing Overview</span></a>
+          </li>
+          <li><a href="/google/play/licensing/setting-up.html">
+              <span class="en">Setting Up for Licensing</span></a>
+          </li>
+          <li><a href="/google/play/licensing/adding-licensing.html">
+              <span class="en">Adding Licensing to Your App</span></a>
+          </li>
+          <li><a href="/google/play/licensing/licensing-reference.html">
+              <span class="en">Licensing Reference</span></a>
+          </li>
+        </ul>
+      </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/backup/index.html">
+      Android Backup Service</a>
+    </div>
+    <ul>
+      <li><a href="/google/backup/signup.html">
+          Register</a>
+      </li>
+    </ul>
+  </li>
+
+  </ul>
+
+</li>
+
+
+
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
+
+        
+
+      </div>
+      <script type="text/javascript">
+       showGoogleRefTree();
+    
+      </script>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+
+
+     
+
+
+
+<div class="col-12"  id="doc-col">
+
+<div id="api-info-block">
+
+
+
+  
+   
+  
+  
+  
+  
+
+
+<div class="sum-details-links">
+
+Summary:
+
+
+
+
+
+
+
+
+
+
+
+
+
+  <a href="#inhmethods">Inherited Methods</a>
+
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+
+</div><!-- end sum-details-links -->
+<div class="api-level">
+  
+  
+  
+
+</div>
+</div><!-- end api-info-block -->
+
+
+<!-- ======== START OF CLASS DATA ======== -->
+
+<div id="jd-header">
+    public
+     
+     
+    abstract
+    @interface
+<h1 itemprop="name">KeepName</h1>
+
+
+
+  
+  
+      implements 
+      
+        Annotation 
+      
+  
+  
+
+
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-">
+<table class="jd-inheritance-table">
+
+
+    <tr>
+         	
+        <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.common.annotation.KeepName</td>
+    </tr>
+    
+
+</table>
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Class Overview</h2>
+<p itemprop="articleBody">Indicates that the name of this object (class, method, etc) should be retained when proguarding.
+</p>
+
+
+
+
+
+</div><!-- jd-descr -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Summary</h2>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="inhmethods" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Methods</div></th></tr>
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-java.lang.annotation.Annotation" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-java.lang.annotation.Annotation-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  java.lang.annotation.Annotation
+
+<div id="inherited-methods-java.lang.annotation.Annotation">
+  <div id="inherited-methods-java.lang.annotation.Annotation-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-java.lang.annotation.Annotation-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            Class&lt;?&nbsp;extends&nbsp;Annotation&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">annotationType</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hashCode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">toString</span>()</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+</table>
+
+
+</div><!-- jd-descr (summary) -->
+
+<!-- Details -->
+
+
+
+
+
+
+
+
+<!-- XML Attributes -->
+
+
+<!-- Enum Values -->
+
+
+<!-- Constants -->
+
+
+<!-- Fields -->
+
+
+<!-- Public ctors -->
+
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<!-- Protected ctors -->
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methdos -->
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+
+
+
+<!-- ========= END OF CLASS DATA ========= -->
+<A NAME="navbar_top"></A>
+
+<div id="footer" class="wrap" >
+        
+
+  <div id="copyright">
+    
+  Except as noted, this content is licensed under <a
+  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
+  For details and restrictions, see the <a href="/license.html">
+  Content License</a>.
+  </div>
+  <div id="build_info">
+    
+<script src="/timestamp.js" type="text/javascript"></script>
+<script>document.write(BUILD_TIMESTAMP)</script>
+
+  </div>
+
+
+  <div id="footerlinks">
+    
+  <p>
+    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/support.html">Support</a>
+  </p>
+  </div>
+
+</div> <!-- end footer -->
+</div> <!-- jd-content -->
+
+</div><!-- end doc-content -->
+
+</div> <!-- end body-content --> 
+
+
+
+
+
+
+</body>
+</html>
diff --git a/docs/html/reference/com/google/android/gms/common/data/DataBuffer.html b/docs/html/reference/com/google/android/gms/common/data/DataBuffer.html
index b45a205..92f7464 100644
--- a/docs/html/reference/com/google/android/gms/common/data/DataBuffer.html
+++ b/docs/html/reference/com/google/android/gms/common/data/DataBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>DataBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -685,7 +692,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -694,7 +701,7 @@
   
       implements 
       
-        <a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;T&gt; 
+        Iterable&lt;T&gt; 
       
   
   
@@ -710,7 +717,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -970,7 +977,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -1001,7 +1008,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1020,7 +1027,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1039,7 +1046,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1068,7 +1075,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1132,7 +1139,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1203,7 +1210,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1222,7 +1229,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
@@ -1453,7 +1460,7 @@
          
          
          
-        <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;
+        Iterator&lt;T&gt;
       </span>
       <span class="sympad">iterator</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/common/data/DataBufferUtils.html b/docs/html/reference/com/google/android/gms/common/data/DataBufferUtils.html
index a865899..75d0c6b 100644
--- a/docs/html/reference/com/google/android/gms/common/data/DataBufferUtils.html
+++ b/docs/html/reference/com/google/android/gms/common/data/DataBufferUtils.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>DataBufferUtils | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -790,7 +797,7 @@
             
             static
             &lt;T,&nbsp;E&nbsp;extends&nbsp;<a href="/reference/com/google/android/gms/common/data/Freezable.html">Freezable</a>&lt;T&gt;&gt;
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;T&gt;</nobr>
+            ArrayList&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBufferUtils.html#freezeAndClose(com.google.android.gms.common.data.DataBuffer<E>)">freezeAndClose</a></span>(<a href="/reference/com/google/android/gms/common/data/DataBuffer.html">DataBuffer</a>&lt;E&gt; buffer)</nobr>
@@ -823,7 +830,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -842,7 +849,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -861,7 +868,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -890,7 +897,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -954,7 +961,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1068,7 +1075,7 @@
          
          
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;T&gt;
+        ArrayList&lt;T&gt;
       </span>
       <span class="sympad">freezeAndClose</span>
       <span class="normal">(<a href="/reference/com/google/android/gms/common/data/DataBuffer.html">DataBuffer</a>&lt;E&gt; buffer)</span>
diff --git a/docs/html/reference/com/google/android/gms/common/data/Freezable.html b/docs/html/reference/com/google/android/gms/common/data/Freezable.html
index 386ab28..a12b532 100644
--- a/docs/html/reference/com/google/android/gms/common/data/Freezable.html
+++ b/docs/html/reference/com/google/android/gms/common/data/Freezable.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Freezable | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/common/data/package-summary.html b/docs/html/reference/com/google/android/gms/common/data/package-summary.html
index bac8164..37c8927 100644
--- a/docs/html/reference/com/google/android/gms/common/data/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/common/data/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.common.data | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html b/docs/html/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html
index dc2a816..b7ef355 100644
--- a/docs/html/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ImageManager.OnImageLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -751,7 +758,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html#onImageLoaded(android.net.Uri, android.graphics.drawable.Drawable)">onImageLoaded</a></span>(<a href="/reference/android/net/Uri.html">Uri</a> uri, <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> drawable)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html#onImageLoaded(android.net.Uri, android.graphics.drawable.Drawable)">onImageLoaded</a></span>(Uri uri, Drawable drawable)</nobr>
         
         <div class="jd-descrdiv">Listener method invoked when an image has been loaded.</div>
   
@@ -819,7 +826,7 @@
         void
       </span>
       <span class="sympad">onImageLoaded</span>
-      <span class="normal">(<a href="/reference/android/net/Uri.html">Uri</a> uri, <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> drawable)</span>
+      <span class="normal">(Uri uri, Drawable drawable)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/common/images/ImageManager.html b/docs/html/reference/com/google/android/gms/common/images/ImageManager.html
index e78d13e..42f1205 100644
--- a/docs/html/reference/com/google/android/gms/common/images/ImageManager.html
+++ b/docs/html/reference/com/google/android/gms/common/images/ImageManager.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ImageManager | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -816,7 +823,7 @@
             <a href="/reference/com/google/android/gms/common/images/ImageManager.html">ImageManager</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#create(android.content.Context)">create</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#create(android.content.Context)">create</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Returns a new ImageManager for loading images from the network.</div>
   
@@ -834,7 +841,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(android.widget.ImageView, android.net.Uri)">loadImage</a></span>(<a href="/reference/android/widget/ImageView.html">ImageView</a> imageView, <a href="/reference/android/net/Uri.html">Uri</a> uri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(android.widget.ImageView, android.net.Uri)">loadImage</a></span>(ImageView imageView, Uri uri)</nobr>
         
         <div class="jd-descrdiv">Loads an image to display from a URI.</div>
   
@@ -852,7 +859,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(android.widget.ImageView, int)">loadImage</a></span>(<a href="/reference/android/widget/ImageView.html">ImageView</a> imageView, int resId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(android.widget.ImageView, int)">loadImage</a></span>(ImageView imageView, int resId)</nobr>
         
         <div class="jd-descrdiv">Loads an image to display from the given resource ID.</div>
   
@@ -870,7 +877,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(com.google.android.gms.common.images.ImageManager.OnImageLoadedListener, android.net.Uri, int)">loadImage</a></span>(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri, int defaultResId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(com.google.android.gms.common.images.ImageManager.OnImageLoadedListener, android.net.Uri, int)">loadImage</a></span>(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, Uri uri, int defaultResId)</nobr>
         
         <div class="jd-descrdiv">Load an image to display from a URI, using the given resource ID as the default if no
  image if found for the given URI.</div>
@@ -889,7 +896,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(com.google.android.gms.common.images.ImageManager.OnImageLoadedListener, android.net.Uri)">loadImage</a></span>(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(com.google.android.gms.common.images.ImageManager.OnImageLoadedListener, android.net.Uri)">loadImage</a></span>(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, Uri uri)</nobr>
         
         <div class="jd-descrdiv">Load an image to display from a URI.</div>
   
@@ -907,7 +914,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(android.widget.ImageView, android.net.Uri, int)">loadImage</a></span>(<a href="/reference/android/widget/ImageView.html">ImageView</a> imageView, <a href="/reference/android/net/Uri.html">Uri</a> uri, int defaultResId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/common/images/ImageManager.html#loadImage(android.widget.ImageView, android.net.Uri, int)">loadImage</a></span>(ImageView imageView, Uri uri, int defaultResId)</nobr>
         
         <div class="jd-descrdiv">Loads an image to display from a URI, using the given resource ID as the default if no
  image if found for the given URI.</div>
@@ -938,7 +945,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -957,7 +964,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -976,7 +983,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1005,7 +1012,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1069,7 +1076,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1186,7 +1193,7 @@
         <a href="/reference/com/google/android/gms/common/images/ImageManager.html">ImageManager</a>
       </span>
       <span class="sympad">create</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1229,7 +1236,7 @@
         void
       </span>
       <span class="sympad">loadImage</span>
-      <span class="normal">(<a href="/reference/android/widget/ImageView.html">ImageView</a> imageView, <a href="/reference/android/net/Uri.html">Uri</a> uri)</span>
+      <span class="normal">(ImageView imageView, Uri uri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1282,7 +1289,7 @@
         void
       </span>
       <span class="sympad">loadImage</span>
-      <span class="normal">(<a href="/reference/android/widget/ImageView.html">ImageView</a> imageView, int resId)</span>
+      <span class="normal">(ImageView imageView, int resId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1329,7 +1336,7 @@
         void
       </span>
       <span class="sympad">loadImage</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri, int defaultResId)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, Uri uri, int defaultResId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1383,7 +1390,7 @@
         void
       </span>
       <span class="sympad">loadImage</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html">ImageManager.OnImageLoadedListener</a> listener, Uri uri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1429,7 +1436,7 @@
         void
       </span>
       <span class="sympad">loadImage</span>
-      <span class="normal">(<a href="/reference/android/widget/ImageView.html">ImageView</a> imageView, <a href="/reference/android/net/Uri.html">Uri</a> uri, int defaultResId)</span>
+      <span class="normal">(ImageView imageView, Uri uri, int defaultResId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/common/images/package-summary.html b/docs/html/reference/com/google/android/gms/common/images/package-summary.html
index b8b6f4a..9f5eea1 100644
--- a/docs/html/reference/com/google/android/gms/common/images/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/common/images/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.common.images | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/common/package-summary.html b/docs/html/reference/com/google/android/gms/common/package-summary.html
index b8877eb..46ea9bf 100644
--- a/docs/html/reference/com/google/android/gms/common/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/common/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.common | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/Game.html b/docs/html/reference/com/google/android/gms/games/Game.html
index ac73eff..9fb39a8 100644
--- a/docs/html/reference/com/google/android/gms/games/Game.html
+++ b/docs/html/reference/com/google/android/gms/games/Game.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Game | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -693,7 +700,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/common/data/Freezable.html">Freezable</a>&lt;T&gt; 
       
@@ -892,7 +899,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getApplicationId()">getApplicationId</a></span>()</nobr>
@@ -910,7 +917,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDescription()">getDescription</a></span>()</nobr>
@@ -931,7 +938,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the description string into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -946,7 +953,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDeveloperName()">getDeveloperName</a></span>()</nobr>
@@ -967,7 +974,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDeveloperName(android.database.CharArrayBuffer)">getDeveloperName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDeveloperName(android.database.CharArrayBuffer)">getDeveloperName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the developer name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -982,7 +989,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -1003,7 +1010,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the display name string into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1018,7 +1025,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getFeaturedImageUri()">getFeaturedImageUri</a></span>()</nobr>
@@ -1037,7 +1044,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1055,7 +1062,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1091,7 +1098,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getPrimaryCategory()">getPrimaryCategory</a></span>()</nobr>
@@ -1109,7 +1116,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getSecondaryCategory()">getSecondaryCategory</a></span>()</nobr>
@@ -1142,7 +1149,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1180,7 +1187,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1339,7 +1346,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getApplicationId</span>
       <span class="normal">()</span>
@@ -1373,7 +1380,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -1410,7 +1417,7 @@
         void
       </span>
       <span class="sympad">getDescription</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1446,7 +1453,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDeveloperName</span>
       <span class="normal">()</span>
@@ -1483,7 +1490,7 @@
         void
       </span>
       <span class="sympad">getDeveloperName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1519,7 +1526,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -1556,7 +1563,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1592,7 +1599,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getFeaturedImageUri</span>
       <span class="normal">()</span>
@@ -1630,7 +1637,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getHiResImageUri</span>
       <span class="normal">()</span>
@@ -1668,7 +1675,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -1739,7 +1746,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPrimaryCategory</span>
       <span class="normal">()</span>
@@ -1773,7 +1780,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getSecondaryCategory</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/GameBuffer.html b/docs/html/reference/com/google/android/gms/games/GameBuffer.html
index 234f316..41e0d70 100644
--- a/docs/html/reference/com/google/android/gms/games/GameBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/GameBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GameBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/GameEntity.html b/docs/html/reference/com/google/android/gms/games/GameEntity.html
index f3167ad..fce4ad8 100644
--- a/docs/html/reference/com/google/android/gms/games/GameEntity.html
+++ b/docs/html/reference/com/google/android/gms/games/GameEntity.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GameEntity | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -679,9 +686,6 @@
   
 
 
-  &#124; <a href="#promethods">Protected Methods</a>
-  
-
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -710,7 +714,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -719,7 +723,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/games/Game.html">Game</a> 
       
@@ -737,7 +741,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -872,7 +876,7 @@
           public
           static
           final
-          <a href="/reference/com/google/android/gms/games/GameEntityCreator.html">GameEntityCreator</a></nobr></td>
+          Creator&lt;<a href="/reference/com/google/android/gms/games/GameEntity.html">GameEntity</a>&gt;</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GameEntity.html#CREATOR">CREATOR</a></td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -923,7 +927,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> obj)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#equals(java.lang.Object)">equals</a></span>(Object obj)</nobr>
         
   </td></tr>
 
@@ -972,7 +976,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getApplicationId()">getApplicationId</a></span>()</nobr>
@@ -990,7 +994,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDescription()">getDescription</a></span>()</nobr>
@@ -1011,7 +1015,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the description string into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1026,7 +1030,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDeveloperName()">getDeveloperName</a></span>()</nobr>
@@ -1047,7 +1051,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDeveloperName(android.database.CharArrayBuffer)">getDeveloperName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDeveloperName(android.database.CharArrayBuffer)">getDeveloperName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the developer name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1062,7 +1066,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -1083,7 +1087,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the display name string into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1098,7 +1102,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getFeaturedImageUri()">getFeaturedImageUri</a></span>()</nobr>
@@ -1133,7 +1137,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1151,7 +1155,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1169,7 +1173,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getInstancePackageName()">getInstancePackageName</a></span>()</nobr>
@@ -1203,7 +1207,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getPrimaryCategory()">getPrimaryCategory</a></span>()</nobr>
@@ -1221,7 +1225,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getSecondaryCategory()">getSecondaryCategory</a></span>()</nobr>
@@ -1305,7 +1309,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#toString()">toString</a></span>()</nobr>
@@ -1324,7 +1328,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel dest, int flags)</nobr>
         
   </td></tr>
 
@@ -1335,63 +1339,6 @@
 
 
 
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getUnparcelClassLoader()">getUnparcelClassLoader</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/Integer.html">Integer</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#getUnparcelClientVersion()">getUnparcelClientVersion</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GameEntity.html#shouldDowngrade()">shouldDowngrade</a></span>()</nobr>
-        
-  </td></tr>
-
-
-
-</table>
-
-
 
 
 
@@ -1409,7 +1356,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1428,7 +1375,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1447,7 +1394,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1476,7 +1423,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1540,7 +1487,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1611,7 +1558,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1649,7 +1596,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1768,7 +1715,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getApplicationId()">getApplicationId</a></span>()</nobr>
@@ -1786,7 +1733,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDescription()">getDescription</a></span>()</nobr>
@@ -1807,7 +1754,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the description string into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1822,7 +1769,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDeveloperName()">getDeveloperName</a></span>()</nobr>
@@ -1843,7 +1790,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDeveloperName(android.database.CharArrayBuffer)">getDeveloperName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDeveloperName(android.database.CharArrayBuffer)">getDeveloperName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the developer name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1858,7 +1805,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -1879,7 +1826,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the display name string into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1894,7 +1841,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getFeaturedImageUri()">getFeaturedImageUri</a></span>()</nobr>
@@ -1913,7 +1860,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1931,7 +1878,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1967,7 +1914,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getPrimaryCategory()">getPrimaryCategory</a></span>()</nobr>
@@ -1985,7 +1932,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Game.html#getSecondaryCategory()">getSecondaryCategory</a></span>()</nobr>
@@ -2041,7 +1988,7 @@
         public 
         static 
         final 
-        <a href="/reference/com/google/android/gms/games/GameEntityCreator.html">GameEntityCreator</a>
+        Creator&lt;<a href="/reference/com/google/android/gms/games/GameEntity.html">GameEntity</a>&gt;
       </span>
         CREATOR
     </h4>
@@ -2120,7 +2067,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> obj)</span>
+      <span class="normal">(Object obj)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2227,7 +2174,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getApplicationId</span>
       <span class="normal">()</span>
@@ -2261,7 +2208,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -2298,7 +2245,7 @@
         void
       </span>
       <span class="sympad">getDescription</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2334,7 +2281,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDeveloperName</span>
       <span class="normal">()</span>
@@ -2371,7 +2318,7 @@
         void
       </span>
       <span class="sympad">getDeveloperName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2407,7 +2354,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -2444,7 +2391,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2480,7 +2427,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getFeaturedImageUri</span>
       <span class="normal">()</span>
@@ -2547,7 +2494,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getHiResImageUri</span>
       <span class="normal">()</span>
@@ -2585,7 +2532,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -2622,7 +2569,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getInstancePackageName</span>
       <span class="normal">()</span>
@@ -2685,7 +2632,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPrimaryCategory</span>
       <span class="normal">()</span>
@@ -2719,7 +2666,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getSecondaryCategory</span>
       <span class="normal">()</span>
@@ -2876,7 +2823,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -2908,7 +2855,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</span>
+      <span class="normal">(Parcel dest, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2929,113 +2876,6 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
-<h2>Protected Methods</h2>
-
-
-
-<A NAME="getUnparcelClassLoader()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a>
-      </span>
-      <span class="sympad">getUnparcelClassLoader</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The ClassLoader to use for unparceling, if any.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="getUnparcelClientVersion()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/Integer.html">Integer</a>
-      </span>
-      <span class="sympad">getUnparcelClientVersion</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The client version to use for unparceling, if known.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="shouldDowngrade()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-         
-         
-         
-         
-        boolean
-      </span>
-      <span class="sympad">shouldDowngrade</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>Whether or not this object has been downgraded to hand back to a client.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/games/GamesActivityResultCodes.html b/docs/html/reference/com/google/android/gms/games/GamesActivityResultCodes.html
index 478b4f4..68576a5 100644
--- a/docs/html/reference/com/google/android/gms/games/GamesActivityResultCodes.html
+++ b/docs/html/reference/com/google/android/gms/games/GamesActivityResultCodes.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GamesActivityResultCodes | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -843,7 +850,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -862,7 +869,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -881,7 +888,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -910,7 +917,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -974,7 +981,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/GamesClient.Builder.html b/docs/html/reference/com/google/android/gms/games/GamesClient.Builder.html
index 3e23650..9879630 100644
--- a/docs/html/reference/com/google/android/gms/games/GamesClient.Builder.html
+++ b/docs/html/reference/com/google/android/gms/games/GamesClient.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GamesClient.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -792,7 +799,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#GamesClient.Builder(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">GamesClient.Builder</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#GamesClient.Builder(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">GamesClient.Builder</a></span>(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
         
         <div class="jd-descrdiv">Create a new Builder object to be used to build a corresponding GamesClient object.</div>
   
@@ -842,7 +849,7 @@
             <a href="/reference/com/google/android/gms/games/GamesClient.Builder.html">GamesClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#setAccountName(java.lang.String)">setAccountName</a></span>(<a href="/reference/java/lang/String.html">String</a> accountName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#setAccountName(java.lang.String)">setAccountName</a></span>(String accountName)</nobr>
         
         <div class="jd-descrdiv">Specify an account name on the device that should be used.</div>
   
@@ -879,7 +886,7 @@
             <a href="/reference/com/google/android/gms/games/GamesClient.Builder.html">GamesClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#setScopes(java.lang.String...)">setScopes</a></span>(<a href="/reference/java/lang/String.html">String...</a> scopes)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#setScopes(java.lang.String...)">setScopes</a></span>(String... scopes)</nobr>
         
         <div class="jd-descrdiv">Set the scopes to use when building the GamesClient object.</div>
   
@@ -897,7 +904,7 @@
             <a href="/reference/com/google/android/gms/games/GamesClient.Builder.html">GamesClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#setViewForPopups(android.view.View)">setViewForPopups</a></span>(<a href="/reference/android/view/View.html">View</a> gamesContentView)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.Builder.html#setViewForPopups(android.view.View)">setViewForPopups</a></span>(View gamesContentView)</nobr>
         
         <div class="jd-descrdiv">Sets the <code><a href="/reference/android/view/View.html">View</a></code> to use as a content view for popups.</div>
   
@@ -927,7 +934,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -946,7 +953,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -965,7 +972,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -994,7 +1001,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1058,7 +1065,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1167,7 +1174,7 @@
         
       </span>
       <span class="sympad">GamesClient.Builder</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1283,7 +1290,7 @@
         <a href="/reference/com/google/android/gms/games/GamesClient.Builder.html">GamesClient.Builder</a>
       </span>
       <span class="sympad">setAccountName</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> accountName)</span>
+      <span class="normal">(String accountName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1371,7 +1378,7 @@
         <a href="/reference/com/google/android/gms/games/GamesClient.Builder.html">GamesClient.Builder</a>
       </span>
       <span class="sympad">setScopes</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String...</a> scopes)</span>
+      <span class="normal">(String... scopes)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1417,7 +1424,7 @@
         <a href="/reference/com/google/android/gms/games/GamesClient.Builder.html">GamesClient.Builder</a>
       </span>
       <span class="sympad">setViewForPopups</span>
-      <span class="normal">(<a href="/reference/android/view/View.html">View</a> gamesContentView)</span>
+      <span class="normal">(View gamesContentView)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/GamesClient.html b/docs/html/reference/com/google/android/gms/games/GamesClient.html
index 74ab6b0..90d5d78 100644
--- a/docs/html/reference/com/google/android/gms/games/GamesClient.html
+++ b/docs/html/reference/com/google/android/gms/games/GamesClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GamesClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -691,7 +698,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -807,42 +814,42 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GamesClient.html#EXTRA_EXCLUSIVE_BIT_MASK">EXTRA_EXCLUSIVE_BIT_MASK</a></td>
         <td class="jd-descrcol" width="100%">Used to bundle the exclusive bit mask of the player for auto-match criteria.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GamesClient.html#EXTRA_INVITATION">EXTRA_INVITATION</a></td>
         <td class="jd-descrcol" width="100%">Used to return an <code><a href="/reference/com/google/android/gms/games/multiplayer/Invitation.html">Invitation</a></code>.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GamesClient.html#EXTRA_MAX_AUTOMATCH_PLAYERS">EXTRA_MAX_AUTOMATCH_PLAYERS</a></td>
         <td class="jd-descrcol" width="100%">Used to return the maximum number of players that should be added to a room by auto-matching.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GamesClient.html#EXTRA_MIN_AUTOMATCH_PLAYERS">EXTRA_MIN_AUTOMATCH_PLAYERS</a></td>
         <td class="jd-descrcol" width="100%">Used to return the minimum number of players that should be added to a room by auto-matching.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GamesClient.html#EXTRA_PLAYERS">EXTRA_PLAYERS</a></td>
         <td class="jd-descrcol" width="100%">Used to return a list of player IDs.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/GamesClient.html#EXTRA_ROOM">EXTRA_ROOM</a></td>
         <td class="jd-descrcol" width="100%">Used to return a <code><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a></code>.</td>
     </tr>
@@ -1152,7 +1159,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#declineRoomInvitation(java.lang.String)">declineRoomInvitation</a></span>(<a href="/reference/java/lang/String.html">String</a> invitationId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#declineRoomInvitation(java.lang.String)">declineRoomInvitation</a></span>(String invitationId)</nobr>
         
         <div class="jd-descrdiv">Decline an invitation for a real-time room.</div>
   
@@ -1188,7 +1195,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#dismissRoomInvitation(java.lang.String)">dismissRoomInvitation</a></span>(<a href="/reference/java/lang/String.html">String</a> invitationId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#dismissRoomInvitation(java.lang.String)">dismissRoomInvitation</a></span>(String invitationId)</nobr>
         
         <div class="jd-descrdiv">Dismiss an invitation to a real-time room.</div>
   
@@ -1203,7 +1210,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getAchievementsIntent()">getAchievementsIntent</a></span>()</nobr>
@@ -1221,7 +1228,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getAllLeaderboardsIntent()">getAllLeaderboardsIntent</a></span>()</nobr>
@@ -1239,7 +1246,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getAppId()">getAppId</a></span>()</nobr>
@@ -1257,7 +1264,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getCurrentAccountName()">getCurrentAccountName</a></span>()</nobr>
@@ -1307,7 +1314,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getCurrentPlayerId()">getCurrentPlayerId</a></span>()</nobr>
@@ -1323,7 +1330,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getInvitationInboxIntent()">getInvitationInboxIntent</a></span>()</nobr>
@@ -1341,10 +1348,10 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getLeaderboardIntent(java.lang.String)">getLeaderboardIntent</a></span>(<a href="/reference/java/lang/String.html">String</a> leaderboardId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getLeaderboardIntent(java.lang.String)">getLeaderboardIntent</a></span>(String leaderboardId)</nobr>
         
         <div class="jd-descrdiv">Gets an intent to show a leaderboard for a game.</div>
   
@@ -1362,7 +1369,7 @@
             <a href="/reference/com/google/android/gms/games/RealTimeSocket.html">RealTimeSocket</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getRealTimeSocketForParticipant(java.lang.String, java.lang.String)">getRealTimeSocketForParticipant</a></span>(<a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/lang/String.html">String</a> participantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getRealTimeSocketForParticipant(java.lang.String, java.lang.String)">getRealTimeSocketForParticipant</a></span>(String roomId, String participantId)</nobr>
         
         <div class="jd-descrdiv">Returns a <code><a href="/reference/com/google/android/gms/games/RealTimeSocket.html">RealTimeSocket</a></code> for carrying network traffic to the given peer.</div>
   
@@ -1377,7 +1384,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getRealTimeWaitingRoomIntent(com.google.android.gms.games.multiplayer.realtime.Room, int)">getRealTimeWaitingRoomIntent</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, int minParticipantsToStart)</nobr>
@@ -1396,7 +1403,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getSelectPlayersIntent(int, int)">getSelectPlayersIntent</a></span>(int minPlayers, int maxPlayers)</nobr>
@@ -1414,7 +1421,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#getSettingsIntent()">getSettingsIntent</a></span>()</nobr>
@@ -1436,7 +1443,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#incrementAchievement(java.lang.String, int)">incrementAchievement</a></span>(<a href="/reference/java/lang/String.html">String</a> id, int numSteps)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#incrementAchievement(java.lang.String, int)">incrementAchievement</a></span>(String id, int numSteps)</nobr>
         
         <div class="jd-descrdiv">Increments an achievement by the given number of steps.</div>
   
@@ -1454,7 +1461,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#incrementAchievementImmediate(com.google.android.gms.games.achievement.OnAchievementUpdatedListener, java.lang.String, int)">incrementAchievementImmediate</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> id, int numSteps)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#incrementAchievementImmediate(com.google.android.gms.games.achievement.OnAchievementUpdatedListener, java.lang.String, int)">incrementAchievementImmediate</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, String id, int numSteps)</nobr>
         
         <div class="jd-descrdiv">Increments an achievement by the given number of steps.</div>
   
@@ -1565,7 +1572,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#leaveRoom(com.google.android.gms.games.multiplayer.realtime.RoomUpdateListener, java.lang.String)">leaveRoom</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html">RoomUpdateListener</a> listener, <a href="/reference/java/lang/String.html">String</a> roomId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#leaveRoom(com.google.android.gms.games.multiplayer.realtime.RoomUpdateListener, java.lang.String)">leaveRoom</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html">RoomUpdateListener</a> listener, String roomId)</nobr>
         
         <div class="jd-descrdiv">Leave the specified room.</div>
   
@@ -1583,24 +1590,6 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadAchievements(com.google.android.gms.games.achievement.OnAchievementsLoadedListener)">loadAchievements</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html">OnAchievementsLoadedListener</a> listener)</nobr>
-        
-        <div class="jd-descrdiv">Asynchronously load achievement data for the currently signed in player.</div>
-  
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadAchievements(com.google.android.gms.games.achievement.OnAchievementsLoadedListener, boolean)">loadAchievements</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html">OnAchievementsLoadedListener</a> listener, boolean forceReload)</nobr>
         
         <div class="jd-descrdiv">Asynchronously load achievement data for the currently signed in player.</div>
@@ -1609,7 +1598,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1627,7 +1616,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1646,7 +1635,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1664,24 +1653,6 @@
 
 
 	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String)">loadLeaderboardMetadata</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId)</nobr>
-        
-        <div class="jd-descrdiv">Asynchronously load a specific leaderboard's metadata for this game.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1692,7 +1663,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener)">loadLeaderboardMetadata</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, boolean)">loadLeaderboardMetadata</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, boolean forceReload)</nobr>
         
         <div class="jd-descrdiv">Asynchronously load the list of leaderboard metadata for this game.</div>
   
@@ -1710,6 +1681,69 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String)">loadLeaderboardMetadata</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, String leaderboardId)</nobr>
+        
+        <div class="jd-descrdiv"><em>
+      This method is deprecated.
+    This form of the API is deprecated and will be removed in a future release. 
+ Please use <code><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String, boolean)">loadLeaderboardMetadata(OnLeaderboardMetadataLoadedListener, String, boolean)</a></code>
+ instead.
+</em></div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener)">loadLeaderboardMetadata</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener)</nobr>
+        
+        <div class="jd-descrdiv"><em>
+      This method is deprecated.
+    This form of the API is deprecated and will be removed in a future release. 
+ Please use <code><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, boolean)">loadLeaderboardMetadata(OnLeaderboardMetadataLoadedListener, boolean)</a></code> instead.
+</em></div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String, boolean)">loadLeaderboardMetadata</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, String leaderboardId, boolean forceReload)</nobr>
+        
+        <div class="jd-descrdiv">Asynchronously load a specific leaderboard's metadata for this game.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadMoreInvitablePlayers(com.google.android.gms.games.OnPlayersLoadedListener, int)">loadMoreInvitablePlayers</a></span>(<a href="/reference/com/google/android/gms/games/OnPlayersLoadedListener.html">OnPlayersLoadedListener</a> listener, int pageSize)</nobr>
         
         <div class="jd-descrdiv">Asynchronously loads an additional page of invitable players.</div>
@@ -1718,7 +1752,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1736,7 +1770,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1746,7 +1780,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadPlayer(com.google.android.gms.games.OnPlayersLoadedListener, java.lang.String)">loadPlayer</a></span>(<a href="/reference/com/google/android/gms/games/OnPlayersLoadedListener.html">OnPlayersLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> playerId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadPlayer(com.google.android.gms.games.OnPlayersLoadedListener, java.lang.String)">loadPlayer</a></span>(<a href="/reference/com/google/android/gms/games/OnPlayersLoadedListener.html">OnPlayersLoadedListener</a> listener, String playerId)</nobr>
         
         <div class="jd-descrdiv">Asynchronously loads the profile for the requested player ID.</div>
   
@@ -1754,24 +1788,6 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadPlayerCenteredScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int, boolean)">loadPlayerCenteredScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</nobr>
-        
-        <div class="jd-descrdiv">Asynchronously load the player-centered page of scores for a given leaderboard.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1782,7 +1798,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadPlayerCenteredScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int)">loadPlayerCenteredScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadPlayerCenteredScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int, boolean)">loadPlayerCenteredScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</nobr>
         
         <div class="jd-descrdiv">Asynchronously load the player-centered page of scores for a given leaderboard.</div>
   
@@ -1800,9 +1816,9 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadTopScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int)">loadTopScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadPlayerCenteredScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int)">loadPlayerCenteredScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults)</nobr>
         
-        <div class="jd-descrdiv">Asynchronously load the top page of scores for a given leaderboard.</div>
+        <div class="jd-descrdiv">Asynchronously load the player-centered page of scores for a given leaderboard.</div>
   
   </td></tr>
 
@@ -1818,7 +1834,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadTopScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int, boolean)">loadTopScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadTopScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int)">loadTopScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults)</nobr>
         
         <div class="jd-descrdiv">Asynchronously load the top page of scores for a given leaderboard.</div>
   
@@ -1836,6 +1852,24 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#loadTopScores(com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener, java.lang.String, int, int, int, boolean)">loadTopScores</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</nobr>
+        
+        <div class="jd-descrdiv">Asynchronously load the top page of scores for a given leaderboard.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#reconnect()">reconnect</a></span>()</nobr>
         
         <div class="jd-descrdiv">Closes the current connection to Google Play services and creates a new connection.</div>
@@ -1844,7 +1878,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1862,7 +1896,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1881,7 +1915,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1899,6 +1933,24 @@
 
 
 	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#revealAchievement(java.lang.String)">revealAchievement</a></span>(String id)</nobr>
+        
+        <div class="jd-descrdiv">Reveal a hidden achievement to the currently signed in player.</div>
+  
+  </td></tr>
+
+
+	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1909,7 +1961,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#revealAchievement(java.lang.String)">revealAchievement</a></span>(<a href="/reference/java/lang/String.html">String</a> id)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#revealAchievementImmediate(com.google.android.gms.games.achievement.OnAchievementUpdatedListener, java.lang.String)">revealAchievementImmediate</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, String id)</nobr>
         
         <div class="jd-descrdiv">Reveal a hidden achievement to the currently signed in player.</div>
   
@@ -1924,28 +1976,10 @@
             
             
             
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#revealAchievementImmediate(com.google.android.gms.games.achievement.OnAchievementUpdatedListener, java.lang.String)">revealAchievementImmediate</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> id)</nobr>
-        
-        <div class="jd-descrdiv">Reveal a hidden achievement to the currently signed in player.</div>
-  
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendReliableRealTimeMessage(com.google.android.gms.games.multiplayer.realtime.RealTimeReliableMessageSentListener, byte[], java.lang.String, java.lang.String)">sendReliableRealTimeMessage</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html">RealTimeReliableMessageSentListener</a> listener, byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/lang/String.html">String</a> recipientParticipantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendReliableRealTimeMessage(com.google.android.gms.games.multiplayer.realtime.RealTimeReliableMessageSentListener, byte[], java.lang.String, java.lang.String)">sendReliableRealTimeMessage</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html">RealTimeReliableMessageSentListener</a> listener, byte[] messageData, String roomId, String recipientParticipantId)</nobr>
         
         <div class="jd-descrdiv">Send a message to a participant in a real-time room reliably.</div>
   
@@ -1953,7 +1987,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1963,7 +1997,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendUnreliableRealTimeMessage(byte[], java.lang.String, java.util.List<java.lang.String>)">sendUnreliableRealTimeMessage</a></span>(byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; recipientParticipantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendUnreliableRealTimeMessage(byte[], java.lang.String, java.util.List<java.lang.String>)">sendUnreliableRealTimeMessage</a></span>(byte[] messageData, String roomId, List&lt;String&gt; recipientParticipantIds)</nobr>
         
         <div class="jd-descrdiv">Send a message to one or more participants in a real-time room.</div>
   
@@ -1971,24 +2005,6 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            int</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendUnreliableRealTimeMessage(byte[], java.lang.String, java.lang.String)">sendUnreliableRealTimeMessage</a></span>(byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/lang/String.html">String</a> recipientParticipantId)</nobr>
-        
-        <div class="jd-descrdiv">Send a message to a participant in a real-time room.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1999,7 +2015,25 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendUnreliableRealTimeMessageToAll(byte[], java.lang.String)">sendUnreliableRealTimeMessageToAll</a></span>(byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendUnreliableRealTimeMessage(byte[], java.lang.String, java.lang.String)">sendUnreliableRealTimeMessage</a></span>(byte[] messageData, String roomId, String recipientParticipantId)</nobr>
+        
+        <div class="jd-descrdiv">Send a message to a participant in a real-time room.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#sendUnreliableRealTimeMessageToAll(byte[], java.lang.String)">sendUnreliableRealTimeMessageToAll</a></span>(byte[] messageData, String roomId)</nobr>
         
         <div class="jd-descrdiv">Send a message to all participants in a real-time room.</div>
   
@@ -2007,7 +2041,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2026,7 +2060,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2045,7 +2079,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2055,7 +2089,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#setViewForPopups(android.view.View)">setViewForPopups</a></span>(<a href="/reference/android/view/View.html">View</a> gamesContentView)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#setViewForPopups(android.view.View)">setViewForPopups</a></span>(View gamesContentView)</nobr>
         
         <div class="jd-descrdiv">Sets the <code><a href="/reference/android/view/View.html">View</a></code> to use as a content view for popups.</div>
   
@@ -2063,7 +2097,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2081,7 +2115,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2099,24 +2133,6 @@
 
 
 	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#submitScore(java.lang.String, long)">submitScore</a></span>(<a href="/reference/java/lang/String.html">String</a> leaderboardId, long score)</nobr>
-        
-        <div class="jd-descrdiv">Submit a score to a leaderboard for the currently signed in player.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -2127,7 +2143,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#submitScoreImmediate(com.google.android.gms.games.leaderboard.OnScoreSubmittedListener, java.lang.String, long)">submitScoreImmediate</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html">OnScoreSubmittedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, long score)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#submitScore(java.lang.String, long)">submitScore</a></span>(String leaderboardId, long score)</nobr>
         
         <div class="jd-descrdiv">Submit a score to a leaderboard for the currently signed in player.</div>
   
@@ -2145,9 +2161,9 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#unlockAchievement(java.lang.String)">unlockAchievement</a></span>(<a href="/reference/java/lang/String.html">String</a> id)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#submitScoreImmediate(com.google.android.gms.games.leaderboard.OnScoreSubmittedListener, java.lang.String, long)">submitScoreImmediate</a></span>(<a href="/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html">OnScoreSubmittedListener</a> listener, String leaderboardId, long score)</nobr>
         
-        <div class="jd-descrdiv">Unlock an achievement for the currently signed in player.</div>
+        <div class="jd-descrdiv">Submit a score to a leaderboard for the currently signed in player.</div>
   
   </td></tr>
 
@@ -2163,7 +2179,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#unlockAchievementImmediate(com.google.android.gms.games.achievement.OnAchievementUpdatedListener, java.lang.String)">unlockAchievementImmediate</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> id)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#unlockAchievement(java.lang.String)">unlockAchievement</a></span>(String id)</nobr>
         
         <div class="jd-descrdiv">Unlock an achievement for the currently signed in player.</div>
   
@@ -2181,6 +2197,24 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#unlockAchievementImmediate(com.google.android.gms.games.achievement.OnAchievementUpdatedListener, java.lang.String)">unlockAchievementImmediate</a></span>(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, String id)</nobr>
+        
+        <div class="jd-descrdiv">Unlock an achievement for the currently signed in player.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/GamesClient.html#unregisterConnectionCallbacks(com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks)">unregisterConnectionCallbacks</a></span>(<a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> listener)</nobr>
         
         <div class="jd-descrdiv">Removes a connection listener from this <code>GooglePlayServicesClient</code>.</div>
@@ -2189,7 +2223,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2207,7 +2241,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -2247,7 +2281,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -2266,7 +2300,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -2285,7 +2319,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -2314,7 +2348,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -2378,7 +2412,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2687,7 +2721,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_EXCLUSIVE_BIT_MASK
     </h4>
@@ -2725,7 +2759,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_INVITATION
     </h4>
@@ -2764,7 +2798,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_MAX_AUTOMATCH_PLAYERS
     </h4>
@@ -2807,7 +2841,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_MIN_AUTOMATCH_PLAYERS
     </h4>
@@ -2850,7 +2884,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_PLAYERS
     </h4>
@@ -2893,7 +2927,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_ROOM
     </h4>
@@ -4152,7 +4186,7 @@
         void
       </span>
       <span class="sympad">declineRoomInvitation</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> invitationId)</span>
+      <span class="normal">(String invitationId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -4221,7 +4255,7 @@
         void
       </span>
       <span class="sympad">dismissRoomInvitation</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> invitationId)</span>
+      <span class="normal">(String invitationId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -4258,7 +4292,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getAchievementsIntent</span>
       <span class="normal">()</span>
@@ -4299,7 +4333,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getAllLeaderboardsIntent</span>
       <span class="normal">()</span>
@@ -4339,7 +4373,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAppId</span>
       <span class="normal">()</span>
@@ -4373,7 +4407,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getCurrentAccountName</span>
       <span class="normal">()</span>
@@ -4394,13 +4428,14 @@
  your manifest in order to use this method.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>Account name for the currently selected account.</li></ul>
+      <ul class="nolist"><li>Account name for the currently selected account. May be null if an error occurred
+         while communicating with the games service.</li></ul>
   </div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>If your app doesn't have the
              <code><a href="/reference/android/Manifest.permission.html#GET_ACCOUNTS">GET_ACCOUNTS</a></code> permission.
 </td>
@@ -4473,7 +4508,8 @@
   <div class="jd-tagdata jd-tagdescr"><p></p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li><code><a href="/reference/com/google/android/gms/games/Player.html">Player</a></code> representing the currently signed in player.
+      <ul class="nolist"><li><code><a href="/reference/com/google/android/gms/games/Player.html">Player</a></code> representing the currently signed in player. May be null if an error
+         occurred while communicating with the games service.
 </li></ul>
   </div>
 
@@ -4491,7 +4527,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getCurrentPlayerId</span>
       <span class="normal">()</span>
@@ -4507,7 +4543,8 @@
   <div class="jd-tagdata jd-tagdescr"><p></p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The player ID for the currently signed in player.
+      <ul class="nolist"><li>The player ID for the currently signed in player. May be null if an error occurred
+         while communicating with the games service.
 </li></ul>
   </div>
 
@@ -4525,7 +4562,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getInvitationInboxIntent</span>
       <span class="normal">()</span>
@@ -4566,10 +4603,10 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getLeaderboardIntent</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> leaderboardId)</span>
+      <span class="normal">(String leaderboardId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -4618,7 +4655,7 @@
         <a href="/reference/com/google/android/gms/games/RealTimeSocket.html">RealTimeSocket</a>
       </span>
       <span class="sympad">getRealTimeSocketForParticipant</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/lang/String.html">String</a> participantId)</span>
+      <span class="normal">(String roomId, String participantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -4666,7 +4703,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getRealTimeWaitingRoomIntent</span>
       <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, int minParticipantsToStart)</span>
@@ -4753,7 +4790,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getSelectPlayersIntent</span>
       <span class="normal">(int minPlayers, int maxPlayers)</span>
@@ -4817,7 +4854,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getSettingsIntent</span>
       <span class="normal">()</span>
@@ -4865,7 +4902,7 @@
         void
       </span>
       <span class="sympad">incrementAchievement</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> id, int numSteps)</span>
+      <span class="normal">(String id, int numSteps)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -4917,7 +4954,7 @@
         void
       </span>
       <span class="sympad">incrementAchievementImmediate</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> id, int numSteps)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, String id, int numSteps)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5176,7 +5213,7 @@
         void
       </span>
       <span class="sympad">leaveRoom</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html">RoomUpdateListener</a> listener, <a href="/reference/java/lang/String.html">String</a> roomId)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html">RoomUpdateListener</a> listener, String roomId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5212,52 +5249,6 @@
 </div>
 
 
-<A NAME="loadAchievements(com.google.android.gms.games.achievement.OnAchievementsLoadedListener)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-         
-         
-        void
-      </span>
-      <span class="sympad">loadAchievements</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html">OnAchievementsLoadedListener</a> listener)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Asynchronously load achievement data for the currently signed in player.
- <p>
- The result is delivered to the given listener on the main thread. If <code><a href="/reference/com/google/android/gms/games/GamesClient.html#disconnect()">disconnect()</a></code> is
- called before the result is ready it will not be delivered.
- <p>
- This form of the API is deprecated and will be removed in a future release. Please use
- <code><a href="/reference/com/google/android/gms/games/GamesClient.html#loadAchievements(com.google.android.gms.games.achievement.OnAchievementsLoadedListener, boolean)">loadAchievements(OnAchievementsLoadedListener, boolean)</a></code> instead.</p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Parameters</h5>
-      <table class="jd-tagtable">
-        <tr>
-          <th>listener</td>
-          <td>The listener that is called when the load is complete. The listener is called
-            on the main thread.
-</td>
-        </tr>
-      </table>
-  </div>
-
-    </div>
-</div>
-
-
 <A NAME="loadAchievements(com.google.android.gms.games.achievement.OnAchievementsLoadedListener, boolean)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -5449,6 +5440,56 @@
 </div>
 
 
+<A NAME="loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, boolean)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">loadLeaderboardMetadata</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, boolean forceReload)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Asynchronously load the list of leaderboard metadata for this game.
+ <p>
+ The result is delivered to the given listener on the main thread. If <code><a href="/reference/com/google/android/gms/games/GamesClient.html#disconnect()">disconnect()</a></code> is
+ called before the result is ready it will not be delivered.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>listener</td>
+          <td>The listener that is called when the load is complete. The listener is called
+            on the main thread.</td>
+        </tr>
+        <tr>
+          <th>forceReload</td>
+          <td>If true, this call will clear any locally cached data and attempt to fetch
+            the latest data from the server. This would commonly be used for something like a
+            user-initiated refresh. Normally, this should be set to false to gain advantages
+            of data caching.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -5462,7 +5503,7 @@
         void
       </span>
       <span class="sympad">loadLeaderboardMetadata</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, String leaderboardId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5471,7 +5512,14 @@
 
       </div>
     <div class="jd-details-descr">
-      
+      <p>
+  <p class="caution"><strong>
+      This method is deprecated.</strong><br/>
+    This form of the API is deprecated and will be removed in a future release. 
+ Please use <code><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String, boolean)">loadLeaderboardMetadata(OnLeaderboardMetadataLoadedListener, String, boolean)</a></code>
+ instead.
+
+  </p>
   <div class="jd-tagdata jd-tagdescr"><p>Asynchronously load a specific leaderboard's metadata for this game.
  <p>
  The result is delivered to the given listener on the main thread. If <code><a href="/reference/com/google/android/gms/games/GamesClient.html#disconnect()">disconnect()</a></code> is
@@ -5486,8 +5534,7 @@
         </tr>
         <tr>
           <th>leaderboardId</td>
-          <td>ID of the leaderboard to load metadata for.
-</td>
+          <td>ID of the leaderboard to load metadata for.</td>
         </tr>
       </table>
   </div>
@@ -5518,7 +5565,13 @@
 
       </div>
     <div class="jd-details-descr">
-      
+      <p>
+  <p class="caution"><strong>
+      This method is deprecated.</strong><br/>
+    This form of the API is deprecated and will be removed in a future release. 
+ Please use <code><a href="/reference/com/google/android/gms/games/GamesClient.html#loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, boolean)">loadLeaderboardMetadata(OnLeaderboardMetadataLoadedListener, boolean)</a></code> instead.
+
+  </p>
   <div class="jd-tagdata jd-tagdescr"><p>Asynchronously load the list of leaderboard metadata for this game.
  <p>
  The result is delivered to the given listener on the main thread. If <code><a href="/reference/com/google/android/gms/games/GamesClient.html#disconnect()">disconnect()</a></code> is
@@ -5529,7 +5582,60 @@
         <tr>
           <th>listener</td>
           <td>The listener that is called when the load is complete. The listener is called
-            on the main thread.
+            on the main thread.</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
+<A NAME="loadLeaderboardMetadata(com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener, java.lang.String, boolean)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">loadLeaderboardMetadata</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html">OnLeaderboardMetadataLoadedListener</a> listener, String leaderboardId, boolean forceReload)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Asynchronously load a specific leaderboard's metadata for this game.
+ <p>
+ The result is delivered to the given listener on the main thread. If <code><a href="/reference/com/google/android/gms/games/GamesClient.html#disconnect()">disconnect()</a></code> is
+ called before the result is ready it will not be delivered.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>listener</td>
+          <td>The listener that is called when the load is complete. The listener is called
+            on the main thread.</td>
+        </tr>
+        <tr>
+          <th>leaderboardId</td>
+          <td>ID of the leaderboard to load metadata for.</td>
+        </tr>
+        <tr>
+          <th>forceReload</td>
+          <td>If true, this call will clear any locally cached data and attempt to fetch
+            the latest data from the server. This would commonly be used for something like a
+            user-initiated refresh. Normally, this should be set to false to gain advantages
+            of data caching.
 </td>
         </tr>
       </table>
@@ -5658,7 +5764,7 @@
         void
       </span>
       <span class="sympad">loadPlayer</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/OnPlayersLoadedListener.html">OnPlayersLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> playerId)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/OnPlayersLoadedListener.html">OnPlayersLoadedListener</a> listener, String playerId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5705,7 +5811,7 @@
         void
       </span>
       <span class="sympad">loadPlayerCenteredScores</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5777,7 +5883,7 @@
         void
       </span>
       <span class="sympad">loadPlayerCenteredScores</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5842,7 +5948,7 @@
         void
       </span>
       <span class="sympad">loadTopScores</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -5906,7 +6012,7 @@
         void
       </span>
       <span class="sympad">loadTopScores</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html">OnLeaderboardScoresLoadedListener</a> listener, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6168,7 +6274,7 @@
         void
       </span>
       <span class="sympad">revealAchievement</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> id)</span>
+      <span class="normal">(String id)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6219,7 +6325,7 @@
         void
       </span>
       <span class="sympad">revealAchievementImmediate</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> id)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, String id)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6275,7 +6381,7 @@
         int
       </span>
       <span class="sympad">sendReliableRealTimeMessage</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html">RealTimeReliableMessageSentListener</a> listener, byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/lang/String.html">String</a> recipientParticipantId)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html">RealTimeReliableMessageSentListener</a> listener, byte[] messageData, String roomId, String recipientParticipantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6337,7 +6443,7 @@
         int
       </span>
       <span class="sympad">sendUnreliableRealTimeMessage</span>
-      <span class="normal">(byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; recipientParticipantIds)</span>
+      <span class="normal">(byte[] messageData, String roomId, List&lt;String&gt; recipientParticipantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6394,7 +6500,7 @@
         int
       </span>
       <span class="sympad">sendUnreliableRealTimeMessage</span>
-      <span class="normal">(byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId, <a href="/reference/java/lang/String.html">String</a> recipientParticipantId)</span>
+      <span class="normal">(byte[] messageData, String roomId, String recipientParticipantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6451,7 +6557,7 @@
         int
       </span>
       <span class="sympad">sendUnreliableRealTimeMessageToAll</span>
-      <span class="normal">(byte[] messageData, <a href="/reference/java/lang/String.html">String</a> roomId)</span>
+      <span class="normal">(byte[] messageData, String roomId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6584,7 +6690,7 @@
         void
       </span>
       <span class="sympad">setViewForPopups</span>
-      <span class="normal">(<a href="/reference/android/view/View.html">View</a> gamesContentView)</span>
+      <span class="normal">(View gamesContentView)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6696,7 +6802,7 @@
         void
       </span>
       <span class="sympad">submitScore</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> leaderboardId, long score)</span>
+      <span class="normal">(String leaderboardId, long score)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6761,7 +6867,7 @@
         void
       </span>
       <span class="sympad">submitScoreImmediate</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html">OnScoreSubmittedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> leaderboardId, long score)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html">OnScoreSubmittedListener</a> listener, String leaderboardId, long score)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6837,7 +6943,7 @@
         void
       </span>
       <span class="sympad">unlockAchievement</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> id)</span>
+      <span class="normal">(String id)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -6888,7 +6994,7 @@
         void
       </span>
       <span class="sympad">unlockAchievementImmediate</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> id)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html">OnAchievementUpdatedListener</a> listener, String id)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/OnGamesLoadedListener.html b/docs/html/reference/com/google/android/gms/games/OnGamesLoadedListener.html
index e715f6c..d92b0eb 100644
--- a/docs/html/reference/com/google/android/gms/games/OnGamesLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/OnGamesLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnGamesLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/OnPlayersLoadedListener.html b/docs/html/reference/com/google/android/gms/games/OnPlayersLoadedListener.html
index 050fe70..40113a0 100644
--- a/docs/html/reference/com/google/android/gms/games/OnPlayersLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/OnPlayersLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnPlayersLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/OnSignOutCompleteListener.html b/docs/html/reference/com/google/android/gms/games/OnSignOutCompleteListener.html
index f1f7c5a..63a03b5 100644
--- a/docs/html/reference/com/google/android/gms/games/OnSignOutCompleteListener.html
+++ b/docs/html/reference/com/google/android/gms/games/OnSignOutCompleteListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnSignOutCompleteListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/PageDirection.html b/docs/html/reference/com/google/android/gms/games/PageDirection.html
index 4022f29..4572efe 100644
--- a/docs/html/reference/com/google/android/gms/games/PageDirection.html
+++ b/docs/html/reference/com/google/android/gms/games/PageDirection.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PageDirection | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -826,7 +833,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -845,7 +852,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -864,7 +871,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -893,7 +900,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -957,7 +964,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/Player.html b/docs/html/reference/com/google/android/gms/games/Player.html
index c5343a6..019aeb6 100644
--- a/docs/html/reference/com/google/android/gms/games/Player.html
+++ b/docs/html/reference/com/google/android/gms/games/Player.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Player | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -693,7 +700,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/common/data/Freezable.html">Freezable</a>&lt;T&gt; 
       
@@ -874,7 +881,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -895,7 +902,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the player's display name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -910,7 +917,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -928,7 +935,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -946,7 +953,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getPlayerId()">getPlayerId</a></span>()</nobr>
@@ -1033,7 +1040,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1071,7 +1078,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1196,7 +1203,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -1233,7 +1240,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1269,7 +1276,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getHiResImageUri</span>
       <span class="normal">()</span>
@@ -1306,7 +1313,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -1344,7 +1351,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPlayerId</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/PlayerBuffer.html b/docs/html/reference/com/google/android/gms/games/PlayerBuffer.html
index 0857022..30a6689 100644
--- a/docs/html/reference/com/google/android/gms/games/PlayerBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/PlayerBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlayerBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/PlayerEntity.html b/docs/html/reference/com/google/android/gms/games/PlayerEntity.html
index e3f858e..b3a4ab1 100644
--- a/docs/html/reference/com/google/android/gms/games/PlayerEntity.html
+++ b/docs/html/reference/com/google/android/gms/games/PlayerEntity.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlayerEntity | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -679,9 +686,6 @@
   
 
 
-  &#124; <a href="#promethods">Protected Methods</a>
-  
-
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -710,7 +714,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -719,7 +723,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/games/Player.html">Player</a> 
       
@@ -737,7 +741,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -872,7 +876,7 @@
           public
           static
           final
-          <a href="/reference/com/google/android/gms/games/PlayerEntityCreator.html">PlayerEntityCreator</a></nobr></td>
+          Creator&lt;<a href="/reference/com/google/android/gms/games/PlayerEntity.html">PlayerEntity</a>&gt;</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#CREATOR">CREATOR</a></td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -923,7 +927,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> obj)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#equals(java.lang.Object)">equals</a></span>(Object obj)</nobr>
         
   </td></tr>
 
@@ -954,7 +958,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -975,7 +979,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the player's display name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -990,7 +994,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1008,7 +1012,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1026,7 +1030,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getPlayerId()">getPlayerId</a></span>()</nobr>
@@ -1132,7 +1136,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#toString()">toString</a></span>()</nobr>
@@ -1151,7 +1155,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel dest, int flags)</nobr>
         
   </td></tr>
 
@@ -1162,63 +1166,6 @@
 
 
 
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getUnparcelClassLoader()">getUnparcelClassLoader</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/Integer.html">Integer</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#getUnparcelClientVersion()">getUnparcelClientVersion</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/PlayerEntity.html#shouldDowngrade()">shouldDowngrade</a></span>()</nobr>
-        
-  </td></tr>
-
-
-
-</table>
-
-
 
 
 
@@ -1236,7 +1183,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1255,7 +1202,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1274,7 +1221,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1303,7 +1250,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1367,7 +1314,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1438,7 +1385,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1476,7 +1423,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1577,7 +1524,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -1598,7 +1545,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the player's display name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1613,7 +1560,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1631,7 +1578,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1649,7 +1596,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/Player.html#getPlayerId()">getPlayerId</a></span>()</nobr>
@@ -1759,7 +1706,7 @@
         public 
         static 
         final 
-        <a href="/reference/com/google/android/gms/games/PlayerEntityCreator.html">PlayerEntityCreator</a>
+        Creator&lt;<a href="/reference/com/google/android/gms/games/PlayerEntity.html">PlayerEntity</a>&gt;
       </span>
         CREATOR
     </h4>
@@ -1838,7 +1785,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> obj)</span>
+      <span class="normal">(Object obj)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1911,7 +1858,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -1948,7 +1895,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1984,7 +1931,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getHiResImageUri</span>
       <span class="normal">()</span>
@@ -2021,7 +1968,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -2059,7 +2006,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPlayerId</span>
       <span class="normal">()</span>
@@ -2260,7 +2207,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -2292,7 +2239,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</span>
+      <span class="normal">(Parcel dest, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2313,113 +2260,6 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
-<h2>Protected Methods</h2>
-
-
-
-<A NAME="getUnparcelClassLoader()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a>
-      </span>
-      <span class="sympad">getUnparcelClassLoader</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The ClassLoader to use for unparceling, if any.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="getUnparcelClientVersion()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/Integer.html">Integer</a>
-      </span>
-      <span class="sympad">getUnparcelClientVersion</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The client version to use for unparceling, if known.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="shouldDowngrade()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-         
-         
-         
-         
-        boolean
-      </span>
-      <span class="sympad">shouldDowngrade</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>Whether or not this object has been downgraded to hand back to a client.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/games/RealTimeSocket.html b/docs/html/reference/com/google/android/gms/games/RealTimeSocket.html
index ca4ce65..e0f0b9b 100644
--- a/docs/html/reference/com/google/android/gms/games/RealTimeSocket.html
+++ b/docs/html/reference/com/google/android/gms/games/RealTimeSocket.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RealTimeSocket | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -779,7 +786,7 @@
             
             
             
-            <a href="/reference/java/io/InputStream.html">InputStream</a></nobr>
+            InputStream</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/RealTimeSocket.html#getInputStream()">getInputStream</a></span>()</nobr>
@@ -797,7 +804,7 @@
             
             
             
-            <a href="/reference/java/io/OutputStream.html">OutputStream</a></nobr>
+            OutputStream</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/RealTimeSocket.html#getOutputStream()">getOutputStream</a></span>()</nobr>
@@ -815,7 +822,7 @@
             
             
             
-            <a href="/reference/android/os/ParcelFileDescriptor.html">ParcelFileDescriptor</a></nobr>
+            ParcelFileDescriptor</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/RealTimeSocket.html#getParcelFileDescriptor()">getParcelFileDescriptor</a></span>()</nobr>
@@ -919,7 +926,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>on error.
 </td>
         </tr>
@@ -940,7 +947,7 @@
          
         abstract 
          
-        <a href="/reference/java/io/InputStream.html">InputStream</a>
+        InputStream
       </span>
       <span class="sympad">getInputStream</span>
       <span class="normal">()</span>
@@ -963,7 +970,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>on error.
 </td>
         </tr>
@@ -984,7 +991,7 @@
          
         abstract 
          
-        <a href="/reference/java/io/OutputStream.html">OutputStream</a>
+        OutputStream
       </span>
       <span class="sympad">getOutputStream</span>
       <span class="normal">()</span>
@@ -1012,7 +1019,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>on error.
 </td>
         </tr>
@@ -1033,7 +1040,7 @@
          
         abstract 
          
-        <a href="/reference/android/os/ParcelFileDescriptor.html">ParcelFileDescriptor</a>
+        ParcelFileDescriptor
       </span>
       <span class="sympad">getParcelFileDescriptor</span>
       <span class="normal">()</span>
@@ -1057,7 +1064,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>in case of error.
 </td>
         </tr>
diff --git a/docs/html/reference/com/google/android/gms/games/achievement/Achievement.html b/docs/html/reference/com/google/android/gms/games/achievement/Achievement.html
index 805c159..423da05 100644
--- a/docs/html/reference/com/google/android/gms/games/achievement/Achievement.html
+++ b/docs/html/reference/com/google/android/gms/games/achievement/Achievement.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Achievement | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -792,7 +799,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getAchievementId()">getAchievementId</a></span>()</nobr>
@@ -829,7 +836,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getDescription()">getDescription</a></span>()</nobr>
@@ -850,7 +857,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the achievement description into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -868,7 +875,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getFormattedCurrentSteps(android.database.CharArrayBuffer)">getFormattedCurrentSteps</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getFormattedCurrentSteps(android.database.CharArrayBuffer)">getFormattedCurrentSteps</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Retrieves the number of steps this user has gone toward unlocking this achievement (formatted
  for the user's locale) into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
@@ -884,7 +891,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getFormattedCurrentSteps()">getFormattedCurrentSteps</a></span>()</nobr>
@@ -907,7 +914,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getFormattedTotalSteps(android.database.CharArrayBuffer)">getFormattedTotalSteps</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getFormattedTotalSteps(android.database.CharArrayBuffer)">getFormattedTotalSteps</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the total number of steps necessary to unlock this achievement (formatted for the
  user's locale) into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>; only applicable for
@@ -924,7 +931,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getFormattedTotalSteps()">getFormattedTotalSteps</a></span>()</nobr>
@@ -965,7 +972,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getName(android.database.CharArrayBuffer)">getName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getName(android.database.CharArrayBuffer)">getName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the achievement name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -980,7 +987,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getName()">getName</a></span>()</nobr>
@@ -1016,7 +1023,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getRevealedImageUri()">getRevealedImageUri</a></span>()</nobr>
@@ -1091,7 +1098,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/Achievement.html#getUnlockedImageUri()">getUnlockedImageUri</a></span>()</nobr>
@@ -1361,7 +1368,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAchievementId</span>
       <span class="normal">()</span>
@@ -1430,7 +1437,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -1467,7 +1474,7 @@
         void
       </span>
       <span class="sympad">getDescription</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1506,7 +1513,7 @@
         void
       </span>
       <span class="sympad">getFormattedCurrentSteps</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1543,7 +1550,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getFormattedCurrentSteps</span>
       <span class="normal">()</span>
@@ -1582,7 +1589,7 @@
         void
       </span>
       <span class="sympad">getFormattedTotalSteps</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1620,7 +1627,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getFormattedTotalSteps</span>
       <span class="normal">()</span>
@@ -1693,7 +1700,7 @@
         void
       </span>
       <span class="sympad">getName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1729,7 +1736,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getName</span>
       <span class="normal">()</span>
@@ -1800,7 +1807,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getRevealedImageUri</span>
       <span class="normal">()</span>
@@ -1943,7 +1950,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getUnlockedImageUri</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/achievement/AchievementBuffer.html b/docs/html/reference/com/google/android/gms/games/achievement/AchievementBuffer.html
index f503274..b50fe88 100644
--- a/docs/html/reference/com/google/android/gms/games/achievement/AchievementBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/achievement/AchievementBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>AchievementBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html b/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html
index 1d5312f..3eff16d 100644
--- a/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnAchievementUpdatedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -752,7 +759,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html#onAchievementUpdated(int, java.lang.String)">onAchievementUpdated</a></span>(int statusCode, <a href="/reference/java/lang/String.html">String</a> achievementId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html#onAchievementUpdated(int, java.lang.String)">onAchievementUpdated</a></span>(int statusCode, String achievementId)</nobr>
         
         <div class="jd-descrdiv">Called when achievement data has been loaded.</div>
   
@@ -820,7 +827,7 @@
         void
       </span>
       <span class="sympad">onAchievementUpdated</span>
-      <span class="normal">(int statusCode, <a href="/reference/java/lang/String.html">String</a> achievementId)</span>
+      <span class="normal">(int statusCode, String achievementId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html b/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html
index ff745b0..7a66f0e 100644
--- a/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnAchievementsLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/achievement/package-summary.html b/docs/html/reference/com/google/android/gms/games/achievement/package-summary.html
index 0e6c871..512368f 100644
--- a/docs/html/reference/com/google/android/gms/games/achievement/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/games/achievement/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.games.achievement | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/Leaderboard.html b/docs/html/reference/com/google/android/gms/games/leaderboard/Leaderboard.html
index 0536eef0..6430211 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/Leaderboard.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/Leaderboard.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Leaderboard | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -771,7 +778,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/Leaderboard.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -792,7 +799,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/Leaderboard.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/Leaderboard.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads this leaderboard's display name into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -807,7 +814,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/Leaderboard.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -826,7 +833,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/Leaderboard.html#getLeaderboardId()">getLeaderboardId</a></span>()</nobr>
@@ -862,7 +869,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html">LeaderboardVariant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html">LeaderboardVariant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/Leaderboard.html#getVariants()">getVariants</a></span>()</nobr>
@@ -1015,7 +1022,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -1052,7 +1059,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1088,7 +1095,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -1126,7 +1133,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getLeaderboardId</span>
       <span class="normal">()</span>
@@ -1195,7 +1202,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html">LeaderboardVariant</a>&gt;
+        ArrayList&lt;<a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html">LeaderboardVariant</a>&gt;
       </span>
       <span class="sympad">getVariants</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html
index add3ff47..7bd82fb 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LeaderboardBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -719,7 +726,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -884,7 +891,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html#getPrimaryDataMarkerColumn()">getPrimaryDataMarkerColumn</a></span>()</nobr>
@@ -1017,7 +1024,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -1040,7 +1047,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1059,7 +1066,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1078,7 +1085,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1107,7 +1114,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1171,7 +1178,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1242,7 +1249,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1261,7 +1268,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
@@ -1461,7 +1468,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPrimaryDataMarkerColumn</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html
index 5a2898c..9ac6a19 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LeaderboardScore | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -784,7 +791,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getDisplayRank(android.database.CharArrayBuffer)">getDisplayRank</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getDisplayRank(android.database.CharArrayBuffer)">getDisplayRank</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Load the formatted display rank into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -799,7 +806,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getDisplayRank()">getDisplayRank</a></span>()</nobr>
@@ -817,7 +824,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getDisplayScore()">getDisplayScore</a></span>()</nobr>
@@ -838,7 +845,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getDisplayScore(android.database.CharArrayBuffer)">getDisplayScore</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getDisplayScore(android.database.CharArrayBuffer)">getDisplayScore</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the formatted display score into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -907,7 +914,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getScoreHolderDisplayName()">getScoreHolderDisplayName</a></span>()</nobr>
@@ -928,7 +935,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getScoreHolderDisplayName(android.database.CharArrayBuffer)">getScoreHolderDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getScoreHolderDisplayName(android.database.CharArrayBuffer)">getScoreHolderDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Load the display name of the player who scored this score into the provided
  <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
@@ -944,7 +951,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getScoreHolderHiResImageUri()">getScoreHolderHiResImageUri</a></span>()</nobr>
@@ -962,7 +969,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html#getScoreHolderIconImageUri()">getScoreHolderIconImageUri</a></span>()</nobr>
@@ -1121,7 +1128,7 @@
         void
       </span>
       <span class="sympad">getDisplayRank</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1157,7 +1164,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayRank</span>
       <span class="normal">()</span>
@@ -1192,7 +1199,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayScore</span>
       <span class="normal">()</span>
@@ -1230,7 +1237,7 @@
         void
       </span>
       <span class="sympad">getDisplayScore</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1374,7 +1381,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getScoreHolderDisplayName</span>
       <span class="normal">()</span>
@@ -1412,7 +1419,7 @@
         void
       </span>
       <span class="sympad">getScoreHolderDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1449,7 +1456,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getScoreHolderHiResImageUri</span>
       <span class="normal">()</span>
@@ -1487,7 +1494,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getScoreHolderIconImageUri</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScoreBuffer.html b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScoreBuffer.html
index 29b23c2..92d4402 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScoreBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardScoreBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LeaderboardScoreBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html
index 5e213be..f41bc76 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LeaderboardVariant | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -839,7 +846,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html#getDisplayPlayerRank()">getDisplayPlayerRank</a></span>()</nobr>
@@ -857,7 +864,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html#getDisplayPlayerScore()">getDisplayPlayerScore</a></span>()</nobr>
@@ -1410,7 +1417,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayPlayerRank</span>
       <span class="normal">()</span>
@@ -1446,7 +1453,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayPlayerScore</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html b/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html
index f702644..61c8647 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnLeaderboardMetadataLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html b/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html
index 0f6c6c2..70c38e3 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnLeaderboardScoresLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html b/docs/html/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html
index a8fa8ff4..1cdf513 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnScoreSubmittedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html b/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html
index 93d45c6..fb23860 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>SubmitScoreResult.Result | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -784,7 +791,7 @@
           public
           
           final
-          <a href="/reference/java/lang/String.html">String</a></nobr></td>
+          String</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html#formattedScore">formattedScore</a></td>
           <td class="jd-descrcol" width="100%">String containing the score data in a display-appropriate format.</td>
       </tr>
@@ -838,7 +845,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html#SubmitScoreResult.Result(long, java.lang.String, boolean)">SubmitScoreResult.Result</a></span>(long rawScore, <a href="/reference/java/lang/String.html">String</a> formattedScore, boolean newBest)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html#SubmitScoreResult.Result(long, java.lang.String, boolean)">SubmitScoreResult.Result</a></span>(long rawScore, String formattedScore, boolean newBest)</nobr>
         
   </td></tr>
 
@@ -864,7 +871,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html#toString()">toString</a></span>()</nobr>
@@ -895,7 +902,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -914,7 +921,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -933,7 +940,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -962,7 +969,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1026,7 +1033,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1128,7 +1135,7 @@
         public 
          
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         formattedScore
     </h4>
@@ -1230,7 +1237,7 @@
         
       </span>
       <span class="sympad">SubmitScoreResult.Result</span>
-      <span class="normal">(long rawScore, <a href="/reference/java/lang/String.html">String</a> formattedScore, boolean newBest)</span>
+      <span class="normal">(long rawScore, String formattedScore, boolean newBest)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1271,7 +1278,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html b/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html
index ca4cf75..79566f9 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>SubmitScoreResult | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -815,7 +822,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#SubmitScoreResult(int, java.lang.String, java.lang.String, java.util.HashMap<java.lang.Integer, com.google.android.gms.games.leaderboard.SubmitScoreResult.Result>)">SubmitScoreResult</a></span>(int statusCode, <a href="/reference/java/lang/String.html">String</a> leaderboardId, <a href="/reference/java/lang/String.html">String</a> playerId, <a href="/reference/java/util/HashMap.html">HashMap</a>&lt;<a href="/reference/java/lang/Integer.html">Integer</a>,&nbsp;<a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html">SubmitScoreResult.Result</a>&gt; results)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#SubmitScoreResult(int, java.lang.String, java.lang.String, java.util.HashMap<java.lang.Integer, com.google.android.gms.games.leaderboard.SubmitScoreResult.Result>)">SubmitScoreResult</a></span>(int statusCode, String leaderboardId, String playerId, HashMap&lt;Integer,&nbsp;<a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html">SubmitScoreResult.Result</a>&gt; results)</nobr>
         
         <div class="jd-descrdiv">Construct a new result describing a SubmitScore operation.</div>
   
@@ -833,7 +840,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#SubmitScoreResult(int, java.lang.String, java.lang.String)">SubmitScoreResult</a></span>(int statusCode, <a href="/reference/java/lang/String.html">String</a> leaderboardId, <a href="/reference/java/lang/String.html">String</a> playerId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#SubmitScoreResult(int, java.lang.String, java.lang.String)">SubmitScoreResult</a></span>(int statusCode, String leaderboardId, String playerId)</nobr>
         
   </td></tr>
 
@@ -859,7 +866,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#getLeaderboardId()">getLeaderboardId</a></span>()</nobr>
@@ -877,7 +884,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#getPlayerId()">getPlayerId</a></span>()</nobr>
@@ -931,7 +938,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html#toString()">toString</a></span>()</nobr>
@@ -962,7 +969,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -981,7 +988,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1000,7 +1007,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1029,7 +1036,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1093,7 +1100,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1202,7 +1209,7 @@
         
       </span>
       <span class="sympad">SubmitScoreResult</span>
-      <span class="normal">(int statusCode, <a href="/reference/java/lang/String.html">String</a> leaderboardId, <a href="/reference/java/lang/String.html">String</a> playerId, <a href="/reference/java/util/HashMap.html">HashMap</a>&lt;<a href="/reference/java/lang/Integer.html">Integer</a>,&nbsp;<a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html">SubmitScoreResult.Result</a>&gt; results)</span>
+      <span class="normal">(int statusCode, String leaderboardId, String playerId, HashMap&lt;Integer,&nbsp;<a href="/reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html">SubmitScoreResult.Result</a>&gt; results)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1253,7 +1260,7 @@
         
       </span>
       <span class="sympad">SubmitScoreResult</span>
-      <span class="normal">(int statusCode, <a href="/reference/java/lang/String.html">String</a> leaderboardId, <a href="/reference/java/lang/String.html">String</a> playerId)</span>
+      <span class="normal">(int statusCode, String leaderboardId, String playerId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1294,7 +1301,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getLeaderboardId</span>
       <span class="normal">()</span>
@@ -1328,7 +1335,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPlayerId</span>
       <span class="normal">()</span>
@@ -1451,7 +1458,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/leaderboard/package-summary.html b/docs/html/reference/com/google/android/gms/games/leaderboard/package-summary.html
index 25ffcdf..7f3d260 100644
--- a/docs/html/reference/com/google/android/gms/games/leaderboard/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/games/leaderboard/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.games.leaderboard | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/Invitation.html b/docs/html/reference/com/google/android/gms/games/multiplayer/Invitation.html
index b4e7bce..2ff6482 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/Invitation.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/Invitation.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Invitation | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -700,7 +707,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/common/data/Freezable.html">Freezable</a>&lt;T&gt; 
       
@@ -921,7 +928,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Invitation.html#getInvitationId()">getInvitationId</a></span>()</nobr>
@@ -990,7 +997,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1028,7 +1035,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1129,7 +1136,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participatable.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -1265,7 +1272,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getInvitationId</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html b/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html
index ae9ee17..3d86e70 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>InvitationBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -719,7 +726,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -884,7 +891,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html#getPrimaryDataMarkerColumn()">getPrimaryDataMarkerColumn</a></span>()</nobr>
@@ -1017,7 +1024,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -1040,7 +1047,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1059,7 +1066,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1078,7 +1085,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1107,7 +1114,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1171,7 +1178,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1242,7 +1249,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1261,7 +1268,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
@@ -1461,7 +1468,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPrimaryDataMarkerColumn</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html b/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html
index 65b1d8f..3a5bff5 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>InvitationEntity | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -686,9 +693,6 @@
   
 
 
-  &#124; <a href="#promethods">Protected Methods</a>
-  
-
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -717,7 +721,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -726,7 +730,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/games/multiplayer/Invitation.html">Invitation</a> 
       
@@ -744,7 +748,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -881,7 +885,7 @@
           public
           static
           final
-          <a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntityCreator.html">InvitationEntityCreator</a></nobr></td>
+          Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html">InvitationEntity</a>&gt;</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#CREATOR">CREATOR</a></td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -932,7 +936,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> obj)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#equals(java.lang.Object)">equals</a></span>(Object obj)</nobr>
         
   </td></tr>
 
@@ -999,7 +1003,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#getInvitationId()">getInvitationId</a></span>()</nobr>
@@ -1035,7 +1039,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -1105,7 +1109,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#toString()">toString</a></span>()</nobr>
@@ -1124,7 +1128,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel dest, int flags)</nobr>
         
   </td></tr>
 
@@ -1135,63 +1139,6 @@
 
 
 
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#getUnparcelClassLoader()">getUnparcelClassLoader</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/Integer.html">Integer</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#getUnparcelClientVersion()">getUnparcelClientVersion</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html#shouldDowngrade()">shouldDowngrade</a></span>()</nobr>
-        
-  </td></tr>
-
-
-
-</table>
-
-
 
 
 
@@ -1209,7 +1156,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1228,7 +1175,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1247,7 +1194,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1276,7 +1223,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1340,7 +1287,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1411,7 +1358,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1449,7 +1396,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1586,7 +1533,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Invitation.html#getInvitationId()">getInvitationId</a></span>()</nobr>
@@ -1666,7 +1613,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participatable.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -1722,7 +1669,7 @@
         public 
         static 
         final 
-        <a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntityCreator.html">InvitationEntityCreator</a>
+        Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/InvitationEntity.html">InvitationEntity</a>&gt;
       </span>
         CREATOR
     </h4>
@@ -1801,7 +1748,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> obj)</span>
+      <span class="normal">(Object obj)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1942,7 +1889,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getInvitationId</span>
       <span class="normal">()</span>
@@ -2010,7 +1957,7 @@
          
          
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;
+        ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;
       </span>
       <span class="sympad">getParticipants</span>
       <span class="normal">()</span>
@@ -2147,7 +2094,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -2179,7 +2126,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</span>
+      <span class="normal">(Parcel dest, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2200,113 +2147,6 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
-<h2>Protected Methods</h2>
-
-
-
-<A NAME="getUnparcelClassLoader()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a>
-      </span>
-      <span class="sympad">getUnparcelClassLoader</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The ClassLoader to use for unparceling, if any.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="getUnparcelClientVersion()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/Integer.html">Integer</a>
-      </span>
-      <span class="sympad">getUnparcelClientVersion</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The client version to use for unparceling, if known.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="shouldDowngrade()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-         
-         
-         
-         
-        boolean
-      </span>
-      <span class="sympad">shouldDowngrade</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>Whether or not this object has been downgraded to hand back to a client.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html b/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html
index 0f8e57e..b43953e 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnInvitationReceivedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html b/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html
index ad26889..f14f652 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>OnInvitationsLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/Participant.html b/docs/html/reference/com/google/android/gms/games/multiplayer/Participant.html
index 02e4c54..b6aea99 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/Participant.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/Participant.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Participant | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/common/data/Freezable.html">Freezable</a>&lt;T&gt; 
       
@@ -914,7 +921,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -935,7 +942,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the display name for this participant into the provided <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -950,7 +957,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -968,7 +975,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -986,7 +993,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getParticipantId()">getParticipantId</a></span>()</nobr>
@@ -1073,7 +1080,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1111,7 +1118,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1399,7 +1406,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -1437,7 +1444,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1473,7 +1480,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getHiResImageUri</span>
       <span class="normal">()</span>
@@ -1510,7 +1517,7 @@
          
         abstract 
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -1548,7 +1555,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getParticipantId</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html b/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html
index 0277169..00f8171 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ParticipantBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html b/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html
index 45c5b00..356c5b2 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ParticipantEntity | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,9 +688,6 @@
   
 
 
-  &#124; <a href="#promethods">Protected Methods</a>
-  
-
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -712,7 +716,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -721,7 +725,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a> 
       
@@ -739,7 +743,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -924,7 +928,7 @@
           public
           static
           final
-          <a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntityCreator.html">ParticipantEntityCreator</a></nobr></td>
+          Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html">ParticipantEntity</a>&gt;</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#CREATOR">CREATOR</a></td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -975,7 +979,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> obj)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#equals(java.lang.Object)">equals</a></span>(Object obj)</nobr>
         
   </td></tr>
 
@@ -1006,7 +1010,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -1027,7 +1031,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the display name for this participant into the provided <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1042,7 +1046,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1060,7 +1064,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1078,7 +1082,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getParticipantId()">getParticipantId</a></span>()</nobr>
@@ -1184,7 +1188,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#toString()">toString</a></span>()</nobr>
@@ -1203,7 +1207,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel dest, int flags)</nobr>
         
   </td></tr>
 
@@ -1214,63 +1218,6 @@
 
 
 
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getUnparcelClassLoader()">getUnparcelClassLoader</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/Integer.html">Integer</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#getUnparcelClientVersion()">getUnparcelClientVersion</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html#shouldDowngrade()">shouldDowngrade</a></span>()</nobr>
-        
-  </td></tr>
-
-
-
-</table>
-
-
 
 
 
@@ -1288,7 +1235,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1307,7 +1254,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1326,7 +1273,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1355,7 +1302,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1419,7 +1366,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1490,7 +1437,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1528,7 +1475,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1629,7 +1576,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getDisplayName()">getDisplayName</a></span>()</nobr>
@@ -1650,7 +1597,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getDisplayName(android.database.CharArrayBuffer)">getDisplayName</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the display name for this participant into the provided <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1665,7 +1612,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getHiResImageUri()">getHiResImageUri</a></span>()</nobr>
@@ -1683,7 +1630,7 @@
             
             
             
-            <a href="/reference/android/net/Uri.html">Uri</a></nobr>
+            Uri</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getIconImageUri()">getIconImageUri</a></span>()</nobr>
@@ -1701,7 +1648,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participant.html#getParticipantId()">getParticipantId</a></span>()</nobr>
@@ -1811,7 +1758,7 @@
         public 
         static 
         final 
-        <a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntityCreator.html">ParticipantEntityCreator</a>
+        Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html">ParticipantEntity</a>&gt;
       </span>
         CREATOR
     </h4>
@@ -1890,7 +1837,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> obj)</span>
+      <span class="normal">(Object obj)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1963,7 +1910,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -2001,7 +1948,7 @@
         void
       </span>
       <span class="sympad">getDisplayName</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2037,7 +1984,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getHiResImageUri</span>
       <span class="normal">()</span>
@@ -2074,7 +2021,7 @@
          
          
          
-        <a href="/reference/android/net/Uri.html">Uri</a>
+        Uri
       </span>
       <span class="sympad">getIconImageUri</span>
       <span class="normal">()</span>
@@ -2112,7 +2059,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getParticipantId</span>
       <span class="normal">()</span>
@@ -2318,7 +2265,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -2350,7 +2297,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</span>
+      <span class="normal">(Parcel dest, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2371,113 +2318,6 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
-<h2>Protected Methods</h2>
-
-
-
-<A NAME="getUnparcelClassLoader()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a>
-      </span>
-      <span class="sympad">getUnparcelClassLoader</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The ClassLoader to use for unparceling, if any.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="getUnparcelClientVersion()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/Integer.html">Integer</a>
-      </span>
-      <span class="sympad">getUnparcelClientVersion</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The client version to use for unparceling, if known.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="shouldDowngrade()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-         
-         
-         
-         
-        boolean
-      </span>
-      <span class="sympad">shouldDowngrade</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>Whether or not this object has been downgraded to hand back to a client.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html b/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html
index f8720d0..c543315 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ParticipantUtils | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -790,10 +797,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html#getParticipantId(java.util.ArrayList<com.google.android.gms.games.multiplayer.Participant>, java.lang.String)">getParticipantId</a></span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt; participants, <a href="/reference/java/lang/String.html">String</a> playerId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html#getParticipantId(java.util.ArrayList<com.google.android.gms.games.multiplayer.Participant>, java.lang.String)">getParticipantId</a></span>(ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt; participants, String playerId)</nobr>
         
         <div class="jd-descrdiv">Get the participant ID corresponding to a given player ID.</div>
   
@@ -823,7 +830,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -842,7 +849,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -861,7 +868,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -890,7 +897,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -954,7 +961,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1068,10 +1075,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getParticipantId</span>
-      <span class="normal">(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt; participants, <a href="/reference/java/lang/String.html">String</a> playerId)</span>
+      <span class="normal">(ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt; participants, String playerId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/Participatable.html b/docs/html/reference/com/google/android/gms/games/multiplayer/Participatable.html
index abec87c..d3b7489 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/Participatable.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/Participatable.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Participatable | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -816,7 +823,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participatable.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -884,7 +891,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;
+        ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;
       </span>
       <span class="sympad">getParticipants</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/package-summary.html b/docs/html/reference/com/google/android/gms/games/multiplayer/package-summary.html
index 4a3ddf4..3f6deae 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.games.multiplayer | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -640,6 +647,11 @@
 <div id="jd-content" class="api apilevel-">
 
 
+  <div class="jd-descr">
+    Contains data classes for multiplayer functionality.
+
+  </div>
+
 
 
 
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html
index 5c52969..929c6c6 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RealTimeMessage | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -872,7 +879,7 @@
           public
           static
           final
-          <a href="/reference/android/os/Parcelable.Creator.html">Creator</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html">RealTimeMessage</a>&gt;</nobr></td>
+          Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html">RealTimeMessage</a>&gt;</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html#CREATOR">CREATOR</a></td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -936,7 +943,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html#getSenderParticipantId()">getSenderParticipantId</a></span>()</nobr>
@@ -971,7 +978,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> parcel, int flag)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel parcel, int flag)</nobr>
         
   </td></tr>
 
@@ -999,7 +1006,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1018,7 +1025,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1037,7 +1044,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1066,7 +1073,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1130,7 +1137,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1201,7 +1208,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1239,7 +1246,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1373,7 +1380,7 @@
         public 
         static 
         final 
-        <a href="/reference/android/os/Parcelable.Creator.html">Creator</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html">RealTimeMessage</a>&gt;
+        Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html">RealTimeMessage</a>&gt;
       </span>
         CREATOR
     </h4>
@@ -1483,7 +1490,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getSenderParticipantId</span>
       <span class="normal">()</span>
@@ -1554,7 +1561,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> parcel, int flag)</span>
+      <span class="normal">(Parcel parcel, int flag)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html
index a5edcac..2099b6a 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RealTimeMessageReceivedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html
index 55dc99f..a310d48 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RealTimeReliableMessageSentListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -751,7 +758,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html#onRealTimeMessageSent(int, int, java.lang.String)">onRealTimeMessageSent</a></span>(int statusCode, int tokenId, <a href="/reference/java/lang/String.html">String</a> recipientParticipantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html#onRealTimeMessageSent(int, int, java.lang.String)">onRealTimeMessageSent</a></span>(int statusCode, int tokenId, String recipientParticipantId)</nobr>
         
         <div class="jd-descrdiv">Called to notify the client that a reliable message was sent for a room.</div>
   
@@ -819,7 +826,7 @@
         void
       </span>
       <span class="sympad">onRealTimeMessageSent</span>
-      <span class="normal">(int statusCode, int tokenId, <a href="/reference/java/lang/String.html">String</a> recipientParticipantId)</span>
+      <span class="normal">(int statusCode, int tokenId, String recipientParticipantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/Room.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/Room.html
index fdec653..9a1ea3f 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/Room.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/Room.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Room | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -703,7 +710,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/common/data/Freezable.html">Freezable</a>&lt;T&gt; 
       
@@ -936,7 +943,7 @@
             
             
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getAutoMatchCriteria()">getAutoMatchCriteria</a></span>()</nobr>
@@ -954,6 +961,26 @@
             
             
             
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getAutoMatchWaitEstimateSeconds()">getAutoMatchWaitEstimateSeconds</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Retrieves the estimated wait time for automatching to finish for players who are not
+ automatched immediately, as measured from the time that the room entered the
+ automatching pool.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
             long</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -963,14 +990,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getCreatorId()">getCreatorId</a></span>()</nobr>
@@ -979,14 +1006,14 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getDescription()">getDescription</a></span>()</nobr>
@@ -995,7 +1022,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1005,7 +1032,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the room description into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1013,24 +1040,6 @@
 
 
 	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            <a href="/reference/java/lang/String.html">String</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantId(java.lang.String)">getParticipantId</a></span>(<a href="/reference/java/lang/String.html">String</a> playerId)</nobr>
-        
-        <div class="jd-descrdiv">Get the participant ID for a given player.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
@@ -1038,7 +1047,25 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;</nobr>
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantId(java.lang.String)">getParticipantId</a></span>(String playerId)</nobr>
+        
+        <div class="jd-descrdiv">Get the participant ID for a given player.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ArrayList&lt;String&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantIds()">getParticipantIds</a></span>()</nobr>
@@ -1047,7 +1074,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1057,7 +1084,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantStatus(java.lang.String)">getParticipantStatus</a></span>(<a href="/reference/java/lang/String.html">String</a> participantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantStatus(java.lang.String)">getParticipantStatus</a></span>(String participantId)</nobr>
         
         <div class="jd-descrdiv">Get the status of a participant in a room.</div>
   
@@ -1065,14 +1092,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getRoomId()">getRoomId</a></span>()</nobr>
@@ -1081,7 +1108,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1097,7 +1124,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1135,7 +1162,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1173,7 +1200,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1274,7 +1301,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participatable.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -1548,7 +1575,7 @@
          
         abstract 
          
-        <a href="/reference/android/os/Bundle.html">Bundle</a>
+        Bundle
       </span>
       <span class="sympad">getAutoMatchCriteria</span>
       <span class="normal">()</span>
@@ -1573,6 +1600,43 @@
 </div>
 
 
+<A NAME="getAutoMatchWaitEstimateSeconds()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+        abstract 
+         
+        int
+      </span>
+      <span class="sympad">getAutoMatchWaitEstimateSeconds</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Retrieves the estimated wait time for automatching to finish for players who are not
+ automatched immediately, as measured from the time that the room entered the
+ automatching pool.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>The estimated wait time in seconds, or -1 if the room is not
+         automatching or no estimate could be provided.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="getCreationTimestamp()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1617,7 +1681,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getCreatorId</span>
       <span class="normal">()</span>
@@ -1651,7 +1715,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -1688,7 +1752,7 @@
         void
       </span>
       <span class="sympad">getDescription</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1724,10 +1788,10 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getParticipantId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> playerId)</span>
+      <span class="normal">(String playerId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1769,7 +1833,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;
+        ArrayList&lt;String&gt;
       </span>
       <span class="sympad">getParticipantIds</span>
       <span class="normal">()</span>
@@ -1807,7 +1871,7 @@
         int
       </span>
       <span class="sympad">getParticipantStatus</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> participantId)</span>
+      <span class="normal">(String participantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1859,7 +1923,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getRoomId</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html
index 17c3c86..d97beb9 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RoomConfig.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -793,7 +800,7 @@
             <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#addPlayersToInvite(java.lang.String...)">addPlayersToInvite</a></span>(<a href="/reference/java/lang/String.html">String...</a> playerIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#addPlayersToInvite(java.lang.String...)">addPlayersToInvite</a></span>(String... playerIds)</nobr>
         
         <div class="jd-descrdiv">Add one or more player IDs to invite to the room.</div>
   
@@ -811,7 +818,7 @@
             <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#addPlayersToInvite(java.util.ArrayList<java.lang.String>)">addPlayersToInvite</a></span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; playerIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#addPlayersToInvite(java.util.ArrayList<java.lang.String>)">addPlayersToInvite</a></span>(ArrayList&lt;String&gt; playerIds)</nobr>
         
         <div class="jd-descrdiv">Add a list of player IDs to invite to the room.</div>
   
@@ -847,7 +854,7 @@
             <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#setAutoMatchCriteria(android.os.Bundle)">setAutoMatchCriteria</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> autoMatchCriteria)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#setAutoMatchCriteria(android.os.Bundle)">setAutoMatchCriteria</a></span>(Bundle autoMatchCriteria)</nobr>
         
         <div class="jd-descrdiv">Sets the auto-match criteria for the room.</div>
   
@@ -865,7 +872,7 @@
             <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#setInvitationIdToAccept(java.lang.String)">setInvitationIdToAccept</a></span>(<a href="/reference/java/lang/String.html">String</a> invitationId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html#setInvitationIdToAccept(java.lang.String)">setInvitationIdToAccept</a></span>(String invitationId)</nobr>
         
         <div class="jd-descrdiv">Set the ID of the invitation to accept.</div>
   
@@ -967,7 +974,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -986,7 +993,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1005,7 +1012,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1034,7 +1041,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1098,7 +1105,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1215,7 +1222,7 @@
         <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a>
       </span>
       <span class="sympad">addPlayersToInvite</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String...</a> playerIds)</span>
+      <span class="normal">(String... playerIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1259,7 +1266,7 @@
         <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a>
       </span>
       <span class="sympad">addPlayersToInvite</span>
-      <span class="normal">(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; playerIds)</span>
+      <span class="normal">(ArrayList&lt;String&gt; playerIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1337,7 +1344,7 @@
         <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a>
       </span>
       <span class="sympad">setAutoMatchCriteria</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> autoMatchCriteria)</span>
+      <span class="normal">(Bundle autoMatchCriteria)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1381,7 +1388,7 @@
         <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html">RoomConfig.Builder</a>
       </span>
       <span class="sympad">setInvitationIdToAccept</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> invitationId)</span>
+      <span class="normal">(String invitationId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html
index 1a493a6..67d83c1 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RoomConfig | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -831,7 +838,7 @@
             
             static
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html#createAutoMatchCriteria(int, int, long)">createAutoMatchCriteria</a></span>(int minAutoMatchPlayers, int maxAutoMatchPlayers, long exclusiveBitMask)</nobr>
@@ -849,7 +856,7 @@
             
             
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html#getAutoMatchCriteria()">getAutoMatchCriteria</a></span>()</nobr>
@@ -867,7 +874,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html#getInvitationId()">getInvitationId</a></span>()</nobr>
@@ -885,7 +892,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String[]</a></nobr>
+            String[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html#getInvitedPlayerIds()">getInvitedPlayerIds</a></span>()</nobr>
@@ -1008,7 +1015,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1027,7 +1034,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1046,7 +1053,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1075,7 +1082,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1139,7 +1146,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1297,7 +1304,7 @@
          
          
          
-        <a href="/reference/android/os/Bundle.html">Bundle</a>
+        Bundle
       </span>
       <span class="sympad">createAutoMatchCriteria</span>
       <span class="normal">(int minAutoMatchPlayers, int maxAutoMatchPlayers, long exclusiveBitMask)</span>
@@ -1351,7 +1358,7 @@
          
          
          
-        <a href="/reference/android/os/Bundle.html">Bundle</a>
+        Bundle
       </span>
       <span class="sympad">getAutoMatchCriteria</span>
       <span class="normal">()</span>
@@ -1385,7 +1392,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getInvitationId</span>
       <span class="normal">()</span>
@@ -1420,7 +1427,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String[]</a>
+        String[]
       </span>
       <span class="sympad">getInvitedPlayerIds</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html
index b2e7fb1..d9c66e3 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RoomEntity | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -688,9 +695,6 @@
   
 
 
-  &#124; <a href="#promethods">Protected Methods</a>
-  
-
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -719,7 +723,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -728,7 +732,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
         <a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> 
       
@@ -746,7 +750,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -944,7 +948,7 @@
           public
           static
           final
-          <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntityCreator.html">RoomEntityCreator</a></nobr></td>
+          Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html">RoomEntity</a>&gt;</nobr></td>
           <td class="jd-linkcol"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#CREATOR">CREATOR</a></td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -995,7 +999,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> obj)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#equals(java.lang.Object)">equals</a></span>(Object obj)</nobr>
         
   </td></tr>
 
@@ -1026,7 +1030,7 @@
             
             
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getAutoMatchCriteria()">getAutoMatchCriteria</a></span>()</nobr>
@@ -1044,6 +1048,26 @@
             
             
             
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getAutoMatchWaitEstimateSeconds()">getAutoMatchWaitEstimateSeconds</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Retrieves the estimated wait time for automatching to finish for players who are not
+ automatched immediately, as measured from the time that the room entered the
+ automatching pool.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
             long</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -1053,14 +1077,14 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getCreatorId()">getCreatorId</a></span>()</nobr>
@@ -1069,14 +1093,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getDescription()">getDescription</a></span>()</nobr>
@@ -1085,7 +1109,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1095,7 +1119,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the room description into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1103,24 +1127,6 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            <a href="/reference/java/lang/String.html">String</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getParticipantId(java.lang.String)">getParticipantId</a></span>(<a href="/reference/java/lang/String.html">String</a> playerId)</nobr>
-        
-        <div class="jd-descrdiv">Get the participant ID for a given player.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1128,7 +1134,25 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;</nobr>
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getParticipantId(java.lang.String)">getParticipantId</a></span>(String playerId)</nobr>
+        
+        <div class="jd-descrdiv">Get the participant ID for a given player.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ArrayList&lt;String&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getParticipantIds()">getParticipantIds</a></span>()</nobr>
@@ -1137,7 +1161,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1147,7 +1171,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getParticipantStatus(java.lang.String)">getParticipantStatus</a></span>(<a href="/reference/java/lang/String.html">String</a> participantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getParticipantStatus(java.lang.String)">getParticipantStatus</a></span>(String participantId)</nobr>
         
         <div class="jd-descrdiv">Get the status of a participant in a room.</div>
   
@@ -1155,14 +1179,14 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -1173,14 +1197,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getRoomId()">getRoomId</a></span>()</nobr>
@@ -1189,7 +1213,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1205,7 +1229,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1221,7 +1245,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1237,7 +1261,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1255,14 +1279,14 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#toString()">toString</a></span>()</nobr>
@@ -1271,7 +1295,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1281,7 +1305,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel dest, int flags)</nobr>
         
   </td></tr>
 
@@ -1292,63 +1316,6 @@
 
 
 
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getUnparcelClassLoader()">getUnparcelClassLoader</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            <a href="/reference/java/lang/Integer.html">Integer</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#getUnparcelClientVersion()">getUnparcelClientVersion</a></span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html#shouldDowngrade()">shouldDowngrade</a></span>()</nobr>
-        
-  </td></tr>
-
-
-
-</table>
-
-
 
 
 
@@ -1366,7 +1333,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1385,7 +1352,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1404,7 +1371,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1433,7 +1400,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1497,7 +1464,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1568,7 +1535,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1606,7 +1573,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1707,7 +1674,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
+            ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/Participatable.html#getParticipants()">getParticipants</a></span>()</nobr>
@@ -1751,7 +1718,7 @@
             
             
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getAutoMatchCriteria()">getAutoMatchCriteria</a></span>()</nobr>
@@ -1769,6 +1736,26 @@
             
             
             
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getAutoMatchWaitEstimateSeconds()">getAutoMatchWaitEstimateSeconds</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Retrieves the estimated wait time for automatching to finish for players who are not
+ automatched immediately, as measured from the time that the room entered the
+ automatching pool.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
             long</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -1778,14 +1765,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getCreatorId()">getCreatorId</a></span>()</nobr>
@@ -1794,14 +1781,14 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getDescription()">getDescription</a></span>()</nobr>
@@ -1810,7 +1797,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1820,7 +1807,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getDescription(android.database.CharArrayBuffer)">getDescription</a></span>(CharArrayBuffer dataOut)</nobr>
         
         <div class="jd-descrdiv">Loads the room description into the given <code><a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a></code>.</div>
   
@@ -1828,24 +1815,6 @@
 
 
 	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            <a href="/reference/java/lang/String.html">String</a></nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantId(java.lang.String)">getParticipantId</a></span>(<a href="/reference/java/lang/String.html">String</a> playerId)</nobr>
-        
-        <div class="jd-descrdiv">Get the participant ID for a given player.</div>
-  
-  </td></tr>
-
-
-	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
@@ -1853,7 +1822,25 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;</nobr>
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantId(java.lang.String)">getParticipantId</a></span>(String playerId)</nobr>
+        
+        <div class="jd-descrdiv">Get the participant ID for a given player.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ArrayList&lt;String&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantIds()">getParticipantIds</a></span>()</nobr>
@@ -1862,7 +1849,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1872,7 +1859,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantStatus(java.lang.String)">getParticipantStatus</a></span>(<a href="/reference/java/lang/String.html">String</a> participantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getParticipantStatus(java.lang.String)">getParticipantStatus</a></span>(String participantId)</nobr>
         
         <div class="jd-descrdiv">Get the status of a participant in a room.</div>
   
@@ -1880,14 +1867,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html#getRoomId()">getRoomId</a></span>()</nobr>
@@ -1896,7 +1883,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1912,7 +1899,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1973,7 +1960,7 @@
         public 
         static 
         final 
-        <a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntityCreator.html">RoomEntityCreator</a>
+        Creator&lt;<a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html">RoomEntity</a>&gt;
       </span>
         CREATOR
     </h4>
@@ -2052,7 +2039,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> obj)</span>
+      <span class="normal">(Object obj)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2125,7 +2112,7 @@
          
          
          
-        <a href="/reference/android/os/Bundle.html">Bundle</a>
+        Bundle
       </span>
       <span class="sympad">getAutoMatchCriteria</span>
       <span class="normal">()</span>
@@ -2150,6 +2137,43 @@
 </div>
 
 
+<A NAME="getAutoMatchWaitEstimateSeconds()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        int
+      </span>
+      <span class="sympad">getAutoMatchWaitEstimateSeconds</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Retrieves the estimated wait time for automatching to finish for players who are not
+ automatched immediately, as measured from the time that the room entered the
+ automatching pool.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>The estimated wait time in seconds, or -1 if the room is not
+         automatching or no estimate could be provided.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="getCreationTimestamp()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -2189,7 +2213,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getCreatorId</span>
       <span class="normal">()</span>
@@ -2218,7 +2242,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -2250,7 +2274,7 @@
         void
       </span>
       <span class="sympad">getDescription</span>
-      <span class="normal">(<a href="/reference/android/database/CharArrayBuffer.html">CharArrayBuffer</a> dataOut)</span>
+      <span class="normal">(CharArrayBuffer dataOut)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2286,10 +2310,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getParticipantId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> playerId)</span>
+      <span class="normal">(String playerId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2331,7 +2355,7 @@
          
          
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;
+        ArrayList&lt;String&gt;
       </span>
       <span class="sympad">getParticipantIds</span>
       <span class="normal">()</span>
@@ -2363,7 +2387,7 @@
         int
       </span>
       <span class="sympad">getParticipantStatus</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> participantId)</span>
+      <span class="normal">(String participantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2405,7 +2429,7 @@
          
          
          
-        <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;
+        ArrayList&lt;<a href="/reference/com/google/android/gms/games/multiplayer/Participant.html">Participant</a>&gt;
       </span>
       <span class="sympad">getParticipants</span>
       <span class="normal">()</span>
@@ -2440,7 +2464,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getRoomId</span>
       <span class="normal">()</span>
@@ -2592,7 +2616,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -2624,7 +2648,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> dest, int flags)</span>
+      <span class="normal">(Parcel dest, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2645,113 +2669,6 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
-<h2>Protected Methods</h2>
-
-
-
-<A NAME="getUnparcelClassLoader()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/ClassLoader.html">ClassLoader</a>
-      </span>
-      <span class="sympad">getUnparcelClassLoader</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The ClassLoader to use for unparceling, if any.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="getUnparcelClientVersion()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-        static 
-         
-         
-         
-        <a href="/reference/java/lang/Integer.html">Integer</a>
-      </span>
-      <span class="sympad">getUnparcelClientVersion</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>The client version to use for unparceling, if known.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="shouldDowngrade()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        protected 
-         
-         
-         
-         
-        boolean
-      </span>
-      <span class="sympad">shouldDowngrade</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>Whether or not this object has been downgraded to hand back to a client.
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html
index ab365b1..fd02e45 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RoomStatusUpdateListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -788,7 +795,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onP2PConnected(java.lang.String)">onP2PConnected</a></span>(<a href="/reference/java/lang/String.html">String</a> participantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onP2PConnected(java.lang.String)">onP2PConnected</a></span>(String participantId)</nobr>
         
         <div class="jd-descrdiv">Called when the client is successfully connected to a peer participant.</div>
   
@@ -806,7 +813,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onP2PDisconnected(java.lang.String)">onP2PDisconnected</a></span>(<a href="/reference/java/lang/String.html">String</a> participantId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onP2PDisconnected(java.lang.String)">onP2PDisconnected</a></span>(String participantId)</nobr>
         
         <div class="jd-descrdiv">Called when client gets disconnected from a peer participant.</div>
   
@@ -824,7 +831,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerDeclined(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerDeclined</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerDeclined(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerDeclined</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</nobr>
         
         <div class="jd-descrdiv">Called when one or more peers decline the invitation to a room.</div>
   
@@ -842,7 +849,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerInvitedToRoom(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerInvitedToRoom</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerInvitedToRoom(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerInvitedToRoom</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</nobr>
         
         <div class="jd-descrdiv">Called when one or more peers are invited to a room.</div>
   
@@ -860,7 +867,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerJoined(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerJoined</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerJoined(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerJoined</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</nobr>
         
         <div class="jd-descrdiv">Called when one or more peer participants join a room.</div>
   
@@ -878,7 +885,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerLeft(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerLeft</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeerLeft(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeerLeft</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</nobr>
         
         <div class="jd-descrdiv">Called when one or more peer participant leave a room.</div>
   
@@ -896,7 +903,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeersConnected(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeersConnected</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeersConnected(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeersConnected</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</nobr>
         
         <div class="jd-descrdiv">Called when one or more peer participants are connected to a room.</div>
   
@@ -914,7 +921,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeersDisconnected(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeersDisconnected</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html#onPeersDisconnected(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List<java.lang.String>)">onPeersDisconnected</a></span>(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</nobr>
         
         <div class="jd-descrdiv">Called when one or more peer participants are disconnected from a room.</div>
   
@@ -1099,7 +1106,7 @@
         void
       </span>
       <span class="sympad">onP2PConnected</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> participantId)</span>
+      <span class="normal">(String participantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1138,7 +1145,7 @@
         void
       </span>
       <span class="sympad">onP2PDisconnected</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> participantId)</span>
+      <span class="normal">(String participantId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1177,7 +1184,7 @@
         void
       </span>
       <span class="sympad">onPeerDeclined</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1221,7 +1228,7 @@
         void
       </span>
       <span class="sympad">onPeerInvitedToRoom</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1265,7 +1272,7 @@
         void
       </span>
       <span class="sympad">onPeerJoined</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1309,7 +1316,7 @@
         void
       </span>
       <span class="sympad">onPeerLeft</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1353,7 +1360,7 @@
         void
       </span>
       <span class="sympad">onPeersConnected</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1397,7 +1404,7 @@
         void
       </span>
       <span class="sympad">onPeersDisconnected</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; participantIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/games/multiplayer/realtime/Room.html">Room</a> room, List&lt;String&gt; participantIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html
index 2235af7..a28307f 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RoomUpdateListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -769,7 +776,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html#onLeftRoom(int, java.lang.String)">onLeftRoom</a></span>(int statusCode, <a href="/reference/java/lang/String.html">String</a> roomId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html#onLeftRoom(int, java.lang.String)">onLeftRoom</a></span>(int statusCode, String roomId)</nobr>
         
         <div class="jd-descrdiv">Called when the client attempts to leaves the real-time room.</div>
   
@@ -928,7 +935,7 @@
         void
       </span>
       <span class="sympad">onLeftRoom</span>
-      <span class="normal">(int statusCode, <a href="/reference/java/lang/String.html">String</a> roomId)</span>
+      <span class="normal">(int statusCode, String roomId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html
index 82f3aae..61f9d5c 100644
--- a/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.games.multiplayer.realtime | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/games/package-summary.html b/docs/html/reference/com/google/android/gms/games/package-summary.html
index e5b82b2..ab274d4 100644
--- a/docs/html/reference/com/google/android/gms/games/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/games/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.games | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html b/docs/html/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html
index 757aed5..dc001d1 100644
--- a/docs/html/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html
+++ b/docs/html/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleCloudMessaging | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -728,25 +735,49 @@
 
 
 <h2>Class Overview</h2>
-<p itemprop="articleBody"><p>Google Cloud Messaging for Android.
+<p itemprop="articleBody"><p>The class you use to write a GCM-enabled client application that runs on an Android device.
+ Client applications can receive GCM messages and optionally send messages of their own back to
+ the server.
 
- <p>This class requires Google Play services version 3.1 or higher.
+ <p>This class requires Google Play services version 3.1 or higher. For a
+ detailed discussion of how to write a GCM client app, see
+ <a href="http://developer.android.com/google/gcm/client.html">
+ Implementing GCM Client</a>.
 
- <p>In order to receive GCM messages you need to declare a permission and a BroadcastReceiver
- in your manifest. This is a backward-compatible subset of what was required in previous
- versions.
+ <p>To send or receive messages, your application first needs to get a registration ID. The
+ registration ID identifies the device and application, and also determines which 3rd-party
+ application servers are allowed to send messages to this application instance.
+
+ <p>To get a registration ID, you must supply one or more sender IDs. A sender ID is a project
+ number you acquire from the API console, as described in
+ <a href="http://developer.android.com/google/gcm/gs.html">Getting Started</a>. The sender ID is
+ used in the registration process to identify a 3rd-party application server that is permitted to
+ send messages to the device. The following snippet shows you how to call the
+ <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register(java.lang.String...)">register()</a></code> method. For a more comprehensive example, see
+ <a href="http://developer.android.com/google/gcm/client.html">Implementing GCM Client</a>.
+
+ <pre>
+ String SENDER_ID = "My-Sender-ID";
+ GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
+ String registrationId = gcm.register(SENDER_ID);
+ // Upload the registration ID to your own server
+ // The request to your server should be authenticated if your app is using accounts.
+ </pre>
+
+ <p>In order to receive GCM messages, you need to declare a permission and a
+ <code>BroadcastReceiver</code> in your manifest. This is a backward-compatible subset of what was
+ required in previous versions of GCM.
 
  <p>To allow the application to use GCM, add this permission to the manifest:
- <pre>
- &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;</pre>
+
+ <pre>&lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;</pre>
 
  <p>GCM delivers messages as a broadcast. The receivers must be registered in the manifest in
  order to wake up the application.
 
- <p>The <code>com.google.android.c2dm.permission.SEND</code> permission is held by
- Google Play services.
- This prevents other code from invoking the broadcast receiver.
- Here is an excerpt from the manifest:
+ <p>The <code>com.google.android.c2dm.permission.SEND permission</code> is held by Google Play
+ services. This prevents other code from invoking the broadcast receiver. Here is an excerpt
+ from a sample manifest:
 
  <pre>
  &lt;receiver android:name=".MyReceiver" android:exported="true"
@@ -757,25 +788,42 @@
      &lt;/intent-filter&gt;
  &lt;/receiver&gt;</pre>
 
- <p>To send or receive messages, you first need to get a registration ID. The registration ID
- identifies the device and application, as well as which servers are allowed to send messages.
+ <p>When a GCM connection server delivers the message to your client app, the
+ <code>BroadcastReceiver</code> receives the message as an intent. You can either process the
+ intent in the <code>BroadcastReceiver</code>, or you can pass off the work of processing the
+ intent to a service (typically, an <code>IntentService</code>). If you use a service, your
+ broadcast receiver should be an instance of <code>WakefulBroadcastReceiver</code>, to hold a
+ wake lock while the service is doing its work.
+
+ <p>When processing the intent GCM passes into your app's broadcase receiver, you can determine
+ the message type by calling <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getMessageType(android.content.Intent)">getMessageType(intent)</a></code>. For example:
 
  <pre>
- GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
-
- String registrationId = gcm.register(sender1, sender2);
- // Upload the registrationId to your own server
- // The request to your server should be authenticated if your app is using accounts.
+ GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
+ String messageType = gcm.getMessageType(intent);
+ ...
+ // Filter messages based on message type. It is likely that GCM will be extended in the future
+ // with new message types, so just ignore message types you're not interested in, or that you
+ // don't recognize.
+ if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
+    // It's an error.
+ } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
+    // Deleted messages on the server.
+ } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
+    // It's a regular GCM message, do some work.
+ }
  </pre>
 
- <p>The BroadcastReceiver will be invoked whenever a message is received, as well as for special
- messages generated by GCM. Within the BroadcastReceiver you can call
- <code>getMessageType(Intent)</code>.
+ <p>If you are using the XMPP-based
+ <a href="http://developer.android.com/google/gcm/ccs.html">Cloud Connection Server</a>, your
+ client app can send upstream messages back to the server. For example:
 
- <p>To send messages, call <code>send()</code>:
  <pre>
- gcm.send(to, msgId, data);
+ gcm.send(SENDER_ID + "&#64;gcm.googleapis.com", id, data);
  </pre>
+
+ For a more details, see
+ <a href="http://developer.android.com/google/gcm/client.html">Implementing GCM Client</a>.
 </p>
 
 
@@ -822,14 +870,15 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#ERROR_MAIN_THREAD">ERROR_MAIN_THREAD</a></td>
-        <td class="jd-descrcol" width="100%">GCM methods are blocking.</td>
+        <td class="jd-descrcol" width="100%">The GCM <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register(java.lang.String...)">register()</a></code> and <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#unregister()">unregister()</a></code> methods are
+ blocking.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#ERROR_SERVICE_NOT_AVAILABLE">ERROR_SERVICE_NOT_AVAILABLE</a></td>
         <td class="jd-descrcol" width="100%">The device can't read the response, or there was a 500/503 from the
  server that can be retried later.</td>
@@ -837,7 +886,7 @@
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_DELETED">MESSAGE_TYPE_DELETED</a></td>
         <td class="jd-descrcol" width="100%">Returned by <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getMessageType(android.content.Intent)">getMessageType(Intent)</a></code> to indicate that the server deleted
  some pending messages because they were collapsible.</td>
@@ -845,14 +894,14 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_MESSAGE">MESSAGE_TYPE_MESSAGE</a></td>
         <td class="jd-descrcol" width="100%">Returned by <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getMessageType(android.content.Intent)">getMessageType(Intent)</a></code> to indicate a regular message.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_SEND_ERROR">MESSAGE_TYPE_SEND_ERROR</a></td>
         <td class="jd-descrcol" width="100%">Returned by <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getMessageType(android.content.Intent)">getMessageType(Intent)</a></code> to indicate a send error.</td>
     </tr>
@@ -936,7 +985,7 @@
             <a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getInstance(android.content.Context)">getInstance</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getInstance(android.content.Context)">getInstance</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Return the singleton instance of GCM.</div>
   
@@ -951,12 +1000,12 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getMessageType(android.content.Intent)">getMessageType</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#getMessageType(android.content.Intent)">getMessageType</a></span>(Intent intent)</nobr>
         
-        <div class="jd-descrdiv">Return the message type.</div>
+        <div class="jd-descrdiv">Return the message type from an intent passed into a client app's broadcast receiver.</div>
   
   </td></tr>
 
@@ -969,10 +1018,10 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register(java.lang.String...)">register</a></span>(<a href="/reference/java/lang/String.html">String...</a> senderIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register(java.lang.String...)">register</a></span>(String... senderIds)</nobr>
         
         <div class="jd-descrdiv">Register the application for GCM and return the registration ID.</div>
   
@@ -990,9 +1039,9 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#send(java.lang.String, java.lang.String, long, android.os.Bundle)">send</a></span>(<a href="/reference/java/lang/String.html">String</a> to, <a href="/reference/java/lang/String.html">String</a> msgId, long timeToLive, <a href="/reference/android/os/Bundle.html">Bundle</a> data)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#send(java.lang.String, java.lang.String, long, android.os.Bundle)">send</a></span>(String to, String msgId, long timeToLive, Bundle data)</nobr>
         
-        <div class="jd-descrdiv">Send a "device to cloud" message.</div>
+        <div class="jd-descrdiv">Send an upstream ("device to cloud") message.</div>
   
   </td></tr>
 
@@ -1008,9 +1057,9 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#send(java.lang.String, java.lang.String, android.os.Bundle)">send</a></span>(<a href="/reference/java/lang/String.html">String</a> to, <a href="/reference/java/lang/String.html">String</a> msgId, <a href="/reference/android/os/Bundle.html">Bundle</a> data)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#send(java.lang.String, java.lang.String, android.os.Bundle)">send</a></span>(String to, String msgId, Bundle data)</nobr>
         
-        <div class="jd-descrdiv">Send a "device to cloud" message.</div>
+        <div class="jd-descrdiv">Send an upstream ("device to cloud") message.</div>
   
   </td></tr>
 
@@ -1056,7 +1105,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1075,7 +1124,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1094,7 +1143,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1123,7 +1172,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1187,7 +1236,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1286,7 +1335,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         ERROR_MAIN_THREAD
     </h4>
@@ -1298,8 +1347,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>GCM methods are blocking. You should not run them in the main thread or in broadcast
- receivers.
+  <div class="jd-tagdata jd-tagdescr"><p>The GCM <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register(java.lang.String...)">register()</a></code> and <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#unregister()">unregister()</a></code> methods are
+ blocking. You should not run them in the main thread or in broadcast receivers.
 </p></div>
 
     
@@ -1325,7 +1374,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         ERROR_SERVICE_NOT_AVAILABLE
     </h4>
@@ -1365,7 +1414,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         MESSAGE_TYPE_DELETED
     </h4>
@@ -1404,7 +1453,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         MESSAGE_TYPE_MESSAGE
     </h4>
@@ -1442,7 +1491,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         MESSAGE_TYPE_SEND_ERROR
     </h4>
@@ -1573,7 +1622,7 @@
         <a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a>
       </span>
       <span class="sympad">getInstance</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1599,10 +1648,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getMessageType</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1612,20 +1661,25 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Return the message type. Regular messages from the server have the type
- <code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_MESSAGE">GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE</a></code>.
+  <div class="jd-tagdata jd-tagdescr"><p>Return the message type from an intent passed into a client app's broadcast receiver. There
+ are two general categories of messages passed from the server: regular GCM messages,
+ and special GCM status messages.
 
- The server may also send special messages. The possible types are:
-  <ul>
-  <li><code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_MESSAGE">MESSAGE_TYPE_MESSAGE</a></code>&mdash;regular message from your server.
-  </li><li><code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_DELETED">MESSAGE_TYPE_DELETED</a></code>&mdash;if some messages have been collapsed by GCM.
-  </li><li><code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_SEND_ERROR">MESSAGE_TYPE_SEND_ERROR</a></code>&mdash;indicates errors sending one of the messages.
+ The possible types are:
+ <ul>
+   <li><code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_MESSAGE">MESSAGE_TYPE_MESSAGE</a></code>&mdash;regular message from your server.
+   </li><li><code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_DELETED">MESSAGE_TYPE_DELETED</a></code>&mdash;special status message indicating that some
+     messages have been collapsed by GCM.
+   </li><li><code><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#MESSAGE_TYPE_SEND_ERROR">MESSAGE_TYPE_SEND_ERROR</a></code>&mdash;special status message indicating that
+     there were errors sending one of the messages.
   </li></ul>
 
-  Additional types may be added later; you should ignore any type you don't handle.</p></div>
+ You can use this method to filter based on message type. Since it is likely that GCM will
+ be extended in the future with new message types, just ignore any message types you're not
+ interested in, or that you don't recognize.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>the message type or null if the intent is not a GCM intent
+      <ul class="nolist"><li>The message type or null if the intent is not a GCM intent
 </li></ul>
   </div>
 
@@ -1643,10 +1697,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">register</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String...</a> senderIds)</span>
+      <span class="normal">(String... senderIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1684,7 +1738,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td></td>
         </tr>
       </table>
@@ -1707,7 +1761,7 @@
         void
       </span>
       <span class="sympad">send</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> to, <a href="/reference/java/lang/String.html">String</a> msgId, long timeToLive, <a href="/reference/android/os/Bundle.html">Bundle</a> data)</span>
+      <span class="normal">(String to, String msgId, long timeToLive, Bundle data)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1717,11 +1771,13 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Send a "device to cloud" message.
+  <div class="jd-tagdata jd-tagdescr"><p>Send an upstream ("device to cloud") message. You can only use the upstream feature
+ if your GCM implementation uses the XMPP-based
+ <a href="http://developer.android.com/google/gcm/ccs.html">Cloud Connection Server</a>.
 
  The current limits for max storage time and number of outstanding messages per
  application are documented in the
- <a href="/google/gcm/gcm.html">GCM Dev Guide</a>.</p></div>
+ <a href="http://developer.android.com/google/gcm/index.html">GCM Developers Guide</a>.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Parameters</h5>
       <table class="jd-tagtable">
@@ -1747,8 +1803,7 @@
         <tr>
           <th>data</td>
           <td>key/value pairs to be sent. Values must be String, any other type will
-   be ignored.
-</td>
+   be ignored.</td>
         </tr>
       </table>
   </div>
@@ -1756,7 +1811,11 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IllegalArgumentException</td>
+            <td></td>
+        </tr>  
+        <tr>
+            <th>IOException</td>
             <td></td>
         </tr>
       </table>
@@ -1779,7 +1838,7 @@
         void
       </span>
       <span class="sympad">send</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> to, <a href="/reference/java/lang/String.html">String</a> msgId, <a href="/reference/android/os/Bundle.html">Bundle</a> data)</span>
+      <span class="normal">(String to, String msgId, Bundle data)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1789,7 +1848,9 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Send a "device to cloud" message.
+  <div class="jd-tagdata jd-tagdescr"><p>Send an upstream ("device to cloud") message. You can only use the upstream feature
+ if your GCM implementation uses the XMPP-based
+ <a href="http://developer.android.com/google/gcm/ccs.html">Cloud Connection Server</a>.
 
  The message will be queued if we don't have an active connection for the max interval.</p></div>
   <div class="jd-tagdata">
@@ -1817,7 +1878,11 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th></td>
+            <td>IllegalArgumentException</td>
+        </tr>  
+        <tr>
+            <th>IOException</td>
             <td></td>
         </tr>
       </table>
@@ -1856,15 +1921,14 @@
 
  You should rarely (if ever) need to call this method. Not only is it
  expensive in terms of resources, but it invalidates your registration ID,
- which should never change unnecessarily. A better approach is to simply
+ which you should never change unnecessarily. A better approach is to simply
  have your server stop sending messages. Only use unregister if you want
- your application to stop using GCM permanently, or you have a compelling
- reason to recycle your registration ID.</p></div>
+ to change your sender ID.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/io/IOException.html">IOException</a></td>
+            <th>IOException</td>
             <td>if we can't connect to server to unregister.
 </td>
         </tr>
diff --git a/docs/html/reference/com/google/android/gms/gcm/package-summary.html b/docs/html/reference/com/google/android/gms/gcm/package-summary.html
index ee590df..0b4cb55 100644
--- a/docs/html/reference/com/google/android/gms/gcm/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/gcm/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.gcm | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -654,7 +661,7 @@
   <table class="jd-sumtable-expando">
         <tr class="alt-color api apilevel-" >
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a></td>
-              <td class="jd-descrcol" width="100%"><p>Google Cloud Messaging for Android.&nbsp;</td>
+              <td class="jd-descrcol" width="100%"><p>The class you use to write a GCM-enabled client application that runs on an Android device.&nbsp;</td>
           </tr>
   </table>
     </div>
diff --git a/docs/html/reference/com/google/android/gms/location/ActivityRecognitionClient.html b/docs/html/reference/com/google/android/gms/location/ActivityRecognitionClient.html
index b2fe29b..56cc48d 100644
--- a/docs/html/reference/com/google/android/gms/location/ActivityRecognitionClient.html
+++ b/docs/html/reference/com/google/android/gms/location/ActivityRecognitionClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ActivityRecognitionClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -688,7 +695,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -713,7 +720,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -842,7 +849,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html#ActivityRecognitionClient(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">ActivityRecognitionClient</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html#ActivityRecognitionClient(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">ActivityRecognitionClient</a></span>(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
         
         <div class="jd-descrdiv">Creates a <code><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html">ActivityRecognitionClient</a></code>.</div>
   
@@ -1021,7 +1028,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html#removeActivityUpdates(android.app.PendingIntent)">removeActivityUpdates</a></span>(<a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html#removeActivityUpdates(android.app.PendingIntent)">removeActivityUpdates</a></span>(PendingIntent callbackIntent)</nobr>
         
         <div class="jd-descrdiv">Removes all activity updates for the specified PendingIntent.</div>
   
@@ -1039,7 +1046,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html#requestActivityUpdates(long, android.app.PendingIntent)">requestActivityUpdates</a></span>(long detectionIntervalMillis, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionClient.html#requestActivityUpdates(long, android.app.PendingIntent)">requestActivityUpdates</a></span>(long detectionIntervalMillis, PendingIntent callbackIntent)</nobr>
         
         <div class="jd-descrdiv">Register for activity recognition updates.</div>
   
@@ -1105,7 +1112,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1124,7 +1131,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1143,7 +1150,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1172,7 +1179,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1236,7 +1243,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1555,7 +1562,7 @@
         
       </span>
       <span class="sympad">ActivityRecognitionClient</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectedListener, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1944,7 +1951,7 @@
         void
       </span>
       <span class="sympad">removeActivityUpdates</span>
-      <span class="normal">(<a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</span>
+      <span class="normal">(PendingIntent callbackIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1972,7 +1979,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if this method was called at an
              inappropriate time, such as before the LocationServiceClient
              has bound to the remote service.
@@ -1998,7 +2005,7 @@
         void
       </span>
       <span class="sympad">requestActivityUpdates</span>
-      <span class="normal">(long detectionIntervalMillis, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</span>
+      <span class="normal">(long detectionIntervalMillis, PendingIntent callbackIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2067,7 +2074,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if this method was called at an
              inappropriate time, such as before the LocationServiceClient
              has bound to the remote service.
diff --git a/docs/html/reference/com/google/android/gms/location/ActivityRecognitionResult.html b/docs/html/reference/com/google/android/gms/location/ActivityRecognitionResult.html
index ecd5eaa..a78f385 100644
--- a/docs/html/reference/com/google/android/gms/location/ActivityRecognitionResult.html
+++ b/docs/html/reference/com/google/android/gms/location/ActivityRecognitionResult.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ActivityRecognitionResult | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -699,7 +706,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -708,7 +715,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -724,7 +731,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -803,7 +810,7 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#EXTRA_ACTIVITY_RESULT">EXTRA_ACTIVITY_RESULT</a></td>
         <td class="jd-descrcol" width="100%"></td>
     </tr>
@@ -907,7 +914,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#ActivityRecognitionResult(java.util.List<com.google.android.gms.location.DetectedActivity>, long, long)">ActivityRecognitionResult</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt; probableActivities, long time, long elapsedRealtimeMillis)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#ActivityRecognitionResult(java.util.List<com.google.android.gms.location.DetectedActivity>, long, long)">ActivityRecognitionResult</a></span>(List&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt; probableActivities, long time, long elapsedRealtimeMillis)</nobr>
         
         <div class="jd-descrdiv">Constructs an ActivityRecognitionResult.</div>
   
@@ -972,7 +979,7 @@
             <a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html">ActivityRecognitionResult</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#extractResult(android.content.Intent)">extractResult</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#extractResult(android.content.Intent)">extractResult</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Extracts the ActivityRecognitionResult from an Intent.</div>
   
@@ -1043,7 +1050,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#getProbableActivities()">getProbableActivities</a></span>()</nobr>
@@ -1084,7 +1091,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#hasResult(android.content.Intent)">hasResult</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#hasResult(android.content.Intent)">hasResult</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Returns true if an Intent contains an ActivityRecognitionResult.</div>
   
@@ -1099,7 +1106,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#toString()">toString</a></span>()</nobr>
@@ -1118,7 +1125,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1146,7 +1153,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1165,7 +1172,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1184,7 +1191,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1213,7 +1220,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1277,7 +1284,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1348,7 +1355,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1386,7 +1393,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1434,7 +1441,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_ACTIVITY_RESULT
     </h4>
@@ -1523,7 +1530,7 @@
         
       </span>
       <span class="sympad">ActivityRecognitionResult</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt; probableActivities, long time, long elapsedRealtimeMillis)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt; probableActivities, long time, long elapsedRealtimeMillis)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1664,7 +1671,7 @@
         <a href="/reference/com/google/android/gms/location/ActivityRecognitionResult.html">ActivityRecognitionResult</a>
       </span>
       <span class="sympad">extractResult</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1792,7 +1799,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/location/DetectedActivity.html">DetectedActivity</a>&gt;
       </span>
       <span class="sympad">getProbableActivities</span>
       <span class="normal">()</span>
@@ -1861,7 +1868,7 @@
         boolean
       </span>
       <span class="sympad">hasResult</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1896,7 +1903,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -1928,7 +1935,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/DetectedActivity.html b/docs/html/reference/com/google/android/gms/location/DetectedActivity.html
index a2a6bac..f90cac5 100644
--- a/docs/html/reference/com/google/android/gms/location/DetectedActivity.html
+++ b/docs/html/reference/com/google/android/gms/location/DetectedActivity.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>DetectedActivity | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -699,7 +706,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -708,7 +715,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -724,7 +731,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1017,7 +1024,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/location/DetectedActivity.html#toString()">toString</a></span>()</nobr>
@@ -1036,7 +1043,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/DetectedActivity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/DetectedActivity.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1064,7 +1071,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1083,7 +1090,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1102,7 +1109,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1131,7 +1138,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1195,7 +1202,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1266,7 +1273,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1304,7 +1311,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1794,7 +1801,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -1826,7 +1833,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/Geofence.Builder.html b/docs/html/reference/com/google/android/gms/location/Geofence.Builder.html
index 88e56ac..32709f8 100644
--- a/docs/html/reference/com/google/android/gms/location/Geofence.Builder.html
+++ b/docs/html/reference/com/google/android/gms/location/Geofence.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Geofence.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -875,7 +882,7 @@
             <a href="/reference/com/google/android/gms/location/Geofence.Builder.html">Geofence.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/Geofence.Builder.html#setRequestId(java.lang.String)">setRequestId</a></span>(<a href="/reference/java/lang/String.html">String</a> requestId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/Geofence.Builder.html#setRequestId(java.lang.String)">setRequestId</a></span>(String requestId)</nobr>
         
         <div class="jd-descrdiv">Sets the request ID of the geofence.</div>
   
@@ -923,7 +930,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -942,7 +949,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -961,7 +968,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -990,7 +997,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1054,7 +1061,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1222,7 +1229,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if any parameters are not set or out
              of range
 </td>
@@ -1339,7 +1346,7 @@
         <a href="/reference/com/google/android/gms/location/Geofence.Builder.html">Geofence.Builder</a>
       </span>
       <span class="sympad">setRequestId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> requestId)</span>
+      <span class="normal">(String requestId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/Geofence.html b/docs/html/reference/com/google/android/gms/location/Geofence.html
index 00d8e4b..dc85cbf 100644
--- a/docs/html/reference/com/google/android/gms/location/Geofence.html
+++ b/docs/html/reference/com/google/android/gms/location/Geofence.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Geofence | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -800,7 +807,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/location/Geofence.html#getRequestId()">getRequestId</a></span>()</nobr>
@@ -992,7 +999,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getRequestId</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html b/docs/html/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html
index dfd088c..91f9930 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationClient.OnAddGeofencesResultListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -752,7 +759,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult</a></span>(int statusCode, <a href="/reference/java/lang/String.html">String[]</a> geofenceRequestIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult</a></span>(int statusCode, String[] geofenceRequestIds)</nobr>
         
         <div class="jd-descrdiv">Called when the <code><a href="/reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">addGeofences(List, PendingIntent, OnAddGeofencesResultListener)</a></code> operation completes successfully
  or unsuccessfully.</div>
@@ -821,7 +828,7 @@
         void
       </span>
       <span class="sympad">onAddGeofencesResult</span>
-      <span class="normal">(int statusCode, <a href="/reference/java/lang/String.html">String[]</a> geofenceRequestIds)</span>
+      <span class="normal">(int statusCode, String[] geofenceRequestIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html b/docs/html/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html
index c273503..542e3c1 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationClient.OnRemoveGeofencesResultListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -752,7 +759,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult</a></span>(int statusCode, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult</a></span>(int statusCode, PendingIntent pendingIntent)</nobr>
         
         <div class="jd-descrdiv">Called when the <code><a href="/reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, OnRemoveGeofencesResultListener)</a></code> operation completes successfully or
  unsuccessfully.</div>
@@ -771,7 +778,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult</a></span>(int statusCode, <a href="/reference/java/lang/String.html">String[]</a> geofenceRequestIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult</a></span>(int statusCode, String[] geofenceRequestIds)</nobr>
         
         <div class="jd-descrdiv">Called when the <code><a href="/reference/com/google/android/gms/location/LocationClient.html#removeGeofences(java.util.List<java.lang.String>, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(List, OnRemoveGeofencesResultListener)</a></code> operation completes successfully or
  unsuccessfully.</div>
@@ -840,7 +847,7 @@
         void
       </span>
       <span class="sympad">onRemoveGeofencesByPendingIntentResult</span>
-      <span class="normal">(int statusCode, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent)</span>
+      <span class="normal">(int statusCode, PendingIntent pendingIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -889,7 +896,7 @@
         void
       </span>
       <span class="sympad">onRemoveGeofencesByRequestIdsResult</span>
-      <span class="normal">(int statusCode, <a href="/reference/java/lang/String.html">String[]</a> geofenceRequestIds)</span>
+      <span class="normal">(int statusCode, String[] geofenceRequestIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/LocationClient.html b/docs/html/reference/com/google/android/gms/location/LocationClient.html
index 6bdbc94..efd157e 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationClient.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -694,7 +701,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -719,7 +726,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -835,7 +842,7 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/location/LocationClient.html#KEY_LOCATION_CHANGED">KEY_LOCATION_CHANGED</a></td>
         <td class="jd-descrcol" width="100%">Key used for a Bundle extra holding a Location value when a location change is broadcast
  using a PendingIntent.</td>
@@ -843,7 +850,7 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/location/LocationClient.html#KEY_MOCK_LOCATION">KEY_MOCK_LOCATION</a></td>
         <td class="jd-descrcol" width="100%">Key used for the Bundle extra in Location object holding a boolean indicating whether
  the location was set using <code><a href="/reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">setMockLocation(Location)</a></code>.</td>
@@ -880,7 +887,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#LocationClient(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">LocationClient</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#LocationClient(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">LocationClient</a></span>(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
         
         <div class="jd-descrdiv">Creates a <code><a href="/reference/com/google/android/gms/location/LocationClient.html">LocationClient</a></code>.</div>
   
@@ -911,7 +918,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">addGeofences</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt; geofences, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">LocationClient.OnAddGeofencesResultListener</a> listener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">addGeofences</a></span>(List&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt; geofences, PendingIntent pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">LocationClient.OnAddGeofencesResultListener</a> listener)</nobr>
         
         <div class="jd-descrdiv">Sets alerts to be notified when the device enters or exits one of the
  specified geofences.</div>
@@ -966,7 +973,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getErrorCode(android.content.Intent)">getErrorCode</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getErrorCode(android.content.Intent)">getErrorCode</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Returns the error code that explains the error that triggered this
  intent.</div>
@@ -985,7 +992,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getGeofenceTransition(android.content.Intent)">getGeofenceTransition</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getGeofenceTransition(android.content.Intent)">getGeofenceTransition</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Returns the transition type of geofence transition alert.</div>
   
@@ -1000,7 +1007,7 @@
             
             
             
-            <a href="/reference/android/location/Location.html">Location</a></nobr>
+            Location</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation</a></span>()</nobr>
@@ -1018,10 +1025,10 @@
             
             static
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getTriggeringGeofences(android.content.Intent)">getTriggeringGeofences</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#getTriggeringGeofences(android.content.Intent)">getTriggeringGeofences</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Returns a list of geofences that triggers this geofence transition alert.</div>
   
@@ -1039,7 +1046,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#hasError(android.content.Intent)">hasError</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#hasError(android.content.Intent)">hasError</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Whether an error triggered this intent.</div>
   
@@ -1169,7 +1176,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#removeGeofences(java.util.List<java.lang.String>, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; geofenceRequestIds, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#removeGeofences(java.util.List<java.lang.String>, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences</a></span>(List&lt;String&gt; geofenceRequestIds, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</nobr>
         
         <div class="jd-descrdiv">Removes geofences by their request IDs.</div>
   
@@ -1187,7 +1194,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences</a></span>(<a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences</a></span>(PendingIntent pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</nobr>
         
         <div class="jd-descrdiv">Removes all geofences associated with the given <code>pendingIntent</code>.</div>
   
@@ -1223,7 +1230,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#removeLocationUpdates(android.app.PendingIntent)">removeLocationUpdates</a></span>(<a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#removeLocationUpdates(android.app.PendingIntent)">removeLocationUpdates</a></span>(PendingIntent callbackIntent)</nobr>
         
         <div class="jd-descrdiv">Removes all location updates for the given pending intent.</div>
   
@@ -1241,7 +1248,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, android.app.PendingIntent)">requestLocationUpdates</a></span>(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, android.app.PendingIntent)">requestLocationUpdates</a></span>(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, PendingIntent callbackIntent)</nobr>
         
         <div class="jd-descrdiv">Requests location updates with a callback on the specified PendingIntent.</div>
   
@@ -1277,7 +1284,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener, android.os.Looper)">requestLocationUpdates</a></span>(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, <a href="/reference/com/google/android/gms/location/LocationListener.html">LocationListener</a> listener, <a href="/reference/android/os/Looper.html">Looper</a> looper)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener, android.os.Looper)">requestLocationUpdates</a></span>(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, <a href="/reference/com/google/android/gms/location/LocationListener.html">LocationListener</a> listener, Looper looper)</nobr>
         
         <div class="jd-descrdiv">Requests location updates with a callback on the specified Looper thread.</div>
   
@@ -1295,7 +1302,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">setMockLocation</a></span>(<a href="/reference/android/location/Location.html">Location</a> mockLocation)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">setMockLocation</a></span>(Location mockLocation)</nobr>
         
         <div class="jd-descrdiv">Sets the mock location to be used for the location provider.</div>
   
@@ -1379,7 +1386,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1398,7 +1405,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1417,7 +1424,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1446,7 +1453,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1510,7 +1517,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1819,7 +1826,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_LOCATION_CHANGED
     </h4>
@@ -1858,7 +1865,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_MOCK_LOCATION
     </h4>
@@ -1915,7 +1922,7 @@
         
       </span>
       <span class="sympad">LocationClient</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1978,7 +1985,7 @@
         void
       </span>
       <span class="sympad">addGeofences</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt; geofences, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">LocationClient.OnAddGeofencesResultListener</a> listener)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt; geofences, PendingIntent pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">LocationClient.OnAddGeofencesResultListener</a> listener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2040,23 +2047,23 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>if the app does not have
              <code><a href="/reference/android/Manifest.permission.html#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></code>
              permission</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the connection to Google Play Store
              Services hasn't been established</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if <code>geofences</code> is <code>null</code> or
              empty</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/NullPointerException.html">NullPointerException</a></td>
+            <th>NullPointerException</td>
             <td>if <code>intent</code> or <code>listener</code> is
              <code>null</code>
 </td>
@@ -2144,7 +2151,7 @@
         int
       </span>
       <span class="sympad">getErrorCode</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2189,7 +2196,7 @@
         int
       </span>
       <span class="sympad">getGeofenceTransition</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2231,7 +2238,7 @@
          
          
          
-        <a href="/reference/android/location/Location.html">Location</a>
+        Location
       </span>
       <span class="sympad">getLastLocation</span>
       <span class="normal">()</span>
@@ -2268,10 +2275,10 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/location/Geofence.html">Geofence</a>&gt;
       </span>
       <span class="sympad">getTriggeringGeofences</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2316,7 +2323,7 @@
         boolean
       </span>
       <span class="sympad">hasError</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2622,7 +2629,7 @@
         void
       </span>
       <span class="sympad">removeGeofences</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; geofenceRequestIds, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</span>
+      <span class="normal">(List&lt;String&gt; geofenceRequestIds, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2660,23 +2667,23 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if <code>geofenceRequestIds</code> is
              <code>null</code> or empty</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>if the app does not have
              <code><a href="/reference/android/Manifest.permission.html#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></code>
              permission</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the connection to Google Play Store
              Services hasn't been established</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/NullPointerException.html">NullPointerException</a></td>
+            <th>NullPointerException</td>
             <td>if <code>listener</code> is <code>null</code>
 </td>
         </tr>
@@ -2700,7 +2707,7 @@
         void
       </span>
       <span class="sympad">removeGeofences</span>
-      <span class="normal">(<a href="/reference/android/app/PendingIntent.html">PendingIntent</a> pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</span>
+      <span class="normal">(PendingIntent pendingIntent, <a href="/reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a> listener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2743,18 +2750,18 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>if the app does not have
              <code><a href="/reference/android/Manifest.permission.html#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></code>
              permission</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the connection to Google Play Store
              Services hasn't been established</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/NullPointerException.html">NullPointerException</a></td>
+            <th>NullPointerException</td>
             <td>if <code>intent</code> or <code>listener</code> is
              null
 </td>
@@ -2818,7 +2825,7 @@
         void
       </span>
       <span class="sympad">removeLocationUpdates</span>
-      <span class="normal">(<a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</span>
+      <span class="normal">(PendingIntent callbackIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2857,7 +2864,7 @@
         void
       </span>
       <span class="sympad">requestLocationUpdates</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, <a href="/reference/android/app/PendingIntent.html">PendingIntent</a> callbackIntent)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, PendingIntent callbackIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2967,7 +2974,7 @@
         void
       </span>
       <span class="sympad">requestLocationUpdates</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, <a href="/reference/com/google/android/gms/location/LocationListener.html">LocationListener</a> listener, <a href="/reference/android/os/Looper.html">Looper</a> looper)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a> request, <a href="/reference/com/google/android/gms/location/LocationListener.html">LocationListener</a> listener, Looper looper)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3026,7 +3033,7 @@
         void
       </span>
       <span class="sympad">setMockLocation</span>
-      <span class="normal">(<a href="/reference/android/location/Location.html">Location</a> mockLocation)</span>
+      <span class="normal">(Location mockLocation)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3057,7 +3064,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>if the ACCESS_MOCK_LOCATION permission is not present or the
                            <code><a href="/reference/android/provider/Settings.Secure.html#ALLOW_MOCK_LOCATION">Settings.Secure.ALLOW_MOCK_LOCATION</a></code> system setting is
                            not enabled.
@@ -3119,7 +3126,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>if the ACCESS_MOCK_LOCATION permission is not present or the
                            <code><a href="/reference/android/provider/Settings.Secure.html#ALLOW_MOCK_LOCATION">Settings.Secure.ALLOW_MOCK_LOCATION</a></code> system setting is
                            not enabled.
diff --git a/docs/html/reference/com/google/android/gms/location/LocationListener.html b/docs/html/reference/com/google/android/gms/location/LocationListener.html
index 48e3487..da51ab7 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationListener.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -755,7 +762,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationListener.html#onLocationChanged(android.location.Location)">onLocationChanged</a></span>(<a href="/reference/android/location/Location.html">Location</a> location)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationListener.html#onLocationChanged(android.location.Location)">onLocationChanged</a></span>(Location location)</nobr>
         
         <div class="jd-descrdiv">Called when the location has changed.</div>
   
@@ -823,7 +830,7 @@
         void
       </span>
       <span class="sympad">onLocationChanged</span>
-      <span class="normal">(<a href="/reference/android/location/Location.html">Location</a> location)</span>
+      <span class="normal">(Location location)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/LocationRequest.html b/docs/html/reference/com/google/android/gms/location/LocationRequest.html
index c5d4a7b..dcfc4d6 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationRequest.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationRequest.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationRequest | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1001,7 +1008,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationRequest.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> object)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationRequest.html#equals(java.lang.Object)">equals</a></span>(Object object)</nobr>
         
   </td></tr>
 
@@ -1268,7 +1275,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationRequest.html#toString()">toString</a></span>()</nobr>
@@ -1287,7 +1294,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationRequest.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> parcel, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/location/LocationRequest.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel parcel, int flags)</nobr>
         
   </td></tr>
 
@@ -1315,7 +1322,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1334,7 +1341,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1353,7 +1360,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1382,7 +1389,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1446,7 +1453,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1517,7 +1524,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1555,7 +1562,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1897,7 +1904,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> object)</span>
+      <span class="normal">(Object object)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2319,7 +2326,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the interval is less than zero</td>
         </tr>
       </table>
@@ -2390,7 +2397,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the interval is less than zero</td>
         </tr>
       </table>
@@ -2447,7 +2454,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if numUpdates is 0 or less</td>
         </tr>
       </table>
@@ -2511,7 +2518,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the quality constant is not valid</td>
         </tr>
       </table>
@@ -2566,7 +2573,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if smallestDisplacementMeters is negative</td>
         </tr>
       </table>
@@ -2586,7 +2593,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -2618,7 +2625,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> parcel, int flags)</span>
+      <span class="normal">(Parcel parcel, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/location/LocationStatusCodes.html b/docs/html/reference/com/google/android/gms/location/LocationStatusCodes.html
index b53f716..f76ea05 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationStatusCodes.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationStatusCodes.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationStatusCodes | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -842,7 +849,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -861,7 +868,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -880,7 +887,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -909,7 +916,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -973,7 +980,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/location/package-summary.html b/docs/html/reference/com/google/android/gms/location/package-summary.html
index c21638c..bfd353e 100644
--- a/docs/html/reference/com/google/android/gms/location/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/location/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.location | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/CameraUpdate.html b/docs/html/reference/com/google/android/gms/maps/CameraUpdate.html
index daa83cf..ac64600 100644
--- a/docs/html/reference/com/google/android/gms/maps/CameraUpdate.html
+++ b/docs/html/reference/com/google/android/gms/maps/CameraUpdate.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>CameraUpdate | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -675,7 +682,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -695,7 +702,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -808,7 +815,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -827,7 +834,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -846,7 +853,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -875,7 +882,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -939,7 +946,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/maps/CameraUpdateFactory.html b/docs/html/reference/com/google/android/gms/maps/CameraUpdateFactory.html
index 3d2d223..0f0da8f 100644
--- a/docs/html/reference/com/google/android/gms/maps/CameraUpdateFactory.html
+++ b/docs/html/reference/com/google/android/gms/maps/CameraUpdateFactory.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>CameraUpdateFactory | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -932,7 +939,7 @@
             <a href="/reference/com/google/android/gms/maps/CameraUpdate.html">CameraUpdate</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/CameraUpdateFactory.html#zoomBy(float, android.graphics.Point)">zoomBy</a></span>(float amount, <a href="/reference/android/graphics/Point.html">Point</a> focus)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/CameraUpdateFactory.html#zoomBy(float, android.graphics.Point)">zoomBy</a></span>(float amount, Point focus)</nobr>
         
         <div class="jd-descrdiv">Returns a <code><a href="/reference/com/google/android/gms/maps/CameraUpdate.html">CameraUpdate</a></code> that shifts the zoom level of the current camera viewpoint.</div>
   
@@ -1036,7 +1043,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1055,7 +1062,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1074,7 +1081,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1103,7 +1110,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1167,7 +1174,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1601,7 +1608,7 @@
         <a href="/reference/com/google/android/gms/maps/CameraUpdate.html">CameraUpdate</a>
       </span>
       <span class="sympad">zoomBy</span>
-      <span class="normal">(float amount, <a href="/reference/android/graphics/Point.html">Point</a> focus)</span>
+      <span class="normal">(float amount, Point focus)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html
index 9af9d29..56be216 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.CancelableCallback | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html
index 46f599d..6181be5 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.InfoWindowAdapter | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -768,7 +775,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html#getInfoContents(com.google.android.gms.maps.model.Marker)">getInfoContents</a></span>(<a href="/reference/com/google/android/gms/maps/model/Marker.html">Marker</a> marker)</nobr>
@@ -786,7 +793,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html#getInfoWindow(com.google.android.gms.maps.model.Marker)">getInfoWindow</a></span>(<a href="/reference/com/google/android/gms/maps/model/Marker.html">Marker</a> marker)</nobr>
@@ -854,7 +861,7 @@
          
         abstract 
          
-        <a href="/reference/android/view/View.html">View</a>
+        View
       </span>
       <span class="sympad">getInfoContents</span>
       <span class="normal">(<a href="/reference/com/google/android/gms/maps/model/Marker.html">Marker</a> marker)</span>
@@ -903,7 +910,7 @@
          
         abstract 
          
-        <a href="/reference/android/view/View.html">View</a>
+        View
       </span>
       <span class="sympad">getInfoWindow</span>
       <span class="normal">(<a href="/reference/com/google/android/gms/maps/model/Marker.html">Marker</a> marker)</span>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html
index 3ea1988..096a195 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnCameraChangeListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html
index 72ae333..cb89c40 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnInfoWindowClickListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html
index 3b59603..db5b3af 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnMapClickListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html
index ab5d2df..b795f2a 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnMapLongClickListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html
index 2f33946..d1326c9 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnMarkerClickListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html
index fac3be0..d9169c8 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnMarkerDragListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html
index 851a613..abcdb2e 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnMyLocationButtonClickListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html
index fed973d..fd2e782 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.OnMyLocationChangeListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -761,7 +768,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html#onMyLocationChange(android.location.Location)">onMyLocationChange</a></span>(<a href="/reference/android/location/Location.html">Location</a> location)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html#onMyLocationChange(android.location.Location)">onMyLocationChange</a></span>(Location location)</nobr>
         
         <div class="jd-descrdiv">Called when the Location of the My Location dot has changed (be it latitude/longitude,
  bearing or accuracy).</div>
@@ -830,7 +837,7 @@
         void
       </span>
       <span class="sympad">onMyLocationChange</span>
-      <span class="normal">(<a href="/reference/android/location/Location.html">Location</a> location)</span>
+      <span class="normal">(Location location)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html
index 12e63d6..ea31d25 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap.SnapshotReadyCallback | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -751,7 +758,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html#onSnapshotReady(android.graphics.Bitmap)">onSnapshotReady</a></span>(<a href="/reference/android/graphics/Bitmap.html">Bitmap</a> snapshot)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html#onSnapshotReady(android.graphics.Bitmap)">onSnapshotReady</a></span>(Bitmap snapshot)</nobr>
         
         <div class="jd-descrdiv">Invoked when the snapshot has been taken.</div>
   
@@ -819,7 +826,7 @@
         void
       </span>
       <span class="sympad">onSnapshotReady</span>
-      <span class="normal">(<a href="/reference/android/graphics/Bitmap.html">Bitmap</a> snapshot)</span>
+      <span class="normal">(Bitmap snapshot)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMap.html b/docs/html/reference/com/google/android/gms/maps/GoogleMap.html
index ebb59c3..dc3e874 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMap.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMap.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMap | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1256,7 +1263,7 @@
             final
             
             
-            <a href="/reference/android/location/Location.html">Location</a></nobr>
+            Location</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.html#getMyLocation()">getMyLocation</a></span>()</nobr>
@@ -1636,9 +1643,9 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.html#setTrafficEnabled(boolean)">setTrafficEnabled</a></span>(boolean enabled)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.html#setPadding(int, int, int, int)">setPadding</a></span>(int left, int top, int right, int bottom)</nobr>
         
-        <div class="jd-descrdiv">Toggles the traffic layer on or off.</div>
+        <div class="jd-descrdiv">Sets padding on the map.</div>
   
   </td></tr>
 
@@ -1654,7 +1661,25 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.html#snapshot(com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback, android.graphics.Bitmap)">snapshot</a></span>(<a href="/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html">GoogleMap.SnapshotReadyCallback</a> callback, <a href="/reference/android/graphics/Bitmap.html">Bitmap</a> bitmap)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.html#setTrafficEnabled(boolean)">setTrafficEnabled</a></span>(boolean enabled)</nobr>
+        
+        <div class="jd-descrdiv">Toggles the traffic layer on or off.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMap.html#snapshot(com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback, android.graphics.Bitmap)">snapshot</a></span>(<a href="/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html">GoogleMap.SnapshotReadyCallback</a> callback, Bitmap bitmap)</nobr>
         
         <div class="jd-descrdiv">Takes a snapshot of the map.</div>
   
@@ -1662,7 +1687,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1680,7 +1705,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1720,7 +1745,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1739,7 +1764,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1758,7 +1783,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1787,7 +1812,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1851,7 +1876,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2237,7 +2262,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if either the image or the position is unspecified in the
              options.
 </td>
@@ -2429,7 +2454,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the <code><a href="/reference/com/google/android/gms/maps/model/TileProvider.html">TileProvider</a></code> is unspecified in the options.
 </td>
         </tr>
@@ -2769,7 +2794,7 @@
         final 
          
          
-        <a href="/reference/android/location/Location.html">Location</a>
+        Location
       </span>
       <span class="sympad">getMyLocation</span>
       <span class="normal">()</span>
@@ -2802,7 +2827,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the my-location layer is not enabled.</td>
         </tr>
       </table>
@@ -3581,6 +3606,63 @@
 </div>
 
 
+<A NAME="setPadding(int, int, int, int)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+        final 
+         
+         
+        void
+      </span>
+      <span class="sympad">setPadding</span>
+      <span class="normal">(int left, int top, int right, int bottom)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets padding on the map.
+
+ <p>This method allows you to define a visible region on the map, to signal to the map that
+ portions of the map around the edges may be obscured, by setting padding on each of the four
+ edges of the map. Map functions will be adapted to the padding. For example, the zoom
+ controls, compass, copyright notices and Google logo will be moved to fit inside the defined
+ region, camera movements will be relative to the center of the visible region, etc.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>left</td>
+          <td>the number of pixels of padding to be added on the left of the map.</td>
+        </tr>
+        <tr>
+          <th>top</td>
+          <td>the number of pixels of padding to be added on the top of the map.</td>
+        </tr>
+        <tr>
+          <th>right</td>
+          <td>the number of pixels of padding to be added on the right of the map.</td>
+        </tr>
+        <tr>
+          <th>bottom</td>
+          <td>the number of pixels of padding to be added on the bottom of the map.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="setTrafficEnabled(boolean)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -3623,7 +3705,7 @@
         void
       </span>
       <span class="sympad">snapshot</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html">GoogleMap.SnapshotReadyCallback</a> callback, <a href="/reference/android/graphics/Bitmap.html">Bitmap</a> bitmap)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html">GoogleMap.SnapshotReadyCallback</a> callback, Bitmap bitmap)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3634,11 +3716,11 @@
     <div class="jd-details-descr">
       
   <div class="jd-tagdata jd-tagdescr"><p>Takes a snapshot of the map.
- <p>
+
  <p>This method is equivalent to <code><a href="/reference/com/google/android/gms/maps/GoogleMap.html#snapshot(com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback)">snapshot(SnapshotReadyCallback)</a></code> but lets you
  provide a preallocated <code><a href="/reference/android/graphics/Bitmap.html">Bitmap</a></code>. If the bitmap does not match the current dimensions of
  the map, another bitmap will be allocated that fits the map's dimensions.
- <p>
+
  <p>Although in most cases the object passed by the callback method is the same as the one
  given in parameter to this method, in some cases the returned object can be different (e.g.
  if the view's dimensions have changed by the time the snapshot is actually taken). Thus, you
diff --git a/docs/html/reference/com/google/android/gms/maps/GoogleMapOptions.html b/docs/html/reference/com/google/android/gms/maps/GoogleMapOptions.html
index fa78bc6..ba0cc9a 100644
--- a/docs/html/reference/com/google/android/gms/maps/GoogleMapOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/GoogleMapOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GoogleMapOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -953,7 +960,7 @@
             <a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html">GoogleMapOptions</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#createFromAttributes(android.content.Context, android.util.AttributeSet)">createFromAttributes</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#createFromAttributes(android.content.Context, android.util.AttributeSet)">createFromAttributes</a></span>(Context context, AttributeSet attrs)</nobr>
         
         <div class="jd-descrdiv">Creates a GoogleMapsOptions from the attribute set
 </div>
@@ -1001,7 +1008,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getCompassEnabled()">getCompassEnabled</a></span>()</nobr>
@@ -1033,7 +1040,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getRotateGesturesEnabled()">getRotateGesturesEnabled</a></span>()</nobr>
@@ -1049,7 +1056,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getScrollGesturesEnabled()">getScrollGesturesEnabled</a></span>()</nobr>
@@ -1065,7 +1072,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getTiltGesturesEnabled()">getTiltGesturesEnabled</a></span>()</nobr>
@@ -1081,7 +1088,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getUseViewLifecycleInFragment()">getUseViewLifecycleInFragment</a></span>()</nobr>
@@ -1097,7 +1104,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getZOrderOnTop()">getZOrderOnTop</a></span>()</nobr>
@@ -1113,7 +1120,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getZoomControlsEnabled()">getZoomControlsEnabled</a></span>()</nobr>
@@ -1129,7 +1136,7 @@
             
             
             
-            <a href="/reference/java/lang/Boolean.html">Boolean</a></nobr>
+            Boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#getZoomGesturesEnabled()">getZoomGesturesEnabled</a></span>()</nobr>
@@ -1239,7 +1246,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1321,7 +1328,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1340,7 +1347,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1359,7 +1366,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1388,7 +1395,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1452,7 +1459,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1523,7 +1530,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1561,7 +1568,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1761,7 +1768,7 @@
         <a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html">GoogleMapOptions</a>
       </span>
       <span class="sympad">createFromAttributes</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1850,7 +1857,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getCompassEnabled</span>
       <span class="normal">()</span>
@@ -1916,7 +1923,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getRotateGesturesEnabled</span>
       <span class="normal">()</span>
@@ -1949,7 +1956,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getScrollGesturesEnabled</span>
       <span class="normal">()</span>
@@ -1982,7 +1989,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getTiltGesturesEnabled</span>
       <span class="normal">()</span>
@@ -2015,7 +2022,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getUseViewLifecycleInFragment</span>
       <span class="normal">()</span>
@@ -2048,7 +2055,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getZOrderOnTop</span>
       <span class="normal">()</span>
@@ -2081,7 +2088,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getZoomControlsEnabled</span>
       <span class="normal">()</span>
@@ -2114,7 +2121,7 @@
          
          
          
-        <a href="/reference/java/lang/Boolean.html">Boolean</a>
+        Boolean
       </span>
       <span class="sympad">getZoomGesturesEnabled</span>
       <span class="normal">()</span>
@@ -2318,7 +2325,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html b/docs/html/reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html
index 94a6ae1..0dcad24 100644
--- a/docs/html/reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html
+++ b/docs/html/reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationSource.OnLocationChangedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -751,7 +758,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html#onLocationChanged(android.location.Location)">onLocationChanged</a></span>(<a href="/reference/android/location/Location.html">Location</a> location)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html#onLocationChanged(android.location.Location)">onLocationChanged</a></span>(Location location)</nobr>
         
         <div class="jd-descrdiv">Called when a new user location is known.</div>
   
@@ -819,7 +826,7 @@
         void
       </span>
       <span class="sympad">onLocationChanged</span>
-      <span class="normal">(<a href="/reference/android/location/Location.html">Location</a> location)</span>
+      <span class="normal">(Location location)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/LocationSource.html b/docs/html/reference/com/google/android/gms/maps/LocationSource.html
index afc5cc4..9ba64e0 100644
--- a/docs/html/reference/com/google/android/gms/maps/LocationSource.html
+++ b/docs/html/reference/com/google/android/gms/maps/LocationSource.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LocationSource | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -895,11 +902,11 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if this provider is already active</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if <code>listener</code> is <code>null</code>
 </td>
         </tr>
@@ -939,7 +946,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if this provider is already inactive
 </td>
         </tr>
diff --git a/docs/html/reference/com/google/android/gms/maps/MapFragment.html b/docs/html/reference/com/google/android/gms/maps/MapFragment.html
index dbff4ab..ecd7f78 100644
--- a/docs/html/reference/com/google/android/gms/maps/MapFragment.html
+++ b/docs/html/reference/com/google/android/gms/maps/MapFragment.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>MapFragment | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -738,7 +745,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1045,7 +1052,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onActivityCreated(android.os.Bundle)">onActivityCreated</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onActivityCreated(android.os.Bundle)">onActivityCreated</a></span>(Bundle savedInstanceState)</nobr>
         
   </td></tr>
 
@@ -1061,7 +1068,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onAttach(android.app.Activity)">onAttach</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> activity)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onAttach(android.app.Activity)">onAttach</a></span>(Activity activity)</nobr>
         
   </td></tr>
 
@@ -1077,7 +1084,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onCreate(android.os.Bundle)">onCreate</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onCreate(android.os.Bundle)">onCreate</a></span>(Bundle savedInstanceState)</nobr>
         
   </td></tr>
 
@@ -1090,10 +1097,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)">onCreateView</a></span>(<a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a> inflater, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> container, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)">onCreateView</a></span>(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)</nobr>
         
   </td></tr>
 
@@ -1141,7 +1148,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle)">onInflate</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> activity, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle)">onInflate</a></span>(Activity activity, AttributeSet attrs, Bundle savedInstanceState)</nobr>
         
         <div class="jd-descrdiv">Parse attributes during inflation from a view hierarchy into the arguments we handle.</div>
   
@@ -1207,7 +1214,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onSaveInstanceState(android.os.Bundle)">onSaveInstanceState</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> outState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#onSaveInstanceState(android.os.Bundle)">onSaveInstanceState</a></span>(Bundle outState)</nobr>
         
   </td></tr>
 
@@ -1223,7 +1230,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#setArguments(android.os.Bundle)">setArguments</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> args)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapFragment.html#setArguments(android.os.Bundle)">setArguments</a></span>(Bundle args)</nobr>
         
   </td></tr>
 
@@ -1273,7 +1280,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dump</span>(<a href="/reference/java/lang/String.html">String</a> arg0, <a href="/reference/java/io/FileDescriptor.html">FileDescriptor</a> arg1, <a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg2, <a href="/reference/java/lang/String.html">String[]</a> arg3)</nobr>
+        <span class="sympad">dump</span>(String arg0, FileDescriptor arg1, PrintWriter arg2, String[] arg3)</nobr>
         
   </td></tr>
 
@@ -1289,7 +1296,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1302,7 +1309,7 @@
             final
             
             
-            <a href="/reference/android/app/Activity.html">Activity</a></nobr>
+            Activity</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getActivity</span>()</nobr>
@@ -1318,7 +1325,7 @@
             final
             
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getArguments</span>()</nobr>
@@ -1382,7 +1389,7 @@
             final
             
             
-            <a href="/reference/android/content/res/Resources.html">Resources</a></nobr>
+            Resources</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getResources</span>()</nobr>
@@ -1414,7 +1421,7 @@
             final
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getString</span>(int arg0)</nobr>
@@ -1430,10 +1437,10 @@
             final
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getString</span>(int arg0, <a href="/reference/java/lang/Object.html">Object...</a> arg1)</nobr>
+        <span class="sympad">getString</span>(int arg0, Object... arg1)</nobr>
         
   </td></tr>
 
@@ -1446,7 +1453,7 @@
             final
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>()</nobr>
@@ -1494,7 +1501,7 @@
             final
             
             
-            <a href="/reference/java/lang/CharSequence.html">CharSequence</a></nobr>
+            CharSequence</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getText</span>(int arg0)</nobr>
@@ -1526,7 +1533,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getView</span>()</nobr>
@@ -1561,7 +1568,7 @@
             Fragment</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">instantiate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, <a href="/reference/java/lang/String.html">String</a> arg1)</nobr>
+        <span class="sympad">instantiate</span>(Context arg0, String arg1)</nobr>
         
   </td></tr>
 
@@ -1577,7 +1584,7 @@
             Fragment</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">instantiate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, <a href="/reference/java/lang/String.html">String</a> arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">instantiate</span>(Context arg0, String arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -1705,7 +1712,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onActivityCreated</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onActivityCreated</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -1721,7 +1728,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onActivityResult</span>(int arg0, int arg1, <a href="/reference/android/content/Intent.html">Intent</a> arg2)</nobr>
+        <span class="sympad">onActivityResult</span>(int arg0, int arg1, Intent arg2)</nobr>
         
   </td></tr>
 
@@ -1737,7 +1744,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onAttach</span>(<a href="/reference/android/app/Activity.html">Activity</a> arg0)</nobr>
+        <span class="sympad">onAttach</span>(Activity arg0)</nobr>
         
   </td></tr>
 
@@ -1753,7 +1760,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -1769,7 +1776,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onContextItemSelected</span>(<a href="/reference/android/view/MenuItem.html">MenuItem</a> arg0)</nobr>
+        <span class="sympad">onContextItemSelected</span>(MenuItem arg0)</nobr>
         
   </td></tr>
 
@@ -1785,7 +1792,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreate</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onCreate</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -1817,7 +1824,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a> arg2)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0, View arg1, ContextMenu.ContextMenuInfo arg2)</nobr>
         
   </td></tr>
 
@@ -1833,7 +1840,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateOptionsMenu</span>(<a href="/reference/android/view/Menu.html">Menu</a> arg0, <a href="/reference/android/view/MenuInflater.html">MenuInflater</a> arg1)</nobr>
+        <span class="sympad">onCreateOptionsMenu</span>(Menu arg0, MenuInflater arg1)</nobr>
         
   </td></tr>
 
@@ -1846,10 +1853,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateView</span>(<a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a> arg0, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">onCreateView</span>(LayoutInflater arg0, ViewGroup arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -1945,7 +1952,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInflate</span>(<a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">onInflate</span>(AttributeSet arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -1961,7 +1968,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInflate</span>(<a href="/reference/android/app/Activity.html">Activity</a> arg0, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">onInflate</span>(Activity arg0, AttributeSet arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -1993,7 +2000,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onOptionsItemSelected</span>(<a href="/reference/android/view/MenuItem.html">MenuItem</a> arg0)</nobr>
+        <span class="sympad">onOptionsItemSelected</span>(MenuItem arg0)</nobr>
         
   </td></tr>
 
@@ -2009,7 +2016,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onOptionsMenuClosed</span>(<a href="/reference/android/view/Menu.html">Menu</a> arg0)</nobr>
+        <span class="sympad">onOptionsMenuClosed</span>(Menu arg0)</nobr>
         
   </td></tr>
 
@@ -2041,7 +2048,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onPrepareOptionsMenu</span>(<a href="/reference/android/view/Menu.html">Menu</a> arg0)</nobr>
+        <span class="sympad">onPrepareOptionsMenu</span>(Menu arg0)</nobr>
         
   </td></tr>
 
@@ -2073,7 +2080,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onSaveInstanceState</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onSaveInstanceState</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -2137,7 +2144,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onViewCreated</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">onViewCreated</span>(View arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -2153,7 +2160,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">registerForContextMenu</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">registerForContextMenu</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2169,7 +2176,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setArguments</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">setArguments</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -2281,7 +2288,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActivity</span>(<a href="/reference/android/content/Intent.html">Intent</a> arg0)</nobr>
+        <span class="sympad">startActivity</span>(Intent arg0)</nobr>
         
   </td></tr>
 
@@ -2297,7 +2304,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActivity</span>(<a href="/reference/android/content/Intent.html">Intent</a> arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">startActivity</span>(Intent arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -2313,7 +2320,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActivityForResult</span>(<a href="/reference/android/content/Intent.html">Intent</a> arg0, int arg1)</nobr>
+        <span class="sympad">startActivityForResult</span>(Intent arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2329,7 +2336,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActivityForResult</span>(<a href="/reference/android/content/Intent.html">Intent</a> arg0, int arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">startActivityForResult</span>(Intent arg0, int arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -2342,7 +2349,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2361,7 +2368,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unregisterForContextMenu</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">unregisterForContextMenu</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2381,7 +2388,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -2400,7 +2407,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -2419,7 +2426,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -2448,7 +2455,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -2512,7 +2519,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2583,7 +2590,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/content/ComponentCallbacks.html">android.content.ComponentCallbacks</a>
+  android.content.ComponentCallbacks
 
 <div id="inherited-methods-android.content.ComponentCallbacks">
   <div id="inherited-methods-android.content.ComponentCallbacks-list"
@@ -2605,7 +2612,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -2683,7 +2690,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/View.OnCreateContextMenuListener.html">android.view.View.OnCreateContextMenuListener</a>
+  android.view.View.OnCreateContextMenuListener
 
 <div id="inherited-methods-android.view.View.OnCreateContextMenuListener">
   <div id="inherited-methods-android.view.View.OnCreateContextMenuListener-list"
@@ -2705,7 +2712,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a> arg2)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0, View arg1, ContextMenu.ContextMenuInfo arg2)</nobr>
         
   </td></tr>
 
@@ -2908,7 +2915,7 @@
         void
       </span>
       <span class="sympad">onActivityCreated</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2937,7 +2944,7 @@
         void
       </span>
       <span class="sympad">onAttach</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> activity)</span>
+      <span class="normal">(Activity activity)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2966,7 +2973,7 @@
         void
       </span>
       <span class="sympad">onCreate</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2992,10 +2999,10 @@
          
          
          
-        <a href="/reference/android/view/View.html">View</a>
+        View
       </span>
       <span class="sympad">onCreateView</span>
-      <span class="normal">(<a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a> inflater, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> container, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3082,7 +3089,7 @@
         void
       </span>
       <span class="sympad">onInflate</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> activity, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Activity activity, AttributeSet attrs, Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3199,7 +3206,7 @@
         void
       </span>
       <span class="sympad">onSaveInstanceState</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> outState)</span>
+      <span class="normal">(Bundle outState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3228,7 +3235,7 @@
         void
       </span>
       <span class="sympad">setArguments</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> args)</span>
+      <span class="normal">(Bundle args)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/MapView.html b/docs/html/reference/com/google/android/gms/maps/MapView.html
index 11bf3f6..a96cfbf 100644
--- a/docs/html/reference/com/google/android/gms/maps/MapView.html
+++ b/docs/html/reference/com/google/android/gms/maps/MapView.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>MapView | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -761,7 +768,7 @@
   
 
   
-    extends <a href="/reference/android/widget/FrameLayout.html">FrameLayout</a><br/>
+    extends FrameLayout<br/>
   
   
   
@@ -781,7 +788,7 @@
 
     <tr>
          	
-        <td colspan="5" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -789,7 +796,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/android/view/View.html">android.view.View</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">android.view.View</td>
     </tr>
     
 
@@ -799,7 +806,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/android/view/ViewGroup.html">android.view.ViewGroup</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">android.view.ViewGroup</td>
     </tr>
     
 
@@ -811,7 +818,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/android/widget/FrameLayout.html">android.widget.FrameLayout</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">android.widget.FrameLayout</td>
     </tr>
     
 
@@ -1393,7 +1400,7 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol">VIEW_LOG_TAG</td>
         <td class="jd-descrcol" width="100%"></td>
     </tr>
@@ -1464,7 +1471,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ALPHA</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1783,7 +1790,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1794,7 +1801,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1805,7 +1812,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1816,7 +1823,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">SCALE_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1827,7 +1834,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">SCALE_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1860,7 +1867,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">TRANSLATION_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1871,7 +1878,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">TRANSLATION_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1893,7 +1900,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1904,7 +1911,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1949,7 +1956,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context)">MapView</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context)">MapView</a></span>(Context context)</nobr>
         
   </td></tr>
 
@@ -1965,7 +1972,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context, android.util.AttributeSet)">MapView</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context, android.util.AttributeSet)">MapView</a></span>(Context context, AttributeSet attrs)</nobr>
         
   </td></tr>
 
@@ -1981,7 +1988,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context, android.util.AttributeSet, int)">MapView</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, int defStyle)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context, android.util.AttributeSet, int)">MapView</a></span>(Context context, AttributeSet attrs, int defStyle)</nobr>
         
   </td></tr>
 
@@ -1997,7 +2004,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context, com.google.android.gms.maps.GoogleMapOptions)">MapView</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html">GoogleMapOptions</a> options)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#MapView(android.content.Context, com.google.android.gms.maps.GoogleMapOptions)">MapView</a></span>(Context context, <a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html">GoogleMapOptions</a> options)</nobr>
         
   </td></tr>
 
@@ -2044,7 +2051,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#onCreate(android.os.Bundle)">onCreate</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#onCreate(android.os.Bundle)">onCreate</a></span>(Bundle savedInstanceState)</nobr>
         
         <div class="jd-descrdiv">You must call this method from the parent Activity/Fragment's corresponding method.</div>
   
@@ -2134,7 +2141,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#onSaveInstanceState(android.os.Bundle)">onSaveInstanceState</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> outState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapView.html#onSaveInstanceState(android.os.Bundle)">onSaveInstanceState</a></span>(Bundle outState)</nobr>
         
         <div class="jd-descrdiv">You must call this method from the parent Activity/Fragment's corresponding method.</div>
   
@@ -2164,7 +2171,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/widget/FrameLayout.html">android.widget.FrameLayout</a>
+  android.widget.FrameLayout
 
 <div id="inherited-methods-android.widget.FrameLayout">
   <div id="inherited-methods-android.widget.FrameLayout-list"
@@ -2186,7 +2193,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2202,7 +2209,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">draw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -2234,7 +2241,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">gatherTransparentRegion</span>(<a href="/reference/android/graphics/Region.html">Region</a> arg0)</nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
         
   </td></tr>
 
@@ -2247,7 +2254,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
@@ -2263,10 +2270,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
         
   </td></tr>
 
@@ -2279,10 +2286,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2311,7 +2318,7 @@
             
             
             
-            <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a></nobr>
+            Drawable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getForeground</span>()</nobr>
@@ -2378,7 +2385,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInitializeAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2458,7 +2465,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setForeground</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setForeground</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -2522,7 +2529,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">verifyDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -2542,7 +2549,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/view/ViewGroup.html">android.view.ViewGroup</a>
+  android.view.ViewGroup
 
 <div id="inherited-methods-android.view.ViewGroup">
   <div id="inherited-methods-android.view.ViewGroup-list"
@@ -2564,7 +2571,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addChildrenForAccessibility</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2580,7 +2587,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -2612,7 +2619,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addTouchables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2628,7 +2635,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2644,7 +2651,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -2660,7 +2667,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2676,7 +2683,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">addView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2692,7 +2699,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -2708,7 +2715,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2, boolean arg3)</nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2, boolean arg3)</nobr>
         
   </td></tr>
 
@@ -2724,7 +2731,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2740,7 +2747,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">attachLayoutAnimationParameters</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1, int arg2, int arg3)</nobr>
+        <span class="sympad">attachLayoutAnimationParameters</span>(View arg0, ViewGroup.LayoutParams arg1, int arg2, int arg3)</nobr>
         
   </td></tr>
 
@@ -2756,7 +2763,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">attachViewToParent</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">attachViewToParent</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2772,7 +2779,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">bringChildToFront</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2804,7 +2811,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2820,7 +2827,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">childDrawableStateChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2836,7 +2843,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">cleanupLayoutState</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">cleanupLayoutState</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2852,7 +2859,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clearChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2932,7 +2939,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">detachViewFromParent</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">detachViewFromParent</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2980,7 +2987,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -3028,7 +3035,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -3044,7 +3051,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchFreezeSelfOnly</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchFreezeSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3060,7 +3067,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericFocusedEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3076,7 +3083,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericPointerEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3092,7 +3099,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3108,7 +3115,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3124,7 +3131,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEventPreIme</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3140,7 +3147,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyShortcutEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3156,7 +3163,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchRestoreInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3172,7 +3179,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchSaveInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3252,7 +3259,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchThawSelfOnly</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchThawSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -3268,7 +3275,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3284,7 +3291,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3300,7 +3307,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchUnhandledMove</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3316,7 +3323,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3380,7 +3387,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">drawChild</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, long arg2)</nobr>
+        <span class="sympad">drawChild</span>(Canvas arg0, View arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -3412,7 +3419,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">endViewTransition</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">endViewTransition</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3425,7 +3432,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findFocus</span>()</nobr>
@@ -3444,7 +3451,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewsWithText</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, <a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg1, int arg2)</nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -3460,7 +3467,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">fitSystemWindows</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -3473,10 +3480,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusSearch</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3492,7 +3499,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusableViewAvailable</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3508,7 +3515,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">gatherTransparentRegion</span>(<a href="/reference/android/graphics/Region.html">Region</a> arg0)</nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
         
   </td></tr>
 
@@ -3521,7 +3528,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
@@ -3537,10 +3544,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
         
   </td></tr>
 
@@ -3553,10 +3560,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -3569,7 +3576,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getChildAt</span>(int arg0)</nobr>
@@ -3636,7 +3643,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildStaticTransformation</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/animation/Transformation.html">Transformation</a> arg1)</nobr>
+        <span class="sympad">getChildStaticTransformation</span>(View arg0, Transformation arg1)</nobr>
         
   </td></tr>
 
@@ -3652,7 +3659,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildVisibleRect</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, <a href="/reference/android/graphics/Point.html">Point</a> arg2)</nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
         
   </td></tr>
 
@@ -3681,7 +3688,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getFocusedChild</span>()</nobr>
@@ -3697,7 +3704,7 @@
             
             
             
-            <a href="/reference/android/view/animation/LayoutAnimationController.html">LayoutAnimationController</a></nobr>
+            LayoutAnimationController</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutAnimation</span>()</nobr>
@@ -3713,7 +3720,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.AnimationListener.html">Animation.AnimationListener</a></nobr>
+            Animation.AnimationListener</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutAnimationListener</span>()</nobr>
@@ -3796,7 +3803,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">indexOfChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">indexOfChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3812,7 +3819,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3825,10 +3832,10 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChildInParent</span>(int[] arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3956,7 +3963,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">measureChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">measureChild</span>(View arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -3972,7 +3979,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">measureChildWithMargins</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        <span class="sympad">measureChildWithMargins</span>(View arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
         
   </td></tr>
 
@@ -4004,7 +4011,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">offsetDescendantRectToMyCoords</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">offsetDescendantRectToMyCoords</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4020,7 +4027,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">offsetRectIntoDescendantCoords</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">offsetRectIntoDescendantCoords</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4084,7 +4091,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInterceptHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onInterceptHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -4100,7 +4107,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInterceptTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onInterceptTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -4132,7 +4139,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4148,7 +4155,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRequestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">onRequestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -4164,7 +4171,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">recomputeViewAttributes</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4212,7 +4219,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeDetachedView</span>(<a href="/reference/android/view/View.html">View</a> arg0, boolean arg1)</nobr>
+        <span class="sympad">removeDetachedView</span>(View arg0, boolean arg1)</nobr>
         
   </td></tr>
 
@@ -4228,7 +4235,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4260,7 +4267,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeViewInLayout</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4308,7 +4315,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1)</nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
         
   </td></tr>
 
@@ -4324,7 +4331,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildRectangleOnScreen</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, boolean arg2)</nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
         
   </td></tr>
 
@@ -4356,7 +4363,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestFocus</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -4372,7 +4379,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -4388,7 +4395,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestTransparentRegion</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4564,7 +4571,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutAnimation</span>(<a href="/reference/android/view/animation/LayoutAnimationController.html">LayoutAnimationController</a> arg0)</nobr>
+        <span class="sympad">setLayoutAnimation</span>(LayoutAnimationController arg0)</nobr>
         
   </td></tr>
 
@@ -4580,7 +4587,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutAnimationListener</span>(<a href="/reference/android/view/animation/Animation.AnimationListener.html">Animation.AnimationListener</a> arg0)</nobr>
+        <span class="sympad">setLayoutAnimationListener</span>(Animation.AnimationListener arg0)</nobr>
         
   </td></tr>
 
@@ -4628,7 +4635,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnHierarchyChangeListener</span>(<a href="/reference/android/view/ViewGroup.OnHierarchyChangeListener.html">ViewGroup.OnHierarchyChangeListener</a> arg0)</nobr>
+        <span class="sympad">setOnHierarchyChangeListener</span>(ViewGroup.OnHierarchyChangeListener arg0)</nobr>
         
   </td></tr>
 
@@ -4708,7 +4715,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">showContextMenuForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4724,7 +4731,7 @@
             ActionMode</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActionModeForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, ActionMode.Callback arg1)</nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
         
   </td></tr>
 
@@ -4756,7 +4763,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startViewTransition</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">startViewTransition</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4772,7 +4779,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">updateViewLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -4792,7 +4799,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/view/View.html">android.view.View</a>
+  android.view.View
 
 <div id="inherited-methods-android.view.View">
   <div id="inherited-methods-android.view.View-list"
@@ -4814,7 +4821,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addChildrenForAccessibility</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -4830,7 +4837,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -4846,7 +4853,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -4894,7 +4901,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addTouchables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -4926,7 +4933,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">announceForAccessibility</span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg0)</nobr>
+        <span class="sympad">announceForAccessibility</span>(CharSequence arg0)</nobr>
         
   </td></tr>
 
@@ -5118,7 +5125,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkInputConnectionProxy</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">checkInputConnectionProxy</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -5310,7 +5317,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">createContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -5342,7 +5349,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -5390,7 +5397,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -5406,7 +5413,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericFocusedEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5422,7 +5429,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericMotionEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericMotionEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5438,7 +5445,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericPointerEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5454,7 +5461,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5470,7 +5477,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5486,7 +5493,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEventPreIme</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5502,7 +5509,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyShortcutEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5518,7 +5525,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5534,7 +5541,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchRestoreInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -5550,7 +5557,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchSaveInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -5630,7 +5637,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5646,7 +5653,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5662,7 +5669,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchUnhandledMove</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -5678,7 +5685,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -5742,7 +5749,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">draw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -5771,7 +5778,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findFocus</span>()</nobr>
@@ -5787,7 +5794,7 @@
             final
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findViewById</span>(int arg0)</nobr>
@@ -5803,10 +5810,10 @@
             final
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewWithTag</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">findViewWithTag</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -5822,7 +5829,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewsWithText</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, <a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg1, int arg2)</nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -5838,7 +5845,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">fitSystemWindows</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -5851,7 +5858,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">focusSearch</span>(int arg0)</nobr>
@@ -5915,7 +5922,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.html">Animation</a></nobr>
+            Animation</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getAnimation</span>()</nobr>
@@ -5931,7 +5938,7 @@
             
             
             
-            <a href="/reference/android/os/IBinder.html">IBinder</a></nobr>
+            IBinder</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getApplicationWindowToken</span>()</nobr>
@@ -5947,7 +5954,7 @@
             
             
             
-            <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a></nobr>
+            Drawable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getBackground</span>()</nobr>
@@ -6043,7 +6050,7 @@
             
             
             
-            <a href="/reference/java/lang/CharSequence.html">CharSequence</a></nobr>
+            CharSequence</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContentDescription</span>()</nobr>
@@ -6059,7 +6066,7 @@
             final
             
             
-            <a href="/reference/android/content/Context.html">Context</a></nobr>
+            Context</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContext</span>()</nobr>
@@ -6075,7 +6082,7 @@
             
             
             
-            <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a></nobr>
+            ContextMenu.ContextMenuInfo</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContextMenuInfo</span>()</nobr>
@@ -6123,7 +6130,7 @@
             
             
             
-            <a href="/reference/android/graphics/Bitmap.html">Bitmap</a></nobr>
+            Bitmap</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getDrawingCache</span>(boolean arg0)</nobr>
@@ -6139,7 +6146,7 @@
             
             
             
-            <a href="/reference/android/graphics/Bitmap.html">Bitmap</a></nobr>
+            Bitmap</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getDrawingCache</span>()</nobr>
@@ -6190,7 +6197,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getDrawingRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getDrawingRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6251,7 +6258,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt;</nobr>
+            ArrayList&lt;View&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getFocusables</span>(int arg0)</nobr>
@@ -6270,7 +6277,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getFocusedRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getFocusedRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6286,7 +6293,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getGlobalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0, <a href="/reference/android/graphics/Point.html">Point</a> arg1)</nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0, Point arg1)</nobr>
         
   </td></tr>
 
@@ -6302,7 +6309,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getGlobalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6315,7 +6322,7 @@
             
             
             
-            <a href="/reference/android/os/Handler.html">Handler</a></nobr>
+            Handler</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getHandler</span>()</nobr>
@@ -6350,7 +6357,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getHitRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getHitRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6443,7 +6450,7 @@
             
             
             
-            <a href="/reference/android/view/KeyEvent.DispatcherState.html">KeyEvent.DispatcherState</a></nobr>
+            KeyEvent.DispatcherState</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getKeyDispatcherState</span>()</nobr>
@@ -6475,7 +6482,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutParams</span>()</nobr>
@@ -6542,7 +6549,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getLocalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getLocalVisibleRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6587,7 +6594,7 @@
             
             
             
-            <a href="/reference/android/graphics/Matrix.html">Matrix</a></nobr>
+            Matrix</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMatrix</span>()</nobr>
@@ -6795,7 +6802,7 @@
             
             
             
-            <a href="/reference/android/view/View.OnFocusChangeListener.html">View.OnFocusChangeListener</a></nobr>
+            View.OnFocusChangeListener</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getOnFocusChangeListener</span>()</nobr>
@@ -6891,7 +6898,7 @@
             final
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParent</span>()</nobr>
@@ -6907,7 +6914,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParentForAccessibility</span>()</nobr>
@@ -6955,7 +6962,7 @@
             
             
             
-            <a href="/reference/android/content/res/Resources.html">Resources</a></nobr>
+            Resources</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getResources</span>()</nobr>
@@ -7019,7 +7026,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getRootView</span>()</nobr>
@@ -7275,7 +7282,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>(int arg0)</nobr>
@@ -7291,7 +7298,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>()</nobr>
@@ -7355,7 +7362,7 @@
             
             
             
-            <a href="/reference/android/view/TouchDelegate.html">TouchDelegate</a></nobr>
+            TouchDelegate</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTouchDelegate</span>()</nobr>
@@ -7371,7 +7378,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt;</nobr>
+            ArrayList&lt;View&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTouchables</span>()</nobr>
@@ -7467,7 +7474,7 @@
             
             
             
-            <a href="/reference/android/view/ViewTreeObserver.html">ViewTreeObserver</a></nobr>
+            ViewTreeObserver</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getViewTreeObserver</span>()</nobr>
@@ -7547,7 +7554,7 @@
             
             
             
-            <a href="/reference/android/os/IBinder.html">IBinder</a></nobr>
+            IBinder</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getWindowToken</span>()</nobr>
@@ -7582,7 +7589,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getWindowVisibleDisplayFrame</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getWindowVisibleDisplayFrame</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -7723,10 +7730,10 @@
             
             static
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">inflate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> arg2)</nobr>
+        <span class="sympad">inflate</span>(Context arg0, int arg1, ViewGroup arg2)</nobr>
         
   </td></tr>
 
@@ -7742,7 +7749,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initializeFadingEdge</span>(<a href="/reference/android/content/res/TypedArray.html">TypedArray</a> arg0)</nobr>
+        <span class="sympad">initializeFadingEdge</span>(TypedArray arg0)</nobr>
         
   </td></tr>
 
@@ -7758,7 +7765,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initializeScrollbars</span>(<a href="/reference/android/content/res/TypedArray.html">TypedArray</a> arg0)</nobr>
+        <span class="sympad">initializeScrollbars</span>(TypedArray arg0)</nobr>
         
   </td></tr>
 
@@ -7774,7 +7781,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidate</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">invalidate</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -7822,7 +7829,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -8478,7 +8485,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -8494,7 +8501,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -8523,10 +8530,10 @@
             
             
             
-            <a href="/reference/android/view/inputmethod/InputConnection.html">InputConnection</a></nobr>
+            InputConnection</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateInputConnection</span>(<a href="/reference/android/view/inputmethod/EditorInfo.html">EditorInfo</a> arg0)</nobr>
+        <span class="sympad">onCreateInputConnection</span>(EditorInfo arg0)</nobr>
         
   </td></tr>
 
@@ -8590,7 +8597,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">onDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -8606,7 +8613,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onDrawScrollBars</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">onDrawScrollBars</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -8622,7 +8629,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onFilterTouchEventForSecurity</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onFilterTouchEventForSecurity</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8670,7 +8677,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, <a href="/reference/android/graphics/Rect.html">Rect</a> arg2)</nobr>
+        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, Rect arg2)</nobr>
         
   </td></tr>
 
@@ -8686,7 +8693,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onGenericMotionEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onGenericMotionEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8718,7 +8725,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8734,7 +8741,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInitializeAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8766,7 +8773,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyDown</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8782,7 +8789,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyLongPress</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8798,7 +8805,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg2)</nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
         
   </td></tr>
 
@@ -8814,7 +8821,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyPreIme</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyPreIme</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8830,7 +8837,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyShortcut</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyShortcut</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8846,7 +8853,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyUp</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8910,7 +8917,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onPopulateAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8926,7 +8933,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRestoreInstanceState</span>(<a href="/reference/android/os/Parcelable.html">Parcelable</a> arg0)</nobr>
+        <span class="sympad">onRestoreInstanceState</span>(Parcelable arg0)</nobr>
         
   </td></tr>
 
@@ -8939,7 +8946,7 @@
             
             
             
-            <a href="/reference/android/os/Parcelable.html">Parcelable</a></nobr>
+            Parcelable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">onSaveInstanceState</span>()</nobr>
@@ -9038,7 +9045,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9054,7 +9061,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9070,7 +9077,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">onVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -9150,7 +9157,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">performAccessibilityAction</span>(int arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">performAccessibilityAction</span>(int arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -9246,7 +9253,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">post</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">post</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9262,7 +9269,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postDelayed</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0, long arg1)</nobr>
+        <span class="sympad">postDelayed</span>(Runnable arg0, long arg1)</nobr>
         
   </td></tr>
 
@@ -9374,7 +9381,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postOnAnimation</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">postOnAnimation</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9390,7 +9397,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postOnAnimationDelayed</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0, long arg1)</nobr>
+        <span class="sympad">postOnAnimationDelayed</span>(Runnable arg0, long arg1)</nobr>
         
   </td></tr>
 
@@ -9422,7 +9429,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeCallbacks</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">removeCallbacks</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9486,7 +9493,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestFocus</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -9566,7 +9573,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestRectangleOnScreen</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -9582,7 +9589,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestRectangleOnScreen</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0, boolean arg1)</nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0, boolean arg1)</nobr>
         
   </td></tr>
 
@@ -9630,7 +9637,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">restoreHierarchyState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">restoreHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -9646,7 +9653,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">saveHierarchyState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">saveHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -9662,7 +9669,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">scheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1, long arg2)</nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -9726,7 +9733,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">sendAccessibilityEventUnchecked</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9790,7 +9797,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setAnimation</span>(<a href="/reference/android/view/animation/Animation.html">Animation</a> arg0)</nobr>
+        <span class="sympad">setAnimation</span>(Animation arg0)</nobr>
         
   </td></tr>
 
@@ -9806,7 +9813,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setBackground</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setBackground</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -9838,7 +9845,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setBackgroundDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setBackgroundDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -9918,7 +9925,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setContentDescription</span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg0)</nobr>
+        <span class="sympad">setContentDescription</span>(CharSequence arg0)</nobr>
         
   </td></tr>
 
@@ -10222,7 +10229,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayerType</span>(int arg0, <a href="/reference/android/graphics/Paint.html">Paint</a> arg1)</nobr>
+        <span class="sympad">setLayerType</span>(int arg0, Paint arg1)</nobr>
         
   </td></tr>
 
@@ -10238,7 +10245,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">setLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -10414,7 +10421,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnClickListener</span>(<a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> arg0)</nobr>
+        <span class="sympad">setOnClickListener</span>(View.OnClickListener arg0)</nobr>
         
   </td></tr>
 
@@ -10430,7 +10437,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnCreateContextMenuListener</span>(<a href="/reference/android/view/View.OnCreateContextMenuListener.html">View.OnCreateContextMenuListener</a> arg0)</nobr>
+        <span class="sympad">setOnCreateContextMenuListener</span>(View.OnCreateContextMenuListener arg0)</nobr>
         
   </td></tr>
 
@@ -10462,7 +10469,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnFocusChangeListener</span>(<a href="/reference/android/view/View.OnFocusChangeListener.html">View.OnFocusChangeListener</a> arg0)</nobr>
+        <span class="sympad">setOnFocusChangeListener</span>(View.OnFocusChangeListener arg0)</nobr>
         
   </td></tr>
 
@@ -10510,7 +10517,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnKeyListener</span>(<a href="/reference/android/view/View.OnKeyListener.html">View.OnKeyListener</a> arg0)</nobr>
+        <span class="sympad">setOnKeyListener</span>(View.OnKeyListener arg0)</nobr>
         
   </td></tr>
 
@@ -10526,7 +10533,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnLongClickListener</span>(<a href="/reference/android/view/View.OnLongClickListener.html">View.OnLongClickListener</a> arg0)</nobr>
+        <span class="sympad">setOnLongClickListener</span>(View.OnLongClickListener arg0)</nobr>
         
   </td></tr>
 
@@ -10558,7 +10565,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnTouchListener</span>(<a href="/reference/android/view/View.OnTouchListener.html">View.OnTouchListener</a> arg0)</nobr>
+        <span class="sympad">setOnTouchListener</span>(View.OnTouchListener arg0)</nobr>
         
   </td></tr>
 
@@ -10958,7 +10965,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTag</span>(int arg0, <a href="/reference/java/lang/Object.html">Object</a> arg1)</nobr>
+        <span class="sympad">setTag</span>(int arg0, Object arg1)</nobr>
         
   </td></tr>
 
@@ -10974,7 +10981,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTag</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">setTag</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -11006,7 +11013,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTouchDelegate</span>(<a href="/reference/android/view/TouchDelegate.html">TouchDelegate</a> arg0)</nobr>
+        <span class="sympad">setTouchDelegate</span>(TouchDelegate arg0)</nobr>
         
   </td></tr>
 
@@ -11214,7 +11221,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startAnimation</span>(<a href="/reference/android/view/animation/Animation.html">Animation</a> arg0)</nobr>
+        <span class="sympad">startAnimation</span>(Animation arg0)</nobr>
         
   </td></tr>
 
@@ -11230,7 +11237,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, <a href="/reference/java/lang/Object.html">Object</a> arg2, int arg3)</nobr>
+        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, Object arg2, int arg3)</nobr>
         
   </td></tr>
 
@@ -11246,7 +11253,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11262,7 +11269,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
         
   </td></tr>
 
@@ -11278,7 +11285,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">verifyDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11330,7 +11337,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -11349,7 +11356,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -11368,7 +11375,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -11397,7 +11404,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -11461,7 +11468,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -11532,7 +11539,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/graphics/drawable/Drawable.Callback.html">android.graphics.drawable.Drawable.Callback</a>
+  android.graphics.drawable.Drawable.Callback
 
 <div id="inherited-methods-android.graphics.drawable.Drawable.Callback">
   <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-list"
@@ -11554,7 +11561,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11570,7 +11577,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">scheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1, long arg2)</nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -11586,7 +11593,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
         
   </td></tr>
 
@@ -11606,7 +11613,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/KeyEvent.Callback.html">android.view.KeyEvent.Callback</a>
+  android.view.KeyEvent.Callback
 
 <div id="inherited-methods-android.view.KeyEvent.Callback">
   <div id="inherited-methods-android.view.KeyEvent.Callback-list"
@@ -11628,7 +11635,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyDown</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11644,7 +11651,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyLongPress</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11660,7 +11667,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg2)</nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
         
   </td></tr>
 
@@ -11676,7 +11683,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyUp</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11696,7 +11703,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/ViewManager.html">android.view.ViewManager</a>
+  android.view.ViewManager
 
 <div id="inherited-methods-android.view.ViewManager">
   <div id="inherited-methods-android.view.ViewManager-list"
@@ -11718,7 +11725,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -11734,7 +11741,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11750,7 +11757,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">updateViewLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -11770,7 +11777,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/ViewParent.html">android.view.ViewParent</a>
+  android.view.ViewParent
 
 <div id="inherited-methods-android.view.ViewParent">
   <div id="inherited-methods-android.view.ViewParent-list"
@@ -11792,7 +11799,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">bringChildToFront</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11808,7 +11815,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">childDrawableStateChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11824,7 +11831,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clearChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11840,7 +11847,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">createContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -11853,10 +11860,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusSearch</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -11872,7 +11879,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusableViewAvailable</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11888,7 +11895,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildVisibleRect</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, <a href="/reference/android/graphics/Point.html">Point</a> arg2)</nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
         
   </td></tr>
 
@@ -11901,7 +11908,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParent</span>()</nobr>
@@ -11917,7 +11924,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParentForAccessibility</span>()</nobr>
@@ -11936,7 +11943,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -11949,10 +11956,10 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChildInParent</span>(int[] arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -11984,7 +11991,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">recomputeViewAttributes</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -12000,7 +12007,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1)</nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
         
   </td></tr>
 
@@ -12016,7 +12023,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildRectangleOnScreen</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, boolean arg2)</nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
         
   </td></tr>
 
@@ -12080,7 +12087,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -12096,7 +12103,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestTransparentRegion</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -12112,7 +12119,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">showContextMenuForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -12128,7 +12135,7 @@
             ActionMode</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActionModeForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, ActionMode.Callback arg1)</nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
         
   </td></tr>
 
@@ -12148,7 +12155,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/accessibility/AccessibilityEventSource.html">android.view.accessibility.AccessibilityEventSource</a>
+  android.view.accessibility.AccessibilityEventSource
 
 <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource">
   <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-list"
@@ -12186,7 +12193,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">sendAccessibilityEventUnchecked</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -12244,7 +12251,7 @@
         
       </span>
       <span class="sympad">MapView</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12273,7 +12280,7 @@
         
       </span>
       <span class="sympad">MapView</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12302,7 +12309,7 @@
         
       </span>
       <span class="sympad">MapView</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, int defStyle)</span>
+      <span class="normal">(Context context, AttributeSet attrs, int defStyle)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12331,7 +12338,7 @@
         
       </span>
       <span class="sympad">MapView</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html">GoogleMapOptions</a> options)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/maps/GoogleMapOptions.html">GoogleMapOptions</a> options)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12411,7 +12418,7 @@
         void
       </span>
       <span class="sympad">onCreate</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12581,7 +12588,7 @@
         void
       </span>
       <span class="sympad">onSaveInstanceState</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> outState)</span>
+      <span class="normal">(Bundle outState)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/MapsInitializer.html b/docs/html/reference/com/google/android/gms/maps/MapsInitializer.html
index a7c65ab..a46f71a 100644
--- a/docs/html/reference/com/google/android/gms/maps/MapsInitializer.html
+++ b/docs/html/reference/com/google/android/gms/maps/MapsInitializer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>MapsInitializer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -799,7 +806,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapsInitializer.html#initialize(android.content.Context)">initialize</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/MapsInitializer.html#initialize(android.content.Context)">initialize</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Initializes the Google Maps Android API so that its classes are ready for use.</div>
   
@@ -829,7 +836,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -848,7 +855,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -867,7 +874,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -896,7 +903,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -960,7 +967,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1077,7 +1084,7 @@
         void
       </span>
       <span class="sympad">initialize</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/Projection.html b/docs/html/reference/com/google/android/gms/maps/Projection.html
index d75fd9b..1d0412fc 100644
--- a/docs/html/reference/com/google/android/gms/maps/Projection.html
+++ b/docs/html/reference/com/google/android/gms/maps/Projection.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Projection | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -795,7 +802,7 @@
             <a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/Projection.html#fromScreenLocation(android.graphics.Point)">fromScreenLocation</a></span>(<a href="/reference/android/graphics/Point.html">Point</a> point)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/Projection.html#fromScreenLocation(android.graphics.Point)">fromScreenLocation</a></span>(Point point)</nobr>
         
         <div class="jd-descrdiv">Returns the geographic location that corresponds to a screen location.</div>
   
@@ -829,7 +836,7 @@
             
             
             
-            <a href="/reference/android/graphics/Point.html">Point</a></nobr>
+            Point</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/Projection.html#toScreenLocation(com.google.android.gms.maps.model.LatLng)">toScreenLocation</a></span>(<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a> location)</nobr>
@@ -862,7 +869,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -881,7 +888,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -900,7 +907,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -929,7 +936,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -993,7 +1000,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1110,7 +1117,7 @@
         <a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>
       </span>
       <span class="sympad">fromScreenLocation</span>
-      <span class="normal">(<a href="/reference/android/graphics/Point.html">Point</a> point)</span>
+      <span class="normal">(Point point)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1189,7 +1196,7 @@
          
          
          
-        <a href="/reference/android/graphics/Point.html">Point</a>
+        Point
       </span>
       <span class="sympad">toScreenLocation</span>
       <span class="normal">(<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a> location)</span>
diff --git a/docs/html/reference/com/google/android/gms/maps/SupportMapFragment.html b/docs/html/reference/com/google/android/gms/maps/SupportMapFragment.html
index 1750f2c..773b7f6 100644
--- a/docs/html/reference/com/google/android/gms/maps/SupportMapFragment.html
+++ b/docs/html/reference/com/google/android/gms/maps/SupportMapFragment.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>SupportMapFragment | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -726,7 +733,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -944,7 +951,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onActivityCreated(android.os.Bundle)">onActivityCreated</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onActivityCreated(android.os.Bundle)">onActivityCreated</a></span>(Bundle savedInstanceState)</nobr>
         
   </td></tr>
 
@@ -960,7 +967,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onAttach(android.app.Activity)">onAttach</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> activity)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onAttach(android.app.Activity)">onAttach</a></span>(Activity activity)</nobr>
         
   </td></tr>
 
@@ -976,7 +983,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onCreate(android.os.Bundle)">onCreate</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onCreate(android.os.Bundle)">onCreate</a></span>(Bundle savedInstanceState)</nobr>
         
   </td></tr>
 
@@ -989,10 +996,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)">onCreateView</a></span>(<a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a> inflater, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> container, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)">onCreateView</a></span>(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)</nobr>
         
   </td></tr>
 
@@ -1040,7 +1047,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle)">onInflate</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> activity, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle)">onInflate</a></span>(Activity activity, AttributeSet attrs, Bundle savedInstanceState)</nobr>
         
         <div class="jd-descrdiv">Parse attributes during inflation from a view hierarchy into the arguments we handle.</div>
   
@@ -1106,7 +1113,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onSaveInstanceState(android.os.Bundle)">onSaveInstanceState</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> outState)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#onSaveInstanceState(android.os.Bundle)">onSaveInstanceState</a></span>(Bundle outState)</nobr>
         
   </td></tr>
 
@@ -1122,7 +1129,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#setArguments(android.os.Bundle)">setArguments</a></span>(<a href="/reference/android/os/Bundle.html">Bundle</a> args)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/SupportMapFragment.html#setArguments(android.os.Bundle)">setArguments</a></span>(Bundle args)</nobr>
         
   </td></tr>
 
@@ -1172,7 +1179,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dump</span>(<a href="/reference/java/lang/String.html">String</a> arg0, <a href="/reference/java/io/FileDescriptor.html">FileDescriptor</a> arg1, <a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg2, <a href="/reference/java/lang/String.html">String[]</a> arg3)</nobr>
+        <span class="sympad">dump</span>(String arg0, FileDescriptor arg1, PrintWriter arg2, String[] arg3)</nobr>
         
   </td></tr>
 
@@ -1188,7 +1195,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1217,7 +1224,7 @@
             final
             
             
-            <a href="/reference/android/os/Bundle.html">Bundle</a></nobr>
+            Bundle</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getArguments</span>()</nobr>
@@ -1281,10 +1288,10 @@
             
             
             
-            <a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a></nobr>
+            LayoutInflater</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getLayoutInflater</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">getLayoutInflater</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -1329,7 +1336,7 @@
             final
             
             
-            <a href="/reference/android/content/res/Resources.html">Resources</a></nobr>
+            Resources</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getResources</span>()</nobr>
@@ -1361,7 +1368,7 @@
             final
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getString</span>(int arg0)</nobr>
@@ -1377,10 +1384,10 @@
             final
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getString</span>(int arg0, <a href="/reference/java/lang/Object.html">Object...</a> arg1)</nobr>
+        <span class="sympad">getString</span>(int arg0, Object... arg1)</nobr>
         
   </td></tr>
 
@@ -1393,7 +1400,7 @@
             final
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>()</nobr>
@@ -1441,7 +1448,7 @@
             final
             
             
-            <a href="/reference/java/lang/CharSequence.html">CharSequence</a></nobr>
+            CharSequence</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getText</span>(int arg0)</nobr>
@@ -1473,7 +1480,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getView</span>()</nobr>
@@ -1524,7 +1531,7 @@
             Fragment</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">instantiate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, <a href="/reference/java/lang/String.html">String</a> arg1)</nobr>
+        <span class="sympad">instantiate</span>(Context arg0, String arg1)</nobr>
         
   </td></tr>
 
@@ -1540,7 +1547,7 @@
             Fragment</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">instantiate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, <a href="/reference/java/lang/String.html">String</a> arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">instantiate</span>(Context arg0, String arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -1684,7 +1691,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onActivityCreated</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onActivityCreated</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -1700,7 +1707,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onActivityResult</span>(int arg0, int arg1, <a href="/reference/android/content/Intent.html">Intent</a> arg2)</nobr>
+        <span class="sympad">onActivityResult</span>(int arg0, int arg1, Intent arg2)</nobr>
         
   </td></tr>
 
@@ -1716,7 +1723,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onAttach</span>(<a href="/reference/android/app/Activity.html">Activity</a> arg0)</nobr>
+        <span class="sympad">onAttach</span>(Activity arg0)</nobr>
         
   </td></tr>
 
@@ -1732,7 +1739,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -1748,7 +1755,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onContextItemSelected</span>(<a href="/reference/android/view/MenuItem.html">MenuItem</a> arg0)</nobr>
+        <span class="sympad">onContextItemSelected</span>(MenuItem arg0)</nobr>
         
   </td></tr>
 
@@ -1764,7 +1771,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreate</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onCreate</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -1777,7 +1784,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.html">Animation</a></nobr>
+            Animation</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">onCreateAnimation</span>(int arg0, boolean arg1, int arg2)</nobr>
@@ -1796,7 +1803,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a> arg2)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0, View arg1, ContextMenu.ContextMenuInfo arg2)</nobr>
         
   </td></tr>
 
@@ -1812,7 +1819,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateOptionsMenu</span>(<a href="/reference/android/view/Menu.html">Menu</a> arg0, <a href="/reference/android/view/MenuInflater.html">MenuInflater</a> arg1)</nobr>
+        <span class="sympad">onCreateOptionsMenu</span>(Menu arg0, MenuInflater arg1)</nobr>
         
   </td></tr>
 
@@ -1825,10 +1832,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateView</span>(<a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a> arg0, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">onCreateView</span>(LayoutInflater arg0, ViewGroup arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -1924,7 +1931,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInflate</span>(<a href="/reference/android/app/Activity.html">Activity</a> arg0, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg1, <a href="/reference/android/os/Bundle.html">Bundle</a> arg2)</nobr>
+        <span class="sympad">onInflate</span>(Activity arg0, AttributeSet arg1, Bundle arg2)</nobr>
         
   </td></tr>
 
@@ -1956,7 +1963,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onOptionsItemSelected</span>(<a href="/reference/android/view/MenuItem.html">MenuItem</a> arg0)</nobr>
+        <span class="sympad">onOptionsItemSelected</span>(MenuItem arg0)</nobr>
         
   </td></tr>
 
@@ -1972,7 +1979,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onOptionsMenuClosed</span>(<a href="/reference/android/view/Menu.html">Menu</a> arg0)</nobr>
+        <span class="sympad">onOptionsMenuClosed</span>(Menu arg0)</nobr>
         
   </td></tr>
 
@@ -2004,7 +2011,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onPrepareOptionsMenu</span>(<a href="/reference/android/view/Menu.html">Menu</a> arg0)</nobr>
+        <span class="sympad">onPrepareOptionsMenu</span>(Menu arg0)</nobr>
         
   </td></tr>
 
@@ -2036,7 +2043,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onSaveInstanceState</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onSaveInstanceState</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -2084,7 +2091,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onViewCreated</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">onViewCreated</span>(View arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -2100,7 +2107,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onViewStateRestored</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">onViewStateRestored</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -2116,7 +2123,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">registerForContextMenu</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">registerForContextMenu</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2132,7 +2139,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setArguments</span>(<a href="/reference/android/os/Bundle.html">Bundle</a> arg0)</nobr>
+        <span class="sympad">setArguments</span>(Bundle arg0)</nobr>
         
   </td></tr>
 
@@ -2244,7 +2251,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActivity</span>(<a href="/reference/android/content/Intent.html">Intent</a> arg0)</nobr>
+        <span class="sympad">startActivity</span>(Intent arg0)</nobr>
         
   </td></tr>
 
@@ -2260,7 +2267,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActivityForResult</span>(<a href="/reference/android/content/Intent.html">Intent</a> arg0, int arg1)</nobr>
+        <span class="sympad">startActivityForResult</span>(Intent arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2273,7 +2280,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2292,7 +2299,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unregisterForContextMenu</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">unregisterForContextMenu</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2312,7 +2319,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -2331,7 +2338,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -2350,7 +2357,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -2379,7 +2386,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -2443,7 +2450,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2514,7 +2521,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/content/ComponentCallbacks.html">android.content.ComponentCallbacks</a>
+  android.content.ComponentCallbacks
 
 <div id="inherited-methods-android.content.ComponentCallbacks">
   <div id="inherited-methods-android.content.ComponentCallbacks-list"
@@ -2536,7 +2543,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -2572,7 +2579,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/View.OnCreateContextMenuListener.html">android.view.View.OnCreateContextMenuListener</a>
+  android.view.View.OnCreateContextMenuListener
 
 <div id="inherited-methods-android.view.View.OnCreateContextMenuListener">
   <div id="inherited-methods-android.view.View.OnCreateContextMenuListener-list"
@@ -2594,7 +2601,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a> arg2)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0, View arg1, ContextMenu.ContextMenuInfo arg2)</nobr>
         
   </td></tr>
 
@@ -2797,7 +2804,7 @@
         void
       </span>
       <span class="sympad">onActivityCreated</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2826,7 +2833,7 @@
         void
       </span>
       <span class="sympad">onAttach</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> activity)</span>
+      <span class="normal">(Activity activity)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2855,7 +2862,7 @@
         void
       </span>
       <span class="sympad">onCreate</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2881,10 +2888,10 @@
          
          
          
-        <a href="/reference/android/view/View.html">View</a>
+        View
       </span>
       <span class="sympad">onCreateView</span>
-      <span class="normal">(<a href="/reference/android/view/LayoutInflater.html">LayoutInflater</a> inflater, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> container, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2971,7 +2978,7 @@
         void
       </span>
       <span class="sympad">onInflate</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> activity, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs, <a href="/reference/android/os/Bundle.html">Bundle</a> savedInstanceState)</span>
+      <span class="normal">(Activity activity, AttributeSet attrs, Bundle savedInstanceState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3088,7 +3095,7 @@
         void
       </span>
       <span class="sympad">onSaveInstanceState</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> outState)</span>
+      <span class="normal">(Bundle outState)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3117,7 +3124,7 @@
         void
       </span>
       <span class="sympad">setArguments</span>
-      <span class="normal">(<a href="/reference/android/os/Bundle.html">Bundle</a> args)</span>
+      <span class="normal">(Bundle args)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/UiSettings.html b/docs/html/reference/com/google/android/gms/maps/UiSettings.html
index ebb7d92b..2b3aec5 100644
--- a/docs/html/reference/com/google/android/gms/maps/UiSettings.html
+++ b/docs/html/reference/com/google/android/gms/maps/UiSettings.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>UiSettings | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1076,7 +1083,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1095,7 +1102,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1114,7 +1121,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1143,7 +1150,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1207,7 +1214,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptor.html b/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptor.html
index f96147c..7f3c1e6 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptor.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptor.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>BitmapDescriptor | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -675,7 +682,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -695,7 +702,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -805,7 +812,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -824,7 +831,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -843,7 +850,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -872,7 +879,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -936,7 +943,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html b/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html
index 213428c..226c8d3 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>BitmapDescriptorFactory | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -923,7 +930,7 @@
             <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromAsset(java.lang.String)">fromAsset</a></span>(<a href="/reference/java/lang/String.html">String</a> assetName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromAsset(java.lang.String)">fromAsset</a></span>(String assetName)</nobr>
         
         <div class="jd-descrdiv">Creates a <code><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a></code> using the name of an image in the assets directory.</div>
   
@@ -941,7 +948,7 @@
             <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromBitmap(android.graphics.Bitmap)">fromBitmap</a></span>(<a href="/reference/android/graphics/Bitmap.html">Bitmap</a> image)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromBitmap(android.graphics.Bitmap)">fromBitmap</a></span>(Bitmap image)</nobr>
         
         <div class="jd-descrdiv">Creates a bitmap descriptor from a given image.</div>
   
@@ -959,7 +966,7 @@
             <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromFile(java.lang.String)">fromFile</a></span>(<a href="/reference/java/lang/String.html">String</a> fileName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromFile(java.lang.String)">fromFile</a></span>(String fileName)</nobr>
         
         <div class="jd-descrdiv">Creates a <code><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a></code> using the name of an image file located in the internal
  storage.</div>
@@ -978,7 +985,7 @@
             <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromPath(java.lang.String)">fromPath</a></span>(<a href="/reference/java/lang/String.html">String</a> absolutePath)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromPath(java.lang.String)">fromPath</a></span>(String absolutePath)</nobr>
         
         <div class="jd-descrdiv">Creates a bitmap descriptor from an absolute file path.</div>
   
@@ -1026,7 +1033,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1045,7 +1052,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1064,7 +1071,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1093,7 +1100,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1157,7 +1164,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1720,7 +1727,7 @@
         <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a>
       </span>
       <span class="sympad">fromAsset</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> assetName)</span>
+      <span class="normal">(String assetName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1764,7 +1771,7 @@
         <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a>
       </span>
       <span class="sympad">fromBitmap</span>
-      <span class="normal">(<a href="/reference/android/graphics/Bitmap.html">Bitmap</a> image)</span>
+      <span class="normal">(Bitmap image)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1794,7 +1801,7 @@
         <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a>
       </span>
       <span class="sympad">fromFile</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> fileName)</span>
+      <span class="normal">(String fileName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1823,7 +1830,7 @@
   </div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">See Also</h5>
-      <ul class="nolist"><li><a href="/guide/topics/data/data-storage.html#filesInternal">
+      <ul class="nolist"><li><a href="http://developer.android.com/guide/topics/data/data-storage.html#filesInternal">
  Using the Internal Storage</a></li>
       </ul>
   </div>
@@ -1845,7 +1852,7 @@
         <a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a>
       </span>
       <span class="sympad">fromPath</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> absolutePath)</span>
+      <span class="normal">(String absolutePath)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.Builder.html b/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.Builder.html
index d54bcf6..7b9940b 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.Builder.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>CameraPosition.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -940,7 +947,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -959,7 +966,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -978,7 +985,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1007,7 +1014,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1071,7 +1078,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.html b/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.html
index b96d938..e9a513b 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/CameraPosition.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>CameraPosition | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -699,7 +706,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -708,7 +715,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -724,7 +731,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1021,7 +1028,7 @@
             <a href="/reference/com/google/android/gms/maps/model/CameraPosition.html">CameraPosition</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#createFromAttributes(android.content.Context, android.util.AttributeSet)">createFromAttributes</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#createFromAttributes(android.content.Context, android.util.AttributeSet)">createFromAttributes</a></span>(Context context, AttributeSet attrs)</nobr>
         
         <div class="jd-descrdiv">Creates a CameraPostion from the attribute set
 </div>
@@ -1056,7 +1063,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> o)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#equals(java.lang.Object)">equals</a></span>(Object o)</nobr>
         
   </td></tr>
 
@@ -1103,7 +1110,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#toString()">toString</a></span>()</nobr>
@@ -1122,7 +1129,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/CameraPosition.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1150,7 +1157,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1169,7 +1176,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1188,7 +1195,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1217,7 +1224,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1281,7 +1288,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1352,7 +1359,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1390,7 +1397,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1643,11 +1650,11 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/NullPointerException.html">NullPointerException</a></td>
+            <th>NullPointerException</td>
             <td>if <code>target</code> is null</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if <code>tilt</code> is outside the range of 0 degress inclusive
              to 90 degrees inclusive.
 </td>
@@ -1745,7 +1752,7 @@
         <a href="/reference/com/google/android/gms/maps/model/CameraPosition.html">CameraPosition</a>
       </span>
       <span class="sympad">createFromAttributes</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1804,7 +1811,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> o)</span>
+      <span class="normal">(Object o)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1907,7 +1914,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -1939,7 +1946,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/Circle.html b/docs/html/reference/com/google/android/gms/maps/model/Circle.html
index 1c99a24..1bd7cf0 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/Circle.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/Circle.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Circle | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -750,11 +757,11 @@
  The default zIndex is 0.</dd>
  <dt>Visibility</dt>
  <dd>Indicates if the circle is visible or invisible, i.e., whether it is drawn on the map. An
- invisible polygon is not drawn, but retains all of its other properties. The default is
+ invisible circle is not drawn, but retains all of its other properties. The default is
  <code>true</code>, i.e., visible.</dd>
  </dl>
 
- <p>Methods that modify a Polygon must be called on the main thread. If not, an
+ <p>Methods that modify a Circle must be called on the main thread. If not, an
  <code><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></code> will be thrown at runtime.</p>
  <h3>Example</h3>
 
@@ -882,12 +889,12 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Circle.html#getId()">getId</a></span>()</nobr>
         
-        <div class="jd-descrdiv">Returns this circle's id.</div>
+        <div class="jd-descrdiv">Gets this circle's id.</div>
   
   </td></tr>
 
@@ -1149,7 +1156,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1168,7 +1175,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1187,7 +1194,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1216,7 +1223,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1280,7 +1287,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1462,7 +1469,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -1475,7 +1482,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Returns this circle's id.
+  <div class="jd-tagdata jd-tagdescr"><p>Gets this circle's id.  The id will be unique amongst all Circles on a map.
 </p></div>
 
     </div>
@@ -1721,7 +1728,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/NullPointerException.html">NullPointerException</a></td>
+            <th>NullPointerException</td>
             <td>if center is null
 </td>
         </tr>
@@ -1814,7 +1821,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if radius is negative
 </td>
         </tr>
@@ -1909,7 +1916,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if width is negative
 </td>
         </tr>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/CircleOptions.html b/docs/html/reference/com/google/android/gms/maps/model/CircleOptions.html
index 0fde34b..8e8dfbd 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/CircleOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/CircleOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>CircleOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1181,7 +1188,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1200,7 +1207,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1219,7 +1226,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1248,7 +1255,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1312,7 +1319,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1383,7 +1390,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1421,7 +1428,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
diff --git a/docs/html/reference/com/google/android/gms/maps/model/GroundOverlay.html b/docs/html/reference/com/google/android/gms/maps/model/GroundOverlay.html
index 9e0556e..2f1af32 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/GroundOverlay.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/GroundOverlay.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GroundOverlay | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -849,7 +856,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/GroundOverlay.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> other)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/GroundOverlay.html#equals(java.lang.Object)">equals</a></span>(Object other)</nobr>
         
   </td></tr>
 
@@ -916,7 +923,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/GroundOverlay.html#getId()">getId</a></span>()</nobr>
@@ -1218,7 +1225,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1237,7 +1244,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1256,7 +1263,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1285,7 +1292,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1349,7 +1356,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1466,7 +1473,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> other)</span>
+      <span class="normal">(Object other)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1594,7 +1601,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -1607,12 +1614,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Gets this ground overlay's id.
- <p>
- When a map is restored from a <code><a href="/reference/android/os/Bundle.html">Bundle</a></code>, ground overlays that were on that
- map are also restored. However, those ground overlays will then be represented by different
- <code>GroundOverlay</code> objects. A ground overlay's id can be used to retrieve the new
- instance of a <code>GroundOverlay</code> object after such restoration.</p></div>
+  <div class="jd-tagdata jd-tagdescr"><p>Gets this ground overlay's id.  The id will be unique amongst all GroundOverlays on a map.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
       <ul class="nolist"><li>this ground overlay's id.
diff --git a/docs/html/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html b/docs/html/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html
index 25209e9..afadaf9 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>GroundOverlayOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -699,7 +706,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -708,7 +715,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -724,7 +731,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1289,7 +1296,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1335,7 +1342,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1354,7 +1361,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1373,7 +1380,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1402,7 +1409,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1466,7 +1473,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1537,7 +1544,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1575,7 +1582,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2365,15 +2372,15 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if anchor is null</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if width or height are negative</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the position was already set using
              <code><a href="/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html#positionFromBounds(com.google.android.gms.maps.model.LatLngBounds)">positionFromBounds(LatLngBounds)</a></code>
 </td>
@@ -2437,15 +2444,15 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if anchor is null</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if width is negative</td>
         </tr>  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the position was already set using
              <code><a href="/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html#positionFromBounds(com.google.android.gms.maps.model.LatLngBounds)">positionFromBounds(LatLngBounds)</a></code>
 </td>
@@ -2499,7 +2506,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if the position was already set using
              <code><a href="/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html#position(com.google.android.gms.maps.model.LatLng, float)">position(LatLng, float)</a></code> or <code><a href="/reference/com/google/android/gms/maps/model/GroundOverlayOptions.html#position(com.google.android.gms.maps.model.LatLng, float, float)">position(LatLng, float, float)</a></code>
 </td>
@@ -2555,7 +2562,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the transparency is outside the range [0..1].
 </td>
         </tr>
@@ -2613,7 +2620,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/LatLng.html b/docs/html/reference/com/google/android/gms/maps/model/LatLng.html
index 0fbd2d2..f01bba5 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/LatLng.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/LatLng.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LatLng | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -949,7 +956,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLng.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> o)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLng.html#equals(java.lang.Object)">equals</a></span>(Object o)</nobr>
         
         <div class="jd-descrdiv">Tests if this <code><a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a></code> is equal to another.</div>
   
@@ -980,7 +987,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLng.html#toString()">toString</a></span>()</nobr>
@@ -999,7 +1006,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLng.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLng.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1027,7 +1034,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1046,7 +1053,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1065,7 +1072,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1094,7 +1101,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1158,7 +1165,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1229,7 +1236,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1267,7 +1274,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1505,7 +1512,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> o)</span>
+      <span class="normal">(Object o)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1565,7 +1572,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -1597,7 +1604,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html b/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html
index eafb4d9..cffce26 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LatLngBounds.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -868,7 +875,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -887,7 +894,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -906,7 +913,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -935,7 +942,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -999,7 +1006,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1167,7 +1174,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalStateException.html">IllegalStateException</a></td>
+            <th>IllegalStateException</td>
             <td>if no points have been included.
 </td>
         </tr>
@@ -1205,10 +1212,10 @@
  way to include this point.
  <p>
  More precisely, it will consider extending the bounds both in the eastward and westward
- directions (one of which may wrap around the world) and choose the smaller of the two. In
- the case that both directions result in a LatLngBounds of the same size, this will extend
- it in the eastward direction. For example, adding points (0, -179) and (1, 179) will
- create a bound crossing the 180 longitude.</p></div>
+ directions (one of which may cross the antimeridian) and choose the smaller of the two.
+ In the case that both directions result in a LatLngBounds of the same size, this will
+ extend it in the eastward direction. For example, adding points (0, -179) and (1, 179)
+ will create a bound crossing the 180 longitude.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Parameters</h5>
       <table class="jd-tagtable">
diff --git a/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.html b/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.html
index 5322c91..f8c1751 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/LatLngBounds.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>LatLngBounds | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -699,7 +706,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -708,7 +715,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -724,7 +731,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1008,7 +1015,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLngBounds.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> o)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLngBounds.html#equals(java.lang.Object)">equals</a></span>(Object o)</nobr>
         
   </td></tr>
 
@@ -1021,6 +1028,24 @@
             
             
             
+            <a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLngBounds.html#getCenter()">getCenter</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Returns the center of this LatLngBounds.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -1030,7 +1055,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1049,14 +1074,14 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLngBounds.html#toString()">toString</a></span>()</nobr>
@@ -1065,7 +1090,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1075,7 +1100,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLngBounds.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/LatLngBounds.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1103,7 +1128,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1122,7 +1147,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1141,7 +1166,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1170,7 +1195,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1234,7 +1259,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1305,7 +1330,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1343,7 +1368,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1529,7 +1554,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if the latitude of the northeast corner is below the
              latitude of the southwest corner.
 </td>
@@ -1670,7 +1695,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> o)</span>
+      <span class="normal">(Object o)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1686,6 +1711,43 @@
 </div>
 
 
+<A NAME="getCenter()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        <a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>
+      </span>
+      <span class="sympad">getCenter</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Returns the center of this LatLngBounds. The center is simply the average of the coordinates
+ (taking into account if it crosses the antimeridian). This is approximately the geographical
+ center (it would be exact if the Earth were a perfect sphere).  It will not necessarily be
+ the center of the rectangle as drawn on the map due to the Mercator projection.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>A <code><a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a></code> that is the center of the LatLngBounds.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="hashCode()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1743,9 +1805,9 @@
  extra point.
  <p>
  In particular, it will consider extending the bounds both in the eastward and westward
- directions (one of which may wrap around the world) and choose the smaller of the two. In the
- case that both directions result in a LatLngBounds of the same size, this will extend it in
- the eastward direction.</p></div>
+ directions (one of which may cross the antimeridian) and choose the smaller of the two. In
+ the case that both directions result in a LatLngBounds of the same size, this will extend it
+ in the eastward direction.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Parameters</h5>
       <table class="jd-tagtable">
@@ -1775,7 +1837,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -1807,7 +1869,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/Marker.html b/docs/html/reference/com/google/android/gms/maps/model/Marker.html
index c5766ca..53503fb 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/Marker.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/Marker.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Marker | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -750,6 +757,18 @@
  <dt>Visibility</dt>
  <dd>By default, the marker is visible. To make the marker invisible, set this property to
  <code>false</code>. You can change this value at any time.</dd>
+ <dt>Flat or Billboard</dt>
+ <dd>If the marker is flat against the map, it will remain stuck to the map as the camera rotates
+ and tilts but will still remain the same size as the camera zooms, unlike a
+ <code><a href="/reference/com/google/android/gms/maps/model/GroundOverlay.html">GroundOverlay</a></code>. If the marker is a billboard, it will always be drawn facing the camera
+ and will rotate and tilt with the camera.  The default is a billboard (<code>false</code>)</dd>
+ <dt>Rotation</dt>
+ <dd>The rotation of the marker in degrees clockwise about the marker's anchor point. The
+ axis of rotation is perpendicular to the marker. A rotation of 0 corresponds to the default
+ position of the marker. When the marker is flat on the map, the default position is North
+ aligned and the rotation is such that the marker always remains flat on the map. When the
+ marker is a billboard, the default position is pointing up and the rotation is such that the
+ marker is always facing the camera. The default value is 0.</dd>
  </dl>
  <h3>Example</h3>
 
@@ -836,7 +855,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> other)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#equals(java.lang.Object)">equals</a></span>(Object other)</nobr>
         
   </td></tr>
 
@@ -849,7 +868,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#getId()">getId</a></span>()</nobr>
@@ -885,12 +904,12 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            float</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#getSnippet()">getSnippet</a></span>()</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#getRotation()">getRotation</a></span>()</nobr>
         
-        <div class="jd-descrdiv">Gets the snippet of the marker.</div>
+        <div class="jd-descrdiv">Gets the rotation of the marker.</div>
   
   </td></tr>
 
@@ -903,7 +922,25 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#getSnippet()">getSnippet</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Gets the snippet of the marker.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#getTitle()">getTitle</a></span>()</nobr>
@@ -914,7 +951,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -930,7 +967,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -948,7 +985,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -966,6 +1003,24 @@
 
 
 	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#isFlat()">isFlat</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Gets the flat setting of the Marker.</div>
+  
+  </td></tr>
+
+
+	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1064,6 +1119,25 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setFlat(boolean)">setFlat</a></span>(boolean flat)</nobr>
+        
+        <div class="jd-descrdiv">Sets whether this marker should be flat against the map <code>true</code> or a billboard facing
+ the camera <code>false</code>.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setIcon(com.google.android.gms.maps.model.BitmapDescriptor)">setIcon</a></span>(<a href="/reference/com/google/android/gms/maps/model/BitmapDescriptor.html">BitmapDescriptor</a> icon)</nobr>
         
         <div class="jd-descrdiv">Sets the icon for the marker.</div>
@@ -1072,6 +1146,25 @@
 
 
 	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setInfoWindowAnchor(float, float)">setInfoWindowAnchor</a></span>(float anchorU, float anchorV)</nobr>
+        
+        <div class="jd-descrdiv">Specifies the point in the marker image at which to anchor the info window when it is
+ displayed.</div>
+  
+  </td></tr>
+
+
+	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1100,9 +1193,9 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setSnippet(java.lang.String)">setSnippet</a></span>(<a href="/reference/java/lang/String.html">String</a> snippet)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setRotation(float)">setRotation</a></span>(float rotation)</nobr>
         
-        <div class="jd-descrdiv">Sets the snippet of the marker.</div>
+        <div class="jd-descrdiv">Sets the rotation of the marker in degrees clockwise about the marker's anchor point.</div>
   
   </td></tr>
 
@@ -1118,7 +1211,25 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setTitle(java.lang.String)">setTitle</a></span>(<a href="/reference/java/lang/String.html">String</a> title)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setSnippet(java.lang.String)">setSnippet</a></span>(String snippet)</nobr>
+        
+        <div class="jd-descrdiv">Sets the snippet of the marker.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Marker.html#setTitle(java.lang.String)">setTitle</a></span>(String title)</nobr>
         
         <div class="jd-descrdiv">Sets the title of the marker.</div>
   
@@ -1126,7 +1237,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1144,7 +1255,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1184,7 +1295,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1203,7 +1314,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1222,7 +1333,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1251,7 +1362,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1315,7 +1426,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1432,7 +1543,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> other)</span>
+      <span class="normal">(Object other)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1458,7 +1569,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -1471,12 +1582,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Gets this marker's id.
- <p>
- When a map is restored from a <code><a href="/reference/android/os/Bundle.html">Bundle</a></code>, markers that were on that map are
- also restored. However, those markers will then be represented by different <code>Marker</code>
- objects. A marker's id can be used to retrieve the new instance of a Marker object after
- such restoration.</p></div>
+  <div class="jd-tagdata jd-tagdescr"><p>Gets this marker's id. The id will be unique amongst all Markers on a map.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
       <ul class="nolist"><li>this marker's id.
@@ -1521,6 +1627,40 @@
 </div>
 
 
+<A NAME="getRotation()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        float
+      </span>
+      <span class="sympad">getRotation</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Gets the rotation of the marker.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the rotation of the marker in degrees clockwise from the default position.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="getSnippet()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1531,7 +1671,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getSnippet</span>
       <span class="normal">()</span>
@@ -1565,7 +1705,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTitle</span>
       <span class="normal">()</span>
@@ -1685,6 +1825,41 @@
 </div>
 
 
+<A NAME="isFlat()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        boolean
+      </span>
+      <span class="sympad">isFlat</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Gets the flat setting of the Marker.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li><code>true</code> if the marker is flat against the map; <code>false</code> if the marker
+ should face the camera.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="isInfoWindowShown()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1879,6 +2054,37 @@
 </div>
 
 
+<A NAME="setFlat(boolean)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">setFlat</span>
+      <span class="normal">(boolean flat)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets whether this marker should be flat against the map <code>true</code> or a billboard facing
+ the camera <code>false</code>.
+</p></div>
+
+    </div>
+</div>
+
+
 <A NAME="setIcon(com.google.android.gms.maps.model.BitmapDescriptor)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1918,6 +2124,54 @@
 </div>
 
 
+<A NAME="setInfoWindowAnchor(float, float)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">setInfoWindowAnchor</span>
+      <span class="normal">(float anchorU, float anchorV)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Specifies the point in the marker image at which to anchor the info window when it is
+ displayed. This is specified in the same coordinate system as the anchor. See
+ <code><a href="/reference/com/google/android/gms/maps/model/Marker.html#setAnchor(float, float)">setAnchor(float, float)</a></code> for more details.  The default is the top middle of the
+ image.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>anchorU</td>
+          <td>u-coordinate of the info window anchor, as a ratio of the image width (in the
+        range [0, 1])</td>
+        </tr>
+        <tr>
+          <th>anchorV</td>
+          <td>v-coordinate of the info window anchor, as a ratio of the image height (in the
+        range [0, 1])
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="setPosition(com.google.android.gms.maps.model.LatLng)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1948,6 +2202,38 @@
 </div>
 
 
+<A NAME="setRotation(float)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">setRotation</span>
+      <span class="normal">(float rotation)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets the rotation of the marker in degrees clockwise about the marker's anchor point. The
+ axis of rotation is perpendicular to the marker. A rotation of 0 corresponds to the default
+ position of the marker.
+</p></div>
+
+    </div>
+</div>
+
+
 <A NAME="setSnippet(java.lang.String)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1961,7 +2247,7 @@
         void
       </span>
       <span class="sympad">setSnippet</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> snippet)</span>
+      <span class="normal">(String snippet)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1991,7 +2277,7 @@
         void
       </span>
       <span class="sympad">setTitle</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> title)</span>
+      <span class="normal">(String title)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2067,7 +2353,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/IllegalArgumentException.html">IllegalArgumentException</a></td>
+            <th>IllegalArgumentException</td>
             <td>if <code>marker</code> is not on this map
 </td>
         </tr>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/MarkerOptions.html b/docs/html/reference/com/google/android/gms/maps/model/MarkerOptions.html
index 68b9bb5..bfbca3f 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/MarkerOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/MarkerOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>MarkerOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -967,6 +974,25 @@
             
             
             
+            <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#flat(boolean)">flat</a></span>(boolean flat)</nobr>
+        
+        <div class="jd-descrdiv">Sets whether this marker should be flat against the map <code>true</code> or a billboard facing
+ the camera <code>false</code>.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
             float</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -978,7 +1004,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -996,7 +1022,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1014,6 +1040,24 @@
 
 
 	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#getInfoWindowAnchorU()">getInfoWindowAnchorU</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Horizontal distance, normalized to [0, 1], of the info window anchor from the left edge.</div>
+  
+  </td></tr>
+
+
+	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1021,6 +1065,24 @@
             
             
             
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#getInfoWindowAnchorV()">getInfoWindowAnchorV</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Vertical distance, normalized to [0, 1], of the info window anchor from the top edge.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
             <a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -1032,6 +1094,24 @@
 
 
 	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#getRotation()">getRotation</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Gets the rotation set for this MarkerOptions object.</div>
+  
+  </td></tr>
+
+
+	 
     <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1039,7 +1119,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#getSnippet()">getSnippet</a></span>()</nobr>
@@ -1057,7 +1137,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#getTitle()">getTitle</a></span>()</nobr>
@@ -1093,6 +1173,24 @@
             
             
             
+            <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#infoWindowAnchor(float, float)">infoWindowAnchor</a></span>(float u, float v)</nobr>
+        
+        <div class="jd-descrdiv">Specifies the anchor point of the info window on the marker image.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
@@ -1104,6 +1202,24 @@
 
 
 	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#isFlat()">isFlat</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Gets the flat setting for this MarkerOptions object.</div>
+  
+  </td></tr>
+
+
+	 
     <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
@@ -1150,9 +1266,9 @@
             <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#snippet(java.lang.String)">snippet</a></span>(<a href="/reference/java/lang/String.html">String</a> snippet)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#rotation(float)">rotation</a></span>(float rotation)</nobr>
         
-        <div class="jd-descrdiv">Sets the snippet for the marker.</div>
+        <div class="jd-descrdiv">Sets the rotation of the marker in degrees clockwise about the marker's anchor point.</div>
   
   </td></tr>
 
@@ -1168,7 +1284,25 @@
             <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#title(java.lang.String)">title</a></span>(<a href="/reference/java/lang/String.html">String</a> title)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#snippet(java.lang.String)">snippet</a></span>(String snippet)</nobr>
+        
+        <div class="jd-descrdiv">Sets the snippet for the marker.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#title(java.lang.String)">title</a></span>(String title)</nobr>
         
         <div class="jd-descrdiv">Sets the title for the marker.</div>
   
@@ -1176,7 +1310,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1194,7 +1328,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1204,7 +1338,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1232,7 +1366,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1251,7 +1385,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1270,7 +1404,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1299,7 +1433,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1363,7 +1497,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1434,7 +1568,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1472,7 +1606,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1734,6 +1868,44 @@
 </div>
 
 
+<A NAME="flat(boolean)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a>
+      </span>
+      <span class="sympad">flat</span>
+      <span class="normal">(boolean flat)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets whether this marker should be flat against the map <code>true</code> or a billboard facing
+ the camera <code>false</code>. If the marker is flat against the map, it will remain stuck to the
+ map as the camera rotates and tilts but will still remain the same size as the camera zooms,
+ unlike a <code><a href="/reference/com/google/android/gms/maps/model/GroundOverlay.html">GroundOverlay</a></code>. If the marker is a billboard, it will always be drawn facing
+ the camera and will rotate and tilt with the camera. The default value is <code>false</code>.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the object for which the method was called, with the new flat state set.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="getAnchorU()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1837,6 +2009,74 @@
 </div>
 
 
+<A NAME="getInfoWindowAnchorU()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        float
+      </span>
+      <span class="sympad">getInfoWindowAnchorU</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Horizontal distance, normalized to [0, 1], of the info window anchor from the left edge.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the u value of the info window anchor.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
+<A NAME="getInfoWindowAnchorV()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        float
+      </span>
+      <span class="sympad">getInfoWindowAnchorV</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Vertical distance, normalized to [0, 1], of the info window anchor from the top edge.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the v value of the info window anchor.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="getPosition()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1871,6 +2111,40 @@
 </div>
 
 
+<A NAME="getRotation()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        float
+      </span>
+      <span class="sympad">getRotation</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Gets the rotation set for this MarkerOptions object.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the rotation of the marker in degrees clockwise from the default position.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="getSnippet()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1881,7 +2155,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getSnippet</span>
       <span class="normal">()</span>
@@ -1915,7 +2189,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTitle</span>
       <span class="normal">()</span>
@@ -1982,6 +2256,57 @@
 </div>
 
 
+<A NAME="infoWindowAnchor(float, float)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a>
+      </span>
+      <span class="sympad">infoWindowAnchor</span>
+      <span class="normal">(float u, float v)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Specifies the anchor point of the info window on the marker image. This is specified in the
+ same coordinate system as the anchor. See <code><a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html#anchor(float, float)">anchor(float, float)</a></code> for more details.
+ The default is the top middle of the image.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>u</td>
+          <td>u-coordinate of the info window anchor, as a ratio of the image width (in the range
+          [0, 1])</td>
+        </tr>
+        <tr>
+          <th>v</td>
+          <td>v-coordinate of the info window anchor, as a ratio of the image height (in the range
+          [0, 1])</td>
+        </tr>
+      </table>
+  </div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the object for which the method was called, with the new info window anchor set.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="isDraggable()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -2016,6 +2341,41 @@
 </div>
 
 
+<A NAME="isFlat()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        boolean
+      </span>
+      <span class="sympad">isFlat</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Gets the flat setting for this MarkerOptions object.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li><code>true</code> if the marker is flat against the map; <code>false</code> if the marker
+ should face the camera.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="isVisible()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -2084,6 +2444,45 @@
 </div>
 
 
+<A NAME="rotation(float)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a>
+      </span>
+      <span class="sympad">rotation</span>
+      <span class="normal">(float rotation)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets the rotation of the marker in degrees clockwise about the marker's anchor point. The
+ axis of rotation is perpendicular to the marker. A rotation of 0 corresponds to the default
+ position of the marker. When the marker is flat on the map, the default position is North
+ aligned and the rotation is such that the marker always remains flat on the map. When the
+ marker is a billboard, the default position is pointing up and the rotation is such that the
+ marker is always facing the camera. The default value is 0.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>the object for which the method was called, with the new rotation set.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="snippet(java.lang.String)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -2097,7 +2496,7 @@
         <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a>
       </span>
       <span class="sympad">snippet</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> snippet)</span>
+      <span class="normal">(String snippet)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2131,7 +2530,7 @@
         <a href="/reference/com/google/android/gms/maps/model/MarkerOptions.html">MarkerOptions</a>
       </span>
       <span class="sympad">title</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> title)</span>
+      <span class="normal">(String title)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2199,7 +2598,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/Polygon.html b/docs/html/reference/com/google/android/gms/maps/model/Polygon.html
index 03db7ab..371d98d 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/Polygon.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/Polygon.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Polygon | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -848,7 +855,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> other)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#equals(java.lang.Object)">equals</a></span>(Object other)</nobr>
         
   </td></tr>
 
@@ -879,7 +886,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;</nobr>
+            List&lt;List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#getHoles()">getHoles</a></span>()</nobr>
@@ -897,7 +904,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#getId()">getId</a></span>()</nobr>
@@ -915,7 +922,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#getPoints()">getPoints</a></span>()</nobr>
@@ -1096,7 +1103,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#setHoles(java.util.List<? extends java.util.List<com.google.android.gms.maps.model.LatLng>>)">setHoles</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;?&nbsp;extends&nbsp;<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt; holes)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#setHoles(java.util.List<? extends java.util.List<com.google.android.gms.maps.model.LatLng>>)">setHoles</a></span>(List&lt;?&nbsp;extends&nbsp;List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt; holes)</nobr>
         
         <div class="jd-descrdiv">Sets the holes of this polygon.</div>
   
@@ -1114,7 +1121,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#setPoints(java.util.List<com.google.android.gms.maps.model.LatLng>)">setPoints</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polygon.html#setPoints(java.util.List<com.google.android.gms.maps.model.LatLng>)">setPoints</a></span>(List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
         
         <div class="jd-descrdiv">Sets the points of this polygon.</div>
   
@@ -1216,7 +1223,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1235,7 +1242,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1254,7 +1261,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1283,7 +1290,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1347,7 +1354,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1464,7 +1471,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> other)</span>
+      <span class="normal">(Object other)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1524,7 +1531,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;
+        List&lt;List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;
       </span>
       <span class="sympad">getHoles</span>
       <span class="normal">()</span>
@@ -1556,7 +1563,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -1569,7 +1576,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Gets this polygon's id.
+  <div class="jd-tagdata jd-tagdescr"><p>Gets this polygon's id.  The id will be unique amongst all Polygons on a map.
 </p></div>
 
     </div>
@@ -1586,7 +1593,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
       </span>
       <span class="sympad">getPoints</span>
       <span class="normal">()</span>
@@ -1931,7 +1938,7 @@
         void
       </span>
       <span class="sympad">setHoles</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;?&nbsp;extends&nbsp;<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt; holes)</span>
+      <span class="normal">(List&lt;?&nbsp;extends&nbsp;List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt; holes)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1971,7 +1978,7 @@
         void
       </span>
       <span class="sympad">setPoints</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/PolygonOptions.html b/docs/html/reference/com/google/android/gms/maps/model/PolygonOptions.html
index c372f98..dd66db3d 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/PolygonOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/PolygonOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PolygonOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -953,7 +960,7 @@
             <a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html">PolygonOptions</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#addAll(java.lang.Iterable<com.google.android.gms.maps.model.LatLng>)">addAll</a></span>(<a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#addAll(java.lang.Iterable<com.google.android.gms.maps.model.LatLng>)">addAll</a></span>(Iterable&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
         
         <div class="jd-descrdiv">Adds vertices to the outline of the polygon being built.</div>
   
@@ -971,7 +978,7 @@
             <a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html">PolygonOptions</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#addHole(java.lang.Iterable<com.google.android.gms.maps.model.LatLng>)">addHole</a></span>(<a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#addHole(java.lang.Iterable<com.google.android.gms.maps.model.LatLng>)">addHole</a></span>(Iterable&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
         
         <div class="jd-descrdiv">Adds a hole to the polygon being built.</div>
   
@@ -1056,7 +1063,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;</nobr>
+            List&lt;List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#getHoles()">getHoles</a></span>()</nobr>
@@ -1074,7 +1081,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#getPoints()">getPoints</a></span>()</nobr>
@@ -1239,7 +1246,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1285,7 +1292,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1304,7 +1311,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1323,7 +1330,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1352,7 +1359,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1416,7 +1423,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1487,7 +1494,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1525,7 +1532,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1731,7 +1738,7 @@
         <a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html">PolygonOptions</a>
       </span>
       <span class="sympad">addAll</span>
-      <span class="normal">(<a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
+      <span class="normal">(Iterable&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1765,7 +1772,7 @@
         <a href="/reference/com/google/android/gms/maps/model/PolygonOptions.html">PolygonOptions</a>
       </span>
       <span class="sympad">addHole</span>
-      <span class="normal">(<a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
+      <span class="normal">(Iterable&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1929,7 +1936,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;
+        List&lt;List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;&gt;
       </span>
       <span class="sympad">getHoles</span>
       <span class="normal">()</span>
@@ -1963,7 +1970,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
       </span>
       <span class="sympad">getPoints</span>
       <span class="normal">()</span>
@@ -2274,7 +2281,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/Polyline.html b/docs/html/reference/com/google/android/gms/maps/model/Polyline.html
index 8e02c73..8d7f6ff 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/Polyline.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/Polyline.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Polyline | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -867,7 +874,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polyline.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> other)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polyline.html#equals(java.lang.Object)">equals</a></span>(Object other)</nobr>
         
   </td></tr>
 
@@ -898,7 +905,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polyline.html#getId()">getId</a></span>()</nobr>
@@ -916,7 +923,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polyline.html#getPoints()">getPoints</a></span>()</nobr>
@@ -1079,7 +1086,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polyline.html#setPoints(java.util.List<com.google.android.gms.maps.model.LatLng>)">setPoints</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Polyline.html#setPoints(java.util.List<com.google.android.gms.maps.model.LatLng>)">setPoints</a></span>(List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
         
         <div class="jd-descrdiv">Sets the points of this polyline.</div>
   
@@ -1163,7 +1170,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1182,7 +1189,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1201,7 +1208,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1230,7 +1237,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1294,7 +1301,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1447,7 +1454,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> other)</span>
+      <span class="normal">(Object other)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1507,7 +1514,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -1520,12 +1527,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Gets this polyline's id.
- <p>
- When a map is restored from a <code><a href="/reference/android/os/Bundle.html">Bundle</a></code>, polylines that were on that map are
- also restored. However, those polylines will then be represented by different
- <code>Polyline</code> objects. A polyline's id can be used to retrieve the new instance of a
- Polyline object after such restoration.</p></div>
+  <div class="jd-tagdata jd-tagdescr"><p>Gets this polyline's id. The id will be unique amongst all Polylines on a map.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Returns</h5>
       <ul class="nolist"><li>this polyline's id.
@@ -1546,7 +1548,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
       </span>
       <span class="sympad">getPoints</span>
       <span class="normal">()</span>
@@ -1858,7 +1860,7 @@
         void
       </span>
       <span class="sympad">setPoints</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/PolylineOptions.html b/docs/html/reference/com/google/android/gms/maps/model/PolylineOptions.html
index 87c6794..b855f5e 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/PolylineOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/PolylineOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PolylineOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -951,7 +958,7 @@
             <a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html">PolylineOptions</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html#addAll(java.lang.Iterable<com.google.android.gms.maps.model.LatLng>)">addAll</a></span>(<a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html#addAll(java.lang.Iterable<com.google.android.gms.maps.model.LatLng>)">addAll</a></span>(Iterable&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</nobr>
         
         <div class="jd-descrdiv">Adds vertices to the end of the polyline being built.</div>
   
@@ -1036,7 +1043,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html#getPoints()">getPoints</a></span>()</nobr>
@@ -1165,7 +1172,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1211,7 +1218,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1230,7 +1237,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1249,7 +1256,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1278,7 +1285,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1342,7 +1349,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1413,7 +1420,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1451,7 +1458,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1656,7 +1663,7 @@
         <a href="/reference/com/google/android/gms/maps/model/PolylineOptions.html">PolylineOptions</a>
       </span>
       <span class="sympad">addAll</span>
-      <span class="normal">(<a href="/reference/java/lang/Iterable.html">Iterable</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
+      <span class="normal">(Iterable&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt; points)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1820,7 +1827,7 @@
          
          
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/maps/model/LatLng.html">LatLng</a>&gt;
       </span>
       <span class="sympad">getPoints</span>
       <span class="normal">()</span>
@@ -2062,7 +2069,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/RuntimeRemoteException.html b/docs/html/reference/com/google/android/gms/maps/model/RuntimeRemoteException.html
index 21a1a97..36a045a 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/RuntimeRemoteException.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/RuntimeRemoteException.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>RuntimeRemoteException | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -712,7 +719,7 @@
   
 
   
-    extends <a href="/reference/java/lang/RuntimeException.html">RuntimeException</a><br/>
+    extends RuntimeException<br/>
   
   
   
@@ -732,7 +739,7 @@
 
     <tr>
          	
-        <td colspan="5" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -740,7 +747,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Throwable</td>
     </tr>
     
 
@@ -750,7 +757,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Exception.html">java.lang.Exception</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Exception</td>
     </tr>
     
 
@@ -762,7 +769,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/RuntimeException.html">java.lang.RuntimeException</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.RuntimeException</td>
     </tr>
     
 
@@ -860,7 +867,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/RuntimeRemoteException.html#RuntimeRemoteException(android.os.RemoteException)">RuntimeRemoteException</a></span>(<a href="/reference/android/os/RemoteException.html">RemoteException</a> e)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/RuntimeRemoteException.html#RuntimeRemoteException(android.os.RemoteException)">RuntimeRemoteException</a></span>(RemoteException e)</nobr>
         
   </td></tr>
 
@@ -896,7 +903,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Throwable.html">java.lang.Throwable</a>
+  java.lang.Throwable
 
 <div id="inherited-methods-java.lang.Throwable">
   <div id="inherited-methods-java.lang.Throwable-list"
@@ -915,7 +922,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">fillInStackTrace</span>()</nobr>
@@ -931,7 +938,7 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getCause</span>()</nobr>
@@ -947,7 +954,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLocalizedMessage</span>()</nobr>
@@ -963,7 +970,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMessage</span>()</nobr>
@@ -979,7 +986,7 @@
             
             
             
-            <a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a></nobr>
+            StackTraceElement[]</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getStackTrace</span>()</nobr>
@@ -995,10 +1002,10 @@
             
             
             
-            <a href="/reference/java/lang/Throwable.html">Throwable</a></nobr>
+            Throwable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initCause</span>(<a href="/reference/java/lang/Throwable.html">Throwable</a> arg0)</nobr>
+        <span class="sympad">initCause</span>(Throwable arg0)</nobr>
         
   </td></tr>
 
@@ -1014,7 +1021,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintWriter.html">PrintWriter</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintWriter arg0)</nobr>
         
   </td></tr>
 
@@ -1030,7 +1037,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">printStackTrace</span>(<a href="/reference/java/io/PrintStream.html">PrintStream</a> arg0)</nobr>
+        <span class="sympad">printStackTrace</span>(PrintStream arg0)</nobr>
         
   </td></tr>
 
@@ -1062,7 +1069,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setStackTrace</span>(<a href="/reference/java/lang/StackTraceElement.html">StackTraceElement[]</a> arg0)</nobr>
+        <span class="sympad">setStackTrace</span>(StackTraceElement[] arg0)</nobr>
         
   </td></tr>
 
@@ -1075,7 +1082,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1098,7 +1105,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1117,7 +1124,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1136,7 +1143,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1165,7 +1172,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1229,7 +1236,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1340,7 +1347,7 @@
         
       </span>
       <span class="sympad">RuntimeRemoteException</span>
-      <span class="normal">(<a href="/reference/android/os/RemoteException.html">RemoteException</a> e)</span>
+      <span class="normal">(RemoteException e)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/Tile.html b/docs/html/reference/com/google/android/gms/maps/model/Tile.html
index 235f104..a8293f8 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/Tile.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/Tile.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Tile | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -960,7 +967,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Tile.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/Tile.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -988,7 +995,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1007,7 +1014,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1026,7 +1033,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1055,7 +1062,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1119,7 +1126,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1190,7 +1197,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1228,7 +1235,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1499,7 +1506,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/TileOverlay.html b/docs/html/reference/com/google/android/gms/maps/model/TileOverlay.html
index 738bf5e..255e74f 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/TileOverlay.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/TileOverlay.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>TileOverlay | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -869,7 +876,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/TileOverlay.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> other)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/TileOverlay.html#equals(java.lang.Object)">equals</a></span>(Object other)</nobr>
         
   </td></tr>
 
@@ -882,7 +889,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/TileOverlay.html#getId()">getId</a></span>()</nobr>
@@ -1021,7 +1028,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1040,7 +1047,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1059,7 +1066,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1088,7 +1095,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1152,7 +1159,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1301,7 +1308,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> other)</span>
+      <span class="normal">(Object other)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1327,7 +1334,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/TileOverlayOptions.html b/docs/html/reference/com/google/android/gms/maps/model/TileOverlayOptions.html
index ac7481d..2978c5a 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/TileOverlayOptions.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/TileOverlayOptions.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>TileOverlayOptions | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -1017,7 +1024,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/TileOverlayOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/TileOverlayOptions.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1064,7 +1071,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1083,7 +1090,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1102,7 +1109,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1131,7 +1138,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1195,7 +1202,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1266,7 +1273,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1304,7 +1311,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1649,7 +1656,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/TileProvider.html b/docs/html/reference/com/google/android/gms/maps/model/TileProvider.html
index ac01ca3..44a84ca 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/TileProvider.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/TileProvider.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>TileProvider | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/UrlTileProvider.html b/docs/html/reference/com/google/android/gms/maps/model/UrlTileProvider.html
index 2f5241c..837f965 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/UrlTileProvider.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/UrlTileProvider.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>UrlTileProvider | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -693,7 +700,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -718,7 +725,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -903,7 +910,7 @@
             
             
             
-            <a href="/reference/java/net/URL.html">URL</a></nobr>
+            URL</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/UrlTileProvider.html#getTileUrl(int, int, int)">getTileUrl</a></span>(int x, int y, int zoom)</nobr>
@@ -936,7 +943,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -955,7 +962,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -974,7 +981,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1003,7 +1010,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1067,7 +1074,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1333,7 +1340,7 @@
          
         abstract 
          
-        <a href="/reference/java/net/URL.html">URL</a>
+        URL
       </span>
       <span class="sympad">getTileUrl</span>
       <span class="normal">(int x, int y, int zoom)</span>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/VisibleRegion.html b/docs/html/reference/com/google/android/gms/maps/model/VisibleRegion.html
index 02b695e..b038976 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/VisibleRegion.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/VisibleRegion.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>VisibleRegion | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -696,7 +703,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -705,7 +712,7 @@
   
       implements 
       
-        <a href="/reference/android/os/Parcelable.html">Parcelable</a> 
+        Parcelable 
       
   
   
@@ -721,7 +728,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -985,7 +992,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/VisibleRegion.html#equals(java.lang.Object)">equals</a></span>(<a href="/reference/java/lang/Object.html">Object</a> o)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/VisibleRegion.html#equals(java.lang.Object)">equals</a></span>(Object o)</nobr>
         
         <div class="jd-descrdiv">Compares this <code><a href="/reference/com/google/android/gms/maps/model/VisibleRegion.html">VisibleRegion</a></code> to another object.</div>
   
@@ -1016,7 +1023,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/VisibleRegion.html#toString()">toString</a></span>()</nobr>
@@ -1035,7 +1042,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/VisibleRegion.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/maps/model/VisibleRegion.html#writeToParcel(android.os.Parcel, int)">writeToParcel</a></span>(Parcel out, int flags)</nobr>
         
   </td></tr>
 
@@ -1063,7 +1070,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1082,7 +1089,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1101,7 +1108,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1130,7 +1137,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1194,7 +1201,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1265,7 +1272,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/os/Parcelable.html">android.os.Parcelable</a>
+  android.os.Parcelable
 
 <div id="inherited-methods-android.os.Parcelable">
   <div id="inherited-methods-android.os.Parcelable-list"
@@ -1303,7 +1310,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">writeToParcel</span>(<a href="/reference/android/os/Parcel.html">Parcel</a> arg0, int arg1)</nobr>
+        <span class="sympad">writeToParcel</span>(Parcel arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -1651,7 +1658,7 @@
         boolean
       </span>
       <span class="sympad">equals</span>
-      <span class="normal">(<a href="/reference/java/lang/Object.html">Object</a> o)</span>
+      <span class="normal">(Object o)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1720,7 +1727,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">toString</span>
       <span class="normal">()</span>
@@ -1752,7 +1759,7 @@
         void
       </span>
       <span class="sympad">writeToParcel</span>
-      <span class="normal">(<a href="/reference/android/os/Parcel.html">Parcel</a> out, int flags)</span>
+      <span class="normal">(Parcel out, int flags)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/maps/model/package-summary.html b/docs/html/reference/com/google/android/gms/maps/model/package-summary.html
index 2c44fc7..519140b 100644
--- a/docs/html/reference/com/google/android/gms/maps/model/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/maps/model/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.maps.model | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/maps/package-summary.html b/docs/html/reference/com/google/android/gms/maps/package-summary.html
index 4d71e4f..76430b6 100644
--- a/docs/html/reference/com/google/android/gms/maps/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/maps/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.maps | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/package-summary.html b/docs/html/reference/com/google/android/gms/package-summary.html
index 5bddf3a..d747e2c 100644
--- a/docs/html/reference/com/google/android/gms/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html b/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html
index 269cc42..c7af288 100644
--- a/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PanoramaClient.OnPanoramaInfoLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -751,7 +758,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html#onPanoramaInfoLoaded(com.google.android.gms.common.ConnectionResult, android.content.Intent)">onPanoramaInfoLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> result, <a href="/reference/android/content/Intent.html">Intent</a> viewerIntent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html#onPanoramaInfoLoaded(com.google.android.gms.common.ConnectionResult, android.content.Intent)">onPanoramaInfoLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> result, Intent viewerIntent)</nobr>
         
         <div class="jd-descrdiv">Called on the main thread when panorama info is loaded.</div>
   
@@ -819,7 +826,7 @@
         void
       </span>
       <span class="sympad">onPanoramaInfoLoaded</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> result, <a href="/reference/android/content/Intent.html">Intent</a> viewerIntent)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> result, Intent viewerIntent)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.html b/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.html
index bbe14fb..944d3bb 100644
--- a/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.html
+++ b/docs/html/reference/com/google/android/gms/panorama/PanoramaClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PanoramaClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -691,7 +698,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -841,7 +848,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.html#PanoramaClient(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">PanoramaClient</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.html#PanoramaClient(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">PanoramaClient</a></span>(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
         
         <div class="jd-descrdiv">Creates a panorama client.</div>
   
@@ -983,7 +990,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.html#loadPanoramaInfo(com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener, android.net.Uri)">loadPanoramaInfo</a></span>(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.html#loadPanoramaInfo(com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener, android.net.Uri)">loadPanoramaInfo</a></span>(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, Uri uri)</nobr>
         
         <div class="jd-descrdiv">Loads information about a panorama.</div>
   
@@ -1001,7 +1008,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.html#loadPanoramaInfoAndGrantAccess(com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener, android.net.Uri)">loadPanoramaInfoAndGrantAccess</a></span>(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/panorama/PanoramaClient.html#loadPanoramaInfoAndGrantAccess(com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener, android.net.Uri)">loadPanoramaInfoAndGrantAccess</a></span>(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, Uri uri)</nobr>
         
         <div class="jd-descrdiv">Loads information about a panorama from a content provider.</div>
   
@@ -1104,7 +1111,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1123,7 +1130,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1142,7 +1149,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1171,7 +1178,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1235,7 +1242,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1554,7 +1561,7 @@
         
       </span>
       <span class="sympad">PanoramaClient</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1838,7 +1845,7 @@
         void
       </span>
       <span class="sympad">loadPanoramaInfo</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, Uri uri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1882,7 +1889,7 @@
         void
       </span>
       <span class="sympad">loadPanoramaInfoAndGrantAccess</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, <a href="/reference/android/net/Uri.html">Uri</a> uri)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html">PanoramaClient.OnPanoramaInfoLoadedListener</a> listener, Uri uri)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/panorama/package-summary.html b/docs/html/reference/com/google/android/gms/panorama/package-summary.html
index bd15388..66f7b45 100644
--- a/docs/html/reference/com/google/android/gms/panorama/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/panorama/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.panorama | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/GooglePlusUtil.html b/docs/html/reference/com/google/android/gms/plus/GooglePlusUtil.html
deleted file mode 100644
index 541cda4..0000000
--- a/docs/html/reference/com/google/android/gms/plus/GooglePlusUtil.html
+++ /dev/null
@@ -1,1528 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>GooglePlusUtil | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-<body class="gc-documentation google
-  develop" itemscope itemtype="http://schema.org/Article">
-  <div id="doc-api-level" class="" style="display:none"></div>
-  <a name="top"></a>
-
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo">
-          <a href="/index.html">
-            <img src="/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
-          </a>
-          <div class="btn-quicknav" id="btn-quicknav">
-          	<a href="#" class="arrow-inactive">Quicknav</a>
-			      <a href="#" class="arrow-active">Quicknav</a>
-          </div>
-          </div>
-            <ul class="nav-x col-9">
-                <li class="design">
-                  <a href="/design/index.html"
-                  zh-tw-lang="設計"
-                  zh-cn-lang="设计"
-                  ru-lang="Проектирование"
-                  ko-lang="디자인"
-                  ja-lang="設計"
-                  es-lang="Diseñar"               
-                  >Design</a></li>
-                <li class="develop"><a href="/develop/index.html"
-                  zh-tw-lang="開發"
-                  zh-cn-lang="开发"
-                  ru-lang="Разработка"
-                  ko-lang="개발"
-                  ja-lang="開発"
-                  es-lang="Desarrollar"               
-                  >Develop</a></li>
-                <li class="distribute last"><a href="/distribute/index.html"
-                  zh-tw-lang="發佈"
-                  zh-cn-lang="分发"
-                  ru-lang="Распространение"
-                  ko-lang="배포"
-                  ja-lang="配布"
-                  es-lang="Distribuir"               
-                  >Distribute</a></li>
-            </ul>
-            
-            <!-- New Search -->
-            <div class="menu-container">
-            <div class="moremenu">
-    <div id="more-btn"></div>
-  </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div>
-    <div class="bottom"></div>
-  </div>
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  </div>
-  <!-- /New Search>
-          
-          
-          <!-- Expanded quicknav -->
-           <div id="quicknav" class="col-9">
-                <ul>
-                    <li class="design">
-                      <ul>
-                        <li><a href="/design/index.html">Get Started</a></li>
-                        <li><a href="/design/style/index.html">Style</a></li>
-                        <li><a href="/design/patterns/index.html">Patterns</a></li>
-                        <li><a href="/design/building-blocks/index.html">Building Blocks</a></li>
-                        <li><a href="/design/downloads/index.html">Downloads</a></li>
-                        <li><a href="/design/videos/index.html">Videos</a></li>
-                      </ul>
-                    </li>
-                    <li class="develop">
-                      <ul>
-                        <li><a href="/training/index.html"
-                          zh-tw-lang="訓練課程"
-                          zh-cn-lang="培训"
-                          ru-lang="Курсы"
-                          ko-lang="교육"
-                          ja-lang="トレーニング"
-                          es-lang="Capacitación"               
-                          >Training</a></li>
-                        <li><a href="/guide/components/index.html"
-                          zh-tw-lang="API 指南"
-                          zh-cn-lang="API 指南"
-                          ru-lang="Руководства по API"
-                          ko-lang="API 가이드"
-                          ja-lang="API ガイド"
-                          es-lang="Guías de la API"               
-                          >API Guides</a></li>
-                        <li><a href="/reference/packages.html"
-                          zh-tw-lang="參考資源"
-                          zh-cn-lang="参考"
-                          ru-lang="Справочник"
-                          ko-lang="참조문서"
-                          ja-lang="リファレンス"
-                          es-lang="Referencia"               
-                          >Reference</a></li>
-                        <li><a href="/tools/index.html"
-                          zh-tw-lang="相關工具"
-                          zh-cn-lang="工具"
-                          ru-lang="Инструменты"
-                          ko-lang="도구"
-                          ja-lang="ツール"
-                          es-lang="Herramientas"               
-                          >Tools</a>
-                          <ul><li><a href="/sdk/index.html">Get the SDK</a></li></ul>
-                        </li>
-                        <li><a href="/google/index.html">Google Services</a>
-                        </li>
-                      </ul>
-                    </li>
-                    <li class="distribute last">
-                      <ul>
-                        <li><a href="/distribute/index.html">Google Play</a></li>
-                        <li><a href="/distribute/googleplay/publish/index.html">Publishing</a></li>
-                        <li><a href="/distribute/googleplay/promote/index.html">Promoting</a></li>
-                        <li><a href="/distribute/googleplay/quality/index.html">App Quality</a></li>
-                        <li><a href="/distribute/googleplay/spotlight/index.html">Spotlight</a></li>
-                        <li><a href="/distribute/open.html">Open Distribution</a></li>
-                      </ul>
-                    </li>
-                </ul>
-          </div>
-          <!-- /Expanded quicknav -->
-        </div>
-    </div>
-    <!-- /Header -->
-    
-    
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-    
-    
-  
-    <!-- Secondary x-nav -->
-    <div id="nav-x">
-        <div class="wrap">
-            <ul class="nav-x col-9 develop" style="width:100%">
-                <li class="training"><a href="/training/index.html"
-                  zh-tw-lang="訓練課程"
-                  zh-cn-lang="培训"
-                  ru-lang="Курсы"
-                  ko-lang="교육"
-                  ja-lang="トレーニング"
-                  es-lang="Capacitación"               
-                  >Training</a></li>
-                <li class="guide"><a href="/guide/components/index.html"
-                  zh-tw-lang="API 指南"
-                  zh-cn-lang="API 指南"
-                  ru-lang="Руководства по API"
-                  ko-lang="API 가이드"
-                  ja-lang="API ガイド"
-                  es-lang="Guías de la API"               
-                  >API Guides</a></li>
-                <li class="reference"><a href="/reference/packages.html"
-                  zh-tw-lang="參考資源"
-                  zh-cn-lang="参考"
-                  ru-lang="Справочник"
-                  ko-lang="참조문서"
-                  ja-lang="リファレンス"
-                  es-lang="Referencia"               
-                  >Reference</a></li>
-                <li class="tools"><a href="/tools/index.html"
-                  zh-tw-lang="相關工具"
-                  zh-cn-lang="工具"
-                  ru-lang="Инструменты"
-                  ko-lang="도구"
-                  ja-lang="ツール"
-                  es-lang="Herramientas"
-                  >Tools</a></li>
-                <li class="google"><a href="/google/index.html"
-                  >Google Services</a>
-                </li>
-            </ul>
-        </div>
-        
-    </div>
-    <!-- /Sendondary x-nav -->
-  
-
-
-
-
-  
-
-
-  
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/index.html">
-          <span class="en">Overview</span>
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/games.html">
-          <span class="en">Games</span>
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/location.html">
-          <span class="en">Location</span>
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/plus.html">
-          <span class="en">Google+</span>
-                </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/maps.html">
-          <span class="en">Google Maps</span>
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/auth.html">
-          <span class="en">Authorization</span>
-      </a></div>
-  </li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/play-services/index.html">
-      <span class="en">Google Play Services</span></a>
-    </div>
-    <ul>
-      <li><a href="/google/play-services/setup.html">
-          <span class="en">Setup</span></a>
-      </li>
-      <li id="gms-tree-list" class="nav-section">
-        <div class="nav-section-header">
-          <a href="/reference/gms-packages.html">
-            <span class="en">Reference</span>
-          </a>
-        <div>
-      </li>
-    </ul>
-  </li>
-
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/play/billing/index.html">
-      <span class="en">Google Play In-app Billing</span></a>
-    </div>
-    <ul>
-      <li><a href="/google/play/billing/billing_overview.html">
-              <span class="en">Overview</span></a>
-      </li>
-      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/api.html">
-              <span class="en">Version 3 API</span></a></div>
-              <ul>
-              <li><a href="/google/play/billing/billing_integrate.html">
-              <span class="en">Implementing the API</span></a></li>
-              <li><a href="/google/play/billing/billing_reference.html">
-              <span class="en">Reference</span></a></li>
-              </ul>
-      </li>
-      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/v2/api.html">
-              <span class="en">Version 2 API</span></a></div>
-              <ul>
-              <li><a href="/google/play/billing/v2/billing_integrate.html">
-              <span class="en">Implementing the API</span></a></li>
-              <li><a href="/google/play/billing/v2/billing_subscriptions.html">
-              <span class="en">Subscriptions</span></a></li>
-              <li><a href="/google/play/billing/v2/billing_reference.html">
-              <span class="en">Reference</span></a></li>
-              </ul>
-      </li>
-      <li><a href="/google/play/billing/billing_subscriptions.html">
-              <span class="en">Subscriptions</span></a>
-      </li>
-      <li><a href="/google/play/billing/billing_best_practices.html">
-              <span class="en">Security and Design</span></a>
-      </li>
-      <li><a href="/google/play/billing/billing_testing.html">
-              <span class="en">Testing In-app Billing</span></a>
-      </li>
-      <li><a href="/google/play/billing/billing_admin.html">
-              <span class="en">Administering In-app Billing</span></a>
-      </li>
-      <li><a href="/google/play/billing/gp-purchase-status-api.html">
-              <span class="en">Purchase Status API</span></a>
-      </li>
-      <li><a href="/google/play/billing/versions.html">
-              <span class="en">Version Notes</span></a>
-      </li>
-    </ul>
-  </li>
-
-
-
-  <li class="nav-section">
-      <div class="nav-section-header"><a href="/google/gcm/index.html">
-        <span class="en">Google Cloud Messaging</span></a>
-      </div>
-      <ul>
-        <li><a href="/google/gcm/gs.html">
-            <span class="en">Getting Started</span></a>
-        </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
-        </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
-        </li>
-        <li><a href="/google/gcm/notifications.html">
-              <span class="en">User Notifications</span></a>
-        </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
-        <li><a href="/google/gcm/adv.html">
-            <span class="en">Advanced Topics</span></a>
-        </li>
-        <li><a href="/google/gcm/c2dm.html">
-            <span class="en">Migration</span></a>
-        </li>
-        <li id="gcm-tree-list" class="nav-section">
-          <div class="nav-section-header">
-            <a href="/reference/gcm-packages.html">
-              <span class="en">Reference</span>
-            </a>
-          <div>
-        </li>
-      </ul>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/play/dist.html">
-      <span class="en">Google Play Distribution</span></a>
-    </div>
-    <ul>
-      <li><a href="/google/play/filters.html">
-          <span class="en">Filters on Google Play</span></a>
-      </li>
-
-      <li><a href="/google/play/publishing/multiple-apks.html">
-          <span class="en">Multiple APK Support</span></a>
-      </li>
-      <li><a href="/google/play/expansion-files.html">
-          <span class="en">APK Expansion Files</span></a>
-      </li>
-      <li class="nav-section">
-        <div class="nav-section-header"><a href="/google/play/licensing/index.html">
-          <span class="en">Application Licensing</span></a>
-        </div>
-        <ul>
-          <li><a href="/google/play/licensing/overview.html">
-              <span class="en">Licensing Overview</span></a>
-          </li>
-          <li><a href="/google/play/licensing/setting-up.html">
-              <span class="en">Setting Up for Licensing</span></a>
-          </li>
-          <li><a href="/google/play/licensing/adding-licensing.html">
-              <span class="en">Adding Licensing to Your App</span></a>
-          </li>
-          <li><a href="/google/play/licensing/licensing-reference.html">
-              <span class="en">Licensing Reference</span></a>
-          </li>
-        </ul>
-      </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/backup/index.html">
-      Android Backup Service</a>
-    </div>
-    <ul>
-      <li><a href="/google/backup/signup.html">
-          Register</a>
-      </li>
-    </ul>
-  </li>
-
-  </ul>
-
-</li>
-
-
-
-</ul>
-
-<script type="text/javascript">
-<!--
-    buildToggleLists();
-    changeNavLang(getLangPref());
-//-->
-</script>
-
-
-        
-
-      </div>
-      <script type="text/javascript">
-       showGoogleRefTree();
-    
-      </script>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-     
-
-
-
-<div class="col-12"  id="doc-col">
-
-<div id="api-info-block">
-
-
-
-  
-   
-  
-  
-  
-  
-
-
-<div class="sum-details-links">
-
-Summary:
-
-
-
-
-
-  <a href="#constants">Constants</a>
-  
-
-
-
-
-
-
-
-  &#124; <a href="#pubmethods">Methods</a>
-  
-
-
-
-  &#124; <a href="#inhmethods">Inherited Methods</a>
-
-&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
-
-</div><!-- end sum-details-links -->
-<div class="api-level">
-  
-  
-  
-
-</div>
-</div><!-- end api-info-block -->
-
-
-<!-- ======== START OF CLASS DATA ======== -->
-
-<div id="jd-header">
-    public
-     
-     
-    
-    class
-<h1 itemprop="name">GooglePlusUtil</h1>
-
-
-
-  
-    extends Object<br/>
-  
-  
-  
-
-  
-  
-  
-
-
-</div><!-- end header -->
-
-<div id="naMessage"></div>
-
-<div id="jd-content" class="api apilevel-">
-<table class="jd-inheritance-table">
-
-
-    <tr>
-         	
-        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
-    </tr>
-    
-
-    <tr>
-        
-            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
-         	
-        <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.plus.GooglePlusUtil</td>
-    </tr>
-    
-
-</table>
-
-
-
-
-
-
-
-<div class="jd-descr">
-
-
-<h2>Class Overview</h2>
-<p itemprop="articleBody">Utility class for verifying that the Google+ app is available and
- up-to-date on this device.
-</p>
-
-
-
-
-
-</div><!-- jd-descr -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class="jd-descr">
-
-
-<h2>Summary</h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<!-- =========== ENUM CONSTANT SUMMARY =========== -->
-<table id="constants" class="jd-sumtable"><tr><th colspan="12">Constants</th></tr>
-
-
-    
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#APP_DISABLED">APP_DISABLED</a></td>
-        <td class="jd-descrcol" width="100%">Status code indicating the Google+ app is installed, but disabled.</td>
-    </tr>
-    
-    
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#APP_MISSING">APP_MISSING</a></td>
-        <td class="jd-descrcol" width="100%">Status code indicating the Google+ app is not installed.</td>
-    </tr>
-    
-    
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#APP_UPDATE_REQUIRED">APP_UPDATE_REQUIRED</a></td>
-        <td class="jd-descrcol" width="100%">Status code indicating the Google+ app is installed, but is older than the
- version required.</td>
-    </tr>
-    
-    
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol">String</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#GOOGLE_PLUS_PACKAGE">GOOGLE_PLUS_PACKAGE</a></td>
-        <td class="jd-descrcol" width="100%">The package name of the Google+ Android app.</td>
-    </tr>
-    
-    
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol">String</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#PLATFORM_LOGGING_TAG">PLATFORM_LOGGING_TAG</a></td>
-        <td class="jd-descrcol" width="100%">Property to enable logging across the Google+ platform for Android.</td>
-    </tr>
-    
-    
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#SUCCESS">SUCCESS</a></td>
-        <td class="jd-descrcol" width="100%">Status code indicating the Google+ app is installed and up-to-date.</td>
-    </tr>
-    
-    
-
-</table>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="pubmethods" class="jd-sumtable"><tr><th colspan="12">Public Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            int</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#checkGooglePlusApp(android.content.Context)">checkGooglePlusApp</a></span>(Context context)</nobr>
-        
-        <div class="jd-descrdiv">Checks if the version of the Google+ app installed on this device is up-to-date.</div>
-  
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            static
-            
-            Dialog</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#getErrorDialog(int, android.app.Activity, int)">getErrorDialog</a></span>(int errorCode, Activity activity, int requestCode)</nobr>
-        
-        <div class="jd-descrdiv">Returns a dialog to address the provided errorCode.</div>
-  
-  </td></tr>
-
-
-
-</table>
-
-
-
-
-
-
-
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="inhmethods" class="jd-sumtable"><tr><th>
-  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
-  <div style="clear:left;">Inherited Methods</div></th></tr>
-
-
-<tr class="api apilevel-" >
-<td colspan="12">
-  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-java.lang.Object" class="jd-expando-trigger closed"
-          ><img id="inherited-methods-java.lang.Object-trigger"
-          src="/assets/images/triangle-closed.png"
-          class="jd-expando-trigger-img" /></a>
-From class
-
-  java.lang.Object
-
-<div id="inherited-methods-java.lang.Object">
-  <div id="inherited-methods-java.lang.Object-list"
-        class="jd-inheritedlinks">
-  </div>
-  <div id="inherited-methods-java.lang.Object-summary" style="display: none;">
-    <table class="jd-sumtable-expando">
-    
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            Object</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clone</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(Object arg0)</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">finalize</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            final
-            
-            
-            Class&lt;?&gt;</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getClass</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            int</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">hashCode</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            final
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">notify</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            final
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">notifyAll</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            String</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">toString</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            final
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">wait</span>()</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            final
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">wait</span>(long arg0, int arg1)</nobr>
-        
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            final
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">wait</span>(long arg0)</nobr>
-        
-  </td></tr>
-
-
-</table>
-  </div>
-</div>
-</td></tr>
-
-
-</table>
-
-
-</div><!-- jd-descr (summary) -->
-
-<!-- Details -->
-
-
-
-
-
-
-
-
-<!-- XML Attributes -->
-
-
-<!-- Enum Values -->
-
-
-<!-- Constants -->
-
-
-<!-- ========= ENUM CONSTANTS DETAIL ======== -->
-<h2>Constants</h2>
-
-
-
-
-<A NAME="APP_DISABLED"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        APP_DISABLED
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Status code indicating the Google+ app is installed, but disabled.
-</p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                3
-                (0x00000003)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
-<A NAME="APP_MISSING"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        APP_MISSING
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Status code indicating the Google+ app is not installed.
-</p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                1
-                (0x00000001)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
-<A NAME="APP_UPDATE_REQUIRED"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        APP_UPDATE_REQUIRED
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Status code indicating the Google+ app is installed, but is older than the
- version required.
-</p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                2
-                (0x00000002)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
-<A NAME="GOOGLE_PLUS_PACKAGE"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        String
-      </span>
-        GOOGLE_PLUS_PACKAGE
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>The package name of the Google+ Android app.
-</p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                "com.google.android.apps.plus"
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
-<A NAME="PLATFORM_LOGGING_TAG"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        String
-      </span>
-        PLATFORM_LOGGING_TAG
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Property to enable logging across the Google+ platform for Android.
- <p>
- To enable logging:<br>
-      <code>adb shell setprop <em>log.tag.GooglePlusPlatform</em> <em>VERBOSE</em></code>
- </p>
- <p>
- To disable logging:<br>
-      <code>adb shell setprop <em>log.tag.GooglePlusPlatform</em> <em>""</em></code>
- </p>
-</p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                "GooglePlusPlatform"
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
-<A NAME="SUCCESS"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        SUCCESS
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Status code indicating the Google+ app is installed and up-to-date.
-</p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                0
-                (0x00000000)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
-
-<!-- Fields -->
-
-
-<!-- Public ctors -->
-
-
-
-<!-- ========= CONSTRUCTOR DETAIL ======== -->
-<!-- Protected ctors -->
-
-
-
-<!-- ========= METHOD DETAIL ======== -->
-<!-- Public methdos -->
-
-<h2>Public Methods</h2>
-
-
-
-<A NAME="checkGooglePlusApp(android.content.Context)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-         
-         
-         
-        int
-      </span>
-      <span class="sympad">checkGooglePlusApp</span>
-      <span class="normal">(Context context)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Checks if the version of the Google+ app installed on this device is up-to-date.</p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Parameters</h5>
-      <table class="jd-tagtable">
-        <tr>
-          <th>context</td>
-          <td>The context.</td>
-        </tr>
-      </table>
-  </div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Returns</h5>
-      <ul class="nolist"><li>One of the status codes that is defined by this class: <code><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#APP_DISABLED">APP_DISABLED</a></code>,
-         <code><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#APP_MISSING">APP_MISSING</a></code>, <code><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#APP_UPDATE_REQUIRED">APP_UPDATE_REQUIRED</a></code>, or <code><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#SUCCESS">SUCCESS</a></code>
-</li></ul>
-  </div>
-
-    </div>
-</div>
-
-
-<A NAME="getErrorDialog(int, android.app.Activity, int)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-         
-         
-         
-        Dialog
-      </span>
-      <span class="sympad">getErrorDialog</span>
-      <span class="normal">(int errorCode, Activity activity, int requestCode)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      
-  <div class="jd-tagdata jd-tagdescr"><p>Returns a dialog to address the provided errorCode. Upon confirmation, the user is directed
- to either the Google Play Store or the System App Settings screen to resolve the error.</p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Parameters</h5>
-      <table class="jd-tagtable">
-        <tr>
-          <th>errorCode</td>
-          <td>error code returned by <code><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#checkGooglePlusApp(android.content.Context)">checkGooglePlusApp(Context)</a></code> call. If
-            errorCode is <code><a href="/reference/com/google/android/gms/plus/GooglePlusUtil.html#SUCCESS">SUCCESS</a></code> then null is returned.</td>
-        </tr>
-        <tr>
-          <th>activity</td>
-          <td>parent activity for creating the dialog, also used for identifying language
-            to display dialog in.</td>
-        </tr>
-        <tr>
-          <th>requestCode</td>
-          <td>The non-negative request code given when calling
-            <code><a href="/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)">startActivityForResult(Intent, int)</a></code>.
-</td>
-        </tr>
-      </table>
-  </div>
-
-    </div>
-</div>
-
-
-
-
-
-<!-- ========= METHOD DETAIL ======== -->
-
-
-
-<!-- ========= END OF CLASS DATA ========= -->
-<A NAME="navbar_top"></A>
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is licensed under <a
-  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
-  For details and restrictions, see the <a href="/license.html">
-  Content License</a>.
-  </div>
-  <div id="build_info">
-    
-<script src="/timestamp.js" type="text/javascript"></script>
-<script>document.write(BUILD_TIMESTAMP)</script>
-
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div> <!-- jd-content -->
-
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-</body>
-</html>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.Builder.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.Builder.html
index 63fd808..0325694 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.Builder.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusClient.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusClient.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -792,7 +799,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#PlusClient.Builder(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">PlusClient.Builder</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#PlusClient.Builder(android.content.Context, com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks, com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener)">PlusClient.Builder</a></span>(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</nobr>
         
         <div class="jd-descrdiv">Builder to help construct the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></code> object.</div>
   
@@ -859,7 +866,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setAccountName(java.lang.String)">setAccountName</a></span>(<a href="/reference/java/lang/String.html">String</a> accountName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setAccountName(java.lang.String)">setAccountName</a></span>(String accountName)</nobr>
         
         <div class="jd-descrdiv">Specify an account name on the device that should be used.</div>
   
@@ -877,9 +884,9 @@
             <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setScopes(java.lang.String...)">setScopes</a></span>(<a href="/reference/java/lang/String.html">String...</a> scopes)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setActions(java.lang.String...)">setActions</a></span>(String... actions)</nobr>
         
-        <div class="jd-descrdiv">Specify the OAuth 2.0 scopes requested by your app.</div>
+        <div class="jd-descrdiv">Specify which user's app activity types can be written to Google.</div>
   
   </td></tr>
 
@@ -895,9 +902,27 @@
             <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setVisibleActivities(java.lang.String...)">setVisibleActivities</a></span>(<a href="/reference/java/lang/String.html">String...</a> visibleActivities)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setScopes(java.lang.String...)">setScopes</a></span>(String... scopes)</nobr>
         
-        <div class="jd-descrdiv">Specify which user's app activity types can be written to Google.</div>
+        <div class="jd-descrdiv">Specify the OAuth 2.0 scopes requested by your app.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setVisibleActivities(java.lang.String...)">setVisibleActivities</a></span>(String... actions)</nobr>
+        
+        <div class="jd-descrdiv">See <code><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setActions(java.lang.String...)">setActions(String)</a></code>.</div>
   
   </td></tr>
 
@@ -925,7 +950,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -944,7 +969,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -963,7 +988,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -992,7 +1017,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1056,7 +1081,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1165,7 +1190,7 @@
         
       </span>
       <span class="sympad">PlusClient.Builder</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
+      <span class="normal">(Context context, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> connectionCallbacks, <a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">GooglePlayServicesClient.OnConnectionFailedListener</a> connectionFailedListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1293,7 +1318,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a>
       </span>
       <span class="sympad">setAccountName</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> accountName)</span>
+      <span class="normal">(String accountName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1322,6 +1347,55 @@
 </div>
 
 
+<A NAME="setActions(java.lang.String...)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a>
+      </span>
+      <span class="sympad">setActions</span>
+      <span class="normal">(String... actions)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Specify which user's app activity types can be written to Google.
+ This must be used with the <code><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_LOGIN">PLUS_LOGIN</a></code> OAuth 2.0 scope.
+
+ <p>
+ See <a href="https://developers.google.com/+/api/moment-types">Types of app
+ activity</a> for the full list of valid app activity types. Example usage:
+ <pre>
+      plusClientBuilder.setActions(
+          "http://schemas.google.com/AddActivity",
+          "http://schemas.google.com/BuyActivity");
+ </pre></p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>actions</td>
+          <td>The user's app activity types that can be written to Google.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
 <A NAME="setScopes(java.lang.String...)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1335,7 +1409,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a>
       </span>
       <span class="sympad">setScopes</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String...</a> scopes)</span>
+      <span class="normal">(String... scopes)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1379,7 +1453,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a>
       </span>
       <span class="sympad">setVisibleActivities</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String...</a> visibleActivities)</span>
+      <span class="normal">(String... actions)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1389,27 +1463,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Specify which user's app activity types can be written to Google.
- This must be used with the <code><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_LOGIN">PLUS_LOGIN</a></code> OAuth 2.0 scope.
-
- <p>
- See <a href="https://developers.google.com/+/api/moment-types">Types of app
- activity</a> for the full list of valid app activity types. Example usage:
- <pre>
-      plusClientBuilder.setVisibleActivities(
-          "http://schemas.google.com/AddActivity",
-          "http://schemas.google.com/BuyActivity");
- </pre></p></div>
-  <div class="jd-tagdata">
-      <h5 class="jd-tagtitle">Parameters</h5>
-      <table class="jd-tagtable">
-        <tr>
-          <th>visibleActivities</td>
-          <td>The user's app activity types that can be written to Google.
-</td>
-        </tr>
-      </table>
-  </div>
+  <div class="jd-tagdata jd-tagdescr"><p>See <code><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html#setActions(java.lang.String...)">setActions(String)</a></code>.
+</p></div>
 
     </div>
 </div>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html
index 2d9abf1..0a5c0eb 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusClient.OnAccessRevokedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html
index 89a5ac5..0c2838a 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusClient.OnMomentsLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -755,7 +762,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html#onMomentsLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.moments.MomentBuffer, java.lang.String, java.lang.String)">onMomentsLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html">MomentBuffer</a> momentBuffer, <a href="/reference/java/lang/String.html">String</a> nextPageToken, <a href="/reference/java/lang/String.html">String</a> updated)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html#onMomentsLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.moments.MomentBuffer, java.lang.String, java.lang.String)">onMomentsLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html">MomentBuffer</a> momentBuffer, String nextPageToken, String updated)</nobr>
         
   </td></tr>
 
@@ -821,7 +828,7 @@
         void
       </span>
       <span class="sympad">onMomentsLoaded</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html">MomentBuffer</a> momentBuffer, <a href="/reference/java/lang/String.html">String</a> nextPageToken, <a href="/reference/java/lang/String.html">String</a> updated)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html">MomentBuffer</a> momentBuffer, String nextPageToken, String updated)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html
index dd35c12..958049b 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusClient.OnPeopleLoadedListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -688,7 +695,7 @@
 
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">See Also</h5>
-      <ul class="nolist"><li><code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)">loadPeople(PlusClient.OnPeopleLoadedListener, int)</a></code></li>
+      <ul class="nolist"><li><code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople(PlusClient.OnPeopleLoadedListener, String...)</a></code></li>
       </ul>
   </div>
 
@@ -757,7 +764,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html#onPeopleLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.people.PersonBuffer, java.lang.String)">onPeopleLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/people/PersonBuffer.html">PersonBuffer</a> personBuffer, <a href="/reference/java/lang/String.html">String</a> nextPageToken)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html#onPeopleLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.people.PersonBuffer, java.lang.String)">onPeopleLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/people/PersonBuffer.html">PersonBuffer</a> personBuffer, String nextPageToken)</nobr>
         
   </td></tr>
 
@@ -823,7 +830,7 @@
         void
       </span>
       <span class="sympad">onPeopleLoaded</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/people/PersonBuffer.html">PersonBuffer</a> personBuffer, <a href="/reference/java/lang/String.html">String</a> nextPageToken)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/people/PersonBuffer.html">PersonBuffer</a> personBuffer, String nextPageToken)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -839,7 +846,7 @@
       <table class="jd-tagtable">
         <tr>
           <th>status</td>
-          <td>The resulting connection status of the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)">loadPeople(PlusClient.OnPeopleLoadedListener, int)</a></code> or
+          <td>The resulting connection status of the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople(PlusClient.OnPeopleLoadedListener, String...)</a></code> or
             <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople(PlusClient.OnPeopleLoadedListener, int, String)</a></code> request.</td>
         </tr>
         <tr>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html
deleted file mode 100644
index 4de4db7..0000000
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html
+++ /dev/null
@@ -1,897 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>PlusClient.OnPersonLoadedListener | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-<body class="gc-documentation google
-  develop" itemscope itemtype="http://schema.org/Article">
-  <div id="doc-api-level" class="" style="display:none"></div>
-  <a name="top"></a>
-
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo">
-          <a href="/index.html">
-            <img src="/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
-          </a>
-          <div class="btn-quicknav" id="btn-quicknav">
-          	<a href="#" class="arrow-inactive">Quicknav</a>
-			      <a href="#" class="arrow-active">Quicknav</a>
-          </div>
-          </div>
-            <ul class="nav-x col-9">
-                <li class="design">
-                  <a href="/design/index.html"
-                  zh-tw-lang="設計"
-                  zh-cn-lang="设计"
-                  ru-lang="Проектирование"
-                  ko-lang="디자인"
-                  ja-lang="設計"
-                  es-lang="Diseñar"               
-                  >Design</a></li>
-                <li class="develop"><a href="/develop/index.html"
-                  zh-tw-lang="開發"
-                  zh-cn-lang="开发"
-                  ru-lang="Разработка"
-                  ko-lang="개발"
-                  ja-lang="開発"
-                  es-lang="Desarrollar"               
-                  >Develop</a></li>
-                <li class="distribute last"><a href="/distribute/index.html"
-                  zh-tw-lang="發佈"
-                  zh-cn-lang="分发"
-                  ru-lang="Распространение"
-                  ko-lang="배포"
-                  ja-lang="配布"
-                  es-lang="Distribuir"               
-                  >Distribute</a></li>
-            </ul>
-            
-            <!-- New Search -->
-            <div class="menu-container">
-            <div class="moremenu">
-    <div id="more-btn"></div>
-  </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div>
-    <div class="bottom"></div>
-  </div>
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  </div>
-  <!-- /New Search>
-          
-          
-          <!-- Expanded quicknav -->
-           <div id="quicknav" class="col-9">
-                <ul>
-                    <li class="design">
-                      <ul>
-                        <li><a href="/design/index.html">Get Started</a></li>
-                        <li><a href="/design/style/index.html">Style</a></li>
-                        <li><a href="/design/patterns/index.html">Patterns</a></li>
-                        <li><a href="/design/building-blocks/index.html">Building Blocks</a></li>
-                        <li><a href="/design/downloads/index.html">Downloads</a></li>
-                        <li><a href="/design/videos/index.html">Videos</a></li>
-                      </ul>
-                    </li>
-                    <li class="develop">
-                      <ul>
-                        <li><a href="/training/index.html"
-                          zh-tw-lang="訓練課程"
-                          zh-cn-lang="培训"
-                          ru-lang="Курсы"
-                          ko-lang="교육"
-                          ja-lang="トレーニング"
-                          es-lang="Capacitación"               
-                          >Training</a></li>
-                        <li><a href="/guide/components/index.html"
-                          zh-tw-lang="API 指南"
-                          zh-cn-lang="API 指南"
-                          ru-lang="Руководства по API"
-                          ko-lang="API 가이드"
-                          ja-lang="API ガイド"
-                          es-lang="Guías de la API"               
-                          >API Guides</a></li>
-                        <li><a href="/reference/packages.html"
-                          zh-tw-lang="參考資源"
-                          zh-cn-lang="参考"
-                          ru-lang="Справочник"
-                          ko-lang="참조문서"
-                          ja-lang="リファレンス"
-                          es-lang="Referencia"               
-                          >Reference</a></li>
-                        <li><a href="/tools/index.html"
-                          zh-tw-lang="相關工具"
-                          zh-cn-lang="工具"
-                          ru-lang="Инструменты"
-                          ko-lang="도구"
-                          ja-lang="ツール"
-                          es-lang="Herramientas"               
-                          >Tools</a>
-                          <ul><li><a href="/sdk/index.html">Get the SDK</a></li></ul>
-                        </li>
-                        <li><a href="/google/index.html">Google Services</a>
-                        </li>
-                      </ul>
-                    </li>
-                    <li class="distribute last">
-                      <ul>
-                        <li><a href="/distribute/index.html">Google Play</a></li>
-                        <li><a href="/distribute/googleplay/publish/index.html">Publishing</a></li>
-                        <li><a href="/distribute/googleplay/promote/index.html">Promoting</a></li>
-                        <li><a href="/distribute/googleplay/quality/index.html">App Quality</a></li>
-                        <li><a href="/distribute/googleplay/spotlight/index.html">Spotlight</a></li>
-                        <li><a href="/distribute/open.html">Open Distribution</a></li>
-                      </ul>
-                    </li>
-                </ul>
-          </div>
-          <!-- /Expanded quicknav -->
-        </div>
-    </div>
-    <!-- /Header -->
-    
-    
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-    
-    
-  
-    <!-- Secondary x-nav -->
-    <div id="nav-x">
-        <div class="wrap">
-            <ul class="nav-x col-9 develop" style="width:100%">
-                <li class="training"><a href="/training/index.html"
-                  zh-tw-lang="訓練課程"
-                  zh-cn-lang="培训"
-                  ru-lang="Курсы"
-                  ko-lang="교육"
-                  ja-lang="トレーニング"
-                  es-lang="Capacitación"               
-                  >Training</a></li>
-                <li class="guide"><a href="/guide/components/index.html"
-                  zh-tw-lang="API 指南"
-                  zh-cn-lang="API 指南"
-                  ru-lang="Руководства по API"
-                  ko-lang="API 가이드"
-                  ja-lang="API ガイド"
-                  es-lang="Guías de la API"               
-                  >API Guides</a></li>
-                <li class="reference"><a href="/reference/packages.html"
-                  zh-tw-lang="參考資源"
-                  zh-cn-lang="参考"
-                  ru-lang="Справочник"
-                  ko-lang="참조문서"
-                  ja-lang="リファレンス"
-                  es-lang="Referencia"               
-                  >Reference</a></li>
-                <li class="tools"><a href="/tools/index.html"
-                  zh-tw-lang="相關工具"
-                  zh-cn-lang="工具"
-                  ru-lang="Инструменты"
-                  ko-lang="도구"
-                  ja-lang="ツール"
-                  es-lang="Herramientas"
-                  >Tools</a></li>
-                <li class="google"><a href="/google/index.html"
-                  >Google Services</a>
-                </li>
-            </ul>
-        </div>
-        
-    </div>
-    <!-- /Sendondary x-nav -->
-  
-
-
-
-
-  
-
-
-  
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/index.html">
-          <span class="en">Overview</span>
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/games.html">
-          <span class="en">Games</span>
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/location.html">
-          <span class="en">Location</span>
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/plus.html">
-          <span class="en">Google+</span>
-                </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/maps.html">
-          <span class="en">Google Maps</span>
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/google/play-services/auth.html">
-          <span class="en">Authorization</span>
-      </a></div>
-  </li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/play-services/index.html">
-      <span class="en">Google Play Services</span></a>
-    </div>
-    <ul>
-      <li><a href="/google/play-services/setup.html">
-          <span class="en">Setup</span></a>
-      </li>
-      <li id="gms-tree-list" class="nav-section">
-        <div class="nav-section-header">
-          <a href="/reference/gms-packages.html">
-            <span class="en">Reference</span>
-          </a>
-        <div>
-      </li>
-    </ul>
-  </li>
-
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/play/billing/index.html">
-      <span class="en">Google Play In-app Billing</span></a>
-    </div>
-    <ul>
-      <li><a href="/google/play/billing/billing_overview.html">
-              <span class="en">Overview</span></a>
-      </li>
-      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/api.html">
-              <span class="en">Version 3 API</span></a></div>
-              <ul>
-              <li><a href="/google/play/billing/billing_integrate.html">
-              <span class="en">Implementing the API</span></a></li>
-              <li><a href="/google/play/billing/billing_reference.html">
-              <span class="en">Reference</span></a></li>
-              </ul>
-      </li>
-      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/v2/api.html">
-              <span class="en">Version 2 API</span></a></div>
-              <ul>
-              <li><a href="/google/play/billing/v2/billing_integrate.html">
-              <span class="en">Implementing the API</span></a></li>
-              <li><a href="/google/play/billing/v2/billing_subscriptions.html">
-              <span class="en">Subscriptions</span></a></li>
-              <li><a href="/google/play/billing/v2/billing_reference.html">
-              <span class="en">Reference</span></a></li>
-              </ul>
-      </li>
-      <li><a href="/google/play/billing/billing_subscriptions.html">
-              <span class="en">Subscriptions</span></a>
-      </li>
-      <li><a href="/google/play/billing/billing_best_practices.html">
-              <span class="en">Security and Design</span></a>
-      </li>
-      <li><a href="/google/play/billing/billing_testing.html">
-              <span class="en">Testing In-app Billing</span></a>
-      </li>
-      <li><a href="/google/play/billing/billing_admin.html">
-              <span class="en">Administering In-app Billing</span></a>
-      </li>
-      <li><a href="/google/play/billing/gp-purchase-status-api.html">
-              <span class="en">Purchase Status API</span></a>
-      </li>
-      <li><a href="/google/play/billing/versions.html">
-              <span class="en">Version Notes</span></a>
-      </li>
-    </ul>
-  </li>
-
-
-
-  <li class="nav-section">
-      <div class="nav-section-header"><a href="/google/gcm/index.html">
-        <span class="en">Google Cloud Messaging</span></a>
-      </div>
-      <ul>
-        <li><a href="/google/gcm/gs.html">
-            <span class="en">Getting Started</span></a>
-        </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
-        </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
-        </li>
-        <li><a href="/google/gcm/notifications.html">
-              <span class="en">User Notifications</span></a>
-        </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
-        <li><a href="/google/gcm/adv.html">
-            <span class="en">Advanced Topics</span></a>
-        </li>
-        <li><a href="/google/gcm/c2dm.html">
-            <span class="en">Migration</span></a>
-        </li>
-        <li id="gcm-tree-list" class="nav-section">
-          <div class="nav-section-header">
-            <a href="/reference/gcm-packages.html">
-              <span class="en">Reference</span>
-            </a>
-          <div>
-        </li>
-      </ul>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/play/dist.html">
-      <span class="en">Google Play Distribution</span></a>
-    </div>
-    <ul>
-      <li><a href="/google/play/filters.html">
-          <span class="en">Filters on Google Play</span></a>
-      </li>
-
-      <li><a href="/google/play/publishing/multiple-apks.html">
-          <span class="en">Multiple APK Support</span></a>
-      </li>
-      <li><a href="/google/play/expansion-files.html">
-          <span class="en">APK Expansion Files</span></a>
-      </li>
-      <li class="nav-section">
-        <div class="nav-section-header"><a href="/google/play/licensing/index.html">
-          <span class="en">Application Licensing</span></a>
-        </div>
-        <ul>
-          <li><a href="/google/play/licensing/overview.html">
-              <span class="en">Licensing Overview</span></a>
-          </li>
-          <li><a href="/google/play/licensing/setting-up.html">
-              <span class="en">Setting Up for Licensing</span></a>
-          </li>
-          <li><a href="/google/play/licensing/adding-licensing.html">
-              <span class="en">Adding Licensing to Your App</span></a>
-          </li>
-          <li><a href="/google/play/licensing/licensing-reference.html">
-              <span class="en">Licensing Reference</span></a>
-          </li>
-        </ul>
-      </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/google/backup/index.html">
-      Android Backup Service</a>
-    </div>
-    <ul>
-      <li><a href="/google/backup/signup.html">
-          Register</a>
-      </li>
-    </ul>
-  </li>
-
-  </ul>
-
-</li>
-
-
-
-</ul>
-
-<script type="text/javascript">
-<!--
-    buildToggleLists();
-    changeNavLang(getLangPref());
-//-->
-</script>
-
-
-        
-
-      </div>
-      <script type="text/javascript">
-       showGoogleRefTree();
-    
-      </script>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-     
-
-
-
-<div class="col-12"  id="doc-col">
-
-<div id="api-info-block">
-
-
-
-
-<div class="sum-details-links">
-
-</div><!-- end sum-details-links -->
-<div class="api-level">
-  
-  
-  
-
-</div>
-</div><!-- end api-info-block -->
-
-
-<!-- ======== START OF CLASS DATA ======== -->
-
-<div id="jd-header">
-    public
-    static 
-     
-    
-    interface
-<h1 itemprop="name">PlusClient.OnPersonLoadedListener</h1>
-
-
-
-  
-  
-  
-
-
-</div><!-- end header -->
-
-<div id="naMessage"></div>
-
-<div id="jd-content" class="api apilevel-">
-<table class="jd-inheritance-table">
-
-
-    <tr>
-         	
-        <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.plus.PlusClient.OnPersonLoadedListener</td>
-    </tr>
-    
-
-</table>
-
-
-
-
-
-
-
-<div class="jd-descr">
-<p>
-  <p class="caution"><strong>
-      This interface is deprecated.</strong><br/>
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a></code>.
-
-  </p>
-
-
-
-
-
-</div><!-- jd-descr -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class="jd-descr">
-
-
-<h2>Summary</h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<!-- ========== METHOD SUMMARY =========== -->
-<table id="pubmethods" class="jd-sumtable"><tr><th colspan="12">Public Methods</th></tr>
-
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html#onPersonLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.people.Person)">onPersonLoaded</a></span>(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a> person)</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html#onPeopleLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.people.PersonBuffer, java.lang.String)">onPeopleLoaded(ConnectionResult, PersonBuffer, String)</a></code>.
-</em></div>
-  
-  </td></tr>
-
-
-
-</table>
-
-
-
-
-
-
-
-</div><!-- jd-descr (summary) -->
-
-<!-- Details -->
-
-
-
-
-
-
-
-
-<!-- XML Attributes -->
-
-
-<!-- Enum Values -->
-
-
-<!-- Constants -->
-
-
-<!-- Fields -->
-
-
-<!-- Public ctors -->
-
-
-
-<!-- ========= CONSTRUCTOR DETAIL ======== -->
-<!-- Protected ctors -->
-
-
-
-<!-- ========= METHOD DETAIL ======== -->
-<!-- Public methdos -->
-
-<h2>Public Methods</h2>
-
-
-
-<A NAME="onPersonLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.people.Person)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-        abstract 
-         
-        void
-      </span>
-      <span class="sympad">onPersonLoaded</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a> status, <a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a> person)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html#onPeopleLoaded(com.google.android.gms.common.ConnectionResult, com.google.android.gms.plus.model.people.PersonBuffer, java.lang.String)">onPeopleLoaded(ConnectionResult, PersonBuffer, String)</a></code>.
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
-
-
-
-<!-- ========= METHOD DETAIL ======== -->
-
-
-
-<!-- ========= END OF CLASS DATA ========= -->
-<A NAME="navbar_top"></A>
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is licensed under <a
-  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
-  For details and restrictions, see the <a href="/license.html">
-  Content License</a>.
-  </div>
-  <div id="build_info">
-    
-<script src="/timestamp.js" type="text/javascript"></script>
-<script>document.write(BUILD_TIMESTAMP)</script>
-
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div> <!-- jd-content -->
-
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-</body>
-</html>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.OrderBy.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.OrderBy.html
index 43ed007..13a0675 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.OrderBy.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusClient.OrderBy.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusClient.OrderBy | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusClient.html b/docs/html/reference/com/google/android/gms/plus/PlusClient.html
index 1221e15..40c7253 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusClient.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusClient.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusClient | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -691,7 +698,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -843,21 +850,6 @@
          
         
         interface</nobr></td>
-      <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html">PlusClient.OnPersonLoadedListener</a></td>
-      <td class="jd-descrcol" width="100%"><em>
-      This interface is deprecated.
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a></code>.
-</em>&nbsp;</td>
-    </tr>
-    
-    
-    <tr class=" api apilevel-" >
-      <td class="jd-typecol"><nobr>
-        
-         
-         
-        
-        interface</nobr></td>
       <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.OrderBy.html">PlusClient.OrderBy</a></td>
       <td class="jd-descrcol" width="100%">Constants to declare the order to return people in.&nbsp;</td>
     </tr>
@@ -882,9 +874,9 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.html#KEY_REQUEST_VISIBLE_ACTIVITIES">KEY_REQUEST_VISIBLE_ACTIVITIES</a></td>
-        <td class="jd-descrcol" width="100%">Bundle key for specifying which user's app activity (moment) types can be written to Google.</td>
+        <td class="jd-descrcol" width="100%">See <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_ACTIONS">KEY_REQUEST_ACTIONS</a></code>.</td>
     </tr>
     
     
@@ -973,7 +965,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#getAccountName()">getAccountName</a></span>()</nobr>
@@ -1087,7 +1079,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadMoments(com.google.android.gms.plus.PlusClient.OnMomentsLoadedListener, int, java.lang.String, android.net.Uri, java.lang.String, java.lang.String)">loadMoments</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html">PlusClient.OnMomentsLoadedListener</a> listener, int maxResults, <a href="/reference/java/lang/String.html">String</a> pageToken, <a href="/reference/android/net/Uri.html">Uri</a> targetUrl, <a href="/reference/java/lang/String.html">String</a> type, <a href="/reference/java/lang/String.html">String</a> userId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadMoments(com.google.android.gms.plus.PlusClient.OnMomentsLoadedListener, int, java.lang.String, android.net.Uri, java.lang.String, java.lang.String)">loadMoments</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html">PlusClient.OnMomentsLoadedListener</a> listener, int maxResults, String pageToken, Uri targetUrl, String type, String userId)</nobr>
         
         <div class="jd-descrdiv">List all of the moments for a particular user.</div>
   
@@ -1123,7 +1115,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.util.Collection<java.lang.String>)">loadPeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, <a href="/reference/java/util/Collection.html">Collection</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; personIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.util.Collection<java.lang.String>)">loadPeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, Collection&lt;String&gt; personIds)</nobr>
         
         <div class="jd-descrdiv">Loads a list of specified people.</div>
   
@@ -1141,7 +1133,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String...</a> personIds)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, String... personIds)</nobr>
         
         <div class="jd-descrdiv">Helper method for
  <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.util.Collection<java.lang.String>)">loadPeople(PlusClient.OnPeopleLoadedListener, java.util.Collection)</a></code>.</div>
@@ -1160,88 +1152,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)">loadPeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int collection)</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople(PlusClient.OnPeopleLoadedListener, int, String)</a></code>.
-</em></div>
-  
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, int, int, java.lang.String)">loadPeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int collection, int orderBy, int maxResults, <a href="/reference/java/lang/String.html">String</a> pageToken)</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople(PlusClient.OnPeopleLoadedListener, int, String)</a></code>.
-</em></div>
-  
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPerson(com.google.android.gms.plus.PlusClient.OnPersonLoadedListener, java.lang.String)">loadPerson</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html">PlusClient.OnPersonLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> userId)</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.util.Collection<java.lang.String>)">loadPeople(PlusClient.OnPeopleLoadedListener, java.util.Collection)</a></code>.
-</em></div>
-  
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String)">loadVisiblePeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> pageToken)</nobr>
-        
-        <div class="jd-descrdiv">Loads the list of visible people in the user's circles.</div>
-  
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            
-            
-            
-            
-            
-            void</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int orderBy, <a href="/reference/java/lang/String.html">String</a> pageToken)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String)">loadVisiblePeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, String pageToken)</nobr>
         
         <div class="jd-descrdiv">Loads the list of visible people in the user's circles.</div>
   
@@ -1259,6 +1170,24 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int orderBy, String pageToken)</nobr>
+        
+        <div class="jd-descrdiv">Loads the list of visible people in the user's circles.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#registerConnectionCallbacks(com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks)">registerConnectionCallbacks</a></span>(<a href="/reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">GooglePlayServicesClient.ConnectionCallbacks</a> listener)</nobr>
         
         <div class="jd-descrdiv">Registers a listener to receive connection events from this <code>GooglePlayServicesClient</code>.</div>
@@ -1267,7 +1196,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1286,7 +1215,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1296,7 +1225,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#removeMoment(java.lang.String)">removeMoment</a></span>(<a href="/reference/java/lang/String.html">String</a> momentId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusClient.html#removeMoment(java.lang.String)">removeMoment</a></span>(String momentId)</nobr>
         
         <div class="jd-descrdiv">Delete a moment.</div>
   
@@ -1304,7 +1233,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1322,7 +1251,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1340,7 +1269,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1358,7 +1287,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             
             
@@ -1398,7 +1327,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1417,7 +1346,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1436,7 +1365,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1465,7 +1394,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1529,7 +1458,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1838,7 +1767,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_REQUEST_VISIBLE_ACTIVITIES
     </h4>
@@ -1850,23 +1779,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Bundle key for specifying which user's app activity (moment) types can be written to Google.
- The list of activity types are represented as a space-separated string passed in the extras
- Bundle when calling <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getToken(Context, String, String, Bundle)</a></code>.
-
- <p>
- This bundle key should be included in the extras Bundle when calling
- <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">getToken(Context, String, String, Bundle)</a></code> and should only be used when
- requesting the <code><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_LOGIN">PLUS_LOGIN</a></code> OAuth 2.0 scope.
-
- See <a href="https://developers.google.com/+/api/moment-types">Types of moments</a>
- for the full list of valid activity types. Example usage:
- <pre>
-     Bundle bundle = new Bundle();
-     bundle.putString(PlusClient.KEY_REQUEST_VISIBLE_ACTIVITIES,
-              "http://schemas.google.com/AddActivity http://schemas.google.com/BuyActivity");
-     String token = GoogleAuthUtil.getToken(context, accountName, Scopes.PLUS_LOGIN, bundle);
- </pre>
+  <div class="jd-tagdata jd-tagdescr"><p>See <code><a href="/reference/com/google/android/gms/auth/GoogleAuthUtil.html#KEY_REQUEST_ACTIONS">KEY_REQUEST_ACTIONS</a></code>.
 </p></div>
 
     
@@ -2015,7 +1928,7 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAccountName</span>
       <span class="normal">()</span>
@@ -2039,7 +1952,7 @@
       <h5 class="jd-tagtitle">Throws</h5>
       <table class="jd-tagtable">  
         <tr>
-            <th><a href="/reference/java/lang/SecurityException.html">SecurityException</a></td>
+            <th>SecurityException</td>
             <td>If your app doesn't have the
          <code><a href="/reference/android/Manifest.permission.html#GET_ACCOUNTS">GET_ACCOUNTS</a></code> permission.
 </td>
@@ -2265,7 +2178,7 @@
         void
       </span>
       <span class="sympad">loadMoments</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html">PlusClient.OnMomentsLoadedListener</a> listener, int maxResults, <a href="/reference/java/lang/String.html">String</a> pageToken, <a href="/reference/android/net/Uri.html">Uri</a> targetUrl, <a href="/reference/java/lang/String.html">String</a> type, <a href="/reference/java/lang/String.html">String</a> userId)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html">PlusClient.OnMomentsLoadedListener</a> listener, int maxResults, String pageToken, Uri targetUrl, String type, String userId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2380,7 +2293,7 @@
         void
       </span>
       <span class="sympad">loadPeople</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, <a href="/reference/java/util/Collection.html">Collection</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; personIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, Collection&lt;String&gt; personIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2432,7 +2345,7 @@
         void
       </span>
       <span class="sympad">loadPeople</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String...</a> personIds)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, String... personIds)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2450,108 +2363,6 @@
 </div>
 
 
-<A NAME="loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-         
-         
-        void
-      </span>
-      <span class="sympad">loadPeople</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int collection)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople(PlusClient.OnPeopleLoadedListener, int, String)</a></code>.
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
-<A NAME="loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, int, int, java.lang.String)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-         
-         
-        void
-      </span>
-      <span class="sympad">loadPeople</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int collection, int orderBy, int maxResults, <a href="/reference/java/lang/String.html">String</a> pageToken)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int, java.lang.String)">loadVisiblePeople(PlusClient.OnPeopleLoadedListener, int, String)</a></code>.
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
-<A NAME="loadPerson(com.google.android.gms.plus.PlusClient.OnPersonLoadedListener, java.lang.String)"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-         
-         
-        void
-      </span>
-      <span class="sympad">loadPerson</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html">PlusClient.OnPersonLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> userId)</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.util.Collection<java.lang.String>)">loadPeople(PlusClient.OnPeopleLoadedListener, java.util.Collection)</a></code>.
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
 <A NAME="loadVisiblePeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String)"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -2565,7 +2376,7 @@
         void
       </span>
       <span class="sympad">loadVisiblePeople</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, <a href="/reference/java/lang/String.html">String</a> pageToken)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, String pageToken)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2581,7 +2392,7 @@
  <p>
  Each <code><a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a></code> will contain the <code>id</code>, <code>displayName</code>,
  <code>image</code>, <code>objectType</code>, and <code>url</code> fields populated.
- To retrieve additional profile data, use the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)">loadPeople(PlusClient.OnPeopleLoadedListener, int)</a></code> method.
+ To retrieve additional profile data, use the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople(PlusClient.OnPeopleLoadedListener, String...)</a></code> method.
  <p>
  This method requires the <code><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_LOGIN">PLUS_LOGIN</a></code>
  OAuth 2.0 scope specified in the <code><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a></code></p></div>
@@ -2614,7 +2425,7 @@
         void
       </span>
       <span class="sympad">loadVisiblePeople</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int orderBy, <a href="/reference/java/lang/String.html">String</a> pageToken)</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a> listener, int orderBy, String pageToken)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2630,7 +2441,7 @@
  <p>
  Each <code><a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a></code> will contain the <code>id</code>, <code>displayName</code>,
  <code>image</code>, <code>objectType</code>, and <code>url</code> fields populated.
- To retrieve additional profile data, use the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)">loadPeople(PlusClient.OnPeopleLoadedListener, int)</a></code> method.
+ To retrieve additional profile data, use the <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople(PlusClient.OnPeopleLoadedListener, String...)</a></code> method.
  <p>
  This method requires the <code><a href="/reference/com/google/android/gms/common/Scopes.html#PLUS_LOGIN">PLUS_LOGIN</a></code>
  OAuth 2.0 scope specified in the <code><a href="/reference/com/google/android/gms/plus/PlusClient.Builder.html">PlusClient.Builder</a></code></p></div>
@@ -2773,7 +2584,7 @@
         void
       </span>
       <span class="sympad">removeMoment</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> momentId)</span>
+      <span class="normal">(String momentId)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html b/docs/html/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html
new file mode 100644
index 0000000..a8fb8dc
--- /dev/null
+++ b/docs/html/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html
@@ -0,0 +1,1381 @@
+<!DOCTYPE html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<html>
+<head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
+
+<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
+<title>PlusOneButton.DefaultOnPlusOneClickListener | Android Developers</title>
+
+<!-- STYLESHEETS -->
+<link rel="stylesheet"
+href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
+
+
+
+<!-- JAVASCRIPT -->
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
+<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
+<script type="text/javascript">
+  var toRoot = "/";
+  var devsite = false;
+</script>
+<script src="/assets/js/docs.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-5831155-1']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+</script>
+</head>
+<body class="gc-documentation google
+  develop" itemscope itemtype="http://schema.org/Article">
+  <div id="doc-api-level" class="" style="display:none"></div>
+  <a name="top"></a>
+
+<a name="top"></a>
+
+    <!-- Header -->
+    <div id="header">
+        <div class="wrap" id="header-wrap">
+          <div class="col-3 logo">
+          <a href="/index.html">
+            <img src="/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
+          </a>
+          <div class="btn-quicknav" id="btn-quicknav">
+          	<a href="#" class="arrow-inactive">Quicknav</a>
+			      <a href="#" class="arrow-active">Quicknav</a>
+          </div>
+          </div>
+            <ul class="nav-x col-9">
+                <li class="design">
+                  <a href="/design/index.html"
+                  zh-tw-lang="設計"
+                  zh-cn-lang="设计"
+                  ru-lang="Проектирование"
+                  ko-lang="디자인"
+                  ja-lang="設計"
+                  es-lang="Diseñar"               
+                  >Design</a></li>
+                <li class="develop"><a href="/develop/index.html"
+                  zh-tw-lang="開發"
+                  zh-cn-lang="开发"
+                  ru-lang="Разработка"
+                  ko-lang="개발"
+                  ja-lang="開発"
+                  es-lang="Desarrollar"               
+                  >Develop</a></li>
+                <li class="distribute last"><a href="/distribute/index.html"
+                  zh-tw-lang="發佈"
+                  zh-cn-lang="分发"
+                  ru-lang="Распространение"
+                  ko-lang="배포"
+                  ja-lang="配布"
+                  es-lang="Distribuir"               
+                  >Distribute</a></li>
+            </ul>
+            
+            <!-- New Search -->
+            <div class="menu-container">
+            <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
+  <div class="morehover" id="moremenu">
+    <div class="top"></div>
+    <div class="mid">
+      <div class="header">Links</div>
+      <ul>
+        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
+        <li><a href="/about/index.html">About Android</a></li>
+      </ul>
+      <div class="header">Android Sites</div>
+      <ul>
+        <li><a href="http://www.android.com">Android.com</a></li>
+        <li class="active"><a>Android Developers</a></li>
+        <li><a href="http://source.android.com">Android Open Source Project</a></li>
+      </ul>
+      
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
+
+
+      <br class="clearfix" />
+    </div>
+    <div class="bottom"></div>
+  </div>
+  <div class="search" id="search-container">
+    <div class="search-inner">
+      <div id="search-btn"></div>
+      <div class="left"></div>
+      <form onsubmit="return submit_search()">
+        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
+onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+onkeydown="return search_changed(event, true, '/')" 
+onkeyup="return search_changed(event, false, '/')" />
+      </form>
+      <div class="right"></div>
+        <a class="close hide">close</a>
+        <div class="left"></div>
+        <div class="right"></div>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper reference">
+    <div class="suggest-card reference no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper docs">
+    <div class="suggest-card dummy no-display">&nbsp;</div>
+    <div class="suggest-card develop no-display">
+      <ul class="search_filtered">
+      </ul>
+      <div class="child-card guides no-display">
+      </div>
+      <div class="child-card training no-display">
+      </div>
+    </div>
+    <div class="suggest-card design no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+    <div class="suggest-card distribute no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  </div>
+  <!-- /New Search>
+          
+          
+          <!-- Expanded quicknav -->
+           <div id="quicknav" class="col-9">
+                <ul>
+                    <li class="design">
+                      <ul>
+                        <li><a href="/design/index.html">Get Started</a></li>
+                        <li><a href="/design/style/index.html">Style</a></li>
+                        <li><a href="/design/patterns/index.html">Patterns</a></li>
+                        <li><a href="/design/building-blocks/index.html">Building Blocks</a></li>
+                        <li><a href="/design/downloads/index.html">Downloads</a></li>
+                        <li><a href="/design/videos/index.html">Videos</a></li>
+                      </ul>
+                    </li>
+                    <li class="develop">
+                      <ul>
+                        <li><a href="/training/index.html"
+                          zh-tw-lang="訓練課程"
+                          zh-cn-lang="培训"
+                          ru-lang="Курсы"
+                          ko-lang="교육"
+                          ja-lang="トレーニング"
+                          es-lang="Capacitación"               
+                          >Training</a></li>
+                        <li><a href="/guide/components/index.html"
+                          zh-tw-lang="API 指南"
+                          zh-cn-lang="API 指南"
+                          ru-lang="Руководства по API"
+                          ko-lang="API 가이드"
+                          ja-lang="API ガイド"
+                          es-lang="Guías de la API"               
+                          >API Guides</a></li>
+                        <li><a href="/reference/packages.html"
+                          zh-tw-lang="參考資源"
+                          zh-cn-lang="参考"
+                          ru-lang="Справочник"
+                          ko-lang="참조문서"
+                          ja-lang="リファレンス"
+                          es-lang="Referencia"               
+                          >Reference</a></li>
+                        <li><a href="/tools/index.html"
+                          zh-tw-lang="相關工具"
+                          zh-cn-lang="工具"
+                          ru-lang="Инструменты"
+                          ko-lang="도구"
+                          ja-lang="ツール"
+                          es-lang="Herramientas"               
+                          >Tools</a>
+                          <ul><li><a href="/sdk/index.html">Get the SDK</a></li></ul>
+                        </li>
+                        <li><a href="/google/index.html">Google Services</a>
+                        </li>
+                        
+                      </ul>
+                    </li>
+                    <li class="distribute last">
+                      <ul>
+                        <li><a href="/distribute/index.html">Google Play</a></li>
+                        <li><a href="/distribute/googleplay/publish/index.html">Publishing</a></li>
+                        <li><a href="/distribute/googleplay/promote/index.html">Promoting</a></li>
+                        <li><a href="/distribute/googleplay/quality/index.html">App Quality</a></li>
+                        <li><a href="/distribute/googleplay/spotlight/index.html">Spotlight</a></li>
+                        <li><a href="/distribute/open.html">Open Distribution</a></li>
+                      </ul>
+                    </li>
+                </ul>
+          </div>
+          <!-- /Expanded quicknav -->
+        </div>
+    </div>
+    <!-- /Header -->
+    
+    
+  <div id="searchResults" class="wrap" style="display:none;">
+          <h2 id="searchTitle">Results</h2>
+          <div id="leftSearchControl" class="search-control">Loading...</div>
+  </div>
+    
+    
+  
+    <!-- Secondary x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x col-9 develop" style="width:100%">
+                <li class="training"><a href="/training/index.html"
+                  zh-tw-lang="訓練課程"
+                  zh-cn-lang="培训"
+                  ru-lang="Курсы"
+                  ko-lang="교육"
+                  ja-lang="トレーニング"
+                  es-lang="Capacitación"               
+                  >Training</a></li>
+                <li class="guide"><a href="/guide/components/index.html"
+                  zh-tw-lang="API 指南"
+                  zh-cn-lang="API 指南"
+                  ru-lang="Руководства по API"
+                  ko-lang="API 가이드"
+                  ja-lang="API ガイド"
+                  es-lang="Guías de la API"               
+                  >API Guides</a></li>
+                <li class="reference"><a href="/reference/packages.html"
+                  zh-tw-lang="參考資源"
+                  zh-cn-lang="参考"
+                  ru-lang="Справочник"
+                  ko-lang="참조문서"
+                  ja-lang="リファレンス"
+                  es-lang="Referencia"               
+                  >Reference</a></li>
+                <li class="tools"><a href="/tools/index.html"
+                  zh-tw-lang="相關工具"
+                  zh-cn-lang="工具"
+                  ru-lang="Инструменты"
+                  ko-lang="도구"
+                  ja-lang="ツール"
+                  es-lang="Herramientas"
+                  >Tools</a></li>
+                <li class="google"><a href="/google/index.html"
+                  >Google Services</a>
+                </li>
+                
+            </ul>
+        </div>
+        
+    </div>
+    <!-- /Sendondary x-nav -->
+  
+
+
+
+
+  
+
+
+  
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
+
+
+
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/index.html">
+          <span class="en">Overview</span>
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/games.html">
+          <span class="en">Games</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/location.html">
+          <span class="en">Location</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/plus.html">
+          <span class="en">Google+</span>
+                </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/maps.html">
+          <span class="en">Google Maps</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/auth.html">
+          <span class="en">Authorization</span>
+      </a></div>
+  </li>
+
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play-services/index.html">
+      <span class="en">Google Play Services</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play-services/setup.html">
+          <span class="en">Setup</span></a>
+      </li>
+      <li id="gms-tree-list" class="nav-section">
+        <div class="nav-section-header">
+          <a href="/reference/gms-packages.html">
+            <span class="en">Reference</span>
+          </a>
+        <div>
+      </li>
+    </ul>
+  </li>
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/billing/index.html">
+      <span class="en">Google Play In-app Billing</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/billing/billing_overview.html">
+              <span class="en">Overview</span></a>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/api.html">
+              <span class="en">Version 3 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/v2/api.html">
+              <span class="en">Version 2 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/v2/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li><a href="/google/play/billing/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_best_practices.html">
+              <span class="en">Security and Design</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_testing.html">
+              <span class="en">Testing In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_admin.html">
+              <span class="en">Administering In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/gp-purchase-status-api.html">
+              <span class="en">Purchase Status API</span></a>
+      </li>
+      <li><a href="/google/play/billing/versions.html">
+              <span class="en">Version Notes</span></a>
+      </li>
+    </ul>
+  </li>
+
+
+
+  <li class="nav-section">
+      <div class="nav-section-header"><a href="/google/gcm/index.html">
+        <span class="en">Google Cloud Messaging</span></a>
+      </div>
+      <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
+        <li><a href="/google/gcm/gs.html">
+            <span class="en">Getting Started</span></a>
+        </li>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
+        </li>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
+        </li>
+        <li><a href="/google/gcm/notifications.html">
+              <span class="en">User Notifications</span></a>
+        </li>
+        <li><a href="/google/gcm/adv.html">
+            <span class="en">Advanced Topics</span></a>
+        </li>
+        <li><a href="/google/gcm/c2dm.html">
+            <span class="en">Migration</span></a>
+        </li>
+        <li id="gcm-tree-list" class="nav-section">
+          <div class="nav-section-header">
+            <a href="/reference/gcm-packages.html">
+              <span class="en">Reference</span>
+            </a>
+          <div>
+        </li>
+      </ul>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/dist.html">
+      <span class="en">Google Play Distribution</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/filters.html">
+          <span class="en">Filters on Google Play</span></a>
+      </li>
+
+      <li><a href="/google/play/publishing/multiple-apks.html">
+          <span class="en">Multiple APK Support</span></a>
+      </li>
+      <li><a href="/google/play/expansion-files.html">
+          <span class="en">APK Expansion Files</span></a>
+      </li>
+      <li class="nav-section">
+        <div class="nav-section-header"><a href="/google/play/licensing/index.html">
+          <span class="en">Application Licensing</span></a>
+        </div>
+        <ul>
+          <li><a href="/google/play/licensing/overview.html">
+              <span class="en">Licensing Overview</span></a>
+          </li>
+          <li><a href="/google/play/licensing/setting-up.html">
+              <span class="en">Setting Up for Licensing</span></a>
+          </li>
+          <li><a href="/google/play/licensing/adding-licensing.html">
+              <span class="en">Adding Licensing to Your App</span></a>
+          </li>
+          <li><a href="/google/play/licensing/licensing-reference.html">
+              <span class="en">Licensing Reference</span></a>
+          </li>
+        </ul>
+      </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/backup/index.html">
+      Android Backup Service</a>
+    </div>
+    <ul>
+      <li><a href="/google/backup/signup.html">
+          Register</a>
+      </li>
+    </ul>
+  </li>
+
+  </ul>
+
+</li>
+
+
+
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
+
+        
+
+      </div>
+      <script type="text/javascript">
+       showGoogleRefTree();
+    
+      </script>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+
+
+     
+
+
+
+<div class="col-12"  id="doc-col">
+
+<div id="api-info-block">
+
+
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+
+<div class="sum-details-links">
+
+Summary:
+
+
+
+
+
+
+
+
+
+  <a href="#pubctors">Ctors</a>
+  
+
+
+
+  &#124; <a href="#pubmethods">Methods</a>
+  
+
+
+
+  &#124; <a href="#inhmethods">Inherited Methods</a>
+
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+
+</div><!-- end sum-details-links -->
+<div class="api-level">
+  
+  
+  
+
+</div>
+</div><!-- end api-info-block -->
+
+
+<!-- ======== START OF CLASS DATA ======== -->
+
+<div id="jd-header">
+    protected
+     
+     
+    
+    class
+<h1 itemprop="name">PlusOneButton.DefaultOnPlusOneClickListener</h1>
+
+
+
+  
+    extends Object<br/>
+  
+  
+  
+
+  
+  
+      implements 
+      
+        View.OnClickListener 
+      
+        <a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> 
+      
+  
+  
+
+
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-">
+<table class="jd-inheritance-table">
+
+
+    <tr>
+         	
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.plus.PlusOneButton.DefaultOnPlusOneClickListener</td>
+    </tr>
+    
+
+</table>
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Class Overview</h2>
+<p itemprop="articleBody">This is an <code><a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a></code> that will proxy clicks to an
+ attached <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a></code>, or default to attempt to start
+ the intent using an <code><a href="/reference/android/app/Activity.html">Activity</a></code> context.
+
+ Important: The implementation of <code><a href="/">ERROR(/OnClickListener#onClick(android.view.View))</a></code>
+ used by DefaultOnPlusOneClickListener relies on the tag of this class'
+ PlusOneButtonView remaining unused.
+</p>
+
+
+
+
+
+</div><!-- jd-descr -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Summary</h2>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="pubctors" class="jd-sumtable"><tr><th colspan="12">Public Constructors</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html#PlusOneButton.DefaultOnPlusOneClickListener(com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)">PlusOneButton.DefaultOnPlusOneClickListener</a></span>(<a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> proxy)</nobr>
+        
+  </td></tr>
+
+
+
+</table>
+
+
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="pubmethods" class="jd-sumtable"><tr><th colspan="12">Public Methods</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html#onClick(android.view.View)">onClick</a></span>(View view)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html#onPlusOneClick(android.content.Intent)">onPlusOneClick</a></span>(Intent intent)</nobr>
+        
+        <div class="jd-descrdiv">Called when the +1 button is clicked.</div>
+  
+  </td></tr>
+
+
+
+</table>
+
+
+
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="inhmethods" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Methods</div></th></tr>
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-java.lang.Object" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-java.lang.Object-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  java.lang.Object
+
+<div id="inherited-methods-java.lang.Object">
+  <div id="inherited-methods-java.lang.Object-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-java.lang.Object-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clone</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">finalize</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            Class&lt;?&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getClass</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hashCode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">notify</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">notifyAll</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">toString</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>(long arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>(long arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.View.OnClickListener" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.View.OnClickListener-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.View.OnClickListener
+
+<div id="inherited-methods-android.view.View.OnClickListener">
+  <div id="inherited-methods-android.view.View.OnClickListener-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.View.OnClickListener-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onClick</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  <a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener</a>
+
+<div id="inherited-methods-com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener">
+  <div id="inherited-methods-com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html#onPlusOneClick(android.content.Intent)">onPlusOneClick</a></span>(Intent intent)</nobr>
+        
+        <div class="jd-descrdiv">Called when the +1 button is clicked.</div>
+  
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+</table>
+
+
+</div><!-- jd-descr (summary) -->
+
+<!-- Details -->
+
+
+
+
+
+
+
+
+<!-- XML Attributes -->
+
+
+<!-- Enum Values -->
+
+
+<!-- Constants -->
+
+
+<!-- Fields -->
+
+
+<!-- Public ctors -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<h2>Public Constructors</h2>
+
+
+
+<A NAME="PlusOneButton.DefaultOnPlusOneClickListener(com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        
+      </span>
+      <span class="sympad">PlusOneButton.DefaultOnPlusOneClickListener</span>
+      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> proxy)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<!-- Protected ctors -->
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methdos -->
+
+<h2>Public Methods</h2>
+
+
+
+<A NAME="onClick(android.view.View)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">onClick</span>
+      <span class="normal">(View view)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+<A NAME="onPlusOneClick(android.content.Intent)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">onPlusOneClick</span>
+      <span class="normal">(Intent intent)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Called when the +1 button is clicked.  Start the intent passed to this method
+ to display the +1 confirmation dialog <code><a href="/reference/android/app/Activity.html">Activity</a></code> with
+ <code><a href="/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)">startActivityForResult(Intent, int)</a></code>.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>intent</td>
+          <td>The intent to display the +1 confirmation dialog.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+
+
+
+<!-- ========= END OF CLASS DATA ========= -->
+<A NAME="navbar_top"></A>
+
+<div id="footer" class="wrap" >
+        
+
+  <div id="copyright">
+    
+  Except as noted, this content is licensed under <a
+  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
+  For details and restrictions, see the <a href="/license.html">
+  Content License</a>.
+  </div>
+  <div id="build_info">
+    
+<script src="/timestamp.js" type="text/javascript"></script>
+<script>document.write(BUILD_TIMESTAMP)</script>
+
+  </div>
+
+
+  <div id="footerlinks">
+    
+  <p>
+    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/support.html">Support</a>
+  </p>
+  </div>
+
+</div> <!-- end footer -->
+</div> <!-- jd-content -->
+
+</div><!-- end doc-content -->
+
+</div> <!-- end body-content --> 
+
+
+
+
+
+
+</body>
+</html>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html b/docs/html/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html
index a6370c5..03aa27e 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusOneButton.OnPlusOneClickListener | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -627,6 +634,25 @@
 
 <div class="sum-details-links">
 
+Summary:
+
+
+
+
+
+
+
+
+
+
+
+  <a href="#pubmethods">Methods</a>
+  
+
+
+
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+
 </div><!-- end sum-details-links -->
 <div class="api-level">
   
@@ -675,6 +701,39 @@
 
 
 
+<table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="12" style="border:none;margin:0;padding:0;">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="subclasses-indirect" class="jd-expando-trigger closed"
+          ><img id="subclasses-indirect-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>Known Indirect Subclasses
+
+  <div id="subclasses-indirect">
+      <div id="subclasses-indirect-list"
+              class="jd-inheritedlinks"
+              
+              >
+          
+            
+              <a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html">PlusOneButton.DefaultOnPlusOneClickListener</a>
+            
+          
+      </div>
+      <div id="subclasses-indirect-summary"
+              style="display: none;"
+              >
+  <table class="jd-sumtable-expando">
+        <tr class="alt-color api apilevel-" >
+              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html">PlusOneButton.DefaultOnPlusOneClickListener</a></td>
+              <td class="jd-descrcol" width="100%">This is an <code><a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a></code> that will proxy clicks to an
+ attached <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a></code>, or default to attempt to start
+ the intent using an <code><a href="/reference/android/app/Activity.html">Activity</a></code> context.&nbsp;</td>
+          </tr>
+  </table>
+      </div>
+  </div>
+</td></tr></table>
+
 
 <div class="jd-descr">
 
@@ -752,7 +811,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html#onPlusOneClick(android.content.Intent)">onPlusOneClick</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html#onPlusOneClick(android.content.Intent)">onPlusOneClick</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Called when the +1 button is clicked.</div>
   
@@ -820,7 +879,7 @@
         void
       </span>
       <span class="sympad">onPlusOneClick</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusOneButton.html b/docs/html/reference/com/google/android/gms/plus/PlusOneButton.html
index 6ee2886..96589fb 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusOneButton.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusOneButton.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusOneButton | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -628,6 +635,13 @@
    
   
   
+  
+  
+
+  
+   
+  
+  
    
   
   
@@ -720,6 +734,9 @@
   
 
 
+  &#124; <a href="#promethods">Protected Methods</a>
+  
+
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -756,7 +773,11 @@
   
 
   
-    extends <a href="/reference/android/view/ViewGroup.html">ViewGroup</a><br/>
+  
+  
+
+  
+    extends FrameLayout<br/>
   
   
   
@@ -776,7 +797,7 @@
 
     <tr>
          	
-        <td colspan="4" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -784,7 +805,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/android/view/View.html">android.view.View</a></td>
+        <td colspan="4" class="jd-inheritance-class-cell">android.view.View</td>
     </tr>
     
 
@@ -794,7 +815,7 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/android/view/ViewGroup.html">android.view.ViewGroup</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">android.view.ViewGroup</td>
     </tr>
     
 
@@ -806,6 +827,20 @@
         
             <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
          	
+        <td colspan="2" class="jd-inheritance-class-cell">android.widget.FrameLayout</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
         <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.plus.PlusOneButton</td>
     </tr>
     
@@ -867,6 +902,20 @@
          
          
         
+        class</nobr></td>
+      <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html">PlusOneButton.DefaultOnPlusOneClickListener</a></td>
+      <td class="jd-descrcol" width="100%">This is an <code><a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a></code> that will proxy clicks to an
+ attached <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a></code>, or default to attempt to start
+ the intent using an <code><a href="/reference/android/app/Activity.html">Activity</a></code> context.&nbsp;</td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+      <td class="jd-typecol"><nobr>
+        
+         
+         
+        
         interface</nobr></td>
       <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a></td>
       <td class="jd-descrcol" width="100%">A listener for +1 button clicks.&nbsp;</td>
@@ -915,26 +964,33 @@
     
     <tr class=" api apilevel-" >
         <td class="jd-typecol">int</td>
+        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#DEFAULT_ACTIVITY_REQUEST_CODE">DEFAULT_ACTIVITY_REQUEST_CODE</a></td>
+        <td class="jd-descrcol" width="100%">An empty ActivityRequestCode to serve as the default before the code has been assigned.</td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_MEDIUM">SIZE_MEDIUM</a></td>
         <td class="jd-descrcol" width="100%">The medium button size.</td>
     </tr>
     
     
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_SMALL">SIZE_SMALL</a></td>
         <td class="jd-descrcol" width="100%">The small button size.</td>
     </tr>
     
     
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_STANDARD">SIZE_STANDARD</a></td>
         <td class="jd-descrcol" width="100%">The standard button size.</td>
     </tr>
     
     
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_TALL">SIZE_TALL</a></td>
         <td class="jd-descrcol" width="100%">The tall button size.</td>
@@ -954,6 +1010,8 @@
   <div style="clear:left;">Inherited Constants</div></th></tr>
 
 
+
+
 <tr class="api apilevel-" >
 <td colspan="12">
 
@@ -1423,7 +1481,7 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol">VIEW_LOG_TAG</td>
         <td class="jd-descrcol" width="100%"></td>
     </tr>
@@ -1470,6 +1528,8 @@
 
 
 
+
+
 <tr class="api apilevel-" >
 <td colspan="12">
 
@@ -1492,7 +1552,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ALPHA</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1811,7 +1871,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1822,7 +1882,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1833,7 +1893,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">ROTATION_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1844,7 +1904,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">SCALE_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1855,7 +1915,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">SCALE_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1888,7 +1948,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">TRANSLATION_X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1899,7 +1959,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">TRANSLATION_Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1921,7 +1981,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">X</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1932,7 +1992,7 @@
           public
           static
           final
-          Property&lt;<a href="/reference/android/view/View.html">View</a>,&nbsp;<a href="/reference/java/lang/Float.html">Float</a>&gt;</nobr></td>
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
           <td class="jd-linkcol">Y</td>
           <td class="jd-descrcol" width="100%"></td>
       </tr>
@@ -1977,7 +2037,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#PlusOneButton(android.content.Context)">PlusOneButton</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#PlusOneButton(android.content.Context)">PlusOneButton</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Creates a +1 button of <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_STANDARD">SIZE_STANDARD</a></code> size with an
  <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#ANNOTATION_BUBBLE">ANNOTATION_BUBBLE</a></code> annotation.</div>
@@ -1996,7 +2056,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#PlusOneButton(android.content.Context, android.util.AttributeSet)">PlusOneButton</a></span>(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#PlusOneButton(android.content.Context, android.util.AttributeSet)">PlusOneButton</a></span>(Context context, AttributeSet attrs)</nobr>
         
         <div class="jd-descrdiv">Creates a +1 button of <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_STANDARD">SIZE_STANDARD</a></code> size with an
  <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#ANNOTATION_BUBBLE">ANNOTATION_BUBBLE</a></code> annotation.</div>
@@ -2028,7 +2088,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#initialize(com.google.android.gms.plus.PlusClient, java.lang.String, com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)">initialize</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient, <a href="/reference/java/lang/String.html">String</a> url, <a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> plusOneClickListener)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#initialize(java.lang.String, com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)">initialize</a></span>(String url, <a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> plusOneClickListener)</nobr>
         
         <div class="jd-descrdiv">Updates the +1 button with a client and URL.</div>
   
@@ -2046,7 +2106,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#initialize(com.google.android.gms.plus.PlusClient, java.lang.String, int)">initialize</a></span>(<a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient, <a href="/reference/java/lang/String.html">String</a> url, int activityRequestCode)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#initialize(java.lang.String, int)">initialize</a></span>(String url, int activityRequestCode)</nobr>
         
         <div class="jd-descrdiv">Updates the +1 button with a <code><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></code> and URL.</div>
   
@@ -2113,6 +2173,47 @@
 
 
 
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#getAnnotation(android.content.Context, android.util.AttributeSet)">getAnnotation</a></span>(Context context, AttributeSet attrs)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#getSize(android.content.Context, android.util.AttributeSet)">getSize</a></span>(Context context, AttributeSet attrs)</nobr>
+        
+  </td></tr>
+
+
+
+</table>
+
+
 
 
 
@@ -2124,13 +2225,391 @@
 
 <tr class="api apilevel-" >
 <td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.widget.FrameLayout" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.widget.FrameLayout-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  android.widget.FrameLayout
+
+<div id="inherited-methods-android.widget.FrameLayout">
+  <div id="inherited-methods-android.widget.FrameLayout-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.widget.FrameLayout-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawableStateChanged</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getConsiderGoneChildrenWhenMeasuring</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Drawable</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getForeground</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getForegroundGravity</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasureAllChildren</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">jumpDrawablesToCurrentState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityNodeInfo</span>(AccessibilityNodeInfo arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onLayout</span>(boolean arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onMeasure</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSizeChanged</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setForeground</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setForegroundGravity</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMeasureAllChildren</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">shouldDelayChildPressedState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
   <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewGroup" class="jd-expando-trigger closed"
           ><img id="inherited-methods-android.view.ViewGroup-trigger"
           src="/assets/images/triangle-closed.png"
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/view/ViewGroup.html">android.view.ViewGroup</a>
+  android.view.ViewGroup
 
 <div id="inherited-methods-android.view.ViewGroup">
   <div id="inherited-methods-android.view.ViewGroup-list"
@@ -2152,7 +2631,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addChildrenForAccessibility</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2168,7 +2647,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -2200,7 +2679,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addTouchables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2216,7 +2695,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2232,7 +2711,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -2248,7 +2727,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2264,7 +2743,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">addView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2280,7 +2759,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -2296,7 +2775,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2, boolean arg3)</nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2, boolean arg3)</nobr>
         
   </td></tr>
 
@@ -2312,7 +2791,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2328,7 +2807,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">attachLayoutAnimationParameters</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1, int arg2, int arg3)</nobr>
+        <span class="sympad">attachLayoutAnimationParameters</span>(View arg0, ViewGroup.LayoutParams arg1, int arg2, int arg3)</nobr>
         
   </td></tr>
 
@@ -2344,7 +2823,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">attachViewToParent</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg2)</nobr>
+        <span class="sympad">attachViewToParent</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
         
   </td></tr>
 
@@ -2360,7 +2839,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">bringChildToFront</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2392,7 +2871,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -2408,7 +2887,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">childDrawableStateChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2424,7 +2903,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">cleanupLayoutState</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">cleanupLayoutState</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2440,7 +2919,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clearChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2520,7 +2999,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">detachViewFromParent</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">detachViewFromParent</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -2568,7 +3047,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -2616,7 +3095,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -2632,7 +3111,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchFreezeSelfOnly</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchFreezeSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2648,7 +3127,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericFocusedEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2664,7 +3143,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericPointerEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2680,7 +3159,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2696,7 +3175,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2712,7 +3191,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEventPreIme</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2728,7 +3207,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyShortcutEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2744,7 +3223,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchRestoreInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2760,7 +3239,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchSaveInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2840,7 +3319,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchThawSelfOnly</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchThawSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -2856,7 +3335,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2872,7 +3351,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -2888,7 +3367,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchUnhandledMove</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2904,7 +3383,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -2968,7 +3447,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">drawChild</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1, long arg2)</nobr>
+        <span class="sympad">drawChild</span>(Canvas arg0, View arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -3000,7 +3479,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">endViewTransition</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">endViewTransition</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3013,7 +3492,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findFocus</span>()</nobr>
@@ -3032,7 +3511,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewsWithText</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, <a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg1, int arg2)</nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -3048,7 +3527,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">fitSystemWindows</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -3061,10 +3540,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusSearch</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -3080,7 +3559,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusableViewAvailable</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3096,7 +3575,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">gatherTransparentRegion</span>(<a href="/reference/android/graphics/Region.html">Region</a> arg0)</nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
         
   </td></tr>
 
@@ -3109,7 +3588,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
@@ -3125,10 +3604,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/util/AttributeSet.html">AttributeSet</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
         
   </td></tr>
 
@@ -3141,10 +3620,10 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">generateLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -3157,7 +3636,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getChildAt</span>(int arg0)</nobr>
@@ -3224,7 +3703,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildStaticTransformation</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/animation/Transformation.html">Transformation</a> arg1)</nobr>
+        <span class="sympad">getChildStaticTransformation</span>(View arg0, Transformation arg1)</nobr>
         
   </td></tr>
 
@@ -3240,7 +3719,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildVisibleRect</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, <a href="/reference/android/graphics/Point.html">Point</a> arg2)</nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
         
   </td></tr>
 
@@ -3269,7 +3748,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getFocusedChild</span>()</nobr>
@@ -3285,7 +3764,7 @@
             
             
             
-            <a href="/reference/android/view/animation/LayoutAnimationController.html">LayoutAnimationController</a></nobr>
+            LayoutAnimationController</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutAnimation</span>()</nobr>
@@ -3301,7 +3780,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.AnimationListener.html">Animation.AnimationListener</a></nobr>
+            Animation.AnimationListener</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutAnimationListener</span>()</nobr>
@@ -3384,7 +3863,7 @@
             int</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">indexOfChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">indexOfChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3400,7 +3879,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3413,10 +3892,10 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChildInParent</span>(int[] arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3544,7 +4023,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">measureChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">measureChild</span>(View arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -3560,7 +4039,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">measureChildWithMargins</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        <span class="sympad">measureChildWithMargins</span>(View arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
         
   </td></tr>
 
@@ -3592,7 +4071,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">offsetDescendantRectToMyCoords</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">offsetDescendantRectToMyCoords</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3608,7 +4087,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">offsetRectIntoDescendantCoords</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">offsetRectIntoDescendantCoords</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3672,7 +4151,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInterceptHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onInterceptHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3688,7 +4167,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInterceptTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onInterceptTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -3720,7 +4199,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3736,7 +4215,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRequestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">onRequestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -3752,7 +4231,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">recomputeViewAttributes</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3800,7 +4279,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeDetachedView</span>(<a href="/reference/android/view/View.html">View</a> arg0, boolean arg1)</nobr>
+        <span class="sympad">removeDetachedView</span>(View arg0, boolean arg1)</nobr>
         
   </td></tr>
 
@@ -3816,7 +4295,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3848,7 +4327,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeViewInLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeViewInLayout</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -3896,7 +4375,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1)</nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
         
   </td></tr>
 
@@ -3912,7 +4391,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildRectangleOnScreen</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, boolean arg2)</nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
         
   </td></tr>
 
@@ -3944,7 +4423,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestFocus</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -3960,7 +4439,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -3976,7 +4455,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestTransparentRegion</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4152,7 +4631,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutAnimation</span>(<a href="/reference/android/view/animation/LayoutAnimationController.html">LayoutAnimationController</a> arg0)</nobr>
+        <span class="sympad">setLayoutAnimation</span>(LayoutAnimationController arg0)</nobr>
         
   </td></tr>
 
@@ -4168,7 +4647,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutAnimationListener</span>(<a href="/reference/android/view/animation/Animation.AnimationListener.html">Animation.AnimationListener</a> arg0)</nobr>
+        <span class="sympad">setLayoutAnimationListener</span>(Animation.AnimationListener arg0)</nobr>
         
   </td></tr>
 
@@ -4216,7 +4695,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnHierarchyChangeListener</span>(<a href="/reference/android/view/ViewGroup.OnHierarchyChangeListener.html">ViewGroup.OnHierarchyChangeListener</a> arg0)</nobr>
+        <span class="sympad">setOnHierarchyChangeListener</span>(ViewGroup.OnHierarchyChangeListener arg0)</nobr>
         
   </td></tr>
 
@@ -4296,7 +4775,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">showContextMenuForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4312,7 +4791,7 @@
             ActionMode</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActionModeForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, ActionMode.Callback arg1)</nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
         
   </td></tr>
 
@@ -4344,7 +4823,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startViewTransition</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">startViewTransition</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4360,7 +4839,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">updateViewLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -4380,7 +4859,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/android/view/View.html">android.view.View</a>
+  android.view.View
 
 <div id="inherited-methods-android.view.View">
   <div id="inherited-methods-android.view.View-list"
@@ -4402,7 +4881,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addChildrenForAccessibility</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -4418,7 +4897,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1, int arg2)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -4434,7 +4913,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addFocusables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, int arg1)</nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -4482,7 +4961,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addTouchables</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0)</nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -4514,7 +4993,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">announceForAccessibility</span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg0)</nobr>
+        <span class="sympad">announceForAccessibility</span>(CharSequence arg0)</nobr>
         
   </td></tr>
 
@@ -4706,7 +5185,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">checkInputConnectionProxy</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">checkInputConnectionProxy</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -4898,7 +5377,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">createContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -4930,7 +5409,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -4978,7 +5457,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -4994,7 +5473,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericFocusedEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5010,7 +5489,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericMotionEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericMotionEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5026,7 +5505,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchGenericPointerEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5042,7 +5521,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5058,7 +5537,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5074,7 +5553,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyEventPreIme</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5090,7 +5569,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchKeyShortcutEvent</span>(<a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5106,7 +5585,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5122,7 +5601,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchRestoreInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -5138,7 +5617,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchSaveInstanceState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -5218,7 +5697,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5234,7 +5713,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -5250,7 +5729,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchUnhandledMove</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -5266,7 +5745,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">dispatchVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -5330,7 +5809,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">draw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -5359,7 +5838,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findFocus</span>()</nobr>
@@ -5375,7 +5854,7 @@
             final
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">findViewById</span>(int arg0)</nobr>
@@ -5391,10 +5870,10 @@
             final
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewWithTag</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">findViewWithTag</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -5410,7 +5889,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">findViewsWithText</span>(<a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt; arg0, <a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg1, int arg2)</nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
         
   </td></tr>
 
@@ -5426,7 +5905,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">fitSystemWindows</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -5439,7 +5918,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">focusSearch</span>(int arg0)</nobr>
@@ -5503,7 +5982,7 @@
             
             
             
-            <a href="/reference/android/view/animation/Animation.html">Animation</a></nobr>
+            Animation</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getAnimation</span>()</nobr>
@@ -5519,7 +5998,7 @@
             
             
             
-            <a href="/reference/android/os/IBinder.html">IBinder</a></nobr>
+            IBinder</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getApplicationWindowToken</span>()</nobr>
@@ -5535,7 +6014,7 @@
             
             
             
-            <a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a></nobr>
+            Drawable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getBackground</span>()</nobr>
@@ -5631,7 +6110,7 @@
             
             
             
-            <a href="/reference/java/lang/CharSequence.html">CharSequence</a></nobr>
+            CharSequence</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContentDescription</span>()</nobr>
@@ -5647,7 +6126,7 @@
             final
             
             
-            <a href="/reference/android/content/Context.html">Context</a></nobr>
+            Context</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContext</span>()</nobr>
@@ -5663,7 +6142,7 @@
             
             
             
-            <a href="/reference/android/view/ContextMenu.ContextMenuInfo.html">ContextMenu.ContextMenuInfo</a></nobr>
+            ContextMenu.ContextMenuInfo</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getContextMenuInfo</span>()</nobr>
@@ -5711,7 +6190,7 @@
             
             
             
-            <a href="/reference/android/graphics/Bitmap.html">Bitmap</a></nobr>
+            Bitmap</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getDrawingCache</span>(boolean arg0)</nobr>
@@ -5727,7 +6206,7 @@
             
             
             
-            <a href="/reference/android/graphics/Bitmap.html">Bitmap</a></nobr>
+            Bitmap</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getDrawingCache</span>()</nobr>
@@ -5778,7 +6257,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getDrawingRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getDrawingRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -5839,7 +6318,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt;</nobr>
+            ArrayList&lt;View&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getFocusables</span>(int arg0)</nobr>
@@ -5858,7 +6337,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getFocusedRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getFocusedRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -5874,7 +6353,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getGlobalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0, <a href="/reference/android/graphics/Point.html">Point</a> arg1)</nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0, Point arg1)</nobr>
         
   </td></tr>
 
@@ -5890,7 +6369,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getGlobalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -5903,7 +6382,7 @@
             
             
             
-            <a href="/reference/android/os/Handler.html">Handler</a></nobr>
+            Handler</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getHandler</span>()</nobr>
@@ -5938,7 +6417,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getHitRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getHitRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6031,7 +6510,7 @@
             
             
             
-            <a href="/reference/android/view/KeyEvent.DispatcherState.html">KeyEvent.DispatcherState</a></nobr>
+            KeyEvent.DispatcherState</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getKeyDispatcherState</span>()</nobr>
@@ -6063,7 +6542,7 @@
             
             
             
-            <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a></nobr>
+            ViewGroup.LayoutParams</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getLayoutParams</span>()</nobr>
@@ -6130,7 +6609,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getLocalVisibleRect</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getLocalVisibleRect</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -6175,7 +6654,7 @@
             
             
             
-            <a href="/reference/android/graphics/Matrix.html">Matrix</a></nobr>
+            Matrix</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getMatrix</span>()</nobr>
@@ -6383,7 +6862,7 @@
             
             
             
-            <a href="/reference/android/view/View.OnFocusChangeListener.html">View.OnFocusChangeListener</a></nobr>
+            View.OnFocusChangeListener</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getOnFocusChangeListener</span>()</nobr>
@@ -6479,7 +6958,7 @@
             final
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParent</span>()</nobr>
@@ -6495,7 +6974,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParentForAccessibility</span>()</nobr>
@@ -6543,7 +7022,7 @@
             
             
             
-            <a href="/reference/android/content/res/Resources.html">Resources</a></nobr>
+            Resources</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getResources</span>()</nobr>
@@ -6607,7 +7086,7 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getRootView</span>()</nobr>
@@ -6863,7 +7342,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>(int arg0)</nobr>
@@ -6879,7 +7358,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTag</span>()</nobr>
@@ -6943,7 +7422,7 @@
             
             
             
-            <a href="/reference/android/view/TouchDelegate.html">TouchDelegate</a></nobr>
+            TouchDelegate</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTouchDelegate</span>()</nobr>
@@ -6959,7 +7438,7 @@
             
             
             
-            <a href="/reference/java/util/ArrayList.html">ArrayList</a>&lt;<a href="/reference/android/view/View.html">View</a>&gt;</nobr>
+            ArrayList&lt;View&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getTouchables</span>()</nobr>
@@ -7055,7 +7534,7 @@
             
             
             
-            <a href="/reference/android/view/ViewTreeObserver.html">ViewTreeObserver</a></nobr>
+            ViewTreeObserver</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getViewTreeObserver</span>()</nobr>
@@ -7135,7 +7614,7 @@
             
             
             
-            <a href="/reference/android/os/IBinder.html">IBinder</a></nobr>
+            IBinder</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getWindowToken</span>()</nobr>
@@ -7170,7 +7649,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getWindowVisibleDisplayFrame</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">getWindowVisibleDisplayFrame</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -7311,10 +7790,10 @@
             
             static
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">inflate</span>(<a href="/reference/android/content/Context.html">Context</a> arg0, int arg1, <a href="/reference/android/view/ViewGroup.html">ViewGroup</a> arg2)</nobr>
+        <span class="sympad">inflate</span>(Context arg0, int arg1, ViewGroup arg2)</nobr>
         
   </td></tr>
 
@@ -7330,7 +7809,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initializeFadingEdge</span>(<a href="/reference/android/content/res/TypedArray.html">TypedArray</a> arg0)</nobr>
+        <span class="sympad">initializeFadingEdge</span>(TypedArray arg0)</nobr>
         
   </td></tr>
 
@@ -7346,7 +7825,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">initializeScrollbars</span>(<a href="/reference/android/content/res/TypedArray.html">TypedArray</a> arg0)</nobr>
+        <span class="sympad">initializeScrollbars</span>(TypedArray arg0)</nobr>
         
   </td></tr>
 
@@ -7362,7 +7841,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidate</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">invalidate</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -7410,7 +7889,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -8066,7 +8545,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onConfigurationChanged</span>(<a href="/reference/android/content/res/Configuration.html">Configuration</a> arg0)</nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
         
   </td></tr>
 
@@ -8082,7 +8561,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -8111,10 +8590,10 @@
             
             
             
-            <a href="/reference/android/view/inputmethod/InputConnection.html">InputConnection</a></nobr>
+            InputConnection</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onCreateInputConnection</span>(<a href="/reference/android/view/inputmethod/EditorInfo.html">EditorInfo</a> arg0)</nobr>
+        <span class="sympad">onCreateInputConnection</span>(EditorInfo arg0)</nobr>
         
   </td></tr>
 
@@ -8178,7 +8657,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onDraw</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">onDraw</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -8194,7 +8673,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onDrawScrollBars</span>(<a href="/reference/android/graphics/Canvas.html">Canvas</a> arg0)</nobr>
+        <span class="sympad">onDrawScrollBars</span>(Canvas arg0)</nobr>
         
   </td></tr>
 
@@ -8210,7 +8689,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onFilterTouchEventForSecurity</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onFilterTouchEventForSecurity</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8258,7 +8737,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, <a href="/reference/android/graphics/Rect.html">Rect</a> arg2)</nobr>
+        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, Rect arg2)</nobr>
         
   </td></tr>
 
@@ -8274,7 +8753,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onGenericMotionEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onGenericMotionEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8306,7 +8785,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onHoverEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onHoverEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8322,7 +8801,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onInitializeAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8354,7 +8833,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyDown</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8370,7 +8849,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyLongPress</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8386,7 +8865,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg2)</nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
         
   </td></tr>
 
@@ -8402,7 +8881,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyPreIme</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyPreIme</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8418,7 +8897,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyShortcut</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyShortcut</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8434,7 +8913,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyUp</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -8498,7 +8977,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onPopulateAccessibilityEvent</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">onPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8514,7 +8993,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onRestoreInstanceState</span>(<a href="/reference/android/os/Parcelable.html">Parcelable</a> arg0)</nobr>
+        <span class="sympad">onRestoreInstanceState</span>(Parcelable arg0)</nobr>
         
   </td></tr>
 
@@ -8527,7 +9006,7 @@
             
             
             
-            <a href="/reference/android/os/Parcelable.html">Parcelable</a></nobr>
+            Parcelable</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">onSaveInstanceState</span>()</nobr>
@@ -8626,7 +9105,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onTouchEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onTouchEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8642,7 +9121,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onTrackballEvent</span>(<a href="/reference/android/view/MotionEvent.html">MotionEvent</a> arg0)</nobr>
+        <span class="sympad">onTrackballEvent</span>(MotionEvent arg0)</nobr>
         
   </td></tr>
 
@@ -8658,7 +9137,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onVisibilityChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">onVisibilityChanged</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -8738,7 +9217,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">performAccessibilityAction</span>(int arg0, <a href="/reference/android/os/Bundle.html">Bundle</a> arg1)</nobr>
+        <span class="sympad">performAccessibilityAction</span>(int arg0, Bundle arg1)</nobr>
         
   </td></tr>
 
@@ -8834,7 +9313,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">post</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">post</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -8850,7 +9329,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postDelayed</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0, long arg1)</nobr>
+        <span class="sympad">postDelayed</span>(Runnable arg0, long arg1)</nobr>
         
   </td></tr>
 
@@ -8962,7 +9441,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postOnAnimation</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">postOnAnimation</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -8978,7 +9457,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">postOnAnimationDelayed</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0, long arg1)</nobr>
+        <span class="sympad">postOnAnimationDelayed</span>(Runnable arg0, long arg1)</nobr>
         
   </td></tr>
 
@@ -9010,7 +9489,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeCallbacks</span>(<a href="/reference/java/lang/Runnable.html">Runnable</a> arg0)</nobr>
+        <span class="sympad">removeCallbacks</span>(Runnable arg0)</nobr>
         
   </td></tr>
 
@@ -9074,7 +9553,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestFocus</span>(int arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -9154,7 +9633,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestRectangleOnScreen</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0)</nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0)</nobr>
         
   </td></tr>
 
@@ -9170,7 +9649,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestRectangleOnScreen</span>(<a href="/reference/android/graphics/Rect.html">Rect</a> arg0, boolean arg1)</nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0, boolean arg1)</nobr>
         
   </td></tr>
 
@@ -9218,7 +9697,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">restoreHierarchyState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">restoreHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -9234,7 +9713,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">saveHierarchyState</span>(<a href="/reference/android/util/SparseArray.html">SparseArray</a>&lt;<a href="/reference/android/os/Parcelable.html">Parcelable</a>&gt; arg0)</nobr>
+        <span class="sympad">saveHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
         
   </td></tr>
 
@@ -9250,7 +9729,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">scheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1, long arg2)</nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -9314,7 +9793,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">sendAccessibilityEventUnchecked</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -9378,7 +9857,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setAnimation</span>(<a href="/reference/android/view/animation/Animation.html">Animation</a> arg0)</nobr>
+        <span class="sympad">setAnimation</span>(Animation arg0)</nobr>
         
   </td></tr>
 
@@ -9394,7 +9873,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setBackground</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setBackground</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -9426,7 +9905,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setBackgroundDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">setBackgroundDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -9506,7 +9985,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setContentDescription</span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> arg0)</nobr>
+        <span class="sympad">setContentDescription</span>(CharSequence arg0)</nobr>
         
   </td></tr>
 
@@ -9810,7 +10289,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayerType</span>(int arg0, <a href="/reference/android/graphics/Paint.html">Paint</a> arg1)</nobr>
+        <span class="sympad">setLayerType</span>(int arg0, Paint arg1)</nobr>
         
   </td></tr>
 
@@ -9826,7 +10305,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setLayoutParams</span>(<a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg0)</nobr>
+        <span class="sympad">setLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
         
   </td></tr>
 
@@ -10002,7 +10481,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnClickListener</span>(<a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> arg0)</nobr>
+        <span class="sympad">setOnClickListener</span>(View.OnClickListener arg0)</nobr>
         
   </td></tr>
 
@@ -10018,7 +10497,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnCreateContextMenuListener</span>(<a href="/reference/android/view/View.OnCreateContextMenuListener.html">View.OnCreateContextMenuListener</a> arg0)</nobr>
+        <span class="sympad">setOnCreateContextMenuListener</span>(View.OnCreateContextMenuListener arg0)</nobr>
         
   </td></tr>
 
@@ -10050,7 +10529,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnFocusChangeListener</span>(<a href="/reference/android/view/View.OnFocusChangeListener.html">View.OnFocusChangeListener</a> arg0)</nobr>
+        <span class="sympad">setOnFocusChangeListener</span>(View.OnFocusChangeListener arg0)</nobr>
         
   </td></tr>
 
@@ -10098,7 +10577,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnKeyListener</span>(<a href="/reference/android/view/View.OnKeyListener.html">View.OnKeyListener</a> arg0)</nobr>
+        <span class="sympad">setOnKeyListener</span>(View.OnKeyListener arg0)</nobr>
         
   </td></tr>
 
@@ -10114,7 +10593,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnLongClickListener</span>(<a href="/reference/android/view/View.OnLongClickListener.html">View.OnLongClickListener</a> arg0)</nobr>
+        <span class="sympad">setOnLongClickListener</span>(View.OnLongClickListener arg0)</nobr>
         
   </td></tr>
 
@@ -10146,7 +10625,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setOnTouchListener</span>(<a href="/reference/android/view/View.OnTouchListener.html">View.OnTouchListener</a> arg0)</nobr>
+        <span class="sympad">setOnTouchListener</span>(View.OnTouchListener arg0)</nobr>
         
   </td></tr>
 
@@ -10546,7 +11025,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTag</span>(int arg0, <a href="/reference/java/lang/Object.html">Object</a> arg1)</nobr>
+        <span class="sympad">setTag</span>(int arg0, Object arg1)</nobr>
         
   </td></tr>
 
@@ -10562,7 +11041,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTag</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">setTag</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -10594,7 +11073,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">setTouchDelegate</span>(<a href="/reference/android/view/TouchDelegate.html">TouchDelegate</a> arg0)</nobr>
+        <span class="sympad">setTouchDelegate</span>(TouchDelegate arg0)</nobr>
         
   </td></tr>
 
@@ -10802,7 +11281,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startAnimation</span>(<a href="/reference/android/view/animation/Animation.html">Animation</a> arg0)</nobr>
+        <span class="sympad">startAnimation</span>(Animation arg0)</nobr>
         
   </td></tr>
 
@@ -10818,7 +11297,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, <a href="/reference/java/lang/Object.html">Object</a> arg2, int arg3)</nobr>
+        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, Object arg2, int arg3)</nobr>
         
   </td></tr>
 
@@ -10834,7 +11313,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -10850,7 +11329,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
         
   </td></tr>
 
@@ -10866,7 +11345,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">verifyDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -10918,7 +11397,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -10937,7 +11416,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -10956,7 +11435,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -10985,7 +11464,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -11049,7 +11528,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -11120,7 +11599,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/graphics/drawable/Drawable.Callback.html">android.graphics.drawable.Drawable.Callback</a>
+  android.graphics.drawable.Drawable.Callback
 
 <div id="inherited-methods-android.graphics.drawable.Drawable.Callback">
   <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-list"
@@ -11142,7 +11621,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0)</nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
         
   </td></tr>
 
@@ -11158,7 +11637,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">scheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1, long arg2)</nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
         
   </td></tr>
 
@@ -11174,7 +11653,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">unscheduleDrawable</span>(<a href="/reference/android/graphics/drawable/Drawable.html">Drawable</a> arg0, <a href="/reference/java/lang/Runnable.html">Runnable</a> arg1)</nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
         
   </td></tr>
 
@@ -11194,7 +11673,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/KeyEvent.Callback.html">android.view.KeyEvent.Callback</a>
+  android.view.KeyEvent.Callback
 
 <div id="inherited-methods-android.view.KeyEvent.Callback">
   <div id="inherited-methods-android.view.KeyEvent.Callback-list"
@@ -11216,7 +11695,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyDown</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11232,7 +11711,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyLongPress</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11248,7 +11727,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg2)</nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
         
   </td></tr>
 
@@ -11264,7 +11743,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">onKeyUp</span>(int arg0, <a href="/reference/android/view/KeyEvent.html">KeyEvent</a> arg1)</nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11284,7 +11763,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/ViewManager.html">android.view.ViewManager</a>
+  android.view.ViewManager
 
 <div id="inherited-methods-android.view.ViewManager">
   <div id="inherited-methods-android.view.ViewManager-list"
@@ -11306,7 +11785,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">addView</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -11322,7 +11801,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">removeView</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11338,7 +11817,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">updateViewLayout</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/ViewGroup.LayoutParams.html">ViewGroup.LayoutParams</a> arg1)</nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
         
   </td></tr>
 
@@ -11358,7 +11837,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/ViewParent.html">android.view.ViewParent</a>
+  android.view.ViewParent
 
 <div id="inherited-methods-android.view.ViewParent">
   <div id="inherited-methods-android.view.ViewParent-list"
@@ -11380,7 +11859,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">bringChildToFront</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11396,7 +11875,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">childDrawableStateChanged</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11412,7 +11891,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">clearChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11428,7 +11907,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">createContextMenu</span>(<a href="/reference/android/view/ContextMenu.html">ContextMenu</a> arg0)</nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
         
   </td></tr>
 
@@ -11441,10 +11920,10 @@
             
             
             
-            <a href="/reference/android/view/View.html">View</a></nobr>
+            View</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusSearch</span>(<a href="/reference/android/view/View.html">View</a> arg0, int arg1)</nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
         
   </td></tr>
 
@@ -11460,7 +11939,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">focusableViewAvailable</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11476,7 +11955,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">getChildVisibleRect</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, <a href="/reference/android/graphics/Point.html">Point</a> arg2)</nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
         
   </td></tr>
 
@@ -11489,7 +11968,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParent</span>()</nobr>
@@ -11505,7 +11984,7 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getParentForAccessibility</span>()</nobr>
@@ -11524,7 +12003,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -11537,10 +12016,10 @@
             
             
             
-            <a href="/reference/android/view/ViewParent.html">ViewParent</a></nobr>
+            ViewParent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">invalidateChildInParent</span>(int[] arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1)</nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
         
   </td></tr>
 
@@ -11572,7 +12051,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">recomputeViewAttributes</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11588,7 +12067,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildFocus</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/View.html">View</a> arg1)</nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
         
   </td></tr>
 
@@ -11604,7 +12083,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestChildRectangleOnScreen</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/graphics/Rect.html">Rect</a> arg1, boolean arg2)</nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
         
   </td></tr>
 
@@ -11668,7 +12147,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestSendAccessibilityEvent</span>(<a href="/reference/android/view/View.html">View</a> arg0, <a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg1)</nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
         
   </td></tr>
 
@@ -11684,7 +12163,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">requestTransparentRegion</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11700,7 +12179,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">showContextMenuForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0)</nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
         
   </td></tr>
 
@@ -11716,7 +12195,7 @@
             ActionMode</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">startActionModeForChild</span>(<a href="/reference/android/view/View.html">View</a> arg0, ActionMode.Callback arg1)</nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
         
   </td></tr>
 
@@ -11736,7 +12215,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/android/view/accessibility/AccessibilityEventSource.html">android.view.accessibility.AccessibilityEventSource</a>
+  android.view.accessibility.AccessibilityEventSource
 
 <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource">
   <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-list"
@@ -11774,7 +12253,7 @@
             void</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">sendAccessibilityEventUnchecked</span>(<a href="/reference/android/view/accessibility/AccessibilityEvent.html">AccessibilityEvent</a> arg0)</nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
         
   </td></tr>
 
@@ -11932,6 +12411,45 @@
 
 
 
+<A NAME="DEFAULT_ACTIVITY_REQUEST_CODE"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+        final 
+        int
+      </span>
+        DEFAULT_ACTIVITY_REQUEST_CODE
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>An empty ActivityRequestCode to serve as the default before the code has been assigned.
+</p></div>
+
+    
+        <div class="jd-tagdata">
+        <span class="jd-tagtitle">Constant Value: </span>
+        <span>
+            
+                -1
+                (0xffffffff)
+            
+        </span>
+        </div>
+    
+    </div>
+</div>
+
+
+
 <A NAME="SIZE_MEDIUM"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -12121,7 +12639,7 @@
         
       </span>
       <span class="sympad">PlusOneButton</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12161,7 +12679,7 @@
         
       </span>
       <span class="sympad">PlusOneButton</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context, <a href="/reference/android/util/AttributeSet.html">AttributeSet</a> attrs)</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12207,7 +12725,7 @@
 
 
 
-<A NAME="initialize(com.google.android.gms.plus.PlusClient, java.lang.String, com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)"></A>
+<A NAME="initialize(java.lang.String, com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)"></A>
 
 <div class="jd-details api apilevel-"> 
     <h4 class="jd-details-title">
@@ -12220,7 +12738,7 @@
         void
       </span>
       <span class="sympad">initialize</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient, <a href="/reference/java/lang/String.html">String</a> url, <a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> plusOneClickListener)</span>
+      <span class="normal">(String url, <a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a> plusOneClickListener)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12236,10 +12754,6 @@
       <h5 class="jd-tagtitle">Parameters</h5>
       <table class="jd-tagtable">
         <tr>
-          <th>plusClient</td>
-          <td>The <code><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></code>.</td>
-        </tr>
-        <tr>
           <th>url</td>
           <td>The URL to be +1'd.</td>
         </tr>
@@ -12255,7 +12769,7 @@
 </div>
 
 
-<A NAME="initialize(com.google.android.gms.plus.PlusClient, java.lang.String, int)"></A>
+<A NAME="initialize(java.lang.String, int)"></A>
 
 <div class="jd-details api apilevel-"> 
     <h4 class="jd-details-title">
@@ -12268,7 +12782,7 @@
         void
       </span>
       <span class="sympad">initialize</span>
-      <span class="normal">(<a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient, <a href="/reference/java/lang/String.html">String</a> url, int activityRequestCode)</span>
+      <span class="normal">(String url, int activityRequestCode)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -12281,15 +12795,11 @@
   <div class="jd-tagdata jd-tagdescr"><p>Updates the +1 button with a <code><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></code> and URL.  Most apps call
  this method each time the button is in focus (for example, in the Activity onResume
  method).  To use this method, the PlusOneButton must be placed in an Activity.  Use
- <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#initialize(com.google.android.gms.plus.PlusClient, java.lang.String, com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)">initialize(PlusClient, String, OnPlusOneClickListener)</a></code> otherwise.</p></div>
+ <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#initialize(java.lang.String, com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener)">initialize(String, OnPlusOneClickListener)</a></code> otherwise.</p></div>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Parameters</h5>
       <table class="jd-tagtable">
         <tr>
-          <th>plusClient</td>
-          <td>The <code><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></code>.</td>
-        </tr>
-        <tr>
           <th>url</td>
           <td>The URL to be +1'd.</td>
         </tr>
@@ -12435,6 +12945,69 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
+<h2>Protected Methods</h2>
+
+
+
+<A NAME="getAnnotation(android.content.Context, android.util.AttributeSet)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        protected 
+        static 
+         
+         
+         
+        int
+      </span>
+      <span class="sympad">getAnnotation</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+<A NAME="getSize(android.content.Context, android.util.AttributeSet)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        protected 
+        static 
+         
+         
+         
+        int
+      </span>
+      <span class="sympad">getSize</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html b/docs/html/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html
new file mode 100644
index 0000000..fb77613
--- /dev/null
+++ b/docs/html/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html
@@ -0,0 +1,12263 @@
+<!DOCTYPE html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<html>
+<head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
+
+<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
+<title>PlusOneButtonWithPopup | Android Developers</title>
+
+<!-- STYLESHEETS -->
+<link rel="stylesheet"
+href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
+
+
+
+<!-- JAVASCRIPT -->
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
+<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
+<script type="text/javascript">
+  var toRoot = "/";
+  var devsite = false;
+</script>
+<script src="/assets/js/docs.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-5831155-1']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+</script>
+</head>
+<body class="gc-documentation google
+  develop" itemscope itemtype="http://schema.org/Article">
+  <div id="doc-api-level" class="" style="display:none"></div>
+  <a name="top"></a>
+
+<a name="top"></a>
+
+    <!-- Header -->
+    <div id="header">
+        <div class="wrap" id="header-wrap">
+          <div class="col-3 logo">
+          <a href="/index.html">
+            <img src="/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
+          </a>
+          <div class="btn-quicknav" id="btn-quicknav">
+          	<a href="#" class="arrow-inactive">Quicknav</a>
+			      <a href="#" class="arrow-active">Quicknav</a>
+          </div>
+          </div>
+            <ul class="nav-x col-9">
+                <li class="design">
+                  <a href="/design/index.html"
+                  zh-tw-lang="設計"
+                  zh-cn-lang="设计"
+                  ru-lang="Проектирование"
+                  ko-lang="디자인"
+                  ja-lang="設計"
+                  es-lang="Diseñar"               
+                  >Design</a></li>
+                <li class="develop"><a href="/develop/index.html"
+                  zh-tw-lang="開發"
+                  zh-cn-lang="开发"
+                  ru-lang="Разработка"
+                  ko-lang="개발"
+                  ja-lang="開発"
+                  es-lang="Desarrollar"               
+                  >Develop</a></li>
+                <li class="distribute last"><a href="/distribute/index.html"
+                  zh-tw-lang="發佈"
+                  zh-cn-lang="分发"
+                  ru-lang="Распространение"
+                  ko-lang="배포"
+                  ja-lang="配布"
+                  es-lang="Distribuir"               
+                  >Distribute</a></li>
+            </ul>
+            
+            <!-- New Search -->
+            <div class="menu-container">
+            <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
+  <div class="morehover" id="moremenu">
+    <div class="top"></div>
+    <div class="mid">
+      <div class="header">Links</div>
+      <ul>
+        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
+        <li><a href="/about/index.html">About Android</a></li>
+      </ul>
+      <div class="header">Android Sites</div>
+      <ul>
+        <li><a href="http://www.android.com">Android.com</a></li>
+        <li class="active"><a>Android Developers</a></li>
+        <li><a href="http://source.android.com">Android Open Source Project</a></li>
+      </ul>
+      
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
+
+
+      <br class="clearfix" />
+    </div>
+    <div class="bottom"></div>
+  </div>
+  <div class="search" id="search-container">
+    <div class="search-inner">
+      <div id="search-btn"></div>
+      <div class="left"></div>
+      <form onsubmit="return submit_search()">
+        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
+onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+onkeydown="return search_changed(event, true, '/')" 
+onkeyup="return search_changed(event, false, '/')" />
+      </form>
+      <div class="right"></div>
+        <a class="close hide">close</a>
+        <div class="left"></div>
+        <div class="right"></div>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper reference">
+    <div class="suggest-card reference no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper docs">
+    <div class="suggest-card dummy no-display">&nbsp;</div>
+    <div class="suggest-card develop no-display">
+      <ul class="search_filtered">
+      </ul>
+      <div class="child-card guides no-display">
+      </div>
+      <div class="child-card training no-display">
+      </div>
+    </div>
+    <div class="suggest-card design no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+    <div class="suggest-card distribute no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  </div>
+  <!-- /New Search>
+          
+          
+          <!-- Expanded quicknav -->
+           <div id="quicknav" class="col-9">
+                <ul>
+                    <li class="design">
+                      <ul>
+                        <li><a href="/design/index.html">Get Started</a></li>
+                        <li><a href="/design/style/index.html">Style</a></li>
+                        <li><a href="/design/patterns/index.html">Patterns</a></li>
+                        <li><a href="/design/building-blocks/index.html">Building Blocks</a></li>
+                        <li><a href="/design/downloads/index.html">Downloads</a></li>
+                        <li><a href="/design/videos/index.html">Videos</a></li>
+                      </ul>
+                    </li>
+                    <li class="develop">
+                      <ul>
+                        <li><a href="/training/index.html"
+                          zh-tw-lang="訓練課程"
+                          zh-cn-lang="培训"
+                          ru-lang="Курсы"
+                          ko-lang="교육"
+                          ja-lang="トレーニング"
+                          es-lang="Capacitación"               
+                          >Training</a></li>
+                        <li><a href="/guide/components/index.html"
+                          zh-tw-lang="API 指南"
+                          zh-cn-lang="API 指南"
+                          ru-lang="Руководства по API"
+                          ko-lang="API 가이드"
+                          ja-lang="API ガイド"
+                          es-lang="Guías de la API"               
+                          >API Guides</a></li>
+                        <li><a href="/reference/packages.html"
+                          zh-tw-lang="參考資源"
+                          zh-cn-lang="参考"
+                          ru-lang="Справочник"
+                          ko-lang="참조문서"
+                          ja-lang="リファレンス"
+                          es-lang="Referencia"               
+                          >Reference</a></li>
+                        <li><a href="/tools/index.html"
+                          zh-tw-lang="相關工具"
+                          zh-cn-lang="工具"
+                          ru-lang="Инструменты"
+                          ko-lang="도구"
+                          ja-lang="ツール"
+                          es-lang="Herramientas"               
+                          >Tools</a>
+                          <ul><li><a href="/sdk/index.html">Get the SDK</a></li></ul>
+                        </li>
+                        <li><a href="/google/index.html">Google Services</a>
+                        </li>
+                        
+                      </ul>
+                    </li>
+                    <li class="distribute last">
+                      <ul>
+                        <li><a href="/distribute/index.html">Google Play</a></li>
+                        <li><a href="/distribute/googleplay/publish/index.html">Publishing</a></li>
+                        <li><a href="/distribute/googleplay/promote/index.html">Promoting</a></li>
+                        <li><a href="/distribute/googleplay/quality/index.html">App Quality</a></li>
+                        <li><a href="/distribute/googleplay/spotlight/index.html">Spotlight</a></li>
+                        <li><a href="/distribute/open.html">Open Distribution</a></li>
+                      </ul>
+                    </li>
+                </ul>
+          </div>
+          <!-- /Expanded quicknav -->
+        </div>
+    </div>
+    <!-- /Header -->
+    
+    
+  <div id="searchResults" class="wrap" style="display:none;">
+          <h2 id="searchTitle">Results</h2>
+          <div id="leftSearchControl" class="search-control">Loading...</div>
+  </div>
+    
+    
+  
+    <!-- Secondary x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x col-9 develop" style="width:100%">
+                <li class="training"><a href="/training/index.html"
+                  zh-tw-lang="訓練課程"
+                  zh-cn-lang="培训"
+                  ru-lang="Курсы"
+                  ko-lang="교육"
+                  ja-lang="トレーニング"
+                  es-lang="Capacitación"               
+                  >Training</a></li>
+                <li class="guide"><a href="/guide/components/index.html"
+                  zh-tw-lang="API 指南"
+                  zh-cn-lang="API 指南"
+                  ru-lang="Руководства по API"
+                  ko-lang="API 가이드"
+                  ja-lang="API ガイド"
+                  es-lang="Guías de la API"               
+                  >API Guides</a></li>
+                <li class="reference"><a href="/reference/packages.html"
+                  zh-tw-lang="參考資源"
+                  zh-cn-lang="参考"
+                  ru-lang="Справочник"
+                  ko-lang="참조문서"
+                  ja-lang="リファレンス"
+                  es-lang="Referencia"               
+                  >Reference</a></li>
+                <li class="tools"><a href="/tools/index.html"
+                  zh-tw-lang="相關工具"
+                  zh-cn-lang="工具"
+                  ru-lang="Инструменты"
+                  ko-lang="도구"
+                  ja-lang="ツール"
+                  es-lang="Herramientas"
+                  >Tools</a></li>
+                <li class="google"><a href="/google/index.html"
+                  >Google Services</a>
+                </li>
+                
+            </ul>
+        </div>
+        
+    </div>
+    <!-- /Sendondary x-nav -->
+  
+
+
+
+
+  
+
+
+  
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
+
+
+
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/index.html">
+          <span class="en">Overview</span>
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/games.html">
+          <span class="en">Games</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/location.html">
+          <span class="en">Location</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/plus.html">
+          <span class="en">Google+</span>
+                </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/maps.html">
+          <span class="en">Google Maps</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/auth.html">
+          <span class="en">Authorization</span>
+      </a></div>
+  </li>
+
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play-services/index.html">
+      <span class="en">Google Play Services</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play-services/setup.html">
+          <span class="en">Setup</span></a>
+      </li>
+      <li id="gms-tree-list" class="nav-section">
+        <div class="nav-section-header">
+          <a href="/reference/gms-packages.html">
+            <span class="en">Reference</span>
+          </a>
+        <div>
+      </li>
+    </ul>
+  </li>
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/billing/index.html">
+      <span class="en">Google Play In-app Billing</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/billing/billing_overview.html">
+              <span class="en">Overview</span></a>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/api.html">
+              <span class="en">Version 3 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/v2/api.html">
+              <span class="en">Version 2 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/v2/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li><a href="/google/play/billing/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_best_practices.html">
+              <span class="en">Security and Design</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_testing.html">
+              <span class="en">Testing In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_admin.html">
+              <span class="en">Administering In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/gp-purchase-status-api.html">
+              <span class="en">Purchase Status API</span></a>
+      </li>
+      <li><a href="/google/play/billing/versions.html">
+              <span class="en">Version Notes</span></a>
+      </li>
+    </ul>
+  </li>
+
+
+
+  <li class="nav-section">
+      <div class="nav-section-header"><a href="/google/gcm/index.html">
+        <span class="en">Google Cloud Messaging</span></a>
+      </div>
+      <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
+        <li><a href="/google/gcm/gs.html">
+            <span class="en">Getting Started</span></a>
+        </li>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
+        </li>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
+        </li>
+        <li><a href="/google/gcm/notifications.html">
+              <span class="en">User Notifications</span></a>
+        </li>
+        <li><a href="/google/gcm/adv.html">
+            <span class="en">Advanced Topics</span></a>
+        </li>
+        <li><a href="/google/gcm/c2dm.html">
+            <span class="en">Migration</span></a>
+        </li>
+        <li id="gcm-tree-list" class="nav-section">
+          <div class="nav-section-header">
+            <a href="/reference/gcm-packages.html">
+              <span class="en">Reference</span>
+            </a>
+          <div>
+        </li>
+      </ul>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/dist.html">
+      <span class="en">Google Play Distribution</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/filters.html">
+          <span class="en">Filters on Google Play</span></a>
+      </li>
+
+      <li><a href="/google/play/publishing/multiple-apks.html">
+          <span class="en">Multiple APK Support</span></a>
+      </li>
+      <li><a href="/google/play/expansion-files.html">
+          <span class="en">APK Expansion Files</span></a>
+      </li>
+      <li class="nav-section">
+        <div class="nav-section-header"><a href="/google/play/licensing/index.html">
+          <span class="en">Application Licensing</span></a>
+        </div>
+        <ul>
+          <li><a href="/google/play/licensing/overview.html">
+              <span class="en">Licensing Overview</span></a>
+          </li>
+          <li><a href="/google/play/licensing/setting-up.html">
+              <span class="en">Setting Up for Licensing</span></a>
+          </li>
+          <li><a href="/google/play/licensing/adding-licensing.html">
+              <span class="en">Adding Licensing to Your App</span></a>
+          </li>
+          <li><a href="/google/play/licensing/licensing-reference.html">
+              <span class="en">Licensing Reference</span></a>
+          </li>
+        </ul>
+      </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/backup/index.html">
+      Android Backup Service</a>
+    </div>
+    <ul>
+      <li><a href="/google/backup/signup.html">
+          Register</a>
+      </li>
+    </ul>
+  </li>
+
+  </ul>
+
+</li>
+
+
+
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
+
+        
+
+      </div>
+      <script type="text/javascript">
+       showGoogleRefTree();
+    
+      </script>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+
+
+     
+
+
+
+<div class="col-12"  id="doc-col">
+
+<div id="api-info-block">
+
+
+
+  
+   
+  
+  
+   
+  
+  
+  
+
+  
+   
+  
+  
+   
+  
+  
+   
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+
+<div class="sum-details-links">
+
+Summary:
+
+
+
+
+
+
+  <a href="#inhconstants">Inherited Constants</a>
+  
+
+
+
+  &#124; <a href="#inhfields">Inherited Fields</a>
+  
+
+
+  &#124; <a href="#pubctors">Ctors</a>
+  
+
+
+
+  &#124; <a href="#pubmethods">Methods</a>
+  
+
+
+  &#124; <a href="#promethods">Protected Methods</a>
+  
+
+
+  &#124; <a href="#inhmethods">Inherited Methods</a>
+
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+
+</div><!-- end sum-details-links -->
+<div class="api-level">
+  
+  
+  
+
+</div>
+</div><!-- end api-info-block -->
+
+
+<!-- ======== START OF CLASS DATA ======== -->
+
+<div id="jd-header">
+    public
+     
+    final 
+    
+    class
+<h1 itemprop="name">PlusOneButtonWithPopup</h1>
+
+
+
+  
+  
+  
+
+  
+  
+  
+
+  
+    extends ViewGroup<br/>
+  
+  
+  
+
+  
+  
+  
+
+
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-">
+<table class="jd-inheritance-table">
+
+
+    <tr>
+         	
+        <td colspan="4" class="jd-inheritance-class-cell">java.lang.Object</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="3" class="jd-inheritance-class-cell">android.view.View</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="2" class="jd-inheritance-class-cell">android.view.ViewGroup</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.plus.PlusOneButtonWithPopup</td>
+    </tr>
+    
+
+</table>
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Class Overview</h2>
+<p itemprop="articleBody">+1 button which shows confirmation messages in a PopupWindow.
+</p>
+
+
+
+
+
+</div><!-- jd-descr -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Summary</h2>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="inhconstants" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Constants</div></th></tr>
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-constants-android.view.ViewGroup" class="jd-expando-trigger closed"
+          ><img id="inherited-constants-android.view.ViewGroup-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>From class
+android.view.ViewGroup
+<div id="inherited-constants-android.view.ViewGroup">
+  <div id="inherited-constants-android.view.ViewGroup-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-constants-android.view.ViewGroup-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">CLIP_TO_PADDING_MASK</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_AFTER_DESCENDANTS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_BEFORE_DESCENDANTS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_BLOCK_DESCENDANTS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_ALL_CACHES</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_ANIMATION_CACHE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_NO_CACHE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_SCROLLING_CACHE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-constants-android.view.View" class="jd-expando-trigger closed"
+          ><img id="inherited-constants-android.view.View-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>From class
+android.view.View
+<div id="inherited-constants-android.view.View">
+  <div id="inherited-constants-android.view.View-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-constants-android.view.View-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">DRAWING_CACHE_QUALITY_AUTO</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">DRAWING_CACHE_QUALITY_HIGH</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">DRAWING_CACHE_QUALITY_LOW</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FIND_VIEWS_WITH_CONTENT_DESCRIPTION</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FIND_VIEWS_WITH_TEXT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUSABLES_ALL</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUSABLES_TOUCH_MODE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_BACKWARD</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_DOWN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_FORWARD</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_LEFT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_RIGHT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_UP</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">GONE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">HAPTIC_FEEDBACK_ENABLED</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">IMPORTANT_FOR_ACCESSIBILITY_AUTO</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">IMPORTANT_FOR_ACCESSIBILITY_NO</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">IMPORTANT_FOR_ACCESSIBILITY_YES</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">INVISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">KEEP_SCREEN_ON</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">LAYER_TYPE_HARDWARE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">LAYER_TYPE_NONE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">LAYER_TYPE_SOFTWARE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_HEIGHT_STATE_SHIFT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_SIZE_MASK</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_STATE_MASK</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_STATE_TOO_SMALL</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">NO_ID</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">OVER_SCROLL_ALWAYS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">OVER_SCROLL_IF_CONTENT_SCROLLS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">OVER_SCROLL_NEVER</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCREEN_STATE_OFF</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCREEN_STATE_ON</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_INSIDE_INSET</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_INSIDE_OVERLAY</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_OUTSIDE_INSET</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_OUTSIDE_OVERLAY</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBAR_POSITION_DEFAULT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBAR_POSITION_LEFT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBAR_POSITION_RIGHT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SOUND_EFFECTS_ENABLED</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">STATUS_BAR_HIDDEN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">STATUS_BAR_VISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_FULLSCREEN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_HIDE_NAVIGATION</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LAYOUT_STABLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LOW_PROFILE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_VISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_LAYOUT_FLAGS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">TEXT_ALIGNMENT_INHERIT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">TEXT_ALIGNMENT_RESOLVED_DEFAULT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">String</td>
+        <td class="jd-linkcol">VIEW_LOG_TAG</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">VISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</table>
+
+
+
+
+
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="inhfields" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Fields</div></th></tr>
+
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-fields-android.view.View" class="jd-expando-trigger closed"
+          ><img id="inherited-fields-android.view.View-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>From class
+android.view.View
+<div id="inherited-fields-android.view.View">
+  <div id="inherited-fields-android.view.View-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-fields-android.view.View-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ALPHA</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">EMPTY_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ROTATION</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ROTATION_X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ROTATION_Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">SCALE_X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">SCALE_Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">TRANSLATION_X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">TRANSLATION_Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</table>
+
+
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="pubctors" class="jd-sumtable"><tr><th colspan="12">Public Constructors</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#PlusOneButtonWithPopup(android.content.Context)">PlusOneButtonWithPopup</a></span>(Context context)</nobr>
+        
+        <div class="jd-descrdiv">Constructor to create from code.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#PlusOneButtonWithPopup(android.content.Context, android.util.AttributeSet)">PlusOneButtonWithPopup</a></span>(Context context, AttributeSet attrs)</nobr>
+        
+        <div class="jd-descrdiv">Constructor called when inflating from XML.</div>
+  
+  </td></tr>
+
+
+
+</table>
+
+
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="pubmethods" class="jd-sumtable"><tr><th colspan="12">Public Methods</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#cancelClick()">cancelClick</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Restore the original +1 button state.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            PendingIntent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#getResolution()">getResolution</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Returns a pending intent to resolve the connection failure or <code>null</code> if there
+ was none.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#initialize(java.lang.String, java.lang.String)">initialize</a></span>(String url, String accountName)</nobr>
+        
+        <div class="jd-descrdiv">Updates the +1 button for the argument URL and account.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#reinitialize()">reinitialize</a></span>()</nobr>
+        
+        <div class="jd-descrdiv">Reload the +1 button state.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#setAnnotation(int)">setAnnotation</a></span>(int annotation)</nobr>
+        
+        <div class="jd-descrdiv">Sets the annotation to display next to the button.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#setOnClickListener(android.view.View.OnClickListener)">setOnClickListener</a></span>(View.OnClickListener onClickListener)</nobr>
+        
+        <div class="jd-descrdiv">Sets the <code><a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a></code> to handle clicks.</div>
+  
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#setSize(int)">setSize</a></span>(int size)</nobr>
+        
+        <div class="jd-descrdiv">Sets the size of the +1 button image.</div>
+  
+  </td></tr>
+
+
+
+</table>
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#onLayout(boolean, int, int, int, int)">onLayout</a></span>(boolean changed, int left, int top, int right, int bottom)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html#onMeasure(int, int)">onMeasure</a></span>(int widthMeasureSpec, int heightMeasureSpec)</nobr>
+        
+  </td></tr>
+
+
+
+</table>
+
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="inhmethods" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Methods</div></th></tr>
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewGroup" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.ViewGroup-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  android.view.ViewGroup
+
+<div id="inherited-methods-android.view.ViewGroup">
+  <div id="inherited-methods-android.view.ViewGroup-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.ViewGroup-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addStatesFromChildren</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2, boolean arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">attachLayoutAnimationParameters</span>(View arg0, ViewGroup.LayoutParams arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">attachViewToParent</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">canAnimate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">cleanupLayoutState</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearDisappearingChildren</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">debug</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachAllViewsFromParent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachViewFromParent</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachViewFromParent</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachViewsFromParent</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDisplayHint</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDragEvent</span>(DragEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchFreezeSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetActivated</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetPressed</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetSelected</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSystemUiVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchThawSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowFocusChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowSystemUiVisiblityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawChild</span>(Canvas arg0, View arg1, long arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawableStateChanged</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">endViewTransition</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildAt</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildCount</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildDrawingOrder</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildMeasureSpec</span>(int arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildStaticTransformation</span>(View arg0, Transformation arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDescendantFocusability</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFocusedChild</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            LayoutAnimationController</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Animation.AnimationListener</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutAnimationListener</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            LayoutTransition</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutTransition</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPersistentDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocusable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">indexOfChild</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isAlwaysDrawnWithCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isAnimationCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isChildrenDrawingOrderEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isChildrenDrawnWithCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isMotionEventSplittingEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">jumpDrawablesToCurrentState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">layout</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measureChild</span>(View arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measureChildWithMargins</span>(View arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measureChildren</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetDescendantRectToMyCoords</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetRectIntoDescendantCoords</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationEnd</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationStart</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateDrawableState</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInterceptHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInterceptTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onLayout</span>(boolean arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onRequestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeAllViews</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeAllViewsInLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeDetachedView</span>(View arg0, boolean arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViewAt</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViewInLayout</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViews</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViewsInLayout</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestDisallowInterceptTouchEvent</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scheduleLayoutAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAddStatesFromChildren</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAlwaysDrawnWithCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAnimationCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setChildrenDrawingCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setChildrenDrawingOrderEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setChildrenDrawnWithCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setClipChildren</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setClipToPadding</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDescendantFocusability</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutAnimation</span>(LayoutAnimationController arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutAnimationListener</span>(Animation.AnimationListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutTransition</span>(LayoutTransition arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMotionEventSplittingEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnHierarchyChangeListener</span>(ViewGroup.OnHierarchyChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPadding</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPersistentDrawingCache</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setStaticTransformationsEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">shouldDelayChildPressedState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ActionMode</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startLayoutAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startViewTransition</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.View" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.View-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  android.view.View
+
+<div id="inherited-methods-android.view.View">
+  <div id="inherited-methods-android.view.View-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.View-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addOnAttachStateChangeListener</span>(View.OnAttachStateChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addOnLayoutChangeListener</span>(View.OnLayoutChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewPropertyAnimator</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">animate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">announceForAccessibility</span>(CharSequence arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">awakenScrollBars</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">awakenScrollBars</span>(int arg0, boolean arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">awakenScrollBars</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">bringToFront</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">buildDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">buildDrawingCache</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">buildLayer</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">callOnClick</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">canScrollHorizontally</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">canScrollVertically</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">cancelLongPress</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">checkInputConnectionProxy</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">combineMeasuredStates</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeHorizontalScrollExtent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeHorizontalScrollOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeHorizontalScrollRange</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeScroll</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeVerticalScrollExtent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeVerticalScrollOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeVerticalScrollRange</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            AccessibilityNodeInfo</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">createAccessibilityNodeInfo</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">destroyDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDisplayHint</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDragEvent</span>(DragEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericMotionEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetActivated</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetPressed</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetSelected</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSystemUiVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowFocusChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowSystemUiVisiblityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawableStateChanged</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewById</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewWithTag</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusSearch</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">forceLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            AccessibilityNodeProvider</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getAccessibilityNodeProvider</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getAlpha</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Animation</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            IBinder</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getApplicationWindowToken</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Drawable</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBackground</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBaseline</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBottom</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBottomFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBottomPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getCameraDistance</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            CharSequence</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getContentDescription</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            Context</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getContext</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ContextMenu.ContextMenuInfo</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getContextMenuInfo</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDefaultSize</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawableState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Bitmap</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCache</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Bitmap</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCacheBackgroundColor</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCacheQuality</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            long</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingTime</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFilterTouchesWhenObscured</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFitsSystemWindows</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ArrayList&lt;View&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFocusables</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFocusedRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0, Point arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Handler</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHandler</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHitRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHorizontalFadingEdgeLength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHorizontalScrollbarHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getImportantForAccessibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getKeepScreenOn</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            KeyEvent.DispatcherState</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getKeyDispatcherState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayerType</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutParams</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLeft</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLeftFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLeftPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLocalVisibleRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLocationInWindow</span>(int[] arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLocationOnScreen</span>(int[] arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Matrix</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMatrix</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredHeightAndState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredWidthAndState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMinimumHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMinimumWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusDownId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusForwardId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusLeftId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusRightId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusUpId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View.OnFocusChangeListener</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getOnFocusChangeListener</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getOverScrollMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingBottom</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingLeft</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingRight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingTop</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParentForAccessibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPivotX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPivotY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Resources</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getResources</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRightFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRightPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRootView</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRotation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRotationX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRotationY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScaleX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScaleY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarDefaultDelayBeforeFade</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarFadeDuration</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarSize</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarStyle</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSolidColor</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSuggestedMinimumHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSuggestedMinimumWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSystemUiVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTag</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTag</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTop</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTopFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTopPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            TouchDelegate</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTouchDelegate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ArrayList&lt;View&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTouchables</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTranslationX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTranslationY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVerticalFadingEdgeLength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVerticalScrollbarPosition</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVerticalScrollbarWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewTreeObserver</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getViewTreeObserver</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowAttachCount</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowSystemUiVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            IBinder</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowToken</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowVisibleDisplayFrame</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocusable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasOnClickListeners</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasOverlappingRendering</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasTransientState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasWindowFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">inflate</span>(Context arg0, int arg1, ViewGroup arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">initializeFadingEdge</span>(TypedArray arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">initializeScrollbars</span>(TypedArray arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidate</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidate</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isActivated</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isClickable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isDirty</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isDrawingCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isDuplicateParentStateEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isFocusable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isFocusableInTouchMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isFocused</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHapticFeedbackEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHardwareAccelerated</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHorizontalFadingEdgeEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHorizontalScrollBarEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHovered</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isInEditMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isInTouchMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isLayoutRequested</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isLongClickable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isOpaque</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isPaddingOffsetRequired</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isPressed</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSaveEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSaveFromParentEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isScrollContainer</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isScrollbarFadingEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSelected</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isShown</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSoundEffectsEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isVerticalFadingEdgeEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isVerticalScrollBarEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">jumpDrawablesToCurrentState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">layout</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measure</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">mergeDrawableStates</span>(int[] arg0, int[] arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetLeftAndRight</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetTopAndBottom</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationEnd</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationStart</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAttachedToWindow</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCheckIsTextEditor</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateDrawableState</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            InputConnection</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateInputConnection</span>(EditorInfo arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDetachedFromWindow</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDisplayHint</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDragEvent</span>(DragEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDraw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDrawScrollBars</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFilterTouchEventForSecurity</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFinishInflate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFinishTemporaryDetach</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, Rect arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onGenericMotionEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onHoverChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityNodeInfo</span>(AccessibilityNodeInfo arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyPreIme</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyShortcut</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onLayout</span>(boolean arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onMeasure</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onOverScrolled</span>(int arg0, int arg1, boolean arg2, boolean arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onRestoreInstanceState</span>(Parcelable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Parcelable</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSaveInstanceState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onScreenStateChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onScrollChanged</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSetAlpha</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSizeChanged</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onStartTemporaryDetach</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onTrackballEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onVisibilityChanged</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onWindowFocusChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onWindowSystemUiVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onWindowVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">overScrollBy</span>(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, boolean arg8)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performAccessibilityAction</span>(int arg0, Bundle arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performClick</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performHapticFeedback</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performHapticFeedback</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performLongClick</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">playSoundEffect</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">post</span>(Runnable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postDelayed</span>(Runnable arg0, long arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidate</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateDelayed</span>(long arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateDelayed</span>(long arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateOnAnimation</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateOnAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postOnAnimation</span>(Runnable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postOnAnimationDelayed</span>(Runnable arg0, long arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">refreshDrawableState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeCallbacks</span>(Runnable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeOnAttachStateChangeListener</span>(View.OnAttachStateChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeOnLayoutChangeListener</span>(View.OnLayoutChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFitSystemWindows</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocusFromTouch</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0, boolean arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">resolveSize</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">resolveSizeAndState</span>(int arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">restoreHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">saveHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scrollBy</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scrollTo</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEvent</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAccessibilityDelegate</span>(View.AccessibilityDelegate arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setActivated</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAlpha</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAnimation</span>(Animation arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackground</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackgroundColor</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackgroundDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackgroundResource</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBottom</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setCameraDistance</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setClickable</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setContentDescription</span>(CharSequence arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDrawingCacheBackgroundColor</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDrawingCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDrawingCacheQuality</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDuplicateParentStateEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFadingEdgeLength</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFilterTouchesWhenObscured</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFitsSystemWindows</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFocusable</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFocusableInTouchMode</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHapticFeedbackEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHasTransientState</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHorizontalFadingEdgeEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHorizontalScrollBarEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHovered</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setImportantForAccessibility</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setKeepScreenOn</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayerType</span>(int arg0, Paint arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLeft</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLongClickable</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMeasuredDimension</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMinimumHeight</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMinimumWidth</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusDownId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusForwardId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusLeftId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusRightId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusUpId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnClickListener</span>(View.OnClickListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnCreateContextMenuListener</span>(View.OnCreateContextMenuListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnDragListener</span>(View.OnDragListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnFocusChangeListener</span>(View.OnFocusChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnGenericMotionListener</span>(View.OnGenericMotionListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnHoverListener</span>(View.OnHoverListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnKeyListener</span>(View.OnKeyListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnLongClickListener</span>(View.OnLongClickListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnSystemUiVisibilityChangeListener</span>(View.OnSystemUiVisibilityChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnTouchListener</span>(View.OnTouchListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOverScrollMode</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPadding</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPivotX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPivotY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPressed</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRight</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRotation</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRotationX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRotationY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSaveEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSaveFromParentEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScaleX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScaleY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarDefaultDelayBeforeFade</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarFadeDuration</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarSize</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarStyle</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollContainer</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollX</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollY</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollbarFadingEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSelected</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSoundEffectsEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSystemUiVisibility</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTag</span>(int arg0, Object arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTag</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTop</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTouchDelegate</span>(TouchDelegate arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTranslationX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTranslationY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVerticalFadingEdgeEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVerticalScrollBarEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVerticalScrollbarPosition</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVisibility</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setWillNotCacheDrawing</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setWillNotDraw</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">showContextMenu</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ActionMode</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startActionMode</span>(ActionMode.Callback arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startAnimation</span>(Animation arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, Object arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">willNotCacheDrawing</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">willNotDraw</span>()</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-java.lang.Object" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-java.lang.Object-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  java.lang.Object
+
+<div id="inherited-methods-java.lang.Object">
+  <div id="inherited-methods-java.lang.Object-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-java.lang.Object-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clone</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">finalize</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            Class&lt;?&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getClass</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hashCode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">notify</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">notifyAll</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">toString</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>(long arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>(long arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.graphics.drawable.Drawable.Callback" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.graphics.drawable.Drawable.Callback-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.graphics.drawable.Drawable.Callback
+
+<div id="inherited-methods-android.graphics.drawable.Drawable.Callback">
+  <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.KeyEvent.Callback" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.KeyEvent.Callback-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.KeyEvent.Callback
+
+<div id="inherited-methods-android.view.KeyEvent.Callback">
+  <div id="inherited-methods-android.view.KeyEvent.Callback-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.KeyEvent.Callback-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewManager" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.ViewManager-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.ViewManager
+
+<div id="inherited-methods-android.view.ViewManager">
+  <div id="inherited-methods-android.view.ViewManager-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.ViewManager-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewParent" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.ViewParent-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.ViewParent
+
+<div id="inherited-methods-android.view.ViewParent">
+  <div id="inherited-methods-android.view.ViewParent-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.ViewParent-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParentForAccessibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isLayoutRequested</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestDisallowInterceptTouchEvent</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFitSystemWindows</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ActionMode</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.accessibility.AccessibilityEventSource" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.accessibility.AccessibilityEventSource-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.accessibility.AccessibilityEventSource
+
+<div id="inherited-methods-android.view.accessibility.AccessibilityEventSource">
+  <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEvent</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+</table>
+
+
+</div><!-- jd-descr (summary) -->
+
+<!-- Details -->
+
+
+
+
+
+
+
+
+<!-- XML Attributes -->
+
+
+<!-- Enum Values -->
+
+
+<!-- Constants -->
+
+
+<!-- Fields -->
+
+
+<!-- Public ctors -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<h2>Public Constructors</h2>
+
+
+
+<A NAME="PlusOneButtonWithPopup(android.content.Context)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        
+      </span>
+      <span class="sympad">PlusOneButtonWithPopup</span>
+      <span class="normal">(Context context)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Constructor to create from code.
+</p></div>
+
+    </div>
+</div>
+
+
+<A NAME="PlusOneButtonWithPopup(android.content.Context, android.util.AttributeSet)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        
+      </span>
+      <span class="sympad">PlusOneButtonWithPopup</span>
+      <span class="normal">(Context context, AttributeSet attrs)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Constructor called when inflating from XML.
+</p></div>
+
+    </div>
+</div>
+
+
+
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<!-- Protected ctors -->
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methdos -->
+
+<h2>Public Methods</h2>
+
+
+
+<A NAME="cancelClick()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">cancelClick</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Restore the original +1 button state.
+</p></div>
+
+    </div>
+</div>
+
+
+<A NAME="getResolution()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        PendingIntent
+      </span>
+      <span class="sympad">getResolution</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Returns a pending intent to resolve the connection failure or <code>null</code> if there
+ was none.
+</p></div>
+
+    </div>
+</div>
+
+
+<A NAME="initialize(java.lang.String, java.lang.String)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">initialize</span>
+      <span class="normal">(String url, String accountName)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Updates the +1 button for the argument URL and account.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>url</td>
+          <td>The URL to be +1'd.</td>
+        </tr>
+        <tr>
+          <th>accountName</td>
+          <td>The the name of the account tied to this +1 button (may be null).
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
+<A NAME="reinitialize()"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">reinitialize</span>
+      <span class="normal">()</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Reload the +1 button state.
+</p></div>
+
+    </div>
+</div>
+
+
+<A NAME="setAnnotation(int)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">setAnnotation</span>
+      <span class="normal">(int annotation)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets the annotation to display next to the button.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>annotation</td>
+          <td>The annotation.  See <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#ANNOTATION_NONE">ANNOTATION_NONE</a></code>,
+            <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#ANNOTATION_INLINE">ANNOTATION_INLINE</a></code>,
+            and <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#ANNOTATION_BUBBLE">ANNOTATION_BUBBLE</a></code>.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
+<A NAME="setOnClickListener(android.view.View.OnClickListener)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">setOnClickListener</span>
+      <span class="normal">(View.OnClickListener onClickListener)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets the <code><a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a></code> to handle clicks.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>onClickListener</td>
+          <td>The listener, or null for default behavior.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
+<A NAME="setSize(int)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">setSize</span>
+      <span class="normal">(int size)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Sets the size of the +1 button image.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>size</td>
+          <td>The size. See <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_STANDARD">SIZE_STANDARD</a></code>,
+            <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_TALL">SIZE_TALL</a></code>, <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_MEDIUM">SIZE_MEDIUM</a></code>, and
+            <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.html#SIZE_SMALL">SIZE_SMALL</a></code>.
+</td>
+        </tr>
+      </table>
+  </div>
+
+    </div>
+</div>
+
+
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+
+<h2>Protected Methods</h2>
+
+
+
+<A NAME="onLayout(boolean, int, int, int, int)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        protected 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">onLayout</span>
+      <span class="normal">(boolean changed, int left, int top, int right, int bottom)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+<A NAME="onMeasure(int, int)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        protected 
+         
+         
+         
+         
+        void
+      </span>
+      <span class="sympad">onMeasure</span>
+      <span class="normal">(int widthMeasureSpec, int heightMeasureSpec)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+
+
+
+<!-- ========= END OF CLASS DATA ========= -->
+<A NAME="navbar_top"></A>
+
+<div id="footer" class="wrap" >
+        
+
+  <div id="copyright">
+    
+  Except as noted, this content is licensed under <a
+  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
+  For details and restrictions, see the <a href="/license.html">
+  Content License</a>.
+  </div>
+  <div id="build_info">
+    
+<script src="/timestamp.js" type="text/javascript"></script>
+<script>document.write(BUILD_TIMESTAMP)</script>
+
+  </div>
+
+
+  <div id="footerlinks">
+    
+  <p>
+    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/support.html">Support</a>
+  </p>
+  </div>
+
+</div> <!-- end footer -->
+</div> <!-- jd-content -->
+
+</div><!-- end doc-content -->
+
+</div> <!-- end body-content --> 
+
+
+
+
+
+
+</body>
+</html>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusOneDummyView.html b/docs/html/reference/com/google/android/gms/plus/PlusOneDummyView.html
new file mode 100644
index 0000000..e3fbd0d
--- /dev/null
+++ b/docs/html/reference/com/google/android/gms/plus/PlusOneDummyView.html
@@ -0,0 +1,12177 @@
+<!DOCTYPE html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<html>
+<head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
+
+<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
+<title>PlusOneDummyView | Android Developers</title>
+
+<!-- STYLESHEETS -->
+<link rel="stylesheet"
+href="//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
+
+
+
+<!-- JAVASCRIPT -->
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
+<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
+<script type="text/javascript">
+  var toRoot = "/";
+  var devsite = false;
+</script>
+<script src="/assets/js/docs.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-5831155-1']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+</script>
+</head>
+<body class="gc-documentation google
+  develop" itemscope itemtype="http://schema.org/Article">
+  <div id="doc-api-level" class="" style="display:none"></div>
+  <a name="top"></a>
+
+<a name="top"></a>
+
+    <!-- Header -->
+    <div id="header">
+        <div class="wrap" id="header-wrap">
+          <div class="col-3 logo">
+          <a href="/index.html">
+            <img src="/assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
+          </a>
+          <div class="btn-quicknav" id="btn-quicknav">
+          	<a href="#" class="arrow-inactive">Quicknav</a>
+			      <a href="#" class="arrow-active">Quicknav</a>
+          </div>
+          </div>
+            <ul class="nav-x col-9">
+                <li class="design">
+                  <a href="/design/index.html"
+                  zh-tw-lang="設計"
+                  zh-cn-lang="设计"
+                  ru-lang="Проектирование"
+                  ko-lang="디자인"
+                  ja-lang="設計"
+                  es-lang="Diseñar"               
+                  >Design</a></li>
+                <li class="develop"><a href="/develop/index.html"
+                  zh-tw-lang="開發"
+                  zh-cn-lang="开发"
+                  ru-lang="Разработка"
+                  ko-lang="개발"
+                  ja-lang="開発"
+                  es-lang="Desarrollar"               
+                  >Develop</a></li>
+                <li class="distribute last"><a href="/distribute/index.html"
+                  zh-tw-lang="發佈"
+                  zh-cn-lang="分发"
+                  ru-lang="Распространение"
+                  ko-lang="배포"
+                  ja-lang="配布"
+                  es-lang="Distribuir"               
+                  >Distribute</a></li>
+            </ul>
+            
+            <!-- New Search -->
+            <div class="menu-container">
+            <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
+  <div class="morehover" id="moremenu">
+    <div class="top"></div>
+    <div class="mid">
+      <div class="header">Links</div>
+      <ul>
+        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
+        <li><a href="/about/index.html">About Android</a></li>
+      </ul>
+      <div class="header">Android Sites</div>
+      <ul>
+        <li><a href="http://www.android.com">Android.com</a></li>
+        <li class="active"><a>Android Developers</a></li>
+        <li><a href="http://source.android.com">Android Open Source Project</a></li>
+      </ul>
+      
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
+
+
+      <br class="clearfix" />
+    </div>
+    <div class="bottom"></div>
+  </div>
+  <div class="search" id="search-container">
+    <div class="search-inner">
+      <div id="search-btn"></div>
+      <div class="left"></div>
+      <form onsubmit="return submit_search()">
+        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
+onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+onkeydown="return search_changed(event, true, '/')" 
+onkeyup="return search_changed(event, false, '/')" />
+      </form>
+      <div class="right"></div>
+        <a class="close hide">close</a>
+        <div class="left"></div>
+        <div class="right"></div>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper reference">
+    <div class="suggest-card reference no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper docs">
+    <div class="suggest-card dummy no-display">&nbsp;</div>
+    <div class="suggest-card develop no-display">
+      <ul class="search_filtered">
+      </ul>
+      <div class="child-card guides no-display">
+      </div>
+      <div class="child-card training no-display">
+      </div>
+    </div>
+    <div class="suggest-card design no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+    <div class="suggest-card distribute no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  </div>
+  <!-- /New Search>
+          
+          
+          <!-- Expanded quicknav -->
+           <div id="quicknav" class="col-9">
+                <ul>
+                    <li class="design">
+                      <ul>
+                        <li><a href="/design/index.html">Get Started</a></li>
+                        <li><a href="/design/style/index.html">Style</a></li>
+                        <li><a href="/design/patterns/index.html">Patterns</a></li>
+                        <li><a href="/design/building-blocks/index.html">Building Blocks</a></li>
+                        <li><a href="/design/downloads/index.html">Downloads</a></li>
+                        <li><a href="/design/videos/index.html">Videos</a></li>
+                      </ul>
+                    </li>
+                    <li class="develop">
+                      <ul>
+                        <li><a href="/training/index.html"
+                          zh-tw-lang="訓練課程"
+                          zh-cn-lang="培训"
+                          ru-lang="Курсы"
+                          ko-lang="교육"
+                          ja-lang="トレーニング"
+                          es-lang="Capacitación"               
+                          >Training</a></li>
+                        <li><a href="/guide/components/index.html"
+                          zh-tw-lang="API 指南"
+                          zh-cn-lang="API 指南"
+                          ru-lang="Руководства по API"
+                          ko-lang="API 가이드"
+                          ja-lang="API ガイド"
+                          es-lang="Guías de la API"               
+                          >API Guides</a></li>
+                        <li><a href="/reference/packages.html"
+                          zh-tw-lang="參考資源"
+                          zh-cn-lang="参考"
+                          ru-lang="Справочник"
+                          ko-lang="참조문서"
+                          ja-lang="リファレンス"
+                          es-lang="Referencia"               
+                          >Reference</a></li>
+                        <li><a href="/tools/index.html"
+                          zh-tw-lang="相關工具"
+                          zh-cn-lang="工具"
+                          ru-lang="Инструменты"
+                          ko-lang="도구"
+                          ja-lang="ツール"
+                          es-lang="Herramientas"               
+                          >Tools</a>
+                          <ul><li><a href="/sdk/index.html">Get the SDK</a></li></ul>
+                        </li>
+                        <li><a href="/google/index.html">Google Services</a>
+                        </li>
+                        
+                      </ul>
+                    </li>
+                    <li class="distribute last">
+                      <ul>
+                        <li><a href="/distribute/index.html">Google Play</a></li>
+                        <li><a href="/distribute/googleplay/publish/index.html">Publishing</a></li>
+                        <li><a href="/distribute/googleplay/promote/index.html">Promoting</a></li>
+                        <li><a href="/distribute/googleplay/quality/index.html">App Quality</a></li>
+                        <li><a href="/distribute/googleplay/spotlight/index.html">Spotlight</a></li>
+                        <li><a href="/distribute/open.html">Open Distribution</a></li>
+                      </ul>
+                    </li>
+                </ul>
+          </div>
+          <!-- /Expanded quicknav -->
+        </div>
+    </div>
+    <!-- /Header -->
+    
+    
+  <div id="searchResults" class="wrap" style="display:none;">
+          <h2 id="searchTitle">Results</h2>
+          <div id="leftSearchControl" class="search-control">Loading...</div>
+  </div>
+    
+    
+  
+    <!-- Secondary x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x col-9 develop" style="width:100%">
+                <li class="training"><a href="/training/index.html"
+                  zh-tw-lang="訓練課程"
+                  zh-cn-lang="培训"
+                  ru-lang="Курсы"
+                  ko-lang="교육"
+                  ja-lang="トレーニング"
+                  es-lang="Capacitación"               
+                  >Training</a></li>
+                <li class="guide"><a href="/guide/components/index.html"
+                  zh-tw-lang="API 指南"
+                  zh-cn-lang="API 指南"
+                  ru-lang="Руководства по API"
+                  ko-lang="API 가이드"
+                  ja-lang="API ガイド"
+                  es-lang="Guías de la API"               
+                  >API Guides</a></li>
+                <li class="reference"><a href="/reference/packages.html"
+                  zh-tw-lang="參考資源"
+                  zh-cn-lang="参考"
+                  ru-lang="Справочник"
+                  ko-lang="참조문서"
+                  ja-lang="リファレンス"
+                  es-lang="Referencia"               
+                  >Reference</a></li>
+                <li class="tools"><a href="/tools/index.html"
+                  zh-tw-lang="相關工具"
+                  zh-cn-lang="工具"
+                  ru-lang="Инструменты"
+                  ko-lang="도구"
+                  ja-lang="ツール"
+                  es-lang="Herramientas"
+                  >Tools</a></li>
+                <li class="google"><a href="/google/index.html"
+                  >Google Services</a>
+                </li>
+                
+            </ul>
+        </div>
+        
+    </div>
+    <!-- /Sendondary x-nav -->
+  
+
+
+
+
+  
+
+
+  
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
+
+
+
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/index.html">
+          <span class="en">Overview</span>
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/games.html">
+          <span class="en">Games</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/location.html">
+          <span class="en">Location</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/plus.html">
+          <span class="en">Google+</span>
+                </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/maps.html">
+          <span class="en">Google Maps</span>
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/google/play-services/auth.html">
+          <span class="en">Authorization</span>
+      </a></div>
+  </li>
+
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play-services/index.html">
+      <span class="en">Google Play Services</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play-services/setup.html">
+          <span class="en">Setup</span></a>
+      </li>
+      <li id="gms-tree-list" class="nav-section">
+        <div class="nav-section-header">
+          <a href="/reference/gms-packages.html">
+            <span class="en">Reference</span>
+          </a>
+        <div>
+      </li>
+    </ul>
+  </li>
+
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/billing/index.html">
+      <span class="en">Google Play In-app Billing</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/billing/billing_overview.html">
+              <span class="en">Overview</span></a>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/api.html">
+              <span class="en">Version 3 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="/google/play/billing/v2/api.html">
+              <span class="en">Version 2 API</span></a></div>
+              <ul>
+              <li><a href="/google/play/billing/v2/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a></li>
+              <li><a href="/google/play/billing/v2/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li><a href="/google/play/billing/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_best_practices.html">
+              <span class="en">Security and Design</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_testing.html">
+              <span class="en">Testing In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/billing_admin.html">
+              <span class="en">Administering In-app Billing</span></a>
+      </li>
+      <li><a href="/google/play/billing/gp-purchase-status-api.html">
+              <span class="en">Purchase Status API</span></a>
+      </li>
+      <li><a href="/google/play/billing/versions.html">
+              <span class="en">Version Notes</span></a>
+      </li>
+    </ul>
+  </li>
+
+
+
+  <li class="nav-section">
+      <div class="nav-section-header"><a href="/google/gcm/index.html">
+        <span class="en">Google Cloud Messaging</span></a>
+      </div>
+      <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
+        <li><a href="/google/gcm/gs.html">
+            <span class="en">Getting Started</span></a>
+        </li>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
+        </li>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
+        </li>
+        <li><a href="/google/gcm/notifications.html">
+              <span class="en">User Notifications</span></a>
+        </li>
+        <li><a href="/google/gcm/adv.html">
+            <span class="en">Advanced Topics</span></a>
+        </li>
+        <li><a href="/google/gcm/c2dm.html">
+            <span class="en">Migration</span></a>
+        </li>
+        <li id="gcm-tree-list" class="nav-section">
+          <div class="nav-section-header">
+            <a href="/reference/gcm-packages.html">
+              <span class="en">Reference</span>
+            </a>
+          <div>
+        </li>
+      </ul>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/play/dist.html">
+      <span class="en">Google Play Distribution</span></a>
+    </div>
+    <ul>
+      <li><a href="/google/play/filters.html">
+          <span class="en">Filters on Google Play</span></a>
+      </li>
+
+      <li><a href="/google/play/publishing/multiple-apks.html">
+          <span class="en">Multiple APK Support</span></a>
+      </li>
+      <li><a href="/google/play/expansion-files.html">
+          <span class="en">APK Expansion Files</span></a>
+      </li>
+      <li class="nav-section">
+        <div class="nav-section-header"><a href="/google/play/licensing/index.html">
+          <span class="en">Application Licensing</span></a>
+        </div>
+        <ul>
+          <li><a href="/google/play/licensing/overview.html">
+              <span class="en">Licensing Overview</span></a>
+          </li>
+          <li><a href="/google/play/licensing/setting-up.html">
+              <span class="en">Setting Up for Licensing</span></a>
+          </li>
+          <li><a href="/google/play/licensing/adding-licensing.html">
+              <span class="en">Adding Licensing to Your App</span></a>
+          </li>
+          <li><a href="/google/play/licensing/licensing-reference.html">
+              <span class="en">Licensing Reference</span></a>
+          </li>
+        </ul>
+      </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="/google/backup/index.html">
+      Android Backup Service</a>
+    </div>
+    <ul>
+      <li><a href="/google/backup/signup.html">
+          Register</a>
+      </li>
+    </ul>
+  </li>
+
+  </ul>
+
+</li>
+
+
+
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
+
+        
+
+      </div>
+      <script type="text/javascript">
+       showGoogleRefTree();
+    
+      </script>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+
+
+     
+
+
+
+<div class="col-12"  id="doc-col">
+
+<div id="api-info-block">
+
+
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+   
+  
+  
+  
+
+  
+   
+  
+  
+   
+  
+  
+   
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+  
+   
+  
+  
+  
+  
+
+
+<div class="sum-details-links">
+
+Summary:
+
+
+
+
+
+  <a href="#constants">Constants</a>
+  
+
+
+  &#124; <a href="#inhconstants">Inherited Constants</a>
+  
+
+
+
+  &#124; <a href="#inhfields">Inherited Fields</a>
+  
+
+
+  &#124; <a href="#pubctors">Ctors</a>
+  
+
+
+
+
+
+  &#124; <a href="#inhmethods">Inherited Methods</a>
+
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+
+</div><!-- end sum-details-links -->
+<div class="api-level">
+  
+  
+  
+
+</div>
+</div><!-- end api-info-block -->
+
+
+<!-- ======== START OF CLASS DATA ======== -->
+
+<div id="jd-header">
+    public
+     
+     
+    
+    class
+<h1 itemprop="name">PlusOneDummyView</h1>
+
+
+
+  
+  
+  
+
+  
+  
+  
+
+  
+  
+  
+
+  
+    extends FrameLayout<br/>
+  
+  
+  
+
+  
+  
+  
+
+
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-">
+<table class="jd-inheritance-table">
+
+
+    <tr>
+         	
+        <td colspan="5" class="jd-inheritance-class-cell">java.lang.Object</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="4" class="jd-inheritance-class-cell">android.view.View</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="3" class="jd-inheritance-class-cell">android.view.ViewGroup</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="2" class="jd-inheritance-class-cell">android.widget.FrameLayout</td>
+    </tr>
+    
+
+    <tr>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;</td>
+        
+            <td class="jd-inheritance-space">&nbsp;&nbsp;&nbsp;&#x21b3;</td>
+         	
+        <td colspan="1" class="jd-inheritance-class-cell">com.google.android.gms.plus.PlusOneDummyView</td>
+    </tr>
+    
+
+</table>
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Class Overview</h2>
+<p itemprop="articleBody">A class used to statically generate dummy views in the event of an error retrieving
+ a PlusOneButton from the apk
+</p>
+
+
+
+
+
+</div><!-- jd-descr -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<div class="jd-descr">
+
+
+<h2>Summary</h2>
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="constants" class="jd-sumtable"><tr><th colspan="12">Constants</th></tr>
+
+
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">String</td>
+        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneDummyView.html#TAG">TAG</a></td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+
+</table>
+
+
+
+
+
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="inhconstants" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Constants</div></th></tr>
+
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-constants-android.view.ViewGroup" class="jd-expando-trigger closed"
+          ><img id="inherited-constants-android.view.ViewGroup-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>From class
+android.view.ViewGroup
+<div id="inherited-constants-android.view.ViewGroup">
+  <div id="inherited-constants-android.view.ViewGroup-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-constants-android.view.ViewGroup-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">CLIP_TO_PADDING_MASK</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_AFTER_DESCENDANTS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_BEFORE_DESCENDANTS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_BLOCK_DESCENDANTS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_ALL_CACHES</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_ANIMATION_CACHE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_NO_CACHE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">PERSISTENT_SCROLLING_CACHE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-constants-android.view.View" class="jd-expando-trigger closed"
+          ><img id="inherited-constants-android.view.View-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>From class
+android.view.View
+<div id="inherited-constants-android.view.View">
+  <div id="inherited-constants-android.view.View-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-constants-android.view.View-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">DRAWING_CACHE_QUALITY_AUTO</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">DRAWING_CACHE_QUALITY_HIGH</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">DRAWING_CACHE_QUALITY_LOW</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FIND_VIEWS_WITH_CONTENT_DESCRIPTION</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FIND_VIEWS_WITH_TEXT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUSABLES_ALL</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUSABLES_TOUCH_MODE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_BACKWARD</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_DOWN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_FORWARD</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_LEFT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_RIGHT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">FOCUS_UP</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">GONE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">HAPTIC_FEEDBACK_ENABLED</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">IMPORTANT_FOR_ACCESSIBILITY_AUTO</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">IMPORTANT_FOR_ACCESSIBILITY_NO</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">IMPORTANT_FOR_ACCESSIBILITY_YES</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">INVISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">KEEP_SCREEN_ON</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">LAYER_TYPE_HARDWARE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">LAYER_TYPE_NONE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">LAYER_TYPE_SOFTWARE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_HEIGHT_STATE_SHIFT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_SIZE_MASK</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_STATE_MASK</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">MEASURED_STATE_TOO_SMALL</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">NO_ID</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">OVER_SCROLL_ALWAYS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">OVER_SCROLL_IF_CONTENT_SCROLLS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">OVER_SCROLL_NEVER</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCREEN_STATE_OFF</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCREEN_STATE_ON</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_INSIDE_INSET</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_INSIDE_OVERLAY</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_OUTSIDE_INSET</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBARS_OUTSIDE_OVERLAY</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBAR_POSITION_DEFAULT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBAR_POSITION_LEFT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SCROLLBAR_POSITION_RIGHT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SOUND_EFFECTS_ENABLED</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">STATUS_BAR_HIDDEN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">STATUS_BAR_VISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_FULLSCREEN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_HIDE_NAVIGATION</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LAYOUT_STABLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_LOW_PROFILE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_FLAG_VISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">SYSTEM_UI_LAYOUT_FLAGS</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">TEXT_ALIGNMENT_INHERIT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">TEXT_ALIGNMENT_RESOLVED_DEFAULT</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol">String</td>
+        <td class="jd-linkcol">VIEW_LOG_TAG</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol">int</td>
+        <td class="jd-linkcol">VISIBLE</td>
+        <td class="jd-descrcol" width="100%"></td>
+    </tr>
+    
+    
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</table>
+
+
+
+
+
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="inhfields" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Fields</div></th></tr>
+
+
+
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-fields-android.view.View" class="jd-expando-trigger closed"
+          ><img id="inherited-fields-android.view.View-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>From class
+android.view.View
+<div id="inherited-fields-android.view.View">
+  <div id="inherited-fields-android.view.View-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-fields-android.view.View-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ALPHA</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">EMPTY_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">ENABLED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">PRESSED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ROTATION</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ROTATION_X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">ROTATION_Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">SCALE_X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">SCALE_Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">SELECTED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">SELECTED_WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">TRANSLATION_X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">TRANSLATION_Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          protected
+          static
+          final
+          int[]</nobr></td>
+          <td class="jd-linkcol">WINDOW_FOCUSED_STATE_SET</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class=" api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">X</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+      <tr class="alt-color api apilevel-" >
+          <td class="jd-typecol"><nobr>
+          public
+          static
+          final
+          Property&lt;View,&nbsp;Float&gt;</nobr></td>
+          <td class="jd-linkcol">Y</td>
+          <td class="jd-descrcol" width="100%"></td>
+      </tr>
+      
+    
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</table>
+
+
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="pubctors" class="jd-sumtable"><tr><th colspan="12">Public Constructors</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusOneDummyView.html#PlusOneDummyView(android.content.Context, int)">PlusOneDummyView</a></span>(Context context, int size)</nobr>
+        
+  </td></tr>
+
+
+
+</table>
+
+
+
+
+
+
+
+
+
+
+
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="inhmethods" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Methods</div></th></tr>
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.widget.FrameLayout" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.widget.FrameLayout-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  android.widget.FrameLayout
+
+<div id="inherited-methods-android.widget.FrameLayout">
+  <div id="inherited-methods-android.widget.FrameLayout-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.widget.FrameLayout-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawableStateChanged</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getConsiderGoneChildrenWhenMeasuring</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Drawable</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getForeground</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getForegroundGravity</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasureAllChildren</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">jumpDrawablesToCurrentState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityNodeInfo</span>(AccessibilityNodeInfo arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onLayout</span>(boolean arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onMeasure</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSizeChanged</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setForeground</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setForegroundGravity</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMeasureAllChildren</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">shouldDelayChildPressedState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewGroup" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.ViewGroup-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  android.view.ViewGroup
+
+<div id="inherited-methods-android.view.ViewGroup">
+  <div id="inherited-methods-android.view.ViewGroup-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.ViewGroup-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addStatesFromChildren</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2, boolean arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addViewInLayout</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">attachLayoutAnimationParameters</span>(View arg0, ViewGroup.LayoutParams arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">attachViewToParent</span>(View arg0, int arg1, ViewGroup.LayoutParams arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">canAnimate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">checkLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">cleanupLayoutState</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearDisappearingChildren</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">debug</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachAllViewsFromParent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachViewFromParent</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachViewFromParent</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">detachViewsFromParent</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDisplayHint</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDragEvent</span>(DragEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchFreezeSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetActivated</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetPressed</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetSelected</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSystemUiVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchThawSelfOnly</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowFocusChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowSystemUiVisiblityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawChild</span>(Canvas arg0, View arg1, long arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawableStateChanged</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">endViewTransition</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">gatherTransparentRegion</span>(Region arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateDefaultLayoutParams</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(AttributeSet arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">generateLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildAt</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildCount</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildDrawingOrder</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildMeasureSpec</span>(int arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildStaticTransformation</span>(View arg0, Transformation arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDescendantFocusability</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFocusedChild</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            LayoutAnimationController</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Animation.AnimationListener</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutAnimationListener</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            LayoutTransition</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutTransition</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPersistentDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocusable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">indexOfChild</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isAlwaysDrawnWithCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isAnimationCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isChildrenDrawingOrderEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isChildrenDrawnWithCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isMotionEventSplittingEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">jumpDrawablesToCurrentState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">layout</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measureChild</span>(View arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measureChildWithMargins</span>(View arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measureChildren</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetDescendantRectToMyCoords</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetRectIntoDescendantCoords</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationEnd</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationStart</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateDrawableState</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInterceptHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInterceptTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onLayout</span>(boolean arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onRequestFocusInDescendants</span>(int arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onRequestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeAllViews</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeAllViewsInLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeDetachedView</span>(View arg0, boolean arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViewAt</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViewInLayout</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViews</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeViewsInLayout</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestDisallowInterceptTouchEvent</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scheduleLayoutAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAddStatesFromChildren</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAlwaysDrawnWithCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAnimationCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setChildrenDrawingCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setChildrenDrawingOrderEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setChildrenDrawnWithCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setClipChildren</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setClipToPadding</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDescendantFocusability</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutAnimation</span>(LayoutAnimationController arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutAnimationListener</span>(Animation.AnimationListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutTransition</span>(LayoutTransition arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMotionEventSplittingEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnHierarchyChangeListener</span>(ViewGroup.OnHierarchyChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPadding</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPersistentDrawingCache</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setStaticTransformationsEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">shouldDelayChildPressedState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ActionMode</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startLayoutAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startViewTransition</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.View" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.View-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  android.view.View
+
+<div id="inherited-methods-android.view.View">
+  <div id="inherited-methods-android.view.View-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.View-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addChildrenForAccessibility</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addFocusables</span>(ArrayList&lt;View&gt; arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addOnAttachStateChangeListener</span>(View.OnAttachStateChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addOnLayoutChangeListener</span>(View.OnLayoutChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addTouchables</span>(ArrayList&lt;View&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewPropertyAnimator</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">animate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">announceForAccessibility</span>(CharSequence arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">awakenScrollBars</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">awakenScrollBars</span>(int arg0, boolean arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">awakenScrollBars</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">bringToFront</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">buildDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">buildDrawingCache</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">buildLayer</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">callOnClick</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">canScrollHorizontally</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">canScrollVertically</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">cancelLongPress</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">checkInputConnectionProxy</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">combineMeasuredStates</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeHorizontalScrollExtent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeHorizontalScrollOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeHorizontalScrollRange</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeScroll</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeVerticalScrollExtent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeVerticalScrollOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">computeVerticalScrollRange</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            AccessibilityNodeInfo</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">createAccessibilityNodeInfo</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">destroyDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchConfigurationChanged</span>(Configuration arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDisplayHint</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDragEvent</span>(DragEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchDraw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericFocusedEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericMotionEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchGenericPointerEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyEventPreIme</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchKeyShortcutEvent</span>(KeyEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchRestoreInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSaveInstanceState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetActivated</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetPressed</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSetSelected</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchSystemUiVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchTrackballEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchUnhandledMove</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchVisibilityChanged</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowFocusChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowSystemUiVisiblityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">dispatchWindowVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">draw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">drawableStateChanged</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewById</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewWithTag</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">findViewsWithText</span>(ArrayList&lt;View&gt; arg0, CharSequence arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">fitSystemWindows</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusSearch</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">forceLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            AccessibilityNodeProvider</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getAccessibilityNodeProvider</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getAlpha</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Animation</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            IBinder</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getApplicationWindowToken</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Drawable</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBackground</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBaseline</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBottom</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBottomFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getBottomPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getCameraDistance</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            CharSequence</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getContentDescription</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            Context</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getContext</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ContextMenu.ContextMenuInfo</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getContextMenuInfo</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDefaultSize</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawableState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Bitmap</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCache</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Bitmap</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCache</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCacheBackgroundColor</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingCacheQuality</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            long</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getDrawingTime</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFilterTouchesWhenObscured</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFitsSystemWindows</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ArrayList&lt;View&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFocusables</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getFocusedRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0, Point arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getGlobalVisibleRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Handler</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHandler</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHitRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHorizontalFadingEdgeLength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getHorizontalScrollbarHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getImportantForAccessibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getKeepScreenOn</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            KeyEvent.DispatcherState</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getKeyDispatcherState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayerType</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewGroup.LayoutParams</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLayoutParams</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLeft</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLeftFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLeftPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLocalVisibleRect</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLocationInWindow</span>(int[] arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getLocationOnScreen</span>(int[] arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Matrix</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMatrix</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredHeightAndState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMeasuredWidthAndState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMinimumHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getMinimumWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusDownId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusForwardId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusLeftId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusRightId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getNextFocusUpId</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View.OnFocusChangeListener</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getOnFocusChangeListener</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getOverScrollMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingBottom</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingLeft</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingRight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPaddingTop</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParentForAccessibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPivotX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getPivotY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Resources</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getResources</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRightFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRightPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRootView</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRotation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRotationX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getRotationY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScaleX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScaleY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarDefaultDelayBeforeFade</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarFadeDuration</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarSize</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollBarStyle</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getScrollY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSolidColor</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSuggestedMinimumHeight</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSuggestedMinimumWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getSystemUiVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTag</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTag</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTop</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTopFadingEdgeStrength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTopPaddingOffset</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            TouchDelegate</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTouchDelegate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ArrayList&lt;View&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTouchables</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTranslationX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getTranslationY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVerticalFadingEdgeLength</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVerticalScrollbarPosition</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVerticalScrollbarWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ViewTreeObserver</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getViewTreeObserver</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWidth</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowAttachCount</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowSystemUiVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            IBinder</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowToken</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowVisibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getWindowVisibleDisplayFrame</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getX</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            float</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getY</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasFocusable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasOnClickListeners</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasOverlappingRendering</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasTransientState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hasWindowFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">inflate</span>(Context arg0, int arg1, ViewGroup arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">initializeFadingEdge</span>(TypedArray arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">initializeScrollbars</span>(TypedArray arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidate</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidate</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isActivated</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isClickable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isDirty</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isDrawingCacheEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isDuplicateParentStateEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isFocusable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isFocusableInTouchMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isFocused</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHapticFeedbackEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHardwareAccelerated</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHorizontalFadingEdgeEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHorizontalScrollBarEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isHovered</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isInEditMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isInTouchMode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isLayoutRequested</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isLongClickable</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isOpaque</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isPaddingOffsetRequired</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isPressed</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSaveEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSaveFromParentEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isScrollContainer</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isScrollbarFadingEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSelected</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isShown</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isSoundEffectsEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isVerticalFadingEdgeEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isVerticalScrollBarEnabled</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">jumpDrawablesToCurrentState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">layout</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">measure</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">mergeDrawableStates</span>(int[] arg0, int[] arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetLeftAndRight</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">offsetTopAndBottom</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationEnd</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAnimationStart</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onAttachedToWindow</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCheckIsTextEditor</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onConfigurationChanged</span>(Configuration arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateContextMenu</span>(ContextMenu arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int[]</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateDrawableState</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            InputConnection</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onCreateInputConnection</span>(EditorInfo arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDetachedFromWindow</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDisplayHint</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDragEvent</span>(DragEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDraw</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onDrawScrollBars</span>(Canvas arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFilterTouchEventForSecurity</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFinishInflate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFinishTemporaryDetach</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onFocusChanged</span>(boolean arg0, int arg1, Rect arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onGenericMotionEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onHoverChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onHoverEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onInitializeAccessibilityNodeInfo</span>(AccessibilityNodeInfo arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyPreIme</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyShortcut</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onLayout</span>(boolean arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onMeasure</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onOverScrolled</span>(int arg0, int arg1, boolean arg2, boolean arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onPopulateAccessibilityEvent</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onRestoreInstanceState</span>(Parcelable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Parcelable</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSaveInstanceState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onScreenStateChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onScrollChanged</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSetAlpha</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onSizeChanged</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onStartTemporaryDetach</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onTouchEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onTrackballEvent</span>(MotionEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onVisibilityChanged</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onWindowFocusChanged</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onWindowSystemUiVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onWindowVisibilityChanged</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">overScrollBy</span>(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, boolean arg8)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performAccessibilityAction</span>(int arg0, Bundle arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performClick</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performHapticFeedback</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performHapticFeedback</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">performLongClick</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">playSoundEffect</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">post</span>(Runnable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postDelayed</span>(Runnable arg0, long arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidate</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidate</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateDelayed</span>(long arg0, int arg1, int arg2, int arg3, int arg4)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateDelayed</span>(long arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateOnAnimation</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postInvalidateOnAnimation</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postOnAnimation</span>(Runnable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">postOnAnimationDelayed</span>(Runnable arg0, long arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">refreshDrawableState</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeCallbacks</span>(Runnable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeOnAttachStateChangeListener</span>(View.OnAttachStateChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeOnLayoutChangeListener</span>(View.OnLayoutChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFitSystemWindows</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>(int arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocus</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFocusFromTouch</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestRectangleOnScreen</span>(Rect arg0, boolean arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">resolveSize</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">resolveSizeAndState</span>(int arg0, int arg1, int arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">restoreHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">saveHierarchyState</span>(SparseArray&lt;Parcelable&gt; arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scrollBy</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scrollTo</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEvent</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAccessibilityDelegate</span>(View.AccessibilityDelegate arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setActivated</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAlpha</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setAnimation</span>(Animation arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackground</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackgroundColor</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackgroundDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBackgroundResource</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setBottom</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setCameraDistance</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setClickable</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setContentDescription</span>(CharSequence arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDrawingCacheBackgroundColor</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDrawingCacheEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDrawingCacheQuality</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setDuplicateParentStateEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFadingEdgeLength</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFilterTouchesWhenObscured</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFitsSystemWindows</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFocusable</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setFocusableInTouchMode</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHapticFeedbackEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHasTransientState</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHorizontalFadingEdgeEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHorizontalScrollBarEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setHovered</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setImportantForAccessibility</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setKeepScreenOn</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayerType</span>(int arg0, Paint arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLayoutParams</span>(ViewGroup.LayoutParams arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLeft</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setLongClickable</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMeasuredDimension</span>(int arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMinimumHeight</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setMinimumWidth</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusDownId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusForwardId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusLeftId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusRightId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setNextFocusUpId</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnClickListener</span>(View.OnClickListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnCreateContextMenuListener</span>(View.OnCreateContextMenuListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnDragListener</span>(View.OnDragListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnFocusChangeListener</span>(View.OnFocusChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnGenericMotionListener</span>(View.OnGenericMotionListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnHoverListener</span>(View.OnHoverListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnKeyListener</span>(View.OnKeyListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnLongClickListener</span>(View.OnLongClickListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnSystemUiVisibilityChangeListener</span>(View.OnSystemUiVisibilityChangeListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOnTouchListener</span>(View.OnTouchListener arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setOverScrollMode</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPadding</span>(int arg0, int arg1, int arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPivotX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPivotY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setPressed</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRight</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRotation</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRotationX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setRotationY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSaveEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSaveFromParentEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScaleX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScaleY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarDefaultDelayBeforeFade</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarFadeDuration</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarSize</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollBarStyle</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollContainer</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollX</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollY</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setScrollbarFadingEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSelected</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSoundEffectsEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setSystemUiVisibility</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTag</span>(int arg0, Object arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTag</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTop</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTouchDelegate</span>(TouchDelegate arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTranslationX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setTranslationY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVerticalFadingEdgeEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVerticalScrollBarEnabled</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVerticalScrollbarPosition</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setVisibility</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setWillNotCacheDrawing</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setWillNotDraw</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setX</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">setY</span>(float arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">showContextMenu</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            ActionMode</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startActionMode</span>(ActionMode.Callback arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startAnimation</span>(Animation arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startDrag</span>(ClipData arg0, View.DragShadowBuilder arg1, Object arg2, int arg3)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">verifyDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">willNotCacheDrawing</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">willNotDraw</span>()</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-java.lang.Object" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-java.lang.Object-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From class
+
+  java.lang.Object
+
+<div id="inherited-methods-java.lang.Object">
+  <div id="inherited-methods-java.lang.Object-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-java.lang.Object-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            Object</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clone</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">finalize</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            Class&lt;?&gt;</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getClass</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            int</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">hashCode</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">notify</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">notifyAll</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            
+            
+            String</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">toString</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>(long arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            final
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">wait</span>(long arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.graphics.drawable.Drawable.Callback" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.graphics.drawable.Drawable.Callback-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.graphics.drawable.Drawable.Callback
+
+<div id="inherited-methods-android.graphics.drawable.Drawable.Callback">
+  <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.graphics.drawable.Drawable.Callback-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateDrawable</span>(Drawable arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">scheduleDrawable</span>(Drawable arg0, Runnable arg1, long arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">unscheduleDrawable</span>(Drawable arg0, Runnable arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.KeyEvent.Callback" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.KeyEvent.Callback-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.KeyEvent.Callback
+
+<div id="inherited-methods-android.view.KeyEvent.Callback">
+  <div id="inherited-methods-android.view.KeyEvent.Callback-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.KeyEvent.Callback-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyDown</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyLongPress</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyMultiple</span>(int arg0, int arg1, KeyEvent arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">onKeyUp</span>(int arg0, KeyEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewManager" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.ViewManager-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.ViewManager
+
+<div id="inherited-methods-android.view.ViewManager">
+  <div id="inherited-methods-android.view.ViewManager-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.ViewManager-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">addView</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">removeView</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">updateViewLayout</span>(View arg0, ViewGroup.LayoutParams arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.ViewParent" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.ViewParent-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.ViewParent
+
+<div id="inherited-methods-android.view.ViewParent">
+  <div id="inherited-methods-android.view.ViewParent-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.ViewParent-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">bringChildToFront</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">childDrawableStateChanged</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">clearChildFocus</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">createContextMenu</span>(ContextMenu arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            View</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusSearch</span>(View arg0, int arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">focusableViewAvailable</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getChildVisibleRect</span>(View arg0, Rect arg1, Point arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParent</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">getParentForAccessibility</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChild</span>(View arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ViewParent</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">invalidateChildInParent</span>(int[] arg0, Rect arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">isLayoutRequested</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">recomputeViewAttributes</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildFocus</span>(View arg0, View arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestChildRectangleOnScreen</span>(View arg0, Rect arg1, boolean arg2)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestDisallowInterceptTouchEvent</span>(boolean arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestFitSystemWindows</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestLayout</span>()</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestSendAccessibilityEvent</span>(View arg0, AccessibilityEvent arg1)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">requestTransparentRegion</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">showContextMenuForChild</span>(View arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            ActionMode</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">startActionModeForChild</span>(View arg0, ActionMode.Callback arg1)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+
+<tr class="api apilevel-" >
+<td colspan="12">
+  <a href="#" onclick="return toggleInherited(this, null)" id="inherited-methods-android.view.accessibility.AccessibilityEventSource" class="jd-expando-trigger closed"
+          ><img id="inherited-methods-android.view.accessibility.AccessibilityEventSource-trigger"
+          src="/assets/images/triangle-closed.png"
+          class="jd-expando-trigger-img" /></a>
+From interface
+
+  android.view.accessibility.AccessibilityEventSource
+
+<div id="inherited-methods-android.view.accessibility.AccessibilityEventSource">
+  <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-android.view.accessibility.AccessibilityEventSource-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEvent</span>(int arg0)</nobr>
+        
+  </td></tr>
+
+
+	 
+    <tr class=" api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            abstract
+            
+            
+            
+            
+            void</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad">sendAccessibilityEventUnchecked</span>(AccessibilityEvent arg0)</nobr>
+        
+  </td></tr>
+
+
+</table>
+  </div>
+</div>
+</td></tr>
+
+
+</table>
+
+
+</div><!-- jd-descr (summary) -->
+
+<!-- Details -->
+
+
+
+
+
+
+
+
+<!-- XML Attributes -->
+
+
+<!-- Enum Values -->
+
+
+<!-- Constants -->
+
+
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Constants</h2>
+
+
+
+
+<A NAME="TAG"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+        static 
+        final 
+        String
+      </span>
+        TAG
+    </h4>
+      <div class="api-level">
+        
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    
+        <div class="jd-tagdata">
+        <span class="jd-tagtitle">Constant Value: </span>
+        <span>
+            
+                "PlusOneDummyView"
+            
+        </span>
+        </div>
+    
+    </div>
+</div>
+
+
+
+
+<!-- Fields -->
+
+
+<!-- Public ctors -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<h2>Public Constructors</h2>
+
+
+
+<A NAME="PlusOneDummyView(android.content.Context, int)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        public 
+         
+         
+         
+         
+        
+      </span>
+      <span class="sympad">PlusOneDummyView</span>
+      <span class="normal">(Context context, int size)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+    </div>
+</div>
+
+
+
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<!-- Protected ctors -->
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methdos -->
+
+
+
+<!-- ========= METHOD DETAIL ======== -->
+
+
+
+<!-- ========= END OF CLASS DATA ========= -->
+<A NAME="navbar_top"></A>
+
+<div id="footer" class="wrap" >
+        
+
+  <div id="copyright">
+    
+  Except as noted, this content is licensed under <a
+  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
+  For details and restrictions, see the <a href="/license.html">
+  Content License</a>.
+  </div>
+  <div id="build_info">
+    
+<script src="/timestamp.js" type="text/javascript"></script>
+<script>document.write(BUILD_TIMESTAMP)</script>
+
+  </div>
+
+
+  <div id="footerlinks">
+    
+  <p>
+    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
+    <a href="/support.html">Support</a>
+  </p>
+  </div>
+
+</div> <!-- end footer -->
+</div> <!-- jd-content -->
+
+</div><!-- end doc-content -->
+
+</div> <!-- end body-content --> 
+
+
+
+
+
+
+</body>
+</html>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusShare.Builder.html b/docs/html/reference/com/google/android/gms/plus/PlusShare.Builder.html
index a251cb9..80da92b 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusShare.Builder.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusShare.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusShare.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -684,7 +691,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -704,7 +711,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -791,7 +798,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#PlusShare.Builder(android.content.Context)">PlusShare.Builder</a></span>(<a href="/reference/android/content/Context.html">Context</a> context)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#PlusShare.Builder(android.content.Context)">PlusShare.Builder</a></span>(Context context)</nobr>
         
         <div class="jd-descrdiv">Create a new Builder for launching a sharing action from the given context.</div>
   
@@ -809,7 +816,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#PlusShare.Builder(android.app.Activity)">PlusShare.Builder</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> launchingActivity)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#PlusShare.Builder(android.app.Activity)">PlusShare.Builder</a></span>(Activity launchingActivity)</nobr>
         
         <div class="jd-descrdiv">Create a new Builder for launching a sharing action from launchingActivity.</div>
   
@@ -827,7 +834,7 @@
             </nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#PlusShare.Builder(android.app.Activity, com.google.android.gms.plus.PlusClient)">PlusShare.Builder</a></span>(<a href="/reference/android/app/Activity.html">Activity</a> launchingActivity, <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#PlusShare.Builder(android.app.Activity, com.google.android.gms.plus.PlusClient)">PlusShare.Builder</a></span>(Activity launchingActivity, <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient)</nobr>
         
         <div class="jd-descrdiv">Create a new Builder for launching a sharing action from launchingActivity.</div>
   
@@ -858,7 +865,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#addCallToAction(java.lang.String, android.net.Uri, java.lang.String)">addCallToAction</a></span>(<a href="/reference/java/lang/String.html">String</a> label, <a href="/reference/android/net/Uri.html">Uri</a> uri, <a href="/reference/java/lang/String.html">String</a> deepLinkId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#addCallToAction(java.lang.String, android.net.Uri, java.lang.String)">addCallToAction</a></span>(String label, Uri uri, String deepLinkId)</nobr>
         
         <div class="jd-descrdiv">Adds a call-to-action button for an interactive post.</div>
   
@@ -876,7 +883,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#addStream(android.net.Uri)">addStream</a></span>(<a href="/reference/android/net/Uri.html">Uri</a> streamUri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#addStream(android.net.Uri)">addStream</a></span>(Uri streamUri)</nobr>
         
         <div class="jd-descrdiv">Add a stream URI to the data that should be shared.</div>
   
@@ -891,7 +898,7 @@
             
             
             
-            <a href="/reference/android/content/Intent.html">Intent</a></nobr>
+            Intent</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#getIntent()">getIntent</a></span>()</nobr>
@@ -912,7 +919,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setContentDeepLinkId(java.lang.String, java.lang.String, java.lang.String, android.net.Uri)">setContentDeepLinkId</a></span>(<a href="/reference/java/lang/String.html">String</a> deepLinkId, <a href="/reference/java/lang/String.html">String</a> title, <a href="/reference/java/lang/String.html">String</a> description, <a href="/reference/android/net/Uri.html">Uri</a> thumbnailUri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setContentDeepLinkId(java.lang.String, java.lang.String, java.lang.String, android.net.Uri)">setContentDeepLinkId</a></span>(String deepLinkId, String title, String description, Uri thumbnailUri)</nobr>
         
         <div class="jd-descrdiv">Include a deep-link ID to a resource to share on Google+.</div>
   
@@ -930,7 +937,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setContentDeepLinkId(java.lang.String)">setContentDeepLinkId</a></span>(<a href="/reference/java/lang/String.html">String</a> deepLinkId)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setContentDeepLinkId(java.lang.String)">setContentDeepLinkId</a></span>(String deepLinkId)</nobr>
         
         <div class="jd-descrdiv">Include a deep-link URI of a resource to share on Google+.</div>
   
@@ -948,7 +955,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setContentUrl(android.net.Uri)">setContentUrl</a></span>(<a href="/reference/android/net/Uri.html">Uri</a> uri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setContentUrl(android.net.Uri)">setContentUrl</a></span>(Uri uri)</nobr>
         
         <div class="jd-descrdiv">Sets a URL to link to from the content on the web.</div>
   
@@ -966,7 +973,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setRecipients(java.util.List<com.google.android.gms.plus.model.people.Person>)">setRecipients</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a>&gt; recipientList)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setRecipients(java.util.List<com.google.android.gms.plus.model.people.Person>)">setRecipients</a></span>(List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a>&gt; recipientList)</nobr>
         
         <div class="jd-descrdiv">Sets a list of people to send the interactive post to.</div>
   
@@ -984,7 +991,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setStream(android.net.Uri)">setStream</a></span>(<a href="/reference/android/net/Uri.html">Uri</a> streamUri)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setStream(android.net.Uri)">setStream</a></span>(Uri streamUri)</nobr>
         
         <div class="jd-descrdiv">Set a stream URI to the data that should be shared.</div>
   
@@ -1002,7 +1009,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setText(java.lang.CharSequence)">setText</a></span>(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> text)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setText(java.lang.CharSequence)">setText</a></span>(CharSequence text)</nobr>
         
         <div class="jd-descrdiv">Set a pre-filled message to be sent as part of the share.</div>
   
@@ -1020,7 +1027,7 @@
             <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setType(java.lang.String)">setType</a></span>(<a href="/reference/java/lang/String.html">String</a> mimeType)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html#setType(java.lang.String)">setType</a></span>(String mimeType)</nobr>
         
         <div class="jd-descrdiv">Set the type of data being shared.</div>
   
@@ -1077,7 +1084,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1096,7 +1103,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1115,7 +1122,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1144,7 +1151,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1208,7 +1215,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1317,7 +1324,7 @@
         
       </span>
       <span class="sympad">PlusShare.Builder</span>
-      <span class="normal">(<a href="/reference/android/content/Context.html">Context</a> context)</span>
+      <span class="normal">(Context context)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1356,7 +1363,7 @@
         
       </span>
       <span class="sympad">PlusShare.Builder</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> launchingActivity)</span>
+      <span class="normal">(Activity launchingActivity)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1395,7 +1402,7 @@
         
       </span>
       <span class="sympad">PlusShare.Builder</span>
-      <span class="normal">(<a href="/reference/android/app/Activity.html">Activity</a> launchingActivity, <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient)</span>
+      <span class="normal">(Activity launchingActivity, <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a> plusClient)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1455,7 +1462,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">addCallToAction</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> label, <a href="/reference/android/net/Uri.html">Uri</a> uri, <a href="/reference/java/lang/String.html">String</a> deepLinkId)</span>
+      <span class="normal">(String label, Uri uri, String deepLinkId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1509,7 +1516,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">addStream</span>
-      <span class="normal">(<a href="/reference/android/net/Uri.html">Uri</a> streamUri)</span>
+      <span class="normal">(Uri streamUri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1555,7 +1562,7 @@
          
          
          
-        <a href="/reference/android/content/Intent.html">Intent</a>
+        Intent
       </span>
       <span class="sympad">getIntent</span>
       <span class="normal">()</span>
@@ -1592,7 +1599,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setContentDeepLinkId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> deepLinkId, <a href="/reference/java/lang/String.html">String</a> title, <a href="/reference/java/lang/String.html">String</a> description, <a href="/reference/android/net/Uri.html">Uri</a> thumbnailUri)</span>
+      <span class="normal">(String deepLinkId, String title, String description, Uri thumbnailUri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1651,7 +1658,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setContentDeepLinkId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> deepLinkId)</span>
+      <span class="normal">(String deepLinkId)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1695,7 +1702,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setContentUrl</span>
-      <span class="normal">(<a href="/reference/android/net/Uri.html">Uri</a> uri)</span>
+      <span class="normal">(Uri uri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1740,7 +1747,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setRecipients</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a>&gt; recipientList)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a>&gt; recipientList)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1759,7 +1766,7 @@
       <table class="jd-tagtable">
         <tr>
           <th>recipientList</td>
-          <td>A list of recipients.  See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, int)">loadPeople(PlusClient.OnPeopleLoadedListener, int)</a></code> and
+          <td>A list of recipients.  See <code><a href="/reference/com/google/android/gms/plus/PlusClient.html#loadPeople(com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener, java.lang.String...)">loadPeople(PlusClient.OnPeopleLoadedListener, String...)</a></code> and
          <code><a href="/reference/com/google/android/gms/plus/PlusShare.html#createPerson(java.lang.String, java.lang.String)">createPerson(String, String)</a></code>.</td>
         </tr>
       </table>
@@ -1787,7 +1794,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setStream</span>
-      <span class="normal">(<a href="/reference/android/net/Uri.html">Uri</a> streamUri)</span>
+      <span class="normal">(Uri streamUri)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1837,7 +1844,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setText</span>
-      <span class="normal">(<a href="/reference/java/lang/CharSequence.html">CharSequence</a> text)</span>
+      <span class="normal">(CharSequence text)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1885,7 +1892,7 @@
         <a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a>
       </span>
       <span class="sympad">setType</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> mimeType)</span>
+      <span class="normal">(String mimeType)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/plus/PlusShare.html b/docs/html/reference/com/google/android/gms/plus/PlusShare.html
index 9eb917d..983c4ee 100644
--- a/docs/html/reference/com/google/android/gms/plus/PlusShare.html
+++ b/docs/html/reference/com/google/android/gms/plus/PlusShare.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PlusShare | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -659,6 +666,9 @@
   
 
 
+  &#124; <a href="#promethods">Protected Methods</a>
+  
+
 
   &#124; <a href="#inhmethods">Inherited Methods</a>
 
@@ -687,7 +697,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -707,7 +717,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -799,14 +809,14 @@
 
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#EXTRA_CALL_TO_ACTION">EXTRA_CALL_TO_ACTION</a></td>
         <td class="jd-descrcol" width="100%">Used as a bundle extra field to describe a call-to-action button for a post on Google+.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#EXTRA_CONTENT_DEEP_LINK_ID">EXTRA_CONTENT_DEEP_LINK_ID</a></td>
         <td class="jd-descrcol" width="100%">Used as a string extra field in <code><a href="/reference/android/content/Intent.html#ACTION_SEND">ACTION_SEND</a></code> intents to
  specify a resource to be shared on Google+.</td>
@@ -814,7 +824,7 @@
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#EXTRA_CONTENT_DEEP_LINK_METADATA">EXTRA_CONTENT_DEEP_LINK_METADATA</a></td>
         <td class="jd-descrcol" width="100%">Used as a bundle extra field in <code><a href="/reference/android/content/Intent.html#ACTION_SEND">ACTION_SEND</a></code> intents to
  describe a resource to be shared on Google+.</td>
@@ -822,70 +832,70 @@
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#EXTRA_CONTENT_URL">EXTRA_CONTENT_URL</a></td>
         <td class="jd-descrcol" width="100%">This is a URL for the content of the post.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#EXTRA_IS_INTERACTIVE_POST">EXTRA_IS_INTERACTIVE_POST</a></td>
         <td class="jd-descrcol" width="100%">Extra indicating that this is an interactive post.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#EXTRA_SENDER_ID">EXTRA_SENDER_ID</a></td>
         <td class="jd-descrcol" width="100%">The ID of the sender on Google+.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#KEY_CALL_TO_ACTION_DEEP_LINK_ID">KEY_CALL_TO_ACTION_DEEP_LINK_ID</a></td>
         <td class="jd-descrcol" width="100%">Bundle key used for the <code><a href="/reference/java/lang/String.html">String</a></code> deep-link ID of the call-to-action button.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#KEY_CALL_TO_ACTION_LABEL">KEY_CALL_TO_ACTION_LABEL</a></td>
         <td class="jd-descrcol" width="100%">Bundle key used for the <code><a href="/reference/java/lang/String.html">String</a></code> label placeholder text of the call-to-action button.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#KEY_CALL_TO_ACTION_URL">KEY_CALL_TO_ACTION_URL</a></td>
         <td class="jd-descrcol" width="100%">Bundle key used for the <code><a href="/reference/java/lang/String.html">String</a></code> URL of the call-to-action button.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#KEY_CONTENT_DEEP_LINK_METADATA_DESCRIPTION">KEY_CONTENT_DEEP_LINK_METADATA_DESCRIPTION</a></td>
         <td class="jd-descrcol" width="100%">Bundle key used for the <code><a href="/reference/java/lang/String.html">String</a></code> description of the resource shared on Google+.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#KEY_CONTENT_DEEP_LINK_METADATA_THUMBNAIL_URL">KEY_CONTENT_DEEP_LINK_METADATA_THUMBNAIL_URL</a></td>
         <td class="jd-descrcol" width="100%">Bundle key used for the <code><a href="/reference/java/lang/String.html">String</a></code> thumbnail URL of the resource shared on Google+.</td>
     </tr>
     
     
     <tr class=" api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#KEY_CONTENT_DEEP_LINK_METADATA_TITLE">KEY_CONTENT_DEEP_LINK_METADATA_TITLE</a></td>
         <td class="jd-descrcol" width="100%">Bundle key used for the <code><a href="/reference/java/lang/String.html">String</a></code> title of the resource shared on Google+.</td>
     </tr>
     
     
     <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><a href="/reference/java/lang/String.html">String</a></td>
+        <td class="jd-typecol">String</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html#PARAM_CONTENT_DEEP_LINK_ID">PARAM_CONTENT_DEEP_LINK_ID</a></td>
         <td class="jd-descrcol" width="100%">The query parameter containing the deep-link ID.</td>
     </tr>
@@ -954,7 +964,7 @@
             <a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.html#createPerson(java.lang.String, java.lang.String)">createPerson</a></span>(<a href="/reference/java/lang/String.html">String</a> id, <a href="/reference/java/lang/String.html">String</a> displayName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.html#createPerson(java.lang.String, java.lang.String)">createPerson</a></span>(String id, String displayName)</nobr>
         
         <div class="jd-descrdiv">Creates a person to use as a recipient with the given ID and display name.</div>
   
@@ -969,10 +979,10 @@
             
             static
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.html#getDeepLinkId(android.content.Intent)">getDeepLinkId</a></span>(<a href="/reference/android/content/Intent.html">Intent</a> intent)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.html#getDeepLinkId(android.content.Intent)">getDeepLinkId</a></span>(Intent intent)</nobr>
         
         <div class="jd-descrdiv">Get the incoming deep link.</div>
   
@@ -985,6 +995,33 @@
 
 
 
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+
+
+
+	 
+    <tr class="alt-color api apilevel-" >
+        <td class="jd-typecol"><nobr>
+            
+            
+            
+            static
+            
+            boolean</nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/PlusShare.html#isDeepLinkIdValid(java.lang.String)">isDeepLinkIdValid</a></span>(String deepLinkId)</nobr>
+        
+        <div class="jd-descrdiv">Determine if the deep-link ID is valid.</div>
+  
+  </td></tr>
+
+
+
+</table>
+
+
 
 
 
@@ -1002,7 +1039,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1021,7 +1058,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1040,7 +1077,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1069,7 +1106,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1133,7 +1170,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1232,7 +1269,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_CALL_TO_ACTION
     </h4>
@@ -1270,7 +1307,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_CONTENT_DEEP_LINK_ID
     </h4>
@@ -1309,7 +1346,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_CONTENT_DEEP_LINK_METADATA
     </h4>
@@ -1349,7 +1386,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_CONTENT_URL
     </h4>
@@ -1387,7 +1424,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_IS_INTERACTIVE_POST
     </h4>
@@ -1425,7 +1462,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         EXTRA_SENDER_ID
     </h4>
@@ -1467,7 +1504,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_CALL_TO_ACTION_DEEP_LINK_ID
     </h4>
@@ -1506,7 +1543,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_CALL_TO_ACTION_LABEL
     </h4>
@@ -1545,7 +1582,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_CALL_TO_ACTION_URL
     </h4>
@@ -1584,7 +1621,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_CONTENT_DEEP_LINK_METADATA_DESCRIPTION
     </h4>
@@ -1623,7 +1660,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_CONTENT_DEEP_LINK_METADATA_THUMBNAIL_URL
     </h4>
@@ -1662,7 +1699,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         KEY_CONTENT_DEEP_LINK_METADATA_TITLE
     </h4>
@@ -1701,7 +1738,7 @@
         public 
         static 
         final 
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
         PARAM_CONTENT_DEEP_LINK_ID
     </h4>
@@ -1803,7 +1840,7 @@
         <a href="/reference/com/google/android/gms/plus/model/people/Person.html">Person</a>
       </span>
       <span class="sympad">createPerson</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> id, <a href="/reference/java/lang/String.html">String</a> displayName)</span>
+      <span class="normal">(String id, String displayName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1844,10 +1881,10 @@
          
          
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDeepLinkId</span>
-      <span class="normal">(<a href="/reference/android/content/Intent.html">Intent</a> intent)</span>
+      <span class="normal">(Intent intent)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1882,6 +1919,45 @@
 
 <!-- ========= METHOD DETAIL ======== -->
 
+<h2>Protected Methods</h2>
+
+
+
+<A NAME="isDeepLinkIdValid(java.lang.String)"></A>
+
+<div class="jd-details api apilevel-"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        protected 
+        static 
+         
+         
+         
+        boolean
+      </span>
+      <span class="sympad">isDeepLinkIdValid</span>
+      <span class="normal">(String deepLinkId)</span>
+    </h4>
+      <div class="api-level">
+        <div></div>
+        
+  
+
+      </div>
+    <div class="jd-details-descr">
+      
+  <div class="jd-tagdata jd-tagdescr"><p>Determine if the deep-link ID is valid.</p></div>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li>True if the provided deep-link ID is valid.
+</li></ul>
+  </div>
+
+    </div>
+</div>
+
+
+
 
 
 <!-- ========= END OF CLASS DATA ========= -->
diff --git a/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html b/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html
index 2a8d1a2..bafdfe9 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ItemScope.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -855,7 +862,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAdditionalName(java.util.List<java.lang.String>)">setAdditionalName</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; additionalName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAdditionalName(java.util.List<java.lang.String>)">setAdditionalName</a></span>(List&lt;String&gt; additionalName)</nobr>
         
         <div class="jd-descrdiv">An additional name for a Person, can be used for a middle name.</div>
   
@@ -891,7 +898,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAddressCountry(java.lang.String)">setAddressCountry</a></span>(<a href="/reference/java/lang/String.html">String</a> addressCountry)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAddressCountry(java.lang.String)">setAddressCountry</a></span>(String addressCountry)</nobr>
         
         <div class="jd-descrdiv">Address country.</div>
   
@@ -909,7 +916,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAddressLocality(java.lang.String)">setAddressLocality</a></span>(<a href="/reference/java/lang/String.html">String</a> addressLocality)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAddressLocality(java.lang.String)">setAddressLocality</a></span>(String addressLocality)</nobr>
         
         <div class="jd-descrdiv">Address locality.</div>
   
@@ -927,7 +934,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAddressRegion(java.lang.String)">setAddressRegion</a></span>(<a href="/reference/java/lang/String.html">String</a> addressRegion)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAddressRegion(java.lang.String)">setAddressRegion</a></span>(String addressRegion)</nobr>
         
         <div class="jd-descrdiv">Address region.</div>
   
@@ -945,7 +952,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAssociated_media(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setAssociated_media</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; associated_media)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAssociated_media(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setAssociated_media</a></span>(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; associated_media)</nobr>
         
         <div class="jd-descrdiv">The encoding.</div>
   
@@ -981,7 +988,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAttendees(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setAttendees</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; attendees)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAttendees(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setAttendees</a></span>(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; attendees)</nobr>
         
         <div class="jd-descrdiv">A person attending the event.</div>
   
@@ -1017,7 +1024,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAuthor(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setAuthor</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; author)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setAuthor(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setAuthor</a></span>(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; author)</nobr>
         
         <div class="jd-descrdiv">The person or persons who created this result.</div>
   
@@ -1035,7 +1042,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setBestRating(java.lang.String)">setBestRating</a></span>(<a href="/reference/java/lang/String.html">String</a> bestRating)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setBestRating(java.lang.String)">setBestRating</a></span>(String bestRating)</nobr>
         
         <div class="jd-descrdiv">Best possible rating value that a result might obtain.</div>
   
@@ -1053,7 +1060,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setBirthDate(java.lang.String)">setBirthDate</a></span>(<a href="/reference/java/lang/String.html">String</a> birthDate)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setBirthDate(java.lang.String)">setBirthDate</a></span>(String birthDate)</nobr>
         
         <div class="jd-descrdiv">Date of birth.</div>
   
@@ -1089,7 +1096,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setCaption(java.lang.String)">setCaption</a></span>(<a href="/reference/java/lang/String.html">String</a> caption)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setCaption(java.lang.String)">setCaption</a></span>(String caption)</nobr>
         
         <div class="jd-descrdiv">The caption for this object.</div>
   
@@ -1107,7 +1114,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setContentSize(java.lang.String)">setContentSize</a></span>(<a href="/reference/java/lang/String.html">String</a> contentSize)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setContentSize(java.lang.String)">setContentSize</a></span>(String contentSize)</nobr>
         
         <div class="jd-descrdiv">File size in (mega/kilo) bytes.</div>
   
@@ -1125,7 +1132,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setContentUrl(java.lang.String)">setContentUrl</a></span>(<a href="/reference/java/lang/String.html">String</a> contentUrl)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setContentUrl(java.lang.String)">setContentUrl</a></span>(String contentUrl)</nobr>
         
         <div class="jd-descrdiv">Actual bytes of the media object, for example the image file or video file.</div>
   
@@ -1143,7 +1150,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setContributor(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setContributor</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; contributor)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setContributor(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setContributor</a></span>(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; contributor)</nobr>
         
         <div class="jd-descrdiv">A list of contributors to this result.</div>
   
@@ -1161,7 +1168,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDateCreated(java.lang.String)">setDateCreated</a></span>(<a href="/reference/java/lang/String.html">String</a> dateCreated)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDateCreated(java.lang.String)">setDateCreated</a></span>(String dateCreated)</nobr>
         
         <div class="jd-descrdiv">The date the result was created such as the date that a review was first created.</div>
   
@@ -1179,7 +1186,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDateModified(java.lang.String)">setDateModified</a></span>(<a href="/reference/java/lang/String.html">String</a> dateModified)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDateModified(java.lang.String)">setDateModified</a></span>(String dateModified)</nobr>
         
         <div class="jd-descrdiv">The date the result was last modified such as the date that a review was last edited.</div>
   
@@ -1197,7 +1204,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDatePublished(java.lang.String)">setDatePublished</a></span>(<a href="/reference/java/lang/String.html">String</a> datePublished)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDatePublished(java.lang.String)">setDatePublished</a></span>(String datePublished)</nobr>
         
         <div class="jd-descrdiv">The initial date that the result was published.</div>
   
@@ -1215,7 +1222,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDescription(java.lang.String)">setDescription</a></span>(<a href="/reference/java/lang/String.html">String</a> description)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDescription(java.lang.String)">setDescription</a></span>(String description)</nobr>
         
         <div class="jd-descrdiv">The string that describes the content of the result.</div>
   
@@ -1233,7 +1240,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDuration(java.lang.String)">setDuration</a></span>(<a href="/reference/java/lang/String.html">String</a> duration)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setDuration(java.lang.String)">setDuration</a></span>(String duration)</nobr>
         
         <div class="jd-descrdiv">The duration of the item (movie, audio recording, event, etc.) in ISO 8601 date format.</div>
   
@@ -1251,7 +1258,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setEmbedUrl(java.lang.String)">setEmbedUrl</a></span>(<a href="/reference/java/lang/String.html">String</a> embedUrl)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setEmbedUrl(java.lang.String)">setEmbedUrl</a></span>(String embedUrl)</nobr>
         
         <div class="jd-descrdiv">A URL pointing to a player for a specific video.</div>
   
@@ -1269,7 +1276,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setEndDate(java.lang.String)">setEndDate</a></span>(<a href="/reference/java/lang/String.html">String</a> endDate)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setEndDate(java.lang.String)">setEndDate</a></span>(String endDate)</nobr>
         
         <div class="jd-descrdiv">The end date and time of the event (in ISO 8601 date format).</div>
   
@@ -1287,7 +1294,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setFamilyName(java.lang.String)">setFamilyName</a></span>(<a href="/reference/java/lang/String.html">String</a> familyName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setFamilyName(java.lang.String)">setFamilyName</a></span>(String familyName)</nobr>
         
         <div class="jd-descrdiv">Family name.</div>
   
@@ -1305,7 +1312,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setGender(java.lang.String)">setGender</a></span>(<a href="/reference/java/lang/String.html">String</a> gender)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setGender(java.lang.String)">setGender</a></span>(String gender)</nobr>
         
         <div class="jd-descrdiv">Gender of the person.</div>
   
@@ -1341,7 +1348,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setGivenName(java.lang.String)">setGivenName</a></span>(<a href="/reference/java/lang/String.html">String</a> givenName)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setGivenName(java.lang.String)">setGivenName</a></span>(String givenName)</nobr>
         
         <div class="jd-descrdiv">Given name.</div>
   
@@ -1359,7 +1366,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setHeight(java.lang.String)">setHeight</a></span>(<a href="/reference/java/lang/String.html">String</a> height)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setHeight(java.lang.String)">setHeight</a></span>(String height)</nobr>
         
         <div class="jd-descrdiv">The height of the media object.</div>
   
@@ -1377,7 +1384,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setId(java.lang.String)">setId</a></span>(<a href="/reference/java/lang/String.html">String</a> id)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setId(java.lang.String)">setId</a></span>(String id)</nobr>
         
         <div class="jd-descrdiv">An identifier for the target.</div>
   
@@ -1395,7 +1402,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setImage(java.lang.String)">setImage</a></span>(<a href="/reference/java/lang/String.html">String</a> image)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setImage(java.lang.String)">setImage</a></span>(String image)</nobr>
         
         <div class="jd-descrdiv">A URL to the image that represents this result.</div>
   
@@ -1485,7 +1492,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setName(java.lang.String)">setName</a></span>(<a href="/reference/java/lang/String.html">String</a> name)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setName(java.lang.String)">setName</a></span>(String name)</nobr>
         
         <div class="jd-descrdiv">The name of the result.</div>
   
@@ -1521,7 +1528,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPerformers(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setPerformers</a></span>(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; performers)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPerformers(java.util.List<com.google.android.gms.plus.model.moments.ItemScope>)">setPerformers</a></span>(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; performers)</nobr>
         
         <div class="jd-descrdiv">The main performer or performers of the event-for example, a presenter, musician, or
  actor.</div>
@@ -1540,7 +1547,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPlayerType(java.lang.String)">setPlayerType</a></span>(<a href="/reference/java/lang/String.html">String</a> playerType)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPlayerType(java.lang.String)">setPlayerType</a></span>(String playerType)</nobr>
         
         <div class="jd-descrdiv">Player type that is required.</div>
   
@@ -1558,7 +1565,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPostOfficeBoxNumber(java.lang.String)">setPostOfficeBoxNumber</a></span>(<a href="/reference/java/lang/String.html">String</a> postOfficeBoxNumber)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPostOfficeBoxNumber(java.lang.String)">setPostOfficeBoxNumber</a></span>(String postOfficeBoxNumber)</nobr>
         
         <div class="jd-descrdiv">Post office box number.</div>
   
@@ -1576,7 +1583,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPostalCode(java.lang.String)">setPostalCode</a></span>(<a href="/reference/java/lang/String.html">String</a> postalCode)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setPostalCode(java.lang.String)">setPostalCode</a></span>(String postalCode)</nobr>
         
         <div class="jd-descrdiv">Postal code.</div>
   
@@ -1594,7 +1601,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setRatingValue(java.lang.String)">setRatingValue</a></span>(<a href="/reference/java/lang/String.html">String</a> ratingValue)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setRatingValue(java.lang.String)">setRatingValue</a></span>(String ratingValue)</nobr>
         
         <div class="jd-descrdiv">Rating value.</div>
   
@@ -1630,7 +1637,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setStartDate(java.lang.String)">setStartDate</a></span>(<a href="/reference/java/lang/String.html">String</a> startDate)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setStartDate(java.lang.String)">setStartDate</a></span>(String startDate)</nobr>
         
         <div class="jd-descrdiv">The start date and time of the event (in ISO 8601 date format).</div>
   
@@ -1648,7 +1655,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setStreetAddress(java.lang.String)">setStreetAddress</a></span>(<a href="/reference/java/lang/String.html">String</a> streetAddress)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setStreetAddress(java.lang.String)">setStreetAddress</a></span>(String streetAddress)</nobr>
         
         <div class="jd-descrdiv">Street address.</div>
   
@@ -1666,7 +1673,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setText(java.lang.String)">setText</a></span>(<a href="/reference/java/lang/String.html">String</a> text)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setText(java.lang.String)">setText</a></span>(String text)</nobr>
         
         <div class="jd-descrdiv">The text that is the result of the app activity.</div>
   
@@ -1702,7 +1709,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setThumbnailUrl(java.lang.String)">setThumbnailUrl</a></span>(<a href="/reference/java/lang/String.html">String</a> thumbnailUrl)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setThumbnailUrl(java.lang.String)">setThumbnailUrl</a></span>(String thumbnailUrl)</nobr>
         
         <div class="jd-descrdiv">A URL to a thumbnail image that represents this result.</div>
   
@@ -1720,7 +1727,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setTickerSymbol(java.lang.String)">setTickerSymbol</a></span>(<a href="/reference/java/lang/String.html">String</a> tickerSymbol)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setTickerSymbol(java.lang.String)">setTickerSymbol</a></span>(String tickerSymbol)</nobr>
         
         <div class="jd-descrdiv">The exchange traded instrument associated with a Corporation object.</div>
   
@@ -1738,7 +1745,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setType(java.lang.String)">setType</a></span>(<a href="/reference/java/lang/String.html">String</a> type)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setType(java.lang.String)">setType</a></span>(String type)</nobr>
         
         <div class="jd-descrdiv">The schema.org URL that best describes the referenced target and matches the type of
  moment.</div>
@@ -1757,7 +1764,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setUrl(java.lang.String)">setUrl</a></span>(<a href="/reference/java/lang/String.html">String</a> url)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setUrl(java.lang.String)">setUrl</a></span>(String url)</nobr>
         
         <div class="jd-descrdiv">The URL that points to the result object.</div>
   
@@ -1775,7 +1782,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setWidth(java.lang.String)">setWidth</a></span>(<a href="/reference/java/lang/String.html">String</a> width)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setWidth(java.lang.String)">setWidth</a></span>(String width)</nobr>
         
         <div class="jd-descrdiv">The width of the media object.</div>
   
@@ -1793,7 +1800,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setWorstRating(java.lang.String)">setWorstRating</a></span>(<a href="/reference/java/lang/String.html">String</a> worstRating)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html#setWorstRating(java.lang.String)">setWorstRating</a></span>(String worstRating)</nobr>
         
         <div class="jd-descrdiv">Worst possible rating value that a result might obtain.</div>
   
@@ -1823,7 +1830,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -1842,7 +1849,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1861,7 +1868,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1890,7 +1897,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1954,7 +1961,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -2168,7 +2175,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAdditionalName</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt; additionalName)</span>
+      <span class="normal">(List&lt;String&gt; additionalName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2228,7 +2235,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAddressCountry</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> addressCountry)</span>
+      <span class="normal">(String addressCountry)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2258,7 +2265,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAddressLocality</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> addressLocality)</span>
+      <span class="normal">(String addressLocality)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2288,7 +2295,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAddressRegion</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> addressRegion)</span>
+      <span class="normal">(String addressRegion)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2318,7 +2325,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAssociated_media</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; associated_media)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; associated_media)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2378,7 +2385,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAttendees</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; attendees)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; attendees)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2438,7 +2445,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setAuthor</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; author)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; author)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2469,7 +2476,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setBestRating</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> bestRating)</span>
+      <span class="normal">(String bestRating)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2501,7 +2508,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setBirthDate</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> birthDate)</span>
+      <span class="normal">(String birthDate)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2561,7 +2568,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setCaption</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> caption)</span>
+      <span class="normal">(String caption)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2591,7 +2598,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setContentSize</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> contentSize)</span>
+      <span class="normal">(String contentSize)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2621,7 +2628,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setContentUrl</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> contentUrl)</span>
+      <span class="normal">(String contentUrl)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2651,7 +2658,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setContributor</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; contributor)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; contributor)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2681,7 +2688,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setDateCreated</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> dateCreated)</span>
+      <span class="normal">(String dateCreated)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2711,7 +2718,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setDateModified</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> dateModified)</span>
+      <span class="normal">(String dateModified)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2741,7 +2748,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setDatePublished</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> datePublished)</span>
+      <span class="normal">(String datePublished)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2774,7 +2781,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setDescription</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> description)</span>
+      <span class="normal">(String description)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2804,7 +2811,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setDuration</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> duration)</span>
+      <span class="normal">(String duration)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2834,7 +2841,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setEmbedUrl</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> embedUrl)</span>
+      <span class="normal">(String embedUrl)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2865,7 +2872,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setEndDate</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> endDate)</span>
+      <span class="normal">(String endDate)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2895,7 +2902,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setFamilyName</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> familyName)</span>
+      <span class="normal">(String familyName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2925,7 +2932,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setGender</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> gender)</span>
+      <span class="normal">(String gender)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -2985,7 +2992,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setGivenName</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> givenName)</span>
+      <span class="normal">(String givenName)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3015,7 +3022,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setHeight</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> height)</span>
+      <span class="normal">(String height)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3045,7 +3052,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> id)</span>
+      <span class="normal">(String id)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3077,7 +3084,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setImage</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> image)</span>
+      <span class="normal">(String image)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3229,7 +3236,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setName</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> name)</span>
+      <span class="normal">(String name)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3290,7 +3297,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setPerformers</span>
-      <span class="normal">(<a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; performers)</span>
+      <span class="normal">(List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt; performers)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3321,7 +3328,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setPlayerType</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> playerType)</span>
+      <span class="normal">(String playerType)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3351,7 +3358,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setPostOfficeBoxNumber</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> postOfficeBoxNumber)</span>
+      <span class="normal">(String postOfficeBoxNumber)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3381,7 +3388,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setPostalCode</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> postalCode)</span>
+      <span class="normal">(String postalCode)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3411,7 +3418,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setRatingValue</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> ratingValue)</span>
+      <span class="normal">(String ratingValue)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3471,7 +3478,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setStartDate</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> startDate)</span>
+      <span class="normal">(String startDate)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3501,7 +3508,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setStreetAddress</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> streetAddress)</span>
+      <span class="normal">(String streetAddress)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3531,7 +3538,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setText</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> text)</span>
+      <span class="normal">(String text)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3592,7 +3599,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setThumbnailUrl</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> thumbnailUrl)</span>
+      <span class="normal">(String thumbnailUrl)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3622,7 +3629,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setTickerSymbol</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> tickerSymbol)</span>
+      <span class="normal">(String tickerSymbol)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3655,7 +3662,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setType</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> type)</span>
+      <span class="normal">(String type)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3686,7 +3693,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setUrl</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> url)</span>
+      <span class="normal">(String url)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3717,7 +3724,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setWidth</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> width)</span>
+      <span class="normal">(String width)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -3747,7 +3754,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html">ItemScope.Builder</a>
       </span>
       <span class="sympad">setWorstRating</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> worstRating)</span>
+      <span class="normal">(String worstRating)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.html b/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.html
index bef3573..33e8491 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/moments/ItemScope.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>ItemScope | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -818,7 +825,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;</nobr>
+            List&lt;String&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAdditionalName()">getAdditionalName</a></span>()</nobr>
@@ -854,7 +861,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAddressCountry()">getAddressCountry</a></span>()</nobr>
@@ -872,7 +879,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAddressLocality()">getAddressLocality</a></span>()</nobr>
@@ -890,7 +897,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAddressRegion()">getAddressRegion</a></span>()</nobr>
@@ -908,7 +915,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAssociated_media()">getAssociated_media</a></span>()</nobr>
@@ -944,7 +951,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAttendees()">getAttendees</a></span>()</nobr>
@@ -980,7 +987,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getAuthor()">getAuthor</a></span>()</nobr>
@@ -998,7 +1005,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getBestRating()">getBestRating</a></span>()</nobr>
@@ -1016,7 +1023,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getBirthDate()">getBirthDate</a></span>()</nobr>
@@ -1052,7 +1059,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getCaption()">getCaption</a></span>()</nobr>
@@ -1070,7 +1077,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getContentSize()">getContentSize</a></span>()</nobr>
@@ -1088,7 +1095,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getContentUrl()">getContentUrl</a></span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getContributor()">getContributor</a></span>()</nobr>
@@ -1124,7 +1131,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getDateCreated()">getDateCreated</a></span>()</nobr>
@@ -1142,7 +1149,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getDateModified()">getDateModified</a></span>()</nobr>
@@ -1160,7 +1167,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getDatePublished()">getDatePublished</a></span>()</nobr>
@@ -1178,7 +1185,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getDescription()">getDescription</a></span>()</nobr>
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getDuration()">getDuration</a></span>()</nobr>
@@ -1214,7 +1221,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getEmbedUrl()">getEmbedUrl</a></span>()</nobr>
@@ -1232,7 +1239,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getEndDate()">getEndDate</a></span>()</nobr>
@@ -1250,7 +1257,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getFamilyName()">getFamilyName</a></span>()</nobr>
@@ -1268,7 +1275,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getGender()">getGender</a></span>()</nobr>
@@ -1304,7 +1311,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getGivenName()">getGivenName</a></span>()</nobr>
@@ -1322,7 +1329,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getHeight()">getHeight</a></span>()</nobr>
@@ -1340,7 +1347,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getId()">getId</a></span>()</nobr>
@@ -1358,7 +1365,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getImage()">getImage</a></span>()</nobr>
@@ -1448,7 +1455,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getName()">getName</a></span>()</nobr>
@@ -1484,7 +1491,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getPerformers()">getPerformers</a></span>()</nobr>
@@ -1502,7 +1509,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getPlayerType()">getPlayerType</a></span>()</nobr>
@@ -1520,7 +1527,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getPostOfficeBoxNumber()">getPostOfficeBoxNumber</a></span>()</nobr>
@@ -1538,7 +1545,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getPostalCode()">getPostalCode</a></span>()</nobr>
@@ -1556,7 +1563,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getRatingValue()">getRatingValue</a></span>()</nobr>
@@ -1592,7 +1599,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getStartDate()">getStartDate</a></span>()</nobr>
@@ -1610,7 +1617,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getStreetAddress()">getStreetAddress</a></span>()</nobr>
@@ -1628,7 +1635,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getText()">getText</a></span>()</nobr>
@@ -1664,7 +1671,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getThumbnailUrl()">getThumbnailUrl</a></span>()</nobr>
@@ -1682,7 +1689,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getTickerSymbol()">getTickerSymbol</a></span>()</nobr>
@@ -1700,7 +1707,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getType()">getType</a></span>()</nobr>
@@ -1718,7 +1725,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getUrl()">getUrl</a></span>()</nobr>
@@ -1736,7 +1743,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getWidth()">getWidth</a></span>()</nobr>
@@ -1754,7 +1761,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html#getWorstRating()">getWorstRating</a></span>()</nobr>
@@ -2894,7 +2901,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/java/lang/String.html">String</a>&gt;
+        List&lt;String&gt;
       </span>
       <span class="sympad">getAdditionalName</span>
       <span class="normal">()</span>
@@ -2954,7 +2961,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAddressCountry</span>
       <span class="normal">()</span>
@@ -2984,7 +2991,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAddressLocality</span>
       <span class="normal">()</span>
@@ -3014,7 +3021,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAddressRegion</span>
       <span class="normal">()</span>
@@ -3044,7 +3051,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
       </span>
       <span class="sympad">getAssociated_media</span>
       <span class="normal">()</span>
@@ -3104,7 +3111,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
       </span>
       <span class="sympad">getAttendees</span>
       <span class="normal">()</span>
@@ -3164,7 +3171,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
       </span>
       <span class="sympad">getAuthor</span>
       <span class="normal">()</span>
@@ -3195,7 +3202,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getBestRating</span>
       <span class="normal">()</span>
@@ -3227,7 +3234,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getBirthDate</span>
       <span class="normal">()</span>
@@ -3287,7 +3294,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getCaption</span>
       <span class="normal">()</span>
@@ -3317,7 +3324,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getContentSize</span>
       <span class="normal">()</span>
@@ -3347,7 +3354,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getContentUrl</span>
       <span class="normal">()</span>
@@ -3377,7 +3384,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
       </span>
       <span class="sympad">getContributor</span>
       <span class="normal">()</span>
@@ -3407,7 +3414,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDateCreated</span>
       <span class="normal">()</span>
@@ -3437,7 +3444,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDateModified</span>
       <span class="normal">()</span>
@@ -3467,7 +3474,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDatePublished</span>
       <span class="normal">()</span>
@@ -3500,7 +3507,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -3530,7 +3537,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDuration</span>
       <span class="normal">()</span>
@@ -3560,7 +3567,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getEmbedUrl</span>
       <span class="normal">()</span>
@@ -3591,7 +3598,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getEndDate</span>
       <span class="normal">()</span>
@@ -3621,7 +3628,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getFamilyName</span>
       <span class="normal">()</span>
@@ -3651,7 +3658,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getGender</span>
       <span class="normal">()</span>
@@ -3711,7 +3718,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getGivenName</span>
       <span class="normal">()</span>
@@ -3741,7 +3748,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getHeight</span>
       <span class="normal">()</span>
@@ -3771,7 +3778,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -3803,7 +3810,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getImage</span>
       <span class="normal">()</span>
@@ -3954,7 +3961,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getName</span>
       <span class="normal">()</span>
@@ -4015,7 +4022,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/moments/ItemScope.html">ItemScope</a>&gt;
       </span>
       <span class="sympad">getPerformers</span>
       <span class="normal">()</span>
@@ -4045,7 +4052,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPlayerType</span>
       <span class="normal">()</span>
@@ -4075,7 +4082,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPostOfficeBoxNumber</span>
       <span class="normal">()</span>
@@ -4105,7 +4112,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getPostalCode</span>
       <span class="normal">()</span>
@@ -4135,7 +4142,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getRatingValue</span>
       <span class="normal">()</span>
@@ -4195,7 +4202,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getStartDate</span>
       <span class="normal">()</span>
@@ -4225,7 +4232,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getStreetAddress</span>
       <span class="normal">()</span>
@@ -4255,7 +4262,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getText</span>
       <span class="normal">()</span>
@@ -4316,7 +4323,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getThumbnailUrl</span>
       <span class="normal">()</span>
@@ -4346,7 +4353,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTickerSymbol</span>
       <span class="normal">()</span>
@@ -4379,7 +4386,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getType</span>
       <span class="normal">()</span>
@@ -4409,7 +4416,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getUrl</span>
       <span class="normal">()</span>
@@ -4440,7 +4447,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getWidth</span>
       <span class="normal">()</span>
@@ -4470,7 +4477,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getWorstRating</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html b/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html
index 48200d8..77188b9 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Moment.Builder | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -681,7 +688,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -701,7 +708,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -837,7 +844,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html">Moment.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html#setId(java.lang.String)">setId</a></span>(<a href="/reference/java/lang/String.html">String</a> id)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html#setId(java.lang.String)">setId</a></span>(String id)</nobr>
         
         <div class="jd-descrdiv">The moment ID.</div>
   
@@ -873,7 +880,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html">Moment.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html#setStartDate(java.lang.String)">setStartDate</a></span>(<a href="/reference/java/lang/String.html">String</a> startDate)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html#setStartDate(java.lang.String)">setStartDate</a></span>(String startDate)</nobr>
         
         <div class="jd-descrdiv">Time stamp of when the action occurred in RFC3339 format.</div>
   
@@ -909,7 +916,7 @@
             <a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html">Moment.Builder</a></nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html#setType(java.lang.String)">setType</a></span>(<a href="/reference/java/lang/String.html">String</a> type)</nobr>
+        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html#setType(java.lang.String)">setType</a></span>(String type)</nobr>
         
         <div class="jd-descrdiv">The Google schema for the type of moment to write.</div>
   
@@ -939,7 +946,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -958,7 +965,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -977,7 +984,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1006,7 +1013,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1070,7 +1077,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1254,7 +1261,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html">Moment.Builder</a>
       </span>
       <span class="sympad">setId</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> id)</span>
+      <span class="normal">(String id)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1315,7 +1322,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html">Moment.Builder</a>
       </span>
       <span class="sympad">setStartDate</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> startDate)</span>
+      <span class="normal">(String startDate)</span>
     </h4>
       <div class="api-level">
         <div></div>
@@ -1375,7 +1382,7 @@
         <a href="/reference/com/google/android/gms/plus/model/moments/Moment.Builder.html">Moment.Builder</a>
       </span>
       <span class="sympad">setType</span>
-      <span class="normal">(<a href="/reference/java/lang/String.html">String</a> type)</span>
+      <span class="normal">(String type)</span>
     </h4>
       <div class="api-level">
         <div></div>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.html b/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.html
index eafe059..ac8d3ff 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/moments/Moment.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Moment | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -800,7 +807,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.html#getId()">getId</a></span>()</nobr>
@@ -836,7 +843,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.html#getStartDate()">getStartDate</a></span>()</nobr>
@@ -872,7 +879,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/moments/Moment.html#getType()">getType</a></span>()</nobr>
@@ -1100,7 +1107,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -1161,7 +1168,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getStartDate</span>
       <span class="normal">()</span>
@@ -1221,7 +1228,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getType</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html b/docs/html/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html
index 717689b..9ca63f3 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/moments/MomentBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>MomentBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/moments/package-summary.html b/docs/html/reference/com/google/android/gms/plus/model/moments/package-summary.html
index bf35ac5..35f1ecc 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/moments/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/moments/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.plus.model.moments | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.AgeRange.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.AgeRange.html
index a44d9da..9d6917e 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.AgeRange.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.AgeRange.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.AgeRange | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Collection.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Collection.html
index 5457931..2df1384 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Collection.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Collection.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Collection | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html
index 052bb10..0e6767a 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Cover.CoverInfo | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html
index 41388a8..4b63bd2 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Cover.CoverPhoto | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -799,7 +806,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html#getUrl()">getUrl</a></span>()</nobr>
@@ -1039,7 +1046,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getUrl</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html
index ed23f8d..cbc618f 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Cover.Layout | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -812,7 +819,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -831,7 +838,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -850,7 +857,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -879,7 +886,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -943,7 +950,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.html
index 82154b0..37f6e95 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Cover.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Cover | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -1129,7 +1136,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The layout of the cover art. Possible values are:
+  <div class="jd-tagdata jd-tagdescr"><p>The layout of the cover art. Possible values include, but are not limited to, the following
+ values:
  - "banner" - One large image banner.
 </p></div>
 
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html
index 5e087c3..b365631 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Emails.Type | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -826,7 +833,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -845,7 +852,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -864,7 +871,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -893,7 +900,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -957,7 +964,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.html
index 5931184..c417d88 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Emails.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Emails | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -818,7 +825,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Emails.html#getValue()">getValue</a></span>()</nobr>
@@ -1061,7 +1068,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getValue</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Gender.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Gender.html
index d687f6f..bfbdb00 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Gender.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Gender.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Gender | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -826,7 +833,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -845,7 +852,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -864,7 +871,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -893,7 +900,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -957,7 +964,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Image.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Image.html
index dc62c46..5a0d367 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Image.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Image.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Image | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -781,7 +788,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Image.html#getUrl()">getUrl</a></span>()</nobr>
@@ -937,7 +944,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getUrl</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Name.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Name.html
index 1e75a78..7bb7657 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Name.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Name.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Name | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -781,7 +788,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Name.html#getFamilyName()">getFamilyName</a></span>()</nobr>
@@ -799,7 +806,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Name.html#getFormatted()">getFormatted</a></span>()</nobr>
@@ -817,7 +824,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Name.html#getGivenName()">getGivenName</a></span>()</nobr>
@@ -835,7 +842,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Name.html#getHonorificPrefix()">getHonorificPrefix</a></span>()</nobr>
@@ -853,7 +860,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Name.html#getHonorificSuffix()">getHonorificSuffix</a></span>()</nobr>
@@ -871,7 +878,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Name.html#getMiddleName()">getMiddleName</a></span>()</nobr>
@@ -1117,7 +1124,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getFamilyName</span>
       <span class="normal">()</span>
@@ -1147,7 +1154,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getFormatted</span>
       <span class="normal">()</span>
@@ -1177,7 +1184,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getGivenName</span>
       <span class="normal">()</span>
@@ -1207,7 +1214,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getHonorificPrefix</span>
       <span class="normal">()</span>
@@ -1237,7 +1244,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getHonorificSuffix</span>
       <span class="normal">()</span>
@@ -1267,7 +1274,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getMiddleName</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.ObjectType.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.ObjectType.html
index 3bada21..e2ffd60 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.ObjectType.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.ObjectType.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.ObjectType | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -819,7 +826,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -838,7 +845,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -857,7 +864,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -886,7 +893,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -950,7 +957,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.OrderBy.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.OrderBy.html
index 1148580..1970270 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.OrderBy.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.OrderBy.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.OrderBy | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html
index 6ade16b..a560398 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Organizations.Type | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -819,7 +826,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -838,7 +845,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -857,7 +864,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -886,7 +893,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -950,7 +957,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.html
index 6ced251..c96a615 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Organizations.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Organizations | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -800,7 +807,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getDepartment()">getDepartment</a></span>()</nobr>
@@ -818,7 +825,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getDescription()">getDescription</a></span>()</nobr>
@@ -836,12 +843,12 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getEndDate()">getEndDate</a></span>()</nobr>
         
-        <div class="jd-descrdiv">The date the person left this organization.</div>
+        <div class="jd-descrdiv">The date that the person left this organization.</div>
   
   </td></tr>
 
@@ -854,7 +861,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getLocation()">getLocation</a></span>()</nobr>
@@ -872,7 +879,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getName()">getName</a></span>()</nobr>
@@ -890,12 +897,12 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getStartDate()">getStartDate</a></span>()</nobr>
         
-        <div class="jd-descrdiv">The date the person joined this organization.</div>
+        <div class="jd-descrdiv">The date that the person joined this organization.</div>
   
   </td></tr>
 
@@ -908,7 +915,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#getTitle()">getTitle</a></span>()</nobr>
@@ -1111,8 +1118,8 @@
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html#isPrimary()">isPrimary</a></span>()</nobr>
         
-        <div class="jd-descrdiv">If "true", indicates this organization is the person's primary one (typically interpreted as
- current one).</div>
+        <div class="jd-descrdiv">If "true", indicates this organization is the person's primary one, which is typically
+ interpreted as the current one.</div>
   
   </td></tr>
 
@@ -1245,7 +1252,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDepartment</span>
       <span class="normal">()</span>
@@ -1275,7 +1282,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDescription</span>
       <span class="normal">()</span>
@@ -1305,7 +1312,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getEndDate</span>
       <span class="normal">()</span>
@@ -1318,7 +1325,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The date the person left this organization.
+  <div class="jd-tagdata jd-tagdescr"><p>The date that the person left this organization.
 </p></div>
 
     </div>
@@ -1335,7 +1342,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getLocation</span>
       <span class="normal">()</span>
@@ -1365,7 +1372,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getName</span>
       <span class="normal">()</span>
@@ -1395,7 +1402,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getStartDate</span>
       <span class="normal">()</span>
@@ -1408,7 +1415,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The date the person joined this organization.
+  <div class="jd-tagdata jd-tagdescr"><p>The date that the person joined this organization.
 </p></div>
 
     </div>
@@ -1425,7 +1432,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTitle</span>
       <span class="normal">()</span>
@@ -1468,7 +1475,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The type of organization. Possible values are:
+  <div class="jd-tagdata jd-tagdescr"><p>The type of organization. Possible values include, but are not limited to, the following
+ values:
  - "work" - Work.
  - "school" - School.
 </p></div>
@@ -1770,8 +1778,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>If "true", indicates this organization is the person's primary one (typically interpreted as
- current one).
+  <div class="jd-tagdata jd-tagdescr"><p>If "true", indicates this organization is the person's primary one, which is typically
+ interpreted as the current one.
 </p></div>
 
     </div>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html
index 7778434..bfcd8a1 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.PlacesLived | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -777,7 +784,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html#getValue()">getValue</a></span>()</nobr>
@@ -969,7 +976,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getValue</span>
       <span class="normal">()</span>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html
index 9221a553..8707d81 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.RelationshipStatus | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -868,7 +875,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -887,7 +894,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -906,7 +913,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -935,7 +942,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -999,7 +1006,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html
index 70d0499..2a94220 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Urls.Type | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -678,7 +685,7 @@
 
 
   
-    extends <a href="/reference/java/lang/Object.html">Object</a><br/>
+    extends Object<br/>
   
   
   
@@ -698,7 +705,7 @@
 
     <tr>
          	
-        <td colspan="2" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="2" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -770,31 +777,11 @@
     
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#BLOG">BLOG</a></td>
-        <td class="jd-descrcol" width="100%"><em>
-      This constant is deprecated.
-    URL for blog (not returned).
-</em></td>
-    </tr>
-    
-    
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#CONTRIBUTOR">CONTRIBUTOR</a></td>
         <td class="jd-descrcol" width="100%">URL for which this person is a contributor to.</td>
     </tr>
     
     
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#HOME">HOME</a></td>
-        <td class="jd-descrcol" width="100%"><em>
-      This constant is deprecated.
-    URL for home (not returned).
-</em></td>
-    </tr>
-    
-    
     <tr class=" api apilevel-" >
         <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#OTHER">OTHER</a></td>
@@ -811,31 +798,11 @@
     
     <tr class=" api apilevel-" >
         <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#PROFILE">PROFILE</a></td>
-        <td class="jd-descrcol" width="100%"><em>
-      This constant is deprecated.
-    URL for profile (not returned).
-</em></td>
-    </tr>
-    
-    
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol">int</td>
         <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#WEBSITE">WEBSITE</a></td>
         <td class="jd-descrcol" width="100%">URL for this Google+ Page's primary website.</td>
     </tr>
     
     
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol">int</td>
-        <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html#WORK">WORK</a></td>
-        <td class="jd-descrcol" width="100%"><em>
-      This constant is deprecated.
-    URL for work (not returned).
-</em></td>
-    </tr>
-    
-    
 
 </table>
 
@@ -873,7 +840,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -892,7 +859,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -911,7 +878,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -940,7 +907,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1004,7 +971,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1095,49 +1062,6 @@
 
 
 
-<A NAME="BLOG"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        BLOG
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This constant is deprecated.</strong><br/>
-    URL for blog (not returned).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                2
-                (0x00000002)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
 <A NAME="CONTRIBUTOR"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1177,49 +1101,6 @@
 
 
 
-<A NAME="HOME"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        HOME
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This constant is deprecated.</strong><br/>
-    URL for home (not returned).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                0
-                (0x00000000)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
 <A NAME="OTHER"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1298,49 +1179,6 @@
 
 
 
-<A NAME="PROFILE"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        PROFILE
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This constant is deprecated.</strong><br/>
-    URL for profile (not returned).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                3
-                (0x00000003)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
 <A NAME="WEBSITE"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1380,49 +1218,6 @@
 
 
 
-<A NAME="WORK"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-        static 
-        final 
-        int
-      </span>
-        WORK
-    </h4>
-      <div class="api-level">
-        
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This constant is deprecated.</strong><br/>
-    URL for work (not returned).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    
-        <div class="jd-tagdata">
-        <span class="jd-tagtitle">Constant Value: </span>
-        <span>
-            
-                1
-                (0x00000001)
-            
-        </span>
-        </div>
-    
-    </div>
-</div>
-
-
-
 
 <!-- Fields -->
 
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.html
index aed3810..cffb8b6 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.Urls.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person.Urls | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -800,7 +807,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html#getLabel()">getLabel</a></span>()</nobr>
@@ -836,7 +843,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html#getValue()">getValue</a></span>()</nobr>
@@ -875,27 +882,6 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html#hasPrimary()">hasPrimary</a></span>()</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    Returns false (removed).
-</em></div>
-  
-  </td></tr>
-
-
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html#hasType()">hasType</a></span>()</nobr>
         
         <div class="jd-descrdiv">Indicates whether the "type" field is explicitly set to a value.</div>
@@ -904,7 +890,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -921,27 +907,6 @@
   </td></tr>
 
 
-	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html#isPrimary()">isPrimary</a></span>()</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    Returns false (removed).
-</em></div>
-  
-  </td></tr>
-
-
 
 </table>
 
@@ -1070,7 +1035,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getLabel</span>
       <span class="normal">()</span>
@@ -1113,11 +1078,11 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The type of URL. Possible values are:
+  <div class="jd-tagdata jd-tagdescr"><p>The type of URL. Possible values include, but are not limited to, the following values:
  - "otherProfile" - URL for another profile.
- - "contributor" - URL for which this person is a contributor to.
+ - "contributor" - URL to a site for which this person is a contributor.
  - "website" - URL for this Google+ Page's primary website.
- - "other" - Other.
+ - "other" - Other URL.
 </p></div>
 
     </div>
@@ -1134,7 +1099,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getValue</span>
       <span class="normal">()</span>
@@ -1184,40 +1149,6 @@
 </div>
 
 
-<A NAME="hasPrimary()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-        abstract 
-         
-        boolean
-      </span>
-      <span class="sympad">hasPrimary</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    Returns false (removed).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
 <A NAME="hasType()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -1278,40 +1209,6 @@
 </div>
 
 
-<A NAME="isPrimary()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-        abstract 
-         
-        boolean
-      </span>
-      <span class="sympad">isPrimary</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    Returns false (removed).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
 
 
 
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/Person.html b/docs/html/reference/com/google/android/gms/plus/model/people/Person.html
index f00f2d6..872d7ab 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/Person.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/Person.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Person | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -949,7 +956,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getAboutMe()">getAboutMe</a></span>()</nobr>
@@ -985,7 +992,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getBirthday()">getBirthday</a></span>()</nobr>
@@ -1003,7 +1010,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getBraggingRights()">getBraggingRights</a></span>()</nobr>
@@ -1058,7 +1065,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getCurrentLocation()">getCurrentLocation</a></span>()</nobr>
@@ -1076,12 +1083,12 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getDisplayName()">getDisplayName</a></span>()</nobr>
         
-        <div class="jd-descrdiv">The name of this person, suitable for display.</div>
+        <div class="jd-descrdiv">The name of this person, which is suitable for display.</div>
   
   </td></tr>
 
@@ -1094,7 +1101,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Emails.html">Person.Emails</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Emails.html">Person.Emails</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getEmails()">getEmails</a></span>()</nobr>
@@ -1130,7 +1137,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getId()">getId</a></span>()</nobr>
@@ -1166,7 +1173,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getLanguage()">getLanguage</a></span>()</nobr>
@@ -1202,7 +1209,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getNickname()">getNickname</a></span>()</nobr>
@@ -1238,7 +1245,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html">Person.Organizations</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html">Person.Organizations</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getOrganizations()">getOrganizations</a></span>()</nobr>
@@ -1256,7 +1263,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html">Person.PlacesLived</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html">Person.PlacesLived</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getPlacesLived()">getPlacesLived</a></span>()</nobr>
@@ -1310,7 +1317,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getTagline()">getTagline</a></span>()</nobr>
@@ -1328,7 +1335,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getUrl()">getUrl</a></span>()</nobr>
@@ -1346,7 +1353,7 @@
             
             
             
-            <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html">Person.Urls</a>&gt;</nobr>
+            List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html">Person.Urls</a>&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#getUrls()">getUrls</a></span>()</nobr>
@@ -1547,27 +1554,6 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#hasHasApp()">hasHasApp</a></span>()</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    Returns false (removed).
-</em></div>
-  
-  </td></tr>
-
-
-	 
-    <tr class="alt-color api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#hasId()">hasId</a></span>()</nobr>
         
         <div class="jd-descrdiv">Indicates whether the "id" field is explicitly set to a value.</div>
@@ -1576,7 +1562,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1594,7 +1580,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1612,7 +1598,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1630,7 +1616,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1648,7 +1634,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1666,7 +1652,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1684,7 +1670,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1702,7 +1688,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1720,7 +1706,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1738,7 +1724,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1756,7 +1742,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1774,7 +1760,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1792,7 +1778,7 @@
 
 
 	 
-    <tr class=" api apilevel-" >
+    <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1810,7 +1796,7 @@
 
 
 	 
-    <tr class="alt-color api apilevel-" >
+    <tr class=" api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
             
@@ -1828,27 +1814,6 @@
 
 
 	 
-    <tr class=" api apilevel-" >
-        <td class="jd-typecol"><nobr>
-            abstract
-            
-            
-            
-            
-            boolean</nobr>
-        </td>
-        <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad"><a href="/reference/com/google/android/gms/plus/model/people/Person.html#isHasApp()">isHasApp</a></span>()</nobr>
-        
-        <div class="jd-descrdiv"><em>
-      This method is deprecated.
-    Returns false (removed).
-</em></div>
-  
-  </td></tr>
-
-
-	 
     <tr class="alt-color api apilevel-" >
         <td class="jd-typecol"><nobr>
             abstract
@@ -2012,7 +1977,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getAboutMe</span>
       <span class="normal">()</span>
@@ -2072,7 +2037,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getBirthday</span>
       <span class="normal">()</span>
@@ -2102,7 +2067,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getBraggingRights</span>
       <span class="normal">()</span>
@@ -2193,7 +2158,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getCurrentLocation</span>
       <span class="normal">()</span>
@@ -2223,7 +2188,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getDisplayName</span>
       <span class="normal">()</span>
@@ -2236,7 +2201,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The name of this person, suitable for display.
+  <div class="jd-tagdata jd-tagdescr"><p>The name of this person, which is suitable for display.
 </p></div>
 
     </div>
@@ -2253,7 +2218,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Emails.html">Person.Emails</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Emails.html">Person.Emails</a>&gt;
       </span>
       <span class="sympad">getEmails</span>
       <span class="normal">()</span>
@@ -2297,7 +2262,7 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The person's gender. Possible values are:
+  <div class="jd-tagdata jd-tagdescr"><p>The person's gender. Possible values include, but are not limited to, the following values:
  - "male" - Male gender.
  - "female" - Female gender.
  - "other" - Other.
@@ -2317,7 +2282,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getId</span>
       <span class="normal">()</span>
@@ -2377,7 +2342,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getLanguage</span>
       <span class="normal">()</span>
@@ -2437,7 +2402,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getNickname</span>
       <span class="normal">()</span>
@@ -2480,7 +2445,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>Type of person within Google+. Possible values are:
+  <div class="jd-tagdata jd-tagdescr"><p>Type of person within Google+. Possible values include, but are not limited to, the following
+ values:
  - "person" - represents an actual person.
  - "page" - represents a page.
 </p></div>
@@ -2499,7 +2465,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html">Person.Organizations</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Organizations.html">Person.Organizations</a>&gt;
       </span>
       <span class="sympad">getOrganizations</span>
       <span class="normal">()</span>
@@ -2529,7 +2495,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html">Person.PlacesLived</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html">Person.PlacesLived</a>&gt;
       </span>
       <span class="sympad">getPlacesLived</span>
       <span class="normal">()</span>
@@ -2602,7 +2568,8 @@
       </div>
     <div class="jd-details-descr">
       
-  <div class="jd-tagdata jd-tagdescr"><p>The person's relationship status. Possible values are:
+  <div class="jd-tagdata jd-tagdescr"><p>The person's relationship status. Possible values include, but are not limited to, the
+ following values:
  - "single" - Person is single.
  - "in_a_relationship" - Person is in a relationship.
  - "engaged" - Person is engaged.
@@ -2628,7 +2595,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getTagline</span>
       <span class="normal">()</span>
@@ -2658,7 +2625,7 @@
          
         abstract 
          
-        <a href="/reference/java/lang/String.html">String</a>
+        String
       </span>
       <span class="sympad">getUrl</span>
       <span class="normal">()</span>
@@ -2688,7 +2655,7 @@
          
         abstract 
          
-        <a href="/reference/java/util/List.html">List</a>&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html">Person.Urls</a>&gt;
+        List&lt;<a href="/reference/com/google/android/gms/plus/model/people/Person.Urls.html">Person.Urls</a>&gt;
       </span>
       <span class="sympad">getUrls</span>
       <span class="normal">()</span>
@@ -3008,40 +2975,6 @@
 </div>
 
 
-<A NAME="hasHasApp()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-        abstract 
-         
-        boolean
-      </span>
-      <span class="sympad">hasHasApp</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    Returns false (removed).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
 <A NAME="hasId()"></A>
 
 <div class="jd-details api apilevel-"> 
@@ -3492,40 +3425,6 @@
 </div>
 
 
-<A NAME="isHasApp()"></A>
-
-<div class="jd-details api apilevel-"> 
-    <h4 class="jd-details-title">
-      <span class="normal">
-        public 
-         
-         
-        abstract 
-         
-        boolean
-      </span>
-      <span class="sympad">isHasApp</span>
-      <span class="normal">()</span>
-    </h4>
-      <div class="api-level">
-        <div></div>
-        
-  
-
-      </div>
-    <div class="jd-details-descr">
-      <p>
-  <p class="caution"><strong>
-      This method is deprecated.</strong><br/>
-    Returns false (removed).
-
-  </p>
-  <div class="jd-tagdata jd-tagdescr"><p></p></div>
-
-    </div>
-</div>
-
-
 <A NAME="isPlusUser()"></A>
 
 <div class="jd-details api apilevel-"> 
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/PersonBuffer.html b/docs/html/reference/com/google/android/gms/plus/model/people/PersonBuffer.html
index fbb223b..2de0808 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/PersonBuffer.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/PersonBuffer.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>PersonBuffer | Android Developers</title>
@@ -305,6 +307,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -371,6 +374,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -503,24 +507,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -716,7 +723,7 @@
 
     <tr>
          	
-        <td colspan="3" class="jd-inheritance-class-cell"><a href="/reference/java/lang/Object.html">java.lang.Object</a></td>
+        <td colspan="3" class="jd-inheritance-class-cell">java.lang.Object</td>
     </tr>
     
 
@@ -952,7 +959,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><a href="/reference/com/google/android/gms/common/data/DataBuffer.html#iterator()">iterator</a></span>()</nobr>
@@ -975,7 +982,7 @@
           class="jd-expando-trigger-img" /></a>
 From class
 
-  <a href="/reference/java/lang/Object.html">java.lang.Object</a>
+  java.lang.Object
 
 <div id="inherited-methods-java.lang.Object">
   <div id="inherited-methods-java.lang.Object-list"
@@ -994,7 +1001,7 @@
             
             
             
-            <a href="/reference/java/lang/Object.html">Object</a></nobr>
+            Object</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">clone</span>()</nobr>
@@ -1013,7 +1020,7 @@
             boolean</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
-        <span class="sympad">equals</span>(<a href="/reference/java/lang/Object.html">Object</a> arg0)</nobr>
+        <span class="sympad">equals</span>(Object arg0)</nobr>
         
   </td></tr>
 
@@ -1042,7 +1049,7 @@
             final
             
             
-            <a href="/reference/java/lang/Class.html">Class</a>&lt;?&gt;</nobr>
+            Class&lt;?&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">getClass</span>()</nobr>
@@ -1106,7 +1113,7 @@
             
             
             
-            <a href="/reference/java/lang/String.html">String</a></nobr>
+            String</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">toString</span>()</nobr>
@@ -1177,7 +1184,7 @@
           class="jd-expando-trigger-img" /></a>
 From interface
 
-  <a href="/reference/java/lang/Iterable.html">java.lang.Iterable</a>
+  java.lang.Iterable
 
 <div id="inherited-methods-java.lang.Iterable">
   <div id="inherited-methods-java.lang.Iterable-list"
@@ -1196,7 +1203,7 @@
             
             
             
-            <a href="/reference/java/util/Iterator.html">Iterator</a>&lt;T&gt;</nobr>
+            Iterator&lt;T&gt;</nobr>
         </td>
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad">iterator</span>()</nobr>
diff --git a/docs/html/reference/com/google/android/gms/plus/model/people/package-summary.html b/docs/html/reference/com/google/android/gms/plus/model/people/package-summary.html
index f567f02..e296efd 100644
--- a/docs/html/reference/com/google/android/gms/plus/model/people/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/plus/model/people/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.plus.model.people | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/reference/com/google/android/gms/plus/package-summary.html b/docs/html/reference/com/google/android/gms/plus/package-summary.html
index a5f422a..feb29a0 100644
--- a/docs/html/reference/com/google/android/gms/plus/package-summary.html
+++ b/docs/html/reference/com/google/android/gms/plus/package-summary.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>com.google.android.gms.plus | Android Developers</title>
@@ -306,6 +308,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -372,6 +375,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -504,24 +508,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -667,17 +674,10 @@
               <td class="jd-descrcol" width="100%">Listener interface for when a collection of people are loaded.&nbsp;</td>
           </tr>
         <tr class=" api apilevel-" >
-              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html">PlusClient.OnPersonLoadedListener</a></td>
-              <td class="jd-descrcol" width="100%"><em>
-      This interface is deprecated.
-    See <code><a href="/reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html">PlusClient.OnPeopleLoadedListener</a></code>.
-</em>&nbsp;</td>
-          </tr>
-        <tr class="alt-color api apilevel-" >
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.OrderBy.html">PlusClient.OrderBy</a></td>
               <td class="jd-descrcol" width="100%">Constants to declare the order to return people in.&nbsp;</td>
           </tr>
-        <tr class=" api apilevel-" >
+        <tr class="alt-color api apilevel-" >
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a></td>
               <td class="jd-descrcol" width="100%">A listener for +1 button clicks.&nbsp;</td>
           </tr>
@@ -704,11 +704,27 @@
               <td class="jd-descrcol" width="100%">The +1 button to recommend a URL on Google+.&nbsp;</td>
           </tr>
         <tr class=" api apilevel-" >
+              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html">PlusOneButton.DefaultOnPlusOneClickListener</a></td>
+              <td class="jd-descrcol" width="100%">This is an <code><a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a></code> that will proxy clicks to an
+ attached <code><a href="/reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html">PlusOneButton.OnPlusOneClickListener</a></code>, or default to attempt to start
+ the intent using an <code><a href="/reference/android/app/Activity.html">Activity</a></code> context.&nbsp;</td>
+          </tr>
+        <tr class="alt-color api apilevel-" >
+              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html">PlusOneButtonWithPopup</a></td>
+              <td class="jd-descrcol" width="100%">+1 button which shows confirmation messages in a PopupWindow.&nbsp;</td>
+          </tr>
+        <tr class=" api apilevel-" >
+              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusOneDummyView.html">PlusOneDummyView</a></td>
+              <td class="jd-descrcol" width="100%">A class used to statically generate dummy views in the event of an error retrieving
+ a PlusOneButton from the apk
+&nbsp;</td>
+          </tr>
+        <tr class="alt-color api apilevel-" >
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.html">PlusShare</a></td>
               <td class="jd-descrcol" width="100%">Utility class for including resources in posts shared on Google+ through
  an <code><a href="/reference/android/content/Intent.html#ACTION_SEND">ACTION_SEND</a></code> intent.&nbsp;</td>
           </tr>
-        <tr class="alt-color api apilevel-" >
+        <tr class=" api apilevel-" >
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusShare.Builder.html">PlusShare.Builder</a></td>
               <td class="jd-descrcol" width="100%">&nbsp;</td>
           </tr>
diff --git a/docs/html/reference/gms-packages.html b/docs/html/reference/gms-packages.html
index a176595..bafda1c 100644
--- a/docs/html/reference/gms-packages.html
+++ b/docs/html/reference/gms-packages.html
@@ -73,12 +73,14 @@
 
 
 
+
+
 <html>
 <head>
 
 
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width" />
 
 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
 <title>Package Index | Android Developers</title>
@@ -304,6 +306,7 @@
                         </li>
                         <li><a href="/google/index.html">Google Services</a>
                         </li>
+                        
                       </ul>
                     </li>
                     <li class="distribute last">
@@ -370,6 +373,7 @@
                 <li class="google"><a href="/google/index.html"
                   >Google Services</a>
                 </li>
+                
             </ul>
         </div>
         
@@ -502,24 +506,27 @@
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="/google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="/google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="/google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="/google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="/google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="/google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="/google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="/google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="/google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="/google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="/google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="/google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
@@ -649,7 +656,7 @@
     <tr class="alt-color api apilevel-" >
         <td class="jd-linkcol">
   <a href="/reference/com/google/android/gms/auth/package-summary.html">com.google.android.gms.auth</a></td>
-        <td class="jd-descrcol" width="100%"></td>
+        <td class="jd-descrcol" width="100%">Contains classes for authenticating Google accounts.</td>
     </tr>
 
 
@@ -698,7 +705,7 @@
     <tr class=" api apilevel-" >
         <td class="jd-linkcol">
   <a href="/reference/com/google/android/gms/games/multiplayer/package-summary.html">com.google.android.gms.games.multiplayer</a></td>
-        <td class="jd-descrcol" width="100%"></td>
+        <td class="jd-descrcol" width="100%">Contains data classes for multiplayer functionality.</td>
     </tr>
 
 
diff --git a/docs/html/reference/gms_lists.js b/docs/html/reference/gms_lists.js
index 9d6258e..27b16e0 100644
--- a/docs/html/reference/gms_lists.js
+++ b/docs/html/reference/gms_lists.js
@@ -32,170 +32,174 @@
       { id:30, label:"com.google.android.gms.common.GooglePlayServicesUtil", link:"reference/com/google/android/gms/common/GooglePlayServicesUtil.html", type:"class", deprecated:"false" },
       { id:31, label:"com.google.android.gms.common.Scopes", link:"reference/com/google/android/gms/common/Scopes.html", type:"class", deprecated:"false" },
       { id:32, label:"com.google.android.gms.common.SignInButton", link:"reference/com/google/android/gms/common/SignInButton.html", type:"class", deprecated:"false" },
-      { id:33, label:"com.google.android.gms.common.data", link:"reference/com/google/android/gms/common/data/package-summary.html", type:"package", deprecated:"false" },
-      { id:34, label:"com.google.android.gms.common.data.DataBuffer", link:"reference/com/google/android/gms/common/data/DataBuffer.html", type:"class", deprecated:"false" },
-      { id:35, label:"com.google.android.gms.common.data.DataBufferUtils", link:"reference/com/google/android/gms/common/data/DataBufferUtils.html", type:"class", deprecated:"false" },
-      { id:36, label:"com.google.android.gms.common.data.Freezable", link:"reference/com/google/android/gms/common/data/Freezable.html", type:"class", deprecated:"false" },
-      { id:37, label:"com.google.android.gms.common.images", link:"reference/com/google/android/gms/common/images/package-summary.html", type:"package", deprecated:"false" },
-      { id:38, label:"com.google.android.gms.common.images.ImageManager", link:"reference/com/google/android/gms/common/images/ImageManager.html", type:"class", deprecated:"false" },
-      { id:39, label:"com.google.android.gms.common.images.ImageManager.OnImageLoadedListener", link:"reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html", type:"class", deprecated:"false" },
-      { id:40, label:"com.google.android.gms.games", link:"reference/com/google/android/gms/games/package-summary.html", type:"package", deprecated:"false" },
-      { id:41, label:"com.google.android.gms.games.Game", link:"reference/com/google/android/gms/games/Game.html", type:"class", deprecated:"false" },
-      { id:42, label:"com.google.android.gms.games.GameBuffer", link:"reference/com/google/android/gms/games/GameBuffer.html", type:"class", deprecated:"false" },
-      { id:43, label:"com.google.android.gms.games.GameEntity", link:"reference/com/google/android/gms/games/GameEntity.html", type:"class", deprecated:"false" },
-      { id:44, label:"com.google.android.gms.games.GamesActivityResultCodes", link:"reference/com/google/android/gms/games/GamesActivityResultCodes.html", type:"class", deprecated:"false" },
-      { id:45, label:"com.google.android.gms.games.GamesClient", link:"reference/com/google/android/gms/games/GamesClient.html", type:"class", deprecated:"false" },
-      { id:46, label:"com.google.android.gms.games.GamesClient.Builder", link:"reference/com/google/android/gms/games/GamesClient.Builder.html", type:"class", deprecated:"false" },
-      { id:47, label:"com.google.android.gms.games.OnGamesLoadedListener", link:"reference/com/google/android/gms/games/OnGamesLoadedListener.html", type:"class", deprecated:"false" },
-      { id:48, label:"com.google.android.gms.games.OnPlayersLoadedListener", link:"reference/com/google/android/gms/games/OnPlayersLoadedListener.html", type:"class", deprecated:"false" },
-      { id:49, label:"com.google.android.gms.games.OnSignOutCompleteListener", link:"reference/com/google/android/gms/games/OnSignOutCompleteListener.html", type:"class", deprecated:"false" },
-      { id:50, label:"com.google.android.gms.games.PageDirection", link:"reference/com/google/android/gms/games/PageDirection.html", type:"class", deprecated:"false" },
-      { id:51, label:"com.google.android.gms.games.Player", link:"reference/com/google/android/gms/games/Player.html", type:"class", deprecated:"false" },
-      { id:52, label:"com.google.android.gms.games.PlayerBuffer", link:"reference/com/google/android/gms/games/PlayerBuffer.html", type:"class", deprecated:"false" },
-      { id:53, label:"com.google.android.gms.games.PlayerEntity", link:"reference/com/google/android/gms/games/PlayerEntity.html", type:"class", deprecated:"false" },
-      { id:54, label:"com.google.android.gms.games.RealTimeSocket", link:"reference/com/google/android/gms/games/RealTimeSocket.html", type:"class", deprecated:"false" },
-      { id:55, label:"com.google.android.gms.games.achievement", link:"reference/com/google/android/gms/games/achievement/package-summary.html", type:"package", deprecated:"false" },
-      { id:56, label:"com.google.android.gms.games.achievement.Achievement", link:"reference/com/google/android/gms/games/achievement/Achievement.html", type:"class", deprecated:"false" },
-      { id:57, label:"com.google.android.gms.games.achievement.AchievementBuffer", link:"reference/com/google/android/gms/games/achievement/AchievementBuffer.html", type:"class", deprecated:"false" },
-      { id:58, label:"com.google.android.gms.games.achievement.OnAchievementUpdatedListener", link:"reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html", type:"class", deprecated:"false" },
-      { id:59, label:"com.google.android.gms.games.achievement.OnAchievementsLoadedListener", link:"reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html", type:"class", deprecated:"false" },
-      { id:60, label:"com.google.android.gms.games.leaderboard", link:"reference/com/google/android/gms/games/leaderboard/package-summary.html", type:"package", deprecated:"false" },
-      { id:61, label:"com.google.android.gms.games.leaderboard.Leaderboard", link:"reference/com/google/android/gms/games/leaderboard/Leaderboard.html", type:"class", deprecated:"false" },
-      { id:62, label:"com.google.android.gms.games.leaderboard.LeaderboardBuffer", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html", type:"class", deprecated:"false" },
-      { id:63, label:"com.google.android.gms.games.leaderboard.LeaderboardScore", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html", type:"class", deprecated:"false" },
-      { id:64, label:"com.google.android.gms.games.leaderboard.LeaderboardScoreBuffer", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardScoreBuffer.html", type:"class", deprecated:"false" },
-      { id:65, label:"com.google.android.gms.games.leaderboard.LeaderboardVariant", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html", type:"class", deprecated:"false" },
-      { id:66, label:"com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener", link:"reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html", type:"class", deprecated:"false" },
-      { id:67, label:"com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener", link:"reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html", type:"class", deprecated:"false" },
-      { id:68, label:"com.google.android.gms.games.leaderboard.OnScoreSubmittedListener", link:"reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html", type:"class", deprecated:"false" },
-      { id:69, label:"com.google.android.gms.games.leaderboard.SubmitScoreResult", link:"reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html", type:"class", deprecated:"false" },
-      { id:70, label:"com.google.android.gms.games.leaderboard.SubmitScoreResult.Result", link:"reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html", type:"class", deprecated:"false" },
-      { id:71, label:"com.google.android.gms.games.multiplayer", link:"reference/com/google/android/gms/games/multiplayer/package-summary.html", type:"package", deprecated:"false" },
-      { id:72, label:"com.google.android.gms.games.multiplayer.Invitation", link:"reference/com/google/android/gms/games/multiplayer/Invitation.html", type:"class", deprecated:"false" },
-      { id:73, label:"com.google.android.gms.games.multiplayer.InvitationBuffer", link:"reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html", type:"class", deprecated:"false" },
-      { id:74, label:"com.google.android.gms.games.multiplayer.InvitationEntity", link:"reference/com/google/android/gms/games/multiplayer/InvitationEntity.html", type:"class", deprecated:"false" },
-      { id:75, label:"com.google.android.gms.games.multiplayer.OnInvitationReceivedListener", link:"reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html", type:"class", deprecated:"false" },
-      { id:76, label:"com.google.android.gms.games.multiplayer.OnInvitationsLoadedListener", link:"reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html", type:"class", deprecated:"false" },
-      { id:77, label:"com.google.android.gms.games.multiplayer.Participant", link:"reference/com/google/android/gms/games/multiplayer/Participant.html", type:"class", deprecated:"false" },
-      { id:78, label:"com.google.android.gms.games.multiplayer.ParticipantBuffer", link:"reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html", type:"class", deprecated:"false" },
-      { id:79, label:"com.google.android.gms.games.multiplayer.ParticipantEntity", link:"reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html", type:"class", deprecated:"false" },
-      { id:80, label:"com.google.android.gms.games.multiplayer.ParticipantUtils", link:"reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html", type:"class", deprecated:"false" },
-      { id:81, label:"com.google.android.gms.games.multiplayer.Participatable", link:"reference/com/google/android/gms/games/multiplayer/Participatable.html", type:"class", deprecated:"false" },
-      { id:82, label:"com.google.android.gms.games.multiplayer.realtime", link:"reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html", type:"package", deprecated:"false" },
-      { id:83, label:"com.google.android.gms.games.multiplayer.realtime.RealTimeMessage", link:"reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html", type:"class", deprecated:"false" },
-      { id:84, label:"com.google.android.gms.games.multiplayer.realtime.RealTimeMessageReceivedListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html", type:"class", deprecated:"false" },
-      { id:85, label:"com.google.android.gms.games.multiplayer.realtime.RealTimeReliableMessageSentListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html", type:"class", deprecated:"false" },
-      { id:86, label:"com.google.android.gms.games.multiplayer.realtime.Room", link:"reference/com/google/android/gms/games/multiplayer/realtime/Room.html", type:"class", deprecated:"false" },
-      { id:87, label:"com.google.android.gms.games.multiplayer.realtime.RoomConfig", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html", type:"class", deprecated:"false" },
-      { id:88, label:"com.google.android.gms.games.multiplayer.realtime.RoomConfig.Builder", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html", type:"class", deprecated:"false" },
-      { id:89, label:"com.google.android.gms.games.multiplayer.realtime.RoomEntity", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html", type:"class", deprecated:"false" },
-      { id:90, label:"com.google.android.gms.games.multiplayer.realtime.RoomStatusUpdateListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html", type:"class", deprecated:"false" },
-      { id:91, label:"com.google.android.gms.games.multiplayer.realtime.RoomUpdateListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html", type:"class", deprecated:"false" },
-      { id:92, label:"com.google.android.gms.gcm", link:"reference/com/google/android/gms/gcm/package-summary.html", type:"package", deprecated:"false" },
-      { id:93, label:"com.google.android.gms.gcm.GoogleCloudMessaging", link:"reference/com/google/android/gms/gcm/GoogleCloudMessaging.html", type:"class", deprecated:"false" },
-      { id:94, label:"com.google.android.gms.location", link:"reference/com/google/android/gms/location/package-summary.html", type:"package", deprecated:"false" },
-      { id:95, label:"com.google.android.gms.location.ActivityRecognitionClient", link:"reference/com/google/android/gms/location/ActivityRecognitionClient.html", type:"class", deprecated:"false" },
-      { id:96, label:"com.google.android.gms.location.ActivityRecognitionResult", link:"reference/com/google/android/gms/location/ActivityRecognitionResult.html", type:"class", deprecated:"false" },
-      { id:97, label:"com.google.android.gms.location.DetectedActivity", link:"reference/com/google/android/gms/location/DetectedActivity.html", type:"class", deprecated:"false" },
-      { id:98, label:"com.google.android.gms.location.Geofence", link:"reference/com/google/android/gms/location/Geofence.html", type:"class", deprecated:"false" },
-      { id:99, label:"com.google.android.gms.location.Geofence.Builder", link:"reference/com/google/android/gms/location/Geofence.Builder.html", type:"class", deprecated:"false" },
-      { id:100, label:"com.google.android.gms.location.LocationClient", link:"reference/com/google/android/gms/location/LocationClient.html", type:"class", deprecated:"false" },
-      { id:101, label:"com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener", link:"reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html", type:"class", deprecated:"false" },
-      { id:102, label:"com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener", link:"reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html", type:"class", deprecated:"false" },
-      { id:103, label:"com.google.android.gms.location.LocationListener", link:"reference/com/google/android/gms/location/LocationListener.html", type:"class", deprecated:"false" },
-      { id:104, label:"com.google.android.gms.location.LocationRequest", link:"reference/com/google/android/gms/location/LocationRequest.html", type:"class", deprecated:"false" },
-      { id:105, label:"com.google.android.gms.location.LocationStatusCodes", link:"reference/com/google/android/gms/location/LocationStatusCodes.html", type:"class", deprecated:"false" },
-      { id:106, label:"com.google.android.gms.maps", link:"reference/com/google/android/gms/maps/package-summary.html", type:"package", deprecated:"false" },
-      { id:107, label:"com.google.android.gms.maps.CameraUpdate", link:"reference/com/google/android/gms/maps/CameraUpdate.html", type:"class", deprecated:"false" },
-      { id:108, label:"com.google.android.gms.maps.CameraUpdateFactory", link:"reference/com/google/android/gms/maps/CameraUpdateFactory.html", type:"class", deprecated:"false" },
-      { id:109, label:"com.google.android.gms.maps.GoogleMap", link:"reference/com/google/android/gms/maps/GoogleMap.html", type:"class", deprecated:"false" },
-      { id:110, label:"com.google.android.gms.maps.GoogleMap.CancelableCallback", link:"reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html", type:"class", deprecated:"false" },
-      { id:111, label:"com.google.android.gms.maps.GoogleMap.InfoWindowAdapter", link:"reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html", type:"class", deprecated:"false" },
-      { id:112, label:"com.google.android.gms.maps.GoogleMap.OnCameraChangeListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html", type:"class", deprecated:"false" },
-      { id:113, label:"com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html", type:"class", deprecated:"false" },
-      { id:114, label:"com.google.android.gms.maps.GoogleMap.OnMapClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html", type:"class", deprecated:"false" },
-      { id:115, label:"com.google.android.gms.maps.GoogleMap.OnMapLongClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html", type:"class", deprecated:"false" },
-      { id:116, label:"com.google.android.gms.maps.GoogleMap.OnMarkerClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html", type:"class", deprecated:"false" },
-      { id:117, label:"com.google.android.gms.maps.GoogleMap.OnMarkerDragListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html", type:"class", deprecated:"false" },
-      { id:118, label:"com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html", type:"class", deprecated:"false" },
-      { id:119, label:"com.google.android.gms.maps.GoogleMap.OnMyLocationChangeListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html", type:"class", deprecated:"true" },
-      { id:120, label:"com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback", link:"reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html", type:"class", deprecated:"false" },
-      { id:121, label:"com.google.android.gms.maps.GoogleMapOptions", link:"reference/com/google/android/gms/maps/GoogleMapOptions.html", type:"class", deprecated:"false" },
-      { id:122, label:"com.google.android.gms.maps.LocationSource", link:"reference/com/google/android/gms/maps/LocationSource.html", type:"class", deprecated:"false" },
-      { id:123, label:"com.google.android.gms.maps.LocationSource.OnLocationChangedListener", link:"reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html", type:"class", deprecated:"false" },
-      { id:124, label:"com.google.android.gms.maps.MapFragment", link:"reference/com/google/android/gms/maps/MapFragment.html", type:"class", deprecated:"false" },
-      { id:125, label:"com.google.android.gms.maps.MapView", link:"reference/com/google/android/gms/maps/MapView.html", type:"class", deprecated:"false" },
-      { id:126, label:"com.google.android.gms.maps.MapsInitializer", link:"reference/com/google/android/gms/maps/MapsInitializer.html", type:"class", deprecated:"false" },
-      { id:127, label:"com.google.android.gms.maps.Projection", link:"reference/com/google/android/gms/maps/Projection.html", type:"class", deprecated:"false" },
-      { id:128, label:"com.google.android.gms.maps.SupportMapFragment", link:"reference/com/google/android/gms/maps/SupportMapFragment.html", type:"class", deprecated:"false" },
-      { id:129, label:"com.google.android.gms.maps.UiSettings", link:"reference/com/google/android/gms/maps/UiSettings.html", type:"class", deprecated:"false" },
-      { id:130, label:"com.google.android.gms.maps.model", link:"reference/com/google/android/gms/maps/model/package-summary.html", type:"package", deprecated:"false" },
-      { id:131, label:"com.google.android.gms.maps.model.BitmapDescriptor", link:"reference/com/google/android/gms/maps/model/BitmapDescriptor.html", type:"class", deprecated:"false" },
-      { id:132, label:"com.google.android.gms.maps.model.BitmapDescriptorFactory", link:"reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html", type:"class", deprecated:"false" },
-      { id:133, label:"com.google.android.gms.maps.model.CameraPosition", link:"reference/com/google/android/gms/maps/model/CameraPosition.html", type:"class", deprecated:"false" },
-      { id:134, label:"com.google.android.gms.maps.model.CameraPosition.Builder", link:"reference/com/google/android/gms/maps/model/CameraPosition.Builder.html", type:"class", deprecated:"false" },
-      { id:135, label:"com.google.android.gms.maps.model.Circle", link:"reference/com/google/android/gms/maps/model/Circle.html", type:"class", deprecated:"false" },
-      { id:136, label:"com.google.android.gms.maps.model.CircleOptions", link:"reference/com/google/android/gms/maps/model/CircleOptions.html", type:"class", deprecated:"false" },
-      { id:137, label:"com.google.android.gms.maps.model.GroundOverlay", link:"reference/com/google/android/gms/maps/model/GroundOverlay.html", type:"class", deprecated:"false" },
-      { id:138, label:"com.google.android.gms.maps.model.GroundOverlayOptions", link:"reference/com/google/android/gms/maps/model/GroundOverlayOptions.html", type:"class", deprecated:"false" },
-      { id:139, label:"com.google.android.gms.maps.model.LatLng", link:"reference/com/google/android/gms/maps/model/LatLng.html", type:"class", deprecated:"false" },
-      { id:140, label:"com.google.android.gms.maps.model.LatLngBounds", link:"reference/com/google/android/gms/maps/model/LatLngBounds.html", type:"class", deprecated:"false" },
-      { id:141, label:"com.google.android.gms.maps.model.LatLngBounds.Builder", link:"reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html", type:"class", deprecated:"false" },
-      { id:142, label:"com.google.android.gms.maps.model.Marker", link:"reference/com/google/android/gms/maps/model/Marker.html", type:"class", deprecated:"false" },
-      { id:143, label:"com.google.android.gms.maps.model.MarkerOptions", link:"reference/com/google/android/gms/maps/model/MarkerOptions.html", type:"class", deprecated:"false" },
-      { id:144, label:"com.google.android.gms.maps.model.Polygon", link:"reference/com/google/android/gms/maps/model/Polygon.html", type:"class", deprecated:"false" },
-      { id:145, label:"com.google.android.gms.maps.model.PolygonOptions", link:"reference/com/google/android/gms/maps/model/PolygonOptions.html", type:"class", deprecated:"false" },
-      { id:146, label:"com.google.android.gms.maps.model.Polyline", link:"reference/com/google/android/gms/maps/model/Polyline.html", type:"class", deprecated:"false" },
-      { id:147, label:"com.google.android.gms.maps.model.PolylineOptions", link:"reference/com/google/android/gms/maps/model/PolylineOptions.html", type:"class", deprecated:"false" },
-      { id:148, label:"com.google.android.gms.maps.model.RuntimeRemoteException", link:"reference/com/google/android/gms/maps/model/RuntimeRemoteException.html", type:"class", deprecated:"false" },
-      { id:149, label:"com.google.android.gms.maps.model.Tile", link:"reference/com/google/android/gms/maps/model/Tile.html", type:"class", deprecated:"false" },
-      { id:150, label:"com.google.android.gms.maps.model.TileOverlay", link:"reference/com/google/android/gms/maps/model/TileOverlay.html", type:"class", deprecated:"false" },
-      { id:151, label:"com.google.android.gms.maps.model.TileOverlayOptions", link:"reference/com/google/android/gms/maps/model/TileOverlayOptions.html", type:"class", deprecated:"false" },
-      { id:152, label:"com.google.android.gms.maps.model.TileProvider", link:"reference/com/google/android/gms/maps/model/TileProvider.html", type:"class", deprecated:"false" },
-      { id:153, label:"com.google.android.gms.maps.model.UrlTileProvider", link:"reference/com/google/android/gms/maps/model/UrlTileProvider.html", type:"class", deprecated:"false" },
-      { id:154, label:"com.google.android.gms.maps.model.VisibleRegion", link:"reference/com/google/android/gms/maps/model/VisibleRegion.html", type:"class", deprecated:"false" },
-      { id:155, label:"com.google.android.gms.panorama", link:"reference/com/google/android/gms/panorama/package-summary.html", type:"package", deprecated:"false" },
-      { id:156, label:"com.google.android.gms.panorama.PanoramaClient", link:"reference/com/google/android/gms/panorama/PanoramaClient.html", type:"class", deprecated:"false" },
-      { id:157, label:"com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener", link:"reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html", type:"class", deprecated:"false" },
-      { id:158, label:"com.google.android.gms.plus", link:"reference/com/google/android/gms/plus/package-summary.html", type:"package", deprecated:"false" },
-      { id:159, label:"com.google.android.gms.plus.PlusClient", link:"reference/com/google/android/gms/plus/PlusClient.html", type:"class", deprecated:"false" },
-      { id:160, label:"com.google.android.gms.plus.PlusClient.Builder", link:"reference/com/google/android/gms/plus/PlusClient.Builder.html", type:"class", deprecated:"false" },
-      { id:161, label:"com.google.android.gms.plus.PlusClient.OnAccessRevokedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html", type:"class", deprecated:"false" },
-      { id:162, label:"com.google.android.gms.plus.PlusClient.OnMomentsLoadedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html", type:"class", deprecated:"false" },
-      { id:163, label:"com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html", type:"class", deprecated:"false" },
-      { id:164, label:"com.google.android.gms.plus.PlusClient.OnPersonLoadedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnPersonLoadedListener.html", type:"class", deprecated:"true" },
-      { id:165, label:"com.google.android.gms.plus.PlusClient.OrderBy", link:"reference/com/google/android/gms/plus/PlusClient.OrderBy.html", type:"class", deprecated:"false" },
-      { id:166, label:"com.google.android.gms.plus.PlusOneButton", link:"reference/com/google/android/gms/plus/PlusOneButton.html", type:"class", deprecated:"false" },
-      { id:167, label:"com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener", link:"reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html", type:"class", deprecated:"false" },
-      { id:168, label:"com.google.android.gms.plus.PlusShare", link:"reference/com/google/android/gms/plus/PlusShare.html", type:"class", deprecated:"false" },
-      { id:169, label:"com.google.android.gms.plus.PlusShare.Builder", link:"reference/com/google/android/gms/plus/PlusShare.Builder.html", type:"class", deprecated:"false" },
-      { id:170, label:"com.google.android.gms.plus.model.moments", link:"reference/com/google/android/gms/plus/model/moments/package-summary.html", type:"package", deprecated:"false" },
-      { id:171, label:"com.google.android.gms.plus.model.moments.ItemScope", link:"reference/com/google/android/gms/plus/model/moments/ItemScope.html", type:"class", deprecated:"false" },
-      { id:172, label:"com.google.android.gms.plus.model.moments.ItemScope.Builder", link:"reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html", type:"class", deprecated:"false" },
-      { id:173, label:"com.google.android.gms.plus.model.moments.Moment", link:"reference/com/google/android/gms/plus/model/moments/Moment.html", type:"class", deprecated:"false" },
-      { id:174, label:"com.google.android.gms.plus.model.moments.Moment.Builder", link:"reference/com/google/android/gms/plus/model/moments/Moment.Builder.html", type:"class", deprecated:"false" },
-      { id:175, label:"com.google.android.gms.plus.model.moments.MomentBuffer", link:"reference/com/google/android/gms/plus/model/moments/MomentBuffer.html", type:"class", deprecated:"false" },
-      { id:176, label:"com.google.android.gms.plus.model.people", link:"reference/com/google/android/gms/plus/model/people/package-summary.html", type:"package", deprecated:"false" },
-      { id:177, label:"com.google.android.gms.plus.model.people.Person", link:"reference/com/google/android/gms/plus/model/people/Person.html", type:"class", deprecated:"false" },
-      { id:178, label:"com.google.android.gms.plus.model.people.Person.AgeRange", link:"reference/com/google/android/gms/plus/model/people/Person.AgeRange.html", type:"class", deprecated:"false" },
-      { id:179, label:"com.google.android.gms.plus.model.people.Person.Collection", link:"reference/com/google/android/gms/plus/model/people/Person.Collection.html", type:"class", deprecated:"true" },
-      { id:180, label:"com.google.android.gms.plus.model.people.Person.Cover", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.html", type:"class", deprecated:"false" },
-      { id:181, label:"com.google.android.gms.plus.model.people.Person.Cover.CoverInfo", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html", type:"class", deprecated:"false" },
-      { id:182, label:"com.google.android.gms.plus.model.people.Person.Cover.CoverPhoto", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html", type:"class", deprecated:"false" },
-      { id:183, label:"com.google.android.gms.plus.model.people.Person.Cover.Layout", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html", type:"class", deprecated:"false" },
-      { id:184, label:"com.google.android.gms.plus.model.people.Person.Emails", link:"reference/com/google/android/gms/plus/model/people/Person.Emails.html", type:"class", deprecated:"false" },
-      { id:185, label:"com.google.android.gms.plus.model.people.Person.Emails.Type", link:"reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html", type:"class", deprecated:"false" },
-      { id:186, label:"com.google.android.gms.plus.model.people.Person.Gender", link:"reference/com/google/android/gms/plus/model/people/Person.Gender.html", type:"class", deprecated:"false" },
-      { id:187, label:"com.google.android.gms.plus.model.people.Person.Image", link:"reference/com/google/android/gms/plus/model/people/Person.Image.html", type:"class", deprecated:"false" },
-      { id:188, label:"com.google.android.gms.plus.model.people.Person.Name", link:"reference/com/google/android/gms/plus/model/people/Person.Name.html", type:"class", deprecated:"false" },
-      { id:189, label:"com.google.android.gms.plus.model.people.Person.ObjectType", link:"reference/com/google/android/gms/plus/model/people/Person.ObjectType.html", type:"class", deprecated:"false" },
-      { id:190, label:"com.google.android.gms.plus.model.people.Person.OrderBy", link:"reference/com/google/android/gms/plus/model/people/Person.OrderBy.html", type:"class", deprecated:"true" },
-      { id:191, label:"com.google.android.gms.plus.model.people.Person.Organizations", link:"reference/com/google/android/gms/plus/model/people/Person.Organizations.html", type:"class", deprecated:"false" },
-      { id:192, label:"com.google.android.gms.plus.model.people.Person.Organizations.Type", link:"reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html", type:"class", deprecated:"false" },
-      { id:193, label:"com.google.android.gms.plus.model.people.Person.PlacesLived", link:"reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html", type:"class", deprecated:"false" },
-      { id:194, label:"com.google.android.gms.plus.model.people.Person.RelationshipStatus", link:"reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html", type:"class", deprecated:"false" },
-      { id:195, label:"com.google.android.gms.plus.model.people.Person.Urls", link:"reference/com/google/android/gms/plus/model/people/Person.Urls.html", type:"class", deprecated:"false" },
-      { id:196, label:"com.google.android.gms.plus.model.people.Person.Urls.Type", link:"reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html", type:"class", deprecated:"false" },
-      { id:197, label:"com.google.android.gms.plus.model.people.PersonBuffer", link:"reference/com/google/android/gms/plus/model/people/PersonBuffer.html", type:"class", deprecated:"false" }
+      { id:33, label:"com.google.android.gms.common.annotation", link:"reference/com/google/android/gms/common/annotation/package-summary.html", type:"package", deprecated:"false" },
+      { id:34, label:"com.google.android.gms.common.annotation.KeepName", link:"reference/com/google/android/gms/common/annotation/KeepName.html", type:"class", deprecated:"false" },
+      { id:35, label:"com.google.android.gms.common.data", link:"reference/com/google/android/gms/common/data/package-summary.html", type:"package", deprecated:"false" },
+      { id:36, label:"com.google.android.gms.common.data.DataBuffer", link:"reference/com/google/android/gms/common/data/DataBuffer.html", type:"class", deprecated:"false" },
+      { id:37, label:"com.google.android.gms.common.data.DataBufferUtils", link:"reference/com/google/android/gms/common/data/DataBufferUtils.html", type:"class", deprecated:"false" },
+      { id:38, label:"com.google.android.gms.common.data.Freezable", link:"reference/com/google/android/gms/common/data/Freezable.html", type:"class", deprecated:"false" },
+      { id:39, label:"com.google.android.gms.common.images", link:"reference/com/google/android/gms/common/images/package-summary.html", type:"package", deprecated:"false" },
+      { id:40, label:"com.google.android.gms.common.images.ImageManager", link:"reference/com/google/android/gms/common/images/ImageManager.html", type:"class", deprecated:"false" },
+      { id:41, label:"com.google.android.gms.common.images.ImageManager.OnImageLoadedListener", link:"reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html", type:"class", deprecated:"false" },
+      { id:42, label:"com.google.android.gms.games", link:"reference/com/google/android/gms/games/package-summary.html", type:"package", deprecated:"false" },
+      { id:43, label:"com.google.android.gms.games.Game", link:"reference/com/google/android/gms/games/Game.html", type:"class", deprecated:"false" },
+      { id:44, label:"com.google.android.gms.games.GameBuffer", link:"reference/com/google/android/gms/games/GameBuffer.html", type:"class", deprecated:"false" },
+      { id:45, label:"com.google.android.gms.games.GameEntity", link:"reference/com/google/android/gms/games/GameEntity.html", type:"class", deprecated:"false" },
+      { id:46, label:"com.google.android.gms.games.GamesActivityResultCodes", link:"reference/com/google/android/gms/games/GamesActivityResultCodes.html", type:"class", deprecated:"false" },
+      { id:47, label:"com.google.android.gms.games.GamesClient", link:"reference/com/google/android/gms/games/GamesClient.html", type:"class", deprecated:"false" },
+      { id:48, label:"com.google.android.gms.games.GamesClient.Builder", link:"reference/com/google/android/gms/games/GamesClient.Builder.html", type:"class", deprecated:"false" },
+      { id:49, label:"com.google.android.gms.games.OnGamesLoadedListener", link:"reference/com/google/android/gms/games/OnGamesLoadedListener.html", type:"class", deprecated:"false" },
+      { id:50, label:"com.google.android.gms.games.OnPlayersLoadedListener", link:"reference/com/google/android/gms/games/OnPlayersLoadedListener.html", type:"class", deprecated:"false" },
+      { id:51, label:"com.google.android.gms.games.OnSignOutCompleteListener", link:"reference/com/google/android/gms/games/OnSignOutCompleteListener.html", type:"class", deprecated:"false" },
+      { id:52, label:"com.google.android.gms.games.PageDirection", link:"reference/com/google/android/gms/games/PageDirection.html", type:"class", deprecated:"false" },
+      { id:53, label:"com.google.android.gms.games.Player", link:"reference/com/google/android/gms/games/Player.html", type:"class", deprecated:"false" },
+      { id:54, label:"com.google.android.gms.games.PlayerBuffer", link:"reference/com/google/android/gms/games/PlayerBuffer.html", type:"class", deprecated:"false" },
+      { id:55, label:"com.google.android.gms.games.PlayerEntity", link:"reference/com/google/android/gms/games/PlayerEntity.html", type:"class", deprecated:"false" },
+      { id:56, label:"com.google.android.gms.games.RealTimeSocket", link:"reference/com/google/android/gms/games/RealTimeSocket.html", type:"class", deprecated:"false" },
+      { id:57, label:"com.google.android.gms.games.achievement", link:"reference/com/google/android/gms/games/achievement/package-summary.html", type:"package", deprecated:"false" },
+      { id:58, label:"com.google.android.gms.games.achievement.Achievement", link:"reference/com/google/android/gms/games/achievement/Achievement.html", type:"class", deprecated:"false" },
+      { id:59, label:"com.google.android.gms.games.achievement.AchievementBuffer", link:"reference/com/google/android/gms/games/achievement/AchievementBuffer.html", type:"class", deprecated:"false" },
+      { id:60, label:"com.google.android.gms.games.achievement.OnAchievementUpdatedListener", link:"reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html", type:"class", deprecated:"false" },
+      { id:61, label:"com.google.android.gms.games.achievement.OnAchievementsLoadedListener", link:"reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html", type:"class", deprecated:"false" },
+      { id:62, label:"com.google.android.gms.games.leaderboard", link:"reference/com/google/android/gms/games/leaderboard/package-summary.html", type:"package", deprecated:"false" },
+      { id:63, label:"com.google.android.gms.games.leaderboard.Leaderboard", link:"reference/com/google/android/gms/games/leaderboard/Leaderboard.html", type:"class", deprecated:"false" },
+      { id:64, label:"com.google.android.gms.games.leaderboard.LeaderboardBuffer", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardBuffer.html", type:"class", deprecated:"false" },
+      { id:65, label:"com.google.android.gms.games.leaderboard.LeaderboardScore", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardScore.html", type:"class", deprecated:"false" },
+      { id:66, label:"com.google.android.gms.games.leaderboard.LeaderboardScoreBuffer", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardScoreBuffer.html", type:"class", deprecated:"false" },
+      { id:67, label:"com.google.android.gms.games.leaderboard.LeaderboardVariant", link:"reference/com/google/android/gms/games/leaderboard/LeaderboardVariant.html", type:"class", deprecated:"false" },
+      { id:68, label:"com.google.android.gms.games.leaderboard.OnLeaderboardMetadataLoadedListener", link:"reference/com/google/android/gms/games/leaderboard/OnLeaderboardMetadataLoadedListener.html", type:"class", deprecated:"false" },
+      { id:69, label:"com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener", link:"reference/com/google/android/gms/games/leaderboard/OnLeaderboardScoresLoadedListener.html", type:"class", deprecated:"false" },
+      { id:70, label:"com.google.android.gms.games.leaderboard.OnScoreSubmittedListener", link:"reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html", type:"class", deprecated:"false" },
+      { id:71, label:"com.google.android.gms.games.leaderboard.SubmitScoreResult", link:"reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.html", type:"class", deprecated:"false" },
+      { id:72, label:"com.google.android.gms.games.leaderboard.SubmitScoreResult.Result", link:"reference/com/google/android/gms/games/leaderboard/SubmitScoreResult.Result.html", type:"class", deprecated:"false" },
+      { id:73, label:"com.google.android.gms.games.multiplayer", link:"reference/com/google/android/gms/games/multiplayer/package-summary.html", type:"package", deprecated:"false" },
+      { id:74, label:"com.google.android.gms.games.multiplayer.Invitation", link:"reference/com/google/android/gms/games/multiplayer/Invitation.html", type:"class", deprecated:"false" },
+      { id:75, label:"com.google.android.gms.games.multiplayer.InvitationBuffer", link:"reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html", type:"class", deprecated:"false" },
+      { id:76, label:"com.google.android.gms.games.multiplayer.InvitationEntity", link:"reference/com/google/android/gms/games/multiplayer/InvitationEntity.html", type:"class", deprecated:"false" },
+      { id:77, label:"com.google.android.gms.games.multiplayer.OnInvitationReceivedListener", link:"reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html", type:"class", deprecated:"false" },
+      { id:78, label:"com.google.android.gms.games.multiplayer.OnInvitationsLoadedListener", link:"reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html", type:"class", deprecated:"false" },
+      { id:79, label:"com.google.android.gms.games.multiplayer.Participant", link:"reference/com/google/android/gms/games/multiplayer/Participant.html", type:"class", deprecated:"false" },
+      { id:80, label:"com.google.android.gms.games.multiplayer.ParticipantBuffer", link:"reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html", type:"class", deprecated:"false" },
+      { id:81, label:"com.google.android.gms.games.multiplayer.ParticipantEntity", link:"reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html", type:"class", deprecated:"false" },
+      { id:82, label:"com.google.android.gms.games.multiplayer.ParticipantUtils", link:"reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html", type:"class", deprecated:"false" },
+      { id:83, label:"com.google.android.gms.games.multiplayer.Participatable", link:"reference/com/google/android/gms/games/multiplayer/Participatable.html", type:"class", deprecated:"false" },
+      { id:84, label:"com.google.android.gms.games.multiplayer.realtime", link:"reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html", type:"package", deprecated:"false" },
+      { id:85, label:"com.google.android.gms.games.multiplayer.realtime.RealTimeMessage", link:"reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html", type:"class", deprecated:"false" },
+      { id:86, label:"com.google.android.gms.games.multiplayer.realtime.RealTimeMessageReceivedListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html", type:"class", deprecated:"false" },
+      { id:87, label:"com.google.android.gms.games.multiplayer.realtime.RealTimeReliableMessageSentListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html", type:"class", deprecated:"false" },
+      { id:88, label:"com.google.android.gms.games.multiplayer.realtime.Room", link:"reference/com/google/android/gms/games/multiplayer/realtime/Room.html", type:"class", deprecated:"false" },
+      { id:89, label:"com.google.android.gms.games.multiplayer.realtime.RoomConfig", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html", type:"class", deprecated:"false" },
+      { id:90, label:"com.google.android.gms.games.multiplayer.realtime.RoomConfig.Builder", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html", type:"class", deprecated:"false" },
+      { id:91, label:"com.google.android.gms.games.multiplayer.realtime.RoomEntity", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html", type:"class", deprecated:"false" },
+      { id:92, label:"com.google.android.gms.games.multiplayer.realtime.RoomStatusUpdateListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html", type:"class", deprecated:"false" },
+      { id:93, label:"com.google.android.gms.games.multiplayer.realtime.RoomUpdateListener", link:"reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html", type:"class", deprecated:"false" },
+      { id:94, label:"com.google.android.gms.gcm", link:"reference/com/google/android/gms/gcm/package-summary.html", type:"package", deprecated:"false" },
+      { id:95, label:"com.google.android.gms.gcm.GoogleCloudMessaging", link:"reference/com/google/android/gms/gcm/GoogleCloudMessaging.html", type:"class", deprecated:"false" },
+      { id:96, label:"com.google.android.gms.location", link:"reference/com/google/android/gms/location/package-summary.html", type:"package", deprecated:"false" },
+      { id:97, label:"com.google.android.gms.location.ActivityRecognitionClient", link:"reference/com/google/android/gms/location/ActivityRecognitionClient.html", type:"class", deprecated:"false" },
+      { id:98, label:"com.google.android.gms.location.ActivityRecognitionResult", link:"reference/com/google/android/gms/location/ActivityRecognitionResult.html", type:"class", deprecated:"false" },
+      { id:99, label:"com.google.android.gms.location.DetectedActivity", link:"reference/com/google/android/gms/location/DetectedActivity.html", type:"class", deprecated:"false" },
+      { id:100, label:"com.google.android.gms.location.Geofence", link:"reference/com/google/android/gms/location/Geofence.html", type:"class", deprecated:"false" },
+      { id:101, label:"com.google.android.gms.location.Geofence.Builder", link:"reference/com/google/android/gms/location/Geofence.Builder.html", type:"class", deprecated:"false" },
+      { id:102, label:"com.google.android.gms.location.LocationClient", link:"reference/com/google/android/gms/location/LocationClient.html", type:"class", deprecated:"false" },
+      { id:103, label:"com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener", link:"reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html", type:"class", deprecated:"false" },
+      { id:104, label:"com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener", link:"reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html", type:"class", deprecated:"false" },
+      { id:105, label:"com.google.android.gms.location.LocationListener", link:"reference/com/google/android/gms/location/LocationListener.html", type:"class", deprecated:"false" },
+      { id:106, label:"com.google.android.gms.location.LocationRequest", link:"reference/com/google/android/gms/location/LocationRequest.html", type:"class", deprecated:"false" },
+      { id:107, label:"com.google.android.gms.location.LocationStatusCodes", link:"reference/com/google/android/gms/location/LocationStatusCodes.html", type:"class", deprecated:"false" },
+      { id:108, label:"com.google.android.gms.maps", link:"reference/com/google/android/gms/maps/package-summary.html", type:"package", deprecated:"false" },
+      { id:109, label:"com.google.android.gms.maps.CameraUpdate", link:"reference/com/google/android/gms/maps/CameraUpdate.html", type:"class", deprecated:"false" },
+      { id:110, label:"com.google.android.gms.maps.CameraUpdateFactory", link:"reference/com/google/android/gms/maps/CameraUpdateFactory.html", type:"class", deprecated:"false" },
+      { id:111, label:"com.google.android.gms.maps.GoogleMap", link:"reference/com/google/android/gms/maps/GoogleMap.html", type:"class", deprecated:"false" },
+      { id:112, label:"com.google.android.gms.maps.GoogleMap.CancelableCallback", link:"reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html", type:"class", deprecated:"false" },
+      { id:113, label:"com.google.android.gms.maps.GoogleMap.InfoWindowAdapter", link:"reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html", type:"class", deprecated:"false" },
+      { id:114, label:"com.google.android.gms.maps.GoogleMap.OnCameraChangeListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html", type:"class", deprecated:"false" },
+      { id:115, label:"com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html", type:"class", deprecated:"false" },
+      { id:116, label:"com.google.android.gms.maps.GoogleMap.OnMapClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html", type:"class", deprecated:"false" },
+      { id:117, label:"com.google.android.gms.maps.GoogleMap.OnMapLongClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html", type:"class", deprecated:"false" },
+      { id:118, label:"com.google.android.gms.maps.GoogleMap.OnMarkerClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html", type:"class", deprecated:"false" },
+      { id:119, label:"com.google.android.gms.maps.GoogleMap.OnMarkerDragListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html", type:"class", deprecated:"false" },
+      { id:120, label:"com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html", type:"class", deprecated:"false" },
+      { id:121, label:"com.google.android.gms.maps.GoogleMap.OnMyLocationChangeListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html", type:"class", deprecated:"true" },
+      { id:122, label:"com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback", link:"reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html", type:"class", deprecated:"false" },
+      { id:123, label:"com.google.android.gms.maps.GoogleMapOptions", link:"reference/com/google/android/gms/maps/GoogleMapOptions.html", type:"class", deprecated:"false" },
+      { id:124, label:"com.google.android.gms.maps.LocationSource", link:"reference/com/google/android/gms/maps/LocationSource.html", type:"class", deprecated:"false" },
+      { id:125, label:"com.google.android.gms.maps.LocationSource.OnLocationChangedListener", link:"reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html", type:"class", deprecated:"false" },
+      { id:126, label:"com.google.android.gms.maps.MapFragment", link:"reference/com/google/android/gms/maps/MapFragment.html", type:"class", deprecated:"false" },
+      { id:127, label:"com.google.android.gms.maps.MapView", link:"reference/com/google/android/gms/maps/MapView.html", type:"class", deprecated:"false" },
+      { id:128, label:"com.google.android.gms.maps.MapsInitializer", link:"reference/com/google/android/gms/maps/MapsInitializer.html", type:"class", deprecated:"false" },
+      { id:129, label:"com.google.android.gms.maps.Projection", link:"reference/com/google/android/gms/maps/Projection.html", type:"class", deprecated:"false" },
+      { id:130, label:"com.google.android.gms.maps.SupportMapFragment", link:"reference/com/google/android/gms/maps/SupportMapFragment.html", type:"class", deprecated:"false" },
+      { id:131, label:"com.google.android.gms.maps.UiSettings", link:"reference/com/google/android/gms/maps/UiSettings.html", type:"class", deprecated:"false" },
+      { id:132, label:"com.google.android.gms.maps.model", link:"reference/com/google/android/gms/maps/model/package-summary.html", type:"package", deprecated:"false" },
+      { id:133, label:"com.google.android.gms.maps.model.BitmapDescriptor", link:"reference/com/google/android/gms/maps/model/BitmapDescriptor.html", type:"class", deprecated:"false" },
+      { id:134, label:"com.google.android.gms.maps.model.BitmapDescriptorFactory", link:"reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html", type:"class", deprecated:"false" },
+      { id:135, label:"com.google.android.gms.maps.model.CameraPosition", link:"reference/com/google/android/gms/maps/model/CameraPosition.html", type:"class", deprecated:"false" },
+      { id:136, label:"com.google.android.gms.maps.model.CameraPosition.Builder", link:"reference/com/google/android/gms/maps/model/CameraPosition.Builder.html", type:"class", deprecated:"false" },
+      { id:137, label:"com.google.android.gms.maps.model.Circle", link:"reference/com/google/android/gms/maps/model/Circle.html", type:"class", deprecated:"false" },
+      { id:138, label:"com.google.android.gms.maps.model.CircleOptions", link:"reference/com/google/android/gms/maps/model/CircleOptions.html", type:"class", deprecated:"false" },
+      { id:139, label:"com.google.android.gms.maps.model.GroundOverlay", link:"reference/com/google/android/gms/maps/model/GroundOverlay.html", type:"class", deprecated:"false" },
+      { id:140, label:"com.google.android.gms.maps.model.GroundOverlayOptions", link:"reference/com/google/android/gms/maps/model/GroundOverlayOptions.html", type:"class", deprecated:"false" },
+      { id:141, label:"com.google.android.gms.maps.model.LatLng", link:"reference/com/google/android/gms/maps/model/LatLng.html", type:"class", deprecated:"false" },
+      { id:142, label:"com.google.android.gms.maps.model.LatLngBounds", link:"reference/com/google/android/gms/maps/model/LatLngBounds.html", type:"class", deprecated:"false" },
+      { id:143, label:"com.google.android.gms.maps.model.LatLngBounds.Builder", link:"reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html", type:"class", deprecated:"false" },
+      { id:144, label:"com.google.android.gms.maps.model.Marker", link:"reference/com/google/android/gms/maps/model/Marker.html", type:"class", deprecated:"false" },
+      { id:145, label:"com.google.android.gms.maps.model.MarkerOptions", link:"reference/com/google/android/gms/maps/model/MarkerOptions.html", type:"class", deprecated:"false" },
+      { id:146, label:"com.google.android.gms.maps.model.Polygon", link:"reference/com/google/android/gms/maps/model/Polygon.html", type:"class", deprecated:"false" },
+      { id:147, label:"com.google.android.gms.maps.model.PolygonOptions", link:"reference/com/google/android/gms/maps/model/PolygonOptions.html", type:"class", deprecated:"false" },
+      { id:148, label:"com.google.android.gms.maps.model.Polyline", link:"reference/com/google/android/gms/maps/model/Polyline.html", type:"class", deprecated:"false" },
+      { id:149, label:"com.google.android.gms.maps.model.PolylineOptions", link:"reference/com/google/android/gms/maps/model/PolylineOptions.html", type:"class", deprecated:"false" },
+      { id:150, label:"com.google.android.gms.maps.model.RuntimeRemoteException", link:"reference/com/google/android/gms/maps/model/RuntimeRemoteException.html", type:"class", deprecated:"false" },
+      { id:151, label:"com.google.android.gms.maps.model.Tile", link:"reference/com/google/android/gms/maps/model/Tile.html", type:"class", deprecated:"false" },
+      { id:152, label:"com.google.android.gms.maps.model.TileOverlay", link:"reference/com/google/android/gms/maps/model/TileOverlay.html", type:"class", deprecated:"false" },
+      { id:153, label:"com.google.android.gms.maps.model.TileOverlayOptions", link:"reference/com/google/android/gms/maps/model/TileOverlayOptions.html", type:"class", deprecated:"false" },
+      { id:154, label:"com.google.android.gms.maps.model.TileProvider", link:"reference/com/google/android/gms/maps/model/TileProvider.html", type:"class", deprecated:"false" },
+      { id:155, label:"com.google.android.gms.maps.model.UrlTileProvider", link:"reference/com/google/android/gms/maps/model/UrlTileProvider.html", type:"class", deprecated:"false" },
+      { id:156, label:"com.google.android.gms.maps.model.VisibleRegion", link:"reference/com/google/android/gms/maps/model/VisibleRegion.html", type:"class", deprecated:"false" },
+      { id:157, label:"com.google.android.gms.panorama", link:"reference/com/google/android/gms/panorama/package-summary.html", type:"package", deprecated:"false" },
+      { id:158, label:"com.google.android.gms.panorama.PanoramaClient", link:"reference/com/google/android/gms/panorama/PanoramaClient.html", type:"class", deprecated:"false" },
+      { id:159, label:"com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener", link:"reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html", type:"class", deprecated:"false" },
+      { id:160, label:"com.google.android.gms.plus", link:"reference/com/google/android/gms/plus/package-summary.html", type:"package", deprecated:"false" },
+      { id:161, label:"com.google.android.gms.plus.PlusClient", link:"reference/com/google/android/gms/plus/PlusClient.html", type:"class", deprecated:"false" },
+      { id:162, label:"com.google.android.gms.plus.PlusClient.Builder", link:"reference/com/google/android/gms/plus/PlusClient.Builder.html", type:"class", deprecated:"false" },
+      { id:163, label:"com.google.android.gms.plus.PlusClient.OnAccessRevokedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnAccessRevokedListener.html", type:"class", deprecated:"false" },
+      { id:164, label:"com.google.android.gms.plus.PlusClient.OnMomentsLoadedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnMomentsLoadedListener.html", type:"class", deprecated:"false" },
+      { id:165, label:"com.google.android.gms.plus.PlusClient.OnPeopleLoadedListener", link:"reference/com/google/android/gms/plus/PlusClient.OnPeopleLoadedListener.html", type:"class", deprecated:"false" },
+      { id:166, label:"com.google.android.gms.plus.PlusClient.OrderBy", link:"reference/com/google/android/gms/plus/PlusClient.OrderBy.html", type:"class", deprecated:"false" },
+      { id:167, label:"com.google.android.gms.plus.PlusOneButton", link:"reference/com/google/android/gms/plus/PlusOneButton.html", type:"class", deprecated:"false" },
+      { id:168, label:"com.google.android.gms.plus.PlusOneButton.DefaultOnPlusOneClickListener", link:"reference/com/google/android/gms/plus/PlusOneButton.DefaultOnPlusOneClickListener.html", type:"class", deprecated:"false" },
+      { id:169, label:"com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener", link:"reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html", type:"class", deprecated:"false" },
+      { id:170, label:"com.google.android.gms.plus.PlusOneButtonWithPopup", link:"reference/com/google/android/gms/plus/PlusOneButtonWithPopup.html", type:"class", deprecated:"false" },
+      { id:171, label:"com.google.android.gms.plus.PlusOneDummyView", link:"reference/com/google/android/gms/plus/PlusOneDummyView.html", type:"class", deprecated:"false" },
+      { id:172, label:"com.google.android.gms.plus.PlusShare", link:"reference/com/google/android/gms/plus/PlusShare.html", type:"class", deprecated:"false" },
+      { id:173, label:"com.google.android.gms.plus.PlusShare.Builder", link:"reference/com/google/android/gms/plus/PlusShare.Builder.html", type:"class", deprecated:"false" },
+      { id:174, label:"com.google.android.gms.plus.model.moments", link:"reference/com/google/android/gms/plus/model/moments/package-summary.html", type:"package", deprecated:"false" },
+      { id:175, label:"com.google.android.gms.plus.model.moments.ItemScope", link:"reference/com/google/android/gms/plus/model/moments/ItemScope.html", type:"class", deprecated:"false" },
+      { id:176, label:"com.google.android.gms.plus.model.moments.ItemScope.Builder", link:"reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html", type:"class", deprecated:"false" },
+      { id:177, label:"com.google.android.gms.plus.model.moments.Moment", link:"reference/com/google/android/gms/plus/model/moments/Moment.html", type:"class", deprecated:"false" },
+      { id:178, label:"com.google.android.gms.plus.model.moments.Moment.Builder", link:"reference/com/google/android/gms/plus/model/moments/Moment.Builder.html", type:"class", deprecated:"false" },
+      { id:179, label:"com.google.android.gms.plus.model.moments.MomentBuffer", link:"reference/com/google/android/gms/plus/model/moments/MomentBuffer.html", type:"class", deprecated:"false" },
+      { id:180, label:"com.google.android.gms.plus.model.people", link:"reference/com/google/android/gms/plus/model/people/package-summary.html", type:"package", deprecated:"false" },
+      { id:181, label:"com.google.android.gms.plus.model.people.Person", link:"reference/com/google/android/gms/plus/model/people/Person.html", type:"class", deprecated:"false" },
+      { id:182, label:"com.google.android.gms.plus.model.people.Person.AgeRange", link:"reference/com/google/android/gms/plus/model/people/Person.AgeRange.html", type:"class", deprecated:"false" },
+      { id:183, label:"com.google.android.gms.plus.model.people.Person.Collection", link:"reference/com/google/android/gms/plus/model/people/Person.Collection.html", type:"class", deprecated:"true" },
+      { id:184, label:"com.google.android.gms.plus.model.people.Person.Cover", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.html", type:"class", deprecated:"false" },
+      { id:185, label:"com.google.android.gms.plus.model.people.Person.Cover.CoverInfo", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html", type:"class", deprecated:"false" },
+      { id:186, label:"com.google.android.gms.plus.model.people.Person.Cover.CoverPhoto", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html", type:"class", deprecated:"false" },
+      { id:187, label:"com.google.android.gms.plus.model.people.Person.Cover.Layout", link:"reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html", type:"class", deprecated:"false" },
+      { id:188, label:"com.google.android.gms.plus.model.people.Person.Emails", link:"reference/com/google/android/gms/plus/model/people/Person.Emails.html", type:"class", deprecated:"true" },
+      { id:189, label:"com.google.android.gms.plus.model.people.Person.Emails.Type", link:"reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html", type:"class", deprecated:"true" },
+      { id:190, label:"com.google.android.gms.plus.model.people.Person.Gender", link:"reference/com/google/android/gms/plus/model/people/Person.Gender.html", type:"class", deprecated:"false" },
+      { id:191, label:"com.google.android.gms.plus.model.people.Person.Image", link:"reference/com/google/android/gms/plus/model/people/Person.Image.html", type:"class", deprecated:"false" },
+      { id:192, label:"com.google.android.gms.plus.model.people.Person.Name", link:"reference/com/google/android/gms/plus/model/people/Person.Name.html", type:"class", deprecated:"false" },
+      { id:193, label:"com.google.android.gms.plus.model.people.Person.ObjectType", link:"reference/com/google/android/gms/plus/model/people/Person.ObjectType.html", type:"class", deprecated:"false" },
+      { id:194, label:"com.google.android.gms.plus.model.people.Person.OrderBy", link:"reference/com/google/android/gms/plus/model/people/Person.OrderBy.html", type:"class", deprecated:"true" },
+      { id:195, label:"com.google.android.gms.plus.model.people.Person.Organizations", link:"reference/com/google/android/gms/plus/model/people/Person.Organizations.html", type:"class", deprecated:"false" },
+      { id:196, label:"com.google.android.gms.plus.model.people.Person.Organizations.Type", link:"reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html", type:"class", deprecated:"false" },
+      { id:197, label:"com.google.android.gms.plus.model.people.Person.PlacesLived", link:"reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html", type:"class", deprecated:"false" },
+      { id:198, label:"com.google.android.gms.plus.model.people.Person.RelationshipStatus", link:"reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html", type:"class", deprecated:"false" },
+      { id:199, label:"com.google.android.gms.plus.model.people.Person.Urls", link:"reference/com/google/android/gms/plus/model/people/Person.Urls.html", type:"class", deprecated:"false" },
+      { id:200, label:"com.google.android.gms.plus.model.people.Person.Urls.Type", link:"reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html", type:"class", deprecated:"false" },
+      { id:201, label:"com.google.android.gms.plus.model.people.PersonBuffer", link:"reference/com/google/android/gms/plus/model/people/PersonBuffer.html", type:"class", deprecated:"false" }
 
     ];
diff --git a/docs/html/samples/images/ActionBarCompat1.png b/docs/html/samples/images/ActionBarCompat1.png
new file mode 100644
index 0000000..64d3e66
--- /dev/null
+++ b/docs/html/samples/images/ActionBarCompat1.png
Binary files differ
diff --git a/docs/html/samples/images/ActionBarCompat2.png b/docs/html/samples/images/ActionBarCompat2.png
new file mode 100644
index 0000000..04a7e6c
--- /dev/null
+++ b/docs/html/samples/images/ActionBarCompat2.png
Binary files differ
diff --git a/docs/html/samples/index.jd b/docs/html/samples/index.jd
new file mode 100644
index 0000000..3ea5245
--- /dev/null
+++ b/docs/html/samples/index.jd
@@ -0,0 +1,11 @@
+page.title=Samples
+@jd:body
+
+
+<div id="samples">
+<p>Some kind of sample sorting will appear here.</p>
+</div>
+
+
+<script>
+</script>
diff --git a/docs/html/samples/samples_toc.cs b/docs/html/samples/samples_toc.cs
new file mode 100644
index 0000000..14a5b0a
--- /dev/null
+++ b/docs/html/samples/samples_toc.cs
@@ -0,0 +1,16 @@
+
+<ul id="nav" class="samples-nav">
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="/samples/index.html">
+      <span class="en">About the Samples</span></a>
+    </div>
+  </li>
+</ul>
+
diff --git a/docs/html/samples/topic.jd b/docs/html/samples/topic.jd
new file mode 100644
index 0000000..cac9b10
--- /dev/null
+++ b/docs/html/samples/topic.jd
@@ -0,0 +1,26 @@
+page.title=Samples
+@jd:body
+
+
+<div id="samples">
+</div>
+
+
+
+<script>
+  $(document).ready(showSamples);
+
+  /** Display links and other information about samples that match the
+      group specified by the URL */
+  function showSamples() {
+    var group = getGroup();
+    $("#body-content h1").html(group);
+    $("#samples").html("<p>OK, here are some samples about <b>" + group + "</b>.</p>");
+  }
+
+  /** Return the group provided by the URL */
+  function getGroup() {
+    var hashParts = location.hash.split('t=');
+    return hashParts[1];
+  }
+</script>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 4ea3752..eb2d6a7 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 
 
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130729.zip
-sdk.linux32_bundle_bytes=457716139
-sdk.linux32_bundle_checksum=b3686d10dc1cbceba1074404d4386283
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130917.zip
+sdk.linux32_bundle_bytes=474924071
+sdk.linux32_bundle_checksum=912b2dac6e0a4fa4ae1417271bf42863
 
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130729.zip
-sdk.linux64_bundle_bytes=458006784
-sdk.linux64_bundle_checksum=1fabcc3f772ba8b2fc194d6e0449da17
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130917.zip
+sdk.linux64_bundle_bytes=475215747
+sdk.linux64_bundle_checksum=2f7523d4eba9a8302c3c4a3955785e18
 
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130729.zip
-sdk.mac64_bundle_bytes=428792424
-sdk.mac64_bundle_checksum=6c42b9966abcfa8a75c0ee83d0d95882
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130917.zip
+sdk.mac64_bundle_bytes=448581372
+sdk.mac64_bundle_checksum=4e2d599486ecc935d24eeef5eb641364
 
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130729.zip
-sdk.win32_bundle_bytes=463931746
-sdk.win32_bundle_checksum=51faf4e5fdf9c5b4a176179a99ce3511
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130917.zip
+sdk.win32_bundle_bytes=481803289
+sdk.win32_bundle_checksum=5d6c79a47c8b47170cff3d231dcf7ad3
 
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130729.zip
-sdk.win64_bundle_bytes=464064756
-sdk.win64_bundle_checksum=e8f05c1fddb8e609e880de23113c7426
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130917.zip
+sdk.win64_bundle_bytes=481934982
+sdk.win64_bundle_checksum=918f80aad61ec21509d86a2fbd87fd44
 
 
 
-sdk.linux_download=android-sdk_r22.0.5-linux.tgz
-sdk.linux_bytes=105641005
-sdk.linux_checksum=8201b10c21510f082c54f58a9bb082c8
+sdk.linux_download=android-sdk_r22.2.1-linux.tgz
+sdk.linux_bytes=100918342
+sdk.linux_checksum=05911d3052a1cbf678561104d35a1bc0
 
-sdk.mac_download=android-sdk_r22.0.5-macosx.zip
-sdk.mac_bytes=77225724
-sdk.mac_checksum=94f3cbe896c332b94ee0408ae610a4b8
+sdk.mac_download=android-sdk_r22.2.1-macosx.zip
+sdk.mac_bytes=74859877
+sdk.mac_checksum=727a51affa2af733eca1aa307c73c3bd
 
-sdk.win_download=android-sdk_r22.0.5-windows.zip
-sdk.win_bytes=113510621
-sdk.win_checksum=30695dffc41e0d7cf9ff948ab0c48920
+sdk.win_download=android-sdk_r22.2.1-windows.zip
+sdk.win_bytes=108797377
+sdk.win_checksum=bea5d28cfb6c073b32643dd3ed0bc1e0
 
-sdk.win_installer=installer_r22.0.5-windows.exe
-sdk.win_installer_bytes=93505782
-sdk.win_installer_checksum=940849be19ac6151e3e35c8706c81d86
+sdk.win_installer=installer_r22.2.1-windows.exe
+sdk.win_installer_bytes=88795776
+sdk.win_installer_checksum=07e6e47de6c4549bea6986453119b37c
 
 
 
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index bdc07d0..66b1c43 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=22.0.5
-adt.zip.download=ADT-22.0.5.zip
-adt.zip.bytes=16839757
-adt.zip.checksum=1097fccf32063e3638a9d27aa0f295ca
+adt.zip.version=22.2.1
+adt.zip.download=ADT-22.2.1.zip
+adt.zip.bytes=14476845
+adt.zip.checksum=97176754a1e86adf2e5e05f44dc7229e
 
 @jd:body
 
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 5a47f85..3399ee8 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -187,7 +187,7 @@
 
 <div id="main">
 
-<div class="figure" style="width:400px;margin-top:-50px">
+<div class="figure" style="width:400px;margin-top:-20px">
 <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"
@@ -221,6 +221,10 @@
   <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>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.
 </ul>
 
 <p class="caution"><strong>Caution:</strong> Android Studio is currently available as
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 3a416f9..9bff5d4 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -74,7 +74,7 @@
 http://developer.android.com/downloads/design/Android_Design_Illustrator_Vectors_20120814.ai
 http://developer.android.com/downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle
 http://developer.android.com/downloads/design/Android_Design_Holo_Widgets_20120814.zip
-http://developer.android.com/downloads/design/Android_Design_Icons_20120814.zip
+http://developer.android.com/downloads/design/Android_Design_Icons_20130926.zip
 http://developer.android.com/downloads/design/Roboto_Hinted_20120823.zip
 http://developer.android.com/downloads/design/Roboto_Specimen_Book_20111129.pdf
 http://developer.android.com/downloads/design/Android_Design_Color_Swatches_20120229.zip
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index 820edbd..02216de 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -22,20 +22,31 @@
 
 
 
-<p>To develop an Android app, you must install at least one Android platform from the SDK Manager
-against which you can compile your app. Often, any given version of the Android will be revised
-with bug fixes or other changes, as denoted by the revision number. Below, you'll find the
-release notes for each version of the platform and the subsequent revisions to the platform
-version.</p>
+<p>This document provides information about Android platform releases. In order to compile your
+application against a particular platform release, you must download and install the SDK Platform
+for that release. If you want to test your application on an emulator, you must also download at
+least one system image for that platform release.</p>
 
-<p>To determine what revision of an Android platform you have installed, refer to the
-<strong>Installed Packages</strong> listing in the Android
+<p>Each platform release includes system images that support a specific processor architecture,
+such as ARM EABI, Intel x86 or MIPS. Platform releases also include a system image that contains
+Google APIs. The <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> lists available
+platform system images under each platform version header, for example:</p>
+
+<ul>
+  <li>ARM EABI v7a System Image</li>
+  <li>Intel x86 Atom System Image</li>
+  <li>MIPS System Image</li>
+  <li>Google APIs</li>
+</ul>
+
+<p>To determine what revisions of an Android platform you have installed, refer to the
+<em>Packages</em> listing in the Android
 <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p>
 
 <p class="caution"><strong>Important:</strong> To download the most recent Android
-system components from the Android SDK Manager, you must first update the SDK Tools to
-revision 22 or later and restart the SDK Manager. If you do not,
-the latest Android system components will not be available for download.</p>
+system components from the Android SDK Manager, you must first update the SDK Tools to the
+most recent release and restart the SDK Manager. If you do not, the latest Android system
+components will not be available for download.</p>
 
 
 
@@ -46,6 +57,25 @@
 
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 2</a> <em>(August 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Maintenance update. The system version is 4.3.</p>
+    <dl>
+      <dt>Dependencies:</dt>
+      <dd>Android SDK Platform-tools r18 or higher is required.</dd>
+      <dd>Android SDK Tools 22.0.4 or higher is recommended.</dd>
+    </dl>
+
+  </div>
+</div>
+
+<div class="toggle-content closed">
+
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
 class="toggle-content-img" alt="" />Revision 1</a> <em>(July 2013)</em>
   </p>
 
@@ -61,6 +91,54 @@
   </div>
 </div>
 
+<h3 id="">Google APIs System Image</h3>
+
+<div class="toggle-content opened">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 3</a> <em>(September 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Maintenance update. This release includes
+    <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 3.2.65,
+    allowing you to test your application in an emulator using the latest Google Play services.</p>
+
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
+class="toggle-content-img" alt="" />Revision 2</a> <em>(August 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Maintenance update. This release includes
+    <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 3.2.25,
+    allowing you to test your application in an emulator using the latest Google Play services.</p>
+
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
+class="toggle-content-img" alt="" />Revision 1</a> <em>(July 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Initial release. This release includes
+    <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 3.1.58.</p>
+
+  </div>
+</div>
+
+
+
 
 <h2 id="4.2">Android 4.2</h2>
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index e9c514e..cfdf8cc 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,78 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 22.2.1</a> <em>(September 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required.</li>
+      <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.2.1</a>.
+        If you haven't already installed SDK Tools r22.2.1 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Fixed problem with templates that causes the new project wizard to hang.
+       (<a href="http://b.android.com/60149">Issue 60149</a>)</li>
+    </ul>
+  </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+      alt=""/>ADT 22.2</a> <em>(September 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required.</li>
+      <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.2</a>.
+        If you haven't already installed SDK Tools r22.2 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Updated build tools to allow use of RenderScript on older versions of Android
+       using new features in the
+       <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+      <li>Reverted signing changes that sometimes trigger a signing verification problem on older
+        platforms.</li>
+      <li>Fixed problem with gradle export function for the Windows platform.</li>
+    </ul>
+  </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 22.0.5</a> <em>(July 2013)</em>
   </p>
 
@@ -78,7 +150,7 @@
   <dt>General Notes:</dt>
   <dd>
     <ul>
-      <li>Fixed Renderscript compilation issue for Windows platforms.</li>
+      <li>Fixed RenderScript compilation issue for Windows platforms.</li>
       <li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> report generation
         in the Monitor and DDMS perspectives.</li>
     </ul>
@@ -113,7 +185,7 @@
   <dt>General Notes:</dt>
   <dd>
     <ul>
-      <li>Fixed problem with compiling Renderscript code.</li>
+      <li>Fixed problem with compiling RenderScript code.</li>
       <li>Improved Gradle export with better workflow and error reporting.</li>
       <li>Improved Gradle multi-module export feature.</li>
       <li>Updated build logic to force exporting of the classpath containers unless you are using
@@ -1005,7 +1077,7 @@
 <dt>Bug fixes:</dt>
 <dd>
 <ul>
-  <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+  <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
     (<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
   <li>Fixed issue when creating projects from existing source code.</li>
   <li>Fixed issues in the SDK Manager
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 4aef8a0..25c409e 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -30,6 +30,88 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 22.2.1</a> <em>(September 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 16 or later.</li>
+        <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+          designed for use with ADT 22.2.1 and later. If you haven't already, update your
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.2.1.</li>
+        <li>If you are developing outside Eclipse, you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Fixed problem with templates that causes the new project wizard to hang.
+         (<a href="http://b.android.com/60149">Issue 60149</a>)</li>
+        <li>Fixed crash when using the lint command line tool because of mis-matched library
+          dependency. (<a href="http://b.android.com/60190">Issue 60190</a>)</li>
+      </ul>
+    </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 22.2</a> <em>(September 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 16 or later.</li>
+        <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+          designed for use with ADT 22.2 and later. If you haven't already, update your
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.2.</li>
+        <li>If you are developing outside Eclipse, you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Updated build tools to allow use of RenderScript on older versions of Android
+         using new features in the
+         <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+        <li>Moved the Systrace tool to the {@code &gt;sdk&lt;/platform-tools/} directory. </li>
+        <li>Modified <a href="{@docRoot}tools/help/gltracer.html">Tracer for OpenGL ES</a> to
+          support OpenGL ES 3.0.</li>
+        <li>Lint
+          <ul>
+            <li>Fixed problem with lint not detecting custom namespaces.
+              (<a href="http://b.android.com/55673">Issue 55673</a>)</li>
+            <li>Fixed problem with the XML report including invalid characters.
+              (<a href="http://b.android.com/56205">Issue 56205</a>)</li>
+            <li>Fixed command-line execution of lint to work in headless mode to support execution
+              by build servers. (<a href="http://b.android.com/55820">Issue 55820</a>)</li>
+          </ul>
+        </li>
+        <li>Improved support for path names with spaces in the Windows command-line tools.</li>
+      </ul>
+    </dd>
+    </dl>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 22.0.5</a> <em>(July 2013)</em>
   </p>
 
@@ -55,10 +137,10 @@
     <dt>General Notes:</dt>
     <dd>
       <ul>
-        <li>Fixed Renderscript compilation issue for Windows platforms with ant.</li>
+        <li>Fixed RenderScript compilation issue for Windows platforms with ant.</li>
         <li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> to work with the
           Android 4.3 platform image.</li>
-        <li>Fixed packaging of Renderscript compiler.</li>
+        <li>Fixed packaging of RenderScript compiler.</li>
         <li>Build tools 18.0.0 is obsolete and 18.0.1 should be used instead.</li>
       </ul>
     </dd>
@@ -95,7 +177,7 @@
     <dt>General Notes:</dt>
     <dd>
       <ul>
-        <li>Fixed problem with compiling Renderscript code.</li>
+        <li>Fixed problem with compiling RenderScript code.</li>
       </ul>
     </dd>
     </dl>
@@ -274,17 +356,17 @@
           </ul>
         </li>
 
-        <li>Renderscript
+        <li>RenderScript
           <ul>
             <li>Added support for
               <a href="{@docRoot}guide/topics/renderscript/compute.html#filterscript">Filterscript</a>
               compilation.</li>
-            <li>Added new project setting to control the Renderscript compilation target separately
+            <li>Added new project setting to control the RenderScript compilation target separately
               from an Android project. Adding the following line to a {@code project.properties}
-              file causes Renderscript code to be compiled for Android API Level 17, while the
+              file causes RenderScript code to be compiled for Android API Level 17, while the
               containing application can target a different (lower) API level:
               <pre>renderscript.target = 17</pre>
-              Previously, the Renderscript compilation target was tied to the
+              Previously, the RenderScript compilation target was tied to the
               {@code android:minSdkVersion} setting in the manifest.
               (<a href="http://code.google.com/p/android/issues/detail?id=40487">Issue 40487</a>)
             </li>
@@ -483,7 +565,7 @@
         <li>Improved resize algorithm for better rendering on scaled emulator windows.</li>
         <li>Fixed a bug in the {@code lint} check for unprotected broadcast receivers to ignore
 unprotected receivers for default Android actions.</li>
-        <li>Fixed build issue for projects using Renderscript.</li>
+        <li>Fixed build issue for projects using RenderScript.</li>
         <li>Fixed memory leak in the emulator.</li>
       </ul>
     </dd>
@@ -823,7 +905,7 @@
     <li>Fixed emulator crash on Linux due to improper webcam detection
     (<a href="http://code.google.com/p/android/issues/detail?id=20952">Issue 20952</a>).</li>
     <li>Fixed emulator issue when using the <code>-wipe-data</code> argument.</li>
-    <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+    <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
     (<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
     <li>Fixed issue when creating an AVD using the GoogleTV addon
     (<a href="http://code.google.com/p/android/issues/detail?id=20963">Issue 20963</a>).</li>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 8d25d96..65148bf 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -15,6 +15,7 @@
           <li><a href="#v7-mediarouter">v7 mediarouter library</a></li>
         </ol>
       </li>
+      <li><a href="#v8">v8 Support Library</a></li>
       <li><a href="#v13">v13 Support Library</a></li>
     </ol>
 
@@ -252,7 +253,7 @@
 where "18.0.0" is the minimum revision at which the library is available. For example:</p>
 
 <pre>
-com.android.support:support-v7-mediarouter:18.0.0
+com.android.support:mediarouter-v7:18.0.+
 </pre>
 
 <p class="caution">The v7 mediarouter library APIs introduced in Support Library
@@ -262,6 +263,24 @@
 developer preview</a>. </p>
 
 
+<h2 id="v8">v8 Support Library</h2>
+
+<p>This library is designed to be used with Android (API level 8) and higher. It adds support for
+  the <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> computation
+  framework. These APIs are included in the {@link android.support.v8.renderscript} package. You
+  should be aware that the steps for including these APIs in your application is <em>very
+  different</em> from other support library APIs. For more information about using these APIs
+  in your application, see the
+  <a href="{@docRoot}guide/topics/renderscript/compute.html#access-rs-apis">RenderScript</a>
+  developer guide.</p>
+
+<p class="note">
+  <strong>Note:</strong> Use of RenderScript with the support library is supported with the Android
+  Eclipse plugin and Ant build tools. It is <em>not currently</em> supported with Android Studio or
+  Gradle-based builds.
+</p>
+
+
 <h2 id="v13">v13 Support Library</h2>
 
 <p>This library is designed to be used for Android 3.2 (API level 13) and higher. It adds support
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 06c7a3f..4ee8c12 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -58,6 +58,7 @@
 
 <p>This section provides details about the Support Library package releases.</p>
 
+
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
diff --git a/docs/html/training/activity-testing/activity-basic-testing.jd b/docs/html/training/activity-testing/activity-basic-testing.jd
new file mode 100644
index 0000000..016289d
--- /dev/null
+++ b/docs/html/training/activity-testing/activity-basic-testing.jd
@@ -0,0 +1,227 @@
+page.title=Creating and Running a Test Case
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#testcase">Create a Test Case for Activity Testing</a>
+      <ol>
+      <li><a href="#fixture">Set Up Your Test Fixture</a></li>
+      <li><a href="#preconditions">Add Test Preconditions</a></li>
+      <li><a href="#test_method">Add Test Methods to Verify Your Activity</a></li>
+      </ol>
+  </li>
+  <li><a href="#build_run">Build and Run Your Test</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+<li><a href="{@docRoot}tools/testing/testing_android.html">Testing
+Fundamentals</a></li>
+</ul>
+
+</div>
+</div>
+<p>In order to verify that there are no regressions in the layout design and
+functional behavior in your application, it's important to
+create a test for each {@link android.app.Activity} in your application. For
+each test, you need to create the individual parts of a test case, including
+the test fixture, preconditions test method, and {@link android.app.Activity}
+test methods. You can then run your test to get a test report. If any test
+method fails, this might indicate a potential defect in your code.</p>
+<p class="note"><strong>Note:</strong> In the Test-Driven Development (TDD)
+approach, instead of writing most or all of your app code up-front and then
+running tests later in the development cycle, you would progressively write
+just enough production code to satisfy your test dependencies, update your
+test cases to reflect new functional requirements, and iterate repeatedly this
+way.</p>
+
+<h2 id="testcase">Create a Test Case</h2>
+<p>{@link android.app.Activity} tests are written in a structured way.
+Make sure to put your tests in a separate package, distinct from the code under
+test.</p>
+<p>By convention, your test package name should follow the same name as the
+application package, suffixed with <strong>".tests"</strong>. In the test package
+you created, add the Java class for your test case. By convention, your test case
+name should also follow the same name as the Java or Android class that you
+want to test, but suffixed with <strong>“Test”</strong>.</p>
+<p>To create a new test case in Eclipse:</p>
+<ol type="a">
+   <li>In the Package Explorer, right-click on the {@code /src} directory for
+your test project and select <strong>New &gt; Package</strong>.</li>
+   <li>Set the <strong>Name</strong> field to
+{@code &lt;your_app_package_name&gt;.tests} (for example,
+{@code com.example.android.testingfun.tests}) and click
+<strong>Finish</strong>.</li>
+   <li>Right-click on the test package you created, and select
+<strong>New &gt; Class</strong>.</li>
+    <li>Set the <strong>Name</strong> field to
+{@code &lt;your_app_activity_name&gt;Test} (for example,
+{@code MyFirstTestActivityTest}) and click <strong>Finish</strong>.</li>
+</ol>
+
+<h3 id="fixture">Set Up Your Test Fixture</h3>
+<p>A <em>test fixture</em> consists of objects that must be initialized for
+running one or more tests. To set up the test fixture, you can override the
+{@link junit.framework.TestCase#setUp()} and
+{@link junit.framework.TestCase#tearDown()} methods in your test. The
+test runner automatically runs {@link junit.framework.TestCase#setUp()} before
+running any other test methods, and {@link junit.framework.TestCase#tearDown()}
+at the end of each test method execution. You can use these methods to keep
+the code for test initialization and clean up separate from the tests methods.
+</p>
+<p>To set up your test fixture in Eclipse:</p>
+<ol>
+<li>In the Package Explorer, double-click on the test case that you created
+earlier to bring up the Eclipse Java editor, then modify your test case class
+to extend one of the sub-classes of {@link android.test.ActivityTestCase}.
+<p>For example:</p>
+<pre>
+public class MyFirstTestActivityTest
+        extends ActivityInstrumentationTestCase2&lt;MyFirstTestActivity&gt; {
+</pre>
+</li>
+<li>Next, add the constructor and {@link junit.framework.TestCase#setUp()}
+methods to your test case, and add variable declarations for the
+{@link android.app.Activity} that you want to test.</p>
+<p>For example:</p>
+<pre>
+public class MyFirstTestActivityTest
+        extends ActivityInstrumentationTestCase2&lt;MyFirstTestActivity&gt; {
+
+    private MyFirstTestActivity mFirstTestActivity;
+    private TextView mFirstTestText;
+
+    public MyFirstTestActivityTest() {
+        super(MyFirstTestActivity.class);
+    }
+
+    &#64;Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mFirstTestActivity = getActivity();
+        mFirstTestText =
+                (TextView) mFirstTestActivity
+                .findViewById(R.id.my_first_test_text_view);
+    }
+}
+</pre>
+<p>The constructor is invoked by the test runner to instantiate the test
+class, while the {@link junit.framework.TestCase#setUp()} method is invoked by
+the test runner before it runs any tests in the test class.</p>
+</li>
+</ol>
+
+<p>Typically, in the {@link junit.framework.TestCase#setUp()} method, you
+should:</p>
+<ul>
+<li>Invoke the superclass constructor for
+{@link junit.framework.TestCase#setUp()}, which is required by JUnit.</li>
+<li>Initialize your test fixture state by:
+   <ul>
+   <li>Defining the instance variables that store the state of the fixture.</li>
+   <li>Creating and storing a reference to an instance of the
+{@link android.app.Activity} under test.</li>
+   <li>Obtaining a reference to any UI components in the
+{@link android.app.Activity} that you want to test.</li>
+   </ul>
+</ul>
+
+<p>You can use the
+{@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to
+get a reference to the {@link android.app.Activity} under test.</p>
+
+<h3 id="preconditions">Add Test Preconditions</h3>
+<p>As a sanity check, it is good practice to verify that the test fixture has
+been set up correctly, and the objects that you want to test have been correctly
+instantiated or initialized. That way, you won’t have to see
+tests failing because something was wrong with the setup of your test fixture.
+By convention, the method for verifying your test fixture is called
+{@code testPreconditions()}.</p>
+
+<p>For example, you might want to add a {@code testPreconditons()} method like
+this to your test case:</p>
+
+<pre>
+public void testPreconditions() {
+    assertNotNull(“mFirstTestActivity is null”, mFirstTestActivity);
+    assertNotNull(“mFirstTestText is null”, mFirstTestText);
+}
+</pre>
+
+<p>The assertion methods are from the JUnit {@link junit.framework.Assert}
+class. Generally, you can use assertions to
+verify if a specific condition that you want to test is true.
+<ul>
+<li>If the condition is false, the assertion method throws an
+{@link android.test.AssertionFailedError} exception, which is then typically
+reported by the test runner. You can provide a string in the first argument of
+your assertion method to give some contextual details if the assertion fails.</li>
+<li>If the condition is true, the test passes.</li>
+</ul>
+<p>In both cases, the test runner proceeds to run the other test methods in the
+test case.</p>
+
+<h3 id="test_method">Add Test Methods to Verify Your Activity</h3>
+<p>Next, add one or more test methods to verify the layout and functional
+behavior of your {@link android.app.Activity}.</p>
+<p>For example, if your {@link android.app.Activity} includes a
+{@link android.widget.TextView}, you can add a test method like this to check
+that it has the correct label text:</p>
+<pre>
+public void testMyFirstTestTextView_labelText() {
+    final String expected =
+            mFirstTestActivity.getString(R.string.my_first_test);
+    final String actual = mFirstTestText.getText().toString();
+    assertEquals(expected, actual);
+}
+</pre>
+
+<p>The {@code testMyFirstTestTextView_labelText()} method simply checks that the
+default text of the {@link android.widget.TextView} that is set by the layout
+is the same as the expected text defined in the {@code strings.xml} resource.</p>
+<p class="note"><strong>Note:</strong> When naming test methods, you can use
+an underscore to separate what is being tested from the specific case being
+tested. This style makes it easier to see exactly what cases are being tested.</p>
+<p>When doing this type of string value comparison, it’s good practice to read
+the expected string from your resources, instead of hardcoding the string in
+your comparison code. This prevents your test from easily breaking whenever the
+string definitions are modified in the resource file.</p>
+<p>To perform the comparison, pass both the expected and actual strings as
+arguments to the
+{@link junit.framework.Assert#assertEquals(java.lang.String, java.lang.String) assertEquals()}
+method. If the values are not the same, the assertion will throw an
+{@link junit.framework.AssertionFailedError} exception.</p>
+<p>If you added a {@code testPreconditions()} method, put your test methods
+after the {@code testPreconditions()} definition in your Java class.</p>
+<p>For a complete test case example, take a look at
+{@code MyFirstTestActivityTest.java} in the sample app.</p>
+
+<h2 id="build_run">Build and Run Your Test</h2>
+<p>You can build and run your test easily from the Package Explorer in
+Eclipse.</p>
+<p>To build and run your test:</p>
+<ol>
+<li>Connect an Android device to your machine. On the device or emulator, open
+the <strong>Settings</strong> menu, select <strong>Developer options</strong>
+and make sure that USB debugging is enabled.</li>
+<li>In the Project Explorer, right-click on the test class that you created
+earlier and select <strong>Run As &gt; Android Junit Test</strong>.</li>
+<li>In the Android Device Chooser dialog, select the device that you just
+connected, then click <strong>OK</strong>.</li>
+<li>In the JUnit view, verify that the test passes with no errors or failures.</li>
+</ol>
+<p>For example, if the test case passes with no errors, the result should look
+like this:</p>
+<img src="{@docRoot}images/training/activity-testing_lesson2_MyFirstTestActivityTest_result.png" alt="" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> Result of a test with no errors.
+</p>
+
+
+
diff --git a/docs/html/training/activity-testing/activity-functional-testing.jd b/docs/html/training/activity-testing/activity-functional-testing.jd
new file mode 100644
index 0000000..7c8ff1d
--- /dev/null
+++ b/docs/html/training/activity-testing/activity-functional-testing.jd
@@ -0,0 +1,166 @@
+page.title=Creating Functional Tests
+trainingnavtop=true
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+   <li><a href="#test_methods">Add Test Method to Validate Functional Behavior</a>
+   <ol>
+      <li><a href="#activitymonitor">Set Up an ActivityMonitor</a></li>
+      <li><a href="#keyinput">Send Keyboard Input Using Instrumentation</a></li>
+   </ol>
+   </li>
+</ol>
+
+<h2>Try it out</h2>
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
+class="button">Download the demo</a>
+ <p class="filename">AndroidTestingFun.zip</p>
+</div>
+
+</div>
+</div>
+<p>Functional testing involves verifying that individual application
+components work together as expected by the user. For example, you can create a
+functional test to verify that an {@link android.app.Activity} correctly
+launches a target {@link android.app.Activity} when the user performs a UI
+interaction.</p>
+
+<p>To create a functional test for your {@link android.app.Activity}, your test
+class should extend {@link android.test.ActivityInstrumentationTestCase2}.
+Unlike {@link android.test.ActivityUnitTestCase},
+tests in {@link android.test.ActivityInstrumentationTestCase2} can
+communicate with the Android system and send keyboard input and click events to
+the UI.</p>
+
+<p>For a complete test case example, take a look at
+{@code SenderActivityTest.java} in the sample app.</p>
+
+<h2 id="test_methods">Add Test Method to Validate Functional Behavior</h2>
+<p id="test_goals">Your functional testing goals might include:</p>
+<ul>
+<li>Verifying that a target {@link android.app.Activity} is started when a
+UI control is pushed in the sender {@link android.app.Activity}.</li>
+<li>Verifying that the target {@link android.app.Activity} displays the
+correct data based on the user's input in the sender
+{@link android.app.Activity}.</li>
+</ul>
+<p>You might implement your test method like this:</p>
+
+<pre>
+&#64;MediumTest
+public void testSendMessageToReceiverActivity() {
+    final Button sendToReceiverButton = (Button) 
+            mSenderActivity.findViewById(R.id.send_message_button);
+
+    final EditText senderMessageEditText = (EditText) 
+            mSenderActivity.findViewById(R.id.message_input_edit_text);
+
+    // Set up an ActivityMonitor
+    ...
+
+    // Send string input value
+    ...
+
+    // Validate that ReceiverActivity is started
+    ...
+
+    // Validate that ReceiverActivity has the correct data
+    ...
+
+    // Remove the ActivityMonitor
+    ...
+}
+</pre>
+<p>The test waits for an {@link android.app.Activity} that matches this monitor,
+otherwise returns null after a timeout elapses. If {@code ReceiverActivity} was
+started, the {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}
+that you set
+up earlier receives a hit. You can use the assertion methods to verify that
+the {@code ReceiverActivity} is indeed started, and that the hit count on the
+{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} incremented
+as expected.</p>
+
+<h2 id="activitymonitor">Set up an ActivityMonitor</h2>
+<p>To monitor a single {@link android.app.Activity} in your application, you
+can register an {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}.
+The {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} is
+notified by the system whenever an {@link android.app.Activity} that matches your criteria is started.
+If a match is found, the monitor’s hit count is updated.</p>
+<p>Generally, to use an
+{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:</p>
+<ol>
+<li>Retrieve the {@link android.app.Instrumentation} instance for your test
+case by using the
+{@link android.test.InstrumentationTestCase#getInstrumentation()} method.</li>
+<li>Add an instance of {@link android.app.Instrumentation.ActivityMonitor} to
+the current instrumentation using one of the {@link android.app.Instrumentation}
+{@code addMonitor()} methods. The match criteria can be specified as an
+{@link android.content.IntentFilter} or a class name string.</li>
+<li>Wait for the {@link android.app.Activity} to start.</li>
+<li>Verify that the monitor hits were incremented.</li>
+<li>Remove the monitor.</li>
+</ol>
+<p>For example:</p>
+<pre>
+// Set up an ActivityMonitor
+ActivityMonitor receiverActivityMonitor =
+        getInstrumentation().addMonitor(ReceiverActivity.class.getName(),
+        null, false);
+
+// Validate that ReceiverActivity is started
+TouchUtils.clickView(this, sendToReceiverButton);
+ReceiverActivity receiverActivity = (ReceiverActivity) 
+        receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS);
+assertNotNull("ReceiverActivity is null", receiverActivity);
+assertEquals("Monitor for ReceiverActivity has not been called",
+        1, receiverActivityMonitor.getHits());
+assertEquals("Activity is of wrong type",
+        ReceiverActivity.class, receiverActivity.getClass());
+
+// Remove the ActivityMonitor
+getInstrumentation().removeMonitor(receiverActivityMonitor);
+</pre>
+
+<h2 id="keyinput">Send Keyboard Input Using Instrumentation</h2>
+<p>If your {@link android.app.Activity} has an {@link android.widget.EditText}
+field, you might want to test that users can enter values into the
+{@link android.widget.EditText} object.</p>
+<p>Generally, to send a string input value to an {@link android.widget.EditText}
+object in {@link android.test.ActivityInstrumentationTestCase2}, you should:</p>
+<ol>
+<li>Use the {@link android.app.Instrumentation#runOnMainSync(java.lang.Runnable) runOnMainSync()}
+method to run the {@link android.view.View#requestFocus()} call synchronously
+in a loop. This way, the UI thread is blocked until focus is received.</li>
+<li>Call {@link android.app.Instrumentation#waitForIdleSync()} method to wait
+for the main thread to become idle (that is, have no more events to process).</li>
+<li>Send a text string to the {@link android.widget.EditText} by calling
+{@link android.app.Instrumentation#sendStringSync(java.lang.String)
+sendStringSync()} and pass your input string as the parameter.</p>
+</ol>
+<p>For example:</p>
+<pre>
+// Send string input value
+getInstrumentation().runOnMainSync(new Runnable() {
+    &#64;Override
+    public void run() {
+        senderMessageEditText.requestFocus();
+    }
+});
+getInstrumentation().waitForIdleSync();
+getInstrumentation().sendStringSync("Hello Android!");
+getInstrumentation().waitForIdleSync();
+</pre>
+
+
+
+
+
+
+
+
diff --git a/docs/html/training/activity-testing/activity-ui-testing.jd b/docs/html/training/activity-testing/activity-ui-testing.jd
new file mode 100644
index 0000000..644f3ca
--- /dev/null
+++ b/docs/html/training/activity-testing/activity-ui-testing.jd
@@ -0,0 +1,216 @@
+page.title=Testing UI Components
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#testcase">Create a Test Case for UI Testing with Instrumentation</a>
+  <li><a href="#test_method">Add Test Methods to Verify UI Behavior</a>
+     <ol>
+     <li><a href="#verify_button_display">Verify Button Layout Parameters</a></li>
+     <li><a href="#verify_TextView">Verify TextView Layout Parameters</a></li>
+     <li><a href="#verify_button_behavior">Verify Button Behavior</a></li>
+     </ol>
+  </li>
+  <li><a href="#annotations">Apply Test Annotations</a></li>
+</ol>
+
+<h2>Try it out</h2>
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
+class="button">Download the demo</a>
+ <p class="filename">AndroidTestingFun.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Typically, your {@link android.app.Activity} includes user interface
+components (such as buttons, editable text fields, checkboxes, and pickers) to
+allow users to interact with your Android application. This lesson shows how
+you can test an {@link android.app.Activity} with a simple push-button UI. You
+can use the same general steps to test other, more sophisticated types of UI
+components.</p>
+
+<p class="note"><strong>Note:</strong> The type of UI testing in this lesson is
+called <em>white-box testing</em> because you have the
+source code for the application that you want to test. The Android
+<a href="{@docRoot}tools/testing/testing_android.html#Instrumentation">Instrumentation</a>
+framework is suitable for creating white-box tests for UI components within an
+application. An alternative type of UI testing is <em>black-box testing</em>,
+where you may not have access to the application source. This type of testing
+is useful when you want to test how your app interacts with other apps or with
+the system. Black-box testing is not covered in this training. To learn more
+about how to perform black-box testing on your Android apps, see the
+<a href="{@docRoot}tools/testing/testing_ui.html">UI Testing guide</a>.
+<p>For a complete test case example, take a look at
+{@code ClickFunActivityTest.java} in the sample app.</p>
+
+<h2 id="testcase">Create a Test Case for UI Testing with Instrumentation</h2>
+<p>When testing an {@link android.app.Activity} that has a user interface (UI),
+the {@link android.app.Activity} under test runs in the UI thread. However, the
+test application itself runs in a separate thread in the same process as the
+application under test. This means that your test app can reference objects
+from the UI thread, but if it attempts to change properties on those objects or
+send events to the UI thread, you will usually get a {@code WrongThreadException}
+error.</p>
+<p>To safely inject {@link android.content.Intent} objects into your
+{@link android.app.Activity} or run test methods on the UI thread, you can
+extend your test class to use {@link android.test.ActivityInstrumentationTestCase2}.
+To learn more about how to run test methods on the UI thread, see
+<a href="{@docRoot}tools/testing/activity_testing.html#RunOnUIThread">Testing
+on the UI thread</a>.</p>
+
+<h3 id="fixture">Set Up Your Test Fixture</h3>
+<p>When setting up the test fixture for UI testing, you should specify the
+<a href="{@docRoot}guide/topics/ui/ui-events.html#TouchMode">touch mode</a>
+in your {@link junit.framework.TestCase#setUp()} method. Setting the touch mode
+to {@code true} prevents the UI control from taking focus when you click it
+programmatically in the test method later (for example, a button UI will just
+fire its on-click listener). Make sure that you call
+{@link android.test.ActivityInstrumentationTestCase2#setActivityInitialTouchMode(boolean) setActivityInitialTouchMode()}
+before calling {@link android.test.ActivityInstrumentationTestCase2#getActivity()}.
+</p>
+<p>For example:</ap>
+<pre>
+public class ClickFunActivityTest
+        extends ActivityInstrumentationTestCase2<ClickFunActivity> {
+    ...
+    &#64;Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        setActivityInitialTouchMode(true);
+
+        mClickFunActivity = getActivity();
+        mClickMeButton = (Button) 
+                mClickFunActivity
+                .findViewById(R.id.launch_next_activity_button);
+        mInfoTextView = (TextView) 
+                mClickFunActivity.findViewById(R.id.info_text_view);
+    }
+}
+</pre>
+
+<h2 id="test_methods">Add Test Methods to Validate UI Behavior</h2>
+<p id="test_goals">Your UI testing goals might include:</p>
+<ul>
+<li>Verifying that a button is displayed with the correct layout when the
+{@link android.app.Activity} is launched.</li>
+<li>Verifying that a {@link android.widget.TextView} is initially hidden.</li>
+<li>Verifying that a {@link android.widget.TextView} displays the expected string
+when a button is pushed.</li>
+</ul>
+<p>The following section demonstrates how you can implement test methods
+to perform these verifications.</p>
+
+<h3 id="verify_button_display">Verify Button Layout Parameters</h3>
+<p>You might add a test method like this to verify that a button is displayed
+correctly in your {@link android.app.Activity}:</p>
+<pre>
+&#64;MediumTest
+public void testClickMeButton_layout() {
+    final View decorView = mClickFunActivity.getWindow().getDecorView();
+
+    ViewAsserts.assertOnScreen(decorView, mClickMeButton);
+
+    final ViewGroup.LayoutParams layoutParams =
+            mClickMeButton.getLayoutParams();
+    assertNotNull(layoutParams);
+    assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT);
+    assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT);
+}
+</pre>
+
+<p>In the {@link android.test.ViewAsserts#assertOnScreen(android.view.View,android.view.View) assertOnScreen()}
+method call, you should pass in the root view and the view that you are
+expecting to be present on the screen. If the expected view is not found in the
+root view, the assertion method throws an {@link junit.framework.AssertionFailedError}
+exception, otherwise the test passes.</p>
+<p>You can also verify that the layout of a {@link android.widget.Button} is
+correct by getting a reference to its {@link android.view.ViewGroup.LayoutParams}
+object, then call assertion methods to verify that the
+{@link android.widget.Button} object's width and height attributes match the
+expected values.</p>
+<p>The {@code &#64;MediumTest} annotation specifies how the test is categorized,
+relative to its absolute execution time. To learn more about using test size
+annotations, see <a href="#annotations">Apply Test Annotations</a>.</p>
+
+<h3 id="verify_TextView">Verify TextView Layout Parameters</h3>
+<p>You might add a test method like this to verify that a
+{@link android.widget.TextView} initially appears hidden in
+your {@link android.app.Activity}:</p>
+<pre>
+&#64;MediumTest
+public void testInfoTextView_layout() {
+    final View decorView = mClickFunActivity.getWindow().getDecorView();
+    ViewAsserts.assertOnScreen(decorView, mInfoTextView);
+    assertTrue(View.GONE == mInfoTextView.getVisibility());
+}
+</pre>
+<p>You can call {@link android.view.Window#getDecorView()} to get a reference
+to the decor view for the {@link android.app.Activity}. The decor view is the
+top-level ViewGroup ({@link android.widget.FrameLayout}) view in the layout
+hierarchy.</p>
+
+<h3 id="verify_button_behavior">Verify Button Behavior</h3>
+<p>You can use a test method like this to verify that a
+{@link android.widget.TextView} becomes visible when a
+{@link android.widget.Button} is pushed:</p>
+
+<pre>
+&#64;MediumTest
+public void testClickMeButton_clickButtonAndExpectInfoText() {
+    String expectedInfoText = mClickFunActivity.getString(R.string.info_text);
+    TouchUtils.clickView(this, mClickMeButton);
+    assertTrue(View.VISIBLE == mInfoTextView.getVisibility());
+    assertEquals(expectedInfoText, mInfoTextView.getText());
+}
+</pre>
+
+<p>To programmatically click a {@link android.widget.Button} in your
+test, call {@link android.test.TouchUtils#clickView(android.test.InstrumentationTestCase,android.view.View) clickView()}.
+You must pass in a reference to the test case that is being run and a reference
+to the {@link android.widget.Button} to manipulate.</p>
+
+<p class="note"><strong>Note: </strong>The {@link android.test.TouchUtils}
+helper class provides convenience methods for simulating touch interactions
+with your application. You can use these methods to simulate clicking, tapping,
+and dragging of Views or the application screen.</p>
+<p class="caution"><strong>Caution: </strong>The {@link android.test.TouchUtils}
+methods are designed to send events to the UI thread safely from the test thread.
+You should not run {@link android.test.TouchUtils} directly in the UI thread or
+any test method annotated with {@code &#64;UIThread}. Doing so might
+raise the {@code WrongThreadException}.</p>
+
+<h2 id="annotations">Apply Test Annotations</h2>
+<p>The following annotations can be applied to indicate the size of a test
+method:</p>
+<dl>
+<dt>{@link
+android.test.suitebuilder.annotation.SmallTest &#64;SmallTest}</dt>
+<dd>Marks a test that should run as part of the small tests.</dd>
+<dt>{@link
+android.test.suitebuilder.annotation.MediumTest &#64;MediumTest}</dt>
+<dd>Marks a test that should run as part of the medium tests.</dd>
+<dt>{@link android.test.suitebuilder.annotation.LargeTest &#64;LargeTest}</dt>
+<dd>Marks a test that should run as part of the large tests.</dd>
+</dl>
+<p>Typically, a short running test that take only a few milliseconds should be
+marked as a {@code &#64;SmallTest}. Longer running tests (100 milliseconds or
+more) are usually marked as {@code &#64;MediumTest}s or {@code &#64;LargeTest}s,
+depending on whether the test accesses resources on the local system only or
+remote resources over a network. For guidance on using test size annotations,
+see this <a href="https://plus.sandbox.google.com/+AndroidDevelopers/posts/TPy1EeSaSg8">Android Tools Protip</a>.</p>
+<p>You can mark up your test methods with other test annotations to control
+how the tests are organized and run. For more information on other annotations,
+see the {@link java.lang.annotation.Annotation} class reference.</p>
+
+
+
+
diff --git a/docs/html/training/activity-testing/activity-unit-testing.jd b/docs/html/training/activity-testing/activity-unit-testing.jd
new file mode 100644
index 0000000..74dcda9
--- /dev/null
+++ b/docs/html/training/activity-testing/activity-unit-testing.jd
@@ -0,0 +1,134 @@
+page.title=Creating Unit Tests
+trainingnavtop=true
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#testcase">Create a Test Case for Activity Unit Testing</a>
+  <li><a href="#test_method">Validate Launch of Another Activity</a>
+</ol>
+
+<h2>Try it out</h2>
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
+class="button">Download the demo</a>
+ <p class="filename">AndroidTestingFun.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>An {@link android.app.Activity} unit test is an excellent way to quickly
+verify the state of an {@link android.app.Activity} and its interactions with
+other components in isolation (that is, disconnected from the rest of the
+system). A unit test generally tests the smallest possible unit of code
+(which could be a method, class, or component), without dependencies on system
+or network resources. For example, you can write a unit test to check
+that an {@link android.app.Activity} has the correct layout or that it
+triggers an {@link android.content.Intent} object correctly.</p>
+<p>Unit tests are generally not suitable for testing complex UI interaction
+events with the system. Instead, you should use
+the {@link android.test.ActivityInstrumentationTestCase2} class, as described
+in <a href="activity-ui-testing.html">Testing UI Components</a>.</p>
+<p>This lesson shows how you can write a unit test to verify that an
+{@link android.content.Intent} is triggered to launch another
+{@link android.app.Activity}.
+Since the test runs in an isolated environment, the
+{@link android.content.Intent}
+is not actually sent to the Android system, but you can inspect that the
+{@link android.content.Intent} object's payload data is accurate.</p>
+<p>For a complete test case example, take a look at
+{@code LaunchActivityTest.java} in the sample app.</p>
+
+<p class="note"><strong>Note: </strong>To test against system or external
+dependencies, you can use mock objects from a mocking
+framework and inject them into your unit tests. To learn more about the mocking
+framework provided by Android, see
+<a href="{@docRoot}tools/testing/testing_android.html#MockObjectClasses}">Mock
+Object Classes</a>.</p>
+
+<h2 id="testcase">Create a Test Case for Activity Unit Testing</h2>
+<p>The {@link android.test.ActivityUnitTestCase} class provides support for
+isolated testing of a single {@link android.app.Activity}. To create a unit
+test for your {@link android.app.Activity}, your test class should extend
+{@link android.test.ActivityUnitTestCase}.</p>
+
+<p>The {@link android.app.Activity} in an {@link android.test.ActivityUnitTestCase}
+is not automatically started by Android Instrumentation. To start the
+{@link android.app.Activity} in isolation, you need to explicitly call the
+{@link android.test.ActivityUnitTestCase#startActivity(android.content.Intent, android.os.Bundle, java.lang.Object) startActivity()}
+method, and pass in the {@link android.content.Intent} to
+launch your target {@link android.app.Activity}.</p>
+
+<p>For example:</p>
+<pre>
+public class LaunchActivityTest
+        extends ActivityUnitTestCase&lt;LaunchActivity&gt; {
+    ...
+
+    &#64;Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mLaunchIntent = new Intent(getInstrumentation()
+                .getTargetContext(), LaunchActivity.class);
+        startActivity(mLaunchIntent, null, null);
+        final Button launchNextButton =
+                (Button) getActivity()
+                .findViewById(R.id.launch_next_activity_button);
+    }
+}
+</pre>
+
+<h2 id="test_method">Validate Launch of Another Activity</h2>
+<p id="test_goals">Your unit testing goals might include:</p>
+<ul>
+<li>Verifying that {@code LaunchActivity} fires an
+{@link android.content.Intent} when a button is pushed clicked.</li>
+<li>Verifying that the launched {@link android.content.Intent} contains the
+correct payload data.</li>
+</ul>
+
+<p>To verify if an {@link android.content.Intent} was triggered
+following the {@link android.widget.Button} click, you can use the
+{@link android.test.ActivityUnitTestCase#getStartedActivityIntent()} method.
+By using assertion methods, you can verify that the returned
+{@link android.content.Intent} is not null, and that it contains the expected
+string value to launch the next {@link android.app.Activity}. If both assertions
+evaluate to {@code true}, you've successfully verified that the
+{@link android.content.Intent} was correctly sent by your
+{@link android.app.Activity}.</p>
+
+<p>You might implement your test method like this:</p>
+<pre>
+&#64;MediumTest
+public void testNextActivityWasLaunchedWithIntent() {
+    startActivity(mLaunchIntent, null, null);
+    final Button launchNextButton =
+            (Button) getActivity()
+            .findViewById(R.id.launch_next_activity_button);
+    launchNextButton.performClick();
+
+    final Intent launchIntent = getStartedActivityIntent();
+    assertNotNull("Intent was null", launchIntent);
+    assertTrue(isFinishCalled());
+
+    final String payload =
+            launchIntent.getStringExtra(NextActivity.EXTRAS_PAYLOAD_KEY);
+    assertEquals("Payload is empty", LaunchActivity.STRING_PAYLOAD, payload);
+}
+</pre>
+<p>Because {@code LaunchActivity} runs in isolation, you cannot use the
+{@link android.test.TouchUtils} library to manipulate UI controls. To directly
+click a {@link android.widget.Button}, you can call the
+{@link android.view.View#performClick()} method instead.</p>
+
+
+
+
+
+
+
diff --git a/docs/html/training/activity-testing/index.jd b/docs/html/training/activity-testing/index.jd
new file mode 100644
index 0000000..ddede71
--- /dev/null
+++ b/docs/html/training/activity-testing/index.jd
@@ -0,0 +1,68 @@
+page.title=Testing Your Android Activity
+page.tags="testing"
+
+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.2 (API Level 8) or higher.</li>
+</ul>
+
+<h2>You Should Also Read</h2>
+<ul>
+<li><a href="{@docRoot}tools/testing/index.html">Testing
+(Developer's Guide)</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>You should be writing and running tests as part of your Android application
+development cycle. Well-written tests can help you to catch bugs early in
+development and give you confidence in your code.</p>
+
+<p>A <em>test case</em> defines a set of objects and methods to run multiple
+tests independently from each other. Test cases can be organized into
+<em>test suites</em> and run programmatically, in a repeatable manner, with
+a <em>test runner</em> provided by a testing framework.</p>
+
+<p>The lessons in this class teaches you how to use the Android's custom
+testing framework that is based on the popular JUnit framework. You can
+write test cases to verify specific behavior in your application, and check for
+consistency across different Android devices. Your test cases also serve as a
+form of internal code documentation by describing the expected behavior of
+app components.</p>
+
+<h2>Lessons</h2>
+
+<!-- Create a list of the lessons in this class along with a short description
+of each lesson. These should be short and to the point. It should be clear from
+reading the summary whether someone will want to jump to a lesson or not.-->
+
+<dl>
+  <dt><b><a href="preparing-activity-testing.html">Setting Up Your Test
+Environment</a></b></dt>
+    <dd>Learn how to create your test project.</dd>
+  <dt><b><a href="activity-basic-testing.html">Creating and Running a Test 
+Case</a></b></dt>
+    <dd>Learn how to write test cases to verify the
+expected properties of your {@link android.app.Activity}, and run the test
+cases with the {@code Instrumentation} test runner provided by the Android
+framework.</dd>
+  <dt><b><a href="activity-ui-testing.html">Testing UI Components</a></b></dt>
+    <dd>Learn how to test the behavior of specific UI
+components in your {@link android.app.Activity}.</dd>
+  <dt><b><a href="activity-unit-testing.html">Creating Unit Tests</a></b></dt>
+    <dd>Learn how to how to perform unit testing to
+verify the behavior of an Activity in isolation.</dd>
+  <dt><b><a href="activity-functional-testing.html">Creating Functional Tests</a></b></dt>
+    <dd>Learn how to perform functional testing to
+verify the interaction of multiple Activities.</dd>
+
diff --git a/docs/html/training/activity-testing/preparing-activity-testing.jd b/docs/html/training/activity-testing/preparing-activity-testing.jd
new file mode 100644
index 0000000..c43c9ed
--- /dev/null
+++ b/docs/html/training/activity-testing/preparing-activity-testing.jd
@@ -0,0 +1,95 @@
+page.title=Setting Up Your Test Environment
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#eclipse">Set Up Eclipse for Testing</a></li>
+  <li><a href="#cmdline">Set Up the Command Line Interface for Testing</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+<li><a href="{@docRoot}sdk/index.html">Getting the SDK Bundle</a></li>
+<li><a href="{@docRoot}tools/testing/testing_eclipse.html">Testing from Eclipse
+with ADT</a></li>
+<li><a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other
+IDEs</a></li>
+</ul>
+
+<h2>Try it out</h2>
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
+class="button">Download the demo</a>
+ <p class="filename">AndroidTestingFun.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Before you start writing and running your tests, you should set up your test
+development environment. This lesson teaches you how to set up the Eclipse
+IDE to build and run tests, and how to
+build and run tests with the Gradle framework by using the command line
+interface.</p>
+
+<p class="note"><strong>Note:</strong> To help you get started, the lessons are
+based on Eclipse with the ADT plugin. However, for your own test development, you
+are free to use the IDE of your choice or the command-line.</p>
+
+<h2 id="eclipse">Set Up Eclipse for Testing</h2>
+<p>Eclipse with the Android Developer Tools (ADT) plugin provides an integrated
+development environment for you to create, build, and run Android application
+test cases from a graphical user interface (GUI). A convenient feature that
+Eclipse provides is the ability to auto-generate a new test project that
+corresponds with your Android application project</a>.
+
+<p>To set up your test environment in Eclipse:</p>
+
+<ol>
+<li><a href="{@docRoot}sdk/installing/bundle.html">Download and install the
+Eclipse ADT plugin</a>, if you haven’t installed it yet.</li>
+<li>Import or create the Android application project that you want to test
+against.</li>
+<li>Generate a test project that corresponds to the application project under
+test. To generate a test project for the app project that you imported:</p>
+   <ol type="a">
+   <li>In the Package Explorer, right-click on your app project, then
+select <strong>Android Tools</strong> &gt; <strong>New Test Project</strong>.</li>
+   <li>In the New Android Test Project wizard, set the property
+values for your test project then click <strong>Finish</strong>.</li>
+   </ol>
+</li>
+</ol>
+<p>You should now be able to create, build, and run test
+cases from your Eclipse environment. To learn how to perform these tasks in
+Eclipse, proceed to <a href="activity-basic-testing.html">Creating and Running 
+a Test Case</a>.</p>
+
+<h2 id="cmdline">Set Up the Command Line Interface for Testing</h2>
+<p>If you are using Gradle version 1.6 or higher as your build environment, you
+can build and run your Android application tests from the command line by using
+the Gradle Wrapper. Make sure that in your {@code gradle.build} file, the
+<a href={@docRoot}guide/topics/manifest/uses-sdk-element.html#min>minSdkVersion</a>
+attribute in the {@code defaultConfig} section is set to 8 or higher. You can
+refer to the sample {@code gradle.build} file that is
+included in the download bundle for this training class.</p>
+<p>To run your tests with the Gradle Wrapper:</p>
+<ol>
+   <li>Connect a physical Android device to your machine or launch the Android
+Emulator.</li>
+   <li>Run the following command from your project directory:
+      <pre>./gradlew build connectedCheck</pre>
+   </li>
+</ol>
+<p>To learn more about using Gradle for Android testing, see the
+<a href="//tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing">Gradle Plugin User Guide</a>.</p>
+<p>To learn more about using command line tools other than Gradle for test
+development, see
+<a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other IDEs</a>.</p>
+
diff --git a/docs/html/training/animation/crossfade.jd b/docs/html/training/animation/crossfade.jd
index 2fbb6c0..7e947f3 100644
--- a/docs/html/training/animation/crossfade.jd
+++ b/docs/html/training/animation/crossfade.jd
@@ -205,13 +205,13 @@
     // Animate the loading view to 0% opacity. After the animation ends,
     // set its visibility to GONE as an optimization step (it won't
     // participate in layout passes, etc.)
-    mHideView.animate()
+    mLoadingView.animate()
             .alpha(0f)
             .setDuration(mShortAnimationDuration)
             .setListener(new AnimatorListenerAdapter() {
                 &#64;Override
                 public void onAnimationEnd(Animator animation) {
-                    mHideView.setVisibility(View.GONE);
+                    mLoadingView.setVisibility(View.GONE);
                 }
             });
 }
diff --git a/docs/html/training/articles/security-ssl.jd b/docs/html/training/articles/security-ssl.jd
index d3f68e2..f52865a 100644
--- a/docs/html/training/articles/security-ssl.jd
+++ b/docs/html/training/articles/security-ssl.jd
@@ -250,7 +250,7 @@
 This is similar to an unknown certificate authority, so you can use the
 same approach from the previous section.</p>
 
-<p>You can create yout own {@link javax.net.ssl.TrustManager},
+<p>You can create your own {@link javax.net.ssl.TrustManager},
 this time trusting the server certificate directly. This has all of the
 downsides discussed earlier of tying your app directly to a certificate, but can be done
 securely. However, you should be careful to make sure your self-signed certificate has a
diff --git a/docs/html/training/articles/smp.jd b/docs/html/training/articles/smp.jd
index 0f667d7..7240eec 100644
--- a/docs/html/training/articles/smp.jd
+++ b/docs/html/training/articles/smp.jd
@@ -1057,7 +1057,7 @@
 fix them.  Before we do that, we need to discuss the use of a basic language
 feature.</p>
 
-<h4 id="volatile">C/C+++ and "volatile"</h4>
+<h4 id="volatile">C/C++ and "volatile"</h4>
 
 <p>When writing single-threaded code, declaring a variable “volatile” can be
 very useful.  The compiler will not omit or reorder accesses to volatile
diff --git a/docs/html/training/basics/actionbar/adding-buttons.jd b/docs/html/training/basics/actionbar/adding-buttons.jd
index 5fb0d59..26c9d0e 100644
--- a/docs/html/training/basics/actionbar/adding-buttons.jd
+++ b/docs/html/training/basics/actionbar/adding-buttons.jd
@@ -74,7 +74,21 @@
 Settings action should always appear in the overflow. (By default, all actions appear in the
 overflow, but it's good practice to explicitly declare your design intentions for each action.)
 
-<p>However, <strong>if your app is using the Support Library</strong> for compatibility on versions
+<p>The {@code icon} attribute requires a resource ID for an
+image. The name that follows {@code &#64;drawable/} must be the name of a bitmap image you've
+saved in your project's {@code res/drawable/} directory. For example,
+{@code "&#64;drawable/ic_action_search"} refers to {@code ic_action_search.png}.
+Likewise, the {@code title} attribute uses a string resource that's defined by an XML
+file in your project's {@code res/values/} directory, as discussed in <a
+href="{@docRoot}training/basics/firstapp/building-ui.html#Strings">Building a Simple User
+Interface</a>.
+
+<p class="note"><strong>Note:</strong> When creating icons and other bitmap images for your app,
+it's important that you provide multiple versions that are each optimized for a different screen
+density. This is discussed more in the lesson about <a
+href="{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different Screens</a>.
+
+<p><strong>If your app is using the Support Library</strong> for compatibility on versions
 as low as Android 2.1, the {@code showAsAction} attribute is not available from
 the {@code android:} namespace. Instead this attribute is provided by the Support Library
 and you must define your own XML namespace and use that namespace as the attribute prefix.
diff --git a/docs/html/training/basics/actionbar/styling.jd b/docs/html/training/basics/actionbar/styling.jd
index a1cc10c..1f76e03 100644
--- a/docs/html/training/basics/actionbar/styling.jd
+++ b/docs/html/training/basics/actionbar/styling.jd
@@ -20,7 +20,7 @@
 <ul>
   <li><a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a></li>
   <li><a class="external-link" target="_blank"
-  href="http://jgilfelt.github.io/android-actionbarstylegenerator/">Android Action Bar Style
+  href="http://www.actionbarstylegenerator.com">Android Action Bar Style
   Generator</a></li>
 </ul>
 
@@ -146,13 +146,13 @@
     &lt;style name="CustomActionBarTheme"
            parent="&#64;style/Theme.Holo.Light.DarkActionBar">
         &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar styles -->
     &lt;style name="MyActionBar"
            parent="&#64;style/Widget.Holo.Light.ActionBar.Solid.Inverse">
         &lt;item name="android:background">&#64;drawable/actionbar_background&lt;/item>
-    &lt;style>
+    &lt;/style>
 &lt;/resources>
 </pre>
 
@@ -178,7 +178,7 @@
 
         &lt;!-- Support library compatibility -->
         &lt;item name="actionBarStyle">&#64;style/MyActionBar&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar styles -->
     &lt;style name="MyActionBar"
@@ -187,7 +187,7 @@
 
         &lt;!-- Support library compatibility -->
         &lt;item name="background">&#64;drawable/actionbar_background&lt;/item>
-    &lt;style>
+    &lt;/style>
 &lt;/resources>
 </pre>
 
@@ -236,25 +236,25 @@
         &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
         &lt;item name="android:actionBarTabTextStyle">&#64;style/MyActionBarTabText&lt;/item>
         &lt;item name="android:actionMenuTextColor">&#64;color/actionbar_text&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar styles -->
     &lt;style name="MyActionBar"
            parent="&#64;style/Widget.Holo.ActionBar">
         &lt;item name="android:titleTextStyle">&#64;style/MyActionBarTitleText&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar title text -->
     &lt;style name="MyActionBarTitleText"
            parent="&#64;style/TextAppearance.Holo.Widget.ActionBar.Title">
         &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar tabs text styles -->
     &lt;style name="MyActionBarTabText"
            parent="&#64;style/Widget.Holo.ActionBar.TabText">
         &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
-    &lt;style>
+    &lt;/style>
 &lt;/resources>
 </pre>
 
@@ -280,7 +280,7 @@
         &lt;item name="actionBarStyle">&#64;style/MyActionBar&lt;/item>
         &lt;item name="actionBarTabTextStyle">&#64;style/MyActionBarTabText&lt;/item>
         &lt;item name="actionMenuTextColor">&#64;color/actionbar_text&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar styles -->
     &lt;style name="MyActionBar"
@@ -289,21 +289,21 @@
 
         &lt;!-- Support library compatibility -->
         &lt;item name="titleTextStyle">&#64;style/MyActionBarTitleText&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar title text -->
     &lt;style name="MyActionBarTitleText"
            parent="&#64;style/TextAppearance.<strong>AppCompat</strong>.Widget.ActionBar.Title">
         &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
         &lt;!-- The textColor property is backward compatible with the Support Library -->
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar tabs text -->
     &lt;style name="MyActionBarTabText"
            parent="&#64;style/Widget.<strong>AppCompat</strong>.ActionBar.TabText">
         &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
         &lt;!-- The textColor property is backward compatible with the Support Library -->
-    &lt;style>
+    &lt;/style>
 &lt;/resources>
 </pre>
 
@@ -392,14 +392,14 @@
     &lt;style name="CustomActionBarTheme"
            parent="&#64;style/Theme.Holo">
         &lt;item name="android:actionBarTabStyle">&#64;style/MyActionBarTabs&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar tabs styles -->
     &lt;style name="MyActionBarTabs"
            parent="&#64;style/Widget.Holo.ActionBar.TabView">
         &lt;!-- tab indicator -->
         &lt;item name="android:background">&#64;drawable/actionbar_tab_indicator&lt;/item>
-    &lt;style>
+    &lt;/style>
 &lt;/resources>
 </pre>
 
@@ -420,7 +420,7 @@
 
         &lt;!-- Support library compatibility -->
         &lt;item name="actionBarTabStyle">&#64;style/MyActionBarTabs&lt;/item>
-    &lt;style>
+    &lt;/style>
 
     &lt;!-- ActionBar tabs styles -->
     &lt;style name="MyActionBarTabs"
@@ -430,7 +430,7 @@
 
         &lt;!-- Support library compatibility -->
         &lt;item name="background">&#64;drawable/actionbar_tab_indicator&lt;/item>
-    &lt;style>
+    &lt;/style>
 &lt;/resources>
 </pre>
 
@@ -442,7 +442,7 @@
   href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> guide.</li>
   <li>For even more complete styling for the action bar,
 try the <a class="external-link" target="_blank"
-  href="www://http.actionbarstylegenerator.com">Android Action Bar Style
+  href="http://www.actionbarstylegenerator.com">Android Action Bar Style
   Generator</a>.</li>
 </ul>
 </div>
\ No newline at end of file
diff --git a/docs/html/training/basics/activity-lifecycle/starting.jd b/docs/html/training/basics/activity-lifecycle/starting.jd
index dce6e30..9046599 100644
--- a/docs/html/training/basics/activity-lifecycle/starting.jd
+++ b/docs/html/training/basics/activity-lifecycle/starting.jd
@@ -220,7 +220,7 @@
 </pre>
 
 <p class="caution"><strong>Caution:</strong> Using the {@link android.os.Build.VERSION#SDK_INT} to
-prevent older system's from executing new APIs works in this way on Android 2.0 (API level
+prevent older systems from executing new APIs works in this way on Android 2.0 (API level
 5) and higher only. Older versions will encounter a runtime exception.</p>
 
 <p>Once the {@link android.app.Activity#onCreate onCreate()} finishes execution, the system
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 6f7fa5d..712eabc 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -426,10 +426,7 @@
 
 <p>That's it, you've built your first Android app!</p>
 
-<p>To learn more about building Android apps, continue to follow the
-basic training classes. The next class is <a
-href="{@docRoot}training/basics/activity-lifecycle/index.html">Managing the Activity
-Lifecycle</a>.</p>
+<p>To learn more, follow the link below to the next class.</p>
 
 
 
diff --git a/docs/html/training/basics/supporting-devices/screens.jd b/docs/html/training/basics/supporting-devices/screens.jd
index 1114f21..e52ee70 100644
--- a/docs/html/training/basics/supporting-devices/screens.jd
+++ b/docs/html/training/basics/supporting-devices/screens.jd
@@ -23,8 +23,8 @@
     <ul>
       <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple
 Screens</a></li>
-      <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-Screens</a></li>
+      <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing
+        Resources</a></li>
       <li><a href="{@docRoot}design/style/iconography.html">Iconography design guide</a></li>
     </ul>
   </div>
diff --git a/docs/html/training/best-background.jd b/docs/html/training/best-background.jd
new file mode 100644
index 0000000..917eabb
--- /dev/null
+++ b/docs/html/training/best-background.jd
@@ -0,0 +1,8 @@
+page.title=Best Practices for Background Jobs
+page.trainingcourse=true
+
+@jd:body
+
+
+<p>These classes show you how to run jobs in the background to boost your
+application's performance and minimize its drain on the battery.</p>
diff --git a/docs/html/training/connect-devices-wirelessly/index.jd b/docs/html/training/connect-devices-wirelessly/index.jd
index f27b9c3..db79abe 100644
--- a/docs/html/training/connect-devices-wirelessly/index.jd
+++ b/docs/html/training/connect-devices-wirelessly/index.jd
@@ -17,7 +17,7 @@
 
 <h2>You should also read</h2>
 <ul>
-  <li><a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi Direct</a></li>
+  <li><a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi P2P</a></li>
 </ul>
 
 
@@ -37,8 +37,8 @@
 <p>This class describes the key APIs for finding and
 connecting to other devices from your application.  Specifically, it
 describes the NSD API for discovering available services and the Wi-Fi
-Direct&trade; API for doing peer-to-peer wireless connections.  This class also
-shows you how to use NSD and Wi-Fi Direct in
+Peer-to-Peer (P2P) API for doing peer-to-peer wireless connections.  This class also
+shows you how to use NSD and Wi-Fi P2P in
 combination to detect the services offered by a device and connect to the
 device when neither device is connected to a network.
 </p>
@@ -49,13 +49,13 @@
   <dd>Learn how to broadcast services offered by your own application, discover
   services offered on the local network, and use NSD to determine the connection
   details for the service you wish to connect to.</dd>
-  <dt><strong><a href="wifi-direct.html">Connecting with Wi-Fi Direct</a></strong></dt>
+  <dt><strong><a href="wifi-direct.html">Creating P2P Connections with Wi-Fi</a></strong></dt>
   <dd>Learn how to fetch a list of nearby peer devices, create an access point
-  for legacy devices, and connect to other devices capable of Wi-Fi Direct
+  for legacy devices, and connect to other devices capable of Wi-Fi P2P
   connections.</dd>
-  <dt><strong><a href="nsd-wifi-direct.html">Using Wi-Fi Direct for Service
+  <dt><strong><a href="nsd-wifi-direct.html">Using Wi-Fi P2P for Service
       Discovery</a></strong></dt>
   <dd>Learn how to discover services published by nearby devices without being
-  on the same network, using Wi-Fi Direct.</dd>
+  on the same network, using Wi-Fi P2P.</dd>
 </dl>
 
diff --git a/docs/html/training/connect-devices-wirelessly/nsd-wifi-direct.jd b/docs/html/training/connect-devices-wirelessly/nsd-wifi-direct.jd
index 5e276de..5c1321e 100644
--- a/docs/html/training/connect-devices-wirelessly/nsd-wifi-direct.jd
+++ b/docs/html/training/connect-devices-wirelessly/nsd-wifi-direct.jd
@@ -1,7 +1,4 @@
-page.title=Using Wi-Fi Direct for Service Discovery
-parent.title=Connecting Devices Wirelessly
-parent.link=index.html
-
+page.title=Using Wi-Fi P2P for Service Discovery
 trainingnavtop=true
 
 @jd:body
@@ -26,23 +23,23 @@
 <p>The first lesson in this class, <a href="nsd.html">Using Network Service
   Discovery</a>, showed you
 how to discover services that are connected to a local network. However, using
-Wi-Fi Direct&trad; Service Discovery allows you to discover the services of nearby devices directly,
-without being connected to a network.  You can also advertise the services
+Wi-Fi Peer-to-Peer (P2P) Service Discovery allows you to discover the services of nearby devices
+directly, without being connected to a network.  You can also advertise the services
 running on your device.  These capabilities help you communicate between apps,
 even when no local network or hotspot is available.</p>
 <p>While this set of APIs is similar in purpose to the Network Service Discovery
 APIs outlined in a previous lesson, implementing them in code is very different.
 This lesson shows you how to discover services available from other devices,
-using Wi-Fi Direct&trade;. The lesson assumes that you're already familiar with the
-<a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi Direct</a> API.</p>
+using Wi-Fi P2P. The lesson assumes that you're already familiar with the
+<a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi P2P</a> API.</p>
 
 
 <h2 id="manifest">Set Up the Manifest</h2>
-<p>In order to use Wi-Fi Direct, add the {@link
+<p>In order to use Wi-Fi P2P, add the {@link
 android.Manifest.permission#CHANGE_WIFI_STATE}, {@link
 android.Manifest.permission#ACCESS_WIFI_STATE},
 and {@link android.Manifest.permission#INTERNET}
-permissions to your manifest.  Even though Wi-Fi Direct doesn't require an
+permissions to your manifest.  Even though Wi-Fi P2P doesn't require an
 Internet connection, it uses standard Java sockets, and using these in Android
 requires the requested permissions.</p>
 
@@ -244,7 +241,7 @@
 and what they mean</p>
 <dl>
   <dt> {@link android.net.wifi.p2p.WifiP2pManager#P2P_UNSUPPORTED}</dt>
-  <dd> Wi-Fi Direct isn't supported on the device running the app.</dd>
+  <dd> Wi-Fi P2P isn't supported on the device running the app.</dd>
   <dt> {@link android.net.wifi.p2p.WifiP2pManager#BUSY}</dt>
   <dd> The system is to busy to process the request.</dd>
   <dt> {@link android.net.wifi.p2p.WifiP2pManager#ERROR}</dt>
diff --git a/docs/html/training/connect-devices-wirelessly/nsd.jd b/docs/html/training/connect-devices-wirelessly/nsd.jd
index 30f5c49..e07e2af 100644
--- a/docs/html/training/connect-devices-wirelessly/nsd.jd
+++ b/docs/html/training/connect-devices-wirelessly/nsd.jd
@@ -1,10 +1,6 @@
 page.title=Using Network Service Discovery
-parent.title=Connecting Devices Wirelessly
-parent.link=index.html
 
 trainingnavtop=true
-next.title=Connecting with Wi-Fi Direct
-next.link=wifi-direct.html
 
 @jd:body
 
diff --git a/docs/html/training/connect-devices-wirelessly/wifi-direct.jd b/docs/html/training/connect-devices-wirelessly/wifi-direct.jd
index b8ed664..d67ed23 100644
--- a/docs/html/training/connect-devices-wirelessly/wifi-direct.jd
+++ b/docs/html/training/connect-devices-wirelessly/wifi-direct.jd
@@ -1,12 +1,6 @@
-page.title=Connecting with Wi-Fi Direct
-parent.title=Connecting Devices Wirelessly
-parent.link=index.html
+page.title=Creating P2P Connections with Wi-Fi
 
 trainingnavtop=true
-previous.title=Using Network Service Discovery
-previous.link=nsd.html
-next.title=Service Discovery with Wi-Fi Direct
-next.link=nsd-wifi-direct.html
 
 @jd:body
 
@@ -21,25 +15,32 @@
       <li><a href="#fetch">Fetch the List of Peers</a></li>
       <li><a href="#connect">Connect to a Peer</a></li>
     </ol>
+    <h2>You should also read</h2>
+    <ul>
+      <li><a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi Peer-to-Peer</a></li>
+    </ul>
   </div>
 </div>
 
-<p>The Wi-Fi Direct&trade; APIs allow applications to connect to nearby devices without
-needing to connect to a network or hotspot.  This allows your application to quickly
+<p>The Wi-Fi peer-to-peer (P2P) APIs allow applications to connect to nearby devices without
+needing to connect to a network or hotspot (Android's Wi-Fi P2P framework complies with the
+<a href="http://www.wi-fi.org/discover-and-learn/wi-fi-direct"
+ class="external-link">Wi-Fi Direct&trade;</a> certification program).
+ Wi-Fi P2P allows your application to quickly
 find and interact with nearby devices, at a range beyond the capabilities of Bluetooth.
 </p>
 <p>
-This lesson shows you how to find and connect to nearby devices using Wi-Fi Direct.
+This lesson shows you how to find and connect to nearby devices using Wi-Fi P2P.
 </p>
 <h2 id="permissions">Set Up Application Permissions</h2>
-<p>In order to use Wi-Fi Direct, add the {@link
+<p>In order to use Wi-Fi P2P, add the {@link
 android.Manifest.permission#CHANGE_WIFI_STATE}, {@link
 android.Manifest.permission#ACCESS_WIFI_STATE},
 and {@link android.Manifest.permission#INTERNET}
-permissions to your manifest.   Wi-Fi Direct doesn't require an internet connection,
+permissions to your manifest.   Wi-Fi P2P doesn't require an internet connection,
 but it does use standard Java sockets, which require the {@link
 android.Manifest.permission#INTERNET} permission.
-So you need the following permissions to use Wi-Fi Direct.</p>
+So you need the following permissions to use Wi-Fi P2P.</p>
 
 <pre>
 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -59,13 +60,13 @@
 </pre>
 
 <h2 id="receiver">Set Up a Broadcast Receiver and Peer-to-Peer Manager</h2>
-<p>To use Wi-Fi Direct, you need to listen for broadcast intents that tell your
+<p>To use Wi-Fi P2P, you need to listen for broadcast intents that tell your
 application when certain events have occurred.  In your application, instantiate
 an {@link
 android.content.IntentFilter} and set it to listen for the following:</p>
 <dl>
   <dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION}</dt>
-  <dd>Indicates whether Wi-Fi Peer-To-Peer (P2P) is enabled</dd>
+  <dd>Indicates whether Wi-Fi P2P is enabled</dd>
   <dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION}</dt>
   <dd>Indicates that the available peer list has changed.</dd>
   <dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION}</dt>
@@ -80,7 +81,7 @@
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
 
-    //  Indicates a change in the Wi-Fi Peer-to-Peer status.
+    //  Indicates a change in the Wi-Fi P2P status.
     intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
 
     // Indicates a change in the list of available peers.
@@ -101,7 +102,7 @@
 android.net.wifi.p2p.WifiP2pManager#initialize(Context, Looper, WifiP2pManager.ChannelListener) initialize()}
 method.  This method returns a {@link
 android.net.wifi.p2p.WifiP2pManager.Channel} object, which you'll use later to
-connect your app to the Wi-Fi Direct Framework.</p>
+connect your app to the Wi-Fi P2P framework.</p>
 
 <pre>
 &#64;Override
@@ -126,7 +127,7 @@
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
         if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
-            // Determine if Wifi Direct mode is enabled or not, alert
+            // Determine if Wifi P2P mode is enabled or not, alert
             // the Activity.
             int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
             if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
@@ -177,7 +178,7 @@
 
 
 <h2 id="discover">Initiate Peer Discovery</h2>
-<p>To start searching for nearby devices with Wi-Fi Direct, call {@link
+<p>To start searching for nearby devices with Wi-Fi P2P, call {@link
 android.net.wifi.p2p.WifiP2pManager#discoverPeers(WifiP2pManager.Channel,
 WifiP2pManager.ActionListener) discoverPeers()}.  This method takes the
 following arguments:</p>
@@ -218,7 +219,7 @@
 <h2 id="fetch">Fetch the List of Peers</h2>
 <p>Now write the code that fetches and processes the list of peers.  First
 implement the {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener}
-interface, which provides information about the peers that Wi-Fi Direct has
+interface, which provides information about the peers that Wi-Fi P2P has
 detected.  The following code snippet illustrates this.</p>
 
 <pre>
diff --git a/docs/html/training/id-auth/authenticate.jd b/docs/html/training/id-auth/authenticate.jd
index 3084bea..65dbc39 100644
--- a/docs/html/training/id-auth/authenticate.jd
+++ b/docs/html/training/id-auth/authenticate.jd
@@ -79,7 +79,7 @@
 
 <p>To get an auth token you first need to request the
 {@link android.Manifest.permission#ACCOUNT_MANAGER}
-to yourmanifest file. To actually do anything useful with the
+to your manifest file. To actually do anything useful with the
 token, you'll also need to add the {@link android.Manifest.permission#INTERNET}
 permission.</p>
 
diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd
index d4a6f7a..2b31bdd 100644
--- a/docs/html/training/id-auth/identify.jd
+++ b/docs/html/training/id-auth/identify.jd
@@ -13,7 +13,7 @@
   <div id="tb">
 <h2>This lesson teaches you to</h2>
 <ol>
-  <li><a href="#ForYou">Determine if AccountManager for You</a></li>
+  <li><a href="#ForYou">Determine if AccountManager is for You</a></li>
   <li><a href="#TaskTwo">Decide What Type of Account to Use</a></li>
   <li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li>
   <li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li>
@@ -41,7 +41,7 @@
 </ul>
 
 
-<h2 id="ForYou">Determine if AccountManager for You</h2>
+<h2 id="ForYou">Determine if AccountManager is for You</h2>
 
 <p>Applications typically try to remember the user using one of three techniques:</p>
 <ol type="a">
diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
index 2b5e4f8..9a94810 100644
--- a/docs/html/training/implementing-navigation/nav-drawer.jd
+++ b/docs/html/training/implementing-navigation/nav-drawer.jd
@@ -26,9 +26,9 @@
 </div>
 
 <div class="download-box">
-<a href="http://developer.android.com/downloads/design/Android_Navigation_Drawer_Icon_20130516.zip"
-  class="button">Download the nav drawer icons</a>
-<p class="filename">Android_Navigation_Drawer_Icon_20130516.zip</p>
+<a href="http://developer.android.com/downloads/design/Android_Design_Icons_20130926.zip"
+  class="button">Download the Action Bar Icon Pack</a>
+<p class="filename">Android_Design_Icons_20130926.zip</p>
 </div>
 
 </div>
@@ -304,8 +304,8 @@
   <li>The {@link android.app.Activity} hosting the drawer.
   <li>The {@link android.support.v4.widget.DrawerLayout}.
   <li>A drawable resource to use as the drawer indicator.
-   <p><a href="http://developer.android.com/downloads/design/Android_Navigation_Drawer_Icon_20130516.zip"
->Download the standard navigation icons</a> (available for both dark and light themes).</p>
+   <p>The standard navigation drawer icon is available in the <a href="http://developer.android.com/downloads/design/Android_Design_Icons_20130926.zip"
+>Download the Action Bar Icon Pack</a>.</p>
   <li>A String resource to describe the "open drawer" action (for accessibility).
   <li>A String resource to describe the "close drawer" action (for accessibility).
 </ul>
diff --git a/docs/html/training/location/activity-recognition.jd b/docs/html/training/location/activity-recognition.jd
index 47ba5f8..d50064b 100644
--- a/docs/html/training/location/activity-recognition.jd
+++ b/docs/html/training/location/activity-recognition.jd
@@ -31,13 +31,13 @@
 </div>
 
 <p>
-    This lesson shows you how to request activity recognition updates from Location Services.
     Activity recognition tries to detect the user's current physical activity, such as walking,
     driving, or standing still. Requests for updates go through an activity recognition client,
     which, while different from the location client used by location or geofencing, follows a
     similar pattern. Based on the update interval you choose, Location Services sends out
     activity information containing one or more possible activities and the confidence level for
-    each one.
+    each one. This lesson shows you how to request activity recognition updates from Location 
+    Services.
 </p>
 <h2 id="RequestUpdates">Request Activity Recognition Updates</h2>
 <p>
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index 5ebbb84..e03eac6 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -85,4 +85,12 @@
         Learn how to recognize the user's current activity, such as walking, bicycling,
         or driving a car, and how to use this information to modify your app's location strategy.
     </dd>
+    <dt>
+        <b><a href="location-testing.html">Testing Using Mock Locations</a></b>
+    </dt>
+    <dd>
+        Learn how to test a location-aware app by injecting mock locations into Location
+        Services. In mock mode, Location Services sends out mock locations that you inject instead
+        of sensor-based locations.
+    </dd>
 </dl>
diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd
new file mode 100644
index 0000000..e36bac1
--- /dev/null
+++ b/docs/html/training/location/location-testing.jd
@@ -0,0 +1,371 @@
+page.title=Testing Using Mock Locations
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+    <li><a href="#TurnOnMockMode">Turn On Mock Mode</a></li>
+    <li><a href="#SendMockLocations">Send Mock Locations</a></li>
+    <li><a href="RunProvider">Run the Mock Location Provider App</a></li>
+    <li><a href="#TestingTips">Testing Tips</a>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="receive-location-updates.html">Receiving Location Updates</a></li>
+  <li><a href="geofencing.html">Creating and Monitoring Geofences</a></li>
+  <li><a href="{@docRoot}guide/components/services.html">Services</a></li>
+  <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a>
+</ul>
+
+<h2>Example Test App</h2>
+
+<div class="download-box">
+  <a href="http://developer.android.com/shareables/training/LocationProvider.zip" class="button"
+  >Download the sample</a>
+  <p class="filename">LocationProvider.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    To test a location-aware app that uses Location Services, you don't need to move your device
+    from place to place to generate location data. Instead, you can put Location Services into mock
+    mode. In this mode, you can send mock {@link android.location.Location} objects to
+    Location Services, which then sends them to location clients. In mock mode, Location Services
+    also uses mock {@link android.location.Location} objects to trigger geofences.
+</p>
+<p>
+    Using mock locations has several advantages:
+</p>
+<ul>
+    <li>
+        Mock locations allow you to create specific mock data, instead of trying to approximate
+        data by moving an actual device.
+    </li>
+    <li>
+        Since mock locations come from Location Services, they test every part of your
+        location-handling code. In addition, since you can send the mock data from outside your
+        production app, you don't have to disable or remove test code before you publish.
+    </li>
+    <li>
+        Since you don't have to generate test locations by moving a device, you can test an app
+        using the emulator.
+    </li>
+</ul>
+<p>
+    The best way to use mock locations is to send them from a separate mock location provider app.
+    This lesson includes a provider app that you can download and use to test your own software.
+    Modify the provider app as necessary to suit your own needs. Some ideas for providing test data
+    to the app are listed in the section <a href="TestData">Managing test data</a>.
+</p>
+<p>
+    The remainder of this lesson shows you how to turn on mock mode and use a location client to
+    send mock locations to Location Services.
+</p>
+<p class="note">
+    <strong>Note:</strong> Mock locations have no effect on the activity recognition algorithm used
+    by Location Services. To learn more about activity recognition, see the lesson
+    <a href="activity-recognition.html">Recognizing the User's Current Activity</a>.
+</p>
+<!--
+    Create a Test App
+ -->
+<h2 id="TurnOnMockMode">Turn On Mock Mode</h2>
+<p>
+    To send mock locations to Location Services in mock mode, a test app must request the permission
+    {@link android.Manifest.permission#ACCESS_MOCK_LOCATION}. In addition, you must enable mock
+    locations on the test device using the option <b>Enable mock locations</b>. To learn how to
+    enable mock locations on the device, see
+    <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>.
+</p>
+<p>
+    To turn on mock mode in Location Services, start by connecting a location client to Location
+    Services, as described in the lesson
+    <a href="retrieve-current.html">Retrieving the Current Location</a>.
+    Next, call the method
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>.
+    Once you call this method, Location Services turns off its internal location providers and only
+    sends out the mock locations you provide it. The following snippet shows you how to call
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>:
+</p>
+<pre>
+    // Define a LocationClient object
+    public LocationClient mLocationClient;
+    ...
+    // Connect to Location Services
+    mLocationClient.connect();
+    ...
+    // When the location client is connected, set mock mode
+    mLocationClinet.setMockMode(true);
+</pre>
+<p>
+    Once you have connected the location client to Location Services, you must keep it connected
+    until you finish sending out mock locations. Once you call
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">LocationClient.disconnect()</a></code>,
+    Location Services returns to using its internal location providers. To turn off mock mode while
+    the location client is connected, call
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(false)</a></code>.
+</p>
+<h2 id="SendMockLocations">Send Mock Locations</h2>
+<p>
+    Once you have set mock mode, you can create mock {@link android.location.Location} objects and
+    send them to Location Services. In turn, Location Services sends these mock
+    {@link android.location.Location} objects to connected location clients. Location Services also
+    uses the mock {@link android.location.Location} objects to control geofence triggering.
+</p>
+<p>
+    To create a new mock {@link android.location.Location}, create a new
+    {@link android.location.Location} object using your test data. Always set the provider
+    value to {@code flp}, which is the code that Location Services puts into the
+    {@link android.location.Location} objects it sends out. The following snippet shows you how
+    to create a new mock {@link android.location.Location}:
+</p>
+<pre>
+    private static final String PROVIDER = "flp";
+    private static final double LAT = 37.377166;
+    private static final double LNG = -122.086966;
+    private static final float ACCURACY = 3.0f;
+    ...
+    /*
+     * From input arguments, create a single Location with provider set to
+     * "flp"
+     */
+    public Location createLocation(double lat, double lng, float accuracy) {
+        // Create a new Location
+        Location newLocation = new Location(PROVIDER);
+        newLocation.setLatitude(lat);
+        newLocation.setLongitude(lng);
+        newLocation.setAccuracy(accuracy);
+        return newLocation;
+    }
+    ...
+    // Example of creating a new Location from test data
+    Location testLocation = createLocation(LAT, LNG, ACCURACY);
+</pre>
+<p>
+    In mock mode, to send a mock location to Location Services call the method
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">LocationClient.setMockLocation()</a></code>.
+    For example:
+</p>
+<pre>
+    mLocationClient.setMockLocation(testLocation);
+</pre>
+<p>
+    Location Services sets this mock location as the current location, and this location is sent
+    out as the next location update. If this new mock location moves across a geofence boundary,
+    Location Services triggers the geofence.
+</p>
+<!--
+    Run the Mock Location Provider
+ -->
+<h2 id="RunProvider">Run the Mock Location Provider App</h2>
+<p>
+    This section contains a brief overview of the mock location provider sample app
+    (available for download above) and gives you directions for testing an app using the sample app.
+</p>
+<h3>Overview</h3>
+<p>
+    The mock location provider app included with this lesson sends mock
+    {@link android.location.Location} objects to Location Services from a background thread running
+    in a started {@link android.app.Service}. By using a started service, the provider app is able
+    to keep running even if the app's main {@link android.app.Activity} is destroyed because of
+    a configuration change or other system event. By using a background thread, the service is able
+    to perform a long-running test without blocking the UI thread.
+</p>
+<p>
+    The {@link android.app.Activity} that starts when you run the provider app allows you to
+    send test parameters to the {@link android.app.Service} and control the type of test you want.
+    You have the following options:
+</p>
+<dl>
+    <dt>
+        Pause before test
+    </dt>
+    <dd>
+        The number of seconds to wait before the provider app starts sending test data to Location
+        Services. This interval allows you to switch from the provider app to the app under test
+        before the testing actually starts.
+    </dd>
+    <dt>
+        Send interval
+    </dt>
+    <dd>
+        The number of seconds that the provider app waits before it sends another mock location to
+        Location Services. See the section <a href="#TestingTips">Testing Tips</a> to learn more
+        about setting the send interval.
+    </dd>
+    <dt>
+        Run once
+    </dt>
+    <dd>
+        Switch from normal mode to mock mode, run through the test data once, switch back to
+        normal mode, and then kill the {@link android.app.Service}.
+    </dd>
+    <dt>
+        Run continuously
+    </dt>
+    <dd>
+        Switch from normal mode to mock mode, then run through the test data indefinitely. The
+        background thread and the started {@link android.app.Service} continue to run, even if the
+        main {@link android.app.Activity} is destroyed.
+    </dd>
+    <dt>
+        Stop test
+    </dt>
+    <dd>
+        If a continuous test is in progress, stop it; otherwise, return a warning message. The
+        started {@link android.app.Service} switches from mock mode to normal mode and then
+        stops itself. This also stops the background thread.
+    </dd>
+</dl>
+<p>
+    Besides the options, the provider app has two status displays:
+</p>
+<dl>
+    <dt>
+        App status
+    </dt>
+    <dd>
+        Displays messages related to the lifecycle of the provider app.
+    </dd>
+    <dt>
+        Connection status
+    </dt>
+    <dd>
+        Displays messages related to the state of the location client connection.
+    </dd>
+</dl>
+<p>
+   While the started {@link android.app.Service} is running, it also posts notifications with the
+   testing status. These notifications allow you to see status updates even if the app is not in
+   the foreground. When you click on a notification, the main {@link android.app.Activity} of the
+   provider app returns to the foreground.
+</p>
+<h3>Test using the mock location provider app</h3>
+<p>
+    To test mock location data coming from the mock location provider app:
+</p>
+<ol>
+    <li>
+        Install the mock location provider app on a device that has Google Play services installed.
+        Location Services is part of Google Play services.
+    </li>
+    <li>
+        On the device, enable mock locations. To learn how to do this, see the topic
+        <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>.
+    </li>
+    <li>
+        Start the provider app from the Launcher, then choose the options you want from the main
+        screen.
+    </li>
+    <li>
+        Unless you've removed the pause interval feature, the mock location provider app
+        pauses for a few seconds, and then starts sending mock location data to Location
+        Services.
+    </li>
+    <li>
+        Run the app you want to test. While the mock location provider app is running, the app
+        you're testing receives mock locations instead of real locations.
+    </li>
+    <li>
+        If the provider app is in the midst of a continuous test, you can switch back to real
+        locations by clicking <b>Stop test</b>. This forces the started {@link android.app.Service}
+        to turn off mock mode and then stop itself. When the service stops itself, the background
+        thread is also destroyed.
+    </li>
+
+</ol>
+<h2 id="TestingTips">Testing Tips</h2>
+<p>
+    The following sections contain tips for creating mock location data and using the data with a
+    mock location provider app.
+</p>
+<h3>Choosing a send interval</h3>
+<p>
+    Each location provider that contributes to the fused location sent out by Location Services has
+    its own minimum update cycle. For example, the GPS provider can't send a new location more often
+    than once per second, and the Wi-Fi provider can't send a new location more often than once
+    every five seconds. These cycle times are handled automatically for real locations, but you
+    should account for them when you send mock locations. For example, you shouldn't send a new mock
+    location more than once per second. If you're testing indoor locations, which rely heavily on
+    the Wi-Fi provider, then you should consider using a send interval of five seconds.
+</p>
+<h3>Simulating speed</h3>
+<p>
+    To simulate the speed of an actual device, shorten or lengthen the distance between two
+    successive locations. For example, changing the location by 88 feet every second simulates
+    car travel, because this change works out to 60 miles an hour. In comparison, changing the
+    location by 1.5 feet every second simulates brisk walking, because this change works out to
+    3 miles per hour.
+</p>
+<h3>Calculating location data</h3>
+<p>
+    By searching the web, you can find a variety of small programs that calculate a new set of
+    latitude and longitude coordinates from a starting location and a distance, as well as
+    references to formulas for calculating the distance between two points based on their latitude
+    and longitude. In addition, the {@link android.location.Location} class offers two methods for
+    calculating the distance between points:
+</p>
+<dl>
+    <dt>
+        {@link android.location.Location#distanceBetween distanceBetween()}
+    </dt>
+    <dd>
+        A static method that calculates the distance between two points specified by latitude and
+        longitude.
+    </dd>
+    <dt>
+        {@link android.location.Location#distanceTo distanceTo()}
+    </dt>
+    <dd>
+        For a given {@link android.location.Location}, returns the distance to another
+        {@link android.location.Location}.
+    </dd>
+</dl>
+<h3>Geofence testing</h3>
+<p>
+    When you test an app that uses geofence detection, use test data that reflects different modes
+    of travel, including walking, cycling, driving, and traveling by train. For a slow mode of
+    travel, make small changes in position between points. Conversely, for a fast mode of travel,
+    make a large change in position between points.
+</p>
+<h3 id="TestData">Managing test data</h3>
+<p>
+    The mock location provider app included with this lesson contains test latitude, longitude,
+    and accuracy values in the form of constants. You may want to consider other ways of organizing
+    data as well:
+</p>
+<dl>
+    <dt>
+        XML
+    </dt>
+    <dd>
+        Store location data in XML files that are including in the provider app. By separating the
+        data from the code, you facilitate changes to the data.
+    </dd>
+    <dt>
+        Server download
+    </dt>
+    <dd>
+        Store location data on a server and then have the provider app download it. Since the data
+        is completely separate from the app, you can change the data without having to rebuild the
+        app. You can also change the data on the server and have the changes reflected immediately
+        in the mock locations you're testing.
+    </dd>
+    <dt>
+        Recorded data
+    </dt>
+    <dd>
+        Instead of making up test data, write a utility app that records location data as you move
+        the device. Use the recorded data as your test data, or use the data to guide you in
+        developing test data. For example, record locations as you walk with a device, and then
+        create mock locations that have an appropriate change in latitude and longitude over
+        time.
+    </dd>
+</dl>
diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
index 11a05e1..fb5096d 100644
--- a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
@@ -49,7 +49,8 @@
         (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
  
 NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
-boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre>
+boolean isConnected = activeNetwork != null &&
+                      activeNetwork.isConnectedOrConnecting();</pre>
 
 
 <h2 id="DetermineType">Determine the Type of your Internet Connection</h2> 
diff --git a/docs/html/training/scheduling/alarms.jd b/docs/html/training/scheduling/alarms.jd
new file mode 100644
index 0000000..758dc95
--- /dev/null
+++ b/docs/html/training/scheduling/alarms.jd
@@ -0,0 +1,312 @@
+page.title=Scheduling Repeating Alarms
+parent.title=Using Wake Locks
+parent.link=index.html
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#set">Set a Repeating Alarm</a></li>
+  <li><a href="#cancel">Cancel an Alarm</a></li>
+  <li><a href="#boot">Start an Alarm When the Device Boots</a></li>
+</ol>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/Scheduler.zip"
+class="button">Download the sample</a>
+ <p class="filename">Scheduler.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Alarms (based on the {@link android.app.AlarmManager} class) give you a way to perform
+time-based operations outside the lifetime of your application.
+For example, you could use an alarm to initiate a long-running operation, such
+as starting a service once a day to download a weather forecast.</p>
+
+<p>Alarms have these characteristics:</p>
+<ul>
+
+<li>They let you fire Intents at set times and/or intervals.</li>
+
+<li>You can use them in conjunction with broadcast receivers to start services and perform
+other operations.</li>
+
+<li>They operate outside of your application, so you can use them to trigger events or
+actions even when your app is not running, and even if the device itself is asleep.</li>
+
+<li>They help you to minimize your app's resource requirements. You can schedule operations
+without relying on timers or continuously running background services.</li>
+
+</ul>
+
+<p class="note"><strong>Note:</strong> For timing operations that are guaranteed to occur
+<em>during</em> the lifetime of your application,
+instead consider using the {@link android.os.Handler} class in conjunction with
+{@link java.util.Timer} and {@link java.lang.Thread}. This approach gives Android better
+control over system resources.</p>
+
+<h2 id="set">Set a Repeating Alarm</h2>
+
+<p>As described above, repeating alarms are a good choice for scheduling regular events or
+data lookups. A repeating alarm has the following characteristics:</p>
+
+<ul>
+<li>A alarm type. For more discussion, see <a href="#type">Choose an alarm type</a>.</li>
+<li>A trigger time. If the trigger time you specify is in the past, the alarm triggers
+immediately.</li>
+<li>The alarm's interval. For example, once a day, every hour, every 5 seconds, and so on.</li>
+<li>A pending intent that fires when the alarm is triggered. When you set a second alarm
+that uses the same pending intent, it replaces the original alarm.</li>
+</ul>
+
+<p>Every choice you make in designing your repeating alarm can have consequences in how your
+app uses (or abuses) system resources. Even a carefully managed alarm can have a major impact
+on battery life. Follow these guidelines as you design your app:</p>
+
+<ul>
+<li>Keep your alarm frequency to a minimum.</li>
+<li>Don't wake up the device unnecessarily (this behavior is determined by the alarm type,
+as described in <a href="#type">Choose an alarm type</a>).</li>
+<li>Don't make your alarm's trigger time any more precise than it has to be:
+
+<ul>
+<li>Use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} instead
+of {@link android.app.AlarmManager#setRepeating setRepeating()} whenever possible.
+When you use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()},
+Android synchronizes multiple inexact repeating alarms and fires
+them at the same time. This reduces the drain on the battery.</li>
+<li>If your alarm's behavior is based on an interval (for example, your alarm
+fires once an hour) rather than a precise trigger time (for example, your alarm fires at
+7 a.m. sharp and every 20 minutes after that), use an {@code ELAPSED_REALTIME}
+alarm type.</li>
+</ul></li>
+
+</ul>
+
+<h3 id="type">Choose an alarm type</h3>
+
+<p>One of the first considerations in using a repeating alarm is what its type should be.</p>
+
+
+<p>There are two general clock types for alarms: "elapsed real time" and "real time clock"
+(RTC).
+Elapsed real time uses the "time since system boot" as a
+reference, and real time clock uses UTC (wall clock) time. This means that
+elapsed real time is suited to setting an alarm based on the passage of time (for
+example, an alarm that fires every 30 seconds) since it isn't affected by
+time zone/locale. The real time clock type is better suited for alarms that are dependent
+on current locale.</p>
+
+<p>Both types have a "wakeup" version, which says to wake up the device's CPU if the
+screen is off. This ensures that the alarm will fire at the scheduled time. This is useful
+if your app has a time dependency&mdash;for example, if it has a limited window to perform a
+particular operation. If you don't use the wakeup version of your alarm type, then
+all the repeating alarms will fire when your device is next awake.</p>
+
+<p>If you simply need your alarm to fire at a particular interval (for example, every half
+hour), use one of the elapsed real time types. In general, this is the better choice.</p>
+
+<p>If you need your alarm to fire at a particular time of day,
+then choose one of the clock-based real time clock types. Note, however, that this approach can
+have some drawbacks&mdash;the app may not translate well to other locales, and if the user
+changes the device's time setting, it could cause unexpected behavior in your app.</p>
+
+<p>Here is the list of types:</p>
+
+<ul>
+
+<li>{@link android.app.AlarmManager#ELAPSED_REALTIME}&mdash;Fires the pending intent based
+on the amount of time since the  device was booted, but doesn't wake up the device. The
+elapsed time includes any time during which the device was asleep.</li>
+
+<li>{@link android.app.AlarmManager#ELAPSED_REALTIME_WAKEUP}&mdash;Wakes up the device and
+fires the pending intent after the specified length of time has elapsed since device
+boot.</li>
+
+<li>{@link android.app.AlarmManager#RTC}&mdash;Fires the pending intent
+at the specified time but does not wake up the device.</li>
+
+<li>{@link android.app.AlarmManager#RTC_WAKEUP}&mdash;Wakes up the
+device to fire the pending intent at the specified time.</li>
+</ul>
+
+<h4>ELAPSED_REALTIME_WAKEUP examples</h3>
+
+<p>Here are some examples of using {@link android.app.AlarmManager#ELAPSED_REALTIME_WAKEUP}.
+</p>
+
+<p>Wake up the device to fire the alarm in 30 minutes, and every 30 minutes
+after that:</p>
+
+<pre>
+// Hopefully your alarm will have a lower frequency than this!
+alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+        AlarmManager.INTERVAL_HALF_HOUR,
+        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);</pre>
+
+<p>Wake up the device to fire a one-time (non-repeating) alarm in one minute:</p>
+
+<pre>private AlarmManager alarmMgr;
+private PendingIntent alarmIntent;
+...
+alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+Intent intent = new Intent(context, AlarmReceiver.class);
+alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+
+alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+        SystemClock.elapsedRealtime() +
+        60 * 1000, alarmIntent);</pre>
+
+
+<h4>RTC examples</h3>
+
+<p>Here are some examples of using {@link android.app.AlarmManager#RTC_WAKEUP}.</p>
+
+<p>Wake up the device to fire the alarm at approximately 2:00 p.m., and repeat once a day
+at the same time:</p>
+
+<pre>// Set the alarm to start at approximately 2:00 p.m.
+Calendar calendar = Calendar.getInstance();
+calendar.setTimeInMillis(System.currentTimeMillis());
+calendar.set(Calendar.HOUR_OF_DAY, 14);
+
+// With setInexactRepeating(), you have to use one of the AlarmManager interval
+// constants--in this case, AlarmManager.INTERVAL_DAY.
+alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
+        AlarmManager.INTERVAL_DAY, alarmIntent);</pre>
+
+<p>Wake up the device to fire the alarm at precisely 8:30 a.m., and every 20 minutes
+thereafter:</p>
+
+<pre>private AlarmManager alarmMgr;
+private PendingIntent alarmIntent;
+...
+alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+Intent intent = new Intent(context, AlarmReceiver.class);
+alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+
+// Set the alarm to start at 8:30 a.m.
+Calendar calendar = Calendar.getInstance();
+calendar.setTimeInMillis(System.currentTimeMillis());
+calendar.set(Calendar.HOUR_OF_DAY, 8);
+calendar.set(Calendar.MINUTE, 30);
+
+// setRepeating() lets you specify a precise custom interval--in this case,
+// 20 minutes.
+alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
+        1000 * 60 * 20, alarmIntent);</pre>
+
+<h3>Decide how precise your alarm needs to be</h3>
+
+<p>As described above, choosing the alarm type is often the first step in creating an alarm.
+A further distinction is how precise you need your alarm to be. For most apps,
+{@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} is the right
+choice.
+When you use this method, Android synchronizes multiple inexact repeating alarms and fires
+them at the same time. This reduces the drain on the battery.</p>
+
+<p>For the rare app that has rigid time requirements&mdash;for example, the alarm needs to
+fire precisely at 8:30 a.m., and every hour on the hour
+thereafter&mdash;use {@link android.app.AlarmManager#setRepeating setRepeating()}. But you
+should avoid using exact alarms if possible.</p>
+
+<p>With {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()},
+you can't specify a custom interval the way you can with
+{@link android.app.AlarmManager#setRepeating setRepeating()}. You have to use one of the
+interval constants, such as {@link android.app.AlarmManager#INTERVAL_FIFTEEN_MINUTES},
+{@link android.app.AlarmManager#INTERVAL_DAY}, and so on. See {@link android.app.AlarmManager}
+for the complete list.
+</p>
+
+<h2 id="cancel">Cancel an Alarm</h2>
+
+<p>Depending on your app, you may want to include the ability to cancel the alarm.
+To cancel an alarm, call {@link android.app.AlarmManager#cancel cancel()} on the Alarm
+Manager, passing in the {@link android.app.PendingIntent} you no longer want to fire. For
+example:</p>
+
+<pre>// If the alarm has been set, cancel it.
+if (alarmMgr!= null) {
+    alarmMgr.cancel(alarmIntent);
+}</pre>
+
+<h2 id="boot">Start an Alarm When the Device Boots</h2>
+
+<p>By default, all alarms are canceled when a device shuts down.
+To prevent this from happening, you can design your application
+to automatically restart a repeating alarm if the user reboots the device. This ensures
+that the {@link android.app.AlarmManager} will continue doing its task without the user
+needing to manually restart the alarm.</p>
+
+
+<p>Here are the steps:</p>
+<ol>
+<li>Set the <a href="{@docRoot}reference/android/Manifest.permission.html#RECEIVE_BOOT_COMPLETED">
+{@code RECEIVE_BOOT_COMPLETED}</a> permission in your application's manifest. This allows
+your app to receive the
+{@link android.content.Intent#ACTION_BOOT_COMPLETED} that is broadcast after the system
+finishes booting (this only works if the app has already been launched by the user at least once):
+<pre>
+&lt;uses-permission android:name=&quot;android.permission.RECEIVE_BOOT_COMPLETED&quot;/&gt;</pre>
+</li>
+
+<li>Implement a {@link android.content.BroadcastReceiver} to receive the broadcast:
+<pre>public class SampleBootReceiver extends BroadcastReceiver {
+
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getAction().equals(&quot;android.intent.action.BOOT_COMPLETED&quot;)) {
+            // Set the alarm here.
+        }
+    }
+}</pre></li>
+
+<li>Add the receiver to your app's manifest file with an intent filter that filters on
+the {@link android.content.Intent#ACTION_BOOT_COMPLETED} action:
+
+<pre>&lt;receiver android:name=&quot;.SampleBootReceiver&quot;
+        android:enabled=&quot;false&quot;&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot;&gt;&lt;/action&gt;
+    &lt;/intent-filter&gt;
+&lt;/receiver&gt;</pre>
+
+
+<p>Notice that in the manifest, the boot receiver is set to
+{@code android:enabled=&quot;false&quot;}. This means that the receiver will not be called
+unless the application explicitly enables it. This prevents the boot receiver from being
+called unnecessarily. You can enable a receiver (for example, if the user sets an alarm)
+as follows:</p>
+
+<pre>ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
+PackageManager pm = context.getPackageManager();
+
+pm.setComponentEnabledSetting(receiver,
+        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+        PackageManager.DONT_KILL_APP);
+</pre>
+
+<p>Once you enable the receiver this way, it will stay enabled, even if the user reboots
+the device. In other words, programmatically enabling the receiver overrides the
+manifest setting, even across reboots. The receiver will stay enabled until your app disables it.
+You can disable a receiver (for example, if the user cancels an alarm) as follows:</p>
+
+<pre>ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
+PackageManager pm = context.getPackageManager();
+
+pm.setComponentEnabledSetting(receiver,
+        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+        PackageManager.DONT_KILL_APP);</pre>
+
+</li>
+</ol>
diff --git a/docs/html/training/scheduling/index.jd b/docs/html/training/scheduling/index.jd
new file mode 100644
index 0000000..9ffbc16
--- /dev/null
+++ b/docs/html/training/scheduling/index.jd
@@ -0,0 +1,66 @@
+page.title=Managing Device Awake State
+page.tags=""
+
+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 1.6 (API Level 4) or higher</li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/Scheduler.zip"
+class="button">Download the sample</a>
+ <p class="filename">Scheduler.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>
+When an Android device is left idle, it will first dim, then turn off the screen, and
+ultimately turn off the CPU. This prevents the device's battery from quickly getting
+drained. Yet there are times when your application might require a different behavior:</p>
+
+<ul>
+
+<li>Apps such as games or movie apps may need to keep the screen turned on.</p>
+
+<li>Other applications may not need the screen to remain on, but they may require the CPU
+ to keep running until a critical operation finishes.</p>
+
+</ul>
+
+<p>
+This class describes how to keep a device awake when necessary without draining
+its battery.
+</p>
+<h2>Lessons</h2>
+
+<dl>
+    <dt>
+        <strong><a href="wakelock.html">Keeping the Device Awake</a></strong>
+    </dt>
+    <dd>
+        Learn how to keep the screen or CPU awake as needed, while minimizing the impact
+        on battery life.
+    </dd>
+    <dt>
+        <strong><a href="alarms.html">Scheduling Repeating Alarms</a></strong>
+    </dt>
+    <dd>
+        Learn how to use repeating alarms to schedule operations that take place outside
+        of the lifetime of the application, even if the application is not running and/or the
+        device is asleep.
+    </dd>
+</dl>
diff --git a/docs/html/training/scheduling/wakelock.jd b/docs/html/training/scheduling/wakelock.jd
new file mode 100644
index 0000000..0fab7be
--- /dev/null
+++ b/docs/html/training/scheduling/wakelock.jd
@@ -0,0 +1,215 @@
+page.title=Keeping the Device Awake
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#screen">Keep the Screen On</a></li>
+  <li><a href="#cpu">Keep the CPU On</a></li>
+</ol>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/Scheduler.zip"
+class="button">Download the sample</a>
+ <p class="filename">Scheduler.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p>To avoid draining the battery, an Android device that is left idle quickly falls asleep.
+However, there are times when an application needs to wake up the screen or the CPU
+and keep it awake to complete some work.</p>
+
+<p>The approach you take depends on the needs of your app. However, a general rule of thumb
+is that you should use the most lightweight approach possible for your app, to minimize your
+app's impact on system resources. The following sections describe how to handle the cases
+where the device's default sleep behavior is incompatible with the requirements of your app.</p>
+
+<h2 id="screen">Keep the Screen On</h2>
+
+<p>Certain apps need to keep the screen turned on, such as games or movie apps. The best
+way to do this is to use the
+{@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON}
+in your activity (and only in an activity, never in a service or
+other app component). For example:</p>
+
+<pre>public class MainActivity extends Activity {
+  &#64;Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_main);
+    <strong>getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);</strong>
+  }</pre>
+
+<p>The advantage of this approach is that unlike wake locks (discussed in <a href="#cpu">
+Keep the CPU On</a>), it doesn't require special permission, and the platform correctly
+manages the user moving between applications, without your app needing to worry about
+releasing unused resources.</p>
+
+<p>Another way to implement this is in your application's layout XML file, by using the
+{@link android.R.attr#keepScreenOn android:keepScreenOn} attribute:</p>
+
+<pre>&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+    android:layout_width=&quot;match_parent&quot;
+    android:layout_height=&quot;match_parent&quot;
+    <strong>android:keepScreenOn=&quot;true&quot;&gt;</strong>
+    ...
+&lt;/RelativeLayout&gt;</pre>
+
+<p>Using <code>android:keepScreenOn=&quot;true&quot;</code> is equivalent to using
+{@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON}.
+You can use whichever approach is best for your app. The advantage of setting the flag
+programmatically in your activity is that it gives you the option of programmatically
+clearing the flag later and thereby allowing the screen to turn off.</p>
+
+<p class="note"><strong>Note:</strong> You don't need to clear the
+{@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON}
+flag unless you no longer want the screen to
+stay on in your running application (for example, if you want the screen to time out
+after a certain period of inactivity). The window manager takes care of
+ensuring that the right things happen when the app goes into the background or returns to
+the foreground. But if you want to explicitly clear the flag and thereby allow the screen to
+turn off again, use {@link android.view.Window#clearFlags clearFlags()}:
+{@code getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)}.</p>
+
+<h2 id="cpu">Keep the CPU On</h2>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h2>Alternatives to using wake locks</h2>
+
+<ul>
+
+<li>If your app is performing long-running HTTP downloads, consider using
+{@link android.app.DownloadManager}.</li>
+
+<li>If your app is synchronizing data from an external server, consider creating a
+<a href="{@docRoot}training/sync-adapters/index.html">sync
+adapter</a>.</li>
+
+<li>If your app relies on background services, consider using
+<a href="{@docRoot}training/scheduling/alarms.html">repeating alarms</a>
+or <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> to trigger these
+services at specific intervals.</li>
+
+</ul>
+</div>
+</div>
+
+
+<p>If you need to keep the CPU running in order to complete some work before the device goes
+to sleep, you can use a {@link android.os.PowerManager} system service feature called
+wake locks. Wake locks allow your application to control the power state of the host device.</p>
+
+<p>Creating and holding wake locks can have a dramatic impact on the host device's battery
+life. Thus you should use wake locks only when strictly necessary
+and hold them for as short a time as possible. For example, you should never need to use a
+wake lock in an activity. As described above, if you want
+to keep the screen on in your activity, use
+{@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON}.</p>
+
+
+<p>One legitimate case for using a wake lock might be a background service
+that needs to grab a wake lock to keep the CPU running to do work while the screen is off.
+Again, though, this practice should be minimized because of its impact on battery life.</p>
+
+<p>To use a wake lock, the first step is to add the {@link android.Manifest.permission#WAKE_LOCK}
+ permission to your application's manifest file:</p>
+
+<pre>&lt;uses-permission android:name=&quot;android.permission.WAKE_LOCK&quot; /&gt;</pre>
+
+<p>If your app includes a broadcast receiver that uses a service to do some
+work, you can manage your wake lock through a
+{@link android.support.v4.content.WakefulBroadcastReceiver}, as described in
+<a href="#wakeful">Using a WakefulBroadcastReceiver</a>. This is the preferred approach.
+If your app doesn't follow that pattern, here is how you set a wake lock
+directly:</p>
+
+<pre>
+PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
+Wakelock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+        "MyWakelockTag");
+wakeLock.acquire();</pre>
+
+<p>To release the wake lock, call
+{@link android.os.PowerManager.WakeLock#release wakelock.release()}. This releases your
+claim to the CPU. It's important to release a wake lock as soon as your app is finished
+using it to avoid draining the battery.</p>
+
+<h3 id="wakeful">Using WakefulBroadcastReceiver</h3>
+
+<p>Using a broadcast receiver in conjunction with a service lets you manage the life cycle
+of a background task.</p>
+
+<p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
+broadcast receiver that takes care of
+creating and managing a
+{@link android.os.PowerManager#PARTIAL_WAKE_LOCK} for your app. A
+{@link android.support.v4.content.WakefulBroadcastReceiver}
+passes off the work to a {@link android.app.Service}
+(typically an
+{@link android.app.IntentService}), while ensuring that the device does not
+go back to sleep in the transition. If you don't hold a wake lock while transitioning
+the work to a service, you are effectively allowing the device to go back to sleep before
+the work completes. The net result is that the app might not finish doing the work until
+some arbitrary point in the future, which is not what you want.</p>
+
+<p>The first step in using a
+{@link android.support.v4.content.WakefulBroadcastReceiver} is to add it to your
+manifest, as with any other broadcast receiver:</p>
+
+<pre>&lt;receiver android:name=&quot;.MyWakefulReceiver&quot;&gt;&lt;/receiver&gt;</pre>
+
+<p>The following code starts {@code MyIntentService} with the method
+{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}.
+This method is comparable to {@link android.content.Context#startService startService()}, except that
+the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a
+wake lock when the service starts. The intent that is passed with
+{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}
+holds an extra identifying the wake lock:</p>
+
+<pre>public class MyWakefulReceiver extends WakefulBroadcastReceiver {
+
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+
+        // Start the service, keeping the device awake while the service is
+        // launching. This is the Intent to deliver to the service.
+        Intent service = new Intent(context, MyIntentService.class);
+        startWakefulService(context, service);
+    }
+}</pre>
+
+<p>When the service is finished, it calls
+{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent MyWakefulReceiver.completeWakefulIntent()}
+to release the wake lock. The
+{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()}
+method has as its parameter the same intent that was
+passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}:</p>
+<pre>
+public class MyIntentService extends IntentService {
+    public static final int NOTIFICATION_ID = 1;
+    private NotificationManager mNotificationManager;
+    NotificationCompat.Builder builder;
+    public MyIntentService() {
+        super("MyIntentService");
+    }
+    &#64;Override
+    protected void onHandleIntent(Intent intent) {
+        Bundle extras = intent.getExtras();
+        // Do the work that requires your app to keep the CPU running.
+        // ...
+        // Release the wake lock provided by the WakefulBroadcastReceiver.
+        MyWakefulReceiver.completeWakefulIntent(intent);
+    }
+}</pre>
diff --git a/docs/html/training/sharing/send.jd b/docs/html/training/sharing/send.jd
index 9cb8eac..ed9e12e 100644
--- a/docs/html/training/sharing/send.jd
+++ b/docs/html/training/sharing/send.jd
@@ -134,34 +134,26 @@
   <li>You can use a MIME type of {@code "*/*"}, but this will only match activities that are able to
 handle generic data streams.</li>
   <li>The receiving application needs permission to access the data the {@link android.net.Uri}
-points to. There are a number of ways to handle this:
+points to. The recommended ways to do this are:
   <ul>
-    <li>Write the data to a file on external/shared storage (such as the SD card), which all apps
-can read. Use {@link android.net.Uri#fromFile(java.io.File) Uri.fromFile()} to create the
-{@link android.net.Uri} that can be passed to the share intent. However, keep in mind that not
-all applications process a {@code file://} style {@link android.net.Uri}.</li>
-    <li>Write the data to a file in your own application directory using {@link
-android.content.Context#openFileOutput(java.lang.String, int) openFileOutput()} with mode {@link
-android.content.Context#MODE_WORLD_READABLE} after which {@link
-android.content.Context#getFileStreamPath(java.lang.String) getFileStreamPath()} can be used to
-return a {@link java.io.File}. As with the previous option, {@link
-android.net.Uri#fromFile(java.io.File) Uri.fromFile()} will create a {@code file://} style {@link
-android.net.Uri} for your share intent.</li>
-    <li>Media files like images, videos and audio can be scanned and added to the system {@link
-android.provider.MediaStore} using {@link
+    <li>Store the data in your own {@link android.content.ContentProvider}, making sure that other
+apps have the correct permission to access your provider. The preferred mechanism for providing
+access is to use <a
+href="{@docRoot}guide/topics/security/permissions.html#uri">per-URI permissions</a> which are
+temporary and only grant access to the receiving application. An easy way to create a
+{@link android.content.ContentProvider} like this is to use the
+{@link android.support.v4.content.FileProvider} helper class.</li>
+    <li>Use the system {@link android.provider.MediaStore}. The {@link android.provider.MediaStore}
+is primarily aimed at video, audio and image MIME types, however beginning with Android 3.0 (API
+level 11) it can also store non-media types (see
+{@link android.provider.MediaStore.Files MediaStore.Files} for more info). Files can be inserted
+into the {@link android.provider.MediaStore} using {@link
 android.media.MediaScannerConnection#scanFile(android.content.Context, java.lang.String[],
-java.lang.String[], android.media.MediaScannerConnection.OnScanCompletedListener) scanFile()}. The
-{@link
-android.media.MediaScannerConnection.OnScanCompletedListener#onScanCompleted(java.lang.String,
-android.net.Uri) onScanCompleted()} callback returns a {@code content://} style {@link
-android.net.Uri} suitable for including in your share intent.</li>
-    <li>Images can be inserted into the system {@link android.provider.MediaStore} using {@link
-android.provider.MediaStore.Images.Media#insertImage(android.content.ContentResolver,
-android.graphics.Bitmap, java.lang.String, java.lang.String) insertImage()} which will return a
-{@code content://} style {@link android.net.Uri} suitable for including in a share intent.</li>
-    <li>Store the data in your own {@link android.content.ContentProvider}, make sure that other
-apps have the correct permission to access your provider (or use <a
-href="{@docRoot}guide/topics/security/security.html#uri">per-URI permissions</a>).</li>
+java.lang.String[], android.media.MediaScannerConnection.OnScanCompletedListener) scanFile()} after
+which a {@code content://} style {@link android.net.Uri} suitable for sharing is passed to the
+provided {@link android.media.MediaScannerConnection.OnScanCompletedListener#onScanCompleted(
+java.lang.String, android.net.Uri) onScanCompleted()} callback. Note that once added to the system
+{@link android.provider.MediaStore} the content is accessible to any app on the device.</li>
   </ul>
   </li>
 </ul>
diff --git a/docs/html/training/testing.jd b/docs/html/training/testing.jd
new file mode 100644
index 0000000..c55370d
--- /dev/null
+++ b/docs/html/training/testing.jd
@@ -0,0 +1,7 @@
+page.title=Best Practices for Testing
+page.trainingcourse=true
+
+@jd:body
+
+<p>These classes and articles provide information about how to
+test your Android application.</p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index c99fc96..77ac235 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -68,6 +68,30 @@
 
       <li class="nav-section">
         <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/basics/supporting-devices/index.html"
+             description=
+             "How to build your app with alternative resources that provide an
+             optimized user experience on multiple device form factors using a single APK."
+            >Supporting Different Devices</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/basics/supporting-devices/languages.html">
+            Supporting Different Languages
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/supporting-devices/screens.html">
+            Supporting Different Screens
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/supporting-devices/platforms.html">
+            Supporting Different Platform Versions
+          </a>
+          </li>
+        </ul>
+      </li>
+
+      <li class="nav-section">
+        <div class="nav-section-header">
           <a href="<?cs var:toroot ?>training/basics/activity-lifecycle/index.html"
              description=
              "How Android activities live and die and how to create
@@ -96,30 +120,6 @@
 
       <li class="nav-section">
         <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>training/basics/supporting-devices/index.html"
-             description=
-             "How to build your app with alternative resources that provide an
-             optimized user experience on multiple device form factors using a single APK."
-            >Supporting Different Devices</a>
-        </div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>training/basics/supporting-devices/languages.html">
-            Supporting Different Languages
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/basics/supporting-devices/screens.html">
-            Supporting Different Screens
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/basics/supporting-devices/platforms.html">
-            Supporting Different Platform Versions
-          </a>
-          </li>
-        </ul>
-      </li>
-
-      <li class="nav-section">
-        <div class="nav-section-header">
           <a href="<?cs var:toroot ?>training/basics/fragments/index.html"
              description=
              "How to build a user interface for your app that is flexible enough
@@ -405,7 +405,7 @@
           <a href="<?cs var:toroot ?>training/connect-devices-wirelessly/index.html"
              description=
              "How to find and connect to local devices using Network Service
-             Discovery and Wi-Fi Direct in order to create peer-to-peer connections."
+             Discovery and how to create peer-to-peer connections with Wi-Fi."
              >Connecting Devices Wirelessly</a>
         </div>
         <ul>
@@ -414,11 +414,11 @@
           </a>
           </li>
           <li><a href="<?cs var:toroot ?>training/connect-devices-wirelessly/wifi-direct.html">
-            Connecting with Wi-Fi Direct
+            Creating P2P Connections with Wi-Fi
           </a>
           </li>
           <li><a href="<?cs var:toroot ?>training/connect-devices-wirelessly/nsd-wifi-direct.html">
-            Using Wi-Fi Direct for Service Discovery
+            Using Wi-Fi P2P for Service Discovery
           </a>
           </li>
         </ul>
@@ -576,29 +576,6 @@
           </li>
         </ul>
       </li>
-      <li class="nav-section">
-        <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>training/id-auth/index.html"
-             description=
-             "How to remember the user by account, authenticate the user, acquire user permission
-             for the user's online data, and create custom accounts on the device."
-            >Remembering Users</a>
-        </div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>training/id-auth/identify.html">
-            Remembering Your User
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/id-auth/authenticate.html">
-            Authenticating to OAuth2 Services
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/id-auth/custom_auth.html">
-            Creating a Custom Account Type
-          </a>
-          </li>
-        </ul>
-      </li>
 
       <li class="nav-section">
         <div class="nav-section-header">
@@ -631,6 +608,10 @@
           Recognizing the User's Current Activity
           </a>
           </li>
+          <li><a href="<?cs var:toroot ?>training/location/location-testing.html">
+          Testing Using Mock Locations
+          </a>
+          </li>
         </ul>
       </li>
     </ul>
@@ -989,6 +970,75 @@
 
   <li class="nav-section">
     <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>training/best-background.html">
+      <span class="small">Best Practices for</span><br/>
+              Background Jobs
+      </a>
+    </div>
+    <ul>
+
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/run-background-service/index.html"
+             description=
+             "How to improve UI performance and responsiveness by sending work to a
+             Service running in the background"
+            >Running in a Background Service</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/run-background-service/create-service.html">
+            Creating a Background Service
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/run-background-service/send-request.html">
+            Sending Work Requests to the Background Service
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/run-background-service/report-status.html">
+            Reporting Work Status
+          </a>
+          </li>
+        </ul>
+      </li>
+
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/load-data-background/index.html"
+             description="How to use CursorLoader to query data without
+             affecting UI responsiveness."
+            >Loading Data in the Background</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/load-data-background/setup-loader.html">
+            Running a Query with a CursorLoader</a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/load-data-background/handle-results.html">
+            Handling the Results</a>
+          </li>
+        </ul>
+      </li>
+
+       <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/scheduling/index.html"
+             description="How to use repeating alarms and wake locks
+             to run background jobs."
+            >Managing Device Awake State</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/scheduling/wakelock.html">
+            Keeping the Device Awake</a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/scheduling/alarms.html">
+            Scheduling Repeating Alarms</a>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li> <!-- end of Background Jobs -->
+
+  <li class="nav-section">
+    <div class="nav-section-header">
       <a href="<?cs var:toroot ?>training/best-performance.html">
       <span class="small">Best Practices for</span><br/>
               Performance
@@ -1034,47 +1084,6 @@
 
       <li class="nav-section">
         <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>training/run-background-service/index.html"
-             description=
-             "How to improve UI performance and responsiveness by sending work to a
-             Service running in the background"
-            >Running in a Background Service</a>
-        </div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>training/run-background-service/create-service.html">
-            Creating a Background Service
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/run-background-service/send-request.html">
-            Sending Work Requests to the Background Service
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/run-background-service/report-status.html">
-            Reporting Work Status
-          </a>
-          </li>
-        </ul>
-      </li>
-
-      <li class="nav-section">
-        <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>training/load-data-background/index.html"
-             description="How to use CursorLoader to query data without
-             affecting UI responsiveness."
-            >Loading Data in the Background</a>
-        </div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>training/load-data-background/setup-loader.html">
-            Running a Query with a CursorLoader</a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/load-data-background/handle-results.html">
-            Handling the Results</a>
-          </li>
-        </ul>
-      </li>
-
-      <li class="nav-section">
-        <div class="nav-section-header">
           <a href="/training/monitoring-device-state/index.html"
              zh-cn-lang="优化电池使用时间"
              ja-lang="電池消費量の最適化"
@@ -1205,6 +1214,45 @@
   </li>
   <!-- End security and user info -->
 
+  <li class="nav-section">
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>training/testing.html">
+      <span class="small">Best Practices for</span><br/>
+              Testing
+      </a>
+    </div>
+    <ul>
+      <li class="nav-section">
+      <div class="nav-section-header"><a href="<?cs var:toroot ?>training/activity-testing/index.html"
+         description="How to test Activities in your Android applications.">
+            Testing Your Activity
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/activity-testing/preparing-activity-testing.html">
+            <span class="en">Setting Up Your Test Environment</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/activity-testing/activity-basic-testing.html">
+            <span class="en">Creating and Running a Test Case</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/activity-testing/activity-ui-testing.html">
+            <span class="en">Testing UI Components</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/activity-testing/activity-unit-testing.html">
+            <span class="en">Creating Unit Tests</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/activity-testing/activity-functional-testing.html">
+            <span class="en">Creating Functional Tests</span>
+          </a>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+  <!-- End best Testing -->
 
   <li class="nav-section">
     <div class="nav-section-header">
diff --git a/graphics/java/android/graphics/Atlas.java b/graphics/java/android/graphics/Atlas.java
new file mode 100644
index 0000000..39a5a53
--- /dev/null
+++ b/graphics/java/android/graphics/Atlas.java
@@ -0,0 +1,441 @@
+/*
+ * 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 android.graphics;
+
+/**
+ * @hide
+ */
+public class Atlas {
+    /**
+     * This flag indicates whether the packing algorithm will attempt
+     * to rotate entries to make them fit better in the atlas.
+     */
+    public static final int FLAG_ALLOW_ROTATIONS = 0x1;
+    /**
+     * This flag indicates whether the packing algorithm should leave
+     * an empty 1 pixel wide border around each bitmap. This border can
+     * be useful if the content of the atlas will be used in OpenGL using
+     * bilinear filtering.
+     */
+    public static final int FLAG_ADD_PADDING = 0x2;
+    /**
+     * Default flags: allow rotations and add padding.
+     */
+    public static final int FLAG_DEFAULTS = FLAG_ADD_PADDING;
+
+    /**
+     * Each type defines a different packing algorithm that can
+     * be used by an {@link Atlas}. The best algorithm to use
+     * will depend on the source dataset and the dimensions of
+     * the atlas.
+     */
+    public enum Type {
+        SliceMinArea,
+        SliceMaxArea,
+        SliceShortAxis,
+        SliceLongAxis
+    }
+
+    /**
+     * Represents a bitmap packed in the atlas. Each entry has a location in
+     * pixels in the atlas and a rotation flag. If the entry was rotated, the
+     * bitmap must be rotated by 90 degrees (in either direction as long as
+     * the origin remains the same) before being rendered into the atlas.
+     */
+    public static class Entry {
+        /**
+         * Location, in pixels, of the bitmap on the X axis in the atlas.
+         */
+        public int x;
+        /**
+         * Location, in pixels, of the bitmap on the Y axis in the atlas.
+         */
+        public int y;
+
+        /**
+         * If true, the bitmap must be rotated 90 degrees in the atlas.
+         */
+        public boolean rotated;
+    }
+
+    private final Policy mPolicy;
+
+    /**
+     * Creates a new atlas with the specified algorithm and dimensions
+     * in pixels. Calling this constructor is equivalent to calling
+     * {@link #Atlas(Atlas.Type, int, int, int)} with {@link #FLAG_DEFAULTS}.
+     *
+     * @param type The algorithm to use to pack rectangles in the atlas
+     * @param width The width of the atlas in pixels
+     * @param height The height of the atlas in pixels
+     *
+     * @see #Atlas(Atlas.Type, int, int, int)
+     */
+    public Atlas(Type type, int width, int height) {
+        this(type, width, height, FLAG_DEFAULTS);
+    }
+
+    /**
+     * Creates a new atlas with the specified algorithm and dimensions
+     * in pixels. A set of flags can also be specified to control the
+     * behavior of the atlas.
+     *
+     * @param type The algorithm to use to pack rectangles in the atlas
+     * @param width The width of the atlas in pixels
+     * @param height The height of the atlas in pixels
+     * @param flags Optional flags to control the behavior of the atlas:
+     *              {@link #FLAG_ADD_PADDING}, {@link #FLAG_ALLOW_ROTATIONS}
+     *
+     * @see #Atlas(Atlas.Type, int, int)
+     */
+    public Atlas(Type type, int width, int height, int flags) {
+        mPolicy = findPolicy(type, width, height, flags);
+    }
+
+    /**
+     * Packs a rectangle of the specified dimensions in this atlas.
+     *
+     * @param width The width of the rectangle to pack in the atlas
+     * @param height The height of the rectangle to pack in the atlas
+     *
+     * @return An {@link Entry} instance if the rectangle was packed in
+     *         the atlas, or null if the rectangle could not fit
+     *
+     * @see #pack(int, int, Atlas.Entry)
+     */
+    public Entry pack(int width, int height) {
+        return pack(width, height, null);
+    }
+
+    /**
+     * Packs a rectangle of the specified dimensions in this atlas.
+     *
+     * @param width The width of the rectangle to pack in the atlas
+     * @param height The height of the rectangle to pack in the atlas
+     * @param entry Out parameter that will be filled in with the location
+     *              and attributes of the packed rectangle, can be null
+     *
+     * @return An {@link Entry} instance if the rectangle was packed in
+     *         the atlas, or null if the rectangle could not fit
+     *
+     * @see #pack(int, int)
+     */
+    public Entry pack(int width, int height, Entry entry) {
+        if (entry == null) entry = new Entry();
+        return mPolicy.pack(width, height, entry);
+    }
+
+    private static Policy findPolicy(Type type, int width, int height, int flags) {
+        switch (type) {
+            case SliceMinArea:
+                return new SlicePolicy(width, height, flags,
+                        new SlicePolicy.MinAreaSplitDecision());
+            case SliceMaxArea:
+                return new SlicePolicy(width, height, flags,
+                        new SlicePolicy.MaxAreaSplitDecision());
+            case SliceShortAxis:
+                return new SlicePolicy(width, height, flags,
+                        new SlicePolicy.ShorterFreeAxisSplitDecision());
+            case SliceLongAxis:
+                return new SlicePolicy(width, height, flags,
+                        new SlicePolicy.LongerFreeAxisSplitDecision());
+        }
+        return null;
+    }
+
+    /**
+     * A policy defines how the atlas performs the packing operation.
+     */
+    private static abstract class Policy {
+        abstract Entry pack(int width, int height, Entry entry);
+    }
+
+    /**
+     * The Slice algorightm divides the remaining empty space either
+     * horizontally or vertically after a bitmap is placed in the atlas.
+     *
+     * NOTE: the algorithm is explained below using a tree but is
+     * implemented using a linked list instead for performance reasons.
+     *
+     * The algorithm starts with a single empty cell covering the entire
+     * atlas:
+     *
+     *  -----------------------
+     * |                       |
+     * |                       |
+     * |                       |
+     * |      Empty space      |
+     * |          (C0)         |
+     * |                       |
+     * |                       |
+     * |                       |
+     *  -----------------------
+     *
+     * The tree of cells looks like this:
+     *
+     * N0(free)
+     *
+     * The algorithm then places a bitmap B1, if possible:
+     *
+     *  -----------------------
+     * |        |              |
+     * |   B1   |              |
+     * |        |              |
+     * |--------               |
+     * |                       |
+     * |                       |
+     * |                       |
+     * |                       |
+     *  -----------------------
+     *
+     *  After placing a bitmap in an empty cell, the algorithm splits
+     *  the remaining space in two new empty cells. The split can occur
+     *  vertically or horizontally (this is controlled by the "split
+     *  decision" parameter of the algorithm.)
+     *
+     *  Here is for the instance the result of a vertical split:
+     *
+     *  -----------------------
+     * |        |              |
+     * |   B1   |              |
+     * |        |              |
+     * |--------|      C2      |
+     * |        |              |
+     * |        |              |
+     * |   C1   |              |
+     * |        |              |
+     *  -----------------------
+     *
+     * The cells tree now looks like this:
+     *
+     *       C0(occupied)
+     *           / \
+     *          /   \
+     *         /     \
+     *        /       \
+     *    C1(free)  C2(free)
+     *
+     * For each bitmap to place in the atlas, the Slice algorithm
+     * will visit the free cells until it finds one where a bitmap can
+     * fit. It will then split the now occupied cell and proceed onto
+     * the next bitmap.
+     */
+    private static class SlicePolicy extends Policy {
+        private final Cell mRoot = new Cell();
+
+        private final SplitDecision mSplitDecision;
+
+        private final boolean mAllowRotation;
+        private final int mPadding;
+
+        /**
+         * A cell represents a sub-rectangle of the atlas. A cell is
+         * a node in a linked list representing the available free
+         * space in the atlas.
+         */
+        private static class Cell {
+            int x;
+            int y;
+
+            int width;
+            int height;
+
+            Cell next;
+
+            @Override
+            public String toString() {
+                return String.format("cell[x=%d y=%d width=%d height=%d", x, y, width, height);
+            }
+        }
+
+        SlicePolicy(int width, int height, int flags, SplitDecision splitDecision) {
+            mAllowRotation = (flags & FLAG_ALLOW_ROTATIONS) != 0;
+            mPadding = (flags & FLAG_ADD_PADDING) != 0 ? 1 : 0;
+
+            // The entire atlas is empty at first, minus padding
+            Cell first = new Cell();
+            first.x = first.y = mPadding;
+            first.width = width - 2 * mPadding;
+            first.height = height - 2 * mPadding;
+
+            mRoot.next = first;
+            mSplitDecision = splitDecision;
+        }
+
+        @Override
+        Entry pack(int width, int height, Entry entry) {
+            Cell cell = mRoot.next;
+            Cell prev = mRoot;
+
+            while (cell != null) {
+                if (insert(cell, prev, width, height, entry)) {
+                    return entry;
+                }
+
+                prev = cell;
+                cell = cell.next;
+            }
+
+            return null;
+        }
+
+        /**
+         * Defines how the remaining empty space should be split up:
+         * vertically or horizontally.
+         */
+        private static interface SplitDecision {
+            /**
+             * Returns true if the remaining space defined by
+             * <code>freeWidth</code> and <code>freeHeight</code>
+             * should be split horizontally.
+             *
+             * @param freeWidth The rectWidth of the free space after packing a rectangle
+             * @param freeHeight The rectHeight of the free space after packing a rectangle
+             * @param rectWidth The rectWidth of the rectangle that was packed in a cell
+             * @param rectHeight The rectHeight of the rectangle that was packed in a cell
+             */
+            boolean splitHorizontal(int freeWidth, int freeHeight,
+                    int rectWidth, int rectHeight);
+        }
+
+        // Splits the free area horizontally to minimize the horizontal section area
+        private static class MinAreaSplitDecision implements SplitDecision {
+            @Override
+            public boolean splitHorizontal(int freeWidth, int freeHeight,
+                    int rectWidth, int rectHeight) {
+                return rectWidth * freeHeight > freeWidth * rectHeight;
+            }
+        }
+
+        // Splits the free area horizontally to maximize the horizontal section area
+        private static class MaxAreaSplitDecision implements SplitDecision {
+            @Override
+            public boolean splitHorizontal(int freeWidth, int freeHeight,
+                    int rectWidth, int rectHeight) {
+                return rectWidth * freeHeight <= freeWidth * rectHeight;
+            }
+        }
+
+        // Splits the free area horizontally if the horizontal axis is shorter
+        private static class ShorterFreeAxisSplitDecision implements SplitDecision {
+            @Override
+            public boolean splitHorizontal(int freeWidth, int freeHeight,
+                    int rectWidth, int rectHeight) {
+                return freeWidth <= freeHeight;
+            }
+        }
+
+        // Splits the free area horizontally if the vertical axis is shorter
+        private static class LongerFreeAxisSplitDecision implements SplitDecision {
+            @Override
+            public boolean splitHorizontal(int freeWidth, int freeHeight,
+                    int rectWidth, int rectHeight) {
+                return freeWidth > freeHeight;
+            }
+        }
+
+        /**
+         * Attempts to pack a rectangle of specified dimensions in the available
+         * empty space.
+         *
+         * @param cell The cell representing free space in which to pack the rectangle
+         * @param prev The previous cell in the free space linked list
+         * @param width The width of the rectangle to pack
+         * @param height The height of the rectangle to pack
+         * @param entry Stores the location of the packged rectangle, if it fits
+         *
+         * @return True if the rectangle was packed in the atlas, false otherwise
+         */
+        @SuppressWarnings("SuspiciousNameCombination")
+        private boolean insert(Cell cell, Cell prev, int width, int height, Entry entry) {
+            boolean rotated = false;
+
+            // If the rectangle doesn't fit we'll try to rotate it
+            // if possible before giving up
+            if (cell.width < width || cell.height < height) {
+                if (mAllowRotation) {
+                    if (cell.width < height || cell.height < width) {
+                        return false;
+                    }
+
+                    // Rotate the rectangle
+                    int temp = width;
+                    width = height;
+                    height = temp;
+                    rotated = true;
+                } else {
+                    return false;
+                }
+            }
+
+            // Remaining free space after packing the rectangle
+            int deltaWidth = cell.width - width;
+            int deltaHeight = cell.height - height;
+
+            // Split the remaining free space into two new cells
+            Cell first = new Cell();
+            Cell second = new Cell();
+
+            first.x = cell.x + width + mPadding;
+            first.y = cell.y;
+            first.width = deltaWidth - mPadding;
+
+            second.x = cell.x;
+            second.y = cell.y + height + mPadding;
+            second.height = deltaHeight - mPadding;
+
+            if (mSplitDecision.splitHorizontal(deltaWidth, deltaHeight,
+                    width, height)) {
+                first.height = height;
+                second.width = cell.width;
+            } else {
+                first.height = cell.height;
+                second.width = width;
+
+                // The order of the cells matters for efficient packing
+                // We want to give priority to the cell chosen by the
+                // split decision heuristic
+                Cell temp = first;
+                first = second;
+                second = temp;
+            }
+
+            // Remove degenerate cases to keep the free list as small as possible
+            if (first.width > 0 && first.height > 0) {
+                prev.next = first;
+                prev = first;
+            }
+
+            if (second.width > 0 && second.height > 0) {
+                prev.next = second;
+                second.next = cell.next;
+            } else {
+                prev.next = cell.next;
+            }
+
+            // The cell is now completely removed from the free list
+            cell.next = null;
+
+            // Return the location and rotation of the packed rectangle
+            entry.x = cell.x;
+            entry.y = cell.y;
+            entry.rotated = rotated;
+
+            return true;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 89abdef..4c7395c 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -46,20 +46,31 @@
     /**
      * Backing buffer for the Bitmap.
      * Made public for quick access from drawing methods -- do NOT modify
-     * from outside this class.
+     * from outside this class
      *
      * @hide
      */
+    @SuppressWarnings("UnusedDeclaration") // native code only
     public byte[] mBuffer;
 
     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
     private final BitmapFinalizer mFinalizer;
 
     private final boolean mIsMutable;
+
+    /**
+     * Represents whether the Bitmap's content is expected to be pre-multiplied.
+     * Note that isPremultiplied() does not directly return this value, because
+     * isPremultiplied() may never return true for a 565 Bitmap.
+     *
+     * setPremultiplied() does directly set the value so that setConfig() and
+     * setPremultiplied() aren't order dependent, despite being setters.
+     */
+    private boolean mIsPremultiplied;
     private byte[] mNinePatchChunk;   // may be null
     private int[] mLayoutBounds;   // may be null
-    private int mWidth = -1;
-    private int mHeight = -1;
+    private int mWidth;
+    private int mHeight;
     private boolean mRecycled;
 
     // Package-scoped for fast access.
@@ -88,38 +99,26 @@
     }
 
     /**
-     * @noinspection UnusedDeclaration
+     * Private constructor that must received an already allocated native bitmap
+     * int (pointer).
      */
-    /*  Private constructor that must received an already allocated native
-        bitmap int (pointer).
-
-        This can be called from JNI code.
-    */
-    Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
-            int density) {
-        this(nativeBitmap, buffer, isMutable, ninePatchChunk, null, density);
-    }
-
-    /**
-     * @noinspection UnusedDeclaration
-     */
-    /*  Private constructor that must received an already allocated native
-        bitmap int (pointer).
-
-        This can be called from JNI code.
-    */
-    Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
-            int[] layoutBounds, int density) {
+    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+    Bitmap(int nativeBitmap, byte[] buffer, int width, int height, int density,
+            boolean isMutable, boolean isPremultiplied,
+            byte[] ninePatchChunk, int[] layoutBounds) {
         if (nativeBitmap == 0) {
             throw new RuntimeException("internal error: native bitmap is 0");
         }
 
+        mWidth = width;
+        mHeight = height;
+        mIsMutable = isMutable;
+        mIsPremultiplied = isPremultiplied;
         mBuffer = buffer;
         // we delete this in our finalizer
         mNativeBitmap = nativeBitmap;
         mFinalizer = new BitmapFinalizer(nativeBitmap);
 
-        mIsMutable = isMutable;
         mNinePatchChunk = ninePatchChunk;
         mLayoutBounds = layoutBounds;
         if (density >= 0) {
@@ -128,6 +127,17 @@
     }
 
     /**
+     * Native bitmap has been reconfigured, so set premult and cached
+     * width/height values
+     */
+    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+    void reinit(int width, int height, boolean isPremultiplied) {
+        mWidth = width;
+        mHeight = height;
+        mIsPremultiplied = isPremultiplied;
+    }
+
+    /**
      * <p>Returns the density for this bitmap.</p>
      *
      * <p>The default density is the same density as the current display,
@@ -167,7 +177,98 @@
     public void setDensity(int density) {
         mDensity = density;
     }
-    
+
+    /**
+     * <p>Modifies the bitmap to have a specified width, height, and {@link
+     * Config}, without affecting the underlying allocation backing the bitmap.
+     * Bitmap pixel data is not re-initialized for the new configuration.</p>
+     *
+     * <p>This method can be used to avoid allocating a new bitmap, instead
+     * reusing an existing bitmap's allocation for a new configuration of equal
+     * or lesser size. If the Bitmap's allocation isn't large enough to support
+     * the new configuration, an IllegalArgumentException will be thrown and the
+     * bitmap will not be modified.</p>
+     *
+     * <p>The result of {@link #getByteCount()} will reflect the new configuration,
+     * while {@link #getAllocationByteCount()} will reflect that of the initial
+     * configuration.</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
+     * reused. Additionally, the view system does not account for bitmap
+     * properties being modifying during use, e.g. while attached to
+     * drawables.</p>
+     *
+     * @see #setWidth(int)
+     * @see #setHeight(int)
+     * @see #setConfig(Config)
+     */
+    public void reconfigure(int width, int height, Config config) {
+        checkRecycled("Can't call reconfigure() on a recycled bitmap");
+        if (width <= 0 || height <= 0) {
+            throw new IllegalArgumentException("width and height must be > 0");
+        }
+        if (!isMutable()) {
+            throw new IllegalStateException("only mutable bitmaps may be reconfigured");
+        }
+        if (mBuffer == null) {
+            throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
+        }
+
+        nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length);
+        mWidth = width;
+        mHeight = height;
+    }
+
+    /**
+     * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
+     * with the current height and config.</p>
+     *
+     * <p>WARNING: this method should not be used on bitmaps currently used by
+     * the view system, see {@link #reconfigure(int, int, Config)} for more
+     * details.</p>
+     *
+     * @see #reconfigure(int, int, Config)
+     * @see #setHeight(int)
+     * @see #setConfig(Config)
+     */
+    public void setWidth(int width) {
+        reconfigure(width, getHeight(), getConfig());
+    }
+
+    /**
+     * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
+     * with the current width and config.</p>
+     *
+     * <p>WARNING: this method should not be used on bitmaps currently used by
+     * the view system, see {@link #reconfigure(int, int, Config)} for more
+     * details.</p>
+     *
+     * @see #reconfigure(int, int, Config)
+     * @see #setWidth(int)
+     * @see #setConfig(Config)
+     */
+    public void setHeight(int height) {
+        reconfigure(getWidth(), height, getConfig());
+    }
+
+    /**
+     * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
+     * with the current height and width.</p>
+     *
+     * <p>WARNING: this method should not be used on bitmaps currently used by
+     * the view system, see {@link #reconfigure(int, int, Config)} for more
+     * details.</p>
+     *
+     * @see #reconfigure(int, int, Config)
+     * @see #setWidth(int)
+     * @see #setHeight(int)
+     */
+    public void setConfig(Config config) {
+        reconfigure(getWidth(), getHeight(), config);
+    }
+
     /**
      * Sets the nine patch chunk.
      *
@@ -318,6 +419,10 @@
          * 
          * It is recommended to use {@link #ARGB_8888} instead of this
          * configuration.
+         *
+         * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT},
+         * any bitmap created with this configuration will be created
+         * using {@link #ARGB_8888} instead.
          * 
          * @deprecated Because of the poor quality of this configuration,
          *             it is advised to use {@link #ARGB_8888} instead.
@@ -449,6 +554,7 @@
         checkRecycled("Can't copy a recycled bitmap");
         Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
         if (b != null) {
+            b.mIsPremultiplied = mIsPremultiplied;
             b.mDensity = mDensity;
         }
         return b;
@@ -457,7 +563,7 @@
     /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
      * specified width and height are the same as the current width and height of 
-     * the source btimap, the source bitmap is returned and now new bitmap is
+     * the source bitmap, the source bitmap is returned and no new bitmap is
      * created.
      *
      * @param src       The source bitmap.
@@ -465,6 +571,7 @@
      * @param dstHeight The new bitmap's desired height.
      * @param filter    true if the source should be filtered.
      * @return The new scaled bitmap or the source bitmap if no scaling is required.
+     * @throws IllegalArgumentException if width is <= 0, or height is <= 0
      */
     public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
             boolean filter) {
@@ -517,6 +624,9 @@
      * @param width    The number of pixels in each row
      * @param height   The number of rows
      * @return A copy of a subset of the source bitmap or the source bitmap itself.
+     * @throws IllegalArgumentException if the x, y, width, height values are
+     *         outside of the dimensions of the source bitmap, or width is <= 0,
+     *         or height is <= 0
      */
     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
         return createBitmap(source, x, y, width, height, null, false);
@@ -543,7 +653,8 @@
      *                   translation.
      * @return A bitmap that represents the specified subset of source
      * @throws IllegalArgumentException if the x, y, width, height values are
-     *         outside of the dimensions of the source bitmap.
+     *         outside of the dimensions of the source bitmap, or width is <= 0,
+     *         or height is <= 0
      */
     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
             Matrix m, boolean filter) {
@@ -620,6 +731,7 @@
         // The new bitmap was created from a known bitmap source so assume that
         // they use the same density
         bitmap.mDensity = source.mDensity;
+        bitmap.mIsPremultiplied = source.mIsPremultiplied;
         
         canvas.setBitmap(bitmap);
         canvas.drawBitmap(source, srcR, dstR, paint);
@@ -701,12 +813,10 @@
         if (config == Config.ARGB_8888 && !hasAlpha) {
             nativeErase(bm.mNativeBitmap, 0xff000000);
             nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
-        } else {
-            // No need to initialize it to zeroes; it is backed by a VM byte array
-            // which is by definition preinitialized to all zeroes.
-            //
-            //nativeErase(bm.mNativeBitmap, 0);
         }
+        // No need to initialize the bitmap to zeroes with other configs;
+        // it is backed by a VM byte array which is by definition preinitialized
+        // to all zeroes.
         return bm;
     }
 
@@ -904,22 +1014,48 @@
      * <p>This method only returns true if {@link #hasAlpha()} returns true.
      * A bitmap with no alpha channel can be used both as a pre-multiplied and
      * as a non pre-multiplied bitmap.</p>
-     * 
+     *
+     * <p>Only pre-multiplied bitmaps may be drawn by the view system or
+     * {@link Canvas}. If a non-pre-multiplied bitmap with an alpha channel is
+     * drawn to a Canvas, a RuntimeException will be thrown.</p>
+     *
      * @return true if the underlying pixels have been pre-multiplied, false
      *         otherwise
+     *
+     * @see Bitmap#setPremultiplied(boolean)
+     * @see BitmapFactory.Options#inPremultiplied
      */
     public final boolean isPremultiplied() {
-        return getConfig() != Config.RGB_565 && hasAlpha();
+        return mIsPremultiplied && getConfig() != Config.RGB_565 && hasAlpha();
+    }
+
+    /**
+     * Sets whether the bitmap should treat its data as pre-multiplied.
+     *
+     * <p>Bitmaps are always treated as pre-multiplied by the view system and
+     * {@link Canvas} for performance reasons. Storing un-pre-multiplied data in
+     * a Bitmap (through {@link #setPixel}, {@link #setPixels}, or {@link
+     * BitmapFactory.Options#inPremultiplied BitmapFactory.Options.inPremultiplied})
+     * can lead to incorrect blending if drawn by the framework.</p>
+     *
+     * <p>This method will not affect the behavior of a bitmap without an alpha
+     * channel, or if {@link #hasAlpha()} returns false.</p>
+     *
+     * @see Bitmap#isPremultiplied()
+     * @see BitmapFactory.Options#inPremultiplied
+     */
+    public final void setPremultiplied(boolean premultiplied) {
+        mIsPremultiplied = premultiplied;
     }
 
     /** Returns the bitmap's width */
     public final int getWidth() {
-        return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth;
+        return mWidth;
     }
 
     /** Returns the bitmap's height */
     public final int getHeight() {
-        return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
+        return mHeight;
     }
 
     /**
@@ -994,6 +1130,10 @@
      * getPixels() or setPixels(), then the pixels are uniformly treated as
      * 32bit values, packed according to the Color class.
      *
+     * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, this method
+     * should not be used to calculate the memory usage of the bitmap. Instead,
+     * see {@link #getAllocationByteCount()}.
+     *
      * @return number of bytes between rows of the native bitmap pixels.
      */
     public final int getRowBytes() {
@@ -1001,7 +1141,11 @@
     }
 
     /**
-     * Returns the number of bytes used to store this bitmap's pixels.
+     * Returns the minimum number of bytes that can be used to store this bitmap's pixels.
+     *
+     * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
+     * no longer be used to determine memory usage of a bitmap. See {@link
+     * #getAllocationByteCount()}.</p>
      */
     public final int getByteCount() {
         // int result permits bitmaps up to 46,340 x 46,340
@@ -1009,6 +1153,24 @@
     }
 
     /**
+     * Returns the size of the allocated memory used to store this bitmap's pixels.
+     *
+     * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
+     * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
+     * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
+     * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
+     * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
+     * the same as that returned by {@link #getByteCount()}.</p>
+     *
+     * <p>This value will not change over the lifetime of a Bitmap.</p>
+     *
+     * @see #reconfigure(int, int, Config)
+     */
+    public final int getAllocationByteCount() {
+        return mBuffer.length;
+    }
+
+    /**
      * If the bitmap's internal config is in one of the public formats, return
      * that config, otherwise return null.
      */
@@ -1113,7 +1275,7 @@
     public int getPixel(int x, int y) {
         checkRecycled("Can't call getPixel() on a recycled bitmap");
         checkPixelAccess(x, y);
-        return nativeGetPixel(mNativeBitmap, x, y);
+        return nativeGetPixel(mNativeBitmap, x, y, mIsPremultiplied);
     }
 
     /**
@@ -1147,7 +1309,7 @@
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
         nativeGetPixels(mNativeBitmap, pixels, offset, stride,
-                        x, y, width, height);
+                        x, y, width, height, mIsPremultiplied);
     }
 
     /**
@@ -1227,7 +1389,7 @@
             throw new IllegalStateException();
         }
         checkPixelAccess(x, y);
-        nativeSetPixel(mNativeBitmap, x, y, color);
+        nativeSetPixel(mNativeBitmap, x, y, color, mIsPremultiplied);
     }
 
     /**
@@ -1264,7 +1426,7 @@
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
         nativeSetPixels(mNativeBitmap, pixels, offset, stride,
-                        x, y, width, height);
+                        x, y, width, height, mIsPremultiplied);
     }
 
     public static final Parcelable.Creator<Bitmap> CREATOR
@@ -1400,31 +1562,32 @@
 
     private static native Bitmap nativeCreate(int[] colors, int offset,
                                               int stride, int width, int height,
-                                            int nativeConfig, boolean mutable);
+                                              int nativeConfig, boolean mutable);
     private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
                                             boolean isMutable);
     private static native void nativeDestructor(int nativeBitmap);
     private static native boolean nativeRecycle(int nativeBitmap);
+    private static native void nativeReconfigure(int nativeBitmap, int width, int height,
+                                                 int config, int allocSize);
 
     private static native boolean nativeCompress(int nativeBitmap, int format,
                                             int quality, OutputStream stream,
                                             byte[] tempStorage);
     private static native void nativeErase(int nativeBitmap, int color);
-    private static native int nativeWidth(int nativeBitmap);
-    private static native int nativeHeight(int nativeBitmap);
     private static native int nativeRowBytes(int nativeBitmap);
     private static native int nativeConfig(int nativeBitmap);
 
-    private static native int nativeGetPixel(int nativeBitmap, int x, int y);
+    private static native int nativeGetPixel(int nativeBitmap, int x, int y,
+                                             boolean isPremultiplied);
     private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
-                                               int offset, int stride, int x,
-                                               int y, int width, int height);
+                                               int offset, int stride, int x, int y,
+                                               int width, int height, boolean isPremultiplied);
 
     private static native void nativeSetPixel(int nativeBitmap, int x, int y,
-                                              int color);
+                                              int color, boolean isPremultiplied);
     private static native void nativeSetPixels(int nativeBitmap, int[] colors,
-                                               int offset, int stride, int x,
-                                               int y, int width, int height);
+                                               int offset, int stride, int x, int y,
+                                               int width, int height, boolean isPremultiplied);
     private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
                                                         Buffer dst);
     private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src);
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index f155cd2..a7c5b20 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,11 +18,11 @@
 
 import android.content.res.AssetManager;
 import android.content.res.Resources;
+import android.os.Trace;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
 
-import java.io.BufferedInputStream;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -43,28 +43,59 @@
         public Options() {
             inDither = false;
             inScaled = true;
+            inPremultiplied = true;
         }
 
         /**
          * If set, decode methods that take the Options object will attempt to
-         * reuse this bitmap when loading content. If the decode operation cannot
-         * use this bitmap, the decode method will return <code>null</code> and
-         * will throw an IllegalArgumentException. The current implementation
-         * necessitates that the reused bitmap be mutable and of the same size as the
-         * source content. The source content must be in jpeg or png format (whether as
-         * a resource or as a stream). The {@link android.graphics.Bitmap.Config
-         * configuration} of the reused bitmap will override the setting of
-         * {@link #inPreferredConfig}, if set. The reused bitmap will continue to
-         * remain mutable even when decoding a resource which would normally result
-         * in an immutable bitmap.
+         * reuse this bitmap when loading content. If the decode operation
+         * cannot use this bitmap, the decode method will return
+         * <code>null</code> and will throw an IllegalArgumentException. The
+         * current implementation necessitates that the reused bitmap be
+         * mutable, and the resulting reused bitmap will continue to remain
+         * mutable even when decoding a resource which would normally result in
+         * an immutable bitmap.</p>
          *
          * <p>You should still always use the returned Bitmap of the decode
          * method and not assume that reusing the bitmap worked, due to the
          * constraints outlined above and failure situations that can occur.
          * Checking whether the return value matches the value of the inBitmap
-         * set in the Options structure is a way to see if the bitmap was reused,
-         * but in all cases you should use the returned Bitmap to make sure
-         * that you are using the bitmap that was used as the decode destination.</p>
+         * set in the Options structure will indicate if the bitmap was reused,
+         * but in all cases you should use the Bitmap returned by the decoding
+         * function to ensure that you are using the bitmap that was used as the
+         * decode destination.</p>
+         *
+         * <h3>Usage with BitmapFactory</h3>
+         *
+         * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, any
+         * mutable bitmap can be reused by {@link BitmapFactory} to decode any
+         * other bitmaps as long as the resulting {@link Bitmap#getByteCount()
+         * byte count} of the decoded bitmap is less than or equal to the {@link
+         * Bitmap#getAllocationByteCount() allocated byte count} of the reused
+         * bitmap. This can be because the intrinsic size is smaller, or its
+         * size post scaling (for density / sample size) is smaller.</p>
+         *
+         * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT}
+         * additional constraints apply: The image being decoded (whether as a
+         * resource or as a stream) must be in jpeg or png format. Only equal
+         * sized bitmaps are supported, with {@link #inSampleSize} set to 1.
+         * Additionally, the {@link android.graphics.Bitmap.Config
+         * configuration} of the reused bitmap will override the setting of
+         * {@link #inPreferredConfig}, if set.</p>
+         *
+         * <h3>Usage with BitmapRegionDecoder</h3>
+         *
+         * <p>BitmapRegionDecoder will draw its requested content into the Bitmap
+         * provided, clipping if the output content size (post scaling) is larger
+         * than the provided Bitmap. The provided Bitmap's width, height, and
+         * {@link Bitmap.Config} will not be changed.
+         *
+         * <p class="note">BitmapRegionDecoder support for {@link #inBitmap} was
+         * introduced in {@link android.os.Build.VERSION_CODES#JELLY_BEAN}. All
+         * formats supported by BitmapRegionDecoder support Bitmap reuse via
+         * {@link #inBitmap}.</p>
+         *
+         * @see Bitmap#reconfigure(int,int, android.graphics.Bitmap.Config)
          */
         public Bitmap inBitmap;
 
@@ -108,6 +139,26 @@
         public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
 
         /**
+         * If true (which is the default), the resulting bitmap will have its
+         * color channels pre-multipled by the alpha channel.
+         *
+         * <p>This should NOT be set to false for images to be directly drawn by
+         * the view system or through a {@link Canvas}. The view system and
+         * {@link Canvas} assume all drawn images are pre-multiplied to simplify
+         * draw-time blending, and will throw a RuntimeException when
+         * un-premultiplied are drawn.</p>
+         *
+         * <p>This is likely only useful if you want to manipulate raw encoded
+         * image data, e.g. with RenderScript or custom OpenGL.</p>
+         *
+         * <p>This does not affect bitmaps without an alpha channel.</p>
+         *
+         * @see Bitmap#hasAlpha()
+         * @see Bitmap#isPremultiplied()
+         */
+        public boolean inPremultiplied;
+
+        /**
          * If dither is true, the decoder will attempt to dither the decoded
          * image.
          */
@@ -192,6 +243,9 @@
          * rather than relying on the graphics system scaling it each time it
          * is drawn to a Canvas.
          *
+         * <p>BitmapRegionDecoder ignores this flag, and will not scale output
+         * based on density. (though {@link #inSampleSize} is supported)</p>
+         *
          * <p>This flag is turned on by default and should be turned off if you need
          * a non-scaled version of the bitmap.  Nine-patch bitmaps ignore this
          * flag and are always scaled.
@@ -426,11 +480,21 @@
         if ((offset | length) < 0 || data.length < offset + length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        Bitmap bm = nativeDecodeByteArray(data, offset, length, opts);
 
-        if (bm == null && opts != null && opts.inBitmap != null) {
-            throw new IllegalArgumentException("Problem decoding into existing bitmap");
+        Bitmap bm;
+
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
+        try {
+            bm = nativeDecodeByteArray(data, offset, length, opts);
+
+            if (bm == null && opts != null && opts.inBitmap != null) {
+                throw new IllegalArgumentException("Problem decoding into existing bitmap");
+            }
+            setDensityFromOptions(bm, opts);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
         }
+
         return bm;
     }
 
@@ -448,6 +512,31 @@
     }
 
     /**
+     * Set the newly decoded bitmap's density based on the Options.
+     */
+    private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
+        if (outputBitmap == null || opts == null) return;
+
+        final int density = opts.inDensity;
+        if (density != 0) {
+            outputBitmap.setDensity(density);
+            final int targetDensity = opts.inTargetDensity;
+            if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
+                return;
+            }
+
+            byte[] np = outputBitmap.getNinePatchChunk();
+            final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
+            if (opts.inScaled || isNinePatch) {
+                outputBitmap.setDensity(targetDensity);
+            }
+        } else if (opts.inBitmap != null) {
+            // bitmap was reused, ensure density is reset
+            outputBitmap.setDensity(Bitmap.getDefaultDensity());
+        }
+    }
+
+    /**
      * Decode an input stream into a bitmap. If the input stream is null, or
      * cannot be used to decode a bitmap, the function returns null.
      * The stream's position will be where ever it was after the encoded data
@@ -464,6 +553,11 @@
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded, or, if opts is non-null, if opts requested only the
      *         size be returned (in opts.outWidth and opts.outHeight)
+     *
+     * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
+     * if {@link InputStream#markSupported is.markSupported()} returns true,
+     * <code>is.mark(1024)</code> would be called. As of
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
      */
     public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
         // we don't throw in this case, thus allowing the caller to only check
@@ -472,123 +566,41 @@
             return null;
         }
 
-        // we need mark/reset to work properly
+        Bitmap bm = null;
 
-        if (!is.markSupported()) {
-            is = new BufferedInputStream(is, DECODE_BUFFER_SIZE);
-        }
-
-        // so we can call reset() if a given codec gives up after reading up to
-        // this many bytes. FIXME: need to find out from the codecs what this
-        // value should be.
-        is.mark(1024);
-
-        Bitmap bm;
-        boolean finish = true;
-
-        if (is instanceof AssetManager.AssetInputStream) {
-            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
-
-            if (opts == null || (opts.inScaled && opts.inBitmap == null)) {
-                float scale = 1.0f;
-                int targetDensity = 0;
-                if (opts != null) {
-                    final int density = opts.inDensity;
-                    targetDensity = opts.inTargetDensity;
-                    if (density != 0 && targetDensity != 0) {
-                        scale = targetDensity / (float) density;
-                    }
-                }
-
-                bm = nativeDecodeAsset(asset, outPadding, opts, true, scale);
-                if (bm != null && targetDensity != 0) bm.setDensity(targetDensity);
-
-                finish = false;
-            } else {
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
+        try {
+            if (is instanceof AssetManager.AssetInputStream) {
+                final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
                 bm = nativeDecodeAsset(asset, outPadding, opts);
-            }
-        } else {
-            // pass some temp storage down to the native code. 1024 is made up,
-            // but should be large enough to avoid too many small calls back
-            // into is.read(...) This number is not related to the value passed
-            // to mark(...) above.
-            byte [] tempStorage = null;
-            if (opts != null) tempStorage = opts.inTempStorage;
-            if (tempStorage == null) tempStorage = new byte[16 * 1024];
-
-            if (opts == null || (opts.inScaled && opts.inBitmap == null)) {
-                float scale = 1.0f;
-                int targetDensity = 0;
-                if (opts != null) {
-                    final int density = opts.inDensity;
-                    targetDensity = opts.inTargetDensity;
-                    if (density != 0 && targetDensity != 0) {
-                        scale = targetDensity / (float) density;
-                    }
-                }
-
-                bm = nativeDecodeStream(is, tempStorage, outPadding, opts, true, scale);
-                if (bm != null && targetDensity != 0) bm.setDensity(targetDensity);
-
-                finish = false;
             } else {
-                bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
-            }
-        }
-
-        if (bm == null && opts != null && opts.inBitmap != null) {
-            throw new IllegalArgumentException("Problem decoding into existing bitmap");
-        }
-
-        return finish ? finishDecode(bm, outPadding, opts) : bm;
-    }
-
-    private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
-        if (bm == null || opts == null) {
-            return bm;
-        }
-        
-        final int density = opts.inDensity;
-        if (density == 0) {
-            return bm;
-        }
-        
-        bm.setDensity(density);
-        final int targetDensity = opts.inTargetDensity;
-        if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
-            return bm;
-        }
-        byte[] np = bm.getNinePatchChunk();
-        int[] lb = bm.getLayoutBounds();
-        final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
-        if (opts.inScaled || isNinePatch) {
-            float scale = targetDensity / (float) density;
-            if (scale != 1.0f) {
-                final Bitmap oldBitmap = bm;
-                bm = Bitmap.createScaledBitmap(oldBitmap,
-                        Math.max(1, (int) (bm.getWidth() * scale + 0.5f)),
-                        Math.max(1, (int) (bm.getHeight() * scale + 0.5f)), true);
-                if (bm != oldBitmap) oldBitmap.recycle();
-
-                if (isNinePatch) {
-                    np = nativeScaleNinePatch(np, scale, outPadding);
-                    bm.setNinePatchChunk(np);
-                }
-                if (lb != null) {
-                    int[] newLb = new int[lb.length];
-                    for (int i=0; i<lb.length; i++) {
-                        newLb[i] = (int)((lb[i]*scale)+.5f);
-                    }
-                    bm.setLayoutBounds(newLb);
-                }
+                bm = decodeStreamInternal(is, outPadding, opts);
             }
 
-            bm.setDensity(targetDensity);
+            if (bm == null && opts != null && opts.inBitmap != null) {
+                throw new IllegalArgumentException("Problem decoding into existing bitmap");
+            }
+
+            setDensityFromOptions(bm, opts);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
         }
 
         return bm;
     }
-    
+
+    /**
+     * Private helper function for decoding an InputStream natively. Buffers the input enough to
+     * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
+     */
+    private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+        // ASSERT(is != null);
+        byte [] tempStorage = null;
+        if (opts != null) tempStorage = opts.inTempStorage;
+        if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
+        return nativeDecodeStream(is, tempStorage, outPadding, opts);
+    }
+
     /**
      * Decode an input stream into a bitmap. If the input stream is null, or
      * cannot be used to decode a bitmap, the function returns null.
@@ -614,26 +626,36 @@
      *                   no bitmap is returned (null) then padding is
      *                   unchanged.
      * @param opts null-ok; Options that control downsampling and whether the
-     *             image should be completely decoded, or just is size returned.
+     *             image should be completely decoded, or just its size returned.
      * @return the decoded bitmap, or null
      */
     public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
-        if (nativeIsSeekable(fd)) {
-            Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+        Bitmap bm;
+
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeFileDescriptor");
+        try {
+            if (nativeIsSeekable(fd)) {
+                bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+            } else {
+                FileInputStream fis = new FileInputStream(fd);
+                try {
+                    bm = decodeStreamInternal(fis, outPadding, opts);
+                } finally {
+                    try {
+                        fis.close();
+                    } catch (Throwable t) {/* ignore */}
+                }
+            }
+
             if (bm == null && opts != null && opts.inBitmap != null) {
                 throw new IllegalArgumentException("Problem decoding into existing bitmap");
             }
-            return finishDecode(bm, outPadding, opts);
-        } else {
-            FileInputStream fis = new FileInputStream(fd);
-            try {
-                return decodeStream(fis, outPadding, opts);
-            } finally {
-                try {
-                    fis.close();
-                } catch (Throwable t) {/* ignore */}
-            }
+
+            setDensityFromOptions(bm, opts);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
         }
+        return bm;
     }
 
     /**
@@ -650,15 +672,10 @@
 
     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
             Rect padding, Options opts);
-    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
-            Rect padding, Options opts, boolean applyScale, float scale);
     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
             Rect padding, Options opts);
     private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
-    private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts,
-            boolean applyScale, float scale);
     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
             int length, Options opts);
-    private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
     private static native boolean nativeIsSeekable(FileDescriptor fd);
 }
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index b38d107..3a99977 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -17,7 +17,6 @@
 
 import android.content.res.AssetManager;
 
-import java.io.BufferedInputStream;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -105,15 +104,14 @@
      *                    allowing sharing may degrade the decoding speed.
      * @return BitmapRegionDecoder, or null if the image data could not be decoded.
      * @throws IOException if the image format is not supported or can not be decoded.
+     *
+     * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
+     * if {@link InputStream#markSupported is.markSupported()} returns true,
+     * <code>is.mark(1024)</code> would be called. As of
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
      */
     public static BitmapRegionDecoder newInstance(InputStream is,
             boolean isShareable) throws IOException {
-        // we need mark/reset to work properly in JNI
-
-        if (!is.markSupported()) {
-            is = new BufferedInputStream(is, 16 * 1024);
-        }
-
         if (is instanceof AssetManager.AssetInputStream) {
             return nativeNewInstance(
                     ((AssetManager.AssetInputStream) is).getAssetInt(),
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index f74d0ef..a4f75b9 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -28,6 +28,9 @@
     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
     public final Bitmap mBitmap;
 
+    private TileMode mTileX;
+    private TileMode mTileY;
+
     /**
      * Call this to create a new shader that will draw with a bitmap.
      *
@@ -37,11 +40,23 @@
      */
     public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
         mBitmap = bitmap;
+        mTileX = tileX;
+        mTileY = tileY;
         final int b = bitmap.ni();
         native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
         native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final BitmapShader copy = new BitmapShader(mBitmap, mTileX, mTileY);
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
     private static native int nativeCreate(int native_bitmap, int shaderTileModeX,
             int shaderTileModeY);
     private static native int nativePostCreate(int native_shader, int native_bitmap,
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index 6f71a2b..9e07bd4 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -22,6 +22,8 @@
  * {@link Canvas}.
  */
 public class Camera {
+    private Matrix mMatrix;
+
     /**
      * Creates a new camera, with empty transformations.
      */
@@ -147,7 +149,13 @@
      * @param canvas The Canvas to set the transform matrix onto
      */
     public void applyToCanvas(Canvas canvas) {
-        nativeApplyToCanvas(canvas.mNativeCanvas);
+        if (canvas.isHardwareAccelerated()) {
+            if (mMatrix == null) mMatrix = new Matrix();
+            getMatrix(mMatrix);
+            canvas.concat(mMatrix);
+        } else {
+            nativeApplyToCanvas(canvas.mNativeCanvas);
+        }
     }
 
     public native float dotWithNormal(float dx, float dy, float dz);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index c851844..d46238f 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -37,12 +37,14 @@
  * Canvas and Drawables</a> developer guide.</p></div>
  */
 public class Canvas {
+
     // assigned in constructors or setBitmap, freed in finalizer
-    int mNativeCanvas;
-    
+    /** @hide */
+    public int mNativeCanvas;
+
     // may be null
     private Bitmap mBitmap;
-    
+
     // optional field set by the caller
     private DrawFilter mDrawFilter;
 
@@ -59,7 +61,7 @@
     protected int mScreenDensity = Bitmap.DENSITY_NONE;
     
     // Used by native code
-    @SuppressWarnings({"UnusedDeclaration"})
+    @SuppressWarnings("UnusedDeclaration")
     private int mSurfaceFormat;
 
     /**
@@ -79,10 +81,9 @@
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
 
     // This field is used to finalize the native Canvas properly
-    @SuppressWarnings({"UnusedDeclaration"})
     private final CanvasFinalizer mFinalizer;
 
-    private static class CanvasFinalizer {
+    private static final class CanvasFinalizer {
         private int mNativeCanvas;
 
         public CanvasFinalizer(int nativeCanvas) {
@@ -92,13 +93,18 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                if (mNativeCanvas != 0) {
-                    finalizer(mNativeCanvas);
-                }
+                dispose();
             } finally {
                 super.finalize();
             }
         }
+
+        public void dispose() {
+            if (mNativeCanvas != 0) {
+                finalizer(mNativeCanvas);
+                mNativeCanvas = 0;
+            }
+        }
     }
 
     /**
@@ -108,9 +114,13 @@
      * canvas.
      */
     public Canvas() {
-        // 0 means no native bitmap
-        mNativeCanvas = initRaster(0);
-        mFinalizer = new CanvasFinalizer(mNativeCanvas);
+        if (!isHardwareAccelerated()) {
+            // 0 means no native bitmap
+            mNativeCanvas = initRaster(0);
+            mFinalizer = new CanvasFinalizer(mNativeCanvas);
+        } else {
+            mFinalizer = null;
+        }
     }
 
     /**
@@ -126,19 +136,20 @@
         if (!bitmap.isMutable()) {
             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
         }
-        throwIfRecycled(bitmap);
+        throwIfCannotDraw(bitmap);
         mNativeCanvas = initRaster(bitmap.ni());
         mFinalizer = new CanvasFinalizer(mNativeCanvas);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
     }
-    
-    Canvas(int nativeCanvas) {
+
+    /** @hide */
+    public Canvas(int nativeCanvas) {
         if (nativeCanvas == 0) {
             throw new IllegalStateException();
         }
         mNativeCanvas = nativeCanvas;
-        mFinalizer = new CanvasFinalizer(nativeCanvas);
+        mFinalizer = new CanvasFinalizer(mNativeCanvas);
         mDensity = Bitmap.getDefaultDensity();
     }
 
@@ -155,7 +166,18 @@
         }
         finalizer(oldCanvas);
     }
-    
+
+    /**
+     * Gets the native canvas pointer.
+     *
+     * @return The native pointer.
+     *
+     * @hide
+     */
+    public int getNativeCanvas() {
+        return mNativeCanvas;
+    }
+
     /**
      * Returns null.
      * 
@@ -203,7 +225,7 @@
             if (!bitmap.isMutable()) {
                 throw new IllegalStateException();
             }
-            throwIfRecycled(bitmap);
+            throwIfCannotDraw(bitmap);
 
             safeCanvasSwap(initRaster(bitmap.ni()), true);
             mDensity = bitmap.mDensity;
@@ -364,8 +386,8 @@
      */
     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
         return native_saveLayer(mNativeCanvas, bounds,
-                                paint != null ? paint.mNativePaint : 0,
-                                saveFlags);
+                paint != null ? paint.mNativePaint : 0,
+                saveFlags);
     }
     
     /**
@@ -374,8 +396,8 @@
     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
             int saveFlags) {
         return native_saveLayer(mNativeCanvas, left, top, right, bottom,
-                                paint != null ? paint.mNativePaint : 0,
-                                saveFlags);
+                paint != null ? paint.mNativePaint : 0,
+                saveFlags);
     }
 
     /**
@@ -495,12 +517,13 @@
     public native void skew(float sx, float sy);
 
     /**
-     * Preconcat the current matrix with the specified matrix.
+     * Preconcat the current matrix with the specified matrix. If the specified
+     * matrix is null, this method does nothing.
      *
      * @param matrix The matrix to preconcatenate with the current matrix
      */
     public void concat(Matrix matrix) {
-        native_concat(mNativeCanvas, matrix.native_instance);
+        if (matrix != null) native_concat(mNativeCanvas, matrix.native_instance);
     }
     
     /**
@@ -1022,7 +1045,7 @@
             throw new NullPointerException();
         }
         native_drawArc(mNativeCanvas, oval, startAngle, sweepAngle,
-                       useCenter, paint.mNativePaint);
+                useCenter, paint.mNativePaint);
     }
 
     /**
@@ -1052,28 +1075,47 @@
     public void drawPath(Path path, Paint paint) {
         native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint);
     }
-    
-    private static void throwIfRecycled(Bitmap bitmap) {
+
+    /**
+     * @hide
+     */
+    protected static void throwIfCannotDraw(Bitmap bitmap) {
         if (bitmap.isRecycled()) {
             throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap);
         }
+        if (!bitmap.isPremultiplied() && bitmap.getConfig() == Bitmap.Config.ARGB_8888 &&
+                bitmap.hasAlpha()) {
+            throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap "
+                    + bitmap);
+        }
     }
 
     /**
      * Draws the specified bitmap as an N-patch (most often, a 9-patches.)
      *
-     * Note: Only supported by hardware accelerated canvas at the moment.
-     *
-     * @param bitmap The bitmap to draw as an N-patch
-     * @param chunks The patches information (matches the native struct Res_png_9patch)
+     * @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(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
-    }    
-    
+    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+        patch.drawSoftware(this, dst, paint);
+    }
+
+    /**
+     * Draws the specified bitmap as an N-patch (most often, a 9-patches.)
+     *
+     * @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, RectF dst, 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.
@@ -1094,7 +1136,7 @@
      * @param paint  The paint used to draw the bitmap (may be null)
      */
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
-        throwIfRecycled(bitmap);
+        throwIfCannotDraw(bitmap);
         native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
                 paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity);
     }
@@ -1125,7 +1167,7 @@
         if (dst == null) {
             throw new NullPointerException();
         }
-        throwIfRecycled(bitmap);
+        throwIfCannotDraw(bitmap);
         native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
                           paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
     }
@@ -1156,9 +1198,9 @@
         if (dst == null) {
             throw new NullPointerException();
         }
-        throwIfRecycled(bitmap);
+        throwIfCannotDraw(bitmap);
         native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
-                          paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
+                paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
     }
     
     /**
@@ -1279,8 +1321,8 @@
             checkRange(colors.length, colorOffset, count);
         }
         nativeDrawBitmapMesh(mNativeCanvas, bitmap.ni(), meshWidth, meshHeight,
-                             verts, vertOffset, colors, colorOffset,
-                             paint != null ? paint.mNativePaint : 0);
+                verts, vertOffset, colors, colorOffset,
+                paint != null ? paint.mNativePaint : 0);
     }
 
     public enum VertexMode {
@@ -1342,8 +1384,8 @@
             checkRange(indices.length, indexOffset, indexCount);
         }
         nativeDrawVertices(mNativeCanvas, mode.nativeInt, vertexCount, verts,
-                           vertOffset, texs, texOffset, colors, colorOffset,
-                          indices, indexOffset, indexCount, paint.mNativePaint);
+                vertOffset, texs, texOffset, colors, colorOffset,
+                indices, indexOffset, indexCount, paint.mNativePaint);
     }
     
     /**
@@ -1414,10 +1456,10 @@
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
             native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
-                            paint.mBidiFlags, paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawText(this, start, end, x, y,
-                                                     paint);
+                    paint);
         } else {
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
@@ -1538,7 +1580,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawPosText(mNativeCanvas, text, index, count, pos,
-                           paint.mNativePaint);
+                paint.mNativePaint);
     }
 
     /**
@@ -1579,8 +1621,8 @@
             throw new ArrayIndexOutOfBoundsException();
         }
         native_drawTextOnPath(mNativeCanvas, text, index, count,
-                              path.ni(), hOffset, vOffset,
-                              paint.mBidiFlags, paint.mNativePaint);
+                path.ni(), hOffset, vOffset,
+                paint.mBidiFlags, paint.mNativePaint);
     }
 
     /**
@@ -1616,7 +1658,9 @@
      */
     public void drawPicture(Picture picture) {
         picture.endRecording();
-        native_drawPicture(mNativeCanvas, picture.ni());
+        int restoreCount = save();
+        picture.draw(this);
+        restoreToCount(restoreCount);
     }
     
     /**
@@ -1647,6 +1691,15 @@
     }
 
     /**
+     * Releases the resources associated with this canvas.
+     *
+     * @hide
+     */
+    public void release() {
+        mFinalizer.dispose();
+    }
+
+    /**
      * Free up as much memory as possible from private caches (e.g. fonts, images)
      *
      * @hide
@@ -1792,7 +1845,5 @@
                                                      float hOffset, 
                                                      float vOffset, 
                                                      int flags, int paint);
-    private static native void native_drawPicture(int nativeCanvas,
-                                                  int nativePicture);
     private static native void finalizer(int nativeCanvas);
 }
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 933948d..8fbedae 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -406,18 +406,18 @@
         sColorNameMap.put("yellow", YELLOW);
         sColorNameMap.put("cyan", CYAN);
         sColorNameMap.put("magenta", MAGENTA);
-        sColorNameMap.put("aqua", 0x00FFFF);
-        sColorNameMap.put("fuchsia", 0xFF00FF);
+        sColorNameMap.put("aqua", 0xFF00FFFF);
+        sColorNameMap.put("fuchsia", 0xFFFF00FF);
         sColorNameMap.put("darkgrey", DKGRAY);
         sColorNameMap.put("grey", GRAY);
         sColorNameMap.put("lightgrey", LTGRAY);
-        sColorNameMap.put("lime", 0x00FF00);
-        sColorNameMap.put("maroon", 0x800000);
-        sColorNameMap.put("navy", 0x000080);
-        sColorNameMap.put("olive", 0x808000);
-        sColorNameMap.put("purple", 0x800080);
-        sColorNameMap.put("silver", 0xC0C0C0);
-        sColorNameMap.put("teal", 0x008080);
+        sColorNameMap.put("lime", 0xFF00FF00);
+        sColorNameMap.put("maroon", 0xFF800000);
+        sColorNameMap.put("navy", 0xFF000080);
+        sColorNameMap.put("olive", 0xFF808000);
+        sColorNameMap.put("purple", 0xFF800080);
+        sColorNameMap.put("silver", 0xFFC0C0C0);
+        sColorNameMap.put("teal", 0xFF008080);
 
     }
 }
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 241ab17..de0d3d6 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -16,10 +16,22 @@
 
 package android.graphics;
 
-/** A subclass of shader that returns the coposition of two other shaders, combined by
+/** A subclass of shader that returns the composition of two other shaders, combined by
     an {@link android.graphics.Xfermode} subclass.
 */
 public class ComposeShader extends Shader {
+
+    private static final int TYPE_XFERMODE = 1;
+    private static final int TYPE_PORTERDUFFMODE = 2;
+
+    /**
+     * Type of the ComposeShader: can be either TYPE_XFERMODE or TYPE_PORTERDUFFMODE
+     */
+    private int mType;
+
+    private Xfermode mXferMode;
+    private PorterDuff.Mode mPorterDuffMode;
+
     /**
      * Hold onto the shaders to avoid GC.
      */
@@ -37,8 +49,10 @@
                         is null, then SRC_OVER is assumed.
     */
     public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
+        mType = TYPE_XFERMODE;
         mShaderA = shaderA;
         mShaderB = shaderB;
+        mXferMode = mode;
         native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
                 (mode != null) ? mode.native_instance : 0);
         if (mode instanceof PorterDuffXfermode) {
@@ -59,14 +73,37 @@
         @param mode     The PorterDuff mode that combines the colors from the two shaders.
     */
     public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
+        mType = TYPE_PORTERDUFFMODE;
         mShaderA = shaderA;
         mShaderB = shaderB;
+        mPorterDuffMode = mode;
         native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
                 mode.nativeInt);
         native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
                 shaderB.native_shader, mode.nativeInt);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final ComposeShader copy;
+        switch (mType) {
+            case TYPE_XFERMODE:
+                copy = new ComposeShader(mShaderA.copy(), mShaderB.copy(), mXferMode);
+                break;
+            case TYPE_PORTERDUFFMODE:
+                copy = new ComposeShader(mShaderA.copy(), mShaderB.copy(), mPorterDuffMode);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "ComposeShader should be created with either Xfermode or PorterDuffMode");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
     private static native int nativeCreate1(int native_shaderA, int native_shaderB,
             int native_mode);
     private static native int nativeCreate2(int native_shaderA, int native_shaderB,
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index f6b747a..e08ed50 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -73,6 +73,66 @@
     public static final int YV12 = 0x32315659;
 
     /**
+     * <p>Android Y8 format.</p>
+     *
+     * <p>Y8 is a YUV planar format comprised of a WxH Y plane only, with each pixel
+     * being represented by 8 bits. It is equivalent to just the Y plane from {@link #YV12}
+     * format.</p>
+     *
+     * <p>This format assumes
+     * <ul>
+     * <li>an even width</li>
+     * <li>an even height</li>
+     * <li>a horizontal stride multiple of 16 pixels</li>
+     * </ul>
+     * </p>
+     *
+     * <pre> y_size = stride * height </pre>
+     *
+     * <p>For example, the {@link android.media.Image} object can provide data
+     * in this format from a {@link android.hardware.camera2.CameraDevice}
+     * through a {@link android.media.ImageReader} object if this format is
+     * supported by {@link android.hardware.camera2.CameraDevice}.</p>
+     *
+     * @see android.media.Image
+     * @see android.media.ImageReader
+     * @see android.hardware.camera2.CameraDevice
+     *
+     * @hide
+     */
+    public static final int Y8 = 0x20203859;
+
+    /**
+     * <p>Android Y16 format.</p>
+     *
+     * Y16 is a YUV planar format comprised of a WxH Y plane, with each pixel
+     * being represented by 16 bits. It is just like {@link #Y8}, but has 16
+     * bits per pixel (little endian).</p>
+     *
+     * <p>This format assumes
+     * <ul>
+     * <li>an even width</li>
+     * <li>an even height</li>
+     * <li>a horizontal stride multiple of 16 pixels</li>
+     * </ul>
+     * </p>
+     *
+     * <pre> y_size = stride * height </pre>
+     *
+     * <p>For example, the {@link android.media.Image} object can provide data
+     * in this format from a {@link android.hardware.camera2.CameraDevice}
+     * through a {@link android.media.ImageReader} object if this format is
+     * supported by {@link android.hardware.camera2.CameraDevice}.</p>
+     *
+     * @see android.media.Image
+     * @see android.media.ImageReader
+     * @see android.hardware.camera2.CameraDevice
+     *
+     * @hide
+     */
+    public static final int Y16 = 0x20363159;
+
+    /**
      * YCbCr format, used for video. Whether this format is supported by the
      * camera hardware can be determined by
      * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
@@ -100,6 +160,57 @@
     public static final int JPEG = 0x100;
 
     /**
+     * <p>Multi-plane Android YUV format</p>
+     *
+     * <p>This format is a generic YCbCr format, capable of describing any 4:2:0
+     * chroma-subsampled planar or semiplanar buffer (but not fully interleaved),
+     * with 8 bits per color sample.</p>
+     *
+     * <p>Images in this format are always represented by three separate buffers
+     * of data, one for each color plane. Additional information always
+     * accompanies the buffers, describing the row stride and the pixel stride
+     * for each plane.</p>
+     *
+     * <p>The order of planes in the array returned by
+     * {@link android.media.Image#getPlanes() Image#getPlanes()} is guaranteed such that
+     * plane #0 is always Y, plane #1 is always U (Cb), and plane #2 is always V (Cr).</p>
+     *
+     * <p>The Y-plane is guaranteed not to be interleaved with the U/V planes
+     * (in particular, pixel stride is always 1 in
+     * {@link android.media.Image.Plane#getPixelStride() yPlane.getPixelStride()}).</p>
+     *
+     * <p>The U/V planes are guaranteed to have the same row stride and pixel stride
+     * (in particular,
+     * {@link android.media.Image.Plane#getRowStride() uPlane.getRowStride()}
+     * == {@link android.media.Image.Plane#getRowStride() vPlane.getRowStride()} and
+     * {@link android.media.Image.Plane#getPixelStride() uPlane.getPixelStride()}
+     * == {@link android.media.Image.Plane#getPixelStride() vPlane.getPixelStride()};
+     * ).</p>
+     *
+     * <p>For example, the {@link android.media.Image} object can provide data
+     * in this format from a {@link android.hardware.camera2.CameraDevice}
+     * through a {@link android.media.ImageReader} object.</p>
+     *
+     * @see android.media.Image
+     * @see android.media.ImageReader
+     * @see android.hardware.camera2.CameraDevice
+     */
+    public static final int YUV_420_888 = 0x23;
+
+    /**
+     * <p>General raw camera sensor image format, usually representing a
+     * single-channel Bayer-mosaic image. Each pixel color sample is stored with
+     * 16 bits of precision.</p>
+     *
+     * <p>The layout of the color mosaic, the maximum and minimum encoding
+     * values of the raw pixel data, the color space of the image, and all other
+     * needed information to interpret a raw sensor image must be queried from
+     * the {@link android.hardware.camera2.CameraDevice} which produced the
+     * image.</p>
+     */
+    public static final int RAW_SENSOR = 0x20;
+
+    /**
      * Raw bayer format used for images, which is 10 bit precision samples
      * stored in 16 bit words. The filter pattern is RGGB. Whether this format
      * is supported by the camera hardware can be determined by
@@ -127,8 +238,16 @@
                 return 16;
             case YV12:
                 return 12;
+            case Y8:
+                return 8;
+            case Y16:
+                return 16;
             case NV21:
                 return 12;
+            case YUV_420_888:
+                return 12;
+            case RAW_SENSOR:
+                return 16;
             case BAYER_RGGB:
                 return 16;
         }
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 96a71e3..4c88de3 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -17,6 +17,27 @@
 package android.graphics;
 
 public class LinearGradient extends Shader {
+
+    private static final int TYPE_COLORS_AND_POSITIONS = 1;
+    private static final int TYPE_COLOR_START_AND_COLOR_END = 2;
+
+    /**
+     * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or
+     * TYPE_COLOR_START_AND_COLOR_END.
+     */
+    private int mType;
+
+    private float mX0;
+    private float mY0;
+    private float mX1;
+    private float mY1;
+    private int[] mColors;
+    private float[] mPositions;
+    private int mColor0;
+    private int mColor1;
+
+    private TileMode mTileMode;
+
 	/**	Create a shader that draws a linear gradient along a line.
         @param x0           The x-coordinate for the start of the gradient line
         @param y0           The y-coordinate for the start of the gradient line
@@ -36,6 +57,14 @@
         if (positions != null && colors.length != positions.length) {
             throw new IllegalArgumentException("color and position arrays must be of equal length");
         }
+        mType = TYPE_COLORS_AND_POSITIONS;
+        mX0 = x0;
+        mY0 = y0;
+        mX1 = x1;
+        mY1 = y1;
+        mColors = colors;
+        mPositions = positions;
+        mTileMode = tile;
         native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
         native_shader = nativePostCreate1(native_instance, x0, y0, x1, y1, colors, positions,
                 tile.nativeInt);
@@ -52,12 +81,42 @@
 	*/
 	public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
             TileMode tile) {
+        mType = TYPE_COLOR_START_AND_COLOR_END;
+        mX0 = x0;
+        mY0 = y0;
+        mX1 = x1;
+        mY1 = y1;
+        mColor0 = color0;
+        mColor1 = color1;
+        mTileMode = tile;
         native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
         native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
                 tile.nativeInt);
     }
 
-	private native int nativeCreate1(float x0, float y0, float x1, float y1,
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final LinearGradient copy;
+        switch (mType) {
+            case TYPE_COLORS_AND_POSITIONS:
+                copy = new LinearGradient(mX0, mY0, mX1, mY1, mColors.clone(),
+                        mPositions != null ? mPositions.clone() : null, mTileMode);
+                break;
+            case TYPE_COLOR_START_AND_COLOR_END:
+                copy = new LinearGradient(mX0, mY0, mX1, mY1, mColor0, mColor1, mTileMode);
+                break;
+            default:
+                throw new IllegalArgumentException("LinearGradient should be created with either " +
+                        "colors and positions or start color and end color");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
+    private native int nativeCreate1(float x0, float y0, float x1, float y1,
             int colors[], float positions[], int tileMode);
 	private native int nativeCreate2(float x0, float y0, float x1, float y1,
             int color0, int color1, int tileMode);
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index a837294..32e0c01 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -21,9 +21,6 @@
 
 /**
  * The Matrix class holds a 3x3 matrix for transforming coordinates.
- * Matrix does not have a constructor, so it must be explicitly initialized
- * using either reset() - to construct an identity matrix, or one of the set..()
- * functions (e.g. setTranslate, setRotate, etc.).
  */
 public class Matrix {
 
@@ -267,13 +264,23 @@
             native_set(native_instance, src.native_instance);
         }
     }
-    
+
     /** Returns true iff obj is a Matrix and its values equal our values.
     */
+    @Override
     public boolean equals(Object obj) {
-        return obj != null &&
-               obj instanceof Matrix &&
-               native_equals(native_instance, ((Matrix)obj).native_instance);
+        //if (obj == this) return true;     -- NaN value would mean matrix != itself
+        if (!(obj instanceof Matrix)) return false;
+        return native_equals(native_instance, ((Matrix)obj).native_instance);
+    }
+
+    @Override
+    public int hashCode() {
+        // This should generate the hash code by performing some arithmetic operation on all
+        // the matrix elements -- our equals() does an element-by-element comparison, and we
+        // need to ensure that the hash code for two equal objects is the same.  We're not
+        // really using this at the moment, so we take the easy way out.
+        return 44;
     }
 
     /** Set the matrix to identity */
@@ -512,7 +519,7 @@
          */
         END     (3);
 
-        // the native values must match those in SkMatrix.h 
+        // the native values must match those in SkMatrix.h
         ScaleToFit(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -535,7 +542,7 @@
         }
         return native_setRectToRect(native_instance, src, dst, stf.nativeInt);
     }
-    
+
     // private helper to perform range checks on arrays of "points"
     private static void checkPointArrays(float[] src, int srcIndex,
                                          float[] dst, int dstIndex,
@@ -598,7 +605,7 @@
         native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
                          pointCount, true);
     }
-    
+
     /**
     * Apply this matrix to the array of 2D vectors specified by src, and write
      * the transformed vectors into the array of vectors specified by dst. The
@@ -620,7 +627,7 @@
         native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
                          vectorCount, false);
     }
-    
+
     /**
      * Apply this matrix to the array of 2D points specified by src, and write
      * the transformed points into the array of points specified by dst. The
@@ -713,7 +720,7 @@
     public float mapRadius(float radius) {
         return native_mapRadius(native_instance, radius);
     }
-    
+
     /** Copy 9 values from the matrix into the array.
     */
     public void getValues(float[] values) {
@@ -736,13 +743,14 @@
         native_setValues(native_instance, values);
     }
 
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(64);
         sb.append("Matrix{");
         toShortString(sb);
         sb.append('}');
         return sb.toString();
-                
+
     }
 
     public String toShortString() {
@@ -780,13 +788,18 @@
                 pw.print(values[5]); pw.print("][");
         pw.print(values[6]); pw.print(", "); pw.print(values[7]); pw.print(", ");
                 pw.print(values[8]); pw.print(']');
-                
+
     }
 
+    @Override
     protected void finalize() throws Throwable {
-        finalizer(native_instance);
+        try {
+            finalizer(native_instance);
+        } finally {
+            super.finalize();
+        }
     }
-    
+
     /*package*/ final int ni() {
         return native_instance;
     }
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 4a33453..9419faf 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -16,12 +16,13 @@
 
 package android.graphics;
 
+import android.content.res.AssetManager;
 import java.io.InputStream;
 import java.io.FileInputStream;
 
 public class Movie {
     private final int mNativeMovie;
-    
+
     private Movie(int nativeMovie) {
         if (nativeMovie == 0) {
             throw new RuntimeException("native movie creation failed");
@@ -42,7 +43,20 @@
         draw(canvas, x, y, null);
     }
 
-    public static native Movie decodeStream(InputStream is);
+    public static Movie decodeStream(InputStream is) {
+        if (is == null) {
+            return null;
+        }
+        if (is instanceof AssetManager.AssetInputStream) {
+            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            return nativeDecodeAsset(asset);
+        }
+
+        return nativeDecodeStream(is);
+    }
+
+    private static native Movie nativeDecodeAsset(int asset);
+    private static native Movie nativeDecodeStream(InputStream is);
     public static native Movie decodeByteArray(byte[] data, int offset,
                                                int length);
 
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 6de4d84..528d9de 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -18,11 +18,8 @@
 
 
 /**
- * The NinePatch class permits drawing a bitmap in nine sections.
- * The four corners are unscaled; the four edges are scaled in one axis,
- * and the middle is scaled in both axes. Normally, the middle is 
- * transparent so that the patch can provide a selection about a rectangle.
- * Essentially, it allows the creation of custom graphics that will scale the 
+ * The NinePatch class permits drawing a bitmap in nine or more sections.
+ * Essentially, it allows the creation of custom graphics that will scale the
  * way that you define, when content added within the image exceeds the normal
  * bounds of the graphic. For a thorough explanation of a NinePatch image, 
  * read the discussion in the 
@@ -36,24 +33,40 @@
  */
 public class NinePatch {
     private final Bitmap mBitmap;
-    private final byte[] mChunk;
+
+    /**
+     * Used by native code. This pointer is an instance of Res_png_9patch*.
+     *
+     * @hide
+     */
+    public final int mNativeChunk;
+
     private Paint mPaint;
-    private String mSrcName;  // Useful for debugging
-    private final RectF mRect = new RectF();
-    
+    private String mSrcName;
+
+    /**
+     * Create a drawable projection from a bitmap to nine patches.
+     *
+     * @param bitmap The bitmap describing the patches.
+     * @param chunk The 9-patch data chunk describing how the underlying bitmap
+     *              is split apart and drawn.
+     */
+    public NinePatch(Bitmap bitmap, byte[] chunk) {
+        this(bitmap, chunk, null);
+    }
+
     /** 
      * Create a drawable projection from a bitmap to nine patches.
      *
-     * @param bitmap    The bitmap describing the patches.
-     * @param chunk     The 9-patch data chunk describing how the underlying
-     *                  bitmap is split apart and drawn.
-     * @param srcName   The name of the source for the bitmap. Might be null.
+     * @param bitmap The bitmap describing the patches.
+     * @param chunk The 9-patch data chunk describing how the underlying
+     *              bitmap is split apart and drawn.
+     * @param srcName The name of the source for the bitmap. Might be null.
      */
     public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
         mBitmap = bitmap;
-        mChunk = chunk;
         mSrcName = srcName;
-        validateNinePatchChunk(mBitmap.ni(), chunk);
+        mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk);
     }
 
     /**
@@ -61,69 +74,103 @@
      */
     public NinePatch(NinePatch patch) {
         mBitmap = patch.mBitmap;
-        mChunk = patch.mChunk;
         mSrcName = patch.mSrcName;
         if (patch.mPaint != null) {
             mPaint = new Paint(patch.mPaint);
         }
-        validateNinePatchChunk(mBitmap.ni(), mChunk);
+        // No need to validate the 9patch chunk again, it was done by
+        // the instance we're copying from
+        mNativeChunk = patch.mNativeChunk;
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            nativeFinalize(mNativeChunk);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Returns the name of this NinePatch object if one was specified
+     * when calling the constructor.
+     */
+    public String getName() {
+        return mSrcName;
+    }
+
+    /**
+     * Returns the paint used to draw this NinePatch. The paint can be null.
+     *
+     * @see #setPaint(Paint)
+     * @see #draw(Canvas, Rect)
+     * @see #draw(Canvas, RectF)
+     */
+    public Paint getPaint() {
+        return mPaint;
+    }
+
+    /**
+     * Sets the paint to use when drawing the NinePatch.
+     *
+     * @param p The paint that will be used to draw this NinePatch.
+     *
+     * @see #getPaint()
+     * @see #draw(Canvas, Rect)
+     * @see #draw(Canvas, RectF)
+     */
     public void setPaint(Paint p) {
         mPaint = p;
     }
-    
-    /** 
-     * Draw a bitmap of nine patches.
-     *
-     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
-     * @param location  Where to draw the bitmap.
+
+    /**
+     * Returns the bitmap used to draw this NinePatch.
      */
-    public void draw(Canvas canvas, RectF location) {
-        if (!canvas.isHardwareAccelerated()) {
-            nativeDraw(canvas.mNativeCanvas, location,
-                       mBitmap.ni(), mChunk,
-                       mPaint != null ? mPaint.mNativePaint : 0,
-                       canvas.mDensity, mBitmap.mDensity);
-        } else {
-            canvas.drawPatch(mBitmap, mChunk, location, mPaint);
-        }
+    public Bitmap getBitmap() {
+        return mBitmap;
     }
     
     /** 
-     * Draw a bitmap of nine patches.
+     * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}.
      *
-     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
-     * @param location  Where to draw the bitmap.
+     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
+     * @param location Where to draw the NinePatch.
      */
-    public void draw(Canvas canvas, Rect location) {
-        if (!canvas.isHardwareAccelerated()) {
-            nativeDraw(canvas.mNativeCanvas, location,
-                        mBitmap.ni(), mChunk,
-                        mPaint != null ? mPaint.mNativePaint : 0,
-                        canvas.mDensity, mBitmap.mDensity);
-        } else {
-            mRect.set(location);
-            canvas.drawPatch(mBitmap, mChunk, mRect, mPaint);
-        }
+    public void draw(Canvas canvas, RectF location) {
+        canvas.drawPatch(this, location, mPaint);
     }
 
     /** 
-     * Draw a bitmap of nine patches.
+     * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}.
      *
-     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
-     * @param location  Where to draw the bitmap.
-     * @param paint     The Paint to draw through.
+     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
+     * @param location Where to draw the NinePatch.
+     */
+    public void draw(Canvas canvas, Rect location) {
+        canvas.drawPatch(this, location, mPaint);
+    }
+
+    /** 
+     * Draws the NinePatch. This method will ignore the paint returned
+     * by {@link #getPaint()} and use the specified paint instead.
+     *
+     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
+     * @param location Where to draw the NinePatch.
+     * @param paint The Paint to draw through.
      */
     public void draw(Canvas canvas, Rect location, Paint paint) {
-        if (!canvas.isHardwareAccelerated()) {
-            nativeDraw(canvas.mNativeCanvas, location,
-                    mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0,
-                    canvas.mDensity, mBitmap.mDensity);
-        } else {
-            mRect.set(location);
-            canvas.drawPatch(mBitmap, mChunk, mRect, paint);
-        }
+        canvas.drawPatch(this, location, paint);
+    }
+
+    void drawSoftware(Canvas canvas, RectF location, Paint paint) {
+        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
+    }
+
+    void drawSoftware(Canvas canvas, Rect location, Paint paint) {
+        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     /**
@@ -133,33 +180,67 @@
     public int getDensity() {
         return mBitmap.mDensity;
     }
-    
+
+    /**
+     * Returns the intrinsic width, in pixels, of this NinePatch. This is equivalent
+     * to querying the width of the underlying bitmap returned by {@link #getBitmap()}.
+     */
     public int getWidth() {
         return mBitmap.getWidth();
     }
 
+    /**
+     * Returns the intrinsic height, in pixels, of this NinePatch. This is equivalent
+     * to querying the height of the underlying bitmap returned by {@link #getBitmap()}.
+     */
     public int getHeight() {
         return mBitmap.getHeight();
     }
 
+    /**
+     * Indicates whether this NinePatch contains transparent or translucent pixels.
+     * This is equivalent to calling <code>getBitmap().hasAlpha()</code> on this
+     * NinePatch.
+     */
     public final boolean hasAlpha() {
         return mBitmap.hasAlpha();
     }
 
-    public final Region getTransparentRegion(Rect location) {
-        int r = nativeGetTransparentRegion(mBitmap.ni(), mChunk, location);
+    /**
+     * Returns a {@link Region} representing the parts of the NinePatch that are
+     * completely transparent.
+     *
+     * @param bounds The location and size of the NinePatch.
+     *
+     * @return null if the NinePatch has no transparent region to
+     * report, else a {@link Region} holding the parts of the specified bounds
+     * that are transparent.
+     */
+    public final Region getTransparentRegion(Rect bounds) {
+        int r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds);
         return r != 0 ? new Region(r) : null;
     }
-    
+
+    /**
+     * Verifies that the specified byte array is a valid 9-patch data chunk.
+     *
+     * @param chunk A byte array representing a 9-patch data chunk.
+     *
+     * @return True if the specified byte array represents a 9-patch data chunk,
+     *         false otherwise.
+     */
     public native static boolean isNinePatchChunk(byte[] chunk);
 
-    private static native void validateNinePatchChunk(int bitmap, byte[] chunk);
+    /**
+     * Validates the 9-patch chunk and throws an exception if the chunk is invalid.
+     * If validation is successful, this method returns a native Res_png_9patch*
+     * object used by the renderers.
+     */
+    private static native int validateNinePatchChunk(int bitmap, byte[] chunk);
+    private static native void nativeFinalize(int chunk);
     private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
-                                          byte[] c, int paint_instance_or_null,
-                                          int destDensity, int srcDensity);
+            int c, int paint_instance_or_null, int destDensity, int srcDensity);
     private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
-                                          byte[] c, int paint_instance_or_null,
-                                          int destDensity, int srcDensity);
-    private static native int nativeGetTransparentRegion(
-            int bitmap, byte[] chunk, Rect location);
+            int c, int paint_instance_or_null, int destDensity, int srcDensity);
+    private static native int nativeGetTransparentRegion(int bitmap, int chunk, Rect location);
 }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1485d8d..5fc2588 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -87,35 +87,133 @@
         Align.LEFT, Align.CENTER, Align.RIGHT
     };
 
-    /** bit mask for the flag enabling antialiasing */
+    /**
+     * Paint flag that enables antialiasing when drawing.
+     *
+     * <p>Enabling this flag will cause all draw operations that support
+     * antialiasing to use it.</p>
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int ANTI_ALIAS_FLAG     = 0x01;
-    /** bit mask for the flag enabling bitmap filtering */
+    /**
+     * Paint flag that enables bilinear sampling on scaled bitmaps.
+     *
+     * <p>If cleared, scaled bitmaps will be drawn with nearest neighbor
+     * sampling, likely resulting in artifacts. This should generally be on
+     * when drawing bitmaps, unless performance-bound (rendering to software
+     * canvas) or preferring pixelation artifacts to blurriness when scaling
+     * significantly.</p>
+     *
+     * <p>If bitmaps are scaled for device density at creation time (as
+     * resource bitmaps often are) the filtering will already have been
+     * done.</p>
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int FILTER_BITMAP_FLAG  = 0x02;
-    /** bit mask for the flag enabling dithering */
+    /**
+     * Paint flag that enables dithering when blitting.
+     *
+     * <p>Enabling this flag applies a dither to any blit operation where the
+     * target's colour space is more constrained than the source.
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int DITHER_FLAG         = 0x04;
-    /** bit mask for the flag enabling underline text */
+    /**
+     * Paint flag that applies an underline decoration to drawn text.
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int UNDERLINE_TEXT_FLAG = 0x08;
-    /** bit mask for the flag enabling strike-thru text */
+    /**
+     * Paint flag that applies a strike-through decoration to drawn text.
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int STRIKE_THRU_TEXT_FLAG = 0x10;
-    /** bit mask for the flag enabling fake-bold text */
+    /**
+     * Paint flag that applies a synthetic bolding effect to drawn text.
+     *
+     * <p>Enabling this flag will cause text draw operations to apply a
+     * simulated bold effect when drawing a {@link Typeface} that is not
+     * already bold.</p>
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int FAKE_BOLD_TEXT_FLAG = 0x20;
-    /** bit mask for the flag enabling linear-text (no caching) */
+    /**
+     * Paint flag that enables smooth linear scaling of text.
+     *
+     * <p>Enabling this flag does not actually scale text, but rather adjusts
+     * text draw operations to deal gracefully with smooth adjustment of scale.
+     * When this flag is enabled, font hinting is disabled to prevent shape
+     * deformation between scale factors, and glyph caching is disabled due to
+     * the large number of glyph images that will be generated.</p>
+     *
+     * <p>{@link #SUBPIXEL_TEXT_FLAG} should be used in conjunction with this
+     * flag to prevent glyph positions from snapping to whole pixel values as
+     * scale factor is adjusted.</p>
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int LINEAR_TEXT_FLAG    = 0x40;
-    /** bit mask for the flag enabling subpixel-text */
+    /**
+     * Paint flag that enables subpixel positioning of text.
+     *
+     * <p>Enabling this flag causes glyph advances to be computed with subpixel
+     * accuracy.</p>
+     *
+     * <p>This can be used with {@link #LINEAR_TEXT_FLAG} to prevent text from
+     * jittering during smooth scale transitions.</p>
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
     public static final int SUBPIXEL_TEXT_FLAG  = 0x80;
-    /** bit mask for the flag enabling device kerning for text */
+    /** Legacy Paint flag, no longer used. */
     public static final int DEV_KERN_TEXT_FLAG  = 0x100;
+    /** @hide bit mask for the flag enabling subpixel glyph rendering for text */
+    public static final int LCD_RENDER_TEXT_FLAG = 0x200;
+    /**
+     * Paint flag that enables the use of bitmap fonts when drawing text.
+     *
+     * <p>Disabling this flag will prevent text draw operations from using
+     * embedded bitmap strikes in fonts, causing fonts with both scalable
+     * outlines and bitmap strikes to draw only the scalable outlines, and
+     * fonts with only bitmap strikes to not draw at all.</p>
+     *
+     * @see #Paint(int)
+     * @see #setFlags(int)
+     */
+    public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400;
+    /** @hide bit mask for the flag forcing freetype's autohinter on for text */
+    public static final int AUTO_HINTING_TEXT_FLAG = 0x800;
+    /** @hide bit mask for the flag enabling vertical rendering for text */
+    public static final int VERTICAL_TEXT_FLAG = 0x1000;
 
     // we use this when we first create a paint
-    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG;
+    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG;
 
     /**
-     * Option for {@link #setHinting}: disable hinting.
+     * Font hinter option that disables font hinting.
+     *
+     * @see #setHinting(int)
      */
     public static final int HINTING_OFF = 0x0;
 
     /**
-     * Option for {@link #setHinting}: enable hinting.
+     * Font hinter option that enables font hinting.
+     *
+     * @see #setHinting(int)
      */
     public static final int HINTING_ON = 0x1;
 
@@ -421,7 +519,11 @@
         mMaskFilter = paint.mMaskFilter;
         mPathEffect = paint.mPathEffect;
         mRasterizer = paint.mRasterizer;
-        mShader = paint.mShader;
+        if (paint.mShader != null) {
+            mShader = paint.mShader.copy();
+        } else {
+            mShader = null;
+        }
         mTypeface = paint.mTypeface;
         mXfermode = paint.mXfermode;
 
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 157c7d1..ef858eb 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -103,21 +103,106 @@
         }
     }
 
-    /** Enum for the ways a path may be filled
-    */
+    /**
+     * The logical operations that can be performed when combining two paths.
+     *
+     * @see #op(Path, android.graphics.Path.Op)
+     * @see #op(Path, Path, android.graphics.Path.Op)
+     */
+    public enum Op {
+        /**
+         * Subtract the second path from the first path.
+         */
+        DIFFERENCE,
+        /**
+         * Intersect the two paths.
+         */
+        INTERSECT,
+        /**
+         * Union (inclusive-or) the two paths.
+         */
+        UNION,
+        /**
+         * Exclusive-or the two paths.
+         */
+        XOR,
+        /**
+         * Subtract the first path from the second path.
+         */
+        REVERSE_DIFFERENCE
+    }
+
+    /**
+     * Set this path to the result of applying the Op to this path and the specified path.
+     * The resulting path will be constructed from non-overlapping contours.
+     * The curve order is reduced where possible so that cubics may be turned
+     * into quadratics, and quadratics maybe turned into lines.
+     *
+     * @param path The second operand (for difference, the subtrahend)
+     *
+     * @return True if operation succeeded, false otherwise and this path remains unmodified.
+     *
+     * @see Op
+     * @see #op(Path, Path, android.graphics.Path.Op)
+     */
+    public boolean op(Path path, Op op) {
+        return op(this, path, op);
+    }
+
+    /**
+     * Set this path to the result of applying the Op to the two specified paths.
+     * The resulting path will be constructed from non-overlapping contours.
+     * The curve order is reduced where possible so that cubics may be turned
+     * into quadratics, and quadratics maybe turned into lines.
+     *
+     * @param path1 The first operand (for difference, the minuend)
+     * @param path2 The second operand (for difference, the subtrahend)
+     *
+     * @return True if operation succeeded, false otherwise and this path remains unmodified.
+     *
+     * @see Op
+     * @see #op(Path, android.graphics.Path.Op)
+     */
+    public boolean op(Path path1, Path path2, Op op) {
+        if (native_op(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
+            isSimplePath = false;
+            rects = null;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Enum for the ways a path may be filled.
+     */
     public enum FillType {
         // these must match the values in SkPath.h
+        /**
+         * Specifies that "inside" is computed by a non-zero sum of signed
+         * edge crossings.
+         */
         WINDING         (0),
+        /**
+         * Specifies that "inside" is computed by an odd number of edge
+         * crossings.
+         */
         EVEN_ODD        (1),
+        /**
+         * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
+         */
         INVERSE_WINDING (2),
+        /**
+         * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
+         */
         INVERSE_EVEN_ODD(3);
         
         FillType(int ni) {
             nativeInt = ni;
         }
+
         final int nativeInt;
     }
-    
+
     // these must be in the same order as their native values
     static final FillType[] sFillTypeArray = {
         FillType.WINDING,
@@ -644,24 +729,20 @@
     private static native void native_addRect(int nPath, float left, float top,
                                             float right, float bottom, int dir);
     private static native void native_addOval(int nPath, RectF oval, int dir);
-    private static native void native_addCircle(int nPath, float x, float y,
-                                                float radius, int dir);
+    private static native void native_addCircle(int nPath, float x, float y, float radius, int dir);
     private static native void native_addArc(int nPath, RectF oval,
                                             float startAngle, float sweepAngle);
     private static native void native_addRoundRect(int nPath, RectF rect,
                                                    float rx, float ry, int dir);
-    private static native void native_addRoundRect(int nPath, RectF r,
-                                                   float[] radii, int dir);
-    private static native void native_addPath(int nPath, int src, float dx,
-                                              float dy);
+    private static native void native_addRoundRect(int nPath, RectF r, float[] radii, int dir);
+    private static native void native_addPath(int nPath, int src, float dx, float dy);
     private static native void native_addPath(int nPath, int src);
     private static native void native_addPath(int nPath, int src, int matrix);
-    private static native void native_offset(int nPath, float dx, float dy,
-                                             int dst_path);
+    private static native void native_offset(int nPath, float dx, float dy, int dst_path);
     private static native void native_offset(int nPath, float dx, float dy);
     private static native void native_setLastPoint(int nPath, float dx, float dy);
-    private static native void native_transform(int nPath, int matrix,
-                                                int dst_path);
+    private static native void native_transform(int nPath, int matrix, int dst_path);
     private static native void native_transform(int nPath, int matrix);
+    private static native boolean native_op(int path1, int path2, int op, int result);
     private static native void finalizer(int nPath);
 }
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index f7c202f..d96d6d8 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -19,16 +19,16 @@
 public class PixelFormat
 {
     /* these constants need to match those in hardware/hardware.h */
-    
+
     public static final int UNKNOWN     = 0;
 
     /** System chooses a format that supports translucency (many alpha bits) */
     public static final int TRANSLUCENT = -3;
 
-    /** 
+    /**
      * System chooses a format that supports transparency
-     * (at least 1 alpha bit) 
-     */    
+     * (at least 1 alpha bit)
+     */
     public static final int TRANSPARENT = -2;
 
     /** System chooses an opaque format (no alpha bits required) */
@@ -43,7 +43,9 @@
     public static final int RGBA_5551   = 6;
     @Deprecated
     public static final int RGBA_4444   = 7;
+    @Deprecated
     public static final int A_8         = 8;
+    @Deprecated
     public static final int L_8         = 9;
     @Deprecated
     public static final int LA_88       = 0xA;
@@ -52,41 +54,71 @@
 
 
     /**
-     * @deprecated use {@link android.graphics.ImageFormat#NV16 
+     * @deprecated use {@link android.graphics.ImageFormat#NV16
      * ImageFormat.NV16} instead.
      */
     @Deprecated
     public static final int YCbCr_422_SP= 0x10;
 
     /**
-     * @deprecated use {@link android.graphics.ImageFormat#NV21 
+     * @deprecated use {@link android.graphics.ImageFormat#NV21
      * ImageFormat.NV21} instead.
      */
     @Deprecated
     public static final int YCbCr_420_SP= 0x11;
 
     /**
-     * @deprecated use {@link android.graphics.ImageFormat#YUY2 
+     * @deprecated use {@link android.graphics.ImageFormat#YUY2
      * ImageFormat.YUY2} instead.
      */
     @Deprecated
     public static final int YCbCr_422_I = 0x14;
 
     /**
-     * @deprecated use {@link android.graphics.ImageFormat#JPEG 
+     * @deprecated use {@link android.graphics.ImageFormat#JPEG
      * ImageFormat.JPEG} instead.
      */
     @Deprecated
     public static final int JPEG        = 0x100;
 
-    /*
-     * We use a class initializer to allow the native code to cache some
-     * field offsets.
-     */
-    native private static void nativeClassInit();
-    static { nativeClassInit(); }
+    public static void getPixelFormatInfo(int format, PixelFormat info) {
+        switch (format) {
+            case RGBA_8888:
+            case RGBX_8888:
+                info.bitsPerPixel = 32;
+                info.bytesPerPixel = 4;
+                break;
+            case RGB_888:
+                info.bitsPerPixel = 24;
+                info.bytesPerPixel = 3;
+                break;
+            case RGB_565:
+            case RGBA_5551:
+            case RGBA_4444:
+            case LA_88:
+                info.bitsPerPixel = 16;
+                info.bytesPerPixel = 2;
+                break;
+            case A_8:
+            case L_8:
+            case RGB_332:
+                info.bitsPerPixel = 8;
+                info.bytesPerPixel = 1;
+                break;
+            case YCbCr_422_SP:
+            case YCbCr_422_I:
+                info.bitsPerPixel = 16;
+                info.bytesPerPixel = 1;
+                break;
+            case YCbCr_420_SP:
+                info.bitsPerPixel = 12;
+                info.bytesPerPixel = 1;
+                break;
+            default:
+                throw new IllegalArgumentException("unkonwon pixel format " + format);
+        }
+    }
 
-    public static native void getPixelFormatInfo(int format, PixelFormat info);
     public static boolean formatHasAlpha(int format) {
         switch (format) {
             case PixelFormat.A_8:
@@ -100,7 +132,7 @@
         }
         return false;
     }
-    
+
     public int  bytesPerPixel;
     public int  bitsPerPixel;
 }
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
index 897762c..f011e5c 100644
--- a/graphics/java/android/graphics/RadialGradient.java
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -18,6 +18,25 @@
 
 public class RadialGradient extends Shader {
 
+    private static final int TYPE_COLORS_AND_POSITIONS = 1;
+    private static final int TYPE_COLOR_CENTER_AND_COLOR_EDGE = 2;
+
+    /**
+     * Type of the RadialGradient: can be either TYPE_COLORS_AND_POSITIONS or
+     * TYPE_COLOR_CENTER_AND_COLOR_EDGE.
+     */
+    private int mType;
+
+    private float mX;
+    private float mY;
+    private float mRadius;
+    private int[] mColors;
+    private float[] mPositions;
+    private int mColor0;
+    private int mColor1;
+
+    private TileMode mTileMode;
+
 	/**	Create a shader that draws a radial gradient given the center and radius.
         @param x        The x-coordinate of the center of the radius
         @param y        The y-coordinate of the center of the radius
@@ -39,6 +58,13 @@
         if (positions != null && colors.length != positions.length) {
             throw new IllegalArgumentException("color and position arrays must be of equal length");
         }
+        mType = TYPE_COLORS_AND_POSITIONS;
+        mX = x;
+        mY = y;
+        mRadius = radius;
+        mColors = colors;
+        mPositions = positions;
+        mTileMode = tile;
         native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
         native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions,
                 tile.nativeInt);
@@ -57,12 +83,41 @@
         if (radius <= 0) {
             throw new IllegalArgumentException("radius must be > 0");
         }
+        mType = TYPE_COLOR_CENTER_AND_COLOR_EDGE;
+        mX = x;
+        mY = y;
+        mRadius = radius;
+        mColor0 = color0;
+        mColor1 = color1;
+        mTileMode = tile;
         native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
         native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1,
                 tile.nativeInt);
     }
 
-	private static native int nativeCreate1(float x, float y, float radius,
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final RadialGradient copy;
+        switch (mType) {
+            case TYPE_COLORS_AND_POSITIONS:
+                copy = new RadialGradient(mX, mY, mRadius, mColors.clone(),
+                        mPositions != null ? mPositions.clone() : null, mTileMode);
+                break;
+            case TYPE_COLOR_CENTER_AND_COLOR_EDGE:
+                copy = new RadialGradient(mX, mY, mRadius, mColor0, mColor1, mTileMode);
+                break;
+            default:
+                throw new IllegalArgumentException("RadialGradient should be created with either " +
+                        "colors and positions or center color and edge color");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
+    private static native int nativeCreate1(float x, float y, float radius,
             int colors[], float positions[], int tileMode);
 	private static native int nativeCreate2(float x, float y, float radius,
             int color0, int color1, int tileMode);
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 43758e7..afc68d8 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -90,6 +90,28 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    protected Shader copy() {
+        final Shader copy = new Shader();
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
+    /**
+     * @hide
+     */
+    protected void copyLocalMatrix(Shader dest) {
+        if (mLocalMatrix != null) {
+            final Matrix lm = new Matrix();
+            getLocalMatrix(lm);
+            dest.setLocalMatrix(lm);
+        } else {
+            dest.setLocalMatrix(null);
+        }
+    }
+
     private static native void nativeDestructor(int native_shader, int native_skiaShader);
     private static native void nativeSetLocalMatrix(int native_shader,
             int native_skiaShader, int matrix_instance);
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index af1a447..b910a24 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.view.Surface;
 
 /**
  * Captures frames from an image stream as an OpenGL ES texture.
@@ -69,6 +70,7 @@
      * These fields are used by native code, do not access or modify.
      */
     private int mSurfaceTexture;
+    private int mBufferQueue;
     private int mFrameAvailableListener;
 
     /**
@@ -79,8 +81,12 @@
     }
 
     /**
-     * Exception thrown when a surface couldn't be created or resized
+     * Exception thrown when a SurfaceTexture couldn't be created or resized.
+     *
+     * @deprecated No longer thrown. {@link Surface.OutOfResourcesException} is used instead.
      */
+    @SuppressWarnings("serial")
+    @Deprecated
     public static class OutOfResourcesException extends Exception {
         public OutOfResourcesException() {
         }
@@ -93,32 +99,32 @@
      * Construct a new SurfaceTexture to stream images to a given OpenGL texture.
      *
      * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
+     *
+     * @throws OutOfResourcesException If the SurfaceTexture cannot be created.
      */
     public SurfaceTexture(int texName) {
-        this(texName, false);
+        init(texName, false);
     }
 
     /**
      * Construct a new SurfaceTexture to stream images to a given OpenGL texture.
      *
-     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
-     * @param allowSynchronousMode whether the SurfaceTexture can run in the synchronous mode.
-     *      When the image stream comes from OpenGL, SurfaceTexture may run in the synchronous
-     *      mode where the producer side may be blocked to avoid skipping frames. To avoid the
-     *      thread block, set allowSynchronousMode to false.
+     * In single buffered mode the application is responsible for serializing access to the image
+     * content buffer. Each time the image content is to be updated, the
+     * {@link #releaseTexImage()} method must be called before the image content producer takes
+     * ownership of the buffer. For example, when producing image content with the NDK
+     * ANativeWindow_lock and ANativeWindow_unlockAndPost functions, {@link #releaseTexImage()}
+     * must be called before each ANativeWindow_lock, or that call will fail. When producing
+     * image content with OpenGL ES, {@link #releaseTexImage()} must be called before the first
+     * OpenGL ES function call each frame.
      *
-     * @hide
+     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
+     * @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
+     *
+     * @throws throws OutOfResourcesException If the SurfaceTexture cannot be created.
      */
-    public SurfaceTexture(int texName, boolean allowSynchronousMode) {
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mEventHandler = new EventHandler(looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mEventHandler = new EventHandler(looper);
-        } else {
-            mEventHandler = null;
-        }
-        nativeInit(texName, new WeakReference<SurfaceTexture>(this), allowSynchronousMode);
+    public SurfaceTexture(int texName, boolean singleBufferMode) {
+        init(texName, singleBufferMode);
     }
 
     /**
@@ -143,9 +149,9 @@
      * android.view.Surface#lockCanvas} is called.  For OpenGL ES, the EGLSurface should be
      * destroyed (via eglDestroySurface), made not-current (via eglMakeCurrent), and then recreated
      * (via eglCreateWindowSurface) to ensure that the new default size has taken effect.
-     * 
+     *
      * The width and height parameters must be no greater than the minimum of
-     * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see 
+     * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see
      * {@link javax.microedition.khronos.opengles.GL10#glGetIntegerv glGetIntegerv}).
      * An error due to invalid dimensions might not be reported until
      * updateTexImage() is called.
@@ -164,6 +170,15 @@
     }
 
     /**
+     * Releases the the texture content. This is needed in single buffered mode to allow the image
+     * content producer to take ownership of the image buffer.
+     * For more information see {@link #SurfaceTexture(int, boolean)}.
+     */
+    public void releaseTexImage() {
+        nativeReleaseTexImage();
+    }
+
+    /**
      * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
      * This call must be made with the OpenGL ES context current on the calling thread.  The OpenGL
      * ES texture object will be deleted as a result of this call.  After calling this method all
@@ -261,6 +276,7 @@
         nativeRelease();
     }
 
+    @Override
     protected void finalize() throws Throwable {
         try {
             nativeFinalize();
@@ -299,12 +315,26 @@
         }
     }
 
-    private native void nativeInit(int texName, Object weakSelf, boolean allowSynchronousMode);
+    private void init(int texName, boolean singleBufferMode) throws Surface.OutOfResourcesException {
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mEventHandler = new EventHandler(looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mEventHandler = new EventHandler(looper);
+        } else {
+            mEventHandler = null;
+        }
+        nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
+    }
+
+    private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf)
+            throws Surface.OutOfResourcesException;
     private native void nativeFinalize();
     private native void nativeGetTransformMatrix(float[] mtx);
     private native long nativeGetTimestamp();
     private native void nativeSetDefaultBufferSize(int width, int height);
     private native void nativeUpdateTexImage();
+    private native void nativeReleaseTexImage();
     private native int nativeDetachFromGLContext();
     private native int nativeAttachToGLContext(int texName);
     private native int nativeGetQueuedCount();
diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java
index 2afdd4d..e9cda39 100644
--- a/graphics/java/android/graphics/SweepGradient.java
+++ b/graphics/java/android/graphics/SweepGradient.java
@@ -18,6 +18,22 @@
 
 public class SweepGradient extends Shader {
 
+    private static final int TYPE_COLORS_AND_POSITIONS = 1;
+    private static final int TYPE_COLOR_START_AND_COLOR_END = 2;
+
+    /**
+     * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or
+     * TYPE_COLOR_START_AND_COLOR_END.
+     */
+    private int mType;
+
+    private float mCx;
+    private float mCy;
+    private int[] mColors;
+    private float[] mPositions;
+    private int mColor0;
+    private int mColor1;
+
     /**
      * A subclass of Shader that draws a sweep gradient around a center point.
      *
@@ -41,6 +57,11 @@
             throw new IllegalArgumentException(
                         "color and position arrays must be of equal length");
         }
+        mType = TYPE_COLORS_AND_POSITIONS;
+        mCx = cx;
+        mCy = cy;
+        mColors = colors;
+        mPositions = positions;
         native_instance = nativeCreate1(cx, cy, colors, positions);
         native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions);
     }
@@ -54,10 +75,37 @@
      * @param color1   The color to use at the end of the sweep
      */
     public SweepGradient(float cx, float cy, int color0, int color1) {
+        mType = TYPE_COLOR_START_AND_COLOR_END;
+        mCx = cx;
+        mCy = cy;
+        mColor0 = color0;
+        mColor1 = color1;
         native_instance = nativeCreate2(cx, cy, color0, color1);
         native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final SweepGradient copy;
+        switch (mType) {
+            case TYPE_COLORS_AND_POSITIONS:
+                copy = new SweepGradient(mCx, mCy, mColors.clone(),
+                        mPositions != null ? mPositions.clone() : null);
+                break;
+            case TYPE_COLOR_START_AND_COLOR_END:
+                copy = new SweepGradient(mCx, mCy, mColor0, mColor1);
+                break;
+            default:
+                throw new IllegalArgumentException("SweepGradient should be created with either " +
+                        "colors and positions or start color and end color");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
     private static native int nativeCreate1(float x, float y, int colors[], float positions[]);
     private static native int nativeCreate2(float x, float y, int color0, int color1);
 
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index f0e9723..9accbbc 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -153,6 +153,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mState.mDrawable.getAlpha();
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         mState.mDrawable.setColorFilter(cf);
     }
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 7c7cd01..bde978d 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -167,7 +167,7 @@
      * @return The Drawable at the specified frame index
      */
     public Drawable getFrame(int index) {
-        return mAnimationState.getChildren()[index];
+        return mAnimationState.getChild(index);
     }
     
     /**
@@ -322,7 +322,7 @@
                 mDurations = orig.mDurations;
                 mOneShot = orig.mOneShot;
             } else {
-                mDurations = new int[getChildren().length];
+                mDurations = new int[getCapacity()];
                 mOneShot = true;
             }
         }
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index a97ed2c..5ceab36 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -23,12 +23,14 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.LayoutDirection;
 import android.view.Gravity;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -72,7 +74,10 @@
      // These are scaled to match the target density.
     private int mBitmapWidth;
     private int mBitmapHeight;
-    
+
+    // Mirroring matrix for using with Shaders
+    private Matrix mMirrorMatrix;
+
     /**
      * Create an empty drawable, not dealing with density.
      * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
@@ -399,14 +404,51 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        if (mBitmapState.mAutoMirrored != mirrored) {
+            mBitmapState.mAutoMirrored = mirrored;
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public final boolean isAutoMirrored() {
+        return mBitmapState.mAutoMirrored;
+    }
+
+    @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
     }
-    
+
+    private boolean needMirroring() {
+        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
+    }
+
+    private void updateMirrorMatrix(float dx) {
+        if (mMirrorMatrix == null) {
+            mMirrorMatrix = new Matrix();
+        }
+        mMirrorMatrix.setTranslate(dx, 0);
+        mMirrorMatrix.preScale(-1.0f, 1.0f);
+    }
+
     @Override
     protected void onBoundsChange(Rect bounds) {
         super.onBoundsChange(bounds);
         mApplyGravity = true;
+        Shader shader = mBitmapState.mPaint.getShader();
+        if (shader != null) {
+            if (needMirroring()) {
+                updateMirrorMatrix(bounds.right - bounds.left);
+                shader.setLocalMatrix(mMirrorMatrix);
+            } else {
+                if (mMirrorMatrix != null) {
+                    mMirrorMatrix = null;
+                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
+                }
+            }
+        }
     }
 
     @Override
@@ -430,6 +472,7 @@
             }
 
             Shader shader = state.mPaint.getShader();
+            final boolean needMirroring = needMirroring();
             if (shader == null) {
                 if (mApplyGravity) {
                     final int layoutDirection = getLayoutDirection();
@@ -437,12 +480,31 @@
                             getBounds(), mDstRect, layoutDirection);
                     mApplyGravity = false;
                 }
+                if (needMirroring) {
+                    canvas.save();
+                    // Mirror the bitmap
+                    canvas.translate(mDstRect.right - mDstRect.left, 0);
+                    canvas.scale(-1.0f, 1.0f);
+                }
                 canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
+                if (needMirroring) {
+                    canvas.restore();
+                }
             } else {
                 if (mApplyGravity) {
                     copyBounds(mDstRect);
                     mApplyGravity = false;
                 }
+                if (needMirroring) {
+                    // Mirror the bitmap
+                    updateMirrorMatrix(mDstRect.right - mDstRect.left);
+                    shader.setLocalMatrix(mMirrorMatrix);
+                } else {
+                    if (mMirrorMatrix != null) {
+                        mMirrorMatrix = null;
+                        shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
+                    }
+                }
                 canvas.drawRect(mDstRect, state.mPaint);
             }
         }
@@ -458,6 +520,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mBitmapState.mPaint.getAlpha();
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         mBitmapState.mPaint.setColorFilter(cf);
         invalidateSelf();
@@ -500,6 +567,8 @@
         setTargetDensity(r.getDisplayMetrics());
         setMipMap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_mipMap,
                 bitmap.hasMipMap()));
+        setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_autoMirrored,
+                false));
 
         final Paint paint = mBitmapState.mPaint;
         paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
@@ -562,6 +631,7 @@
         Shader.TileMode mTileModeY = null;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
         boolean mRebuildShader;
+        boolean mAutoMirrored;
 
         BitmapState(Bitmap bitmap) {
             mBitmap = bitmap;
@@ -576,6 +646,12 @@
             mTargetDensity = bitmapState.mTargetDensity;
             mPaint = new Paint(bitmapState.mPaint);
             mRebuildShader = bitmapState.mRebuildShader;
+            mAutoMirrored = bitmapState.mAutoMirrored;
+        }
+
+        @Override
+        public Bitmap getBitmap() {
+            return mBitmap;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index eb9f046..2a9a14b 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -158,6 +158,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mClipState.mDrawable.getAlpha();
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         mClipState.mDrawable.setColorFilter(cf);
     }
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index d11e554..61dd675 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -116,6 +116,7 @@
      *
      * @return A value between 0 and 255.
      */
+    @Override
     public int getAlpha() {
         return mState.mUseColor >>> 24;
     }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index d5183d5..8135716 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -411,6 +411,17 @@
     public abstract void setAlpha(int alpha);
 
     /**
+     * Gets the current alpha value for the drawable. 0 means fully transparent,
+     * 255 means fully opaque. This method is implemented by
+     * Drawable subclasses and the value returned is specific to how that class treats alpha.
+     * The default return value is 255 if the class does not override this method to return a value
+     * specific to its use of alpha.
+     */
+    public int getAlpha() {
+        return 0xFF;
+    }
+
+    /**
      * Specify an optional colorFilter for the drawable. Pass null to remove
      * any filters.
     */
@@ -561,6 +572,25 @@
     }
 
     /**
+     * Set whether this Drawable is automatically mirrored when its layout direction is RTL
+     * (right-to left). See {@link android.util.LayoutDirection}.
+     *
+     * @param mirrored Set to true if the Drawable should be mirrored, false if not.
+     */
+    public void setAutoMirrored(boolean mirrored) {
+    }
+
+    /**
+     * Tells if this Drawable will be automatically mirrored  when its layout direction is RTL
+     * right-to-left. See {@link android.util.LayoutDirection}.
+     *
+     * @return boolean Returns true if this Drawable will be automatically mirrored.
+     */
+    public boolean isAutoMirrored() {
+        return false;
+    }
+
+    /**
      * Return the opacity/transparency of this Drawable.  The returned value is
      * one of the abstract format constants in
      * {@link android.graphics.PixelFormat}:
@@ -858,10 +888,6 @@
             drawable = new StateListDrawable();
         } else if (name.equals("level-list")) {
             drawable = new LevelListDrawable();
-        /* Probably not doing this.
-        } else if (name.equals("mipmap")) {
-            drawable = new MipmapDrawable();
-        */
         } else if (name.equals("layer-list")) {
             drawable = new LayerDrawable();
         } else if (name.equals("transition")) {
@@ -985,6 +1011,13 @@
          * this drawable (and thus require completely reloading it).
          */
         public abstract int getChangingConfigurations();
+
+        /**
+         * @hide
+         */
+        public Bitmap getBitmap() {
+            return null;
+        }
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 0f84e86..e350e8d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -23,6 +23,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.SystemClock;
+import android.util.SparseArray;
 
 /**
  * A helper class that contains several {@link Drawable}s and selects which one to use.
@@ -76,7 +77,7 @@
                 | mDrawableContainerState.mChangingConfigurations
                 | mDrawableContainerState.mChildrenChangingConfigurations;
     }
-    
+
     @Override
     public boolean getPadding(Rect padding) {
         final Rect r = mDrawableContainerState.getConstantPadding();
@@ -114,6 +115,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mAlpha;
+    }
+
+    @Override
     public void setDither(boolean dither) {
         if (mDrawableContainerState.mDither != dither) {
             mDrawableContainerState.mDither = dither;
@@ -132,7 +138,7 @@
             }
         }
     }
-    
+
     /**
      * Change the global fade duration when a new drawable is entering
      * the scene.
@@ -141,7 +147,7 @@
     public void setEnterFadeDuration(int ms) {
         mDrawableContainerState.mEnterFadeDuration = ms;
     }
-    
+
     /**
      * Change the global fade duration when a new drawable is leaving
      * the scene.
@@ -150,7 +156,7 @@
     public void setExitFadeDuration(int ms) {
         mDrawableContainerState.mExitFadeDuration = ms;
     }
-    
+
     @Override
     protected void onBoundsChange(Rect bounds) {
         if (mLastDrawable != null) {
@@ -160,12 +166,25 @@
             mCurrDrawable.setBounds(bounds);
         }
     }
-    
+
     @Override
     public boolean isStateful() {
         return mDrawableContainerState.isStateful();
     }
-    
+
+    @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mDrawableContainerState.mAutoMirrored = mirrored;
+        if (mCurrDrawable != null) {
+            mCurrDrawable.mutate().setAutoMirrored(mDrawableContainerState.mAutoMirrored);
+        }
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mDrawableContainerState.mAutoMirrored;
+    }
+
     @Override
     public void jumpToCurrentState() {
         boolean changed = false;
@@ -228,7 +247,7 @@
         }
         return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1;
     }
-    
+
     @Override
     public int getMinimumWidth() {
         if (mDrawableContainerState.isConstantSize()) {
@@ -245,18 +264,21 @@
         return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0;
     }
 
+    @Override
     public void invalidateDrawable(Drawable who) {
         if (who == mCurrDrawable && getCallback() != null) {
             getCallback().invalidateDrawable(this);
         }
     }
 
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         if (who == mCurrDrawable && getCallback() != null) {
             getCallback().scheduleDrawable(this, what, when);
         }
     }
 
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         if (who == mCurrDrawable && getCallback() != null) {
             getCallback().unscheduleDrawable(this, what);
@@ -308,7 +330,7 @@
         }
 
         if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
-            Drawable d = mDrawableContainerState.mDrawables[idx];
+            final Drawable d = mDrawableContainerState.getChild(idx);
             mCurrDrawable = d;
             mCurIndex = idx;
             if (d != null) {
@@ -325,6 +347,7 @@
                 d.setLevel(getLevel());
                 d.setBounds(getBounds());
                 d.setLayoutDirection(getLayoutDirection());
+                d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
             }
         } else {
             mCurrDrawable = null;
@@ -350,7 +373,7 @@
 
         return true;
     }
-    
+
     void animate(boolean schedule) {
         final long now = SystemClock.uptimeMillis();
         boolean animating = false;
@@ -410,11 +433,7 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            final int N = mDrawableContainerState.getChildCount();
-            final Drawable[] drawables = mDrawableContainerState.getChildren();
-            for (int i = 0; i < N; i++) {
-                if (drawables[i] != null) drawables[i].mutate();
-            }
+            mDrawableContainerState.mutate();
             mMutated = true;
         }
         return this;
@@ -428,90 +447,108 @@
      */
     public abstract static class DrawableContainerState extends ConstantState {
         final DrawableContainer mOwner;
+        final Resources mRes;
 
-        int         mChangingConfigurations;
-        int         mChildrenChangingConfigurations;
-        
-        Drawable[]  mDrawables;
-        int         mNumChildren;
+        SparseArray<ConstantStateFuture> mDrawableFutures;
 
-        boolean     mVariablePadding = false;
-        Rect        mConstantPadding = null;
+        int mChangingConfigurations;
+        int mChildrenChangingConfigurations;
 
-        boolean     mConstantSize = false;
-        boolean     mComputedConstantSize = false;
-        int         mConstantWidth;
-        int         mConstantHeight;
-        int         mConstantMinimumWidth;
-        int         mConstantMinimumHeight;
+        Drawable[] mDrawables;
+        int mNumChildren;
 
-        int         mOpacity;
+        boolean mVariablePadding;
+        boolean mPaddingChecked;
+        Rect mConstantPadding;
 
-        boolean     mHaveStateful = false;
-        boolean     mStateful;
+        boolean mConstantSize;
+        boolean mComputedConstantSize;
+        int mConstantWidth;
+        int mConstantHeight;
+        int mConstantMinimumWidth;
+        int mConstantMinimumHeight;
 
-        boolean     mCheckedConstantState;
-        boolean     mCanConstantState;
+        boolean mCheckedOpacity;
+        int mOpacity;
 
-        boolean     mPaddingChecked = false;
-        
-        boolean     mDither = DEFAULT_DITHER;        
+        boolean mCheckedStateful;
+        boolean mStateful;
 
-        int         mEnterFadeDuration;
-        int         mExitFadeDuration;
+        boolean mCheckedConstantState;
+        boolean mCanConstantState;
+
+        boolean mDither = DEFAULT_DITHER;
+
+        boolean mMutated;
+        int mLayoutDirection;
+
+        int mEnterFadeDuration;
+        int mExitFadeDuration;
+
+        boolean mAutoMirrored;
 
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
+            mRes = res;
 
             if (orig != null) {
                 mChangingConfigurations = orig.mChangingConfigurations;
                 mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
-                
-                final Drawable[] origDr = orig.mDrawables;
 
+                mCheckedConstantState = true;
+                mCanConstantState = true;
+
+                mVariablePadding = orig.mVariablePadding;
+                mConstantSize = orig.mConstantSize;
+                mDither = orig.mDither;
+                mMutated = orig.mMutated;
+                mLayoutDirection = orig.mLayoutDirection;
+                mEnterFadeDuration = orig.mEnterFadeDuration;
+                mExitFadeDuration = orig.mExitFadeDuration;
+                mAutoMirrored = orig.mAutoMirrored;
+
+                // Cloning the following values may require creating futures.
+                mConstantPadding = orig.getConstantPadding();
+                mPaddingChecked = true;
+
+                mConstantWidth = orig.getConstantWidth();
+                mConstantHeight = orig.getConstantHeight();
+                mConstantMinimumWidth = orig.getConstantMinimumWidth();
+                mConstantMinimumHeight = orig.getConstantMinimumHeight();
+                mComputedConstantSize = true;
+
+                mOpacity = orig.getOpacity();
+                mCheckedOpacity = true;
+
+                mStateful = orig.isStateful();
+                mCheckedStateful = true;
+
+                // Postpone cloning children and futures until we're absolutely
+                // sure that we're done computing values for the original state.
+                final Drawable[] origDr = orig.mDrawables;
                 mDrawables = new Drawable[origDr.length];
                 mNumChildren = orig.mNumChildren;
 
+                final SparseArray<ConstantStateFuture> origDf = orig.mDrawableFutures;
+                if (origDf != null) {
+                    mDrawableFutures = origDf.clone();
+                } else {
+                    mDrawableFutures = new SparseArray<ConstantStateFuture>(mNumChildren);
+                }
+
                 final int N = mNumChildren;
-                for (int i=0; i<N; i++) {
-                    if (res != null) {
-                        mDrawables[i] = origDr[i].getConstantState().newDrawable(res);
-                    } else {
-                        mDrawables[i] = origDr[i].getConstantState().newDrawable();
+                for (int i = 0; i < N; i++) {
+                    if (origDr[i] != null) {
+                        mDrawableFutures.put(i, new ConstantStateFuture(origDr[i]));
                     }
-                    mDrawables[i].setCallback(owner);
-                    mDrawables[i].setLayoutDirection(origDr[i].getLayoutDirection());
                 }
-
-                mCheckedConstantState = mCanConstantState = true;
-                mVariablePadding = orig.mVariablePadding;
-                if (orig.mConstantPadding != null) {
-                    mConstantPadding = new Rect(orig.mConstantPadding);
-                }
-                mConstantSize = orig.mConstantSize;
-                mComputedConstantSize = orig.mComputedConstantSize;
-                mConstantWidth = orig.mConstantWidth;
-                mConstantHeight = orig.mConstantHeight;
-                mConstantMinimumWidth = orig.mConstantMinimumWidth;
-                mConstantMinimumHeight = orig.mConstantMinimumHeight;
-                
-                mOpacity = orig.mOpacity;
-                mHaveStateful = orig.mHaveStateful;
-                mStateful = orig.mStateful;
-                
-                mDither = orig.mDither;
-
-                mEnterFadeDuration = orig.mEnterFadeDuration;
-                mExitFadeDuration = orig.mExitFadeDuration;
-
             } else {
                 mDrawables = new Drawable[10];
                 mNumChildren = 0;
-                mCheckedConstantState = mCanConstantState = false;
             }
         }
-        
+
         @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations | mChildrenChangingConfigurations;
@@ -530,7 +567,8 @@
             mDrawables[pos] = dr;
             mNumChildren++;
             mChildrenChangingConfigurations |= dr.getChangingConfigurations();
-            mHaveStateful = false;
+            mCheckedStateful = false;
+            mCheckedOpacity = false;
 
             mConstantPadding = null;
             mPaddingChecked = false;
@@ -539,18 +577,89 @@
             return pos;
         }
 
+        final int getCapacity() {
+            return mDrawables.length;
+        }
+
+        private final void createAllFutures() {
+            if (mDrawableFutures != null) {
+                final int futureCount = mDrawableFutures.size();
+                for (int keyIndex = 0; keyIndex < futureCount; keyIndex++) {
+                    final int index = mDrawableFutures.keyAt(keyIndex);
+                    mDrawables[index] = mDrawableFutures.valueAt(keyIndex).get(this);
+                }
+
+                mDrawableFutures = null;
+            }
+        }
+
         public final int getChildCount() {
             return mNumChildren;
         }
 
+        /*
+         * @deprecated Use {@link #getChild} instead.
+         */
         public final Drawable[] getChildren() {
+            // Create all futures for backwards compatibility.
+            createAllFutures();
+
             return mDrawables;
         }
 
-        /** A boolean value indicating whether to use the maximum padding value of 
-          * all frames in the set (false), or to use the padding value of the frame 
-          * being shown (true). Default value is false. 
-          */
+        public final Drawable getChild(int index) {
+            final Drawable result = mDrawables[index];
+            if (result != null) {
+                return result;
+            }
+
+            // Prepare future drawable if necessary.
+            if (mDrawableFutures != null) {
+                final int keyIndex = mDrawableFutures.indexOfKey(index);
+                if (keyIndex >= 0) {
+                    final Drawable prepared = mDrawableFutures.valueAt(keyIndex).get(this);
+                    mDrawables[index] = prepared;
+                    mDrawableFutures.removeAt(keyIndex);
+                    return prepared;
+                }
+            }
+
+            return null;
+        }
+
+        final void setLayoutDirection(int layoutDirection) {
+            // No need to call createAllFutures, since future drawables will
+            // change layout direction when they are prepared.
+            final int N = mNumChildren;
+            final Drawable[] drawables = mDrawables;
+            for (int i = 0; i < N; i++) {
+                if (drawables[i] != null) {
+                    drawables[i].setLayoutDirection(layoutDirection);
+                }
+            }
+
+            mLayoutDirection = layoutDirection;
+        }
+
+        final void mutate() {
+            // No need to call createAllFutures, since future drawables will
+            // mutate when they are prepared.
+            final int N = mNumChildren;
+            final Drawable[] drawables = mDrawables;
+            for (int i = 0; i < N; i++) {
+                if (drawables[i] != null) {
+                    drawables[i].mutate();
+                }
+            }
+
+            mMutated = true;
+        }
+
+        /**
+         * A boolean value indicating whether to use the maximum padding value
+         * of all frames in the set (false), or to use the padding value of the
+         * frame being shown (true). Default value is false.
+         */
         public final void setVariablePadding(boolean variable) {
             mVariablePadding = variable;
         }
@@ -559,13 +668,16 @@
             if (mVariablePadding) {
                 return null;
             }
-            if (mConstantPadding != null || mPaddingChecked) {
+
+            if ((mConstantPadding != null) || mPaddingChecked) {
                 return mConstantPadding;
             }
 
+            createAllFutures();
+
             Rect r = null;
             final Rect t = new Rect();
-            final int N = getChildCount();
+            final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
             for (int i = 0; i < N; i++) {
                 if (drawables[i].getPadding(t)) {
@@ -576,6 +688,7 @@
                     if (t.bottom > r.bottom) r.bottom = t.bottom;
                 }
             }
+
             mPaddingChecked = true;
             return (mConstantPadding = r);
         }
@@ -623,12 +736,14 @@
         protected void computeConstantSize() {
             mComputedConstantSize = true;
 
-            final int N = getChildCount();
+            createAllFutures();
+
+            final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
             mConstantWidth = mConstantHeight = -1;
             mConstantMinimumWidth = mConstantMinimumHeight = 0;
             for (int i = 0; i < N; i++) {
-                Drawable dr = drawables[i];
+                final Drawable dr = drawables[i];
                 int s = dr.getIntrinsicWidth();
                 if (s > mConstantWidth) mConstantWidth = s;
                 s = dr.getIntrinsicHeight();
@@ -657,33 +772,45 @@
         }
 
         public final int getOpacity() {
-            final int N = getChildCount();
+            if (mCheckedOpacity) {
+                return mOpacity;
+            }
+
+            createAllFutures();
+
+            mCheckedOpacity = true;
+
+            final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
-            int op = N > 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT;
+            int op = (N > 0) ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT;
             for (int i = 1; i < N; i++) {
                 op = Drawable.resolveOpacity(op, drawables[i].getOpacity());
             }
+
             mOpacity = op;
             return op;
         }
 
         public final boolean isStateful() {
-            if (mHaveStateful) {
+            if (mCheckedStateful) {
                 return mStateful;
             }
-            
-            boolean stateful = false;
-            final int N = getChildCount();
+
+            createAllFutures();
+
+            mCheckedStateful = true;
+
+            final int N = mNumChildren;
+            final Drawable[] drawables = mDrawables;
             for (int i = 0; i < N; i++) {
-                if (mDrawables[i].isStateful()) {
-                    stateful = true;
-                    break;
+                if (drawables[i].isStateful()) {
+                    mStateful = true;
+                    return true;
                 }
             }
-            
-            mStateful = stateful;
-            mHaveStateful = true;
-            return stateful;
+
+            mStateful = false;
+            return false;
         }
 
         public void growArray(int oldSize, int newSize) {
@@ -693,24 +820,60 @@
         }
 
         public synchronized boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = true;
-                final int N = mNumChildren;
-                for (int i=0; i<N; i++) {
-                    if (mDrawables[i].getConstantState() == null) {
-                        mCanConstantState = false;
-                        break;
-                    }
-                }
-                mCheckedConstantState = true;
+            if (mCheckedConstantState) {
+                return mCanConstantState;
             }
 
-            return mCanConstantState;
+            createAllFutures();
+
+            mCheckedConstantState = true;
+
+            final int N = mNumChildren;
+            final Drawable[] drawables = mDrawables;
+            for (int i = 0; i < N; i++) {
+                if (drawables[i].getConstantState() == null) {
+                    mCanConstantState = false;
+                    return false;
+                }
+            }
+
+            mCanConstantState = true;
+            return true;
+        }
+
+        /**
+         * Class capable of cloning a Drawable from another Drawable's
+         * ConstantState.
+         */
+        private static class ConstantStateFuture {
+            private final ConstantState mConstantState;
+
+            private ConstantStateFuture(Drawable source) {
+                mConstantState = source.getConstantState();
+            }
+
+            /**
+             * Obtains and prepares the Drawable represented by this future.
+             *
+             * @param state the container into which this future will be placed
+             * @return a prepared Drawable
+             */
+            public Drawable get(DrawableContainerState state) {
+                final Drawable result = (state.mRes == null) ?
+                        mConstantState.newDrawable() : mConstantState.newDrawable(state.mRes);
+                result.setLayoutDirection(state.mLayoutDirection);
+                result.setCallback(state.mOwner);
+
+                if (state.mMutated) {
+                    result.mutate();
+                }
+
+                return result;
+            }
         }
     }
 
-    protected void setConstantState(DrawableContainerState state)
-    {
+    protected void setConstantState(DrawableContainerState state) {
         mDrawableContainerState = state;
     }
 }
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index b966bb4..b340777 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -19,6 +19,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.DashPathEffect;
 import android.graphics.LinearGradient;
@@ -639,6 +640,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mAlpha;
+    }
+
+    @Override
     public void setDither(boolean dither) {
         if (dither != mDither) {
             mDither = dither;
@@ -742,9 +748,6 @@
 
                     mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
                             colors, st.mPositions, Shader.TileMode.CLAMP));
-                    if (!mGradientState.mHasSolidColor) {
-                        mFillPaint.setColor(mAlpha << 24);
-                    }
                 } else if (st.mGradient == RADIAL_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -754,9 +757,6 @@
                     mFillPaint.setShader(new RadialGradient(x0, y0,
                             level * st.mGradientRadius, colors, null,
                             Shader.TileMode.CLAMP));
-                    if (!mGradientState.mHasSolidColor) {
-                        mFillPaint.setColor(mAlpha << 24);
-                    }
                 } else if (st.mGradient == SWEEP_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -787,9 +787,12 @@
 
                     }
                     mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));
-                    if (!mGradientState.mHasSolidColor) {
-                        mFillPaint.setColor(mAlpha << 24);
-                    }
+                }
+
+                // If we don't have a solid color, the alpha channel must be
+                // maxed out so that alpha modulation works correctly.
+                if (!st.mHasSolidColor) {
+                    mFillPaint.setColor(Color.BLACK);
                 }
             }
         }
@@ -1276,6 +1279,9 @@
             // the app is stroking the shape, set the color to the default
             // value of state.mSolidColor
             mFillPaint.setColor(0);
+        } else {
+            // Otherwise, make sure the fill alpha is maxed out.
+            mFillPaint.setColor(Color.BLACK);
         }
         mPadding = state.mPadding;
         if (state.mStrokeWidth >= 0) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 2576f42e..8188782 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -192,12 +192,23 @@
     public void setAlpha(int alpha) {
         mInsetState.mDrawable.setAlpha(alpha);
     }
-    
+
+    @Override
+    public int getAlpha() {
+        return mInsetState.mDrawable.getAlpha();
+    }
+
     @Override
     public void setColorFilter(ColorFilter cf) {
         mInsetState.mDrawable.setColorFilter(cf);
     }
-    
+
+    /** {@hide} */
+    @Override
+    public void setLayoutDirection(int layoutDirection) {
+        mInsetState.mDrawable.setLayoutDirection(layoutDirection);
+    }
+
     @Override
     public int getOpacity() {
         return mInsetState.mDrawable.getOpacity();
@@ -256,6 +267,13 @@
         return this;
     }
 
+    /**
+     * Returns the drawable wrapped by this InsetDrawable. May be null.
+     */
+    public Drawable getDrawable() {
+        return mInsetState.mDrawable;
+    }
+
     final static class InsetState extends ConstantState {
         Drawable mDrawable;
         int mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 6b59dba..81cc11b 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -119,6 +119,9 @@
         mOpacityOverride = a.getInt(com.android.internal.R.styleable.LayerDrawable_opacity,
                 PixelFormat.UNKNOWN);
 
+        setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored,
+                false));
+
         a.recycle();
 
         final int innerDepth = parser.getDepth() + 1;
@@ -200,6 +203,7 @@
         st.mChildren[i] = childDrawable;
         childDrawable.mId = id;
         childDrawable.mDrawable = layer;
+        childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
         childDrawable.mInsetL = left;
         childDrawable.mInsetT = top;
         childDrawable.mInsetR = right;
@@ -402,7 +406,18 @@
             array[i].mDrawable.setAlpha(alpha);
         }
     }
-    
+
+    @Override
+    public int getAlpha() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        if (mLayerState.mNum > 0) {
+            // All layers should have the same alpha set on them - just return the first one
+            return array[0].mDrawable.getAlpha();
+        } else {
+            return super.getAlpha();
+        }
+    }
+
     @Override
     public void setColorFilter(ColorFilter cf) {
         final ChildDrawable[] array = mLayerState.mChildren;
@@ -437,6 +452,21 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mLayerState.mAutoMirrored = mirrored;
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i=0; i<N; i++) {
+            array[i].mDrawable.setAutoMirrored(mirrored);
+        }
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mLayerState.mAutoMirrored;
+    }
+
+    @Override
     public boolean isStateful() {
         return mLayerState.isStateful();
     }
@@ -619,6 +649,8 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
+        private boolean mAutoMirrored;
+
         LayerState(LayerState orig, LayerDrawable owner, Resources res) {
             if (orig != null) {
                 final ChildDrawable[] origChildDrawable = orig.mChildren;
@@ -652,6 +684,7 @@
                 mHaveStateful = orig.mHaveStateful;
                 mStateful = orig.mStateful;
                 mCheckedConstantState = mCanConstantState = true;
+                mAutoMirrored = orig.mAutoMirrored;
             } else {
                 mNum = 0;
                 mChildren = null;
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 21be983..872fdce 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -164,8 +164,8 @@
                 mLows = orig.mLows;
                 mHighs = orig.mHighs;
             } else {
-                mLows = new int[getChildren().length];
-                mHighs = new int[getChildren().length];
+                mLows = new int[getCapacity()];
+                mHighs = new int[getCapacity()];
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/MipmapDrawable.java b/graphics/java/android/graphics/drawable/MipmapDrawable.java
deleted file mode 100644
index cd39719..0000000
--- a/graphics/java/android/graphics/drawable/MipmapDrawable.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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.
- */
-
-package android.graphics.drawable;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-
-import java.io.IOException;
-
-/**
- * @hide -- we are probably moving to do MipMaps in another way (more integrated
- * with the resource system).
- *
- * A resource that manages a number of alternate Drawables, and which actually draws the one which
- * size matches the most closely the drawing bounds. Providing several pre-scaled version of the
- * drawable helps minimizing the aliasing artifacts that can be introduced by the scaling.
- *
- * <p>
- * Use {@link #addDrawable(Drawable)} to define the different Drawables that will represent the
- * mipmap levels of this MipmapDrawable. The mipmap Drawable that will actually be used when this
- * MipmapDrawable is drawn is the one which has the smallest intrinsic height greater or equal than
- * the bounds' height. This selection ensures that the best available mipmap level is scaled down to
- * draw this MipmapDrawable.
- * </p>
- *
- * If the bounds' height is larger than the largest mipmap, the largest mipmap will be scaled up.
- * Note that Drawables without intrinsic height (i.e. with a negative value, such as Color) will
- * only be used if no other mipmap Drawable are provided. The Drawables' intrinsic heights should
- * not be changed after the Drawable has been added to this MipmapDrawable.
- *
- * <p>
- * The different mipmaps' parameters (opacity, padding, color filter, gravity...) should typically
- * be similar to ensure a continuous visual appearance when the MipmapDrawable is scaled. The aspect
- * ratio of the different mipmaps should especially be equal.
- * </p>
- *
- * A typical example use of a MipmapDrawable would be for an image which is intended to be scaled at
- * various sizes, and for which one wants to provide pre-scaled versions to precisely control its
- * appearance.
- *
- * <p>
- * The intrinsic size of a MipmapDrawable are inferred from those of the largest mipmap (in terms of
- * {@link Drawable#getIntrinsicHeight()}). On the opposite, its minimum
- * size is defined by the smallest provided mipmap.
- * </p>
-
- * It can be defined in an XML file with the <code>&lt;mipmap></code> element.
- * Each mipmap Drawable is defined in a nested <code>&lt;item></code>. For example:
- * <pre>
- * &lt;mipmap xmlns:android="http://schemas.android.com/apk/res/android">
- *  &lt;item android:drawable="@drawable/my_image_8" />
- *  &lt;item android:drawable="@drawable/my_image_32" />
- *  &lt;item android:drawable="@drawable/my_image_128" />
- * &lt;/mipmap>
- *</pre>
- * <p>
- * With this XML saved into the res/drawable/ folder of the project, it can be referenced as
- * the drawable for an {@link android.widget.ImageView}. Assuming that the heights of the provided
- * drawables are respectively 8, 32 and 128 pixels, the first one will be scaled down when the
- * bounds' height is lower or equal than 8 pixels. The second drawable will then be used up to a
- * height of 32 pixels and the largest drawable will be used for greater heights.
- * </p>
- * @attr ref android.R.styleable#MipmapDrawableItem_drawable
- */
-public class MipmapDrawable extends DrawableContainer {
-    private final MipmapContainerState mMipmapContainerState;
-    private boolean mMutated;
-
-    public MipmapDrawable() {
-        this(null, null);
-    }
-
-    /**
-     * Adds a Drawable to the list of available mipmap Drawables. The Drawable actually used when
-     * this MipmapDrawable is drawn is determined from its bounds.
-     *
-     * This method has no effect if drawable is null.
-     *
-     * @param drawable The Drawable that will be added to list of available mipmap Drawables.
-     */
-
-    public void addDrawable(Drawable drawable) {
-        if (drawable != null) {
-            mMipmapContainerState.addDrawable(drawable);
-            onDrawableAdded();
-        }
-    }
-
-    private void onDrawableAdded() {
-        // selectDrawable assumes that the container content does not change.
-        // When a Drawable is added, the same index can correspond to a new Drawable, and since
-        // selectDrawable has a fast exit case when oldIndex==newIndex, the new drawable could end
-        // up not being used in place of the previous one if they happen to share the same index.
-        // This make sure the new computed index can actually replace the previous one.
-        selectDrawable(-1);
-        onBoundsChange(getBounds());
-    }
-
-    // overrides from Drawable
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        final int index = mMipmapContainerState.indexForBounds(bounds);
-
-        // Will call invalidateSelf() if needed
-        selectDrawable(index);
-
-        super.onBoundsChange(bounds);
-    }
-
-    @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
-    throws XmlPullParserException, IOException {
-
-        super.inflate(r, parser, attrs);
-
-        int type;
-
-        final int innerDepth = parser.getDepth() + 1;
-        int depth;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth
-                        || type != XmlPullParser.END_TAG)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (depth > innerDepth || !parser.getName().equals("item")) {
-                continue;
-            }
-
-            TypedArray a = r.obtainAttributes(attrs,
-                    com.android.internal.R.styleable.MipmapDrawableItem);
-
-            int drawableRes = a.getResourceId(
-                    com.android.internal.R.styleable.MipmapDrawableItem_drawable, 0);
-
-            a.recycle();
-
-            Drawable dr;
-            if (drawableRes != 0) {
-                dr = r.getDrawable(drawableRes);
-            } else {
-                while ((type = parser.next()) == XmlPullParser.TEXT) {
-                }
-                if (type != XmlPullParser.START_TAG) {
-                    throw new XmlPullParserException(
-                            parser.getPositionDescription()
-                            + ": <item> tag requires a 'drawable' attribute or "
-                            + "child tag defining a drawable");
-                }
-                dr = Drawable.createFromXmlInner(r, parser, attrs);
-            }
-
-            mMipmapContainerState.addDrawable(dr);
-        }
-
-        onDrawableAdded();
-    }
-
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mMipmapContainerState.mMipmapHeights = mMipmapContainerState.mMipmapHeights.clone();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    private final static class MipmapContainerState extends DrawableContainerState {
-        private int[] mMipmapHeights;
-
-        MipmapContainerState(MipmapContainerState orig, MipmapDrawable owner, Resources res) {
-            super(orig, owner, res);
-
-            if (orig != null) {
-                mMipmapHeights = orig.mMipmapHeights;
-            } else {
-                mMipmapHeights = new int[getChildren().length];
-            }
-
-            // Change the default value
-            setConstantSize(true);
-        }
-
-        /**
-         * Returns the index of the child mipmap drawable that will best fit the provided bounds.
-         * This index is determined by comparing bounds' height and children intrinsic heights.
-         * The returned mipmap index is the smallest mipmap which height is greater or equal than
-         * the bounds' height. If the bounds' height is larger than the largest mipmap, the largest
-         * mipmap index is returned.
-         *
-         * @param bounds The bounds of the MipMapDrawable.
-         * @return The index of the child Drawable that will best fit these bounds, or -1 if there
-         * are no children mipmaps.
-         */
-        public int indexForBounds(Rect bounds) {
-            final int boundsHeight = bounds.height();
-            final int N = getChildCount();
-            for (int i = 0; i < N; i++) {
-                if (boundsHeight <= mMipmapHeights[i]) {
-                    return i;
-                }
-            }
-
-            // No mipmap larger than bounds found. Use largest one which will be scaled up.
-            if (N > 0) {
-                return N - 1;
-            }
-            // No Drawable mipmap at all
-            return -1;
-        }
-
-        /**
-         * Adds a Drawable to the list of available mipmap Drawables. This list can be retrieved
-         * using {@link DrawableContainer.DrawableContainerState#getChildren()} and this method
-         * ensures that it is always sorted by increasing {@link Drawable#getIntrinsicHeight()}.
-         *
-         * @param drawable The Drawable that will be added to children list
-         */
-        public void addDrawable(Drawable drawable) {
-            // Insert drawable in last position, correctly resetting cached values and
-            // especially mComputedConstantSize
-            int pos = addChild(drawable);
-
-            // Bubble sort the last drawable to restore the sort by intrinsic height
-            final int drawableHeight = drawable.getIntrinsicHeight();
-
-            while (pos > 0) {
-                final Drawable previousDrawable = mDrawables[pos-1];
-                final int previousIntrinsicHeight = previousDrawable.getIntrinsicHeight();
-
-                if (drawableHeight < previousIntrinsicHeight) {
-                    mDrawables[pos] = previousDrawable;
-                    mMipmapHeights[pos] = previousIntrinsicHeight;
-
-                    mDrawables[pos-1] = drawable;
-                    mMipmapHeights[pos-1] = drawableHeight;
-                    pos--;
-                } else {
-                    break;
-                }
-            }
-        }
-
-        /**
-         * Intrinsic sizes are those of the largest available mipmap.
-         * Minimum sizes are those of the smallest available mipmap.
-         */
-        @Override
-        protected void computeConstantSize() {
-            final int N = getChildCount();
-            if (N > 0) {
-                final Drawable smallestDrawable = mDrawables[0];
-                mConstantMinimumWidth = smallestDrawable.getMinimumWidth();
-                mConstantMinimumHeight = smallestDrawable.getMinimumHeight();
-
-                final Drawable largestDrawable = mDrawables[N-1];
-                mConstantWidth = largestDrawable.getIntrinsicWidth();
-                mConstantHeight = largestDrawable.getIntrinsicHeight();
-            } else {
-                mConstantWidth = mConstantHeight = -1;
-                mConstantMinimumWidth = mConstantMinimumHeight = 0;
-            }
-            mComputedConstantSize = true;
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new MipmapDrawable(this, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res) {
-            return new MipmapDrawable(this, res);
-        }
-
-        @Override
-        public void growArray(int oldSize, int newSize) {
-            super.growArray(oldSize, newSize);
-            int[] newInts = new int[newSize];
-            System.arraycopy(mMipmapHeights, 0, newInts, 0, oldSize);
-            mMipmapHeights = newInts;
-        }
-    }
-
-    private MipmapDrawable(MipmapContainerState state, Resources res) {
-        MipmapContainerState as = new MipmapContainerState(state, this, res);
-        mMipmapContainerState = as;
-        setConstantState(as);
-        onDrawableAdded();
-    }
-}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index a9dc22b..ab34c0f 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -30,6 +30,7 @@
 import android.graphics.Region;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.LayoutDirection;
 import android.util.TypedValue;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -52,7 +53,7 @@
  */
 public class NinePatchDrawable extends Drawable {
     // dithering helps a lot, and is pretty cheap, so default is true
-    private static final boolean DEFAULT_DITHER = true;
+    private static final boolean DEFAULT_DITHER = false;
     private NinePatchState mNinePatchState;
     private NinePatch mNinePatch;
     private Rect mPadding;
@@ -132,6 +133,7 @@
             // lazy allocation of a paint
             setDither(state.mDither);
         }
+        setAutoMirrored(state.mAutoMirrored);
         if (mNinePatch != null) {
             computeBitmapSize();
         }
@@ -197,10 +199,8 @@
             mBitmapHeight = mNinePatch.getHeight();
             mOpticalInsets = mNinePatchState.mOpticalInsets;
         } else {
-            mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(),
-                    sdensity, tdensity);
-            mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(),
-                    sdensity, tdensity);
+            mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), sdensity, tdensity);
+            mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(), sdensity, tdensity);
             if (mNinePatchState.mPadding != null && mPadding != null) {
                 Rect dest = mPadding;
                 Rect src = mNinePatchState.mPadding;
@@ -218,7 +218,18 @@
 
     @Override
     public void draw(Canvas canvas) {
-        mNinePatch.draw(canvas, getBounds(), mPaint);
+        final Rect bounds = getBounds();
+        final boolean needsMirroring = needsMirroring();
+        if (needsMirroring) {
+            canvas.save();
+            // Mirror the 9patch
+            canvas.translate(bounds.right - bounds.left, 0);
+            canvas.scale(-1.0f, 1.0f);
+        }
+        mNinePatch.draw(canvas, bounds, mPaint);
+        if (needsMirroring) {
+            canvas.restore();
+        }
     }
 
     @Override
@@ -228,7 +239,11 @@
 
     @Override
     public boolean getPadding(Rect padding) {
-        padding.set(mPadding);
+        if (needsMirroring()) {
+            padding.set(mPadding.right, mPadding.top, mPadding.left, mPadding.bottom);
+        } else {
+            padding.set(mPadding);
+        }
         return true;
     }
 
@@ -237,7 +252,12 @@
      */
     @Override
     public Insets getOpticalInsets() {
-        return mOpticalInsets;
+        if (needsMirroring()) {
+            return Insets.of(mOpticalInsets.right, mOpticalInsets.top, mOpticalInsets.right,
+                    mOpticalInsets.bottom);
+        } else {
+            return mOpticalInsets;
+        }
     }
 
     @Override
@@ -251,6 +271,15 @@
     }
 
     @Override
+    public int getAlpha() {
+        if (mPaint == null) {
+            // Fast common case -- normal alpha.
+            return 0xFF;
+        }
+        return getPaint().getAlpha();
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         if (mPaint == null && cf == null) {
             // Fast common case -- leave at no color filter.
@@ -262,6 +291,7 @@
 
     @Override
     public void setDither(boolean dither) {
+        //noinspection PointlessBooleanExpression
         if (mPaint == null && dither == DEFAULT_DITHER) {
             // Fast common case -- leave at default dither.
             return;
@@ -271,6 +301,20 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mNinePatchState.mAutoMirrored = mirrored;
+    }
+
+    private boolean needsMirroring() {
+        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mNinePatchState.mAutoMirrored;
+    }
+
+    @Override
     public void setFilterBitmap(boolean filter) {
         getPaint().setFilterBitmap(filter);
         invalidateSelf();
@@ -290,8 +334,7 @@
         }
 
         final boolean dither = a.getBoolean(
-                com.android.internal.R.styleable.NinePatchDrawable_dither,
-                DEFAULT_DITHER);
+                com.android.internal.R.styleable.NinePatchDrawable_dither, DEFAULT_DITHER);
         final BitmapFactory.Options options = new BitmapFactory.Options();
         if (dither) {
             options.inDither = false;
@@ -321,9 +364,11 @@
                     ": <nine-patch> requires a valid 9-patch source image");
         }
 
-        setNinePatchState(new NinePatchState(
-                new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
-                padding, opticalInsets, dither), r);
+        final boolean automirrored = a.getBoolean(
+                com.android.internal.R.styleable.NinePatchDrawable_autoMirrored, false);
+
+        setNinePatchState(new NinePatchState(new NinePatch(bitmap, bitmap.getNinePatchChunk()),
+                padding, opticalInsets, dither, automirrored), r);
         mNinePatchState.mTargetDensity = mTargetDensity;
 
         a.recycle();
@@ -394,39 +439,49 @@
         return this;
     }
 
-    private final static class NinePatchState extends ConstantState {
+    final static class NinePatchState extends ConstantState {
         final NinePatch mNinePatch;
         final Rect mPadding;
         final Insets mOpticalInsets;
         final boolean mDither;
         int mChangingConfigurations;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+        boolean mAutoMirrored;
 
         NinePatchState(NinePatch ninePatch, Rect padding) {
-            this(ninePatch, padding, new Rect(), DEFAULT_DITHER);
+            this(ninePatch, padding, new Rect(), DEFAULT_DITHER, false);
         }
 
         NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets) {
-            this(ninePatch, padding, opticalInsets, DEFAULT_DITHER);
+            this(ninePatch, padding, opticalInsets, DEFAULT_DITHER, false);
         }
 
-        NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither) {
+        NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither,
+                       boolean autoMirror) {
             mNinePatch = ninePatch;
             mPadding = rect;
             mOpticalInsets = Insets.of(opticalInsets);
             mDither = dither;
+            mAutoMirrored = autoMirror;
         }
 
         // Copy constructor
 
         NinePatchState(NinePatchState state) {
-            mNinePatch = new NinePatch(state.mNinePatch);
+            // Note we don't copy the nine patch because it is immutable.
+            mNinePatch = state.mNinePatch;
             // Note we don't copy the padding because it is immutable.
             mPadding = state.mPadding;
             mOpticalInsets = state.mOpticalInsets;
             mDither = state.mDither;
             mChangingConfigurations = state.mChangingConfigurations;
             mTargetDensity = state.mTargetDensity;
+            mAutoMirrored = state.mAutoMirrored;
+        }
+
+        @Override
+        public Bitmap getBitmap() {
+            return mNinePatch.getBitmap();
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 83d9581..aec3a4b 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -108,6 +108,11 @@
         mState.mDrawable.setAlpha(alpha);
     }
 
+    @Override
+    public int getAlpha() {
+        return mState.mDrawable.getAlpha();
+    }
+
     public void setColorFilter(ColorFilter cf) {
         mState.mDrawable.setColorFilter(cf);
     }
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 0664214..ec6b2c16 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -177,6 +177,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mScaleState.mDrawable.getAlpha();
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         mScaleState.mDrawable.setColorFilter(cf);
     }
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 1dbcddb..93f2dc60 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -252,7 +252,12 @@
         mShapeState.mAlpha = alpha;
         invalidateSelf();
     }
-    
+
+    @Override
+    public int getAlpha() {
+        return mShapeState.mAlpha;
+    }
+
     @Override
     public void setColorFilter(ColorFilter cf) {
         mShapeState.mPaint.setColorFilter(cf);
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index f8f3ac9..48d66b7 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -132,6 +132,9 @@
         setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither,
                                DEFAULT_DITHER));
 
+        setAutoMirrored(a.getBoolean(
+                com.android.internal.R.styleable.StateListDrawable_autoMirrored, false));
+
         a.recycle();
 
         int type;
@@ -228,7 +231,7 @@
      * @see #getStateSet(int)
      */
     public Drawable getStateDrawable(int index) {
-        return mStateListState.getChildren()[index];
+        return mStateListState.getChild(index);
     }
     
     /**
@@ -264,11 +267,11 @@
     /** @hide */
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        final int numStates = getStateCount();
-        for (int i = 0; i < numStates; i++) {
-            getStateDrawable(i).setLayoutDirection(layoutDirection);
-        }
         super.setLayoutDirection(layoutDirection);
+
+        // Let the container handle setting its own layout direction. Otherwise,
+        // we're accessing potentially unused states.
+        mStateListState.setLayoutDirection(layoutDirection);
     }
 
     static final class StateListState extends DrawableContainerState {
@@ -278,9 +281,9 @@
             super(orig, owner, res);
 
             if (orig != null) {
-                mStateSets = orig.mStateSets;
+                mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
             } else {
-                mStateSets = new int[getChildren().length][];
+                mStateSets = new int[getCapacity()][];
             }
         }
 
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
new file mode 100644
index 0000000..066ae2b
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -0,0 +1,424 @@
+/*
+ * 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 android.graphics.pdf;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+import dalvik.system.CloseGuard;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>
+ * This class enables generating a PDF document from native Android content. You
+ * open a new document and then for every page you want to add you start a page,
+ * write content to the page, and finish the page. After you are done with all
+ * pages, you write the document to an output stream and close the document.
+ * After a document is closed you should not use it anymore. Note that pages are
+ * created one by one, i.e. you can have only a single page to which you are
+ * writing at any given time. This class is not thread safe.
+ * </p>
+ * <p>
+ * A typical use of the APIs looks like this:
+ * </p>
+ * <pre>
+ * // create a new document
+ * PdfDocument document = new PdfDocument();
+ *
+ * // crate a page description
+ * PageInfo pageInfo = new PageInfo.Builder(new Rect(0, 0, 100, 100), 1).create();
+ *
+ * // start a page
+ * Page page = document.startPage(pageInfo);
+ *
+ * // draw something on the page
+ * View content = getContentView();
+ * content.draw(page.getCanvas());
+ *
+ * // finish the page
+ * document.finishPage(page);
+ * . . .
+ * // add more pages
+ * . . .
+ * // write the document content
+ * document.writeTo(getOutputStream());
+ *
+ * //close the document
+ * document.close();
+ * </pre>
+ */
+public class PdfDocument {
+
+    private final byte[] mChunk = new byte[4096];
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private final List<PageInfo> mPages = new ArrayList<PageInfo>();
+
+    private int mNativeDocument;
+
+    private Page mCurrentPage;
+
+    /**
+     * Creates a new instance.
+     */
+    public PdfDocument() {
+        mNativeDocument = nativeCreateDocument();
+        mCloseGuard.open("close");
+    }
+
+    /**
+     * Starts a page using the provided {@link PageInfo}. After the page
+     * is created you can draw arbitrary content on the page's canvas which
+     * you can get by calling {@link Page#getCanvas()}. After you are done
+     * drawing the content you should finish the page by calling
+     * {@link #finishPage(Page)}. After the page is finished you should
+     * no longer access the page or its canvas.
+     * <p>
+     * <strong>Note:</strong> Do not call this method after {@link #close()}.
+     * Also do not call this method if the last page returned by this method
+     * is not finished by calling {@link #finishPage(Page)}.
+     * </p>
+     *
+     * @param pageInfo The page info. Cannot be null.
+     * @return A blank page.
+     *
+     * @see #finishPage(Page)
+     */
+    public Page startPage(PageInfo pageInfo) {
+        throwIfClosed();
+        throwIfCurrentPageNotFinished();
+        if (pageInfo == null) {
+            throw new IllegalArgumentException("page cannot be null");
+        }
+        Canvas canvas = new PdfCanvas(nativeCreatePage(pageInfo.mPageWidth,
+                pageInfo.mPageHeight, pageInfo.mContentRect.left, pageInfo.mContentRect.top,
+                pageInfo.mContentRect.right, pageInfo.mContentRect.bottom));
+        mCurrentPage = new Page(canvas, pageInfo);
+        return mCurrentPage;
+    }
+
+    /**
+     * Finishes a started page. You should always finish the last started page.
+     * <p>
+     * <strong>Note:</strong> Do not call this method after {@link #close()}.
+     * You should not finish the same page more than once.
+     * </p>
+     *
+     * @param page The page. Cannot be null.
+     *
+     * @see #startPage(PageInfo)
+     */
+    public void finishPage(Page page) {
+        throwIfClosed();
+        if (page == null) {
+            throw new IllegalArgumentException("page cannot be null");
+        }
+        if (page != mCurrentPage) {
+            throw new IllegalStateException("invalid page");
+        }
+        if (page.isFinished()) {
+            throw new IllegalStateException("page already finished");
+        }
+        mPages.add(page.getInfo());
+        mCurrentPage = null;
+        nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas);
+        page.finish();
+    }
+
+    /**
+     * Writes the document to an output stream. You can call this method
+     * multiple times.
+     * <p>
+     * <strong>Note:</strong> Do not call this method after {@link #close()}.
+     * Also do not call this method if a page returned by {@link #startPage(
+     * PageInfo)} is not finished by calling {@link #finishPage(Page)}.
+     * </p>
+     *
+     * @param out The output stream. Cannot be null.
+     *
+     * @throws IOException If an error occurs while writing.
+     */
+    public void writeTo(OutputStream out) throws IOException {
+        throwIfClosed();
+        throwIfCurrentPageNotFinished();
+        if (out == null) {
+            throw new IllegalArgumentException("out cannot be null!");
+        }
+        nativeWriteTo(mNativeDocument, out, mChunk);
+    }
+
+    /**
+     * Gets the pages of the document.
+     *
+     * @return The pages or an empty list.
+     */
+    public List<PageInfo> getPages() {
+        return Collections.unmodifiableList(mPages);
+    }
+
+    /**
+     * Closes this document. This method should be called after you
+     * are done working with the document. After this call the document
+     * is considered closed and none of its methods should be called.
+     * <p>
+     * <strong>Note:</strong> Do not call this method if the page
+     * returned by {@link #startPage(PageInfo)} is not finished by
+     * calling {@link #finishPage(Page)}.
+     * </p>
+     */
+    public void close() {
+        throwIfCurrentPageNotFinished();
+        dispose();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            dispose();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private void dispose() {
+        if (mNativeDocument != 0) {
+            nativeFinalize(mNativeDocument);
+            mCloseGuard.close();
+            mNativeDocument = 0;
+        }
+    }
+
+    /**
+     * Throws an exception if the document is already closed.
+     */
+    private void throwIfClosed() {
+        if (mNativeDocument == 0) {
+            throw new IllegalStateException("document is closed!");
+        }
+    }
+
+    /**
+     * Throws an exception if the last started page is not finished.
+     */
+    private void throwIfCurrentPageNotFinished() {
+        if (mCurrentPage != null) {
+            throw new IllegalStateException("Current page not finished!");
+        }
+    }
+
+    private native int nativeCreateDocument();
+
+    private native void nativeFinalize(int document);
+
+    private native void nativeAppendPage(int document, int page);
+
+    private native void nativeWriteTo(int document, OutputStream out, byte[] chunk);
+
+    private static native int nativeCreatePage(int pageWidth, int pageHeight, int contentLeft,
+            int contentTop, int contentRight, int contentBottom);
+
+    private final class PdfCanvas extends Canvas {
+
+        public PdfCanvas(int nativeCanvas) {
+            super(nativeCanvas);
+        }
+
+        @Override
+        public void setBitmap(Bitmap bitmap) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * This class represents meta-data that describes a PDF {@link Page}.
+     */
+    public static final class PageInfo {
+        private int mPageWidth;
+        private int mPageHeight;
+        private Rect mContentRect;
+        private int mPageNumber;
+
+        /**
+         * Creates a new instance.
+         */
+        private PageInfo() {
+            /* do nothing */
+        }
+
+        /**
+         * Gets the page width in PostScript points (1/72th of an inch).
+         *
+         * @return The page width.
+         */
+        public int getPageWidth() {
+            return mPageWidth;
+        }
+
+        /**
+         * Gets the page height in PostScript points (1/72th of an inch).
+         *
+         * @return The page height.
+         */
+        public int getPageHeight() {
+            return mPageHeight;
+        }
+
+        /**
+         * Get the content rectangle in PostScript points (1/72th of an inch).
+         * This is the area that contains the page content and is relative to
+         * the page top left.
+         *
+         * @return The content rectangle.
+         */
+        public Rect getContentRect() {
+            return mContentRect;
+        }
+
+        /**
+         * Gets the page number.
+         *
+         * @return The page number.
+         */
+        public int getPageNumber() {
+            return mPageNumber;
+        }
+
+        /**
+         * Builder for creating a {@link PageInfo}.
+         */
+        public static final class Builder {
+            private final PageInfo mPageInfo = new PageInfo();
+
+            /**
+             * Creates a new builder with the mandatory page info attributes.
+             *
+             * @param pageWidth The page width in PostScript (1/72th of an inch).
+             * @param pageHeight The page height in PostScript (1/72th of an inch).
+             * @param pageNumber The page number.
+             */
+            public Builder(int pageWidth, int pageHeight, int pageNumber) {
+                if (pageWidth <= 0) {
+                    throw new IllegalArgumentException("page width must be positive");
+                }
+                if (pageHeight <= 0) {
+                    throw new IllegalArgumentException("page width must be positive");
+                }
+                if (pageNumber < 0) {
+                    throw new IllegalArgumentException("pageNumber must be non negative");
+                }
+                mPageInfo.mPageWidth = pageWidth;
+                mPageInfo.mPageHeight = pageHeight;
+                mPageInfo.mPageNumber = pageNumber;
+            }
+
+            /**
+             * Sets the content rectangle in PostScript point (1/72th of an inch).
+             * This is the area that contains the page content and is relative to
+             * the page top left.
+             *
+             * @param contentRect The content rectangle. Must fit in the page.
+             */
+            public Builder setContentRect(Rect contentRect) {
+                if (contentRect != null && (contentRect.left < 0
+                        || contentRect.top < 0
+                        || contentRect.right > mPageInfo.mPageWidth
+                        || contentRect.bottom > mPageInfo.mPageHeight)) {
+                    throw new IllegalArgumentException("contentRect does not fit the page");
+                }
+                mPageInfo.mContentRect = contentRect;
+                return this;
+            }
+
+            /**
+             * Creates a new {@link PageInfo}.
+             *
+             * @return The new instance.
+             */
+            public PageInfo create() {
+                if (mPageInfo.mContentRect == null) {
+                    mPageInfo.mContentRect = new Rect(0, 0,
+                            mPageInfo.mPageWidth, mPageInfo.mPageHeight);
+                }
+                return mPageInfo;
+            }
+        }
+    }
+
+    /**
+     * This class represents a PDF document page. It has associated
+     * a canvas on which you can draw content and is acquired by a
+     * call to {@link #getCanvas()}. It also has associated a
+     * {@link PageInfo} instance that describes its attributes. Also
+     * a page has 
+     */
+    public static final class Page {
+        private final PageInfo mPageInfo;
+        private Canvas mCanvas;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param canvas The canvas of the page.
+         * @param pageInfo The info with meta-data.
+         */
+        private Page(Canvas canvas, PageInfo pageInfo) {
+            mCanvas = canvas;
+            mPageInfo = pageInfo;
+        }
+
+        /**
+         * Gets the {@link Canvas} of the page.
+         *
+         * @return The canvas if the page is not finished, null otherwise.
+         *
+         * @see PdfDocument#finishPage(Page)
+         */
+        public Canvas getCanvas() {
+            return mCanvas;
+        }
+
+        /**
+         * Gets the {@link PageInfo} with meta-data for the page.
+         *
+         * @return The page info.
+         *
+         * @see PdfDocument#finishPage(Page)
+         */
+        public PageInfo getInfo() {
+            return mPageInfo;
+        }
+
+        boolean isFinished() {
+            return mCanvas == null;
+        }
+
+        private void finish() {
+            if (mCanvas != null) {
+                mCanvas.release();
+                mCanvas = null;
+            }
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/pdf/package.html b/graphics/java/android/graphics/pdf/package.html
new file mode 100644
index 0000000..51f2460
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Contains classes for manipulation of PDF content.
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index b460a4d..dca934f 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -28,6 +28,7 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.graphics.Canvas;
+import android.os.Trace;
 
 /**
  * <p> This class provides the primary method through which data is passed to
@@ -60,6 +61,7 @@
     Bitmap mBitmap;
     int mUsage;
     Allocation mAdaptedAllocation;
+    int mSize;
 
     boolean mConstrainedLOD;
     boolean mConstrainedFace;
@@ -78,7 +80,7 @@
     int mCurrentCount;
     static HashMap<Integer, Allocation> mAllocationMap =
             new HashMap<Integer, Allocation>();
-    IoInputNotifier mBufferNotifier;
+    OnBufferAvailableListener mBufferNotifier;
 
     /**
      * The usage of the Allocation.  These signal to RenderScript where to place
@@ -269,8 +271,23 @@
         mUsage = usage;
 
         if (t != null) {
+            // TODO: A3D doesn't have Type info during creation, so we can't
+            // calculate the size ahead of time. We can possibly add a method
+            // to update the size in the future if it seems reasonable.
+            mSize = mType.getCount() * mType.getElement().getBytesSize();
             updateCacheInfo(t);
         }
+        try {
+            RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
+        } catch (Exception e) {
+            Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
+            throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
+        super.finalize();
     }
 
     private void validateIsInt32() {
@@ -352,6 +369,7 @@
      *
      */
     public void syncAll(int srcLocation) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "syncAll");
         switch (srcLocation) {
         case USAGE_GRAPHICS_TEXTURE:
         case USAGE_SCRIPT:
@@ -372,6 +390,7 @@
         }
         mRS.validate();
         mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -382,12 +401,14 @@
      *
      */
     public void ioSend() {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "ioSend");
         if ((mUsage & USAGE_IO_OUTPUT) == 0) {
             throw new RSIllegalArgumentException(
                 "Can only send buffer if IO_OUTPUT usage specified.");
         }
         mRS.validate();
         mRS.nAllocationIoSend(getID(mRS));
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -404,12 +425,14 @@
      *
      */
     public void ioReceive() {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "ioReceive");
         if ((mUsage & USAGE_IO_INPUT) == 0) {
             throw new RSIllegalArgumentException(
                 "Can only receive if IO_INPUT usage specified.");
         }
         mRS.validate();
         mRS.nAllocationIoReceive(getID(mRS));
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -418,6 +441,7 @@
      * @param d Source array.
      */
     public void copyFrom(BaseObj[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         validateIsObject();
         if (d.length != mCurrentCount) {
@@ -429,6 +453,7 @@
             i[ct] = d[ct].getID(mRS);
         }
         copy1DRangeFromUnchecked(0, mCurrentCount, i);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     private void validateBitmapFormat(Bitmap b) {
@@ -494,6 +519,7 @@
      * @param d the source data array
      */
     public void copyFromUnchecked(int[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFromUnchecked");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -502,7 +528,9 @@
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
+
     /**
      * Copy into this Allocation from an array. This method does not guarantee
      * that the Allocation is compatible with the input buffer; it copies memory
@@ -511,6 +539,7 @@
      * @param d the source data array
      */
     public void copyFromUnchecked(short[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFromUnchecked");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -519,7 +548,9 @@
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
+
     /**
      * Copy into this Allocation from an array. This method does not guarantee
      * that the Allocation is compatible with the input buffer; it copies memory
@@ -528,6 +559,7 @@
      * @param d the source data array
      */
     public void copyFromUnchecked(byte[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFromUnchecked");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -536,7 +568,9 @@
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
+
     /**
      * Copy into this Allocation from an array. This method does not guarantee
      * that the Allocation is compatible with the input buffer; it copies memory
@@ -545,6 +579,7 @@
      * @param d the source data array
      */
     public void copyFromUnchecked(float[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFromUnchecked");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -553,8 +588,10 @@
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
+
     /**
      * Copy into this Allocation from an array.  This variant is type checked
      * and will generate exceptions if the Allocation's {@link
@@ -563,6 +600,7 @@
      * @param d the source data array
      */
     public void copyFrom(int[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -571,6 +609,7 @@
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -581,6 +620,7 @@
      * @param d the source data array
      */
     public void copyFrom(short[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -589,6 +629,7 @@
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -599,6 +640,7 @@
      * @param d the source data array
      */
     public void copyFrom(byte[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -607,6 +649,7 @@
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -617,6 +660,7 @@
      * @param d the source data array
      */
     public void copyFrom(float[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         if (mCurrentDimZ > 0) {
             copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
@@ -625,6 +669,7 @@
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -641,6 +686,7 @@
      * @param b the source bitmap
      */
     public void copyFrom(Bitmap b) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         if (b.getConfig() == null) {
             Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
@@ -652,6 +698,7 @@
         validateBitmapSize(b);
         validateBitmapFormat(b);
         mRS.nAllocationCopyFromBitmap(getID(mRS), b);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -661,14 +708,15 @@
      * @param a the source allocation
      */
     public void copyFrom(Allocation a) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
         mRS.validate();
         if (!mType.equals(a.getType())) {
             throw new RSIllegalArgumentException("Types of allocations must match.");
         }
         copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
-
     /**
      * This is only intended to be used by auto-generated code reflected from
      * the RenderScript script files and should not be used by developers.
@@ -759,10 +807,13 @@
      * @param d the source data array
      */
     public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
         mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
+
     /**
      * Copy an array into part of this Allocation.  This method does not
      * guarantee that the Allocation is compatible with the input buffer.
@@ -772,10 +823,13 @@
      * @param d the source data array
      */
     public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length * 2, dataSize);
         mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
+
     /**
      * Copy an array into part of this Allocation.  This method does not
      * guarantee that the Allocation is compatible with the input buffer.
@@ -785,10 +839,13 @@
      * @param d the source data array
      */
     public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length, dataSize);
         mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
+
     /**
      * Copy an array into part of this Allocation.  This method does not
      * guarantee that the Allocation is compatible with the input buffer.
@@ -798,9 +855,11 @@
      * @param d the source data array
      */
     public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
         mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -813,8 +872,10 @@
      * @param d the source data array
      */
     public void copy1DRangeFrom(int off, int count, int[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFrom");
         validateIsInt32();
         copy1DRangeFromUnchecked(off, count, d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -827,8 +888,10 @@
      * @param d the source data array
      */
     public void copy1DRangeFrom(int off, int count, short[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFrom");
         validateIsInt16();
         copy1DRangeFromUnchecked(off, count, d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -841,8 +904,10 @@
      * @param d the source data array
      */
     public void copy1DRangeFrom(int off, int count, byte[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFrom");
         validateIsInt8();
         copy1DRangeFromUnchecked(off, count, d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -855,10 +920,11 @@
      * @param d the source data array.
      */
     public void copy1DRangeFrom(int off, int count, float[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFrom");
         validateIsFloat32();
         copy1DRangeFromUnchecked(off, count, d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
-
      /**
      * Copy part of an Allocation into this Allocation.
      *
@@ -869,6 +935,7 @@
      *          be copied.
      */
     public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFrom");
         mRS.nAllocationData2D(getIDSafe(), off, 0,
                               mSelectedLOD, mSelectedFace.mID,
                               count, 1, data.getID(mRS), dataOff, 0,
@@ -893,34 +960,41 @@
     }
 
     void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, byte[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
                               w, h, data, data.length);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, short[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
                               w, h, data, data.length * 2);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, int[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
                               w, h, data, data.length * 4);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, float[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
                               w, h, data, data.length * 4);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
-
     /**
      * Copy from an array into a rectangular region in this Allocation.  The
      * array is assumed to be tightly packed.
@@ -932,8 +1006,10 @@
      * @param data to be placed into the Allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
         validateIsInt8();
         copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -947,8 +1023,10 @@
      * @param data to be placed into the Allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
         validateIsInt16();
         copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -962,8 +1040,10 @@
      * @param data to be placed into the Allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
         validateIsInt32();
         copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -977,8 +1057,10 @@
      * @param data to be placed into the Allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
         validateIsFloat32();
         copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -995,12 +1077,14 @@
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
                                 Allocation data, int dataXoff, int dataYoff) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
                               mSelectedLOD, mSelectedFace.mID,
                               w, h, data.getID(mRS), dataXoff, dataYoff,
                               data.mSelectedLOD, data.mSelectedFace.mID);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -1013,6 +1097,7 @@
      * @param data the Bitmap to be copied
      */
     public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
         mRS.validate();
         if (data.getConfig() == null) {
             Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
@@ -1024,6 +1109,7 @@
         validateBitmapFormat(data);
         validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
@@ -1166,10 +1252,12 @@
      * @param b The bitmap to be set from the Allocation.
      */
     public void copyTo(Bitmap b) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         mRS.validate();
         validateBitmapFormat(b);
         validateBitmapSize(b);
         mRS.nAllocationCopyToBitmap(getID(mRS), b);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -1180,9 +1268,11 @@
      * @param d The array to be set from the Allocation.
      */
     public void copyTo(byte[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsInt8();
         mRS.validate();
         mRS.nAllocationRead(getID(mRS), d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -1193,9 +1283,11 @@
      * @param d The array to be set from the Allocation.
      */
     public void copyTo(short[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsInt16();
         mRS.validate();
         mRS.nAllocationRead(getID(mRS), d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -1206,9 +1298,11 @@
      * @param d The array to be set from the Allocation.
      */
     public void copyTo(int[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsInt32();
         mRS.validate();
         mRS.nAllocationRead(getID(mRS), d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -1219,9 +1313,11 @@
      * @param d The array to be set from the Allocation.
      */
     public void copyTo(float[] d) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsFloat32();
         mRS.validate();
         mRS.nAllocationRead(getID(mRS), d);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
     /**
@@ -1271,6 +1367,7 @@
      *              utilized
      */
     static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "createTyped");
         rs.validate();
         if (type.getID(rs) == 0) {
             throw new RSInvalidStateException("Bad Type");
@@ -1279,6 +1376,7 @@
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
         return new Allocation(id, rs, type, usage);
     }
 
@@ -1323,6 +1421,7 @@
      */
     static public Allocation createSized(RenderScript rs, Element e,
                                          int count, int usage) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "createSized");
         rs.validate();
         Type.Builder b = new Type.Builder(rs, e);
         b.setX(count);
@@ -1332,6 +1431,7 @@
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
         return new Allocation(id, rs, t, usage);
     }
 
@@ -1391,6 +1491,7 @@
     static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
                                               MipmapControl mips,
                                               int usage) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "createFromBitmap");
         rs.validate();
 
         // WAR undocumented color formats
@@ -1426,6 +1527,7 @@
         if (id == 0) {
             throw new RSRuntimeException("Load failed.");
         }
+        Trace.traceEnd(RenderScript.TRACE_TAG);
         return new Allocation(id, rs, t, usage);
     }
 
@@ -1739,26 +1841,22 @@
     }
 
     /**
-     * @hide
-     *
      * Interface to handle notification when new buffers are available via
      * {@link #USAGE_IO_INPUT}. An application will receive one notification
      * when a buffer is available. Additional buffers will not trigger new
      * notifications until a buffer is processed.
      */
-    public interface IoInputNotifier {
+    public interface OnBufferAvailableListener {
         public void onBufferAvailable(Allocation a);
     }
 
     /**
-     * @hide
-     *
      * Set a notification handler for {@link #USAGE_IO_INPUT}.
      *
-     * @param callback instance of the IoInputNotifier class to be called
-     *                 when buffer arrive.
+     * @param callback instance of the OnBufferAvailableListener
+     *                 class to be called when buffer arrive.
      */
-    public void setIoInputNotificationHandler(IoInputNotifier callback) {
+    public void setOnBufferAvailableListener(OnBufferAvailableListener callback) {
         synchronized(mAllocationMap) {
             mAllocationMap.put(new Integer(getID(mRS)), this);
             mBufferNotifier = callback;
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 3838c61..68badfa 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -725,6 +725,13 @@
         return rs.mElement_LONG_4;
     }
 
+    public static Element YUV(RenderScript rs) {
+        if (rs.mElement_YUV == null) {
+            rs.mElement_YUV = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_YUV);
+        }
+        return rs.mElement_YUV;
+    }
+
     public static Element MATRIX_4X4(RenderScript rs) {
         if(rs.mElement_MATRIX_4X4 == null) {
             rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 1264adc..7d4a5c4 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -18,6 +18,7 @@
 
 import java.io.File;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -29,8 +30,8 @@
 import android.os.Process;
 import android.util.Log;
 import android.view.Surface;
-
-
+import android.os.SystemProperties;
+import android.os.Trace;
 
 /**
  * This class provides access to a RenderScript context, which controls RenderScript
@@ -44,6 +45,8 @@
  * </div>
  **/
 public class RenderScript {
+    static final long TRACE_TAG = Trace.TRACE_TAG_RS;
+
     static final String LOG_TAG = "RenderScript_jni";
     static final boolean DEBUG  = false;
     @SuppressWarnings({"UnusedDeclaration", "deprecation"})
@@ -55,20 +58,35 @@
      * We use a class initializer to allow the native code to cache some
      * field offsets.
      */
-    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
+    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // TODO: now used locally; remove?
     static boolean sInitialized;
     native static void _nInit();
 
+    static Object sRuntime;
+    static Method registerNativeAllocation;
+    static Method registerNativeFree;
 
     static {
         sInitialized = false;
-        try {
-            System.loadLibrary("rs_jni");
-            _nInit();
-            sInitialized = true;
-        } catch (UnsatisfiedLinkError e) {
-            Log.e(LOG_TAG, "Error loading RS jni library: " + e);
-            throw new RSRuntimeException("Error loading RS jni library: " + e);
+        if (!SystemProperties.getBoolean("config.disable_renderscript", false)) {
+            try {
+                Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
+                Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
+                sRuntime = get_runtime.invoke(null);
+                registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE);
+                registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE);
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Error loading GC methods: " + e);
+                throw new RSRuntimeException("Error loading GC methods: " + e);
+            }
+            try {
+                System.loadLibrary("rs_jni");
+                _nInit();
+                sInitialized = true;
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(LOG_TAG, "Error loading RS jni library: " + e);
+                throw new RSRuntimeException("Error loading RS jni library: " + e);
+            }
         }
     }
 
@@ -92,6 +110,11 @@
      * @param cacheDir A directory the current process can write to
      */
     public static void setupDiskCache(File cacheDir) {
+        if (!sInitialized) {
+            Log.e(LOG_TAG, "RenderScript.setupDiskCache() called when disabled");
+            return;
+        }
+
         // Defer creation of cache path to nScriptCCreate().
         mCacheDir = cacheDir;
     }
@@ -875,6 +898,8 @@
     Element mElement_LONG_3;
     Element mElement_LONG_4;
 
+    Element mElement_YUV;
+
     Element mElement_MATRIX_4X4;
     Element mElement_MATRIX_3X3;
     Element mElement_MATRIX_2X2;
@@ -1137,6 +1162,11 @@
      * @return RenderScript
      */
     public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
+        if (!sInitialized) {
+            Log.e(LOG_TAG, "RenderScript.create() called when disabled; someone is likely to crash");
+            return null;
+        }
+
         RenderScript rs = new RenderScript(ctx);
 
         rs.mDev = rs.nDeviceCreate();
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
index 77b9385..32c3d15 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
@@ -21,15 +21,27 @@
 /**
  * Intrinsic for applying a color matrix to allocations.
  *
- * This has the same effect as loading each element and
- * converting it to a {@link Element#F32_4}, multiplying the
- * result by the 4x4 color matrix as performed by
- * rsMatrixMultiply() and writing it to the output after
- * conversion back to {@link Element#U8_4}.
+ * If the element type is {@link Element.DataType#UNSIGNED_8},
+ * it is converted to {@link Element.DataType#FLOAT_32} and
+ * normalized from (0-255) to (0-1). If the incoming vector size
+ * is less than four, a {@link Element#F32_4} is created by
+ * filling the missing vector channels with zero. This value is
+ * then multiplied by the 4x4 color matrix as performed by
+ * rsMatrixMultiply(), adding a {@link Element#F32_4}, and then
+ * writing it to the output {@link Allocation}.
+ *
+ * If the ouptut type is unsigned, the value is normalized from
+ * (0-1) to (0-255) and converted. If the output vector size is
+ * less than four, the unused channels are discarded.
+ *
+ * Supported elements types are {@link Element#U8}, {@link
+ * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
+ * {@link Element#F32}, {@link Element#F32_2}, {@link
+ * Element#F32_3}, and {@link Element#F32_4}.
  **/
 public final class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
     private final Matrix4f mMatrix = new Matrix4f();
-    private Allocation mInput;
+    private final Float4 mAdd = new Float4();
 
     private ScriptIntrinsicColorMatrix(int id, RenderScript rs) {
         super(id, rs);
@@ -39,18 +51,31 @@
      * Create an intrinsic for applying a color matrix to an
      * allocation.
      *
-     * Supported elements types are {@link Element#U8_4}
-     *
      * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
+     * @param e Element type for inputs and outputs, As of API 19,
+     *          this parameter is ignored. The Element type check is
+     *          performed in the kernel launch.
+     *
+     * @deprecated Use the single argument version as Element is now
+     *             ignored.
      *
      * @return ScriptIntrinsicColorMatrix
      */
+    @Deprecated
     public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8_4(rs))) {
-            throw new RSIllegalArgumentException("Unsuported element type.");
-        }
-        int id = rs.nScriptIntrinsicCreate(2, e.getID(rs));
+        return create(rs);
+    }
+
+    /**
+     * Create an intrinsic for applying a color matrix to an
+     * allocation.
+     *
+     * @param rs The RenderScript context
+     *
+     * @return ScriptIntrinsicColorMatrix
+     */
+    public static ScriptIntrinsicColorMatrix create(RenderScript rs) {
+        int id = rs.nScriptIntrinsicCreate(2, 0);
         return new ScriptIntrinsicColorMatrix(id, rs);
 
     }
@@ -84,6 +109,49 @@
     }
 
     /**
+     * Set the value to be added after the color matrix has been
+     * applied. The default value is {0, 0, 0, 0}
+     *
+     * @param f The float4 value to be added.
+     */
+    public void setAdd(Float4 f) {
+        mAdd.x = f.x;
+        mAdd.y = f.y;
+        mAdd.z = f.z;
+        mAdd.w = f.w;
+
+        FieldPacker fp = new FieldPacker(4*4);
+        fp.addF32(f.x);
+        fp.addF32(f.y);
+        fp.addF32(f.z);
+        fp.addF32(f.w);
+        setVar(1, fp);
+    }
+
+    /**
+     * Set the value to be added after the color matrix has been
+     * applied. The default value is {0, 0, 0, 0}
+     *
+     * @param r The red add value.
+     * @param g The green add value.
+     * @param b The blue add value.
+     * @param a The alpha add value.
+     */
+    public void setAdd(float r, float g, float b, float a) {
+        mAdd.x = r;
+        mAdd.y = g;
+        mAdd.z = b;
+        mAdd.w = a;
+
+        FieldPacker fp = new FieldPacker(4*4);
+        fp.addF32(mAdd.x);
+        fp.addF32(mAdd.y);
+        fp.addF32(mAdd.z);
+        fp.addF32(mAdd.w);
+        setVar(1, fp);
+    }
+
+    /**
      * Set a color matrix to convert from RGB to luminance. The alpha channel
      * will be a copy.
      *
@@ -142,13 +210,45 @@
 
 
     /**
-     * Invoke the kernel and apply the matrix to each cell of ain and copy to
-     * aout.
+     * Invoke the kernel and apply the matrix to each cell of input
+     * {@link Allocation} and copy to the output {@link Allocation}.
+     *
+     * If the vector size of the input is less than four, the
+     * remaining components are treated as zero for the matrix
+     * multiply.
+     *
+     * If the output vector size is less than four, the unused
+     * vector components are discarded.
+     *
      *
      * @param ain Input allocation
      * @param aout Output allocation
      */
     public void forEach(Allocation ain, Allocation aout) {
+        if (!ain.getElement().isCompatible(Element.U8(mRS)) &&
+            !ain.getElement().isCompatible(Element.U8_2(mRS)) &&
+            !ain.getElement().isCompatible(Element.U8_3(mRS)) &&
+            !ain.getElement().isCompatible(Element.U8_4(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32_2(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32_3(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32_4(mRS))) {
+
+            throw new RSIllegalArgumentException("Unsuported element type.");
+        }
+
+        if (!aout.getElement().isCompatible(Element.U8(mRS)) &&
+            !aout.getElement().isCompatible(Element.U8_2(mRS)) &&
+            !aout.getElement().isCompatible(Element.U8_3(mRS)) &&
+            !aout.getElement().isCompatible(Element.U8_4(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32_2(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32_3(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32_4(mRS))) {
+
+            throw new RSIllegalArgumentException("Unsuported element type.");
+        }
+
         forEach(0, ain, aout, null);
     }
 
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
index c9c54b2..5d3c1d3 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -31,7 +31,10 @@
     }
 
     /**
-     * Supported elements types are {@link Element#U8_4}
+     * Supported elements types are {@link Element#U8}, {@link
+     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
+     * {@link Element#F32}, {@link Element#F32_2}, {@link
+     * Element#F32_3}, and {@link Element#F32_4}
      *
      * The default coefficients are.
      *
@@ -48,7 +51,14 @@
      */
     public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) {
         float f[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0};
-        if (!e.isCompatible(Element.U8_4(rs))) {
+        if (!e.isCompatible(Element.U8(rs)) &&
+            !e.isCompatible(Element.U8_2(rs)) &&
+            !e.isCompatible(Element.U8_3(rs)) &&
+            !e.isCompatible(Element.U8_4(rs)) &&
+            !e.isCompatible(Element.F32(rs)) &&
+            !e.isCompatible(Element.F32_2(rs)) &&
+            !e.isCompatible(Element.F32_3(rs)) &&
+            !e.isCompatible(Element.F32_4(rs))) {
             throw new RSIllegalArgumentException("Unsuported element type.");
         }
         int id = rs.nScriptIntrinsicCreate(1, e.getID(rs));
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
index c6e1e39..ad09f95 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
@@ -31,7 +31,10 @@
     }
 
     /**
-     * Supported elements types are {@link Element#U8_4}
+     * Supported elements types are {@link Element#U8}, {@link
+     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
+     * {@link Element#F32}, {@link Element#F32_2}, {@link
+     * Element#F32_3}, and {@link Element#F32_4}
      *
      * The default coefficients are.
      * <code>
@@ -48,6 +51,17 @@
      * @return ScriptIntrinsicConvolve5x5
      */
     public static ScriptIntrinsicConvolve5x5 create(RenderScript rs, Element e) {
+        if (!e.isCompatible(Element.U8(rs)) &&
+            !e.isCompatible(Element.U8_2(rs)) &&
+            !e.isCompatible(Element.U8_3(rs)) &&
+            !e.isCompatible(Element.U8_4(rs)) &&
+            !e.isCompatible(Element.F32(rs)) &&
+            !e.isCompatible(Element.F32_2(rs)) &&
+            !e.isCompatible(Element.F32_3(rs)) &&
+            !e.isCompatible(Element.F32_4(rs))) {
+            throw new RSIllegalArgumentException("Unsuported element type.");
+        }
+
         int id = rs.nScriptIntrinsicCreate(4, e.getID(rs));
         return new ScriptIntrinsicConvolve5x5(id, rs);
 
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java b/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java
new file mode 100644
index 0000000..adc2d95
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java
@@ -0,0 +1,186 @@
+/*
+ * 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 android.renderscript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+/**
+ * Intrinsic Histogram filter.
+ *
+ *
+ **/
+public final class ScriptIntrinsicHistogram extends ScriptIntrinsic {
+    private Allocation mOut;
+
+    private ScriptIntrinsicHistogram(int id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Create an intrinsic for calculating the histogram of an uchar
+     * or uchar4 image.
+     *
+     * Supported elements types are
+     * {@link Element#U8_4}, {@link Element#U8_3},
+     * {@link Element#U8_2}, {@link Element#U8}
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for inputs
+     *
+     * @return ScriptIntrinsicHistogram
+     */
+    public static ScriptIntrinsicHistogram create(RenderScript rs, Element e) {
+        if ((!e.isCompatible(Element.U8_4(rs))) &&
+            (!e.isCompatible(Element.U8_3(rs))) &&
+            (!e.isCompatible(Element.U8_2(rs))) &&
+            (!e.isCompatible(Element.U8(rs)))) {
+            throw new RSIllegalArgumentException("Unsuported element type.");
+        }
+        int id = rs.nScriptIntrinsicCreate(9, e.getID(rs));
+        ScriptIntrinsicHistogram sib = new ScriptIntrinsicHistogram(id, rs);
+        return sib;
+    }
+
+    /**
+     * Process an input buffer and place the histogram into the
+     * output allocation. The output allocation may be a narrower
+     * vector size than the input. In this case the vector size of
+     * the output is used to determine how many of the input
+     * channels are used in the computation. This is useful if you
+     * have an RGBA input buffer but only want the histogram for
+     * RGB.
+     *
+     * 1D and 2D input allocations are supported.
+     *
+     * @param ain The input image
+     */
+    public void forEach(Allocation ain) {
+        if (ain.getType().getElement().getVectorSize() <
+            mOut.getType().getElement().getVectorSize()) {
+
+            throw new RSIllegalArgumentException(
+                "Input vector size must be >= output vector size.");
+        }
+        if (ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
+            ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
+        }
+
+        forEach(0, ain, null, null);
+    }
+
+    /**
+     * Set the coefficients used for the RGBA to Luminocity
+     * calculation. The default is {0.299f, 0.587f, 0.114f, 0.f}.
+     *
+     * Coefficients must be >= 0 and sum to 1.0 or less.
+     *
+     * @param r Red coefficient
+     * @param g Green coefficient
+     * @param b Blue coefficient
+     * @param a Alpha coefficient
+     */
+    public void setDotCoefficients(float r, float g, float b, float a) {
+        if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
+            throw new RSIllegalArgumentException("Coefficient may not be negative.");
+        }
+        if ((r + g + b + a) > 1.f) {
+            throw new RSIllegalArgumentException("Sum of coefficients must be 1.0 or less.");
+        }
+
+        FieldPacker fp = new FieldPacker(16);
+        fp.addF32(r);
+        fp.addF32(g);
+        fp.addF32(b);
+        fp.addF32(a);
+        setVar(0, fp);
+    }
+
+    /**
+     * Set the output of the histogram.  32 bit integer types are
+     * supported.
+     *
+     * @param aout The output allocation
+     */
+    public void setOutput(Allocation aout) {
+        mOut = aout;
+        if (mOut.getType().getElement() != Element.U32(mRS) &&
+            mOut.getType().getElement() != Element.U32_2(mRS) &&
+            mOut.getType().getElement() != Element.U32_3(mRS) &&
+            mOut.getType().getElement() != Element.U32_4(mRS) &&
+            mOut.getType().getElement() != Element.I32(mRS) &&
+            mOut.getType().getElement() != Element.I32_2(mRS) &&
+            mOut.getType().getElement() != Element.I32_3(mRS) &&
+            mOut.getType().getElement() != Element.I32_4(mRS)) {
+
+            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
+        }
+        if ((mOut.getType().getX() != 256) ||
+            (mOut.getType().getY() != 0) ||
+            mOut.getType().hasMipmaps() ||
+            (mOut.getType().getYuv() != 0)) {
+
+            throw new RSIllegalArgumentException("Output must be 1D, 256 elements.");
+        }
+        setVar(1, aout);
+    }
+
+    /**
+     * Process an input buffer and place the histogram into the
+     * output allocation. The dot product of the input channel and
+     * the coefficients from 'setDotCoefficients' are used to
+     * calculate the output values.
+     *
+     * 1D and 2D input allocations are supported.
+     *
+     * @param ain The input image
+     */
+    public void forEach_Dot(Allocation ain) {
+        if (mOut.getType().getElement().getVectorSize() != 1) {
+            throw new RSIllegalArgumentException("Output vector size must be one.");
+        }
+        if (ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
+            ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
+        }
+
+        forEach(1, ain, null, null);
+    }
+
+
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID_Separate() {
+        return createKernelID(0, 3, null, null);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(1, null);
+    }
+}
+
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
index 9b5de9b..845625d 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
@@ -20,9 +20,9 @@
 /**
  * Intrinsic for converting an Android YUV buffer to RGB.
  *
- * The input allocation is supplied in NV21 format as a U8
- * element type. The output is RGBA, the alpha channel will be
- * set to 255.
+ * The input allocation should be supplied in a supported YUV format
+ * as a YUV element Allocation. The output is RGBA; the alpha channel
+ * will be set to 255.
  */
 public final class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic {
     private Allocation mInput;
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index ef08c29..e023739 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -37,10 +37,11 @@
  * faces. LOD and cube map faces are booleans to indicate present or not
  * present. </p>
  *
- * <p>A Type also supports YUV format information to support an {@link
- * android.renderscript.Allocation} in a YUV format. The YUV formats supported
- * are {@link android.graphics.ImageFormat#YV12} and {@link
- * android.graphics.ImageFormat#NV21}.</p>
+ * <p>A Type also supports YUV format information to support an
+ * {@link android.renderscript.Allocation} in a YUV format. The YUV formats
+ * supported are {@link android.graphics.ImageFormat#YV12},
+ * {@link android.graphics.ImageFormat#NV21}, and
+ * {@link android.graphics.ImageFormat#YUV_420_888}</p>
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
@@ -284,16 +285,19 @@
         /**
          * Set the YUV layout for a Type.
          *
-         * @param yuvFormat {@link android.graphics.ImageFormat#YV12} or {@link android.graphics.ImageFormat#NV21}
+         * @param yuvFormat {@link android.graphics.ImageFormat#YV12}, {@link android.graphics.ImageFormat#NV21}, or
+         * {@link android.graphics.ImageFormat#YUV_420_888}.
          */
         public Builder setYuvFormat(int yuvFormat) {
             switch (yuvFormat) {
             case android.graphics.ImageFormat.NV21:
             case android.graphics.ImageFormat.YV12:
+            case android.graphics.ImageFormat.YUV_420_888:
                 break;
 
             default:
-                throw new RSIllegalArgumentException("Only NV21 and YV12 are supported..");
+                throw new RSIllegalArgumentException(
+                    "Only ImageFormat.NV21, .YV12, and .YUV_420_888 are supported..");
             }
 
             mYuv = yuvFormat;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index b9f8713..cbc4e5a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -27,7 +27,6 @@
 #include <core/SkPixelRef.h>
 #include <core/SkStream.h>
 #include <core/SkTemplates.h>
-#include <images/SkImageDecoder.h>
 
 #include <androidfw/Asset.h>
 #include <androidfw/AssetManager.h>
@@ -185,7 +184,7 @@
 nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver, jint sdkVer, jint ct)
 {
     LOG_API("nContextCreate");
-    return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, false, false);
+    return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
 }
 
 static jint
diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/MipmapDrawableTest.java b/graphics/tests/graphicstests/src/android/graphics/drawable/MipmapDrawableTest.java
deleted file mode 100644
index 5fcc3bc..0000000
--- a/graphics/tests/graphicstests/src/android/graphics/drawable/MipmapDrawableTest.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.MipmapDrawable;
-import android.graphics.drawable.DrawableContainer.DrawableContainerState;
-import android.test.InstrumentationTestCase;
-
-public class MipmapDrawableTest extends InstrumentationTestCase {
-    private MockMipmapDrawable mMipmapDrawable;
-
-    private DrawableContainerState mDrawableContainerState;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mMipmapDrawable = new MockMipmapDrawable();
-        mDrawableContainerState = (DrawableContainerState) mMipmapDrawable.getConstantState();
-    }
-
-    public void testMipmapDrawable() {
-        new MipmapDrawable();
-        // Check the values set in the constructor
-        assertNotNull(new MipmapDrawable().getConstantState());
-        assertTrue(new MockMipmapDrawable().hasCalledOnBoundsChanged());
-    }
-
-    public void testAddDrawable() {
-        assertEquals(0, mDrawableContainerState.getChildCount());
-
-        // nothing happens if drawable is null
-        mMipmapDrawable.reset();
-        mMipmapDrawable.addDrawable(null);
-        assertEquals(0, mDrawableContainerState.getChildCount());
-        assertFalse(mMipmapDrawable.hasCalledOnBoundsChanged());
-
-        mMipmapDrawable.reset();
-        mMipmapDrawable.addDrawable(new MockDrawable());
-        assertEquals(1, mDrawableContainerState.getChildCount());
-        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
-
-        mMipmapDrawable.reset();
-        mMipmapDrawable.addDrawable(new MockDrawable());
-        assertEquals(2, mDrawableContainerState.getChildCount());
-        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
-    }
-
-    public void testSortedByHeight() {
-        Drawable small = new MockDrawable(8);
-        Drawable medium = new MockDrawable(32);
-        Drawable large = new MockDrawable(128);
-
-        mMipmapDrawable.addDrawable(medium);
-        assertSame(medium, mDrawableContainerState.getChildren()[0]);
-
-        mMipmapDrawable.addDrawable(small);
-        assertSame(small, mDrawableContainerState.getChildren()[0]);
-        assertSame(medium, mDrawableContainerState.getChildren()[1]);
-
-        mMipmapDrawable.addDrawable(large);
-        assertSame(small, mDrawableContainerState.getChildren()[0]);
-        assertSame(medium, mDrawableContainerState.getChildren()[1]);
-        assertSame(large, mDrawableContainerState.getChildren()[2]);
-
-        mMipmapDrawable.addDrawable(small);
-        assertSame(small, mDrawableContainerState.getChildren()[0]);
-        assertSame(small, mDrawableContainerState.getChildren()[1]);
-        assertSame(medium, mDrawableContainerState.getChildren()[2]);
-        assertSame(large, mDrawableContainerState.getChildren()[3]);
-
-        mMipmapDrawable.addDrawable(medium);
-        assertSame(small, mDrawableContainerState.getChildren()[0]);
-        assertSame(small, mDrawableContainerState.getChildren()[1]);
-        assertSame(medium, mDrawableContainerState.getChildren()[2]);
-        assertSame(medium, mDrawableContainerState.getChildren()[3]);
-        assertSame(large, mDrawableContainerState.getChildren()[4]);
-
-        mMipmapDrawable.addDrawable(large);
-        assertSame(small, mDrawableContainerState.getChildren()[0]);
-        assertSame(small, mDrawableContainerState.getChildren()[1]);
-        assertSame(medium, mDrawableContainerState.getChildren()[2]);
-        assertSame(medium, mDrawableContainerState.getChildren()[3]);
-        assertSame(large, mDrawableContainerState.getChildren()[4]);
-        assertSame(large, mDrawableContainerState.getChildren()[5]);
-    }
-
-    public void testSetBoundsOneItem() {
-        // the method is not called if same bounds are set
-        mMipmapDrawable.reset();
-        mMipmapDrawable.setBounds(mMipmapDrawable.getBounds());
-        assertFalse(mMipmapDrawable.hasCalledOnBoundsChanged());
-
-        // the method is called if different bounds are set, even without drawables
-        mMipmapDrawable.reset();
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, mMipmapDrawable.getBounds().height() + 1));
-        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
-
-        // adding an item should check bounds to see if new drawable is more appropriate
-        mMipmapDrawable.reset();
-        Drawable item = new MockDrawable(42);
-        mMipmapDrawable.addDrawable(item);
-        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
-
-        // the method is called if different bounds are set
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, mMipmapDrawable.getBounds().height() + 1));
-        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
-
-        // check that correct drawable is selected for any size.
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight() - 1));
-        assertSame(item, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight()));
-        assertSame(item, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight() + 1));
-        assertSame(item, mMipmapDrawable.getCurrent());
-    }
-
-    public void testSetBounds() {
-        Drawable small = new MockDrawable(8);
-        Drawable medium = new MockDrawable(32);
-        Drawable large = new MockDrawable(128);
-
-        mMipmapDrawable.addDrawable(large);
-        mMipmapDrawable.addDrawable(small);
-        mMipmapDrawable.addDrawable(medium);
-
-        // check that correct drawable is selected.
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight() - 1));
-        assertSame(small, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight()));
-        assertSame(small, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight() + 1));
-        assertSame(medium, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight() - 1));
-        assertSame(medium, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight()));
-        assertSame(medium, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight() + 1));
-        assertSame(large, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight() - 1));
-        assertSame(large, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight()));
-        assertSame(large, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight() + 1));
-        assertSame(large, mMipmapDrawable.getCurrent());
-    }
-
-    public void testSizes() {
-        // Check default value with no mipmap defined
-        assertEquals(-1, mMipmapDrawable.getIntrinsicHeight());
-        assertEquals(-1, mMipmapDrawable.getIntrinsicWidth());
-        assertEquals(0, mMipmapDrawable.getMinimumHeight());
-        assertEquals(0, mMipmapDrawable.getMinimumWidth());
-
-        Drawable small = new MockDrawable(8, 4);
-        Drawable medium = new MockDrawable(32, 16);
-        Drawable large = new MockDrawable(128, 64);
-
-        mMipmapDrawable.addDrawable(medium);
-        assertEquals(medium.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight());
-        assertEquals(medium.getMinimumHeight(), mMipmapDrawable.getMinimumHeight());
-
-        mMipmapDrawable.addDrawable(large);
-        assertEquals(large.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight());
-        assertEquals(medium.getMinimumHeight(), mMipmapDrawable.getMinimumHeight());
-
-        mMipmapDrawable.addDrawable(small);
-        assertEquals(large.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight());
-        assertEquals(small.getMinimumHeight(), mMipmapDrawable.getMinimumHeight());
-    }
-
-    public void testReplacementWhenAdded() {
-        Drawable small = new MockDrawable(8);
-        Drawable medium = new MockDrawable(32);
-        Drawable large = new MockDrawable(128);
-
-        // Small bounds, so that the smallest mipmap should always be selected
-        mMipmapDrawable.setBounds(new Rect(0, 0, 0, 0));
-
-        // Providing smaller versions, that should immediately be used as current
-        mMipmapDrawable.addDrawable(large);
-        assertSame(large, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.addDrawable(medium);
-        assertSame(medium, mMipmapDrawable.getCurrent());
-
-        mMipmapDrawable.addDrawable(small);
-        assertSame(small, mMipmapDrawable.getCurrent());
-    }
-
-    private class MockMipmapDrawable extends MipmapDrawable {
-        private boolean mHasCalledOnBoundsChanged;
-
-        public boolean hasCalledOnBoundsChanged() {
-            return mHasCalledOnBoundsChanged;
-        }
-
-        public void reset() {
-            mHasCalledOnBoundsChanged = false;
-        }
-
-        @Override
-        protected void onBoundsChange(Rect bounds) {
-            super.onBoundsChange(bounds);
-            mHasCalledOnBoundsChanged = true;
-        }
-    }
-
-    private class MockDrawable extends Drawable {
-        int mIntrinsicHeight;
-        int mMinimumHeight;
-
-        public MockDrawable() {
-            this(0);
-        }
-
-        public MockDrawable(int intrinsicHeight) {
-            this(intrinsicHeight, intrinsicHeight);
-        }
-
-        public MockDrawable(int intrinsicHeight, int minimumHeight) {
-            mIntrinsicHeight = intrinsicHeight;
-            mMinimumHeight = minimumHeight;
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            return mIntrinsicHeight;
-        }
-
-        @Override
-        public int getMinimumHeight() {
-            return mMinimumHeight;
-        }
-    }
-}
diff --git a/include/android_runtime/Log.h b/include/android_runtime/Log.h
new file mode 100644
index 0000000..aa6d202
--- /dev/null
+++ b/include/android_runtime/Log.h
@@ -0,0 +1,35 @@
+/*
+ * 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 _RUNTIME_ANDROID_LOG_H
+#define _RUNTIME_ANDROID_LOG_H
+
+// This relies on JNIHelp.h
+
+/* Logging macros.
+ *
+ * Logs an exception.  If the exception is omitted or NULL, logs the current exception
+ * from the JNI environment, if any.
+ */
+#define LOG_EX(env, priority, tag, ...) \
+    jniLogException(env, ANDROID_##priority, tag, ##__VA_ARGS__)
+#define LOGV_EX(env, ...) LOG_EX(env, LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define LOGD_EX(env, ...) LOG_EX(env, LOG_DEBUG, LOG_TAG, ##__VA_ARGS__)
+#define LOGI_EX(env, ...) LOG_EX(env, LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define LOGW_EX(env, ...) LOG_EX(env, LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define LOGE_EX(env, ...) LOG_EX(env, LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+
+#endif // _RUNTIME_ANDROID_LOG_H
diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/include/android_runtime/android_graphics_SurfaceTexture.h
index 77ccd2a..c534d4b 100644
--- a/include/android_runtime/android_graphics_SurfaceTexture.h
+++ b/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -24,14 +24,17 @@
 namespace android {
 
 class GLConsumer;
+class IGraphicBufferProducer;
 
-extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
-        JNIEnv* env, jobject thiz);
+extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz);
 extern bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz);
 
 /* Gets the underlying GLConsumer from a SurfaceTexture Java object. */
 extern sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
 
+/* gets the producer end of the SurfaceTexture */
+extern sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz);
+
 } // namespace android
 
 #endif // _ANDROID_GRAPHICS_SURFACETEXTURE_H
diff --git a/include/android_runtime/android_view_InputQueue.h b/include/android_runtime/android_view_InputQueue.h
index ba2d02d..ed37b0a 100644
--- a/include/android_runtime/android_view_InputQueue.h
+++ b/include/android_runtime/android_view_InputQueue.h
@@ -17,7 +17,7 @@
 #ifndef _ANDROID_VIEW_INPUTQUEUE_H
 #define _ANDROID_VIEW_INPUTQUEUE_H
 
-#include <androidfw/Input.h>
+#include <input/Input.h>
 #include <utils/Looper.h>
 #include <utils/TypeHelpers.h>
 #include <utils/Vector.h>
diff --git a/include/androidfw/AssetDir.h b/include/androidfw/AssetDir.h
index abf8a35..bd89d7d 100644
--- a/include/androidfw/AssetDir.h
+++ b/include/androidfw/AssetDir.h
@@ -20,10 +20,10 @@
 #ifndef __LIBS_ASSETDIR_H
 #define __LIBS_ASSETDIR_H
 
+#include <androidfw/misc.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/SortedVector.h>
-#include <utils/misc.h>
 #include <sys/types.h>
 
 namespace android {
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index d153c31..d95b45e 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -22,13 +22,13 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/AssetDir.h>
+#include <androidfw/ZipFileRO.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Vector.h>
-#include <utils/ZipFileRO.h>
 
 /*
  * Native-app access is via the opaque typedef struct AAssetManager in the C namespace.
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
deleted file mode 100644
index 37ab279..0000000
--- a/include/androidfw/Input.h
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 _ANDROIDFW_INPUT_H
-#define _ANDROIDFW_INPUT_H
-
-/**
- * Native input event structures.
- */
-
-#include <android/input.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-#ifdef HAVE_ANDROID_OS
-class SkMatrix;
-#endif
-
-/*
- * Additional private constants not defined in ndk/ui/input.h.
- */
-enum {
-    /* Signifies that the key is being predispatched */
-    AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000,
-
-    /* Private control to determine when an app is tracking a key sequence. */
-    AKEY_EVENT_FLAG_START_TRACKING = 0x40000000,
-
-    /* Key event is inconsistent with previously sent key events. */
-    AKEY_EVENT_FLAG_TAINTED = 0x80000000,
-};
-
-enum {
-    /* Motion event is inconsistent with previously sent motion events. */
-    AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
-};
-
-enum {
-    /* Used when a motion event is not associated with any display.
-     * Typically used for non-pointer events. */
-    ADISPLAY_ID_NONE = -1,
-
-    /* The default display id. */
-    ADISPLAY_ID_DEFAULT = 0,
-};
-
-enum {
-    /*
-     * Indicates that an input device has switches.
-     * This input source flag is hidden from the API because switches are only used by the system
-     * and applications have no way to interact with them.
-     */
-    AINPUT_SOURCE_SWITCH = 0x80000000,
-};
-
-/*
- * SystemUiVisibility constants from View.
- */
-enum {
-    ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
-    ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
-};
-
-/*
- * Maximum number of pointers supported per motion event.
- * Smallest number of pointers is 1.
- * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
- * will occasionally emit 11.  There is not much harm making this constant bigger.)
- */
-#define MAX_POINTERS 16
-
-/*
- * Maximum pointer id value supported in a motion event.
- * Smallest pointer id is 0.
- * (This is limited by our use of BitSet32 to track pointer assignments.)
- */
-#define MAX_POINTER_ID 31
-
-/*
- * Declare a concrete type for the NDK's input event forward declaration.
- */
-struct AInputEvent {
-    virtual ~AInputEvent() { }
-};
-
-/*
- * Declare a concrete type for the NDK's input device forward declaration.
- */
-struct AInputDevice {
-    virtual ~AInputDevice() { }
-};
-
-
-namespace android {
-
-#ifdef HAVE_ANDROID_OS
-class Parcel;
-#endif
-
-/*
- * Flags that flow alongside events in the input dispatch system to help with certain
- * policy decisions such as waking from device sleep.
- *
- * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java.
- */
-enum {
-    /* These flags originate in RawEvents and are generally set in the key map.
-     * NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */
-
-    POLICY_FLAG_WAKE = 0x00000001,
-    POLICY_FLAG_WAKE_DROPPED = 0x00000002,
-    POLICY_FLAG_SHIFT = 0x00000004,
-    POLICY_FLAG_CAPS_LOCK = 0x00000008,
-    POLICY_FLAG_ALT = 0x00000010,
-    POLICY_FLAG_ALT_GR = 0x00000020,
-    POLICY_FLAG_MENU = 0x00000040,
-    POLICY_FLAG_LAUNCHER = 0x00000080,
-    POLICY_FLAG_VIRTUAL = 0x00000100,
-    POLICY_FLAG_FUNCTION = 0x00000200,
-
-    POLICY_FLAG_RAW_MASK = 0x0000ffff,
-
-    /* These flags are set by the input dispatcher. */
-
-    // Indicates that the input event was injected.
-    POLICY_FLAG_INJECTED = 0x01000000,
-
-    // Indicates that the input event is from a trusted source such as a directly attached
-    // input device or an application with system-wide event injection permission.
-    POLICY_FLAG_TRUSTED = 0x02000000,
-
-    // Indicates that the input event has passed through an input filter.
-    POLICY_FLAG_FILTERED = 0x04000000,
-
-    // Disables automatic key repeating behavior.
-    POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000,
-
-    /* These flags are set by the input reader policy as it intercepts each event. */
-
-    // Indicates that the screen was off when the event was received and the event
-    // should wake the device.
-    POLICY_FLAG_WOKE_HERE = 0x10000000,
-
-    // Indicates that the screen was dim when the event was received and the event
-    // should brighten the device.
-    POLICY_FLAG_BRIGHT_HERE = 0x20000000,
-
-    // Indicates that the event should be dispatched to applications.
-    // The input event should still be sent to the InputDispatcher so that it can see all
-    // input events received include those that it will not deliver.
-    POLICY_FLAG_PASS_TO_USER = 0x40000000,
-};
-
-/*
- * Pointer coordinate data.
- */
-struct PointerCoords {
-    enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64
-
-    // Bitfield of axes that are present in this structure.
-    uint64_t bits;
-
-    // Values of axes that are stored in this structure packed in order by axis id
-    // for each axis that is present in the structure according to 'bits'.
-    float values[MAX_AXES];
-
-    inline void clear() {
-        bits = 0;
-    }
-
-    float getAxisValue(int32_t axis) const;
-    status_t setAxisValue(int32_t axis, float value);
-
-    void scale(float scale);
-
-    inline float getX() const {
-        return getAxisValue(AMOTION_EVENT_AXIS_X);
-    }
-
-    inline float getY() const {
-        return getAxisValue(AMOTION_EVENT_AXIS_Y);
-    }
-
-#ifdef HAVE_ANDROID_OS
-    status_t readFromParcel(Parcel* parcel);
-    status_t writeToParcel(Parcel* parcel) const;
-#endif
-
-    bool operator==(const PointerCoords& other) const;
-    inline bool operator!=(const PointerCoords& other) const {
-        return !(*this == other);
-    }
-
-    void copyFrom(const PointerCoords& other);
-
-private:
-    void tooManyAxes(int axis);
-};
-
-/*
- * Pointer property data.
- */
-struct PointerProperties {
-    // The id of the pointer.
-    int32_t id;
-
-    // The pointer tool type.
-    int32_t toolType;
-
-    inline void clear() {
-        id = -1;
-        toolType = 0;
-    }
-
-    bool operator==(const PointerProperties& other) const;
-    inline bool operator!=(const PointerProperties& other) const {
-        return !(*this == other);
-    }
-
-    void copyFrom(const PointerProperties& other);
-};
-
-/*
- * Input events.
- */
-class InputEvent : public AInputEvent {
-public:
-    virtual ~InputEvent() { }
-
-    virtual int32_t getType() const = 0;
-
-    inline int32_t getDeviceId() const { return mDeviceId; }
-
-    inline int32_t getSource() const { return mSource; }
-
-    inline void setSource(int32_t source) { mSource = source; }
-
-protected:
-    void initialize(int32_t deviceId, int32_t source);
-    void initialize(const InputEvent& from);
-
-    int32_t mDeviceId;
-    int32_t mSource;
-};
-
-/*
- * Key events.
- */
-class KeyEvent : public InputEvent {
-public:
-    virtual ~KeyEvent() { }
-
-    virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; }
-
-    inline int32_t getAction() const { return mAction; }
-
-    inline int32_t getFlags() const { return mFlags; }
-
-    inline void setFlags(int32_t flags) { mFlags = flags; }
-
-    inline int32_t getKeyCode() const { return mKeyCode; }
-
-    inline int32_t getScanCode() const { return mScanCode; }
-
-    inline int32_t getMetaState() const { return mMetaState; }
-
-    inline int32_t getRepeatCount() const { return mRepeatCount; }
-
-    inline nsecs_t getDownTime() const { return mDownTime; }
-
-    inline nsecs_t getEventTime() const { return mEventTime; }
-
-    // Return true if this event may have a default action implementation.
-    static bool hasDefaultAction(int32_t keyCode);
-    bool hasDefaultAction() const;
-
-    // Return true if this event represents a system key.
-    static bool isSystemKey(int32_t keyCode);
-    bool isSystemKey() const;
-    
-    void initialize(
-            int32_t deviceId,
-            int32_t source,
-            int32_t action,
-            int32_t flags,
-            int32_t keyCode,
-            int32_t scanCode,
-            int32_t metaState,
-            int32_t repeatCount,
-            nsecs_t downTime,
-            nsecs_t eventTime);
-    void initialize(const KeyEvent& from);
-
-protected:
-    int32_t mAction;
-    int32_t mFlags;
-    int32_t mKeyCode;
-    int32_t mScanCode;
-    int32_t mMetaState;
-    int32_t mRepeatCount;
-    nsecs_t mDownTime;
-    nsecs_t mEventTime;
-};
-
-/*
- * Motion events.
- */
-class MotionEvent : public InputEvent {
-public:
-    virtual ~MotionEvent() { }
-
-    virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; }
-
-    inline int32_t getAction() const { return mAction; }
-
-    inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
-
-    inline int32_t getActionIndex() const {
-        return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
-                >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-    }
-
-    inline void setAction(int32_t action) { mAction = action; }
-
-    inline int32_t getFlags() const { return mFlags; }
-
-    inline void setFlags(int32_t flags) { mFlags = flags; }
-
-    inline int32_t getEdgeFlags() const { return mEdgeFlags; }
-
-    inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; }
-
-    inline int32_t getMetaState() const { return mMetaState; }
-
-    inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
-
-    inline int32_t getButtonState() const { return mButtonState; }
-
-    inline float getXOffset() const { return mXOffset; }
-
-    inline float getYOffset() const { return mYOffset; }
-
-    inline float getXPrecision() const { return mXPrecision; }
-
-    inline float getYPrecision() const { return mYPrecision; }
-
-    inline nsecs_t getDownTime() const { return mDownTime; }
-
-    inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
-
-    inline size_t getPointerCount() const { return mPointerProperties.size(); }
-
-    inline const PointerProperties* getPointerProperties(size_t pointerIndex) const {
-        return &mPointerProperties[pointerIndex];
-    }
-
-    inline int32_t getPointerId(size_t pointerIndex) const {
-        return mPointerProperties[pointerIndex].id;
-    }
-
-    inline int32_t getToolType(size_t pointerIndex) const {
-        return mPointerProperties[pointerIndex].toolType;
-    }
-
-    inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
-
-    const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
-
-    float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
-
-    inline float getRawX(size_t pointerIndex) const {
-        return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
-    }
-
-    inline float getRawY(size_t pointerIndex) const {
-        return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
-    }
-
-    float getAxisValue(int32_t axis, size_t pointerIndex) const;
-
-    inline float getX(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
-    }
-
-    inline float getY(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
-    }
-
-    inline float getPressure(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex);
-    }
-
-    inline float getSize(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex);
-    }
-
-    inline float getTouchMajor(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex);
-    }
-
-    inline float getTouchMinor(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex);
-    }
-
-    inline float getToolMajor(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex);
-    }
-
-    inline float getToolMinor(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex);
-    }
-
-    inline float getOrientation(size_t pointerIndex) const {
-        return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex);
-    }
-
-    inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
-
-    inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const {
-        return mSampleEventTimes[historicalIndex];
-    }
-
-    const PointerCoords* getHistoricalRawPointerCoords(
-            size_t pointerIndex, size_t historicalIndex) const;
-
-    float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
-            size_t historicalIndex) const;
-
-    inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalRawAxisValue(
-                AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalRawAxisValue(
-                AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
-    }
-
-    float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const;
-
-    inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex);
-    }
-
-    inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalAxisValue(
-                AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
-    }
-
-    ssize_t findPointerIndex(int32_t pointerId) const;
-
-    void initialize(
-            int32_t deviceId,
-            int32_t source,
-            int32_t action,
-            int32_t flags,
-            int32_t edgeFlags,
-            int32_t metaState,
-            int32_t buttonState,
-            float xOffset,
-            float yOffset,
-            float xPrecision,
-            float yPrecision,
-            nsecs_t downTime,
-            nsecs_t eventTime,
-            size_t pointerCount,
-            const PointerProperties* pointerProperties,
-            const PointerCoords* pointerCoords);
-
-    void copyFrom(const MotionEvent* other, bool keepHistory);
-
-    void addSample(
-            nsecs_t eventTime,
-            const PointerCoords* pointerCoords);
-
-    void offsetLocation(float xOffset, float yOffset);
-
-    void scale(float scaleFactor);
-
-#ifdef HAVE_ANDROID_OS
-    void transform(const SkMatrix* matrix);
-
-    status_t readFromParcel(Parcel* parcel);
-    status_t writeToParcel(Parcel* parcel) const;
-#endif
-
-    static bool isTouchEvent(int32_t source, int32_t action);
-    inline bool isTouchEvent() const {
-        return isTouchEvent(mSource, mAction);
-    }
-
-    // Low-level accessors.
-    inline const PointerProperties* getPointerProperties() const {
-        return mPointerProperties.array();
-    }
-    inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
-    inline const PointerCoords* getSamplePointerCoords() const {
-            return mSamplePointerCoords.array();
-    }
-
-protected:
-    int32_t mAction;
-    int32_t mFlags;
-    int32_t mEdgeFlags;
-    int32_t mMetaState;
-    int32_t mButtonState;
-    float mXOffset;
-    float mYOffset;
-    float mXPrecision;
-    float mYPrecision;
-    nsecs_t mDownTime;
-    Vector<PointerProperties> mPointerProperties;
-    Vector<nsecs_t> mSampleEventTimes;
-    Vector<PointerCoords> mSamplePointerCoords;
-};
-
-/*
- * Input event factory.
- */
-class InputEventFactoryInterface {
-protected:
-    virtual ~InputEventFactoryInterface() { }
-
-public:
-    InputEventFactoryInterface() { }
-
-    virtual KeyEvent* createKeyEvent() = 0;
-    virtual MotionEvent* createMotionEvent() = 0;
-};
-
-/*
- * A simple input event factory implementation that uses a single preallocated instance
- * of each type of input event that are reused for each request.
- */
-class PreallocatedInputEventFactory : public InputEventFactoryInterface {
-public:
-    PreallocatedInputEventFactory() { }
-    virtual ~PreallocatedInputEventFactory() { }
-
-    virtual KeyEvent* createKeyEvent() { return & mKeyEvent; }
-    virtual MotionEvent* createMotionEvent() { return & mMotionEvent; }
-
-private:
-    KeyEvent mKeyEvent;
-    MotionEvent mMotionEvent;
-};
-
-/*
- * An input event factory implementation that maintains a pool of input events.
- */
-class PooledInputEventFactory : public InputEventFactoryInterface {
-public:
-    PooledInputEventFactory(size_t maxPoolSize = 20);
-    virtual ~PooledInputEventFactory();
-
-    virtual KeyEvent* createKeyEvent();
-    virtual MotionEvent* createMotionEvent();
-
-    void recycle(InputEvent* event);
-
-private:
-    const size_t mMaxPoolSize;
-
-    Vector<KeyEvent*> mKeyEventPool;
-    Vector<MotionEvent*> mMotionEventPool;
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_INPUT_H
diff --git a/include/androidfw/InputDevice.h b/include/androidfw/InputDevice.h
deleted file mode 100644
index 45dc2db..0000000
--- a/include/androidfw/InputDevice.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROIDFW_INPUT_DEVICE_H
-#define _ANDROIDFW_INPUT_DEVICE_H
-
-#include <androidfw/Input.h>
-#include <androidfw/KeyCharacterMap.h>
-
-namespace android {
-
-/*
- * Identifies a device.
- */
-struct InputDeviceIdentifier {
-    inline InputDeviceIdentifier() :
-            bus(0), vendor(0), product(0), version(0) {
-    }
-
-    // Information provided by the kernel.
-    String8 name;
-    String8 location;
-    String8 uniqueId;
-    uint16_t bus;
-    uint16_t vendor;
-    uint16_t product;
-    uint16_t version;
-
-    // A composite input device descriptor string that uniquely identifies the device
-    // even across reboots or reconnections.  The value of this field is used by
-    // upper layers of the input system to associate settings with individual devices.
-    // It is hashed from whatever kernel provided information is available.
-    // Ideally, the way this value is computed should not change between Android releases
-    // because that would invalidate persistent settings that rely on it.
-    String8 descriptor;
-};
-
-/*
- * Describes the characteristics and capabilities of an input device.
- */
-class InputDeviceInfo {
-public:
-    InputDeviceInfo();
-    InputDeviceInfo(const InputDeviceInfo& other);
-    ~InputDeviceInfo();
-
-    struct MotionRange {
-        int32_t axis;
-        uint32_t source;
-        float min;
-        float max;
-        float flat;
-        float fuzz;
-        float resolution;
-    };
-
-    void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier,
-            const String8& alias, bool isExternal);
-
-    inline int32_t getId() const { return mId; }
-    inline int32_t getGeneration() const { return mGeneration; }
-    inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
-    inline const String8& getAlias() const { return mAlias; }
-    inline const String8& getDisplayName() const {
-        return mAlias.isEmpty() ? mIdentifier.name : mAlias;
-    }
-    inline bool isExternal() const { return mIsExternal; }
-    inline uint32_t getSources() const { return mSources; }
-
-    const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
-
-    void addSource(uint32_t source);
-    void addMotionRange(int32_t axis, uint32_t source,
-            float min, float max, float flat, float fuzz, float resolution);
-    void addMotionRange(const MotionRange& range);
-
-    inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
-    inline int32_t getKeyboardType() const { return mKeyboardType; }
-
-    inline void setKeyCharacterMap(const sp<KeyCharacterMap>& value) {
-        mKeyCharacterMap = value;
-    }
-
-    inline sp<KeyCharacterMap> getKeyCharacterMap() const {
-        return mKeyCharacterMap;
-    }
-
-    inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
-    inline bool hasVibrator() const { return mHasVibrator; }
-
-    inline const Vector<MotionRange>& getMotionRanges() const {
-        return mMotionRanges;
-    }
-
-private:
-    int32_t mId;
-    int32_t mGeneration;
-    InputDeviceIdentifier mIdentifier;
-    String8 mAlias;
-    bool mIsExternal;
-    uint32_t mSources;
-    int32_t mKeyboardType;
-    sp<KeyCharacterMap> mKeyCharacterMap;
-    bool mHasVibrator;
-
-    Vector<MotionRange> mMotionRanges;
-};
-
-/* Types of input device configuration files. */
-enum InputDeviceConfigurationFileType {
-    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0,     /* .idc file */
-    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1,        /* .kl file */
-    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
-};
-
-/*
- * Gets the path of an input device configuration file, if one is available.
- * Considers both system provided and user installed configuration files.
- *
- * The device identifier is used to construct several default configuration file
- * names to try based on the device name, vendor, product, and version.
- *
- * Returns an empty string if not found.
- */
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
-        const InputDeviceIdentifier& deviceIdentifier,
-        InputDeviceConfigurationFileType type);
-
-/*
- * Gets the path of an input device configuration file, if one is available.
- * Considers both system provided and user installed configuration files.
- *
- * The name is case-sensitive and is used to construct the filename to resolve.
- * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
- *
- * Returns an empty string if not found.
- */
-extern String8 getInputDeviceConfigurationFilePathByName(
-        const String8& name, InputDeviceConfigurationFileType type);
-
-} // namespace android
-
-#endif // _ANDROIDFW_INPUT_DEVICE_H
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
deleted file mode 100644
index 8712995..0000000
--- a/include/androidfw/InputTransport.h
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 _ANDROIDFW_INPUT_TRANSPORT_H
-#define _ANDROIDFW_INPUT_TRANSPORT_H
-
-/**
- * Native input transport.
- *
- * The InputChannel provides a mechanism for exchanging InputMessage structures across processes.
- *
- * The InputPublisher and InputConsumer each handle one end-point of an input channel.
- * The InputPublisher is used by the input dispatcher to send events to the application.
- * The InputConsumer is used by the application to receive events from the input dispatcher.
- */
-
-#include <androidfw/Input.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/BitSet.h>
-
-namespace android {
-
-/*
- * Intermediate representation used to send input events and related signals.
- */
-struct InputMessage {
-    enum {
-        TYPE_KEY = 1,
-        TYPE_MOTION = 2,
-        TYPE_FINISHED = 3,
-    };
-
-    struct Header {
-        uint32_t type;
-        uint32_t padding; // 8 byte alignment for the body that follows
-    } header;
-
-    union Body {
-        struct Key {
-            uint32_t seq;
-            nsecs_t eventTime;
-            int32_t deviceId;
-            int32_t source;
-            int32_t action;
-            int32_t flags;
-            int32_t keyCode;
-            int32_t scanCode;
-            int32_t metaState;
-            int32_t repeatCount;
-            nsecs_t downTime;
-
-            inline size_t size() const {
-                return sizeof(Key);
-            }
-        } key;
-
-        struct Motion {
-            uint32_t seq;
-            nsecs_t eventTime;
-            int32_t deviceId;
-            int32_t source;
-            int32_t action;
-            int32_t flags;
-            int32_t metaState;
-            int32_t buttonState;
-            int32_t edgeFlags;
-            nsecs_t downTime;
-            float xOffset;
-            float yOffset;
-            float xPrecision;
-            float yPrecision;
-            size_t pointerCount;
-            struct Pointer {
-                PointerProperties properties;
-                PointerCoords coords;
-            } pointers[MAX_POINTERS];
-
-            int32_t getActionId() const {
-                uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
-                        >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-                return pointers[index].properties.id;
-            }
-
-            inline size_t size() const {
-                return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
-                        + sizeof(Pointer) * pointerCount;
-            }
-        } motion;
-
-        struct Finished {
-            uint32_t seq;
-            bool handled;
-
-            inline size_t size() const {
-                return sizeof(Finished);
-            }
-        } finished;
-    } body;
-
-    bool isValid(size_t actualSize) const;
-    size_t size() const;
-};
-
-/*
- * An input channel consists of a local unix domain socket used to send and receive
- * input messages across processes.  Each channel has a descriptive name for debugging purposes.
- *
- * Each endpoint has its own InputChannel object that specifies its file descriptor.
- *
- * The input channel is closed when all references to it are released.
- */
-class InputChannel : public RefBase {
-protected:
-    virtual ~InputChannel();
-
-public:
-    InputChannel(const String8& name, int fd);
-
-    /* Creates a pair of input channels.
-     *
-     * Returns OK on success.
-     */
-    static status_t openInputChannelPair(const String8& name,
-            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
-
-    inline String8 getName() const { return mName; }
-    inline int getFd() const { return mFd; }
-
-    /* Sends a message to the other endpoint.
-     *
-     * If the channel is full then the message is guaranteed not to have been sent at all.
-     * Try again after the consumer has sent a finished signal indicating that it has
-     * consumed some of the pending messages from the channel.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if the channel is full.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t sendMessage(const InputMessage* msg);
-
-    /* Receives a message sent by the other endpoint.
-     *
-     * If there is no message present, try again after poll() indicates that the fd
-     * is readable.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if there is no message present.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t receiveMessage(InputMessage* msg);
-
-    /* Returns a new object that has a duplicate of this channel's fd. */
-    sp<InputChannel> dup() const;
-
-private:
-    String8 mName;
-    int mFd;
-};
-
-/*
- * Publishes input events to an input channel.
- */
-class InputPublisher {
-public:
-    /* Creates a publisher associated with an input channel. */
-    explicit InputPublisher(const sp<InputChannel>& channel);
-
-    /* Destroys the publisher and releases its input channel. */
-    ~InputPublisher();
-
-    /* Gets the underlying input channel. */
-    inline sp<InputChannel> getChannel() { return mChannel; }
-
-    /* Publishes a key event to the input channel.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if the channel is full.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Returns BAD_VALUE if seq is 0.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t publishKeyEvent(
-            uint32_t seq,
-            int32_t deviceId,
-            int32_t source,
-            int32_t action,
-            int32_t flags,
-            int32_t keyCode,
-            int32_t scanCode,
-            int32_t metaState,
-            int32_t repeatCount,
-            nsecs_t downTime,
-            nsecs_t eventTime);
-
-    /* Publishes a motion event to the input channel.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if the channel is full.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t publishMotionEvent(
-            uint32_t seq,
-            int32_t deviceId,
-            int32_t source,
-            int32_t action,
-            int32_t flags,
-            int32_t edgeFlags,
-            int32_t metaState,
-            int32_t buttonState,
-            float xOffset,
-            float yOffset,
-            float xPrecision,
-            float yPrecision,
-            nsecs_t downTime,
-            nsecs_t eventTime,
-            size_t pointerCount,
-            const PointerProperties* pointerProperties,
-            const PointerCoords* pointerCoords);
-
-    /* Receives the finished signal from the consumer in reply to the original dispatch signal.
-     * If a signal was received, returns the message sequence number,
-     * and whether the consumer handled the message.
-     *
-     * The returned sequence number is never 0 unless the operation failed.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if there is no signal present.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
-
-private:
-    sp<InputChannel> mChannel;
-};
-
-/*
- * Consumes input events from an input channel.
- */
-class InputConsumer {
-public:
-    /* Creates a consumer associated with an input channel. */
-    explicit InputConsumer(const sp<InputChannel>& channel);
-
-    /* Destroys the consumer and releases its input channel. */
-    ~InputConsumer();
-
-    /* Gets the underlying input channel. */
-    inline sp<InputChannel> getChannel() { return mChannel; }
-
-    /* Consumes an input event from the input channel and copies its contents into
-     * an InputEvent object created using the specified factory.
-     *
-     * Tries to combine a series of move events into larger batches whenever possible.
-     *
-     * If consumeBatches is false, then defers consuming pending batched events if it
-     * is possible for additional samples to be added to them later.  Call hasPendingBatch()
-     * to determine whether a pending batch is available to be consumed.
-     *
-     * If consumeBatches is true, then events are still batched but they are consumed
-     * immediately as soon as the input channel is exhausted.
-     *
-     * The frameTime parameter specifies the time when the current display frame started
-     * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown.
-     *
-     * The returned sequence number is never 0 unless the operation failed.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if there is no event present.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Returns NO_MEMORY if the event could not be created.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
-
-    /* Sends a finished signal to the publisher to inform it that the message
-     * with the specified sequence number has finished being process and whether
-     * the message was handled by the consumer.
-     *
-     * Returns OK on success.
-     * Returns BAD_VALUE if seq is 0.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t sendFinishedSignal(uint32_t seq, bool handled);
-
-    /* Returns true if there is a deferred event waiting.
-     *
-     * Should be called after calling consume() to determine whether the consumer
-     * has a deferred event to be processed.  Deferred events are somewhat special in
-     * that they have already been removed from the input channel.  If the input channel
-     * becomes empty, the client may need to do extra work to ensure that it processes
-     * the deferred event despite the fact that the input channel's file descriptor
-     * is not readable.
-     *
-     * One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
-     * This guarantees that all deferred events will be processed.
-     *
-     * Alternately, the caller can call hasDeferredEvent() to determine whether there is
-     * a deferred event waiting and then ensure that its event loop wakes up at least
-     * one more time to consume the deferred event.
-     */
-    bool hasDeferredEvent() const;
-
-    /* Returns true if there is a pending batch.
-     *
-     * Should be called after calling consume() with consumeBatches == false to determine
-     * whether consume() should be called again later on with consumeBatches == true.
-     */
-    bool hasPendingBatch() const;
-
-private:
-    // True if touch resampling is enabled.
-    const bool mResampleTouch;
-
-    // The input channel.
-    sp<InputChannel> mChannel;
-
-    // The current input message.
-    InputMessage mMsg;
-
-    // True if mMsg contains a valid input message that was deferred from the previous
-    // call to consume and that still needs to be handled.
-    bool mMsgDeferred;
-
-    // Batched motion events per device and source.
-    struct Batch {
-        Vector<InputMessage> samples;
-    };
-    Vector<Batch> mBatches;
-
-    // Touch state per device and source, only for sources of class pointer.
-    struct History {
-        nsecs_t eventTime;
-        BitSet32 idBits;
-        int32_t idToIndex[MAX_POINTER_ID + 1];
-        PointerCoords pointers[MAX_POINTERS];
-
-        void initializeFrom(const InputMessage* msg) {
-            eventTime = msg->body.motion.eventTime;
-            idBits.clear();
-            for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
-                uint32_t id = msg->body.motion.pointers[i].properties.id;
-                idBits.markBit(id);
-                idToIndex[id] = i;
-                pointers[i].copyFrom(msg->body.motion.pointers[i].coords);
-            }
-        }
-
-        const PointerCoords& getPointerById(uint32_t id) const {
-            return pointers[idToIndex[id]];
-        }
-    };
-    struct TouchState {
-        int32_t deviceId;
-        int32_t source;
-        size_t historyCurrent;
-        size_t historySize;
-        History history[2];
-        History lastResample;
-
-        void initialize(int32_t deviceId, int32_t source) {
-            this->deviceId = deviceId;
-            this->source = source;
-            historyCurrent = 0;
-            historySize = 0;
-            lastResample.eventTime = 0;
-            lastResample.idBits.clear();
-        }
-
-        void addHistory(const InputMessage* msg) {
-            historyCurrent ^= 1;
-            if (historySize < 2) {
-                historySize += 1;
-            }
-            history[historyCurrent].initializeFrom(msg);
-        }
-
-        const History* getHistory(size_t index) const {
-            return &history[(historyCurrent + index) & 1];
-        }
-    };
-    Vector<TouchState> mTouchStates;
-
-    // Chain of batched sequence numbers.  When multiple input messages are combined into
-    // a batch, we append a record here that associates the last sequence number in the
-    // batch with the previous one.  When the finished signal is sent, we traverse the
-    // chain to individually finish all input messages that were part of the batch.
-    struct SeqChain {
-        uint32_t seq;   // sequence number of batched input message
-        uint32_t chain; // sequence number of previous batched input message
-    };
-    Vector<SeqChain> mSeqChains;
-
-    status_t consumeBatch(InputEventFactoryInterface* factory,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
-    status_t consumeSamples(InputEventFactoryInterface* factory,
-            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
-
-    void updateTouchState(InputMessage* msg);
-    void rewriteMessage(const TouchState& state, InputMessage* msg);
-    void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
-            const InputMessage *next);
-
-    ssize_t findBatch(int32_t deviceId, int32_t source) const;
-    ssize_t findTouchState(int32_t deviceId, int32_t source) const;
-
-    status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
-
-    static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
-    static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
-    static void addSample(MotionEvent* event, const InputMessage* msg);
-    static bool canAddSample(const Batch& batch, const InputMessage* msg);
-    static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
-    static bool shouldResampleTool(int32_t toolType);
-
-    static bool isTouchResamplingEnabled();
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_INPUT_TRANSPORT_H
diff --git a/include/androidfw/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
deleted file mode 100644
index 06799f9..0000000
--- a/include/androidfw/KeyCharacterMap.h
+++ /dev/null
@@ -1,257 +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.
- */
-
-#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H
-#define _ANDROIDFW_KEY_CHARACTER_MAP_H
-
-#include <stdint.h>
-
-#if HAVE_ANDROID_OS
-#include <binder/IBinder.h>
-#endif
-
-#include <androidfw/Input.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Tokenizer.h>
-#include <utils/String8.h>
-#include <utils/Unicode.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-/**
- * Describes a mapping from Android key codes to characters.
- * Also specifies other functions of the keyboard such as the keyboard type
- * and key modifier semantics.
- *
- * This object is immutable after it has been loaded.
- */
-class KeyCharacterMap : public RefBase {
-public:
-    enum KeyboardType {
-        KEYBOARD_TYPE_UNKNOWN = 0,
-        KEYBOARD_TYPE_NUMERIC = 1,
-        KEYBOARD_TYPE_PREDICTIVE = 2,
-        KEYBOARD_TYPE_ALPHA = 3,
-        KEYBOARD_TYPE_FULL = 4,
-        KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
-        KEYBOARD_TYPE_OVERLAY = 6,
-    };
-
-    enum Format {
-        // Base keyboard layout, may contain device-specific options, such as "type" declaration.
-        FORMAT_BASE = 0,
-        // Overlay keyboard layout, more restrictive, may be published by applications,
-        // cannot override device-specific options.
-        FORMAT_OVERLAY = 1,
-        // Either base or overlay layout ok.
-        FORMAT_ANY = 2,
-    };
-
-    // Substitute key code and meta state for fallback action.
-    struct FallbackAction {
-        int32_t keyCode;
-        int32_t metaState;
-    };
-
-    /* Loads a key character map from a file. */
-    static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
-
-    /* Loads a key character map from its string contents. */
-    static status_t loadContents(const String8& filename,
-            const char* contents, Format format, sp<KeyCharacterMap>* outMap);
-
-    /* Combines a base key character map and an overlay. */
-    static sp<KeyCharacterMap> combine(const sp<KeyCharacterMap>& base,
-            const sp<KeyCharacterMap>& overlay);
-
-    /* Returns an empty key character map. */
-    static sp<KeyCharacterMap> empty();
-
-    /* Gets the keyboard type. */
-    int32_t getKeyboardType() const;
-
-    /* Gets the primary character for this key as in the label physically printed on it.
-     * Returns 0 if none (eg. for non-printing keys). */
-    char16_t getDisplayLabel(int32_t keyCode) const;
-
-    /* Gets the Unicode character for the number or symbol generated by the key
-     * when the keyboard is used as a dialing pad.
-     * Returns 0 if no number or symbol is generated.
-     */
-    char16_t getNumber(int32_t keyCode) const;
-
-    /* Gets the Unicode character generated by the key and meta key modifiers.
-     * Returns 0 if no character is generated.
-     */
-    char16_t getCharacter(int32_t keyCode, int32_t metaState) const;
-
-    /* Gets the fallback action to use by default if the application does not
-     * handle the specified key.
-     * Returns true if an action was available, false if none.
-     */
-    bool getFallbackAction(int32_t keyCode, int32_t metaState,
-            FallbackAction* outFallbackAction) const;
-
-    /* Gets the first matching Unicode character that can be generated by the key,
-     * preferring the one with the specified meta key modifiers.
-     * Returns 0 if no matching character is generated.
-     */
-    char16_t getMatch(int32_t keyCode, const char16_t* chars,
-            size_t numChars, int32_t metaState) const;
-
-    /* Gets a sequence of key events that could plausibly generate the specified
-     * character sequence.  Returns false if some of the characters cannot be generated.
-     */
-    bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
-            Vector<KeyEvent>& outEvents) const;
-
-    /* Maps a scan code and usage code to a key code, in case this key map overrides
-     * the mapping in some way. */
-    status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
-
-#if HAVE_ANDROID_OS
-    /* Reads a key map from a parcel. */
-    static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
-
-    /* Writes a key map to a parcel. */
-    void writeToParcel(Parcel* parcel) const;
-#endif
-
-protected:
-    virtual ~KeyCharacterMap();
-
-private:
-    struct Behavior {
-        Behavior();
-        Behavior(const Behavior& other);
-
-        /* The next behavior in the list, or NULL if none. */
-        Behavior* next;
-
-        /* The meta key modifiers for this behavior. */
-        int32_t metaState;
-
-        /* The character to insert. */
-        char16_t character;
-
-        /* The fallback keycode if the key is not handled. */
-        int32_t fallbackKeyCode;
-    };
-
-    struct Key {
-        Key();
-        Key(const Key& other);
-        ~Key();
-
-        /* The single character label printed on the key, or 0 if none. */
-        char16_t label;
-
-        /* The number or symbol character generated by the key, or 0 if none. */
-        char16_t number;
-
-        /* The list of key behaviors sorted from most specific to least specific
-         * meta key binding. */
-        Behavior* firstBehavior;
-    };
-
-    class Parser {
-        enum State {
-            STATE_TOP = 0,
-            STATE_KEY = 1,
-        };
-
-        enum {
-            PROPERTY_LABEL = 1,
-            PROPERTY_NUMBER = 2,
-            PROPERTY_META = 3,
-        };
-
-        struct Property {
-            inline Property(int32_t property = 0, int32_t metaState = 0) :
-                    property(property), metaState(metaState) { }
-
-            int32_t property;
-            int32_t metaState;
-        };
-
-        KeyCharacterMap* mMap;
-        Tokenizer* mTokenizer;
-        Format mFormat;
-        State mState;
-        int32_t mKeyCode;
-
-    public:
-        Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format);
-        ~Parser();
-        status_t parse();
-
-    private:
-        status_t parseType();
-        status_t parseMap();
-        status_t parseMapKey();
-        status_t parseKey();
-        status_t parseKeyProperty();
-        status_t finishKey(Key* key);
-        status_t parseModifier(const String8& token, int32_t* outMetaState);
-        status_t parseCharacterLiteral(char16_t* outCharacter);
-    };
-
-    static sp<KeyCharacterMap> sEmpty;
-
-    KeyedVector<int32_t, Key*> mKeys;
-    int mType;
-
-    KeyedVector<int32_t, int32_t> mKeysByScanCode;
-    KeyedVector<int32_t, int32_t> mKeysByUsageCode;
-
-    KeyCharacterMap();
-    KeyCharacterMap(const KeyCharacterMap& other);
-
-    bool getKey(int32_t keyCode, const Key** outKey) const;
-    bool getKeyBehavior(int32_t keyCode, int32_t metaState,
-            const Key** outKey, const Behavior** outBehavior) const;
-    static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState);
-
-    bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
-
-    static status_t load(Tokenizer* tokenizer, Format format, sp<KeyCharacterMap>* outMap);
-
-    static void addKey(Vector<KeyEvent>& outEvents,
-            int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
-    static void addMetaKeys(Vector<KeyEvent>& outEvents,
-            int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
-            int32_t* currentMetaState);
-    static bool addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
-            int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
-            int32_t keyCode, int32_t keyMetaState,
-            int32_t* currentMetaState);
-    static void addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
-            int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
-            int32_t leftKeyCode, int32_t leftKeyMetaState,
-            int32_t rightKeyCode, int32_t rightKeyMetaState,
-            int32_t eitherKeyMetaState,
-            int32_t* currentMetaState);
-    static void addLockedMetaKey(Vector<KeyEvent>& outEvents,
-            int32_t deviceId, int32_t metaState, nsecs_t time,
-            int32_t keyCode, int32_t keyMetaState,
-            int32_t* currentMetaState);
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/androidfw/KeyLayoutMap.h b/include/androidfw/KeyLayoutMap.h
deleted file mode 100644
index e7f22a2..0000000
--- a/include/androidfw/KeyLayoutMap.h
+++ /dev/null
@@ -1,107 +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.
- */
-
-#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H
-#define _ANDROIDFW_KEY_LAYOUT_MAP_H
-
-#include <stdint.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Tokenizer.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct AxisInfo {
-    enum Mode {
-        // Axis value is reported directly.
-        MODE_NORMAL = 0,
-        // Axis value should be inverted before reporting.
-        MODE_INVERT = 1,
-        // Axis value should be split into two axes
-        MODE_SPLIT = 2,
-    };
-
-    // Axis mode.
-    Mode mode;
-
-    // Axis id.
-    // When split, this is the axis used for values smaller than the split position.
-    int32_t axis;
-
-    // When split, this is the axis used for values after higher than the split position.
-    int32_t highAxis;
-
-    // The split value, or 0 if not split.
-    int32_t splitValue;
-
-    // The flat value, or -1 if none.
-    int32_t flatOverride;
-
-    AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
-    }
-};
-
-/**
- * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
- *
- * This object is immutable after it has been loaded.
- */
-class KeyLayoutMap : public RefBase {
-public:
-    static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
-
-    status_t mapKey(int32_t scanCode, int32_t usageCode,
-            int32_t* outKeyCode, uint32_t* outFlags) const;
-    status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
-
-    status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
-
-protected:
-    virtual ~KeyLayoutMap();
-
-private:
-    struct Key {
-        int32_t keyCode;
-        uint32_t flags;
-    };
-
-    KeyedVector<int32_t, Key> mKeysByScanCode;
-    KeyedVector<int32_t, Key> mKeysByUsageCode;
-    KeyedVector<int32_t, AxisInfo> mAxes;
-
-    KeyLayoutMap();
-
-    const Key* getKey(int32_t scanCode, int32_t usageCode) const;
-
-    class Parser {
-        KeyLayoutMap* mMap;
-        Tokenizer* mTokenizer;
-
-    public:
-        Parser(KeyLayoutMap* map, Tokenizer* tokenizer);
-        ~Parser();
-        status_t parse();
-
-    private:
-        status_t parseKey();
-        status_t parseAxis();
-    };
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H
diff --git a/include/androidfw/Keyboard.h b/include/androidfw/Keyboard.h
deleted file mode 100644
index 6537a8f..0000000
--- a/include/androidfw/Keyboard.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 _ANDROIDFW_KEYBOARD_H
-#define _ANDROIDFW_KEYBOARD_H
-
-#include <androidfw/Input.h>
-#include <androidfw/InputDevice.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/PropertyMap.h>
-
-namespace android {
-
-enum {
-    /* Device id of the built in keyboard. */
-    DEVICE_ID_BUILT_IN_KEYBOARD = 0,
-
-    /* Device id of a generic virtual keyboard with a full layout that can be used
-     * to synthesize key events. */
-    DEVICE_ID_VIRTUAL_KEYBOARD = -1,
-};
-
-class KeyLayoutMap;
-class KeyCharacterMap;
-
-/**
- * Loads the key layout map and key character map for a keyboard device.
- */
-class KeyMap {
-public:
-    String8 keyLayoutFile;
-    sp<KeyLayoutMap> keyLayoutMap;
-
-    String8 keyCharacterMapFile;
-    sp<KeyCharacterMap> keyCharacterMap;
-
-    KeyMap();
-    ~KeyMap();
-
-    status_t load(const InputDeviceIdentifier& deviceIdenfier,
-            const PropertyMap* deviceConfiguration);
-
-    inline bool haveKeyLayout() const {
-        return !keyLayoutFile.isEmpty();
-    }
-
-    inline bool haveKeyCharacterMap() const {
-        return !keyCharacterMapFile.isEmpty();
-    }
-
-    inline bool isComplete() const {
-        return haveKeyLayout() && haveKeyCharacterMap();
-    }
-
-private:
-    bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
-    status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
-    status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-            const String8& name);
-    String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
-            const String8& name, InputDeviceConfigurationFileType type);
-};
-
-/**
- * Returns true if the keyboard is eligible for use as a built-in keyboard.
- */
-extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
-        const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
-
-/**
- * Gets a key code by its short form label, eg. "HOME".
- * Returns 0 if unknown.
- */
-extern int32_t getKeyCodeByLabel(const char* label);
-
-/**
- * Gets a key flag by its short form label, eg. "WAKE".
- * Returns 0 if unknown.
- */
-extern uint32_t getKeyFlagByLabel(const char* label);
-
-/**
- * Gets a axis by its short form label, eg. "X".
- * Returns -1 if unknown.
- */
-extern int32_t getAxisByLabel(const char* label);
-
-/**
- * Gets a axis label by its id.
- * Returns NULL if unknown.
- */
-extern const char* getAxisLabel(int32_t axisId);
-
-/**
- * Updates a meta state field when a key is pressed or released.
- */
-extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
-
-/**
- * Returns true if a key is a meta key like ALT or CAPS_LOCK.
- */
-extern bool isMetaKey(int32_t keyCode);
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEYBOARD_H
diff --git a/include/androidfw/KeycodeLabels.h b/include/androidfw/KeycodeLabels.h
deleted file mode 100644
index 3e12f26..0000000
--- a/include/androidfw/KeycodeLabels.h
+++ /dev/null
@@ -1,321 +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.
- */
-
-#ifndef _ANDROIDFW_KEYCODE_LABELS_H
-#define _ANDROIDFW_KEYCODE_LABELS_H
-
-#include <android/keycodes.h>
-
-struct KeycodeLabel {
-    const char *literal;
-    int value;
-};
-
-static const KeycodeLabel KEYCODES[] = {
-    { "SOFT_LEFT", 1 },
-    { "SOFT_RIGHT", 2 },
-    { "HOME", 3 },
-    { "BACK", 4 },
-    { "CALL", 5 },
-    { "ENDCALL", 6 },
-    { "0", 7 },
-    { "1", 8 },
-    { "2", 9 },
-    { "3", 10 },
-    { "4", 11 },
-    { "5", 12 },
-    { "6", 13 },
-    { "7", 14 },
-    { "8", 15 },
-    { "9", 16 },
-    { "STAR", 17 },
-    { "POUND", 18 },
-    { "DPAD_UP", 19 },
-    { "DPAD_DOWN", 20 },
-    { "DPAD_LEFT", 21 },
-    { "DPAD_RIGHT", 22 },
-    { "DPAD_CENTER", 23 },
-    { "VOLUME_UP", 24 },
-    { "VOLUME_DOWN", 25 },
-    { "POWER", 26 },
-    { "CAMERA", 27 },
-    { "CLEAR", 28 },
-    { "A", 29 },
-    { "B", 30 },
-    { "C", 31 },
-    { "D", 32 },
-    { "E", 33 },
-    { "F", 34 },
-    { "G", 35 },
-    { "H", 36 },
-    { "I", 37 },
-    { "J", 38 },
-    { "K", 39 },
-    { "L", 40 },
-    { "M", 41 },
-    { "N", 42 },
-    { "O", 43 },
-    { "P", 44 },
-    { "Q", 45 },
-    { "R", 46 },
-    { "S", 47 },
-    { "T", 48 },
-    { "U", 49 },
-    { "V", 50 },
-    { "W", 51 },
-    { "X", 52 },
-    { "Y", 53 },
-    { "Z", 54 },
-    { "COMMA", 55 },
-    { "PERIOD", 56 },
-    { "ALT_LEFT", 57 },
-    { "ALT_RIGHT", 58 },
-    { "SHIFT_LEFT", 59 },
-    { "SHIFT_RIGHT", 60 },
-    { "TAB", 61 },
-    { "SPACE", 62 },
-    { "SYM", 63 },
-    { "EXPLORER", 64 },
-    { "ENVELOPE", 65 },
-    { "ENTER", 66 },
-    { "DEL", 67 },
-    { "GRAVE", 68 },
-    { "MINUS", 69 },
-    { "EQUALS", 70 },
-    { "LEFT_BRACKET", 71 },
-    { "RIGHT_BRACKET", 72 },
-    { "BACKSLASH", 73 },
-    { "SEMICOLON", 74 },
-    { "APOSTROPHE", 75 },
-    { "SLASH", 76 },
-    { "AT", 77 },
-    { "NUM", 78 },
-    { "HEADSETHOOK", 79 },
-    { "FOCUS", 80 },
-    { "PLUS", 81 },
-    { "MENU", 82 },
-    { "NOTIFICATION", 83 },
-    { "SEARCH", 84 },
-    { "MEDIA_PLAY_PAUSE", 85 },
-    { "MEDIA_STOP", 86 },
-    { "MEDIA_NEXT", 87 },
-    { "MEDIA_PREVIOUS", 88 },
-    { "MEDIA_REWIND", 89 },
-    { "MEDIA_FAST_FORWARD", 90 },
-    { "MUTE", 91 },
-    { "PAGE_UP", 92 },
-    { "PAGE_DOWN", 93 },
-    { "PICTSYMBOLS", 94 },
-    { "SWITCH_CHARSET", 95 },
-    { "BUTTON_A", 96 },
-    { "BUTTON_B", 97 },
-    { "BUTTON_C", 98 },
-    { "BUTTON_X", 99 },
-    { "BUTTON_Y", 100 },
-    { "BUTTON_Z", 101 },
-    { "BUTTON_L1", 102 },
-    { "BUTTON_R1", 103 },
-    { "BUTTON_L2", 104 },
-    { "BUTTON_R2", 105 },
-    { "BUTTON_THUMBL", 106 },
-    { "BUTTON_THUMBR", 107 },
-    { "BUTTON_START", 108 },
-    { "BUTTON_SELECT", 109 },
-    { "BUTTON_MODE", 110 },
-    { "ESCAPE", 111 },
-    { "FORWARD_DEL", 112 },
-    { "CTRL_LEFT", 113 },
-    { "CTRL_RIGHT", 114 },
-    { "CAPS_LOCK", 115 },
-    { "SCROLL_LOCK", 116 },
-    { "META_LEFT", 117 },
-    { "META_RIGHT", 118 },
-    { "FUNCTION", 119 },
-    { "SYSRQ", 120 },
-    { "BREAK", 121 },
-    { "MOVE_HOME", 122 },
-    { "MOVE_END", 123 },
-    { "INSERT", 124 },
-    { "FORWARD", 125 },
-    { "MEDIA_PLAY", 126 },
-    { "MEDIA_PAUSE", 127 },
-    { "MEDIA_CLOSE", 128 },
-    { "MEDIA_EJECT", 129 },
-    { "MEDIA_RECORD", 130 },
-    { "F1", 131 },
-    { "F2", 132 },
-    { "F3", 133 },
-    { "F4", 134 },
-    { "F5", 135 },
-    { "F6", 136 },
-    { "F7", 137 },
-    { "F8", 138 },
-    { "F9", 139 },
-    { "F10", 140 },
-    { "F11", 141 },
-    { "F12", 142 },
-    { "NUM_LOCK", 143 },
-    { "NUMPAD_0", 144 },
-    { "NUMPAD_1", 145 },
-    { "NUMPAD_2", 146 },
-    { "NUMPAD_3", 147 },
-    { "NUMPAD_4", 148 },
-    { "NUMPAD_5", 149 },
-    { "NUMPAD_6", 150 },
-    { "NUMPAD_7", 151 },
-    { "NUMPAD_8", 152 },
-    { "NUMPAD_9", 153 },
-    { "NUMPAD_DIVIDE", 154 },
-    { "NUMPAD_MULTIPLY", 155 },
-    { "NUMPAD_SUBTRACT", 156 },
-    { "NUMPAD_ADD", 157 },
-    { "NUMPAD_DOT", 158 },
-    { "NUMPAD_COMMA", 159 },
-    { "NUMPAD_ENTER", 160 },
-    { "NUMPAD_EQUALS", 161 },
-    { "NUMPAD_LEFT_PAREN", 162 },
-    { "NUMPAD_RIGHT_PAREN", 163 },
-    { "VOLUME_MUTE", 164 },
-    { "INFO", 165 },
-    { "CHANNEL_UP", 166 },
-    { "CHANNEL_DOWN", 167 },
-    { "ZOOM_IN", 168 },
-    { "ZOOM_OUT", 169 },
-    { "TV", 170 },
-    { "WINDOW", 171 },
-    { "GUIDE", 172 },
-    { "DVR", 173 },
-    { "BOOKMARK", 174 },
-    { "CAPTIONS", 175 },
-    { "SETTINGS", 176 },
-    { "TV_POWER", 177 },
-    { "TV_INPUT", 178 },
-    { "STB_POWER", 179 },
-    { "STB_INPUT", 180 },
-    { "AVR_POWER", 181 },
-    { "AVR_INPUT", 182 },
-    { "PROG_RED", 183 },
-    { "PROG_GREEN", 184 },
-    { "PROG_YELLOW", 185 },
-    { "PROG_BLUE", 186 },
-    { "APP_SWITCH", 187 },
-    { "BUTTON_1", 188 },
-    { "BUTTON_2", 189 },
-    { "BUTTON_3", 190 },
-    { "BUTTON_4", 191 },
-    { "BUTTON_5", 192 },
-    { "BUTTON_6", 193 },
-    { "BUTTON_7", 194 },
-    { "BUTTON_8", 195 },
-    { "BUTTON_9", 196 },
-    { "BUTTON_10", 197 },
-    { "BUTTON_11", 198 },
-    { "BUTTON_12", 199 },
-    { "BUTTON_13", 200 },
-    { "BUTTON_14", 201 },
-    { "BUTTON_15", 202 },
-    { "BUTTON_16", 203 },
-    { "LANGUAGE_SWITCH", 204 },
-    { "MANNER_MODE", 205 },
-    { "3D_MODE", 206 },
-    { "CONTACTS", 207 },
-    { "CALENDAR", 208 },
-    { "MUSIC", 209 },
-    { "CALCULATOR", 210 },
-    { "ZENKAKU_HANKAKU", 211 },
-    { "EISU", 212 },
-    { "MUHENKAN", 213 },
-    { "HENKAN", 214 },
-    { "KATAKANA_HIRAGANA", 215 },
-    { "YEN", 216 },
-    { "RO", 217 },
-    { "KANA", 218 },
-    { "ASSIST", 219 },
-    { "BRIGHTNESS_DOWN", 220 },
-    { "BRIGHTNESS_UP", 221 },
-
-    // NOTE: If you add a new keycode here you must also add it to several other files.
-    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
-
-    { NULL, 0 }
-};
-
-// NOTE: If you edit these flags, also edit policy flags in Input.h.
-static const KeycodeLabel FLAGS[] = {
-    { "WAKE", 0x00000001 },
-    { "WAKE_DROPPED", 0x00000002 },
-    { "SHIFT", 0x00000004 },
-    { "CAPS_LOCK", 0x00000008 },
-    { "ALT", 0x00000010 },
-    { "ALT_GR", 0x00000020 },
-    { "MENU", 0x00000040 },
-    { "LAUNCHER", 0x00000080 },
-    { "VIRTUAL", 0x00000100 },
-    { "FUNCTION", 0x00000200 },
-    { NULL, 0 }
-};
-
-static const KeycodeLabel AXES[] = {
-    { "X", 0 },
-    { "Y", 1 },
-    { "PRESSURE", 2 },
-    { "SIZE", 3 },
-    { "TOUCH_MAJOR", 4 },
-    { "TOUCH_MINOR", 5 },
-    { "TOOL_MAJOR", 6 },
-    { "TOOL_MINOR", 7 },
-    { "ORIENTATION", 8 },
-    { "VSCROLL", 9 },
-    { "HSCROLL", 10 },
-    { "Z", 11 },
-    { "RX", 12 },
-    { "RY", 13 },
-    { "RZ", 14 },
-    { "HAT_X", 15 },
-    { "HAT_Y", 16 },
-    { "LTRIGGER", 17 },
-    { "RTRIGGER", 18 },
-    { "THROTTLE", 19 },
-    { "RUDDER", 20 },
-    { "WHEEL", 21 },
-    { "GAS", 22 },
-    { "BRAKE", 23 },
-    { "DISTANCE", 24 },
-    { "TILT", 25 },
-    { "GENERIC_1", 32 },
-    { "GENERIC_2", 33 },
-    { "GENERIC_3", 34 },
-    { "GENERIC_4", 35 },
-    { "GENERIC_5", 36 },
-    { "GENERIC_6", 37 },
-    { "GENERIC_7", 38 },
-    { "GENERIC_8", 39 },
-    { "GENERIC_9", 40 },
-    { "GENERIC_10", 41 },
-    { "GENERIC_11", 42 },
-    { "GENERIC_12", 43 },
-    { "GENERIC_13", 44 },
-    { "GENERIC_14", 45 },
-    { "GENERIC_15", 46 },
-    { "GENERIC_16", 47 },
-
-    // NOTE: If you add a new axis here you must also add it to several other files.
-    //       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
-
-    { NULL, -1 }
-};
-
-#endif // _ANDROIDFW_KEYCODE_LABELS_H
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 5b45d70..97afa59 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -479,7 +479,7 @@
     const uint32_t*             mEntries;
     const uint32_t*             mEntryStyles;
     const void*                 mStrings;
-    char16_t**                  mCache;
+    char16_t mutable**          mCache;
     uint32_t                    mStringPoolSize;    // number of uint16_t
     const uint32_t*             mStyles;
     uint32_t                    mStylePoolSize;    // number of uint32_t
@@ -678,11 +678,15 @@
     // Returns -1 if no namespace, -2 if idx out of range.
     int32_t getAttributeNamespaceID(size_t idx) const;
     const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
-    
+
     int32_t getAttributeNameID(size_t idx) const;
     const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
     uint32_t getAttributeNameResID(size_t idx) const;
-    
+
+    // These will work only if the underlying string pool is UTF-8.
+    const char* getAttributeNamespace8(size_t idx, size_t* outLen) const;
+    const char* getAttributeName8(size_t idx, size_t* outLen) const;
+
     int32_t getAttributeValueStringID(size_t idx) const;
     const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
     
@@ -1294,12 +1298,14 @@
         const char16_t* package;
         size_t packageLen;
         const char16_t* type;
+        const char* type8;
         size_t typeLen;
         const char16_t* name;
+        const char* name8;
         size_t nameLen;
     };
 
-    bool getResourceName(uint32_t resID, resource_name* outName) const;
+    bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const;
 
     /**
      * Retrieve the value of a resource.  If the resource is found, returns a
@@ -1553,10 +1559,8 @@
     static bool getIdmapInfo(const void* idmap, size_t size,
                              uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
 
-#ifndef HAVE_ANDROID_OS
     void print(bool inclValues) const;
     static String8 normalizeForOutput(const char* input);
-#endif
 
 private:
     struct Header;
diff --git a/include/androidfw/VelocityControl.h b/include/androidfw/VelocityControl.h
deleted file mode 100644
index 84e0444..0000000
--- a/include/androidfw/VelocityControl.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROIDFW_VELOCITY_CONTROL_H
-#define _ANDROIDFW_VELOCITY_CONTROL_H
-
-#include <androidfw/Input.h>
-#include <androidfw/VelocityTracker.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-/*
- * Specifies parameters that govern pointer or wheel acceleration.
- */
-struct VelocityControlParameters {
-    // A scale factor that is multiplied with the raw velocity deltas
-    // prior to applying any other velocity control factors.  The scale
-    // factor should be used to adapt the input device resolution
-    // (eg. counts per inch) to the output device resolution (eg. pixels per inch).
-    //
-    // Must be a positive value.
-    // Default is 1.0 (no scaling).
-    float scale;
-
-    // The scaled speed at which acceleration begins to be applied.
-    // This value establishes the upper bound of a low speed regime for
-    // small precise motions that are performed without any acceleration.
-    //
-    // Must be a non-negative value.
-    // Default is 0.0 (no low threshold).
-    float lowThreshold;
-
-    // The scaled speed at which maximum acceleration is applied.
-    // The difference between highThreshold and lowThreshold controls
-    // the range of speeds over which the acceleration factor is interpolated.
-    // The wider the range, the smoother the acceleration.
-    //
-    // Must be a non-negative value greater than or equal to lowThreshold.
-    // Default is 0.0 (no high threshold).
-    float highThreshold;
-
-    // The acceleration factor.
-    // When the speed is above the low speed threshold, the velocity will scaled
-    // by an interpolated value between 1.0 and this amount.
-    //
-    // Must be a positive greater than or equal to 1.0.
-    // Default is 1.0 (no acceleration).
-    float acceleration;
-
-    VelocityControlParameters() :
-            scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
-    }
-
-    VelocityControlParameters(float scale, float lowThreshold,
-            float highThreshold, float acceleration) :
-            scale(scale), lowThreshold(lowThreshold),
-            highThreshold(highThreshold), acceleration(acceleration) {
-    }
-};
-
-/*
- * Implements mouse pointer and wheel speed control and acceleration.
- */
-class VelocityControl {
-public:
-    VelocityControl();
-
-    /* Sets the various parameters. */
-    void setParameters(const VelocityControlParameters& parameters);
-
-    /* Resets the current movement counters to zero.
-     * This has the effect of nullifying any acceleration. */
-    void reset();
-
-    /* Translates a raw movement delta into an appropriately
-     * scaled / accelerated delta based on the current velocity. */
-    void move(nsecs_t eventTime, float* deltaX, float* deltaY);
-
-private:
-    // If no movements are received within this amount of time,
-    // we assume the movement has stopped and reset the movement counters.
-    static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
-
-    VelocityControlParameters mParameters;
-
-    nsecs_t mLastMovementTime;
-    VelocityTracker::Position mRawPosition;
-    VelocityTracker mVelocityTracker;
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_VELOCITY_CONTROL_H
diff --git a/include/androidfw/VelocityTracker.h b/include/androidfw/VelocityTracker.h
deleted file mode 100644
index 8c24219..0000000
--- a/include/androidfw/VelocityTracker.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROIDFW_VELOCITY_TRACKER_H
-#define _ANDROIDFW_VELOCITY_TRACKER_H
-
-#include <androidfw/Input.h>
-#include <utils/Timers.h>
-#include <utils/BitSet.h>
-
-namespace android {
-
-class VelocityTrackerStrategy;
-
-/*
- * Calculates the velocity of pointer movements over time.
- */
-class VelocityTracker {
-public:
-    struct Position {
-        float x, y;
-    };
-
-    struct Estimator {
-        static const size_t MAX_DEGREE = 4;
-
-        // Estimator time base.
-        nsecs_t time;
-
-        // Polynomial coefficients describing motion in X and Y.
-        float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
-
-        // Polynomial degree (number of coefficients), or zero if no information is
-        // available.
-        uint32_t degree;
-
-        // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit).
-        float confidence;
-
-        inline void clear() {
-            time = 0;
-            degree = 0;
-            confidence = 0;
-            for (size_t i = 0; i <= MAX_DEGREE; i++) {
-                xCoeff[i] = 0;
-                yCoeff[i] = 0;
-            }
-        }
-    };
-
-    // Creates a velocity tracker using the specified strategy.
-    // If strategy is NULL, uses the default strategy for the platform.
-    VelocityTracker(const char* strategy = NULL);
-
-    ~VelocityTracker();
-
-    // Resets the velocity tracker state.
-    void clear();
-
-    // Resets the velocity tracker state for specific pointers.
-    // Call this method when some pointers have changed and may be reusing
-    // an id that was assigned to a different pointer earlier.
-    void clearPointers(BitSet32 idBits);
-
-    // Adds movement information for a set of pointers.
-    // The idBits bitfield specifies the pointer ids of the pointers whose positions
-    // are included in the movement.
-    // The positions array contains position information for each pointer in order by
-    // increasing id.  Its size should be equal to the number of one bits in idBits.
-    void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
-
-    // Adds movement information for all pointers in a MotionEvent, including historical samples.
-    void addMovement(const MotionEvent* event);
-
-    // Gets the velocity of the specified pointer id in position units per second.
-    // Returns false and sets the velocity components to zero if there is
-    // insufficient movement information for the pointer.
-    bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
-
-    // Gets an estimator for the recent movements of the specified pointer id.
-    // Returns false and clears the estimator if there is no information available
-    // about the pointer.
-    bool getEstimator(uint32_t id, Estimator* outEstimator) const;
-
-    // Gets the active pointer id, or -1 if none.
-    inline int32_t getActivePointerId() const { return mActivePointerId; }
-
-    // Gets a bitset containing all pointer ids from the most recent movement.
-    inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
-
-private:
-    static const char* DEFAULT_STRATEGY;
-
-    nsecs_t mLastEventTime;
-    BitSet32 mCurrentPointerIdBits;
-    int32_t mActivePointerId;
-    VelocityTrackerStrategy* mStrategy;
-
-    bool configureStrategy(const char* strategy);
-
-    static VelocityTrackerStrategy* createStrategy(const char* strategy);
-};
-
-
-/*
- * Implements a particular velocity tracker algorithm.
- */
-class VelocityTrackerStrategy {
-protected:
-    VelocityTrackerStrategy() { }
-
-public:
-    virtual ~VelocityTrackerStrategy() { }
-
-    virtual void clear() = 0;
-    virtual void clearPointers(BitSet32 idBits) = 0;
-    virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
-            const VelocityTracker::Position* positions) = 0;
-    virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
-};
-
-
-/*
- * Velocity tracker algorithm based on least-squares linear regression.
- */
-class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
-public:
-    enum Weighting {
-        // No weights applied.  All data points are equally reliable.
-        WEIGHTING_NONE,
-
-        // Weight by time delta.  Data points clustered together are weighted less.
-        WEIGHTING_DELTA,
-
-        // Weight such that points within a certain horizon are weighed more than those
-        // outside of that horizon.
-        WEIGHTING_CENTRAL,
-
-        // Weight such that points older than a certain amount are weighed less.
-        WEIGHTING_RECENT,
-    };
-
-    // Degree must be no greater than Estimator::MAX_DEGREE.
-    LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE);
-    virtual ~LeastSquaresVelocityTrackerStrategy();
-
-    virtual void clear();
-    virtual void clearPointers(BitSet32 idBits);
-    virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
-            const VelocityTracker::Position* positions);
-    virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
-
-private:
-    // Sample horizon.
-    // We don't use too much history by default since we want to react to quick
-    // changes in direction.
-    static const nsecs_t HORIZON = 100 * 1000000; // 100 ms
-
-    // Number of samples to keep.
-    static const uint32_t HISTORY_SIZE = 20;
-
-    struct Movement {
-        nsecs_t eventTime;
-        BitSet32 idBits;
-        VelocityTracker::Position positions[MAX_POINTERS];
-
-        inline const VelocityTracker::Position& getPosition(uint32_t id) const {
-            return positions[idBits.getIndexOfBit(id)];
-        }
-    };
-
-    float chooseWeight(uint32_t index) const;
-
-    const uint32_t mDegree;
-    const Weighting mWeighting;
-    uint32_t mIndex;
-    Movement mMovements[HISTORY_SIZE];
-};
-
-
-/*
- * Velocity tracker algorithm that uses an IIR filter.
- */
-class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
-public:
-    // Degree must be 1 or 2.
-    IntegratingVelocityTrackerStrategy(uint32_t degree);
-    ~IntegratingVelocityTrackerStrategy();
-
-    virtual void clear();
-    virtual void clearPointers(BitSet32 idBits);
-    virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
-            const VelocityTracker::Position* positions);
-    virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
-
-private:
-    // Current state estimate for a particular pointer.
-    struct State {
-        nsecs_t updateTime;
-        uint32_t degree;
-
-        float xpos, xvel, xaccel;
-        float ypos, yvel, yaccel;
-    };
-
-    const uint32_t mDegree;
-    BitSet32 mPointerIdBits;
-    State mPointerState[MAX_POINTER_ID + 1];
-
-    void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
-    void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
-    void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const;
-};
-
-
-/*
- * Velocity tracker strategy used prior to ICS.
- */
-class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy {
-public:
-    LegacyVelocityTrackerStrategy();
-    virtual ~LegacyVelocityTrackerStrategy();
-
-    virtual void clear();
-    virtual void clearPointers(BitSet32 idBits);
-    virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
-            const VelocityTracker::Position* positions);
-    virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
-
-private:
-    // Oldest sample to consider when calculating the velocity.
-    static const nsecs_t HORIZON = 200 * 1000000; // 100 ms
-
-    // Number of samples to keep.
-    static const uint32_t HISTORY_SIZE = 20;
-
-    // The minimum duration between samples when estimating velocity.
-    static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
-
-    struct Movement {
-        nsecs_t eventTime;
-        BitSet32 idBits;
-        VelocityTracker::Position positions[MAX_POINTERS];
-
-        inline const VelocityTracker::Position& getPosition(uint32_t id) const {
-            return positions[idBits.getIndexOfBit(id)];
-        }
-    };
-
-    uint32_t mIndex;
-    Movement mMovements[HISTORY_SIZE];
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_VELOCITY_TRACKER_H
diff --git a/include/androidfw/VirtualKeyMap.h b/include/androidfw/VirtualKeyMap.h
deleted file mode 100644
index dd3ad1e9..0000000
--- a/include/androidfw/VirtualKeyMap.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 _ANDROIDFW_VIRTUAL_KEY_MAP_H
-#define _ANDROIDFW_VIRTUAL_KEY_MAP_H
-
-#include <stdint.h>
-
-#include <androidfw/Input.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Tokenizer.h>
-#include <utils/String8.h>
-#include <utils/Unicode.h>
-
-namespace android {
-
-/* Describes a virtual key. */
-struct VirtualKeyDefinition {
-    int32_t scanCode;
-
-    // configured position data, specified in display coords
-    int32_t centerX;
-    int32_t centerY;
-    int32_t width;
-    int32_t height;
-};
-
-
-/**
- * Describes a collection of virtual keys on a touch screen in terms of
- * virtual scan codes and hit rectangles.
- *
- * This object is immutable after it has been loaded.
- */
-class VirtualKeyMap {
-public:
-    ~VirtualKeyMap();
-
-    static status_t load(const String8& filename, VirtualKeyMap** outMap);
-
-    inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
-        return mVirtualKeys;
-    }
-
-private:
-    class Parser {
-        VirtualKeyMap* mMap;
-        Tokenizer* mTokenizer;
-
-    public:
-        Parser(VirtualKeyMap* map, Tokenizer* tokenizer);
-        ~Parser();
-        status_t parse();
-
-    private:
-        bool consumeFieldDelimiterAndSkipWhitespace();
-        bool parseNextIntField(int32_t* outValue);
-    };
-
-    Vector<VirtualKeyDefinition> mVirtualKeys;
-
-    VirtualKeyMap();
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h
new file mode 100644
index 0000000..547e36a
--- /dev/null
+++ b/include/androidfw/ZipFileRO.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Read-only access to Zip archives, with minimal heap allocation.
+ *
+ * This is similar to the more-complete ZipFile class, but no attempt
+ * has been made to make them interchangeable.  This class operates under
+ * a very different set of assumptions and constraints.
+ *
+ * One such assumption is that if you're getting file descriptors for
+ * use with this class as a child of a fork() operation, you must be on
+ * a pread() to guarantee correct operation. This is because pread() can
+ * atomically read at a file offset without worrying about a lock around an
+ * lseek() + read() pair.
+ */
+#ifndef __LIBS_ZIPFILERO_H
+#define __LIBS_ZIPFILERO_H
+
+#include <utils/Compat.h>
+#include <utils/Errors.h>
+#include <utils/FileMap.h>
+#include <utils/threads.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+namespace android {
+
+/*
+ * Trivial typedef to ensure that ZipEntryRO is not treated as a simple
+ * integer.  We use NULL to indicate an invalid value.
+ */
+typedef void* ZipEntryRO;
+
+/*
+ * Open a Zip archive for reading.
+ *
+ * We want "open" and "find entry by name" to be fast operations, and we
+ * want to use as little memory as possible.  We memory-map the file,
+ * and load a hash table with pointers to the filenames (which aren't
+ * null-terminated).  The other fields are at a fixed offset from the
+ * filename, so we don't need to extract those (but we do need to byte-read
+ * and endian-swap them every time we want them).
+ *
+ * To speed comparisons when doing a lookup by name, we could make the mapping
+ * "private" (copy-on-write) and null-terminate the filenames after verifying
+ * the record structure.  However, this requires a private mapping of
+ * every page that the Central Directory touches.  Easier to tuck a copy
+ * of the string length into the hash table entry.
+ *
+ * NOTE: If this is used on file descriptors inherited from a fork() operation,
+ * you must be on a platform that implements pread() to guarantee correctness
+ * on the shared file descriptors.
+ */
+class ZipFileRO {
+public:
+    ZipFileRO()
+        : mFd(-1), mFileName(NULL), mFileLength(-1),
+          mDirectoryMap(NULL),
+          mNumEntries(-1), mDirectoryOffset(-1),
+          mHashTableSize(-1), mHashTable(NULL)
+        {}
+
+    ~ZipFileRO();
+
+    /*
+     * Open an archive.
+     */
+    status_t open(const char* zipFileName);
+
+    /*
+     * Find an entry, by name.  Returns the entry identifier, or NULL if
+     * not found.
+     *
+     * If two entries have the same name, one will be chosen at semi-random.
+     */
+    ZipEntryRO findEntryByName(const char* fileName) const;
+
+    /*
+     * Return the #of entries in the Zip archive.
+     */
+    int getNumEntries(void) const {
+        return mNumEntries;
+    }
+
+    /*
+     * Return the Nth entry.  Zip file entries are not stored in sorted
+     * order, and updated entries may appear at the end, so anyone walking
+     * the archive needs to avoid making ordering assumptions.  We take
+     * that further by returning the Nth non-empty entry in the hash table
+     * rather than the Nth entry in the archive.
+     *
+     * Valid values are [0..numEntries).
+     *
+     * [This is currently O(n).  If it needs to be fast we can allocate an
+     * additional data structure or provide an iterator interface.]
+     */
+    ZipEntryRO findEntryByIndex(int idx) const;
+
+    /*
+     * Copy the filename into the supplied buffer.  Returns 0 on success,
+     * -1 if "entry" is invalid, or the filename length if it didn't fit.  The
+     * length, and the returned string, include the null-termination.
+     */
+    int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const;
+
+    /*
+     * Get the vital stats for an entry.  Pass in NULL pointers for anything
+     * you don't need.
+     *
+     * "*pOffset" holds the Zip file offset of the entry's data.
+     *
+     * Returns "false" if "entry" is bogus or if the data in the Zip file
+     * appears to be bad.
+     */
+    bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const;
+
+    /*
+     * Create a new FileMap object that maps a subset of the archive.  For
+     * an uncompressed entry this effectively provides a pointer to the
+     * actual data, for a compressed entry this provides the input buffer
+     * for inflate().
+     */
+    FileMap* createEntryFileMap(ZipEntryRO entry) const;
+
+    /*
+     * Uncompress the data into a buffer.  Depending on the compression
+     * format, this is either an "inflate" operation or a memcpy.
+     *
+     * Use "uncompLen" from getEntryInfo() to determine the required
+     * buffer size.
+     *
+     * Returns "true" on success.
+     */
+    bool uncompressEntry(ZipEntryRO entry, void* buffer) const;
+
+    /*
+     * Uncompress the data to an open file descriptor.
+     */
+    bool uncompressEntry(ZipEntryRO entry, int fd) const;
+
+    /* Zip compression methods we support */
+    enum {
+        kCompressStored     = 0,        // no compression
+        kCompressDeflated   = 8,        // standard deflate
+    };
+
+    /*
+     * Utility function: uncompress deflated data, buffer to buffer.
+     */
+    static bool inflateBuffer(void* outBuf, const void* inBuf,
+        size_t uncompLen, size_t compLen);
+
+    /*
+     * Utility function: uncompress deflated data, buffer to fd.
+     */
+    static bool inflateBuffer(int fd, const void* inBuf,
+        size_t uncompLen, size_t compLen);
+
+    /*
+     * Utility function to convert ZIP's time format to a timespec struct.
+     */
+    static inline void zipTimeToTimespec(long when, struct tm* timespec) {
+        const long date = when >> 16;
+        timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
+        timespec->tm_mon = (date >> 5) & 0x0F;
+        timespec->tm_mday = date & 0x1F;
+
+        timespec->tm_hour = (when >> 11) & 0x1F;
+        timespec->tm_min = (when >> 5) & 0x3F;
+        timespec->tm_sec = (when & 0x1F) << 1;
+    }
+
+    /*
+     * Some basic functions for raw data manipulation.  "LE" means
+     * Little Endian.
+     */
+    static inline unsigned short get2LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8);
+    }
+    static inline unsigned long get4LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+
+private:
+    /* these are private and not defined */ 
+    ZipFileRO(const ZipFileRO& src);
+    ZipFileRO& operator=(const ZipFileRO& src);
+
+    /* locate and parse the central directory */
+    bool mapCentralDirectory(void);
+
+    /* parse the archive, prepping internal structures */
+    bool parseZipArchive(void);
+
+    /* add a new entry to the hash table */
+    void addToHash(const char* str, int strLen, unsigned int hash);
+
+    /* compute string hash code */
+    static unsigned int computeHash(const char* str, int len);
+
+    /* convert a ZipEntryRO back to a hash table index */
+    int entryToIndex(const ZipEntryRO entry) const;
+
+    /*
+     * One entry in the hash table.
+     */
+    typedef struct HashEntry {
+        const char*     name;
+        unsigned short  nameLen;
+        //unsigned int    hash;
+    } HashEntry;
+
+    /* open Zip archive */
+    int         mFd;
+
+    /* Lock for handling the file descriptor (seeks, etc) */
+    mutable Mutex mFdLock;
+
+    /* zip file name */
+    char*       mFileName;
+
+    /* length of file */
+    size_t      mFileLength;
+
+    /* mapped file */
+    FileMap*    mDirectoryMap;
+
+    /* number of entries in the Zip archive */
+    int         mNumEntries;
+
+    /* CD directory offset in the Zip archive */
+    off64_t     mDirectoryOffset;
+
+    /*
+     * We know how many entries are in the Zip archive, so we have a
+     * fixed-size hash table.  We probe for an empty slot.
+     */
+    int         mHashTableSize;
+    HashEntry*  mHashTable;
+};
+
+}; // namespace android
+
+#endif /*__LIBS_ZIPFILERO_H*/
diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h
new file mode 100644
index 0000000..42c42b6
--- /dev/null
+++ b/include/androidfw/ZipUtils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Miscellaneous zip/gzip utility functions.
+//
+#ifndef __LIBS_ZIPUTILS_H
+#define __LIBS_ZIPUTILS_H
+
+#include <stdio.h>
+
+namespace android {
+
+/*
+ * Container class for utility functions, primarily for namespace reasons.
+ */
+class ZipUtils {
+public:
+    /*
+     * General utility function for uncompressing "deflate" data from a file
+     * to a buffer.
+     */
+    static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
+        long compressedLen);
+    static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
+        long compressedLen);
+
+    /*
+     * Someday we might want to make this generic and handle bzip2 ".bz2"
+     * files too.
+     *
+     * We could declare gzip to be a sub-class of zip that has exactly
+     * one always-compressed entry, but we currently want to treat Zip
+     * and gzip as distinct, so there's no value.
+     *
+     * The zlib library has some gzip utilities, but it has no interface
+     * for extracting the uncompressed length of the file (you do *not*
+     * want to gzseek to the end).
+     *
+     * Pass in a seeked file pointer for the gzip file.  If this is a gzip
+     * file, we set our return values appropriately and return "true" with
+     * the file seeked to the start of the compressed data.
+     */
+    static bool examineGzip(FILE* fp, int* pCompressionMethod,
+        long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32);
+
+private:
+    ZipUtils() {}
+    ~ZipUtils() {}
+};
+
+}; // namespace android
+
+#endif /*__LIBS_ZIPUTILS_H*/
diff --git a/include/androidfw/misc.h b/include/androidfw/misc.h
new file mode 100644
index 0000000..5a5a0e2
--- /dev/null
+++ b/include/androidfw/misc.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <sys/types.h>
+
+//
+// Handy utility functions and portability code.
+//
+#ifndef _LIBS_ANDROID_FW_MISC_H
+#define _LIBS_ANDROID_FW_MISC_H
+
+namespace android {
+
+/*
+ * Some utility functions for working with files.  These could be made
+ * part of a "File" class.
+ */
+typedef enum FileType {
+    kFileTypeUnknown = 0,
+    kFileTypeNonexistent,       // i.e. ENOENT
+    kFileTypeRegular,
+    kFileTypeDirectory,
+    kFileTypeCharDev,
+    kFileTypeBlockDev,
+    kFileTypeFifo,
+    kFileTypeSymlink,
+    kFileTypeSocket,
+} FileType;
+/* get the file's type; follows symlinks */
+FileType getFileType(const char* fileName);
+/* get the file's modification date; returns -1 w/errno set on failure */
+time_t getFileModDate(const char* fileName);
+
+}; // namespace android
+
+#endif // _LIBS_ANDROID_FW_MISC_H
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index c9700d7..8ad973d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -445,7 +445,10 @@
             }
             @Override public void onServiceDisconnected(ComponentName name) {}
         };
-        boolean isBound = context.bindService(new Intent(IKeyChainService.class.getName()),
+        Intent intent = new Intent(IKeyChainService.class.getName());
+        ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
+        intent.setComponent(comp);
+        boolean isBound = context.bindService(intent,
                                               keyChainServiceConnection,
                                               Context.BIND_AUTO_CREATE);
         if (!isBound) {
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index da1abdc..21d6caa 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -233,7 +233,6 @@
     /**
      * Returns the key type (e.g., "RSA", "DSA", "EC") specified by this
      * parameter.
-     * @hide
      */
     public String getKeyType() {
         return mKeyType;
@@ -243,7 +242,6 @@
      * Returns the key size specified by this parameter. For instance, for RSA
      * this will return the modulus size and for EC it will return the field
      * size.
-     * @hide
      */
     public int getKeySize() {
         return mKeySize;
@@ -252,7 +250,6 @@
     /**
      * Returns the {@link AlgorithmParameterSpec} that will be used for creation
      * of the key pair.
-     * @hide
      */
     public AlgorithmParameterSpec getAlgorithmParameterSpec() {
         return mSpec;
@@ -375,7 +372,6 @@
 
         /**
          * Sets the key type (e.g., RSA, DSA, EC) of the keypair to be created.
-         * @hide
          */
         public Builder setKeyType(String keyType) throws NoSuchAlgorithmException {
             if (keyType == null) {
@@ -395,7 +391,6 @@
          * Sets the key size for the keypair to be created. For instance, for a
          * key type of RSA this will set the modulus size and for a key type of
          * EC it will select a curve with a matching field size.
-         * @hide
          */
         public Builder setKeySize(int keySize) {
             if (keySize < 0) {
@@ -409,7 +404,6 @@
          * Sets the underlying key type's parameters. This is required for DSA
          * where you must set this to an instance of
          * {@link java.security.spec.DSAParameterSpec}.
-         * @hide
          */
         public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) {
             if (spec == null) {
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 3ed75a2..d80612b 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -14,47 +14,47 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# libandroidfw is partially built for the host (used by build time keymap validation tool)
+# libandroidfw is partially built for the host (used by obbtool and others)
 # These files are common to host and target builds.
 
-# formerly in libutils
-commonUtilsSources:= \
+commonSources := \
     Asset.cpp \
     AssetDir.cpp \
     AssetManager.cpp \
+    misc.cpp \
     ObbFile.cpp \
     ResourceTypes.cpp \
-    StreamingZipInflater.cpp
+    StreamingZipInflater.cpp \
+    ZipFileRO.cpp \
+    ZipUtils.cpp
 
-# formerly in libui
-commonUiSources:= \
-    Input.cpp \
-    InputDevice.cpp \
-    Keyboard.cpp \
-    KeyCharacterMap.cpp \
-    KeyLayoutMap.cpp \
-    VelocityControl.cpp \
-    VelocityTracker.cpp \
-    VirtualKeyMap.cpp
+deviceSources := \
+    $(commonSources) \
+    BackupData.cpp \
+    BackupHelpers.cpp \
+    CursorWindow.cpp
 
-commonSources:= \
-	$(commonUtilsSources) \
-	$(commonUiSources)
+hostSources := \
+    $(commonSources)
 
 # For the host
 # =====================================================
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= $(commonSources)
+LOCAL_SRC_FILES:= $(hostSources)
 
 LOCAL_MODULE:= libandroidfw
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
+
 LOCAL_C_INCLUDES := \
 	external/zlib
 
+LOCAL_STATIC_LIBRARIES := liblog
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -63,23 +63,16 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
-	$(commonSources) \
-	BackupData.cpp \
-	BackupHelpers.cpp \
-    CursorWindow.cpp \
-	InputTransport.cpp
+LOCAL_SRC_FILES:= $(deviceSources)
 
 LOCAL_SHARED_LIBRARIES := \
+	libbinder \
 	liblog \
 	libcutils \
 	libutils \
-	libbinder \
-	libskia \
 	libz
 
 LOCAL_C_INCLUDES := \
-    external/skia/include/core \
     external/icu4c/common \
 	external/zlib
 
@@ -90,20 +83,6 @@
 include $(BUILD_SHARED_LIBRARY)
 
 
-ifeq ($(TARGET_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += \
-	external/skia/include/core \
-	external/zlib \
-	external/icu4c/common \
-	bionic/libc/private
-LOCAL_LDLIBS := -lrt -ldl -lpthread
-LOCAL_MODULE := libandroidfw
-LOCAL_SRC_FILES := $(commonUtilsSources) BackupData.cpp BackupHelpers.cpp
-include $(BUILD_STATIC_LIBRARY)
-endif
-
-
 # Include subdirectory makefiles
 # ============================================================
 
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index fd5b3e4..cb7628d 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -23,11 +23,11 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/StreamingZipInflater.h>
+#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
 #include <utils/Atomic.h>
 #include <utils/FileMap.h>
 #include <utils/Log.h>
-#include <utils/ZipFileRO.h>
-#include <utils/ZipUtils.h>
 #include <utils/threads.h>
 
 #include <assert.h>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index b08c36b..6667daf 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -25,14 +25,15 @@
 #include <androidfw/Asset.h>
 #include <androidfw/AssetDir.h>
 #include <androidfw/AssetManager.h>
+#include <androidfw/misc.h>
 #include <androidfw/ResourceTypes.h>
+#include <androidfw/ZipFileRO.h>
 #include <utils/Atomic.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
-#include <utils/ZipFileRO.h>
 #ifdef HAVE_ANDROID_OS
 #include <cutils/trace.h>
 #endif
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 047a4c8..0f54edb 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -17,8 +17,9 @@
 #undef LOG_TAG
 #define LOG_TAG "CursorWindow"
 
-#include <utils/Log.h>
 #include <androidfw/CursorWindow.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
 
 #include <cutils/ashmem.h>
 #include <sys/mman.h>
diff --git a/libs/androidfw/Input.cpp b/libs/androidfw/Input.cpp
deleted file mode 100644
index eca692a..0000000
--- a/libs/androidfw/Input.cpp
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "Input"
-//#define LOG_NDEBUG 0
-
-#include <math.h>
-#include <limits.h>
-
-#include <androidfw/Input.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <binder/Parcel.h>
-
-#include "SkPoint.h"
-#include "SkMatrix.h"
-#include "SkScalar.h"
-#endif
-
-namespace android {
-
-// --- InputEvent ---
-
-void InputEvent::initialize(int32_t deviceId, int32_t source) {
-    mDeviceId = deviceId;
-    mSource = source;
-}
-
-void InputEvent::initialize(const InputEvent& from) {
-    mDeviceId = from.mDeviceId;
-    mSource = from.mSource;
-}
-
-// --- KeyEvent ---
-
-bool KeyEvent::hasDefaultAction(int32_t keyCode) {
-    switch (keyCode) {
-        case AKEYCODE_HOME:
-        case AKEYCODE_BACK:
-        case AKEYCODE_CALL:
-        case AKEYCODE_ENDCALL:
-        case AKEYCODE_VOLUME_UP:
-        case AKEYCODE_VOLUME_DOWN:
-        case AKEYCODE_VOLUME_MUTE:
-        case AKEYCODE_POWER:
-        case AKEYCODE_CAMERA:
-        case AKEYCODE_HEADSETHOOK:
-        case AKEYCODE_MENU:
-        case AKEYCODE_NOTIFICATION:
-        case AKEYCODE_FOCUS:
-        case AKEYCODE_SEARCH:
-        case AKEYCODE_MEDIA_PLAY:
-        case AKEYCODE_MEDIA_PAUSE:
-        case AKEYCODE_MEDIA_PLAY_PAUSE:
-        case AKEYCODE_MEDIA_STOP:
-        case AKEYCODE_MEDIA_NEXT:
-        case AKEYCODE_MEDIA_PREVIOUS:
-        case AKEYCODE_MEDIA_REWIND:
-        case AKEYCODE_MEDIA_RECORD:
-        case AKEYCODE_MEDIA_FAST_FORWARD:
-        case AKEYCODE_MUTE:
-        case AKEYCODE_BRIGHTNESS_DOWN:
-        case AKEYCODE_BRIGHTNESS_UP:
-            return true;
-    }
-    
-    return false;
-}
-
-bool KeyEvent::hasDefaultAction() const {
-    return hasDefaultAction(getKeyCode());
-}
-
-bool KeyEvent::isSystemKey(int32_t keyCode) {
-    switch (keyCode) {
-        case AKEYCODE_MENU:
-        case AKEYCODE_SOFT_RIGHT:
-        case AKEYCODE_HOME:
-        case AKEYCODE_BACK:
-        case AKEYCODE_CALL:
-        case AKEYCODE_ENDCALL:
-        case AKEYCODE_VOLUME_UP:
-        case AKEYCODE_VOLUME_DOWN:
-        case AKEYCODE_VOLUME_MUTE:
-        case AKEYCODE_MUTE:
-        case AKEYCODE_POWER:
-        case AKEYCODE_HEADSETHOOK:
-        case AKEYCODE_MEDIA_PLAY:
-        case AKEYCODE_MEDIA_PAUSE:
-        case AKEYCODE_MEDIA_PLAY_PAUSE:
-        case AKEYCODE_MEDIA_STOP:
-        case AKEYCODE_MEDIA_NEXT:
-        case AKEYCODE_MEDIA_PREVIOUS:
-        case AKEYCODE_MEDIA_REWIND:
-        case AKEYCODE_MEDIA_RECORD:
-        case AKEYCODE_MEDIA_FAST_FORWARD:
-        case AKEYCODE_CAMERA:
-        case AKEYCODE_FOCUS:
-        case AKEYCODE_SEARCH:
-        case AKEYCODE_BRIGHTNESS_DOWN:
-        case AKEYCODE_BRIGHTNESS_UP:
-            return true;
-    }
-    
-    return false;
-}
-
-bool KeyEvent::isSystemKey() const {
-    return isSystemKey(getKeyCode());
-}
-
-void KeyEvent::initialize(
-        int32_t deviceId,
-        int32_t source,
-        int32_t action,
-        int32_t flags,
-        int32_t keyCode,
-        int32_t scanCode,
-        int32_t metaState,
-        int32_t repeatCount,
-        nsecs_t downTime,
-        nsecs_t eventTime) {
-    InputEvent::initialize(deviceId, source);
-    mAction = action;
-    mFlags = flags;
-    mKeyCode = keyCode;
-    mScanCode = scanCode;
-    mMetaState = metaState;
-    mRepeatCount = repeatCount;
-    mDownTime = downTime;
-    mEventTime = eventTime;
-}
-
-void KeyEvent::initialize(const KeyEvent& from) {
-    InputEvent::initialize(from);
-    mAction = from.mAction;
-    mFlags = from.mFlags;
-    mKeyCode = from.mKeyCode;
-    mScanCode = from.mScanCode;
-    mMetaState = from.mMetaState;
-    mRepeatCount = from.mRepeatCount;
-    mDownTime = from.mDownTime;
-    mEventTime = from.mEventTime;
-}
-
-
-// --- PointerCoords ---
-
-float PointerCoords::getAxisValue(int32_t axis) const {
-    if (axis < 0 || axis > 63) {
-        return 0;
-    }
-
-    uint64_t axisBit = 1LL << axis;
-    if (!(bits & axisBit)) {
-        return 0;
-    }
-    uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
-    return values[index];
-}
-
-status_t PointerCoords::setAxisValue(int32_t axis, float value) {
-    if (axis < 0 || axis > 63) {
-        return NAME_NOT_FOUND;
-    }
-
-    uint64_t axisBit = 1LL << axis;
-    uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
-    if (!(bits & axisBit)) {
-        if (value == 0) {
-            return OK; // axes with value 0 do not need to be stored
-        }
-        uint32_t count = __builtin_popcountll(bits);
-        if (count >= MAX_AXES) {
-            tooManyAxes(axis);
-            return NO_MEMORY;
-        }
-        bits |= axisBit;
-        for (uint32_t i = count; i > index; i--) {
-            values[i] = values[i - 1];
-        }
-    }
-    values[index] = value;
-    return OK;
-}
-
-static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
-    float value = c.getAxisValue(axis);
-    if (value != 0) {
-        c.setAxisValue(axis, value * scaleFactor);
-    }
-}
-
-void PointerCoords::scale(float scaleFactor) {
-    // No need to scale pressure or size since they are normalized.
-    // No need to scale orientation since it is meaningless to do so.
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
-}
-
-#ifdef HAVE_ANDROID_OS
-status_t PointerCoords::readFromParcel(Parcel* parcel) {
-    bits = parcel->readInt64();
-
-    uint32_t count = __builtin_popcountll(bits);
-    if (count > MAX_AXES) {
-        return BAD_VALUE;
-    }
-
-    for (uint32_t i = 0; i < count; i++) {
-        values[i] = parcel->readFloat();
-    }
-    return OK;
-}
-
-status_t PointerCoords::writeToParcel(Parcel* parcel) const {
-    parcel->writeInt64(bits);
-
-    uint32_t count = __builtin_popcountll(bits);
-    for (uint32_t i = 0; i < count; i++) {
-        parcel->writeFloat(values[i]);
-    }
-    return OK;
-}
-#endif
-
-void PointerCoords::tooManyAxes(int axis) {
-    ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
-            "cannot contain more than %d axis values.", axis, int(MAX_AXES));
-}
-
-bool PointerCoords::operator==(const PointerCoords& other) const {
-    if (bits != other.bits) {
-        return false;
-    }
-    uint32_t count = __builtin_popcountll(bits);
-    for (uint32_t i = 0; i < count; i++) {
-        if (values[i] != other.values[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void PointerCoords::copyFrom(const PointerCoords& other) {
-    bits = other.bits;
-    uint32_t count = __builtin_popcountll(bits);
-    for (uint32_t i = 0; i < count; i++) {
-        values[i] = other.values[i];
-    }
-}
-
-
-// --- PointerProperties ---
-
-bool PointerProperties::operator==(const PointerProperties& other) const {
-    return id == other.id
-            && toolType == other.toolType;
-}
-
-void PointerProperties::copyFrom(const PointerProperties& other) {
-    id = other.id;
-    toolType = other.toolType;
-}
-
-
-// --- MotionEvent ---
-
-void MotionEvent::initialize(
-        int32_t deviceId,
-        int32_t source,
-        int32_t action,
-        int32_t flags,
-        int32_t edgeFlags,
-        int32_t metaState,
-        int32_t buttonState,
-        float xOffset,
-        float yOffset,
-        float xPrecision,
-        float yPrecision,
-        nsecs_t downTime,
-        nsecs_t eventTime,
-        size_t pointerCount,
-        const PointerProperties* pointerProperties,
-        const PointerCoords* pointerCoords) {
-    InputEvent::initialize(deviceId, source);
-    mAction = action;
-    mFlags = flags;
-    mEdgeFlags = edgeFlags;
-    mMetaState = metaState;
-    mButtonState = buttonState;
-    mXOffset = xOffset;
-    mYOffset = yOffset;
-    mXPrecision = xPrecision;
-    mYPrecision = yPrecision;
-    mDownTime = downTime;
-    mPointerProperties.clear();
-    mPointerProperties.appendArray(pointerProperties, pointerCount);
-    mSampleEventTimes.clear();
-    mSamplePointerCoords.clear();
-    addSample(eventTime, pointerCoords);
-}
-
-void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
-    InputEvent::initialize(other->mDeviceId, other->mSource);
-    mAction = other->mAction;
-    mFlags = other->mFlags;
-    mEdgeFlags = other->mEdgeFlags;
-    mMetaState = other->mMetaState;
-    mButtonState = other->mButtonState;
-    mXOffset = other->mXOffset;
-    mYOffset = other->mYOffset;
-    mXPrecision = other->mXPrecision;
-    mYPrecision = other->mYPrecision;
-    mDownTime = other->mDownTime;
-    mPointerProperties = other->mPointerProperties;
-
-    if (keepHistory) {
-        mSampleEventTimes = other->mSampleEventTimes;
-        mSamplePointerCoords = other->mSamplePointerCoords;
-    } else {
-        mSampleEventTimes.clear();
-        mSampleEventTimes.push(other->getEventTime());
-        mSamplePointerCoords.clear();
-        size_t pointerCount = other->getPointerCount();
-        size_t historySize = other->getHistorySize();
-        mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
-                + (historySize * pointerCount), pointerCount);
-    }
-}
-
-void MotionEvent::addSample(
-        int64_t eventTime,
-        const PointerCoords* pointerCoords) {
-    mSampleEventTimes.push(eventTime);
-    mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
-}
-
-const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
-    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
-}
-
-float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
-    return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
-}
-
-float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
-    float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
-    switch (axis) {
-    case AMOTION_EVENT_AXIS_X:
-        return value + mXOffset;
-    case AMOTION_EVENT_AXIS_Y:
-        return value + mYOffset;
-    }
-    return value;
-}
-
-const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
-        size_t pointerIndex, size_t historicalIndex) const {
-    return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
-}
-
-float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
-        size_t historicalIndex) const {
-    return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
-}
-
-float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
-        size_t historicalIndex) const {
-    float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
-    switch (axis) {
-    case AMOTION_EVENT_AXIS_X:
-        return value + mXOffset;
-    case AMOTION_EVENT_AXIS_Y:
-        return value + mYOffset;
-    }
-    return value;
-}
-
-ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
-    size_t pointerCount = mPointerProperties.size();
-    for (size_t i = 0; i < pointerCount; i++) {
-        if (mPointerProperties.itemAt(i).id == pointerId) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-void MotionEvent::offsetLocation(float xOffset, float yOffset) {
-    mXOffset += xOffset;
-    mYOffset += yOffset;
-}
-
-void MotionEvent::scale(float scaleFactor) {
-    mXOffset *= scaleFactor;
-    mYOffset *= scaleFactor;
-    mXPrecision *= scaleFactor;
-    mYPrecision *= scaleFactor;
-
-    size_t numSamples = mSamplePointerCoords.size();
-    for (size_t i = 0; i < numSamples; i++) {
-        mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
-    }
-}
-
-#ifdef HAVE_ANDROID_OS
-static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
-    // Construct and transform a vector oriented at the specified clockwise angle from vertical.
-    // Coordinate system: down is increasing Y, right is increasing X.
-    SkPoint vector;
-    vector.fX = SkFloatToScalar(sinf(angleRadians));
-    vector.fY = SkFloatToScalar(-cosf(angleRadians));
-    matrix->mapVectors(& vector, 1);
-
-    // Derive the transformed vector's clockwise angle from vertical.
-    float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
-    if (result < - M_PI_2) {
-        result += M_PI;
-    } else if (result > M_PI_2) {
-        result -= M_PI;
-    }
-    return result;
-}
-
-void MotionEvent::transform(const SkMatrix* matrix) {
-    float oldXOffset = mXOffset;
-    float oldYOffset = mYOffset;
-
-    // The tricky part of this implementation is to preserve the value of
-    // rawX and rawY.  So we apply the transformation to the first point
-    // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
-    SkPoint point;
-    float rawX = getRawX(0);
-    float rawY = getRawY(0);
-    matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
-            & point);
-    float newX = SkScalarToFloat(point.fX);
-    float newY = SkScalarToFloat(point.fY);
-    float newXOffset = newX - rawX;
-    float newYOffset = newY - rawY;
-
-    mXOffset = newXOffset;
-    mYOffset = newYOffset;
-
-    // Apply the transformation to all samples.
-    size_t numSamples = mSamplePointerCoords.size();
-    for (size_t i = 0; i < numSamples; i++) {
-        PointerCoords& c = mSamplePointerCoords.editItemAt(i);
-        float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
-        float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
-        matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
-        c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
-        c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
-
-        float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
-        c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
-    }
-}
-
-status_t MotionEvent::readFromParcel(Parcel* parcel) {
-    size_t pointerCount = parcel->readInt32();
-    size_t sampleCount = parcel->readInt32();
-    if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
-        return BAD_VALUE;
-    }
-
-    mDeviceId = parcel->readInt32();
-    mSource = parcel->readInt32();
-    mAction = parcel->readInt32();
-    mFlags = parcel->readInt32();
-    mEdgeFlags = parcel->readInt32();
-    mMetaState = parcel->readInt32();
-    mButtonState = parcel->readInt32();
-    mXOffset = parcel->readFloat();
-    mYOffset = parcel->readFloat();
-    mXPrecision = parcel->readFloat();
-    mYPrecision = parcel->readFloat();
-    mDownTime = parcel->readInt64();
-
-    mPointerProperties.clear();
-    mPointerProperties.setCapacity(pointerCount);
-    mSampleEventTimes.clear();
-    mSampleEventTimes.setCapacity(sampleCount);
-    mSamplePointerCoords.clear();
-    mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
-
-    for (size_t i = 0; i < pointerCount; i++) {
-        mPointerProperties.push();
-        PointerProperties& properties = mPointerProperties.editTop();
-        properties.id = parcel->readInt32();
-        properties.toolType = parcel->readInt32();
-    }
-
-    while (sampleCount-- > 0) {
-        mSampleEventTimes.push(parcel->readInt64());
-        for (size_t i = 0; i < pointerCount; i++) {
-            mSamplePointerCoords.push();
-            status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
-            if (status) {
-                return status;
-            }
-        }
-    }
-    return OK;
-}
-
-status_t MotionEvent::writeToParcel(Parcel* parcel) const {
-    size_t pointerCount = mPointerProperties.size();
-    size_t sampleCount = mSampleEventTimes.size();
-
-    parcel->writeInt32(pointerCount);
-    parcel->writeInt32(sampleCount);
-
-    parcel->writeInt32(mDeviceId);
-    parcel->writeInt32(mSource);
-    parcel->writeInt32(mAction);
-    parcel->writeInt32(mFlags);
-    parcel->writeInt32(mEdgeFlags);
-    parcel->writeInt32(mMetaState);
-    parcel->writeInt32(mButtonState);
-    parcel->writeFloat(mXOffset);
-    parcel->writeFloat(mYOffset);
-    parcel->writeFloat(mXPrecision);
-    parcel->writeFloat(mYPrecision);
-    parcel->writeInt64(mDownTime);
-
-    for (size_t i = 0; i < pointerCount; i++) {
-        const PointerProperties& properties = mPointerProperties.itemAt(i);
-        parcel->writeInt32(properties.id);
-        parcel->writeInt32(properties.toolType);
-    }
-
-    const PointerCoords* pc = mSamplePointerCoords.array();
-    for (size_t h = 0; h < sampleCount; h++) {
-        parcel->writeInt64(mSampleEventTimes.itemAt(h));
-        for (size_t i = 0; i < pointerCount; i++) {
-            status_t status = (pc++)->writeToParcel(parcel);
-            if (status) {
-                return status;
-            }
-        }
-    }
-    return OK;
-}
-#endif
-
-bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
-    if (source & AINPUT_SOURCE_CLASS_POINTER) {
-        // Specifically excludes HOVER_MOVE and SCROLL.
-        switch (action & AMOTION_EVENT_ACTION_MASK) {
-        case AMOTION_EVENT_ACTION_DOWN:
-        case AMOTION_EVENT_ACTION_MOVE:
-        case AMOTION_EVENT_ACTION_UP:
-        case AMOTION_EVENT_ACTION_POINTER_DOWN:
-        case AMOTION_EVENT_ACTION_POINTER_UP:
-        case AMOTION_EVENT_ACTION_CANCEL:
-        case AMOTION_EVENT_ACTION_OUTSIDE:
-            return true;
-        }
-    }
-    return false;
-}
-
-
-// --- PooledInputEventFactory ---
-
-PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
-        mMaxPoolSize(maxPoolSize) {
-}
-
-PooledInputEventFactory::~PooledInputEventFactory() {
-    for (size_t i = 0; i < mKeyEventPool.size(); i++) {
-        delete mKeyEventPool.itemAt(i);
-    }
-    for (size_t i = 0; i < mMotionEventPool.size(); i++) {
-        delete mMotionEventPool.itemAt(i);
-    }
-}
-
-KeyEvent* PooledInputEventFactory::createKeyEvent() {
-    if (!mKeyEventPool.isEmpty()) {
-        KeyEvent* event = mKeyEventPool.top();
-        mKeyEventPool.pop();
-        return event;
-    }
-    return new KeyEvent();
-}
-
-MotionEvent* PooledInputEventFactory::createMotionEvent() {
-    if (!mMotionEventPool.isEmpty()) {
-        MotionEvent* event = mMotionEventPool.top();
-        mMotionEventPool.pop();
-        return event;
-    }
-    return new MotionEvent();
-}
-
-void PooledInputEventFactory::recycle(InputEvent* event) {
-    switch (event->getType()) {
-    case AINPUT_EVENT_TYPE_KEY:
-        if (mKeyEventPool.size() < mMaxPoolSize) {
-            mKeyEventPool.push(static_cast<KeyEvent*>(event));
-            return;
-        }
-        break;
-    case AINPUT_EVENT_TYPE_MOTION:
-        if (mMotionEventPool.size() < mMaxPoolSize) {
-            mMotionEventPool.push(static_cast<MotionEvent*>(event));
-            return;
-        }
-        break;
-    }
-    delete event;
-}
-
-} // namespace android
diff --git a/libs/androidfw/InputDevice.cpp b/libs/androidfw/InputDevice.cpp
deleted file mode 100644
index f742052..0000000
--- a/libs/androidfw/InputDevice.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "InputDevice"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <androidfw/InputDevice.h>
-
-namespace android {
-
-static const char* CONFIGURATION_FILE_DIR[] = {
-        "idc/",
-        "keylayout/",
-        "keychars/",
-};
-
-static const char* CONFIGURATION_FILE_EXTENSION[] = {
-        ".idc",
-        ".kl",
-        ".kcm",
-};
-
-static bool isValidNameChar(char ch) {
-    return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
-}
-
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
-        const String8& name, InputDeviceConfigurationFileType type) {
-    path.append(CONFIGURATION_FILE_DIR[type]);
-    for (size_t i = 0; i < name.length(); i++) {
-        char ch = name[i];
-        if (!isValidNameChar(ch)) {
-            ch = '_';
-        }
-        path.append(&ch, 1);
-    }
-    path.append(CONFIGURATION_FILE_EXTENSION[type]);
-}
-
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
-        const InputDeviceIdentifier& deviceIdentifier,
-        InputDeviceConfigurationFileType type) {
-    if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
-        if (deviceIdentifier.version != 0) {
-            // Try vendor product version.
-            String8 versionPath(getInputDeviceConfigurationFilePathByName(
-                    String8::format("Vendor_%04x_Product_%04x_Version_%04x",
-                            deviceIdentifier.vendor, deviceIdentifier.product,
-                            deviceIdentifier.version),
-                    type));
-            if (!versionPath.isEmpty()) {
-                return versionPath;
-            }
-        }
-
-        // Try vendor product.
-        String8 productPath(getInputDeviceConfigurationFilePathByName(
-                String8::format("Vendor_%04x_Product_%04x",
-                        deviceIdentifier.vendor, deviceIdentifier.product),
-                type));
-        if (!productPath.isEmpty()) {
-            return productPath;
-        }
-    }
-
-    // Try device name.
-    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
-}
-
-String8 getInputDeviceConfigurationFilePathByName(
-        const String8& name, InputDeviceConfigurationFileType type) {
-    // Search system repository.
-    String8 path;
-    path.setTo(getenv("ANDROID_ROOT"));
-    path.append("/usr/");
-    appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
-    ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
-#endif
-    if (!access(path.string(), R_OK)) {
-#if DEBUG_PROBE
-        ALOGD("Found");
-#endif
-        return path;
-    }
-
-    // Search user repository.
-    // TODO Should only look here if not in safe mode.
-    path.setTo(getenv("ANDROID_DATA"));
-    path.append("/system/devices/");
-    appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
-    ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
-#endif
-    if (!access(path.string(), R_OK)) {
-#if DEBUG_PROBE
-        ALOGD("Found");
-#endif
-        return path;
-    }
-
-    // Not found.
-#if DEBUG_PROBE
-    ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
-            name.string(), type);
-#endif
-    return String8();
-}
-
-
-// --- InputDeviceInfo ---
-
-InputDeviceInfo::InputDeviceInfo() {
-    initialize(-1, -1, InputDeviceIdentifier(), String8(), false);
-}
-
-InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
-        mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier),
-        mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources),
-        mKeyboardType(other.mKeyboardType),
-        mKeyCharacterMap(other.mKeyCharacterMap),
-        mHasVibrator(other.mHasVibrator),
-        mMotionRanges(other.mMotionRanges) {
-}
-
-InputDeviceInfo::~InputDeviceInfo() {
-}
-
-void InputDeviceInfo::initialize(int32_t id, int32_t generation,
-        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
-    mId = id;
-    mGeneration = generation;
-    mIdentifier = identifier;
-    mAlias = alias;
-    mIsExternal = isExternal;
-    mSources = 0;
-    mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
-    mHasVibrator = false;
-    mMotionRanges.clear();
-}
-
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
-        int32_t axis, uint32_t source) const {
-    size_t numRanges = mMotionRanges.size();
-    for (size_t i = 0; i < numRanges; i++) {
-        const MotionRange& range = mMotionRanges.itemAt(i);
-        if (range.axis == axis && range.source == source) {
-            return &range;
-        }
-    }
-    return NULL;
-}
-
-void InputDeviceInfo::addSource(uint32_t source) {
-    mSources |= source;
-}
-
-void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
-        float flat, float fuzz, float resolution) {
-    MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
-    mMotionRanges.add(range);
-}
-
-void InputDeviceInfo::addMotionRange(const MotionRange& range) {
-    mMotionRanges.add(range);
-}
-
-} // namespace android
diff --git a/libs/androidfw/InputTransport.cpp b/libs/androidfw/InputTransport.cpp
deleted file mode 100644
index 498389ea..0000000
--- a/libs/androidfw/InputTransport.cpp
+++ /dev/null
@@ -1,957 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// Provides a shared memory transport for input events.
-//
-#define LOG_TAG "InputTransport"
-
-//#define LOG_NDEBUG 0
-
-// Log debug messages about channel messages (send message, receive message)
-#define DEBUG_CHANNEL_MESSAGES 0
-
-// Log debug messages whenever InputChannel objects are created/destroyed
-#define DEBUG_CHANNEL_LIFECYCLE 0
-
-// Log debug messages about transport actions
-#define DEBUG_TRANSPORT_ACTIONS 0
-
-// Log debug messages about touch event resampling
-#define DEBUG_RESAMPLING 0
-
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <androidfw/InputTransport.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <math.h>
-
-
-namespace android {
-
-// Socket buffer size.  The default is typically about 128KB, which is much larger than
-// we really need.  So we make it smaller.  It just needs to be big enough to hold
-// a few dozen large multi-finger motion events in the case where an application gets
-// behind processing touches.
-static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
-
-// Nanoseconds per milliseconds.
-static const nsecs_t NANOS_PER_MS = 1000000;
-
-// Latency added during resampling.  A few milliseconds doesn't hurt much but
-// reduces the impact of mispredicted touch positions.
-static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS;
-
-// Minimum time difference between consecutive samples before attempting to resample.
-static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;
-
-// Maximum time to predict forward from the last known state, to avoid predicting too
-// far into the future.  This time is further bounded by 50% of the last time delta.
-static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
-
-template<typename T>
-inline static T min(const T& a, const T& b) {
-    return a < b ? a : b;
-}
-
-inline static float lerp(float a, float b, float alpha) {
-    return a + alpha * (b - a);
-}
-
-// --- InputMessage ---
-
-bool InputMessage::isValid(size_t actualSize) const {
-    if (size() == actualSize) {
-        switch (header.type) {
-        case TYPE_KEY:
-            return true;
-        case TYPE_MOTION:
-            return body.motion.pointerCount > 0
-                    && body.motion.pointerCount <= MAX_POINTERS;
-        case TYPE_FINISHED:
-            return true;
-        }
-    }
-    return false;
-}
-
-size_t InputMessage::size() const {
-    switch (header.type) {
-    case TYPE_KEY:
-        return sizeof(Header) + body.key.size();
-    case TYPE_MOTION:
-        return sizeof(Header) + body.motion.size();
-    case TYPE_FINISHED:
-        return sizeof(Header) + body.finished.size();
-    }
-    return sizeof(Header);
-}
-
-
-// --- InputChannel ---
-
-InputChannel::InputChannel(const String8& name, int fd) :
-        mName(name), mFd(fd) {
-#if DEBUG_CHANNEL_LIFECYCLE
-    ALOGD("Input channel constructed: name='%s', fd=%d",
-            mName.string(), fd);
-#endif
-
-    int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
-            "non-blocking.  errno=%d", mName.string(), errno);
-}
-
-InputChannel::~InputChannel() {
-#if DEBUG_CHANNEL_LIFECYCLE
-    ALOGD("Input channel destroyed: name='%s', fd=%d",
-            mName.string(), mFd);
-#endif
-
-    ::close(mFd);
-}
-
-status_t InputChannel::openInputChannelPair(const String8& name,
-        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
-    int sockets[2];
-    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
-        status_t result = -errno;
-        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
-                name.string(), errno);
-        outServerChannel.clear();
-        outClientChannel.clear();
-        return result;
-    }
-
-    int bufferSize = SOCKET_BUFFER_SIZE;
-    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
-    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
-    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
-    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
-
-    String8 serverChannelName = name;
-    serverChannelName.append(" (server)");
-    outServerChannel = new InputChannel(serverChannelName, sockets[0]);
-
-    String8 clientChannelName = name;
-    clientChannelName.append(" (client)");
-    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
-    return OK;
-}
-
-status_t InputChannel::sendMessage(const InputMessage* msg) {
-    size_t msgLength = msg->size();
-    ssize_t nWrite;
-    do {
-        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
-    } while (nWrite == -1 && errno == EINTR);
-
-    if (nWrite < 0) {
-        int error = errno;
-#if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
-                msg->header.type, error);
-#endif
-        if (error == EAGAIN || error == EWOULDBLOCK) {
-            return WOULD_BLOCK;
-        }
-        if (error == EPIPE || error == ENOTCONN) {
-            return DEAD_OBJECT;
-        }
-        return -error;
-    }
-
-    if (size_t(nWrite) != msgLength) {
-#if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
-                mName.string(), msg->header.type);
-#endif
-        return DEAD_OBJECT;
-    }
-
-#if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
-#endif
-    return OK;
-}
-
-status_t InputChannel::receiveMessage(InputMessage* msg) {
-    ssize_t nRead;
-    do {
-        nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
-    } while (nRead == -1 && errno == EINTR);
-
-    if (nRead < 0) {
-        int error = errno;
-#if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
-#endif
-        if (error == EAGAIN || error == EWOULDBLOCK) {
-            return WOULD_BLOCK;
-        }
-        if (error == EPIPE || error == ENOTCONN) {
-            return DEAD_OBJECT;
-        }
-        return -error;
-    }
-
-    if (nRead == 0) { // check for EOF
-#if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
-#endif
-        return DEAD_OBJECT;
-    }
-
-    if (!msg->isValid(nRead)) {
-#if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ received invalid message", mName.string());
-#endif
-        return BAD_VALUE;
-    }
-
-#if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
-#endif
-    return OK;
-}
-
-sp<InputChannel> InputChannel::dup() const {
-    int fd = ::dup(getFd());
-    return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
-}
-
-
-// --- InputPublisher ---
-
-InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
-        mChannel(channel) {
-}
-
-InputPublisher::~InputPublisher() {
-}
-
-status_t InputPublisher::publishKeyEvent(
-        uint32_t seq,
-        int32_t deviceId,
-        int32_t source,
-        int32_t action,
-        int32_t flags,
-        int32_t keyCode,
-        int32_t scanCode,
-        int32_t metaState,
-        int32_t repeatCount,
-        nsecs_t downTime,
-        nsecs_t eventTime) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
-            "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
-            "downTime=%lld, eventTime=%lld",
-            mChannel->getName().string(), seq,
-            deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
-            downTime, eventTime);
-#endif
-
-    if (!seq) {
-        ALOGE("Attempted to publish a key event with sequence number 0.");
-        return BAD_VALUE;
-    }
-
-    InputMessage msg;
-    msg.header.type = InputMessage::TYPE_KEY;
-    msg.body.key.seq = seq;
-    msg.body.key.deviceId = deviceId;
-    msg.body.key.source = source;
-    msg.body.key.action = action;
-    msg.body.key.flags = flags;
-    msg.body.key.keyCode = keyCode;
-    msg.body.key.scanCode = scanCode;
-    msg.body.key.metaState = metaState;
-    msg.body.key.repeatCount = repeatCount;
-    msg.body.key.downTime = downTime;
-    msg.body.key.eventTime = eventTime;
-    return mChannel->sendMessage(&msg);
-}
-
-status_t InputPublisher::publishMotionEvent(
-        uint32_t seq,
-        int32_t deviceId,
-        int32_t source,
-        int32_t action,
-        int32_t flags,
-        int32_t edgeFlags,
-        int32_t metaState,
-        int32_t buttonState,
-        float xOffset,
-        float yOffset,
-        float xPrecision,
-        float yPrecision,
-        nsecs_t downTime,
-        nsecs_t eventTime,
-        size_t pointerCount,
-        const PointerProperties* pointerProperties,
-        const PointerCoords* pointerCoords) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
-            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
-            "xOffset=%f, yOffset=%f, "
-            "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
-            "pointerCount=%d",
-            mChannel->getName().string(), seq,
-            deviceId, source, action, flags, edgeFlags, metaState, buttonState,
-            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
-#endif
-
-    if (!seq) {
-        ALOGE("Attempted to publish a motion event with sequence number 0.");
-        return BAD_VALUE;
-    }
-
-    if (pointerCount > MAX_POINTERS || pointerCount < 1) {
-        ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
-                mChannel->getName().string(), pointerCount);
-        return BAD_VALUE;
-    }
-
-    InputMessage msg;
-    msg.header.type = InputMessage::TYPE_MOTION;
-    msg.body.motion.seq = seq;
-    msg.body.motion.deviceId = deviceId;
-    msg.body.motion.source = source;
-    msg.body.motion.action = action;
-    msg.body.motion.flags = flags;
-    msg.body.motion.edgeFlags = edgeFlags;
-    msg.body.motion.metaState = metaState;
-    msg.body.motion.buttonState = buttonState;
-    msg.body.motion.xOffset = xOffset;
-    msg.body.motion.yOffset = yOffset;
-    msg.body.motion.xPrecision = xPrecision;
-    msg.body.motion.yPrecision = yPrecision;
-    msg.body.motion.downTime = downTime;
-    msg.body.motion.eventTime = eventTime;
-    msg.body.motion.pointerCount = pointerCount;
-    for (size_t i = 0; i < pointerCount; i++) {
-        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
-        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
-    }
-    return mChannel->sendMessage(&msg);
-}
-
-status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
-            mChannel->getName().string());
-#endif
-
-    InputMessage msg;
-    status_t result = mChannel->receiveMessage(&msg);
-    if (result) {
-        *outSeq = 0;
-        *outHandled = false;
-        return result;
-    }
-    if (msg.header.type != InputMessage::TYPE_FINISHED) {
-        ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
-                mChannel->getName().string(), msg.header.type);
-        return UNKNOWN_ERROR;
-    }
-    *outSeq = msg.body.finished.seq;
-    *outHandled = msg.body.finished.handled;
-    return OK;
-}
-
-// --- InputConsumer ---
-
-InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
-        mResampleTouch(isTouchResamplingEnabled()),
-        mChannel(channel), mMsgDeferred(false) {
-}
-
-InputConsumer::~InputConsumer() {
-}
-
-bool InputConsumer::isTouchResamplingEnabled() {
-    char value[PROPERTY_VALUE_MAX];
-    int length = property_get("debug.inputconsumer.resample", value, NULL);
-    if (length > 0) {
-        if (!strcmp("0", value)) {
-            return false;
-        }
-        if (strcmp("1", value)) {
-            ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'.  "
-                    "Use '1' or '0'.");
-        }
-    }
-    return true;
-}
-
-status_t InputConsumer::consume(InputEventFactoryInterface* factory,
-        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
-            mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
-#endif
-
-    *outSeq = 0;
-    *outEvent = NULL;
-
-    // Fetch the next input message.
-    // Loop until an event can be returned or no additional events are received.
-    while (!*outEvent) {
-        if (mMsgDeferred) {
-            // mMsg contains a valid input message from the previous call to consume
-            // that has not yet been processed.
-            mMsgDeferred = false;
-        } else {
-            // Receive a fresh message.
-            status_t result = mChannel->receiveMessage(&mMsg);
-            if (result) {
-                // Consume the next batched event unless batches are being held for later.
-                if (consumeBatches || result != WOULD_BLOCK) {
-                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
-                    if (*outEvent) {
-#if DEBUG_TRANSPORT_ACTIONS
-                        ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
-                                mChannel->getName().string(), *outSeq);
-#endif
-                        break;
-                    }
-                }
-                return result;
-            }
-        }
-
-        switch (mMsg.header.type) {
-        case InputMessage::TYPE_KEY: {
-            KeyEvent* keyEvent = factory->createKeyEvent();
-            if (!keyEvent) return NO_MEMORY;
-
-            initializeKeyEvent(keyEvent, &mMsg);
-            *outSeq = mMsg.body.key.seq;
-            *outEvent = keyEvent;
-#if DEBUG_TRANSPORT_ACTIONS
-            ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
-#endif
-            break;
-        }
-
-        case AINPUT_EVENT_TYPE_MOTION: {
-            ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
-            if (batchIndex >= 0) {
-                Batch& batch = mBatches.editItemAt(batchIndex);
-                if (canAddSample(batch, &mMsg)) {
-                    batch.samples.push(mMsg);
-#if DEBUG_TRANSPORT_ACTIONS
-                    ALOGD("channel '%s' consumer ~ appended to batch event",
-                            mChannel->getName().string());
-#endif
-                    break;
-                } else {
-                    // We cannot append to the batch in progress, so we need to consume
-                    // the previous batch right now and defer the new message until later.
-                    mMsgDeferred = true;
-                    status_t result = consumeSamples(factory,
-                            batch, batch.samples.size(), outSeq, outEvent);
-                    mBatches.removeAt(batchIndex);
-                    if (result) {
-                        return result;
-                    }
-#if DEBUG_TRANSPORT_ACTIONS
-                    ALOGD("channel '%s' consumer ~ consumed batch event and "
-                            "deferred current event, seq=%u",
-                            mChannel->getName().string(), *outSeq);
-#endif
-                    break;
-                }
-            }
-
-            // Start a new batch if needed.
-            if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
-                    || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-                mBatches.push();
-                Batch& batch = mBatches.editTop();
-                batch.samples.push(mMsg);
-#if DEBUG_TRANSPORT_ACTIONS
-                ALOGD("channel '%s' consumer ~ started batch event",
-                        mChannel->getName().string());
-#endif
-                break;
-            }
-
-            MotionEvent* motionEvent = factory->createMotionEvent();
-            if (! motionEvent) return NO_MEMORY;
-
-            updateTouchState(&mMsg);
-            initializeMotionEvent(motionEvent, &mMsg);
-            *outSeq = mMsg.body.motion.seq;
-            *outEvent = motionEvent;
-#if DEBUG_TRANSPORT_ACTIONS
-            ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
-#endif
-            break;
-        }
-
-        default:
-            ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
-                    mChannel->getName().string(), mMsg.header.type);
-            return UNKNOWN_ERROR;
-        }
-    }
-    return OK;
-}
-
-status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
-        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
-    status_t result;
-    for (size_t i = mBatches.size(); i-- > 0; ) {
-        Batch& batch = mBatches.editItemAt(i);
-        if (frameTime < 0) {
-            result = consumeSamples(factory, batch, batch.samples.size(),
-                    outSeq, outEvent);
-            mBatches.removeAt(i);
-            return result;
-        }
-
-        nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY;
-        ssize_t split = findSampleNoLaterThan(batch, sampleTime);
-        if (split < 0) {
-            continue;
-        }
-
-        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
-        const InputMessage* next;
-        if (batch.samples.isEmpty()) {
-            mBatches.removeAt(i);
-            next = NULL;
-        } else {
-            next = &batch.samples.itemAt(0);
-        }
-        if (!result) {
-            resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
-        }
-        return result;
-    }
-
-    return WOULD_BLOCK;
-}
-
-status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
-        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
-    MotionEvent* motionEvent = factory->createMotionEvent();
-    if (! motionEvent) return NO_MEMORY;
-
-    uint32_t chain = 0;
-    for (size_t i = 0; i < count; i++) {
-        InputMessage& msg = batch.samples.editItemAt(i);
-        updateTouchState(&msg);
-        if (i) {
-            SeqChain seqChain;
-            seqChain.seq = msg.body.motion.seq;
-            seqChain.chain = chain;
-            mSeqChains.push(seqChain);
-            addSample(motionEvent, &msg);
-        } else {
-            initializeMotionEvent(motionEvent, &msg);
-        }
-        chain = msg.body.motion.seq;
-    }
-    batch.samples.removeItemsAt(0, count);
-
-    *outSeq = chain;
-    *outEvent = motionEvent;
-    return OK;
-}
-
-void InputConsumer::updateTouchState(InputMessage* msg) {
-    if (!mResampleTouch ||
-            !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
-        return;
-    }
-
-    int32_t deviceId = msg->body.motion.deviceId;
-    int32_t source = msg->body.motion.source;
-    nsecs_t eventTime = msg->body.motion.eventTime;
-
-    // Update the touch state history to incorporate the new input message.
-    // If the message is in the past relative to the most recently produced resampled
-    // touch, then use the resampled time and coordinates instead.
-    switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) {
-    case AMOTION_EVENT_ACTION_DOWN: {
-        ssize_t index = findTouchState(deviceId, source);
-        if (index < 0) {
-            mTouchStates.push();
-            index = mTouchStates.size() - 1;
-        }
-        TouchState& touchState = mTouchStates.editItemAt(index);
-        touchState.initialize(deviceId, source);
-        touchState.addHistory(msg);
-        break;
-    }
-
-    case AMOTION_EVENT_ACTION_MOVE: {
-        ssize_t index = findTouchState(deviceId, source);
-        if (index >= 0) {
-            TouchState& touchState = mTouchStates.editItemAt(index);
-            touchState.addHistory(msg);
-            if (eventTime < touchState.lastResample.eventTime) {
-                rewriteMessage(touchState, msg);
-            } else {
-                touchState.lastResample.idBits.clear();
-            }
-        }
-        break;
-    }
-
-    case AMOTION_EVENT_ACTION_POINTER_DOWN: {
-        ssize_t index = findTouchState(deviceId, source);
-        if (index >= 0) {
-            TouchState& touchState = mTouchStates.editItemAt(index);
-            touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
-            rewriteMessage(touchState, msg);
-        }
-        break;
-    }
-
-    case AMOTION_EVENT_ACTION_POINTER_UP: {
-        ssize_t index = findTouchState(deviceId, source);
-        if (index >= 0) {
-            TouchState& touchState = mTouchStates.editItemAt(index);
-            rewriteMessage(touchState, msg);
-            touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
-        }
-        break;
-    }
-
-    case AMOTION_EVENT_ACTION_SCROLL: {
-        ssize_t index = findTouchState(deviceId, source);
-        if (index >= 0) {
-            const TouchState& touchState = mTouchStates.itemAt(index);
-            rewriteMessage(touchState, msg);
-        }
-        break;
-    }
-
-    case AMOTION_EVENT_ACTION_UP:
-    case AMOTION_EVENT_ACTION_CANCEL: {
-        ssize_t index = findTouchState(deviceId, source);
-        if (index >= 0) {
-            const TouchState& touchState = mTouchStates.itemAt(index);
-            rewriteMessage(touchState, msg);
-            mTouchStates.removeAt(index);
-        }
-        break;
-    }
-    }
-}
-
-void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
-    for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
-        uint32_t id = msg->body.motion.pointers[i].properties.id;
-        if (state.lastResample.idBits.hasBit(id)) {
-            PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
-            const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
-#if DEBUG_RESAMPLING
-            ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
-                    resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                    resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y),
-                    msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                    msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
-#endif
-            msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
-            msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
-        }
-    }
-}
-
-void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
-    const InputMessage* next) {
-    if (!mResampleTouch
-            || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)
-            || event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
-        return;
-    }
-
-    ssize_t index = findTouchState(event->getDeviceId(), event->getSource());
-    if (index < 0) {
-#if DEBUG_RESAMPLING
-        ALOGD("Not resampled, no touch state for device.");
-#endif
-        return;
-    }
-
-    TouchState& touchState = mTouchStates.editItemAt(index);
-    if (touchState.historySize < 1) {
-#if DEBUG_RESAMPLING
-        ALOGD("Not resampled, no history for device.");
-#endif
-        return;
-    }
-
-    // Ensure that the current sample has all of the pointers that need to be reported.
-    const History* current = touchState.getHistory(0);
-    size_t pointerCount = event->getPointerCount();
-    for (size_t i = 0; i < pointerCount; i++) {
-        uint32_t id = event->getPointerId(i);
-        if (!current->idBits.hasBit(id)) {
-#if DEBUG_RESAMPLING
-            ALOGD("Not resampled, missing id %d", id);
-#endif
-            return;
-        }
-    }
-
-    // Find the data to use for resampling.
-    const History* other;
-    History future;
-    float alpha;
-    if (next) {
-        // Interpolate between current sample and future sample.
-        // So current->eventTime <= sampleTime <= future.eventTime.
-        future.initializeFrom(next);
-        other = &future;
-        nsecs_t delta = future.eventTime - current->eventTime;
-        if (delta < RESAMPLE_MIN_DELTA) {
-#if DEBUG_RESAMPLING
-            ALOGD("Not resampled, delta time is %lld ns.", delta);
-#endif
-            return;
-        }
-        alpha = float(sampleTime - current->eventTime) / delta;
-    } else if (touchState.historySize >= 2) {
-        // Extrapolate future sample using current sample and past sample.
-        // So other->eventTime <= current->eventTime <= sampleTime.
-        other = touchState.getHistory(1);
-        nsecs_t delta = current->eventTime - other->eventTime;
-        if (delta < RESAMPLE_MIN_DELTA) {
-#if DEBUG_RESAMPLING
-            ALOGD("Not resampled, delta time is %lld ns.", delta);
-#endif
-            return;
-        }
-        nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION);
-        if (sampleTime > maxPredict) {
-#if DEBUG_RESAMPLING
-            ALOGD("Sample time is too far in the future, adjusting prediction "
-                    "from %lld to %lld ns.",
-                    sampleTime - current->eventTime, maxPredict - current->eventTime);
-#endif
-            sampleTime = maxPredict;
-        }
-        alpha = float(current->eventTime - sampleTime) / delta;
-    } else {
-#if DEBUG_RESAMPLING
-        ALOGD("Not resampled, insufficient data.");
-#endif
-        return;
-    }
-
-    // Resample touch coordinates.
-    touchState.lastResample.eventTime = sampleTime;
-    touchState.lastResample.idBits.clear();
-    for (size_t i = 0; i < pointerCount; i++) {
-        uint32_t id = event->getPointerId(i);
-        touchState.lastResample.idToIndex[id] = i;
-        touchState.lastResample.idBits.markBit(id);
-        PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
-        const PointerCoords& currentCoords = current->getPointerById(id);
-        if (other->idBits.hasBit(id)
-                && shouldResampleTool(event->getToolType(i))) {
-            const PointerCoords& otherCoords = other->getPointerById(id);
-            resampledCoords.copyFrom(currentCoords);
-            resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
-                    lerp(currentCoords.getX(), otherCoords.getX(), alpha));
-            resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
-                    lerp(currentCoords.getY(), otherCoords.getY(), alpha));
-#if DEBUG_RESAMPLING
-            ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
-                    "other (%0.3f, %0.3f), alpha %0.3f",
-                    id, resampledCoords.getX(), resampledCoords.getY(),
-                    currentCoords.getX(), currentCoords.getY(),
-                    otherCoords.getX(), otherCoords.getY(),
-                    alpha);
-#endif
-        } else {
-            resampledCoords.copyFrom(currentCoords);
-#if DEBUG_RESAMPLING
-            ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)",
-                    id, resampledCoords.getX(), resampledCoords.getY(),
-                    currentCoords.getX(), currentCoords.getY());
-#endif
-        }
-    }
-
-    event->addSample(sampleTime, touchState.lastResample.pointers);
-}
-
-bool InputConsumer::shouldResampleTool(int32_t toolType) {
-    return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
-            || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
-}
-
-status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
-            mChannel->getName().string(), seq, handled ? "true" : "false");
-#endif
-
-    if (!seq) {
-        ALOGE("Attempted to send a finished signal with sequence number 0.");
-        return BAD_VALUE;
-    }
-
-    // Send finished signals for the batch sequence chain first.
-    size_t seqChainCount = mSeqChains.size();
-    if (seqChainCount) {
-        uint32_t currentSeq = seq;
-        uint32_t chainSeqs[seqChainCount];
-        size_t chainIndex = 0;
-        for (size_t i = seqChainCount; i-- > 0; ) {
-             const SeqChain& seqChain = mSeqChains.itemAt(i);
-             if (seqChain.seq == currentSeq) {
-                 currentSeq = seqChain.chain;
-                 chainSeqs[chainIndex++] = currentSeq;
-                 mSeqChains.removeAt(i);
-             }
-        }
-        status_t status = OK;
-        while (!status && chainIndex-- > 0) {
-            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
-        }
-        if (status) {
-            // An error occurred so at least one signal was not sent, reconstruct the chain.
-            do {
-                SeqChain seqChain;
-                seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
-                seqChain.chain = chainSeqs[chainIndex];
-                mSeqChains.push(seqChain);
-            } while (chainIndex-- > 0);
-            return status;
-        }
-    }
-
-    // Send finished signal for the last message in the batch.
-    return sendUnchainedFinishedSignal(seq, handled);
-}
-
-status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
-    InputMessage msg;
-    msg.header.type = InputMessage::TYPE_FINISHED;
-    msg.body.finished.seq = seq;
-    msg.body.finished.handled = handled;
-    return mChannel->sendMessage(&msg);
-}
-
-bool InputConsumer::hasDeferredEvent() const {
-    return mMsgDeferred;
-}
-
-bool InputConsumer::hasPendingBatch() const {
-    return !mBatches.isEmpty();
-}
-
-ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
-    for (size_t i = 0; i < mBatches.size(); i++) {
-        const Batch& batch = mBatches.itemAt(i);
-        const InputMessage& head = batch.samples.itemAt(0);
-        if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
-    for (size_t i = 0; i < mTouchStates.size(); i++) {
-        const TouchState& touchState = mTouchStates.itemAt(i);
-        if (touchState.deviceId == deviceId && touchState.source == source) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
-    event->initialize(
-            msg->body.key.deviceId,
-            msg->body.key.source,
-            msg->body.key.action,
-            msg->body.key.flags,
-            msg->body.key.keyCode,
-            msg->body.key.scanCode,
-            msg->body.key.metaState,
-            msg->body.key.repeatCount,
-            msg->body.key.downTime,
-            msg->body.key.eventTime);
-}
-
-void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
-    size_t pointerCount = msg->body.motion.pointerCount;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
-        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
-    }
-
-    event->initialize(
-            msg->body.motion.deviceId,
-            msg->body.motion.source,
-            msg->body.motion.action,
-            msg->body.motion.flags,
-            msg->body.motion.edgeFlags,
-            msg->body.motion.metaState,
-            msg->body.motion.buttonState,
-            msg->body.motion.xOffset,
-            msg->body.motion.yOffset,
-            msg->body.motion.xPrecision,
-            msg->body.motion.yPrecision,
-            msg->body.motion.downTime,
-            msg->body.motion.eventTime,
-            pointerCount,
-            pointerProperties,
-            pointerCoords);
-}
-
-void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
-    size_t pointerCount = msg->body.motion.pointerCount;
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
-    }
-
-    event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
-    event->addSample(msg->body.motion.eventTime, pointerCoords);
-}
-
-bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) {
-    const InputMessage& head = batch.samples.itemAt(0);
-    size_t pointerCount = msg->body.motion.pointerCount;
-    if (head.body.motion.pointerCount != pointerCount
-            || head.body.motion.action != msg->body.motion.action) {
-        return false;
-    }
-    for (size_t i = 0; i < pointerCount; i++) {
-        if (head.body.motion.pointers[i].properties
-                != msg->body.motion.pointers[i].properties) {
-            return false;
-        }
-    }
-    return true;
-}
-
-ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) {
-    size_t numSamples = batch.samples.size();
-    size_t index = 0;
-    while (index < numSamples
-            && batch.samples.itemAt(index).body.motion.eventTime <= time) {
-        index += 1;
-    }
-    return ssize_t(index) - 1;
-}
-
-} // namespace android
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
deleted file mode 100644
index 36cb6e1..0000000
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ /dev/null
@@ -1,1153 +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.
- */
-
-#define LOG_TAG "KeyCharacterMap"
-
-#include <stdlib.h>
-#include <string.h>
-#include <android/keycodes.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeyCharacterMap.h>
-
-#if HAVE_ANDROID_OS
-#include <binder/Parcel.h>
-#endif
-
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-#include <utils/Timers.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
-
-struct Modifier {
-    const char* label;
-    int32_t metaState;
-};
-static const Modifier modifiers[] = {
-        { "shift", AMETA_SHIFT_ON },
-        { "lshift", AMETA_SHIFT_LEFT_ON },
-        { "rshift", AMETA_SHIFT_RIGHT_ON },
-        { "alt", AMETA_ALT_ON },
-        { "lalt", AMETA_ALT_LEFT_ON },
-        { "ralt", AMETA_ALT_RIGHT_ON },
-        { "ctrl", AMETA_CTRL_ON },
-        { "lctrl", AMETA_CTRL_LEFT_ON },
-        { "rctrl", AMETA_CTRL_RIGHT_ON },
-        { "meta", AMETA_META_ON },
-        { "lmeta", AMETA_META_LEFT_ON },
-        { "rmeta", AMETA_META_RIGHT_ON },
-        { "sym", AMETA_SYM_ON },
-        { "fn", AMETA_FUNCTION_ON },
-        { "capslock", AMETA_CAPS_LOCK_ON },
-        { "numlock", AMETA_NUM_LOCK_ON },
-        { "scrolllock", AMETA_SCROLL_LOCK_ON },
-};
-
-#if DEBUG_MAPPING
-static String8 toString(const char16_t* chars, size_t numChars) {
-    String8 result;
-    for (size_t i = 0; i < numChars; i++) {
-        result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
-    }
-    return result;
-}
-#endif
-
-
-// --- KeyCharacterMap ---
-
-sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
-
-KeyCharacterMap::KeyCharacterMap() :
-    mType(KEYBOARD_TYPE_UNKNOWN) {
-}
-
-KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
-    RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
-    mKeysByUsageCode(other.mKeysByUsageCode) {
-    for (size_t i = 0; i < other.mKeys.size(); i++) {
-        mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
-    }
-}
-
-KeyCharacterMap::~KeyCharacterMap() {
-    for (size_t i = 0; i < mKeys.size(); i++) {
-        Key* key = mKeys.editValueAt(i);
-        delete key;
-    }
-}
-
-status_t KeyCharacterMap::load(const String8& filename,
-        Format format, sp<KeyCharacterMap>* outMap) {
-    outMap->clear();
-
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening key character map file %s.", status, filename.string());
-    } else {
-        status = load(tokenizer, format, outMap);
-        delete tokenizer;
-    }
-    return status;
-}
-
-status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
-        Format format, sp<KeyCharacterMap>* outMap) {
-    outMap->clear();
-
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening key character map.", status);
-    } else {
-        status = load(tokenizer, format, outMap);
-        delete tokenizer;
-    }
-    return status;
-}
-
-status_t KeyCharacterMap::load(Tokenizer* tokenizer,
-        Format format, sp<KeyCharacterMap>* outMap) {
-    status_t status = OK;
-    sp<KeyCharacterMap> map = new KeyCharacterMap();
-    if (!map.get()) {
-        ALOGE("Error allocating key character map.");
-        status = NO_MEMORY;
-    } else {
-#if DEBUG_PARSER_PERFORMANCE
-        nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
-        Parser parser(map.get(), tokenizer, format);
-        status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
-        nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-        ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
-                tokenizer->getFilename().string(), tokenizer->getLineNumber(),
-                elapsedTime / 1000000.0);
-#endif
-        if (!status) {
-            *outMap = map;
-        }
-    }
-    return status;
-}
-
-sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
-        const sp<KeyCharacterMap>& overlay) {
-    if (overlay == NULL) {
-        return base;
-    }
-    if (base == NULL) {
-        return overlay;
-    }
-
-    sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get());
-    for (size_t i = 0; i < overlay->mKeys.size(); i++) {
-        int32_t keyCode = overlay->mKeys.keyAt(i);
-        Key* key = overlay->mKeys.valueAt(i);
-        ssize_t oldIndex = map->mKeys.indexOfKey(keyCode);
-        if (oldIndex >= 0) {
-            delete map->mKeys.valueAt(oldIndex);
-            map->mKeys.editValueAt(oldIndex) = new Key(*key);
-        } else {
-            map->mKeys.add(keyCode, new Key(*key));
-        }
-    }
-
-    for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
-        map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
-                overlay->mKeysByScanCode.valueAt(i));
-    }
-
-    for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
-        map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
-                overlay->mKeysByUsageCode.valueAt(i));
-    }
-    return map;
-}
-
-sp<KeyCharacterMap> KeyCharacterMap::empty() {
-    return sEmpty;
-}
-
-int32_t KeyCharacterMap::getKeyboardType() const {
-    return mType;
-}
-
-char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
-    char16_t result = 0;
-    const Key* key;
-    if (getKey(keyCode, &key)) {
-        result = key->label;
-    }
-#if DEBUG_MAPPING
-    ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
-#endif
-    return result;
-}
-
-char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
-    char16_t result = 0;
-    const Key* key;
-    if (getKey(keyCode, &key)) {
-        result = key->number;
-    }
-#if DEBUG_MAPPING
-    ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
-#endif
-    return result;
-}
-
-char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
-    char16_t result = 0;
-    const Key* key;
-    const Behavior* behavior;
-    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
-        result = behavior->character;
-    }
-#if DEBUG_MAPPING
-    ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
-#endif
-    return result;
-}
-
-bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
-        FallbackAction* outFallbackAction) const {
-    outFallbackAction->keyCode = 0;
-    outFallbackAction->metaState = 0;
-
-    bool result = false;
-    const Key* key;
-    const Behavior* behavior;
-    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
-        if (behavior->fallbackKeyCode) {
-            outFallbackAction->keyCode = behavior->fallbackKeyCode;
-            outFallbackAction->metaState = metaState & ~behavior->metaState;
-            result = true;
-        }
-    }
-#if DEBUG_MAPPING
-    ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
-            "fallback keyCode=%d, fallback metaState=0x%08x.",
-            keyCode, metaState, result ? "true" : "false",
-            outFallbackAction->keyCode, outFallbackAction->metaState);
-#endif
-    return result;
-}
-
-char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
-        int32_t metaState) const {
-    char16_t result = 0;
-    const Key* key;
-    if (getKey(keyCode, &key)) {
-        // Try to find the most general behavior that maps to this character.
-        // For example, the base key behavior will usually be last in the list.
-        // However, if we find a perfect meta state match for one behavior then use that one.
-        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
-            if (behavior->character) {
-                for (size_t i = 0; i < numChars; i++) {
-                    if (behavior->character == chars[i]) {
-                        result = behavior->character;
-                        if ((behavior->metaState & metaState) == behavior->metaState) {
-                            goto ExactMatch;
-                        }
-                        break;
-                    }
-                }
-            }
-        }
-    ExactMatch: ;
-    }
-#if DEBUG_MAPPING
-    ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
-            keyCode, toString(chars, numChars).string(), metaState, result);
-#endif
-    return result;
-}
-
-bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
-        Vector<KeyEvent>& outEvents) const {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-
-    for (size_t i = 0; i < numChars; i++) {
-        int32_t keyCode, metaState;
-        char16_t ch = chars[i];
-        if (!findKey(ch, &keyCode, &metaState)) {
-#if DEBUG_MAPPING
-            ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
-                    deviceId, toString(chars, numChars).string(), ch);
-#endif
-            return false;
-        }
-
-        int32_t currentMetaState = 0;
-        addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
-        addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
-        addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
-        addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
-    }
-#if DEBUG_MAPPING
-    ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
-            deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
-    for (size_t i = 0; i < outEvents.size(); i++) {
-        ALOGD("  Key: keyCode=%d, metaState=0x%08x, %s.",
-                outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
-                outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
-    }
-#endif
-    return true;
-}
-
-status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
-    if (usageCode) {
-        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
-        if (index >= 0) {
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
-            scanCode, usageCode, *outKeyCode);
-#endif
-            *outKeyCode = mKeysByUsageCode.valueAt(index);
-            return OK;
-        }
-    }
-    if (scanCode) {
-        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
-        if (index >= 0) {
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
-            scanCode, usageCode, *outKeyCode);
-#endif
-            *outKeyCode = mKeysByScanCode.valueAt(index);
-            return OK;
-        }
-    }
-
-#if DEBUG_MAPPING
-        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
-    *outKeyCode = AKEYCODE_UNKNOWN;
-    return NAME_NOT_FOUND;
-}
-
-bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
-    ssize_t index = mKeys.indexOfKey(keyCode);
-    if (index >= 0) {
-        *outKey = mKeys.valueAt(index);
-        return true;
-    }
-    return false;
-}
-
-bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
-        const Key** outKey, const Behavior** outBehavior) const {
-    const Key* key;
-    if (getKey(keyCode, &key)) {
-        const Behavior* behavior = key->firstBehavior;
-        while (behavior) {
-            if (matchesMetaState(metaState, behavior->metaState)) {
-                *outKey = key;
-                *outBehavior = behavior;
-                return true;
-            }
-            behavior = behavior->next;
-        }
-    }
-    return false;
-}
-
-bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
-    // Behavior must have at least the set of meta states specified.
-    // And if the key event has CTRL, ALT or META then the behavior must exactly
-    // match those, taking into account that a behavior can specify that it handles
-    // one, both or either of a left/right modifier pair.
-    if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
-        const int32_t EXACT_META_STATES =
-                AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
-                | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
-                | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
-        int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
-        if (behaviorMetaState & AMETA_CTRL_ON) {
-            unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
-        } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
-            unmatchedMetaState &= ~AMETA_CTRL_ON;
-        }
-        if (behaviorMetaState & AMETA_ALT_ON) {
-            unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
-        } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
-            unmatchedMetaState &= ~AMETA_ALT_ON;
-        }
-        if (behaviorMetaState & AMETA_META_ON) {
-            unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
-        } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
-            unmatchedMetaState &= ~AMETA_META_ON;
-        }
-        return !unmatchedMetaState;
-    }
-    return false;
-}
-
-bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
-    if (!ch) {
-        return false;
-    }
-
-    for (size_t i = 0; i < mKeys.size(); i++) {
-        const Key* key = mKeys.valueAt(i);
-
-        // Try to find the most general behavior that maps to this character.
-        // For example, the base key behavior will usually be last in the list.
-        const Behavior* found = NULL;
-        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
-            if (behavior->character == ch) {
-                found = behavior;
-            }
-        }
-        if (found) {
-            *outKeyCode = mKeys.keyAt(i);
-            *outMetaState = found->metaState;
-            return true;
-        }
-    }
-    return false;
-}
-
-void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
-        int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
-    outEvents.push();
-    KeyEvent& event = outEvents.editTop();
-    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
-            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
-            0, keyCode, 0, metaState, 0, time, time);
-}
-
-void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
-        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
-        int32_t* currentMetaState) {
-    // Add and remove meta keys symmetrically.
-    if (down) {
-        addLockedMetaKey(outEvents, deviceId, metaState, time,
-                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
-        addLockedMetaKey(outEvents, deviceId, metaState, time,
-                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
-        addLockedMetaKey(outEvents, deviceId, metaState, time,
-                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
-
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
-                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
-                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
-                AMETA_SHIFT_ON, currentMetaState);
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
-                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
-                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
-                AMETA_ALT_ON, currentMetaState);
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
-                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
-                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
-                AMETA_CTRL_ON, currentMetaState);
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
-                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
-                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
-                AMETA_META_ON, currentMetaState);
-
-        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
-                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
-        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
-                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
-    } else {
-        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
-                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
-        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
-                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
-
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
-                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
-                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
-                AMETA_META_ON, currentMetaState);
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
-                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
-                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
-                AMETA_CTRL_ON, currentMetaState);
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
-                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
-                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
-                AMETA_ALT_ON, currentMetaState);
-        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
-                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
-                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
-                AMETA_SHIFT_ON, currentMetaState);
-
-        addLockedMetaKey(outEvents, deviceId, metaState, time,
-                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
-        addLockedMetaKey(outEvents, deviceId, metaState, time,
-                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
-        addLockedMetaKey(outEvents, deviceId, metaState, time,
-                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
-    }
-}
-
-bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
-        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
-        int32_t keyCode, int32_t keyMetaState,
-        int32_t* currentMetaState) {
-    if ((metaState & keyMetaState) == keyMetaState) {
-        *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
-        addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
-        return true;
-    }
-    return false;
-}
-
-void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
-        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
-        int32_t leftKeyCode, int32_t leftKeyMetaState,
-        int32_t rightKeyCode, int32_t rightKeyMetaState,
-        int32_t eitherKeyMetaState,
-        int32_t* currentMetaState) {
-    bool specific = false;
-    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
-            leftKeyCode, leftKeyMetaState, currentMetaState);
-    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
-            rightKeyCode, rightKeyMetaState, currentMetaState);
-
-    if (!specific) {
-        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
-                leftKeyCode, eitherKeyMetaState, currentMetaState);
-    }
-}
-
-void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
-        int32_t deviceId, int32_t metaState, nsecs_t time,
-        int32_t keyCode, int32_t keyMetaState,
-        int32_t* currentMetaState) {
-    if ((metaState & keyMetaState) == keyMetaState) {
-        *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
-        addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
-        *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
-        addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
-    }
-}
-
-#if HAVE_ANDROID_OS
-sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
-    sp<KeyCharacterMap> map = new KeyCharacterMap();
-    map->mType = parcel->readInt32();
-    size_t numKeys = parcel->readInt32();
-    if (parcel->errorCheck()) {
-        return NULL;
-    }
-
-    for (size_t i = 0; i < numKeys; i++) {
-        int32_t keyCode = parcel->readInt32();
-        char16_t label = parcel->readInt32();
-        char16_t number = parcel->readInt32();
-        if (parcel->errorCheck()) {
-            return NULL;
-        }
-
-        Key* key = new Key();
-        key->label = label;
-        key->number = number;
-        map->mKeys.add(keyCode, key);
-
-        Behavior* lastBehavior = NULL;
-        while (parcel->readInt32()) {
-            int32_t metaState = parcel->readInt32();
-            char16_t character = parcel->readInt32();
-            int32_t fallbackKeyCode = parcel->readInt32();
-            if (parcel->errorCheck()) {
-                return NULL;
-            }
-
-            Behavior* behavior = new Behavior();
-            behavior->metaState = metaState;
-            behavior->character = character;
-            behavior->fallbackKeyCode = fallbackKeyCode;
-            if (lastBehavior) {
-                lastBehavior->next = behavior;
-            } else {
-                key->firstBehavior = behavior;
-            }
-            lastBehavior = behavior;
-        }
-
-        if (parcel->errorCheck()) {
-            return NULL;
-        }
-    }
-    return map;
-}
-
-void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
-    parcel->writeInt32(mType);
-
-    size_t numKeys = mKeys.size();
-    parcel->writeInt32(numKeys);
-    for (size_t i = 0; i < numKeys; i++) {
-        int32_t keyCode = mKeys.keyAt(i);
-        const Key* key = mKeys.valueAt(i);
-        parcel->writeInt32(keyCode);
-        parcel->writeInt32(key->label);
-        parcel->writeInt32(key->number);
-        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
-                behavior = behavior->next) {
-            parcel->writeInt32(1);
-            parcel->writeInt32(behavior->metaState);
-            parcel->writeInt32(behavior->character);
-            parcel->writeInt32(behavior->fallbackKeyCode);
-        }
-        parcel->writeInt32(0);
-    }
-}
-#endif
-
-
-// --- KeyCharacterMap::Key ---
-
-KeyCharacterMap::Key::Key() :
-        label(0), number(0), firstBehavior(NULL) {
-}
-
-KeyCharacterMap::Key::Key(const Key& other) :
-        label(other.label), number(other.number),
-        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
-}
-
-KeyCharacterMap::Key::~Key() {
-    Behavior* behavior = firstBehavior;
-    while (behavior) {
-        Behavior* next = behavior->next;
-        delete behavior;
-        behavior = next;
-    }
-}
-
-
-// --- KeyCharacterMap::Behavior ---
-
-KeyCharacterMap::Behavior::Behavior() :
-        next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
-}
-
-KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
-        next(other.next ? new Behavior(*other.next) : NULL),
-        metaState(other.metaState), character(other.character),
-        fallbackKeyCode(other.fallbackKeyCode) {
-}
-
-
-// --- KeyCharacterMap::Parser ---
-
-KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
-        mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
-}
-
-KeyCharacterMap::Parser::~Parser() {
-}
-
-status_t KeyCharacterMap::Parser::parse() {
-    while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
-        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
-                mTokenizer->peekRemainderOfLine().string());
-#endif
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-
-        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
-            switch (mState) {
-            case STATE_TOP: {
-                String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
-                if (keywordToken == "type") {
-                    mTokenizer->skipDelimiters(WHITESPACE);
-                    status_t status = parseType();
-                    if (status) return status;
-                } else if (keywordToken == "map") {
-                    mTokenizer->skipDelimiters(WHITESPACE);
-                    status_t status = parseMap();
-                    if (status) return status;
-                } else if (keywordToken == "key") {
-                    mTokenizer->skipDelimiters(WHITESPACE);
-                    status_t status = parseKey();
-                    if (status) return status;
-                } else {
-                    ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
-                            keywordToken.string());
-                    return BAD_VALUE;
-                }
-                break;
-            }
-
-            case STATE_KEY: {
-                status_t status = parseKeyProperty();
-                if (status) return status;
-                break;
-            }
-            }
-
-            mTokenizer->skipDelimiters(WHITESPACE);
-            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
-                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
-                        mTokenizer->getLocation().string(),
-                        mTokenizer->peekRemainderOfLine().string());
-                return BAD_VALUE;
-            }
-        }
-
-        mTokenizer->nextLine();
-    }
-
-    if (mState != STATE_TOP) {
-        ALOGE("%s: Unterminated key description at end of file.",
-                mTokenizer->getLocation().string());
-        return BAD_VALUE;
-    }
-
-    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
-        ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
-                mTokenizer->getLocation().string());
-        return BAD_VALUE;
-    }
-
-    if (mFormat == FORMAT_BASE) {
-        if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
-            ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
-                    mTokenizer->getLocation().string());
-            return BAD_VALUE;
-        }
-    } else if (mFormat == FORMAT_OVERLAY) {
-        if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
-            ALOGE("%s: Overlay keyboard layout missing required keyboard "
-                    "'type OVERLAY' declaration.",
-                    mTokenizer->getLocation().string());
-            return BAD_VALUE;
-        }
-    }
-
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseType() {
-    if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
-        ALOGE("%s: Duplicate keyboard 'type' declaration.",
-                mTokenizer->getLocation().string());
-        return BAD_VALUE;
-    }
-
-    KeyboardType type;
-    String8 typeToken = mTokenizer->nextToken(WHITESPACE);
-    if (typeToken == "NUMERIC") {
-        type = KEYBOARD_TYPE_NUMERIC;
-    } else if (typeToken == "PREDICTIVE") {
-        type = KEYBOARD_TYPE_PREDICTIVE;
-    } else if (typeToken == "ALPHA") {
-        type = KEYBOARD_TYPE_ALPHA;
-    } else if (typeToken == "FULL") {
-        type = KEYBOARD_TYPE_FULL;
-    } else if (typeToken == "SPECIAL_FUNCTION") {
-        type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
-    } else if (typeToken == "OVERLAY") {
-        type = KEYBOARD_TYPE_OVERLAY;
-    } else {
-        ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
-                typeToken.string());
-        return BAD_VALUE;
-    }
-
-#if DEBUG_PARSER
-    ALOGD("Parsed type: type=%d.", type);
-#endif
-    mMap->mType = type;
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseMap() {
-    String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
-    if (keywordToken == "key") {
-        mTokenizer->skipDelimiters(WHITESPACE);
-        return parseMapKey();
-    }
-    ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
-            keywordToken.string());
-    return BAD_VALUE;
-}
-
-status_t KeyCharacterMap::Parser::parseMapKey() {
-    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
-    bool mapUsage = false;
-    if (codeToken == "usage") {
-        mapUsage = true;
-        mTokenizer->skipDelimiters(WHITESPACE);
-        codeToken = mTokenizer->nextToken(WHITESPACE);
-    }
-
-    char* end;
-    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
-    if (*end) {
-        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
-                mapUsage ? "usage" : "scan code", codeToken.string());
-        return BAD_VALUE;
-    }
-    KeyedVector<int32_t, int32_t>& map =
-            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
-    if (map.indexOfKey(code) >= 0) {
-        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
-                mapUsage ? "usage" : "scan code", codeToken.string());
-        return BAD_VALUE;
-    }
-
-    mTokenizer->skipDelimiters(WHITESPACE);
-    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
-    if (!keyCode) {
-        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
-                keyCodeToken.string());
-        return BAD_VALUE;
-    }
-
-#if DEBUG_PARSER
-    ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
-            mapUsage ? "usage" : "scan code", code, keyCode);
-#endif
-    map.add(code, keyCode);
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseKey() {
-    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
-    if (!keyCode) {
-        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
-                keyCodeToken.string());
-        return BAD_VALUE;
-    }
-    if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
-        ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
-                keyCodeToken.string());
-        return BAD_VALUE;
-    }
-
-    mTokenizer->skipDelimiters(WHITESPACE);
-    String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
-    if (openBraceToken != "{") {
-        ALOGE("%s: Expected '{' after key code label, got '%s'.",
-                mTokenizer->getLocation().string(), openBraceToken.string());
-        return BAD_VALUE;
-    }
-
-#if DEBUG_PARSER
-    ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
-#endif
-    mKeyCode = keyCode;
-    mMap->mKeys.add(keyCode, new Key());
-    mState = STATE_KEY;
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseKeyProperty() {
-    Key* key = mMap->mKeys.valueFor(mKeyCode);
-    String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
-    if (token == "}") {
-        mState = STATE_TOP;
-        return finishKey(key);
-    }
-
-    Vector<Property> properties;
-
-    // Parse all comma-delimited property names up to the first colon.
-    for (;;) {
-        if (token == "label") {
-            properties.add(Property(PROPERTY_LABEL));
-        } else if (token == "number") {
-            properties.add(Property(PROPERTY_NUMBER));
-        } else {
-            int32_t metaState;
-            status_t status = parseModifier(token, &metaState);
-            if (status) {
-                ALOGE("%s: Expected a property name or modifier, got '%s'.",
-                        mTokenizer->getLocation().string(), token.string());
-                return status;
-            }
-            properties.add(Property(PROPERTY_META, metaState));
-        }
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-        if (!mTokenizer->isEol()) {
-            char ch = mTokenizer->nextChar();
-            if (ch == ':') {
-                break;
-            } else if (ch == ',') {
-                mTokenizer->skipDelimiters(WHITESPACE);
-                token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
-                continue;
-            }
-        }
-
-        ALOGE("%s: Expected ',' or ':' after property name.",
-                mTokenizer->getLocation().string());
-        return BAD_VALUE;
-    }
-
-    // Parse behavior after the colon.
-    mTokenizer->skipDelimiters(WHITESPACE);
-
-    Behavior behavior;
-    bool haveCharacter = false;
-    bool haveFallback = false;
-
-    do {
-        char ch = mTokenizer->peekChar();
-        if (ch == '\'') {
-            char16_t character;
-            status_t status = parseCharacterLiteral(&character);
-            if (status || !character) {
-                ALOGE("%s: Invalid character literal for key.",
-                        mTokenizer->getLocation().string());
-                return BAD_VALUE;
-            }
-            if (haveCharacter) {
-                ALOGE("%s: Cannot combine multiple character literals or 'none'.",
-                        mTokenizer->getLocation().string());
-                return BAD_VALUE;
-            }
-            behavior.character = character;
-            haveCharacter = true;
-        } else {
-            token = mTokenizer->nextToken(WHITESPACE);
-            if (token == "none") {
-                if (haveCharacter) {
-                    ALOGE("%s: Cannot combine multiple character literals or 'none'.",
-                            mTokenizer->getLocation().string());
-                    return BAD_VALUE;
-                }
-                haveCharacter = true;
-            } else if (token == "fallback") {
-                mTokenizer->skipDelimiters(WHITESPACE);
-                token = mTokenizer->nextToken(WHITESPACE);
-                int32_t keyCode = getKeyCodeByLabel(token.string());
-                if (!keyCode) {
-                    ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
-                            mTokenizer->getLocation().string(),
-                            token.string());
-                    return BAD_VALUE;
-                }
-                if (haveFallback) {
-                    ALOGE("%s: Cannot combine multiple fallback key codes.",
-                            mTokenizer->getLocation().string());
-                    return BAD_VALUE;
-                }
-                behavior.fallbackKeyCode = keyCode;
-                haveFallback = true;
-            } else {
-                ALOGE("%s: Expected a key behavior after ':'.",
-                        mTokenizer->getLocation().string());
-                return BAD_VALUE;
-            }
-        }
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-    } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
-
-    // Add the behavior.
-    for (size_t i = 0; i < properties.size(); i++) {
-        const Property& property = properties.itemAt(i);
-        switch (property.property) {
-        case PROPERTY_LABEL:
-            if (key->label) {
-                ALOGE("%s: Duplicate label for key.",
-                        mTokenizer->getLocation().string());
-                return BAD_VALUE;
-            }
-            key->label = behavior.character;
-#if DEBUG_PARSER
-            ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
-#endif
-            break;
-        case PROPERTY_NUMBER:
-            if (key->number) {
-                ALOGE("%s: Duplicate number for key.",
-                        mTokenizer->getLocation().string());
-                return BAD_VALUE;
-            }
-            key->number = behavior.character;
-#if DEBUG_PARSER
-            ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
-#endif
-            break;
-        case PROPERTY_META: {
-            for (Behavior* b = key->firstBehavior; b; b = b->next) {
-                if (b->metaState == property.metaState) {
-                    ALOGE("%s: Duplicate key behavior for modifier.",
-                            mTokenizer->getLocation().string());
-                    return BAD_VALUE;
-                }
-            }
-            Behavior* newBehavior = new Behavior(behavior);
-            newBehavior->metaState = property.metaState;
-            newBehavior->next = key->firstBehavior;
-            key->firstBehavior = newBehavior;
-#if DEBUG_PARSER
-            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
-                    newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
-#endif
-            break;
-        }
-        }
-    }
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::finishKey(Key* key) {
-    // Fill in default number property.
-    if (!key->number) {
-        char16_t digit = 0;
-        char16_t symbol = 0;
-        for (Behavior* b = key->firstBehavior; b; b = b->next) {
-            char16_t ch = b->character;
-            if (ch) {
-                if (ch >= '0' && ch <= '9') {
-                    digit = ch;
-                } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
-                        || ch == '-' || ch == '+' || ch == ',' || ch == '.'
-                        || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
-                    symbol = ch;
-                }
-            }
-        }
-        key->number = digit ? digit : symbol;
-    }
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
-    if (token == "base") {
-        *outMetaState = 0;
-        return NO_ERROR;
-    }
-
-    int32_t combinedMeta = 0;
-
-    const char* str = token.string();
-    const char* start = str;
-    for (const char* cur = str; ; cur++) {
-        char ch = *cur;
-        if (ch == '+' || ch == '\0') {
-            size_t len = cur - start;
-            int32_t metaState = 0;
-            for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
-                if (strlen(modifiers[i].label) == len
-                        && strncmp(modifiers[i].label, start, len) == 0) {
-                    metaState = modifiers[i].metaState;
-                    break;
-                }
-            }
-            if (!metaState) {
-                return BAD_VALUE;
-            }
-            if (combinedMeta & metaState) {
-                ALOGE("%s: Duplicate modifier combination '%s'.",
-                        mTokenizer->getLocation().string(), token.string());
-                return BAD_VALUE;
-            }
-
-            combinedMeta |= metaState;
-            start = cur + 1;
-
-            if (ch == '\0') {
-                break;
-            }
-        }
-    }
-    *outMetaState = combinedMeta;
-    return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
-    char ch = mTokenizer->nextChar();
-    if (ch != '\'') {
-        goto Error;
-    }
-
-    ch = mTokenizer->nextChar();
-    if (ch == '\\') {
-        // Escape sequence.
-        ch = mTokenizer->nextChar();
-        if (ch == 'n') {
-            *outCharacter = '\n';
-        } else if (ch == 't') {
-            *outCharacter = '\t';
-        } else if (ch == '\\') {
-            *outCharacter = '\\';
-        } else if (ch == '\'') {
-            *outCharacter = '\'';
-        } else if (ch == '"') {
-            *outCharacter = '"';
-        } else if (ch == 'u') {
-            *outCharacter = 0;
-            for (int i = 0; i < 4; i++) {
-                ch = mTokenizer->nextChar();
-                int digit;
-                if (ch >= '0' && ch <= '9') {
-                    digit = ch - '0';
-                } else if (ch >= 'A' && ch <= 'F') {
-                    digit = ch - 'A' + 10;
-                } else if (ch >= 'a' && ch <= 'f') {
-                    digit = ch - 'a' + 10;
-                } else {
-                    goto Error;
-                }
-                *outCharacter = (*outCharacter << 4) | digit;
-            }
-        } else {
-            goto Error;
-        }
-    } else if (ch >= 32 && ch <= 126 && ch != '\'') {
-        // ASCII literal character.
-        *outCharacter = ch;
-    } else {
-        goto Error;
-    }
-
-    ch = mTokenizer->nextChar();
-    if (ch != '\'') {
-        goto Error;
-    }
-
-    // Ensure that we consumed the entire token.
-    if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
-        return NO_ERROR;
-    }
-
-Error:
-    ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
-    return BAD_VALUE;
-}
-
-} // namespace android
diff --git a/libs/androidfw/KeyLayoutMap.cpp b/libs/androidfw/KeyLayoutMap.cpp
deleted file mode 100644
index ae14f23..0000000
--- a/libs/androidfw/KeyLayoutMap.cpp
+++ /dev/null
@@ -1,366 +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.
- */
-
-#define LOG_TAG "KeyLayoutMap"
-
-#include <stdlib.h>
-#include <android/keycodes.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-#include <utils/Timers.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-
-// --- KeyLayoutMap ---
-
-KeyLayoutMap::KeyLayoutMap() {
-}
-
-KeyLayoutMap::~KeyLayoutMap() {
-}
-
-status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
-    outMap->clear();
-
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening key layout map file %s.", status, filename.string());
-    } else {
-        sp<KeyLayoutMap> map = new KeyLayoutMap();
-        if (!map.get()) {
-            ALOGE("Error allocating key layout map.");
-            status = NO_MEMORY;
-        } else {
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
-            Parser parser(map.get(), tokenizer);
-            status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-            ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
-                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),
-                    elapsedTime / 1000000.0);
-#endif
-            if (!status) {
-                *outMap = map;
-            }
-        }
-        delete tokenizer;
-    }
-    return status;
-}
-
-status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode,
-        int32_t* outKeyCode, uint32_t* outFlags) const {
-    const Key* key = getKey(scanCode, usageCode);
-    if (!key) {
-#if DEBUG_MAPPING
-        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
-        *outKeyCode = AKEYCODE_UNKNOWN;
-        *outFlags = 0;
-        return NAME_NOT_FOUND;
-    }
-
-    *outKeyCode = key->keyCode;
-    *outFlags = key->flags;
-
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
-            scanCode, usageCode, *outKeyCode, *outFlags);
-#endif
-    return NO_ERROR;
-}
-
-const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
-    if (usageCode) {
-        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
-        if (index >= 0) {
-            return &mKeysByUsageCode.valueAt(index);
-        }
-    }
-    if (scanCode) {
-        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
-        if (index >= 0) {
-            return &mKeysByScanCode.valueAt(index);
-        }
-    }
-    return NULL;
-}
-
-status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
-    const size_t N = mKeysByScanCode.size();
-    for (size_t i=0; i<N; i++) {
-        if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
-            outScanCodes->add(mKeysByScanCode.keyAt(i));
-        }
-    }
-    return NO_ERROR;
-}
-
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
-    ssize_t index = mAxes.indexOfKey(scanCode);
-    if (index < 0) {
-#if DEBUG_MAPPING
-        ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
-#endif
-        return NAME_NOT_FOUND;
-    }
-
-    *outAxisInfo = mAxes.valueAt(index);
-
-#if DEBUG_MAPPING
-    ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
-            "splitValue=%d, flatOverride=%d.",
-            scanCode,
-            outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
-            outAxisInfo->splitValue, outAxisInfo->flatOverride);
-#endif
-    return NO_ERROR;
-}
-
-
-// --- KeyLayoutMap::Parser ---
-
-KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
-        mMap(map), mTokenizer(tokenizer) {
-}
-
-KeyLayoutMap::Parser::~Parser() {
-}
-
-status_t KeyLayoutMap::Parser::parse() {
-    while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
-        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
-                mTokenizer->peekRemainderOfLine().string());
-#endif
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-
-        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
-            String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
-            if (keywordToken == "key") {
-                mTokenizer->skipDelimiters(WHITESPACE);
-                status_t status = parseKey();
-                if (status) return status;
-            } else if (keywordToken == "axis") {
-                mTokenizer->skipDelimiters(WHITESPACE);
-                status_t status = parseAxis();
-                if (status) return status;
-            } else {
-                ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
-                        keywordToken.string());
-                return BAD_VALUE;
-            }
-
-            mTokenizer->skipDelimiters(WHITESPACE);
-            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
-                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
-                        mTokenizer->getLocation().string(),
-                        mTokenizer->peekRemainderOfLine().string());
-                return BAD_VALUE;
-            }
-        }
-
-        mTokenizer->nextLine();
-    }
-    return NO_ERROR;
-}
-
-status_t KeyLayoutMap::Parser::parseKey() {
-    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
-    bool mapUsage = false;
-    if (codeToken == "usage") {
-        mapUsage = true;
-        mTokenizer->skipDelimiters(WHITESPACE);
-        codeToken = mTokenizer->nextToken(WHITESPACE);
-    }
-
-    char* end;
-    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
-    if (*end) {
-        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
-                mapUsage ? "usage" : "scan code", codeToken.string());
-        return BAD_VALUE;
-    }
-    KeyedVector<int32_t, Key>& map =
-            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
-    if (map.indexOfKey(code) >= 0) {
-        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
-                mapUsage ? "usage" : "scan code", codeToken.string());
-        return BAD_VALUE;
-    }
-
-    mTokenizer->skipDelimiters(WHITESPACE);
-    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
-    if (!keyCode) {
-        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
-                keyCodeToken.string());
-        return BAD_VALUE;
-    }
-
-    uint32_t flags = 0;
-    for (;;) {
-        mTokenizer->skipDelimiters(WHITESPACE);
-        if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
-
-        String8 flagToken = mTokenizer->nextToken(WHITESPACE);
-        uint32_t flag = getKeyFlagByLabel(flagToken.string());
-        if (!flag) {
-            ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
-                    flagToken.string());
-            return BAD_VALUE;
-        }
-        if (flags & flag) {
-            ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
-                    flagToken.string());
-            return BAD_VALUE;
-        }
-        flags |= flag;
-    }
-
-#if DEBUG_PARSER
-    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
-            mapUsage ? "usage" : "scan code", code, keyCode, flags);
-#endif
-    Key key;
-    key.keyCode = keyCode;
-    key.flags = flags;
-    map.add(code, key);
-    return NO_ERROR;
-}
-
-status_t KeyLayoutMap::Parser::parseAxis() {
-    String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
-    char* end;
-    int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
-    if (*end) {
-        ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
-                scanCodeToken.string());
-        return BAD_VALUE;
-    }
-    if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
-        ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
-                scanCodeToken.string());
-        return BAD_VALUE;
-    }
-
-    AxisInfo axisInfo;
-
-    mTokenizer->skipDelimiters(WHITESPACE);
-    String8 token = mTokenizer->nextToken(WHITESPACE);
-    if (token == "invert") {
-        axisInfo.mode = AxisInfo::MODE_INVERT;
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-        String8 axisToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.axis = getAxisByLabel(axisToken.string());
-        if (axisInfo.axis < 0) {
-            ALOGE("%s: Expected inverted axis label, got '%s'.",
-                    mTokenizer->getLocation().string(), axisToken.string());
-            return BAD_VALUE;
-        }
-    } else if (token == "split") {
-        axisInfo.mode = AxisInfo::MODE_SPLIT;
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-        String8 splitToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
-        if (*end) {
-            ALOGE("%s: Expected split value, got '%s'.",
-                    mTokenizer->getLocation().string(), splitToken.string());
-            return BAD_VALUE;
-        }
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-        String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.axis = getAxisByLabel(lowAxisToken.string());
-        if (axisInfo.axis < 0) {
-            ALOGE("%s: Expected low axis label, got '%s'.",
-                    mTokenizer->getLocation().string(), lowAxisToken.string());
-            return BAD_VALUE;
-        }
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-        String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
-        if (axisInfo.highAxis < 0) {
-            ALOGE("%s: Expected high axis label, got '%s'.",
-                    mTokenizer->getLocation().string(), highAxisToken.string());
-            return BAD_VALUE;
-        }
-    } else {
-        axisInfo.axis = getAxisByLabel(token.string());
-        if (axisInfo.axis < 0) {
-            ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
-                    mTokenizer->getLocation().string(), token.string());
-            return BAD_VALUE;
-        }
-    }
-
-    for (;;) {
-        mTokenizer->skipDelimiters(WHITESPACE);
-        if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
-            break;
-        }
-        String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
-        if (keywordToken == "flat") {
-            mTokenizer->skipDelimiters(WHITESPACE);
-            String8 flatToken = mTokenizer->nextToken(WHITESPACE);
-            axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
-            if (*end) {
-                ALOGE("%s: Expected flat value, got '%s'.",
-                        mTokenizer->getLocation().string(), flatToken.string());
-                return BAD_VALUE;
-            }
-        } else {
-            ALOGE("%s: Expected keyword 'flat', got '%s'.",
-                    mTokenizer->getLocation().string(), keywordToken.string());
-            return BAD_VALUE;
-        }
-    }
-
-#if DEBUG_PARSER
-    ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
-            "splitValue=%d, flatOverride=%d.",
-            scanCode,
-            axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
-            axisInfo.splitValue, axisInfo.flatOverride);
-#endif
-    mMap->mAxes.add(scanCode, axisInfo);
-    return NO_ERROR;
-}
-
-};
diff --git a/libs/androidfw/Keyboard.cpp b/libs/androidfw/Keyboard.cpp
deleted file mode 100644
index 4ddbeab..0000000
--- a/libs/androidfw/Keyboard.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "Keyboard"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeycodeLabels.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/InputDevice.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <cutils/properties.h>
-
-namespace android {
-
-// --- KeyMap ---
-
-KeyMap::KeyMap() {
-}
-
-KeyMap::~KeyMap() {
-}
-
-status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
-        const PropertyMap* deviceConfiguration) {
-    // Use the configured key layout if available.
-    if (deviceConfiguration) {
-        String8 keyLayoutName;
-        if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
-                keyLayoutName)) {
-            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
-            if (status == NAME_NOT_FOUND) {
-                ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
-                        "it was not found.",
-                        deviceIdenfifier.name.string(), keyLayoutName.string());
-            }
-        }
-
-        String8 keyCharacterMapName;
-        if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
-                keyCharacterMapName)) {
-            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
-            if (status == NAME_NOT_FOUND) {
-                ALOGE("Configuration for keyboard device '%s' requested keyboard character "
-                        "map '%s' but it was not found.",
-                        deviceIdenfifier.name.string(), keyLayoutName.string());
-            }
-        }
-
-        if (isComplete()) {
-            return OK;
-        }
-    }
-
-    // Try searching by device identifier.
-    if (probeKeyMap(deviceIdenfifier, String8::empty())) {
-        return OK;
-    }
-
-    // Fall back on the Generic key map.
-    // TODO Apply some additional heuristics here to figure out what kind of
-    //      generic key map to use (US English, etc.) for typical external keyboards.
-    if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
-        return OK;
-    }
-
-    // Try the Virtual key map as a last resort.
-    if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
-        return OK;
-    }
-
-    // Give up!
-    ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
-            deviceIdenfifier.name.string());
-    return NAME_NOT_FOUND;
-}
-
-bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyMapName) {
-    if (!haveKeyLayout()) {
-        loadKeyLayout(deviceIdentifier, keyMapName);
-    }
-    if (!haveKeyCharacterMap()) {
-        loadKeyCharacterMap(deviceIdentifier, keyMapName);
-    }
-    return isComplete();
-}
-
-status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name) {
-    String8 path(getPath(deviceIdentifier, name,
-            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
-    if (path.isEmpty()) {
-        return NAME_NOT_FOUND;
-    }
-
-    status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
-    if (status) {
-        return status;
-    }
-
-    keyLayoutFile.setTo(path);
-    return OK;
-}
-
-status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name) {
-    String8 path(getPath(deviceIdentifier, name,
-            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
-    if (path.isEmpty()) {
-        return NAME_NOT_FOUND;
-    }
-
-    status_t status = KeyCharacterMap::load(path,
-            KeyCharacterMap::FORMAT_BASE, &keyCharacterMap);
-    if (status) {
-        return status;
-    }
-
-    keyCharacterMapFile.setTo(path);
-    return OK;
-}
-
-String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name, InputDeviceConfigurationFileType type) {
-    return name.isEmpty()
-            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
-            : getInputDeviceConfigurationFilePathByName(name, type);
-}
-
-
-// --- Global functions ---
-
-bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
-        const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
-    if (!keyMap->haveKeyCharacterMap()
-            || keyMap->keyCharacterMap->getKeyboardType()
-                    == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
-        return false;
-    }
-
-    if (deviceConfiguration) {
-        bool builtIn = false;
-        if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
-                && builtIn) {
-            return true;
-        }
-    }
-
-    return strstr(deviceIdentifier.name.string(), "-keypad");
-}
-
-static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
-    while (list->literal) {
-        if (strcmp(literal, list->literal) == 0) {
-            return list->value;
-        }
-        list++;
-    }
-    return list->value;
-}
-
-static const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
-    while (list->literal) {
-        if (list->value == value) {
-            return list->literal;
-        }
-        list++;
-    }
-    return NULL;
-}
-
-int32_t getKeyCodeByLabel(const char* label) {
-    return int32_t(lookupValueByLabel(label, KEYCODES));
-}
-
-uint32_t getKeyFlagByLabel(const char* label) {
-    return uint32_t(lookupValueByLabel(label, FLAGS));
-}
-
-int32_t getAxisByLabel(const char* label) {
-    return int32_t(lookupValueByLabel(label, AXES));
-}
-
-const char* getAxisLabel(int32_t axisId) {
-    return lookupLabelByValue(axisId, AXES);
-}
-
-static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
-    int32_t newMetaState;
-    if (down) {
-        newMetaState = oldMetaState | mask;
-    } else {
-        newMetaState = oldMetaState &
-                ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
-    }
-
-    if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
-        newMetaState |= AMETA_ALT_ON;
-    }
-
-    if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
-        newMetaState |= AMETA_SHIFT_ON;
-    }
-
-    if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
-        newMetaState |= AMETA_CTRL_ON;
-    }
-
-    if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
-        newMetaState |= AMETA_META_ON;
-    }
-    return newMetaState;
-}
-
-static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
-    if (down) {
-        return oldMetaState;
-    } else {
-        return oldMetaState ^ mask;
-    }
-}
-
-int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
-    int32_t mask;
-    switch (keyCode) {
-    case AKEYCODE_ALT_LEFT:
-        return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
-    case AKEYCODE_ALT_RIGHT:
-        return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
-    case AKEYCODE_SHIFT_LEFT:
-        return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
-    case AKEYCODE_SHIFT_RIGHT:
-        return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
-    case AKEYCODE_SYM:
-        return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
-    case AKEYCODE_FUNCTION:
-        return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
-    case AKEYCODE_CTRL_LEFT:
-        return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
-    case AKEYCODE_CTRL_RIGHT:
-        return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
-    case AKEYCODE_META_LEFT:
-        return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
-    case AKEYCODE_META_RIGHT:
-        return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
-    case AKEYCODE_CAPS_LOCK:
-        return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
-    case AKEYCODE_NUM_LOCK:
-        return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
-    case AKEYCODE_SCROLL_LOCK:
-        return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
-    default:
-        return oldMetaState;
-    }
-}
-
-bool isMetaKey(int32_t keyCode) {
-    switch (keyCode) {
-    case AKEYCODE_ALT_LEFT:
-    case AKEYCODE_ALT_RIGHT:
-    case AKEYCODE_SHIFT_LEFT:
-    case AKEYCODE_SHIFT_RIGHT:
-    case AKEYCODE_SYM:
-    case AKEYCODE_FUNCTION:
-    case AKEYCODE_CTRL_LEFT:
-    case AKEYCODE_CTRL_RIGHT:
-    case AKEYCODE_META_LEFT:
-    case AKEYCODE_META_RIGHT:
-    case AKEYCODE_CAPS_LOCK:
-    case AKEYCODE_NUM_LOCK:
-    case AKEYCODE_SCROLL_LOCK:
-        return true;
-    default:
-        return false;
-    }
-}
-
-
-} // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index a730065..1cc3563 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -24,7 +24,6 @@
 #include <utils/Log.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
-#include <utils/TextOutput.h>
 
 #include <stdlib.h>
 #include <string.h>
@@ -36,7 +35,7 @@
 #define INT32_MAX ((int32_t)(2147483647))
 #endif
 
-#define POOL_NOISY(x) //x
+#define STRING_POOL_NOISY(x) //x
 #define XML_NOISY(x) //x
 #define TABLE_NOISY(x) //x
 #define TABLE_GETENTRY(x) //x
@@ -379,7 +378,6 @@
         size_t charSize;
         if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
             charSize = sizeof(uint8_t);
-            mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
         } else {
             charSize = sizeof(char16_t);
         }
@@ -594,6 +592,23 @@
                 if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
                     AutoMutex lock(mDecodeLock);
 
+                    if (mCache == NULL) {
+#ifndef HAVE_ANDROID_OS
+                        STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes",
+                                mHeader->stringCount*sizeof(char16_t**)));
+#else
+                        // We do not want to be in this case when actually running Android.
+                        ALOGW("CREATING STRING CACHE OF %d bytes",
+                                mHeader->stringCount*sizeof(char16_t**));
+#endif
+                        mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
+                        if (mCache == NULL) {
+                            ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
+                                    (int)(mHeader->stringCount*sizeof(char16_t**)));
+                            return NULL;
+                        }
+                    }
+
                     if (mCache[idx] != NULL) {
                         return mCache[idx];
                     }
@@ -613,6 +628,7 @@
                         return NULL;
                     }
 
+                    STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str));
                     utf8_to_utf16(u8str, u8len, u16str);
                     mCache[idx] = u16str;
                     return u16str;
@@ -634,20 +650,20 @@
 const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
 {
     if (mError == NO_ERROR && idx < mHeader->stringCount) {
-        const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
-        const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
+        if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
+            return NULL;
+        }
+        const uint32_t off = mEntries[idx]/sizeof(char);
         if (off < (mStringPoolSize-1)) {
-            if (isUTF8) {
-                const uint8_t* strings = (uint8_t*)mStrings;
-                const uint8_t* str = strings+off;
-                *outLen = decodeLength(&str);
-                size_t encLen = decodeLength(&str);
-                if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
-                    return (const char*)str;
-                } else {
-                    ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
-                            (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
-                }
+            const uint8_t* strings = (uint8_t*)mStrings;
+            const uint8_t* str = strings+off;
+            *outLen = decodeLength(&str);
+            size_t encLen = decodeLength(&str);
+            if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+                return (const char*)str;
+            } else {
+                ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+                        (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
             }
         } else {
             ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
@@ -696,45 +712,104 @@
 
     size_t len;
 
-    // TODO optimize searching for UTF-8 strings taking into account
-    // the cache fill to determine when to convert the searched-for
-    // string key to UTF-8.
+    if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
+        STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string()));
 
-    if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
-        // Do a binary search for the string...
-        ssize_t l = 0;
-        ssize_t h = mHeader->stringCount-1;
+        // The string pool contains UTF 8 strings; we don't want to cause
+        // temporary UTF-16 strings to be created as we search.
+        if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+            // Do a binary search for the string...  this is a little tricky,
+            // because the strings are sorted with strzcmp16().  So to match
+            // the ordering, we need to convert strings in the pool to UTF-16.
+            // But we don't want to hit the cache, so instead we will have a
+            // local temporary allocation for the conversions.
+            char16_t* convBuffer = (char16_t*)malloc(strLen+4);
+            ssize_t l = 0;
+            ssize_t h = mHeader->stringCount-1;
 
-        ssize_t mid;
-        while (l <= h) {
-            mid = l + (h - l)/2;
-            const char16_t* s = stringAt(mid, &len);
-            int c = s ? strzcmp16(s, len, str, strLen) : -1;
-            POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
-                         String8(str).string(),
-                         String8(s).string(),
-                         c, (int)l, (int)mid, (int)h));
-            if (c == 0) {
-                return mid;
-            } else if (c < 0) {
-                l = mid + 1;
-            } else {
-                h = mid - 1;
+            ssize_t mid;
+            while (l <= h) {
+                mid = l + (h - l)/2;
+                const uint8_t* s = (const uint8_t*)string8At(mid, &len);
+                int c;
+                if (s != NULL) {
+                    char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3);
+                    *end = 0;
+                    c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
+                } else {
+                    c = -1;
+                }
+                STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                             (const char*)s, c, (int)l, (int)mid, (int)h));
+                if (c == 0) {
+                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    free(convBuffer);
+                    return mid;
+                } else if (c < 0) {
+                    l = mid + 1;
+                } else {
+                    h = mid - 1;
+                }
+            }
+            free(convBuffer);
+        } else {
+            // It is unusual to get the ID from an unsorted string block...
+            // most often this happens because we want to get IDs for style
+            // span tags; since those always appear at the end of the string
+            // block, start searching at the back.
+            String8 str8(str, strLen);
+            const size_t str8Len = str8.size();
+            for (int i=mHeader->stringCount-1; i>=0; i--) {
+                const char* s = string8At(i, &len);
+                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
+                             String8(s).string(),
+                             i));
+                if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
+                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    return i;
+                }
             }
         }
+
     } else {
-        // It is unusual to get the ID from an unsorted string block...
-        // most often this happens because we want to get IDs for style
-        // span tags; since those always appear at the end of the string
-        // block, start searching at the back.
-        for (int i=mHeader->stringCount-1; i>=0; i--) {
-            const char16_t* s = stringAt(i, &len);
-            POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
-                         String8(str, strLen).string(),
-                         String8(s).string(),
-                         i));
-            if (s && strzcmp16(s, len, str, strLen) == 0) {
-                return i;
+        STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()));
+
+        if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+            // Do a binary search for the string...
+            ssize_t l = 0;
+            ssize_t h = mHeader->stringCount-1;
+
+            ssize_t mid;
+            while (l <= h) {
+                mid = l + (h - l)/2;
+                const char16_t* s = stringAt(mid, &len);
+                int c = s ? strzcmp16(s, len, str, strLen) : -1;
+                STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                             String8(s).string(),
+                             c, (int)l, (int)mid, (int)h));
+                if (c == 0) {
+                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    return mid;
+                } else if (c < 0) {
+                    l = mid + 1;
+                } else {
+                    h = mid - 1;
+                }
+            }
+        } else {
+            // It is unusual to get the ID from an unsorted string block...
+            // most often this happens because we want to get IDs for style
+            // span tags; since those always appear at the end of the string
+            // block, start searching at the back.
+            for (int i=mHeader->stringCount-1; i>=0; i--) {
+                const char16_t* s = stringAt(i, &len);
+                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
+                             String8(s).string(),
+                             i));
+                if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
+                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    return i;
+                }
             }
         }
     }
@@ -937,6 +1012,14 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
+const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
+{
+    int32_t id = getAttributeNamespaceID(idx);
+    //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
+    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+    return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+}
+
 int32_t ResXMLParser::getAttributeNameID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
@@ -960,6 +1043,14 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
+const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
+{
+    int32_t id = getAttributeNameID(idx);
+    //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
+    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+    return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+}
+
 uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
 {
     int32_t id = getAttributeNameID(idx);
@@ -1049,22 +1140,67 @@
                                        const char16_t* attr, size_t attrLen) const
 {
     if (mEventCode == START_TAG) {
+        if (attr == NULL) {
+            return NAME_NOT_FOUND;
+        }
         const size_t N = getAttributeCount();
-        for (size_t i=0; i<N; i++) {
-            size_t curNsLen, curAttrLen;
-            const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
-            const char16_t* curAttr = getAttributeName(i, &curAttrLen);
-            //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
-            //       i, ns, attr, curNs, curAttr);
-            //printf(" --> attr=%s, curAttr=%s\n",
-            //       String8(attr).string(), String8(curAttr).string());
-            if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
-                if (ns == NULL) {
-                    if (curNs == NULL) return i;
-                } else if (curNs != NULL) {
-                    //printf(" --> ns=%s, curNs=%s\n",
-                    //       String8(ns).string(), String8(curNs).string());
-                    if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
+        if (mTree.mStrings.isUTF8()) {
+            String8 ns8, attr8;
+            if (ns != NULL) {
+                ns8 = String8(ns, nsLen);
+            }
+            attr8 = String8(attr, attrLen);
+            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen,
+                    attr8.string(), attrLen));
+            for (size_t i=0; i<N; i++) {
+                size_t curNsLen = 0, curAttrLen = 0;
+                const char* curNs = getAttributeNamespace8(i, &curNsLen);
+                const char* curAttr = getAttributeName8(i, &curAttrLen);
+                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen,
+                        curAttr, curAttrLen));
+                if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
+                        && memcmp(attr8.string(), curAttr, attrLen) == 0) {
+                    if (ns == NULL) {
+                        if (curNs == NULL) {
+                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            return i;
+                        }
+                    } else if (curNs != NULL) {
+                        //printf(" --> ns=%s, curNs=%s\n",
+                        //       String8(ns).string(), String8(curNs).string());
+                        if (memcmp(ns8.string(), curNs, nsLen) == 0) {
+                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            return i;
+                        }
+                    }
+                }
+            }
+        } else {
+            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)",
+                    String8(ns, nsLen).string(), nsLen,
+                    String8(attr, attrLen).string(), attrLen));
+            for (size_t i=0; i<N; i++) {
+                size_t curNsLen = 0, curAttrLen = 0;
+                const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
+                const char16_t* curAttr = getAttributeName(i, &curAttrLen);
+                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)",
+                        String8(curNs, curNsLen).string(), curNsLen,
+                        String8(curAttr, curAttrLen).string(), curAttrLen));
+                if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
+                        && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
+                    if (ns == NULL) {
+                        if (curNs == NULL) {
+                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            return i;
+                        }
+                    } else if (curNs != NULL) {
+                        //printf(" --> ns=%s, curNs=%s\n",
+                        //       String8(ns).string(), String8(curNs).string());
+                        if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
+                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            return i;
+                        }
+                    }
                 }
             }
         }
@@ -2941,7 +3077,7 @@
     mHeaders.clear();
 }
 
-bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
+bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
 {
     if (mError != NO_ERROR) {
         return false;
@@ -2981,13 +3117,28 @@
 
         outName->package = grp->name.string();
         outName->packageLen = grp->name.size();
-        outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
-        outName->name = grp->basePackage->keyStrings.stringAt(
-            dtohl(entry->key.index), &outName->nameLen);
-
-        // If we have a bad index for some reason, we should abort.
-        if (outName->type == NULL || outName->name == NULL) {
-            return false;
+        if (allowUtf8) {
+            outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen);
+            outName->name8 = grp->basePackage->keyStrings.string8At(
+                dtohl(entry->key.index), &outName->nameLen);
+        } else {
+            outName->type8 = NULL;
+            outName->name8 = NULL;
+        }
+        if (outName->type8 == NULL) {
+            outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
+            // If we have a bad index for some reason, we should abort.
+            if (outName->type == NULL) {
+                return false;
+            }
+        }
+        if (outName->name8 == NULL) {
+            outName->name = grp->basePackage->keyStrings.stringAt(
+                dtohl(entry->key.index), &outName->nameLen);
+            // If we have a bad index for some reason, we should abort.
+            if (outName->name == NULL) {
+                return false;
+            }
         }
 
         return true;
@@ -4486,7 +4637,7 @@
             while (cnt > 0) {
                 if (!Res_INTERNALID(bag->map.name.ident)) {
                     //printf("Trying attr #%08x\n", bag->map.name.ident);
-                    if (getResourceName(bag->map.name.ident, &rname)) {
+                    if (getResourceName(bag->map.name.ident, false, &rname)) {
                         #if 0
                         printf("Matching %s against %s (0x%08x)\n",
                                String8(s, len).string(),
@@ -4539,7 +4690,7 @@
                 for (i=0; i<cnt; i++, bagi++) {
                     if (!Res_INTERNALID(bagi->map.name.ident)) {
                         //printf("Trying attr #%08x\n", bagi->map.name.ident);
-                        if (getResourceName(bagi->map.name.ident, &rname)) {
+                        if (getResourceName(bagi->map.name.ident, false, &rname)) {
                             #if 0
                             printf("Matching %s against %s (0x%08x)\n",
                                    String8(start,pos-start).string(),
@@ -5217,7 +5368,7 @@
                 | (0x00ff0000 & ((typeIndex+1)<<16))
                 | (0x0000ffff & (entryIndex));
             resource_name resName;
-            if (!this->getResourceName(resID, &resName)) {
+            if (!this->getResourceName(resID, true, &resName)) {
                 ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
                 // add dummy value, or trimming leading/trailing zeroes later will fail
                 vector.push(0);
@@ -5324,13 +5475,12 @@
 }
 
 
-#ifndef HAVE_ANDROID_OS
 #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
 
 #define CHAR16_ARRAY_EQ(constant, var, len) \
         ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
 
-void print_complex(uint32_t complex, bool isFraction)
+static void print_complex(uint32_t complex, bool isFraction)
 {
     const float MANTISSA_MULT =
         1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
@@ -5485,12 +5635,23 @@
                                     | (0x00ff0000 & ((typeIndex+1)<<16))
                                     | (0x0000ffff & (entryIndex));
                         resource_name resName;
-                        if (this->getResourceName(resID, &resName)) {
+                        if (this->getResourceName(resID, true, &resName)) {
+                            String8 type8;
+                            String8 name8;
+                            if (resName.type8 != NULL) {
+                                type8 = String8(resName.type8, resName.typeLen);
+                            } else {
+                                type8 = String8(resName.type, resName.typeLen);
+                            }
+                            if (resName.name8 != NULL) {
+                                name8 = String8(resName.name8, resName.nameLen);
+                            } else {
+                                name8 = String8(resName.name, resName.nameLen);
+                            }
                             printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
                                 resID,
                                 CHAR16_TO_CSTR(resName.package, resName.packageLen),
-                                CHAR16_TO_CSTR(resName.type, resName.typeLen),
-                                CHAR16_TO_CSTR(resName.name, resName.nameLen),
+                                type8.string(), name8.string(),
                                 dtohl(typeConfigs->typeSpecFlags[entryIndex]));
                         } else {
                             printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
@@ -5533,11 +5694,22 @@
                                     | (0x00ff0000 & ((typeIndex+1)<<16))
                                     | (0x0000ffff & (entryIndex));
                         resource_name resName;
-                        if (this->getResourceName(resID, &resName)) {
+                        if (this->getResourceName(resID, true, &resName)) {
+                            String8 type8;
+                            String8 name8;
+                            if (resName.type8 != NULL) {
+                                type8 = String8(resName.type8, resName.typeLen);
+                            } else {
+                                type8 = String8(resName.type, resName.typeLen);
+                            }
+                            if (resName.name8 != NULL) {
+                                name8 = String8(resName.name8, resName.nameLen);
+                            } else {
+                                name8 = String8(resName.name, resName.nameLen);
+                            }
                             printf("        resource 0x%08x %s:%s/%s: ", resID,
                                     CHAR16_TO_CSTR(resName.package, resName.packageLen),
-                                    CHAR16_TO_CSTR(resName.type, resName.typeLen),
-                                    CHAR16_TO_CSTR(resName.name, resName.nameLen));
+                                    type8.string(), name8.string());
                         } else {
                             printf("        INVALID RESOURCE 0x%08x: ", resID);
                         }
@@ -5621,6 +5793,4 @@
     }
 }
 
-#endif // HAVE_ANDROID_OS
-
 }   // namespace android
diff --git a/libs/androidfw/VelocityControl.cpp b/libs/androidfw/VelocityControl.cpp
deleted file mode 100644
index cde2b76..0000000
--- a/libs/androidfw/VelocityControl.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VelocityControl"
-//#define LOG_NDEBUG 0
-
-// Log debug messages about acceleration.
-#define DEBUG_ACCELERATION 0
-
-#include <math.h>
-#include <limits.h>
-
-#include <androidfw/VelocityControl.h>
-#include <utils/BitSet.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-// --- VelocityControl ---
-
-const nsecs_t VelocityControl::STOP_TIME;
-
-VelocityControl::VelocityControl() {
-    reset();
-}
-
-void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
-    mParameters = parameters;
-    reset();
-}
-
-void VelocityControl::reset() {
-    mLastMovementTime = LLONG_MIN;
-    mRawPosition.x = 0;
-    mRawPosition.y = 0;
-    mVelocityTracker.clear();
-}
-
-void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
-    if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
-        if (eventTime >= mLastMovementTime + STOP_TIME) {
-#if DEBUG_ACCELERATION
-            ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
-                    (eventTime - mLastMovementTime) * 0.000001f);
-#endif
-            reset();
-        }
-
-        mLastMovementTime = eventTime;
-        if (deltaX) {
-            mRawPosition.x += *deltaX;
-        }
-        if (deltaY) {
-            mRawPosition.y += *deltaY;
-        }
-        mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
-
-        float vx, vy;
-        float scale = mParameters.scale;
-        if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
-            float speed = hypotf(vx, vy) * scale;
-            if (speed >= mParameters.highThreshold) {
-                // Apply full acceleration above the high speed threshold.
-                scale *= mParameters.acceleration;
-            } else if (speed > mParameters.lowThreshold) {
-                // Linearly interpolate the acceleration to apply between the low and high
-                // speed thresholds.
-                scale *= 1 + (speed - mParameters.lowThreshold)
-                        / (mParameters.highThreshold - mParameters.lowThreshold)
-                        * (mParameters.acceleration - 1);
-            }
-
-#if DEBUG_ACCELERATION
-            ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
-                    "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
-                    mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
-                    mParameters.acceleration,
-                    vx, vy, speed, scale / mParameters.scale);
-#endif
-        } else {
-#if DEBUG_ACCELERATION
-            ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
-                    mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
-                    mParameters.acceleration);
-#endif
-        }
-
-        if (deltaX) {
-            *deltaX *= scale;
-        }
-        if (deltaY) {
-            *deltaY *= scale;
-        }
-    }
-}
-
-} // namespace android
diff --git a/libs/androidfw/VelocityTracker.cpp b/libs/androidfw/VelocityTracker.cpp
deleted file mode 100644
index f48ec62..0000000
--- a/libs/androidfw/VelocityTracker.cpp
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VelocityTracker"
-//#define LOG_NDEBUG 0
-
-// Log debug messages about velocity tracking.
-#define DEBUG_VELOCITY 0
-
-// Log debug messages about the progress of the algorithm itself.
-#define DEBUG_STRATEGY 0
-
-#include <math.h>
-#include <limits.h>
-
-#include <androidfw/VelocityTracker.h>
-#include <utils/BitSet.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
-#include <cutils/properties.h>
-
-namespace android {
-
-// Nanoseconds per milliseconds.
-static const nsecs_t NANOS_PER_MS = 1000000;
-
-// Threshold for determining that a pointer has stopped moving.
-// Some input devices do not send ACTION_MOVE events in the case where a pointer has
-// stopped.  We need to detect this case so that we can accurately predict the
-// velocity after the pointer starts moving again.
-static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;
-
-
-static float vectorDot(const float* a, const float* b, uint32_t m) {
-    float r = 0;
-    while (m--) {
-        r += *(a++) * *(b++);
-    }
-    return r;
-}
-
-static float vectorNorm(const float* a, uint32_t m) {
-    float r = 0;
-    while (m--) {
-        float t = *(a++);
-        r += t * t;
-    }
-    return sqrtf(r);
-}
-
-#if DEBUG_STRATEGY || DEBUG_VELOCITY
-static String8 vectorToString(const float* a, uint32_t m) {
-    String8 str;
-    str.append("[");
-    while (m--) {
-        str.appendFormat(" %f", *(a++));
-        if (m) {
-            str.append(",");
-        }
-    }
-    str.append(" ]");
-    return str;
-}
-
-static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
-    String8 str;
-    str.append("[");
-    for (size_t i = 0; i < m; i++) {
-        if (i) {
-            str.append(",");
-        }
-        str.append(" [");
-        for (size_t j = 0; j < n; j++) {
-            if (j) {
-                str.append(",");
-            }
-            str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
-        }
-        str.append(" ]");
-    }
-    str.append(" ]");
-    return str;
-}
-#endif
-
-
-// --- VelocityTracker ---
-
-// The default velocity tracker strategy.
-// Although other strategies are available for testing and comparison purposes,
-// this is the strategy that applications will actually use.  Be very careful
-// when adjusting the default strategy because it can dramatically affect
-// (often in a bad way) the user experience.
-const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
-
-VelocityTracker::VelocityTracker(const char* strategy) :
-        mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
-    char value[PROPERTY_VALUE_MAX];
-
-    // Allow the default strategy to be overridden using a system property for debugging.
-    if (!strategy) {
-        int length = property_get("debug.velocitytracker.strategy", value, NULL);
-        if (length > 0) {
-            strategy = value;
-        } else {
-            strategy = DEFAULT_STRATEGY;
-        }
-    }
-
-    // Configure the strategy.
-    if (!configureStrategy(strategy)) {
-        ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy);
-        if (!configureStrategy(DEFAULT_STRATEGY)) {
-            LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!",
-                    strategy);
-        }
-    }
-}
-
-VelocityTracker::~VelocityTracker() {
-    delete mStrategy;
-}
-
-bool VelocityTracker::configureStrategy(const char* strategy) {
-    mStrategy = createStrategy(strategy);
-    return mStrategy != NULL;
-}
-
-VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
-    if (!strcmp("lsq1", strategy)) {
-        // 1st order least squares.  Quality: POOR.
-        // Frequently underfits the touch data especially when the finger accelerates
-        // or changes direction.  Often underestimates velocity.  The direction
-        // is overly influenced by historical touch points.
-        return new LeastSquaresVelocityTrackerStrategy(1);
-    }
-    if (!strcmp("lsq2", strategy)) {
-        // 2nd order least squares.  Quality: VERY GOOD.
-        // Pretty much ideal, but can be confused by certain kinds of touch data,
-        // particularly if the panel has a tendency to generate delayed,
-        // duplicate or jittery touch coordinates when the finger is released.
-        return new LeastSquaresVelocityTrackerStrategy(2);
-    }
-    if (!strcmp("lsq3", strategy)) {
-        // 3rd order least squares.  Quality: UNUSABLE.
-        // Frequently overfits the touch data yielding wildly divergent estimates
-        // of the velocity when the finger is released.
-        return new LeastSquaresVelocityTrackerStrategy(3);
-    }
-    if (!strcmp("wlsq2-delta", strategy)) {
-        // 2nd order weighted least squares, delta weighting.  Quality: EXPERIMENTAL
-        return new LeastSquaresVelocityTrackerStrategy(2,
-                LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA);
-    }
-    if (!strcmp("wlsq2-central", strategy)) {
-        // 2nd order weighted least squares, central weighting.  Quality: EXPERIMENTAL
-        return new LeastSquaresVelocityTrackerStrategy(2,
-                LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL);
-    }
-    if (!strcmp("wlsq2-recent", strategy)) {
-        // 2nd order weighted least squares, recent weighting.  Quality: EXPERIMENTAL
-        return new LeastSquaresVelocityTrackerStrategy(2,
-                LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT);
-    }
-    if (!strcmp("int1", strategy)) {
-        // 1st order integrating filter.  Quality: GOOD.
-        // Not as good as 'lsq2' because it cannot estimate acceleration but it is
-        // more tolerant of errors.  Like 'lsq1', this strategy tends to underestimate
-        // the velocity of a fling but this strategy tends to respond to changes in
-        // direction more quickly and accurately.
-        return new IntegratingVelocityTrackerStrategy(1);
-    }
-    if (!strcmp("int2", strategy)) {
-        // 2nd order integrating filter.  Quality: EXPERIMENTAL.
-        // For comparison purposes only.  Unlike 'int1' this strategy can compensate
-        // for acceleration but it typically overestimates the effect.
-        return new IntegratingVelocityTrackerStrategy(2);
-    }
-    if (!strcmp("legacy", strategy)) {
-        // Legacy velocity tracker algorithm.  Quality: POOR.
-        // For comparison purposes only.  This algorithm is strongly influenced by
-        // old data points, consistently underestimates velocity and takes a very long
-        // time to adjust to changes in direction.
-        return new LegacyVelocityTrackerStrategy();
-    }
-    return NULL;
-}
-
-void VelocityTracker::clear() {
-    mCurrentPointerIdBits.clear();
-    mActivePointerId = -1;
-
-    mStrategy->clear();
-}
-
-void VelocityTracker::clearPointers(BitSet32 idBits) {
-    BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value);
-    mCurrentPointerIdBits = remainingIdBits;
-
-    if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
-        mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
-    }
-
-    mStrategy->clearPointers(idBits);
-}
-
-void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
-    while (idBits.count() > MAX_POINTERS) {
-        idBits.clearLastMarkedBit();
-    }
-
-    if ((mCurrentPointerIdBits.value & idBits.value)
-            && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
-#if DEBUG_VELOCITY
-        ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
-                (eventTime - mLastEventTime) * 0.000001f);
-#endif
-        // We have not received any movements for too long.  Assume that all pointers
-        // have stopped.
-        mStrategy->clear();
-    }
-    mLastEventTime = eventTime;
-
-    mCurrentPointerIdBits = idBits;
-    if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
-        mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
-    }
-
-    mStrategy->addMovement(eventTime, idBits, positions);
-
-#if DEBUG_VELOCITY
-    ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
-            eventTime, idBits.value, mActivePointerId);
-    for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
-        uint32_t id = iterBits.firstMarkedBit();
-        uint32_t index = idBits.getIndexOfBit(id);
-        iterBits.clearBit(id);
-        Estimator estimator;
-        getEstimator(id, &estimator);
-        ALOGD("  %d: position (%0.3f, %0.3f), "
-                "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
-                id, positions[index].x, positions[index].y,
-                int(estimator.degree),
-                vectorToString(estimator.xCoeff, estimator.degree + 1).string(),
-                vectorToString(estimator.yCoeff, estimator.degree + 1).string(),
-                estimator.confidence);
-    }
-#endif
-}
-
-void VelocityTracker::addMovement(const MotionEvent* event) {
-    int32_t actionMasked = event->getActionMasked();
-
-    switch (actionMasked) {
-    case AMOTION_EVENT_ACTION_DOWN:
-    case AMOTION_EVENT_ACTION_HOVER_ENTER:
-        // Clear all pointers on down before adding the new movement.
-        clear();
-        break;
-    case AMOTION_EVENT_ACTION_POINTER_DOWN: {
-        // Start a new movement trace for a pointer that just went down.
-        // We do this on down instead of on up because the client may want to query the
-        // final velocity for a pointer that just went up.
-        BitSet32 downIdBits;
-        downIdBits.markBit(event->getPointerId(event->getActionIndex()));
-        clearPointers(downIdBits);
-        break;
-    }
-    case AMOTION_EVENT_ACTION_MOVE:
-    case AMOTION_EVENT_ACTION_HOVER_MOVE:
-        break;
-    default:
-        // Ignore all other actions because they do not convey any new information about
-        // pointer movement.  We also want to preserve the last known velocity of the pointers.
-        // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
-        // of the pointers that went up.  ACTION_POINTER_UP does include the new position of
-        // pointers that remained down but we will also receive an ACTION_MOVE with this
-        // information if any of them actually moved.  Since we don't know how many pointers
-        // will be going up at once it makes sense to just wait for the following ACTION_MOVE
-        // before adding the movement.
-        return;
-    }
-
-    size_t pointerCount = event->getPointerCount();
-    if (pointerCount > MAX_POINTERS) {
-        pointerCount = MAX_POINTERS;
-    }
-
-    BitSet32 idBits;
-    for (size_t i = 0; i < pointerCount; i++) {
-        idBits.markBit(event->getPointerId(i));
-    }
-
-    uint32_t pointerIndex[MAX_POINTERS];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
-    }
-
-    nsecs_t eventTime;
-    Position positions[pointerCount];
-
-    size_t historySize = event->getHistorySize();
-    for (size_t h = 0; h < historySize; h++) {
-        eventTime = event->getHistoricalEventTime(h);
-        for (size_t i = 0; i < pointerCount; i++) {
-            uint32_t index = pointerIndex[i];
-            positions[index].x = event->getHistoricalX(i, h);
-            positions[index].y = event->getHistoricalY(i, h);
-        }
-        addMovement(eventTime, idBits, positions);
-    }
-
-    eventTime = event->getEventTime();
-    for (size_t i = 0; i < pointerCount; i++) {
-        uint32_t index = pointerIndex[i];
-        positions[index].x = event->getX(i);
-        positions[index].y = event->getY(i);
-    }
-    addMovement(eventTime, idBits, positions);
-}
-
-bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
-    Estimator estimator;
-    if (getEstimator(id, &estimator) && estimator.degree >= 1) {
-        *outVx = estimator.xCoeff[1];
-        *outVy = estimator.yCoeff[1];
-        return true;
-    }
-    *outVx = 0;
-    *outVy = 0;
-    return false;
-}
-
-bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const {
-    return mStrategy->getEstimator(id, outEstimator);
-}
-
-
-// --- LeastSquaresVelocityTrackerStrategy ---
-
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
-LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
-        uint32_t degree, Weighting weighting) :
-        mDegree(degree), mWeighting(weighting) {
-    clear();
-}
-
-LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {
-}
-
-void LeastSquaresVelocityTrackerStrategy::clear() {
-    mIndex = 0;
-    mMovements[0].idBits.clear();
-}
-
-void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
-    BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
-    mMovements[mIndex].idBits = remainingIdBits;
-}
-
-void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
-        const VelocityTracker::Position* positions) {
-    if (++mIndex == HISTORY_SIZE) {
-        mIndex = 0;
-    }
-
-    Movement& movement = mMovements[mIndex];
-    movement.eventTime = eventTime;
-    movement.idBits = idBits;
-    uint32_t count = idBits.count();
-    for (uint32_t i = 0; i < count; i++) {
-        movement.positions[i] = positions[i];
-    }
-}
-
-/**
- * Solves a linear least squares problem to obtain a N degree polynomial that fits
- * the specified input data as nearly as possible.
- *
- * Returns true if a solution is found, false otherwise.
- *
- * The input consists of two vectors of data points X and Y with indices 0..m-1
- * along with a weight vector W of the same size.
- *
- * The output is a vector B with indices 0..n that describes a polynomial
- * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i]
- * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized.
- *
- * Accordingly, the weight vector W should be initialized by the caller with the
- * reciprocal square root of the variance of the error in each input data point.
- * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]).
- * The weights express the relative importance of each data point.  If the weights are
- * all 1, then the data points are considered to be of equal importance when fitting
- * the polynomial.  It is a good idea to choose weights that diminish the importance
- * of data points that may have higher than usual error margins.
- *
- * Errors among data points are assumed to be independent.  W is represented here
- * as a vector although in the literature it is typically taken to be a diagonal matrix.
- *
- * That is to say, the function that generated the input data can be approximated
- * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
- *
- * The coefficient of determination (R^2) is also returned to describe the goodness
- * of fit of the model for the given data.  It is a value between 0 and 1, where 1
- * indicates perfect correspondence.
- *
- * This function first expands the X vector to a m by n matrix A such that
- * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then
- * multiplies it by w[i]./
- *
- * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
- * and an m by n upper triangular matrix R.  Because R is upper triangular (lower
- * part is all zeroes), we can simplify the decomposition into an m by n matrix
- * Q1 and a n by n matrix R1 such that A = Q1 R1.
- *
- * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y)
- * to find B.
- *
- * For efficiency, we lay out A and Q column-wise in memory because we frequently
- * operate on the column vectors.  Conversely, we lay out R row-wise.
- *
- * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
- * http://en.wikipedia.org/wiki/Gram-Schmidt
- */
-static bool solveLeastSquares(const float* x, const float* y,
-        const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
-#if DEBUG_STRATEGY
-    ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
-            vectorToString(x, m).string(), vectorToString(y, m).string(),
-            vectorToString(w, m).string());
-#endif
-
-    // Expand the X vector to a matrix A, pre-multiplied by the weights.
-    float a[n][m]; // column-major order
-    for (uint32_t h = 0; h < m; h++) {
-        a[0][h] = w[h];
-        for (uint32_t i = 1; i < n; i++) {
-            a[i][h] = a[i - 1][h] * x[h];
-        }
-    }
-#if DEBUG_STRATEGY
-    ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
-#endif
-
-    // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
-    float q[n][m]; // orthonormal basis, column-major order
-    float r[n][n]; // upper triangular matrix, row-major order
-    for (uint32_t j = 0; j < n; j++) {
-        for (uint32_t h = 0; h < m; h++) {
-            q[j][h] = a[j][h];
-        }
-        for (uint32_t i = 0; i < j; i++) {
-            float dot = vectorDot(&q[j][0], &q[i][0], m);
-            for (uint32_t h = 0; h < m; h++) {
-                q[j][h] -= dot * q[i][h];
-            }
-        }
-
-        float norm = vectorNorm(&q[j][0], m);
-        if (norm < 0.000001f) {
-            // vectors are linearly dependent or zero so no solution
-#if DEBUG_STRATEGY
-            ALOGD("  - no solution, norm=%f", norm);
-#endif
-            return false;
-        }
-
-        float invNorm = 1.0f / norm;
-        for (uint32_t h = 0; h < m; h++) {
-            q[j][h] *= invNorm;
-        }
-        for (uint32_t i = 0; i < n; i++) {
-            r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
-        }
-    }
-#if DEBUG_STRATEGY
-    ALOGD("  - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
-    ALOGD("  - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
-
-    // calculate QR, if we factored A correctly then QR should equal A
-    float qr[n][m];
-    for (uint32_t h = 0; h < m; h++) {
-        for (uint32_t i = 0; i < n; i++) {
-            qr[i][h] = 0;
-            for (uint32_t j = 0; j < n; j++) {
-                qr[i][h] += q[j][h] * r[j][i];
-            }
-        }
-    }
-    ALOGD("  - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
-#endif
-
-    // Solve R B = Qt W Y to find B.  This is easy because R is upper triangular.
-    // We just work from bottom-right to top-left calculating B's coefficients.
-    float wy[m];
-    for (uint32_t h = 0; h < m; h++) {
-        wy[h] = y[h] * w[h];
-    }
-    for (uint32_t i = n; i-- != 0; ) {
-        outB[i] = vectorDot(&q[i][0], wy, m);
-        for (uint32_t j = n - 1; j > i; j--) {
-            outB[i] -= r[i][j] * outB[j];
-        }
-        outB[i] /= r[i][i];
-    }
-#if DEBUG_STRATEGY
-    ALOGD("  - b=%s", vectorToString(outB, n).string());
-#endif
-
-    // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
-    // SSerr is the residual sum of squares (variance of the error),
-    // and SStot is the total sum of squares (variance of the data) where each
-    // has been weighted.
-    float ymean = 0;
-    for (uint32_t h = 0; h < m; h++) {
-        ymean += y[h];
-    }
-    ymean /= m;
-
-    float sserr = 0;
-    float sstot = 0;
-    for (uint32_t h = 0; h < m; h++) {
-        float err = y[h] - outB[0];
-        float term = 1;
-        for (uint32_t i = 1; i < n; i++) {
-            term *= x[h];
-            err -= term * outB[i];
-        }
-        sserr += w[h] * w[h] * err * err;
-        float var = y[h] - ymean;
-        sstot += w[h] * w[h] * var * var;
-    }
-    *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
-#if DEBUG_STRATEGY
-    ALOGD("  - sserr=%f", sserr);
-    ALOGD("  - sstot=%f", sstot);
-    ALOGD("  - det=%f", *outDet);
-#endif
-    return true;
-}
-
-bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
-        VelocityTracker::Estimator* outEstimator) const {
-    outEstimator->clear();
-
-    // Iterate over movement samples in reverse time order and collect samples.
-    float x[HISTORY_SIZE];
-    float y[HISTORY_SIZE];
-    float w[HISTORY_SIZE];
-    float time[HISTORY_SIZE];
-    uint32_t m = 0;
-    uint32_t index = mIndex;
-    const Movement& newestMovement = mMovements[mIndex];
-    do {
-        const Movement& movement = mMovements[index];
-        if (!movement.idBits.hasBit(id)) {
-            break;
-        }
-
-        nsecs_t age = newestMovement.eventTime - movement.eventTime;
-        if (age > HORIZON) {
-            break;
-        }
-
-        const VelocityTracker::Position& position = movement.getPosition(id);
-        x[m] = position.x;
-        y[m] = position.y;
-        w[m] = chooseWeight(index);
-        time[m] = -age * 0.000000001f;
-        index = (index == 0 ? HISTORY_SIZE : index) - 1;
-    } while (++m < HISTORY_SIZE);
-
-    if (m == 0) {
-        return false; // no data
-    }
-
-    // Calculate a least squares polynomial fit.
-    uint32_t degree = mDegree;
-    if (degree > m - 1) {
-        degree = m - 1;
-    }
-    if (degree >= 1) {
-        float xdet, ydet;
-        uint32_t n = degree + 1;
-        if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
-                && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) {
-            outEstimator->time = newestMovement.eventTime;
-            outEstimator->degree = degree;
-            outEstimator->confidence = xdet * ydet;
-#if DEBUG_STRATEGY
-            ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
-                    int(outEstimator->degree),
-                    vectorToString(outEstimator->xCoeff, n).string(),
-                    vectorToString(outEstimator->yCoeff, n).string(),
-                    outEstimator->confidence);
-#endif
-            return true;
-        }
-    }
-
-    // No velocity data available for this pointer, but we do have its current position.
-    outEstimator->xCoeff[0] = x[0];
-    outEstimator->yCoeff[0] = y[0];
-    outEstimator->time = newestMovement.eventTime;
-    outEstimator->degree = 0;
-    outEstimator->confidence = 1;
-    return true;
-}
-
-float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const {
-    switch (mWeighting) {
-    case WEIGHTING_DELTA: {
-        // Weight points based on how much time elapsed between them and the next
-        // point so that points that "cover" a shorter time span are weighed less.
-        //   delta  0ms: 0.5
-        //   delta 10ms: 1.0
-        if (index == mIndex) {
-            return 1.0f;
-        }
-        uint32_t nextIndex = (index + 1) % HISTORY_SIZE;
-        float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime)
-                * 0.000001f;
-        if (deltaMillis < 0) {
-            return 0.5f;
-        }
-        if (deltaMillis < 10) {
-            return 0.5f + deltaMillis * 0.05;
-        }
-        return 1.0f;
-    }
-
-    case WEIGHTING_CENTRAL: {
-        // Weight points based on their age, weighing very recent and very old points less.
-        //   age  0ms: 0.5
-        //   age 10ms: 1.0
-        //   age 50ms: 1.0
-        //   age 60ms: 0.5
-        float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime)
-                * 0.000001f;
-        if (ageMillis < 0) {
-            return 0.5f;
-        }
-        if (ageMillis < 10) {
-            return 0.5f + ageMillis * 0.05;
-        }
-        if (ageMillis < 50) {
-            return 1.0f;
-        }
-        if (ageMillis < 60) {
-            return 0.5f + (60 - ageMillis) * 0.05;
-        }
-        return 0.5f;
-    }
-
-    case WEIGHTING_RECENT: {
-        // Weight points based on their age, weighing older points less.
-        //   age   0ms: 1.0
-        //   age  50ms: 1.0
-        //   age 100ms: 0.5
-        float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime)
-                * 0.000001f;
-        if (ageMillis < 50) {
-            return 1.0f;
-        }
-        if (ageMillis < 100) {
-            return 0.5f + (100 - ageMillis) * 0.01f;
-        }
-        return 0.5f;
-    }
-
-    case WEIGHTING_NONE:
-    default:
-        return 1.0f;
-    }
-}
-
-
-// --- IntegratingVelocityTrackerStrategy ---
-
-IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) :
-        mDegree(degree) {
-}
-
-IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
-}
-
-void IntegratingVelocityTrackerStrategy::clear() {
-    mPointerIdBits.clear();
-}
-
-void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
-    mPointerIdBits.value &= ~idBits.value;
-}
-
-void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
-        const VelocityTracker::Position* positions) {
-    uint32_t index = 0;
-    for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
-        uint32_t id = iterIdBits.clearFirstMarkedBit();
-        State& state = mPointerState[id];
-        const VelocityTracker::Position& position = positions[index++];
-        if (mPointerIdBits.hasBit(id)) {
-            updateState(state, eventTime, position.x, position.y);
-        } else {
-            initState(state, eventTime, position.x, position.y);
-        }
-    }
-
-    mPointerIdBits = idBits;
-}
-
-bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id,
-        VelocityTracker::Estimator* outEstimator) const {
-    outEstimator->clear();
-
-    if (mPointerIdBits.hasBit(id)) {
-        const State& state = mPointerState[id];
-        populateEstimator(state, outEstimator);
-        return true;
-    }
-
-    return false;
-}
-
-void IntegratingVelocityTrackerStrategy::initState(State& state,
-        nsecs_t eventTime, float xpos, float ypos) const {
-    state.updateTime = eventTime;
-    state.degree = 0;
-
-    state.xpos = xpos;
-    state.xvel = 0;
-    state.xaccel = 0;
-    state.ypos = ypos;
-    state.yvel = 0;
-    state.yaccel = 0;
-}
-
-void IntegratingVelocityTrackerStrategy::updateState(State& state,
-        nsecs_t eventTime, float xpos, float ypos) const {
-    const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
-    const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
-
-    if (eventTime <= state.updateTime + MIN_TIME_DELTA) {
-        return;
-    }
-
-    float dt = (eventTime - state.updateTime) * 0.000000001f;
-    state.updateTime = eventTime;
-
-    float xvel = (xpos - state.xpos) / dt;
-    float yvel = (ypos - state.ypos) / dt;
-    if (state.degree == 0) {
-        state.xvel = xvel;
-        state.yvel = yvel;
-        state.degree = 1;
-    } else {
-        float alpha = dt / (FILTER_TIME_CONSTANT + dt);
-        if (mDegree == 1) {
-            state.xvel += (xvel - state.xvel) * alpha;
-            state.yvel += (yvel - state.yvel) * alpha;
-        } else {
-            float xaccel = (xvel - state.xvel) / dt;
-            float yaccel = (yvel - state.yvel) / dt;
-            if (state.degree == 1) {
-                state.xaccel = xaccel;
-                state.yaccel = yaccel;
-                state.degree = 2;
-            } else {
-                state.xaccel += (xaccel - state.xaccel) * alpha;
-                state.yaccel += (yaccel - state.yaccel) * alpha;
-            }
-            state.xvel += (state.xaccel * dt) * alpha;
-            state.yvel += (state.yaccel * dt) * alpha;
-        }
-    }
-    state.xpos = xpos;
-    state.ypos = ypos;
-}
-
-void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
-        VelocityTracker::Estimator* outEstimator) const {
-    outEstimator->time = state.updateTime;
-    outEstimator->confidence = 1.0f;
-    outEstimator->degree = state.degree;
-    outEstimator->xCoeff[0] = state.xpos;
-    outEstimator->xCoeff[1] = state.xvel;
-    outEstimator->xCoeff[2] = state.xaccel / 2;
-    outEstimator->yCoeff[0] = state.ypos;
-    outEstimator->yCoeff[1] = state.yvel;
-    outEstimator->yCoeff[2] = state.yaccel / 2;
-}
-
-
-// --- LegacyVelocityTrackerStrategy ---
-
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
-LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
-    clear();
-}
-
-LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() {
-}
-
-void LegacyVelocityTrackerStrategy::clear() {
-    mIndex = 0;
-    mMovements[0].idBits.clear();
-}
-
-void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
-    BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
-    mMovements[mIndex].idBits = remainingIdBits;
-}
-
-void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
-        const VelocityTracker::Position* positions) {
-    if (++mIndex == HISTORY_SIZE) {
-        mIndex = 0;
-    }
-
-    Movement& movement = mMovements[mIndex];
-    movement.eventTime = eventTime;
-    movement.idBits = idBits;
-    uint32_t count = idBits.count();
-    for (uint32_t i = 0; i < count; i++) {
-        movement.positions[i] = positions[i];
-    }
-}
-
-bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id,
-        VelocityTracker::Estimator* outEstimator) const {
-    outEstimator->clear();
-
-    const Movement& newestMovement = mMovements[mIndex];
-    if (!newestMovement.idBits.hasBit(id)) {
-        return false; // no data
-    }
-
-    // Find the oldest sample that contains the pointer and that is not older than HORIZON.
-    nsecs_t minTime = newestMovement.eventTime - HORIZON;
-    uint32_t oldestIndex = mIndex;
-    uint32_t numTouches = 1;
-    do {
-        uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
-        const Movement& nextOldestMovement = mMovements[nextOldestIndex];
-        if (!nextOldestMovement.idBits.hasBit(id)
-                || nextOldestMovement.eventTime < minTime) {
-            break;
-        }
-        oldestIndex = nextOldestIndex;
-    } while (++numTouches < HISTORY_SIZE);
-
-    // Calculate an exponentially weighted moving average of the velocity estimate
-    // at different points in time measured relative to the oldest sample.
-    // This is essentially an IIR filter.  Newer samples are weighted more heavily
-    // than older samples.  Samples at equal time points are weighted more or less
-    // equally.
-    //
-    // One tricky problem is that the sample data may be poorly conditioned.
-    // Sometimes samples arrive very close together in time which can cause us to
-    // overestimate the velocity at that time point.  Most samples might be measured
-    // 16ms apart but some consecutive samples could be only 0.5sm apart because
-    // the hardware or driver reports them irregularly or in bursts.
-    float accumVx = 0;
-    float accumVy = 0;
-    uint32_t index = oldestIndex;
-    uint32_t samplesUsed = 0;
-    const Movement& oldestMovement = mMovements[oldestIndex];
-    const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id);
-    nsecs_t lastDuration = 0;
-
-    while (numTouches-- > 1) {
-        if (++index == HISTORY_SIZE) {
-            index = 0;
-        }
-        const Movement& movement = mMovements[index];
-        nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
-
-        // If the duration between samples is small, we may significantly overestimate
-        // the velocity.  Consequently, we impose a minimum duration constraint on the
-        // samples that we include in the calculation.
-        if (duration >= MIN_DURATION) {
-            const VelocityTracker::Position& position = movement.getPosition(id);
-            float scale = 1000000000.0f / duration; // one over time delta in seconds
-            float vx = (position.x - oldestPosition.x) * scale;
-            float vy = (position.y - oldestPosition.y) * scale;
-            accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
-            accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
-            lastDuration = duration;
-            samplesUsed += 1;
-        }
-    }
-
-    // Report velocity.
-    const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id);
-    outEstimator->time = newestMovement.eventTime;
-    outEstimator->confidence = 1;
-    outEstimator->xCoeff[0] = newestPosition.x;
-    outEstimator->yCoeff[0] = newestPosition.y;
-    if (samplesUsed) {
-        outEstimator->xCoeff[1] = accumVx;
-        outEstimator->yCoeff[1] = accumVy;
-        outEstimator->degree = 1;
-    } else {
-        outEstimator->degree = 0;
-    }
-    return true;
-}
-
-} // namespace android
diff --git a/libs/androidfw/VirtualKeyMap.cpp b/libs/androidfw/VirtualKeyMap.cpp
deleted file mode 100644
index 2ba1673..0000000
--- a/libs/androidfw/VirtualKeyMap.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "VirtualKeyMap"
-
-#include <stdlib.h>
-#include <string.h>
-#include <androidfw/VirtualKeyMap.h>
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-#include <utils/Timers.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
-
-
-// --- VirtualKeyMap ---
-
-VirtualKeyMap::VirtualKeyMap() {
-}
-
-VirtualKeyMap::~VirtualKeyMap() {
-}
-
-status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
-    *outMap = NULL;
-
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
-    } else {
-        VirtualKeyMap* map = new VirtualKeyMap();
-        if (!map) {
-            ALOGE("Error allocating virtual key map.");
-            status = NO_MEMORY;
-        } else {
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
-            Parser parser(map, tokenizer);
-            status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-            ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
-                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),
-                    elapsedTime / 1000000.0);
-#endif
-            if (status) {
-                delete map;
-            } else {
-                *outMap = map;
-            }
-        }
-        delete tokenizer;
-    }
-    return status;
-}
-
-
-// --- VirtualKeyMap::Parser ---
-
-VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
-        mMap(map), mTokenizer(tokenizer) {
-}
-
-VirtualKeyMap::Parser::~Parser() {
-}
-
-status_t VirtualKeyMap::Parser::parse() {
-    while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
-        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
-                mTokenizer->peekRemainderOfLine().string());
-#endif
-
-        mTokenizer->skipDelimiters(WHITESPACE);
-
-        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
-            // Multiple keys can appear on one line or they can be broken up across multiple lines.
-            do {
-                String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
-                if (token != "0x01") {
-                    ALOGE("%s: Unknown virtual key type, expected 0x01.",
-                          mTokenizer->getLocation().string());
-                    return BAD_VALUE;
-                }
-
-                VirtualKeyDefinition defn;
-                bool success = parseNextIntField(&defn.scanCode)
-                        && parseNextIntField(&defn.centerX)
-                        && parseNextIntField(&defn.centerY)
-                        && parseNextIntField(&defn.width)
-                        && parseNextIntField(&defn.height);
-                if (!success) {
-                    ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
-                          mTokenizer->getLocation().string());
-                    return BAD_VALUE;
-                }
-
-#if DEBUG_PARSER
-                ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
-                        "width=%d, height=%d",
-                        defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
-#endif
-                mMap->mVirtualKeys.push(defn);
-            } while (consumeFieldDelimiterAndSkipWhitespace());
-
-            if (!mTokenizer->isEol()) {
-                ALOGE("%s: Expected end of line, got '%s'.",
-                        mTokenizer->getLocation().string(),
-                        mTokenizer->peekRemainderOfLine().string());
-                return BAD_VALUE;
-            }
-        }
-
-        mTokenizer->nextLine();
-    }
-
-    return NO_ERROR;
-}
-
-bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
-    mTokenizer->skipDelimiters(WHITESPACE);
-    if (mTokenizer->peekChar() == ':') {
-        mTokenizer->nextChar();
-        mTokenizer->skipDelimiters(WHITESPACE);
-        return true;
-    }
-    return false;
-}
-
-bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
-    if (!consumeFieldDelimiterAndSkipWhitespace()) {
-        return false;
-    }
-
-    String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
-    char* end;
-    *outValue = strtol(token.string(), &end, 0);
-    if (token.isEmpty() || *end != '\0') {
-        ALOGE("Expected an integer, got '%s'.", token.string());
-        return false;
-    }
-    return true;
-}
-
-} // namespace android
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
new file mode 100644
index 0000000..ec5f95c
--- /dev/null
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -0,0 +1,995 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Read-only access to Zip archives, with minimal heap allocation.
+//
+#define LOG_TAG "zipro"
+//#define LOG_NDEBUG 0
+#include <androidfw/ZipFileRO.h>
+#include <utils/Log.h>
+#include <utils/Compat.h>
+#include <utils/misc.h>
+#include <utils/threads.h>
+
+#include <zlib.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+/*
+ * We must open binary files using open(path, ... | O_BINARY) under Windows.
+ * Otherwise strange read errors will happen.
+ */
+#ifndef O_BINARY
+#  define O_BINARY  0
+#endif
+
+using namespace android;
+
+/*
+ * Zip file constants.
+ */
+#define kEOCDSignature       0x06054b50
+#define kEOCDLen             22
+#define kEOCDDiskNumber      4               // number of the current disk
+#define kEOCDDiskNumberForCD 6               // disk number with the Central Directory
+#define kEOCDNumEntries      8               // offset to #of entries in file
+#define kEOCDTotalNumEntries 10              // offset to total #of entries in spanned archives
+#define kEOCDSize            12              // size of the central directory
+#define kEOCDFileOffset      16              // offset to central directory
+#define kEOCDCommentSize     20              // offset to the length of the file comment
+
+#define kMaxCommentLen       65535           // longest possible in ushort
+#define kMaxEOCDSearch       (kMaxCommentLen + kEOCDLen)
+
+#define kLFHSignature        0x04034b50
+#define kLFHLen              30              // excluding variable-len fields
+#define kLFHGPBFlags          6              // offset to GPB flags
+#define kLFHNameLen          26              // offset to filename length
+#define kLFHExtraLen         28              // offset to extra length
+
+#define kCDESignature        0x02014b50
+#define kCDELen              46              // excluding variable-len fields
+#define kCDEGPBFlags          8              // offset to GPB flags
+#define kCDEMethod           10              // offset to compression method
+#define kCDEModWhen          12              // offset to modification timestamp
+#define kCDECRC              16              // offset to entry CRC
+#define kCDECompLen          20              // offset to compressed length
+#define kCDEUncompLen        24              // offset to uncompressed length
+#define kCDENameLen          28              // offset to filename length
+#define kCDEExtraLen         30              // offset to extra length
+#define kCDECommentLen       32              // offset to comment length
+#define kCDELocalOffset      42              // offset to local hdr
+
+/* General Purpose Bit Flag */
+#define kGPFEncryptedFlag    (1 << 0)
+#define kGPFUnsupportedMask  (kGPFEncryptedFlag)
+
+/*
+ * The values we return for ZipEntryRO use 0 as an invalid value, so we
+ * want to adjust the hash table index by a fixed amount.  Using a large
+ * value helps insure that people don't mix & match arguments, e.g. to
+ * findEntryByIndex().
+ */
+#define kZipEntryAdj        10000
+
+ZipFileRO::~ZipFileRO() {
+    free(mHashTable);
+    if (mDirectoryMap)
+        mDirectoryMap->release();
+    if (mFd >= 0)
+        TEMP_FAILURE_RETRY(close(mFd));
+    if (mFileName)
+        free(mFileName);
+}
+
+/*
+ * Convert a ZipEntryRO to a hash table index, verifying that it's in a
+ * valid range.
+ */
+int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
+{
+    long ent = ((intptr_t) entry) - kZipEntryAdj;
+    if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
+        ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
+        return -1;
+    }
+    return ent;
+}
+
+
+/*
+ * Open the specified file read-only.  We memory-map the entire thing and
+ * close the file before returning.
+ */
+status_t ZipFileRO::open(const char* zipFileName)
+{
+    int fd = -1;
+
+    assert(mDirectoryMap == NULL);
+
+    /*
+     * Open and map the specified file.
+     */
+    fd = TEMP_FAILURE_RETRY(::open(zipFileName, O_RDONLY | O_BINARY));
+    if (fd < 0) {
+        ALOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
+        return NAME_NOT_FOUND;
+    }
+
+    mFileLength = lseek64(fd, 0, SEEK_END);
+    if (mFileLength < kEOCDLen) {
+        TEMP_FAILURE_RETRY(close(fd));
+        return UNKNOWN_ERROR;
+    }
+
+    if (mFileName != NULL) {
+        free(mFileName);
+    }
+    mFileName = strdup(zipFileName);
+
+    mFd = fd;
+
+    /*
+     * Find the Central Directory and store its size and number of entries.
+     */
+    if (!mapCentralDirectory()) {
+        goto bail;
+    }
+
+    /*
+     * Verify Central Directory and create data structures for fast access.
+     */
+    if (!parseZipArchive()) {
+        goto bail;
+    }
+
+    return OK;
+
+bail:
+    free(mFileName);
+    mFileName = NULL;
+    TEMP_FAILURE_RETRY(close(fd));
+    return UNKNOWN_ERROR;
+}
+
+/*
+ * Parse the Zip archive, verifying its contents and initializing internal
+ * data structures.
+ */
+bool ZipFileRO::mapCentralDirectory(void)
+{
+    ssize_t readAmount = kMaxEOCDSearch;
+    if (readAmount > (ssize_t) mFileLength)
+        readAmount = mFileLength;
+
+    if (readAmount < kEOCDSize) {
+        ALOGW("File too short to be a zip file");
+        return false;
+    }
+
+    unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
+    if (scanBuf == NULL) {
+        ALOGW("couldn't allocate scanBuf: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Make sure this is a Zip archive.
+     */
+    if (lseek64(mFd, 0, SEEK_SET) != 0) {
+        ALOGW("seek to start failed: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t)));
+    if (actual != (ssize_t) sizeof(int32_t)) {
+        ALOGI("couldn't read first signature from zip archive: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    unsigned int header = get4LE(scanBuf);
+    if (header != kLFHSignature) {
+        ALOGV("Not a Zip archive (found 0x%08x)\n", header);
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Perform the traditional EOCD snipe hunt.
+     *
+     * We're searching for the End of Central Directory magic number,
+     * which appears at the start of the EOCD block.  It's followed by
+     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
+     * need to read the last part of the file into a buffer, dig through
+     * it to find the magic number, parse some values out, and use those
+     * to determine the extent of the CD.
+     *
+     * We start by pulling in the last part of the file.
+     */
+    off64_t searchStart = mFileLength - readAmount;
+
+    if (lseek64(mFd, searchStart, SEEK_SET) != searchStart) {
+        ALOGW("seek %ld failed: %s\n",  (long) searchStart, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+    actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
+    if (actual != (ssize_t) readAmount) {
+        ALOGW("Zip: read " ZD ", expected " ZD ". Failed: %s\n",
+            (ZD_TYPE) actual, (ZD_TYPE) readAmount, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Scan backward for the EOCD magic.  In an archive without a trailing
+     * comment, we'll find it on the first try.  (We may want to consider
+     * doing an initial minimal read; if we don't find it, retry with a
+     * second read as above.)
+     */
+    int i;
+    for (i = readAmount - kEOCDLen; i >= 0; i--) {
+        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
+            ALOGV("+++ Found EOCD at buf+%d\n", i);
+            break;
+        }
+    }
+    if (i < 0) {
+        ALOGD("Zip: EOCD not found, %s is not zip\n", mFileName);
+        free(scanBuf);
+        return false;
+    }
+
+    off64_t eocdOffset = searchStart + i;
+    const unsigned char* eocdPtr = scanBuf + i;
+
+    assert(eocdOffset < mFileLength);
+
+    /*
+     * Grab the CD offset and size, and the number of entries in the
+     * archive. After that, we can release our EOCD hunt buffer.
+     */
+    unsigned int diskNumber = get2LE(eocdPtr + kEOCDDiskNumber);
+    unsigned int diskWithCentralDir = get2LE(eocdPtr + kEOCDDiskNumberForCD);
+    unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries);
+    unsigned int totalNumEntries = get2LE(eocdPtr + kEOCDTotalNumEntries);
+    unsigned int centralDirSize = get4LE(eocdPtr + kEOCDSize);
+    unsigned int centralDirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+    unsigned int commentSize = get2LE(eocdPtr + kEOCDCommentSize);
+    free(scanBuf);
+
+    // Verify that they look reasonable.
+    if ((long long) centralDirOffset + (long long) centralDirSize > (long long) eocdOffset) {
+        ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
+            (long) centralDirOffset, centralDirSize, (long) eocdOffset);
+        return false;
+    }
+    if (numEntries == 0) {
+        ALOGW("empty archive?\n");
+        return false;
+    } else if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
+        ALOGW("spanned archives not supported");
+        return false;
+    }
+
+    // Check to see if comment is a sane size
+    if ((commentSize > (mFileLength - kEOCDLen))
+            || (eocdOffset > (mFileLength - kEOCDLen) - commentSize)) {
+        ALOGW("comment size runs off end of file");
+        return false;
+    }
+
+    ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
+        numEntries, centralDirSize, centralDirOffset);
+
+    mDirectoryMap = new FileMap();
+    if (mDirectoryMap == NULL) {
+        ALOGW("Unable to create directory map: %s", strerror(errno));
+        return false;
+    }
+
+    if (!mDirectoryMap->create(mFileName, mFd, centralDirOffset, centralDirSize, true)) {
+        ALOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName,
+                (ZD_TYPE) centralDirOffset, (ZD_TYPE) (centralDirOffset + centralDirSize), strerror(errno));
+        return false;
+    }
+
+    mNumEntries = numEntries;
+    mDirectoryOffset = centralDirOffset;
+
+    return true;
+}
+
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+static unsigned int roundUpPower2(unsigned int val)
+{
+    val--;
+    val |= val >> 1;
+    val |= val >> 2;
+    val |= val >> 4;
+    val |= val >> 8;
+    val |= val >> 16;
+    val++;
+
+    return val;
+}
+
+bool ZipFileRO::parseZipArchive(void)
+{
+    bool result = false;
+    const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr();
+    size_t cdLength = mDirectoryMap->getDataLength();
+    int numEntries = mNumEntries;
+
+    /*
+     * Create hash table.  We have a minimum 75% load factor, possibly as
+     * low as 50% after we round off to a power of 2.
+     */
+    mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3);
+    mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry));
+
+    /*
+     * Walk through the central directory, adding entries to the hash
+     * table.
+     */
+    const unsigned char* ptr = cdPtr;
+    for (int i = 0; i < numEntries; i++) {
+        if (get4LE(ptr) != kCDESignature) {
+            ALOGW("Missed a central dir sig (at %d)\n", i);
+            goto bail;
+        }
+        if (ptr + kCDELen > cdPtr + cdLength) {
+            ALOGW("Ran off the end (at %d)\n", i);
+            goto bail;
+        }
+
+        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset >= mDirectoryOffset) {
+            ALOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i);
+            goto bail;
+        }
+
+        unsigned int gpbf = get2LE(ptr + kCDEGPBFlags);
+        if ((gpbf & kGPFUnsupportedMask) != 0) {
+            ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
+            goto bail;
+        }
+
+        unsigned int nameLen = get2LE(ptr + kCDENameLen);
+        unsigned int extraLen = get2LE(ptr + kCDEExtraLen);
+        unsigned int commentLen = get2LE(ptr + kCDECommentLen);
+
+        const char *name = (const char *) ptr + kCDELen;
+
+        /* Check name for NULL characters */
+        if (memchr(name, 0, nameLen) != NULL) {
+            ALOGW("Filename contains NUL byte");
+            goto bail;
+        }
+
+        /* add the CDE filename to the hash table */
+        unsigned int hash = computeHash(name, nameLen);
+        addToHash(name, nameLen, hash);
+
+        /* We don't care about the comment or extra data. */
+        ptr += kCDELen + nameLen + extraLen + commentLen;
+        if ((size_t)(ptr - cdPtr) > cdLength) {
+            ALOGW("bad CD advance (%d vs " ZD ") at entry %d\n",
+                (int) (ptr - cdPtr), (ZD_TYPE) cdLength, i);
+            goto bail;
+        }
+    }
+    ALOGV("+++ zip good scan %d entries\n", numEntries);
+    result = true;
+
+bail:
+    return result;
+}
+
+/*
+ * Simple string hash function for non-null-terminated strings.
+ */
+/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len)
+{
+    unsigned int hash = 0;
+
+    while (len--)
+        hash = hash * 31 + *str++;
+
+    return hash;
+}
+
+/*
+ * Add a new entry to the hash table.
+ */
+void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash)
+{
+    int ent = hash & (mHashTableSize-1);
+
+    /*
+     * We over-allocate the table, so we're guaranteed to find an empty slot.
+     */
+    while (mHashTable[ent].name != NULL)
+        ent = (ent + 1) & (mHashTableSize-1);
+
+    mHashTable[ent].name = str;
+    mHashTable[ent].nameLen = strLen;
+}
+
+/*
+ * Find a matching entry.
+ *
+ * Returns NULL if not found.
+ */
+ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const
+{
+    /*
+     * If the ZipFileRO instance is not initialized, the entry number will
+     * end up being garbage since mHashTableSize is -1.
+     */
+    if (mHashTableSize <= 0) {
+        return NULL;
+    }
+
+    int nameLen = strlen(fileName);
+    unsigned int hash = computeHash(fileName, nameLen);
+    int ent = hash & (mHashTableSize-1);
+
+    while (mHashTable[ent].name != NULL) {
+        if (mHashTable[ent].nameLen == nameLen &&
+            memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
+        {
+            /* match */
+            return (ZipEntryRO)(long)(ent + kZipEntryAdj);
+        }
+
+        ent = (ent + 1) & (mHashTableSize-1);
+    }
+
+    return NULL;
+}
+
+/*
+ * Find the Nth entry.
+ *
+ * This currently involves walking through the sparse hash table, counting
+ * non-empty entries.  If we need to speed this up we can either allocate
+ * a parallel lookup table or (perhaps better) provide an iterator interface.
+ */
+ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
+{
+    if (idx < 0 || idx >= mNumEntries) {
+        ALOGW("Invalid index %d\n", idx);
+        return NULL;
+    }
+
+    for (int ent = 0; ent < mHashTableSize; ent++) {
+        if (mHashTable[ent].name != NULL) {
+            if (idx-- == 0)
+                return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj);
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Get the useful fields from the zip entry.
+ *
+ * Returns "false" if the offsets to the fields or the contents of the fields
+ * appear to be bogus.
+ */
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+    size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const
+{
+    bool ret = false;
+
+    const int ent = entryToIndex(entry);
+    if (ent < 0) {
+        ALOGW("cannot find entry");
+        return false;
+    }
+
+    HashEntry hashEntry = mHashTable[ent];
+
+    /*
+     * Recover the start of the central directory entry from the filename
+     * pointer.  The filename is the first entry past the fixed-size data,
+     * so we can just subtract back from that.
+     */
+    const unsigned char* ptr = (const unsigned char*) hashEntry.name;
+    off64_t cdOffset = mDirectoryOffset;
+
+    ptr -= kCDELen;
+
+    int method = get2LE(ptr + kCDEMethod);
+    if (pMethod != NULL)
+        *pMethod = method;
+
+    if (pModWhen != NULL)
+        *pModWhen = get4LE(ptr + kCDEModWhen);
+    if (pCrc32 != NULL)
+        *pCrc32 = get4LE(ptr + kCDECRC);
+
+    size_t compLen = get4LE(ptr + kCDECompLen);
+    if (pCompLen != NULL)
+        *pCompLen = compLen;
+    size_t uncompLen = get4LE(ptr + kCDEUncompLen);
+    if (pUncompLen != NULL)
+        *pUncompLen = uncompLen;
+
+    /*
+     * If requested, determine the offset of the start of the data.  All we
+     * have is the offset to the Local File Header, which is variable size,
+     * so we have to read the contents of the struct to figure out where
+     * the actual data starts.
+     *
+     * We also need to make sure that the lengths are not so large that
+     * somebody trying to map the compressed or uncompressed data runs
+     * off the end of the mapped region.
+     *
+     * Note we don't verify compLen/uncompLen if they don't request the
+     * dataOffset, because dataOffset is expensive to determine.  However,
+     * if they don't have the file offset, they're not likely to be doing
+     * anything with the contents.
+     */
+    if (pOffset != NULL) {
+        long localHdrOffset = get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset + kLFHLen >= cdOffset) {
+            ALOGE("ERROR: bad local hdr offset in zip\n");
+            return false;
+        }
+
+        unsigned char lfhBuf[kLFHLen];
+
+#ifdef HAVE_PREAD
+        /*
+         * This file descriptor might be from zygote's preloaded assets,
+         * so we need to do an pread64() instead of a lseek64() + read() to
+         * guarantee atomicity across the processes with the shared file
+         * descriptors.
+         */
+        ssize_t actual =
+                TEMP_FAILURE_RETRY(pread64(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset));
+
+        if (actual != sizeof(lfhBuf)) {
+            ALOGW("failed reading lfh from offset %ld\n", localHdrOffset);
+            return false;
+        }
+
+        if (get4LE(lfhBuf) != kLFHSignature) {
+            ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
+                    "got: data=0x%08lx\n",
+                    localHdrOffset, kLFHSignature, get4LE(lfhBuf));
+            return false;
+        }
+#else /* HAVE_PREAD */
+        /*
+         * For hosts don't have pread64() we cannot guarantee atomic reads from
+         * an offset in a file. Android should never run on those platforms.
+         * File descriptors inherited from a fork() share file offsets and
+         * there would be nothing to protect from two different processes
+         * calling lseek64() concurrently.
+         */
+
+        {
+            AutoMutex _l(mFdLock);
+
+            if (lseek64(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
+                ALOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);
+                return false;
+            }
+
+            ssize_t actual =
+                    TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf)));
+            if (actual != sizeof(lfhBuf)) {
+                ALOGW("failed reading lfh from offset %ld\n", localHdrOffset);
+                return false;
+            }
+
+            if (get4LE(lfhBuf) != kLFHSignature) {
+                off64_t actualOffset = lseek64(mFd, 0, SEEK_CUR);
+                ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
+                        "got: offset=" ZD " data=0x%08lx\n",
+                        localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf));
+                return false;
+            }
+        }
+#endif /* HAVE_PREAD */
+
+        unsigned int gpbf = get2LE(lfhBuf + kLFHGPBFlags);
+        if ((gpbf & kGPFUnsupportedMask) != 0) {
+            ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
+            return false;
+        }
+
+        off64_t dataOffset = localHdrOffset + kLFHLen
+            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
+        if (dataOffset >= cdOffset) {
+            ALOGW("bad data offset %ld in zip\n", (long) dataOffset);
+            return false;
+        }
+
+        /* check lengths */
+        if ((dataOffset >= cdOffset) || (compLen > (cdOffset - dataOffset))) {
+            ALOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
+                (long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
+            return false;
+        }
+
+        if (method == kCompressStored &&
+            ((dataOffset >= cdOffset) ||
+             (uncompLen > (cdOffset - dataOffset))))
+        {
+            ALOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
+                (long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
+            return false;
+        }
+
+        *pOffset = dataOffset;
+    }
+
+    return true;
+}
+
+/*
+ * Copy the entry's filename to the buffer.
+ */
+int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
+    const
+{
+    int ent = entryToIndex(entry);
+    if (ent < 0)
+        return -1;
+
+    int nameLen = mHashTable[ent].nameLen;
+    if (bufLen < nameLen+1)
+        return nameLen+1;
+
+    memcpy(buffer, mHashTable[ent].name, nameLen);
+    buffer[nameLen] = '\0';
+    return 0;
+}
+
+/*
+ * Create a new FileMap object that spans the data in "entry".
+ */
+FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
+{
+    /*
+     * TODO: the efficient way to do this is to modify FileMap to allow
+     * sub-regions of a file to be mapped.  A reference-counting scheme
+     * can manage the base memory mapping.  For now, we just create a brand
+     * new mapping off of the Zip archive file descriptor.
+     */
+
+    FileMap* newMap;
+    int method;
+    size_t uncompLen;
+    size_t compLen;
+    off64_t offset;
+
+    if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
+        return NULL;
+    }
+
+    size_t actualLen;
+    if (method == kCompressStored) {
+        actualLen = uncompLen;
+    } else {
+        actualLen = compLen;
+    }
+
+    newMap = new FileMap();
+    if (!newMap->create(mFileName, mFd, offset, actualLen, true)) {
+        newMap->release();
+        return NULL;
+    }
+
+    return newMap;
+}
+
+/*
+ * Uncompress an entry, in its entirety, into the provided output buffer.
+ *
+ * This doesn't verify the data's CRC, which might be useful for
+ * uncompressed data.  The caller should be able to manage it.
+ */
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
+{
+    const size_t kSequentialMin = 32768;
+    bool result = false;
+    int ent = entryToIndex(entry);
+    if (ent < 0) {
+        return false;
+    }
+
+    int method;
+    size_t uncompLen, compLen;
+    off64_t offset;
+    const unsigned char* ptr;
+    FileMap *file;
+
+    if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
+        goto bail;
+    }
+
+    file = createEntryFileMap(entry);
+    if (file == NULL) {
+        goto bail;
+    }
+
+    ptr = (const unsigned char*) file->getDataPtr();
+
+    /*
+     * Experiment with madvise hint.  When we want to uncompress a file,
+     * we pull some stuff out of the central dir entry and then hit a
+     * bunch of compressed or uncompressed data sequentially.  The CDE
+     * visit will cause a limited amount of read-ahead because it's at
+     * the end of the file.  We could end up doing lots of extra disk
+     * access if the file we're prying open is small.  Bottom line is we
+     * probably don't want to turn MADV_SEQUENTIAL on and leave it on.
+     *
+     * So, if the compressed size of the file is above a certain minimum
+     * size, temporarily boost the read-ahead in the hope that the extra
+     * pair of system calls are negated by a reduction in page faults.
+     */
+    if (compLen > kSequentialMin)
+        file->advise(FileMap::SEQUENTIAL);
+
+    if (method == kCompressStored) {
+        memcpy(buffer, ptr, uncompLen);
+    } else {
+        if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
+            goto unmap;
+    }
+
+    if (compLen > kSequentialMin)
+        file->advise(FileMap::NORMAL);
+
+    result = true;
+
+unmap:
+    file->release();
+bail:
+    return result;
+}
+
+/*
+ * Uncompress an entry, in its entirety, to an open file descriptor.
+ *
+ * This doesn't verify the data's CRC, but probably should.
+ */
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const
+{
+    bool result = false;
+    int ent = entryToIndex(entry);
+    if (ent < 0) {
+        return false;
+    }
+
+    int method;
+    size_t uncompLen, compLen;
+    off64_t offset;
+    const unsigned char* ptr;
+    FileMap *file;
+
+    if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
+        goto bail;
+    }
+
+    file = createEntryFileMap(entry);
+    if (file == NULL) {
+        goto bail;
+    }
+
+    ptr = (const unsigned char*) file->getDataPtr();
+
+    if (method == kCompressStored) {
+        ssize_t actual = TEMP_FAILURE_RETRY(write(fd, ptr, uncompLen));
+        if (actual < 0) {
+            ALOGE("Write failed: %s\n", strerror(errno));
+            goto unmap;
+        } else if ((size_t) actual != uncompLen) {
+            ALOGE("Partial write during uncompress (" ZD " of " ZD ")\n",
+                (ZD_TYPE) actual, (ZD_TYPE) uncompLen);
+            goto unmap;
+        } else {
+            ALOGI("+++ successful write\n");
+        }
+    } else {
+        if (!inflateBuffer(fd, ptr, uncompLen, compLen)) {
+            goto unmap;
+        }
+    }
+
+    result = true;
+
+unmap:
+    file->release();
+bail:
+    return result;
+}
+
+/*
+ * Uncompress "deflate" data from one buffer to another.
+ */
+/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
+    size_t uncompLen, size_t compLen)
+{
+    bool result = false;
+    z_stream zstream;
+    int zerr;
+
+    /*
+     * Initialize the zlib stream struct.
+     */
+    memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = (Bytef*)inBuf;
+    zstream.avail_in = compLen;
+    zstream.next_out = (Bytef*) outBuf;
+    zstream.avail_out = uncompLen;
+    zstream.data_type = Z_UNKNOWN;
+
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Expand data.
+     */
+    zerr = inflate(&zstream, Z_FINISH);
+    if (zerr != Z_STREAM_END) {
+        ALOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+            zerr, zstream.next_in, zstream.avail_in,
+            zstream.next_out, zstream.avail_out);
+        goto z_bail;
+    }
+
+    /* paranoia */
+    if (zstream.total_out != uncompLen) {
+        ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
+            zstream.total_out, (ZD_TYPE) uncompLen);
+        goto z_bail;
+    }
+
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+    return result;
+}
+
+/*
+ * Uncompress "deflate" data from one buffer to an open file descriptor.
+ */
+/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
+    size_t uncompLen, size_t compLen)
+{
+    bool result = false;
+    const size_t kWriteBufSize = 32768;
+    unsigned char writeBuf[kWriteBufSize];
+    z_stream zstream;
+    int zerr;
+
+    /*
+     * Initialize the zlib stream struct.
+     */
+    memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = (Bytef*)inBuf;
+    zstream.avail_in = compLen;
+    zstream.next_out = (Bytef*) writeBuf;
+    zstream.avail_out = sizeof(writeBuf);
+    zstream.data_type = Z_UNKNOWN;
+
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have more to do.
+     */
+    do {
+        /*
+         * Expand data.
+         */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            ALOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+                zerr, zstream.next_in, zstream.avail_in,
+                zstream.next_out, zstream.avail_out);
+            goto z_bail;
+        }
+
+        /* write when we're full or when we're done */
+        if (zstream.avail_out == 0 ||
+            (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
+        {
+            long writeSize = zstream.next_out - writeBuf;
+            int cc = TEMP_FAILURE_RETRY(write(fd, writeBuf, writeSize));
+            if (cc < 0) {
+                ALOGW("write failed in inflate: %s", strerror(errno));
+                goto z_bail;
+            } else if (cc != (int) writeSize) {
+                ALOGW("write failed in inflate (%d vs %ld)", cc, writeSize);
+                goto z_bail;
+            }
+
+            zstream.next_out = writeBuf;
+            zstream.avail_out = sizeof(writeBuf);
+        }
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    /* paranoia */
+    if (zstream.total_out != uncompLen) {
+        ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
+            zstream.total_out, (ZD_TYPE) uncompLen);
+        goto z_bail;
+    }
+
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+    return result;
+}
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
new file mode 100644
index 0000000..997eb7d
--- /dev/null
+++ b/libs/androidfw/ZipUtils.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Misc zip/gzip utility functions.
+//
+
+#define LOG_TAG "ziputil"
+
+#include <androidfw/ZipUtils.h>
+#include <androidfw/ZipFileRO.h>
+#include <utils/Log.h>
+#include <utils/Compat.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <zlib.h>
+
+using namespace android;
+
+/*
+ * Utility function that expands zip/gzip "deflate" compressed data
+ * into a buffer.
+ *
+ * "fd" is an open file positioned at the start of the "deflate" data
+ * "buf" must hold at least "uncompressedLen" bytes.
+ */
+/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
+    long uncompressedLen, long compressedLen)
+{
+    bool result = false;
+	const unsigned long kReadBufSize = 32768;
+	unsigned char* readBuf = NULL;
+    z_stream zstream;
+    int zerr;
+    unsigned long compRemaining;
+
+    assert(uncompressedLen >= 0);
+    assert(compressedLen >= 0);
+
+	readBuf = new unsigned char[kReadBufSize];
+	if (readBuf == NULL)
+        goto bail;
+    compRemaining = compressedLen;
+
+    /*
+     * Initialize the zlib stream.
+     */
+	memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = (Bytef*) buf;
+    zstream.avail_out = uncompressedLen;
+    zstream.data_type = Z_UNKNOWN;
+
+	/*
+	 * Use the undocumented "negative window bits" feature to tell zlib
+	 * that there's no zlib header waiting for it.
+	 */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have data.
+     */
+    do {
+        unsigned long getSize;
+
+        /* read as much as we can */
+        if (zstream.avail_in == 0) {
+            getSize = (compRemaining > kReadBufSize) ?
+                        kReadBufSize : compRemaining;
+            ALOGV("+++ reading %ld bytes (%ld left)\n",
+                getSize, compRemaining);
+
+            int cc = TEMP_FAILURE_RETRY(read(fd, readBuf, getSize));
+            if (cc < 0) {
+                ALOGW("inflate read failed: %s", strerror(errno));
+            } else if (cc != (int) getSize) {
+                ALOGW("inflate read failed (%d vs %ld)", cc, getSize);
+                goto z_bail;
+            }
+
+            compRemaining -= getSize;
+
+            zstream.next_in = readBuf;
+            zstream.avail_in = getSize;
+        }
+
+        /* uncompress the data */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
+            goto z_bail;
+        }
+
+		/* output buffer holds all, so no need to write the output */
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    if ((long) zstream.total_out != uncompressedLen) {
+        ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+            zstream.total_out, uncompressedLen);
+        goto z_bail;
+    }
+
+    // success!
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+	delete[] readBuf;
+    return result;
+}
+
+/*
+ * Utility function that expands zip/gzip "deflate" compressed data
+ * into a buffer.
+ *
+ * (This is a clone of the previous function, but it takes a FILE* instead
+ * of an fd.  We could pass fileno(fd) to the above, but we can run into
+ * trouble when "fp" has a different notion of what fd's file position is.)
+ *
+ * "fp" is an open file positioned at the start of the "deflate" data
+ * "buf" must hold at least "uncompressedLen" bytes.
+ */
+/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
+    long uncompressedLen, long compressedLen)
+{
+    bool result = false;
+	const unsigned long kReadBufSize = 32768;
+	unsigned char* readBuf = NULL;
+    z_stream zstream;
+    int zerr;
+    unsigned long compRemaining;
+
+    assert(uncompressedLen >= 0);
+    assert(compressedLen >= 0);
+
+	readBuf = new unsigned char[kReadBufSize];
+	if (readBuf == NULL)
+        goto bail;
+    compRemaining = compressedLen;
+
+    /*
+     * Initialize the zlib stream.
+     */
+	memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = (Bytef*) buf;
+    zstream.avail_out = uncompressedLen;
+    zstream.data_type = Z_UNKNOWN;
+
+	/*
+	 * Use the undocumented "negative window bits" feature to tell zlib
+	 * that there's no zlib header waiting for it.
+	 */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have data.
+     */
+    do {
+        unsigned long getSize;
+
+        /* read as much as we can */
+        if (zstream.avail_in == 0) {
+            getSize = (compRemaining > kReadBufSize) ?
+                        kReadBufSize : compRemaining;
+            ALOGV("+++ reading %ld bytes (%ld left)\n",
+                getSize, compRemaining);
+
+            int cc = fread(readBuf, 1, getSize, fp);
+            if (cc != (int) getSize) {
+                ALOGD("inflate read failed (%d vs %ld)\n",
+                    cc, getSize);
+                goto z_bail;
+            }
+
+            compRemaining -= getSize;
+
+            zstream.next_in = readBuf;
+            zstream.avail_in = getSize;
+        }
+
+        /* uncompress the data */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
+            goto z_bail;
+        }
+
+		/* output buffer holds all, so no need to write the output */
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    if ((long) zstream.total_out != uncompressedLen) {
+        ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+            zstream.total_out, uncompressedLen);
+        goto z_bail;
+    }
+
+    // success!
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+	delete[] readBuf;
+    return result;
+}
+
+/*
+ * Look at the contents of a gzip archive.  We want to know where the
+ * data starts, and how long it will be after it is uncompressed.
+ *
+ * We expect to find the CRC and length as the last 8 bytes on the file.
+ * This is a pretty reasonable thing to expect for locally-compressed
+ * files, but there's a small chance that some extra padding got thrown
+ * on (the man page talks about compressed data written to tape).  We
+ * don't currently deal with that here.  If "gzip -l" whines, we're going
+ * to fail too.
+ *
+ * On exit, "fp" is pointing at the start of the compressed data.
+ */
+/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod,
+    long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32)
+{
+    enum {  // flags
+        FTEXT       = 0x01,
+        FHCRC       = 0x02,
+        FEXTRA      = 0x04,
+        FNAME       = 0x08,
+        FCOMMENT    = 0x10,
+    };
+    int ic;
+    int method, flags;
+    int i;
+
+    ic = getc(fp);
+    if (ic != 0x1f || getc(fp) != 0x8b)
+        return false;       // not gzip
+    method = getc(fp);
+    flags = getc(fp);
+
+    /* quick sanity checks */
+    if (method == EOF || flags == EOF)
+        return false;
+    if (method != ZipFileRO::kCompressDeflated)
+        return false;
+
+    /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
+    for (i = 0; i < 6; i++)
+        (void) getc(fp);
+    /* consume "extra" field, if present */
+    if ((flags & FEXTRA) != 0) {
+        int len;
+
+        len = getc(fp);
+        len |= getc(fp) << 8;
+        while (len-- && getc(fp) != EOF)
+            ;
+    }
+    /* consume filename, if present */
+    if ((flags & FNAME) != 0) {
+        do {
+            ic = getc(fp);
+        } while (ic != 0 && ic != EOF);
+    }
+    /* consume comment, if present */
+    if ((flags & FCOMMENT) != 0) {
+        do {
+            ic = getc(fp);
+        } while (ic != 0 && ic != EOF);
+    }
+    /* consume 16-bit header CRC, if present */
+    if ((flags & FHCRC) != 0) {
+        (void) getc(fp);
+        (void) getc(fp);
+    }
+
+    if (feof(fp) || ferror(fp))
+        return false;
+
+    /* seek to the end; CRC and length are in the last 8 bytes */
+    long curPosn = ftell(fp);
+    unsigned char buf[8];
+    fseek(fp, -8, SEEK_END);
+    *pCompressedLen = ftell(fp) - curPosn;
+
+    if (fread(buf, 1, 8, fp) != 8)
+        return false;
+    /* seek back to start of compressed data */
+    fseek(fp, curPosn, SEEK_SET);
+
+    *pCompressionMethod = method;
+    *pCRC32 = ZipFileRO::get4LE(&buf[0]);
+    *pUncompressedLen = ZipFileRO::get4LE(&buf[4]);
+
+    return true;
+}
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
new file mode 100644
index 0000000..29686ef
--- /dev/null
+++ b/libs/androidfw/misc.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "misc"
+
+//
+// Miscellaneous utility functions.
+//
+#include <androidfw/misc.h>
+
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+using namespace android;
+
+namespace android {
+
+/*
+ * Get a file's type.
+ */
+FileType getFileType(const char* fileName)
+{
+    struct stat sb;
+
+    if (stat(fileName, &sb) < 0) {
+        if (errno == ENOENT || errno == ENOTDIR)
+            return kFileTypeNonexistent;
+        else {
+            fprintf(stderr, "getFileType got errno=%d on '%s'\n",
+                errno, fileName);
+            return kFileTypeUnknown;
+        }
+    } else {
+        if (S_ISREG(sb.st_mode))
+            return kFileTypeRegular;
+        else if (S_ISDIR(sb.st_mode))
+            return kFileTypeDirectory;
+        else if (S_ISCHR(sb.st_mode))
+            return kFileTypeCharDev;
+        else if (S_ISBLK(sb.st_mode))
+            return kFileTypeBlockDev;
+        else if (S_ISFIFO(sb.st_mode))
+            return kFileTypeFifo;
+#ifdef HAVE_SYMLINKS
+        else if (S_ISLNK(sb.st_mode))
+            return kFileTypeSymlink;
+        else if (S_ISSOCK(sb.st_mode))
+            return kFileTypeSocket;
+#endif
+        else
+            return kFileTypeUnknown;
+    }
+}
+
+/*
+ * Get a file's modification date.
+ */
+time_t getFileModDate(const char* fileName)
+{
+    struct stat sb;
+
+    if (stat(fileName, &sb) < 0)
+        return (time_t) -1;
+
+    return sb.st_mtime;
+}
+
+}; // namespace android
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 4ae23ec..0522212 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -4,19 +4,15 @@
 
 # Build the unit tests.
 test_src_files := \
-    InputChannel_test.cpp \
-    InputEvent_test.cpp \
-    InputPublisherAndConsumer_test.cpp \
-    ObbFile_test.cpp
+    ObbFile_test.cpp \
+    ZipFileRO_test.cpp
 
 shared_libraries := \
     libandroidfw \
     libcutils \
     libutils \
-    libbinder \
     libui \
-    libstlport \
-    libskia
+    libstlport
 
 static_libraries := \
     libgtest \
diff --git a/libs/androidfw/tests/InputChannel_test.cpp b/libs/androidfw/tests/InputChannel_test.cpp
deleted file mode 100644
index 7fff8af..0000000
--- a/libs/androidfw/tests/InputChannel_test.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <androidfw/InputTransport.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <utils/StrongPointer.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-#include <errno.h>
-
-#include "TestHelpers.h"
-
-namespace android {
-
-class InputChannelTest : public testing::Test {
-protected:
-    virtual void SetUp() { }
-    virtual void TearDown() { }
-};
-
-
-TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
-    // Our purpose here is to verify that the input channel destructor closes the
-    // file descriptor provided to it.  One easy way is to provide it with one end
-    // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
-    Pipe pipe;
-
-    sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
-
-    EXPECT_STREQ("channel name", inputChannel->getName().string())
-            << "channel should have provided name";
-    EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
-            << "channel should have provided fd";
-
-    inputChannel.clear(); // destroys input channel
-
-    EXPECT_EQ(-EPIPE, pipe.readSignal())
-            << "channel should have closed fd when destroyed";
-
-    // clean up fds of Pipe endpoints that were closed so we don't try to close them again
-    pipe.sendFd = -1;
-}
-
-TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
-    sp<InputChannel> serverChannel, clientChannel;
-
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
-            serverChannel, clientChannel);
-
-    ASSERT_EQ(OK, result)
-            << "should have successfully opened a channel pair";
-
-    // Name
-    EXPECT_STREQ("channel name (server)", serverChannel->getName().string())
-            << "server channel should have suffixed name";
-    EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
-            << "client channel should have suffixed name";
-
-    // Server->Client communication
-    InputMessage serverMsg;
-    memset(&serverMsg, 0, sizeof(InputMessage));
-    serverMsg.header.type = InputMessage::TYPE_KEY;
-    serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
-    EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
-            << "server channel should be able to send message to client channel";
-
-    InputMessage clientMsg;
-    EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
-            << "client channel should be able to receive message from server channel";
-    EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
-            << "client channel should receive the correct message from server channel";
-    EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
-            << "client channel should receive the correct message from server channel";
-
-    // Client->Server communication
-    InputMessage clientReply;
-    memset(&clientReply, 0, sizeof(InputMessage));
-    clientReply.header.type = InputMessage::TYPE_FINISHED;
-    clientReply.body.finished.seq = 0x11223344;
-    clientReply.body.finished.handled = true;
-    EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
-            << "client channel should be able to send message to server channel";
-
-    InputMessage serverReply;
-    EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply))
-            << "server channel should be able to receive message from client channel";
-    EXPECT_EQ(clientReply.header.type, serverReply.header.type)
-            << "server channel should receive the correct message from client channel";
-    EXPECT_EQ(clientReply.body.finished.seq, serverReply.body.finished.seq)
-            << "server channel should receive the correct message from client channel";
-    EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled)
-            << "server channel should receive the correct message from client channel";
-}
-
-TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
-    sp<InputChannel> serverChannel, clientChannel;
-
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
-            serverChannel, clientChannel);
-
-    ASSERT_EQ(OK, result)
-            << "should have successfully opened a channel pair";
-
-    InputMessage msg;
-    EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
-            << "receiveMessage should have returned WOULD_BLOCK";
-}
-
-TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
-    sp<InputChannel> serverChannel, clientChannel;
-
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
-            serverChannel, clientChannel);
-
-    ASSERT_EQ(OK, result)
-            << "should have successfully opened a channel pair";
-
-    serverChannel.clear(); // close server channel
-
-    InputMessage msg;
-    EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
-            << "receiveMessage should have returned DEAD_OBJECT";
-}
-
-TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
-    sp<InputChannel> serverChannel, clientChannel;
-
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
-            serverChannel, clientChannel);
-
-    ASSERT_EQ(OK, result)
-            << "should have successfully opened a channel pair";
-
-    serverChannel.clear(); // close server channel
-
-    InputMessage msg;
-    msg.header.type = InputMessage::TYPE_KEY;
-    EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
-            << "sendMessage should have returned DEAD_OBJECT";
-}
-
-
-} // namespace android
diff --git a/libs/androidfw/tests/InputEvent_test.cpp b/libs/androidfw/tests/InputEvent_test.cpp
deleted file mode 100644
index e9164d1..0000000
--- a/libs/androidfw/tests/InputEvent_test.cpp
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * 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.
- */
-
-#include <androidfw/Input.h>
-#include <gtest/gtest.h>
-#include <binder/Parcel.h>
-
-#include <math.h>
-#include <core/SkMatrix.h>
-
-namespace android {
-
-class BaseTest : public testing::Test {
-protected:
-    virtual void SetUp() { }
-    virtual void TearDown() { }
-};
-
-// --- PointerCoordsTest ---
-
-class PointerCoordsTest : public BaseTest {
-};
-
-TEST_F(PointerCoordsTest, ClearSetsBitsToZero) {
-    PointerCoords coords;
-    coords.clear();
-
-    ASSERT_EQ(0ULL, coords.bits);
-}
-
-TEST_F(PointerCoordsTest, AxisValues) {
-    float* valuePtr;
-    PointerCoords coords;
-    coords.clear();
-
-    // Check invariants when no axes are present.
-    ASSERT_EQ(0, coords.getAxisValue(0))
-            << "getAxisValue should return zero because axis is not present";
-    ASSERT_EQ(0, coords.getAxisValue(1))
-            << "getAxisValue should return zero because axis is not present";
-
-    // Set first axis.
-    ASSERT_EQ(OK, coords.setAxisValue(1, 5));
-    ASSERT_EQ(0x00000002ULL, coords.bits);
-    ASSERT_EQ(5, coords.values[0]);
-
-    ASSERT_EQ(0, coords.getAxisValue(0))
-            << "getAxisValue should return zero because axis is not present";
-    ASSERT_EQ(5, coords.getAxisValue(1))
-            << "getAxisValue should return value of axis";
-
-    // Set an axis with a higher id than all others.  (appending value at the end)
-    ASSERT_EQ(OK, coords.setAxisValue(3, 2));
-    ASSERT_EQ(0x0000000aULL, coords.bits);
-    ASSERT_EQ(5, coords.values[0]);
-    ASSERT_EQ(2, coords.values[1]);
-
-    ASSERT_EQ(0, coords.getAxisValue(0))
-            << "getAxisValue should return zero because axis is not present";
-    ASSERT_EQ(5, coords.getAxisValue(1))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(0, coords.getAxisValue(2))
-            << "getAxisValue should return zero because axis is not present";
-    ASSERT_EQ(2, coords.getAxisValue(3))
-            << "getAxisValue should return value of axis";
-
-    // Set an axis with an id lower than all others.  (prepending value at beginning)
-    ASSERT_EQ(OK, coords.setAxisValue(0, 4));
-    ASSERT_EQ(0x0000000bULL, coords.bits);
-    ASSERT_EQ(4, coords.values[0]);
-    ASSERT_EQ(5, coords.values[1]);
-    ASSERT_EQ(2, coords.values[2]);
-
-    ASSERT_EQ(4, coords.getAxisValue(0))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(5, coords.getAxisValue(1))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(0, coords.getAxisValue(2))
-            << "getAxisValue should return zero because axis is not present";
-    ASSERT_EQ(2, coords.getAxisValue(3))
-            << "getAxisValue should return value of axis";
-
-    // Set an axis with an id between the others.  (inserting value in the middle)
-    ASSERT_EQ(OK, coords.setAxisValue(2, 1));
-    ASSERT_EQ(0x0000000fULL, coords.bits);
-    ASSERT_EQ(4, coords.values[0]);
-    ASSERT_EQ(5, coords.values[1]);
-    ASSERT_EQ(1, coords.values[2]);
-    ASSERT_EQ(2, coords.values[3]);
-
-    ASSERT_EQ(4, coords.getAxisValue(0))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(5, coords.getAxisValue(1))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(1, coords.getAxisValue(2))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(2, coords.getAxisValue(3))
-            << "getAxisValue should return value of axis";
-
-    // Set an existing axis value in place.
-    ASSERT_EQ(OK, coords.setAxisValue(1, 6));
-    ASSERT_EQ(0x0000000fULL, coords.bits);
-    ASSERT_EQ(4, coords.values[0]);
-    ASSERT_EQ(6, coords.values[1]);
-    ASSERT_EQ(1, coords.values[2]);
-    ASSERT_EQ(2, coords.values[3]);
-
-    ASSERT_EQ(4, coords.getAxisValue(0))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(6, coords.getAxisValue(1))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(1, coords.getAxisValue(2))
-            << "getAxisValue should return value of axis";
-    ASSERT_EQ(2, coords.getAxisValue(3))
-            << "getAxisValue should return value of axis";
-
-    // Set maximum number of axes.
-    for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) {
-        ASSERT_EQ(OK, coords.setAxisValue(axis, axis));
-    }
-    ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
-
-    // Try to set one more axis beyond maximum number.
-    // Ensure bits are unchanged.
-    ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100));
-    ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
-}
-
-TEST_F(PointerCoordsTest, Parcel) {
-    Parcel parcel;
-
-    PointerCoords inCoords;
-    inCoords.clear();
-    PointerCoords outCoords;
-
-    // Round trip with empty coords.
-    inCoords.writeToParcel(&parcel);
-    parcel.setDataPosition(0);
-    outCoords.readFromParcel(&parcel);
-
-    ASSERT_EQ(0ULL, outCoords.bits);
-
-    // Round trip with some values.
-    parcel.freeData();
-    inCoords.setAxisValue(2, 5);
-    inCoords.setAxisValue(5, 8);
-
-    inCoords.writeToParcel(&parcel);
-    parcel.setDataPosition(0);
-    outCoords.readFromParcel(&parcel);
-
-    ASSERT_EQ(outCoords.bits, inCoords.bits);
-    ASSERT_EQ(outCoords.values[0], inCoords.values[0]);
-    ASSERT_EQ(outCoords.values[1], inCoords.values[1]);
-}
-
-
-// --- KeyEventTest ---
-
-class KeyEventTest : public BaseTest {
-};
-
-TEST_F(KeyEventTest, Properties) {
-    KeyEvent event;
-
-    // Initialize and get properties.
-    const nsecs_t ARBITRARY_DOWN_TIME = 1;
-    const nsecs_t ARBITRARY_EVENT_TIME = 2;
-    event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
-            AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
-            AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
-
-    ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
-    ASSERT_EQ(2, event.getDeviceId());
-    ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
-    ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
-    ASSERT_EQ(121, event.getScanCode());
-    ASSERT_EQ(AMETA_ALT_ON, event.getMetaState());
-    ASSERT_EQ(1, event.getRepeatCount());
-    ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime());
-    ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getEventTime());
-
-    // Set source.
-    event.setSource(AINPUT_SOURCE_JOYSTICK);
-    ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
-}
-
-
-// --- MotionEventTest ---
-
-class MotionEventTest : public BaseTest {
-protected:
-    static const nsecs_t ARBITRARY_DOWN_TIME;
-    static const nsecs_t ARBITRARY_EVENT_TIME;
-    static const float X_OFFSET;
-    static const float Y_OFFSET;
-
-    void initializeEventWithHistory(MotionEvent* event);
-    void assertEqualsEventWithHistory(const MotionEvent* event);
-};
-
-const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1;
-const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2;
-const float MotionEventTest::X_OFFSET = 1.0f;
-const float MotionEventTest::Y_OFFSET = 1.1f;
-
-void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
-    PointerProperties pointerProperties[2];
-    pointerProperties[0].clear();
-    pointerProperties[0].id = 1;
-    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-    pointerProperties[1].clear();
-    pointerProperties[1].id = 2;
-    pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
-
-    PointerCoords pointerCoords[2];
-    pointerCoords[0].clear();
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
-    pointerCoords[1].clear();
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
-    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
-            AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
-            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
-            X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
-            ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
-            2, pointerProperties, pointerCoords);
-
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
-    event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords);
-
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
-    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
-    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
-    event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords);
-}
-
-void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
-    // Check properties.
-    ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
-    ASSERT_EQ(2, event->getDeviceId());
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
-    ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
-    ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
-    ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
-    ASSERT_EQ(X_OFFSET, event->getXOffset());
-    ASSERT_EQ(Y_OFFSET, event->getYOffset());
-    ASSERT_EQ(2.0f, event->getXPrecision());
-    ASSERT_EQ(2.1f, event->getYPrecision());
-    ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime());
-
-    ASSERT_EQ(2U, event->getPointerCount());
-    ASSERT_EQ(1, event->getPointerId(0));
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0));
-    ASSERT_EQ(2, event->getPointerId(1));
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1));
-
-    ASSERT_EQ(2U, event->getHistorySize());
-
-    // Check data.
-    ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0));
-    ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1));
-    ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime());
-
-    ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(211, event->getRawPointerCoords(0)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(221, event->getRawPointerCoords(1)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-
-    ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
-    ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
-    ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
-    ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
-    ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
-    ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
-
-    ASSERT_EQ(10, event->getHistoricalRawX(0, 0));
-    ASSERT_EQ(20, event->getHistoricalRawX(1, 0));
-    ASSERT_EQ(110, event->getHistoricalRawX(0, 1));
-    ASSERT_EQ(120, event->getHistoricalRawX(1, 1));
-    ASSERT_EQ(210, event->getRawX(0));
-    ASSERT_EQ(220, event->getRawX(1));
-
-    ASSERT_EQ(11, event->getHistoricalRawY(0, 0));
-    ASSERT_EQ(21, event->getHistoricalRawY(1, 0));
-    ASSERT_EQ(111, event->getHistoricalRawY(0, 1));
-    ASSERT_EQ(121, event->getHistoricalRawY(1, 1));
-    ASSERT_EQ(211, event->getRawY(0));
-    ASSERT_EQ(221, event->getRawY(1));
-
-    ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0));
-    ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0));
-    ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1));
-    ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1));
-    ASSERT_EQ(X_OFFSET + 210, event->getX(0));
-    ASSERT_EQ(X_OFFSET + 220, event->getX(1));
-
-    ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0));
-    ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0));
-    ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1));
-    ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1));
-    ASSERT_EQ(Y_OFFSET + 211, event->getY(0));
-    ASSERT_EQ(Y_OFFSET + 221, event->getY(1));
-
-    ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
-    ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
-    ASSERT_EQ(112, event->getHistoricalPressure(0, 1));
-    ASSERT_EQ(122, event->getHistoricalPressure(1, 1));
-    ASSERT_EQ(212, event->getPressure(0));
-    ASSERT_EQ(222, event->getPressure(1));
-
-    ASSERT_EQ(13, event->getHistoricalSize(0, 0));
-    ASSERT_EQ(23, event->getHistoricalSize(1, 0));
-    ASSERT_EQ(113, event->getHistoricalSize(0, 1));
-    ASSERT_EQ(123, event->getHistoricalSize(1, 1));
-    ASSERT_EQ(213, event->getSize(0));
-    ASSERT_EQ(223, event->getSize(1));
-
-    ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0));
-    ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0));
-    ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1));
-    ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1));
-    ASSERT_EQ(214, event->getTouchMajor(0));
-    ASSERT_EQ(224, event->getTouchMajor(1));
-
-    ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0));
-    ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0));
-    ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1));
-    ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1));
-    ASSERT_EQ(215, event->getTouchMinor(0));
-    ASSERT_EQ(225, event->getTouchMinor(1));
-
-    ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0));
-    ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0));
-    ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1));
-    ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1));
-    ASSERT_EQ(216, event->getToolMajor(0));
-    ASSERT_EQ(226, event->getToolMajor(1));
-
-    ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0));
-    ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0));
-    ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1));
-    ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1));
-    ASSERT_EQ(217, event->getToolMinor(0));
-    ASSERT_EQ(227, event->getToolMinor(1));
-
-    ASSERT_EQ(18, event->getHistoricalOrientation(0, 0));
-    ASSERT_EQ(28, event->getHistoricalOrientation(1, 0));
-    ASSERT_EQ(118, event->getHistoricalOrientation(0, 1));
-    ASSERT_EQ(128, event->getHistoricalOrientation(1, 1));
-    ASSERT_EQ(218, event->getOrientation(0));
-    ASSERT_EQ(228, event->getOrientation(1));
-}
-
-TEST_F(MotionEventTest, Properties) {
-    MotionEvent event;
-
-    // Initialize, add samples and check properties.
-    initializeEventWithHistory(&event);
-    ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
-
-    // Set source.
-    event.setSource(AINPUT_SOURCE_JOYSTICK);
-    ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
-
-    // Set action.
-    event.setAction(AMOTION_EVENT_ACTION_CANCEL);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
-
-    // Set meta state.
-    event.setMetaState(AMETA_CTRL_ON);
-    ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState());
-}
-
-TEST_F(MotionEventTest, CopyFrom_KeepHistory) {
-    MotionEvent event;
-    initializeEventWithHistory(&event);
-
-    MotionEvent copy;
-    copy.copyFrom(&event, true /*keepHistory*/);
-
-    ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
-}
-
-TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) {
-    MotionEvent event;
-    initializeEventWithHistory(&event);
-
-    MotionEvent copy;
-    copy.copyFrom(&event, false /*keepHistory*/);
-
-    ASSERT_EQ(event.getPointerCount(), copy.getPointerCount());
-    ASSERT_EQ(0U, copy.getHistorySize());
-
-    ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0));
-    ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1));
-
-    ASSERT_EQ(event.getEventTime(), copy.getEventTime());
-
-    ASSERT_EQ(event.getX(0), copy.getX(0));
-}
-
-TEST_F(MotionEventTest, OffsetLocation) {
-    MotionEvent event;
-    initializeEventWithHistory(&event);
-
-    event.offsetLocation(5.0f, -2.0f);
-
-    ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset());
-    ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset());
-}
-
-TEST_F(MotionEventTest, Scale) {
-    MotionEvent event;
-    initializeEventWithHistory(&event);
-
-    event.scale(2.0f);
-
-    ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
-    ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
-
-    ASSERT_EQ(210 * 2, event.getRawX(0));
-    ASSERT_EQ(211 * 2, event.getRawY(0));
-    ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0));
-    ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0));
-    ASSERT_EQ(212, event.getPressure(0));
-    ASSERT_EQ(213, event.getSize(0));
-    ASSERT_EQ(214 * 2, event.getTouchMajor(0));
-    ASSERT_EQ(215 * 2, event.getTouchMinor(0));
-    ASSERT_EQ(216 * 2, event.getToolMajor(0));
-    ASSERT_EQ(217 * 2, event.getToolMinor(0));
-    ASSERT_EQ(218, event.getOrientation(0));
-}
-
-TEST_F(MotionEventTest, Parcel) {
-    Parcel parcel;
-
-    MotionEvent inEvent;
-    initializeEventWithHistory(&inEvent);
-    MotionEvent outEvent;
-
-    // Round trip.
-    inEvent.writeToParcel(&parcel);
-    parcel.setDataPosition(0);
-    outEvent.readFromParcel(&parcel);
-
-    ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent));
-}
-
-TEST_F(MotionEventTest, Transform) {
-    // Generate some points on a circle.
-    // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
-    // of ARC * i degrees clockwise relative to the Y axis.
-    // The geometrical representation is irrelevant to the test, it's just easy to generate
-    // and check rotation.  We set the orientation to the same angle.
-    // Coordinate system: down is increasing Y, right is increasing X.
-    const float PI_180 = float(M_PI / 180);
-    const float RADIUS = 10;
-    const float ARC = 36;
-    const float ROTATION = ARC * 2;
-
-    const size_t pointerCount = 11;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        float angle = float(i * ARC * PI_180);
-        pointerProperties[i].clear();
-        pointerProperties[i].id = i;
-        pointerCoords[i].clear();
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
-    }
-    MotionEvent event;
-    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
-    float originalRawX = 0 + 3;
-    float originalRawY = -RADIUS + 2;
-
-    // Check original raw X and Y assumption.
-    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
-    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
-
-    // Now translate the motion event so the circle's origin is at (0,0).
-    event.offsetLocation(-3, -2);
-
-    // Offsetting the location should preserve the raw X and Y of the first point.
-    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
-    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
-
-    // Apply a rotation about the origin by ROTATION degrees clockwise.
-    SkMatrix matrix;
-    matrix.setRotate(ROTATION);
-    event.transform(&matrix);
-
-    // Check the points.
-    for (size_t i = 0; i < pointerCount; i++) {
-        float angle = float((i * ARC + ROTATION) * PI_180);
-        ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001);
-        ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001);
-        ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
-    }
-
-    // Applying the transformation should preserve the raw X and Y of the first point.
-    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
-    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
-}
-
-} // namespace android
diff --git a/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp b/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
deleted file mode 100644
index f45774b..0000000
--- a/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <androidfw/InputTransport.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
-
-#include "TestHelpers.h"
-
-namespace android {
-
-class InputPublisherAndConsumerTest : public testing::Test {
-protected:
-    sp<InputChannel> serverChannel, clientChannel;
-    InputPublisher* mPublisher;
-    InputConsumer* mConsumer;
-    PreallocatedInputEventFactory mEventFactory;
-
-    virtual void SetUp() {
-        status_t result = InputChannel::openInputChannelPair(String8("channel name"),
-                serverChannel, clientChannel);
-
-        mPublisher = new InputPublisher(serverChannel);
-        mConsumer = new InputConsumer(clientChannel);
-    }
-
-    virtual void TearDown() {
-        if (mPublisher) {
-            delete mPublisher;
-            mPublisher = NULL;
-        }
-
-        if (mConsumer) {
-            delete mConsumer;
-            mConsumer = NULL;
-        }
-
-        serverChannel.clear();
-        clientChannel.clear();
-    }
-
-    void PublishAndConsumeKeyEvent();
-    void PublishAndConsumeMotionEvent();
-};
-
-TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
-    EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get());
-    EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
-}
-
-void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
-    status_t status;
-
-    const uint32_t seq = 15;
-    const int32_t deviceId = 1;
-    const int32_t source = AINPUT_SOURCE_KEYBOARD;
-    const int32_t action = AKEY_EVENT_ACTION_DOWN;
-    const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
-    const int32_t keyCode = AKEYCODE_ENTER;
-    const int32_t scanCode = 13;
-    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
-    const int32_t repeatCount = 1;
-    const nsecs_t downTime = 3;
-    const nsecs_t eventTime = 4;
-
-    status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
-            keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
-    ASSERT_EQ(OK, status)
-            << "publisher publishKeyEvent should return OK";
-
-    uint32_t consumeSeq;
-    InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
-    ASSERT_EQ(OK, status)
-            << "consumer consume should return OK";
-
-    ASSERT_TRUE(event != NULL)
-            << "consumer should have returned non-NULL event";
-    ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
-            << "consumer should have returned a key event";
-
-    KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
-    EXPECT_EQ(seq, consumeSeq);
-    EXPECT_EQ(deviceId, keyEvent->getDeviceId());
-    EXPECT_EQ(source, keyEvent->getSource());
-    EXPECT_EQ(action, keyEvent->getAction());
-    EXPECT_EQ(flags, keyEvent->getFlags());
-    EXPECT_EQ(keyCode, keyEvent->getKeyCode());
-    EXPECT_EQ(scanCode, keyEvent->getScanCode());
-    EXPECT_EQ(metaState, keyEvent->getMetaState());
-    EXPECT_EQ(repeatCount, keyEvent->getRepeatCount());
-    EXPECT_EQ(downTime, keyEvent->getDownTime());
-    EXPECT_EQ(eventTime, keyEvent->getEventTime());
-
-    status = mConsumer->sendFinishedSignal(seq, true);
-    ASSERT_EQ(OK, status)
-            << "consumer sendFinishedSignal should return OK";
-
-    uint32_t finishedSeq = 0;
-    bool handled = false;
-    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
-    ASSERT_EQ(OK, status)
-            << "publisher receiveFinishedSignal should return OK";
-    ASSERT_EQ(seq, finishedSeq)
-            << "publisher receiveFinishedSignal should have returned the original sequence number";
-    ASSERT_TRUE(handled)
-            << "publisher receiveFinishedSignal should have set handled to consumer's reply";
-}
-
-void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
-    status_t status;
-
-    const uint32_t seq = 15;
-    const int32_t deviceId = 1;
-    const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
-    const int32_t action = AMOTION_EVENT_ACTION_MOVE;
-    const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-    const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
-    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
-    const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
-    const float xOffset = -10;
-    const float yOffset = -20;
-    const float xPrecision = 0.25;
-    const float yPrecision = 0.5;
-    const nsecs_t downTime = 3;
-    const size_t pointerCount = 3;
-    const nsecs_t eventTime = 4;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].clear();
-        pointerProperties[i].id = (i + 2) % pointerCount;
-        pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-
-        pointerCoords[i].clear();
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
-        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
-    }
-
-    status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
-            metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
-            downTime, eventTime, pointerCount,
-            pointerProperties, pointerCoords);
-    ASSERT_EQ(OK, status)
-            << "publisher publishMotionEvent should return OK";
-
-    uint32_t consumeSeq;
-    InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
-    ASSERT_EQ(OK, status)
-            << "consumer consume should return OK";
-
-    ASSERT_TRUE(event != NULL)
-            << "consumer should have returned non-NULL event";
-    ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
-            << "consumer should have returned a motion event";
-
-    MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
-    EXPECT_EQ(seq, consumeSeq);
-    EXPECT_EQ(deviceId, motionEvent->getDeviceId());
-    EXPECT_EQ(source, motionEvent->getSource());
-    EXPECT_EQ(action, motionEvent->getAction());
-    EXPECT_EQ(flags, motionEvent->getFlags());
-    EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
-    EXPECT_EQ(metaState, motionEvent->getMetaState());
-    EXPECT_EQ(buttonState, motionEvent->getButtonState());
-    EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
-    EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
-    EXPECT_EQ(downTime, motionEvent->getDownTime());
-    EXPECT_EQ(eventTime, motionEvent->getEventTime());
-    EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
-    EXPECT_EQ(0U, motionEvent->getHistorySize());
-
-    for (size_t i = 0; i < pointerCount; i++) {
-        SCOPED_TRACE(i);
-        EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
-        EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
-
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
-                motionEvent->getRawX(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
-                motionEvent->getRawY(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
-                motionEvent->getX(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
-                motionEvent->getY(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                motionEvent->getPressure(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-                motionEvent->getSize(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                motionEvent->getTouchMajor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                motionEvent->getTouchMinor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                motionEvent->getToolMajor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                motionEvent->getToolMinor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
-                motionEvent->getOrientation(i));
-    }
-
-    status = mConsumer->sendFinishedSignal(seq, false);
-    ASSERT_EQ(OK, status)
-            << "consumer sendFinishedSignal should return OK";
-
-    uint32_t finishedSeq = 0;
-    bool handled = true;
-    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
-    ASSERT_EQ(OK, status)
-            << "publisher receiveFinishedSignal should return OK";
-    ASSERT_EQ(seq, finishedSeq)
-            << "publisher receiveFinishedSignal should have returned the original sequence number";
-    ASSERT_FALSE(handled)
-            << "publisher receiveFinishedSignal should have set handled to consumer's reply";
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
-    status_t status;
-    const size_t pointerCount = 0;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(BAD_VALUE, status)
-            << "publisher publishMotionEvent should return BAD_VALUE";
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
-    status_t status;
-    const size_t pointerCount = MAX_POINTERS + 1;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].clear();
-        pointerCoords[i].clear();
-    }
-
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(BAD_VALUE, status)
-            << "publisher publishMotionEvent should return BAD_VALUE";
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
-}
-
-} // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
deleted file mode 100644
index d8e985e..0000000
--- a/libs/androidfw/tests/TestHelpers.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 TESTHELPERS_H
-#define TESTHELPERS_H
-
-#include <utils/threads.h>
-
-namespace android {
-
-class Pipe {
-public:
-    int sendFd;
-    int receiveFd;
-
-    Pipe() {
-        int fds[2];
-        ::pipe(fds);
-
-        receiveFd = fds[0];
-        sendFd = fds[1];
-    }
-
-    ~Pipe() {
-        if (sendFd != -1) {
-            ::close(sendFd);
-        }
-
-        if (receiveFd != -1) {
-            ::close(receiveFd);
-        }
-    }
-
-    status_t writeSignal() {
-        ssize_t nWritten = ::write(sendFd, "*", 1);
-        return nWritten == 1 ? 0 : -errno;
-    }
-
-    status_t readSignal() {
-        char buf[1];
-        ssize_t nRead = ::read(receiveFd, buf, 1);
-        return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
-    }
-};
-
-class DelayedTask : public Thread {
-    int mDelayMillis;
-
-public:
-    DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
-
-protected:
-    virtual ~DelayedTask() { }
-
-    virtual void doTask() = 0;
-
-    virtual bool threadLoop() {
-        usleep(mDelayMillis * 1000);
-        doTask();
-        return false;
-    }
-};
-
-} // namespace android
-
-#endif // TESTHELPERS_H
diff --git a/libs/androidfw/tests/ZipFileRO_test.cpp b/libs/androidfw/tests/ZipFileRO_test.cpp
new file mode 100644
index 0000000..cb9c721
--- /dev/null
+++ b/libs/androidfw/tests/ZipFileRO_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ZipFileRO_test"
+#include <utils/Log.h>
+#include <androidfw/ZipFileRO.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+class ZipFileROTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+    struct tm t;
+
+    // 2011-06-29 14:40:40
+    long when = 0x3EDD7514;
+
+    ZipFileRO::zipTimeToTimespec(when, &t);
+
+    EXPECT_EQ(2011, t.tm_year + 1900)
+            << "Year was improperly converted.";
+
+    EXPECT_EQ(6, t.tm_mon)
+            << "Month was improperly converted.";
+
+    EXPECT_EQ(29, t.tm_mday)
+            << "Day was improperly converted.";
+
+    EXPECT_EQ(14, t.tm_hour)
+            << "Hour was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_min)
+            << "Minute was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_sec)
+            << "Second was improperly converted.";
+}
+
+}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a630ea1..411c133 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -10,6 +10,7 @@
 		thread/TaskManager.cpp \
 		font/CacheTexture.cpp \
 		font/Font.cpp \
+		AssetAtlas.cpp \
 		FontRenderer.cpp \
 		GammaFontRenderer.cpp \
 		Caches.cpp \
@@ -21,6 +22,7 @@
 		Extensions.cpp \
 		FboCache.cpp \
 		GradientCache.cpp \
+		Image.cpp \
 		Layer.cpp \
 		LayerCache.cpp \
 		LayerRenderer.cpp \
@@ -39,6 +41,7 @@
 		SkiaShader.cpp \
 		Snapshot.cpp \
 		Stencil.cpp \
+		Texture.cpp \
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 
@@ -52,17 +55,26 @@
 		external/skia/include/images \
 		external/skia/src/core \
 		external/skia/src/ports \
-		external/skia/include/utils \
-		$(intermediates) \
-		frameworks/rs/cpp \
-		frameworks/rs
+		external/skia/include/utils
 
-	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
+	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libGLESv2 libskia libui libRS libRScpp
+	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 
+	ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+		LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
+		LOCAL_SHARED_LIBRARIES += libRS libRScpp libstlport
+		LOCAL_C_INCLUDES += \
+			$(intermediates) \
+			frameworks/rs/cpp \
+			frameworks/rs \
+			external/stlport/stlport \
+			bionic/ \
+			bionic/libstdc++/include
+	endif
+
 	ifndef HWUI_COMPILE_SYMBOLS
 		LOCAL_CFLAGS += -fvisibility=hidden
 	endif
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
new file mode 100644
index 0000000..eb8bb9f
--- /dev/null
+++ b/libs/hwui/AssetAtlas.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include "AssetAtlas.h"
+#include "Caches.h"
+
+#include <GLES2/gl2ext.h>
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Lifecycle
+///////////////////////////////////////////////////////////////////////////////
+
+void AssetAtlas::init(sp<GraphicBuffer> buffer, int* map, int count) {
+    if (mImage) {
+        return;
+    }
+
+    mImage = new Image(buffer);
+
+    if (mImage->getTexture()) {
+        Caches& caches = Caches::getInstance();
+
+        mTexture = new Texture(caches);
+        mTexture->id = mImage->getTexture();
+        mTexture->width = buffer->getWidth();
+        mTexture->height = buffer->getHeight();
+
+        createEntries(caches, map, count);
+    } else {
+        ALOGW("Could not create atlas image");
+
+        delete mImage;
+        mImage = NULL;
+        mTexture = NULL;
+    }
+
+    mGenerationId++;
+}
+
+void AssetAtlas::terminate() {
+    if (mImage) {
+        delete mImage;
+        mImage = NULL;
+
+        delete mTexture;
+        mTexture = NULL;
+
+        for (size_t i = 0; i < mEntries.size(); i++) {
+            delete mEntries.valueAt(i);
+        }
+        mEntries.clear();
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Entries
+///////////////////////////////////////////////////////////////////////////////
+
+AssetAtlas::Entry* AssetAtlas::getEntry(SkBitmap* const bitmap) const {
+    ssize_t index = mEntries.indexOfKey(bitmap);
+    return index >= 0 ? mEntries.valueAt(index) : NULL;
+}
+
+Texture* AssetAtlas::getEntryTexture(SkBitmap* const bitmap) const {
+    ssize_t index = mEntries.indexOfKey(bitmap);
+    return index >= 0 ? mEntries.valueAt(index)->texture : NULL;
+}
+
+/**
+ * Delegates changes to wrapping and filtering to the base atlas texture
+ * instead of applying the changes to the virtual textures.
+ */
+struct DelegateTexture: public Texture {
+    DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { }
+
+    virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+        mDelegate->setWrapST(wrapS, wrapT, bindTexture, force, renderTarget);
+    }
+
+    virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+        mDelegate->setFilterMinMag(min, mag, bindTexture, force, renderTarget);
+    }
+
+private:
+    Texture* const mDelegate;
+}; // struct DelegateTexture
+
+/**
+ * TODO: This method does not take the rotation flag into account
+ */
+void AssetAtlas::createEntries(Caches& caches, int* map, int count) {
+    const float width = float(mTexture->width);
+    const float height = float(mTexture->height);
+
+    for (int i = 0; i < count; ) {
+        SkBitmap* bitmap = (SkBitmap*) map[i++];
+        int x = map[i++];
+        int y = map[i++];
+        bool rotated = map[i++] > 0;
+
+        // Bitmaps should never be null, we're just extra paranoid
+        if (!bitmap) continue;
+
+        const UvMapper mapper(
+                x / width, (x + bitmap->width()) / width,
+                y / height, (y + bitmap->height()) / height);
+
+        Texture* texture = new DelegateTexture(caches, mTexture);
+        texture->id = mTexture->id;
+        texture->blend = !bitmap->isOpaque();
+        texture->width = bitmap->width();
+        texture->height = bitmap->height();
+
+        Entry* entry = new Entry(bitmap, x, y, rotated, texture, mapper, *this);
+        texture->uvMapper = &entry->uvMapper;
+
+        mEntries.add(entry->bitmap, entry);
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
new file mode 100644
index 0000000..a28efc6
--- /dev/null
+++ b/libs/hwui/AssetAtlas.h
@@ -0,0 +1,195 @@
+/*
+ * 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_ASSET_ATLAS_H
+#define ANDROID_HWUI_ASSET_ATLAS_H
+
+#include <GLES2/gl2.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/KeyedVector.h>
+
+#include <cutils/compiler.h>
+
+#include <SkBitmap.h>
+
+#include "Image.h"
+#include "Texture.h"
+#include "UvMapper.h"
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+
+/**
+ * An asset atlas holds a collection of framework bitmaps in a single OpenGL
+ * texture. Each bitmap is associated with a location, defined in pixels,
+ * inside the atlas. The atlas is generated by the framework and bound as
+ * an external texture using the EGLImageKHR extension.
+ */
+class AssetAtlas {
+public:
+    /**
+     * Entry representing the position and rotation of a
+     * bitmap inside the atlas.
+     */
+    struct Entry {
+        /**
+         * The bitmap that generated this atlas entry.
+         */
+        SkBitmap* bitmap;
+
+        /**
+         * Location of the bitmap inside the atlas, in pixels.
+         */
+        int x;
+        int y;
+
+        /**
+         * If set, the bitmap is rotated 90 degrees (clockwise)
+         * inside the atlas.
+         */
+        bool rotated;
+
+        /*
+         * A "virtual texture" object that represents the texture
+         * this entry belongs to. This texture should never be
+         * modified.
+         */
+        Texture* texture;
+
+        /**
+         * Maps texture coordinates in the [0..1] range into the
+         * correct range to sample this entry from the atlas.
+         */
+        const UvMapper uvMapper;
+
+        /**
+         * Atlas this entry belongs to.
+         */
+        const AssetAtlas& atlas;
+
+        /**
+         * Unique identifier used to merge bitmaps and 9-patches stored
+         * in the atlas.
+         */
+        const void* getMergeId() const {
+            return texture->blend ? &atlas.mBlendKey : &atlas.mOpaqueKey;
+        }
+
+    private:
+        Entry(SkBitmap* bitmap, int x, int y, bool rotated,
+                Texture* texture, const UvMapper& mapper, const AssetAtlas& atlas):
+                bitmap(bitmap), x(x), y(y), rotated(rotated),
+                texture(texture), uvMapper(mapper), atlas(atlas) {
+        }
+
+        ~Entry() {
+            delete texture;
+        }
+
+        friend class AssetAtlas;
+    };
+
+    AssetAtlas(): mTexture(NULL), mImage(NULL), mGenerationId(0),
+            mBlendKey(true), mOpaqueKey(false) { }
+    ~AssetAtlas() { terminate(); }
+
+    /**
+     * Initializes the atlas with the specified buffer and
+     * map. The buffer is a gralloc'd texture that will be
+     * used as an EGLImage. The map is a list of SkBitmap*
+     * and their (x, y) positions as well as their rotation
+     * flags.
+     *
+     * This method returns immediately if the atlas is already
+     * initialized. To re-initialize the atlas, you must
+     * first call terminate().
+     */
+    ANDROID_API void init(sp<GraphicBuffer> buffer, int* map, int count);
+
+    /**
+     * Destroys the atlas texture. This object can be
+     * re-initialized after calling this method.
+     *
+     * After calling this method, the width, height
+     * and texture are set to 0.
+     */
+    ANDROID_API void terminate();
+
+    /**
+     * Returns the width of this atlas in pixels.
+     * Can return 0 if the atlas is not initialized.
+     */
+    uint32_t getWidth() const {
+        return mTexture ? mTexture->width : 0;
+    }
+
+    /**
+     * Returns the height of this atlas in pixels.
+     * Can return 0 if the atlas is not initialized.
+     */
+    uint32_t getHeight() const {
+        return mTexture ? mTexture->height : 0;
+    }
+
+    /**
+     * Returns the OpenGL name of the texture backing this atlas.
+     * Can return 0 if the atlas is not initialized.
+     */
+    GLuint getTexture() const {
+        return mTexture ? mTexture->id : 0;
+    }
+
+    /**
+     * Returns the entry in the atlas associated with the specified
+     * bitmap. If the bitmap is not in the atlas, return NULL.
+     */
+    Entry* getEntry(SkBitmap* const bitmap) const;
+
+    /**
+     * Returns the texture for the atlas entry associated with the
+     * specified bitmap. If the bitmap is not in the atlas, return NULL.
+     */
+    Texture* getEntryTexture(SkBitmap* const bitmap) const;
+
+    /**
+     * Returns the current generation id of the atlas.
+     */
+    uint32_t getGenerationId() const {
+        return mGenerationId;
+    }
+
+private:
+    void createEntries(Caches& caches, int* map, int count);
+
+    Texture* mTexture;
+    Image* mImage;
+
+    uint32_t mGenerationId;
+
+    const bool mBlendKey;
+    const bool mOpaqueKey;
+
+    KeyedVector<SkBitmap*, Entry*> mEntries;
+}; // class AssetAtlas
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_ASSET_ATLAS_H
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index a381a68..f8d3589 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -47,19 +47,21 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Caches::Caches(): Singleton<Caches>(), mExtensions(Extensions::getInstance()), mInitialized(false) {
+Caches::Caches(): Singleton<Caches>(),
+        mExtensions(Extensions::getInstance()), mInitialized(false) {
     init();
     initFont();
     initConstraints();
     initProperties();
+    initStaticProperties();
     initExtensions();
 
     mDebugLevel = readDebugLevel();
     ALOGD("Enabling debug mode %d", mDebugLevel);
 }
 
-void Caches::init() {
-    if (mInitialized) return;
+bool Caches::init() {
+    if (mInitialized) return false;
 
     glGenBuffers(1, &meshBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
@@ -82,6 +84,7 @@
     mTextureUnit = 0;
 
     mRegionMesh = NULL;
+    mMeshIndices = 0;
 
     blend = false;
     lastSrcMode = GL_ZERO;
@@ -94,7 +97,13 @@
     debugOverdraw = false;
     debugStencilClip = kStencilHide;
 
+    patchCache.init(*this);
+
     mInitialized = true;
+
+    resetBoundTextures();
+
+    return true;
 }
 
 void Caches::initFont() {
@@ -132,6 +141,18 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 }
 
+void Caches::initStaticProperties() {
+    gpuPixelBuffersEnabled = false;
+
+    // OpenGL ES 3.0+ specific features
+    if (mExtensions.hasPixelBufferObjects()) {
+        char property[PROPERTY_VALUE_MAX];
+        if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
+            gpuPixelBuffersEnabled = !strcmp(property, "true");
+        }
+    }
+}
+
 bool Caches::initProperties() {
     bool prevDebugLayersUpdates = debugLayersUpdates;
     bool prevDebugOverdraw = debugOverdraw;
@@ -145,11 +166,16 @@
         debugLayersUpdates = false;
     }
 
+    debugOverdraw = false;
     if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
         INIT_LOGD("  Overdraw debug enabled: %s", property);
-        debugOverdraw = !strcmp(property, "true");
-    } else {
-        debugOverdraw = false;
+        if (!strcmp(property, "show")) {
+            debugOverdraw = true;
+            mOverdrawDebugColorSet = kColorSet_Default;
+        } else if (!strcmp(property, "show_deuteranomaly")) {
+            debugOverdraw = true;
+            mOverdrawDebugColorSet = kColorSet_Deuteranomaly;
+        }
     }
 
     // See Properties.h for valid values
@@ -191,8 +217,9 @@
     glDeleteBuffers(1, &meshBuffer);
     mCurrentBuffer = 0;
 
-    glDeleteBuffers(1, &mRegionMeshIndices);
+    glDeleteBuffers(1, &mMeshIndices);
     delete[] mRegionMesh;
+    mMeshIndices = 0;
     mRegionMesh = NULL;
 
     fboCache.clear();
@@ -200,6 +227,12 @@
     programCache.clear();
     currentProgram = NULL;
 
+    assetAtlas.terminate();
+
+    patchCache.clear();
+
+    clearGarbage();
+
     mInitialized = false;
 }
 
@@ -207,6 +240,16 @@
 // Debug
 ///////////////////////////////////////////////////////////////////////////////
 
+uint32_t Caches::getOverdrawColor(uint32_t amount) const {
+    static uint32_t sOverdrawColors[2][4] = {
+            { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
+            { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
+    };
+    if (amount < 1) amount = 1;
+    if (amount > 4) amount = 4;
+    return sOverdrawColors[mOverdrawDebugColorSet][amount - 1];
+}
+
 void Caches::dumpMemoryUsage() {
     String8 stringLog;
     dumpMemoryUsage(stringLog);
@@ -227,15 +270,19 @@
             pathCache.getSize(), pathCache.getMaxSize());
     log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
             dropShadowCache.getMaxSize());
+    log.appendFormat("  PatchCache           %8d / %8d\n",
+            patchCache.getSize(), patchCache.getMaxSize());
     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
-        const uint32_t size = fontRenderer->getFontRendererSize(i);
-        log.appendFormat("  FontRenderer %d       %8d / %8d\n", i, size, size);
+        const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
+        const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
+        log.appendFormat("  FontRenderer %d A8    %8d / %8d\n", i, sizeA8, sizeA8);
+        log.appendFormat("  FontRenderer %d RGBA  %8d / %8d\n", i, sizeRGBA, sizeRGBA);
+        log.appendFormat("  FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
+                sizeA8 + sizeRGBA);
     }
     log.appendFormat("Other:\n");
     log.appendFormat("  FboCache             %8d / %8d\n",
             fboCache.getSize(), fboCache.getMaxSize());
-    log.appendFormat("  PatchCache           %8d / %8d\n",
-            patchCache.getSize(), patchCache.getMaxSize());
 
     uint32_t total = 0;
     total += textureCache.getSize();
@@ -244,8 +291,10 @@
     total += gradientCache.getSize();
     total += pathCache.getSize();
     total += dropShadowCache.getSize();
+    total += patchCache.getSize();
     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
-        total += fontRenderer->getFontRendererSize(i);
+        total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
+        total += fontRenderer->getFontRendererSize(i, GL_RGBA);
     }
 
     log.appendFormat("Total memory usage:\n");
@@ -259,6 +308,7 @@
 void Caches::clearGarbage() {
     textureCache.clearGarbage();
     pathCache.clearGarbage();
+    patchCache.clearGarbage();
 
     Vector<DisplayList*> displayLists;
     Vector<Layer*> layers;
@@ -298,6 +348,11 @@
 void Caches::flush(FlushMode mode) {
     FLUSH_LOGD("Flushing caches (mode %d)", mode);
 
+    // We must stop tasks before clearing caches
+    if (mode > kFlushMode_Layers) {
+        tasks.stop();
+    }
+
     switch (mode) {
         case kFlushMode_Full:
             textureCache.clear();
@@ -305,13 +360,13 @@
             dropShadowCache.clear();
             gradientCache.clear();
             fontRenderer->clear();
+            fboCache.clear();
             dither.clear();
             // fall through
         case kFlushMode_Moderate:
             fontRenderer->flush();
             textureCache.flush();
             pathCache.clear();
-            tasks.stop();
             // fall through
         case kFlushMode_Layers:
             layerCache.clear();
@@ -357,6 +412,32 @@
     return false;
 }
 
+bool Caches::bindIndicesBuffer() {
+    if (!mMeshIndices) {
+        uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
+        for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
+            uint16_t quad = i * 4;
+            int index = i * 6;
+            regionIndices[index    ] = quad;       // top-left
+            regionIndices[index + 1] = quad + 1;   // top-right
+            regionIndices[index + 2] = quad + 2;   // bottom-left
+            regionIndices[index + 3] = quad + 2;   // bottom-left
+            regionIndices[index + 4] = quad + 1;   // top-right
+            regionIndices[index + 5] = quad + 3;   // bottom-right
+        }
+
+        glGenBuffers(1, &mMeshIndices);
+        bool force = bindIndicesBuffer(mMeshIndices);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
+                regionIndices, GL_STATIC_DRAW);
+
+        delete[] regionIndices;
+        return force;
+    }
+
+    return bindIndicesBuffer(mMeshIndices);
+}
+
 bool Caches::unbindIndicesBuffer() {
     if (mCurrentIndicesBuffer) {
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -441,6 +522,50 @@
     }
 }
 
+void Caches::resetActiveTexture() {
+    mTextureUnit = -1;
+}
+
+void Caches::bindTexture(GLuint texture) {
+    if (mBoundTextures[mTextureUnit] != texture) {
+        glBindTexture(GL_TEXTURE_2D, texture);
+        mBoundTextures[mTextureUnit] = texture;
+    }
+}
+
+void Caches::bindTexture(GLenum target, GLuint texture) {
+    if (mBoundTextures[mTextureUnit] != texture) {
+        glBindTexture(target, texture);
+        mBoundTextures[mTextureUnit] = texture;
+    }
+}
+
+void Caches::deleteTexture(GLuint texture) {
+    // When glDeleteTextures() is called on a currently bound texture,
+    // OpenGL ES specifies that the texture is then considered unbound
+    // Consider the following series of calls:
+    //
+    // glGenTextures -> creates texture name 2
+    // glBindTexture(2)
+    // glDeleteTextures(2) -> 2 is now unbound
+    // glGenTextures -> can return 2 again
+    //
+    // If we don't call glBindTexture(2) after the second glGenTextures
+    // 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;
+        }
+    }
+    glDeleteTextures(1, &texture);
+}
+
+void Caches::resetBoundTextures() {
+    memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Scissor
 ///////////////////////////////////////////////////////////////////////////////
@@ -545,28 +670,7 @@
 TextureVertex* Caches::getRegionMesh() {
     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
     if (!mRegionMesh) {
-        mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
-
-        uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
-        for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
-            uint16_t quad = i * 4;
-            int index = i * 6;
-            regionIndices[index    ] = quad;       // top-left
-            regionIndices[index + 1] = quad + 1;   // top-right
-            regionIndices[index + 2] = quad + 2;   // bottom-left
-            regionIndices[index + 3] = quad + 2;   // bottom-left
-            regionIndices[index + 4] = quad + 1;   // top-right
-            regionIndices[index + 5] = quad + 3;   // bottom-right
-        }
-
-        glGenBuffers(1, &mRegionMeshIndices);
-        bindIndicesBuffer(mRegionMeshIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
-                regionIndices, GL_STATIC_DRAW);
-
-        delete[] regionIndices;
-    } else {
-        bindIndicesBuffer(mRegionMeshIndices);
+        mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
     }
 
     return mRegionMesh;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 91b938b..282aee9 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -21,13 +21,18 @@
     #define LOG_TAG "OpenGLRenderer"
 #endif
 
+#include <GLES3/gl3.h>
+
+#include <utils/KeyedVector.h>
 #include <utils/Singleton.h>
+#include <utils/Vector.h>
 
 #include <cutils/compiler.h>
 
 #include "thread/TaskProcessor.h"
 #include "thread/TaskManager.h"
 
+#include "AssetAtlas.h"
 #include "FontRenderer.h"
 #include "GammaFontRenderer.h"
 #include "TextureCache.h"
@@ -50,9 +55,11 @@
 // Globals
 ///////////////////////////////////////////////////////////////////////////////
 
+// GL ES 2.0 defines that at least 16 texture units must be supported
 #define REQUIRED_TEXTURE_UNITS_COUNT 3
 
-#define REGION_MESH_QUAD_COUNT 512
+// Maximum number of quads that pre-allocated meshes can draw
+static const uint32_t gMaxNumberOfQuads = 2048;
 
 // Generates simple and textured vertices
 #define FV(x, y, u, v) { { x, y }, { u, v } }
@@ -74,6 +81,7 @@
 static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
 static const GLsizei gMeshCount = 4;
 
+// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
 static const GLenum gTextureUnits[] = {
     GL_TEXTURE0,
     GL_TEXTURE1,
@@ -113,7 +121,7 @@
     /**
      * Initialize caches.
      */
-    void init();
+    bool init();
 
     /**
      * Initialize global system properties.
@@ -142,6 +150,12 @@
     }
 
     /**
+     * Returns a non-premultiplied ARGB color for the specified
+     * amount of overdraw (1 for 1x, 2 for 2x, etc.)
+     */
+    uint32_t getOverdrawColor(uint32_t amount) const;
+
+    /**
      * Call this on each frame to ensure that garbage is deleted from
      * GPU memory.
      */
@@ -172,6 +186,11 @@
      */
     bool unbindMeshBuffer();
 
+    /**
+     * Binds a global indices buffer that can draw up to
+     * gMaxNumberOfQuads quads.
+     */
+    bool bindIndicesBuffer();
     bool bindIndicesBuffer(const GLuint buffer);
     bool unbindIndicesBuffer();
 
@@ -213,6 +232,38 @@
     void activeTexture(GLuint textureUnit);
 
     /**
+     * Invalidate the cached value of the active texture unit.
+     */
+    void resetActiveTexture();
+
+    /**
+     * Binds the specified texture as a GL_TEXTURE_2D texture.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLenum, GLuint).
+     */
+    void bindTexture(GLuint texture);
+
+    /**
+     * Binds the specified texture with the specified render target.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLuint).
+     */
+    void bindTexture(GLenum target, GLuint texture);
+
+    /**
+     * Deletes the specified texture and clears it from the cache
+     * of bound textures.
+     * All textures must be deleted using this method.
+     */
+    void deleteTexture(GLuint texture);
+
+    /**
+     * Signals that the cache of bound textures should be cleared.
+     * Other users of the context may have altered which textures are bound.
+     */
+    void resetBoundTextures();
+
+    /**
      * Sets the scissor for the current surface.
      */
     bool setScissor(GLint x, GLint y, GLint width, GLint height);
@@ -290,6 +341,10 @@
     Dither dither;
     Stencil stencil;
 
+    AssetAtlas assetAtlas;
+
+    bool gpuPixelBuffersEnabled;
+
     // Debug methods
     PFNGLINSERTEVENTMARKEREXTPROC eventMark;
     PFNGLPUSHGROUPMARKEREXTPROC startMark;
@@ -299,9 +354,15 @@
     PFNGLGETOBJECTLABELEXTPROC getLabel;
 
 private:
+    enum OverdrawColorSet {
+        kColorSet_Default = 0,
+        kColorSet_Deuteranomaly
+    };
+
     void initFont();
     void initExtensions();
     void initConstraints();
+    void initStaticProperties();
 
     static void eventMarkNull(GLsizei length, const GLchar* marker) { }
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
@@ -336,7 +397,9 @@
 
     // Used to render layers
     TextureVertex* mRegionMesh;
-    GLuint mRegionMeshIndices;
+
+    // Global index buffer
+    GLuint mMeshIndices;
 
     mutable Mutex mGarbageLock;
     Vector<Layer*> mLayerGarbage;
@@ -346,6 +409,10 @@
     bool mInitialized;
 
     uint32_t mFunctorsCount;
+
+    GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
+
+    OverdrawColorSet mOverdrawDebugColorSet;
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 790c4f4..786f12a 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -53,8 +53,6 @@
 
 // Turn on to display debug info about 9patch objects
 #define DEBUG_PATCHES 0
-// Turn on to "explode" 9patch objects
-#define DEBUG_EXPLODE_PATCHES 0
 // Turn on to display vertex and tex coords data about 9patch objects
 // This flag requires DEBUG_PATCHES to be turned on
 #define DEBUG_PATCHES_VERTICES 0
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 9323a3a..7eb7028 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -20,6 +20,8 @@
 #include <SkCanvas.h>
 
 #include <utils/Trace.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 #include "Caches.h"
 #include "Debug.h"
@@ -51,32 +53,36 @@
 public:
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0;
     virtual ~Batch() {}
+    virtual bool purelyDrawBatch() { return false; }
+    virtual bool coversBounds(const Rect& bounds) { return false; }
 };
 
 class DrawBatch : public Batch {
 public:
-    DrawBatch(int batchId, mergeid_t mergeId) : mBatchId(batchId), mMergeId(mergeId) {
+    DrawBatch(const DeferInfo& deferInfo) : mAllOpsOpaque(true),
+            mBatchId(deferInfo.batchId), mMergeId(deferInfo.mergeId) {
         mOps.clear();
     }
 
     virtual ~DrawBatch() { mOps.clear(); }
 
-    void add(DrawOp* op) {
+    virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
         // NOTE: ignore empty bounds special case, since we don't merge across those ops
-        mBounds.unionWith(op->state.mBounds);
-        mOps.add(op);
+        mBounds.unionWith(state->mBounds);
+        mAllOpsOpaque &= opaqueOverBounds;
+        mOps.add(OpStatePair(op, state));
     }
 
-    bool intersects(Rect& rect) {
+    bool intersects(const Rect& rect) {
         if (!rect.intersects(mBounds)) return false;
 
         for (unsigned int i = 0; i < mOps.size(); i++) {
-            if (rect.intersects(mOps[i]->state.mBounds)) {
+            if (rect.intersects(mOps[i].state->mBounds)) {
 #if DEBUG_DEFER
-                DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
-                        mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
-                        mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
-                mOps[i]->output(2);
+                DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i].op,
+                        mOps[i].state->mBounds.left, mOps[i].state->mBounds.top,
+                        mOps[i].state->mBounds.right, mOps[i].state->mBounds.bottom);
+                mOps[i].op->output(2);
 #endif
                 return true;
             }
@@ -85,15 +91,15 @@
     }
 
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
-        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
-                index, this, mOps.size(), mOps[0]->getBatchId(), mOps[0]->getMergeId());
+        DEFER_LOGD("%d  replaying DrawBatch %p, with %d ops (batch id %x, merge id %p)",
+                index, this, mOps.size(), getBatchId(), getMergeId());
 
         status_t status = DrawGlInfo::kStatusDone;
         DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
         for (unsigned int i = 0; i < mOps.size(); i++) {
-            DrawOp* op = mOps[i];
-
-            renderer.restoreDisplayState(op->state);
+            DrawOp* op = mOps[i].op;
+            const DeferredDisplayState* state = mOps[i].state;
+            renderer.restoreDisplayState(*state);
 
 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
             renderer.eventMark(op->name());
@@ -102,7 +108,7 @@
             status |= op->applyDraw(renderer, dirty);
 
 #if DEBUG_MERGE_BEHAVIOR
-            Rect& bounds = mOps[i]->state.mBounds;
+            const Rect& bounds = state->mBounds;
             int batchColor = 0x1f000000;
             if (getBatchId() & 0x1) batchColor |= 0x0000ff;
             if (getBatchId() & 0x2) batchColor |= 0x00ff00;
@@ -114,14 +120,28 @@
         return status;
     }
 
+    virtual bool purelyDrawBatch() { return true; }
+
+    virtual bool coversBounds(const Rect& bounds) {
+        if (CC_LIKELY(!mAllOpsOpaque || !mBounds.contains(bounds) || count() == 1)) return false;
+
+        Region uncovered(android::Rect(bounds.left, bounds.top, bounds.right, bounds.bottom));
+        for (unsigned int i = 0; i < mOps.size(); i++) {
+            const Rect &r = mOps[i].state->mBounds;
+            uncovered.subtractSelf(android::Rect(r.left, r.top, r.right, r.bottom));
+        }
+        return uncovered.isEmpty();
+    }
+
     inline int getBatchId() const { return mBatchId; }
     inline mergeid_t getMergeId() const { return mMergeId; }
     inline int count() const { return mOps.size(); }
 
 protected:
-    Vector<DrawOp*> mOps;
-    Rect mBounds;
+    Vector<OpStatePair> mOps;
+    Rect mBounds; // union of bounds of contained ops
 private:
+    bool mAllOpsOpaque;
     int mBatchId;
     mergeid_t mMergeId;
 };
@@ -132,39 +152,77 @@
 
 class MergingDrawBatch : public DrawBatch {
 public:
-    MergingDrawBatch(int batchId, mergeid_t mergeId) : DrawBatch(batchId, mergeId) {}
+    MergingDrawBatch(DeferInfo& deferInfo, int width, int height) :
+            DrawBatch(deferInfo), mClipRect(width, height),
+            mClipSideFlags(kClipSide_None) {}
+
+    /*
+     * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
+     * and clip side flags. Positive bounds delta means new bounds fit in old.
+     */
+    static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
+            float boundsDelta) {
+        bool currentClipExists = currentFlags & side;
+        bool newClipExists = newFlags & side;
+
+        // if current is clipped, we must be able to fit new bounds in current
+        if (boundsDelta > 0 && currentClipExists) return false;
+
+        // if new is clipped, we must be able to fit current bounds in new
+        if (boundsDelta < 0 && newClipExists) return false;
+
+        return true;
+    }
 
     /*
      * Checks if a (mergeable) op can be merged into this batch
      *
      * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
      * important to consider all paint attributes used in the draw calls in deciding both a) if an
-     * op tries to merge at all, and b) if the op
+     * op tries to merge at all, and b) if the op can merge with another set of ops
      *
      * False positives can lead to information from the paints of subsequent merged operations being
      * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
      */
-    bool canMergeWith(DrawOp* op) {
-        if (!op->state.mMatrix.isPureTranslate()) return false;
-
+    bool canMergeWith(const DrawOp* op, const DeferredDisplayState* state) {
         bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text ||
                 getBatchId() == DeferredDisplayList::kOpBatch_ColorText;
 
         // Overlapping other operations is only allowed for text without shadow. For other ops,
         // multiDraw isn't guaranteed to overdraw correctly
-        if (!isTextBatch || op->state.mDrawModifiers.mHasShadow) {
-            if (intersects(op->state.mBounds)) return false;
+        if (!isTextBatch || state->mDrawModifiers.mHasShadow) {
+            if (intersects(state->mBounds)) return false;
+        }
+        const DeferredDisplayState* lhs = state;
+        const DeferredDisplayState* rhs = mOps[0].state;
+
+        if (NEQ_FALPHA(lhs->mAlpha, rhs->mAlpha)) return false;
+
+        /* Clipping compatibility check
+         *
+         * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its
+         * clip for that side.
+         */
+        const int currentFlags = mClipSideFlags;
+        const int newFlags = state->mClipSideFlags;
+        if (currentFlags != kClipSide_None || newFlags != kClipSide_None) {
+            const Rect& opBounds = state->mBounds;
+            float boundsDelta = mBounds.left - opBounds.left;
+            if (!checkSide(currentFlags, newFlags, kClipSide_Left, boundsDelta)) return false;
+            boundsDelta = mBounds.top - opBounds.top;
+            if (!checkSide(currentFlags, newFlags, kClipSide_Top, boundsDelta)) return false;
+
+            // right and bottom delta calculation reversed to account for direction
+            boundsDelta = opBounds.right - mBounds.right;
+            if (!checkSide(currentFlags, newFlags, kClipSide_Right, boundsDelta)) return false;
+            boundsDelta = opBounds.bottom - mBounds.bottom;
+            if (!checkSide(currentFlags, newFlags, kClipSide_Bottom, boundsDelta)) return false;
         }
 
-        const DeferredDisplayState& lhs = op->state;
-        const DeferredDisplayState& rhs = mOps[0]->state;
-
-        if (NEQ_FALPHA(lhs.mAlpha, rhs.mAlpha)) return false;
-
         // if paints are equal, then modifiers + paint attribs don't need to be compared
-        if (op->mPaint == mOps[0]->mPaint) return true;
+        if (op->mPaint == mOps[0].op->mPaint) return true;
 
-        if (op->getPaintAlpha() != mOps[0]->getPaintAlpha()) return false;
+        if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false;
 
         /* Draw Modifiers compatibility check
          *
@@ -178,9 +236,8 @@
          *
          * These ignore cases prevent us from simply memcmp'ing the drawModifiers
          */
-
-        const DrawModifiers& lhsMod = lhs.mDrawModifiers;
-        const DrawModifiers& rhsMod = rhs.mDrawModifiers;
+        const DrawModifiers& lhsMod = lhs->mDrawModifiers;
+        const DrawModifiers& rhsMod = rhs->mDrawModifiers;
         if (lhsMod.mShader != rhsMod.mShader) return false;
         if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
 
@@ -192,17 +249,37 @@
         return true;
     }
 
+    virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
+        DrawBatch::add(op, state, opaqueOverBounds);
+
+        const int newClipSideFlags = state->mClipSideFlags;
+        mClipSideFlags |= newClipSideFlags;
+        if (newClipSideFlags & kClipSide_Left) mClipRect.left = state->mClip.left;
+        if (newClipSideFlags & kClipSide_Top) mClipRect.top = state->mClip.top;
+        if (newClipSideFlags & kClipSide_Right) mClipRect.right = state->mClip.right;
+        if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom;
+    }
+
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
-        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
-                index, this, mOps.size(), getBatchId(), getMergeId());
+        DEFER_LOGD("%d  replaying MergingDrawBatch %p, with %d ops,"
+                " clip flags %x (batch id %x, merge id %p)",
+                index, this, mOps.size(), mClipSideFlags, getBatchId(), getMergeId());
         if (mOps.size() == 1) {
-            return DrawBatch::replay(renderer, dirty, false);
+            return DrawBatch::replay(renderer, dirty, -1);
         }
 
-        DrawOp* op = mOps[0];
+        // clipping in the merged case is done ahead of time since all ops share the clip (if any)
+        renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : NULL);
+
+        DrawOp* op = mOps[0].op;
         DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
         buffer.writeCommand(0, "multiDraw");
         buffer.writeCommand(1, op->name());
+
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+        renderer.eventMark("multiDraw");
+        renderer.eventMark(op->name());
+#endif
         status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
 
 #if DEBUG_MERGE_BEHAVIOR
@@ -211,16 +288,25 @@
 #endif
         return status;
     }
+
+private:
+    /*
+     * Contains the effective clip rect shared by all merged ops. Initialized to the layer viewport,
+     * it will shrink if an op must be clipped on a certain side. The clipped sides are reflected in
+     * mClipSideFlags.
+     */
+    Rect mClipRect;
+    int mClipSideFlags;
 };
 
 class StateOpBatch : public Batch {
 public:
     // creates a single operation batch
-    StateOpBatch(StateOp* op) : mOp(op) {}
+    StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {}
 
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
         DEFER_LOGD("replaying state op batch %p", this);
-        renderer.restoreDisplayState(mOp->state);
+        renderer.restoreDisplayState(*mState);
 
         // use invalid save count because it won't be used at flush time - RestoreToCountOp is the
         // only one to use it, and we don't use that class at flush time, instead calling
@@ -232,16 +318,18 @@
 
 private:
     const StateOp* mOp;
+    const DeferredDisplayState* mState;
 };
 
 class RestoreToCountBatch : public Batch {
 public:
-    RestoreToCountBatch(StateOp* op, int restoreCount) : mOp(op), mRestoreCount(restoreCount) {}
+    RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) :
+            mOp(op), mState(state), mRestoreCount(restoreCount) {}
 
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
         DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
 
-        renderer.restoreDisplayState(mOp->state);
+        renderer.restoreDisplayState(*mState);
         renderer.restoreToCount(mRestoreCount);
         return DrawGlInfo::kStatusDone;
     }
@@ -249,6 +337,8 @@
 private:
     // we use the state storage for the RestoreToCountOp, but don't replay the op itself
     const StateOp* mOp;
+    const DeferredDisplayState* mState;
+
     /*
      * The count used here represents the flush() time saveCount. This is as opposed to the
      * DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and
@@ -294,6 +384,7 @@
     mBatches.clear();
     mSaveStack.clear();
     mEarliestBatchIndex = 0;
+    mEarliestUnclearedIndex = 0;
 }
 
 /////////////////////////////////////////////////////////////////////////////////
@@ -398,22 +489,45 @@
 }
 
 void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
-    if (renderer.storeDisplayState(op->state, getDrawOpDeferFlags())) {
+    /* 1: op calculates local bounds */
+    DeferredDisplayState* const state = createState();
+    if (op->getLocalBounds(renderer.getDrawModifiers(), state->mBounds)) {
+        if (state->mBounds.isEmpty()) {
+            // valid empty bounds, don't bother deferring
+            tryRecycleState(state);
+            return;
+        }
+    } else {
+        state->mBounds.setEmpty();
+    }
+
+    /* 2: renderer calculates global bounds + stores state */
+    if (renderer.storeDisplayState(*state, getDrawOpDeferFlags())) {
+        tryRecycleState(state);
         return; // quick rejected
     }
 
-    int batchId = kOpBatch_None;
-    mergeid_t mergeId = (mergeid_t) -1;
-    bool mergeable = op->onDefer(renderer, &batchId, &mergeId);
+    /* 3: ask op for defer info, given renderer state */
+    DeferInfo deferInfo;
+    op->onDefer(renderer, deferInfo, *state);
 
     // complex clip has a complex set of expectations on the renderer state - for now, avoid taking
     // the merge path in those cases
-    mergeable &= !recordingComplexClip();
+    deferInfo.mergeable &= !recordingComplexClip();
+    deferInfo.opaqueOverBounds &= !recordingComplexClip() && mSaveStack.isEmpty();
+
+    if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
+            state->mClipSideFlags != kClipSide_ConservativeFull &&
+            deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) {
+        // avoid overdraw by resetting drawing state + discarding drawing ops
+        discardDrawingBatches(mBatches.size() - 1);
+        resetBatchingState();
+    }
 
     if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
         // TODO: elegant way to reuse batches?
-        DrawBatch* b = new DrawBatch(batchId, mergeId);
-        b->add(op);
+        DrawBatch* b = new DrawBatch(deferInfo);
+        b->add(op, state, deferInfo.opaqueOverBounds);
         mBatches.add(b);
         return;
     }
@@ -425,10 +539,10 @@
     // (eventually, should be similar shader)
     int insertBatchIndex = mBatches.size();
     if (!mBatches.isEmpty()) {
-        if (op->state.mBounds.isEmpty()) {
+        if (state->mBounds.isEmpty()) {
             // don't know the bounds for op, so add to last batch and start from scratch on next op
-            DrawBatch* b = new DrawBatch(batchId, mergeId);
-            b->add(op);
+            DrawBatch* b = new DrawBatch(deferInfo);
+            b->add(op, state, deferInfo.opaqueOverBounds);
             mBatches.add(b);
             resetBatchingState();
 #if DEBUG_DEFER
@@ -438,19 +552,19 @@
             return;
         }
 
-        if (mergeable) {
+        if (deferInfo.mergeable) {
             // Try to merge with any existing batch with same mergeId.
-            if (mMergingBatches[batchId].get(mergeId, targetBatch)) {
-                if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op)) {
+            if (mMergingBatches[deferInfo.batchId].get(deferInfo.mergeId, targetBatch)) {
+                if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) {
                     targetBatch = NULL;
                 }
             }
         } else {
             // join with similar, non-merging batch
-            targetBatch = (DrawBatch*)mBatchLookup[batchId];
+            targetBatch = (DrawBatch*)mBatchLookup[deferInfo.batchId];
         }
 
-        if (targetBatch || mergeable) {
+        if (targetBatch || deferInfo.mergeable) {
             // iterate back toward target to see if anything drawn since should overlap the new op
             // if no target, merging ops still interate to find similar batch to insert after
             for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
@@ -459,19 +573,19 @@
                 if (overBatch == targetBatch) break;
 
                 // TODO: also consider shader shared between batch types
-                if (batchId == overBatch->getBatchId()) {
+                if (deferInfo.batchId == overBatch->getBatchId()) {
                     insertBatchIndex = i + 1;
                     if (!targetBatch) break; // found insert position, quit
                 }
 
-                if (overBatch->intersects(op->state.mBounds)) {
+                if (overBatch->intersects(state->mBounds)) {
                     // NOTE: it may be possible to optimize for special cases where two operations
                     // of the same batch/paint could swap order, such as with a non-mergeable
                     // (clipped) and a mergeable text operation
                     targetBatch = NULL;
 #if DEBUG_DEFER
-                    DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
-                            targetIndex, i);
+                    DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d",
+                            targetBatch, i);
                     op->output(2);
 #endif
                     break;
@@ -481,27 +595,30 @@
     }
 
     if (!targetBatch) {
-        if (mergeable) {
-            targetBatch = new MergingDrawBatch(batchId, mergeId);
-            mMergingBatches[batchId].put(mergeId, targetBatch);
+        if (deferInfo.mergeable) {
+            targetBatch = new MergingDrawBatch(deferInfo,
+                    renderer.getViewportWidth(), renderer.getViewportHeight());
+            mMergingBatches[deferInfo.batchId].put(deferInfo.mergeId, targetBatch);
         } else {
-            targetBatch = new DrawBatch(batchId, mergeId);
-            mBatchLookup[batchId] = targetBatch;
-            DEFER_LOGD("creating Batch %p, bid %x, at %d",
-                    targetBatch, batchId, insertBatchIndex);
+            targetBatch = new DrawBatch(deferInfo);
+            mBatchLookup[deferInfo.batchId] = targetBatch;
         }
 
+        DEFER_LOGD("creating %singBatch %p, bid %x, at %d",
+                deferInfo.mergeable ? "Merg" : "Draw",
+                targetBatch, deferInfo.batchId, insertBatchIndex);
         mBatches.insertAt(targetBatch, insertBatchIndex);
     }
 
-    targetBatch->add(op);
+    targetBatch->add(op, state, deferInfo.opaqueOverBounds);
 }
 
 void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) {
     DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size());
 
-    renderer.storeDisplayState(op->state, getStateOpDeferFlags());
-    mBatches.add(new StateOpBatch(op));
+    DeferredDisplayState* state = createState();
+    renderer.storeDisplayState(*state, getStateOpDeferFlags());
+    mBatches.add(new StateOpBatch(op, state));
     resetBatchingState();
 }
 
@@ -512,8 +629,9 @@
 
     // store displayState for the restore operation, as it may be associated with a saveLayer that
     // doesn't have kClip_SaveFlag set
-    renderer.storeDisplayState(op->state, getStateOpDeferFlags());
-    mBatches.add(new RestoreToCountBatch(op, newSaveCount));
+    DeferredDisplayState* state = createState();
+    renderer.storeDisplayState(*state, getStateOpDeferFlags());
+    mBatches.add(new RestoreToCountBatch(op, state, newSaveCount));
     resetBatchingState();
 }
 
@@ -526,7 +644,9 @@
     status_t status = DrawGlInfo::kStatusDone;
 
     for (unsigned int i = 0; i < batchList.size(); i++) {
-        status |= batchList[i]->replay(renderer, dirty, i);
+        if (batchList[i]) {
+            status |= batchList[i]->replay(renderer, dirty, i);
+        }
     }
     DEFER_LOGD("--flushed, drew %d batches", batchList.size());
     return status;
@@ -548,6 +668,13 @@
     DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
     renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
+    if (CC_LIKELY(mAvoidOverdraw)) {
+        for (unsigned int i = 1; i < mBatches.size(); i++) {
+            if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) {
+                discardDrawingBatches(i - 1);
+            }
+        }
+    }
     // NOTE: depth of the save stack at this point, before playback, should be reflected in
     // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly
     status |= replayBatchList(mBatches, renderer, dirty);
@@ -560,5 +687,17 @@
     return status;
 }
 
+void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) {
+    for (unsigned int i = mEarliestUnclearedIndex; i <= maxIndex; i++) {
+        // leave deferred state ops alone for simplicity (empty save restore pairs may now exist)
+        if (mBatches[i] && mBatches[i]->purelyDrawBatch()) {
+            DrawBatch* b = (DrawBatch*) mBatches[i];
+            delete mBatches[i];
+            mBatches.replaceAt(NULL, i);
+        }
+    }
+    mEarliestUnclearedIndex = maxIndex + 1;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 9782c1c..3dcbd0b 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -18,11 +18,13 @@
 #define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
 
 #include <utils/Errors.h>
+#include <utils/LinearAllocator.h>
 #include <utils/Vector.h>
+#include <utils/TinyHashMap.h>
 
 #include "Matrix.h"
+#include "OpenGLRenderer.h"
 #include "Rect.h"
-#include "utils/TinyHashMap.h"
 
 class SkBitmap;
 
@@ -34,18 +36,56 @@
 class SaveOp;
 class SaveLayerOp;
 class StateOp;
+
+class DeferredDisplayState;
 class OpenGLRenderer;
 
 class Batch;
 class DrawBatch;
 class MergingDrawBatch;
 
-typedef void* mergeid_t;
+typedef const void* mergeid_t;
+
+class DeferredDisplayState {
+public:
+    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
+    Rect mBounds;
+
+    // the below are set and used by the OpenGLRenderer at record and deferred playback
+    bool mClipValid;
+    Rect mClip;
+    int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
+    bool mClipped;
+    mat4 mMatrix;
+    DrawModifiers mDrawModifiers;
+    float mAlpha;
+};
+
+class OpStatePair {
+public:
+    OpStatePair()
+            : op(NULL), state(NULL) {}
+    OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState)
+            : op(newOp), state(newState) {}
+    OpStatePair(const OpStatePair& other)
+            : op(other.op), state(other.state) {}
+    DrawOp* op;
+    const DeferredDisplayState* state;
+};
 
 class DeferredDisplayList {
 public:
-    DeferredDisplayList() { clear(); }
+    DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
+            mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
+        clear();
+    }
     ~DeferredDisplayList() { clear(); }
+    void reset(const Rect& bounds) { mBounds.set(bounds); }
 
     enum OpBatchId {
         kOpBatch_None = 0, // Don't batch
@@ -75,11 +115,19 @@
 
     /**
      * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if
-     * disallowReorder is false, respecting draw order when overlaps occur
+     * disallowReorder is false, respecting draw order when overlaps occur.
      */
     void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
 
 private:
+    DeferredDisplayState* createState() {
+        return new (mAllocator) DeferredDisplayState();
+    }
+
+    void tryRecycleState(DeferredDisplayState* state) {
+        mAllocator.rewindIfLastAlloc(state, sizeof(DeferredDisplayState));
+    }
+
     /**
      * Resets the batching back-pointers, creating a barrier in the operation stream so that no ops
      * added in the future will be inserted into a batch that already exist.
@@ -96,6 +144,12 @@
     int getStateOpDeferFlags() const;
     int getDrawOpDeferFlags() const;
 
+    void discardDrawingBatches(const unsigned int maxIndex);
+
+    // layer space bounds of rendering
+    Rect mBounds;
+    const bool mAvoidOverdraw;
+
     /**
      * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so
      * that when an associated restoreToCount is deferred, it can be recorded as a
@@ -112,12 +166,35 @@
     // Points to the index after the most recent barrier
     int mEarliestBatchIndex;
 
+    // Points to the first index that may contain a pure drawing batch
+    int mEarliestUnclearedIndex;
+
     /**
      * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
      * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
      * collide, which avoids the need to resolve mergeid collisions.
      */
     TinyHashMap<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
+
+    LinearAllocator mAllocator;
+};
+
+/**
+ * Struct containing information that instructs the defer
+ */
+struct DeferInfo {
+public:
+    DeferInfo() :
+            batchId(DeferredDisplayList::kOpBatch_None),
+            mergeId((mergeid_t) -1),
+            mergeable(false),
+            opaqueOverBounds(false) {
+    };
+
+    int batchId;
+    mergeid_t mergeId;
+    bool mergeable;
+    bool opaqueOverBounds; // opaque over bounds in DeferredDisplayState - can skip ops below
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 1cbd531..bb6526e 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -44,13 +44,14 @@
 }
 
 DisplayList::DisplayList(const DisplayListRenderer& recorder) :
-    mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
+    mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
     mStaticMatrix(NULL), mAnimationMatrix(NULL) {
 
     initFromDisplayListRenderer(recorder);
 }
 
 DisplayList::~DisplayList() {
+    mDestroyed = true;
     clearResources();
 }
 
@@ -63,7 +64,6 @@
 
 void DisplayList::clearResources() {
     mDisplayListData = NULL;
-    mSize = 0; // TODO: shouldn't be needed, WAR possible use after delete
 
     mClipRectOp = NULL;
     mSaveLayerOp = NULL;
@@ -100,6 +100,10 @@
         caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
     }
 
+    for (size_t i = 0; i < mPatchResources.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
+    }
+
     for (size_t i = 0; i < mShaders.size(); i++) {
         caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
         caches.resourceCache.destructorLocked(mShaders.itemAt(i));
@@ -134,6 +138,7 @@
     mBitmapResources.clear();
     mOwnedBitmapResources.clear();
     mFilterResources.clear();
+    mPatchResources.clear();
     mShaders.clear();
     mSourcePaths.clear();
     mPaints.clear();
@@ -169,6 +174,10 @@
     mSaveLayerOp = new (alloc) SaveLayerOp();
     mSaveOp = new (alloc) SaveOp();
     mRestoreToCountOp = new (alloc) RestoreToCountOp();
+    if (CC_UNLIKELY(!mSaveOp)) { // temporary debug logging
+        ALOGW("Error: %s's SaveOp not allocated, size %d", getName(), mSize);
+        CRASH();
+    }
 
     mFunctorCount = recorder.getFunctorCount();
 
@@ -197,6 +206,13 @@
         caches.resourceCache.incrementRefcountLocked(resource);
     }
 
+    const Vector<Res_png_9patch*>& patchResources = recorder.getPatchResources();
+    for (size_t i = 0; i < patchResources.size(); i++) {
+        Res_png_9patch* resource = patchResources.itemAt(i);
+        mPatchResources.add(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
+    }
+
     const Vector<SkiaShader*>& shaders = recorder.getShaders();
     for (size_t i = 0; i < shaders.size(); i++) {
         SkiaShader* resource = shaders.itemAt(i);
@@ -342,7 +358,7 @@
     }
     if (mAnimationMatrix) {
         ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
-                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
+                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix));
     }
     if (mMatrixFlags != 0) {
         if (mMatrixFlags == TRANSLATION) {
@@ -352,6 +368,8 @@
                     level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
         }
     }
+
+    bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
     if (mAlpha < 1) {
         if (mCaching) {
             ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
@@ -359,15 +377,16 @@
             ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
         } else {
             int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (mClipToBounds) {
+            if (clipToBoundsNeeded) {
                 flags |= SkCanvas::kClipToLayer_SaveFlag;
+                clipToBoundsNeeded = false; // clipping done by save layer
             }
             ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
                     (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
                     (int)(mAlpha * 255), flags);
         }
     }
-    if (mClipToBounds && !mCaching) {
+    if (clipToBoundsNeeded) {
         ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
                 (float) mRight - mLeft, (float) mBottom - mTop);
     }
@@ -402,6 +421,7 @@
             renderer.concatMatrix(mTransformMatrix);
         }
     }
+    bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
     if (mAlpha < 1) {
         if (mCaching) {
             renderer.setOverrideLayerAlpha(mAlpha);
@@ -412,15 +432,16 @@
             // have to pass it into this call. In fact, this information might be in the
             // location/size info that we store with the new native transform data.
             int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (mClipToBounds) {
+            if (clipToBoundsNeeded) {
                 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
+                clipToBoundsNeeded = false; // clipping done by saveLayer
             }
             handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
                     mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
                     mClipToBounds);
         }
     }
-    if (mClipToBounds && !mCaching) {
+    if (clipToBoundsNeeded) {
         handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
                 PROPERTY_SAVECOUNT, mClipToBounds);
     }
@@ -480,7 +501,11 @@
  */
 template <class T>
 void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
-    if (mSize == 0 || mAlpha <= 0 || CC_UNLIKELY(!mSaveOp)) { // TODO: shouldn't need mSaveOp check
+    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
+        ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize);
+        CRASH();
+    }
+    if (mSize == 0 || mAlpha <= 0) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
         return;
     }
@@ -514,6 +539,10 @@
     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, saveCount, mClipToBounds);
     }
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5f84329..1cd5f1c 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -26,13 +26,15 @@
 
 #include <private/hwui/DrawGlInfo.h>
 
+#include <utils/LinearAllocator.h>
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
+
 #include <cutils/compiler.h>
 
-#include "utils/LinearAllocator.h"
+#include <androidfw/ResourceTypes.h>
 
 #include "Debug.h"
 
@@ -111,7 +113,6 @@
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-
     void defer(DeferStateStruct& deferStruct, const int level);
     void replay(ReplayStateStruct& replayStruct, const int level);
 
@@ -129,7 +130,12 @@
 
     void setName(const char* name) {
         if (name) {
-            mName.setTo(name);
+            char* lastPeriod = strrchr(name, '.');
+            if (lastPeriod) {
+                mName.setTo(lastPeriod + 1);
+            } else {
+                mName.setTo(name);
+            }
         }
     }
 
@@ -479,6 +485,7 @@
     Vector<SkBitmap*> mBitmapResources;
     Vector<SkBitmap*> mOwnedBitmapResources;
     Vector<SkiaColorFilter*> mFilterResources;
+    Vector<Res_png_9patch*> mPatchResources;
 
     Vector<SkPaint*> mPaints;
     Vector<SkPath*> mPaths;
@@ -496,6 +503,7 @@
     uint32_t mFunctorCount;
 
     String8 mName;
+    bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
 
     // View properties
     bool mClipToBounds;
@@ -525,11 +533,11 @@
      * an alpha causes a SaveLayerAlpha to occur). These operations point into mDisplayListData's
      * allocation, or null if uninitialized.
      *
-     * These are initialized (via friend constructors) when a displayList is issued in either replay
-     * or deferred mode. If replaying, the ops are not used until the next frame. If deferring, the
-     * ops may be stored in the DeferredDisplayList to be played back a second time.
+     * These are initialized (via friend re-constructors) when a displayList is issued in either
+     * replay or deferred mode. If replaying, the ops are not used until the next frame. If
+     * deferring, the ops may be stored in the DeferredDisplayList to be played back a second time.
      *
-     * They should be used at most once per frame (one call to iterate)
+     * They should be used at most once per frame (one call to 'iterate') to avoid overwriting data
      */
     ClipRectOp* mClipRectOp;
     SaveLayerOp* mSaveLayerOp;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index a0290e3..326805a 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -26,26 +26,19 @@
 #include <private/hwui/DrawGlInfo.h>
 
 #include "OpenGLRenderer.h"
+#include "AssetAtlas.h"
 #include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
+#include "UvMapper.h"
 #include "utils/LinearAllocator.h"
 
 #define CRASH() do { \
-    *(int *)(uintptr_t)0xbbadbeef = 0; \
+    *(int *)(uintptr_t) 0xbbadbeef = 0; \
     ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
 } while(false)
 
-#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
-#define MATRIX_ARGS(m) \
-    m->get(0), m->get(1), m->get(2), \
-    m->get(3), m->get(4), m->get(5), \
-    m->get(6), m->get(7), m->get(8)
-#define RECT_STRING "%.2f %.2f %.2f %.2f"
-#define RECT_ARGS(r) \
-    r.left, r.top, r.right, r.bottom
-
 // Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
-#define OP_LOGS(s) OP_LOG("%s", s)
+#define OP_LOGS(s) OP_LOG("%s", (s))
 #define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
 
 namespace android {
@@ -84,20 +77,11 @@
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
             bool useQuickReject) = 0;
 
-    virtual void output(int level, uint32_t logFlags = 0) = 0;
+    virtual void output(int level, uint32_t logFlags = 0) const = 0;
 
     // NOTE: it would be nice to declare constants and overriding the implementation in each op to
     // point at the constants, but that seems to require a .cpp file
     virtual const char* name() = 0;
-
-    /**
-     * Stores the relevant canvas state of the object between deferral and replay (if the canvas
-     * state supports being stored) See OpenGLRenderer::simpleClipAndState()
-     *
-     * TODO: don't reserve space for StateOps that won't be deferred
-     */
-    DeferredDisplayState state;
-
 };
 
 class StateOp : public DisplayListOp {
@@ -136,11 +120,6 @@
             return;
         }
 
-        if (!getLocalBounds(state.mBounds)) {
-            // empty bounds signify bounds can't be calculated
-            state.mBounds.setEmpty();
-        }
-
         deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
     }
 
@@ -163,16 +142,16 @@
      * reducing which operations are tagged as mergeable.
      */
     virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
-            const Vector<DrawOp*>& ops, const Rect& bounds) {
+            const Vector<OpStatePair>& ops, const Rect& bounds) {
         status_t status = DrawGlInfo::kStatusDone;
         for (unsigned int i = 0; i < ops.size(); i++) {
-            renderer.restoreDisplayState(ops[i]->state);
-            status |= ops[i]->applyDraw(renderer, dirty);
+            renderer.restoreDisplayState(*(ops[i].state), true);
+            status |= ops[i].op->applyDraw(renderer, dirty);
         }
         return status;
     }
 
-    /*
+    /**
      * When this method is invoked the state field is initialized to have the
      * final rendering state. We can thus use it to process data as it will be
      * used at draw time.
@@ -180,21 +159,25 @@
      * Additionally, this method allows subclasses to provide defer-time preferences for batching
      * and merging.
      *
-     * Return true if the op can merge with others of its kind (such subclasses should implement
-     * multiDraw)
+     * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw()
      */
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {}
+
+    /**
+     * Query the conservative, local bounds (unmapped) bounds of the op.
+     *
+     * returns true if bounds exist
+     */
+    virtual bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
         return false;
     }
 
-    // returns true if bounds exist
-    virtual bool getLocalBounds(Rect& localBounds) { return false; }
-
     // TODO: better refine localbounds usage
     void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
     bool getQuickRejected() { return mQuickRejected; }
 
-    inline int getPaintAlpha() {
+    inline int getPaintAlpha() const {
         return OpenGLRenderer::getAlphaDirect(mPaint);
     }
 
@@ -209,6 +192,23 @@
         return renderer.filterPaint(mPaint);
     }
 
+    // Helper method for determining op opaqueness. Assumes op fills its bounds in local
+    // coordinates, and that paint's alpha is used
+    inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
+        // ensure that local bounds cover mapped bounds
+        if (!state.mMatrix.isSimple()) return false;
+
+        // check state/paint for transparency
+        if (state.mDrawModifiers.mShader ||
+                state.mAlpha != 1.0f ||
+                (mPaint && mPaint->getAlpha() != 0xFF)) return false;
+
+        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
+        return (mode == SkXfermode::kSrcOver_Mode ||
+                mode == SkXfermode::kSrc_Mode);
+
+    }
+
     SkPaint* mPaint; // should be accessed via getPaint() when applying
     bool mQuickRejected;
 };
@@ -218,6 +218,9 @@
     DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
             : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
 
+    DrawBoundedOp(const Rect& localBounds, SkPaint* paint)
+            : DrawOp(paint), mLocalBounds(localBounds) {}
+
     // Calculates bounds as smallest rect encompassing all points
     // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
     // subclass' constructor)
@@ -232,24 +235,20 @@
     }
 
     // default empty constructor for bounds, to be overridden in child constructor body
-    DrawBoundedOp(SkPaint* paint)
-            : DrawOp(paint) {}
+    DrawBoundedOp(SkPaint* paint): DrawOp(paint) { }
 
-    bool getLocalBounds(Rect& localBounds) {
+    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
         localBounds.set(mLocalBounds);
+        if (drawModifiers.mHasShadow) {
+            // TODO: inspect paint's looper directly
+            Rect shadow(mLocalBounds);
+            shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
+            shadow.outset(drawModifiers.mShadowRadius);
+            localBounds.unionWith(shadow);
+        }
         return true;
     }
 
-    bool mergeAllowed() {
-        if (!state.mMatrix.isPureTranslate()) return false;
-
-        // checks that we're unclipped, and srcover
-        const Rect& opBounds = state.mBounds;
-        return fabs(opBounds.getWidth() - mLocalBounds.getWidth()) < 0.1 &&
-                fabs(opBounds.getHeight() - mLocalBounds.getHeight()) < 0.1 &&
-                (OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode);
-    }
-
 protected:
     Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
 };
@@ -275,7 +274,7 @@
         renderer.save(mFlags);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Save flags %x", mFlags);
     }
 
@@ -309,7 +308,7 @@
         renderer.restoreToCount(saveCount + mCount);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Restore to count %d", mCount);
     }
 
@@ -348,7 +347,7 @@
         renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("SaveLayer%s of area " RECT_STRING,
                 (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
     }
@@ -369,7 +368,7 @@
         return this;
     }
 
-    bool isSaveLayerAlpha() { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
+    bool isSaveLayerAlpha() const { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
     Rect mArea;
     int mAlpha;
     SkXfermode::Mode mMode;
@@ -385,7 +384,7 @@
         renderer.translate(mDx, mDy);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Translate by %f %f", mDx, mDy);
     }
 
@@ -405,7 +404,7 @@
         renderer.rotate(mDegrees);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Rotate by %f degrees", mDegrees);
     }
 
@@ -424,7 +423,7 @@
         renderer.scale(mSx, mSy);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Scale by %f %f", mSx, mSy);
     }
 
@@ -444,7 +443,7 @@
         renderer.skew(mSx, mSy);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Skew by %f %f", mSx, mSy);
     }
 
@@ -464,8 +463,12 @@
         renderer.setMatrix(mMatrix);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
-        OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+    virtual void output(int level, uint32_t logFlags) const {
+        if (mMatrix) {
+            OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+        } else {
+            OP_LOGS("SetMatrix (reset)");
+        }
     }
 
     virtual const char* name() { return "SetMatrix"; }
@@ -483,7 +486,7 @@
         renderer.concatMatrix(mMatrix);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
     }
 
@@ -527,7 +530,7 @@
         renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
     }
 
@@ -556,7 +559,7 @@
         renderer.clipPath(mPath, mOp);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         SkRect bounds = mPath->getBounds();
         OP_LOG("ClipPath bounds " RECT_STRING,
                 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
@@ -577,7 +580,7 @@
         renderer.clipRegion(mRegion, mOp);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         SkIRect bounds = mRegion->getBounds();
         OP_LOG("ClipRegion bounds %d %d %d %d",
                 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
@@ -587,7 +590,6 @@
 
 private:
     SkRegion* mRegion;
-    SkRegion::Op mOp;
 };
 
 class ResetShaderOp : public StateOp {
@@ -596,7 +598,7 @@
         renderer.resetShader();
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOGS("ResetShader");
     }
 
@@ -611,7 +613,7 @@
         renderer.setupShader(mShader);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("SetupShader, shader %p", mShader);
     }
 
@@ -627,7 +629,7 @@
         renderer.resetColorFilter();
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOGS("ResetColorFilter");
     }
 
@@ -643,7 +645,7 @@
         renderer.setupColorFilter(mColorFilter);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("SetupColorFilter, filter %p", mColorFilter);
     }
 
@@ -659,7 +661,7 @@
         renderer.resetShadow();
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOGS("ResetShadow");
     }
 
@@ -675,7 +677,7 @@
         renderer.setupShadow(mRadius, mDx, mDy, mColor);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
     }
 
@@ -694,7 +696,7 @@
         renderer.resetPaintFilter();
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOGS("ResetPaintFilter");
     }
 
@@ -710,7 +712,7 @@
         renderer.setupPaintFilter(mClearBits, mSetBits);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
     }
 
@@ -721,7 +723,6 @@
     int mSetBits;
 };
 
-
 ///////////////////////////////////////////////////////////////////////////////
 // DRAW OPERATIONS - these are operations that can draw to the canvas's device
 ///////////////////////////////////////////////////////////////////////////////
@@ -729,34 +730,63 @@
 class DrawBitmapOp : public DrawBoundedOp {
 public:
     DrawBitmapOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
-            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(),
-                    paint),
-            mBitmap(bitmap) {}
+            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(), paint),
+            mBitmap(bitmap), mAtlas(Caches::getInstance().assetAtlas) {
+        mEntry = mAtlas.getEntry(bitmap);
+        if (mEntry) {
+            mEntryGenerationId = mAtlas.getGenerationId();
+            mUvMapper = mEntry->uvMapper;
+        }
+    }
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
                 getPaint(renderer));
     }
 
+    AssetAtlas::Entry* getAtlasEntry() {
+        // The atlas entry is stale, let's get a new one
+        if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) {
+            mEntryGenerationId = mAtlas.getGenerationId();
+            mEntry = mAtlas.getEntry(mBitmap);
+            mUvMapper = mEntry->uvMapper;
+        }
+        return mEntry;
+    }
+
 #define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
     TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
             texCoordsRect.xDim, texCoordsRect.yDim)
 
+    /**
+     * This multi-draw operation builds a mesh on the stack by generating a quad
+     * for each bitmap in the batch. This method is also responsible for dirtying
+     * the current layer, if any.
+     */
     virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
-            const Vector<DrawOp*>& ops, const Rect& bounds) {
-        renderer.restoreDisplayState(state, true); // restore all but the clip
-        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
+            const Vector<OpStatePair>& ops, const Rect& bounds) {
+        const DeferredDisplayState& firstState = *(ops[0].state);
+        renderer.restoreDisplayState(firstState, true); // restore all but the clip
+
         TextureVertex vertices[6 * ops.size()];
         TextureVertex* vertex = &vertices[0];
 
-        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op, and allowing
-        // them to be merged in getBatchId()
-        const Rect texCoords(0, 0, 1, 1);
+        const bool hasLayer = renderer.hasLayer();
+        bool pureTranslate = true;
 
-        const float width = mBitmap->width();
-        const float height = mBitmap->height();
+        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
+        // and allowing them to be merged in getBatchId()
         for (unsigned int i = 0; i < ops.size(); i++) {
-            const Rect& opBounds = ops[i]->state.mBounds;
+            const DeferredDisplayState& state = *(ops[i].state);
+            const Rect& opBounds = state.mBounds;
+            // When we reach multiDraw(), the matrix can be either
+            // pureTranslate or simple (translate and/or scale).
+            // If the matrix is not pureTranslate, then we have a scale
+            pureTranslate &= state.mMatrix.isPureTranslate();
+
+            Rect texCoords(0, 0, 1, 1);
+            ((DrawBitmapOp*) ops[i].op)->mUvMapper.map(texCoords);
+
             SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
             SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
             SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
@@ -764,29 +794,45 @@
             SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
             SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
             SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
+
+            if (hasLayer) {
+                renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
+            }
         }
 
-        return renderer.drawBitmaps(mBitmap, ops.size(), &vertices[0], bounds, mPaint);
+        return renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
+                pureTranslate, bounds, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
     }
 
     virtual const char* name() { return "DrawBitmap"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        *mergeId = (mergeid_t)mBitmap;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
+        deferInfo.mergeId = getAtlasEntry() ?
+                (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
 
-        // don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
-        // MergingDrawBatch::canMergeWith
-        return mergeAllowed() && (mBitmap->getConfig() != SkBitmap::kA8_Config);
+        // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
+        // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
+        // MergingDrawBatch::canMergeWith()
+        // TODO: support clipped bitmaps by handling them in SET_TEXTURE
+        deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
+                !state.mClipSideFlags &&
+                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
+                (mBitmap->getConfig() != SkBitmap::kA8_Config);
     }
 
     const SkBitmap* bitmap() { return mBitmap; }
 protected:
     SkBitmap* mBitmap;
+    const AssetAtlas& mAtlas;
+    uint32_t mEntryGenerationId;
+    AssetAtlas::Entry* mEntry;
+    UvMapper mUvMapper;
 };
 
 class DrawBitmapMatrixOp : public DrawBoundedOp {
@@ -802,15 +848,15 @@
         return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
     }
 
     virtual const char* name() { return "DrawBitmapMatrix"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        return false;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
     }
 
 private:
@@ -831,16 +877,16 @@
                 getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
                 mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
     }
 
     virtual const char* name() { return "DrawBitmapRect"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        return false;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
     }
 
 private:
@@ -858,15 +904,15 @@
                 mLocalBounds.top, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw bitmap %p", mBitmap);
     }
 
     virtual const char* name() { return "DrawBitmapData"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        return false;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
     }
 };
 
@@ -883,15 +929,15 @@
                 mVertices, mColors, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
     }
 
     virtual const char* name() { return "DrawBitmapMesh"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        return false;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
     }
 
 private:
@@ -904,45 +950,148 @@
 
 class DrawPatchOp : public DrawBoundedOp {
 public:
-    DrawPatchOp(SkBitmap* bitmap, const int32_t* xDivs,
-            const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height,
-            int8_t numColors, float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode)
-            : DrawBoundedOp(left, top, right, bottom, 0),
-            mBitmap(bitmap), mxDivs(xDivs), myDivs(yDivs),
-            mColors(colors), mxDivsCount(width), myDivsCount(height),
-            mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
+    DrawPatchOp(SkBitmap* bitmap, Res_png_9patch* patch,
+            float left, float top, float right, float bottom, SkPaint* paint)
+            : DrawBoundedOp(left, top, right, bottom, paint),
+            mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(NULL),
+            mAtlas(Caches::getInstance().assetAtlas) {
+        mEntry = mAtlas.getEntry(bitmap);
+        if (mEntry) {
+            mEntryGenerationId = mAtlas.getGenerationId();
+        }
+    };
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        // NOTE: not calling the virtual method, which takes a paint
-        return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
-                mxDivsCount, myDivsCount, mNumColors,
-                mLocalBounds.left, mLocalBounds.top,
-                mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
+    AssetAtlas::Entry* getAtlasEntry() {
+        // The atlas entry is stale, let's get a new one
+        if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) {
+            mEntryGenerationId = mAtlas.getGenerationId();
+            mEntry = mAtlas.getEntry(mBitmap);
+        }
+        return mEntry;
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    const Patch* getMesh(OpenGLRenderer& renderer) {
+        if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) {
+            PatchCache& cache = renderer.getCaches().patchCache;
+            mMesh = cache.get(getAtlasEntry(), mBitmap->width(), mBitmap->height(),
+                    mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch);
+            mGenerationId = cache.getGenerationId();
+        }
+        return mMesh;
+    }
+
+    /**
+     * This multi-draw operation builds an indexed mesh on the stack by copying
+     * and transforming the vertices of each 9-patch in the batch. This method
+     * is also responsible for dirtying the current layer, if any.
+     */
+    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<OpStatePair>& ops, const Rect& bounds) {
+        const DeferredDisplayState& firstState = *(ops[0].state);
+        renderer.restoreDisplayState(firstState, true); // restore all but the clip
+
+        // Batches will usually contain a small number of items so it's
+        // worth performing a first iteration to count the exact number
+        // of vertices we need in the new mesh
+        uint32_t totalVertices = 0;
+        for (unsigned int i = 0; i < ops.size(); i++) {
+            totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
+        }
+
+        const bool hasLayer = renderer.hasLayer();
+
+        uint32_t indexCount = 0;
+
+        TextureVertex vertices[totalVertices];
+        TextureVertex* vertex = &vertices[0];
+
+        // Create a mesh that contains the transformed vertices for all the
+        // 9-patch objects that are part of the batch. Note that onDefer()
+        // enforces ops drawn by this function to have a pure translate or
+        // identity matrix
+        for (unsigned int i = 0; i < ops.size(); i++) {
+            DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
+            const DeferredDisplayState* state = ops[i].state;
+            const Patch* opMesh = patchOp->getMesh(renderer);
+            uint32_t vertexCount = opMesh->verticesCount;
+            if (vertexCount == 0) continue;
+
+            // We use the bounds to know where to translate our vertices
+            // Using patchOp->state.mBounds wouldn't work because these
+            // bounds are clipped
+            const float tx = (int) floorf(state->mMatrix.getTranslateX() +
+                    patchOp->mLocalBounds.left + 0.5f);
+            const float ty = (int) floorf(state->mMatrix.getTranslateY() +
+                    patchOp->mLocalBounds.top + 0.5f);
+
+            // Copy & transform all the vertices for the current operation
+            TextureVertex* opVertices = opMesh->vertices;
+            for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
+                TextureVertex::set(vertex++,
+                        opVertices->position[0] + tx, opVertices->position[1] + ty,
+                        opVertices->texture[0], opVertices->texture[1]);
+            }
+
+            // Dirty the current layer if possible. When the 9-patch does not
+            // contain empty quads we can take a shortcut and simply set the
+            // dirty rect to the object's bounds.
+            if (hasLayer) {
+                if (!opMesh->hasEmptyQuads) {
+                    renderer.dirtyLayer(tx, ty,
+                            tx + patchOp->mLocalBounds.getWidth(),
+                            ty + patchOp->mLocalBounds.getHeight());
+                } else {
+                    const size_t count = opMesh->quads.size();
+                    for (size_t i = 0; i < count; i++) {
+                        const Rect& quadBounds = opMesh->quads[i];
+                        const float x = tx + quadBounds.left;
+                        const float y = ty + quadBounds.top;
+                        renderer.dirtyLayer(x, y,
+                                x + quadBounds.getWidth(), y + quadBounds.getHeight());
+                    }
+                }
+            }
+
+            indexCount += opMesh->indexCount;
+        }
+
+        return renderer.drawPatches(mBitmap, getAtlasEntry(),
+                &vertices[0], indexCount, getPaint(renderer));
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+        // We're not calling the public variant of drawPatch() here
+        // This method won't perform the quickReject() since we've already done it at this point
+        return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(),
+                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
+                getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
     virtual const char* name() { return "DrawPatch"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Patch;
-        *mergeId = (mergeid_t)mBitmap;
-        return true;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
+        deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
+        deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
+                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
+        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
     }
 
 private:
     SkBitmap* mBitmap;
-    const int32_t* mxDivs;
-    const int32_t* myDivs;
-    const uint32_t* mColors;
-    uint32_t mxDivsCount;
-    uint32_t myDivsCount;
-    int8_t mNumColors;
-    int mAlpha;
-    SkXfermode::Mode mMode;
+    Res_png_9patch* mPatch;
+
+    uint32_t mGenerationId;
+    const Patch* mMesh;
+
+    const AssetAtlas& mAtlas;
+    uint32_t mEntryGenerationId;
+    AssetAtlas::Entry* mEntry;
 };
 
 class DrawColorOp : public DrawOp {
@@ -954,7 +1103,7 @@
         return renderer.drawColor(mColor, mMode);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw color %#x, mode %d", mColor, mMode);
     }
 
@@ -970,7 +1119,7 @@
     DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
             : DrawBoundedOp(left, top, right, bottom, paint) {};
 
-    bool getLocalBounds(Rect& localBounds) {
+    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
         localBounds.set(mLocalBounds);
         if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
             localBounds.outset(strokeWidthOutset());
@@ -978,15 +1127,15 @@
         return true;
     }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
         if (mPaint->getPathEffect()) {
-            *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+            deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
         } else {
-            *batchId = mPaint->isAntiAlias() ?
+            deferInfo.batchId = mPaint->isAntiAlias() ?
                     DeferredDisplayList::kOpBatch_AlphaVertices :
                     DeferredDisplayList::kOpBatch_Vertices;
         }
-        return false;
     }
 };
 
@@ -1000,10 +1149,17 @@
                 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        DrawStrokableOp::onDefer(renderer, deferInfo, state);
+        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
+                mPaint->getStyle() == SkPaint::kFill_Style;
+    }
+
     virtual const char* name() { return "DrawRect"; }
 };
 
@@ -1017,15 +1173,15 @@
         return renderer.drawRects(mRects, mCount, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Rects count %d", mCount);
     }
 
     virtual const char* name() { return "DrawRects"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = DeferredDisplayList::kOpBatch_Vertices;
-        return false;
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
     }
 
 private:
@@ -1044,7 +1200,7 @@
                 mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
     }
 
@@ -1065,7 +1221,7 @@
         return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
     }
 
@@ -1087,7 +1243,7 @@
                 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
@@ -1107,7 +1263,7 @@
                 mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
                 RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
     }
@@ -1136,15 +1292,15 @@
         return renderer.drawPath(mPath, getPaint(renderer));
     }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
         SkPaint* paint = getPaint(renderer);
         renderer.getCaches().pathCache.precache(mPath, paint);
 
-        *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
-        return false;
+        deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
     }
 
@@ -1166,17 +1322,17 @@
         return renderer.drawLines(mPoints, mCount, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Lines count %d", mCount);
     }
 
     virtual const char* name() { return "DrawLines"; }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
-        *batchId = mPaint->isAntiAlias() ?
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
+        deferInfo.batchId = mPaint->isAntiAlias() ?
                 DeferredDisplayList::kOpBatch_AlphaVertices :
                 DeferredDisplayList::kOpBatch_Vertices;
-        return false;
     }
 
 protected:
@@ -1193,7 +1349,7 @@
         return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Points count %d", mCount);
     }
 
@@ -1205,20 +1361,19 @@
     DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
             : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
         SkPaint* paint = getPaint(renderer);
         FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
         fontRenderer.precache(paint, mText, mCount, mat4::identity());
 
-        *batchId = mPaint->getColor() == 0xff000000 ?
+        deferInfo.batchId = mPaint->getColor() == 0xff000000 ?
                 DeferredDisplayList::kOpBatch_Text :
                 DeferredDisplayList::kOpBatch_ColorText;
-
-        return false;
     }
 
 protected:
@@ -1270,27 +1425,14 @@
 class DrawTextOp : public DrawBoundedOp {
 public:
     DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, SkPaint* paint, float length)
-            : DrawBoundedOp(paint), mText(text), mBytesCount(bytesCount), mCount(count),
-            mX(x), mY(y), mPositions(positions), mLength(length) {
-        // duplicates bounds calculation from OpenGLRenderer::drawText, but doesn't alter mX
-        SkPaint::FontMetrics metrics;
-        paint->getFontMetrics(&metrics, 0.0f);
-        switch (paint->getTextAlign()) {
-        case SkPaint::kCenter_Align:
-            x -= length / 2.0f;
-            break;
-        case SkPaint::kRight_Align:
-            x -= length;
-            break;
-        default:
-            break;
-        }
-        mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
+            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds)
+            : DrawBoundedOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
+            mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
         memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
     }
 
-    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+            const DeferredDisplayState& state) {
         SkPaint* paint = getPaint(renderer);
         FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
         const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
@@ -1298,39 +1440,45 @@
             fontRenderer.precache(paint, mText, mCount, transform);
             mPrecacheTransform = transform;
         }
-        *batchId = mPaint->getColor() == 0xff000000 ?
+        deferInfo.batchId = mPaint->getColor() == 0xff000000 ?
                 DeferredDisplayList::kOpBatch_Text :
                 DeferredDisplayList::kOpBatch_ColorText;
 
-        *mergeId = (mergeid_t)mPaint->getColor();
+        deferInfo.mergeId = (mergeid_t)mPaint->getColor();
 
         // don't merge decorated text - the decorations won't draw in order
         bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
                         SkPaint::kStrikeThruText_Flag));
-        return mergeAllowed() && noDecorations;
+        deferInfo.mergeable = state.mMatrix.isPureTranslate() && noDecorations &&
+                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
     }
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+        Rect bounds;
+        getLocalBounds(renderer.getDrawModifiers(), bounds);
         return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
-                mPositions, getPaint(renderer), mLength);
+                mPositions, getPaint(renderer), mTotalAdvance, bounds);
     }
 
     virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
-            const Vector<DrawOp*>& ops, const Rect& bounds) {
+            const Vector<OpStatePair>& ops, const Rect& bounds) {
         status_t status = DrawGlInfo::kStatusDone;
-        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
         for (unsigned int i = 0; i < ops.size(); i++) {
+            const DeferredDisplayState& state = *(ops[i].state);
             DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
-            renderer.restoreDisplayState(ops[i]->state, true); // restore all but the clip
+            renderer.restoreDisplayState(state, true); // restore all but the clip
 
-            DrawTextOp& op = *((DrawTextOp*)ops[i]);
+            DrawTextOp& op = *((DrawTextOp*)ops[i].op);
+            // quickReject() will not occure in drawText() so we can use mLocalBounds
+            // directly, we do not need to account for shadow by calling getLocalBounds()
             status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
-                    op.mPositions, op.getPaint(renderer), op.mLength, drawOpMode);
+                    op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
+                    drawOpMode);
         }
         return status;
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
     }
 
@@ -1343,7 +1491,7 @@
     float mX;
     float mY;
     const float* mPositions;
-    float mLength;
+    float mTotalAdvance;
     mat4 mPrecacheTransform;
 };
 
@@ -1363,7 +1511,7 @@
         return ret;
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Functor %p", mFunctor);
     }
 
@@ -1397,7 +1545,7 @@
         return DrawGlInfo::kStatusDone;
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
         if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
             mDisplayList->output(level + 1);
@@ -1420,7 +1568,7 @@
         return renderer.drawLayer(mLayer, mX, mY);
     }
 
-    virtual void output(int level, uint32_t logFlags) {
+    virtual void output(int level, uint32_t logFlags) const {
         OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
     }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 876c38a..8866029 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,6 +57,10 @@
         mCaches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
     }
 
+    for (size_t i = 0; i < mPatchResources.size(); i++) {
+        mCaches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
+    }
+
     for (size_t i = 0; i < mShaders.size(); i++) {
         mCaches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
     }
@@ -74,6 +78,7 @@
     mBitmapResources.clear();
     mOwnedBitmapResources.clear();
     mFilterResources.clear();
+    mPatchResources.clear();
     mSourcePaths.clear();
 
     mShaders.clear();
@@ -313,20 +318,13 @@
     return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs,
-        const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height,
-        int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint) {
-    int alpha;
-    SkXfermode::Mode mode;
-    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
-
+status_t DisplayListRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
+        float left, float top, float right, float bottom, SkPaint* paint) {
     bitmap = refBitmap(bitmap);
-    xDivs = refBuffer<int>(xDivs, width);
-    yDivs = refBuffer<int>(yDivs, height);
-    colors = refBuffer<uint32_t>(colors, numColors);
+    patch = refPatch(patch);
+    paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawPatchOp(bitmap, xDivs, yDivs, colors, width, height, numColors,
-                    left, top, right, bottom, alpha, mode));
+    addDrawOp(new (alloc()) DrawPatchOp(bitmap, patch, left, top, right, bottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
@@ -423,17 +421,16 @@
 
 status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
         float x, float y, const float* positions, SkPaint* paint,
-        float length, DrawOpMode drawOpMode) {
+        float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) {
 
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
 
-    if (length < 0.0f) length = paint->measureText(text, bytesCount);
-
     text = refText(text, bytesCount);
     positions = refBuffer<float>(positions, count * 2);
     paint = refPaint(paint);
 
-    DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count, x, y, positions, paint, length);
+    DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count,
+            x, y, positions, paint, totalAdvance, bounds);
     addDrawOp(op);
     return DrawGlInfo::kStatusDone;
 }
@@ -467,10 +464,12 @@
 
 void DisplayListRenderer::resetShadow() {
     addStateOp(new (alloc()) ResetShadowOp());
+    OpenGLRenderer::resetShadow();
 }
 
 void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
     addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color));
+    OpenGLRenderer::setupShadow(radius, dx, dy, color);
 }
 
 void DisplayListRenderer::resetPaintFilter() {
@@ -506,11 +505,12 @@
 
 void DisplayListRenderer::addDrawOp(DrawOp* op) {
     Rect localBounds;
-    if (op->getLocalBounds(localBounds)) {
+    if (op->getLocalBounds(mDrawModifiers, localBounds)) {
         bool rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
                 localBounds.right, localBounds.bottom);
         op->setQuickRejected(rejected);
     }
+
     mHasDrawOps = true;
     addOpInternal(op);
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 75abad6..d233150 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -103,8 +103,7 @@
     virtual status_t drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual status_t drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
             float* vertices, int* colors, SkPaint* paint);
-    virtual status_t drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+    virtual status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
             float left, float top, float right, float bottom, SkPaint* paint);
     virtual status_t drawColor(int color, SkXfermode::Mode mode);
     virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint);
@@ -122,7 +121,8 @@
     virtual status_t drawPosText(const char* text, int bytesCount, int count,
             const float* positions, SkPaint* paint);
     virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, SkPaint* paint, float length, DrawOpMode drawOpMode);
+            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds,
+            DrawOpMode drawOpMode);
 
     virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
 
@@ -156,6 +156,10 @@
         return mFilterResources;
     }
 
+    const Vector<Res_png_9patch*>& getPatchResources() const {
+        return mPatchResources;
+    }
+
     const Vector<SkiaShader*>& getShaders() const {
         return mShaders;
     }
@@ -265,11 +269,14 @@
     }
 
     inline SkMatrix* refMatrix(SkMatrix* matrix) {
-        // Copying the matrix is cheap and prevents against the user changing the original
-        // matrix before the operation that uses it
-        SkMatrix* copy = new SkMatrix(*matrix);
-        mMatrices.add(copy);
-        return copy;
+        if (matrix) {
+            // Copying the matrix is cheap and prevents against the user changing
+            // the original matrix before the operation that uses it
+            SkMatrix* copy = new SkMatrix(*matrix);
+            mMatrices.add(copy);
+            return copy;
+        }
+        return matrix;
     }
 
     inline Layer* refLayer(Layer* layer) {
@@ -315,9 +322,16 @@
         return colorFilter;
     }
 
+    inline Res_png_9patch* refPatch(Res_png_9patch* patch) {
+        mPatchResources.add(patch);
+        mCaches.resourceCache.incrementRefcount(patch);
+        return patch;
+    }
+
     Vector<SkBitmap*> mBitmapResources;
     Vector<SkBitmap*> mOwnedBitmapResources;
     Vector<SkiaColorFilter*> mFilterResources;
+    Vector<Res_png_9patch*> mPatchResources;
 
     Vector<SkPaint*> mPaints;
     DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap;
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 19b3849..77006a4 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -24,12 +24,15 @@
 // Lifecycle
 ///////////////////////////////////////////////////////////////////////////////
 
+Dither::Dither(): mCaches(NULL), mInitialized(false), mDitherTexture(0) {
+}
+
 void Dither::bindDitherTexture() {
     if (!mInitialized) {
-        bool useFloatTexture = Extensions::getInstance().getMajorGlVersion() >= 3;
+        bool useFloatTexture = Extensions::getInstance().hasFloatTextures();
 
         glGenTextures(1, &mDitherTexture);
-        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
+        mCaches->bindTexture(mDitherTexture);
 
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -68,13 +71,13 @@
 
         mInitialized = true;
     } else {
-        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
+        mCaches->bindTexture(mDitherTexture);
     }
 }
 
 void Dither::clear() {
     if (mInitialized) {
-        glDeleteTextures(1, &mDitherTexture);
+        mCaches->deleteTexture(mDitherTexture);
         mInitialized = false;
     }
 }
@@ -84,8 +87,10 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void Dither::setupProgram(Program* program, GLuint* textureUnit) {
+    if (!mCaches) mCaches = &Caches::getInstance();
+
     GLuint textureSlot = (*textureUnit)++;
-    Caches::getInstance().activeTexture(textureSlot);
+    mCaches->activeTexture(textureSlot);
 
     bindDitherTexture();
 
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
index 4d1f921..546236be 100644
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -24,9 +24,7 @@
 namespace android {
 namespace uirenderer {
 
-///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
+class Caches;
 
 // Must be a power of two
 #define DITHER_KERNEL_SIZE 4
@@ -39,7 +37,7 @@
  */
 class Dither {
 public:
-    Dither(): mInitialized(false), mDitherTexture(0) { }
+    Dither();
 
     void clear();
     void setupProgram(Program* program, GLuint* textureUnit);
@@ -47,6 +45,7 @@
 private:
     void bindDitherTexture();
 
+    Caches* mCaches;
     bool mInitialized;
     GLuint mDitherTexture;
 };
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 51aec8d..84e7e65 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -14,8 +14,19 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "OpenGLRenderer"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/Log.h>
+
 #include "Debug.h"
 #include "Extensions.h"
+#include "Properties.h"
 
 namespace android {
 
@@ -40,33 +51,28 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Extensions::Extensions(): Singleton<Extensions>() {
-    const char* buffer = (const char*) glGetString(GL_EXTENSIONS);
-    const char* current = buffer;
-    const char* head = current;
-    EXT_LOGD("Available GL extensions:");
-    do {
-        head = strchr(current, ' ');
-        String8 s(current, head ? head - current : strlen(current));
-        if (s.length()) {
-            mExtensionList.add(s);
-            EXT_LOGD("  %s", s.string());
-        }
-        current = head + 1;
-    } while (head);
+    // Query GL extensions
+    findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList);
+    mHasNPot = hasGlExtension("GL_OES_texture_npot");
+    mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
+    mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
+    mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
+    mHasDebugLabel = hasGlExtension("GL_EXT_debug_label");
+    mHasTiledRendering = hasGlExtension("GL_QCOM_tiled_rendering");
+    mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
+    mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
 
-    mHasNPot = hasExtension("GL_OES_texture_npot");
-    mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
-    mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
-    mHasDebugMarker = hasExtension("GL_EXT_debug_marker");
-    mHasDebugLabel = hasExtension("GL_EXT_debug_label");
-    mHasTiledRendering = hasExtension("GL_QCOM_tiled_rendering");
-    mHas1BitStencil = hasExtension("GL_OES_stencil1");
-    mHas4BitStencil = hasExtension("GL_OES_stencil4");
+    // Query EGL extensions
+    findExtensions(eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS), mEglExtensionList);
 
-    mExtensions = strdup(buffer);
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_DEBUG_NV_PROFILING, property, NULL) > 0) {
+        mHasNvSystemTime = !strcmp(property, "true") && hasEglExtension("EGL_NV_system_time");
+    } else {
+        mHasNvSystemTime = false;
+    }
 
     const char* version = (const char*) glGetString(GL_VERSION);
-    mVersion = strdup(version);
 
     // Section 6.1.5 of the OpenGL ES specification indicates the GL version
     // string strictly follows this format:
@@ -80,7 +86,7 @@
     // or more digits. The release number and vendor specific information are
     // optional."
 
-    if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) !=2) {
+    if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) {
         // If we cannot parse the version number, assume OpenGL ES 2.0
         mVersionMajor = 2;
         mVersionMinor = 0;
@@ -88,22 +94,41 @@
 }
 
 Extensions::~Extensions() {
-   free(mExtensions);
-   free(mVersion);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Methods
 ///////////////////////////////////////////////////////////////////////////////
 
-bool Extensions::hasExtension(const char* extension) const {
+bool Extensions::hasGlExtension(const char* extension) const {
    const String8 s(extension);
-   return mExtensionList.indexOf(s) >= 0;
+   return mGlExtensionList.indexOf(s) >= 0;
+}
+
+bool Extensions::hasEglExtension(const char* extension) const {
+   const String8 s(extension);
+   return mEglExtensionList.indexOf(s) >= 0;
+}
+
+void Extensions::findExtensions(const char* extensions, SortedVector<String8>& list) const {
+    const char* current = extensions;
+    const char* head = current;
+    EXT_LOGD("Available extensions:");
+    do {
+        head = strchr(current, ' ');
+        String8 s(current, head ? head - current : strlen(current));
+        if (s.length()) {
+            list.add(s);
+            EXT_LOGD("  %s", s.string());
+        }
+        current = head + 1;
+    } while (head);
 }
 
 void Extensions::dump() const {
-   ALOGD("%s", mVersion);
-   ALOGD("Supported extensions:\n%s", mExtensions);
+   ALOGD("%s", (const char*) glGetString(GL_VERSION));
+   ALOGD("Supported GL extensions:\n%s", (const char*) glGetString(GL_EXTENSIONS));
+   ALOGD("Supported EGL extensions:\n%s", eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS));
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 54a3987..25d4c5e 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -17,13 +17,12 @@
 #ifndef ANDROID_HWUI_EXTENSIONS_H
 #define ANDROID_HWUI_EXTENSIONS_H
 
+#include <cutils/compiler.h>
+
 #include <utils/Singleton.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
 namespace android {
 namespace uirenderer {
 
@@ -31,11 +30,8 @@
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
-class Extensions: public Singleton<Extensions> {
+class ANDROID_API Extensions: public Singleton<Extensions> {
 public:
-    Extensions();
-    ~Extensions();
-
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
@@ -44,21 +40,30 @@
     inline bool hasTiledRendering() const { return mHasTiledRendering; }
     inline bool has1BitStencil() const { return mHas1BitStencil; }
     inline bool has4BitStencil() const { return mHas4BitStencil; }
+    inline bool hasNvSystemTime() const { return mHasNvSystemTime; }
+    inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; }
+    inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
+    inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
+    inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
 
     inline int getMajorGlVersion() const { return mVersionMajor; }
     inline int getMinorGlVersion() const { return mVersionMinor; }
 
-    bool hasExtension(const char* extension) const;
+    bool hasGlExtension(const char* extension) const;
+    bool hasEglExtension(const char* extension) const;
 
     void dump() const;
 
 private:
+    Extensions();
+    ~Extensions();
+
+    void findExtensions(const char* extensions, SortedVector<String8>& list) const;
+
     friend class Singleton<Extensions>;
 
-    SortedVector<String8> mExtensionList;
-
-    char* mExtensions;
-    char* mVersion;
+    SortedVector<String8> mGlExtensionList;
+    SortedVector<String8> mEglExtensionList;
 
     bool mHasNPot;
     bool mHasFramebufferFetch;
@@ -68,6 +73,7 @@
     bool mHasTiledRendering;
     bool mHas1BitStencil;
     bool mHas4BitStencil;
+    bool mHasNvSystemTime;
 
     int mVersionMajor;
     int mVersionMinor;
diff --git a/libs/hwui/Fence.h b/libs/hwui/Fence.h
new file mode 100644
index 0000000..f175e98
--- /dev/null
+++ b/libs/hwui/Fence.h
@@ -0,0 +1,113 @@
+/*
+ * 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_FENCE_H
+#define ANDROID_HWUI_FENCE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Creating a Fence instance inserts a new sync fence in the OpenGL
+ * commands stream. The caller can then wait for the fence to be signaled
+ * by calling the wait method.
+ */
+class Fence {
+public:
+    enum {
+        /**
+         * Default timeout in nano-seconds for wait()
+         */
+        kDefaultTimeout = 1000000000
+    };
+
+    /**
+     * Inserts a new sync fence in the OpenGL commands stream.
+     */
+    Fence() {
+        mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        if (mDisplay != EGL_NO_DISPLAY) {
+            mFence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
+        } else {
+            mFence = EGL_NO_SYNC_KHR;
+        }
+    }
+
+    /**
+     * Destroys the fence. Any caller waiting on the fence will be
+     * signaled immediately.
+     */
+    ~Fence() {
+        if (mFence != EGL_NO_SYNC_KHR) {
+            eglDestroySyncKHR(mDisplay, mFence);
+        }
+    }
+
+    /**
+     * Blocks the calling thread until this fence is signaled, or until
+     * <timeout> nanoseconds have passed.
+     *
+     * Returns true if waiting for the fence was successful, false if
+     * a timeout or an error occurred.
+     */
+    bool wait(EGLTimeKHR timeout = kDefaultTimeout) {
+        EGLint waitStatus = eglClientWaitSyncKHR(mDisplay, mFence,
+                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, timeout);
+        if (waitStatus == EGL_FALSE) {
+            ALOGW("Failed to wait for the fence %#x", eglGetError());
+        }
+        return waitStatus == EGL_CONDITION_SATISFIED_KHR;
+    }
+
+private:
+    EGLDisplay mDisplay;
+    EGLSyncKHR mFence;
+
+}; // class Fence
+
+/**
+ * An AutoFence creates a Fence instance and waits for the fence
+ * to be signaled when the AutoFence is destroyed. This is useful
+ * to automatically wait for a series of OpenGL commands to be
+ * executed. For example:
+ *
+ * void drawAndWait() {
+ *     glDrawElements();
+ *     AutoFence fence;
+ * }
+ */
+class AutoFence {
+public:
+    AutoFence(EGLTimeKHR timeout = Fence::kDefaultTimeout): mTimeout(timeout) {
+    }
+
+    ~AutoFence() {
+        mFence.wait(mTimeout);
+    }
+
+private:
+    EGLTimeKHR mTimeout;
+    Fence mFence;
+
+}; // class AutoFence
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_FENCE_H
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 543cfa2..00e7870 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -21,10 +21,11 @@
 
 #include <cutils/properties.h>
 
-#include <utils/Functor.h>
 #include <utils/Log.h>
 
+#ifdef ANDROID_ENABLE_RENDERSCRIPT
 #include <RenderScript.h>
+#endif
 
 #include "utils/Blur.h"
 #include "utils/Timing.h"
@@ -33,6 +34,7 @@
 #include "Debug.h"
 #include "Extensions.h"
 #include "FontRenderer.h"
+#include "OpenGLRenderer.h"
 #include "PixelBuffer.h"
 #include "Rect.h"
 
@@ -43,6 +45,52 @@
 #define RS_MIN_INPUT_CUTOFF 10000
 
 ///////////////////////////////////////////////////////////////////////////////
+// TextSetupFunctor
+///////////////////////////////////////////////////////////////////////////////
+status_t TextSetupFunctor::operator ()(int what, void* data) {
+    Data* typedData = reinterpret_cast<Data*>(data);
+    GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
+
+    renderer->setupDraw();
+    renderer->setupDrawTextGamma(paint);
+    renderer->setupDrawDirtyRegionsDisabled();
+    renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
+    switch (glyphFormat) {
+        case GL_ALPHA: {
+            renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
+            break;
+        }
+        case GL_RGBA: {
+            float floatAlpha = alpha / 255.0f;
+            renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
+            break;
+        }
+        default: {
+#if DEBUG_FONT_RENDERER
+            ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
+#endif
+            break;
+        }
+    }
+    renderer->setupDrawColorFilter();
+    renderer->setupDrawShader();
+    renderer->setupDrawBlending(true, mode);
+    renderer->setupDrawProgram();
+    renderer->setupDrawModelView(x, y, x, y, pureTranslate, true);
+    // Calling setupDrawTexture with the name 0 will enable the
+    // uv attributes and increase the texture unit count
+    // texture binding will be performed by the font renderer as
+    // needed
+    renderer->setupDrawTexture(0);
+    renderer->setupDrawPureColorUniforms();
+    renderer->setupDrawColorFilterUniforms();
+    renderer->setupDrawShaderUniforms(pureTranslate);
+    renderer->setupDrawTextGammaUniforms();
+
+    return NO_ERROR;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -62,8 +110,6 @@
 
     mLinearFiltering = false;
 
-    mIndexBufferID = 0;
-
     mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
     mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
     mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
@@ -103,17 +149,16 @@
     sLogFontRendererCreate = false;
 }
 
-FontRenderer::~FontRenderer() {
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        delete mCacheTextures[i];
+void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        delete cacheTextures[i];
     }
-    mCacheTextures.clear();
+    cacheTextures.clear();
+}
 
-    if (mInitialized) {
-        // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
-        Caches::getInstance().unbindIndicesBuffer();
-        glDeleteBuffers(1, &mIndexBufferID);
-    }
+FontRenderer::~FontRenderer() {
+    clearCacheTextures(mACacheTextures);
+    clearCacheTextures(mRGBACacheTextures);
 
     LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
     while (it.next()) {
@@ -130,15 +175,19 @@
         it.value()->invalidateTextureCache();
     }
 
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        mCacheTextures[i]->init();
+    for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
+        mACacheTextures[i]->init();
+    }
+
+    for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
+        mRGBACacheTextures[i]->init();
     }
 }
 
-void FontRenderer::flushLargeCaches() {
+void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
     // Start from 1; don't deallocate smallest/default texture
-    for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
-        CacheTexture* cacheTexture = mCacheTextures[i];
+    for (uint32_t i = 1; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
         if (cacheTexture->getPixelBuffer()) {
             cacheTexture->init();
             LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
@@ -150,11 +199,16 @@
     }
 }
 
-CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
-        uint32_t* startX, uint32_t* startY) {
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) {
-            return mCacheTextures[i];
+void FontRenderer::flushLargeCaches() {
+    flushLargeCaches(mACacheTextures);
+    flushLargeCaches(mRGBACacheTextures);
+}
+
+CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
+        const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
+            return cacheTextures[i];
         }
     }
     // Could not fit glyph into current cache textures
@@ -175,9 +229,27 @@
 
     cachedGlyph->mIsValid = false;
 
+    // choose an appropriate cache texture list for this glyph format
+    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
+    Vector<CacheTexture*>* cacheTextures = NULL;
+    switch (format) {
+        case SkMask::kA8_Format:
+        case SkMask::kBW_Format:
+            cacheTextures = &mACacheTextures;
+            break;
+        case SkMask::kARGB32_Format:
+            cacheTextures = &mRGBACacheTextures;
+            break;
+        default:
+#if DEBUG_FONT_RENDERER
+            ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
+#endif
+        return;
+    }
+
     // If the glyph is too tall, don't cache it
     if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
-                mCacheTextures[mCacheTextures.size() - 1]->getHeight()) {
+                (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
         ALOGE("Font size too large to fit in cache. width, height = %i, %i",
                 (int) glyph.fWidth, (int) glyph.fHeight);
         return;
@@ -187,14 +259,14 @@
     uint32_t startX = 0;
     uint32_t startY = 0;
 
-    CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
+    CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
 
     if (!cacheTexture) {
         if (!precaching) {
             // If the new glyph didn't fit and we are not just trying to precache it,
             // clear out the cache and try again
             flushAllAndInvalidate();
-            cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
+            cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
         }
 
         if (!cacheTexture) {
@@ -222,24 +294,21 @@
         cacheTexture->allocateMesh();
     }
 
-    // Tells us whether the glyphs is B&W (1 bit per pixel)
-    // or anti-aliased (8 bits per pixel)
-    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
-
     uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
-    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
+    int srcStride = glyph.rowBytes();
 
     // Copy the glyph image, taking the mask format into account
-    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
-    int stride = glyph.rowBytes();
-
-    uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
-    memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
-
     switch (format) {
         case SkMask::kA8_Format: {
+            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
+                    - TEXTURE_BORDER_SIZE;
+            // write leading border line
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
+            // write glyph data
             if (mGammaTable) {
-                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
+                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
                     row = cacheY * cacheWidth;
                     cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
                     for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
@@ -249,21 +318,55 @@
                     cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
                 }
             } else {
-                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
+                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
                     row = cacheY * cacheWidth;
                     memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
                     cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
                     cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
                 }
             }
+            // write trailing border line
+            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
+            break;
+        }
+        case SkMask::kARGB32_Format: {
+            // prep data lengths
+            const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
+            const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
+            size_t rowSize = formatSize * glyph.fWidth;
+            // prep advances
+            size_t dstStride = formatSize * cacheWidth;
+            // prep indices
+            // - we actually start one row early, and then increment before first copy
+            uint8_t* src = &bitmapBuffer[0 - srcStride];
+            uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
+            uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
+            uint8_t* dstL = dst - borderSize;
+            uint8_t* dstR = dst + rowSize;
+            // write leading border line
+            memset(dstL, 0, rowSize + 2 * borderSize);
+            // write glyph data
+            while (dst < dstEnd) {
+                memset(dstL += dstStride, 0, borderSize); // leading border column
+                memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
+                memset(dstR += dstStride, 0, borderSize); // trailing border column
+            }
+            // write trailing border line
+            memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
             break;
         }
         case SkMask::kBW_Format: {
+            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
+                    - TEXTURE_BORDER_SIZE;
             static const uint8_t COLORS[2] = { 0, 255 };
-
+            // write leading border line
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
+            // write glyph data
             for (cacheY = startY; cacheY < endY; cacheY++) {
                 cacheX = startX;
-                int rowBytes = stride;
+                int rowBytes = srcStride;
                 uint8_t* buffer = bitmapBuffer;
 
                 row = cacheY * cacheWidth;
@@ -276,23 +379,24 @@
                 }
                 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
 
-                bitmapBuffer += stride;
+                bitmapBuffer += srcStride;
             }
+            // write trailing border line
+            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
             break;
         }
         default:
-            ALOGW("Unkown glyph format: 0x%x", format);
+            ALOGW("Unknown glyph format: 0x%x", format);
             break;
     }
 
-    row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
-    memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
-
     cachedGlyph->mIsValid = true;
 }
 
-CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
-    CacheTexture* cacheTexture = new CacheTexture(width, height, gMaxNumberOfQuads);
+CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
+        bool allocate) {
+    CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
 
     if (allocate) {
         Caches::getInstance().activeTexture(0);
@@ -304,44 +408,23 @@
 }
 
 void FontRenderer::initTextTexture() {
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        delete mCacheTextures[i];
-    }
-    mCacheTextures.clear();
+    clearCacheTextures(mACacheTextures);
+    clearCacheTextures(mRGBACacheTextures);
 
     mUploadTexture = false;
-    mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
-    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false));
-    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false));
-    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, false));
-    mCurrentCacheTexture = mCacheTextures[0];
-}
-
-// Avoid having to reallocate memory and render quad by quad
-void FontRenderer::initVertexArrayBuffers() {
-    uint32_t numIndices = gMaxNumberOfQuads * 6;
-    uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
-    uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
-
-    // Four verts, two triangles , six indices per quad
-    for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
-        int i6 = i * 6;
-        int i4 = i * 4;
-
-        indexBufferData[i6 + 0] = i4 + 0;
-        indexBufferData[i6 + 1] = i4 + 1;
-        indexBufferData[i6 + 2] = i4 + 2;
-
-        indexBufferData[i6 + 3] = i4 + 0;
-        indexBufferData[i6 + 4] = i4 + 2;
-        indexBufferData[i6 + 5] = i4 + 3;
-    }
-
-    glGenBuffers(1, &mIndexBufferID);
-    Caches::getInstance().bindIndicesBuffer(mIndexBufferID);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
-
-    free(indexBufferData);
+    mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
+            GL_ALPHA, true));
+    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
+            GL_ALPHA, false));
+    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
+            GL_ALPHA, false));
+    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
+            GL_ALPHA, false));
+    mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
+            GL_RGBA, false));
+    mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
+            GL_RGBA, false));
+    mCurrentCacheTexture = mACacheTextures[0];
 }
 
 // We don't want to allocate anything unless we actually draw text
@@ -351,11 +434,28 @@
     }
 
     initTextTexture();
-    initVertexArrayBuffers();
 
     mInitialized = true;
 }
 
+void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
+        bool& resetPixelStore, GLuint& lastTextureId) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
+        if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
+            if (cacheTexture->getTextureId() != lastTextureId) {
+                lastTextureId = cacheTexture->getTextureId();
+                caches.activeTexture(0);
+                caches.bindTexture(lastTextureId);
+            }
+
+            if (cacheTexture->upload()) {
+                resetPixelStore = true;
+            }
+        }
+    }
+}
+
 void FontRenderer::checkTextureUpdate() {
     if (!mUploadTexture) {
         return;
@@ -368,25 +468,8 @@
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
     // Iterate over all the cache textures and see which ones need to be updated
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        CacheTexture* cacheTexture = mCacheTextures[i];
-        if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
-            if (cacheTexture->getTextureId() != lastTextureId) {
-                lastTextureId = cacheTexture->getTextureId();
-                caches.activeTexture(0);
-                glBindTexture(GL_TEXTURE_2D, lastTextureId);
-            }
-
-            if (cacheTexture->upload()) {
-                resetPixelStore = true;
-            }
-
-#if DEBUG_FONT_RENDERER
-            ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
-                    i, x, y, width, height);
-#endif
-        }
-    }
+    checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
+    checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
 
     // Unbind any PBO we might have used to update textures
     caches.unbindPixelBuffer();
@@ -400,21 +483,21 @@
     mUploadTexture = false;
 }
 
-void FontRenderer::issueDrawCommand() {
+void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
+    Caches& caches = Caches::getInstance();
     bool first = true;
     bool force = false;
-
-    GLuint lastId = 0;
-    Caches& caches = Caches::getInstance();
-
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        CacheTexture* texture = mCacheTextures[i];
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* texture = cacheTextures[i];
         if (texture->canDraw()) {
             if (first) {
-                if (mFunctor) (*mFunctor)(0, NULL);
+                if (mFunctor) {
+                    TextSetupFunctor::Data functorData(texture->getFormat());
+                    (*mFunctor)(0, &functorData);
+                }
 
                 checkTextureUpdate();
-                caches.bindIndicesBuffer(mIndexBufferID);
+                caches.bindIndicesBuffer();
 
                 if (!mDrawn) {
                     // If returns true, a VBO was bound and we must
@@ -427,7 +510,7 @@
                 first = false;
             }
 
-            glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
+            caches.bindTexture(texture->getTextureId());
             texture->setLinearFiltering(mLinearFiltering, false);
 
             TextureVertex* mesh = texture->mesh();
@@ -441,6 +524,11 @@
             texture->resetMesh();
         }
     }
+}
+
+void FontRenderer::issueDrawCommand() {
+    issueDrawCommand(mACacheTextures);
+    issueDrawCommand(mRGBACacheTextures);
 
     mDrawn = true;
 }
@@ -532,13 +620,18 @@
         return image;
     }
 
+#ifdef ANDROID_ENABLE_RENDERSCRIPT
     // Align buffers for renderscript usage
     if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
         paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
     }
-
     int size = paddedWidth * paddedHeight;
     uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
+#else
+    int size = paddedWidth * paddedHeight;
+    uint8_t* dataBuffer = (uint8_t*) malloc(size);
+#endif
+
     memset(dataBuffer, 0, size);
 
     int penX = radius - bounds.left;
@@ -611,13 +704,13 @@
 
 bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
-        float hOffset, float vOffset, Rect* bounds) {
+        float hOffset, float vOffset, Rect* bounds, Functor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
     }
 
-    initRender(clip, bounds, NULL);
+    initRender(clip, bounds, functor);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
     finishRender();
 
@@ -633,49 +726,55 @@
 }
 
 void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
-    if (width * height * radius < RS_MIN_INPUT_CUTOFF) {
-        float *gaussian = new float[2 * radius + 1];
-        Blur::generateGaussianWeights(gaussian, radius);
+#ifdef ANDROID_ENABLE_RENDERSCRIPT
+    if (width * height * radius >= RS_MIN_INPUT_CUTOFF) {
+        uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
 
-        uint8_t* scratch = new uint8_t[width * height];
-        Blur::horizontal(gaussian, radius, *image, scratch, width, height);
-        Blur::vertical(gaussian, radius, scratch, *image, width, height);
+        if (mRs == 0) {
+            mRs = new RSC::RS();
+            if (!mRs->init(RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
+                ALOGE("blur RS failed to init");
+            }
 
-        delete[] gaussian;
-        delete[] scratch;
-        return;
-    }
-
-    uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
-
-    if (mRs.get() == 0) {
-        mRs = new RSC::RS();
-        if (!mRs->init(true, true)) {
-            ALOGE("blur RS failed to init");
+            mRsElement = RSC::Element::A_8(mRs);
+            mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
         }
 
-        mRsElement = RSC::Element::A_8(mRs);
-        mRsScript = new RSC::ScriptIntrinsicBlur(mRs, mRsElement);
+        RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
+        RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
+                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+                *image);
+        RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
+                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+                outImage);
+
+        mRsScript->setRadius(radius);
+        mRsScript->setInput(ain);
+        mRsScript->forEach(aout);
+
+        // replace the original image's pointer, avoiding a copy back to the original buffer
+        free(*image);
+        *image = outImage;
+
+        return;
     }
+#endif
 
-    sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
-    sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
-            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
-    sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
-            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
+    float *gaussian = new float[2 * radius + 1];
+    Blur::generateGaussianWeights(gaussian, radius);
 
-    mRsScript->setRadius(radius);
-    mRsScript->blur(ain, aout);
+    uint8_t* scratch = new uint8_t[width * height];
+    Blur::horizontal(gaussian, radius, *image, scratch, width, height);
+    Blur::vertical(gaussian, radius, scratch, *image, width, height);
 
-    // replace the original image's pointer, avoiding a copy back to the original buffer
-    free(*image);
-    *image = outImage;
+    delete[] gaussian;
+    delete[] scratch;
 }
 
-uint32_t FontRenderer::getCacheSize() const {
+static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
     uint32_t size = 0;
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        CacheTexture* cacheTexture = mCacheTextures[i];
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
         if (cacheTexture && cacheTexture->getPixelBuffer()) {
             size += cacheTexture->getPixelBuffer()->getSize();
         }
@@ -683,5 +782,19 @@
     return size;
 }
 
+uint32_t FontRenderer::getCacheSize(GLenum format) const {
+    switch (format) {
+        case GL_ALPHA: {
+            return calculateCacheSize(mACacheTextures);
+        }
+        case GL_RGBA: {
+            return calculateCacheSize(mRGBACacheTextures);
+        }
+        default: {
+            return 0;
+        }
+    }
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 307a1d9..aa7e776 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_HWUI_FONT_RENDERER_H
 #define ANDROID_HWUI_FONT_RENDERER_H
 
+#include <utils/Functor.h>
 #include <utils/LruCache.h>
 #include <utils/Vector.h>
+#include <utils/StrongPointer.h>
 
 #include <SkPaint.h>
 
@@ -32,19 +34,55 @@
 #include "Matrix.h"
 #include "Properties.h"
 
+#ifdef ANDROID_ENABLE_RENDERSCRIPT
+#include "RenderScript.h"
 namespace RSC {
     class Element;
     class RS;
     class ScriptIntrinsicBlur;
+    class sp;
 }
+#endif
 
 class Functor;
 
 namespace android {
 namespace uirenderer {
 
+class OpenGLRenderer;
+
 ///////////////////////////////////////////////////////////////////////////////
-// Renderer
+// TextSetupFunctor
+///////////////////////////////////////////////////////////////////////////////
+class TextSetupFunctor: public Functor {
+public:
+    struct Data {
+        Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
+        }
+
+        GLenum glyphFormat;
+    };
+
+    TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
+            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
+            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
+            alpha(alpha), mode(mode), paint(paint) {
+    }
+    ~TextSetupFunctor() { }
+
+    status_t operator ()(int what, void* data);
+
+    OpenGLRenderer* renderer;
+    float x;
+    float y;
+    bool pureTranslate;
+    int alpha;
+    SkXfermode::Mode mode;
+    SkPaint* paint;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
 class FontRenderer {
@@ -52,6 +90,7 @@
     FontRenderer();
     ~FontRenderer();
 
+    void flushLargeCaches(Vector<CacheTexture*>& cacheTextures);
     void flushLargeCaches();
 
     void setGammaTable(const uint8_t* gammaTable) {
@@ -70,7 +109,8 @@
 
     // bounds is an out parameter
     bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
-            uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds);
+            uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds,
+            Functor* functor);
 
     struct DropShadow {
         DropShadow() { };
@@ -97,30 +137,29 @@
         mLinearFiltering = linearFiltering;
     }
 
-    uint32_t getCacheSize() const;
+    uint32_t getCacheSize(GLenum format) const;
 
 private:
     friend class Font;
 
-    static const uint32_t gMaxNumberOfQuads = 2048;
-
     const uint8_t* mGammaTable;
 
     void allocateTextureMemory(CacheTexture* cacheTexture);
     void deallocateTextureMemory(CacheTexture* cacheTexture);
     void initTextTexture();
-    CacheTexture* createCacheTexture(int width, int height, bool allocate);
+    CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate);
     void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
             uint32_t *retOriginX, uint32_t *retOriginY, bool precaching);
-    CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
+    CacheTexture* cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph,
+            uint32_t* startX, uint32_t* startY);
 
     void flushAllAndInvalidate();
-    void initVertexArrayBuffers();
 
     void checkInit();
     void initRender(const Rect* clip, Rect* bounds, Functor* functor);
     void finishRender();
 
+    void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
     void issueDrawCommand();
     void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
             float x2, float y2, float u2, float v2,
@@ -148,7 +187,8 @@
     uint32_t mLargeCacheWidth;
     uint32_t mLargeCacheHeight;
 
-    Vector<CacheTexture*> mCacheTextures;
+    Vector<CacheTexture*> mACacheTextures;
+    Vector<CacheTexture*> mRGBACacheTextures;
 
     Font* mCurrentFont;
     LruCache<Font::FontDescription, Font*> mActiveFonts;
@@ -157,8 +197,6 @@
 
     bool mUploadTexture;
 
-    uint32_t mIndexBufferID;
-
     Functor* mFunctor;
     const Rect* mClip;
     Rect* mBounds;
@@ -168,10 +206,12 @@
 
     bool mLinearFiltering;
 
+#ifdef ANDROID_ENABLE_RENDERSCRIPT
     // RS constructs
-    sp<RSC::RS> mRs;
-    sp<const RSC::Element> mRsElement;
-    sp<RSC::ScriptIntrinsicBlur> mRsScript;
+    RSC::sp<RSC::RS> mRs;
+    RSC::sp<const RSC::Element> mRsElement;
+    RSC::sp<RSC::ScriptIntrinsicBlur> mRsScript;
+#endif
 
     static void computeGaussianWeights(float* weights, int32_t radius);
     static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index bbfa66d..46cfd04 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -35,7 +35,7 @@
     virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0;
 
     virtual uint32_t getFontRendererCount() const = 0;
-    virtual uint32_t getFontRendererSize(uint32_t fontRenderer) const = 0;
+    virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0;
 
     virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
     virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
@@ -81,8 +81,8 @@
         return 1;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
-        return mRenderer ? mRenderer->getCacheSize() : 0;
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+        return mRenderer ? mRenderer->getCacheSize(format) : 0;
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const;
@@ -128,8 +128,8 @@
         return 1;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
-        return mRenderer ? mRenderer->getCacheSize() : 0;
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+        return mRenderer ? mRenderer->getCacheSize(format) : 0;
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const {
@@ -162,13 +162,13 @@
         return kGammaCount;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
         if (fontRenderer >= kGammaCount) return 0;
 
         FontRenderer* renderer = mRenderers[fontRenderer];
         if (!renderer) return 0;
 
-        return renderer->getCacheSize();
+        return renderer->getCacheSize(format);
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const {
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 507ed95..0916942 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -78,7 +78,7 @@
     mCache.setOnEntryRemovedListener(this);
 
     const Extensions& extensions = Extensions::getInstance();
-    mUseFloatTexture = extensions.getMajorGlVersion() >= 3;
+    mUseFloatTexture = extensions.hasFloatTextures();
     mHasNpot = extensions.hasNPot();
 }
 
@@ -120,7 +120,7 @@
         const uint32_t size = texture->width * texture->height * bytesPerPixel();
         mSize -= size;
 
-        glDeleteTextures(1, &texture->id);
+        texture->deleteTexture();
         delete texture;
     }
 }
@@ -173,7 +173,7 @@
     GradientInfo info;
     getGradientInfo(colors, count, info);
 
-    Texture* texture = new Texture;
+    Texture* texture = new Texture();
     texture->width = info.width;
     texture->height = 2;
     texture->blend = info.hasAlpha;
@@ -286,7 +286,7 @@
     memcpy(pixels + rowBytes, pixels, rowBytes);
 
     glGenTextures(1, &texture->id);
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    Caches::getInstance().bindTexture(texture->id);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
     if (mUseFloatTexture) {
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
new file mode 100644
index 0000000..edf3930
--- /dev/null
+++ b/libs/hwui/Image.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+
+#include "Caches.h"
+#include "Image.h"
+
+namespace android {
+namespace uirenderer {
+
+Image::Image(sp<GraphicBuffer> buffer) {
+    // Create the EGLImage object that maps the GraphicBuffer
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+    EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+
+    mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
+            EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+
+    if (mImage == EGL_NO_IMAGE_KHR) {
+        ALOGW("Error creating image (%#x)", eglGetError());
+        mTexture = 0;
+    } else {
+        // Create a 2D texture to sample from the EGLImage
+        glGenTextures(1, &mTexture);
+        Caches::getInstance().bindTexture(mTexture);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
+
+        GLenum status = GL_NO_ERROR;
+        while ((status = glGetError()) != GL_NO_ERROR) {
+            ALOGW("Error creating image (%#x)", status);
+        }
+    }
+}
+
+Image::~Image() {
+    if (mImage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage);
+        mImage = EGL_NO_IMAGE_KHR;
+
+        Caches::getInstance().deleteTexture(mTexture);
+        mTexture = 0;
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Image.h b/libs/hwui/Image.h
new file mode 100644
index 0000000..2514535
--- /dev/null
+++ b/libs/hwui/Image.h
@@ -0,0 +1,67 @@
+/*
+ * 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_IMAGE_H
+#define ANDROID_HWUI_IMAGE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * A simple wrapper that creates an EGLImage and a texture for a GraphicBuffer.
+ */
+class Image {
+public:
+    /**
+     * Creates a new image from the specified graphic buffer. If the image
+     * cannot be created, getTexture() will return 0 and getImage() will
+     * return EGL_NO_IMAGE_KHR.
+     */
+    Image(sp<GraphicBuffer> buffer);
+    ~Image();
+
+    /**
+     * Returns the name of the GL texture that can be used to sample
+     * from this image.
+     */
+    GLuint getTexture() const {
+        return mTexture;
+    }
+
+    /**
+     * Returns the name of the EGL image represented by this object.
+     */
+    EGLImageKHR getImage() const {
+        return mImage;
+    }
+
+private:
+    GLuint mTexture;
+    EGLImageKHR mImage;
+}; // class Image
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_IMAGE_H
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 4adad05..bd371a3 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -28,9 +28,9 @@
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
+Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight):
+        caches(Caches::getInstance()), texture(caches) {
     mesh = NULL;
-    meshIndices = NULL;
     meshElementCount = 0;
     cacheable = true;
     dirty = false;
@@ -47,16 +47,15 @@
     debugDrawUpdate = false;
     hasDrawnSinceUpdate = false;
     deferredList = NULL;
-    Caches::getInstance().resourceCache.incrementRefcount(this);
+    caches.resourceCache.incrementRefcount(this);
 }
 
 Layer::~Layer() {
-    if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+    if (colorFilter) caches.resourceCache.decrementRefcount(colorFilter);
     removeFbo();
     deleteTexture();
 
     delete[] mesh;
-    delete[] meshIndices;
     delete deferredList;
 }
 
@@ -76,7 +75,7 @@
         return true;
     }
 
-    const uint32_t maxTextureSize = Caches::getInstance().maxTextureSize;
+    const uint32_t maxTextureSize = caches.maxTextureSize;
     if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
                 desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
@@ -89,7 +88,7 @@
     setSize(desiredWidth, desiredHeight);
 
     if (fbo) {
-        Caches::getInstance().activeTexture(0);
+        caches.activeTexture(0);
         bindTexture();
         allocateTexture();
 
@@ -120,14 +119,14 @@
         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
         if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
 
-        Caches::getInstance().renderBufferCache.put(stencil);
+        caches.renderBufferCache.put(stencil);
         stencil = NULL;
     }
 
     if (fbo) {
         if (flush) LayerRenderer::flushLayer(this);
         // If put fails the cache will delete the FBO
-        Caches::getInstance().fboCache.put(fbo);
+        caches.fboCache.put(fbo);
         fbo = 0;
     }
 }
@@ -138,21 +137,55 @@
 
 void Layer::setColorFilter(SkiaColorFilter* filter) {
     if (colorFilter) {
-        Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+        caches.resourceCache.decrementRefcount(colorFilter);
     }
     colorFilter = filter;
     if (colorFilter) {
-        Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
+        caches.resourceCache.incrementRefcount(colorFilter);
+    }
+}
+
+void Layer::bindTexture() const {
+    if (texture.id) {
+        caches.bindTexture(renderTarget, texture.id);
+    }
+}
+
+void Layer::bindStencilRenderBuffer() const {
+    if (stencil) {
+        stencil->bind();
+    }
+}
+
+void Layer::generateTexture() {
+    if (!texture.id) {
+        glGenTextures(1, &texture.id);
+    }
+}
+
+void Layer::deleteTexture() {
+    if (texture.id) {
+        texture.deleteTexture();
+        texture.id = 0;
+    }
+}
+
+void Layer::clearTexture() {
+    texture.id = 0;
+}
+
+void Layer::allocateTexture() {
+#if DEBUG_LAYERS
+    ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
+#endif
+    if (texture.id) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+        glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
     }
 }
 
 void Layer::defer() {
-    if (!deferredList) {
-        deferredList = new DeferredDisplayList;
-    }
-    DeferStateStruct deferredState(*deferredList, *renderer,
-            DisplayList::kReplayFlag_ClipChildren);
-
     const float width = layer.getWidth();
     const float height = layer.getHeight();
 
@@ -161,6 +194,14 @@
         dirtyRect.set(0, 0, width, height);
     }
 
+    if (deferredList) {
+        deferredList->reset(dirtyRect);
+    } else {
+        deferredList = new DeferredDisplayList(dirtyRect);
+    }
+    DeferStateStruct deferredState(*deferredList, *renderer,
+            DisplayList::kReplayFlag_ClipChildren);
+
     renderer->initViewport(width, height);
     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
             dirtyRect.right, dirtyRect.bottom, !isBlend());
@@ -170,8 +211,19 @@
     deferredUpdateScheduled = false;
 }
 
-void Layer::flush() {
+void Layer::cancelDefer() {
+    renderer = NULL;
+    displayList = NULL;
+    deferredUpdateScheduled = false;
     if (deferredList) {
+        delete deferredList;
+        deferredList = NULL;
+    }
+}
+
+void Layer::flush() {
+    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
+    if (deferredList && renderer) {
         renderer->setViewport(layer.getWidth(), layer.getHeight());
         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
                 !isBlend());
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 7186603..b70042f 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -40,6 +40,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 // Forward declarations
+class Caches;
 class OpenGLRenderer;
 class DisplayList;
 class DeferredDisplayList;
@@ -221,50 +222,19 @@
 
     ANDROID_API void setColorFilter(SkiaColorFilter* filter);
 
-    inline void bindTexture() const {
-        if (texture.id) {
-            glBindTexture(renderTarget, texture.id);
-        }
-    }
+    void bindStencilRenderBuffer() const;
 
-    inline void bindStencilRenderBuffer() const {
-        if (stencil) {
-            stencil->bind();
-        }
-    }
-
-    inline void generateTexture() {
-        if (!texture.id) {
-            glGenTextures(1, &texture.id);
-        }
-    }
-
-    inline void deleteTexture() {
-        if (texture.id) {
-            glDeleteTextures(1, &texture.id);
-            texture.id = 0;
-        }
-    }
+    void bindTexture() const;
+    void generateTexture();
+    void allocateTexture();
+    void deleteTexture();
 
     /**
      * When the caller frees the texture itself, the caller
      * must call this method to tell this layer that it lost
      * the texture.
      */
-    void clearTexture() {
-        texture.id = 0;
-    }
-
-    inline void allocateTexture() {
-#if DEBUG_LAYERS
-        ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
-#endif
-        if (texture.id) {
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-            glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
-                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-        }
-    }
+    ANDROID_API void clearTexture();
 
     inline mat4& getTexTransform() {
         return texTransform;
@@ -275,6 +245,7 @@
     }
 
     void defer();
+    void cancelDefer();
     void flush();
     void render();
 
@@ -306,7 +277,6 @@
      * If the layer can be rendered as a mesh, this is non-null.
      */
     TextureVertex* mesh;
-    uint16_t* meshIndices;
     GLsizei meshElementCount;
 
     /**
@@ -320,6 +290,8 @@
     bool hasDrawnSinceUpdate;
 
 private:
+    Caches& caches;
+
     /**
      * Name of the FBO used to render the layer. If the name is 0
      * this layer is not backed by an FBO, but a simple texture.
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index a0709af..6be0146 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -155,9 +155,7 @@
                     victim->layer.getHeight());
         }
 
-        layer->deferredUpdateScheduled = false;
-        layer->renderer = NULL;
-        layer->displayList = NULL;
+        layer->cancelDefer();
 
         LayerEntry entry(layer);
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 3e55fff..f8076cc 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -130,10 +130,7 @@
     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
         if (mLayer->mesh) {
             delete[] mLayer->mesh;
-            delete[] mLayer->meshIndices;
-
             mLayer->mesh = NULL;
-            mLayer->meshIndices = NULL;
             mLayer->meshElementCount = 0;
         }
 
@@ -154,17 +151,11 @@
 
     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
         delete[] mLayer->mesh;
-        delete[] mLayer->meshIndices;
-
         mLayer->mesh = NULL;
-        mLayer->meshIndices = NULL;
     }
 
-    bool rebuildIndices = false;
     if (!mLayer->mesh) {
         mLayer->mesh = new TextureVertex[count * 4];
-        mLayer->meshIndices = new uint16_t[elementCount];
-        rebuildIndices = true;
     }
     mLayer->meshElementCount = elementCount;
 
@@ -173,7 +164,6 @@
     const float height = mLayer->layer.getHeight();
 
     TextureVertex* mesh = mLayer->mesh;
-    uint16_t* indices = mLayer->meshIndices;
 
     for (size_t i = 0; i < count; i++) {
         const android::Rect* r = &rects[i];
@@ -187,17 +177,6 @@
         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
-
-        if (rebuildIndices) {
-            uint16_t quad = i * 4;
-            int index = i * 6;
-            indices[index    ] = quad;       // top-left
-            indices[index + 1] = quad + 1;   // top-right
-            indices[index + 2] = quad + 2;   // bottom-left
-            indices[index + 3] = quad + 2;   // bottom-left
-            indices[index + 4] = quad + 1;   // top-right
-            indices[index + 5] = quad + 3;   // bottom-right
-        }
     }
 }
 
@@ -436,7 +415,7 @@
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         caches.activeTexture(0);
-        glBindTexture(GL_TEXTURE_2D, texture);
+        caches.bindTexture(texture);
 
         glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
 
@@ -467,7 +446,7 @@
             mat4 texTransform(layer->getTexTransform());
 
             mat4 invert;
-            invert.translate(0.0f, 1.0f, 0.0f);
+            invert.translate(0.0f, 1.0f);
             invert.scale(1.0f, -1.0f, 1.0f);
             layer->getTexTransform().multiply(invert);
 
@@ -498,7 +477,7 @@
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
-        glDeleteTextures(1, &texture);
+        caches.deleteTexture(texture);
         caches.fboCache.put(fbo);
         glViewport(previousViewport[0], previousViewport[1],
                 previousViewport[2], previousViewport[3]);
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 6a5ea51..ba22071 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -72,7 +72,7 @@
     return fabs(f) <= EPSILON;
 }
 
-uint32_t Matrix4::getType() const {
+uint8_t Matrix4::getType() const {
     if (mType & kTypeUnknown) {
         mType = kTypeIdentity;
 
@@ -114,7 +114,7 @@
     return mType;
 }
 
-uint32_t Matrix4::getGeometryType() const {
+uint8_t Matrix4::getGeometryType() const {
     return getType() & sGeometryMask;
 }
 
@@ -122,12 +122,16 @@
     return getType() & kTypeRectToRect;
 }
 
+bool Matrix4::positiveScale() const {
+    return (data[kScaleX] > 0.0f && data[kScaleY] > 0.0f);
+}
+
 bool Matrix4::changesBounds() const {
     return getType() & (kTypeScale | kTypeAffine | kTypePerspective);
 }
 
 bool Matrix4::isPureTranslate() const {
-    return getGeometryType() == kTypeTranslate;
+    return getGeometryType() <= kTypeTranslate;
 }
 
 bool Matrix4::isSimple() const {
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 75e280c..b861ba4 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -26,6 +26,12 @@
 namespace android {
 namespace uirenderer {
 
+#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
+#define MATRIX_ARGS(m) \
+    (m)->get(0), (m)->get(1), (m)->get(2), \
+    (m)->get(3), (m)->get(4), (m)->get(5), \
+    (m)->get(6), (m)->get(7), (m)->get(8)
+
 ///////////////////////////////////////////////////////////////////////////////
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
@@ -118,7 +124,7 @@
 
     void loadOrtho(float left, float right, float bottom, float top, float near, float far);
 
-    uint32_t getType() const;
+    uint8_t getType() const;
 
     void multiply(const Matrix4& v) {
         Matrix4 u;
@@ -128,10 +134,27 @@
 
     void multiply(float v);
 
-    void translate(float x, float y, float z) {
-        Matrix4 u;
-        u.loadTranslate(x, y, z);
-        multiply(u);
+    void translate(float x, float y) {
+        if ((getType() & sGeometryMask) <= kTypeTranslate) {
+            data[kTranslateX] += x;
+            data[kTranslateY] += y;
+        } else {
+            // Doing a translation will only affect the translate bit of the type
+            // Save the type
+            uint8_t type = mType;
+
+            Matrix4 u;
+            u.loadTranslate(x, y, 0.0f);
+            multiply(u);
+
+            // Restore the type and fix the translate bit
+            mType = type;
+            if (data[kTranslateX] != 0.0f || data[kTranslateY] != 0.0f) {
+                mType |= kTypeTranslate;
+            } else {
+                mType &= ~kTypeTranslate;
+            }
+        }
     }
 
     void scale(float sx, float sy, float sz) {
@@ -160,6 +183,7 @@
     bool isIdentity() const;
     bool isPerspective() const;
     bool rectToRect() const;
+    bool positiveScale() const;
 
     bool changesBounds() const;
 
@@ -179,7 +203,7 @@
     static const Matrix4& identity();
 
 private:
-    mutable uint32_t mType;
+    mutable uint8_t mType;
 
     inline float get(int i, int j) const {
         return data[i * 4 + j];
@@ -189,7 +213,7 @@
         data[i * 4 + j] = v;
     }
 
-    uint32_t getGeometryType() const;
+    uint8_t getGeometryType() const;
 
 }; // class Matrix4
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7735819..35fc804 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 
 #include <SkCanvas.h>
-#include <SkPathMeasure.h>
 #include <SkTypeface.h>
 
 #include <utils/Log.h>
@@ -34,6 +33,7 @@
 #include "OpenGLRenderer.h"
 #include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
+#include "Fence.h"
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "Vector.h"
@@ -107,6 +107,15 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// Functions
+///////////////////////////////////////////////////////////////////////////////
+
+template<typename T>
+static inline T min(T a, T b) {
+    return a < b ? a : b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -120,6 +129,7 @@
 
     mFirstSnapshot = new Snapshot;
     mFrameStarted = false;
+    mCountOverdraw = false;
 
     mScissorOptimizationDisabled = false;
 }
@@ -222,6 +232,7 @@
 
 status_t OpenGLRenderer::prepareDirty(float left, float top,
         float right, float bottom, bool opaque) {
+
     setupFrameState(left, top, right, bottom, opaque);
 
     // Layer renderers will start the frame immediately
@@ -253,7 +264,7 @@
 }
 
 status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
-    if (!opaque) {
+    if (!opaque || mCountOverdraw) {
         mCaches.enableScissor();
         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
@@ -335,6 +346,10 @@
 #endif
     }
 
+    if (mCountOverdraw) {
+        countOverdraw();
+    }
+
     mFrameStarted = false;
 }
 
@@ -345,6 +360,7 @@
             mCaches.currentProgram = NULL;
         }
     }
+    mCaches.resetActiveTexture();
     mCaches.unbindMeshBuffer();
     mCaches.unbindIndicesBuffer();
     mCaches.resetVertexPointers();
@@ -366,6 +382,7 @@
     dirtyClip();
 
     mCaches.activeTexture(0);
+    mCaches.resetBoundTextures();
 
     mCaches.blend = true;
     glEnable(GL_BLEND);
@@ -432,13 +449,8 @@
 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
-    interrupt();
     detachFunctor(functor);
 
-    mCaches.enableScissor();
-    if (mDirtyClip) {
-        setScissorFromClip();
-    }
 
     Rect clip(*mSnapshot->clipRect);
     clip.snapToPixelBoundaries();
@@ -459,7 +471,18 @@
     info.height = getSnapshot()->height;
     getSnapshot()->transform->copyTo(&info.transform[0]);
 
-    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew;
+    bool dirtyClip = mDirtyClip;
+    // setup GL state for functor
+    if (mDirtyClip) {
+        setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
+    }
+    if (mCaches.enableScissor() || dirtyClip) {
+        setScissorFromClip();
+    }
+    interrupt();
+
+    // call functor immediately after GL state setup
+    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
 
     if (result != DrawGlInfo::kStatusDone) {
         Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
@@ -471,7 +494,7 @@
     }
 
     resume();
-    return result;
+    return result | DrawGlInfo::kStatusDrew;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -512,18 +535,41 @@
         mCaches.setScissor(clip->left, mFirstSnapshot->height - clip->bottom,
                 clip->right - clip->left, clip->bottom - clip->top);
 
+        // 1x overdraw
         mCaches.stencil.enableDebugTest(2);
-        drawColor(0x2f0000ff, SkXfermode::kSrcOver_Mode);
+        drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
+
+        // 2x overdraw
         mCaches.stencil.enableDebugTest(3);
-        drawColor(0x2f00ff00, SkXfermode::kSrcOver_Mode);
+        drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
+
+        // 3x overdraw
         mCaches.stencil.enableDebugTest(4);
-        drawColor(0x3fff0000, SkXfermode::kSrcOver_Mode);
+        drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
+
+        // 4x overdraw and higher
         mCaches.stencil.enableDebugTest(4, true);
-        drawColor(0x7fff0000, SkXfermode::kSrcOver_Mode);
+        drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
+
         mCaches.stencil.disable();
     }
 }
 
+void OpenGLRenderer::countOverdraw() {
+    size_t count = mWidth * mHeight;
+    uint32_t* buffer = new uint32_t[count];
+    glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
+
+    size_t total = 0;
+    for (size_t i = 0; i < count; i++) {
+        total += buffer[i] & 0xff;
+    }
+
+    mOverdraw = total / float(count);
+
+    delete[] buffer;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Layers
 ///////////////////////////////////////////////////////////////////////////////
@@ -531,6 +577,8 @@
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
     if (layer->deferredUpdateScheduled && layer->renderer &&
             layer->displayList && layer->displayList->isRenderable()) {
+        ATRACE_CALL();
+
         Rect& dirty = layer->dirtyRect;
 
         if (inFrame) {
@@ -598,8 +646,11 @@
             sprintf(layerName, "Layer #%d", i);
             startMark(layerName);
 
+            ATRACE_BEGIN("flushLayer");
             Layer* layer = mLayerUpdates.itemAt(i);
             layer->flush();
+            ATRACE_END();
+
             mCaches.resourceCache.decrementRefcount(layer);
 
             endMark();
@@ -628,6 +679,18 @@
     }
 }
 
+void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
+    if (layer) {
+        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
+            if (mLayerUpdates.itemAt(i) == layer) {
+                mLayerUpdates.removeAt(i);
+                mCaches.resourceCache.decrementRefcount(layer);
+                break;
+            }
+        }
+    }
+}
+
 void OpenGLRenderer::clearLayerUpdates() {
     size_t count = mLayerUpdates.size();
     if (count > 0) {
@@ -640,6 +703,14 @@
     }
 }
 
+void OpenGLRenderer::flushLayerUpdates() {
+    syncState();
+    updateLayers();
+    flushLayers();
+    // Wait for all the layer updates to be executed
+    AutoFence fence;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // State management
 ///////////////////////////////////////////////////////////////////////////////
@@ -780,6 +851,7 @@
         if (!mSnapshot->isIgnored()) {
             mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
             mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+            mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
         }
     }
 
@@ -961,6 +1033,10 @@
     const Rect& rect = layer->layer;
     const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
 
+    bool clipRequired = false;
+    quickRejectNoScissor(rect, &clipRequired); // safely ignore return, should never be rejected
+    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+
     if (fboLayer) {
         endTiling();
 
@@ -1013,7 +1089,7 @@
 }
 
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
-    float alpha = layer->getAlpha() / 255.0f * mSnapshot->alpha;
+    float alpha = getLayerAlpha(layer);
 
     setupDraw();
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
@@ -1049,8 +1125,6 @@
     setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-
-    finishDrawTexture();
 }
 
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -1119,8 +1193,6 @@
         return;
     }
 
-    // TODO: See LayerRenderer.cpp::generateMesh() for important
-    //       information about this implementation
     if (CC_LIKELY(!layer->region.isEmpty())) {
         size_t count;
         const android::Rect* rects;
@@ -1143,7 +1215,7 @@
         // after we setup drawing in case we need to mess with the
         // stencil buffer in setupDraw()
         TextureVertex* mesh = mCaches.getRegionMesh();
-        GLsizei numQuads = 0;
+        uint32_t numQuads = 0;
 
         setupDrawWithTexture();
         setupDrawColor(alpha, alpha, alpha, alpha);
@@ -1182,7 +1254,7 @@
 
             numQuads++;
 
-            if (numQuads >= REGION_MESH_QUAD_COUNT) {
+            if (numQuads >= gMaxNumberOfQuads) {
                 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
                                 GL_UNSIGNED_SHORT, NULL));
                 numQuads = 0;
@@ -1195,8 +1267,6 @@
                             GL_UNSIGNED_SHORT, NULL));
         }
 
-        finishDrawTexture();
-
 #if DEBUG_LAYERS_AS_REGIONS
         drawRegionRects(layer->region);
 #endif
@@ -1233,7 +1303,6 @@
 
 void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color,
         SkXfermode::Mode mode, bool dirty) {
-    int count = 0;
     Vector<float> rects;
 
     SkRegion::Iterator it(region);
@@ -1243,11 +1312,10 @@
         rects.push(r.fTop);
         rects.push(r.fRight);
         rects.push(r.fBottom);
-        count += 4;
         it.next();
     }
 
-    drawColorRects(rects.array(), count, color, mode, true, dirty, false);
+    drawColorRects(rects.array(), rects.size(), color, mode, true, dirty, false);
 }
 
 void OpenGLRenderer::dirtyLayer(const float left, const float top,
@@ -1277,6 +1345,21 @@
     }
 }
 
+void OpenGLRenderer::drawIndexedQuads(Vertex* mesh, GLsizei quadsCount) {
+    GLsizei elementsCount = quadsCount * 6;
+    while (elementsCount > 0) {
+        GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+
+        setupDrawIndexedVertices(&mesh[0].position[0]);
+        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
+
+        elementsCount -= drawCount;
+        // Though there are 4 vertices in a quad, we use 6 indices per
+        // quad to draw with GL_TRIANGLES
+        mesh += (drawCount / 6) * 4;
+    }
+}
+
 void OpenGLRenderer::clearLayerRegions() {
     const size_t count = mLayers.size();
     if (count == 0) return;
@@ -1291,17 +1374,15 @@
         // is likely different so we need to disable clipping here
         bool scissorChanged = mCaches.disableScissor();
 
-        Vertex mesh[count * 6];
+        Vertex mesh[count * 4];
         Vertex* vertex = mesh;
 
         for (uint32_t i = 0; i < count; i++) {
             Rect* bounds = mLayers.itemAt(i);
 
-            Vertex::set(vertex++, bounds->left, bounds->bottom);
             Vertex::set(vertex++, bounds->left, bounds->top);
             Vertex::set(vertex++, bounds->right, bounds->top);
             Vertex::set(vertex++, bounds->left, bounds->bottom);
-            Vertex::set(vertex++, bounds->right, bounds->top);
             Vertex::set(vertex++, bounds->right, bounds->bottom);
 
             delete bounds;
@@ -1317,9 +1398,8 @@
         setupDrawProgram();
         setupDrawPureColorUniforms();
         setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
-        setupDrawVertices(&mesh[0].position[0]);
 
-        glDrawArrays(GL_TRIANGLES, 0, count * 6);
+        drawIndexedQuads(&mesh[0], count);
 
         if (scissorChanged) mCaches.enableScissor();
     } else {
@@ -1342,11 +1422,30 @@
         // state has bounds initialized in local coordinates
         if (!state.mBounds.isEmpty()) {
             currentMatrix.mapRect(state.mBounds);
-            if (!state.mBounds.intersect(currentClip)) {
+            Rect clippedBounds(state.mBounds);
+            // NOTE: if we ever want to use this clipping info to drive whether the scissor
+            // is used, it should more closely duplicate the quickReject logic (in how it uses
+            // snapToPixelBoundaries)
+
+            if(!clippedBounds.intersect(currentClip)) {
                 // quick rejected
                 return true;
             }
+
+            state.mClipSideFlags = kClipSide_None;
+            if (!currentClip.contains(state.mBounds)) {
+                int& flags = state.mClipSideFlags;
+                // op partially clipped, so record which sides are clipped for clip-aware merging
+                if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
+                if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
+                if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
+                if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
+            }
+            state.mBounds.set(clippedBounds);
         } else {
+            // Empty bounds implies size unknown. Label op as conservatively clipped to disable
+            // overdraw avoidance (since we don't know what it overlaps)
+            state.mClipSideFlags = kClipSide_ConservativeFull;
             state.mBounds.set(currentClip);
         }
     }
@@ -1370,14 +1469,27 @@
     mSnapshot->alpha = state.mAlpha;
 
     if (state.mClipValid && !skipClipRestore) {
-        mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
+        mSnapshot->setClip(state.mClip.left, state.mClip.top,
+                state.mClip.right, state.mClip.bottom);
         dirtyClip();
     }
 }
 
-void OpenGLRenderer::setFullScreenClip() {
-    mSnapshot->setClip(0, 0, mWidth, mHeight);
+/**
+ * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
+ * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
+ * least one op is clipped), or disabled entirely (because no merged op is clipped)
+ *
+ * This method should be called when restoreDisplayState() won't be restoring the clip
+ */
+void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
+    if (clipRect != NULL) {
+        mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+    } else {
+        mSnapshot->setClip(0, 0, mWidth, mHeight);
+    }
     dirtyClip();
+    mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1385,7 +1497,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::translate(float dx, float dy) {
-    currentTransform().translate(dx, dy, 0.0f);
+    currentTransform().translate(dx, dy);
 }
 
 void OpenGLRenderer::rotate(float degrees) {
@@ -1508,65 +1620,49 @@
     return mSnapshot->getLocalClip();
 }
 
-bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
-    if (mSnapshot->isIgnored()) {
-        return true;
-    }
-
-    Rect r(left, top, right, bottom);
-    currentTransform().mapRect(r);
-    r.snapToPixelBoundaries();
-
-    Rect clipRect(*mSnapshot->clipRect);
-    clipRect.snapToPixelBoundaries();
-
-    return !clipRect.intersects(r);
-}
-
 bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
-        Rect& transformed, Rect& clip) {
-    if (mSnapshot->isIgnored()) {
-        return true;
-    }
-
-    transformed.set(left, top, right, bottom);
-    currentTransform().mapRect(transformed);
-    transformed.snapToPixelBoundaries();
-
-    clip.set(*mSnapshot->clipRect);
-    clip.snapToPixelBoundaries();
-
-    return !clip.intersects(transformed);
-}
-
-bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    if (paint->getStyle() != SkPaint::kFill_Style) {
-        float outset = paint->getStrokeWidth() * 0.5f;
-        return quickReject(left - outset, top - outset, right + outset, bottom + outset);
-    } else {
-        return quickReject(left, top, right, bottom);
-    }
-}
-
-bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
+        bool snapOut, bool* clipRequired) {
     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
         return true;
     }
 
     Rect r(left, top, right, bottom);
     currentTransform().mapRect(r);
-    r.snapToPixelBoundaries();
+    r.snapGeometryToPixelBoundaries(snapOut);
 
     Rect clipRect(*mSnapshot->clipRect);
     clipRect.snapToPixelBoundaries();
 
-    bool rejected = !clipRect.intersects(r);
-    if (!isDeferred() && !rejected) {
-        mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r));
+    if (!clipRect.intersects(r)) return true;
+
+    if (clipRequired) *clipRequired = !clipRect.contains(r);
+    return false;
+}
+
+bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
+        SkPaint* paint) {
+    // AA geometry will likely have a ramp around it (not accounted for in local bounds). Snap out
+    // the final mapped rect to ensure correct clipping behavior for the ramp.
+    bool snapOut = paint->isAntiAlias();
+
+    if (paint->getStyle() != SkPaint::kFill_Style) {
+        float outset = paint->getStrokeWidth() * 0.5f;
+        return quickReject(left - outset, top - outset, right + outset, bottom + outset, snapOut);
+    } else {
+        return quickReject(left, top, right, bottom, snapOut);
+    }
+}
+
+bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom, bool snapOut) {
+    bool clipRequired = false;
+    if (quickRejectNoScissor(left, top, right, bottom, snapOut, &clipRequired)) {
+        return true;
     }
 
-    return rejected;
+    if (!isDeferred()) {
+        mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+    }
+    return false;
 }
 
 void OpenGLRenderer::debugClip() {
@@ -1589,7 +1685,7 @@
     SkPath path;
     path.addRect(left, top, right, bottom);
 
-    return clipPath(&path, op);
+    return OpenGLRenderer::clipPath(&path, op);
 }
 
 bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {
@@ -1600,11 +1696,15 @@
     path->transform(transform, &transformed);
 
     SkRegion clip;
-    if (!mSnapshot->clipRegion->isEmpty()) {
-        clip.setRegion(*mSnapshot->clipRegion);
+    if (!mSnapshot->previous->clipRegion->isEmpty()) {
+        clip.setRegion(*mSnapshot->previous->clipRegion);
     } else {
-        Rect* bounds = mSnapshot->clipRect;
-        clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
+        if (mSnapshot->previous == mFirstSnapshot) {
+            clip.setRect(0, 0, mWidth, mHeight);
+        } else {
+            Rect* bounds = mSnapshot->previous->clipRect;
+            clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
+        }
     }
 
     SkRegion region;
@@ -1659,6 +1759,8 @@
     mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
             mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
             mCaches.stencil.isTestEnabled();
+
+    mDescription.emulateStencil = mCountOverdraw;
 }
 
 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1684,11 +1786,6 @@
     mDescription.isAA = true;
 }
 
-void OpenGLRenderer::setupDrawPoint(float pointSize) {
-    mDescription.isPoint = true;
-    mDescription.pointSize = pointSize;
-}
-
 void OpenGLRenderer::setupDrawColor(int color, int alpha) {
     mColorA = alpha / 255.0f;
     mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
@@ -1803,11 +1900,6 @@
     }
 }
 
-void OpenGLRenderer::setupDrawPointUniforms() {
-    int slot = mCaches.currentProgram->getUniform("pointSize");
-    glUniform1f(slot, mDescription.pointSize);
-}
-
 void OpenGLRenderer::setupDrawColorUniforms() {
     if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
@@ -1876,7 +1968,7 @@
 
 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
     bool force = false;
-    if (!vertices) {
+    if (!vertices || vbo) {
         force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
     } else {
         force = mCaches.unbindMeshBuffer();
@@ -1907,21 +1999,28 @@
     mCaches.unbindIndicesBuffer();
 }
 
-void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
-    bool force = mCaches.unbindMeshBuffer();
+void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
+    bool force = false;
+    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
+    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
+    // use the default VBO found in Caches
+    if (!vertices || vbo) {
+        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+    } else {
+        force = mCaches.unbindMeshBuffer();
+    }
+    mCaches.bindIndicesBuffer();
+
     mCaches.bindPositionVertexPointer(force, vertices);
     if (mCaches.currentProgram->texCoords >= 0) {
         mCaches.bindTexCoordsVertexPointer(force, texCoords);
     }
 }
 
-void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
+void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
     bool force = mCaches.unbindMeshBuffer();
+    mCaches.bindIndicesBuffer();
     mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
-    mCaches.unbindIndicesBuffer();
-}
-
-void OpenGLRenderer::finishDrawTexture() {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1941,7 +2040,8 @@
             return status | replayStruct.mDrawGlStatus;
         }
 
-        DeferredDisplayList deferredList;
+        bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
+        DeferredDisplayList deferredList(*(mSnapshot->clipRect), avoidOverdraw);
         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
         displayList->defer(deferStruct, 0);
 
@@ -1983,20 +2083,24 @@
         texture->setFilter(FILTER(paint), true);
     }
 
+    // No need to check for a UV mapper on the texture object, only ARGB_8888
+    // bitmaps get packed in the atlas
     drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-            paint != NULL, color, alpha, mode, (GLvoid*) NULL,
-            (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+            paint != NULL, color, alpha, mode, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
+            GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
 }
 
-status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
-        const Rect& bounds, SkPaint* paint) {
-
-    // merged draw operations don't need scissor, but clip should still be valid
-    mCaches.setScissorEnabled(mScissorOptimizationDisabled);
-
+/**
+ * Important note: this method is intended to draw batches of bitmaps and
+ * will not set the scissor enable or dirty the current layer, if any.
+ * The caller is responsible for properly dirtying the current layer.
+ */
+status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
+        TextureVertex* vertices, bool pureTranslate, const Rect& bounds, SkPaint* paint) {
     mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
     if (!texture) return DrawGlInfo::kStatusDone;
+
     const AutoTexture autoCleanup(texture);
 
     int alpha;
@@ -2004,7 +2108,7 @@
     getAlphaAndMode(paint, &alpha, &mode);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(GL_NEAREST, true); // merged ops are always pure-translation for now
+    texture->setFilter(pureTranslate ? GL_NEAREST : FILTER(paint), true);
 
     const float x = (int) floorf(bounds.left + 0.5f);
     const float y = (int) floorf(bounds.top + 0.5f);
@@ -2013,12 +2117,12 @@
         drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
                 texture->id, paint != NULL, color, alpha, mode,
                 &vertices[0].position[0], &vertices[0].texture[0],
-                GL_TRIANGLES, bitmapCount * 6, true, true);
+                GL_TRIANGLES, bitmapCount * 6, true, true, false);
     } else {
         drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
                 texture->id, alpha / 255.0f, mode, texture->blend,
                 &vertices[0].position[0], &vertices[0].texture[0],
-                GL_TRIANGLES, bitmapCount * 6, false, true, 0, true);
+                GL_TRIANGLES, bitmapCount * 6, false, true, 0, true, false);
     }
 
     return DrawGlInfo::kStatusDrew;
@@ -2033,7 +2137,7 @@
     }
 
     mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = getTexture(bitmap);
     if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
@@ -2056,7 +2160,7 @@
     }
 
     mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = getTexture(bitmap);
     if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
@@ -2101,6 +2205,9 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    // TODO: use quickReject on bounds from vertices
+    mCaches.enableScissor();
+
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
@@ -2119,6 +2226,10 @@
         cleanupColors = true;
     }
 
+    mCaches.activeTexture(0);
+    Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
+    const UvMapper& mapper(getMapper(texture));
+
     for (int32_t y = 0; y < meshHeight; y++) {
         for (int32_t x = 0; x < meshWidth; x++) {
             uint32_t i = (y * (meshWidth + 1) + x) * 2;
@@ -2128,6 +2239,8 @@
             float v1 = float(y) / meshHeight;
             float v2 = float(y + 1) / meshHeight;
 
+            mapper.map(u1, v1, u2, v2);
+
             int ax = i + (meshWidth + 1) * 2;
             int ay = ax + 1;
             int bx = i;
@@ -2157,11 +2270,12 @@
         return DrawGlInfo::kStatusDone;
     }
 
-    mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) {
-        if (cleanupColors) delete[] colors;
-        return DrawGlInfo::kStatusDone;
+        texture = mCaches.textureCache.get(bitmap);
+        if (!texture) {
+            if (cleanupColors) delete[] colors;
+            return DrawGlInfo::kStatusDone;
+        }
     }
     const AutoTexture autoCleanup(texture);
 
@@ -2193,8 +2307,6 @@
 
     glDrawArrays(GL_TRIANGLES, 0, count);
 
-    finishDrawTexture();
-
     int slot = mCaches.currentProgram->getAttrib("colors");
     if (slot >= 0) {
         glDisableVertexAttribArray(slot);
@@ -2214,17 +2326,19 @@
     }
 
     mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = getTexture(bitmap);
     if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     const float width = texture->width;
     const float height = texture->height;
 
-    const float u1 = fmax(0.0f, srcLeft / width);
-    const float v1 = fmax(0.0f, srcTop / height);
-    const float u2 = fmin(1.0f, srcRight / width);
-    const float v2 = fmin(1.0f, srcBottom / height);
+    float u1 = fmax(0.0f, srcLeft / width);
+    float v1 = fmax(0.0f, srcTop / height);
+    float u2 = fmin(1.0f, srcRight / width);
+    float v2 = fmin(1.0f, srcBottom / height);
+
+    getMapper(texture).map(u1, v1, u2, v2);
 
     mCaches.unbindMeshBuffer();
     resetDrawTextureTexCoords(u1, v1, u2, v2);
@@ -2295,37 +2409,38 @@
     return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
         float left, float top, float right, float bottom, SkPaint* paint) {
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
-            left, top, right, bottom, alpha, mode);
-}
-
-status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode) {
     if (quickReject(left, top, right, bottom)) {
         return DrawGlInfo::kStatusDone;
     }
 
-    alpha *= mSnapshot->alpha;
+    AssetAtlas::Entry* entry = mCaches.assetAtlas.getEntry(bitmap);
+    const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
+            right - left, bottom - top, patch);
 
-    const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
-            right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
+    return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
+}
+
+status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
+        float left, float top, float right, float bottom, SkPaint* paint) {
+    if (quickReject(left, top, right, bottom)) {
+        return DrawGlInfo::kStatusDone;
+    }
 
     if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
         mCaches.activeTexture(0);
-        Texture* texture = mCaches.textureCache.get(bitmap);
+        Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
         if (!texture) return DrawGlInfo::kStatusDone;
         const AutoTexture autoCleanup(texture);
+
         texture->setWrap(GL_CLAMP_TO_EDGE, true);
         texture->setFilter(GL_LINEAR, true);
 
+        int alpha;
+        SkXfermode::Mode mode;
+        getAlphaAndMode(paint, &alpha, &mode);
+
         const bool pureTranslate = currentTransform().isPureTranslate();
         // Mark the current layer dirty where we are going to draw the patch
         if (hasLayer() && mesh->hasEmptyQuads) {
@@ -2349,24 +2464,52 @@
             const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
             const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
 
-            drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f,
-                    mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
-                    GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer,
-                    true, !mesh->hasEmptyQuads);
+            right = x + right - left;
+            bottom = y + bottom - top;
+            drawIndexedTextureMesh(x, y, right, bottom, texture->id, alpha / 255.0f,
+                    mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
+                    GL_TRIANGLES, mesh->indexCount, false, true,
+                    mCaches.patchCache.getMeshBuffer(), true, !mesh->hasEmptyQuads);
         } else {
-            drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
-                    mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
-                    GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
-                    true, !mesh->hasEmptyQuads);
+            drawIndexedTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
+                    mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
+                    GL_TRIANGLES, mesh->indexCount, false, false,
+                    mCaches.patchCache.getMeshBuffer(), true, !mesh->hasEmptyQuads);
         }
     }
 
     return DrawGlInfo::kStatusDrew;
 }
 
+/**
+ * Important note: this method is intended to draw batches of 9-patch objects and
+ * will not set the scissor enable or dirty the current layer, if any.
+ * The caller is responsible for properly dirtying the current layer.
+ */
+status_t OpenGLRenderer::drawPatches(SkBitmap* bitmap, AssetAtlas::Entry* entry,
+        TextureVertex* vertices, uint32_t indexCount, SkPaint* paint) {
+    mCaches.activeTexture(0);
+    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
+    if (!texture) return DrawGlInfo::kStatusDone;
+    const AutoTexture autoCleanup(texture);
+
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(GL_LINEAR, true);
+
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
+            mode, texture->blend, &vertices[0].position[0], &vertices[0].texture[0],
+            GL_TRIANGLES, indexCount, false, true, 0, true, false);
+
+    return DrawGlInfo::kStatusDrew;
+}
+
 status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint,
         bool useOffset) {
-    if (!vertexBuffer.getSize()) {
+    if (!vertexBuffer.getVertexCount()) {
         // no vertices to draw
         return DrawGlInfo::kStatusDone;
     }
@@ -2404,7 +2547,7 @@
         glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
     }
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize());
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
 
     if (isAA) {
         glDisableVertexAttribArray(alphaSlot);
@@ -2467,65 +2610,22 @@
 }
 
 status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
+    if (mSnapshot->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
 
-    // TODO: The paint's cap style defines whether the points are square or circular
-    // TODO: Handle AA for round points
+    count &= ~0x1; // round down to nearest two
 
-    // A stroke width of 0 has a special meaning in Skia:
-    // it draws an unscaled 1px point
-    float strokeWidth = paint->getStrokeWidth();
-    const bool isHairLine = paint->getStrokeWidth() == 0.0f;
-    if (isHairLine) {
-        // Now that we know it's hairline, we can set the effective width, to be used later
-        strokeWidth = 1.0f;
-    }
-    const float halfWidth = strokeWidth / 2;
+    VertexBuffer buffer;
+    SkRect bounds;
+    PathTessellator::tessellatePoints(points, count, paint, mSnapshot->transform, bounds, buffer);
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    int verticesCount = count >> 1;
-    int generatedVerticesCount = 0;
-
-    TextureVertex pointsData[verticesCount];
-    TextureVertex* vertex = &pointsData[0];
-
-    // TODO: We should optimize this method to not generate vertices for points
-    // that lie outside of the clip.
-    mCaches.enableScissor();
-
-    setupDraw();
-    setupDrawNoTexture();
-    setupDrawPoint(strokeWidth);
-    setupDrawColor(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(mode);
-    setupDrawProgram();
-    setupDrawModelViewIdentity(true);
-    setupDrawColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawPointUniforms();
-    setupDrawShaderIdentityUniforms();
-    setupDrawMesh(vertex);
-
-    for (int i = 0; i < count; i += 2) {
-        TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
-        generatedVerticesCount++;
-
-        float left = points[i] - halfWidth;
-        float right = points[i] + halfWidth;
-        float top = points[i + 1] - halfWidth;
-        float bottom = points [i + 1] + halfWidth;
-
-        dirtyLayer(left, top, right, bottom, currentTransform());
+    if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
+        return DrawGlInfo::kStatusDone;
     }
 
-    glDrawArrays(GL_POINTS, 0, generatedVerticesCount);
+    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
 
-    return DrawGlInfo::kStatusDrew;
+    bool useOffset = !paint->isAntiAlias();
+    return drawVertexBuffer(buffer, paint, useOffset);
 }
 
 status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -2741,48 +2841,6 @@
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
-class TextSetupFunctor: public Functor {
-public:
-    TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate,
-            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
-            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
-            alpha(alpha), mode(mode), paint(paint) {
-    }
-    ~TextSetupFunctor() { }
-
-    status_t operator ()(int what, void* data) {
-        renderer.setupDraw();
-        renderer.setupDrawTextGamma(paint);
-        renderer.setupDrawDirtyRegionsDisabled();
-        renderer.setupDrawWithTexture(true);
-        renderer.setupDrawAlpha8Color(paint->getColor(), alpha);
-        renderer.setupDrawColorFilter();
-        renderer.setupDrawShader();
-        renderer.setupDrawBlending(true, mode);
-        renderer.setupDrawProgram();
-        renderer.setupDrawModelView(x, y, x, y, pureTranslate, true);
-        // Calling setupDrawTexture with the name 0 will enable the
-        // uv attributes and increase the texture unit count
-        // texture binding will be performed by the font renderer as
-        // needed
-        renderer.setupDrawTexture(0);
-        renderer.setupDrawPureColorUniforms();
-        renderer.setupDrawColorFilterUniforms();
-        renderer.setupDrawShaderUniforms(pureTranslate);
-        renderer.setupDrawTextGammaUniforms();
-
-        return NO_ERROR;
-    }
-
-    OpenGLRenderer& renderer;
-    float x;
-    float y;
-    bool pureTranslate;
-    int alpha;
-    SkXfermode::Mode mode;
-    SkPaint* paint;
-};
-
 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
@@ -2794,6 +2852,8 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    mCaches.enableScissor();
+
     float x = 0.0f;
     float y = 0.0f;
     const bool pureTranslate = currentTransform().isPureTranslate();
@@ -2826,7 +2886,7 @@
 
     const bool hasActiveLayer = hasLayer();
 
-    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
+    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
             positions, hasActiveLayer ? &bounds : NULL, &functor)) {
         if (hasActiveLayer) {
@@ -2856,36 +2916,17 @@
     return fontTransform;
 }
 
-status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
-        float x, float y, const float* positions, SkPaint* paint, float length,
+status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
+        const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds,
         DrawOpMode drawOpMode) {
 
-    if (drawOpMode == kDrawOpMode_Immediate &&
-            (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint))) {
-        return DrawGlInfo::kStatusDone;
-    }
-
-    if (length < 0.0f) length = paint->measureText(text, bytesCount);
-    switch (paint->getTextAlign()) {
-        case SkPaint::kCenter_Align:
-            x -= length / 2.0f;
-            break;
-        case SkPaint::kRight_Align:
-            x -= length;
-            break;
-        default:
-            break;
-    }
-
-    SkPaint::FontMetrics metrics;
-    paint->getFontMetrics(&metrics, 0.0f);
     if (drawOpMode == kDrawOpMode_Immediate) {
-        if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
+        // The checks for corner-case ignorable text and quick rejection is only done for immediate
+        // drawing as ops from DeferredDisplayList are already filtered for these
+        if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint) ||
+                quickReject(bounds)) {
             return DrawGlInfo::kStatusDone;
         }
-    } else {
-        // merged draw operations don't need scissor, but clip should still be valid
-        mCaches.setScissorEnabled(mScissorOptimizationDisabled);
     }
 
     const float oldX = x;
@@ -2933,10 +2974,10 @@
 
     // TODO: Implement better clipping for scaled/rotated text
     const Rect* clip = !pureTranslate ? NULL : mSnapshot->clipRect;
-    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
+    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
-    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
+    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
 
     // don't call issuedrawcommand, do it at end of batch
     bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
@@ -2944,20 +2985,20 @@
         SkPaint paintCopy(*paint);
         paintCopy.setTextAlign(SkPaint::kLeft_Align);
         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
+                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
     } else {
         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
+                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
     }
 
     if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
         if (!pureTranslate) {
-            transform.mapRect(bounds);
+            transform.mapRect(layerBounds);
         }
-        dirtyLayerUnchecked(bounds, getRegion());
+        dirtyLayerUnchecked(layerBounds, getRegion());
     }
 
-    drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
+    drawTextDecorations(text, bytesCount, totalAdvance, oldX, oldY, paint);
 
     return DrawGlInfo::kStatusDrew;
 }
@@ -2968,6 +3009,9 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
+    mCaches.enableScissor();
+
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, mat4::identity());
     fontRenderer.setTextureFiltering(true);
@@ -2975,26 +3019,7 @@
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
-
-    setupDraw();
-    setupDrawTextGamma(paint);
-    setupDrawDirtyRegionsDisabled();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(true, mode);
-    setupDrawProgram();
-    setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
-    // Calling setupDrawTexture with the name 0 will enable the
-    // uv attributes and increase the texture unit count
-    // texture binding will be performed by the font renderer as
-    // needed
-    setupDrawTexture(0);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms(false);
-    setupDrawTextGammaUniforms();
+    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
 
     const Rect* clip = &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
@@ -3002,7 +3027,7 @@
     const bool hasActiveLayer = hasLayer();
 
     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
-            hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) {
+            hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
         if (hasActiveLayer) {
             currentTransform().mapRect(bounds);
             dirtyLayerUnchecked(bounds, getRegion());
@@ -3043,10 +3068,9 @@
         }
     }
 
-    Rect transformed;
-    Rect clip;
+    bool clipRequired = false;
     const bool rejected = quickRejectNoScissor(x, y,
-            x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
+            x + layer->layer.getWidth(), y + layer->layer.getHeight(), false, &clipRequired);
 
     if (rejected) {
         if (transform && !transform->isIdentity()) {
@@ -3057,7 +3081,7 @@
 
     updateLayer(layer, true);
 
-    mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed));
+    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
     mCaches.activeTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
@@ -3090,13 +3114,22 @@
                 setupDrawModelViewTranslate(x, y,
                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
             }
-            setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
 
-            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
-                    glDrawElements(GL_TRIANGLES, layer->meshElementCount,
-                            GL_UNSIGNED_SHORT, layer->meshIndices));
+            TextureVertex* mesh = &layer->mesh[0];
+            GLsizei elementsCount = layer->meshElementCount;
 
-            finishDrawTexture();
+            while (elementsCount > 0) {
+                GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+
+                setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
+                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
+
+                elementsCount -= drawCount;
+                // Though there are 4 vertices in a quad, we use 6 indices per
+                // quad to draw with GL_TRIANGLES
+                mesh += (drawCount / 6) * 4;
+            }
 
 #if DEBUG_LAYERS_AS_REGIONS
             drawRegionRects(layer->region);
@@ -3131,7 +3164,7 @@
 void OpenGLRenderer::setupShader(SkiaShader* shader) {
     mDrawModifiers.mShader = shader;
     if (mDrawModifiers.mShader) {
-        mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
+        mDrawModifiers.mShader->setCaches(mCaches);
     }
 }
 
@@ -3199,6 +3232,14 @@
 // Drawing implementation
 ///////////////////////////////////////////////////////////////////////////////
 
+Texture* OpenGLRenderer::getTexture(SkBitmap* bitmap) {
+    Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
+    if (!texture) {
+        return mCaches.textureCache.get(bitmap);
+    }
+    return texture;
+}
+
 void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
         float x, float y, SkPaint* paint) {
     if (quickReject(x, y, x + texture->width, y + texture->height)) {
@@ -3224,8 +3265,6 @@
     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-
-    finishDrawTexture();
 }
 
 // Same values used by Skia
@@ -3233,17 +3272,12 @@
 #define kStdUnderline_Offset    (1.0f / 9.0f)
 #define kStdUnderline_Thickness (1.0f / 18.0f)
 
-void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
+void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float underlineWidth,
         float x, float y, SkPaint* paint) {
     // Handle underline and strike-through
     uint32_t flags = paint->getFlags();
     if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
         SkPaint paintCopy(*paint);
-        float underlineWidth = length;
-        // If length is > 0.0f, we already measured the text for the text alignment
-        if (length <= 0.0f) {
-            underlineWidth = paintCopy.measureText(text, bytesCount);
-        }
 
         if (CC_LIKELY(underlineWidth > 0.0f)) {
             const float textSize = paintCopy.getTextSize();
@@ -3309,8 +3343,7 @@
     float right = FLT_MIN;
     float bottom = FLT_MIN;
 
-    int vertexCount = 0;
-    Vertex mesh[count * 6];
+    Vertex mesh[count];
     Vertex* vertex = mesh;
 
     for (int index = 0; index < count; index += 4) {
@@ -3319,15 +3352,11 @@
         float r = rects[index + 2];
         float b = rects[index + 3];
 
-        Vertex::set(vertex++, l, b);
         Vertex::set(vertex++, l, t);
         Vertex::set(vertex++, r, t);
         Vertex::set(vertex++, l, b);
-        Vertex::set(vertex++, r, t);
         Vertex::set(vertex++, r, b);
 
-        vertexCount += 6;
-
         left = fminf(left, l);
         top = fminf(top, t);
         right = fmaxf(right, r);
@@ -3350,13 +3379,12 @@
     setupDrawColorUniforms();
     setupDrawShaderUniforms();
     setupDrawColorFilterUniforms();
-    setupDrawVertices((GLvoid*) &mesh[0].position[0]);
 
     if (dirty && hasLayer()) {
         dirtyLayer(left, top, right, bottom, currentTransform());
     }
 
-    glDrawArrays(GL_TRIANGLES, 0, vertexCount);
+    drawIndexedQuads(&mesh[0], count / 4);
 
     return DrawGlInfo::kStatusDrew;
 }
@@ -3392,19 +3420,35 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
+    GLvoid* vertices = (GLvoid*) NULL;
+    GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
+
+    if (texture->uvMapper) {
+        vertices = &mMeshVertices[0].position[0];
+        texCoords = &mMeshVertices[0].texture[0];
+
+        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
+        texture->uvMapper->map(uvs);
+
+        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
+    }
+
     if (CC_LIKELY(currentTransform().isPureTranslate())) {
         const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
         const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
 
         texture->setFilter(GL_NEAREST, true);
         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-                alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL,
-                (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true);
+                alpha / 255.0f, mode, texture->blend, vertices, texCoords,
+                GL_TRIANGLE_STRIP, gMeshCount, false, true);
     } else {
         texture->setFilter(FILTER(paint), true);
         drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
-                texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
-                GL_TRIANGLE_STRIP, gMeshCount);
+                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
+    }
+
+    if (texture->uvMapper) {
+        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     }
 }
 
@@ -3437,8 +3481,31 @@
     setupDrawMesh(vertices, texCoords, vbo);
 
     glDrawArrays(drawMode, 0, elementsCount);
+}
 
-    finishDrawTexture();
+void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
+        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
+        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
+        bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
+
+    setupDraw();
+    setupDrawWithTexture();
+    setupDrawColor(alpha, alpha, alpha, alpha);
+    setupDrawColorFilter();
+    setupDrawBlending(blend, mode, swapSrcDst);
+    setupDrawProgram();
+    if (!dirty) setupDrawDirtyRegionsDisabled();
+    if (!ignoreScale) {
+        setupDrawModelView(left, top, right, bottom, ignoreTransform);
+    } else {
+        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
+    }
+    setupDrawTexture(texture);
+    setupDrawPureColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawMeshIndices(vertices, texCoords, vbo);
+
+    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
 }
 
 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
@@ -3468,12 +3535,23 @@
     setupDrawMesh(vertices, texCoords);
 
     glDrawArrays(drawMode, 0, elementsCount);
-
-    finishDrawTexture();
 }
 
 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
         ProgramDescription& description, bool swapSrcDst) {
+    if (mCountOverdraw) {
+        if (!mCaches.blend) glEnable(GL_BLEND);
+        if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
+            glBlendFunc(GL_ONE, GL_ONE);
+        }
+
+        mCaches.blend = true;
+        mCaches.lastSrcMode = GL_ONE;
+        mCaches.lastDstMode = GL_ONE;
+
+        return;
+    }
+
     blend = blend || mode != SkXfermode::kSrcOver_Mode;
 
     if (blend) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index a0ad888..9afb7ad 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -34,6 +34,8 @@
 
 #include <cutils/compiler.h>
 
+#include <androidfw/ResourceTypes.h>
+
 #include "Debug.h"
 #include "Extensions.h"
 #include "Matrix.h"
@@ -43,12 +45,21 @@
 #include "Vertex.h"
 #include "SkiaShader.h"
 #include "SkiaColorFilter.h"
+#include "UvMapper.h"
 #include "Caches.h"
 
 namespace android {
 namespace uirenderer {
 
 struct DrawModifiers {
+    DrawModifiers() {
+        reset();
+    }
+
+    void reset() {
+        memset(this, 0, sizeof(DrawModifiers));
+    }
+
     SkiaShader* mShader;
     SkiaColorFilter* mColorFilter;
     float mOverrideLayerAlpha;
@@ -77,21 +88,21 @@
     kDrawOpMode_Flush
 };
 
-struct DeferredDisplayState {
-    Rect mBounds; // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped.
-
-    // the below are set and used by the OpenGLRenderer at record and deferred playback
-    bool mClipValid;
-    Rect mClip;
-    mat4 mMatrix;
-    DrawModifiers mDrawModifiers;
-    float mAlpha;
+enum ClipSideFlags {
+    kClipSide_None = 0x0,
+    kClipSide_Left = 0x1,
+    kClipSide_Top = 0x2,
+    kClipSide_Right = 0x4,
+    kClipSide_Bottom = 0x8,
+    kClipSide_Full = 0xF,
+    kClipSide_ConservativeFull = 0x1F
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
 
+class DeferredDisplayState;
 class DisplayList;
 class TextSetupFunctor;
 class VertexBuffer;
@@ -188,13 +199,23 @@
      */
     virtual void resume();
 
+    ANDROID_API void setCountOverdrawEnabled(bool enabled) {
+        mCountOverdraw = enabled;
+    }
+
+    ANDROID_API float getOverdraw() {
+        return mCountOverdraw ? mOverdraw : 0.0f;
+    }
+
     ANDROID_API status_t invokeFunctors(Rect& dirty);
     ANDROID_API void detachFunctor(Functor* functor);
     ANDROID_API void attachFunctor(Functor* functor);
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
     ANDROID_API void pushLayerUpdate(Layer* layer);
+    ANDROID_API void cancelLayerUpdate(Layer* layer);
     ANDROID_API void clearLayerUpdates();
+    ANDROID_API void flushLayerUpdates();
 
     ANDROID_API int getSaveCount() const;
     virtual int save(int flags);
@@ -228,8 +249,32 @@
     virtual void concatMatrix(SkMatrix* matrix);
 
     ANDROID_API const Rect& getClipBounds();
-    ANDROID_API bool quickReject(float left, float top, float right, float bottom);
-    bool quickRejectNoScissor(float left, float top, float right, float bottom);
+
+    /**
+     * Performs a quick reject but adjust the bounds to account for stroke width if necessary,
+     * and handling snapOut for AA geometry.
+     */
+    bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
+
+    /**
+     * Returns false and sets scissor based upon bounds if drawing won't be clipped out
+     */
+    bool quickReject(float left, float top, float right, float bottom, bool snapOut = false);
+    bool quickReject(const Rect& bounds) {
+        return quickReject(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
+    /**
+     * Same as quickReject, without the scissor, instead returning clipRequired through pointer.
+     * clipRequired will be only set if not rejected
+     */
+    ANDROID_API bool quickRejectNoScissor(float left, float top, float right, float bottom,
+            bool snapOut = false, bool* clipRequired = NULL);
+    bool quickRejectNoScissor(const Rect& bounds, bool* clipRequired = NULL) {
+        return quickRejectNoScissor(bounds.left, bounds.top, bounds.right, bounds.bottom,
+                clipRequired);
+    }
+
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
     virtual bool clipPath(SkPath* path, SkRegion::Op op);
     virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
@@ -239,8 +284,8 @@
     virtual void outputDisplayList(DisplayList* displayList);
     virtual status_t drawLayer(Layer* layer, float x, float y);
     virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
-    status_t drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
-            const Rect& bounds, SkPaint* paint);
+    status_t drawBitmaps(SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
+            TextureVertex* vertices, bool pureTranslate, const Rect& bounds, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
@@ -248,12 +293,12 @@
     virtual status_t drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual status_t drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
             float* vertices, int* colors, SkPaint* paint);
-    virtual status_t drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+    status_t drawPatches(SkBitmap* bitmap, AssetAtlas::Entry* entry,
+            TextureVertex* vertices, uint32_t indexCount, SkPaint* paint);
+    virtual status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
             float left, float top, float right, float bottom, SkPaint* paint);
-    status_t drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode);
+    status_t drawPatch(SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
+            float left, float top, float right, float bottom, SkPaint* paint);
     virtual status_t drawColor(int color, SkXfermode::Mode mode);
     virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint);
     virtual status_t drawRoundRect(float left, float top, float right, float bottom,
@@ -270,7 +315,7 @@
     virtual status_t drawPosText(const char* text, int bytesCount, int count,
             const float* positions, SkPaint* paint);
     virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, SkPaint* paint, float length = -1.0f,
+            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds,
             DrawOpMode drawOpMode = kDrawOpMode_Immediate);
     virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
 
@@ -291,9 +336,15 @@
 
     SkPaint* filterPaint(SkPaint* paint);
 
+    /**
+     * Store the current display state (most importantly, the current clip and transform), and
+     * additionally map the state's bounds from local to window coordinates.
+     *
+     * Returns true if quick-rejected
+     */
     bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
     void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false);
-    void setFullScreenClip();
+    void setupMergedMultiDraw(const Rect* clipRect);
 
     const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
     void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
@@ -311,6 +362,9 @@
         return mSnapshot->clipRegion->isEmpty();
     }
 
+    int getViewportWidth() { return getSnapshot()->viewport.getWidth(); }
+    int getViewportHeight() { return getSnapshot()->viewport.getHeight(); }
+
     /**
      * Scales the alpha on the current snapshot. This alpha value will be modulated
      * with other alpha values when drawing primitives.
@@ -356,7 +410,7 @@
         return getXfermode(paint->getXfermode());
     }
 
-    static inline int getAlphaDirect(SkPaint* paint) {
+    static inline int getAlphaDirect(const SkPaint* paint) {
         if (!paint) return 255;
         return paint->getAlpha();
     }
@@ -579,18 +633,6 @@
     void setStencilFromClip();
 
     /**
-     * Performs a quick reject but does not affect the scissor. Returns
-     * the transformed rect to test and the current clip.
-     */
-    bool quickRejectNoScissor(float left, float top, float right, float bottom,
-            Rect& transformed, Rect& clip);
-
-    /**
-     * Performs a quick reject but adjust the bounds to account for stroke width if necessary
-     */
-    bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
-
-    /**
      * Given the local bounds of the layer, calculates ...
      */
     void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer);
@@ -798,22 +840,35 @@
             bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
             bool ignoreScale = false, bool dirty = true);
 
+    void drawIndexedTextureMesh(float left, float top, float right, float bottom, GLuint texture,
+            float alpha, SkXfermode::Mode mode, bool blend,
+            GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
+            bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
+            bool ignoreScale = false, bool dirty = true);
+
     void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
             GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool ignoreTransform, bool ignoreScale = false, bool dirty = true);
 
     /**
+     * Draws the specified list of vertices as quads using indexed GL_TRIANGLES.
+     * If the number of vertices to draw exceeds the number of indices we have
+     * pre-allocated, this method will generate several glDrawElements() calls.
+     */
+    void drawIndexedQuads(Vertex* mesh, GLsizei quadsCount);
+
+    /**
      * Draws text underline and strike-through if needed.
      *
      * @param text The text to decor
      * @param bytesCount The number of bytes in the text
-     * @param length The length in pixels of the text, can be <= 0.0f to force a measurement
+     * @param totalAdvance The total advance in pixels, defines underline/strikethrough length
      * @param x The x coordinate where the text will be drawn
      * @param y The y coordinate where the text will be drawn
      * @param paint The paint to draw the text with
      */
-    void drawTextDecorations(const char* text, int bytesCount, float length,
+    void drawTextDecorations(const char* text, int bytesCount, float totalAdvance,
             float x, float y, SkPaint* paint);
 
    /**
@@ -868,7 +923,7 @@
      * prior to calling this method.
      */
     inline void bindTexture(GLuint texture) {
-        glBindTexture(GL_TEXTURE_2D, texture);
+        mCaches.bindTexture(texture);
     }
 
     /**
@@ -876,7 +931,7 @@
      * prior to calling this method.
      */
     inline void bindExternalTexture(GLuint texture) {
-        glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+        mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
     }
 
     /**
@@ -911,7 +966,6 @@
     void setupDrawWithExternalTexture();
     void setupDrawNoTexture();
     void setupDrawAA();
-    void setupDrawPoint(float pointSize);
     void setupDrawColor(int color, int alpha);
     void setupDrawColor(float r, float g, float b, float a);
     void setupDrawAlpha8Color(int color, int alpha);
@@ -929,7 +983,6 @@
             bool ignoreTransform = false, bool ignoreModelView = false);
     void setupDrawModelViewTranslate(float left, float top, float right, float bottom,
             bool ignoreTransform = false);
-    void setupDrawPointUniforms();
     void setupDrawColorUniforms();
     void setupDrawPureColorUniforms();
     void setupDrawShaderIdentityUniforms();
@@ -943,9 +996,8 @@
     void setupDrawTextGammaUniforms();
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors);
-    void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords);
-    void setupDrawVertices(GLvoid* vertices);
-    void finishDrawTexture();
+    void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0);
+    void setupDrawIndexedVertices(GLvoid* vertices);
     void accountForClear(SkXfermode::Mode mode);
 
     bool updateLayer(Layer* layer, bool inFrame);
@@ -973,6 +1025,7 @@
 
     void debugOverdraw(bool enable, bool clear);
     void renderOverdraw();
+    void countOverdraw();
 
     /**
      * Should be invoked every time the glScissor is modified.
@@ -985,6 +1038,17 @@
         return *mSnapshot->transform;
     }
 
+    inline const UvMapper& getMapper(const Texture* texture) {
+        return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;
+    }
+
+    /**
+     * Returns a texture object for the specified bitmap. The texture can
+     * come from the texture cache or an atlas. If this method returns
+     * NULL, the texture could not be found and/or allocated.
+     */
+    Texture* getTexture(SkBitmap* bitmap);
+
     // Dimensions of the drawing surface
     int mWidth, mHeight;
 
@@ -1010,6 +1074,9 @@
     // Used to draw textured quads
     TextureVertex mMeshVertices[4];
 
+    // Default UV mapper
+    const UvMapper mUvMapper;
+
     // shader, filters, and shadow
     DrawModifiers mDrawModifiers;
     SkPaint mFilteredPaint;
@@ -1050,12 +1117,19 @@
     // No-ops start/endTiling when set
     bool mSuppressTiling;
 
+    // If true, this renderer will setup drawing to emulate
+    // an increment stencil buffer in the color buffer
+    bool mCountOverdraw;
+    float mOverdraw;
+
     // Optional name of the renderer
     String8 mName;
 
     friend class DisplayListRenderer;
     friend class Layer;
     friend class TextSetupFunctor;
+    friend class DrawBitmapOp;
+    friend class DrawPatchOp;
 
 }; // class OpenGLRenderer
 
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 45c619e..9b023f9 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -20,9 +20,10 @@
 
 #include <utils/Log.h>
 
-#include "Patch.h"
 #include "Caches.h"
+#include "Patch.h"
 #include "Properties.h"
+#include "UvMapper.h"
 
 namespace android {
 namespace uirenderer {
@@ -31,90 +32,58 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads):
-        mXCount(xCount), mYCount(yCount), mEmptyQuads(emptyQuads) {
-    // Initialized with the maximum number of vertices we will need
-    // 2 triangles per patch, 3 vertices per triangle
-    uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
-    mVertices = new TextureVertex[maxVertices];
-    mAllocatedVerticesCount = 0;
-
-    verticesCount = 0;
-    hasEmptyQuads = emptyQuads > 0;
-
-    mColorKey = 0;
-    mXDivs = new int32_t[mXCount];
-    mYDivs = new int32_t[mYCount];
-
-    PATCH_LOGD("    patch: xCount = %d, yCount = %d, emptyQuads = %d, max vertices = %d",
-            xCount, yCount, emptyQuads, maxVertices);
-
-    glGenBuffers(1, &meshBuffer);
+Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(false) {
 }
 
 Patch::~Patch() {
-    delete[] mVertices;
-    delete[] mXDivs;
-    delete[] mYDivs;
-    glDeleteBuffers(1, &meshBuffer);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Patch management
-///////////////////////////////////////////////////////////////////////////////
-
-void Patch::copy(const int32_t* xDivs, const int32_t* yDivs) {
-    memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t));
-    memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
-}
-
-void Patch::updateColorKey(const uint32_t colorKey) {
-    mColorKey = colorKey;
-}
-
-bool Patch::matches(const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t colorKey, const int8_t emptyQuads) {
-
-    bool matches = true;
-
-    if (mEmptyQuads != emptyQuads) {
-        mEmptyQuads = emptyQuads;
-        hasEmptyQuads = emptyQuads > 0;
-        matches = false;
-    }
-
-    if (mColorKey != colorKey) {
-        updateColorKey(colorKey);
-        matches = false;
-    }
-
-    if (memcmp(mXDivs, xDivs, mXCount * sizeof(int32_t))) {
-        memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t));
-        matches = false;
-    }
-
-    if (memcmp(mYDivs, yDivs, mYCount * sizeof(int32_t))) {
-        memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
-        matches = false;
-    }
-
-    return matches;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Vertices management
 ///////////////////////////////////////////////////////////////////////////////
 
-void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
-        float left, float top, float right, float bottom) {
-    if (hasEmptyQuads) quads.clear();
+uint32_t Patch::getSize() const {
+    return verticesCount * sizeof(TextureVertex);
+}
 
-    // Reset the vertices count here, we will count exactly how many
-    // vertices we actually need when generating the quads
-    verticesCount = 0;
+TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
+        float width, float height, const Res_png_9patch* patch) {
+    UvMapper mapper;
+    return createMesh(bitmapWidth, bitmapHeight, width, height, mapper, patch);
+}
 
-    const uint32_t xStretchCount = (mXCount + 1) >> 1;
-    const uint32_t yStretchCount = (mYCount + 1) >> 1;
+TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
+        float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) {
+    if (vertices) return vertices;
+
+    int8_t emptyQuads = 0;
+    mColors = patch->colors;
+
+    const int8_t numColors = patch->numColors;
+    if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
+        for (int8_t i = 0; i < numColors; i++) {
+            if (mColors[i] == 0x0) {
+                emptyQuads++;
+            }
+        }
+    }
+
+    hasEmptyQuads = emptyQuads > 0;
+
+    uint32_t xCount = patch->numXDivs;
+    uint32_t yCount = patch->numYDivs;
+
+    uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4;
+    if (maxVertices == 0) return NULL;
+
+    TextureVertex* tempVertices = new TextureVertex[maxVertices];
+    TextureVertex* vertex = tempVertices;
+
+    const int32_t* xDivs = patch->xDivs;
+    const int32_t* yDivs = patch->yDivs;
+
+    const uint32_t xStretchCount = (xCount + 1) >> 1;
+    const uint32_t yStretchCount = (yCount + 1) >> 1;
 
     float stretchX = 0.0f;
     float stretchY = 0.0f;
@@ -124,29 +93,28 @@
 
     if (xStretchCount > 0) {
         uint32_t stretchSize = 0;
-        for (uint32_t i = 1; i < mXCount; i += 2) {
-            stretchSize += mXDivs[i] - mXDivs[i - 1];
+        for (uint32_t i = 1; i < xCount; i += 2) {
+            stretchSize += xDivs[i] - xDivs[i - 1];
         }
         const float xStretchTex = stretchSize;
         const float fixed = bitmapWidth - stretchSize;
-        const float xStretch = fmaxf(right - left - fixed, 0.0f);
+        const float xStretch = fmaxf(width - fixed, 0.0f);
         stretchX = xStretch / xStretchTex;
-        rescaleX = fixed == 0.0f ? 0.0f : fminf(fmaxf(right - left, 0.0f) / fixed, 1.0f);
+        rescaleX = fixed == 0.0f ? 0.0f : fminf(fmaxf(width, 0.0f) / fixed, 1.0f);
     }
 
     if (yStretchCount > 0) {
         uint32_t stretchSize = 0;
-        for (uint32_t i = 1; i < mYCount; i += 2) {
-            stretchSize += mYDivs[i] - mYDivs[i - 1];
+        for (uint32_t i = 1; i < yCount; i += 2) {
+            stretchSize += yDivs[i] - yDivs[i - 1];
         }
         const float yStretchTex = stretchSize;
         const float fixed = bitmapHeight - stretchSize;
-        const float yStretch = fmaxf(bottom - top - fixed, 0.0f);
+        const float yStretch = fmaxf(height - fixed, 0.0f);
         stretchY = yStretch / yStretchTex;
-        rescaleY = fixed == 0.0f ? 0.0f : fminf(fmaxf(bottom - top, 0.0f) / fixed, 1.0f);
+        rescaleY = fixed == 0.0f ? 0.0f : fminf(fmaxf(height, 0.0f) / fixed, 1.0f);
     }
 
-    TextureVertex* vertex = mVertices;
     uint32_t quadCount = 0;
 
     float previousStepY = 0.0f;
@@ -155,8 +123,10 @@
     float y2 = 0.0f;
     float v1 = 0.0f;
 
-    for (uint32_t i = 0; i < mYCount; i++) {
-        float stepY = mYDivs[i];
+    mUvMapper = mapper;
+
+    for (uint32_t i = 0; i < yCount; i++) {
+        float stepY = yDivs[i];
         const float segment = stepY - previousStepY;
 
         if (i & 1) {
@@ -170,15 +140,8 @@
         v1 += vOffset / bitmapHeight;
 
         if (stepY > 0.0f) {
-#if DEBUG_EXPLODE_PATCHES
-            y1 += i * EXPLODE_GAP;
-            y2 += i * EXPLODE_GAP;
-#endif
-            generateRow(vertex, y1, y2, v1, v2, stretchX, rescaleX, right - left,
-                    bitmapWidth, quadCount);
-#if DEBUG_EXPLODE_PATCHES
-            y2 -= i * EXPLODE_GAP;
-#endif
+            generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX,
+                    width, bitmapWidth, quadCount);
         }
 
         y1 = y2;
@@ -188,34 +151,25 @@
     }
 
     if (previousStepY != bitmapHeight) {
-        y2 = bottom - top;
-#if DEBUG_EXPLODE_PATCHES
-        y1 += mYCount * EXPLODE_GAP;
-        y2 += mYCount * EXPLODE_GAP;
-#endif
-        generateRow(vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, right - left,
-                bitmapWidth, quadCount);
+        y2 = height;
+        generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX,
+                width, bitmapWidth, quadCount);
     }
 
-    if (verticesCount > 0) {
-        Caches& caches = Caches::getInstance();
-        caches.bindMeshBuffer(meshBuffer);
-        if (mAllocatedVerticesCount < verticesCount) {
-            glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
-                    mVertices, GL_DYNAMIC_DRAW);
-            mAllocatedVerticesCount = verticesCount;
-        } else {
-            glBufferSubData(GL_ARRAY_BUFFER, 0,
-                    sizeof(TextureVertex) * verticesCount, mVertices);
-        }
-        caches.resetVertexPointers();
+    if (verticesCount == maxVertices) {
+        vertices = tempVertices;
+    } else {
+        vertices = new TextureVertex[verticesCount];
+        memcpy(vertices, tempVertices, verticesCount * sizeof(TextureVertex));
+        delete[] tempVertices;
     }
 
-    PATCH_LOGD("    patch: new vertices count = %d", verticesCount);
+    return vertices;
 }
 
-void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
-        float stretchX, float rescaleX, float width, float bitmapWidth, uint32_t& quadCount) {
+void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
+        float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
+        float width, float bitmapWidth, uint32_t& quadCount) {
     float previousStepX = 0.0f;
 
     float x1 = 0.0f;
@@ -223,8 +177,8 @@
     float u1 = 0.0f;
 
     // Generate the row quad by quad
-    for (uint32_t i = 0; i < mXCount; i++) {
-        float stepX = mXDivs[i];
+    for (uint32_t i = 0; i < xCount; i++) {
+        float stepX = xDivs[i];
         const float segment = stepX - previousStepX;
 
         if (i & 1) {
@@ -238,14 +192,7 @@
         u1 += uOffset / bitmapWidth;
 
         if (stepX > 0.0f) {
-#if DEBUG_EXPLODE_PATCHES
-            x1 += i * EXPLODE_GAP;
-            x2 += i * EXPLODE_GAP;
-#endif
             generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
-#if DEBUG_EXPLODE_PATCHES
-            x2 -= i * EXPLODE_GAP;
-#endif
         }
 
         x1 = x2;
@@ -256,10 +203,6 @@
 
     if (previousStepX != bitmapWidth) {
         x2 = width;
-#if DEBUG_EXPLODE_PATCHES
-        x1 += mXCount * EXPLODE_GAP;
-        x2 += mXCount * EXPLODE_GAP;
-#endif
         generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount);
     }
 }
@@ -275,11 +218,11 @@
     if (y2 < 0.0f) y2 = 0.0f;
 
     // Skip degenerate and transparent (empty) quads
-    if (((mColorKey >> oldQuadCount) & 0x1) || x1 >= x2 || y1 >= y2) {
+    if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) {
 #if DEBUG_PATCHES_EMPTY_VERTICES
         PATCH_LOGD("    quad %d (empty)", oldQuadCount);
-        PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.4f, %.4f", x1, y1, u1, v1);
-        PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.4f, %.4f", x2, y2, u2, v2);
+        PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1);
+        PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2);
 #endif
         return;
     }
@@ -290,23 +233,20 @@
         quads.add(bounds);
     }
 
-    // Left triangle
+    mUvMapper.map(u1, v1, u2, v2);
+
     TextureVertex::set(vertex++, x1, y1, u1, v1);
     TextureVertex::set(vertex++, x2, y1, u2, v1);
     TextureVertex::set(vertex++, x1, y2, u1, v2);
-
-    // Right triangle
-    TextureVertex::set(vertex++, x1, y2, u1, v2);
-    TextureVertex::set(vertex++, x2, y1, u2, v1);
     TextureVertex::set(vertex++, x2, y2, u2, v2);
 
-    // A quad is made of 2 triangles, 6 vertices
-    verticesCount += 6;
+    verticesCount += 4;
+    indexCount += 6;
 
 #if DEBUG_PATCHES_VERTICES
     PATCH_LOGD("    quad %d", oldQuadCount);
-    PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.4f, %.4f", x1, y1, u1, v1);
-    PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.4f, %.4f", x2, y2, u2, v2);
+    PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1);
+    PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2);
 #endif
 }
 
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index ee7bf70..763a785 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -23,62 +23,51 @@
 
 #include <utils/Vector.h>
 
+#include <androidfw/ResourceTypes.h>
+
 #include "Rect.h"
+#include "UvMapper.h"
 #include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-#define EXPLODE_GAP 4
-
-///////////////////////////////////////////////////////////////////////////////
 // 9-patch structures
 ///////////////////////////////////////////////////////////////////////////////
 
-/**
- * An OpenGL patch. This contains an array of vertices and an array of
- * indices to render the vertices.
- */
 struct Patch {
-    Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads);
+    Patch();
     ~Patch();
 
-    void updateVertices(const float bitmapWidth, const float bitmapHeight,
-            float left, float top, float right, float bottom);
+    /**
+     * Returns the size of this patch's mesh in bytes.
+     */
+    uint32_t getSize() const;
 
-    void updateColorKey(const uint32_t colorKey);
-    void copy(const int32_t* xDivs, const int32_t* yDivs);
-    bool matches(const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t colorKey, const int8_t emptyQuads);
-
-    GLuint meshBuffer;
+    TextureVertex* vertices;
     uint32_t verticesCount;
+    uint32_t indexCount;
     bool hasEmptyQuads;
     Vector<Rect> quads;
 
+    GLintptr offset;
+    GLintptr textureOffset;
+
+    TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight,
+            float width, float height, const Res_png_9patch* patch);
+    TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight,
+            float width, float height, const UvMapper& mapper, const Res_png_9patch* patch);
+
 private:
-    TextureVertex* mVertices;
-    uint32_t mAllocatedVerticesCount;
-
-    int32_t* mXDivs;
-    int32_t* mYDivs;
-    uint32_t mColorKey;
-
-    uint32_t mXCount;
-    uint32_t mYCount;
-    int8_t mEmptyQuads;
-
-    void generateRow(TextureVertex*& vertex, float y1, float y2,
-            float v1, float v2, float stretchX, float rescaleX,
+    void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
+            float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
             float width, float bitmapWidth, uint32_t& quadCount);
-    void generateQuad(TextureVertex*& vertex,
-            float x1, float y1, float x2, float y2,
-            float u1, float v1, float u2, float v2,
-            uint32_t& quadCount);
+    void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+            float u1, float v1, float u2, float v2, uint32_t& quadCount);
+
+    uint32_t* mColors;
+    UvMapper mUvMapper;
 }; // struct Patch
 
 }; // namespace uirenderer
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 62e38d3..dc0d98c 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -16,8 +16,10 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
+#include <utils/JenkinsHash.h>
 #include <utils/Log.h>
 
+#include "Caches.h"
 #include "PatchCache.h"
 #include "Properties.h"
 
@@ -28,111 +30,243 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-PatchCache::PatchCache(): mMaxEntries(DEFAULT_PATCH_CACHE_SIZE) {
-}
-
-PatchCache::PatchCache(uint32_t maxEntries): mMaxEntries(maxEntries) {
+PatchCache::PatchCache():
+        mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
+        mMeshBuffer(0), mFreeBlocks(NULL), mGenerationId(0) {
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) {
+        INIT_LOGD("  Setting patch cache size to %skB", property);
+        mMaxSize = KB(atoi(property));
+    } else {
+        INIT_LOGD("  Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE);
+        mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE);
+    }
 }
 
 PatchCache::~PatchCache() {
     clear();
 }
 
+void PatchCache::init(Caches& caches) {
+    bool created = false;
+    if (!mMeshBuffer) {
+        glGenBuffers(1, &mMeshBuffer);
+        created = true;
+    }
+
+    caches.bindMeshBuffer(mMeshBuffer);
+    caches.resetVertexPointers();
+
+    if (created) {
+        createVertexBuffer();
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Caching
 ///////////////////////////////////////////////////////////////////////////////
 
-int PatchCache::PatchDescription::compare(
-        const PatchCache::PatchDescription& lhs, const PatchCache::PatchDescription& rhs) {
-    int deltaInt = lhs.bitmapWidth - rhs.bitmapWidth;
-    if (deltaInt != 0) return deltaInt;
+hash_t PatchCache::PatchDescription::hash() const {
+    uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch));
+    hash = JenkinsHashMix(hash, mBitmapWidth);
+    hash = JenkinsHashMix(hash, mBitmapHeight);
+    hash = JenkinsHashMix(hash, mPixelWidth);
+    hash = JenkinsHashMix(hash, mPixelHeight);
+    return JenkinsHashWhiten(hash);
+}
 
-    deltaInt = lhs.bitmapHeight - rhs.bitmapHeight;
-    if (deltaInt != 0) return deltaInt;
-
-    if (lhs.pixelWidth < rhs.pixelWidth) return -1;
-    if (lhs.pixelWidth > rhs.pixelWidth) return +1;
-
-    if (lhs.pixelHeight < rhs.pixelHeight) return -1;
-    if (lhs.pixelHeight > rhs.pixelHeight) return +1;
-
-    deltaInt = lhs.xCount - rhs.xCount;
-    if (deltaInt != 0) return deltaInt;
-
-    deltaInt = lhs.yCount - rhs.yCount;
-    if (deltaInt != 0) return deltaInt;
-
-    deltaInt = lhs.emptyCount - rhs.emptyCount;
-    if (deltaInt != 0) return deltaInt;
-
-    deltaInt = lhs.colorKey - rhs.colorKey;
-    if (deltaInt != 0) return deltaInt;
-
-    return 0;
+int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
+            const PatchCache::PatchDescription& rhs) {
+    return memcmp(&lhs, &rhs, sizeof(PatchDescription));
 }
 
 void PatchCache::clear() {
-    size_t count = mCache.size();
-    for (size_t i = 0; i < count; i++) {
-        delete mCache.valueAt(i);
+    clearCache();
+
+    if (mMeshBuffer) {
+        Caches::getInstance().unbindMeshBuffer();
+        glDeleteBuffers(1, &mMeshBuffer);
+        mMeshBuffer = 0;
+        mSize = 0;
     }
-    mCache.clear();
 }
 
-Patch* PatchCache::get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
-        const float pixelWidth, const float pixelHeight,
-        const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors,
-        const uint32_t width, const uint32_t height, const int8_t numColors) {
+void PatchCache::clearCache() {
+    LruCache<PatchDescription, Patch*>::Iterator i(mCache);
+    while (i.next()) {
+        delete i.value();
+    }
+    mCache.clear();
 
-    int8_t transparentQuads = 0;
-    uint32_t colorKey = 0;
+    BufferBlock* block = mFreeBlocks;
+    while (block) {
+        BufferBlock* next = block->next;
+        delete block;
+        block = next;
+    }
+    mFreeBlocks = NULL;
+}
 
-    if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
-        for (int8_t i = 0; i < numColors; i++) {
-            if (colors[i] == 0x0) {
-                transparentQuads++;
-                colorKey |= 0x1 << i;
-            }
+void PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch) {
+    LruCache<PatchDescription, Patch*>::Iterator i(mCache);
+    while (i.next()) {
+        const PatchDescription& key = i.key();
+        if (key.getPatch() == patch) {
+            patchesToRemove.push(patch_pair_t(&key, i.value()));
         }
     }
+}
 
-    // If the 9patch is made of only transparent quads
-    if (transparentQuads == int8_t((width + 1) * (height + 1))) {
-        return NULL;
+void PatchCache::removeDeferred(Res_png_9patch* patch) {
+    Mutex::Autolock _l(mLock);
+    mGarbage.push(patch);
+}
+
+void PatchCache::clearGarbage() {
+    Vector<patch_pair_t> patchesToRemove;
+
+    { // scope for the mutex
+        Mutex::Autolock _l(mLock);
+        size_t count = mGarbage.size();
+        for (size_t i = 0; i < count; i++) {
+            remove(patchesToRemove, mGarbage[i]);
+        }
+        mGarbage.clear();
     }
 
-    const PatchDescription description(bitmapWidth, bitmapHeight,
-            pixelWidth, pixelHeight, width, height, transparentQuads, colorKey);
+    // TODO: We could sort patchesToRemove by offset to merge
+    // adjacent free blocks
+    for (size_t i = 0; i < patchesToRemove.size(); i++) {
+        const patch_pair_t& pair = patchesToRemove[i];
 
-    ssize_t index = mCache.indexOfKey(description);
-    Patch* mesh = NULL;
-    if (index >= 0) {
-        mesh = mCache.valueAt(index);
+        // Add a new free block to the list
+        const Patch* patch = pair.getSecond();
+        BufferBlock* block = new BufferBlock(patch->offset, patch->getSize());
+        block->next = mFreeBlocks;
+        mFreeBlocks = block;
+
+        mSize -= patch->getSize();
+
+        mCache.remove(*pair.getFirst());
     }
 
+#if DEBUG_PATCHES
+    if (patchesToRemove.size() > 0) {
+        dumpFreeBlocks("Removed garbage");
+    }
+#endif
+}
+
+void PatchCache::createVertexBuffer() {
+    glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
+    mSize = 0;
+    mFreeBlocks = new BufferBlock(0, mMaxSize);
+    mGenerationId++;
+}
+
+/**
+ * Sets the mesh's offsets and copies its associated vertices into
+ * the mesh buffer (VBO).
+ */
+void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
+    // This call ensures the VBO exists and that it is bound
+    init(Caches::getInstance());
+
+    // If we're running out of space, let's clear the entire cache
+    uint32_t size = newMesh->getSize();
+    if (mSize + size > mMaxSize) {
+        clearCache();
+        createVertexBuffer();
+    }
+
+    // Find a block where we can fit the mesh
+    BufferBlock* previous = NULL;
+    BufferBlock* block = mFreeBlocks;
+    while (block) {
+        // The mesh fits
+        if (block->size >= size) {
+            break;
+        }
+        previous = block;
+        block = block->next;
+    }
+
+    // We have enough space left in the buffer, but it's
+    // too fragmented, let's clear the cache
+    if (!block) {
+        clearCache();
+        createVertexBuffer();
+        previous = NULL;
+        block = mFreeBlocks;
+    }
+
+    // Copy the 9patch mesh in the VBO
+    newMesh->offset = (GLintptr) (block->offset);
+    newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
+    glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
+
+    // Remove the block since we've used it entirely
+    if (block->size == size) {
+        if (previous) {
+            previous->next = block->next;
+        } else {
+            mFreeBlocks = block->next;
+        }
+    } else {
+        // Resize the block now that it's occupied
+        block->offset += size;
+        block->size -= size;
+    }
+
+    mSize += size;
+}
+
+const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
+        const uint32_t bitmapWidth, const uint32_t bitmapHeight,
+        const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
+
+    const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
+    const Patch* mesh = mCache.get(description);
+
     if (!mesh) {
-        PATCH_LOGD("New patch mesh "
-                "xCount=%d yCount=%d, w=%.2f h=%.2f, bw=%.2f bh=%.2f",
-                width, height, pixelWidth, pixelHeight, bitmapWidth, bitmapHeight);
+        Patch* newMesh = new Patch();
+        TextureVertex* vertices;
 
-        mesh = new Patch(width, height, transparentQuads);
-        mesh->updateColorKey(colorKey);
-        mesh->copy(xDivs, yDivs);
-        mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight);
-
-        if (mCache.size() >= mMaxEntries) {
-            delete mCache.valueAt(mCache.size() - 1);
-            mCache.removeItemsAt(mCache.size() - 1, 1);
+        if (entry) {
+            // An atlas entry has a UV mapper
+            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
+                    pixelWidth, pixelHeight, entry->uvMapper, patch);
+        } else {
+            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
+                    pixelWidth, pixelHeight, patch);
         }
 
-        mCache.add(description, mesh);
-    } else if (!mesh->matches(xDivs, yDivs, colorKey, transparentQuads)) {
-        PATCH_LOGD("Patch mesh does not match, refreshing vertices");
-        mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight);
+        if (vertices) {
+            setupMesh(newMesh, vertices);
+        }
+
+#if DEBUG_PATCHES
+        dumpFreeBlocks("Adding patch");
+#endif
+
+        mCache.put(description, newMesh);
+        return newMesh;
     }
 
     return mesh;
 }
 
+#if DEBUG_PATCHES
+void PatchCache::dumpFreeBlocks(const char* prefix) {
+    String8 dump;
+    BufferBlock* block = mFreeBlocks;
+    while (block) {
+        dump.appendFormat("->(%d, %d)", block->offset, block->size);
+        block = block->next;
+    }
+    ALOGD("%s: Free blocks%s", prefix, dump.string());
+}
+#endif
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 0822cba..9f2c9a5 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -17,10 +17,16 @@
 #ifndef ANDROID_HWUI_PATCH_CACHE_H
 #define ANDROID_HWUI_PATCH_CACHE_H
 
-#include <utils/KeyedVector.h>
+#include <GLES2/gl2.h>
 
+#include <utils/LruCache.h>
+
+#include <androidfw/ResourceTypes.h>
+
+#include "AssetAtlas.h"
 #include "Debug.h"
 #include "Patch.h"
+#include "utils/Pair.h"
 
 namespace android {
 namespace uirenderer {
@@ -40,45 +46,64 @@
 // Cache
 ///////////////////////////////////////////////////////////////////////////////
 
+class Caches;
+
 class PatchCache {
 public:
     PatchCache();
-    PatchCache(uint32_t maxCapacity);
     ~PatchCache();
+    void init(Caches& caches);
 
-    Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
-            const float pixelWidth, const float pixelHeight,
-            const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors,
-            const uint32_t width, const uint32_t height, const int8_t numColors);
+    const Patch* get(const AssetAtlas::Entry* entry,
+            const uint32_t bitmapWidth, const uint32_t bitmapHeight,
+            const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
     void clear();
 
     uint32_t getSize() const {
-        return mCache.size();
+        return mSize;
     }
 
     uint32_t getMaxSize() const {
-        return mMaxEntries;
+        return mMaxSize;
     }
 
-private:
+    GLuint getMeshBuffer() const {
+        return mMeshBuffer;
+    }
+
+    uint32_t getGenerationId() const {
+        return mGenerationId;
+    }
+
     /**
-     * Description of a patch.
+     * Removes the entries associated with the specified 9-patch. This is meant
+     * to be called from threads that are not the EGL context thread (GC thread
+     * on the VM side for instance.)
      */
+    void removeDeferred(Res_png_9patch* patch);
+
+    /**
+     * Process deferred removals.
+     */
+    void clearGarbage();
+
+
+private:
     struct PatchDescription {
-        PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0),
-                xCount(0), yCount(0), emptyCount(0), colorKey(0) {
+        PatchDescription(): mPatch(NULL), mBitmapWidth(0), mBitmapHeight(0),
+                mPixelWidth(0), mPixelHeight(0) {
         }
 
         PatchDescription(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
-                const float pixelWidth, const float pixelHeight,
-                const uint32_t xCount, const uint32_t yCount,
-                const int8_t emptyCount, const uint32_t colorKey):
-                bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
-                pixelWidth(pixelWidth), pixelHeight(pixelHeight),
-                xCount(xCount), yCount(yCount),
-                emptyCount(emptyCount), colorKey(colorKey) {
+                const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch):
+                mPatch(patch), mBitmapWidth(bitmapWidth), mBitmapHeight(bitmapHeight),
+                mPixelWidth(pixelWidth), mPixelHeight(pixelHeight) {
         }
 
+        hash_t hash() const;
+
+        const Res_png_9patch* getPatch() const { return mPatch; }
+
         static int compare(const PatchDescription& lhs, const PatchDescription& rhs);
 
         bool operator==(const PatchDescription& other) const {
@@ -99,21 +124,63 @@
             return PatchDescription::compare(lhs, rhs);
         }
 
+        friend inline hash_t hash_type(const PatchDescription& entry) {
+            return entry.hash();
+        }
+
     private:
-        uint32_t bitmapWidth;
-        uint32_t bitmapHeight;
-        float pixelWidth;
-        float pixelHeight;
-        uint32_t xCount;
-        uint32_t yCount;
-        int8_t emptyCount;
-        uint32_t colorKey;
+        const Res_png_9patch* mPatch;
+        uint32_t mBitmapWidth;
+        uint32_t mBitmapHeight;
+        float mPixelWidth;
+        float mPixelHeight;
 
     }; // struct PatchDescription
 
-    uint32_t mMaxEntries;
-    KeyedVector<PatchDescription, Patch*> mCache;
+    /**
+     * A buffer block represents an empty range in the mesh buffer
+     * that can be used to store vertices.
+     *
+     * The patch cache maintains a linked-list of buffer blocks
+     * to track available regions of memory in the VBO.
+     */
+    struct BufferBlock {
+        BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(NULL) {
+        }
 
+        uint32_t offset;
+        uint32_t size;
+
+        BufferBlock* next;
+    }; // struct BufferBlock
+
+    typedef Pair<const PatchDescription*, Patch*> patch_pair_t;
+
+    void clearCache();
+    void createVertexBuffer();
+
+    void setupMesh(Patch* newMesh, TextureVertex* vertices);
+
+    void remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch);
+
+#if DEBUG_PATCHES
+    void dumpFreeBlocks(const char* prefix);
+#endif
+
+    uint32_t mMaxSize;
+    uint32_t mSize;
+
+    LruCache<PatchDescription, Patch*> mCache;
+
+    GLuint mMeshBuffer;
+    // First available free block inside the mesh buffer
+    BufferBlock* mFreeBlocks;
+
+    uint32_t mGenerationId;
+
+    // Garbage tracking, required to handle GC events on the VM side
+    Vector<Res_png_9patch*> mGarbage;
+    mutable Mutex mLock;
 }; // class PatchCache
 
 }; // namespace uirenderer
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index fdb10e2..5df6408 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -139,7 +139,7 @@
 
 static PathTexture* createTexture(float left, float top, float offset,
         uint32_t width, uint32_t height, uint32_t id) {
-    PathTexture* texture = new PathTexture();
+    PathTexture* texture = new PathTexture(Caches::getInstance());
     texture->left = left;
     texture->top = top;
     texture->offset = offset;
@@ -214,7 +214,22 @@
 void PathCache::removeTexture(PathTexture* texture) {
     if (texture) {
         const uint32_t size = texture->width * texture->height;
-        mSize -= size;
+
+        // If there is a pending task we must wait for it to return
+        // before attempting our cleanup
+        const sp<Task<SkBitmap*> >& task = texture->task();
+        if (task != NULL) {
+            SkBitmap* bitmap = task->getResult();
+            texture->clearTask();
+        } else {
+            // If there is a pending task, the path was not added
+            // to the cache and the size wasn't increased
+            if (size > mSize) {
+                ALOGE("Removing path texture of size %d will leave "
+                        "the cache in an inconsistent state", size);
+            }
+            mSize -= size;
+        }
 
         PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
                 texture->id, size, mSize);
@@ -223,7 +238,7 @@
         }
 
         if (texture->id) {
-            glDeleteTextures(1, &texture->id);
+            Caches::getInstance().deleteTexture(texture->id);
         }
         delete texture;
     }
@@ -283,6 +298,11 @@
             mCache.put(entry, texture);
         }
     } else {
+        // It's okay to add a texture that's bigger than the cache since
+        // we'll trim the cache later when addToCache is set to false
+        if (!addToCache) {
+            mSize += size;
+        }
         texture->cleanup = true;
     }
 }
@@ -300,7 +320,7 @@
 
     glGenTextures(1, &texture->id);
 
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    Caches::getInstance().bindTexture(texture->id);
     // Textures are Alpha8
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
@@ -350,8 +370,7 @@
 // Paths
 ///////////////////////////////////////////////////////////////////////////////
 
-void PathCache::remove(const path_pair_t& pair) {
-    Vector<PathDescription> pathsToRemove;
+void PathCache::remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair) {
     LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
 
     while (i.next()) {
@@ -362,10 +381,6 @@
             pathsToRemove.push(key);
         }
     }
-
-    for (size_t i = 0; i < pathsToRemove.size(); i++) {
-        mCache.remove(pathsToRemove.itemAt(i));
-    }
 }
 
 void PathCache::removeDeferred(SkPath* path) {
@@ -374,12 +389,20 @@
 }
 
 void PathCache::clearGarbage() {
-    Mutex::Autolock l(mLock);
-    size_t count = mGarbage.size();
-    for (size_t i = 0; i < count; i++) {
-        remove(mGarbage.itemAt(i));
+    Vector<PathDescription> pathsToRemove;
+
+    { // scope for the mutex
+        Mutex::Autolock l(mLock);
+        size_t count = mGarbage.size();
+        for (size_t i = 0; i < count; i++) {
+            remove(pathsToRemove, mGarbage.itemAt(i));
+        }
+        mGarbage.clear();
     }
-    mGarbage.clear();
+
+    for (size_t i = 0; i < pathsToRemove.size(); i++) {
+        mCache.remove(pathsToRemove.itemAt(i));
+    }
 }
 
 /**
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index dd1f996..16d20a8 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -58,7 +58,7 @@
  * Alpha texture used to represent a path.
  */
 struct PathTexture: public Texture {
-    PathTexture(): Texture() {
+    PathTexture(Caches& caches): Texture(caches) {
     }
 
     ~PathTexture() {
@@ -269,7 +269,7 @@
      * Removes an entry.
      * The pair must define first=path, second=sourcePath
      */
-    void remove(const path_pair_t& pair);
+    void remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair);
 
     /**
      * Ensures there is enough space in the cache for a texture of the specified
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 0879b1b..3970913 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -66,11 +66,11 @@
     }
 }
 
-inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
+inline static void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
     Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
 }
 
-inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
+inline static void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
     AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha);
 }
 
@@ -84,7 +84,7 @@
  *
  * NOTE: assumes angles between normals 90 degrees or less
  */
-inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) {
+inline static vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) {
     return (normalA + normalB) / (1 + fabs(normalA.dot(normalB)));
 }
 
@@ -224,6 +224,20 @@
     DEBUG_DUMP_BUFFER();
 }
 
+static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center,
+        const vec2& normal, Vertex* buffer, int& currentIndex, bool begin) {
+    vec2 strokeOffset = normal;
+    paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
+
+    vec2 referencePoint(center.position[0], center.position[1]);
+    if (paintInfo.cap == SkPaint::kSquare_Cap) {
+        referencePoint += vec2(-strokeOffset.y, strokeOffset.x) * (begin ? -1 : 1);
+    }
+
+    Vertex::set(&buffer[currentIndex++], referencePoint + strokeOffset);
+    Vertex::set(&buffer[currentIndex++], referencePoint - strokeOffset);
+}
+
 /**
  * Fills a vertexBuffer with non-alpha vertices similar to getStrokeVerticesFromPerimeter, except:
  *
@@ -235,19 +249,17 @@
         const Vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
     const int extra = paintInfo.capExtraDivisions();
     const int allocSize = (vertices.size() + extra) * 2;
-
     Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize);
 
+    const int lastIndex = vertices.size() - 1;
     if (extra > 0) {
         // tessellate both round caps
-        const int last = vertices.size() - 1;
         float beginTheta = atan2(
-                - (vertices[0].position[0] - vertices[1].position[0]),
-                vertices[0].position[1] - vertices[1].position[1]);
+                    - (vertices[0].position[0] - vertices[1].position[0]),
+                    vertices[0].position[1] - vertices[1].position[1]);
         float endTheta = atan2(
-                - (vertices[last].position[0] - vertices[last - 1].position[0]),
-                vertices[last].position[1] - vertices[last - 1].position[1]);
-
+                    - (vertices[lastIndex].position[0] - vertices[lastIndex - 1].position[0]),
+                    vertices[lastIndex].position[1] - vertices[lastIndex - 1].position[1]);
         const float dTheta = PI / (extra + 1);
         const float radialScale = 2.0f / (1 + cos(dTheta));
 
@@ -270,56 +282,45 @@
             vec2 endRadialOffset(cos(endTheta), sin(endTheta));
             paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
             Vertex::set(&buffer[allocSize - 1 - capOffset],
-                    vertices[last].position[0] + endRadialOffset.x,
-                    vertices[last].position[1] + endRadialOffset.y);
+                    vertices[lastIndex].position[0] + endRadialOffset.x,
+                    vertices[lastIndex].position[1] + endRadialOffset.y);
         }
     }
 
     int currentIndex = extra;
-    const Vertex* current = &(vertices[0]);
-    vec2 lastNormal;
-    for (unsigned int i = 0; i < vertices.size() - 1; i++) {
+    const Vertex* last = &(vertices[0]);
+    const Vertex* current = &(vertices[1]);
+    vec2 lastNormal(current->position[1] - last->position[1],
+                last->position[0] - current->position[0]);
+    lastNormal.normalize();
+
+    storeBeginEnd(paintInfo, vertices[0], lastNormal, buffer, currentIndex, true);
+
+    for (unsigned int i = 1; i < vertices.size() - 1; i++) {
         const Vertex* next = &(vertices[i + 1]);
         vec2 nextNormal(next->position[1] - current->position[1],
                 current->position[0] - next->position[0]);
         nextNormal.normalize();
 
-        vec2 totalOffset;
-        if (i == 0) {
-            totalOffset = nextNormal;
-        } else {
-            totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
-        }
-        paintInfo.scaleOffsetForStrokeWidth(totalOffset);
+        vec2 strokeOffset  = totalOffsetFromNormals(lastNormal, nextNormal);
+        paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
 
-        Vertex::set(&buffer[currentIndex++],
-                current->position[0] + totalOffset.x,
-                current->position[1] + totalOffset.y);
-
-        Vertex::set(&buffer[currentIndex++],
-                current->position[0] - totalOffset.x,
-                current->position[1] - totalOffset.y);
+        vec2 center(current->position[0], current->position[1]);
+        Vertex::set(&buffer[currentIndex++], center + strokeOffset);
+        Vertex::set(&buffer[currentIndex++], center - strokeOffset);
 
         current = next;
         lastNormal = nextNormal;
     }
 
-    vec2 totalOffset = lastNormal;
-    paintInfo.scaleOffsetForStrokeWidth(totalOffset);
-
-    Vertex::set(&buffer[currentIndex++],
-            current->position[0] + totalOffset.x,
-            current->position[1] + totalOffset.y);
-    Vertex::set(&buffer[currentIndex++],
-            current->position[0] - totalOffset.x,
-            current->position[1] - totalOffset.y);
+    storeBeginEnd(paintInfo, vertices[lastIndex], lastNormal, buffer, currentIndex, false);
 
     DEBUG_DUMP_BUFFER();
 }
 
 /**
  * Populates a vertexBuffer with AlphaVertices to create an anti-aliased fill shape tessellation
- * 
+ *
  * 1 - create the AA perimeter of unit width, by zig-zagging at each point around the perimeter of
  * the shape (using 2 * perimeter.size() vertices)
  *
@@ -389,7 +390,7 @@
  * For explanation of constants and general methodoloyg, see comments for
  * getStrokeVerticesFromUnclosedVerticesAA() below.
  */
-inline void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices,
+inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices,
         AlphaVertex* buffer, bool isFirst, vec2 normal, int offset) {
     const int extra = paintInfo.capExtraDivisions();
     const int extraOffset = (extra + 1) / 2;
@@ -772,11 +773,67 @@
     }
 }
 
+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(SkRect& rect, const Vertex& vertex) {
-    rect.fLeft = fminf(rect.fLeft, vertex.position[0]);
-    rect.fTop = fminf(rect.fTop, vertex.position[1]);
-    rect.fRight = fmaxf(rect.fRight, vertex.position[0]);
-    rect.fBottom = fmaxf(rect.fBottom, vertex.position[1]);
+    expandRectToCoverVertex(rect, vertex.position[0], vertex.position[1]);
+}
+
+template <class TYPE>
+static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
+        const float* points, int count, SkRect& bounds) {
+    bounds.set(points[0], points[1], points[0], points[1]);
+
+    int numPoints = count / 2;
+    int verticesPerPoint = srcBuffer.getVertexCount();
+    dstBuffer.alloc<TYPE>(numPoints * verticesPerPoint + (numPoints - 1) * 2);
+
+    for (int i = 0; i < count; i += 2) {
+        expandRectToCoverVertex(bounds, points[i + 0], points[i + 1]);
+        dstBuffer.copyInto<TYPE>(srcBuffer, points[i + 0], points[i + 1]);
+    }
+    dstBuffer.createDegenerateSeparators<TYPE>(verticesPerPoint);
+}
+
+void PathTessellator::tessellatePoints(const float* points, int count, SkPaint* paint,
+        const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer) {
+    const PaintInfo paintInfo(paint, transform);
+
+    // determine point shape
+    SkPath path;
+    float radius = paintInfo.halfStrokeWidth;
+    if (radius == 0.0f) radius = 0.25f;
+
+    if (paintInfo.cap == SkPaint::kRound_Cap) {
+        path.addCircle(0, 0, radius);
+    } else {
+        path.addRect(-radius, -radius, radius, radius);
+    }
+
+    // calculate outline
+    Vector<Vertex> outlineVertices;
+    approximatePathOutlineVertices(path, true,
+            paintInfo.inverseScaleX * paintInfo.inverseScaleX,
+            paintInfo.inverseScaleY * paintInfo.inverseScaleY, outlineVertices);
+
+    if (!outlineVertices.size()) return;
+
+    // tessellate, then duplicate outline across points
+    int numPoints = count / 2;
+    VertexBuffer tempBuffer;
+    if (!paintInfo.isAA) {
+        getFillVerticesFromPerimeter(outlineVertices, tempBuffer);
+        instanceVertices<Vertex>(tempBuffer, vertexBuffer, points, count, bounds);
+    } else {
+        getFillVerticesFromPerimeterAA(paintInfo, outlineVertices, tempBuffer);
+        instanceVertices<AlphaVertex>(tempBuffer, vertexBuffer, points, count, bounds);
+    }
+
+    expandBoundsForStroke(bounds, paint, true); // force-expand bounds to incorporate stroke
 }
 
 void PathTessellator::tessellateLines(const float* points, int count, SkPaint* paint,
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index 596d49d..85797fc 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -30,7 +30,7 @@
 public:
     VertexBuffer():
         mBuffer(0),
-        mSize(0),
+        mVertexCount(0),
         mCleanupMethod(NULL)
     {}
 
@@ -44,30 +44,42 @@
        multiple regions within a single VertexBuffer, such as with PathTessellator::tesselateLines()
      */
     template <class TYPE>
-    TYPE* alloc(int size) {
-        if (mSize) {
+    TYPE* alloc(int vertexCount) {
+        if (mVertexCount) {
             TYPE* reallocBuffer = (TYPE*)mReallocBuffer;
             // already have allocated the buffer, re-allocate space within
             if (mReallocBuffer != mBuffer) {
                 // not first re-allocation, leave space for degenerate triangles to separate strips
                 reallocBuffer += 2;
             }
-            mReallocBuffer = reallocBuffer + size;
+            mReallocBuffer = reallocBuffer + vertexCount;
             return reallocBuffer;
         }
-        mSize = size;
-        mReallocBuffer = mBuffer = (void*)new TYPE[size];
+        mVertexCount = vertexCount;
+        mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
         mCleanupMethod = &(cleanup<TYPE>);
 
         return (TYPE*)mBuffer;
     }
 
-    void* getBuffer() const { return mBuffer; }
-    unsigned int getSize() const { return mSize; }
+    template <class TYPE>
+    void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) {
+        int verticesToCopy = srcBuffer.getVertexCount();
+
+        TYPE* dst = alloc<TYPE>(verticesToCopy);
+        TYPE* src = (TYPE*)srcBuffer.getBuffer();
+
+        for (int i = 0; i < verticesToCopy; i++) {
+            TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset);
+        }
+    }
+
+    void* getBuffer() const { return mBuffer; } // shouldn't be const, since not a const ptr?
+    unsigned int getVertexCount() const { return mVertexCount; }
 
     template <class TYPE>
     void createDegenerateSeparators(int allocSize) {
-        TYPE* end = (TYPE*)mBuffer + mSize;
+        TYPE* end = (TYPE*)mBuffer + mVertexCount;
         for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) {
             memcpy(degen, degen - 1, sizeof(TYPE));
             memcpy(degen + 1, degen + 2, sizeof(TYPE));
@@ -81,7 +93,7 @@
     }
 
     void* mBuffer;
-    unsigned int mSize;
+    unsigned int mVertexCount;
 
     void* mReallocBuffer; // used for multi-allocation
 
@@ -95,6 +107,9 @@
     static void tessellatePath(const SkPath& path, const SkPaint* paint,
             const mat4 *transform, VertexBuffer& vertexBuffer);
 
+    static void tessellatePoints(const float* points, int count, SkPaint* paint,
+            const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer);
+
     static void tessellateLines(const float* points, int count, SkPaint* paint,
             const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer);
 
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 8280370..36e89c6 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "Caches.h"
+#include "Debug.h"
 #include "Extensions.h"
 #include "PixelBuffer.h"
 #include "Properties.h"
@@ -113,6 +114,14 @@
     if (mAccessMode == kAccessMode_None) {
         mCaches.bindPixelBuffer(mBuffer);
         mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
+#if DEBUG_OPENGL
+        if (!mMappedPointer) {
+            GLenum status = GL_NO_ERROR;
+            while ((status = glGetError()) != GL_NO_ERROR) {
+                ALOGE("Could not map GPU pixel buffer: 0x%x", status);
+            }
+        }
+#endif
         mAccessMode = mode;
     }
 
@@ -123,7 +132,10 @@
     if (mAccessMode != kAccessMode_None) {
         if (mMappedPointer) {
             mCaches.bindPixelBuffer(mBuffer);
-            glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
+            GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
+            if (status == GL_FALSE) {
+                ALOGE("Corrupted GPU pixel buffer");
+            }
         }
         mAccessMode = kAccessMode_None;
         mMappedPointer = NULL;
@@ -147,14 +159,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
-    bool gpuBuffer = type == kBufferType_Auto && Extensions::getInstance().getMajorGlVersion() >= 3;
-    if (gpuBuffer) {
-        char property[PROPERTY_VALUE_MAX];
-        if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "false") > 0) {
-            if (!strcmp(property, "true")) {
-                return new GpuPixelBuffer(format, width, height);
-            }
-        }
+    if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
+        return new GpuPixelBuffer(format, width, height);
     }
     return new CpuPixelBuffer(format, width, height);
 }
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 32d5417..9725a61 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -112,13 +112,25 @@
     virtual uint8_t* getMappedPointer() const = 0;
 
     /**
-     * Upload the specified rectangle of this pixe buffer as a
+     * Upload the specified rectangle of this pixel buffer as a
      * GL_TEXTURE_2D texture. Calling this method will trigger
      * an unmap() if necessary.
      */
     virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0;
 
     /**
+     * Upload the specified rectangle of this pixel buffer as a
+     * GL_TEXTURE_2D texture. Calling this method will trigger
+     * an unmap() if necessary.
+     *
+     * This is a convenience function provided to save callers the
+     * trouble of computing the offset parameter.
+     */
+    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
+        upload(x, y, width, height, getOffset(x, y));
+    }
+
+    /**
      * Returns the width of the render buffer in pixels.
      */
     uint32_t getWidth() const {
@@ -140,6 +152,13 @@
     }
 
     /**
+     * Returns the offset of a pixel in this pixel buffer, in bytes.
+     */
+    uint32_t getOffset(uint32_t x, uint32_t y) const {
+        return (y * mWidth + x) * formatSize(mFormat);
+    }
+
+    /**
      * Returns the number of bytes per pixel in the specified format.
      *
      * Supported formats:
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 14a2376..7814a01 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -15,8 +15,12 @@
  */
 
 #define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <utils/Trace.h>
 
 #include "Program.h"
+#include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
@@ -25,7 +29,6 @@
 // Base program
 ///////////////////////////////////////////////////////////////////////////////
 
-// TODO: Program instance should be created from a factory method
 Program::Program(const ProgramDescription& description, const char* vertex, const char* fragment) {
     mInitialized = false;
     mHasColorUniform = false;
@@ -50,7 +53,9 @@
                 texCoords = -1;
             }
 
+            ATRACE_BEGIN("linkProgram");
             glLinkProgram(mProgramId);
+            ATRACE_END();
 
             GLint status;
             glGetProgramiv(mProgramId, GL_LINK_STATUS, &status);
@@ -87,6 +92,9 @@
 
 Program::~Program() {
     if (mInitialized) {
+        // This would ideally happen after linking the program
+        // but Tegra drivers, especially when perfhud is enabled,
+        // sometimes crash if we do so
         glDetachShader(mProgramId, mVertexShader);
         glDetachShader(mProgramId, mFragmentShader);
 
@@ -132,6 +140,8 @@
 }
 
 GLuint Program::buildShader(const char* source, GLenum type) {
+    ATRACE_CALL();
+
     GLuint shader = glCreateShader(type);
     glShaderSource(shader, 1, &source, 0);
     glCompileShader(shader);
@@ -153,20 +163,24 @@
 
 void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
         const mat4& transformMatrix, bool offset) {
-    mat4 p(projectionMatrix);
-    if (offset) {
-        // offset screenspace xy by an amount that compensates for typical precision
-        // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
-        // up and to the left.
-        // This offset value is based on an assumption that some hardware may use as
-        // little as 12.4 precision, so we offset by slightly more than 1/16.
-        p.translate(.065, .065, 0);
+    if (projectionMatrix != mProjection) {
+        if (CC_LIKELY(!offset)) {
+            glUniformMatrix4fv(projection, 1, GL_FALSE, &projectionMatrix.data[0]);
+        } else {
+            mat4 p(projectionMatrix);
+            // offset screenspace xy by an amount that compensates for typical precision
+            // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
+            // up and to the left.
+            // This offset value is based on an assumption that some hardware may use as
+            // little as 12.4 precision, so we offset by slightly more than 1/16.
+            p.translate(Vertex::gGeometryFudgeFactor, Vertex::gGeometryFudgeFactor);
+            glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
+        }
+        mProjection = projectionMatrix;
     }
 
     mat4 t(transformMatrix);
     t.multiply(modelViewMatrix);
-
-    glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
     glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
 }
 
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index e8b6d47..4f94afc 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -68,23 +68,22 @@
 #define PROGRAM_BITMAP_WRAPS_SHIFT 9
 #define PROGRAM_BITMAP_WRAPT_SHIFT 11
 
-#define PROGRAM_GRADIENT_TYPE_SHIFT 33
+#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
 #define PROGRAM_MODULATE_SHIFT 35
 
-#define PROGRAM_IS_POINT_SHIFT 36
+#define PROGRAM_HAS_AA_SHIFT 36
 
-#define PROGRAM_HAS_AA_SHIFT 37
+#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 37
+#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 38
 
-#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
-#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
+#define PROGRAM_HAS_GAMMA_CORRECTION 39
 
-#define PROGRAM_HAS_GAMMA_CORRECTION 40
+#define PROGRAM_IS_SIMPLE_GRADIENT 40
 
-#define PROGRAM_IS_SIMPLE_GRADIENT 41
+#define PROGRAM_HAS_COLORS 41
 
-#define PROGRAM_HAS_COLORS 42
-
-#define PROGRAM_HAS_DEBUG_HIGHLIGHT 43
+#define PROGRAM_HAS_DEBUG_HIGHLIGHT 42
+#define PROGRAM_EMULATE_STENCIL 43
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
@@ -156,13 +155,11 @@
     SkXfermode::Mode framebufferMode;
     bool swapSrcDst;
 
-    bool isPoint;
-    float pointSize;
-
     bool hasGammaCorrection;
     float gamma;
 
     bool hasDebugHighlight;
+    bool emulateStencil;
 
     /**
      * Resets this description. All fields are reset back to the default
@@ -199,9 +196,6 @@
         framebufferMode = SkXfermode::kClear_Mode;
         swapSrcDst = false;
 
-        isPoint = false;
-        pointSize = 0.0f;
-
         hasGammaCorrection = false;
         gamma = 2.2f;
 
@@ -267,7 +261,6 @@
         key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
         if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
         if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
-        if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
         if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
         if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
         if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
@@ -275,6 +268,7 @@
         if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
         if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
         if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
+        if (emulateStencil) key |= programid(0x1) << PROGRAM_EMULATE_STENCIL;
         return key;
     }
 
@@ -430,10 +424,13 @@
     bool mUse;
     bool mInitialized;
 
+    // Uniforms caching
     bool mHasColorUniform;
     int mColorUniform;
 
     bool mHasSampler;
+
+    mat4 mProjection;
 }; // class Program
 
 }; // namespace uirenderer
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 8eb85e5..a5ce6f6 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -53,8 +53,6 @@
 const char* gVS_Header_Uniforms =
         "uniform mat4 projection;\n" \
         "uniform mat4 transform;\n";
-const char* gVS_Header_Uniforms_IsPoint =
-        "uniform mediump float pointSize;\n";
 const char* gVS_Header_Uniforms_HasGradient =
         "uniform mat4 screenSpace;\n";
 const char* gVS_Header_Uniforms_HasBitmap =
@@ -68,8 +66,6 @@
         "varying float alpha;\n";
 const char* gVS_Header_Varyings_HasBitmap =
         "varying highp vec2 outBitmapTexCoords;\n";
-const char* gVS_Header_Varyings_PointHasBitmap =
-        "varying highp vec2 outPointBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_HasGradient[6] = {
         // Linear
         "varying highp vec2 linear;\n"
@@ -118,12 +114,8 @@
 };
 const char* gVS_Main_OutBitmapTexCoords =
         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
-const char* gVS_Main_OutPointBitmapTexCoords =
-        "    outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
 const char* gVS_Main_Position =
         "    gl_Position = projection * transform * position;\n";
-const char* gVS_Main_PointSize =
-        "    gl_PointSize = pointSize;\n";
 const char* gVS_Main_AAVertexShape =
         "    alpha = vtxAlpha;\n";
 const char* gVS_Footer =
@@ -141,9 +133,6 @@
         "precision mediump float;\n\n";
 const char* gFS_Uniforms_Color =
         "uniform vec4 color;\n";
-const char* gFS_Header_Uniforms_PointHasBitmap =
-        "uniform vec2 textureDimension;\n"
-        "uniform float pointSize;\n";
 const char* gFS_Uniforms_TextureSampler =
         "uniform sampler2D baseSampler;\n";
 const char* gFS_Uniforms_ExternalTextureSampler =
@@ -178,10 +167,6 @@
         "\nvoid main(void) {\n"
         "    lowp vec4 fragColor;\n";
 
-const char* gFS_Main_PointBitmapTexCoords =
-        "    highp vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
-        "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
-
 const char* gFS_Main_Dither[2] = {
         // ES 2.0
         "texture2D(ditherSampler, ditherTexCoords).a * " STR(DITHER_KERNEL_SIZE_INV_SQUARE),
@@ -342,6 +327,12 @@
 };
 const char* gFS_Main_DebugHighlight =
         "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
+const char* gFS_Main_EmulateStencil =
+        "    gl_FragColor.rgba = vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0);\n"
+        "    return;\n"
+        "    /*\n";
+const char* gFS_Footer_EmulateStencil =
+        "    */\n";
 const char* gFS_Footer =
         "}\n\n";
 
@@ -478,9 +469,6 @@
     if (description.hasBitmap) {
         shader.append(gVS_Header_Uniforms_HasBitmap);
     }
-    if (description.isPoint) {
-        shader.append(gVS_Header_Uniforms_IsPoint);
-    }
     // Varyings
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
@@ -495,9 +483,7 @@
         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
     }
     if (description.hasBitmap) {
-        shader.append(description.isPoint ?
-                gVS_Header_Varyings_PointHasBitmap :
-                gVS_Header_Varyings_HasBitmap);
+        shader.append(gVS_Header_Varyings_HasBitmap);
     }
 
     // Begin the shader
@@ -514,12 +500,7 @@
             shader.append(gVS_Main_OutColors);
         }
         if (description.hasBitmap) {
-            shader.append(description.isPoint ?
-                    gVS_Main_OutPointBitmapTexCoords :
-                    gVS_Main_OutBitmapTexCoords);
-        }
-        if (description.isPoint) {
-            shader.append(gVS_Main_PointSize);
+            shader.append(gVS_Main_OutBitmapTexCoords);
         }
         // Output transformed position
         shader.append(gVS_Main_Position);
@@ -570,9 +551,7 @@
         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
     }
     if (description.hasBitmap) {
-        shader.append(description.isPoint ?
-                gVS_Header_Varyings_PointHasBitmap :
-                gVS_Header_Varyings_HasBitmap);
+        shader.append(gVS_Header_Varyings_HasBitmap);
     }
 
     // Uniforms
@@ -593,9 +572,6 @@
         shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
                 gFS_Uniforms_Dither);
     }
-    if (description.hasBitmap && description.isPoint) {
-        shader.append(gFS_Header_Uniforms_PointHasBitmap);
-    }
     if (description.hasGammaCorrection) {
         shader.append(gFS_Uniforms_Gamma);
     }
@@ -603,7 +579,7 @@
     // Optimization for common cases
     if (!description.isAA && !blendFramebuffer && !description.hasColors &&
             description.colorOp == ProgramDescription::kColorNone &&
-            !description.isPoint && !description.hasDebugHighlight) {
+            !description.hasDebugHighlight && !description.emulateStencil) {
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -683,6 +659,9 @@
 
     // Begin the shader
     shader.append(gFS_Main); {
+        if (description.emulateStencil) {
+            shader.append(gFS_Main_EmulateStencil);
+        }
         // Stores the result in fragColor directly
         if (description.hasTexture || description.hasExternalTexture) {
             if (description.hasAlpha8Texture) {
@@ -703,9 +682,6 @@
             shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
         }
         if (description.hasBitmap) {
-            if (description.isPoint) {
-                shader.append(gFS_Main_PointBitmapTexCoords);
-            }
             if (!description.isBitmapNpot) {
                 shader.append(gFS_Main_FetchBitmap);
             } else {
@@ -757,6 +733,9 @@
             shader.append(gFS_Main_DebugHighlight);
         }
     }
+    if (description.emulateStencil) {
+        shader.append(gFS_Footer_EmulateStencil);
+    }
     // End the shader
     shader.append(gFS_Footer);
 
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 6eea00c..20b8f2f 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -70,10 +70,23 @@
 #define PROPERTY_DEBUG_LAYERS_UPDATES "debug.hwui.show_layers_updates"
 
 /**
- * Used to enable/disable overdraw debugging. The accepted values are
- * "true" and "false". The default value is "false".
+ * Used to enable/disable overdraw debugging.
+ *
+ * The accepted values are
+ * "show", to show overdraw
+ * "show_deuteranomaly", to show overdraw if you suffer from Deuteranomaly
+ * "count", to show an overdraw counter
+ * "false", to disable overdraw debugging
+ *
+ * The default value is "false".
  */
-#define PROPERTY_DEBUG_OVERDRAW "debug.hwui.show_overdraw"
+#define PROPERTY_DEBUG_OVERDRAW "debug.hwui.overdraw"
+
+/**
+ * Used to enable/disable PerfHUD ES profiling. The accepted values
+ * are "true" and "false". The default value is "false".
+ */
+#define PROPERTY_DEBUG_NV_PROFILING "debug.hwui.nv_profiling"
 
 /**
  * Used to enable/disable non-rectangular clipping debugging.
@@ -123,9 +136,9 @@
 
 /**
  * Indicates whether PBOs can be used to back pixel buffers.
- * Accepted values are "true" and "false".
+ * Accepted values are "true" and "false". Default is true.
  */
-#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "hwui.use_gpu_pixel_buffers"
+#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "ro.hwui.use_gpu_pixel_buffers"
 
 // These properties are defined in mega-bytes
 #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
@@ -133,6 +146,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_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"
 
@@ -178,7 +192,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_PATCH_CACHE_SIZE 512
+#define DEFAULT_PATCH_CACHE_SIZE 128 // in kB
 #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
 #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
 #define DEFAULT_FBO_CACHE_SIZE 16
@@ -195,6 +209,8 @@
 
 // Converts a number of mega-bytes into bytes
 #define MB(s) s * 1024 * 1024
+// Converts a number of kilo-bytes into bytes
+#define KB(s) s * 1024
 
 static DebugLevel readDebugLevel() {
     char property[PROPERTY_VALUE_MAX];
diff --git a/libs/hwui/Query.h b/libs/hwui/Query.h
new file mode 100644
index 0000000..e25b16b
--- /dev/null
+++ b/libs/hwui/Query.h
@@ -0,0 +1,152 @@
+/*
+ * 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_QUERY_H
+#define ANDROID_HWUI_QUERY_H
+
+#include <GLES3/gl3.h>
+
+#include "Extensions.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * A Query instance can be used to perform occlusion queries. If the device
+ * does not support occlusion queries, the result of a query will always be
+ * 0 and the result will always be marked available.
+ *
+ * To run an occlusion query successfully, you must start end end the query:
+ *
+ * Query query;
+ * query.begin();
+ * // execute OpenGL calls
+ * query.end();
+ * GLuint result = query.getResult();
+ */
+class Query {
+public:
+    /**
+     * Possible query targets.
+     */
+    enum Target {
+        /**
+         * Indicates if any sample passed the depth & stencil tests.
+         */
+        kTargetSamples = GL_ANY_SAMPLES_PASSED,
+        /**
+         * Indicates if any sample passed the depth & stencil tests.
+         * The implementation may choose to use a less precise version
+         * of the test, potentially resulting in false positives.
+         */
+        kTargetConservativeSamples = GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
+    };
+
+    /**
+     * Creates a new query with the specified target. The default
+     * target is kTargetSamples (of GL_ANY_SAMPLES_PASSED in OpenGL.)
+     */
+    Query(Target target = kTargetSamples): mActive(false), mTarget(target),
+            mCanQuery(Extensions::getInstance().hasOcclusionQueries()),
+            mQuery(0) {
+    }
+
+    ~Query() {
+        if (mQuery) {
+            glDeleteQueries(1, &mQuery);
+        }
+    }
+
+    /**
+     * Begins the query. If the query has already begun or if the device
+     * does not support occlusion queries, calling this method as no effect.
+     * After calling this method successfully, the query is marked active.
+     */
+    void begin() {
+        if (!mActive && mCanQuery) {
+            if (!mQuery) {
+                glGenQueries(1, &mQuery);
+            }
+
+            glBeginQuery(mTarget, mQuery);
+            mActive = true;
+        }
+    }
+
+    /**
+     * Ends the query. If the query has already begun or if the device
+     * does not support occlusion queries, calling this method as no effect.
+     * After calling this method successfully, the query is marked inactive.
+     */
+    void end() {
+        if (mQuery && mActive) {
+            glEndQuery(mTarget);
+            mActive = false;
+        }
+    }
+
+    /**
+     * Returns true if the query is active, false otherwise.
+     */
+    bool isActive() {
+        return mActive;
+    }
+
+    /**
+     * Returns true if the result of the query is available,
+     * false otherwise. Calling getResult() before the result
+     * is available may result in the calling thread being blocked.
+     * If the device does not support queries, this method always
+     * returns true.
+     */
+    bool isResultAvailable() {
+        if (!mQuery) return true;
+
+        GLuint result;
+        glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &result);
+        return result == GL_TRUE;
+    }
+
+    /**
+     * Returns the result of the query. If the device does not
+     * support queries this method will return 0.
+     *
+     * Calling this method implicitely calls end() if the query
+     * is currently active.
+     */
+    GLuint getResult() {
+        if (!mQuery) return 0;
+
+        end();
+
+        GLuint result;
+        glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT, &result);
+        return result;
+    }
+
+
+private:
+    bool mActive;
+    GLenum mTarget;
+    bool mCanQuery;
+    GLuint mQuery;
+
+}; // class Query
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_QUERY_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index f50ac3c..dabd8d4 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -21,9 +21,15 @@
 
 #include <utils/Log.h>
 
+#include "Vertex.h"
+
 namespace android {
 namespace uirenderer {
 
+#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
+#define RECT_ARGS(r) \
+    (r).left, (r).top, (r).right, (r).bottom
+
 ///////////////////////////////////////////////////////////////////////////////
 // Structs
 ///////////////////////////////////////////////////////////////////////////////
@@ -125,11 +131,11 @@
         return intersect(r.left, r.top, r.right, r.bottom);
     }
 
-    inline bool contains(float l, float t, float r, float b) {
+    inline bool contains(float l, float t, float r, float b) const {
         return l >= left && t >= top && r <= right && b <= bottom;
     }
 
-    inline bool contains(const Rect& r) {
+    inline bool contains(const Rect& r) const {
         return contains(r.left, r.top, r.right, r.bottom);
     }
 
@@ -166,6 +172,40 @@
         bottom += delta;
     }
 
+    /**
+     * Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding
+     * errors.
+     *
+     * This function should be used whenever estimating the damage rect of geometry already mapped
+     * into layer space.
+     */
+    void snapGeometryToPixelBoundaries(bool snapOut) {
+        if (snapOut) {
+            /* For AA geometry with a ramp perimeter, don't snap by rounding - AA geometry will have
+             * a 0.5 pixel perimeter not accounted for in its bounds. Instead, snap by
+             * conservatively rounding out the bounds with floor/ceil.
+             *
+             * In order to avoid changing integer bounds with floor/ceil due to rounding errors
+             * inset the bounds first by the fudge factor. Very small fraction-of-a-pixel errors
+             * from this inset will only incur similarly small errors in output, due to transparency
+             * in extreme outside of the geometry.
+             */
+            left = floorf(left + Vertex::gGeometryFudgeFactor);
+            top = floorf(top + Vertex::gGeometryFudgeFactor);
+            right = ceilf(right - Vertex::gGeometryFudgeFactor);
+            bottom = ceilf(bottom - Vertex::gGeometryFudgeFactor);
+        } else {
+            /* For other geometry, we do the regular rounding in order to snap, but also outset the
+             * bounds by a fudge factor. This ensures that ambiguous geometry (e.g. a non-AA Rect
+             * with top left at (0.5, 0.5)) will err on the side of a larger damage rect.
+             */
+            left = floorf(left + 0.5f - Vertex::gGeometryFudgeFactor);
+            top = floorf(top + 0.5f - Vertex::gGeometryFudgeFactor);
+            right = floorf(right + 0.5f + Vertex::gGeometryFudgeFactor);
+            bottom = floorf(bottom + 0.5f + Vertex::gGeometryFudgeFactor);
+        }
+    }
+
     void snapToPixelBoundaries() {
         left = floorf(left + 0.5f);
         top = floorf(top + 0.5f);
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 347bd78..3f77021 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "OpenGLRenderer"
+
 #include <SkPixelRef.h>
 #include "ResourceCache.h"
 #include "Caches.h"
@@ -60,7 +62,7 @@
 }
 
 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
-    SkSafeRef(bitmapResource->pixelRef());
+    bitmapResource->pixelRef()->globalRef();
     SkSafeRef(bitmapResource->getColorTable());
     incrementRefcount((void*) bitmapResource, kBitmap);
 }
@@ -79,6 +81,10 @@
     incrementRefcount((void*) filterResource, kColorFilter);
 }
 
+void ResourceCache::incrementRefcount(Res_png_9patch* patchResource) {
+    incrementRefcount((void*) patchResource, kNinePatch);
+}
+
 void ResourceCache::incrementRefcount(Layer* layerResource) {
     incrementRefcount((void*) layerResource, kLayer);
 }
@@ -94,7 +100,7 @@
 }
 
 void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) {
-    SkSafeRef(bitmapResource->pixelRef());
+    bitmapResource->pixelRef()->globalRef();
     SkSafeRef(bitmapResource->getColorTable());
     incrementRefcountLocked((void*) bitmapResource, kBitmap);
 }
@@ -113,6 +119,10 @@
     incrementRefcountLocked((void*) filterResource, kColorFilter);
 }
 
+void ResourceCache::incrementRefcountLocked(Res_png_9patch* patchResource) {
+    incrementRefcountLocked((void*) patchResource, kNinePatch);
+}
+
 void ResourceCache::incrementRefcountLocked(Layer* layerResource) {
     incrementRefcountLocked((void*) layerResource, kLayer);
 }
@@ -123,7 +133,7 @@
 }
 
 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
-    SkSafeUnref(bitmapResource->pixelRef());
+    bitmapResource->pixelRef()->globalUnref();
     SkSafeUnref(bitmapResource->getColorTable());
     decrementRefcount((void*) bitmapResource);
 }
@@ -142,6 +152,10 @@
     decrementRefcount((void*) filterResource);
 }
 
+void ResourceCache::decrementRefcount(Res_png_9patch* patchResource) {
+    decrementRefcount((void*) patchResource);
+}
+
 void ResourceCache::decrementRefcount(Layer* layerResource) {
     decrementRefcount((void*) layerResource);
 }
@@ -160,7 +174,7 @@
 }
 
 void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) {
-    SkSafeUnref(bitmapResource->pixelRef());
+    bitmapResource->pixelRef()->globalUnref();
     SkSafeUnref(bitmapResource->getColorTable());
     decrementRefcountLocked((void*) bitmapResource);
 }
@@ -179,6 +193,10 @@
     decrementRefcountLocked((void*) filterResource);
 }
 
+void ResourceCache::decrementRefcountLocked(Res_png_9patch* patchResource) {
+    decrementRefcountLocked((void*) patchResource);
+}
+
 void ResourceCache::decrementRefcountLocked(Layer* layerResource) {
     decrementRefcountLocked((void*) layerResource);
 }
@@ -265,6 +283,30 @@
     }
 }
 
+void ResourceCache::destructor(Res_png_9patch* resource) {
+    Mutex::Autolock _l(mLock);
+    destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(Res_png_9patch* resource) {
+    ssize_t index = mCache->indexOfKey(resource);
+    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
+    if (ref == NULL) {
+        if (Caches::hasInstance()) {
+            Caches::getInstance().patchCache.removeDeferred(resource);
+        }
+        // If we're not tracking this resource, just delete it
+        // A Res_png_9patch is actually an array of byte that's larger
+        // than sizeof(Res_png_9patch). It must be freed as an array.
+        delete[] (int8_t*) resource;
+        return;
+    }
+    ref->destroyed = true;
+    if (ref->refCount == 0) {
+        deleteResourceReferenceLocked(resource, ref);
+    }
+}
+
 /**
  * Return value indicates whether resource was actually recycled, which happens when RefCnt
  * reaches 0.
@@ -335,6 +377,16 @@
                 delete filter;
             }
             break;
+            case kNinePatch: {
+                if (Caches::hasInstance()) {
+                    Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
+                }
+                // A Res_png_9patch is actually an array of byte that's larger
+                // than sizeof(Res_png_9patch). It must be freed as an array.
+                int8_t* patch = (int8_t*) resource;
+                delete[] patch;
+            }
+            break;
             case kLayer: {
                 Layer* layer = (Layer*) resource;
                 Caches::getInstance().deleteLayerDeferred(layer);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index ab493e5..ea0c1b5 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -22,7 +22,11 @@
 #include <SkBitmap.h>
 #include <SkiaColorFilter.h>
 #include <SkiaShader.h>
+
 #include <utils/KeyedVector.h>
+
+#include <androidfw/ResourceTypes.h>
+
 #include "Layer.h"
 
 namespace android {
@@ -35,6 +39,7 @@
     kBitmap,
     kShader,
     kColorFilter,
+    kNinePatch,
     kPath,
     kLayer
 };
@@ -69,35 +74,41 @@
     void incrementRefcount(SkBitmap* resource);
     void incrementRefcount(SkiaShader* resource);
     void incrementRefcount(SkiaColorFilter* resource);
+    void incrementRefcount(Res_png_9patch* resource);
     void incrementRefcount(Layer* resource);
 
     void incrementRefcountLocked(SkPath* resource);
     void incrementRefcountLocked(SkBitmap* resource);
     void incrementRefcountLocked(SkiaShader* resource);
     void incrementRefcountLocked(SkiaColorFilter* resource);
+    void incrementRefcountLocked(Res_png_9patch* resource);
     void incrementRefcountLocked(Layer* resource);
 
     void decrementRefcount(SkBitmap* resource);
     void decrementRefcount(SkPath* resource);
     void decrementRefcount(SkiaShader* resource);
     void decrementRefcount(SkiaColorFilter* resource);
+    void decrementRefcount(Res_png_9patch* resource);
     void decrementRefcount(Layer* resource);
 
     void decrementRefcountLocked(SkBitmap* resource);
     void decrementRefcountLocked(SkPath* resource);
     void decrementRefcountLocked(SkiaShader* resource);
     void decrementRefcountLocked(SkiaColorFilter* resource);
+    void decrementRefcountLocked(Res_png_9patch* resource);
     void decrementRefcountLocked(Layer* resource);
 
     void destructor(SkPath* resource);
     void destructor(SkBitmap* resource);
     void destructor(SkiaShader* resource);
     void destructor(SkiaColorFilter* resource);
+    void destructor(Res_png_9patch* resource);
 
     void destructorLocked(SkPath* resource);
     void destructorLocked(SkBitmap* resource);
     void destructorLocked(SkiaShader* resource);
     void destructorLocked(SkiaColorFilter* resource);
+    void destructorLocked(Res_png_9patch* resource);
 
     bool recycle(SkBitmap* resource);
     bool recycleLocked(SkBitmap* resource);
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index c38eedb..797ed10 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -69,9 +69,13 @@
     mGenerationId = shader.mGenerationId;
 }
 
+SkiaShader::SkiaShader(): mCaches(NULL) {
+}
+
 SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
         SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
-        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) {
+        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
+        mCaches(NULL) {
     setMatrix(matrix);
     mGenerationId = 0;
 }
@@ -87,7 +91,7 @@
 }
 
 void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    mCaches->bindTexture(texture->id);
     texture->setWrapST(wrapS, wrapT);
 }
 
@@ -114,7 +118,7 @@
 }
 
 void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
-    Texture* texture = mTextureCache->get(mBitmap);
+    Texture* texture = mCaches->textureCache.get(mBitmap);
     if (!texture) return;
     mTexture = texture;
 
@@ -229,7 +233,7 @@
         GLuint textureSlot = (*textureUnit)++;
         Caches::getInstance().activeTexture(textureSlot);
 
-        Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
+        Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
 
         // Uniforms
         bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
@@ -349,7 +353,7 @@
         GLuint textureSlot = (*textureUnit)++;
         Caches::getInstance().activeTexture(textureSlot);
 
-        Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
+        Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
 
         // Uniforms
         bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
@@ -359,7 +363,7 @@
        bindUniformColor(program->getUniform("endColor"), mColors[1]);
     }
 
-    Caches::getInstance().dither.setupProgram(program, textureUnit);
+    mCaches->dither.setupProgram(program, textureUnit);
 
     mat4 screenSpace;
     computeScreenSpaceMatrix(screenSpace, modelView);
@@ -394,12 +398,6 @@
     return copy;
 }
 
-void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
-    SkiaShader::set(textureCache, gradientCache);
-    mFirst->set(textureCache, gradientCache);
-    mSecond->set(textureCache, gradientCache);
-}
-
 void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
     mFirst->describe(description, extensions);
     mSecond->describe(description, extensions);
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index bc12b0d..a63431c 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -33,6 +33,8 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Base shader
 ///////////////////////////////////////////////////////////////////////////////
@@ -77,9 +79,8 @@
         return mType;
     }
 
-    virtual void set(TextureCache* textureCache, GradientCache* gradientCache) {
-        mTextureCache = textureCache;
-        mGradientCache = gradientCache;
+    virtual void setCaches(Caches& caches) {
+        mCaches = &caches;
     }
 
     uint32_t getGenerationId() {
@@ -103,8 +104,7 @@
     void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
 
 protected:
-    SkiaShader() {
-    }
+    SkiaShader();
 
     /**
      * The appropriate texture unit must have been activated prior to invoking
@@ -118,8 +118,7 @@
     SkShader::TileMode mTileY;
     bool mBlend;
 
-    TextureCache* mTextureCache;
-    GradientCache* mGradientCache;
+    Caches* mCaches;
 
     mat4 mUnitMatrix;
     mat4 mShaderMatrix;
@@ -229,7 +228,11 @@
     ~SkiaComposeShader();
     SkiaShader* copy();
 
-    void set(TextureCache* textureCache, GradientCache* gradientCache);
+    void setCaches(Caches& caches) {
+        SkiaShader::setCaches(caches);
+        mFirst->setCaches(caches);
+        mSecond->setCaches(caches);
+    }
 
     void describe(ProgramDescription& description, const Extensions& extensions);
     void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp
index ba2e6f2..2764523 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/Stencil.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "Debug.h"
 #include "Extensions.h"
 #include "Properties.h"
 #include "Stencil.h"
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 6976eaa..0b2c130 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -18,6 +18,7 @@
 
 #include <utils/JenkinsHash.h>
 
+#include "Caches.h"
 #include "Debug.h"
 #include "TextDropShadowCache.h"
 #include "Properties.h"
@@ -154,7 +155,7 @@
             ALOGD("Shadow texture deleted, size = %d", texture->bitmapSize);
         }
 
-        glDeleteTextures(1, &texture->id);
+        texture->deleteTexture();
         delete texture;
     }
 }
@@ -182,7 +183,9 @@
             return NULL;
         }
 
-        texture = new ShadowTexture;
+        Caches& caches = Caches::getInstance();
+
+        texture = new ShadowTexture(caches);
         texture->left = shadow.penX;
         texture->top = shadow.penY;
         texture->width = shadow.width;
@@ -202,7 +205,7 @@
 
         glGenTextures(1, &texture->id);
 
-        glBindTexture(GL_TEXTURE_2D, texture->id);
+        caches.bindTexture(texture->id);
         // Textures are Alpha8
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 0bed72b6..04d7357 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -30,6 +30,8 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
+
 struct ShadowText {
     ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(NULL),
             flags(0), italicStyle(0.0f), scaleX(0), text(NULL), positions(NULL) {
@@ -114,7 +116,7 @@
  * Alpha texture used to represent a shadow.
  */
 struct ShadowTexture: public Texture {
-    ShadowTexture(): Texture() {
+    ShadowTexture(Caches& caches): Texture(caches) {
     }
 
     float left;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
new file mode 100644
index 0000000..7923ce7
--- /dev/null
+++ b/libs/hwui/Texture.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+
+#include "Caches.h"
+#include "Texture.h"
+
+namespace android {
+namespace uirenderer {
+
+Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
+        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
+        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
+        mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
+}
+
+Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
+        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
+        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
+        mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
+}
+
+void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
+        GLenum renderTarget) {
+
+    if (mFirstWrap || force || wrapS != mWrapS || wrapT != mWrapT) {
+        mFirstWrap = false;
+
+        mWrapS = wrapS;
+        mWrapT = wrapT;
+
+        if (bindTexture) {
+            mCaches.bindTexture(renderTarget, id);
+        }
+
+        glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
+        glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
+    }
+}
+
+void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool force,
+        GLenum renderTarget) {
+
+    if (mFirstFilter || force || min != mMinFilter || mag != mMagFilter) {
+        mFirstFilter = false;
+
+        mMinFilter = min;
+        mMagFilter = mag;
+
+        if (bindTexture) {
+            mCaches.bindTexture(renderTarget, id);
+        }
+
+        if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
+
+        glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
+        glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
+    }
+}
+
+void Texture::deleteTexture() const {
+    mCaches.deleteTexture(id);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 8d88bdc..d48ec59 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -22,75 +22,39 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
+class UvMapper;
+
 /**
  * Represents an OpenGL texture.
  */
-struct Texture {
-    Texture() {
-        cleanup = false;
-        bitmapSize = 0;
+class Texture {
+public:
+    Texture();
+    Texture(Caches& caches);
 
-        wrapS = GL_CLAMP_TO_EDGE;
-        wrapT = GL_CLAMP_TO_EDGE;
+    virtual ~Texture() { }
 
-        minFilter = GL_NEAREST;
-        magFilter = GL_NEAREST;
-
-        mipMap = false;
-
-        firstFilter = true;
-        firstWrap = true;
-
-        id = 0;
-    }
-
-    void setWrap(GLenum wrap, bool bindTexture = false, bool force = false,
+    inline void setWrap(GLenum wrap, bool bindTexture = false, bool force = false,
                 GLenum renderTarget = GL_TEXTURE_2D) {
         setWrapST(wrap, wrap, bindTexture, force, renderTarget);
     }
 
-    void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false,
-            GLenum renderTarget = GL_TEXTURE_2D) {
+    virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D);
 
-        if (firstWrap || force || wrapS != this->wrapS || wrapT != this->wrapT) {
-            firstWrap = false;
-
-            this->wrapS = wrapS;
-            this->wrapT = wrapT;
-
-            if (bindTexture) {
-                glBindTexture(renderTarget, id);
-            }
-
-            glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
-            glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
-        }
-    }
-
-    void setFilter(GLenum filter, bool bindTexture = false, bool force = false,
+    inline void setFilter(GLenum filter, bool bindTexture = false, bool force = false,
                 GLenum renderTarget = GL_TEXTURE_2D) {
         setFilterMinMag(filter, filter, bindTexture, force, renderTarget);
     }
 
-    void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false, bool force = false,
-            GLenum renderTarget = GL_TEXTURE_2D) {
+    virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D);
 
-        if (firstFilter || force || min != minFilter || mag != magFilter) {
-            firstFilter = false;
-
-            minFilter = min;
-            magFilter = mag;
-
-            if (bindTexture) {
-                glBindTexture(renderTarget, id);
-            }
-
-            if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
-
-            glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
-            glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
-        }
-    }
+    /**
+     * Convenience method to call glDeleteTextures() on this texture's id.
+     */
+    void deleteTexture() const;
 
     /**
      * Name of the texture.
@@ -125,21 +89,28 @@
      */
     bool mipMap;
 
+    /**
+     * Optional, pointer to a texture coordinates mapper.
+     */
+    const UvMapper* uvMapper;
+
 private:
     /**
      * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
      */
-    GLenum wrapS;
-    GLenum wrapT;
+    GLenum mWrapS;
+    GLenum mWrapT;
 
     /**
      * Last filters set on this texture. Defaults to GL_NEAREST.
      */
-    GLenum minFilter;
-    GLenum magFilter;
+    GLenum mMinFilter;
+    GLenum mMagFilter;
 
-    bool firstFilter;
-    bool firstWrap;
+    bool mFirstFilter;
+    bool mFirstWrap;
+
+    Caches& mCaches;
 }; // struct Texture
 
 class AutoTexture {
@@ -147,7 +118,7 @@
     AutoTexture(const Texture* texture): mTexture(texture) { }
     ~AutoTexture() {
         if (mTexture && mTexture->cleanup) {
-            glDeleteTextures(1, &mTexture->id);
+            mTexture->deleteTexture();
             delete mTexture;
         }
     }
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 2378eb5..ed0a79a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -112,7 +112,7 @@
         if (mDebugEnabled) {
             ALOGD("Texture deleted, size = %d", texture->bitmapSize);
         }
-        glDeleteTextures(1, &texture->id);
+        texture->deleteTexture();
         delete texture;
     }
 }
@@ -139,7 +139,7 @@
             }
         }
 
-        texture = new Texture;
+        texture = new Texture();
         texture->bitmapSize = size;
         generateTexture(bitmap, texture, false);
 
@@ -162,7 +162,7 @@
 }
 
 Texture* TextureCache::getTransient(SkBitmap* bitmap) {
-    Texture* texture = new Texture;
+    Texture* texture = new Texture();
     texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
     texture->cleanup = true;
 
@@ -235,25 +235,25 @@
     texture->width = bitmap->width();
     texture->height = bitmap->height();
 
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    Caches::getInstance().bindTexture(texture->id);
 
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height,
-                GL_UNSIGNED_BYTE, bitmap->getPixels());
+        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(),
+                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(), texture->height,
-                GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
+        uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(),
+                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(), texture->height,
-                GL_UNSIGNED_BYTE, bitmap->getPixels());
+        uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(),
+                texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
         // Do this after calling getPixels() to make sure Skia's deferred
         // decoding happened
         texture->blend = !bitmap->isOpaque();
@@ -293,17 +293,28 @@
     SkCanvas canvas(rgbaBitmap);
     canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
 
-    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), height,
+    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height,
             GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
 }
 
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
-        GLenum type, const GLvoid * data) {
+void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride,
+        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 (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);
+    }
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 80bb22e..57fc19a 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -125,8 +125,8 @@
     void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
 
     void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
-    void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
-            GLenum type, const GLvoid * data);
+    void uploadToTexture(bool resize, GLenum format, GLsizei stride,
+            GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
 
     void init();
 
diff --git a/libs/hwui/UvMapper.h b/libs/hwui/UvMapper.h
new file mode 100644
index 0000000..70428d2
--- /dev/null
+++ b/libs/hwui/UvMapper.h
@@ -0,0 +1,133 @@
+/*
+ * 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_UV_MAPPER_H
+#define ANDROID_HWUI_UV_MAPPER_H
+
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * This class can be used to map UV coordinates from the [0..1]
+ * range to other arbitrary ranges. All the methods below assume
+ * that the input values lie in the [0..1] range already.
+ */
+class UvMapper {
+public:
+    /**
+     * Using this constructor is equivalent to not using any mapping at all.
+     * UV coordinates in the [0..1] range remain in the [0..1] range.
+     */
+    UvMapper(): mIdentity(true), mMinU(0.0f), mMaxU(1.0f), mMinV(0.0f), mMaxV(1.0f) {
+    }
+
+    /**
+     * Creates a new mapper with the specified ranges for U and V coordinates.
+     * The parameter minU must be < maxU and minV must be < maxV.
+     */
+    UvMapper(float minU, float maxU, float minV, float maxV):
+        mMinU(minU), mMaxU(maxU), mMinV(minV), mMaxV(maxV) {
+        checkIdentity();
+    }
+
+    /**
+     * Returns true if calling the map*() methods has no effect (that is,
+     * texture coordinates remain in the 0..1 range.)
+     */
+    bool isIdentity() const {
+        return mIdentity;
+    }
+
+    /**
+     * Changes the U and V mapping ranges.
+     * The parameter minU must be < maxU and minV must be < maxV.
+     */
+    void setMapping(float minU, float maxU, float minV, float maxV) {
+        mMinU = minU;
+        mMaxU = maxU;
+        mMinV = minV;
+        mMaxV = maxV;
+        checkIdentity();
+    }
+
+    /**
+     * Maps a single value in the U range.
+     */
+    void mapU(float& u) const {
+        if (!mIdentity) u = lerp(mMinU, mMaxU, u);
+    }
+
+    /**
+     * Maps a single value in the V range.
+     */
+    void mapV(float& v) const {
+        if (!mIdentity) v = lerp(mMinV, mMaxV, v);
+    }
+
+    /**
+     * Maps the specified rectangle in place. This method assumes:
+     * - left = min. U
+     * - top = min. V
+     * - right = max. U
+     * - bottom = max. V
+     */
+    void map(Rect& texCoords) const {
+        if (!mIdentity) {
+            texCoords.left = lerp(mMinU, mMaxU, texCoords.left);
+            texCoords.right = lerp(mMinU, mMaxU, texCoords.right);
+            texCoords.top = lerp(mMinV, mMaxV, texCoords.top);
+            texCoords.bottom = lerp(mMinV, mMaxV, texCoords.bottom);
+        }
+    }
+
+    /**
+     * Maps the specified UV coordinates in place.
+     */
+    void map(float& u1, float& v1, float& u2, float& v2) const {
+        if (!mIdentity) {
+            u1 = lerp(mMinU, mMaxU, u1);
+            u2 = lerp(mMinU, mMaxU, u2);
+            v1 = lerp(mMinV, mMaxV, v1);
+            v2 = lerp(mMinV, mMaxV, v2);
+        }
+    }
+
+    void dump() const {
+        ALOGD("mapper[minU=%.2f maxU=%.2f minV=%.2f maxV=%.2f]", mMinU, mMaxU, mMinV, mMaxV);
+    }
+
+private:
+    static float lerp(float start, float stop, float amount) {
+        return start + (stop - start) * amount;
+    }
+
+    void checkIdentity() {
+        mIdentity = mMinU == 0.0f && mMaxU == 1.0f && mMinV == 0.0f && mMaxV == 1.0f;
+    }
+
+    bool mIdentity;
+    float mMinU;
+    float mMaxU;
+    float mMinV;
+    float mMaxV;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_UV_MAPPER_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 523120e..790d4fc 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HWUI_VERTEX_H
 #define ANDROID_HWUI_VERTEX_H
 
+#include "Vector.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -24,12 +26,30 @@
  * Simple structure to describe a vertex with a position and a texture.
  */
 struct Vertex {
+    /**
+     * Fudge-factor used to disambiguate geometry pixel positioning.
+     *
+     * Used to offset lines and points to avoid ambiguous intersection with pixel centers (see
+     * Program::set()), and used to make geometry damage rect calculation conservative (see
+     * Rect::snapGeometryToPixelBoundaries())
+     */
+    static const float gGeometryFudgeFactor = 0.0656f;
+
     float position[2];
 
     static inline void set(Vertex* vertex, float x, float y) {
         vertex[0].position[0] = x;
         vertex[0].position[1] = y;
     }
+
+    static inline void set(Vertex* vertex, vec2 val) {
+        set(vertex, val.x, val.y);
+    }
+
+    static inline void copyWithOffset(Vertex* vertex, const Vertex& src, float x, float y) {
+        set(vertex, src.position[0] + x, src.position[1] + y);
+    }
+
 }; // struct Vertex
 
 /**
@@ -81,6 +101,12 @@
         vertex[0].alpha = alpha;
     }
 
+    static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src,
+            float x, float y) {
+        Vertex::set(vertex, src.position[0] + x, src.position[1] + y);
+        vertex[0].alpha = src.alpha;
+    }
+
     static inline void setColor(AlphaVertex* vertex, float alpha) {
         vertex[0].alpha = alpha;
     }
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 6c5267d..d5f38b5 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -17,6 +17,7 @@
 #include <SkGlyph.h>
 
 #include "CacheTexture.h"
+#include "../Caches.h"
 #include "../Debug.h"
 #include "../Extensions.h"
 #include "../PixelBuffer.h"
@@ -107,17 +108,18 @@
 // CacheTexture
 ///////////////////////////////////////////////////////////////////////////////
 
-CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount) :
-            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
+CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) :
+            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
             mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
-            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) {
+            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
+            mCaches(Caches::getInstance()) {
     mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
             mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
 
     // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
     // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
     // With OpenGL ES 2.0 we have to upload entire stripes instead.
-    mHasES3 = Extensions::getInstance().getMajorGlVersion() >= 3;
+    mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
 }
 
 CacheTexture::~CacheTexture() {
@@ -154,7 +156,7 @@
         mTexture = NULL;
     }
     if (mTextureId) {
-        glDeleteTextures(1, &mTextureId);
+        mCaches.deleteTexture(mTextureId);
         mTextureId = 0;
     }
     mDirty = false;
@@ -166,7 +168,7 @@
        mLinearFiltering = linearFiltering;
 
        const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
-       if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
+       if (bind) mCaches.bindTexture(getTextureId());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    }
@@ -180,17 +182,17 @@
 
 void CacheTexture::allocateTexture() {
     if (!mTexture) {
-        mTexture = PixelBuffer::create(GL_ALPHA, mWidth, mHeight);
+        mTexture = PixelBuffer::create(mFormat, mWidth, mHeight);
     }
 
     if (!mTextureId) {
         glGenTextures(1, &mTextureId);
 
-        glBindTexture(GL_TEXTURE_2D, mTextureId);
+        mCaches.bindTexture(mTextureId);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         // Initialize texture dimensions
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0,
-                GL_ALPHA, GL_UNSIGNED_BYTE, 0);
+        glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
+                mFormat, GL_UNSIGNED_BYTE, 0);
 
         const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
@@ -204,22 +206,21 @@
 bool CacheTexture::upload() {
     const Rect& dirtyRect = mDirtyRect;
 
-    uint32_t x = mHasES3 ? dirtyRect.left : 0;
+    uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0;
     uint32_t y = dirtyRect.top;
-    uint32_t width = mHasES3 ? dirtyRect.getWidth() : mWidth;
+    uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : mWidth;
     uint32_t height = dirtyRect.getHeight();
 
     // The unpack row length only needs to be specified when a new
     // texture is bound
-    if (mHasES3) {
+    if (mHasUnpackRowLength) {
         glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
     }
 
-    mTexture->upload(x, y, width, height, y * mWidth + x);
-
+    mTexture->upload(x, y, width, height);
     setDirty(false);
 
-    return mHasES3;
+    return mHasUnpackRowLength;
 }
 
 void CacheTexture::setDirty(bool dirty) {
@@ -230,6 +231,32 @@
 }
 
 bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
+    switch (glyph.fMaskFormat) {
+        case SkMask::kA8_Format:
+        case SkMask::kBW_Format:
+            if (mFormat != GL_ALPHA) {
+#if DEBUG_FONT_RENDERER
+                ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
+                        mFormat);
+#endif
+                return false;
+            }
+            break;
+        case SkMask::kARGB32_Format:
+            if (mFormat != GL_RGBA) {
+#if DEBUG_FONT_RENDERER
+                ALOGD("fitBitmap: texture format %x is inappropriate for colour glyphs", mFormat);
+#endif
+                return false;
+            }
+            break;
+        default:
+#if DEBUG_FONT_RENDERER
+            ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat);
+#endif
+            return false;
+    }
+
     if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
         return false;
     }
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index ddcc836..61b38f8 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -24,13 +24,14 @@
 #include <utils/Log.h>
 
 #include "FontUtil.h"
+#include "../PixelBuffer.h"
 #include "../Rect.h"
 #include "../Vertex.h"
 
 namespace android {
 namespace uirenderer {
 
-class PixelBuffer;
+class Caches;
 
 /**
  * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
@@ -73,7 +74,7 @@
 
 class CacheTexture {
 public:
-    CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount);
+    CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount);
     ~CacheTexture();
 
     void reset();
@@ -99,6 +100,14 @@
         return mHeight;
     }
 
+    inline GLenum getFormat() const {
+        return mFormat;
+    }
+
+    inline uint32_t getOffset(uint16_t x, uint16_t y) const {
+        return (y * mWidth + x) * PixelBuffer::formatSize(mFormat);
+    }
+
     inline const Rect* getDirtyRect() const {
         return &mDirtyRect;
     }
@@ -150,9 +159,9 @@
             float x3, float y3, float u3, float v3,
             float x4, float y4, float u4, float v4) {
         TextureVertex* mesh = mMesh + mCurrentQuad * 4;
-        TextureVertex::set(mesh++, x1, y1, u1, v1);
         TextureVertex::set(mesh++, x2, y2, u2, v2);
         TextureVertex::set(mesh++, x3, y3, u3, v3);
+        TextureVertex::set(mesh++, x1, y1, u1, v1);
         TextureVertex::set(mesh++, x4, y4, u4, v4);
         mCurrentQuad++;
     }
@@ -172,15 +181,17 @@
     GLuint mTextureId;
     uint16_t mWidth;
     uint16_t mHeight;
+    GLenum mFormat;
     bool mLinearFiltering;
     bool mDirty;
     uint16_t mNumGlyphs;
     TextureVertex* mMesh;
     uint32_t mCurrentQuad;
     uint32_t mMaxQuadCount;
+    Caches& mCaches;
     CacheBlock* mCacheBlocks;
+    bool mHasUnpackRowLength;
     Rect mDirtyRect;
-    bool mHasES3;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 011cfc1..18983d8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -55,6 +55,7 @@
     mStyle = paint->getStyle();
     mStrokeWidth = paint->getStrokeWidth();
     mAntiAliasing = paint->isAntiAlias();
+    mHinting = paint->getHinting();
     mLookupTransform.reset();
     mLookupTransform[SkMatrix::kMScaleX] = roundf(fmaxf(1.0f, matrix[mat4::kScaleX]));
     mLookupTransform[SkMatrix::kMScaleY] = roundf(fmaxf(1.0f, matrix[mat4::kScaleY]));
@@ -80,6 +81,7 @@
     hash = JenkinsHashMix(hash, android::hash_type(mStyle));
     hash = JenkinsHashMix(hash, android::hash_type(mStrokeWidth));
     hash = JenkinsHashMix(hash, int(mAntiAliasing));
+    hash = JenkinsHashMix(hash, android::hash_type(mHinting));
     hash = JenkinsHashMix(hash, android::hash_type(mLookupTransform[SkMatrix::kMScaleX]));
     hash = JenkinsHashMix(hash, android::hash_type(mLookupTransform[SkMatrix::kMScaleY]));
     return JenkinsHashWhiten(hash);
@@ -111,6 +113,9 @@
     deltaInt = int(lhs.mAntiAliasing) - int(rhs.mAntiAliasing);
     if (deltaInt != 0) return deltaInt;
 
+    deltaInt = int(lhs.mHinting) - int(rhs.mHinting);
+    if (deltaInt != 0) return deltaInt;
+
     if (lhs.mLookupTransform[SkMatrix::kMScaleX] <
             rhs.mLookupTransform[SkMatrix::kMScaleX]) return -1;
     if (lhs.mLookupTransform[SkMatrix::kMScaleX] >
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 52cca1c..9e7ec2d 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -69,6 +69,7 @@
         uint8_t mStyle;
         float mStrokeWidth;
         bool mAntiAliasing;
+        uint8_t mHinting;
         SkMatrix mLookupTransform;
         SkMatrix mInverseLookupTransform;
     };
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index f758666..cdcb23c 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -31,6 +31,9 @@
 #define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
 
 #define TEXTURE_BORDER_SIZE 1
+#if TEXTURE_BORDER_SIZE != 1
+# error TEXTURE_BORDER_SIZE other than 1 is not currently supported
+#endif
 
 #define CACHE_BLOCK_ROUNDING_SIZE 4
 
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index c8bfd9c..189895c 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -29,7 +29,7 @@
 
 TaskManager::TaskManager() {
     // Get the number of available CPUs. This value does not change over time.
-    int cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+    int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
 
     for (int i = 0; i < cpuCount / 2; i++) {
         String8 name;
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
index 477314b..f2a216f 100644
--- a/libs/hwui/thread/TaskManager.h
+++ b/libs/hwui/thread/TaskManager.h
@@ -43,7 +43,7 @@
     /**
      * Returns true if this task  manager can run tasks,
      * false otherwise. This method will typically return
-     * true on a single CPU core device.
+     * false on a single CPU core device.
      */
     bool canRunTasks() const;
 
diff --git a/location/Android.mk b/location/Android.mk
index 12db2f7..feeb8ce 100644
--- a/location/Android.mk
+++ b/location/Android.mk
@@ -14,6 +14,4 @@
 
 LOCAL_PATH := $(call my-dir)
 
-ifeq ($(TARGET_BUILD_APPS),)
 include $(call all-makefiles-under, $(LOCAL_PATH))
-endif
diff --git a/location/java/android/location/FusedBatchOptions.aidl b/location/java/android/location/FusedBatchOptions.aidl
new file mode 100644
index 0000000..94cb6e1
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.location;
+
+parcelable FusedBatchOptions;
\ No newline at end of file
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
new file mode 100644
index 0000000..623d707
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -0,0 +1,135 @@
+/*
+ * 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 android.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A data class representing a set of options to configure batching sessions.
+ * @hide
+ */
+public class FusedBatchOptions implements Parcelable {
+    private volatile long mPeriodInNS = 0;
+    private volatile int mSourcesToUse = 0;
+    private volatile int mFlags = 0;
+
+    // the default value is set to request fixes at no cost
+    private volatile double mMaxPowerAllocationInMW = 0;
+
+    /*
+     * Getters and setters for properties needed to hold the options.
+     */
+    public void setMaxPowerAllocationInMW(double value) {
+        mMaxPowerAllocationInMW = value;
+    }
+
+    public double getMaxPowerAllocationInMW() {
+        return mMaxPowerAllocationInMW;
+    }
+
+    public void setPeriodInNS(long value) {
+        mPeriodInNS = value;
+    }
+
+    public long getPeriodInNS() {
+        return mPeriodInNS;
+    }
+
+    public void setSourceToUse(int source) {
+        mSourcesToUse |= source;
+    }
+
+    public void resetSourceToUse(int source) {
+        mSourcesToUse &= ~source;
+    }
+
+    public boolean isSourceToUseSet(int source) {
+        return (mSourcesToUse & source) != 0;
+    }
+
+    public int getSourcesToUse() {
+        return mSourcesToUse;
+    }
+
+    public void setFlag(int flag) {
+        mFlags |= flag;
+    }
+
+    public void resetFlag(int flag) {
+        mFlags &= ~flag;
+    }
+
+    public boolean isFlagSet(int flag) {
+        return (mFlags & flag) != 0;
+    }
+
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Definition of enum flag sets needed by this class.
+     * Such values need to be kept in sync with the ones in fused_location.h
+     */
+    public static final class SourceTechnologies {
+        public static int GNSS = 1<<0;
+        public static int WIFI = 1<<1;
+        public static int SENSORS = 1<<2;
+        public static int CELL = 1<<3;
+        public static int BLUETOOTH = 1<<4;
+    }
+
+    public static final class BatchFlags {
+        public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+        public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+    }
+
+    /*
+     * Method definitions to support Parcelable operations.
+     */
+    public static final Parcelable.Creator<FusedBatchOptions> CREATOR =
+            new Parcelable.Creator<FusedBatchOptions>() {
+        @Override
+        public FusedBatchOptions createFromParcel(Parcel parcel) {
+            FusedBatchOptions options = new FusedBatchOptions();
+            options.setMaxPowerAllocationInMW(parcel.readDouble());
+            options.setPeriodInNS(parcel.readLong());
+            options.setSourceToUse(parcel.readInt());
+            options.setFlag(parcel.readInt());
+            return options;
+        }
+
+        @Override
+        public FusedBatchOptions[] newArray(int size) {
+            return new FusedBatchOptions[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeDouble(mMaxPowerAllocationInMW);
+        parcel.writeLong(mPeriodInNS);
+        parcel.writeInt(mSourcesToUse);
+        parcel.writeInt(mFlags);
+    }
+}
diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/location/java/android/location/IFusedGeofenceHardware.aidl
new file mode 100644
index 0000000..d8c3585
--- /dev/null
+++ b/location/java/android/location/IFusedGeofenceHardware.aidl
@@ -0,0 +1,93 @@
+/*
+ * 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/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.location;
+
+import android.hardware.location.GeofenceHardwareRequestParcelable;
+
+/**
+ * Fused Geofence Hardware interface.
+ *
+ * <p>This interface is the basic set of supported functionality by Fused Hardware modules that offer
+ * Geofencing capabilities.
+ *
+ * All operations are asynchronous and the status codes can be obtained via a set of callbacks.
+ *
+ * @hide
+ */
+interface IFusedGeofenceHardware {
+    /**
+     * Flags if the interface functionality is supported by the platform.
+     *
+     * @return true if the functionality is supported, false otherwise.
+     */
+    boolean isSupported();
+
+    /**
+     * Adds a given list of geofences to the system.
+     *
+     * @param geofenceRequestsArray    The list of geofences to add.
+     */
+    void addGeofences(in GeofenceHardwareRequestParcelable[] geofenceRequestsArray);
+
+    /**
+     * Removes a give list of geofences from the system.
+     *
+     * @param geofences     The list of geofences to remove.
+     */
+    void removeGeofences(in int[] geofenceIds);
+
+    /**
+     * Pauses monitoring a particular geofence.
+     * 
+     * @param geofenceId    The geofence to pause monitoring.
+     */
+    void pauseMonitoringGeofence(in int geofenceId);
+
+    /**
+     * Resumes monitoring a particular geofence.
+     *
+     * @param geofenceid            The geofence to resume monitoring.
+     * @param transitionsToMonitor  The transitions to monitor upon resume.
+     *
+     * Remarks: keep naming of geofence request options consistent with the naming used in
+     *          GeofenceHardwareRequest
+     */
+    void resumeMonitoringGeofence(in int geofenceId, in int monitorTransitions);
+
+    /**
+     * Modifies the request options if a geofence that is already known by the
+     * system.
+     *  
+     * @param geofenceId                    The geofence to modify.
+     * @param lastTransition                The last known transition state of
+     *                                      the geofence.
+     * @param monitorTransitions            The set of transitions to monitor.
+     * @param notificationResponsiveness    The notification responsivness needed.
+     * @param unknownTimer                  The time span associated with the.
+     * @param sourcesToUse                  The source technologies to use.
+     *
+     * Remarks: keep the options as separate fields to be able to leverage the class
+     * GeofenceHardwareRequest without any changes
+     */
+    void modifyGeofenceOptions(
+            in int geofenceId,
+            in int lastTransition,
+            in int monitorTransitions,
+            in int notificationResponsiveness,
+            in int unknownTimer,
+            in int sourcesToUse);
+}
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
new file mode 100644
index 0000000..8870d2a
--- /dev/null
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 android.location;
+
+import android.hardware.location.IFusedLocationHardware;
+
+/**
+ * Interface definition for Location providers that require FLP services.
+ * @hide
+ */
+interface IFusedProvider {
+    /**
+     * Provides access to a FusedLocationHardware instance needed for the provider to work.
+     *
+     * @param instance      The FusedLocationHardware available for the provider to use.
+     */
+    void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
+}
\ No newline at end of file
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 989178a..ccb4304 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -152,12 +152,25 @@
 
     /**
      * Broadcast intent action when the configured location providers
-     * change.
+     * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the
+     * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}
+     * instead.
      */
     public static final String PROVIDERS_CHANGED_ACTION =
         "android.location.PROVIDERS_CHANGED";
 
     /**
+     * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.
+     * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
+     * If you're interacting with {@link #isProviderEnabled(String)}, use
+     * {@link #PROVIDERS_CHANGED_ACTION} instead.
+     *
+     * In the future, there may be mode changes that do not result in
+     * {@link #PROVIDERS_CHANGED_ACTION} broadcasts.
+     */
+    public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
+
+    /**
      * Broadcast intent action indicating that the GPS has either started or
      * stopped receiving GPS fixes. An intent extra provides this state as a
      * boolean, where {@code true} means that the GPS is actively receiving fixes.
@@ -177,6 +190,17 @@
      */
     public static final String EXTRA_GPS_ENABLED = "enabled";
 
+    /**
+     * Broadcast intent action indicating that a high power location requests
+     * has either started or stopped being active.  The current state of
+     * active location requests should be read from AppOpsManager using
+     * {@code OP_MONITOR_HIGH_POWER_LOCATION}.
+     *
+     * @hide
+     */
+    public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
+        "android.location.HIGH_POWER_REQUEST_CHANGE";
+
     // Map from LocationListeners to their associated ListenerTransport objects
     private HashMap<LocationListener,ListenerTransport> mListeners =
         new HashMap<LocationListener,ListenerTransport>();
@@ -1075,8 +1099,13 @@
      * <p>If the user has enabled this provider in the Settings menu, true
      * is returned otherwise false is returned
      *
+     * <p>Callers should instead use
+     * {@link android.provider.Settings.Secure#LOCATION_MODE}
+     * unless they depend on provider-specific APIs such as
+     * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
+     *
      * @param provider the name of the provider
-     * @return true if the provider is enabled
+     * @return true if the provider exists and is enabled
      *
      * @throws IllegalArgumentException if provider is null
      * @throws SecurityException if no suitable permission is present
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 68f540b..c9162fe 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -19,6 +19,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.util.TimeUtils;
 
 
@@ -145,6 +146,8 @@
     private long mExpireAt = Long.MAX_VALUE;  // no expiry
     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
     private float mSmallestDisplacement = 0.0f;    // meters
+    private WorkSource mWorkSource = null;
+    private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
 
     private String mProvider = LocationManager.FUSED_PROVIDER;  // for deprecated APIs that explicitly request a provider
 
@@ -233,6 +236,8 @@
         mNumUpdates = src.mNumUpdates;
         mSmallestDisplacement = src.mSmallestDisplacement;
         mProvider = src.mProvider;
+        mWorkSource = src.mWorkSource;
+        mHideFromAppOps = src.mHideFromAppOps;
     }
 
     /**
@@ -493,6 +498,48 @@
         return mSmallestDisplacement;
     }
 
+    /**
+     * Sets the WorkSource to use for power blaming of this location request.
+     *
+     * <p>No permissions are required to make this call, however the LocationManager
+     * will throw a SecurityException when requesting location updates if the caller
+     * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
+     *
+     * @param workSource WorkSource defining power blame for this location request.
+     * @hide
+     */
+    public void setWorkSource(WorkSource workSource) {
+        mWorkSource = workSource;
+    }
+
+    /** @hide */
+    public WorkSource getWorkSource() {
+        return mWorkSource;
+    }
+
+    /**
+     * Sets whether or not this location request should be hidden from AppOps.
+     *
+     * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this
+     * request's existence.  It does not affect power blaming in the Battery page.
+     *
+     * <p>No permissions are required to make this call, however the LocationManager
+     * will throw a SecurityException when requesting location updates if the caller
+     * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
+     *
+     * @param hideFromAppOps If true AppOps won't keep track of this location request.
+     * @see android.app.AppOpsManager
+     * @hide
+     */
+    public void setHideFromAppOps(boolean hideFromAppOps) {
+        mHideFromAppOps = hideFromAppOps;
+    }
+
+    /** @hide */
+    public boolean getHideFromAppOps() {
+        return mHideFromAppOps;
+    }
+
     private static void checkInterval(long millis) {
         if (millis < 0) {
             throw new IllegalArgumentException("invalid interval: " + millis);
@@ -536,8 +583,11 @@
             request.setExpireAt(in.readLong());
             request.setNumUpdates(in.readInt());
             request.setSmallestDisplacement(in.readFloat());
+            request.setHideFromAppOps(in.readInt() != 0);
             String provider = in.readString();
             if (provider != null) request.setProvider(provider);
+            WorkSource workSource = in.readParcelable(null);
+            if (workSource != null) request.setWorkSource(workSource);
             return request;
         }
         @Override
@@ -559,7 +609,9 @@
         parcel.writeLong(mExpireAt);
         parcel.writeInt(mNumUpdates);
         parcel.writeFloat(mSmallestDisplacement);
+        parcel.writeInt(mHideFromAppOps ? 1 : 0);
         parcel.writeString(mProvider);
+        parcel.writeParcelable(mWorkSource, 0);
     }
 
     /** @hide */
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
new file mode 100644
index 0000000..9f321f3
--- /dev/null
+++ b/location/java/android/location/SettingInjectorService.java
@@ -0,0 +1,238 @@
+/*
+ * 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 android.location;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Dynamically specifies the summary (subtitle) and enabled status of a preference injected into
+ * the list of app settings displayed by the system settings app
+ * <p/>
+ * For use only by apps that are included in the system image, for preferences that affect multiple
+ * apps. Location settings that apply only to one app should be shown within that app,
+ * rather than in the system settings.
+ * <p/>
+ * To add a preference to the list, a subclass of {@link SettingInjectorService} must be declared in
+ * the manifest as so:
+ *
+ * <pre>
+ *     &lt;service android:name="com.example.android.injector.MyInjectorService" &gt;
+ *         &lt;intent-filter&gt;
+ *             &lt;action android:name="android.location.SettingInjectorService" /&gt;
+ *         &lt;/intent-filter&gt;
+ *
+ *         &lt;meta-data
+ *             android:name="android.location.SettingInjectorService"
+ *             android:resource="@xml/my_injected_location_setting" /&gt;
+ *     &lt;/service&gt;
+ * </pre>
+ * The resource file specifies the static data for the setting:
+ * <pre>
+ *     &lt;injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+ *         android:title="@string/injected_setting_title"
+ *         android:icon="@drawable/ic_acme_corp"
+ *         android:settingsActivity="com.example.android.injector.MySettingActivity"
+ *     /&gt;
+ * </pre>
+ * Here:
+ * <ul>
+ *     <li>title: The {@link android.preference.Preference#getTitle()} value. The title should make
+ *     it clear which apps are affected by the setting, typically by including the name of the
+ *     developer. For example, "Acme Corp. ads preferences." </li>
+ *
+ *     <li>icon: The {@link android.preference.Preference#getIcon()} value. Typically this will be a
+ *     generic icon for the developer rather than the icon for an individual app.</li>
+ *
+ *     <li>settingsActivity: the activity which is launched to allow the user to modify the setting
+ *     value.  The activity must be in the same package as the subclass of
+ *     {@link SettingInjectorService}. The activity should use your own branding to help emphasize
+ *     to the user that it is not part of the system settings.</li>
+ * </ul>
+ *
+ * To ensure a good user experience, your {@link android.app.Application#onCreate()},
+ * {@link #onGetSummary()}, and {@link #onGetEnabled()} methods must all be fast. If any are slow,
+ * it can delay the display of settings values for other apps as well. Note further that all are
+ * called on your app's UI thread.
+ * <p/>
+ * For compactness, only one copy of a given setting should be injected. If each account has a
+ * distinct value for the setting, then the {@link #onGetSummary()} value should represent a summary
+ * of the state across all of the accounts and {@code settingsActivity} should display the value for
+ * each account.
+ */
+public abstract class SettingInjectorService extends Service {
+
+    private static final String TAG = "SettingInjectorService";
+
+    /**
+     * Intent action that must be declared in the manifest for the subclass. Used to start the
+     * service to read the dynamic status for the setting.
+     */
+    public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
+
+    /**
+     * Name of the meta-data tag used to specify the resource file that includes the settings
+     * attributes.
+     */
+    public static final String META_DATA_NAME = "android.location.SettingInjectorService";
+
+    /**
+     * Name of the XML tag that includes the attributes for the setting.
+     */
+    public static final String ATTRIBUTES_NAME = "injected-location-setting";
+
+    /**
+     * Intent action a client should broadcast when the value of one of its injected settings has
+     * changed, so that the setting can be updated in the UI.
+     */
+    public static final String ACTION_INJECTED_SETTING_CHANGED =
+            "android.location.InjectedSettingChanged";
+
+    /**
+     * Name of the bundle key for the string specifying the summary for the setting (e.g., "ON" or
+     * "OFF").
+     *
+     * @hide
+     */
+    public static final String SUMMARY_KEY = "summary";
+
+    /**
+     * Name of the bundle key for the string specifying whether the setting is currently enabled.
+     *
+     * @hide
+     */
+    public static final String ENABLED_KEY = "enabled";
+
+    /**
+     * Name of the intent key used to specify the messenger
+     *
+     * @hide
+     */
+    public static final String MESSENGER_KEY = "messenger";
+
+    private final String mName;
+
+    /**
+     * Constructor.
+     *
+     * @param name used to identify your subclass in log messages
+     */
+    public SettingInjectorService(String name) {
+        mName = name;
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public final void onStart(Intent intent, int startId) {
+        super.onStart(intent, startId);
+    }
+
+    @Override
+    public final int onStartCommand(Intent intent, int flags, int startId) {
+        onHandleIntent(intent);
+        stopSelf(startId);
+        return START_NOT_STICKY;
+    }
+
+    private void onHandleIntent(Intent intent) {
+
+        String summary;
+        try {
+            summary = onGetSummary();
+        } catch (RuntimeException e) {
+            // Exception. Send status anyway, so that settings injector can immediately start
+            // loading the status of the next setting.
+            sendStatus(intent, null, true);
+            throw e;
+        }
+
+        boolean enabled;
+        try {
+            enabled = onGetEnabled();
+        } catch (RuntimeException e) {
+            // Exception. Send status anyway, so that settings injector can immediately start
+            // loading the status of the next setting.
+            sendStatus(intent, summary, true);
+            throw e;
+        }
+
+        sendStatus(intent, summary, enabled);
+    }
+
+    /**
+     * Send the summary and enabled values back to the caller via the messenger encoded in the
+     * intent.
+     */
+    private void sendStatus(Intent intent, String summary, boolean enabled) {
+        Message message = Message.obtain();
+        Bundle bundle = new Bundle();
+        bundle.putString(SUMMARY_KEY, summary);
+        bundle.putBoolean(ENABLED_KEY, enabled);
+        message.setData(bundle);
+
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, mName + ": received " + intent + ", summary=" + summary
+                    + ", enabled=" + enabled + ", sending message: " + message);
+        }
+
+        Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY);
+        try {
+            messenger.send(message);
+        } catch (RemoteException e) {
+            Log.e(TAG, mName + ": sending dynamic status failed", e);
+        }
+    }
+
+    /**
+     * Returns the {@link android.preference.Preference#getSummary()} value (allowed to be null or
+     * empty). Should not perform unpredictably-long operations such as network access--see the
+     * running-time comments in the class-level javadoc.
+     *
+     * @return the {@link android.preference.Preference#getSummary()} value
+     */
+    protected abstract String onGetSummary();
+
+    /**
+     * Returns the {@link android.preference.Preference#isEnabled()} value. Should not perform
+     * unpredictably-long operations such as network access--see the running-time comments in the
+     * class-level javadoc.
+     * <p/>
+     * Note that to prevent churn in the settings list, there is no support for dynamically choosing
+     * to hide a setting. Instead you should have this method return false, which will disable the
+     * setting and its link to your setting activity. One reason why you might choose to do this is
+     * if {@link android.provider.Settings.Secure#LOCATION_MODE} is {@link
+     * android.provider.Settings.Secure#LOCATION_MODE_OFF}.
+     * <p/>
+     * It is possible that the user may click on the setting before this method returns, so your
+     * settings activity must handle the case where it is invoked even though the setting is
+     * disabled. The simplest approach may be to simply call {@link android.app.Activity#finish()}
+     * when disabled.
+     *
+     * @return the {@link android.preference.Preference#isEnabled()} value
+     */
+    protected abstract boolean onGetEnabled();
+}
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
new file mode 100644
index 0000000..bc5a8a1
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
@@ -0,0 +1,280 @@
+/*
+ * 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.location.provider;
+
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+
+import android.location.Location;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class that exposes IFusedLocationHardware functionality to unbundled services.
+ */
+public final class FusedLocationHardware {
+    private final String TAG = "FusedLocationHardware";
+
+    private IFusedLocationHardware mLocationHardware;
+
+    // the list uses a copy-on-write pattern to update its contents
+    HashMap<FusedLocationHardwareSink, DispatcherHandler> mSinkList =
+            new HashMap<FusedLocationHardwareSink, DispatcherHandler>();
+
+    private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
+        @Override
+        public void onLocationAvailable(Location[] locations) {
+            dispatchLocations(locations);
+        }
+
+        @Override
+        public void onDiagnosticDataAvailable(String data) {
+            dispatchDiagnosticData(data);
+        }
+    };
+
+    /**
+     * @hide
+     */
+    public FusedLocationHardware(IFusedLocationHardware locationHardware) {
+        mLocationHardware = locationHardware;
+    }
+
+    /*
+     * Methods to provide a Facade for IFusedLocationHardware
+     */
+    public void registerSink(FusedLocationHardwareSink sink, Looper looper) {
+        if(sink == null || looper == null) {
+            throw new IllegalArgumentException("Parameter sink and looper cannot be null.");
+        }
+
+        boolean registerSink;
+        synchronized (mSinkList) {
+            // register only on first insertion
+            registerSink = mSinkList.size() == 0;
+            // guarantee uniqueness
+            if(mSinkList.containsKey(sink)) {
+                return;
+            }
+
+            HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
+                    new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
+            newSinkList.put(sink, new DispatcherHandler(looper));
+            mSinkList = newSinkList;
+        }
+
+        if(registerSink) {
+            try {
+                mLocationHardware.registerSink(mInternalSink);
+            } catch(RemoteException e) {
+                Log.e(TAG, "RemoteException at registerSink");
+            }
+        }
+    }
+
+    public void unregisterSink(FusedLocationHardwareSink sink) {
+        if(sink == null) {
+            throw new IllegalArgumentException("Parameter sink cannot be null.");
+        }
+
+        boolean unregisterSink;
+        synchronized(mSinkList) {
+            if(!mSinkList.containsKey(sink)) {
+                //done
+                return;
+            }
+
+            HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
+                    new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
+            newSinkList.remove(sink);
+            //unregister after the last sink
+            unregisterSink = newSinkList.size() == 0;
+
+            mSinkList = newSinkList;
+        }
+
+        if(unregisterSink) {
+            try {
+                mLocationHardware.unregisterSink(mInternalSink);
+            } catch(RemoteException e) {
+                Log.e(TAG, "RemoteException at unregisterSink");
+            }
+        }
+    }
+
+    public int getSupportedBatchSize() {
+        try {
+            return mLocationHardware.getSupportedBatchSize();
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at getSupportedBatchSize");
+            return 0;
+        }
+    }
+
+    public void startBatching(int id, GmsFusedBatchOptions batchOptions) {
+        try {
+            mLocationHardware.startBatching(id, batchOptions.getParcelableOptions());
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at startBatching");
+        }
+    }
+
+    public void stopBatching(int id) {
+        try {
+            mLocationHardware.stopBatching(id);
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at stopBatching");
+        }
+    }
+
+    public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) {
+        try {
+            mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions());
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at updateBatchingOptions");
+        }
+    }
+
+    public void requestBatchOfLocations(int batchSizeRequest) {
+        try {
+            mLocationHardware.requestBatchOfLocations(batchSizeRequest);
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at requestBatchOfLocations");
+        }
+    }
+
+    public boolean supportsDiagnosticDataInjection() {
+        try {
+            return mLocationHardware.supportsDiagnosticDataInjection();
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection");
+            return false;
+        }
+    }
+
+    public void injectDiagnosticData(String data) {
+        try {
+            mLocationHardware.injectDiagnosticData(data);
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at injectDiagnosticData");
+        }
+    }
+
+    public boolean supportsDeviceContextInjection() {
+        try {
+            return mLocationHardware.supportsDeviceContextInjection();
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at supportsDeviceContextInjection");
+            return false;
+        }
+    }
+
+    public void injectDeviceContext(int deviceEnabledContext) {
+        try {
+            mLocationHardware.injectDeviceContext(deviceEnabledContext);
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at injectDeviceContext");
+        }
+    }
+
+    /*
+     * Helper methods and classes
+     */
+    private class DispatcherHandler extends Handler {
+        public static final int DISPATCH_LOCATION = 1;
+        public static final int DISPATCH_DIAGNOSTIC_DATA = 2;
+
+        public DispatcherHandler(Looper looper) {
+            super(looper, null /*callback*/ , true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            MessageCommand command = (MessageCommand) message.obj;
+            switch(message.what) {
+                case DISPATCH_LOCATION:
+                    command.dispatchLocation();
+                    break;
+                case DISPATCH_DIAGNOSTIC_DATA:
+                    command.dispatchDiagnosticData();
+                default:
+                    Log.e(TAG, "Invalid dispatch message");
+                    break;
+            }
+        }
+    }
+
+    private class MessageCommand {
+        private final FusedLocationHardwareSink mSink;
+        private final Location[] mLocations;
+        private final String mData;
+
+        public MessageCommand(
+                FusedLocationHardwareSink sink,
+                Location[] locations,
+                String data) {
+            mSink = sink;
+            mLocations = locations;
+            mData = data;
+        }
+
+        public void dispatchLocation() {
+            mSink.onLocationAvailable(mLocations);
+        }
+
+        public void dispatchDiagnosticData() {
+            mSink.onDiagnosticDataAvailable(mData);
+        }
+    }
+
+    private void dispatchLocations(Location[] locations) {
+        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
+        synchronized (mSinkList) {
+            sinks = mSinkList;
+        }
+
+        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
+            Message message = Message.obtain(
+                    entry.getValue(),
+                    DispatcherHandler.DISPATCH_LOCATION,
+                    new MessageCommand(entry.getKey(), locations, null /*data*/));
+            message.sendToTarget();
+        }
+    }
+
+    private void dispatchDiagnosticData(String data) {
+        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
+        synchronized(mSinkList) {
+            sinks = mSinkList;
+        }
+
+        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
+            Message message = Message.obtain(
+                    entry.getValue(),
+                    DispatcherHandler.DISPATCH_DIAGNOSTIC_DATA,
+                    new MessageCommand(entry.getKey(), null /*locations*/, data));
+            message.sendToTarget();
+        }
+    }
+}
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
new file mode 100644
index 0000000..2c39fa8
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
@@ -0,0 +1,30 @@
+/*
+ * 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.location.provider;
+
+import android.location.Location;
+
+/**
+ * Base class for sinks to interact with FusedLocationHardware.
+ */
+public abstract class FusedLocationHardwareSink {
+    /*
+     * Methods to provide a facade for IFusedLocationHardware
+     */
+    public abstract void onLocationAvailable(Location[] locations);
+    public abstract void onDiagnosticDataAvailable(String data);
+}
\ No newline at end of file
diff --git a/location/lib/java/com/android/location/provider/FusedProvider.java b/location/lib/java/com/android/location/provider/FusedProvider.java
new file mode 100644
index 0000000..c966ade
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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.location.provider;
+
+import android.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.IBinder;
+
+/**
+ * Base class for Fused providers implemented as unbundled services.
+ *
+ * <p>Fused providers can be implemented as services and return the result of
+ * {@link com.android.location.provider.FusedProvider#getBinder()} in its getBinder() method.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
+ * API stable. See README.txt in the root of this package for more information.
+ */
+public abstract class FusedProvider {
+    private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() {
+        @Override
+        public void onFusedLocationHardwareChange(IFusedLocationHardware instance) {
+            setFusedLocationHardware(new FusedLocationHardware(instance));
+        }
+    };
+
+    /**
+     * Gets the Binder associated with the provider.
+     * This is intended to be used for the onBind() method of a service that implements a fused
+     * service.
+     *
+     * @return The IBinder instance associated with the provider.
+     */
+    public IBinder getBinder() {
+        return mProvider;
+    }
+
+    /**
+     * Sets the FusedLocationHardware instance in the provider..
+     * @param value     The instance to set. This can be null in cases where the service connection
+     *                  is disconnected.
+     */
+    public abstract void setFusedLocationHardware(FusedLocationHardware value);
+}
diff --git a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
new file mode 100644
index 0000000..fd3f402
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
@@ -0,0 +1,106 @@
+/*
+ * 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.location.provider;
+
+import android.location.FusedBatchOptions;
+
+/**
+ * Class that exposes FusedBatchOptions to the GmsCore .
+ */
+public class GmsFusedBatchOptions {
+    private FusedBatchOptions mOptions = new FusedBatchOptions();
+
+    /*
+     * Methods that provide a facade for properties in FusedBatchOptions.
+     */
+    public void setMaxPowerAllocationInMW(double value) {
+        mOptions.setMaxPowerAllocationInMW(value);
+    }
+
+    public double getMaxPowerAllocationInMW() {
+        return mOptions.getMaxPowerAllocationInMW();
+    }
+
+    public void setPeriodInNS(long value) {
+        mOptions.setPeriodInNS(value);
+    }
+
+    public long getPeriodInNS() {
+        return mOptions.getPeriodInNS();
+    }
+
+    public void setSourceToUse(int source) {
+        mOptions.setSourceToUse(source);
+    }
+
+    public void resetSourceToUse(int source) {
+        mOptions.resetSourceToUse(source);
+    }
+
+    public boolean isSourceToUseSet(int source) {
+        return mOptions.isSourceToUseSet(source);
+    }
+
+    public int getSourcesToUse() {
+        return mOptions.getSourcesToUse();
+    }
+
+    public void setFlag(int flag) {
+        mOptions.setFlag(flag);
+    }
+
+    public void resetFlag(int flag) {
+        mOptions.resetFlag(flag);
+    }
+
+    public boolean isFlagSet(int flag) {
+        return mOptions.isFlagSet(flag);
+    }
+
+    public int getFlags() {
+        return mOptions.getFlags();
+    }
+
+    /**
+     * Definition of enum flag sets needed by this class.
+     * Such values need to be kept in sync with the ones in fused_location.h
+     */
+
+    public static final class SourceTechnologies {
+        public static int GNSS = 1<<0;
+        public static int WIFI = 1<<1;
+        public static int SENSORS = 1<<2;
+        public static int CELL = 1<<3;
+        public static int BLUETOOTH = 1<<4;
+    }
+
+    public static final class BatchFlags {
+        public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+        public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+    }
+
+    /*
+     * Method definitions for internal use.
+     */
+
+    /*
+     * @hide
+     */
+    public FusedBatchOptions getParcelableOptions() {
+        return mOptions;
+    }
+}
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 8a5a739..150c289 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -35,6 +35,7 @@
 import com.android.internal.location.ILocationProvider;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.FastPrintWriter;
 
 /**
  * Base class for location providers implemented as unbundled services.
@@ -106,7 +107,7 @@
         }
         @Override
         public void dump(FileDescriptor fd, String[] args) {
-            PrintWriter pw = new PrintWriter(new FileOutputStream(fd));
+            PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
             onDump(fd, pw, args);
             pw.flush();
         }
diff --git a/media/java/android/drm/mobile1/DrmConstraintInfo.java b/media/java/android/drm/mobile1/DrmConstraintInfo.java
deleted file mode 100644
index 50ae8bd..0000000
--- a/media/java/android/drm/mobile1/DrmConstraintInfo.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.drm.mobile1;
-
-import java.util.Date;
-
-/**
- * This class provides interfaces to access the DRM constraint.
- */
-public class DrmConstraintInfo {
-    /**
-     * The constraint of count.
-     */
-    private int count;
-
-    /**
-     * The constraint of start date.
-     */
-    private long startDate;
-
-    /**
-     * The constraint of end date.
-     */
-    private long endDate;
-
-    /**
-     * The constraint of interval.
-     */
-    private long interval;
-
-    /**
-     * Construct the DrmConstraint.
-     */
-    DrmConstraintInfo() {
-        count = -1;
-        startDate = -1;
-        endDate = -1;
-        interval = -1;
-    }
-
-    /**
-     * Get the count constraint.
-     *
-     * @return the count or -1 if no limit.
-     */
-    public int getCount() {
-        return count;
-    }
-
-    /**
-     * Get the start date constraint.
-     *
-     * @return the start date or null if no limit.
-     */
-    public Date getStartDate() {
-        if (startDate == -1)
-            return null;
-
-        return new Date(startDate);
-    }
-
-    /**
-     * Get the end date constraint.
-     *
-     * @return the end date or null if no limit.
-     */
-    public Date getEndDate() {
-        if (endDate == -1)
-            return null;
-
-        return new Date(endDate);
-    }
-
-    /**
-     * Get the Interval constraint.
-     *
-     * @return the interval or -1 if no limit.
-     */
-    public long getInterval() {
-        return interval;
-    }
-}
diff --git a/media/java/android/drm/mobile1/DrmException.java b/media/java/android/drm/mobile1/DrmException.java
deleted file mode 100644
index 7b06c92..0000000
--- a/media/java/android/drm/mobile1/DrmException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.drm.mobile1;
-
-import java.io.IOException;
-
-/**
- * A DrmException is thrown to report errors specific to handle DRM content and rights.
- */
-public class DrmException extends Exception
-{
-    // TODO: add more specific DRM error codes.
-    
-    private DrmException() {
-    }
-    
-    public DrmException(String message) {
-        super(message);
-    }
-}
diff --git a/media/java/android/drm/mobile1/DrmRawContent.java b/media/java/android/drm/mobile1/DrmRawContent.java
deleted file mode 100644
index 046b84a..0000000
--- a/media/java/android/drm/mobile1/DrmRawContent.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.drm.mobile1;
-
-import java.io.*;
-
-/**
- * This class provides interfaces to access the DRM raw content.
- */
-public class DrmRawContent {
-    /**
-     * The "application/vnd.oma.drm.message" mime type.
-     */
-    public static final String DRM_MIMETYPE_MESSAGE_STRING = "application/vnd.oma.drm.message";
-
-    /**
-     * The "application/vnd.oma.drm.content" mime type.
-     */
-    public static final String DRM_MIMETYPE_CONTENT_STRING = "application/vnd.oma.drm.content";
-
-    /**
-     * The DRM delivery type: Forward-Lock
-     */
-    public static final int DRM_FORWARD_LOCK = 1;
-
-    /**
-     * The DRM delivery type: Combined Delivery
-     */
-    public static final int DRM_COMBINED_DELIVERY = 2;
-
-    /**
-     * The DRM delivery type: Separate Delivery
-     */
-    public static final int DRM_SEPARATE_DELIVERY = 3;
-
-    /**
-     * The DRM delivery type: Separate Delivery in DRM message
-     */
-    public static final int DRM_SEPARATE_DELIVERY_DM = 4;
-
-    /**
-     * The DRM media content length is unknown currently
-     */
-    public static final int DRM_UNKNOWN_DATA_LEN = -1;
-
-
-    /**
-     * The id of "application/vnd.oma.drm.message" mime type.
-     */
-    private static final int DRM_MIMETYPE_MESSAGE = 1;
-
-    /**
-     * The id of "application/vnd.oma.drm.content" mime type.
-     */
-    private static final int DRM_MIMETYPE_CONTENT = 2;
-
-    /**
-     * Successful operation.
-     */
-    private static final int JNI_DRM_SUCCESS = 0;
-
-    /**
-     * General failure.
-     */
-    private static final int JNI_DRM_FAILURE = -1;
-
-    /**
-     * Indicates the end of the DRM content is reached.
-     */
-    private static final int JNI_DRM_EOF = -2;
-
-    /**
-     * The media content length is unknown from native method
-     */
-    private static final int JNI_DRM_UNKNOWN_DATA_LEN = -3;
-
-    /**
-     * The member to save the original InputStream data.
-     */
-    private BufferedInputStream inData;
-
-    /**
-     * The member to save the original InputStream data length.
-     */
-    private int inDataLen;
-
-    /**
-     * The unique id to this DRM content. It will be initialized
-     * in constructor by native method. And it will not be changed
-     * after initialization.
-     */
-    private int id;
-
-    /**
-     * The rights issuer address of this DRM object.
-     */
-    private String rightsIssuer;
-
-    /**
-     * The media content type of this DRM object.
-     */
-    private String mediaType;
-
-    /**
-     * The delivery method type of this DRM object.
-     */
-    private int rawType;
-
-
-    /**
-     * Construct a DrmRawContent object.
-     *
-     * @param inRawdata     object of DRM raw data stream.
-     * @param len           the length of raw data can be read.
-     * @param mimeTypeStr   the mime type of the DRM content.
-     */
-    public DrmRawContent(InputStream inRawdata, int len, String mimeTypeStr) throws DrmException, IOException {
-        int mimeType;
-
-        id = -1;
-        inData = new BufferedInputStream(inRawdata, 1024);
-        inDataLen = len;
-
-        if (DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr))
-            mimeType = DRM_MIMETYPE_MESSAGE;
-        else if (DRM_MIMETYPE_CONTENT_STRING.equals(mimeTypeStr))
-            mimeType = DRM_MIMETYPE_CONTENT;
-        else
-            throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_MESSAGE or DRM_MIMETYPE_CONTENT");
-
-        if (len <= 0)
-            throw new IllegalArgumentException("len must be > 0");
-
-        /* call native method to initialize this DRM content */
-        id = nativeConstructDrmContent(inData, inDataLen, mimeType);
-
-        if (JNI_DRM_FAILURE == id)
-            throw new DrmException("nativeConstructDrmContent() returned JNI_DRM_FAILURE");
-
-        /* init the rights issuer field. */
-        rightsIssuer = nativeGetRightsAddress();
-
-        /* init the raw content type. */
-        rawType = nativeGetDeliveryMethod();
-        if (JNI_DRM_FAILURE == rawType)
-            throw new DrmException("nativeGetDeliveryMethod() returned JNI_DRM_FAILURE");
-
-        /* init the media content type. */
-        mediaType = nativeGetContentType();
-        if (null == mediaType)
-            throw new DrmException("nativeGetContentType() returned null");
-    }
-
-    /**
-     * Get rights address from raw Seperate Delivery content.
-     *
-     * @return the string of the rights issuer address,
-     *         or null if no rights issuer.
-     */
-    public String getRightsAddress() {
-        return rightsIssuer;
-    }
-
-    /**
-     * Get the type of the raw DRM content.
-     *
-     * @return one of the following delivery type of this DRM content:
-     *              #DRM_FORWARD_LOCK
-     *              #DRM_COMBINED_DELIVERY
-     *              #DRM_SEPARATE_DELIVERY
-     *              #DRM_SEPARATE_DELIVERY_DM
-     */
-    public int getRawType() {
-        return rawType;
-    }
-
-    /**
-     * Get one InputStream object to read decrypted content.
-     *
-     * @param rights        the rights object contain decrypted key.
-     *
-     * @return the InputStream object of decrypted media content.
-     */
-    public InputStream getContentInputStream(DrmRights rights) {
-        if (null == rights)
-            throw new NullPointerException();
-
-        return new DrmInputStream(rights);
-    }
-
-    /**
-     * Get the type of the decrypted media content.
-     *
-     * @return the decrypted media content type of this DRM content.
-     */
-    public String getContentType() {
-        return mediaType;
-    }
-
-    /**
-     * Get the length of the decrypted media content.
-     *
-     * @param rights        the rights object contain decrypted key.
-     *
-     * @return the length of the decrypted media content.
-     *         #DRM_UNKNOWN_DATA_LEN if the length is unknown currently.
-     */
-    public int getContentLength(DrmRights rights) throws DrmException {
-        /**
-         * Because currently the media object associate with rights object
-         * has been handled in native logic, so here it is not need to deal
-         * the rights. But for the apps, it is mandatory for user to get
-         * the rights object before get the media content length.
-         */
-        if (null == rights)
-            throw new NullPointerException();
-
-        int mediaLen = nativeGetContentLength();
-
-        if (JNI_DRM_FAILURE == mediaLen)
-            throw new DrmException("nativeGetContentLength() returned JNI_DRM_FAILURE");
-
-        if (JNI_DRM_UNKNOWN_DATA_LEN == mediaLen)
-            return DRM_UNKNOWN_DATA_LEN;
-
-        return mediaLen;
-    }
-
-    /**
-     * This class provide a InputStream to the DRM media content.
-     */
-    class DrmInputStream extends InputStream
-    {
-        /**
-         * The flag to indicate whether this stream is closed or not.
-         */
-        private boolean isClosed;
-
-        /**
-         * The offset of this DRM content to be reset.
-         */
-        private int offset;
-
-        /**
-         * A byte of data to be readed.
-         */
-        private byte[] b;
-
-        /**
-         * Construct a DrmInputStream instance.
-         */
-        public DrmInputStream(DrmRights rights) {
-            /**
-             * Because currently the media object associate with rights object
-             * has been handled in native logic, so here it is not need to deal
-             * the rights. But for the apps, it is mandatory for user to get
-             * the rights object before get the media content data.
-             */
-
-            isClosed = false;
-            offset = 0;
-            b = new byte[1];
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#available()
-         */
-        public int available() throws IOException {
-            /* call native method to get this DRM decrypted media content length */
-            int len = nativeGetContentLength();
-
-            if (JNI_DRM_FAILURE == len)
-                throw new IOException();
-
-            /* if the length is unknown, just return 0 for available value */
-            if (JNI_DRM_UNKNOWN_DATA_LEN == len)
-                return 0;
-
-            int availableLen = len - offset;
-            if (availableLen < 0)
-                throw new IOException();
-
-            return availableLen;
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#read()
-         */
-        public int read() throws IOException {
-            int res;
-
-            res = read(b, 0, 1);
-
-            if (-1 == res)
-                return -1;
-
-            return b[0] & 0xff;
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#read(byte)
-         */
-        public int read(byte[] b) throws IOException {
-            return read(b, 0, b.length);
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#read(byte, int, int)
-         */
-        public int read(byte[] b, int off, int len) throws IOException {
-            if (null == b)
-                throw new NullPointerException();
-            if (off < 0 || len < 0 || off + len > b.length)
-                throw new IndexOutOfBoundsException();
-            if (true == isClosed)
-                throw new IOException();
-
-            if (0 == len)
-                return 0;
-
-            len = nativeReadContent(b, off, len, offset);
-
-            if (JNI_DRM_FAILURE == len)
-                throw new IOException();
-            else if (JNI_DRM_EOF == len)
-                return -1;
-
-            offset += len;
-
-            return len;
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#markSupported()
-         */
-        public boolean markSupported() {
-            return false;
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#mark(int)
-         */
-        public void mark(int readlimit) {
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#reset()
-         */
-        public void reset() throws IOException {
-            throw new IOException();
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#skip()
-         */
-        public long skip(long n) throws IOException {
-            return 0;
-        }
-
-        /* Non-javadoc
-         * @see java.io.InputStream#close()
-         */
-        public void close() {
-            isClosed = true;
-        }
-    }
-
-    /**
-     * native method: construct a DRM content according the mime type.
-     *
-     * @param data      input DRM content data to be parsed.
-     * @param len       the length of the data.
-     * @param mimeType  the mime type of this DRM content. the value of this field includes:
-     *                      #DRM_MIMETYPE_MESSAGE
-     *                      #DRM_MIMETYPE_CONTENT
-     *
-     * @return #the id of the DRM content if succeed.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeConstructDrmContent(InputStream data, int len, int mimeType);
-
-    /**
-     * native method: get this DRM content rights issuer.
-     *
-     * @return the address of rights issuer if in case of separate delivery.
-     *         null if not separete delivery, or otherwise.
-     */
-    private native String nativeGetRightsAddress();
-
-    /**
-     * native method: get this DRM content delivery type.
-     *
-     * @return the delivery method, the value may be one of the following:
-     *              #DRM_FORWARD_LOCK
-     *              #DRM_COMBINED_DELIVERY
-     *              #DRM_SEPARATE_DELIVERY
-     *              #DRM_SEPARATE_DELIVERY_DM
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeGetDeliveryMethod();
-
-    /**
-     * native method: get a piece of media content data.
-     *
-     * @param buf       the buffer to save DRM media content data.
-     * @param bufOff    the offset of the buffer to start to save data.
-     * @param len       the number of byte to read.
-     * @param mediaOff  the offset of the media content data to start to read.
-     *
-     * @return the length of the media content data has been read.
-     *         #JNI_DRM_EOF if reach to end of the media content.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeReadContent(byte[] buf, int bufOff, int len, int mediaOff);
-
-    /**
-     * native method: get this DRM content type.
-     *
-     * @return the decrypted media content type.
-     *         null if fail.
-     */
-    private native String nativeGetContentType();
-
-    /**
-     * native method: get this DRM decrypted media content length.
-     *
-     * @return the length of decrypted media content.
-     *         #JNI_DRM_FAILURE if fail.
-     *         #JNI_DRM_UNKNOWN_DATA_LEN if the length is unknown currently.
-     */
-    private native int nativeGetContentLength();
-
-    /**
-     * The finalizer of the DRMRawContent. Do some cleanup.
-     */
-    protected native void finalize();
-
-
-    /**
-     * Load the shared library to link the native methods.
-     */
-    static {
-        try {
-            System.loadLibrary("drm1_jni");
-        }
-        catch (UnsatisfiedLinkError ule) {
-            System.err.println("WARNING: Could not load libdrm1_jni.so");
-        }
-    }
-}
diff --git a/media/java/android/drm/mobile1/DrmRights.java b/media/java/android/drm/mobile1/DrmRights.java
deleted file mode 100644
index bcccb6a..0000000
--- a/media/java/android/drm/mobile1/DrmRights.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.drm.mobile1;
-
-/**
- * This class provides interfaces to access the DRM rights.
- */
-public class DrmRights {
-    /**
-     * The DRM permission of play.
-     */
-    public static final int DRM_PERMISSION_PLAY = 1;
-
-    /**
-     * The DRM permission of display.
-     */
-    public static final int DRM_PERMISSION_DISPLAY = 2;
-
-    /**
-     * The DRM permission of execute.
-     */
-    public static final int DRM_PERMISSION_EXECUTE = 3;
-
-    /**
-     * The DRM permission of print.
-     */
-    public static final int DRM_PERMISSION_PRINT = 4;
-
-    /**
-     * Successful operation.
-     */
-    private static final int JNI_DRM_SUCCESS = 0;
-
-    /**
-     * General failure.
-     */
-    private static final int JNI_DRM_FAILURE = -1;
-
-    /**
-     * The uid of this rights object.
-     */
-    private String roId = "";
-
-
-    /**
-     * Construct the DrmRights.
-     */
-    public DrmRights() {
-    }
-
-    /**
-     * Get the constraint of the given permission on this rights object.
-     *
-     * @param permission    the given permission.
-     *
-     * @return a DrmConstraint instance.
-     */
-    public DrmConstraintInfo getConstraint(int permission) {
-        DrmConstraintInfo c = new DrmConstraintInfo();
-
-        /* call native method to get latest constraint information */
-        int res = nativeGetConstraintInfo(permission, c);
-
-        if (JNI_DRM_FAILURE == res)
-            return null;
-
-        return c;
-    }
-
-    /**
-     * Consume the rights of the given permission.
-     *
-     * @param permission    the given permission.
-     *
-     * @return true if consume success.
-     *         false if consume failure.
-     */
-    public boolean consumeRights(int permission) {
-        /* call native method to consume and update rights */
-        int res = nativeConsumeRights(permission);
-
-        if (JNI_DRM_FAILURE == res)
-            return false;
-
-        return true;
-    }
-
-
-    /**
-     * native method: get the constraint information of the given permission.
-     *
-     * @param permission    the given permission.
-     * @param constraint    the instance of constraint.
-     *
-     * @return #JNI_DRM_SUCCESS if succeed.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeGetConstraintInfo(int permission, DrmConstraintInfo constraint);
-
-    /**
-     * native method: consume the rights of the given permission.
-     *
-     * @param permission    the given permission.
-     *
-     * @return #JNI_DRM_SUCCESS if succeed.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeConsumeRights(int permission);
-
-
-    /**
-     * Load the shared library to link the native methods.
-     */
-    static {
-        try {
-            System.loadLibrary("drm1_jni");
-        }
-        catch (UnsatisfiedLinkError ule) {
-            System.err.println("WARNING: Could not load libdrm1_jni.so");
-        }
-    }
-}
diff --git a/media/java/android/drm/mobile1/DrmRightsManager.java b/media/java/android/drm/mobile1/DrmRightsManager.java
deleted file mode 100644
index 1bc36ec..0000000
--- a/media/java/android/drm/mobile1/DrmRightsManager.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.drm.mobile1;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * This class provides interfaces to access the DRM right manager.
- */
-public class DrmRightsManager {
-    /**
-     * The "application/vnd.oma.drm.rights+xml" mime type.
-     */
-    public static final String DRM_MIMETYPE_RIGHTS_XML_STRING = "application/vnd.oma.drm.rights+xml";
-
-    /**
-     * The "application/vnd.oma.drm.rights+wbxml" mime type.
-     */
-    public static final String DRM_MIMETYPE_RIGHTS_WBXML_STRING = "application/vnd.oma.drm.rights+wbxml";
-
-    /**
-     * The id of "application/vnd.oma.drm.rights+xml" mime type.
-     */
-    private static final int DRM_MIMETYPE_RIGHTS_XML = 3;
-
-    /**
-     * The id of "application/vnd.oma.drm.rights+wbxml" mime type.
-     */
-    private static final int DRM_MIMETYPE_RIGHTS_WBXML = 4;
-
-    /**
-     * The id of "application/vnd.oma.drm.message" mime type.
-     */
-    private static final int DRM_MIMETYPE_MESSAGE = 1;
-
-    /**
-     * Successful operation.
-     */
-    private static final int JNI_DRM_SUCCESS = 0;
-
-    /**
-     * General failure.
-     */
-    private static final int JNI_DRM_FAILURE = -1;
-
-    /**
-     * The instance of the rights manager.
-     */
-    private static DrmRightsManager singleton = null;
-
-
-    /**
-     * Construct a DrmRightsManager
-     */
-    protected DrmRightsManager() {
-    }
-
-    /**
-     * Get the DrmRightsManager instance.
-     *
-     * @return the instance of DrmRightsManager.
-     */
-    public static synchronized DrmRightsManager getInstance() {
-        if (singleton == null) {
-            singleton = new DrmRightsManager();
-        }
-
-        return singleton;
-    }
-
-    /**
-     * Install one DRM rights and return one instance of DrmRights.
-     *
-     * @param rightsData    raw rights data.
-     * @param mimeTypeStr   the mime type of the rights object.
-     *
-     * @return the instance of the installed DrmRights.
-     */
-    public synchronized DrmRights installRights(InputStream rightsData, int len, String mimeTypeStr) throws DrmException, IOException {
-        int mimeType = 0;
-
-        if (DRM_MIMETYPE_RIGHTS_XML_STRING.equals(mimeTypeStr))
-            mimeType = DRM_MIMETYPE_RIGHTS_XML;
-        else if (DRM_MIMETYPE_RIGHTS_WBXML_STRING.equals(mimeTypeStr))
-            mimeType = DRM_MIMETYPE_RIGHTS_WBXML;
-        else if (DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr))
-            mimeType = DRM_MIMETYPE_MESSAGE;
-        else
-            throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_RIGHTS_XML or DRM_MIMETYPE_RIGHTS_WBXML or DRM_MIMETYPE_MESSAGE");
-
-        if (len <= 0)
-            return null;
-
-        DrmRights rights = new DrmRights();
-
-        /* call native method to install this rights object. */
-        int res = nativeInstallDrmRights(rightsData, len, mimeType, rights);
-
-        if (JNI_DRM_FAILURE == res)
-            throw new DrmException("nativeInstallDrmRights() returned JNI_DRM_FAILURE");
-
-        return rights;
-    }
-
-    /**
-     * Query DRM rights of specified DRM raw content.
-     *
-     * @param content       raw content object.
-     *
-     * @return the instance of DrmRights, or null if there is no rights.
-     */
-    public synchronized DrmRights queryRights(DrmRawContent content) {
-        DrmRights rights = new DrmRights();
-
-        /* call native method to query the rights */
-        int res = nativeQueryRights(content, rights);
-
-        if (JNI_DRM_FAILURE == res)
-            return null;
-
-        return rights;
-    }
-
-    /**
-     * Get the list of all DRM rights saved in local client.
-     *
-     * @return the list of all the rights object.
-     */
-    public synchronized List getRightsList() {
-        List rightsList = new ArrayList();
-
-        /* call native method to get how many rights object in current agent */
-        int num = nativeGetNumOfRights();
-
-        if (JNI_DRM_FAILURE == num)
-            return null;
-
-        if (num > 0) {
-            DrmRights[] rightsArray = new DrmRights[num];
-            int i;
-
-            for (i = 0; i < num; i++)
-                rightsArray[i] = new DrmRights();
-
-            /* call native method to get all the rights information */
-            num = nativeGetRightsList(rightsArray, num);
-
-            if (JNI_DRM_FAILURE == num)
-                return null;
-
-            /* add all rights informations to ArrayList */
-            for (i = 0; i < num; i++)
-                rightsList.add(rightsArray[i]);
-        }
-
-        return rightsList;
-    }
-
-    /**
-     * Delete the specified DRM rights object.
-     *
-     * @param rights    the specified rights object to be deleted.
-     */
-    public synchronized void deleteRights(DrmRights rights) {
-        /* call native method to delete the specified rights object */
-        int res = nativeDeleteRights(rights);
-
-        if (JNI_DRM_FAILURE == res)
-            return;
-    }
-
-
-    /**
-     * native method: install rights object to local client.
-     *
-     * @param data      input DRM rights object data to be installed.
-     * @param len       the length of the data.
-     * @param mimeType  the mime type of this DRM rights object. the value of this field includes:
-     *                      #DRM_MIMETYPE_RIGHTS_XML
-     *                      #DRM_MIMETYPE_RIGHTS_WBXML
-     * @parma rights    the instance of DRMRights to be filled.
-     *
-     * @return #JNI_DRM_SUCCESS if succeed.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeInstallDrmRights(InputStream data, int len, int mimeType, DrmRights rights);
-
-    /**
-     * native method: query the given DRM content's rights object.
-     *
-     * @param content   the given DRM content.
-     * @param rights    the instance of rights to set if have.
-     *
-     * @return #JNI_DRM_SUCCESS if succeed.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeQueryRights(DrmRawContent content, DrmRights rights);
-
-    /**
-     * native method: get how many rights object in current DRM agent.
-     *
-     * @return the number of the rights object.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeGetNumOfRights();
-
-    /**
-     * native method: get all the rights object in current local agent.
-     *
-     * @param rights    the array instance of rights object.
-     * @param numRights how many rights can be saved.
-     *
-     * @return the number of the rights object has been gotten.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeGetRightsList(DrmRights[] rights, int numRights);
-
-    /**
-     * native method: delete a specified rights object.
-     *
-     * @param rights    the specified rights object to be deleted.
-     *
-     * @return #JNI_DRM_SUCCESS if succeed.
-     *         #JNI_DRM_FAILURE if fail.
-     */
-    private native int nativeDeleteRights(DrmRights rights);
-
-
-    /**
-     * Load the shared library to link the native methods.
-     */
-    static {
-        try {
-            System.loadLibrary("drm1_jni");
-        }
-        catch (UnsatisfiedLinkError ule) {
-            System.err.println("WARNING: Could not load libdrm1_jni.so");
-        }
-    }
-}
diff --git a/media/java/android/drm/mobile1/package.html b/media/java/android/drm/mobile1/package.html
deleted file mode 100644
index 1c9bf9d..0000000
--- a/media/java/android/drm/mobile1/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-<body>
-    {@hide}
-</body>
-</html>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 93ab401..c8ee5ad 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.Manifest;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.PendingIntent;
@@ -323,6 +324,12 @@
     public static final int FLAG_FIXED_VOLUME = 1 << 5;
 
     /**
+     * Indicates the volume set/adjust call is for Bluetooth absolute volume
+     * @hide
+     */
+    public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
+
+    /**
      * Ringer mode that will be silent and will not vibrate. (This overrides the
      * vibrate setting.)
      *
@@ -437,6 +444,38 @@
     }
 
     /**
+     * Sends a simulated key event for a media button.
+     * To simulate a key press, you must first send a KeyEvent built with a
+     * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
+     * action.
+     * <p>The key event will be sent to the current media key event consumer which registered with
+     * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
+     * @param keyEvent a {@link KeyEvent} instance whose key code is one of
+     *     {@link KeyEvent#KEYCODE_MUTE},
+     *     {@link KeyEvent#KEYCODE_HEADSETHOOK},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PLAY},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
+     *     {@link KeyEvent#KEYCODE_MEDIA_STOP},
+     *     {@link KeyEvent#KEYCODE_MEDIA_NEXT},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
+     *     {@link KeyEvent#KEYCODE_MEDIA_REWIND},
+     *     {@link KeyEvent#KEYCODE_MEDIA_RECORD},
+     *     {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
+     *     {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
+     *     {@link KeyEvent#KEYCODE_MEDIA_EJECT},
+     *     or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
+     */
+    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        IAudioService service = getService();
+        try {
+            service.dispatchMediaKeyEvent(keyEvent);
+        } catch (RemoteException e) {
+            Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+        }
+    }
+
+    /**
      * @hide
      */
     public void preDispatchKeyEvent(KeyEvent event, int stream) {
@@ -551,9 +590,10 @@
         IAudioService service = getService();
         try {
             if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags);
+                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
             } else {
-                service.adjustStreamVolume(streamType, direction, flags);
+                service.adjustStreamVolume(streamType, direction, flags,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustStreamVolume", e);
@@ -581,9 +621,9 @@
         IAudioService service = getService();
         try {
             if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags);
+                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
             } else {
-                service.adjustVolume(direction, flags);
+                service.adjustVolume(direction, flags, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustVolume", e);
@@ -611,9 +651,10 @@
         IAudioService service = getService();
         try {
             if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags);
+                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
             } else {
-                service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+                service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
@@ -632,7 +673,7 @@
     public void adjustMasterVolume(int steps, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustMasterVolume(steps, flags);
+            service.adjustMasterVolume(steps, flags, mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustMasterVolume", e);
         }
@@ -784,9 +825,9 @@
         IAudioService service = getService();
         try {
             if (mUseMasterVolume) {
-                service.setMasterVolume(index, flags);
+                service.setMasterVolume(index, flags, mContext.getOpPackageName());
             } else {
-                service.setStreamVolume(streamType, index, flags);
+                service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setStreamVolume", e);
@@ -843,16 +884,16 @@
      * Sets the volume index for master volume.
      *
      * @param index The volume index to set. See
-     *            {@link #getMasterMaxVolume(int)} for the largest valid value.
+     *            {@link #getMasterMaxVolume()} for the largest valid value.
      * @param flags One or more flags.
-     * @see #getMasterMaxVolume(int)
-     * @see #getMasterVolume(int)
+     * @see #getMasterMaxVolume()
+     * @see #getMasterVolume()
      * @hide
      */
     public void setMasterVolume(int index, int flags) {
         IAudioService service = getService();
         try {
-            service.setMasterVolume(index, flags);
+            service.setMasterVolume(index, flags, mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setMasterVolume", e);
         }
@@ -1314,19 +1355,6 @@
     }
 
     /**
-     * @hide
-     * Signals whether remote submix audio rerouting is enabled.
-     */
-    public void setRemoteSubmixOn(boolean on, int address) {
-        IAudioService service = getService();
-        try {
-            service.setRemoteSubmixOn(on, address);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setRemoteSubmixOn", e);
-        }
-    }
-
-    /**
      * Sets audio routing to the wired headset on or off.
      *
      * @param on set <var>true</var> to route audio to/from wired
@@ -1543,12 +1571,18 @@
 
     /**
      * @hide
-     * Checks whether speech recognition is active
-     * @return true if a recording with source {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}
-     *    is underway.
+     * Checks whether the current audio focus is exclusive.
+     * @return true if the top of the audio focus stack requested focus
+     *     with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
      */
-    public boolean isSpeechRecognitionActive() {
-        return AudioSystem.isSourceActive(MediaRecorder.AudioSource.VOICE_RECOGNITION);
+    public boolean isAudioFocusExclusive() {
+        IAudioService service = getService();
+        try {
+            return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in isAudioFocusExclusive()", e);
+            return false;
+        }
     }
 
     /**
@@ -1563,7 +1597,8 @@
         }
         IAudioService service = getService();
         try {
-            service.adjustLocalOrRemoteStreamVolume(streamType, direction);
+            service.adjustLocalOrRemoteStreamVolume(streamType, direction,
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustLocalOrRemoteStreamVolume", e);
         }
@@ -1582,7 +1617,7 @@
      */
     /**
      * @hide
-     * @deprecated Use {@link #setPrameters(String)} instead
+     * @deprecated Use {@link #setParameters(String)} instead
      */
     @Deprecated public void setParameter(String key, String value) {
         setParameters(key+"="+value);
@@ -1656,10 +1691,16 @@
      * @see #playSoundEffect(int)
      */
     public static final int FX_KEYPRESS_RETURN = 8;
+
+    /**
+     * Invalid keypress sound
+     * @see #playSoundEffect(int)
+     */
+    public static final int FX_KEYPRESS_INVALID = 9;
     /**
      * @hide Number of sound effects
      */
-    public static final int NUM_SOUND_EFFECTS = 9;
+    public static final int NUM_SOUND_EFFECTS = 10;
 
     /**
      * Plays a sound effect (Key clicks, lid open/close...)
@@ -1673,6 +1714,7 @@
      *            {@link #FX_KEYPRESS_SPACEBAR},
      *            {@link #FX_KEYPRESS_DELETE},
      *            {@link #FX_KEYPRESS_RETURN},
+     *            {@link #FX_KEYPRESS_INVALID},
      * NOTE: This version uses the UI settings to determine
      * whether sounds are heard or not.
      */
@@ -1705,6 +1747,7 @@
      *            {@link #FX_KEYPRESS_SPACEBAR},
      *            {@link #FX_KEYPRESS_DELETE},
      *            {@link #FX_KEYPRESS_RETURN},
+     *            {@link #FX_KEYPRESS_INVALID},
      * @param volume Sound effect volume.
      * The volume value is a raw scalar so UI controls should be scaled logarithmically.
      * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used.
@@ -1760,6 +1803,12 @@
     }
 
     /**
+     * @hide
+     * Used to indicate no audio focus has been gained or lost.
+     */
+    public static final int AUDIOFOCUS_NONE = 0;
+
+    /**
      * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
@@ -1784,6 +1833,15 @@
      */
     public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
     /**
+     * Used to indicate a temporary request of audio focus, anticipated to last a short
+     * amount of time, during which no other applications, or system components, should play
+     * anything. Examples of exclusive and transient audio focus requests are voice
+     * memo recording and speech recognition, during which the system shouldn't play any
+     * notifications, and media playback should have paused.
+     * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
+     */
+    public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
+    /**
      * Used to indicate a loss of audio focus of unknown duration.
      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
      */
@@ -1947,14 +2005,17 @@
      *      for the playback of driving directions, or notifications sounds.
      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
      *      the previous focus owner to keep playing if it ducks its audio output.
+     *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
+     *      that benefits from the system not playing disruptive sounds like notifications, for
+     *      usecases such as voice memo recording, or speech recognition.
      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
      *      as the playback of a song or a video.
      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
      */
     public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
         int status = AUDIOFOCUS_REQUEST_FAILED;
-        if ((durationHint < AUDIOFOCUS_GAIN) || (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK))
-        {
+        if ((durationHint < AUDIOFOCUS_GAIN) ||
+                (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
             Log.e(TAG, "Invalid duration hint, audio focus request denied");
             return status;
         }
@@ -1964,7 +2025,7 @@
         try {
             status = service.requestAudioFocus(streamType, durationHint, mICallBack,
                     mAudioFocusDispatcher, getIdForAudioFocusListener(l),
-                    mContext.getPackageName() /* package name */);
+                    mContext.getOpPackageName() /* package name */);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
         }
@@ -1985,8 +2046,8 @@
         IAudioService service = getService();
         try {
             service.requestAudioFocus(streamType, durationHint, mICallBack, null,
-                    AudioService.IN_VOICE_COMM_FOCUS_ID,
-                    "system" /* dump-friendly package name */);
+                    MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
         }
@@ -2001,7 +2062,7 @@
     public void abandonAudioFocusForCall() {
         IAudioService service = getService();
         try {
-            service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);
+            service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
         }
@@ -2206,6 +2267,50 @@
     }
 
     /**
+     * Registers a {@link RemoteController} instance for it to receive media metadata updates
+     * and playback state information from applications using {@link RemoteControlClient}, and
+     * control their playback.
+     * <p>Registration requires the {@link Manifest.permission#MEDIA_CONTENT_CONTROL} permission.
+     * @param rctlr the object to register.
+     * @return true if the {@link RemoteController} was successfully registered, false if an
+     *     error occurred, due to an internal system error, or insufficient permissions.
+     */
+    public boolean registerRemoteController(RemoteController rctlr) {
+        if (rctlr == null) {
+            return false;
+        }
+        IAudioService service = getService();
+        try {
+            int[] artworkDimensions = rctlr.getArtworkSize();
+            boolean reg = service.registerRemoteControlDisplay(rctlr.getRcDisplay(),
+                    artworkDimensions[0]/*w*/, artworkDimensions[1]/*h*/);
+            rctlr.setIsRegistered(reg);
+            return reg;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
+            return false;
+        }
+    }
+
+    /**
+     * Unregisters a {@link RemoteController}, causing it to no longer receive media metadata and
+     * playback state information, and no longer be capable of controlling playback.
+     * @param rctlr the object to unregister.
+     */
+    public void unregisterRemoteController(RemoteController rctlr) {
+        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);
+        }
+    }
+
+    /**
      * @hide
      * Registers a remote control display that will be sent information by remote control clients.
      * Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
@@ -2235,8 +2340,6 @@
         }
         IAudioService service = getService();
         try {
-            // passing a negative value for art work width and height as they are unknown at
-            // this stage
             service.registerRemoteControlDisplay(rcd, w, h);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
@@ -2328,6 +2431,26 @@
     }
 
     /**
+     * @hide
+     * Notify the user of a RemoteControlClient that it should update its metadata with the
+     * new value for the given key.
+     * @param generationId the RemoteControlClient generation counter for which this request is
+     *         issued. Requests for an older generation than current one will be ignored.
+     * @param key the metadata key for which a new value exists
+     * @param value the new metadata value
+     */
+    public void updateRemoteControlClientMetadata(int generationId, int key,
+            Rating value) {
+        IAudioService service = getService();
+        try {
+            service.updateRemoteControlClientMetadata(generationId, key, value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in updateRemoteControlClientMetadata("+ generationId + ", "
+                    + key +", " + value + ")", e);
+        }
+    }
+
+    /**
      *  @hide
      *  Reload audio settings. This method is called by Settings backup
      *  agent when audio settings are restored and causes the AudioService
@@ -2342,6 +2465,21 @@
         }
     }
 
+    /**
+     * @hide
+     * Notifies AudioService that it is connected to an A2DP device that supports absolute volume,
+     * so that AudioService can send volume change events to the A2DP device, rather than handling
+     * them.
+     */
+    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
+        IAudioService service = getService();
+        try {
+            service.avrcpSupportsAbsoluteVolume(address, support);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in avrcpSupportsAbsoluteVolume", e);
+        }
+    }
+
      /**
       * {@hide}
       */
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 5383d08..f49ef2e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -17,8 +17,6 @@
 package android.media;
 
 import java.lang.ref.WeakReference;
-import java.lang.IllegalArgumentException;
-import java.lang.IllegalStateException;
 import java.nio.ByteBuffer;
 
 import android.os.Handler;
@@ -89,7 +87,7 @@
     private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    = -20;
 
     // Events:
-    // to keep in sync with frameworks/base/include/media/AudioRecord.h
+    // to keep in sync with frameworks/av/include/media/AudioRecord.h
     /**
      * Event id denotes when record head has reached a previously set marker.
      */
@@ -99,7 +97,7 @@
      */
     private static final int NATIVE_EVENT_NEW_POS = 3;
 
-    private final static String TAG = "AudioRecord-Java";
+    private final static String TAG = "android.media.AudioRecord";
 
 
     //---------------------------------------------------------
@@ -124,29 +122,25 @@
     /**
      * The audio data sampling rate in Hz.
      */
-    private int mSampleRate = 22050;
+    private int mSampleRate;
     /**
      * The number of input audio channels (1 is mono, 2 is stereo)
      */
-    private int mChannelCount = 1;
+    private int mChannelCount;
     /**
      * The audio channel mask
      */
-    private int mChannels = AudioFormat.CHANNEL_IN_MONO;
-    /**
-     * The current audio channel configuration
-     */
-    private int mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO;
+    private int mChannelMask;
     /**
      * The encoding of the audio samples.
      * @see AudioFormat#ENCODING_PCM_8BIT
      * @see AudioFormat#ENCODING_PCM_16BIT
      */
-    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+    private int mAudioFormat;
     /**
      * Where the audio data is recorded from.
      */
-    private int mRecordSource = MediaRecorder.AudioSource.DEFAULT;
+    private int mRecordSource;
     /**
      * Indicates the state of the AudioRecord instance.
      */
@@ -214,7 +208,6 @@
     public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
             int bufferSizeInBytes)
     throws IllegalArgumentException {
-        mState = STATE_UNINITIALIZED;
         mRecordingState = RECORDSTATE_STOPPED;
 
         // remember which looper is associated with the AudioRecord instanciation
@@ -232,7 +225,7 @@
         //TODO: update native initialization when information about hardware init failure
         //      due to capture device already open is available.
         int initResult = native_setup( new WeakReference<AudioRecord>(this),
-                mRecordSource, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes,
+                mRecordSource, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes,
                 session);
         if (initResult != SUCCESS) {
             loge("Error code "+initResult+" when initializing native AudioRecord object.");
@@ -250,7 +243,7 @@
     // postconditions:
     //    mRecordSource is valid
     //    mChannelCount is valid
-    //    mChannels is valid
+    //    mChannelMask is valid
     //    mAudioFormat is valid
     //    mSampleRate is valid
     private void audioParamCheck(int audioSource, int sampleRateInHz,
@@ -259,46 +252,40 @@
         //--------------
         // audio source
         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
-             (audioSource > MediaRecorder.getAudioSourceMax()) )  {
-            throw (new IllegalArgumentException("Invalid audio source."));
-        } else {
-            mRecordSource = audioSource;
+             ((audioSource > MediaRecorder.getAudioSourceMax()) &&
+              (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
+            throw new IllegalArgumentException("Invalid audio source.");
         }
+        mRecordSource = audioSource;
 
         //--------------
         // sample rate
         if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
-            throw (new IllegalArgumentException(sampleRateInHz
-                    + "Hz is not a supported sample rate."));
-        } else {
-            mSampleRate = sampleRateInHz;
+            throw new IllegalArgumentException(sampleRateInHz
+                    + "Hz is not a supported sample rate.");
         }
+        mSampleRate = sampleRateInHz;
 
         //--------------
         // channel config
-        mChannelConfiguration = channelConfig;
-
         switch (channelConfig) {
         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
         case AudioFormat.CHANNEL_IN_MONO:
         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
             mChannelCount = 1;
-            mChannels = AudioFormat.CHANNEL_IN_MONO;
+            mChannelMask = AudioFormat.CHANNEL_IN_MONO;
             break;
         case AudioFormat.CHANNEL_IN_STEREO:
         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
             mChannelCount = 2;
-            mChannels = AudioFormat.CHANNEL_IN_STEREO;
+            mChannelMask = AudioFormat.CHANNEL_IN_STEREO;
             break;
         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
             mChannelCount = 2;
-            mChannels = channelConfig;
+            mChannelMask = channelConfig;
             break;
         default:
-            mChannelCount = 0;
-            mChannels = AudioFormat.CHANNEL_INVALID;
-            mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
-            throw (new IllegalArgumentException("Unsupported channel configuration."));
+            throw new IllegalArgumentException("Unsupported channel configuration.");
         }
 
         //--------------
@@ -312,9 +299,8 @@
             mAudioFormat = audioFormat;
             break;
         default:
-            mAudioFormat = AudioFormat.ENCODING_INVALID;
-        throw (new IllegalArgumentException("Unsupported sample encoding."
-                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
+            throw new IllegalArgumentException("Unsupported sample encoding."
+                    + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
         }
     }
 
@@ -331,7 +317,7 @@
         int frameSizeInBytes = mChannelCount
             * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
-            throw (new IllegalArgumentException("Invalid audio buffer size."));
+            throw new IllegalArgumentException("Invalid audio buffer size.");
         }
 
         mNativeBufferSizeInBytes = audioBufferSize;
@@ -393,7 +379,7 @@
      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
      */
     public int getChannelConfiguration() {
-        return mChannelConfiguration;
+        return mChannelMask;
     }
 
     /**
@@ -421,7 +407,9 @@
      * @see AudioRecord#RECORDSTATE_RECORDING
      */
     public int getRecordingState() {
-        return mRecordingState;
+        synchronized (mRecordingStateLock) {
+            return mRecordingState;
+        }
     }
 
     /**
@@ -440,10 +428,12 @@
 
     /**
      * Returns the minimum buffer size required for the successful creation of an AudioRecord
-     * object.
+     * object, in byte units.
      * Note that this size doesn't guarantee a smooth recording under load, and higher values
      * should be chosen according to the expected frequency at which the AudioRecord instance
      * will be polled for new data.
+     * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
+     * configuration values.
      * @param sampleRateInHz the sample rate expressed in Hertz.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
@@ -453,10 +443,9 @@
      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
      *  hardware, or an invalid parameter was passed,
      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
-     *  output properties,
+     *  input properties,
      *   or the minimum buffer size expressed in bytes.
-     * @see #AudioRecord(int, int, int, int, int) for more information on valid
-     *   configuration values.
+     * @see #AudioRecord(int, int, int, int, int)
      */
     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
         int channelCount = 0;
@@ -474,21 +463,21 @@
         case AudioFormat.CHANNEL_INVALID:
         default:
             loge("getMinBufferSize(): Invalid channel configuration.");
-            return AudioRecord.ERROR_BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
 
         // PCM_8BIT is not supported at the moment
         if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
             loge("getMinBufferSize(): Invalid audio format.");
-            return AudioRecord.ERROR_BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
 
         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
         if (size == 0) {
-            return AudioRecord.ERROR_BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         else if (size == -1) {
-            return AudioRecord.ERROR;
+            return ERROR;
         }
         else {
             return size;
@@ -514,8 +503,8 @@
     public void startRecording()
     throws IllegalStateException {
         if (mState != STATE_INITIALIZED) {
-            throw(new IllegalStateException("startRecording() called on an "
-                    +"uninitialized AudioRecord."));
+            throw new IllegalStateException("startRecording() called on an "
+                    + "uninitialized AudioRecord.");
         }
 
         // start recording
@@ -536,8 +525,8 @@
     public void startRecording(MediaSyncEvent syncEvent)
     throws IllegalStateException {
         if (mState != STATE_INITIALIZED) {
-            throw(new IllegalStateException("startRecording() called on an "
-                    +"uninitialized AudioRecord."));
+            throw new IllegalStateException("startRecording() called on an "
+                    + "uninitialized AudioRecord.");
         }
 
         // start recording
@@ -555,7 +544,7 @@
     public void stop()
     throws IllegalStateException {
         if (mState != STATE_INITIALIZED) {
-            throw(new IllegalStateException("stop() called on an uninitialized AudioRecord."));
+            throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
         }
 
         // stop recording
@@ -585,6 +574,7 @@
         }
 
         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+                || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
                 || (offsetInBytes + sizeInBytes > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
@@ -609,6 +599,7 @@
         }
 
         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+                || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
                 || (offsetInShorts + sizeInShorts > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
@@ -692,6 +683,9 @@
      *  {@link #ERROR_INVALID_OPERATION}
      */
     public int setNotificationMarkerPosition(int markerInFrames) {
+        if (mState == STATE_UNINITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
         return native_set_marker_pos(markerInFrames);
     }
 
@@ -700,10 +694,14 @@
      * Sets the period at which the listener is called, if set with
      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
+     * It is possible for notifications to be lost if the period is too small.
      * @param periodInFrames update period expressed in frames
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
      */
     public int setPositionNotificationPeriod(int periodInFrames) {
+        if (mState == STATE_UNINITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
         return native_set_pos_update_period(periodInFrames);
     }
 
@@ -769,9 +767,8 @@
                 }
                 break;
             default:
-                Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " +
-                        "Unknown event type: " + msg.what);
-            break;
+                loge("Unknown native event type: " + msg.what);
+                break;
             }
         }
     };
@@ -837,11 +834,11 @@
     //------------------
 
     private static void logd(String msg) {
-        Log.d(TAG, "[ android.media.AudioRecord ] " + msg);
+        Log.d(TAG, msg);
     }
 
     private static void loge(String msg) {
-        Log.e(TAG, "[ android.media.AudioRecord ] " + msg);
+        Log.e(TAG, msg);
     }
 
 }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index aa91200..84ea4c90 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -22,11 +22,12 @@
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.AppOpsManager;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.app.PendingIntent.OnFinished;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -105,7 +106,7 @@
  *
  * @hide
  */
-public class AudioService extends IAudioService.Stub implements OnFinished {
+public class AudioService extends IAudioService.Stub {
 
     private static final String TAG = "AudioService";
 
@@ -117,9 +118,10 @@
     /** How long to delay before persisting a change in volume/ringer mode. */
     private static final int PERSIST_DELAY = 500;
 
-    private Context mContext;
-    private ContentResolver mContentResolver;
-    private boolean mVoiceCapable;
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final AppOpsManager mAppOps;
+    private final boolean mVoiceCapable;
 
     /** The UI */
     private VolumePanel mVolumePanel;
@@ -138,39 +140,28 @@
     private static final int MSG_PERSIST_MASTER_VOLUME = 2;
     private static final int MSG_PERSIST_RINGER_MODE = 3;
     private static final int MSG_MEDIA_SERVER_DIED = 4;
-    private static final int MSG_MEDIA_SERVER_STARTED = 5;
-    private static final int MSG_PLAY_SOUND_EFFECT = 6;
-    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7;
-    private static final int MSG_LOAD_SOUND_EFFECTS = 8;
-    private static final int MSG_SET_FORCE_USE = 9;
-    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10;
-    private static final int MSG_BT_HEADSET_CNCT_FAILED = 11;
-    private static final int MSG_RCDISPLAY_CLEAR = 12;
-    private static final int MSG_RCDISPLAY_UPDATE = 13;
-    private static final int MSG_SET_ALL_VOLUMES = 14;
-    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15;
-    private static final int MSG_REPORT_NEW_ROUTES = 16;
-    private static final int MSG_REEVALUATE_REMOTE = 17;
-    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18;
-    private static final int MSG_RCC_NEW_VOLUME_OBS = 19;
-    private static final int MSG_SET_FORCE_BT_A2DP_USE = 20;
+    private static final int MSG_PLAY_SOUND_EFFECT = 5;
+    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
+    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
+    private static final int MSG_SET_FORCE_USE = 8;
+    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
+    private static final int MSG_SET_ALL_VOLUMES = 10;
+    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
+    private static final int MSG_REPORT_NEW_ROUTES = 12;
+    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
+    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
+    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
+    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
+    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
+    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
-    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21;
-    private static final int MSG_SET_A2DP_CONNECTION_STATE = 22;
+    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
+    private static final int MSG_SET_A2DP_CONNECTION_STATE = 101;
     // end of messages handled under wakelock
-    private static final int MSG_SET_RSX_CONNECTION_STATE = 23; // change remote submix connection
-    private static final int MSG_CHECK_MUSIC_ACTIVE = 24;
-    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27;
-    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28;
-    private static final int MSG_PROMOTE_RCC = 29;
-    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 30;
-    private static final int MSG_UNLOAD_SOUND_EFFECTS = 31;
-    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 32;
-    private static final int MSG_RCC_SEEK_REQUEST = 33;
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
     // Timeout for connection to bluetooth headset service
@@ -184,12 +175,10 @@
     private VolumeStreamState[] mStreamStates;
     private SettingsObserver mSettingsObserver;
 
-    private int mMode;
+    private int mMode = AudioSystem.MODE_NORMAL;
     // protects mRingerMode
     private final Object mSettingsLock = new Object();
 
-    private boolean mMediaServerOk;
-
     private SoundPool mSoundPool;
     private final Object mSoundEffectsLock = new Object();
     private static final int NUM_SOUNDPOOL_CHANNELS = 4;
@@ -211,7 +200,7 @@
     private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
 
    /** @hide Maximum volume index values for audio streams */
-    private final int[] MAX_STREAM_VOLUME = new int[] {
+    private static final int[] MAX_STREAM_VOLUME = new int[] {
         5,  // STREAM_VOICE_CALL
         7,  // STREAM_SYSTEM
         7,  // STREAM_RING
@@ -257,6 +246,23 @@
     };
     private int[] mStreamVolumeAlias;
 
+    /**
+     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
+     * after mapping through mStreamVolumeAlias.
+     */
+    private static final int[] STEAM_VOLUME_OPS = new int[] {
+        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
+        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
+        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
+        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
+        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
+    };
+
     private final boolean mUseFixedVolume;
 
     // stream names used by dumpStreamStates()
@@ -277,23 +283,13 @@
         public void onError(int error) {
             switch (error) {
             case AudioSystem.AUDIO_STATUS_SERVER_DIED:
-                if (mMediaServerOk) {
-                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
-                            null, 1500);
-                    mMediaServerOk = false;
-                }
-                break;
-            case AudioSystem.AUDIO_STATUS_OK:
-                if (!mMediaServerOk) {
-                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0,
-                            null, 0);
-                    mMediaServerOk = true;
-                }
+                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
+                        SENDMSG_NOOP, 0, 0, null, 0);
                 break;
             default:
                 break;
             }
-       }
+        }
     };
 
     /**
@@ -326,9 +322,6 @@
     // Broadcast receiver for device connections intent broadcasts
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
 
-    // Used to alter media button redirection when the phone is ringing.
-    private boolean mIsRinging = false;
-
     // Devices currently connected
     private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
 
@@ -449,6 +442,16 @@
     // and used later when/if disableSafeMediaVolume() is called.
     private StreamVolumeCommand mPendingVolumeCommand;
 
+    private PowerManager.WakeLock mAudioEventWakeLock;
+
+    private final MediaFocusControl mMediaFocusControl;
+
+    // Reference to BluetoothA2dp to query for AbsoluteVolume.
+    private BluetoothA2dp mA2dp;
+    private final Object mA2dpAvrcpLock = new Object();
+    // If absolute volume is supported in AVRCP device
+    private boolean mAvrcpAbsVolSupported = false;
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -457,11 +460,12 @@
     public AudioService(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
+        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
         mVoiceCapable = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_voice_capable);
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
 
         Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
@@ -475,11 +479,15 @@
                 com.android.internal.R.integer.config_soundEffectVolumeDb);
 
         mVolumePanel = new VolumePanel(context, this);
-        mMode = AudioSystem.MODE_NORMAL;
         mForcedUseForComm = AudioSystem.FORCE_NONE;
 
         createAudioSystemThread();
 
+        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
+                mContext, /*VolumeController*/ mVolumePanel, this);
+
+        AudioSystem.setErrorCallback(mAudioSystemCallback);
+
         boolean cameraSoundForced = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_camera_sound_forced);
         mCameraSoundForced = new Boolean(cameraSoundForced);
@@ -508,15 +516,13 @@
         updateStreamVolumeAlias(false /*updateVolumes*/);
         createStreamStates();
 
-        mMediaServerOk = true;
+        readAndSetLowRamDevice();
 
         // Call setRingerModeInt() to apply correct mute
         // state on streams affected by ringer mode.
         mRingerModeMutedStreams = 0;
         setRingerModeInt(getRingerMode(), false);
 
-        AudioSystem.setErrorCallback(mAudioSystemCallback);
-
         // Register for device connection intent broadcasts.
         IntentFilter intentFilter =
                 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
@@ -548,20 +554,6 @@
 
         context.registerReceiver(mReceiver, intentFilter);
 
-        // Register for package removal intent broadcasts for media button receiver persistence
-        IntentFilter pkgFilter = new IntentFilter();
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
-        pkgFilter.addDataScheme("package");
-        context.registerReceiver(mReceiver, pkgFilter);
-
-        // Register for phone state monitoring
-        TelephonyManager tmgr = (TelephonyManager)
-                context.getSystemService(Context.TELEPHONY_SERVICE);
-        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
         mUseMasterVolume = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_useMasterVolume);
         restoreMasterVolume();
@@ -569,11 +561,6 @@
         mMasterVolumeRamp = context.getResources().getIntArray(
                 com.android.internal.R.array.config_masterVolumeRamp);
 
-        mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC],
-                MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
-        mHasRemotePlayback = false;
-        mMainRemoteIsActive = false;
-        postReevaluateRemote();
     }
 
     private void createAudioSystemThread() {
@@ -775,7 +762,7 @@
         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
 
         // Restore the default media button receiver from the system settings
-        restoreMediaButtonReceiver();
+        mMediaFocusControl.restoreMediaButtonReceiver();
     }
 
     private int rescaleIndex(int index, int srcStream, int dstStream) {
@@ -787,23 +774,26 @@
     ///////////////////////////////////////////////////////////////////////////
 
     /** @see AudioManager#adjustVolume(int, int) */
-    public void adjustVolume(int direction, int flags) {
-        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
+    public void adjustVolume(int direction, int flags, String callingPackage) {
+        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags,
+                callingPackage);
     }
 
     /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
      *  on streamType: fixed to STREAM_MUSIC */
-    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) {
+    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
+            String callingPackage) {
         if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
-        if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
-            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
+        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
+            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
         } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
-            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0);
+            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
         }
     }
 
     /** @see AudioManager#adjustVolume(int, int) */
-    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
+    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
+            String callingPackage) {
         if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
         int streamType;
         if (mVolumeControlStream != -1) {
@@ -824,14 +814,15 @@
             // don't play sounds for remote
             flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
             //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
-            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
+            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
         } else {
-            adjustStreamVolume(streamType, direction, flags);
+            adjustStreamVolume(streamType, direction, flags, callingPackage);
         }
     }
 
     /** @see AudioManager#adjustStreamVolume(int, int, int) */
-    public void adjustStreamVolume(int streamType, int direction, int flags) {
+    public void adjustStreamVolume(int streamType, int direction, int flags,
+            String callingPackage) {
         if (mUseFixedVolume) {
             return;
         }
@@ -852,6 +843,18 @@
         boolean adjustVolume = true;
         int step;
 
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
+        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
         // reset any pending volume command
         synchronized (mSafeMediaVolumeState) {
             mPendingVolumeCommand = null;
@@ -896,6 +899,18 @@
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
         if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+
+            // Check if volume update should be send to AVRCP
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
+                    }
+                }
+            }
+
             if ((direction == AudioManager.ADJUST_RAISE) &&
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
@@ -917,7 +932,7 @@
     }
 
     /** @see AudioManager#adjustMasterVolume(int, int) */
-    public void adjustMasterVolume(int steps, int flags) {
+    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
         if (mUseFixedVolume) {
             return;
         }
@@ -932,7 +947,7 @@
         }
 
         //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
-        setMasterVolume(volume, flags);
+        setMasterVolume(volume, flags, callingPackage);
     }
 
     // StreamVolumeCommand contains the information needed to defer the process of
@@ -968,27 +983,50 @@
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
-    public void setStreamVolume(int streamType, int index, int flags) {
+    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
         if (mUseFixedVolume) {
             return;
         }
 
         ensureValidStreamType(streamType);
-        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
+        int streamTypeAlias = mStreamVolumeAlias[streamType];
+        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
 
         final int device = getDeviceForStream(streamType);
         int oldIndex;
 
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
+        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
         synchronized (mSafeMediaVolumeState) {
             // reset any pending volume command
             mPendingVolumeCommand = null;
 
             oldIndex = streamState.getIndex(device);
 
-            index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
+            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
+
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.setAvrcpAbsoluteVolume(index);
+                    }
+                }
+            }
 
             flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-            if ((mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
+            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
                     ((device & mFixedVolumeDevices) != 0)) {
                 flags |= AudioManager.FLAG_FIXED_VOLUME;
 
@@ -1003,7 +1041,7 @@
                 }
             }
 
-            if (!checkSafeMediaVolume(mStreamVolumeAlias[streamType], index, device)) {
+            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                 mVolumePanel.postDisplaySafeVolumeWarning(flags);
                 mPendingVolumeCommand = new StreamVolumeCommand(
                                                     streamType, index, flags, device);
@@ -1239,6 +1277,10 @@
         return AudioSystem.getMasterMute();
     }
 
+    protected static int getMaxStreamVolume(int streamType) {
+        return MAX_STREAM_VOLUME[streamType];
+    }
+
     /** @see AudioManager#getStreamVolume(int) */
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -1261,11 +1303,16 @@
         return getLastAudibleMasterVolume();
     }
 
-    public void setMasterVolume(int volume, int flags) {
+    public void setMasterVolume(int volume, int flags, String callingPackage) {
         if (mUseFixedVolume) {
             return;
         }
 
+        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
         if (volume < 0) {
             volume = 0;
         } else if (volume > MAX_MASTER_VOLUME) {
@@ -1883,7 +1930,16 @@
         if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
             return;
         }
-        mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
+
+        if (on) {
+            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
+                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
+            }
+            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
+            mForcedUseForComm = AudioSystem.FORCE_NONE;
+        }
 
         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
@@ -1899,7 +1955,12 @@
         if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
             return;
         }
-        mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+
+        if (on) {
+            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+            mForcedUseForComm = AudioSystem.FORCE_NONE;
+        }
 
         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
@@ -2248,21 +2309,23 @@
             List<BluetoothDevice> deviceList;
             switch(profile) {
             case BluetoothProfile.A2DP:
-                BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
-                deviceList = a2dp.getConnectedDevices();
-                if (deviceList.size() > 0) {
-                    btDevice = deviceList.get(0);
-                    synchronized (mConnectedDevices) {
-                        int state = a2dp.getConnectionState(btDevice);
-                        int delay = checkSendBecomingNoisyIntent(
-                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
-                        queueMsgUnderWakeLock(mAudioHandler,
-                                MSG_SET_A2DP_CONNECTION_STATE,
-                                state,
-                                0,
-                                btDevice,
-                                delay);
+                synchronized (mA2dpAvrcpLock) {
+                    mA2dp = (BluetoothA2dp) proxy;
+                    deviceList = mA2dp.getConnectedDevices();
+                    if (deviceList.size() > 0) {
+                        btDevice = deviceList.get(0);
+                        synchronized (mConnectedDevices) {
+                            int state = mA2dp.getConnectionState(btDevice);
+                            int delay = checkSendBecomingNoisyIntent(
+                                                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                                    (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
+                            queueMsgUnderWakeLock(mAudioHandler,
+                                    MSG_SET_A2DP_CONNECTION_STATE,
+                                    state,
+                                    0,
+                                    btDevice,
+                                    delay);
+                        }
                     }
                 }
                 break;
@@ -2324,10 +2387,13 @@
         public void onServiceDisconnected(int profile) {
             switch(profile) {
             case BluetoothProfile.A2DP:
-                synchronized (mConnectedDevices) {
-                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
-                        makeA2dpDeviceUnavailableNow(
-                                mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
+                synchronized (mA2dpAvrcpLock) {
+                    mA2dp = null;
+                    synchronized (mConnectedDevices) {
+                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
+                            makeA2dpDeviceUnavailableNow(
+                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
+                        }
                     }
                 }
                 break;
@@ -2344,26 +2410,6 @@
         }
     };
 
-    /** see AudioManager.setRemoteSubmixOn(boolean on) */
-    public void setRemoteSubmixOn(boolean on, int address) {
-        sendMsg(mAudioHandler, MSG_SET_RSX_CONNECTION_STATE,
-                SENDMSG_REPLACE /* replace with QUEUE when multiple addresses are supported */,
-                on ? 1 : 0 /*arg1*/,
-                address /*arg2*/,
-                null/*obj*/, 0/*delay*/);
-    }
-
-    private void onSetRsxConnectionState(int available, int address) {
-        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX,
-                available == 1 ?
-                        AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                String.valueOf(address) /*device_address*/);
-        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX,
-                available == 1 ?
-                        AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                String.valueOf(address) /*device_address*/);
-    }
-
     private void onCheckMusicActive() {
         synchronized (mSafeMediaVolumeState) {
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
@@ -2557,7 +2603,7 @@
             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                 // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
                 // volume can have priority over STREAM_MUSIC
-                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
+                if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
                     if (DEBUG_VOL)
                         Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                     return STREAM_REMOTE_MUSIC;
@@ -2597,7 +2643,7 @@
                 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
                 return AudioSystem.STREAM_NOTIFICATION;
             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
+                if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
                     // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
                     // volume can have priority over STREAM_MUSIC
                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
@@ -2641,7 +2687,11 @@
      */
     private void queueMsgUnderWakeLock(Handler handler, int msg,
             int arg1, int arg2, Object obj, int delay) {
-        mMediaEventWakeLock.acquire();
+        final long ident = Binder.clearCallingIdentity();
+        // Always acquire the wake lock as AudioService because it is released by the
+        // message handler.
+        mAudioEventWakeLock.acquire();
+        Binder.restoreCallingIdentity(ident);
         sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
     }
 
@@ -2807,7 +2857,12 @@
             int index;
             if (isMuted()) {
                 index = 0;
-            } else {
+            } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
+                       (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                       mAvrcpAbsVolSupported) {
+                index = (mIndexMax + 5)/10;
+            }
+            else {
                 index = (getIndex(device) + 5)/10;
             }
             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
@@ -3339,13 +3394,6 @@
             }
         }
 
-        private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
-            Settings.System.putStringForUser(mContentResolver,
-                                             Settings.System.MEDIA_BUTTON_RECEIVER,
-                                             receiver == null ? "" : receiver.flattenToString(),
-                                             UserHandle.USER_CURRENT);
-        }
-
         private void cleanupPlayer(MediaPlayer mp) {
             if (mp != null) {
                 try {
@@ -3411,24 +3459,22 @@
                     break;
 
                 case MSG_MEDIA_SERVER_DIED:
-                    if (!mMediaServerOk) {
+                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
                         Log.e(TAG, "Media server died.");
-                        // Force creation of new IAudioFlinger interface so that we are notified
-                        // when new media_server process is back to life.
-                        AudioSystem.setErrorCallback(mAudioSystemCallback);
                         sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
                                 null, 500);
+                        break;
                     }
-                    break;
-
-                case MSG_MEDIA_SERVER_STARTED:
                     Log.e(TAG, "Media server started.");
+
                     // indicate to audio HAL that we start the reconfiguration phase after a media
                     // server crash
-                    // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server
+                    // Note that we only execute this when the media server
                     // process restarts after a crash, not the first time it is started.
                     AudioSystem.setParameters("restarting=true");
 
+                    readAndSetLowRamDevice();
+
                     // Restore device connection states
                     synchronized (mConnectedDevices) {
                         Set set = mConnectedDevices.entrySet();
@@ -3522,31 +3568,18 @@
                     setForceUse(msg.arg1, msg.arg2);
                     break;
 
-                case MSG_PERSIST_MEDIABUTTONRECEIVER:
-                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
-                    break;
-
-                case MSG_RCDISPLAY_CLEAR:
-                    onRcDisplayClear();
-                    break;
-
-                case MSG_RCDISPLAY_UPDATE:
-                    // msg.obj is guaranteed to be non null
-                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
-                    break;
-
                 case MSG_BT_HEADSET_CNCT_FAILED:
                     resetBluetoothSco();
                     break;
 
                 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
                     onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
-                    mMediaEventWakeLock.release();
+                    mAudioEventWakeLock.release();
                     break;
 
                 case MSG_SET_A2DP_CONNECTION_STATE:
                     onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
-                    mMediaEventWakeLock.release();
+                    mAudioEventWakeLock.release();
                     break;
 
                 case MSG_REPORT_NEW_ROUTES: {
@@ -3569,30 +3602,6 @@
                     break;
                 }
 
-                case MSG_REEVALUATE_REMOTE:
-                    onReevaluateRemote();
-                    break;
-
-                case MSG_RCC_NEW_PLAYBACK_INFO:
-                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
-                            ((Integer)msg.obj).intValue() /* value */);
-                    break;
-                case MSG_RCC_NEW_VOLUME_OBS:
-                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
-                            (IRemoteVolumeObserver)msg.obj /* rvo */);
-                    break;
-                case MSG_RCC_NEW_PLAYBACK_STATE:
-                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */,
-                            (RccPlaybackState)msg.obj /* newState */);
-                    break;
-                case MSG_RCC_SEEK_REQUEST:
-                    onSetRemoteControlClientPlaybackPosition(msg.arg1 /* generationId */,
-                            ((Long)msg.obj).longValue() /* timeMs */);
-
-                case MSG_SET_RSX_CONNECTION_STATE:
-                    onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/);
-                    break;
-
                 case MSG_CHECK_MUSIC_ACTIVE:
                     onCheckMusicActive();
                     break;
@@ -3609,10 +3618,6 @@
                     onPersistSafeVolumeState(msg.arg1);
                     break;
 
-                case MSG_PROMOTE_RCC:
-                    onPromoteRcc(msg.arg1);
-                    break;
-
                 case MSG_BROADCAST_BT_CONNECTION_STATE:
                     onBroadcastScoConnectionState(msg.arg1);
                     break;
@@ -3672,6 +3677,9 @@
     private void makeA2dpDeviceAvailable(String address) {
         // enable A2DP before notifying A2DP connection to avoid unecessary processing in
         // audio policy manager
+        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -3688,6 +3696,9 @@
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpDeviceUnavailableNow(String address) {
+        synchronized (mA2dpAvrcpLock) {
+            mAvrcpAbsVolSupported = false;
+        }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 address);
@@ -3719,6 +3730,7 @@
 
     private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
     {
+        if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state);
         if (btDevice == null) {
             return;
         }
@@ -3726,6 +3738,7 @@
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
         }
+
         synchronized (mConnectedDevices) {
             boolean isConnected =
                 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
@@ -3776,6 +3789,16 @@
         }
     }
 
+    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
+        // address is not used for now, but may be used when multiple a2dp devices are supported
+        synchronized (mA2dpAvrcpLock) {
+            mAvrcpAbsVolSupported = support;
+            VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
+        }
+    }
+
     private boolean handleDeviceConnection(boolean connected, int device, String params) {
         synchronized (mConnectedDevices) {
             boolean isConnected = (mConnectedDevices.containsKey(device) &&
@@ -4090,21 +4113,6 @@
                         0,
                         null,
                         SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
-            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
-                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
-                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                    // a package is being removed, not replaced
-                    String packageName = intent.getData().getSchemeSpecificPart();
-                    if (packageName != null) {
-                        cleanupMediaButtonReceiverForPackage(packageName, true);
-                    }
-                }
-            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
-                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
-                String packageName = intent.getData().getSchemeSpecificPart();
-                if (packageName != null) {
-                    cleanupMediaButtonReceiverForPackage(packageName, false);
-                }
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 AudioSystem.setParameters("screen_state=on");
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
@@ -4121,7 +4129,7 @@
                         null,
                         0);
                 // the current audio focus owner is no longer valid
-                discardAudioFocusOwner();
+                mMediaFocusControl.discardAudioFocusOwner();
 
                 // load volume settings for new user
                 readAudioSettings(true /*userSwitch*/);
@@ -4137,2204 +4145,119 @@
     }
 
     //==========================================================================================
-    // AudioFocus
+    // RemoteControlDisplay / RemoteControlClient / Remote info
     //==========================================================================================
-
-    /* constant to identify focus stack entry that is used to hold the focus while the phone
-     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
-     * entering and exiting calls.
-     */
-    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
-
-    private final static Object mAudioFocusLock = new Object();
-
-    private final static Object mRingingLock = new Object();
-
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (state == TelephonyManager.CALL_STATE_RINGING) {
-                //Log.v(TAG, " CALL_STATE_RINGING");
-                synchronized(mRingingLock) {
-                    mIsRinging = true;
-                }
-            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
-                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
-                synchronized(mRingingLock) {
-                    mIsRinging = false;
-                }
-            }
-        }
-    };
-
-    /**
-     * Discard the current audio focus owner.
-     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
-     * focus), remove it from the stack, and clear the remote control display.
-     */
-    private void discardAudioFocusOwner() {
-        synchronized(mAudioFocusLock) {
-            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
-                // notify the current focus owner it lost focus after removing it from stack
-                FocusStackEntry focusOwner = mFocusStack.pop();
-                try {
-                    focusOwner.mFocusDispatcher.dispatchAudioFocusChange(
-                            AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failure to signal loss of audio focus due to "+ e);
-                    e.printStackTrace();
-                }
-                focusOwner.unlinkToDeath();
-                // clear RCD
-                synchronized(mRCStack) {
-                    clearRemoteControlDisplay_syncAfRcs();
-                }
-            }
-        }
-    }
-
-    private void notifyTopOfAudioFocusStack() {
-        // notify the top of the stack it gained focus
-        if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
-            if (canReassignAudioFocus()) {
-                try {
-                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
-                            AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-    private static class FocusStackEntry {
-        public int mStreamType = -1;// no stream type
-        public IAudioFocusDispatcher mFocusDispatcher = null;
-        public IBinder mSourceRef = null;
-        public String mClientId;
-        public int mFocusChangeType;
-        public AudioFocusDeathHandler mHandler;
-        public String mPackageName;
-        public int mCallingUid;
-
-        public FocusStackEntry() {
-        }
-
-        public FocusStackEntry(int streamType, int duration,
-                IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
-                String pn, int uid) {
-            mStreamType = streamType;
-            mFocusDispatcher = afl;
-            mSourceRef = source;
-            mClientId = id;
-            mFocusChangeType = duration;
-            mHandler = hdlr;
-            mPackageName = pn;
-            mCallingUid = uid;
-        }
-
-        public void unlinkToDeath() {
-            try {
-                if (mSourceRef != null && mHandler != null) {
-                    mSourceRef.unlinkToDeath(mHandler, 0);
-                    mHandler = null;
-                }
-            } catch (java.util.NoSuchElementException e) {
-                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
-            }
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            unlinkToDeath(); // unlink exception handled inside method
-            super.finalize();
-        }
-    }
-
-    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the audio focus stack
-     */
-    private void dumpFocusStack(PrintWriter pw) {
-        pw.println("\nAudio Focus stack entries (last is top of stack):");
-        synchronized(mAudioFocusLock) {
-            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
-            while(stackIterator.hasNext()) {
-                FocusStackEntry fse = stackIterator.next();
-                pw.println("  source:" + fse.mSourceRef
-                        + " -- pack: " + fse.mPackageName
-                        + " -- client: " + fse.mClientId
-                        + " -- duration: " + fse.mFocusChangeType
-                        + " -- uid: " + fse.mCallingUid
-                        + " -- stream: " + fse.mStreamType);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock
-     * Remove a focus listener from the focus stack.
-     * @param clientToRemove the focus listener
-     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
-     *   focus, notify the next item in the stack it gained focus.
-     */
-    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
-        // is the current top of the focus stack abandoning focus? (because of request, not death)
-        if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
-        {
-            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
-            FocusStackEntry fse = mFocusStack.pop();
-            fse.unlinkToDeath();
-            if (signal) {
-                // notify the new top of the stack it gained focus
-                notifyTopOfAudioFocusStack();
-                // there's a new top of the stack, let the remote control know
-                synchronized(mRCStack) {
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }
-        } else {
-            // focus is abandoned by a client that's not at the top of the stack,
-            // no need to update focus.
-            // (using an iterator on the stack so we can safely remove an entry after having
-            //  evaluated it, traversal order doesn't matter here)
-            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
-            while(stackIterator.hasNext()) {
-                FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
-                if(fse.mClientId.equals(clientToRemove)) {
-                    Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
-                            + fse.mClientId);
-                    stackIterator.remove();
-                    fse.unlinkToDeath();
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock
-     * Remove focus listeners from the focus stack for a particular client when it has died.
-     */
-    private void removeFocusStackEntryForClient(IBinder cb) {
-        // is the owner of the audio focus part of the client to remove?
-        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
-                mFocusStack.peek().mSourceRef.equals(cb);
-        // (using an iterator on the stack so we can safely remove an entry after having
-        //  evaluated it, traversal order doesn't matter here)
-        Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
-        while(stackIterator.hasNext()) {
-            FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
-            if(fse.mSourceRef.equals(cb)) {
-                Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
-                        + fse.mClientId);
-                stackIterator.remove();
-                // the client just died, no need to unlink to its death
-            }
-        }
-        if (isTopOfStackForClientToRemove) {
-            // we removed an entry at the top of the stack:
-            //  notify the new top of the stack it gained focus.
-            notifyTopOfAudioFocusStack();
-            // there's a new top of the stack, let the remote control know
-            synchronized(mRCStack) {
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
-     */
-    private boolean canReassignAudioFocus() {
-        // focus requests are rejected during a phone call or when the phone is ringing
-        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
-        if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
-     * stack if necessary.
-     */
-    private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-
-        AudioFocusDeathHandler(IBinder cb) {
-            mCb = cb;
-        }
-
-        public void binderDied() {
-            synchronized(mAudioFocusLock) {
-                Log.w(TAG, "  AudioFocus   audio focus client died");
-                removeFocusStackEntryForClient(mCb);
-            }
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-
-    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
-    public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
-        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
-        // the main stream type for the audio focus request is currently not used. It may
-        // potentially be used to handle multiple stream type-dependent audio focuses.
-
-        // we need a valid binder callback for clients
-        if (!cb.pingBinder()) {
-            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
-            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        synchronized(mAudioFocusLock) {
-            if (!canReassignAudioFocus()) {
-                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-            }
-
-            // handle the potential premature death of the new holder of the focus
-            // (premature death == death before abandoning focus)
-            // Register for client death notification
-            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
-            try {
-                cb.linkToDeath(afdh, 0);
-            } catch (RemoteException e) {
-                // client has already died!
-                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
-                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-            }
-
-            if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
-                // if focus is already owned by this client and the reason for acquiring the focus
-                // hasn't changed, don't do anything
-                if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
-                    // unlink death handler so it can be gc'ed.
-                    // linkToDeath() creates a JNI global reference preventing collection.
-                    cb.unlinkToDeath(afdh, 0);
-                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-                }
-                // the reason for the audio focus request has changed: remove the current top of
-                // stack and respond as if we had a new focus owner
-                FocusStackEntry fse = mFocusStack.pop();
-                fse.unlinkToDeath();
-            }
-
-            // notify current top of stack it is losing focus
-            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
-                try {
-                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
-                            -1 * focusChangeHint, // loss and gain codes are inverse of each other
-                            mFocusStack.peek().mClientId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, " Failure to signal loss of focus due to "+ e);
-                    e.printStackTrace();
-                }
-            }
-
-            // focus requester might already be somewhere below in the stack, remove it
-            removeFocusStackEntry(clientId, false /* signal */);
-
-            // push focus requester at the top of the audio focus stack
-            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
-                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
-
-            // there's a new top of the stack, let the remote control know
-            synchronized(mRCStack) {
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }//synchronized(mAudioFocusLock)
-
-        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-    }
-
-    /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener)  */
-    public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
-        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
-        try {
-            // this will take care of notifying the new focus owner if needed
-            synchronized(mAudioFocusLock) {
-                removeFocusStackEntry(clientId, true);
-            }
-        } catch (java.util.ConcurrentModificationException cme) {
-            // Catching this exception here is temporary. It is here just to prevent
-            // a crash seen when the "Silent" notification is played. This is believed to be fixed
-            // but this try catch block is left just to be safe.
-            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
-            cme.printStackTrace();
-        }
-
-        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-    }
-
-
-    public void unregisterAudioFocusClient(String clientId) {
-        synchronized(mAudioFocusLock) {
-            removeFocusStackEntry(clientId, false);
-        }
-    }
-
-
-    //==========================================================================================
-    // RemoteControl
-    //==========================================================================================
-    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
-    }
-
-    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
-    }
-
-    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        // sanity check on the incoming key event
-        if (!isValidMediaKeyEvent(keyEvent)) {
-            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
-            return;
-        }
-        // event filtering for telephony
-        synchronized(mRingingLock) {
-            synchronized(mRCStack) {
-                if ((mMediaReceiverForCalls != null) &&
-                        (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
-                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
-                    return;
-                }
-            }
-        }
-        // event filtering based on voice-based interactions
-        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
-            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
-        } else {
-            dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to the telephony package.
-     * Precondition: mMediaReceiverForCalls != null
-     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                    null, mKeyEventDone, mAudioHandler, Activity.RESULT_OK, null, null);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to one of the registered listeners,
-     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
-     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        synchronized(mRCStack) {
-            if (!mRCStack.empty()) {
-                // send the intent that was registered by the client
-                try {
-                    mRCStack.peek().mMediaIntent.send(mContext,
-                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
-                            keyIntent, AudioService.this, mAudioHandler);
-                } catch (CanceledException e) {
-                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
-                    e.printStackTrace();
-                }
-            } else {
-                // legacy behavior when nobody registered their media button event receiver
-                //    through AudioManager
-                if (needWakeLock) {
-                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-                }
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                            null, mKeyEventDone,
-                            mAudioHandler, Activity.RESULT_OK, null, null);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-        }
-    }
-
-    /**
-     * The different actions performed in response to a voice button key event.
-     */
-    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
-    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
-    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
-
-    private final Object mVoiceEventLock = new Object();
-    private boolean mVoiceButtonDown;
-    private boolean mVoiceButtonHandled;
-
-    /**
-     * Filter key events that may be used for voice-based interactions
-     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
-     *    media buttons that can be used to trigger voice-based interactions.
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (DEBUG_RC) {
-            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
-        }
-
-        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
-        int keyAction = keyEvent.getAction();
-        synchronized (mVoiceEventLock) {
-            if (keyAction == KeyEvent.ACTION_DOWN) {
-                if (keyEvent.getRepeatCount() == 0) {
-                    // initial down
-                    mVoiceButtonDown = true;
-                    mVoiceButtonHandled = false;
-                } else if (mVoiceButtonDown && !mVoiceButtonHandled
-                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
-                    // long-press, start voice-based interactions
-                    mVoiceButtonHandled = true;
-                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
-                }
-            } else if (keyAction == KeyEvent.ACTION_UP) {
-                if (mVoiceButtonDown) {
-                    // voice button up
-                    mVoiceButtonDown = false;
-                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
-                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
-                    }
-                }
-            }
-        }//synchronized (mVoiceEventLock)
-
-        // take action after media button event filtering for voice-based interactions
-        switch (voiceButtonAction) {
-            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
-                break;
-            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
-                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
-                // then start the voice-based interactions
-                startVoiceBasedInteractions(needWakeLock);
-                break;
-            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
-                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
-                break;
-        }
-    }
-
-    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
-        // send DOWN event
-        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        // send UP event
-        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-
-    }
-
-
-    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            return false;
-        }
-        final int keyCode = keyEvent.getKeyCode();
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_MEDIA_CLOSE:
-            case KeyEvent.KEYCODE_MEDIA_EJECT:
-                break;
-            default:
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Checks whether the given key code is one that can trigger the launch of voice-based
-     *   interactions.
-     * @param keyCode the key code associated with the key event
-     * @return true if the key is one of the supported voice-based interaction triggers
-     */
-    private static boolean isValidVoiceInputKeyCode(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
+    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
+            mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
             return true;
         } else {
+            Log.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
+                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
+                    " to register IRemoteControlDisplay");
             return false;
         }
     }
 
-    /**
-     * Tell the system to start voice-based interactions / voice commands
-     */
-    private void startVoiceBasedInteractions(boolean needWakeLock) {
-        Intent voiceIntent = null;
-        // select which type of search to launch:
-        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
-        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
-        //    with EXTRA_SECURE set to true if the device is securely locked
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-        if (!isLocked && pm.isScreenOn()) {
-            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
-            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
-        } else {
-            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
-                    isLocked && mKeyguardManager.isKeyguardSecure());
-            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
-        }
-        // start the search activity
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        try {
-            if (voiceIntent != null) {
-                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                mContext.startActivity(voiceIntent);
-            }
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "No activity for search: " + e);
-        } finally {
-            if (needWakeLock) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    }
-
-    private PowerManager.WakeLock mMediaEventWakeLock;
-
-    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
-
-    // only set when wakelock was acquired, no need to check value when received
-    private static final String EXTRA_WAKELOCK_ACQUIRED =
-            "android.media.AudioService.WAKELOCK_ACQUIRED";
-
-    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
-            int resultCode, String resultData, Bundle resultExtras) {
-        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
-            mMediaEventWakeLock.release();
-        }
-    }
-
-    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            if (intent == null) {
-                return;
-            }
-            Bundle extras = intent.getExtras();
-            if (extras == null) {
-                return;
-            }
-            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    };
-
-    /**
-     * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
-     */
-    private final Object mCurrentRcLock = new Object();
-    /**
-     * The one remote control client which will receive a request for display information.
-     * This object may be null.
-     * Access protected by mCurrentRcLock.
-     */
-    private IRemoteControlClient mCurrentRcClient = null;
-
-    private final static int RC_INFO_NONE = 0;
-    private final static int RC_INFO_ALL =
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
-
-    /**
-     * A monotonically increasing generation counter for mCurrentRcClient.
-     * Only accessed with a lock on mCurrentRcLock.
-     * No value wrap-around issues as we only act on equal values.
-     */
-    private int mCurrentRcClientGen = 0;
-
-    /**
-     * Inner class to monitor remote control client deaths, and remove the client for the
-     * remote control stack if necessary.
-     */
-    private class RcClientDeathHandler implements IBinder.DeathRecipient {
-        final private IBinder mCb; // To be notified of client's death
-        final private PendingIntent mMediaIntent;
-
-        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
-            mCb = cb;
-            mMediaIntent = pi;
-        }
-
-        public void binderDied() {
-            Log.w(TAG, "  RemoteControlClient died");
-            // remote control client died, make sure the displays don't use it anymore
-            //  by setting its remote control client to null
-            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
-            // the dead client was maybe handling remote playback, reevaluate
-            postReevaluateRemote();
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-    /**
-     * A global counter for RemoteControlClient identifiers
-     */
-    private static int sLastRccId = 0;
-
-    private class RemotePlaybackState {
-        int mRccId;
-        int mVolume;
-        int mVolumeMax;
-        int mVolumeHandling;
-
-        private RemotePlaybackState(int id, int vol, int volMax) {
-            mRccId = id;
-            mVolume = vol;
-            mVolumeMax = volMax;
-            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-        }
-    }
-
-    /**
-     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
-     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
-     * every time we need this info.
-     */
-    private RemotePlaybackState mMainRemote;
-    /**
-     * Indicates whether the "main" RemoteControlClient is considered active.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mMainRemoteIsActive;
-    /**
-     * Indicates whether there is remote playback going on. True even if there is no "active"
-     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
-     * handles remote playback.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mHasRemotePlayback;
-
-    private static class RccPlaybackState {
-        public int mState;
-        public long mPositionMs;
-        public float mSpeed;
-
-        public RccPlaybackState(int state, long positionMs, float speed) {
-            mState = state;
-            mPositionMs = positionMs;
-            mSpeed = speed;
-        }
-
-        public void reset() {
-            mState = RemoteControlClient.PLAYSTATE_STOPPED;
-            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
-            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
-        }
-
-        @Override
-        public String toString() {
-            return stateToString() + ", "
-                    + ((mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) ?
-                            "PLAYBACK_POSITION_INVALID ," : String.valueOf(mPositionMs)) + "ms ,"
-                    + mSpeed + "X";
-        }
-
-        private String stateToString() {
-            switch (mState) {
-                case RemoteControlClient.PLAYSTATE_NONE:
-                    return "PLAYSTATE_NONE";
-                case RemoteControlClient.PLAYSTATE_STOPPED:
-                    return "PLAYSTATE_STOPPED";
-                case RemoteControlClient.PLAYSTATE_PAUSED:
-                    return "PLAYSTATE_PAUSED";
-                case RemoteControlClient.PLAYSTATE_PLAYING:
-                    return "PLAYSTATE_PLAYING";
-                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                    return "PLAYSTATE_FAST_FORWARDING";
-                case RemoteControlClient.PLAYSTATE_REWINDING:
-                    return "PLAYSTATE_REWINDING";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                    return "PLAYSTATE_SKIPPING_FORWARDS";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                    return "PLAYSTATE_SKIPPING_BACKWARDS";
-                case RemoteControlClient.PLAYSTATE_BUFFERING:
-                    return "PLAYSTATE_BUFFERING";
-                case RemoteControlClient.PLAYSTATE_ERROR:
-                    return "PLAYSTATE_ERROR";
-                default:
-                    return "[invalid playstate]";
-            }
-        }
-    }
-
-    private static class RemoteControlStackEntry implements DeathRecipient {
-        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        final public AudioService mService;
-        /**
-         * The target for the ACTION_MEDIA_BUTTON events.
-         * Always non null.
-         */
-        final public PendingIntent mMediaIntent;
-        /**
-         * The registered media button event receiver.
-         * Always non null.
-         */
-        final public ComponentName mReceiverComponent;
-        public IBinder mToken;
-        public String mCallingPackageName;
-        public int mCallingUid;
-        /**
-         * Provides access to the information to display on the remote control.
-         * May be null (when a media button event receiver is registered,
-         *     but no remote control client has been registered) */
-        public IRemoteControlClient mRcClient;
-        public RcClientDeathHandler mRcClientDeathHandler;
-        /**
-         * Information only used for non-local playback
-         */
-        public int mPlaybackType;
-        public int mPlaybackVolume;
-        public int mPlaybackVolumeMax;
-        public int mPlaybackVolumeHandling;
-        public int mPlaybackStream;
-        public RccPlaybackState mPlaybackState;
-        public IRemoteVolumeObserver mRemoteVolumeObs;
-
-        public void resetPlaybackInfo() {
-            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
-            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-            mPlaybackStream = AudioManager.STREAM_MUSIC;
-            mPlaybackState.reset();
-            mRemoteVolumeObs = null;
-        }
-
-        /** precondition: mediaIntent != null */
-        public RemoteControlStackEntry(AudioService service, PendingIntent mediaIntent,
-                ComponentName eventReceiver, IBinder token) {
-            mService = service;
-            mMediaIntent = mediaIntent;
-            mReceiverComponent = eventReceiver;
-            mToken = token;
-            mCallingUid = -1;
-            mRcClient = null;
-            mRccId = ++sLastRccId;
-            mPlaybackState = new RccPlaybackState(
-                    RemoteControlClient.PLAYSTATE_STOPPED,
-                    RemoteControlClient.PLAYBACK_POSITION_INVALID,
-                    RemoteControlClient.PLAYBACK_SPEED_1X);
-
-            resetPlaybackInfo();
-            if (mToken != null) {
-                try {
-                    mToken.linkToDeath(this, 0);
-                } catch (RemoteException e) {
-                    mService.mAudioHandler.post(new Runnable() {
-                        @Override public void run() {
-                            mService.unregisterMediaButtonIntent(mMediaIntent);
-                        }
-                    });
-                }
-            }
-        }
-
-        public void unlinkToRcClientDeath() {
-            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
-                try {
-                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
-                    mRcClientDeathHandler = null;
-                } catch (java.util.NoSuchElementException e) {
-                    // not much we can do here
-                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
-                    e.printStackTrace();
-                }
-            }
-        }
-
-        public void destroy() {
-            unlinkToRcClientDeath();
-            if (mToken != null) {
-                mToken.unlinkToDeath(this, 0);
-                mToken = null;
-            }
-        }
-
-        @Override
-        public void binderDied() {
-            mService.unregisterMediaButtonIntent(mMediaIntent);
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            destroy(); // unlink exception handled inside method
-            super.finalize();
-        }
-    }
-
-    /**
-     *  The stack of remote control event receivers.
-     *  Code sections and methods that modify the remote control event receiver stack are
-     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
-     *  stack, audio focus or RC, can lead to a change in the remote control display
-     */
-    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
-
-    /**
-     * The component the telephony package can register so telephony calls have priority to
-     * handle media button events
-     */
-    private ComponentName mMediaReceiverForCalls = null;
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control focus stack
-     */
-    private void dumpRCStack(PrintWriter pw) {
-        pw.println("\nRemote Control stack entries (last is top of stack):");
-        synchronized(mRCStack) {
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                pw.println("  pi: " + rcse.mMediaIntent +
-                        " -- pack: " + rcse.mCallingPackageName +
-                        "  -- ercvr: " + rcse.mReceiverComponent +
-                        "  -- client: " + rcse.mRcClient +
-                        "  -- uid: " + rcse.mCallingUid +
-                        "  -- type: " + rcse.mPlaybackType +
-                        "  state: " + rcse.mPlaybackState);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control stack, focusing
-     * on RemoteControlClient data
-     */
-    private void dumpRCCStack(PrintWriter pw) {
-        pw.println("\nRemote Control Client stack entries (last is top of stack):");
-        synchronized(mRCStack) {
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                pw.println("  uid: " + rcse.mCallingUid +
-                        "  -- id: " + rcse.mRccId +
-                        "  -- type: " + rcse.mPlaybackType +
-                        "  -- state: " + rcse.mPlaybackState +
-                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
-                        "  -- vol: " + rcse.mPlaybackVolume +
-                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
-                        "  -- volObs: " + rcse.mRemoteVolumeObs);
-            }
-            synchronized(mCurrentRcLock) {
-                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
-            }
-        }
-        synchronized (mMainRemote) {
-            pw.println("\nRemote Volume State:");
-            pw.println("  has remote: " + mHasRemotePlayback);
-            pw.println("  is remote active: " + mMainRemoteIsActive);
-            pw.println("  rccId: " + mMainRemote.mRccId);
-            pw.println("  volume handling: "
-                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
-                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
-            pw.println("  volume: " + mMainRemote.mVolume);
-            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the list of remote control displays
-     */
-    private void dumpRCDList(PrintWriter pw) {
-        pw.println("\nRemote Control Display list entries:");
-        synchronized(mRCStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                pw.println("  IRCD: " + di.mRcDisplay +
-                        "  -- w:" + di.mArtworkExpectedWidth +
-                        "  -- h:" + di.mArtworkExpectedHeight+
-                        "  -- wantsPosSync:" + di.mWantsPositionSync);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Remove any entry in the remote control stack that has the same package name as packageName
-     * Pre-condition: packageName != null
-     */
-    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
-        synchronized(mRCStack) {
-            if (mRCStack.empty()) {
-                return;
-            } else {
-                final PackageManager pm = mContext.getPackageManager();
-                RemoteControlStackEntry oldTop = mRCStack.peek();
-                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                // iterate over the stack entries
-                // (using an iterator on the stack so we can safely remove an entry after having
-                //  evaluated it, traversal order doesn't matter here)
-                while(stackIterator.hasNext()) {
-                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
-                    if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
-                        // a stack entry is from the package being removed, remove it from the stack
-                        stackIterator.remove();
-                        rcse.destroy();
-                    } else if (rcse.mReceiverComponent != null) {
-                        try {
-                            // Check to see if this receiver still exists.
-                            pm.getReceiverInfo(rcse.mReceiverComponent, 0);
-                        } catch (PackageManager.NameNotFoundException e) {
-                            // Not found -- remove it!
-                            stackIterator.remove();
-                            rcse.destroy();
-                        }
-                    }
-                }
-                if (mRCStack.empty()) {
-                    // no saved media button receiver
-                    mAudioHandler.sendMessage(
-                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                    null));
-                } else if (oldTop != mRCStack.peek()) {
-                    // the top of the stack has changed, save it in the system settings
-                    // by posting a message to persist it; only do this however if it has
-                    // a concrete component name (is not a transient registration)
-                    RemoteControlStackEntry rcse = mRCStack.peek();
-                    if (rcse.mReceiverComponent != null) {
-                        mAudioHandler.sendMessage(
-                                mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                        rcse.mReceiverComponent));
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Restore remote control receiver from the system settings.
-     */
-    private void restoreMediaButtonReceiver() {
-        String receiverName = Settings.System.getStringForUser(mContentResolver,
-                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
-        if ((null != receiverName) && !receiverName.isEmpty()) {
-            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
-            if (eventReceiver == null) {
-                // an invalid name was persisted
-                return;
-            }
-            // construct a PendingIntent targeted to the restored component name
-            // for the media button and register it
-            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-            //     the associated intent will be handled by the component being registered
-            mediaButtonIntent.setComponent(eventReceiver);
-            PendingIntent pi = PendingIntent.getBroadcast(mContext,
-                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
-            registerMediaButtonIntent(pi, eventReceiver, null);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Set the new remote control receiver at the top of the RC focus stack.
-     * Called synchronized on mAudioFocusLock, then mRCStack
-     * precondition: mediaIntent != null
-     */
-    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
-            IBinder token) {
-        // already at top of stack?
-        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
-            return;
-        }
-        RemoteControlStackEntry rcse = null;
-        boolean wasInsideStack = false;
-        try {
-            for (int index = mRCStack.size()-1; index >= 0; index--) {
-                rcse = mRCStack.elementAt(index);
-                if(rcse.mMediaIntent.equals(mediaIntent)) {
-                    // ok to remove element while traversing the stack since we're leaving the loop
-                    mRCStack.removeElementAt(index);
-                    wasInsideStack = true;
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification
-            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-        }
-        if (!wasInsideStack) {
-            rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
-        }
-        mRCStack.push(rcse); // rcse is never null
-
-        // post message to persist the default media button receiver
-        if (target != null) {
-            mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
-                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
-        }
-    }
-
-    /**
-     * Helper function:
-     * Remove the remote control receiver from the RC focus stack.
-     * Called synchronized on mAudioFocusLock, then mRCStack
-     * precondition: pi != null
-     */
-    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
-        try {
-            for (int index = mRCStack.size()-1; index >= 0; index--) {
-                final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                if (rcse.mMediaIntent.equals(pi)) {
-                    rcse.destroy();
-                    // ok to remove element while traversing the stack since we're leaving the loop
-                    mRCStack.removeElementAt(index);
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification
-            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mRCStack
-     */
-    private boolean isCurrentRcController(PendingIntent pi) {
-        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
-            return true;
-        }
-        return false;
-    }
-
-    //==========================================================================================
-    // Remote control display / client
-    //==========================================================================================
-    /**
-     * Update the remote control displays with the new "focused" client generation
-     */
-    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        synchronized(mRCStack) {
-            if (mRcDisplays.size() > 0) {
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = displayIterator.next();
-                    try {
-                        di.mRcDisplay.setCurrentClientId(
-                                newClientGeneration, newMediaIntent, clearing);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
-                        di.release();
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the remote control clients with the new "focused" client generation
-     */
-    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
-        // (using an iterator on the stack so we can safely remove an entry if needed,
-        //  traversal order doesn't matter here as we update all entries)
-        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-        while(stackIterator.hasNext()) {
-            RemoteControlStackEntry se = stackIterator.next();
-            if ((se != null) && (se.mRcClient != null)) {
-                try {
-                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
-                    stackIterator.remove();
-                    se.unlinkToRcClientDeath();
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the displays and clients with the new "focused" client generation and name
-     * @param newClientGeneration the new generation value matching a client update
-     * @param newMediaIntent the media button event receiver associated with the client.
-     *    May be null, which implies there is no registered media button event receiver.
-     * @param clearing true if the new client generation value maps to a remote control update
-     *    where the display should be cleared.
-     */
-    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        // send the new valid client generation ID to all displays
-        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
-        // send the new valid client generation ID to all clients
-        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_CLEAR event
-     */
-    private void onRcDisplayClear() {
-        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
-
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                mCurrentRcClientGen++;
-                // synchronously update the displays and clients with the new client generation
-                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                        null /*newMediaIntent*/, true /*clearing*/);
-            }
-        }
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_UPDATE event
-     */
-    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
-                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
-
-                    mCurrentRcClientGen++;
-                    // synchronously update the displays and clients with
-                    //      the new client generation
-                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                            rcse.mMediaIntent /*newMediaIntent*/,
-                            false /*clearing*/);
-
-                    // tell the current client that it needs to send info
-                    try {
-                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                } else {
-                    // the remote control display owner has changed between the
-                    // the message to update the display was sent, and the time it
-                    // gets to be processed (now)
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Helper function:
-     * Called synchronized on mRCStack
-     */
-    private void clearRemoteControlDisplay_syncAfRcs() {
-        synchronized(mCurrentRcLock) {
-            mCurrentRcClient = null;
-        }
-        // will cause onRcDisplayClear() to be called in AudioService's handler thread
-        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
-    }
-
-    /**
-     * Helper function for code readability: only to be called from
-     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
-     *    this method.
-     * Preconditions:
-     *    - called synchronized mAudioFocusLock then on mRCStack
-     *    - mRCStack.isEmpty() is false
-     */
-    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
-        RemoteControlStackEntry rcse = mRCStack.peek();
-        int infoFlagsAboutToBeUsed = infoChangedFlags;
-        // this is where we enforce opt-in for information display on the remote controls
-        //   with the new AudioManager.registerRemoteControlClient() API
-        if (rcse.mRcClient == null) {
-            //Log.w(TAG, "Can't update remote control display with null remote control client");
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-        synchronized(mCurrentRcLock) {
-            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
-                // new RC client, assume every type of information shall be queried
-                infoFlagsAboutToBeUsed = RC_INFO_ALL;
-            }
-            mCurrentRcClient = rcse.mRcClient;
-        }
-        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
-        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
-                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock, then mRCStack
-     * Check whether the remote control display should be updated, triggers the update if required
-     * @param infoChangedFlags the flags corresponding to the remote control client information
-     *     that has changed, if applicable (checking for the update conditions might trigger a
-     *     clear, rather than an update event).
-     */
-    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
-        // determine whether the remote control display should be refreshed
-        // if either stack is empty, there is a mismatch, so clear the RC display
-        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // determine which entry in the AudioFocus stack to consider, and compare against the
-        // top of the stack for the media button event receivers : simply using the top of the
-        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
-        // notifications playing during music playback.
-        // Crawl the AudioFocus stack from the top until an entry is found with the following
-        // characteristics:
-        // - focus gain on STREAM_MUSIC stream
-        // - non-transient focus gain on a stream other than music
-        FocusStackEntry af = null;
-        try {
-            for (int index = mFocusStack.size()-1; index >= 0; index--) {
-                FocusStackEntry fse = mFocusStack.elementAt(index);
-                if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
-                        || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
-                    af = fse;
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
-            af = null;
-        }
-        if (af == null) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
-        if ((mRCStack.peek().mCallingPackageName != null)
-                && (af.mPackageName != null)
-                && !(mRCStack.peek().mCallingPackageName.compareTo(
-                        af.mPackageName) == 0)) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-        // if the audio focus didn't originate from the same Uid as the one in which the remote
-        //   control information will be retrieved, clear
-        if (mRCStack.peek().mCallingUid != af.mCallingUid) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // refresh conditions were verified: update the remote controls
-        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
-        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
-    }
-
-    /**
-     * Helper function:
-     * Post a message to asynchronously move the media button event receiver associated with the
-     * given remote control client ID to the top of the remote control stack
-     * @param rccId
-     */
-    private void postPromoteRcc(int rccId) {
-        sendMsg(mAudioHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE,
-                rccId /*arg1*/, 0, null, 0/*delay*/);
-    }
-
-    private void onPromoteRcc(int rccId) {
-        if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                // ignore if given RCC ID is already at top of remote control stack
-                if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) {
-                    return;
-                }
-                int indexToPromote = -1;
-                try {
-                    for (int index = mRCStack.size()-1; index >= 0; index--) {
-                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                        if (rcse.mRccId == rccId) {
-                            indexToPromote = index;
-                            break;
-                        }
-                    }
-                    if (indexToPromote >= 0) {
-                        if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
-                                + " to " + (mRCStack.size()-1)); }
-                        final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote);
-                        mRCStack.push(rcse);
-                        // the RC stack changed, reevaluate the display
-                        checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
-            }//synchronized(mRCStack)
-        }//synchronized(mAudioFocusLock)
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
-     * precondition: mediaIntent != null
-     */
-    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
-            IBinder token) {
-        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
-                // new RC client, assume every type of information shall be queried
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
-     * precondition: mediaIntent != null, eventReceiver != null
-     */
-    public void unregisterMediaButtonIntent(PendingIntent mediaIntent)
-    {
-        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
-                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
-                if (topOfStackWillChange) {
-                    // current RC client will change, assume every type of info needs to be queried
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }
-        }
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
-     * precondition: c != null
-     */
-    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
-            return;
-        }
-        synchronized(mRCStack) {
-            mMediaReceiverForCalls = c;
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
-     */
-    public void unregisterMediaButtonEventReceiverForCalls() {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
-            return;
-        }
-        synchronized(mRCStack) {
-            mMediaReceiverForCalls = null;
-        }
-    }
-
-    /**
-     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
-     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
-     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
-     *     without modifying the RC stack, but while still causing the display to refresh (will
-     *     become blank as a result of this)
-     */
-    public int registerRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient, String callingPackageName) {
-        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                // store the new display information
-                try {
-                    for (int index = mRCStack.size()-1; index >= 0; index--) {
-                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                        if(rcse.mMediaIntent.equals(mediaIntent)) {
-                            // already had a remote control client?
-                            if (rcse.mRcClientDeathHandler != null) {
-                                // stop monitoring the old client's death
-                                rcse.unlinkToRcClientDeath();
-                            }
-                            // save the new remote control client
-                            rcse.mRcClient = rcClient;
-                            rcse.mCallingPackageName = callingPackageName;
-                            rcse.mCallingUid = Binder.getCallingUid();
-                            if (rcClient == null) {
-                                // here rcse.mRcClientDeathHandler is null;
-                                rcse.resetPlaybackInfo();
-                                break;
-                            }
-                            rccId = rcse.mRccId;
-
-                            // there is a new (non-null) client:
-                            // 1/ give the new client the displays (if any)
-                            if (mRcDisplays.size() > 0) {
-                                plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
-                            }
-                            // 2/ monitor the new client's death
-                            IBinder b = rcse.mRcClient.asBinder();
-                            RcClientDeathHandler rcdh =
-                                    new RcClientDeathHandler(b, rcse.mMediaIntent);
-                            try {
-                                b.linkToDeath(rcdh, 0);
-                            } catch (RemoteException e) {
-                                // remote control client is DOA, disqualify it
-                                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
-                                rcse.mRcClient = null;
-                            }
-                            rcse.mRcClientDeathHandler = rcdh;
-                            break;
-                        }
-                    }//for
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
-
-                // if the eventReceiver is at the top of the stack
-                // then check for potential refresh of the remote controls
-                if (isCurrentRcController(mediaIntent)) {
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }//synchronized(mRCStack)
-        }//synchronized(mAudioFocusLock)
-        return rccId;
-    }
-
-    /**
-     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
-     * rcClient is guaranteed non-null
-     */
-    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient) {
-        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                boolean topRccChange = false;
-                try {
-                    for (int index = mRCStack.size()-1; index >= 0; index--) {
-                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                        if ((rcse.mMediaIntent.equals(mediaIntent))
-                                && rcClient.equals(rcse.mRcClient)) {
-                            // we found the IRemoteControlClient to unregister
-                            // stop monitoring its death
-                            rcse.unlinkToRcClientDeath();
-                            // reset the client-related fields
-                            rcse.mRcClient = null;
-                            rcse.mCallingPackageName = null;
-                            topRccChange = (index == mRCStack.size()-1);
-                            // there can only be one matching RCC in the RC stack, we're done
-                            break;
-                        }
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
-                if (topRccChange) {
-                    // no more RCC for the RCD, check for potential refresh of the remote controls
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }
-        }
-    }
-
-
-    /**
-     * A class to encapsulate all the information about a remote control display.
-     * After instanciation, init() must always be called before the object is added in the list
-     * of displays.
-     * Before being removed from the list of displays, release() must always be called (otherwise
-     * it will leak death handlers).
-     */
-    private class DisplayInfoForServer implements IBinder.DeathRecipient {
-        /** may never be null */
-        private IRemoteControlDisplay mRcDisplay;
-        private IBinder mRcDisplayBinder;
-        private int mArtworkExpectedWidth = -1;
-        private int mArtworkExpectedHeight = -1;
-        private boolean mWantsPositionSync = false;
-
-        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
-            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
-            mRcDisplay = rcd;
-            mRcDisplayBinder = rcd.asBinder();
-            mArtworkExpectedWidth = w;
-            mArtworkExpectedHeight = h;
-        }
-
-        public boolean init() {
-            try {
-                mRcDisplayBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                // remote control display is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
-                return false;
-            }
-            return true;
-        }
-
-        public void release() {
-            try {
-                mRcDisplayBinder.unlinkToDeath(this, 0);
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here, the display should have been unregistered anyway
-                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
-            }
-        }
-
-        public void binderDied() {
-            synchronized(mRCStack) {
-                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
-                // remove the display from the list
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                    if (di.mRcDisplay == mRcDisplay) {
-                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
-                        displayIterator.remove();
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * The remote control displays.
-     * Access synchronized on mRCStack
-     */
-    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
-
-    /**
-     * Plug each registered display into the specified client
-     * @param rcc, guaranteed non null
-     */
-    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-            try {
-                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
-                        di.mArtworkExpectedHeight);
-                if (di.mWantsPositionSync) {
-                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
-            }
-        }
-    }
-
-    /**
-     * Is the remote control display interface already registered
-     * @param rcd
-     * @return true if the IRemoteControlDisplay is already in the list of displays
-     */
-    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Register an IRemoteControlDisplay.
-     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
-     * at the top of the stack to update the new display with its information.
-     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay to register. No effect if null.
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
-    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
-                    return;
-                }
-                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
-                if (!di.init()) {
-                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
-                    return;
-                }
-                // add RCD to list of displays
-                mRcDisplays.add(di);
-
-                // let all the remote control clients know there is a new display (so the remote
-                //   control stack traversal order doesn't matter).
-                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                while(stackIterator.hasNext()) {
-                    RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mRcClient != null) {
-                        try {
-                            rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error connecting RCD to client: ", e);
-                        }
-                    }
-                }
-
-                // we have a new display, of which all the clients are now aware: have it be updated
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * Unregister an IRemoteControlDisplay.
-     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
-     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
-     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
-     */
     public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
-        synchronized(mRCStack) {
-            if (rcd == null) {
-                return;
-            }
-
-            boolean displayWasPluggedIn = false;
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext() && !displayWasPluggedIn) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    displayWasPluggedIn = true;
-                    di.release();
-                    displayIterator.remove();
-                }
-            }
-
-            if (displayWasPluggedIn) {
-                // disconnect this remote control display from all the clients, so the remote
-                //   control stack traversal order doesn't matter
-                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mRcClient != null) {
-                        try {
-                            rcse.mRcClient.unplugRemoteControlDisplay(rcd);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
-                        }
-                    }
-                }
-            } else {
-                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
-            }
-        }
+        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
     }
 
-    /**
-     * Update the size of the artwork used by an IRemoteControlDisplay.
-     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
     public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        synchronized(mRCStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            boolean artworkSizeUpdate = false;
-            while (displayIterator.hasNext() && !artworkSizeUpdate) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
-                        di.mArtworkExpectedWidth = w;
-                        di.mArtworkExpectedHeight = h;
-                        artworkSizeUpdate = true;
-                    }
-                }
-            }
-            if (artworkSizeUpdate) {
-                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
-                // stack traversal order doesn't matter
-                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mRcClient != null) {
-                        try {
-                            rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
-                        }
-                    }
-                }
-            }
-        }
+        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
     }
 
-    /**
-     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
-     * playback position to verify that the estimated position has not drifted from the actual
-     * position. By default the check is not performed.
-     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
-     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
-     *     or disabled. Not null.
-     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
-     *     to the framework will regularly compare the estimated playback position with the actual
-     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
-     *     detected.
-     */
     public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
             boolean wantsSync) {
-        synchronized(mRCStack) {
-            boolean rcdRegistered = false;
-            // store the information about this display
-            // (display stack traversal order doesn't matter).
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    di.mWantsPositionSync = wantsSync;
-                    rcdRegistered = true;
-                    break;
-                }
-            }
-            if (!rcdRegistered) {
-                return;
-            }
-            // notify all current RemoteControlClients
-            // (stack traversal order doesn't matter as we notify all RCCs)
-            final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while (stackIterator.hasNext()) {
-                final RemoteControlStackEntry rcse = stackIterator.next();
-                if (rcse.mRcClient != null) {
-                    try {
-                        rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
-                    }
-                }
-            }
-        }
+        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
+    }
+
+    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
+    }
+
+    public void unregisterMediaButtonEventReceiverForCalls() {
+        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
+    }
+
+    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
+        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
+    }
+
+    public void unregisterMediaButtonIntent(PendingIntent pi) {
+        mMediaFocusControl.unregisterMediaButtonIntent(pi);
+    }
+
+    public int registerRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient, String callingPckg) {
+        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
+    }
+
+    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient) {
+        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
     }
 
     public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        // ignore position change requests if invalid generation ID
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                if (mCurrentRcClientGen != generationId) {
-                    return;
-                }
-            }
-        }
-        // discard any unprocessed seek request in the message queue, and replace with latest
-        sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
-                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
+        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
     }
 
-    public void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
-                ", timeMs=" + timeMs + ")");
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
-                    // tell the current client to seek to the requested location
-                    try {
-                        mCurrentRcClient.seekTo(generationId, timeMs);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                }
-            }
-        }
-    }
-
-    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
-        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
-                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
-    }
-
-    // handler for MSG_RCC_NEW_PLAYBACK_INFO
-    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
-        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
-                ", what=" + key + ",val=" + value + ")");
-        synchronized(mRCStack) {
-            // iterating from top of stack as playback information changes are more likely
-            //   on entries at the top of the remote control stack
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if (rcse.mRccId == rccId) {
-                        switch (key) {
-                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
-                                rcse.mPlaybackType = value;
-                                postReevaluateRemote();
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
-                                rcse.mPlaybackVolume = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolume = value;
-                                        mVolumePanel.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
-                                rcse.mPlaybackVolumeMax = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolumeMax = value;
-                                        mVolumePanel.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
-                                rcse.mPlaybackVolumeHandling = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolumeHandling = value;
-                                        mVolumePanel.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
-                                rcse.mPlaybackStream = value;
-                                break;
-                            default:
-                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
-                                break;
-                        }
-                        return;
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
-            }
-        }
-    }
-
-    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
-        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
-                rccId /* arg1 */, state /* arg2 */,
-                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
-    }
-
-    public void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
-        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
-                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
-        synchronized(mRCStack) {
-            // iterating from top of stack as playback information changes are more likely
-            //   on entries at the top of the remote control stack
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if (rcse.mRccId == rccId) {
-                        rcse.mPlaybackState = newState;
-                        synchronized (mMainRemote) {
-                            if (rccId == mMainRemote.mRccId) {
-                                mMainRemoteIsActive = isPlaystateActive(state);
-                                postReevaluateRemote();
-                            }
-                        }
-                        // an RCC moving to a "playing" state should become the media button
-                        //   event receiver so it can be controlled, without requiring the
-                        //   app to re-register its receiver
-                        if (isPlaystateActive(state)) {
-                            postPromoteRcc(rccId);
-                        }
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
-            }
-        }
+    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
+        mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
     }
 
     public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
-                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
-    }
-
-    // handler for MSG_RCC_NEW_VOLUME_OBS
-    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        synchronized(mRCStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if (rcse.mRccId == rccId) {
-                        rcse.mRemoteVolumeObs = rvo;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-    }
-
-    /**
-     * Checks if a remote client is active on the supplied stream type. Update the remote stream
-     * volume state if found and playing
-     * @param streamType
-     * @return false if no remote playing is currently playing
-     */
-    private boolean checkUpdateRemoteStateIfActive(int streamType) {
-        synchronized(mRCStack) {
-            // iterating from top of stack as active playback is more likely on entries at the top
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
-                            && isPlaystateActive(rcse.mPlaybackState.mState)
-                            && (rcse.mPlaybackStream == streamType)) {
-                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
-                                + ", vol =" + rcse.mPlaybackVolume);
-                        synchronized (mMainRemote) {
-                            mMainRemote.mRccId = rcse.mRccId;
-                            mMainRemote.mVolume = rcse.mPlaybackVolume;
-                            mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
-                            mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
-                            mMainRemoteIsActive = true;
-                        }
-                        return true;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-        }
-        synchronized (mMainRemote) {
-            mMainRemoteIsActive = false;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if the given playback state is considered "active", i.e. it describes a state
-     * where playback is happening, or about to
-     * @param playState the playback state to evaluate
-     * @return true if active, false otherwise (inactive or unknown)
-     */
-    private static boolean isPlaystateActive(int playState) {
-        switch (playState) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private void adjustRemoteVolume(int streamType, int direction, int flags) {
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        boolean volFixed = false;
-        synchronized (mMainRemote) {
-            if (!mMainRemoteIsActive) {
-                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
-                return;
-            }
-            rccId = mMainRemote.mRccId;
-            volFixed = (mMainRemote.mVolumeHandling ==
-                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
-        }
-        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
-        // we can only notify the remote that volume needs to be updated, and we'll get an async'
-        // update through setPlaybackInfoForRcc()
-        if (!volFixed) {
-            sendVolumeUpdateToRemote(rccId, direction);
-        }
-
-        // fire up the UI
-        mVolumePanel.postRemoteVolumeChanged(streamType, flags);
-    }
-
-    private void sendVolumeUpdateToRemote(int rccId, int direction) {
-        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
-        if (direction == 0) {
-            // only handling discrete events
-            return;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mRCStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (rcse.mRccId == rccId) {
-                        rvo = rcse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(direction, -1);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching relative volume update", e);
-            }
-        }
-    }
-
-    public int getRemoteStreamMaxVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolumeMax;
-        }
+        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
     }
 
     public int getRemoteStreamVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolume;
-        }
+        return mMediaFocusControl.getRemoteStreamVolume();
     }
 
-    public void setRemoteStreamVolume(int vol) {
-        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return;
-            }
-            rccId = mMainRemote.mRccId;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mRCStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (rcse.mRccId == rccId) {
-                        rvo = rcse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(0, vol);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching absolute volume update", e);
-            }
-        }
+    public int getRemoteStreamMaxVolume() {
+        return mMediaFocusControl.getRemoteStreamMaxVolume();
     }
 
-    /**
-     * Call to make AudioService reevaluate whether it's in a mode where remote players should
-     * have their volume controlled. In this implementation this is only to reset whether
-     * VolumePanel should display remote volumes
-     */
-    private void postReevaluateRemote() {
-        sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
+    public void setRemoteStreamVolume(int index) {
+        mMediaFocusControl.setRemoteStreamVolume(index);
     }
 
-    private void onReevaluateRemote() {
-        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
-        // is there a registered RemoteControlClient that is handling remote playback
-        boolean hasRemotePlayback = false;
-        synchronized (mRCStack) {
-            // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack
-            //   traversal order doesn't matter
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
-                    hasRemotePlayback = true;
-                    break;
-                }
-            }
-        }
-        synchronized (mMainRemote) {
-            if (mHasRemotePlayback != hasRemotePlayback) {
-                mHasRemotePlayback = hasRemotePlayback;
-                mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback);
-            }
-        }
+    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
+        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
+    }
+
+    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
+        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
+    }
+
+    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+    }
+
+    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
+        mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+    }
+
+    //==========================================================================================
+    // Audio Focus
+    //==========================================================================================
+    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
+        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
+                clientId, callingPackageName);
+    }
+
+    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
+        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
+    }
+
+    public void unregisterAudioFocusClient(String clientId) {
+        mMediaFocusControl.unregisterAudioFocusClient(clientId);
+    }
+
+    public int getCurrentAudioFocus() {
+        return mMediaFocusControl.getCurrentAudioFocus();
     }
 
     //==========================================================================================
@@ -6638,14 +4561,20 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
 
-        dumpFocusStack(pw);
-        dumpRCStack(pw);
-        dumpRCCStack(pw);
-        dumpRCDList(pw);
+        mMediaFocusControl.dump(pw);
         dumpStreamStates(pw);
         dumpRingerMode(pw);
         pw.println("\nAudio routes:");
         pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
         pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
     }
+
+    // Inform AudioFlinger of our device's low RAM attribute
+    private static void readAndSetLowRamDevice()
+    {
+        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
+        if (status != 0) {
+            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
+        }
+    }
 }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index d42bfd4..661b0fd 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -177,12 +177,10 @@
     {
         synchronized (AudioSystem.class) {
             mErrorCallback = cb;
+            if (cb != null) {
+                cb.onError(checkAudioFlinger());
+            }
         }
-        // Calling a method on AudioFlinger here makes sure that we bind to IAudioFlinger
-        // binder interface death. Not doing that would result in not being notified of
-        // media_server process death if no other method is called on AudioSystem that reaches
-        // to AudioFlinger.
-        isMicrophoneMuted();
     }
 
     private static void errorCallbackFromNative(int error)
@@ -403,4 +401,6 @@
     public static native int getPrimaryOutputFrameCount();
     public static native int getOutputLatency(int stream);
 
+    public static native int setLowRamDevice(boolean isLowRamDevice);
+    public static native int checkAudioFlinger();
 }
diff --git a/media/java/android/media/AudioTimestamp.java b/media/java/android/media/AudioTimestamp.java
new file mode 100644
index 0000000..965ba85
--- /dev/null
+++ b/media/java/android/media/AudioTimestamp.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.media;
+
+/**
+ * Structure that groups a position in frame units relative to an assumed audio stream,
+ * together with the estimated time when that frame was presented or is committed to be
+ * presented.
+ * In the case of audio output, "present" means that audio produced on device
+ * is detectable by an external observer off device.
+ * The time is based on the implementation's best effort, using whatever knowledge
+ * is available to the system, but cannot account for any delay unknown to the implementation.
+ *
+ * @see AudioTrack#getTimestamp
+ */
+public final class AudioTimestamp
+{
+    /**
+     * Position in frames relative to start of an assumed audio stream.
+     * The low-order 32 bits of position is in wrapping frame units similar to
+     * {@link AudioTrack#getPlaybackHeadPosition}.
+     */
+    public long framePosition;
+
+    /**
+     * The estimated time when frame was presented or is committed to be presented,
+     * in the same units and timebase as {@link java.lang.System#nanoTime}.
+     */
+    public long nanoTime;
+}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 9768a78..78a37c5 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -26,7 +26,7 @@
 
 /**
  * The AudioTrack class manages and plays a single audio resource for Java applications.
- * It allows streaming PCM audio buffers to the audio hardware for playback. This is
+ * It allows streaming of PCM audio buffers to the audio sink for playback. This is
  * achieved by "pushing" the data to the AudioTrack object using one of the
  *  {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
  *
@@ -53,8 +53,10 @@
  * can play before running out of data.<br>
  * For an AudioTrack using the static mode, this size is the maximum size of the sound that can
  * be played from it.<br>
- * For the streaming mode, data will be written to the hardware in chunks of
+ * For the streaming mode, data will be written to the audio sink in chunks of
  * sizes less than or equal to the total buffer size.
+ *
+ * AudioTrack is not final and thus permits subclasses, but such use is not recommended.
  */
 public class AudioTrack
 {
@@ -130,7 +132,7 @@
     private static final int ERROR_NATIVESETUP_NATIVEINITFAILED    = -20;
 
     // Events:
-    // to keep in sync with frameworks/base/include/media/AudioTrack.h
+    // to keep in sync with frameworks/av/include/media/AudioTrack.h
     /**
      * Event id denotes when playback head has reached a previously set marker.
      */
@@ -159,11 +161,12 @@
      */
     private final Object mPlayStateLock = new Object();
     /**
-     * Size of the native audio buffer.
+     * Sizes of the native audio buffer.
      */
     private int mNativeBufferSizeInBytes = 0;
+    private int mNativeBufferSizeInFrames = 0;
     /**
-     * Handler for marker events coming from the native code.
+     * Handler for events coming from the native code.
      */
     private NativeEventHandlerDelegate mEventHandlerDelegate;
     /**
@@ -171,7 +174,7 @@
      */
     private final Looper mInitializationLooper;
     /**
-     * The audio data sampling rate in Hz.
+     * The audio data source sampling rate in Hz.
      */
     private int mSampleRate; // initialized by all constructors
     /**
@@ -192,7 +195,7 @@
      */
     private int mStreamType = AudioManager.STREAM_MUSIC;
     /**
-     * The way audio is consumed by the hardware, streaming or static.
+     * The way audio is consumed by the audio sink, streaming or static.
      */
     private int mDataLoadMode = MODE_STREAM;
     /**
@@ -236,17 +239,20 @@
      *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
      *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
      *   {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
-     * @param sampleRateInHz the sample rate expressed in Hertz.
+     * @param sampleRateInHz the initial source sample rate expressed in Hz.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
      *   {@link AudioFormat#ENCODING_PCM_8BIT}
-     * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
-     *   from for playback. If using the AudioTrack in streaming mode, you can write data into
-     *   this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
-     *   this is the maximum size of the sound that will be played for this instance.
+     * @param bufferSizeInBytes the total size (in bytes) of the internal buffer where audio data is
+     *   read from for playback.
+     *   If track's creation mode is {@link #MODE_STREAM}, you can write data into
+     *   this buffer in chunks less than or equal to this size, and it is typical to use
+     *   chunks of 1/2 of the total size to permit double-buffering.
+     *   If the track's creation mode is {@link #MODE_STATIC},
+     *   this is the maximum length sample, or audio clip, that can be played by this instance.
      *   See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size
      *   for the successful creation of an AudioTrack instance in streaming mode. Using values
      *   smaller than getMinBufferSize() will result in an initialization failure.
@@ -257,7 +263,7 @@
             int bufferSizeInBytes, int mode)
     throws IllegalArgumentException {
         this(streamType, sampleRateInHz, channelConfig, audioFormat,
-                bufferSizeInBytes, mode, 0);
+                bufferSizeInBytes, mode, 0 /*session*/);
     }
 
     /**
@@ -267,7 +273,7 @@
      * is provided when creating an AudioEffect, this effect will be applied only to audio tracks
      * and media players in the same session and not to the output mix.
      * When an AudioTrack is created without specifying a session, it will create its own session
-     * which can be retreived by calling the {@link #getAudioSessionId()} method.
+     * which can be retrieved by calling the {@link #getAudioSessionId()} method.
      * If a non-zero session ID is provided, this AudioTrack will share effects attached to this
      * session
      * with all other media players or audio tracks in the same session, otherwise a new session
@@ -276,7 +282,7 @@
      *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
      *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
      *   {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
-     * @param sampleRateInHz the sample rate expressed in Hertz.
+     * @param sampleRateInHz the initial source sample rate expressed in Hz.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -365,18 +371,16 @@
            && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)
            && (streamType != AudioManager.STREAM_DTMF)) {
             throw new IllegalArgumentException("Invalid stream type.");
-        } else {
-            mStreamType = streamType;
         }
+        mStreamType = streamType;
 
         //--------------
         // sample rate, note these values are subject to change
         if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
             throw new IllegalArgumentException(sampleRateInHz
                     + "Hz is not a supported sample rate.");
-        } else {
-            mSampleRate = sampleRateInHz;
         }
+        mSampleRate = sampleRateInHz;
 
         //--------------
         // channel config
@@ -397,14 +401,10 @@
         default:
             if (!isMultichannelConfigSupported(channelConfig)) {
                 // input channel configuration features unsupported channels
-                mChannelCount = 0;
-                mChannels = AudioFormat.CHANNEL_INVALID;
-                mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
                 throw new IllegalArgumentException("Unsupported channel configuration.");
-            } else {
-                mChannels = channelConfig;
-                mChannelCount = Integer.bitCount(channelConfig);
             }
+            mChannels = channelConfig;
+            mChannelCount = Integer.bitCount(channelConfig);
         }
 
         //--------------
@@ -418,7 +418,6 @@
             mAudioFormat = audioFormat;
             break;
         default:
-            mAudioFormat = AudioFormat.ENCODING_INVALID;
             throw new IllegalArgumentException("Unsupported sample encoding."
                 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
         }
@@ -427,9 +426,8 @@
         // audio load mode
         if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) {
             throw new IllegalArgumentException("Invalid mode.");
-        } else {
-            mDataLoadMode = mode;
         }
+        mDataLoadMode = mode;
     }
 
     /**
@@ -464,7 +462,7 @@
     }
 
 
-    // Convenience method for the contructor's audio buffer size check.
+    // Convenience method for the constructor's audio buffer size check.
     // preconditions:
     //    mChannelCount is valid
     //    mAudioFormat is valid
@@ -480,6 +478,7 @@
         }
 
         mNativeBufferSizeInBytes = audioBufferSize;
+        mNativeBufferSizeInFrames = audioBufferSize / frameSizeInBytes;
     }
 
 
@@ -559,7 +558,6 @@
 
     /**
      * Returns the configured channel configuration.
-
      * See {@link AudioFormat#CHANNEL_OUT_MONO}
      * and {@link AudioFormat#CHANNEL_OUT_STEREO}.
      */
@@ -577,8 +575,7 @@
     /**
      * Returns the state of the AudioTrack instance. This is useful after the
      * AudioTrack instance has been created to check if it was initialized
-     * properly. This ensures that the appropriate hardware resources have been
-     * acquired.
+     * properly. This ensures that the appropriate resources have been acquired.
      * @see #STATE_INITIALIZED
      * @see #STATE_NO_STATIC_DATA
      * @see #STATE_UNINITIALIZED
@@ -600,14 +597,26 @@
     }
 
     /**
-     *  Returns the native frame count used by the hardware.
+     *  Returns the "native frame count", derived from the bufferSizeInBytes specified at
+     *  creation time and converted to frame units.
+     *  If track's creation mode is {@link #MODE_STATIC},
+     *  it is equal to the specified bufferSizeInBytes converted to frame units.
+     *  If track's creation mode is {@link #MODE_STREAM},
+     *  it is typically greater than or equal to the specified bufferSizeInBytes converted to frame
+     *  units; it may be rounded up to a larger value if needed by the target device implementation.
+     *  @deprecated Only accessible by subclasses, which are not recommended for AudioTrack.
+     *  See {@link AudioManager#getProperty(String)} for key
+     *  {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
      */
+    @Deprecated
     protected int getNativeFrameCount() {
         return native_get_native_frame_count();
     }
 
     /**
      * Returns marker position expressed in frames.
+     * @return marker position in wrapping frame units similar to {@link #getPlaybackHeadPosition},
+     * or zero if marker is disabled.
      */
     public int getNotificationMarkerPosition() {
         return native_get_marker_pos();
@@ -615,13 +624,19 @@
 
     /**
      * Returns the notification update period expressed in frames.
+     * Zero means that no position update notifications are being delivered.
      */
     public int getPositionNotificationPeriod() {
         return native_get_pos_update_period();
     }
 
     /**
-     * Returns the playback head position expressed in frames
+     * Returns the playback head position expressed in frames.
+     * Though the "int" type is signed 32-bits, the value should be reinterpreted as if it is
+     * unsigned 32-bits.  That is, the next position after 0x7FFFFFFF is (int) 0x80000000.
+     * This is a continuously advancing counter.  It will wrap (overflow) periodically,
+     * for example approximately once every 27:03:11 hours:minutes:seconds at 44.1 kHz.
+     * It is reset to zero by flush(), reload(), and stop().
      */
     public int getPlaybackHeadPosition() {
         return native_get_position();
@@ -640,7 +655,7 @@
     }
 
     /**
-     *  Returns the hardware output sample rate
+     *  Returns the output sample rate in Hz for the specified stream type.
      */
     static public int getNativeOutputSampleRate(int streamType) {
         return native_get_output_sample_rate(streamType);
@@ -651,7 +666,10 @@
      * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't
      * guarantee a smooth playback under load, and higher values should be chosen according to
      * the expected frequency at which the buffer will be refilled with additional data to play.
-     * @param sampleRateInHz the sample rate expressed in Hertz.
+     * For example, if you intend to dynamically set the source sample rate of an AudioTrack
+     * to a higher value than the initial source sample rate, be sure to configure the buffer size
+     * based on the highest planned sample rate.
+     * @param sampleRateInHz the source sample rate expressed in Hz.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -659,8 +677,7 @@
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
      *   {@link AudioFormat#ENCODING_PCM_8BIT}
      * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
-     *   or {@link #ERROR} if the implementation was unable to query the hardware for its output
-     *     properties,
+     *   or {@link #ERROR} if unable to query for output properties,
      *   or the minimum buffer size expressed in bytes.
      */
     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
@@ -715,6 +732,45 @@
         return mSessionId;
     }
 
+   /**
+    * Poll for a timestamp on demand.
+    *
+    * Use if you need to get the most recent timestamp outside of the event callback handler.
+    * Calling this method too often may be inefficient;
+    * if you need a high-resolution mapping between frame position and presentation time,
+    * consider implementing that at application level, based on low-resolution timestamps.
+    * The audio data at the returned position may either already have been
+    * presented, or may have not yet been presented but is committed to be presented.
+    * It is not possible to request the time corresponding to a particular position,
+    * or to request the (fractional) position corresponding to a particular time.
+    * If you need such features, consider implementing them at application level.
+    *
+    * @param timestamp a reference to a non-null AudioTimestamp instance allocated
+    *        and owned by caller.
+    * @return true if a timestamp is available, or false if no timestamp is available.
+    *         If a timestamp if available,
+    *         the AudioTimestamp instance is filled in with a position in frame units, together
+    *         with the estimated time when that frame was presented or is committed to
+    *         be presented.
+    *         In the case that no timestamp is available, any supplied instance is left unaltered.
+    */
+    public boolean getTimestamp(AudioTimestamp timestamp)
+    {
+        if (timestamp == null) {
+            throw new IllegalArgumentException();
+        }
+        // It's unfortunate, but we have to either create garbage every time or use synchronized
+        long[] longArray = new long[2];
+        int ret = native_get_timestamp(longArray);
+        if (ret != SUCCESS) {
+            return false;
+        }
+        timestamp.framePosition = longArray[0];
+        timestamp.nanoTime = longArray[1];
+        return true;
+    }
+
+
     //--------------------------------------------------------------------------
     // Initialization / configuration
     //--------------------
@@ -793,10 +849,13 @@
 
     /**
      * Sets the playback sample rate for this track. This sets the sampling rate at which
-     * the audio data will be consumed and played back, not the original sampling rate of the
-     * content. Setting it to half the sample rate of the content will cause the playback to
-     * last twice as long, but will also result in a negative pitch shift.
-     * The valid sample rate range is from 1Hz to twice the value returned by
+     * the audio data will be consumed and played back
+     * (as set by the sampleRateInHz parameter in the
+     * {@link #AudioTrack(int, int, int, int, int, int)} constructor),
+     * not the original sampling rate of the
+     * content. For example, setting it to half the sample rate of the content will cause the
+     * playback to last twice as long, but will also result in a pitch shift down by one octave.
+     * The valid sample rate range is from 1 Hz to twice the value returned by
      * {@link #getNativeOutputSampleRate(int)}.
      * @param sampleRateInHz the sample rate expressed in Hz
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
@@ -814,8 +873,11 @@
 
 
     /**
-     * Sets the position of the notification marker.
-     * @param markerInFrames marker in frames
+     * Sets the position of the notification marker.  At most one marker can be active.
+     * @param markerInFrames marker position in wrapping frame units similar to
+     * {@link #getPlaybackHeadPosition}, or zero to disable the marker.
+     * To set a marker at a position which would appear as zero due to wraparound,
+     * a workaround is to use a non-zero position near zero, such as -1 or 1.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *  {@link #ERROR_INVALID_OPERATION}
      */
@@ -845,6 +907,8 @@
      * The track must be stopped or paused for the position to be changed,
      * and must use the {@link #MODE_STATIC} mode.
      * @param positionInFrames playback head position expressed in frames
+     * Zero corresponds to start of buffer.
+     * The position must not be greater than the buffer size in frames, or negative.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
@@ -853,18 +917,28 @@
                 getPlayState() == PLAYSTATE_PLAYING) {
             return ERROR_INVALID_OPERATION;
         }
+        if (!(0 <= positionInFrames && positionInFrames <= mNativeBufferSizeInFrames)) {
+            return ERROR_BAD_VALUE;
+        }
         return native_set_position(positionInFrames);
     }
 
     /**
      * Sets the loop points and the loop count. The loop can be infinite.
      * Similarly to setPlaybackHeadPosition,
-     * the track must be stopped or paused for the position to be changed,
+     * the track must be stopped or paused for the loop points to be changed,
      * and must use the {@link #MODE_STATIC} mode.
      * @param startInFrames loop start marker expressed in frames
+     * Zero corresponds to start of buffer.
+     * The start marker must not be greater than or equal to the buffer size in frames, or negative.
      * @param endInFrames loop end marker expressed in frames
+     * The total buffer size in frames corresponds to end of buffer.
+     * The end marker must not be greater than the buffer size in frames.
+     * For looping, the end marker must not be less than or equal to the start marker,
+     * but to disable looping
+     * it is permitted for start marker, end marker, and loop count to all be 0.
      * @param loopCount the number of times the loop is looped.
-     *    A value of -1 means infinite looping.
+     *    A value of -1 means infinite looping, and 0 disables looping.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
@@ -873,14 +947,23 @@
                 getPlayState() == PLAYSTATE_PLAYING) {
             return ERROR_INVALID_OPERATION;
         }
+        if (loopCount == 0) {
+            ;   // explicitly allowed as an exception to the loop region range check
+        } else if (!(0 <= startInFrames && startInFrames < mNativeBufferSizeInFrames &&
+                startInFrames < endInFrames && endInFrames <= mNativeBufferSizeInFrames)) {
+            return ERROR_BAD_VALUE;
+        }
         return native_set_loop(startInFrames, endInFrames, loopCount);
     }
 
     /**
-     * Sets the initialization state of the instance. To be used in an AudioTrack subclass
-     * constructor to set a subclass-specific post-initialization state.
+     * Sets the initialization state of the instance. This method was originally intended to be used
+     * in an AudioTrack subclass constructor to set a subclass-specific post-initialization state.
+     * However, subclasses of AudioTrack are no longer recommended, so this method is obsolete.
      * @param state the state of the AudioTrack instance
+     * @deprecated Only accessible by subclasses, which are not recommended for AudioTrack.
      */
+    @Deprecated
     protected void setState(int state) {
         mState = state;
     }
@@ -891,6 +974,7 @@
     //--------------------
     /**
      * Starts playing an AudioTrack.
+     * If track's creation mode is {@link #MODE_STATIC}, you must have called write() prior.
      *
      * @throws IllegalStateException
      */
@@ -955,7 +1039,8 @@
 
     /**
      * Flushes the audio data currently queued for playback. Any data that has
-     * not been played back will be discarded.
+     * not been played back will be discarded.  No-op if not stopped or paused,
+     * or if the track's creation mode is not {@link #MODE_STREAM}.
      */
     public void flush() {
         if (mState == STATE_INITIALIZED) {
@@ -966,11 +1051,13 @@
     }
 
     /**
-     * Writes the audio data to the audio hardware for playback. Will block until
-     * all data has been written to the audio mixer.
+     * Writes the audio data to the audio sink for playback (streaming mode),
+     * or copies audio data for later playback (static buffer mode).
+     * In streaming mode, will block until all data has been written to the audio sink.
+     * In static buffer mode, copies the data to the buffer starting at offset 0.
      * Note that the actual playback of this data might occur after this function
      * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the mixer.
+     * in which case all of the specified data might not be written to the audio sink.
      *
      * @param audioData the array that holds the data to play.
      * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
@@ -1007,16 +1094,18 @@
 
 
     /**
-     * Writes the audio data to the audio hardware for playback. Will block until
-     * all data has been written to the audio mixer.
+     * Writes the audio data to the audio sink for playback (streaming mode),
+     * or copies audio data for later playback (static buffer mode).
+     * In streaming mode, will block until all data has been written to the audio sink.
+     * In static buffer mode, copies the data to the buffer starting at offset 0.
      * Note that the actual playback of this data might occur after this function
      * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the mixer.
+     * in which case all of the specified data might not be written to the audio sink.
      *
      * @param audioData the array that holds the data to play.
      * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
      *     starts.
-     * @param sizeInShorts the number of bytes to read in audioData after the offset.
+     * @param sizeInShorts the number of shorts to read in audioData after the offset.
      * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
       *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
       *    the parameters don't resolve to valid data and indexes.
@@ -1049,8 +1138,8 @@
 
     /**
      * Notifies the native resource to reuse the audio data already loaded in the native
-     * layer. This call is only valid with AudioTrack instances that don't use the streaming
-     * model.
+     * layer, that is to rewind to start of buffer.
+     * The track's creation mode must be {@link #MODE_STATIC}.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *  {@link #ERROR_INVALID_OPERATION}
      */
@@ -1091,8 +1180,9 @@
 
     /**
      * Sets the send level of the audio track to the attached auxiliary effect
-     * {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
-     * <p>By default the send level is 0, so even if an effect is attached to the player
+     * {@link #attachAuxEffect(int)}.  The level value range is 0.0f to 1.0f.
+     * Values are clamped to the (0.0f, 1.0f) interval if outside this range.
+     * <p>By default the send level is 0.0f, so even if an effect is attached to the player
      * this method must be called for the effect to be applied.
      * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
      * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
@@ -1270,6 +1360,11 @@
 
     private native final int native_get_latency();
 
+    // longArray must be a non-null array of length >= 2
+    // [0] is assigned the frame position
+    // [1] is assigned the time in CLOCK_MONOTONIC nanoseconds
+    private native final int native_get_timestamp(long[] longArray);
+
     private native final int native_set_loop(int start, int end, int loopCount);
 
     static private native final int native_get_output_sample_rate(int streamType);
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4cd3e37..20eb356 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -291,6 +291,20 @@
     }
 
     /**
+     * Returns the offset and length of thumbnail inside the JPEG file, or
+     * {@code null} if there is no thumbnail.
+     *
+     * @return two-element array, the offset in the first value, and length in
+     *         the second, or {@code null} if no thumbnail was found.
+     * @hide
+     */
+    public long[] getThumbnailRange() {
+        synchronized (sLock) {
+            return getThumbnailRangeNative(mFilename);
+        }
+    }
+
+    /**
      * Stores the latitude and longitude value in a float array. The first element is
      * the latitude, and the second element is the longitude. Returns false if the
      * Exif tags are not available.
@@ -416,4 +430,6 @@
     private native void commitChangesNative(String fileName);
 
     private native byte[] getThumbnailNative(String fileName);
+
+    private native long[] getThumbnailRangeNative(String fileName);
 }
diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java
new file mode 100644
index 0000000..9a39994
--- /dev/null
+++ b/media/java/android/media/FocusRequester.java
@@ -0,0 +1,244 @@
+/*
+ * 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 android.media;
+
+import android.media.MediaFocusControl.AudioFocusDeathHandler;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ * Class to handle all the information about a user of audio focus. The lifecycle of each
+ * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
+ * stack to its release.
+ */
+class FocusRequester {
+
+    // on purpose not using this classe's name, as it will only be used from MediaFocusControl
+    private static final String TAG = "MediaFocusControl";
+    private static final boolean DEBUG = false;
+
+    private AudioFocusDeathHandler mDeathHandler;
+    private final IAudioFocusDispatcher mFocusDispatcher; // may be null
+    private final IBinder mSourceRef;
+    private final String mClientId;
+    private final String mPackageName;
+    private final int mCallingUid;
+    /**
+     * the audio focus gain request that caused the addition of this object in the focus stack.
+     */
+    private final int mFocusGainRequest;
+    /**
+     * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
+     *  it never lost focus.
+     */
+    private int mFocusLossReceived;
+    /**
+     * the stream type associated with the focus request
+     */
+    private final int mStreamType;
+
+    FocusRequester(int streamType, int focusRequest,
+            IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
+            String pn, int uid) {
+        mStreamType = streamType;
+        mFocusDispatcher = afl;
+        mSourceRef = source;
+        mClientId = id;
+        mDeathHandler = hdlr;
+        mPackageName = pn;
+        mCallingUid = uid;
+        mFocusGainRequest = focusRequest;
+        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
+    }
+
+
+    boolean hasSameClient(String otherClient) {
+        try {
+            return mClientId.compareTo(otherClient) == 0;
+        } catch (NullPointerException e) {
+            return false;
+        }
+    }
+
+    boolean hasSameBinder(IBinder ib) {
+        return (mSourceRef != null) && mSourceRef.equals(ib);
+    }
+
+    boolean hasSamePackage(String pack) {
+        try {
+            return mPackageName.compareTo(pack) == 0;
+        } catch (NullPointerException e) {
+            return false;
+        }
+    }
+
+    boolean hasSameUid(int uid) {
+        return mCallingUid == uid;
+    }
+
+
+    int getGainRequest() {
+        return mFocusGainRequest;
+    }
+
+    int getStreamType() {
+        return mStreamType;
+    }
+
+
+    private static String focusChangeToString(int focus) {
+        switch(focus) {
+            case AudioManager.AUDIOFOCUS_NONE:
+                return "none";
+            case AudioManager.AUDIOFOCUS_GAIN:
+                return "GAIN";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                return "GAIN_TRANSIENT";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                return "GAIN_TRANSIENT_MAY_DUCK";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+                return "GAIN_TRANSIENT_EXCLUSIVE";
+            case AudioManager.AUDIOFOCUS_LOSS:
+                return "LOSS";
+            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                return "LOSS_TRANSIENT";
+            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                return "LOSS_TRANSIENT_CAN_DUCK";
+            default:
+                return "[invalid focus change" + focus + "]";
+        }
+    }
+
+    private String focusGainToString() {
+        return focusChangeToString(mFocusGainRequest);
+    }
+
+    private String focusLossToString() {
+        return focusChangeToString(mFocusLossReceived);
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("  source:" + mSourceRef
+                + " -- pack: " + mPackageName
+                + " -- client: " + mClientId
+                + " -- gain: " + focusGainToString()
+                + " -- loss: " + focusLossToString()
+                + " -- uid: " + mCallingUid
+                + " -- stream: " + mStreamType);
+    }
+
+
+    void release() {
+        try {
+            if (mSourceRef != null && mDeathHandler != null) {
+                mSourceRef.unlinkToDeath(mDeathHandler, 0);
+                mDeathHandler = null;
+            }
+        } catch (java.util.NoSuchElementException e) {
+            Log.e(TAG, "FocusRequester.release() hit ", e);
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        release();
+        super.finalize();
+    }
+
+    /**
+     * For a given audio focus gain request, return the audio focus loss type that will result
+     * from it, taking into account any previous focus loss.
+     * @param gainRequest
+     * @return the audio focus loss type that matches the gain request
+     */
+    private int focusLossForGainRequest(int gainRequest) {
+        switch(gainRequest) {
+            case AudioManager.AUDIOFOCUS_GAIN:
+                switch(mFocusLossReceived) {
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                    case AudioManager.AUDIOFOCUS_NONE:
+                        return AudioManager.AUDIOFOCUS_LOSS;
+                }
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                switch(mFocusLossReceived) {
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_NONE:
+                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                        return AudioManager.AUDIOFOCUS_LOSS;
+                }
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                switch(mFocusLossReceived) {
+                    case AudioManager.AUDIOFOCUS_NONE:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                        return AudioManager.AUDIOFOCUS_LOSS;
+                }
+            default:
+                Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
+                        return AudioManager.AUDIOFOCUS_NONE;
+        }
+    }
+
+    void handleExternalFocusGain(int focusGain) {
+        int focusLoss = focusLossForGainRequest(focusGain);
+        handleFocusLoss(focusLoss);
+    }
+
+    void handleFocusGain(int focusGain) {
+        try {
+            if (mFocusDispatcher != null) {
+                if (DEBUG) {
+                    Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
+                        + mClientId);
+                }
+                mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
+            }
+            mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
+        } catch (android.os.RemoteException e) {
+            Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
+        }
+    }
+
+    void handleFocusLoss(int focusLoss) {
+        try {
+            if (focusLoss != mFocusLossReceived) {
+                if (mFocusDispatcher != null) {
+                    if (DEBUG) {
+                        Log.v(TAG, "dispatching " + focusChangeToString(focusLoss) + " to "
+                            + mClientId);
+                    }
+                    mFocusDispatcher.dispatchAudioFocusChange(focusLoss, mClientId);
+                }
+                mFocusLossReceived = focusLoss;
+            }
+        } catch (android.os.RemoteException e) {
+            Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
+        }
+    }
+
+}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fda8c1b..e3b87dd 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
 import android.media.IRemoteControlDisplay;
 import android.media.IRemoteVolumeObserver;
 import android.media.IRingtonePlayer;
+import android.media.Rating;
 import android.net.Uri;
 import android.view.KeyEvent;
 
@@ -33,25 +34,27 @@
  * {@hide}
  */
 interface IAudioService {
-    
-    void adjustVolume(int direction, int flags);
 
-    oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction);
+    void adjustVolume(int direction, int flags, String callingPackage);
 
-    void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
+    oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
+            String callingPackage);
 
-    void adjustStreamVolume(int streamType, int direction, int flags);
+    void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
+            String callingPackage);
 
-    void adjustMasterVolume(int direction, int flags);
+    void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
 
-    void setStreamVolume(int streamType, int index, int flags);
+    void adjustMasterVolume(int direction, int flags, String callingPackage);
+
+    void setStreamVolume(int streamType, int index, int flags, String callingPackage);
 
     oneway void setRemoteStreamVolume(int index);
 
-    void setMasterVolume(int index, int flags);
-    
+    void setMasterVolume(int index, int flags, String callingPackage);
+
     void setStreamSolo(int streamType, boolean state, IBinder cb);
-   	
+
     void setStreamMute(int streamType, boolean state, IBinder cb);
 
     boolean isStreamMute(int streamType);
@@ -67,19 +70,19 @@
     int getStreamMaxVolume(int streamType);
 
     int getMasterMaxVolume();
-    
+
     int getLastAudibleStreamVolume(int streamType);
 
     int getLastAudibleMasterVolume();
 
     void setRingerMode(int ringerMode);
-    
+
     int getRingerMode();
 
     void setVibrateSetting(int vibrateType, int vibrateSetting);
-    
+
     int getVibrateSetting(int vibrateType);
-    
+
     boolean shouldVibrate(int vibrateType);
 
     void setMode(int mode, IBinder cb);
@@ -87,15 +90,17 @@
     int getMode();
 
     oneway void playSoundEffect(int effectType);
-  
+
     oneway void playSoundEffectVolume(int effectType, float volume);
 
     boolean loadSoundEffects();
-  
+
     oneway void unloadSoundEffects();
 
     oneway void reloadAudioSettings();
 
+    oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
+
     void setSpeakerphoneOn(boolean on);
 
     boolean isSpeakerphoneOn();
@@ -108,15 +113,15 @@
 
     boolean isBluetoothA2dpOn();
 
-    oneway void setRemoteSubmixOn(boolean on, int address);
+    int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName);
 
-    int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l,
-            String clientId, String callingPackageName);
+    int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId);
 
-    int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);
-    
     void unregisterAudioFocusClient(String clientId);
 
+    int getCurrentAudioFocus();
+
     oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
     void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
 
@@ -136,7 +141,7 @@
      * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
      *   display doesn't need to receive artwork.
      */
-    oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
+    boolean registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
     /**
      * Unregister an IRemoteControlDisplay.
      * No effect if the IRemoteControlDisplay hasn't been successfully registered.
@@ -173,6 +178,15 @@
      * @param timeMs the time in ms to seek to, must be positive.
      */
      void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
+     /**
+      * Notify the user of a RemoteControlClient that it should update its metadata with the
+      * new value for the given key.
+      * @param generationId the RemoteControlClient generation counter for which this request is
+      *         issued. Requests for an older generation than current one will be ignored.
+      * @param key the metadata key for which a new value exists
+      * @param value the new metadata value
+      */
+     void updateRemoteControlClientMetadata(int generationId, int key, in Rating value);
 
     /**
      * Do not use directly, use instead
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index 2236129..999b8ba 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -17,6 +17,7 @@
 
 import android.graphics.Bitmap;
 import android.media.IRemoteControlDisplay;
+import android.media.Rating;
 
 /**
  * @hide
@@ -40,6 +41,13 @@
     void onInformationRequested(int generationId, int infoFlags);
 
     /**
+     * Notifies a remote control client that information for the given generation ID is
+     * requested for the given IRemoteControlDisplay alone.
+     * @param rcd the display to which current info should be sent
+     */
+    void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h);
+
+    /**
      * Sets the generation counter of the current client that is displayed on the remote control.
      */
     void setCurrentClientGenerationId(int clientGeneration);
@@ -49,4 +57,5 @@
     void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
     void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
     void seekTo(int clientGeneration, long timeMs);
+    void updateMetadata(int clientGeneration, int key, in Rating value);
 }
\ No newline at end of file
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
new file mode 100644
index 0000000..a346e17
--- /dev/null
+++ b/media/java/android/media/Image.java
@@ -0,0 +1,190 @@
+/*
+ * 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 android.media;
+
+import java.nio.ByteBuffer;
+import java.lang.AutoCloseable;
+
+/**
+ * <p>A single complete image buffer to use with a media source such as a
+ * {@link MediaCodec} or a
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
+ *
+ * <p>This class allows for efficient direct application access to the pixel
+ * data of the Image through one or more
+ * {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
+ * {@link Plane} that describes the layout of the pixel data in that plane. Due
+ * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
+ * Images are not directly usable as as UI resources.</p>
+ *
+ * <p>Since Images are often directly produced or consumed by hardware
+ * components, they are a limited resource shared across the system, and should
+ * be closed as soon as they are no longer needed.</p>
+ *
+ * <p>For example, when using the {@link ImageReader} class to read out Images
+ * from various media sources, not closing old Image objects will prevent the
+ * availability of new Images once
+ * {@link ImageReader#getMaxImages the maximum outstanding image count} is
+ * reached. When this happens, the function acquiring new Images will typically
+ * throw an {@link IllegalStateException}.</p>
+ *
+ * @see ImageReader
+ */
+public abstract class Image implements AutoCloseable {
+    /**
+     * @hide
+     */
+    protected Image() {
+    }
+
+    /**
+     * Get the format for this image. This format determines the number of
+     * ByteBuffers needed to represent the image, and the general layout of the
+     * pixel data in each in ByteBuffer.
+     *
+     * <p>
+     * The format is one of the values from
+     * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
+     * formats and the planes is as follows:
+     * </p>
+     *
+     * <table>
+     * <tr>
+     *   <th>Format</th>
+     *   <th>Plane count</th>
+     *   <th>Layout details</th>
+     * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
+     *   <td>1</td>
+     *   <td>Compressed data, so row and pixel strides are 0. To uncompress, use
+     *      {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
+     *   </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
+     *   <td>3</td>
+     *   <td>A luminance plane followed by the Cb and Cr chroma planes.
+     *     The chroma planes have half the width and height of the luminance
+     *     plane (4:2:0 subsampling). Each pixel sample in each plane has 8 bits.
+     *     Each plane has its own row stride and pixel stride.</td>
+     * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
+     *   <td>1</td>
+     *   <td>A single plane of raw sensor image data, with 16 bits per color
+     *     sample. The details of the layout need to be queried from the source of
+     *     the raw sensor data, such as
+     *     {@link android.hardware.camera2.CameraDevice CameraDevice}.
+     *   </td>
+     * </tr>
+     * </table>
+     *
+     * @see android.graphics.ImageFormat
+     */
+    public abstract int getFormat();
+
+    /**
+     * The width of the image in pixels. For formats where some color channels
+     * are subsampled, this is the width of the largest-resolution plane.
+     */
+    public abstract int getWidth();
+
+    /**
+     * The height of the image in pixels. For formats where some color channels
+     * are subsampled, this is the height of the largest-resolution plane.
+     */
+    public abstract int getHeight();
+
+    /**
+     * Get the timestamp associated with this frame.
+     * <p>
+     * The timestamp is measured in nanoseconds, and is monotonically
+     * increasing. However, the zero point and whether the timestamp can be
+     * compared against other sources of time or images depend on the source of
+     * this image.
+     * </p>
+     */
+    public abstract long getTimestamp();
+
+    /**
+     * Get the array of pixel planes for this Image. The number of planes is
+     * determined by the format of the Image.
+     */
+    public abstract Plane[] getPlanes();
+
+    /**
+     * Free up this frame for reuse.
+     * <p>
+     * After calling this method, calling any methods on this {@code Image} will
+     * result in an {@link IllegalStateException}, and attempting to read from
+     * {@link ByteBuffer ByteBuffers} returned by an earlier
+     * {@link Plane#getBuffer} call will have undefined behavior.
+     * </p>
+     */
+    @Override
+    public abstract void close();
+
+    /**
+     * <p>A single color plane of image data.</p>
+     *
+     * <p>The number and meaning of the planes in an Image are determined by the
+     * format of the Image.</p>
+     *
+     * <p>Once the Image has been closed, any access to the the plane's
+     * ByteBuffer will fail.</p>
+     *
+     * @see #getFormat
+     */
+    public static abstract class Plane {
+        /**
+         * @hide
+         */
+        protected Plane() {
+        }
+
+        /**
+         * <p>The row stride for this color plane, in bytes.</p>
+         *
+         * <p>This is the distance between the start of two consecutive rows of
+         * pixels in the image. The row stride is always greater than 0.</p>
+         */
+        public abstract int getRowStride();
+        /**
+         * <p>The distance between adjacent pixel samples, in bytes.</p>
+         *
+         * <p>This is the distance between two consecutive pixel values in a row
+         * of pixels. It may be larger than the size of a single pixel to
+         * account for interleaved image data or padded formats.
+         * The pixel stride is always greater than 0.</p>
+         */
+        public abstract int getPixelStride();
+        /**
+         * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
+         * containing the frame data.</p>
+         *
+         * <p>In particular, the buffer returned will always have
+         * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
+         * the underlying data could be mapped as a pointer in JNI without doing
+         * any copies with {@code GetDirectBufferAddress}.</p>
+         *
+         * @return the byte buffer containing the image data for this plane.
+         */
+        public abstract ByteBuffer getBuffer();
+    }
+
+}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
new file mode 100644
index 0000000..1bd32c4
--- /dev/null
+++ b/media/java/android/media/ImageReader.java
@@ -0,0 +1,737 @@
+/*
+ * 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 android.media;
+
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.view.Surface;
+
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * <p>The ImageReader class allows direct application access to image data
+ * rendered into a {@link android.view.Surface}</p>
+ *
+ * <p>Several Android media API classes accept Surface objects as targets to
+ * render to, including {@link MediaPlayer}, {@link MediaCodec},
+ * {@link android.hardware.camera2.CameraDevice}, and
+ * {@link android.renderscript.Allocation RenderScript Allocations}. The image
+ * sizes and formats that can be used with each source vary, and should be
+ * checked in the documentation for the specific API.</p>
+ *
+ * <p>The image data is encapsulated in {@link Image} objects, and multiple such
+ * objects can be accessed at the same time, up to the number specified by the
+ * {@code maxImages} constructor parameter. New images sent to an ImageReader
+ * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
+ * or {@link #acquireNextImage} call. Due to memory limits, an image source will
+ * eventually stall or drop Images in trying to render to the Surface if the
+ * ImageReader does not obtain and release Images at a rate equal to the
+ * production rate.</p>
+ */
+public class ImageReader implements AutoCloseable {
+
+    /**
+     * Returned by nativeImageSetup when acquiring the image was successful.
+     */
+    private static final int ACQUIRE_SUCCESS = 0;
+    /**
+     * Returned by nativeImageSetup when we couldn't acquire the buffer,
+     * because there were no buffers available to acquire.
+     */
+    private static final int ACQUIRE_NO_BUFS = 1;
+    /**
+     * Returned by nativeImageSetup when we couldn't acquire the buffer
+     * because the consumer has already acquired {@maxImages} and cannot
+     * acquire more than that.
+     */
+    private static final int ACQUIRE_MAX_IMAGES = 2;
+
+    /**
+     * <p>Create a new reader for images of the desired size and format.</p>
+     *
+     * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
+     * objects that can be be acquired from the {@code ImageReader}
+     * simultaneously. Requesting more buffers will use up more memory, so it is
+     * important to use only the minimum number necessary for the use case.</p>
+     *
+     * <p>The valid sizes and formats depend on the source of the image
+     * data.</p>
+     *
+     * @param width
+     *            The width in pixels of the Images that this reader will produce.
+     * @param height
+     *            The height in pixels of the Images that this reader will produce.
+     * @param format
+     *            The format of the Image that this reader will produce. This
+     *            must be one of the {@link android.graphics.ImageFormat} or
+     *            {@link android.graphics.PixelFormat} constants. Note that
+     *            not all formats is supported, like ImageFormat.NV21.
+     * @param maxImages
+     *            The maximum number of images the user will want to
+     *            access simultaneously. This should be as small as possible to limit
+     *            memory use. Once maxImages Images are obtained by the user, one of them
+     *            has to be released before a new Image will become available for access
+     *            through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
+     *            Must be greater than 0.
+     *
+     * @see Image
+     */
+    public static ImageReader newInstance(int width, int height, int format, int maxImages) {
+        return new ImageReader(width, height, format, maxImages);
+    }
+
+    /**
+     * @hide
+     */
+    protected ImageReader(int width, int height, int format, int maxImages) {
+        mWidth = width;
+        mHeight = height;
+        mFormat = format;
+        mMaxImages = maxImages;
+
+        if (width < 1 || height < 1) {
+            throw new IllegalArgumentException(
+                "The image dimensions must be positive");
+        }
+        if (mMaxImages < 1) {
+            throw new IllegalArgumentException(
+                "Maximum outstanding image count must be at least 1");
+        }
+
+        if (format == ImageFormat.NV21) {
+            throw new IllegalArgumentException(
+                    "NV21 format is not supported");
+        }
+
+        mNumPlanes = getNumPlanesFromFormat();
+
+        nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
+
+        mSurface = nativeGetSurface();
+    }
+
+    /**
+     * The width of each {@link Image}, in pixels.
+     *
+     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+     * {@link #acquireNextImage}) will have the same dimensions as specified in
+     * {@link #newInstance}.</p>
+     *
+     * @return the width of an Image
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * The height of each {@link Image}, in pixels.
+     *
+     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+     * {@link #acquireNextImage}) will have the same dimensions as specified in
+     * {@link #newInstance}.</p>
+     *
+     * @return the height of an Image
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * The {@link ImageFormat image format} of each Image.
+     *
+     * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
+     *  (for example, with {@link #acquireNextImage}) will have the same format as specified in
+     * {@link #newInstance}.</p>
+     *
+     * @return the format of an Image
+     *
+     * @see ImageFormat
+     */
+    public int getImageFormat() {
+        return mFormat;
+    }
+
+    /**
+     * Maximum number of images that can be acquired from the ImageReader by any time (for example,
+     * with {@link #acquireNextImage}).
+     *
+     * <p>An image is considered acquired after it's returned by a function from ImageReader, and
+     * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
+     * </p>
+     *
+     * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
+     * acquire function throwing a {@link IllegalStateException}. Furthermore,
+     * while the max number of images have been acquired by the ImageReader user, the producer
+     * enqueueing additional images may stall until at least one image has been released. </p>
+     *
+     * @return Maximum number of images for this ImageReader.
+     *
+     * @see Image#close
+     */
+    public int getMaxImages() {
+        return mMaxImages;
+    }
+
+    /**
+     * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
+     * {@code ImageReader}.</p>
+     *
+     * <p>Until valid image data is rendered into this {@link Surface}, the
+     * {@link #acquireNextImage} method will return {@code null}. Only one source
+     * can be producing data into this Surface at the same time, although the
+     * same {@link Surface} can be reused with a different API once the first source is
+     * disconnected from the {@link Surface}.</p>
+     *
+     * @return A {@link Surface} to use for a drawing target for various APIs.
+     */
+    public Surface getSurface() {
+        return mSurface;
+    }
+
+    /**
+     * <p>
+     * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
+     * {@link Image images}. Returns {@code null} if no new image is available.
+     * </p>
+     * <p>
+     * This operation will acquire all the images possible from the ImageReader,
+     * but {@link #close} all images that aren't the latest. This function is
+     * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
+     * more suited for real-time processing.
+     * </p>
+     * <p>
+     * Note that {@link #getMaxImages maxImages} should be at least 2 for
+     * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
+     * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
+     * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
+     * with less than two images of margin, that is
+     * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
+     * </p>
+     * <p>
+     * This operation will fail by throwing an {@link IllegalStateException} if
+     * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
+     * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
+     * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
+     * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
+     * will be thrown until more images are
+     * released with {@link Image#close}.
+     * </p>
+     *
+     * @return latest frame of image data, or {@code null} if no image data is available.
+     * @throws IllegalStateException if too many images are currently acquired
+     */
+    public Image acquireLatestImage() {
+        Image image = acquireNextImage();
+        if (image == null) {
+            return null;
+        }
+        try {
+            for (;;) {
+                Image next = acquireNextImageNoThrowISE();
+                if (next == null) {
+                    Image result = image;
+                    image = null;
+                    return result;
+                }
+                image.close();
+                image = next;
+            }
+        } finally {
+            if (image != null) {
+                image.close();
+            }
+        }
+    }
+
+    /**
+     * Don't throw IllegalStateException if there are too many images acquired.
+     *
+     * @return Image if acquiring succeeded, or null otherwise.
+     *
+     * @hide
+     */
+    public Image acquireNextImageNoThrowISE() {
+        SurfaceImage si = new SurfaceImage();
+        return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
+    }
+
+    /**
+     * Attempts to acquire the next image from the underlying native implementation.
+     *
+     * <p>
+     * Note that unexpected failures will throw at the JNI level.
+     * </p>
+     *
+     * @param si A blank SurfaceImage.
+     * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
+     *
+     * @see #ACQUIRE_MAX_IMAGES
+     * @see #ACQUIRE_NO_BUFS
+     * @see #ACQUIRE_SUCCESS
+     */
+    private int acquireNextSurfaceImage(SurfaceImage si) {
+
+        int status = nativeImageSetup(si);
+
+        switch (status) {
+            case ACQUIRE_SUCCESS:
+                si.createSurfacePlanes();
+                si.setImageValid(true);
+            case ACQUIRE_NO_BUFS:
+            case ACQUIRE_MAX_IMAGES:
+                break;
+            default:
+                throw new AssertionError("Unknown nativeImageSetup return code " + status);
+        }
+
+        return status;
+    }
+
+    /**
+     * <p>
+     * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
+     * no new image is available.
+     * </p>
+     *
+     * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
+     * automatically release older images, and allow slower-running processing routines to catch
+     * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
+     * batch/background processing. Incorrectly using this function can cause images to appear
+     * with an ever-increasing delay, followed by a complete stall where no new images seem to
+     * appear.
+     * </p>
+     *
+     * <p>
+     * This operation will fail by throwing an {@link IllegalStateException} if
+     * {@code maxImages} have been acquired with {@link #acquireNextImage} or
+     * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
+     * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
+     * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
+     * {@link IllegalStateException} will be thrown until more images are released with
+     * {@link Image#close}.
+     * </p>
+     *
+     * @return a new frame of image data, or {@code null} if no image data is available.
+     * @throws IllegalStateException if {@code maxImages} images are currently acquired
+     * @see #acquireLatestImage
+     */
+    public Image acquireNextImage() {
+        SurfaceImage si = new SurfaceImage();
+        int status = acquireNextSurfaceImage(si);
+
+        switch (status) {
+            case ACQUIRE_SUCCESS:
+                return si;
+            case ACQUIRE_NO_BUFS:
+                return null;
+            case ACQUIRE_MAX_IMAGES:
+                throw new IllegalStateException(
+                        String.format(
+                                "maxImages (%d) has already been acquired, " +
+                                "call #close before acquiring more.", mMaxImages));
+            default:
+                throw new AssertionError("Unknown nativeImageSetup return code " + status);
+        }
+    }
+
+    /**
+     * <p>Return the frame to the ImageReader for reuse.</p>
+     */
+    private void releaseImage(Image i) {
+        if (! (i instanceof SurfaceImage) ) {
+            throw new IllegalArgumentException(
+                "This image was not produced by an ImageReader");
+        }
+        SurfaceImage si = (SurfaceImage) i;
+        if (si.getReader() != this) {
+            throw new IllegalArgumentException(
+                "This image was not produced by this ImageReader");
+        }
+
+        si.clearSurfacePlanes();
+        nativeReleaseImage(i);
+        si.setImageValid(false);
+    }
+
+    /**
+     * Register a listener to be invoked when a new image becomes available
+     * from the ImageReader.
+     *
+     * @param listener
+     *            The listener that will be run.
+     * @param handler
+     *            The handler on which the listener should be invoked, or null
+     *            if the listener should be invoked on the calling thread's looper.
+     * @throws IllegalArgumentException
+     *            If no handler specified and the calling thread has no looper.
+     */
+    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+        synchronized (mListenerLock) {
+            if (listener != null) {
+                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+                if (looper == null) {
+                    throw new IllegalArgumentException(
+                            "handler is null but the current thread is not a looper");
+                }
+                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
+                    mListenerHandler = new ListenerHandler(looper);
+                }
+                mListener = listener;
+            } else {
+                mListener = null;
+                mListenerHandler = null;
+            }
+        }
+    }
+
+    /**
+     * Callback interface for being notified that a new image is available.
+     *
+     * <p>
+     * The onImageAvailable is called per image basis, that is, callback fires for every new frame
+     * available from ImageReader.
+     * </p>
+     */
+    public interface OnImageAvailableListener {
+        /**
+         * Callback that is called when a new image is available from ImageReader.
+         *
+         * @param reader the ImageReader the callback is associated with.
+         * @see ImageReader
+         * @see Image
+         */
+        void onImageAvailable(ImageReader reader);
+    }
+
+    /**
+     * Free up all the resources associated with this ImageReader.
+     *
+     * <p>
+     * After calling this method, this ImageReader can not be used. Calling
+     * any methods on this ImageReader and Images previously provided by
+     * {@link #acquireNextImage} or {@link #acquireLatestImage}
+     * will result in an {@link IllegalStateException}, and attempting to read from
+     * {@link ByteBuffer ByteBuffers} returned by an earlier
+     * {@link Image.Plane#getBuffer Plane#getBuffer} call will
+     * have undefined behavior.
+     * </p>
+     */
+    @Override
+    public void close() {
+        setOnImageAvailableListener(null, null);
+        nativeClose();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Only a subset of the formats defined in
+     * {@link android.graphics.ImageFormat ImageFormat} and
+     * {@link android.graphics.PixelFormat PixelFormat} are supported by
+     * ImageReader. When reading RGB data from a surface, the formats defined in
+     * {@link android.graphics.PixelFormat PixelFormat} can be used, when
+     * reading YUV, JPEG or raw sensor data (for example, from camera or video
+     * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
+     * are used.
+     */
+    private int getNumPlanesFromFormat() {
+        switch (mFormat) {
+            case ImageFormat.YV12:
+            case ImageFormat.YUV_420_888:
+            case ImageFormat.NV21:
+                return 3;
+            case ImageFormat.NV16:
+                return 2;
+            case PixelFormat.RGB_565:
+            case PixelFormat.RGBA_8888:
+            case PixelFormat.RGBX_8888:
+            case PixelFormat.RGB_888:
+            case ImageFormat.JPEG:
+            case ImageFormat.YUY2:
+            case ImageFormat.Y8:
+            case ImageFormat.Y16:
+            case ImageFormat.RAW_SENSOR:
+                return 1;
+            default:
+                throw new UnsupportedOperationException(
+                        String.format("Invalid format specified %d", mFormat));
+        }
+    }
+
+    /**
+     * Called from Native code when an Event happens.
+     *
+     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
+     * synchronized appropriately.
+     */
+    private static void postEventFromNative(Object selfRef) {
+        @SuppressWarnings("unchecked")
+        WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
+        final ImageReader ir = weakSelf.get();
+        if (ir == null) {
+            return;
+        }
+
+        final Handler handler;
+        synchronized (ir.mListenerLock) {
+            handler = ir.mListenerHandler;
+        }
+        if (handler != null) {
+            handler.sendEmptyMessage(0);
+        }
+    }
+
+
+    private final int mWidth;
+    private final int mHeight;
+    private final int mFormat;
+    private final int mMaxImages;
+    private final int mNumPlanes;
+    private final Surface mSurface;
+
+    private final Object mListenerLock = new Object();
+    private OnImageAvailableListener mListener;
+    private ListenerHandler mListenerHandler;
+
+    /**
+     * This field is used by native code, do not access or modify.
+     */
+    private long mNativeContext;
+
+    /**
+     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
+     */
+    private final class ListenerHandler extends Handler {
+        public ListenerHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            OnImageAvailableListener listener;
+            synchronized (mListenerLock) {
+                listener = mListener;
+            }
+            if (listener != null) {
+                listener.onImageAvailable(ImageReader.this);
+            }
+        }
+    }
+
+    private class SurfaceImage extends android.media.Image {
+        public SurfaceImage() {
+            mIsImageValid = false;
+        }
+
+        @Override
+        public void close() {
+            if (mIsImageValid) {
+                ImageReader.this.releaseImage(this);
+            }
+        }
+
+        public ImageReader getReader() {
+            return ImageReader.this;
+        }
+
+        @Override
+        public int getFormat() {
+            if (mIsImageValid) {
+                return ImageReader.this.mFormat;
+            } else {
+                throw new IllegalStateException("Image is already released");
+            }
+        }
+
+        @Override
+        public int getWidth() {
+            if (mIsImageValid) {
+                return ImageReader.this.mWidth;
+            } else {
+                throw new IllegalStateException("Image is already released");
+            }
+        }
+
+        @Override
+        public int getHeight() {
+            if (mIsImageValid) {
+                return ImageReader.this.mHeight;
+            } else {
+                throw new IllegalStateException("Image is already released");
+            }
+        }
+
+        @Override
+        public long getTimestamp() {
+            if (mIsImageValid) {
+                return mTimestamp;
+            } else {
+                throw new IllegalStateException("Image is already released");
+            }
+        }
+
+        @Override
+        public Plane[] getPlanes() {
+            if (mIsImageValid) {
+                // Shallow copy is fine.
+                return mPlanes.clone();
+            } else {
+                throw new IllegalStateException("Image is already released");
+            }
+        }
+
+        @Override
+        protected final void finalize() throws Throwable {
+            try {
+                close();
+            } finally {
+                super.finalize();
+            }
+        }
+
+        private void setImageValid(boolean isValid) {
+            mIsImageValid = isValid;
+        }
+
+        private boolean isImageValid() {
+            return mIsImageValid;
+        }
+
+        private void clearSurfacePlanes() {
+            if (mIsImageValid) {
+                for (int i = 0; i < mPlanes.length; i++) {
+                    if (mPlanes[i] != null) {
+                        mPlanes[i].clearBuffer();
+                        mPlanes[i] = null;
+                    }
+                }
+            }
+        }
+
+        private void createSurfacePlanes() {
+            mPlanes = new SurfacePlane[ImageReader.this.mNumPlanes];
+            for (int i = 0; i < ImageReader.this.mNumPlanes; i++) {
+                mPlanes[i] = nativeCreatePlane(i);
+            }
+        }
+        private class SurfacePlane extends android.media.Image.Plane {
+            // SurfacePlane instance is created by native code when a new SurfaceImage is created
+            private SurfacePlane(int index, int rowStride, int pixelStride) {
+                mIndex = index;
+                mRowStride = rowStride;
+                mPixelStride = pixelStride;
+            }
+
+            @Override
+            public ByteBuffer getBuffer() {
+                if (SurfaceImage.this.isImageValid() == false) {
+                    throw new IllegalStateException("Image is already released");
+                }
+                if (mBuffer != null) {
+                    return mBuffer;
+                } else {
+                    mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex);
+                    // Set the byteBuffer order according to host endianness (native order),
+                    // otherwise, the byteBuffer order defaults to ByteOrder.BIG_ENDIAN.
+                    return mBuffer.order(ByteOrder.nativeOrder());
+                }
+            }
+
+            @Override
+            public int getPixelStride() {
+                if (SurfaceImage.this.isImageValid()) {
+                    return mPixelStride;
+                } else {
+                    throw new IllegalStateException("Image is already released");
+                }
+            }
+
+            @Override
+            public int getRowStride() {
+                if (SurfaceImage.this.isImageValid()) {
+                    return mRowStride;
+                } else {
+                    throw new IllegalStateException("Image is already released");
+                }
+            }
+
+            private void clearBuffer() {
+                mBuffer = null;
+            }
+
+            final private int mIndex;
+            final private int mPixelStride;
+            final private int mRowStride;
+
+            private ByteBuffer mBuffer;
+        }
+
+        /**
+         * This field is used to keep track of native object and used by native code only.
+         * Don't modify.
+         */
+        private long mLockedBuffer;
+
+        /**
+         * This field is set by native code during nativeImageSetup().
+         */
+        private long mTimestamp;
+
+        private SurfacePlane[] mPlanes;
+        private boolean mIsImageValid;
+
+        private synchronized native ByteBuffer nativeImageGetBuffer(int idx);
+        private synchronized native SurfacePlane nativeCreatePlane(int idx);
+    }
+
+    private synchronized native void nativeInit(Object weakSelf, int w, int h,
+                                                    int fmt, int maxImgs);
+    private synchronized native void nativeClose();
+    private synchronized native void nativeReleaseImage(Image i);
+    private synchronized native Surface nativeGetSurface();
+
+    /**
+     * @return A return code {@code ACQUIRE_*}
+     *
+     * @see #ACQUIRE_SUCCESS
+     * @see #ACQUIRE_NO_BUFS
+     * @see #ACQUIRE_MAX_IMAGES
+     */
+    private synchronized native int nativeImageSetup(Image i);
+
+    /**
+     * We use a class initializer to allow the native code to cache some
+     * field offsets.
+     */
+    private static native void nativeClassInit();
+    static {
+        System.loadLibrary("media_jni");
+        nativeClassInit();
+    }
+}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d703642c..5175830 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -20,7 +20,9 @@
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
 import android.media.MediaFormat;
+import android.os.Bundle;
 import android.view.Surface;
+
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Map;
@@ -164,7 +166,8 @@
      *
      * The following is a partial list of defined mime types and their semantics:
      * <ul>
-     * <li>"video/x-vnd.on2.vp8" - VPX video (i.e. video in .webm)
+     * <li>"video/x-vnd.on2.vp8" - VP8 video (i.e. video in .webm)
+     * <li>"video/x-vnd.on2.vp9" - VP9 video (i.e. video in .webm)
      * <li>"video/avc" - H.264/AVC video
      * <li>"video/mp4v-es" - MPEG4 video
      * <li>"video/3gpp" - H.263 video
@@ -293,12 +296,36 @@
      */
     public native final void flush();
 
+    /**
+     * Thrown when a crypto error occurs while queueing a secure input buffer.
+     */
     public final static class CryptoException extends RuntimeException {
         public CryptoException(int errorCode, String detailMessage) {
             super(detailMessage);
             mErrorCode = errorCode;
         }
 
+        /**
+         * This indicates that no key has been set to perform the requested
+         * decrypt operation.
+         */
+        public static final int ERROR_NO_KEY = 1;
+
+        /**
+         * This indicates that the key used for decryption is no longer
+         * valid due to license term expiration.
+         */
+        public static final int ERROR_KEY_EXPIRED = 2;
+
+        /**
+         * This indicates that a required crypto resource was not able to be
+         * allocated while attempting the requested operation.
+         */
+        public static final int ERROR_RESOURCE_BUSY = 3;
+
+        /**
+         * Retrieve the error code associated with a CryptoException
+         */
         public int getErrorCode() {
             return mErrorCode;
         }
@@ -430,6 +457,9 @@
      * @param presentationTimeUs The time at which this buffer should be rendered.
      * @param flags A bitmask of flags {@link #BUFFER_FLAG_SYNC_FRAME},
      *              {@link #BUFFER_FLAG_CODEC_CONFIG} or {@link #BUFFER_FLAG_END_OF_STREAM}.
+     * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
+     *              An error code associated with the exception helps identify the
+     *              reason for the failure.
      */
     public native final void queueSecureInputBuffer(
             int index,
@@ -545,6 +575,52 @@
     public native final String getName();
 
     /**
+     * Change a video encoder's target bitrate on the fly. The value is an
+     * Integer object containing the new bitrate in bps.
+     */
+    public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
+
+    /**
+     * Temporarily suspend/resume encoding of input data. While suspended
+     * input data is effectively discarded instead of being fed into the
+     * encoder. This parameter really only makes sense to use with an encoder
+     * in "surface-input" mode, as the client code has no control over the
+     * input-side of the encoder in that case.
+     * The value is an Integer object containing the value 1 to suspend
+     * or the value 0 to resume.
+     */
+    public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+
+    /**
+     * Request that the encoder produce a sync frame "soon".
+     * Provide an Integer with the value 0.
+     */
+    public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+
+    /**
+     * Communicate additional parameter changes to the component instance.
+     */
+    public final void setParameters(Bundle params) {
+        if (params == null) {
+            return;
+        }
+
+        String[] keys = new String[params.size()];
+        Object[] values = new Object[params.size()];
+
+        int i = 0;
+        for (final String key: params.keySet()) {
+            keys[i] = key;
+            values[i] = params.get(key);
+            ++i;
+        }
+
+        setParameters(keys, values);
+    }
+
+    private native final void setParameters(String[] keys, Object[] values);
+
+    /**
      * Get the codec info. If the codec was created by createDecoderByType
      * or createEncoderByType, what component is chosen is not known beforehand,
      * and thus the caller does not have the MediaCodecInfo.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index aeed7d4..90c12c6 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -72,7 +72,8 @@
     /**
      * Encapsulates the capabilities of a given codec component.
      * For example, what profile/level combinations it supports and what colorspaces
-     * it is capable of providing the decoded data in.
+     * it is capable of providing the decoded data in, as well as some
+     * codec-type specific capability flags.
      * <p>You can get an instance for a given {@link MediaCodecInfo} object with
      * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type.
      */
@@ -139,6 +140,24 @@
          * OMX_COLOR_FORMATTYPE.
          */
         public int[] colorFormats;
+
+        private final static int FLAG_SupportsAdaptivePlayback       = (1 << 0);
+        private int flags;
+
+        /**
+         * <b>video decoder only</b>: codec supports seamless resolution changes.
+         */
+        public final static String FEATURE_AdaptivePlayback       = "adaptive-playback";
+
+        /**
+         * Query codec feature capabilities.
+         */
+        public final boolean isFeatureSupported(String name) {
+            if (name.equals(FEATURE_AdaptivePlayback)) {
+                return (flags & FLAG_SupportsAdaptivePlayback) != 0;
+            }
+            return false;
+        }
     };
 
     /**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 7677d8a1..6b278d4 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -108,7 +108,19 @@
      * @param uuid The UUID of the crypto scheme.
      */
     public static final boolean isCryptoSchemeSupported(UUID uuid) {
-        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid));
+        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), null);
+    }
+
+    /**
+     * Query if the given scheme identified by its UUID is supported on
+     * this device, and whether the drm plugin is able to handle the
+     * media container format specified by mimeType.
+     * @param uuid The UUID of the crypto scheme.
+     * @param mimeType The MIME type of the media container, e.g. "video/mp4"
+     *   or "video/webm"
+     */
+    public static final boolean isCryptoSchemeSupported(UUID uuid, String mimeType) {
+        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), mimeType);
     }
 
     private static final byte[] getByteArrayFromUUID(UUID uuid) {
@@ -124,7 +136,8 @@
         return uuidBytes;
     }
 
-    private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid);
+    private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid,
+                                                                      String mimeType);
 
     /**
      * Instantiate a MediaDrm object
@@ -273,6 +286,7 @@
      * Open a new session with the MediaDrm object.  A session ID is returned.
      *
      * @throws NotProvisionedException if provisioning is needed
+     * @throws ResourceBusyException if required resources are in use
      */
     public native byte[] openSession() throws NotProvisionedException;
 
@@ -379,6 +393,7 @@
      * reprovisioning is required
      * @throws DeniedByServerException if the response indicates that the
      * server rejected the request
+     * @throws ResourceBusyException if required resources are in use
      */
     public native byte[] provideKeyResponse(byte[] scope, byte[] response)
         throws NotProvisionedException, DeniedByServerException;
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
new file mode 100644
index 0000000..2a7a731
--- /dev/null
+++ b/media/java/android/media/MediaFocusControl.java
@@ -0,0 +1,2505 @@
+/*
+ * 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 android.media;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.PendingIntent.OnFinished;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.IBinder.DeathRecipient;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Stack;
+
+/**
+ * @hide
+ *
+ */
+public class MediaFocusControl implements OnFinished {
+
+    private static final String TAG = "MediaFocusControl";
+
+    /** Debug remote control client/display feature */
+    protected static final boolean DEBUG_RC = false;
+    /** Debug volumes */
+    protected static final boolean DEBUG_VOL = false;
+
+    /** Used to alter media button redirection when the phone is ringing. */
+    private boolean mIsRinging = false;
+
+    private final PowerManager.WakeLock mMediaEventWakeLock;
+    private final MediaEventHandler mEventHandler;
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final VolumeController mVolumeController;
+    private final BroadcastReceiver mReceiver = new PackageIntentsReceiver();
+    private final AppOpsManager mAppOps;
+    private final KeyguardManager mKeyguardManager;
+    private final AudioService mAudioService;
+
+    protected MediaFocusControl(Looper looper, Context cntxt,
+            VolumeController volumeCtrl, AudioService as) {
+        mEventHandler = new MediaEventHandler(looper);
+        mContext = cntxt;
+        mContentResolver = mContext.getContentResolver();
+        mVolumeController = volumeCtrl;
+        mAudioService = as;
+
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mMainRemote = new RemotePlaybackState(-1,
+                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC),
+                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC));
+
+        // Register for phone state monitoring
+        TelephonyManager tmgr = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+        // Register for package addition/removal/change intent broadcasts
+        //    for media button receiver persistence
+        IntentFilter pkgFilter = new IntentFilter();
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+        pkgFilter.addDataScheme("package");
+        mContext.registerReceiver(mReceiver, pkgFilter);
+
+        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mKeyguardManager =
+                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+
+        mHasRemotePlayback = false;
+        mMainRemoteIsActive = false;
+        postReevaluateRemote();
+    }
+
+    protected void dump(PrintWriter pw) {
+        dumpFocusStack(pw);
+        dumpRCStack(pw);
+        dumpRCCStack(pw);
+        dumpRCDList(pw);
+    }
+
+    //==========================================================================================
+    // Internal event handling
+    //==========================================================================================
+
+    // event handler messages
+    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 0;
+    private static final int MSG_RCDISPLAY_CLEAR = 1;
+    private static final int MSG_RCDISPLAY_UPDATE = 2;
+    private static final int MSG_REEVALUATE_REMOTE = 3;
+    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
+    private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
+    private static final int MSG_PROMOTE_RCC = 6;
+    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
+    private static final int MSG_RCC_SEEK_REQUEST = 8;
+    private static final int MSG_RCC_UPDATE_METADATA = 9;
+    private static final int MSG_RCDISPLAY_INIT_INFO = 10;
+
+    // sendMsg() flags
+    /** 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. */
+    private static final int SENDMSG_NOOP = 1;
+    /** If the msg is already queued, queue this one and leave the old. */
+    private static final int SENDMSG_QUEUE = 2;
+
+    private static void sendMsg(Handler handler, int msg,
+            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
+
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+
+        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
+    }
+
+    private class MediaEventHandler extends Handler {
+        MediaEventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_PERSIST_MEDIABUTTONRECEIVER:
+                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
+                    break;
+
+                case MSG_RCDISPLAY_CLEAR:
+                    onRcDisplayClear();
+                    break;
+
+                case MSG_RCDISPLAY_UPDATE:
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
+                    break;
+
+                case MSG_REEVALUATE_REMOTE:
+                    onReevaluateRemote();
+                    break;
+
+                case MSG_RCC_NEW_PLAYBACK_INFO:
+                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
+                            ((Integer)msg.obj).intValue() /* value */);
+                    break;
+
+                case MSG_RCC_NEW_VOLUME_OBS:
+                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
+                            (IRemoteVolumeObserver)msg.obj /* rvo */);
+                    break;
+
+                case MSG_RCC_NEW_PLAYBACK_STATE:
+                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */,
+                            msg.arg2 /* state */,
+                            (RccPlaybackState)msg.obj /* newState */);
+                    break;
+
+                case MSG_RCC_SEEK_REQUEST:
+                    onSetRemoteControlClientPlaybackPosition(
+                            msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
+                    break;
+
+                case MSG_RCC_UPDATE_METADATA:
+                    onUpdateRemoteControlClientMetadata(msg.arg1 /*genId*/, msg.arg2 /*key*/,
+                            (Rating) msg.obj /* value */);
+                    break;
+
+                case MSG_PROMOTE_RCC:
+                    onPromoteRcc(msg.arg1);
+                    break;
+
+                case MSG_RCDISPLAY_INIT_INFO:
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
+                            msg.arg1/*w*/, msg.arg2/*h*/);
+                    break;
+            }
+        }
+    }
+
+
+    //==========================================================================================
+    // AudioFocus
+    //==========================================================================================
+
+    /* constant to identify focus stack entry that is used to hold the focus while the phone
+     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+     * entering and exiting calls.
+     */
+    protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+
+    private final static Object mAudioFocusLock = new Object();
+
+    private final static Object mRingingLock = new Object();
+
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (state == TelephonyManager.CALL_STATE_RINGING) {
+                //Log.v(TAG, " CALL_STATE_RINGING");
+                synchronized(mRingingLock) {
+                    mIsRinging = true;
+                }
+            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
+                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
+                synchronized(mRingingLock) {
+                    mIsRinging = false;
+                }
+            }
+        }
+    };
+
+    /**
+     * Discard the current audio focus owner.
+     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
+     * focus), remove it from the stack, and clear the remote control display.
+     */
+    protected void discardAudioFocusOwner() {
+        synchronized(mAudioFocusLock) {
+            if (!mFocusStack.empty()) {
+                // notify the current focus owner it lost focus after removing it from stack
+                final FocusRequester exFocusOwner = mFocusStack.pop();
+                exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
+                exFocusOwner.release();
+                // clear RCD
+                synchronized(mRCStack) {
+                    clearRemoteControlDisplay_syncAfRcs();
+                }
+            }
+        }
+    }
+
+    private void notifyTopOfAudioFocusStack() {
+        // notify the top of the stack it gained focus
+        if (!mFocusStack.empty()) {
+            if (canReassignAudioFocus()) {
+                mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
+            }
+        }
+    }
+
+    /**
+     * Focus is requested, propagate the associated loss throughout the stack.
+     * @param focusGain the new focus gain that will later be added at the top of the stack
+     */
+    private void propagateFocusLossFromGain_syncAf(int focusGain) {
+        // going through the audio focus stack to signal new focus, traversing order doesn't
+        // matter as all entries respond to the same external focus gain
+        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+        while(stackIterator.hasNext()) {
+            stackIterator.next().handleExternalFocusGain(focusGain);
+        }
+    }
+
+    private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the audio focus stack
+     */
+    private void dumpFocusStack(PrintWriter pw) {
+        pw.println("\nAudio Focus stack entries (last is top of stack):");
+        synchronized(mAudioFocusLock) {
+            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+            while(stackIterator.hasNext()) {
+                stackIterator.next().dump(pw);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock
+     * Remove a focus listener from the focus stack.
+     * @param clientToRemove the focus listener
+     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
+     *   focus, notify the next item in the stack it gained focus.
+     */
+    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
+        // is the current top of the focus stack abandoning focus? (because of request, not death)
+        if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
+        {
+            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
+            FocusRequester fr = mFocusStack.pop();
+            fr.release();
+            if (signal) {
+                // notify the new top of the stack it gained focus
+                notifyTopOfAudioFocusStack();
+                // there's a new top of the stack, let the remote control know
+                synchronized(mRCStack) {
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }
+        } else {
+            // focus is abandoned by a client that's not at the top of the stack,
+            // no need to update focus.
+            // (using an iterator on the stack so we can safely remove an entry after having
+            //  evaluated it, traversal order doesn't matter here)
+            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+            while(stackIterator.hasNext()) {
+                FocusRequester fr = (FocusRequester)stackIterator.next();
+                if(fr.hasSameClient(clientToRemove)) {
+                    Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
+                            + clientToRemove);
+                    stackIterator.remove();
+                    fr.release();
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock
+     * Remove focus listeners from the focus stack for a particular client when it has died.
+     */
+    private void removeFocusStackEntryForClient(IBinder cb) {
+        // is the owner of the audio focus part of the client to remove?
+        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
+                mFocusStack.peek().hasSameBinder(cb);
+        // (using an iterator on the stack so we can safely remove an entry after having
+        //  evaluated it, traversal order doesn't matter here)
+        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+        while(stackIterator.hasNext()) {
+            FocusRequester fr = (FocusRequester)stackIterator.next();
+            if(fr.hasSameBinder(cb)) {
+                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
+                stackIterator.remove();
+                // the client just died, no need to unlink to its death
+            }
+        }
+        if (isTopOfStackForClientToRemove) {
+            // we removed an entry at the top of the stack:
+            //  notify the new top of the stack it gained focus.
+            notifyTopOfAudioFocusStack();
+            // there's a new top of the stack, let the remote control know
+            synchronized(mRCStack) {
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
+     */
+    private boolean canReassignAudioFocus() {
+        // focus requests are rejected during a phone call or when the phone is ringing
+        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
+        if (!mFocusStack.isEmpty() && mFocusStack.peek().hasSameClient(IN_VOICE_COMM_FOCUS_ID)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
+     * stack if necessary.
+     */
+    protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+
+        AudioFocusDeathHandler(IBinder cb) {
+            mCb = cb;
+        }
+
+        public void binderDied() {
+            synchronized(mAudioFocusLock) {
+                Log.w(TAG, "  AudioFocus   audio focus client died");
+                removeFocusStackEntryForClient(mCb);
+            }
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+    protected int getCurrentAudioFocus() {
+        synchronized(mAudioFocusLock) {
+            if (mFocusStack.empty()) {
+                return AudioManager.AUDIOFOCUS_NONE;
+            } else {
+                return mFocusStack.peek().getGainRequest();
+            }
+        }
+    }
+
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
+    protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
+        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
+        // we need a valid binder callback for clients
+        if (!cb.pingBinder()) {
+            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
+                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        synchronized(mAudioFocusLock) {
+            if (!canReassignAudioFocus()) {
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+
+            // handle the potential premature death of the new holder of the focus
+            // (premature death == death before abandoning focus)
+            // Register for client death notification
+            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+            try {
+                cb.linkToDeath(afdh, 0);
+            } catch (RemoteException e) {
+                // client has already died!
+                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+
+            if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
+                // if focus is already owned by this client and the reason for acquiring the focus
+                // hasn't changed, don't do anything
+                if (mFocusStack.peek().getGainRequest() == focusChangeHint) {
+                    // unlink death handler so it can be gc'ed.
+                    // linkToDeath() creates a JNI global reference preventing collection.
+                    cb.unlinkToDeath(afdh, 0);
+                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+                }
+                // the reason for the audio focus request has changed: remove the current top of
+                // stack and respond as if we had a new focus owner
+                FocusRequester fr = mFocusStack.pop();
+                fr.release();
+            }
+
+            // focus requester might already be somewhere below in the stack, remove it
+            removeFocusStackEntry(clientId, false /* signal */);
+
+            // propagate the focus change through the stack
+            if (!mFocusStack.empty()) {
+                propagateFocusLossFromGain_syncAf(focusChangeHint);
+            }
+
+            // push focus requester at the top of the audio focus stack
+            mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
+                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
+
+            // there's a new top of the stack, let the remote control know
+            synchronized(mRCStack) {
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }//synchronized(mAudioFocusLock)
+
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
+    /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener)  */
+    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
+        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
+        try {
+            // this will take care of notifying the new focus owner if needed
+            synchronized(mAudioFocusLock) {
+                removeFocusStackEntry(clientId, true /*signal*/);
+            }
+        } catch (java.util.ConcurrentModificationException cme) {
+            // Catching this exception here is temporary. It is here just to prevent
+            // a crash seen when the "Silent" notification is played. This is believed to be fixed
+            // but this try catch block is left just to be safe.
+            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
+            cme.printStackTrace();
+        }
+
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
+
+    protected void unregisterAudioFocusClient(String clientId) {
+        synchronized(mAudioFocusLock) {
+            removeFocusStackEntry(clientId, false);
+        }
+    }
+
+
+    //==========================================================================================
+    // RemoteControl
+    //==========================================================================================
+    /**
+     * No-op if the key code for keyEvent is not a valid media key
+     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
+     * @param keyEvent the key event to send
+     */
+    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
+    }
+
+    /**
+     * No-op if the key code for keyEvent is not a valid media key
+     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
+     * @param keyEvent the key event to send
+     */
+    protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
+        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
+    }
+
+    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        // sanity check on the incoming key event
+        if (!isValidMediaKeyEvent(keyEvent)) {
+            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
+            return;
+        }
+        // event filtering for telephony
+        synchronized(mRingingLock) {
+            synchronized(mRCStack) {
+                if ((mMediaReceiverForCalls != null) &&
+                        (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
+                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
+                    return;
+                }
+            }
+        }
+        // event filtering based on voice-based interactions
+        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
+            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
+        } else {
+            dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        }
+    }
+
+    /**
+     * Handles the dispatching of the media button events to the telephony package.
+     * Precondition: mMediaReceiverForCalls != null
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                    null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Handles the dispatching of the media button events to one of the registered listeners,
+     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+        }
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        synchronized(mRCStack) {
+            if (!mRCStack.empty()) {
+                // send the intent that was registered by the client
+                try {
+                    mRCStack.peek().mMediaIntent.send(mContext,
+                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
+                            keyIntent, this, mEventHandler);
+                } catch (CanceledException e) {
+                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
+                    e.printStackTrace();
+                }
+            } else {
+                // legacy behavior when nobody registered their media button event receiver
+                //    through AudioManager
+                if (needWakeLock) {
+                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+                }
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                            null, mKeyEventDone,
+                            mEventHandler, Activity.RESULT_OK, null, null);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+
+    /**
+     * The different actions performed in response to a voice button key event.
+     */
+    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
+    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
+    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
+
+    private final Object mVoiceEventLock = new Object();
+    private boolean mVoiceButtonDown;
+    private boolean mVoiceButtonHandled;
+
+    /**
+     * Filter key events that may be used for voice-based interactions
+     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
+     *    media buttons that can be used to trigger voice-based interactions.
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (DEBUG_RC) {
+            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
+        }
+
+        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
+        int keyAction = keyEvent.getAction();
+        synchronized (mVoiceEventLock) {
+            if (keyAction == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    // initial down
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled
+                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                    // long-press, start voice-based interactions
+                    mVoiceButtonHandled = true;
+                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
+                }
+            } else if (keyAction == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    // voice button up
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
+                    }
+                }
+            }
+        }//synchronized (mVoiceEventLock)
+
+        // take action after media button event filtering for voice-based interactions
+        switch (voiceButtonAction) {
+            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
+                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
+                break;
+            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
+                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
+                // then start the voice-based interactions
+                startVoiceBasedInteractions(needWakeLock);
+                break;
+            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
+                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
+                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
+                break;
+        }
+    }
+
+    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
+        // send DOWN event
+        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
+        dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        // send UP event
+        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
+        dispatchMediaKeyEvent(keyEvent, needWakeLock);
+
+    }
+
+    private class PackageIntentsReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    // a package is being removed, not replaced
+                    String packageName = intent.getData().getSchemeSpecificPart();
+                    if (packageName != null) {
+                        cleanupMediaButtonReceiverForPackage(packageName, true);
+                    }
+                }
+            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
+                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
+                String packageName = intent.getData().getSchemeSpecificPart();
+                if (packageName != null) {
+                    cleanupMediaButtonReceiverForPackage(packageName, false);
+                }
+            }
+        }
+    }
+
+    protected static boolean isMediaKeyCode(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_CLOSE:
+            case KeyEvent.KEYCODE_MEDIA_EJECT:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            return false;
+        }
+        return MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode());
+    }
+
+    /**
+     * Checks whether the given key code is one that can trigger the launch of voice-based
+     *   interactions.
+     * @param keyCode the key code associated with the key event
+     * @return true if the key is one of the supported voice-based interaction triggers
+     */
+    private static boolean isValidVoiceInputKeyCode(int keyCode) {
+        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tell the system to start voice-based interactions / voice commands
+     */
+    private void startVoiceBasedInteractions(boolean needWakeLock) {
+        Intent voiceIntent = null;
+        // select which type of search to launch:
+        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
+        //    with EXTRA_SECURE set to true if the device is securely locked
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+        if (!isLocked && pm.isScreenOn()) {
+            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
+        } else {
+            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+                    isLocked && mKeyguardManager.isKeyguardSecure());
+            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
+        }
+        // start the search activity
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (voiceIntent != null) {
+                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "No activity for search: " + e);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+            if (needWakeLock) {
+                mMediaEventWakeLock.release();
+            }
+        }
+    }
+
+    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
+
+    // only set when wakelock was acquired, no need to check value when received
+    private static final String EXTRA_WAKELOCK_ACQUIRED =
+            "android.media.AudioService.WAKELOCK_ACQUIRED";
+
+    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
+            int resultCode, String resultData, Bundle resultExtras) {
+        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
+            mMediaEventWakeLock.release();
+        }
+    }
+
+    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            Bundle extras = intent.getExtras();
+            if (extras == null) {
+                return;
+            }
+            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
+                mMediaEventWakeLock.release();
+            }
+        }
+    };
+
+    /**
+     * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
+     */
+    private final Object mCurrentRcLock = new Object();
+    /**
+     * The one remote control client which will receive a request for display information.
+     * This object may be null.
+     * Access protected by mCurrentRcLock.
+     */
+    private IRemoteControlClient mCurrentRcClient = null;
+    /**
+     * The PendingIntent associated with mCurrentRcClient. Its value is irrelevant
+     * if mCurrentRcClient is null
+     */
+    private PendingIntent mCurrentRcClientIntent = null;
+
+    private final static int RC_INFO_NONE = 0;
+    private final static int RC_INFO_ALL =
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
+
+    /**
+     * A monotonically increasing generation counter for mCurrentRcClient.
+     * Only accessed with a lock on mCurrentRcLock.
+     * No value wrap-around issues as we only act on equal values.
+     */
+    private int mCurrentRcClientGen = 0;
+
+    /**
+     * Inner class to monitor remote control client deaths, and remove the client for the
+     * remote control stack if necessary.
+     */
+    private class RcClientDeathHandler implements IBinder.DeathRecipient {
+        final private IBinder mCb; // To be notified of client's death
+        final private PendingIntent mMediaIntent;
+
+        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
+            mCb = cb;
+            mMediaIntent = pi;
+        }
+
+        public void binderDied() {
+            Log.w(TAG, "  RemoteControlClient died");
+            // remote control client died, make sure the displays don't use it anymore
+            //  by setting its remote control client to null
+            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
+            // the dead client was maybe handling remote playback, reevaluate
+            postReevaluateRemote();
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+    /**
+     * A global counter for RemoteControlClient identifiers
+     */
+    private static int sLastRccId = 0;
+
+    private class RemotePlaybackState {
+        int mRccId;
+        int mVolume;
+        int mVolumeMax;
+        int mVolumeHandling;
+
+        private RemotePlaybackState(int id, int vol, int volMax) {
+            mRccId = id;
+            mVolume = vol;
+            mVolumeMax = volMax;
+            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+        }
+    }
+
+    /**
+     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
+     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
+     * every time we need this info.
+     */
+    private RemotePlaybackState mMainRemote;
+    /**
+     * Indicates whether the "main" RemoteControlClient is considered active.
+     * Use synchronized on mMainRemote.
+     */
+    private boolean mMainRemoteIsActive;
+    /**
+     * Indicates whether there is remote playback going on. True even if there is no "active"
+     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
+     * handles remote playback.
+     * Use synchronized on mMainRemote.
+     */
+    private boolean mHasRemotePlayback;
+
+    private static class RccPlaybackState {
+        public int mState;
+        public long mPositionMs;
+        public float mSpeed;
+
+        public RccPlaybackState(int state, long positionMs, float speed) {
+            mState = state;
+            mPositionMs = positionMs;
+            mSpeed = speed;
+        }
+
+        public void reset() {
+            mState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
+            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
+        }
+
+        @Override
+        public String toString() {
+            return stateToString() + ", " + posToString() + ", " + mSpeed + "X";
+        }
+
+        private String posToString() {
+            if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) {
+                return "PLAYBACK_POSITION_INVALID";
+            } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+                return "PLAYBACK_POSITION_ALWAYS_UNKNOWN";
+            } else {
+                return (String.valueOf(mPositionMs) + "ms");
+            }
+        }
+
+        private String stateToString() {
+            switch (mState) {
+                case RemoteControlClient.PLAYSTATE_NONE:
+                    return "PLAYSTATE_NONE";
+                case RemoteControlClient.PLAYSTATE_STOPPED:
+                    return "PLAYSTATE_STOPPED";
+                case RemoteControlClient.PLAYSTATE_PAUSED:
+                    return "PLAYSTATE_PAUSED";
+                case RemoteControlClient.PLAYSTATE_PLAYING:
+                    return "PLAYSTATE_PLAYING";
+                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+                    return "PLAYSTATE_FAST_FORWARDING";
+                case RemoteControlClient.PLAYSTATE_REWINDING:
+                    return "PLAYSTATE_REWINDING";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                    return "PLAYSTATE_SKIPPING_FORWARDS";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                    return "PLAYSTATE_SKIPPING_BACKWARDS";
+                case RemoteControlClient.PLAYSTATE_BUFFERING:
+                    return "PLAYSTATE_BUFFERING";
+                case RemoteControlClient.PLAYSTATE_ERROR:
+                    return "PLAYSTATE_ERROR";
+                default:
+                    return "[invalid playstate]";
+            }
+        }
+    }
+
+    protected static class RemoteControlStackEntry implements DeathRecipient {
+        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        final public MediaFocusControl mController;
+        /**
+         * The target for the ACTION_MEDIA_BUTTON events.
+         * Always non null.
+         */
+        final public PendingIntent mMediaIntent;
+        /**
+         * The registered media button event receiver.
+         * Always non null.
+         */
+        final public ComponentName mReceiverComponent;
+        public IBinder mToken;
+        public String mCallingPackageName;
+        public int mCallingUid;
+        /**
+         * Provides access to the information to display on the remote control.
+         * May be null (when a media button event receiver is registered,
+         *     but no remote control client has been registered) */
+        public IRemoteControlClient mRcClient;
+        public RcClientDeathHandler mRcClientDeathHandler;
+        /**
+         * Information only used for non-local playback
+         */
+        public int mPlaybackType;
+        public int mPlaybackVolume;
+        public int mPlaybackVolumeMax;
+        public int mPlaybackVolumeHandling;
+        public int mPlaybackStream;
+        public RccPlaybackState mPlaybackState;
+        public IRemoteVolumeObserver mRemoteVolumeObs;
+
+        public void resetPlaybackInfo() {
+            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
+            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+            mPlaybackStream = AudioManager.STREAM_MUSIC;
+            mPlaybackState.reset();
+            mRemoteVolumeObs = null;
+        }
+
+        /** precondition: mediaIntent != null */
+        public RemoteControlStackEntry(MediaFocusControl controller, PendingIntent mediaIntent,
+                ComponentName eventReceiver, IBinder token) {
+            mController = controller;
+            mMediaIntent = mediaIntent;
+            mReceiverComponent = eventReceiver;
+            mToken = token;
+            mCallingUid = -1;
+            mRcClient = null;
+            mRccId = ++sLastRccId;
+            mPlaybackState = new RccPlaybackState(
+                    RemoteControlClient.PLAYSTATE_STOPPED,
+                    RemoteControlClient.PLAYBACK_POSITION_INVALID,
+                    RemoteControlClient.PLAYBACK_SPEED_1X);
+
+            resetPlaybackInfo();
+            if (mToken != null) {
+                try {
+                    mToken.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    mController.mEventHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mController.unregisterMediaButtonIntent(mMediaIntent);
+                        }
+                    });
+                }
+            }
+        }
+
+        public void unlinkToRcClientDeath() {
+            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
+                try {
+                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+                    mRcClientDeathHandler = null;
+                } catch (java.util.NoSuchElementException e) {
+                    // not much we can do here
+                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        public void destroy() {
+            unlinkToRcClientDeath();
+            if (mToken != null) {
+                mToken.unlinkToDeath(this, 0);
+                mToken = null;
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mController.unregisterMediaButtonIntent(mMediaIntent);
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            destroy(); // unlink exception handled inside method
+            super.finalize();
+        }
+    }
+
+    /**
+     *  The stack of remote control event receivers.
+     *  Code sections and methods that modify the remote control event receiver stack are
+     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
+     *  stack, audio focus or RC, can lead to a change in the remote control display
+     */
+    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
+
+    /**
+     * The component the telephony package can register so telephony calls have priority to
+     * handle media button events
+     */
+    private ComponentName mMediaReceiverForCalls = null;
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the remote control focus stack
+     */
+    private void dumpRCStack(PrintWriter pw) {
+        pw.println("\nRemote Control stack entries (last is top of stack):");
+        synchronized(mRCStack) {
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                pw.println("  pi: " + rcse.mMediaIntent +
+                        " -- pack: " + rcse.mCallingPackageName +
+                        "  -- ercvr: " + rcse.mReceiverComponent +
+                        "  -- client: " + rcse.mRcClient +
+                        "  -- uid: " + rcse.mCallingUid +
+                        "  -- type: " + rcse.mPlaybackType +
+                        "  state: " + rcse.mPlaybackState);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the remote control stack, focusing
+     * on RemoteControlClient data
+     */
+    private void dumpRCCStack(PrintWriter pw) {
+        pw.println("\nRemote Control Client stack entries (last is top of stack):");
+        synchronized(mRCStack) {
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                pw.println("  uid: " + rcse.mCallingUid +
+                        "  -- id: " + rcse.mRccId +
+                        "  -- type: " + rcse.mPlaybackType +
+                        "  -- state: " + rcse.mPlaybackState +
+                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
+                        "  -- vol: " + rcse.mPlaybackVolume +
+                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
+                        "  -- volObs: " + rcse.mRemoteVolumeObs);
+            }
+            synchronized(mCurrentRcLock) {
+                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
+            }
+        }
+        synchronized (mMainRemote) {
+            pw.println("\nRemote Volume State:");
+            pw.println("  has remote: " + mHasRemotePlayback);
+            pw.println("  is remote active: " + mMainRemoteIsActive);
+            pw.println("  rccId: " + mMainRemote.mRccId);
+            pw.println("  volume handling: "
+                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
+                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
+            pw.println("  volume: " + mMainRemote.mVolume);
+            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the list of remote control displays
+     */
+    private void dumpRCDList(PrintWriter pw) {
+        pw.println("\nRemote Control Display list entries:");
+        synchronized(mRCStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                pw.println("  IRCD: " + di.mRcDisplay +
+                        "  -- w:" + di.mArtworkExpectedWidth +
+                        "  -- h:" + di.mArtworkExpectedHeight+
+                        "  -- wantsPosSync:" + di.mWantsPositionSync);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Remove any entry in the remote control stack that has the same package name as packageName
+     * Pre-condition: packageName != null
+     */
+    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
+        synchronized(mRCStack) {
+            if (mRCStack.empty()) {
+                return;
+            } else {
+                final PackageManager pm = mContext.getPackageManager();
+                RemoteControlStackEntry oldTop = mRCStack.peek();
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                // iterate over the stack entries
+                // (using an iterator on the stack so we can safely remove an entry after having
+                //  evaluated it, traversal order doesn't matter here)
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+                    if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
+                        // a stack entry is from the package being removed, remove it from the stack
+                        stackIterator.remove();
+                        rcse.destroy();
+                    } else if (rcse.mReceiverComponent != null) {
+                        try {
+                            // Check to see if this receiver still exists.
+                            pm.getReceiverInfo(rcse.mReceiverComponent, 0);
+                        } catch (PackageManager.NameNotFoundException e) {
+                            // Not found -- remove it!
+                            stackIterator.remove();
+                            rcse.destroy();
+                        }
+                    }
+                }
+                if (mRCStack.empty()) {
+                    // no saved media button receiver
+                    mEventHandler.sendMessage(
+                            mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                    null));
+                } else if (oldTop != mRCStack.peek()) {
+                    // the top of the stack has changed, save it in the system settings
+                    // by posting a message to persist it; only do this however if it has
+                    // a concrete component name (is not a transient registration)
+                    RemoteControlStackEntry rcse = mRCStack.peek();
+                    if (rcse.mReceiverComponent != null) {
+                        mEventHandler.sendMessage(
+                                mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                        rcse.mReceiverComponent));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Restore remote control receiver from the system settings.
+     */
+    protected void restoreMediaButtonReceiver() {
+        String receiverName = Settings.System.getStringForUser(mContentResolver,
+                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
+        if ((null != receiverName) && !receiverName.isEmpty()) {
+            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
+            if (eventReceiver == null) {
+                // an invalid name was persisted
+                return;
+            }
+            // construct a PendingIntent targeted to the restored component name
+            // for the media button and register it
+            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+            //     the associated intent will be handled by the component being registered
+            mediaButtonIntent.setComponent(eventReceiver);
+            PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
+            registerMediaButtonIntent(pi, eventReceiver, null);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Set the new remote control receiver at the top of the RC focus stack.
+     * Called synchronized on mAudioFocusLock, then mRCStack
+     * precondition: mediaIntent != null
+     */
+    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
+            IBinder token) {
+        // already at top of stack?
+        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
+            return;
+        }
+        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
+                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+        RemoteControlStackEntry rcse = null;
+        boolean wasInsideStack = false;
+        try {
+            for (int index = mRCStack.size()-1; index >= 0; index--) {
+                rcse = mRCStack.elementAt(index);
+                if(rcse.mMediaIntent.equals(mediaIntent)) {
+                    // ok to remove element while traversing the stack since we're leaving the loop
+                    mRCStack.removeElementAt(index);
+                    wasInsideStack = true;
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // not expected to happen, indicates improper concurrent modification
+            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+        }
+        if (!wasInsideStack) {
+            rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
+        }
+        mRCStack.push(rcse); // rcse is never null
+
+        // post message to persist the default media button receiver
+        if (target != null) {
+            mEventHandler.sendMessage( mEventHandler.obtainMessage(
+                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+        }
+    }
+
+    /**
+     * Helper function:
+     * Remove the remote control receiver from the RC focus stack.
+     * Called synchronized on mAudioFocusLock, then mRCStack
+     * precondition: pi != null
+     */
+    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
+        try {
+            for (int index = mRCStack.size()-1; index >= 0; index--) {
+                final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                if (rcse.mMediaIntent.equals(pi)) {
+                    rcse.destroy();
+                    // ok to remove element while traversing the stack since we're leaving the loop
+                    mRCStack.removeElementAt(index);
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // not expected to happen, indicates improper concurrent modification
+            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     */
+    private boolean isCurrentRcController(PendingIntent pi) {
+        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
+            return true;
+        }
+        return false;
+    }
+
+    private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
+        Settings.System.putStringForUser(mContentResolver,
+                                         Settings.System.MEDIA_BUTTON_RECEIVER,
+                                         receiver == null ? "" : receiver.flattenToString(),
+                                         UserHandle.USER_CURRENT);
+    }
+
+    //==========================================================================================
+    // Remote control display / client
+    //==========================================================================================
+    /**
+     * Update the remote control displays with the new "focused" client generation
+     */
+    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
+            PendingIntent newMediaIntent, boolean clearing) {
+        synchronized(mRCStack) {
+            if (mRcDisplays.size() > 0) {
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = displayIterator.next();
+                    try {
+                        di.mRcDisplay.setCurrentClientId(
+                                newClientGeneration, newMediaIntent, clearing);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
+                        di.release();
+                        displayIterator.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the remote control clients with the new "focused" client generation
+     */
+    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
+        // (using an iterator on the stack so we can safely remove an entry if needed,
+        //  traversal order doesn't matter here as we update all entries)
+        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+        while(stackIterator.hasNext()) {
+            RemoteControlStackEntry se = stackIterator.next();
+            if ((se != null) && (se.mRcClient != null)) {
+                try {
+                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
+                    stackIterator.remove();
+                    se.unlinkToRcClientDeath();
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the displays and clients with the new "focused" client generation and name
+     * @param newClientGeneration the new generation value matching a client update
+     * @param newMediaIntent the media button event receiver associated with the client.
+     *    May be null, which implies there is no registered media button event receiver.
+     * @param clearing true if the new client generation value maps to a remote control update
+     *    where the display should be cleared.
+     */
+    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
+            PendingIntent newMediaIntent, boolean clearing) {
+        // send the new valid client generation ID to all displays
+        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
+        // send the new valid client generation ID to all clients
+        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_CLEAR event
+     */
+    private void onRcDisplayClear() {
+        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
+
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                mCurrentRcClientGen++;
+                // synchronously update the displays and clients with the new client generation
+                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+                        null /*newMediaIntent*/, true /*clearing*/);
+            }
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_UPDATE event
+     */
+    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
+                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
+
+                    mCurrentRcClientGen++;
+                    // synchronously update the displays and clients with
+                    //      the new client generation
+                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+                            rcse.mMediaIntent /*newMediaIntent*/,
+                            false /*clearing*/);
+
+                    // tell the current client that it needs to send info
+                    try {
+                        //TODO change name to informationRequestForAllDisplays()
+                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead: "+e);
+                        mCurrentRcClient = null;
+                    }
+                } else {
+                    // the remote control display owner has changed between the
+                    // the message to update the display was sent, and the time it
+                    // gets to be processed (now)
+                }
+            }
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_INIT_INFO event
+     * Causes the current RemoteControlClient to send its info (metadata, playstate...) to
+     *   a single RemoteControlDisplay, NOT all of them, as with MSG_RCDISPLAY_UPDATE.
+     */
+    private void onRcDisplayInitInfo(IRemoteControlDisplay newRcd, int w, int h) {
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if (mCurrentRcClient != null) {
+                    if (DEBUG_RC) { Log.i(TAG, "Init RCD with current info"); }
+                    try {
+                        // synchronously update the new RCD with the current client generation
+                        // and matching PendingIntent
+                        newRcd.setCurrentClientId(mCurrentRcClientGen, mCurrentRcClientIntent,
+                                false);
+
+                        // tell the current RCC that it needs to send info, but only to the new RCD
+                        try {
+                            mCurrentRcClient.informationRequestForDisplay(newRcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Current valid remote client is dead: ", e);
+                            mCurrentRcClient = null;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in onRcDisplayInitInfo()", e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     */
+    private void clearRemoteControlDisplay_syncAfRcs() {
+        synchronized(mCurrentRcLock) {
+            mCurrentRcClient = null;
+        }
+        // will cause onRcDisplayClear() to be called in AudioService's handler thread
+        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
+    }
+
+    /**
+     * Helper function for code readability: only to be called from
+     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
+     *    this method.
+     * Preconditions:
+     *    - called synchronized mAudioFocusLock then on mRCStack
+     *    - mRCStack.isEmpty() is false
+     */
+    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+        RemoteControlStackEntry rcse = mRCStack.peek();
+        int infoFlagsAboutToBeUsed = infoChangedFlags;
+        // this is where we enforce opt-in for information display on the remote controls
+        //   with the new AudioManager.registerRemoteControlClient() API
+        if (rcse.mRcClient == null) {
+            //Log.w(TAG, "Can't update remote control display with null remote control client");
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+        synchronized(mCurrentRcLock) {
+            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
+                // new RC client, assume every type of information shall be queried
+                infoFlagsAboutToBeUsed = RC_INFO_ALL;
+            }
+            mCurrentRcClient = rcse.mRcClient;
+            mCurrentRcClientIntent = rcse.mMediaIntent;
+        }
+        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
+        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
+                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock, then mRCStack
+     * Check whether the remote control display should be updated, triggers the update if required
+     * @param infoChangedFlags the flags corresponding to the remote control client information
+     *     that has changed, if applicable (checking for the update conditions might trigger a
+     *     clear, rather than an update event).
+     */
+    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+        // determine whether the remote control display should be refreshed
+        // if either stack is empty, there is a mismatch, so clear the RC display
+        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+
+        // determine which entry in the AudioFocus stack to consider, and compare against the
+        // top of the stack for the media button event receivers : simply using the top of the
+        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
+        // notifications playing during music playback.
+        // Crawl the AudioFocus stack from the top until an entry is found with the following
+        // characteristics:
+        // - focus gain on STREAM_MUSIC stream
+        // - non-transient focus gain on a stream other than music
+        FocusRequester af = null;
+        try {
+            for (int index = mFocusStack.size()-1; index >= 0; index--) {
+                FocusRequester fr = mFocusStack.elementAt(index);
+                if ((fr.getStreamType() == AudioManager.STREAM_MUSIC)
+                        || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) {
+                    af = fr;
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
+            af = null;
+        }
+        if (af == null) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+
+        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
+        if (!af.hasSamePackage(mRCStack.peek().mCallingPackageName)) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+        // if the audio focus didn't originate from the same Uid as the one in which the remote
+        //   control information will be retrieved, clear
+        if (!af.hasSameUid(mRCStack.peek().mCallingUid)) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+
+        // refresh conditions were verified: update the remote controls
+        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
+        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
+    }
+
+    /**
+     * Helper function:
+     * Post a message to asynchronously move the media button event receiver associated with the
+     * given remote control client ID to the top of the remote control stack
+     * @param rccId
+     */
+    private void postPromoteRcc(int rccId) {
+        sendMsg(mEventHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE,
+                rccId /*arg1*/, 0, null, 0/*delay*/);
+    }
+
+    private void onPromoteRcc(int rccId) {
+        if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // ignore if given RCC ID is already at top of remote control stack
+                if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) {
+                    return;
+                }
+                int indexToPromote = -1;
+                try {
+                    for (int index = mRCStack.size()-1; index >= 0; index--) {
+                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                        if (rcse.mRccId == rccId) {
+                            indexToPromote = index;
+                            break;
+                        }
+                    }
+                    if (indexToPromote >= 0) {
+                        if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
+                                + " to " + (mRCStack.size()-1)); }
+                        final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote);
+                        mRCStack.push(rcse);
+                        // the RC stack changed, reevaluate the display
+                        checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    // not expected to happen, indicates improper concurrent modification
+                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                }
+            }//synchronized(mRCStack)
+        }//synchronized(mAudioFocusLock)
+    }
+
+    /**
+     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
+     * precondition: mediaIntent != null
+     */
+    protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
+            IBinder token) {
+        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
+
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
+                // new RC client, assume every type of information shall be queried
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
+     * precondition: mediaIntent != null, eventReceiver != null
+     */
+    protected void unregisterMediaButtonIntent(PendingIntent mediaIntent)
+    {
+        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
+
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
+                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
+                if (topOfStackWillChange) {
+                    // current RC client will change, assume every type of info needs to be queried
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }
+        }
+    }
+
+    /**
+     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
+     * precondition: c != null
+     */
+    protected void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
+            return;
+        }
+        synchronized(mRCStack) {
+            mMediaReceiverForCalls = c;
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
+     */
+    protected void unregisterMediaButtonEventReceiverForCalls() {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
+            return;
+        }
+        synchronized(mRCStack) {
+            mMediaReceiverForCalls = null;
+        }
+    }
+
+    /**
+     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
+     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
+     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
+     *     without modifying the RC stack, but while still causing the display to refresh (will
+     *     become blank as a result of this)
+     */
+    protected int registerRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient, String callingPackageName) {
+        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // store the new display information
+                try {
+                    for (int index = mRCStack.size()-1; index >= 0; index--) {
+                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                        if(rcse.mMediaIntent.equals(mediaIntent)) {
+                            // already had a remote control client?
+                            if (rcse.mRcClientDeathHandler != null) {
+                                // stop monitoring the old client's death
+                                rcse.unlinkToRcClientDeath();
+                            }
+                            // save the new remote control client
+                            rcse.mRcClient = rcClient;
+                            rcse.mCallingPackageName = callingPackageName;
+                            rcse.mCallingUid = Binder.getCallingUid();
+                            if (rcClient == null) {
+                                // here rcse.mRcClientDeathHandler is null;
+                                rcse.resetPlaybackInfo();
+                                break;
+                            }
+                            rccId = rcse.mRccId;
+
+                            // there is a new (non-null) client:
+                            // 1/ give the new client the displays (if any)
+                            if (mRcDisplays.size() > 0) {
+                                plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
+                            }
+                            // 2/ monitor the new client's death
+                            IBinder b = rcse.mRcClient.asBinder();
+                            RcClientDeathHandler rcdh =
+                                    new RcClientDeathHandler(b, rcse.mMediaIntent);
+                            try {
+                                b.linkToDeath(rcdh, 0);
+                            } catch (RemoteException e) {
+                                // remote control client is DOA, disqualify it
+                                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
+                                rcse.mRcClient = null;
+                            }
+                            rcse.mRcClientDeathHandler = rcdh;
+                            break;
+                        }
+                    }//for
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    // not expected to happen, indicates improper concurrent modification
+                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                }
+
+                // if the eventReceiver is at the top of the stack
+                // then check for potential refresh of the remote controls
+                if (isCurrentRcController(mediaIntent)) {
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }//synchronized(mRCStack)
+        }//synchronized(mAudioFocusLock)
+        return rccId;
+    }
+
+    /**
+     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
+     * rcClient is guaranteed non-null
+     */
+    protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient) {
+        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                boolean topRccChange = false;
+                try {
+                    for (int index = mRCStack.size()-1; index >= 0; index--) {
+                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                        if ((rcse.mMediaIntent.equals(mediaIntent))
+                                && rcClient.equals(rcse.mRcClient)) {
+                            // we found the IRemoteControlClient to unregister
+                            // stop monitoring its death
+                            rcse.unlinkToRcClientDeath();
+                            // reset the client-related fields
+                            rcse.mRcClient = null;
+                            rcse.mCallingPackageName = null;
+                            topRccChange = (index == mRCStack.size()-1);
+                            // there can only be one matching RCC in the RC stack, we're done
+                            break;
+                        }
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    // not expected to happen, indicates improper concurrent modification
+                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                }
+                if (topRccChange) {
+                    // no more RCC for the RCD, check for potential refresh of the remote controls
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * A class to encapsulate all the information about a remote control display.
+     * After instanciation, init() must always be called before the object is added in the list
+     * of displays.
+     * Before being removed from the list of displays, release() must always be called (otherwise
+     * it will leak death handlers).
+     */
+    private class DisplayInfoForServer implements IBinder.DeathRecipient {
+        /** may never be null */
+        private IRemoteControlDisplay mRcDisplay;
+        private IBinder mRcDisplayBinder;
+        private int mArtworkExpectedWidth = -1;
+        private int mArtworkExpectedHeight = -1;
+        private boolean mWantsPositionSync = false;
+
+        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
+            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
+            mRcDisplay = rcd;
+            mRcDisplayBinder = rcd.asBinder();
+            mArtworkExpectedWidth = w;
+            mArtworkExpectedHeight = h;
+        }
+
+        public boolean init() {
+            try {
+                mRcDisplayBinder.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                // remote control display is DOA, disqualify it
+                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
+                return false;
+            }
+            return true;
+        }
+
+        public void release() {
+            try {
+                mRcDisplayBinder.unlinkToDeath(this, 0);
+            } catch (java.util.NoSuchElementException e) {
+                // not much we can do here, the display should have been unregistered anyway
+                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
+            }
+        }
+
+        public void binderDied() {
+            synchronized(mRCStack) {
+                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
+                // remove the display from the list
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                    if (di.mRcDisplay == mRcDisplay) {
+                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
+                        displayIterator.remove();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * The remote control displays.
+     * Access synchronized on mRCStack
+     */
+    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
+
+    /**
+     * Plug each registered display into the specified client
+     * @param rcc, guaranteed non null
+     */
+    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+            try {
+                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
+                        di.mArtworkExpectedHeight);
+                if (di.mWantsPositionSync) {
+                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
+            }
+        }
+    }
+
+    /**
+     * Is the remote control display interface already registered
+     * @param rcd
+     * @return true if the IRemoteControlDisplay is already in the list of displays
+     */
+    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Register an IRemoteControlDisplay.
+     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
+     * at the top of the stack to update the new display with its information.
+     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay to register. No effect if null.
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    protected void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
+                    return;
+                }
+                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
+                if (!di.init()) {
+                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
+                    return;
+                }
+                // add RCD to list of displays
+                mRcDisplays.add(di);
+
+                // let all the remote control clients know there is a new display (so the remote
+                //   control stack traversal order doesn't matter).
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error connecting RCD to client: ", e);
+                        }
+                    }
+                }
+
+                // we have a new display, of which all the clients are now aware: have it be
+                // initialized wih the current gen ID and the current client info, do not
+                // reset the information for the other (existing) displays
+                sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
+                        w /*arg1*/, h /*arg2*/,
+                        rcd /*obj*/, 0/*delay*/);
+            }
+        }
+    }
+
+    /**
+     * Unregister an IRemoteControlDisplay.
+     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
+     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
+     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
+     */
+    protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
+        synchronized(mRCStack) {
+            if (rcd == null) {
+                return;
+            }
+
+            boolean displayWasPluggedIn = false;
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext() && !displayWasPluggedIn) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    displayWasPluggedIn = true;
+                    di.release();
+                    displayIterator.remove();
+                }
+            }
+
+            if (displayWasPluggedIn) {
+                // disconnect this remote control display from all the clients, so the remote
+                //   control stack traversal order doesn't matter
+                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.unplugRemoteControlDisplay(rcd);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
+                        }
+                    }
+                }
+            } else {
+                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
+            }
+        }
+    }
+
+    /**
+     * Update the size of the artwork used by an IRemoteControlDisplay.
+     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+        synchronized(mRCStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            boolean artworkSizeUpdate = false;
+            while (displayIterator.hasNext() && !artworkSizeUpdate) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
+                        di.mArtworkExpectedWidth = w;
+                        di.mArtworkExpectedHeight = h;
+                        artworkSizeUpdate = true;
+                    }
+                }
+            }
+            if (artworkSizeUpdate) {
+                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
+                // stack traversal order doesn't matter
+                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
+     * playback position to verify that the estimated position has not drifted from the actual
+     * position. By default the check is not performed.
+     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
+     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
+     *     or disabled. Not null.
+     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
+     *     to the framework will regularly compare the estimated playback position with the actual
+     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
+     *     detected.
+     */
+    protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
+            boolean wantsSync) {
+        synchronized(mRCStack) {
+            boolean rcdRegistered = false;
+            // store the information about this display
+            // (display stack traversal order doesn't matter).
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    di.mWantsPositionSync = wantsSync;
+                    rcdRegistered = true;
+                    break;
+                }
+            }
+            if (!rcdRegistered) {
+                return;
+            }
+            // notify all current RemoteControlClients
+            // (stack traversal order doesn't matter as we notify all RCCs)
+            final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while (stackIterator.hasNext()) {
+                final RemoteControlStackEntry rcse = stackIterator.next();
+                if (rcse.mRcClient != null) {
+                    try {
+                        rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        // ignore position change requests if invalid generation ID
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if (mCurrentRcClientGen != generationId) {
+                    return;
+                }
+            }
+        }
+        // discard any unprocessed seek request in the message queue, and replace with latest
+        sendMsg(mEventHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
+                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
+    }
+
+    private void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
+                ", timeMs=" + timeMs + ")");
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
+                    // tell the current client to seek to the requested location
+                    try {
+                        mCurrentRcClient.seekTo(generationId, timeMs);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead: "+e);
+                        mCurrentRcClient = null;
+                    }
+                }
+            }
+        }
+    }
+
+    protected void updateRemoteControlClientMetadata(int genId, int key, Rating value) {
+        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA, SENDMSG_QUEUE,
+                genId /* arg1 */, key /* arg2 */, value /* obj */, 0 /* delay */);
+    }
+
+    private void onUpdateRemoteControlClientMetadata(int genId, int key, Rating value) {
+        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadata(genId=" + genId +
+                ", what=" + key + ",rating=" + value + ")");
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
+                    try {
+                        switch (key) {
+                            case MediaMetadataEditor.RATING_KEY_BY_USER:
+                                mCurrentRcClient.updateMetadata(genId, key, value);
+                                break;
+                            default:
+                                Log.e(TAG, "unhandled metadata key " + key + " update for RCC "
+                                        + genId);
+                                break;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead", e);
+                        mCurrentRcClient = null;
+                    }
+                }
+            }
+        }
+    }
+
+    protected void setPlaybackInfoForRcc(int rccId, int what, int value) {
+        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
+                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
+    }
+
+    // handler for MSG_RCC_NEW_PLAYBACK_INFO
+    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
+        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
+                ", what=" + key + ",val=" + value + ")");
+        synchronized(mRCStack) {
+            // iterating from top of stack as playback information changes are more likely
+            //   on entries at the top of the remote control stack
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        switch (key) {
+                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
+                                rcse.mPlaybackType = value;
+                                postReevaluateRemote();
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
+                                rcse.mPlaybackVolume = value;
+                                synchronized (mMainRemote) {
+                                    if (rccId == mMainRemote.mRccId) {
+                                        mMainRemote.mVolume = value;
+                                        mVolumeController.postHasNewRemotePlaybackInfo();
+                                    }
+                                }
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
+                                rcse.mPlaybackVolumeMax = value;
+                                synchronized (mMainRemote) {
+                                    if (rccId == mMainRemote.mRccId) {
+                                        mMainRemote.mVolumeMax = value;
+                                        mVolumeController.postHasNewRemotePlaybackInfo();
+                                    }
+                                }
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
+                                rcse.mPlaybackVolumeHandling = value;
+                                synchronized (mMainRemote) {
+                                    if (rccId == mMainRemote.mRccId) {
+                                        mMainRemote.mVolumeHandling = value;
+                                        mVolumeController.postHasNewRemotePlaybackInfo();
+                                    }
+                                }
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
+                                rcse.mPlaybackStream = value;
+                                break;
+                            default:
+                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
+                                break;
+                        }
+                        return;
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
+            }
+        }
+    }
+
+    protected void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
+        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
+                rccId /* arg1 */, state /* arg2 */,
+                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
+    }
+
+    private void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
+        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
+                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
+        synchronized(mRCStack) {
+            // iterating from top of stack as playback information changes are more likely
+            //   on entries at the top of the remote control stack
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mPlaybackState = newState;
+                        synchronized (mMainRemote) {
+                            if (rccId == mMainRemote.mRccId) {
+                                mMainRemoteIsActive = isPlaystateActive(state);
+                                postReevaluateRemote();
+                            }
+                        }
+                        // an RCC moving to a "playing" state should become the media button
+                        //   event receiver so it can be controlled, without requiring the
+                        //   app to re-register its receiver
+                        if (isPlaystateActive(state)) {
+                            postPromoteRcc(rccId);
+                        }
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
+            }
+        }
+    }
+
+    protected void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
+        sendMsg(mEventHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
+                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
+    }
+
+    // handler for MSG_RCC_NEW_VOLUME_OBS
+    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
+        synchronized(mRCStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mRemoteVolumeObs = rvo;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+    }
+
+    /**
+     * Checks if a remote client is active on the supplied stream type. Update the remote stream
+     * volume state if found and playing
+     * @param streamType
+     * @return false if no remote playing is currently playing
+     */
+    protected boolean checkUpdateRemoteStateIfActive(int streamType) {
+        synchronized(mRCStack) {
+            // iterating from top of stack as active playback is more likely on entries at the top
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
+                            && isPlaystateActive(rcse.mPlaybackState.mState)
+                            && (rcse.mPlaybackStream == streamType)) {
+                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
+                                + ", vol =" + rcse.mPlaybackVolume);
+                        synchronized (mMainRemote) {
+                            mMainRemote.mRccId = rcse.mRccId;
+                            mMainRemote.mVolume = rcse.mPlaybackVolume;
+                            mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
+                            mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
+                            mMainRemoteIsActive = true;
+                        }
+                        return true;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+        }
+        synchronized (mMainRemote) {
+            mMainRemoteIsActive = false;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the given playback state is considered "active", i.e. it describes a state
+     * where playback is happening, or about to
+     * @param playState the playback state to evaluate
+     * @return true if active, false otherwise (inactive or unknown)
+     */
+    private static boolean isPlaystateActive(int playState) {
+        switch (playState) {
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    protected void adjustRemoteVolume(int streamType, int direction, int flags) {
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        boolean volFixed = false;
+        synchronized (mMainRemote) {
+            if (!mMainRemoteIsActive) {
+                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
+                return;
+            }
+            rccId = mMainRemote.mRccId;
+            volFixed = (mMainRemote.mVolumeHandling ==
+                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
+        }
+        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
+        // we can only notify the remote that volume needs to be updated, and we'll get an async'
+        // update through setPlaybackInfoForRcc()
+        if (!volFixed) {
+            sendVolumeUpdateToRemote(rccId, direction);
+        }
+
+        // fire up the UI
+        mVolumeController.postRemoteVolumeChanged(streamType, flags);
+    }
+
+    private void sendVolumeUpdateToRemote(int rccId, int direction) {
+        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
+        if (direction == 0) {
+            // only handling discrete events
+            return;
+        }
+        IRemoteVolumeObserver rvo = null;
+        synchronized (mRCStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (rcse.mRccId == rccId) {
+                        rvo = rcse.mRemoteVolumeObs;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(direction, -1);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching relative volume update", e);
+            }
+        }
+    }
+
+    protected int getRemoteStreamMaxVolume() {
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return 0;
+            }
+            return mMainRemote.mVolumeMax;
+        }
+    }
+
+    protected int getRemoteStreamVolume() {
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return 0;
+            }
+            return mMainRemote.mVolume;
+        }
+    }
+
+    protected void setRemoteStreamVolume(int vol) {
+        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return;
+            }
+            rccId = mMainRemote.mRccId;
+        }
+        IRemoteVolumeObserver rvo = null;
+        synchronized (mRCStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (rcse.mRccId == rccId) {
+                        rvo = rcse.mRemoteVolumeObs;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(0, vol);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching absolute volume update", e);
+            }
+        }
+    }
+
+    /**
+     * Call to make AudioService reevaluate whether it's in a mode where remote players should
+     * have their volume controlled. In this implementation this is only to reset whether
+     * VolumePanel should display remote volumes
+     */
+    private void postReevaluateRemote() {
+        sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    private void onReevaluateRemote() {
+        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
+        // is there a registered RemoteControlClient that is handling remote playback
+        boolean hasRemotePlayback = false;
+        synchronized (mRCStack) {
+            // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack
+            //   traversal order doesn't matter
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
+                    hasRemotePlayback = true;
+                    break;
+                }
+            }
+        }
+        synchronized (mMainRemote) {
+            if (mHasRemotePlayback != hasRemotePlayback) {
+                mHasRemotePlayback = hasRemotePlayback;
+                mVolumeController.postRemoteSliderVisibility(hasRemotePlayback);
+            }
+        }
+    }
+
+}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 3fbaf69..0f7906e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -26,7 +26,7 @@
  *
  * The format of the media data is specified as string/value pairs.
  *
- * Keys common to all formats, <b>all keys not marked optional are mandatory</b>:
+ * Keys common to all audio/video formats, <b>all keys not marked optional are mandatory</b>:
  *
  * <table>
  * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
@@ -44,7 +44,19 @@
  *         for encoders, readable in the output format of decoders</b></td></tr>
  * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
  * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
+ * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
+ * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
+ * <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>video decoder rendering to a surface only</b></td></tr>
  * </table>
+ * Specify both {@link #KEY_MAX_WIDTH} and {@link #KEY_MAX_HEIGHT} to enable
+ * adaptive playback (seamless resolution change) for a video decoder that
+ * supports it ({@link MediaCodecInfo.CodecCapabilities#FEATURE_AdaptivePlayback}).
+ * The values are used as hints for the codec: they are the maximum expected
+ * resolution to prepare for.  Depending on codec support, preparing for larger
+ * maximum resolution may require more memory even if that resolution is never
+ * reached.  These fields have no effect for codecs that do not support adaptive
+ * playback.<br /><br />
  *
  * Audio formats have the following keys:
  * <table>
@@ -57,6 +69,11 @@
  * <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
  * </table>
  *
+ * Subtitle formats have the following keys:
+ * <table>
+ * <tr><td>{@link #KEY_MIME}</td><td>String</td><td>The type of the format.</td></tr>
+ * <tr><td>{@link #KEY_LANGUAGE}</td><td>String</td><td>The language of the content.</td></tr>
+ * </table>
  */
 public final class MediaFormat {
     private Map<String, Object> mMap;
@@ -68,6 +85,12 @@
     public static final String KEY_MIME = "mime";
 
     /**
+     * A key describing the language of the content, using either ISO 639-1
+     * or 639-2/T codes.  The associated value is a string.
+     */
+    public static final String KEY_LANGUAGE = "language";
+
+    /**
      * A key describing the sample rate of an audio format.
      * The associated value is an integer
      */
@@ -91,6 +114,20 @@
      */
     public static final String KEY_HEIGHT = "height";
 
+    /**
+     * A key describing the maximum expected width of the content in a video
+     * decoder format, in case there are resolution changes in the video content.
+     * The associated value is an integer
+     */
+    public static final String KEY_MAX_WIDTH = "max-width";
+
+    /**
+     * A key describing the maximum expected height of the content in a video
+     * decoder format, in case there are resolution changes in the video content.
+     * The associated value is an integer
+     */
+    public static final String KEY_MAX_HEIGHT = "max-height";
+
     /** A key describing the maximum size in bytes of a buffer of data
      * described by this MediaFormat.
      * The associated value is an integer
@@ -132,6 +169,24 @@
     public static final String KEY_SLICE_HEIGHT = "slice-height";
 
     /**
+     * Applies only when configuring a video encoder in "surface-input" mode.
+     * The associated value is a long and gives the time in microseconds
+     * after which the frame previously submitted to the encoder will be
+     * repeated (once) if no new frame became available since.
+     */
+    public static final String KEY_REPEAT_PREVIOUS_FRAME_AFTER
+        = "repeat-previous-frame-after";
+
+    /**
+     * If specified when configuring a video decoder rendering to a surface,
+     * causes the decoder to output "blank", i.e. black frames to the surface
+     * when stopped to clear out any previously displayed contents.
+     * The associated value is an integer of value 1.
+     */
+    public static final String KEY_PUSH_BLANK_BUFFERS_ON_STOP
+        = "push-blank-buffers-on-shutdown";
+
+    /**
      * A key describing the duration (in microseconds) of the content.
      * The associated value is a long.
      */
@@ -166,6 +221,38 @@
      */
     public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 
+    /**
+     * A key for boolean AUTOSELECT behavior for the track. Tracks with AUTOSELECT=true
+     * are considered when automatically selecting a track without specific user
+     * choice, based on the current locale.
+     * This is currently only used for subtitle tracks, when the user selected
+     * 'Default' for the captioning locale.
+     * The associated value is an integer, where non-0 means TRUE.  This is an optional
+     * field; if not specified, AUTOSELECT defaults to TRUE.
+     */
+    public static final String KEY_IS_AUTOSELECT = "is-autoselect";
+
+    /**
+     * A key for boolean DEFAULT behavior for the track. The track with DEFAULT=true is
+     * selected in the absence of a specific user choice.
+     * This is currently only used for subtitle tracks, when the user selected
+     * 'Default' for the captioning locale.
+     * The associated value is an integer, where non-0 means TRUE.  This is an optional
+     * field; if not specified, DEFAULT is considered to be FALSE.
+     */
+    public static final String KEY_IS_DEFAULT = "is-default";
+
+
+    /**
+     * A key for the FORCED field for subtitle tracks. True if it is a
+     * forced subtitle track.  Forced subtitle tracks are essential for the
+     * content and are shown even when the user turns off Captions.  They
+     * are used for example to translate foreign/alien dialogs or signs.
+     * The associated value is an integer, where non-0 means TRUE.  This is an
+     * optional field; if not specified, FORCED defaults to FALSE.
+     */
+    public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
+
     /* package private */ MediaFormat(Map<String, Object> map) {
         mMap = map;
     }
@@ -196,6 +283,20 @@
     }
 
     /**
+     * Returns the value of an integer key, or the default value if the
+     * key is missing or is for another type value.
+     * @hide
+     */
+    public final int getInteger(String name, int defaultValue) {
+        try {
+            return getInteger(name);
+        }
+        catch (NullPointerException  e) { /* no such field */ }
+        catch (ClassCastException e) { /* field of different type */ }
+        return defaultValue;
+    }
+
+    /**
      * Returns the value of a long key.
      */
     public final long getLong(String name) {
@@ -277,6 +378,24 @@
     }
 
     /**
+     * Creates a minimal subtitle format.
+     * @param mime The mime type of the content.
+     * @param language The language of the content, using either ISO 639-1 or 639-2/T
+     *        codes.  Specify null or "und" if language information is only included
+     *        in the content.  (This will also work if there are multiple language
+     *        tracks in the content.)
+     */
+    public static final MediaFormat createSubtitleFormat(
+            String mime,
+            String language) {
+        MediaFormat format = new MediaFormat();
+        format.setString(KEY_MIME, mime);
+        format.setString(KEY_LANGUAGE, language);
+
+        return format;
+    }
+
+    /**
      * Creates a minimal video format.
      * @param mime The mime type of the content.
      * @param width The width of the content (in pixels)
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
new file mode 100644
index 0000000..373ba11
--- /dev/null
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -0,0 +1,462 @@
+/*
+ * 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 android.media;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+/**
+ * An abstract class for editing and storing metadata that can be published by
+ * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)}
+ * method to instantiate a {@link RemoteControlClient.MetadataEditor} object.
+ */
+public abstract class MediaMetadataEditor {
+
+    private final static String TAG = "MediaMetadataEditor";
+    /**
+     * @hide
+     */
+    protected MediaMetadataEditor() {
+    }
+
+    // Public keys for metadata used by RemoteControlClient and RemoteController.
+    // Note that these keys are defined here, and not in MediaMetadataRetriever
+    // because they are not supported by the MediaMetadataRetriever features.
+    /**
+     * The metadata key for the content artwork / album art.
+     */
+    public final static int BITMAP_KEY_ARTWORK =
+            RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK;
+
+    /**
+     * The metadata key for the content's average rating, not the user's rating.
+     * The value associated with this key is a {@link Rating} instance.
+     * @see #RATING_KEY_BY_USER
+     */
+    public final static int RATING_KEY_BY_OTHERS = 101;
+
+    /**
+     * The metadata key for the content's user rating.
+     * The value associated with this key is a {@link Rating} instance.
+     * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
+     * receiving user rating values through the
+     * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
+     */
+    public final static int RATING_KEY_BY_USER = 0x10000001;
+
+    /**
+     * @hide
+     * Editable key mask
+     */
+    public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
+
+
+    /**
+     * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance
+     * was created or since {@link #clear()} was called.
+     */
+    public abstract void apply();
+
+
+    /**
+     * @hide
+     * Mask of editable keys.
+     */
+    protected long mEditableKeys;
+
+    /**
+     * @hide
+     */
+    protected boolean mMetadataChanged = false;
+
+    /**
+     * @hide
+     */
+    protected boolean mApplied = false;
+
+    /**
+     * @hide
+     */
+    protected boolean mArtworkChanged = false;
+
+    /**
+     * @hide
+     */
+    protected Bitmap mEditorArtwork;
+
+    /**
+     * @hide
+     */
+    protected Bundle mEditorMetadata;
+
+
+    /**
+     * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
+     * created or since this method was last called.
+     * Note that clearing the metadata doesn't reset the editable keys
+     * (use {@link #removeEditableKeys()} instead).
+     */
+    public synchronized void clear() {
+        if (mApplied) {
+            Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor");
+            return;
+        }
+        mEditorMetadata.clear();
+        mEditorArtwork = null;
+    }
+
+    /**
+     * Flags the given key as being editable.
+     * This should only be used by metadata publishers, such as {@link RemoteControlClient},
+     * which will declare the metadata field as eligible to be updated, with new values
+     * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
+     * @param key the type of metadata that can be edited. The supported key is
+     *     {@link #RATING_KEY_BY_USER}.
+     */
+    public synchronized void addEditableKey(int key) {
+        if (mApplied) {
+            Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
+            return;
+        }
+        // only one editable key at the moment, so we're not wasting memory on an array
+        // of editable keys to check the validity of the key, just hardcode the supported key.
+        if (key == RATING_KEY_BY_USER) {
+            mEditableKeys |= (KEY_EDITABLE_MASK & key);
+            mMetadataChanged = true;
+        } else {
+            Log.e(TAG, "Metadata key " + key + " cannot be edited");
+        }
+    }
+
+    /**
+     * Causes all metadata fields to be read-only.
+     */
+    public synchronized void removeEditableKeys() {
+        if (mApplied) {
+            Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor");
+            return;
+        }
+        if (mEditableKeys != 0) {
+            mEditableKeys = 0;
+            mMetadataChanged = true;
+        }
+    }
+
+    /**
+     * Retrieves the keys flagged as editable.
+     * @return null if there are no editable keys, or an array containing the keys.
+     */
+    public synchronized int[] getEditableKeys() {
+        // only one editable key supported here
+        if (mEditableKeys == RATING_KEY_BY_USER) {
+            int[] keys = { RATING_KEY_BY_USER };
+            return keys;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Adds textual information.
+     * Note that none of the information added after {@link #apply()} has been called,
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key The identifier of a the metadata field to set. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+     * @param value The text for the given key, or {@code null} to signify there is no valid
+     *      information for the field.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     */
+    public synchronized MediaMetadataEditor putString(int key, String value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+            throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+        }
+        mEditorMetadata.putString(String.valueOf(key), value);
+        mMetadataChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds numerical information.
+     * Note that none of the information added after {@link #apply()} has been called
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key the identifier of a the metadata field to set. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+     *      expressed in milliseconds),
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+     * @param value The long value for the given key
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     */
+    public synchronized MediaMetadataEditor putLong(int key, long value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+            throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+        }
+        mEditorMetadata.putLong(String.valueOf(key), value);
+        mMetadataChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds image.
+     * @param key the identifier of the bitmap to set. The only valid value is
+     *      {@link #BITMAP_KEY_ARTWORK}
+     * @param bitmap The bitmap for the artwork, or null if there isn't any.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     * @see android.graphics.Bitmap
+     */
+    public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (key != BITMAP_KEY_ARTWORK) {
+            throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+        }
+        mEditorArtwork = bitmap;
+        mArtworkChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds information stored as an instance.
+     * Note that none of the information added after {@link #apply()} has been called
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key the identifier of a the metadata field to set. Valid keys for a:
+     *     <ul>
+     *     <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
+     *     <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
+     *     <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
+     *     <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
+     *         and {@link #RATING_KEY_BY_USER}.</li>
+     *     </ul>
+     * @param value the metadata to add.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     */
+    public synchronized MediaMetadataEditor putObject(int key, Object value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+            case METADATA_TYPE_LONG:
+                if (value instanceof Long) {
+                    return putLong(key, ((Long)value).longValue());
+                } else {
+                    throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
+                }
+            case METADATA_TYPE_STRING:
+                if ((value == null) || (value instanceof String)) {
+                    return putString(key, (String) value);
+                } else {
+                    throw(new IllegalArgumentException("Not a String for key "+ key));
+                }
+            case METADATA_TYPE_RATING:
+                mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
+                mMetadataChanged = true;
+                break;
+            case METADATA_TYPE_BITMAP:
+                if ((value == null) || (value instanceof Bitmap))  {
+                    return putBitmap(key, (Bitmap) value);
+                } else {
+                    throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
+                }
+            default:
+                throw(new IllegalArgumentException("Invalid key "+ key));
+        }
+        return this;
+    }
+
+
+    /**
+     * Returns the long value for the key.
+     * @param key one of the keys supported in {@link #putLong(int, long)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the long value for the key, or the supplied default value if the key is not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized long getLong(int key, long defaultValue)
+            throws IllegalArgumentException {
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+            throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+        }
+        return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
+    }
+
+    /**
+     * Returns the {@link String} value for the key.
+     * @param key one of the keys supported in {@link #putString(int, String)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the {@link String} value for the key, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized String getString(int key, String defaultValue)
+            throws IllegalArgumentException {
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+            throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+        }
+        return mEditorMetadata.getString(String.valueOf(key), defaultValue);
+    }
+
+    /**
+     * Returns the {@link Bitmap} value for the key.
+     * @param key the {@link #BITMAP_KEY_ARTWORK} key
+     * @param defaultValue the value returned if the key is not present
+     * @return the {@link Bitmap} value for the key, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
+            throws IllegalArgumentException {
+        if (key != BITMAP_KEY_ARTWORK) {
+            throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+        }
+        return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+    }
+
+    /**
+     * Returns an object representation of the value for the key
+     * @param key one of the keys supported in {@link #putObject(int, Object)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
+     *     {@link Rating} depending on the key value, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized Object getObject(int key, Object defaultValue)
+            throws IllegalArgumentException {
+        switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+            case METADATA_TYPE_LONG:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getLong(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_STRING:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getString(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_RATING:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getParcelable(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_BITMAP:
+                // only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
+                if (key == BITMAP_KEY_ARTWORK) {
+                    return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+                } // else: fall through to invalid key handling
+            default:
+                throw(new IllegalArgumentException("Invalid key "+ key));
+        }
+    }
+
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_INVALID = -1;
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_LONG = 0;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_STRING = 1;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_BITMAP = 2;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_RATING = 3;
+
+    /**
+     * @hide
+     */
+    protected static final SparseIntArray METADATA_KEYS_TYPE;
+
+    static {
+        METADATA_KEYS_TYPE = new SparseIntArray(17);
+        // NOTE: if adding to the list below, make sure you increment the array initialization size
+        // keys with long values
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+        // keys with String values
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
+        // keys with Bitmap values
+        METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
+        // keys with Rating values
+        METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+    }
+}
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 774964e..65a9308 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -92,6 +92,7 @@
             Object[] values);
     private static native void nativeSetOrientationHint(int nativeObject,
             int degrees);
+    private static native void nativeSetLocation(int nativeObject, int latitude, int longitude);
     private static native void nativeWriteSampleData(int nativeObject,
             int trackIndex, ByteBuffer byteBuf,
             int offset, int size, long presentationTimeUs, int flags);
@@ -165,6 +166,41 @@
     }
 
     /**
+     * Set and store the geodata (latitude and longitude) in the output file.
+     * This method should be called before {@link #start}. The geodata is stored
+     * in udta box if the output format is
+     * {@link OutputFormat#MUXER_OUTPUT_MPEG_4}, and is ignored for other output
+     * formats. The geodata is stored according to ISO-6709 standard.
+     *
+     * @param latitude Latitude in degrees. Its value must be in the range [-90,
+     * 90].
+     * @param longitude Longitude in degrees. Its value must be in the range
+     * [-180, 180].
+     * @throws IllegalArgumentException If the given latitude or longitude is out
+     * of range.
+     * @throws IllegalStateException If this method is called after {@link #start}.
+     */
+    public void setLocation(float latitude, float longitude) {
+        int latitudex10000  = (int) (latitude * 10000 + 0.5);
+        int longitudex10000 = (int) (longitude * 10000 + 0.5);
+
+        if (latitudex10000 > 900000 || latitudex10000 < -900000) {
+            String msg = "Latitude: " + latitude + " out of range.";
+            throw new IllegalArgumentException(msg);
+        }
+        if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
+            String msg = "Longitude: " + longitude + " out of range";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (mState == MUXER_STATE_INITIALIZED && mNativeObject != 0) {
+            nativeSetLocation(mNativeObject, latitudex10000, longitudex10000);
+        } else {
+            throw new IllegalStateException("Can't set location due to wrong state.");
+        }
+    }
+
+    /**
      * Starts the muxer.
      * <p>Make sure this is called after {@link #addTrack} and before
      * {@link #writeSampleData}.</p>
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b729640..0abd5f8 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -26,11 +26,13 @@
 import android.net.ProxyProperties;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.PowerManager;
 import android.util.Log;
 import android.view.Surface;
@@ -38,14 +40,23 @@
 import android.graphics.Bitmap;
 import android.graphics.SurfaceTexture;
 import android.media.AudioManager;
+import android.media.MediaFormat;
+import android.media.MediaTimeProvider;
+import android.media.MediaTimeProvider.OnMediaTimeListener;
+import android.media.SubtitleController;
+import android.media.SubtitleData;
 
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Runnable;
 import java.net.InetSocketAddress;
 import java.util.Map;
+import java.util.Scanner;
 import java.util.Set;
+import java.util.Vector;
 import java.lang.ref.WeakReference;
 
 /**
@@ -515,7 +526,7 @@
  * thread by default has a Looper running).
  *
  */
-public class MediaPlayer
+public class MediaPlayer implements SubtitleController.Listener
 {
     /**
        Constant to retrieve only the new metadata since the last
@@ -588,6 +599,11 @@
             mEventHandler = null;
         }
 
+        mTimeProvider = new TimeProvider(this);
+        mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>();
+        mOpenSubtitleSources = new Vector<InputStream>();
+        mInbandSubtitleTracks = new SubtitleTrack[0];
+
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
          */
@@ -639,7 +655,6 @@
      *
      * @param reply Output parcel with the data returned by the
      * native player.
-     *
      * {@hide}
      */
     public void invoke(Parcel request, Parcel reply) {
@@ -1336,6 +1351,11 @@
         mOnInfoListener = null;
         mOnVideoSizeChangedListener = null;
         mOnTimedTextListener = null;
+        if (mTimeProvider != null) {
+            mTimeProvider.close();
+            mTimeProvider = null;
+        }
+        mOnSubtitleDataListener = null;
         _release();
     }
 
@@ -1347,10 +1367,32 @@
      * data source and calling prepare().
      */
     public void reset() {
+        mSelectedSubtitleTrackIndex = -1;
+        synchronized(mOpenSubtitleSources) {
+            for (final InputStream is: mOpenSubtitleSources) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+            mOpenSubtitleSources.clear();
+        }
+        mOutOfBandSubtitleTracks.clear();
+        mInbandSubtitleTracks = new SubtitleTrack[0];
+        if (mSubtitleController != null) {
+            mSubtitleController.reset();
+        }
+        if (mTimeProvider != null) {
+            mTimeProvider.close();
+            mTimeProvider = null;
+        }
+
         stayAwake(false);
         _reset();
         // make sure none of the listeners get called anymore
-        mEventHandler.removeCallbacksAndMessages(null);
+        if (mEventHandler != null) {
+            mEventHandler.removeCallbacksAndMessages(null);
+        }
 
         disableProxyListener();
     }
@@ -1410,13 +1452,6 @@
     }
 
     /**
-     * Currently not implemented, returns null.
-     * @deprecated
-     * @hide
-     */
-    public native Bitmap getFrameAt(int msec) throws IllegalStateException;
-
-    /**
      * Sets the audio session ID.
      *
      * @param sessionId the audio session ID.
@@ -1458,100 +1493,6 @@
      */
     public native void attachAuxEffect(int effectId);
 
-    /* Do not change these values (starting with KEY_PARAMETER) without updating
-     * their counterparts in include/media/mediaplayer.h!
-     */
-
-    // There are currently no defined keys usable from Java with get*Parameter.
-    // But if any keys are defined, the order must be kept in sync with include/media/mediaplayer.h.
-    // private static final int KEY_PARAMETER_... = ...;
-
-    /**
-     * Sets the parameter indicated by key.
-     * @param key key indicates the parameter to be set.
-     * @param value value of the parameter to be set.
-     * @return true if the parameter is set successfully, false otherwise
-     * {@hide}
-     */
-    public native boolean setParameter(int key, Parcel value);
-
-    /**
-     * Sets the parameter indicated by key.
-     * @param key key indicates the parameter to be set.
-     * @param value value of the parameter to be set.
-     * @return true if the parameter is set successfully, false otherwise
-     * {@hide}
-     */
-    public boolean setParameter(int key, String value) {
-        Parcel p = Parcel.obtain();
-        p.writeString(value);
-        boolean ret = setParameter(key, p);
-        p.recycle();
-        return ret;
-    }
-
-    /**
-     * Sets the parameter indicated by key.
-     * @param key key indicates the parameter to be set.
-     * @param value value of the parameter to be set.
-     * @return true if the parameter is set successfully, false otherwise
-     * {@hide}
-     */
-    public boolean setParameter(int key, int value) {
-        Parcel p = Parcel.obtain();
-        p.writeInt(value);
-        boolean ret = setParameter(key, p);
-        p.recycle();
-        return ret;
-    }
-
-    /*
-     * Gets the value of the parameter indicated by key.
-     * @param key key indicates the parameter to get.
-     * @param reply value of the parameter to get.
-     */
-    private native void getParameter(int key, Parcel reply);
-
-    /**
-     * Gets the value of the parameter indicated by key.
-     * The caller is responsible for recycling the returned parcel.
-     * @param key key indicates the parameter to get.
-     * @return value of the parameter.
-     * {@hide}
-     */
-    public Parcel getParcelParameter(int key) {
-        Parcel p = Parcel.obtain();
-        getParameter(key, p);
-        return p;
-    }
-
-    /**
-     * Gets the value of the parameter indicated by key.
-     * @param key key indicates the parameter to get.
-     * @return value of the parameter.
-     * {@hide}
-     */
-    public String getStringParameter(int key) {
-        Parcel p = Parcel.obtain();
-        getParameter(key, p);
-        String ret = p.readString();
-        p.recycle();
-        return ret;
-    }
-
-    /**
-     * Gets the value of the parameter indicated by key.
-     * @param key key indicates the parameter to get.
-     * @return value of the parameter.
-     * {@hide}
-     */
-    public int getIntParameter(int key) {
-        Parcel p = Parcel.obtain();
-        getParameter(key, p);
-        int ret = p.readInt();
-        p.recycle();
-        return ret;
-    }
 
     /**
      * Sets the send level of the player to the attached auxiliary effect
@@ -1628,20 +1569,56 @@
          * ISO-639-2 language code, "und", is returned.
          */
         public String getLanguage() {
-            return mLanguage;
+            String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
+            return language == null ? "und" : language;
+        }
+
+        /**
+         * Gets the {@link MediaFormat} of the track.  If the format is
+         * unknown or could not be determined, null is returned.
+         */
+        public MediaFormat getFormat() {
+            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
+                    || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+                return mFormat;
+            }
+            return null;
         }
 
         public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0;
         public static final int MEDIA_TRACK_TYPE_VIDEO = 1;
         public static final int MEDIA_TRACK_TYPE_AUDIO = 2;
         public static final int MEDIA_TRACK_TYPE_TIMEDTEXT = 3;
+        /** @hide */
+        public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4;
 
         final int mTrackType;
-        final String mLanguage;
+        final MediaFormat mFormat;
 
         TrackInfo(Parcel in) {
             mTrackType = in.readInt();
-            mLanguage = in.readString();
+            // TODO: parcel in the full MediaFormat
+            String language = in.readString();
+
+            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
+                mFormat = MediaFormat.createSubtitleFormat(
+                    MEDIA_MIMETYPE_TEXT_SUBRIP, language);
+            } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+                mFormat = MediaFormat.createSubtitleFormat(
+                    MEDIA_MIMETYPE_TEXT_VTT, 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());
+            } else {
+                mFormat = new MediaFormat();
+                mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
+            }
+        }
+
+        /** @hide */
+        TrackInfo(int type, MediaFormat format) {
+            mTrackType = type;
+            mFormat = format;
         }
 
         /**
@@ -1658,7 +1635,13 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mTrackType);
-            dest.writeString(mLanguage);
+            dest.writeString(getLanguage());
+
+            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+                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));
+            }
         }
 
         /**
@@ -1688,6 +1671,19 @@
      * @throws IllegalStateException if it is called in an invalid state.
      */
     public TrackInfo[] getTrackInfo() throws IllegalStateException {
+        TrackInfo trackInfo[] = getInbandTrackInfo();
+        // add out-of-band tracks
+        TrackInfo allTrackInfo[] = new TrackInfo[trackInfo.length + mOutOfBandSubtitleTracks.size()];
+        System.arraycopy(trackInfo, 0, allTrackInfo, 0, trackInfo.length);
+        int i = trackInfo.length;
+        for (SubtitleTrack track: mOutOfBandSubtitleTracks) {
+            allTrackInfo[i] = new TrackInfo(TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE, track.getFormat());
+            ++i;
+        }
+        return allTrackInfo;
+    }
+
+    private TrackInfo[] getInbandTrackInfo() throws IllegalStateException {
         Parcel request = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
@@ -1710,6 +1706,12 @@
      */
     public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
 
+    /**
+     * MIME type for WebVTT subtitle data.
+     * @hide
+     */
+    public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
+
     /*
      * A helper function to check if the mime type is supported by media framework.
      */
@@ -1720,6 +1722,149 @@
         return false;
     }
 
+    private SubtitleController mSubtitleController;
+
+    /** @hide */
+    public void setSubtitleAnchor(
+            SubtitleController controller,
+            SubtitleController.Anchor anchor) {
+        // TODO: create SubtitleController in MediaPlayer
+        mSubtitleController = controller;
+        mSubtitleController.setAnchor(anchor);
+    }
+
+    private SubtitleTrack[] mInbandSubtitleTracks;
+    private int mSelectedSubtitleTrackIndex = -1;
+    private Vector<SubtitleTrack> mOutOfBandSubtitleTracks;
+    private Vector<InputStream> mOpenSubtitleSources;
+
+    private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() {
+        @Override
+        public void onSubtitleData(MediaPlayer mp, SubtitleData data) {
+            int index = data.getTrackIndex();
+            if (index >= mInbandSubtitleTracks.length) {
+                return;
+            }
+            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);
+                }
+            }
+        }
+    };
+
+    /** @hide */
+    @Override
+    public void onSubtitleTrackSelected(SubtitleTrack track) {
+        if (mSelectedSubtitleTrackIndex >= 0) {
+            try {
+                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
+            } catch (IllegalStateException e) {
+            }
+            mSelectedSubtitleTrackIndex = -1;
+        }
+        setOnSubtitleDataListener(null);
+        if (track == null) {
+            return;
+        }
+        for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
+            if (mInbandSubtitleTracks[i] == track) {
+                Log.v(TAG, "Selecting subtitle track " + i);
+                mSelectedSubtitleTrackIndex = i;
+                try {
+                    selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
+                } catch (IllegalStateException e) {
+                }
+                setOnSubtitleDataListener(mSubtitleDataListener);
+                break;
+            }
+        }
+        // no need to select out-of-band tracks
+    }
+
+    /** @hide */
+    public void addSubtitleSource(InputStream is, MediaFormat format)
+            throws IllegalStateException
+    {
+        final InputStream fIs = is;
+        final MediaFormat fFormat = format;
+
+        // Ensure all input streams are closed.  It is also a handy
+        // way to implement timeouts in the future.
+        synchronized(mOpenSubtitleSources) {
+            mOpenSubtitleSources.add(is);
+        }
+
+        // process each subtitle in its own thread
+        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
+              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
+        thread.start();
+        Handler handler = new Handler(thread.getLooper());
+        handler.post(new Runnable() {
+            private int addTrack() {
+                if (fIs == null || mSubtitleController == null) {
+                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
+                }
+
+                SubtitleTrack track = mSubtitleController.addTrack(fFormat);
+                if (track == null) {
+                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
+                }
+
+                // TODO: do the conversion in the subtitle track
+                Scanner scanner = new Scanner(fIs, "UTF-8");
+                String contents = scanner.useDelimiter("\\A").next();
+                synchronized(mOpenSubtitleSources) {
+                    mOpenSubtitleSources.remove(fIs);
+                }
+                scanner.close();
+                mOutOfBandSubtitleTracks.add(track);
+                track.onData(contents, true /* eos */, ~0 /* runID: keep forever */);
+                return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
+            }
+
+            public void run() {
+                int res = addTrack();
+                if (mEventHandler != null) {
+                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
+                    mEventHandler.sendMessage(m);
+                }
+                thread.getLooper().quitSafely();
+            }
+        });
+    }
+
+    private void scanInternalSubtitleTracks() {
+        if (mSubtitleController == null) {
+            Log.e(TAG, "Should have subtitle controller already set");
+            return;
+        }
+
+        TrackInfo[] tracks = getInbandTrackInfo();
+        SubtitleTrack[] inbandTracks = new SubtitleTrack[tracks.length];
+        for (int i=0; i < tracks.length; i++) {
+            if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+                if (i < mInbandSubtitleTracks.length) {
+                    inbandTracks[i] = mInbandSubtitleTracks[i];
+                } else {
+                    SubtitleTrack track = mSubtitleController.addTrack(
+                            tracks[i].getFormat());
+                    inbandTracks[i] = track;
+                }
+            }
+        }
+        mInbandSubtitleTracks = inbandTracks;
+        mSubtitleController.selectDefaultTrack();
+    }
+
     /* TODO: Limit the total number of external timed text source to a reasonable number.
      */
     /**
@@ -1910,6 +2055,30 @@
 
     private void selectOrDeselectTrack(int index, boolean select)
             throws IllegalStateException {
+        // handle subtitle track through subtitle controller
+        SubtitleTrack track = null;
+        if (index < mInbandSubtitleTracks.length) {
+            track = mInbandSubtitleTracks[index];
+        } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
+            track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length);
+        }
+
+        if (mSubtitleController != null && track != null) {
+            if (select) {
+                mSubtitleController.selectTrack(track);
+            } else if (mSubtitleController.getSelectedTrack() == track) {
+                mSubtitleController.selectTrack(null);
+            } else {
+                Log.w(TAG, "trying to deselect track that was not selected");
+            }
+            return;
+        }
+
+        selectOrDeselectInbandTrack(index, select);
+    }
+
+    private void selectOrDeselectInbandTrack(int index, boolean select)
+            throws IllegalStateException {
         Parcel request = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
@@ -1990,9 +2159,24 @@
     private static final int MEDIA_BUFFERING_UPDATE = 3;
     private static final int MEDIA_SEEK_COMPLETE = 4;
     private static final int MEDIA_SET_VIDEO_SIZE = 5;
+    private static final int MEDIA_STARTED = 6;
+    private static final int MEDIA_PAUSED = 7;
+    private static final int MEDIA_STOPPED = 8;
+    private static final int MEDIA_SKIPPED = 9;
     private static final int MEDIA_TIMED_TEXT = 99;
     private static final int MEDIA_ERROR = 100;
     private static final int MEDIA_INFO = 200;
+    private static final int MEDIA_SUBTITLE_DATA = 201;
+
+    private TimeProvider mTimeProvider;
+
+    /** @hide */
+    public MediaTimeProvider getMediaTimeProvider() {
+        if (mTimeProvider == null) {
+            mTimeProvider = new TimeProvider(this);
+        }
+        return mTimeProvider;
+    }
 
     private class EventHandler extends Handler
     {
@@ -2011,6 +2195,7 @@
             }
             switch(msg.what) {
             case MEDIA_PREPARED:
+                scanInternalSubtitleTracks();
                 if (mOnPreparedListener != null)
                     mOnPreparedListener.onPrepared(mMediaPlayer);
                 return;
@@ -2021,14 +2206,34 @@
                 stayAwake(false);
                 return;
 
+            case MEDIA_STOPPED:
+                if (mTimeProvider != null) {
+                    mTimeProvider.onStopped();
+                }
+                break;
+
+            case MEDIA_STARTED:
+            case MEDIA_PAUSED:
+                if (mTimeProvider != null) {
+                    mTimeProvider.onPaused(msg.what == MEDIA_PAUSED);
+                }
+                break;
+
             case MEDIA_BUFFERING_UPDATE:
                 if (mOnBufferingUpdateListener != null)
                     mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
                 return;
 
             case MEDIA_SEEK_COMPLETE:
-              if (mOnSeekCompleteListener != null)
+              if (mOnSeekCompleteListener != null) {
                   mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
+              }
+              // fall through
+
+            case MEDIA_SKIPPED:
+              if (mTimeProvider != null) {
+                  mTimeProvider.onSeekComplete(mMediaPlayer);
+              }
               return;
 
             case MEDIA_SET_VIDEO_SIZE:
@@ -2049,9 +2254,21 @@
                 return;
 
             case MEDIA_INFO:
-                if (msg.arg1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
+                switch (msg.arg1) {
+                case MEDIA_INFO_VIDEO_TRACK_LAGGING:
                     Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
+                    break;
+                case MEDIA_INFO_METADATA_UPDATE:
+                    scanInternalSubtitleTracks();
+                    // fall through
+
+                case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
+                    msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
+                    // update default track selection
+                    mSubtitleController.selectDefaultTrack();
+                    break;
                 }
+
                 if (mOnInfoListener != null) {
                     mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
                 }
@@ -2072,6 +2289,18 @@
                 }
                 return;
 
+            case MEDIA_SUBTITLE_DATA:
+                if (mOnSubtitleDataListener == null) {
+                    return;
+                }
+                if (msg.obj instanceof Parcel) {
+                    Parcel parcel = (Parcel) msg.obj;
+                    SubtitleData data = new SubtitleData(parcel);
+                    parcel.recycle();
+                    mOnSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
+                }
+                return;
+
             case MEDIA_NOP: // interface test message - ignore
                 break;
 
@@ -2283,6 +2512,30 @@
 
     private OnTimedTextListener mOnTimedTextListener;
 
+    /**
+     * Interface definition of a callback to be invoked when a
+     * track has data available.
+     *
+     * @hide
+     */
+    public interface OnSubtitleDataListener
+    {
+        public void onSubtitleData(MediaPlayer mp, SubtitleData data);
+    }
+
+    /**
+     * Register a callback to be invoked when a track has data available.
+     *
+     * @param listener the callback that will be run
+     *
+     * @hide
+     */
+    public void setOnSubtitleDataListener(OnSubtitleDataListener listener)
+    {
+        mOnSubtitleDataListener = listener;
+    }
+
+    private OnSubtitleDataListener mOnSubtitleDataListener;
 
     /* Do not change these values without updating their counterparts
      * in include/media/mediaplayer.h!
@@ -2414,6 +2667,12 @@
      */
     public static final int MEDIA_INFO_METADATA_UPDATE = 802;
 
+    /** A new set of external-only metadata is available.  Used by
+     *  JAVA framework to avoid triggering track scanning.
+     * @hide
+     */
+    public static final int MEDIA_INFO_EXTERNAL_METADATA_UPDATE = 803;
+
     /** Failed to handle timed text track properly.
      * @see android.media.MediaPlayer.OnInfoListener
      *
@@ -2421,6 +2680,16 @@
      */
     public static final int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
 
+    /** Subtitle track was not supported by the media framework.
+     * @see android.media.MediaPlayer.OnInfoListener
+     */
+    public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;
+
+    /** Reading the subtitle track takes too long.
+     * @see android.media.MediaPlayer.OnInfoListener
+     */
+    public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
+
     /**
      * Interface definition of a callback to be invoked to communicate some
      * info and/or warning about the media or its playback.
@@ -2441,6 +2710,8 @@
          * <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
          * <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
          * <li>{@link #MEDIA_INFO_METADATA_UPDATE}
+         * <li>{@link #MEDIA_INFO_UNSUPPORTED_SUBTITLE}
+         * <li>{@link #MEDIA_INFO_SUBTITLE_TIMED_OUT}
          * </ul>
          * @param extra an extra code, specific to the info. Typically
          * implementation dependent.
@@ -2523,4 +2794,390 @@
     }
 
     private native void updateProxyConfig(ProxyProperties props);
+
+    /** @hide */
+    static class TimeProvider implements MediaPlayer.OnSeekCompleteListener,
+            MediaTimeProvider {
+        private static final String TAG = "MTP";
+        private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
+        private static final long MAX_EARLY_CALLBACK_US = 1000;
+        private static final long TIME_ADJUSTMENT_RATE = 2;  /* meaning 1/2 */
+        private long mLastTimeUs = 0;
+        private MediaPlayer mPlayer;
+        private boolean mPaused = true;
+        private boolean mStopped = true;
+        private long mLastReportedTime;
+        private long mTimeAdjustment;
+        // since we are expecting only a handful listeners per stream, there is
+        // no need for log(N) search performance
+        private MediaTimeProvider.OnMediaTimeListener mListeners[];
+        private long mTimes[];
+        private long mLastNanoTime;
+        private Handler mEventHandler;
+        private boolean mRefresh = false;
+        private boolean mPausing = false;
+        private boolean mSeeking = false;
+        private static final int NOTIFY = 1;
+        private static final int NOTIFY_TIME = 0;
+        private static final int REFRESH_AND_NOTIFY_TIME = 1;
+        private static final int NOTIFY_STOP = 2;
+        private static final int NOTIFY_SEEK = 3;
+        private HandlerThread mHandlerThread;
+
+        /** @hide */
+        public boolean DEBUG = false;
+
+        public TimeProvider(MediaPlayer mp) {
+            mPlayer = mp;
+            try {
+                getCurrentTimeUs(true, false);
+            } catch (IllegalStateException e) {
+                // we assume starting position
+                mRefresh = true;
+            }
+
+            Looper looper;
+            if ((looper = Looper.myLooper()) == null &&
+                (looper = Looper.getMainLooper()) == null) {
+                // Create our own looper here in case MP was created without one
+                mHandlerThread = new HandlerThread("MediaPlayerMTPEventThread",
+                      Process.THREAD_PRIORITY_FOREGROUND);
+                mHandlerThread.start();
+                looper = mHandlerThread.getLooper();
+            }
+            mEventHandler = new EventHandler(looper);
+
+            mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
+            mTimes = new long[0];
+            mLastTimeUs = 0;
+            mTimeAdjustment = 0;
+        }
+
+        private void scheduleNotification(int type, long delayUs) {
+            // ignore time notifications until seek is handled
+            if (mSeeking &&
+                    (type == NOTIFY_TIME || type == REFRESH_AND_NOTIFY_TIME)) {
+                return;
+            }
+
+            if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
+            mStopped = type == NOTIFY_STOP;
+            mSeeking = type == NOTIFY_SEEK;
+            mEventHandler.removeMessages(NOTIFY);
+            Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
+            mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
+        }
+
+        /** @hide */
+        public void close() {
+            mEventHandler.removeMessages(NOTIFY);
+            if (mHandlerThread != null) {
+                mHandlerThread.quitSafely();
+                mHandlerThread = null;
+            }
+        }
+
+        /** @hide */
+        protected void finalize() {
+            if (mHandlerThread != null) {
+                mHandlerThread.quitSafely();
+            }
+        }
+
+        /** @hide */
+        public void onPaused(boolean paused) {
+            synchronized(this) {
+                if (DEBUG) Log.d(TAG, "onPaused: " + paused);
+                if (mStopped) { // handle as seek if we were stopped
+                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
+                } else {
+                    mPausing = paused;  // special handling if player disappeared
+                    scheduleNotification(REFRESH_AND_NOTIFY_TIME, 0 /* delay */);
+                }
+            }
+        }
+
+        /** @hide */
+        public void onStopped() {
+            synchronized(this) {
+                if (DEBUG) Log.d(TAG, "onStopped");
+                mPaused = true;
+                scheduleNotification(NOTIFY_STOP, 0 /* delay */);
+            }
+        }
+
+        /** @hide */
+        @Override
+        public void onSeekComplete(MediaPlayer mp) {
+            synchronized(this) {
+                scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
+            }
+        }
+
+        /** @hide */
+        public void onNewPlayer() {
+            if (mRefresh) {
+                synchronized(this) {
+                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
+                }
+            }
+        }
+
+        private synchronized void notifySeek() {
+            mSeeking = false;
+            try {
+                long timeUs = getCurrentTimeUs(true, false);
+                if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
+
+                for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
+                    if (listener == null) {
+                        break;
+                    }
+                    listener.onSeek(timeUs);
+                }
+            } catch (IllegalStateException e) {
+                // we should not be there, but at least signal pause
+                if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
+                mPausing = true;  // special handling if player disappeared
+                notifyTimedEvent(false /* refreshTime */);
+            }
+        }
+
+        private synchronized void notifyStop() {
+            for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
+                if (listener == null) {
+                    break;
+                }
+                listener.onStop();
+            }
+        }
+
+        private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
+            int i = 0;
+            for (; i < mListeners.length; i++) {
+                if (mListeners[i] == listener || mListeners[i] == null) {
+                    break;
+                }
+            }
+
+            // new listener
+            if (i >= mListeners.length) {
+                MediaTimeProvider.OnMediaTimeListener[] newListeners =
+                    new MediaTimeProvider.OnMediaTimeListener[i + 1];
+                long[] newTimes = new long[i + 1];
+                System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
+                System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
+                mListeners = newListeners;
+                mTimes = newTimes;
+            }
+
+            if (mListeners[i] == null) {
+                mListeners[i] = listener;
+                mTimes[i] = MediaTimeProvider.NO_TIME;
+            }
+            return i;
+        }
+
+        public void notifyAt(
+                long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
+            synchronized(this) {
+                if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
+                mTimes[registerListener(listener)] = timeUs;
+                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
+            }
+        }
+
+        public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
+            synchronized(this) {
+                if (DEBUG) Log.d(TAG, "scheduleUpdate");
+                int i = registerListener(listener);
+
+                if (mStopped) {
+                    scheduleNotification(NOTIFY_STOP, 0 /* delay */);
+                } else {
+                    mTimes[i] = 0;
+                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
+                }
+            }
+        }
+
+        public void cancelNotifications(
+                MediaTimeProvider.OnMediaTimeListener listener) {
+            synchronized(this) {
+                int i = 0;
+                for (; i < mListeners.length; i++) {
+                    if (mListeners[i] == listener) {
+                        System.arraycopy(mListeners, i + 1,
+                                mListeners, i, mListeners.length - i - 1);
+                        System.arraycopy(mTimes, i + 1,
+                                mTimes, i, mTimes.length - i - 1);
+                        mListeners[mListeners.length - 1] = null;
+                        mTimes[mTimes.length - 1] = NO_TIME;
+                        break;
+                    } else if (mListeners[i] == null) {
+                        break;
+                    }
+                }
+
+                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
+            }
+        }
+
+        private synchronized void notifyTimedEvent(boolean refreshTime) {
+            // figure out next callback
+            long nowUs;
+            try {
+                nowUs = getCurrentTimeUs(refreshTime, true);
+            } catch (IllegalStateException e) {
+                // assume we paused until new player arrives
+                mRefresh = true;
+                mPausing = true; // this ensures that call succeeds
+                nowUs = getCurrentTimeUs(refreshTime, true);
+            }
+            long nextTimeUs = nowUs;
+
+            if (mSeeking) {
+                // skip timed-event notifications until seek is complete
+                return;
+            }
+
+            if (DEBUG) {
+                StringBuilder sb = new StringBuilder();
+                sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
+                        .append(nowUs).append(") from {");
+                boolean first = true;
+                for (long time: mTimes) {
+                    if (time == NO_TIME) {
+                        continue;
+                    }
+                    if (!first) sb.append(", ");
+                    sb.append(time);
+                    first = false;
+                }
+                sb.append("}");
+                Log.d(TAG, sb.toString());
+            }
+
+            Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
+                new Vector<MediaTimeProvider.OnMediaTimeListener>();
+            for (int ix = 0; ix < mTimes.length; ix++) {
+                if (mListeners[ix] == null) {
+                    break;
+                }
+                if (mTimes[ix] <= NO_TIME) {
+                    // ignore, unless we were stopped
+                } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
+                    activatedListeners.add(mListeners[ix]);
+                    if (DEBUG) Log.d(TAG, "removed");
+                    mTimes[ix] = NO_TIME;
+                } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
+                    nextTimeUs = mTimes[ix];
+                }
+            }
+
+            if (nextTimeUs > nowUs && !mPaused) {
+                // schedule callback at nextTimeUs
+                if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
+                scheduleNotification(NOTIFY_TIME, nextTimeUs - nowUs);
+            } else {
+                mEventHandler.removeMessages(NOTIFY);
+                // no more callbacks
+            }
+
+            for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
+                listener.onTimedEvent(nowUs);
+            }
+        }
+
+        private long getEstimatedTime(long nanoTime, boolean monotonic) {
+            if (mPaused) {
+                mLastReportedTime = mLastTimeUs + mTimeAdjustment;
+            } else {
+                long timeSinceRead = (nanoTime - mLastNanoTime) / 1000;
+                mLastReportedTime = mLastTimeUs + timeSinceRead;
+                if (mTimeAdjustment > 0) {
+                    long adjustment =
+                        mTimeAdjustment - timeSinceRead / TIME_ADJUSTMENT_RATE;
+                    if (adjustment <= 0) {
+                        mTimeAdjustment = 0;
+                    } else {
+                        mLastReportedTime += adjustment;
+                    }
+                }
+            }
+            return mLastReportedTime;
+        }
+
+        public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
+                throws IllegalStateException {
+            synchronized (this) {
+                // we always refresh the time when the paused-state changes, because
+                // we expect to have received the pause-change event delayed.
+                if (mPaused && !refreshTime) {
+                    return mLastReportedTime;
+                }
+
+                long nanoTime = System.nanoTime();
+                if (refreshTime ||
+                        nanoTime >= mLastNanoTime + MAX_NS_WITHOUT_POSITION_CHECK) {
+                    try {
+                        mLastTimeUs = mPlayer.getCurrentPosition() * 1000;
+                        mPaused = !mPlayer.isPlaying();
+                        if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
+                    } catch (IllegalStateException e) {
+                        if (mPausing) {
+                            // if we were pausing, get last estimated timestamp
+                            mPausing = false;
+                            getEstimatedTime(nanoTime, monotonic);
+                            mPaused = true;
+                            if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
+                            return mLastReportedTime;
+                        }
+                        // TODO get time when prepared
+                        throw e;
+                    }
+                    mLastNanoTime = nanoTime;
+                    if (monotonic && mLastTimeUs < mLastReportedTime) {
+                        /* have to adjust time */
+                        mTimeAdjustment = mLastReportedTime - mLastTimeUs;
+                        if (mTimeAdjustment > 1000000) {
+                            // schedule seeked event if time jumped significantly
+                            // TODO: do this properly by introducing an exception
+                            scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
+                        }
+                    } else {
+                        mTimeAdjustment = 0;
+                    }
+                }
+
+                return getEstimatedTime(nanoTime, monotonic);
+            }
+        }
+
+        private class EventHandler extends Handler {
+            public EventHandler(Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == NOTIFY) {
+                    switch (msg.arg1) {
+                    case NOTIFY_TIME:
+                        notifyTimedEvent(false /* refreshTime */);
+                        break;
+                    case REFRESH_AND_NOTIFY_TIME:
+                        notifyTimedEvent(true /* refreshTime */);
+                        break;
+                    case NOTIFY_STOP:
+                        notifyStop();
+                        break;
+                    case NOTIFY_SEEK:
+                        notifySeek();
+                        break;
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3e688db..8dcbd6b 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -179,6 +179,40 @@
          *  is applied.
          */
         public static final int VOICE_COMMUNICATION = 7;
+
+        /**
+         * Audio source for a submix of audio streams to be presented remotely.
+         * <p>
+         * An application can use this audio source to capture a mix of audio streams
+         * that should be transmitted to a remote receiver such as a Wifi display.
+         * While recording is active, these audio streams are redirected to the remote
+         * submix instead of being played on the device speaker or headset.
+         * </p><p>
+         * Certain streams are excluded from the remote submix, including
+         * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_ALARM},
+         * and {@link AudioManager#STREAM_NOTIFICATION}.  These streams will continue
+         * to be presented locally as usual.
+         * </p><p>
+         * Capturing the remote submix audio requires the
+         * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
+         * This permission is reserved for use by system components and is not available to
+         * third-party applications.
+         * </p>
+         */
+        public static final int REMOTE_SUBMIX = 8;
+
+        /**
+         * Audio source for preemptible, low-priority software hotword detection
+         * It presents the same gain and pre processing tuning as {@link #VOICE_RECOGNITION}.
+         * <p>
+         * An application should use this audio source when it wishes to do
+         * always-on software hotword detection, while gracefully giving in to any other application
+         * that might want to read from the microphone.
+         * </p>
+         * This is a hidden audio source.
+         * @hide
+         */
+        protected static final int HOTWORD = 1999;
     }
 
     /**
@@ -294,7 +328,7 @@
      * @see android.media.MediaRecorder.AudioSource
      */
     public static final int getAudioSourceMax() {
-        return AudioSource.VOICE_COMMUNICATION;
+        return AudioSource.REMOTE_SUBMIX;
     }
 
     /**
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 5c58503..9a79c94 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -653,7 +654,13 @@
             if (info == sStatic.mSelectedRoute) {
                 // Removing the currently selected route? Select the default before we remove it.
                 // TODO: Be smarter about the route types here; this selects for all valid.
-                selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudioVideo);
+                if (info != sStatic.mBluetoothA2dpRoute && sStatic.mBluetoothA2dpRoute != null) {
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
+                            sStatic.mBluetoothA2dpRoute);
+                } else {
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
+                            sStatic.mDefaultAudioVideo);
+                }
             }
             if (!found) {
                 sStatic.mCategories.remove(removingCat);
@@ -875,44 +882,45 @@
         boolean wantScan = false;
         boolean blockScan = false;
         WifiDisplay[] oldDisplays = oldStatus != null ?
-                oldStatus.getRememberedDisplays() : WifiDisplay.EMPTY_ARRAY;
+                oldStatus.getDisplays() : WifiDisplay.EMPTY_ARRAY;
         WifiDisplay[] newDisplays;
-        WifiDisplay[] availableDisplays;
         WifiDisplay activeDisplay;
 
         if (newStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
-            newDisplays = newStatus.getRememberedDisplays();
-            availableDisplays = newStatus.getAvailableDisplays();
+            newDisplays = newStatus.getDisplays();
             activeDisplay = newStatus.getActiveDisplay();
         } else {
-            newDisplays = availableDisplays = WifiDisplay.EMPTY_ARRAY;
+            newDisplays = WifiDisplay.EMPTY_ARRAY;
             activeDisplay = null;
         }
 
         for (int i = 0; i < newDisplays.length; i++) {
             final WifiDisplay d = newDisplays[i];
-            final boolean available = findMatchingDisplay(d, availableDisplays) != null;
-            RouteInfo route = findWifiDisplayRoute(d);
-            if (route == null) {
-                route = makeWifiDisplayRoute(d, available);
-                addRouteStatic(route);
-                wantScan = true;
-            } else {
-                updateWifiDisplayRoute(route, d, available, newStatus);
-            }
-            if (d.equals(activeDisplay)) {
-                selectRouteStatic(route.getSupportedTypes(), route);
+            if (d.isRemembered()) {
+                RouteInfo route = findWifiDisplayRoute(d);
+                if (route == null) {
+                    route = makeWifiDisplayRoute(d, newStatus);
+                    addRouteStatic(route);
+                    wantScan = true;
+                } else {
+                    updateWifiDisplayRoute(route, d, newStatus);
+                }
+                if (d.equals(activeDisplay)) {
+                    selectRouteStatic(route.getSupportedTypes(), route);
 
-                // Don't scan if we're already connected to a wifi display,
-                // the scanning process can cause a hiccup with some configurations.
-                blockScan = true;
+                    // Don't scan if we're already connected to a wifi display,
+                    // the scanning process can cause a hiccup with some configurations.
+                    blockScan = true;
+                }
             }
         }
         for (int i = 0; i < oldDisplays.length; i++) {
             final WifiDisplay d = oldDisplays[i];
-            final WifiDisplay newDisplay = findMatchingDisplay(d, newDisplays);
-            if (newDisplay == null) {
-                removeRoute(findWifiDisplayRoute(d));
+            if (d.isRemembered()) {
+                final WifiDisplay newDisplay = findMatchingDisplay(d, newDisplays);
+                if (newDisplay == null || !newDisplay.isRemembered()) {
+                    removeRoute(findWifiDisplayRoute(d));
+                }
             }
         }
 
@@ -923,42 +931,20 @@
         sStatic.mLastKnownWifiDisplayStatus = newStatus;
     }
 
-    static RouteInfo makeWifiDisplayRoute(WifiDisplay display, boolean available) {
-        final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory);
-        newRoute.mDeviceAddress = display.getDeviceAddress();
-        newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
-        newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
-        newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE;
-
-        newRoute.setStatusCode(available ?
-                RouteInfo.STATUS_AVAILABLE : RouteInfo.STATUS_CONNECTING);
-        newRoute.mEnabled = available;
-
-        newRoute.mName = display.getFriendlyDisplayName();
-        newRoute.mDescription = sStatic.mResources.getText(
-                com.android.internal.R.string.wireless_display_route_description);
-
-        newRoute.mPresentationDisplay = choosePresentationDisplayForRoute(newRoute,
-                sStatic.getAllPresentationDisplays());
-        return newRoute;
-    }
-
-    private static void updateWifiDisplayRoute(RouteInfo route, WifiDisplay display,
-            boolean available, WifiDisplayStatus wifiDisplayStatus) {
-        final boolean isScanning =
-                wifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING;
-
-        boolean changed = false;
+    static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) {
         int newStatus = RouteInfo.STATUS_NONE;
 
-        if (available) {
-            newStatus = isScanning ? RouteInfo.STATUS_SCANNING : RouteInfo.STATUS_AVAILABLE;
+        if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) {
+            newStatus = RouteInfo.STATUS_SCANNING;
+        } else if (d.isAvailable()) {
+            newStatus = d.canConnect() ?
+                    RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE;
         } else {
             newStatus = RouteInfo.STATUS_NOT_AVAILABLE;
         }
 
-        if (display.equals(wifiDisplayStatus.getActiveDisplay())) {
-            final int activeState = wifiDisplayStatus.getActiveDisplayState();
+        if (d.equals(wfdStatus.getActiveDisplay())) {
+            final int activeState = wfdStatus.getActiveDisplayState();
             switch (activeState) {
                 case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
                     newStatus = RouteInfo.STATUS_NONE;
@@ -972,22 +958,51 @@
             }
         }
 
+        return newStatus;
+    }
+
+    static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) {
+        return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay()));
+    }
+
+    static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) {
+        final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory);
+        newRoute.mDeviceAddress = display.getDeviceAddress();
+        newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
+        newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
+        newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE;
+
+        newRoute.setStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
+        newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus);
+        newRoute.mName = display.getFriendlyDisplayName();
+        newRoute.mDescription = sStatic.mResources.getText(
+                com.android.internal.R.string.wireless_display_route_description);
+
+        newRoute.mPresentationDisplay = choosePresentationDisplayForRoute(newRoute,
+                sStatic.getAllPresentationDisplays());
+        return newRoute;
+    }
+
+    private static void updateWifiDisplayRoute(
+            RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus) {
+        boolean changed = false;
         final String newName = display.getFriendlyDisplayName();
         if (!route.getName().equals(newName)) {
             route.mName = newName;
             changed = true;
         }
 
-        changed |= route.mEnabled != available;
-        route.mEnabled = available;
+        boolean enabled = isWifiDisplayEnabled(display, wfdStatus);
+        changed |= route.mEnabled != enabled;
+        route.mEnabled = enabled;
 
-        changed |= route.setStatusCode(newStatus);
+        changed |= route.setStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
 
         if (changed) {
             dispatchRouteChanged(route);
         }
 
-        if (!available && route == sStatic.mSelectedRoute) {
+        if (!enabled && route == sStatic.mSelectedRoute) {
             // Oops, no longer available. Reselect the default.
             final RouteInfo defaultRoute = sStatic.mDefaultAudioVideo;
             selectRouteStatic(defaultRoute.getSupportedTypes(), defaultRoute);
@@ -1068,6 +1083,7 @@
         /** @hide */ public static final int STATUS_CONNECTING = 2;
         /** @hide */ public static final int STATUS_AVAILABLE = 3;
         /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4;
+        /** @hide */ public static final int STATUS_IN_USE = 5;
 
         private Object mTag;
 
@@ -1179,6 +1195,9 @@
                     case STATUS_NOT_AVAILABLE:
                         resId = com.android.internal.R.string.media_route_status_not_available;
                         break;
+                    case STATUS_IN_USE:
+                        resId = com.android.internal.R.string.media_route_status_in_use;
+                        break;
                 }
                 mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null;
                 return true;
@@ -1292,7 +1311,8 @@
         public void requestSetVolume(int volume) {
             if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
                 try {
-                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0);
+                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0,
+                            ActivityThread.currentPackageName());
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
@@ -1312,7 +1332,8 @@
                 try {
                     final int volume =
                             Math.max(0, Math.min(getVolume() + direction, getVolumeMax()));
-                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0);
+                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0,
+                            ActivityThread.currentPackageName());
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 21b6e14..273eb64 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -113,6 +113,9 @@
         synchronized (this) {
             if (!mConnected) {
                 Intent intent = new Intent(IMediaScannerService.class.getName());
+                intent.setComponent(
+                        new ComponentName("com.android.providers.media",
+                                "com.android.providers.media.MediaScannerService"));
                 mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
                 mConnected = true;
             }
diff --git a/media/java/android/media/MediaTimeProvider.java b/media/java/android/media/MediaTimeProvider.java
new file mode 100644
index 0000000..fe37712
--- /dev/null
+++ b/media/java/android/media/MediaTimeProvider.java
@@ -0,0 +1,90 @@
+/*
+ * 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 android.media;
+
+/** @hide */
+public interface MediaTimeProvider {
+    // we do not allow negative media time
+    /**
+     * Presentation time value if no timed event notification is requested.
+     */
+    public final static long NO_TIME = -1;
+
+    /**
+     * Cancels all previous notification request from this listener if any.  It
+     * registers the listener to get seek and stop notifications.  If timeUs is
+     * not negative, it also registers the listener for a timed event
+     * notification when the presentation time reaches (becomes greater) than
+     * the value specified.  This happens immediately if the current media time
+     * is larger than or equal to timeUs.
+     *
+     * @param timeUs presentation time to get timed event callback at (or
+     *               {@link #NO_TIME})
+     */
+    public void notifyAt(long timeUs, OnMediaTimeListener listener);
+
+    /**
+     * Cancels all previous notification request from this listener if any.  It
+     * registers the listener to get seek and stop notifications.  If the media
+     * is stopped, the listener will immediately receive a stop notification.
+     * Otherwise, it will receive a timed event notificaton.
+     */
+    public void scheduleUpdate(OnMediaTimeListener listener);
+
+    /**
+     * Cancels all previous notification request from this listener if any.
+     */
+    public void cancelNotifications(OnMediaTimeListener listener);
+
+    /**
+     * Get the current presentation time.
+     *
+     * @param precise   Whether getting a precise time is important. This is
+     *                  more costly.
+     * @param monotonic Whether returned time should be monotonic: that is,
+     *                  greater than or equal to the last returned time.  Don't
+     *                  always set this to true.  E.g. this has undesired
+     *                  consequences if the media is seeked between calls.
+     * @throws IllegalStateException if the media is not initialized
+     */
+    public long getCurrentTimeUs(boolean precise, boolean monotonic)
+            throws IllegalStateException;
+
+    /** @hide */
+    public static interface OnMediaTimeListener {
+        /**
+         * Called when the registered time was reached naturally.
+         *
+         * @param timeUs current media time
+         */
+        void onTimedEvent(long timeUs);
+
+        /**
+         * Called when the media time changed due to seeking.
+         *
+         * @param timeUs current media time
+         */
+        void onSeek(long timeUs);
+
+        /**
+         * Called when the playback stopped.  This is not called on pause, only
+         * on full stop, at which point there is no further current media time.
+         */
+        void onStop();
+    }
+}
+
diff --git a/media/java/android/media/Rating.aidl b/media/java/android/media/Rating.aidl
new file mode 100644
index 0000000..1dc336a
--- /dev/null
+++ b/media/java/android/media/Rating.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.media;
+
+parcelable Rating;
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
new file mode 100644
index 0000000..82c0392
--- /dev/null
+++ b/media/java/android/media/Rating.java
@@ -0,0 +1,284 @@
+/*
+ * 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 android.media;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class to encapsulate rating information used as content metadata.
+ * A rating is defined by its rating style (see {@link #RATING_HEART},
+ * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
+ * be defined as "unrated"), both of which are defined when the rating instance is constructed
+ * through one of the factory methods.
+ */
+public final class Rating implements Parcelable {
+
+    private final static String TAG = "Rating";
+
+    /**
+     * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
+     * indicate the content referred to is a favorite (or not).
+     */
+    public final static int RATING_HEART = 1;
+
+    /**
+     * A rating style for "thumb up" vs "thumb down".
+     */
+    public final static int RATING_THUMB_UP_DOWN = 2;
+
+    /**
+     * A rating style with 0 to 3 stars.
+     */
+    public final static int RATING_3_STARS = 3;
+
+    /**
+     * A rating style with 0 to 4 stars.
+     */
+    public final static int RATING_4_STARS = 4;
+
+    /**
+     * A rating style with 0 to 5 stars.
+     */
+    public final static int RATING_5_STARS = 5;
+
+    /**
+     * A rating style expressed as a percentage.
+     */
+    public final static int RATING_PERCENTAGE = 6;
+
+    private final static float RATING_NOT_RATED = -1.0f;
+
+    private final int mRatingStyle;
+
+    private final float mRatingValue;
+
+    private Rating(int ratingStyle, float rating) {
+        mRatingStyle = ratingStyle;
+        mRatingValue = rating;
+    }
+
+
+    /**
+     * @hide
+     */
+    @Override
+    public String toString () {
+        return "Rating:style=" + mRatingStyle + " rating="
+                + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
+    }
+
+    @Override
+    public int describeContents() {
+        return mRatingStyle;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRatingStyle);
+        dest.writeFloat(mRatingValue);
+    }
+
+    public static final Parcelable.Creator<Rating> CREATOR
+            = new Parcelable.Creator<Rating>() {
+        /**
+         * Rebuilds a Rating previously stored with writeToParcel().
+         * @param p    Parcel object to read the Rating from
+         * @return a new Rating created from the data in the parcel
+         */
+        public Rating createFromParcel(Parcel p) {
+            return new Rating(p.readInt(), p.readFloat());
+        }
+        public Rating[] newArray(int size) {
+            return new Rating[size];
+        }
+    };
+
+    /**
+     * Return a Rating instance with no rating.
+     * Create and return a new Rating instance with no rating known for the given
+     * rating style.
+     * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+     *    or {@link #RATING_PERCENTAGE}.
+     * @return null if an invalid rating style is passed, a new Rating instance otherwise.
+     */
+    public static Rating newUnratedRating(int ratingStyle) {
+        switch(ratingStyle) {
+            case RATING_HEART:
+            case RATING_THUMB_UP_DOWN:
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+            case RATING_PERCENTAGE:
+                return new Rating(ratingStyle, RATING_NOT_RATED);
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Return a Rating instance with a heart-based rating.
+     * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
+     * and a heart-based rating.
+     * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
+     * @return a new Rating instance.
+     */
+    public static Rating newHeartRating(boolean hasHeart) {
+        return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
+    }
+
+    /**
+     * Return a Rating instance with a thumb-based rating.
+     * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
+     * rating style, and a "thumb up" or "thumb down" rating.
+     * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
+     * @return a new Rating instance.
+     */
+    public static Rating newThumbRating(boolean thumbIsUp) {
+        return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
+    }
+
+    /**
+     * Return a Rating instance with a star-based rating.
+     * Create and return a new Rating instance with one of the star-base rating styles
+     * and the given integer or fractional number of stars. Non integer values can for instance
+     * be used to represent an average rating value, which might not be an integer number of stars.
+     * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+     *     {@link #RATING_5_STARS}.
+     * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
+     *     the rating style.
+     * @return null if the rating style is invalid, or the rating is out of range,
+     *     a new Rating instance otherwise.
+     */
+    public static Rating newStarRating(int starRatingStyle, float starRating) {
+        float maxRating = -1.0f;
+        switch(starRatingStyle) {
+            case RATING_3_STARS:
+                maxRating = 3.0f;
+                break;
+            case RATING_4_STARS:
+                maxRating = 4.0f;
+                break;
+            case RATING_5_STARS:
+                maxRating = 5.0f;
+                break;
+            default:
+                Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
+                        return null;
+        }
+        if ((starRating < 0.0f) || (starRating > maxRating)) {
+            Log.e(TAG, "Trying to set out of range star-based rating");
+            return null;
+        }
+        return new Rating(starRatingStyle, starRating);
+    }
+
+    /**
+     * Return a Rating instance with a percentage-based rating.
+     * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
+     * rating style, and a rating of the given percentage.
+     * @param percent the value of the rating
+     * @return null if the rating is out of range, a new Rating instance otherwise.
+     */
+    public static Rating newPercentageRating(float percent) {
+        if ((percent < 0.0f) || (percent > 100.0f)) {
+            Log.e(TAG, "Invalid percentage-based rating value");
+            return null;
+        } else {
+            return new Rating(RATING_PERCENTAGE, percent);
+        }
+    }
+
+    /**
+     * Return whether there is a rating value available.
+     * @return true if the instance was not created with {@link #newUnratedRating(int)}.
+     */
+    public boolean isRated() {
+        return mRatingValue >= 0.0f;
+    }
+
+    /**
+     * Return the rating style.
+     * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+     *    or {@link #RATING_PERCENTAGE}.
+     */
+    public int getRatingStyle() {
+        return mRatingStyle;
+    }
+
+    /**
+     * Return whether the rating is "heart selected".
+     * @return true if the rating is "heart selected", false if the rating is "heart unselected",
+     *    if the rating style is not {@link #RATING_HEART} or if it is unrated.
+     */
+    public boolean hasHeart() {
+        if (mRatingStyle != RATING_HEART) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    /**
+     * Return whether the rating is "thumb up".
+     * @return true if the rating is "thumb up", false if the rating is "thumb down",
+     *    if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
+     */
+    public boolean isThumbUp() {
+        if (mRatingStyle != RATING_THUMB_UP_DOWN) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    /**
+     * Return the star-based rating value.
+     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+     *    not star-based, or if it is unrated.
+     */
+    public float getStarRating() {
+        switch (mRatingStyle) {
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+                if (isRated()) {
+                    return mRatingValue;
+                }
+            default:
+                return -1.0f;
+        }
+    }
+
+    /**
+     * Return the percentage-based rating value.
+     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+     *    not percentage-based, or if it is unrated.
+     */
+    public float getPercentRating() {
+        if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
+            return -1.0f;
+        } else {
+            return mRatingValue;
+        }
+    }
+}
\ No newline at end of file
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 7379438..ab6bd70 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -293,6 +294,17 @@
      * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
      */
     public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
+    /**
+     * Flag indicating a RemoteControlClient supports ratings.
+     * This flag must be set in order for components that display the RemoteControlClient
+     * information, to display ratings information, and, if ratings are declared editable
+     * (by calling {@link MediaMetadataEditor#addEditableKey(int)} with the
+     * {@link MediaMetadataEditor#RATING_KEY_BY_USER} key), it will enable the user to rate
+     * the media, with values being received through the interface set with
+     * {@link #setMetadataUpdateListener(OnMetadataUpdateListener)}.
+     * @see #setTransportControlFlags(int)
+     */
+    public final static int FLAG_KEY_MEDIA_RATING = 1 << 9;
 
     /**
      * @hide
@@ -374,23 +386,6 @@
         mEventHandler = new EventHandler(this, looper);
     }
 
-    private static final int[] METADATA_KEYS_TYPE_STRING = {
-        MediaMetadataRetriever.METADATA_KEY_ALBUM,
-        MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-        MediaMetadataRetriever.METADATA_KEY_TITLE,
-        MediaMetadataRetriever.METADATA_KEY_ARTIST,
-        MediaMetadataRetriever.METADATA_KEY_AUTHOR,
-        MediaMetadataRetriever.METADATA_KEY_COMPILATION,
-        MediaMetadataRetriever.METADATA_KEY_COMPOSER,
-        MediaMetadataRetriever.METADATA_KEY_DATE,
-        MediaMetadataRetriever.METADATA_KEY_GENRE,
-        MediaMetadataRetriever.METADATA_KEY_TITLE,
-        MediaMetadataRetriever.METADATA_KEY_WRITER };
-    private static final int[] METADATA_KEYS_TYPE_LONG = {
-        MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
-        MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
-        MediaMetadataRetriever.METADATA_KEY_DURATION };
-
     /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
      * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
@@ -399,24 +394,7 @@
      * for the associated client. Once the metadata has been "applied", you cannot reuse this
      * instance of the MetadataEditor.
      */
-    public class MetadataEditor {
-        /**
-         * @hide
-         */
-        protected boolean mMetadataChanged;
-        /**
-         * @hide
-         */
-        protected boolean mArtworkChanged;
-        /**
-         * @hide
-         */
-        protected Bitmap mEditorArtwork;
-        /**
-         * @hide
-         */
-        protected Bundle mEditorMetadata;
-        private boolean mApplied = false;
+    public class MetadataEditor extends MediaMetadataEditor {
 
         // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
         private MetadataEditor() { }
@@ -431,9 +409,10 @@
          * The metadata key for the content artwork / album art.
          */
         public final static int BITMAP_KEY_ARTWORK = 100;
+
         /**
          * @hide
-         * TODO(jmtrivi) have lockscreen and music move to the new key name
+         * TODO(jmtrivi) have lockscreen move to the new key name and remove
          */
         public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
 
@@ -460,15 +439,7 @@
          */
         public synchronized MetadataEditor putString(int key, String value)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
-                throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
-            }
-            mEditorMetadata.putString(String.valueOf(key), value);
-            mMetadataChanged = true;
+            super.putString(key, value);
             return this;
         }
 
@@ -489,15 +460,7 @@
          */
         public synchronized MetadataEditor putLong(int key, long value)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
-                throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
-            }
-            mEditorMetadata.putLong(String.valueOf(key), value);
-            mMetadataChanged = true;
+            super.putLong(key, value);
             return this;
         }
 
@@ -511,31 +474,22 @@
          * @throws IllegalArgumentException
          * @see android.graphics.Bitmap
          */
+        @Override
         public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (key != BITMAP_KEY_ARTWORK) {
-                throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
-            }
-            mEditorArtwork = bitmap;
-            mArtworkChanged = true;
+            super.putBitmap(key, bitmap);
             return this;
         }
 
         /**
-         * Clears all the metadata that has been set since the MetadataEditor instance was
-         *     created with {@link RemoteControlClient#editMetadata(boolean)}.
+         * Clears all the metadata that has been set since the MetadataEditor instance was created
+         * (with {@link RemoteControlClient#editMetadata(boolean)}).
+         * Note that clearing the metadata doesn't reset the editable keys
+         * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
          */
+        @Override
         public synchronized void clear() {
-            if (mApplied) {
-                Log.e(TAG, "Can't clear a previously applied MetadataEditor");
-                return;
-            }
-            mEditorMetadata.clear();
-            mEditorArtwork = null;
+            super.clear();
         }
 
         /**
@@ -552,6 +506,8 @@
             synchronized(mCacheLock) {
                 // assign the edited data
                 mMetadata = new Bundle(mEditorMetadata);
+                // add the information about editable keys
+                mMetadata.putLong(String.valueOf(KEY_EDITABLE_MASK), mEditableKeys);
                 if ((mOriginalArtwork != null) && (!mOriginalArtwork.equals(mEditorArtwork))) {
                     mOriginalArtwork.recycle();
                 }
@@ -559,13 +515,13 @@
                 mEditorArtwork = null;
                 if (mMetadataChanged & mArtworkChanged) {
                     // send to remote control display if conditions are met
-                    sendMetadataWithArtwork_syncCacheLock();
+                    sendMetadataWithArtwork_syncCacheLock(null, 0, 0);
                 } else if (mMetadataChanged) {
                     // send to remote control display if conditions are met
-                    sendMetadata_syncCacheLock();
+                    sendMetadata_syncCacheLock(null);
                 } else if (mArtworkChanged) {
                     // send to remote control display if conditions are met
-                    sendArtwork_syncCacheLock();
+                    sendArtwork_syncCacheLock(null, 0, 0);
                 }
                 mApplied = true;
             }
@@ -585,6 +541,7 @@
             editor.mEditorArtwork = null;
             editor.mMetadataChanged = true;
             editor.mArtworkChanged = true;
+            editor.mEditableKeys = 0;
         } else {
             editor.mEditorMetadata = new Bundle(mMetadata);
             editor.mEditorArtwork = mOriginalArtwork;
@@ -663,7 +620,7 @@
                 mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
 
                 // send to remote control display if conditions are met
-                sendPlaybackState_syncCacheLock();
+                sendPlaybackState_syncCacheLock(null);
                 // update AudioService
                 sendAudioServiceNewPlaybackState_syncCacheLock();
 
@@ -739,7 +696,8 @@
      *      {@link #FLAG_KEY_MEDIA_STOP},
      *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
      *      {@link #FLAG_KEY_MEDIA_NEXT},
-     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE}
+     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE},
+     *      {@link #FLAG_KEY_MEDIA_RATING}.
      */
     public void setTransportControlFlags(int transportControlFlags) {
         synchronized(mCacheLock) {
@@ -747,11 +705,40 @@
             mTransportControlFlags = transportControlFlags;
 
             // send to remote control display if conditions are met
-            sendTransportControlInfo_syncCacheLock();
+            sendTransportControlInfo_syncCacheLock(null);
         }
     }
 
     /**
+     * Interface definition for a callback to be invoked when one of the metadata values has
+     * been updated.
+     * Implement this interface to receive metadata updates after registering your listener
+     * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
+     */
+    public interface OnMetadataUpdateListener {
+        /**
+         * Called on the implementer to notify that the metadata field for the given key has
+         * been updated to the new value.
+         * @param key the identifier of the updated metadata field.
+         * @param newValue the Object storing the new value for the key.
+         */
+        public abstract void onMetadataUpdate(int key, Object newValue);
+    }
+
+    /**
+     * Sets the listener to be called whenever the metadata is updated.
+     * New metadata values will be received in the same thread as the one in which
+     * RemoteControlClient was created.
+     * @param l the metadata update listener
+     */
+    public void setMetadataUpdateListener(OnMetadataUpdateListener l) {
+        synchronized(mCacheLock) {
+            mMetadataUpdateListener = l;
+        }
+    }
+
+
+    /**
      * Interface definition for a callback to be invoked when the media playback position is
      * requested to be updated.
      * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
@@ -804,7 +791,7 @@
             mPositionUpdateListener = l;
             if (oldCapa != mPlaybackPositionCapabilities) {
                 // tell RCDs that this RCC's playback position capabilities have changed
-                sendTransportControlInfo_syncCacheLock();
+                sendTransportControlInfo_syncCacheLock(null);
             }
         }
     }
@@ -826,7 +813,7 @@
             mPositionProvider = l;
             if (oldCapa != mPlaybackPositionCapabilities) {
                 // tell RCDs that this RCC's playback position capabilities have changed
-                sendTransportControlInfo_syncCacheLock();
+                sendTransportControlInfo_syncCacheLock(null);
             }
             if ((mPositionProvider != null) && (mEventHandler != null)
                     && playbackPositionShouldMove(mPlaybackState)) {
@@ -1023,6 +1010,11 @@
      */
     private OnGetPlaybackPositionListener mPositionProvider;
     /**
+     * Listener registered by user of RemoteControlClient to receive edit changes to metadata
+     * it exposes.
+     */
+    private OnMetadataUpdateListener mMetadataUpdateListener;
+    /**
      * The current remote control client generation ID across the system, as known by this object
      */
     private int mCurrentClientGenId = -1;
@@ -1091,6 +1083,7 @@
      */
     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) {
@@ -1104,12 +1097,30 @@
                 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));
+                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, null));
                 mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+                        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));
+                }
             }
         }
 
@@ -1163,6 +1174,14 @@
                         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));
+            }
+        }
     };
 
     /**
@@ -1206,6 +1225,8 @@
     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 class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1217,22 +1238,29 @@
             switch(msg.what) {
                 case MSG_REQUEST_PLAYBACK_STATE:
                     synchronized (mCacheLock) {
-                        sendPlaybackState_syncCacheLock();
+                        sendPlaybackState_syncCacheLock((IRemoteControlDisplay)msg.obj);
                     }
                     break;
                 case MSG_REQUEST_METADATA:
                     synchronized (mCacheLock) {
-                        sendMetadata_syncCacheLock();
+                        sendMetadata_syncCacheLock((IRemoteControlDisplay)msg.obj);
                     }
                     break;
                 case MSG_REQUEST_TRANSPORTCONTROL:
                     synchronized (mCacheLock) {
-                        sendTransportControlInfo_syncCacheLock();
+                        sendTransportControlInfo_syncCacheLock((IRemoteControlDisplay)msg.obj);
                     }
                     break;
                 case MSG_REQUEST_ARTWORK:
                     synchronized (mCacheLock) {
-                        sendArtwork_syncCacheLock();
+                        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:
@@ -1259,6 +1287,9 @@
                 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;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
             }
@@ -1268,8 +1299,19 @@
     //===========================================================
     // Communication with the IRemoteControlDisplay (the displays known to the system)
 
-    private void sendPlaybackState_syncCacheLock() {
+    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 = (DisplayInfoForClient) displayIterator.next();
@@ -1285,8 +1327,17 @@
         }
     }
 
-    private void sendMetadata_syncCacheLock() {
+    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 = (DisplayInfoForClient) displayIterator.next();
@@ -1300,8 +1351,19 @@
         }
     }
 
-    private void sendTransportControlInfo_syncCacheLock() {
+    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 = (DisplayInfoForClient) displayIterator.next();
@@ -1317,9 +1379,15 @@
         }
     }
 
-    private void sendArtwork_syncCacheLock() {
+    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((DisplayInfoForClient) displayIterator.next())) {
@@ -1349,9 +1417,23 @@
         return true;
     }
 
-    private void sendMetadataWithArtwork_syncCacheLock() {
+    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 = (DisplayInfoForClient) displayIterator.next();
@@ -1538,6 +1620,14 @@
         }
     }
 
+    private void onUpdateMetadata(int generationId, int key, Object value) {
+        synchronized (mCacheLock) {
+            if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
+                mMetadataUpdateListener.onMetadataUpdate(key, value);
+            }
+        }
+    }
+
     //===========================================================
     // Internal utilities
 
@@ -1576,24 +1666,6 @@
         return bitmap;
     }
 
-    /**
-     *  Fast routine to go through an array of allowed keys and return whether the key is part
-     *  of that array
-     * @param key the key value
-     * @param validKeys the array of valid keys for a given type
-     * @return true if the key is part of the array, false otherwise
-     */
-    private static boolean validTypeForKey(int key, int[] validKeys) {
-        try {
-            for (int i = 0 ; ; i++) {
-                if (key == validKeys[i]) {
-                    return true;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            return false;
-        }
-    }
 
     /**
      * Returns whether, for the given playback state, the playback position is expected to
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
new file mode 100644
index 0000000..96f6a92
--- /dev/null
+++ b/media/java/android/media/RemoteController.java
@@ -0,0 +1,786 @@
+/*
+ * 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 android.media;
+
+import android.Manifest;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.IRemoteControlDisplay;
+import android.media.MediaMetadataEditor;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * The RemoteController class is used to control media playback, display and update media metadata
+ * and playback status, published by applications using the {@link RemoteControlClient} class.
+ * <p>
+ * A RemoteController shall be registered through
+ * {@link AudioManager#registerRemoteController(RemoteController)} in order for the system to send
+ * media event updates to the listener set in
+ * {@link #setOnClientUpdateListener(OnClientUpdateListener)}. This listener is a subclass of
+ * the {@link OnClientUpdateListener} abstract class. Override its methods to receive the
+ * information published by the active {@link RemoteControlClient} instances.
+ * By default an {@link OnClientUpdateListener} implementation will not receive bitmaps for album
+ * art. Use {@link #setArtworkConfiguration(int, int)} to receive images as well.
+ * <p>
+ * Registration requires the {@link Manifest.permission#MEDIA_CONTENT_CONTROL} permission.
+ */
+public final class RemoteController
+{
+    private final static int MAX_BITMAP_DIMENSION = 512;
+    private final static int TRANSPORT_UNKNOWN = 0;
+    private final static String TAG = "RemoteController";
+    private final static boolean DEBUG = false;
+    private final static Object mGenLock = new Object();
+    private final static Object mInfoLock = new Object();
+    private final RcDisplay mRcd;
+    private final Context mContext;
+    private final AudioManager mAudioManager;
+    private MetadataEditor mMetadataEditor;
+
+    /**
+     * Synchronized on mGenLock
+     */
+    private int mClientGenerationIdCurrent = 0;
+
+    /**
+     * Synchronized on mInfoLock
+     */
+    private boolean mIsRegistered = false;
+    private PendingIntent mClientPendingIntentCurrent;
+    private OnClientUpdateListener mOnClientUpdateListener;
+    private PlaybackInfo mLastPlaybackInfo;
+    private int mLastTransportControlFlags = TRANSPORT_UNKNOWN;
+    private int mArtworkWidth = -1;
+    private int mArtworkHeight = -1;
+
+    /**
+     * Class constructor.
+     * @param context non-null the {@link Context}, must be non-null
+     * @throws java.lang.IllegalArgumentException
+     */
+    public RemoteController(Context context) throws IllegalArgumentException {
+        this(context, null);
+    }
+
+    /**
+     * Class constructor.
+     * @param looper the {@link Looper} on which to run the event loop,
+     *     or null to use the current thread's looper.
+     * @param context the {@link Context}, must be non-null
+     * @throws java.lang.IllegalArgumentException
+     */
+    public RemoteController(Context context, Looper looper) throws IllegalArgumentException {
+        if (context == null) {
+            throw new IllegalArgumentException("Invalid null Context");
+        }
+        if (looper != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else {
+            Looper l = Looper.myLooper();
+            if (l != null) {
+                mEventHandler = new EventHandler(this, l);
+            } else {
+                throw new IllegalArgumentException("Calling thread not associated with a looper");
+            }
+        }
+        mContext = context;
+        mRcd = new RcDisplay();
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+
+    /**
+     * An abstract class definition for the callbacks to be invoked whenever media events, metadata
+     * and playback status are available.
+     */
+    public static abstract class OnClientUpdateListener {
+        /**
+         * The method called whenever all information previously received through the other
+         * methods of the listener, is no longer valid and is about to be refreshed.
+         * This is typically called whenever a new {@link RemoteControlClient} has been selected
+         * by the system to have its media information published.
+         * @param clearing true if there is no selected RemoteControlClient and no information
+         *     is available.
+         */
+        public void onClientChange(boolean clearing) { }
+
+        /**
+         * The method called whenever the playback state has changed.
+         * It is called when no information is known about the playback progress in the media and
+         * the playback speed.
+         * @param state one of the playback states authorized
+         *     in {@link RemoteControlClient#setPlaybackState(int)}.
+         */
+        public void onClientPlaybackStateUpdate(int state) { }
+        /**
+         * The method called whenever the playback state has changed, and playback position and
+         * speed are known.
+         * @param state one of the playback states authorized
+         *     in {@link RemoteControlClient#setPlaybackState(int)}.
+         * @param stateChangeTimeMs the system time at which the state change was reported,
+         *     expressed in ms.
+         * @param currentPosMs a positive value for the current media playback position expressed
+         *     in ms, a negative value if the position is temporarily unknown.
+         * @param speed  a value expressed as a ratio of 1x playback: 1.0f is normal playback,
+         *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
+         *    playing (e.g. when state is {@link RemoteControlClient#PLAYSTATE_ERROR}).
+         */
+        public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) { }
+        /**
+         * The method called whenever the transport control flags have changed.
+         * @param transportControlFlags one of the flags authorized
+         *     in {@link RemoteControlClient#setTransportControlFlags(int)}.
+         */
+        public void onClientTransportControlUpdate(int transportControlFlags) { }
+        /**
+         * The method called whenever new metadata is available.
+         * See the {@link MediaMetadataEditor#putLong(int, long)},
+         *  {@link MediaMetadataEditor#putString(int, String)},
+         *  {@link MediaMetadataEditor#putBitmap(int, Bitmap)}, and
+         *  {@link MediaMetadataEditor#putObject(int, Object)} methods for the various keys that
+         *  can be queried.
+         * @param metadataEditor the container of the new metadata.
+         */
+        public void onClientMetadataUpdate(MetadataEditor metadataEditor) { }
+    };
+
+    /**
+     * Sets the listener to be called whenever new client information is available.
+     * This method can only be called on a registered RemoteController.
+     * @param l the update listener to be called.
+     */
+    public void setOnClientUpdateListener(OnClientUpdateListener l) {
+        synchronized(mInfoLock) {
+            mOnClientUpdateListener = l;
+            if (!mIsRegistered) {
+                // since the object is not registered, it hasn't received any information from
+                // RemoteControlClients yet, so we can exit here.
+                return;
+            }
+            if (mLastPlaybackInfo != null) {
+                sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+                        mClientGenerationIdCurrent /*arg1*/, 0,
+                        mLastPlaybackInfo /*obj*/, 0 /*delay*/);
+            }
+            if (mLastTransportControlFlags != TRANSPORT_UNKNOWN) {
+                sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+                        mClientGenerationIdCurrent /*arg1*/, mLastTransportControlFlags /*arg2*/,
+                        null /*obj*/, 0 /*delay*/);
+            }
+            if (mMetadataEditor != null) {
+                sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                        mClientGenerationIdCurrent /*arg1*/, 0 /*arg2*/,
+                        mMetadataEditor /*obj*/, 0 /*delay*/);
+            }
+        }
+    }
+
+
+    /**
+     * Send a simulated key event for a media button to be received by the current client.
+     * To simulate a key press, you must first send a KeyEvent built with
+     * a {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
+     * action.
+     * <p>The key event will be sent to the registered receiver
+     * (see {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}) whose associated
+     * {@link RemoteControlClient}'s metadata and playback state is published (there may be
+     * none under some circumstances).
+     * @param keyEvent a {@link KeyEvent} instance whose key code is one of
+     *     {@link KeyEvent#KEYCODE_MUTE},
+     *     {@link KeyEvent#KEYCODE_HEADSETHOOK},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PLAY},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
+     *     {@link KeyEvent#KEYCODE_MEDIA_STOP},
+     *     {@link KeyEvent#KEYCODE_MEDIA_NEXT},
+     *     {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
+     *     {@link KeyEvent#KEYCODE_MEDIA_REWIND},
+     *     {@link KeyEvent#KEYCODE_MEDIA_RECORD},
+     *     {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
+     *     {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
+     *     {@link KeyEvent#KEYCODE_MEDIA_EJECT},
+     *     or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
+     */
+    public int sendMediaKeyEvent(KeyEvent keyEvent) {
+        if (!MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode())) {
+            Log.e(TAG, "Cannot use sendMediaKeyEvent() for a non-media key event");
+            return ERROR_BAD_VALUE;
+        }
+        final PendingIntent pi;
+        synchronized(mInfoLock) {
+            if (!mIsRegistered) {
+                Log.e(TAG, "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
+                return ERROR;
+            }
+            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 ERROR;
+            }
+        } else {
+            Log.i(TAG, "No-op when sending key click, no receiver right now");
+            return ERROR;
+        }
+        return SUCCESS;
+    }
+
+
+    // Error codes
+    /**
+     * Successful operation.
+     */
+    public  static final int SUCCESS            = 0;
+    /**
+     * Unspecified error.
+     */
+    public  static final int ERROR              = -1;
+    /**
+     * Operation failed due to bad parameter value.
+     */
+    public  static final int ERROR_BAD_VALUE    = -2;
+
+
+    /**
+     * Sets the new playback position.
+     * This method can only be called on a registered RemoteController.
+     * @param timeMs a 0 or positive value for the new playback position, expressed in ms.
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int seekTo(long timeMs) {
+        if (timeMs < 0) {
+            return ERROR_BAD_VALUE;
+        }
+        final int genId;
+        synchronized (mGenLock) {
+            genId = mClientGenerationIdCurrent;
+        }
+        mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
+        return SUCCESS;
+    }
+
+
+    /**
+     * @hide
+     * @param wantBitmap
+     * @param width
+     * @param height
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setArtworkConfiguration(boolean wantBitmap, int width, int height) {
+        synchronized (mInfoLock) {
+            if (wantBitmap) {
+                if ((width > 0) && (height > 0)) {
+                    if (width > MAX_BITMAP_DIMENSION) { width = MAX_BITMAP_DIMENSION; }
+                    if (height > MAX_BITMAP_DIMENSION) { height = MAX_BITMAP_DIMENSION; }
+                    mArtworkWidth = width;
+                    mArtworkHeight = height;
+                } else {
+                    Log.e(TAG, "Invalid dimensions");
+                    return ERROR_BAD_VALUE;
+                }
+            } else {
+                mArtworkWidth = -1;
+                mArtworkHeight = -1;
+            }
+            if (mIsRegistered) {
+                mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd,
+                        mArtworkWidth, mArtworkHeight);
+            } // else new values have been stored, and will be read by AudioManager with
+              //    RemoteController.getArtworkSize() when AudioManager.registerRemoteController()
+              //    is called.
+        }
+        return SUCCESS;
+    }
+
+    /**
+     * Set the maximum artwork image dimensions to be received in the metadata.
+     * No bitmaps will be received unless this has been specified.
+     * @param width the maximum width in pixels
+     * @param height  the maximum height in pixels
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setArtworkConfiguration(int width, int height) {
+        return setArtworkConfiguration(true, width, height);
+    }
+
+    /**
+     * Prevents this RemoteController from receiving artwork images.
+     * @return {@link #SUCCESS}, {@link #ERROR}
+     */
+    public int clearArtworkConfiguration() {
+        return setArtworkConfiguration(false, -1, -1);
+    }
+
+
+    /**
+     * Default playback position synchronization mode where the RemoteControlClient is not
+     * asked regularly for its playback position to see if it has drifted from the estimated
+     * position.
+     */
+    public static final int POSITION_SYNCHRONIZATION_NONE = 0;
+
+    /**
+     * The playback position synchronization mode where the RemoteControlClient instances which
+     * expose their playback position to the framework, will be regularly polled to check
+     * whether any drift has been noticed between their estimated position and the one they report.
+     * Note that this mode should only ever be used when needing to display very accurate playback
+     * position, as regularly polling a RemoteControlClient for its position may have an impact
+     * on battery life (if applicable) when this query will trigger network transactions in the
+     * case of remote playback.
+     */
+    public static final int POSITION_SYNCHRONIZATION_CHECK = 1;
+
+    /**
+     * Set the playback position synchronization mode.
+     * Must be called on a registered RemoteController.
+     * @param sync {@link #POSITION_SYNCHRONIZATION_NONE} or {@link #POSITION_SYNCHRONIZATION_CHECK}
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setSynchronizationMode(int sync) {
+        if ((sync != POSITION_SYNCHRONIZATION_NONE) || (sync != POSITION_SYNCHRONIZATION_CHECK)) {
+            Log.e(TAG, "Unknown synchronization mode");
+            return ERROR_BAD_VALUE;
+        }
+        if (!mIsRegistered) {
+            Log.e(TAG, "Cannot set synchronization mode on an unregistered RemoteController");
+            return ERROR;
+        }
+        mAudioManager.remoteControlDisplayWantsPlaybackPositionSync(mRcd,
+                POSITION_SYNCHRONIZATION_CHECK == sync);
+        return SUCCESS;
+    }
+
+
+    /**
+     * Creates a {@link MetadataEditor} for updating metadata values of the editable keys of
+     * the current {@link RemoteControlClient}.
+     * This method can only be called on a registered RemoteController.
+     * @return a new MetadataEditor instance.
+     */
+    public MetadataEditor editMetadata() {
+        MetadataEditor editor = new MetadataEditor();
+        editor.mEditorMetadata = new Bundle();
+        editor.mEditorArtwork = null;
+        editor.mMetadataChanged = true;
+        editor.mArtworkChanged = true;
+        editor.mEditableKeys = 0;
+        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.
+     */
+    public class MetadataEditor extends MediaMetadataEditor {
+        /**
+         * @hide
+         */
+        protected MetadataEditor() { }
+
+        /**
+         * @hide
+         */
+        protected MetadataEditor(Bundle metadata, long editableKeys) {
+            mEditorMetadata = metadata;
+            mEditableKeys = editableKeys;
+            mEditorArtwork = null;
+            mMetadataChanged = true;
+            mArtworkChanged = true;
+            mApplied = false;
+        }
+
+        private void cleanupBitmapFromBundle(int key) {
+            if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) == METADATA_TYPE_BITMAP) {
+                mEditorMetadata.remove(String.valueOf(key));
+            }
+        }
+
+        /**
+         * Applies all of the metadata changes that have been set since the MediaMetadataEditor
+         * instance was created with {@link RemoteController#editMetadata()}
+         * or since {@link #clear()} was called.
+         */
+        public synchronized void apply() {
+            // "applying" a metadata bundle in RemoteController is only for sending edited
+            // key values back to the RemoteControlClient, so here we only care about the only
+            // editable key we support: RATING_KEY_BY_USER
+            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");
+                }
+                // 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;
+            }
+        }
+
+    }
+
+
+    //==================================================
+    // Implementation of IRemoteControlDisplay interface
+    private class RcDisplay extends IRemoteControlDisplay.Stub {
+
+        public void setCurrentClientId(int genId, PendingIntent clientMediaIntent,
+                boolean clearing) {
+            boolean isNew = false;
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    mClientGenerationIdCurrent = genId;
+                    isNew = true;
+                }
+            }
+            if (clientMediaIntent != null) {
+                sendMsg(mEventHandler, MSG_NEW_PENDING_INTENT, SENDMSG_REPLACE,
+                        genId /*arg1*/, 0, clientMediaIntent /*obj*/, 0 /*delay*/);
+            }
+            if (isNew || clearing) {
+                sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+                        genId /*arg1*/, clearing ? 1 : 0, null /*obj*/, 0 /*delay*/);
+            }
+        }
+
+        public void setPlaybackState(int genId, int state,
+                long stateChangeTimeMs, long currentPosMs, float speed) {
+            if (DEBUG) {
+                Log.d(TAG, "> new playback state: genId="+genId
+                        + " state="+ state
+                        + " changeTime="+ stateChangeTimeMs
+                        + " pos=" + currentPosMs
+                        + "ms speed=" + speed);
+            }
+
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            final PlaybackInfo playbackInfo =
+                    new PlaybackInfo(state, stateChangeTimeMs, currentPosMs, speed);
+            sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+                    genId /*arg1*/, 0, playbackInfo /*obj*/, 0 /*delay*/);
+
+        }
+
+        public void setTransportControlInfo(int genId, int transportControlFlags,
+                int posCapabilities) {
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+                    genId /*arg1*/, transportControlFlags /*arg2*/,
+                    null /*obj*/, 0 /*delay*/);
+        }
+
+        public void setMetadata(int genId, Bundle metadata) {
+            if (DEBUG) { Log.e(TAG, "setMetadata("+genId+")"); }
+            if (metadata == null) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+
+        public void setArtwork(int genId, Bitmap artwork) {
+            if (DEBUG) { Log.v(TAG, "setArtwork("+genId+")"); }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            Bundle metadata = new Bundle(1);
+            metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), artwork);
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+
+        public void setAllMetadata(int genId, Bundle metadata, Bitmap artwork) {
+            if (DEBUG) { Log.e(TAG, "setAllMetadata("+genId+")"); }
+            if ((metadata == null) && (artwork == null)) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            if (metadata == null) {
+                metadata = new Bundle(1);
+            }
+            if (artwork != null) {
+                metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+                        artwork);
+            }
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+    }
+
+    //==================================================
+    // Event handling
+    private final EventHandler mEventHandler;
+    private final static int MSG_NEW_PENDING_INTENT = 0;
+    private final static int MSG_NEW_PLAYBACK_INFO =  1;
+    private final static int MSG_NEW_TRANSPORT_INFO = 2;
+    private final static int MSG_NEW_METADATA       = 3; // msg always has non-null obj parameter
+    private final static int MSG_CLIENT_CHANGE      = 4;
+
+    private class EventHandler extends Handler {
+
+        public EventHandler(RemoteController rc, Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_NEW_PENDING_INTENT:
+                    onNewPendingIntent(msg.arg1, (PendingIntent) msg.obj);
+                    break;
+                case MSG_NEW_PLAYBACK_INFO:
+                    onNewPlaybackInfo(msg.arg1, (PlaybackInfo) msg.obj);
+                    break;
+                case MSG_NEW_TRANSPORT_INFO:
+                    onNewTransportInfo(msg.arg1, msg.arg2);
+                    break;
+                case MSG_NEW_METADATA:
+                    onNewMetadata(msg.arg1, (Bundle)msg.obj);
+                    break;
+                case MSG_CLIENT_CHANGE:
+                    onClientChange(msg.arg1, msg.arg2 == 1);
+                    break;
+                default:
+                    Log.e(TAG, "unknown event " + msg.what);
+            }
+        }
+    }
+
+    /** 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. */
+    private static final int SENDMSG_NOOP = 1;
+    /** If the msg is already queued, queue this one and leave the old. */
+    private static final int SENDMSG_QUEUE = 2;
+
+    private static void sendMsg(Handler handler, int msg, int existingMsgPolicy,
+            int arg1, int arg2, Object obj, int delayMs) {
+        if (handler == null) {
+            Log.e(TAG, "null event handler, will not deliver message " + msg);
+            return;
+        }
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
+    }
+
+    private void onNewPendingIntent(int genId, PendingIntent pi) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        synchronized(mInfoLock) {
+            mClientPendingIntentCurrent = pi;
+        }
+    }
+
+    private void onNewPlaybackInfo(int genId, PlaybackInfo pi) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = this.mOnClientUpdateListener;
+            mLastPlaybackInfo = pi;
+        }
+        if (l != null) {
+            if (pi.mCurrentPosMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+                l.onClientPlaybackStateUpdate(pi.mState);
+            } else {
+                l.onClientPlaybackStateUpdate(pi.mState, pi.mStateChangeTimeMs, pi.mCurrentPosMs,
+                        pi.mSpeed);
+            }
+        }
+    }
+
+    private void onNewTransportInfo(int genId, int transportControlFlags) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            mLastTransportControlFlags = transportControlFlags;
+        }
+        if (l != null) {
+            l.onClientTransportControlUpdate(transportControlFlags);
+        }
+    }
+
+    /**
+     * @param genId
+     * @param metadata guaranteed to be always non-null
+     */
+    private void onNewMetadata(int genId, Bundle metadata) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        final MetadataEditor metadataEditor;
+        // prepare the received Bundle to be used inside a MetadataEditor
+        final long editableKeys = metadata.getLong(
+                String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK), 0);
+        if (editableKeys != 0) {
+            metadata.remove(String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK));
+        }
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            if ((mMetadataEditor != null) && (mMetadataEditor.mEditorMetadata != null)) {
+                if (mMetadataEditor.mEditorMetadata != metadata) {
+                    // existing metadata, merge existing and new
+                    mMetadataEditor.mEditorMetadata.putAll(metadata);
+                }
+                mMetadataEditor.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK,
+                        (Bitmap)metadata.getParcelable(
+                                String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK)));
+                mMetadataEditor.cleanupBitmapFromBundle(MediaMetadataEditor.BITMAP_KEY_ARTWORK);
+            } else {
+                mMetadataEditor = new MetadataEditor(metadata, editableKeys);
+            }
+            metadataEditor = mMetadataEditor;
+        }
+        if (l != null) {
+            l.onClientMetadataUpdate(metadataEditor);
+        }
+    }
+
+    private void onClientChange(int genId, boolean clearing) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+        }
+        if (l != null) {
+            l.onClientChange(clearing);
+        }
+    }
+
+
+    //==================================================
+    private static class PlaybackInfo {
+        int mState;
+        long mStateChangeTimeMs;
+        long mCurrentPosMs;
+        float mSpeed;
+
+        PlaybackInfo(int state, long stateChangeTimeMs, long currentPosMs, float speed) {
+            mState = state;
+            mStateChangeTimeMs = stateChangeTimeMs;
+            mCurrentPosMs = currentPosMs;
+            mSpeed = speed;
+        }
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to mark this instance as registered.
+     * @param registered
+     */
+    protected void setIsRegistered(boolean registered) {
+        synchronized (mInfoLock) {
+            mIsRegistered = registered;
+        }
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to access binder to be registered/unregistered inside MediaFocusControl
+     * @return
+     */
+    protected RcDisplay getRcDisplay() {
+        return mRcd;
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to read the current artwork dimension
+     * @return array containing width (index 0) and height (index 1) of currently set artwork size
+     */
+    protected int[] getArtworkSize() {
+        synchronized (mInfoLock) {
+            int[] size = { mArtworkWidth, mArtworkHeight };
+            return size;
+        }
+    }
+
+}
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
index b463d26..7afce1a 100644
--- a/media/java/android/media/RemoteDisplay.java
+++ b/media/java/android/media/RemoteDisplay.java
@@ -42,6 +42,8 @@
 
     private native int nativeListen(String iface);
     private native void nativeDispose(int ptr);
+    private native void nativePause(int ptr);
+    private native void nativeResume(int ptr);
 
     private RemoteDisplay(Listener listener, Handler handler) {
         mListener = listener;
@@ -87,6 +89,14 @@
         dispose(false);
     }
 
+    public void pause() {
+        nativePause(mPtr);
+    }
+
+    public void resume() {
+        nativeResume(mPtr);
+    }
+
     private void dispose(boolean finalized) {
         if (mPtr != 0) {
             if (mGuard != null) {
@@ -113,11 +123,11 @@
 
     // Called from native.
     private void notifyDisplayConnected(final Surface surface,
-            final int width, final int height, final int flags) {
+            final int width, final int height, final int flags, final int session) {
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                mListener.onDisplayConnected(surface, width, height, flags);
+                mListener.onDisplayConnected(surface, width, height, flags, session);
             }
         });
     }
@@ -146,7 +156,8 @@
      * Listener invoked when the remote display connection changes state.
      */
     public interface Listener {
-        void onDisplayConnected(Surface surface, int width, int height, int flags);
+        void onDisplayConnected(Surface surface,
+                int width, int height, int flags, int session);
         void onDisplayDisconnected();
         void onDisplayError(int error);
     }
diff --git a/media/java/android/media/ResourceBusyException.java b/media/java/android/media/ResourceBusyException.java
new file mode 100644
index 0000000..a5abe21
--- /dev/null
+++ b/media/java/android/media/ResourceBusyException.java
@@ -0,0 +1,27 @@
+/*
+ * 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 android.media;
+
+/**
+ * Exception thrown when an operation on a MediaDrm object is attempted
+ * and hardware resources are not available, due to being in use.
+ */
+public final class ResourceBusyException extends MediaDrmException {
+    public ResourceBusyException(String detailMessage) {
+        super(detailMessage);
+    }
+}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index ebbfad9..1283e9b 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -24,7 +24,6 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
-import android.provider.DrmStore;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.util.Log;
@@ -50,12 +49,6 @@
         MediaStore.Audio.Media.TITLE
     };
 
-    private static final String[] DRM_COLUMNS = new String[] {
-        DrmStore.Audio._ID,
-        DrmStore.Audio.DATA,
-        DrmStore.Audio.TITLE
-    };
-
     private final Context mContext;
     private final AudioManager mAudioManager;
     private final boolean mAllowRemote;
@@ -101,8 +94,8 @@
     }
 
     /**
-     * Returns a human-presentable title for ringtone. Looks in media and DRM
-     * content providers. If not in either, uses the filename
+     * Returns a human-presentable title for ringtone. Looks in media
+     * content provider. If not in either, uses the filename
      * 
      * @param context A context used for querying. 
      */
@@ -131,9 +124,7 @@
                 }
             } else {
                 try {
-                    if (DrmStore.AUTHORITY.equals(authority)) {
-                        cursor = res.query(uri, DRM_COLUMNS, null, null, null);
-                    } else if (MediaStore.AUTHORITY.equals(authority)) {
+                    if (MediaStore.AUTHORITY.equals(authority)) {
                         cursor = res.query(uri, MEDIA_COLUMNS, null, null, null);
                     }
                 } catch (SecurityException e) {
@@ -289,7 +280,7 @@
     private boolean playFallbackRingtone() {
         if (mAudioManager.getStreamVolume(mStreamType) != 0) {
             int ringtoneType = RingtoneManager.getDefaultType(mUri);
-            if (ringtoneType != -1 &&
+            if (ringtoneType == -1 ||
                     RingtoneManager.getActualDefaultRingtoneUri(mContext, ringtoneType) != null) {
                 // Default ringtone, try fallback ringtone.
                 try {
@@ -318,6 +309,8 @@
                 } catch (NotFoundException nfe) {
                     Log.e(TAG, "Fallback ringtone does not exist");
                 }
+            } else {
+                Log.w(TAG, "not playing fallback for " + mUri);
             }
         }
         return false;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 5e18bfa..8e4004b 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -27,7 +27,6 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
-import android.provider.DrmStore;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.System;
@@ -85,7 +84,6 @@
      * {@link #EXTRA_RINGTONE_SHOW_DEFAULT},
      * {@link #EXTRA_RINGTONE_SHOW_SILENT}, {@link #EXTRA_RINGTONE_TYPE},
      * {@link #EXTRA_RINGTONE_DEFAULT_URI}, {@link #EXTRA_RINGTONE_TITLE},
-     * {@link #EXTRA_RINGTONE_INCLUDE_DRM}.
      * <p>
      * Output: {@link #EXTRA_RINGTONE_PICKED_URI}.
      */
@@ -113,7 +111,9 @@
 
     /**
      * Given to the ringtone picker as a boolean. Whether to include DRM ringtones.
+     * @deprecated DRM ringtones are no longer supported
      */
+    @Deprecated
     public static final String EXTRA_RINGTONE_INCLUDE_DRM =
             "android.intent.extra.ringtone.INCLUDE_DRM";
     
@@ -183,12 +183,6 @@
         MediaStore.Audio.Media.TITLE_KEY
     };
 
-    private static final String[] DRM_COLUMNS = new String[] {
-        DrmStore.Audio._ID, DrmStore.Audio.TITLE,
-        "\"" + DrmStore.Audio.CONTENT_URI + "\"",
-        DrmStore.Audio.TITLE + " AS " + MediaStore.Audio.Media.TITLE_KEY
-    };
-
     private static final String[] MEDIA_COLUMNS = new String[] {
         MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
         "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"",
@@ -228,8 +222,6 @@
     
     private boolean mStopPreviousRingtone = true;
     private Ringtone mPreviousRingtone;
-
-    private boolean mIncludeDrm;
     
     /**
      * Constructs a RingtoneManager. This constructor is recommended as its
@@ -328,18 +320,26 @@
      * 
      * @return Whether DRM ringtones will be included.
      * @see #setIncludeDrm(boolean)
+     * Obsolete - always returns false
+     * @deprecated DRM ringtones are no longer supported
      */
+    @Deprecated
     public boolean getIncludeDrm() {
-        return mIncludeDrm;
+        return false;
     }
 
     /**
      * Sets whether to include DRM ringtones.
      * 
      * @param includeDrm Whether to include DRM ringtones.
+     * Obsolete - no longer has any effect
+     * @deprecated DRM ringtones are no longer supported
      */
+    @Deprecated
     public void setIncludeDrm(boolean includeDrm) {
-        mIncludeDrm = includeDrm;
+        if (includeDrm) {
+            Log.w(TAG, "setIncludeDrm no longer supported");
+        }
     }
 
     /**
@@ -363,10 +363,9 @@
         }
         
         final Cursor internalCursor = getInternalRingtones();
-        final Cursor drmCursor = mIncludeDrm ? getDrmRingtones() : null;
         final Cursor mediaCursor = getMediaRingtones();
              
-        return mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor },
+        return mCursor = new SortCursor(new Cursor[] { internalCursor, mediaCursor },
                 MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
     }
 
@@ -462,10 +461,6 @@
             uri = getValidRingtoneUriFromCursorAndClose(context, rm.getMediaRingtones());
         }
         
-        if (uri == null) {
-            uri = getValidRingtoneUriFromCursorAndClose(context, rm.getDrmRingtones());
-        }
-        
         return uri;
     }
     
@@ -487,16 +482,9 @@
     private Cursor getInternalRingtones() {
         return query(
                 MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS,
-                constructBooleanTrueWhereClause(mFilterColumns, mIncludeDrm),
+                constructBooleanTrueWhereClause(mFilterColumns),
                 null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
     }
-    
-    private Cursor getDrmRingtones() {
-        // DRM store does not have any columns to use for filtering 
-        return query(
-                DrmStore.Audio.CONTENT_URI, DRM_COLUMNS,
-                null, null, DrmStore.Audio.TITLE);
-    }
 
     private Cursor getMediaRingtones() {
          // Get the external media cursor. First check to see if it is mounted.
@@ -506,7 +494,7 @@
                     status.equals(Environment.MEDIA_MOUNTED_READ_ONLY))
                 ? query(
                     MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
-                    constructBooleanTrueWhereClause(mFilterColumns, mIncludeDrm), null,
+                    constructBooleanTrueWhereClause(mFilterColumns), null,
                     MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
                 : null;
     }
@@ -536,7 +524,7 @@
      * @param columns The columns that must be true.
      * @return The where clause.
      */
-    private static String constructBooleanTrueWhereClause(List<String> columns, boolean includeDrm) {
+    private static String constructBooleanTrueWhereClause(List<String> columns) {
         
         if (columns == null) return null;
         
@@ -554,15 +542,6 @@
 
         sb.append(")");
 
-        if (!includeDrm) {
-            // If not DRM files should be shown, the where clause
-            // will be something like "(is_notification=1) and is_drm=0"
-            sb.append(" and ");
-            sb.append(MediaStore.MediaColumns.IS_DRM);
-            sb.append("=0");
-        }
-
-
         return sb.toString();
     }
     
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 587af47..06af5de 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -16,19 +16,21 @@
 
 package android.media;
 
-import android.util.AndroidRuntimeException;
-import android.util.Log;
 import java.io.File;
 import java.io.FileDescriptor;
-import android.os.ParcelFileDescriptor;
+import java.io.IOException;
 import java.lang.ref.WeakReference;
+
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
-import java.io.IOException;
-
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+
 
 /**
  * The SoundPool class manages and plays audio resources for applications.
@@ -102,24 +104,8 @@
  * another level, a new SoundPool is created, sounds are loaded, and play
  * resumes.</p>
  */
-public class SoundPool
-{
-    static { System.loadLibrary("soundpool"); }
-
-    private final static String TAG = "SoundPool";
-    private final static boolean DEBUG = false;
-
-    private int mNativeContext; // accessed by native methods
-
-    private EventHandler mEventHandler;
-    private OnLoadCompleteListener mOnLoadCompleteListener;
-
-    private final Object mLock;
-
-    // SoundPool messages
-    //
-    // must match SoundPool.h
-    private static final int SAMPLE_LOADED = 1;
+public class SoundPool {
+    private final SoundPoolDelegate mImpl;
 
     /**
      * Constructor. Constructs a SoundPool object with the following
@@ -135,12 +121,11 @@
      * @return a SoundPool object, or null if creation failed
      */
     public SoundPool(int maxStreams, int streamType, int srcQuality) {
-
-        // do native setup
-        if (native_setup(new WeakReference(this), maxStreams, streamType, srcQuality) != 0) {
-            throw new RuntimeException("Native setup failed");
+        if (SystemProperties.getBoolean("config.disable_media", false)) {
+            mImpl = new SoundPoolStub();
+        } else {
+            mImpl = new SoundPoolImpl(this, maxStreams, streamType, srcQuality);
         }
-        mLock = new Object();
     }
 
     /**
@@ -151,25 +136,8 @@
      *                 a value of 1 for future compatibility.
      * @return a sound ID. This value can be used to play or unload the sound.
      */
-    public int load(String path, int priority)
-    {
-        // pass network streams to player
-        if (path.startsWith("http:"))
-            return _load(path, priority);
-
-        // try local path
-        int id = 0;
-        try {
-            File f = new File(path);
-            ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
-            if (fd != null) {
-                id = _load(fd.getFileDescriptor(), 0, f.length(), priority);
-                fd.close();
-            }
-        } catch (java.io.IOException e) {
-            Log.e(TAG, "error loading " + path);
-        }
-        return id;
+    public int load(String path, int priority) {
+        return mImpl.load(path, priority);
     }
 
     /**
@@ -188,17 +156,7 @@
      * @return a sound ID. This value can be used to play or unload the sound.
      */
     public int load(Context context, int resId, int priority) {
-        AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
-        int id = 0;
-        if (afd != null) {
-            id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
-            try {
-                afd.close();
-            } catch (java.io.IOException ex) {
-                //Log.d(TAG, "close failed:", ex);
-            }
-        }
-        return id;
+        return mImpl.load(context, resId, priority);
     }
 
     /**
@@ -210,15 +168,7 @@
      * @return a sound ID. This value can be used to play or unload the sound.
      */
     public int load(AssetFileDescriptor afd, int priority) {
-        if (afd != null) {
-            long len = afd.getLength();
-            if (len < 0) {
-                throw new AndroidRuntimeException("no length for fd");
-            }
-            return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority);
-        } else {
-            return 0;
-        }
+        return mImpl.load(afd, priority);
     }
 
     /**
@@ -236,13 +186,9 @@
      * @return a sound ID. This value can be used to play or unload the sound.
      */
     public int load(FileDescriptor fd, long offset, long length, int priority) {
-        return _load(fd, offset, length, priority);
+        return mImpl.load(fd, offset, length, priority);
     }
 
-    private native final int _load(String uri, int priority);
-
-    private native final int _load(FileDescriptor fd, long offset, long length, int priority);
-
     /**
      * Unload a sound from a sound ID.
      *
@@ -253,7 +199,9 @@
      * @param soundID a soundID returned by the load() function
      * @return true if just unloaded, false if previously unloaded
      */
-    public native final boolean unload(int soundID);
+    public final boolean unload(int soundID) {
+        return mImpl.unload(soundID);
+    }
 
     /**
      * Play a sound from a sound ID.
@@ -279,8 +227,11 @@
      * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0)
      * @return non-zero streamID if successful, zero if failed
      */
-    public native final int play(int soundID, float leftVolume, float rightVolume,
-            int priority, int loop, float rate);
+    public final int play(int soundID, float leftVolume, float rightVolume,
+            int priority, int loop, float rate) {
+        return mImpl.play(
+            soundID, leftVolume, rightVolume, priority, loop, rate);
+    }
 
     /**
      * Pause a playback stream.
@@ -293,7 +244,9 @@
      *
      * @param streamID a streamID returned by the play() function
      */
-    public native final void pause(int streamID);
+    public final void pause(int streamID) {
+        mImpl.pause(streamID);
+    }
 
     /**
      * Resume a playback stream.
@@ -305,7 +258,9 @@
      *
      * @param streamID a streamID returned by the play() function
      */
-    public native final void resume(int streamID);
+    public final void resume(int streamID) {
+        mImpl.resume(streamID);
+    }
 
     /**
      * Pause all active streams.
@@ -315,7 +270,9 @@
      * are playing. It also sets a flag so that any streams that
      * are playing can be resumed by calling autoResume().
      */
-    public native final void autoPause();
+    public final void autoPause() {
+        mImpl.autoPause();
+    }
 
     /**
      * Resume all previously active streams.
@@ -323,7 +280,9 @@
      * Automatically resumes all streams that were paused in previous
      * calls to autoPause().
      */
-    public native final void autoResume();
+    public final void autoResume() {
+        mImpl.autoResume();
+    }
 
     /**
      * Stop a playback stream.
@@ -336,7 +295,9 @@
      *
      * @param streamID a streamID returned by the play() function
      */
-    public native final void stop(int streamID);
+    public final void stop(int streamID) {
+        mImpl.stop(streamID);
+    }
 
     /**
      * Set stream volume.
@@ -350,8 +311,10 @@
      * @param leftVolume left volume value (range = 0.0 to 1.0)
      * @param rightVolume right volume value (range = 0.0 to 1.0)
      */
-    public native final void setVolume(int streamID,
-            float leftVolume, float rightVolume);
+    public final void setVolume(int streamID,
+            float leftVolume, float rightVolume) {
+        mImpl.setVolume(streamID, leftVolume, rightVolume);
+    }
 
     /**
      * Similar, except set volume of all channels to same value.
@@ -371,7 +334,9 @@
      *
      * @param streamID a streamID returned by the play() function
      */
-    public native final void setPriority(int streamID, int priority);
+    public final void setPriority(int streamID, int priority) {
+        mImpl.setPriority(streamID, priority);
+    }
 
     /**
      * Set loop mode.
@@ -384,7 +349,9 @@
      * @param streamID a streamID returned by the play() function
      * @param loop loop mode (0 = no loop, -1 = loop forever)
      */
-    public native final void setLoop(int streamID, int loop);
+    public final void setLoop(int streamID, int loop) {
+        mImpl.setLoop(streamID, loop);
+    }
 
     /**
      * Change playback rate.
@@ -398,19 +365,16 @@
      * @param streamID a streamID returned by the play() function
      * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0)
      */
-    public native final void setRate(int streamID, float rate);
+    public final void setRate(int streamID, float rate) {
+        mImpl.setRate(streamID, rate);
+    }
 
-    /**
-     * Interface definition for a callback to be invoked when all the
-     * sounds are loaded.
-     */
-    public interface OnLoadCompleteListener
-    {
+    public interface OnLoadCompleteListener {
         /**
          * Called when a sound has completed loading.
          *
          * @param soundPool SoundPool object from the load() method
-         * @param soundPool the sample ID of the sound loaded.
+         * @param sampleId the sample ID of the sound loaded.
          * @param status the status of the load operation (0 = success)
          */
         public void onLoadComplete(SoundPool soundPool, int sampleId, int status);
@@ -419,64 +383,8 @@
     /**
      * Sets the callback hook for the OnLoadCompleteListener.
      */
-    public void setOnLoadCompleteListener(OnLoadCompleteListener listener)
-    {
-        synchronized(mLock) {
-            if (listener != null) {
-                // setup message handler
-                Looper looper;
-                if ((looper = Looper.myLooper()) != null) {
-                    mEventHandler = new EventHandler(this, looper);
-                } else if ((looper = Looper.getMainLooper()) != null) {
-                    mEventHandler = new EventHandler(this, looper);
-                } else {
-                    mEventHandler = null;
-                }
-            } else {
-                mEventHandler = null;
-            }
-            mOnLoadCompleteListener = listener;
-        }
-    }
-
-    private class EventHandler extends Handler
-    {
-        private SoundPool mSoundPool;
-
-        public EventHandler(SoundPool soundPool, Looper looper) {
-            super(looper);
-            mSoundPool = soundPool;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-            case SAMPLE_LOADED:
-                if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
-                synchronized(mLock) {
-                    if (mOnLoadCompleteListener != null) {
-                        mOnLoadCompleteListener.onLoadComplete(mSoundPool, msg.arg1, msg.arg2);
-                    }
-                }
-                break;
-            default:
-                Log.e(TAG, "Unknown message type " + msg.what);
-                return;
-            }
-        }
-    }
-
-    // post event from native code to message handler
-    private static void postEventFromNative(Object weakRef, int msg, int arg1, int arg2, Object obj)
-    {
-        SoundPool soundPool = (SoundPool)((WeakReference)weakRef).get();
-        if (soundPool == null)
-            return;
-
-        if (soundPool.mEventHandler != null) {
-            Message m = soundPool.mEventHandler.obtainMessage(msg, arg1, arg2, obj);
-            soundPool.mEventHandler.sendMessage(m);
-        }
+    public void setOnLoadCompleteListener(OnLoadCompleteListener listener) {
+        mImpl.setOnLoadCompleteListener(listener);
     }
 
     /**
@@ -486,9 +394,286 @@
      * object. The SoundPool can no longer be used and the reference
      * should be set to null.
      */
-    public native final void release();
+    public final void release() {
+        mImpl.release();
+    }
 
-    private native final int native_setup(Object weakRef, int maxStreams, int streamType, int srcQuality);
+    /**
+     * Interface for SoundPool implementations.
+     * SoundPool is statically referenced and unconditionally called from all
+     * over the framework, so we can't simply omit the class or make it throw
+     * runtime exceptions, as doing so would break the framework. Instead we
+     * now select either a real or no-op impl object based on whether media is
+     * enabled.
+     *
+     * @hide
+     */
+    /* package */ interface SoundPoolDelegate {
+        public int load(String path, int priority);
+        public int load(Context context, int resId, int priority);
+        public int load(AssetFileDescriptor afd, int priority);
+        public int load(
+                FileDescriptor fd, long offset, long length, int priority);
+        public boolean unload(int soundID);
+        public int play(
+                int soundID, float leftVolume, float rightVolume,
+                int priority, int loop, float rate);
+        public void pause(int streamID);
+        public void resume(int streamID);
+        public void autoPause();
+        public void autoResume();
+        public void stop(int streamID);
+        public void setVolume(int streamID, float leftVolume, float rightVolume);
+        public void setVolume(int streamID, float volume);
+        public void setPriority(int streamID, int priority);
+        public void setLoop(int streamID, int loop);
+        public void setRate(int streamID, float rate);
+        public void setOnLoadCompleteListener(OnLoadCompleteListener listener);
+        public void release();
+    }
 
-    protected void finalize() { release(); }
+
+    /**
+     * Real implementation of the delegate interface. This was formerly the
+     * body of SoundPool itself.
+     */
+    /* package */ static class SoundPoolImpl implements SoundPoolDelegate {
+        static { System.loadLibrary("soundpool"); }
+
+        private final static String TAG = "SoundPool";
+        private final static boolean DEBUG = false;
+
+        private int mNativeContext; // accessed by native methods
+
+        private EventHandler mEventHandler;
+        private SoundPool.OnLoadCompleteListener mOnLoadCompleteListener;
+        private SoundPool mProxy;
+
+        private final Object mLock;
+
+        // SoundPool messages
+        //
+        // must match SoundPool.h
+        private static final int SAMPLE_LOADED = 1;
+
+        public SoundPoolImpl(SoundPool proxy, int maxStreams, int streamType, int srcQuality) {
+
+            // do native setup
+            if (native_setup(new WeakReference(this), maxStreams, streamType, srcQuality) != 0) {
+                throw new RuntimeException("Native setup failed");
+            }
+            mLock = new Object();
+            mProxy = proxy;
+        }
+
+        public int load(String path, int priority)
+        {
+            // pass network streams to player
+            if (path.startsWith("http:"))
+                return _load(path, priority);
+
+            // try local path
+            int id = 0;
+            try {
+                File f = new File(path);
+                ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
+                if (fd != null) {
+                    id = _load(fd.getFileDescriptor(), 0, f.length(), priority);
+                    fd.close();
+                }
+            } catch (java.io.IOException e) {
+                Log.e(TAG, "error loading " + path);
+            }
+            return id;
+        }
+
+        public int load(Context context, int resId, int priority) {
+            AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
+            int id = 0;
+            if (afd != null) {
+                id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
+                try {
+                    afd.close();
+                } catch (java.io.IOException ex) {
+                    //Log.d(TAG, "close failed:", ex);
+                }
+            }
+            return id;
+        }
+
+        public int load(AssetFileDescriptor afd, int priority) {
+            if (afd != null) {
+                long len = afd.getLength();
+                if (len < 0) {
+                    throw new AndroidRuntimeException("no length for fd");
+                }
+                return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority);
+            } else {
+                return 0;
+            }
+        }
+
+        public int load(FileDescriptor fd, long offset, long length, int priority) {
+            return _load(fd, offset, length, priority);
+        }
+
+        private native final int _load(String uri, int priority);
+
+        private native final int _load(FileDescriptor fd, long offset, long length, int priority);
+
+        public native final boolean unload(int soundID);
+
+        public native final int play(int soundID, float leftVolume, float rightVolume,
+                int priority, int loop, float rate);
+
+        public native final void pause(int streamID);
+
+        public native final void resume(int streamID);
+
+        public native final void autoPause();
+
+        public native final void autoResume();
+
+        public native final void stop(int streamID);
+
+        public native final void setVolume(int streamID,
+                float leftVolume, float rightVolume);
+
+        public void setVolume(int streamID, float volume) {
+            setVolume(streamID, volume, volume);
+        }
+
+        public native final void setPriority(int streamID, int priority);
+
+        public native final void setLoop(int streamID, int loop);
+
+        public native final void setRate(int streamID, float rate);
+
+        public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener)
+        {
+            synchronized(mLock) {
+                if (listener != null) {
+                    // setup message handler
+                    Looper looper;
+                    if ((looper = Looper.myLooper()) != null) {
+                        mEventHandler = new EventHandler(mProxy, looper);
+                    } else if ((looper = Looper.getMainLooper()) != null) {
+                        mEventHandler = new EventHandler(mProxy, looper);
+                    } else {
+                        mEventHandler = null;
+                    }
+                } else {
+                    mEventHandler = null;
+                }
+                mOnLoadCompleteListener = listener;
+            }
+        }
+
+        private class EventHandler extends Handler
+        {
+            private SoundPool mSoundPool;
+
+            public EventHandler(SoundPool soundPool, Looper looper) {
+                super(looper);
+                mSoundPool = soundPool;
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch(msg.what) {
+                case SAMPLE_LOADED:
+                    if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
+                    synchronized(mLock) {
+                        if (mOnLoadCompleteListener != null) {
+                            mOnLoadCompleteListener.onLoadComplete(mSoundPool, msg.arg1, msg.arg2);
+                        }
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Unknown message type " + msg.what);
+                    return;
+                }
+            }
+        }
+
+        // post event from native code to message handler
+        private static void postEventFromNative(Object weakRef, int msg, int arg1, int arg2, Object obj)
+        {
+            SoundPoolImpl soundPoolImpl = (SoundPoolImpl)((WeakReference)weakRef).get();
+            if (soundPoolImpl == null)
+                return;
+
+            if (soundPoolImpl.mEventHandler != null) {
+                Message m = soundPoolImpl.mEventHandler.obtainMessage(msg, arg1, arg2, obj);
+                soundPoolImpl.mEventHandler.sendMessage(m);
+            }
+        }
+
+        public native final void release();
+
+        private native final int native_setup(Object weakRef, int maxStreams, int streamType, int srcQuality);
+
+        protected void finalize() { release(); }
+    }
+
+    /**
+     * No-op implementation of SoundPool.
+     * Used when media is disabled by the system.
+     * @hide
+     */
+    /* package */ static class SoundPoolStub implements SoundPoolDelegate {
+        public SoundPoolStub() { }
+
+        public int load(String path, int priority) {
+            return 0;
+        }
+
+        public int load(Context context, int resId, int priority) {
+            return 0;
+        }
+
+        public int load(AssetFileDescriptor afd, int priority) {
+            return 0;
+        }
+
+        public int load(FileDescriptor fd, long offset, long length, int priority) {
+            return 0;
+        }
+
+        public final boolean unload(int soundID) {
+            return true;
+        }
+
+        public final int play(int soundID, float leftVolume, float rightVolume,
+                int priority, int loop, float rate) {
+            return 0;
+        }
+
+        public final void pause(int streamID) { }
+
+        public final void resume(int streamID) { }
+
+        public final void autoPause() { }
+
+        public final void autoResume() { }
+
+        public final void stop(int streamID) { }
+
+        public final void setVolume(int streamID,
+                float leftVolume, float rightVolume) { }
+
+        public void setVolume(int streamID, float volume) {
+        }
+
+        public final void setPriority(int streamID, int priority) { }
+
+        public final void setLoop(int streamID, int loop) { }
+
+        public final void setRate(int streamID, float rate) { }
+
+        public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener) {
+        }
+
+        public final void release() { }
+    }
 }
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
new file mode 100644
index 0000000..13205bc
--- /dev/null
+++ b/media/java/android/media/SubtitleController.java
@@ -0,0 +1,492 @@
+/*
+ * 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 android.media;
+
+import java.util.Locale;
+import java.util.Vector;
+
+import android.content.Context;
+import android.media.SubtitleTrack.RenderingWidget;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.view.accessibility.CaptioningManager;
+
+/**
+ * The subtitle controller provides the architecture to display subtitles for a
+ * media source.  It allows specifying which tracks to display, on which anchor
+ * to display them, and also allows adding external, out-of-band subtitle tracks.
+ *
+ * @hide
+ */
+public class SubtitleController {
+    private MediaTimeProvider mTimeProvider;
+    private Vector<Renderer> mRenderers;
+    private Vector<SubtitleTrack> mTracks;
+    private SubtitleTrack mSelectedTrack;
+    private boolean mShowing;
+    private CaptioningManager mCaptioningManager;
+    private Handler mHandler;
+
+    private static final int WHAT_SHOW = 1;
+    private static final int WHAT_HIDE = 2;
+    private static final int WHAT_SELECT_TRACK = 3;
+    private static final int WHAT_SELECT_DEFAULT_TRACK = 4;
+
+    private final Handler.Callback mCallback = new Handler.Callback() {
+        @Override
+        public boolean handleMessage(Message msg) {
+            switch (msg.what) {
+            case WHAT_SHOW:
+                doShow();
+                return true;
+            case WHAT_HIDE:
+                doHide();
+                return true;
+            case WHAT_SELECT_TRACK:
+                doSelectTrack((SubtitleTrack)msg.obj);
+                return true;
+            case WHAT_SELECT_DEFAULT_TRACK:
+                doSelectDefaultTrack();
+                return true;
+            default:
+                return false;
+            }
+        }
+    };
+
+    private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
+        new CaptioningManager.CaptioningChangeListener() {
+            /** @hide */
+            @Override
+            public void onEnabledChanged(boolean enabled) {
+                selectDefaultTrack();
+            }
+
+            /** @hide */
+            @Override
+            public void onLocaleChanged(Locale locale) {
+                selectDefaultTrack();
+            }
+        };
+
+    /**
+     * Creates a subtitle controller for a media playback object that implements
+     * the MediaTimeProvider interface.
+     *
+     * @param timeProvider
+     */
+    public SubtitleController(
+            Context context,
+            MediaTimeProvider timeProvider,
+            Listener listener) {
+        mTimeProvider = timeProvider;
+        mListener = listener;
+
+        mRenderers = new Vector<Renderer>();
+        mShowing = false;
+        mTracks = new Vector<SubtitleTrack>();
+        mCaptioningManager =
+            (CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        mCaptioningManager.removeCaptioningChangeListener(
+                mCaptioningChangeListener);
+        super.finalize();
+    }
+
+    /**
+     * @return the available subtitle tracks for this media. These include
+     * the tracks found by {@link MediaPlayer} as well as any tracks added
+     * manually via {@link #addTrack}.
+     */
+    public SubtitleTrack[] getTracks() {
+        synchronized(mTracks) {
+            SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
+            mTracks.toArray(tracks);
+            return tracks;
+        }
+    }
+
+    /**
+     * @return the currently selected subtitle track
+     */
+    public SubtitleTrack getSelectedTrack() {
+        return mSelectedTrack;
+    }
+
+    private RenderingWidget getRenderingWidget() {
+        if (mSelectedTrack == null) {
+            return null;
+        }
+        return mSelectedTrack.getRenderingWidget();
+    }
+
+    /**
+     * Selects a subtitle track.  As a result, this track will receive
+     * in-band data from the {@link MediaPlayer}.  However, this does
+     * not change the subtitle visibility.
+     *
+     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+     *
+     * @param track The subtitle track to select.  This must be one of the
+     *              tracks in {@link #getTracks}.
+     * @return true if the track was successfully selected.
+     */
+    public boolean selectTrack(SubtitleTrack track) {
+        if (track != null && !mTracks.contains(track)) {
+            return false;
+        }
+
+        processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_TRACK, track));
+        return true;
+    }
+
+    private void doSelectTrack(SubtitleTrack track) {
+        mTrackIsExplicit = true;
+        if (mSelectedTrack == track) {
+            return;
+        }
+
+        if (mSelectedTrack != null) {
+            mSelectedTrack.hide();
+            mSelectedTrack.setTimeProvider(null);
+        }
+
+        mSelectedTrack = track;
+        if (mAnchor != null) {
+            mAnchor.setSubtitleWidget(getRenderingWidget());
+        }
+
+        if (mSelectedTrack != null) {
+            mSelectedTrack.setTimeProvider(mTimeProvider);
+            mSelectedTrack.show();
+        }
+
+        if (mListener != null) {
+            mListener.onSubtitleTrackSelected(track);
+        }
+    }
+
+    /**
+     * @return the default subtitle track based on system preferences, or null,
+     * if no such track exists in this manager.
+     *
+     * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
+     *
+     * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
+     * consider all tracks, but prefer non-FORCED ones.
+     * 2. If user selected "Default" caption language:
+     *   a. If there is a considered track with DEFAULT=yes, returns that track
+     *      (favor the first one in the current language if there are more than
+     *      one default tracks, or the first in general if none of them are in
+     *      the current language).
+     *   b. Otherwise, if there is a track with AUTOSELECT=yes in the current
+     *      language, return that one.
+     *   c. If there are no default tracks, and no autoselectable tracks in the
+     *      current language, return null.
+     * 3. If there is a track with the caption language, select that one.  Prefer
+     * the one with AUTOSELECT=no.
+     *
+     * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
+     * and FORCED=no.
+     */
+    public SubtitleTrack getDefaultTrack() {
+        SubtitleTrack bestTrack = null;
+        int bestScore = -1;
+
+        Locale selectedLocale = mCaptioningManager.getLocale();
+        Locale locale = selectedLocale;
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+        boolean selectForced = !mCaptioningManager.isEnabled();
+
+        synchronized(mTracks) {
+            for (SubtitleTrack track: mTracks) {
+                MediaFormat format = track.getFormat();
+                String language = format.getString(MediaFormat.KEY_LANGUAGE);
+                boolean forced =
+                    format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
+                boolean autoselect =
+                    format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
+                boolean is_default =
+                    format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
+
+                boolean languageMatches =
+                    (locale == null ||
+                    locale.getLanguage().equals("") ||
+                    locale.getISO3Language().equals(language) ||
+                    locale.getLanguage().equals(language));
+                // is_default is meaningless unless caption language is 'default'
+                int score = (forced ? 0 : 8) +
+                    (((selectedLocale == null) && is_default) ? 4 : 0) +
+                    (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
+
+                if (selectForced && !forced) {
+                    continue;
+                }
+
+                // we treat null locale/language as matching any language
+                if ((selectedLocale == null && is_default) ||
+                    (languageMatches &&
+                     (autoselect || forced || selectedLocale != null))) {
+                    if (score > bestScore) {
+                        bestScore = score;
+                        bestTrack = track;
+                    }
+                }
+            }
+        }
+        return bestTrack;
+    }
+
+    private boolean mTrackIsExplicit = false;
+    private boolean mVisibilityIsExplicit = false;
+
+    /** @hide - should be called from anchor thread */
+    public void selectDefaultTrack() {
+        processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_DEFAULT_TRACK));
+    }
+
+    private void doSelectDefaultTrack() {
+        if (mTrackIsExplicit) {
+            // If track selection is explicit, but visibility
+            // is not, it falls back to the captioning setting
+            if (!mVisibilityIsExplicit) {
+                if (mCaptioningManager.isEnabled() ||
+                    (mSelectedTrack != null &&
+                     mSelectedTrack.getFormat().getInteger(
+                            MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
+                    show();
+                } else {
+                    hide();
+                }
+                mVisibilityIsExplicit = false;
+            }
+            return;
+        }
+
+        // We can have a default (forced) track even if captioning
+        // is not enabled.  This is handled by getDefaultTrack().
+        // Show this track unless subtitles were explicitly hidden.
+        SubtitleTrack track = getDefaultTrack();
+        if (track != null) {
+            selectTrack(track);
+            mTrackIsExplicit = false;
+            if (!mVisibilityIsExplicit) {
+                show();
+                mVisibilityIsExplicit = false;
+            }
+        }
+    }
+
+    /** @hide - must be called from anchor thread */
+    public void reset() {
+        checkAnchorLooper();
+        hide();
+        selectTrack(null);
+        mTracks.clear();
+        mTrackIsExplicit = false;
+        mVisibilityIsExplicit = false;
+        mCaptioningManager.removeCaptioningChangeListener(
+                mCaptioningChangeListener);
+    }
+
+    /**
+     * Adds a new, external subtitle track to the manager.
+     *
+     * @param format the format of the track that will include at least
+     *               the MIME type {@link MediaFormat@KEY_MIME}.
+     * @return the created {@link SubtitleTrack} object
+     */
+    public SubtitleTrack addTrack(MediaFormat format) {
+        synchronized(mRenderers) {
+            for (Renderer renderer: mRenderers) {
+                if (renderer.supports(format)) {
+                    SubtitleTrack track = renderer.createTrack(format);
+                    if (track != null) {
+                        synchronized(mTracks) {
+                            if (mTracks.size() == 0) {
+                                mCaptioningManager.addCaptioningChangeListener(
+                                        mCaptioningChangeListener);
+                            }
+                            mTracks.add(track);
+                        }
+                        return track;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Show the selected (or default) subtitle track.
+     *
+     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+     */
+    public void show() {
+        processOnAnchor(mHandler.obtainMessage(WHAT_SHOW));
+    }
+
+    private void doShow() {
+        mShowing = true;
+        mVisibilityIsExplicit = true;
+        if (mSelectedTrack != null) {
+            mSelectedTrack.show();
+        }
+    }
+
+    /**
+     * Hide the selected (or default) subtitle track.
+     *
+     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+     */
+    public void hide() {
+        processOnAnchor(mHandler.obtainMessage(WHAT_HIDE));
+    }
+
+    private void doHide() {
+        mVisibilityIsExplicit = true;
+        if (mSelectedTrack != null) {
+            mSelectedTrack.hide();
+        }
+        mShowing = false;
+    }
+
+    /**
+     * Interface for supporting a single or multiple subtitle types in {@link
+     * MediaPlayer}.
+     */
+    public abstract static class Renderer {
+        /**
+         * Called by {@link MediaPlayer}'s {@link SubtitleController} when a new
+         * subtitle track is detected, to see if it should use this object to
+         * parse and display this subtitle track.
+         *
+         * @param format the format of the track that will include at least
+         *               the MIME type {@link MediaFormat@KEY_MIME}.
+         *
+         * @return true if and only if the track format is supported by this
+         * renderer
+         */
+        public abstract boolean supports(MediaFormat format);
+
+        /**
+         * Called by {@link MediaPlayer}'s {@link SubtitleController} for each
+         * subtitle track that was detected and is supported by this object to
+         * create a {@link SubtitleTrack} object.  This object will be created
+         * for each track that was found.  If the track is selected for display,
+         * this object will be used to parse and display the track data.
+         *
+         * @param format the format of the track that will include at least
+         *               the MIME type {@link MediaFormat@KEY_MIME}.
+         * @return a {@link SubtitleTrack} object that will be used to parse
+         * and render the subtitle track.
+         */
+        public abstract SubtitleTrack createTrack(MediaFormat format);
+    }
+
+    /**
+     * Add support for a subtitle format in {@link MediaPlayer}.
+     *
+     * @param renderer a {@link SubtitleController.Renderer} object that adds
+     *                 support for a subtitle format.
+     */
+    public void registerRenderer(Renderer renderer) {
+        synchronized(mRenderers) {
+            // TODO how to get available renderers in the system
+            if (!mRenderers.contains(renderer)) {
+                // TODO should added renderers override existing ones (to allow replacing?)
+                mRenderers.add(renderer);
+            }
+        }
+    }
+
+    /**
+     * Subtitle anchor, an object that is able to display a subtitle renderer,
+     * e.g. a VideoView.
+     */
+    public interface Anchor {
+        /**
+         * Anchor should use the supplied subtitle rendering widget, or
+         * none if it is null.
+         * @hide
+         */
+        public void setSubtitleWidget(RenderingWidget subtitleWidget);
+
+        /**
+         * Anchors provide the looper on which all track visibility changes
+         * (track.show/hide, setSubtitleWidget) will take place.
+         * @hide
+         */
+        public Looper getSubtitleLooper();
+    }
+
+    private Anchor mAnchor;
+
+    /**
+     *  @hide - called from anchor's looper (if any, both when unsetting and
+     *  setting)
+     */
+    public void setAnchor(Anchor anchor) {
+        if (mAnchor == anchor) {
+            return;
+        }
+
+        if (mAnchor != null) {
+            checkAnchorLooper();
+            mAnchor.setSubtitleWidget(null);
+        }
+        mAnchor = anchor;
+        mHandler = null;
+        if (mAnchor != null) {
+            mHandler = new Handler(mAnchor.getSubtitleLooper(), mCallback);
+            checkAnchorLooper();
+            mAnchor.setSubtitleWidget(getRenderingWidget());
+        }
+    }
+
+    private void checkAnchorLooper() {
+        assert mHandler != null : "Should have a looper already";
+        assert Looper.myLooper() == mHandler.getLooper() : "Must be called from the anchor's looper";
+    }
+
+    private void processOnAnchor(Message m) {
+        assert mHandler != null : "Should have a looper already";
+        if (Looper.myLooper() == mHandler.getLooper()) {
+            mHandler.dispatchMessage(m);
+        } else {
+            mHandler.sendMessage(m);
+        }
+    }
+
+    public interface Listener {
+        /**
+         * Called when a subtitle track has been selected.
+         *
+         * @param track selected subtitle track or null
+         * @hide
+         */
+        public void onSubtitleTrackSelected(SubtitleTrack track);
+    }
+
+    private Listener mListener;
+}
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
new file mode 100644
index 0000000..f552e82
--- /dev/null
+++ b/media/java/android/media/SubtitleData.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.os.Parcel;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ * Class to hold the subtitle track's data, including:
+ * <ul>
+ * <li> Track index</li>
+ * <li> Start time (in microseconds) of the data</li>
+ * <li> Duration (in microseconds) of the data</li>
+ * <li> A byte-array of the data</li>
+ * </ul>
+ *
+ * <p> To receive the subtitle data, applications need to do the following:
+ *
+ * <ul>
+ * <li> Select a track of type MEDIA_TRACK_TYPE_SUBTITLE with {@link MediaPlayer.selectTrack(int)</li>
+ * <li> Implement the {@link MediaPlayer.OnSubtitleDataListener} interface</li>
+ * <li> Register the {@link MediaPlayer.OnSubtitleDataListener} callback on a MediaPlayer object</li>
+ * </ul>
+ *
+ * @see android.media.MediaPlayer
+ */
+public final class SubtitleData
+{
+    private static final String TAG = "SubtitleData";
+
+    private int mTrackIndex;
+    private long mStartTimeUs;
+    private long mDurationUs;
+    private byte[] mData;
+
+    public SubtitleData(Parcel parcel) {
+        if (!parseParcel(parcel)) {
+            throw new IllegalArgumentException("parseParcel() fails");
+        }
+    }
+
+    public int getTrackIndex() {
+        return mTrackIndex;
+    }
+
+    public long getStartTimeUs() {
+        return mStartTimeUs;
+    }
+
+    public long getDurationUs() {
+        return mDurationUs;
+    }
+
+    public byte[] getData() {
+        return mData;
+    }
+
+    private boolean parseParcel(Parcel parcel) {
+        parcel.setDataPosition(0);
+        if (parcel.dataAvail() == 0) {
+            return false;
+        }
+
+        mTrackIndex = parcel.readInt();
+        mStartTimeUs = parcel.readLong();
+        mDurationUs = parcel.readLong();
+        mData = new byte[parcel.readInt()];
+        parcel.readByteArray(mData);
+
+        return true;
+    }
+}
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
new file mode 100644
index 0000000..06063de
--- /dev/null
+++ b/media/java/android/media/SubtitleTrack.java
@@ -0,0 +1,705 @@
+/*
+ * 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 android.media;
+
+import android.graphics.Canvas;
+import android.os.Handler;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Pair;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Vector;
+
+/**
+ * A subtitle track abstract base class that is responsible for parsing and displaying
+ * an instance of a particular type of subtitle.
+ *
+ * @hide
+ */
+public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeListener {
+    private static final String TAG = "SubtitleTrack";
+    private long mLastUpdateTimeMs;
+    private long mLastTimeMs;
+
+    private Runnable mRunnable;
+
+    /** @hide TODO private */
+    final protected LongSparseArray<Run> mRunsByEndTime = new LongSparseArray<Run>();
+    /** @hide TODO private */
+    final protected LongSparseArray<Run> mRunsByID = new LongSparseArray<Run>();
+
+    /** @hide TODO private */
+    protected CueList mCues;
+    /** @hide TODO private */
+    final protected Vector<Cue> mActiveCues = new Vector<Cue>();
+    /** @hide */
+    protected boolean mVisible;
+
+    /** @hide */
+    public boolean DEBUG = false;
+
+    /** @hide */
+    protected Handler mHandler = new Handler();
+
+    private MediaFormat mFormat;
+
+    public SubtitleTrack(MediaFormat format) {
+        mFormat = format;
+        mCues = new CueList();
+        clearActiveCues();
+        mLastTimeMs = -1;
+    }
+
+    /** @hide */
+    public final MediaFormat getFormat() {
+        return mFormat;
+    }
+
+    private long mNextScheduledTimeMs = -1;
+
+    /**
+     * Called when there is input data for the subtitle track.  The
+     * complete subtitle for a track can include multiple whole units
+     * (runs).  Each of these units can have multiple sections.  The
+     * contents of a run are submitted in sequential order, with eos
+     * indicating the last section of the run.  Calls from different
+     * runs must not be intermixed.
+     *
+     * @param data
+     * @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
+     *              display.  Cues with runID of ~0 are discarded
+     *              only at the deletion of the track object.  Cues
+     *              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);
+
+    /**
+     * Called when adding the subtitle rendering widget to the view hierarchy,
+     * as well as when showing or hiding the subtitle track, or when the video
+     * surface position has changed.
+     *
+     * @return the widget that renders this subtitle track. For most renderers
+     *         there should be a single shared instance that is used for all
+     *         tracks supported by that renderer, as at most one subtitle track
+     *         is visible at one time.
+     */
+    public abstract RenderingWidget getRenderingWidget();
+
+    /**
+     * Called when the active cues have changed, and the contents of the subtitle
+     * view should be updated.
+     *
+     * @hide
+     */
+    public abstract void updateView(Vector<Cue> activeCues);
+
+    /** @hide */
+    protected synchronized void updateActiveCues(boolean rebuild, long timeMs) {
+        // out-of-order times mean seeking or new active cues being added
+        // (during their own timespan)
+        if (rebuild || mLastUpdateTimeMs > timeMs) {
+            clearActiveCues();
+        }
+
+        for(Iterator<Pair<Long, Cue> > it =
+                mCues.entriesBetween(mLastUpdateTimeMs, timeMs).iterator(); it.hasNext(); ) {
+            Pair<Long, Cue> event = it.next();
+            Cue cue = event.second;
+
+            if (cue.mEndTimeMs == event.first) {
+                // remove past cues
+                if (DEBUG) Log.v(TAG, "Removing " + cue);
+                mActiveCues.remove(cue);
+                if (cue.mRunID == 0) {
+                    it.remove();
+                }
+            } else if (cue.mStartTimeMs == event.first) {
+                // add new cues
+                // TRICKY: this will happen in start order
+                if (DEBUG) Log.v(TAG, "Adding " + cue);
+                if (cue.mInnerTimesMs != null) {
+                    cue.onTime(timeMs);
+                }
+                mActiveCues.add(cue);
+            } else if (cue.mInnerTimesMs != null) {
+                // cue is modified
+                cue.onTime(timeMs);
+            }
+        }
+
+        /* complete any runs */
+        while (mRunsByEndTime.size() > 0 &&
+               mRunsByEndTime.keyAt(0) <= timeMs) {
+            removeRunsByEndTimeIndex(0); // removes element
+        }
+        mLastUpdateTimeMs = timeMs;
+    }
+
+    private void removeRunsByEndTimeIndex(int ix) {
+        Run run = mRunsByEndTime.valueAt(ix);
+        while (run != null) {
+            Cue cue = run.mFirstCue;
+            while (cue != null) {
+                mCues.remove(cue);
+                Cue nextCue = cue.mNextInRun;
+                cue.mNextInRun = null;
+                cue = nextCue;
+            }
+            mRunsByID.remove(run.mRunID);
+            Run nextRun = run.mNextRunAtEndTimeMs;
+            run.mPrevRunAtEndTimeMs = null;
+            run.mNextRunAtEndTimeMs = null;
+            run = nextRun;
+        }
+        mRunsByEndTime.removeAt(ix);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        /* remove all cues (untangle all cross-links) */
+        int size = mRunsByEndTime.size();
+        for(int ix = size - 1; ix >= 0; ix--) {
+            removeRunsByEndTimeIndex(ix);
+        }
+
+        super.finalize();
+    }
+
+    private synchronized void takeTime(long timeMs) {
+        mLastTimeMs = timeMs;
+    }
+
+    /** @hide */
+    protected synchronized void clearActiveCues() {
+        if (DEBUG) Log.v(TAG, "Clearing " + mActiveCues.size() + " active cues");
+        mActiveCues.clear();
+        mLastUpdateTimeMs = -1;
+    }
+
+    /** @hide */
+    protected void scheduleTimedEvents() {
+        /* get times for the next event */
+        if (mTimeProvider != null) {
+            mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
+            if (DEBUG) Log.d(TAG, "sched @" + mNextScheduledTimeMs + " after " + mLastTimeMs);
+            mTimeProvider.notifyAt(
+                    mNextScheduledTimeMs >= 0 ?
+                        (mNextScheduledTimeMs * 1000) : MediaTimeProvider.NO_TIME,
+                    this);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void onTimedEvent(long timeUs) {
+        if (DEBUG) Log.d(TAG, "onTimedEvent " + timeUs);
+        synchronized (this) {
+            long timeMs = timeUs / 1000;
+            updateActiveCues(false, timeMs);
+            takeTime(timeMs);
+        }
+        updateView(mActiveCues);
+        scheduleTimedEvents();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void onSeek(long timeUs) {
+        if (DEBUG) Log.d(TAG, "onSeek " + timeUs);
+        synchronized (this) {
+            long timeMs = timeUs / 1000;
+            updateActiveCues(true, timeMs);
+            takeTime(timeMs);
+        }
+        updateView(mActiveCues);
+        scheduleTimedEvents();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void onStop() {
+        synchronized (this) {
+            if (DEBUG) Log.d(TAG, "onStop");
+            clearActiveCues();
+            mLastTimeMs = -1;
+        }
+        updateView(mActiveCues);
+        mNextScheduledTimeMs = -1;
+        mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+    }
+
+    /** @hide */
+    protected MediaTimeProvider mTimeProvider;
+
+    /** @hide */
+    public void show() {
+        if (mVisible) {
+            return;
+        }
+
+        mVisible = true;
+        getRenderingWidget().setVisible(true);
+        if (mTimeProvider != null) {
+            mTimeProvider.scheduleUpdate(this);
+        }
+    }
+
+    /** @hide */
+    public void hide() {
+        if (!mVisible) {
+            return;
+        }
+
+        if (mTimeProvider != null) {
+            mTimeProvider.cancelNotifications(this);
+        }
+        getRenderingWidget().setVisible(false);
+        mVisible = false;
+    }
+
+    /** @hide */
+    protected synchronized boolean addCue(Cue cue) {
+        mCues.add(cue);
+
+        if (cue.mRunID != 0) {
+            Run run = mRunsByID.get(cue.mRunID);
+            if (run == null) {
+                run = new Run();
+                mRunsByID.put(cue.mRunID, run);
+                run.mEndTimeMs = cue.mEndTimeMs;
+            } else if (run.mEndTimeMs < cue.mEndTimeMs) {
+                run.mEndTimeMs = cue.mEndTimeMs;
+            }
+
+            // link-up cues in the same run
+            cue.mNextInRun = run.mFirstCue;
+            run.mFirstCue = cue;
+        }
+
+        // if a cue is added that should be visible, need to refresh view
+        long nowMs = -1;
+        if (mTimeProvider != null) {
+            try {
+                nowMs = mTimeProvider.getCurrentTimeUs(
+                        false /* precise */, true /* monotonic */) / 1000;
+            } catch (IllegalStateException e) {
+                // handle as it we are not playing
+            }
+        }
+
+        if (DEBUG) Log.v(TAG, "mVisible=" + mVisible + ", " +
+                cue.mStartTimeMs + " <= " + nowMs + ", " +
+                cue.mEndTimeMs + " >= " + mLastTimeMs);
+
+        if (mVisible &&
+                cue.mStartTimeMs <= nowMs &&
+                // we don't trust nowMs, so check any cue since last callback
+                cue.mEndTimeMs >= mLastTimeMs) {
+            if (mRunnable != null) {
+                mHandler.removeCallbacks(mRunnable);
+            }
+            final SubtitleTrack track = this;
+            final long thenMs = nowMs;
+            mRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    // even with synchronized, it is possible that we are going
+                    // to do multiple updates as the runnable could be already
+                    // running.
+                    synchronized (track) {
+                        mRunnable = null;
+                        updateActiveCues(true, thenMs);
+                        updateView(mActiveCues);
+                    }
+                }
+            };
+            // delay update so we don't update view on every cue.  TODO why 10?
+            if (mHandler.postDelayed(mRunnable, 10 /* delay */)) {
+                if (DEBUG) Log.v(TAG, "scheduling update");
+            } else {
+                if (DEBUG) Log.w(TAG, "failed to schedule subtitle view update");
+            }
+            return true;
+        }
+
+        if (mVisible &&
+                cue.mEndTimeMs >= mLastTimeMs &&
+                (cue.mStartTimeMs < mNextScheduledTimeMs ||
+                 mNextScheduledTimeMs < 0)) {
+            scheduleTimedEvents();
+        }
+
+        return false;
+    }
+
+    /** @hide */
+    public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
+        if (mTimeProvider == timeProvider) {
+            return;
+        }
+        if (mTimeProvider != null) {
+            mTimeProvider.cancelNotifications(this);
+        }
+        mTimeProvider = timeProvider;
+        if (mTimeProvider != null) {
+            mTimeProvider.scheduleUpdate(this);
+        }
+    }
+
+
+    /** @hide */
+    static class CueList {
+        private static final String TAG = "CueList";
+        // simplistic, inefficient implementation
+        private SortedMap<Long, Vector<Cue> > mCues;
+        public boolean DEBUG = false;
+
+        private boolean addEvent(Cue cue, long timeMs) {
+            Vector<Cue> cues = mCues.get(timeMs);
+            if (cues == null) {
+                cues = new Vector<Cue>(2);
+                mCues.put(timeMs, cues);
+            } else if (cues.contains(cue)) {
+                // do not duplicate cues
+                return false;
+            }
+
+            cues.add(cue);
+            return true;
+        }
+
+        private void removeEvent(Cue cue, long timeMs) {
+            Vector<Cue> cues = mCues.get(timeMs);
+            if (cues != null) {
+                cues.remove(cue);
+                if (cues.size() == 0) {
+                    mCues.remove(timeMs);
+                }
+            }
+        }
+
+        public void add(Cue cue) {
+            // ignore non-positive-duration cues
+            if (cue.mStartTimeMs >= cue.mEndTimeMs)
+                return;
+
+            if (!addEvent(cue, cue.mStartTimeMs)) {
+                return;
+            }
+
+            long lastTimeMs = cue.mStartTimeMs;
+            if (cue.mInnerTimesMs != null) {
+                for (long timeMs: cue.mInnerTimesMs) {
+                    if (timeMs > lastTimeMs && timeMs < cue.mEndTimeMs) {
+                        addEvent(cue, timeMs);
+                        lastTimeMs = timeMs;
+                    }
+                }
+            }
+
+            addEvent(cue, cue.mEndTimeMs);
+        }
+
+        public void remove(Cue cue) {
+            removeEvent(cue, cue.mStartTimeMs);
+            if (cue.mInnerTimesMs != null) {
+                for (long timeMs: cue.mInnerTimesMs) {
+                    removeEvent(cue, timeMs);
+                }
+            }
+            removeEvent(cue, cue.mEndTimeMs);
+        }
+
+        public Iterable<Pair<Long, Cue>> entriesBetween(
+                final long lastTimeMs, final long timeMs) {
+            return new Iterable<Pair<Long, Cue> >() {
+                @Override
+                public Iterator<Pair<Long, Cue> > iterator() {
+                    if (DEBUG) Log.d(TAG, "slice (" + lastTimeMs + ", " + timeMs + "]=");
+                    try {
+                        return new EntryIterator(
+                                mCues.subMap(lastTimeMs + 1, timeMs + 1));
+                    } catch(IllegalArgumentException e) {
+                        return new EntryIterator(null);
+                    }
+                }
+            };
+        }
+
+        public long nextTimeAfter(long timeMs) {
+            SortedMap<Long, Vector<Cue>> tail = null;
+            try {
+                tail = mCues.tailMap(timeMs + 1);
+                if (tail != null) {
+                    return tail.firstKey();
+                } else {
+                    return -1;
+                }
+            } catch(IllegalArgumentException e) {
+                return -1;
+            } catch(NoSuchElementException e) {
+                return -1;
+            }
+        }
+
+        class EntryIterator implements Iterator<Pair<Long, Cue> > {
+            @Override
+            public boolean hasNext() {
+                return !mDone;
+            }
+
+            @Override
+            public Pair<Long, Cue> next() {
+                if (mDone) {
+                    throw new NoSuchElementException("");
+                }
+                mLastEntry = new Pair<Long, Cue>(
+                        mCurrentTimeMs, mListIterator.next());
+                mLastListIterator = mListIterator;
+                if (!mListIterator.hasNext()) {
+                    nextKey();
+                }
+                return mLastEntry;
+            }
+
+            @Override
+            public void remove() {
+                // only allow removing end tags
+                if (mLastListIterator == null ||
+                        mLastEntry.second.mEndTimeMs != mLastEntry.first) {
+                    throw new IllegalStateException("");
+                }
+
+                // remove end-cue
+                mLastListIterator.remove();
+                mLastListIterator = null;
+                if (mCues.get(mLastEntry.first).size() == 0) {
+                    mCues.remove(mLastEntry.first);
+                }
+
+                // remove rest of the cues
+                Cue cue = mLastEntry.second;
+                removeEvent(cue, cue.mStartTimeMs);
+                if (cue.mInnerTimesMs != null) {
+                    for (long timeMs: cue.mInnerTimesMs) {
+                        removeEvent(cue, timeMs);
+                    }
+                }
+            }
+
+            public EntryIterator(SortedMap<Long, Vector<Cue> > cues) {
+                if (DEBUG) Log.v(TAG, cues + "");
+                mRemainingCues = cues;
+                mLastListIterator = null;
+                nextKey();
+            }
+
+            private void nextKey() {
+                do {
+                    try {
+                        if (mRemainingCues == null) {
+                            throw new NoSuchElementException("");
+                        }
+                        mCurrentTimeMs = mRemainingCues.firstKey();
+                        mListIterator =
+                            mRemainingCues.get(mCurrentTimeMs).iterator();
+                        try {
+                            mRemainingCues =
+                                mRemainingCues.tailMap(mCurrentTimeMs + 1);
+                        } catch (IllegalArgumentException e) {
+                            mRemainingCues = null;
+                        }
+                        mDone = false;
+                    } catch (NoSuchElementException e) {
+                        mDone = true;
+                        mRemainingCues = null;
+                        mListIterator = null;
+                        return;
+                    }
+                } while (!mListIterator.hasNext());
+            }
+
+            private long mCurrentTimeMs;
+            private Iterator<Cue> mListIterator;
+            private boolean mDone;
+            private SortedMap<Long, Vector<Cue> > mRemainingCues;
+            private Iterator<Cue> mLastListIterator;
+            private Pair<Long,Cue> mLastEntry;
+        }
+
+        CueList() {
+            mCues = new TreeMap<Long, Vector<Cue>>();
+        }
+    }
+
+    /** @hide */
+    public static class Cue {
+        public long mStartTimeMs;
+        public long mEndTimeMs;
+        public long[] mInnerTimesMs;
+        public long mRunID;
+
+        /** @hide */
+        public Cue mNextInRun;
+
+        public void onTime(long timeMs) { }
+    }
+
+    /** @hide update mRunsByEndTime (with default end time) */
+    protected void finishedRun(long runID) {
+        if (runID != 0 && runID != ~0) {
+            Run run = mRunsByID.get(runID);
+            if (run != null) {
+                run.storeByEndTimeMs(mRunsByEndTime);
+            }
+        }
+    }
+
+    /** @hide update mRunsByEndTime with given end time */
+    public void setRunDiscardTimeMs(long runID, long timeMs) {
+        if (runID != 0 && runID != ~0) {
+            Run run = mRunsByID.get(runID);
+            if (run != null) {
+                run.mEndTimeMs = timeMs;
+                run.storeByEndTimeMs(mRunsByEndTime);
+            }
+        }
+    }
+
+    /** @hide */
+    private static class Run {
+        public Cue mFirstCue;
+        public Run mNextRunAtEndTimeMs;
+        public Run mPrevRunAtEndTimeMs;
+        public long mEndTimeMs = -1;
+        public long mRunID = 0;
+        private long mStoredEndTimeMs = -1;
+
+        public void storeByEndTimeMs(LongSparseArray<Run> runsByEndTime) {
+            // remove old value if any
+            int ix = runsByEndTime.indexOfKey(mStoredEndTimeMs);
+            if (ix >= 0) {
+                if (mPrevRunAtEndTimeMs == null) {
+                    assert(this == runsByEndTime.valueAt(ix));
+                    if (mNextRunAtEndTimeMs == null) {
+                        runsByEndTime.removeAt(ix);
+                    } else {
+                        runsByEndTime.setValueAt(ix, mNextRunAtEndTimeMs);
+                    }
+                }
+                removeAtEndTimeMs();
+            }
+
+            // add new value
+            if (mEndTimeMs >= 0) {
+                mPrevRunAtEndTimeMs = null;
+                mNextRunAtEndTimeMs = runsByEndTime.get(mEndTimeMs);
+                if (mNextRunAtEndTimeMs != null) {
+                    mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = this;
+                }
+                runsByEndTime.put(mEndTimeMs, this);
+                mStoredEndTimeMs = mEndTimeMs;
+            }
+        }
+
+        public void removeAtEndTimeMs() {
+            Run prev = mPrevRunAtEndTimeMs;
+
+            if (mPrevRunAtEndTimeMs != null) {
+                mPrevRunAtEndTimeMs.mNextRunAtEndTimeMs = mNextRunAtEndTimeMs;
+                mPrevRunAtEndTimeMs = null;
+            }
+            if (mNextRunAtEndTimeMs != null) {
+                mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = prev;
+                mNextRunAtEndTimeMs = null;
+            }
+        }
+    }
+
+    /**
+     * Interface for rendering subtitles onto a Canvas.
+     */
+    public interface RenderingWidget {
+        /**
+         * Sets the widget's callback, which is used to send updates when the
+         * rendered data has changed.
+         *
+         * @param callback update callback
+         */
+        public void setOnChangedListener(OnChangedListener callback);
+
+        /**
+         * Sets the widget's size.
+         *
+         * @param width width in pixels
+         * @param height height in pixels
+         */
+        public void setSize(int width, int height);
+
+        /**
+         * Sets whether the widget should draw subtitles.
+         *
+         * @param visible true if subtitles should be drawn, false otherwise
+         */
+        public void setVisible(boolean visible);
+
+        /**
+         * Renders subtitles onto a {@link Canvas}.
+         *
+         * @param c canvas on which to render subtitles
+         */
+        public void draw(Canvas c);
+
+        /**
+         * Called when the widget is attached to a window.
+         */
+        public void onAttachedToWindow();
+
+        /**
+         * Called when the widget is detached from a window.
+         */
+        public void onDetachedFromWindow();
+
+        /**
+         * Callback used to send updates about changes to rendering data.
+         */
+        public interface OnChangedListener {
+            /**
+             * Called when the rendering data has changed.
+             *
+             * @param renderingWidget the widget whose data has changed
+             */
+            public void onChanged(RenderingWidget renderingWidget);
+        }
+    }
+}
diff --git a/media/java/android/media/VolumeController.java b/media/java/android/media/VolumeController.java
new file mode 100644
index 0000000..2d12bf2
--- /dev/null
+++ b/media/java/android/media/VolumeController.java
@@ -0,0 +1,29 @@
+/*
+ * 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 android.media;
+
+/**
+ * @hide
+ */
+public interface VolumeController {
+
+    public void postHasNewRemotePlaybackInfo();
+
+    public void postRemoteVolumeChanged(int streamType, int flags);
+
+    public void postRemoteSliderVisibility(boolean visible);
+}
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
new file mode 100644
index 0000000..4dec081
--- /dev/null
+++ b/media/java/android/media/WebVttRenderer.java
@@ -0,0 +1,1842 @@
+/*
+ * 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 android.media;
+
+import android.content.Context;
+import android.text.Layout.Alignment;
+import android.text.SpannableStringBuilder;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+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 com.android.internal.widget.SubtitleView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/** @hide */
+public class WebVttRenderer extends SubtitleController.Renderer {
+    private final Context mContext;
+
+    private WebVttRenderingWidget mRenderingWidget;
+
+    public WebVttRenderer(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public boolean supports(MediaFormat format) {
+        if (format.containsKey(MediaFormat.KEY_MIME)) {
+            return format.getString(MediaFormat.KEY_MIME).equals("text/vtt");
+        }
+        return false;
+    }
+
+    @Override
+    public SubtitleTrack createTrack(MediaFormat format) {
+        if (mRenderingWidget == null) {
+            mRenderingWidget = new WebVttRenderingWidget(mContext);
+        }
+
+        return new WebVttTrack(mRenderingWidget, format);
+    }
+}
+
+/** @hide */
+class TextTrackCueSpan {
+    long mTimestampMs;
+    boolean mEnabled;
+    String mText;
+    TextTrackCueSpan(String text, long timestamp) {
+        mTimestampMs = timestamp;
+        mText = text;
+        // spans with timestamp will be enabled by Cue.onTime
+        mEnabled = (mTimestampMs < 0);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof TextTrackCueSpan)) {
+            return false;
+        }
+        TextTrackCueSpan span = (TextTrackCueSpan) o;
+        return mTimestampMs == span.mTimestampMs &&
+                mText.equals(span.mText);
+    }
+}
+
+/**
+ * @hide
+ *
+ * Extract all text without style, but with timestamp spans.
+ */
+class UnstyledTextExtractor implements Tokenizer.OnTokenListener {
+    StringBuilder mLine = new StringBuilder();
+    Vector<TextTrackCueSpan[]> mLines = new Vector<TextTrackCueSpan[]>();
+    Vector<TextTrackCueSpan> mCurrentLine = new Vector<TextTrackCueSpan>();
+    long mLastTimestamp;
+
+    UnstyledTextExtractor() {
+        init();
+    }
+
+    private void init() {
+        mLine.delete(0, mLine.length());
+        mLines.clear();
+        mCurrentLine.clear();
+        mLastTimestamp = -1;
+    }
+
+    @Override
+    public void onData(String s) {
+        mLine.append(s);
+    }
+
+    @Override
+    public void onStart(String tag, String[] classes, String annotation) { }
+
+    @Override
+    public void onEnd(String tag) { }
+
+    @Override
+    public void onTimeStamp(long timestampMs) {
+        // finish any prior span
+        if (mLine.length() > 0 && timestampMs != mLastTimestamp) {
+            mCurrentLine.add(
+                    new TextTrackCueSpan(mLine.toString(), mLastTimestamp));
+            mLine.delete(0, mLine.length());
+        }
+        mLastTimestamp = timestampMs;
+    }
+
+    @Override
+    public void onLineEnd() {
+        // finish any pending span
+        if (mLine.length() > 0) {
+            mCurrentLine.add(
+                    new TextTrackCueSpan(mLine.toString(), mLastTimestamp));
+            mLine.delete(0, mLine.length());
+        }
+
+        TextTrackCueSpan[] spans = new TextTrackCueSpan[mCurrentLine.size()];
+        mCurrentLine.toArray(spans);
+        mCurrentLine.clear();
+        mLines.add(spans);
+    }
+
+    public TextTrackCueSpan[][] getText() {
+        // for politeness, finish last cue-line if it ends abruptly
+        if (mLine.length() > 0 || mCurrentLine.size() > 0) {
+            onLineEnd();
+        }
+        TextTrackCueSpan[][] lines = new TextTrackCueSpan[mLines.size()][];
+        mLines.toArray(lines);
+        init();
+        return lines;
+    }
+}
+
+/**
+ * @hide
+ *
+ * Tokenizer tokenizes the WebVTT Cue Text into tags and data
+ */
+class Tokenizer {
+    private static final String TAG = "Tokenizer";
+    private TokenizerPhase mPhase;
+    private TokenizerPhase mDataTokenizer;
+    private TokenizerPhase mTagTokenizer;
+
+    private OnTokenListener mListener;
+    private String mLine;
+    private int mHandledLen;
+
+    interface TokenizerPhase {
+        TokenizerPhase start();
+        void tokenize();
+    }
+
+    class DataTokenizer implements TokenizerPhase {
+        // includes both WebVTT data && escape state
+        private StringBuilder mData;
+
+        public TokenizerPhase start() {
+            mData = new StringBuilder();
+            return this;
+        }
+
+        private boolean replaceEscape(String escape, String replacement, int pos) {
+            if (mLine.startsWith(escape, pos)) {
+                mData.append(mLine.substring(mHandledLen, pos));
+                mData.append(replacement);
+                mHandledLen = pos + escape.length();
+                pos = mHandledLen - 1;
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void tokenize() {
+            int end = mLine.length();
+            for (int pos = mHandledLen; pos < mLine.length(); pos++) {
+                if (mLine.charAt(pos) == '&') {
+                    if (replaceEscape("&amp;", "&", pos) ||
+                            replaceEscape("&lt;", "<", pos) ||
+                            replaceEscape("&gt;", ">", pos) ||
+                            replaceEscape("&lrm;", "\u200e", pos) ||
+                            replaceEscape("&rlm;", "\u200f", pos) ||
+                            replaceEscape("&nbsp;", "\u00a0", pos)) {
+                        continue;
+                    }
+                } else if (mLine.charAt(pos) == '<') {
+                    end = pos;
+                    mPhase = mTagTokenizer.start();
+                    break;
+                }
+            }
+            mData.append(mLine.substring(mHandledLen, end));
+            // yield mData
+            mListener.onData(mData.toString());
+            mData.delete(0, mData.length());
+            mHandledLen = end;
+        }
+    }
+
+    class TagTokenizer implements TokenizerPhase {
+        private boolean mAtAnnotation;
+        private String mName, mAnnotation;
+
+        public TokenizerPhase start() {
+            mName = mAnnotation = "";
+            mAtAnnotation = false;
+            return this;
+        }
+
+        @Override
+        public void tokenize() {
+            if (!mAtAnnotation)
+                mHandledLen++;
+            if (mHandledLen < mLine.length()) {
+                String[] parts;
+                /**
+                 * Collect annotations and end-tags to closing >.  Collect tag
+                 * name to closing bracket or next white-space.
+                 */
+                if (mAtAnnotation || mLine.charAt(mHandledLen) == '/') {
+                    parts = mLine.substring(mHandledLen).split(">");
+                } else {
+                    parts = mLine.substring(mHandledLen).split("[\t\f >]");
+                }
+                String part = mLine.substring(
+                            mHandledLen, mHandledLen + parts[0].length());
+                mHandledLen += parts[0].length();
+
+                if (mAtAnnotation) {
+                    mAnnotation += " " + part;
+                } else {
+                    mName = part;
+                }
+            }
+
+            mAtAnnotation = true;
+
+            if (mHandledLen < mLine.length() && mLine.charAt(mHandledLen) == '>') {
+                yield_tag();
+                mPhase = mDataTokenizer.start();
+                mHandledLen++;
+            }
+        }
+
+        private void yield_tag() {
+            if (mName.startsWith("/")) {
+                mListener.onEnd(mName.substring(1));
+            } else if (mName.length() > 0 && Character.isDigit(mName.charAt(0))) {
+                // timestamp
+                try {
+                    long timestampMs = WebVttParser.parseTimestampMs(mName);
+                    mListener.onTimeStamp(timestampMs);
+                } catch (NumberFormatException e) {
+                    Log.d(TAG, "invalid timestamp tag: <" + mName + ">");
+                }
+            } else {
+                mAnnotation = mAnnotation.replaceAll("\\s+", " ");
+                if (mAnnotation.startsWith(" ")) {
+                    mAnnotation = mAnnotation.substring(1);
+                }
+                if (mAnnotation.endsWith(" ")) {
+                    mAnnotation = mAnnotation.substring(0, mAnnotation.length() - 1);
+                }
+
+                String[] classes = null;
+                int dotAt = mName.indexOf('.');
+                if (dotAt >= 0) {
+                    classes = mName.substring(dotAt + 1).split("\\.");
+                    mName = mName.substring(0, dotAt);
+                }
+                mListener.onStart(mName, classes, mAnnotation);
+            }
+        }
+    }
+
+    Tokenizer(OnTokenListener listener) {
+        mDataTokenizer = new DataTokenizer();
+        mTagTokenizer = new TagTokenizer();
+        reset();
+        mListener = listener;
+    }
+
+    void reset() {
+        mPhase = mDataTokenizer.start();
+    }
+
+    void tokenize(String s) {
+        mHandledLen = 0;
+        mLine = s;
+        while (mHandledLen < mLine.length()) {
+            mPhase.tokenize();
+        }
+        /* we are finished with a line unless we are in the middle of a tag */
+        if (!(mPhase instanceof TagTokenizer)) {
+            // yield END-OF-LINE
+            mListener.onLineEnd();
+        }
+    }
+
+    interface OnTokenListener {
+        void onData(String s);
+        void onStart(String tag, String[] classes, String annotation);
+        void onEnd(String tag);
+        void onTimeStamp(long timestampMs);
+        void onLineEnd();
+    }
+}
+
+/** @hide */
+class TextTrackRegion {
+    final static int SCROLL_VALUE_NONE      = 300;
+    final static int SCROLL_VALUE_SCROLL_UP = 301;
+
+    String mId;
+    float mWidth;
+    int mLines;
+    float mAnchorPointX, mAnchorPointY;
+    float mViewportAnchorPointX, mViewportAnchorPointY;
+    int mScrollValue;
+
+    TextTrackRegion() {
+        mId = "";
+        mWidth = 100;
+        mLines = 3;
+        mAnchorPointX = mViewportAnchorPointX = 0.f;
+        mAnchorPointY = mViewportAnchorPointY = 100.f;
+        mScrollValue = SCROLL_VALUE_NONE;
+    }
+
+    public String toString() {
+        StringBuilder res = new StringBuilder(" {id:\"").append(mId)
+            .append("\", width:").append(mWidth)
+            .append(", lines:").append(mLines)
+            .append(", anchorPoint:(").append(mAnchorPointX)
+            .append(", ").append(mAnchorPointY)
+            .append("), viewportAnchorPoints:").append(mViewportAnchorPointX)
+            .append(", ").append(mViewportAnchorPointY)
+            .append("), scrollValue:")
+            .append(mScrollValue == SCROLL_VALUE_NONE ? "none" :
+                    mScrollValue == SCROLL_VALUE_SCROLL_UP ? "scroll_up" :
+                    "INVALID")
+            .append("}");
+        return res.toString();
+    }
+}
+
+/** @hide */
+class TextTrackCue extends SubtitleTrack.Cue {
+    final static int WRITING_DIRECTION_HORIZONTAL  = 100;
+    final static int WRITING_DIRECTION_VERTICAL_RL = 101;
+    final static int WRITING_DIRECTION_VERTICAL_LR = 102;
+
+    final static int ALIGNMENT_MIDDLE = 200;
+    final static int ALIGNMENT_START  = 201;
+    final static int ALIGNMENT_END    = 202;
+    final static int ALIGNMENT_LEFT   = 203;
+    final static int ALIGNMENT_RIGHT  = 204;
+    private static final String TAG = "TTCue";
+
+    String  mId;
+    boolean mPauseOnExit;
+    int     mWritingDirection;
+    String  mRegionId;
+    boolean mSnapToLines;
+    Integer mLinePosition;  // null means AUTO
+    boolean mAutoLinePosition;
+    int     mTextPosition;
+    int     mSize;
+    int     mAlignment;
+    // Vector<String> mText;
+    String[] mStrings;
+    TextTrackCueSpan[][] mLines;
+    TextTrackRegion mRegion;
+
+    TextTrackCue() {
+        mId = "";
+        mPauseOnExit = false;
+        mWritingDirection = WRITING_DIRECTION_HORIZONTAL;
+        mRegionId = "";
+        mSnapToLines = true;
+        mLinePosition = null /* AUTO */;
+        mTextPosition = 50;
+        mSize = 100;
+        mAlignment = ALIGNMENT_MIDDLE;
+        mLines = null;
+        mRegion = null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof TextTrackCue)) {
+            return false;
+        }
+        if (this == o) {
+            return true;
+        }
+
+        try {
+            TextTrackCue cue = (TextTrackCue) o;
+            boolean res = mId.equals(cue.mId) &&
+                    mPauseOnExit == cue.mPauseOnExit &&
+                    mWritingDirection == cue.mWritingDirection &&
+                    mRegionId.equals(cue.mRegionId) &&
+                    mSnapToLines == cue.mSnapToLines &&
+                    mAutoLinePosition == cue.mAutoLinePosition &&
+                    (mAutoLinePosition || mLinePosition == cue.mLinePosition) &&
+                    mTextPosition == cue.mTextPosition &&
+                    mSize == cue.mSize &&
+                    mAlignment == cue.mAlignment &&
+                    mLines.length == cue.mLines.length;
+            if (res == true) {
+                for (int line = 0; line < mLines.length; line++) {
+                    if (!Arrays.equals(mLines[line], cue.mLines[line])) {
+                        return false;
+                    }
+                }
+            }
+            return res;
+        } catch(IncompatibleClassChangeError e) {
+            return false;
+        }
+    }
+
+    public StringBuilder appendStringsToBuilder(StringBuilder builder) {
+        if (mStrings == null) {
+            builder.append("null");
+        } else {
+            builder.append("[");
+            boolean first = true;
+            for (String s: mStrings) {
+                if (!first) {
+                    builder.append(", ");
+                }
+                if (s == null) {
+                    builder.append("null");
+                } else {
+                    builder.append("\"");
+                    builder.append(s);
+                    builder.append("\"");
+                }
+                first = false;
+            }
+            builder.append("]");
+        }
+        return builder;
+    }
+
+    public StringBuilder appendLinesToBuilder(StringBuilder builder) {
+        if (mLines == null) {
+            builder.append("null");
+        } else {
+            builder.append("[");
+            boolean first = true;
+            for (TextTrackCueSpan[] spans: mLines) {
+                if (!first) {
+                    builder.append(", ");
+                }
+                if (spans == null) {
+                    builder.append("null");
+                } else {
+                    builder.append("\"");
+                    boolean innerFirst = true;
+                    long lastTimestamp = -1;
+                    for (TextTrackCueSpan span: spans) {
+                        if (!innerFirst) {
+                            builder.append(" ");
+                        }
+                        if (span.mTimestampMs != lastTimestamp) {
+                            builder.append("<")
+                                    .append(WebVttParser.timeToString(
+                                            span.mTimestampMs))
+                                    .append(">");
+                            lastTimestamp = span.mTimestampMs;
+                        }
+                        builder.append(span.mText);
+                        innerFirst = false;
+                    }
+                    builder.append("\"");
+                }
+                first = false;
+            }
+            builder.append("]");
+        }
+        return builder;
+    }
+
+    public String toString() {
+        StringBuilder res = new StringBuilder();
+
+        res.append(WebVttParser.timeToString(mStartTimeMs))
+                .append(" --> ").append(WebVttParser.timeToString(mEndTimeMs))
+                .append(" {id:\"").append(mId)
+                .append("\", pauseOnExit:").append(mPauseOnExit)
+                .append(", direction:")
+                .append(mWritingDirection == WRITING_DIRECTION_HORIZONTAL ? "horizontal" :
+                        mWritingDirection == WRITING_DIRECTION_VERTICAL_LR ? "vertical_lr" :
+                        mWritingDirection == WRITING_DIRECTION_VERTICAL_RL ? "vertical_rl" :
+                        "INVALID")
+                .append(", regionId:\"").append(mRegionId)
+                .append("\", snapToLines:").append(mSnapToLines)
+                .append(", linePosition:").append(mAutoLinePosition ? "auto" :
+                                                  mLinePosition)
+                .append(", textPosition:").append(mTextPosition)
+                .append(", size:").append(mSize)
+                .append(", alignment:")
+                .append(mAlignment == ALIGNMENT_END ? "end" :
+                        mAlignment == ALIGNMENT_LEFT ? "left" :
+                        mAlignment == ALIGNMENT_MIDDLE ? "middle" :
+                        mAlignment == ALIGNMENT_RIGHT ? "right" :
+                        mAlignment == ALIGNMENT_START ? "start" : "INVALID")
+                .append(", text:");
+        appendStringsToBuilder(res).append("}");
+        return res.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    @Override
+    public void onTime(long timeMs) {
+        for (TextTrackCueSpan[] line: mLines) {
+            for (TextTrackCueSpan span: line) {
+                span.mEnabled = timeMs >= span.mTimestampMs;
+            }
+        }
+    }
+}
+
+/** @hide */
+class WebVttParser {
+    private static final String TAG = "WebVttParser";
+    private Phase mPhase;
+    private TextTrackCue mCue;
+    private Vector<String> mCueTexts;
+    private WebVttCueListener mListener;
+    private String mBuffer;
+
+    WebVttParser(WebVttCueListener listener) {
+        mPhase = mParseStart;
+        mBuffer = "";   /* mBuffer contains up to 1 incomplete line */
+        mListener = listener;
+        mCueTexts = new Vector<String>();
+    }
+
+    /* parsePercentageString */
+    public static float parseFloatPercentage(String s)
+            throws NumberFormatException {
+        if (!s.endsWith("%")) {
+            throw new NumberFormatException("does not end in %");
+        }
+        s = s.substring(0, s.length() - 1);
+        // parseFloat allows an exponent or a sign
+        if (s.matches(".*[^0-9.].*")) {
+            throw new NumberFormatException("contains an invalid character");
+        }
+
+        try {
+            float value = Float.parseFloat(s);
+            if (value < 0.0f || value > 100.0f) {
+                throw new NumberFormatException("is out of range");
+            }
+            return value;
+        } catch (NumberFormatException e) {
+            throw new NumberFormatException("is not a number");
+        }
+    }
+
+    public static int parseIntPercentage(String s) throws NumberFormatException {
+        if (!s.endsWith("%")) {
+            throw new NumberFormatException("does not end in %");
+        }
+        s = s.substring(0, s.length() - 1);
+        // parseInt allows "-0" that returns 0, so check for non-digits
+        if (s.matches(".*[^0-9].*")) {
+            throw new NumberFormatException("contains an invalid character");
+        }
+
+        try {
+            int value = Integer.parseInt(s);
+            if (value < 0 || value > 100) {
+                throw new NumberFormatException("is out of range");
+            }
+            return value;
+        } catch (NumberFormatException e) {
+            throw new NumberFormatException("is not a number");
+        }
+    }
+
+    public static long parseTimestampMs(String s) throws NumberFormatException {
+        if (!s.matches("(\\d+:)?[0-5]\\d:[0-5]\\d\\.\\d{3}")) {
+            throw new NumberFormatException("has invalid format");
+        }
+
+        String[] parts = s.split("\\.", 2);
+        long value = 0;
+        for (String group: parts[0].split(":")) {
+            value = value * 60 + Long.parseLong(group);
+        }
+        return value * 1000 + Long.parseLong(parts[1]);
+    }
+
+    public static String timeToString(long timeMs) {
+        return String.format("%d:%02d:%02d.%03d",
+                timeMs / 3600000, (timeMs / 60000) % 60,
+                (timeMs / 1000) % 60, timeMs % 1000);
+    }
+
+    public void parse(String s) {
+        boolean trailingCR = false;
+        mBuffer = (mBuffer + s.replace("\0", "\ufffd")).replace("\r\n", "\n");
+
+        /* keep trailing '\r' in case matching '\n' arrives in next packet */
+        if (mBuffer.endsWith("\r")) {
+            trailingCR = true;
+            mBuffer = mBuffer.substring(0, mBuffer.length() - 1);
+        }
+
+        String[] lines = mBuffer.split("[\r\n]");
+        for (int i = 0; i < lines.length - 1; i++) {
+            mPhase.parse(lines[i]);
+        }
+
+        mBuffer = lines[lines.length - 1];
+        if (trailingCR)
+            mBuffer += "\r";
+    }
+
+    public void eos() {
+        if (mBuffer.endsWith("\r")) {
+            mBuffer = mBuffer.substring(0, mBuffer.length() - 1);
+        }
+
+        mPhase.parse(mBuffer);
+        mBuffer = "";
+
+        yieldCue();
+        mPhase = mParseStart;
+    }
+
+    public void yieldCue() {
+        if (mCue != null && mCueTexts.size() > 0) {
+            mCue.mStrings = new String[mCueTexts.size()];
+            mCueTexts.toArray(mCue.mStrings);
+            mCueTexts.clear();
+            mListener.onCueParsed(mCue);
+        }
+        mCue = null;
+    }
+
+    interface Phase {
+        void parse(String line);
+    }
+
+    final private Phase mSkipRest = new Phase() {
+        @Override
+        public void parse(String line) { }
+    };
+
+    final private Phase mParseStart = new Phase() { // 5-9
+        @Override
+        public void parse(String line) {
+            if (line.startsWith("\ufeff")) {
+                line = line.substring(1);
+            }
+            if (!line.equals("WEBVTT") &&
+                    !line.startsWith("WEBVTT ") &&
+                    !line.startsWith("WEBVTT\t")) {
+                log_warning("Not a WEBVTT header", line);
+                mPhase = mSkipRest;
+            } else {
+                mPhase = mParseHeader;
+            }
+        }
+    };
+
+    final private Phase mParseHeader = new Phase() { // 10-13
+        TextTrackRegion parseRegion(String s) {
+            TextTrackRegion region = new TextTrackRegion();
+            for (String setting: s.split(" +")) {
+                int equalAt = setting.indexOf('=');
+                if (equalAt <= 0 || equalAt == setting.length() - 1) {
+                    continue;
+                }
+
+                String name = setting.substring(0, equalAt);
+                String value = setting.substring(equalAt + 1);
+                if (name.equals("id")) {
+                    region.mId = value;
+                } else if (name.equals("width")) {
+                    try {
+                        region.mWidth = parseFloatPercentage(value);
+                    } catch (NumberFormatException e) {
+                        log_warning("region setting", name,
+                                "has invalid value", e.getMessage(), value);
+                    }
+                } else if (name.equals("lines")) {
+                    try {
+                        int lines = Integer.parseInt(value);
+                        if (lines >= 0) {
+                            region.mLines = lines;
+                        } else {
+                            log_warning("region setting", name, "is negative", value);
+                        }
+                    } catch (NumberFormatException e) {
+                        log_warning("region setting", name, "is not numeric", value);
+                    }
+                } else if (name.equals("regionanchor") ||
+                           name.equals("viewportanchor")) {
+                    int commaAt = value.indexOf(",");
+                    if (commaAt < 0) {
+                        log_warning("region setting", name, "contains no comma", value);
+                        continue;
+                    }
+
+                    String anchorX = value.substring(0, commaAt);
+                    String anchorY = value.substring(commaAt + 1);
+                    float x, y;
+
+                    try {
+                        x = parseFloatPercentage(anchorX);
+                    } catch (NumberFormatException e) {
+                        log_warning("region setting", name,
+                                "has invalid x component", e.getMessage(), anchorX);
+                        continue;
+                    }
+                    try {
+                        y = parseFloatPercentage(anchorY);
+                    } catch (NumberFormatException e) {
+                        log_warning("region setting", name,
+                                "has invalid y component", e.getMessage(), anchorY);
+                        continue;
+                    }
+
+                    if (name.charAt(0) == 'r') {
+                        region.mAnchorPointX = x;
+                        region.mAnchorPointY = y;
+                    } else {
+                        region.mViewportAnchorPointX = x;
+                        region.mViewportAnchorPointY = y;
+                    }
+                } else if (name.equals("scroll")) {
+                    if (value.equals("up")) {
+                        region.mScrollValue =
+                            TextTrackRegion.SCROLL_VALUE_SCROLL_UP;
+                    } else {
+                        log_warning("region setting", name, "has invalid value", value);
+                    }
+                }
+            }
+            return region;
+        }
+
+        @Override
+        public void parse(String line)  {
+            if (line.length() == 0) {
+                mPhase = mParseCueId;
+            } else if (line.contains("-->")) {
+                mPhase = mParseCueTime;
+                mPhase.parse(line);
+            } else {
+                int colonAt = line.indexOf(':');
+                if (colonAt <= 0 || colonAt >= line.length() - 1) {
+                    log_warning("meta data header has invalid format", line);
+                }
+                String name = line.substring(0, colonAt);
+                String value = line.substring(colonAt + 1);
+
+                if (name.equals("Region")) {
+                    TextTrackRegion region = parseRegion(value);
+                    mListener.onRegionParsed(region);
+                }
+            }
+        }
+    };
+
+    final private Phase mParseCueId = new Phase() {
+        @Override
+        public void parse(String line) {
+            if (line.length() == 0) {
+                return;
+            }
+
+            assert(mCue == null);
+
+            if (line.equals("NOTE") || line.startsWith("NOTE ")) {
+                mPhase = mParseCueText;
+            }
+
+            mCue = new TextTrackCue();
+            mCueTexts.clear();
+
+            mPhase = mParseCueTime;
+            if (line.contains("-->")) {
+                mPhase.parse(line);
+            } else {
+                mCue.mId = line;
+            }
+        }
+    };
+
+    final private Phase mParseCueTime = new Phase() {
+        @Override
+        public void parse(String line) {
+            int arrowAt = line.indexOf("-->");
+            if (arrowAt < 0) {
+                mCue = null;
+                mPhase = mParseCueId;
+                return;
+            }
+
+            String start = line.substring(0, arrowAt).trim();
+            // convert only initial and first other white-space to space
+            String rest = line.substring(arrowAt + 3)
+                    .replaceFirst("^\\s+", "").replaceFirst("\\s+", " ");
+            int spaceAt = rest.indexOf(' ');
+            String end = spaceAt > 0 ? rest.substring(0, spaceAt) : rest;
+            rest = spaceAt > 0 ? rest.substring(spaceAt + 1) : "";
+
+            mCue.mStartTimeMs = parseTimestampMs(start);
+            mCue.mEndTimeMs = parseTimestampMs(end);
+            for (String setting: rest.split(" +")) {
+                int colonAt = setting.indexOf(':');
+                if (colonAt <= 0 || colonAt == setting.length() - 1) {
+                    continue;
+                }
+                String name = setting.substring(0, colonAt);
+                String value = setting.substring(colonAt + 1);
+
+                if (name.equals("region")) {
+                    mCue.mRegionId = value;
+                } else if (name.equals("vertical")) {
+                    if (value.equals("rl")) {
+                        mCue.mWritingDirection =
+                            TextTrackCue.WRITING_DIRECTION_VERTICAL_RL;
+                    } else if (value.equals("lr")) {
+                        mCue.mWritingDirection =
+                            TextTrackCue.WRITING_DIRECTION_VERTICAL_LR;
+                    } else {
+                        log_warning("cue setting", name, "has invalid value", value);
+                    }
+                } else if (name.equals("line")) {
+                    try {
+                        int linePosition;
+                        /* TRICKY: we know that there are no spaces in value */
+                        assert(value.indexOf(' ') < 0);
+                        if (value.endsWith("%")) {
+                            linePosition = Integer.parseInt(
+                                    value.substring(0, value.length() - 1));
+                            if (linePosition < 0 || linePosition > 100) {
+                                log_warning("cue setting", name, "is out of range", value);
+                                continue;
+                            }
+                            mCue.mSnapToLines = false;
+                            mCue.mLinePosition = linePosition;
+                        } else {
+                            mCue.mSnapToLines = true;
+                            mCue.mLinePosition = Integer.parseInt(value);
+                        }
+                    } catch (NumberFormatException e) {
+                        log_warning("cue setting", name,
+                               "is not numeric or percentage", value);
+                    }
+                } else if (name.equals("position")) {
+                    try {
+                        mCue.mTextPosition = parseIntPercentage(value);
+                    } catch (NumberFormatException e) {
+                        log_warning("cue setting", name,
+                               "is not numeric or percentage", value);
+                    }
+                } else if (name.equals("size")) {
+                    try {
+                        mCue.mSize = parseIntPercentage(value);
+                    } catch (NumberFormatException e) {
+                        log_warning("cue setting", name,
+                               "is not numeric or percentage", value);
+                    }
+                } else if (name.equals("align")) {
+                    if (value.equals("start")) {
+                        mCue.mAlignment = TextTrackCue.ALIGNMENT_START;
+                    } else if (value.equals("middle")) {
+                        mCue.mAlignment = TextTrackCue.ALIGNMENT_MIDDLE;
+                    } else if (value.equals("end")) {
+                        mCue.mAlignment = TextTrackCue.ALIGNMENT_END;
+                    } else if (value.equals("left")) {
+                        mCue.mAlignment = TextTrackCue.ALIGNMENT_LEFT;
+                    } else if (value.equals("right")) {
+                        mCue.mAlignment = TextTrackCue.ALIGNMENT_RIGHT;
+                    } else {
+                        log_warning("cue setting", name, "has invalid value", value);
+                        continue;
+                    }
+                }
+            }
+
+            if (mCue.mLinePosition != null ||
+                    mCue.mSize != 100 ||
+                    (mCue.mWritingDirection !=
+                        TextTrackCue.WRITING_DIRECTION_HORIZONTAL)) {
+                mCue.mRegionId = "";
+            }
+
+            mPhase = mParseCueText;
+        }
+    };
+
+    /* also used for notes */
+    final private Phase mParseCueText = new Phase() {
+        @Override
+        public void parse(String line) {
+            if (line.length() == 0) {
+                yieldCue();
+                mPhase = mParseCueId;
+                return;
+            } else if (mCue != null) {
+                mCueTexts.add(line);
+            }
+        }
+    };
+
+    private void log_warning(
+            String nameType, String name, String message,
+            String subMessage, String value) {
+        Log.w(this.getClass().getName(), nameType + " '" + name + "' " +
+                message + " ('" + value + "' " + subMessage + ")");
+    }
+
+    private void log_warning(
+            String nameType, String name, String message, String value) {
+        Log.w(this.getClass().getName(), nameType + " '" + name + "' " +
+                message + " ('" + value + "')");
+    }
+
+    private void log_warning(String message, String value) {
+        Log.w(this.getClass().getName(), message + " ('" + value + "')");
+    }
+}
+
+/** @hide */
+interface WebVttCueListener {
+    void onCueParsed(TextTrackCue cue);
+    void onRegionParsed(TextTrackRegion region);
+}
+
+/** @hide */
+class WebVttTrack extends SubtitleTrack implements WebVttCueListener {
+    private static final String TAG = "WebVttTrack";
+
+    private final WebVttParser mParser = new WebVttParser(this);
+    private final UnstyledTextExtractor mExtractor =
+        new UnstyledTextExtractor();
+    private final Tokenizer mTokenizer = new Tokenizer(mExtractor);
+    private final Vector<Long> mTimestamps = new Vector<Long>();
+    private final WebVttRenderingWidget mRenderingWidget;
+
+    private final Map<String, TextTrackRegion> mRegions =
+        new HashMap<String, TextTrackRegion>();
+    private Long mCurrentRunID;
+
+    WebVttTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) {
+        super(format);
+
+        mRenderingWidget = renderingWidget;
+    }
+
+    @Override
+    public WebVttRenderingWidget getRenderingWidget() {
+        return mRenderingWidget;
+    }
+
+    @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);
+            }
+            mCurrentRunID = runID;
+            mParser.parse(data);
+            if (eos) {
+                finishedRun(runID);
+                mParser.eos();
+                mRegions.clear();
+                mCurrentRunID = null;
+            }
+        }
+    }
+
+    @Override
+    public void onCueParsed(TextTrackCue cue) {
+        synchronized (mParser) {
+            // resolve region
+            if (cue.mRegionId.length() != 0) {
+                cue.mRegion = mRegions.get(cue.mRegionId);
+            }
+
+            if (DEBUG) Log.v(TAG, "adding cue " + cue);
+
+            // tokenize text track string-lines into lines of spans
+            mTokenizer.reset();
+            for (String s: cue.mStrings) {
+                mTokenizer.tokenize(s);
+            }
+            cue.mLines = mExtractor.getText();
+            if (DEBUG) Log.v(TAG, cue.appendLinesToBuilder(
+                    cue.appendStringsToBuilder(
+                        new StringBuilder()).append(" simplified to: "))
+                            .toString());
+
+            // extract inner timestamps
+            for (TextTrackCueSpan[] line: cue.mLines) {
+                for (TextTrackCueSpan span: line) {
+                    if (span.mTimestampMs > cue.mStartTimeMs &&
+                            span.mTimestampMs < cue.mEndTimeMs &&
+                            !mTimestamps.contains(span.mTimestampMs)) {
+                        mTimestamps.add(span.mTimestampMs);
+                    }
+                }
+            }
+
+            if (mTimestamps.size() > 0) {
+                cue.mInnerTimesMs = new long[mTimestamps.size()];
+                for (int ix=0; ix < mTimestamps.size(); ++ix) {
+                    cue.mInnerTimesMs[ix] = mTimestamps.get(ix);
+                }
+                mTimestamps.clear();
+            } else {
+                cue.mInnerTimesMs = null;
+            }
+
+            cue.mRunID = mCurrentRunID;
+        }
+
+        addCue(cue);
+    }
+
+    @Override
+    public void onRegionParsed(TextTrackRegion region) {
+        synchronized(mParser) {
+            mRegions.put(region.mId, region);
+        }
+    }
+
+    @Override
+    public void updateView(Vector<SubtitleTrack.Cue> activeCues) {
+        if (!mVisible) {
+            // don't keep the state if we are not visible
+            return;
+        }
+
+        if (DEBUG && mTimeProvider != null) {
+            try {
+                Log.d(TAG, "at " +
+                        (mTimeProvider.getCurrentTimeUs(false, true) / 1000) +
+                        " ms the active cues are:");
+            } catch (IllegalStateException e) {
+                Log.d(TAG, "at (illegal state) the active cues are:");
+            }
+        }
+
+        mRenderingWidget.setActiveCues(activeCues);
+    }
+}
+
+/**
+ * Widget capable of rendering WebVTT captions.
+ *
+ * @hide
+ */
+class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.RenderingWidget {
+    private static final boolean DEBUG = false;
+    private static final int DEBUG_REGION_BACKGROUND = 0x800000FF;
+    private static final int DEBUG_CUE_BACKGROUND = 0x80FF0000;
+
+    /** WebVtt specifies line height as 5.3% of the viewport height. */
+    private static final float LINE_HEIGHT_RATIO = 0.0533f;
+
+    /** Map of active regions, used to determine enter/exit. */
+    private final ArrayMap<TextTrackRegion, RegionLayout> mRegionBoxes =
+            new ArrayMap<TextTrackRegion, RegionLayout>();
+
+    /** Map of active cues, used to determine enter/exit. */
+    private final ArrayMap<TextTrackCue, CueLayout> mCueBoxes =
+            new ArrayMap<TextTrackCue, CueLayout>();
+
+    /** 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;
+
+    /** Current font size, computed from font scaling factor and height. */
+    private float mFontSize;
+
+    /** Whether a caption style change listener is registered. */
+    private boolean mHasChangeListener;
+
+    public WebVttRenderingWidget(Context context) {
+        this(context, null);
+    }
+
+    public WebVttRenderingWidget(Context context, AttributeSet attrs) {
+        this(context, null, 0);
+    }
+
+    public WebVttRenderingWidget(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 = mManager.getUserStyle();
+        mFontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO;
+    }
+
+    @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 onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void setOnChangedListener(OnChangedListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            setVisibility(View.VISIBLE);
+        } else {
+            setVisibility(View.GONE);
+        }
+
+        manageChangeListener();
+    }
+
+    /**
+     * Manages whether this renderer is listening for caption style changes.
+     */
+    private void manageChangeListener() {
+        final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+        if (mHasChangeListener != needsListener) {
+            mHasChangeListener = needsListener;
+
+            if (needsListener) {
+                mManager.addCaptioningChangeListener(mCaptioningListener);
+
+                final CaptionStyle captionStyle = mManager.getUserStyle();
+                final float fontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO;
+                setCaptionStyle(captionStyle, fontSize);
+            } else {
+                mManager.removeCaptioningChangeListener(mCaptioningListener);
+            }
+        }
+    }
+
+    public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) {
+        final Context context = getContext();
+        final CaptionStyle captionStyle = mCaptionStyle;
+        final float fontSize = mFontSize;
+
+        prepForPrune();
+
+        // Ensure we have all necessary cue and region boxes.
+        final int count = activeCues.size();
+        for (int i = 0; i < count; i++) {
+            final TextTrackCue cue = (TextTrackCue) activeCues.get(i);
+            final TextTrackRegion region = cue.mRegion;
+            if (region != null) {
+                RegionLayout regionBox = mRegionBoxes.get(region);
+                if (regionBox == null) {
+                    regionBox = new RegionLayout(context, region, captionStyle, fontSize);
+                    mRegionBoxes.put(region, regionBox);
+                    addView(regionBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                }
+                regionBox.put(cue);
+            } else {
+                CueLayout cueBox = mCueBoxes.get(cue);
+                if (cueBox == null) {
+                    cueBox = new CueLayout(context, cue, captionStyle, fontSize);
+                    mCueBoxes.put(cue, cueBox);
+                    addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                }
+                cueBox.update();
+                cueBox.setOrder(i);
+            }
+        }
+
+        prune();
+
+        // Force measurement and layout.
+        final int width = getWidth();
+        final int height = getHeight();
+        setSize(width, height);
+
+        if (mListener != null) {
+            mListener.onChanged(this);
+        }
+    }
+
+    private void setCaptionStyle(CaptionStyle captionStyle, float fontSize) {
+        mCaptionStyle = captionStyle;
+        mFontSize = fontSize;
+
+        final int cueCount = mCueBoxes.size();
+        for (int i = 0; i < cueCount; i++) {
+            final CueLayout cueBox = mCueBoxes.valueAt(i);
+            cueBox.setCaptionStyle(captionStyle, fontSize);
+        }
+
+        final int regionCount = mRegionBoxes.size();
+        for (int i = 0; i < regionCount; i++) {
+            final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+            regionBox.setCaptionStyle(captionStyle, fontSize);
+        }
+    }
+
+    /**
+     * Remove inactive cues and regions.
+     */
+    private void prune() {
+        int regionCount = mRegionBoxes.size();
+        for (int i = 0; i < regionCount; i++) {
+            final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+            if (regionBox.prune()) {
+                removeView(regionBox);
+                mRegionBoxes.removeAt(i);
+                regionCount--;
+                i--;
+            }
+        }
+
+        int cueCount = mCueBoxes.size();
+        for (int i = 0; i < cueCount; i++) {
+            final CueLayout cueBox = mCueBoxes.valueAt(i);
+            if (!cueBox.isActive()) {
+                removeView(cueBox);
+                mCueBoxes.removeAt(i);
+                cueCount--;
+                i--;
+            }
+        }
+    }
+
+    /**
+     * Reset active cues and regions.
+     */
+    private void prepForPrune() {
+        final int regionCount = mRegionBoxes.size();
+        for (int i = 0; i < regionCount; i++) {
+            final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+            regionBox.prepForPrune();
+        }
+
+        final int cueCount = mCueBoxes.size();
+        for (int i = 0; i < cueCount; i++) {
+            final CueLayout cueBox = mCueBoxes.valueAt(i);
+            cueBox.prepForPrune();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        final int regionCount = mRegionBoxes.size();
+        for (int i = 0; i < regionCount; i++) {
+            final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+            regionBox.measureForParent(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        final int cueCount = mCueBoxes.size();
+        for (int i = 0; i < cueCount; i++) {
+            final CueLayout cueBox = mCueBoxes.valueAt(i);
+            cueBox.measureForParent(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int viewportWidth = r - l;
+        final int viewportHeight = b - t;
+
+        setCaptionStyle(mCaptionStyle,
+                mManager.getFontScale() * LINE_HEIGHT_RATIO * viewportHeight);
+
+        final int regionCount = mRegionBoxes.size();
+        for (int i = 0; i < regionCount; i++) {
+            final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+            layoutRegion(viewportWidth, viewportHeight, regionBox);
+        }
+
+        final int cueCount = mCueBoxes.size();
+        for (int i = 0; i < cueCount; i++) {
+            final CueLayout cueBox = mCueBoxes.valueAt(i);
+            layoutCue(viewportWidth, viewportHeight, cueBox);
+        }
+    }
+
+    /**
+     * Lays out a region within the viewport. The region handles layout for
+     * contained cues.
+     */
+    private void layoutRegion(
+            int viewportWidth, int viewportHeight,
+            RegionLayout regionBox) {
+        final TextTrackRegion region = regionBox.getRegion();
+        final int regionHeight = regionBox.getMeasuredHeight();
+        final int regionWidth = regionBox.getMeasuredWidth();
+
+        // TODO: Account for region anchor point.
+        final float x = region.mViewportAnchorPointX;
+        final float y = region.mViewportAnchorPointY;
+        final int left = (int) (x * (viewportWidth - regionWidth) / 100);
+        final int top = (int) (y * (viewportHeight - regionHeight) / 100);
+
+        regionBox.layout(left, top, left + regionWidth, top + regionHeight);
+    }
+
+    /**
+     * Lays out a cue within the viewport.
+     */
+    private void layoutCue(
+            int viewportWidth, int viewportHeight, CueLayout cueBox) {
+        final TextTrackCue cue = cueBox.getCue();
+        final int direction = getLayoutDirection();
+        final int absAlignment = resolveCueAlignment(direction, cue.mAlignment);
+        final boolean cueSnapToLines = cue.mSnapToLines;
+
+        int size = 100 * cueBox.getMeasuredWidth() / viewportWidth;
+
+        // Determine raw x-position.
+        int xPosition;
+        switch (absAlignment) {
+            case TextTrackCue.ALIGNMENT_LEFT:
+                xPosition = cue.mTextPosition;
+                break;
+            case TextTrackCue.ALIGNMENT_RIGHT:
+                xPosition = cue.mTextPosition - size;
+                break;
+            case TextTrackCue.ALIGNMENT_MIDDLE:
+            default:
+                xPosition = cue.mTextPosition - size / 2;
+                break;
+        }
+
+        // Adjust x-position for layout.
+        if (direction == LAYOUT_DIRECTION_RTL) {
+            xPosition = 100 - xPosition;
+        }
+
+        // If the text track cue snap-to-lines flag is set, adjust
+        // x-position and size for padding. This is equivalent to placing the
+        // cue within the title-safe area.
+        if (cueSnapToLines) {
+            final int paddingLeft = 100 * getPaddingLeft() / viewportWidth;
+            final int paddingRight = 100 * getPaddingRight() / viewportWidth;
+            if (xPosition < paddingLeft && xPosition + size > paddingLeft) {
+                xPosition += paddingLeft;
+                size -= paddingLeft;
+            }
+            final float rightEdge = 100 - paddingRight;
+            if (xPosition < rightEdge && xPosition + size > rightEdge) {
+                size -= paddingRight;
+            }
+        }
+
+        // Compute absolute left position and width.
+        final int left = xPosition * viewportWidth / 100;
+        final int width = size * viewportWidth / 100;
+
+        // Determine initial y-position.
+        final int yPosition = calculateLinePosition(cueBox);
+
+        // Compute absolute final top position and height.
+        final int height = cueBox.getMeasuredHeight();
+        final int top;
+        if (yPosition < 0) {
+            // TODO: This needs to use the actual height of prior boxes.
+            top = viewportHeight + yPosition * height;
+        } else {
+            top = yPosition * (viewportHeight - height) / 100;
+        }
+
+        // Layout cue in final position.
+        cueBox.layout(left, top, left + width, top + height);
+    }
+
+    /**
+     * Calculates the line position for a cue.
+     * <p>
+     * If the resulting position is negative, it represents a bottom-aligned
+     * position relative to the number of active cues. Otherwise, it represents
+     * a percentage [0-100] of the viewport height.
+     */
+    private int calculateLinePosition(CueLayout cueBox) {
+        final TextTrackCue cue = cueBox.getCue();
+        final Integer linePosition = cue.mLinePosition;
+        final boolean snapToLines = cue.mSnapToLines;
+        final boolean autoPosition = (linePosition == null);
+
+        if (!snapToLines && !autoPosition && (linePosition < 0 || linePosition > 100)) {
+            // Invalid line position defaults to 100.
+            return 100;
+        } else if (!autoPosition) {
+            // Use the valid, supplied line position.
+            return linePosition;
+        } else if (!snapToLines) {
+            // Automatic, non-snapped line position defaults to 100.
+            return 100;
+        } else {
+            // Automatic snapped line position uses active cue order.
+            return -(cueBox.mOrder + 1);
+        }
+    }
+
+    /**
+     * Resolves cue alignment according to the specified layout direction.
+     */
+    private static int resolveCueAlignment(int layoutDirection, int alignment) {
+        switch (alignment) {
+            case TextTrackCue.ALIGNMENT_START:
+                return layoutDirection == View.LAYOUT_DIRECTION_LTR ?
+                        TextTrackCue.ALIGNMENT_LEFT : TextTrackCue.ALIGNMENT_RIGHT;
+            case TextTrackCue.ALIGNMENT_END:
+                return layoutDirection == View.LAYOUT_DIRECTION_LTR ?
+                        TextTrackCue.ALIGNMENT_RIGHT : TextTrackCue.ALIGNMENT_LEFT;
+        }
+        return alignment;
+    }
+
+    private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+        @Override
+        public void onFontScaleChanged(float fontScale) {
+            final float fontSize = fontScale * getHeight() * LINE_HEIGHT_RATIO;
+            setCaptionStyle(mCaptionStyle, fontSize);
+        }
+
+        @Override
+        public void onUserStyleChanged(CaptionStyle userStyle) {
+            setCaptionStyle(userStyle, mFontSize);
+        }
+    };
+
+    /**
+     * A text track region represents a portion of the video viewport and
+     * provides a rendering area for text track cues.
+     */
+    private static class RegionLayout extends LinearLayout {
+        private final ArrayList<CueLayout> mRegionCueBoxes = new ArrayList<CueLayout>();
+        private final TextTrackRegion mRegion;
+
+        private CaptionStyle mCaptionStyle;
+        private float mFontSize;
+
+        public RegionLayout(Context context, TextTrackRegion region, CaptionStyle captionStyle,
+                float fontSize) {
+            super(context);
+
+            mRegion = region;
+            mCaptionStyle = captionStyle;
+            mFontSize = fontSize;
+
+            // TODO: Add support for vertical text
+            setOrientation(VERTICAL);
+
+            if (DEBUG) {
+                setBackgroundColor(DEBUG_REGION_BACKGROUND);
+            }
+        }
+
+        public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) {
+            mCaptionStyle = captionStyle;
+            mFontSize = fontSize;
+
+            final int cueCount = mRegionCueBoxes.size();
+            for (int i = 0; i < cueCount; i++) {
+                final CueLayout cueBox = mRegionCueBoxes.get(i);
+                cueBox.setCaptionStyle(captionStyle, fontSize);
+            }
+        }
+
+        /**
+         * Performs the parent's measurement responsibilities, then
+         * automatically performs its own measurement.
+         */
+        public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) {
+            final TextTrackRegion region = mRegion;
+            final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+            final int specHeight = MeasureSpec.getSize(heightMeasureSpec);
+            final int width = (int) region.mWidth;
+
+            // Determine the absolute maximum region size as the requested size.
+            final int size = width * specWidth / 100;
+
+            widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST);
+            measure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        /**
+         * Prepares this region for pruning by setting all tracks as inactive.
+         * <p>
+         * Tracks that are added or updated using {@link #put(TextTrackCue)}
+         * after this calling this method will be marked as active.
+         */
+        public void prepForPrune() {
+            final int cueCount = mRegionCueBoxes.size();
+            for (int i = 0; i < cueCount; i++) {
+                final CueLayout cueBox = mRegionCueBoxes.get(i);
+                cueBox.prepForPrune();
+            }
+        }
+
+        /**
+         * Adds a {@link TextTrackCue} to this region. If the track had already
+         * been added, updates its active state.
+         *
+         * @param cue
+         */
+        public void put(TextTrackCue cue) {
+            final int cueCount = mRegionCueBoxes.size();
+            for (int i = 0; i < cueCount; i++) {
+                final CueLayout cueBox = mRegionCueBoxes.get(i);
+                if (cueBox.getCue() == cue) {
+                    cueBox.update();
+                    return;
+                }
+            }
+
+            final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize);
+            mRegionCueBoxes.add(cueBox);
+            addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+
+            if (getChildCount() > mRegion.mLines) {
+                removeViewAt(0);
+            }
+        }
+
+        /**
+         * Remove all inactive tracks from this region.
+         *
+         * @return true if this region is empty and should be pruned
+         */
+        public boolean prune() {
+            int cueCount = mRegionCueBoxes.size();
+            for (int i = 0; i < cueCount; i++) {
+                final CueLayout cueBox = mRegionCueBoxes.get(i);
+                if (!cueBox.isActive()) {
+                    mRegionCueBoxes.remove(i);
+                    removeView(cueBox);
+                    cueCount--;
+                    i--;
+                }
+            }
+
+            return mRegionCueBoxes.isEmpty();
+        }
+
+        /**
+         * @return the region data backing this layout
+         */
+        public TextTrackRegion getRegion() {
+            return mRegion;
+        }
+    }
+
+    /**
+     * A text track cue is the unit of time-sensitive data in a text track,
+     * corresponding for instance for subtitles and captions to the text that
+     * appears at a particular time and disappears at another time.
+     * <p>
+     * A single cue may contain multiple {@link SpanLayout}s, each representing a
+     * single line of text.
+     */
+    private static class CueLayout extends LinearLayout {
+        public final TextTrackCue mCue;
+
+        private CaptionStyle mCaptionStyle;
+        private float mFontSize;
+
+        private boolean mActive;
+        private int mOrder;
+
+        public CueLayout(
+                Context context, TextTrackCue cue, CaptionStyle captionStyle, float fontSize) {
+            super(context);
+
+            mCue = cue;
+            mCaptionStyle = captionStyle;
+            mFontSize = fontSize;
+
+            // TODO: Add support for vertical text.
+            final boolean horizontal = cue.mWritingDirection
+                    == TextTrackCue.WRITING_DIRECTION_HORIZONTAL;
+            setOrientation(horizontal ? VERTICAL : HORIZONTAL);
+
+            switch (cue.mAlignment) {
+                case TextTrackCue.ALIGNMENT_END:
+                    setGravity(Gravity.END);
+                    break;
+                case TextTrackCue.ALIGNMENT_LEFT:
+                    setGravity(Gravity.LEFT);
+                    break;
+                case TextTrackCue.ALIGNMENT_MIDDLE:
+                    setGravity(horizontal
+                            ? Gravity.CENTER_HORIZONTAL : Gravity.CENTER_VERTICAL);
+                    break;
+                case TextTrackCue.ALIGNMENT_RIGHT:
+                    setGravity(Gravity.RIGHT);
+                    break;
+                case TextTrackCue.ALIGNMENT_START:
+                    setGravity(Gravity.START);
+                    break;
+            }
+
+            if (DEBUG) {
+                setBackgroundColor(DEBUG_CUE_BACKGROUND);
+            }
+
+            update();
+        }
+
+        public void setCaptionStyle(CaptionStyle style, float fontSize) {
+            mCaptionStyle = style;
+            mFontSize = fontSize;
+
+            final int n = getChildCount();
+            for (int i = 0; i < n; i++) {
+                final View child = getChildAt(i);
+                if (child instanceof SpanLayout) {
+                    ((SpanLayout) child).setCaptionStyle(style, fontSize);
+                }
+            }
+        }
+
+        public void prepForPrune() {
+            mActive = false;
+        }
+
+        public void update() {
+            mActive = true;
+
+            removeAllViews();
+
+            final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment);
+            final Alignment alignment;
+            switch (cueAlignment) {
+                case TextTrackCue.ALIGNMENT_LEFT:
+                    alignment = Alignment.ALIGN_LEFT;
+                    break;
+                case TextTrackCue.ALIGNMENT_RIGHT:
+                    alignment = Alignment.ALIGN_RIGHT;
+                    break;
+                case TextTrackCue.ALIGNMENT_MIDDLE:
+                default:
+                    alignment = Alignment.ALIGN_CENTER;
+            }
+
+            final CaptionStyle captionStyle = mCaptionStyle;
+            final float fontSize = mFontSize;
+            final TextTrackCueSpan[][] lines = mCue.mLines;
+            final int lineCount = lines.length;
+            for (int i = 0; i < lineCount; i++) {
+                final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]);
+                lineBox.setAlignment(alignment);
+                lineBox.setCaptionStyle(captionStyle, fontSize);
+
+                addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+            }
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        /**
+         * Performs the parent's measurement responsibilities, then
+         * automatically performs its own measurement.
+         */
+        public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) {
+            final TextTrackCue cue = mCue;
+            final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+            final int specHeight = MeasureSpec.getSize(heightMeasureSpec);
+            final int direction = getLayoutDirection();
+            final int absAlignment = resolveCueAlignment(direction, cue.mAlignment);
+
+            // Determine the maximum size of cue based on its starting position
+            // and the direction in which it grows.
+            final int maximumSize;
+            switch (absAlignment) {
+                case TextTrackCue.ALIGNMENT_LEFT:
+                    maximumSize = 100 - cue.mTextPosition;
+                    break;
+                case TextTrackCue.ALIGNMENT_RIGHT:
+                    maximumSize = cue.mTextPosition;
+                    break;
+                case TextTrackCue.ALIGNMENT_MIDDLE:
+                    if (cue.mTextPosition <= 50) {
+                        maximumSize = cue.mTextPosition * 2;
+                    } else {
+                        maximumSize = (100 - cue.mTextPosition) * 2;
+                    }
+                    break;
+                default:
+                    maximumSize = 0;
+            }
+
+            // Determine absolute maximum cue size as the smaller of the
+            // requested size and the maximum theoretical size.
+            final int size = Math.min(cue.mSize, maximumSize) * specWidth / 100;
+            widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST);
+            measure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        /**
+         * Sets the order of this cue in the list of active cues.
+         *
+         * @param order the order of this cue in the list of active cues
+         */
+        public void setOrder(int order) {
+            mOrder = order;
+        }
+
+        /**
+         * @return whether this cue is marked as active
+         */
+        public boolean isActive() {
+            return mActive;
+        }
+
+        /**
+         * @return the cue data backing this layout
+         */
+        public TextTrackCue getCue() {
+            return mCue;
+        }
+    }
+
+    /**
+     * A text track line represents a single line of text within a cue.
+     * <p>
+     * A single line may contain multiple spans, each representing a section of
+     * text that may be enabled or disabled at a particular time.
+     */
+    private static class SpanLayout extends SubtitleView {
+        private final SpannableStringBuilder mBuilder = new SpannableStringBuilder();
+        private final TextTrackCueSpan[] mSpans;
+
+        public SpanLayout(Context context, TextTrackCueSpan[] spans) {
+            super(context);
+
+            mSpans = spans;
+
+            update();
+        }
+
+        public void update() {
+            final SpannableStringBuilder builder = mBuilder;
+            final TextTrackCueSpan[] spans = mSpans;
+
+            builder.clear();
+            builder.clearSpans();
+
+            final int spanCount = spans.length;
+            for (int i = 0; i < spanCount; i++) {
+                final TextTrackCueSpan span = spans[i];
+                if (span.mEnabled) {
+                    builder.append(spans[i].mText);
+                }
+            }
+
+            setText(builder);
+        }
+
+        public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) {
+            setBackgroundColor(captionStyle.backgroundColor);
+            setForegroundColor(captionStyle.foregroundColor);
+            setEdgeColor(captionStyle.edgeColor);
+            setEdgeType(captionStyle.edgeType);
+            setTypeface(captionStyle.getTypeface());
+            setTextSize(fontSize);
+        }
+    }
+}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 52c0c2d..12f7bd9 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -120,6 +120,14 @@
             .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
 
     /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * UUID for Loudness Enhancer
+     */
+    public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
+              .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1");
+
+    /**
      * Null effect UUID. Used when the UUID for effect type of
      * @hide
      */
diff --git a/media/java/android/media/audiofx/LoudnessEnhancer.java b/media/java/android/media/audiofx/LoudnessEnhancer.java
new file mode 100644
index 0000000..eb2fb75
--- /dev/null
+++ b/media/java/android/media/audiofx/LoudnessEnhancer.java
@@ -0,0 +1,291 @@
+/*
+ * 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 android.media.audiofx;
+
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.media.audiofx.AudioEffect;
+import android.util.Log;
+
+import java.util.StringTokenizer;
+
+
+/**
+ * LoudnessEnhancer is an audio effect for increasing audio loudness.
+ * The processing is parametrized by a target gain value, which determines the maximum amount
+ * by which an audio signal will be amplified; signals amplified outside of the sample
+ * range supported by the platform are compressed.
+ * An application creates a LoudnessEnhancer object to instantiate and control a
+ * this audio effect in the audio framework.
+ * To attach the LoudnessEnhancer to a particular AudioTrack or MediaPlayer,
+ * specify the audio session ID of this AudioTrack or MediaPlayer when constructing the effect
+ * (see {@link AudioTrack#getAudioSessionId()} and {@link MediaPlayer#getAudioSessionId()}).
+ */
+
+public class LoudnessEnhancer extends AudioEffect {
+
+    private final static String TAG = "LoudnessEnhancer";
+
+    // These parameter constants must be synchronized with those in
+    // /system/media/audio_effects/include/audio_effects/effect_loudnessenhancer.h
+    /**
+     * The maximum gain applied applied to the signal to process.
+     * It is expressed in millibels (100mB = 1dB) where 0mB corresponds to no amplification.
+     */
+    public static final int PARAM_TARGET_GAIN_MB = 0;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change events
+     * from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * @hide
+     * Class constructor.
+     * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+     * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public LoudnessEnhancer(int audioSession)
+            throws IllegalStateException, IllegalArgumentException,
+                UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, 0, audioSession);
+
+        if (audioSession == 0) {
+            Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+        }
+    }
+
+    /**
+     * @hide
+     * Class constructor for the LoudnessEnhancer audio effect.
+     * @param priority the priority level requested by the application for controlling the
+     * LoudnessEnhancer engine. As the same engine can be shared by several applications,
+     * this parameter indicates how much the requesting application needs control of effect
+     * parameters. The normal priority is 0, above normal is a positive number, below normal a
+     * negative number.
+     * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+     * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public LoudnessEnhancer(int priority, int audioSession)
+            throws IllegalStateException, IllegalArgumentException,
+                UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        if (audioSession == 0) {
+            Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+        }
+    }
+
+    /**
+     * Set the target gain for the audio effect.
+     * The target gain is the maximum value by which a sample value will be amplified when the
+     * effect is enabled.
+     * @param gainmB the effect target gain expressed in mB. 0mB corresponds to no amplification.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setTargetGain(int gainmB)
+            throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_TARGET_GAIN_MB, gainmB));
+    }
+
+    /**
+     * Return the target gain.
+     * @return the effect target gain expressed in mB.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public float getTargetGain()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] value = new int[1];
+        checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+        return value[0];
+    }
+
+    /**
+     * @hide
+     * The OnParameterChangeListener interface defines a method called by the LoudnessEnhancer
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * LoudnessEnhancer engine.
+         * @param effect the LoudnessEnhancer on which the interface is registered.
+         * @param param ID of the modified parameter. See {@link #PARAM_GENERIC_PARAM1} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(LoudnessEnhancer effect, int param, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            // only notify when the parameter was successfully change
+            if (status != AudioEffect.SUCCESS) {
+                return;
+            }
+            OnParameterChangeListener l = null;
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                int v = Integer.MIN_VALUE;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+                if (p != -1 && v != Integer.MIN_VALUE) {
+                    l.onParameterChange(LoudnessEnhancer.this, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+            mParamListener = listener;
+        }
+    }
+
+    /**
+     * @hide
+     * The Settings class regroups the LoudnessEnhancer parameters. It is used in
+     * conjunction with the getProperties() and setProperties() methods to backup and restore
+     * all parameters in a single call.
+     */
+    public static class Settings {
+        public int targetGainmB;
+
+        public Settings() {
+        }
+
+        /**
+         * Settings class constructor from a key=value; pairs formatted string. The string is
+         * typically returned by Settings.toString() method.
+         * @throws IllegalArgumentException if the string is not correctly formatted.
+         */
+        public Settings(String settings) {
+            StringTokenizer st = new StringTokenizer(settings, "=;");
+            //int tokens = st.countTokens();
+            if (st.countTokens() != 3) {
+                throw new IllegalArgumentException("settings: " + settings);
+            }
+            String key = st.nextToken();
+            if (!key.equals("LoudnessEnhancer")) {
+                throw new IllegalArgumentException(
+                        "invalid settings for LoudnessEnhancer: " + key);
+            }
+            try {
+                key = st.nextToken();
+                if (!key.equals("targetGainmB")) {
+                    throw new IllegalArgumentException("invalid key name: " + key);
+                }
+                targetGainmB = Integer.parseInt(st.nextToken());
+             } catch (NumberFormatException nfe) {
+                throw new IllegalArgumentException("invalid value for key: " + key);
+            }
+        }
+
+        @Override
+        public String toString() {
+            String str = new String (
+                    "LoudnessEnhancer"+
+                    ";targetGainmB="+Integer.toString(targetGainmB)
+                    );
+            return str;
+        }
+    };
+
+
+    /**
+     * @hide
+     * Gets the LoudnessEnhancer properties. This method is useful when a snapshot of current
+     * effect settings must be saved by the application.
+     * @return a LoudnessEnhancer.Settings object containing all current parameters values
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public LoudnessEnhancer.Settings getProperties()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        Settings settings = new Settings();
+        int[] value = new int[1];
+        checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+        settings.targetGainmB = value[0];
+        return settings;
+    }
+
+    /**
+     * @hide
+     * Sets the LoudnessEnhancer properties. This method is useful when bass boost settings
+     * have to be applied from a previous backup.
+     * @param settings a LoudnessEnhancer.Settings object containing the properties to apply
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setProperties(LoudnessEnhancer.Settings settings)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_TARGET_GAIN_MB, settings.targetGainmB));
+    }
+}
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 9197ed8..fb7f718 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -57,6 +57,11 @@
  * anymore to free up native resources associated to the Visualizer instance.
  * <p>Creating a Visualizer on the output mix (audio session 0) requires permission
  * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}
+ * <p>The Visualizer class can also be used to perform measurements on the audio being played back.
+ * The measurements to perform are defined by setting a mask of the requested measurement modes with
+ * {@link #setMeasurementMode(int)}. Supported values are {@link #MEASUREMENT_MODE_NONE} to cancel
+ * any measurement, and {@link #MEASUREMENT_MODE_PEAK_RMS} for peak and RMS monitoring.
+ * Measurements can be retrieved through {@link #getMeasurementPeakRms(MeasurementPeakRms)}.
  */
 
 public class Visualizer {
@@ -93,6 +98,19 @@
      */
     public static final int SCALING_MODE_AS_PLAYED = 1;
 
+    /**
+     * Defines a measurement mode in which no measurements are performed.
+     */
+    public static final int MEASUREMENT_MODE_NONE = 0;
+
+    /**
+     * Defines a measurement mode which computes the peak and RMS value in mB, where 0mB is the
+     * maximum sample value, and -9600mB is the minimum value.
+     * Values for peak and RMS can be retrieved with
+     * {@link #getMeasurementPeakRms(MeasurementPeakRms)}.
+     */
+    public static final int MEASUREMENT_MODE_PEAK_RMS = 1 << 0;
+
     // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
     private static final int NATIVE_EVENT_PCM_CAPTURE = 0;
     private static final int NATIVE_EVENT_FFT_CAPTURE = 1;
@@ -350,6 +368,43 @@
     }
 
     /**
+     * Sets the combination of measurement modes to be performed by this audio effect.
+     * @param mode a mask of the measurements to perform. The valid values are
+     *     {@link #MEASUREMENT_MODE_NONE} (to cancel any measurement)
+     *     or {@link #MEASUREMENT_MODE_PEAK_RMS}.
+     * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE} in case of failure.
+     * @throws IllegalStateException
+     */
+    public int setMeasurementMode(int mode)
+            throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState == STATE_UNINITIALIZED) {
+                throw(new IllegalStateException("setMeasurementMode() called in wrong state: "
+                        + mState));
+            }
+            return native_setMeasurementMode(mode);
+        }
+    }
+
+    /**
+     * Returns the current measurement modes performed by this audio effect
+     * @return the mask of the measurements,
+     *     {@link #MEASUREMENT_MODE_NONE} (when no measurements are performed)
+     *     or {@link #MEASUREMENT_MODE_PEAK_RMS}.
+     * @throws IllegalStateException
+     */
+    public int getMeasurementMode()
+            throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState == STATE_UNINITIALIZED) {
+                throw(new IllegalStateException("getMeasurementMode() called in wrong state: "
+                        + mState));
+            }
+            return native_getMeasurementMode();
+        }
+    }
+
+    /**
      * Returns the sampling rate of the captured audio.
      * @return the sampling rate in milliHertz.
      */
@@ -437,6 +492,46 @@
         }
     }
 
+    /**
+     * A class to store peak and RMS values.
+     * Peak and RMS are expressed in mB, as described in the
+     * {@link Visualizer#MEASUREMENT_MODE_PEAK_RMS} measurement mode.
+     */
+    public static final class MeasurementPeakRms {
+        /**
+         * The peak value in mB.
+         */
+        public int mPeak;
+        /**
+         * The RMS value in mB.
+         */
+        public int mRms;
+    }
+
+    /**
+     * Retrieves the latest peak and RMS measurement.
+     * Sets the peak and RMS fields of the supplied {@link Visualizer.MeasurementPeakRms} to the
+     * latest measured values.
+     * @param measurement a non-null {@link Visualizer.MeasurementPeakRms} instance to store
+     *    the measurement values.
+     * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+     *    {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+     *    in case of failure.
+     */
+    public int getMeasurementPeakRms(MeasurementPeakRms measurement) {
+        if (measurement == null) {
+            Log.e(TAG, "Cannot store measurements in a null object");
+            return ERROR_BAD_VALUE;
+        }
+        synchronized (mStateLock) {
+            if (mState != STATE_ENABLED) {
+                throw (new IllegalStateException("getMeasurementPeakRms() called in wrong state: "
+                        + mState));
+            }
+            return native_getPeakRms(measurement);
+        }
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
@@ -640,12 +735,18 @@
 
     private native final int native_getScalingMode();
 
+    private native final int native_setMeasurementMode(int mode);
+
+    private native final int native_getMeasurementMode();
+
     private native final int native_getSamplingRate();
 
     private native final int native_getWaveForm(byte[] waveform);
 
     private native final int native_getFft(byte[] fft);
 
+    private native final int native_getPeakRms(MeasurementPeakRms measurement);
+
     private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft);
 
     //---------------------------------------------------------
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 416a2a1..63a61e2 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
+    android_media_ImageReader.cpp \
     android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
     android_media_MediaCodecList.cpp \
@@ -56,6 +57,8 @@
     frameworks/av/media/libstagefright/codecs/amrnb/common/include \
     frameworks/av/media/mtp \
     frameworks/native/include/media/openmax \
+    $(call include-path-for, libhardware)/hardware \
+    system/media/camera/include \
     $(PV_INCLUDES) \
     $(JNI_H_INCLUDE) \
     $(call include-path-for, corecg graphics)
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
new file mode 100644
index 0000000..0030dbd
--- /dev/null
+++ b/media/jni/android_media_ImageReader.cpp
@@ -0,0 +1,879 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ImageReader_JNI"
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <utils/List.h>
+#include <utils/String8.h>
+
+#include <cstdio>
+
+#include <gui/CpuConsumer.h>
+#include <gui/Surface.h>
+#include <camera3.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
+#define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID       "mNativeContext"
+#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mLockedBuffer"
+#define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID       "mTimestamp"
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+enum {
+    IMAGE_READER_MAX_NUM_PLANES = 3,
+};
+
+enum {
+    ACQUIRE_SUCCESS = 0,
+    ACQUIRE_NO_BUFFERS = 1,
+    ACQUIRE_MAX_IMAGES = 2,
+};
+
+static struct {
+    jfieldID mNativeContext;
+    jmethodID postEventFromNative;
+} gImageReaderClassInfo;
+
+static struct {
+    jfieldID mLockedBuffer;
+    jfieldID mTimestamp;
+} gSurfaceImageClassInfo;
+
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} gSurfacePlaneClassInfo;
+
+// ----------------------------------------------------------------------------
+
+class JNIImageReaderContext : public CpuConsumer::FrameAvailableListener
+{
+public:
+    JNIImageReaderContext(JNIEnv* env, jobject weakThiz, jclass clazz, int maxImages);
+
+    virtual ~JNIImageReaderContext();
+
+    virtual void onFrameAvailable();
+
+    CpuConsumer::LockedBuffer* getLockedBuffer();
+
+    void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer);
+
+    void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; }
+    CpuConsumer* getCpuConsumer() { return mConsumer.get(); }
+
+    void setBufferQueue(const sp<BufferQueue>& bq) { mBufferQueue = bq; }
+    BufferQueue* getBufferQueue() { return mBufferQueue.get(); }
+
+    void setBufferFormat(int format) { mFormat = format; }
+    int getBufferFormat() { return mFormat; }
+
+    void setBufferWidth(int width) { mWidth = width; }
+    int getBufferWidth() { return mWidth; }
+
+    void setBufferHeight(int height) { mHeight = height; }
+    int getBufferHeight() { return mHeight; }
+
+private:
+    static JNIEnv* getJNIEnv(bool* needsDetach);
+    static void detachJNI();
+
+    List<CpuConsumer::LockedBuffer*> mBuffers;
+    sp<CpuConsumer> mConsumer;
+    sp<BufferQueue> mBufferQueue;
+    jobject mWeakThiz;
+    jclass mClazz;
+    int mFormat;
+    int mWidth;
+    int mHeight;
+};
+
+JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env,
+        jobject weakThiz, jclass clazz, int maxImages) :
+    mWeakThiz(env->NewGlobalRef(weakThiz)),
+    mClazz((jclass)env->NewGlobalRef(clazz)) {
+    for (int i = 0; i < maxImages; i++) {
+        CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer;
+        mBuffers.push_back(buffer);
+    }
+}
+
+JNIEnv* JNIImageReaderContext::getJNIEnv(bool* needsDetach) {
+    LOG_ALWAYS_FATAL_IF(needsDetach == NULL, "needsDetach is null!!!");
+    *needsDetach = false;
+    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("thread attach failed: %#x", result);
+            return NULL;
+        }
+        *needsDetach = true;
+    }
+    return env;
+}
+
+void JNIImageReaderContext::detachJNI() {
+    JavaVM* vm = AndroidRuntime::getJavaVM();
+    int result = vm->DetachCurrentThread();
+    if (result != JNI_OK) {
+        ALOGE("thread detach failed: %#x", result);
+    }
+}
+
+CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() {
+    if (mBuffers.empty()) {
+        return NULL;
+    }
+    // Return a LockedBuffer pointer and remove it from the list
+    List<CpuConsumer::LockedBuffer*>::iterator it = mBuffers.begin();
+    CpuConsumer::LockedBuffer* buffer = *it;
+    mBuffers.erase(it);
+    return buffer;
+}
+
+void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) {
+    mBuffers.push_back(buffer);
+}
+
+JNIImageReaderContext::~JNIImageReaderContext() {
+    bool needsDetach = false;
+    JNIEnv* env = getJNIEnv(&needsDetach);
+    if (env != NULL) {
+        env->DeleteGlobalRef(mWeakThiz);
+        env->DeleteGlobalRef(mClazz);
+    } else {
+        ALOGW("leaking JNI object references");
+    }
+    if (needsDetach) {
+        detachJNI();
+    }
+
+    // Delete LockedBuffers
+    for (List<CpuConsumer::LockedBuffer *>::iterator it = mBuffers.begin();
+            it != mBuffers.end(); it++) {
+        delete *it;
+    }
+    mBuffers.clear();
+    mConsumer.clear();
+}
+
+void JNIImageReaderContext::onFrameAvailable()
+{
+    ALOGV("%s: frame available", __FUNCTION__);
+    bool needsDetach = false;
+    JNIEnv* env = getJNIEnv(&needsDetach);
+    if (env != NULL) {
+        env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz);
+    } else {
+        ALOGW("onFrameAvailable event will not posted");
+    }
+    if (needsDetach) {
+        detachJNI();
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+extern "C" {
+
+static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz)
+{
+    JNIImageReaderContext *ctx;
+    ctx = reinterpret_cast<JNIImageReaderContext *>
+              (env->GetLongField(thiz, gImageReaderClassInfo.mNativeContext));
+    return ctx;
+}
+
+static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz)
+{
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
+        return NULL;
+    }
+    return ctx->getCpuConsumer();
+}
+
+static BufferQueue* ImageReader_getBufferQueue(JNIEnv* env, jobject thiz)
+{
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
+        return NULL;
+    }
+    return ctx->getBufferQueue();
+}
+
+static void ImageReader_setNativeContext(JNIEnv* env,
+        jobject thiz, sp<JNIImageReaderContext> ctx)
+{
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* const p = ImageReader_getContext(env, thiz);
+    if (ctx != 0) {
+        ctx->incStrong((void*)ImageReader_setNativeContext);
+    }
+    if (p) {
+        p->decStrong((void*)ImageReader_setNativeContext);
+    }
+    env->SetLongField(thiz, gImageReaderClassInfo.mNativeContext,
+            reinterpret_cast<jlong>(ctx.get()));
+}
+
+static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image)
+{
+    return reinterpret_cast<CpuConsumer::LockedBuffer*>(
+            env->GetLongField(image, gSurfaceImageClassInfo.mLockedBuffer));
+}
+
+static void Image_setBuffer(JNIEnv* env, jobject thiz,
+        const CpuConsumer::LockedBuffer* buffer)
+{
+    env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer));
+}
+
+// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
+// graphics.h, need convert to the one defined in graphics.h here.
+static int Image_getPixelFormat(JNIEnv* env, int format)
+{
+    int jpegFormat, rawSensorFormat;
+    jfieldID fid;
+
+    ALOGV("%s: format = 0x%x", __FUNCTION__, format);
+
+    jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
+    ALOG_ASSERT(imageFormatClazz != NULL);
+
+    fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
+    jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
+    fid = env->GetStaticFieldID(imageFormatClazz, "RAW_SENSOR", "I");
+    rawSensorFormat = env->GetStaticIntField(imageFormatClazz, fid);
+
+    // Translate the JPEG to BLOB for camera purpose, an add more if more mismatch is found.
+    if (format == jpegFormat) {
+        format = HAL_PIXEL_FORMAT_BLOB;
+    }
+    // Same thing for RAW_SENSOR format
+    if (format == rawSensorFormat) {
+        format = HAL_PIXEL_FORMAT_RAW_SENSOR;
+    }
+
+    return format;
+}
+
+static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer)
+{
+    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
+    uint32_t size = 0;
+    uint32_t width = buffer->width;
+    uint8_t* jpegBuffer = buffer->data;
+
+    // First check for JPEG transport header at the end of the buffer
+    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+    struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
+    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+        size = blob->jpeg_size;
+        ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+    }
+
+    // failed to find size, default to whole buffer
+    if (size == 0) {
+        size = width;
+    }
+
+    return size;
+}
+
+static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
+                                uint8_t **base, uint32_t *size)
+{
+    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
+    ALOG_ASSERT(base != NULL, "base is NULL!!!");
+    ALOG_ASSERT(size != NULL, "size is NULL!!!");
+    ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
+
+    ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
+
+    uint32_t dataSize, ySize, cSize, cStride;
+    uint8_t *cb, *cr;
+    uint8_t *pData = NULL;
+    int bytesPerPixel = 0;
+
+    dataSize = ySize = cSize = cStride = 0;
+    int32_t fmt = buffer->format;
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            pData =
+                (idx == 0) ?
+                    buffer->data :
+                (idx == 1) ?
+                    buffer->dataCb :
+                buffer->dataCr;
+            if (idx == 0) {
+                dataSize = buffer->stride * buffer->height;
+            } else {
+                dataSize = buffer->chromaStride * buffer->height / 2;
+            }
+            break;
+        // NV21
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            cr = buffer->data + (buffer->stride * buffer->height);
+            cb = cr + 1;
+            ySize = buffer->width * buffer->height;
+            cSize = buffer->width * buffer->height / 2;
+
+            pData =
+                (idx == 0) ?
+                    buffer->data :
+                (idx == 1) ?
+                    cb:
+                cr;
+
+            dataSize = (idx == 0) ? ySize : cSize;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:
+            // Y and C stride need to be 16 pixel aligned.
+            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
+                                "Stride is not 16 pixel aligned %d", buffer->stride);
+
+            ySize = buffer->stride * buffer->height;
+            cStride = ALIGN(buffer->stride / 2, 16);
+            cr = buffer->data + ySize;
+            cSize = cStride * buffer->height / 2;
+            cb = cr + cSize;
+
+            pData =
+                (idx == 0) ?
+                    buffer->data :
+                (idx == 1) ?
+                    cb :
+                cr;
+            dataSize = (idx == 0) ? ySize : cSize;
+            break;
+        case HAL_PIXEL_FORMAT_Y8:
+            // Single plane, 8bpp.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height;
+            break;
+        case HAL_PIXEL_FORMAT_Y16:
+            // Single plane, 16bpp, strides are specified in pixels, not in bytes
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * 2;
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Used for JPEG data, height must be 1, width == size, single plane.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);
+
+            pData = buffer->data;
+            dataSize = Image_getJpegSize(buffer);
+            break;
+        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            // Single plane 16bpp bayer data.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->width * 2 * buffer->height;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            // Single plane, 32bpp.
+            bytesPerPixel = 4;
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_565:
+            // Single plane, 16bpp.
+            bytesPerPixel = 2;
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            bytesPerPixel = 3;
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            break;
+        default:
+            jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                                 "Pixel format: 0x%x is unsupported", fmt);
+            break;
+    }
+
+    *base = pData;
+    *size = dataSize;
+}
+
+static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx)
+{
+    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+    ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
+
+    int pixelStride = 0;
+    ALOG_ASSERT(buffer != NULL, "buffer is NULL");
+
+    int32_t fmt = buffer->format;
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            pixelStride = (idx == 0) ? 1 : buffer->chromaStep;
+            break;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            pixelStride = (idx == 0) ? 1 : 2;
+            break;
+        case HAL_PIXEL_FORMAT_Y8:
+            // Single plane 8bpp data.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pixelStride;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:
+            pixelStride = 1;
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Used for JPEG data, single plane, row and pixel strides are 0
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pixelStride = 0;
+            break;
+        case HAL_PIXEL_FORMAT_Y16:
+        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            // Single plane 16bpp data.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pixelStride = 2;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pixelStride = 4;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pixelStride = 3;
+            break;
+        default:
+            jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                                 "Pixel format: 0x%x is unsupported", fmt);
+            break;
+    }
+
+    return pixelStride;
+}
+
+static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx)
+{
+    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+    ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
+
+    int rowStride = 0;
+    ALOG_ASSERT(buffer != NULL, "buffer is NULL");
+
+    int32_t fmt = buffer->format;
+
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride;
+            break;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            rowStride = buffer->width;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:
+            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
+                                "Stride is not 16 pixel aligned %d", buffer->stride);
+            rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Used for JPEG data, single plane, row and pixel strides are 0
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            rowStride = 0;
+            break;
+        case HAL_PIXEL_FORMAT_Y8:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
+                                "Stride is not 16 pixel aligned %d", buffer->stride);
+            rowStride = buffer->stride;
+            break;
+        case HAL_PIXEL_FORMAT_Y16:
+        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            // In native side, strides are specified in pixels, not in bytes.
+            // Single plane 16bpp bayer data. even width/height,
+            // row stride multiple of 16 pixels (32 bytes)
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
+                                "Stride is not 16 pixel aligned %d", buffer->stride);
+            rowStride = buffer->stride * 2;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_565:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            rowStride = buffer->stride * 2;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            rowStride = buffer->stride * 4;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            rowStride = buffer->stride * 3;
+            break;
+        default:
+            ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
+            jniThrowException(env, "java/lang/UnsupportedOperationException",
+                              "unsupported buffer format");
+          break;
+    }
+
+    return rowStride;
+}
+
+// ----------------------------------------------------------------------------
+
+static void ImageReader_classInit(JNIEnv* env, jclass clazz)
+{
+    ALOGV("%s:", __FUNCTION__);
+
+    jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage");
+    LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
+                        "can't find android/graphics/ImageReader$SurfaceImage");
+    gSurfaceImageClassInfo.mLockedBuffer = env->GetFieldID(
+            imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J");
+    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mLockedBuffer == NULL,
+                        "can't find android/graphics/ImageReader.%s",
+                        ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID);
+
+    gSurfaceImageClassInfo.mTimestamp = env->GetFieldID(
+            imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J");
+    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTimestamp == NULL,
+                        "can't find android/graphics/ImageReader.%s",
+                        ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
+
+    gImageReaderClassInfo.mNativeContext = env->GetFieldID(
+            clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
+    LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL,
+                        "can't find android/graphics/ImageReader.%s",
+                          ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID);
+
+    gImageReaderClassInfo.postEventFromNative = env->GetStaticMethodID(
+            clazz, "postEventFromNative", "(Ljava/lang/Object;)V");
+    LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.postEventFromNative == NULL,
+                        "can't find android/graphics/ImageReader.postEventFromNative");
+
+    jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane");
+    LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class");
+    // FindClass only gives a local reference of jclass object.
+    gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
+    gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
+            "(Landroid/media/ImageReader$SurfaceImage;III)V");
+    LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
+            "Can not find SurfacePlane constructor");
+}
+
+static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
+                             jint width, jint height, jint format, jint maxImages)
+{
+    status_t res;
+    int nativeFormat;
+
+    ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
+          __FUNCTION__, width, height, format, maxImages);
+
+    nativeFormat = Image_getPixelFormat(env, format);
+
+    sp<BufferQueue> bq = new BufferQueue();
+    sp<CpuConsumer> consumer = new CpuConsumer(bq, maxImages,
+                                               /*controlledByApp*/true);
+    // TODO: throw dvm exOutOfMemoryError?
+    if (consumer == NULL) {
+        jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
+        return;
+    }
+
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader");
+        return;
+    }
+    sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
+    ctx->setCpuConsumer(consumer);
+    ctx->setBufferQueue(bq);
+    consumer->setFrameAvailableListener(ctx);
+    ImageReader_setNativeContext(env, thiz, ctx);
+    ctx->setBufferFormat(nativeFormat);
+    ctx->setBufferWidth(width);
+    ctx->setBufferHeight(height);
+
+    // Set the width/height/format to the CpuConsumer
+    res = consumer->setDefaultBufferSize(width, height);
+    if (res != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set CpuConsumer buffer size");
+        return;
+    }
+    res = consumer->setDefaultBufferFormat(nativeFormat);
+    if (res != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set CpuConsumer buffer format");
+    }
+}
+
+static void ImageReader_close(JNIEnv* env, jobject thiz)
+{
+    ALOGV("%s:", __FUNCTION__);
+
+    JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        // ImageReader is already closed.
+        return;
+    }
+
+    CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz);
+    if (consumer != NULL) {
+        consumer->abandon();
+        consumer->setFrameAvailableListener(NULL);
+    }
+    ImageReader_setNativeContext(env, thiz, NULL);
+}
+
+static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
+{
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        ALOGW("ImageReader#close called before Image#close, consider calling Image#close first");
+        return;
+    }
+
+    CpuConsumer* consumer = ctx->getCpuConsumer();
+    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
+    if (!buffer) {
+        ALOGW("Image already released!!!");
+        return;
+    }
+    consumer->unlockBuffer(*buffer);
+    Image_setBuffer(env, image, NULL);
+    ctx->returnLockedBuffer(buffer);
+}
+
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz,
+                                             jobject image)
+{
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
+        return -1;
+    }
+
+    CpuConsumer* consumer = ctx->getCpuConsumer();
+    CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer();
+    if (buffer == NULL) {
+        ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
+            " maxImages buffers");
+        return ACQUIRE_MAX_IMAGES;
+    }
+    status_t res = consumer->lockNextBuffer(buffer);
+    if (res != NO_ERROR) {
+        if (res != BAD_VALUE /*no buffers*/) {
+            if (res == NOT_ENOUGH_DATA) {
+                return ACQUIRE_MAX_IMAGES;
+            } else {
+                ALOGE("%s Fail to lockNextBuffer with error: %d ",
+                      __FUNCTION__, res);
+                jniThrowExceptionFmt(env, "java/lang/AssertionError",
+                          "Unknown error (%d) when we tried to lock buffer.",
+                          res);
+            }
+        }
+        return ACQUIRE_NO_BUFFERS;
+    }
+
+    if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+        jniThrowException(env, "java/lang/UnsupportedOperationException",
+                "NV21 format is not supported by ImageReader");
+        return -1;
+    }
+
+    // Check if the left-top corner of the crop rect is origin, we currently assume this point is
+    // zero, will revist this once this assumption turns out problematic.
+    Point lt = buffer->crop.leftTop();
+    if (lt.x != 0 || lt.y != 0) {
+        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
+        return -1;
+    }
+
+    // Check if the producer buffer configurations match what ImageReader configured.
+    // We want to fail for the very first image because this case is too bad.
+    int outputWidth = buffer->width;
+    int outputHeight = buffer->height;
+
+    // Correct width/height when crop is set.
+    if (!buffer->crop.isEmpty()) {
+        outputWidth = buffer->crop.getWidth();
+        outputHeight = buffer->crop.getHeight();
+    }
+
+    int imageReaderWidth = ctx->getBufferWidth();
+    int imageReaderHeight = ctx->getBufferHeight();
+    if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) &&
+            (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) {
+        /**
+         * For video decoder, the buffer height is actually the vertical stride,
+         * which is always >= actual image height. For future, decoder need provide
+         * right crop rectangle to CpuConsumer to indicate the actual image height,
+         * see bug 9563986. After this bug is fixed, we can enforce the height equal
+         * check. Right now, only make sure buffer height is no less than ImageReader
+         * height.
+         */
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
+                outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+        return -1;
+    }
+
+    if (ctx->getBufferFormat() != buffer->format) {
+        // Return the buffer to the queue.
+        consumer->unlockBuffer(*buffer);
+        ctx->returnLockedBuffer(buffer);
+
+        // Throw exception
+        ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
+              buffer->format, ctx->getBufferFormat());
+        String8 msg;
+        msg.appendFormat("The producer output buffer format 0x%x doesn't "
+                "match the ImageReader's configured buffer format 0x%x.",
+                buffer->format, ctx->getBufferFormat());
+        jniThrowException(env, "java/lang/UnsupportedOperationException",
+                msg.string());
+        return -1;
+    }
+    // Set SurfaceImage instance member variables
+    Image_setBuffer(env, image, buffer);
+    env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
+            static_cast<jlong>(buffer->timestamp));
+
+    return ACQUIRE_SUCCESS;
+}
+
+static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
+{
+    ALOGV("%s: ", __FUNCTION__);
+
+    BufferQueue* bq = ImageReader_getBufferQueue(env, thiz);
+    if (bq == NULL) {
+        jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
+        return NULL;
+    }
+
+    // Wrap the IGBP in a Java-language Surface.
+    return android_view_Surface_createFromIGraphicBufferProducer(env, bq);
+}
+
+static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx)
+{
+    int rowStride, pixelStride;
+    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+
+    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+
+    ALOG_ASSERT(buffer != NULL);
+    if (buffer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
+    }
+    rowStride = Image_imageGetRowStride(env, buffer, idx);
+    pixelStride = Image_imageGetPixelStride(env, buffer, idx);
+
+    jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
+            gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
+
+    return surfPlaneObj;
+}
+
+static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx)
+{
+    uint8_t *base = NULL;
+    uint32_t size = 0;
+    jobject byteBuffer;
+
+    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+
+    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+
+    if (buffer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
+    }
+
+    // Create byteBuffer from native buffer
+    Image_getLockedBufferInfo(env, buffer, idx, &base, &size);
+    byteBuffer = env->NewDirectByteBuffer(base, size);
+    // TODO: throw dvm exOutOfMemoryError?
+    if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
+        jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer");
+    }
+
+    return byteBuffer;
+}
+
+} // extern "C"
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gImageReaderMethods[] = {
+    {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
+    {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
+    {"nativeClose",            "()V",                        (void*)ImageReader_close },
+    {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
+    {"nativeImageSetup",       "(Landroid/media/Image;)I",    (void*)ImageReader_imageSetup },
+    {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
+};
+
+static JNINativeMethod gImageMethods[] = {
+    {"nativeImageGetBuffer",   "(I)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
+    {"nativeCreatePlane",      "(I)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+                                                             (void*)Image_createSurfacePlane },
+};
+
+int register_android_media_ImageReader(JNIEnv *env) {
+
+    int ret1 = AndroidRuntime::registerNativeMethods(env,
+                   "android/media/ImageReader", gImageReaderMethods, NELEM(gImageReaderMethods));
+
+    int ret2 = AndroidRuntime::registerNativeMethods(env,
+                   "android/media/ImageReader$SurfaceImage", gImageMethods, NELEM(gImageMethods));
+
+    return (ret1 || ret2);
+}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index cd1d9ce..b8d437c 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -38,6 +38,8 @@
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <nativehelper/ScopedLocalRef.h>
+
 #include <system/window.h>
 
 namespace android {
@@ -49,9 +51,14 @@
     DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
 };
 
+struct CryptoErrorCodes {
+    jint cryptoErrorNoKey;
+    jint cryptoErrorKeyExpired;
+    jint cryptoErrorResourceBusy;
+} gCryptoErrorCodes;
+
 struct fields_t {
     jfieldID context;
-
     jfieldID cryptoInfoNumSubSamplesID;
     jfieldID cryptoInfoNumBytesOfClearDataID;
     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
@@ -81,7 +88,7 @@
     mLooper->start(
             false,      // runOnCallingThread
             false,       // canCallJava
-            PRIORITY_DEFAULT);
+            PRIORITY_FOREGROUND);
 
     if (nameIsType) {
         mCodec = MediaCodec::CreateByType(mLooper, name, encoder);
@@ -115,7 +122,7 @@
         int flags) {
     sp<Surface> client;
     if (bufferProducer != NULL) {
-        mSurfaceTextureClient = new Surface(bufferProducer);
+        mSurfaceTextureClient = new Surface(bufferProducer, true /* controlledByApp */);
     } else {
         mSurfaceTextureClient.clear();
     }
@@ -181,9 +188,10 @@
         return err;
     }
 
-    jclass clazz = env->FindClass("android/media/MediaCodec$BufferInfo");
+    ScopedLocalRef<jclass> clazz(
+            env, env->FindClass("android/media/MediaCodec$BufferInfo"));
 
-    jmethodID method = env->GetMethodID(clazz, "set", "(IIJI)V");
+    jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
     env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags);
 
     return OK;
@@ -222,29 +230,33 @@
         return err;
     }
 
-    jclass byteBufferClass = env->FindClass("java/nio/ByteBuffer");
-    CHECK(byteBufferClass != NULL);
+    ScopedLocalRef<jclass> byteBufferClass(
+            env, env->FindClass("java/nio/ByteBuffer"));
+
+    CHECK(byteBufferClass.get() != NULL);
 
     jmethodID orderID = env->GetMethodID(
-            byteBufferClass,
+            byteBufferClass.get(),
             "order",
             "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
 
     CHECK(orderID != NULL);
 
-    jclass byteOrderClass = env->FindClass("java/nio/ByteOrder");
-    CHECK(byteOrderClass != NULL);
+    ScopedLocalRef<jclass> byteOrderClass(
+            env, env->FindClass("java/nio/ByteOrder"));
+
+    CHECK(byteOrderClass.get() != NULL);
 
     jmethodID nativeOrderID = env->GetStaticMethodID(
-            byteOrderClass, "nativeOrder", "()Ljava/nio/ByteOrder;");
+            byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
     CHECK(nativeOrderID != NULL);
 
     jobject nativeByteOrderObj =
-        env->CallStaticObjectMethod(byteOrderClass, nativeOrderID);
+        env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
     CHECK(nativeByteOrderObj != NULL);
 
     *bufArray = (jobjectArray)env->NewObjectArray(
-            buffers.size(), byteBufferClass, NULL);
+            buffers.size(), byteBufferClass.get(), NULL);
     if (*bufArray == NULL) {
         env->DeleteLocalRef(nativeByteOrderObj);
         return NO_MEMORY;
@@ -298,6 +310,10 @@
     return OK;
 }
 
+status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
+    return mCodec->setParameters(msg);
+}
+
 void JMediaCodec::setVideoScalingMode(int mode) {
     if (mSurfaceTextureClient != NULL) {
         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
@@ -333,26 +349,41 @@
 }
 
 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
-    jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException");
-    CHECK(clazz != NULL);
+    ScopedLocalRef<jclass> clazz(
+            env, env->FindClass("android/media/MediaCodec$CryptoException"));
+    CHECK(clazz.get() != NULL);
 
     jmethodID constructID =
-        env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");
+        env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
     CHECK(constructID != NULL);
 
     jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
 
+    /* translate OS errors to Java API CryptoException errorCodes */
+    switch (err) {
+        case ERROR_DRM_NO_LICENSE:
+            err = gCryptoErrorCodes.cryptoErrorNoKey;
+            break;
+        case ERROR_DRM_LICENSE_EXPIRED:
+            err = gCryptoErrorCodes.cryptoErrorKeyExpired;
+            break;
+        case ERROR_DRM_RESOURCE_BUSY:
+            err = gCryptoErrorCodes.cryptoErrorResourceBusy;
+            break;
+        default:
+            break;
+    }
+
     jthrowable exception =
-        (jthrowable)env->NewObject(clazz, constructID, err, msgObj);
+        (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
 
     env->Throw(exception);
 }
 
 static jint throwExceptionAsNecessary(
         JNIEnv *env, status_t err, const char *msg = NULL) {
-    if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) {
+    if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
         // We'll throw our custom MediaCodec.CryptoException
-
         throwCryptoException(env, err, msg);
         return 0;
     }
@@ -370,6 +401,12 @@
         case INFO_OUTPUT_BUFFERS_CHANGED:
             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
 
+        case ERROR_DRM_NO_LICENSE:
+        case ERROR_DRM_LICENSE_EXPIRED:
+        case ERROR_DRM_RESOURCE_BUSY:
+            throwCryptoException(env, err, msg);
+            break;
+
         default:
         {
             jniThrowException(env, "java/lang/IllegalStateException", msg);
@@ -804,6 +841,27 @@
     return NULL;
 }
 
+static void android_media_MediaCodec_setParameters(
+        JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
+    ALOGV("android_media_MediaCodec_setParameters");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+    if (codec == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    sp<AMessage> params;
+    status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
+
+    if (err == OK) {
+        err = codec->setParameters(params);
+    }
+
+    throwExceptionAsNecessary(env, err);
+}
+
 static void android_media_MediaCodec_setVideoScalingMode(
         JNIEnv *env, jobject thiz, jint mode) {
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -823,35 +881,55 @@
 }
 
 static void android_media_MediaCodec_native_init(JNIEnv *env) {
-    jclass clazz = env->FindClass("android/media/MediaCodec");
-    CHECK(clazz != NULL);
+    ScopedLocalRef<jclass> clazz(
+            env, env->FindClass("android/media/MediaCodec"));
+    CHECK(clazz.get() != NULL);
 
-    gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+    gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "I");
     CHECK(gFields.context != NULL);
 
-    clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
-    CHECK(clazz != NULL);
+    clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
+    CHECK(clazz.get() != NULL);
 
     gFields.cryptoInfoNumSubSamplesID =
-        env->GetFieldID(clazz, "numSubSamples", "I");
+        env->GetFieldID(clazz.get(), "numSubSamples", "I");
     CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
 
     gFields.cryptoInfoNumBytesOfClearDataID =
-        env->GetFieldID(clazz, "numBytesOfClearData", "[I");
+        env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
     CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
 
     gFields.cryptoInfoNumBytesOfEncryptedDataID =
-        env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I");
+        env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
     CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
 
-    gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B");
+    gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
     CHECK(gFields.cryptoInfoKeyID != NULL);
 
-    gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B");
+    gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
     CHECK(gFields.cryptoInfoIVID != NULL);
 
-    gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I");
+    gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
     CHECK(gFields.cryptoInfoModeID != NULL);
+
+    clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
+    CHECK(clazz.get() != NULL);
+
+    jfieldID field;
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorNoKey =
+        env->GetStaticIntField(clazz.get(), field);
+
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorKeyExpired =
+        env->GetStaticIntField(clazz.get(), field);
+
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorResourceBusy =
+        env->GetStaticIntField(clazz.get(), field);
 }
 
 static void android_media_MediaCodec_native_setup(
@@ -933,6 +1011,9 @@
     { "getName", "()Ljava/lang/String;",
       (void *)android_media_MediaCodec_getName },
 
+    { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
+      (void *)android_media_MediaCodec_setParameters },
+
     { "setVideoScalingMode", "(I)V",
       (void *)android_media_MediaCodec_setVideoScalingMode },
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 282d2c5..2fbbd72 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -87,6 +87,8 @@
 
     status_t getName(JNIEnv *env, jstring *name) const;
 
+    status_t setParameters(const sp<AMessage> &params);
+
     void setVideoScalingMode(int mode);
 
 protected:
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 04430ec..caa594e 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -110,10 +110,11 @@
 
     Vector<MediaCodecList::ProfileLevel> profileLevels;
     Vector<uint32_t> colorFormats;
+    uint32_t flags;
 
     status_t err =
         MediaCodecList::getInstance()->getCodecCapabilities(
-                index, typeStr, &profileLevels, &colorFormats);
+                index, typeStr, &profileLevels, &colorFormats, &flags);
 
     env->ReleaseStringUTFChars(type, typeStr);
     typeStr = NULL;
@@ -127,6 +128,9 @@
         env->FindClass("android/media/MediaCodecInfo$CodecCapabilities");
     CHECK(capsClazz != NULL);
 
+    jfieldID flagsField =
+        env->GetFieldID(capsClazz, "flags", "I");
+
     jobject caps = env->AllocObject(capsClazz);
 
     jclass profileLevelClazz =
@@ -163,6 +167,8 @@
 
     env->SetObjectField(caps, profileLevelsField, profileLevelArray);
 
+    env->SetIntField(caps, flagsField, flags);
+
     env->DeleteLocalRef(profileLevelArray);
     profileLevelArray = NULL;
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 7799ca4..bbb74d25b 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -21,6 +21,7 @@
 #include "android_media_MediaDrm.h"
 
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 #include "android_os_Parcel.h"
 #include "jni.h"
 #include "JNIHelp.h"
@@ -242,6 +243,9 @@
     } else if (err == ERROR_DRM_NOT_PROVISIONED) {
         jniThrowException(env, "android/media/NotProvisionedException", msg);
         return true;
+    } else if (err == ERROR_DRM_RESOURCE_BUSY) {
+        jniThrowException(env, "android/media/ResourceBusyException", msg);
+        return true;
     } else if (err == ERROR_DRM_DEVICE_REVOKED) {
         jniThrowException(env, "android/media/DeniedByServerException", msg);
         return true;
@@ -345,14 +349,14 @@
 
 
 // static
-bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
+bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
     sp<IDrm> drm = MakeDrm();
 
     if (drm == NULL) {
         return false;
     }
 
-    return drm->isCryptoSchemeSupported(uuid);
+    return drm->isCryptoSchemeSupported(uuid, mimeType);
 }
 
 status_t JDrm::initCheck() const {
@@ -608,7 +612,7 @@
 }
 
 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
-        JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
+    JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) {
 
     if (uuidObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
@@ -625,7 +629,12 @@
         return false;
     }
 
-    return JDrm::IsCryptoSchemeSupported(uuid.array());
+    String8 mimeType;
+    if (jmimeType != NULL) {
+        mimeType = JStringToString8(env, jmimeType);
+    }
+
+    return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
 }
 
 static jbyteArray android_media_MediaDrm_openSession(
@@ -750,7 +759,9 @@
 
     status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
 
-    throwExceptionAsNecessary(env, err, "Failed to handle key response");
+    if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
+        return NULL;
+    }
     return VectorToJByteArray(env, keySetId);
 }
 
@@ -1101,7 +1112,9 @@
 
     status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
 
-    throwExceptionAsNecessary(env, err, "Failed to encrypt");
+    if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
+        return NULL;
+    }
 
     return VectorToJByteArray(env, output);
 }
@@ -1129,7 +1142,9 @@
     Vector<uint8_t> output;
 
     status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
-    throwExceptionAsNecessary(env, err, "Failed to decrypt");
+    if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
+        return NULL;
+    }
 
     return VectorToJByteArray(env, output);
 }
@@ -1157,7 +1172,9 @@
 
     status_t err = drm->sign(sessionId, keyId, message, signature);
 
-    throwExceptionAsNecessary(env, err, "Failed to sign");
+    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
+        return NULL;
+    }
 
     return VectorToJByteArray(env, signature);
 }
@@ -1201,7 +1218,7 @@
     { "native_finalize", "()V",
       (void *)android_media_MediaDrm_native_finalize },
 
-    { "isCryptoSchemeSupportedNative", "([B)Z",
+    { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
 
     { "openSession", "()[B",
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 9b3917f..620ad28 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -37,7 +37,7 @@
 };
 
 struct JDrm : public BnDrmClient {
-    static bool IsCryptoSchemeSupported(const uint8_t uuid[16]);
+    static bool IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
 
     JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);
 
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 1704d5c..1ac45d4 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -22,6 +22,7 @@
 
 #include "android_media_Utils.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 #include "jni.h"
 #include "JNIHelp.h"
 
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 7517e85..457b956 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -164,6 +164,18 @@
 
 }
 
+static void android_media_MediaMuxer_setLocation(
+        JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) {
+    MediaMuxer* muxer = reinterpret_cast<MediaMuxer *>(nativeObject);
+
+    status_t res = muxer->setLocation(latitude, longitude);
+    if (res != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set location");
+        return;
+    }
+}
+
 static void android_media_MediaMuxer_start(JNIEnv *env, jclass clazz,
                                            jint nativeObject) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
@@ -216,6 +228,9 @@
     { "nativeSetOrientationHint", "(II)V",
         (void *)android_media_MediaMuxer_setOrientationHint},
 
+    { "nativeSetLocation", "(III)V",
+        (void *)android_media_MediaMuxer_setLocation},
+
     { "nativeStart", "(I)V", (void *)android_media_MediaMuxer_start},
 
     { "nativeWriteSampleData", "(IILjava/nio/ByteBuffer;IIJI)V",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 7c607ea..d134667 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -31,6 +31,7 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
+#include "android_runtime/Log.h"
 #include "utils/Errors.h"  // for status_t
 #include "utils/KeyedVector.h"
 #include "utils/String8.h"
@@ -525,14 +526,6 @@
     process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL );
 }
 
-// FIXME: deprecated
-static jobject
-android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
-{
-    return NULL;
-}
-
-
 // Sends the request and reply parcels to the media player via the
 // binder interface.
 static jint
@@ -781,39 +774,6 @@
     return ret;
 }
 
-static jboolean
-android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
-{
-    ALOGV("setParameter: key %d", key);
-    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return false;
-    }
-
-    Parcel *request = parcelForJavaObject(env, java_request);
-    status_t err = mp->setParameter(key, *request);
-    if (err == OK) {
-        return true;
-    } else {
-        return false;
-    }
-}
-
-static void
-android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply)
-{
-    ALOGV("getParameter: key %d", key);
-    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return;
-    }
-
-    Parcel *reply = parcelForJavaObject(env, java_reply);
-    process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL );
-}
-
 static void
 android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
 {
@@ -912,7 +872,6 @@
     {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
     {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
     {"setVolume",           "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
-    {"getFrameAt",          "(I)Landroid/graphics/Bitmap;",     (void *)android_media_MediaPlayer_getFrameAt},
     {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
     {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
     {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
@@ -924,8 +883,6 @@
     {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
     {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
-    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
-    {"getParameter",        "(ILandroid/os/Parcel;)V",          (void *)android_media_MediaPlayer_getParameter},
     {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer_setRetransmitEndpoint},
     {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
     {"updateProxyConfig", "(Landroid/net/ProxyProperties;)V", (void *)android_media_MediaPlayer_updateProxyConfig},
@@ -940,6 +897,7 @@
                 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
 }
 
+extern int register_android_media_ImageReader(JNIEnv *env);
 extern int register_android_media_Crypto(JNIEnv *env);
 extern int register_android_media_Drm(JNIEnv *env);
 extern int register_android_media_MediaCodec(JNIEnv *env);
@@ -967,6 +925,11 @@
     }
     assert(env != NULL);
 
+    if (register_android_media_ImageReader(env) < 0) {
+        ALOGE("ERROR: ImageReader native registration failed");
+        goto bail;
+    }
+
     if (register_android_media_MediaPlayer(env) < 0) {
         ALOGE("ERROR: MediaPlayer native registration failed\n");
         goto bail;
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 5d27966..4e3d14e 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -25,6 +25,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 
 using namespace android;
 
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index e35ace3..54c5e9b 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -24,6 +24,8 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 
+#include <nativehelper/ScopedLocalRef.h>
+
 namespace android {
 
 bool ConvertKeyValueArraysToKeyedVector(
@@ -76,33 +78,35 @@
 }
 
 static jobject makeIntegerObject(JNIEnv *env, int32_t value) {
-    jclass clazz = env->FindClass("java/lang/Integer");
-    CHECK(clazz != NULL);
+    ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer"));
+    CHECK(clazz.get() != NULL);
 
-    jmethodID integerConstructID = env->GetMethodID(clazz, "<init>", "(I)V");
+    jmethodID integerConstructID =
+        env->GetMethodID(clazz.get(), "<init>", "(I)V");
     CHECK(integerConstructID != NULL);
 
-    return env->NewObject(clazz, integerConstructID, value);
+    return env->NewObject(clazz.get(), integerConstructID, value);
 }
 
 static jobject makeLongObject(JNIEnv *env, int64_t value) {
-    jclass clazz = env->FindClass("java/lang/Long");
-    CHECK(clazz != NULL);
+    ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long"));
+    CHECK(clazz.get() != NULL);
 
-    jmethodID longConstructID = env->GetMethodID(clazz, "<init>", "(J)V");
+    jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V");
     CHECK(longConstructID != NULL);
 
-    return env->NewObject(clazz, longConstructID, value);
+    return env->NewObject(clazz.get(), longConstructID, value);
 }
 
 static jobject makeFloatObject(JNIEnv *env, float value) {
-    jclass clazz = env->FindClass("java/lang/Float");
-    CHECK(clazz != NULL);
+    ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float"));
+    CHECK(clazz.get() != NULL);
 
-    jmethodID floatConstructID = env->GetMethodID(clazz, "<init>", "(F)V");
+    jmethodID floatConstructID =
+        env->GetMethodID(clazz.get(), "<init>", "(F)V");
     CHECK(floatConstructID != NULL);
 
-    return env->NewObject(clazz, floatConstructID, value);
+    return env->NewObject(clazz.get(), floatConstructID, value);
 }
 
 static jobject makeByteBufferObject(
@@ -110,15 +114,16 @@
     jbyteArray byteArrayObj = env->NewByteArray(size);
     env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data);
 
-    jclass clazz = env->FindClass("java/nio/ByteBuffer");
-    CHECK(clazz != NULL);
+    ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer"));
+    CHECK(clazz.get() != NULL);
 
     jmethodID byteBufWrapID =
-        env->GetStaticMethodID(clazz, "wrap", "([B)Ljava/nio/ByteBuffer;");
+        env->GetStaticMethodID(
+                clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;");
     CHECK(byteBufWrapID != NULL);
 
     jobject byteBufObj = env->CallStaticObjectMethod(
-            clazz, byteBufWrapID, byteArrayObj);
+            clazz.get(), byteBufWrapID, byteArrayObj);
 
     env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL;
 
@@ -140,14 +145,15 @@
 
 status_t ConvertMessageToMap(
         JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
-    jclass hashMapClazz = env->FindClass("java/util/HashMap");
+    ScopedLocalRef<jclass> hashMapClazz(
+            env, env->FindClass("java/util/HashMap"));
 
-    if (hashMapClazz == NULL) {
+    if (hashMapClazz.get() == NULL) {
         return -EINVAL;
     }
 
     jmethodID hashMapConstructID =
-        env->GetMethodID(hashMapClazz, "<init>", "()V");
+        env->GetMethodID(hashMapClazz.get(), "<init>", "()V");
 
     if (hashMapConstructID == NULL) {
         return -EINVAL;
@@ -155,7 +161,7 @@
 
     jmethodID hashMapPutID =
         env->GetMethodID(
-                hashMapClazz,
+                hashMapClazz.get(),
                 "put",
                 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
 
@@ -163,7 +169,7 @@
         return -EINVAL;
     }
 
-    jobject hashMap = env->NewObject(hashMapClazz, hashMapConstructID);
+    jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);
 
     for (size_t i = 0; i < msg->countEntries(); ++i) {
         AMessage::Type valueType;
@@ -276,17 +282,16 @@
 status_t ConvertKeyValueArraysToMessage(
         JNIEnv *env, jobjectArray keys, jobjectArray values,
         sp<AMessage> *out) {
-    jclass stringClass = env->FindClass("java/lang/String");
-    CHECK(stringClass != NULL);
-
-    jclass integerClass = env->FindClass("java/lang/Integer");
-    CHECK(integerClass != NULL);
-
-    jclass floatClass = env->FindClass("java/lang/Float");
-    CHECK(floatClass != NULL);
-
-    jclass byteBufClass = env->FindClass("java/nio/ByteBuffer");
-    CHECK(byteBufClass != NULL);
+    ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
+    CHECK(stringClass.get() != NULL);
+    ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer"));
+    CHECK(integerClass.get() != NULL);
+    ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
+    CHECK(longClass.get() != NULL);
+    ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float"));
+    CHECK(floatClass.get() != NULL);
+    ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
+    CHECK(byteBufClass.get() != NULL);
 
     sp<AMessage> msg = new AMessage;
 
@@ -309,7 +314,7 @@
     for (jsize i = 0; i < numEntries; ++i) {
         jobject keyObj = env->GetObjectArrayElement(keys, i);
 
-        if (!env->IsInstanceOf(keyObj, stringClass)) {
+        if (!env->IsInstanceOf(keyObj, stringClass.get())) {
             return -EINVAL;
         }
 
@@ -326,7 +331,7 @@
 
         jobject valueObj = env->GetObjectArrayElement(values, i);
 
-        if (env->IsInstanceOf(valueObj, stringClass)) {
+        if (env->IsInstanceOf(valueObj, stringClass.get())) {
             const char *value = env->GetStringUTFChars((jstring)valueObj, NULL);
 
             if (value == NULL) {
@@ -337,29 +342,37 @@
 
             env->ReleaseStringUTFChars((jstring)valueObj, value);
             value = NULL;
-        } else if (env->IsInstanceOf(valueObj, integerClass)) {
+        } else if (env->IsInstanceOf(valueObj, integerClass.get())) {
             jmethodID intValueID =
-                env->GetMethodID(integerClass, "intValue", "()I");
+                env->GetMethodID(integerClass.get(), "intValue", "()I");
             CHECK(intValueID != NULL);
 
             jint value = env->CallIntMethod(valueObj, intValueID);
 
             msg->setInt32(key.c_str(), value);
-        } else if (env->IsInstanceOf(valueObj, floatClass)) {
+        } else if (env->IsInstanceOf(valueObj, longClass.get())) {
+            jmethodID longValueID =
+                env->GetMethodID(longClass.get(), "longValue", "()J");
+            CHECK(longValueID != NULL);
+
+            jlong value = env->CallLongMethod(valueObj, longValueID);
+
+            msg->setInt64(key.c_str(), value);
+        } else if (env->IsInstanceOf(valueObj, floatClass.get())) {
             jmethodID floatValueID =
-                env->GetMethodID(floatClass, "floatValue", "()F");
+                env->GetMethodID(floatClass.get(), "floatValue", "()F");
             CHECK(floatValueID != NULL);
 
             jfloat value = env->CallFloatMethod(valueObj, floatValueID);
 
             msg->setFloat(key.c_str(), value);
-        } else if (env->IsInstanceOf(valueObj, byteBufClass)) {
+        } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) {
             jmethodID positionID =
-                env->GetMethodID(byteBufClass, "position", "()I");
+                env->GetMethodID(byteBufClass.get(), "position", "()I");
             CHECK(positionID != NULL);
 
             jmethodID limitID =
-                env->GetMethodID(byteBufClass, "limit", "()I");
+                env->GetMethodID(byteBufClass.get(), "limit", "()I");
             CHECK(limitID != NULL);
 
             jint position = env->CallIntMethod(valueObj, positionID);
@@ -375,7 +388,7 @@
                        buffer->size());
             } else {
                 jmethodID arrayID =
-                    env->GetMethodID(byteBufClass, "array", "()[B");
+                    env->GetMethodID(byteBufClass.get(), "array", "()[B");
                 CHECK(arrayID != NULL);
 
                 jbyteArray byteArray =
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index fbd5d21..77c7966 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -26,6 +26,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 
 #include "MtpDatabase.h"
 #include "MtpDataPacket.h"
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 113784e..b61b66c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -28,6 +28,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 #include "private/android_filesystem_config.h"
 
 #include "MtpTypes.h"
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 4d77cfd..40cd06b 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -43,6 +43,8 @@
 
 // ----------------------------------------------------------------------------
 static const char* const kClassPathName = "android/media/audiofx/Visualizer";
+static const char* const kClassPeakRmsPathName =
+        "android/media/audiofx/Visualizer$MeasurementPeakRms";
 
 struct fields_t {
     // these fields provide access from C++ to the...
@@ -50,6 +52,8 @@
     jmethodID midPostNativeEvent;   // event post callback method
     jfieldID  fidNativeVisualizer; // stores in Java the native Visualizer object
     jfieldID  fidJniData;           // stores in Java additional resources used by the native Visualizer
+    jfieldID  fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak
+    jfieldID  fidRms;  // to access Visualizer.MeasurementPeakRms.mRms
 };
 static fields_t fields;
 
@@ -257,6 +261,14 @@
 
     fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
 
+    // Get the Visualizer.MeasurementPeakRms class
+    clazz = env->FindClass(kClassPeakRmsPathName);
+    if (clazz == NULL) {
+        ALOGE("Can't find %s", kClassPeakRmsPathName);
+        return;
+    }
+    jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz);
+
     // Get the postEvent method
     fields.midPostNativeEvent = env->GetStaticMethodID(
             fields.clazzEffect,
@@ -283,7 +295,24 @@
         ALOGE("Can't find Visualizer.%s", "mJniData");
         return;
     }
+    //      fidPeak
+    fields.fidPeak = env->GetFieldID(
+            clazzMeasurementPeakRms,
+            "mPeak", "I");
+    if (fields.fidPeak == NULL) {
+        ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
+        return;
+    }
+    //      fidRms
+    fields.fidRms = env->GetFieldID(
+            clazzMeasurementPeakRms,
+            "mRms", "I");
+    if (fields.fidRms == NULL) {
+        ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
+        return;
+    }
 
+    env->DeleteGlobalRef(clazzMeasurementPeakRms);
 }
 
 static void android_media_visualizer_effect_callback(int32_t event,
@@ -513,6 +542,26 @@
 }
 
 static jint
+android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+    return translateError(lpVisualizer->setMeasurementMode(mode));
+}
+
+static jint
+android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return MEASUREMENT_MODE_NONE;
+    }
+    return lpVisualizer->getMeasurementMode();
+}
+
+static jint
 android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
 {
     Visualizer* lpVisualizer = getVisualizer(env, thiz);
@@ -560,6 +609,25 @@
 }
 
 static jint
+android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
+{
+    Visualizer* lpVisualizer = getVisualizer(env, thiz);
+    if (lpVisualizer == NULL) {
+        return VISUALIZER_ERROR_NO_INIT;
+    }
+    int32_t measurements[2];
+    jint status = translateError(
+                lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS,
+                        2, measurements));
+    if (status == VISUALIZER_SUCCESS) {
+        // measurement worked, write the values to the java object
+        env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]);
+        env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]);
+    }
+    return status;
+}
+
+static jint
 android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
 {
     Visualizer* lpVisualizer = getVisualizer(env, thiz);
@@ -606,9 +674,13 @@
     {"native_getCaptureSize",    "()I",   (void *)android_media_visualizer_native_getCaptureSize},
     {"native_setScalingMode",    "(I)I",  (void *)android_media_visualizer_native_setScalingMode},
     {"native_getScalingMode",    "()I",   (void *)android_media_visualizer_native_getScalingMode},
+    {"native_setMeasurementMode","(I)I",  (void *)android_media_visualizer_native_setMeasurementMode},
+    {"native_getMeasurementMode","()I",   (void *)android_media_visualizer_native_getMeasurementMode},
     {"native_getSamplingRate",   "()I",   (void *)android_media_visualizer_native_getSamplingRate},
     {"native_getWaveForm",       "([B)I", (void *)android_media_visualizer_native_getWaveForm},
     {"native_getFft",            "([B)I", (void *)android_media_visualizer_native_getFft},
+    {"native_getPeakRms",      "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
+                                          (void *)android_media_visualizer_native_getPeakRms},
     {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
 };
 
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 4982a47..d8099dd 100644
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VideoEditorClasses"
 
 #include <VideoEditorClasses.h>
 #include <VideoEditorJava.h>
diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp
index bcf9099..fde0fb5 100644
--- a/media/jni/mediaeditor/VideoEditorJava.cpp
+++ b/media/jni/mediaeditor/VideoEditorJava.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VideoEditorJava"
+
 #include <VideoEditorClasses.h>
 #include <VideoEditorJava.h>
 #include <VideoEditorLogging.h>
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
index 479d8b6..1f1228a 100644
--- a/media/jni/mediaeditor/VideoEditorLogging.h
+++ b/media/jni/mediaeditor/VideoEditorLogging.h
@@ -17,6 +17,16 @@
 #ifndef VIDEO_EDITOR_LOGGING_H
 #define VIDEO_EDITOR_LOGGING_H
 
+#ifndef LOG_TAG
+#error "No LOG_TAG defined!"
+#endif
+
+/*
+ * This file is used as a proxy for cutils/log.h.  Include cutils/log.h here to
+ * avoid relying on import ordering.
+ */
+#include <cutils/log.h>
+
 //#define VIDEOEDIT_LOGGING_ENABLED
 
 #define VIDEOEDIT_LOG_INDENTATION                       (3)
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index a8c08ac..c12b1f5 100644
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VideoEditorOsal"
+
 #include <VideoEditorJava.h>
 #include <VideoEditorLogging.h>
 #include <VideoEditorOsal.h>
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index c8fb263..2f8e357 100644
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VideoEditorPropertiesMain"
+
 #include <dlfcn.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 5835b9f..ed8d7c1 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	android_media_SoundPool.cpp
+	android_media_SoundPool_SoundPoolImpl.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
deleted file mode 100644
index 9658856..0000000
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ /dev/null
@@ -1,327 +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.
- */
-
-#include <stdio.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "SoundPool-JNI"
-
-#include <utils/Log.h>
-#include <nativehelper/jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <media/SoundPool.h>
-
-using namespace android;
-
-static struct fields_t {
-    jfieldID    mNativeContext;
-    jmethodID   mPostEvent;
-    jclass      mSoundPoolClass;
-} fields;
-
-static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) {
-    return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext);
-}
-
-// ----------------------------------------------------------------------------
-static int
-android_media_SoundPool_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority)
-{
-    ALOGV("android_media_SoundPool_load_URL");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return 0;
-    }
-    const char* s = env->GetStringUTFChars(path, NULL);
-    int id = ap->load(s, priority);
-    env->ReleaseStringUTFChars(path, s);
-    return id;
-}
-
-static int
-android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
-        jlong offset, jlong length, jint priority)
-{
-    ALOGV("android_media_SoundPool_load_FD");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return 0;
-    return ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
-            int64_t(offset), int64_t(length), int(priority));
-}
-
-static bool
-android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) {
-    ALOGV("android_media_SoundPool_unload\n");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return 0;
-    return ap->unload(sampleID);
-}
-
-static int
-android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID,
-        jfloat leftVolume, jfloat rightVolume, jint priority, jint loop,
-        jfloat rate)
-{
-    ALOGV("android_media_SoundPool_play\n");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return 0;
-    return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate);
-}
-
-static void
-android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID)
-{
-    ALOGV("android_media_SoundPool_pause");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->pause(channelID);
-}
-
-static void
-android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID)
-{
-    ALOGV("android_media_SoundPool_resume");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->resume(channelID);
-}
-
-static void
-android_media_SoundPool_autoPause(JNIEnv *env, jobject thiz)
-{
-    ALOGV("android_media_SoundPool_autoPause");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->autoPause();
-}
-
-static void
-android_media_SoundPool_autoResume(JNIEnv *env, jobject thiz)
-{
-    ALOGV("android_media_SoundPool_autoResume");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->autoResume();
-}
-
-static void
-android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID)
-{
-    ALOGV("android_media_SoundPool_stop");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->stop(channelID);
-}
-
-static void
-android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID,
-        float leftVolume, float rightVolume)
-{
-    ALOGV("android_media_SoundPool_setVolume");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->setVolume(channelID, leftVolume, rightVolume);
-}
-
-static void
-android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID,
-        int priority)
-{
-    ALOGV("android_media_SoundPool_setPriority");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->setPriority(channelID, priority);
-}
-
-static void
-android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID,
-        int loop)
-{
-    ALOGV("android_media_SoundPool_setLoop");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->setLoop(channelID, loop);
-}
-
-static void
-android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID,
-        float rate)
-{
-    ALOGV("android_media_SoundPool_setRate");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap == NULL) return;
-    ap->setRate(channelID, rate);
-}
-
-static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, void* user)
-{
-    ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user);
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL);
-}
-
-static jint
-android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality)
-{
-    ALOGV("android_media_SoundPool_native_setup");
-    SoundPool *ap = new SoundPool(maxChannels, (audio_stream_type_t) streamType, srcQuality);
-    if (ap == NULL) {
-        return -1;
-    }
-
-    // save pointer to SoundPool C++ object in opaque field in Java object
-    env->SetIntField(thiz, fields.mNativeContext, (int)ap);
-
-    // set callback with weak reference
-    jobject globalWeakRef = env->NewGlobalRef(weakRef);
-    ap->setCallback(android_media_callback, globalWeakRef);
-    return 0;
-}
-
-static void
-android_media_SoundPool_release(JNIEnv *env, jobject thiz)
-{
-    ALOGV("android_media_SoundPool_release");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (ap != NULL) {
-
-        // release weak reference
-        jobject weakRef = (jobject) ap->getUserData();
-        if (weakRef != NULL) {
-            env->DeleteGlobalRef(weakRef);
-        }
-
-        // clear callback and native context
-        ap->setCallback(NULL, NULL);
-        env->SetIntField(thiz, fields.mNativeContext, 0);
-        delete ap;
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-// Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
-    {   "_load",
-        "(Ljava/lang/String;I)I",
-        (void *)android_media_SoundPool_load_URL
-    },
-    {   "_load",
-        "(Ljava/io/FileDescriptor;JJI)I",
-        (void *)android_media_SoundPool_load_FD
-    },
-    {   "unload",
-        "(I)Z",
-        (void *)android_media_SoundPool_unload
-    },
-    {   "play",
-        "(IFFIIF)I",
-        (void *)android_media_SoundPool_play
-    },
-    {   "pause",
-        "(I)V",
-        (void *)android_media_SoundPool_pause
-    },
-    {   "resume",
-        "(I)V",
-        (void *)android_media_SoundPool_resume
-    },
-    {   "autoPause",
-        "()V",
-        (void *)android_media_SoundPool_autoPause
-    },
-    {   "autoResume",
-        "()V",
-        (void *)android_media_SoundPool_autoResume
-    },
-    {   "stop",
-        "(I)V",
-        (void *)android_media_SoundPool_stop
-    },
-    {   "setVolume",
-        "(IFF)V",
-        (void *)android_media_SoundPool_setVolume
-    },
-    {   "setPriority",
-        "(II)V",
-        (void *)android_media_SoundPool_setPriority
-    },
-    {   "setLoop",
-        "(II)V",
-        (void *)android_media_SoundPool_setLoop
-    },
-    {   "setRate",
-        "(IF)V",
-        (void *)android_media_SoundPool_setRate
-    },
-    {   "native_setup",
-        "(Ljava/lang/Object;III)I",
-        (void*)android_media_SoundPool_native_setup
-    },
-    {   "release",
-        "()V",
-        (void*)android_media_SoundPool_release
-    }
-};
-
-static const char* const kClassPathName = "android/media/SoundPool";
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
-    JNIEnv* env = NULL;
-    jint result = -1;
-    jclass clazz;
-
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        ALOGE("ERROR: GetEnv failed\n");
-        goto bail;
-    }
-    assert(env != NULL);
-
-    clazz = env->FindClass(kClassPathName);
-    if (clazz == NULL) {
-        ALOGE("Can't find %s", kClassPathName);
-        goto bail;
-    }
-
-    fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I");
-    if (fields.mNativeContext == NULL) {
-        ALOGE("Can't find SoundPool.mNativeContext");
-        goto bail;
-    }
-
-    fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
-                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-    if (fields.mPostEvent == NULL) {
-        ALOGE("Can't find android/media/SoundPool.postEventFromNative");
-        goto bail;
-    }
-
-    // create a reference to class. Technically, we're leaking this reference
-    // since it's a static object.
-    fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz);
-
-    if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
-        goto bail;
-
-    /* success -- return valid version number */
-    result = JNI_VERSION_1_4;
-
-bail:
-    return result;
-}
diff --git a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
new file mode 100644
index 0000000..2604850
--- /dev/null
+++ b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool-JNI"
+
+#include <utils/Log.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <media/SoundPool.h>
+
+using namespace android;
+
+static struct fields_t {
+    jfieldID    mNativeContext;
+    jmethodID   mPostEvent;
+    jclass      mSoundPoolClass;
+} fields;
+
+static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) {
+    return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext);
+}
+
+// ----------------------------------------------------------------------------
+static int
+android_media_SoundPool_SoundPoolImpl_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_load_URL");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (path == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return 0;
+    }
+    const char* s = env->GetStringUTFChars(path, NULL);
+    int id = ap->load(s, priority);
+    env->ReleaseStringUTFChars(path, s);
+    return id;
+}
+
+static int
+android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
+        jlong offset, jlong length, jint priority)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_load_FD");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return 0;
+    return ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
+            int64_t(offset), int64_t(length), int(priority));
+}
+
+static bool
+android_media_SoundPool_SoundPoolImpl_unload(JNIEnv *env, jobject thiz, jint sampleID) {
+    ALOGV("android_media_SoundPool_SoundPoolImpl_unload\n");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return 0;
+    return ap->unload(sampleID);
+}
+
+static int
+android_media_SoundPool_SoundPoolImpl_play(JNIEnv *env, jobject thiz, jint sampleID,
+        jfloat leftVolume, jfloat rightVolume, jint priority, jint loop,
+        jfloat rate)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_play\n");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return 0;
+    return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_pause(JNIEnv *env, jobject thiz, jint channelID)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_pause");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->pause(channelID);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_resume(JNIEnv *env, jobject thiz, jint channelID)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_resume");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->resume(channelID);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_autoPause(JNIEnv *env, jobject thiz)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_autoPause");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->autoPause();
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_autoResume(JNIEnv *env, jobject thiz)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_autoResume");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->autoResume();
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_stop(JNIEnv *env, jobject thiz, jint channelID)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_stop");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->stop(channelID);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_setVolume(JNIEnv *env, jobject thiz, jint channelID,
+        float leftVolume, float rightVolume)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_setVolume");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->setVolume(channelID, leftVolume, rightVolume);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_setPriority(JNIEnv *env, jobject thiz, jint channelID,
+        int priority)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_setPriority");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->setPriority(channelID, priority);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_setLoop(JNIEnv *env, jobject thiz, jint channelID,
+        int loop)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_setLoop");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->setLoop(channelID, loop);
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_setRate(JNIEnv *env, jobject thiz, jint channelID,
+        float rate)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_setRate");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap == NULL) return;
+    ap->setRate(channelID, rate);
+}
+
+static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, void* user)
+{
+    ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL);
+}
+
+static jint
+android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_native_setup");
+    SoundPool *ap = new SoundPool(maxChannels, (audio_stream_type_t) streamType, srcQuality);
+    if (ap == NULL) {
+        return -1;
+    }
+
+    // save pointer to SoundPool C++ object in opaque field in Java object
+    env->SetIntField(thiz, fields.mNativeContext, (int)ap);
+
+    // set callback with weak reference
+    jobject globalWeakRef = env->NewGlobalRef(weakRef);
+    ap->setCallback(android_media_callback, globalWeakRef);
+    return 0;
+}
+
+static void
+android_media_SoundPool_SoundPoolImpl_release(JNIEnv *env, jobject thiz)
+{
+    ALOGV("android_media_SoundPool_SoundPoolImpl_release");
+    SoundPool *ap = MusterSoundPool(env, thiz);
+    if (ap != NULL) {
+
+        // release weak reference
+        jobject weakRef = (jobject) ap->getUserData();
+        if (weakRef != NULL) {
+            env->DeleteGlobalRef(weakRef);
+        }
+
+        // clear callback and native context
+        ap->setCallback(NULL, NULL);
+        env->SetIntField(thiz, fields.mNativeContext, 0);
+        delete ap;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+// Dalvik VM type signatures
+static JNINativeMethod gMethods[] = {
+    {   "_load",
+        "(Ljava/lang/String;I)I",
+        (void *)android_media_SoundPool_SoundPoolImpl_load_URL
+    },
+    {   "_load",
+        "(Ljava/io/FileDescriptor;JJI)I",
+        (void *)android_media_SoundPool_SoundPoolImpl_load_FD
+    },
+    {   "unload",
+        "(I)Z",
+        (void *)android_media_SoundPool_SoundPoolImpl_unload
+    },
+    {   "play",
+        "(IFFIIF)I",
+        (void *)android_media_SoundPool_SoundPoolImpl_play
+    },
+    {   "pause",
+        "(I)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_pause
+    },
+    {   "resume",
+        "(I)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_resume
+    },
+    {   "autoPause",
+        "()V",
+        (void *)android_media_SoundPool_SoundPoolImpl_autoPause
+    },
+    {   "autoResume",
+        "()V",
+        (void *)android_media_SoundPool_SoundPoolImpl_autoResume
+    },
+    {   "stop",
+        "(I)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_stop
+    },
+    {   "setVolume",
+        "(IFF)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_setVolume
+    },
+    {   "setPriority",
+        "(II)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_setPriority
+    },
+    {   "setLoop",
+        "(II)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_setLoop
+    },
+    {   "setRate",
+        "(IF)V",
+        (void *)android_media_SoundPool_SoundPoolImpl_setRate
+    },
+    {   "native_setup",
+        "(Ljava/lang/Object;III)I",
+        (void*)android_media_SoundPool_SoundPoolImpl_native_setup
+    },
+    {   "release",
+        "()V",
+        (void*)android_media_SoundPool_SoundPoolImpl_release
+    }
+};
+
+static const char* const kClassPathName = "android/media/SoundPool$SoundPoolImpl";
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+    JNIEnv* env = NULL;
+    jint result = -1;
+    jclass clazz;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGE("ERROR: GetEnv failed\n");
+        goto bail;
+    }
+    assert(env != NULL);
+
+    clazz = env->FindClass(kClassPathName);
+    if (clazz == NULL) {
+        ALOGE("Can't find %s", kClassPathName);
+        goto bail;
+    }
+
+    fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I");
+    if (fields.mNativeContext == NULL) {
+        ALOGE("Can't find SoundPoolImpl.mNativeContext");
+        goto bail;
+    }
+
+    fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
+                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    if (fields.mPostEvent == NULL) {
+        ALOGE("Can't find android/media/SoundPoolImpl.postEventFromNative");
+        goto bail;
+    }
+
+    // create a reference to class. Technically, we're leaking this reference
+    // since it's a static object.
+    fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz);
+
+    if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
+        goto bail;
+
+    /* success -- return valid version number */
+    result = JNI_VERSION_1_4;
+
+bail:
+    return result;
+}
diff --git a/media/libdrm/MODULE_LICENSE_APACHE2 b/media/libdrm/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/media/libdrm/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/media/libdrm/NOTICE b/media/libdrm/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/libdrm/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-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.
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/media/libdrm/mobile1/Android.mk b/media/libdrm/mobile1/Android.mk
deleted file mode 100644
index 7356f46..0000000
--- a/media/libdrm/mobile1/Android.mk
+++ /dev/null
@@ -1,83 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# ---------------------------------------
-# First project
-# 
-# Build DRM1 core library
-#
-# Output: libdrm1.so
-# ---------------------------------------
-include $(CLEAR_VARS)
-
-ifeq ($(TARGET_ARCH), arm)
-LOCAL_DRM_CFLAG = -DDRM_DEVICE_ARCH_ARM
-endif
-
-ifeq ($(TARGET_ARCH), x86)
-LOCAL_DRM_CFLAG = -DDRM_DEVICE_ARCH_X86
-endif
-
-# DRM 1.0 core source files
-LOCAL_SRC_FILES :=                  \
-    src/objmng/drm_decoder.c        \
-    src/objmng/drm_file.c           \
-    src/objmng/drm_i18n.c           \
-    src/objmng/drm_time.c           \
-    src/objmng/drm_api.c            \
-    src/objmng/drm_rights_manager.c \
-    src/parser/parser_dcf.c         \
-    src/parser/parser_dm.c          \
-    src/parser/parser_rel.c         \
-    src/xml/xml_tinyparser.c
-
-# Header files path
-LOCAL_C_INCLUDES :=                 \
-    $(LOCAL_PATH)/include           \
-    $(LOCAL_PATH)/include/objmng    \
-    $(LOCAL_PATH)/include/parser    \
-    $(LOCAL_PATH)/include/xml       \
-    external/openssl/include        \
-    $(call include-path-for, system-core)/cutils
-
-LOCAL_CFLAGS := $(LOCAL_DRM_CFLAG)
-
-LOCAL_SHARED_LIBRARIES :=   \
-    libutils                \
-    libcutils               \
-    liblog                  \
-    libcrypto
-
-LOCAL_MODULE := libdrm1
-
-include $(BUILD_SHARED_LIBRARY)
-
-# ---------------------------------------
-# Second project
-# 
-# Build DRM1 Java Native Interface(JNI) library
-#
-# Output: libdrm1_jni.so
-# ------------------------------------------------
-include $(CLEAR_VARS)
-
-# Source files of DRM1 Java Native Interfaces
-LOCAL_SRC_FILES :=      \
-    src/jni/drm1_jni.c
-
-# Header files path
-LOCAL_C_INCLUDES :=         \
-    $(LOCAL_PATH)/include   \
-    $(LOCAL_PATH)/include/parser \
-    $(JNI_H_INCLUDE)    \
-    $(call include-path-for, system-core)/cutils
-
-
-LOCAL_SHARED_LIBRARIES := libdrm1 \
-    libnativehelper               \
-    libutils                      \
-    libcutils                     \
-    liblog
-
-LOCAL_MODULE := libdrm1_jni
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libdrm/mobile1/include/drm_common_types.h b/media/libdrm/mobile1/include/drm_common_types.h
deleted file mode 100644
index c6bea61..0000000
--- a/media/libdrm/mobile1/include/drm_common_types.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __COMMON_TYPES_H__
-#define __COMMON_TYPES_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#define Trace(...)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __COMMON_TYPES_H__ */
diff --git a/media/libdrm/mobile1/include/jni/drm1_jni.h b/media/libdrm/mobile1/include/jni/drm1_jni.h
deleted file mode 100644
index 64e78ad..0000000
--- a/media/libdrm/mobile1/include/jni/drm1_jni.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __DRM1_JNI_H__
-#define __DRM1_JNI_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class android_drm_mobile1_DrmRawContent */
-
-#undef android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK
-#define android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK 1L
-#undef android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY
-#define android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY 2L
-#undef android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY
-#define android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY 3L
-#undef android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM
-#define android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM 4L
-#undef android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE
-#define android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE 1L
-#undef android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT
-#define android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT 2L
-#undef android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS
-#define android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS 0L
-#undef android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE
-#define android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE -1L
-#undef android_drm_mobile1_DrmRawContent_JNI_DRM_EOF
-#define android_drm_mobile1_DrmRawContent_JNI_DRM_EOF -2L
-#undef android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN
-#define android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN -3L
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    nativeConstructDrmContent
- * Signature: (Ljava/io/InputStream;II)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent
-  (JNIEnv *, jobject, jobject, jint, jint);
-
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    nativeGetRightsAddress
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress
-  (JNIEnv *, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    nativeGetDeliveryMethod
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod
-  (JNIEnv *, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    nativeReadPieceOfContent
- * Signature: ([BIII)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeReadContent
-  (JNIEnv *, jobject, jbyteArray, jint, jint, jint);
-
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    nativeGetContentType
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetContentType
-  (JNIEnv *, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    nativeGetContentLength
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength
-  (JNIEnv *, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRawContent
- * Method:    finalize
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_android_drm_mobile1_DrmRawContent_finalize
-  (JNIEnv *, jobject);
-
-/* Header for class android_drm_mobile1_DrmRights */
-
-#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY
-#define android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY 1L
-#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY
-#define android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY 2L
-#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE
-#define android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE 3L
-#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT
-#define android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT 4L
-#undef android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_SUCCESS
-#define android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_SUCCESS 0L
-#undef android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_FAILURE
-#define android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_FAILURE -1L
-#undef android_drm_mobile1_DrmRights_JNI_DRM_SUCCESS
-#define android_drm_mobile1_DrmRights_JNI_DRM_SUCCESS 0L
-#undef android_drm_mobile1_DrmRights_JNI_DRM_FAILURE
-#define android_drm_mobile1_DrmRights_JNI_DRM_FAILURE -1L
-/*
- * Class:     android_drm_mobile1_DrmRights
- * Method:    nativeGetConstraintInfo
- * Signature: (ILandroid/drm/mobile1/DrmConstraintInfo;)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo
-  (JNIEnv *, jobject, jint, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRights
- * Method:    nativeConsumeRights
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRights_nativeConsumeRights
-  (JNIEnv *, jobject, jint);
-
-/* Header for class android_drm_mobile1_DrmRightsManager */
-
-#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML
-#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML 3L
-#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML
-#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML 4L
-#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_MESSAGE
-#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_MESSAGE 1L
-#undef android_drm_mobile1_DrmRightsManager_JNI_DRM_SUCCESS
-#define android_drm_mobile1_DrmRightsManager_JNI_DRM_SUCCESS 0L
-#undef android_drm_mobile1_DrmRightsManager_JNI_DRM_FAILURE
-#define android_drm_mobile1_DrmRightsManager_JNI_DRM_FAILURE -1L
-/* Inaccessible static: singleton */
-/*
- * Class:     android_drm_mobile1_DrmRightsManager
- * Method:    nativeInstallDrmRights
- * Signature: (Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights
-  (JNIEnv *, jobject, jobject, jint, jint, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRightsManager
- * Method:    nativeQueryRights
- * Signature: (Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights
-  (JNIEnv *, jobject, jobject, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRightsManager
- * Method:    nativeGetRightsNumber
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights
-  (JNIEnv *, jobject);
-
-/*
- * Class:     android_drm_mobile1_DrmRightsManager
- * Method:    nativeGetRightsList
- * Signature: ([Landroid/drm/mobile1/DrmRights;I)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList
-  (JNIEnv *, jobject, jobjectArray, jint);
-
-/*
- * Class:     android_drm_mobile1_DrmRightsManager
- * Method:    nativeDeleteRights
- * Signature: (Landroid/drm/mobile1/DrmRights;)I
- */
-JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights
-  (JNIEnv *, jobject, jobject);
-
-/**
- * DRM return value defines
- */
-#define JNI_DRM_SUCCESS \
-    android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS   /**< Successful operation */
-#define JNI_DRM_FAILURE \
-    android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE   /**< General failure */
-#define JNI_DRM_EOF \
-    android_drm_mobile1_DrmRawContent_JNI_DRM_EOF       /**< Indicates the end of the DRM content is reached */
-#define JNI_DRM_UNKNOWN_DATA_LEN \
-    android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN  /**< Indicates the data length is unknown */
-
-/**
- * DRM MIME type defines
- */
-#define JNI_DRM_MIMETYPE_MESSAGE \
-    android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE          /**< The "application/vnd.oma.drm.message" MIME type */
-#define JNI_DRM_MIMETYPE_CONTENT \
-    android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT          /**< The "application/vnd.oma.drm.content" MIME type */
-#define JNI_DRM_MIMETYPE_RIGHTS_XML \
-    android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML    /**< The "application/vnd.oma.drm.rights+xml" MIME type */
-#define JNI_DRM_MIMETYPE_RIGHTS_WBXML \
-    android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML  /**< The "application/vnd.oma.drm.rights+wbxml" MIME type */
-
-/**
- * DRM permission defines
- */
-#define JNI_DRM_PERMISSION_PLAY \
-    android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY       /**< The permission to play */
-#define JNI_DRM_PERMISSION_DISPLAY \
-    android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY    /**< The permission to display */
-#define JNI_DRM_PERMISSION_EXECUTE \
-    android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE    /**< The permission to execute */
-#define JNI_DRM_PERMISSION_PRINT \
-    android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT      /**< The permission to print */
-
-/**
- * DRM delivery type defines
- */
-#define JNI_DRM_FORWARD_LOCK \
-    android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK          /**< forward lock */
-#define JNI_DRM_COMBINED_DELIVERY \
-    android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY     /**< combined delivery */
-#define JNI_DRM_SEPARATE_DELIVERY \
-    android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY     /**< separate delivery */
-#define JNI_DRM_SEPARATE_DELIVERY_DM \
-    android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM  /**< separate delivery DRM message */
-#ifdef __cplusplus
-}
-#endif
-#endif /* __DRM1_JNI_H__ */
-
diff --git a/media/libdrm/mobile1/include/objmng/drm_decoder.h b/media/libdrm/mobile1/include/objmng/drm_decoder.h
deleted file mode 100644
index a769c81..0000000
--- a/media/libdrm/mobile1/include/objmng/drm_decoder.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file drm_decoder.h
- *
- * provide service to decode base64 data.
- *
- * <!-- #interface list begin -->
- * \section drm decoder interface
- * - drm_decodeBase64()
- * <!-- #interface list end -->
- */
-
-#ifndef __DRM_DECODER_H__
-#define __DRM_DECODER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-/**
- * Decode base64
- * \param dest          dest buffer to save decode base64 data
- * \param destLen       dest buffer length
- * \param src           source data to be decoded
- * \param srcLen        source buffer length, and when return, give out how many bytes has been decoded
- * \return
- *        -when success, return a positive integer of dest buffer length,
- *                       if input dest buffer is NULL or destLen is 0,
- *                       return dest buffer length that user should allocate to save decoding data
- *        -when failed, return -1
- */
-int32_t drm_decodeBase64(uint8_t * dest, int32_t destLen, uint8_t * src, int32_t * srcLen);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DRM_DECODER_H__ */
diff --git a/media/libdrm/mobile1/include/objmng/drm_file.h b/media/libdrm/mobile1/include/objmng/drm_file.h
deleted file mode 100644
index b94ddd0..0000000
--- a/media/libdrm/mobile1/include/objmng/drm_file.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/**
- * File Porting Layer.
- */
-#ifndef __DRM_FILE_H__
-#define __DRM_FILE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-/** Type value of a regular file or file name. */
-#define DRM_FILE_ISREG 1
-/** Type value of a directory or directory name. */
-#define DRM_FILE_ISDIR 2
-/** Type value of a filter name */
-#define DRM_FILE_ISFILTER 3
-
-
-/** Return code that indicates successful completion of an operation. */
-#define DRM_FILE_SUCCESS 0
-/** Indicates that an operation failed. */
-#define DRM_FILE_FAILURE -1
-/** Indicates that the a DRM_file_read() call reached the end of the file. */
-#define DRM_FILE_EOF -2
-
-
-/** Open for read access. */
-#define DRM_FILE_MODE_READ 1
-/** Open for write access. */
-#define DRM_FILE_MODE_WRITE 2
-
-
-#ifndef MAX_FILENAME_LEN
-/** Maximum number of characters that a filename may have. By default assumes
- *  that the entry results of DRM_file_listNextEntry() are returned in the async state
- *  buffer, after the #DRM_file_result_s, and calculates the maximum name
- *  from that.
- */
-#define MAX_FILENAME_LEN 1024
-#endif
-
-
-/**
- * Performs one-time initialization of the File System (FS).
- * This function is called once during the lifetime of an application,
- * and before any call to <code>DRM_file_*</code> functions by this application.
- * When several applications are using the file interface, this function may be called
- * several times, once per application.
- *
- * @return #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_startup(void);
-
-/**
- * Returns the length of a file (by name, opened or unopened).
- *
- * @param name Name of the file, UCS-2 encoded.
- * @param nameChars Number characters encoded in name.
- * asynchronous operation returns #DRM_FILE_WOULDBLOCK.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the file length.
- */
-int32_t DRM_file_getFileLength(const uint16_t* name,
-                               int32_t nameChars);
-
-/**
- * Initializes a list iteration session.
- *
- * @param prefix Prefix that must be matched, UCS-2 encoded. *
- * @param prefixChars Number characters encoded in prefix.
- * @param session List session identifier.
- * @param iteration List iteration identifier.
- *
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_listOpen(const uint16_t* prefix,
-                          int32_t prefixChars,
-                          int32_t* session,
-                          int32_t* iteration);
-
-/**
- * Used to fetch a list of file names that match a given name prefix.
- *
- * @param prefix See DRM_file_listOpen(). This does not change during the
- * iteration session.
- * @param prefixChars See DRM_file_listOpen(). This does not change during
- * the iteration session.
- * @param entry Buffer parameter to return the next file name that matches the
- * #prefix parameter, if any, when the function returns a positive number of
- * characters.
- * @param entryBytes Size of entry in bytes.
- * @param session See DRM_file_listOpen().
- * @param iteration See DRM_file_listOpen().
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the number of
- * characters encoded in entry. Returns 0 when the end of the list is reached.
- */
-int32_t DRM_file_listNextEntry(const uint16_t* prefix,
-                               int32_t prefixChars,
-                               uint16_t* entry,
-                               int32_t entryBytes,
-                               int32_t* session,
-                               int32_t* iteration);
-
-/**
- * Ends a list iteration session. Notifies the implementation
- * that the list session is over and that any session resources
- * can be released.
- *
- * @param session See DRM_file_listOpen().
- * @param iteration See DRM_file_listOpen().
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_listClose(int32_t session, int32_t iteration);
-
-/**
- * Renames a file, given its old name. The file or directory is renamed
- * immediately on the actual file system upon invocation of this method.
- * Any open handles on the file specified by oldName become invalid after
- * this method has been called.
- *
- * @param oldName Current file name (unopened), UCS-2 encoded.
- * @param oldNameChars Number of characters encoded on oldName.
- * @param newName New name for the file (unopened), UCS-2 encoded.
- * @param newNameChars Number of characters encoded on newName.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. In particular,
- * #DRM_FILE_FAILURE if a file or directory already exists with the new name.
- */
-int32_t DRM_file_rename(const uint16_t* oldName,
-                        int32_t oldNameChars,
-                        const uint16_t* newName,
-                        int32_t newNameChars);
-
-/**
- * Tests if a file exists given its name.
- *
- * @param name Name of the file, UCS-2 encoded.
- * @param nameChars Number of characters encoded in name.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_ISREG, #DRM_FILE_ISDIR, #DRM_FILE_FAILURE. If name
- * exists, returns #DRM_FILE_ISREG if it is a regular file and #DRM_FILE_ISDIR if it is a directory.
- * Returns #DRM_FILE_FAILURE in all other cases, including those where name exists but is neither
- * a regular file nor a directory. Platforms that do not support directories MUST NOT return
- * #DRM_FILE_ISDIR.
- */
-int32_t DRM_file_exists(const uint16_t* name,
-                        int32_t nameChars);
-
-/**
- * Opens a file with the given name and returns its file handle.
- *
- * @param name Name of the file, UCS-2 encoded.
- * @param nameChars Number of characters encoded in name.
- * @param mode Any combination of the #DRM_FILE_MODE_READ and
- * #DRM_FILE_MODE_WRITE flags. If the file does not exist and mode contains the
- * #DRM_FILE_MODE_WRITE flag, then the file is automatically created. If the
- * file exists and the mode contains the #DRM_FILE_MODE_WRITE flag, the file is
- * opened so it can be modified, but the data is not modified by the open call.
- * In all cases the current position is set to the start of the file.
- * The following table shows how to map the mode semantics above to UNIX
- * fopen-style modes.  For brevity in the table, R=#DRM_FILE_MODE_READ,
- * W=#DRM_FILE_MODE_WRITE, E=File exists:
- * <table>
- * <tr><td>RW</td><td>E</td><td>Maps-to</td></tr>
- * <tr><td>00</td><td>0</td><td>Return #DRM_FILE_FAILURE</td></tr>
- * <tr><td>00</td><td>1</td><td>Return #DRM_FILE_FAILURE</td></tr>
- * <tr><td>01</td><td>0</td><td>Use fopen mode "w"</td></tr>
- * <tr><td>01</td><td>1</td><td>Use fopen mode "a" and fseek to the start</td></tr>
- * <tr><td>10</td><td>0</td><td>Return #DRM_FILE_FAILURE</td></tr>
- * <tr><td>10</td><td>1</td><td>Use fopen mode "r"</td></tr>
- * <tr><td>11</td><td>0</td><td>Use fopen mode "w+"</td></tr>
- * <tr><td>11</td><td>1</td><td>Use fopen mode "r+"</td></tr>
- * </table>
- * @param handle Pointer where the result handle value is placed when the function
- * is called synchronously.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_open(const uint16_t* name,
-                      int32_t nameChars,
-                      int32_t mode,
-                      int32_t* handle);
-
-/**
- * Deletes a file given its name, UCS-2 encoded. The file or directory is
- * deleted immediately on the actual file system upon invocation of this
- * method. Any open handles on the file specified by name become invalid
- * after this method has been called.
- *
- * If the port needs to ensure that a specific application does not exceed a given storage
- * space quota, then the bytes freed by the deletion must be added to the available space for
- * that application.
- *
- * @param name Name of the file, UCS-2 encoded.
- * @param nameChars Number of characters encoded in name.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_delete(const uint16_t* name,
-                        int32_t nameChars);
-
-/**
- * Read bytes from a file at the current position to a buffer. Afterwards the
- * new file position is the byte after the last byte read.
- * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a
- * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close).
- *
- * @param handle File handle as returned by DRM_file_open().
- * @param dst Buffer where the data is to be copied.
- * @param length Number of bytes to be copied.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE, #DRM_FILE_EOF
- *         or the number of bytes that were read, i.e. in the range 0..length.
- */
-int32_t DRM_file_read(int32_t handle,
-                      uint8_t* dst,
-                      int32_t length);
-
-/**
- * Write bytes from a buffer to the file at the current position.  If the
- * current position + number of bytes written > current size of the file,
- * then the file is grown.  Afterwards the new file position is the byte
- * after the last byte written.
- * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a
- * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close).
- *
- * @param handle File handle as returned by DRM_file_open().
- * @param src Buffer that contains the bytes to be written.
- * @param length Number of bytes to be written.
- * If the port needs to ensure that a specific application does not exceed a given storage
- * space quota, the implementation must make sure the call does not violate that invariant.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the number of bytes
- *         that were written. This number must be in the range 0..length.
- *         Returns #DRM_FILE_FAILURE when storage is full or exceeds quota.
- */
-int32_t DRM_file_write(int32_t handle,
-                       const uint8_t* src,
-                       int32_t length);
-
-/**
- * Closes a file.
- * DRM_FILE_SUCCESS is returned if the handle is invalid (e.g., as a
- * consquence of DRM_file_delete or DRM_file_rename).
- *
- * @param handle File handle as returned by DRM_file_open().
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_close(int32_t handle);
-
-/**
- * Sets the current position in an opened file.
- * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a
- * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close).
- *
- * @param handle File handle as returned by DRM_file_open().
- * @param value The new current position of the file. If value is greater
- * than the length of the file then the file should be extended. The contents
- * of the newly extended portion of the file is undefined.
- * If the port needs to ensure that a specific application does not exceed a given storage
- * space quota, the implementation must make sure the call does not violate that invariant.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- *         Returns #DRM_FILE_FAILURE when storage is full or exceeds quota.
- */
-int32_t DRM_file_setPosition(int32_t handle, int32_t value);
-
-/**
- * Creates a directory with the assigned name and full file permissions on
- * the file system. The full path to the new directory must already exist.
- * The directory is created immediately on the actual file system upon
- * invocation of this method.
- *
- * @param name Name of the directory, UCS-2 encoded.
- * @param nameChars Number of characters encoded in name.
- * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE.
- */
-int32_t DRM_file_mkdir(const uint16_t* name,
-                       int32_t nameChars);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DRM_FILE_H__ */
diff --git a/media/libdrm/mobile1/include/objmng/drm_i18n.h b/media/libdrm/mobile1/include/objmng/drm_i18n.h
deleted file mode 100644
index 7487e9b..0000000
--- a/media/libdrm/mobile1/include/objmng/drm_i18n.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef __DRM_I18N_H__
-#define __DRM_I18N_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-/**
- * @name Charset value defines
- * @ingroup i18n
- *
- * Charset value defines
- * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_81rn.asp
- */
-typedef enum {
-    DRM_CHARSET_GBK        = 936,      /** Simplified Chinese GBK (CP936) */
-    DRM_CHARSET_GB2312     = 20936,    /** Simplified Chinese GB2312 (CP936) */
-    DRM_CHARSET_BIG5       = 950,      /** BIG5 (CP950) */
-    DRM_CHARSET_LATIN1     = 28591,    /** ISO 8859-1, Latin 1 */
-    DRM_CHARSET_LATIN2     = 28592,    /** ISO 8859-2, Latin 2 */
-    DRM_CHARSET_LATIN3     = 28593,    /** ISO 8859-3, Latin 3 */
-    DRM_CHARSET_LATIN4     = 28594,    /** ISO 8859-4, Latin 4 */
-    DRM_CHARSET_CYRILLIC   = 28595,    /** ISO 8859-5, Cyrillic */
-    DRM_CHARSET_ARABIC     = 28596,    /** ISO 8859-6, Arabic */
-    DRM_CHARSET_GREEK      = 28597,    /** ISO 8859-7, Greek */
-    DRM_CHARSET_HEBREW     = 28598,    /** ISO 8859-8, Hebrew */
-    DRM_CHARSET_LATIN5     = 28599,    /** ISO 8859-9, Latin 5 */
-    DRM_CHARSET_LATIN6     = 865,      /** ISO 8859-10, Latin 6 (not sure here) */
-    DRM_CHARSET_THAI       = 874,      /** ISO 8859-11, Thai */
-    DRM_CHARSET_LATIN7     = 1257,     /** ISO 8859-13, Latin 7 (not sure here) */
-    DRM_CHARSET_LATIN8     = 38598,    /** ISO 8859-14, Latin 8 (not sure here) */
-    DRM_CHARSET_LATIN9     = 28605,    /** ISO 8859-15, Latin 9 */
-    DRM_CHARSET_LATIN10    = 28606,    /** ISO 8859-16, Latin 10 */
-    DRM_CHARSET_UTF8       = 65001,    /** UTF-8 */
-    DRM_CHARSET_UTF16LE    = 1200,     /** UTF-16 LE */
-    DRM_CHARSET_UTF16BE    = 1201,     /** UTF-16 BE */
-    DRM_CHARSET_HINDI      = 57002,    /** Hindi/Mac Devanagari */
-    DRM_CHARSET_UNSUPPORTED = -1
-} DRM_Charset_t;
-
-/**
- * Convert multibyte string of specified charset to unicode string.
- * Note NO terminating '\0' will be appended to the output unicode string.
- *
- * @param charset Charset of the multibyte string.
- * @param mbs Multibyte string to be converted.
- * @param mbsLen Number of the bytes (in mbs) to be converted.
- * @param wcsBuf Buffer for the converted unicode characters.
- *               If wcsBuf is NULL, the function returns the number of unicode
- *               characters required for the buffer.
- * @param bufSizeInWideChar The size (in wide char) of wcsBuf
- * @param bytesConsumed The number of bytes in mbs that have been successfully
- *                      converted. The value of *bytesConsumed is undefined
- *                      if wcsBuf is NULL.
- *
- * @return Number of the successfully converted unicode characters if wcsBuf
- *         is not NULL. If wcsBuf is NULL, returns required unicode buffer
- *         size. -1 for unrecoverable errors.
- */
-int32_t DRM_i18n_mbsToWcs(DRM_Charset_t charset,
-        const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed);
-
-/**
- * Convert unicode string to multibyte string with specified charset.
- * Note NO terminating '\0' will be appended to the output multibyte string.
- *
- * @param charset Charset of the multibyte string to be converted to.
- * @param wcs     Unicode string to be converted.
- * @param wcsLen  Number of the unicode characters (in wcs) to be converted.
- * @param mbsBuf  Buffer for converted multibyte characters.
- *                If mbsBuf is NULL, the function returns the number of bytes
- *                required for the buffer.
- * @param bufSizeInByte The size (in byte) of mbsBuf.
- *
- * @return Number of the successfully converted bytes.
- */
-int32_t DRM_i18n_wcsToMbs(DRM_Charset_t charset,
-        const uint16_t *wcs, int32_t wcsLen,
-        uint8_t *mbsBuf, int32_t bufSizeInByte);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/media/libdrm/mobile1/include/objmng/drm_inner.h b/media/libdrm/mobile1/include/objmng/drm_inner.h
deleted file mode 100644
index 55234f8..0000000
--- a/media/libdrm/mobile1/include/objmng/drm_inner.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __DRM_INNER_H__
-#define __DRM_INNER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-#define INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time) do{\
-    year = date / 10000;\
-    mon = date % 10000 / 100;\
-    day = date %100;\
-    hour = time / 10000;\
-    min = time % 10000 / 100;\
-    sec = time % 100;\
-}while(0)
-
-/**
- * Define the max malloc length for a DRM.
- */
-#define DRM_MAX_MALLOC_LEN          (50 * 1024) /* 50K */
-
-#define DRM_ONE_AES_BLOCK_LEN       16
-#define DRM_TWO_AES_BLOCK_LEN       32
-
-typedef struct _T_DRM_DM_Binary_Node {
-    uint8_t boundary[256];
-} T_DRM_DM_Binary_Node;
-
-typedef struct _T_DRM_DM_Base64_Node {
-    uint8_t boundary[256];
-    uint8_t b64DecodeData[4];
-    int32_t b64DecodeDataLen;
-} T_DRM_DM_Base64_Node;
-
-typedef struct _T_DRM_Dcf_Node {
-    uint8_t rightsIssuer[256];
-    int32_t encContentLength;
-    uint8_t aesDecData[16];
-    int32_t aesDecDataLen;
-    int32_t aesDecDataOff;
-    uint8_t aesBackupBuf[16];
-    int32_t bAesBackupBuf;
-} T_DRM_Dcf_Node;
-
-typedef struct _T_DRM_Session_Node {
-    int32_t sessionId;
-    int32_t inputHandle;
-    int32_t mimeType;
-    int32_t (*getInputDataLengthFunc)(int32_t inputHandle);
-    int32_t (*readInputDataFunc)(int32_t inputHandle, uint8_t* buf, int32_t bufLen);
-    int32_t (*seekInputDataFunc)(int32_t inputHandle, int32_t offset);
-    int32_t deliveryMethod;
-    int32_t transferEncoding;
-    uint8_t contentType[64];
-    int32_t contentLength;
-    int32_t contentOffset;
-    uint8_t contentID[256];
-    uint8_t* rawContent;
-    int32_t rawContentLen;
-    int32_t bEndData;
-    uint8_t* readBuf;
-    int32_t readBufLen;
-    int32_t readBufOff;
-    void* infoStruct;
-    struct _T_DRM_Session_Node* next;
-} T_DRM_Session_Node;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DRM_INNER_H__ */
diff --git a/media/libdrm/mobile1/include/objmng/drm_rights_manager.h b/media/libdrm/mobile1/include/objmng/drm_rights_manager.h
deleted file mode 100644
index d81e7a1..0000000
--- a/media/libdrm/mobile1/include/objmng/drm_rights_manager.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __DRM_RIGHTS_MANAGER_H__
-#define __DRM_RIGHTS_MANAGER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <openssl/aes.h>
-#include <drm_common_types.h>
-#include <parser_rel.h>
-
-#ifdef DRM_DEVICE_ARCH_ARM
-#define ANDROID_DRM_CORE_PATH   "/data/drm/rights/"
-#define DRM_UID_FILE_PATH       "/data/drm/rights/uid.txt"
-#else
-#define ANDROID_DRM_CORE_PATH   "/home/user/golf/esmertec/device/out/debug/host/linux-x86/product/sim/data/data/com.android.drm.mobile1/"
-#define DRM_UID_FILE_PATH       "/home/user/golf/esmertec/device/out/debug/host/linux-x86/product/sim/data/data/com.android.drm.mobile1/uid.txt"
-#endif
-
-#define EXTENSION_NAME_INFO     ".info"
-
-#define GET_ID      1
-#define GET_UID     2
-
-#define GET_ROAMOUNT        1
-#define GET_ALL_RO          2
-#define SAVE_ALL_RO         3
-#define GET_A_RO            4
-#define SAVE_A_RO           5
-
-/**
- * Get the id or uid from the "uid.txt" file.
- *
- * \param Uid       The content id for a specially DRM object.
- * \param id        The id number managed by DRM engine for a specially DRM object.
- * \param option    The option to get id or uid, the value includes: GET_ID, GET_UID.
- *
- * \return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_readFromUidTxt(uint8_t* Uid, int32_t* id, int32_t option);
-
-/**
- * Save or read the rights information on the "id.info" file.
- *
- * \param id        The id number managed by DRM engine for a specially DRM object.
- * \param Ro        The rights structure to save the rights information.
- * \param RoAmount  The number of rights for this DRM object.
- * \param option    The option include: GET_ROAMOUNT, GET_ALL_RO, SAVE_ALL_RO, GET_A_RO, SAVE_A_RO.
- *
- * \return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_writeOrReadInfo(int32_t id, T_DRM_Rights* Ro, int32_t* RoAmount, int32_t option);
-
-/**
- * Append a rights information to DRM engine storage.
- *
- * \param Ro        The rights structure to save the rights information.
- *
- * return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_appendRightsInfo(T_DRM_Rights* rights);
-
-/**
- * Get the mex id number from the "uid.txt" file.
- *
- * \return
- *      -an integer to indicate the max id number.
- *      -(-1), if the operation failed.
- */
-int32_t drm_getMaxIdFromUidTxt();
-
-/**
- * Remove the "id.info" file if all the rights for this DRM object has been deleted.
- *
- * \param id        The id number managed by DRM engine for a specially DRM object.
- *
- * \return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_removeIdInfoFile(int32_t id);
-
-/**
- * Update the "uid.txt" file when delete the rights object.
- *
- * \param id        The id number managed by DRM engine for a specially DRM object.
- *
- * \return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_updateUidTxtWhenDelete(int32_t id);
-
-/**
- * Get the CEK according the given content id.
- *
- * \param uid       The content id for a specially DRM object.
- * \param KeyValue  The buffer to save the CEK.
- *
- * \return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_getKey(uint8_t* uid, uint8_t* KeyValue);
-
-/**
- * Discard the padding bytes in DCF decrypted data.
- *
- * \param decryptedBuf      The aes decrypted data buffer to be scanned.
- * \param decryptedBufLen   The length of the buffer. And save the output result.
- *
- * \return
- *      -0
- */
-void drm_discardPaddingByte(uint8_t *decryptedBuf, int32_t *decryptedBufLen);
-
-/**
- * Decrypt the media data according the CEK.
- *
- * \param Buffer    The buffer to decrypted and also used to save the output data.
- * \param BufferLen The length of the buffer data and also save the output data length.
- * \param key       The structure of the CEK.
- *
- * \return
- *      -0
- */
-int32_t drm_aesDecBuffer(uint8_t * Buffer, int32_t * BufferLen, AES_KEY *key);
-
-/**
- * Update the DCF data length according the CEK.
- *
- * \param pDcfLastData  The last several byte for the DCF.
- * \param keyValue  The CEK of the DRM content.
- * \param moreBytes Output the more bytes for discarded.
- *
- * \return
- *      -TRUE, if the operation successfully.
- *      -FALSE, if the operation failed.
- */
-int32_t drm_updateDcfDataLen(uint8_t* pDcfLastData, uint8_t* keyValue, int32_t* moreBytes);
-
-/**
- * Check and update the rights for a specially DRM content.
- *
- * \param id        The id number managed by DRM engine for a specially DRM object.
- * \param permission    The permission to be check and updated.
- *
- * \return
- *      -DRM_SUCCESS, if there is a valid rights and update it successfully.
- *      -DRM_NO_RIGHTS, if there is no rights for this content.
- *      -DRM_RIGHTS_PENDING, if the rights is pending.
- *      -DRM_RIGHTS_EXPIRED, if the rights has expired.
- *      -DRM_RIGHTS_FAILURE, if there is some other error occur.
- */
-int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DRM_RIGHTS_MANAGER_H__ */
diff --git a/media/libdrm/mobile1/include/objmng/drm_time.h b/media/libdrm/mobile1/include/objmng/drm_time.h
deleted file mode 100644
index 9b013e6..0000000
--- a/media/libdrm/mobile1/include/objmng/drm_time.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/**
- * @file
- * Time Porting Layer
- *
- * Basic support functions that are needed by time.
- *
- * <!-- #interface list begin -->
- * \section drm_time Interface
- * - DRM_time_getElapsedSecondsFrom1970()
- * - DRM_time_sleep()
- * - DRM_time_getSysTime()
- * <!-- #interface list end -->
- */
-
-#ifndef __DRM_TIME_H__
-#define __DRM_TIME_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <time.h>
-#include <drm_common_types.h>
-
-/** the time format */
-typedef struct __db_system_time_
-{
-    uint16_t year;
-    uint16_t month;
-    uint16_t day;
-    uint16_t hour;
-    uint16_t min;
-    uint16_t sec;
-} T_DB_TIME_SysTime;
-
-/**
- * Get the system time.it's up to UTC
- * \return Return the time in elapsed seconds.
- */
-uint32_t DRM_time_getElapsedSecondsFrom1970(void);
-
-/**
- * Suspend the execution of the current thread for a specified interval
- * \param ms suspended time by millisecond
- */
-void DRM_time_sleep(uint32_t ms);
-
-/**
- * function: get current system time
- * \param  time_ptr[OUT]  the system time got
- * \attention
- *    time_ptr must not be NULL
- */
-void DRM_time_getSysTime(T_DB_TIME_SysTime *time_ptr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DRM_TIME_H__ */
diff --git a/media/libdrm/mobile1/include/objmng/svc_drm.h b/media/libdrm/mobile1/include/objmng/svc_drm.h
deleted file mode 100644
index 789343f..0000000
--- a/media/libdrm/mobile1/include/objmng/svc_drm.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SVC_DRM_NEW_H__
-#define __SVC_DRM_NEW_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-/**
- * Define the mime type of DRM data.
- */
-#define TYPE_DRM_MESSAGE            0x48    /**< The mime type is "application/vnd.oma.drm.message" */
-#define TYPE_DRM_CONTENT            0x49    /**< The mime type is "application/vnd.oma.drm.content" */
-#define TYPE_DRM_RIGHTS_XML         0x4a    /**< The mime type is "application/vnd.oma.drm.rights+xml" */
-#define TYPE_DRM_RIGHTS_WBXML       0x4b    /**< The mime type is "application/vnd.oma.drm.rights+wbxml" */
-#define TYPE_DRM_UNKNOWN            0xff    /**< The mime type is unknown */
-
-/**
- * Define the delivery methods.
- */
-#define FORWARD_LOCK                1       /**< Forward_lock */
-#define COMBINED_DELIVERY           2       /**< Combined delivery */
-#define SEPARATE_DELIVERY           3       /**< Separate delivery */
-#define SEPARATE_DELIVERY_FL        4       /**< Separate delivery but DCF is forward-lock */
-
-/**
- * Define the permissions.
- */
-#define DRM_PERMISSION_PLAY         0x01    /**< Play */
-#define DRM_PERMISSION_DISPLAY      0x02    /**< Display */
-#define DRM_PERMISSION_EXECUTE      0x04    /**< Execute */
-#define DRM_PERMISSION_PRINT        0x08    /**< Print */
-#define DRM_PERMISSION_FORWARD      0x10    /**< Forward */
-
-/**
- * Define the constraints.
- */
-#define DRM_NO_CONSTRAINT           0x80    /**< Indicate have no constraint, it can use freely */
-#define DRM_END_TIME_CONSTRAINT     0x08    /**< Indicate have end time constraint */
-#define DRM_INTERVAL_CONSTRAINT     0x04    /**< Indicate have interval constraint */
-#define DRM_COUNT_CONSTRAINT        0x02    /**< Indicate have count constraint */
-#define DRM_START_TIME_CONSTRAINT   0x01    /**< Indicate have start time constraint */
-#define DRM_NO_PERMISSION           0x00    /**< Indicate no rights */
-
-/**
- * Define the return values for those interface.
- */
-#define DRM_SUCCESS                 0
-#define DRM_FAILURE                 -1
-#define DRM_MEDIA_EOF               -2
-#define DRM_RIGHTS_DATA_INVALID     -3
-#define DRM_MEDIA_DATA_INVALID      -4
-#define DRM_SESSION_NOT_OPENED      -5
-#define DRM_NO_RIGHTS               -6
-#define DRM_NOT_SD_METHOD           -7
-#define DRM_RIGHTS_PENDING          -8
-#define DRM_RIGHTS_EXPIRED          -9
-#define DRM_UNKNOWN_DATA_LEN        -10
-
-/**
- * The input DRM data structure, include DM, DCF, DR, DRC.
- */
-typedef struct _T_DRM_Input_Data {
-    /**
-     * The handle of the input DRM data.
-     */
-    int32_t inputHandle;
-
-    /**
-     * The mime type of the DRM data, if the mime type set to unknown, DRM engine
-     * will try to scan the input data to confirm the mime type, but we must say that
-     * the scan and check of mime type is not strictly precise.
-     */
-    int32_t mimeType;
-
-    /**
-     * The function to get input data length, this function should be implement by out module,
-     * and DRM engine will call-back it.
-     *
-     * \param inputHandle   The handle of the DRM data.
-     *
-     * \return
-     *      -A positive integer indicate the length of input data.
-     *      -0, if some error occurred.
-     */
-    int32_t (*getInputDataLength)(int32_t inputHandle);
-
-    /**
-     * The function to read the input data, this function should be implement by out module,
-     * and DRM engine will call-back it.
-     *
-     * \param inputHandle   The handle of the DRM data.
-     * \param buf       The buffer mallocced by DRM engine to save the data.
-     * \param bufLen    The length of the buffer.
-     *
-     * \return
-     *      -A positive integer indicate the actually length of byte has been read.
-     *      -0, if some error occurred.
-     *      -(-1), if reach to the end of the data.
-     */
-    int32_t (*readInputData)(int32_t inputHandle, uint8_t* buf, int32_t bufLen);
-
-    /**
-     * The function to seek the current file pointer, this function should be implement by out module,
-     * and DRM engine will call-back it.
-     *
-     * \param inputHandle   The handle of the DRM data.
-     * \param offset    The offset from the start position to be seek.
-     *
-     * \return
-     *      -0, if seek operation success.
-     *      -(-1), if seek operation fail.
-     */
-    int32_t (*seekInputData)(int32_t inputHandle, int32_t offset);
-} T_DRM_Input_Data;
-
-/**
- * The constraint structure.
- */
-typedef struct _T_DRM_Constraint_Info {
-    uint8_t indicator;          /**< Whether there is a right */
-    uint8_t unUsed[3];
-    int32_t count;              /**< The constraint of count */
-    int32_t startDate;          /**< The constraint of start date */
-    int32_t startTime;          /**< The constraint of start time */
-    int32_t endDate;            /**< The constraint of end date */
-    int32_t endTime;            /**< The constraint of end time */
-    int32_t intervalDate;       /**< The constraint of interval date */
-    int32_t intervalTime;       /**< The constraint of interval time */
-} T_DRM_Constraint_Info;
-
-/**
- * The rights permission and constraint information structure.
- */
-typedef struct _T_DRM_Rights_Info {
-    uint8_t roId[256];                     /**< The unique id for a specially rights object */
-    T_DRM_Constraint_Info playRights;       /**< Constraint of play */
-    T_DRM_Constraint_Info displayRights;    /**< Constraint of display */
-    T_DRM_Constraint_Info executeRights;    /**< Constraint of execute */
-    T_DRM_Constraint_Info printRights;      /**< Constraint of print */
-} T_DRM_Rights_Info;
-
-/**
- * The list node of the Rights information structure.
- */
-typedef struct _T_DRM_Rights_Info_Node {
-    T_DRM_Rights_Info roInfo;
-    struct _T_DRM_Rights_Info_Node *next;
-} T_DRM_Rights_Info_Node;
-
-/**
- * Install a rights object to DRM engine, include the rights in Combined Delivery cases.
- * Because all the rights object is managed by DRM engine, so every incoming rights object
- * must be install to the engine first, or the DRM engine will not recognize it.
- *
- * \param data      The rights object data or Combined Delivery case data.
- * \param pRightsInfo   The structure to save this rights information.
- *
- * \return
- *      -DRM_SUCCESS, when install successfully.
- *      -DRM_RIGHTS_DATA_INVALID, when the input rights data is invalid.
- *      -DRM_FAILURE, when some other error occur.
- */
-int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo);
-
-/**
- * Open a session for a special DRM object, it will parse the input DRM data, and then user
- * can try to get information for this DRM object, or try to use it if the rights is valid.
- *
- * \param data      The DRM object data, DM or DCF.
- *
- * \return
- *      -A handle for this opened DRM object session.
- *      -DRM_MEDIA_DATA_INVALID, when the input DRM object data is invalid.
- *      -DRM_FAILURE, when some other error occurred.
- */
-int32_t SVC_drm_openSession(T_DRM_Input_Data data);
-
-/**
- * Get the delivery method of the DRM object.
- *
- * \param session   The handle for this DRM object session.
- *
- * \return
- *      -The delivery method of this DRM object, include: FORWARD_LOCK, COMBINED_DELIVERY, SEPARATE_DELIVERY, SEPARATE_DELIVERY_FL.
- *      -DRM_FAILURE, when some other error occurred.
- */
-int32_t SVC_drm_getDeliveryMethod(int32_t session);
-
-/**
- * Get DRM object media object content type.
- *
- * \param session   The handle for this DRM object session.
- * \param mediaType The buffer to save the media type string, 64 bytes is enough.
- *
- * \return
- *      -DRM_SUCCESS, when get the media object content type successfully.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType);
-
-/**
- * Check whether a specific DRM object has the specific permission rights or not.
- *
- * \param session   The handle for this DRM object session.
- * \param permission    Specify the permission to be checked.
- *
- * \return
- *      -DRM_SUCCESS, when it has the rights for the permission.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_NO_RIGHTS, when it has no rights.
- *      -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending.
- *      -DRM_RIGHTS_EXPIRED, when the rights has expired.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_checkRights(int32_t session, int32_t permission);
-
-/**
- * Consume the rights when try to use the DRM object.
- *
- * \param session   The handle for this DRM object session.
- * \param permission    Specify the permission to be checked.
- *
- * \return
- *      -DRM_SUCCESS, when consume rights successfully.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_NO_RIGHTS, when it has no rights.
- *      -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending.
- *      -DRM_RIGHTS_EXPIRED, when the rights has expired.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_consumeRights(int32_t session, int32_t permission);
-
-/**
- * Get DRM media object content data length.
- *
- * \param session   The handle for this DRM object session.
- *
- * \return
- *      -A positive integer indicate the length of the media object content data.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_NO_RIGHTS, when the rights object is not existed.
- *      -DRM_UNKNOWN_DATA_LEN, when DRM object media data length is unknown in case of DCF has no rights.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_getContentLength(int32_t session);
-
-/**
- * Get DRM media object content data. Support get the data piece by piece if the content is too large.
- *
- * \param session   The handle for this DRM object session.
- * \param offset    The offset to start to get content.
- * \param mediaBuf  The buffer to save media object data.
- * \param mediaBufLen   The length of the buffer.
- *
- * \return
- *      -A positive integer indicate the actually length of the data has been got.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_NO_RIGHTS, when the rights object is not existed.
- *      -DRM_MEDIA_EOF, when reach to the end of the media data.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen);
-
-/**
- * Get the rights issuer address, this interface is specially for Separate Delivery method.
- *
- * \param session   The handle for this DRM object session.
- * \param rightsIssuer  The buffer to save rights issuer, 256 bytes are enough.
- *
- * \return
- *      -DRM_SUCCESS, when get the rights issuer successfully.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_NOT_SD_METHOD, when it is not a Separate Delivery DRM object.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer);
-
-/**
- * Get DRM object constraint informations.
- *
- * \param session   The handle for this DRM object session.
- * \param rights    The structue to save the rights object information.
- *
- * \return
- *      -DRM_SUCCESS, when get the rights information successfully.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_NO_RIGHTS, when this DRM object has not rights.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights);
-
-/**
- * Close the opened session, after closed, the handle become invalid.
- *
- * \param session   The handle for this DRM object session.
- *
- * \return
- *      -DRM_SUCCESS, when close operation success.
- *      -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_closeSession(int32_t session);
-
-/**
- * Check and update the given rights according the given permission.
- *
- * \param contentID The unique id of the rights object.
- * \param permission    The permission to be updated.
- *
- * \return
- *      -DRM_SUCCESS, when update operation success.
- *      -DRM_NO_RIGHTS, when it has no rights.
- *      -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending.
- *      -DRM_RIGHTS_EXPIRED, when the rights has expired.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission);
-
-/**
- * Scan all the rights object in current DRM engine, and get all their information.
- *
- * \param ppRightsInfo  The pointer to the list structure to save rights info.
- *
- * \return
- *      -DRM_SUCCESS, when get information successfully.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo);
-
-/**
- * Free the allocated memory when call "SVC_drm_viewAllRights".
- *
- * \param pRightsHeader The header pointer of the list to be free.
- *
- * \return
- *      -DRM_SUCCESS, when free operation successfully.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader);
-
-/**
- * Delete a specify rights.
- *
- * \param roId      The unique id of the rights.
- *
- * \return
- *      -DRM_SUCCESS, when free operation successfully.
- *      -DRM_NO_RIGHTS, when there is not this rights object.
- *      -DRM_FAILURE, when some other error occured.
- */
-int32_t SVC_drm_deleteRights(uint8_t* roId);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SVC_DRM_NEW_H__ */
diff --git a/media/libdrm/mobile1/include/parser/parser_dcf.h b/media/libdrm/mobile1/include/parser/parser_dcf.h
deleted file mode 100644
index c63a195..0000000
--- a/media/libdrm/mobile1/include/parser/parser_dcf.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PARSER_DCF_H__
-#define __PARSER_DCF_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-#define MAX_ENCRYPTION_METHOD_LEN                            64
-#define MAX_RIGHTS_ISSUER_LEN                                256
-#define MAX_CONTENT_NAME_LEN                                 64
-#define MAX_CONTENT_DESCRIPTION_LEN                          256
-#define MAX_CONTENT_VENDOR_LEN                               256
-#define MAX_ICON_URI_LEN                                     256
-#define MAX_CONTENT_TYPE_LEN                                 64
-#define MAX_CONTENT_URI_LEN                                  256
-
-#define HEADER_ENCRYPTION_METHOD                             "Encryption-Method: "
-#define HEADER_RIGHTS_ISSUER                                 "Rights-Issuer: "
-#define HEADER_CONTENT_NAME                                  "Content-Name: "
-#define HEADER_CONTENT_DESCRIPTION                           "Content-Description: "
-#define HEADER_CONTENT_VENDOR                                "Content-Vendor: "
-#define HEADER_ICON_URI                                      "Icon-Uri: "
-
-#define HEADER_ENCRYPTION_METHOD_LEN                         19
-#define HEADER_RIGHTS_ISSUER_LEN                             15
-#define HEADER_CONTENT_NAME_LEN                              14
-#define HEADER_CONTENT_DESCRIPTION_LEN                       21
-#define HEADER_CONTENT_VENDOR_LEN                            16
-#define HEADER_ICON_URI_LEN                                  10
-
-#define UINT_VAR_FLAG                                        0x80
-#define UINT_VAR_DATA                                        0x7F
-#define MAX_UINT_VAR_BYTE                                    5
-#define DRM_UINT_VAR_ERR                                     -1
-
-typedef struct _T_DRM_DCF_Info {
-    uint8_t Version;
-    uint8_t ContentTypeLen;                                  /**< Length of the ContentType field */
-    uint8_t ContentURILen;                                   /**< Length of the ContentURI field */
-    uint8_t unUsed;
-    uint8_t ContentType[MAX_CONTENT_TYPE_LEN];               /**< The MIME media type of the plaintext data */
-    uint8_t ContentURI[MAX_CONTENT_URI_LEN];                 /**< The unique identifier of this content object */
-    int32_t HeadersLen;                                      /**< Length of the Headers field */
-    int32_t EncryptedDataLen;                                /**< Length of the encrypted data field */
-    int32_t DecryptedDataLen;                                /**< Length of the decrypted data field */
-    uint8_t Encryption_Method[MAX_ENCRYPTION_METHOD_LEN];    /**< Encryption method */
-    uint8_t Rights_Issuer[MAX_RIGHTS_ISSUER_LEN];            /**< Rights issuer */
-    uint8_t Content_Name[MAX_CONTENT_NAME_LEN];              /**< Content name */
-    uint8_t ContentDescription[MAX_CONTENT_DESCRIPTION_LEN]; /**< Content description */
-    uint8_t ContentVendor[MAX_CONTENT_VENDOR_LEN];           /**< Content vendor */
-    uint8_t Icon_URI[MAX_ICON_URI_LEN];                      /**< Icon URI */
-} T_DRM_DCF_Info;
-
-/**
- * Parse the DRM content format data
- *
- * \param buffer            (in)Input the DCF format data
- * \param bufferLen         (in)The input buffer length
- * \param pDcfInfo          (out)A structure pointer which contain information of DCF headers
- * \param ppEncryptedData   (out)The location of encrypted data
- *
- * \return
- *      -TRUE, when success
- *      -FALSE, when failed
- */
-int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo,
-                      uint8_t **ppEncryptedData);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PARSER_DCF_H__ */
diff --git a/media/libdrm/mobile1/include/parser/parser_dm.h b/media/libdrm/mobile1/include/parser/parser_dm.h
deleted file mode 100644
index ec8b6b2..0000000
--- a/media/libdrm/mobile1/include/parser/parser_dm.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PARSER_DM_H__
-#define __PARSER_DM_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-#define MAX_CONTENT_TYPE_LEN                                64
-#define MAX_CONTENT_ID                                      256
-#define MAX_CONTENT_BOUNDARY_LEN                            256
-#define MAX_RIGHTS_ISSUER_LEN                               256
-
-#define DRM_MIME_TYPE_RIGHTS_XML                            "application/vnd.oma.drm.rights+xml"
-#define DRM_MIME_TYPE_CONTENT                               "application/vnd.oma.drm.content"
-
-#define HEADERS_TRANSFER_CODING                             "Content-Transfer-Encoding:"
-#define HEADERS_CONTENT_TYPE                                "Content-Type:"
-#define HEADERS_CONTENT_ID                                  "Content-ID:"
-
-#define TRANSFER_CODING_TYPE_7BIT                           "7bit"
-#define TRANSFER_CODING_TYPE_8BIT                           "8bit"
-#define TRANSFER_CODING_TYPE_BINARY                         "binary"
-#define TRANSFER_CODING_TYPE_BASE64                         "base64"
-
-#define DRM_UID_TYPE_FORWORD_LOCK                           "forwardlock"
-#define DRM_NEW_LINE_CRLF                                   "\r\n"
-
-#define HEADERS_TRANSFER_CODING_LEN                         26
-#define HEADERS_CONTENT_TYPE_LEN                            13
-#define HEADERS_CONTENT_ID_LEN                              11
-
-#define DRM_MESSAGE_CODING_7BIT                             0  /* default */
-#define DRM_MESSAGE_CODING_8BIT                             1
-#define DRM_MESSAGE_CODING_BINARY                           2
-#define DRM_MESSAGE_CODING_BASE64                           3
-
-#define DRM_B64_DEC_BLOCK                                   3
-#define DRM_B64_ENC_BLOCK                                   4
-
-typedef struct _T_DRM_DM_Info {
-    uint8_t contentType[MAX_CONTENT_TYPE_LEN];  /**< Content type */
-    uint8_t contentID[MAX_CONTENT_ID];          /**< Content ID */
-    uint8_t boundary[MAX_CONTENT_BOUNDARY_LEN]; /**< DRM message's boundary */
-    uint8_t deliveryType;                       /**< The Delivery type */
-    uint8_t transferEncoding;                   /**< Transfer encoding type */
-    int32_t contentOffset;                      /**< The offset of the media content from the original DRM data */
-    int32_t contentLen;                         /**< The length of the media content */
-    int32_t rightsOffset;                       /**< The offset of the rights object in case of combined delivery */
-    int32_t rightsLen;                          /**< The length of the rights object in case of combined delivery */
-    uint8_t rightsIssuer[MAX_RIGHTS_ISSUER_LEN];/**< The rights issuer address in case of separate delivery */
-} T_DRM_DM_Info;
-
-/**
- * Search the string in a limited length.
- *
- * \param str           The original string
- * \param strSearch     The sub-string to be searched
- * \param len           The length limited
- *
- * \return
- *      -NULL, when there is not the searched string in length
- *      -The pointer of this sub-string
- */
-const uint8_t* drm_strnstr(const uint8_t* str, const uint8_t* strSearch, int32_t len);
-
-/**
- * Parse the DRM message format data.
- *
- * \param buffer        (in)Input the DRM message format data
- * \param bufferLen     (in)The input buffer length
- * \param pDmInfo       (out)A structure pointer which contain information of DRM message headers
- *
- * \return
- *      -TRUE, when success
- *      -FALSE, when failed
- */
-int32_t drm_parseDM(const uint8_t* buffer, int32_t bufferLen, T_DRM_DM_Info* pDmInfo);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PARSER_DM_H__ */
diff --git a/media/libdrm/mobile1/include/parser/parser_rel.h b/media/libdrm/mobile1/include/parser/parser_rel.h
deleted file mode 100644
index 8def199..0000000
--- a/media/libdrm/mobile1/include/parser/parser_rel.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PARSER_REL_H__
-#define __PARSER_REL_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-#define WRITE_RO_FLAG(whoIsAble, boolValue, Indicator, RIGHTS) do{\
-    whoIsAble = boolValue;\
-    Indicator |= RIGHTS;\
-}while(0)
-
-#define CHECK_VALIDITY(ret) do{\
-    if(ret == NULL){\
-        if(XML_ERROR_NO_SUCH_NODE != xml_errno)\
-            return FALSE;\
-    }\
-    else\
-    {\
-        if(XML_ERROR_OK != xml_errno)\
-            return FALSE;\
-    }\
-}while(0)
-
-#define YMD_HMS_2_INT(year, mon, day, date, hour, min, sec, time) do{\
-    date = year * 10000 + mon * 100 + day;\
-    time = hour * 10000 + min * 100 + sec;\
-}while(0)
-
-#define DRM_UID_LEN         256
-#define DRM_KEY_LEN         16
-
-#define XML_DOM_PARSER
-
-typedef struct _T_DRM_DATETIME {
-    int32_t date; /**< year * 10000 + mon *100 + day */
-    int32_t time; /**< hour * 10000 + min *100 + sec */
-} T_DRM_DATETIME;
-
-typedef struct _T_DRM_Rights_Constraint {
-    uint8_t Indicator;          /**< Indicate which is constrainted, the first one indicate 0001, second one indicate 0010 */
-    uint8_t unUsed[3];
-    int32_t Count;              /**< The times that can be used */
-    T_DRM_DATETIME StartTime;   /**< The starting time */
-    T_DRM_DATETIME EndTime;     /**< The ending time */
-    T_DRM_DATETIME Interval;    /**< The interval time */
-} T_DRM_Rights_Constraint;
-
-typedef struct _T_DRM_Rights {
-    uint8_t Version[8];                         /**< Version number */
-    uint8_t uid[256];                           /**< record the rights object name */
-    uint8_t KeyValue[16];                       /**< Decode base64 */
-    int32_t bIsPlayable;                        /**< Is playable */
-    int32_t bIsDisplayable;                     /**< Is displayable */
-    int32_t bIsExecuteable;                     /**< Is executeable */
-    int32_t bIsPrintable;                       /**< Is printable */
-    T_DRM_Rights_Constraint PlayConstraint;     /**< Play constraint */
-    T_DRM_Rights_Constraint DisplayConstraint;  /**< Display constraint */
-    T_DRM_Rights_Constraint ExecuteConstraint;  /**< Execute constraint */
-    T_DRM_Rights_Constraint PrintConstraint;    /**< Print constraint */
-} T_DRM_Rights;
-
-/**
- * Input year and month, return how many days that month have
- * \param year          (in)Input the year
- * \param month         (in)Input the month
- * \return
- *      -A positive integer, which is how many days that month have
- *      -When wrong input, return -1
- */
-int32_t drm_monthDays(int32_t year, int32_t month);
-
-/**
- * Check whether the date and time is valid.
- * \param year          year of the date
- * \param month         month of the date
- * \param day           day of the date
- * \param hour          hour of the time
- * \param min           minute of the time
- * \param sec           second of the time
- * \return
- *      -when it is a valid time, return 0
- *      -when it is a invalid time, return -1
- */
-int32_t drm_checkDate(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec);
-
-/**
- * Parse the rights object include xml format and wbxml format data
- *
- * \param buffer        (in)Input the DRM rights object data
- * \param bufferLen     (in)The buffer length
- * \param format        (in)Which format, xml or wbxml
- * \param pRights       (out)A structure pointer which save the rights information
- *
- * \return
- *      -TRUE, when success
- *      -FALSE, when failed
- */
-int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PARSER_REL_H__ */
diff --git a/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h b/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h
deleted file mode 100644
index 1c40467..0000000
--- a/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __WBXML_TINYPARSER_H__
-#define __WBXML_TINYPARSER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-#define REL_TAG_RIGHTS                                       0x05
-#define REL_TAG_CONTEXT                                      0x06
-#define REL_TAG_VERSION                                      0x07
-#define REL_TAG_UID                                          0x08
-#define REL_TAG_AGREEMENT                                    0x09
-#define REL_TAG_ASSET                                        0x0A
-#define REL_TAG_KEYINFO                                      0x0B
-#define REL_TAG_KEYVALUE                                     0x0C
-#define REL_TAG_PERMISSION                                   0x0D
-#define REL_TAG_PLAY                                         0x0E
-#define REL_TAG_DISPLAY                                      0x0F
-#define REL_TAG_EXECUTE                                      0x10
-#define REL_TAG_PRINT                                        0x11
-#define REL_TAG_CONSTRAINT                                   0x12
-#define REL_TAG_COUNT                                        0x13
-#define REL_TAG_DATETIME                                     0x14
-#define REL_TAG_START                                        0x15
-#define REL_TAG_END                                          0x16
-#define REL_TAG_INTERVAL                                     0x17
-
-#define REL_CHECK_WBXML_HEADER(x) ((x != NULL) && (x[0] == 0x03) && (x[1] == 0x0E) && (x[2] == 0x6A))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WBXML_TINYPARSER_H__ */
diff --git a/media/libdrm/mobile1/include/xml/xml_tinyParser.h b/media/libdrm/mobile1/include/xml/xml_tinyParser.h
deleted file mode 100644
index 4ad65b8..0000000
--- a/media/libdrm/mobile1/include/xml/xml_tinyParser.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __XML_TINYPARSER_H__
-#define __XML_TINYPARSER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <drm_common_types.h>
-
-#define XML_DOM_PARSER
-#define WBXML_DOM_PARSER
-#define XML_DOM_CHECK_ENDTAG
-#define XML_ENABLE_ERRNO
-#define WBXML_OLD_VERSION /* for drm only */
-
-#ifdef DEBUG_MODE
-void XML_PrintMallocInfo();
-#endif /* DEBUG_MODE */
-
-#define XML_TRUE                                             1
-#define XML_FALSE                                            0
-#define XML_EOF                                              0
-#define XML_TAG_START                                        0
-#define XML_TAG_END                                          1
-#define XML_TAG_SELF                                         2
-
-#define XML_MAX_PROPERTY_LEN                                 256
-#define XML_MAX_ATTR_NAME_LEN                                256
-#define XML_MAX_ATTR_VALUE_LEN                               256
-#define XML_MAX_VALUE_LEN                                    256
-
-#define XML_ERROR_OK                                         0
-#define XML_ERROR_BUFFER_NULL                                -1
-#define XML_ERROR_ATTR_NAME                                  -2
-#define XML_ERROR_ATTR_MISSED_EQUAL                          -3
-#define XML_ERROR_PROPERTY_NAME                              -4
-#define XML_ERROR_ATTR_VALUE                                 -5
-#define XML_ERROR_ENDTAG                                     -6
-#define XML_ERROR_NO_SUCH_NODE                               -7
-#define XML_ERROR_PROPERTY_END                               -8
-#define XML_ERROR_VALUE                                      -9
-#define XML_ERROR_NO_START_TAG                               -14
-#define XML_ERROR_NOVALUE                                    -15
-
-#define WBXML_ERROR_MISSED_CONTENT                           -10
-#define WBXML_ERROR_MBUINT32                                 -11
-#define WBXML_ERROR_MISSED_STARTTAG                          -12
-#define WBXML_ERROR_MISSED_ENDTAG                            -13
-
-#ifdef XML_ENABLE_ERRNO
-extern int32_t xml_errno;
-#define XML_ERROR(x) do { xml_errno = x; } while (0)
-#else  /* XML_ENABLE_ERRNO */
-#define XML_ERROR
-#endif /* XML_ENABLE_ERRNO */
-
-#ifdef XML_DOM_PARSER
-uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node);
-uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node,
-                           uint8_t **value, int32_t *valueLen);
-
-uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen);
-uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen,
-                      uint8_t **pValue, int32_t *valueLen);
-
-uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName,
-                          int32_t *nodenameLen);
-
-uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType);
-#endif /* XML_DOM_PARSER */
-
-#ifdef WBXML_DOM_PARSER
-
-#define WBXML_WITH_ATTR                                      0x80
-#define WBXML_WITH_CONTENT                                   0x40
-#define WBXML_ATTR_END                                       0x01
-#define WBXML_CONTENT_END                                    0x01
-
-#define WBXML_SWITCH_PAGE                                    0x00
-#define WBXML_STR_I                                          0x03
-#define WBXML_END                                            0x00
-#define WBXML_OPAUE                                          0xC3
-#define WBXML_STR_T                                          0x83
-#define WBXML_OPAQUE                                         0xC3
-
-#define WBXML_GET_TAG(x) ((x) & 0x3F) /* get 6-digits */
-#define WBXML_HAS_ATTR(x) ((x) & WBXML_WITH_ATTR)
-#define WBXML_HAS_CONTENT(x) ((x) & WBXML_WITH_CONTENT)
-
-typedef struct _WBXML {
-    uint8_t version;
-    uint8_t unUsed[3];
-    uint32_t publicid;
-    uint32_t charset;
-    int32_t strTableLen;
-    uint8_t *strTable;
-    uint8_t *Content;
-    uint8_t *End;
-    uint8_t *curPtr;
-    int32_t depth;
-} WBXML;
-
-typedef int32_t XML_BOOL;
-
-#ifdef WBXML_OLD_VERSION
-uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen,
-                                 uint8_t *node);
-uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen,
-                                      uint8_t *node,
-                                      uint8_t **value,
-                                      int32_t *valueLen);
-#endif /* WBXML_OLD_VERSION */
-
-XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer,
-                        int32_t bufferLen);
-XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml);
-uint8_t WBXML_DOM_GetTag(WBXML * pWbxml);
-uint8_t WBXML_DOM_GetChar(WBXML * pWbxml);
-uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml);
-void WBXML_DOM_Rewind(WBXML * pWbxml);
-void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset);
-int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len);
-
-#endif /* WBXML_DOM_PARSER */
-
-#ifdef XML_TREE_STRUCTURE
-
-typedef struct _XML_TREE_ATTR XML_TREE_ATTR;
-struct _XML_TREE_ATTR {
-    uint8_t name[XML_MAX_ATTR_VALUE_LEN];
-    uint8_t value[XML_MAX_ATTR_VALUE_LEN];
-    XML_TREE_ATTR *next;
-};
-
-typedef struct _XML_TREE XML_TREE;
-struct _XML_TREE {
-    uint8_t tag[XML_MAX_PROPERTY_LEN];
-    uint8_t value[XML_MAX_VALUE_LEN];
-    XML_TREE_ATTR *attr;
-    XML_TREE_ATTR *last_attr;
-    XML_TREE *brother;
-    XML_TREE *last_brother;
-    XML_TREE *child;
-};
-
-XML_TREE *XML_makeTree(uint8_t **buf);
-void XML_freeTree(XML_TREE * pTree);
-
-#endif /* XML_TREE_STRUCTURE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XML_TINYPARSER_H__ */
diff --git a/media/libdrm/mobile1/src/jni/drm1_jni.c b/media/libdrm/mobile1/src/jni/drm1_jni.c
deleted file mode 100644
index 11353a7..0000000
--- a/media/libdrm/mobile1/src/jni/drm1_jni.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file drm1_jni.c
- *
- * This file implement the Java Native Interface
- * for supporting OMA DRM 1.0
- */
-
-#include <jni/drm1_jni.h>
-#include <objmng/svc_drm.h>
-#include "log.h"
-#include "JNIHelp.h"
-
-
-#define MS_PER_SECOND 1000                  /* Milliseconds per second */
-#define MS_PER_MINUTE 60 * MS_PER_SECOND    /* Milliseconds per minute */
-#define MS_PER_HOUR   60 * MS_PER_MINUTE    /* Milliseconds per hour */
-#define MS_PER_DAY    24 * MS_PER_HOUR      /* Milliseconds per day */
-
-#define SECONDS_PER_MINUTE 60                       /* Seconds per minute*/
-#define SECONDS_PER_HOUR   60 * SECONDS_PER_MINUTE  /* Seconds per hour */
-#define SECONDS_PER_DAY    24 * SECONDS_PER_HOUR    /* Seconds per day */
-
-#define DAY_PER_MONTH 30                    /* Days per month */
-#define DAY_PER_YEAR  365                   /* Days per year */
-
-/** Nonzero if 'y' is a leap year, else zero. */
-#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
-
-/** Number of leap years from 1970 to 'y' (not including 'y' itself). */
-#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
-
-/** Accumulated number of days from 01-Jan up to start of current month. */
-static const int32_t ydays[] = {
-    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
-};
-
-#define int64_const(s)          (s)
-#define int64_add(dst, s1, s2)  ((void)((dst) = (s1) + (s2)))
-#define int64_mul(dst, s1, s2)  ((void)((dst) = (int64_t)(s1) * (int64_t)(s2)))
-
-/**
- * DRM data structure
- */
-typedef struct _DrmData {
-    /**
-     * The id of the DRM content.
-     */
-    int32_t id;
-
-    /**
-     * The pointer of JNI interface.
-     */
-    JNIEnv* env;
-
-    /**
-     * The pointer of DRM raw content InputStream object.
-     */
-    jobject* pInData;
-
-    /**
-     * The len of the InputStream object.
-     */
-    int32_t len;
-
-    /**
-     * The next DRM data.
-     */
-    struct _DrmData *next;
-} DrmData;
-
-/** The table to hold all the DRM data. */
-static DrmData *drmTable = NULL;
-
-/**
- * Allocate a new item of DrmData.
- *
- * \return a pointer to a DrmData item if allocate successfully,
- *         otherwise return NULL
- */
-static DrmData * newItem(void)
-{
-    DrmData *d = (DrmData *)malloc(sizeof(DrmData));
-
-    if (d != NULL) {
-        d->id = -1;
-        d->next = NULL;
-    }
-
-    return d;
-}
-
-/**
- * Free the memory of the specified DrmData item <code>d</code>.
- *
- * \param d - a pointer to DrmData
- */
-static void freeItem(DrmData *d)
-{
-    assert(d != NULL);
-
-    free(d);
-}
-
-/**
- * Insert a DrmData item with given <code>name</code> into the head of
- * the DrmData list.
- *
- * @param d - the pointer of the JNI interface
- * @param pInData - the pointer of the DRM content InputStream object.
- *
- * @return <code>JNI_DRM_SUCCESS</code> if insert successfully, otherwise
- *         return <code>JNI_DRM_FAILURE</code>
- */
-static int32_t addItem(DrmData* d)
-{
-    if (NULL == d)
-        return JNI_DRM_FAILURE;
-
-    if (NULL == drmTable) {
-        drmTable = d;
-        return JNI_DRM_SUCCESS;
-    }
-
-    d->next = drmTable;
-    drmTable = d;
-
-    return JNI_DRM_SUCCESS;
-}
-
-/**
- * Get the item from the DrmData list by the specified <code>
- * id</code>.
- *
- * @param p - the pointer of the DRM content InputStream object.
- *
- * @return a pointer to the DrmData item if find it successfuly,
- *         otherwise return NULL
- */
-static DrmData * getItem(int32_t id)
-{
-    DrmData *d;
-
-    if (NULL == drmTable)
-        return NULL;
-
-    for (d = drmTable; d != NULL; d = d->next) {
-        if (id == d->id)
-            return d;
-    }
-
-    return NULL;
-}
-
-/**
- * Remove the specified DrmData item <code>d</code>.
- *
- * @param p - the pointer of the DRM content InputStream object.
- *
- * @return <code>JNI_DRM_SUCCESS</code> if remove successfuly,
- *         otherwise return <code>JNI_DRM_FAILURE</code>
- */
-static int32_t removeItem(int32_t id)
-{
-    DrmData *curItem, *preItem, *dstItem;
-
-    if (NULL == drmTable)
-        return JNI_DRM_FAILURE;
-
-    preItem = NULL;
-    for (curItem = drmTable; curItem != NULL; curItem = curItem->next) {
-        if (id == curItem->id) {
-            if (curItem == drmTable)
-                drmTable = curItem->next;
-            else
-                preItem->next = curItem->next;
-
-            freeItem(curItem);
-
-            return JNI_DRM_SUCCESS;
-        }
-
-        preItem = curItem;
-    }
-
-    return JNI_DRM_FAILURE;
-}
-
-
-static int32_t getInputStreamDataLength(int32_t handle)
-{
-    JNIEnv* env;
-    jobject* pInputStream;
-    int32_t len;
-    DrmData* p;
-    jclass cls;
-    jmethodID mid;
-
-    p = (DrmData *)handle;
-
-    if (NULL == p)
-        return 0;
-
-    env = p->env;
-    pInputStream = p->pInData;
-    len = p->len;
-
-    if (NULL == env || p->len <= 0 || NULL == pInputStream)
-        return 0;
-
-    /* check the original InputStream is available or not */
-    cls = (*env)->GetObjectClass(env, *pInputStream);
-    mid = (*env)->GetMethodID(env, cls, "available", "()I");
-    (*env)->DeleteLocalRef(env, cls);
-
-    if (NULL == mid)
-        return 0;
-
-    if (0 > (*env)->CallIntMethod(env, *pInputStream, mid))
-        return 0;
-
-    return len;
-}
-
-static int32_t readInputStreamData(int32_t handle, uint8_t* buf, int32_t bufLen)
-{
-    JNIEnv* env;
-    jobject* pInputStream;
-    int32_t len;
-    DrmData* p;
-    jclass cls;
-    jmethodID mid;
-    jbyteArray tmp;
-    int tmpLen;
-    jbyte* pNativeBuf;
-
-    p = (DrmData *)handle;
-
-    if (NULL == p || NULL == buf || bufLen <- 0)
-        return 0;
-
-    env = p->env;
-    pInputStream = p->pInData;
-    len = p->len;
-
-    if (NULL == env || p->len <= 0 || NULL == pInputStream)
-        return 0;
-
-    cls = (*env)->GetObjectClass(env, *pInputStream);
-    mid = (*env)->GetMethodID(env, cls, "read", "([BII)I");
-    tmp = (*env)->NewByteArray(env, bufLen);
-    bufLen = (*env)->CallIntMethod(env, *pInputStream, mid, tmp, 0, bufLen);
-
-    (*env)->DeleteLocalRef(env, cls);
-
-    if (-1 == bufLen)
-        return -1;
-
-    pNativeBuf = (*env)->GetByteArrayElements(env, tmp, NULL);
-    memcpy(buf, pNativeBuf, bufLen);
-    (*env)->ReleaseByteArrayElements(env, tmp, pNativeBuf, 0);
-    (*env)->DeleteLocalRef(env, tmp);
-
-    return bufLen;
-}
-
-static const T_DRM_Rights_Info_Node *searchRightsObject(const jbyte* roId, const T_DRM_Rights_Info_Node* pRightsList)
-{
-    const T_DRM_Rights_Info_Node *pTmp;
-
-    if (NULL == roId || NULL == pRightsList)
-        return NULL;
-
-    pTmp = pRightsList;
-
-    while (NULL != pTmp) {
-        if(0 == strcmp((char *)roId, (char *)pTmp->roInfo.roId))
-            break;
-        pTmp = pTmp->next;
-    }
-
-    return pTmp;
-}
-
-/**
- * Returns the difference in seconds between the given GMT time
- * and 1970-01-01 00:00:00 GMT.
- *
- * \param year the year (since 1970)
- * \param month the month (1 - 12)
- * \param day the day (1 - 31)
- * \param hour the hour (0 - 23)
- * \param minute the minute (0 - 59)
- * \param second the second (0 - 59)
- *
- * \return the difference in seconds between the given GMT time
- *         and 1970-01-01 00:00:00 GMT.
- */
-static int64_t mkgmtime(
-        uint32_t year, uint32_t month, uint32_t day,
-        uint32_t hour, uint32_t minute, uint32_t second)
-{
-    int64_t result;
-
-    /*
-     * FIXME: It does not check whether the specified days
-     *        is valid based on the specified months.
-     */
-    assert(year >= 1970
-            && month > 0 && month <= 12
-            && day > 0 && day <= 31
-            && hour < 24 && minute < 60
-            && second < 60);
-
-    /* Set 'day' to the number of days into the year. */
-    day += ydays[month - 1] + (month > 2 && leap (year)) - 1;
-
-    /* Now calculate 'day' to the number of days since Jan 1, 1970. */
-    day = day + 365 * (year - 1970) + nleap(year);
-
-    int64_mul(result, int64_const(day), int64_const(SECONDS_PER_DAY));
-    int64_add(result, result, int64_const(
-        SECONDS_PER_HOUR * hour + SECONDS_PER_MINUTE * minute + second));
-
-    return result;
-}
-
-/**
- * Compute the milliseconds by the specified <code>date</code>
- * and <code>time</code>.
- *
- * @param date - the specified date,
- *               <code>date = year * 10000 + month * 100 + day</code>
- * @param time - the specified time,
- *               <code>time = hour * 10000 + minute * 100 + second</code>
- *
- * @return the related milliseconds
- */
-static int64_t computeTime(int32_t date, int32_t time)
-{
-    int32_t year, month, day, hour, minute, second;
-
-    year = date / 10000;
-    month = (date / 100) % 100;
-    day = date % 100;
-    hour = time / 10000;
-    minute = (time / 100) % 100;
-    second = time % 100;
-
-    /* Adjust the invalid parameters. */
-    if (year < 1970) year = 1970;
-    if (month < 1) month = 1;
-    if (month > 12) month = 12;
-    if (day < 1) day = 1;
-    if (day > 31) day = 31;
-    if (hour < 0) hour = 0;
-    if (hour > 23) hour = 23;
-    if (minute < 0) minute = 0;
-    if (minute > 59) minute = 59;
-    if (second < 0) second = 0;
-    if (second > 59) second = 59;
-
-    return mkgmtime(year, month, day, hour, minute, second) * 1000;
-}
-
-/**
- * Compute the milliseconds by the specified <code>date</code>
- * and <code>time</code>.
- * Note that here we always treat 1 year as 365 days and 1 month as 30 days
- * that is not precise. But it should not be a problem since OMA DRM 2.0
- * already restricts the interval representation to be day-based,
- * i.e. there will not be an interval with year or month any more in the
- * future.
- *
- * @param date - the specified date,
- *               <code>date = year * 10000 + month * 100 + day</code>
- * @param time - the specified time,
- *               <code>time = hour * 10000 + minute * 100 + second</code>
- *
- * @return the related milliseconds
- */
-static int64_t computeInterval(int32_t date, int32_t time)
-{
-    int32_t year, month, day, hour, minute, second;
-    int64_t milliseconds;
-
-    year = date / 10000;
-    month = (date / 100) % 100;
-    day = date % 100;
-    hour = time / 10000;
-    minute = (time / 100) % 100;
-    second = time % 100;
-
-    /* milliseconds = ((((year * 365 + month * 30 + day) * 24
-     *                + hour) * 60 + minute) * 60 + second) * 1000;
-     */
-    int64_mul(milliseconds,
-        int64_const(year * DAY_PER_YEAR + month * DAY_PER_MONTH + day),
-        int64_const(MS_PER_DAY));
-    int64_add(milliseconds, milliseconds,
-        int64_const(hour * MS_PER_HOUR + minute * MS_PER_MINUTE +
-            second * MS_PER_SECOND));
-
-    return milliseconds;
-}
-
-static jint getObjectIntField(JNIEnv * env, jobject obj, const char *name, jint * value)
-{
-    jclass clazz;
-    jfieldID field;
-
-    clazz = (*env)->GetObjectClass(env, obj);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, clazz, name, "I");
-    (*env)->DeleteLocalRef(env, clazz);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    *value = (*env)->GetIntField(env, obj, field);
-
-    return JNI_DRM_SUCCESS;
-}
-
-static jint setObjectIntField(JNIEnv * env, jobject obj, const char *name, jint value)
-{
-    jclass clazz;
-    jfieldID field;
-
-    clazz = (*env)->GetObjectClass(env, obj);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, clazz, name, "I");
-    (*env)->DeleteLocalRef(env, clazz);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    (*env)->SetIntField(env, obj, field, value);
-
-    return JNI_DRM_SUCCESS;
-}
-
-static jint setObjectLongField(JNIEnv * env, jobject obj, const char *name, jlong value)
-{
-    jclass clazz;
-    jfieldID field;
-
-    clazz = (*env)->GetObjectClass(env, obj);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, clazz, name, "J");
-    (*env)->DeleteLocalRef(env, clazz);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    (*env)->SetLongField(env, obj, field, value);
-
-    return JNI_DRM_SUCCESS;
-}
-
-static jint setConstraintFields(JNIEnv * env, jobject constraint, T_DRM_Constraint_Info * pConstraint)
-{
-    /* if no this permission */
-    if (pConstraint->indicator == (uint8_t)DRM_NO_RIGHTS) {
-        if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", 0))
-            return JNI_DRM_FAILURE;
-
-        return JNI_DRM_SUCCESS;
-    }
-
-    /* set count field */
-    if (pConstraint->indicator & DRM_COUNT_CONSTRAINT) {
-        if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", pConstraint->count))
-            return JNI_DRM_FAILURE;
-    }
-
-    /* set start time field */
-    if (pConstraint->indicator & DRM_START_TIME_CONSTRAINT) {
-        int64_t startTime;
-
-        startTime = computeTime(pConstraint->startDate, pConstraint->startTime);
-
-        if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "startDate", startTime))
-            return JNI_DRM_FAILURE;
-    }
-
-    /* set end time field */
-    if (pConstraint->indicator & DRM_END_TIME_CONSTRAINT) {
-        int64_t endTime;
-
-        endTime = computeTime(pConstraint->endDate, pConstraint->endTime);
-
-        if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "endDate", endTime))
-            return JNI_DRM_FAILURE;
-    }
-
-    /* set interval field */
-    if (pConstraint->indicator & DRM_INTERVAL_CONSTRAINT) {
-        int64_t interval;
-
-        interval = computeInterval(pConstraint->intervalDate, pConstraint->intervalTime);
-
-        if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "interval", interval))
-            return JNI_DRM_FAILURE;
-    }
-
-    return JNI_DRM_SUCCESS;
-}
-
-static jint setRightsFields(JNIEnv * env, jobject rights, T_DRM_Rights_Info* pRoInfo)
-{
-    jclass clazz;
-    jfieldID field;
-    jstring str;
-    jint index;
-
-    clazz = (*env)->GetObjectClass(env, rights);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    /* set roId field */
-    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
-    (*env)->DeleteLocalRef(env, clazz);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    str = (*env)->NewStringUTF(env, (char *)pRoInfo->roId);
-    if (NULL == str)
-        return JNI_DRM_FAILURE;
-
-    (*env)->SetObjectField(env, rights, field, str);
-    (*env)->DeleteLocalRef(env, str);
-
-    return JNI_DRM_SUCCESS;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent
-  (JNIEnv * env, jobject rawContent, jobject data, jint len, jint mimeType)
-{
-    int32_t id;
-    T_DRM_Input_Data inData;
-    DrmData* drmInData;
-
-    switch (mimeType) {
-    case JNI_DRM_MIMETYPE_MESSAGE:
-        mimeType = TYPE_DRM_MESSAGE;
-        break;
-    case JNI_DRM_MIMETYPE_CONTENT:
-        mimeType = TYPE_DRM_CONTENT;
-        break;
-    default:
-        return JNI_DRM_FAILURE;
-    }
-
-    drmInData = newItem();
-    if (NULL == drmInData)
-        return JNI_DRM_FAILURE;
-
-    drmInData->env = env;
-    drmInData->pInData = &data;
-    drmInData->len = len;
-
-    if (JNI_DRM_FAILURE == addItem(drmInData))
-        return JNI_DRM_FAILURE;
-
-    inData.inputHandle = (int32_t)drmInData;
-    inData.mimeType = mimeType;
-    inData.getInputDataLength = getInputStreamDataLength;
-    inData.readInputData = readInputStreamData;
-
-    id = SVC_drm_openSession(inData);
-    if (id < 0)
-        return JNI_DRM_FAILURE;
-
-    drmInData->id = id;
-
-    return id;
-}
-
-/* native interface */
-JNIEXPORT jstring JNICALL
-Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress
-  (JNIEnv * env, jobject rawContent)
-{
-    jint id;
-    uint8_t rightsIssuer[256] = {0};
-    jstring str = NULL;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return NULL;
-
-    if (DRM_SUCCESS == SVC_drm_getRightsIssuer(id, rightsIssuer))
-        str = (*env)->NewStringUTF(env, (char *)rightsIssuer);
-
-    return str;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod
-  (JNIEnv * env, jobject rawContent)
-{
-    jint id;
-    int32_t res;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return JNI_DRM_FAILURE;
-
-    res = SVC_drm_getDeliveryMethod(id);
-
-    switch (res) {
-    case FORWARD_LOCK:
-        return JNI_DRM_FORWARD_LOCK;
-    case COMBINED_DELIVERY:
-        return JNI_DRM_COMBINED_DELIVERY;
-    case SEPARATE_DELIVERY:
-        return JNI_DRM_SEPARATE_DELIVERY;
-    case SEPARATE_DELIVERY_FL:
-        return JNI_DRM_SEPARATE_DELIVERY_DM;
-    default:
-        return JNI_DRM_FAILURE;
-    }
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRawContent_nativeReadContent
-  (JNIEnv * env, jobject rawContent, jbyteArray buf, jint bufOff, jint len, jint mediaOff)
-{
-    jint id;
-    jbyte *nativeBuf;
-    jclass cls;
-    jmethodID mid;
-    DrmData* p;
-    jobject inputStream;
-    jfieldID field;
-
-    if (NULL == buf) {
-        jniThrowNullPointerException(env, "b == null");
-        return JNI_DRM_FAILURE;
-    }
-
-    if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) {
-        jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
-        return JNI_DRM_FAILURE;
-    }
-
-    if (mediaOff < 0 || len == 0)
-        return JNI_DRM_FAILURE;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return JNI_DRM_FAILURE;
-
-    p = getItem(id);
-    if (NULL == p)
-        return JNI_DRM_FAILURE;
-
-    cls = (*env)->GetObjectClass(env, rawContent);
-    if (NULL == cls)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, cls, "inData", "Ljava/io/BufferedInputStream;");
-    (*env)->DeleteLocalRef(env, cls);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    inputStream = (*env)->GetObjectField(env, rawContent, field);
-
-    p->env = env;
-    p->pInData = &inputStream;
-
-    nativeBuf = (*env)->GetByteArrayElements(env, buf, NULL);
-
-    len = SVC_drm_getContent(id, mediaOff, (uint8_t *)nativeBuf + bufOff, len);
-
-    (*env)->ReleaseByteArrayElements(env, buf, nativeBuf, 0);
-
-    if (DRM_MEDIA_EOF == len)
-        return JNI_DRM_EOF;
-    if (len <= 0)
-        return JNI_DRM_FAILURE;
-
-    return len;
-}
-
-/* native interface */
-JNIEXPORT jstring JNICALL
-Java_android_drm_mobile1_DrmRawContent_nativeGetContentType
-  (JNIEnv * env, jobject rawContent)
-{
-    jint id;
-    uint8_t contentType[64] = {0};
-    jstring str = NULL;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return NULL;
-
-    if (DRM_SUCCESS == SVC_drm_getContentType(id, contentType))
-        str = (*env)->NewStringUTF(env, (char *)contentType);
-
-    return str;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength
-  (JNIEnv * env, jobject rawContent)
-{
-    jint id;
-    int32_t len;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return JNI_DRM_FAILURE;
-
-    len = SVC_drm_getContentLength(id);
-
-    if (DRM_UNKNOWN_DATA_LEN == len)
-        return JNI_DRM_UNKNOWN_DATA_LEN;
-
-    if (0 > len)
-        return JNI_DRM_FAILURE;
-
-    return len;
-}
-
-/* native interface */
-JNIEXPORT void JNICALL
-Java_android_drm_mobile1_DrmRawContent_finalize
-  (JNIEnv * env, jobject rawContent)
-{
-    jint id;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return;
-
-    removeItem(id);
-
-    SVC_drm_closeSession(id);
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo
-  (JNIEnv * env, jobject rights, jint permission, jobject constraint)
-{
-    jclass clazz;
-    jfieldID field;
-    jstring str;
-    uint8_t *nativeStr;
-    T_DRM_Rights_Info_Node *pRightsList;
-    T_DRM_Rights_Info_Node *pCurNode;
-    T_DRM_Constraint_Info *pConstraint;
-
-    clazz = (*env)->GetObjectClass(env, rights);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
-    (*env)->DeleteLocalRef(env, clazz);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    str = (*env)->GetObjectField(env, rights, field);
-
-    nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL);
-    if (NULL == nativeStr)
-        return JNI_DRM_FAILURE;
-
-    /* this means forward-lock rights */
-    if (0 == strcmp((char *)nativeStr, "ForwardLock")) {
-        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-        return JNI_DRM_SUCCESS;
-    }
-
-    if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) {
-        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-        return JNI_DRM_FAILURE;
-    }
-
-    pCurNode = searchRightsObject((jbyte *)nativeStr, pRightsList);
-    if (NULL == pCurNode) {
-        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-        SVC_drm_freeRightsInfoList(pRightsList);
-        return JNI_DRM_FAILURE;
-    }
-    (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-
-    switch (permission) {
-    case JNI_DRM_PERMISSION_PLAY:
-        pConstraint = &(pCurNode->roInfo.playRights);
-        break;
-    case JNI_DRM_PERMISSION_DISPLAY:
-        pConstraint = &(pCurNode->roInfo.displayRights);
-        break;
-    case JNI_DRM_PERMISSION_EXECUTE:
-        pConstraint = &(pCurNode->roInfo.executeRights);
-        break;
-    case JNI_DRM_PERMISSION_PRINT:
-        pConstraint = &(pCurNode->roInfo.printRights);
-        break;
-    default:
-        SVC_drm_freeRightsInfoList(pRightsList);
-        return JNI_DRM_FAILURE;
-    }
-
-    /* set constraint field */
-    if (JNI_DRM_FAILURE == setConstraintFields(env, constraint, pConstraint)) {
-        SVC_drm_freeRightsInfoList(pRightsList);
-        return JNI_DRM_FAILURE;
-    }
-
-    SVC_drm_freeRightsInfoList(pRightsList);
-
-    return JNI_DRM_SUCCESS;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRights_nativeConsumeRights
-  (JNIEnv * env, jobject rights, jint permission)
-{
-    jclass clazz;
-    jfieldID field;
-    jstring str;
-    uint8_t *nativeStr;
-    int32_t id;
-
-    switch (permission) {
-    case JNI_DRM_PERMISSION_PLAY:
-        permission = DRM_PERMISSION_PLAY;
-        break;
-    case JNI_DRM_PERMISSION_DISPLAY:
-        permission = DRM_PERMISSION_DISPLAY;
-        break;
-    case JNI_DRM_PERMISSION_EXECUTE:
-        permission = DRM_PERMISSION_EXECUTE;
-        break;
-    case JNI_DRM_PERMISSION_PRINT:
-        permission = DRM_PERMISSION_PRINT;
-        break;
-    default:
-        return JNI_DRM_FAILURE;
-    }
-
-    clazz = (*env)->GetObjectClass(env, rights);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
-    (*env)->DeleteLocalRef(env, clazz);
-
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    str = (*env)->GetObjectField(env, rights, field);
-
-    nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL);
-    if (NULL == nativeStr)
-        return JNI_DRM_FAILURE;
-
-    if (0 == strcmp("ForwardLock", (char *)nativeStr)) {
-        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-        return JNI_DRM_SUCCESS;
-    }
-
-    if (DRM_SUCCESS != SVC_drm_updateRights(nativeStr, permission)) {
-        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-        return JNI_DRM_FAILURE;
-    }
-
-    (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-
-    return JNI_DRM_SUCCESS;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights
-  (JNIEnv * env, jobject rightsManager, jobject data, jint len, jint mimeType, jobject rights)
-{
-    int32_t id;
-    T_DRM_Input_Data inData;
-    DrmData* drmInData;
-    jclass cls;
-    jmethodID mid;
-    T_DRM_Rights_Info rightsInfo;
-
-    switch (mimeType) {
-    case JNI_DRM_MIMETYPE_RIGHTS_XML:
-        mimeType = TYPE_DRM_RIGHTS_XML;
-        break;
-    case JNI_DRM_MIMETYPE_RIGHTS_WBXML:
-        mimeType = TYPE_DRM_RIGHTS_WBXML;
-        break;
-    case JNI_DRM_MIMETYPE_MESSAGE:
-        mimeType = TYPE_DRM_MESSAGE;
-        break;
-    default:
-        return JNI_DRM_FAILURE;
-    }
-
-    drmInData = newItem();
-    if (NULL == drmInData)
-        return JNI_DRM_FAILURE;
-
-    drmInData->env = env;
-    drmInData->pInData = &data;
-    drmInData->len = len;
-
-    inData.inputHandle = (int32_t)drmInData;
-    inData.mimeType = mimeType;
-    inData.getInputDataLength = getInputStreamDataLength;
-    inData.readInputData = readInputStreamData;
-
-    memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info));
-    if (DRM_FAILURE == SVC_drm_installRights(inData, &rightsInfo))
-        return JNI_DRM_FAILURE;
-
-    freeItem(drmInData);
-
-    return setRightsFields(env, rights, &rightsInfo);
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights
-  (JNIEnv * env, jobject rightsManager, jobject rawContent, jobject rights)
-{
-    jint id;
-    T_DRM_Rights_Info rightsInfo;
-
-    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
-        return JNI_DRM_FAILURE;
-
-    memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info));
-    if (DRM_SUCCESS != SVC_drm_getRightsInfo(id, &rightsInfo))
-        return JNI_DRM_FAILURE;
-
-    return setRightsFields(env, rights, &rightsInfo);
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights
-  (JNIEnv * env, jobject rightsManager)
-{
-    T_DRM_Rights_Info_Node *pRightsList;
-    T_DRM_Rights_Info_Node *pCurNode;
-    int32_t num = 0;
-
-    if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList))
-        return JNI_DRM_FAILURE;
-
-    pCurNode = pRightsList;
-    while (pCurNode != NULL) {
-        num++;
-        pCurNode = pCurNode->next;
-    }
-
-    SVC_drm_freeRightsInfoList(pRightsList);
-
-    return num;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList
-  (JNIEnv * env, jobject rightsManager, jobjectArray rightsArray, jint num)
-{
-    T_DRM_Rights_Info_Node *pRightsList;
-    T_DRM_Rights_Info_Node *pCurNode;
-    int32_t index;
-
-    if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList))
-        return JNI_DRM_FAILURE;
-
-    pCurNode = pRightsList;
-    for (index = 0; NULL != pCurNode; index++) {
-        jobject rights = (*env)->GetObjectArrayElement(env, rightsArray, index);
-        if (NULL == rights)
-            break;
-
-        if (JNI_DRM_FAILURE == setRightsFields(env, rights, &(pCurNode->roInfo)))
-            break;
-
-        (*env)->SetObjectArrayElement(env, rightsArray, index, rights);
-
-        pCurNode = pCurNode->next;
-    }
-
-    SVC_drm_freeRightsInfoList(pRightsList);
-
-    return index;
-}
-
-/* native interface */
-JNIEXPORT jint JNICALL
-Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights
-  (JNIEnv * env, jobject rightsManager, jobject rights)
-{
-    jclass clazz;
-    jfieldID field;
-    jstring str;
-    uint8_t *nativeStr;
-
-    clazz = (*env)->GetObjectClass(env, rights);
-    if (NULL == clazz)
-        return JNI_DRM_FAILURE;
-
-    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
-    if (NULL == field)
-        return JNI_DRM_FAILURE;
-
-    str = (*env)->GetObjectField(env, rights, field);
-
-    nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL);
-    if (NULL == nativeStr)
-        return JNI_DRM_FAILURE;
-
-    if (0 == strcmp("ForwardLock", (char *)nativeStr))
-        return JNI_DRM_SUCCESS;
-
-    if (DRM_SUCCESS != SVC_drm_deleteRights(nativeStr)) {
-        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-        return JNI_DRM_FAILURE;
-    }
-
-    (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
-    return JNI_DRM_SUCCESS;
-}
-
-/*
- * Table of methods associated with the DrmRawContent class.
- */
-static JNINativeMethod gDrmRawContentMethods[] = {
-    /* name, signature, funcPtr */
-    {"nativeConstructDrmContent", "(Ljava/io/InputStream;II)I",
-        (void*)Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent},
-    {"nativeGetRightsAddress", "()Ljava/lang/String;",
-        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress},
-    {"nativeGetDeliveryMethod", "()I",
-        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod},
-    {"nativeReadContent", "([BIII)I",
-        (void*)Java_android_drm_mobile1_DrmRawContent_nativeReadContent},
-    {"nativeGetContentType", "()Ljava/lang/String;",
-        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentType},
-    {"nativeGetContentLength", "()I",
-        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength},
-    {"finalize", "()V",
-        (void*)Java_android_drm_mobile1_DrmRawContent_finalize},
-};
-
-/*
- * Table of methods associated with the DrmRights class.
- */
-static JNINativeMethod gDrmRightsMethods[] = {
-    /* name, signature, funcPtr */
-    {"nativeGetConstraintInfo", "(ILandroid/drm/mobile1/DrmConstraintInfo;)I",
-        (void*)Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo},
-    {"nativeConsumeRights", "(I)I",
-        (void*)Java_android_drm_mobile1_DrmRights_nativeConsumeRights},
-};
-
-/*
- * Table of methods associated with the DrmRightsManager class.
- */
-static JNINativeMethod gDrmRightsManagerMethods[] = {
-    /* name, signature, funcPtr */
-    {"nativeInstallDrmRights", "(Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I",
-        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights},
-    {"nativeQueryRights", "(Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I",
-        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights},
-    {"nativeGetNumOfRights", "()I",
-        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights},
-    {"nativeGetRightsList", "([Landroid/drm/mobile1/DrmRights;I)I",
-        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList},
-    {"nativeDeleteRights", "(Landroid/drm/mobile1/DrmRights;)I",
-        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights},
-};
-
-/*
- * Register several native methods for one class.
- */
-static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
-{
-    jclass clazz;
-
-    clazz = (*env)->FindClass(env, className);
-    if (clazz == NULL)
-        return JNI_FALSE;
-
-    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
-        return JNI_FALSE;
-
-    return JNI_TRUE;
-}
-
-/*
- * Register native methods for all classes we know about.
- */
-static int registerNatives(JNIEnv* env)
-{
-    if (!registerNativeMethods(env, "android/drm/mobile1/DrmRawContent",
-            gDrmRawContentMethods, sizeof(gDrmRawContentMethods) / sizeof(gDrmRawContentMethods[0])))
-        return JNI_FALSE;
-
-    if (!registerNativeMethods(env, "android/drm/mobile1/DrmRights",
-            gDrmRightsMethods, sizeof(gDrmRightsMethods) / sizeof(gDrmRightsMethods[0])))
-        return JNI_FALSE;
-
-    if (!registerNativeMethods(env, "android/drm/mobile1/DrmRightsManager",
-            gDrmRightsManagerMethods, sizeof(gDrmRightsManagerMethods) / sizeof(gDrmRightsManagerMethods[0])))
-        return JNI_FALSE;
-
-    return JNI_TRUE;
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
-    JNIEnv* env = NULL;
-    jint result = -1;
-
-    printf("Entering JNI_OnLoad\n");
-
-    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK)
-        goto bail;
-
-    assert(env != NULL);
-
-    if (!registerNatives(env))
-        goto bail;
-
-    /* success -- return valid version number */
-    result = JNI_VERSION_1_4;
-
-bail:
-    printf("Leaving JNI_OnLoad (result=0x%x)\n", result);
-    return result;
-}
diff --git a/media/libdrm/mobile1/src/objmng/drm_api.c b/media/libdrm/mobile1/src/objmng/drm_api.c
deleted file mode 100644
index 232d9f4..0000000
--- a/media/libdrm/mobile1/src/objmng/drm_api.c
+++ /dev/null
@@ -1,1943 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <svc_drm.h>
-#include <drm_inner.h>
-#include <parser_dm.h>
-#include <parser_dcf.h>
-#include <parser_rel.h>
-#include <drm_rights_manager.h>
-#include <drm_time.h>
-#include <drm_decoder.h>
-#include "log.h"
-
-/**
- * Current id.
- */
-static int32_t curID = 0;
-
-/**
- * The header pointer for the session list.
- */
-static T_DRM_Session_Node* sessionTable = NULL;
-
-/**
- * New a session.
- */
-static T_DRM_Session_Node* newSession(T_DRM_Input_Data data)
-{
-    T_DRM_Session_Node* s = (T_DRM_Session_Node *)malloc(sizeof(T_DRM_Session_Node));
-
-    if (NULL != s) {
-        memset(s, 0, sizeof(T_DRM_Session_Node));
-
-        s->sessionId = curID++;
-        s->inputHandle = data.inputHandle;
-        s->mimeType = data.mimeType;
-        s->getInputDataLengthFunc = data.getInputDataLength;
-        s->readInputDataFunc = data.readInputData;
-        s->seekInputDataFunc = data.seekInputData;
-    }
-
-    return s;
-}
-
-/**
- * Free a session.
- */
-static void freeSession(T_DRM_Session_Node* s)
-{
-    if (NULL == s)
-        return;
-
-    if (NULL != s->rawContent)
-        free(s->rawContent);
-
-    if (NULL != s->readBuf)
-        free(s->readBuf);
-
-    if (NULL != s->infoStruct)
-        free(s->infoStruct);
-
-    free(s);
-}
-
-/**
- * Add a session to list.
- */
-static int32_t addSession(T_DRM_Session_Node* s)
-{
-    if (NULL == s)
-        return -1;
-
-    s->next = sessionTable;
-    sessionTable = s;
-
-    return s->sessionId;
-}
-
-/**
- * Get a session from the list.
- */
-static T_DRM_Session_Node* getSession(int32_t sessionId)
-{
-    T_DRM_Session_Node* s;
-
-    if (sessionId < 0 || NULL == sessionTable)
-        return NULL;
-
-    for (s = sessionTable; s != NULL; s = s->next) {
-        if (sessionId == s->sessionId)
-            return s;
-    }
-
-    return NULL;
-}
-
-/**
- * Remove a session from the list.
- */
-static void removeSession(int32_t sessionId)
-{
-    T_DRM_Session_Node *curS, *preS;
-
-    if (sessionId < 0 || NULL == sessionTable)
-        return;
-
-    if (sessionId == sessionTable->sessionId) {
-        curS = sessionTable;
-        sessionTable = curS->next;
-        freeSession(curS);
-        return;
-    }
-
-    for (preS = sessionTable; preS->next != NULL; preS = preS->next) {
-        if (preS->next->sessionId == sessionId)
-            curS = preS->next;
-    }
-
-    if (NULL == preS->next)
-        return;
-
-    preS->next = curS->next;
-    freeSession(curS);
-}
-
-/**
- * Try to identify the mimetype according the input DRM data.
- */
-static int32_t getMimeType(const uint8_t *buf, int32_t bufLen)
-{
-    const uint8_t *p;
-
-    if (NULL == buf || bufLen <= 0)
-        return TYPE_DRM_UNKNOWN;
-
-    p = buf;
-
-    /* check if it is DRM Content Format, only check the first field of Version, it must be "0x01" */
-    if (0x01 == *p)
-        return TYPE_DRM_CONTENT;
-
-    /* check if it is DRM Message, only check the first two bytes, it must be the start flag of boundary: "--" */
-    if (bufLen >= 2 && '-' == *p && '-' == *(p + 1))
-        return TYPE_DRM_MESSAGE;
-
-    /* check if it is DRM Rights XML format, only check the first several bytes, it must be: "<o-ex:rights" */
-    if (bufLen >= 12 && 0 == strncmp("<o-ex:rights", (char *)p, 12))
-        return TYPE_DRM_RIGHTS_XML;
-
-    /* check if it is DRM Rights WBXML format, only check the first two bytes, it must be: 0x03, 0x0e */
-    if (bufLen >= 2 && 0x03 == *p && 0x0e == *(p + 1))
-        return TYPE_DRM_RIGHTS_WBXML;
-
-    return TYPE_DRM_UNKNOWN;
-}
-
-static int32_t drm_skipCRLFinB64(const uint8_t* b64Data, int32_t len)
-{
-    const uint8_t* p;
-    int32_t skipLen = 0;
-
-    if (NULL == b64Data || len <= 0)
-        return -1;
-
-    p = b64Data;
-    while (p - b64Data < len) {
-        if ('\r' == *p || '\n'== *p)
-            skipLen++;
-        p++;
-    }
-
-    return skipLen;
-}
-
-static int32_t drm_scanEndBoundary(const uint8_t* pBuf, int32_t len, uint8_t* const boundary)
-{
-    const uint8_t* p;
-    int32_t leftLen;
-    int32_t boundaryLen;
-
-    if (NULL == pBuf || len <=0 || NULL == boundary)
-        return -1;
-
-    p = pBuf;
-    boundaryLen = strlen((char *)boundary) + 2; /* 2 means: '\r' and '\n' */
-    leftLen = len - (p - pBuf);
-    while (leftLen > 0) {
-        if (NULL == (p = memchr(p, '\r', leftLen)))
-            break;
-
-        leftLen = len - (p - pBuf);
-        if (leftLen < boundaryLen)
-            return -2; /* here means may be the boundary has been split */
-
-        if (('\n' == *(p + 1)) && (0 == memcmp(p + 2, boundary, strlen((char *)boundary))))
-            return p - pBuf; /* find the boundary here */
-
-        p++;
-        leftLen--;
-    }
-
-    return len; /* no boundary found */
-}
-
-static int32_t drm_getLicenseInfo(T_DRM_Rights* pRights, T_DRM_Rights_Info* licenseInfo)
-{
-    if (NULL != licenseInfo && NULL != pRights) {
-        strcpy((char *)licenseInfo->roId, (char *)pRights->uid);
-
-        if (1 == pRights->bIsDisplayable) {
-            licenseInfo->displayRights.indicator = pRights->DisplayConstraint.Indicator;
-            licenseInfo->displayRights.count =
-                pRights->DisplayConstraint.Count;
-            licenseInfo->displayRights.startDate =
-                pRights->DisplayConstraint.StartTime.date;
-            licenseInfo->displayRights.startTime =
-                pRights->DisplayConstraint.StartTime.time;
-            licenseInfo->displayRights.endDate =
-                pRights->DisplayConstraint.EndTime.date;
-            licenseInfo->displayRights.endTime =
-                pRights->DisplayConstraint.EndTime.time;
-            licenseInfo->displayRights.intervalDate =
-                pRights->DisplayConstraint.Interval.date;
-            licenseInfo->displayRights.intervalTime =
-                pRights->DisplayConstraint.Interval.time;
-        }
-        if (1 == pRights->bIsPlayable) {
-            licenseInfo->playRights.indicator = pRights->PlayConstraint.Indicator;
-            licenseInfo->playRights.count = pRights->PlayConstraint.Count;
-            licenseInfo->playRights.startDate =
-                pRights->PlayConstraint.StartTime.date;
-            licenseInfo->playRights.startTime =
-                pRights->PlayConstraint.StartTime.time;
-            licenseInfo->playRights.endDate =
-                pRights->PlayConstraint.EndTime.date;
-            licenseInfo->playRights.endTime =
-                pRights->PlayConstraint.EndTime.time;
-            licenseInfo->playRights.intervalDate =
-                pRights->PlayConstraint.Interval.date;
-            licenseInfo->playRights.intervalTime =
-                pRights->PlayConstraint.Interval.time;
-        }
-        if (1 == pRights->bIsExecuteable) {
-            licenseInfo->executeRights.indicator = pRights->ExecuteConstraint.Indicator;
-            licenseInfo->executeRights.count =
-                pRights->ExecuteConstraint.Count;
-            licenseInfo->executeRights.startDate =
-                pRights->ExecuteConstraint.StartTime.date;
-            licenseInfo->executeRights.startTime =
-                pRights->ExecuteConstraint.StartTime.time;
-            licenseInfo->executeRights.endDate =
-                pRights->ExecuteConstraint.EndTime.date;
-            licenseInfo->executeRights.endTime =
-                pRights->ExecuteConstraint.EndTime.time;
-            licenseInfo->executeRights.intervalDate =
-                pRights->ExecuteConstraint.Interval.date;
-            licenseInfo->executeRights.intervalTime =
-                pRights->ExecuteConstraint.Interval.time;
-        }
-        if (1 == pRights->bIsPrintable) {
-            licenseInfo->printRights.indicator = pRights->PrintConstraint.Indicator;
-            licenseInfo->printRights.count =
-                pRights->PrintConstraint.Count;
-            licenseInfo->printRights.startDate =
-                pRights->PrintConstraint.StartTime.date;
-            licenseInfo->printRights.startTime =
-                pRights->PrintConstraint.StartTime.time;
-            licenseInfo->printRights.endDate =
-                pRights->PrintConstraint.EndTime.date;
-            licenseInfo->printRights.endTime =
-                pRights->PrintConstraint.EndTime.time;
-            licenseInfo->printRights.intervalDate =
-                pRights->PrintConstraint.Interval.date;
-            licenseInfo->printRights.intervalTime =
-                pRights->PrintConstraint.Interval.time;
-        }
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static int32_t drm_addRightsNodeToList(T_DRM_Rights_Info_Node **ppRightsHeader,
-                                       T_DRM_Rights_Info_Node *pInputRightsNode)
-{
-    T_DRM_Rights_Info_Node *pRightsNode;
-
-    if (NULL == ppRightsHeader || NULL == pInputRightsNode)
-        return FALSE;
-
-    pRightsNode = (T_DRM_Rights_Info_Node *)malloc(sizeof(T_DRM_Rights_Info_Node));
-    if (NULL == pRightsNode)
-        return FALSE;
-
-    memcpy(pRightsNode, pInputRightsNode, sizeof(T_DRM_Rights_Info_Node));
-    pRightsNode->next = NULL;
-
-    /* this means it is the first node */
-    if (NULL == *ppRightsHeader)
-        *ppRightsHeader = pRightsNode;
-    else {
-        T_DRM_Rights_Info_Node *pTmp;
-
-        pTmp = *ppRightsHeader;
-        while (NULL != pTmp->next)
-            pTmp = pTmp->next;
-
-        pTmp->next = pRightsNode;
-    }
-    return TRUE;
-}
-
-static int32_t drm_startConsumeRights(int32_t * bIsXXable,
-                                      T_DRM_Rights_Constraint * XXConstraint,
-                                      int32_t * writeFlag)
-{
-    T_DB_TIME_SysTime curDateTime;
-    T_DRM_DATETIME CurrentTime;
-    uint8_t countFlag = 0;
-
-    memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME));
-
-    if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint || NULL == writeFlag)
-        return DRM_FAILURE;
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */
-        return DRM_SUCCESS;
-
-    *bIsXXable = 0; /* Assume have invalid rights at first */
-    *writeFlag = 0;
-
-    if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT | DRM_INTERVAL_CONSTRAINT))) {
-        DRM_time_getSysTime(&curDateTime);
-
-        if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day,
-                                curDateTime.hour, curDateTime.min, curDateTime.sec))
-            return DRM_FAILURE;
-
-        YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day,
-                      CurrentTime.date, curDateTime.hour, curDateTime.min,
-                      curDateTime.sec, CurrentTime.time);
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */
-        *writeFlag = 1;
-        /* If it has only one time for use, after use this function, we will delete this rights */
-        if (XXConstraint->Count <= 0) {
-            XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT;
-            return DRM_RIGHTS_EXPIRED;
-        }
-
-        if (XXConstraint->Count-- <= 1) {
-            XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT;
-            countFlag = 1;
-        }
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) {
-        if (XXConstraint->StartTime.date > CurrentTime.date ||
-            (XXConstraint->StartTime.date == CurrentTime.date &&
-             XXConstraint->StartTime.time >= CurrentTime.time)) {
-            *bIsXXable = 1;
-            return DRM_RIGHTS_PENDING;
-        }
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */
-        if (XXConstraint->EndTime.date < CurrentTime.date ||
-            (XXConstraint->EndTime.date == CurrentTime.date &&
-             XXConstraint->EndTime.time <= CurrentTime.time)) {
-            *writeFlag = 1;
-            XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT;
-            return DRM_RIGHTS_EXPIRED;
-        }
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */
-        int32_t year, mon, day, hour, min, sec, date, time;
-        int32_t ret;
-
-        XXConstraint->Indicator |= DRM_END_TIME_CONSTRAINT;
-        XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT; /* Write off interval right */
-        *writeFlag = 1;
-
-        if (XXConstraint->Interval.date == 0
-            && XXConstraint->Interval.time == 0) {
-            return DRM_RIGHTS_EXPIRED;
-        }
-        date = CurrentTime.date + XXConstraint->Interval.date;
-        time = CurrentTime.time + XXConstraint->Interval.time;
-        INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time);
-
-        if (sec > 59) {
-            min += sec / 60;
-            sec %= 60;
-        }
-        if (min > 59) {
-            hour += min / 60;
-            min %= 60;
-        }
-        if (hour > 23) {
-            day += hour / 24;
-            hour %= 24;
-        }
-        if (day > 31) {
-            mon += day / 31;
-            day %= 31;
-        }
-        if (mon > 12) {
-            year += mon / 12;
-            mon %= 12;
-        }
-        if (day > (ret = drm_monthDays(year, mon))) {
-            day -= ret;
-            mon++;
-            if (mon > 12) {
-                mon -= 12;
-                year++;
-            }
-        }
-        YMD_HMS_2_INT(year, mon, day, XXConstraint->EndTime.date, hour,
-                      min, sec, XXConstraint->EndTime.time);
-    }
-
-    if (1 != countFlag)
-        *bIsXXable = 1; /* Can go here ,so  right must be valid */
-    return DRM_SUCCESS;
-}
-
-static int32_t drm_startCheckRights(int32_t * bIsXXable,
-                                    T_DRM_Rights_Constraint * XXConstraint)
-{
-    T_DB_TIME_SysTime curDateTime;
-    T_DRM_DATETIME CurrentTime;
-
-    memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME));
-
-    if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint)
-        return DRM_FAILURE;
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */
-        return DRM_SUCCESS;
-
-    *bIsXXable = 0; /* Assume have invalid rights at first */
-
-    if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT))) {
-        DRM_time_getSysTime(&curDateTime);
-
-        if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day,
-                                curDateTime.hour, curDateTime.min, curDateTime.sec))
-            return DRM_FAILURE;
-
-        YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day,
-                      CurrentTime.date, curDateTime.hour, curDateTime.min,
-                      curDateTime.sec, CurrentTime.time);
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */
-        if (XXConstraint->Count <= 0) {
-            XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT;
-            return DRM_RIGHTS_EXPIRED;
-        }
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) {
-        if (XXConstraint->StartTime.date > CurrentTime.date ||
-            (XXConstraint->StartTime.date == CurrentTime.date &&
-             XXConstraint->StartTime.time >= CurrentTime.time)) {
-            *bIsXXable = 1;
-            return DRM_RIGHTS_PENDING;
-        }
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */
-        if (XXConstraint->EndTime.date < CurrentTime.date ||
-            (XXConstraint->EndTime.date == CurrentTime.date &&
-             XXConstraint->EndTime.time <= CurrentTime.time)) {
-            XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT;
-            return DRM_RIGHTS_EXPIRED;
-        }
-    }
-
-    if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */
-        if (XXConstraint->Interval.date == 0 && XXConstraint->Interval.time == 0) {
-            XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT;
-            return DRM_RIGHTS_EXPIRED;
-        }
-    }
-
-    *bIsXXable = 1;
-    return DRM_SUCCESS;
-}
-
-int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission)
-{
-    int32_t writeFlag = 0;
-    int32_t roAmount;
-    int32_t validRoAmount = 0;
-    int32_t flag = DRM_FAILURE;
-    int32_t i, j;
-    T_DRM_Rights *pRo;
-    T_DRM_Rights *pCurRo;
-    int32_t * pNumOfPriority;
-    int32_t iNum;
-    T_DRM_Rights_Constraint * pCurConstraint;
-    T_DRM_Rights_Constraint * pCompareConstraint;
-    int priority[8] = {1, 2, 4, 3, 8, 6, 7, 5};
-
-    if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT))
-        return DRM_FAILURE;
-
-    validRoAmount = roAmount;
-    if (roAmount < 1)
-        return DRM_NO_RIGHTS;
-
-    pRo = malloc(roAmount * sizeof(T_DRM_Rights));
-    pCurRo = pRo;
-    if (NULL == pRo)
-        return DRM_FAILURE;
-
-    if (FALSE == drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO)) {
-        free(pRo);
-        return DRM_FAILURE;
-    }
-
-    /** check the right priority */
-    pNumOfPriority = malloc(sizeof(int32_t) * roAmount);
-    for(i = 0; i < roAmount; i++) {
-        iNum = roAmount - 1;
-        for(j = 0; j < roAmount; j++) {
-            if(i == j)
-                continue;
-            switch(permission) {
-            case DRM_PERMISSION_PLAY:
-                pCurConstraint = &pRo[i].PlayConstraint;
-                pCompareConstraint = &pRo[j].PlayConstraint;
-                break;
-            case DRM_PERMISSION_DISPLAY:
-                pCurConstraint = &pRo[i].DisplayConstraint;
-                pCompareConstraint = &pRo[j].DisplayConstraint;
-                break;
-            case DRM_PERMISSION_EXECUTE:
-                pCurConstraint = &pRo[i].ExecuteConstraint;
-                pCompareConstraint = &pRo[j].ExecuteConstraint;
-                break;
-            case DRM_PERMISSION_PRINT:
-                pCurConstraint = &pRo[i].PrintConstraint;
-                pCompareConstraint = &pRo[j].PrintConstraint;
-                break;
-            default:
-                free(pRo);
-                free(pNumOfPriority);
-                return DRM_FAILURE;
-            }
-
-            /**get priority by Indicator*/
-            if(0 == (pCurConstraint->Indicator & DRM_NO_CONSTRAINT) &&
-                0 == (pCompareConstraint->Indicator & DRM_NO_CONSTRAINT)) {
-                    int num1, num2;
-                    num1 = (pCurConstraint->Indicator & 0x0e) >> 1;
-                    num2 = (pCompareConstraint->Indicator & 0x0e) >> 1;
-                    if(priority[num1] > priority[num2]) {
-                        iNum--;
-                        continue;
-                    } else if(priority[pCurConstraint->Indicator] < priority[pCompareConstraint->Indicator])
-                        continue;
-            } else if(pCurConstraint->Indicator > pCompareConstraint->Indicator) {
-                iNum--;
-                continue;
-            } else if(pCurConstraint->Indicator < pCompareConstraint->Indicator)
-                continue;
-
-            if(0 != (pCurConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) {
-                if(pCurConstraint->EndTime.date < pCompareConstraint->EndTime.date) {
-                    iNum--;
-                    continue;
-                } else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date)
-                    continue;
-
-                if(pCurConstraint->EndTime.time < pCompareConstraint->EndTime.time) {
-                    iNum--;
-                    continue;
-                } else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date)
-                    continue;
-            }
-
-            if(0 != (pCurConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) {
-                if(pCurConstraint->Interval.date < pCompareConstraint->Interval.date) {
-                    iNum--;
-                    continue;
-                } else if(pCurConstraint->Interval.date > pCompareConstraint->Interval.date)
-                    continue;
-
-                if(pCurConstraint->Interval.time < pCompareConstraint->Interval.time) {
-                    iNum--;
-                    continue;
-                } else if(pCurConstraint->Interval.time > pCompareConstraint->Interval.time)
-                    continue;
-            }
-
-            if(0 != (pCurConstraint->Indicator & DRM_COUNT_CONSTRAINT)) {
-                if(pCurConstraint->Count < pCompareConstraint->Count) {
-                    iNum--;
-                    continue;
-                } else if(pCurConstraint->Count > pCompareConstraint->Count)
-                    continue;
-            }
-
-            if(i < j)
-                iNum--;
-        }
-        pNumOfPriority[iNum] = i;
-    }
-
-    for (i = 0; i < validRoAmount; i++) {
-        /** check the right priority */
-        if (pNumOfPriority[i] >= validRoAmount)
-            break;
-
-        pCurRo = pRo + pNumOfPriority[i];
-
-        switch (permission) {
-        case DRM_PERMISSION_PLAY:
-            flag =
-                drm_startConsumeRights(&pCurRo->bIsPlayable,
-                                       &pCurRo->PlayConstraint, &writeFlag);
-            break;
-        case DRM_PERMISSION_DISPLAY:
-            flag =
-                drm_startConsumeRights(&pCurRo->bIsDisplayable,
-                                       &pCurRo->DisplayConstraint,
-                                       &writeFlag);
-            break;
-        case DRM_PERMISSION_EXECUTE:
-            flag =
-                drm_startConsumeRights(&pCurRo->bIsExecuteable,
-                                       &pCurRo->ExecuteConstraint,
-                                       &writeFlag);
-            break;
-        case DRM_PERMISSION_PRINT:
-            flag =
-                drm_startConsumeRights(&pCurRo->bIsPrintable,
-                                       &pCurRo->PrintConstraint, &writeFlag);
-            break;
-        default:
-            free(pNumOfPriority);
-            free(pRo);
-            return DRM_FAILURE;
-        }
-
-        /* Here confirm the valid RO amount and set the writeFlag */
-        if (0 == pCurRo->bIsPlayable && 0 == pCurRo->bIsDisplayable &&
-            0 == pCurRo->bIsExecuteable && 0 == pCurRo->bIsPrintable) {
-            int32_t iCurPri;
-
-            /** refresh the right priority */
-            iCurPri = pNumOfPriority[i];
-            for(j = i; j < validRoAmount - 1; j++)
-                pNumOfPriority[j] = pNumOfPriority[j + 1];
-
-            if(iCurPri != validRoAmount - 1) {
-                memcpy(pCurRo, pRo + validRoAmount - 1,
-                    sizeof(T_DRM_Rights));
-                for(j = 0; j < validRoAmount -1; j++) {
-                    if(validRoAmount - 1 == pNumOfPriority[j])
-                        pNumOfPriority[j] = iCurPri;
-                }
-            }
-
-            /* Here means it is not the last one RO, so the invalid RO should be deleted */
-            writeFlag = 1;
-            validRoAmount--; /* If current right is invalid */
-            i--;
-        }
-
-        /* If the flag is TRUE, this means: we have found a valid RO, so break, no need to check other RO */
-        if (DRM_SUCCESS == flag)
-            break;
-    }
-
-    if (1 == writeFlag) {
-        /* Delete the *.info first */
-        //drm_removeIdInfoFile(id);
-
-        if (FALSE == drm_writeOrReadInfo(id, pRo, &validRoAmount, SAVE_ALL_RO))
-            flag = DRM_FAILURE;
-    }
-
-    free(pNumOfPriority);
-    free(pRo);
-    return flag;
-}
-
-
-/* see svc_drm.h */
-int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo)
-{
-    uint8_t *buf;
-    int32_t dataLen, bufLen;
-    T_DRM_Rights rights;
-
-    if (0 == data.inputHandle)
-        return DRM_RIGHTS_DATA_INVALID;
-
-    /* Get input rights data length */
-    dataLen = data.getInputDataLength(data.inputHandle);
-    if (dataLen <= 0)
-        return DRM_RIGHTS_DATA_INVALID;
-
-    /* Check if the length is larger than DRM max malloc length */
-    if (dataLen > DRM_MAX_MALLOC_LEN)
-        bufLen = DRM_MAX_MALLOC_LEN;
-    else
-        bufLen = dataLen;
-
-    buf = (uint8_t *)malloc(bufLen);
-    if (NULL == buf)
-        return DRM_FAILURE;
-
-    /* Read input data to buffer */
-    if (0 >= data.readInputData(data.inputHandle, buf, bufLen)) {
-        free(buf);
-        return DRM_RIGHTS_DATA_INVALID;
-    }
-
-    /* if the input mime type is unknown, DRM engine will try to recognize it. */
-    if (TYPE_DRM_UNKNOWN == data.mimeType)
-        data.mimeType = getMimeType(buf, bufLen);
-
-    switch(data.mimeType) {
-    case TYPE_DRM_MESSAGE: /* in case of Combined Delivery, extract the rights part to install */
-        {
-            T_DRM_DM_Info dmInfo;
-
-            memset(&dmInfo, 0, sizeof(T_DRM_DM_Info));
-            if (FALSE == drm_parseDM(buf, bufLen, &dmInfo)) {
-                free(buf);
-                return DRM_RIGHTS_DATA_INVALID;
-            }
-
-            /* if it is not Combined Delivery, it can not use to "SVC_drm_installRights" */
-            if (COMBINED_DELIVERY != dmInfo.deliveryType || dmInfo.rightsOffset <= 0 || dmInfo.rightsLen <= 0) {
-                free(buf);
-                return DRM_RIGHTS_DATA_INVALID;
-            }
-
-            memset(&rights, 0, sizeof(T_DRM_Rights));
-            if (FALSE == drm_relParser(buf + dmInfo.rightsOffset, dmInfo.rightsLen, TYPE_DRM_RIGHTS_XML, &rights)) {
-                free(buf);
-                return DRM_RIGHTS_DATA_INVALID;
-            }
-        }
-        break;
-    case TYPE_DRM_RIGHTS_XML:
-    case TYPE_DRM_RIGHTS_WBXML:
-        memset(&rights, 0, sizeof(T_DRM_Rights));
-        if (FALSE == drm_relParser(buf, bufLen, data.mimeType, &rights)) {
-            free(buf);
-            return DRM_RIGHTS_DATA_INVALID;
-        }
-        break;
-    case TYPE_DRM_CONTENT: /* DCF should not using "SVC_drm_installRights", it should be used to open a session. */
-    case TYPE_DRM_UNKNOWN:
-    default:
-        free(buf);
-        return DRM_MEDIA_DATA_INVALID;
-    }
-
-    free(buf);
-
-    /* append the rights information to DRM engine storage */
-    if (FALSE == drm_appendRightsInfo(&rights))
-        return DRM_FAILURE;
-
-    memset(pRightsInfo, 0, sizeof(T_DRM_Rights_Info));
-    drm_getLicenseInfo(&rights, pRightsInfo);
-
-    return DRM_SUCCESS;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_openSession(T_DRM_Input_Data data)
-{
-    int32_t session;
-    int32_t dataLen;
-    T_DRM_Session_Node* s;
-
-    if (0 == data.inputHandle)
-        return DRM_MEDIA_DATA_INVALID;
-
-    /* Get input data length */
-    dataLen = data.getInputDataLength(data.inputHandle);
-    if (dataLen <= 0)
-        return DRM_MEDIA_DATA_INVALID;
-
-    s = newSession(data);
-    if (NULL == s)
-        return DRM_FAILURE;
-
-    /* Check if the length is larger than DRM max malloc length */
-    if (dataLen > DRM_MAX_MALLOC_LEN)
-        s->rawContentLen = DRM_MAX_MALLOC_LEN;
-    else
-        s->rawContentLen = dataLen;
-
-    s->rawContent = (uint8_t *)malloc(s->rawContentLen);
-    if (NULL == s->rawContent)
-        return DRM_FAILURE;
-
-    /* Read input data to buffer */
-    if (0 >= data.readInputData(data.inputHandle, s->rawContent, s->rawContentLen)) {
-        freeSession(s);
-        return DRM_MEDIA_DATA_INVALID;
-    }
-
-    /* if the input mime type is unknown, DRM engine will try to recognize it. */
-    if (TYPE_DRM_UNKNOWN == data.mimeType)
-        data.mimeType = getMimeType(s->rawContent, s->rawContentLen);
-
-    switch(data.mimeType) {
-    case TYPE_DRM_MESSAGE:
-        {
-            T_DRM_DM_Info dmInfo;
-
-            memset(&dmInfo, 0, sizeof(T_DRM_DM_Info));
-            if (FALSE == drm_parseDM(s->rawContent, s->rawContentLen, &dmInfo)) {
-                freeSession(s);
-                return DRM_MEDIA_DATA_INVALID;
-            }
-
-            s->deliveryMethod = dmInfo.deliveryType;
-
-            if (SEPARATE_DELIVERY_FL == s->deliveryMethod)
-                s->contentLength = DRM_UNKNOWN_DATA_LEN;
-            else
-                s->contentLength = dmInfo.contentLen;
-
-            s->transferEncoding = dmInfo.transferEncoding;
-            s->contentOffset = dmInfo.contentOffset;
-            s->bEndData = FALSE;
-            strcpy((char *)s->contentType, (char *)dmInfo.contentType);
-            strcpy((char *)s->contentID, (char *)dmInfo.contentID);
-
-            if (SEPARATE_DELIVERY_FL == s->deliveryMethod) {
-                s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node));
-                if (NULL == s->infoStruct)
-                    return DRM_FAILURE;
-                memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node));
-
-                ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dmInfo.contentLen;
-                strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dmInfo.rightsIssuer);
-                break;
-            }
-
-            if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) {
-                s->infoStruct = (T_DRM_DM_Base64_Node *)malloc(sizeof(T_DRM_DM_Base64_Node));
-                if (NULL == s->infoStruct)
-                    return DRM_FAILURE;
-                memset(s->infoStruct, 0, sizeof(T_DRM_DM_Base64_Node));
-
-                strcpy((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary);
-            } else {
-                s->infoStruct = (T_DRM_DM_Binary_Node *)malloc(sizeof(T_DRM_DM_Binary_Node));
-                if (NULL == s->infoStruct)
-                    return DRM_FAILURE;
-                memset(s->infoStruct, 0, sizeof(T_DRM_DM_Binary_Node));
-
-                strcpy((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary);
-            }
-
-
-            if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) {
-                if (s->contentLength > 0) {
-                    int32_t encLen, decLen;
-
-                    encLen = s->contentLength;
-                    decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK;
-
-                    decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen);
-                    s->contentLength = decLen;
-                } else {
-                    int32_t encLen = DRM_MAX_MALLOC_LEN - s->contentOffset, decLen;
-                    int32_t skipLen, needBytes, i;
-                    uint8_t *pStart;
-                    int32_t res, bFoundBoundary = FALSE;
-
-                    pStart = s->rawContent + s->contentOffset;
-                    if (-1 == (skipLen = drm_skipCRLFinB64(pStart, encLen))) {
-                        freeSession(s);
-                        return DRM_FAILURE;
-                    }
-
-                    needBytes = DRM_B64_ENC_BLOCK - ((encLen - skipLen) % DRM_B64_ENC_BLOCK);
-                    if (needBytes < DRM_B64_ENC_BLOCK) {
-                        s->rawContent = (uint8_t *)realloc(s->rawContent, DRM_MAX_MALLOC_LEN + needBytes);
-                        if (NULL == s->rawContent) {
-                            freeSession(s);
-                            return DRM_FAILURE;
-                        }
-
-                        i = 0;
-                        while (i < needBytes) {
-                            if (-1 != data.readInputData(data.inputHandle, s->rawContent + DRM_MAX_MALLOC_LEN + i, 1)) {
-                                if ('\r' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i) || '\n' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i))
-                                    continue;
-                                i++;
-                            } else
-                                break;
-                        }
-                        encLen += i;
-                    }
-
-                    res = drm_scanEndBoundary(pStart, encLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary);
-                    if (-1 == res) {
-                        freeSession(s);
-                        return DRM_FAILURE;
-                    }
-                    if (-2 == res) { /* may be there is a boundary */
-                        int32_t boundaryLen, leftLen, readBytes;
-                        char* pTmp = memrchr(pStart, '\r', encLen);
-
-                        if (NULL == pTmp) {
-                            freeSession(s);
-                            return DRM_FAILURE; /* conflict */
-                        }
-                        boundaryLen = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */
-                        s->readBuf = (uint8_t *)malloc(boundaryLen);
-                        if (NULL == s->readBuf) {
-                            freeSession(s);
-                            return DRM_FAILURE;
-                        }
-                        s->readBufOff = encLen - ((uint8_t *)pTmp - pStart);
-                        s->readBufLen = boundaryLen - s->readBufOff;
-                        memcpy(s->readBuf, pTmp, s->readBufOff);
-                        readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen);
-                        if (-1 == readBytes || readBytes < s->readBufLen) {
-                            freeSession(s);
-                            return DRM_MEDIA_DATA_INVALID;
-                        }
-
-                        if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary)) {
-                            encLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */
-                            bFoundBoundary = TRUE;
-                        }
-                    } else {
-                        if (res >= 0 && res < encLen) {
-                            encLen = res;
-                            bFoundBoundary = TRUE;
-                        }
-                    }
-
-                    decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK;
-                    decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen);
-                    ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen = decLen;
-                    if (bFoundBoundary)
-                        s->contentLength = decLen;
-                }
-            } else {
-                /* binary data */
-                if (DRM_UNKNOWN_DATA_LEN == s->contentLength) {
-                    /* try to check whether there is boundary may be split */
-                    int32_t res, binContentLen;
-                    uint8_t* pStart;
-                    int32_t bFoundBoundary = FALSE;
-
-                    pStart = s->rawContent + s->contentOffset;
-                    binContentLen = s->rawContentLen - s->contentOffset;
-                    res = drm_scanEndBoundary(pStart, binContentLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary);
-
-                    if (-1 == res) {
-                        freeSession(s);
-                        return DRM_FAILURE;
-                    }
-
-                    if (-2 == res) { /* may be the boundary is split */
-                        int32_t boundaryLen, leftLen, readBytes;
-                        char* pTmp = memrchr(pStart, '\r', binContentLen);
-
-                        if (NULL == pTmp) {
-                            freeSession(s);
-                            return DRM_FAILURE; /* conflict */
-                        }
-
-                        boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */
-                        s->readBuf = (uint8_t *)malloc(boundaryLen);
-                        if (NULL == s->readBuf) {
-                            freeSession(s);
-                            return DRM_FAILURE;
-                        }
-                        s->readBufOff = binContentLen - ((uint8_t *)pTmp - pStart);
-                        s->readBufLen = boundaryLen - s->readBufOff;
-                        memcpy(s->readBuf, pTmp, s->readBufOff);
-                        readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen);
-                        if (-1 == readBytes || readBytes < s->readBufLen) {
-                            freeSession(s);
-                            return DRM_MEDIA_DATA_INVALID;
-                        }
-
-                        if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) {
-                            binContentLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */
-                            bFoundBoundary = TRUE;
-                        }
-                    } else {
-                        if (res >= 0 && res < binContentLen) {
-                            binContentLen = res;
-                            bFoundBoundary = TRUE;
-                        }
-                    }
-
-                    if (bFoundBoundary)
-                        s->contentLength = binContentLen;
-                }
-            }
-        }
-        break;
-    case TYPE_DRM_CONTENT:
-        {
-            T_DRM_DCF_Info dcfInfo;
-            uint8_t* pEncData = NULL;
-
-            memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info));
-            if (FALSE == drm_dcfParser(s->rawContent, s->rawContentLen, &dcfInfo, &pEncData)) {
-                freeSession(s);
-                return DRM_MEDIA_DATA_INVALID;
-            }
-
-            s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node));
-            if (NULL == s->infoStruct)
-                return DRM_FAILURE;
-            memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node));
-
-            s->deliveryMethod = SEPARATE_DELIVERY;
-            s->contentLength = dcfInfo.DecryptedDataLen;
-            ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dcfInfo.EncryptedDataLen;
-            s->contentOffset = pEncData - s->rawContent;
-            strcpy((char *)s->contentType, (char *)dcfInfo.ContentType);
-            strcpy((char *)s->contentID, (char *)dcfInfo.ContentURI);
-            strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dcfInfo.Rights_Issuer);
-        }
-        break;
-    case TYPE_DRM_RIGHTS_XML:   /* rights object should using "SVC_drm_installRights", it can not open a session */
-    case TYPE_DRM_RIGHTS_WBXML: /* rights object should using "SVC_drm_installRights", it can not open a session */
-    case TYPE_DRM_UNKNOWN:
-    default:
-        freeSession(s);
-        return DRM_MEDIA_DATA_INVALID;
-    }
-
-    if ((SEPARATE_DELIVERY_FL == s->deliveryMethod || SEPARATE_DELIVERY == s->deliveryMethod) &&
-        s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN) {
-        uint8_t keyValue[DRM_KEY_LEN];
-        uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN];
-        int32_t seekPos, moreBytes;
-
-        if (TRUE == drm_getKey(s->contentID, keyValue)) {
-            seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN;
-            memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN);
-
-            if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) {
-                s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength;
-                s->contentLength -= moreBytes;
-            }
-        }
-    }
-
-    session = addSession(s);
-    if (-1 == session)
-        return DRM_FAILURE;
-
-    return session;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_getDeliveryMethod(int32_t session)
-{
-    T_DRM_Session_Node* s;
-
-    if (session < 0)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    return s->deliveryMethod;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType)
-{
-    T_DRM_Session_Node* s;
-
-    if (session < 0 || NULL == mediaType)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    strcpy((char *)mediaType, (char *)s->contentType);
-
-    return DRM_SUCCESS;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_checkRights(int32_t session, int32_t permission)
-{
-    T_DRM_Session_Node* s;
-    int32_t id;
-    T_DRM_Rights *pRo, *pCurRo;
-    int32_t roAmount;
-    int32_t i;
-    int32_t res = DRM_FAILURE;
-
-    if (session < 0)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    /* if it is Forward-Lock cases, check it and return directly */
-    if (FORWARD_LOCK == s->deliveryMethod) {
-        if (DRM_PERMISSION_PLAY == permission ||
-            DRM_PERMISSION_DISPLAY == permission ||
-            DRM_PERMISSION_EXECUTE == permission ||
-            DRM_PERMISSION_PRINT == permission)
-            return DRM_SUCCESS;
-
-        return DRM_FAILURE;
-    }
-
-    /* if try to forward, only DCF can be forwarded */
-    if (DRM_PERMISSION_FORWARD == permission) {
-        if (SEPARATE_DELIVERY == s->deliveryMethod)
-            return DRM_SUCCESS;
-
-        return DRM_FAILURE;
-    }
-
-    /* The following will check CD or SD other permissions */
-    if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID))
-        return DRM_FAILURE;
-
-    drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT);
-    if (roAmount <= 0)
-        return DRM_FAILURE;
-
-    pRo = malloc(roAmount * sizeof(T_DRM_Rights));
-    if (NULL == pRo)
-        return DRM_FAILURE;
-
-    drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO);
-
-    pCurRo = pRo;
-    for (i = 0; i < roAmount; i++) {
-        switch (permission) {
-        case DRM_PERMISSION_PLAY:
-            res = drm_startCheckRights(&(pCurRo->bIsPlayable), &(pCurRo->PlayConstraint));
-            break;
-        case DRM_PERMISSION_DISPLAY:
-            res = drm_startCheckRights(&(pCurRo->bIsDisplayable), &(pCurRo->DisplayConstraint));
-            break;
-        case DRM_PERMISSION_EXECUTE:
-            res = drm_startCheckRights(&(pCurRo->bIsExecuteable), &(pCurRo->ExecuteConstraint));
-            break;
-        case DRM_PERMISSION_PRINT:
-            res = drm_startCheckRights(&(pCurRo->bIsPrintable), &(pCurRo->PrintConstraint));
-            break;
-        default:
-            free(pRo);
-            return DRM_FAILURE;
-        }
-
-        if (DRM_SUCCESS == res) {
-            free(pRo);
-            return DRM_SUCCESS;
-        }
-        pCurRo++;
-    }
-
-    free(pRo);
-    return res;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_consumeRights(int32_t session, int32_t permission)
-{
-    T_DRM_Session_Node* s;
-    int32_t id;
-
-    if (session < 0)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    if (DRM_PERMISSION_FORWARD == permission) {
-        if (SEPARATE_DELIVERY == s->deliveryMethod)
-            return DRM_SUCCESS;
-
-        return DRM_FAILURE;
-    }
-
-    if (FORWARD_LOCK == s->deliveryMethod) /* Forwardlock type have utter rights */
-        return DRM_SUCCESS;
-
-    if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID))
-        return DRM_FAILURE;
-
-    return drm_checkRoAndUpdate(id, permission);
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_getContentLength(int32_t session)
-{
-    T_DRM_Session_Node* s;
-
-    if (session < 0)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    if (DRM_UNKNOWN_DATA_LEN == s->contentLength && s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN &&
-        (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod)) {
-        uint8_t keyValue[DRM_KEY_LEN];
-        uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN];
-        int32_t seekPos, moreBytes;
-
-        if (TRUE == drm_getKey(s->contentID, keyValue)) {
-            seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN;
-            memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN);
-
-            if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) {
-                s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength;
-                s->contentLength -= moreBytes;
-            }
-        }
-    }
-
-    return s->contentLength;
-}
-
-static int32_t drm_readAesData(uint8_t* buf, T_DRM_Session_Node* s, int32_t aesStart, int32_t bufLen)
-{
-    if (NULL == buf || NULL == s || aesStart < 0 || bufLen < 0)
-        return -1;
-
-    if (aesStart - s->contentOffset + bufLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength)
-        return -2;
-
-    if (aesStart < DRM_MAX_MALLOC_LEN) {
-        if (aesStart + bufLen <= DRM_MAX_MALLOC_LEN) { /* read from buffer */
-            memcpy(buf, s->rawContent + aesStart, bufLen);
-            return bufLen;
-        } else { /* first read from buffer and then from InputStream */
-            int32_t point = DRM_MAX_MALLOC_LEN - aesStart;
-            int32_t res;
-
-            if (((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf) {
-                memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN);
-                res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
-                if (0 == res || -1 == res)
-                    return -1;
-
-                res += DRM_ONE_AES_BLOCK_LEN;
-            } else {
-                memcpy(buf, s->rawContent + aesStart, point);
-                res = s->readInputDataFunc(s->inputHandle, buf + point, bufLen - point);
-                if (0 == res || -1 == res)
-                    return -1;
-
-                res += point;
-            }
-
-            memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
-            ((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf = TRUE;
-
-            return res;
-        }
-    } else { /* read from InputStream */
-        int32_t res;
-
-        memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN);
-        res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
-
-        if (0 == res || -1 == res)
-            return -1;
-
-        memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
-
-        return DRM_ONE_AES_BLOCK_LEN + res;
-    }
-}
-
-static int32_t drm_readContentFromBuf(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    int32_t readBytes;
-
-    if (offset > s->contentLength)
-        return DRM_FAILURE;
-
-    if (offset == s->contentLength)
-        return DRM_MEDIA_EOF;
-
-    if (offset + mediaBufLen > s->contentLength)
-        readBytes = s->contentLength - offset;
-    else
-        readBytes = mediaBufLen;
-
-    if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding)
-        memcpy(mediaBuf, s->rawContent + offset, readBytes);
-    else
-        memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes);
-
-    return readBytes;
-}
-
-static int32_t drm_readB64ContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    uint8_t encBuf[DRM_B64_ENC_BLOCK], decBuf[DRM_B64_DEC_BLOCK];
-    int32_t encLen, decLen;
-    int32_t i, j, piece, leftLen, firstBytes;
-    int32_t readBytes = 0;
-
-    if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) {
-        readBytes = ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen - offset;
-        memcpy(mediaBuf, s->rawContent + offset, readBytes);
-    } else {
-        if (s->bEndData)
-            return DRM_MEDIA_EOF;
-
-        firstBytes = offset % DRM_B64_DEC_BLOCK;
-        if (firstBytes > 0) {
-            if (DRM_B64_DEC_BLOCK - firstBytes >= mediaBufLen) {
-                readBytes = mediaBufLen;
-                memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes);
-                return readBytes;
-            }
-
-            readBytes = DRM_B64_DEC_BLOCK - firstBytes;
-            memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes);
-        }
-    }
-
-    leftLen = mediaBufLen - readBytes;
-    encLen = (leftLen - 1) / DRM_B64_DEC_BLOCK * DRM_B64_ENC_BLOCK + DRM_B64_ENC_BLOCK;
-    piece = encLen / DRM_B64_ENC_BLOCK;
-
-    for (i = 0; i < piece; i++) {
-        j = 0;
-        while (j < DRM_B64_ENC_BLOCK) {
-            if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
-                *(encBuf + j) = s->readBuf[s->readBufOff];
-                s->readBufOff++;
-                s->readBufLen--;
-            } else { /* read from InputStream */
-                if (0 == s->readInputDataFunc(s->inputHandle, encBuf + j, 1))
-                    return DRM_MEDIA_DATA_INVALID;
-            }
-
-            if ('\r' == *(encBuf + j) || '\n' == *(encBuf + j))
-                continue; /* skip CRLF */
-
-            if ('-' == *(encBuf + j)) {
-                int32_t k, len;
-
-                /* invalid base64 data, it comes to end boundary */
-                if (0 != j)
-                    return DRM_MEDIA_DATA_INVALID;
-
-                /* check whether it is really the boundary */
-                len = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary);
-                if (NULL == s->readBuf) {
-                    s->readBuf = (uint8_t *)malloc(len);
-                    if (NULL == s->readBuf)
-                        return DRM_FAILURE;
-                }
-
-                s->readBuf[0] = '-';
-                for (k = 0; k < len - 1; k++) {
-                    if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
-                        *(s->readBuf + k + 1) = s->readBuf[s->readBufOff];
-                        s->readBufOff++;
-                        s->readBufLen--;
-                    } else { /* read from InputStream */
-                        if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + 1, 1))
-                            return DRM_MEDIA_DATA_INVALID;
-                    }
-                }
-                if (0 == memcmp(s->readBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, len))
-                    s->bEndData = TRUE;
-                else
-                    return DRM_MEDIA_DATA_INVALID;
-
-                break;
-            }
-            j++;
-        }
-
-        if (TRUE == s->bEndData) { /* it means come to the end of base64 data */
-            if (0 == readBytes)
-                return DRM_MEDIA_EOF;
-
-            break;
-        }
-
-        encLen = DRM_B64_ENC_BLOCK;
-        decLen = DRM_B64_DEC_BLOCK;
-        if (-1 == (decLen = drm_decodeBase64(decBuf, decLen, encBuf, &encLen)))
-            return DRM_MEDIA_DATA_INVALID;
-
-        if (leftLen >= decLen) {
-            memcpy(mediaBuf + readBytes, decBuf, decLen);
-            readBytes += decLen;
-            leftLen -= decLen;
-        } else {
-            if (leftLen > 0) {
-                memcpy(mediaBuf + readBytes, decBuf, leftLen);
-                readBytes += leftLen;
-            }
-            break;
-        }
-    }
-    memcpy(((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData, decBuf, DRM_B64_DEC_BLOCK);
-
-    return readBytes;
-}
-
-static int32_t drm_readBase64Content(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    int32_t readBytes;
-
-    /* when the content length has been well-known */
-    if (s->contentLength >= 0)
-        readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen);
-    else /* else when the content length has not been well-known yet */
-        if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen)
-            if (offset + mediaBufLen <= ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) {
-                readBytes = mediaBufLen;
-                memcpy(mediaBuf, s->rawContent + offset, readBytes);
-            } else
-                readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
-        else
-            readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
-
-    return readBytes;
-}
-
-static int32_t drm_readBinaryContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    int32_t res = 0, readBytes = 0;
-    int32_t leftLen;
-
-    if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN) {
-        readBytes = DRM_MAX_MALLOC_LEN - s->contentOffset - offset;
-        memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes);
-    } else
-        if (s->bEndData)
-            return DRM_MEDIA_EOF;
-
-    leftLen = mediaBufLen - readBytes;
-
-    if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
-        if (leftLen <= s->readBufLen) {
-            memcpy(mediaBuf + readBytes, s->readBuf + s->readBufOff, leftLen);
-            s->readBufOff += leftLen;
-            s->readBufLen -= leftLen;
-            readBytes += leftLen;
-            leftLen = 0;
-        } else {
-            memcpy(mediaBuf + readBytes, s->readBuf + s->readBufOff, s->readBufLen);
-            s->readBufOff += s->readBufLen;
-            leftLen -= s->readBufLen;
-            readBytes += s->readBufLen;
-            s->readBufLen = 0;
-        }
-    }
-
-    if (leftLen > 0) {
-        res = s->readInputDataFunc(s->inputHandle, mediaBuf + readBytes, mediaBufLen - readBytes);
-        if (-1 == res)
-            return DRM_MEDIA_DATA_INVALID;
-    }
-
-    readBytes += res;
-    res = drm_scanEndBoundary(mediaBuf, readBytes, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary);
-    if (-1 == res)
-        return DRM_MEDIA_DATA_INVALID;
-    if (-2 == res) { /* may be the boundary is split */
-        int32_t boundaryLen, len, off, k;
-        char* pTmp = memrchr(mediaBuf, '\r', readBytes);
-
-        if (NULL == pTmp)
-            return DRM_FAILURE; /* conflict */
-
-        boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */
-        if (NULL == s->readBuf) {
-            s->readBuf = (uint8_t *)malloc(boundaryLen);
-            if (NULL == s->readBuf)
-                return DRM_FAILURE;
-        }
-
-        off = readBytes - ((uint8_t *)pTmp - mediaBuf);
-        len = boundaryLen - off;
-        memcpy(s->readBuf, pTmp, off);
-        for (k = 0; k < boundaryLen - off; k++) {
-            if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
-                *(s->readBuf + k + off) = s->readBuf[s->readBufOff];
-                s->readBufOff++;
-                s->readBufLen--;
-            } else { /* read from InputStream */
-                if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + off, 1))
-                    return DRM_MEDIA_DATA_INVALID;
-            }
-        }
-        s->readBufOff = off;
-        s->readBufLen = len;
-
-        if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) {
-            readBytes = (uint8_t *)pTmp - mediaBuf; /* yes, it is the end boundary */
-            s->bEndData = TRUE;
-        }
-    } else {
-        if (res >= 0 && res < readBytes) {
-            readBytes = res;
-            s->bEndData = TRUE;
-        }
-    }
-
-    if (s->bEndData) {
-        if (0 == readBytes)
-            return DRM_MEDIA_EOF;
-    }
-
-    return readBytes;
-}
-
-static int32_t drm_readBinaryContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    int32_t readBytes;
-
-    if (s->contentLength >= 0)
-        readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen);
-    else /* else when the content length has not been well-known yet */
-        if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN)
-            if (s->contentOffset + offset + mediaBufLen <= DRM_MAX_MALLOC_LEN) {
-                readBytes = mediaBufLen;
-                memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes);
-            } else
-                readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
-        else
-            readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
-
-    return readBytes;
-}
-
-static int32_t drm_readAesContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    uint8_t keyValue[DRM_KEY_LEN];
-    uint8_t buf[DRM_TWO_AES_BLOCK_LEN];
-    int32_t readBytes = 0;
-    int32_t bufLen, piece, i, copyBytes, leftBytes;
-    int32_t aesStart, mediaStart, mediaBufOff;
-    AES_KEY key;
-
-    if (FALSE == drm_getKey(s->contentID, keyValue))
-        return DRM_NO_RIGHTS;
-
-    /* when the content length has been well-known */
-    if (s->contentLength > 0) {
-        if (offset > s->contentLength)
-            return DRM_FAILURE;
-
-        if (offset == s->contentLength)
-            return DRM_MEDIA_EOF;
-
-        if (offset + mediaBufLen > s->contentLength)
-            readBytes = s->contentLength - offset;
-        else
-            readBytes = mediaBufLen;
-
-        aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN);
-        piece = (offset + readBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2;
-        mediaStart = offset % DRM_ONE_AES_BLOCK_LEN;
-
-        AES_set_decrypt_key(keyValue, DRM_KEY_LEN * 8, &key);
-        mediaBufOff = 0;
-        leftBytes = readBytes;
-
-        for (i = 0; i < piece - 1; i++) {
-            memcpy(buf, s->rawContent + aesStart + i * DRM_ONE_AES_BLOCK_LEN, DRM_TWO_AES_BLOCK_LEN);
-            bufLen = DRM_TWO_AES_BLOCK_LEN;
-
-            if (drm_aesDecBuffer(buf, &bufLen, &key) < 0)
-                return DRM_MEDIA_DATA_INVALID;
-
-            if (0 != i)
-                mediaStart = 0;
-
-            if (bufLen - mediaStart <= leftBytes)
-                copyBytes = bufLen - mediaStart;
-            else
-                copyBytes = leftBytes;
-
-            memcpy(mediaBuf + mediaBufOff, buf + mediaStart, copyBytes);
-            leftBytes -= copyBytes;
-            mediaBufOff += copyBytes;
-        }
-    } else {
-        int32_t res;
-
-        if (s->bEndData)
-            return DRM_MEDIA_EOF;
-
-        if (((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff) {
-            if (mediaBufLen < ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff)
-                copyBytes = mediaBufLen;
-            else
-                copyBytes = ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff;
-
-            memcpy(mediaBuf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff, copyBytes);
-            ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff += copyBytes;
-            readBytes += copyBytes;
-        }
-
-        leftBytes = mediaBufLen - readBytes;
-        if (0 == leftBytes)
-            return readBytes;
-        if (leftBytes < 0)
-            return DRM_FAILURE;
-
-        offset += readBytes;
-        aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN);
-        piece = (offset + leftBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2;
-        mediaBufOff = readBytes;
-
-        AES_set_decrypt_key(keyValue, DRM_KEY_LEN * 8, &key);
-
-        for (i = 0; i < piece - 1; i++) {
-            if (-1 == (res = drm_readAesData(buf, s, aesStart, DRM_TWO_AES_BLOCK_LEN)))
-                return DRM_MEDIA_DATA_INVALID;
-
-            if (-2 == res)
-                break;
-
-            bufLen = DRM_TWO_AES_BLOCK_LEN;
-            aesStart += DRM_ONE_AES_BLOCK_LEN;
-
-            if (drm_aesDecBuffer(buf, &bufLen, &key) < 0)
-                return DRM_MEDIA_DATA_INVALID;
-
-            drm_discardPaddingByte(buf, &bufLen);
-
-            if (bufLen <= leftBytes)
-                copyBytes = bufLen;
-            else
-                copyBytes = leftBytes;
-
-            memcpy(mediaBuf + mediaBufOff, buf, copyBytes);
-            leftBytes -= copyBytes;
-            mediaBufOff += copyBytes;
-            readBytes += copyBytes;
-        }
-
-        memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData, buf, DRM_ONE_AES_BLOCK_LEN);
-        ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen = bufLen;
-        ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff = copyBytes;
-
-        if (aesStart - s->contentOffset > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN && ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff == ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen) {
-            s->bEndData = TRUE;
-            if (0 == readBytes)
-                return DRM_MEDIA_EOF;
-        }
-    }
-
-    return readBytes;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
-{
-    T_DRM_Session_Node* s;
-    int32_t readBytes;
-
-    if (session < 0 || offset < 0 || NULL == mediaBuf || mediaBufLen <= 0)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    if (0 >= s->getInputDataLengthFunc(s->inputHandle))
-        return DRM_MEDIA_DATA_INVALID;
-
-    switch(s->deliveryMethod) {
-    case FORWARD_LOCK:
-    case COMBINED_DELIVERY:
-        if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding)
-            readBytes = drm_readBase64Content(s, offset, mediaBuf, mediaBufLen);
-        else /* binary */
-            readBytes = drm_readBinaryContent(s, offset, mediaBuf, mediaBufLen);
-        break;
-    case SEPARATE_DELIVERY:
-    case SEPARATE_DELIVERY_FL:
-        readBytes = drm_readAesContent(s, offset, mediaBuf, mediaBufLen);
-        break;
-    default:
-        return DRM_FAILURE;
-    }
-
-    return readBytes;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer)
-{
-    T_DRM_Session_Node* s;
-
-    if (session < 0 || NULL == rightsIssuer)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    if (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod) {
-        strcpy((char *)rightsIssuer, (char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer);
-        return DRM_SUCCESS;
-    }
-
-    return DRM_NOT_SD_METHOD;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights)
-{
-    T_DRM_Session_Node* s;
-    T_DRM_Rights rightsInfo;
-    int32_t roAmount, id;
-
-    if (session < 0 || NULL == rights)
-        return DRM_FAILURE;
-
-    s = getSession(session);
-    if (NULL == s)
-        return DRM_SESSION_NOT_OPENED;
-
-    if (FORWARD_LOCK == s->deliveryMethod) {
-        strcpy((char *)rights->roId, "ForwardLock");
-        rights->displayRights.indicator = DRM_NO_CONSTRAINT;
-        rights->playRights.indicator = DRM_NO_CONSTRAINT;
-        rights->executeRights.indicator = DRM_NO_CONSTRAINT;
-        rights->printRights.indicator = DRM_NO_CONSTRAINT;
-        return DRM_SUCCESS;
-    }
-
-    if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID))
-        return DRM_NO_RIGHTS;
-
-    if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT))
-        return DRM_FAILURE;
-
-    if (roAmount < 0)
-        return DRM_NO_RIGHTS;
-
-    /* some rights has been installed, but now there is no valid rights */
-    if (0 == roAmount) {
-        strcpy((char *)rights->roId, s->contentID);
-        rights->displayRights.indicator = DRM_NO_PERMISSION;
-        rights->playRights.indicator = DRM_NO_PERMISSION;
-        rights->executeRights.indicator = DRM_NO_PERMISSION;
-        rights->printRights.indicator = DRM_NO_PERMISSION;
-        return DRM_SUCCESS;
-    }
-
-    roAmount = 1;
-    memset(&rightsInfo, 0, sizeof(T_DRM_Rights));
-    if (FALSE == drm_writeOrReadInfo(id, &rightsInfo, &roAmount, GET_A_RO))
-        return DRM_FAILURE;
-
-    memset(rights, 0, sizeof(T_DRM_Rights_Info));
-    drm_getLicenseInfo(&rightsInfo, rights);
-    return DRM_SUCCESS;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_closeSession(int32_t session)
-{
-    if (session < 0)
-        return DRM_FAILURE;
-
-    if (NULL == getSession(session))
-        return DRM_SESSION_NOT_OPENED;
-
-    removeSession(session);
-
-    return DRM_SUCCESS;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission)
-{
-    int32_t id;
-
-    if (NULL == contentID)
-        return DRM_FAILURE;
-
-    if (FALSE == drm_readFromUidTxt(contentID, &id, GET_ID))
-        return DRM_FAILURE;
-
-    return drm_checkRoAndUpdate(id, permission);
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo)
-{
-    T_DRM_Rights_Info_Node rightsNode;
-    int32_t maxId, id, roAmount, j;
-    T_DRM_Rights rights;
-
-    memset(&rights, 0, sizeof(T_DRM_Rights));
-
-    if (NULL == ppRightsInfo)
-        return DRM_FAILURE;
-
-    *ppRightsInfo = NULL;
-
-    maxId = drm_getMaxIdFromUidTxt();
-    if (-1 == maxId)
-        return DRM_FAILURE;
-
-    for (id = 1; id <= maxId; id++) {
-        drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT);
-        if (roAmount <= 0) /* this means there is not any rights */
-            continue;
-
-        for (j = 1; j <= roAmount; j++) {
-            if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO))
-                continue;
-
-            memset(&rightsNode, 0, sizeof(T_DRM_Rights_Info_Node));
-
-            drm_getLicenseInfo(&rights, &(rightsNode.roInfo));
-
-            if (FALSE == drm_addRightsNodeToList(ppRightsInfo, &rightsNode))
-                continue;
-        }
-    }
-    return DRM_SUCCESS;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader)
-{
-    T_DRM_Rights_Info_Node *pNode, *pTmp;
-
-    if (NULL == pRightsHeader)
-        return DRM_FAILURE;
-
-    pNode = pRightsHeader;
-
-    while (NULL != pNode) {
-        pTmp = pNode;
-        pNode = pNode->next;
-        free(pTmp);
-    }
-    return DRM_SUCCESS;
-}
-
-/* see svc_drm.h */
-int32_t SVC_drm_deleteRights(uint8_t* roId)
-{
-    int32_t maxId, id, roAmount, j;
-    T_DRM_Rights rights;
-
-    memset(&rights, 0, sizeof(T_DRM_Rights));
-
-    if (NULL == roId)
-        return DRM_FAILURE;
-
-    maxId = drm_getMaxIdFromUidTxt();
-    if (-1 == maxId)
-        return DRM_NO_RIGHTS;
-
-    for (id = 1; id <= maxId; id++) {
-        drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT);
-        if (roAmount <= 0) /* this means there is not any rights */
-            continue;
-
-        for (j = 1; j <= roAmount; j++) {
-            if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO))
-                continue;
-
-            /* here find the RO which will be deleted */
-            if (0 == strcmp((char *)rights.uid, (char *)roId)) {
-                T_DRM_Rights *pAllRights;
-
-                pAllRights = (T_DRM_Rights *)malloc(roAmount * sizeof(T_DRM_Rights));
-                if (NULL == pAllRights)
-                    return DRM_FAILURE;
-
-                drm_writeOrReadInfo(id, pAllRights, &roAmount, GET_ALL_RO);
-                roAmount--;
-                if (0 == roAmount) { /* this means it is the last one rights */
-                    drm_removeIdInfoFile(id); /* delete the id.info file first */
-                    drm_updateUidTxtWhenDelete(id); /* update uid.txt file */
-                    free(pAllRights);
-                    return DRM_SUCCESS;
-                } else /* using the last one rights instead of the deleted one */
-                    memcpy(pAllRights + (j - 1), pAllRights + roAmount, sizeof(T_DRM_Rights));
-
-                /* delete the id.info file first */
-//                drm_removeIdInfoFile(id);
-
-                if (FALSE == drm_writeOrReadInfo(id, pAllRights, &roAmount, SAVE_ALL_RO)) {
-                    free(pAllRights);
-                    return DRM_FAILURE;
-                }
-
-                free(pAllRights);
-                return DRM_SUCCESS;
-            }
-        }
-    }
-
-    return DRM_FAILURE;
-}
diff --git a/media/libdrm/mobile1/src/objmng/drm_decoder.c b/media/libdrm/mobile1/src/objmng/drm_decoder.c
deleted file mode 100644
index 82c7efb..0000000
--- a/media/libdrm/mobile1/src/objmng/drm_decoder.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <objmng/drm_decoder.h>
-
-/* global variables */
-static const uint8_t * base64_alphabet = (const uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-#define SKIP_CRLF(p) while('\r' == *(p) || '\n' == *(p)) \
-                         p++
-
-static int8_t get_alphabet_index(int8_t ch)
-{
-    uint8_t * tmp;
-
-    if ('=' == ch)
-        return 64;
-
-    tmp = (uint8_t *)strchr((const char *)base64_alphabet, ch);
-    if (NULL == tmp)
-        return -1;
-
-    return (int8_t)(tmp - base64_alphabet);
-}
-
-/* See drm_decoder.h */
-int32_t drm_decodeBase64(uint8_t * dest, int32_t destLen, uint8_t * src, int32_t * srcLen)
-{
-    int32_t maxDestSize, i, maxGroup;
-    uint8_t *pDest, *pSrc;
-    int8_t tpChar;
-
-    if (NULL == src || NULL == srcLen || *srcLen <= 0 || destLen < 0)
-        return -1;
-
-    maxDestSize = (*srcLen) * 3/4;
-    if (NULL == dest || 0 == destLen)
-        return maxDestSize;
-
-    if (destLen < maxDestSize)
-        maxDestSize = destLen;
-    maxGroup = maxDestSize/3;
-
-    pDest = dest;   /* start to decode src to dest */
-    pSrc = src;
-    for (i = 0; i < maxGroup && *srcLen - (pSrc - src) >= 4; i++) {
-        SKIP_CRLF(pSrc);
-        if (pSrc - src >= *srcLen)
-            break;
-        tpChar = get_alphabet_index(*pSrc);       /* to first byte */
-        if (-1 == tpChar || 64 == tpChar)
-            return -1;
-        pDest[0] = tpChar << 2;
-        pSrc++;
-        SKIP_CRLF(pSrc);
-        tpChar = get_alphabet_index(*pSrc);
-        if (-1 == tpChar || 64 == tpChar)
-            return -1;
-        pDest[0] |= (tpChar >> 4);
-        pDest[1] = tpChar << 4;                     /* to second byte */
-        pSrc++;
-        SKIP_CRLF(pSrc);
-        tpChar = get_alphabet_index(*pSrc);
-        if (-1 == tpChar)
-            return -1;
-        if (64 == tpChar)           /* end */
-            return pDest - dest + 1;
-        pDest[1] |= (tpChar >> 2);
-        pDest[2] = tpChar << 6;                     /* to third byte */
-        pSrc++;
-        SKIP_CRLF(pSrc);
-        tpChar = get_alphabet_index(*pSrc);
-        if (-1 == tpChar)
-            return -1;
-        if (64 == tpChar)           /* end */
-            return pDest - dest + 2;
-        pDest[2] |= tpChar;
-        pDest += 3;
-        pSrc++;
-    }
-    *srcLen = pSrc - src;
-    return pDest - dest;
-}
diff --git a/media/libdrm/mobile1/src/objmng/drm_file.c b/media/libdrm/mobile1/src/objmng/drm_file.c
deleted file mode 100644
index e6c303e..0000000
--- a/media/libdrm/mobile1/src/objmng/drm_file.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <objmng/drm_file.h>
-
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-
-/**
- * Fails on zaurus?
- #define DEVICE_FILESYSTEM
-*/
-#define DEFAULT_TOTAL_SPACE (4L * 1024L * 1024L) /* 4 Meg. */
-
-#ifndef DEVICE_FILESYSTEM
-/* Store the total space on FS VM can use. */
-static int32_t totalSpace;
-/* how many remain space can VM use. */
-static int32_t availableSize;
-#endif
-
-extern char* getStorageRoot(void);
-
-static char tmpPathBuf1[MAX_FILENAME_LEN];
-static char tmpPathBuf2[MAX_FILENAME_LEN];
-
-static int32_t
-convertFilename(const uint16_t *strData, int32_t strLength, char *buffer);
-
-static int calcDirSize(char *path, int len, uint8_t includeSubdirs);
-
-#ifndef DEVICE_FILESYSTEM
-static void initFsVariables(void);
-#endif
-
-/**
- * Convert a Java string into a nul terminated ascii string to pass to posix
- * @param strData    first character of name
- * @param strLength  number of characters in name
- * @param buffer Buffer to store terminated string in (at least MAXPATHLEN)
- * @return Length of filename in characters (excl. nul), or -1 on failure.
- */
-static int32_t
-convertFilename(const uint16_t *strData, int32_t strLength, char *buffer)
-{
-    int idx;
-
-    if (strLength >= (MAXPATHLEN-1))
-    {
-        Trace("convertFilename '%.*S' too long", strLength, strData);
-        return -1;
-    }
-
-    for (idx = 0; idx < strLength; ++idx)
-        *buffer++ = (char)*strData++;
-
-    *buffer = 0;
-    return strLength;
-}
-
-
-/**
- * Perform a stat() call on the given filename.
- * Helper for getFileLength and exists
- * @param name unicode name
- * @param nameLen number of unicode characters in name
- * @param sbuf stat buffer
- * @return TRUE on success, FALSE on failure
- */
-static int32_t
-getFileStat(const uint16_t *name, int32_t nameLen, struct stat *sbuf)
-{
-    Trace("getFileStat: %.*S", nameLen, name);
-
-    if (convertFilename(name, nameLen, tmpPathBuf1) <= 0)
-    {
-        Trace("getFileStat: bad filename");
-    }
-    else if (stat(tmpPathBuf1, sbuf) != 0)
-    {
-        Trace("getFileStat %s: stat() errno=%d", tmpPathBuf1, errno);
-    }
-    else /* Successful */
-    {
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-#ifndef DEVICE_FILESYSTEM
-/**
- * initial the variables like totalSpace, availableSize...
- */
-static void initFsVariables(void)
-{
-    totalSpace = DEFAULT_TOTAL_SPACE;
-
-    availableSize = totalSpace;
-}
-#endif /* DEVICE_FILESYSTEM */
-
-/**
- * calculate the size of everything inside path pointed directory
- * this function will use path pointed buffer to store some extra info
- * so param len is needed.
- * @param path    the directory path need to calculate
- * @param len   length of the path buffer, not the path string length
- * @param includeSubdirs  also calculate all the subdirs in path holds?
- * @return the calculated size, DRM_FILE_FAILURE on failure.
- */
-static int calcDirSize(char *path, int len, uint8_t includeSubdirs)
-{
-    struct dirent *ent;
-    struct stat stat_buf;
-
-    DIR *dir = NULL;
-    int size = 0;
-    int exists = -1;
-    int dirPathLen = strlen(path);
-
-    /* Ensure space for wildcard */
-    if((dirPathLen + 2) >= MAXPATHLEN || (dirPathLen + 2) >= len)
-    {
-        return DRM_FILE_FAILURE;
-    }
-
-    if(path[dirPathLen - 1] != '/')
-    {
-        path[dirPathLen++] = '/';
-        path[dirPathLen] = '\0';
-    }
-
-    dir = opendir(path);
-    if (dir == NULL)
-    {
-        return DRM_FILE_FAILURE;
-    }
-
-    while ((ent = readdir(dir)) != NULL )
-    {
-        if (strcmp(ent->d_name, ".") == 0 ||
-                strcmp(ent->d_name, "..") == 0)
-        {
-            continue;
-        }
-
-        path[dirPathLen] = '\0';
-        if ((int)(strlen(ent->d_name) + dirPathLen + 1) < len)
-        {
-            strcat(path, ent->d_name);
-        }
-        else
-        {
-            continue;
-        }
-
-        exists = stat(path, &stat_buf);
-        if (exists != -1)
-        {
-            /* exclude the storage occupied by directory itself */
-            if (stat_buf.st_mode & S_IFDIR)
-            {
-                if(includeSubdirs)
-                {
-                    /* calculate the size recursively */
-                    int ret;
-                    ret = calcDirSize(path, len, includeSubdirs);
-                    /* ignore failure in subdirs */
-                    if( DRM_FILE_FAILURE != ret )
-                    {
-                        size += ret;
-                    }
-                }
-            }
-            else
-            {
-                size += stat_buf.st_size;
-            }
-        }
-    }
-
-    closedir(dir);
-    return size;
-}
-
-/* see drm_file.h */
-int32_t DRM_file_startup(void)
-{
-    Trace("DRM_file_startup");
-
-#ifndef DEVICE_FILESYSTEM
-    availableSize = -1;
-
-    initFsVariables();
-#endif
-
-    return DRM_FILE_SUCCESS;    /* Nothing to do */
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_listOpen(const uint16_t *prefix,
-                    int32_t prefixLen,
-                    int32_t* session,
-                    int32_t* iteration)
-{
-    Trace("DRM_file_listOpen: %.*S", prefixLen, prefix);
-
-    if (convertFilename(prefix, prefixLen, tmpPathBuf1) <= 0)
-    {
-        Trace("DRM_file_listOpen: bad filename");
-    }
-    else
-    {
-        DIR *dir;
-
-        /* find the last /, and store the offset to the leaf prefix in
-         * *iteration
-         */
-
-        char *sep = strrchr(tmpPathBuf1, '/');
-        /* Root "/" is a leaf */
-        if (sep == NULL || ((sep != NULL) && (sep == tmpPathBuf1)))
-        {
-            *iteration = prefixLen;
-
-#ifdef TRACE_ON
-            sep = " <empty>"; /* trace will show sep+1 */
-#endif
-        }
-        else
-        {
-            *iteration = sep - tmpPathBuf1 + 1;
-            *sep = 0;
-        }
-
-        dir = opendir(tmpPathBuf1);
-
-        if (dir == NULL)
-        {
-            Trace("DRM_file_listOpen: opendir %s: errno=%d", tmpPathBuf1, errno);
-        }
-        else
-        {
-            Trace("DRM_file_listOpen: dir %s, filter %s", tmpPathBuf1, sep+1);
-            *session = (int32_t)dir;
-            return DRM_FILE_SUCCESS;
-        }
-    }
-
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_listNextEntry(const uint16_t *prefix, int32_t prefixLen,
-                       uint16_t* entry, int32_t entrySize,
-                       int32_t *session, int32_t* iteration)
-{
-    struct dirent *ent;
-
-    /* We stored the offset of the leaf part of the prefix (if any)
-     * in *iteration
-     */
-    const uint16_t* strData   = prefix + *iteration;
-    int32_t   strLength = prefixLen - *iteration;
-
-    /* entrySize is bytes for some reason. Convert to ucs chars */
-    entrySize /= 2;
-
-    /* Now we want to filter for files which start with the (possibly empty)
-     * sequence at strData. We have to return fully-qualified filenames,
-     * which means *iteration characters from prefix, plus the
-     * leaf name.
-     */
-
-    while ( (ent = readdir((DIR *)*session)) != NULL)
-    {
-        int len = strlen(ent->d_name);
-
-        if ( (len + *iteration) > entrySize)
-        {
-            Trace("DRM_file_listNextEntry: %s too long", ent->d_name);
-        }
-        else if (strcmp(ent->d_name, ".") != 0 &&
-                 strcmp(ent->d_name, "..") != 0)
-        {
-            int idx;
-            struct stat sinfo;
-
-            /* check against the filter */
-
-            for (idx = 0; idx < strLength; ++idx)
-            {
-                if (ent->d_name[idx] != strData[idx])
-                    goto next_name;
-            }
-
-            Trace("DRM_file_listNextEntry: matched %s", ent->d_name);
-
-            /* Now generate the fully-qualified name */
-
-            for (idx = 0; idx < *iteration; ++idx)
-                entry[idx] = prefix[idx];
-
-            for (idx = 0; idx < len; ++idx)
-                entry[*iteration + idx] = (unsigned char)ent->d_name[idx];
-
-            /*add "/" at the end of a DIR file entry*/
-            if (getFileStat(entry, idx + *iteration, &sinfo)){
-                if (S_ISDIR(sinfo.st_mode) &&
-                        (idx + 1 + *iteration) < entrySize) {
-                    entry[*iteration + idx] = '/';
-                    ++idx;
-                }
-            }
-            else
-            {
-                Trace("DRM_file_listNextEntry: stat FAILURE on %.*S",
-                      idx + *iteration, entry);
-            }
-            Trace("DRM_file_listNextEntry: got %.*S", idx + *iteration, entry);
-
-            return idx + *iteration;
-        }
-
-    next_name:
-        Trace("DRM_file_listNextEntry: rejected %s", ent->d_name);
-    }
-
-    Trace("DRM_file_listNextEntry: end of list");
-    return 0;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_listClose(int32_t session, int32_t iteration)
-{
-    closedir( (DIR *)session);
-    return DRM_FILE_SUCCESS;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_getFileLength(const uint16_t *name, int32_t nameLen)
-{
-    struct stat sbuf;
-
-    if (getFileStat(name, nameLen, &sbuf))
-    {
-        if (sbuf.st_size >= INT32_MAX)
-        {
-            Trace("DRM_file_getFileLength: file too big");
-        }
-        else /* Successful */
-        {
-            Trace("DRM_file_getFileLength: %.*S -> %d",
-                                         nameLen, name, (int32_t)sbuf.st_size);
-            return (int32_t)sbuf.st_size;
-        }
-    }
-
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_delete(const uint16_t *name, int32_t nameLen)
-{
-    Trace("DRM_file_delete: %.*S", nameLen, name);
-
-    if (convertFilename(name, nameLen, tmpPathBuf1) <= 0)
-    {
-        Trace("DRM_file_delete: bad filename");
-        return DRM_FILE_FAILURE;
-    }
-    else
-    {
-       struct stat sinfo;
-       if (stat(tmpPathBuf1, &sinfo) != 0){
-           Trace("DRM_file_delete: stat failed, errno=%d", errno);
-           return DRM_FILE_FAILURE;
-       }
-#ifndef DEVICE_FILESYSTEM
-       if (S_ISDIR(sinfo.st_mode)){
-            /* it's a dir */
-            if (rmdir(tmpPathBuf1) != 0){
-                Trace("DRM_file_delete: dir remove failed, errno=%d", errno);
-                return DRM_FILE_FAILURE;
-            }
-            else
-            {
-                return DRM_FILE_SUCCESS;
-            }
-        }
-#endif
-        /* it's a file */
-        if (unlink(tmpPathBuf1) != 0)
-        {
-            Trace("DRM_file_delete: file remove failed, errno=%d", errno);
-            return DRM_FILE_FAILURE;
-        }
-        else
-        {
-#ifndef DEVICE_FILESYSTEM
-            availableSize += sinfo.st_size;
-#endif
-            return DRM_FILE_SUCCESS;
-        }
-    }
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_rename(const uint16_t *oldName, int32_t oldNameLen,
-                const uint16_t *newName, int32_t newNameLen)
-{
-    Trace("DRM_file_rename %.*S -> %.*S",
-                                    oldNameLen, oldName, newNameLen, newName);
-    if (DRM_file_exists(newName, newNameLen) != DRM_FILE_FAILURE)
-    {
-        Trace("DRM_file_rename: filename:%s exist",newName);
-        return DRM_FILE_FAILURE;
-    }
-
-    if (convertFilename(oldName, oldNameLen, tmpPathBuf1) <= 0 ||
-        convertFilename(newName, newNameLen, tmpPathBuf2) <= 0)
-    {
-        Trace("DRM_file_rename: bad filename");
-    }
-    else if (rename(tmpPathBuf1, tmpPathBuf2) != 0)
-    {
-         Trace("DRM_file_rename: failed errno=%d", errno);
-    }
-    else /* Success */
-    {
-        return DRM_FILE_SUCCESS;
-    }
-
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_exists(const uint16_t *name, int32_t nameLen)
-{
-    struct stat sbuf;
-
-    Trace("DRM_file_exists: %.*S", nameLen, name);
-
-    /*remove trailing "/" separators, except the first "/" standing for root*/
-    while ((nameLen > 1) && (name[nameLen -1] == '/'))
-       --nameLen;
-
-    if (getFileStat(name, nameLen, &sbuf))
-    {
-        Trace("DRM_file_exists: stat returns mode 0x%x", sbuf.st_mode);
-
-        if (S_ISDIR(sbuf.st_mode))
-            return DRM_FILE_ISDIR;
-        if (S_ISREG(sbuf.st_mode))
-            return DRM_FILE_ISREG;
-    }
-
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_open(const uint16_t *name, int32_t nameLen, int32_t mode,
-                      int32_t* handle)
-{
-    int res;
-
-#if DRM_FILE_MODE_READ != 1 || DRM_FILE_MODE_WRITE != 2
-#error constants changed
-#endif
-
-    /* Convert DRM file modes to posix modes */
-    static const int modes[4] =
-    { 0,
-      O_RDONLY,
-      O_WRONLY | O_CREAT,
-      O_RDWR | O_CREAT
-    };
-
-    Trace("DRM_file_open %.*S mode 0x%x", nameLen, name, mode);
-
-    assert((mode & ~(DRM_FILE_MODE_READ|DRM_FILE_MODE_WRITE)) == 0);
-
-    if (convertFilename(name, nameLen, tmpPathBuf1) <= 0)
-    {
-        Trace("DRM_file_open: bad filename");
-        return DRM_FILE_FAILURE;
-    }
-
-    if ((res = open(tmpPathBuf1, modes[mode], 0777)) == -1)
-    {
-        Trace("DRM_file_open: open failed errno=%d", errno);
-        return DRM_FILE_FAILURE;
-    }
-
-    Trace("DRM_file_open: open '%s; returned %d", tmpPathBuf1, res);
-    *handle = res;
-
-    return DRM_FILE_SUCCESS;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_read(int32_t handle, uint8_t* dst, int32_t length)
-{
-    int n;
-
-    assert(length > 0);
-
-    /* TODO: Make dst a void *? */
-
-    n = read((int)handle, dst, (size_t)length);
-    if (n > 0)
-    {
-        Trace("DRM_file_read handle=%d read %d bytes", handle, n);
-        return n;
-    }
-    else if (n == 0)
-    {
-        Trace("DRM_file_read read EOF: handle=%d", handle);
-        return DRM_FILE_EOF;
-    }
-    else
-    {
-        Trace("DRM_file_read failed handle=%d, errno=%d", handle, errno);
-        return DRM_FILE_FAILURE;
-    }
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_write(int32_t handle, const uint8_t* src, int32_t length)
-{
-    /* TODO: Make dst a void *? */
-    int n;
-#ifndef DEVICE_FILESYSTEM
-    int delta;
-    off_t prevPos;
-    struct stat sbuf;
-    int prevFileSize;
-#endif
-
-    assert(length >= 0);
-
-#ifndef DEVICE_FILESYSTEM
-    if ( -1 == fstat((int)handle, &sbuf) )
-    {
-        Trace("DRM_file_write: fstat error %d", errno);
-        return DRM_FILE_FAILURE;
-    }
-    prevFileSize = (int)(sbuf.st_size);
-    prevPos = lseek( (int)handle, 0, SEEK_CUR);
-    if ( (off_t)-1 == prevPos )
-    {
-        Trace("DRM_file_write: get current pos error %d", errno);
-        return DRM_FILE_FAILURE;
-    }
-    delta = (int)prevPos + length - prevFileSize;
-    if (delta > availableSize)
-    {
-        Trace("DRM_file_write: not enough size!");
-        return DRM_FILE_FAILURE;
-    }
-#endif
-    n = write((int)handle, src, (size_t)length);
-    if (n < 0)
-    {
-        Trace("DRM_file_write failed errno=%d", errno);
-        return DRM_FILE_FAILURE;
-    }
-#ifndef DEVICE_FILESYSTEM
-    delta = prevPos + n - prevFileSize;
-
-    if ( delta > 0 )
-    {
-        availableSize -= delta;
-    }
-#endif
-    Trace("DRM_file_write handle=%d wrote %d/%d bytes", handle, n, length);
-
-    return n;
-}
-
-/* see drm_file.h */
-int32_t DRM_file_close(int32_t handle)
-{
-    if (close((int)handle) == 0)
-    {
-        Trace("DRM_file_close handle=%d success", handle);
-        return DRM_FILE_SUCCESS;
-    }
-
-    Trace("DRM_file_close handle=%d failed", handle);
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_setPosition(int32_t handle, int32_t value)
-{
-#ifndef DEVICE_FILESYSTEM
-    struct stat sbuf;
-#endif
-    off_t newPos;
-
-    if (value < 0)
-    {
-        Trace("DRM_file_setPosition: handle=%d negative value (%d)",
-            handle, value);
-        return DRM_FILE_FAILURE;
-    }
-
-#ifndef DEVICE_FILESYSTEM
-    if ( fstat((int)handle, &sbuf) == -1 )
-    {
-        Trace("DRM_file_setPosition: fstat fail errno=%d", errno);
-        return DRM_FILE_FAILURE;
-    }
-
-    if ( ((off_t)value > sbuf.st_size) &&
-         (availableSize < (value - (int)(sbuf.st_size))) )
-    {
-        Trace("DRM_file_setPosition: not enough space");
-        return DRM_FILE_FAILURE;
-    }
-#endif
-
-    newPos = lseek( (int)handle, (off_t)value, SEEK_SET);
-    if ( newPos == (off_t)-1 )
-    {
-        Trace("DRM_file_setPosition: seek failed: errno=%d", errno);
-    }
-    else
-    {
-#ifndef DEVICE_FILESYSTEM
-        if ( newPos > sbuf.st_size )
-        {
-            availableSize -= (int)(newPos - sbuf.st_size);
-        }
-#endif
-        return DRM_FILE_SUCCESS;
-    }
-
-    return DRM_FILE_FAILURE;
-}
-
-/* see drm_file.h */
-int32_t
-DRM_file_mkdir(const uint16_t* name, int32_t nameChars)
-{
-    Trace("DRM_file_mkdir started!..");
-
-    if (convertFilename(name, nameChars, tmpPathBuf1) <= 0)
-    {
-        Trace("DRM_file_mkdir: bad filename");
-        return DRM_FILE_FAILURE;
-    }
-
-    if (mkdir(tmpPathBuf1,0777) != 0)
-    {
-        Trace("DRM_file_mkdir failed!errno=%d",errno);
-        return DRM_FILE_FAILURE;
-    }
-
-    return DRM_FILE_SUCCESS;
-}
diff --git a/media/libdrm/mobile1/src/objmng/drm_i18n.c b/media/libdrm/mobile1/src/objmng/drm_i18n.c
deleted file mode 100644
index b1118a9..0000000
--- a/media/libdrm/mobile1/src/objmng/drm_i18n.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <objmng/drm_i18n.h>
-
-#define IS_GB2312_HIGH_BYTE(c)  ((c) >= 0xA1 && (c) <= 0xF7)
-#define IS_GB2312_LOW_BYTE(c)   ((c) >= 0xA1 && (c) <= 0xFE)
-#define IS_GBK_HIGH_BYTE(c)     ((c) >= 0x81 && (c) <= 0xFE)
-#define IS_GBK_LOW_BYTE(c)      ((c) >= 0x40 && (c) <= 0xFE && (c) != 0x7F)
-#define IS_BIG5_HIGH_BYTE(c)    ((c) >= 0xA1 && (c) <= 0xF9)
-#define IS_BIG5_LOW_BYTE(c)     (((c) >= 0x40 && (c) <= 0x7E) \
-                                 || ((c) >= 0xA1 && (c) <= 0xFE))
-#define IS_ASCII(c)             ((c) <= 127)
-
-#define INVALID_UNICODE         0xFFFD
-
-#define I18N_LATIN1_SUPPORT
-#define I18N_UTF8_UTF16_SUPPORT
-
-
-/**
- * Simply convert ISO 8859-1 (latin1) to unicode
- */
-static int32_t latin1ToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed);
-
-/**
- * Convert one unicode char to ISO 8859-1 (latin1) byte
- */
-static int32_t wcToLatin1(uint16_t wc, uint8_t * mbs, int32_t bufSize);
-
-/**
- * Convert UTF-8 to unicode
- */
-static int32_t utf8ToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed);
-
-/**
- * Convert one unicode char to UTF-8 bytes
- */
-static int32_t wcToUtf8(uint16_t wc, uint8_t * mbs, int32_t bufSize);
-
-/**
- * Convert UTF-16 BE to unicode
- */
-static int32_t utf16beToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed);
-
-/**
- * Convert one unicode char to UTF-16 BE bytes
- */
-static int32_t wcToUtf16be(uint16_t wc, uint8_t * mbs, int32_t bufSize);
-
-/**
- * Convert UTF-16 LE to unicode
- */
-static int32_t utf16leToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed);
-
-/**
- * Convert one unicode char to UTF-16 LE bytes
- */
-static int32_t wcToUtf16le(uint16_t wc, uint8_t * mbs, int32_t bufSize);
-
-/*
- * see drm_i18n.h
- */
-int32_t DRM_i18n_mbsToWcs(DRM_Charset_t charset,
-        const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed)
-{
-    switch (charset)
-    {
-#ifdef I18N_GB2312_SUPPORT
-        case DRM_CHARSET_GB2312:
-            return gb2312ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-#endif
-#ifdef I18N_GBK_SUPPORT
-        case DRM_CHARSET_GBK:
-            return gbkToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-#endif
-#ifdef I18N_BIG5_SUPPORT
-        case DRM_CHARSET_BIG5:
-            return big5ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-#endif
-#ifdef I18N_LATIN1_SUPPORT
-        case DRM_CHARSET_LATIN1:
-            return latin1ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-#endif
-#ifdef I18N_ISO8859X_SUPPORT
-        case DRM_CHARSET_LATIN2:
-        case DRM_CHARSET_LATIN3:
-        case DRM_CHARSET_LATIN4:
-        case DRM_CHARSET_CYRILLIC:
-        case DRM_CHARSET_ARABIC:
-        case DRM_CHARSET_GREEK:
-        case DRM_CHARSET_HEBREW:
-        case DRM_CHARSET_LATIN5:
-        case DRM_CHARSET_LATIN6:
-        case DRM_CHARSET_THAI:
-        case DRM_CHARSET_LATIN7:
-        case DRM_CHARSET_LATIN8:
-        case DRM_CHARSET_LATIN9:
-        case DRM_CHARSET_LATIN10:
-            return iso8859xToWcs(charset, mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-#endif
-#ifdef I18N_UTF8_UTF16_SUPPORT
-        case DRM_CHARSET_UTF8:
-            return utf8ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-        case DRM_CHARSET_UTF16BE:
-            return utf16beToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-        case DRM_CHARSET_UTF16LE:
-            return utf16leToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed);
-#endif
-        default:
-            return -1;
-    }
-}
-
-/*
- * see drm_i18n.h
- */
-int32_t DRM_i18n_wcsToMbs(DRM_Charset_t charset,
-        const uint16_t *wcs, int32_t wcsLen,
-        uint8_t *mbsBuf, int32_t bufSizeInByte)
-{
-    int32_t (* wcToMbFunc)(uint16_t, uint8_t *, int32_t);
-    int32_t charIndex = 0;
-    int32_t numMultiBytes = 0;
-
-    switch (charset)
-    {
-#ifdef I18N_LATIN1_SUPPORT
-        case DRM_CHARSET_LATIN1:
-            wcToMbFunc = wcToLatin1;
-            break;
-#endif
-#ifdef I18N_UTF8_UTF16_SUPPORT
-        case DRM_CHARSET_UTF8:
-            wcToMbFunc = wcToUtf8;
-            break;
-        case DRM_CHARSET_UTF16BE:
-            wcToMbFunc = wcToUtf16be;
-            break;
-        case DRM_CHARSET_UTF16LE:
-            wcToMbFunc = wcToUtf16le;
-            break;
-#endif
-#ifdef I18N_ISO8859X_SUPPORT
-        case DRM_CHARSET_LATIN2:
-        case DRM_CHARSET_LATIN3:
-        case DRM_CHARSET_LATIN4:
-        case DRM_CHARSET_CYRILLIC:
-        case DRM_CHARSET_ARABIC:
-        case DRM_CHARSET_GREEK:
-        case DRM_CHARSET_HEBREW:
-        case DRM_CHARSET_LATIN5:
-        case DRM_CHARSET_LATIN6:
-        case DRM_CHARSET_THAI:
-        case DRM_CHARSET_LATIN7:
-        case DRM_CHARSET_LATIN8:
-        case DRM_CHARSET_LATIN9:
-        case DRM_CHARSET_LATIN10:
-            return wcsToIso8859x(charset, wcs, wcsLen, mbsBuf, bufSizeInByte);
-#endif
-        default:
-            return -1;
-    }
-
-    if (mbsBuf) {
-        while (numMultiBytes < bufSizeInByte && charIndex < wcsLen) {
-            /* TODO: handle surrogate pair values here */
-            int32_t mbLen = wcToMbFunc(wcs[charIndex],
-                    &mbsBuf[numMultiBytes], bufSizeInByte - numMultiBytes);
-
-            if (numMultiBytes + mbLen > bufSizeInByte) {
-                /* Insufficient buffer. Don't update numMultiBytes */
-                break;
-            }
-            charIndex++;
-            numMultiBytes += mbLen;
-        }
-    } else {
-        while (charIndex < wcsLen) {
-            /* TODO: handle surrogate pair values here */
-            numMultiBytes += wcToMbFunc(wcs[charIndex], NULL, 0);
-            charIndex++;
-        }
-    }
-
-    return numMultiBytes;
-}
-
-
-#ifdef I18N_LATIN1_SUPPORT
-
-int32_t latin1ToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed)
-{
-    int32_t charsToConvert;
-    int32_t len;
-
-    if (wcsBuf == NULL) {
-        return mbsLen;
-    }
-
-    len = charsToConvert = mbsLen > bufSizeInWideChar ? bufSizeInWideChar : mbsLen;
-    if (len < 0)
-        return 0;
-    while (len--) {
-        *wcsBuf++ = *mbs++;
-    }
-
-    if (bytesConsumed)
-        *bytesConsumed = charsToConvert;
-
-    return charsToConvert;
-}
-
-int32_t wcToLatin1(uint16_t wc, uint8_t * mbs, int32_t bufSize)
-{
-    uint8_t ch;
-
-    if (wc < 0x100) {
-        ch = (uint8_t)(wc & 0xff);
-    } else {
-        ch = '?';
-    }
-    if (mbs && bufSize > 0)
-        *mbs = ch;
-    return 1;
-}
-
-#endif /* I18N_LATIN1_SUPPORT */
-
-#ifdef I18N_UTF8_UTF16_SUPPORT
-
-int32_t utf8ToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed)
-{
-    int32_t charsConverted = 0;
-    int32_t i = 0;
-    int32_t wideChar;
-
-    if (wcsBuf == NULL) {
-        /* No conversion but we're still going to calculate bytesConsumed */
-        bufSizeInWideChar = mbsLen * 2;
-    }
-
-    while((i < mbsLen) && (charsConverted < bufSizeInWideChar)) {
-        uint8_t ch = mbs[i];
-        uint8_t ch2, ch3, ch4;
-
-        wideChar = -1;
-
-        if(IS_ASCII(ch)) {
-            wideChar = ch;
-            i++;
-        } else if ((ch & 0xc0) == 0xc0) {
-            int utfStart = i;
-            if ((ch & 0xe0) == 0xc0) {
-                /* 2 byte sequence */
-                if (i + 1 < mbsLen && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80) {
-                    wideChar = (uint16_t)(((ch & 0x1F) << 6) | (ch2 & 0x3F));
-                    i += 2;
-                } else {
-                    /* skip incomplete sequence */
-                    i++;
-                }
-            } else if ((ch & 0xf0) == 0xe0) {
-                /* 3 byte sequence */
-                if (i + 2 < mbsLen
-                        && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80
-                        && ((ch3 = mbs[i + 2]) & 0xc0) == 0x80) {
-                    wideChar = (uint16_t)(((ch & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F));
-                    i += 3;
-                } else {
-                    /* skip incomplete sequence (up to 2 bytes) */
-                    i++;
-                    if (i < mbsLen && (mbs[i] & 0xc0) == 0x80)
-                        i++;
-                }
-            } else if ((ch & 0xf8) == 0xf0) {
-                /* 4 byte sequence */
-                if (i + 3 < mbsLen
-                        && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80
-                        && ((ch3 = mbs[i + 2]) & 0xc0) == 0x80
-                        && ((ch4 = mbs[i + 3]) & 0xc0) == 0x80) {
-                    /* FIXME: we do NOT support U+10000 - U+10FFFF for now.
-                     *        leave it as 0xFFFD. */
-                    wideChar = INVALID_UNICODE;
-                    i += 4;
-                } else {
-                    /* skip incomplete sequence (up to 3 bytes) */
-                    i++;
-                    if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) {
-                        i++;
-                        if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) {
-                            i++;
-                        }
-                    }
-                }
-            } else {
-                /* invalid */
-                i++;
-            }
-            if (i >= mbsLen && wideChar == -1) {
-                /* Possible incomplete UTF-8 sequence at the end of mbs.
-                 * Leave it to the caller.
-                 */
-                i = utfStart;
-                break;
-            }
-        } else {
-            /* invalid */
-            i++;
-        }
-        if(wcsBuf) {
-            if (wideChar == -1)
-                wideChar = INVALID_UNICODE;
-            wcsBuf[charsConverted] = (uint16_t)wideChar;
-        }
-        charsConverted++;
-    }
-
-    if (bytesConsumed)
-        *bytesConsumed = i;
-
-    return charsConverted;
-}
-
-int32_t wcToUtf8(uint16_t wc, uint8_t * mbs, int32_t bufSize)
-{
-    if (wc <= 0x7f) {
-        if (mbs && (bufSize >= 1)) {
-            *mbs = (uint8_t)wc;
-        }
-        return 1;
-    } else if (wc <= 0x7ff) {
-        if (mbs && (bufSize >= 2)) {
-            *mbs++ = (uint8_t)((wc >> 6) | 0xc0);
-            *mbs = (uint8_t)((wc & 0x3f) | 0x80);
-        }
-        return 2;
-    } else {
-        if (mbs && (bufSize >= 3)) {
-            *mbs++ = (uint8_t)((wc >> 12) | 0xe0);
-            *mbs++ = (uint8_t)(((wc >> 6) & 0x3f)| 0x80);
-            *mbs = (uint8_t)((wc & 0x3f) | 0x80);
-        }
-        return 3;
-    }
-}
-
-int32_t utf16beToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed)
-{
-    int32_t charsToConvert;
-    int32_t len;
-
-    if (wcsBuf == NULL) {
-        return mbsLen / 2;
-    }
-
-    len = charsToConvert = (mbsLen / 2) > bufSizeInWideChar ? bufSizeInWideChar : (mbsLen / 2);
-    while (len--) {
-        /* TODO: handle surrogate pair values */
-        *wcsBuf++ = (uint16_t)((*mbs << 8) | *(mbs + 1));
-        mbs += 2;
-    }
-
-    if (bytesConsumed)
-        *bytesConsumed = charsToConvert * 2;
-
-    return charsToConvert;
-}
-
-int32_t wcToUtf16be(uint16_t wc, uint8_t * mbs, int32_t bufSize)
-{
-    if (mbs && bufSize >= 2) {
-        /* TODO: handle surrogate pair values */
-        *mbs = (uint8_t)(wc >> 8);
-        *(mbs + 1) = (uint8_t)(wc & 0xff);
-    }
-    return 2;
-}
-
-int32_t utf16leToWcs(const uint8_t *mbs, int32_t mbsLen,
-        uint16_t *wcsBuf, int32_t bufSizeInWideChar,
-        int32_t *bytesConsumed)
-{
-    int32_t charsToConvert;
-    int32_t len;
-
-    if (wcsBuf == NULL) {
-        return mbsLen / 2;
-    }
-
-    len = charsToConvert = (mbsLen / 2) > bufSizeInWideChar ? bufSizeInWideChar : (mbsLen / 2);
-    while (len--) {
-        /* TODO: handle surrogate pair values */
-        *wcsBuf++ = (uint16_t)(*mbs | (*(mbs + 1) << 8));
-        mbs += 2;
-    }
-
-    if (bytesConsumed)
-        *bytesConsumed = charsToConvert * 2;
-
-    return charsToConvert;
-}
-
-int32_t wcToUtf16le(uint16_t wc, uint8_t * mbs, int32_t bufSize)
-{
-    if (mbs && bufSize >= 2) {
-        /* TODO: handle surrogate pair values */
-        *mbs = (uint8_t)(wc & 0xff);
-        *(mbs + 1) = (uint8_t)(wc >> 8);
-    }
-    return 2;
-}
-
-#endif /* I18N_UTF8_UTF16_SUPPORT */
-
diff --git a/media/libdrm/mobile1/src/objmng/drm_rights_manager.c b/media/libdrm/mobile1/src/objmng/drm_rights_manager.c
deleted file mode 100644
index df22327..0000000
--- a/media/libdrm/mobile1/src/objmng/drm_rights_manager.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <drm_rights_manager.h>
-#include <drm_inner.h>
-#include <drm_file.h>
-#include <drm_i18n.h>
-
-static int32_t drm_getString(uint8_t* string, int32_t len, int32_t handle)
-{
-    int32_t i;
-
-    for (i = 0; i < len; i++) {
-        if (DRM_FILE_FAILURE == DRM_file_read(handle, &string[i], 1))
-            return FALSE;
-        if (string[i] == '\n') {
-            string[i + 1] = '\0';
-            break;
-        }
-    }
-    return TRUE;
-}
-
-static int32_t drm_putString(uint8_t* string, int32_t handle)
-{
-    int32_t i = 0;
-
-    for (i = 0;; i++) {
-        if (string[i] == '\0')
-            break;
-        if (DRM_FILE_FAILURE == DRM_file_write(handle, &string[i], 1))
-            return FALSE;
-    }
-    return TRUE;
-}
-
-static int32_t drm_writeToUidTxt(uint8_t* Uid, int32_t* id)
-{
-    int32_t length;
-    int32_t i;
-    uint8_t idStr[8];
-    int32_t idMax;
-    uint8_t(*uidStr)[256];
-    uint16_t nameUcs2[MAX_FILENAME_LEN];
-    int32_t nameLen;
-    int32_t bytesConsumed;
-    int32_t handle;
-    int32_t fileRes;
-
-    if (*id < 1)
-        return FALSE;
-
-    /* convert in ucs2 */
-    nameLen = strlen(DRM_UID_FILE_PATH);
-    nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8,
-                        (uint8_t *)DRM_UID_FILE_PATH,
-                        nameLen,
-                        nameUcs2,
-                        MAX_FILENAME_LEN,
-                        &bytesConsumed);
-    fileRes = DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_READ,
-                        &handle);
-    if (DRM_FILE_SUCCESS != fileRes) {
-        DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_WRITE,
-                        &handle);
-        DRM_file_write(handle, (uint8_t *)"0\n", 2);
-        DRM_file_close(handle);
-        DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_READ,
-                        &handle);
-    }
-
-    if (!drm_getString(idStr, 8, handle)) {
-        DRM_file_close(handle);
-        return FALSE;
-    }
-    idMax = atoi((char *)idStr);
-
-    if (idMax < *id)
-        uidStr = malloc((idMax + 1) * 256);
-    else
-        uidStr = malloc(idMax * 256);
-
-    for (i = 0; i < idMax; i++) {
-        if (!drm_getString(uidStr[i], 256, handle)) {
-            DRM_file_close(handle);
-            free(uidStr);
-            return FALSE;
-        }
-    }
-    length = strlen((char *)Uid);
-    strcpy((char *)uidStr[*id - 1], (char *)Uid);
-    uidStr[*id - 1][length] = '\n';
-    uidStr[*id - 1][length + 1] = '\0';
-    if (idMax < (*id))
-        idMax++;
-    DRM_file_close(handle);
-
-    DRM_file_open(nameUcs2,
-                    nameLen,
-                    DRM_FILE_MODE_WRITE,
-                    &handle);
-    sprintf((char *)idStr, "%d", idMax);
-
-    if (!drm_putString(idStr, handle)) {
-        DRM_file_close(handle);
-        free(uidStr);
-        return FALSE;
-    }
-    if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t *)"\n", 1)) {
-        DRM_file_close(handle);
-        free(uidStr);
-        return FALSE;
-    }
-    for (i = 0; i < idMax; i++) {
-        if (!drm_putString(uidStr[i], handle)) {
-            DRM_file_close(handle);
-            free(uidStr);
-            return FALSE;
-        }
-    }
-    if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t *)"\n", 1)) {
-        DRM_file_close(handle);
-        free(uidStr);
-        return FALSE;
-    }
-    DRM_file_close(handle);
-    free(uidStr);
-    return TRUE;
-}
-
-/* See objmng_files.h */
-int32_t drm_readFromUidTxt(uint8_t* Uid, int32_t* id, int32_t option)
-{
-    int32_t i;
-    uint8_t p[256] = { 0 };
-    uint8_t idStr[8];
-    int32_t idMax = 0;
-    uint16_t nameUcs2[MAX_FILENAME_LEN];
-    int32_t nameLen = 0;
-    int32_t bytesConsumed;
-    int32_t handle;
-    int32_t fileRes;
-
-    if (NULL == id || NULL == Uid)
-        return FALSE;
-
-    DRM_file_startup();
-
-    /* convert in ucs2 */
-    nameLen = strlen(DRM_UID_FILE_PATH);
-    nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8,
-                        (uint8_t *)DRM_UID_FILE_PATH,
-                        nameLen,
-                        nameUcs2,
-                        MAX_FILENAME_LEN,
-                        &bytesConsumed);
-    fileRes = DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_READ,
-                        &handle);
-    if (DRM_FILE_SUCCESS != fileRes) {
-        DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_WRITE,
-                        &handle);
-        DRM_file_write(handle, (uint8_t *)"0\n", 2);
-        DRM_file_close(handle);
-        DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_READ,
-                        &handle);
-    }
-
-    if (!drm_getString(idStr, 8, handle)) {
-        DRM_file_close(handle);
-        return FALSE;
-    }
-    idMax = atoi((char *)idStr);
-
-    if (option == GET_UID) {
-        if (*id < 1 || *id > idMax) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-        for (i = 1; i <= *id; i++) {
-            if (!drm_getString(Uid, 256, handle)) {
-                DRM_file_close(handle);
-                return FALSE;
-            }
-        }
-        DRM_file_close(handle);
-        return TRUE;
-    }
-    if (option == GET_ID) {
-        *id = -1;
-        for (i = 1; i <= idMax; i++) {
-            if (!drm_getString(p, 256, handle)) {
-                DRM_file_close(handle);
-                return FALSE;
-            }
-            if (strstr((char *)p, (char *)Uid) != NULL
-                && strlen((char *)p) == strlen((char *)Uid) + 1) {
-                *id = i;
-                DRM_file_close(handle);
-                return TRUE;
-            }
-            if ((*id == -1) && (strlen((char *)p) < 3))
-                *id = i;
-        }
-        if (*id != -1) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-        *id = idMax + 1;
-        DRM_file_close(handle);
-        return FALSE;
-    }
-    DRM_file_close(handle);
-    return FALSE;
-}
-
-static int32_t drm_acquireId(uint8_t* uid, int32_t* id)
-{
-    if (TRUE == drm_readFromUidTxt(uid, id, GET_ID))
-        return TRUE;
-
-    drm_writeToUidTxt(uid, id);
-
-    return FALSE; /* The Uid is not exit, then return FALSE indicate it */
-}
-
-int32_t drm_writeOrReadInfo(int32_t id, T_DRM_Rights* Ro, int32_t* RoAmount, int32_t option)
-{
-    uint8_t fullname[MAX_FILENAME_LEN] = {0};
-    int32_t tmpRoAmount;
-    uint16_t nameUcs2[MAX_FILENAME_LEN];
-    int32_t nameLen = 0;
-    int32_t bytesConsumed;
-    int32_t handle;
-    int32_t fileRes;
-
-    sprintf((char *)fullname, ANDROID_DRM_CORE_PATH"%d"EXTENSION_NAME_INFO, id);
-
-    /* convert in ucs2 */
-    nameLen = strlen((char *)fullname);
-    nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8,
-                        fullname,
-                        nameLen,
-                        nameUcs2,
-                        MAX_FILENAME_LEN,
-                        &bytesConsumed);
-    fileRes = DRM_file_open(nameUcs2,
-                            nameLen,
-                            DRM_FILE_MODE_READ,
-                            &handle);
-    if (DRM_FILE_SUCCESS != fileRes) {
-        if (GET_ALL_RO == option || GET_A_RO == option)
-            return FALSE;
-
-        if (GET_ROAMOUNT == option) {
-            *RoAmount = -1;
-            return TRUE;
-        }
-    }
-
-    DRM_file_close(handle);
-    DRM_file_open(nameUcs2,
-                nameLen,
-                DRM_FILE_MODE_READ | DRM_FILE_MODE_WRITE,
-                &handle);
-
-    switch(option) {
-    case GET_ROAMOUNT:
-        if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)RoAmount, sizeof(int32_t))) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-        break;
-    case GET_ALL_RO:
-        DRM_file_setPosition(handle, sizeof(int32_t));
-
-        if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)Ro, (*RoAmount) * sizeof(T_DRM_Rights))) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-        break;
-    case SAVE_ALL_RO:
-        if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*)RoAmount, sizeof(int32_t))) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-
-        if (NULL != Ro && *RoAmount >= 1) {
-            if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*) Ro, (*RoAmount) * sizeof(T_DRM_Rights))) {
-                DRM_file_close(handle);
-                return FALSE;
-            }
-        }
-        break;
-    case GET_A_RO:
-        DRM_file_setPosition(handle, sizeof(int32_t) + (*RoAmount - 1) * sizeof(T_DRM_Rights));
-
-        if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)Ro, sizeof(T_DRM_Rights))) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-        break;
-    case SAVE_A_RO:
-        DRM_file_setPosition(handle, sizeof(int32_t) + (*RoAmount - 1) * sizeof(T_DRM_Rights));
-
-        if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*)Ro, sizeof(T_DRM_Rights))) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-
-        DRM_file_setPosition(handle, 0);
-        if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)&tmpRoAmount, sizeof(int32_t))) {
-            DRM_file_close(handle);
-            return FALSE;
-        }
-        if (tmpRoAmount < *RoAmount) {
-            DRM_file_setPosition(handle, 0);
-            DRM_file_write(handle, (uint8_t*)RoAmount, sizeof(int32_t));
-        }
-        break;
-    default:
-        DRM_file_close(handle);
-        return FALSE;
-    }
-
-    DRM_file_close(handle);
-    return TRUE;
-}
-
-int32_t drm_appendRightsInfo(T_DRM_Rights* rights)
-{
-    int32_t id;
-    int32_t roAmount;
-
-    if (NULL == rights)
-        return FALSE;
-
-    drm_acquireId(rights->uid, &id);
-
-    if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT))
-        return FALSE;
-
-    if (-1 == roAmount)
-        roAmount = 0;
-
-    /* The RO amount increase */
-    roAmount++;
-
-    /* Save the rights information */
-    if (FALSE == drm_writeOrReadInfo(id, rights, &roAmount, SAVE_A_RO))
-        return FALSE;
-
-    return TRUE;
-}
-
-int32_t drm_getMaxIdFromUidTxt()
-{
-    uint8_t idStr[8];
-    int32_t idMax = 0;
-    uint16_t nameUcs2[MAX_FILENAME_LEN] = {0};
-    int32_t nameLen = 0;
-    int32_t bytesConsumed;
-    int32_t handle;
-    int32_t fileRes;
-
-    /* convert in ucs2 */
-    nameLen = strlen(DRM_UID_FILE_PATH);
-    nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8,
-                        (uint8_t *)DRM_UID_FILE_PATH,
-                        nameLen,
-                        nameUcs2,
-                        MAX_FILENAME_LEN,
-                        &bytesConsumed);
-    fileRes = DRM_file_open(nameUcs2,
-                        nameLen,
-                        DRM_FILE_MODE_READ,
-                        &handle);
-
-    /* this means the uid.txt file is not exist, so there is not any DRM object */
-    if (DRM_FILE_SUCCESS != fileRes)
-        return 0;
-
-    if (!drm_getString(idStr, 8, handle)) {
-        DRM_file_close(handle);
-        return -1;
-    }
-    DRM_file_close(handle);
-
-    idMax = atoi((char *)idStr);
-    return idMax;
-}
-
-int32_t drm_removeIdInfoFile(int32_t id)
-{
-    uint8_t filename[MAX_FILENAME_LEN] = {0};
-    uint16_t nameUcs2[MAX_FILENAME_LEN];
-    int32_t nameLen = 0;
-    int32_t bytesConsumed;
-
-    if (id <= 0)
-        return FALSE;
-
-    sprintf((char *)filename, ANDROID_DRM_CORE_PATH"%d"EXTENSION_NAME_INFO, id);
-
-    /* convert in ucs2 */
-    nameLen = strlen((char *)filename);
-    nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8,
-                        filename,
-                        nameLen,
-                        nameUcs2,
-                        MAX_FILENAME_LEN,
-                        &bytesConsumed);
-    if (DRM_FILE_SUCCESS != DRM_file_delete(nameUcs2, nameLen))
-        return FALSE;
-
-    return TRUE;
-}
-
-int32_t drm_updateUidTxtWhenDelete(int32_t id)
-{
-    uint16_t nameUcs2[MAX_FILENAME_LEN];
-    int32_t nameLen = 0;
-    int32_t bytesConsumed;
-    int32_t handle;
-    int32_t fileRes;
-    int32_t bufferLen;
-    uint8_t *buffer;
-    uint8_t idStr[8];
-    int32_t idMax;
-
-    if (id <= 0)
-        return FALSE;
-
-    nameLen = strlen(DRM_UID_FILE_PATH);
-    nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8,
-                        (uint8_t *)DRM_UID_FILE_PATH,
-                        nameLen,
-                        nameUcs2,
-                        MAX_FILENAME_LEN,
-                        &bytesConsumed);
-    bufferLen = DRM_file_getFileLength(nameUcs2, nameLen);
-    if (bufferLen <= 0)
-        return FALSE;
-
-    buffer = (uint8_t *)malloc(bufferLen);
-    if (NULL == buffer)
-        return FALSE;
-
-    fileRes = DRM_file_open(nameUcs2,
-                            nameLen,
-                            DRM_FILE_MODE_READ,
-                            &handle);
-    if (DRM_FILE_SUCCESS != fileRes) {
-        free(buffer);
-        return FALSE;
-    }
-
-    drm_getString(idStr, 8, handle);
-    idMax = atoi((char *)idStr);
-
-    bufferLen -= strlen((char *)idStr);
-    fileRes = DRM_file_read(handle, buffer, bufferLen);
-    buffer[bufferLen] = '\0';
-    DRM_file_close(handle);
-
-    /* handle this buffer */
-    {
-        uint8_t *pStart, *pEnd;
-        int32_t i, movLen;
-
-        pStart = buffer;
-        pEnd = pStart;
-        for (i = 0; i < id; i++) {
-            if (pEnd != pStart)
-                pStart = ++pEnd;
-            while ('\n' != *pEnd)
-                pEnd++;
-            if (pStart == pEnd)
-                pStart--;
-        }
-        movLen = bufferLen - (pEnd - buffer);
-        memmove(pStart, pEnd, movLen);
-        bufferLen -= (pEnd - pStart);
-    }
-
-    if (DRM_FILE_SUCCESS != DRM_file_delete(nameUcs2, nameLen)) {
-        free(buffer);
-        return FALSE;
-    }
-
-    fileRes = DRM_file_open(nameUcs2,
-        nameLen,
-        DRM_FILE_MODE_WRITE,
-        &handle);
-    if (DRM_FILE_SUCCESS != fileRes) {
-        free(buffer);
-        return FALSE;
-    }
-    sprintf((char *)idStr, "%d", idMax);
-    drm_putString(idStr, handle);
-    DRM_file_write(handle, (uint8_t*)"\n", 1);
-    DRM_file_write(handle, buffer, bufferLen);
-    free(buffer);
-    DRM_file_close(handle);
-    return TRUE;
-}
-
-int32_t drm_getKey(uint8_t* uid, uint8_t* KeyValue)
-{
-    T_DRM_Rights ro;
-    int32_t id, roAmount;
-
-    if (NULL == uid || NULL == KeyValue)
-        return FALSE;
-
-    if (FALSE == drm_readFromUidTxt(uid, &id, GET_ID))
-        return FALSE;
-
-    if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT))
-        return FALSE;
-
-    if (roAmount <= 0)
-        return FALSE;
-
-    memset(&ro, 0, sizeof(T_DRM_Rights));
-    roAmount = 1;
-    if (FALSE == drm_writeOrReadInfo(id, &ro, &roAmount, GET_A_RO))
-        return FALSE;
-
-    memcpy(KeyValue, ro.KeyValue, DRM_KEY_LEN);
-    return TRUE;
-}
-
-void drm_discardPaddingByte(uint8_t *decryptedBuf, int32_t *decryptedBufLen)
-{
-    int32_t tmpLen = *decryptedBufLen;
-    int32_t i;
-
-    if (NULL == decryptedBuf || *decryptedBufLen < 0)
-        return;
-
-    /* Check whether the last several bytes are padding or not */
-    for (i = 1; i < decryptedBuf[tmpLen - 1]; i++) {
-        if (decryptedBuf[tmpLen - 1 - i] != decryptedBuf[tmpLen - 1])
-            break; /* Not the padding bytes */
-    }
-    if (i == decryptedBuf[tmpLen - 1]) /* They are padding bytes */
-        *decryptedBufLen = tmpLen - i;
-    return;
-}
-
-int32_t drm_aesDecBuffer(uint8_t * Buffer, int32_t * BufferLen, AES_KEY *key)
-{
-    uint8_t dbuf[3 * DRM_ONE_AES_BLOCK_LEN], buf[DRM_ONE_AES_BLOCK_LEN];
-    uint64_t i, len, wlen = DRM_ONE_AES_BLOCK_LEN, curLen, restLen;
-    uint8_t *pTarget, *pTargetHead;
-
-    pTargetHead = Buffer;
-    pTarget = Buffer;
-    curLen = 0;
-    restLen = *BufferLen;
-
-    if (restLen > 2 * DRM_ONE_AES_BLOCK_LEN) {
-        len = 2 * DRM_ONE_AES_BLOCK_LEN;
-    } else {
-        len = restLen;
-    }
-    memcpy(dbuf, Buffer, (size_t)len);
-    restLen -= len;
-    Buffer += len;
-
-    if (len < 2 * DRM_ONE_AES_BLOCK_LEN) { /* The original file is less than one block in length */
-        len -= DRM_ONE_AES_BLOCK_LEN;
-        /* Decrypt from position len to position len + DRM_ONE_AES_BLOCK_LEN */
-        AES_decrypt((dbuf + len), (dbuf + len), key);
-
-        /* Undo the CBC chaining */
-        for (i = 0; i < len; ++i)
-            dbuf[i] ^= dbuf[i + DRM_ONE_AES_BLOCK_LEN];
-
-        /* Output the decrypted bytes */
-        memcpy(pTarget, dbuf, (size_t)len);
-        pTarget += len;
-    } else {
-        uint8_t *b1 = dbuf, *b2 = b1 + DRM_ONE_AES_BLOCK_LEN, *b3 = b2 + DRM_ONE_AES_BLOCK_LEN, *bt;
-
-        for (;;) { /* While some ciphertext remains, prepare to decrypt block b2 */
-            /* Read in the next block to see if ciphertext stealing is needed */
-            b3 = Buffer;
-            if (restLen > DRM_ONE_AES_BLOCK_LEN) {
-                len = DRM_ONE_AES_BLOCK_LEN;
-            } else {
-                len = restLen;
-            }
-            restLen -= len;
-            Buffer += len;
-
-            /* Decrypt the b2 block */
-            AES_decrypt((uint8_t *)b2, buf, key);
-
-            if (len == 0 || len == DRM_ONE_AES_BLOCK_LEN) { /* No ciphertext stealing */
-                /* Unchain CBC using the previous ciphertext block in b1 */
-                for (i = 0; i < DRM_ONE_AES_BLOCK_LEN; ++i)
-                    buf[i] ^= b1[i];
-            } else { /* Partial last block - use ciphertext stealing */
-                wlen = len;
-                /* Produce last 'len' bytes of plaintext by xoring with */
-                /* The lowest 'len' bytes of next block b3 - C[N-1] */
-                for (i = 0; i < len; ++i)
-                    buf[i] ^= b3[i];
-
-                /* Reconstruct the C[N-1] block in b3 by adding in the */
-                /* Last (DRM_ONE_AES_BLOCK_LEN - len) bytes of C[N-2] in b2 */
-                for (i = len; i < DRM_ONE_AES_BLOCK_LEN; ++i)
-                    b3[i] = buf[i];
-
-                /* Decrypt the C[N-1] block in b3 */
-                AES_decrypt((uint8_t *)b3, (uint8_t *)b3, key);
-
-                /* Produce the last but one plaintext block by xoring with */
-                /* The last but two ciphertext block */
-                for (i = 0; i < DRM_ONE_AES_BLOCK_LEN; ++i)
-                    b3[i] ^= b1[i];
-
-                /* Write decrypted plaintext blocks */
-                memcpy(pTarget, b3, DRM_ONE_AES_BLOCK_LEN);
-                pTarget += DRM_ONE_AES_BLOCK_LEN;
-            }
-
-            /* Write the decrypted plaintext block */
-            memcpy(pTarget, buf, (size_t)wlen);
-            pTarget += wlen;
-
-            if (len != DRM_ONE_AES_BLOCK_LEN) {
-                *BufferLen = pTarget - pTargetHead;
-                return 0;
-            }
-
-            /* Advance the buffer pointers */
-            bt = b1, b1 = b2, b2 = b3, b3 = bt;
-        }
-    }
-    return 0;
-}
-
-int32_t drm_updateDcfDataLen(uint8_t* pDcfLastData, uint8_t* keyValue, int32_t* moreBytes)
-{
-    AES_KEY key;
-    int32_t len = DRM_TWO_AES_BLOCK_LEN;
-
-    if (NULL == pDcfLastData || NULL == keyValue)
-        return FALSE;
-
-    AES_set_decrypt_key(keyValue, DRM_KEY_LEN * 8, &key);
-
-    if (drm_aesDecBuffer(pDcfLastData, &len, &key) < 0)
-        return FALSE;
-
-    drm_discardPaddingByte(pDcfLastData, &len);
-
-    *moreBytes = DRM_TWO_AES_BLOCK_LEN - len;
-
-    return TRUE;
-}
diff --git a/media/libdrm/mobile1/src/objmng/drm_time.c b/media/libdrm/mobile1/src/objmng/drm_time.c
deleted file mode 100644
index fceb4952..0000000
--- a/media/libdrm/mobile1/src/objmng/drm_time.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file
- * DRM 1.0 Reference Port: linux implementation of drm_time.c.
- */
-
-#include <objmng/drm_time.h>
-#include <unistd.h>
-
-/* See drm_time.h */
-uint32_t DRM_time_getElapsedSecondsFrom1970(void)
-{
-    return time(NULL);
-}
-
-/* See drm_time.h */
-void DRM_time_sleep(uint32_t ms)
-{
-    usleep(ms * 1000);
-}
-
-/* See drm_time.h */
-void DRM_time_getSysTime(T_DB_TIME_SysTime *time_ptr)
-{
-    time_t t;
-    struct tm *tm_t;
-
-    time(&t);
-    tm_t = gmtime(&t);
-
-    time_ptr->year = tm_t->tm_year + 1900;
-    time_ptr->month = tm_t->tm_mon + 1;
-    time_ptr->day = tm_t->tm_mday;
-    time_ptr->hour = tm_t->tm_hour;
-    time_ptr->min = tm_t->tm_min;
-    time_ptr->sec = tm_t->tm_sec;
-}
diff --git a/media/libdrm/mobile1/src/parser/parser_dcf.c b/media/libdrm/mobile1/src/parser/parser_dcf.c
deleted file mode 100644
index 3eac120..0000000
--- a/media/libdrm/mobile1/src/parser/parser_dcf.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <parser_dcf.h>
-#include <svc_drm.h>
-
-static int32_t drm_parseUintVar(uint8_t * buffer, uint8_t * len)
-{
-    int32_t i;
-    int32_t byteLen;
-    int32_t sum;
-
-    if (NULL == buffer)
-        return DRM_UINT_VAR_ERR;
-
-    byteLen = 0;
-    while ((buffer[byteLen] & UINT_VAR_FLAG) > 0 && byteLen < MAX_UINT_VAR_BYTE) /* UINT_VAR_FLAG == 0x80 */
-        byteLen++;
-
-    if (byteLen >= MAX_UINT_VAR_BYTE) /* MAX_UINT_VAR_BYTE == 5 */
-        return DRM_UINT_VAR_ERR; /* The var int is too large, and that is impossible */
-
-    *len = (uint8_t)(byteLen + 1);
-    sum = buffer[byteLen];
-    for (i = byteLen - 1; i >= 0; i--)
-        sum += ((buffer[i] & UINT_VAR_DATA) << 7 * (byteLen - i)); /* UINT_VAR_DATA == 0x7F */
-
-    return sum;
-}
-
-/* See parser_dcf.h */
-int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo,
-                      uint8_t **ppEncryptedData)
-{
-    uint8_t *tmpBuf;
-    uint8_t *pStart, *pEnd;
-    uint8_t *pHeader, *pData;
-    uint8_t varLen;
-
-    if (NULL == buffer || bufferLen <= 0 || NULL == pDcfInfo)
-        return FALSE;
-
-    tmpBuf = buffer;
-    /* 1. Parse the version, content-type and content-url */
-    pDcfInfo->Version = *(tmpBuf++);
-    if (0x01 != pDcfInfo->Version) /* Because it is OMA DRM v1.0, the vension must be 1 */
-        return FALSE;
-
-    pDcfInfo->ContentTypeLen = *(tmpBuf++);
-    if (pDcfInfo->ContentTypeLen >= MAX_CONTENT_TYPE_LEN)
-        return FALSE;
-
-    pDcfInfo->ContentURILen = *(tmpBuf++);
-    if (pDcfInfo->ContentURILen >= MAX_CONTENT_URI_LEN)
-        return FALSE;
-
-    strncpy((char *)pDcfInfo->ContentType, (char *)tmpBuf, pDcfInfo->ContentTypeLen);
-    pDcfInfo->ContentType[MAX_CONTENT_TYPE_LEN - 1] = 0;
-    tmpBuf += pDcfInfo->ContentTypeLen;
-    strncpy((char *)pDcfInfo->ContentURI, (char *)tmpBuf, pDcfInfo->ContentURILen);
-    pDcfInfo->ContentURI[MAX_CONTENT_URI_LEN - 1] = 0;
-    tmpBuf += pDcfInfo->ContentURILen;
-
-    /* 2. Get the headers length and data length */
-    pDcfInfo->HeadersLen = drm_parseUintVar(tmpBuf, &varLen);
-    if (DRM_UINT_VAR_ERR == pDcfInfo->HeadersLen)
-        return FALSE;
-    tmpBuf += varLen;
-    pDcfInfo->DecryptedDataLen = DRM_UNKNOWN_DATA_LEN;
-    pDcfInfo->EncryptedDataLen = drm_parseUintVar(tmpBuf, &varLen);
-    if (DRM_UINT_VAR_ERR == pDcfInfo->EncryptedDataLen)
-        return FALSE;
-    tmpBuf += varLen;
-    pHeader = tmpBuf;
-    tmpBuf += pDcfInfo->HeadersLen;
-    pData = tmpBuf;
-
-    /* 3. Parse the headers */
-    pStart = pHeader;
-    while (pStart < pData) {
-        pEnd = pStart;
-        while ('\r' != *pEnd && pEnd < pData)
-            pEnd++;
-
-        if (0 == strncmp((char *)pStart, HEADER_ENCRYPTION_METHOD, HEADER_ENCRYPTION_METHOD_LEN)) {
-            if ((pEnd - pStart - HEADER_ENCRYPTION_METHOD_LEN) >= MAX_ENCRYPTION_METHOD_LEN)
-                return FALSE;
-            strncpy((char *)pDcfInfo->Encryption_Method,
-                         (char *)(pStart + HEADER_ENCRYPTION_METHOD_LEN),
-                         pEnd - pStart - HEADER_ENCRYPTION_METHOD_LEN);
-            pDcfInfo->Encryption_Method[MAX_ENCRYPTION_METHOD_LEN - 1] = 0;
-        } else if (0 == strncmp((char *)pStart, HEADER_RIGHTS_ISSUER, HEADER_RIGHTS_ISSUER_LEN)) {
-            if ((pEnd - pStart - HEADER_RIGHTS_ISSUER_LEN) >= MAX_RIGHTS_ISSUER_LEN)
-                return FALSE;
-            strncpy((char *)pDcfInfo->Rights_Issuer,
-                         (char *)(pStart + HEADER_RIGHTS_ISSUER_LEN),
-                         pEnd - pStart - HEADER_RIGHTS_ISSUER_LEN);
-            pDcfInfo->Rights_Issuer[MAX_RIGHTS_ISSUER_LEN - 1] = 0;
-        } else if (0 == strncmp((char *)pStart, HEADER_CONTENT_NAME, HEADER_CONTENT_NAME_LEN)) {
-            if ((pEnd - pStart - HEADER_CONTENT_NAME_LEN) >= MAX_CONTENT_NAME_LEN)
-                return FALSE;
-            strncpy((char *)pDcfInfo->Content_Name,
-                         (char *)(pStart + HEADER_CONTENT_NAME_LEN),
-                         pEnd - pStart - HEADER_CONTENT_NAME_LEN);
-            pDcfInfo->Content_Name[MAX_CONTENT_NAME_LEN - 1] = 0;
-        } else if (0 == strncmp((char *)pStart, HEADER_CONTENT_DESCRIPTION, HEADER_CONTENT_DESCRIPTION_LEN)) {
-            if ((pEnd - pStart - HEADER_CONTENT_DESCRIPTION_LEN) >= MAX_CONTENT_DESCRIPTION_LEN)
-                return FALSE;
-            strncpy((char *)pDcfInfo->ContentDescription,
-                         (char *)(pStart + HEADER_CONTENT_DESCRIPTION_LEN),
-                         pEnd - pStart - HEADER_CONTENT_DESCRIPTION_LEN);
-            pDcfInfo->ContentDescription[MAX_CONTENT_DESCRIPTION_LEN - 1] = 0;
-        } else if (0 == strncmp((char *)pStart, HEADER_CONTENT_VENDOR, HEADER_CONTENT_VENDOR_LEN)) {
-            if ((pEnd - pStart - HEADER_CONTENT_VENDOR_LEN) >= MAX_CONTENT_VENDOR_LEN)
-                return FALSE;
-            strncpy((char *)pDcfInfo->ContentVendor,
-                         (char *)(pStart + HEADER_CONTENT_VENDOR_LEN),
-                         pEnd - pStart - HEADER_CONTENT_VENDOR_LEN);
-            pDcfInfo->ContentVendor[MAX_CONTENT_VENDOR_LEN - 1] = 0;
-        } else if (0 == strncmp((char *)pStart, HEADER_ICON_URI, HEADER_ICON_URI_LEN)) {
-            if ((pEnd - pStart - HEADER_ICON_URI_LEN) >= MAX_ICON_URI_LEN)
-                return FALSE;
-            strncpy((char *)pDcfInfo->Icon_URI,
-                         (char *)(pStart + HEADER_ICON_URI_LEN),
-                         pEnd - pStart - HEADER_ICON_URI_LEN);
-            pDcfInfo->Icon_URI[MAX_ICON_URI_LEN - 1] = 0;
-        }
-
-        if ('\n' == *(pEnd + 1))
-            pStart = pEnd + 2;  /* Two bytes: a '\r' and a '\n' */
-        else
-            pStart = pEnd + 1;
-    }
-
-    /* 4. Give out the location of encrypted data */
-    if (NULL != ppEncryptedData)
-        *ppEncryptedData = pData;
-
-    return TRUE;
-}
diff --git a/media/libdrm/mobile1/src/parser/parser_dm.c b/media/libdrm/mobile1/src/parser/parser_dm.c
deleted file mode 100644
index 4b4a2da..0000000
--- a/media/libdrm/mobile1/src/parser/parser_dm.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <parser_dm.h>
-#include <parser_dcf.h>
-#include <svc_drm.h>
-#include "log.h"
-
-#define DRM_SKIP_SPACE_TAB(p) while( (*(p) == ' ') || (*(p) == '\t') ) \
-                                  p++
-
-typedef enum _DM_PARSE_STATUS {
-    DM_PARSE_START,
-    DM_PARSING_RIGHTS,
-    DM_PARSING_CONTENT,
-    DM_PARSE_END
-} DM_PARSE_STATUS;
-
-static int drm_strnicmp(const uint8_t* s1, const uint8_t* s2, int32_t n)
-{
-    if (n < 0 || NULL == s1 || NULL == s2)
-        return -1;
-
-    if (n == 0)
-        return 0;
-
-    while (n-- != 0 && tolower(*s1) == tolower(*s2))
-    {
-        if (n == 0 || *s1 == '\0' || *s2 == '\0')
-            break;
-        s1++;
-        s2++;
-    }
-
-    return tolower(*s1) - tolower(*s2);
-}
-
-const uint8_t * drm_strnstr(const uint8_t * str, const uint8_t * strSearch, int32_t len)
-{
-    int32_t i, stringLen;
-
-    if (NULL == str || NULL == strSearch || len <= 0)
-        return NULL;
-
-    stringLen = strlen((char *)strSearch);
-    for (i = 0; i < len - stringLen + 1; i++) {
-        if (str[i] == *strSearch && 0 == memcmp(str + i, strSearch, stringLen))
-            return str + i;
-    }
-    return NULL;
-}
-
-/* See parser_dm.h */
-int32_t drm_parseDM(const uint8_t *buffer, int32_t bufferLen, T_DRM_DM_Info *pDmInfo)
-{
-    const uint8_t *pStart = NULL, *pEnd = NULL;
-    const uint8_t *pBufferEnd;
-    int32_t contentLen, leftLen;
-    DM_PARSE_STATUS status = DM_PARSE_START;
-    int32_t boundaryLen;
-
-    if (NULL == buffer || bufferLen <= 0 || NULL == pDmInfo)
-        return FALSE;
-
-    /* Find the end of the input buffer */
-    pBufferEnd = buffer + bufferLen;
-    leftLen = bufferLen;
-
-    /* Find out the boundary */
-    pStart = drm_strnstr(buffer, (uint8_t *)"--", bufferLen);
-    if (NULL == pStart)
-        return FALSE; /* No boundary error */
-    pEnd = pStart;
-
-    /* Record the boundary */
-    pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen);
-    /* if can not find the CRLF, return FALSE */
-    if (NULL == pEnd)
-        return FALSE;
-    if ((pEnd - pStart) >= MAX_CONTENT_BOUNDARY_LEN)
-        return FALSE;
-    strncpy((char *)pDmInfo->boundary, (char *)pStart, pEnd - pStart);
-    pDmInfo->boundary[MAX_CONTENT_BOUNDARY_LEN - 1] = 0;
-    boundaryLen = strlen((char *)pDmInfo->boundary) + 2; /* 2 means: '\r' and '\n' */
-
-    pEnd += 2; /* skip the '\r' and '\n' */
-    pStart = pEnd;
-    leftLen = pBufferEnd - pStart;
-    do {
-        pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; /* According RFC2045 chapter 6.1, the default value should be 7bit.*/
-        strcpy((char *)pDmInfo->contentType, "text/plain");  /* According RFC2045 chapter 5.2, the default value should be "text/plain". */
-
-        /* Deal the header information */
-        while ((('\r' != *pStart) || ('\n' != *(pStart + 1))) && pStart < pBufferEnd) {
-            pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen);
-            if (NULL == pEnd)
-                return FALSE;
-
-            if (0 != pDmInfo->deliveryType) { /* This means the delivery type has been confirmed */
-                if (0 == strncmp((char *)pStart, HEADERS_TRANSFER_CODING, HEADERS_TRANSFER_CODING_LEN)) {
-                    pStart += HEADERS_TRANSFER_CODING_LEN;
-                    DRM_SKIP_SPACE_TAB(pStart);
-
-                    if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_7BIT, pEnd - pStart))
-                        pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT;
-                    else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_8BIT, pEnd - pStart))
-                        pDmInfo->transferEncoding = DRM_MESSAGE_CODING_8BIT;
-                    else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BINARY, pEnd - pStart))
-                        pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BINARY;
-                    else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BASE64, pEnd - pStart))
-                        pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BASE64;
-                    else
-                        return FALSE; /* Unknown transferCoding error */
-                } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) {
-                    pStart += HEADERS_CONTENT_TYPE_LEN;
-                    DRM_SKIP_SPACE_TAB(pStart);
-
-                    if (pEnd - pStart > 0) {
-                        if ((pEnd - pStart) >= MAX_CONTENT_TYPE_LEN)
-                            return FALSE;
-                        strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart);
-                        pDmInfo->contentType[pEnd - pStart] = '\0';
-                    }
-                } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_ID, HEADERS_CONTENT_ID_LEN)) {
-                    uint8_t tmpBuf[MAX_CONTENT_ID] = {0};
-                    uint8_t *pTmp;
-
-                    pStart += HEADERS_CONTENT_ID_LEN;
-                    DRM_SKIP_SPACE_TAB(pStart);
-
-                    /* error: more than one content id */
-                    if(drm_strnstr(pStart, (uint8_t*)HEADERS_CONTENT_ID, pBufferEnd - pStart)){
-                        ALOGD("drm_dmParser: error: more than one content id\r\n");
-                        return FALSE;
-                    }
-
-                    status = DM_PARSING_CONTENT; /* can go here means that the rights object has been parsed. */
-
-                    /* Change the format from <...> to cid:... */
-                    if (NULL != (pTmp = (uint8_t *)memchr((char *)pStart, '<', pEnd - pStart))) {
-                        if ((pEnd - pTmp - 1) >= (int) sizeof(tmpBuf))
-                            return FALSE;
-                        strncpy((char *)tmpBuf, (char *)(pTmp + 1), pEnd - pTmp - 1);
-                        tmpBuf[MAX_CONTENT_ID - 1] = 0;
-
-                        if (NULL != (pTmp = (uint8_t *)memchr((char *)tmpBuf, '>', pEnd - pTmp - 1))) {
-                            *pTmp = '\0';
-
-                            memset(pDmInfo->contentID, 0, MAX_CONTENT_ID);
-                            snprintf((char *)pDmInfo->contentID, MAX_CONTENT_ID, "%s%s", "cid:", (int8_t *)tmpBuf);
-                        }
-                    }
-                }
-            } else { /* First confirm delivery type, Forward_Lock, Combined Delivery or Separate Delivery */
-                if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) {
-                    pStart += HEADERS_CONTENT_TYPE_LEN;
-                    DRM_SKIP_SPACE_TAB(pStart);
-
-                    if (pEnd - pStart > 0) {
-                        strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart);
-                        pDmInfo->contentType[pEnd - pStart] = '\0';
-                    }
-
-                    if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_RIGHTS_XML)) {
-                        pDmInfo->deliveryType = COMBINED_DELIVERY;
-                        status = DM_PARSING_RIGHTS;
-                    }
-                    else if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_CONTENT)) {
-                        pDmInfo->deliveryType = SEPARATE_DELIVERY_FL;
-                        status = DM_PARSING_CONTENT;
-                    }
-                    else if (0 == pDmInfo->deliveryType) {
-                        pDmInfo->deliveryType = FORWARD_LOCK;
-                        status = DM_PARSING_CONTENT;
-                    }
-                }
-            }
-            pEnd += 2; /* skip the '\r' and '\n' */
-            pStart = pEnd;
-            leftLen = pBufferEnd - pStart;
-        }
-        pStart += 2; /* skip the second CRLF: "\r\n" */
-        pEnd = pStart;
-
-        /* Deal the content part, including rel or real content */
-        while (leftLen > 0) {
-            if (NULL == (pEnd = memchr(pEnd, '\r', leftLen))) {
-                pEnd = pBufferEnd;
-                break; /* no boundary found */
-            }
-
-            leftLen = pBufferEnd - pEnd;
-            if (leftLen < boundaryLen) {
-                pEnd = pBufferEnd;
-                break; /* here means may be the boundary has been split */
-            }
-
-            if (('\n' == *(pEnd + 1)) && (0 == memcmp(pEnd + 2, pDmInfo->boundary, strlen((char *)pDmInfo->boundary))))
-                break; /* find the boundary here */
-
-            pEnd++;
-            leftLen--;
-        }
-
-        if (pEnd >= pBufferEnd)
-            contentLen = DRM_UNKNOWN_DATA_LEN;
-        else
-            contentLen = pEnd - pStart;
-
-        switch(pDmInfo->deliveryType) {
-        case FORWARD_LOCK:
-            pDmInfo->contentLen = contentLen;
-            pDmInfo->contentOffset = pStart - buffer;
-            status = DM_PARSE_END;
-            break;
-        case COMBINED_DELIVERY:
-            if (DM_PARSING_RIGHTS == status) {
-                pDmInfo->rightsLen = contentLen;
-                pDmInfo->rightsOffset = pStart - buffer;
-            } else {
-                pDmInfo->contentLen = contentLen;
-                pDmInfo->contentOffset = pStart - buffer;
-                status = DM_PARSE_END;
-            }
-            break;
-        case SEPARATE_DELIVERY_FL:
-            {
-                T_DRM_DCF_Info dcfInfo;
-                uint8_t* pEncData = NULL;
-
-                memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info));
-                if (DRM_UNKNOWN_DATA_LEN == contentLen)
-                    contentLen = pEnd - pStart;
-                if (FALSE == drm_dcfParser(pStart, contentLen, &dcfInfo, &pEncData))
-                    return FALSE;
-
-                pDmInfo->contentLen = dcfInfo.EncryptedDataLen;
-                pDmInfo->contentOffset = pEncData - buffer;
-                strcpy((char *)pDmInfo->contentType, (char *)dcfInfo.ContentType);
-                strcpy((char *)pDmInfo->contentID, (char *)dcfInfo.ContentURI);
-                strcpy((char *)pDmInfo->rightsIssuer, (char *)dcfInfo.Rights_Issuer);
-                status = DM_PARSE_END;
-            }
-            break;
-        default:
-            return FALSE;
-        }
-
-        if (DM_PARSING_RIGHTS == status) {
-            /* Here means the rights object data has been completed, boundary must exist */
-            leftLen = pBufferEnd - pEnd;
-            pStart = drm_strnstr(pEnd, pDmInfo->boundary, leftLen);
-            if (NULL == pStart)
-                return FALSE;
-            leftLen = pBufferEnd - pStart;
-            pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen);
-            if (NULL == pEnd)
-                return FALSE; /* only rights object, no media object, error */
-
-            pEnd += 2; /* skip the "\r\n" */
-            pStart = pEnd;
-        }
-    } while (DM_PARSE_END != status);
-
-    return TRUE;
-}
diff --git a/media/libdrm/mobile1/src/parser/parser_rel.c b/media/libdrm/mobile1/src/parser/parser_rel.c
deleted file mode 100644
index 537fa9ce..0000000
--- a/media/libdrm/mobile1/src/parser/parser_rel.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <parser_rel.h>
-#include <parser_dm.h>
-#include <xml_tinyParser.h>
-#include <wbxml_tinyparser.h>
-#include <drm_decoder.h>
-#include <svc_drm.h>
-
-/* See parser_rel.h */
-int32_t drm_monthDays(int32_t year, int32_t month)
-{
-    switch (month) {
-    case 1:
-    case 3:
-    case 5:
-    case 7:
-    case 8:
-    case 10:
-    case 12:
-        return 31;
-    case 4:
-    case 6:
-    case 9:
-    case 11:
-        return 30;
-    case 2:
-        if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
-            return 29;
-        else
-            return 28;
-    default:
-        return -1;
-    }
-}
-
-int32_t drm_checkDate(int32_t year, int32_t month, int32_t day,
-                      int32_t hour, int32_t min, int32_t sec)
-{
-    if (month >= 1 && month <= 12 &&
-        day >= 1 && day <= drm_monthDays(year, month) &&
-        hour >= 0 && hour <= 23 &&
-        min >= 0 && min <= 59 && sec >= 0 && sec <= 59)
-        return 0;
-    else
-        return -1;
-}
-
-static int32_t drm_getStartEndTime(uint8_t * pValue, int32_t valueLen,
-                                   T_DRM_DATETIME * dateTime)
-{
-    int32_t year, mon, day, hour, min, sec;
-    uint8_t pTmp[64] = {0};
-
-    strncpy((char *)pTmp, (char *)pValue, valueLen);
-    {
-        uint8_t * pHead = pTmp;
-        uint8_t * pEnd = NULL;
-        uint8_t tmpByte;
-
-        /** get year */
-        pEnd = (uint8_t *)strstr((char *)pHead, "-");
-        if(NULL == pEnd)
-            return FALSE;
-        tmpByte = *pEnd;
-        *pEnd = '\0';
-        year = atoi((char *)pHead);
-        pHead = pEnd + 1;
-        *pEnd = tmpByte;
-
-        /** get month */
-        pEnd = (uint8_t *)strstr((char *)pHead, "-");
-        if(NULL == pEnd)
-            return FALSE;
-        tmpByte = *pEnd;
-        *pEnd = '\0';
-        mon = atoi((char *)pHead);
-        pHead = pEnd + 1;
-        *pEnd = tmpByte;
-
-        /** get day */
-        pEnd = (uint8_t *)strstr((char *)pHead, "T");
-        if(NULL == pEnd)
-            return FALSE;
-        tmpByte = *pEnd;
-        *pEnd = '\0';
-        day = atoi((char *)pHead);
-        pHead = pEnd + 1;
-        *pEnd = tmpByte;
-
-        /** get hour */
-        pEnd = (uint8_t *)strstr((char *)pHead, ":");
-        if(NULL == pEnd)
-            return FALSE;
-        tmpByte = *pEnd;
-        *pEnd = '\0';
-        hour = atoi((char *)pHead);
-        pHead = pEnd + 1;
-        *pEnd = tmpByte;
-
-        /** get minute */
-        pEnd = (uint8_t *)strstr((char *)pHead, ":");
-        if(NULL == pEnd)
-            return FALSE;
-        tmpByte = *pEnd;
-        *pEnd = '\0';
-        min = atoi((char *)pHead);
-        pHead = pEnd + 1;
-        *pEnd = tmpByte;
-
-        /** get second */
-        sec = atoi((char *)pHead);
-    }
-    if (0 != drm_checkDate(year, mon, day, hour, min, sec))
-        return FALSE;
-
-    YMD_HMS_2_INT(year, mon, day, dateTime->date, hour, min, sec,
-                  dateTime->time);
-    return TRUE;
-}
-
-static int32_t drm_checkWhetherHasUnknowConstraint(uint8_t* drm_constrain)
-{
-    char* begin_constrain = "<o-ex:constraint>";
-    char* end_constrain = "</o-ex:constraint>";
-    char* constrain_begin = strstr((char*)drm_constrain,begin_constrain);
-    char* constrain_end = strstr((char*)drm_constrain,end_constrain);
-    uint32_t constrain_len = 0;
-
-    if(NULL == constrain_begin)
-        return FALSE;
-
-    if(NULL == constrain_end)
-        return TRUE;
-
-    /* compute valid characters length */
-    {
-        uint32_t constrain_begin_len = strlen(begin_constrain);
-        char* cur_pos = constrain_begin + constrain_begin_len;
-
-        constrain_len = (constrain_end - constrain_begin) - constrain_begin_len;
-
-        while(cur_pos < constrain_end){
-            if(isspace(*cur_pos))
-                constrain_len--;
-
-            cur_pos++;
-        }
-    }
-
-    /* check all constraints */
-    {
-        #define DRM_ALL_CONSTRAINT_COUNT 5
-
-        int32_t i = 0;
-        int32_t has_datetime = FALSE;
-        int32_t has_start_or_end = FALSE;
-
-        char* all_vaild_constraints[DRM_ALL_CONSTRAINT_COUNT][2] = {
-            {"<o-dd:count>","</o-dd:count>"},
-            {"<o-dd:interval>","</o-dd:interval>"},
-            {"<o-dd:datetime>","</o-dd:datetime>"},
-            {"<o-dd:start>","</o-dd:start>"},
-            {"<o-dd:end>","</o-dd:end>"}
-        };
-
-        for(i = 0; i < DRM_ALL_CONSTRAINT_COUNT; i++){
-            char*start = strstr((char*)drm_constrain,all_vaild_constraints[i][0]);
-
-            if(start && (start < constrain_end)){
-                char* end = strstr((char*)drm_constrain,all_vaild_constraints[i][1]);
-
-                if(end && (end < constrain_end)){
-                    if(0 == strncmp(all_vaild_constraints[i][0],"<o-dd:datetime>",strlen("<o-dd:datetime>"))){
-                        constrain_len -= strlen(all_vaild_constraints[i][0]);
-                        constrain_len -= strlen(all_vaild_constraints[i][1]);
-
-                        if(0 == constrain_len)
-                            return TRUE;
-
-                        has_datetime = TRUE;
-                        continue;
-                    }
-
-                    if((0 == strncmp(all_vaild_constraints[i][0],"<o-dd:start>",strlen("<o-dd:start>")))
-                        || (0 == strncmp(all_vaild_constraints[i][0],"<o-dd:end>",strlen("<o-dd:end>")))){
-                        if(FALSE == has_datetime)
-                            return TRUE;
-                        else
-                            has_start_or_end = TRUE;
-                    }
-
-                    constrain_len -= (end - start);
-                    constrain_len -= strlen(all_vaild_constraints[i][1]);
-
-                    if(0 == constrain_len)
-                        if(has_datetime != has_start_or_end)
-                            return TRUE;
-                        else
-                            return FALSE;
-                }
-                else
-                    return TRUE;
-            }
-        }
-
-        if(has_datetime != has_start_or_end)
-            return TRUE;
-
-        if(constrain_len)
-            return TRUE;
-        else
-            return FALSE;
-    }
-}
-
-static int32_t drm_getRightValue(uint8_t * buffer, int32_t bufferLen,
-                                 T_DRM_Rights * ro, uint8_t * operation,
-                                 uint8_t oper_char)
-{
-    uint8_t *pBuf, *pValue;
-    uint8_t sProperty[256];
-    int32_t valueLen;
-    int32_t year, mon, day, hour, min, sec;
-    T_DRM_Rights_Constraint *pConstraint;
-    int32_t *bIsAble;
-    uint8_t *ret = NULL;
-    int32_t flag = 0;
-
-    if (operation == NULL) {
-        switch (oper_char) {
-        case REL_TAG_PLAY:
-            pConstraint = &(ro->PlayConstraint);
-            bIsAble = &(ro->bIsPlayable);
-            break;
-        case REL_TAG_DISPLAY:
-            pConstraint = &(ro->DisplayConstraint);
-            bIsAble = &(ro->bIsDisplayable);
-            break;
-        case REL_TAG_EXECUTE:
-            pConstraint = &(ro->ExecuteConstraint);
-            bIsAble = &(ro->bIsExecuteable);
-            break;
-        case REL_TAG_PRINT:
-            pConstraint = &(ro->PrintConstraint);
-            bIsAble = &(ro->bIsPrintable);
-            break;
-        default:
-            return FALSE; /* The input parm is err */
-        }
-    } else {
-        if (strcmp((char *)operation, "play") == 0) {
-            pConstraint = &(ro->PlayConstraint);
-            bIsAble = &(ro->bIsPlayable);
-        } else if (strcmp((char *)operation, "display") == 0) {
-            pConstraint = &(ro->DisplayConstraint);
-            bIsAble = &(ro->bIsDisplayable);
-        } else if (strcmp((char *)operation, "execute") == 0) {
-            pConstraint = &(ro->ExecuteConstraint);
-            bIsAble = &(ro->bIsExecuteable);
-        } else if (strcmp((char *)operation, "print") == 0) {
-            pConstraint = &(ro->PrintConstraint);
-            bIsAble = &(ro->bIsPrintable);
-        } else
-            return FALSE; /* The input parm is err */
-    }
-
-    if (operation == NULL) {
-        sprintf((char *)sProperty, "%c%c%c%c", REL_TAG_RIGHTS,
-                     REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char);
-        ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty);
-    } else {
-        sprintf((char *)sProperty,
-                     "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s",
-                     operation);
-        ret = XML_DOM_getNode(buffer, sProperty);
-    }
-    CHECK_VALIDITY(ret);
-    if (NULL == ret)
-        return TRUE;
-    WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */
-    flag = 1;
-
-    if (operation == NULL) { /* If father element node is not exit then return */
-        sprintf((char *)sProperty, "%c%c%c%c%c", REL_TAG_RIGHTS,
-                     REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
-                     REL_TAG_CONSTRAINT);
-        ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty);
-    } else {
-        sprintf((char *)sProperty,
-                     "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint",
-                     operation);
-        ret = XML_DOM_getNode(buffer, sProperty);
-    }
-
-    CHECK_VALIDITY(ret);
-    if (ret == NULL)
-        return TRUE;
-
-    if(TRUE == drm_checkWhetherHasUnknowConstraint(ret))
-        return FALSE;
-
-    *bIsAble = 0;
-    pConstraint->Indicator = DRM_NO_PERMISSION; /* If exit constraint assume have no rights */
-    flag = 2;
-
-    if (operation == NULL) {
-        sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS,
-                     REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
-                     REL_TAG_CONSTRAINT, REL_TAG_INTERVAL);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-    } else {
-        sprintf((char *)sProperty,
-                     "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:interval",
-                     operation);
-        pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
-    }
-    CHECK_VALIDITY(pBuf);
-    if (pBuf) { /* If interval element exit then get the value */
-        uint8_t pTmp[64] = {0};
-
-        strncpy((char *)pTmp, (char *)pValue, valueLen);
-        {
-            uint8_t * pHead = pTmp + 1;
-            uint8_t * pEnd = NULL;
-            uint8_t tmpChar;
-
-            /** get year */
-            pEnd = (uint8_t *)strstr((char *)pHead, "Y");
-            if(NULL == pEnd)
-                return FALSE;
-            tmpChar = *pEnd;
-            *pEnd = '\0';
-            year = atoi((char *)pHead);
-            pHead = pEnd + 1;
-            *pEnd = tmpChar;
-
-            /** get month */
-            pEnd = (uint8_t *)strstr((char *)pHead, "M");
-            if(NULL == pEnd)
-                return FALSE;
-            tmpChar = *pEnd;
-            *pEnd = '\0';
-            mon = atoi((char *)pHead);
-            pHead = pEnd + 1;
-            *pEnd = tmpChar;
-
-            /** get day */
-            pEnd = (uint8_t *)strstr((char *)pHead, "D");
-            if(NULL == pEnd)
-                return FALSE;
-            tmpChar = *pEnd;
-            *pEnd = '\0';
-            day = atoi((char *)pHead);
-            pHead = pEnd + 2;
-            *pEnd = tmpChar;
-
-            /** get hour */
-            pEnd = (uint8_t *)strstr((char *)pHead, "H");
-            if(NULL == pEnd)
-                return FALSE;
-            tmpChar = *pEnd;
-            *pEnd = '\0';
-            hour = atoi((char *)pHead);
-            pHead = pEnd + 1;
-            *pEnd = tmpChar;
-
-            /** get minute */
-            pEnd = (uint8_t *)strstr((char *)pHead, "M");
-            if(NULL == pEnd)
-                return FALSE;
-            tmpChar = *pEnd;
-            *pEnd = '\0';
-            min = atoi((char *)pHead);
-            pHead = pEnd + 1;
-            *pEnd = tmpChar;
-
-            /** get second */
-            pEnd = (uint8_t *)strstr((char *)pHead, "S");
-            if(NULL == pEnd)
-                return FALSE;
-            tmpChar = *pEnd;
-            *pEnd = '\0';
-            sec = atoi((char *)pHead);
-            pHead = pEnd + 1;
-            *pEnd = tmpChar;
-        }
-
-        if (year < 0 || mon < 0 || day < 0 || hour < 0
-            || min < 0 || sec < 0)
-            return FALSE;
-        YMD_HMS_2_INT(year, mon, day, pConstraint->Interval.date, hour,
-                      min, sec, pConstraint->Interval.time);
-        WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator,
-                      DRM_INTERVAL_CONSTRAINT);
-        flag = 3;
-    }
-
-    if (operation == NULL) {
-        sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS,
-                     REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
-                     REL_TAG_CONSTRAINT, REL_TAG_COUNT);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-    } else {
-        sprintf((char *)sProperty,
-                     "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:count",
-                     operation);
-        pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
-    }
-    CHECK_VALIDITY(pBuf);
-    if (pBuf) { /* If count element exit the  get the value */
-        uint8_t pTmp[16] = {0};
-        int32_t i;
-
-        for (i = 0; i < valueLen; i++) { /* Check the count format */
-            if (0 == isdigit(*(pValue + i)))
-                return FALSE;
-        }
-
-        strncpy((char *)pTmp, (char *)pValue, valueLen);
-        pConstraint->Count = atoi((char *)pTmp);
-
-    if(0 == pConstraint->Count)
-    {
-      WRITE_RO_FLAG(*bIsAble, 0, pConstraint->Indicator, DRM_NO_PERMISSION);
-    }
-    else if( pConstraint->Count > 0)
-    {
-      WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_COUNT_CONSTRAINT);
-    }
-    else  /* < 0 */
-    {
-       return FALSE;
-    }
-
-        flag = 3;
-    }
-
-    if (operation == NULL) {
-        sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS,
-                     REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
-                     REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_START);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-    } else {
-        sprintf((char *)sProperty,
-                     "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:start",
-                     operation);
-        pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
-    }
-    CHECK_VALIDITY(pBuf);
-    if (pBuf) { /* If start element exit then get the value */
-        if (FALSE ==
-            drm_getStartEndTime(pValue, valueLen, &pConstraint->StartTime))
-            return FALSE;
-        WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_START_TIME_CONSTRAINT);
-        flag = 3;
-    }
-
-    if (operation == NULL) {
-        sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS,
-                     REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
-                     REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_END);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-    } else {
-        sprintf((char *)sProperty,
-                     "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:end",
-                     operation);
-        pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
-    }
-    CHECK_VALIDITY(pBuf);
-    if (pBuf) {
-        if (FALSE ==
-            drm_getStartEndTime(pValue, valueLen, &pConstraint->EndTime))
-            return FALSE;
-        WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_END_TIME_CONSTRAINT);
-        flag = 3;
-    }
-
-    if (2 == flag)
-        WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */
-    return TRUE;
-}
-
-/* See parser_rel.h */
-int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights)
-{
-    uint8_t *pBuf, *pValue;
-    uint8_t sProperty[256];
-    int32_t valueLen;
-
-    if (TYPE_DRM_RIGHTS_WBXML != Format && TYPE_DRM_RIGHTS_XML != Format) /* It is not the support parse format */
-        return FALSE;
-
-    if (TYPE_DRM_RIGHTS_XML == Format) {
-        /* Check whether it is a CD, and parse it using TYPE_DRM_RIGHTS_XML */
-        if (NULL != drm_strnstr(buffer, (uint8_t *)HEADERS_CONTENT_ID, bufferLen))
-            return FALSE;
-
-        pBuf =
-            XML_DOM_getNodeValue(buffer,
-                                 (uint8_t *)"o-ex:rights\\o-ex:context\\o-dd:version",
-                                 &pValue, &valueLen);
-        CHECK_VALIDITY(pBuf);
-
-        if (pBuf) {
-            if (valueLen > 8) /* Check version lenth */
-                return FALSE;
-
-           /* error version */
-           if(strncmp(pValue,"1.0",valueLen))
-                return FALSE;
-
-            strncpy((char *)pRights->Version, (char *)pValue, valueLen);
-        } else
-            return FALSE;
-
-        /* this means there is more than one version label in rights */
-        if(strstr((char*)pBuf, "<o-dd:version>"))
-            return FALSE;
-
-        pBuf =
-            XML_DOM_getNodeValue(buffer,
-                                 (uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\ds:KeyInfo\\ds:KeyValue",
-                                 &pValue, &valueLen);
-        CHECK_VALIDITY(pBuf);
-        if (pBuf) { /* Get keyvalue */
-            int32_t keyLen;
-
-            if (24 != valueLen)
-                return FALSE;
-
-            keyLen = drm_decodeBase64(NULL, 0, pValue, &valueLen);
-            if (keyLen < 0)
-                return FALSE;
-
-            if (DRM_KEY_LEN != drm_decodeBase64(pRights->KeyValue, keyLen, pValue, &valueLen))
-                return FALSE;
-        }
-
-        pBuf =
-            XML_DOM_getNodeValue(buffer,
-                                 (uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\o-ex:context\\o-dd:uid",
-                                 &pValue, &valueLen);
-        CHECK_VALIDITY(pBuf);
-        if (pBuf) {
-            if (valueLen > DRM_UID_LEN)
-                return FALSE;
-            strncpy((char *)pRights->uid, (char *)pValue, valueLen);
-            pRights->uid[valueLen] = '\0';
-        } else
-            return FALSE;
-
-        /* this means there is more than one uid label in rights */
-        if(strstr((char*)pBuf, "<o-dd:uid>"))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"play", 0))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"display", 0))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"execute", 0))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"print", 0))
-            return FALSE;
-    } else if (TYPE_DRM_RIGHTS_WBXML == Format) {
-        if (!REL_CHECK_WBXML_HEADER(buffer))
-            return FALSE;
-
-        sprintf((char *)sProperty, "%c%c%c", REL_TAG_RIGHTS, REL_TAG_CONTEXT,
-                     REL_TAG_VERSION);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-        CHECK_VALIDITY(pBuf);
-
-        if (pBuf) {
-            if (valueLen > 8) /* Check version lenth */
-                return FALSE;
-            strncpy((char *)pRights->Version, (char *)pValue, valueLen);
-        } else
-            return FALSE;
-
-        sprintf((char *)sProperty, "%c%c%c%c%c",
-                     REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET,
-                     REL_TAG_KEYINFO, REL_TAG_KEYVALUE);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-        CHECK_VALIDITY(pBuf);
-        if (pBuf) {
-            if (DRM_KEY_LEN != valueLen)
-                return FALSE;
-            memcpy(pRights->KeyValue, pValue, DRM_KEY_LEN);
-            memset(pValue, 0, DRM_KEY_LEN); /* Clean the KeyValue */
-        }
-
-        sprintf((char *)sProperty, "%c%c%c%c%c",
-                     REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET,
-                     REL_TAG_CONTEXT, REL_TAG_UID);
-        pBuf =
-            WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
-                                   &valueLen);
-        CHECK_VALIDITY(pBuf);
-        if (pBuf) {
-            if (valueLen > DRM_UID_LEN)
-                return FALSE;
-            strncpy((char *)pRights->uid, (char *)pValue, valueLen);
-            pRights->uid[valueLen] = '\0';
-        } else
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, NULL,
-                              REL_TAG_PLAY))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, NULL,
-                              REL_TAG_DISPLAY))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, NULL,
-                              REL_TAG_EXECUTE))
-            return FALSE;
-
-        if (FALSE ==
-            drm_getRightValue(buffer, bufferLen, pRights, NULL,
-                              REL_TAG_PRINT))
-            return FALSE;
-    }
-
-    return TRUE;
-}
diff --git a/media/libdrm/mobile1/src/xml/xml_tinyparser.c b/media/libdrm/mobile1/src/xml/xml_tinyparser.c
deleted file mode 100644
index 7580312..0000000
--- a/media/libdrm/mobile1/src/xml/xml_tinyparser.c
+++ /dev/null
@@ -1,834 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <xml/xml_tinyParser.h>
-
-int32_t xml_errno;
-
-#ifdef XML_DOM_PARSER
-
-#define XML_IS_WHITESPACE(x) ((x) == '\t' || (x) == '\n' || (x) == ' ' || (x) == '\r')
-#define XML_IS_NAMECHAR(ch) (isalpha(ch) || isdigit(ch) || ch ==':' || \
-                             ch == '_' || ch == '-' || ch =='.')
-
-static uint8_t *xml_ignore_blank(uint8_t *buffer)
-{
-    if (NULL == buffer)
-        return NULL;
-
-    while (XML_IS_WHITESPACE(*buffer))
-        buffer++;
-
-    return buffer;
-}
-
-static uint8_t *xml_goto_tagend(uint8_t *buffer)
-{
-    int32_t nameLen, valueLen;
-    uint8_t *name, *value;
-
-    if (NULL == buffer)
-        return NULL;
-
-    /* Ignore the start-tag */
-    if (*buffer == '<') {
-        buffer++;
-        while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
-            buffer++;
-        if (NULL == buffer)
-            return NULL;
-    }
-
-    do {
-        if (NULL == (buffer = xml_ignore_blank(buffer)))
-            return NULL;
-
-        if (*buffer == '>' || (*buffer == '/' && *(buffer + 1) == '>'))
-            return buffer;
-
-        if (NULL ==
-            XML_DOM_getAttr(buffer, &name, &nameLen, &value, &valueLen))
-            return NULL;
-
-        buffer = value + valueLen + 1;
-    } while (*buffer != '\0');
-
-    return NULL;
-}
-
-static uint8_t *xml_match_tag(uint8_t *buffer)
-{
-    int32_t tagLen, tagType, bal;
-
-    if (NULL == buffer)
-        return NULL;
-
-    bal = 0;
-    do {
-        if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType)))
-            return NULL;
-
-        switch (tagType) {
-        case XML_TAG_SELF:
-        case XML_TAG_START:
-            if (NULL == (buffer = xml_goto_tagend(buffer + tagLen + 1)))
-                return NULL;
-            if (strncmp((char *)buffer, "/>", 2) == 0) {
-                buffer += 2;
-            } else {
-                bal++;
-            }
-            break;
-
-        case XML_TAG_END:
-            if (bal <= 0)
-                return NULL;
-            buffer = buffer + tagLen + 2;
-            bal--;
-            break;
-        }
-    } while (bal != 0);
-
-    return buffer;
-}
-
-uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen,
-                      uint8_t **pValue, int32_t *valueLen)
-{
-    uint8_t charQuoted;
-
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    /* Ignore the tag */
-    if (*buffer == '<') {
-        buffer++;
-        /* Ignore the STag */
-        while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
-            buffer++;
-        if (NULL == buffer)
-            return NULL;
-    }
-
-    if (NULL == (buffer = xml_ignore_blank(buffer))) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    /* Name */
-    *pName = buffer;
-    while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
-        buffer++;
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_ATTR_NAME);
-        return NULL;
-    }
-    *nameLen = buffer - *pName;
-    if (*nameLen <= 0) {
-        XML_ERROR(XML_ERROR_ATTR_NAME);
-        return NULL;
-    }
-
-    /* '=' */
-    buffer = xml_ignore_blank(buffer);
-    if (NULL == buffer || *buffer != '=') {
-        XML_ERROR(XML_ERROR_ATTR_MISSED_EQUAL);
-        return NULL;
-    }
-
-    /* Value */
-    buffer++;
-    buffer = xml_ignore_blank(buffer);
-    if (NULL == buffer || (*buffer != '"' && *buffer != '\'')) {
-        XML_ERROR(XML_ERROR_ATTR_VALUE);
-        return NULL;
-    }
-    charQuoted = *buffer++;
-    *pValue = buffer;
-    while (*buffer != '\0' && *buffer != charQuoted)
-        buffer++;
-    if (*buffer != charQuoted) {
-        XML_ERROR(XML_ERROR_ATTR_VALUE);
-        return NULL;
-    }
-    *valueLen = buffer - *pValue;
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return buffer + 1;
-}
-
-uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen)
-{
-    uint8_t *pEnd;
-
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    /* Ignore the STag */
-    if (*buffer == '<') {
-        buffer++;
-        /* If it's an end_tag, no value should be returned */
-        if (*buffer == '/') {
-            *valueLen = 0;
-            XML_ERROR(XML_ERROR_NOVALUE);
-            return NULL;
-        }
-
-        while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
-            buffer++;
-        if (NULL == buffer) {
-            XML_ERROR(XML_ERROR_BUFFER_NULL);
-            return NULL;
-        }
-
-        if (NULL == (buffer = xml_goto_tagend(buffer))) {
-            XML_ERROR(XML_ERROR_PROPERTY_END);
-            return NULL;
-        }
-    }
-
-    /* <test/> node found */
-    if (*buffer == '/') {
-        if (*(buffer + 1) != '>') {
-            XML_ERROR(XML_ERROR_PROPERTY_END);
-            return NULL;
-        }
-        XML_ERROR(XML_ERROR_OK);
-        *valueLen = 0;
-        return buffer;
-    }
-
-    if (*buffer == '>')
-        buffer++;
-
-    if (NULL == (buffer = xml_ignore_blank(buffer))) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    /* the following is a tag instead of the value */
-    if (*buffer == '<') { /* nono value, such as <test></test> */
-        buffer++;
-        if (*buffer != '/') {
-            XML_ERROR(XML_ERROR_ENDTAG);
-            return NULL;
-        }
-        *valueLen = 0;
-        XML_ERROR(XML_ERROR_OK);
-        return NULL;
-    }
-
-    *pValue = buffer;
-    pEnd = NULL;
-    while (*buffer != '\0' && *buffer != '<') {
-        if (!XML_IS_WHITESPACE(*buffer))
-            pEnd = buffer;
-        buffer++;
-    }
-    if (*buffer != '<' || pEnd == NULL) {
-        XML_ERROR(XML_ERROR_VALUE);
-        return NULL;
-    }
-
-    *valueLen = pEnd - *pValue + 1;
-
-    buffer++;
-    if (*buffer != '/') {
-        XML_ERROR(XML_ERROR_ENDTAG);
-        return NULL;
-    }
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return buffer - 1;
-}
-
-uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType)
-{
-    uint8_t *pStart;
-
-    /* WARNING: <!-- --> comment is not supported in this verison */
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    do {
-        while (*buffer != '<') {
-            if (*buffer == '\0') {
-                XML_ERROR(XML_ERROR_BUFFER_NULL);
-                return NULL;
-            }
-
-            if (*buffer == '\"' || *buffer == '\'') {
-                uint8_t charQuoted = *buffer;
-                buffer++;
-                while (*buffer != '\0' && *buffer != charQuoted)
-                    buffer++;
-                if (*buffer == '\0') {
-                    XML_ERROR(XML_ERROR_BUFFER_NULL);
-                    return NULL;
-                }
-            }
-            buffer++;
-        }
-        buffer++;
-    } while (*buffer == '!' || *buffer == '?');
-
-    pStart = buffer - 1;
-
-    if (*buffer == '/') {
-        buffer++;
-        *tagType = XML_TAG_END;
-    } else {
-        /* check here if it is self-end-tag */
-        uint8_t *pCheck = xml_goto_tagend(pStart);
-        if (pCheck == NULL) {
-            XML_ERROR(XML_ERROR_PROPERTY_END);
-            return NULL;
-        }
-
-        if (*pCheck == '>')
-            *tagType = XML_TAG_START;
-        else if (strncmp((char *)pCheck, "/>", 2) == 0)
-            *tagType = XML_TAG_SELF;
-        else {
-            XML_ERROR(XML_ERROR_PROPERTY_END);
-            return NULL;
-        }
-    }
-
-    while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
-        buffer++;
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    if (*tagType == XML_TAG_END)
-        *tagLen = buffer - pStart - 2;
-    else
-        *tagLen = buffer - pStart - 1;
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return pStart;
-}
-
-uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node)
-{
-    uint8_t *pStart;
-    uint8_t buf[XML_MAX_PROPERTY_LEN + 2];
-    uint8_t *nodeStr = buf;
-    uint8_t *retPtr = NULL;
-    int32_t tagLen, tagType;
-    uint8_t *lastNode = (uint8_t *)"";
-
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    strncpy((char *)nodeStr, (char *)node, XML_MAX_PROPERTY_LEN);
-    strcat((char *)nodeStr, "\\");
-    pStart = (uint8_t *)strchr((char *)nodeStr, '\\');
-
-    while (pStart != NULL) {
-        *pStart = '\0';
-
-        /* get the first start_tag from buffer */
-        if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType))) {
-            XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-            return NULL;
-        }
-
-        if (tagType == XML_TAG_END) {
-            if (0 ==
-                strncmp((char *)lastNode, (char *)(buffer + 2), strlen((char *)lastNode)))
-                XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-            else
-                XML_ERROR(XML_ERROR_NO_START_TAG);
-            return NULL;
-        }
-
-        /* wrong node, contiue to fetch the next node */
-        if ((int32_t) strlen((char *)nodeStr) != tagLen
-            || strncmp((char *)nodeStr, (char *)(buffer + 1), tagLen) != 0) {
-            /* we should ignore all the middle code */
-            buffer = xml_match_tag(buffer);
-            continue;
-        }
-
-        retPtr = buffer;        /* retPtr starts with '<xxx>' */
-        buffer += (tagLen + 1);
-
-        if (tagType == XML_TAG_SELF) {
-            nodeStr = pStart + 1;
-            break;
-        }
-
-        lastNode = nodeStr;
-        nodeStr = pStart + 1;
-        pStart = (uint8_t *)strchr((char *)nodeStr, '\\');
-    }
-
-    /* Check 5: nodeStr should be empty here */
-    if (*nodeStr != '\0') {
-        XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-        return NULL;
-    }
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return retPtr;
-}
-
-uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node,
-                           uint8_t **value, int32_t *valueLen)
-{
-    uint8_t *pStart;
-    uint8_t *lastTag;
-
-    if (NULL == node || NULL == buffer) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    lastTag = node + strlen((char *)node) - 1;
-    while (lastTag >= node && *lastTag != '\\')
-        lastTag--;
-    lastTag++;
-
-    if (NULL == (pStart = XML_DOM_getNode(buffer, node)))
-        return NULL;
-
-    pStart += (strlen((char *)lastTag) + 1);
-
-    if (NULL == (pStart = xml_goto_tagend(pStart))) {
-        XML_ERROR(XML_ERROR_PROPERTY_END);
-        return NULL;
-    }
-
-    if (NULL == (pStart = XML_DOM_getValue(pStart, value, valueLen)))
-        return NULL;
-
-    /* Check the end tag */
-#ifdef XML_DOM_CHECK_ENDTAG
-    if (strncmp((char *)pStart, "/>", 2) == 0) {
-
-    } else if (strncmp((char *)lastTag, (char *)(pStart + 2), strlen((char *)lastTag)) !=
-               0) {
-        XML_ERROR(XML_ERROR_ENDTAG);
-        return NULL;
-    }
-#endif
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return *value;
-}
-
-uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName, int32_t *nodenameLen)
-{
-    int32_t tagType;
-
-    if (NULL == buffer)
-        return NULL;
-
-    do {
-        if (NULL ==
-            (buffer = XML_DOM_getTag(buffer + 1, nodenameLen, &tagType))) {
-            XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-            return NULL;
-        }
-    } while (tagType == XML_TAG_END);
-
-    *pNodeName = buffer + 1;
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return buffer;
-}
-
-#endif /* XML_DOM_PARSER */
-
-#ifdef WBXML_DOM_PARSER
-
-#ifdef WBXML_OLD_VERSION
-uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen,
-                                 uint8_t *node)
-{
-    int32_t i = 0, j = 0;
-
-    if (NULL == buffer || node == NULL) {
-        XML_ERROR(XML_ERROR_BUFFER_NULL);
-        return NULL;
-    }
-
-    while (i < bufferLen) {
-        if (WBXML_GET_TAG(buffer[i]) == WBXML_GET_TAG(node[j])) {
-            j++;
-            if (node[j] == '\0')
-                break;
-
-            /* Check if there is the content(it should have content) */
-            if (!WBXML_HAS_CONTENT(buffer[i])) {
-                /*XML_ERROR(WBXML_ERROR_MISSED_CONTENT); */
-                XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-                return NULL;
-            }
-
-            /* Ignore the attrib filed */
-            if (WBXML_HAS_ATTR(buffer[i])) {
-                while (i < bufferLen && buffer[i] != WBXML_ATTR_END)
-                    i++;
-                if (i >= bufferLen)
-                    break;
-            }
-        }
-        i++;
-
-        /* Ignore the content filed */
-        if (buffer[i] == WBXML_STR_I) {
-            while (i < bufferLen && buffer[i] != WBXML_END)
-                i++;
-            if (i >= bufferLen)
-                break;
-            i++;
-        }
-    }
-
-    if (i >= bufferLen) {
-        XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-        return NULL;
-    }
-
-    XML_ERROR(XML_ERROR_OK);
-
-    return buffer + i + 1;
-}
-
-uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen,
-                                      uint8_t *node,
-                                      uint8_t **value, int32_t *valueLen)
-{
-    int32_t i;
-    uint8_t *pEnd;
-
-    *value = NULL;
-    *valueLen = 0;
-
-    pEnd = buffer + bufferLen;
-    buffer = WBXML_DOM_getNode(buffer, bufferLen, node);
-    if (NULL == buffer) {
-        XML_ERROR(XML_ERROR_NO_SUCH_NODE);
-        return NULL;
-    }
-
-    if (*buffer == WBXML_OPAUE) {
-        buffer++;
-        *valueLen = WBXML_GetUintVar(buffer, &i);
-        if (*valueLen < 0) {
-            XML_ERROR(WBXML_ERROR_MBUINT32);
-            return NULL;
-        }
-        buffer += i;
-        *value = buffer;
-        return *value;
-    }
-
-    if (*buffer != WBXML_STR_I) {
-        XML_ERROR(WBXML_ERROR_MISSED_STARTTAG);
-        return NULL;
-    }
-
-    buffer++;
-
-    i = 0;
-    while ((buffer + i) < pEnd && buffer[i] != WBXML_END)
-        i++;
-
-    if (buffer[i] != WBXML_END) {
-        XML_ERROR(WBXML_ERROR_MISSED_ENDTAG);
-        return NULL;
-    }
-
-    *value = buffer;
-    *valueLen = i;
-    XML_ERROR(XML_ERROR_OK);
-
-    return *value;
-}
-#endif /* WBXML_OLD_VERSION */
-
-#define MAX_UINT_VAR_BYTE                                    4
-#define UINTVAR_INVALID                                      -1
-int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len)
-{
-    int32_t i, byteLen;
-    int32_t sum;
-
-    byteLen = 0;
-    while ((buffer[byteLen] & 0x80) > 0 && byteLen < MAX_UINT_VAR_BYTE)
-        byteLen++;
-
-    if (byteLen > MAX_UINT_VAR_BYTE)
-        return UINTVAR_INVALID;
-
-    *len = byteLen + 1;
-    sum = buffer[byteLen];
-    for (i = byteLen - 1; i >= 0; i--)
-        sum += ((buffer[i] & 0x7F) << 7 * (byteLen - i));
-
-    return sum;
-}
-
-XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer,
-                        int32_t bufferLen)
-{
-    int32_t num, len;
-
-    pWbxml->End = buffer + bufferLen;
-    pWbxml->version = *buffer++;
-    if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len)))
-        return XML_FALSE;
-    buffer += len;
-    pWbxml->publicid = num;
-    if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len)))
-        return XML_FALSE;
-    buffer += len;
-    pWbxml->charset = num;
-    if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len)))
-        return XML_FALSE;
-    buffer += len;
-    pWbxml->strTable = buffer;
-    pWbxml->strTableLen = num;
-    buffer += num;
-    pWbxml->curPtr = pWbxml->Content = buffer;
-    pWbxml->depth = 0;
-
-    return XML_TRUE;
-}
-
-void WBXML_DOM_Rewind(WBXML * pWbxml)
-{
-    pWbxml->curPtr = pWbxml->Content;
-}
-
-XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml)
-{
-    if (pWbxml->curPtr > pWbxml->End)
-        return XML_TRUE;
-
-    return XML_FALSE;
-}
-
-uint8_t WBXML_DOM_GetTag(WBXML * pWbxml)
-{
-    uint8_t tagChar;
-
-    if (pWbxml->curPtr > pWbxml->End)
-        return XML_EOF;
-
-    tagChar = *pWbxml->curPtr;
-    pWbxml->curPtr++;
-
-    if (WBXML_GET_TAG(tagChar) == WBXML_CONTENT_END)
-        pWbxml->depth--;
-    else
-        pWbxml->depth++;
-
-    return tagChar;
-}
-
-uint8_t WBXML_DOM_GetChar(WBXML * pWbxml)
-{
-    return *pWbxml->curPtr++;
-}
-
-void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset)
-{
-    pWbxml->curPtr += offset;
-}
-
-uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml)
-{
-    int32_t num, len;
-
-    num = WBXML_GetUintVar(pWbxml->curPtr, &len);
-    pWbxml->curPtr += len;
-
-    return (uint8_t)num;
-}
-
-#ifdef XML_TREE_STRUCTURE
-
-#ifdef DEBUG_MODE
-static int32_t malloc_times = 0;
-static int32_t free_times = 0;
-void XML_PrintMallocInfo()
-{
-    printf("====XML_PrintMallocInfo====\n");
-    printf(" Total malloc times:%d\n", malloc_times);
-    printf(" Total free   times:%d\n", free_times);
-    printf("===========================\n");
-}
-#endif
-
-void *xml_malloc(int32_t size)
-{
-#ifdef DEBUG_MODE
-    malloc_times++;
-#endif
-    return malloc(size);
-}
-
-void xml_free(void *buffer)
-{
-#ifdef DEBUG_MODE
-    free_times++;
-#endif
-    free(buffer);
-}
-
-XML_TREE *xml_tree_fillnode(uint8_t **buf, int32_t tagLen)
-{
-    XML_TREE *Tree;
-    uint8_t *pAttr, *pName, *pValue;
-    int32_t nameLen, valueLen;
-    uint8_t *buffer = *buf;
-
-    if (NULL == (Tree = (XML_TREE *) xml_malloc(sizeof(XML_TREE))))
-        return NULL;
-    memset(Tree, 0, sizeof(XML_TREE));
-
-    strncpy((char *)Tree->tag, (char *)++buffer, tagLen);
-    buffer += tagLen;
-    pAttr = buffer;
-
-    /* attribute */
-    while (NULL !=
-           (pAttr =
-            XML_DOM_getAttr(pAttr, &pName, &nameLen, &pValue,
-                            &valueLen))) {
-        XML_TREE_ATTR *attr;
-        if (NULL ==
-            (attr = (XML_TREE_ATTR *) xml_malloc(sizeof(XML_TREE_ATTR))))
-            return NULL;
-        memset(attr, 0, sizeof(XML_TREE_ATTR));
-        strncpy((char *)attr->name, (char *)pName, nameLen);
-        strncpy((char *)attr->value, (char *)pValue, valueLen);
-        buffer = pValue + valueLen + 1;
-
-        if (NULL != Tree->attr) // no attribute now
-            Tree->last_attr->next = attr;
-        else
-            Tree->attr = attr;
-        Tree->last_attr = attr;
-    }
-
-    /* value */
-    pAttr = XML_DOM_getValue(buffer, &pValue, &valueLen);
-    if (pAttr != NULL && valueLen > 0) {
-        strncpy((char *)Tree->value, (char *)pValue, valueLen);
-        buffer = pValue + valueLen;
-    }
-
-    *buf = buffer;
-    return Tree;
-}
-
-XML_TREE *XML_makeTree(uint8_t **buf)
-{
-    uint8_t *pBuf;
-    int32_t valueLen, tagType;
-    uint8_t *buffer = *buf;
-    XML_TREE *TreeHead = NULL;
-
-    if (NULL == (buffer = XML_DOM_getTag(buffer, &valueLen, &tagType)))
-        return NULL;
-    if (XML_TAG_END == tagType)
-        return NULL;
-    if (NULL == (TreeHead = xml_tree_fillnode(&buffer, valueLen)))
-        return NULL;
-    if (XML_TAG_SELF == tagType) {
-        *buf = buffer;
-        return TreeHead;
-    }
-
-    do {
-        if (NULL == (pBuf = XML_DOM_getTag(buffer, &valueLen, &tagType)))
-            return NULL;
-
-        switch (tagType) {
-        case XML_TAG_SELF:
-        case XML_TAG_START:
-            if (NULL == TreeHead->child)
-                TreeHead->child = XML_makeTree(&buffer);
-            else if (NULL == TreeHead->child->last_brother) {
-                TreeHead->child->brother = XML_makeTree(&buffer);
-                TreeHead->child->last_brother = TreeHead->child->brother;
-            } else {
-                TreeHead->child->last_brother->brother =
-                    XML_makeTree(&buffer);
-                TreeHead->child->last_brother =
-                    TreeHead->child->last_brother->brother;
-            }
-            break;
-        case XML_TAG_END:
-            *buf = pBuf;
-            return TreeHead;
-        }
-        buffer++;
-    } while (1);
-}
-
-void XML_freeTree(XML_TREE * pTree)
-{
-    XML_TREE *p, *pNext;
-    XML_TREE_ATTR *pa, *lastpa;
-
-    if (NULL == pTree)
-        return;
-
-    p = pTree->brother;
-    while (NULL != p) {
-        pNext = p->brother;
-        p->brother = NULL;
-        XML_freeTree(p);
-        p = pNext;
-    }
-
-    if (NULL != pTree->child)
-        XML_freeTree(pTree->child);
-
-    pa = pTree->attr;
-    while (NULL != pa) {
-        lastpa = pa;
-        pa = pa->next;
-        xml_free(lastpa);
-    }
-    xml_free(pTree);
-}
-
-#endif /* XML_TREE_STRUCTURE */
-
-#endif /* WBXML_DOM_PARSER */
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp
index 73768fe..84dad8c 100644
--- a/media/mca/filterfw/native/core/gl_env.cpp
+++ b/media/mca/filterfw/native/core/gl_env.cpp
@@ -26,6 +26,8 @@
 #include <string>
 #include <EGL/eglext.h>
 
+#include <gui/GLConsumer.h>
+
 namespace android {
 namespace filterfw {
 
@@ -160,9 +162,9 @@
   }
 
   // Create dummy surface using a GLConsumer
-  surfaceTexture_ = new GLConsumer(0);
-  window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(
-          surfaceTexture_->getBufferQueue()));
+  sp<BufferQueue> bq = new BufferQueue();
+  surfaceTexture_ = new GLConsumer(bq, 0);
+  window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(bq));
 
   surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
   if (CheckEGLError("eglCreateWindowSurface")) return false;
diff --git a/media/mca/filterfw/native/core/gl_env.h b/media/mca/filterfw/native/core/gl_env.h
index 81e1e9d..a709638 100644
--- a/media/mca/filterfw/native/core/gl_env.h
+++ b/media/mca/filterfw/native/core/gl_env.h
@@ -31,6 +31,9 @@
 #include <gui/Surface.h>
 
 namespace android {
+
+class GLConsumer;
+
 namespace filterfw {
 
 class ShaderProgram;
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index c9afa19..1e6b2e7 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -7,7 +7,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := easymocklib
+LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target
 
 LOCAL_PACKAGE_NAME := mediaframeworktest
 
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index b698705..91ee2c6 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -71,4 +71,9 @@
          android:label="Media Power tests InstrumentationRunner">
      </instrumentation>
 
+    <instrumentation android:name=".MediaFrameworkIntegrationTestRunner"
+         android:targetPackage="com.android.mediaframeworktest"
+         android:label="MediaFramework integration tests InstrumentationRunner">
+     </instrumentation>
+
 </manifest>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java
new file mode 100644
index 0000000..7751fcc
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java
@@ -0,0 +1,72 @@
+/*
+ * 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.mediaframeworktest;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import android.util.Log;
+
+import com.android.mediaframeworktest.integration.CameraBinderTest;
+import com.android.mediaframeworktest.integration.CameraDeviceBinderTest;
+
+import junit.framework.TestSuite;
+
+/**
+ * Instrumentation Test Runner for all media framework integration tests.
+ *
+ * Running all tests:
+ *
+ * adb shell am instrument -w com.android.mediaframeworktest/.MediaFrameworkIntegrationTestRunner
+ */
+
+public class MediaFrameworkIntegrationTestRunner extends InstrumentationTestRunner {
+
+    private static final String TAG = "MediaFrameworkIntegrationTestRunner";
+
+    public static int mCameraId = 0;
+
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(CameraBinderTest.class);
+        suite.addTestSuite(CameraDeviceBinderTest.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return MediaFrameworkIntegrationTestRunner.class.getClassLoader();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        String cameraId = (String) icicle.get("camera_id");
+        if (cameraId != null) {
+            try {
+                Log.v(TAG,
+                        String.format("Reading camera_id from icicle: '%s'", cameraId));
+                mCameraId = Integer.parseInt(cameraId);
+            }
+            catch (NumberFormatException e) {
+                Log.e(TAG, String.format("Failed to convert camera_id to integer"));
+            }
+        }
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 92ac9eb..cbb6642 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -50,7 +50,7 @@
  * Running all tests:
  *
  * adb shell am instrument \
- *   -w com.android.smstests.MediaPlayerInstrumentationTestRunner
+ *  -w com.android.mediaframeworktest/.MediaFrameworkTestRunner
  */
 
 public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 62af3f3..64b12b7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -48,6 +48,8 @@
         addMediaRecorderStateUnitTests(suite);
         addMediaPlayerStateUnitTests(suite);
         addMediaScannerUnitTests(suite);
+        addCameraUnitTests(suite);
+        addImageReaderTests(suite);
         return suite;
     }
 
@@ -56,6 +58,18 @@
         return MediaFrameworkUnitTestRunner.class.getClassLoader();
     }
 
+    private void addCameraUnitTests(TestSuite suite) {
+        suite.addTestSuite(CameraUtilsDecoratorTest.class);
+        suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
+        suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
+        suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
+        suite.addTestSuite(CameraMetadataTest.class);
+    }
+
+    private void addImageReaderTests(TestSuite suite) {
+        suite.addTestSuite(ImageReaderTest.class);
+    }
+
     // Running all unit tests checking the state machine may be time-consuming.
     private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
         suite.addTestSuite(MediaMetadataRetrieverTest.class);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
index 2f864d7..7f23ba5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
@@ -36,7 +36,12 @@
 
 /**
  * Junit / Instrumentation test case for the camera api
- 
+ *
+ * To run only tests in this class:
+ *
+ * adb shell am instrument \
+ *   -e class com.android.mediaframeworktest.functional.CameraTest \
+ *   -w  com.android.mediaframeworktest/.MediaFrameworkTestRunner
  */  
 public class CameraTest extends ActivityInstrumentationTestCase<MediaFrameworkTest> {    
     private String TAG = "CameraTest";
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
new file mode 100644
index 0000000..1b7faec
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.mediaframeworktest.integration;
+
+import android.hardware.CameraInfo;
+import android.hardware.ICamera;
+import android.hardware.ICameraClient;
+import android.hardware.ICameraServiceListener;
+import android.hardware.IProCameraCallbacks;
+import android.hardware.IProCameraUser;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.BinderHolder;
+import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+/**
+ * <p>
+ * Junit / Instrumentation test case for the camera2 api
+ * </p>
+ * <p>
+ * To run only tests in this class:
+ * </p>
+ *
+ * <pre>
+ * adb shell am instrument \
+ *   -e class com.android.mediaframeworktest.integration.CameraBinderTest \
+ *   -w com.android.mediaframeworktest/.MediaFrameworkIntegrationTestRunner
+ * </pre>
+ */
+public class CameraBinderTest extends AndroidTestCase {
+    static String TAG = "CameraBinderTest";
+
+    protected CameraBinderTestUtils mUtils;
+
+    public CameraBinderTest() {
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mUtils = new CameraBinderTestUtils(getContext());
+    }
+
+    @SmallTest
+    public void testNumberOfCameras() throws Exception {
+
+        int numCameras = mUtils.getCameraService().getNumberOfCameras();
+        assertTrue("At least this many cameras: " + mUtils.getGuessedNumCameras(),
+                numCameras >= mUtils.getGuessedNumCameras());
+        Log.v(TAG, "Number of cameras " + numCameras);
+    }
+
+    @SmallTest
+    public void testCameraInfo() throws Exception {
+        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+            CameraInfo info = new CameraInfo();
+            info.info.facing = -1;
+            info.info.orientation = -1;
+
+            assertTrue(
+                    "Camera service returned info for camera " + cameraId,
+                    mUtils.getCameraService().getCameraInfo(cameraId, info) ==
+                    CameraBinderTestUtils.NO_ERROR);
+            assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
+            assertTrue("Orientation was not set for camera " + cameraId,
+                    info.info.orientation != -1);
+
+            Log.v(TAG, "Camera " + cameraId + " info: facing " + info.info.facing
+                    + ", orientation " + info.info.orientation);
+        }
+    }
+
+    static abstract class DummyBase extends Binder implements android.os.IInterface {
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+    }
+
+    static class DummyCameraClient extends DummyBase implements ICameraClient {
+    }
+
+    @SmallTest
+    public void testConnect() throws Exception {
+        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+            ICameraClient dummyCallbacks = new DummyCameraClient();
+
+            String clientPackageName = getContext().getPackageName();
+
+            BinderHolder holder = new BinderHolder();
+            CameraBinderDecorator.newInstance(mUtils.getCameraService())
+                    .connect(dummyCallbacks, cameraId, clientPackageName,
+                    CameraBinderTestUtils.USE_CALLING_UID, holder);
+            ICamera cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
+
+            Log.v(TAG, String.format("Camera %s connected", cameraId));
+
+            cameraUser.disconnect();
+        }
+    }
+
+    static class DummyProCameraCallbacks extends DummyBase implements IProCameraCallbacks {
+    }
+
+    @SmallTest
+    public void testConnectPro() throws Exception {
+        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+            IProCameraCallbacks dummyCallbacks = new DummyProCameraCallbacks();
+
+            String clientPackageName = getContext().getPackageName();
+
+            BinderHolder holder = new BinderHolder();
+            CameraBinderDecorator.newInstance(mUtils.getCameraService())
+                    .connectPro(dummyCallbacks, cameraId,
+                    clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
+            IProCameraUser cameraUser = IProCameraUser.Stub.asInterface(holder.getBinder());
+            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
+
+            Log.v(TAG, String.format("Camera %s connected", cameraId));
+
+            cameraUser.disconnect();
+        }
+    }
+
+    static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
+
+        @Override
+        public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
+        }
+
+        @Override
+        public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException {
+        }
+    }
+
+    @SmallTest
+    public void testConnectDevice() throws Exception {
+        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+            ICameraDeviceCallbacks dummyCallbacks = new DummyCameraDeviceCallbacks();
+
+            String clientPackageName = getContext().getPackageName();
+
+            BinderHolder holder = new BinderHolder();
+            CameraBinderDecorator.newInstance(mUtils.getCameraService())
+                    .connectDevice(dummyCallbacks, cameraId,
+                    clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
+            ICameraDeviceUser cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
+
+            Log.v(TAG, String.format("Camera %s connected", cameraId));
+
+            cameraUser.disconnect();
+        }
+    }
+
+    static class DummyCameraServiceListener extends ICameraServiceListener.Stub {
+        @Override
+        public void onStatusChanged(int status, int cameraId)
+                throws RemoteException {
+            Log.v(TAG, String.format("Camera %d has status changed to 0x%x", cameraId, status));
+        }
+    }
+
+    /**
+     * <pre>
+     * adb shell am instrument \
+     *   -e class 'com.android.mediaframeworktest.integration.CameraBinderTest#testAddRemoveListeners' \
+     *   -w com.android.mediaframeworktest/.MediaFrameworkIntegrationTestRunner
+     * </pre>
+     */
+    @SmallTest
+    public void testAddRemoveListeners() throws Exception {
+        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+            ICameraServiceListener listener = new DummyCameraServiceListener();
+
+            assertTrue(
+                    "Listener was removed before added",
+                    mUtils.getCameraService().removeListener(listener) ==
+                    CameraBinderTestUtils.BAD_VALUE);
+
+            assertTrue("Listener was not added",
+                    mUtils.getCameraService().addListener(listener) ==
+                    CameraBinderTestUtils.NO_ERROR);
+            assertTrue(
+                    "Listener was wrongly added again",
+                    mUtils.getCameraService().addListener(listener) ==
+                    CameraBinderTestUtils.ALREADY_EXISTS);
+
+            assertTrue(
+                    "Listener was not removed",
+                    mUtils.getCameraService().removeListener(listener) ==
+                    CameraBinderTestUtils.NO_ERROR);
+            assertTrue(
+                    "Listener was wrongly removed again",
+                    mUtils.getCameraService().removeListener(listener) ==
+                    CameraBinderTestUtils.BAD_VALUE);
+        }
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
new file mode 100644
index 0000000..1be2a62
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -0,0 +1,93 @@
+
+package com.android.mediaframeworktest.integration;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+import android.hardware.ICameraService;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+public class CameraBinderTestUtils {
+    private final ICameraService mCameraService;
+    private int mGuessedNumCameras;
+
+    static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
+
+    protected static final int USE_CALLING_UID = -1;
+    protected static final int BAD_VALUE = -22;
+    protected static final int INVALID_OPERATION = -38;
+    protected static final int ALREADY_EXISTS = -17;
+    public static final int NO_ERROR = 0;
+    private final Context mContext;
+
+    public CameraBinderTestUtils(Context context) {
+
+        mContext = context;
+
+        guessNumCameras();
+
+        IBinder cameraServiceBinder = ServiceManager
+                .getService(CameraBinderTestUtils.CAMERA_SERVICE_BINDER_NAME);
+        assertNotNull("Camera service IBinder should not be null", cameraServiceBinder);
+
+        this.mCameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
+        assertNotNull("Camera service should not be null", getCameraService());
+    }
+
+    private void guessNumCameras() {
+
+        /**
+         * Why do we need this? This way we have no dependency on getNumCameras
+         * actually working. On most systems there are only 0, 1, or 2 cameras,
+         * and this covers that 'usual case'. On other systems there might be 3+
+         * cameras, but this will at least check the first 2.
+         */
+        this.mGuessedNumCameras = 0;
+
+        // Front facing camera
+        if (CameraBinderTestUtils.isFeatureAvailable(mContext,
+                PackageManager.FEATURE_CAMERA_FRONT)) {
+            this.mGuessedNumCameras = getGuessedNumCameras() + 1;
+        }
+
+        // Back facing camera
+        if (CameraBinderTestUtils.isFeatureAvailable(mContext,
+                PackageManager.FEATURE_CAMERA)) {
+            this.mGuessedNumCameras = getGuessedNumCameras() + 1;
+        }
+
+        // Any facing camera
+        if (getGuessedNumCameras() == 0
+                && CameraBinderTestUtils.isFeatureAvailable(mContext,
+                        PackageManager.FEATURE_CAMERA_ANY)) {
+            this.mGuessedNumCameras = getGuessedNumCameras() + 1;
+        }
+
+        Log.v(CameraBinderTest.TAG, "Guessing there are at least " + getGuessedNumCameras()
+                + " cameras");
+    }
+
+    final static public boolean isFeatureAvailable(Context context, String feature) {
+        final PackageManager packageManager = context.getPackageManager();
+        final FeatureInfo[] featuresList = packageManager.getSystemAvailableFeatures();
+        for (FeatureInfo f : featuresList) {
+            if (f.name != null && f.name.equals(feature)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    ICameraService getCameraService() {
+        return mCameraService;
+    }
+
+    int getGuessedNumCameras() {
+        return mGuessedNumCameras;
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
new file mode 100644
index 0000000..13ce52e
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -0,0 +1,377 @@
+/*
+ * 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.mediaframeworktest.integration;
+
+import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.BinderHolder;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.view.Surface;
+
+import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW;
+
+import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner;
+
+import org.mockito.ArgumentMatcher;
+import static org.mockito.Mockito.*;
+
+public class CameraDeviceBinderTest extends AndroidTestCase {
+    private static String TAG = "CameraDeviceBinderTest";
+    // Number of streaming callbacks need to check.
+    private static int NUM_CALLBACKS_CHECKED = 10;
+    // Wait for capture result timeout value: 1500ms
+    private final static int WAIT_FOR_COMPLETE_TIMEOUT_MS = 1500;
+    // Default size is VGA, which is mandatory camera supported image size by CDD.
+    private static final int DEFAULT_IMAGE_WIDTH = 640;
+    private static final int DEFAULT_IMAGE_HEIGHT = 480;
+    private static final int MAX_NUM_IMAGES = 5;
+
+    private int mCameraId;
+    private ICameraDeviceUser mCameraUser;
+    private CameraBinderTestUtils mUtils;
+    private ICameraDeviceCallbacks.Stub mMockCb;
+    private Surface mSurface;
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+    ImageReader mImageReader;
+
+    public CameraDeviceBinderTest() {
+    }
+
+    private class ImageDropperListener implements ImageReader.OnImageAvailableListener {
+
+        @Override
+        public void onImageAvailable(ImageReader reader) {
+            Image image = reader.acquireNextImage();
+            if (image != null) image.close();
+        }
+    }
+
+    public class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
+
+        @Override
+        public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
+        }
+
+        @Override
+        public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException {
+        }
+    }
+
+    class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> {
+        @Override
+        public boolean matches(Object obj) {
+            return !((CameraMetadataNative) obj).isEmpty();
+        }
+     }
+
+    private void createDefaultSurface() {
+        mImageReader =
+                ImageReader.newInstance(DEFAULT_IMAGE_WIDTH,
+                        DEFAULT_IMAGE_HEIGHT,
+                        ImageFormat.YUV_420_888,
+                        MAX_NUM_IMAGES);
+        mImageReader.setOnImageAvailableListener(new ImageDropperListener(), mHandler);
+        mSurface = mImageReader.getSurface();
+    }
+
+    private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
+        CameraMetadataNative metadata = new CameraMetadataNative();
+        assertTrue(metadata.isEmpty());
+
+        int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        assertFalse(metadata.isEmpty());
+
+        CaptureRequest.Builder request = new CaptureRequest.Builder(metadata);
+        assertFalse(request.isEmpty());
+        assertFalse(metadata.isEmpty());
+        if (needStream) {
+            int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20,
+                    /* ignored */30, mSurface);
+            assertEquals(0, streamId);
+            request.addTarget(mSurface);
+        }
+        return request;
+    }
+
+    private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
+        int requestId = mCameraUser.submitRequest(request, streaming);
+        assertTrue("Request IDs should be non-negative", requestId >= 0);
+        return requestId;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        /**
+         * Workaround for mockito and JB-MR2 incompatibility
+         *
+         * Avoid java.lang.IllegalArgumentException: dexcache == null
+         * https://code.google.com/p/dexmaker/issues/detail?id=2
+         */
+        System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+        mUtils = new CameraBinderTestUtils(getContext());
+
+        // This cannot be set in the constructor, since the onCreate isn't
+        // called yet
+        mCameraId = MediaFrameworkIntegrationTestRunner.mCameraId;
+
+        ICameraDeviceCallbacks.Stub dummyCallbacks = new DummyCameraDeviceCallbacks();
+
+        String clientPackageName = getContext().getPackageName();
+
+        mMockCb = spy(dummyCallbacks);
+
+        BinderHolder holder = new BinderHolder();
+        mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
+                clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
+        mCameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+        assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        createDefaultSurface();
+
+        Log.v(TAG, String.format("Camera %s connected", mCameraId));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mCameraUser.disconnect();
+        mCameraUser = null;
+        mSurface.release();
+        mImageReader.close();
+        mHandlerThread.quitSafely();
+    }
+
+    @SmallTest
+    public void testCreateDefaultRequest() throws Exception {
+        CameraMetadataNative metadata = new CameraMetadataNative();
+        assertTrue(metadata.isEmpty());
+
+        int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        assertFalse(metadata.isEmpty());
+
+    }
+
+    @SmallTest
+    public void testCreateStream() throws Exception {
+        int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, /* ignored */30,
+                mSurface);
+        assertEquals(0, streamId);
+
+        assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
+                mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface));
+
+        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
+    }
+
+    @SmallTest
+    public void testDeleteInvalidStream() throws Exception {
+        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(-1));
+        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0));
+        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(1));
+        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0xC0FFEE));
+    }
+
+    @SmallTest
+    public void testCreateStreamTwo() throws Exception {
+
+        // Create first stream
+        int streamId = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0,
+                mSurface);
+        assertEquals(0, streamId);
+
+        assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
+                mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface));
+
+        // Create second stream with a different surface.
+        SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
+        surfaceTexture.setDefaultBufferSize(640, 480);
+        Surface surface2 = new Surface(surfaceTexture);
+
+        int streamId2 = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0,
+                surface2);
+        assertEquals(1, streamId2);
+
+        // Clean up streams
+        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
+        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId2));
+    }
+
+    @SmallTest
+    public void testSubmitBadRequest() throws Exception {
+
+        CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
+        CaptureRequest request1 = builder.build();
+        int status = mCameraUser.submitRequest(request1, /* streaming */false);
+        assertEquals("Expected submitRequest to return BAD_VALUE " +
+                "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
+
+        builder.addTarget(mSurface);
+        CaptureRequest request2 = builder.build();
+        status = mCameraUser.submitRequest(request2, /* streaming */false);
+        assertEquals("Expected submitRequest to return BAD_VALUE since " +
+                "the target surface wasn't registered with createStream.",
+                CameraBinderTestUtils.BAD_VALUE, status);
+    }
+
+    @SmallTest
+    public void testSubmitGoodRequest() throws Exception {
+
+        CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+        CaptureRequest request = builder.build();
+
+        // Submit valid request twice.
+        int requestId1 = submitCameraRequest(request, /* streaming */false);
+        int requestId2 = submitCameraRequest(request, /* streaming */false);
+        assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
+
+    }
+
+    @SmallTest
+    public void testSubmitStreamingRequest() throws Exception {
+
+        CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+
+        CaptureRequest request = builder.build();
+
+        // Submit valid request once (non-streaming), and another time
+        // (streaming)
+        int requestId1 = submitCameraRequest(request, /* streaming */false);
+
+        int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
+        assertNotSame("Request IDs should be unique for multiple requests", requestId1,
+                requestIdStreaming);
+
+        int status = mCameraUser.cancelRequest(-1);
+        assertEquals("Invalid request IDs should not be cancellable",
+                CameraBinderTestUtils.BAD_VALUE, status);
+
+        status = mCameraUser.cancelRequest(requestId1);
+        assertEquals("Non-streaming request IDs should not be cancellable",
+                CameraBinderTestUtils.BAD_VALUE, status);
+
+        status = mCameraUser.cancelRequest(requestIdStreaming);
+        assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
+                status);
+
+    }
+
+    @SmallTest
+    public void testCameraInfo() throws RemoteException {
+        CameraMetadataNative info = new CameraMetadataNative();
+
+        int status = mCameraUser.getCameraInfo(/*out*/info);
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+
+        assertFalse(info.isEmpty());
+        assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
+    }
+
+    @SmallTest
+    public void testCameraCharacteristics() throws RemoteException {
+        CameraMetadataNative info = new CameraMetadataNative();
+
+        int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info);
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+
+        assertFalse(info.isEmpty());
+        assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
+    }
+
+    @SmallTest
+    public void testWaitUntilIdle() throws Exception {
+        CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+        int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
+
+        // Test Bad case first: waitUntilIdle when there is active repeating request
+        int status = mCameraUser.waitUntilIdle();
+        assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
+            CameraBinderTestUtils.INVALID_OPERATION, status);
+
+        // Test good case, waitUntilIdle when there is no active repeating request
+        status = mCameraUser.cancelRequest(requestIdStreaming);
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        status = mCameraUser.waitUntilIdle();
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+    }
+
+    @SmallTest
+    public void testCaptureResultCallbacks() throws Exception {
+        IsMetadataNotEmpty matcher = new IsMetadataNotEmpty();
+        CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
+
+        // Test both single request and streaming request.
+        int requestId1 = submitCameraRequest(request, /* streaming */false);
+        verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onResultReceived(
+                eq(requestId1),
+                argThat(matcher));
+
+        int streamingId = submitCameraRequest(request, /* streaming */true);
+        verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
+                .onResultReceived(
+                        eq(streamingId),
+                        argThat(matcher));
+    }
+
+    @SmallTest
+    public void testFlush() throws Exception {
+        int status;
+
+        // Initial flush should work
+        status = mCameraUser.flush();
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+
+        // Then set up a stream
+        CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
+
+        // Flush should still be a no-op, really
+        status = mCameraUser.flush();
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+
+        // Submit a few capture requests
+        int requestId1 = submitCameraRequest(request, /* streaming */false);
+        int requestId2 = submitCameraRequest(request, /* streaming */false);
+        int requestId3 = submitCameraRequest(request, /* streaming */false);
+        int requestId4 = submitCameraRequest(request, /* streaming */false);
+        int requestId5 = submitCameraRequest(request, /* streaming */false);
+
+        // Then flush
+        status = mCameraUser.flush();
+        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+
+        // TODO: When errors are hooked up, count that errors + successful
+        // requests equal to 5.
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 074bfe4..7b2a20e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -61,6 +61,7 @@
     private SurfaceHolder mSurfaceHolder = null;
     private static final int NUM_STRESS_LOOP = 10;
     private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20;
+    private static final int SHORT_WAIT = 2 * 1000; // 2 seconds
     private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds
     private static final String MEDIA_MEMORY_OUTPUT =
         "/sdcard/mediaMemOutput.txt";
@@ -86,9 +87,9 @@
     private Writer mProcMemWriter;
     private Writer mMemWriter;
 
-    private CamcorderProfile mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
-    private int mVideoWidth = mCamcorderProfile.videoFrameWidth;
-    private int mVideoHeight = mCamcorderProfile.videoFrameHeight;
+    private CamcorderProfile mCamcorderProfile;
+    private int mVideoWidth;
+    private int mVideoHeight;
 
     Camera mCamera;
 
@@ -101,8 +102,15 @@
         super.setUp();
         //Insert a 2 second before launching the test activity. This is
         //the workaround for the race condition of requesting the updated surface.
-        Thread.sleep(2000);
+        Thread.sleep(SHORT_WAIT);
         getActivity();
+        //Check if the device support the camcorder
+        mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
+        if (mCamcorderProfile != null) {
+            mVideoWidth = mCamcorderProfile.videoFrameWidth;
+            mVideoHeight = mCamcorderProfile.videoFrameHeight;
+            Log.v(TAG, "height = " + mVideoHeight + " width= " + mVideoWidth);
+        }
         if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
             MediaTestUtil.getNativeHeapDump(this.getName() + "_before");
 
@@ -240,6 +248,8 @@
                 Thread.sleep(MEDIA_STRESS_WAIT_TIME);
                 mRecorder.stop();
                 mRecorder.release();
+                //Insert 2 seconds to make sure the camera released.
+                Thread.sleep(SHORT_WAIT);
             } catch (Exception e) {
                 Log.v("record video failed ", e.toString());
                 mRecorder.release();
@@ -332,7 +342,7 @@
         // USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
         // media     131   1     13676  4796  ffffffff 400b1bd0 S media.log
         // media     219   131   37768  6892  ffffffff 400b236c S /system/bin/mediaserver
-        String memusage = poList[2].concat("\n");
+        String memusage = poList[poList.length-1].concat("\n");
         return memusage;
     }
 
@@ -410,59 +420,65 @@
     // Test case 4: Capture the memory usage after every 20 video only recorded
     @LargeTest
     public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
-        boolean memoryResult = false;
-        mStartPid = getMediaserverPid();
-        int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
-        assertTrue("H263 video recording frame rate", frameRate != -1);
-        for (int i = 0; i < NUM_STRESS_LOOP; i++) {
-            assertTrue(stressVideoRecord(frameRate, mVideoWidth, mVideoHeight,
-                    MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4,
-                    MediaNames.RECORDED_VIDEO_3GP, true));
-            getMemoryWriteToLog(i);
-            writeProcmemInfo();
+        if (mCamcorderProfile != null) {
+            boolean memoryResult = false;
+            mStartPid = getMediaserverPid();
+            int frameRate = MediaProfileReader
+                    .getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
+            assertTrue("H263 video recording frame rate", frameRate != -1);
+            for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+                assertTrue(stressVideoRecord(frameRate, mVideoWidth, mVideoHeight,
+                        MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4,
+                        MediaNames.RECORDED_VIDEO_3GP, true));
+                getMemoryWriteToLog(i);
+                writeProcmemInfo();
+            }
+            memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
+            assertTrue("H263 record only memory test", memoryResult);
         }
-        memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
-        assertTrue("H263 record only memory test", memoryResult);
     }
 
     // Test case 5: Capture the memory usage after every 20 video only recorded
     @LargeTest
     public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception {
-        boolean memoryResult = false;
-
-        mStartPid = getMediaserverPid();
-        int frameRate = MediaProfileReader.getMaxFrameRateForCodec
-                (MediaRecorder.VideoEncoder.MPEG_4_SP);
-        assertTrue("MPEG4 video recording frame rate", frameRate != -1);
-        for (int i = 0; i < NUM_STRESS_LOOP; i++) {
-            assertTrue(stressVideoRecord(frameRate, mVideoWidth, mVideoHeight,
-                    MediaRecorder.VideoEncoder.MPEG_4_SP, MediaRecorder.OutputFormat.MPEG_4,
-                    MediaNames.RECORDED_VIDEO_3GP, true));
-            getMemoryWriteToLog(i);
-            writeProcmemInfo();
+        if (mCamcorderProfile != null) {
+            boolean memoryResult = false;
+            mStartPid = getMediaserverPid();
+            int frameRate = MediaProfileReader.getMaxFrameRateForCodec
+                    (MediaRecorder.VideoEncoder.MPEG_4_SP);
+            assertTrue("MPEG4 video recording frame rate", frameRate != -1);
+            for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+                assertTrue(stressVideoRecord(frameRate, mVideoWidth, mVideoHeight,
+                        MediaRecorder.VideoEncoder.MPEG_4_SP, MediaRecorder.OutputFormat.MPEG_4,
+                        MediaNames.RECORDED_VIDEO_3GP, true));
+                getMemoryWriteToLog(i);
+                writeProcmemInfo();
+            }
+            memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
+            assertTrue("mpeg4 record only memory test", memoryResult);
         }
-        memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
-        assertTrue("mpeg4 record only memory test", memoryResult);
     }
 
     // Test case 6: Capture the memory usage after every 20 video and audio
     // recorded
     @LargeTest
     public void testRecordVideoAudioMemoryUsage() throws Exception {
-        boolean memoryResult = false;
-
-        mStartPid = getMediaserverPid();
-        int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
-        assertTrue("H263 video recording frame rate", frameRate != -1);
-        for (int i = 0; i < NUM_STRESS_LOOP; i++) {
-            assertTrue(stressVideoRecord(frameRate, mVideoWidth, mVideoHeight,
-                    MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4,
-                    MediaNames.RECORDED_VIDEO_3GP, false));
-            getMemoryWriteToLog(i);
-            writeProcmemInfo();
+        if (mCamcorderProfile != null) {
+            boolean memoryResult = false;
+            mStartPid = getMediaserverPid();
+            int frameRate = MediaProfileReader
+                    .getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
+            assertTrue("H263 video recording frame rate", frameRate != -1);
+            for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+                assertTrue(stressVideoRecord(frameRate, mVideoWidth, mVideoHeight,
+                        MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4,
+                        MediaNames.RECORDED_VIDEO_3GP, false));
+                getMemoryWriteToLog(i);
+                writeProcmemInfo();
+            }
+            memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
+            assertTrue("H263 audio video record memory test", memoryResult);
         }
-        memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
-        assertTrue("H263 audio video record memory test", memoryResult);
     }
 
     // Test case 7: Capture the memory usage after every 20 audio only recorded
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
new file mode 100644
index 0000000..874e078
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -0,0 +1,526 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.Rational;
+import android.hardware.camera2.Size;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * <pre>
+ * adb shell am instrument \
+ *      -e class 'com.android.mediaframeworktest.unit.CameraMetadataTest' \
+ *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
+ * </pre>
+ */
+public class CameraMetadataTest extends junit.framework.TestCase {
+
+    CameraMetadataNative mMetadata;
+    Parcel mParcel;
+
+    // Sections
+    static final int ANDROID_COLOR_CORRECTION = 0;
+    static final int ANDROID_CONTROL = 1;
+
+    // Section starts
+    static final int ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16;
+    static final int ANDROID_CONTROL_START = ANDROID_CONTROL << 16;
+
+    // Tags
+    static final int ANDROID_COLOR_CORRECTION_MODE = ANDROID_COLOR_CORRECTION_START;
+    static final int ANDROID_COLOR_CORRECTION_TRANSFORM = ANDROID_COLOR_CORRECTION_START + 1;
+
+    static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START;
+    static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1;
+
+    @Override
+    public void setUp() {
+        mMetadata = new CameraMetadataNative();
+        mParcel = Parcel.obtain();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mMetadata = null;
+
+        mParcel.recycle();
+        mParcel = null;
+    }
+
+    @SmallTest
+    public void testNew() {
+        assertEquals(0, mMetadata.getEntryCount());
+        assertTrue(mMetadata.isEmpty());
+    }
+
+    @SmallTest
+    public void testGetTagFromKey() {
+
+        // Test success
+
+        assertEquals(ANDROID_COLOR_CORRECTION_MODE,
+                CameraMetadataNative.getTag("android.colorCorrection.mode"));
+        assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM,
+                CameraMetadataNative.getTag("android.colorCorrection.transform"));
+        assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+                CameraMetadataNative.getTag("android.control.aeAntibandingMode"));
+        assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+                CameraMetadataNative.getTag("android.control.aeExposureCompensation"));
+
+        // Test failures
+
+        try {
+            CameraMetadataNative.getTag(null);
+            fail("A null key should throw NPE");
+        } catch(NullPointerException e) {
+        }
+
+        try {
+            CameraMetadataNative.getTag("android.control");
+            fail("A section name only should not be a valid key");
+        } catch(IllegalArgumentException e) {
+        }
+
+        try {
+            CameraMetadataNative.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
+            fail("A valid section with an invalid tag name should not be a valid key");
+        } catch(IllegalArgumentException e) {
+        }
+
+        try {
+            CameraMetadataNative.getTag("android");
+            fail("A namespace name only should not be a valid key");
+        } catch(IllegalArgumentException e) {
+        }
+
+        try {
+            CameraMetadataNative.getTag("this.key.is.definitely.invalid");
+            fail("A completely fake key name should not be valid");
+        } catch(IllegalArgumentException e) {
+        }
+    }
+
+    @SmallTest
+    public void testGetTypeFromTag() {
+        assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
+        assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
+        assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
+        assertEquals(TYPE_INT32,
+                CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
+
+        try {
+            CameraMetadataNative.getNativeType(0xDEADF00D);
+            fail("No type should exist for invalid tag 0xDEADF00D");
+        } catch(IllegalArgumentException e) {
+        }
+    }
+
+    @SmallTest
+    public void testReadWriteValues() {
+        final byte ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
+        byte[] valueResult;
+
+        assertEquals(0, mMetadata.getEntryCount());
+        assertEquals(true, mMetadata.isEmpty());
+
+        //
+        // android.colorCorrection.mode (single enum byte)
+        //
+
+        assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
+
+        // Write/read null values
+        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, null);
+        assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
+
+        // Write 0 values
+        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {});
+
+        // Read 0 values
+        valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
+        assertNotNull(valueResult);
+        assertEquals(0, valueResult.length);
+
+        assertEquals(1, mMetadata.getEntryCount());
+        assertEquals(false, mMetadata.isEmpty());
+
+        // Write 1 value
+        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {
+            ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY
+        });
+
+        // Read 1 value
+        valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
+        assertNotNull(valueResult);
+        assertEquals(1, valueResult.length);
+        assertEquals(ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY, valueResult[0]);
+
+        assertEquals(1, mMetadata.getEntryCount());
+        assertEquals(false, mMetadata.isEmpty());
+
+        //
+        // android.colorCorrection.transform (3x3 matrix)
+        //
+
+        final float[] transformMatrix = new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+        byte[] transformMatrixAsByteArray = new byte[transformMatrix.length * 4];
+        ByteBuffer transformMatrixByteBuffer =
+                ByteBuffer.wrap(transformMatrixAsByteArray).order(ByteOrder.nativeOrder());
+        for (float f : transformMatrix)
+            transformMatrixByteBuffer.putFloat(f);
+
+        // Read
+        assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_TRANSFORM));
+        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_TRANSFORM, transformMatrixAsByteArray);
+
+        // Write
+        assertArrayEquals(transformMatrixAsByteArray,
+                mMetadata.readValues(ANDROID_COLOR_CORRECTION_TRANSFORM));
+
+        assertEquals(2, mMetadata.getEntryCount());
+        assertEquals(false, mMetadata.isEmpty());
+
+        // Erase
+        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_TRANSFORM, null);
+        assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_TRANSFORM));
+        assertEquals(1, mMetadata.getEntryCount());
+    }
+
+    private static <T> void assertArrayEquals(T expected, T actual) {
+        assertEquals(Array.getLength(expected), Array.getLength(actual));
+
+        int len = Array.getLength(expected);
+        for (int i = 0; i < len; ++i) {
+            assertEquals(Array.get(expected, i), Array.get(actual, i));
+        }
+    }
+
+    private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
+        assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray());
+
+        Key<T> key = new Key<T>(keyStr, type);
+        assertNull(mMetadata.get(key));
+        mMetadata.set(key, null);
+        assertNull(mMetadata.get(key));
+        mMetadata.set(key, value);
+
+        T actual = mMetadata.get(key);
+        assertEquals(value, actual);
+    }
+
+    private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
+        assertTrue(type.isArray());
+
+        Key<T> key = new Key<T>(keyStr, type);
+        assertNull(mMetadata.get(key));
+        mMetadata.set(key, value);
+        assertArrayEquals(value, mMetadata.get(key));
+    }
+
+    @SmallTest
+    public void testReadWritePrimitive() {
+        // int32 (single)
+        checkKeyGetAndSet("android.control.aeExposureCompensation", Integer.TYPE, 0xC0FFEE);
+
+        // byte (single)
+        checkKeyGetAndSet("android.flash.maxEnergy", Byte.TYPE, (byte)6);
+
+        // int64 (single)
+        checkKeyGetAndSet("android.flash.firingTime", Long.TYPE, 0xABCD12345678FFFFL);
+
+        // float (single)
+        checkKeyGetAndSet("android.lens.aperture", Float.TYPE, Float.MAX_VALUE);
+
+        // double (single) -- technically double x 3, but we fake it
+        checkKeyGetAndSet("android.jpeg.gpsCoordinates", Double.TYPE, Double.MAX_VALUE);
+
+        // rational (single)
+        checkKeyGetAndSet("android.sensor.baseGainFactor", Rational.class, new Rational(1, 2));
+
+        /**
+         * Weirder cases, that don't map 1:1 with the native types
+         */
+
+        // bool (single) -- with TYPE_BYTE
+        checkKeyGetAndSet("android.control.aeLock", Boolean.TYPE, true);
+
+        // integer (single) -- with TYPE_BYTE
+        checkKeyGetAndSet("android.control.aePrecaptureTrigger", Integer.TYPE, 6);
+    }
+
+    @SmallTest
+    public void testReadWritePrimitiveArray() {
+        // int32 (n)
+        checkKeyGetAndSetArray("android.sensor.info.availableSensitivities", int[].class,
+                new int[] {
+                        0xC0FFEE, 0xDEADF00D
+                });
+
+        // byte (n)
+        checkKeyGetAndSetArray("android.statistics.faceScores", byte[].class, new byte[] {
+                1, 2, 3, 4
+        });
+
+        // int64 (n)
+        checkKeyGetAndSetArray("android.scaler.availableProcessedMinDurations", long[].class,
+                new long[] {
+                        0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
+                });
+
+        // float (n)
+        checkKeyGetAndSetArray("android.lens.info.availableApertures", float[].class,
+                new float[] {
+                        Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
+                });
+
+        // double (n) -- in particular double x 3
+        checkKeyGetAndSetArray("android.jpeg.gpsCoordinates", double[].class,
+                new double[] {
+                        Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
+                });
+
+        // rational (n) -- in particular rational x 9
+        checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
+                new Rational[] {
+                        new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
+                        new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
+                        new Rational(12, 13), new Rational(14, 15), new Rational(15, 16)
+                });
+
+        /**
+         * Weirder cases, that don't map 1:1 with the native types
+         */
+
+        // bool (n) -- with TYPE_BYTE
+        checkKeyGetAndSetArray("android.control.aeLock", boolean[].class, new boolean[] {
+                true, false, true
+        });
+
+
+        // integer (n) -- with TYPE_BYTE
+        checkKeyGetAndSetArray("android.control.aeAvailableModes", int[].class, new int[] {
+            1, 2, 3, 4
+        });
+    }
+
+    private enum ColorCorrectionMode {
+        TRANSFORM_MATRIX,
+        FAST,
+        HIGH_QUALITY
+    }
+
+    private enum AeAntibandingMode {
+        OFF,
+        _50HZ,
+        _60HZ,
+        AUTO
+    }
+
+    // TODO: special values for the enum.
+    private enum AvailableFormat {
+        RAW_SENSOR,
+        YV12,
+        YCrCb_420_SP,
+        IMPLEMENTATION_DEFINED,
+        YCbCr_420_888,
+        BLOB
+    }
+
+    @SmallTest
+    public void testReadWriteEnum() {
+        // byte (single)
+        checkKeyGetAndSet("android.colorCorrection.mode", ColorCorrectionMode.class,
+                ColorCorrectionMode.HIGH_QUALITY);
+
+        // byte (single)
+        checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
+                AeAntibandingMode.AUTO);
+
+        // byte (n)
+        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
+                AeAntibandingMode[].class, new AeAntibandingMode[] {
+                        AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
+                        AeAntibandingMode.AUTO
+                });
+
+        /**
+         * Stranger cases that don't use byte enums
+         */
+        // int (n)
+        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
+                new AvailableFormat[] {
+                        AvailableFormat.RAW_SENSOR,
+                        AvailableFormat.YV12,
+                        AvailableFormat.IMPLEMENTATION_DEFINED
+                });
+
+    }
+
+    @SmallTest
+    public void testReadWriteEnumWithCustomValues() {
+        CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
+            0,
+            10,
+            20,
+            30
+        });
+
+        // byte (single)
+        checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
+                AeAntibandingMode.AUTO);
+
+        // byte (n)
+        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
+                AeAntibandingMode[].class, new AeAntibandingMode[] {
+                        AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
+                        AeAntibandingMode.AUTO
+                });
+
+        Key<AeAntibandingMode[]> aeAntibandingModeKey =
+                new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
+                        AeAntibandingMode[].class);
+        byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
+                .getTag("android.control.aeAvailableAntibandingModes"));
+        byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
+        assertArrayEquals(expectedValues, aeAntibandingModeValues);
+
+
+        /**
+         * Stranger cases that don't use byte enums
+         */
+        // int (n)
+        CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
+            0x20,
+            0x32315659,
+            0x11,
+            0x22,
+            0x23,
+            0x21,
+        });
+
+        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
+                new AvailableFormat[] {
+                        AvailableFormat.RAW_SENSOR,
+                        AvailableFormat.YV12,
+                        AvailableFormat.IMPLEMENTATION_DEFINED,
+                        AvailableFormat.YCbCr_420_888
+                });
+
+        Key<AeAntibandingMode> availableFormatsKey =
+                new Key<AeAntibandingMode>("android.scaler.availableFormats",
+                        AeAntibandingMode.class);
+        byte[] availableFormatValues = mMetadata.readValues(CameraMetadataNative
+                .getTag(availableFormatsKey.getName()));
+
+        int[] expectedIntValues = new int[] {
+                0x20,
+                0x32315659,
+                0x22,
+                0x23
+        };
+
+        ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
+
+        assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
+        for (int i = 0; i < expectedIntValues.length; ++i) {
+            assertEquals(expectedIntValues[i], bf.getInt());
+        }
+    }
+
+    @SmallTest
+    public void testReadWriteSize() {
+        // int32 x n
+        checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
+
+        // int32 x 2 x n
+        checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] {
+            new Size(123, 456),
+            new Size(0xDEAD, 0xF00D),
+            new Size(0xF00, 0xB00)
+        });
+    }
+
+    @SmallTest
+    public void testReadWriteRectangle() {
+        // int32 x n
+        checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024));
+
+        // int32 x 2 x n
+        checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] {
+            new Rect(110, 111, 11280, 11024),
+            new Rect(210, 111, 21280, 21024),
+            new Rect(310, 111, 31280, 31024)
+        });
+    }
+
+    @SmallTest
+    public void testReadWriteString() {
+        // (byte) string
+        Key<String> gpsProcessingMethodKey =
+                new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
+
+        String helloWorld = new String("HelloWorld");
+        byte[] helloWorldBytes = new byte[] {
+                'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0' };
+
+        mMetadata.set(gpsProcessingMethodKey, helloWorld);
+
+        String actual = mMetadata.get(gpsProcessingMethodKey);
+        assertEquals(helloWorld, actual);
+
+        byte[] actualBytes = mMetadata.readValues(getTag(gpsProcessingMethodKey.getName()));
+        assertArrayEquals(helloWorldBytes, actualBytes);
+
+        // Does not yet test as a string[] since we don't support that in native code.
+
+        // (byte) string
+        Key<String[]> gpsProcessingMethodKeyArray =
+                new Key<String[]>("android.jpeg.gpsProcessingMethod", String[].class);
+
+        String[] gpsStrings = new String[] { "HelloWorld", "FooBar", "Shazbot" };
+        byte[] gpsBytes = new byte[] {
+                'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0',
+                'F', 'o', 'o', 'B', 'a', 'r', '\0',
+                'S', 'h', 'a', 'z', 'b', 'o', 't', '\0'};
+
+        mMetadata.set(gpsProcessingMethodKeyArray, gpsStrings);
+
+        String[] actualArray = mMetadata.get(gpsProcessingMethodKeyArray);
+        assertArrayEquals(gpsStrings, actualArray);
+
+        byte[] actualBytes2 = mMetadata.readValues(getTag(gpsProcessingMethodKeyArray.getName()));
+        assertArrayEquals(gpsBytes, actualBytes2);
+    }
+
+    <T> void compareGeneric(T expected, T actual) {
+        assertEquals(expected, actual);
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
new file mode 100644
index 0000000..727af78
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.camera2.utils.CameraRuntimeException;
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.os.TransactionTooLargeException;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.mockito.Mockito.*;
+import static android.hardware.camera2.utils.CameraBinderDecorator.*;
+import static android.hardware.camera2.CameraAccessException.*;
+
+import junit.framework.Assert;
+
+public class CameraUtilsBinderDecoratorTest extends junit.framework.TestCase {
+
+    private interface ICameraBinderStereotype {
+
+        double doNothing();
+
+        // int is a 'status_t'
+        int doSomethingPositive();
+
+        int doSomethingNoError();
+
+        int doSomethingPermissionDenied();
+
+        int doSomethingAlreadyExists();
+
+        int doSomethingBadValue();
+
+        int doSomethingDeadObject() throws CameraRuntimeException;
+
+        int doSomethingBadPolicy() throws CameraRuntimeException;
+
+        int doSomethingDeviceBusy() throws CameraRuntimeException;
+
+        int doSomethingNoSuchDevice() throws CameraRuntimeException;
+
+        int doSomethingUnknownErrorCode();
+
+        int doSomethingThrowDeadObjectException() throws RemoteException;
+
+        int doSomethingThrowTransactionTooLargeException() throws RemoteException;
+    }
+
+    private static final double SOME_ARBITRARY_DOUBLE = 1.0;
+    private static final int SOME_ARBITRARY_POSITIVE_INT = 5;
+    private static final int SOME_ARBITRARY_NEGATIVE_INT = -0xC0FFEE;
+
+    @SmallTest
+    public void testStereotypes() {
+
+        ICameraBinderStereotype mock = mock(ICameraBinderStereotype.class);
+        try {
+            when(mock.doNothing()).thenReturn(SOME_ARBITRARY_DOUBLE);
+            when(mock.doSomethingPositive()).thenReturn(SOME_ARBITRARY_POSITIVE_INT);
+            when(mock.doSomethingNoError()).thenReturn(NO_ERROR);
+            when(mock.doSomethingPermissionDenied()).thenReturn(PERMISSION_DENIED);
+            when(mock.doSomethingAlreadyExists()).thenReturn(ALREADY_EXISTS);
+            when(mock.doSomethingBadValue()).thenReturn(BAD_VALUE);
+            when(mock.doSomethingDeadObject()).thenReturn(DEAD_OBJECT);
+            when(mock.doSomethingBadPolicy()).thenReturn(EACCES);
+            when(mock.doSomethingDeviceBusy()).thenReturn(EBUSY);
+            when(mock.doSomethingNoSuchDevice()).thenReturn(ENODEV);
+            when(mock.doSomethingUnknownErrorCode()).thenReturn(SOME_ARBITRARY_NEGATIVE_INT);
+            when(mock.doSomethingThrowDeadObjectException()).thenThrow(new DeadObjectException());
+            when(mock.doSomethingThrowTransactionTooLargeException()).thenThrow(
+                    new TransactionTooLargeException());
+        } catch (RemoteException e) {
+            Assert.fail("Unreachable");
+        }
+
+        ICameraBinderStereotype decoratedMock = CameraBinderDecorator.newInstance(mock);
+
+        // ignored by decorator because return type is double, not int
+        assertEquals(SOME_ARBITRARY_DOUBLE, decoratedMock.doNothing());
+
+        // pass through for positive values
+        assertEquals(SOME_ARBITRARY_POSITIVE_INT, decoratedMock.doSomethingPositive());
+
+        // pass through NO_ERROR
+        assertEquals(NO_ERROR, decoratedMock.doSomethingNoError());
+
+        try {
+            decoratedMock.doSomethingPermissionDenied();
+            Assert.fail("Should've thrown SecurityException");
+        } catch (SecurityException e) {
+        }
+
+        assertEquals(ALREADY_EXISTS, decoratedMock.doSomethingAlreadyExists());
+
+        try {
+            decoratedMock.doSomethingBadValue();
+            Assert.fail("Should've thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            decoratedMock.doSomethingDeadObject();
+            Assert.fail("Should've thrown CameraRuntimeException");
+        } catch (CameraRuntimeException e) {
+            assertEquals(CAMERA_DISCONNECTED, e.getReason());
+        }
+
+        try {
+            decoratedMock.doSomethingBadPolicy();
+            Assert.fail("Should've thrown CameraRuntimeException");
+        } catch (CameraRuntimeException e) {
+            assertEquals(CAMERA_DISABLED, e.getReason());
+        }
+
+        try {
+            decoratedMock.doSomethingDeviceBusy();
+            Assert.fail("Should've thrown CameraRuntimeException");
+        } catch (CameraRuntimeException e) {
+            assertEquals(CAMERA_IN_USE, e.getReason());
+        }
+
+        try {
+            decoratedMock.doSomethingNoSuchDevice();
+            Assert.fail("Should've thrown CameraRuntimeException");
+        } catch (CameraRuntimeException e) {
+            assertEquals(CAMERA_DISCONNECTED, e.getReason());
+        }
+
+        try {
+            decoratedMock.doSomethingUnknownErrorCode();
+            Assert.fail("Should've thrown UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            assertEquals(String.format("Unknown error %d",
+                    SOME_ARBITRARY_NEGATIVE_INT), e.getMessage());
+        }
+
+        try {
+            decoratedMock.doSomethingThrowDeadObjectException();
+            Assert.fail("Should've thrown CameraRuntimeException");
+        } catch (CameraRuntimeException e) {
+            assertEquals(CAMERA_DISCONNECTED, e.getReason());
+        } catch (RemoteException e) {
+            Assert.fail("Should not throw a DeadObjectException directly, but rethrow");
+        }
+
+        try {
+            decoratedMock.doSomethingThrowTransactionTooLargeException();
+            Assert.fail("Should've thrown UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            assertTrue(e.getCause() instanceof TransactionTooLargeException);
+        } catch (RemoteException e) {
+            Assert.fail("Should not throw a TransactionTooLargeException directly, but rethrow");
+        }
+    }
+
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
new file mode 100644
index 0000000..c3b6006
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.hardware.camera2.utils.*;
+import android.hardware.camera2.utils.Decorator.DecoratorListener;
+
+import junit.framework.Assert;
+
+import java.lang.reflect.Method;
+
+/**
+ * adb shell am instrument -e class 'com.android.mediaframeworktest.unit.CameraUtilsDecoratorTest' \
+ *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
+ */
+public class CameraUtilsDecoratorTest extends junit.framework.TestCase {
+    private DummyListener mDummyListener;
+    private DummyInterface mIface;
+
+    @Override
+    public void setUp() {
+        mDummyListener = new DummyListener();
+        mIface = Decorator.newInstance(new DummyImpl(), mDummyListener);
+    }
+
+    interface DummyInterface {
+        int addValues(int x, int y, int z);
+
+        void raiseException() throws Exception;
+
+        void raiseUnsupportedOperationException() throws UnsupportedOperationException;
+    }
+
+    class DummyImpl implements DummyInterface {
+        @Override
+        public int addValues(int x, int y, int z) {
+            return x + y + z;
+        }
+
+        @Override
+        public void raiseException() throws Exception {
+            throw new Exception("Test exception");
+        }
+
+        @Override
+        public void raiseUnsupportedOperationException() throws UnsupportedOperationException {
+            throw new UnsupportedOperationException("Test exception");
+        }
+    }
+
+    class DummyListener implements DecoratorListener {
+
+        public boolean beforeCalled = false;
+        public boolean afterCalled = false;
+        public boolean catchCalled = false;
+        public boolean finallyCalled = false;
+        public Object resultValue = null;
+
+        public boolean raiseException = false;
+
+        @Override
+        public void onBeforeInvocation(Method m, Object[] args) {
+            beforeCalled = true;
+        }
+
+        @Override
+        public void onAfterInvocation(Method m, Object[] args, Object result) {
+            afterCalled = true;
+            resultValue = result;
+
+            if (raiseException) {
+                throw new UnsupportedOperationException("Test exception");
+            }
+        }
+
+        @Override
+        public boolean onCatchException(Method m, Object[] args, Throwable t) {
+            catchCalled = true;
+            return false;
+        }
+
+        @Override
+        public void onFinally(Method m, Object[] args) {
+            finallyCalled = true;
+        }
+
+    };
+
+    @SmallTest
+    public void testDecorator() {
+
+        // TODO rewrite this using mocks
+
+        assertTrue(mIface.addValues(1, 2, 3) == 6);
+        assertTrue(mDummyListener.beforeCalled);
+        assertTrue(mDummyListener.afterCalled);
+
+        int resultValue = (Integer)mDummyListener.resultValue;
+        assertTrue(resultValue == 6);
+        assertTrue(mDummyListener.finallyCalled);
+        assertFalse(mDummyListener.catchCalled);
+    }
+
+    @SmallTest
+    public void testDecoratorExceptions() {
+
+        boolean gotExceptions = false;
+        try {
+            mIface.raiseException();
+        } catch (Exception e) {
+            gotExceptions = true;
+            assertTrue(e.getMessage() == "Test exception");
+        }
+        assertTrue(gotExceptions);
+        assertTrue(mDummyListener.beforeCalled);
+        assertFalse(mDummyListener.afterCalled);
+        assertTrue(mDummyListener.catchCalled);
+        assertTrue(mDummyListener.finallyCalled);
+    }
+
+    @SmallTest
+    public void testDecoratorUnsupportedOperationException() {
+
+        boolean gotExceptions = false;
+        try {
+            mIface.raiseUnsupportedOperationException();
+        } catch (UnsupportedOperationException e) {
+            gotExceptions = true;
+            assertTrue(e.getMessage() == "Test exception");
+        }
+        assertTrue(gotExceptions);
+        assertTrue(mDummyListener.beforeCalled);
+        assertFalse(mDummyListener.afterCalled);
+        assertTrue(mDummyListener.catchCalled);
+        assertTrue(mDummyListener.finallyCalled);
+    }
+
+    @SmallTest
+    public void testDecoratorRaisesException() {
+
+        boolean gotExceptions = false;
+        try {
+            mDummyListener.raiseException = true;
+            mIface.addValues(1, 2, 3);
+            Assert.fail("unreachable");
+        } catch (UnsupportedOperationException e) {
+            gotExceptions = true;
+            assertTrue(e.getMessage() == "Test exception");
+        }
+        assertTrue(gotExceptions);
+        assertTrue(mDummyListener.beforeCalled);
+        assertTrue(mDummyListener.afterCalled);
+        assertFalse(mDummyListener.catchCalled);
+        assertTrue(mDummyListener.finallyCalled);
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
new file mode 100644
index 0000000..02c9f2a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.UncheckedThrow;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.Assert;
+
+public class CameraUtilsRuntimeExceptionTest extends junit.framework.TestCase {
+
+    @SmallTest
+    public void testCameraRuntimeException1() {
+        try {
+            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345);
+            throw runtimeExc.asChecked();
+        } catch (CameraAccessException e) {
+            assertEquals(12345, e.getReason());
+            assertNull(e.getMessage());
+            assertNull(e.getCause());
+        }
+    }
+
+    @SmallTest
+    public void testCameraRuntimeException2() {
+        try {
+            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello");
+            throw runtimeExc.asChecked();
+        } catch (CameraAccessException e) {
+            assertEquals(12345, e.getReason());
+            assertEquals("Hello", e.getMessage());
+            assertNull(e.getCause());
+        }
+    }
+
+    @SmallTest
+    public void testCameraRuntimeException3() {
+        Throwable cause = new IllegalStateException("For great justice");
+        try {
+            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, cause);
+            throw runtimeExc.asChecked();
+        } catch (CameraAccessException e) {
+            assertEquals(12345, e.getReason());
+            assertNull(e.getMessage());
+            assertEquals(cause, e.getCause());
+        }
+    }
+
+    @SmallTest
+    public void testCameraRuntimeException4() {
+        Throwable cause = new IllegalStateException("For great justice");
+        try {
+            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello", cause);
+            throw runtimeExc.asChecked();
+        } catch (CameraAccessException e) {
+            assertEquals(12345, e.getReason());
+            assertEquals("Hello", e.getMessage());
+            assertEquals(cause, e.getCause());
+        }
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
new file mode 100644
index 0000000..b648763
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.utils.UncheckedThrow;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.Assert;
+
+public class CameraUtilsUncheckedThrowTest extends junit.framework.TestCase {
+
+    private void fakeNeverThrowsCameraAccess() throws CameraAccessException {
+    }
+
+    @SmallTest
+    public void testUncheckedThrow() {
+        try {
+            UncheckedThrow.throwAnyException(new CameraAccessException(
+                    CameraAccessException.CAMERA_DISCONNECTED));
+            Assert.fail("unreachable");
+            fakeNeverThrowsCameraAccess();
+        } catch (CameraAccessException e) {
+        }
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
new file mode 100644
index 0000000..f6cd990
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import static org.mockito.Mockito.*;
+
+import android.graphics.ImageFormat;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.media.ImageReader.OnImageAvailableListener;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ImageReaderTest extends AndroidTestCase {
+
+    private static final String TAG = "ImageReaderTest-unit";
+
+    private static final int DEFAULT_WIDTH = 640;
+    private static final int DEFAULT_HEIGHT = 480;
+    private static final int DEFAULT_FORMAT = ImageFormat.YUV_420_888;
+    private static final int DEFAULT_MAX_IMAGES = 3;
+
+    private ImageReader mReader;
+    private Image mImage1;
+    private Image mImage2;
+    private Image mImage3;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        /**
+         * Workaround for mockito and JB-MR2 incompatibility
+         *
+         * Avoid java.lang.IllegalArgumentException: dexcache == null
+         * https://code.google.com/p/dexmaker/issues/detail?id=2
+         */
+        System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+
+        // TODO: refactor above into one of the test runners
+
+        mReader = spy(ImageReader.newInstance(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                DEFAULT_MAX_IMAGES));
+        mImage1 = mock(Image.class);
+        mImage2 = mock(Image.class);
+        mImage3 = mock(Image.class);
+
+        /**
+         * Ensure rest of classes are mockable
+         */
+        {
+            mock(Plane.class);
+            mock(OnImageAvailableListener.class);
+        }
+
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mReader.close();
+
+        super.tearDown();
+    }
+
+    /**
+     * Return null when there is nothing in the image queue.
+     */
+    @SmallTest
+    public void testGetLatestImageEmpty() {
+        when(mReader.acquireNextImage()).thenReturn(null);
+        when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+        assertEquals(null, mReader.acquireLatestImage());
+    }
+
+    /**
+     * Return the last image from the image queue, close up the rest.
+     */
+    @SmallTest
+    public void testGetLatestImage1() {
+        when(mReader.acquireNextImage()).thenReturn(mImage1);
+        when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+        assertEquals(mImage1, mReader.acquireLatestImage());
+        verify(mImage1, never()).close();
+    }
+
+    /**
+     * Return the last image from the image queue, close up the rest.
+     */
+    @SmallTest
+    public void testGetLatestImage2() {
+        when(mReader.acquireNextImage()).thenReturn(mImage1);
+        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).thenReturn(null);
+        assertEquals(mImage2, mReader.acquireLatestImage());
+        verify(mImage1, atLeastOnce()).close();
+        verify(mImage2, never()).close();
+    }
+
+    /**
+     * Return the last image from the image queue, close up the rest.
+     */
+    @SmallTest
+    public void testGetLatestImage3() {
+        when(mReader.acquireNextImage()).thenReturn(mImage1);
+        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+                                                   thenReturn(mImage3).
+                                                   thenReturn(null);
+        assertEquals(mImage3, mReader.acquireLatestImage());
+        verify(mImage1, atLeastOnce()).close();
+        verify(mImage2, atLeastOnce()).close();
+        verify(mImage3, never()).close();
+    }
+
+    /**
+     * Return null if get a IllegalStateException with no images in the queue.
+     */
+    @SmallTest
+    public void testGetLatestImageTooManyBuffersAcquiredEmpty()  {
+        when(mReader.acquireNextImage()).thenThrow(new IllegalStateException());
+        try {
+            mReader.acquireLatestImage();
+            fail("Expected IllegalStateException to be thrown");
+        } catch(IllegalStateException e) {
+        }
+    }
+
+    /**
+     * All images are cleaned up when we get an unexpected Error.
+     */
+    @SmallTest
+    public void testGetLatestImageExceptionalError() {
+        when(mReader.acquireNextImage()).thenReturn(mImage1);
+        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+                                                   thenReturn(mImage3).
+                                                   thenThrow(new OutOfMemoryError());
+        try {
+            mReader.acquireLatestImage();
+            fail("Impossible");
+        } catch(OutOfMemoryError e) {
+        }
+
+        verify(mImage1, atLeastOnce()).close();
+        verify(mImage2, atLeastOnce()).close();
+        verify(mImage3, atLeastOnce()).close();
+    }
+
+    /**
+     * All images are cleaned up when we get an unexpected RuntimeException.
+     */
+    @SmallTest
+    public void testGetLatestImageExceptionalRuntime() {
+
+        when(mReader.acquireNextImage()).thenReturn(mImage1);
+        when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+                                                   thenReturn(mImage3).
+                                                   thenThrow(new RuntimeException());
+        try {
+            mReader.acquireLatestImage();
+            fail("Impossible");
+        } catch(RuntimeException e) {
+        }
+
+        verify(mImage1, atLeastOnce()).close();
+        verify(mImage2, atLeastOnce()).close();
+        verify(mImage3, atLeastOnce()).close();
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
new file mode 100644
index 0000000..9621f92
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.hardware.camera2.Rational;
+
+/**
+ * <pre>
+ * adb shell am instrument \
+ *      -e class 'com.android.mediaframeworktest.unit.RationalTest' \
+ *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
+ * </pre>
+ */
+public class RationalTest extends junit.framework.TestCase {
+    @SmallTest
+    public void testConstructor() {
+
+        // Simple case
+        Rational r = new Rational(1, 2);
+        assertEquals(1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Denominator negative
+        r = new Rational(-1, 2);
+        assertEquals(-1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Numerator negative
+        r = new Rational(1, -2);
+        assertEquals(-1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Both negative
+        r = new Rational(-1, -2);
+        assertEquals(1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Infinity.
+        r = new Rational(1, 0);
+        assertEquals(0, r.getNumerator());
+        assertEquals(0, r.getDenominator());
+
+        // Negative infinity.
+        r = new Rational(-1, 0);
+        assertEquals(0, r.getNumerator());
+        assertEquals(0, r.getDenominator());
+
+        // NaN.
+        r = new Rational(0, 0);
+        assertEquals(0, r.getNumerator());
+        assertEquals(0, r.getDenominator());
+    }
+
+    @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());
+        assertEquals(2, r.getDenominator());
+
+        assertEquals(r, r);
+        assertFalse(r.equals(null));
+        assertFalse(r.equals(new Object()));
+
+        Rational twoThirds = new Rational(2, 3);
+        assertFalse(r.equals(twoThirds));
+        assertFalse(twoThirds.equals(r));
+
+        Rational fourSixths = new Rational(4, 6);
+        assertEquals(twoThirds, fourSixths);
+        assertEquals(fourSixths, twoThirds);
+
+        Rational moreComplicated = new Rational(5*6*7*8*9, 1*2*3*4*5);
+        Rational moreComplicated2 = new Rational(5*6*7*8*9*78, 1*2*3*4*5*78);
+        assertEquals(moreComplicated, moreComplicated2);
+        assertEquals(moreComplicated2, moreComplicated);
+
+        // Ensure negatives are fine
+        twoThirds = new Rational(-2, 3);
+        fourSixths = new Rational(-4, 6);
+        assertEquals(twoThirds, fourSixths);
+        assertEquals(fourSixths, twoThirds);
+
+        moreComplicated = new Rational(-5*6*7*8*9, 1*2*3*4*5);
+        moreComplicated2 = new Rational(-5*6*7*8*9*78, 1*2*3*4*5*78);
+        assertEquals(moreComplicated, moreComplicated2);
+        assertEquals(moreComplicated2, moreComplicated);
+
+        Rational nan = new Rational(0, 0);
+        Rational nan2 = new Rational(0, 0);
+        assertTrue(nan.equals(nan));
+        assertTrue(nan.equals(nan2));
+        assertTrue(nan2.equals(nan));
+        assertFalse(nan.equals(r));
+        assertFalse(r.equals(nan));
+
+        // Infinities of the same sign are equal.
+        Rational posInf = new Rational(1, 0);
+        Rational posInf2 = new Rational(2, 0);
+        Rational negInf = new Rational(-1, 0);
+        Rational negInf2 = new Rational(-2, 0);
+        assertEquals(posInf, posInf);
+        assertEquals(negInf, negInf);
+        assertEquals(posInf, posInf2);
+        assertEquals(negInf, negInf2);
+
+        // Infinities aren't equal to anything else.
+        assertFalse(posInf.equals(negInf));
+        assertFalse(negInf.equals(posInf));
+        assertFalse(negInf.equals(r));
+        assertFalse(posInf.equals(r));
+        assertFalse(r.equals(negInf));
+        assertFalse(r.equals(posInf));
+        assertFalse(posInf.equals(nan));
+        assertFalse(negInf.equals(nan));
+        assertFalse(nan.equals(posInf));
+        assertFalse(nan.equals(negInf));
+    }
+}
diff --git a/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java b/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java
index fe3929d..0304640 100644
--- a/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java
+++ b/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java
@@ -429,7 +429,7 @@
                     mMediaRecorder.start();
                     mState = 1;
                 } catch (Exception e) {
-                    Log.e(TAG, "Could start MediaRecorder: " + e.toString());
+                    Log.e(TAG, "Could start MediaRecorder: ", e);
                     mMediaRecorder.release();
                     mMediaRecorder = null;
                     mState = 0;
@@ -439,7 +439,7 @@
                     mMediaRecorder.stop();
                     mMediaRecorder.reset();
                 } catch (Exception e) {
-                    Log.e(TAG, "Could not stop MediaRecorder: " + e.toString());
+                    Log.e(TAG, "Could not stop MediaRecorder: ", e);
                     mMediaRecorder.release();
                     mMediaRecorder = null;
                 } finally {
@@ -466,7 +466,7 @@
                 mMediaRecorder.prepare();
             }
             catch (Exception e) {
-                Log.e(TAG, "Could not prepare MediaRecorder: " + e.toString());
+                Log.e(TAG, "Could not prepare MediaRecorder: ", e);
                 mMediaRecorder.release();
                 mMediaRecorder = null;
             }
@@ -475,9 +475,14 @@
         @Override
         public void stop() {
             if (mMediaRecorder != null) {
-                mMediaRecorder.stop();
-                mMediaRecorder.release();
-                mMediaRecorder = null;
+                try {
+                    mMediaRecorder.stop();
+                } catch (Exception e) {
+                    Log.e(TAG, "Could not stop MediaRecorder: ", e);
+                } finally {
+                    mMediaRecorder.release();
+                    mMediaRecorder = null;
+                }
             }
             updatePlayPauseButton();
         }
diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml
index 126276c..8a29052 100644
--- a/media/tests/SoundPoolTest/AndroidManifest.xml
+++ b/media/tests/SoundPoolTest/AndroidManifest.xml
@@ -8,4 +8,5 @@
             </intent-filter>
         </activity>
     </application>
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
 </manifest>
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
index 33db2dd..cc3306c 100644
--- a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -143,7 +143,7 @@
                 if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
                 sleep(50);
             }
-            if (DEBUG) Log.d(LOG_TAG, "End scale test");
+            if (DEBUG) Log.d(LOG_TAG, "End sounds test");
             return true;
         }
 
@@ -165,7 +165,7 @@
                 if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
                 sleep(50);
             }
-            if (DEBUG) Log.d(LOG_TAG, "End sounds test");
+            if (DEBUG) Log.d(LOG_TAG, "End scale test");
             return true;
         }
 
@@ -189,6 +189,7 @@
                 if (DEBUG) Log.d(LOG_TAG, "Change rate " + mScale[step]);
             }
             mSoundPool.stop(id);
+            if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
             if (DEBUG) Log.d(LOG_TAG, "End rate test");
             return true;
         }
@@ -205,34 +206,38 @@
                 Log.e(LOG_TAG, "Error occurred starting note");
                 return false;
             }
-            sleep(250);
+            sleep(1000);
 
             // play a low priority sound
-            int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+            int id = mSoundPool.play(mSounds[1], DEFAULT_VOLUME, DEFAULT_VOLUME,
                     LOW_PRIORITY, DEFAULT_LOOP, 1.0f);
-            if (id > 0) {
+            if (id != 0) {
                 Log.e(LOG_TAG, "Normal > Low priority test failed");
                 result = false;
                 mSoundPool.stop(id);
             } else {
-                Log.e(LOG_TAG, "Normal > Low priority test passed");
+                sleep(1000);
+                Log.i(LOG_TAG, "Normal > Low priority test passed");
             }
-            sleep(250);
 
             // play a high priority sound
-            id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+            id = mSoundPool.play(mSounds[2], DEFAULT_VOLUME, DEFAULT_VOLUME,
                     HIGH_PRIORITY, DEFAULT_LOOP, 1.0f);
             if (id == 0) {
                 Log.e(LOG_TAG, "High > Normal priority test failed");
                 result = false;
             } else {
-                Log.e(LOG_TAG, "High > Normal priority test passed");
+                sleep(1000);
+                Log.i(LOG_TAG, "Stopping high priority");
+                mSoundPool.stop(id);
+                sleep(1000);
+                Log.i(LOG_TAG, "High > Normal priority test passed");
             }
-            sleep(250);
-            mSoundPool.stop(id);
 
             // stop normal note
+            Log.i(LOG_TAG, "Stopping normal priority");
             mSoundPool.stop(normalId);
+            sleep(1000);
 
             if (DEBUG) Log.d(LOG_TAG, "End priority test");
             return result;
@@ -250,17 +255,21 @@
                 Log.e(LOG_TAG, "Error occurred starting note");
                 return false;
             }
-            sleep(250);
+            sleep(2500);
 
             // pause and resume sound a few times
             for (int count = 0; count < 5; count++) {
+                if (DEBUG) Log.d(LOG_TAG, "Pause note " + id);
                 mSoundPool.pause(id);
-                sleep(250);
+                sleep(1000);
+                if (DEBUG) Log.d(LOG_TAG, "Resume note " + id);
                 mSoundPool.resume(id);
-                sleep(250);
+                sleep(1000);
             }
 
+            if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
             mSoundPool.stop(id);
+            sleep(1000);
 
             // play 5 sounds, forces one to be stolen
             int ids[] = new int[5];
@@ -272,18 +281,21 @@
                     Log.e(LOG_TAG, "Error occurred starting note");
                     return false;
                 }
-                sleep(250);
+                sleep(1000);
             }
 
             // pause and resume sound a few times
             for (int count = 0; count < 5; count++) {
+                if (DEBUG) Log.d(LOG_TAG, "autoPause");
                 mSoundPool.autoPause();
-                sleep(250);
+                sleep(1000);
+                if (DEBUG) Log.d(LOG_TAG, "autoResume");
                 mSoundPool.autoResume();
-                sleep(250);
+                sleep(1000);
             }
 
             for (int i = 0; i < 5; i++) {
+                if (DEBUG) Log.d(LOG_TAG, "Stop note " + ids[i]);
                 mSoundPool.stop(ids[i]);
             }
 
@@ -302,9 +314,9 @@
                 return false;
             }
 
-            // pan from left to right
+            // pan from right to left
             for (int count = 0; count < 101; count++) {
-                sleep(20);
+                sleep(50);
                 double radians = PI_OVER_2 * count / 100.0;
                 float leftVolume = (float) Math.sin(radians);
                 float rightVolume = (float) Math.cos(radians);
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
new file mode 100644
index 0000000..69f0bb5
--- /dev/null
+++ b/media/tests/audiotests/Android.mk
@@ -0,0 +1,21 @@
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= shared_mem_test
+LOCAL_SRC_FILES := \
+		   shared_mem_test.cpp
+LOCAL_SHARED_LIBRARIES :=  \
+		libc \
+        libcutils \
+        libutils \
+        libbinder \
+        libhardware_legacy \
+		libmedia
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/media/tests/audiotests/shared_mem_test.cpp b/media/tests/audiotests/shared_mem_test.cpp
new file mode 100644
index 0000000..992c900
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.cpp
@@ -0,0 +1,216 @@
+// Copyright 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.
+
+//
+#define LOG_NDEBUG 0
+#define LOG_TAG "shared_mem_test"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <cutils/properties.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <math.h>
+
+#include "shared_mem_test.h"
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/ProcessState.h>
+
+
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+
+/************************************************************
+*
+*    Constructor
+*
+************************************************************/
+AudioTrackTest::AudioTrackTest(void) {
+
+    InitSine();         // init sine table
+
+}
+
+
+/************************************************************
+*
+*
+************************************************************/
+void AudioTrackTest::Execute(void) {
+    if (Test01() == 0) {
+        ALOGD("01 passed\n");
+    } else {
+        ALOGD("01 failed\n");
+    }
+}
+
+/************************************************************
+*
+*    Shared memory test
+*
+************************************************************/
+#define BUF_SZ 44100
+
+int AudioTrackTest::Test01() {
+
+    sp<MemoryDealer> heap;
+    sp<IMemory> iMem;
+    uint8_t* p;
+
+    short smpBuf[BUF_SZ];
+    long rate = 44100;
+    unsigned long phi;
+    unsigned long dPhi;
+    long amplitude;
+    long freq = 1237;
+    float f0;
+
+    f0 = pow(2., 32.) * freq / (float)rate;
+    dPhi = (unsigned long)f0;
+    amplitude = 1000;
+    phi = 0;
+    Generate(smpBuf, BUF_SZ, amplitude, phi, dPhi);  // fill buffer
+
+    for (int i = 0; i < 1024; i++) {
+        heap = new MemoryDealer(1024*1024, "AudioTrack Heap Base");
+
+        iMem = heap->allocate(BUF_SZ*sizeof(short));
+
+        p = static_cast<uint8_t*>(iMem->pointer());
+        memcpy(p, smpBuf, BUF_SZ*sizeof(short));
+
+        sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream type
+               rate,
+               AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
+               AUDIO_CHANNEL_OUT_MONO,
+               iMem);
+
+        status_t status = track->initCheck();
+        if(status != NO_ERROR) {
+            track.clear();
+            ALOGD("Failed for initCheck()");
+            return -1;
+        }
+
+        // start play
+        ALOGD("start");
+        track->start();
+
+        usleep(20000);
+
+        ALOGD("stop");
+        track->stop();
+        iMem.clear();
+        heap.clear();
+        usleep(20000);
+    }
+
+    return 0;
+
+}
+
+/************************************************************
+*
+*    Generate a mono buffer
+*    Error is less than 3lsb
+*
+************************************************************/
+void AudioTrackTest::Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi)
+{
+    long pi13 = 25736;   // 2^13*pi
+    // fill buffer
+    for(int i0=0; i0<bufferSz; i0++) {
+        long sample;
+        long l0, l1;
+
+        buffer[i0] = ComputeSine( amplitude, phi);
+        phi += dPhi;
+    }
+}
+
+/************************************************************
+*
+*    Generate a sine
+*    Error is less than 3lsb
+*
+************************************************************/
+short AudioTrackTest::ComputeSine(long amplitude, long phi)
+{
+    long pi13 = 25736;   // 2^13*pi
+    long sample;
+    long l0, l1;
+
+    sample = (amplitude*sin1024[(phi>>22) & 0x3ff]) >> 15;
+    // correct with interpolation
+    l0 = (phi>>12) & 0x3ff;         // 2^20 * x / (2*pi)
+    l1 = (amplitude*sin1024[((phi>>22) + 256) & 0x3ff]) >> 15;    // 2^15*cosine
+    l0 = (l0 * l1) >> 10;
+    l0 = (l0 * pi13) >> 22;
+    sample = sample + l0;
+
+    return (short)sample;
+}
+
+
+/************************************************************
+*
+*    init sine table
+*
+************************************************************/
+void AudioTrackTest::InitSine(void) {
+    double phi = 0;
+    double dPhi = 2 * M_PI / SIN_SZ;
+    for(int i0 = 0; i0<SIN_SZ; i0++) {
+        long d0;
+
+        d0 = 32768. * sin(phi);
+        phi += dPhi;
+        if(d0 >= 32767) d0 = 32767;
+        if(d0 <= -32768) d0 = -32768;
+        sin1024[i0] = (short)d0;
+    }
+}
+
+/************************************************************
+*
+*    main in name space
+*
+************************************************************/
+int main() {
+    ProcessState::self()->startThreadPool();
+    AudioTrackTest *test;
+
+    test = new AudioTrackTest();
+    test->Execute();
+    delete test;
+
+    return 0;
+}
+
+}
+
+/************************************************************
+*
+*    global main
+*
+************************************************************/
+int main(int argc, char *argv[]) {
+
+    return android::main();
+}
diff --git a/media/tests/audiotests/shared_mem_test.h b/media/tests/audiotests/shared_mem_test.h
new file mode 100644
index 0000000..f495955
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.h
@@ -0,0 +1,27 @@
+// Copyright 2008 The Android Open Source Project
+
+#ifndef AUDIOTRACKTEST_H_
+#define AUDIOTRACKTEST_H_
+
+namespace android {
+
+class AudioTrackTest{
+    public:
+        AudioTrackTest(void);
+        ~AudioTrackTest() {};
+
+        void Execute(void);
+        int Test01();
+
+        void Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi);
+        void InitSine();
+        short ComputeSine(long amplitude, long phi);
+
+        #define SIN_SZ    1024
+        short sin1024[SIN_SZ];           // sine table 2*pi = 1024
+};
+
+};
+
+
+#endif /*AUDIOTRACKTEST_H_*/
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 207cc4b..cda38e0 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -20,6 +20,7 @@
     liblog \
     libcutils \
     libandroidfw \
+    libinput \
     libutils \
     libbinder \
     libui \
diff --git a/native/android/input.cpp b/native/android/input.cpp
index f6ea576..e9d08b4 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -18,8 +18,8 @@
 #include <utils/Log.h>
 
 #include <android/input.h>
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
 #include <utils/Looper.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
index 131d898..330e2d4 100644
--- a/nfc-extras/Android.mk
+++ b/nfc-extras/Android.mk
@@ -9,6 +9,3 @@
 LOCAL_MODULE:= com.android.nfc_extras
 
 include $(BUILD_JAVA_LIBRARY)
-
-# put the classes.jar, with full class files instead of classes.dex inside, into the dist directory
-$(call dist-for-goals, droidcore, $(full_classes_jar):com.android.nfc_extras.jar)
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 05b498c..0c65283 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -121,6 +121,13 @@
                     (header).mAuthResp.length);
 
         }
+
+        if ((header).mConnectionID != null) {
+            mRequestHeader.mConnectionID = new byte[4];
+            System.arraycopy((header).mConnectionID, 0, mRequestHeader.mConnectionID, 0,
+                    4);
+
+        }
     }
 
     /**
@@ -420,7 +427,7 @@
                 //split the headerArray
                 end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
                         - ObexHelper.BASE_PACKET_LENGTH);
-                // can not split 
+                // can not split
                 if (end == -1) {
                     mOperationDone = true;
                     abort();
@@ -521,7 +528,7 @@
             return false;
         }
 
-        // send all of the output data in 0x48, 
+        // send all of the output data in 0x48,
         // send 0x49 with empty body
         if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
             returnValue = true;
@@ -723,4 +730,7 @@
             }
         }
     }
+
+    public void noBodyHeader(){
+    }
 }
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
index b89b707..2b3066f 100644
--- a/obex/javax/obex/HeaderSet.java
+++ b/obex/javax/obex/HeaderSet.java
@@ -464,6 +464,8 @@
                 return mHttpHeader;
             case WHO:
                 return mWho;
+            case CONNECTION_ID:
+                return mConnectionID;
             case OBJECT_CLASS:
                 return mObjectClass;
             case APPLICATION_PARAMETER:
diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java
index 25656ed..5b4d5ac 100644
--- a/obex/javax/obex/Operation.java
+++ b/obex/javax/obex/Operation.java
@@ -178,4 +178,6 @@
     void close() throws IOException;
 
     int getMaxPacketSize();
+
+    public void noBodyHeader();
 }
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index d1476d2..fc441e0 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -88,6 +88,8 @@
 
     private boolean mHasBody;
 
+    private boolean mSendBodyHeader = true;
+
     /**
      * Creates new ServerOperation
      * @param p the parent that created this object
@@ -364,24 +366,33 @@
                  * (End of Body) otherwise, we need to send 0x48 (Body)
                  */
                 if ((finalBitSet) || (mPrivateOutput.isClosed())) {
-                    out.write(0x49);
+                    if(mSendBodyHeader == true) {
+                        out.write(0x49);
+                        bodyLength += 3;
+                        out.write((byte)(bodyLength >> 8));
+                        out.write((byte)bodyLength);
+                        out.write(body);
+                    }
                 } else {
+                    if(mSendBodyHeader == true) {
                     out.write(0x48);
+                    bodyLength += 3;
+                    out.write((byte)(bodyLength >> 8));
+                    out.write((byte)bodyLength);
+                    out.write(body);
+                    }
                 }
 
-                bodyLength += 3;
-                out.write((byte)(bodyLength >> 8));
-                out.write((byte)bodyLength);
-                out.write(body);
             }
         }
 
         if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
-            out.write(0x49);
-            orginalBodyLength = 3;
-            out.write((byte)(orginalBodyLength >> 8));
-            out.write((byte)orginalBodyLength);
-
+            if(mSendBodyHeader == true) {
+                out.write(0x49);
+                orginalBodyLength = 3;
+                out.write((byte)(orginalBodyLength >> 8));
+                out.write((byte)orginalBodyLength);
+            }
         }
 
         mResponseSize = 3;
@@ -711,4 +722,8 @@
     public void streamClosed(boolean inStream) throws IOException {
 
     }
+
+    public void noBodyHeader(){
+        mSendBodyHeader = false;
+    }
 }
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index a4b9759..f1b9a0d 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -256,6 +256,10 @@
     public void sendResponse(int code, byte[] header) throws IOException {
         int totalLength = 3;
         byte[] data = null;
+        OutputStream op = mOutput;
+        if (op == null) {
+            return;
+        }
 
         if (header != null) {
             totalLength += header.length;
@@ -270,8 +274,8 @@
             data[1] = (byte)0x00;
             data[2] = (byte)totalLength;
         }
-        mOutput.write(data);
-        mOutput.flush();
+        op.write(data);
+        op.flush();
     }
 
     /**
diff --git a/opengl/java/android/opengl/EGLConfig.java b/opengl/java/android/opengl/EGLConfig.java
index d457c9f..a7a6bbb 100644
--- a/opengl/java/android/opengl/EGLConfig.java
+++ b/opengl/java/android/opengl/EGLConfig.java
@@ -29,7 +29,7 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (!(o instanceof EGLConfig)) return false;
 
         EGLConfig that = (EGLConfig) o;
         return getHandle() == that.getHandle();
diff --git a/opengl/java/android/opengl/EGLContext.java b/opengl/java/android/opengl/EGLContext.java
index 41b8ef1..c93bd6e 100644
--- a/opengl/java/android/opengl/EGLContext.java
+++ b/opengl/java/android/opengl/EGLContext.java
@@ -29,7 +29,7 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (!(o instanceof EGLContext)) return false;
 
         EGLContext that = (EGLContext) o;
         return getHandle() == that.getHandle();
diff --git a/opengl/java/android/opengl/EGLDisplay.java b/opengl/java/android/opengl/EGLDisplay.java
index 17d1a64..5b8043a 100644
--- a/opengl/java/android/opengl/EGLDisplay.java
+++ b/opengl/java/android/opengl/EGLDisplay.java
@@ -29,7 +29,7 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (!(o instanceof EGLDisplay)) return false;
 
         EGLDisplay that = (EGLDisplay) o;
         return getHandle() == that.getHandle();
diff --git a/opengl/java/android/opengl/EGLSurface.java b/opengl/java/android/opengl/EGLSurface.java
index 65bec4f..c379dc9 100644
--- a/opengl/java/android/opengl/EGLSurface.java
+++ b/opengl/java/android/opengl/EGLSurface.java
@@ -29,7 +29,7 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (!(o instanceof EGLSurface)) return false;
 
         EGLSurface that = (EGLSurface) o;
         return getHandle() == that.getHandle();
diff --git a/opengl/java/android/opengl/Matrix.java b/opengl/java/android/opengl/Matrix.java
index 72128ac..ce3f57e 100644
--- a/opengl/java/android/opengl/Matrix.java
+++ b/opengl/java/android/opengl/Matrix.java
@@ -19,24 +19,21 @@
 /**
  * Matrix math utilities. These methods operate on OpenGL ES format
  * matrices and vectors stored in float arrays.
- *
+ * <p>
  * Matrices are 4 x 4 column-vector matrices stored in column-major
  * order:
  * <pre>
  *  m[offset +  0] m[offset +  4] m[offset +  8] m[offset + 12]
  *  m[offset +  1] m[offset +  5] m[offset +  9] m[offset + 13]
  *  m[offset +  2] m[offset +  6] m[offset + 10] m[offset + 14]
- *  m[offset +  3] m[offset +  7] m[offset + 11] m[offset + 15]
- * </pre>
+ *  m[offset +  3] m[offset +  7] m[offset + 11] m[offset + 15]</pre>
  *
- * Vectors are 4 row x 1 column column-vectors stored in order:
+ * Vectors are 4 x 1 column vectors stored in order:
  * <pre>
  * v[offset + 0]
  * v[offset + 1]
  * v[offset + 2]
- * v[offset + 3]
- * </pre>
- *
+ * v[offset + 3]</pre>
  */
 public class Matrix {
 
@@ -44,12 +41,18 @@
     private final static float[] sTemp = new float[32];
 
     /**
-     * Multiply two 4x4 matrices together and store the result in a third 4x4
+     * @deprecated All methods are static, do not instantiate this class.
+     */
+    @Deprecated
+    public Matrix() {}
+
+    /**
+     * Multiplies two 4x4 matrices together and stores the result in a third 4x4
      * matrix. In matrix notation: result = lhs x rhs. Due to the way
      * matrix multiplication works, the result matrix will have the same
      * effect as first multiplying by the rhs matrix, then multiplying by
      * the lhs matrix. This is the opposite of what you might expect.
-     *
+     * <p>
      * The same float array may be passed for result, lhs, and/or rhs. However,
      * the result element values are undefined if the result elements overlap
      * either the lhs or rhs elements.
@@ -70,9 +73,9 @@
             float[] lhs, int lhsOffset, float[] rhs, int rhsOffset);
 
     /**
-     * Multiply a 4 element vector by a 4x4 matrix and store the result in a 4
-     * element column vector. In matrix notation: result = lhs x rhs
-     *
+     * Multiplies a 4 element vector by a 4x4 matrix and stores the result in a
+     * 4-element column vector. In matrix notation: result = lhs x rhs
+     * <p>
      * The same float array may be passed for resultVec, lhsMat, and/or rhsVec.
      * However, the resultVec element values are undefined if the resultVec
      * elements overlap either the lhsMat or rhsVec elements.
@@ -97,12 +100,14 @@
 
     /**
      * Transposes a 4 x 4 matrix.
+     * <p>
+     * mTrans and m must not overlap.
      *
-     * @param mTrans the array that holds the output inverted matrix
-     * @param mTransOffset an offset into mInv where the inverted matrix is
+     * @param mTrans the array that holds the output transposed matrix
+     * @param mTransOffset an offset into mTrans where the transposed matrix is
      *        stored.
      * @param m the input array
-     * @param mOffset an offset into m where the matrix is stored.
+     * @param mOffset an offset into m where the input matrix is stored.
      */
     public static void transposeM(float[] mTrans, int mTransOffset, float[] m,
             int mOffset) {
@@ -117,12 +122,14 @@
 
     /**
      * Inverts a 4 x 4 matrix.
+     * <p>
+     * mInv and m must not overlap.
      *
      * @param mInv the array that holds the output inverted matrix
      * @param mInvOffset an offset into mInv where the inverted matrix is
      *        stored.
      * @param m the input array
-     * @param mOffset an offset into m where the matrix is stored.
+     * @param mOffset an offset into m where the input matrix is stored.
      * @return true if the matrix could be inverted, false if it could not.
      */
     public static boolean invertM(float[] mInv, int mInvOffset, float[] m,
@@ -301,10 +308,11 @@
 
 
     /**
-     * Define a projection matrix in terms of six clip planes
-     * @param m the float array that holds the perspective matrix
+     * Defines a projection matrix in terms of six clip planes.
+     *
+     * @param m the float array that holds the output perspective matrix
      * @param offset the offset into float array m where the perspective
-     * matrix data is written
+     *        matrix data is written
      * @param left
      * @param right
      * @param bottom
@@ -358,11 +366,12 @@
     }
 
     /**
-     * Define a projection matrix in terms of a field of view angle, an
-     * aspect ratio, and z clip planes
+     * Defines a projection matrix in terms of a field of view angle, an
+     * aspect ratio, and z clip planes.
+     *
      * @param m the float array that holds the perspective matrix
      * @param offset the offset into float array m where the perspective
-     * matrix data is written
+     *        matrix data is written
      * @param fovy field of view in y direction, in degrees
      * @param aspect width to height aspect ratio of the viewport
      * @param zNear
@@ -395,7 +404,7 @@
     }
 
     /**
-     * Computes the length of a vector
+     * Computes the length of a vector.
      *
      * @param x x coordinate of a vector
      * @param y y coordinate of a vector
@@ -408,6 +417,7 @@
 
     /**
      * Sets matrix m to the identity matrix.
+     *
      * @param sm returns the result
      * @param smOffset index into sm where the result matrix starts
      */
@@ -421,7 +431,10 @@
     }
 
     /**
-     * Scales matrix  m by x, y, and z, putting the result in sm
+     * Scales matrix m by x, y, and z, putting the result in sm.
+     * <p>
+     * m and sm must not overlap.
+     *
      * @param sm returns the result
      * @param smOffset index into sm where the result matrix starts
      * @param m source matrix
@@ -444,7 +457,8 @@
     }
 
     /**
-     * Scales matrix m in place by sx, sy, and sz
+     * Scales matrix m in place by sx, sy, and sz.
+     *
      * @param m matrix to scale
      * @param mOffset index into m where the matrix starts
      * @param x scale factor x
@@ -462,7 +476,10 @@
     }
 
     /**
-     * Translates matrix m by x, y, and z, putting the result in tm
+     * Translates matrix m by x, y, and z, putting the result in tm.
+     * <p>
+     * m and tm must not overlap.
+     *
      * @param tm returns the result
      * @param tmOffset index into sm where the result matrix starts
      * @param m source matrix
@@ -487,6 +504,7 @@
 
     /**
      * Translates matrix m by x, y, and z in place.
+     *
      * @param m matrix
      * @param mOffset index into m where the matrix starts
      * @param x translation factor x
@@ -503,15 +521,18 @@
     }
 
     /**
-     * Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
+     * Rotates matrix m by angle a (in degrees) around the axis (x, y, z).
+     * <p>
+     * m and rm must not overlap.
+     *
      * @param rm returns the result
      * @param rmOffset index into rm where the result matrix starts
      * @param m source matrix
      * @param mOffset index into m where the source matrix starts
      * @param a angle to rotate in degrees
-     * @param x scale factor x
-     * @param y scale factor y
-     * @param z scale factor z
+     * @param x X axis component
+     * @param y Y axis component
+     * @param z Z axis component
      */
     public static void rotateM(float[] rm, int rmOffset,
             float[] m, int mOffset,
@@ -524,13 +545,14 @@
 
     /**
      * Rotates matrix m in place by angle a (in degrees)
-     * around the axis (x, y, z)
+     * around the axis (x, y, z).
+     *
      * @param m source matrix
      * @param mOffset index into m where the matrix starts
      * @param a angle to rotate in degrees
-     * @param x scale factor x
-     * @param y scale factor y
-     * @param z scale factor z
+     * @param x X axis component
+     * @param y Y axis component
+     * @param z Z axis component
      */
     public static void rotateM(float[] m, int mOffset,
             float a, float x, float y, float z) {
@@ -542,13 +564,18 @@
     }
 
     /**
-     * Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
+     * Creates a matrix for rotation by angle a (in degrees)
+     * around the axis (x, y, z).
+     * <p>
+     * An optimized path will be used for rotation about a major axis
+     * (e.g. x=1.0f y=0.0f z=0.0f).
+     *
      * @param rm returns the result
      * @param rmOffset index into rm where the result matrix starts
      * @param a angle to rotate in degrees
-     * @param x scale factor x
-     * @param y scale factor y
-     * @param z scale factor z
+     * @param x X axis component
+     * @param y Y axis component
+     * @param z Z axis component
      */
     public static void setRotateM(float[] rm, int rmOffset,
             float a, float x, float y, float z) {
@@ -608,7 +635,8 @@
     }
 
     /**
-     * Converts Euler angles to a rotation matrix
+     * Converts Euler angles to a rotation matrix.
+     *
      * @param rm returns the result
      * @param rmOffset index into rm where the result matrix starts
      * @param x angle of rotation, in degrees
@@ -651,7 +679,7 @@
     }
 
     /**
-     * Define a viewing transformation in terms of an eye point, a center of
+     * Defines a viewing transformation in terms of an eye point, a center of
      * view, and an up vector.
      *
      * @param rm returns the result
diff --git a/packages/BackupRestoreConfirmation/Android.mk b/packages/BackupRestoreConfirmation/Android.mk
index e775b44..b84c07f 100644
--- a/packages/BackupRestoreConfirmation/Android.mk
+++ b/packages/BackupRestoreConfirmation/Android.mk
@@ -23,6 +23,7 @@
 
 LOCAL_PACKAGE_NAME := BackupRestoreConfirmation
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 include $(BUILD_PACKAGE)
 
diff --git a/packages/BackupRestoreConfirmation/res/values-af/strings.xml b/packages/BackupRestoreConfirmation/res/values-af/strings.xml
index fadd125..0bf54cf 100644
--- a/packages/BackupRestoreConfirmation/res/values-af/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-af/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Volledige rugsteun"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Volledige herstel"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"\'n Volledige rugsteun van al die data na \'n rekenaar is aangevra. Wil jy dit toelaat? "\n\n"As jy nie self die rugsteun versoek het nie, moenie toelaat dat die aksie voortgaan nie."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"\'n Volledige rugsteun van al die data na \'n rekenaar is aangevra. Wil jy dit toelaat? \n\nAs jy nie self die rugsteun versoek het nie, moenie toelaat dat die aksie voortgaan nie."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Rugsteun my data"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Moenie rugsteun nie"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"\'n Volle teruglaai van alle data van \'n gekoppelde rekenaar is versoek. Wil jy dit toelaat? "\n\n" As jy nie die teruglaai self versoek het nie, moenie die aksie toelaat nie. Dit sal enige data tans op die toestel vervang!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"\'n Volle teruglaai van alle data van \'n gekoppelde rekenaar is versoek. Wil jy dit toelaat? \n\n As jy nie die teruglaai self versoek het nie, moenie die aksie toelaat nie. Dit sal enige data tans op die toestel vervang!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Laai my data terug"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Moenie herstel nie"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Voer asseblief jou huidige rugsteunwagwoord hieronder in:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-am/strings.xml b/packages/BackupRestoreConfirmation/res/values-am/strings.xml
index 512d917..ec5b9631 100644
--- a/packages/BackupRestoreConfirmation/res/values-am/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-am/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"ሙሉ ለሙሉ መጠባበቂያ"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"ሙሉ ለሙሉ እነበረበት መልስ"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"ሁሉንም ውሂብ በሙሉ መጠበቂያ ከተያያዘ የዴስክቶፕ ኮምፒዩተር ተጠይቋል። ይህ እንዲከሰት ለመፍቀድ ይፈልጋሉ? "\n\n"እርስዎ ራስዎ የመጠባበቂያውን ጥየቃ ካልጠየቁ ክወናው እንዲካሄድ አይፍቀዱ።"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"ሁሉንም ውሂብ በሙሉ መጠበቂያ ከተያያዘ የዴስክቶፕ ኮምፒዩተር ተጠይቋል። ይህ እንዲከሰት ለመፍቀድ ይፈልጋሉ? \n\nእርስዎ ራስዎ የመጠባበቂያውን ጥየቃ ካልጠየቁ ክወናው እንዲካሄድ አይፍቀዱ።"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"ውሂቤን መጠባበቂያ"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"መጠባበቂያ አታድርግ"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"ሁሉንም ውሂብ በሙሉ መጠበቂያ ከተያያዘ የዴስክቶፕ ኮምፒዩተር ተጠይቋል። ይህ እንዲከሰት ለመፍቀድ ይፈልጋሉ? "\n\n"እርስዎ ራስዎ የመጠባበቂያውን ጥየቃ ካልጠየቁ ክወናው እንዲካሄድ አይፍቀዱ። ይህም አሁን በመሣሪያዎ ላይ ያለውን ማንኛውም ውሂብ ይተካል!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"ሁሉንም ውሂብ በሙሉ መጠበቂያ ከተያያዘ የዴስክቶፕ ኮምፒዩተር ተጠይቋል። ይህ እንዲከሰት ለመፍቀድ ይፈልጋሉ? \n\nእርስዎ ራስዎ የመጠባበቂያውን ጥየቃ ካልጠየቁ ክወናው እንዲካሄድ አይፍቀዱ። ይህም አሁን በመሣሪያዎ ላይ ያለውን ማንኛውም ውሂብ ይተካል!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"ውሂቤን እነበረበት መልስ"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"እነበረበት አትመልስ"</string>
     <string name="current_password_text" msgid="8268189555578298067">"እባክዎ የአሁኑን የመጠባበቂያ ይለፍቃል ከታች ያስገቡ፡"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ar/strings.xml b/packages/BackupRestoreConfirmation/res/values-ar/strings.xml
index 2e9ec40..6a6edd9 100644
--- a/packages/BackupRestoreConfirmation/res/values-ar/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ar/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"نسخ احتياطي بالكامل"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"استعادة كاملة"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"تم طلب الاحتفاظ بنسخة احتياطية كاملة من البيانات على كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟"\n\n"إذا لم تطلب الاحتفاظ بنسخة احتياطية بنفسك، فلا تسمح بمتابعة العملية."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"تم طلب الاحتفاظ بنسخة احتياطية كاملة من البيانات على كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاحتفاظ بنسخة احتياطية بنفسك، فلا تسمح بمتابعة العملية."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"الاحتفاظ بنسخة احتياطية من بياناتي"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"عدم النسخ الاحتياطي"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"تم طلب استرداد جميع البيانات بالكامل من كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟"\n\n"إذا لم تطلب الاسترداد بنفسك، فلا تسمح بمتابعة العملية. يؤدي لك إلى استبدال أية بيانات حاليًا على الجهاز."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"تم طلب استرداد جميع البيانات بالكامل من كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاسترداد بنفسك، فلا تسمح بمتابعة العملية. يؤدي لك إلى استبدال أية بيانات حاليًا على الجهاز."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"استرداد بياناتي"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"عدم الاسترداد"</string>
     <string name="current_password_text" msgid="8268189555578298067">"الرجاء إدخال كلمة مرور النسخ الاحتياطي أدناه:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-be/strings.xml b/packages/BackupRestoreConfirmation/res/values-be/strings.xml
index 4836125..188041a 100644
--- a/packages/BackupRestoreConfirmation/res/values-be/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-be/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Поўнае рэзервовае капіяванне"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Поўнае аднаўленне"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Было прапанавана поўнае рэзервовае капіяванне ўсіх дадзеных на падлучаным настольным кампутары. Дазволіць гэта?"\n\n"Калі вы самі не запытвалі рэзервовае капiяванне, спынiце аперацыю."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Было прапанавана поўнае рэзервовае капіяванне ўсіх дадзеных на падлучаным настольным кампутары. Дазволіць гэта?\n\nКалі вы самі не запытвалі рэзервовае капiяванне, спынiце аперацыю."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Рэзервовае капіяванне дадзеных"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Не ствараць рэзервовыя копіі"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Запытана поўнае аднаўленне ўсіх дадзеных з падлучанага настольнага кампутара. Дазволіць гэта?"\n\n"Калі вы самі не запытвалі аднаўленне, не дазваляйце працягваць аперацыю. Гэта прывядзе да замены якіх-небудзь дадзеных, якія зараз знаходзяцца на прыладзе."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Запытана поўнае аднаўленне ўсіх дадзеных з падлучанага настольнага кампутара. Дазволіць гэта?\n\nКалі вы самі не запытвалі аднаўленне, не дазваляйце працягваць аперацыю. Гэта прывядзе да замены якіх-небудзь дадзеных, якія зараз знаходзяцца на прыладзе."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Аднавіць мае дадзеныя"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Не аднаўляць"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Увядзіце ваш бягучы пароль рэзервовага капіявання ніжэй:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-bg/strings.xml b/packages/BackupRestoreConfirmation/res/values-bg/strings.xml
index a431bf7..c332774 100644
--- a/packages/BackupRestoreConfirmation/res/values-bg/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-bg/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Пълно резервно копие"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Пълно възстановяване"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Бе поискано пълно резервно копие на всичките данни до свързан настолен компютър. Искате ли да разрешите това?"\n\n"Ако не сте заявили създаването на копие, не позволявайте операцията да продължи."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Бе поискано пълно резервно копие на всичките данни до свързан настолен компютър. Искате ли да разрешите това?\n\nАко не сте заявили създаването на копие, не позволявайте операцията да продължи."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Резервно копие на данните ми"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Без резервно копие"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Бе поискано пълно възстановяване на всичките данни от свързан настолен компютър. Искате ли да разрешите това?"\n\n"Ако не сте заявили възстановяването, не позволявайте операцията да продължи. Това ще замести данните, които понастоящем са в устройството!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Бе поискано пълно възстановяване на всичките данни от свързан настолен компютър. Искате ли да разрешите това?\n\nАко не сте заявили възстановяването, не позволявайте операцията да продължи. Това ще замести данните, които понастоящем са в устройството!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Възстановяване на данните ми"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Без възстановяване"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Моля, въведете текущата си парола за резервно копие по-долу:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ca/strings.xml b/packages/BackupRestoreConfirmation/res/values-ca/strings.xml
index 32cfefc..359df47 100644
--- a/packages/BackupRestoreConfirmation/res/values-ca/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ca/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Còpia de seguretat completa"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restaura completament"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"S\'ha sol·licitat una còpia de seguretat completa de totes les dades a un equip de sobretaula connectat. Vols permetre que això passi?"\n" "\n"Si no has sol·licitat la còpia de seguretat tu mateix, no permetis que continuï l\'operació."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"S\'ha sol·licitat una còpia de seguretat completa de totes les dades a un equip de sobretaula connectat. Vols permetre que això passi?\n \nSi no has sol·licitat la còpia de seguretat tu mateix, no permetis que continuï l\'operació."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Còpia de seguretat de dades"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"No en facis una còpia de seguretat"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"S\'ha sol·licitat una restauració completa de totes les dades d\'un equip d\'escriptori connectat. Vols permetre que això passi?"\n" "\n"Si no has sol·licitat la restauració tu mateix, no permetis que continuï l\'operació. Això reemplaçarà les dades que hi hagi actualment a l\'equip."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"S\'ha sol·licitat una restauració completa de totes les dades d\'un equip d\'escriptori connectat. Vols permetre que això passi?\n \nSi no has sol·licitat la restauració tu mateix, no permetis que continuï l\'operació. Això reemplaçarà les dades que hi hagi actualment a l\'equip."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaura les meves dades"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"No ho restauris"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Introdueix la teva contrasenya actual de còpia de seguretat a continuació:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-cs/strings.xml b/packages/BackupRestoreConfirmation/res/values-cs/strings.xml
index 0732cd8..c46916b 100644
--- a/packages/BackupRestoreConfirmation/res/values-cs/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-cs/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Úplná záloha"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Úplné obnovení"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Obdrželi jsme požadavek na úplnou zálohu všech dat do připojeného počítače. Chcete tuto akci povolit? "\n\n"Pokud jste o zálohu nežádali, operaci nepovolujte."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Obdrželi jsme požadavek na úplnou zálohu všech dat do připojeného počítače. Chcete tuto akci povolit? \n\nPokud jste o zálohu nežádali, operaci nepovolujte."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Zálohovat data"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nezálohovat"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Obdrželi jsme žádost o úplné obnovení všech dat z připojeného počítače. Chcete tuto akci povolit?"\n\n"Pokud jste o obnovení nepožádali, operaci nepovolujte. Tato akce nahradí veškerá data v zařízení."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Obdrželi jsme žádost o úplné obnovení všech dat z připojeného počítače. Chcete tuto akci povolit?\n\nPokud jste o obnovení nepožádali, operaci nepovolujte. Tato akce nahradí veškerá data v zařízení."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnovit moje data"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Neobnovovat"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Zadejte prosím aktuální heslo pro zálohy níže:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-da/strings.xml b/packages/BackupRestoreConfirmation/res/values-da/strings.xml
index b3756d9..0a84c30 100644
--- a/packages/BackupRestoreConfirmation/res/values-da/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-da/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Fuld sikkerhedskopiering"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Fuld genoprettelse"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Der er anmodet om en fuld sikkerhedskopiering af alle data til en tilsluttet stationær computer. Vil du tillade dette?"\n\n"Hvis du ikke har anmodet om sikkerhedskopiering, skal du ikke tillade denne handling."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Der er anmodet om en fuld sikkerhedskopiering af alle data til en tilsluttet stationær computer. Vil du tillade dette?\n\nHvis du ikke har anmodet om sikkerhedskopiering, skal du ikke tillade denne handling."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Sikkerhedskopier mine data"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Undlad at sikkerhedskopiere"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Der er anmodet om en fuld sikkerhedskopiering af alle data til en tilsluttet stationær computer. Vil du tillade dette?"\n\n"Hvis du ikke har anmodet om sikkerhedskopiering, skal du ikke tillade denne handling."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Der er anmodet om en fuld sikkerhedskopiering af alle data til en tilsluttet stationær computer. Vil du tillade dette?\n\nHvis du ikke har anmodet om sikkerhedskopiering, skal du ikke tillade denne handling."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Gendan mine data"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Gendan ikke"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Indtast din aktuelle adgangskode til sikkerhedskopiering nedenfor:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-de/strings.xml b/packages/BackupRestoreConfirmation/res/values-de/strings.xml
index a8f2d13..91a1dff 100644
--- a/packages/BackupRestoreConfirmation/res/values-de/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-de/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Vollständige Sicherung"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Vollständige Wiederherstellung"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Es wurde eine vollständige Sicherung sämtlicher Daten auf einen verbundenen Desktop-Computer angefordert. Möchten Sie dies zulassen?"\n\n"Wenn Sie die Sicherung nicht selbst angefordert haben, sollten Sie dem Vorgang nicht zustimmen."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Es wurde eine vollständige Sicherung sämtlicher Daten auf einen verbundenen Desktop-Computer angefordert. Möchten Sie dies zulassen?\n\nWenn Sie die Sicherung nicht selbst angefordert haben, sollten Sie dem Vorgang nicht zustimmen."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Meine Daten sichern"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nicht sichern"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Es wurde eine vollständige Wiederherstellung aller Daten von einem verbundenen Desktop-Computer angefordert. Möchten Sie dies zulassen?"\n\n"Wenn Sie die Wiederherstellung nicht selbst angefordert haben, sollten Sie dem Vorgang nicht zustimmen. Dadurch werden alle zurzeit auf dem Gerät befindlichen Daten ersetzt!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Es wurde eine vollständige Wiederherstellung aller Daten von einem verbundenen Desktop-Computer angefordert. Möchten Sie dies zulassen?\n\nWenn Sie die Wiederherstellung nicht selbst angefordert haben, sollten Sie dem Vorgang nicht zustimmen. Dadurch werden alle zurzeit auf dem Gerät befindlichen Daten ersetzt!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Meine Daten wiederherstellen"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Nicht wiederherstellen"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Geben Sie Ihr aktuelles Sicherungspasswort unten ein:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-el/strings.xml b/packages/BackupRestoreConfirmation/res/values-el/strings.xml
index 13a78cb..cd325ef 100644
--- a/packages/BackupRestoreConfirmation/res/values-el/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-el/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Πλήρης δημιουργία αντιγράφων ασφαλείας"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Πλήρης επαναφορά"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Έχει ζητηθεί ένα πλήρες αντίγραφο ασφαλείας όλων των δεδομένων σε έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτραπεί αυτή η ενέργεια;"\n\n"Αν δεν έχετε ζητήσει οι ίδιοι αυτό το αντίγραφο ασφαλείας, μην επιτρέψετε την ενέργεια."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Έχει ζητηθεί ένα πλήρες αντίγραφο ασφαλείας όλων των δεδομένων σε έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτραπεί αυτή η ενέργεια;\n\nΑν δεν έχετε ζητήσει οι ίδιοι αυτό το αντίγραφο ασφαλείας, μην επιτρέψετε την ενέργεια."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Δημιουργία αντιγράφων ασφαλείας για τα δεδομένα μου"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Να μην δημιουργείται αντίγραφο ασφαλείας"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Έχει ζητηθεί πλήρης επαναφορά όλων των δεδομένων από έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτρέψετε αυτήν την ενέργεια;"\n\n"Αν δεν έχετε ζητήσει οι ίδιοι αυτήν την επαναφορά, μην επιτρέψετε την ενέργεια. Θα γίνει αντικατάσταση τυχόν δεδομένων τα οποία υπάρχουν αυτήν τη στιγμή στη συσκευή σας!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Έχει ζητηθεί πλήρης επαναφορά όλων των δεδομένων από έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτρέψετε αυτήν την ενέργεια;\n\nΑν δεν έχετε ζητήσει οι ίδιοι αυτήν την επαναφορά, μην επιτρέψετε την ενέργεια. Θα γίνει αντικατάσταση τυχόν δεδομένων τα οποία υπάρχουν αυτήν τη στιγμή στη συσκευή σας!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Αποκατάσταση των δεδομένων μου"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Να μην γίνει επαναφορά"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Εισαγάγετε τον τρέχοντα κωδικό πρόσβασής αντιγράφων ασφαλείας παρακάτω:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-en-rGB/strings.xml b/packages/BackupRestoreConfirmation/res/values-en-rGB/strings.xml
index 7b94e2e..d096d98 100644
--- a/packages/BackupRestoreConfirmation/res/values-en-rGB/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-en-rGB/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Full backup"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Full restoration"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"A full backup of all data to a connected desktop computer has been requested. Do you want to allow this to happen?"\n\n"If you did not request the backup yourself, do not allow the operation to proceed."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"A full backup of all data to a connected desktop computer has been requested. Do you want to allow this to happen?\n\nIf you did not request the backup yourself, do not allow the operation to proceed."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Back up my data"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Do not back up"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"A full restore of all data from a connected desktop computer has been requested. Do you want to allow this to happen?"\n\n"If you did not request the restore yourself, do not allow the operation to proceed. This will replace any data currently on the device!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"A full restore of all data from a connected desktop computer has been requested. Do you want to allow this to happen?\n\nIf you did not request the restore yourself, do not allow the operation to proceed. This will replace any data currently on the device!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restore my data"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Do not restore"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Please enter your current backup password below:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-es-rUS/strings.xml b/packages/BackupRestoreConfirmation/res/values-es-rUS/strings.xml
index 21afa31..13ce1da 100644
--- a/packages/BackupRestoreConfirmation/res/values-es-rUS/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-es-rUS/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Realización de la copia de seguridad completa"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauración completa"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Se ha solicitado una copia de seguridad completa de todos los datos en una computadora de escritorio conectada. ¿Deseas permitirla?"\n\n"Si tú no has solicitado la copia de seguridad, no permitas que se realice la operación."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Se ha solicitado una copia de seguridad completa de todos los datos en una computadora de escritorio conectada. ¿Deseas permitirla?\n\nSi tú no has solicitado la copia de seguridad, no permitas que se realice la operación."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Copia de seguridad de mis datos"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"No realizar una copia de seguridad"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Se ha solicitado una restauración completa de todos los datos de una computadora de escritorio conectada. ¿Deseas permitirla?"\n\n"Si tú no has solicitado la restauración, no permitas que se realice la operación. Esto reemplazaría los datos actuales del dispositivo."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Se ha solicitado una restauración completa de todos los datos de una computadora de escritorio conectada. ¿Deseas permitirla?\n\nSi tú no has solicitado la restauración, no permitas que se realice la operación. Esto reemplazaría los datos actuales del dispositivo."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar mis datos"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"No restaurar"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Introduce tu contraseña actual de copia de seguridad a continuación:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-es/strings.xml b/packages/BackupRestoreConfirmation/res/values-es/strings.xml
index ef97e3c..7ce3990 100644
--- a/packages/BackupRestoreConfirmation/res/values-es/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-es/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Copia de seguridad completa"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauración completa"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Se ha solicitado una copia de seguridad completa de todos los datos en un ordenador conectado. ¿Quieres permitir la copia de seguridad?"\n\n"No debes permitir la copia de seguridad si no has realizado tú la solicitud."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Se ha solicitado una copia de seguridad completa de todos los datos en un ordenador conectado. ¿Quieres permitir la copia de seguridad?\n\nNo debes permitir la copia de seguridad si no has realizado tú la solicitud."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Copia de seguridad de datos"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"No hacer copia de seguridad"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Se ha solicitado una restauración completa de todos los datos desde un ordenador conectado. ¿Quieres permitir la restauración?"\n\n"No debes permitir la restauración si no has realizado tú la solicitud. Se sustituirán los datos actuales del dispositivo."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Se ha solicitado una restauración completa de todos los datos desde un ordenador conectado. ¿Quieres permitir la restauración?\n\nNo debes permitir la restauración si no has realizado tú la solicitud. Se sustituirán los datos actuales del dispositivo."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar mis datos"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"No restaurar"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Introduce a continuación la contraseña actual de copia de seguridad:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-et/strings.xml b/packages/BackupRestoreConfirmation/res/values-et/strings.xml
index 5a5c454..0f5fde2 100644
--- a/packages/BackupRestoreConfirmation/res/values-et/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-et/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Täielik varundus"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Täielik taastamine"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Taotleti kõikide andmete varundamist ühendatud lauaarvutist. Kas soovite seda lubada?"\n\n"Kui te ei taotlenud varundust, siis ärge lubage toimingut jätkata."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Taotleti kõikide andmete varundamist ühendatud lauaarvutist. Kas soovite seda lubada?\n\nKui te ei taotlenud varundust, siis ärge lubage toimingut jätkata."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Varunda mu andmed"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ära varunda"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Taotletud on kõikide andmete taastamist ühendatud lauaarvutist. Kas soovite seda lubada?"\n\n"Kui te ei taotlenud taastamist, siis ärge lubage toimingut jätkata. See asendab kõik praegu seadmes olevad andmed."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Taotletud on kõikide andmete taastamist ühendatud lauaarvutist. Kas soovite seda lubada?\n\nKui te ei taotlenud taastamist, siis ärge lubage toimingut jätkata. See asendab kõik praegu seadmes olevad andmed."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Taasta mu andmed"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ära taasta"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Sisestage allpool praegune varunduse parool:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-fa/strings.xml b/packages/BackupRestoreConfirmation/res/values-fa/strings.xml
index 4349444..8b20954 100644
--- a/packages/BackupRestoreConfirmation/res/values-fa/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-fa/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"پشتیبان‌گیری کامل"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"بازیابی کامل"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"درخواست پشتیبان گیری کامل از تمام داده‌ها به یک رایانه دسک‌تاپ متصل داده شده است. آیا می‌خواهید این عمل انجام شود؟"\n\n"اگر شما درخواست تهیهٔ نسخهٔ پشتیبان را نداده‌اید، اجازه‌ ادامه عملیات را ندهید."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"درخواست پشتیبان گیری کامل از تمام داده‌ها به یک رایانه دسک‌تاپ متصل داده شده است. آیا می‌خواهید این عمل انجام شود؟\n\nاگر شما درخواست تهیهٔ نسخهٔ پشتیبان را نداده‌اید، اجازه‌ ادامه عملیات را ندهید."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"از داده‌های من نسخهٔ پشتیبان تهیه شود"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"نسخهٔ پشتیبان تهیه نشود"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"بازیابی کامل تمام داده‌ها از یک رایانه دسک تاپ متصل درخواست شده است. آیا می‌خواهید این اجازه را بدهید؟"\n\n"اگر خود شما درخواست بازیابی نداده‌اید، اجازه ادامه این عملیات را ندهید. با این کار همه داده‌هایی که اکنون روی دستگاه است جایگزین می‌شود!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"بازیابی کامل تمام داده‌ها از یک رایانه دسک تاپ متصل درخواست شده است. آیا می‌خواهید این اجازه را بدهید؟\n\nاگر خود شما درخواست بازیابی نداده‌اید، اجازه ادامه این عملیات را ندهید. با این کار همه داده‌هایی که اکنون روی دستگاه است جایگزین می‌شود!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"بازیابی داده‌های من"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"بازیابی نشود"</string>
     <string name="current_password_text" msgid="8268189555578298067">"لطفاً گذرواژه نسخهٔ پشتیبان فعلی خود را در زیر وارد کنید:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-fi/strings.xml b/packages/BackupRestoreConfirmation/res/values-fi/strings.xml
index 80da29b..88aaaa5 100644
--- a/packages/BackupRestoreConfirmation/res/values-fi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-fi/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Täysi varmuuskopiointi"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Täysi palautus"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Kytketyn tietokoneen kaikista tiedoista on pyydetty täydellistä varmuuskopiota. Haluatko sallia tämän?"\n\n"Jos et ole itse pyytänyt varmuuskopiota, älä salli toimintoa."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Kytketyn tietokoneen kaikista tiedoista on pyydetty täydellistä varmuuskopiota. Haluatko sallia tämän?\n\nJos et ole itse pyytänyt varmuuskopiota, älä salli toimintoa."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Varmuuskopioi omat tiedot"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Älä varmuuskopioi"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Täydellinen varmuuskopio kytketyn tietokoneen kaikista tiedoista on pyydetty. Haluatko sallia tämän?"\n\n"Jos et ole itse pyytänyt varmuuskopiota, älä salli toimintoa. Tämä korvaa laitteesi kaikki nykyiset tiedot!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Täydellinen varmuuskopio kytketyn tietokoneen kaikista tiedoista on pyydetty. Haluatko sallia tämän?\n\nJos et ole itse pyytänyt varmuuskopiota, älä salli toimintoa. Tämä korvaa laitteesi kaikki nykyiset tiedot!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Palauta omat tiedot"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Älä palauta"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Kirjoita nykyinen varmuuskopioinnin salasana alla:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-fr/strings.xml b/packages/BackupRestoreConfirmation/res/values-fr/strings.xml
index 9af37b0..897d8d1 100644
--- a/packages/BackupRestoreConfirmation/res/values-fr/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-fr/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Sauvegarde complète"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauration complète"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Vous avez demandé une sauvegarde complète de l\'ensemble des données vers un ordinateur de bureau connecté. Voulez-vous l\'autoriser ?"\n\n"Si vous n\'avez pas demandé la sauvegarde vous-même, n\'autorisez pas la poursuite de l\'opération."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Vous avez demandé une sauvegarde complète de l\'ensemble des données vers un ordinateur de bureau connecté. Voulez-vous l\'autoriser ?\n\nSi vous n\'avez pas demandé la sauvegarde vous-même, n\'autorisez pas la poursuite de l\'opération."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Sauvegarder mes données"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ne pas sauvegarder"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Vous avez demandé une restauration complète de l\'ensemble des données à partir d\'un ordinateur de bureau connecté. Voulez-vous l\'autoriser ?"\n\n"Si vous n\'avez pas demandé vous-même la restauration, n\'autorisez pas sa poursuite. Cette opération remplacera toutes les données actuellement sur l\'appareil !"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Vous avez demandé une restauration complète de l\'ensemble des données à partir d\'un ordinateur de bureau connecté. Voulez-vous l\'autoriser ?\n\nSi vous n\'avez pas demandé vous-même la restauration, n\'autorisez pas sa poursuite. Cette opération remplacera toutes les données actuellement sur l\'appareil !"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurer mes données"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne pas restaurer"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Veuillez saisir votre mot de passe de sauvegarde actuel ci-dessous :"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
index 1495f8e..dd0c645 100644
--- a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"पूर्ण बैकअप"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"पूर्ण पुनर्स्‍थापना"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"कनेक्‍ट कि‍ए गए डेस्‍कटॉप कंप्‍यूटर से सभी डेटा के संपूर्ण बैकअप का अनुरोध कि‍या गया है. क्‍या आप इसकी अनुमति‍ देना चाहते हैं?"\n\n"यदि‍ आपने स्‍वयं बैकअप का अनुरोध नहीं कि‍या है, तो प्रक्रि‍या जारी रखने की अनुमति‍ न दें."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"कनेक्‍ट कि‍ए गए डेस्‍कटॉप कंप्‍यूटर से सभी डेटा के संपूर्ण बैकअप का अनुरोध कि‍या गया है. क्‍या आप इसकी अनुमति‍ देना चाहते हैं?\n\nयदि‍ आपने स्‍वयं बैकअप का अनुरोध नहीं कि‍या है, तो प्रक्रि‍या जारी रखने की अनुमति‍ न दें."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"मेरे डेटा का बैकअप लें"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"बैकअप न लें"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"कनेक्‍ट कि‍ए गए डेस्‍कटॉप कंप्‍यूटर से सभी डेटा की पूर्ण पुनर्स्थापना का अनुरोध कि‍या गया है. क्‍या आप इसकी अनुमति‍ देना चाहते हैं?"\n\n"यदि‍ आपने स्‍वयं पुनर्प्राप्ति‍ का अनुरोध नहीं कि‍या है, तो प्रक्रि‍या जारी रखने की अनुमति‍ न दें. इससे वर्तमान में आपके उपकरण पर मौजूद डेटा बदल जाएगा!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"कनेक्‍ट कि‍ए गए डेस्‍कटॉप कंप्‍यूटर से सभी डेटा की पूर्ण पुनर्स्थापना का अनुरोध कि‍या गया है. क्‍या आप इसकी अनुमति‍ देना चाहते हैं?\n\nयदि‍ आपने स्‍वयं पुनर्प्राप्ति‍ का अनुरोध नहीं कि‍या है, तो प्रक्रि‍या जारी रखने की अनुमति‍ न दें. इससे वर्तमान में आपके उपकरण पर मौजूद डेटा बदल जाएगा!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"मेरा डेटा पुनर्स्थापित करें"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"पुनर्स्‍थापित न करें"</string>
     <string name="current_password_text" msgid="8268189555578298067">"कृपया नीचे अपना वर्तमान बैकअप पासवर्ड डालें:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hr/strings.xml b/packages/BackupRestoreConfirmation/res/values-hr/strings.xml
index c5c4ce9..3451103 100644
--- a/packages/BackupRestoreConfirmation/res/values-hr/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hr/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Puna sigurnosna kopija"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Potpuno vraćanje"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Zatražena je potpuna sigurnosna kopija svih podataka na povezano stolno računalo. Želite li to dozvoliti?"\n\n"Ako niste vi zatražili sigurnosnu kopiju, ne dozvolite nastavak te radnje."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Zatražena je potpuna sigurnosna kopija svih podataka na povezano stolno računalo. Želite li to dozvoliti?\n\nAko niste vi zatražili sigurnosnu kopiju, ne dozvolite nastavak te radnje."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Izradi sigurnosnu kopiju mojih podataka"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ne radi sigurnosnu kopiju"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Zatraženo je potpuno vraćanje svih podataka s povezanog stolnog računala. Želite li to dozvoliti?"\n\n"Ako niste sami zatražili vraćanje, ne dozvolite nastavak radnje. To će zamijeniti sve podatke koji se trenutačno nalaze na uređaju!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Zatraženo je potpuno vraćanje svih podataka s povezanog stolnog računala. Želite li to dozvoliti?\n\nAko niste sami zatražili vraćanje, ne dozvolite nastavak radnje. To će zamijeniti sve podatke koji se trenutačno nalaze na uređaju!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Vrati moje podatke"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne vraćaj"</string>
     <string name="current_password_text" msgid="8268189555578298067">"U nastavku unesite trenutačnu zaporku za sigurnosnu kopiju:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hu/strings.xml b/packages/BackupRestoreConfirmation/res/values-hu/strings.xml
index c2901c1..73d9a63 100644
--- a/packages/BackupRestoreConfirmation/res/values-hu/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hu/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Teljes biztonsági mentés"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Teljes helyreállítás"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Kérés érkezett az összes adat biztonsági mentésére egy csatlakoztatott asztali számítógépre. Engedélyezi, hogy ez megtörténjen?"\n\n"Ha nem Ön kérte a mentést, ne engedélyezze a művelet folytatását."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Kérés érkezett az összes adat biztonsági mentésére egy csatlakoztatott asztali számítógépre. Engedélyezi, hogy ez megtörténjen?\n\nHa nem Ön kérte a mentést, ne engedélyezze a művelet folytatását."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Adatok biztonsági mentése"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ne mentsen"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Kérés érkezett egy csatlakoztatott asztali számítógép összes adatának teljes helyreállítására. Engedélyezi, hogy ez megtörténjen?"\n\n"Ha nem Ön kérte a visszaállítást, ne engedélyezze a művelet folytatását. Ez az eszközön lévő összes jelenlegi adatot felülírja!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Kérés érkezett egy csatlakoztatott asztali számítógép összes adatának teljes helyreállítására. Engedélyezi, hogy ez megtörténjen?\n\nHa nem Ön kérte a visszaállítást, ne engedélyezze a művelet folytatását. Ez az eszközön lévő összes jelenlegi adatot felülírja!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Adatok visszaállítása"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne állítsa vissza"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Kérjük, adja meg a jelenlegi biztonsági jelszót alább:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-in/strings.xml b/packages/BackupRestoreConfirmation/res/values-in/strings.xml
index 3fb6d6b..f2d6ad5 100644
--- a/packages/BackupRestoreConfirmation/res/values-in/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-in/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Pencadangan sepenuhnya"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Pemulihan sepenuhnya"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Cadangan lengkap semua data ke komputer yang tersambung telah diminta. Apakah Anda ingin mengizinkan hal ini dilakukan?"\n\n"Jika Anda tidak meminta pencadangan ini, jangan izinkan operasi dilanjutkan."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Cadangan lengkap semua data ke komputer yang tersambung telah diminta. Apakah Anda ingin mengizinkan hal ini dilakukan?\n\nJika Anda tidak meminta pencadangan ini, jangan izinkan operasi dilanjutkan."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Cadangkan data saya"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Jangan mencadangkan"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Pemulihan lengkap semua data dari komputer desktop yang tersambung telah diminta. Apakah Anda ingin mengizinkan hal ini?"\n\n"Jika Anda tidak meminta pemulihan ini, jangan izinkan operasi dilanjutkan. Operasi ini akan mengganti data apa pun yang saat ini ada dalam perangkat!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Pemulihan lengkap semua data dari komputer desktop yang tersambung telah diminta. Apakah Anda ingin mengizinkan hal ini?\n\nJika Anda tidak meminta pemulihan ini, jangan izinkan operasi dilanjutkan. Operasi ini akan mengganti data apa pun yang saat ini ada dalam perangkat!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Memulihkan data saya"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Jangan pulihkan"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Masukkan sandi cadangan Anda saat ini di bawah:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-it/strings.xml b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
index 9442ae3..a9e8ae4 100644
--- a/packages/BackupRestoreConfirmation/res/values-it/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Backup completo"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Ripristino totale"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"È stato richiesto un backup completo di tutti i dati su un computer desktop connesso. Consentire l\'operazione?"\n\n"Se non hai richiesto il backup, non consentire all\'operazione di procedere."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"È stato richiesto un backup completo di tutti i dati su un computer desktop connesso. Consentire l\'operazione?\n\nSe non hai richiesto il backup, non consentire all\'operazione di procedere."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Effettua backup dei miei dati"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Non eseguire il backup"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"È stato richiesto un ripristino completo di tutti i dati da un computer desktop connesso. Consentire questa operazione?"\n\n"Se non hai richiesto il ripristino, non consentire all\'operazione di procedere. Questa operazione sostituirà tutti i dati attualmente presenti sul dispositivo."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"È stato richiesto un ripristino completo di tutti i dati da un computer desktop connesso. Consentire questa operazione?\n\nSe non hai richiesto il ripristino, non consentire all\'operazione di procedere. Questa operazione sostituirà tutti i dati attualmente presenti sul dispositivo."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Ripristina i miei dati"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Non ripristinare"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Inserisci la tua password di backup corrente di seguito:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-iw/strings.xml b/packages/BackupRestoreConfirmation/res/values-iw/strings.xml
index a41944a..395c39e 100644
--- a/packages/BackupRestoreConfirmation/res/values-iw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-iw/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"גיבוי מלא"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"שחזור מלא"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"הוגשה בקשה לגיבוי מלא של כל הנתונים במחשב שולחני מחובר. האם אתה רוצה לאפשר פעולה זו? "\n\n"אם לא ביקשת את הגיבוי בעצמך, אל תאפשר לפעולה להמשיך."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"הוגשה בקשה לגיבוי מלא של כל הנתונים במחשב שולחני מחובר. האם אתה רוצה לאפשר פעולה זו? \n\nאם לא ביקשת את הגיבוי בעצמך, אל תאפשר לפעולה להמשיך."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"גבה את הנתונים שלי"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"אל תגבה"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"הוגשה בקשה לשחזור מלא של כל הנתונים ממחשב שולחני מחובר. האם אתה רוצה לאפשר פעולה זו? "\n" "\n" אם לא ביקשת את השחזור בעצמך, אל תאפשר לפעולה להמשיך. פעולה זו תחליף את כל הנתונים שנמצאים כעת במכשיר!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"הוגשה בקשה לשחזור מלא של כל הנתונים ממחשב שולחני מחובר. האם אתה רוצה לאפשר פעולה זו? \n \n אם לא ביקשת את השחזור בעצמך, אל תאפשר לפעולה להמשיך. פעולה זו תחליף את כל הנתונים שנמצאים כעת במכשיר!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"שחזר את הנתונים שלי"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"אל תשחזר"</string>
     <string name="current_password_text" msgid="8268189555578298067">"הזן את סיסמת הגיבוי הנוכחית למטה:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ja/strings.xml b/packages/BackupRestoreConfirmation/res/values-ja/strings.xml
index 98916c5..6859b35 100644
--- a/packages/BackupRestoreConfirmation/res/values-ja/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ja/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"フルバックアップ"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"完全な復元"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"接続しているデスクトップパソコンに対してすべてのデータのフルバックアップを行うようリクエストされています。許可しますか?"\n\n"ご自分でバックアップをリクエストしていない場合は、この操作の続行を許可しないでください。"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"接続しているデスクトップパソコンに対してすべてのデータのフルバックアップを行うようリクエストされています。許可しますか?\n\nご自分でバックアップをリクエストしていない場合は、この操作の続行を許可しないでください。"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"データをバックアップ"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"バックアップしない"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"接続されているデスクトップパソコンからすべてのデータを完全に復元するようにリクエストされています。許可しますか? "\n\n"ご自身で復元をリクエストしていない場合、操作の続行を許可しないでください。端末に現在あるデータがすべて置換されます。"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"接続されているデスクトップパソコンからすべてのデータを完全に復元するようにリクエストされています。許可しますか? \n\nご自身で復元をリクエストしていない場合、操作の続行を許可しないでください。端末に現在あるデータがすべて置換されます。"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"データを復元する"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"復元しない"</string>
     <string name="current_password_text" msgid="8268189555578298067">"以下に現在のバックアップ用のパスワードを入力してください:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ko/strings.xml b/packages/BackupRestoreConfirmation/res/values-ko/strings.xml
index 4137058..23c8662 100644
--- a/packages/BackupRestoreConfirmation/res/values-ko/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ko/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"전체 백업"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"전체 복원"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"연결된 데스크톱 컴퓨터에 대한 전체 데이터 백업을 요청했습니다. 백업을 실행하시겠습니까?"\n\n"직접 백업을 요청한 것이 아니라면 작업을 진행하지 마시기 바랍니다."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"연결된 데스크톱 컴퓨터에 대한 전체 데이터 백업을 요청했습니다. 백업을 실행하시겠습니까?\n\n직접 백업을 요청한 것이 아니라면 작업을 진행하지 마시기 바랍니다."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"데이터 백업"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"백업하지 않음"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"연결된 데스크톱 컴퓨터에 대한 전체 데이터 백업을 요청했습니다. 백업을 실행하시겠습니까?"\n\n"직접 백업을 요청한 것이 아니라면 작업을 진행하지 마시기 바랍니다. 기기에 있는 모든 데이터가 변경됩니다."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"연결된 데스크톱 컴퓨터에 대한 전체 데이터 백업을 요청했습니다. 백업을 실행하시겠습니까?\n\n직접 백업을 요청한 것이 아니라면 작업을 진행하지 마시기 바랍니다. 기기에 있는 모든 데이터가 변경됩니다."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"데이터 복원"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"복원하지 않음"</string>
     <string name="current_password_text" msgid="8268189555578298067">"아래에 현재 사용 중인 백업 비밀번호를 입력하세요."</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-lt/strings.xml b/packages/BackupRestoreConfirmation/res/values-lt/strings.xml
index 4e9efc5..44e67de 100644
--- a/packages/BackupRestoreConfirmation/res/values-lt/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-lt/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Visos atsarginės kopijos kūrimas"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Visas atkūrimas"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Prijungtame staliniame kompiuteryje pageidauta sukurti visų duomenų atsarginę kopiją. Ar norite, kad tai būtų atlikta?"\n\n"Jei patys atsarginės kopijos kurti neprašėte, neleiskite pradėti operacijos."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Prijungtame staliniame kompiuteryje pageidauta sukurti visų duomenų atsarginę kopiją. Ar norite, kad tai būtų atlikta?\n\nJei patys atsarginės kopijos kurti neprašėte, neleiskite pradėti operacijos."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Kurti atsarginę duomenų kopiją"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nekurti atsarginės kopijos"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Pateikta visų staliniame kompiuteryje saugomų duomenų visiško atkūrimo užklausa. Ar norite, kad tai būtų atlikta?"\n\n"Jei patys atkurti neprašėte, neleiskite pradėti operacijos. Kitaip bus pakeisti visi dabar įrenginyje saugomi duomenys!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Pateikta visų staliniame kompiuteryje saugomų duomenų visiško atkūrimo užklausa. Ar norite, kad tai būtų atlikta?\n\nJei patys atkurti neprašėte, neleiskite pradėti operacijos. Kitaip bus pakeisti visi dabar įrenginyje saugomi duomenys!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Atkurti mano duomenis"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Neatkurti"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Toliau įveskite dabartinį atsarginės kopijos slaptažodį:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-lv/strings.xml b/packages/BackupRestoreConfirmation/res/values-lv/strings.xml
index b8ce24b..c58d6fd 100644
--- a/packages/BackupRestoreConfirmation/res/values-lv/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-lv/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Pilna dublēšana"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Pilna atjaunošana"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Ir pieprasīta visu datu pilnīga dublēšana savienotā galda datorā. Vai vēlaties to atļaut?"\n\n"Ja neesat pieprasījis dublēšanu, neatļaujiet turpināt šo darbību."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Ir pieprasīta visu datu pilnīga dublēšana savienotā galda datorā. Vai vēlaties to atļaut?\n\nJa neesat pieprasījis dublēšanu, neatļaujiet turpināt šo darbību."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Dublēt manus datus"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Neveidot dublējumu"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Ir pieprasīta visu savienotā galda datora datu pilnīga atjaunošana. Vai vēlaties to atļaut?"\n\n"Ja neesat pieprasījis atjaunošanu, neatļaujiet turpināt šo darbību. Tās rezultātā tiks aizstāti visi pašreiz ierīcē esošie dati!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Ir pieprasīta visu savienotā galda datora datu pilnīga atjaunošana. Vai vēlaties to atļaut?\n\nJa neesat pieprasījis atjaunošanu, neatļaujiet turpināt šo darbību. Tās rezultātā tiks aizstāti visi pašreiz ierīcē esošie dati!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Atjaunot manus datus"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Neatjaunot"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Lūdzu, tālāk ievadiet pašreizējo dublējuma paroli:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ms/strings.xml b/packages/BackupRestoreConfirmation/res/values-ms/strings.xml
index bcfa615..65a9ede 100644
--- a/packages/BackupRestoreConfirmation/res/values-ms/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ms/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Sandaran penuh"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Pemulihan penuh"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Sandaran lengkap bagi semua data ke komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?"\n\n"Jika anda tidak meminta sandaran ini sendiri, jangan benarkan operasi diteruskan."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Sandaran lengkap bagi semua data ke komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?\n\nJika anda tidak meminta sandaran ini sendiri, jangan benarkan operasi diteruskan."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Sandarkan data saya"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Jangan buat sandaran"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Pemulihan penuh semua data dari komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?"\n\n"Jika anda tidak meminta pemulihan ini sendiri, jangan benarkan operasi ini diteruskan. Ini akan menggantikan sebarang data semasa pada peranti!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Pemulihan penuh semua data dari komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?\n\nJika anda tidak meminta pemulihan ini sendiri, jangan benarkan operasi ini diteruskan. Ini akan menggantikan sebarang data semasa pada peranti!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Pulihkan data saya"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Jangan kembalikan"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Sila masukkan kata laluan sandaran semasa anda di bawah:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-nb/strings.xml b/packages/BackupRestoreConfirmation/res/values-nb/strings.xml
index a93c081..d43ec2f 100644
--- a/packages/BackupRestoreConfirmation/res/values-nb/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-nb/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Fullstendig sikkerhetskopi"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Fullstendig gjenoppretting"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"En full sikkerhetskopi av alle dataene til en tilkoblet datamaskin er forespurt. Vil du tillate dette?"\n\n"Hvis du ikke har bedt om sikkerhetskopieringen selv, må du ikke tillate at operasjonen fortsetter."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"En full sikkerhetskopi av alle dataene til en tilkoblet datamaskin er forespurt. Vil du tillate dette?\n\nHvis du ikke har bedt om sikkerhetskopieringen selv, må du ikke tillate at operasjonen fortsetter."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Sikkerhetskopier dataene mine"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ikke sikkerhetskopiér"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"En full gjenoppretting av alle data fra en tilkoblet datamaskin er forespurt. Vil du tillate dette?"\n\n"Hvis du ikke har bedt om gjenopprettingen selv, må du ikke la operasjonen fortsette. Handlingen vil erstatte alle dataene som ligger på enheten!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"En full gjenoppretting av alle data fra en tilkoblet datamaskin er forespurt. Vil du tillate dette?\n\nHvis du ikke har bedt om gjenopprettingen selv, må du ikke la operasjonen fortsette. Handlingen vil erstatte alle dataene som ligger på enheten!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Gjenopprett dataene mine"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ikke gjenopprett"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Skriv inn ditt nåværende passord for sikkerhetskopiering nedenfor:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-nl/strings.xml b/packages/BackupRestoreConfirmation/res/values-nl/strings.xml
index d525429..1bf73e9 100644
--- a/packages/BackupRestoreConfirmation/res/values-nl/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-nl/strings.xml
@@ -18,17 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Volledige back-up"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Volledig herstel"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Er is een volledige back-up van alle gegevens naar een verbonden desktopcomputer aangevraagd. Wilt u dit toestaan?"\n\n"Als u de back-up zelf niet heeft aangevraagd, moet u niet toestaan dat de bewerking wordt uitgevoerd."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Er is een volledige back-up van alle gegevens naar een verbonden desktopcomputer aangevraagd. Wilt u dit toestaan?\n\nAls u de back-up zelf niet heeft aangevraagd, moet u niet toestaan dat de bewerking wordt uitgevoerd."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Back-up maken van mijn gegevens"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Geen back-up maken"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Er is volledig herstel van alle gegevens van een verbonden desktopcomputer aangevraagd. Wilt u dit toestaan?"\n\n"Als u het herstel zelf niet heeft aangevraagd, moet u niet toestaan dat de bewerking wordt uitgevoerd. Bij herstel worden alle gegevens op het apparaat vervangen."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Er is volledig herstel van alle gegevens van een verbonden desktopcomputer aangevraagd. Wilt u dit toestaan?\n\nAls u het herstel zelf niet heeft aangevraagd, moet u niet toestaan dat de bewerking wordt uitgevoerd. Bij herstel worden alle gegevens op het apparaat vervangen."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Mijn gegevens herstellen"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Niet herstellen"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Geef hieronder uw huidige back-upwachtwoord op:"</string>
     <string name="device_encryption_restore_text" msgid="1570864916855208992">"Geef hieronder uw wachtwoord voor apparaatcodering op."</string>
-    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Geef hieronder uw wachtwoord voor apparaatcodering op. Dit wordt ook gebruikt om het back-uparchief te coderen."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Geef hieronder uw wachtwoord voor apparaatversleuteling op. Dit wordt ook gebruikt om het back-uparchief te versleutelen."</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"Geef een wachtwoord op dat u wilt gebruiken voor het coderen van de gegevens van de volledige back-up. Als u dit leeg laat, wordt uw huidige back-upwachtwoord gebruikt:"</string>
-    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Als u de gegevens van de volledige back-up wilt coderen, geeft u daarvoor hieronder een wachtwoord op:"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Als u de gegevens van de volledige back-up wilt versleutelen, geeft u daarvoor hieronder een wachtwoord op:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"Als deze herstelgegevens zijn gecodeerd, geeft u hieronder het wachtwoord op:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Back-up starten..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Back-up voltooid"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pl/strings.xml b/packages/BackupRestoreConfirmation/res/values-pl/strings.xml
index 1a70bb0..122b5df 100644
--- a/packages/BackupRestoreConfirmation/res/values-pl/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pl/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Pełna kopia zapasowa"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Pełne przywracanie"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Zażądano wykonania pełnej kopii zapasowej wszystkich danych na podłączonym komputerze stacjonarnym. Czy chcesz na to zezwolić?"\n\n"Jeśli żądanie utworzenia kopii zapasowej nie pochodzi od Ciebie, nie zezwalaj na kontynuowanie tej operacji."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Zażądano wykonania pełnej kopii zapasowej wszystkich danych na podłączonym komputerze stacjonarnym. Czy chcesz na to zezwolić?\n\nJeśli żądanie utworzenia kopii zapasowej nie pochodzi od Ciebie, nie zezwalaj na kontynuowanie tej operacji."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Utwórz kopię zapasową danych"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nie twórz kopii zapasowej"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Zażądano pełnego przywrócenia wszystkich danych z połączonego komputera stacjonarnego. Czy chcesz na to zezwolić?"\n\n"Jeśli żądanie przywrócenia nie pochodzi od Ciebie, nie zezwalaj na kontynuowanie tej operacji. Spowoduje to zastąpienie wszelkich danych znajdujących się aktualnie w urządzeniu."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Zażądano pełnego przywrócenia wszystkich danych z połączonego komputera stacjonarnego. Czy chcesz na to zezwolić?\n\nJeśli żądanie przywrócenia nie pochodzi od Ciebie, nie zezwalaj na kontynuowanie tej operacji. Spowoduje to zastąpienie wszelkich danych znajdujących się aktualnie w urządzeniu."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Przywróć moje dane"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Nie przywracaj"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Wpisz poniżej aktualne hasło kopii zapasowej:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
index a486f54..477d423 100644
--- a/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Cópia de segurança completa"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauro completo"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitada uma cópia de segurança completa de todos os dados para um computador. Pretende permitir esta operação?"\n\n"Caso não tenha solicitado a cópia de segurança, não permita que a operação prossiga."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitada uma cópia de segurança completa de todos os dados para um computador. Pretende permitir esta operação?\n\nCaso não tenha solicitado a cópia de segurança, não permita que a operação prossiga."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer cópia de seg. dos dados"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Não efetuar cópia de seg."</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitado um restauro completo de todos os dados a partir de um computador. Pretende permitir esta operação?"\n\n"Caso não tenha solicitado o restauro, não permita que a operação prossiga. Isto substituirá os dados existentes no equipamento!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitado um restauro completo de todos os dados a partir de um computador. Pretende permitir esta operação?\n\nCaso não tenha solicitado o restauro, não permita que a operação prossiga. Isto substituirá os dados existentes no equipamento!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar os meus dados"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Introduza a palavra-passe de cópia de segurança atual abaixo:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pt/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt/strings.xml
index 99fd2e1..a56b31ca 100644
--- a/packages/BackupRestoreConfirmation/res/values-pt/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pt/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Backup completo"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauração completa"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Deseja permitir que isso aconteça?"\n\n"Caso você não tenha solicitado o backup, não permita que a operação prossiga."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Deseja permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer backup de meus dados"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer backup"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Deseja permitir que isso ocorra?"\n\n"Caso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Deseja permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar meus dados"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Digite sua senha de backup atual abaixo:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
index 4c49bf8..839edbb 100644
--- a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Copiere de rezervă completă"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restabilire completă"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriţi să permiteţi acest lucru?"\n\n"Dacă nu aţi solicitat dvs. copierea de rezervă, nu permiteţi ca operaţiunea să continue."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriţi să permiteţi acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteţi ca operaţiunea să continue."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Creaţi copii de rezervă pentru datele dvs."</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nu creaţi copii de rezervă"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriţi să permiteţi acest lucru?"\n\n"Dacă nu dvs. aţi solicitat această restabilire, nu permiteţi continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriţi să permiteţi acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteţi continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliţi datele dvs."</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Nu restabiliţi"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Introduceţi mai jos parola actuală pentru copia de rezervă:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ru/strings.xml b/packages/BackupRestoreConfirmation/res/values-ru/strings.xml
index 0dbba05..f516493 100644
--- a/packages/BackupRestoreConfirmation/res/values-ru/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ru/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Полное резервное копирование"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Полное восстановление"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Запрошено резервное копирование всех данных на подключенном компьютере. Разрешить?"\n\n"Если вы не запрашивали этого, не разрешайте выполнение операции."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Запрошено резервное копирование всех данных на подключенном компьютере. Разрешить?\n\nЕсли вы не запрашивали этого, не разрешайте выполнение операции."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Создать резервную копию данных"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Не создавать резервную копию"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Подключенный компьютер запрашивает восстановление всех данных. Разрешить?"\n\n"Если вы не запрашивали этого, не разрешайте выполнение операции, т. к. она заменит все данные на этом устройстве."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Подключенный компьютер запрашивает восстановление всех данных. Разрешить?\n\nЕсли вы не запрашивали этого, не разрешайте выполнение операции, т. к. она заменит все данные на этом устройстве."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Восстановить данные"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Не восстанавливать"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Введите пароль для резервного копирования:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
index b432165..21e21b5 100644
--- a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Úplná záloha"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Úplné obnovenie"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Bola vyžiadaná úplná záloha všetkých dát do pripojeného počítača. Chcete túto akciu povoliť?"\n\n"Ak ste zálohu nevyžiadali vy, túto operáciu nepovoľujte."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Bola vyžiadaná úplná záloha všetkých dát do pripojeného počítača. Chcete túto akciu povoliť?\n\nAk ste zálohu nevyžiadali vy, túto operáciu nepovoľujte."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Zálohovať údaje"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nezálohovať"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?"\n\n"Ak ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?\n\nAk ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnoviť údaje"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Neobnoviť"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo pre zálohu nižšie:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sl/strings.xml b/packages/BackupRestoreConfirmation/res/values-sl/strings.xml
index 5df0449..17d4d80 100644
--- a/packages/BackupRestoreConfirmation/res/values-sl/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sl/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Polna varnostna kopija"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Popolna obnova"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Zahtevano je popolno varnostno kopiranje vseh podatkov v povezanem računalniku. Ali želite to dovoliti?"\n\n"Če varnostnega kopiranja niste zahtevali, ne dovolite nadaljevanja postopka."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Zahtevano je popolno varnostno kopiranje vseh podatkov v povezanem računalniku. Ali želite to dovoliti?\n\nČe varnostnega kopiranja niste zahtevali, ne dovolite nadaljevanja postopka."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Varnostno kopiraj moje podatke"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Brez varnostnega kopiranja"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Zahtevana je popolna obnovitev vseh podatkov iz povezanega računalnika. Ali želite to dovoliti?"\n\n"Če niste zahtevali obnovitve, ne dovolite nadaljevanja postopka. Sicer bodo zamenjani vsi podatki, trenutno shranjeni v napravi."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Zahtevana je popolna obnovitev vseh podatkov iz povezanega računalnika. Ali želite to dovoliti?\n\nČe niste zahtevali obnovitve, ne dovolite nadaljevanja postopka. Sicer bodo zamenjani vsi podatki, trenutno shranjeni v napravi."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnovi moje podatke"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne obnovi"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Spodaj vnesite trenutno geslo za varnostno kopiranje:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sr/strings.xml b/packages/BackupRestoreConfirmation/res/values-sr/strings.xml
index 0a5859e..82cb85f 100644
--- a/packages/BackupRestoreConfirmation/res/values-sr/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sr/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Прављење резервне копије свих података"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Потпуно враћање"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Захтевана је потпуна резервна копија свих података на повезани стони рачунар. Да ли желите да дозволите то?"\n\n"Ако нисте лично захтевали резервну копију, не дозвољавајте наставак радње."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Захтевана је потпуна резервна копија свих података на повезани стони рачунар. Да ли желите да дозволите то?\n\nАко нисте лично захтевали резервну копију, не дозвољавајте наставак радње."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Направи резервну копију мојих података"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Не прави резервне копије"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Захтевано је потпуно враћање свих података са повезаног стоног рачунара. Да ли желите да дозволите то?"\n\n"Ако нисте лично захтевали враћање, не дозвољавајте наставак радње. Тиме ћете заменити све податке који су тренутно на уређају!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Захтевано је потпуно враћање свих података са повезаног стоног рачунара. Да ли желите да дозволите то?\n\nАко нисте лично захтевали враћање, не дозвољавајте наставак радње. Тиме ћете заменити све податке који су тренутно на уређају!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Врати моје податке"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Не враћај"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Унесите тренутну лозинку резервне копије у наставку:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sv/strings.xml b/packages/BackupRestoreConfirmation/res/values-sv/strings.xml
index 167fce3..a2ef430 100644
--- a/packages/BackupRestoreConfirmation/res/values-sv/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sv/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Fullständig säkerhetskopiering"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Fullständig återställning"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"En fullständig säkerhetskopia av alla data till en ansluten dator har begärts. Vill du tillåta detta?"\n\n"Om du inte själv begärde säkerhetskopian ska du inte tillåta detta."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"En fullständig säkerhetskopia av alla data till en ansluten dator har begärts. Vill du tillåta detta?\n\nOm du inte själv begärde säkerhetskopian ska du inte tillåta detta."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Säkerhetskopiera mina data"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Säkerhetskopiera inte"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"En fullständig återställning av alla data från en ansluten dator har begärts. Vill du tillåta detta? "\n" "\n" Om du inte själv har begärt återställningen ska du inte tillåta den. Alla data som finns på enheten kommer då att ersättas!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"En fullständig återställning av alla data från en ansluten dator har begärts. Vill du tillåta detta? \n \n Om du inte själv har begärt återställningen ska du inte tillåta den. Alla data som finns på enheten kommer då att ersättas!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Återställ mina data"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Återställ inte"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Ange det aktuella lösenordet för säkerhetskopian nedan:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 493c168..619a6db 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -17,11 +17,11 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
-    <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejeza kamili"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?"\n\n" Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
-    <string name="allow_backup_button_label" msgid="4217228747769644068">"Cheleza data yangu"</string>
+    <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
+    <string name="allow_backup_button_label" msgid="4217228747769644068">"Hifadhi nakala ya data yangu"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?"\n\n" Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Rejesha upya data yangu"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Usirejeshe upya"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri lako la chelezo hapo chini:"</string>
@@ -32,7 +32,7 @@
     <string name="restore_enc_password_text" msgid="6140898525580710823">"Ikiwa data iliyorejeshwa upya, tafadhali ingiza nenosiri lililo hapo chini:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Inaanza kuhifadhi..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Imemaliza kuhifadhi"</string>
-    <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejeza..."</string>
-    <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejeza kumekamilika"</string>
+    <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejesha..."</string>
+    <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejesha kumekamilika"</string>
     <string name="toast_timeout" msgid="5276598587087626877">"Muda wa uendeshaji umeisha"</string>
 </resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-th/strings.xml b/packages/BackupRestoreConfirmation/res/values-th/strings.xml
index 2d08620..c0543a0 100644
--- a/packages/BackupRestoreConfirmation/res/values-th/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-th/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"การสำรองข้อมูลทั้งหมด"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"การคืนค่าทั้งหมด"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"เราได้รับการขอให้ทำการสำรองข้อมูลทั้งหมดลงในคอมพิวเตอร์เดสก์ท็อปที่เชื่อมต่ออยู่ คุณต้องการอนุญาตให้ดำเนินการตามนี้หรือไม่"\n\n" หากคุณไม่ได้เป็นผู้ขอให้ทำการสำรองข้อมูลดังกล่าว โปรดอย่าอนุญาตให้ดำเนินการ"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"เราได้รับการขอให้ทำการสำรองข้อมูลทั้งหมดลงในคอมพิวเตอร์เดสก์ท็อปที่เชื่อมต่ออยู่ คุณต้องการอนุญาตให้ดำเนินการตามนี้หรือไม่\n\n หากคุณไม่ได้เป็นผู้ขอให้ทำการสำรองข้อมูลดังกล่าว โปรดอย่าอนุญาตให้ดำเนินการ"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"สำรองข้อมูลของฉัน"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"ไม่ต้องสำรองข้อมูล"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"เราได้รับการขอให้ทำการคืนค่าข้อมูลทั้งหมดจากคอมพิวเตอร์เดสก์ท็อปที่เชื่อมต่ออยู่ คุณต้องการอนุญาตให้ดำเนินการตามนี้หรือไม่"\n\n" หากคุณไม่ได้เป็นผู้ขอให้ทำการคืนค่าดังกล่าว โปรดอย่าอนุญาตให้ดำเนินการ การดำเนินการนี้จะแทนค่าข้อมูลปัจจุบันทั้งหมดในอุปกรณ์"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"เราได้รับการขอให้ทำการคืนค่าข้อมูลทั้งหมดจากคอมพิวเตอร์เดสก์ท็อปที่เชื่อมต่ออยู่ คุณต้องการอนุญาตให้ดำเนินการตามนี้หรือไม่\n\n หากคุณไม่ได้เป็นผู้ขอให้ทำการคืนค่าดังกล่าว โปรดอย่าอนุญาตให้ดำเนินการ การดำเนินการนี้จะแทนค่าข้อมูลปัจจุบันทั้งหมดในอุปกรณ์"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"คืนค่าข้อมูลของฉัน"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"ไม่คืนค่า"</string>
     <string name="current_password_text" msgid="8268189555578298067">"โปรดป้อนรหัสผ่านการสำรองข้อมูลปัจจุบันของคุณด้านล่างนี้:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-tl/strings.xml b/packages/BackupRestoreConfirmation/res/values-tl/strings.xml
index 97662b5..5c564ba 100644
--- a/packages/BackupRestoreConfirmation/res/values-tl/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-tl/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Ganap na pag-backup"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Ganap na pagpapanumbalik"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Hiniling ang isang buong pag-backup ng lahat ng data sa isang nakakonektang desktop computer. Gusto mo ba itong payagang maganap? "\n\n"Kung hindi ikaw mismo ang humiling ng pag-backup, huwag payagang magpatuloy ang pagpapatakbo."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Hiniling ang isang buong pag-backup ng lahat ng data sa isang nakakonektang desktop computer. Gusto mo ba itong payagang maganap? \n\nKung hindi ikaw mismo ang humiling ng pag-backup, huwag payagang magpatuloy ang pagpapatakbo."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"I-back up ang aking data"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Huwag i-back up"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Hiniling ang isang buong pagpapanumbalik ng lahat ng data mula sa isang nakakonektang desktop computer. Gusto mo ba itong payagang maganap?"\n\n"Kung hindi ikaw mismo ang humiling ng pagpapanumbalik, huwag payagang magpatuloy ang pagpapatakbo. Papalitan nito ang anumang data na kasalukuyang nasa device!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Hiniling ang isang buong pagpapanumbalik ng lahat ng data mula sa isang nakakonektang desktop computer. Gusto mo ba itong payagang maganap?\n\nKung hindi ikaw mismo ang humiling ng pagpapanumbalik, huwag payagang magpatuloy ang pagpapatakbo. Papalitan nito ang anumang data na kasalukuyang nasa device!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Ipanumbalik ang aking data"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Huwag ipanumbalik"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Pakilagay ang iyong kasalukuyang backup na password sa ibaba:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-tr/strings.xml b/packages/BackupRestoreConfirmation/res/values-tr/strings.xml
index 62b9f4b..591be7c 100644
--- a/packages/BackupRestoreConfirmation/res/values-tr/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-tr/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Tam yedekleme"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Tam geri yükleme"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Tüm verilerin bağlı bir masaüstü bilgisayara tam olarak yedeklenmesi için istekte bulunuldu?"\n\n"Yedekleme isteğinde siz bulunmadıysanız, işlemin devam etmesine izin vermeyin."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Tüm verilerin bağlı bir masaüstü bilgisayara tam olarak yedeklenmesi için istekte bulunuldu?\n\nYedekleme isteğinde siz bulunmadıysanız, işlemin devam etmesine izin vermeyin."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Verilerimi yedekle"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Yedekleme"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Tüm verilerin, bağlı bir masaüstü bilgisayardan tam olarak geri yüklenmesi için istekte bulunuldu. Bu işleme izin vermek istiyor musunuz?"\n\n"Geri yükleme isteğinde siz bulunmadıysanız, işlemin ilerlemesine izin vermeyin. Bu işlem, cihazınızdaki tüm verileri silip üzerine yazar!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Tüm verilerin, bağlı bir masaüstü bilgisayardan tam olarak geri yüklenmesi için istekte bulunuldu. Bu işleme izin vermek istiyor musunuz?\n\nGeri yükleme isteğinde siz bulunmadıysanız, işlemin ilerlemesine izin vermeyin. Bu işlem, cihazınızdaki tüm verileri silip üzerine yazar!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Verilerimi geri yükle"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Geri yükleme"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Lütfen mevcut yedekleme şifrenizi aşağıya girin:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-uk/strings.xml b/packages/BackupRestoreConfirmation/res/values-uk/strings.xml
index f3dfa1c..b4ddef1 100644
--- a/packages/BackupRestoreConfirmation/res/values-uk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-uk/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Повне резервне копіювання"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Повне відновлення"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Надійшов запит на повне резервне копіювання всіх даних на під’єднаний настільний комп’ютер. Дозволити це?"\n\n"Якщо ви не надсилали запит на резервне копіювання, не дозволяйте виконувати цю операцію."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Надійшов запит на повне резервне копіювання всіх даних на під’єднаний настільний комп’ютер. Дозволити це?\n\nЯкщо ви не надсилали запит на резервне копіювання, не дозволяйте виконувати цю операцію."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Резервне копіювання даних"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Не створювати резервну копію"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Надійшов запит на повне відновлення всіх даних із під’єднаного настільного комп’ютера. Дозволити це?"\n\n"Якщо ви не надсилали запит на відновлення, не дозволяйте виконувати цю операцію. Усі розміщені зараз на пристрої дані буде замінено!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Надійшов запит на повне відновлення всіх даних із під’єднаного настільного комп’ютера. Дозволити це?\n\nЯкщо ви не надсилали запит на відновлення, не дозволяйте виконувати цю операцію. Усі розміщені зараз на пристрої дані буде замінено!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Відновити мої дані"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Не відновлювати"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Введіть свій поточний пароль резервного копіювання нижче:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-vi/strings.xml b/packages/BackupRestoreConfirmation/res/values-vi/strings.xml
index ac34a993..69e8f9c 100644
--- a/packages/BackupRestoreConfirmation/res/values-vi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-vi/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Sao lưu hoàn toàn"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Khôi phục hoàn toàn"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Đã yêu cầu sao lưu đầy đủ toàn bộ dữ liệu tới máy tính được kết nối. Bạn có muốn cho phép điều này xảy ra không?"\n\n"Nếu không phải bản thân bạn yêu cầu sao lưu, đừng cho phép thao tác này tiếp tục."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Đã yêu cầu sao lưu đầy đủ toàn bộ dữ liệu tới máy tính được kết nối. Bạn có muốn cho phép điều này xảy ra không?\n\nNếu không phải bản thân bạn yêu cầu sao lưu, đừng cho phép thao tác này tiếp tục."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Sao lưu dữ liệu của tôi"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Không sao lưu"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Đã yêu cầu khôi phục đầy đủ toàn bộ dữ liệu từ máy tính được kết nối. Bạn có muốn cho phép điều này xảy ra không?"\n\n"Nếu không phải bản thân bạn yêu cầu khôi phục, đừng cho phép thao tác này tiếp tục. Thao tác này sẽ thay thế mọi dữ liệu hiện tại trên thiết bị!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Đã yêu cầu khôi phục đầy đủ toàn bộ dữ liệu từ máy tính được kết nối. Bạn có muốn cho phép điều này xảy ra không?\n\nNếu không phải bản thân bạn yêu cầu khôi phục, đừng cho phép thao tác này tiếp tục. Thao tác này sẽ thay thế mọi dữ liệu hiện tại trên thiết bị!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Khôi phục dữ liệu của tôi"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Không khôi phục"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Vui lòng nhập mật khẩu sao lưu hiện tại của bạn bên dưới:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
index 5f3ca05..b2764fb 100644
--- a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"完全备份"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"完全还原"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面计算机。允许此操作吗?"\n\n"如果您本人未要求备份,请阻止该操作。"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面计算机。允许此操作吗?\n\n如果您本人未要求备份,请阻止该操作。"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"备份我的数据"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"不备份"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"系统请求从连接的桌面计算机完整还原所有数据。允许此操作吗?"\n\n"如果您本人未要求还原,请阻止该操作。该操作会覆盖设备上当前的所有数据!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"系统请求从连接的桌面计算机完整还原所有数据。允许此操作吗?\n\n如果您本人未要求还原,请阻止该操作。该操作会覆盖设备上当前的所有数据!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"恢复我的数据"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"不恢复"</string>
     <string name="current_password_text" msgid="8268189555578298067">"请在下方输入您的当前备份密码:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rTW/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rTW/strings.xml
index 5afb226..4da6114 100644
--- a/packages/BackupRestoreConfirmation/res/values-zh-rTW/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rTW/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"完整備份"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"完整還原"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"系統收到將所有資料完整備份至連線電腦的要求,請問您允許進行備份嗎?"\n\n"如果您本人並未提出備份要求,請勿允許繼續進行這項作業。"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"系統收到將所有資料完整備份至連線電腦的要求,請問您允許進行備份嗎?\n\n如果您本人並未提出備份要求,請勿允許繼續進行這項作業。"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"備份我的資料"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"不要備份"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"系統收到從連線電腦完整還原所有資料的要求,請問您允許進行還原嗎?"\n\n"如果您本人並未提出還原要求,請勿允許繼續進行這項作業。這項作業將取代裝置上現有的全部資料!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"系統收到從連線電腦完整還原所有資料的要求,請問您允許進行還原嗎?\n\n如果您本人並未提出還原要求,請勿允許繼續進行這項作業。這項作業將取代裝置上現有的全部資料!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"還原我的資料"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"不要還原"</string>
     <string name="current_password_text" msgid="8268189555578298067">"請在下面輸入您目前的備份密碼:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-zu/strings.xml b/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
index 241bd37..b62b7af 100644
--- a/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Ukulondolozwa okuphelele"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Ukubuyisela okuphelele"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Kucelwe ukwesekelwa ngokulondoloza okuphelele kwayo yonke imininingo ekwi-desktop yekhompuyutha exhunyiwe. Angifuni ukuvumel alokhu ukuthi kwenzeke?"\n\n"Uma kuwukuthi awuzange ucele ukuthi kwesekelwe ngokulondoloza wena uqobo lwakho, ungavumeli ukuthi lolu hlelo luqhubekele phambili."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Kucelwe ukwesekelwa ngokulondoloza okuphelele kwayo yonke imininingo ekwi-desktop yekhompuyutha exhunyiwe. Angifuni ukuvumel alokhu ukuthi kwenzeke?\n\nUma kuwukuthi awuzange ucele ukuthi kwesekelwe ngokulondoloza wena uqobo lwakho, ungavumeli ukuthi lolu hlelo luqhubekele phambili."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Sekela ngokulondoloza imininingo yami"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ungenzi isipele"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Kucelwe ukubuyiselwa esimweni okuphelele kwayo yonke imininingo yakho kwi-desktop yekhompuyutha exhunyiswe. Ngabe ufuna ukuvumela lokhu ukuthi kwenzeke?"\n\n"Uma ungazange ucele ukuthi lokhu kwenzeke wena uqobo, ungavumeli lokhu ukuthi kuqhubekele phambili. Lokhu kuzothatha indawo yayo yonke imininingo ekhona njengamanje kwi-device!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Kucelwe ukubuyiselwa esimweni okuphelele kwayo yonke imininingo yakho kwi-desktop yekhompuyutha exhunyiswe. Ngabe ufuna ukuvumela lokhu ukuthi kwenzeke?\n\nUma ungazange ucele ukuthi lokhu kwenzeke wena uqobo, ungavumeli lokhu ukuthi kuqhubekele phambili. Lokhu kuzothatha indawo yayo yonke imininingo ekhona njengamanje kwi-device!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Buyisela esimweni imininingo yami"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ungabuyiseli esimweni"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Sicela ufake iphasiwedi yakho yamanje yokwenza isipele ngezansi:"</string>
diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk
index 56b8005..9961168 100644
--- a/packages/DefaultContainerService/Android.mk
+++ b/packages/DefaultContainerService/Android.mk
@@ -11,6 +11,8 @@
 
 LOCAL_CERTIFICATE := platform
 
+LOCAL_PRIVILEGED_MODULE := true
+
 include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index d3bd197..6e34bbb 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -146,6 +146,8 @@
                 Slog.e(TAG, "Could not copy URI " + packageURI.toString() + " Security: "
                                 + e.getMessage());
                 return PackageManager.INSTALL_FAILED_INVALID_APK;
+            } finally {
+                IoUtils.closeQuietly(autoOut);
             }
         }
 
@@ -293,10 +295,10 @@
             try {
                 while ((item = pm.nextPackageToClean(item)) != null) {
                     final UserEnvironment userEnv = new UserEnvironment(item.userId);
-                    eraseFiles(userEnv.getExternalStorageAppDataDirectory(item.packageName));
-                    eraseFiles(userEnv.getExternalStorageAppMediaDirectory(item.packageName));
+                    eraseFiles(userEnv.buildExternalStorageAppDataDirs(item.packageName));
+                    eraseFiles(userEnv.buildExternalStorageAppMediaDirs(item.packageName));
                     if (item.andCode) {
-                        eraseFiles(userEnv.getExternalStorageAppObbDirectory(item.packageName));
+                        eraseFiles(userEnv.buildExternalStorageAppObbDirs(item.packageName));
                     }
                 }
             } catch (RemoteException e) {
@@ -304,6 +306,12 @@
         }
     }
 
+    void eraseFiles(File[] paths) {
+        for (File path : paths) {
+            eraseFiles(path);
+        }
+    }
+
     void eraseFiles(File path) {
         if (path.isDirectory()) {
             String[] files = path.list();
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
new file mode 100644
index 0000000..2f97809
--- /dev/null
+++ b/packages/DocumentsUI/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 guava
+
+LOCAL_PACKAGE_NAME := DocumentsUI
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
new file mode 100644
index 0000000..6faf7f8
--- /dev/null
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -0,0 +1,62 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.documentsui">
+
+    <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
+    <uses-permission android:name="android.permission.REMOVE_TASKS" />
+
+    <application
+        android:name=".DocumentsApplication"
+        android:label="@string/app_label"
+        android:supportsRtl="true">
+
+        <!-- TODO: allow rotation when state saving is in better shape -->
+        <activity
+            android:name=".DocumentsActivity"
+            android:theme="@style/Theme"
+            android:icon="@drawable/ic_doc_text">
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.OPEN_DOCUMENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.OPENABLE" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.CREATE_DOCUMENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.OPENABLE" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.GET_CONTENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.OPENABLE" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.provider.action.MANAGE_ROOT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.document/root" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".SettingsActivity"
+            android:label="@string/menu_settings"
+            android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge"
+            android:exported="false" />
+
+        <provider
+            android:name=".RecentsProvider"
+            android:authorities="com.android.documentsui.recents"
+            android:exported="false" />
+
+        <!-- TODO: remove when we have real clients -->
+        <activity android:name=".TestActivity" android:enabled="false">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/packages/DocumentsUI/res/animator-ldrtl/dir_down.xml b/packages/DocumentsUI/res/animator-ldrtl/dir_down.xml
new file mode 100644
index 0000000..6c7e224
--- /dev/null
+++ b/packages/DocumentsUI/res/animator-ldrtl/dir_down.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="-1"
+    android:valueTo="0"
+    android:propertyName="position"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:interpolator="@android:interpolator/decelerate_quad" />
diff --git a/packages/DocumentsUI/res/animator-ldrtl/dir_up.xml b/packages/DocumentsUI/res/animator-ldrtl/dir_up.xml
new file mode 100644
index 0000000..8e2925c
--- /dev/null
+++ b/packages/DocumentsUI/res/animator-ldrtl/dir_up.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="0"
+    android:valueTo="-1"
+    android:propertyName="position"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:interpolator="@android:interpolator/accelerate_quad" />
diff --git a/packages/DocumentsUI/res/animator/dir_down.xml b/packages/DocumentsUI/res/animator/dir_down.xml
new file mode 100644
index 0000000..7f547f1
--- /dev/null
+++ b/packages/DocumentsUI/res/animator/dir_down.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="1"
+    android:valueTo="0"
+    android:propertyName="position"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:interpolator="@android:interpolator/decelerate_quad" />
diff --git a/packages/DocumentsUI/res/animator/dir_frozen.xml b/packages/DocumentsUI/res/animator/dir_frozen.xml
new file mode 100644
index 0000000..b541d13
--- /dev/null
+++ b/packages/DocumentsUI/res/animator/dir_frozen.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="0"
+    android:valueTo="0"
+    android:propertyName="position"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/packages/DocumentsUI/res/animator/dir_up.xml b/packages/DocumentsUI/res/animator/dir_up.xml
new file mode 100644
index 0000000..fda0faf
--- /dev/null
+++ b/packages/DocumentsUI/res/animator/dir_up.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="0"
+    android:valueTo="1"
+    android:propertyName="position"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:interpolator="@android:interpolator/accelerate_quad" />
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png
new file mode 100644
index 0000000..7c4c1a6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png
new file mode 100644
index 0000000..649985d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png
new file mode 100644
index 0000000..791bf6d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png
new file mode 100644
index 0000000..6c32af1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png
new file mode 100644
index 0000000..5bc4e05
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png
new file mode 100644
index 0000000..ffb076c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow_am.9.png
new file mode 100644
index 0000000..904d525
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
new file mode 100644
index 0000000..179db33
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
new file mode 100644
index 0000000..8704a78
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png
new file mode 100644
index 0000000..465838d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
new file mode 100644
index 0000000..434a6e6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
new file mode 100644
index 0000000..940d185
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
new file mode 100644
index 0000000..35cdc1f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png
new file mode 100644
index 0000000..8f3b82c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png
new file mode 100644
index 0000000..a3df893
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
new file mode 100644
index 0000000..92225ba
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png
new file mode 100644
index 0000000..55b9b7d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png
new file mode 100644
index 0000000..72b611d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
new file mode 100644
index 0000000..e08b0e6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
new file mode 100644
index 0000000..0c55e8c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png
new file mode 100644
index 0000000..880564e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png
new file mode 100644
index 0000000..cb60165
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png
new file mode 100644
index 0000000..9a942d2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_glyph.png
new file mode 100644
index 0000000..251ecfb
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_glyph.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..0d75172
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_am.9.png
new file mode 100644
index 0000000..4a710ce
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_tablet_am.9.png
new file mode 100644
index 0000000..a1bbc8b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_tablet_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..403eddb
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png
new file mode 100644
index 0000000..7c3d69d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png
new file mode 100644
index 0000000..8b90094
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png
new file mode 100644
index 0000000..1e41d7a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
new file mode 100644
index 0000000..a6e56ea
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png
new file mode 100644
index 0000000..b896c55
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png
new file mode 100644
index 0000000..c907bf6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png
new file mode 100644
index 0000000..1fe7af7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png
new file mode 100644
index 0000000..8a88407
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
new file mode 100644
index 0000000..638c812
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png
new file mode 100644
index 0000000..2a007d2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
new file mode 100644
index 0000000..2756327
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png
new file mode 100644
index 0000000..b00328b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png
new file mode 100644
index 0000000..03e0cc7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png
new file mode 100644
index 0000000..cf7d2f4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
new file mode 100644
index 0000000..0d4cdc1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
new file mode 100644
index 0000000..20dce0f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png
new file mode 100644
index 0000000..3f3b536
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png
new file mode 100644
index 0000000..79bffc9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png
new file mode 100644
index 0000000..595c4b9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png
new file mode 100644
index 0000000..3700512
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png
new file mode 100644
index 0000000..52f1c70
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png
new file mode 100644
index 0000000..915e118
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png
new file mode 100644
index 0000000..303b7f9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png
new file mode 100644
index 0000000..2375e17
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
new file mode 100644
index 0000000..5c0c87b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
new file mode 100644
index 0000000..99060cd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png
new file mode 100644
index 0000000..09e77afb
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png
new file mode 100644
index 0000000..f42be13
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png
new file mode 100644
index 0000000..b47e306
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png
new file mode 100644
index 0000000..903a041
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png
new file mode 100644
index 0000000..4835d5f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png
new file mode 100644
index 0000000..2d29442
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow_am.9.png
new file mode 100644
index 0000000..068619b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
new file mode 100644
index 0000000..318dd5b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
new file mode 100644
index 0000000..932995e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png
new file mode 100644
index 0000000..cb94d99
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
new file mode 100644
index 0000000..240d7f4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
new file mode 100644
index 0000000..6c6aad6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
new file mode 100644
index 0000000..8fc7bea
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png
new file mode 100644
index 0000000..290ad3a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png
new file mode 100644
index 0000000..e5eda72
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
new file mode 100644
index 0000000..00bd478
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png
new file mode 100644
index 0000000..a1bd14e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png
new file mode 100644
index 0000000..b81b1e5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
new file mode 100644
index 0000000..3381c42
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
new file mode 100644
index 0000000..68cc971
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png
new file mode 100644
index 0000000..2934e5a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png
new file mode 100644
index 0000000..95565b3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png
new file mode 100644
index 0000000..3a5b798
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_glyph.png
new file mode 100644
index 0000000..ae0da34
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_glyph.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..0d75172
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_am.9.png
new file mode 100644
index 0000000..9343a39
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_tablet_am.9.png
new file mode 100644
index 0000000..fabb56e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_tablet_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..9a9cf5e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png
new file mode 100644
index 0000000..567a06b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png
new file mode 100644
index 0000000..1525572
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png
new file mode 100644
index 0000000..16c9296
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
new file mode 100644
index 0000000..6e63b8c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png
new file mode 100644
index 0000000..1120864
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png
new file mode 100644
index 0000000..fbf5c88
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png
new file mode 100644
index 0000000..ecb4bf2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png
new file mode 100644
index 0000000..96b01b9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
new file mode 100644
index 0000000..ee95809
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png
new file mode 100644
index 0000000..7a63828
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
new file mode 100644
index 0000000..9ab2f78
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png
new file mode 100644
index 0000000..2d0ab8a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png
new file mode 100644
index 0000000..cf5575a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png
new file mode 100644
index 0000000..368fbd6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
new file mode 100644
index 0000000..2768b1c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
new file mode 100644
index 0000000..d56db42
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png
new file mode 100644
index 0000000..0a0c8f1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png
new file mode 100644
index 0000000..8a724ac
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png
new file mode 100644
index 0000000..adfacc1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png
new file mode 100644
index 0000000..b17de2d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png
new file mode 100644
index 0000000..4f903df
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png
new file mode 100644
index 0000000..4352d08
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png
new file mode 100644
index 0000000..bf9b1b6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png
new file mode 100644
index 0000000..6adc2a3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
new file mode 100644
index 0000000..d318dba
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
new file mode 100644
index 0000000..a7a2b12
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png
new file mode 100644
index 0000000..33c8f27
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png
new file mode 100644
index 0000000..ef9641d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png
new file mode 100644
index 0000000..9c3d008
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png
new file mode 100644
index 0000000..4cf4f3f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png
new file mode 100644
index 0000000..17f9f9e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png
new file mode 100644
index 0000000..2f9cc58
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow_am.9.png
new file mode 100644
index 0000000..e38a868
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
new file mode 100644
index 0000000..e67aa8d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
new file mode 100644
index 0000000..d0e2594
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png
new file mode 100644
index 0000000..2e66f03
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
new file mode 100644
index 0000000..64e0d42
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
new file mode 100644
index 0000000..a4f70ba
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
new file mode 100644
index 0000000..4897221c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png
new file mode 100644
index 0000000..4cec994
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png
new file mode 100644
index 0000000..5e46b71
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
new file mode 100644
index 0000000..977cfd2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png
new file mode 100644
index 0000000..e05c4b4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png
new file mode 100644
index 0000000..98d3f79
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
new file mode 100644
index 0000000..ff2ff14
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
new file mode 100644
index 0000000..2917377
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png
new file mode 100644
index 0000000..87c6538
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png
new file mode 100644
index 0000000..97c4500
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png
new file mode 100644
index 0000000..1a8e632
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_glyph.png
new file mode 100644
index 0000000..7402c6d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_glyph.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..0d75172
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_am.9.png
new file mode 100644
index 0000000..027c64a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_tablet_am.9.png
new file mode 100644
index 0000000..2c39a67
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_tablet_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..205c34b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png
new file mode 100644
index 0000000..8f7f4ab
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png
new file mode 100644
index 0000000..b82ae20
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png
new file mode 100644
index 0000000..edd6266
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
new file mode 100644
index 0000000..c3af9ec
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png
new file mode 100644
index 0000000..60ce8d5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png
new file mode 100644
index 0000000..c650185
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png
new file mode 100644
index 0000000..0771ed2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png
new file mode 100644
index 0000000..91c31e3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
new file mode 100644
index 0000000..f06b298
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png
new file mode 100644
index 0000000..c3a7eaa
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
new file mode 100644
index 0000000..17e09b3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png
new file mode 100644
index 0000000..0ab604f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png
new file mode 100644
index 0000000..5054fc8
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png
new file mode 100644
index 0000000..d3d386e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
new file mode 100644
index 0000000..f24ca1a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
new file mode 100644
index 0000000..82c1a30
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png
new file mode 100644
index 0000000..0258312
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png
new file mode 100644
index 0000000..ccace9d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png
new file mode 100644
index 0000000..a56940a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png
new file mode 100644
index 0000000..f6a0af4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png
new file mode 100644
index 0000000..6c6447e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png
new file mode 100644
index 0000000..c916e0b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png
new file mode 100644
index 0000000..714f2ee
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png
new file mode 100644
index 0000000..6016c08
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
new file mode 100644
index 0000000..b05b9a4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
new file mode 100644
index 0000000..1da8196
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png
new file mode 100644
index 0000000..06681e3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png
new file mode 100644
index 0000000..ac88818
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png
new file mode 100644
index 0000000..88356c7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png
new file mode 100644
index 0000000..75658db
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png
new file mode 100644
index 0000000..8bee0dc
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png
new file mode 100644
index 0000000..ad6c59b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow_am.9.png
new file mode 100644
index 0000000..0b332e4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
new file mode 100644
index 0000000..4c56bd0c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
new file mode 100644
index 0000000..5f64229
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png
new file mode 100644
index 0000000..48ab9c7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
new file mode 100644
index 0000000..68e619e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
new file mode 100644
index 0000000..945119a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
new file mode 100644
index 0000000..bf49d78
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png
new file mode 100644
index 0000000..5263365
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png
new file mode 100644
index 0000000..77a0fae
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
new file mode 100644
index 0000000..30d2c4c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png
new file mode 100644
index 0000000..c098866
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png
new file mode 100644
index 0000000..06d8d9c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
new file mode 100644
index 0000000..a3b146b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
new file mode 100644
index 0000000..c09d6ab
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png
new file mode 100644
index 0000000..2170e66
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png
new file mode 100644
index 0000000..bc4ce79
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png
new file mode 100644
index 0000000..42d8ec1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_glyph.png
new file mode 100644
index 0000000..4160699
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_glyph.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..32b5f98
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_am.9.png
new file mode 100644
index 0000000..1a59e1a8
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_tablet_am.9.png
new file mode 100644
index 0000000..3c95790
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_tablet_am.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..f47d50a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png
new file mode 100644
index 0000000..7bbaf9d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png
new file mode 100644
index 0000000..901af80
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png
new file mode 100644
index 0000000..e21e350
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
new file mode 100644
index 0000000..86a74cd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png
new file mode 100644
index 0000000..988c856
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png
new file mode 100644
index 0000000..f23e23c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png
new file mode 100644
index 0000000..f67c72e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png
new file mode 100644
index 0000000..676d0f7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
new file mode 100644
index 0000000..b17ba1d0
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png
new file mode 100644
index 0000000..58f1381
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
new file mode 100644
index 0000000..eed0eaf
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png
new file mode 100644
index 0000000..40fb392
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png
new file mode 100644
index 0000000..b988ab5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png
new file mode 100644
index 0000000..6ace932
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
new file mode 100644
index 0000000..8f19afa
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
new file mode 100644
index 0000000..e4c9f8a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png
new file mode 100644
index 0000000..9e27d63
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png
new file mode 100644
index 0000000..e4c679a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png
new file mode 100644
index 0000000..b467962
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png
new file mode 100644
index 0000000..5f5a86f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png
new file mode 100644
index 0000000..3b8afc9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png
new file mode 100644
index 0000000..077c851
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png
new file mode 100644
index 0000000..a3215f2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png
new file mode 100644
index 0000000..873a553
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
new file mode 100644
index 0000000..d213e7c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
new file mode 100644
index 0000000..db53a01
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow.xml b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow.xml
new file mode 100644
index 0000000..0de7ddc
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_breadcrumb_arrow_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_dir_shadow.xml b/packages/DocumentsUI/res/drawable/ic_dir_shadow.xml
new file mode 100644
index 0000000..1153e69
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_dir_shadow.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_dir_shadow_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
new file mode 100644
index 0000000..c6ccea6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_audio_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
new file mode 100644
index 0000000..e645551
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_contact_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_event.xml b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
new file mode 100644
index 0000000..dcbd912
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_event_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
new file mode 100644
index 0000000..d5f64ed
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_generic_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
new file mode 100644
index 0000000..8c6e056
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_spreadsheet_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_text.xml b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
new file mode 100644
index 0000000..ac63ecb
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_text_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
new file mode 100644
index 0000000..e196262
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_doc_video_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_drawer_shadow.xml b/packages/DocumentsUI/res/drawable/ic_drawer_shadow.xml
new file mode 100644
index 0000000..8d457be
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_drawer_shadow.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_drawer_shadow_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/packages/DocumentsUI/res/drawable/ic_drawer_shadow_tablet.xml b/packages/DocumentsUI/res/drawable/ic_drawer_shadow_tablet.xml
new file mode 100644
index 0000000..382ebff
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_drawer_shadow_tablet.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_drawer_shadow_tablet_am"
+        android:autoMirrored="true">
+</nine-patch>
diff --git a/packages/DocumentsUI/res/drawable/ic_menu_disconnect.xml b/packages/DocumentsUI/res/drawable/ic_menu_disconnect.xml
new file mode 100644
index 0000000..e5b4c8d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_menu_disconnect.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_menu_disconnect_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_menu_new_folder.xml b/packages/DocumentsUI/res/drawable/ic_menu_new_folder.xml
new file mode 100644
index 0000000..42e7f90
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_menu_new_folder.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_menu_new_folder_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_menu_rename.xml b/packages/DocumentsUI/res/drawable/ic_menu_rename.xml
new file mode 100644
index 0000000..e332313
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_menu_rename.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_menu_rename_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/packages/DocumentsUI/res/drawable/ic_menu_sortby.xml b/packages/DocumentsUI/res/drawable/ic_menu_sortby.xml
new file mode 100644
index 0000000..d908582
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_menu_sortby.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_menu_sortby_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_menu_undo.xml b/packages/DocumentsUI/res/drawable/ic_menu_undo.xml
new file mode 100644
index 0000000..f25d90d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_menu_undo.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_menu_undo_am"
+        android:autoMirrored="true">
+</bitmap>
diff --git a/packages/DocumentsUI/res/drawable/ic_open.xml b/packages/DocumentsUI/res/drawable/ic_open.xml
new file mode 100644
index 0000000..faeb03d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_open.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_open_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_popout.xml b/packages/DocumentsUI/res/drawable/ic_popout.xml
new file mode 100644
index 0000000..223598d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_popout.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_popout_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_root_folder.xml b/packages/DocumentsUI/res/drawable/ic_root_folder.xml
new file mode 100644
index 0000000..a3c8f61
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_root_folder.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_root_folder_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml b/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
new file mode 100644
index 0000000..0f66e2a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_subdirectory_arrow_am"
+        android:autoMirrored="true">
+</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/item_background.xml b/packages/DocumentsUI/res/drawable/item_background.xml
new file mode 100644
index 0000000..6fcab3c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_background.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+    <item android:state_focused="true"   android:state_activated="true" android:drawable="@*android:drawable/list_selected_holo_light" />
+    <item android:state_focused="false"  android:state_activated="true" android:drawable="@*android:drawable/list_selected_holo_light" />
+
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" />
+    <item android:state_focused="true"                                                             android:drawable="@*android:drawable/list_focused_holo" />
+
+    <item android:drawable="@android:color/transparent" />
+
+</selector>
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/packages/DocumentsUI/res/drawable/item_doc_grid.xml
new file mode 100644
index 0000000..3f036f7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_doc_grid.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_grid_card_background" />
+</selector>
diff --git a/packages/DocumentsUI/res/drawable/item_root.xml b/packages/DocumentsUI/res/drawable/item_root.xml
new file mode 100644
index 0000000..60d4ab0
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_root.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@color/item_root_pressed" />
+    <item android:state_activated="true" android:drawable="@color/item_root_focused" />
+    <item android:state_focused="true" android:drawable="@color/item_root_focused" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
new file mode 100644
index 0000000..851061f
--- /dev/null
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -0,0 +1,116 @@
+<?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:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/item_background"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:baselineAligned="false">
+
+    <FrameLayout
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/icon_size"
+        android:layout_height="@dimen/icon_size"
+        android:layout_marginStart="12dp"
+        android:layout_marginEnd="20dp">
+
+        <ImageView
+            android:id="@+id/icon_mime"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
+
+        <ImageView
+            android:id="@+id/icon_thumb"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerCrop"
+            android:contentDescription="@null" />
+
+    </FrameLayout>
+
+    <!-- This is the one special case where we want baseline alignment! -->
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.5"
+            android:layout_marginEnd="12dp"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAlignment="viewStart"
+            style="@style/TextAppearance.Medium" />
+
+        <ImageView
+            android:id="@android:id/icon1"
+            android:layout_width="@dimen/root_icon_size"
+            android:layout_height="@dimen/root_icon_size"
+            android:layout_marginEnd="8dp"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.25"
+            android:layout_marginEnd="12dp"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAlignment="viewStart"
+            style="@style/TextAppearance.Small" />
+
+        <TextView
+            android:id="@+id/size"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.125"
+            android:layout_marginEnd="12dp"
+            android:minWidth="70dp"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAlignment="viewEnd"
+            style="@style/TextAppearance.Small" />
+
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.125"
+            android:layout_marginEnd="12dp"
+            android:minWidth="70dp"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAlignment="viewEnd"
+            style="@style/TextAppearance.Small" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
new file mode 100644
index 0000000..9286277
--- /dev/null
+++ b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
@@ -0,0 +1,61 @@
+<?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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:baselineAligned="false">
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:id="@+id/dialog_roots">
+
+        <FrameLayout
+            android:id="@+id/container_roots"
+            android:layout_width="250dp"
+            android:layout_height="match_parent" />
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="end"
+            android:scaleType="fitXY"
+            android:src="@drawable/ic_drawer_shadow_tablet" />
+
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <com.android.documentsui.DirectoryContainerView
+            android:id="@+id/container_directory"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+        <FrameLayout
+            android:id="@+id/container_save"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/activity.xml
new file mode 100644
index 0000000..2ef7e9c
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/activity.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/drawer_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <com.android.documentsui.DirectoryContainerView
+            android:id="@+id/container_directory"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+        <FrameLayout
+            android:id="@+id/container_save"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <FrameLayout
+        android:id="@+id/container_roots"
+        android:layout_width="250dp"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:background="#fff" />
+
+</android.support.v4.widget.DrawerLayout>
diff --git a/packages/DocumentsUI/res/layout/dialog_create_dir.xml b/packages/DocumentsUI/res/layout/dialog_create_dir.xml
new file mode 100644
index 0000000..54e26b4
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/dialog_create_dir.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="?android:attr/listPreferredItemPaddingEnd">
+
+    <EditText
+        android:id="@android:id/text1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
new file mode 100644
index 0000000..77cdc3b
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -0,0 +1,50 @@
+<?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.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/ic_dir_shadow">
+
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="@string/empty"
+        android:visibility="gone"
+        style="@style/TextAppearance.Medium" />
+
+    <ListView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:listSelector="@android:color/transparent" />
+
+    <GridView
+        android:id="@+id/grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingStart="@dimen/grid_padding_horiz"
+        android:paddingEnd="@dimen/grid_padding_horiz"
+        android:paddingTop="@dimen/grid_padding"
+        android:paddingBottom="@dimen/grid_padding"
+        android:clipToPadding="false"
+        android:scrollbarStyle="outsideOverlay"
+        android:listSelector="@android:color/transparent"
+        android:visibility="gone" />
+
+</com.android.documentsui.DirectoryView>
diff --git a/packages/DocumentsUI/res/layout/fragment_roots.xml b/packages/DocumentsUI/res/layout/fragment_roots.xml
new file mode 100644
index 0000000..c3a3da0
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/fragment_roots.xml
@@ -0,0 +1,21 @@
+<?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="match_parent"
+    android:layout_height="match_parent"
+    android:divider="@drawable/ic_drawer_hairline_divider" />
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
new file mode 100644
index 0000000..891f0a0
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -0,0 +1,66 @@
+<?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:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <!-- Le sigh, this really should be an asset -->
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="#ccc" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:baselineAligned="false"
+        android:gravity="center_vertical"
+        android:background="#ddd"
+        android:minHeight="?android:attr/listPreferredItemHeightSmall">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
+
+        <EditText
+            android:id="@android:id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:singleLine="true"
+            android:selectAllOnFocus="true" />
+
+        <Button
+            android:id="@android:id/button1"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:background="?android:attr/selectableItemBackground"
+            android:text="@string/menu_save"
+            android:textAllCaps="true"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:padding="8dp" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
new file mode 100644
index 0000000..bb5dce1
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -0,0 +1,128 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/grid_height"
+    android:background="@drawable/item_doc_grid"
+    android:foreground="@drawable/item_background">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingBottom="6dp"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_marginBottom="6dp"
+            android:background="#fff"
+            android:foreground="@drawable/ic_grid_gradient_bg"
+            android:foregroundGravity="fill">
+
+            <ImageView
+                android:id="@+id/icon_mime"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="centerInside"
+                android:contentDescription="@null" />
+
+            <ImageView
+                android:id="@+id/icon_thumb"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="centerCrop"
+                android:contentDescription="@null" />
+
+        </FrameLayout>
+
+        <LinearLayout
+            android:id="@+id/line1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:baselineAligned="false"
+            android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Medium" />
+
+            <ImageView
+                android:id="@android:id/icon1"
+                android:layout_width="@dimen/root_icon_size"
+                android:layout_height="@dimen/root_icon_size"
+                android:layout_marginStart="8dp"
+                android:scaleType="centerInside"
+                android:contentDescription="@null" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/line2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:baselineAligned="false"
+            android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+            <TextView
+                android:id="@+id/date"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Small" />
+
+            <TextView
+                android:id="@+id/size"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"
+                android:layout_marginStart="8dp"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Small" />
+
+            <ImageView
+                android:id="@android:id/icon2"
+                android:layout_width="@dimen/root_icon_size"
+                android:layout_height="@dimen/root_icon_size"
+                android:layout_marginStart="8dp"
+                android:scaleType="centerInside"
+                android:contentDescription="@null"
+                android:visibility="gone" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
new file mode 100644
index 0000000..4c5b2e3
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -0,0 +1,131 @@
+<?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:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/item_background"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:baselineAligned="false">
+
+    <FrameLayout
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/icon_size"
+        android:layout_height="@dimen/icon_size"
+        android:layout_marginStart="12dp"
+        android:layout_marginEnd="20dp">
+
+        <ImageView
+            android:id="@+id/icon_mime"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
+
+        <ImageView
+            android:id="@+id/icon_thumb"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerCrop"
+            android:contentDescription="@null" />
+
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:baselineAligned="false">
+
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Medium" />
+
+            <ImageView
+                android:id="@android:id/icon1"
+                android:layout_width="@dimen/root_icon_size"
+                android:layout_height="@dimen/root_icon_size"
+                android:layout_marginStart="8dp"
+                android:scaleType="centerInside"
+                android:contentDescription="@null" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/line2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:baselineAligned="false">
+
+            <TextView
+                android:id="@+id/date"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.25"
+                android:minWidth="70dp"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Small" />
+
+            <TextView
+                android:id="@+id/size"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.25"
+                android:layout_marginStart="8dp"
+                android:minWidth="70dp"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Small" />
+
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"
+                android:layout_marginStart="8dp"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAlignment="viewStart"
+                style="@style/TextAppearance.Small" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
new file mode 100644
index 0000000..0bf6137
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/grid_height"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:orientation="horizontal">
+
+    <ProgressBar
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:indeterminate="true"
+        style="?android:attr/progressBarStyle" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_loading_list.xml b/packages/DocumentsUI/res/layout/item_loading_list.xml
new file mode 100644
index 0000000..cdcd01d
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_loading_list.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<FrameLayout 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:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp">
+
+    <ProgressBar
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:indeterminate="true"
+        style="?android:attr/progressBarStyle" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
new file mode 100644
index 0000000..b3bdd28
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_message_grid.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/grid_height"
+    android:paddingTop="?android:attr/listPreferredItemPaddingStart"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
+    android:foreground="@drawable/item_background">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@null" />
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:maxLines="4"
+            android:ellipsize="end"
+            android:paddingTop="6dp"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textAlignment="viewStart" />
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml
new file mode 100644
index 0000000..2bcbc2d
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_message_list.xml
@@ -0,0 +1,48 @@
+<?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:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/item_background"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:orientation="horizontal"
+    android:baselineAligned="false">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="@android:dimen/app_icon_size"
+        android:layout_height="@android:dimen/app_icon_size"
+        android:layout_marginEnd="8dp"
+        android:layout_gravity="center_vertical"
+        android:scaleType="centerInside"
+        android:contentDescription="@null" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:maxLines="2"
+        android:ellipsize="end"
+        android:textAlignment="viewStart"
+        android:textAppearance="?android:attr/textAppearanceSmall" />
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
new file mode 100644
index 0000000..9b52d85
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -0,0 +1,61 @@
+<?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:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:baselineAligned="false"
+    android:background="@drawable/item_root">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/icon_size"
+        android:layout_height="@dimen/icon_size"
+        android:layout_marginEnd="8dp"
+        android:scaleType="centerInside"
+        android:contentDescription="@null" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAlignment="viewStart"
+            style="@style/TextAppearance.Medium" />
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAlignment="viewStart"
+            style="@style/TextAppearance.Small" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root_header.xml b/packages/DocumentsUI/res/layout/item_root_header.xml
new file mode 100644
index 0000000..6b9857d
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_root_header.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="12dp">
+
+    <TextView
+        android:id="@android:id/title"
+        android:textColor="?android:attr/textColorTertiary"
+        style="?android:attr/listSeparatorTextViewStyle" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root_spacer.xml b/packages/DocumentsUI/res/layout/item_root_spacer.xml
new file mode 100644
index 0000000..7d96ac8
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_root_spacer.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/ic_drawer_tall_divider" />
diff --git a/packages/DocumentsUI/res/layout/item_title.xml b/packages/DocumentsUI/res/layout/item_title.xml
new file mode 100644
index 0000000..58016f1
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_title.xml
@@ -0,0 +1,45 @@
+<?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:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:baselineAligned="false">
+
+    <ImageView
+        android:id="@+id/subdir"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:scaleType="centerInside"
+        android:visibility="gone"
+        android:src="@drawable/ic_subdirectory_arrow"
+        android:contentDescription="@null" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAlignment="viewStart"
+        style="@style/TextAppearance.Medium" />
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
new file mode 100644
index 0000000..d995376
--- /dev/null
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/menu_create_dir"
+        android:title="@string/menu_create_dir"
+        android:icon="@drawable/ic_menu_new_folder"
+        android:showAsAction="always" />
+    <item
+        android:id="@+id/menu_search"
+        android:title="@string/menu_search"
+        android:icon="@drawable/ic_menu_search"
+        android:showAsAction="always|collapseActionView"
+        android:actionViewClass="android.widget.SearchView"
+        android:imeOptions="actionSearch" />
+    <item
+        android:id="@+id/menu_sort"
+        android:title="@string/menu_sort"
+        android:icon="@drawable/ic_menu_sortby"
+        android:showAsAction="always">
+        <menu>
+            <item
+                android:id="@+id/menu_sort_name"
+                android:title="@string/sort_name" />
+            <item
+                android:id="@+id/menu_sort_date"
+                android:title="@string/sort_date" />
+            <item
+                android:id="@+id/menu_sort_size"
+                android:title="@string/sort_size" />
+        </menu>
+    </item>
+    <item
+        android:id="@+id/menu_grid"
+        android:title="@string/menu_grid"
+        android:icon="@drawable/ic_menu_view_grid"
+        android:showAsAction="never" />
+    <item
+        android:id="@+id/menu_list"
+        android:title="@string/menu_list"
+        android:icon="@drawable/ic_menu_view_list"
+        android:showAsAction="never" />
+    <item
+        android:id="@+id/menu_settings"
+        android:title="@string/menu_settings"
+        android:icon="@drawable/ic_menu_settings"
+        android:showAsAction="never" />
+</menu>
diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml
new file mode 100644
index 0000000..0a3645f
--- /dev/null
+++ b/packages/DocumentsUI/res/menu/mode_directory.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/menu_open"
+        android:title="@string/menu_open"
+        android:showAsAction="always" />
+    <item
+        android:id="@+id/menu_share"
+        android:icon="@drawable/ic_menu_share"
+        android:title="@string/menu_share"
+        android:showAsAction="always" />
+    <item
+        android:id="@+id/menu_delete"
+        android:icon="@drawable/ic_menu_delete"
+        android:title="@string/menu_delete"
+        android:showAsAction="always" />
+</menu>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..961608c
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+    <bool name="always_show_summary">true</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..3a75dfa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<resources>
+    <bool name="show_as_dialog">true</bool>
+
+    <item type="dimen" name="dialog_width">85%</item>
+    <item type="dimen" name="dialog_height">90%</item>
+
+    <dimen name="grid_padding_horiz">20dp</dimen>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
new file mode 100644
index 0000000..a581e08
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme" parent="@android:style/Theme.Holo.Light">
+        <item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
+        <item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowIsTranslucent">true</item>
+    </style>
+</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
new file mode 100644
index 0000000..adeff77
--- /dev/null
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<resources>
+    <color name="chip">#ddd</color>
+    <color name="item_root_pressed">#33cccccc</color>
+    <color name="item_root_focused">#66cccccc</color>
+</resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
new file mode 100644
index 0000000..924a8d6
--- /dev/null
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<resources>
+    <dimen name="icon_size">32dp</dimen>
+    <dimen name="root_icon_size">24dp</dimen>
+    <dimen name="grid_width">160dp</dimen>
+    <dimen name="grid_height">170dp</dimen>
+
+    <dimen name="grid_padding">4dp</dimen>
+    <dimen name="grid_padding_horiz">4dp</dimen>
+
+    <bool name="show_as_dialog">false</bool>
+    <bool name="always_show_summary">false</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
new file mode 100644
index 0000000..92c30ba
--- /dev/null
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -0,0 +1,101 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Title of the documents application [CHAR LIMIT=32] -->
+    <string name="app_label">Documents</string>
+
+    <!-- Action bar title prompting user to choose a location to open a document from [CHAR LIMIT=32] -->
+    <string name="title_open">Open from</string>
+    <!-- Action bar title prompting user to choose a location to save a document to [CHAR LIMIT=32] -->
+    <string name="title_save">Save to</string>
+
+    <!-- Menu item that creates a new directory/folder at the current location [CHAR LIMIT=24] -->
+    <string name="menu_create_dir">Create folder</string>
+    <!-- Menu item that switches view to show documents as a large-format grid of thumbnails [CHAR LIMIT=24] -->
+    <string name="menu_grid">Grid view</string>
+    <!-- Menu item that switches view to show documents as a list [CHAR LIMIT=24] -->
+    <string name="menu_list">List view</string>
+    <!-- Menu item that switches the criteria with which documents are sorted [CHAR LIMIT=24] -->
+    <string name="menu_sort">Sort by</string>
+    <!-- Menu item that enters a mode to search for documents [CHAR LIMIT=24] -->
+    <string name="menu_search">Search</string>
+    <!-- Menu item that enters activity to change settings [CHAR LIMIT=24] -->
+    <string name="menu_settings">Settings</string>
+
+    <!-- Menu item title that opens the selected documents [CHAR LIMIT=24] -->
+    <string name="menu_open">Open</string>
+    <!-- Menu item title that saves the current document [CHAR LIMIT=24] -->
+    <string name="menu_save">Save</string>
+    <!-- Menu item title that shares the selected documents [CHAR LIMIT=24] -->
+    <string name="menu_share">Share</string>
+    <!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
+    <string name="menu_delete">Delete</string>
+
+    <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
+    <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
+
+    <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
+    <string name="sort_name">By name</string>
+    <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
+    <string name="sort_date">By date modified</string>
+    <!-- Mode that sorts documents by their file size in descending order; largest first [CHAR LIMIT=24] -->
+    <string name="sort_size">By size</string>
+
+    <!-- Accessibility title to open the drawer showing all roots where documents can be stored [CHAR LIMIT=32] -->
+    <string name="drawer_open">Show roots</string>
+    <!-- Accessibility title to close the drawer showing all roots where documents can be stored [CHAR LIMIT=32] -->
+    <string name="drawer_close">Hide roots</string>
+
+    <!-- Toast shown when saving a document failed with an error [CHAR LIMIT=48] -->
+    <string name="save_error">Failed to save document</string>
+    <!-- Toast shown when creating a folder failed with an error [CHAR LIMIT=48] -->
+    <string name="create_error">Failed to create folder</string>
+    <!-- Error message shown when querying for a list of documents failed [CHAR LIMIT=48] -->
+    <string name="query_error">Failed to query documents</string>
+
+    <!-- Title of storage root location that contains recently modified or used documents [CHAR LIMIT=24] -->
+    <string name="root_recent">Recent</string>
+    <!-- Subtitle of storage root indicating the total free space available, in bytes [CHAR LIMIT=24] -->
+    <string name="root_available_bytes"><xliff:g id="size" example="3GB">%1$s</xliff:g> free</string>
+
+    <!-- Header title for list of storage roots that contains cloud services [CHAR LIMIT=24] -->
+    <string name="root_type_service">Storage services</string>
+    <!-- Header title for list of storage roots that contains shortcuts to documents that may be available elsewhere [CHAR LIMIT=24] -->
+    <string name="root_type_shortcut">Shortcuts</string>
+    <!-- Header title for list of storage roots that contains physical devices [CHAR LIMIT=24] -->
+    <string name="root_type_device">Devices</string>
+    <!-- Header title for list of additional apps that can provide documents [CHAR LIMIT=24] -->
+    <string name="root_type_apps">More apps</string>
+
+    <!-- Title for setting that will show all advanced storage devices [CHAR LIMIT=32] -->
+    <string name="pref_advanced_devices">Display advanced devices</string>
+    <!-- Title for setting that will show file sizes for all documents [CHAR LIMIT=32] -->
+    <string name="pref_file_size">Display file size</string>
+    <string name="pref_device_size">Display device size</string>
+
+    <!-- Text shown when a directory of documents is empty [CHAR LIMIT=24] -->
+    <string name="empty">No items</string>
+
+    <!-- Toast shown when no app can be found to open the selected document [CHAR LIMIT=48] -->
+    <string name="toast_no_application">Can\'t open file</string>
+    <!-- Toast shown when some of the selected documents failed to be deleted [CHAR LIMIT=48] -->
+    <string name="toast_failed_delete">Unable to delete some documents</string>
+
+    <!-- Title of dialog when prompting user to select an app to share documents with [CHAR LIMIT=32] -->
+    <string name="share_via">Share via</string>
+
+</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
new file mode 100644
index 0000000..0c8f712
--- /dev/null
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="TextAppearance" />
+
+    <style name="TextAppearance.Medium">
+        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+
+    <style name="TextAppearance.Small">
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
+    </style>
+
+    <!-- Normally just a redirection, but this is used to make ourselves a
+         dialog on large tablets -->
+    <style name="Theme" parent="@android:style/Theme.Holo.Light">
+        <item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
+    </style>
+    
+    <style name="DarkerOverflow" parent="@android:style/Widget.Holo.Light.ActionButton.Overflow">
+        <item name="android:src">@drawable/ic_menu_overflow</item>
+    </style>
+
+</resources>
diff --git a/packages/DocumentsUI/res/xml/preferences.xml b/packages/DocumentsUI/res/xml/preferences.xml
new file mode 100644
index 0000000..5589ff1
--- /dev/null
+++ b/packages/DocumentsUI/res/xml/preferences.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <CheckBoxPreference
+        android:title="@string/pref_advanced_devices"
+        android:defaultValue="false"
+        android:key="advancedDevices" />
+    <CheckBoxPreference
+        android:title="@string/pref_file_size"
+        android:defaultValue="false"
+        android:key="fileSize" />
+</PreferenceScreen>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ColumnAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/ColumnAdapter.java
new file mode 100644
index 0000000..092b5db
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/ColumnAdapter.java
@@ -0,0 +1,139 @@
+/*
+ * 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.documentsui;
+
+import android.database.DataSetObserver;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Adapter that wraps an existing adapter, presenting its contents in multiple
+ * equally-sized horizontal columns.
+ */
+public class ColumnAdapter extends BaseAdapter {
+    private final ListAdapter mWrapped;
+    private final OnItemClickListener mListener;
+
+    private int mColumns = 1;
+
+    public interface OnItemClickListener {
+        public void onItemClick(ListAdapter adapter, int position);
+    }
+
+    public ColumnAdapter(ListAdapter wrapped, OnItemClickListener listener) {
+        mWrapped = Preconditions.checkNotNull(wrapped);
+        mListener = Preconditions.checkNotNull(listener);
+
+        if (!wrapped.areAllItemsEnabled()) {
+            throw new IllegalStateException("All items must be enabled");
+        }
+        if (wrapped.getViewTypeCount() > 1) {
+            throw new IllegalStateException("All items must be identical");
+        }
+    }
+
+    public static void prepare(ListView list) {
+        list.setItemsCanFocus(true);
+    }
+
+    public void setColumns(int columns) {
+        mColumns = columns;
+        notifyDataSetChanged();
+    }
+
+    private View.OnClickListener mItemListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final int position = (Integer) v.getTag();
+            mListener.onItemClick(mWrapped, position);
+        }
+    };
+
+    @Override
+    public int getCount() {
+        return (mWrapped.getCount() + mColumns - 1) / mColumns;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return position;
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            convertView = new LinearLayout(parent.getContext());
+        }
+
+        final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                0, LinearLayout.LayoutParams.WRAP_CONTENT);
+        params.weight = 1f / mColumns;
+
+        final LinearLayout row = (LinearLayout) convertView;
+        final int first = position * mColumns;
+        final int last = mWrapped.getCount() - 1;
+
+        for (int i = 0; i < mColumns; i++) {
+            View convertItem = null;
+            if (i < row.getChildCount()) {
+                convertItem = row.getChildAt(i);
+            }
+
+            final int pos = first + i;
+            final int validPos = Math.min(pos, last);
+            final View item = mWrapped.getView(validPos, convertItem, row);
+            item.setTag(validPos);
+            item.setOnClickListener(mItemListener);
+            item.setFocusable(true);
+
+            if (pos == validPos) {
+                item.setVisibility(View.VISIBLE);
+            } else {
+                item.setVisibility(View.INVISIBLE);
+            }
+
+            if (convertItem == null) {
+                row.addView(item, params);
+            }
+        }
+
+        return convertView;
+    }
+
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        super.registerDataSetObserver(observer);
+        mWrapped.registerDataSetObserver(observer);
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        super.unregisterDataSetObserver(observer);
+        mWrapped.unregisterDataSetObserver(observer);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
new file mode 100644
index 0000000..22dd6e4
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -0,0 +1,125 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.android.documentsui.model.DocumentInfo;
+
+/**
+ * Dialog to create a new directory.
+ */
+public class CreateDirectoryFragment extends DialogFragment {
+    private static final String TAG_CREATE_DIRECTORY = "create_directory";
+
+    public static void show(FragmentManager fm) {
+        final CreateDirectoryFragment dialog = new CreateDirectoryFragment();
+        dialog.show(fm, TAG_CREATE_DIRECTORY);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final Context context = getActivity();
+        final ContentResolver resolver = context.getContentResolver();
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
+
+        final View view = dialogInflater.inflate(R.layout.dialog_create_dir, null, false);
+        final EditText text1 = (EditText) view.findViewById(android.R.id.text1);
+
+        builder.setTitle(R.string.menu_create_dir);
+        builder.setView(view);
+
+        builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                final String displayName = text1.getText().toString();
+
+                final DocumentsActivity activity = (DocumentsActivity) getActivity();
+                final DocumentInfo cwd = activity.getCurrentDirectory();
+
+                new CreateDirectoryTask(displayName).executeOnExecutor(
+                        ProviderExecutor.forAuthority(cwd.authority));
+            }
+        });
+        builder.setNegativeButton(android.R.string.cancel, null);
+
+        return builder.create();
+    }
+
+    private class CreateDirectoryTask extends AsyncTask<Void, Void, DocumentInfo> {
+        private final String mDisplayName;
+
+        public CreateDirectoryTask(String displayName) {
+            mDisplayName = displayName;
+        }
+
+        @Override
+        protected DocumentInfo doInBackground(Void... params) {
+            final DocumentsActivity activity = (DocumentsActivity) getActivity();
+            final ContentResolver resolver = activity.getContentResolver();
+
+            final DocumentInfo cwd = activity.getCurrentDirectory();
+
+            ContentProviderClient client = null;
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        resolver, cwd.derivedUri.getAuthority());
+                final Uri childUri = DocumentsContract.createDocument(
+                        client, cwd.derivedUri, Document.MIME_TYPE_DIR, mDisplayName);
+                return DocumentInfo.fromUri(resolver, childUri);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to create directory", e);
+                return null;
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+        }
+
+        @Override
+        protected void onPostExecute(DocumentInfo result) {
+            final DocumentsActivity activity = (DocumentsActivity) getActivity();
+            if (result != null) {
+                // Navigate into newly created child
+                activity.onDocumentPicked(result);
+            } else {
+                Toast.makeText(activity, R.string.create_error, Toast.LENGTH_SHORT).show();
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
new file mode 100644
index 0000000..77595b6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
@@ -0,0 +1,63 @@
+/*
+ * 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.documentsui;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+
+public class DirectoryContainerView extends FrameLayout {
+    private boolean mDisappearingFirst = false;
+
+    public DirectoryContainerView(Context context) {
+        super(context);
+        setClipChildren(false);
+    }
+
+    public DirectoryContainerView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setClipChildren(false);
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        final ArrayList<View> disappearing = mDisappearingChildren;
+        if (mDisappearingFirst && disappearing != null) {
+            for (int i = 0; i < disappearing.size(); i++) {
+                super.drawChild(canvas, disappearing.get(i), getDrawingTime());
+            }
+        }
+        super.dispatchDraw(canvas);
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        if (mDisappearingFirst && mDisappearingChildren != null
+                && mDisappearingChildren.contains(child)) {
+            return false;
+        }
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    public void setDrawDisappearingFirst(boolean disappearingFirst) {
+        mDisappearingFirst = disappearingFirst;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
new file mode 100644
index 0000000..59caad0
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -0,0 +1,1117 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
+import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.app.ActivityManager;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.Loader;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Parcelable;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+import android.text.format.Time;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AbsListView.MultiChoiceModeListener;
+import android.widget.AbsListView.RecyclerListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.GridView;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.StateColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.RootInfo;
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Display the documents inside a single directory.
+ */
+public class DirectoryFragment extends Fragment {
+
+    private View mEmptyView;
+    private ListView mListView;
+    private GridView mGridView;
+
+    private AbsListView mCurrentView;
+
+    public static final int TYPE_NORMAL = 1;
+    public static final int TYPE_SEARCH = 2;
+    public static final int TYPE_RECENT_OPEN = 3;
+
+    public static final int ANIM_NONE = 1;
+    public static final int ANIM_SIDE = 2;
+    public static final int ANIM_DOWN = 3;
+    public static final int ANIM_UP = 4;
+
+    private int mType = TYPE_NORMAL;
+    private String mStateKey;
+
+    private int mLastMode = MODE_UNKNOWN;
+    private int mLastSortOrder = SORT_ORDER_UNKNOWN;
+    private boolean mLastShowSize = false;
+
+    private boolean mHideGridTitles = false;
+
+    private boolean mSvelteRecents;
+    private Point mThumbSize;
+
+    private DocumentsAdapter mAdapter;
+    private LoaderCallbacks<DirectoryResult> mCallbacks;
+
+    private static final String EXTRA_TYPE = "type";
+    private static final String EXTRA_ROOT = "root";
+    private static final String EXTRA_DOC = "doc";
+    private static final String EXTRA_QUERY = "query";
+    private static final String EXTRA_IGNORE_STATE = "ignoreState";
+
+    private static AtomicInteger sLoaderId = new AtomicInteger(4000);
+
+    private final int mLoaderId = sLoaderId.incrementAndGet();
+
+    public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
+        show(fm, TYPE_NORMAL, root, doc, null, anim);
+    }
+
+    public static void showSearch(FragmentManager fm, RootInfo root, String query, int anim) {
+        show(fm, TYPE_SEARCH, root, null, query, anim);
+    }
+
+    public static void showRecentsOpen(FragmentManager fm, int anim) {
+        show(fm, TYPE_RECENT_OPEN, null, null, null, anim);
+    }
+
+    private static void show(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+            String query, int anim) {
+        final Bundle args = new Bundle();
+        args.putInt(EXTRA_TYPE, type);
+        args.putParcelable(EXTRA_ROOT, root);
+        args.putParcelable(EXTRA_DOC, doc);
+        args.putString(EXTRA_QUERY, query);
+
+        final FragmentTransaction ft = fm.beginTransaction();
+        switch (anim) {
+            case ANIM_SIDE:
+                args.putBoolean(EXTRA_IGNORE_STATE, true);
+                break;
+            case ANIM_DOWN:
+                args.putBoolean(EXTRA_IGNORE_STATE, true);
+                ft.setCustomAnimations(R.animator.dir_down, R.animator.dir_frozen);
+                break;
+            case ANIM_UP:
+                ft.setCustomAnimations(R.animator.dir_frozen, R.animator.dir_up);
+                break;
+        }
+
+        final DirectoryFragment fragment = new DirectoryFragment();
+        fragment.setArguments(args);
+
+        ft.replace(R.id.container_directory, fragment);
+        ft.commitAllowingStateLoss();
+    }
+
+    private static String buildStateKey(RootInfo root, DocumentInfo doc) {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(root != null ? root.authority : "null").append(';');
+        builder.append(root != null ? root.rootId : "null").append(';');
+        builder.append(doc != null ? doc.documentId : "null");
+        return builder.toString();
+    }
+
+    public static DirectoryFragment get(FragmentManager fm) {
+        // TODO: deal with multiple directories shown at once
+        return (DirectoryFragment) fm.findFragmentById(R.id.container_directory);
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        final Context context = inflater.getContext();
+        final View view = inflater.inflate(R.layout.fragment_directory, container, false);
+
+        mEmptyView = view.findViewById(android.R.id.empty);
+
+        mListView = (ListView) view.findViewById(R.id.list);
+        mListView.setOnItemClickListener(mItemListener);
+        mListView.setMultiChoiceModeListener(mMultiListener);
+        mListView.setRecyclerListener(mRecycleListener);
+
+        mGridView = (GridView) view.findViewById(R.id.grid);
+        mGridView.setOnItemClickListener(mItemListener);
+        mGridView.setMultiChoiceModeListener(mMultiListener);
+        mGridView.setRecyclerListener(mRecycleListener);
+
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+
+        // Cancel any outstanding thumbnail requests
+        final ViewGroup target = (mListView.getAdapter() != null) ? mListView : mGridView;
+        final int count = target.getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View view = target.getChildAt(i);
+            mRecycleListener.onMovedToScrapHeap(view);
+        }
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final Context context = getActivity();
+        final State state = getDisplayState(DirectoryFragment.this);
+
+        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
+        mAdapter = new DocumentsAdapter();
+        mType = getArguments().getInt(EXTRA_TYPE);
+        mStateKey = buildStateKey(root, doc);
+
+        if (mType == TYPE_RECENT_OPEN) {
+            // Hide titles when showing recents for picking images/videos
+            mHideGridTitles = MimePredicate.mimeMatches(
+                    MimePredicate.VISUAL_MIMES, state.acceptMimes);
+        } else {
+            mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+        }
+
+        final ActivityManager am = (ActivityManager) context.getSystemService(
+                Context.ACTIVITY_SERVICE);
+        mSvelteRecents = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+
+        mCallbacks = new LoaderCallbacks<DirectoryResult>() {
+            @Override
+            public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
+                final String query = getArguments().getString(EXTRA_QUERY);
+
+                Uri contentsUri;
+                switch (mType) {
+                    case TYPE_NORMAL:
+                        contentsUri = DocumentsContract.buildChildDocumentsUri(
+                                doc.authority, doc.documentId);
+                        if (state.action == ACTION_MANAGE) {
+                            contentsUri = DocumentsContract.setManageMode(contentsUri);
+                        }
+                        return new DirectoryLoader(
+                                context, mType, root, doc, contentsUri, state.userSortOrder);
+                    case TYPE_SEARCH:
+                        contentsUri = DocumentsContract.buildSearchDocumentsUri(
+                                root.authority, root.rootId, query);
+                        if (state.action == ACTION_MANAGE) {
+                            contentsUri = DocumentsContract.setManageMode(contentsUri);
+                        }
+                        return new DirectoryLoader(
+                                context, mType, root, doc, contentsUri, state.userSortOrder);
+                    case TYPE_RECENT_OPEN:
+                        final RootsCache roots = DocumentsApplication.getRootsCache(context);
+                        return new RecentLoader(context, roots, state);
+                    default:
+                        throw new IllegalStateException("Unknown type " + mType);
+                }
+            }
+
+            @Override
+            public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
+                if (!isAdded()) return;
+
+                mAdapter.swapResult(result);
+
+                // Push latest state up to UI
+                // TODO: if mode change was racing with us, don't overwrite it
+                if (result.mode != MODE_UNKNOWN) {
+                    state.derivedMode = result.mode;
+                }
+                state.derivedSortOrder = result.sortOrder;
+                ((DocumentsActivity) context).onStateChanged();
+
+                updateDisplayState();
+
+                // Restore any previous instance state
+                final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
+                if (container != null && !getArguments().getBoolean(EXTRA_IGNORE_STATE, false)) {
+                    getView().restoreHierarchyState(container);
+                } else if (mLastSortOrder != state.derivedSortOrder) {
+                    mListView.smoothScrollToPosition(0);
+                    mGridView.smoothScrollToPosition(0);
+                }
+
+                mLastSortOrder = state.derivedSortOrder;
+            }
+
+            @Override
+            public void onLoaderReset(Loader<DirectoryResult> loader) {
+                mAdapter.swapResult(null);
+            }
+        };
+
+        // Kick off loader at least once
+        getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
+
+        updateDisplayState();
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+
+        // Remember last scroll location
+        final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
+        getView().saveHierarchyState(container);
+        final State state = getDisplayState(this);
+        state.dirState.put(mStateKey, container);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateDisplayState();
+    }
+
+    public void onUserSortOrderChanged() {
+        // Sort order change always triggers reload; we'll trigger state change
+        // on the flip side.
+        getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
+    }
+
+    public void onUserModeChanged() {
+        final ContentResolver resolver = getActivity().getContentResolver();
+        final State state = getDisplayState(this);
+
+        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
+        if (root != null && doc != null) {
+            final Uri stateUri = RecentsProvider.buildState(
+                    root.authority, root.rootId, doc.documentId);
+            final ContentValues values = new ContentValues();
+            values.put(StateColumns.MODE, state.userMode);
+
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    resolver.insert(stateUri, values);
+                    return null;
+                }
+            }.execute();
+        }
+
+        // Mode change is just visual change; no need to kick loader, and
+        // deliver change event immediately.
+        state.derivedMode = state.userMode;
+        ((DocumentsActivity) getActivity()).onStateChanged();
+
+        updateDisplayState();
+    }
+
+    private void updateDisplayState() {
+        final State state = getDisplayState(this);
+
+        if (mLastMode == state.derivedMode && mLastShowSize == state.showSize) return;
+        mLastMode = state.derivedMode;
+        mLastShowSize = state.showSize;
+
+        mListView.setVisibility(state.derivedMode == MODE_LIST ? View.VISIBLE : View.GONE);
+        mGridView.setVisibility(state.derivedMode == MODE_GRID ? View.VISIBLE : View.GONE);
+
+        final int choiceMode;
+        if (state.allowMultiple) {
+            choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
+        } else {
+            choiceMode = ListView.CHOICE_MODE_NONE;
+        }
+
+        final int thumbSize;
+        if (state.derivedMode == MODE_GRID) {
+            thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
+            mListView.setAdapter(null);
+            mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
+            mGridView.setAdapter(mAdapter);
+            mGridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.grid_width));
+            mGridView.setNumColumns(GridView.AUTO_FIT);
+            mGridView.setChoiceMode(choiceMode);
+            mCurrentView = mGridView;
+        } else if (state.derivedMode == MODE_LIST) {
+            thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
+            mGridView.setAdapter(null);
+            mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
+            mListView.setAdapter(mAdapter);
+            mListView.setChoiceMode(choiceMode);
+            mCurrentView = mListView;
+        } else {
+            throw new IllegalStateException("Unknown state " + state.derivedMode);
+        }
+
+        mThumbSize = new Point(thumbSize, thumbSize);
+    }
+
+    private OnItemClickListener mItemListener = new OnItemClickListener() {
+        @Override
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            final Cursor cursor = mAdapter.getItem(position);
+            if (cursor != null) {
+                final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+                final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+                if (isDocumentEnabled(docMimeType, docFlags)) {
+                    final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+                    ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+                }
+            }
+        }
+    };
+
+    private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() {
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
+            return true;
+        }
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            final State state = getDisplayState(DirectoryFragment.this);
+
+            final MenuItem open = menu.findItem(R.id.menu_open);
+            final MenuItem share = menu.findItem(R.id.menu_share);
+            final MenuItem delete = menu.findItem(R.id.menu_delete);
+
+            final boolean manageMode = state.action == ACTION_MANAGE;
+            open.setVisible(!manageMode);
+            share.setVisible(manageMode);
+            delete.setVisible(manageMode);
+
+            return true;
+        }
+
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
+            final ArrayList<DocumentInfo> docs = Lists.newArrayList();
+            final int size = checked.size();
+            for (int i = 0; i < size; i++) {
+                if (checked.valueAt(i)) {
+                    final Cursor cursor = mAdapter.getItem(checked.keyAt(i));
+                    final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+                    docs.add(doc);
+                }
+            }
+
+            final int id = item.getItemId();
+            if (id == R.id.menu_open) {
+                DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
+                mode.finish();
+                return true;
+
+            } else if (id == R.id.menu_share) {
+                onShareDocuments(docs);
+                mode.finish();
+                return true;
+
+            } else if (id == R.id.menu_delete) {
+                onDeleteDocuments(docs);
+                mode.finish();
+                return true;
+
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public void onDestroyActionMode(ActionMode mode) {
+            // ignored
+        }
+
+        @Override
+        public void onItemCheckedStateChanged(
+                ActionMode mode, int position, long id, boolean checked) {
+            if (checked) {
+                // Directories and footer items cannot be checked
+                boolean valid = false;
+
+                final Cursor cursor = mAdapter.getItem(position);
+                if (cursor != null) {
+                    final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+                    final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+                    if (!Document.MIME_TYPE_DIR.equals(docMimeType)) {
+                        valid = isDocumentEnabled(docMimeType, docFlags);
+                    }
+                }
+
+                if (!valid) {
+                    mCurrentView.setItemChecked(position, false);
+                }
+            }
+
+            mode.setTitle(getResources()
+                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+        }
+    };
+
+    private RecyclerListener mRecycleListener = new RecyclerListener() {
+        @Override
+        public void onMovedToScrapHeap(View view) {
+            final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
+            if (iconThumb != null) {
+                final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
+                if (oldTask != null) {
+                    oldTask.reallyCancel();
+                    iconThumb.setTag(null);
+                }
+            }
+        }
+    };
+
+    private void onShareDocuments(List<DocumentInfo> docs) {
+        Intent intent;
+        if (docs.size() == 1) {
+            final DocumentInfo doc = docs.get(0);
+
+            intent = new Intent(Intent.ACTION_SEND);
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            intent.addCategory(Intent.CATEGORY_DEFAULT);
+            intent.setType(doc.mimeType);
+            intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
+
+        } else if (docs.size() > 1) {
+            intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            intent.addCategory(Intent.CATEGORY_DEFAULT);
+
+            final ArrayList<String> mimeTypes = Lists.newArrayList();
+            final ArrayList<Uri> uris = Lists.newArrayList();
+            for (DocumentInfo doc : docs) {
+                mimeTypes.add(doc.mimeType);
+                uris.add(doc.derivedUri);
+            }
+
+            intent.setType(findCommonMimeType(mimeTypes));
+            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+
+        } else {
+            return;
+        }
+
+        intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
+        startActivity(intent);
+    }
+
+    private void onDeleteDocuments(List<DocumentInfo> docs) {
+        final Context context = getActivity();
+        final ContentResolver resolver = context.getContentResolver();
+
+        boolean hadTrouble = false;
+        for (DocumentInfo doc : docs) {
+            if (!doc.isDeleteSupported()) {
+                Log.w(TAG, "Skipping " + doc);
+                hadTrouble = true;
+                continue;
+            }
+
+            ContentProviderClient client = null;
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        resolver, doc.derivedUri.getAuthority());
+                DocumentsContract.deleteDocument(client, doc.derivedUri);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to delete " + doc);
+                hadTrouble = true;
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+        }
+
+        if (hadTrouble) {
+            Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    private static State getDisplayState(Fragment fragment) {
+        return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
+    }
+
+    private static abstract class Footer {
+        private final int mItemViewType;
+
+        public Footer(int itemViewType) {
+            mItemViewType = itemViewType;
+        }
+
+        public abstract View getView(View convertView, ViewGroup parent);
+
+        public int getItemViewType() {
+            return mItemViewType;
+        }
+    }
+
+    private class LoadingFooter extends Footer {
+        public LoadingFooter() {
+            super(1);
+        }
+
+        @Override
+        public View getView(View convertView, ViewGroup parent) {
+            final Context context = parent.getContext();
+            final State state = getDisplayState(DirectoryFragment.this);
+
+            if (convertView == null) {
+                final LayoutInflater inflater = LayoutInflater.from(context);
+                if (state.derivedMode == MODE_LIST) {
+                    convertView = inflater.inflate(R.layout.item_loading_list, parent, false);
+                } else if (state.derivedMode == MODE_GRID) {
+                    convertView = inflater.inflate(R.layout.item_loading_grid, parent, false);
+                } else {
+                    throw new IllegalStateException();
+                }
+            }
+
+            return convertView;
+        }
+    }
+
+    private class MessageFooter extends Footer {
+        private final int mIcon;
+        private final String mMessage;
+
+        public MessageFooter(int itemViewType, int icon, String message) {
+            super(itemViewType);
+            mIcon = icon;
+            mMessage = message;
+        }
+
+        @Override
+        public View getView(View convertView, ViewGroup parent) {
+            final Context context = parent.getContext();
+            final State state = getDisplayState(DirectoryFragment.this);
+
+            if (convertView == null) {
+                final LayoutInflater inflater = LayoutInflater.from(context);
+                if (state.derivedMode == MODE_LIST) {
+                    convertView = inflater.inflate(R.layout.item_message_list, parent, false);
+                } else if (state.derivedMode == MODE_GRID) {
+                    convertView = inflater.inflate(R.layout.item_message_grid, parent, false);
+                } else {
+                    throw new IllegalStateException();
+                }
+            }
+
+            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            icon.setImageResource(mIcon);
+            title.setText(mMessage);
+            return convertView;
+        }
+    }
+
+    private class DocumentsAdapter extends BaseAdapter {
+        private Cursor mCursor;
+        private int mCursorCount;
+
+        private List<Footer> mFooters = Lists.newArrayList();
+
+        public void swapResult(DirectoryResult result) {
+            mCursor = result != null ? result.cursor : null;
+            mCursorCount = mCursor != null ? mCursor.getCount() : 0;
+
+            mFooters.clear();
+
+            final Bundle extras = mCursor != null ? mCursor.getExtras() : null;
+            if (extras != null) {
+                final String info = extras.getString(DocumentsContract.EXTRA_INFO);
+                if (info != null) {
+                    mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, info));
+                }
+                final String error = extras.getString(DocumentsContract.EXTRA_ERROR);
+                if (error != null) {
+                    mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error));
+                }
+                if (extras.getBoolean(DocumentsContract.EXTRA_LOADING, false)) {
+                    mFooters.add(new LoadingFooter());
+                }
+            }
+
+            if (result != null && result.exception != null) {
+                mFooters.add(new MessageFooter(
+                        3, R.drawable.ic_dialog_alert, getString(R.string.query_error)));
+            }
+
+            if (isEmpty()) {
+                mEmptyView.setVisibility(View.VISIBLE);
+            } else {
+                mEmptyView.setVisibility(View.GONE);
+            }
+
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (position < mCursorCount) {
+                return getDocumentView(position, convertView, parent);
+            } else {
+                position -= mCursorCount;
+                convertView = mFooters.get(position).getView(convertView, parent);
+                // Only the view itself is disabled; contents inside shouldn't
+                // be dimmed.
+                convertView.setEnabled(false);
+                return convertView;
+            }
+        }
+
+        private View getDocumentView(int position, View convertView, ViewGroup parent) {
+            final Context context = parent.getContext();
+            final State state = getDisplayState(DirectoryFragment.this);
+
+            final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
+            final RootsCache roots = DocumentsApplication.getRootsCache(context);
+            final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+                    context, mThumbSize);
+
+            if (convertView == null) {
+                final LayoutInflater inflater = LayoutInflater.from(context);
+                if (state.derivedMode == MODE_LIST) {
+                    convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
+                } else if (state.derivedMode == MODE_GRID) {
+                    convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
+
+                    // Apply padding to grid items
+                    final FrameLayout grid = (FrameLayout) convertView;
+                    final int gridPadding = getResources()
+                            .getDimensionPixelSize(R.dimen.grid_padding);
+
+                    // Tricksy hobbitses! We need to fully clear the drawable so
+                    // the view doesn't clobber the new InsetDrawable callback
+                    // when setting back later.
+                    final Drawable fg = grid.getForeground();
+                    final Drawable bg = grid.getBackground();
+                    grid.setForeground(null);
+                    grid.setBackground(null);
+                    grid.setForeground(new InsetDrawable(fg, gridPadding));
+                    grid.setBackground(new InsetDrawable(bg, gridPadding));
+                } else {
+                    throw new IllegalStateException();
+                }
+            }
+
+            final Cursor cursor = getItem(position);
+
+            final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+            final String docRootId = getCursorString(cursor, RootCursorWrapper.COLUMN_ROOT_ID);
+            final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+            final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+            final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+            final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+            final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+            final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+            final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
+            final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+            final View line1 = convertView.findViewById(R.id.line1);
+            final View line2 = convertView.findViewById(R.id.line2);
+
+            final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
+            final ImageView iconThumb = (ImageView) convertView.findViewById(R.id.icon_thumb);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
+            final ImageView icon2 = (ImageView) convertView.findViewById(android.R.id.icon2);
+            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
+            final TextView date = (TextView) convertView.findViewById(R.id.date);
+            final TextView size = (TextView) convertView.findViewById(R.id.size);
+
+            final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
+            if (oldTask != null) {
+                oldTask.reallyCancel();
+                iconThumb.setTag(null);
+            }
+
+            iconMime.animate().cancel();
+            iconThumb.animate().cancel();
+
+            final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+            final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
+                    || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
+            final boolean showThumbnail = supportsThumbnail && allowThumbnail && !mSvelteRecents;
+
+            boolean cacheHit = false;
+            if (showThumbnail) {
+                final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+                final Bitmap cachedResult = thumbs.get(uri);
+                if (cachedResult != null) {
+                    iconThumb.setImageBitmap(cachedResult);
+                    cacheHit = true;
+                } else {
+                    iconThumb.setImageDrawable(null);
+                    final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
+                            uri, iconMime, iconThumb, mThumbSize);
+                    iconThumb.setTag(task);
+                    task.executeOnExecutor(ProviderExecutor.forAuthority(docAuthority));
+                }
+            }
+
+            // Always throw MIME icon into place, even when a thumbnail is being
+            // loaded in background.
+            if (cacheHit) {
+                iconMime.setAlpha(0f);
+                iconMime.setImageDrawable(null);
+                iconThumb.setAlpha(1f);
+            } else {
+                iconMime.setAlpha(1f);
+                iconThumb.setAlpha(0f);
+                iconThumb.setImageDrawable(null);
+                if (docIcon != 0) {
+                    iconMime.setImageDrawable(
+                            IconUtils.loadPackageIcon(context, docAuthority, docIcon));
+                } else {
+                    iconMime.setImageDrawable(IconUtils.loadMimeIcon(
+                            context, docMimeType, docAuthority, docId, state.derivedMode));
+                }
+            }
+
+            boolean hasLine1 = false;
+            boolean hasLine2 = false;
+
+            final boolean hideTitle = (state.derivedMode == MODE_GRID) && mHideGridTitles;
+            if (!hideTitle) {
+                title.setText(docDisplayName);
+                hasLine1 = true;
+            }
+
+            Drawable iconDrawable = null;
+            if (mType == TYPE_RECENT_OPEN) {
+                // We've already had to enumerate roots before any results can
+                // be shown, so this will never block.
+                final RootInfo root = roots.getRootBlocking(docAuthority, docRootId);
+                iconDrawable = root.loadIcon(context);
+
+                if (summary != null) {
+                    final boolean alwaysShowSummary = getResources()
+                            .getBoolean(R.bool.always_show_summary);
+                    if (alwaysShowSummary) {
+                        summary.setText(root.getDirectoryString());
+                        summary.setVisibility(View.VISIBLE);
+                        hasLine2 = true;
+                    } else {
+                        if (iconDrawable != null && roots.isIconUniqueBlocking(root)) {
+                            // No summary needed if icon speaks for itself
+                            summary.setVisibility(View.INVISIBLE);
+                        } else {
+                            summary.setText(root.getDirectoryString());
+                            summary.setVisibility(View.VISIBLE);
+                            summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
+                            hasLine2 = true;
+                        }
+                    }
+                }
+            } else {
+                // Directories showing thumbnails in grid mode get a little icon
+                // hint to remind user they're a directory.
+                if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
+                        && showThumbnail) {
+                    iconDrawable = context.getResources().getDrawable(R.drawable.ic_root_folder);
+                }
+
+                if (summary != null) {
+                    if (docSummary != null) {
+                        summary.setText(docSummary);
+                        summary.setVisibility(View.VISIBLE);
+                        hasLine2 = true;
+                    } else {
+                        summary.setVisibility(View.INVISIBLE);
+                    }
+                }
+            }
+
+            if (icon1 != null) icon1.setVisibility(View.GONE);
+            if (icon2 != null) icon2.setVisibility(View.GONE);
+
+            if (iconDrawable != null) {
+                if (hasLine1) {
+                    icon1.setVisibility(View.VISIBLE);
+                    icon1.setImageDrawable(iconDrawable);
+                } else {
+                    icon2.setVisibility(View.VISIBLE);
+                    icon2.setImageDrawable(iconDrawable);
+                }
+            }
+
+            if (docLastModified == -1) {
+                date.setText(null);
+            } else {
+                date.setText(formatTime(context, docLastModified));
+                hasLine2 = true;
+            }
+
+            if (state.showSize) {
+                size.setVisibility(View.VISIBLE);
+                if (Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
+                    size.setText(null);
+                } else {
+                    size.setText(Formatter.formatFileSize(context, docSize));
+                    hasLine2 = true;
+                }
+            } else {
+                size.setVisibility(View.GONE);
+            }
+
+            if (line1 != null) {
+                line1.setVisibility(hasLine1 ? View.VISIBLE : View.GONE);
+            }
+            if (line2 != null) {
+                line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
+            }
+
+            final boolean enabled = isDocumentEnabled(docMimeType, docFlags);
+            if (enabled) {
+                setEnabledRecursive(convertView, true);
+                iconMime.setAlpha(1f);
+                iconThumb.setAlpha(1f);
+                if (icon1 != null) icon1.setAlpha(1f);
+                if (icon2 != null) icon2.setAlpha(1f);
+            } else {
+                setEnabledRecursive(convertView, false);
+                iconMime.setAlpha(0.5f);
+                iconThumb.setAlpha(0.5f);
+                if (icon1 != null) icon1.setAlpha(0.5f);
+                if (icon2 != null) icon2.setAlpha(0.5f);
+            }
+
+            return convertView;
+        }
+
+        @Override
+        public int getCount() {
+            return mCursorCount + mFooters.size();
+        }
+
+        @Override
+        public Cursor getItem(int position) {
+            if (position < mCursorCount) {
+                mCursor.moveToPosition(position);
+                return mCursor;
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 4;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            if (position < mCursorCount) {
+                return 0;
+            } else {
+                position -= mCursorCount;
+                return mFooters.get(position).getItemViewType();
+            }
+        }
+    }
+
+    private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> {
+        private final Uri mUri;
+        private final ImageView mIconMime;
+        private final ImageView mIconThumb;
+        private final Point mThumbSize;
+        private final CancellationSignal mSignal;
+
+        public ThumbnailAsyncTask(
+                Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize) {
+            mUri = uri;
+            mIconMime = iconMime;
+            mIconThumb = iconThumb;
+            mThumbSize = thumbSize;
+            mSignal = new CancellationSignal();
+        }
+
+        public void reallyCancel() {
+            cancel(false);
+            mSignal.cancel();
+        }
+
+        @Override
+        protected Bitmap doInBackground(Uri... params) {
+            if (isCancelled()) return null;
+
+            final Context context = mIconThumb.getContext();
+            final ContentResolver resolver = context.getContentResolver();
+
+            ContentProviderClient client = null;
+            Bitmap result = null;
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        resolver, mUri.getAuthority());
+                result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
+                if (result != null) {
+                    final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+                            context, mThumbSize);
+                    thumbs.put(mUri, result);
+                }
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+            return result;
+        }
+
+        @Override
+        protected void onPostExecute(Bitmap result) {
+            if (mIconThumb.getTag() == this && result != null) {
+                mIconThumb.setTag(null);
+                mIconThumb.setImageBitmap(result);
+
+                final float targetAlpha = mIconMime.isEnabled() ? 1f : 0.5f;
+                mIconMime.setAlpha(targetAlpha);
+                mIconMime.animate().alpha(0f).start();
+                mIconThumb.setAlpha(0f);
+                mIconThumb.animate().alpha(targetAlpha).start();
+            }
+        }
+    }
+
+    private static String formatTime(Context context, long when) {
+        // TODO: DateUtils should make this easier
+        Time then = new Time();
+        then.set(when);
+        Time now = new Time();
+        now.setToNow();
+
+        int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
+                | DateUtils.FORMAT_ABBREV_ALL;
+
+        if (then.year != now.year) {
+            flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
+        } else if (then.yearDay != now.yearDay) {
+            flags |= DateUtils.FORMAT_SHOW_DATE;
+        } else {
+            flags |= DateUtils.FORMAT_SHOW_TIME;
+        }
+
+        return DateUtils.formatDateTime(context, when, flags);
+    }
+
+    private String findCommonMimeType(List<String> mimeTypes) {
+        String[] commonType = mimeTypes.get(0).split("/");
+        if (commonType.length != 2) {
+            return "*/*";
+        }
+
+        for (int i = 1; i < mimeTypes.size(); i++) {
+            String[] type = mimeTypes.get(i).split("/");
+            if (type.length != 2) continue;
+
+            if (!commonType[1].equals(type[1])) {
+                commonType[1] = "*";
+            }
+
+            if (!commonType[0].equals(type[0])) {
+                commonType[0] = "*";
+                commonType[1] = "*";
+                break;
+            }
+        }
+
+        return commonType[0] + "/" + commonType[1];
+    }
+
+    private void setEnabledRecursive(View v, boolean enabled) {
+        if (v == null) return;
+        if (v.isEnabled() == enabled) return;
+        v.setEnabled(enabled);
+
+        if (v instanceof ViewGroup) {
+            final ViewGroup vg = (ViewGroup) v;
+            for (int i = vg.getChildCount() - 1; i >= 0; i--) {
+                setEnabledRecursive(vg.getChildAt(i), enabled);
+            }
+        }
+    }
+
+    private boolean isDocumentEnabled(String docMimeType, int docFlags) {
+        final State state = getDisplayState(DirectoryFragment.this);
+
+        // Directories are always enabled
+        if (Document.MIME_TYPE_DIR.equals(docMimeType)) {
+            return true;
+        }
+
+        // Read-only files are disabled when creating
+        if (state.action == ACTION_CREATE && (docFlags & Document.FLAG_SUPPORTS_WRITE) == 0) {
+            return false;
+        }
+
+        return MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
new file mode 100644
index 0000000..163615d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -0,0 +1,267 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+
+import android.content.AsyncTaskLoader;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.StateColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.RootInfo;
+
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+
+class DirectoryResult implements AutoCloseable {
+    ContentProviderClient client;
+    Cursor cursor;
+    Exception exception;
+
+    int mode = MODE_UNKNOWN;
+    int sortOrder = SORT_ORDER_UNKNOWN;
+
+    @Override
+    public void close() {
+        IoUtils.closeQuietly(cursor);
+        ContentProviderClient.releaseQuietly(client);
+        cursor = null;
+        client = null;
+    }
+}
+
+public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
+
+    private static final String[] SEARCH_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };
+
+    private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
+
+    private final int mType;
+    private final RootInfo mRoot;
+    private DocumentInfo mDoc;
+    private final Uri mUri;
+    private final int mUserSortOrder;
+
+    private CancellationSignal mSignal;
+    private DirectoryResult mResult;
+
+    public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
+            int userSortOrder) {
+        super(context, ProviderExecutor.forAuthority(root.authority));
+        mType = type;
+        mRoot = root;
+        mDoc = doc;
+        mUri = uri;
+        mUserSortOrder = userSortOrder;
+    }
+
+    @Override
+    public final DirectoryResult loadInBackground() {
+        synchronized (this) {
+            if (isLoadInBackgroundCanceled()) {
+                throw new OperationCanceledException();
+            }
+            mSignal = new CancellationSignal();
+        }
+
+        final ContentResolver resolver = getContext().getContentResolver();
+        final String authority = mUri.getAuthority();
+
+        final DirectoryResult result = new DirectoryResult();
+
+        int userMode = State.MODE_UNKNOWN;
+
+        // Use default document when searching
+        if (mType == DirectoryFragment.TYPE_SEARCH) {
+            final Uri docUri = DocumentsContract.buildDocumentUri(
+                    mRoot.authority, mRoot.documentId);
+            try {
+                mDoc = DocumentInfo.fromUri(resolver, docUri);
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Failed to query", e);
+                result.exception = e;
+                return result;
+            }
+        }
+
+        // Pick up any custom modes requested by user
+        Cursor cursor = null;
+        try {
+            final Uri stateUri = RecentsProvider.buildState(
+                    mRoot.authority, mRoot.rootId, mDoc.documentId);
+            cursor = resolver.query(stateUri, null, null, null, null);
+            if (cursor.moveToFirst()) {
+                userMode = getCursorInt(cursor, StateColumns.MODE);
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+
+        if (userMode != State.MODE_UNKNOWN) {
+            result.mode = userMode;
+        } else {
+            if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
+                result.mode = State.MODE_GRID;
+            } else {
+                result.mode = State.MODE_LIST;
+            }
+        }
+
+        if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
+            result.sortOrder = mUserSortOrder;
+        } else {
+            if ((mDoc.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0) {
+                result.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
+            } else {
+                result.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
+            }
+        }
+
+        // Search always uses ranking from provider
+        if (mType == DirectoryFragment.TYPE_SEARCH) {
+            result.sortOrder = State.SORT_ORDER_UNKNOWN;
+        }
+
+        Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
+                + result.mode + ", sortOrder=" + result.sortOrder);
+
+        ContentProviderClient client = null;
+        try {
+            client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
+
+            cursor = client.query(
+                    mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
+            cursor.registerContentObserver(mObserver);
+
+            cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
+
+            if (mType == DirectoryFragment.TYPE_SEARCH) {
+                // Filter directories out of search results, for now
+                cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
+            } else {
+                // Normal directories should have sorting applied
+                cursor = new SortingCursorWrapper(cursor, result.sortOrder);
+            }
+
+            result.client = client;
+            result.cursor = cursor;
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to query", e);
+            result.exception = e;
+            ContentProviderClient.releaseQuietly(client);
+        } finally {
+            synchronized (this) {
+                mSignal = null;
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public void cancelLoadInBackground() {
+        super.cancelLoadInBackground();
+
+        synchronized (this) {
+            if (mSignal != null) {
+                mSignal.cancel();
+            }
+        }
+    }
+
+    @Override
+    public void deliverResult(DirectoryResult result) {
+        if (isReset()) {
+            IoUtils.closeQuietly(result);
+            return;
+        }
+        DirectoryResult oldResult = mResult;
+        mResult = result;
+
+        if (isStarted()) {
+            super.deliverResult(result);
+        }
+
+        if (oldResult != null && oldResult != result) {
+            IoUtils.closeQuietly(oldResult);
+        }
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (mResult != null) {
+            deliverResult(mResult);
+        }
+        if (takeContentChanged() || mResult == null) {
+            forceLoad();
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        cancelLoad();
+    }
+
+    @Override
+    public void onCanceled(DirectoryResult result) {
+        IoUtils.closeQuietly(result);
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+
+        // Ensure the loader is stopped
+        onStopLoading();
+
+        IoUtils.closeQuietly(mResult);
+        mResult = null;
+
+        getContext().getContentResolver().unregisterContentObserver(mObserver);
+    }
+
+    public static String getQuerySortOrder(int sortOrder) {
+        switch (sortOrder) {
+            case SORT_ORDER_DISPLAY_NAME:
+                return Document.COLUMN_DISPLAY_NAME + " ASC";
+            case SORT_ORDER_LAST_MODIFIED:
+                return Document.COLUMN_LAST_MODIFIED + " DESC";
+            case SORT_ORDER_SIZE:
+                return Document.COLUMN_SIZE + " DESC";
+            default:
+                return null;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
new file mode 100644
index 0000000..b552e5a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -0,0 +1,62 @@
+/*
+ * 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.documentsui;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class DirectoryView extends FrameLayout {
+    private float mPosition = 0f;
+
+    private int mWidth;
+
+    public DirectoryView(Context context) {
+        super(context);
+    }
+
+    public DirectoryView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void setBackground(Drawable background) {
+        final Rect rect = new Rect();
+        background.getPadding(rect);
+        final InsetDrawable inset = new InsetDrawable(background, -rect.left, 0, -rect.right, 0);
+        super.setBackground(inset);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mWidth = w;
+        setPosition(mPosition);
+    }
+
+    public float getPosition() {
+        return mPosition;
+    }
+
+    public void setPosition(float position) {
+        mPosition = position;
+        setX((mWidth > 0) ? (mPosition * mWidth) : 0);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
new file mode 100644
index 0000000..7660779
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -0,0 +1,1206 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
+import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
+import static com.android.documentsui.DirectoryFragment.ANIM_UP;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN;
+import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
+import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
+
+import android.app.ActionBar;
+import android.app.ActionBar.OnNavigationListener;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Point;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Root;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.SearchView;
+import android.widget.SearchView.OnQueryTextListener;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.documentsui.RecentsProvider.RecentColumns;
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+import com.google.common.collect.Maps;
+
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+public class DocumentsActivity extends Activity {
+    public static final String TAG = "Documents";
+
+    private static final String EXTRA_STATE = "state";
+
+    private static final int CODE_FORWARD = 42;
+
+    private boolean mShowAsDialog;
+
+    private SearchView mSearchView;
+
+    private DrawerLayout mDrawerLayout;
+    private ActionBarDrawerToggle mDrawerToggle;
+    private View mRootsContainer;
+
+    private DirectoryContainerView mDirectoryContainer;
+
+    private boolean mIgnoreNextNavigation;
+    private boolean mIgnoreNextClose;
+    private boolean mIgnoreNextCollapse;
+
+    private RootsCache mRoots;
+    private State mState;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mRoots = DocumentsApplication.getRootsCache(this);
+
+        setResult(Activity.RESULT_CANCELED);
+        setContentView(R.layout.activity);
+
+        final Resources res = getResources();
+        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
+
+        if (mShowAsDialog) {
+            // backgroundDimAmount from theme isn't applied; do it manually
+            final WindowManager.LayoutParams a = getWindow().getAttributes();
+            a.dimAmount = 0.6f;
+            getWindow().setAttributes(a);
+
+            getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
+            getWindow().setFlags(~0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+
+            // Inset ourselves to look like a dialog
+            final Point size = new Point();
+            getWindowManager().getDefaultDisplay().getSize(size);
+
+            final int width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
+            final int height = (int) res.getFraction(R.dimen.dialog_height, size.y, size.y);
+            final int insetX = (size.x - width) / 2;
+            final int insetY = (size.y - height) / 2;
+
+            final Drawable before = getWindow().getDecorView().getBackground();
+            final Drawable after = new InsetDrawable(before, insetX, insetY, insetX, insetY);
+            getWindow().getDecorView().setBackground(after);
+
+            // Dismiss when touch down in the dimmed inset area
+            getWindow().getDecorView().setOnTouchListener(new OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                        final float x = event.getX();
+                        final float y = event.getY();
+                        if (x < insetX || x > v.getWidth() - insetX || y < insetY
+                                || y > v.getHeight() - insetY) {
+                            finish();
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            });
+
+        } else {
+            // Non-dialog means we have a drawer
+            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+
+            mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
+                    R.drawable.ic_drawer_glyph, R.string.drawer_open, R.string.drawer_close);
+
+            mDrawerLayout.setDrawerListener(mDrawerListener);
+            mDrawerLayout.setDrawerShadow(R.drawable.ic_drawer_shadow, GravityCompat.START);
+
+            mRootsContainer = findViewById(R.id.container_roots);
+        }
+
+        mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
+
+        if (icicle != null) {
+            mState = icicle.getParcelable(EXTRA_STATE);
+        } else {
+            buildDefaultState();
+        }
+
+        // Hide roots when we're managing a specific root
+        if (mState.action == ACTION_MANAGE) {
+            if (mShowAsDialog) {
+                findViewById(R.id.dialog_roots).setVisibility(View.GONE);
+            } else {
+                mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+            }
+        }
+
+        if (mState.action == ACTION_CREATE) {
+            final String mimeType = getIntent().getType();
+            final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
+            SaveFragment.show(getFragmentManager(), mimeType, title);
+        }
+
+        if (mState.action == ACTION_GET_CONTENT) {
+            final Intent moreApps = new Intent(getIntent());
+            moreApps.setComponent(null);
+            moreApps.setPackage(null);
+            RootsFragment.show(getFragmentManager(), moreApps);
+        } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE) {
+            RootsFragment.show(getFragmentManager(), null);
+        }
+
+        if (!mState.restored) {
+            if (mState.action == ACTION_MANAGE) {
+                final Uri rootUri = getIntent().getData();
+                new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
+            } else {
+                new RestoreStackTask().execute();
+            }
+        } else {
+            onCurrentDirectoryChanged(ANIM_NONE);
+        }
+    }
+
+    private void buildDefaultState() {
+        mState = new State();
+
+        final Intent intent = getIntent();
+        final String action = intent.getAction();
+        if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
+            mState.action = ACTION_OPEN;
+        } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
+            mState.action = ACTION_CREATE;
+        } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
+            mState.action = ACTION_GET_CONTENT;
+        } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {
+            mState.action = ACTION_MANAGE;
+        }
+
+        if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
+            mState.allowMultiple = intent.getBooleanExtra(
+                    Intent.EXTRA_ALLOW_MULTIPLE, false);
+        }
+
+        if (mState.action == ACTION_MANAGE) {
+            mState.acceptMimes = new String[] { "*/*" };
+            mState.allowMultiple = true;
+        } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+            mState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
+        } else {
+            mState.acceptMimes = new String[] { intent.getType() };
+        }
+
+        mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
+        mState.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(this);
+    }
+
+    private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
+        private Uri mRootUri;
+
+        public RestoreRootTask(Uri rootUri) {
+            mRootUri = rootUri;
+        }
+
+        @Override
+        protected RootInfo doInBackground(Void... params) {
+            final String rootId = DocumentsContract.getRootId(mRootUri);
+            return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+        }
+
+        @Override
+        protected void onPostExecute(RootInfo root) {
+            if (isDestroyed()) return;
+            mState.restored = true;
+
+            if (root != null) {
+                onRootPicked(root, true);
+            } else {
+                Log.w(TAG, "Failed to find root: " + mRootUri);
+                finish();
+            }
+        }
+    }
+
+    private class RestoreStackTask extends AsyncTask<Void, Void, Void> {
+        private volatile boolean mRestoredStack;
+        private volatile boolean mExternal;
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            // Restore last stack for calling package
+            final String packageName = getCallingPackage();
+            final Cursor cursor = getContentResolver()
+                    .query(RecentsProvider.buildResume(packageName), null, null, null, null);
+            try {
+                if (cursor.moveToFirst()) {
+                    mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
+                    final byte[] rawStack = cursor.getBlob(
+                            cursor.getColumnIndex(ResumeColumns.STACK));
+                    DurableUtils.readFromArray(rawStack, mState.stack);
+                    mRestoredStack = true;
+                }
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to resume: " + e);
+            } finally {
+                IoUtils.closeQuietly(cursor);
+            }
+
+            if (mRestoredStack) {
+                // Update the restored stack to ensure we have freshest data
+                final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
+                try {
+                    mState.stack.updateRoot(matchingRoots);
+                    mState.stack.updateDocuments(getContentResolver());
+                } catch (FileNotFoundException e) {
+                    Log.w(TAG, "Failed to restore stack: " + e);
+                    mState.stack.reset();
+                    mRestoredStack = false;
+                }
+            }
+
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            if (isDestroyed()) return;
+            mState.restored = true;
+
+            // Show drawer when no stack restored, but only when requesting
+            // non-visual content. However, if we last used an external app,
+            // drawer is always shown.
+
+            boolean showDrawer = false;
+            if (!mRestoredStack) {
+                showDrawer = true;
+            }
+            if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
+                showDrawer = false;
+            }
+            if (mExternal && mState.action == ACTION_GET_CONTENT) {
+                showDrawer = true;
+            }
+
+            if (showDrawer) {
+                setRootsDrawerOpen(true);
+            }
+
+            onCurrentDirectoryChanged(ANIM_NONE);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        if (mState.action == ACTION_MANAGE) {
+            mState.showSize = true;
+        } else {
+            mState.showSize = SettingsActivity.getDisplayFileSize(this);
+            invalidateOptionsMenu();
+        }
+    }
+
+    private DrawerListener mDrawerListener = new DrawerListener() {
+        @Override
+        public void onDrawerSlide(View drawerView, float slideOffset) {
+            mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
+        }
+
+        @Override
+        public void onDrawerOpened(View drawerView) {
+            mDrawerToggle.onDrawerOpened(drawerView);
+            updateActionBar();
+            invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onDrawerClosed(View drawerView) {
+            mDrawerToggle.onDrawerClosed(drawerView);
+            updateActionBar();
+            invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onDrawerStateChanged(int newState) {
+            mDrawerToggle.onDrawerStateChanged(newState);
+        }
+    };
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        if (mDrawerToggle != null) {
+            mDrawerToggle.syncState();
+        }
+    }
+
+    public void setRootsDrawerOpen(boolean open) {
+        if (!mShowAsDialog) {
+            if (open) {
+                mDrawerLayout.openDrawer(mRootsContainer);
+            } else {
+                mDrawerLayout.closeDrawer(mRootsContainer);
+            }
+        }
+    }
+
+    private boolean isRootsDrawerOpen() {
+        if (mShowAsDialog) {
+            return false;
+        } else {
+            return mDrawerLayout.isDrawerOpen(mRootsContainer);
+        }
+    }
+
+    public void updateActionBar() {
+        final ActionBar actionBar = getActionBar();
+
+        actionBar.setDisplayShowHomeEnabled(true);
+
+        final boolean showIndicator = !mShowAsDialog && (mState.action != ACTION_MANAGE);
+        actionBar.setDisplayHomeAsUpEnabled(showIndicator);
+        if (mDrawerToggle != null) {
+            mDrawerToggle.setDrawerIndicatorEnabled(showIndicator);
+        }
+
+        if (isRootsDrawerOpen()) {
+            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+            actionBar.setIcon(new ColorDrawable());
+
+            if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
+                actionBar.setTitle(R.string.title_open);
+            } else if (mState.action == ACTION_CREATE) {
+                actionBar.setTitle(R.string.title_save);
+            }
+        } else {
+            final RootInfo root = getCurrentRoot();
+            actionBar.setIcon(root != null ? root.loadIcon(this) : null);
+
+            if (mState.stack.size() <= 1) {
+                actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+                actionBar.setTitle(root.title);
+            } else {
+                mIgnoreNextNavigation = true;
+                actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+                actionBar.setTitle(null);
+                actionBar.setListNavigationCallbacks(mStackAdapter, mStackListener);
+                actionBar.setSelectedNavigationItem(mStackAdapter.getCount() - 1);
+            }
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.activity, menu);
+
+        // Actions are always visible when showing as dialog
+        if (mShowAsDialog) {
+            for (int i = 0; i < menu.size(); i++) {
+                menu.getItem(i).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+            }
+        }
+
+        final MenuItem searchMenu = menu.findItem(R.id.menu_search);
+        mSearchView = (SearchView) searchMenu.getActionView();
+        mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
+            @Override
+            public boolean onQueryTextSubmit(String query) {
+                mState.currentSearch = query;
+                mSearchView.clearFocus();
+                onCurrentDirectoryChanged(ANIM_NONE);
+                return true;
+            }
+
+            @Override
+            public boolean onQueryTextChange(String newText) {
+                return false;
+            }
+        });
+
+        searchMenu.setOnActionExpandListener(new OnActionExpandListener() {
+            @Override
+            public boolean onMenuItemActionExpand(MenuItem item) {
+                return true;
+            }
+
+            @Override
+            public boolean onMenuItemActionCollapse(MenuItem item) {
+                if (mIgnoreNextCollapse) {
+                    mIgnoreNextCollapse = false;
+                    return true;
+                }
+
+                mState.currentSearch = null;
+                onCurrentDirectoryChanged(ANIM_NONE);
+                return true;
+            }
+        });
+
+        mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
+            @Override
+            public boolean onClose() {
+                if (mIgnoreNextClose) {
+                    mIgnoreNextClose = false;
+                    return false;
+                }
+
+                mState.currentSearch = null;
+                onCurrentDirectoryChanged(ANIM_NONE);
+                return false;
+            }
+        });
+
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+
+        final FragmentManager fm = getFragmentManager();
+
+        final RootInfo root = getCurrentRoot();
+        final DocumentInfo cwd = getCurrentDirectory();
+
+        final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
+        final MenuItem search = menu.findItem(R.id.menu_search);
+        final MenuItem sort = menu.findItem(R.id.menu_sort);
+        final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
+        final MenuItem grid = menu.findItem(R.id.menu_grid);
+        final MenuItem list = menu.findItem(R.id.menu_list);
+        final MenuItem settings = menu.findItem(R.id.menu_settings);
+
+        // Open drawer means we hide most actions
+        if (isRootsDrawerOpen()) {
+            createDir.setVisible(false);
+            search.setVisible(false);
+            sort.setVisible(false);
+            grid.setVisible(false);
+            list.setVisible(false);
+            mIgnoreNextCollapse = true;
+            search.collapseActionView();
+            return true;
+        }
+
+        sort.setVisible(cwd != null);
+        grid.setVisible(mState.derivedMode != MODE_GRID);
+        list.setVisible(mState.derivedMode != MODE_LIST);
+
+        if (mState.currentSearch != null) {
+            // Search uses backend ranking; no sorting
+            sort.setVisible(false);
+
+            search.expandActionView();
+
+            mSearchView.setIconified(false);
+            mSearchView.clearFocus();
+            mSearchView.setQuery(mState.currentSearch, false);
+        } else {
+            mIgnoreNextClose = true;
+            mSearchView.setIconified(true);
+            mSearchView.clearFocus();
+
+            mIgnoreNextCollapse = true;
+            search.collapseActionView();
+        }
+
+        // Only sort by size when visible
+        sortSize.setVisible(mState.showSize);
+
+        final boolean searchVisible;
+        if (mState.action == ACTION_CREATE) {
+            createDir.setVisible(cwd != null && cwd.isCreateSupported());
+            searchVisible = false;
+
+            // No display options in recent directories
+            if (cwd == null) {
+                grid.setVisible(false);
+                list.setVisible(false);
+            }
+
+            SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
+        } else {
+            createDir.setVisible(false);
+
+            searchVisible = root != null
+                    && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0);
+        }
+
+        // TODO: close any search in-progress when hiding
+        search.setVisible(searchVisible);
+
+        settings.setVisible(mState.action != ACTION_MANAGE);
+
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
+            return true;
+        }
+
+        final int id = item.getItemId();
+        if (id == android.R.id.home) {
+            onBackPressed();
+            return true;
+        } else if (id == R.id.menu_create_dir) {
+            CreateDirectoryFragment.show(getFragmentManager());
+            return true;
+        } else if (id == R.id.menu_search) {
+            return false;
+        } else if (id == R.id.menu_sort_name) {
+            setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME);
+            return true;
+        } else if (id == R.id.menu_sort_date) {
+            setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED);
+            return true;
+        } else if (id == R.id.menu_sort_size) {
+            setUserSortOrder(State.SORT_ORDER_SIZE);
+            return true;
+        } else if (id == R.id.menu_grid) {
+            setUserMode(State.MODE_GRID);
+            return true;
+        } else if (id == R.id.menu_list) {
+            setUserMode(State.MODE_LIST);
+            return true;
+        } else if (id == R.id.menu_settings) {
+            startActivity(new Intent(this, SettingsActivity.class));
+            return true;
+        } else {
+            return super.onOptionsItemSelected(item);
+        }
+    }
+
+    /**
+     * Update UI to reflect internal state changes not from user.
+     */
+    public void onStateChanged() {
+        invalidateOptionsMenu();
+    }
+
+    /**
+     * Set state sort order based on explicit user action.
+     */
+    private void setUserSortOrder(int sortOrder) {
+        mState.userSortOrder = sortOrder;
+        DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+    }
+
+    /**
+     * Set state mode based on explicit user action.
+     */
+    private void setUserMode(int mode) {
+        mState.userMode = mode;
+        DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (!mState.stackTouched) {
+            super.onBackPressed();
+            return;
+        }
+
+        final int size = mState.stack.size();
+        if (size > 1) {
+            mState.stack.pop();
+            onCurrentDirectoryChanged(ANIM_UP);
+        } else if (size == 1 && !isRootsDrawerOpen()) {
+            // TODO: open root drawer once we can capture back key
+            super.onBackPressed();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle state) {
+        super.onSaveInstanceState(state);
+        state.putParcelable(EXTRA_STATE, mState);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+        updateActionBar();
+    }
+
+    private BaseAdapter mStackAdapter = new BaseAdapter() {
+        @Override
+        public int getCount() {
+            return mState.stack.size();
+        }
+
+        @Override
+        public DocumentInfo getItem(int position) {
+            return mState.stack.get(mState.stack.size() - position - 1);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = LayoutInflater.from(parent.getContext())
+                        .inflate(R.layout.item_title, parent, false);
+            }
+
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final DocumentInfo doc = getItem(position);
+
+            if (position == 0) {
+                final RootInfo root = getCurrentRoot();
+                title.setText(root.title);
+            } else {
+                title.setText(doc.displayName);
+            }
+
+            // No padding when shown in actionbar
+            convertView.setPadding(0, 0, 0, 0);
+            return convertView;
+        }
+
+        @Override
+        public View getDropDownView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = LayoutInflater.from(parent.getContext())
+                        .inflate(R.layout.item_title, parent, false);
+            }
+
+            final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final DocumentInfo doc = getItem(position);
+
+            if (position == 0) {
+                final RootInfo root = getCurrentRoot();
+                title.setText(root.title);
+                subdir.setVisibility(View.GONE);
+            } else {
+                title.setText(doc.displayName);
+                subdir.setVisibility(View.VISIBLE);
+            }
+
+            return convertView;
+        }
+    };
+
+    private OnNavigationListener mStackListener = new OnNavigationListener() {
+        @Override
+        public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+            if (mIgnoreNextNavigation) {
+                mIgnoreNextNavigation = false;
+                return false;
+            }
+
+            while (mState.stack.size() > itemPosition + 1) {
+                mState.stackTouched = true;
+                mState.stack.pop();
+            }
+            onCurrentDirectoryChanged(ANIM_UP);
+            return true;
+        }
+    };
+
+    public RootInfo getCurrentRoot() {
+        if (mState.stack.root != null) {
+            return mState.stack.root;
+        } else {
+            return mRoots.getRecentsRoot();
+        }
+    }
+
+    public DocumentInfo getCurrentDirectory() {
+        return mState.stack.peek();
+    }
+
+    public Executor getCurrentExecutor() {
+        final DocumentInfo cwd = getCurrentDirectory();
+        if (cwd != null && cwd.authority != null) {
+            return ProviderExecutor.forAuthority(cwd.authority);
+        } else {
+            return AsyncTask.THREAD_POOL_EXECUTOR;
+        }
+    }
+
+    public State getDisplayState() {
+        return mState;
+    }
+
+    private void onCurrentDirectoryChanged(int anim) {
+        final FragmentManager fm = getFragmentManager();
+        final RootInfo root = getCurrentRoot();
+        final DocumentInfo cwd = getCurrentDirectory();
+
+        mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
+
+        if (cwd == null) {
+            // No directory means recents
+            if (mState.action == ACTION_CREATE) {
+                RecentsCreateFragment.show(fm);
+            } else {
+                DirectoryFragment.showRecentsOpen(fm, anim);
+
+                // Start recents in grid when requesting visual things
+                final boolean visualMimes = MimePredicate.mimeMatches(
+                        MimePredicate.VISUAL_MIMES, mState.acceptMimes);
+                mState.userMode = visualMimes ? MODE_GRID : MODE_LIST;
+                mState.derivedMode = mState.userMode;
+            }
+        } else {
+            if (mState.currentSearch != null) {
+                // Ongoing search
+                DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
+            } else {
+                // Normal boring directory
+                DirectoryFragment.showNormal(fm, root, cwd, anim);
+            }
+        }
+
+        // Forget any replacement target
+        if (mState.action == ACTION_CREATE) {
+            final SaveFragment save = SaveFragment.get(fm);
+            if (save != null) {
+                save.setReplaceTarget(null);
+            }
+        }
+
+        final RootsFragment roots = RootsFragment.get(fm);
+        if (roots != null) {
+            roots.onCurrentRootChanged();
+        }
+
+        updateActionBar();
+        invalidateOptionsMenu();
+        dumpStack();
+    }
+
+    public void onStackPicked(DocumentStack stack) {
+        try {
+            // Update the restored stack to ensure we have freshest data
+            stack.updateDocuments(getContentResolver());
+
+            mState.stack = stack;
+            mState.stackTouched = true;
+            onCurrentDirectoryChanged(ANIM_SIDE);
+
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "Failed to restore stack: " + e);
+        }
+    }
+
+    public void onRootPicked(RootInfo root, boolean closeDrawer) {
+        // Clear entire backstack and start in new root
+        mState.stack.root = root;
+        mState.stack.clear();
+        mState.stackTouched = true;
+
+        if (!mRoots.isRecentsRoot(root)) {
+            new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
+        } else {
+            onCurrentDirectoryChanged(ANIM_SIDE);
+        }
+
+        if (closeDrawer) {
+            setRootsDrawerOpen(false);
+        }
+    }
+
+    private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
+        private RootInfo mRoot;
+
+        public PickRootTask(RootInfo root) {
+            mRoot = root;
+        }
+
+        @Override
+        protected DocumentInfo doInBackground(Void... params) {
+            try {
+                final Uri uri = DocumentsContract.buildDocumentUri(
+                        mRoot.authority, mRoot.documentId);
+                return DocumentInfo.fromUri(getContentResolver(), uri);
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Failed to find root", e);
+                return null;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(DocumentInfo result) {
+            if (result != null) {
+                mState.stack.push(result);
+                mState.stackTouched = true;
+                onCurrentDirectoryChanged(ANIM_SIDE);
+            }
+        }
+    }
+
+    public void onAppPicked(ResolveInfo info) {
+        final Intent intent = new Intent(getIntent());
+        intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+        intent.setComponent(new ComponentName(
+                info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
+        startActivityForResult(intent, CODE_FORWARD);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        Log.d(TAG, "onActivityResult() code=" + resultCode);
+
+        // Only relay back results when not canceled; otherwise stick around to
+        // let the user pick another app/backend.
+        if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) {
+
+            // Remember that we last picked via external app
+            final String packageName = getCallingPackage();
+            final ContentValues values = new ContentValues();
+            values.put(ResumeColumns.EXTERNAL, 1);
+            getContentResolver().insert(RecentsProvider.buildResume(packageName), values);
+
+            // Pass back result to original caller
+            setResult(resultCode, data);
+            finish();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    public void onDocumentPicked(DocumentInfo doc) {
+        final FragmentManager fm = getFragmentManager();
+        if (doc.isDirectory()) {
+            mState.stack.push(doc);
+            mState.stackTouched = true;
+            onCurrentDirectoryChanged(ANIM_DOWN);
+        } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
+            // Explicit file picked, return
+            new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor());
+        } else if (mState.action == ACTION_CREATE) {
+            // Replace selected file
+            SaveFragment.get(fm).setReplaceTarget(doc);
+        } else if (mState.action == ACTION_MANAGE) {
+            // First try managing the document; we expect manager to filter
+            // based on authority, so we don't grant.
+            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
+            manage.setData(doc.derivedUri);
+
+            try {
+                startActivity(manage);
+            } catch (ActivityNotFoundException ex) {
+                // Fall back to viewing
+                final Intent view = new Intent(Intent.ACTION_VIEW);
+                view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                view.setData(doc.derivedUri);
+
+                try {
+                    startActivity(view);
+                } catch (ActivityNotFoundException ex2) {
+                    Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+                }
+            }
+        }
+    }
+
+    public void onDocumentsPicked(List<DocumentInfo> docs) {
+        if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
+            final int size = docs.size();
+            final Uri[] uris = new Uri[size];
+            for (int i = 0; i < size; i++) {
+                uris[i] = docs.get(i).derivedUri;
+            }
+            new ExistingFinishTask(uris).executeOnExecutor(getCurrentExecutor());
+        }
+    }
+
+    public void onSaveRequested(DocumentInfo replaceTarget) {
+        new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
+    }
+
+    public void onSaveRequested(String mimeType, String displayName) {
+        new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
+    }
+
+    private void saveStackBlocking() {
+        final ContentResolver resolver = getContentResolver();
+        final ContentValues values = new ContentValues();
+
+        final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
+        if (mState.action == ACTION_CREATE) {
+            // Remember stack for last create
+            values.clear();
+            values.put(RecentColumns.KEY, mState.stack.buildKey());
+            values.put(RecentColumns.STACK, rawStack);
+            resolver.insert(RecentsProvider.buildRecent(), values);
+        }
+
+        // Remember location for next app launch
+        final String packageName = getCallingPackage();
+        values.clear();
+        values.put(ResumeColumns.STACK, rawStack);
+        values.put(ResumeColumns.EXTERNAL, 0);
+        resolver.insert(RecentsProvider.buildResume(packageName), values);
+    }
+
+    private void onFinished(Uri... uris) {
+        Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+
+        final Intent intent = new Intent();
+        if (uris.length == 1) {
+            intent.setData(uris[0]);
+        } else if (uris.length > 1) {
+            final ClipData clipData = new ClipData(
+                    null, mState.acceptMimes, new ClipData.Item(uris[0]));
+            for (int i = 1; i < uris.length; i++) {
+                clipData.addItem(new ClipData.Item(uris[i]));
+            }
+            intent.setClipData(clipData);
+        }
+
+        if (mState.action == ACTION_GET_CONTENT) {
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        } else {
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+        }
+
+        setResult(Activity.RESULT_OK, intent);
+        finish();
+    }
+
+    private class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
+        private final String mMimeType;
+        private final String mDisplayName;
+
+        public CreateFinishTask(String mimeType, String displayName) {
+            mMimeType = mimeType;
+            mDisplayName = displayName;
+        }
+
+        @Override
+        protected Uri doInBackground(Void... params) {
+            final ContentResolver resolver = getContentResolver();
+            final DocumentInfo cwd = getCurrentDirectory();
+
+            ContentProviderClient client = null;
+            Uri childUri = null;
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        resolver, cwd.derivedUri.getAuthority());
+                childUri = DocumentsContract.createDocument(
+                        client, cwd.derivedUri, mMimeType, mDisplayName);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to create document", e);
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+
+            if (childUri != null) {
+                saveStackBlocking();
+            }
+
+            return childUri;
+        }
+
+        @Override
+        protected void onPostExecute(Uri result) {
+            if (result != null) {
+                onFinished(result);
+            } else {
+                Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
+                        .show();
+            }
+        }
+    }
+
+    private class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
+        private final Uri[] mUris;
+
+        public ExistingFinishTask(Uri... uris) {
+            mUris = uris;
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            saveStackBlocking();
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            onFinished(mUris);
+        }
+    }
+
+    public static class State implements android.os.Parcelable {
+        public int action;
+        public String[] acceptMimes;
+
+        /** Explicit user choice */
+        public int userMode = MODE_UNKNOWN;
+        /** Derived after loader */
+        public int derivedMode = MODE_LIST;
+
+        /** Explicit user choice */
+        public int userSortOrder = SORT_ORDER_UNKNOWN;
+        /** Derived after loader */
+        public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+        public boolean allowMultiple = false;
+        public boolean showSize = false;
+        public boolean localOnly = false;
+        public boolean showAdvanced = false;
+        public boolean stackTouched = false;
+        public boolean restored = false;
+
+        /** Current user navigation stack; empty implies recents. */
+        public DocumentStack stack = new DocumentStack();
+        /** Currently active search, overriding any stack. */
+        public String currentSearch;
+
+        /** Instance state for every shown directory */
+        public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
+
+        public static final int ACTION_OPEN = 1;
+        public static final int ACTION_CREATE = 2;
+        public static final int ACTION_GET_CONTENT = 3;
+        public static final int ACTION_MANAGE = 4;
+
+        public static final int MODE_UNKNOWN = 0;
+        public static final int MODE_LIST = 1;
+        public static final int MODE_GRID = 2;
+
+        public static final int SORT_ORDER_UNKNOWN = 0;
+        public static final int SORT_ORDER_DISPLAY_NAME = 1;
+        public static final int SORT_ORDER_LAST_MODIFIED = 2;
+        public static final int SORT_ORDER_SIZE = 3;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(action);
+            out.writeInt(userMode);
+            out.writeStringArray(acceptMimes);
+            out.writeInt(userSortOrder);
+            out.writeInt(allowMultiple ? 1 : 0);
+            out.writeInt(showSize ? 1 : 0);
+            out.writeInt(localOnly ? 1 : 0);
+            out.writeInt(showAdvanced ? 1 : 0);
+            out.writeInt(stackTouched ? 1 : 0);
+            out.writeInt(restored ? 1 : 0);
+            DurableUtils.writeToParcel(out, stack);
+            out.writeString(currentSearch);
+            out.writeMap(dirState);
+        }
+
+        public static final Creator<State> CREATOR = new Creator<State>() {
+            @Override
+            public State createFromParcel(Parcel in) {
+                final State state = new State();
+                state.action = in.readInt();
+                state.userMode = in.readInt();
+                state.acceptMimes = in.readStringArray();
+                state.userSortOrder = in.readInt();
+                state.allowMultiple = in.readInt() != 0;
+                state.showSize = in.readInt() != 0;
+                state.localOnly = in.readInt() != 0;
+                state.showAdvanced = in.readInt() != 0;
+                state.stackTouched = in.readInt() != 0;
+                state.restored = in.readInt() != 0;
+                DurableUtils.readFromParcel(in, state.stack);
+                state.currentSearch = in.readString();
+                in.readMap(state.dirState, null);
+                return state;
+            }
+
+            @Override
+            public State[] newArray(int size) {
+                return new State[size];
+            }
+        };
+    }
+
+    private void dumpStack() {
+        Log.d(TAG, "Current stack: ");
+        Log.d(TAG, " * " + mState.stack.root);
+        for (DocumentInfo doc : mState.stack) {
+            Log.d(TAG, " +-- " + doc);
+        }
+    }
+
+    public static DocumentsActivity get(Fragment fragment) {
+        return (DocumentsActivity) fragment.getActivity();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
new file mode 100644
index 0000000..6b46e3a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
@@ -0,0 +1,109 @@
+/*
+ * 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.documentsui;
+
+import android.app.ActivityManager;
+import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.text.format.DateUtils;
+
+public class DocumentsApplication extends Application {
+    private static final long PROVIDER_ANR_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS;
+
+    private RootsCache mRoots;
+    private Point mThumbnailsSize;
+    private ThumbnailCache mThumbnails;
+
+    public static RootsCache getRootsCache(Context context) {
+        return ((DocumentsApplication) context.getApplicationContext()).mRoots;
+    }
+
+    public static ThumbnailCache getThumbnailsCache(Context context, Point size) {
+        final DocumentsApplication app = (DocumentsApplication) context.getApplicationContext();
+        final ThumbnailCache thumbnails = app.mThumbnails;
+        if (!size.equals(app.mThumbnailsSize)) {
+            thumbnails.evictAll();
+            app.mThumbnailsSize = size;
+        }
+        return thumbnails;
+    }
+
+    public static ContentProviderClient acquireUnstableProviderOrThrow(
+            ContentResolver resolver, String authority) throws RemoteException {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                authority);
+        if (client == null) {
+            throw new RemoteException("Failed to acquire provider for " + authority);
+        }
+        client.setDetectNotResponding(PROVIDER_ANR_TIMEOUT);
+        return client;
+    }
+
+    @Override
+    public void onCreate() {
+        final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+        final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024;
+
+        mRoots = new RootsCache(this);
+        mRoots.updateAsync();
+
+        mThumbnails = new ThumbnailCache(memoryClassBytes / 4);
+
+        final IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageFilter.addDataScheme("package");
+        registerReceiver(mCacheReceiver, packageFilter);
+
+        final IntentFilter localeFilter = new IntentFilter();
+        localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+        registerReceiver(mCacheReceiver, localeFilter);
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+
+        if (level >= TRIM_MEMORY_MODERATE) {
+            mThumbnails.evictAll();
+        } else if (level >= TRIM_MEMORY_BACKGROUND) {
+            mThumbnails.trimToSize(mThumbnails.size() / 2);
+        }
+    }
+
+    private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final Uri data = intent.getData();
+            if (data != null) {
+                final String packageName = data.getSchemeSpecificPart();
+                mRoots.updatePackageAsync(packageName);
+            } else {
+                mRoots.updateAsync();
+            }
+        }
+    };
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
new file mode 100644
index 0000000..52d816f
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -0,0 +1,136 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.database.AbstractCursor;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+/**
+ * Cursor wrapper that filters MIME types not matching given list.
+ */
+public class FilteringCursorWrapper extends AbstractCursor {
+    private final Cursor mCursor;
+
+    private final int[] mPosition;
+    private int mCount;
+
+    public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) {
+        this(cursor, acceptMimes, null, Long.MIN_VALUE);
+    }
+
+    public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes, String[] rejectMimes) {
+        this(cursor, acceptMimes, rejectMimes, Long.MIN_VALUE);
+    }
+
+    public FilteringCursorWrapper(
+            Cursor cursor, String[] acceptMimes, String[] rejectMimes, long rejectBefore) {
+        mCursor = cursor;
+
+        final int count = cursor.getCount();
+        mPosition = new int[count];
+
+        cursor.moveToPosition(-1);
+        while (cursor.moveToNext()) {
+            final String mimeType = cursor.getString(
+                    cursor.getColumnIndex(Document.COLUMN_MIME_TYPE));
+            final long lastModified = cursor.getLong(
+                    cursor.getColumnIndex(Document.COLUMN_LAST_MODIFIED));
+            if (rejectMimes != null && MimePredicate.mimeMatches(rejectMimes, mimeType)) {
+                continue;
+            }
+            if (lastModified < rejectBefore) {
+                continue;
+            }
+            if (MimePredicate.mimeMatches(acceptMimes, mimeType)) {
+                mPosition[mCount++] = cursor.getPosition();
+            }
+        }
+
+        Log.d(TAG, "Before filtering " + cursor.getCount() + ", after " + mCount);
+    }
+
+    @Override
+    public Bundle getExtras() {
+        return mCursor.getExtras();
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        mCursor.close();
+    }
+
+    @Override
+    public boolean onMove(int oldPosition, int newPosition) {
+        return mCursor.moveToPosition(mPosition[newPosition]);
+    }
+
+    @Override
+    public String[] getColumnNames() {
+        return mCursor.getColumnNames();
+    }
+
+    @Override
+    public int getCount() {
+        return mCount;
+    }
+
+    @Override
+    public double getDouble(int column) {
+        return mCursor.getDouble(column);
+    }
+
+    @Override
+    public float getFloat(int column) {
+        return mCursor.getFloat(column);
+    }
+
+    @Override
+    public int getInt(int column) {
+        return mCursor.getInt(column);
+    }
+
+    @Override
+    public long getLong(int column) {
+        return mCursor.getLong(column);
+    }
+
+    @Override
+    public short getShort(int column) {
+        return mCursor.getShort(column);
+    }
+
+    @Override
+    public String getString(int column) {
+        return mCursor.getString(column);
+    }
+
+    @Override
+    public int getType(int column) {
+        return mCursor.getType(column);
+    }
+
+    @Override
+    public boolean isNull(int column) {
+        return mCursor.isNull(column);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
new file mode 100644
index 0000000..1f7386c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -0,0 +1,264 @@
+/*
+ * 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.documentsui;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import com.google.android.collect.Maps;
+
+import java.util.HashMap;
+
+public class IconUtils {
+
+    private static HashMap<String, Integer> sMimeIcons = Maps.newHashMap();
+
+    private static void add(String mimeType, int resId) {
+        if (sMimeIcons.put(mimeType, resId) != null) {
+            throw new RuntimeException(mimeType + " already registered!");
+        }
+    }
+
+    static {
+        int icon;
+
+        // Package
+        icon = R.drawable.ic_doc_apk;
+        add("application/vnd.android.package-archive", icon);
+
+        // Audio
+        icon = R.drawable.ic_doc_audio;
+        add("application/ogg", icon);
+        add("application/x-flac", icon);
+
+        // Certificate
+        icon = R.drawable.ic_doc_certificate;
+        add("application/pgp-keys", icon);
+        add("application/pgp-signature", icon);
+        add("application/x-pkcs12", icon);
+        add("application/x-pkcs7-certreqresp", icon);
+        add("application/x-pkcs7-crl", icon);
+        add("application/x-x509-ca-cert", icon);
+        add("application/x-x509-user-cert", icon);
+        add("application/x-pkcs7-certificates", icon);
+        add("application/x-pkcs7-mime", icon);
+        add("application/x-pkcs7-signature", icon);
+
+        // Source code
+        icon = R.drawable.ic_doc_codes;
+        add("application/rdf+xml", icon);
+        add("application/rss+xml", icon);
+        add("application/x-object", icon);
+        add("application/xhtml+xml", icon);
+        add("text/css", icon);
+        add("text/html", icon);
+        add("text/xml", icon);
+        add("text/x-c++hdr", icon);
+        add("text/x-c++src", icon);
+        add("text/x-chdr", icon);
+        add("text/x-csrc", icon);
+        add("text/x-dsrc", icon);
+        add("text/x-csh", icon);
+        add("text/x-haskell", icon);
+        add("text/x-java", icon);
+        add("text/x-literate-haskell", icon);
+        add("text/x-pascal", icon);
+        add("text/x-tcl", icon);
+        add("text/x-tex", icon);
+        add("application/x-latex", icon);
+        add("application/x-texinfo", icon);
+        add("application/atom+xml", icon);
+        add("application/ecmascript", icon);
+        add("application/json", icon);
+        add("application/javascript", icon);
+        add("application/xml", icon);
+        add("text/javascript", icon);
+        add("application/x-javascript", icon);
+
+        // Compressed
+        icon = R.drawable.ic_doc_compressed;
+        add("application/mac-binhex40", icon);
+        add("application/rar", icon);
+        add("application/zip", icon);
+        add("application/x-apple-diskimage", icon);
+        add("application/x-debian-package", icon);
+        add("application/x-gtar", icon);
+        add("application/x-iso9660-image", icon);
+        add("application/x-lha", icon);
+        add("application/x-lzh", icon);
+        add("application/x-lzx", icon);
+        add("application/x-stuffit", icon);
+        add("application/x-tar", icon);
+        add("application/x-webarchive", icon);
+        add("application/x-webarchive-xml", icon);
+        add("application/gzip", icon);
+        add("application/x-7z-compressed", icon);
+        add("application/x-deb", icon);
+        add("application/x-rar-compressed", icon);
+
+        // Contact
+        icon = R.drawable.ic_doc_contact;
+        add("text/x-vcard", icon);
+        add("text/vcard", icon);
+
+        // Event
+        icon = R.drawable.ic_doc_event;
+        add("text/calendar", icon);
+        add("text/x-vcalendar", icon);
+
+        // Font
+        icon = R.drawable.ic_doc_font;
+        add("application/x-font", icon);
+        add("application/font-woff", icon);
+        add("application/x-font-woff", icon);
+        add("application/x-font-ttf", icon);
+
+        // Image
+        icon = R.drawable.ic_doc_image;
+        add("application/vnd.oasis.opendocument.graphics", icon);
+        add("application/vnd.oasis.opendocument.graphics-template", icon);
+        add("application/vnd.oasis.opendocument.image", icon);
+        add("application/vnd.stardivision.draw", icon);
+        add("application/vnd.sun.xml.draw", icon);
+        add("application/vnd.sun.xml.draw.template", icon);
+
+        // PDF
+        icon = R.drawable.ic_doc_pdf;
+        add("application/pdf", icon);
+
+        // Presentation
+        icon = R.drawable.ic_doc_presentation;
+        add("application/vnd.ms-powerpoint", icon);
+        add("application/vnd.openxmlformats-officedocument.presentationml.presentation", icon);
+        add("application/vnd.openxmlformats-officedocument.presentationml.template", icon);
+        add("application/vnd.openxmlformats-officedocument.presentationml.slideshow", icon);
+        add("application/vnd.stardivision.impress", icon);
+        add("application/vnd.sun.xml.impress", icon);
+        add("application/vnd.sun.xml.impress.template", icon);
+        add("application/x-kpresenter", icon);
+        add("application/vnd.oasis.opendocument.presentation", icon);
+
+        // Spreadsheet
+        icon = R.drawable.ic_doc_spreadsheet;
+        add("application/vnd.oasis.opendocument.spreadsheet", icon);
+        add("application/vnd.oasis.opendocument.spreadsheet-template", icon);
+        add("application/vnd.ms-excel", icon);
+        add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", icon);
+        add("application/vnd.openxmlformats-officedocument.spreadsheetml.template", icon);
+        add("application/vnd.stardivision.calc", icon);
+        add("application/vnd.sun.xml.calc", icon);
+        add("application/vnd.sun.xml.calc.template", icon);
+        add("application/x-kspread", icon);
+
+        // Text
+        icon = R.drawable.ic_doc_text;
+        add("application/vnd.oasis.opendocument.text", icon);
+        add("application/vnd.oasis.opendocument.text-master", icon);
+        add("application/vnd.oasis.opendocument.text-template", icon);
+        add("application/vnd.oasis.opendocument.text-web", icon);
+        add("application/msword", icon);
+        add("application/vnd.openxmlformats-officedocument.wordprocessingml.document", icon);
+        add("application/vnd.openxmlformats-officedocument.wordprocessingml.template", icon);
+        add("application/vnd.stardivision.writer", icon);
+        add("application/vnd.stardivision.writer-global", icon);
+        add("application/vnd.sun.xml.writer", icon);
+        add("application/vnd.sun.xml.writer.global", icon);
+        add("application/vnd.sun.xml.writer.template", icon);
+        add("application/x-abiword", icon);
+        add("application/x-kword", icon);
+
+        // Video
+        icon = R.drawable.ic_doc_video;
+        add("application/x-quicktimeplayer", icon);
+        add("application/x-shockwave-flash", icon);
+    }
+
+    public static Drawable loadPackageIcon(Context context, String authority, int icon) {
+        if (icon != 0) {
+            if (authority != null) {
+                final PackageManager pm = context.getPackageManager();
+                final ProviderInfo info = pm.resolveContentProvider(authority, 0);
+                if (info != null) {
+                    return pm.getDrawable(info.packageName, icon, info.applicationInfo);
+                }
+            } else {
+                return context.getResources().getDrawable(icon);
+            }
+        }
+        return null;
+    }
+
+    public static Drawable loadMimeIcon(
+            Context context, String mimeType, String authority, String docId, int mode) {
+        final Resources res = context.getResources();
+
+        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+            // TODO: eventually move these hacky assets into that package
+            if ("com.android.providers.media.documents".equals(authority)
+                    && docId.startsWith("album")) {
+                return res.getDrawable(R.drawable.ic_doc_album);
+            }
+
+            if (mode == DocumentsActivity.State.MODE_GRID) {
+                return res.getDrawable(R.drawable.ic_grid_folder);
+            } else {
+                return res.getDrawable(R.drawable.ic_root_folder);
+            }
+        }
+
+        return loadMimeIcon(context, mimeType);
+    }
+
+    public static Drawable loadMimeIcon(Context context, String mimeType) {
+        final Resources res = context.getResources();
+
+        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+            // TODO: return a mipmap, since this is used for grid
+            return res.getDrawable(R.drawable.ic_root_folder);
+        }
+
+        // Look for exact match first
+        Integer resId = sMimeIcons.get(mimeType);
+        if (resId != null) {
+            return res.getDrawable(resId);
+        }
+
+        if (mimeType == null) {
+            // TODO: generic icon?
+            return null;
+        }
+
+        // Otherwise look for partial match
+        final String typeOnly = mimeType.split("/")[0];
+        if ("audio".equals(typeOnly)) {
+            return res.getDrawable(R.drawable.ic_doc_audio);
+        } else if ("image".equals(typeOnly)) {
+            return res.getDrawable(R.drawable.ic_doc_image);
+        } else if ("text".equals(typeOnly)) {
+            return res.getDrawable(R.drawable.ic_doc_text);
+        } else if ("video".equals(typeOnly)) {
+            return res.getDrawable(R.drawable.ic_doc_video);
+        } else {
+            return res.getDrawable(R.drawable.ic_doc_generic);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
new file mode 100644
index 0000000..9df55a0
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -0,0 +1,95 @@
+/*
+ * 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.documentsui;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.internal.util.Predicate;
+
+public class MimePredicate implements Predicate<DocumentInfo> {
+    private final String[] mFilters;
+
+    /**
+     * MIME types that are visual in nature. For example, they should always be
+     * shown as thumbnails in list mode.
+     */
+    public static final String[] VISUAL_MIMES = new String[] { "image/*", "video/*" };
+
+    public MimePredicate(String[] filters) {
+        mFilters = filters;
+    }
+
+    @Override
+    public boolean apply(DocumentInfo doc) {
+        if (doc.isDirectory()) {
+            return true;
+        }
+        if (mimeMatches(mFilters, doc.mimeType)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean mimeMatches(String[] filters, String[] tests) {
+        if (tests == null) {
+            return false;
+        }
+        for (String test : tests) {
+            if (mimeMatches(filters, test)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean mimeMatches(String filter, String[] tests) {
+        if (tests == null) {
+            return true;
+        }
+        for (String test : tests) {
+            if (mimeMatches(filter, test)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean mimeMatches(String[] filters, String test) {
+        if (filters == null) {
+            return true;
+        }
+        for (String filter : filters) {
+            if (mimeMatches(filter, test)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean mimeMatches(String filter, String test) {
+        if (test == null) {
+            return false;
+        } else if (filter == null || "*/*".equals(filter)) {
+            return true;
+        } else if (filter.equals(test)) {
+            return true;
+        } else if (filter.endsWith("/*")) {
+            return filter.regionMatches(0, test, 0, filter.indexOf('/'));
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
new file mode 100644
index 0000000..2105cb41
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.documentsui;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.google.android.collect.Maps;
+
+import java.util.HashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ProviderExecutor extends Thread implements Executor {
+
+    @GuardedBy("sExecutors")
+    private static HashMap<String, ProviderExecutor> sExecutors = Maps.newHashMap();
+
+    public static Executor forAuthority(String authority) {
+        synchronized (sExecutors) {
+            ProviderExecutor executor = sExecutors.get(authority);
+            if (executor == null) {
+                executor = new ProviderExecutor();
+                executor.setName("ProviderExecutor: " + authority);
+                executor.start();
+                sExecutors.put(authority, executor);
+            }
+            return executor;
+        }
+    }
+
+    private final LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<Runnable>();
+
+    @Override
+    public void execute(Runnable command) {
+        Preconditions.checkNotNull(command);
+        mQueue.add(command);
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            try {
+                final Runnable command = mQueue.take();
+                command.run();
+            } catch (InterruptedException e) {
+                // That was weird; let's go look for more tasks.
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
new file mode 100644
index 0000000..3a8a3fb
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -0,0 +1,310 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
+
+import android.app.ActivityManager;
+import android.content.AsyncTaskLoader;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MergeCursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.model.RootInfo;
+import com.google.android.collect.Maps;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.AbstractFuture;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
+    private static final boolean LOGD = true;
+
+    private static final int MAX_OUTSTANDING_RECENTS = 4;
+    private static final int MAX_OUTSTANDING_RECENTS_SVELTE = 2;
+
+    /**
+     * Time to wait for first pass to complete before returning partial results.
+     */
+    private static final int MAX_FIRST_PASS_WAIT_MILLIS = 500;
+
+    /** Maximum documents from a single root. */
+    private static final int MAX_DOCS_FROM_ROOT = 64;
+
+    /** Ignore documents older than this age. */
+    private static final long REJECT_OLDER_THAN = 45 * DateUtils.DAY_IN_MILLIS;
+
+    /** MIME types that should always be excluded from recents. */
+    private static final String[] RECENT_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };
+
+    private final Semaphore mQueryPermits;
+
+    private final RootsCache mRoots;
+    private final State mState;
+
+    private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
+
+    private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
+
+    private CountDownLatch mFirstPassLatch;
+    private volatile boolean mFirstPassDone;
+
+    private DirectoryResult mResult;
+
+    // TODO: create better transfer of ownership around cursor to ensure its
+    // closed in all edge cases.
+
+    public class RecentTask extends AbstractFuture<Cursor> implements Runnable, Closeable {
+        public final String authority;
+        public final String rootId;
+
+        private Cursor mWithRoot;
+
+        public RecentTask(String authority, String rootId) {
+            this.authority = authority;
+            this.rootId = rootId;
+        }
+
+        @Override
+        public void run() {
+            if (isCancelled()) return;
+
+            try {
+                mQueryPermits.acquire();
+            } catch (InterruptedException e) {
+                return;
+            }
+
+            try {
+                runInternal();
+            } finally {
+                mQueryPermits.release();
+            }
+        }
+
+        public void runInternal() {
+            ContentProviderClient client = null;
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        getContext().getContentResolver(), authority);
+
+                final Uri uri = DocumentsContract.buildRecentDocumentsUri(authority, rootId);
+                final Cursor cursor = client.query(
+                        uri, null, null, null, DirectoryLoader.getQuerySortOrder(mSortOrder));
+                mWithRoot = new RootCursorWrapper(authority, rootId, cursor, MAX_DOCS_FROM_ROOT);
+
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to load " + authority + ", " + rootId, e);
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+
+            set(mWithRoot);
+
+            mFirstPassLatch.countDown();
+            if (mFirstPassDone) {
+                onContentChanged();
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            IoUtils.closeQuietly(mWithRoot);
+        }
+    }
+
+    public RecentLoader(Context context, RootsCache roots, State state) {
+        super(context);
+        mRoots = roots;
+        mState = state;
+
+        // Keep clients around on high-RAM devices, since we'd be spinning them
+        // up moments later to fetch thumbnails anyway.
+        final ActivityManager am = (ActivityManager) getContext().getSystemService(
+                Context.ACTIVITY_SERVICE);
+        mQueryPermits = new Semaphore(
+                am.isLowRamDevice() ? MAX_OUTSTANDING_RECENTS_SVELTE : MAX_OUTSTANDING_RECENTS);
+    }
+
+    @Override
+    public DirectoryResult loadInBackground() {
+        if (mFirstPassLatch == null) {
+            // First time through we kick off all the recent tasks, and wait
+            // around to see if everyone finishes quickly.
+
+            final Collection<RootInfo> roots = mRoots.getMatchingRootsBlocking(mState);
+            for (RootInfo root : roots) {
+                if ((root.flags & Root.FLAG_SUPPORTS_RECENTS) != 0) {
+                    final RecentTask task = new RecentTask(root.authority, root.rootId);
+                    mTasks.put(root, task);
+                }
+            }
+
+            mFirstPassLatch = new CountDownLatch(mTasks.size());
+            for (RecentTask task : mTasks.values()) {
+                ProviderExecutor.forAuthority(task.authority).execute(task);
+            }
+
+            try {
+                mFirstPassLatch.await(MAX_FIRST_PASS_WAIT_MILLIS, TimeUnit.MILLISECONDS);
+                mFirstPassDone = true;
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        final long rejectBefore = System.currentTimeMillis() - REJECT_OLDER_THAN;
+
+        // Collect all finished tasks
+        boolean allDone = true;
+        List<Cursor> cursors = Lists.newArrayList();
+        for (RecentTask task : mTasks.values()) {
+            if (task.isDone()) {
+                try {
+                    final Cursor cursor = task.get();
+                    if (cursor == null) continue;
+
+                    final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
+                            cursor, mState.acceptMimes, RECENT_REJECT_MIMES, rejectBefore) {
+                        @Override
+                        public void close() {
+                            // Ignored, since we manage cursor lifecycle internally
+                        }
+                    };
+                    cursors.add(filtered);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                } catch (ExecutionException e) {
+                    // We already logged on other side
+                }
+            } else {
+                allDone = false;
+            }
+        }
+
+        if (LOGD) {
+            Log.d(TAG, "Found " + cursors.size() + " of " + mTasks.size() + " recent queries done");
+        }
+
+        final DirectoryResult result = new DirectoryResult();
+        result.sortOrder = SORT_ORDER_LAST_MODIFIED;
+
+        // Hint to UI if we're still loading
+        final Bundle extras = new Bundle();
+        if (!allDone) {
+            extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
+        }
+
+        final Cursor merged;
+        if (cursors.size() > 0) {
+            merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
+        } else {
+            // Return something when nobody is ready
+            merged = new MatrixCursor(new String[0]);
+        }
+
+        final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder) {
+            @Override
+            public Bundle getExtras() {
+                return extras;
+            }
+        };
+
+        result.cursor = sorted;
+
+        return result;
+    }
+
+    @Override
+    public void cancelLoadInBackground() {
+        super.cancelLoadInBackground();
+    }
+
+    @Override
+    public void deliverResult(DirectoryResult result) {
+        if (isReset()) {
+            IoUtils.closeQuietly(result);
+            return;
+        }
+        DirectoryResult oldResult = mResult;
+        mResult = result;
+
+        if (isStarted()) {
+            super.deliverResult(result);
+        }
+
+        if (oldResult != null && oldResult != result) {
+            IoUtils.closeQuietly(oldResult);
+        }
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (mResult != null) {
+            deliverResult(mResult);
+        }
+        if (takeContentChanged() || mResult == null) {
+            forceLoad();
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        cancelLoad();
+    }
+
+    @Override
+    public void onCanceled(DirectoryResult result) {
+        IoUtils.closeQuietly(result);
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+
+        // Ensure the loader is stopped
+        onStopLoading();
+
+        for (RecentTask task : mTasks.values()) {
+            IoUtils.closeQuietly(task);
+        }
+
+        IoUtils.closeQuietly(mResult);
+        mResult = null;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
new file mode 100644
index 0000000..3954173
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -0,0 +1,260 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Loader;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils.TruncateAt;
+import android.text.style.ImageSpan;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.RecentColumns;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+import com.google.android.collect.Lists;
+
+import libcore.io.IoUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Display directories where recent creates took place.
+ */
+public class RecentsCreateFragment extends Fragment {
+
+    private View mEmptyView;
+    private ListView mListView;
+
+    private DocumentStackAdapter mAdapter;
+    private LoaderCallbacks<List<DocumentStack>> mCallbacks;
+
+    private static final int LOADER_RECENTS = 3;
+
+    public static void show(FragmentManager fm) {
+        final RecentsCreateFragment fragment = new RecentsCreateFragment();
+        final FragmentTransaction ft = fm.beginTransaction();
+        ft.replace(R.id.container_directory, fragment);
+        ft.commitAllowingStateLoss();
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        final Context context = inflater.getContext();
+
+        final View view = inflater.inflate(R.layout.fragment_directory, container, false);
+
+        mEmptyView = view.findViewById(android.R.id.empty);
+
+        mListView = (ListView) view.findViewById(R.id.list);
+        mListView.setOnItemClickListener(mItemListener);
+
+        mAdapter = new DocumentStackAdapter();
+        mListView.setAdapter(mAdapter);
+
+        final RootsCache roots = DocumentsApplication.getRootsCache(context);
+        final State state = ((DocumentsActivity) getActivity()).getDisplayState();
+
+        mCallbacks = new LoaderCallbacks<List<DocumentStack>>() {
+            @Override
+            public Loader<List<DocumentStack>> onCreateLoader(int id, Bundle args) {
+                return new RecentsCreateLoader(context, roots, state);
+            }
+
+            @Override
+            public void onLoadFinished(
+                    Loader<List<DocumentStack>> loader, List<DocumentStack> data) {
+                mAdapter.swapStacks(data);
+            }
+
+            @Override
+            public void onLoaderReset(Loader<List<DocumentStack>> loader) {
+                mAdapter.swapStacks(null);
+            }
+        };
+
+        return view;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        getLoaderManager().restartLoader(LOADER_RECENTS, getArguments(), mCallbacks);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        getLoaderManager().destroyLoader(LOADER_RECENTS);
+    }
+
+    private OnItemClickListener mItemListener = new OnItemClickListener() {
+        @Override
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            final DocumentStack stack = mAdapter.getItem(position);
+            ((DocumentsActivity) getActivity()).onStackPicked(stack);
+        }
+    };
+
+    public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> {
+        private final RootsCache mRoots;
+        private final State mState;
+
+        public RecentsCreateLoader(Context context, RootsCache roots, State state) {
+            super(context, RecentsProvider.buildRecent());
+            mRoots = roots;
+            mState = state;
+        }
+
+        @Override
+        public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) {
+            final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
+            final ArrayList<DocumentStack> result = Lists.newArrayList();
+
+            final ContentResolver resolver = getContext().getContentResolver();
+            final Cursor cursor = resolver.query(
+                    uri, null, null, null, RecentColumns.TIMESTAMP + " DESC", signal);
+            try {
+                while (cursor != null && cursor.moveToNext()) {
+                    final byte[] rawStack = cursor.getBlob(
+                            cursor.getColumnIndex(RecentColumns.STACK));
+                    try {
+                        final DocumentStack stack = new DocumentStack();
+                        DurableUtils.readFromArray(rawStack, stack);
+
+                        // Only update root here to avoid spinning up all
+                        // providers; we update the stack during the actual
+                        // restore. This also filters away roots that don't
+                        // match current filter.
+                        stack.updateRoot(matchingRoots);
+                        result.add(stack);
+                    } catch (IOException e) {
+                        Log.w(TAG, "Failed to resolve stack: " + e);
+                    }
+                }
+            } finally {
+                IoUtils.closeQuietly(cursor);
+            }
+
+            return result;
+        }
+    }
+
+    private class DocumentStackAdapter extends BaseAdapter {
+        private List<DocumentStack> mStacks;
+
+        public DocumentStackAdapter() {
+        }
+
+        public void swapStacks(List<DocumentStack> stacks) {
+            mStacks = stacks;
+
+            if (isEmpty()) {
+                mEmptyView.setVisibility(View.VISIBLE);
+            } else {
+                mEmptyView.setVisibility(View.GONE);
+            }
+
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final Context context = parent.getContext();
+
+            if (convertView == null) {
+                final LayoutInflater inflater = LayoutInflater.from(context);
+                convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
+            }
+
+            final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final View line2 = convertView.findViewById(R.id.line2);
+
+            final DocumentStack stack = getItem(position);
+            iconMime.setImageDrawable(stack.root.loadIcon(context));
+
+            final Drawable crumb = context.getResources()
+                    .getDrawable(R.drawable.ic_breadcrumb_arrow);
+            crumb.setBounds(0, 0, crumb.getIntrinsicWidth(), crumb.getIntrinsicHeight());
+
+            final SpannableStringBuilder builder = new SpannableStringBuilder();
+            builder.append(stack.root.title);
+            for (int i = stack.size() - 2; i >= 0; i--) {
+                appendDrawable(builder, crumb);
+                builder.append(stack.get(i).displayName);
+            }
+            title.setText(builder);
+            title.setEllipsize(TruncateAt.MIDDLE);
+
+            if (line2 != null) line2.setVisibility(View.GONE);
+
+            return convertView;
+        }
+
+        @Override
+        public int getCount() {
+            return mStacks != null ? mStacks.size() : 0;
+        }
+
+        @Override
+        public DocumentStack getItem(int position) {
+            return mStacks.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return getItem(position).hashCode();
+        }
+    }
+
+    private static void appendDrawable(SpannableStringBuilder b, Drawable d) {
+        final int length = b.length();
+        b.append("\u232a");
+        b.setSpan(new ImageSpan(d), length, b.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
new file mode 100644
index 0000000..4313fa7
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -0,0 +1,234 @@
+/*
+ * 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.documentsui;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+public class RecentsProvider extends ContentProvider {
+    private static final String TAG = "RecentsProvider";
+
+    public static final long MAX_HISTORY_IN_MILLIS = 45 * DateUtils.DAY_IN_MILLIS;
+
+    private static final String AUTHORITY = "com.android.documentsui.recents";
+
+    private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+    private static final int URI_RECENT = 1;
+    private static final int URI_STATE = 2;
+    private static final int URI_RESUME = 3;
+
+    static {
+        sMatcher.addURI(AUTHORITY, "recent", URI_RECENT);
+        // state/authority/rootId/docId
+        sMatcher.addURI(AUTHORITY, "state/*/*/*", URI_STATE);
+        // resume/packageName
+        sMatcher.addURI(AUTHORITY, "resume/*", URI_RESUME);
+    }
+
+    public static final String TABLE_RECENT = "recent";
+    public static final String TABLE_STATE = "state";
+    public static final String TABLE_RESUME = "resume";
+
+    public static class RecentColumns {
+        public static final String KEY = "key";
+        public static final String STACK = "stack";
+        public static final String TIMESTAMP = "timestamp";
+    }
+
+    public static class StateColumns {
+        public static final String AUTHORITY = "authority";
+        public static final String ROOT_ID = Root.COLUMN_ROOT_ID;
+        public static final String DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID;
+        public static final String MODE = "mode";
+        public static final String SORT_ORDER = "sortOrder";
+    }
+
+    public static class ResumeColumns {
+        public static final String PACKAGE_NAME = "package_name";
+        public static final String STACK = "stack";
+        public static final String TIMESTAMP = "timestamp";
+        public static final String EXTERNAL = "external";
+    }
+
+    public static Uri buildRecent() {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(AUTHORITY).appendPath("recent").build();
+    }
+
+    public static Uri buildState(String authority, String rootId, String documentId) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
+                .appendPath("state").appendPath(authority).appendPath(rootId).appendPath(documentId)
+                .build();
+    }
+
+    public static Uri buildResume(String packageName) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(AUTHORITY).appendPath("resume").appendPath(packageName).build();
+    }
+
+    private DatabaseHelper mHelper;
+
+    private static class DatabaseHelper extends SQLiteOpenHelper {
+        private static final String DB_NAME = "recents.db";
+
+        private static final int VERSION_INIT = 1;
+        private static final int VERSION_AS_BLOB = 3;
+        private static final int VERSION_ADD_EXTERNAL = 4;
+        private static final int VERSION_ADD_RECENT_KEY = 5;
+
+        public DatabaseHelper(Context context) {
+            super(context, DB_NAME, null, VERSION_ADD_RECENT_KEY);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+
+            db.execSQL("CREATE TABLE " + TABLE_RECENT + " (" +
+                    RecentColumns.KEY + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
+                    RecentColumns.STACK + " BLOB DEFAULT NULL," +
+                    RecentColumns.TIMESTAMP + " INTEGER" +
+                    ")");
+
+            db.execSQL("CREATE TABLE " + TABLE_STATE + " (" +
+                    StateColumns.AUTHORITY + " TEXT," +
+                    StateColumns.ROOT_ID + " TEXT," +
+                    StateColumns.DOCUMENT_ID + " TEXT," +
+                    StateColumns.MODE + " INTEGER," +
+                    StateColumns.SORT_ORDER + " INTEGER," +
+                    "PRIMARY KEY (" + StateColumns.AUTHORITY + ", " + StateColumns.ROOT_ID + ", "
+                    + StateColumns.DOCUMENT_ID + ")" +
+                    ")");
+
+            db.execSQL("CREATE TABLE " + TABLE_RESUME + " (" +
+                    ResumeColumns.PACKAGE_NAME + " TEXT NOT NULL PRIMARY KEY," +
+                    ResumeColumns.STACK + " BLOB DEFAULT NULL," +
+                    ResumeColumns.TIMESTAMP + " INTEGER," +
+                    ResumeColumns.EXTERNAL + " INTEGER NOT NULL DEFAULT 0" +
+                    ")");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.w(TAG, "Upgrading database; wiping app data");
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT);
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_STATE);
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_RESUME);
+            onCreate(db);
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        mHelper = new DatabaseHelper(getContext());
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        final SQLiteDatabase db = mHelper.getReadableDatabase();
+        switch (sMatcher.match(uri)) {
+            case URI_RECENT:
+                final long cutoff = System.currentTimeMillis() - MAX_HISTORY_IN_MILLIS;
+                return db.query(TABLE_RECENT, projection, RecentColumns.TIMESTAMP + ">" + cutoff,
+                        null, null, null, sortOrder);
+            case URI_STATE:
+                final String authority = uri.getPathSegments().get(1);
+                final String rootId = uri.getPathSegments().get(2);
+                final String documentId = uri.getPathSegments().get(3);
+                return db.query(TABLE_STATE, projection, StateColumns.AUTHORITY + "=? AND "
+                        + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
+                        new String[] { authority, rootId, documentId }, null, null, sortOrder);
+            case URI_RESUME:
+                final String packageName = uri.getPathSegments().get(1);
+                return db.query(TABLE_RESUME, projection, ResumeColumns.PACKAGE_NAME + "=?",
+                        new String[] { packageName }, null, null, sortOrder);
+            default:
+                throw new UnsupportedOperationException("Unsupported Uri " + uri);
+        }
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        final SQLiteDatabase db = mHelper.getWritableDatabase();
+        final ContentValues key = new ContentValues();
+        switch (sMatcher.match(uri)) {
+            case URI_RECENT:
+                values.put(RecentColumns.TIMESTAMP, System.currentTimeMillis());
+                db.insert(TABLE_RECENT, null, values);
+                final long cutoff = System.currentTimeMillis() - MAX_HISTORY_IN_MILLIS;
+                db.delete(TABLE_RECENT, RecentColumns.TIMESTAMP + "<" + cutoff, null);
+                return uri;
+            case URI_STATE:
+                final String authority = uri.getPathSegments().get(1);
+                final String rootId = uri.getPathSegments().get(2);
+                final String documentId = uri.getPathSegments().get(3);
+
+                key.put(StateColumns.AUTHORITY, authority);
+                key.put(StateColumns.ROOT_ID, rootId);
+                key.put(StateColumns.DOCUMENT_ID, documentId);
+
+                // Ensure that row exists, then update with changed values
+                db.insertWithOnConflict(TABLE_STATE, null, key, SQLiteDatabase.CONFLICT_IGNORE);
+                db.update(TABLE_STATE, values, StateColumns.AUTHORITY + "=? AND "
+                        + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
+                        new String[] { authority, rootId, documentId });
+
+                return uri;
+            case URI_RESUME:
+                values.put(ResumeColumns.TIMESTAMP, System.currentTimeMillis());
+
+                final String packageName = uri.getPathSegments().get(1);
+                key.put(ResumeColumns.PACKAGE_NAME, packageName);
+
+                // Ensure that row exists, then update with changed values
+                db.insertWithOnConflict(TABLE_RESUME, null, key, SQLiteDatabase.CONFLICT_IGNORE);
+                db.update(TABLE_RESUME, values, ResumeColumns.PACKAGE_NAME + "=?",
+                        new String[] { packageName });
+                return uri;
+            default:
+                throw new UnsupportedOperationException("Unsupported Uri " + uri);
+        }
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("Unsupported Uri " + uri);
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("Unsupported Uri " + uri);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/RootCursorWrapper.java
new file mode 100644
index 0000000..0b58218
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootCursorWrapper.java
@@ -0,0 +1,137 @@
+/*
+ * 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.documentsui;
+
+import android.database.AbstractCursor;
+import android.database.Cursor;
+import android.os.Bundle;
+
+/**
+ * Cursor wrapper that adds columns to identify which root a document came from.
+ */
+public class RootCursorWrapper extends AbstractCursor {
+    private final String mAuthority;
+    private final String mRootId;
+
+    private final Cursor mCursor;
+    private final int mCount;
+
+    private final String[] mColumnNames;
+
+    private final int mAuthorityIndex;
+    private final int mRootIdIndex;
+
+    public static final String COLUMN_AUTHORITY = "android:authority";
+    public static final String COLUMN_ROOT_ID = "android:rootId";
+
+    public RootCursorWrapper(String authority, String rootId, Cursor cursor, int maxCount) {
+        mAuthority = authority;
+        mRootId = rootId;
+        mCursor = cursor;
+
+        final int count = cursor.getCount();
+        if (maxCount > 0 && count > maxCount) {
+            mCount = maxCount;
+        } else {
+            mCount = count;
+        }
+
+        if (cursor.getColumnIndex(COLUMN_AUTHORITY) != -1
+                || cursor.getColumnIndex(COLUMN_ROOT_ID) != -1) {
+            throw new IllegalArgumentException("Cursor contains internal columns!");
+        }
+        final String[] before = cursor.getColumnNames();
+        mColumnNames = new String[before.length + 2];
+        System.arraycopy(before, 0, mColumnNames, 0, before.length);
+        mAuthorityIndex = before.length;
+        mRootIdIndex = before.length + 1;
+        mColumnNames[mAuthorityIndex] = COLUMN_AUTHORITY;
+        mColumnNames[mRootIdIndex] = COLUMN_ROOT_ID;
+    }
+
+    @Override
+    public Bundle getExtras() {
+        return mCursor.getExtras();
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        mCursor.close();
+    }
+
+    @Override
+    public boolean onMove(int oldPosition, int newPosition) {
+        return mCursor.moveToPosition(newPosition);
+    }
+
+    @Override
+    public String[] getColumnNames() {
+        return mColumnNames;
+    }
+
+    @Override
+    public int getCount() {
+        return mCount;
+    }
+
+    @Override
+    public double getDouble(int column) {
+        return mCursor.getDouble(column);
+    }
+
+    @Override
+    public float getFloat(int column) {
+        return mCursor.getFloat(column);
+    }
+
+    @Override
+    public int getInt(int column) {
+        return mCursor.getInt(column);
+    }
+
+    @Override
+    public long getLong(int column) {
+        return mCursor.getLong(column);
+    }
+
+    @Override
+    public short getShort(int column) {
+        return mCursor.getShort(column);
+    }
+
+    @Override
+    public String getString(int column) {
+        if (column == mAuthorityIndex) {
+            return mAuthority;
+        } else if (column == mRootIdIndex) {
+            return mRootId;
+        } else {
+            return mCursor.getString(column);
+        }
+    }
+
+    @Override
+    public int getType(int column) {
+        return mCursor.getType(column);
+    }
+
+    @Override
+    public boolean isNull(int column) {
+        return mCursor.isNull(column);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
new file mode 100644
index 0000000..bad0a96
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -0,0 +1,371 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Root;
+import android.util.Log;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.model.RootInfo;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Objects;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import libcore.io.IoUtils;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Cache of known storage backends and their roots.
+ */
+public class RootsCache {
+    private static final boolean LOGD = true;
+
+    // TODO: cache roots in local provider to avoid spinning up backends
+    // TODO: root updates should trigger UI refresh
+
+    private final Context mContext;
+    private final ContentObserver mObserver;
+
+    private final RootInfo mRecentsRoot = new RootInfo();
+
+    private final Object mLock = new Object();
+    private final CountDownLatch mFirstLoad = new CountDownLatch(1);
+
+    @GuardedBy("mLock")
+    private Multimap<String, RootInfo> mRoots = ArrayListMultimap.create();
+    @GuardedBy("mLock")
+    private HashSet<String> mStoppedAuthorities = Sets.newHashSet();
+
+    @GuardedBy("mObservedAuthorities")
+    private final HashSet<String> mObservedAuthorities = Sets.newHashSet();
+
+    public RootsCache(Context context) {
+        mContext = context;
+        mObserver = new RootsChangedObserver();
+    }
+
+    private class RootsChangedObserver extends ContentObserver {
+        public RootsChangedObserver() {
+            super(new Handler());
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (LOGD) Log.d(TAG, "Updating roots due to change at " + uri);
+            updateAuthorityAsync(uri.getAuthority());
+        }
+    }
+
+    /**
+     * Gather roots from all known storage providers.
+     */
+    public void updateAsync() {
+        // Special root for recents
+        mRecentsRoot.authority = null;
+        mRecentsRoot.rootId = null;
+        mRecentsRoot.icon = R.drawable.ic_root_recent;
+        mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE;
+        mRecentsRoot.title = mContext.getString(R.string.root_recent);
+        mRecentsRoot.availableBytes = -1;
+
+        new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    /**
+     * Gather roots from storage providers belonging to given package name.
+     */
+    public void updatePackageAsync(String packageName) {
+        // Need at least first load, since we're going to be using previously
+        // cached values for non-matching packages.
+        waitForFirstLoad();
+        new UpdateTask(packageName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    /**
+     * Gather roots from storage providers belonging to given authority.
+     */
+    public void updateAuthorityAsync(String authority) {
+        final ProviderInfo info = mContext.getPackageManager().resolveContentProvider(authority, 0);
+        if (info != null) {
+            updatePackageAsync(info.packageName);
+        }
+    }
+
+    private void waitForFirstLoad() {
+        boolean success = false;
+        try {
+            success = mFirstLoad.await(15, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+        }
+        if (!success) {
+            Log.w(TAG, "Timeout waiting for first update");
+        }
+    }
+
+    /**
+     * Load roots from authorities that are in stopped state. Normal
+     * {@link UpdateTask} passes ignore stopped applications.
+     */
+    private void loadStoppedAuthorities() {
+        final ContentResolver resolver = mContext.getContentResolver();
+        synchronized (mLock) {
+            for (String authority : mStoppedAuthorities) {
+                if (LOGD) Log.d(TAG, "Loading stopped authority " + authority);
+                mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+            }
+            mStoppedAuthorities.clear();
+        }
+    }
+
+    private class UpdateTask extends AsyncTask<Void, Void, Void> {
+        private final String mFilterPackage;
+
+        /**
+         * Update all roots.
+         */
+        public UpdateTask() {
+            this(null);
+        }
+
+        /**
+         * Only update roots belonging to given package name. Other roots will
+         * be copied from cached {@link #mRoots} values.
+         */
+        public UpdateTask(String filterPackage) {
+            mFilterPackage = filterPackage;
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            final long start = SystemClock.elapsedRealtime();
+
+            final Multimap<String, RootInfo> roots = ArrayListMultimap.create();
+            final HashSet<String> stoppedAuthorities = Sets.newHashSet();
+
+            roots.put(mRecentsRoot.authority, mRecentsRoot);
+
+            final ContentResolver resolver = mContext.getContentResolver();
+            final PackageManager pm = mContext.getPackageManager();
+            final List<ProviderInfo> providers = pm.queryContentProviders(
+                    null, -1, PackageManager.GET_META_DATA);
+            for (ProviderInfo info : providers) {
+                if (info.metaData != null && info.metaData.containsKey(
+                        DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
+                    // Ignore stopped packages for now; we might query them
+                    // later during UI interaction.
+                    if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+                        if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority);
+                        stoppedAuthorities.add(info.authority);
+                        continue;
+                    }
+
+                    // Try using cached roots if filtering
+                    boolean cacheHit = false;
+                    if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
+                        synchronized (mLock) {
+                            if (roots.putAll(info.authority, mRoots.get(info.authority))) {
+                                if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority);
+                                cacheHit = true;
+                            }
+                        }
+                    }
+
+                    // Cache miss, or loading everything
+                    if (!cacheHit) {
+                        roots.putAll(
+                                info.authority, loadRootsForAuthority(resolver, info.authority));
+                    }
+                }
+            }
+
+            final long delta = SystemClock.elapsedRealtime() - start;
+            Log.d(TAG, "Update found " + roots.size() + " roots in " + delta + "ms");
+            synchronized (mLock) {
+                mStoppedAuthorities = stoppedAuthorities;
+                mRoots = roots;
+            }
+            mFirstLoad.countDown();
+            return null;
+        }
+    }
+
+    /**
+     * Bring up requested provider and query for all active roots.
+     */
+    private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) {
+        if (LOGD) Log.d(TAG, "Loading roots for " + authority);
+
+        synchronized (mObservedAuthorities) {
+            if (mObservedAuthorities.add(authority)) {
+                // Watch for any future updates
+                final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
+                mContext.getContentResolver().registerContentObserver(rootsUri, true, mObserver);
+            }
+        }
+
+        final List<RootInfo> roots = Lists.newArrayList();
+        final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
+
+        ContentProviderClient client = null;
+        Cursor cursor = null;
+        try {
+            client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
+            cursor = client.query(rootsUri, null, null, null, null);
+            while (cursor.moveToNext()) {
+                final RootInfo root = RootInfo.fromRootsCursor(authority, cursor);
+                roots.add(root);
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to load some roots from " + authority + ": " + e);
+        } finally {
+            IoUtils.closeQuietly(cursor);
+            ContentProviderClient.releaseQuietly(client);
+        }
+        return roots;
+    }
+
+    /**
+     * Return the requested {@link RootInfo}, but only loading the roots for the
+     * requested authority. This is useful when we want to load fast without
+     * waiting for all the other roots to come back.
+     */
+    public RootInfo getRootOneshot(String authority, String rootId) {
+        synchronized (mLock) {
+            RootInfo root = getRootLocked(authority, rootId);
+            if (root == null) {
+                mRoots.putAll(
+                        authority, loadRootsForAuthority(mContext.getContentResolver(), authority));
+                root = getRootLocked(authority, rootId);
+            }
+            return root;
+        }
+    }
+
+    public RootInfo getRootBlocking(String authority, String rootId) {
+        waitForFirstLoad();
+        loadStoppedAuthorities();
+        synchronized (mLock) {
+            return getRootLocked(authority, rootId);
+        }
+    }
+
+    private RootInfo getRootLocked(String authority, String rootId) {
+        for (RootInfo root : mRoots.get(authority)) {
+            if (Objects.equal(root.rootId, rootId)) {
+                return root;
+            }
+        }
+        return null;
+    }
+
+    public boolean isIconUniqueBlocking(RootInfo root) {
+        waitForFirstLoad();
+        loadStoppedAuthorities();
+        synchronized (mLock) {
+            final int rootIcon = root.derivedIcon != 0 ? root.derivedIcon : root.icon;
+            for (RootInfo test : mRoots.get(root.authority)) {
+                if (Objects.equal(test.rootId, root.rootId)) {
+                    continue;
+                }
+                final int testIcon = test.derivedIcon != 0 ? test.derivedIcon : test.icon;
+                if (testIcon == rootIcon) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    public RootInfo getRecentsRoot() {
+        return mRecentsRoot;
+    }
+
+    public boolean isRecentsRoot(RootInfo root) {
+        return mRecentsRoot == root;
+    }
+
+    public Collection<RootInfo> getRootsBlocking() {
+        waitForFirstLoad();
+        loadStoppedAuthorities();
+        synchronized (mLock) {
+            return mRoots.values();
+        }
+    }
+
+    public Collection<RootInfo> getMatchingRootsBlocking(State state) {
+        waitForFirstLoad();
+        loadStoppedAuthorities();
+        synchronized (mLock) {
+            return getMatchingRoots(mRoots.values(), state);
+        }
+    }
+
+    @VisibleForTesting
+    static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
+        final List<RootInfo> matching = Lists.newArrayList();
+        for (RootInfo root : roots) {
+            final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 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;
+
+            // Exclude read-only devices when creating
+            if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
+            // Exclude advanced devices when not requested
+            if (!state.showAdvanced && advanced) continue;
+            // Exclude non-local devices when local only
+            if (state.localOnly && !localOnly) continue;
+            // Only show empty roots when creating
+            if (state.action != State.ACTION_CREATE && empty) continue;
+
+            // Only include roots that serve requested content
+            final boolean overlap =
+                    MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
+                    MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
+            if (!overlap) {
+                continue;
+            }
+
+            matching.add(root);
+        }
+        return matching;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
new file mode 100644
index 0000000..2fb12bb
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -0,0 +1,366 @@
+/*
+ * 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.documentsui;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.RootInfo;
+import com.android.internal.util.Objects;
+import com.google.common.collect.Lists;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Display list of known storage backend roots.
+ */
+public class RootsFragment extends Fragment {
+
+    private ListView mList;
+    private RootsAdapter mAdapter;
+
+    private LoaderCallbacks<Collection<RootInfo>> mCallbacks;
+
+    private static final String EXTRA_INCLUDE_APPS = "includeApps";
+
+    public static void show(FragmentManager fm, Intent includeApps) {
+        final Bundle args = new Bundle();
+        args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
+
+        final RootsFragment fragment = new RootsFragment();
+        fragment.setArguments(args);
+
+        final FragmentTransaction ft = fm.beginTransaction();
+        ft.replace(R.id.container_roots, fragment);
+        ft.commitAllowingStateLoss();
+    }
+
+    public static RootsFragment get(FragmentManager fm) {
+        return (RootsFragment) fm.findFragmentById(R.id.container_roots);
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        final Context context = inflater.getContext();
+
+        final View view = inflater.inflate(R.layout.fragment_roots, container, false);
+        mList = (ListView) view.findViewById(android.R.id.list);
+        mList.setOnItemClickListener(mItemListener);
+        mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+
+        return view;
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final Context context = getActivity();
+        final RootsCache roots = DocumentsApplication.getRootsCache(context);
+        final State state = ((DocumentsActivity) context).getDisplayState();
+
+        mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() {
+            @Override
+            public Loader<Collection<RootInfo>> onCreateLoader(int id, Bundle args) {
+                return new RootsLoader(context, roots, state);
+            }
+
+            @Override
+            public void onLoadFinished(
+                    Loader<Collection<RootInfo>> loader, Collection<RootInfo> result) {
+                if (!isAdded()) return;
+
+                final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
+
+                mAdapter = new RootsAdapter(context, result, includeApps);
+                mList.setAdapter(mAdapter);
+
+                onCurrentRootChanged();
+            }
+
+            @Override
+            public void onLoaderReset(Loader<Collection<RootInfo>> loader) {
+                mAdapter = null;
+                mList.setAdapter(null);
+            }
+        };
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        final Context context = getActivity();
+        final State state = ((DocumentsActivity) context).getDisplayState();
+        state.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(context);
+
+        getLoaderManager().restartLoader(2, null, mCallbacks);
+    }
+
+    public void onCurrentRootChanged() {
+        if (mAdapter == null) return;
+
+        final RootInfo root = ((DocumentsActivity) getActivity()).getCurrentRoot();
+        for (int i = 0; i < mAdapter.getCount(); i++) {
+            final Object item = mAdapter.getItem(i);
+            if (Objects.equal(item, root)) {
+                mList.setItemChecked(i, true);
+                return;
+            }
+        }
+    }
+
+    private OnItemClickListener mItemListener = new OnItemClickListener() {
+        @Override
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
+            final Item item = mAdapter.getItem(position);
+            if (item instanceof RootItem) {
+                activity.onRootPicked(((RootItem) item).root, true);
+            } else if (item instanceof AppItem) {
+                activity.onAppPicked(((AppItem) item).info);
+            } else {
+                throw new IllegalStateException("Unknown root: " + item);
+            }
+        }
+    };
+
+    private static abstract class Item {
+        private final int mLayoutId;
+
+        public Item(int layoutId) {
+            mLayoutId = layoutId;
+        }
+
+        public View getView(View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = LayoutInflater.from(parent.getContext())
+                        .inflate(mLayoutId, parent, false);
+            }
+            bindView(convertView);
+            return convertView;
+        }
+
+        public abstract void bindView(View convertView);
+    }
+
+    private static class RootItem extends Item {
+        public final RootInfo root;
+
+        public RootItem(RootInfo root) {
+            super(R.layout.item_root);
+            this.root = root;
+        }
+
+        @Override
+        public void bindView(View convertView) {
+            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
+
+            final Context context = convertView.getContext();
+            icon.setImageDrawable(root.loadIcon(context));
+            title.setText(root.title);
+
+            // Show available space if no summary
+            String summaryText = root.summary;
+            if (TextUtils.isEmpty(summaryText) && root.availableBytes >= 0) {
+                summaryText = context.getString(R.string.root_available_bytes,
+                        Formatter.formatFileSize(context, root.availableBytes));
+            }
+
+            summary.setText(summaryText);
+            summary.setVisibility(TextUtils.isEmpty(summaryText) ? View.GONE : View.VISIBLE);
+        }
+    }
+
+    private static class SpacerItem extends Item {
+        public SpacerItem() {
+            super(R.layout.item_root_spacer);
+        }
+
+        @Override
+        public void bindView(View convertView) {
+            // Nothing to bind
+        }
+    }
+
+    private static class AppItem extends Item {
+        public final ResolveInfo info;
+
+        public AppItem(ResolveInfo info) {
+            super(R.layout.item_root);
+            this.info = info;
+        }
+
+        @Override
+        public void bindView(View convertView) {
+            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
+
+            final PackageManager pm = convertView.getContext().getPackageManager();
+            icon.setImageDrawable(info.loadIcon(pm));
+            title.setText(info.loadLabel(pm));
+
+            // TODO: match existing summary behavior from disambig dialog
+            summary.setVisibility(View.GONE);
+        }
+    }
+
+    private static class RootsAdapter extends ArrayAdapter<Item> {
+        public RootsAdapter(Context context, Collection<RootInfo> roots, Intent includeApps) {
+            super(context, 0);
+
+            RootItem recents = null;
+            RootItem images = null;
+            RootItem videos = null;
+            RootItem audio = null;
+            RootItem downloads = null;
+
+            final List<RootInfo> clouds = Lists.newArrayList();
+            final List<RootInfo> locals = Lists.newArrayList();
+
+            for (RootInfo root : roots) {
+                if (root.isRecents()) {
+                    recents = new RootItem(root);
+                } else if (root.isExternalStorage()) {
+                    locals.add(root);
+                } else if (root.isDownloads()) {
+                    downloads = new RootItem(root);
+                } else if (root.isImages()) {
+                    images = new RootItem(root);
+                } else if (root.isVideos()) {
+                    videos = new RootItem(root);
+                } else if (root.isAudio()) {
+                    audio = new RootItem(root);
+                } else {
+                    clouds.add(root);
+                }
+            }
+
+            final RootComparator comp = new RootComparator();
+            Collections.sort(clouds, comp);
+            Collections.sort(locals, comp);
+
+            if (recents != null) add(recents);
+
+            for (RootInfo cloud : clouds) {
+                add(new RootItem(cloud));
+            }
+
+            if (images != null) add(images);
+            if (videos != null) add(videos);
+            if (audio != null) add(audio);
+            if (downloads != null) add(downloads);
+
+            for (RootInfo local : locals) {
+                add(new RootItem(local));
+            }
+
+            if (includeApps != null) {
+                final PackageManager pm = context.getPackageManager();
+                final List<ResolveInfo> infos = pm.queryIntentActivities(
+                        includeApps, PackageManager.MATCH_DEFAULT_ONLY);
+
+                final List<AppItem> apps = Lists.newArrayList();
+
+                // Omit ourselves from the list
+                for (ResolveInfo info : infos) {
+                    if (!context.getPackageName().equals(info.activityInfo.packageName)) {
+                        apps.add(new AppItem(info));
+                    }
+                }
+
+                if (apps.size() > 0) {
+                    add(new SpacerItem());
+                    for (Item item : apps) {
+                        add(item);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final Item item = getItem(position);
+            return item.getView(convertView, parent);
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return getItemViewType(position) != 1;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            final Item item = getItem(position);
+            if (item instanceof RootItem || item instanceof AppItem) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+    }
+
+    public static class RootComparator implements Comparator<RootInfo> {
+        @Override
+        public int compare(RootInfo lhs, RootInfo rhs) {
+            final int score = DocumentInfo.compareToIgnoreCaseNullable(lhs.title, rhs.title);
+            if (score != 0) {
+                return score;
+            } else {
+                return DocumentInfo.compareToIgnoreCaseNullable(lhs.summary, rhs.summary);
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
new file mode 100644
index 0000000..7108971
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -0,0 +1,81 @@
+/*
+ * 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.documentsui;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.model.RootInfo;
+
+import java.util.Collection;
+
+public class RootsLoader extends AsyncTaskLoader<Collection<RootInfo>> {
+    private final RootsCache mRoots;
+    private final State mState;
+
+    private Collection<RootInfo> mResult;
+
+    public RootsLoader(Context context, RootsCache roots, State state) {
+        super(context);
+        mRoots = roots;
+        mState = state;
+    }
+
+    @Override
+    public final Collection<RootInfo> loadInBackground() {
+        return mRoots.getMatchingRootsBlocking(mState);
+    }
+
+    @Override
+    public void deliverResult(Collection<RootInfo> result) {
+        if (isReset()) {
+            return;
+        }
+        Collection<RootInfo> oldResult = mResult;
+        mResult = result;
+
+        if (isStarted()) {
+            super.deliverResult(result);
+        }
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (mResult != null) {
+            deliverResult(mResult);
+        }
+        if (takeContentChanged() || mResult == null) {
+            forceLoad();
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        cancelLoad();
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+
+        // Ensure the loader is stopped
+        onStopLoading();
+
+        mResult = null;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
new file mode 100644
index 0000000..23e047c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -0,0 +1,143 @@
+/*
+ * 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.documentsui;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+
+import com.android.documentsui.model.DocumentInfo;
+
+/**
+ * Display document title editor and save button.
+ */
+public class SaveFragment extends Fragment {
+    public static final String TAG = "SaveFragment";
+
+    private DocumentInfo mReplaceTarget;
+    private EditText mDisplayName;
+    private Button mSave;
+    private boolean mIgnoreNextEdit;
+
+    private static final String EXTRA_MIME_TYPE = "mime_type";
+    private static final String EXTRA_DISPLAY_NAME = "display_name";
+
+    public static void show(FragmentManager fm, String mimeType, String displayName) {
+        final Bundle args = new Bundle();
+        args.putString(EXTRA_MIME_TYPE, mimeType);
+        args.putString(EXTRA_DISPLAY_NAME, displayName);
+
+        final SaveFragment fragment = new SaveFragment();
+        fragment.setArguments(args);
+
+        final FragmentTransaction ft = fm.beginTransaction();
+        ft.replace(R.id.container_save, fragment, TAG);
+        ft.commitAllowingStateLoss();
+    }
+
+    public static SaveFragment get(FragmentManager fm) {
+        return (SaveFragment) fm.findFragmentByTag(TAG);
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        final Context context = inflater.getContext();
+
+        final View view = inflater.inflate(R.layout.fragment_save, container, false);
+
+        final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
+        icon.setImageDrawable(
+                IconUtils.loadMimeIcon(context, getArguments().getString(EXTRA_MIME_TYPE)));
+
+        mDisplayName = (EditText) view.findViewById(android.R.id.title);
+        mDisplayName.addTextChangedListener(mDisplayNameWatcher);
+        mDisplayName.setText(getArguments().getString(EXTRA_DISPLAY_NAME));
+
+        mSave = (Button) view.findViewById(android.R.id.button1);
+        mSave.setOnClickListener(mSaveListener);
+        mSave.setEnabled(false);
+
+        return view;
+    }
+
+    private TextWatcher mDisplayNameWatcher = new TextWatcher() {
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            if (mIgnoreNextEdit) {
+                mIgnoreNextEdit = false;
+            } else {
+                Log.d(TAG, "onTextChanged!");
+                mReplaceTarget = null;
+            }
+        }
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            // ignored
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            // ignored
+        }
+    };
+
+    private View.OnClickListener mSaveListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this);
+            if (mReplaceTarget != null) {
+                activity.onSaveRequested(mReplaceTarget);
+            } else {
+                final String mimeType = getArguments().getString(EXTRA_MIME_TYPE);
+                final String displayName = mDisplayName.getText().toString();
+                activity.onSaveRequested(mimeType, displayName);
+            }
+        }
+    };
+
+    /**
+     * Set given document as target for in-place writing if user hits save
+     * without changing the filename. Can be set to {@code null} if user
+     * navigates outside the target directory.
+     */
+    public void setReplaceTarget(DocumentInfo replaceTarget) {
+        mReplaceTarget = replaceTarget;
+
+        if (mReplaceTarget != null) {
+            getArguments().putString(EXTRA_DISPLAY_NAME, replaceTarget.displayName);
+            mIgnoreNextEdit = true;
+            mDisplayName.setText(replaceTarget.displayName);
+        }
+    }
+
+    public void setSaveEnabled(boolean enabled) {
+        mSave.setEnabled(enabled);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
new file mode 100644
index 0000000..088e3fa
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
@@ -0,0 +1,166 @@
+/*
+ * 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.documentsui;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ListAdapter;
+
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+
+/**
+ * Adapter that combines multiple adapters as sections, asking each section to
+ * provide a header, and correctly handling item types across child adapters.
+ */
+public class SectionedListAdapter extends BaseAdapter {
+    private ArrayList<SectionAdapter> mSections = Lists.newArrayList();
+
+    public interface SectionAdapter extends ListAdapter {
+        public View getHeaderView(View convertView, ViewGroup parent);
+    }
+
+    public void clearSections() {
+        mSections.clear();
+        notifyDataSetChanged();
+    }
+
+    /**
+     * After mutating sections, you <em>must</em>
+     * {@link AdapterView#setAdapter(android.widget.Adapter)} to correctly
+     * recount view types.
+     */
+    public void addSection(SectionAdapter adapter) {
+        mSections.add(adapter);
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getCount() {
+        int count = 0;
+        final int size = mSections.size();
+        for (int i = 0; i < size; i++) {
+            count += mSections.get(i).getCount() + 1;
+        }
+        return count;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        final int size = mSections.size();
+        for (int i = 0; i < size; i++) {
+            final SectionAdapter section = mSections.get(i);
+            final int sectionSize = section.getCount() + 1;
+
+            // Check if position inside this section
+            if (position == 0) {
+                return section;
+            } else if (position < sectionSize) {
+                return section.getItem(position - 1);
+            }
+
+            // Otherwise jump into next section
+            position -= sectionSize;
+        }
+        throw new IllegalStateException("Unknown position " + position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        final int size = mSections.size();
+        for (int i = 0; i < size; i++) {
+            final SectionAdapter section = mSections.get(i);
+            final int sectionSize = section.getCount() + 1;
+
+            // Check if position inside this section
+            if (position == 0) {
+                return section.getHeaderView(convertView, parent);
+            } else if (position < sectionSize) {
+                return section.getView(position - 1, convertView, parent);
+            }
+
+            // Otherwise jump into next section
+            position -= sectionSize;
+        }
+        throw new IllegalStateException("Unknown position " + position);
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        final int size = mSections.size();
+        for (int i = 0; i < size; i++) {
+            final SectionAdapter section = mSections.get(i);
+            final int sectionSize = section.getCount() + 1;
+
+            // Check if position inside this section
+            if (position == 0) {
+                return false;
+            } else if (position < sectionSize) {
+                return section.isEnabled(position - 1);
+            }
+
+            // Otherwise jump into next section
+            position -= sectionSize;
+        }
+        throw new IllegalStateException("Unknown position " + position);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        int type = 1;
+        final int size = mSections.size();
+        for (int i = 0; i < size; i++) {
+            final SectionAdapter section = mSections.get(i);
+            final int sectionSize = section.getCount() + 1;
+
+            // Check if position inside this section
+            if (position == 0) {
+                return 0;
+            } else if (position < sectionSize) {
+                return type + section.getItemViewType(position - 1);
+            }
+
+            // Otherwise jump into next section
+            position -= sectionSize;
+            type += section.getViewTypeCount();
+        }
+        throw new IllegalStateException("Unknown position " + position);
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        int count = 1;
+        final int size = mSections.size();
+        for (int i = 0; i < size; i++) {
+            count += mSections.get(i).getViewTypeCount();
+        }
+        return count;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
new file mode 100644
index 0000000..d423e3f
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
@@ -0,0 +1,71 @@
+/*
+ * 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.documentsui;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.view.MenuItem;
+
+public class SettingsActivity extends Activity {
+    private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
+    private static final String KEY_FILE_SIZE = "fileSize";
+
+    public static boolean getDisplayAdvancedDevices(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context)
+                .getBoolean(KEY_ADVANCED_DEVICES, false);
+    }
+
+    public static boolean getDisplayFileSize(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context)
+                .getBoolean(KEY_FILE_SIZE, false);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getFragmentManager()
+                .beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
+
+        final ActionBar bar = getActionBar();
+        if (bar != null) {
+            bar.setDisplayShowHomeEnabled(false);
+            bar.setDisplayHomeAsUpEnabled(true);
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == android.R.id.home) {
+            finish();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    public static class SettingsFragment extends PreferenceFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            addPreferencesFromResource(R.xml.preferences);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
new file mode 100644
index 0000000..19ad2e2
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -0,0 +1,262 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
+
+import android.database.AbstractCursor;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.DocumentsContract.Document;
+
+/**
+ * Cursor wrapper that presents a sorted view of the underlying cursor. Handles
+ * common {@link Document} sorting modes, such as ordering directories first.
+ */
+public class SortingCursorWrapper extends AbstractCursor {
+    private final Cursor mCursor;
+
+    private final int[] mPosition;
+    private final String[] mValueString;
+    private final long[] mValueLong;
+
+    public SortingCursorWrapper(Cursor cursor, int sortOrder) {
+        mCursor = cursor;
+
+        final int count = cursor.getCount();
+        mPosition = new int[count];
+        switch (sortOrder) {
+            case SORT_ORDER_DISPLAY_NAME:
+                mValueString = new String[count];
+                mValueLong = null;
+                break;
+            case SORT_ORDER_LAST_MODIFIED:
+            case SORT_ORDER_SIZE:
+                mValueString = null;
+                mValueLong = new long[count];
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+
+        cursor.moveToPosition(-1);
+        for (int i = 0; i < count; i++) {
+            cursor.moveToNext();
+            mPosition[i] = i;
+
+            switch (sortOrder) {
+                case SORT_ORDER_DISPLAY_NAME:
+                    final String mimeType = cursor.getString(
+                            cursor.getColumnIndex(Document.COLUMN_MIME_TYPE));
+                    final String displayName = cursor.getString(
+                            cursor.getColumnIndex(Document.COLUMN_DISPLAY_NAME));
+                    if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+                        mValueString[i] = '\001' + displayName;
+                    } else {
+                        mValueString[i] = displayName;
+                    }
+                    break;
+                case SORT_ORDER_LAST_MODIFIED:
+                    mValueLong[i] = cursor.getLong(
+                            cursor.getColumnIndex(Document.COLUMN_LAST_MODIFIED));
+                    break;
+                case SORT_ORDER_SIZE:
+                    mValueLong[i] = cursor.getLong(cursor.getColumnIndex(Document.COLUMN_SIZE));
+                    break;
+            }
+        }
+
+        switch (sortOrder) {
+            case SORT_ORDER_DISPLAY_NAME:
+                synchronized (SortingCursorWrapper.class) {
+
+                    binarySort(mPosition, mValueString);
+                }
+                break;
+            case SORT_ORDER_LAST_MODIFIED:
+            case SORT_ORDER_SIZE:
+                binarySort(mPosition, mValueLong);
+                break;
+        }
+    }
+
+    @Override
+    public Bundle getExtras() {
+        return mCursor.getExtras();
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        mCursor.close();
+    }
+
+    @Override
+    public boolean onMove(int oldPosition, int newPosition) {
+        return mCursor.moveToPosition(mPosition[newPosition]);
+    }
+
+    @Override
+    public String[] getColumnNames() {
+        return mCursor.getColumnNames();
+    }
+
+    @Override
+    public int getCount() {
+        return mCursor.getCount();
+    }
+
+    @Override
+    public double getDouble(int column) {
+        return mCursor.getDouble(column);
+    }
+
+    @Override
+    public float getFloat(int column) {
+        return mCursor.getFloat(column);
+    }
+
+    @Override
+    public int getInt(int column) {
+        return mCursor.getInt(column);
+    }
+
+    @Override
+    public long getLong(int column) {
+        return mCursor.getLong(column);
+    }
+
+    @Override
+    public short getShort(int column) {
+        return mCursor.getShort(column);
+    }
+
+    @Override
+    public String getString(int column) {
+        return mCursor.getString(column);
+    }
+
+    @Override
+    public int getType(int column) {
+        return mCursor.getType(column);
+    }
+
+    @Override
+    public boolean isNull(int column) {
+        return mCursor.isNull(column);
+    }
+
+    /**
+     * Borrowed from TimSort.binarySort(), but modified to sort two column
+     * dataset.
+     */
+    private static void binarySort(int[] position, String[] value) {
+        final int count = position.length;
+        for (int start = 1; start < count; start++) {
+            final int pivotPosition = position[start];
+            final String pivotValue = value[start];
+
+            int left = 0;
+            int right = start;
+
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+
+                final String lhs = pivotValue;
+                final String rhs = value[mid];
+                final int compare;
+                if (lhs == null) {
+                    compare = -1;
+                } else if (rhs == null) {
+                    compare = 1;
+                } else {
+                    compare = lhs.compareToIgnoreCase(rhs);
+                }
+
+                if (compare < 0) {
+                    right = mid;
+                } else {
+                    left = mid + 1;
+                }
+            }
+
+            int n = start - left;
+            switch (n) {
+                case 2:
+                    position[left + 2] = position[left + 1];
+                    value[left + 2] = value[left + 1];
+                case 1:
+                    position[left + 1] = position[left];
+                    value[left + 1] = value[left];
+                    break;
+                default:
+                    System.arraycopy(position, left, position, left + 1, n);
+                    System.arraycopy(value, left, value, left + 1, n);
+            }
+
+            position[left] = pivotPosition;
+            value[left] = pivotValue;
+        }
+    }
+
+    /**
+     * Borrowed from TimSort.binarySort(), but modified to sort two column
+     * dataset.
+     */
+    private static void binarySort(int[] position, long[] value) {
+        final int count = position.length;
+        for (int start = 1; start < count; start++) {
+            final int pivotPosition = position[start];
+            final long pivotValue = value[start];
+
+            int left = 0;
+            int right = start;
+
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+
+                final long lhs = pivotValue;
+                final long rhs = value[mid];
+                final int compare = Long.compare(lhs, rhs);
+                if (compare > 0) {
+                    right = mid;
+                } else {
+                    left = mid + 1;
+                }
+            }
+
+            int n = start - left;
+            switch (n) {
+                case 2:
+                    position[left + 2] = position[left + 1];
+                    value[left + 2] = value[left + 1];
+                case 1:
+                    position[left + 1] = position[left];
+                    value[left + 1] = value[left];
+                    break;
+                default:
+                    System.arraycopy(position, left, position, left + 1, n);
+                    System.arraycopy(value, left, value, left + 1, n);
+            }
+
+            position[left] = pivotPosition;
+            value[left] = pivotValue;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
new file mode 100644
index 0000000..1a47308
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
@@ -0,0 +1,268 @@
+/*
+ * 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.documentsui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class TestActivity extends Activity {
+    private static final String TAG = "TestActivity";
+
+    private static final int CODE_READ = 42;
+    private static final int CODE_WRITE = 43;
+
+    private TextView mResult;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final Context context = this;
+
+        final LinearLayout view = new LinearLayout(context);
+        view.setOrientation(LinearLayout.VERTICAL);
+
+        mResult = new TextView(context);
+        view.addView(mResult);
+
+        final CheckBox multiple = new CheckBox(context);
+        multiple.setText("ALLOW_MULTIPLE");
+        view.addView(multiple);
+        final CheckBox localOnly = new CheckBox(context);
+        localOnly.setText("LOCAL_ONLY");
+        view.addView(localOnly);
+
+        Button button;
+        button = new Button(context);
+        button.setText("OPEN_DOC */*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("OPEN_DOC image/*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("image/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("OPEN_DOC audio/ogg");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("audio/ogg");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("OPEN_DOC text/plain, application/msword");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
+                        "text/plain", "application/msword" });
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("CREATE_DOC text/plain");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("text/plain");
+                intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_WRITE);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("CREATE_DOC image/png");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("image/png");
+                intent.putExtra(Intent.EXTRA_TITLE, "mypicture.png");
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_WRITE);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("GET_CONTENT */*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        final ScrollView scroll = new ScrollView(context);
+        scroll.addView(view);
+
+        setContentView(scroll);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        mResult.setText(null);
+        String result = "resultCode=" + resultCode + ", data=" + String.valueOf(data);
+
+        if (requestCode == CODE_READ) {
+            final Uri uri = data != null ? data.getData() : null;
+            if (uri != null) {
+                if (DocumentsContract.isDocumentUri(this, uri)) {
+                    result += "; DOC_ID";
+                }
+                try {
+                    getContentResolver().takePersistableUriPermission(
+                            uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                } catch (SecurityException e) {
+                    result += "; FAILED TO TAKE";
+                    Log.e(TAG, "Failed to take", e);
+                }
+                InputStream is = null;
+                try {
+                    is = getContentResolver().openInputStream(uri);
+                    final int length = Streams.readFullyNoClose(is).length;
+                    result += "; read length=" + length;
+                } catch (Exception e) {
+                    result += "; ERROR";
+                    Log.e(TAG, "Failed to read " + uri, e);
+                } finally {
+                    IoUtils.closeQuietly(is);
+                }
+            } else {
+                result += "no uri?";
+            }
+        } else if (requestCode == CODE_WRITE) {
+            final Uri uri = data != null ? data.getData() : null;
+            if (uri != null) {
+                if (DocumentsContract.isDocumentUri(this, uri)) {
+                    result += "; DOC_ID";
+                }
+                try {
+                    getContentResolver().takePersistableUriPermission(
+                            uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                } catch (SecurityException e) {
+                    result += "; FAILED TO TAKE";
+                    Log.e(TAG, "Failed to take", e);
+                }
+                OutputStream os = null;
+                try {
+                    os = getContentResolver().openOutputStream(uri);
+                    os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
+                } catch (Exception e) {
+                    result += "; ERROR";
+                    Log.e(TAG, "Failed to write " + uri, e);
+                } finally {
+                    IoUtils.closeQuietly(os);
+                }
+            } else {
+                result += "no uri?";
+            }
+        }
+
+        Log.d(TAG, result);
+        mResult.setText(result);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java b/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java
new file mode 100644
index 0000000..ad7cbf6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java
@@ -0,0 +1,32 @@
+/*
+ * 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.documentsui;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.util.LruCache;
+
+public class ThumbnailCache extends LruCache<Uri, Bitmap> {
+    public ThumbnailCache(int maxSizeBytes) {
+        super(maxSizeBytes);
+    }
+
+    @Override
+    protected int sizeOf(Uri key, Bitmap value) {
+        return value.getByteCount();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
new file mode 100644
index 0000000..1a5bb0c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
@@ -0,0 +1,135 @@
+/*
+ * 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.documentsui;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+
+/**
+ * Loader that derives its data from a Uri. Watches for {@link ContentObserver}
+ * changes while started, manages {@link CancellationSignal}, and caches
+ * returned results.
+ */
+public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
+    final ForceLoadContentObserver mObserver;
+
+    private final P mParam;
+
+    private R mResult;
+    private CancellationSignal mCancellationSignal;
+
+    @Override
+    public final R loadInBackground() {
+        synchronized (this) {
+            if (isLoadInBackgroundCanceled()) {
+                throw new OperationCanceledException();
+            }
+            mCancellationSignal = new CancellationSignal();
+        }
+        try {
+            return loadInBackground(mParam, mCancellationSignal);
+        } finally {
+            synchronized (this) {
+                mCancellationSignal = null;
+            }
+        }
+    }
+
+    public abstract R loadInBackground(P param, CancellationSignal signal);
+
+    @Override
+    public void cancelLoadInBackground() {
+        super.cancelLoadInBackground();
+
+        synchronized (this) {
+            if (mCancellationSignal != null) {
+                mCancellationSignal.cancel();
+            }
+        }
+    }
+
+    @Override
+    public void deliverResult(R result) {
+        if (isReset()) {
+            closeQuietly(result);
+            return;
+        }
+        R oldResult = mResult;
+        mResult = result;
+
+        if (isStarted()) {
+            super.deliverResult(result);
+        }
+
+        if (oldResult != null && oldResult != result) {
+            closeQuietly(oldResult);
+        }
+    }
+
+    public UriDerivativeLoader(Context context, P param) {
+        super(context);
+        mObserver = new ForceLoadContentObserver();
+        mParam = param;
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (mResult != null) {
+            deliverResult(mResult);
+        }
+        if (takeContentChanged() || mResult == null) {
+            forceLoad();
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        cancelLoad();
+    }
+
+    @Override
+    public void onCanceled(R result) {
+        closeQuietly(result);
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+
+        // Ensure the loader is stopped
+        onStopLoading();
+
+        closeQuietly(mResult);
+        mResult = null;
+
+        getContext().getContentResolver().unregisterContentObserver(mObserver);
+    }
+
+    private void closeQuietly(R result) {
+        if (result instanceof AutoCloseable) {
+            try {
+                ((AutoCloseable) result).close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
new file mode 100644
index 0000000..91d9124
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -0,0 +1,276 @@
+/*
+ * 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.documentsui.model;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsProvider;
+
+import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.RootCursorWrapper;
+
+import libcore.io.IoUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.ProtocolException;
+
+/**
+ * Representation of a {@link Document}.
+ */
+public class DocumentInfo implements Durable, Parcelable {
+    private static final int VERSION_INIT = 1;
+    private static final int VERSION_SPLIT_URI = 2;
+
+    public String authority;
+    public String documentId;
+    public String mimeType;
+    public String displayName;
+    public long lastModified;
+    public int flags;
+    public String summary;
+    public long size;
+    public int icon;
+
+    /** Derived fields that aren't persisted */
+    public Uri derivedUri;
+
+    public DocumentInfo() {
+        reset();
+    }
+
+    @Override
+    public void reset() {
+        authority = null;
+        documentId = null;
+        mimeType = null;
+        displayName = null;
+        lastModified = -1;
+        flags = 0;
+        summary = null;
+        size = -1;
+        icon = 0;
+
+        derivedUri = null;
+    }
+
+    @Override
+    public void read(DataInputStream in) throws IOException {
+        final int version = in.readInt();
+        switch (version) {
+            case VERSION_INIT:
+                throw new ProtocolException("Ignored upgrade");
+            case VERSION_SPLIT_URI:
+                authority = DurableUtils.readNullableString(in);
+                documentId = DurableUtils.readNullableString(in);
+                mimeType = DurableUtils.readNullableString(in);
+                displayName = DurableUtils.readNullableString(in);
+                lastModified = in.readLong();
+                flags = in.readInt();
+                summary = DurableUtils.readNullableString(in);
+                size = in.readLong();
+                icon = in.readInt();
+                deriveFields();
+                break;
+            default:
+                throw new ProtocolException("Unknown version " + version);
+        }
+    }
+
+    @Override
+    public void write(DataOutputStream out) throws IOException {
+        out.writeInt(VERSION_SPLIT_URI);
+        DurableUtils.writeNullableString(out, authority);
+        DurableUtils.writeNullableString(out, documentId);
+        DurableUtils.writeNullableString(out, mimeType);
+        DurableUtils.writeNullableString(out, displayName);
+        out.writeLong(lastModified);
+        out.writeInt(flags);
+        DurableUtils.writeNullableString(out, summary);
+        out.writeLong(size);
+        out.writeInt(icon);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        DurableUtils.writeToParcel(dest, this);
+    }
+
+    public static final Creator<DocumentInfo> CREATOR = new Creator<DocumentInfo>() {
+        @Override
+        public DocumentInfo createFromParcel(Parcel in) {
+            final DocumentInfo doc = new DocumentInfo();
+            DurableUtils.readFromParcel(in, doc);
+            return doc;
+        }
+
+        @Override
+        public DocumentInfo[] newArray(int size) {
+            return new DocumentInfo[size];
+        }
+    };
+
+    public static DocumentInfo fromDirectoryCursor(Cursor cursor) {
+        final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+        return fromCursor(cursor, authority);
+    }
+
+    public static DocumentInfo fromCursor(Cursor cursor, String authority) {
+        final DocumentInfo info = new DocumentInfo();
+        info.updateFromCursor(cursor, authority);
+        return info;
+    }
+
+    public void updateFromCursor(Cursor cursor, String authority) {
+        this.authority = authority;
+        this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+        this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+        this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        this.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+        this.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+        this.flags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+        this.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
+        this.size = getCursorLong(cursor, Document.COLUMN_SIZE);
+        this.icon = getCursorInt(cursor, Document.COLUMN_ICON);
+        this.deriveFields();
+    }
+
+    public static DocumentInfo fromUri(ContentResolver resolver, Uri uri)
+            throws FileNotFoundException {
+        final DocumentInfo info = new DocumentInfo();
+        info.updateFromUri(resolver, uri);
+        return info;
+    }
+
+    /**
+     * Update a possibly stale restored document against a live
+     * {@link DocumentsProvider}.
+     */
+    public void updateSelf(ContentResolver resolver) throws FileNotFoundException {
+        updateFromUri(resolver, derivedUri);
+    }
+
+    public void updateFromUri(ContentResolver resolver, Uri uri) throws FileNotFoundException {
+        ContentProviderClient client = null;
+        Cursor cursor = null;
+        try {
+            client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                    resolver, uri.getAuthority());
+            cursor = client.query(uri, null, null, null, null);
+            if (!cursor.moveToFirst()) {
+                throw new FileNotFoundException("Missing details for " + uri);
+            }
+            updateFromCursor(cursor, uri.getAuthority());
+        } catch (Throwable t) {
+            throw asFileNotFoundException(t);
+        } finally {
+            IoUtils.closeQuietly(cursor);
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    private void deriveFields() {
+        derivedUri = DocumentsContract.buildDocumentUri(authority, documentId);
+    }
+
+    @Override
+    public String toString() {
+        return "Document{docId=" + documentId + ", name=" + displayName + "}";
+    }
+
+    public boolean isCreateSupported() {
+        return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
+    }
+
+    public boolean isThumbnailSupported() {
+        return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+    }
+
+    public boolean isDirectory() {
+        return Document.MIME_TYPE_DIR.equals(mimeType);
+    }
+
+    public boolean isGridPreferred() {
+        return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0;
+    }
+
+    public boolean isDeleteSupported() {
+        return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
+    }
+
+    public boolean isGridTitlesHidden() {
+        return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
+    }
+
+    public static String getCursorString(Cursor cursor, String columnName) {
+        final int index = cursor.getColumnIndex(columnName);
+        return (index != -1) ? cursor.getString(index) : null;
+    }
+
+    /**
+     * Missing or null values are returned as -1.
+     */
+    public static long getCursorLong(Cursor cursor, String columnName) {
+        final int index = cursor.getColumnIndex(columnName);
+        if (index == -1) return -1;
+        final String value = cursor.getString(index);
+        if (value == null) return -1;
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Missing or null values are returned as 0.
+     */
+    public static int getCursorInt(Cursor cursor, String columnName) {
+        final int index = cursor.getColumnIndex(columnName);
+        return (index != -1) ? cursor.getInt(index) : 0;
+    }
+
+    public static FileNotFoundException asFileNotFoundException(Throwable t)
+            throws FileNotFoundException {
+        if (t instanceof FileNotFoundException) {
+            throw (FileNotFoundException) t;
+        }
+        final FileNotFoundException fnfe = new FileNotFoundException(t.getMessage());
+        fnfe.initCause(t);
+        throw fnfe;
+    }
+
+    public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
+        if (lhs == null) return -1;
+        if (rhs == null) return 1;
+        return lhs.compareToIgnoreCase(rhs);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
new file mode 100644
index 0000000..28bab6c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -0,0 +1,138 @@
+/*
+ * 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.documentsui.model;
+
+import android.content.ContentResolver;
+import android.provider.DocumentsProvider;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * Representation of a stack of {@link DocumentInfo}, usually the result of a
+ * user-driven traversal.
+ */
+public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
+    private static final int VERSION_INIT = 1;
+    private static final int VERSION_ADD_ROOT = 2;
+
+    public RootInfo root;
+
+    public String getTitle() {
+        if (size() == 1 && root != null) {
+            return root.title;
+        } else if (size() > 1) {
+            return peek().displayName;
+        } else {
+            return null;
+        }
+    }
+
+    public boolean isRecents() {
+        return size() == 0;
+    }
+
+    public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException {
+        for (RootInfo root : matchingRoots) {
+            if (root.equals(this.root)) {
+                this.root = root;
+                return;
+            }
+        }
+        throw new FileNotFoundException("Failed to find matching root for " + root);
+    }
+
+    /**
+     * Update a possibly stale restored stack against a live
+     * {@link DocumentsProvider}.
+     */
+    public void updateDocuments(ContentResolver resolver) throws FileNotFoundException {
+        for (DocumentInfo info : this) {
+            info.updateSelf(resolver);
+        }
+    }
+
+    /**
+     * Build key that uniquely identifies this stack. It omits most of the raw
+     * details included in {@link #write(DataOutputStream)}, since they change
+     * too regularly to be used as a key.
+     */
+    public String buildKey() {
+        final StringBuilder builder = new StringBuilder();
+        if (root != null) {
+            builder.append(root.authority).append('#');
+            builder.append(root.rootId).append('#');
+        } else {
+            builder.append("[null]").append('#');
+        }
+        for (DocumentInfo doc : this) {
+            builder.append(doc.documentId).append('#');
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public void reset() {
+        clear();
+        root = null;
+    }
+
+    @Override
+    public void read(DataInputStream in) throws IOException {
+        final int version = in.readInt();
+        switch (version) {
+            case VERSION_INIT:
+                throw new ProtocolException("Ignored upgrade");
+            case VERSION_ADD_ROOT:
+                if (in.readBoolean()) {
+                    root = new RootInfo();
+                    root.read(in);
+                }
+                final int size = in.readInt();
+                for (int i = 0; i < size; i++) {
+                    final DocumentInfo doc = new DocumentInfo();
+                    doc.read(in);
+                    add(doc);
+                }
+                break;
+            default:
+                throw new ProtocolException("Unknown version " + version);
+        }
+    }
+
+    @Override
+    public void write(DataOutputStream out) throws IOException {
+        out.writeInt(VERSION_ADD_ROOT);
+        if (root != null) {
+            out.writeBoolean(true);
+            root.write(out);
+        } else {
+            out.writeBoolean(false);
+        }
+        final int size = size();
+        out.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            final DocumentInfo doc = get(i);
+            doc.write(out);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Durable.java b/packages/DocumentsUI/src/com/android/documentsui/model/Durable.java
new file mode 100644
index 0000000..01633ed
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Durable.java
@@ -0,0 +1,27 @@
+/*
+ * 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.documentsui.model;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public interface Durable {
+    public void reset();
+    public void read(DataInputStream in) throws IOException;
+    public void write(DataOutputStream out) throws IOException;
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
new file mode 100644
index 0000000..2a29cbc
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
@@ -0,0 +1,101 @@
+/*
+ * 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.documentsui.model;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.os.BadParcelableException;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class DurableUtils {
+    public static <D extends Durable> byte[] writeToArray(D d) throws IOException {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        d.write(new DataOutputStream(out));
+        return out.toByteArray();
+    }
+
+    public static <D extends Durable> D readFromArray(byte[] data, D d) throws IOException {
+        if (data == null) throw new IOException("Missing data");
+        final ByteArrayInputStream in = new ByteArrayInputStream(data);
+        d.reset();
+        try {
+            d.read(new DataInputStream(in));
+        } catch (IOException e) {
+            d.reset();
+            throw e;
+        }
+        return d;
+    }
+
+    public static <D extends Durable> byte[] writeToArrayOrNull(D d) {
+        try {
+            return writeToArray(d);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to write", e);
+            return null;
+        }
+    }
+
+    public static <D extends Durable> D readFromArrayOrNull(byte[] data, D d) {
+        try {
+            return readFromArray(data, d);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to read", e);
+            return null;
+        }
+    }
+
+    public static <D extends Durable> void writeToParcel(Parcel parcel, D d) {
+        try {
+            parcel.writeByteArray(writeToArray(d));
+        } catch (IOException e) {
+            throw new BadParcelableException(e);
+        }
+    }
+
+    public static <D extends Durable> D readFromParcel(Parcel parcel, D d) {
+        try {
+            return readFromArray(parcel.createByteArray(), d);
+        } catch (IOException e) {
+            throw new BadParcelableException(e);
+        }
+    }
+
+    public static void writeNullableString(DataOutputStream out, String value) throws IOException {
+        if (value != null) {
+            out.write(1);
+            out.writeUTF(value);
+        } else {
+            out.write(0);
+        }
+    }
+
+    public static String readNullableString(DataInputStream in) throws IOException {
+        if (in.read() != 0) {
+            return in.readUTF();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
new file mode 100644
index 0000000..e220c9e
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -0,0 +1,232 @@
+/*
+ * 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.documentsui.model;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.DocumentsContract.Root;
+import android.text.TextUtils;
+
+import com.android.documentsui.IconUtils;
+import com.android.documentsui.R;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.util.Objects;
+
+/**
+ * Representation of a {@link Root}.
+ */
+public class RootInfo implements Durable, Parcelable {
+    private static final int VERSION_INIT = 1;
+    private static final int VERSION_DROP_TYPE = 2;
+
+    public String authority;
+    public String rootId;
+    public int flags;
+    public int icon;
+    public String title;
+    public String summary;
+    public String documentId;
+    public long availableBytes;
+    public String mimeTypes;
+
+    /** Derived fields that aren't persisted */
+    public String derivedPackageName;
+    public String[] derivedMimeTypes;
+    public int derivedIcon;
+
+    public RootInfo() {
+        reset();
+    }
+
+    @Override
+    public void reset() {
+        authority = null;
+        rootId = null;
+        flags = 0;
+        icon = 0;
+        title = null;
+        summary = null;
+        documentId = null;
+        availableBytes = -1;
+        mimeTypes = null;
+
+        derivedPackageName = null;
+        derivedMimeTypes = null;
+        derivedIcon = 0;
+    }
+
+    @Override
+    public void read(DataInputStream in) throws IOException {
+        final int version = in.readInt();
+        switch (version) {
+            case VERSION_DROP_TYPE:
+                authority = DurableUtils.readNullableString(in);
+                rootId = DurableUtils.readNullableString(in);
+                flags = in.readInt();
+                icon = in.readInt();
+                title = DurableUtils.readNullableString(in);
+                summary = DurableUtils.readNullableString(in);
+                documentId = DurableUtils.readNullableString(in);
+                availableBytes = in.readLong();
+                mimeTypes = DurableUtils.readNullableString(in);
+                deriveFields();
+                break;
+            default:
+                throw new ProtocolException("Unknown version " + version);
+        }
+    }
+
+    @Override
+    public void write(DataOutputStream out) throws IOException {
+        out.writeInt(VERSION_DROP_TYPE);
+        DurableUtils.writeNullableString(out, authority);
+        DurableUtils.writeNullableString(out, rootId);
+        out.writeInt(flags);
+        out.writeInt(icon);
+        DurableUtils.writeNullableString(out, title);
+        DurableUtils.writeNullableString(out, summary);
+        DurableUtils.writeNullableString(out, documentId);
+        out.writeLong(availableBytes);
+        DurableUtils.writeNullableString(out, mimeTypes);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        DurableUtils.writeToParcel(dest, this);
+    }
+
+    public static final Creator<RootInfo> CREATOR = new Creator<RootInfo>() {
+        @Override
+        public RootInfo createFromParcel(Parcel in) {
+            final RootInfo root = new RootInfo();
+            DurableUtils.readFromParcel(in, root);
+            return root;
+        }
+
+        @Override
+        public RootInfo[] newArray(int size) {
+            return new RootInfo[size];
+        }
+    };
+
+    public static RootInfo fromRootsCursor(String authority, Cursor cursor) {
+        final RootInfo root = new RootInfo();
+        root.authority = authority;
+        root.rootId = getCursorString(cursor, Root.COLUMN_ROOT_ID);
+        root.flags = getCursorInt(cursor, Root.COLUMN_FLAGS);
+        root.icon = getCursorInt(cursor, Root.COLUMN_ICON);
+        root.title = getCursorString(cursor, Root.COLUMN_TITLE);
+        root.summary = getCursorString(cursor, Root.COLUMN_SUMMARY);
+        root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID);
+        root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES);
+        root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
+        root.deriveFields();
+        return root;
+    }
+
+    private void deriveFields() {
+        derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
+
+        // TODO: remove these special case icons
+        if (isExternalStorage()) {
+            derivedIcon = R.drawable.ic_root_sdcard;
+        } else if (isDownloads()) {
+            derivedIcon = R.drawable.ic_root_download;
+        } else if (isImages()) {
+            derivedIcon = R.drawable.ic_doc_image;
+        } else if (isVideos()) {
+            derivedIcon = R.drawable.ic_doc_video;
+        } else if (isAudio()) {
+            derivedIcon = R.drawable.ic_doc_audio;
+        }
+    }
+
+    public boolean isRecents() {
+        return authority == null && rootId == null;
+    }
+
+    public boolean isExternalStorage() {
+        return "com.android.externalstorage.documents".equals(authority);
+    }
+
+    public boolean isDownloads() {
+        return "com.android.providers.downloads.documents".equals(authority);
+    }
+
+    public boolean isImages() {
+        return "com.android.providers.media.documents".equals(authority)
+                && "images_root".equals(rootId);
+    }
+
+    public boolean isVideos() {
+        return "com.android.providers.media.documents".equals(authority)
+                && "videos_root".equals(rootId);
+    }
+
+    public boolean isAudio() {
+        return "com.android.providers.media.documents".equals(authority)
+                && "audio_root".equals(rootId);
+    }
+
+    @Override
+    public String toString() {
+        return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
+    }
+
+    public Drawable loadIcon(Context context) {
+        if (derivedIcon != 0) {
+            return context.getResources().getDrawable(derivedIcon);
+        } else {
+            return IconUtils.loadPackageIcon(context, authority, icon);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof RootInfo) {
+            final RootInfo root = (RootInfo) o;
+            return Objects.equals(authority, root.authority) && Objects.equals(rootId, root.rootId);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(authority, rootId);
+    }
+
+    public String getDirectoryString() {
+        return !TextUtils.isEmpty(summary) ? summary : title;
+    }
+}
diff --git a/packages/DocumentsUI/tests/Android.mk b/packages/DocumentsUI/tests/Android.mk
new file mode 100644
index 0000000..fdf4fab
--- /dev/null
+++ b/packages/DocumentsUI/tests/Android.mk
@@ -0,0 +1,16 @@
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := DocumentsUITests
+LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/DocumentsUI/tests/AndroidManifest.xml b/packages/DocumentsUI/tests/AndroidManifest.xml
new file mode 100644
index 0000000..81a2889
--- /dev/null
+++ b/packages/DocumentsUI/tests/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.documentsui.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.documentsui"
+        android:label="Tests for DocumentsUI" />
+
+</manifest>
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
new file mode 100644
index 0000000..cdb6b33
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.documentsui;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.model.RootInfo;
+import com.google.android.collect.Lists;
+
+import java.util.List;
+
+@SmallTest
+public class RootsCacheTest extends AndroidTestCase {
+
+    private static RootInfo buildForMimeTypes(String... mimeTypes) {
+        final RootInfo root = new RootInfo();
+        root.derivedMimeTypes = mimeTypes;
+        return root;
+    }
+
+    private RootInfo mNull = new RootInfo();
+    private RootInfo mEmpty = buildForMimeTypes();
+    private RootInfo mWild = buildForMimeTypes("*/*");
+    private RootInfo mImages = buildForMimeTypes("image/*");
+    private RootInfo mAudio = buildForMimeTypes("audio/*", "application/ogg", "application/x-flac");
+    private RootInfo mDocs = buildForMimeTypes("application/msword", "application/vnd.ms-excel");
+    private RootInfo mMalformed1 = buildForMimeTypes("meow");
+    private RootInfo mMalformed2 = buildForMimeTypes("*/meow");
+
+    private List<RootInfo> mRoots = Lists.newArrayList(
+            mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+
+    private State mState;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mState = new State();
+        mState.action = State.ACTION_OPEN;
+        mState.showAdvanced = true;
+        mState.localOnly = false;
+    }
+
+    public void testMatchingRootsEverything() throws Exception {
+        mState.acceptMimes = new String[] { "*/*" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsPngOrWild() throws Exception {
+        mState.acceptMimes = new String[] { "image/png", "*/*" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsAudioWild() throws Exception {
+        mState.acceptMimes = new String[] { "audio/*" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mAudio),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsAudioWildOrImageWild() throws Exception {
+        mState.acceptMimes = new String[] { "audio/*", "image/*" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mAudio, mImages),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsAudioSpecific() throws Exception {
+        mState.acceptMimes = new String[] { "audio/mpeg" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mAudio),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsDocument() throws Exception {
+        mState.acceptMimes = new String[] { "application/msword" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mDocs),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsApplication() throws Exception {
+        mState.acceptMimes = new String[] { "application/*" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mAudio, mDocs),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRootsFlacOrPng() throws Exception {
+        mState.acceptMimes = new String[] { "application/x-flac", "image/png" };
+        assertContainsExactly(
+                Lists.newArrayList(mNull, mWild, mAudio, mImages),
+                RootsCache.getMatchingRoots(mRoots, mState));
+    }
+
+    private static void assertContainsExactly(List<?> expected, List<?> actual) {
+        assertEquals(expected.size(), actual.size());
+        for (Object o : expected) {
+            assertTrue(actual.contains(o));
+        }
+    }
+}
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
new file mode 100644
index 0000000..db825ff4
--- /dev/null
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := ExternalStorageProvider
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
new file mode 100644
index 0000000..7094efc
--- /dev/null
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.externalstorage">
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application android:label="@string/app_label">
+        <provider
+            android:name=".ExternalStorageProvider"
+            android:authorities="com.android.externalstorage.documents"
+            android:grantUriPermissions="true"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS">
+            <meta-data
+                android:name="android.content.DOCUMENT_PROVIDER"
+                android:value="true" />
+        </provider>
+
+        <!-- TODO: find a better place for tests to live -->
+        <provider
+            android:name=".TestDocumentsProvider"
+            android:authorities="com.example.documents"
+            android:grantUriPermissions="true"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS"
+            android:enabled="false">
+            <meta-data
+                android:name="android.content.DOCUMENT_PROVIDER"
+                android:value="true" />
+        </provider>
+    </application>
+</manifest>
diff --git a/packages/ExternalStorageProvider/res/values/strings.xml b/packages/ExternalStorageProvider/res/values/strings.xml
new file mode 100644
index 0000000..f1c1ade
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resources>
+    <!-- Title of the external storage application [CHAR LIMIT=32] -->
+    <string name="app_label">External Storage</string>
+
+    <!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
+    <string name="root_internal_storage">Internal storage</string>
+    <!-- Title for documents backend that offers documents. [CHAR LIMIT=24] -->
+    <string name="root_documents">Documents</string>
+</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
new file mode 100644
index 0000000..9328b33
--- /dev/null
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -0,0 +1,370 @@
+/*
+ * 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.externalstorage;
+
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.graphics.Point;
+import android.media.ExifInterface;
+import android.os.CancellationSignal;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+import android.webkit.MimeTypeMap;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+public class ExternalStorageProvider extends DocumentsProvider {
+    private static final String TAG = "ExternalStorage";
+
+    // docId format: root:path/to/file
+
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
+            Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES,
+    };
+
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+    };
+
+    private static class RootInfo {
+        public String rootId;
+        public int flags;
+        public String title;
+        public String docId;
+    }
+
+    private ArrayList<RootInfo> mRoots;
+    private HashMap<String, RootInfo> mIdToRoot;
+    private HashMap<String, File> mIdToPath;
+
+    @Override
+    public boolean onCreate() {
+        mRoots = Lists.newArrayList();
+        mIdToRoot = Maps.newHashMap();
+        mIdToPath = Maps.newHashMap();
+
+        // TODO: support multiple storage devices
+
+        try {
+            final String rootId = "primary";
+            final File path = Environment.getExternalStorageDirectory();
+            mIdToPath.put(rootId, path);
+
+            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.title = getContext().getString(R.string.root_internal_storage);
+            root.docId = getDocIdForFile(path);
+            mRoots.add(root);
+            mIdToRoot.put(rootId, root);
+        } catch (FileNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
+
+        return true;
+    }
+
+    private static String[] resolveRootProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
+    }
+
+    private static String[] resolveDocumentProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
+    }
+
+    private String getDocIdForFile(File file) throws FileNotFoundException {
+        String path = file.getAbsolutePath();
+
+        // Find the most-specific root path
+        Map.Entry<String, File> mostSpecific = null;
+        for (Map.Entry<String, File> root : mIdToPath.entrySet()) {
+            final String rootPath = root.getValue().getPath();
+            if (path.startsWith(rootPath) && (mostSpecific == null
+                    || rootPath.length() > mostSpecific.getValue().getPath().length())) {
+                mostSpecific = root;
+            }
+        }
+
+        if (mostSpecific == null) {
+            throw new FileNotFoundException("Failed to find root that contains " + path);
+        }
+
+        // Start at first char of path under root
+        final String rootPath = mostSpecific.getValue().getPath();
+        if (rootPath.equals(path)) {
+            path = "";
+        } else if (rootPath.endsWith("/")) {
+            path = path.substring(rootPath.length());
+        } else {
+            path = path.substring(rootPath.length() + 1);
+        }
+
+        return mostSpecific.getKey() + ':' + path;
+    }
+
+    private File getFileForDocId(String docId) throws FileNotFoundException {
+        final int splitIndex = docId.indexOf(':', 1);
+        final String tag = docId.substring(0, splitIndex);
+        final String path = docId.substring(splitIndex + 1);
+
+        File target = mIdToPath.get(tag);
+        if (target == null) {
+            throw new FileNotFoundException("No root for " + tag);
+        }
+        if (!target.exists()) {
+            target.mkdirs();
+        }
+        target = new File(target, path);
+        if (!target.exists()) {
+            throw new FileNotFoundException("Missing file for " + docId + " at " + target);
+        }
+        return target;
+    }
+
+    private void includeFile(MatrixCursor result, String docId, File file)
+            throws FileNotFoundException {
+        if (docId == null) {
+            docId = getDocIdForFile(file);
+        } else {
+            file = getFileForDocId(docId);
+        }
+
+        int flags = 0;
+
+        if (file.canWrite()) {
+            if (file.isDirectory()) {
+                flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+            } else {
+                flags |= Document.FLAG_SUPPORTS_WRITE;
+            }
+            flags |= Document.FLAG_SUPPORTS_DELETE;
+        }
+
+        final String displayName = file.getName();
+        final String mimeType = getTypeForFile(file);
+        if (mimeType.startsWith("image/")) {
+            flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
+        }
+
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, docId);
+        row.add(Document.COLUMN_DISPLAY_NAME, displayName);
+        row.add(Document.COLUMN_SIZE, file.length());
+        row.add(Document.COLUMN_MIME_TYPE, mimeType);
+        row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
+        row.add(Document.COLUMN_FLAGS, flags);
+    }
+
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
+        for (String rootId : mIdToPath.keySet()) {
+            final RootInfo root = mIdToRoot.get(rootId);
+            final File path = mIdToPath.get(rootId);
+
+            final RowBuilder row = result.newRow();
+            row.add(Root.COLUMN_ROOT_ID, root.rootId);
+            row.add(Root.COLUMN_FLAGS, root.flags);
+            row.add(Root.COLUMN_TITLE, root.title);
+            row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
+            row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
+        }
+        return result;
+    }
+
+    @Override
+    public String createDocument(String docId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        final File parent = getFileForDocId(docId);
+        File file;
+
+        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+            file = new File(parent, displayName);
+            if (!file.mkdir()) {
+                throw new IllegalStateException("Failed to mkdir " + file);
+            }
+        } else {
+            displayName = removeExtension(mimeType, displayName);
+            file = new File(parent, addExtension(mimeType, displayName));
+
+            // If conflicting file, try adding counter suffix
+            int n = 0;
+            while (file.exists() && n++ < 32) {
+                file = new File(parent, addExtension(mimeType, displayName + " (" + n + ")"));
+            }
+
+            try {
+                if (!file.createNewFile()) {
+                    throw new IllegalStateException("Failed to touch " + file);
+                }
+            } catch (IOException e) {
+                throw new IllegalStateException("Failed to touch " + file + ": " + e);
+            }
+        }
+        return getDocIdForFile(file);
+    }
+
+    @Override
+    public void deleteDocument(String docId) throws FileNotFoundException {
+        final File file = getFileForDocId(docId);
+        if (!file.delete()) {
+            throw new IllegalStateException("Failed to delete " + file);
+        }
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        includeFile(result, documentId, null);
+        return result;
+    }
+
+    @Override
+    public Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        final File parent = getFileForDocId(parentDocumentId);
+        for (File file : parent.listFiles()) {
+            includeFile(result, null, file);
+        }
+        return result;
+    }
+
+    @Override
+    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        final File parent = mIdToPath.get(rootId);
+
+        final LinkedList<File> pending = new LinkedList<File>();
+        pending.add(parent);
+        while (!pending.isEmpty() && result.getCount() < 24) {
+            final File file = pending.removeFirst();
+            if (file.isDirectory()) {
+                for (File child : file.listFiles()) {
+                    pending.add(child);
+                }
+            }
+            if (file.getName().toLowerCase().contains(query)) {
+                includeFile(result, null, file);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String getDocumentType(String documentId) throws FileNotFoundException {
+        final File file = getFileForDocId(documentId);
+        return getTypeForFile(file);
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(
+            String documentId, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        final File file = getFileForDocId(documentId);
+        return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode));
+    }
+
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(
+            String documentId, Point sizeHint, CancellationSignal signal)
+            throws FileNotFoundException {
+        final File file = getFileForDocId(documentId);
+        final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                file, ParcelFileDescriptor.MODE_READ_ONLY);
+
+        try {
+            final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
+            final long[] thumb = exif.getThumbnailRange();
+            if (thumb != null) {
+                return new AssetFileDescriptor(pfd, thumb[0], thumb[1]);
+            }
+        } catch (IOException e) {
+        }
+
+        return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+    }
+
+    private static String getTypeForFile(File file) {
+        if (file.isDirectory()) {
+            return Document.MIME_TYPE_DIR;
+        } else {
+            return getTypeForName(file.getName());
+        }
+    }
+
+    private static String getTypeForName(String name) {
+        final int lastDot = name.lastIndexOf('.');
+        if (lastDot >= 0) {
+            final String extension = name.substring(lastDot + 1);
+            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            if (mime != null) {
+                return mime;
+            }
+        }
+
+        return "application/octet-stream";
+    }
+
+    /**
+     * Remove file extension from name, but only if exact MIME type mapping
+     * exists. This means we can reapply the extension later.
+     */
+    private static String removeExtension(String mimeType, String name) {
+        final int lastDot = name.lastIndexOf('.');
+        if (lastDot >= 0) {
+            final String extension = name.substring(lastDot + 1);
+            final String nameMime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            if (mimeType.equals(nameMime)) {
+                return name.substring(0, lastDot);
+            }
+        }
+        return name;
+    }
+
+    /**
+     * Add file extension to name, but only if exact MIME type mapping exists.
+     */
+    private static String addExtension(String mimeType, String name) {
+        final String extension = MimeTypeMap.getSingleton()
+                .getExtensionFromMimeType(mimeType);
+        if (extension != null) {
+            return name + "." + extension;
+        }
+        return name;
+    }
+}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
new file mode 100644
index 0000000..0caddcc
--- /dev/null
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
@@ -0,0 +1,369 @@
+/*
+ * 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.externalstorage;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+public class TestDocumentsProvider extends DocumentsProvider {
+    private static final String TAG = "TestDocuments";
+
+    private static final boolean ROOTS_WEDGE = false;
+    private static final boolean ROOTS_LAG = false;
+    private static final boolean ROOTS_CRASH = false;
+    private static final boolean ROOTS_REFRESH = false;
+
+    private static final boolean DOCUMENT_CRASH = false;
+
+    private static final boolean RECENT_WEDGE = false;
+
+    private static final boolean CHILD_WEDGE = false;
+    private static final boolean CHILD_CRASH = false;
+
+    private static final boolean THUMB_HUNDREDS = false;
+    private static final boolean THUMB_WEDGE = false;
+    private static final boolean THUMB_CRASH = false;
+
+    private static final String MY_ROOT_ID = "myRoot";
+    private static final String MY_DOC_ID = "myDoc";
+    private static final String MY_DOC_NULL = "myNull";
+
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON,
+            Root.COLUMN_TITLE, Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID,
+            Root.COLUMN_AVAILABLE_BYTES,
+    };
+
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+    };
+
+    private static String[] resolveRootProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
+    }
+
+    private static String[] resolveDocumentProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
+    }
+
+    private String mAuthority;
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        mAuthority = info.authority;
+        super.attachInfo(context, info);
+    }
+
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        Log.d(TAG, "Someone asked for our roots!");
+
+        if (ROOTS_WEDGE) SystemClock.sleep(Integer.MAX_VALUE);
+        if (ROOTS_LAG) SystemClock.sleep(3000);
+        if (ROOTS_CRASH) System.exit(12);
+
+        if (ROOTS_REFRESH) {
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    SystemClock.sleep(3000);
+                    Log.d(TAG, "Notifying that something changed!!");
+                    final Uri uri = DocumentsContract.buildRootsUri(mAuthority);
+                    getContext().getContentResolver().notifyChange(uri, null, false);
+                    return null;
+                }
+            }.execute();
+        }
+
+        final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
+        final RowBuilder row = result.newRow();
+        row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
+        row.add(Root.COLUMN_TITLE, "_Test title which is really long");
+        row.add(Root.COLUMN_SUMMARY,
+                SystemClock.elapsedRealtime() + " summary which is also super long text");
+        row.add(Root.COLUMN_DOCUMENT_ID, MY_DOC_ID);
+        row.add(Root.COLUMN_AVAILABLE_BYTES, 1024);
+        return result;
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        if (DOCUMENT_CRASH) System.exit(12);
+
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        includeFile(result, documentId, 0);
+        return result;
+    }
+
+    /**
+     * Holds any outstanding or finished "network" fetching.
+     */
+    private WeakReference<CloudTask> mTask;
+
+    private static class CloudTask implements Runnable {
+
+        private final ContentResolver mResolver;
+        private final Uri mNotifyUri;
+
+        private volatile boolean mFinished;
+
+        public CloudTask(ContentResolver resolver, Uri notifyUri) {
+            mResolver = resolver;
+            mNotifyUri = notifyUri;
+        }
+
+        @Override
+        public void run() {
+            // Pretend to do some network
+            Log.d(TAG, hashCode() + ": pretending to do some network!");
+            SystemClock.sleep(2000);
+            Log.d(TAG, hashCode() + ": network done!");
+
+            mFinished = true;
+
+            // Tell anyone remotely they should requery
+            mResolver.notifyChange(mNotifyUri, null, false);
+        }
+
+        public boolean includeIfFinished(MatrixCursor result) {
+            Log.d(TAG, hashCode() + ": includeIfFinished() found " + mFinished);
+            if (mFinished) {
+                includeFile(result, "_networkfile1", 0);
+                includeFile(result, "_networkfile2", 0);
+                includeFile(result, "_networkfile3", 0);
+                includeFile(result, "_networkfile4", 0);
+                includeFile(result, "_networkfile5", 0);
+                includeFile(result, "_networkfile6", 0);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    private static class CloudCursor extends MatrixCursor {
+        public Object keepAlive;
+        public final Bundle extras = new Bundle();
+
+        public CloudCursor(String[] columnNames) {
+            super(columnNames);
+        }
+
+        @Override
+        public Bundle getExtras() {
+            return extras;
+        }
+    }
+
+    @Override
+    public Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+
+        if (CHILD_WEDGE) SystemClock.sleep(Integer.MAX_VALUE);
+        if (CHILD_CRASH) System.exit(12);
+
+        final ContentResolver resolver = getContext().getContentResolver();
+        final Uri notifyUri = DocumentsContract.buildDocumentUri(
+                "com.example.documents", parentDocumentId);
+
+        CloudCursor result = new CloudCursor(resolveDocumentProjection(projection));
+        result.setNotificationUri(resolver, notifyUri);
+
+        // Always include local results
+        includeFile(result, MY_DOC_NULL, 0);
+        includeFile(result, "localfile1", 0);
+        includeFile(result, "localfile2", Document.FLAG_SUPPORTS_THUMBNAIL);
+        includeFile(result, "localfile3", 0);
+        includeFile(result, "localfile4", 0);
+
+        if (THUMB_HUNDREDS) {
+            for (int i = 0; i < 256; i++) {
+                includeFile(result, "i maded u an picshure", Document.FLAG_SUPPORTS_THUMBNAIL);
+            }
+        }
+
+        synchronized (this) {
+            // Try picking up an existing network fetch
+            CloudTask task = mTask != null ? mTask.get() : null;
+            if (task == null) {
+                Log.d(TAG, "No network task found; starting!");
+                task = new CloudTask(resolver, notifyUri);
+                mTask = new WeakReference<CloudTask>(task);
+                new Thread(task).start();
+
+                // Aggressively try freeing weak reference above
+                new Thread() {
+                    @Override
+                    public void run() {
+                        while (mTask.get() != null) {
+                            SystemClock.sleep(200);
+                            System.gc();
+                            System.runFinalization();
+                        }
+                        Log.d(TAG, "AHA! THE CLOUD TASK WAS GC'ED!");
+                    }
+                }.start();
+            }
+
+            // Blend in cloud results if ready
+            if (task.includeIfFinished(result)) {
+                result.extras.putString(DocumentsContract.EXTRA_INFO,
+                        "Everything Went Better Than Expected and this message is quite "
+                                + "long and verbose and maybe even too long");
+                result.extras.putString(DocumentsContract.EXTRA_ERROR,
+                        "But then again, maybe our server ran into an error, which means "
+                                + "we're going to have a bad time");
+            } else {
+                result.extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
+            }
+
+            // Tie the network fetch to the cursor GC lifetime
+            result.keepAlive = task;
+
+            return result;
+        }
+    }
+
+    @Override
+    public Cursor queryRecentDocuments(String rootId, String[] projection)
+            throws FileNotFoundException {
+
+        if (RECENT_WEDGE) SystemClock.sleep(Integer.MAX_VALUE);
+
+        // Pretend to take a super long time to respond
+        SystemClock.sleep(3000);
+
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        includeFile(
+                result, "It was /worth/ the_wait for?the file:with the&incredibly long name", 0);
+        return result;
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        throw new FileNotFoundException();
+    }
+
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(
+            String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
+
+        if (THUMB_WEDGE) wedgeUntilCanceled(signal);
+        if (THUMB_CRASH) System.exit(12);
+
+        final Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bitmap);
+        final Paint paint = new Paint();
+        paint.setColor(Color.BLUE);
+        canvas.drawColor(Color.RED);
+        canvas.drawLine(0, 0, 32, 32, paint);
+
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        bitmap.compress(CompressFormat.JPEG, 50, bos);
+
+        final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+        try {
+            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createReliablePipe();
+            new AsyncTask<Object, Object, Object>() {
+                @Override
+                protected Object doInBackground(Object... params) {
+                    final FileOutputStream fos = new FileOutputStream(fds[1].getFileDescriptor());
+                    try {
+                        Streams.copy(bis, fos);
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                    IoUtils.closeQuietly(fds[1]);
+                    return null;
+                }
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+            return new AssetFileDescriptor(fds[0], 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+        } catch (IOException e) {
+            throw new FileNotFoundException(e.getMessage());
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    private static void wedgeUntilCanceled(CancellationSignal signal) {
+        if (signal != null) {
+            while (true) {
+                signal.throwIfCanceled();
+                SystemClock.sleep(500);
+            }
+        } else {
+            Log.w(TAG, "WEDGING WITHOUT A CANCELLATIONSIGNAL");
+            SystemClock.sleep(Integer.MAX_VALUE);
+        }
+    }
+
+    private static void includeFile(MatrixCursor result, String docId, int flags) {
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, docId);
+        row.add(Document.COLUMN_DISPLAY_NAME, docId);
+        row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
+        row.add(Document.COLUMN_FLAGS, flags);
+
+        if (MY_DOC_ID.equals(docId)) {
+            row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+        } else if (MY_DOC_NULL.equals(docId)) {
+            // No MIME type
+        } else {
+            row.add(Document.COLUMN_MIME_TYPE, "application/octet-stream");
+        }
+    }
+}
diff --git a/packages/FusedLocation/Android.mk b/packages/FusedLocation/Android.mk
index 318782f..7406eaf4 100644
--- a/packages/FusedLocation/Android.mk
+++ b/packages/FusedLocation/Android.mk
@@ -23,5 +23,6 @@
 
 LOCAL_PACKAGE_NAME := FusedLocation
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 include $(BUILD_PACKAGE)
diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk
index 37f2428..f537022 100644
--- a/packages/InputDevices/Android.mk
+++ b/packages/InputDevices/Android.mk
@@ -23,20 +23,27 @@
 
 LOCAL_PACKAGE_NAME := InputDevices
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 include $(BUILD_PACKAGE)
 
 # Validate all key maps.
 include $(CLEAR_VARS)
 
-validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
-files := frameworks/base/packages/InputDevices/res/raw/*.kcm
-
 LOCAL_MODULE := validate_input_devices_keymaps
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := validatekeymaps
+intermediates := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE),,COMMON)
+LOCAL_BUILT_MODULE := $(intermediates)/stamp
 
-validate_input_devices_keymaps: $(files)
-	$(hide) $(validatekeymaps) $(files)
+validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
+input_devices_keymaps := $(wildcard $(LOCAL_PATH)/res/raw/*.kcm)
+$(LOCAL_BUILT_MODULE): PRIVATE_VALIDATEKEYMAPS := $(validatekeymaps)
+$(LOCAL_BUILT_MODULE) : $(input_devices_keymaps) | $(validatekeymaps)
+	$(hide) $(PRIVATE_VALIDATEKEYMAPS) $^
+	$(hide) mkdir -p $(dir $@) && touch $@
 
-include $(BUILD_PHONY_PACKAGE)
+# Run validatekeymaps unconditionally for platform build.
+droidcore all_modules : $(LOCAL_BUILT_MODULE)
+
+# Reset temp vars.
+validatekeymaps :=
+input_devices_keymaps :=
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
new file mode 100644
index 0000000..f6f441d
--- /dev/null
+++ b/packages/Keyguard/Android.mk
@@ -0,0 +1,33 @@
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
+
+LOCAL_JAVA_LIBRARIES := services
+
+LOCAL_PACKAGE_NAME := Keyguard
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
+
+#include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
new file mode 100644
index 0000000..9e296e2
--- /dev/null
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?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.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.keyguard"
+    android:sharedUserId="android.uid.systemui"
+    coreApp="true">
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17"/>
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.STATUS_BAR" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
+
+    <application android:label="@string/app_name"
+        android:process="com.android.systemui"
+        android:persistent="true"
+        android:supportsRtl="true">
+
+        <service android:name=".KeyguardService"
+            android:exported="true" />
+
+    </application>
+</manifest>
diff --git a/packages/Keyguard/NOTICE b/packages/Keyguard/NOTICE
new file mode 100644
index 0000000..33ff961
--- /dev/null
+++ b/packages/Keyguard/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/packages/Keyguard/proguard.flags b/packages/Keyguard/proguard.flags
new file mode 100644
index 0000000..fb74b64
--- /dev/null
+++ b/packages/Keyguard/proguard.flags
@@ -0,0 +1,27 @@
+-keep public class * {
+  public void setBackgroundAlpha(float);
+  public float getBackgroundAlpha();
+  public void setContentAlpha(float);
+  public float getContentAlpha();
+  public void setAlpha(float);
+  public float getAlpha();
+  public void setAlpha(int);
+  public int getAlpha();
+  public void setRotationX(float);
+  public float getRotationX();
+  public void setRotationY(float);
+  public float getRotationY();
+  public void setPivotX(float);
+  public float getPivotX();
+  public void setPivotY(float);
+  public float getPivotY();
+  public void setScaleX(float);
+  public float getScaleX();
+  public void setScaleY(float);
+  public float getScaleY();
+  public void setTranslationX(float);
+  public float getTranslationX();
+  public void setTranslationY(float);
+  public float getTranslationY();
+}
+
diff --git a/core/res/res/anim/keyguard_action_assist_enter.xml b/packages/Keyguard/res/anim/keyguard_action_assist_enter.xml
similarity index 100%
rename from core/res/res/anim/keyguard_action_assist_enter.xml
rename to packages/Keyguard/res/anim/keyguard_action_assist_enter.xml
diff --git a/core/res/res/anim/keyguard_action_assist_exit.xml b/packages/Keyguard/res/anim/keyguard_action_assist_exit.xml
similarity index 100%
rename from core/res/res/anim/keyguard_action_assist_exit.xml
rename to packages/Keyguard/res/anim/keyguard_action_assist_exit.xml
diff --git a/packages/Keyguard/res/anim/lock_screen_enter.xml b/packages/Keyguard/res/anim/lock_screen_enter.xml
new file mode 100644
index 0000000..4344cf9
--- /dev/null
+++ b/packages/Keyguard/res/anim/lock_screen_enter.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@android:interpolator/accelerate_cubic">
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:duration="@integer/config_activityDefaultDur" />
+</set>
diff --git a/packages/Keyguard/res/anim/lock_screen_exit.xml b/packages/Keyguard/res/anim/lock_screen_exit.xml
new file mode 100644
index 0000000..c75b3cc
--- /dev/null
+++ b/packages/Keyguard/res/anim/lock_screen_exit.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:zAdjustment="top"
+    android:shareInterpolator="false">
+    <scale
+        android:fromXScale="1.0" android:toXScale="1.10"
+        android:fromYScale="1.0" android:toYScale="1.10"
+        android:pivotX="50%p" android:pivotY="50%p"
+        android:fillEnabled="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/accelerate_quint"
+        android:duration="@android:integer/config_shortAnimTime" />
+    <alpha
+        android:fromAlpha="1.0" android:toAlpha="0"
+        android:fillEnabled="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/accelerate_quad"
+        android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_action_assist_generic_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_action_assist_generic_activated.png
new file mode 100644
index 0000000..c0e2098
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_action_assist_generic_activated.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_action_assist_generic_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_action_assist_generic_normal.png
new file mode 100644
index 0000000..a852e2c
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_action_assist_generic_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_facial_backup.png b/packages/Keyguard/res/drawable-hdpi/ic_facial_backup.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_facial_backup.png
rename to packages/Keyguard/res/drawable-hdpi/ic_facial_backup.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_input_delete.png b/packages/Keyguard/res/drawable-hdpi/ic_input_delete.png
new file mode 100644
index 0000000..5d638bd
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_input_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_alarm.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_alarm.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_alarm.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_camera_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_activated.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_camera_activated.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_camera_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_camera_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_glowdot.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..983c45e
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_activated.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_focused.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..58a5f16
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_ime.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_ime.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_ime.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_player_background.9.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_player_background.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_player_background.9.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_player_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_search_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_activated.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_search_activated.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_search_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_search_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_activated.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_focused.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_sim.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_sim.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_sim.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_sim.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
rename to packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_media_next.png b/packages/Keyguard/res/drawable-hdpi/ic_media_next.png
new file mode 100644
index 0000000..6e27b81
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_media_next.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_media_play.png b/packages/Keyguard/res/drawable-hdpi/ic_media_play.png
new file mode 100644
index 0000000..2746d17
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_media_play.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_media_previous.png b/packages/Keyguard/res/drawable-hdpi/ic_media_previous.png
new file mode 100644
index 0000000..85b3766
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/intro_bg.png b/packages/Keyguard/res/drawable-hdpi/intro_bg.png
similarity index 100%
rename from core/res/res/drawable-hdpi/intro_bg.png
rename to packages/Keyguard/res/drawable-hdpi/intro_bg.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_add_widget.png b/packages/Keyguard/res/drawable-hdpi/kg_add_widget.png
new file mode 100644
index 0000000..7456705
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/kg_add_widget.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_add_widget_disabled.png b/packages/Keyguard/res/drawable-hdpi/kg_add_widget_disabled.png
similarity index 100%
rename from core/res/res/drawable-hdpi/kg_add_widget_disabled.png
rename to packages/Keyguard/res/drawable-hdpi/kg_add_widget_disabled.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-hdpi/kg_add_widget_pressed.png
new file mode 100644
index 0000000..70a960d
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/kg_add_widget_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/kg_bouncer_bg_white.9.png
rename to packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_security_grip.9.png b/packages/Keyguard/res/drawable-hdpi/kg_security_grip.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/kg_security_grip.9.png
rename to packages/Keyguard/res/drawable-hdpi/kg_security_grip.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_security_lock.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock.png
similarity index 100%
rename from core/res/res/drawable-hdpi/kg_security_lock.png
rename to packages/Keyguard/res/drawable-hdpi/kg_security_lock.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_focused.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_focused.png
new file mode 100644
index 0000000..9a82799
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_focused.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_normal.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_normal.png
new file mode 100644
index 0000000..d608707
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_pressed.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_pressed.png
new file mode 100644
index 0000000..7ca995d
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
new file mode 100644
index 0000000..476a826
--- /dev/null
+++ b/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png b/packages/Keyguard/res/drawable-hdpi/kg_widget_delete_drop_target.png
similarity index 100%
rename from core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png
rename to packages/Keyguard/res/drawable-hdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/lockscreen_protection_pattern.png b/packages/Keyguard/res/drawable-hdpi/lockscreen_protection_pattern.png
similarity index 100%
rename from core/res/res/drawable-hdpi/lockscreen_protection_pattern.png
rename to packages/Keyguard/res/drawable-hdpi/lockscreen_protection_pattern.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_return_holo.png b/packages/Keyguard/res/drawable-hdpi/sym_keyboard_return_holo.png
similarity index 100%
rename from core/res/res/drawable-hdpi/sym_keyboard_return_holo.png
rename to packages/Keyguard/res/drawable-hdpi/sym_keyboard_return_holo.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_input_delete.png b/packages/Keyguard/res/drawable-ldpi/ic_input_delete.png
new file mode 100644
index 0000000..d7eff17
--- /dev/null
+++ b/packages/Keyguard/res/drawable-ldpi/ic_input_delete.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_media_next.png b/packages/Keyguard/res/drawable-ldpi/ic_media_next.png
new file mode 100644
index 0000000..99927fd
--- /dev/null
+++ b/packages/Keyguard/res/drawable-ldpi/ic_media_next.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_media_play.png b/packages/Keyguard/res/drawable-ldpi/ic_media_play.png
new file mode 100644
index 0000000..e7c1972
--- /dev/null
+++ b/packages/Keyguard/res/drawable-ldpi/ic_media_play.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_media_previous.png b/packages/Keyguard/res/drawable-ldpi/ic_media_previous.png
new file mode 100644
index 0000000..df04322
--- /dev/null
+++ b/packages/Keyguard/res/drawable-ldpi/ic_media_previous.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_action_assist_generic_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_action_assist_generic_activated.png
new file mode 100644
index 0000000..f88f7e1
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_action_assist_generic_activated.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_action_assist_generic_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_action_assist_generic_normal.png
new file mode 100644
index 0000000..7426994
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_action_assist_generic_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_facial_backup.png b/packages/Keyguard/res/drawable-mdpi/ic_facial_backup.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_facial_backup.png
rename to packages/Keyguard/res/drawable-mdpi/ic_facial_backup.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_input_delete.png b/packages/Keyguard/res/drawable-mdpi/ic_input_delete.png
new file mode 100644
index 0000000..47c8708
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_input_delete.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_alarm.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_alarm.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_alarm.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_camera_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_activated.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_camera_activated.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_camera_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_camera_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_glowdot.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..056c3f17
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_activated.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_focused.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..0187a02
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_ime.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_ime.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_ime.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_player_background.9.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_player_background.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_player_background.9.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_player_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_search_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_activated.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_search_activated.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_search_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_search_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_activated.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_focused.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_sim.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_sim.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_sim.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_sim.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
rename to packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_media_next.png b/packages/Keyguard/res/drawable-mdpi/ic_media_next.png
new file mode 100644
index 0000000..fcd73d9
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_media_next.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_media_play.png b/packages/Keyguard/res/drawable-mdpi/ic_media_play.png
new file mode 100644
index 0000000..7966bbc
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_media_play.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_media_previous.png b/packages/Keyguard/res/drawable-mdpi/ic_media_previous.png
new file mode 100644
index 0000000..b653d05
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/intro_bg.png b/packages/Keyguard/res/drawable-mdpi/intro_bg.png
similarity index 100%
rename from core/res/res/drawable-mdpi/intro_bg.png
rename to packages/Keyguard/res/drawable-mdpi/intro_bg.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_add_widget.png b/packages/Keyguard/res/drawable-mdpi/kg_add_widget.png
new file mode 100644
index 0000000..1cab0d9
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/kg_add_widget.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_add_widget_disabled.png b/packages/Keyguard/res/drawable-mdpi/kg_add_widget_disabled.png
similarity index 100%
rename from core/res/res/drawable-mdpi/kg_add_widget_disabled.png
rename to packages/Keyguard/res/drawable-mdpi/kg_add_widget_disabled.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-mdpi/kg_add_widget_pressed.png
new file mode 100644
index 0000000..a68d4c1
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/kg_add_widget_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/kg_bouncer_bg_white.9.png
rename to packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_security_grip.9.png b/packages/Keyguard/res/drawable-mdpi/kg_security_grip.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/kg_security_grip.9.png
rename to packages/Keyguard/res/drawable-mdpi/kg_security_grip.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_security_lock.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock.png
similarity index 100%
rename from core/res/res/drawable-mdpi/kg_security_lock.png
rename to packages/Keyguard/res/drawable-mdpi/kg_security_lock.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_focused.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_focused.png
new file mode 100644
index 0000000..c3608f9
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_focused.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_normal.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_normal.png
new file mode 100644
index 0000000..7957c79
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_pressed.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_pressed.png
new file mode 100644
index 0000000..41715f5
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
new file mode 100644
index 0000000..aa441de
--- /dev/null
+++ b/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png b/packages/Keyguard/res/drawable-mdpi/kg_widget_delete_drop_target.png
similarity index 100%
rename from core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png
rename to packages/Keyguard/res/drawable-mdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/lockscreen_protection_pattern.png b/packages/Keyguard/res/drawable-mdpi/lockscreen_protection_pattern.png
similarity index 100%
rename from core/res/res/drawable-mdpi/lockscreen_protection_pattern.png
rename to packages/Keyguard/res/drawable-mdpi/lockscreen_protection_pattern.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_return_holo.png b/packages/Keyguard/res/drawable-mdpi/sym_keyboard_return_holo.png
similarity index 100%
rename from core/res/res/drawable-mdpi/sym_keyboard_return_holo.png
rename to packages/Keyguard/res/drawable-mdpi/sym_keyboard_return_holo.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
similarity index 100%
rename from core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
rename to packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..728fc67
--- /dev/null
+++ b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
similarity index 100%
rename from core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
rename to packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..c7da024
--- /dev/null
+++ b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
similarity index 100%
rename from core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
rename to packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..534c10b
--- /dev/null
+++ b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_action_assist_generic_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_action_assist_generic_activated.png
new file mode 100644
index 0000000..500b157
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_action_assist_generic_activated.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_action_assist_generic_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_action_assist_generic_normal.png
new file mode 100644
index 0000000..d0e4cf3
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_action_assist_generic_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_facial_backup.png b/packages/Keyguard/res/drawable-xhdpi/ic_facial_backup.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_facial_backup.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_facial_backup.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_input_delete.png b/packages/Keyguard/res/drawable-xhdpi/ic_input_delete.png
new file mode 100644
index 0000000..8b822d9
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_input_delete.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_alarm.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_alarm.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_alarm.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_camera_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_camera_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_glowdot.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..cbd039a
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_activated.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_focused.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_handle_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..2d28009
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_ime.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_ime.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_player_background.9.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_player_background.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_player_background.9.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_player_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_sim.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_sim.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_sim.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_sim.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
rename to packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_media_next.png b/packages/Keyguard/res/drawable-xhdpi/ic_media_next.png
new file mode 100644
index 0000000..4def965
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_media_next.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_media_play.png b/packages/Keyguard/res/drawable-xhdpi/ic_media_play.png
new file mode 100644
index 0000000..ccfef18
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_media_play.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_media_previous.png b/packages/Keyguard/res/drawable-xhdpi/ic_media_previous.png
new file mode 100644
index 0000000..c4472ae
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/intro_bg.png b/packages/Keyguard/res/drawable-xhdpi/intro_bg.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/intro_bg.png
rename to packages/Keyguard/res/drawable-xhdpi/intro_bg.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget.png b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget.png
new file mode 100644
index 0000000..d71905f
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_disabled.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/kg_add_widget_disabled.png
rename to packages/Keyguard/res/drawable-xhdpi/kg_add_widget_disabled.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_pressed.png
new file mode 100644
index 0000000..edf7070
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
rename to packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_security_grip.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_grip.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/kg_security_grip.9.png
rename to packages/Keyguard/res/drawable-xhdpi/kg_security_grip.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_security_lock.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/kg_security_lock.png
rename to packages/Keyguard/res/drawable-xhdpi/kg_security_lock.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_focused.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_focused.png
new file mode 100644
index 0000000..db22016
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_focused.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_normal.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_normal.png
new file mode 100644
index 0000000..17ebb5f
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_normal.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_pressed.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_pressed.png
new file mode 100644
index 0000000..186b6ff
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_pressed.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
new file mode 100644
index 0000000..6c372dd
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png b/packages/Keyguard/res/drawable-xhdpi/kg_widget_delete_drop_target.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png
rename to packages/Keyguard/res/drawable-xhdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/lockscreen_protection_pattern.png b/packages/Keyguard/res/drawable-xhdpi/lockscreen_protection_pattern.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/lockscreen_protection_pattern.png
rename to packages/Keyguard/res/drawable-xhdpi/lockscreen_protection_pattern.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/sym_keyboard_return_holo.png b/packages/Keyguard/res/drawable-xhdpi/sym_keyboard_return_holo.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/sym_keyboard_return_holo.png
rename to packages/Keyguard/res/drawable-xhdpi/sym_keyboard_return_holo.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
new file mode 100644
index 0000000..f4e398b
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable/ic_action_assist_generic.xml b/packages/Keyguard/res/drawable/ic_action_assist_generic.xml
new file mode 100644
index 0000000..60f5d5d
--- /dev/null
+++ b/packages/Keyguard/res/drawable/ic_action_assist_generic.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_action_assist_generic_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_action_assist_generic_activated" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="true"
+        android:drawable="@drawable/ic_action_assist_generic_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_camera.xml b/packages/Keyguard/res/drawable/ic_lockscreen_camera.xml
similarity index 100%
rename from core/res/res/drawable/ic_lockscreen_camera.xml
rename to packages/Keyguard/res/drawable/ic_lockscreen_camera.xml
diff --git a/core/res/res/drawable/ic_lockscreen_handle.xml b/packages/Keyguard/res/drawable/ic_lockscreen_handle.xml
similarity index 100%
rename from core/res/res/drawable/ic_lockscreen_handle.xml
rename to packages/Keyguard/res/drawable/ic_lockscreen_handle.xml
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_outerring.xml b/packages/Keyguard/res/drawable/ic_lockscreen_outerring.xml
new file mode 100644
index 0000000..75bea70
--- /dev/null
+++ b/packages/Keyguard/res/drawable/ic_lockscreen_outerring.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval"
+    >
+    <size android:height="@dimen/keyguard_lockscreen_outerring_diameter"
+          android:width="@dimen/keyguard_lockscreen_outerring_diameter" />
+    <solid android:color="#00000000" />
+    <stroke android:color="#1affffff" android:width="2dp" />
+</shape>
diff --git a/core/res/res/drawable/ic_lockscreen_silent.xml b/packages/Keyguard/res/drawable/ic_lockscreen_silent.xml
similarity index 100%
rename from core/res/res/drawable/ic_lockscreen_silent.xml
rename to packages/Keyguard/res/drawable/ic_lockscreen_silent.xml
diff --git a/core/res/res/drawable/ic_lockscreen_soundon.xml b/packages/Keyguard/res/drawable/ic_lockscreen_soundon.xml
similarity index 100%
rename from core/res/res/drawable/ic_lockscreen_soundon.xml
rename to packages/Keyguard/res/drawable/ic_lockscreen_soundon.xml
diff --git a/core/res/res/drawable/ic_lockscreen_unlock.xml b/packages/Keyguard/res/drawable/ic_lockscreen_unlock.xml
similarity index 100%
rename from core/res/res/drawable/ic_lockscreen_unlock.xml
rename to packages/Keyguard/res/drawable/ic_lockscreen_unlock.xml
diff --git a/core/res/res/drawable/ic_lockscreen_unlock_phantom.xml b/packages/Keyguard/res/drawable/ic_lockscreen_unlock_phantom.xml
similarity index 100%
rename from core/res/res/drawable/ic_lockscreen_unlock_phantom.xml
rename to packages/Keyguard/res/drawable/ic_lockscreen_unlock_phantom.xml
diff --git a/core/res/res/drawable/keyguard_add_widget_button.xml b/packages/Keyguard/res/drawable/keyguard_add_widget_button.xml
similarity index 100%
rename from core/res/res/drawable/keyguard_add_widget_button.xml
rename to packages/Keyguard/res/drawable/keyguard_add_widget_button.xml
diff --git a/core/res/res/drawable/keyguard_expand_challenge_handle.xml b/packages/Keyguard/res/drawable/keyguard_expand_challenge_handle.xml
similarity index 100%
rename from core/res/res/drawable/keyguard_expand_challenge_handle.xml
rename to packages/Keyguard/res/drawable/keyguard_expand_challenge_handle.xml
diff --git a/core/res/res/drawable/lockscreen_emergency_button.xml b/packages/Keyguard/res/drawable/lockscreen_emergency_button.xml
similarity index 100%
rename from core/res/res/drawable/lockscreen_emergency_button.xml
rename to packages/Keyguard/res/drawable/lockscreen_emergency_button.xml
diff --git a/core/res/res/drawable/lockscreen_forgot_password_button.xml b/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml
similarity index 100%
rename from core/res/res/drawable/lockscreen_forgot_password_button.xml
rename to packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml
diff --git a/packages/Keyguard/res/layout-land/keyguard_host_view.xml b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
new file mode 100644
index 0000000..eeb9ee7
--- /dev/null
+++ b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
@@ -0,0 +1,81 @@
+<?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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+    and the security view. -->
+<com.android.keyguard.KeyguardHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_host_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <com.android.keyguard.MultiPaneChallengeLayout
+        android:id="@+id/multi_pane_challenge"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:clipChildren="false">
+
+        <include layout="@layout/keyguard_widget_remove_drop_target"
+            android:id="@+id/keyguard_widget_pager_delete_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            androidprv:layout_childType="pageDeleteDropTarget" />
+
+        <include layout="@layout/keyguard_widget_pager"
+            android:id="@+id/app_widget_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            androidprv:layout_centerWithinArea="0.55"
+            androidprv:layout_childType="widget"
+            androidprv:layout_maxWidth="480dp"
+            androidprv:layout_maxHeight="480dp" />
+        <include layout="@layout/keyguard_multi_user_selector"/>
+
+        <View android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              androidprv:layout_childType="scrim"
+              android:background="#99000000" />
+
+        <com.android.keyguard.KeyguardSecurityContainer
+            android:id="@+id/keyguard_security_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_childType="challenge"
+            androidprv:layout_centerWithinArea="0.55">
+            <com.android.keyguard.KeyguardSecurityViewFlipper
+                android:id="@+id/view_flipper"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingLeft="@dimen/keyguard_security_view_margin"
+                android:paddingTop="@dimen/keyguard_security_view_margin"
+                android:paddingRight="@dimen/keyguard_security_view_margin"
+                android:paddingBottom="@dimen/keyguard_security_view_margin"
+                android:gravity="center">
+            </com.android.keyguard.KeyguardSecurityViewFlipper>
+        </com.android.keyguard.KeyguardSecurityContainer>
+
+    </com.android.keyguard.MultiPaneChallengeLayout>
+</com.android.keyguard.KeyguardHostView>
+
diff --git a/packages/Keyguard/res/layout-land/keyguard_status_area.xml b/packages/Keyguard/res/layout-land/keyguard_status_area.xml
new file mode 100644
index 0000000..d450c5c
--- /dev/null
+++ b/packages/Keyguard/res/layout-land/keyguard_status_area.xml
@@ -0,0 +1,58 @@
+<?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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_status_area"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="end"
+    android:layout_marginTop="-16dp"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="end"
+        android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/kg_status_date_font_size"
+        android:textAllCaps="@bool/kg_use_all_caps"
+        />
+
+    <TextView
+        android:id="@+id/alarm_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="end"
+        android:layout_marginTop="28dp"
+        android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearance"
+        android:textSize="@dimen/kg_status_line_font_size"
+        android:drawablePadding="4dip"
+        android:textAllCaps="@bool/kg_use_all_caps"
+        />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml b/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml
new file mode 100644
index 0000000..da31065
--- /dev/null
+++ b/packages/Keyguard/res/layout-land/keyguard_widget_pager.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.
+*/
+-->
+
+<!-- This is the selector widget that allows the user to select an action. -->
+<com.android.keyguard.KeyguardWidgetCarousel
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:paddingLeft="25dp"
+    android:paddingRight="25dp"
+    android:paddingTop="25dp"
+    android:paddingBottom="25dp"
+    android:clipToPadding="false"
+    androidprv:pageSpacing="10dp">
+</com.android.keyguard.KeyguardWidgetCarousel>
diff --git a/packages/Keyguard/res/layout-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
new file mode 100644
index 0000000..8498dcf
--- /dev/null
+++ b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
@@ -0,0 +1,94 @@
+<?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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+    and the security view. -->
+<com.android.keyguard.KeyguardHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_host_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal"
+    android:orientation="vertical">
+
+    <com.android.keyguard.SlidingChallengeLayout
+        android:id="@+id/sliding_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            androidprv:layout_childType="pageDeleteDropTarget">
+            <include layout="@layout/keyguard_widget_remove_drop_target"
+                android:id="@+id/keyguard_widget_pager_delete_target"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="top|center_horizontal" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            androidprv:layout_childType="widgets">
+            <include layout="@layout/keyguard_widget_pager"
+                android:id="@+id/app_widget_container"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"/>
+        </FrameLayout>
+
+        <View android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              androidprv:layout_childType="scrim"
+              android:background="#99000000" />
+
+        <com.android.keyguard.KeyguardSecurityContainer
+            android:id="@+id/keyguard_security_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+            androidprv:layout_childType="challenge"
+            android:padding="0dp"
+            android:gravity="bottom|center_horizontal">
+            <com.android.keyguard.KeyguardSecurityViewFlipper
+                android:id="@+id/view_flipper"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingTop="@dimen/keyguard_security_view_margin"
+                android:gravity="center">
+            </com.android.keyguard.KeyguardSecurityViewFlipper>
+        </com.android.keyguard.KeyguardSecurityContainer>
+
+        <ImageButton
+              android:layout_width="match_parent"
+              android:layout_height="@dimen/kg_widget_pager_bottom_padding"
+              androidprv:layout_childType="expandChallengeHandle"
+              android:focusable="true"
+              android:background="@null"
+              android:src="@drawable/keyguard_expand_challenge_handle"
+              android:scaleType="center"
+              android:contentDescription="@string/keyguard_accessibility_expand_lock_area" />
+
+    </com.android.keyguard.SlidingChallengeLayout>
+</com.android.keyguard.KeyguardHostView>
+
diff --git a/packages/Keyguard/res/layout-port/keyguard_status_area.xml b/packages/Keyguard/res/layout-port/keyguard_status_area.xml
new file mode 100644
index 0000000..af0d2e8
--- /dev/null
+++ b/packages/Keyguard/res/layout-port/keyguard_status_area.xml
@@ -0,0 +1,61 @@
+<?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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_status_area"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="right"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="0dp"
+        android:layout_gravity="right">
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@dimen/kg_status_date_font_size"
+            android:textAllCaps="@bool/kg_use_all_caps"
+            />
+
+        <TextView
+            android:id="@+id/alarm_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearance"
+            android:textSize="@dimen/kg_status_line_font_size"
+            android:drawablePadding="4dip"
+            android:textAllCaps="@bool/kg_use_all_caps"
+            />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml b/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
new file mode 100644
index 0000000..d0a07ca
--- /dev/null
+++ b/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
@@ -0,0 +1,31 @@
+<?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.
+*/
+-->
+
+<!-- This is the selector widget that allows the user to select an action. -->
+<com.android.keyguard.KeyguardWidgetPager
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/app_widget_container"
+    android:paddingLeft="25dp"
+    android:paddingRight="25dp"
+    android:paddingTop="25dp"
+    android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
+    android:clipToPadding="false"
+    androidprv:pageSpacing="10dp">
+</com.android.keyguard.KeyguardWidgetPager>
diff --git a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
new file mode 100644
index 0000000..77bc9b5
--- /dev/null
+++ b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -0,0 +1,82 @@
+<?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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+    and the security view. -->
+<com.android.keyguard.KeyguardHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_host_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <com.android.keyguard.MultiPaneChallengeLayout
+        android:id="@+id/multi_pane_challenge"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        android:orientation="vertical">
+
+        <include layout="@layout/keyguard_widget_remove_drop_target"
+            android:id="@+id/keyguard_widget_pager_delete_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            androidprv:layout_childType="pageDeleteDropTarget" />
+
+        <include layout="@layout/keyguard_widget_pager"
+            android:id="@+id/app_widget_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            androidprv:layout_centerWithinArea="0.5"
+            androidprv:layout_childType="widget"
+            androidprv:layout_maxWidth="480dp"
+            androidprv:layout_maxHeight="480dp" />
+
+        <include layout="@layout/keyguard_multi_user_selector"/>
+
+        <View android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              androidprv:layout_childType="scrim"
+              android:background="#99000000" />
+
+        <com.android.keyguard.KeyguardSecurityContainer
+            android:id="@+id/keyguard_security_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_centerWithinArea="0.5"
+            androidprv:layout_childType="challenge"
+            android:layout_gravity="center_horizontal|bottom">
+            <com.android.keyguard.KeyguardSecurityViewFlipper
+                android:id="@+id/view_flipper"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingLeft="@dimen/keyguard_security_view_margin"
+                android:paddingTop="@dimen/keyguard_security_view_margin"
+                android:paddingRight="@dimen/keyguard_security_view_margin"
+                android:paddingBottom="@dimen/keyguard_security_view_margin"
+                android:gravity="center">
+            </com.android.keyguard.KeyguardSecurityViewFlipper>
+        </com.android.keyguard.KeyguardSecurityContainer>
+
+    </com.android.keyguard.MultiPaneChallengeLayout>
+</com.android.keyguard.KeyguardHostView>
diff --git a/core/res/res/layout-sw600dp/keyguard_glow_pad_container.xml b/packages/Keyguard/res/layout-sw600dp/keyguard_glow_pad_container.xml
similarity index 100%
rename from core/res/res/layout-sw600dp/keyguard_glow_pad_container.xml
rename to packages/Keyguard/res/layout-sw600dp/keyguard_glow_pad_container.xml
diff --git a/packages/Keyguard/res/layout/keyguard_account_view.xml b/packages/Keyguard/res/layout/keyguard_account_view.xml
new file mode 100644
index 0000000..766effa
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_account_view.xml
@@ -0,0 +1,88 @@
+<?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.
+*/
+-->
+<com.android.keyguard.KeyguardAccountView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_account_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:orientation="vertical">
+
+    <include layout="@layout/keyguard_message_area"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1">
+
+        <EditText
+            android:id="@+id/login"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dip"
+            android:layout_marginStart="7dip"
+            android:layout_marginEnd="7dip"
+            android:layout_alignParentTop="true"
+            android:hint="@string/kg_login_username_hint"
+            android:inputType="textEmailAddress"
+            />
+
+        <EditText
+            android:id="@+id/password"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/login"
+            android:layout_toLeftOf="@+id/ok"
+            android:layout_marginTop="15dip"
+            android:layout_marginStart="7dip"
+            android:layout_marginEnd="7dip"
+            android:inputType="textPassword"
+            android:hint="@string/kg_login_password_hint"
+            android:nextFocusRight="@+id/ok"
+            android:nextFocusDown="@+id/ok"
+            />
+
+        <!-- ok below password, aligned to right of screen -->
+        <Button
+            android:id="@+id/ok"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="7dip"
+            android:layout_alignParentEnd="true"
+            android:layout_below="@id/login"
+            android:text="@string/kg_login_submit_button"
+            />
+
+    </RelativeLayout>
+
+    <!--  no room for ECA on this screen right now
+    <include layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="bottom|center_horizontal"
+        android:gravity="center_horizontal" />
+    -->
+
+</com.android.keyguard.KeyguardAccountView>
diff --git a/packages/Keyguard/res/layout/keyguard_add_widget.xml b/packages/Keyguard/res/layout/keyguard_add_widget.xml
new file mode 100644
index 0000000..01b616c
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_add_widget.xml
@@ -0,0 +1,42 @@
+<?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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.keyguard.KeyguardWidgetFrame
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_add_widget"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+    <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:contentDescription="@string/keyguard_accessibility_widget_empty_slot"
+            >
+        <ImageView
+            android:id="@+id/keyguard_add_widget_view"
+            android:clickable="true"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:padding="24dp"
+            android:src="@drawable/keyguard_add_widget_button"
+            android:contentDescription="@string/keyguard_accessibility_add_widget"/>
+    </FrameLayout>
+</com.android.keyguard.KeyguardWidgetFrame>
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
new file mode 100644
index 0000000..313fe9f
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -0,0 +1,79 @@
+<?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.
+*/
+-->
+
+<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
+<com.android.keyguard.EmergencyCarrierArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center"
+    android:layout_gravity="center_horizontal"
+    android:layout_alignParentBottom="true"
+    android:clickable="true">
+
+    <com.android.keyguard.CarrierText
+        android:id="@+id/carrier_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/kg_status_line_font_size"
+        android:textColor="?android:attr/textColorSecondary"
+        android:textAllCaps="@bool/kg_use_all_caps" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="-10dip"
+        style="?android:attr/buttonBarStyle"
+        android:orientation="horizontal"
+        android:gravity="center"
+        android:weightSum="2">
+
+        <com.android.keyguard.EmergencyButton
+            android:id="@+id/emergency_call_button"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:drawableLeft="@drawable/lockscreen_emergency_button"
+            android:text="@string/kg_emergency_call_label"
+            style="?android:attr/buttonBarButtonStyle"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@dimen/kg_status_line_font_size"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="8dip" 
+            android:textAllCaps="@bool/kg_use_all_caps" />
+
+        <Button android:id="@+id/forgot_password_button"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:drawableLeft="@drawable/lockscreen_forgot_password_button"
+            style="?android:attr/buttonBarButtonStyle"
+            android:textSize="@dimen/kg_status_line_font_size"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:drawablePadding="8dip"
+            android:visibility="gone"
+            android:textAllCaps="@bool/kg_use_all_caps" />
+    </LinearLayout>
+
+</com.android.keyguard.EmergencyCarrierArea>
diff --git a/core/res/res/layout/keyguard_emergency_carrier_area_empty.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area_empty.xml
similarity index 100%
rename from core/res/res/layout/keyguard_emergency_carrier_area_empty.xml
rename to packages/Keyguard/res/layout/keyguard_emergency_carrier_area_empty.xml
diff --git a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
new file mode 100644
index 0000000..94c68a5
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
@@ -0,0 +1,79 @@
+<?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.
+*/
+-->
+
+<!-- This is the screen that allows the user to unlock by showing their face.  -->
+<com.android.keyguard.KeyguardFaceUnlockView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_face_unlock_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:contentDescription="@string/keyguard_accessibility_face_unlock">
+
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+
+    <FrameLayout
+       android:id="@+id/keyguard_bouncer_frame"
+       android:background="@drawable/kg_bouncer_bg_white"
+       android:layout_width="match_parent"
+       android:layout_height="0dp"
+       android:layout_weight="1"
+       >
+       <com.android.internal.widget.FaceUnlockView
+           android:id="@+id/face_unlock_area_view"
+           android:layout_width="match_parent"
+           android:layout_height="match_parent"
+           android:layout_gravity="center_horizontal"
+           android:background="@drawable/intro_bg"
+           android:gravity="center">
+
+           <View
+               android:id="@+id/spotlightMask"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent"
+               android:background="@color/facelock_spotlight_mask"
+           />
+
+           <ImageButton
+               android:id="@+id/face_unlock_cancel_button"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:padding="5dip"
+               android:layout_alignParentTop="true"
+               android:layout_alignParentEnd="true"
+               android:background="#00000000"
+               android:src="@drawable/ic_facial_backup"
+           />
+       </com.android.internal.widget.FaceUnlockView>
+    </FrameLayout>
+
+    <include layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="bottom|center_horizontal"
+        android:gravity="center_horizontal" />
+</com.android.keyguard.KeyguardFaceUnlockView>
diff --git a/packages/Keyguard/res/layout/keyguard_glow_pad_container.xml b/packages/Keyguard/res/layout/keyguard_glow_pad_container.xml
new file mode 100644
index 0000000..07953b4
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_glow_pad_container.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <include layout="@layout/keyguard_glow_pad_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginBottom="@dimen/glowpadcontainer_bottom_margin"/>
+</merge>
diff --git a/packages/Keyguard/res/layout/keyguard_glow_pad_view.xml b/packages/Keyguard/res/layout/keyguard_glow_pad_view.xml
new file mode 100644
index 0000000..3a466dd
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_glow_pad_view.xml
@@ -0,0 +1,46 @@
+<?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.
+*/
+-->
+
+<!-- This is the selector widget that allows the user to select an action. -->
+<com.android.internal.widget.multiwaveview.GlowPadView
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/glow_pad_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:orientation="horizontal"
+    android:gravity="@integer/kg_selector_gravity"
+    android:contentDescription="@string/keyguard_accessibility_slide_area"
+
+    prvandroid:targetDrawables="@array/lockscreen_targets_unlock_only"
+    prvandroid:targetDescriptions="@array/lockscreen_target_descriptions_unlock_only"
+    prvandroid:directionDescriptions="@array/lockscreen_direction_descriptions"
+    prvandroid:handleDrawable="@drawable/ic_lockscreen_handle"
+    prvandroid:outerRingDrawable="@drawable/ic_lockscreen_outerring"
+    prvandroid:outerRadius="@dimen/glowpadview_target_placement_radius"
+    prvandroid:innerRadius="@dimen/glowpadview_inner_radius"
+    prvandroid:snapMargin="@dimen/glowpadview_snap_margin"
+    prvandroid:firstItemOffset="@integer/kg_glowpad_rotation_offset"
+    prvandroid:magneticTargets="true"
+    prvandroid:feedbackCount="1"
+    prvandroid:vibrationDuration="20"
+    prvandroid:glowRadius="@dimen/glowpadview_glow_radius"
+    prvandroid:pointDrawable="@drawable/ic_lockscreen_glowdot"
+    prvandroid:allowScaling="true" />
diff --git a/packages/Keyguard/res/layout/keyguard_message_area.xml b/packages/Keyguard/res/layout/keyguard_message_area.xml
new file mode 100644
index 0000000..a709e98
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_message_area.xml
@@ -0,0 +1,33 @@
+<?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.
+*/
+-->
+
+<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
+<com.android.keyguard.KeyguardMessageArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:id="@+id/keyguard_message_area"
+    android:singleLine="true"
+    android:ellipsize="marquee"
+    android:textAppearance="?android:attr/textAppearance"
+    android:textSize="@dimen/kg_status_line_font_size"
+    android:textColor="?android:attr/textColorSecondary"
+    android:clickable="true" />
+
diff --git a/packages/Keyguard/res/layout/keyguard_message_area_large.xml b/packages/Keyguard/res/layout/keyguard_message_area_large.xml
new file mode 100644
index 0000000..ab6246d
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_message_area_large.xml
@@ -0,0 +1,31 @@
+<?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.
+*/
+-->
+
+<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
+<com.android.keyguard.KeyguardMessageArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:id="@+id/keyguard_message_area"
+    android:maxLines="4"
+    android:textAppearance="?android:attr/textAppearance"
+    android:textSize="@dimen/kg_status_line_font_size"
+    android:textColor="?android:attr/textColorSecondary" />
+
diff --git a/packages/Keyguard/res/layout/keyguard_multi_user_avatar.xml b/packages/Keyguard/res/layout/keyguard_multi_user_avatar.xml
new file mode 100644
index 0000000..41b0be9
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_multi_user_avatar.xml
@@ -0,0 +1,45 @@
+<?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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.keyguard.KeyguardMultiUserAvatar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/keyguard_avatar_size"
+    android:layout_height="@dimen/keyguard_avatar_size"
+    android:background="#00000000"
+    android:gravity="center_horizontal">
+    <ImageView
+        android:id="@+id/keyguard_user_avatar"
+        android:scaleType="center"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"/>
+    <TextView
+       android:id="@+id/keyguard_user_name"
+       android:layout_width="match_parent"
+       android:layout_height="wrap_content"
+       android:layout_gravity="bottom"
+       android:gravity="center"
+       android:textSize="@dimen/keyguard_avatar_name_size"
+       android:textColor="#ffffff"
+       android:singleLine="true"
+       android:ellipsize="end"
+       android:paddingLeft="2dp"
+       android:paddingRight="2dp" />
+</com.android.keyguard.KeyguardMultiUserAvatar>
diff --git a/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml b/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
new file mode 100644
index 0000000..c1d5326
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
@@ -0,0 +1,39 @@
+<?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.
+*/
+-->
+<com.android.keyguard.KeyguardMultiUserSelectorView
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    androidprv:layout_childType="userSwitcher"
+    android:id="@+id/keyguard_user_selector"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="bottom"
+    android:contentDescription="@string/keyguard_accessibility_user_selector"
+    android:visibility="gone">
+
+    <com.android.keyguard.KeyguardLinearLayout
+        android:id="@+id/keyguard_users_grid"
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_marginBottom="@dimen/keyguard_muliuser_selector_margin"
+        android:layout_height="@dimen/keyguard_avatar_size"
+        android:layout_gravity="center|bottom" />
+
+</com.android.keyguard.KeyguardMultiUserSelectorView>
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
new file mode 100644
index 0000000..d8012bf
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<com.android.keyguard.KeyguardPasswordView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_password_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:gravity="bottom"
+    android:contentDescription="@string/keyguard_accessibility_password_unlock"
+    >
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        />
+
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <!-- Password entry field -->
+    <!-- Note: the entire container is styled to look like the edit field,
+         since the backspace/IME switcher looks better inside -->
+      <FrameLayout
+         android:id="@+id/keyguard_bouncer_frame"
+         android:background="@drawable/kg_bouncer_bg_white"
+         android:layout_height="wrap_content"
+         android:layout_width="match_parent"
+         >
+         <LinearLayout
+             android:layout_height="wrap_content"
+             android:layout_width="match_parent"
+             android:orientation="horizontal"
+             android:background="#70000000"
+             android:layout_marginTop="8dp"
+             android:layout_marginBottom="8dp"
+             >
+
+             <EditText android:id="@+id/passwordEntry"
+                 android:layout_width="0dip"
+                 android:layout_height="wrap_content"
+                 android:layout_weight="1"
+                 android:gravity="center_horizontal"
+                 android:layout_gravity="center_vertical"
+                 android:layout_marginStart="@dimen/keyguard_lockscreen_pin_margin_left"
+                 android:singleLine="true"
+                 android:textStyle="normal"
+                 android:inputType="textPassword"
+                 android:textSize="36sp"
+                 android:background="@null"
+                 android:textAppearance="?android:attr/textAppearanceMedium"
+                 android:textColor="#ffffffff"
+                 android:imeOptions="flagForceAscii|actionDone"
+                 />
+
+             <ImageView android:id="@+id/switch_ime_button"
+                 android:layout_width="wrap_content"
+                 android:layout_height="wrap_content"
+                 android:src="@drawable/ic_lockscreen_ime"
+                 android:clickable="true"
+                 android:padding="8dip"
+                 android:layout_gravity="center"
+                 android:background="?android:attr/selectableItemBackground"
+                 android:visibility="gone"
+                 />
+
+            </LinearLayout>
+       </FrameLayout>
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        />
+
+    <include layout="@layout/keyguard_eca"
+             android:id="@+id/keyguard_selector_fade_container"
+             android:layout_width="match_parent"
+             android:layout_height="wrap_content"
+             android:orientation="vertical"
+             android:layout_gravity="bottom|center_horizontal"
+             android:gravity="center_horizontal" />
+
+</com.android.keyguard.KeyguardPasswordView>
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
new file mode 100644
index 0000000..0c9380c
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -0,0 +1,79 @@
+<?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.
+*/
+-->
+
+<!-- This is the screen that shows the 9 circle unlock widget and instructs
+     the user how to unlock their device, or make an emergency call.  This
+     is the portrait layout.  -->
+<com.android.keyguard.KeyguardPatternView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_pattern_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:gravity="center_horizontal"
+    android:contentDescription="@string/keyguard_accessibility_pattern_unlock">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:orientation="vertical"
+            android:layout_gravity="center">
+
+            <include layout="@layout/keyguard_message_area"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+               />
+
+          <FrameLayout
+             android:id="@+id/keyguard_bouncer_frame"
+             android:background="@drawable/kg_bouncer_bg_white"
+             android:layout_width="match_parent"
+             android:layout_height="0dp"
+             android:layout_weight="1"
+             >
+            <com.android.internal.widget.LockPatternView
+                android:id="@+id/lockPatternView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:layout_marginEnd="8dip"
+                android:layout_marginBottom="4dip"
+                android:layout_marginStart="8dip"
+                android:layout_gravity="center_horizontal"
+                android:gravity="center"
+                android:contentDescription="@string/keyguard_accessibility_pattern_area" />
+          </FrameLayout>
+          <include layout="@layout/keyguard_eca"
+              android:id="@+id/keyguard_selector_fade_container"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical"
+              android:layout_gravity="bottom|center_horizontal"
+              android:gravity="center_horizontal" />
+        </LinearLayout>
+    </FrameLayout>
+
+</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/Keyguard/res/layout/keyguard_pin_view.xml b/packages/Keyguard/res/layout/keyguard_pin_view.xml
new file mode 100644
index 0000000..00c6a21
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_pin_view.xml
@@ -0,0 +1,224 @@
+<?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.
+*/
+-->
+
+<com.android.keyguard.KeyguardPINView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_pin_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:orientation="vertical"
+    android:contentDescription="@string/keyguard_accessibility_pin_unlock"
+    >
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+    <LinearLayout
+       android:id="@+id/keyguard_bouncer_frame"
+       android:background="@drawable/kg_bouncer_bg_white"
+       android:layout_width="match_parent"
+       android:layout_height="0dp"
+       android:orientation="vertical"
+       android:layout_weight="1"
+       android:layoutDirection="ltr"
+       >
+       <LinearLayout
+          android:layout_width="match_parent"
+          android:layout_height="0dp"
+          android:orientation="horizontal"
+          android:layout_weight="1"
+          >
+          <TextView android:id="@+id/pinEntry"
+               android:editable="true"
+               android:layout_width="0dip"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               android:gravity="center"
+               android:layout_marginStart="@dimen/keyguard_lockscreen_pin_margin_left"
+               android:singleLine="true"
+               android:cursorVisible="false"
+               android:background="@null"
+               android:textAppearance="@style/TextAppearance.NumPadKey"
+               android:imeOptions="flagForceAscii|actionDone"
+               />
+           <ImageButton android:id="@+id/delete_button"
+               android:layout_width="wrap_content"
+               android:layout_height="match_parent"
+               android:gravity="center_vertical"
+               android:src="@drawable/ic_input_delete"
+               android:clickable="true"
+               android:paddingTop="8dip"
+               android:paddingBottom="8dip"
+               android:paddingLeft="24dp"
+               android:paddingRight="24dp"
+               android:background="?android:attr/selectableItemBackground"
+               android:contentDescription="@string/keyboardview_keycode_delete"
+               />
+       </LinearLayout>
+       <View
+           android:layout_width="wrap_content"
+           android:layout_height="1dp"
+           android:background="#55FFFFFF"
+           />
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key1"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="1"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key2"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="2"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key3"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="3"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key4"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="4"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key5"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="5"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key6"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="6"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:orientation="horizontal"
+           android:layout_weight="1"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key7"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="7"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key8"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="8"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key9"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="9"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <Space
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key0"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="0"
+               />
+           <ImageButton
+               android:id="@+id/key_enter"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               android:paddingRight="30dp"
+               android:src="@drawable/sym_keyboard_return_holo"
+               android:contentDescription="@string/keyboardview_keycode_enter"
+               />
+       </LinearLayout>
+    </LinearLayout>
+    <include layout="@layout/keyguard_eca"
+                   android:id="@+id/keyguard_selector_fade_container"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content"
+                   android:orientation="vertical"
+                   android:layout_gravity="bottom|center_horizontal"
+                   android:gravity="center_horizontal" />
+
+</com.android.keyguard.KeyguardPINView>
diff --git a/packages/Keyguard/res/layout/keyguard_selector_view.xml b/packages/Keyguard/res/layout/keyguard_selector_view.xml
new file mode 100644
index 0000000..6cb5e67
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_selector_view.xml
@@ -0,0 +1,64 @@
+<?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.
+*/
+-->
+
+<!-- This is the selector widget that allows the user to select an action. -->
+<com.android.keyguard.KeyguardSelectorView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_selector_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="420dp"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="vertical"
+    android:contentDescription="@string/keyguard_accessibility_slide_unlock">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:gravity="center">
+
+        <include layout="@layout/keyguard_message_area"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <View
+            android:id="@+id/keyguard_selector_view_frame"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginLeft="16dp"
+            android:layout_marginRight="16dp"
+            android:background="@drawable/kg_bouncer_bg_white"/>
+
+        <include layout="@layout/keyguard_glow_pad_container" />
+
+        <include layout="@layout/keyguard_eca"
+            android:id="@+id/keyguard_selector_fade_container"
+            android:layout_width="match_parent"
+            android:layout_height="48dp"
+            android:layout_gravity="bottom|center_horizontal" />
+    </FrameLayout>
+
+</com.android.keyguard.KeyguardSelectorView>
+
diff --git a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
new file mode 100644
index 0000000..eccac19
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
@@ -0,0 +1,230 @@
+<?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.
+*/
+-->
+<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
+<com.android.keyguard.KeyguardSimPinView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_sim_pin_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:gravity="center_horizontal">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_lockscreen_sim"/>
+
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+    <LinearLayout
+       android:id="@+id/keyguard_bouncer_frame"
+       android:background="@drawable/kg_bouncer_bg_white"
+       android:layout_width="match_parent"
+       android:layout_height="0dp"
+       android:orientation="vertical"
+       android:layout_weight="1"
+       android:layoutDirection="ltr"
+       >
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:orientation="horizontal"
+           android:layout_weight="1"
+           >
+           <TextView android:id="@+id/pinEntry"
+               android:editable="true"
+               android:layout_width="0dip"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               android:gravity="center"
+               android:layout_marginStart="@dimen/keyguard_lockscreen_pin_margin_left"
+               android:singleLine="true"
+               android:cursorVisible="false"
+               android:background="@null"
+               android:textAppearance="@style/TextAppearance.NumPadKey"
+               android:imeOptions="flagForceAscii|actionDone"
+               />
+           <ImageButton android:id="@+id/delete_button"
+               android:layout_width="wrap_content"
+               android:layout_height="match_parent"
+               android:gravity="center_vertical"
+               android:src="@drawable/ic_input_delete"
+               android:clickable="true"
+               android:paddingTop="8dip"
+               android:paddingBottom="8dip"
+               android:paddingLeft="24dp"
+               android:paddingRight="24dp"
+               android:background="?android:attr/selectableItemBackground"
+               android:contentDescription="@string/keyboardview_keycode_delete"
+               />
+       </LinearLayout>
+       <View
+           android:layout_width="wrap_content"
+           android:layout_height="1dp"
+           android:background="#55FFFFFF"
+           />
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key1"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="1"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key2"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="2"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key3"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="3"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key4"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="4"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key5"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="5"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key6"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="6"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:orientation="horizontal"
+           android:layout_weight="1"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key7"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="7"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key8"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="8"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key9"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="9"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <Space
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key0"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="0"
+               />
+           <ImageButton
+               android:id="@+id/key_enter"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               android:paddingRight="30dp"
+               android:src="@drawable/sym_keyboard_return_holo"
+               android:contentDescription="@string/keyboardview_keycode_enter"
+               />
+       </LinearLayout>
+    </LinearLayout>
+
+    <include layout="@layout/keyguard_eca"
+                   android:id="@+id/keyguard_selector_fade_container"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content"
+                   android:orientation="vertical"
+                   android:layout_gravity="bottom|center_horizontal"
+                   android:gravity="center_horizontal" />
+
+</com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
new file mode 100644
index 0000000..fe37203
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<!-- This is the SIM PUK view that allows the user to recover their device by entering the
+    carrier-provided PUK code and entering a new SIM PIN for it. -->
+<com.android.keyguard.KeyguardSimPukView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_sim_puk_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:gravity="center_horizontal">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_lockscreen_sim"/>
+
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+    <LinearLayout
+       android:id="@+id/keyguard_bouncer_frame"
+       android:background="@drawable/kg_bouncer_bg_white"
+       android:layout_width="match_parent"
+       android:layout_height="0dp"
+       android:orientation="vertical"
+       android:layout_weight="1"
+       android:layoutDirection="ltr"
+       >
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:orientation="horizontal"
+           android:layout_weight="1"
+           >
+           <TextView android:id="@+id/pinEntry"
+               android:editable="true"
+               android:layout_width="0dip"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               android:gravity="center"
+               android:layout_marginStart="@dimen/keyguard_lockscreen_pin_margin_left"
+               android:singleLine="true"
+               android:cursorVisible="false"
+               android:background="@null"
+               android:textAppearance="@style/TextAppearance.NumPadKey"
+               android:imeOptions="flagForceAscii|actionDone"
+               />
+           <ImageButton android:id="@+id/delete_button"
+               android:layout_width="wrap_content"
+               android:layout_height="match_parent"
+               android:gravity="center_vertical"
+               android:src="@drawable/ic_input_delete"
+               android:clickable="true"
+               android:paddingTop="8dip"
+               android:paddingBottom="8dip"
+               android:paddingLeft="24dp"
+               android:paddingRight="24dp"
+               android:background="?android:attr/selectableItemBackground"
+               android:contentDescription="@string/keyboardview_keycode_delete"
+               />
+       </LinearLayout>
+       <View
+           android:layout_width="wrap_content"
+           android:layout_height="1dp"
+           android:background="#55FFFFFF"
+           />
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key1"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="1"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key2"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="2"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key3"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="3"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key4"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="4"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key5"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="5"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key6"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="6"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:orientation="horizontal"
+           android:layout_weight="1"
+           >
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key7"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="7"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key8"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="8"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key9"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="9"
+               />
+       </LinearLayout>
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_weight="1"
+           android:orientation="horizontal"
+           >
+           <Space
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               />
+           <view class="com.android.keyguard.NumPadKey"
+               android:id="@+id/key0"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               androidprv:textView="@+id/pinEntry"
+               androidprv:digit="0"
+               />
+           <ImageButton
+               android:id="@+id/key_enter"
+               style="@style/Widget.Button.NumPadKey"
+               android:layout_width="0px"
+               android:layout_height="match_parent"
+               android:layout_weight="1"
+               android:paddingRight="30dp"
+               android:src="@drawable/sym_keyboard_return_holo"
+               android:contentDescription="@string/keyboardview_keycode_enter"
+               />
+       </LinearLayout>
+    </LinearLayout>
+
+    <include layout="@layout/keyguard_eca"
+                   android:id="@+id/keyguard_selector_fade_container"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content"
+                   android:orientation="vertical"
+                   android:layout_gravity="bottom|center_horizontal"
+                   android:gravity="center_horizontal" />
+</com.android.keyguard.KeyguardSimPukView>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
new file mode 100644
index 0000000..2304d9f
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -0,0 +1,68 @@
+<?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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.keyguard.KeyguardWidgetFrame
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_status_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:gravity="center_horizontal">
+
+    <com.android.keyguard.KeyguardStatusView
+        android:id="@+id/keyguard_status_view_face_palm"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center_horizontal|top"
+        android:contentDescription="@string/keyguard_accessibility_status">
+
+        <LinearLayout android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_gravity="center_horizontal|top"
+                      android:orientation="vertical"
+                      android:focusable="true">
+            <com.android.keyguard.ClockView
+                android:id="@+id/clock_view"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
+                android:layout_gravity="right">
+
+                <TextView android:id="@+id/clock_text"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:singleLine="true"
+                          android:ellipsize="none"
+                          android:textSize="@dimen/kg_status_clock_font_size"
+                          android:textAppearance="?android:attr/textAppearanceMedium"
+                          android:textColor="#ffffffff"
+                          android:drawablePadding="2dip"
+                          />
+
+            </com.android.keyguard.ClockView>
+
+            <include layout="@layout/keyguard_status_area" />
+        </LinearLayout>
+
+    </com.android.keyguard.KeyguardStatusView>
+</com.android.keyguard.KeyguardWidgetFrame>
diff --git a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
new file mode 100644
index 0000000..801999a
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
@@ -0,0 +1,106 @@
+<?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.
+-->
+
+<!-- This is a view to control music playback in keyguard. -->
+<com.android.keyguard.KeyguardTransportControlView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal"
+    android:id="@+id/keyguard_transport_control">
+
+    <!-- Use ImageView for its cropping features; otherwise could be android:background -->
+    <ImageView
+        android:id="@+id/albumart"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="fill"
+        android:scaleType="centerCrop"
+        android:adjustViewBounds="false"
+        android:contentDescription="@string/keygaurd_accessibility_media_controls" />
+
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom">
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dip"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip"
+            android:gravity="center_horizontal"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+        />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginTop="5dip">
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1">
+                <ImageView
+                    android:id="@+id/btn_prev"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:src="@drawable/ic_media_previous"
+                    android:clickable="true"
+                    android:background="?android:attr/selectableItemBackground"
+                    android:padding="10dip"
+                    android:contentDescription="@string/keyguard_accessibility_transport_prev_description"/>
+            </FrameLayout>
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1">
+                <ImageView
+                    android:id="@+id/btn_play"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:clickable="true"
+                    android:src="@drawable/ic_media_play"
+                    android:background="?android:attr/selectableItemBackground"
+                    android:padding="10dip"
+                    android:contentDescription="@string/keyguard_accessibility_transport_play_description"/>
+            </FrameLayout>
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1">
+                <ImageView
+                    android:id="@+id/btn_next"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:clickable="true"
+                    android:src="@drawable/ic_media_next"
+                    android:background="?android:attr/selectableItemBackground"
+                    android:padding="10dip"
+                    android:contentDescription="@string/keyguard_accessibility_transport_next_description"/>
+            </FrameLayout>
+        </LinearLayout>
+    </LinearLayout>
+
+</com.android.keyguard.KeyguardTransportControlView>
diff --git a/core/res/res/layout/keyguard_widget_remove_drop_target.xml b/packages/Keyguard/res/layout/keyguard_widget_remove_drop_target.xml
similarity index 100%
rename from core/res/res/layout/keyguard_widget_remove_drop_target.xml
rename to packages/Keyguard/res/layout/keyguard_widget_remove_drop_target.xml
diff --git a/packages/Keyguard/res/values-af/activitystrings.xml b/packages/Keyguard/res/values-af/activitystrings.xml
new file mode 100644
index 0000000..f6e8d5e
--- /dev/null
+++ b/packages/Keyguard/res/values-af/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardToetsAktiwiteit"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"VerenigdeKamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Geen sekuriteit nie"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Wagwoord"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Patroon"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Kies legstuk…"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"opSkermAfgeskakel"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"opSkermAangeskakel"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doenKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifieerOntsluit"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
new file mode 100644
index 0000000..7e1f0bf
--- /dev/null
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Voer PIN-kode in"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Voer PUK en nuwe PIN-kode in"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kode"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nuwe PIN-kode"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Raak om wagwoord in te voer"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Voer wagwoord in om te ontsluit"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Voer PIN in om te ontsluit"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Verkeerde PIN-kode."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Geen SIM-kaart nie"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Geen SIM-kaart in tablet nie."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Geen SIM-kaart in foon nie."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Steek \'n SIM-kaart in."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Die SIM-kaart is weg of nie leesbaar nie. Steek \'n SIM-kaart in."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Onbruikbare SIM-kaart."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Jou SIM-kaart is permanent gedeaktiveer.\n Kontak jou draadlose diensverskaffer vir \'n ander SIM-kaart."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kaart is gesluit."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kaart is PUK-geslote."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ontsluit tans SIM-kaart…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Legstuk %2$d van %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Voeg legstuk by."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Leeg"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ontsluitruimte uitgevou."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ontsluitruimte ingevou."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-legstuk."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Gebruikerkieser"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media-kontroles"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Herordening van legstuk begin."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Herordening van legstuk beëindig."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Legstuk <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> uitgevee."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Vou ontsluitruimte uit."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Sleep-ontsluit."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Patroon ontsluit."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Gesigslot."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN ontsluit."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Wagwoord ontsluit."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Patroonarea."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Sleep-area."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Vorigesnit-knoppie"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Volgendesnit-knoppie"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Laatwag-knoppie"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Speel-knoppie"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop-knoppie"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselleer"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Vee uit"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Klaar"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modus verander"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Invoersleutel"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Ontsluit"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Stil"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Klank aan"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Gly af vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Gly links vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Gly regs vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Het jy die patroon vergeet?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Verkeerde patroon"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Verkeerde wagwoord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Verkeerde PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer weer oor <xliff:g id="NUMBER">%d</xliff:g> sekondes."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken jou patroon"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Voer SIM-PIN in"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Voer PIN in"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Voer wagwoord in"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Kontak diensverskaffer vir details."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Voer die gewenste PIN-kode in"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bevestig gewenste PIN-kode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ontsluit tans SIM-kaart…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Verkeerde PIN-kode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Tik \'n PIN in wat 4 tot 8 syfers lank is."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-kode moet 8 of meer syfers wees."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Voer weer die korrekte PUK-kode in. Herhaalde pogings sal die SIM permanent deaktiveer."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodes stem nie ooreen nie"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogings"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Om te ontsluit, meld met jou Google-rekening aan."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikernaam (e-pos)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Wagwoord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Meld aan"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikernaam of wagwoord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Het jy jou gebruikernaam of wagwoord vergeet?\nBesoek "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontroleer tans rekening..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik gepoog om die tablet te ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal die tablet na die fabrieksverstek teruggestel word en al die gebruikerdata sal verlore wees."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik gepoog om die foon te ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal die foon na die fabrieksverstek teruggestel word en al die gebruikerdata sal verlore wees."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Jy het <xliff:g id="NUMBER">%d</xliff:g> keer verkeerdelik gepoog om die tablet te ontsluit. Die tablet sal nou na fabrieksverstek teruggestel word."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Jy het <xliff:g id="NUMBER">%d</xliff:g> keer verkeerdelik gepoog om die foon te ontsluit. Die foon sal nou na fabrieksverstek teruggestel word."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwyder"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Vorigesnit-knoppie"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Volgendesnit-knoppie"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Laatwag-knoppie"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Speel-knoppie"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop-knoppie"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen diens nie."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-am/activitystrings.xml b/packages/Keyguard/res/values-am/activitystrings.xml
new file mode 100644
index 0000000..a6c7449
--- /dev/null
+++ b/packages/Keyguard/res/values-am/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"ምንም ደህንነት የለም"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"ፒን"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"የይለፍ ቃል"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"ሥርዓተ ጥለት"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"የሲም ፒን"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"የሲም ፒዩኬ"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"ንዑስ ፕሮግራም ይምረጡ..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
new file mode 100644
index 0000000..2f6dab0
--- /dev/null
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"ፒን ኮድ ተይብ"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK እና አዲስ ፒን ተይብ"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"የPUK ኮድ"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"አዲስ Pin ኮድ"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"የይለፍ ቃል ለመተየብ ንካ"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ለመክፈት የይለፍ ቃል ተይብ"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ለመክፈት ፒን ተይብ"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ PIN ኮድ።"</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_low_battery" msgid="8143808018719173859">"የኃይል መሙያዎን ይሰኩ።"</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ለመክፈት ምናሌውን ይጫኑ።"</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"አውታረ መረብ ተቆልፏል"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"ምንም ሲም ካርድ የለም"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"በጡባዊ ውስጥ ምንም ሲም ካርድ የለም።"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"በስልኩ ውስጥ ምንም ሲም ካርድ የለም።"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"ሲም ካርድ ያስገቡ።"</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"ሲም ካርዱ ጠፍቷል ወይም መነበብ አይችልም። እባክዎ ሲም ሲም ካርድ ያስገቡ።"</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"የማይሰራ ሲም ካርድ።"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"ሲም ካርድዎ እስከመጨረሻው ተሰናክሏል።\n ሌላ ሲም ካርድ ለማግኘት ከገመድ አልባ አገልግሎት አቅራቢዎ ጋር ይገናኙ።"</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ሲም ካርድ ተዘግቷል።"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ሲም ካርድ በፒዩኬ ተዘግቷል።"</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ሲም ካርዱን በመክፈት ላይ…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s። ምግብር %2$d ከ%3$d።"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ንዑስ ፕሮግራም አክል"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ባዶ"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"የመክፈቻ አካባቢ ተስፋፍቷል።"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"የመክፈቻ አካባቢ ተሰብስቧል።"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"የ<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ንዑስ ፕሮግራም።"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ተጠቃሚ መራጭ"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ሁኔታ"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ካሜራ"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"የሚዲያ መቆጣጠሪያዎች"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"የንዑስ ፕሮግራም ዳግም መደርደር ተጀምሯል።"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"የንዑስ ፕሮግራም ዳግም መደርደር አብቅቷል።"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ንዑስ ፕሮግራም <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ተሰርዟል።"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"የመክፈቻ አካባቢውን አስፋፋ።"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"በማንሸራተት ክፈት።"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"በስርዓተ-ጥለት መክፈት።"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"በፊት መክፈት።"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"በፒን መክፈት።"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"በይለፍ ቃል መክፈት።"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"የስርዓተ-ጥለት አካባቢ።"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"የማንሸራተቻ አካባቢ።"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"የቀዳሚ ትራክ አዝራር"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"የቀጣይ ትራክ አዝራር"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ለአፍታ አቁም አዝራር"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"የአጫውት አዝራር"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"አቁም አዝራር"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ተወው"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ተከናውኗል"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ሞድ ለውጥ"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ቀይር"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"አስገባ"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"ክፈት"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"ካሜራ"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"ፀጥታ"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"ድምፅ አብራ"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ታች አንሸራትት።"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ግራ አንሸራትት።"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ቀኝ አንሸራትት።"</string>
+    <string name="user_switched" msgid="3768006783166984410">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"የአደጋ ጊዜ ጥሪ"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ስርዓተ ጥለቱን እርሳ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"የተሳሳተ ስርዓተ ጥለት"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"የተሳሳተ ይለፍ ቃል"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"የተሳሳተ ፒን"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"በ<xliff:g id="NUMBER">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"ስርዓተ ጥለትዎን ይሳሉ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"የሲም ፒን ያስገቡ"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"ፒን ያስገቡ"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"የይለፍ ቃል ያስገቡ"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ለዝርዝር ድምጸ ተያያዥ ሞደምን ያግኙ።"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"የተፈለገውን የፒን ኮድ ያስገቡ"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"የተፈለገውን የፒን ኮድ ያረጋግጡ"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ሲም ካርዱን በመክፈት ላይ…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ትክክል ያልሆነ ፒን ኮድ።"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"የPUK ኮድ 8 ወይም ከዚያ በላይ ቁጥሮች ሊኖረው ይገባል።"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"ለመክፈት በGoogle መለያዎ ይግቡ።"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"የተጠቃሚ ስም (ኢሜይል)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"የይለፍ ቃል"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ግባ"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ልክ ያልሆነ የተጠቃሚ ስም ወይም የይለፍ ቃል።"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"የተጠቃሚ ስምዎን ወይም የይለፍ ቃልዎን ረሱት?\n"<b>"google.com/accounts/recovery"</b>"ይጎብኙ።"</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"መለያውን በማረጋገጥ ላይ…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"አስወግድ"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"የቀዳሚ ትራክ አዝራር"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"የቀጣይ ትራክ አዝራር"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ለአፍታ አቁም አዝራር"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"የአጫውት አዝራር"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"አቁም አዝራር"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ar/activitystrings.xml b/packages/Keyguard/res/values-ar/activitystrings.xml
new file mode 100644
index 0000000..f77d8f00
--- /dev/null
+++ b/packages/Keyguard/res/values-ar/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"بدون تأمين"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"رقم التعريف الشخصي"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"كلمة المرور"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"نقش"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"رقم التعريف الشخصي لبطاقة SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"رمز PUK لبطاقة SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"جارٍ اختيار أداة..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
new file mode 100644
index 0000000..bcfe7db
--- /dev/null
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"اكتب رمز رقم التعريف الشخصي"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"اكتب رمز PUK ورمز رقم التعريف الشخصي الجديد"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"رمز PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"رمز رقم التعريف الشخصي الجديد"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"المس لكتابة كلمة المرور"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"اكتب كلمة المرور لإلغاء التأمين"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"اكتب رقم التعريف الشخصي لإلغاء التأمين"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"رقم التعريف الشخصي غير صحيح."</string>
+    <string name="keyguard_label_text" msgid="861796461028298424">"لإلغاء التأمين، اضغط على \"القائمة\" ثم على 0."</string>
+    <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_low_battery" msgid="8143808018719173859">"توصيل جهاز الشحن."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"اضغط على \"القائمة\" لإلغاء القفل."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"الشبكة مؤمّنة"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"ليست هناك بطاقة SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"ليست هناك بطاقة SIM في الجهاز اللوحي."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"ليست هناك بطاقة SIM في الهاتف."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"أدخل بطاقة SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"بطاقة SIM مفقودة أو غير قابلة للقراءة. أدخل بطاقة SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"بطاقة SIM غير قابلة للاستخدام."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"تم تعطيل بطاقة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على بطاقة SIM أخرى."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"بطاقة SIM مؤمّنة."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"بطاقة SIM مؤمّنة بكود PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"جارٍ إلغاء تأمين بطاقة SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. الأداة %2$d من %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"إضافة أداة."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"فارغة"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"تم توسيع منطقة إلغاء القفل."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"تم تصغير منطقة إلغاء القفل."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"أداة <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"محدد المستخدم"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"الحالة"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"الكاميرا"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"أدوات التحكم في الوسائط"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"بدأت إعادة ترتيب الأدوات."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"انتهت إعادة ترتيب الأدوات."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"تم حذف أداة <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"توسيع منطقة إلغاء القفل."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"إلغاء القفل باستخدام التمرير."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"إلغاء القفل باستخدام النقش."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"تأمين الجهاز بالوجه."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"إلغاء القفل باستخدام رقم التعريف الشخصي."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"إلغاء القفل باستخدام كلمة المرور."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"منطقة النقش."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"منطقة التمرير."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"زر المقطع الصوتي السابق"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"زر المقطع الصوتي التالي"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"زر الإيقاف المؤقت"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"زر التشغيل"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"زر الإيقاف"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ب ت ث"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"إلغاء"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"تم"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغيير الوضع"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"العالي"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"إلغاء تأمين"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"الكاميرا"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"صامت"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"تشغيل الصوت"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"تمرير لأسفل لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"تمرير لليسار لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"تمرير لليمين لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"الاتصال بالطوارئ"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"نسيت النقش"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"نقش خاطئ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"كلمة مرور خاطئة"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"رقم تعريف شخصي خاطئ"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"حاول مرة أخرى خلال <xliff:g id="NUMBER">%d</xliff:g> ثانية."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"ارسم نقشك"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"أدخل رقم التعريف الشخصي لبطاقة SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"أدخل رقم التعريف الشخصي"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"أدخل كلمة المرور"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"بطاقة SIM معطلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوال للاطلاع على التفاصيل."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"إدخال رمز رقم التعريف الشخصي المراد"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"تأكيد رمز رقم التعريف الشخصي المراد"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"جارٍ إلغاء تأمين بطاقة SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"رقم التعريف الشخصي غير صحيح."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"اكتب رقم التعريف الشخصي المكون من 4 إلى 8 أرقام."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"يجب أن يتضمن رمز PUK‏ 8 أرقام أو أكثر."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل بطاقة SIM نهائيًا."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"لا يتطابق رمزا رقم التعريف الشخصي"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"محاولات النقش كثيرة جدًا"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"لإلغاء التأمين، سجّل الدخول بحسابك في Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"اسم المستخدم (البريد إلكتروني)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"كلمة المرور"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"تسجيل الدخول"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"اسم مستخدم غير صحيح أو كلمة مرور غير صالحة."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"هل نسيت اسم المستخدم أو كلمة المرور؟\nانتقل إلى "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"جارٍ فحص الحساب…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"لقد كتبت رقم التعريف الشخصي بشكل غير صحيح <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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"إزالة"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"زر المقطع الصوتي السابق"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"زر المقطع الصوتي التالي"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"زر الإيقاف المؤقت"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"زر التشغيل"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"زر الإيقاف"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"لا تتوفر خدمة"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-be/activitystrings.xml b/packages/Keyguard/res/values-be/activitystrings.xml
new file mode 100644
index 0000000..ccefe40
--- /dev/null
+++ b/packages/Keyguard/res/values-be/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Аховы няма"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN-код"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Пароль"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Шаблон"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN-код SIM-карты"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-код SIM-карты"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Выбар вiджэта..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-be/strings.xml b/packages/Keyguard/res/values-be/strings.xml
new file mode 100644
index 0000000..81020a0
--- /dev/null
+++ b/packages/Keyguard/res/values-be/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Увядзіце PIN-код"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK-код і новы PIN-код"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Каб разблакаваць, увядзіце PIN-код"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Няправільны PIN-код."</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_low_battery" msgid="8143808018719173859">"Падключыце зарадную прыладу."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Націсніце кнопку \"Меню\", каб разблакіраваць."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сетка заблакiраваная"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Няма SIM-карты"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"У планшэце няма SIM-карты."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"У тэлефоне няма SIM-карты."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Устаўце SIM-карту."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM-карту немагчыма выкарыстоўваць."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ваша SIM-карта была адключана назаўсёды.\n Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карта заблакiраваная."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-карта заблакiравана PUK-кодам."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Разблакiраванне SIM-карты..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ВIджэт %2$d з %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Дадаць віджэт"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Пусты"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Вобласць разблакіроўкі разгарнута."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Вобласць разблакіроўкі згарнута."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Віджэт <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Селектар карыстальнiка"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Стан"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Налады мультымедыя"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Змяненне парадку віджэтаў пачалося."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Змяненне парадку віджэтаў скончылася."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Віджэт <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> выдалены."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Разгарнуць вобласць разблакіроўкі."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Разблакiроўка слайда."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Узор разблакiроўкі."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фэйскантроль"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-код разблакiроўкі."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Пароль разблакiроўкі."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Вобласць узора."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Вобласць слайда."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Кнопка папярэдняй кампазiцыі"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Кнопка наступнай кампазiцыі"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Кнопка паўзы"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Кнопка прайгравання"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Кнопка спынення"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Адмена"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Выдаліць"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Гатова"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Змена рэжыму"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Разблакаваць"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Ціхі рэжым"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Гук уключаны"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Правядзіце пальцам уніз, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Правядзіце пальцам улева, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Правядзіце пальцам управа, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстранны выклік"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйце ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Увядзіце PIN-код SIM-карты"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Увядзіце PIN-код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Увядзіце пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-карта зараз адключана. Увядзіце PUK-код, каб працягнуць. Звяжыцеся са сваiм аператарам, каб атрымаць дадатковую iнфармацыю."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Увядзіце жаданы PIN-код"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Пацвердзіце жадан PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблакiроўка SIM-карты..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Няправільны PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код павінен утрымлiваць 8 лiчбаў і больш."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Паўторна увядзіце правільны PUK-код. Неаднаразовыя спробы назаўжды адключаць SIM-карту."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не супадаюць"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Занадта шмат спроб паўтарыць шаблон!"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Каб разблакiраваць, увайдзіце ў свой уліковы запіс Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Імя карыстальніка (электронная пошта)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Увайсцi"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Няправільнае імя карыстальніка ці пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыліся на імя карыстальніка або пароль?\nНаведайце "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Праверка ўлiковага запiсу..."</string>
+    <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">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <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">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да завадскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Вы няправільна спрабавалі разблакiраваць тэлефон некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Выдалiць"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Кнопка папярэдняй кампазiцыі"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Кнопка наступнай кампазiцыі"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Кнопка паўзы"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Кнопка прайгравання"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Кнопка спынення"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Не абслугоўваецца."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-bg/activitystrings.xml b/packages/Keyguard/res/values-bg/activitystrings.xml
new file mode 100644
index 0000000..807bcf2
--- /dev/null
+++ b/packages/Keyguard/res/values-bg/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Без защита"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"ПИН код"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Парола"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Фигура"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"ПИН код за SIM карта"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK код за SIM карта"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Избиране на приспособление..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
new file mode 100644
index 0000000..869ab7b
--- /dev/null
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Въведете ПИН кода"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Въведете PUK и новия ПИН код"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK код"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Нов ПИН код"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Докоснете и въведете парола"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Въведете парола, за да отключите"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Въведете ПИН, за да отключите"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неправилен ПИН код."</string>
+    <string name="keyguard_label_text" msgid="861796461028298424">"За да отключите, натиснете „Меню“ и после 0."</string>
+    <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_low_battery" msgid="8143808018719173859">"Свържете зарядното си устройство."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Натиснете иконата за меню, за да отключите."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Мрежата е заключена"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Няма SIM карта"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"В таблета няма SIM карта."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"В телефона няма SIM карта."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Поставете SIM карта."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM картата липсва или е нечетима. Поставете SIM карта."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Неизползваема SIM карта."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM картата ви е деактивирана за постоянно.\nЗа да получите друга, се свържете с доставчика на безжичната си услуга."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM картата е заключена."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картата е заключена с PUK код."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM картата се отключва…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Приспособление %2$d от %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Добавяне на приспособление."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Празно"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Областта за отключване е разгъната."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Областта за отключване е свита."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Приспособление за <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Инструмент за избор на потребители"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Състояние"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроли за мултимедията"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Пренареждането на приспособленията започна."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Пренареждането на приспособленията завърши."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Приспособлението за <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> е изтрито."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Разгъване на областта за отключване."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Отключване с плъзгане."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Отключване с фигура."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Отключване с лице."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Отключване с ПИН код."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Отключване с парола."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Област на фигурата."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Област на плъзгане."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Бутон за предишния запис"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Бутон за следващия запис"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Бутон за пауза"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Бутон за пускане"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Бутон за спиране"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отказ"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Изтриване"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Промяна на режима"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Отключване"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Тих режим"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Включване на звука"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Плъзнете надолу за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Плъзнете наляво за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Плъзнете надясно за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Спешно обаждане"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забравена фигура"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Грешна фигура"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Грешна парола"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Грешен ПИН код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Опитайте отново след <xliff:g id="NUMBER">%d</xliff:g> секунди."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Начертайте фигурата си"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Въведете ПИН кода за SIM картата"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Въведете ПИН код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Въведете паролата"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Свържете се с оператора за подробности."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Въведете желания ПИН код"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Потвърдете желания ПИН код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картата се отключва…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправилен ПИН код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Въведете ПИН код с четири до осем цифри."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK кодът трябва да е с 8 или повече цифри."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"За да отключите, влезте с профила си в Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Потребителско име (имейл)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Парола"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Вход"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Невалидно потребителско име или парола."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?\nПосетете "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Профилът се проверява…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Премахване"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Бутон за предишния запис"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Бутон за следващия запис"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Бутон за пауза"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Бутон за пускане"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Бутон за спиране"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Няма покритие."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ca/activitystrings.xml b/packages/Keyguard/res/values-ca/activitystrings.xml
new file mode 100644
index 0000000..c18b9bb
--- /dev/null
+++ b/packages/Keyguard/res/values-ca/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"No hi ha seguretat"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Contrasenya"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Patró"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN de la SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK de la SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Tria un widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
new file mode 100644
index 0000000..4f97c6b
--- /dev/null
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introdueix el codi PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introdueix el codi PUK i el codi PIN nou"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Codi PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Codi PIN nou"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Toca per introduir contrasenya"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introdueix la contrasenya per desbloquejar"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introdueix la contrasenya per desbloquejar"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Codi PIN incorrecte."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"No hi ha cap targeta SIM."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"No hi ha cap targeta SIM a la tauleta."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"No hi ha cap targeta SIM al telèfon."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insereix una targeta SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Falta la targeta SIM o no es pot llegir. Insereix-ne una."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Targeta SIM no utilitzable."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"La targeta SIM s\'ha desactivat permanentment.\n Contacta amb el teu proveïdor de serveis sense fil per obtenir-ne una altra."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La targeta SIM està bloquejada."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La targeta SIM està bloquejada pel PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"S\'està desbloquejant la targeta SIM..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Afegeix un widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Buit"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"S\'ha ampliat l\'àrea de desbloqueig."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"L\'àrea de desbloqueig està replegada."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector d\'usuaris"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Estat"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Càmera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controls multimèdia"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"S\'ha iniciat la reorganització del widget."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ha finalitzat la reorganització del widget."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"S\'ha suprimit el widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Amplia l\'àrea de desbloqueig."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueig lliscant el dit"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueig mitjançant patró"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueig facial"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueig mitjançant PIN"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueig mitjançant contrasenya"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Àrea de patró"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Àrea per lliscar el dit"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botó de pista anterior"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botó de pista següent"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botó de pausa"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botó de reproducció"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botó de parada"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel·la"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Suprimeix"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fet"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Canvi de mode"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Retorn"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloqueja"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Càmera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silenci"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Activa el so"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Fes lliscar el dit cap avall per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Fes lliscar el dit cap a l\'esquerra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Fes lliscar el dit cap a la dreta per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Trucada d\'emergència"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patró oblidat"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patró incorrecte"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Contrasenya incorrecta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecte"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER">%d</xliff:g> segons."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuixa el patró"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introdueix el PIN de la SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introdueix el PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introdueix la contrasenya"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La SIM està desactivada. Introdueix el codi PUK per continuar. Contacta amb l\'operador de telefonia mòbil per obtenir detalls."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introdueix el codi PIN"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirma el codi PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"S\'està desbloquejant la targeta SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codi PIN incorrecte."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escriu un PIN que tingui de 4 a 8 números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El codi PUK ha de tenir 8 números o més."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Per desbloquejar el telèfon, inicia la sessió amb el compte de Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'usuari (correu electrònic)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contrasenya"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Inicia la sessió"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'usuari o contrasenya no vàlids."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Has oblidat el teu nom d\'usuari o la contrasenya?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"S\'està comprovant el compte…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, la tauleta es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, el telèfon es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. Ara la tauleta es restablirà a la configuració predeterminada de fàbrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. Ara el telèfon es restablirà a la configuració predeterminada de fàbrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Elimina"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botó de pista anterior"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botó de pista següent"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botó de pausa"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botó de reproducció"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botó de parada"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sense servei."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-cs/activitystrings.xml b/packages/Keyguard/res/values-cs/activitystrings.xml
new file mode 100644
index 0000000..354176e
--- /dev/null
+++ b/packages/Keyguard/res/values-cs/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Žádné zabezpečení"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Heslo"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Gesto"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN SIM karty"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK SIM karty"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Zvolte widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
new file mode 100644
index 0000000..ec2833c
--- /dev/null
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadejte kód PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Zadejte kód PUK a nový kód PIN."</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kód PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nový kód PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dotykem zadáte heslo"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Zadejte heslo pro odemknutí"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Zadejte kód PIN pro odemknutí"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Nesprávný kód PIN."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Není vložena SIM karta."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"V tabletu není SIM karta."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"V telefonu není SIM karta."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vložte SIM kartu."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Nepoužitelná SIM karta."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Vaše SIM karta byla natrvalo zablokována.\n Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM karta je zablokována."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM karta je zablokována pomocí kódu PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Odblokování SIM karty…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d z %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Přidat widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prázdné"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oblast odemknutí byla rozšířena."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oblast odemknutí byla sbalena."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Výběr uživatele"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stav"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparát"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Ovládání médií"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Přeuspořádání widgetů bylo zahájeno."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Přeuspořádání widgetů bylo dokončeno."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> byl smazán."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Rozšířit oblast odemknutí"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odemknutí přejetím prstem."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odemknutí gestem."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Odemknutí obličejem."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odemknutí kódem PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odemknutí heslem."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Oblast pro zadání bezpečnostního gesta."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast pro přejetí prstem."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tlačítko Předchozí stopa"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tlačítko Další stopa"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tlačítko Pozastavit"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Tlačítko Přehrát"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Tlačítko Zastavit"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušit"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Smazat"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Hotovo"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Změna režimu"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Odemknout"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparát"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Tichý"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Zapnout zvuk"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Přejeďte prstem dolů: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Přejeďte prstem doleva: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Přejeďte prstem doprava: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+    <string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Tísňové volání"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zapomenuté gesto"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávné gesto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nesprávné heslo"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nesprávný kód PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zkuste to znovu za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nakreslete gesto"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadejte kód PIN SIM karty"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Zadejte kód PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Zadejte heslo"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM karta byla deaktivována. Chcete-li pokračovat, je třeba zadat kód PUK. Podrobné informace získáte od operátora."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Zadejte požadovaný kód PIN."</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrďte požadovaný kód PIN."</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokování SIM karty..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávný kód PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadejte kód PIN o délce 4–8 číslic."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Minimální délka kódu PUK je 8 číslic."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale deaktivujete."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN se neshodují."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Chcete-li telefon odemknout, přihlaste se pomocí svého účtu Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Uživatelské jméno (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Přihlásit se"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné uživatelské jméno nebo heslo."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zapomněli jste uživatelské jméno nebo heslo?\nPřejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontrola účtu…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v tabletu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v telefonu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. V tabletu se nyní obnoví výchozí tovární nastavení."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. V telefonu se nyní obnoví výchozí tovární nastavení."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odebrat"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Tlačítko Předchozí stopa"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Tlačítko Další stopa"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tlačítko Pozastavit"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Tlačítko Přehrát"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Tlačítko Zastavit"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žádný signál."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-da/activitystrings.xml b/packages/Keyguard/res/values-da/activitystrings.xml
new file mode 100644
index 0000000..af07ba5
--- /dev/null
+++ b/packages/Keyguard/res/values-da/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Ingen sikkerhed"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"Pinkode"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Adgangskode"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Mønster"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"Pinkode til SIM-kort"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-kode til SIM-kort"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Vælg widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
new file mode 100644
index 0000000..cfc7464
--- /dev/null
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Indtast pinkode"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Indtast PUK- og pinkode"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kode"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Ny pinkode"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Tryk for at angive adgangskode"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Indtast adgangskoden for at låse op"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Indtast pinkode for at låse op"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Forkert pinkode."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Intet SIM-kort"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Der er ikke noget SIM-kort i tabletten."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Der er ikke noget SIM-kort i telefonen."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Indsæt et SIM-kort."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-kortet mangler eller kan ikke læses. Indsæt et SIM-kort."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Ubrugeligt SIM-kort."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Dit SIM-kort er blevet permanent deaktiveret.\nKontakt din tjenesteudbyder for at få et nyt SIM-kort."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortet er låst."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kort er låst med PUK-koden."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kortet låses op…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d af %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tilføj widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tom"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oplåsningsområdet er udvidet."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oplåsningsområdet er skjult."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget til <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Brugervælger"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediekontrolelementer"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Omrokering af widgets er påbegyndt."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Omrokering af widgets er afsluttet."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgetten <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> er slettet."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Udvid oplåsningsområdet."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lås op ved at stryge."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Lås op med mønster."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Lås op med ansigt."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Lås op med pinkode."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Lås op med adgangskode."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mønsterområde."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Strygeområde."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knap til forrige nummer"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knap til næste nummer"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause-knap"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Afspil-knap"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop-knap"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuller"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slet"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Udført"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ændring af tilstand"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Angiv"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Lås op"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Lydløs"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Lyd slået til"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Glid ned for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Glid til venstre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Glid til højre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødopkald"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Glemt mønster"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Forkert mønster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Forkert adgangskode"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Kontakt mobiloperatøren for at få flere oplysninger."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Indtast den ønskede pinkode"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bekræft den ønskede pinkode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortet låses op…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Forkert pinkode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Indtast en pinkode på mellem 4 og 8 tal."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på 8 tal eller mere."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Indtast den korrekte PUK-kode. Gentagne forsøg vil permanent deaktivere SIM-kortet."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pinkoderne stemmer ikke overens"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Lås op ved at logge ind med din Google-konto."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Brugernavn (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Adgangskode"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Log ind"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt dit brugernavn eller din adgangskode?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontoen kontrolleres…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg nulstilles tabletten til fabriksindstillingerne, og alle brugerdata mistes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg, nulstilles telefonen til fabriksindstillingerne, og alle brugerdata mistes."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Tabletten nulstilles til fabriksindstillingerne."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles til fabriksindstillingerne."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Knap til forrige nummer"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Knap til næste nummer"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause-knap"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Afspil-knap"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop-knap"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-de/activitystrings.xml b/packages/Keyguard/res/values-de/activitystrings.xml
new file mode 100644
index 0000000..d8e9272
--- /dev/null
+++ b/packages/Keyguard/res/values-de/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Keine Sicherheit"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Passwort"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Muster"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN für SIM-Karte"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK für SIM-Karte"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Widget auswählen..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
new file mode 100644
index 0000000..85d1a4f9
--- /dev/null
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN-Code eingeben"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK und neuen PIN-Code eingeben"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-Code"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Neuer PIN-Code"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Zur Passworteingabe berühren"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Passwort zum Entsperren eingeben"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"PIN zum Entsperren eingeben"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Falscher PIN-Code"</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Keine SIM-Karte"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Keine SIM-Karte im Tablet"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Keine SIM-Karte im Telefon"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Legen Sie eine SIM-Karte ein."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-Karte fehlt oder ist nicht lesbar. Bitte legen Sie eine SIM-Karte ein."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM-Karte unbrauchbar"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ihre SIM-Karte wurde dauerhaft deaktiviert.\n Wenden Sie sich an Ihren Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-Karte ist gesperrt."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-Karte wird entsperrt…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d von %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Widget hinzufügen"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Leer"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Entsperr-Bereich maximiert"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Entsperr-Bereich mminimiert"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Nutzerauswahl"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediensteuerelemente"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Neuordnung der Widgets gestartet"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Neuordnung der Widgets abgeschlossen"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> gelöscht"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Entsperr-Bereich maximieren"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Entsperrung mit Fingerbewegung"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Entsperrung mit Muster"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face Unlock"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Entsperrung mit PIN"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Entsperrung mit Passwort"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Bereich für Muster"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Bereich für Fingerbewegung"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Schaltfläche für vorherigen Titel"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Schaltfläche für nächsten Titel"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Schaltfläche für Pause"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Schaltfläche für Wiedergabe"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Schaltfläche für Stopp"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Abbrechen"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Löschen"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fertig"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modusänderung"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Umschalttaste"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Eingabetaste"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Entsperren"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Lautlos"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Ton ein"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach unten schieben"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach links schieben"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach rechts schieben"</string>
+    <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Notruf"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Muster vergessen"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Falsches Muster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Falsches Passwort"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Falsche PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Muster zeichnen"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM-PIN eingeben"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN eingeben"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Passwort eingeben"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Die SIM-Karte ist jetzt deaktiviert. Geben Sie den PUK-Code ein, um fortzufahren. Weitere Informationen erhalten Sie von Ihrem Mobilfunkanbieter."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Gewünschten PIN-Code eingeben"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Gewünschten PIN-Code bestätigen"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-Karte wird entsperrt…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Falscher PIN-Code"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Geben Sie eine 4- bis 8-stellige PIN ein."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Der PUK-Code muss mindestens 8 Ziffern betragen."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Geben Sie den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-Codes stimmen nicht überein"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nutzername (E-Mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Passwort"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Anmelden"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ungültiger Nutzername oder ungültiges Passwort"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?\nBesuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto wird geprüft…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Schaltfläche für vorherigen Titel"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Schaltfläche für nächsten Titel"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Schaltfläche für Pause"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Schaltfläche für Wiedergabe"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Schaltfläche für Stopp"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Kein Dienst"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-el/activitystrings.xml b/packages/Keyguard/res/values-el/activitystrings.xml
new file mode 100644
index 0000000..3941f4f
--- /dev/null
+++ b/packages/Keyguard/res/values-el/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Χωρίς ασφάλεια"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Κωδικός πρόσβασης"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Μοτίβο"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"Κωδικός PIN κάρτας SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"Κωδικός PUK κάρτας SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Επιλογή γραφικού στοιχείου…"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
new file mode 100644
index 0000000..e86f24d
--- /dev/null
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Πληκτρολογήστε τον κωδικό PUK και τον νέο κωδικό PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Κωδικός PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Νέος κωδικός PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Αγγίξτε για εισαγ. κωδ. πρόσβ."</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Πληκτρολογήστε τον κωδικό πρόσβασης για ξεκλείδωμα"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Πληκτρολογήστε τον αριθμό PIN για ξεκλείδωμα"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Εσφαλμένος κωδικός PIN."</string>
+    <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_low_battery" msgid="8143808018719173859">"Συνδέστε τον φορτιστή."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Το δίκτυο κλειδώθηκε"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Δεν υπάρχει κάρτα SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Δεν υπάρχει κάρτα SIM στο tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Τοποθετήστε μια κάρτα SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Η κάρτα SIM δεν υπάρχει ή δεν είναι δυνατή η ανάγνωσή της. Τοποθετήστε μια κάρτα SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Η κάρτα SIM έχει απενεργοποιηθεί οριστικά.\n Επικοινωνήστε με τον παροχέα υπηρεσιών ασύρματου δικτύου για να λάβετε μια νέα κάρτα SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Η κάρτα SIM είναι κλειδωμένη."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Η κάρτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ξεκλείδωμα κάρτας SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Γραφικό στοιχείο %2$d από %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Προσθήκη γραφικού στοιχείου"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Κενή"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ανάπτυξη της περιοχής ξεκλειδώματος."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Σύμπτυξη της περιοχής ξεκλειδώματος."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Γραφικό στοιχείο <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Επιλογέας χρήστη"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Κατάσταση"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Φωτογραφική μηχανή"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Στοιχεία ελέγχου μέσων"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Έχει ξεκινήσει η αναδιάταξη των γραφικών στοιχείων."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Έχει ολοκληρωθεί η αναδιάταξη των γραφικών στοιχείων."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Το γραφικό στοιχείο <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> έχει διαγραφεί."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ανάπτυξη περιοχής ξεκλειδώματος."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Ξεκλείδωμα ολίσθησης."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ξεκλείδωμα μοτίβου."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Ξεκλείδωμα κωδικού ασφαλείας"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Ξεκλείδωμα κωδικού πρόσβασης."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Περιοχή μοτίβου."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Περιοχή ολίσθησης"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Κουμπί προηγούμενου κομματιού"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Κουμπί επόμενου κομματιού"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Κουμπί παύσης"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Κουμπί αναπαραγωγής"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Κουμπί διακοπής"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ΑΒΓ"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ακύρωση"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Διαγραφή"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Τέλος"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Αλλαγή τρόπου"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Ξεκλείδωμα"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Φωτογραφική μηχανή"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Αθόρυβο"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Ενεργοποίηση ήχου"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Κύλιση προς τα κάτω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Κύλιση προς τα αριστερά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Κύλιση προς τα δεξιά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Κλήσεις επείγουσας ανάγκης"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ξεχάσατε το μοτίβο"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Εσφαλμένο μοτίβο"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Εσφαλμένος κωδικός πρόσβασης"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Εσφαλμένος κωδικός PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Δοκιμάστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Σχεδιάστε το μοτίβο σας"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Εισαγωγή PIN SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Πληκτρολογήστε το PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Εισαγάγετε κωδικό πρόσβασης"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Η κάρτα SIM είναι απενεργοποιημένη αυτή τη στιγμή. Εισαγάγετε τον κωδικό PUK για να συνεχίσετε. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας σας για λεπτομέρειες."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Εισαγάγετε τον απαιτούμενο κωδικό PIN"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Επιβεβαιώστε τον απαιτούμενο κωδικό PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ξεκλείδωμα κάρτας SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Εσφαλμένος κωδικός PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Πληκτρολογήστε έναν αριθμό PIN που να αποτελείται από 4 έως 8 αριθμούς."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Ο κωδικός PUK θα πρέπει να περιέχει τουλάχιστον 8 αριθμούς."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Εισαγάγετε ξανά τον κωδικό PUK. Οι επαναλαμβανόμενες προσπάθειες θα απενεργοποιήσουν οριστικά την κάρτα SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Δεν υπάρχει αντιστοιχία των κωδικών PIN"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Πάρα πολλές προσπάθειες μοτίβου"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Για ξεκλείδωμα, συνδεθείτε με τον λογαριασμό σας Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Όνομα χρήστη (διεύθυνση ηλεκτρονικού ταχυδρομείου)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Κωδικός πρόσβασης"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Σύνδεση"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;\nΕπισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Έλεγχος λογαριασμού…"</string>
+    <string name="kg_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">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες, το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις και όλα τα δεδομένα χρήστη θα χαθούν."</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">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές. Το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις."</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> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Κατάργηση"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Κουμπί προηγούμενου κομματιού"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Κουμπί επόμενου κομματιού"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Κουμπί παύσης"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Κουμπί αναπαραγωγής"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Κουμπί διακοπής"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Καμία υπηρεσία."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-en-rGB/activitystrings.xml b/packages/Keyguard/res/values-en-rGB/activitystrings.xml
new file mode 100644
index 0000000..88e806e
--- /dev/null
+++ b/packages/Keyguard/res/values-en-rGB/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"No security"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Password"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Pattern"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Choose widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..967c3fa
--- /dev/null
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Type PUK and new PIN code"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK code"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"New PIN Code"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Touch to type password"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Type password to unlock"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Type PIN to unlock"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"No SIM card"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"No SIM card in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"No SIM card in phone."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insert a SIM card."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"The SIM card is missing or not readable. Insert a SIM card."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Unusable SIM card."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Your SIM card has been permanently disabled.\n Contact your wireless service provider for another SIM card."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM card is locked."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM card is PUK-locked."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Unlocking SIM card…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d of %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Add widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Empty"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Unlock area expanded."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Unlock area collapsed."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"User selector"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media controls"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget reordering started."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget reordering ended."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> deleted."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expand unlock area."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Slide unlock."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pattern unlock."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin unlock."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Password unlock."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Pattern area."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Slide area."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Previous track button"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Next track button"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause button"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Play button"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop button"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Done"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Unlock"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silent"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Sound on"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Slide down for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Slide right for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Wrong Password"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Wrong PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Draw your pattern"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Enter SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Enter PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Enter Password"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Enter desired PIN code"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirm desired PIN code"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Unlocking SIM card…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Incorrect PIN code."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Type a PIN that is 4 to 8 numbers."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK code should be 8 numbers or more."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"To unlock, sign in with your Google account."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?\nVisit "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Checking account…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the tablet will be reset to factory default and all user data will be lost."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the phone will be reset to factory default and all user data will be lost."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The tablet will now be reset to factory default."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The phone will now be reset to factory default."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Previous track button"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Next track button"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause button"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Play button"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop button"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-es-rUS/activitystrings.xml b/packages/Keyguard/res/values-es-rUS/activitystrings.xml
new file mode 100644
index 0000000..20117c4
--- /dev/null
+++ b/packages/Keyguard/res/values-es-rUS/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Sin seguridad"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Contraseña"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Patrón"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN de tarjeta SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK de tarjeta SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Elegir widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..787581a
--- /dev/null
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingresa el código PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Escribe el código PUK y un nuevo código PIN."</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Código PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nuevo código PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Toca para ingresar la contraseña"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ingresar contraseña para desbloquear"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ingresa el PIN para desbloquear"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"No se insertó ninguna tarjeta SIM."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"No se insertó ninguna tarjeta SIM en la tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"No se insertó ninguna tarjeta SIM en el dispositivo."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Inserta una tarjeta SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Falta la tarjeta SIM o esta no se puede leer. Inserta una tarjeta SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Tarjeta SIM inutilizable"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Tu tarjeta SIM se inhabilitó de forma permanente.\n Comunícate con tu proveedor de servicios inalámbricos para obtener otra tarjeta SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La tarjeta SIM está bloqueada."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La tarjeta SIM está bloqueada por código PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando tarjeta SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Agregar widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vacío"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área desbloqueada expandida."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"El área desbloqueada se contrajo."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Estado"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cámara"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de medios"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Se comenzaron a reordenar los widgets."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Se terminaron de reordenar los widgets."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandir el área desbloqueada"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueo por deslizamiento"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueo por patrón"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueo facial"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueo por PIN"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueo por contraseña"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área de patrón"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslizamiento"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de pista anterior"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de pista siguiente"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botón de reproducción"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botón de detención"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Listo"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio de modo"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayúscula"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ingresar"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Sonido activado"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Desliza el dedo hacia abajo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Desliza el dedo hacia la derecha para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuja tu patrón."</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingresa el PIN de la tarjeta SIM."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ingresa el PIN."</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ingresa tu contraseña."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La tarjeta SIM está inhabilitada. Para continuar, ingresa el código PUK. Si quieres obtener más información, ponte en contacto con el proveedor."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ingresa el código PIN deseado"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmar código PIN deseado"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escribe un PIN que tenga de cuatro a ocho números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El código PUK debe tener ocho números como mínimo."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a ingresar el código PUK correcto. Si ingresas un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de ingresar el patrón"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, accede con tu cuenta de Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Acceder"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nombre de usuario o contraseña incorrectos"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"¿Olvidaste tu nombre de usuario o contraseña?\nAccede a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando la cuenta…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica de la tablet y se pierdan todos los datos del usuario."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del dispositivo y se pierdan todos los datos del usuario."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica de la tablet."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del dispositivo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botón de pista anterior"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botón de pista siguiente"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botón de pausa"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botón de reproducción"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botón de detención"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-es/activitystrings.xml b/packages/Keyguard/res/values-es/activitystrings.xml
new file mode 100644
index 0000000..34899cc
--- /dev/null
+++ b/packages/Keyguard/res/values-es/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Sin seguridad"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Contraseña"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Patrón"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN de tarjeta SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK de tarjeta SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Seleccionar widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
new file mode 100644
index 0000000..d0c79eb
--- /dev/null
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduce el código PIN."</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduce el código PUK y un nuevo código PIN."</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Código PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nuevo código PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Toca para introducir contraseña"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduce la contraseña para desbloquear."</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduce el código PIN para desbloquear."</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
+    <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">"Cargado"</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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Falta la tarjeta SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"No se ha insertado ninguna tarjeta SIM en el tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Inserta una tarjeta SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Tarjeta SIM inutilizable"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Tu tarjeta SIM se ha inhabilitado permanentemente.\n Para obtener otra, ponte en contacto con tu proveedor de servicios de telefonía."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La tarjeta SIM está bloqueada."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La tarjeta SIM está bloqueada con el código PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando tarjeta SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Añadir widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vacío"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueo ampliada"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueo contraída"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Estado"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cámara"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles multimedia"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Se ha empezado a cambiar el orden de los widgets."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Se ha terminado de cambiar el orden de los widgets."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ampliar área de desbloqueo"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueo deslizando el dedo"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueo por patrón"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueo facial"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueo por PIN"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueo por contraseña"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área de patrón"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área para deslizar"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de canción anterior"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de siguiente canción"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botón de reproducción"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botón para detener la reproducción"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Listo"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio de modo"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayús"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Intro"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silencio"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Sonido activado"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Desliza el dedo hacia abajo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Desliza el dedo hacia la derecha para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Has olvidado el patrón?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"El patrón es incorrecto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Inténtalo de nuevo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuja tu patrón de desbloqueo."</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduce el PIN de la tarjeta SIM."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduce el PIN."</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Escribe tu contraseña."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La tarjeta SIM está inhabilitada. Para continuar, introduce el código PUK. Si quieres obtener más información, ponte en contacto con el operador"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduce el código PIN deseado"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirma el código PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El código PUK debe tener ocho números como mínimo."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear el teléfono, inicia sesión con tu cuenta de Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo electrónico)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sesión"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"El nombre de usuario o la contraseña no son válidos."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Si has olvidado tu nombre de usuario o tu contraseña,\naccede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando cuenta…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botón de canción anterior"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botón de siguiente canción"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botón de pausa"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botón de reproducción"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botón para detener la reproducción"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-et/activitystrings.xml b/packages/Keyguard/res/values-et/activitystrings.xml
new file mode 100644
index 0000000..eb71afc
--- /dev/null
+++ b/packages/Keyguard/res/values-et/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Turvamata"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN-kood"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Parool"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Muster"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM-i PIN-kood"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM-i PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Vidina valimine ..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-et/strings.xml b/packages/Keyguard/res/values-et/strings.xml
new file mode 100644
index 0000000..0a17a9c
--- /dev/null
+++ b/packages/Keyguard/res/values-et/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Sisestage PIN-kood"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Sisestage PUK-kood ja uus PIN-kood"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kood"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Uus PIN-kood"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Puudutage parooli sisestamiseks"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Avamiseks sisestage parool"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Avamiseks sisestage PIN-kood"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM-kaarti pole"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tahvelarvutis pole SIM-kaarti."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefonis pole SIM-kaarti."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Sisestage SIM-kaart."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-kaart puudub või on loetamatu. Sisestage SIM-kaart."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kasutamiskõlbmatu SIM-kaart."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-kaart on jäädavalt keelatud.\n Uue SIM-kaardi saamiseks võtke ühendust oma mobiilsideoperaatoriga."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kaart on lukus."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kaart on PUK-lukus."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kaardi avamine ..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidin %2$d/%3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidina lisamine."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tühi"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Avamisala on laiendatud."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Avamisala on ahendatud."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kasutaja valija"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Olek"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kaamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Meedia juhtnupud"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Vidina ümberkorraldamine algas."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Vidina ümberkorraldamine lõppes."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> on kustutatud."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Avamisala laiendamine."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lohistamisega avamine."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mustriga avamine."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Näoga avamine."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-koodiga avamine."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Parooliga avamine."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mustri ala."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Lohistamisala."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nupp Eelmine lugu"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nupp Järgmine lugu"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nupp Peata"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Nupp Esita"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Nupp Peata"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Tühista"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Kustuta"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Valmis"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režiimi muutmine"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tõstuklahv"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Sisestusklahv"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Luku avamine"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kaamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Lohistage alla: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Lohistage vasakule: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Lohistage paremale: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasin mustri"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Vale muster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Vale parool"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Vale PIN-kood"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Joonistage oma muster"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Sisestage SIM-i PIN-kood"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Sisestage PIN-kood"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Sisestage parool"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Üksikasju küsige operaatorilt."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Sisestage soovitud PIN-kood"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Kinnitage soovitud PIN-kood"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koodi pikkus peab olema vähemalt 8 numbrit."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Avamiseks logige sisse oma Google\'i kontoga."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Kasutajanimi (e-post)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parool"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logi sisse"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Vale kasutajanimi või parool."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?\nKülastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto kontrollimine ..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse tahvelarvuti tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse telefon tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Olete püüdnud tahvelarvutit <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Tahvelarvuti lähtestatakse nüüd tehase vaikeseadetele."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Olete püüdnud telefoni <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Telefon lähtestatakse nüüd tehase vaikeseadetele."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Nupp Eelmine lugu"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nupp Järgmine lugu"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Nupp Peata"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Nupp Esita"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Nupp Peata"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fa/activitystrings.xml b/packages/Keyguard/res/values-fa/activitystrings.xml
new file mode 100644
index 0000000..735af8d
--- /dev/null
+++ b/packages/Keyguard/res/values-fa/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"عدم وجود امنیت"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"پین"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"گذرواژه"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"الگو"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"پین سیم کارت"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK سیم کارت"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"انتخاب ابزارک..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
new file mode 100644
index 0000000..83c5a34
--- /dev/null
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"پین کد را وارد کنید"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK و پین کد جدید را تایپ کنید"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"کد PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"پین کد جدید"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"برای تایپ گذرواژه لمس کنید"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"برای بازکردن قفل، گذرواژه را وارد کنید"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"برای بازکردن قفل، پین را تایپ کنید"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"پین کد اشتباه است."</string>
+    <string name="keyguard_label_text" msgid="861796461028298424">"برای بازگشایی قفل، منو را فشار دهید و سپس 0 را فشار دهید."</string>
+    <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_low_battery" msgid="8143808018719173859">"شارژر خود را وصل کنید."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"برای بازگشایی قفل روی منو فشار دهید."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"شبکه قفل شد"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"سیم کارت موجود نیست"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"سیم کارتی در رایانه لوحی نیست."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"سیم کارت در تلفن نیست."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"سیم کارت را وارد کنید."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"سیم کارت موجود نیست یا قابل خواندن نیست. یک سیم کارت وارد کنید."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"سیم کارت غیرقابل استفاده است."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"سیم کارت شما به طور دائم غیر فعال شده است. \nبرای داشتن سیم کارت دیگر با ارائه‎دهنده سرویس بی‎سیم خود تماس بگیرید."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"سیم کارت قفل شد."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"سیم کارت با PUK قفل شده است."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"درحال بازگشایی قفل سیم کارت..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ابزارک %2$d از %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ابزارک اضافه کنید."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"خالی"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"منطقه بازگشایی گسترده شد."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"منطقه بازگشایی کوچک شد."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"ابزارک <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"انتخابگر کاربر"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"وضعیت"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"دوربین"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"کنترل‌های رسانه"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"مرتب سازی مجدد ابزارک آغاز شد."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"مرتب‌سازی مجدد ابزارک به پایان رسید."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ابزارک <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> حذف شد.‍"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"گسترده کردن منطقه بازگشایی شده."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"باز کردن قفل با کشیدن انگشت روی صفحه."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"باز کردن قفل با الگو."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"باز کردن قفل با چهره."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"باز کردن قفل با پین."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"باز کردن قفل با گذرواژه."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ناحیه الگو."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"ناحیه کشیدن انگشت روی صفحه."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"دکمه تراک قبلی"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"دکمه تراک بعدی"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"دکمه توقف موقت"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"دکمه پخش"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"دکمه توقف"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"لغو"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"انجام شد"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغییر حالت"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"بازکردن قفل"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"دوربین"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"ساکت"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"صدا روشن"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"لغزاندن به پایین برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"لغزاندن به راست برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"تماس اضطراری"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"الگو را فراموش کرده‌اید"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"الگوی اشتباه"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"گذرواژه اشتباه"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"پین اشتباه"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"پس از <xliff:g id="NUMBER">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"الگوی خود را رسم کنید"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"پین سیم کارت را وارد کنید"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"پین را وارد کنید"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"گذرواژه را وارد کنید"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"اکنون سیم کارت غیرفعال است. پین کد را برای ادامه وارد کنید. برای جزئیات با شرکت مخابراتی خود تماس بگیرید."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"پین کد دلخواه را وارد کنید"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"تأیید پین کد دلخواه"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"بازگشایی قفل سیم کارت..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"پین کد اشتباه است."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"یک پین ۴ تا ۸ رقمی را تایپ کنید."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"پین کد باید ۸ عدد یا بیشتر باشد."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"پین کد صحیح را دوباره وارد کنید. تلاش‌های مکرر به‌طور دائم سیم کارت را غیرفعال خواهد کرد."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"پین کدها منطبق نیستند"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"برای بازگشایی قفل، با حساب Google خود وارد سیستم شوید."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"نام کاربری (ایمیل)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"گذرواژه"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ورود به سیستم"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"نام کاربری یا گذرواژه نامعتبر."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"نام کاربری یا گذرواژه خود را فراموش کردید؟\nاز "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"درحال بررسی حساب..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"حذف"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"دکمه تراک قبلی"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"دکمه تراک بعدی"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"دکمه توقف موقت"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"دکمه پخش"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"دکمه توقف"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"خدماتی وجود ندارد."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fi/activitystrings.xml b/packages/Keyguard/res/values-fi/activitystrings.xml
new file mode 100644
index 0000000..6e0a5a9
--- /dev/null
+++ b/packages/Keyguard/res/values-fi/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Ei suojausta"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN-koodi"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Salasana"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Kuvio"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM-kortin PIN-koodi"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM-kortin PUK-koodi"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Valitse widget…"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
new file mode 100644
index 0000000..dbca50d
--- /dev/null
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Anna PIN-koodi"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Anna PUK-koodi ja uusi PIN-koodi"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-koodi"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Uusi PIN-koodi"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Kosketa ja anna salasana"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Poista lukitus antamalla salasana"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Poista lukitus antamalla PIN-koodi"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN-koodi väärin."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Ei SIM-korttia"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tablet-laitteessa ei ole SIM-korttia."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Puhelimessa ei ole SIM-korttia."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Aseta SIM-kortti."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-korttia ei löydy tai sitä ei voi lukea. Aseta SIM-kortti."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM-kortti ei kelpaa."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-kortti on poistettu pysyvästi käytöstä.\n Ota yhteyttä operaattoriisi ja hanki uusi SIM-kortti."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortti on lukittu."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortti on PUK-lukittu."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kortin lukitusta poistetaan…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d/%3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Lisää widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tyhjä"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Lukituksen poiston alue laajennettu."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Lukituksen poiston alue tiivistetty."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-widget."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Käyttäjävalitsin"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Tila"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediaohjaimet"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widgetien järjestely aloitettu."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widgetien järjestely päättyi."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> poistettu."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Laajenna lukituksen poiston aluetta."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lukituksen poisto liu\'uttamalla."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Lukituksen poisto salasanalla."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face Unlock"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Lukituksen poisto PIN-koodilla."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Lukituksen poisto salasanalla."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kuvioalue."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Liu\'utusalue."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Edellinen kappale -painike"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Seuraava kappale -painike"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tauko-painike"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Toista-painike"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Keskeytä-painike"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Peruuta"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Poista"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Valmis"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Tilan muutos"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Poista lukitus"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Äänetön"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Ääni käytössä"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Liu\'uta alas ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Liu\'uta vasemmalle ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Liu\'uta oikealle ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Hätäpuhelu"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unohtunut kuvio"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Väärä kuvio"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Väärä salasana"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Väärä PIN-koodi"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Yritä uudelleen <xliff:g id="NUMBER">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Piirrä kuvio"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Anna SIM-kortin PIN-koodi"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Anna PIN-koodi"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Anna salasana"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortti on nyt poistettu käytöstä. Jatka antamalla PUK-koodi. Saat lisätietoja ottamalla yhteyttä operaattoriin."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Anna haluamasi PIN-koodi"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Vahvista haluamasi PIN-koodi"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortin lukitusta poistetaan…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Virheellinen PIN-koodi."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Anna 4–8-numeroinen PIN-koodi."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koodissa tulee olla vähintään 8 numeroa."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Anna uudelleen oikea PUK-koodi. Jos teet liian monta yritystä, SIM-kortti poistetaan käytöstä pysyvästi."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodit eivät täsmää"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liikaa kuvionpiirtoyrityksiä"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Poista lukitus kirjautumalla sisään Google-tililläsi."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Käyttäjänimi (sähköposti)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Salasana"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Kirjaudu sisään"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Virheellinen käyttäjänimi tai salasana."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Unohditko käyttäjänimesi tai salasanasi?\nKäy osoitteessa "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Tarkistetaan tiliä..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tablet-laitteeseen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, puhelimeen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Laitteeseen palautetaan nyt tehdasasetukset."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Puhelimeen palautetaan nyt tehdasasetukset."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Poista"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Edellinen kappale -painike"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Seuraava kappale -painike"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tauko-painike"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Toista-painike"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Keskeytä-painike"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ei yhteyttä."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fr/activitystrings.xml b/packages/Keyguard/res/values-fr/activitystrings.xml
new file mode 100644
index 0000000..dc79842
--- /dev/null
+++ b/packages/Keyguard/res/values-fr/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Aucune sécurité"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"Code PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Mot de passe"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Schéma"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"Code PIN de la carte SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"Clé PUK de la carte SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Sélectionner un widget"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
new file mode 100644
index 0000000..250a136
--- /dev/null
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le code PIN."</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Saisissez la clé PUK et le nouveau code PIN."</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Code PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nouveau code PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Appuyez pour saisir mot passe"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Saisissez le mot de passe pour déverrouiller le clavier."</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Saisissez le code PIN pour déverrouiller le clavier."</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Le code PIN est erroné."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Aucune carte SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Aucune carte SIM n\'est insérée dans la tablette."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insérez une carte SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Carte SIM absente ou illisible. Veuillez insérer une carte SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Carte SIM inutilisable."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Votre carte SIM a été définitivement désactivée.\n Veuillez contacter votre opérateur de téléphonie mobile pour en obtenir une autre."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La carte SIM est verrouillée."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La carte SIM est verrouillée par clé PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Déverrouillage de la carte SIM en cours…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ajouter un widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vide"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Zone de déverrouillage développée."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Zone de déverrouillage réduite."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Sélecteur d\'utilisateur"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"État"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Caméra"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Commandes multimédias"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Début de la réorganisation des widgets"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Réorganisation des widgets terminée."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Le widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a été supprimé."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Développer la zone de déverrouillage"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Déverrouillage par schéma"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Déverrouillage par reconnaissance faciale"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Déverrouillage par code PIN"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Déverrouillage par mot de passe"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Zone du schéma"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Zone où faire glisser votre doigt sur l\'écran"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Bouton pour revenir au titre précédent"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Bouton pour atteindre le titre suivant"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Bouton de pause"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Bouton de lecture"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Bouton d\'arrêt"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminé"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Changement de mode"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Déverrouiller"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Appareil photo"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Mode silencieux"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Son activé"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Faites glisser vers le bas pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Faites glisser vers la gauche pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Faites glisser vers la droite pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Mot de passe incorrect."</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Code PIN incorrect."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dessinez votre schéma."</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Saisissez le code PIN de la carte SIM."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Saisissez le code PIN."</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Saisissez votre mot de passe."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Contactez votre opérateur pour en savoir plus."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Saisir le code PIN souhaité"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmer le code PIN souhaité"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Le code PIN est erroné."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Veuillez saisir un code PIN comprenant entre quatre et huit chiffres."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Pour déverrouiller le téléphone, veuillez vous connecter avec votre compte Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'utilisateur (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?\nRendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Vérification du compte en cours…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Bouton pour revenir au titre précédent"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Bouton pour atteindre le titre suivant"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Bouton de pause"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Bouton de lecture"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Bouton d\'arrêt"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hi/activitystrings.xml b/packages/Keyguard/res/values-hi/activitystrings.xml
new file mode 100644
index 0000000..4b0a082
--- /dev/null
+++ b/packages/Keyguard/res/values-hi/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"कोई सुरक्षा नहीं"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"पासवर्ड"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"प्रतिमान"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM पिन"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"विजेट चुनें..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
new file mode 100644
index 0000000..714d9fb
--- /dev/null
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"पिन कोड लिखें"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK और नया पिन कोड लिखें"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK कोड"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"नया पिन कोड"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"पासवर्ड लिखने के लिए स्पर्श करें"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करने के लिए पासवर्ड लिखें"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलॉक करने के लिए पिन लिखें"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत पिन कोड."</string>
+    <string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करने के लिए, मेनू दबाएं और फिर 0 दबाएं."</string>
+    <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_low_battery" msgid="8143808018719173859">"अपना चार्जर कनेक्‍ट करें."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"अनलॉक करने के लिए मेनू दबाएं."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"नेटवर्क लॉक किया गया"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"कोई SIM कार्ड नहीं है"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"टेबलेट में कोई SIM कार्ड नहीं है."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"फ़ोन में कोई SIM कार्ड नहीं है."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIM कार्ड डालें."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM कार्ड गुम है या पढ़ने योग्‍य नहीं है. SIM कार्ड डालें."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"अनुपयोगी SIM कार्ड."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"आपका SIM कार्ड स्‍थायी रूप से अक्षम कर दिया गया है.\n दूसरे SIM कार्ड के लिए अपने वायरलेस सेवा प्रदाता से संपर्क करें."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"सिम कार्ड लॉक है."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM कार्ड PUK द्वारा लॉक किया हुआ है."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM कार्ड अनलॉक हो रहा है…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोड़ें"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"रिक्त"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"अनलॉक क्षेत्र को विस्तृत कर दिया गया."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"अनलॉक क्षेत्र को संक्षिप्त कर दिया गया."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> विजेट."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"उपयोगकर्ता चयनकर्ता"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"स्थिति"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"कैमरा"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"मीडिया नियंत्रण"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"विजेट पुनः क्रमित करना प्रारंभ."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"विजेट पुनः क्रमित करना समाप्त."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करें."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"प्रतिमान अनलॉक."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलॉक."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"प्रतिमान क्षेत्र."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"पिछला ट्रैक बटन"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"अगला ट्रैक बटन"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"पॉज़ करें बटन"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"चलाएं बटन"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"रोकें बटन"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द करें"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटाएं"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"अनलॉक करें"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"कैमरा"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"मौन"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"ध्‍वनि चालू करें"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए नीचे स्‍लाइड करें."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए बाएं स्‍लाइड करें."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए दाएं स्‍लाइड करें."</string>
+    <string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"प्रतिमान भूल गए"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड डालें"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"सिम अब अक्षम हो गई है. जारी रखने के लिए PUK कोड डालें. विवरण के लिए कैरियर से संपर्क करें."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"इच्छित पिन कोड डालें"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"इच्छित पिन कोड की पुष्टि करें"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM कार्ड अनलॉक कर रहा है…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"गलत PIN कोड."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ऐसा PIN लिखें, जो 4 से 8 अंकों का हो."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक प्रतिमान प्रयास"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से साइन इन करें."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करें"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"पिछला ट्रैक बटन"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"अगला ट्रैक बटन"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"पॉज़ करें बटन"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"चलाएं बटन"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"रोकें बटन"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"कोई सेवा नहीं."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hr/activitystrings.xml b/packages/Keyguard/res/values-hr/activitystrings.xml
new file mode 100644
index 0000000..d2b8e92
--- /dev/null
+++ b/packages/Keyguard/res/values-hr/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Nema zaštite"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Zaporka"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Uzorak"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN za SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK za SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Odaberite widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
new file mode 100644
index 0000000..70e6305
--- /dev/null
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN kôd"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN kôd"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kôd"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN kôd"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite za tipkanje zaporke"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite zaporku za otključavanje"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Netočan PIN kôd."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nema SIM kartice"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"U tabletnom uređaju nema SIM kartice."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"U telefonu nema SIM kartice."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Umetnite SIM karticu."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kartica nedostaje ili nije čitljiva. Umetnite SIM karticu."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Neupotrebljiva SIM kartica."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Vaša SIM kartica trajno je onemogućena.\n Obratite se svom pružatelju bežičnih usluga da biste dobili drugu SIM karticu."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kartica je zaključana."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kartica zaključana je PUK-om."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Otključavanje SIM kartice…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d od %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodavanje widgeta."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prazno"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Područje za otključavanje prošireno je."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Područje za otključavanje sažeto je."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Birač korisnika"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparat"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Nadzor medija"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Pokrenuta je promjena redoslijeda widgeta."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Završena je promjena redoslijeda widgeta."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> izbrisan je."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Proširivanje područja za otključavanje."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Otključavanje klizanjem."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Uzorak za otključavanje."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Otključavanje licem."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje PIN-om."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje zaporkom."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Područje uzorka."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Područje klizanja."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Gumb Prethodni zapis"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Gumb Sljedeći zapis"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Gumb Pauza"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Gumb Reprodukcija"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Gumb Zaustavi"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Odustani"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotovo"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Promjena načina"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Otključaj"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparat"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Bešumno"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Zvuk je uključen"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Kliznite prema dolje za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Kliznite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Kliznite desno za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Hitan poziv"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste obrazac"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan obrazac"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna zaporka"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Iscrtajte svoj obrazac"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN za SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Unesite zaporku"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM je sad onemogućen. Unesite PUK kôd da biste nastavili. Kontaktirajte operatera za pojedinosti."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Upišite željeni PIN kôd"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrdite željeni PIN kôd"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netočan PIN kôd."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji ima od 4 do 8 brojeva."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kôd treba imati 8 brojeva ili više."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji trajno će onemogućiti SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi nisu jednaki"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja iscrtavanja obrasca"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Za otključavanje prijavite se Google računom."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Korisničko ime (e-pošta)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Zaporka"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili zaporka."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili zaporku?\nPosjetite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Provjera računa..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Netočno ste pokušali otključati tabletno računalo <xliff:g id="NUMBER_0">%d</xliff:g> puta. Ono će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Netočno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%d</xliff:g> puta. On će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Netočno ste pokušali otključati tabletno računalo <xliff:g id="NUMBER">%d</xliff:g> puta. Sada će se vratiti na tvorničke postavke."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Netočno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Sada će se vratiti na tvorničke postavke."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Gumb Prethodni zapis"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Gumb Sljedeći zapis"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Gumb Pauza"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Gumb Reprodukcija"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Gumb Zaustavi"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nema usluge."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hu/activitystrings.xml b/packages/Keyguard/res/values-hu/activitystrings.xml
new file mode 100644
index 0000000..30d2951
--- /dev/null
+++ b/packages/Keyguard/res/values-hu/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Nincs védelem"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN kód"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Jelszó"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Minta"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM kártya PIN kódja"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM kártya PUK kódja"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Modul kiválasztása..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
new file mode 100644
index 0000000..611602e
--- /dev/null
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Írja be a PIN kódot"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Írja be a PUK kódot, majd az új PIN kódot"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kód"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Új PIN kód"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Érintsen jelszó megadásához"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"A feloldáshoz írja be a jelszót"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Feloldáshoz írja be a PIN kódot"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Helytelen PIN kód."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nincs SIM kártya."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Nincs SIM kártya a táblagépben."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Nincs SIM kártya a telefonban."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Helyezzen be egy SIM kártyát."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"A SIM kártya hiányzik vagy nem olvasható. Helyezzen be egy SIM kártyát."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"A SIM kártya nem használható."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM kártyája véglegesen le van tiltva.\n Forduljon a vezeték nélküli szolgáltatójához másik SIM kártya beszerzése érdekében."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"A SIM kártya le van zárva."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"A SIM kártya le van zárva a PUK kóddal."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM kártya feloldása..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Modul %3$d/%2$d"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Modul hozzáadása."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Üres"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Feloldási terület kiterjesztve."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Feloldási terület összecsukva."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> modul."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Felhasználóválasztó"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Állapot"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Médiaelemek vezérlője"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"A modulátrendezés elkezdődött."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"A modulátrendezés véget ért."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> modul törölve."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"A feloldási terület kiterjesztése."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Feloldás csúsztatással"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Feloldás mintával"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Arcalapú feloldás"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Feloldás PIN kóddal"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Feloldás jelszóval"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mintaterület"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Csúsztatási terület"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Előző szám gomb"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Következő szám gomb"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Szünet gomb"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Lejátszás gomb"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Leállítás gomb"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Mégse"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Kész"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mód váltása"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Feloldás"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Némítás"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Hang bekapcsolása"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa lefelé."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa balra."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa jobbra."</string>
+    <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Segélyhívás"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Elfelejtett minta"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Helytelen minta"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Helytelen jelszó"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Helytelen PIN kód"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Próbálkozzon újra <xliff:g id="NUMBER">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Rajzolja le a mintát"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Adja meg a SIM kártya PIN kódját"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Adja meg a PIN kódot"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Írja be a jelszót"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"A SIM kártya le van tiltva. A folytatáshoz adja meg a PUK kódot. A részletekért vegye fel a kapcsolatot szolgáltatójával."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Kívánt PIN kód megadása"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Kívánt PIN kód megerősítése"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kártya feloldása..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Helytelen PIN kód."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4–8 számjegyű PIN kódot írjon be."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"A PUK kód legalább  8 számjegyből kell, hogy álljon."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Adja meg újra a helyes PUK kódot. Az ismételt próbálkozással véglegesen letiltja a SIM kártyát."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"A PIN kódok nem egyeznek."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Túl sok mintarajzolási próbálkozás"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"A feloldáshoz jelentkezzen be Google Fiókjával."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Felhasználónév (e-mail cím)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Jelszó"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Bejelentkezés"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Érvénytelen felhasználónév vagy jelszó."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Elfelejtette a felhasználónevét vagy jelszavát?\nKeresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Fiók ellenőrzése..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. \n\n Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"A táblagépet <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a táblagép gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"A telefont <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a telefon gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"A táblagépet <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a táblagép gyári alapértelmezett beállításait."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"A telefont <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a telefon gyári alapértelmezett beállításait."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eltávolítás"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Előző szám gomb"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Következő szám gomb"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Szünet gomb"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Lejátszás gomb"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Leállítás gomb"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nincs szolgáltatás."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-in/activitystrings.xml b/packages/Keyguard/res/values-in/activitystrings.xml
new file mode 100644
index 0000000..ec9774d
--- /dev/null
+++ b/packages/Keyguard/res/values-in/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Tanpa pengamanan"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Sandi"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Pola"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Pilih widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
new file mode 100644
index 0000000..9f731ab
--- /dev/null
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ketik kode PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Ketik kode PUK dan PIN baru"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kode PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Kode Pin baru"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Sentuh untuk mengetikkan sandi"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ketik sandi untuk membuka kunci"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ketik PIN untuk membuka kunci"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kode PIN salah."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Tidak ada kartu SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tidak ada kartu SIM dalam tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Tidak ada Kartu SIM di dalam ponsel."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Masukkan kartu SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Kartu SIM tidak ada atau tidak dapat dibaca. Masukkan kartu SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kartu SIM tidak dapat digunakan."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Kartu SIM Anda telah dinonaktifkan secara permanen.\n Hubungi penyedia layanan nirkabel Anda untuk kartu SIM lain."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kartu SIM terkunci."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kartu SIM terkunci PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Membuka kartu SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tambahkan widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Kosong"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Area buka kunci diluaskan."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Area buka kunci diciutkan."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrol media"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Pengurutan ulang widget dimulai."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Pengurutan ulang widget berakhir."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> dihapus."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Luaskan area buka kunci."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Buka kunci dengan menggeser."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Buka kunci dengan pola."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Buka kunci dengan face unlock."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Buka kunci dengan PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Buka kunci dengan sandi."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Area pola."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Area geser."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tombol lagu sebelumnya"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tombol lagu berikutnya"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tombol jeda"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Tombol putar"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Tombol hentikan"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Hapus"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Selesai"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Pengubahan mode"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Membuka gembok"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Suara hidup"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Geser ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Geser ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Geser ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan darurat"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Pola?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pola Salah"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Sandi Salah"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Salah"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Coba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> detik."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Gambar pola Anda"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Sandi"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM telah dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Hubungi operator untuk keterangan selengkapnya."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Masukkan kode PIN yang diinginkan"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Konfirmasi kode PIN yang diinginkan"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kartu SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kode PIN salah."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ketik PIN yang terdiri dari 4 sampai 8 angka."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kode PUK harus terdiri dari 8 angka atau lebih."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kode PIN tidak cocok"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, masuk dengan akun Google Anda."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama pengguna (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Sandi"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Masuk"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau sandi tidak valid."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau sandi Anda?\nKunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Memeriksa akun…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, tablet akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali gagal saat berusaha membuka kunci ponsel. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, ponsel akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Kini tablet akan disetel ulang ke setelan default pabrik."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha untuk membuka kunci ponsel. Kini ponsel akan disetel ulang ke setelan default pabrik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hapus"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Tombol lagu sebelumnya"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Tombol lagu berikutnya"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tombol jeda"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Tombol putar"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Tombol hentikan"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tidak ada layanan."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-it/activitystrings.xml b/packages/Keyguard/res/values-it/activitystrings.xml
new file mode 100644
index 0000000..34ad96497
--- /dev/null
+++ b/packages/Keyguard/res/values-it/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Nessuna sicurezza"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Password"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Sequenza"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN della SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK della SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Scegli widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
new file mode 100644
index 0000000..4eda348
--- /dev/null
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Inserisci il codice PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Inserisci il PUK e il nuovo codice PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Codice PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nuovo codice PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Tocca per inserire la password"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Inserisci password per sbloccare"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Inserisci PIN per sbloccare"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Codice PIN errato."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nessuna scheda SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Nessuna scheda SIM presente nel tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Nessuna scheda SIM presente nel telefono."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Inserisci una scheda SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Scheda SIM mancante o non leggibile. Inserisci una scheda SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Scheda SIM inutilizzabile."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"La scheda SIM è stata disattivata definitivamente.\n Contatta il fornitore del tuo servizio wireless per ricevere un\'altra scheda SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La SIM è bloccata."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La SIM è bloccata tramite PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Sblocco scheda SIM..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d di %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Aggiungi widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vuoto"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Area di sblocco estesa."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Area di sblocco compressa."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selettore utente"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stato"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotocamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controlli media"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Riordino dei widget iniziato."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Riordino dei widget terminato."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminato."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Espandi area di sblocco."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Sblocco con scorrimento."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Sblocco con sequenza."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Sblocco col sorriso."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Sblocco con PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Sblocco con password."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Area sequenza."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Area di scorrimento."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Pulsante traccia precedente"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Pulsante traccia successiva"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pulsante Pausa"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Pulsante Riproduci"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Pulsante di arresto"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annulla"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Canc"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fine"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio modalità"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maiuscolo"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Invio"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Sblocca"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Fotocamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silenzioso"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Audio attivato"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Giù per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"A destra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Chiamata di emergenza"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Sequenza dimenticata"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequenza sbagliata"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Password sbagliata"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN errato"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Inserisci la sequenza"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Inserisci il PIN della SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Inserisci PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Inserisci la password"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La scheda SIM è disattivata. Inserisci il codice PUK per continuare. Contatta l\'operatore per avere informazioni dettagliate."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Inserisci il codice PIN desiderato"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Conferma il codice PIN desiderato"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Sblocco scheda SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codice PIN errato."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Il PIN deve essere di 4-8 numeri."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Il codice PUK dovrebbe avere almeno otto numeri."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"I codici PIN non corrispondono"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Per sbloccare, accedi con il tuo account Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome utente (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Accedi"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome utente o password non validi."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Hai dimenticato il nome utente o la password?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Controllo account…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di sblocco del tablet. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il tablet verrà sottoposto a un ripristino dei dati di fabbrica e tutti i dati utente andranno persi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di sblocco del telefono. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il telefono verrà sottoposto a un ripristino dei dati di fabbrica e tutti i dati utente andranno persi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"<xliff:g id="NUMBER">%d</xliff:g> tentativi errati di sblocco del tablet. Il tablet verrà sottoposto a un ripristino dei dati di fabbrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"<xliff:g id="NUMBER">%d</xliff:g> tentativi errati di sblocco del telefono. Il telefono verrà sottoposto a un ripristino dei dati di fabbrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Pulsante traccia precedente"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Pulsante traccia successiva"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pulsante Pausa"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Pulsante Riproduci"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Pulsante di arresto"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nessun servizio."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-iw/activitystrings.xml b/packages/Keyguard/res/values-iw/activitystrings.xml
new file mode 100644
index 0000000..84e351a2
--- /dev/null
+++ b/packages/Keyguard/res/values-iw/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"ללא אבטחה"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"סיסמה"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"קו ביטול נעילה"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN של SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK של SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"בחר Widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
new file mode 100644
index 0000000..8d36309
--- /dev/null
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"הקלד קוד PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"הקלד את קוד ה-PUK וקוד  ה-PIN החדש"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"קוד PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"קוד PIN חדש"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"גע כדי להקליד את הסיסמה"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"הקלד סיסמה לביטול הנעילה"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"הקלד קוד PIN לביטול הנעילה"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"קוד PIN שגוי"</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_low_battery" msgid="8143808018719173859">"חבר את המטען."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"רשת נעולה"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"אין כרטיס SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"אין כרטיס SIM בטאבלט."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"אין כרטיס SIM בטלפון."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"הכנס כרטיס SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"כרטיס ה-SIM חסר או שלא ניתן לקרוא אותו. הכנס כרטיס SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"לא ניתן להשתמש בכרטיס SIM זה."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"כרטיס ה-SIM שלך הושבת לצמיתות.\nפנה לספק השירות האלחוטי שלך לקבלת כרטיס SIM אחר."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"כרטיס ה-SIM נעול."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"כרטיס SIM נעול באמצעות PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"מבטל נעילה של כרטיס SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d מתוך %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"הוסף Widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ריק"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"אזור ביטול הנעילה הורחב."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"אזור ביטול הנעילה כווץ."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget ‏<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"בוחר משתמשים"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"סטטוס"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"מצלמה"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"פקדי מדיה"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"סידור מחדש של Widgets התחיל."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"סידור מחדש של Widgets הסתיים."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget ‏<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> נמחק."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"הרחב את אזור ביטול הנעילה."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ביטול נעילה באמצעות הסטה."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ביטול נעילה באמצעות ציור קו."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פרצוף."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ביטול נעילה באמצעות מספר PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ביטול נעילה באמצעות סיסמה."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"אזור ציור קו."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"אזור הסטה."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"לחצן \'הרצועה הקודמת\'"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"לחצן \'הרצועה הבאה\'"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"לחצן \'השהה\'"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"לחצן \'הפעל\'"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"לחצן \'הפסק\'"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"אבג"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ביטול"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"מחק"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"סיום"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"שינוי מצב"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"בטל נעילה"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"מצלמה"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"שקט"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"הקול פועל"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"הסט למטה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"הסט שמאלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"הסט ימינה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"שיחת חירום"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"שכחת את הקו"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"קו ביטול נעילה שגוי"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"סיסמה שגויה"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"מספר PIN שגוי"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"נסה שוב בעוד <xliff:g id="NUMBER">%d</xliff:g> שניות."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"שרטט את קו ביטול הנעילה"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"הזן מספר PIN ל-SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"הזן מספר PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"הזן את הסיסמה"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"כרטיס ה-SIM מושבת כעת. הזן קוד PUK כדי להמשיך. פנה אל הספק לפרטים."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"הזן את קוד ה-PIN הרצוי"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"אשר את קוד ה-PIN הרצוי"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"מבטל נעילה של כרטיס SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"קוד PIN שגוי."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"הקלד מספר PIN שאורכו 4 עד 8 ספרות."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"קוד PUK צריך להיות בן 8 ספרות או יותר."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"הזן מחדש את קוד PUK הנכון. ניסיונות חוזרים ישביתו לצמיתות את כרטיס ה-SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"קודי ה-PIN אינם תואמים"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ניסיונות רבים מדי לשרטוט קו ביטול נעילה."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"כדי לבטל את הנעילה, היכנס באמצעות חשבון Google שלך."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"שם משתמש (דוא\"ל)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"סיסמה"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"היכנס"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"שם משתמש או סיסמה לא חוקיים."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"שכחת את שם המשתמש או הסיסמה?\nבקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"בודק חשבון…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"הסר"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"לחצן \'הרצועה הקודמת\'"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"לחצן \'הרצועה הבאה\'"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"לחצן \'השהה\'"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"לחצן \'הפעל\'"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"לחצן \'הפסק\'"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"אין קליטה."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ja/activitystrings.xml b/packages/Keyguard/res/values-ja/activitystrings.xml
new file mode 100644
index 0000000..b0e77f1
--- /dev/null
+++ b/packages/Keyguard/res/values-ja/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"セキュリティなし"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"パスワード"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"パターン"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"ウィジェットを選択..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
new file mode 100644
index 0000000..92e308b
--- /dev/null
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PINコードを入力"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUKと新しいPINコードを入力"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUKコード"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新しいPINコード"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"タップしてパスワードを入力"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ロックを解除するにはパスワードを入力"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ロックを解除するにはPINを入力"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PINコードが正しくありません。"</string>
+    <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_low_battery" msgid="8143808018719173859">"充電してください。"</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"メニューからロックを解除できます。"</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"ネットワークがロックされました"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIMカードが挿入されていません"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"タブレット内にSIMカードがありません。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"SIMカードが端末に挿入されていません。"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIMカードを挿入してください。"</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIMカードが見つからないか読み取れません。SIMカードを挿入してください。"</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIMカードは使用できません。"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"お使いのSIMカードは永久に無効となっています。\nワイヤレスサービスプロバイダに問い合わせて新しいSIMカードを入手してください。"</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIMカードはロックされています。"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIMカードはPUKでロックされています。"</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIMカードをロック解除しています…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。ウィジェット%2$d/%3$d。"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ウィジェットを追加します。"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"なし"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ロック解除エリアを拡大しました。"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ロック解除エリアを縮小しました。"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ウィジェットです。"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ユーザー切り替え"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ステータス"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"カメラ"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"メディアコントロール"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ウィジェットの並べ替えを開始しました。"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ウィジェットの並べ替えを終了しました。"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ウィジェットを削除しました。"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ロック解除エリアを拡大します。"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"スライドロックを解除します。"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"パターンロックを解除します。"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"フェイスアンロックを行います。"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PINロックを解除します。"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"パスワードロックを解除します。"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"パターンエリアです。"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"スライドエリアです。"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"前のトラックボタン"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"次のトラックボタン"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"一時停止ボタン"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"再生ボタン"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"停止ボタン"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"キャンセル"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"削除"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完了"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"モードを変更"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"ロックを解除"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"カメラ"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"マナーモード"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"サウンドON"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"下にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"左にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"右にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
+    <string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急通報"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"パターンを忘れた場合"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"パターンが正しくありません"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"パスワードが正しくありません"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PINが正しくありません"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g>秒後にもう一度お試しください。"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"パターンを入力"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PINを入力"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PINを入力"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"パスワードを入力"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIMが無効になりました。続行するにはPUKコードを入力してください。詳しくは携帯通信会社にお問い合わせください。"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"希望のPINコードを入力してください"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"希望のPINコードを確認してください"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIMカードのロック解除中…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PINコードが正しくありません。"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"PINは4~8桁の数字で入力してください。"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUKコードは8桁以上の番号です。"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"正しいPUKコードを再入力してください。誤入力を繰り返すと、SIMが永久に無効になるおそれがあります。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PINコードが一致しません"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"パターンの入力を所定の回数以上間違えました。"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"ロックを解除するにはGoogleアカウントでログインしてください。"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"ユーザー名(メール)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"パスワード"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ログイン"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ユーザー名またはパスワードが無効です。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ユーザー名またはパスワードを忘れた場合は\n "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"アカウントをチェックしています…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"削除"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"前のトラックボタン"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"次のトラックボタン"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"一時停止ボタン"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"再生ボタン"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"停止ボタン"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"通信サービスはありません。"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ko/activitystrings.xml b/packages/Keyguard/res/values-ko/activitystrings.xml
new file mode 100644
index 0000000..3aab225
--- /dev/null
+++ b/packages/Keyguard/res/values-ko/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"보안 사용 안함"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"비밀번호"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"패턴"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"위젯 선택..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
new file mode 100644
index 0000000..dfac106
--- /dev/null
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN 코드 입력"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK 및 새 PIN 코드 입력"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 코드"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"새 PIN 코드"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"비밀번호를 입력하려면 터치"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"잠금 해제하려면 비밀번호 입력"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"잠금을 해제하려면 PIN 입력"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 코드가 잘못되었습니다."</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_low_battery" msgid="8143808018719173859">"충전기를 연결하세요."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"잠금해제하려면 메뉴를 누르세요."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"네트워크 잠김"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM 카드가 없습니다."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"태블릿에 SIM 카드가 없습니다."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"휴대전화에 SIM 카드가 없습니다."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIM 카드를 삽입하세요."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM 카드가 없거나 읽을 수 없습니다. SIM 카드를 삽입하세요."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"사용할 수 없는 SIM 카드입니다."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM 카드를 완전히 사용할 수 없게 되었습니다.\n다른 SIM 카드를 사용하려면 무선 서비스 제공업체에 문의하시기 바랍니다."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 카드가 잠겨 있습니다."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 카드가 PUK 잠김 상태입니다."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM 카드 잠금해제 중..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d의 위젯 %2$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"위젯 추가"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"비어 있음"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"잠금 해제 영역 확장됨"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"잠금 해제 영역 축소됨"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> 위젯"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"사용자 선택기"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"상태"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"카메라"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"미디어 조정"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"위젯 재정렬 시작됨"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"위젯 재정렬 완료됨"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> 위젯이 삭제됨"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"잠금 해제 영역 확장"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"슬라이드하여 잠금해제합니다."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"패턴을 사용하여 잠금해제합니다."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"얼굴 인식을 사용하여 잠금해제합니다."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"핀을 사용하여 잠금해제합니다."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"비밀번호를 사용하여 잠금해제합니다."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"패턴을 그리는 부분입니다."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"슬라이드하는 부분입니다."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"이전 트랙 버튼"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"다음 트랙 버튼"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"일시중지 버튼"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"재생 버튼"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"중지 버튼"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 키"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"취소"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 키"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"완료"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"모드 변경"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 키"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 키"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"잠금 해제"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"카메라"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"무음"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"사운드 켜기"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 아래로 슬라이드"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 왼쪽으로 슬라이드"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 오른쪽으로 슬라이드"</string>
+    <string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"긴급 통화"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"패턴을 잊음"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"잘못된 패턴"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"잘못된 비밀번호"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"잘못된 PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"패턴 그리기"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN 입력"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN 입력"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"비밀번호 입력"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"이제 SIM을 사용할 수 없습니다. 계속하려면 PUK 코드를 입력합니다. 자세한 내용은 이동통신사에 문의하세요."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"원하는 PIN 코드 입력"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"원하는 PIN 코드 확인"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM 카드 잠금해제 중..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 코드가 잘못되었습니다."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4~8자리 숫자로 된 PIN을 입력하세요."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 코드는 8자리 이상의 숫자여야 합니다."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM을 영구적으로 사용할 수 없게 됩니다."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 코드가 일치하지 않음"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"패턴 시도 횟수가 너무 많음"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"잠금해제하려면 Google 계정으로 로그인하세요."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"사용자 이름(이메일)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"비밀번호"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"로그인"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"사용자 이름이나 비밀번호를 잊어버렸습니까?\n"<b>"google.com/accounts/recovery"</b>" 페이지를 방문하세요."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"계정 확인 중…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"삭제"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"이전 트랙 버튼"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"다음 트랙 버튼"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"일시중지 버튼"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"재생 버튼"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"중지 버튼"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"서비스 불가"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-land/alias.xml b/packages/Keyguard/res/values-land/alias.xml
new file mode 100644
index 0000000..7aac5b4
--- /dev/null
+++ b/packages/Keyguard/res/values-land/alias.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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.
+*/
+-->
+<resources>
+    <!-- Alias used to reference one of two possible layouts in keyguard.  -->
+    <item type="layout" name="keyguard_eca">@layout/keyguard_emergency_carrier_area_empty</item>
+</resources>
diff --git a/packages/Keyguard/res/values-land/arrays.xml b/packages/Keyguard/res/values-land/arrays.xml
new file mode 100644
index 0000000..240b9e4
--- /dev/null
+++ b/packages/Keyguard/res/values-land/arrays.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Resources for GlowPadView in LockScreen -->
+    <array name="lockscreen_targets_when_silent">
+        <item>@null</item>"
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_soundon</item>
+        <item>@drawable/ic_lockscreen_unlock</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_silent">
+        <item>@null</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_soundon</item>
+        <item>@string/description_target_unlock</item>
+    </array>
+
+    <array name="lockscreen_direction_descriptions">
+        <item>@null</item>
+        <item>@string/description_direction_up</item>
+        <item>@string/description_direction_left</item>
+        <item>@string/description_direction_down</item>
+    </array>
+
+    <array name="lockscreen_targets_when_soundon">
+        <item>@null</item>
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_silent</item>
+        <item>@drawable/ic_lockscreen_unlock</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_soundon">
+        <item>@null</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_silent</item>
+        <item>@string/description_target_unlock</item>
+    </array>
+
+    <array name="lockscreen_targets_with_camera">
+        <item>@null</item>
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_camera</item>
+        <item>@drawable/ic_lockscreen_unlock</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_with_camera">
+        <item>@null</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_camera</item>
+        <item>@string/description_target_unlock</item>
+    </array>
+
+</resources>
diff --git a/packages/Keyguard/res/values-land/bools.xml b/packages/Keyguard/res/values-land/bools.xml
new file mode 100644
index 0000000..a1dd2e4
--- /dev/null
+++ b/packages/Keyguard/res/values-land/bools.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <bool name="kg_enable_camera_default_widget">false</bool>
+    <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
+    <bool name="kg_share_status_area">false</bool>
+    <bool name="kg_sim_puk_account_full_screen">false</bool>
+</resources>
diff --git a/packages/Keyguard/res/values-land/dimens.xml b/packages/Keyguard/res/values-land/dimens.xml
new file mode 100644
index 0000000..64e043c
--- /dev/null
+++ b/packages/Keyguard/res/values-land/dimens.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 a key in the password keyboard for alpha -->
+    <dimen name="password_keyboard_key_height_alpha">47dip</dimen>
+    <!-- Default height of a key in the password keyboard for numeric -->
+    <dimen name="password_keyboard_key_height_numeric">50dip</dimen>
+    <!-- Default correction for the space key in the password keyboard -->
+    <dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen>
+    <dimen name="preference_widget_width">72dp</dimen>
+
+    <!-- Size of clock font in LockScreen on Unsecure unlock screen. -->
+    <dimen name="keyguard_lockscreen_clock_font_size">70sp</dimen>
+
+    <!-- Shift emergency button from the left edge by this amount.  Used by landscape layout on
+         phones -->
+    <dimen name="kg_emergency_button_shift">30dp</dimen>
+
+    <!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
+    <dimen name="kg_secure_padding_height">0dp</dimen>
+
+    <!-- Top padding for the widget pager -->
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
+
+    <!-- Bottom padding for the widget pager -->
+    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+
+    <!-- If the height if keyguard drops below this threshold (most likely
+    due to the appearance of the IME), then drop the multiuser selector.
+    Landscape's layout allows this to be smaller than for portrait. -->
+    <dimen name="kg_squashed_layout_threshold">400dp</dimen>
+
+</resources>
diff --git a/packages/Keyguard/res/values-land/integers.xml b/packages/Keyguard/res/values-land/integers.xml
new file mode 100644
index 0000000..020fd23
--- /dev/null
+++ b/packages/Keyguard/res/values-land/integers.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+-->
+<resources>
+    <!-- Gravity to make KeyguardSelectorView work in multiple orientations
+        0x13 == "left|center_vertical" -->
+    <integer name="kg_selector_gravity">0x13</integer>
+    <integer name="kg_widget_region_weight">45</integer>
+    <integer name="kg_security_flipper_weight">55</integer>
+    <integer name="kg_glowpad_rotation_offset">-90</integer>
+</resources>
diff --git a/packages/Keyguard/res/values-large/dimens.xml b/packages/Keyguard/res/values-large/dimens.xml
new file mode 100644
index 0000000..8cd614d
--- /dev/null
+++ b/packages/Keyguard/res/values-large/dimens.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<resources>
+    <!-- Default height of a key in the password keyboard for alpha -->
+    <dimen name="password_keyboard_key_height_alpha">75dip</dimen>
+    <!-- Default height of a key in the password keyboard for numeric -->
+    <dimen name="password_keyboard_key_height_numeric">75dip</dimen>
+    <!-- keyboardHeight = key_height*4 + key_bottom_gap*3 -->
+    <dimen name="password_keyboard_height">48.0mm</dimen>
+
+    <!-- Minimum width of the search view text entry area. -->
+    <dimen name="search_view_text_min_width">192dip</dimen>
+
+    <item type="dimen" name="dialog_min_width_major">55%</item>
+    <item type="dimen" name="dialog_min_width_minor">80%</item>
+
+    <!-- Preference UI dimensions for larger screens. -->
+    <dimen name="preference_widget_width">56dp</dimen>
+</resources>
diff --git a/packages/Keyguard/res/values-lt/activitystrings.xml b/packages/Keyguard/res/values-lt/activitystrings.xml
new file mode 100644
index 0000000..9ec21e4
--- /dev/null
+++ b/packages/Keyguard/res/values-lt/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Neapsaugota"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN kodas"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Slaptažodis"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Šablonas"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM kortelės PIN kodas"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM kortelės PUK kodas"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Pasirinkite valdiklį..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
new file mode 100644
index 0000000..29f62a7
--- /dev/null
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Įveskite PIN kodą"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Įveskite PUK ir naują PIN kodus"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kodas"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Naujas PIN kodas"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Palieskite, kad įves. slaptaž."</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Jei norite atrakinti, įveskite slaptažodį"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Jei norite atrakinti, įveskite PIN kodą"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Neteisingas PIN kodas."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nėra SIM kortelės"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Planšetiniame kompiuteryje nėra SIM kortelės."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefone nėra SIM kortelės."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Įdėkite SIM kortelę."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Trūksta SIM kortelės arba ji neskaitoma. Įdėkite SIM kortelę."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Negalima naudoti SIM kortelės."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM kortelė visam laikui neleidžiama.\n Jei norite gauti kitą SIM kortelę, susisiekite su belaidžio ryšio paslaugos teikėju."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kortelė užrakinta."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kortelė užrakinta PUK kodu."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Atrakinama SIM kortelė…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d valdiklis iš %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Pridėti valdiklį."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tuščia"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Atrakinimo sritis išplėsta."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Atrakinimo sritis sutraukta."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Valdiklis <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Naudotojo pasirinkimo valdiklis"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Būsena"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparatas"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Medijos valdikliai"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Valdiklių pertvarkymas pradėtas."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Valdiklių pertvarkymas baigtas."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Valdiklis <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ištrintas."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Išplėsti atrakinimo sritį."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Atrakinimas slystant."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Atrakinimas pagal piešinį."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Atrakinimas pagal veidą."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Atrakinimas įvedus PIN kodą."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Atrakinimas įvedus slaptažodį."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Atrakinimo pagal piešinį sritis."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Slydimo sritis."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Ankstesnio takelio mygtukas"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Kito takelio mygtukas"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pristabdymo mygtukas"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Paleidimo mygtukas"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Sustabdymo mygtukas"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atšaukti"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ištrinti"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Atlikta"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režimo keitimas"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Įvesti"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Atrakinti"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Vaizdo kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Begarsis"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Garsas įjungtas"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Slyskite žemyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Slyskite į kairę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Slyskite į dešinę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Skambutis pagalbos numeriu"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pamiršau atrakinimo piešinį"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Netinkamas atrakinimo piešinys"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Netinkamas slaptažodis"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Netinkamas PIN kodas"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Bandyti dar kartą po <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nupieškite atrakinimo piešinį"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Įveskite SIM PIN kodą"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Įveskite PIN kodą"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Įveskite slaptažodį"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Dabar SIM neleidžiama. Jei norite tęsti, įveskite PUK kodą. Jei reikia išsamios informacijos, susisiekite su operatoriumi."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Įveskite pageidaujamą PIN kodą"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Patvirtinkite pageidaujamą PIN kodą"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Atrakinama SIM kortelė…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netinkamas PIN kodas."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Įveskite PIN kodą, sudarytą iš 4–8 skaičių."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodas turėtų būti mažiausiai 8 skaitmenų."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM bus neleidžiama visam laikui."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodai neatitinka"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Jei norite atrakinti, prisijunkite naudodami „Google“ paskyrą."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Naudotojo vardas (el. paštas)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Slaptažodis"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prisijungti"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Netinkamas naudotojo vardas ar slaptažodis."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Pamiršote naudotojo vardą ar slaptažodį?\nApsilankykite šiuo adresu: "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Tikrinama paskyra…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"<xliff:g id="NUMBER_0">%d</xliff:g> k. bandėte netinkamai atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"<xliff:g id="NUMBER_0">%d</xliff:g> k. bandėte netinkamai atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"<xliff:g id="NUMBER">%d</xliff:g> k. bandėte netinkamai atrakinti planšetinį kompiuterį. Planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"<xliff:g id="NUMBER">%d</xliff:g> k. bandėte netinkamai atrakinti telefoną. Telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Pašalinti"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Ankstesnio takelio mygtukas"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Kito takelio mygtukas"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pristabdymo mygtukas"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Paleidimo mygtukas"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Sustabdymo mygtukas"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nėra paslaugos."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-lv/activitystrings.xml b/packages/Keyguard/res/values-lv/activitystrings.xml
new file mode 100644
index 0000000..96807de
--- /dev/null
+++ b/packages/Keyguard/res/values-lv/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Drošība nav iespējota"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Parole"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Kombinācija"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Izvēlēties logrīku..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
new file mode 100644
index 0000000..aa13934
--- /dev/null
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ievadiet PIN kodu."</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Ievadiet PUK kodu un jaunu PIN kodu."</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kods"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Jauns PIN kods"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Pieskarieties, lai ievadītu paroli"</font>"."</string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ievadiet paroli, lai atbloķētu."</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Lai atbloķētu, ievadiet PIN."</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kods nav pareizs."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nav SIM kartes."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Planšetdatorā nav SIM kartes."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Tālrunī nav SIM kartes."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Ievietojiet SIM karti."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Nav SIM kartes, vai arī to nevar nolasīt. Ievietojiet SIM karti."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM karte nav lietojama."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Jūsu SIM karte ir neatgriezeniski atspējota.\nSazinieties ar savu bezvadu pakalpojumu sniedzēju, lai iegūtu citu SIM karti."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM karte ir bloķēta."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM karte ir bloķēta ar PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Notiek SIM kartes atbloķēšana..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d. logrīks no %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Pievienot logrīku."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tukšs"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Atbloķēšanas apgabals ir izvērsts."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Atbloķēšanas apgabals ir sakļauts."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Logrīks <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Lietotāju atlasītājs"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Statuss"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multivides vadīklas"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Logrīku pārkārtošana ir sākta."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Logrīku pārkārtošana ir pabeigta."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Logrīks <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ir izdzēsts."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Izvērst atbloķēšanas apgabalu."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Autorizācija, velkot ar pirkstu."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Autorizācija ar kombināciju."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Autorizācija pēc sejas."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Autorizācija ar PIN kodu."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Autorizācija ar paroli."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kombinācijas ievades apgabals."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Apgabals, kur vilkt ar pirkstu."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Iepriekšējā ieraksta poga"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nākamā ieraksta poga"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pārtraukšanas poga"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Atskaņošanas poga"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Apturēšanas poga"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alternēšanas taustiņš"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atcelt"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Dzēšanas taustiņš"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gatavs"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režīma maiņa"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Pārslēgšanas taustiņš"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ievadīšanas taustiņš"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Atbloķēt"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Klusums"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Skaņa ieslēgta"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Velciet uz leju, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Velciet pa kreisi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Velciet pa labi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Ārkārtas izsaukums"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Aizmirsu kombināciju"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nepareiza kombinācija"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nepareiza parole"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nepareizs PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER">%d</xliff:g> sekundēm."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Norādiet savu kombināciju"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ievadiet SIM kartes PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ievadiet PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ievadiet paroli"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM karte ir atspējota. Lai turpinātu, ievadiet PUK kodu. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ievadiet vēlamo PIN kodu."</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Apstipriniet vēlamo PIN."</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Notiek SIM kartes atbloķēšana..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN kods nav pareizs."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ievadiet PIN, kas sastāv no 4 līdz 8 cipariem."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodam ir jābūt vismaz 8 ciparus garam."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Atkārtoti ievadiet pareizo PUK kodu. Ja vairākas reizes ievadīsiet to nepareizi, SIM karte tiks neatgriezeniski atspējota."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodi neatbilst."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Pārāk daudz kombinācijas mēģinājumu"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Lai atbloķētu, pierakstieties, izmantojot savu Google kontu."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Lietotājvārds (e-pasts)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parole"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Pierakstīties"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nederīgs lietotājvārds vai parole."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vai aizmirsāt lietotājvārdu vai paroli?\nApmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Notiek konta pārbaude…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi un lietotāja dati tiks zaudēti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi un lietotāja dati tiks zaudēti."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">"  — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Noņemt"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Iepriekšējā ieraksta poga"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nākamā ieraksta poga"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pārtraukšanas poga"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Atskaņošanas poga"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Apturēšanas poga"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nav pakalpojuma."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ms/activitystrings.xml b/packages/Keyguard/res/values-ms/activitystrings.xml
new file mode 100644
index 0000000..04e2184
--- /dev/null
+++ b/packages/Keyguard/res/values-ms/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Tiada keselamatan"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Kata laluan"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Corak"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Pilih widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ms/strings.xml b/packages/Keyguard/res/values-ms/strings.xml
new file mode 100644
index 0000000..0aeeeb5
--- /dev/null
+++ b/packages/Keyguard/res/values-ms/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Taip kod PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Taip PUK dan kod PIN baharu"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kod PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Kod PIN Baharu"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Sentuh untuk menaip kata laluan"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Taip kata laluan untuk membuka kunci"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Taip PIN untuk membuka kunci"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kod PIN salah."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Tiada kad SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tiada kad SIM dalam tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Tiada kad SIM dalam telefon."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Masukkan kad SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Kad SIM tiada atau tidak boleh dibaca. Sila masukkan kad SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kad SIM tidak boleh digunakan."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Kad SIM anda telah dilumpuhkan secara kekal.\n Hubungi pembekal perkhidmatan wayarles anda untuk mendapatkan kad SIM lain."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kad SIM dikunci."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kad SIM dikunci dengan PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Membuka kunci kad SIM..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tambah widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Kosong"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Bahagian buka kunci dikembangkan."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Bahagian buka kunci diruntuhkan."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kawalan media"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Penyusunan semula widget dimulakan."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Penyusunan semula widget tamat."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> dipadamkan."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Kembangkan bahagian buka kunci."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Buka kunci luncur."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Buka kunci corak."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Wajah Buka Kunci"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Buka kunci pin."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Buka kunci kata laluan."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kawasan corak."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Kawasan luncur."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butang lagu sebelumnya"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butang lagu seterusnya"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butang jeda"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Butang main"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Butang berhenti"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Padam"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Selesai"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Perubahan mod"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Masuk"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Buka kunci"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Bunyi dihidupkan"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Luncurkan ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Luncurkan ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Luncurkan ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Corak Salah"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Kata Laluan Salah"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN salah"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Cuba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> saat."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Lukiskan corak anda"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Kata Laluan"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Hubungi pembawa untuk butiran."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Masukkan kod PIN yang diingini"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Sahkan kod PIN yang diingini"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK mestilah 8 nombor atau lebih."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Kata laluan"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?\nLawati"<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Menyemak akaun…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah mencuba untuk membuka kunci tablet dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, tablet akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah mencuba untuk membuka kunci telefon dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, telefon akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah mencuba untuk membuka kunci tablet secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah mencuba untuk membuka kunci telefon secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Butang lagu sebelumnya"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Butang lagu seterusnya"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Butang jeda"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Butang main"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Butang berhenti"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-nb/activitystrings.xml b/packages/Keyguard/res/values-nb/activitystrings.xml
new file mode 100644
index 0000000..015df15
--- /dev/null
+++ b/packages/Keyguard/res/values-nb/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Ingen sikkerhet"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Passord"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Mønster"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"Personlig kode for SIM-kort"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-kode for SIM-kort"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Velg modul"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
new file mode 100644
index 0000000..6a5bfa9
--- /dev/null
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Skriv inn PIN-kode"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Skriv inn PUK-kode og ny personlig kode"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kode"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Ny PIN-kode"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Trykk for å skrive inn passord"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Skriv inn passord for å låse opp"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Skriv inn PIN-kode for å låse opp"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Feil personlig kode."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM-kortet mangler"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Nettbrettet mangler SIM-kort."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefonen mangler SIM-kort."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Sett inn et SIM-kort."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-kort mangler eller er uleselig. Sett inn et SIM-kort."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Ubrukelig SIM-kort."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-kortet er deaktivert permanent.\nTa kontakt med leverandøren av trådløstjenesten for å få et nytt SIM-kort."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortet er låst."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortet er PUK-låst."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Låser opp SIM-kortet ..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Modul %2$d av %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Legg til modul."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tom"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Opplåsingsfeltet vises."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Opplåsingsfeltet skjules."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-modul."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Brukervelgeren"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediekontroll"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Endring av modulplasseringen har startet."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Endringen av modulplasseringen er ferdig."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Modulen <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ble slettet."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Vis opplåsingsfeltet."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Opplåsning ved å dra med fingeren."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mønsteropplåsning."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Ansiktsopplåsning."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-opplåsning."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Passordopplåsning."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mønsterområde."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Dra-felt."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Forrige spor-knapp"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Neste spor-knapp"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause-knapp"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Avspillingsknapp"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stopp-knapp"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slett"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Ferdig"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modusendring"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Lås opp"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Stille"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Lyd på"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Dra ned for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Dra til venstre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Dra til høyre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødnummer"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glemt mønsteret?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Feil mønster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Feil passord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Feil PIN-kode"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv på nytt om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn mønsteret ditt"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Skriv inn PIN-koden for SIM-kortet"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Skriv inn PIN-koden"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Skriv inn passordet"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nå deaktivert. Skriv inn PUK-koden for å fortsette. Ta kontakt med operatøren for mer informasjon."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Tast inn ønsket PIN-kode"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bekreft ønsket PIN-kode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser opp SIM-kortet ..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Feil PIN-kode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Skriv inn en PIN-kode på fire til åtte sifre."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på åtte eller flere siffer."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Logg deg på med Google-kontoen din for å låse opp."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Brukernavn (e-postadresse)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Passord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logg på"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldig brukernavn eller passord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Sjekker kontoen ..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har oppgitt feil opplåsningspassord for nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, tilbakestilles nettbrettet til fabrikkstandard og all data går tapt."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har oppgitt feil opplåsningspassord for telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, tilbakestilles telefonen til fabrikkstandard og all data går tapt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har oppgitt feil opplåsningspassord for nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Telefonen tilbakestilles nå til fabrikkstandard."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har oppgitt feil opplåsningspassord for telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Telefonen tilbakestilles nå til fabrikkstandard."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Forrige spor-knapp"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Neste spor-knapp"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause-knapp"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Avspillingsknapp"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stopp-knappen"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjeneste."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-nl/activitystrings.xml b/packages/Keyguard/res/values-nl/activitystrings.xml
new file mode 100644
index 0000000..fcb0be9
--- /dev/null
+++ b/packages/Keyguard/res/values-nl/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Geen beveiliging"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"Pincode"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Wachtwoord"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Patroon"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"Pincode van simkaart"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-code van simkaart"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Widget kiezen…"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
new file mode 100644
index 0000000..b94cb70
--- /dev/null
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Pincode typen"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Geef de PUK-code en de nieuwe pincode op"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-code"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nieuwe pincode"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Raak aan om wachtwoord in te voeren"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Typ het wachtwoord om te ontgrendelen"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Typ pincode om te ontgrendelen"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Onjuiste pincode."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Geen simkaart"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Geen simkaart in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Geen simkaart in telefoon."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Plaats een simkaart."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"De simkaart ontbreekt of kan niet worden gelezen. Plaats een simkaart."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Onbruikbare simkaart."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Uw simkaart is permanent uitgeschakeld.\n Neem contact op met uw mobiele serviceprovider voor een nieuwe simkaart."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Simkaart is vergrendeld."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Simkaart is vergrendeld met PUK-code."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Simkaart ontgrendelen…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d van %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Widget toevoegen."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Leeg"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ontgrendelingsgebied uitgevouwen."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ontgrendelingsgebied samengevouwen."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Gebruikersselectie"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediabediening"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Opnieuw indelen van widget gestart."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Opnieuw indelen van widget beëindigd."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> verwijderd."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ontgrendelingsgebied uitvouwen."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Ontgrendeling via schuiven."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ontgrendeling via patroon."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Ontgrendelen via gezichtsherkenning"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Ontgrendeling via pincode."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Ontgrendeling via wachtwoord."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Tekengebied voor patroon."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Schuifgebied."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knop voor vorig nummer"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knop voor volgend nummer"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Knop voor onderbreken"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Knop voor afspelen"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Knop voor stoppen"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuleren"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gereed"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modus wijzigen"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Ontgrendelen"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Stil"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Geluid aan"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Veeg omlaag voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Veeg naar links voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Veeg naar rechts voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patroon vergeten"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Onjuist patroon"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Onjuist wachtwoord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Onjuiste pincode"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken uw patroon"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Geef de pincode van de simkaart op"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Pincode opgeven"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Wachtwoord invoeren"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"De simkaart is nu uitgeschakeld. Geef de PUK-code op om door te gaan. Neem contact op met de provider voor informatie."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Gewenste pincode opgeven"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Gewenste pincode bevestigen"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Simkaart ontgrendelen..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Onjuiste pincode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Voer een pincode van 4 tot 8 cijfers in."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"De PUK-code is minimaal acht nummers lang."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u inloggen op uw Google-account."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikersnaam (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Wachtwoord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Inloggen"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikersnaam of wachtwoord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?\nGa naar "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Account controleren…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de tablet en gaan alle gebruikersgegevens verloren."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"U heeft nu <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de telefoon en gaan alle gebruikersgegevens verloren."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de tablet."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de telefoon."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Knop voor vorig nummer"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Knop voor volgend nummer"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Knop voor onderbreken"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Knop voor afspelen"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Knop voor stoppen"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen service"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-pl/activitystrings.xml b/packages/Keyguard/res/values-pl/activitystrings.xml
new file mode 100644
index 0000000..f04170e
--- /dev/null
+++ b/packages/Keyguard/res/values-pl/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Bez zabezpieczeń"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Hasło"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Wzór"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN do karty SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK do karty SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Wybierz widżet..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
new file mode 100644
index 0000000..15a4a7c
--- /dev/null
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Wpisz kod PIN."</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Wpisz kod PUK i nowy kod PIN."</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kod PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nowy PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dotknij, aby wpisać hasło."</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Wpisz hasło, aby odblokować."</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Wpisz kod PIN, aby odblokować."</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Błędny kod PIN"</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Brak karty SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Brak karty SIM w tablecie."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Brak karty SIM w telefonie."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Włóż kartę SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Brak karty SIM lub nie można jej odczytać. Włóż kartę SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Karta SIM bezużyteczna."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Karta SIM jest trwale wyłączona.\n Skontaktuj się z dostawcą usług bezprzewodowych, by otrzymać inną kartę SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Karta SIM jest zablokowana."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Karta SIM jest zablokowana za pomocą kodu PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Odblokowuję kartę SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widżet %2$d z %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodaj widżet."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Puste"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Rozwinięto obszar odblokowania."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Zwinięto obszar odblokowania."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widżet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Wybór użytkownika"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stan"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Aparat"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Elementy sterujące multimediów"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Rozpoczęto zmienianie kolejności widżetów."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Zakończono zmienianie kolejności widżetów."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Usunięto widżet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Rozwiń obszar odblokowania."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odblokowanie przesunięciem."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odblokowanie wzorem."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Rozpoznanie twarzy"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odblokowanie kodem PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odblokowanie hasłem."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Obszar wzoru."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Obszar przesuwania."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Przycisk poprzedniego utworu"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Przycisk następnego utworu"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Przycisk wstrzymania"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Przycisk odtwarzania"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Przycisk zatrzymania"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anuluj"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotowe"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Zmiana trybu"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Odblokuj"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Aparat"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Wyciszenie"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Włącz dźwięk"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Przesuń w dół: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Przesuń w lewo: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Przesuń w prawo: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Połączenie alarmowe"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nie pamiętam wzoru"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nieprawidłowy wzór"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nieprawidłowe hasło"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nieprawidłowy PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Narysuj wzór"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Podaj PIN karty SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Podaj PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Wpisz hasło"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Karta SIM została wyłączona. Podaj kod PUK, by przejść dalej. Szczegóły uzyskasz od operatora."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Podaj wybrany kod PIN"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potwierdź wybrany kod PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokowuję kartę SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nieprawidłowy PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Wpisz PIN o długości od 4 do 8 cyfr."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK musi mieć co najmniej 8 cyfr."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponownie podaj poprawny kod PUK. Nieudane próby spowodują trwałe wyłączenie karty SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kody PIN nie pasują"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Aby odblokować, zaloguj się na konto Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nazwa użytkownika (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Hasło"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Zaloguj się"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nieprawidłowa nazwa użytkownika lub hasło."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nie pamiętasz nazwy użytkownika lub hasła?\nWejdź na "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Sprawdzam konto"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie teraz zresetowany do ustawień fabrycznych."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie teraz zresetowany do ustawień fabrycznych."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Usuń"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Przycisk poprzedniego utworu"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Przycisk następnego utworu"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Przycisk wstrzymania"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Przycisk odtwarzania"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Przycisk zatrzymania"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Brak usługi."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-port/alias.xml b/packages/Keyguard/res/values-port/alias.xml
new file mode 100644
index 0000000..c3ecbb9
--- /dev/null
+++ b/packages/Keyguard/res/values-port/alias.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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.
+*/
+-->
+<resources>
+    <!-- Alias used to reference one of two possible layouts in keyguard.  -->
+    <item type="layout" name="keyguard_eca">@layout/keyguard_emergency_carrier_area</item>
+</resources>
diff --git a/packages/Keyguard/res/values-port/bools.xml b/packages/Keyguard/res/values-port/bools.xml
new file mode 100644
index 0000000..1e2a4f2
--- /dev/null
+++ b/packages/Keyguard/res/values-port/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <bool name="action_bar_embed_tabs">false</bool>
+    <bool name="kg_share_status_area">true</bool>
+    <bool name="kg_sim_puk_account_full_screen">true</bool>
+</resources>
diff --git a/packages/Keyguard/res/values-port/integers.xml b/packages/Keyguard/res/values-port/integers.xml
new file mode 100644
index 0000000..ef7e4da
--- /dev/null
+++ b/packages/Keyguard/res/values-port/integers.xml
@@ -0,0 +1,23 @@
+<?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.
+*/
+-->
+<resources>
+    <!-- Gravity to make KeyguardSelectorView work in multiple orientations
+        0x31 == "top|center_horizontal" -->
+    <integer name="kg_selector_gravity">0x31</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-pt-rPT/activitystrings.xml b/packages/Keyguard/res/values-pt-rPT/activitystrings.xml
new file mode 100644
index 0000000..470865d
--- /dev/null
+++ b/packages/Keyguard/res/values-pt-rPT/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Sem segurança"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Palavra-passe"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Sequência"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN do SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK do SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Escolher widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..222051c
--- /dev/null
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Escreva o código PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Escreva o PUK e o novo código PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Código PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novo código PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Toque para escrever a palavra-passe"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Escreva a palavra-passe para desbloquear"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Escreva o PIN para desbloquear"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nenhum cartão SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Nenhum cartão SIM no tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Nenhum cartão SIM no telemóvel."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insira um cartão SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"O cartão SIM está em falta ou não é legível. Introduza um cartão SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Cartão SIM inutilizável."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"O cartão SIM foi desativado definitivamente.\n Contacte o seu fornecedor de serviços de rede sem fios para obter outro cartão SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"O cartão SIM está bloqueado."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"O cartão SIM está bloqueado por PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"A desbloquear o cartão SIM..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Adicionar widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vazio"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueio expandida."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueio minimizada."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Seletor de utilizadores"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Estado"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Câmara"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controlos de multimédia"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Reordenação de widgets iniciada."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordenação de widgets concluída."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandir área de desbloqueio."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueio através de deslize."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio através de sequência."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio através do rosto."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio através de PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio através de palavra-passe."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área da sequência."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botão Faixa anterior"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botão Faixa seguinte"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botão Pausa"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botão Reproduzir"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botão Parar"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Concluído"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Alteração do modo"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Câmara"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Som ativado"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Deslize para baixo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Deslize para a esquerda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Deslize para a direita para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueceu-se da Sequência"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequência Incorreta"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Palavra-passe Incorreta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Incorreto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe a sua sequência"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduzir PIN do cartão SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduzir PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduzir Palavra-passe"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O SIM está agora desativado. Introduza o código PUK para continuar. Contacte o operador para obter detalhes."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduza o código PIN pretendido"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirme o código PIN pretendido"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"A desbloquear cartão SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduza um PIN entre 4 e 8 números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"O código PUK deve ter 8 ou mais números."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não correspondem"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiadas tentativas para desenhar sequência"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, inicie sessão com a sua Conta do Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de utilizador (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Palavra-passe"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sessão"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de utilizador ou palavra-passe inválidos."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu-se do nome de utilizador ou da palavra-passe?\nAceda a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"A verificar a conta…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tentou desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, as definições de origem do telemóvel serão repostas e todos os dados do utilizador serão perdidos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, as definições de origem do telemóvel serão repostas e todos os dados do utilizador serão perdidos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tentou desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que será reposta a predefinição de fábrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que será reposta a predefinição de fábrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botão Faixa anterior"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botão Faixa seguinte"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botão Pausa"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botão Reproduzir"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botão Parar"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-pt/activitystrings.xml b/packages/Keyguard/res/values-pt/activitystrings.xml
new file mode 100644
index 0000000..7a63708
--- /dev/null
+++ b/packages/Keyguard/res/values-pt/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Sem segurança"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Senha"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Padrão"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN do SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK do SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Escolher widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
new file mode 100644
index 0000000..a563372
--- /dev/null
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Insira o código PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Insira o PUK e o novo código PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Código PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novo código PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Toque para inserir a senha"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Digite a senha para desbloquear"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Insira o PIN para desbloquear"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Sem cartão SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Não há um cartão SIM no tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Não há um cartão SIM no telefone."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insira um cartão SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"O cartão SIM não foi inserido ou não é possível lê-lo. Insira um cartão SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Cartão SIM inutilizável."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"O cartão SIM foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para receber outro cartão SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"O cartão SIM está bloqueado."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"O cartão SIM está bloqueado pelo PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando o cartão SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Adicionar widget"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vazio"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueio expandida."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueio recolhida."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Seletor de usuários"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Câmera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de mídia"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Reordenação de widgets iniciada."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordenação de widgets concluída."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> excluído."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandir a área de desbloqueio."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueio com deslize."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio com padrão."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio facial."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio com PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio com senha."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área do padrão."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botão \"Faixa anterior\""</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botão \"Próxima faixa\""</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botão \"Pausar\""</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botão \"Reproduzir\""</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botão \"Parar\""</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Excluir"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Concluído"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Alteração do modo"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Câmera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Som ativado"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para baixo."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para a esquerda."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para a direita."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueci o padrão"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Padrão incorreto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Senha incorreta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorreto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe seu padrão"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do cartão SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Digite o PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Digite a senha"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para obter mais detalhes."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Digite o código PIN desejado"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirme o código PIN desejado"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o cartão SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Digite um PIN com quatro a oito números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"O código PUK deve ter 8 números ou mais."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, faça login usando sua Conta do Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de usuário (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Senha"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Fazer login"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de usuário ou senha inválidos."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu seu nome de usuário ou senha?\nAcesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Verificando a conta..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o tablet será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o telefone será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O tablet será redefinido para o padrão de fábrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER">%d</xliff:g> vezes. O telefone será redefinido para o padrão de fábrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botão \"Faixa anterior\""</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botão \"Próxima faixa\""</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botão \"Pausar\""</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botão \"Reproduzir\""</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botão \"Parar\""</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-rm/strings.xml b/packages/Keyguard/res/values-rm/strings.xml
new file mode 100644
index 0000000..8dda055
--- /dev/null
+++ b/packages/Keyguard/res/values-rm/strings.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_puk_code (4800725266925845333) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_puk_prompt (1341112146710087048) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_pin_prompt (8027680321614196258) -->
+    <skip />
+    <!-- no translation found for keyguard_password_entry_touch_hint (7858547464982981384) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_password_code (1054721668279049780) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_pin_password_code (6391755146112503443) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (2422225591006134936) -->
+    <skip />
+    <string name="keyguard_label_text" msgid="861796461028298424">"Smatgai per debloccar sin la tasta Menu e lura sin 0."</string>
+    <!-- no translation found for faceunlock_multiple_failures (754137583022792429) -->
+    <skip />
+    <!-- no translation found for keyguard_charged (3272223906073492454) -->
+    <skip />
+    <!-- no translation found for keyguard_plugged_in (8117572000639998388) -->
+    <skip />
+    <!-- no translation found for keyguard_low_battery (8143808018719173859) -->
+    <skip />
+    <!-- no translation found for keyguard_instructions_when_pattern_disabled (1332288268600329841) -->
+    <skip />
+    <!-- no translation found for keyguard_network_locked_message (9169717779058037168) -->
+    <skip />
+    <!-- no translation found for keyguard_missing_sim_message_short (494980561304211931) -->
+    <skip />
+    <!-- no translation found for keyguard_missing_sim_message (1445849005909260039) -->
+    <skip />
+    <!-- no translation found for keyguard_missing_sim_message (3481110395508637643) -->
+    <skip />
+    <!-- no translation found for keyguard_missing_sim_instructions (5210891509995942250) -->
+    <skip />
+    <!-- no translation found for keyguard_missing_sim_instructions_long (5968985489463870358) -->
+    <skip />
+    <!-- no translation found for keyguard_permanent_disabled_sim_message_short (8340813989586622356) -->
+    <skip />
+    <!-- no translation found for keyguard_permanent_disabled_sim_instructions (5892940909699723544) -->
+    <skip />
+    <!-- no translation found for keyguard_sim_locked_message (6875773413306380902) -->
+    <skip />
+    <!-- no translation found for keyguard_sim_puk_locked_message (3747232467471801633) -->
+    <skip />
+    <!-- no translation found for keyguard_sim_unlock_progress_dialog_message (7975221805033614426) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_add_widget (8273277058724924654) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_empty_slot (1281505703307930757) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_unlock_area_expanded (2278106022311170299) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_unlock_area_collapsed (6366992066936076396) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget (6527131039741808240) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_camera (8904231194181114603) -->
+    <skip />
+    <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_reorder_start (8736853615588828197) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_reorder_end (7170190950870468320) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_deleted (4426204263929224434) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_expand_lock_area (519859720934178024) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_slide_unlock (2959928478764697254) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_pattern_unlock (1490840706075246612) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_face_unlock (4817282543351718535) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_pin_unlock (2469687111784035046) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_password_unlock (7675777623912155089) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_pattern_area (7679891324509597904) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_slide_area (6736064494019979544) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_transport_prev_description (1337286538318543555) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_transport_next_description (7073928300444909320) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_transport_pause_description (8455979545295224302) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_transport_play_description (8146417789511154044) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_transport_stop_description (7656358482980912216) -->
+    <skip />
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <!-- no translation found for keyboardview_keycode_alt (4856868820040051939) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_cancel (1203984017245783244) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_delete (3337914833206635744) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_done (1992571118466679775) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_mode_change (4547387741906537519) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_shift (2270748814315147690) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_enter (2985864015076059467) -->
+    <skip />
+    <!-- no translation found for description_target_unlock (2228524900439801453) -->
+    <skip />
+    <!-- no translation found for description_target_camera (969071997552486814) -->
+    <skip />
+    <!-- no translation found for description_target_silent (893551287746522182) -->
+    <skip />
+    <!-- no translation found for description_target_soundon (30052466675500172) -->
+    <skip />
+    <!-- no translation found for description_target_search (3091587249776033139) -->
+    <skip />
+    <!-- no translation found for description_direction_up (7169032478259485180) -->
+    <skip />
+    <!-- no translation found for description_direction_down (5087739728639014595) -->
+    <skip />
+    <!-- no translation found for description_direction_left (7207478719805562165) -->
+    <skip />
+    <!-- no translation found for description_direction_right (8034433242579600980) -->
+    <skip />
+    <!-- no translation found for user_switched (3768006783166984410) -->
+    <skip />
+    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
+    <skip />
+    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
+    <skip />
+    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
+    <skip />
+    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
+    <skip />
+    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_attempts_countdown (6358110221603297548) -->
+    <skip />
+    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
+    <skip />
+    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
+    <skip />
+    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
+    <skip />
+    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
+    <skip />
+    <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
+    <skip />
+    <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
+    <skip />
+    <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
+    <skip />
+    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
+    <skip />
+    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
+    <skip />
+    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
+    <skip />
+    <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
+    <skip />
+    <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
+    <skip />
+    <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
+    <skip />
+    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
+    <skip />
+    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
+    <skip />
+    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
+    <skip />
+    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
+    <skip />
+    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
+    <skip />
+    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
+    <skip />
+    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
+    <skip />
+    <!-- no translation found for kg_login_checking_password (1052685197710252395) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_pin_attempts_dialog_message (8276745642049502550) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_password_attempts_dialog_message (7813713389422226531) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_pattern_attempts_dialog_message (74089475965050805) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (1575557200627128949) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (4051015943038199910) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (2072996269148483637) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (4817627474419471518) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (3253575572118914370) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (1437638152015574839) -->
+    <skip />
+    <!-- no translation found for kg_text_message_separator (4160700433287233771) -->
+    <skip />
+    <!-- no translation found for kg_reordering_delete_drop_target_text (7899202978204438708) -->
+    <skip />
+    <!-- no translation found for keyguard_transport_prev_description (8229108430245669854) -->
+    <skip />
+    <!-- no translation found for keyguard_transport_next_description (4299258300283778305) -->
+    <skip />
+    <!-- no translation found for keyguard_transport_pause_description (5093073338238310224) -->
+    <skip />
+    <!-- no translation found for keyguard_transport_play_description (2924628863741150956) -->
+    <skip />
+    <!-- no translation found for keyguard_transport_stop_description (3084179324810575787) -->
+    <skip />
+    <!-- no translation found for keyguard_carrier_default (8700650403054042153) -->
+    <skip />
+</resources>
diff --git a/packages/Keyguard/res/values-ro/activitystrings.xml b/packages/Keyguard/res/values-ro/activitystrings.xml
new file mode 100644
index 0000000..6d3447d
--- /dev/null
+++ b/packages/Keyguard/res/values-ro/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Fără securitate"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Parolă"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Model"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Alegeți un widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
new file mode 100644
index 0000000..01d79f8
--- /dev/null
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceţi codul PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduceţi codul PUK şi noul cod PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Codul PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Noul cod PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeţi şi introduceţi parola"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Niciun card SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tableta nu are card SIM."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefonul nu are card SIM."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Introduceți un card SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Cardul SIM lipsește sau nu poate fi citit. Introduceți un card SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Card SIM inutilizabil."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Cardul SIM este dezactivat definitiv.\n Contactați furnizorul de servicii wireless pentru a obține alt card SIM."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Cardul SIM este blocat."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Cardul SIM este blocat cu codul PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Se deblochează cardul SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d din %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Adăugaţi un widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Gol"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Zona de deblocare a fost extinsă."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Zona de deblocare a fost restrânsă."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector utilizator"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stare"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cameră foto"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Comenzi media"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"A început reordonarea widgeturilor."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordonarea widgeturilor s-a încheiat."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgetul <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a fost eliminat."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Extindeţi zona de deblocare."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Deblocare prin glisare."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Deblocare cu model."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Deblocare facială."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Deblocare cu PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Deblocare cu parolă."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Zonă model."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Zonă glisare."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butonul Melodia anterioară"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butonul Melodia următoare"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butonul Întrerupeți"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Butonul Redați"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Butonul Opriți"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anulaţi"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminat"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Schimbarea modului"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Deblocaţi"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Cameră foto"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Silenţios"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Sunet activat"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Glisaţi în jos pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Glisaţi spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Glisaţi spre dreapta pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Apel de urgenţă"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greşită"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercaţi din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceţi codul PUK pentru a continua. Contactaţi operatorul pentru mai multe detalii."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceţi codul PIN dorit"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmaţi codul PIN dorit"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Codul PUK trebuie să aibă minimum 8 cifre."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Conectaţi-vă"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Se verifică contul…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Butonul Melodia anterioară"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Butonul Melodia următoare"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Butonul Întrerupeți"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Butonul Redați"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Butonul Opriți"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Fără serviciu."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ru/activitystrings.xml b/packages/Keyguard/res/values-ru/activitystrings.xml
new file mode 100644
index 0000000..002cd56
--- /dev/null
+++ b/packages/Keyguard/res/values-ru/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Защита отключена"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN-код"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Пароль"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Графический ключ"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN-код SIM-карты"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-код SIM-карты"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Выбор виджета..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
new file mode 100644
index 0000000..136982a
--- /dev/null
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Введите PIN-код"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Введите PUK-код и новый PIN-код"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-код"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новый PIN-код"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Нажмите для ввода пароля"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Введите пароль"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Введите PIN-код"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неверный PIN-код."</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_low_battery" msgid="8143808018719173859">"Подключите зарядное устройство."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Для разблокировки нажмите \"Меню\"."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сеть заблокирована"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Нет SIM-карты"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Нет SIM-карты."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Нет SIM-карты."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Вставьте SIM-карту."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-карта отсутствует или недоступна. Вставьте SIM-карту."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM-карта непригодна."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-карта окончательно заблокирована.\nЧтобы получить новую, обратитесь к своему оператору."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карта заблокирована."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Для разблокировки SIM-карты требуется PUK-код."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Разблокировка SIM-карты…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виджет %2$d из %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Добавить виджет"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Пусто"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Область разблокировки развернута"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Область разблокировки свернута"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Виджет \"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>\""</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Выбор аккаунта"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Управление блокировкой"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Начато переопределение порядка виджетов"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Порядок виджетов определен"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Виджет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> удален"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Развернуть области разблокировки"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Прокрутка"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Графический ключ"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фейсконтроль"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-код"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Пароль"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Область ввода графического ключа"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Область слайдера"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Кнопка перехода к предыдущему треку"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Кнопка перехода к следующему треку"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Кнопка паузы"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Кнопка воспроизведения"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Кнопка выключения"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Клавиша ALT"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отмена"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Клавиша удаления"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Клавиша смены режима"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Клавиша смены регистра"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Клавиша ввода"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Разблокировать"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Без звука"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Включить звук"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Проведите вниз, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Проведите влево, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Проведите вправо, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстренный вызов"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забыли графический ключ?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильный графический ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Неправильный пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Неправильный PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Введите графический ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введите PIN-код SIM-карты"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Введите PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Введите пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-карта заблокирована. Чтобы продолжить, введите PUK-код. За подробной информацией обратитесь к своему оператору связи."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Введите желаемый PIN-код"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Введите PIN-код ещё раз"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблокировка SIM-карты…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неверный PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введите PIN-код (от 4 до 8 цифр)."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код должен содержать не менее 8 символов."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не совпадают"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Слишком много попыток ввода графического ключа"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Чтобы разблокировать устройство, войдите в свой аккаунт Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Имя пользователя (эл. почта)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Войти"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неверное имя пользователя или пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыли имя пользователя или пароль?\nПерейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Проверка данных…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. \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_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> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <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="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Удалить"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Кнопка перехода к предыдущему треку"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Кнопка перехода к следующему треку"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Кнопка паузы"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Кнопка воспроизведения"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Кнопка выключения"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нет сигнала."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sk/activitystrings.xml b/packages/Keyguard/res/values-sk/activitystrings.xml
new file mode 100644
index 0000000..33f2228
--- /dev/null
+++ b/packages/Keyguard/res/values-sk/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Bez zabezpečenia"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"Kód PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Heslo"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Vzor"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN karty SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK karty SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Vyberte miniaplikáciu..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
new file mode 100644
index 0000000..4b2e1e3
--- /dev/null
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadajte kód PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Zadajte kód PUK a nový kód PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kód PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nový kód PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dotknutím zadajte heslo"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Zadajte heslo na odomknutie"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Zadajte kód PIN na odomknutie"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Nesprávny kód PIN."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM."</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"V tablete nie je žiadna karta SIM."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"V telefóne nie je žiadna karta SIM."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vložte kartu SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Karta SIM chýba alebo sa z nej nedá čítať. Vložte kartu SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Karta SIM je nepoužiteľná."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Vaša karta SIM bola natrvalo zakázaná.\nAk chcete získať inú kartu SIM, kontaktujte svojho poskytovateľa bezdrôtových služieb."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Karta SIM je uzamknutá."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Karta SIM je uzamknutá pomocou kódu PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Prebieha odomykanie karty SIM..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Miniaplikácia %2$d z %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Pridať miniaplikáciu."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prázdne"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oblasť na odomknutie bola rozšírená."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oblasť na odomknutie bola zúžená."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Miniaplikácia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Výber používateľa"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stav"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparát"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Ovládacie prvky médií"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Zmena usporiadania miniaplikácií sa začala."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Zmena usporiadania miniaplikácií sa skončila."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Miniaplikácia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> bola odstránená."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Rozšíriť oblasť na odomknutie."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odomknutie prejdením prstom."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odomknutie vzorom."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Odomknutie tvárou."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odomknutie kódom PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odomknutie heslom."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Oblasť na zadanie bezpečnostného vzoru."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblasť na prejdenie prstom."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tlačidlo Predchádzajúca stopa"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tlačidlo Ďalšia stopa"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tlačidlo Pozastaviť"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Tlačidlo Prehrať"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Tlačidlo Zastaviť"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušiť"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Odstrániť"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Hotovo"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Zmena režimu"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Odomknúť"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparát"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Tichý"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Zapnúť zvuk"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Prejdite prstom nadol: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Prejdite prstom doľava: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Prejdite prstom doprava: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nepamätám si vzor"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávny vzor"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nesprávne heslo"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nesprávny kód PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Skúste to znova o <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nakreslite svoj vzor"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadajte kód PIN karty SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Zadajte kód PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Zadajte heslo"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Karta SIM je teraz zakázaná. Ak chcete pokračovať, zadajte kód PUK. Podrobné informácie získate od operátora."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Zadajte požadovaný kód PIN"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrďte požadovaný kód PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Prebieha odomykanie karty SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávny kód PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadajte kód PIN s dĺžkou 4 až 8 číslic."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kód PUK musí obsahovať 8 alebo viac číslic."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Znova zadajte správny kód PUK. Opakované pokusy zakážu kartu SIM natrvalo."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN sa nezhodujú"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Ak chcete telefón odomknúť, prihláste sa pomocou svojho účtu Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Používateľské meno (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prihlásiť sa"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné používateľské meno alebo heslo."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zabudli ste svoje používateľské meno alebo heslo?\n Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Prebieha kontrola účtu..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <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>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v tablete obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v telefóne obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V tablete sa teraz obnovia predvolené továrenské nastavenia."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V telefóne sa teraz obnovia predvolené továrenské nastavenia."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrániť"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Tlačidlo Predchádzajúca stopa"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Tlačidlo Ďalšia stopa"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tlačidlo Pozastaviť"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Tlačidlo Prehrať"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Tlačidlo Zastaviť"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žiadny signál"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sl/activitystrings.xml b/packages/Keyguard/res/values-sl/activitystrings.xml
new file mode 100644
index 0000000..2c60219
--- /dev/null
+++ b/packages/Keyguard/res/values-sl/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Brez varnosti"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Geslo"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Vzorec"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN za kartico SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK za kartico SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Izberite pripomoček ..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
new file mode 100644
index 0000000..b6cfc1c
--- /dev/null
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Vnesite kodo PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Vnesite kodo PUK in novo kodo PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Koda PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nova koda PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dotaknite se za vnos gesla"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Vnesite geslo za odklepanje"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Vnesite PIN za odklepanje"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Napačna koda PIN."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Ni kartice SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"V tabličnem računalniku ni kartice SIM."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"V telefonu ni kartice SIM."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vstavite kartico SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Kartice SIM ni ali je ni mogoče prebrati. Vstavite jo."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Neuporabna kartica SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Kartica SIM je trajno onemogočena.\n Obrnite se na operaterja za drugo."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kartica SIM je zaklenjena."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kartica SIM je zaklenjena s kodo PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Odklepanje kartice SIM …"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Pripomoček %2$d za %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodajanje pripomočka."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prazno"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Območje odklepanja razširjeno."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Območje odklepanja strnjeno."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Pripomoček <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Izbirnik uporabnika"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stanje"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparat"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrolniki predstavnosti"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Prerazporejanje pripomočkov začeto."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Prerazporejanje pripomočkov končano."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Pripomoček <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> izbrisan."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Razširitev območja odklepanja."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odklepanje s podrsanjem."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odklepanje z vzorcem."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Odklepanje z obrazom."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odklepanje s kodo PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odklepanje z geslom."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Območje vzorca."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Območje podrsanja."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Gumb za prejšnjo skladbo"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Gumb za naslednjo skladbo"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Gumb za začasno ustavitev"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Gumb za predvajanje"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Gumb za ustavitev"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Tipka Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Prekliči"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tipka Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Končano"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Sprememba načina"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tipka Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Tipka Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Odkleni"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparat"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Tiho"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Vklopljen zvok"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Povlecite navzdol za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Povlecite v levo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Povlecite v desno za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Klic v sili"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pozabljen vzorec"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Napačen vzorec"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Napačno geslo"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Napačen PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Čez <xliff:g id="NUMBER">%d</xliff:g> sekund poskusite znova."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Narišite vzorec"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Vnesite PIN za kartico SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Vnesite PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Vnesite geslo"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Kartica SIM je onemogočena. Če želite nadaljevati, vnesite kodo PUK. Za dodatne informacije se obrnite na operaterja."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Vnesite želeno kodo PIN"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potrdite želeno kodo PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odklepanje kartice SIM ..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Napačna koda PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Vnesite PIN, ki vsebuje od štiri do osem številk."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Koda PUK mora vsebovati 8 ali več števk."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kodi PIN se ne ujemata"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Preveč poskusov vzorca"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Če želite odkleniti napravo, se prijavite z Google Računom."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Uporabniško ime (e-pošta)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Geslo"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neveljavno uporabniško ime ali geslo."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ali ste pozabili uporabniško ime ali geslo?\nObiščite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Preverjanje računa ..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablični računalnik ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve in vsi uporabniški podatki bodo izgubljeni."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefon ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve in vsi uporabniški podatki bodo izgubljeni."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablični računalnik ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat napačno odkleniti, zato bo ponastavljen na privzete tovarniške nastavitve."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat napačno odkleniti, zato bo ponastavljen na privzete tovarniške nastavitve."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Gumb za prejšnjo skladbo"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Gumb za naslednjo skladbo"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Gumb za začasno ustavitev"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Gumb za predvajanje"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Gumb za ustavitev"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ni storitve."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sr/activitystrings.xml b/packages/Keyguard/res/values-sr/activitystrings.xml
new file mode 100644
index 0000000..34802df
--- /dev/null
+++ b/packages/Keyguard/res/values-sr/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Без заштите"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Лозинка"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Шаблон"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN SIM картице"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK SIM картице"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Изабери виџет..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
new file mode 100644
index 0000000..664b85e
--- /dev/null
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Унесите PIN кôд"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Унесите PUK и нови PIN кôд"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK кôд"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Нови PIN кôд"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Додирните да бисте унели лозинку"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Откуцајте лозинку да бисте откључали"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Унесите PIN за откључавање"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN кôд је нетачан."</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_low_battery" msgid="8143808018719173859">"Повежите пуњач."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Притисните Мени да бисте откључали."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Мрежа је закључана"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Нема SIM картице"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"У таблету нема SIM картице."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"У телефону нема SIM картице."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Уметните SIM картицу."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM картица недостаје или не може да се прочита. Уметните SIM картицу."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM картица је неупотребљива."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM картица је трајно онемогућена.\n Обратите се добављачу услуге бежичне мреже да бисте добили другу SIM картицу."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM картица је закључана."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картица је закључана PUK кодом."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Откључавање SIM картице…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виџет %2$d од %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Додај виџет."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Празно"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Област откључавања је проширена."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Област откључавања је скупљена."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Избор корисника"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроле за медије"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Започела је промена редоследа виџета."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Промена редоследа виџета је завршена."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> је избрисан."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Прошири област откључавања."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Откључавање превлачењем."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Откључавање шаблоном."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Откључавање лицем."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Откључавање PIN-ом."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Откључавање лозинком."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Област шаблона."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Област превлачења."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Дугме за претходну песму"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Дугме за следећу песму"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Дугме за паузу"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Дугме за репродукцију"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Дугме за заустављање"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Откажи"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Избриши"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Промена режима"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Откључај"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Нечујно"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Укључи звук"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Превуците надоле за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Превуците улево за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Превуците удесно за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Хитни позив"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборављени шаблон"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Унесите PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Унесите лозинку"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM картица је сада онемогућена. Унесите PUK кôд да бисте наставили. За детаље контактирајте оператера."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Унесите жељени PIN кôд"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Потврдите жељени PIN кôд"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Откључавање SIM картице…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN кôд је нетачан."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Унесите PIN који има од 4 до 8 бројева."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK кôд треба да има 8 или више бројева."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Поново унесите исправни PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Провера налога…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Дугме за претходну песму"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Дугме за следећу песму"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Дугме за паузу"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Дугме за репродукцију"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Дугме за заустављање"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ван мреже сте."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sv/activitystrings.xml b/packages/Keyguard/res/values-sv/activitystrings.xml
new file mode 100644
index 0000000..e664383
--- /dev/null
+++ b/packages/Keyguard/res/values-sv/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Ingen säkerhet"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN-kod"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Lösenord"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Grafiskt lösenord"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN-kod för SIM-kort"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-kod för SIM-kort"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Välj widget ..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
new file mode 100644
index 0000000..fb0f912
--- /dev/null
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ange PIN-kod"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Ange PUK-koden och en ny PIN-kod"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kod"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Ny PIN-kod"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Tryck om du vill ange lösenord"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ange lösenord för att låsa upp"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ange PIN-kod för att låsa upp"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Fel PIN-kod."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Inget SIM-kort"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Inget SIM-kort i surfplattan."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Inget SIM-kort i mobilen."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Sätt i ett SIM-kort."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-kort saknas eller kan inte läsas. Sätt i ett SIM-kort."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Oanvändbart SIM-kort."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-kortet har inaktiverats permanent.\n Beställ ett nytt SIM-kort från din operatör."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortet är låst."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortet är PUK-låst."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Låser upp SIM-kort …"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d av %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Lägg till en widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tom"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Expanderad upplåsningsyta."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Komprimerad upplåsningsyta."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget för <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Användarväljare"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediereglage"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Ändring av widgetarnas ordning har påbörjats."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ändring av widgetarnas ordning har avslutats."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgeten <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> har tagits bort."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandera upplåsningsytan."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lås upp genom att dra."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Lås upp med grafiskt lösenord."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Lås upp med Ansiktslås."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Lås upp med PIN-kod."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Lås upp med lösenord."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Fält för grafiskt lösenord."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Fält med dragreglage."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knapp för föregående spår"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knapp för nästa spår"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pausknappen"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Uppspelningsknappen"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stoppknappen"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Klar"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Funktionsändring"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Skift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Retur"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Lås upp"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Tyst"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Ljud på"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Dra nedåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Dra åt höger för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Nödsamtal"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glömt ditt grafiska lösenord?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Fel grafiskt lösenord"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Fel lösenord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Fel PIN-kod"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Rita ditt grafiska lösenord"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ange PIN-kod för SIM-kortet"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ange PIN-kod"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ange lösenord"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet är nu inaktiverat. Ange PUK-koden om du vill fortsätta. Kontakta operatören om du vill få mer information."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ange önskad PIN-kod"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bekräfta önskad PIN-kod"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser upp SIM-kort …"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Fel PIN-kod."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ange en PIN-kod med 4 till 8 siffror."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden ska vara minst åtta siffror."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koderna stämmer inte överens"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"För många försök med grafiskt lösenord"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Logga in med ditt Google-konto om du vill låsa upp."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Användarnamn (e-post)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Lösenord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logga in"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ogiltigt användarnamn eller lösenord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glömt ditt användarnamn eller lösenord?\nBesök "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontot kontrolleras …"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök återställs surfplattan till fabriksinställningarna. Du förlorar då alla användardata."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök återställs mobilen till fabriksinställningarna. Du förlorar då alla användardata."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har försökt låsa upp surfplattan på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs nu till fabriksinställningarna."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs nu till fabriksinställningarna."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ta bort"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Knapp för föregående spår"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Knapp för nästa spår"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pausknappen"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Uppspelningsknappen"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stoppknappen"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjänst."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sw/activitystrings.xml b/packages/Keyguard/res/values-sw/activitystrings.xml
new file mode 100644
index 0000000..357b911
--- /dev/null
+++ b/packages/Keyguard/res/values-sw/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Hakuna usalama"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Nenosiri"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Ruwaza"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN ya SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK ya SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Chagua wijeti..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
new file mode 100644
index 0000000..27f1f30
--- /dev/null
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingiza msimbo wa PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Ingiza PUK na msimbo mpya wa PIN"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Msimbo wa PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Msimbo mpya wa PIN"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Gusa kuingiza nenosiri "</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Charaza nenosiri ili kufungua"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ingiza PIN ili kufungua"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Msimbo wa PIN usio sahihi."</string>
+    <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">"Imechajiwa"</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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Hakuna SIM kadi"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Hakuna SIM kadi katika kompyuta ndogo."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Hakuna SIM kadi kwenye simu."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Ingiza SIM kadi."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kadi haiko au haisomeki. Ingiza SIM kadi."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM kadi isiyotumika."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM kadi yako imefungwa kabisa.\n Wasiliana na mtoa huduma wako wa pasi waya ili upate SIM kadi nyingine."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kadi imefungwa."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kadi imefungwa na PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Inafungua SIM kadi..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Wiji %2$d ya %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ongeza wiji"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tupu"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Eneo la kufungua limepanuliwa."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Eneo la kufungua limekunjwa."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ya wiji."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kiteuzi cha mtumiaji"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Hali"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Vidhibiti vya media"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Upangaji upya wa wiji umeanza."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Upangaji upya wa wiji umekamilika."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Wiji <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> imefutwa."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Panua eneo la kufungua."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Kufungua slaidi."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Kufungua kwa ruwaza."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Kufungua kwa uso."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Kufungua kwa PIN."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Kufungua kwa nenosiri."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Eneo la ruwaza."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Eneo la slaidi."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Kitufe cha wimbo uliotangulia"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Kitufe cha wimbo unaofuata"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Kitufe cha kusitisha"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Kitufe cha kucheza"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Kitufe cha kusitisha"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Nimemaliza"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Fungua"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Kimya"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Sauti imewashwa"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Sogeza chini kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Sogeza kushoto kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Sogeza kulika kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Mchoro Usio sahihi"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nenosiri Lisilo sahihi"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN isiyo sahihi"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Jaribu tena baada ya sekunde <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Chora ruwaza yako"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingiza PIN ya SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ingiza PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ingiza Nenosiri"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM sasa imelemazwa. Ingiza msimbo wa PUK ili kuendelea. Wasiliana na mtoa huduma kwa maelezo."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ingiza msimbo wa PIN unaopendelewa"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Thibitisha msimbo wa PIN unaopendelewa"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Inafungua SIM kadi..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Msimbo wa PIN usio sahihi."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Charaza PIN iliyo na tarakimu kati ya 4 na 8."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Msimbo wa PUK unafaa kuwa na nambari 8 au zaidi."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Ili kufungua, ingia kwa Akaunti yako ya Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Jina la mtumiaji (barua pepe)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Nenosiri"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Ingia"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Jina la mtumiaji au nenosiri batili."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Je, umesahau jina lako la mtumiaji au nenosiri?\nTembela "<b>"Bgoogle.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Inakagua akaunti…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofaulu, kompyuta ndogo itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani data yote ya mtumiaji itapotea."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofaulu, simu itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani na data yote ya mtumiaji itapotea."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa kompyuta ndogo itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa simu  itarejeshwa katika mfumo chaguo-msingi ilivyotoka kiwandani."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ondoa"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Kitufe cha wimbo wa awali"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Kitufe cha wimbo unaofuata"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Kitufe cha kusitisha"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Kitufe cha kucheza"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Kitufe cha kusimamisha"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hakuna huduma."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sw320dp/dimens.xml b/packages/Keyguard/res/values-sw320dp/dimens.xml
new file mode 100644
index 0000000..2c209e2
--- /dev/null
+++ b/packages/Keyguard/res/values-sw320dp/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">345dp</dimen>
+
+</resources>
diff --git a/packages/Keyguard/res/values-sw360dp/dimens.xml b/packages/Keyguard/res/values-sw360dp/dimens.xml
new file mode 100644
index 0000000..6e39a42
--- /dev/null
+++ b/packages/Keyguard/res/values-sw360dp/dimens.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x
+         keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">400dp</dimen>
+
+    <!-- The bottom margin for the GlowPadView container -->
+    <dimen name="glowpadcontainer_bottom_margin">-48dp</dimen>
+
+</resources>
diff --git a/packages/Keyguard/res/values-sw380dp-land/dimens.xml b/packages/Keyguard/res/values-sw380dp-land/dimens.xml
new file mode 100644
index 0000000..20eb1be
--- /dev/null
+++ b/packages/Keyguard/res/values-sw380dp-land/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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.
+*/
+-->
+<resources>
+    <!-- Top margin for the clock view --> 
+    <dimen name="kg_clock_top_margin">48dp</dimen>
+</resources>
diff --git a/packages/Keyguard/res/values-sw380dp/dimens.xml b/packages/Keyguard/res/values-sw380dp/dimens.xml
new file mode 100644
index 0000000..fc0e85d
--- /dev/null
+++ b/packages/Keyguard/res/values-sw380dp/dimens.xml
@@ -0,0 +1,23 @@
+<?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.
+*/
+-->
+
+<resources>
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">340dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp-land/arrays.xml b/packages/Keyguard/res/values-sw600dp-land/arrays.xml
new file mode 100644
index 0000000..5550216
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp-land/arrays.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Resources for GlowPadView in LockScreen -->
+    <array name="lockscreen_targets_when_silent">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_silent">
+        <item>@string/description_target_unlock</item>
+        <item>@null</item>
+        <item>@string/description_target_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_direction_descriptions">
+        <item>@string/description_direction_right</item>
+        <item>@null</item>
+        <item>@string/description_direction_left</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_when_soundon">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_silent</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_soundon">
+        <item>@string/description_target_unlock</item>
+        <item>@null</item>
+        <item>@string/description_target_silent</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_with_camera">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_camera</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_with_camera">
+        <item>@string/description_target_unlock</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_camera</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
new file mode 100644
index 0000000..5507e5f
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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>
+    <!-- Top margin for the clock view --> 
+    <dimen name="kg_clock_top_margin">85dp</dimen>
+
+    <!-- Size of margin on the right of keyguard's status view -->
+    <dimen name="kg_status_line_font_right_margin">16dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp-land/integers.xml b/packages/Keyguard/res/values-sw600dp-land/integers.xml
new file mode 100644
index 0000000..b724c90
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp-land/integers.xml
@@ -0,0 +1,23 @@
+<?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.
+*/
+-->
+<resources>
+    <integer name="kg_widget_region_weight">50</integer>
+    <integer name="kg_security_flipper_weight">50</integer>
+    <integer name="kg_glowpad_rotation_offset">0</integer>
+</resources>
diff --git a/packages/Keyguard/res/values-sw600dp-port/integers.xml b/packages/Keyguard/res/values-sw600dp-port/integers.xml
new file mode 100644
index 0000000..65b854a
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp-port/integers.xml
@@ -0,0 +1,22 @@
+<?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.
+*/
+-->
+<resources>
+    <integer name="kg_widget_region_weight">46</integer>
+    <integer name="kg_security_flipper_weight">54</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/alias.xml b/packages/Keyguard/res/values-sw600dp/alias.xml
new file mode 100644
index 0000000..c3ecbb9
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp/alias.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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.
+*/
+-->
+<resources>
+    <!-- Alias used to reference one of two possible layouts in keyguard.  -->
+    <item type="layout" name="keyguard_eca">@layout/keyguard_emergency_carrier_area</item>
+</resources>
diff --git a/packages/Keyguard/res/values-sw600dp/bools.xml b/packages/Keyguard/res/values-sw600dp/bools.xml
new file mode 100644
index 0000000..ddc48c5
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp/bools.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resources>
+    <bool name="target_honeycomb_needs_options_menu">false</bool>
+    <bool name="show_ongoing_ime_switcher">true</bool>
+    <bool name="kg_share_status_area">false</bool>
+    <bool name="kg_sim_puk_account_full_screen">false</bool>
+    <bool name="kg_show_ime_at_screen_on">false</bool>
+    <!-- No camera for you, tablet user -->
+    <bool name="kg_enable_camera_default_widget">false</bool>
+    <bool name="kg_center_small_widgets_vertically">true</bool>
+    <bool name="kg_top_align_page_shrink_on_bouncer_visible">false</bool>
+</resources>
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..c0e3937
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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>
+    <!-- Size of clock font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_clock_font_size">112sp</dimen>
+
+    <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
+    <dimen name="keyguard_lockscreen_outerring_diameter">364dp</dimen>
+
+    <!-- Height of FaceUnlock view in keyguard -->
+    <dimen name="face_unlock_height">430dip</dimen>
+
+    <!-- target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
+    <dimen name="glowpadview_target_placement_radius">182dip</dimen>
+
+    <!-- Size of status line font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
+
+    <!-- Keyguard dimensions -->
+    <!-- Size of the clock font in keyguard's status view -->
+    <dimen name="kg_status_clock_font_size">141dp</dimen>
+
+    <!-- Size of the date font in keyguard's status view  -->
+    <dimen name="kg_status_date_font_size">25.5dp</dimen>
+
+    <!-- Size of the generic status lines keyguard's status view  -->
+    <dimen name="kg_status_line_font_size">16sp</dimen>
+
+    <!-- Top margin for the clock view --> 
+    <dimen name="kg_clock_top_margin">0dp</dimen>
+
+    <!-- Size of margin on the right of keyguard's status view -->
+    <dimen name="kg_status_line_font_right_margin">50dp</dimen>
+
+    <!-- Horizontal padding for the widget pager -->
+    <dimen name="kg_widget_pager_horizontal_padding">24dp</dimen>
+
+    <!-- Top padding for the widget pager -->
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
+
+    <!-- Bottom padding for the widget pager -->
+    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+
+    <!-- Top margin for the runway lights. We add a negative margin in large
+        devices to account for the widget pager padding -->
+    <dimen name="kg_runway_lights_top_margin">-10dp</dimen>
+
+    <!-- Margin around the various security views -->
+    <dimen name="keyguard_security_view_margin">12dp</dimen>
+
+    <!-- Margin around the various security views -->
+    <dimen name="keyguard_muliuser_selector_margin">12dp</dimen>
+
+</resources>
diff --git a/packages/Keyguard/res/values-sw600dp/integers.xml b/packages/Keyguard/res/values-sw600dp/integers.xml
new file mode 100644
index 0000000..de9829c
--- /dev/null
+++ b/packages/Keyguard/res/values-sw600dp/integers.xml
@@ -0,0 +1,21 @@
+<?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.
+*/
+-->
+<resources>
+    <integer name="kg_carousel_angle">60</integer>
+</resources>
diff --git a/packages/Keyguard/res/values-sw720dp-land/dimens.xml b/packages/Keyguard/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..14726ab
--- /dev/null
+++ b/packages/Keyguard/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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.
+*/
+-->
+<resources>
+    <!-- Top margin for the clock view --> 
+    <dimen name="kg_clock_top_margin">174dp</dimen>
+
+    <!-- Size of margin on the right of keyguard's status view -->
+    <dimen name="kg_status_line_font_right_margin">16dp</dimen>
+
+    <!-- Horizontal padding for the widget pager -->
+    <dimen name="kg_widget_pager_horizontal_padding">32dp</dimen>
+</resources>
diff --git a/packages/Keyguard/res/values-sw720dp-port/integers.xml b/packages/Keyguard/res/values-sw720dp-port/integers.xml
new file mode 100644
index 0000000..5f85f71
--- /dev/null
+++ b/packages/Keyguard/res/values-sw720dp-port/integers.xml
@@ -0,0 +1,22 @@
+<?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.
+*/
+-->
+<resources>
+    <integer name="kg_widget_region_weight">48</integer>
+    <integer name="kg_security_flipper_weight">52</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..b29ac22
--- /dev/null
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -0,0 +1,66 @@
+<?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.
+*/
+-->
+<resources>
+    <!-- Keyguard dimensions -->
+    <!-- Size of the clock font in keyguard's status view -->
+    <dimen name="kg_status_clock_font_size">188dp</dimen>
+
+    <!-- Size of the date font in keyguard's status view  -->
+    <dimen name="kg_status_date_font_size">34dp</dimen>
+
+    <!-- Size of the generic status lines keyguard's status view  -->
+    <dimen name="kg_status_line_font_size">19sp</dimen>
+
+    <!-- Top margin for the clock view --> 
+    <dimen name="kg_clock_top_margin">0dp</dimen>
+
+    <!-- Size of margin on the right of keyguard's status view -->
+    <dimen name="kg_status_line_font_right_margin">32dp</dimen>
+
+    <!-- Horizontal padding for the widget pager -->
+    <dimen name="kg_widget_pager_horizontal_padding">80dp</dimen>
+
+    <!-- Top padding for the widget pager -->
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
+
+    <!-- Bottom padding for the widget pager -->
+    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+
+    <!-- Top margin for the runway lights. We add a negative margin in large
+        devices to account for the widget pager padding -->
+    <dimen name="kg_runway_lights_top_margin">-30dp</dimen>
+
+    <!-- Margin around the various security views -->
+    <dimen name="keyguard_muliuser_selector_margin">24dp</dimen>
+
+    <!-- Stroke width of the frame for the circular avatars. -->
+    <dimen name="keyguard_avatar_frame_stroke_width">3dp</dimen>
+
+    <!-- Size of the avator on the multiuser lockscreen. -->
+    <dimen name="keyguard_avatar_size">88dp</dimen>
+
+    <!-- Size of the text under the avator on the multiuser lockscreen. -->
+    <dimen name="keyguard_avatar_name_size">12sp</dimen>
+
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">420dp</dimen>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">420dp</dimen>
+</resources>
diff --git a/packages/Keyguard/res/values-th/activitystrings.xml b/packages/Keyguard/res/values-th/activitystrings.xml
new file mode 100644
index 0000000..64f50cc
--- /dev/null
+++ b/packages/Keyguard/res/values-th/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"ไม่มีการรักษาความปลอดภัย"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"รหัสผ่าน"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"รูปแบบ"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN ของซิม"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK ของซิม"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"เลือกวิดเจ็ต..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
new file mode 100644
index 0000000..d6308b6
--- /dev/null
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"พิมพ์รหัส PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"พิมพ์ PUK และรหัส PIN ใหม่"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"รหัส PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"รหัส PIN ใหม่"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"แตะเพื่อพิมพ์รหัสผ่าน"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"พิมพ์รหัสผ่านเพื่อปลดล็อก"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"พิมพ์ PIN เพื่อปลดล็อก"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"รหัส PIN ไม่ถูกต้อง"</string>
+    <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_low_battery" msgid="8143808018719173859">"เสียบที่ชาร์จของคุณ"</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"กด \"เมนู\" เพื่อปลดล็อก"</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"เครือข่ายล็อก"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"ไม่มีซิมการ์ด"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"ไม่มีซิมการ์ดในแท็บเล็ต"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"ไม่มีซิมการ์ดในโทรศัพท์"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"ใส่ซิมการ์ด"</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"ไม่มีหรือไม่สามารถอ่านซิมการ์ดได้ โปรดใส่ซิมการ์ด"</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"ซิมการ์ดใช้ไม่ได้"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"ซิมการ์ดของคุณถูกปิดใช้งานอย่างถาวร\nติดต่อผู้ให้บริการระบบไร้สายของคุณเพื่อรับซิมการ์ดใหม่"</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ซิมการ์ดถูกล็อก"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ซิมการ์ดถูกล็อกด้วย PUK"</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"กำลังปลดล็อกซิมการ์ด…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s วิดเจ็ต %2$d ของ %3$d"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"เพิ่มวิดเจ็ต"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ว่าง"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ขยายพื้นที่ปลดล็อกแล้ว"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ยุบพื้นที่ปลดล็อกแล้ว"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"วิดเจ็ต <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ตัวเลือกผู้ใช้"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"สถานะ"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"กล้องถ่ายรูป"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"การควบคุมสื่อ"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"เริ่มเรียงลำดับวิดเจ็ตใหม่"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"เรียงลำดับวิดเจ็ตใหม่เสร็จแล้ว"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ลบวิดเจ็ต <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> แล้ว"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ขยายพื้นที่ปลดล็อก"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"การปลดล็อกด้วยการเลื่อน"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"การปลดล็อกด้วยรูปแบบ"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"การปลดล็อกด้วยใบหน้า"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"การปลดล็อกด้วย PIN"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"การปลดล็อกด้วยรหัสผ่าน"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"พื้นที่สำหรับรูปแบบ"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"พื้นที่สำหรับการเลื่อน"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ปุ่มแทร็กก่อนหน้า"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ปุ่มแทร็กถัดไป"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ปุ่มหยุดชั่วคราว"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ปุ่มเล่น"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ปุ่มหยุด"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ยกเลิก"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ลบ"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"เสร็จสิ้น"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"เปลี่ยนโหมด"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ป้อน"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"ปลดล็อก"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"กล้อง"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"ปิดเสียง"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"เปิดเสียง"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"เลื่อนลงเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"เลื่อนไปทางซ้ายเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"เลื่อนไปทางขวาเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+    <string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"หมายเลขฉุกเฉิน"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ลืมรูปแบบใช่หรือไม่"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"รูปแบบไม่ถูกต้อง"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"รหัสผ่านไม่ถูกต้อง"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN ไม่ถูกต้อง"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ลองอีกครั้งในอีก <xliff:g id="NUMBER">%d</xliff:g> วินาที"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"วาดรูปแบบของคุณ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ป้อน PIN ของซิม"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"ป้อน PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"ป้อนรหัสผ่าน"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ซิมการ์ดถูกปิดใช้งานแล้วในตอนนี้ ป้อนรหัส PUK เพื่อดำเนินการต่อ โปรดติดต่อผู้ให้บริการสำหรับรายละเอียด"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"ป้อนรหัส PIN ที่ต้องการ"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"ยืนยันรหัส PIN ที่ต้องการ"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"กำลังปลดล็อกซิมการ์ด…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"รหัส PIN ไม่ถูกต้อง"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"พิมพ์ PIN ซึ่งเป็นเลข 4 ถึง 8 หลัก"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"รหัส PUK ต้องเป็นตัวเลขอย่างน้อย 8 หลัก"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"หากต้องการปลดล็อก ให้ลงชื่อเข้าใช้ด้วยบัญชี Google ของคุณ"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"ชื่อผู้ใช้ (อีเมล)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"รหัสผ่าน"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ลงชื่อเข้าใช้"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน\nโปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"กำลังตรวจสอบบัญชี…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"นำออก"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ปุ่มแทร็กก่อนหน้า"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ปุ่มแทร็กถัดไป"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ปุ่มหยุดชั่วคราว"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ปุ่มเล่น"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ปุ่มหยุด"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"ไม่มีบริการ"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-tl/activitystrings.xml b/packages/Keyguard/res/values-tl/activitystrings.xml
new file mode 100644
index 0000000..71f3564
--- /dev/null
+++ b/packages/Keyguard/res/values-tl/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Walang seguridad"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Password"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Pattern"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Pumili ng widget..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenNaka-off"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenNaka-on"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
new file mode 100644
index 0000000..a41d268
--- /dev/null
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"I-type ang PIN code"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"I-type ang PUK at bagong PIN code"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK code"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Bagong PIN code"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Pindutin upang i-type password"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"I-type ang password upang i-unlock"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"I-type ang PIN upang i-unlock"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Maling PIN code."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Walang SIM card"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Walang SIM card sa tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Walang SIM card sa telepono."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Maglagay ng SIM card."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Wala o hindi nababasa ang SIM card. Maglagay ng SIM card."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Hindi nagagamit na SIM card."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ang iyong SIM card ay permanenteng hindi pinagana.\n Makipag-ugnay sa iyong wireless service provider para sa isa pang SIM card."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Naka-lock ang SIM card."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Naka-lock ang SIM card gamit ang PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ina-unlock ang SIM card…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d ng %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Magdagdag ng widget."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Walang laman"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Pinalaki ang bahagi ng pag-unlock."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Pinaliit ang bahagi ng pag-unlock."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Tagapili ng user"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Katayuan"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mga kontrol ng media"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Nagsimula na ang pagbabago ng ayos ng widget."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Natapos na ang pagbabago ng ayos ng widget."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Tinanggal ang widget na <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Palakihin ang bahagi ng pag-unlock."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Pag-unlock ng slide."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pag-unlock ng pattern."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pag-unlock ng pin."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Pag-unlock ng password."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Bahagi ng pattern."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Bahagi ng slide."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Button na Nakaraang track"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Button na Susunod na track"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Button na I-pause"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Button na I-play"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Button na Ihinto"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselahin"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tanggalin"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Tapos na"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Pagbabago ng Mode"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"I-unlock"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Tahimik"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"I-on ang tunog"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Mag-slide pababa para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Mag-slide pakaliwa para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Mag-slide pakanan para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency na tawag"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nakalimutan ang Pattern"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Maling Pattern"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Maling Password"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Maling PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Subukang muli sa loob ng <xliff:g id="NUMBER">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Iguhit ang iyong pattern"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ilagay ang SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ilagay ang PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ilagay ang Password"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Hindi na pinagana ang SIM ngayon. Maglagay ng PUK code upang magpatuloy. Makipag-ugnay sa carrier para sa mga detalye."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ilagay ang ninanais na PIN code"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Kumpirmahin ang ninanais na PIN code"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ina-unlock ang SIM card…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Hindi tamang PIN code."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Mag-type ng PIN na 4 hanggang 8 numero."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Dapat ay 8 numero o higit pa ang PUK code."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Muling ilagay ang tamang PUK code. Permanenteng hindi pagaganahin ang SIM ng mga paulit-ulit na pagtatangka."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Hindi tumutugma ang mga PIN code"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Masyadong maraming pagtatangka sa pattern"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Upang i-unlock, mag-sign in gamit ang iyong Google account."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Mag-sign in"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Di-wastong username o password."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nakalimutan ang iyong username o password?\nBisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Tinitingnan ang account…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tinangka mo sa hindi tamang paraan na i-unlock ang tabelt nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, ire-reset ang tablet sa factory default at mawawala ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Tinangka mo sa hindi tamang paraan na i-unlock ang telepono nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, ire-reset ang telepono sa factory default at mawawala ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tinangka mo sa hindi tamang paraan na i-unlock ang tablet nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Ire-reset na ngayon ang tablet sa factory default."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Tinangka mo sa hindi tamang paraan na i-unlock ang telepono nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Ire-reset na ngayon ang telepono sa factory default."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Button na Nakaraang track"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Button na Susunod na track"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Button na I-pause"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Button na I-play"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Button na Ihinto"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Walang serbisyo."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-tr/activitystrings.xml b/packages/Keyguard/res/values-tr/activitystrings.xml
new file mode 100644
index 0000000..7f5a958
--- /dev/null
+++ b/packages/Keyguard/res/values-tr/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Güvenlik yok"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Şifre"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Desen"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN\'i"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK\'u"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Widget seç..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
new file mode 100644
index 0000000..0af7740
--- /dev/null
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN kodunu yazın"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK ve yeni PIN kodunu yazın"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kodu"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Yeni PIN kodu"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Şifre yazmak için dokunun"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Kilidi açmak için şifreyi yazın"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Kilidi açmak için PIN kodunu yazın"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Yanlış PIN kodu."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM kart yok"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tablette SIM kart yok."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefonda SIM kart yok."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIM kart takın."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kart yok veya okunamıyor. Bir SIM kart takın."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kullanılamayan SIM kart"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM kartınız kalıcı olarak devre dışı bırakıldı.\n Başka bir SIM kart için kablosuz servis sağlayıcınıza başvurun."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kart kilitli."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kart PUK kilidi devrede."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM kart kilidi açılıyor…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d / %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Widget ekleyin."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Boş"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Kilit açma alanı genişletildi."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Kilit açma alanı daraltıldı."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget\'ı."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kullanıcı seçici"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Durum"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Medya denetimleri"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget\'ları yeniden sıralama işlemi başladı."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget\'ları yeniden sıralama işlemi bitti."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget\'ı silindi."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Kilit açma alanını genişletin."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Kaydırarak kilit açma."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desenle kilit açma."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Yüzle kilit açma."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin koduyla kilit açma."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Şifreyle kilit açma."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Desen alanı."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Kaydırma alanı."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Önceki parça düğmesi"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Sonraki parça düğmesi"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Duraklat düğmesi"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Oynat düğmesi"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Durdur düğmesi"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"İptal"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Sil"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Bitti"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mod değiştirme"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ÜstKrkt"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Giriş"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Kilidi aç"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Sessiz"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Ses açık"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için aşağı kaydırın."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için sola kaydırın."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için sağa kaydırın."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Acil durum çağrısı"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Deseni Unuttunuz mu?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Yanlış Desen"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Yanlış Şifre"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Yanlış PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Deseninizi çizin"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN kodunu girin"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN\'i girin"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Şifreyi Girin"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM kart artık devre dışı bırakıldı. Devam etmek için PUK kodunu girin. Ayrıntılı bilgi için operatörle bağlantı kurun."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"İstenen PIN kodunu girin"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"İstenen PIN kodunu onaylayın"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kart kilidi açılıyor…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Yanlış PIN kodu."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 rakamdan oluşan bir PIN girin."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodu 8 veya daha çok basamaklı bir sayı olmalıdır."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Doğru PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodları eşleşmiyor"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Kilidi açmak için Google hesabınızla oturum açın."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Kullanıcı adı (e-posta)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Şifre"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Oturum aç"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Geçersiz kullanıcı adı veya şifre."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?\n"<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Hesap denetleniyor…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, tablet fabrika varsayılan değerine sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, telefon fabrika varsayılan değerine sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Tablet şimdi fabrika varsayılanına sıfırlanacak."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Telefon şimdi fabrika varsayılanına sıfırlanacak."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kaldır"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Önceki parça düğmesi"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Sonraki parça düğmesi"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Duraklat düğmesi"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Oynat düğmesi"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Durdur düğmesi"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hizmet yok."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-uk/activitystrings.xml b/packages/Keyguard/res/values-uk/activitystrings.xml
new file mode 100644
index 0000000..d4d0a4d
--- /dev/null
+++ b/packages/Keyguard/res/values-uk/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Без захисту"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN-код"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Пароль"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Ключ"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"PIN-код SIM-карти"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"PUK-код SIM-карти"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Вибрати віджет…"</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
new file mode 100644
index 0000000..2879e87
--- /dev/null
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Введіть PIN-код"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Введіть PUK-код і новий PIN-код"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-код"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новий PIN-код"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Торкніться, щоб ввести пароль"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Введіть пароль, щоб розблокувати"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Введіть PIN-код, щоб розблокувати"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неправильний PIN-код."</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_low_battery" msgid="8143808018719173859">"Підключіть зарядний пристрій."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Натисніть Меню, щоб розблокувати."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Мережу заблоковано"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Відсутня SIM-карта"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"У планшетному ПК немає SIM-карти."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"У телефоні немає SIM-карти."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Вставте SIM-карту."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-карта відсутня або не доступна для читання. Вставте SIM-карту."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Непридатна SIM-карта."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Вашу SIM-карту вимкнено назавжди.\n Зверніться до свого постачальника послуг бездротового зв’язку, щоб отримати іншу SIM-карту."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карту заблоковано."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-карту заблоковано PUK-кодом."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Розблокування SIM-карти…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Віджет %2$d з %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Додати віджет."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Порожня область"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Область розблокування розгорнуто."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Область розблокування згорнуто."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Віджет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Вибір користувача"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Елементи керування носієм"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Змінення порядку віджетів розпочато."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Змінення порядку віджетів закінчено."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Віджет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> видалено."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Розгорнути область розблокування."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Розблокування повзунком."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Розблокування ключем."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фейсконтроль"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Розблокування PIN-кодом."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Розблокування паролем."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Область ключа."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Область повзунка."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Кнопка \"Попередня композиція\""</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Кнопка \"Наступна композиція\""</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Кнопка \"Призупинити\""</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Кнопка \"Відтворити\""</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Кнопка \"Зупинити\""</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Скасувати"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Зміна режиму"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Розблокувати"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Без звуку"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Увімкнути звук"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Проведіть пальцем униз, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Проведіть пальцем ліворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Проведіть пальцем праворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Екстрений виклик"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Не пам’ятаю ключ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильний ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Неправильний пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Неправильний PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторіть спробу через <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйте ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введіть PIN-код SIM-карти"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Введіть PIN-код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Введіть пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Зараз SIM-карту вимкнено. Введіть PUK-код, щоб продовжити. Зв’яжіться з оператором, щоб дізнатися більше."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Введіть потрібний PIN-код"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Підтвердьте потрібний PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Розблокування SIM-карти…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправильний PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введіть PIN-код із 4–8 цифр."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код має складатися зі щонайменше 8 цифр."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно введіть правильний PUK-код. Численні спроби назавжди вимкнуть SIM-карту."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коди не збігаються"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Забагато спроб намалювати ключ"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Щоб розблокувати, увійдіть, використовуючи дані облікового запису Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Ім’я користувача (електронна адреса)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Увійти"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Недійсне ім’я користувача чи пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Не пам’ятаєте ім’я користувача чи пароль?\nВідвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Перевірка облікового запису…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Вилучити"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Кнопка \"Попередня композиція\""</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Кнопка \"Наступна композиція\""</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Кнопка \"Призупинити\""</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Кнопка \"Відтворити\""</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Кнопка \"Зупинити\""</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Зв’язку немає."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-vi/activitystrings.xml b/packages/Keyguard/res/values-vi/activitystrings.xml
new file mode 100644
index 0000000..009c3bd
--- /dev/null
+++ b/packages/Keyguard/res/values-vi/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Không có bảo mật"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"Mã PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Mật khẩu"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Hình"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"Mã PIN của SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"Mã PUK của SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Chọn tiện ích..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
new file mode 100644
index 0000000..70d3c73
--- /dev/null
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Nhập mã PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Nhập PUK và mã PIN mới"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Mã PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Mã PIN mới"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Chạm để nhập mật khẩu"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Nhập mật khẩu để mở khóa"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Nhập mã PIN để mở khóa"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Mã PIN không chính xác."</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Không có thẻ SIM nào"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Không có thẻ SIM nào trong máy tính bảng."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Không có thẻ SIM nào trong điện thoại."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vui lòng lắp thẻ SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Thẻ SIM bị thiếu hoặc không thể đọc được. Vui lòng lắp thẻ SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Thẻ SIM không sử dụng được."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Thẻ SIM của bạn đã bị vô hiệu hóa vĩnh viễn.\n Hãy liên hệ với nhà cung cấp dịch vụ không dây của bạn để lấy thẻ SIM khác."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Thẻ SIM đã bị khóa."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Thẻ SIM đã bị khóa PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Đang mở khóa thẻ SIM…"</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Tiện ích %2$d trong số %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Thêm tiện ích."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Trống"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Đã mở rộng vùng khóa."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Đã thu gọn vùng khóa."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> tiện ích."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Bộ chọn người dùng"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Trạng thái"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Máy ảnh"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Điều khiển phương tiện"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Đã bắt đầu xắp xếp lại tiện ích."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Đã kết thúc sắp xếp lại tiện ích."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Đã xóa tiện ích <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Mở rộng vùng khóa."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Mở khóa bằng cách trượt."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mở khóa bằng hình."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Mở khóa bằng khuôn mặt."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Mở khóa bằng mã pin."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Mở khóa bằng mật khẩu."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Khu vực hình."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Khu vực trượt."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nút bản nhạc trước"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nút bản nhạc tiếp theo"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nút tạm dừng"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Nút phát"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Nút dừng"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hủy"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Xóa"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Xong"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Thay đổi chế độ"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Mở khóa"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Máy ảnh"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Im lặng"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Bật âm thanh"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Trượt xuống để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Trượt sang trái để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Trượt sang phải để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Cuộc gọi khẩn cấp"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Đã quên hình"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Hình sai"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Mật khẩu sai"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN sai"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Hãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Vẽ hình của bạn"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Nhập PIN của SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Nhập PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Nhập mật khẩu"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM hiện bị vô hiệu hóa. Nhập mã PUK để tiếp tục. Liên hệ với nhà cung cấp dịch vụ để biết chi tiết."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Nhập mã PIN mong muốn"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Xác nhận mã PIN mong muốn"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Đang mở khóa thẻ SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Mã PIN không chính xác."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Nhập mã PIN có từ 4 đến 8 số."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Mã PUK phải có từ 8 số trở lên."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Mã PIN không khớp"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Để mở khóa, hãy đăng nhập bằng tài khoản Google của bạn."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Tên người dùng (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mật khẩu"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Đăng nhập"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Tên người dùng hoặc mật khẩu không hợp lệ."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bạn quên tên người dùng hoặc mật khẩu?\nHãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Đang kiểm tra tài khoản…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần mở khóa máy tính bảng không đúng cách. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần mở khóa điện thoại không đúng cách. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, điện thoại sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Bạn đã <xliff:g id="NUMBER">%d</xliff:g> lần mở khóa máy tính bảng không đúng cách. Bây giờ, máy tính bảng sẽ được đặt lại về mặc định ban đầu."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Bạn đã <xliff:g id="NUMBER">%d</xliff:g> lần mở khóa điện thoại không đúng cách. Bây giờ, điện thoại sẽ được đặt lại về mặc định ban đầu."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Xóa"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Nút bản nhạc trước"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nút bản nhạc tiếp theo"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Nút tạm dừng"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Nút phát"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Nút dừng"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Không có dịch vụ."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-xlarge/dimens.xml b/packages/Keyguard/res/values-xlarge/dimens.xml
new file mode 100644
index 0000000..b8cf287
--- /dev/null
+++ b/packages/Keyguard/res/values-xlarge/dimens.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 a key in the password keyboard for alpha -->
+    <dimen name="password_keyboard_key_height_alpha">75dip</dimen>
+    <!-- Default height of a key in the password keyboard for numeric -->
+    <dimen name="password_keyboard_key_height_numeric">75dip</dimen>
+    <!-- keyboardHeight = key_height*4 + key_bottom_gap*3 -->
+    <dimen name="password_keyboard_height">48.0mm</dimen>
+</resources>
diff --git a/packages/Keyguard/res/values-zh-rCN/activitystrings.xml b/packages/Keyguard/res/values-zh-rCN/activitystrings.xml
new file mode 100644
index 0000000..d9b99e0
--- /dev/null
+++ b/packages/Keyguard/res/values-zh-rCN/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"无安全措施"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"密码"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"图案"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM 卡 PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM 卡 PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"选择小部件..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..cdb1944e
--- /dev/null
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"请输入 PUK 码和新的 PIN 码"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 码"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新的 PIN 码"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"触摸可输入密码"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"输入 PIN 进行解锁"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 码有误。"</string>
+    <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_low_battery" msgid="8143808018719173859">"请连接充电器。"</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按“菜单”键解锁。"</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"网络已锁定"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无 SIM 卡"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM 卡缺失或无法读取,请插入 SIM 卡。"</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM 卡无法使用。"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的 SIM 卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡已被锁定。"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡已被 PUK 锁定。"</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解锁 SIM 卡..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。%3$d的小部件%2$d。"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"添加小部件。"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"已展开解锁区域。"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"已折叠解锁区域。"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小部件。"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"用户选择器"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"状态"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相机"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒体控制"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已开始将小部件重新排序。"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"已完成小部件重新排序。"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"已删除小部件<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>。"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展开解锁区域。"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑动解锁。"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"图案解锁。"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"人脸解锁。"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解锁。"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密码解锁。"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"图案区域。"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"滑动区域。"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"上一曲按钮"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"下一曲按钮"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"暂停按钮"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"播放按钮"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"停止按钮"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式更改"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"解锁"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"相机"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"静音"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"打开声音"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"向下滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"向左滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"向右滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+    <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"紧急呼救"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘记了图案"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"图案错误"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"密码错误"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡已被停用,需要输入 PUK 码才能继续使用。有关详情,请联系您的运营商。"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需 PIN 码"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需 PIN 码"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 码有误。"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 码应至少包含 8 位数字。"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的 PUK 码。如果尝试错误次数过多,SIM 卡将永久停用。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的 Google 帐户。"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"用户名(电子邮件地址)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"密码"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"登录"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"用户名或密码无效。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘记了用户名或密码?\n请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"正在检查帐户…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。\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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"“上一曲”按钮"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"“下一曲”按钮"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"“暂停”按钮"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"“播放”按钮"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"“停止”按钮"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-zh-rTW/activitystrings.xml b/packages/Keyguard/res/values-zh-rTW/activitystrings.xml
new file mode 100644
index 0000000..42c2a51
--- /dev/null
+++ b/packages/Keyguard/res/values-zh-rTW/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"Keyguard 測試活動"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"整合式相機"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"無安全性設定"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"密碼"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"圖形"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"SIM PIN"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"SIM PUK"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"選擇小工具..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"在螢幕上關閉"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"在螢幕上開啟"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"執行 Keyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"驗證解鎖"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..72a1c0f
--- /dev/null
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"輸入 PIN 碼"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"輸入 PUK 碼和新 PIN 碼"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 碼"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新 PIN 碼"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"輕觸即可輸入密碼"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"輸入密碼即可解鎖"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"輸入 PIN 即可解鎖"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</string>
+    <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_low_battery" msgid="8143808018719173859">"連接充電器。"</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按選單鍵解鎖。"</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"網路已鎖定"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"找不到 SIM 卡"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板電腦中沒有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手機中沒有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"插入 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"找不到或無法讀取 SIM 卡。請插入 SIM 卡。"</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM 卡無法使用。"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的 SIM 卡已遭永久停用。\n請與您的無線網路服務供應商聯絡,以取得別張 SIM 卡。"</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡處於鎖定狀態。"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡處於 PUK 鎖定狀態"</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解除 SIM 卡鎖定..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"新增小工具。"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"解鎖區域已展開。"</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"解鎖區域已收合。"</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具。"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"使用者選取工具"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"狀態"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相機"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制項"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已開始將小工具重新排序。"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"小工具重新排序已完成。"</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展開解鎖區域。"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑動解鎖。"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖形解鎖。"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"人臉解鎖。"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密碼解鎖。"</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"圖形區域。"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"滑動區域。"</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"[上一首曲目] 按鈕"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"[下一首曲目] 按鈕"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"[暫停] 按鈕"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"[播放] 按鈕"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"[停止] 按鈕"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 鍵"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 鍵"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式變更"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"解除鎖定"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"相機"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"靜音"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"開啟音效"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+    <string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖形"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖形錯誤"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"密碼錯誤"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 錯誤"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"請在 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"畫出圖形"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"輸入 SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"輸入 PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"輸入密碼"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡已遭停用,必須輸入 PUK 碼才能繼續使用。詳情請洽您的行動通訊業者。"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"輸入所需的 PIN 碼"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"確認所需的 PIN 碼"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解除 SIM 卡鎖定..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 碼不正確。"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"請輸入 4 到 8 碼的 PIN。"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 碼至少必須為 8 碼。"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"重新輸入正確的 PUK 碼。如果錯誤次數過多,SIM 卡將會永久停用。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖形嘗試次數過多"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"如要解除鎖定,請使用 Google 帳戶登入。"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"使用者名稱 (電子郵件)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"使用者名稱或密碼無效。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘了使用者名稱或密碼?\n請前往 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
+    <string name="kg_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_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>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <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>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"[上一首曲目] 按鈕"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"[下一首曲目] 按鈕"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"[暫停] 按鈕"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"[播放] 按鈕"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"[停止] 按鈕"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-zu/activitystrings.xml b/packages/Keyguard/res/values-zu/activitystrings.xml
new file mode 100644
index 0000000..0031a8b
--- /dev/null
+++ b/packages/Keyguard/res/values-zu/activitystrings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="3352888186674981593">"I-KeyguardTestActivity"</string>
+    <string name="secure_app_name" msgid="7955498742816868049">"I-UnifiedCamera"</string>
+    <string name="none_menu_item" msgid="6156747285687551424">"Akukho ukuphepha"</string>
+    <string name="pin_menu_item" msgid="1179756433268962311">"I-PIN"</string>
+    <string name="password_menu_item" msgid="1959980499662153160">"Iphasiwedi"</string>
+    <string name="pattern_menu_item" msgid="2987798152175140249">"Iphethini"</string>
+    <string name="sim_pin_menu_item" msgid="3962286639645084880">"I-PIN ye-SIM"</string>
+    <string name="sim_puk_menu_item" msgid="6190044133008392974">"I-PUK YE-SIM"</string>
+    <string name="add_widget_item" msgid="279702152366857415">"Khetha iwijethi..."</string>
+    <string name="on_screen_turned_off" msgid="8761396329770508367">"I-onScreenTurnedOff"</string>
+    <string name="on_screen_turned_on" msgid="9222926818030728999">"I-onScreenTurnedOn"</string>
+    <string name="do_keyguard" msgid="9210936977823118796">"I-doKeyguard"</string>
+    <string name="verify_unlock" msgid="8508722273329306968">"I-verifyUnlock"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
new file mode 100644
index 0000000..185ea03
--- /dev/null
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Faka ikhodi ye-PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Faka i-PUK nephinikhodi entsha"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Ikhodi le-PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Iphinikhodi entsha"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Thinta ukubhala iphasiwedi"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Bhala iphasiwedi ukuze kuvuleke"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Faka i-PIN ukuvula"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Ikhodi ye-PIN engalungile!"</string>
+    <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_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>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Alikho ikhadi le-SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Alikho ikhadi le-SIM kuthebulethi."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Alikho ikhadi le-SIM kufoni."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Faka ikhadi le-SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Ikhadi le-SIM alitholakali noma alifundeki. Faka ikhadi le-SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Ikhadi le-SIM elingasebenziseki."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"I-SIM khadi yakho ikhutshazwe unomphela.\n Xhumana nomhlinzeki wakho wokuxhumana okungenazintambo ukuze uthole enye i-SIM khadi."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Ikhadi le-SIM likhiyiwe."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Ikhadi le-SIM likhiywe nge-PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ivula ikhadi le-SIM..."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. iwijethi %2$d ye-%3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Engeza iwijethi."</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Akunalutho"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Indawo yokuvula inwetshisiwe."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Indawo yokuvula inciphisiwe."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> iwijethi."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Isikhethi somsebenzisi"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Isimo"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Ikhamera"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Izilawuli zemidiya"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Ukuhlelwa kabusha kwewijethi kuqalile"</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ukuhlelwa kabusha kwewijethi kuphelile."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Iwijethi <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> isusiwe."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Nwebisa indawo yokuvula."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Ukuvula ngokuslayida."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ukuvula ngephethini."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Vula ngobuso"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Ukuvula ngephinikhodi."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Ukuvula ngephasiwedi."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Indawo yephethini."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Indawo yokushelelisa."</string>
+    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Inkinombo yethrekhi yangaphambilini"</string>
+    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Inkinobho yethrekhi elandelayo"</string>
+    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Inkinobho yokumiswa isikhashana"</string>
+    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Inkinobho yokudlala"</string>
+    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Inkinobho yokumisa"</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"i-ALT"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Khansela"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Susa"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Kwenziwe"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ukushintsha kwendlela esetshenziswayo"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Beka kwenye indawo"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Faka"</string>
+    <string name="description_target_unlock" msgid="2228524900439801453">"Vula"</string>
+    <string name="description_target_camera" msgid="969071997552486814">"Ikhamera"</string>
+    <string name="description_target_silent" msgid="893551287746522182">"Thulile"</string>
+    <string name="description_target_soundon" msgid="30052466675500172">"Umsindo uvuliwe"</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>
+    <string name="description_direction_down" msgid="5087739728639014595">"Shelelisela ngezansi ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Shelelisela ngakwesokunxele ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_right" msgid="8034433242579600980">"Shelelisela ngakwesokudla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Ucingo lwezimo eziphuthumayo"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ukhohlwe iphethini?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Iphatheni engalungile"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Iphasiwedi engalungile"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Iphinikhodi engalungile"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zama futhi emasekhondini angu-<xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dweba iphethini"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Faka iphinikhodi ye-SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Faka iphinikhodi"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Faka iphasiwedi"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Xhumana nenkampani yenethiwekhi ngemininingwane."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Faka iphinikhodi oyithandayo"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Qiniseka iphinikhodi oyithandayo"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ivula ikhadi le-SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Iphinikhodi engalungile."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Thayipha iphinikhodi enezinombolo ezingu-4 kuya kwezingu-8."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Ikhodi ye-PUK kufanele ibe yizinombolo ezingu-8 noma eziningi."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Iphinikhodi ayifani"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Kunemizamo eminingi kakhulu yephathini"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Ukuvula, ngena ngemvume kwi-akhawunti ye-Google"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Igama lomsebenzisi (i-imeyli)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Iphasiwedi"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Ngena ngemvume"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Igama lomsebezisi elingalungile noma iphasiwedi."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?\nVakashela"<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Ukuhlola i-akhawunti…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Uzame ngokusebenzisa indlela engafanele ukuvula ithebhulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kokuzama ngaphandle kwempumelelo okungu-<xliff:g id="NUMBER_1">%d</xliff:g>, ithebhulethi izobuyiselwa kwizimiso zasembonini futhi yonke imininingwane yomsebenzisi izolahleka."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Uzame ngokusebenzisa indlela engafanele ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kokuzama ngaphandle kwempumelelo okungu-<xliff:g id="NUMBER_1">%d</xliff:g>, ifoni izobuyiselwa kwizimiso zasembonini futhi yonke imininingwane yomsebenzisi izolahleka."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Uzame ukuvula ngendlela engafanele ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Ithebhulethi manje isizosethwa kabusha ibe yizimiso ezizenzakalelayo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Uzame ukuvula ngendlela engafanele ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Ifoni manje isizosethwa kabusha ibe yizimiso ezizenzakalelayo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Susa"</string>
+    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Inkinombo yethrekhi yangaphambilini"</string>
+    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Inkinobho yethrekhi elandelayo"</string>
+    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Inkinobho yokumiswa isikhashana"</string>
+    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Inkinobho yokudlala"</string>
+    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Inkinobho yokumisa"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ayikho isevisi."</string>
+</resources>
diff --git a/packages/Keyguard/res/values/alias.xml b/packages/Keyguard/res/values/alias.xml
new file mode 100644
index 0000000..c964391
--- /dev/null
+++ b/packages/Keyguard/res/values/alias.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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>
+
+    <!-- Alias used to reference framework color for transparency. -->
+    <item type="color" name="transparent">@android:color/transparent</item>
+
+    <!-- Alias used to reference framework drawable in keyguard. -->
+    <item type="drawable" name="stat_sys_warning">@android:drawable/stat_sys_warning</item>
+
+    <!-- Alias used to reference framework drawable in keyguard. -->
+    <item type="drawable" name="ic_media_pause">@android:drawable/ic_media_pause</item>
+
+    <!-- Alias used to reference framework drawable in keyguard. -->
+    <item type="drawable" name="ic_media_stop">@*android:drawable/ic_media_stop</item>
+
+    <!-- Alias used to reference framework drawable in keyguard. -->
+    <item type="drawable" name="ic_contact_picture">@*android:drawable/ic_contact_picture</item>
+
+    <!-- Alias used to reference framework drawable in keyguard. -->
+    <item type="drawable" name="ic_lock_idle_alarm">@*android:drawable/ic_lock_idle_alarm</item>
+
+    <!-- Alias used to reference framework "OK" string in keyguard.  -->
+    <item type="string" name="ok">@*android:string/ok</item>
+
+    <!-- Alias used to reference framework "OK" string in keyguard.  -->
+    <item type="string" name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</item>
+
+    <!-- Alias used to reference framework configuration for screen rotation.  -->
+    <item type="bool" name="config_enableLockScreenRotation">@*android:bool/config_enableLockScreenRotation</item>
+
+    <!-- Alias used to reference framework configuration for transparent bars.  -->
+    <item type="bool" name="config_enableLockScreenTransparentBars">@*android:bool/config_enableLockScreenTransparentBars</item>
+
+    <!-- Alias used to reference framework activity duration.  -->
+    <item type="integer" name="config_activityDefaultDur">@*android:integer/config_activityDefaultDur</item>
+
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values/arrays.xml b/packages/Keyguard/res/values/arrays.xml
new file mode 100644
index 0000000..550f80c
--- /dev/null
+++ b/packages/Keyguard/res/values/arrays.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Resources for GlowPadView in LockScreen -->
+    <array name="lockscreen_targets_when_silent">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_silent">
+        <item>@string/description_target_unlock</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_direction_descriptions">
+        <item>@string/description_direction_right</item>
+        <item>@string/description_direction_up</item>
+        <item>@string/description_direction_left</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_when_soundon">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_silent</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_soundon">
+        <item>@string/description_target_unlock</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_silent</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_with_camera">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@drawable/ic_action_assist_generic</item>
+        <item>@drawable/ic_lockscreen_camera</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_with_camera">
+        <item>@string/description_target_unlock</item>
+        <item>@string/description_target_search</item>
+        <item>@string/description_target_camera</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_unlock_only">
+        <item>@drawable/ic_lockscreen_unlock</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_unlock_only">
+        <item>@string/description_target_unlock</item>
+    </array>
+
+    <!-- list of 3- or 4-letter mnemonics for a 10-key numeric keypad -->
+    <string-array translatable="false" name="lockscreen_num_pad_klondike">
+        <item></item><!-- 0 -->
+        <item></item><!-- 1 -->
+        <item>ABC</item><!-- 2 -->
+        <item>DEF</item><!-- 3 -->
+        <item>GHI</item><!-- 4 -->
+        <item>JKL</item><!-- 5 -->
+        <item>MNO</item><!-- 6 -->
+        <item>PQRS</item><!-- 7 -->
+        <item>TUV</item><!-- 8 -->
+        <item>WXYZ</item><!-- 9 -->
+    </string-array>
+</resources>
diff --git a/packages/Keyguard/res/values/attrs.xml b/packages/Keyguard/res/values/attrs.xml
new file mode 100644
index 0000000..e045dd2
--- /dev/null
+++ b/packages/Keyguard/res/values/attrs.xml
@@ -0,0 +1,136 @@
+<?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.
+-->
+
+<!-- Formatting note: terminate all comments with a period, to avoid breaking
+     the documentation output. To suppress comment lines from the documentation
+     output, insert an eat-comment element after the comment lines.
+-->
+
+<resources>
+    <!-- Standard gravity constant that a child supplies to its parent.
+         Defines how the child view should be positioned, on both the X and Y axes, within its enclosing layout. -->
+    <attr name="layout_gravity">
+        <!-- Push object to the top of its container, not changing its size. -->
+        <flag name="top" value="0x30" />
+        <!-- Push object to the bottom of its container, not changing its size. -->
+        <flag name="bottom" value="0x50" />
+        <!-- Push object to the left of its container, not changing its size. -->
+        <flag name="left" value="0x03" />
+        <!-- Push object to the right of its container, not changing its size. -->
+        <flag name="right" value="0x05" />
+        <!-- Place object in the vertical center of its container, not changing its size. -->
+        <flag name="center_vertical" value="0x10" />
+        <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
+        <flag name="fill_vertical" value="0x70" />
+        <!-- Place object in the horizontal center of its container, not changing its size. -->
+        <flag name="center_horizontal" value="0x01" />
+        <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
+        <flag name="fill_horizontal" value="0x07" />
+        <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
+        <flag name="center" value="0x11" />
+        <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
+        <flag name="fill" value="0x77" />
+        <!-- Additional option that can be set to have the top and/or bottom edges of
+             the child clipped to its container's bounds.
+             The clip will be based on the vertical gravity: a top gravity will clip the bottom
+             edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
+        <flag name="clip_vertical" value="0x80" />
+        <!-- Additional option that can be set to have the left and/or right edges of
+             the child clipped to its container's bounds.
+             The clip will be based on the horizontal gravity: a left gravity will clip the right
+             edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+        <flag name="clip_horizontal" value="0x08" />
+        <!-- Push object to the beginning of its container, not changing its size. -->
+        <flag name="start" value="0x00800003" />
+        <!-- Push object to the end of its container, not changing its size. -->
+        <flag name="end" value="0x00800005" />
+    </attr>
+
+
+    <!-- PagedView specific attributes. These attributes are used to customize
+         a PagedView view in XML files. -->
+    <declare-styleable name="PagedView">
+        <!-- The space between adjacent pages of the PagedView. -->
+        <attr name="pageSpacing" format="dimension" />
+        <!-- The padding for the scroll indicator area -->
+        <attr name="scrollIndicatorPaddingLeft" format="dimension" />
+        <attr name="scrollIndicatorPaddingRight" format="dimension" />
+    </declare-styleable>
+
+    <declare-styleable name="KeyguardGlowStripView">
+        <attr name="dotSize" format="dimension" />
+        <attr name="numDots" format="integer" />
+        <attr name="glowDot" format="reference" />
+        <attr name="leftToRight" format="boolean" />
+    </declare-styleable>
+
+    <!-- Some child types have special behavior. -->
+    <attr name="layout_childType">
+        <!-- No special behavior. Layout will proceed as normal. -->
+        <enum name="none" value="0" />
+        <!-- Widget container.
+             This will be resized in response to certain events. -->
+        <enum name="widget" value="1" />
+        <!-- Security challenge container.
+             This will be dismissed/shown in response to certain events,
+             possibly obscuring widget elements. -->
+        <enum name="challenge" value="2" />
+        <!-- User switcher.
+             This will consume space from the total layout area. -->
+        <enum name="userSwitcher" value="3" />
+        <!-- Scrim. This will block access to child views that
+             come before it in the child list in bouncer mode. -->
+        <enum name="scrim" value="4" />
+        <!-- The home for widgets. All widgets will be descendents of this. -->
+        <enum name="widgets" value="5" />
+        <!-- This is a handle that is used for expanding the
+             security challenge container when it is collapsed. -->
+        <enum name="expandChallengeHandle" value="6" />
+        <!-- Delete drop target.  This will be the drop target to delete pages. -->
+        <enum name="pageDeleteDropTarget" value="7" />
+    </attr>
+
+    <declare-styleable name="SlidingChallengeLayout_Layout">
+        <attr name="layout_childType" />
+        <attr name="layout_maxHeight" format="dimension" />
+    </declare-styleable>
+
+    <declare-styleable name="MultiPaneChallengeLayout">
+        <!-- Influences how layout_centerWithinArea behaves -->
+        <attr name="android:orientation" />
+    </declare-styleable>
+
+    <declare-styleable name="MultiPaneChallengeLayout_Layout">
+        <!-- Percentage of the screen this child should consume or center within.
+             If 0/default, the view will be measured by standard rules
+             as if this were a FrameLayout. -->
+        <attr name="layout_centerWithinArea" format="float" />
+        <attr name="layout_childType" />
+        <attr name="layout_gravity" />
+        <attr name="layout_maxWidth" format="dimension" />
+        <attr name="layout_maxHeight" />
+    </declare-styleable>
+
+    <declare-styleable name="KeyguardSecurityViewFlipper_Layout">
+        <attr name="layout_maxWidth" />
+        <attr name="layout_maxHeight" />
+    </declare-styleable>
+
+    <declare-styleable name="NumPadKey">
+        <attr name="digit" format="integer" />
+        <attr name="textView" format="reference" />
+    </declare-styleable>
+</resources>
diff --git a/packages/Keyguard/res/values/bools.xml b/packages/Keyguard/res/values/bools.xml
new file mode 100644
index 0000000..5e842d7
--- /dev/null
+++ b/packages/Keyguard/res/values/bools.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<resources>
+    <bool name="kg_enable_camera_default_widget">true</bool>
+    <bool name="kg_center_small_widgets_vertically">false</bool>
+    <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
+    <bool name="kg_show_ime_at_screen_on">true</bool>
+    <bool name="kg_use_all_caps">true</bool>
+</resources>
diff --git a/packages/Keyguard/res/values/colors.xml b/packages/Keyguard/res/values/colors.xml
new file mode 100644
index 0000000..0c56a43
--- /dev/null
+++ b/packages/Keyguard/res/values/colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Keyguard colors -->
+    <color name="keyguard_avatar_frame_color">#ffffffff</color>
+    <color name="keyguard_avatar_frame_shadow_color">#80000000</color>
+    <color name="keyguard_avatar_nick_color">#ffffffff</color>
+    <color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
+    <color name="kg_widget_pager_gradient">#ffffffff</color>
+
+    <!-- FaceLock -->
+    <color name="facelock_spotlight_mask">#CC000000</color>
+</resources>
diff --git a/packages/Keyguard/res/values/config.xml b/packages/Keyguard/res/values/config.xml
new file mode 100644
index 0000000..de17c4b
--- /dev/null
+++ b/packages/Keyguard/res/values/config.xml
@@ -0,0 +1,32 @@
+<?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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
+    <string name="widget_default_package_name"></string>
+
+    <!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
+    <string name="widget_default_class_name"></string>
+
+    <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
+    <bool name="config_disableMenuKeyInLockScreen">false</bool>
+
+</resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
new file mode 100644
index 0000000..ce72f43
--- /dev/null
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 a key in the password keyboard for alpha (used by keyguard) -->
+    <dimen name="password_keyboard_key_height_alpha">56dip</dimen>
+    <!-- Default height of a key in the password keyboard for numeric (used by keyguard) -->
+    <dimen name="password_keyboard_key_height_numeric">56dip</dimen>
+    <!-- Default correction for the space key in the password keyboard  (used by keyguard) -->
+    <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
+    <!-- Default horizontal gap between keys in the password keyboard (used by keyguard) -->
+    <dimen name="password_keyboard_horizontalGap">3dip</dimen>
+    <!-- Default vertical gap between keys in the password keyboard (used by keyguard) -->
+    <dimen name="password_keyboard_verticalGap">9dip</dimen>
+
+    <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
+    <dimen name="keyguard_lockscreen_outerring_diameter">270dp</dimen>
+
+    <!-- The bottom margin for the GlowPadView container -->
+    <dimen name="glowpadcontainer_bottom_margin">-80dp</dimen>
+
+    <!-- Default target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
+    <dimen name="glowpadview_target_placement_radius">135dip</dimen>
+
+    <!-- Default glow radius for GlowPadView -->
+    <dimen name="glowpadview_glow_radius">75dip</dimen>
+
+    <!-- Default distance beyond which GlowPadView snaps to the matching target -->
+    <dimen name="glowpadview_snap_margin">40dip</dimen>
+
+    <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
+    <dimen name="glowpadview_inner_radius">15dip</dimen>
+
+    <!-- Size of clock font in LockScreen on Unsecure unlock screen. -->
+    <dimen name="keyguard_lockscreen_clock_font_size">80dip</dimen>
+
+    <!-- Size of status line font on Unsecure unlock LockScreen. -->
+    <dimen name="keyguard_lockscreen_status_line_font_size">14dip</dimen>
+
+    <!-- Size of right margin on Unsecure unlock LockScreen -->
+    <dimen name="keyguard_lockscreen_status_line_font_right_margin">42dip</dimen>
+
+    <!-- Size of top margin on Clock font to edge on unlock LockScreen -->
+    <dimen name="keyguard_lockscreen_status_line_clockfont_top_margin">22dip</dimen>
+
+    <!-- Size of top margin on Clock font to edge on unlock LockScreen -->
+    <dimen name="keyguard_lockscreen_status_line_clockfont_bottom_margin">12dip</dimen>
+
+    <!-- Padding on left margin of PIN text entry field to center it when del button is showing -->
+    <dimen name="keyguard_lockscreen_pin_margin_left">40dip</dimen>
+
+    <!-- Height of FaceUnlock view in keyguard -->
+    <dimen name="face_unlock_height">330dip</dimen>
+
+    <!-- Keyguard dimensions -->
+    <!-- TEMP -->
+    <dimen name="kg_security_panel_height">600dp</dimen>
+
+    <!-- Height of security view in keyguard. -->
+    <dimen name="kg_security_view_height">480dp</dimen>
+
+    <!-- Width of widget view in keyguard. -->
+    <dimen name="kg_widget_view_width">0dp</dimen>
+
+    <!-- Height of widget view in keyguard. -->
+    <dimen name="kg_widget_view_height">0dp</dimen>
+
+    <!-- Size of the clock font in keyguard's status view -->
+    <dimen name="kg_status_clock_font_size">75dp</dimen>
+
+    <!-- Size of the date font in keyguard's status view  -->
+    <dimen name="kg_status_date_font_size">15dp</dimen>
+
+    <!-- Size of the generic status lines keyguard's status view  -->
+    <dimen name="kg_status_line_font_size">13dp</dimen>
+
+    <!-- Size of margin on the right of keyguard's status view -->
+    <dimen name="kg_status_line_font_right_margin">16dp</dimen>
+
+    <!-- Top margin for the clock view -->
+    <dimen name="kg_clock_top_margin">-16dp</dimen>
+
+    <!-- Horizontal gap between keys in PIN and SIM PIN numeric keyboards in keyguard -->
+    <dimen name="kg_key_horizontal_gap">0dp</dimen>
+
+    <!-- Horizontal gap between keys in PIN and SIM PIN numeric keyboards in keyguard -->
+    <dimen name="kg_key_vertical_gap">0dp</dimen>
+
+    <!-- Horizontal gap between keys in PIN and SIM PIN numeric keyboards in keyguard -->
+    <dimen name="kg_pin_key_height">60dp</dimen>
+
+    <!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
+    <dimen name="kg_secure_padding_height">46dp</dimen>
+
+    <!-- The height of the runway lights strip -->
+    <dimen name="kg_runway_lights_height">7dp</dimen>
+
+    <!-- The height of the runway lights strip -->
+    <dimen name="kg_runway_lights_vertical_padding">2dp</dimen>
+
+    <!-- Horizontal padding for the widget pager -->
+    <dimen name="kg_widget_pager_horizontal_padding">16dp</dimen>
+
+    <!-- Top padding for the widget pager -->
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
+
+    <!-- Bottom padding for the widget pager -->
+    <dimen name="kg_widget_pager_bottom_padding">64dp</dimen>
+
+    <!-- Top margin for the runway lights. We add a negative margin in large
+        devices to account for the widget pager padding -->
+    <dimen name="kg_runway_lights_top_margin">0dp</dimen>
+
+    <!-- Touch slop for the global toggle accessibility gesture -->
+    <dimen name="accessibility_touch_slop">80dip</dimen>
+
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">320dp</dimen>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">400dp</dimen>
+
+    <!-- Margin around the various security views -->
+    <dimen name="keyguard_security_view_margin">8dp</dimen>
+
+    <!-- Margin around the various security views -->
+    <dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
+
+    <!-- Stroke width of the frame for the circular avatars. -->
+    <dimen name="keyguard_avatar_frame_stroke_width">2dp</dimen>
+
+    <!-- Shadow radius under the frame for the circular avatars. -->
+    <dimen name="keyguard_avatar_frame_shadow_radius">1dp</dimen>
+
+    <!-- Size of the avator on hte multiuser lockscreen. -->
+    <dimen name="keyguard_avatar_size">66dp</dimen>
+
+    <!-- Size of the text under the avator on the multiuser lockscreen. -->
+    <dimen name="keyguard_avatar_name_size">10sp</dimen>
+
+    <!-- Size of the region along the edge of the screen that will accept
+         swipes to scroll the widget area. -->
+    <dimen name="kg_edge_swipe_region_size">24dp</dimen>
+
+    <!-- If the height if keyguard drops below this threshold (most likely
+    due to the appearance of the IME), then drop the multiuser selector. -->
+    <dimen name="kg_squashed_layout_threshold">600dp</dimen>
+
+    <!-- The height of widgets which do not support vertical resizing. This is only
+    used on tablets; on phones, this size is determined by the space left by the
+    security mode. -->
+    <dimen name="kg_small_widget_height">160dp</dimen>
+
+</resources>
diff --git a/packages/Keyguard/res/values/integers.xml b/packages/Keyguard/res/values/integers.xml
new file mode 100644
index 0000000..dc90bbf
--- /dev/null
+++ b/packages/Keyguard/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?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.
+*/
+-->
+<resources>
+    <integer name="kg_carousel_angle">75</integer>
+    <integer name="kg_glowpad_rotation_offset">0</integer>
+</resources>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
new file mode 100644
index 0000000..89e7240
--- /dev/null
+++ b/packages/Keyguard/res/values/strings.xml
@@ -0,0 +1,341 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
+         Displayed in one line in a large font.  -->
+    <string name="keyguard_password_enter_pin_code">Type PIN code</string>
+
+    <!-- Instructions telling the user to enter their SIM PUK to unlock the keyguard.
+         Displayed in one line in a large font.  -->
+    <string name="keyguard_password_enter_puk_code">Type PUK and new PIN code</string>
+
+    <!-- Prompt to enter SIM PUK in Edit Text Box in unlock screen -->
+    <string name="keyguard_password_enter_puk_prompt">PUK code</string>
+    <!-- Prompt to enter New SIM PIN in Edit Text Box in unlock screen -->
+    <string name="keyguard_password_enter_pin_prompt">New PIN code</string>
+
+    <!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]-->
+    <string name="keyguard_password_entry_touch_hint"><font size="17">Touch to type password</font></string>
+
+    <!-- Instructions telling the user to enter their text password to unlock the keyguard.
+         Displayed in one line in a large font.  -->
+    <string name="keyguard_password_enter_password_code">Type password to unlock</string>
+
+    <!-- Instructions telling the user to enter their PIN password to unlock the keyguard.
+         Displayed in one line in a large font.  -->
+    <string name="keyguard_password_enter_pin_password_code">Type PIN to unlock</string>
+
+    <!-- Instructions telling the user that they entered the wrong pin while trying
+         to unlock the keyguard.  Displayed in one line in a large font.  -->
+    <string name="keyguard_password_wrong_pin_code">Incorrect PIN code.</string>
+
+    <!-- Instructions telling the user how to unlock the phone. -->
+    <string name="keyguard_label_text">To unlock, press Menu then 0.</string>
+
+    <!-- Shown when face unlock failed multiple times so we're just using the backup -->
+    <string name="faceunlock_multiple_failures">Maximum Face Unlock attempts exceeded</string>
+
+    <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
+         charged, say that it is charged. -->
+    <string name="keyguard_charged">Charged</string>
+
+    <!-- When the lock screen is showing and the phone plugged in, and the battery
+         is not fully charged, show the current charge %.  -->
+    <string name="keyguard_plugged_in">Charging, <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string>
+
+    <!-- When the lock screen is showing and the battery is low, warn user to plug
+         in the phone soon. -->
+    <string name="keyguard_low_battery">Connect your charger.</string>
+
+    <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock.  This is shown in small font at the bottom. -->
+    <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
+
+    <!-- SIM messages --><skip />
+    <!-- When the user inserts a sim card from an unsupported network, it becomes network locked -->
+    <string name="keyguard_network_locked_message">Network locked</string>
+    <!-- Shown when there is no SIM card. -->
+    <string name="keyguard_missing_sim_message_short">No SIM card</string>
+    <!-- Shown when there is no SIM card. -->
+    <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string>
+    <!-- Shown when there is no SIM card. -->
+    <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string>
+    <!-- Shown to ask the user to insert a SIM card. -->
+    <string name="keyguard_missing_sim_instructions">Insert a SIM card.</string>
+    <!-- Shown to ask the user to insert a SIM card when sim is missing or not readable. -->
+    <string name="keyguard_missing_sim_instructions_long">The SIM card is missing or not readable. Insert a SIM card.</string>
+    <!-- Shown when SIM card is permanently disabled. -->
+    <string name="keyguard_permanent_disabled_sim_message_short">Unusable SIM card.</string>
+    <!-- Shown to inform the user to SIM card is permanently disabled. -->
+    <string name="keyguard_permanent_disabled_sim_instructions">Your SIM card has been permanently disabled.\n
+    Contact your wireless service provider for another SIM card.</string>
+    <!-- Shown to tell the user that their SIM is locked and they must unlock it. -->
+    <string name="keyguard_sim_locked_message">SIM card is locked.</string>
+    <!-- When the user enters a wrong sim pin too many times, it becomes PUK locked (Pin Unlock Kode) -->
+    <string name="keyguard_sim_puk_locked_message">SIM card is PUK-locked.</string>
+    <!-- For the unlock screen, When the user enters a sim unlock code, it takes a little while to check
+         whether it is valid, and to unlock the sim if it is valid.  we display a
+         progress dialog in the meantime.  this is the emssage. -->
+    <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+
+
+    <!-- Accessibility description sent when user changes the current lock screen widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_changed">%1$s. Widget %2$d of %3$d.</string>
+    <!-- Accessibility description of the add widget button. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_add_widget">Add widget.</string>
+    <!-- Accessibility description of the empty sidget slot (place holder for a new widget). [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_empty_slot">Empty</string>
+    <!-- Accessibility description of the event of expanding an unlock area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_unlock_area_expanded">Unlock area expanded.</string>
+    <!-- Accessibility description of the event of collapsing an unlock area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_unlock_area_collapsed">Unlock area collapsed.</string>
+    <!-- Accessibility description of a lock screen widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string>
+    <!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_user_selector">User selector</string>
+    <!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_status">Status</string>
+    <!-- Accessibility description of the camera widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_camera">Camera</string>
+    <!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
+    <string name="keygaurd_accessibility_media_controls">Media controls</string>
+    <!-- Accessibility description of widget reordering start. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_reorder_start">Widget reordering started.</string>
+    <!-- Accessibility description of widget reordering end. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_reorder_end">Widget reordering ended.</string>
+    <!-- Accessibility description of the a widget deletion event. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_deleted">Widget <xliff:g id="widget_index">%1$s</xliff:g> deleted.</string>
+    <!-- Accessibility description of the button to expand the lock area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_expand_lock_area">Expand unlock area.</string>
+    <!-- Accessibility description of the slide unlock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_slide_unlock">Slide unlock.</string>
+    <!-- Accessibility description of the pattern unlock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string>
+    <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_face_unlock">Face unlock.</string>
+    <!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_pin_unlock">Pin unlock.</string>
+    <!-- Accessibility description of the password lock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_password_unlock">Password unlock.</string>
+    <!-- Accessibility description of the unlock pattern area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_pattern_area">Pattern area.</string>
+    <!-- Accessibility description of the unlock slide area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_slide_area">Slide area.</string>
+
+    <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
+    <string name="keyguard_accessibility_transport_prev_description">Previous track button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button goes to next track. -->
+    <string name="keyguard_accessibility_transport_next_description">Next track button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
+    <string name="keyguard_accessibility_transport_pause_description">Pause button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
+    <string name="keyguard_accessibility_transport_play_description">Play button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
+    <string name="keyguard_accessibility_transport_stop_description">Stop button</string>
+
+    <!-- Accessibility description for when the device prompts the user to dismiss keyguard
+         in order to complete an action. This will be followed by a message about the current
+         security option (e.g. "Pattern unlock."). [CHAR LIMIT=NONE] -->
+    <string name="keyguard_accessibility_show_bouncer">Unlock to continue</string>
+
+    <!-- Accessibility description for when the bouncer prompt is dismissed. [CHAR LIMIT=NONE] -->
+    <string name="keyguard_accessibility_hide_bouncer">Launch canceled</string>
+
+    <!-- Accessibility description announced when user drags widget over the delete drop target [CHAR LIMIT=NONE] -->
+    <string name="keyguard_accessibility_delete_widget_start">Drop <xliff:g id="widget_index">%1$s</xliff:g> to delete.</string>
+
+    <!-- Accessibility description announced when user drags widget away from delete drop target [CHAR LIMIT=NONE] -->
+    <string name="keyguard_accessibility_delete_widget_end"><xliff:g id="widget_index">%1$s</xliff:g> will not be deleted.</string>
+
+    <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
+    <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
+    <string name="password_keyboard_label_symbol_key">\?123</string>
+    <!-- Label for "switch to alphabetic" key.  Must be short to fit on key! -->
+    <string name="password_keyboard_label_alpha_key">ABC</string>
+    <!-- Label for ALT modifier key.  Must be short to fit on key! -->
+    <string name="password_keyboard_label_alt_key">ALT</string>
+
+    <!-- KeyboardView - accessibility support --><skip />
+    <!-- Description of the Alt button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_alt">Alt</string>
+    <!-- Description of the Cancel button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_cancel">Cancel</string>
+    <!-- Description of the Delete button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_delete">Delete</string>
+    <!-- Description of the Done button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_done">Done</string>
+    <!-- Description of the Mode change button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_mode_change">Mode change</string>
+    <!-- Description of the Shift button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_shift">Shift</string>
+    <!-- Description of the Enter button in a KeyboardView. [CHAR LIMIT=NONE] -->
+    <string name="keyboardview_keycode_enter">Enter</string>
+
+    <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_target_unlock">Unlock</string>
+    <!-- Description of the camera target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_target_camera">Camera</string>
+    <!-- Description of the silent target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_target_silent">Silent</string>
+    <!-- Description of the sound on target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_target_soundon">Sound on</string>
+    <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_target_search">Search</string>
+
+    <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_direction_up">Slide up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
+    <!-- Description of the down direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_direction_down">Slide down for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
+    <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
+    <!-- Description of the right direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_direction_right">Slide right for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
+
+    <!-- Text spoken when the current user is switched if accessibility is enabled. [CHAR LIMIT=none] -->
+    <string name="user_switched">Current user <xliff:g id="name" example="Bob">%1$s</xliff:g>.</string>
+
+    <!-- Label shown on emergency call button in keyguard -->
+    <string name="kg_emergency_call_label">Emergency call</string>
+    <!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
+    <string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
+    <!-- Message shown when user enters wrong pattern -->
+    <string name="kg_wrong_pattern">Wrong Pattern</string>
+    <!-- Message shown when user enters wrong password -->
+    <string name="kg_wrong_password">Wrong Password</string>
+    <!-- Message shown when user enters wrong PIN -->
+    <string name="kg_wrong_pin">Wrong PIN</string>
+    <!-- Countdown message shown after too many failed unlock attempts -->
+    <string name="kg_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>
+    <!-- Instructions for using the pattern unlock screen -->
+    <string name="kg_pattern_instructions">Draw your pattern</string>
+    <!-- Instructions for using the SIM PIN unlock screen -->
+    <string name="kg_sim_pin_instructions">Enter SIM PIN</string>
+    <!-- Instructions for using the PIN unlock screen -->
+    <string name="kg_pin_instructions">Enter PIN</string>
+    <!-- Instructions for using the password unlock screen -->
+    <string name="kg_password_instructions">Enter Password</string>
+    <!-- Hint shown in the PUK screen that asks the user to enter the PUK code given to them by their provider -->
+    <string name="kg_puk_enter_puk_hint">SIM is now disabled. Enter PUK code to continue. Contact carrier for details.</string>
+    <!-- Hint shown in the PUK unlock screen PIN TextView -->
+    <string name="kg_puk_enter_pin_hint">Enter desired PIN code</string>
+    <!-- Message shown when the user needs to confirm the PIN they just entered in the PUK screen -->
+    <string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
+    <!-- Message shown in dialog while the device is unlocking the SIM card -->
+    <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+    <!-- Message shown when the user enters the wrong PIN code -->
+    <string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
+    <!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
+    <string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
+    <!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
+    <string name="kg_invalid_sim_puk_hint">PUK code should be 8 numbers or more.</string>
+    <!-- Message shown when the user enters an invalid PUK code -->
+    <string name="kg_invalid_puk">Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM.</string>
+      <!-- String shown in PUK screen when PIN codes don't match -->
+    <string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string>
+    <!-- Message shown when the user exceeds the maximum number of pattern attempts -->
+    <string name="kg_login_too_many_attempts">Too many pattern attempts</string>
+    <!-- Instructions show in account unlock screen allowing user to enter their email password -->
+    <string name="kg_login_instructions">To unlock, sign in with your Google account.</string>
+    <!-- Hint shown in TextView in account unlock screen of keyguard -->
+    <string name="kg_login_username_hint">Username (email)</string>
+    <!-- Hint shown in TextView in account unlock screen of keyguard -->
+    <string name="kg_login_password_hint">Password</string>
+    <!-- Label shown on sign in button on account unlock screen of keyguard -->
+    <string name="kg_login_submit_button">Sign in</string>
+    <!-- Message shown when the user enters an invalid username/password combination in account unlock screen of keyguard -->
+    <string name="kg_login_invalid_input">Invalid username or password.</string>
+    <!-- Hint text shown when user has too many failed password attempts in account unlock screen of keyguard -->
+    <string name="kg_login_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b>.</string>
+    <!-- Message shown while device checks username/password in account unlock screen of keyguard -->
+    <string name="kg_login_checking_password">Checking account\u2026</string>
+    <!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
+    <string name="kg_too_many_failed_pin_attempts_dialog_message">
+        You have incorrectly typed your PIN <xliff:g id="number">%d</xliff:g> times.
+        \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+    <!-- Message shown in dialog when max number of attempts are reached for password screen of keyguard -->
+    <string name="kg_too_many_failed_password_attempts_dialog_message">
+        You have incorrectly typed your password <xliff:g id="number">%d</xliff:g> times.
+        \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message">
+        You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
+        \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       the tablet will be reset to factory default and all user data will be lost.
+    </string>
+    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
+    <string name="kg_failed_attempts_almost_at_wipe" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       the phone will be reset to factory default and all user data will be lost.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
+    <string name="kg_failed_attempts_now_wiping" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
+       The tablet will now be reset to factory default.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
+    <string name="kg_failed_attempts_now_wiping" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
+       The phone will now be reset to factory default.
+    </string>
+    <!-- Message shown in dialog when user is almost at the limit where they will be
+    locked out and may have to enter an alternate username/password to unlock the phone -->
+    <string name="kg_failed_attempts_almost_at_login" product="tablet">
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       you will be asked to unlock your tablet using an email account.\n\n
+       Try again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+    <!-- Message shown in dialog when user is almost at the limit where they will be
+    locked out and may have to enter an alternate username/password to unlock the phone -->
+    <string name="kg_failed_attempts_almost_at_login" product="default">
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       you will be asked to unlock your phone using an email account.\n\n
+       Try again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+    <!-- Sequence of characters used to separate message strings in keyguard. Typically just em-dash
+         with spaces on either side. [CHAR LIMIT=3] -->
+    <string name="kg_text_message_separator" product="default">" \u2014 "</string>
+    <!-- The delete-widget drop target button text -->
+    <string name="kg_reordering_delete_drop_target_text">Remove</string>
+
+    <!-- Transport control strings -->
+    <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
+    <string name="keyguard_transport_prev_description">Previous track button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button goes to next track. -->
+    <string name="keyguard_transport_next_description">Next track button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
+    <string name="keyguard_transport_pause_description">Pause button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
+    <string name="keyguard_transport_play_description">Play button</string>
+    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
+    <string name="keyguard_transport_stop_description">Stop button</string>
+
+    <!-- On the keyguard screen, it shows the carrier the phone is connected to.
+        This is displayed if the phone is not connected to a carrier.-->
+    <string name="keyguard_carrier_default">No service.</string>
+
+</resources>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
new file mode 100644
index 0000000..a31f708
--- /dev/null
+++ b/packages/Keyguard/res/values/styles.xml
@@ -0,0 +1,56 @@
+<?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.
+*/
+-->
+
+<resources>
+    <!-- Keyguard PIN pad styles -->
+    <style name="Widget.Button.NumPadKey"
+            parent="@android:style/Widget.Button">
+        <item name="android:singleLine">true</item>
+        <item name="android:gravity">left|center_vertical</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:textSize">34dp</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffff</item>
+        <item name="android:paddingTop">6dp</item>
+        <item name="android:paddingBottom">8dp</item>
+        <item name="android:paddingLeft">20dp</item>
+        <item name="android:paddingRight">6dp</item>
+    </style>
+    <style name="TextAppearance.NumPadKey"
+            parent="@android:style/TextAppearance">
+        <item name="android:textSize">34dp</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffff</item>
+    </style>
+    <style name="TextAppearance.NumPadKey.Klondike">
+        <item name="android:textSize">20dp</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#80ffffff</item>
+    </style>
+
+    <!-- Standard animations for a non-full-screen window or activity. -->
+    <style name="Animation.LockScreen" parent="@android:style/Animation">
+        <item name="android:windowEnterAnimation">@anim/lock_screen_enter</item>
+        <item name="android:windowExitAnimation">@anim/lock_screen_exit</item>
+    </style>
+
+</resources>
diff --git a/packages/Keyguard/scripts/copy_profile_icons.sh b/packages/Keyguard/scripts/copy_profile_icons.sh
new file mode 100755
index 0000000..5416101
--- /dev/null
+++ b/packages/Keyguard/scripts/copy_profile_icons.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+for user in `adb $* shell ls /data/system/users | grep -v xml`
+do
+  user=${user/$'\r'/}
+  adb shell mkdir /data/user/${user}/users
+  for photo in `adb $* shell ls /data/system/users | grep -v xml`
+  do
+    photo=${photo/$'\r'/}
+    adb shell mkdir /data/user/${user}/users/${photo}
+    adb pull /data/system/users/${photo}/photo.png
+    adb push photo.png /data/user/${user}/users/${photo}
+  done
+done
diff --git a/packages/Keyguard/scripts/new_merge.py b/packages/Keyguard/scripts/new_merge.py
new file mode 100755
index 0000000..70fafec
--- /dev/null
+++ b/packages/Keyguard/scripts/new_merge.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import difflib
+import filecmp
+import tempfile
+from optparse import OptionParser
+from subprocess import call
+from subprocess import Popen
+from subprocess import PIPE
+
+def which(program):
+    def executable(path):
+        return os.path.isfile(path) and os.access(path, os.X_OK)
+
+    path, file = os.path.split(program)
+    if path and executable(program):
+		return program
+    else:
+        for path in os.environ["PATH"].split(os.pathsep):
+            exe = os.path.join(path, program)
+            if executable(exe):
+                return exe
+    return ""
+
+DIFF_TOOLS=["meld", "kdiff3", "xdiff", "diffmerge.sh", "diff"]
+
+PROTO_SRC="./src/com/android/keyguard/"
+PROTO_RES="./res/"
+
+TEMP_FILE1="/tmp/tempFile1.txt"
+TEMP_FILE2="/tmp/tempFile2.txt"
+
+FW_SRC="../../../../frameworks/base/policy/src/com/android/internal/policy/impl/keyguard/"
+FW_RES="../../../../frameworks/base/core/res/res/"
+
+FW_PKG="com.android.internal.policy.impl.keyguard"
+PROTO_PKG="com.android.keyguard"
+
+FW_RES_IMPORT="import com.android.internal.R;"
+
+# Find a differ
+DIFF_TOOL=""
+if ("DIFF_TOOL" in os.environ and len(os.environ["DIFF_TOOL"]) > 0):
+	DIFF_TOOL=which(os.environ["DIFF_TOOL"])
+if len(DIFF_TOOL) == 0:
+	for differ in DIFF_TOOLS:
+		DIFF_TOOL=which(differ)
+		if len(DIFF_TOOL) > 0:
+			break
+
+print "Using differ", DIFF_TOOL
+
+#Anything file which contains any string in this list as a substring will be ommitted
+IGNORE=["LockHotnessActivity.java", "unified_lock_activity.xml", "optionmenu.xml"]
+WATCH=[]
+
+def dirCompare(sourceDir, destDir, ext, run_in_reverse):
+	sourceFiles = getFileList(sourceDir, ext)
+	destFiles = getFileList(destDir, ext)
+	for file in sourceFiles:
+		print file
+		destFile = destDir + file
+		sourceFile = sourceDir + file
+		if (file in destFiles):
+			if run_in_reverse:
+				prepareFileForCompare(sourceFile, TEMP_FILE1, FW_RES_IMPORT, FW_PKG, PROTO_PKG)
+				prepareFileForCompare(destFile, TEMP_FILE2, FW_RES_IMPORT,)
+			else:
+				prepareFileForCompare(destFile, TEMP_FILE1, FW_RES_IMPORT, FW_PKG, PROTO_PKG)
+				prepareFileForCompare(sourceFile, TEMP_FILE2, FW_RES_IMPORT,)
+			if (filecmp.cmp(TEMP_FILE1, TEMP_FILE2)):
+				print "File %s is the same in proto and framework" %(file)
+			else:
+				print "Running diff for: %s" %(file)
+				diff(sourceFile, destFile)
+		else:
+			print "File %s does not exist in framework" %(file)
+			if not run_in_reverse:
+				diff(sourceFile, destFile)
+
+def main(argv):
+	run_in_reverse = False
+	if len(argv) > 1:
+		if argv[1] == '--help' or argv[1] == '-h':
+			print ('Usage: %s [<commit>]' % argv[0])
+			print ('\tdiff to framework, ' +
+					'optionally restricting to files in <commit>')
+			sys.exit(0)
+		elif argv[1] == '--reverse':
+			print "Running in reverse"
+			run_in_reverse = True
+		else:
+			print ("**** Pulling file list from: %s" % argv[1])
+			pipe = Popen(['git', 'diff', '--name-only',  argv[1]], stdout=PIPE).stdout
+			for line in iter(pipe.readline,''):
+				path = line.rstrip()
+				file = path[path.rfind('/') + 1:]
+				print '**** watching: %s' % file
+				WATCH.append(file);
+			pipe.close()
+
+	if run_in_reverse:
+		#dirCompare(FW_RES, PROTO_RES, ".xml", run_in_reverse)
+		print ("**** Source files:")
+		dirCompare(FW_SRC, PROTO_SRC, ".java", run_in_reverse)
+	else:
+		#dirCompare(PROTO_RES, FW_RES, ".xml", run_in_reverse)
+		print ("**** Source files:")
+		dirCompare(PROTO_SRC, FW_SRC, ".java", run_in_reverse)
+
+	if (os.path.exists(TEMP_FILE1)):
+		os.remove(TEMP_FILE1)
+
+	if (os.path.exists(TEMP_FILE2)):
+		os.remove(TEMP_FILE2)
+
+def getFileList(rootdir, extension):
+	fileList = []
+
+	for root, subFolders, files in os.walk(rootdir):
+	    for file in files:
+	        f = os.path.join(root,file)
+	        if (os.path.splitext(f)[1] == extension and (not inIgnore(f))):
+	        	fileList.append(f[len(rootdir):])
+	return fileList
+
+
+def prepareFileForCompare(inFile, outFile, skip="", replace="", withText=""):
+	# Delete the outfile, so we're starting with a new file
+	if (os.path.exists(outFile)):
+		os.remove(outFile)
+
+	fin = open(inFile)
+	fout = open(outFile, "w")
+	for line in fin:
+		# Ignore any lines containing the ignore string ("import com.android.internal.R;) and
+		# ignore any lines containing only whitespace.
+		if (line.find(skip) < 0  and len(line.strip(' \t\n\r')) > 0):
+			# For comparison, for framework files, we replace the fw package with the
+			# proto package, since these aren't relevant.
+			if len(replace) > 0:
+				fout.write(line.replace(replace, withText))
+			else:
+				fout.write(line)
+	fin.close()
+	fout.close()
+
+def diff(file1, file2):
+	call([DIFF_TOOL, file1, file2])
+
+def inIgnore(file):
+	for ignore in IGNORE:
+		if file.find(ignore) >= 0:
+			return True
+        if len(WATCH) > 0:
+            for watch in WATCH:
+		if file.find(watch) >= 0:
+                    return False
+            return True
+	return False
+
+if __name__=="__main__":
+  main(sys.argv)
diff --git a/packages/Keyguard/src/com/android/keyguard/BiometricSensorUnlock.java b/packages/Keyguard/src/com/android/keyguard/BiometricSensorUnlock.java
new file mode 100644
index 0000000..230ef81
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/BiometricSensorUnlock.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.view.View;
+
+interface BiometricSensorUnlock {
+    /**
+     * Initializes the view provided for the biometric unlock UI to work within.  The provided area
+     * completely covers the backup unlock mechanism.
+     * @param biometricUnlockView View provided for the biometric unlock UI.
+     */
+    public void initializeView(View biometricUnlockView);
+
+    /**
+     * Indicates whether the biometric unlock is running.  Before
+     * {@link BiometricSensorUnlock#start} is called, isRunning() returns false.  After a successful
+     * call to {@link BiometricSensorUnlock#start}, isRunning() returns true until the biometric
+     * unlock completes, {@link BiometricSensorUnlock#stop} has been called, or an error has
+     * forced the biometric unlock to stop.
+     * @return whether the biometric unlock is currently running.
+     */
+    public boolean isRunning();
+
+    /**
+     * Stops and removes the biometric unlock and shows the backup unlock
+     */
+    public void stopAndShowBackup();
+
+    /**
+     * Binds to the biometric unlock service and starts the unlock procedure.  Called on the UI
+     * thread.
+     * @return false if it can't be started or the backup should be used.
+     */
+    public boolean start();
+
+    /**
+     * Stops the biometric unlock procedure and unbinds from the service.  Called on the UI thread.
+     * @return whether the biometric unlock was running when called.
+     */
+    public boolean stop();
+
+    /**
+     * Cleans up any resources used by the biometric unlock.
+     */
+    public void cleanUp();
+
+    /**
+     * Gets the Device Policy Manager quality of the biometric unlock sensor
+     * (e.g., PASSWORD_QUALITY_BIOMETRIC_WEAK).
+     * @return biometric unlock sensor quality, as defined by Device Policy Manager.
+     */
+    public int getQuality();
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
new file mode 100644
index 0000000..146c092
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+
+import com.android.keyguard.KeyguardActivityLauncher.CameraWidgetInfo;
+
+public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
+    private static final String TAG = CameraWidgetFrame.class.getSimpleName();
+    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+    private static final int WIDGET_ANIMATION_DURATION = 250; // ms
+    private static final int WIDGET_WAIT_DURATION = 650; // ms
+    private static final int RECOVERY_DELAY = 1000; // ms
+
+    interface Callbacks {
+        void onLaunchingCamera();
+        void onCameraLaunchedSuccessfully();
+        void onCameraLaunchedUnsuccessfully();
+    }
+
+    private final Handler mHandler = new Handler();
+    private final KeyguardActivityLauncher mActivityLauncher;
+    private final Callbacks mCallbacks;
+    private final CameraWidgetInfo mWidgetInfo;
+    private final WindowManager mWindowManager;
+    private final Point mRenderedSize = new Point();
+    private final int[] mTmpLoc = new int[2];
+    private final Rect mTmpRect = new Rect();
+
+    private long mLaunchCameraStart;
+    private boolean mActive;
+    private boolean mTransitioning;
+    private boolean mDown;
+
+    private FixedSizeFrameLayout mPreview;
+    private View mFullscreenPreview;
+
+    private final Runnable mTransitionToCameraRunnable = new Runnable() {
+        @Override
+        public void run() {
+            transitionToCamera();
+        }};
+
+    private final Runnable mTransitionToCameraEndAction = new Runnable() {
+        @Override
+        public void run() {
+            if (!mTransitioning)
+                return;
+            Handler worker =  getWorkerHandler() != null ? getWorkerHandler() : mHandler;
+            mLaunchCameraStart = SystemClock.uptimeMillis();
+            if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart);
+            mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
+        }};
+
+    private final Runnable mPostTransitionToCameraEndAction = new Runnable() {
+        @Override
+        public void run() {
+            mHandler.post(mTransitionToCameraEndAction);
+        }};
+
+    private final Runnable mRecoverRunnable = new Runnable() {
+        @Override
+        public void run() {
+            recover();
+        }};
+
+    private final Runnable mRenderRunnable = new Runnable() {
+        @Override
+        public void run() {
+            render();
+        }};
+
+    private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() {
+        @Override
+        public void run() {
+            onSecureCameraActivityStarted();
+        }
+    };
+
+    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+        private boolean mShowing;
+        void onKeyguardVisibilityChanged(boolean showing) {
+            if (mShowing == showing)
+                return;
+            mShowing = showing;
+            CameraWidgetFrame.this.onKeyguardVisibilityChanged(mShowing);
+        };
+    };
+
+    private static final class FixedSizeFrameLayout extends FrameLayout {
+        int width;
+        int height;
+
+        FixedSizeFrameLayout(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            measureChildren(
+                    MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            setMeasuredDimension(width, height);
+        }
+    }
+
+    private CameraWidgetFrame(Context context, Callbacks callbacks,
+            KeyguardActivityLauncher activityLauncher,
+            CameraWidgetInfo widgetInfo, View previewWidget) {
+        super(context);
+        mCallbacks = callbacks;
+        mActivityLauncher = activityLauncher;
+        mWidgetInfo = widgetInfo;
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback);
+
+        mPreview = new FixedSizeFrameLayout(context);
+        mPreview.addView(previewWidget);
+        addView(mPreview);
+
+        View clickBlocker = new View(context);
+        clickBlocker.setBackgroundColor(Color.TRANSPARENT);
+        clickBlocker.setOnClickListener(this);
+        addView(clickBlocker);
+
+        setContentDescription(context.getString(R.string.keyguard_accessibility_camera));
+        if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId());
+    }
+
+    public static CameraWidgetFrame create(Context context, Callbacks callbacks,
+            KeyguardActivityLauncher launcher) {
+        if (context == null || callbacks == null || launcher == null)
+            return null;
+
+        CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo();
+        if (widgetInfo == null)
+            return null;
+        View previewWidget = getPreviewWidget(context, widgetInfo);
+        if (previewWidget == null)
+            return null;
+
+        return new CameraWidgetFrame(context, callbacks, launcher, widgetInfo, previewWidget);
+    }
+
+    private static View getPreviewWidget(Context context, CameraWidgetInfo widgetInfo) {
+        return widgetInfo.layoutId > 0 ?
+                inflateWidgetView(context, widgetInfo) :
+                inflateGenericWidgetView(context);
+    }
+
+    private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) {
+        if (DEBUG) Log.d(TAG, "inflateWidgetView: " + widgetInfo.contextPackage);
+        View widgetView = null;
+        Exception exception = null;
+        try {
+            Context cameraContext = context.createPackageContext(
+                    widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
+            LayoutInflater cameraInflater = (LayoutInflater)
+                    cameraContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            cameraInflater = cameraInflater.cloneInContext(cameraContext);
+            widgetView = cameraInflater.inflate(widgetInfo.layoutId, null, false);
+        } catch (NameNotFoundException e) {
+            exception = e;
+        } catch (RuntimeException e) {
+            exception = e;
+        }
+        if (exception != null) {
+            Log.w(TAG, "Error creating camera widget view", exception);
+        }
+        return widgetView;
+    }
+
+    private static View inflateGenericWidgetView(Context context) {
+        if (DEBUG) Log.d(TAG, "inflateGenericWidgetView");
+        ImageView iv = new ImageView(context);
+        iv.setImageResource(R.drawable.ic_lockscreen_camera);
+        iv.setScaleType(ScaleType.CENTER);
+        iv.setBackgroundColor(Color.argb(127, 0, 0, 0));
+        return iv;
+    }
+
+    private void render() {
+        final View root = getRootView();
+        final int width = root.getWidth();
+        final int height = root.getHeight();
+        if (mRenderedSize.x == width && mRenderedSize.y == height) {
+            if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", width, height));
+            return;
+        }
+        if (width == 0 || height == 0) {
+            return;
+        }
+
+        mPreview.width = width;
+        mPreview.height = height;
+        mPreview.requestLayout();
+
+        final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight();
+        final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom();
+
+        final float pvScaleX = (float) thisWidth / width;
+        final float pvScaleY = (float) thisHeight / height;
+        final float pvScale = Math.min(pvScaleX, pvScaleY);
+
+        final int pvWidth = (int) (pvScale * width);
+        final int pvHeight = (int) (pvScale * height);
+
+        final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0;
+        final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0;
+
+        mPreview.setPivotX(0);
+        mPreview.setPivotY(0);
+        mPreview.setScaleX(pvScale);
+        mPreview.setScaleY(pvScale);
+        mPreview.setTranslationX(pvTransX);
+        mPreview.setTranslationY(pvTransY);
+
+        mRenderedSize.set(width, height);
+        if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s",
+                width, height, instanceId()));
+    }
+
+    private void transitionToCamera() {
+        if (mTransitioning || mDown) return;
+
+        mTransitioning = true;
+
+        enableWindowExitAnimation(false);
+
+        mPreview.getLocationInWindow(mTmpLoc);
+        final float pvHeight = mPreview.getHeight() * mPreview.getScaleY();
+        final float pvCenter = mTmpLoc[1] + pvHeight / 2f;
+
+        final ViewGroup root = (ViewGroup) getRootView();
+        if (mFullscreenPreview == null) {
+            mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo);
+            mFullscreenPreview.setClickable(false);
+            root.addView(mFullscreenPreview);
+        }
+
+        root.getWindowVisibleDisplayFrame(mTmpRect);
+        final float fsHeight = mTmpRect.height();
+        final float fsCenter = mTmpRect.top + fsHeight / 2;
+
+        final float fsScaleY = pvHeight / fsHeight;
+        final float fsTransY = pvCenter - fsCenter;
+        final float fsScaleX = mPreview.getScaleX();
+
+        mPreview.setVisibility(View.GONE);
+        mFullscreenPreview.setVisibility(View.VISIBLE);
+        mFullscreenPreview.setTranslationY(fsTransY);
+        mFullscreenPreview.setScaleX(fsScaleX);
+        mFullscreenPreview.setScaleY(fsScaleY);
+        mFullscreenPreview
+            .animate()
+            .scaleX(1)
+            .scaleY(1)
+            .translationX(0)
+            .translationY(0)
+            .setDuration(WIDGET_ANIMATION_DURATION)
+            .withEndAction(mPostTransitionToCameraEndAction)
+            .start();
+        mCallbacks.onLaunchingCamera();
+    }
+
+    private void recover() {
+        if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
+        mCallbacks.onCameraLaunchedUnsuccessfully();
+        reset();
+    }
+
+    @Override
+    public void setOnLongClickListener(OnLongClickListener l) {
+        // ignore
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (DEBUG) Log.d(TAG, "clicked");
+        if (mTransitioning) return;
+        if (mActive) {
+            cancelTransitionToCamera();
+            transitionToCamera();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (DEBUG) Log.d(TAG, "onDetachedFromWindow: instance " + instanceId()
+                + " at " + SystemClock.uptimeMillis());
+        super.onDetachedFromWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
+        cancelTransitionToCamera();
+        mHandler.removeCallbacks(mRecoverRunnable);
+    }
+
+    @Override
+    public void onActive(boolean isActive) {
+        mActive = isActive;
+        if (mActive) {
+            rescheduleTransitionToCamera();
+        } else {
+            reset();
+        }
+    }
+
+    @Override
+    public boolean onUserInteraction(MotionEvent event) {
+        if (mTransitioning) {
+            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning");
+            return true;
+        }
+
+        getLocationOnScreen(mTmpLoc);
+        int rawBottom = mTmpLoc[1] + getHeight();
+        if (event.getRawY() > rawBottom) {
+            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
+            return true;
+        }
+
+        int action = event.getAction();
+        mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE;
+        if (mActive) {
+            rescheduleTransitionToCamera();
+        }
+        if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten");
+        return false;
+    }
+
+    @Override
+    protected void onFocusLost() {
+        if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis());
+        cancelTransitionToCamera();
+        super.onFocusLost();
+    }
+
+    public void onScreenTurnedOff() {
+        if (DEBUG) Log.d(TAG, "onScreenTurnedOff");
+        reset();
+    }
+
+    private void rescheduleTransitionToCamera() {
+        if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis());
+        mHandler.removeCallbacks(mTransitionToCameraRunnable);
+        mHandler.postDelayed(mTransitionToCameraRunnable, WIDGET_WAIT_DURATION);
+    }
+
+    private void cancelTransitionToCamera() {
+        if (DEBUG) Log.d(TAG, "cancelTransitionToCamera at " + SystemClock.uptimeMillis());
+        mHandler.removeCallbacks(mTransitionToCameraRunnable);
+    }
+
+    private void onCameraLaunched() {
+        mCallbacks.onCameraLaunchedSuccessfully();
+        reset();
+    }
+
+    private void reset() {
+        if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
+        mLaunchCameraStart = 0;
+        mTransitioning = false;
+        mDown = false;
+        cancelTransitionToCamera();
+        mHandler.removeCallbacks(mRecoverRunnable);
+        mPreview.setVisibility(View.VISIBLE);
+        if (mFullscreenPreview != null) {
+            mFullscreenPreview.animate().cancel();
+            mFullscreenPreview.setVisibility(View.GONE);
+        }
+        enableWindowExitAnimation(true);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
+                w, h, oldw, oldh, SystemClock.uptimeMillis()));
+        mHandler.post(mRenderRunnable);
+        super.onSizeChanged(w, h, oldw, oldh);
+    }
+
+    @Override
+    public void onBouncerShowing(boolean showing) {
+        if (showing) {
+            mTransitioning = false;
+            mHandler.post(mRecoverRunnable);
+        }
+    }
+
+    private void enableWindowExitAnimation(boolean isEnabled) {
+        View root = getRootView();
+        ViewGroup.LayoutParams lp = root.getLayoutParams();
+        if (!(lp instanceof WindowManager.LayoutParams))
+            return;
+        WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
+        int newWindowAnimations = isEnabled ? R.style.Animation_LockScreen : 0;
+        if (newWindowAnimations != wlp.windowAnimations) {
+            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations
+                    + " at " + SystemClock.uptimeMillis());
+            wlp.windowAnimations = newWindowAnimations;
+            mWindowManager.updateViewLayout(root, wlp);
+        }
+    }
+
+    private void onKeyguardVisibilityChanged(boolean showing) {
+        if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing
+                + " at " + SystemClock.uptimeMillis());
+        if (mTransitioning && !showing) {
+            mTransitioning = false;
+            mHandler.removeCallbacks(mRecoverRunnable);
+            if (mLaunchCameraStart > 0) {
+                long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
+                if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
+                mLaunchCameraStart = 0;
+                onCameraLaunched();
+            }
+        }
+    }
+
+    private void onSecureCameraActivityStarted() {
+        if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis());
+        mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY);
+    }
+
+    private String instanceId() {
+        return Integer.toHexString(hashCode());
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
new file mode 100644
index 0000000..03b09b1
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.widget.LockPatternUtils;
+
+public class CarrierText extends TextView {
+    private static CharSequence mSeparator;
+
+    private LockPatternUtils mLockPatternUtils;
+
+    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+        private CharSequence mPlmn;
+        private CharSequence mSpn;
+        private State mSimState;
+
+        @Override
+        public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+            mPlmn = plmn;
+            mSpn = spn;
+            updateCarrierText(mSimState, mPlmn, mSpn);
+        }
+
+        @Override
+        public void onSimStateChanged(IccCardConstants.State simState) {
+            mSimState = simState;
+            updateCarrierText(mSimState, mPlmn, mSpn);
+        }
+    };
+    /**
+     * The status of this lock screen. Primarily used for widgets on LockScreen.
+     */
+    private static enum StatusMode {
+        Normal, // Normal case (sim card present, it's not locked)
+        NetworkLocked, // SIM card is 'network locked'.
+        SimMissing, // SIM card is missing.
+        SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
+        SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
+        SimLocked, // SIM card is currently locked
+        SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
+        SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
+    }
+
+    public CarrierText(Context context) {
+        this(context, null);
+    }
+
+    public CarrierText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLockPatternUtils = new LockPatternUtils(mContext);
+    }
+
+    protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
+        setText(getCarrierTextForSimState(simState, plmn, spn));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mSeparator = getResources().getString(R.string.kg_text_message_separator);
+        setSelected(true); // Allow marquee to work.
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
+    }
+
+    /**
+     * Top-level function for creating carrier text. Makes text based on simState, PLMN
+     * and SPN as well as device capabilities, such as being emergency call capable.
+     *
+     * @param simState
+     * @param plmn
+     * @param spn
+     * @return
+     */
+    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
+            CharSequence plmn, CharSequence spn) {
+        CharSequence carrierText = null;
+        StatusMode status = getStatusForIccState(simState);
+        switch (status) {
+            case Normal:
+                carrierText = concatenate(plmn, spn);
+                break;
+
+            case SimNotReady:
+                carrierText = null; // nothing to display yet.
+                break;
+
+            case NetworkLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        mContext.getText(R.string.keyguard_network_locked_message), plmn);
+                break;
+
+            case SimMissing:
+                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
+                // This depends on mPlmn containing the text "Emergency calls only" when the radio
+                // has some connectivity. Otherwise, it should be null or empty and just show
+                // "No SIM card"
+                carrierText =  makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_missing_sim_message_short),
+                        plmn);
+                break;
+
+            case SimPermDisabled:
+                carrierText = getContext().getText(
+                        R.string.keyguard_permanent_disabled_sim_message_short);
+                break;
+
+            case SimMissingLocked:
+                carrierText =  makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_missing_sim_message_short),
+                        plmn);
+                break;
+
+            case SimLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_sim_locked_message),
+                        plmn);
+                break;
+
+            case SimPukLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_sim_puk_locked_message),
+                        plmn);
+                break;
+        }
+
+        return carrierText;
+    }
+
+    /*
+     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
+     */
+    private CharSequence makeCarrierStringOnEmergencyCapable(
+            CharSequence simMessage, CharSequence emergencyCallMessage) {
+        if (mLockPatternUtils.isEmergencyCallCapable()) {
+            return concatenate(simMessage, emergencyCallMessage);
+        }
+        return simMessage;
+    }
+
+    /**
+     * Determine the current status of the lock screen given the SIM state and other stuff.
+     */
+    private StatusMode getStatusForIccState(IccCardConstants.State simState) {
+        // Since reading the SIM may take a while, we assume it is present until told otherwise.
+        if (simState == null) {
+            return StatusMode.Normal;
+        }
+
+        final boolean missingAndNotProvisioned =
+                !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
+                && (simState == IccCardConstants.State.ABSENT ||
+                        simState == IccCardConstants.State.PERM_DISABLED);
+
+        // Assume we're NETWORK_LOCKED if not provisioned
+        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
+        switch (simState) {
+            case ABSENT:
+                return StatusMode.SimMissing;
+            case NETWORK_LOCKED:
+                return StatusMode.SimMissingLocked;
+            case NOT_READY:
+                return StatusMode.SimNotReady;
+            case PIN_REQUIRED:
+                return StatusMode.SimLocked;
+            case PUK_REQUIRED:
+                return StatusMode.SimPukLocked;
+            case READY:
+                return StatusMode.Normal;
+            case PERM_DISABLED:
+                return StatusMode.SimPermDisabled;
+            case UNKNOWN:
+                return StatusMode.SimMissing;
+        }
+        return StatusMode.SimMissing;
+    }
+
+    private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
+        final boolean plmnValid = !TextUtils.isEmpty(plmn);
+        final boolean spnValid = !TextUtils.isEmpty(spn);
+        if (plmnValid && spnValid) {
+            return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
+        } else if (plmnValid) {
+            return plmn;
+        } else if (spnValid) {
+            return spn;
+        } else {
+            return "";
+        }
+    }
+
+    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
+            String plmn, String spn) {
+        int carrierHelpTextId = 0;
+        StatusMode status = getStatusForIccState(simState);
+        switch (status) {
+            case NetworkLocked:
+                carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
+                break;
+
+            case SimMissing:
+                carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
+                break;
+
+            case SimPermDisabled:
+                carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
+                break;
+
+            case SimMissingLocked:
+                carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
+                break;
+
+            case Normal:
+            case SimLocked:
+            case SimPukLocked:
+                break;
+        }
+
+        return mContext.getText(carrierHelpTextId);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
new file mode 100644
index 0000000..677f1f1
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+/**
+ * Interface implemented by ViewGroup-derived layouts that implement
+ * special logic for presenting security challenges to the user.
+ */
+public interface ChallengeLayout {
+    /**
+     * @return true if the security challenge area of this layout is currently visible
+     */
+    boolean isChallengeShowing();
+
+    /**
+     * @return true if the challenge area significantly overlaps other content
+     */
+    boolean isChallengeOverlapping();
+
+    /**
+     * Show or hide the challenge layout.
+     *
+     * If you want to show the challenge layout in bouncer mode where applicable,
+     * use {@link #showBouncer()} instead.
+     *
+     * @param b true to show, false to hide
+     */
+    void showChallenge(boolean b);
+
+    /**
+     * Show the bouncer challenge. This may block access to other child views.
+     */
+    void showBouncer();
+
+    /**
+     * Hide the bouncer challenge if it is currently showing.
+     * This may restore previously blocked access to other child views.
+     */
+    void hideBouncer();
+
+    /**
+     * Returns true if the challenge is currently in bouncer mode,
+     * potentially blocking access to other child views.
+     */
+    boolean isBouncing();
+
+    /**
+     * Returns the duration of the bounce animation.
+     */
+    int getBouncerAnimationDuration();
+
+    /**
+     * Set a listener that will respond to changes in bouncer state.
+     *
+     * @param listener listener to register
+     */
+    void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener);
+
+    /**
+     * Listener interface that reports changes in bouncer state.
+     * The bouncer is
+     */
+    public interface OnBouncerStateChangedListener {
+        /**
+         * Called when the bouncer state changes.
+         * The bouncer is activated when the user must pass a security challenge
+         * to proceed with the requested action.
+         *
+         * <p>This differs from simply showing or hiding the security challenge
+         * as the bouncer will prevent interaction with other elements of the UI.
+         * If the user attempts to escape from the bouncer, it will be dismissed,
+         * this method will be called with false as the parameter, and the action
+         * should be canceled. If the security component reports a successful
+         * authentication and the containing code calls hideBouncer() as a result,
+         * this method will also be called with a false parameter. It is up to the
+         * caller of hideBouncer to be ready for this.</p>
+         *
+         * @param bouncerActive true if the bouncer is now active,
+         *                      false if the bouncer was dismissed.
+         */
+        public void onBouncerStateChanged(boolean bouncerActive);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/CheckLongPressHelper.java b/packages/Keyguard/src/com/android/keyguard/CheckLongPressHelper.java
new file mode 100644
index 0000000..52e7cd5
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/CheckLongPressHelper.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public class CheckLongPressHelper {
+    private View mView;
+    private boolean mHasPerformedLongPress;
+    private CheckForLongPress mPendingCheckForLongPress;
+    private float mDownX, mDownY;
+    private int mLongPressTimeout;
+    private int mScaledTouchSlop;
+
+    class CheckForLongPress implements Runnable {
+        public void run() {
+            if ((mView.getParent() != null) && mView.hasWindowFocus()
+                    && !mHasPerformedLongPress) {
+                if (mView.performLongClick()) {
+                    mView.setPressed(false);
+                    mHasPerformedLongPress = true;
+                }
+            }
+        }
+    }
+
+    public CheckLongPressHelper(View v) {
+        mScaledTouchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
+        mView = v;
+    }
+
+    public void postCheckForLongPress(MotionEvent ev) {
+        mDownX = ev.getX();
+        mDownY = ev.getY();
+        mHasPerformedLongPress = false;
+
+        if (mPendingCheckForLongPress == null) {
+            mPendingCheckForLongPress = new CheckForLongPress();
+        }
+        mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout);
+    }
+
+    public void onMove(MotionEvent ev) {
+        float x = ev.getX();
+        float y = ev.getY();
+        boolean xMoved = Math.abs(mDownX - x) > mScaledTouchSlop;
+        boolean yMoved = Math.abs(mDownY - y) > mScaledTouchSlop;
+
+        if (xMoved || yMoved) {
+            cancelLongPress();
+        }
+    }
+
+    public void cancelLongPress() {
+        mHasPerformedLongPress = false;
+        if (mPendingCheckForLongPress != null) {
+            mView.removeCallbacks(mPendingCheckForLongPress);
+            mPendingCheckForLongPress = null;
+        }
+    }
+
+    public boolean hasPerformedLongPress() {
+        return mHasPerformedLongPress;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/ClockView.java b/packages/Keyguard/src/com/android/keyguard/ClockView.java
new file mode 100644
index 0000000..ad85e9a
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/ClockView.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+import java.text.DateFormatSymbols;
+import java.util.Calendar;
+
+/**
+ * Displays the time
+ */
+public class ClockView extends RelativeLayout {
+    private static final String ANDROID_CLOCK_FONT_FILE = "/system/fonts/AndroidClock.ttf";
+    private final static String M12 = "h:mm";
+    private final static String M24 = "HH:mm";
+
+    private Calendar mCalendar;
+    private String mFormat;
+    private TextView mTimeView;
+    private AmPm mAmPm;
+    private ContentObserver mFormatChangeObserver;
+    private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced
+
+    /* called by system on minute ticks */
+    private final Handler mHandler = new Handler();
+    private BroadcastReceiver mIntentReceiver;
+
+    private static class TimeChangedReceiver extends BroadcastReceiver {
+        private WeakReference<ClockView> mClock;
+        private Context mContext;
+
+        public TimeChangedReceiver(ClockView clock) {
+            mClock = new WeakReference<ClockView>(clock);
+            mContext = clock.getContext();
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Post a runnable to avoid blocking the broadcast.
+            final boolean timezoneChanged =
+                    intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
+            final ClockView clock = mClock.get();
+            if (clock != null) {
+                clock.mHandler.post(new Runnable() {
+                    public void run() {
+                        if (timezoneChanged) {
+                            clock.mCalendar = Calendar.getInstance();
+                        }
+                        clock.updateTime();
+                    }
+                });
+            } else {
+                try {
+                    mContext.unregisterReceiver(this);
+                } catch (RuntimeException e) {
+                    // Shouldn't happen
+                }
+            }
+        }
+    };
+
+    static class AmPm {
+        private TextView mAmPmTextView;
+        private String mAmString, mPmString;
+
+        AmPm(View parent, Typeface tf) {
+            // No longer used, uncomment if we decide to use AM/PM indicator again
+            // mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm);
+            if (mAmPmTextView != null && tf != null) {
+                mAmPmTextView.setTypeface(tf);
+            }
+
+            String[] ampm = new DateFormatSymbols().getAmPmStrings();
+            mAmString = ampm[0];
+            mPmString = ampm[1];
+        }
+
+        void setShowAmPm(boolean show) {
+            if (mAmPmTextView != null) {
+                mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE);
+            }
+        }
+
+        void setIsMorning(boolean isMorning) {
+            if (mAmPmTextView != null) {
+                mAmPmTextView.setText(isMorning ? mAmString : mPmString);
+            }
+        }
+    }
+
+    private static class FormatChangeObserver extends ContentObserver {
+        private WeakReference<ClockView> mClock;
+        private Context mContext;
+        public FormatChangeObserver(ClockView clock) {
+            super(new Handler());
+            mClock = new WeakReference<ClockView>(clock);
+            mContext = clock.getContext();
+        }
+        @Override
+        public void onChange(boolean selfChange) {
+            ClockView digitalClock = mClock.get();
+            if (digitalClock != null) {
+                digitalClock.setDateFormat();
+                digitalClock.updateTime();
+            } else {
+                try {
+                    mContext.getContentResolver().unregisterContentObserver(this);
+                } catch (RuntimeException e) {
+                    // Shouldn't happen
+                }
+            }
+        }
+    }
+
+    public ClockView(Context context) {
+        this(context, null);
+    }
+
+    public ClockView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mTimeView = (TextView) findViewById(R.id.clock_text);
+        mTimeView.setTypeface(Typeface.createFromFile(ANDROID_CLOCK_FONT_FILE));
+        mAmPm = new AmPm(this, null);
+        mCalendar = Calendar.getInstance();
+        setDateFormat();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        mAttached++;
+
+        /* monitor time ticks, time changed, timezone */
+        if (mIntentReceiver == null) {
+            mIntentReceiver = new TimeChangedReceiver(this);
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_TIME_TICK);
+            filter.addAction(Intent.ACTION_TIME_CHANGED);
+            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+            mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.OWNER, filter, null, null );
+        }
+
+        /* monitor 12/24-hour display preference */
+        if (mFormatChangeObserver == null) {
+            mFormatChangeObserver = new FormatChangeObserver(this);
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+        }
+
+        updateTime();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        mAttached--;
+
+        if (mIntentReceiver != null) {
+            mContext.unregisterReceiver(mIntentReceiver);
+        }
+        if (mFormatChangeObserver != null) {
+            mContext.getContentResolver().unregisterContentObserver(
+                    mFormatChangeObserver);
+        }
+
+        mFormatChangeObserver = null;
+        mIntentReceiver = null;
+    }
+
+    void updateTime(Calendar c) {
+        mCalendar = c;
+        updateTime();
+    }
+
+    public void updateTime() {
+        mCalendar.setTimeInMillis(System.currentTimeMillis());
+
+        CharSequence newTime = DateFormat.format(mFormat, mCalendar);
+        mTimeView.setText(newTime);
+        mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0);
+    }
+
+    private void setDateFormat() {
+        mFormat = android.text.format.DateFormat.is24HourFormat(getContext()) ? M24 : M12;
+        mAmPm.setShowAmPm(mFormat.equals(M12));
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
new file mode 100644
index 0000000..fd56613
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -0,0 +1,133 @@
+/*
+ * 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 com.android.keyguard;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.widget.LockPatternUtils;
+
+/**
+ * This class implements a smart emergency button that updates itself based
+ * on telephony state.  When the phone is idle, it is an emergency call button.
+ * When there's a call in progress, it presents an appropriate message and
+ * allows the user to return to the call.
+ */
+public class EmergencyButton extends Button {
+
+    private static final int EMERGENCY_CALL_TIMEOUT = 10000; // screen timeout after starting e.d.
+    private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
+    KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
+
+        @Override
+        public void onSimStateChanged(State simState) {
+            int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState();
+            updateEmergencyCallButton(simState, phoneState);
+        }
+
+        void onPhoneStateChanged(int phoneState) {
+            State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState();
+            updateEmergencyCallButton(simState, phoneState);
+        };
+    };
+    private LockPatternUtils mLockPatternUtils;
+    private PowerManager mPowerManager;
+
+    public EmergencyButton(Context context) {
+        this(context, null);
+    }
+
+    public EmergencyButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mLockPatternUtils = new LockPatternUtils(mContext);
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                takeEmergencyCallAction();
+            }
+        });
+        int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState();
+        State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState();
+        updateEmergencyCallButton(simState, phoneState);
+    }
+
+    /**
+     * Shows the emergency dialer or returns the user to the existing call.
+     */
+    public void takeEmergencyCallAction() {
+        // TODO: implement a shorter timeout once new PowerManager API is ready.
+        // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
+        mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
+        if (TelephonyManager.getDefault().getCallState()
+                == TelephonyManager.CALL_STATE_OFFHOOK) {
+            mLockPatternUtils.resumeCall();
+        } else {
+            final boolean bypassHandler = true;
+            KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
+            Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            getContext().startActivityAsUser(intent,
+                    new UserHandle(mLockPatternUtils.getCurrentUser()));
+        }
+    }
+
+    private void updateEmergencyCallButton(State simState, int phoneState) {
+        boolean enabled = false;
+        if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
+            enabled = true; // always show "return to call" if phone is off-hook
+        } else if (mLockPatternUtils.isEmergencyCallCapable()) {
+            boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimLocked();
+            if (simLocked) {
+                // Some countries can't handle emergency calls while SIM is locked.
+                enabled = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
+            } else {
+                // True if we need to show a secure screen (pin/pattern/SIM pin/SIM puk);
+                // hides emergency button on "Slide" screen if device is not secure.
+                enabled = mLockPatternUtils.isSecure();
+            }
+        }
+        mLockPatternUtils.updateEmergencyCallButtonState(this, phoneState, enabled, false);
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java b/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java
new file mode 100644
index 0000000..6d392fc
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java
@@ -0,0 +1,62 @@
+/*
+ * 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.keyguard;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.keyguard.R;
+
+public class EmergencyCarrierArea extends LinearLayout {
+
+    private CarrierText mCarrierText;
+    private EmergencyButton mEmergencyButton;
+
+    public EmergencyCarrierArea(Context context) {
+        super(context);
+    }
+
+    public EmergencyCarrierArea(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mCarrierText = (CarrierText) findViewById(R.id.carrier_text);
+        mEmergencyButton = (EmergencyButton) findViewById(R.id.emergency_call_button);
+
+        // The emergency button overlaps the carrier text, only noticeable when highlighted.
+        // So temporarily hide the carrier text while the emergency button is pressed.
+        mEmergencyButton.setOnTouchListener(new OnTouchListener(){
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                switch(event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        mCarrierText.animate().alpha(0);
+                        break;
+                    case MotionEvent.ACTION_UP:
+                        mCarrierText.animate().alpha(1);
+                        break;
+                }
+                return false;
+            }});
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
new file mode 100644
index 0000000..689366b
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import com.android.internal.policy.IFaceLockCallback;
+import com.android.internal.policy.IFaceLockInterface;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.View;
+
+public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
+
+    private static final boolean DEBUG = false;
+    private static final String TAG = "FULLockscreen";
+
+    private final Context mContext;
+    private final LockPatternUtils mLockPatternUtils;
+
+    // TODO: is mServiceRunning needed or can we just use mIsRunning or check if mService is null?
+    private boolean mServiceRunning = false;
+    // TODO: now that the code has been restructure to do almost all operations from a handler, this
+    // lock may no longer be necessary.
+    private final Object mServiceRunningLock = new Object();
+    private IFaceLockInterface mService;
+    private boolean mBoundToService = false;
+    private View mFaceUnlockView;
+
+    private Handler mHandler;
+    private final int MSG_SERVICE_CONNECTED = 0;
+    private final int MSG_SERVICE_DISCONNECTED = 1;
+    private final int MSG_UNLOCK = 2;
+    private final int MSG_CANCEL = 3;
+    private final int MSG_REPORT_FAILED_ATTEMPT = 4;
+    private final int MSG_POKE_WAKELOCK = 5;
+
+    // TODO: This was added for the purpose of adhering to what the biometric interface expects
+    // the isRunning() function to return.  However, it is probably not necessary to have both
+    // mRunning and mServiceRunning.  I'd just rather wait to change that logic.
+    private volatile boolean mIsRunning = false;
+
+    // So the user has a consistent amount of time when brought to the backup method from Face
+    // Unlock
+    private final int BACKUP_LOCK_TIMEOUT = 5000;
+
+    KeyguardSecurityCallback mKeyguardScreenCallback;
+
+    /**
+     * Stores some of the structures that Face Unlock will need to access and creates the handler
+     * will be used to execute messages on the UI thread.
+     */
+    public FaceUnlock(Context context) {
+        mContext = context;
+        mLockPatternUtils = new LockPatternUtils(context);
+        mHandler = new Handler(this);
+    }
+
+    public void setKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback) {
+        mKeyguardScreenCallback = keyguardScreenCallback;
+    }
+
+    /**
+     * Stores and displays the view that Face Unlock is allowed to draw within.
+     * TODO: since the layout object will eventually be shared by multiple biometric unlock
+     * methods, we will have to add our other views (background, cancel button) here.
+     */
+    public void initializeView(View biometricUnlockView) {
+        Log.d(TAG, "initializeView()");
+        mFaceUnlockView = biometricUnlockView;
+    }
+
+    /**
+     * Indicates whether Face Unlock is currently running.
+     */
+    public boolean isRunning() {
+        return mIsRunning;
+    }
+
+    /**
+     * Dismisses face unlock and goes to the backup lock
+     */
+    public void stopAndShowBackup() {
+        if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
+        mHandler.sendEmptyMessage(MSG_CANCEL);
+    }
+
+    /**
+     * Binds to the Face Unlock service.  Face Unlock will be started when the bind completes.  The
+     * Face Unlock view is displayed to hide the backup lock while the service is starting up.
+     * Called on the UI thread.
+     */
+    public boolean start() {
+        if (DEBUG) Log.d(TAG, "start()");
+        if (mHandler.getLooper() != Looper.myLooper()) {
+            Log.e(TAG, "start() called off of the UI thread");
+        }
+
+        if (mIsRunning) {
+            Log.w(TAG, "start() called when already running");
+        }
+
+        if (!mBoundToService) {
+            Log.d(TAG, "Binding to Face Unlock service for user="
+                    + mLockPatternUtils.getCurrentUser());
+            mContext.bindServiceAsUser(new Intent(IFaceLockInterface.class.getName()),
+                    mConnection,
+                    Context.BIND_AUTO_CREATE,
+                    new UserHandle(mLockPatternUtils.getCurrentUser()));
+            mBoundToService = true;
+        } else {
+            Log.w(TAG, "Attempt to bind to Face Unlock when already bound");
+        }
+
+        mIsRunning = true;
+        return true;
+    }
+
+    /**
+     * Stops Face Unlock and unbinds from the service.  Called on the UI thread.
+     */
+    public boolean stop() {
+        if (DEBUG) Log.d(TAG, "stop()");
+        if (mHandler.getLooper() != Looper.myLooper()) {
+            Log.e(TAG, "stop() called from non-UI thread");
+        }
+
+        // Clearing any old service connected messages.
+        mHandler.removeMessages(MSG_SERVICE_CONNECTED);
+
+        boolean mWasRunning = mIsRunning;
+
+        stopUi();
+
+        if (mBoundToService) {
+            if (mService != null) {
+                try {
+                    mService.unregisterCallback(mFaceUnlockCallback);
+                } catch (RemoteException e) {
+                    // Not much we can do
+                }
+            }
+            Log.d(TAG, "Unbinding from Face Unlock service");
+            mContext.unbindService(mConnection);
+            mBoundToService = false;
+        } else {
+            // This is usually not an error when this happens.  Sometimes we will tell it to
+            // unbind multiple times because it's called from both onWindowFocusChanged and
+            // onDetachedFromWindow.
+            if (DEBUG) Log.d(TAG, "Attempt to unbind from Face Unlock when not bound");
+        }
+        mIsRunning = false;
+        return mWasRunning;
+    }
+
+    /**
+     * Frees up resources used by Face Unlock and stops it if it is still running.
+     */
+    public void cleanUp() {
+        if (DEBUG) Log.d(TAG, "cleanUp()");
+        if (mService != null) {
+            try {
+                mService.unregisterCallback(mFaceUnlockCallback);
+            } catch (RemoteException e) {
+                // Not much we can do
+            }
+            stopUi();
+            mService = null;
+        }
+    }
+
+    /**
+     * Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK.
+     */
+    public int getQuality() {
+        return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+    }
+
+    /**
+     * Handles messages such that everything happens on the UI thread in a deterministic order.
+     * Calls from the Face Unlock service come from binder threads.  Calls from lockscreen typically
+     * come from the UI thread.  This makes sure there are no race conditions between those calls.
+     */
+    public boolean handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_SERVICE_CONNECTED:
+                handleServiceConnected();
+                break;
+            case MSG_SERVICE_DISCONNECTED:
+                handleServiceDisconnected();
+                break;
+            case MSG_UNLOCK:
+                handleUnlock(msg.arg1);
+                break;
+            case MSG_CANCEL:
+                handleCancel();
+                break;
+            case MSG_REPORT_FAILED_ATTEMPT:
+                handleReportFailedAttempt();
+                break;
+            case MSG_POKE_WAKELOCK:
+                handlePokeWakelock(msg.arg1);
+                break;
+            default:
+                Log.e(TAG, "Unhandled message");
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Tells the service to start its UI via an AIDL interface.  Called when the
+     * onServiceConnected() callback is received.
+     */
+    void handleServiceConnected() {
+        Log.d(TAG, "handleServiceConnected()");
+
+        // It is possible that an unbind has occurred in the time between the bind and when this
+        // function is reached.  If an unbind has already occurred, proceeding on to call startUi()
+        // can result in a fatal error.  Note that the onServiceConnected() callback is
+        // asynchronous, so this possibility would still exist if we executed this directly in
+        // onServiceConnected() rather than using a handler.
+        if (!mBoundToService) {
+            Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
+            return;
+        }
+
+        try {
+            mService.registerCallback(mFaceUnlockCallback);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString());
+            mService = null;
+            mBoundToService = false;
+            mIsRunning = false;
+            return;
+        }
+
+        if (mFaceUnlockView != null) {
+            IBinder windowToken = mFaceUnlockView.getWindowToken();
+            if (windowToken != null) {
+                // When switching between portrait and landscape view while Face Unlock is running,
+                // the screen will eventually go dark unless we poke the wakelock when Face Unlock
+                // is restarted.
+                mKeyguardScreenCallback.userActivity(0);
+
+                int[] position;
+                position = new int[2];
+                mFaceUnlockView.getLocationInWindow(position);
+                startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(),
+                        mFaceUnlockView.getHeight());
+            } else {
+                Log.e(TAG, "windowToken is null in handleServiceConnected()");
+            }
+        }
+    }
+
+    /**
+     * Called when the onServiceDisconnected() callback is received.  This should not happen during
+     * normal operation.  It indicates an error has occurred.
+     */
+    void handleServiceDisconnected() {
+        Log.e(TAG, "handleServiceDisconnected()");
+        // TODO: this lock may no longer be needed now that everything is being called from a
+        // handler
+        synchronized (mServiceRunningLock) {
+            mService = null;
+            mServiceRunning = false;
+        }
+        mBoundToService = false;
+        mIsRunning = false;
+    }
+
+    /**
+     * Stops the Face Unlock service and tells the device to grant access to the user.
+     */
+    void handleUnlock(int authenticatedUserId) {
+        if (DEBUG) Log.d(TAG, "handleUnlock()");
+        stop();
+        int currentUserId = mLockPatternUtils.getCurrentUser();
+        if (authenticatedUserId == currentUserId) {
+            if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
+            mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
+            mKeyguardScreenCallback.dismiss(true);
+        } else {
+            Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
+                    ") because the current user is " + currentUserId);
+        }
+    }
+
+    /**
+     * Stops the Face Unlock service and goes to the backup lock.
+     */
+    void handleCancel() {
+        if (DEBUG) Log.d(TAG, "handleCancel()");
+        // We are going to the backup method, so we don't want to see Face Unlock again until the
+        // next time the user visits keyguard.
+        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
+
+        mKeyguardScreenCallback.showBackupSecurity();
+        stop();
+        mKeyguardScreenCallback.userActivity(BACKUP_LOCK_TIMEOUT);
+    }
+
+    /**
+     * Increments the number of failed Face Unlock attempts.
+     */
+    void handleReportFailedAttempt() {
+        if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()");
+        // We are going to the backup method, so we don't want to see Face Unlock again until the
+        // next time the user visits keyguard.
+        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
+
+        mKeyguardScreenCallback.reportFailedUnlockAttempt();
+    }
+
+    /**
+     * If the screen is on, pokes the wakelock to keep the screen alive and active for a specific
+     * amount of time.
+     */
+    void handlePokeWakelock(int millis) {
+      PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+      if (powerManager.isScreenOn()) {
+        mKeyguardScreenCallback.userActivity(millis);
+      }
+    }
+
+    /**
+     * Implements service connection methods.
+     */
+    private ServiceConnection mConnection = new ServiceConnection() {
+        /**
+         * Called when the Face Unlock service connects after calling bind().
+         */
+        public void onServiceConnected(ComponentName className, IBinder iservice) {
+            Log.d(TAG, "Connected to Face Unlock service");
+            mService = IFaceLockInterface.Stub.asInterface(iservice);
+            mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED);
+        }
+
+        /**
+         * Called if the Face Unlock service unexpectedly disconnects.  This indicates an error.
+         */
+        public void onServiceDisconnected(ComponentName className) {
+            Log.e(TAG, "Unexpected disconnect from Face Unlock service");
+            mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED);
+        }
+    };
+
+    /**
+     * Tells the Face Unlock service to start displaying its UI and start processing.
+     */
+    private void startUi(IBinder windowToken, int x, int y, int w, int h) {
+        if (DEBUG) Log.d(TAG, "startUi()");
+        synchronized (mServiceRunningLock) {
+            if (!mServiceRunning) {
+                Log.d(TAG, "Starting Face Unlock");
+                try {
+                    mService.startUi(windowToken, x, y, w, h,
+                            mLockPatternUtils.isBiometricWeakLivelinessEnabled());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
+                    return;
+                }
+                mServiceRunning = true;
+            } else {
+                Log.w(TAG, "startUi() attempted while running");
+            }
+        }
+    }
+
+    /**
+     * Tells the Face Unlock service to stop displaying its UI and stop processing.
+     */
+    private void stopUi() {
+        if (DEBUG) Log.d(TAG, "stopUi()");
+        // Note that attempting to stop Face Unlock when it's not running is not an issue.
+        // Face Unlock can return, which stops it and then we try to stop it when the
+        // screen is turned off.  That's why we check.
+        synchronized (mServiceRunningLock) {
+            if (mServiceRunning) {
+                Log.d(TAG, "Stopping Face Unlock");
+                try {
+                    mService.stopUi();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString());
+                }
+                mServiceRunning = false;
+            } else {
+                // This is usually not an error when this happens.  Sometimes we will tell it to
+                // stop multiple times because it's called from both onWindowFocusChanged and
+                // onDetachedFromWindow.
+                if (DEBUG) Log.d(TAG, "stopUi() attempted while not running");
+            }
+        }
+    }
+
+    /**
+     * Implements the AIDL biometric unlock service callback interface.
+     */
+    private final IFaceLockCallback mFaceUnlockCallback = new IFaceLockCallback.Stub() {
+        /**
+         * Called when Face Unlock wants to grant access to the user.
+         */
+        public void unlock() {
+            if (DEBUG) Log.d(TAG, "unlock()");
+            Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1);
+            mHandler.sendMessage(message);
+        }
+
+        /**
+         * Called when Face Unlock wants to go to the backup.
+         */
+        public void cancel() {
+            if (DEBUG) Log.d(TAG, "cancel()");
+            mHandler.sendEmptyMessage(MSG_CANCEL);
+        }
+
+        /**
+         * Called when Face Unlock wants to increment the number of failed attempts.
+         */
+        public void reportFailedAttempt() {
+            if (DEBUG) Log.d(TAG, "reportFailedAttempt()");
+            mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT);
+        }
+
+        /**
+         * Called when Face Unlock wants to keep the screen alive and active for a specific amount
+         * of time.
+         */
+        public void pokeWakelock(int millis) {
+            if (DEBUG) Log.d(TAG, "pokeWakelock() for " + millis + "ms");
+            Message message = mHandler.obtainMessage(MSG_POKE_WAKELOCK, millis, -1);
+            mHandler.sendMessage(message);
+        }
+
+    };
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
new file mode 100644
index 0000000..fb2eeda
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import com.android.internal.widget.LockPatternUtils;
+
+/**
+ * Base class for PIN and password unlock screens.
+ */
+public abstract class KeyguardAbsKeyInputView extends LinearLayout
+        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+    protected KeyguardSecurityCallback mCallback;
+    protected TextView mPasswordEntry;
+    protected LockPatternUtils mLockPatternUtils;
+    protected SecurityMessageDisplay mSecurityMessageDisplay;
+    protected View mEcaView;
+    private Drawable mBouncerFrame;
+    protected boolean mEnableHaptics;
+
+    // To avoid accidental lockout due to events while the device in in the pocket, ignore
+    // any passwords with length less than or equal to this length.
+    protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
+
+    public KeyguardAbsKeyInputView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+        mCallback = callback;
+    }
+
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+        mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        if (hasWindowFocus) {
+            reset();
+        }
+    }
+
+    public void reset() {
+        // start fresh
+        mPasswordEntry.setText("");
+        mPasswordEntry.requestFocus();
+
+        // if the user is currently locked out, enforce it.
+        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+        if (deadline != 0) {
+            handleAttemptLockout(deadline);
+        } else {
+            resetState();
+        }
+    }
+
+    protected abstract int getPasswordTextViewId();
+    protected abstract void resetState();
+
+    @Override
+    protected void onFinishInflate() {
+        mLockPatternUtils = new LockPatternUtils(mContext);
+
+        mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
+        mPasswordEntry.setOnEditorActionListener(this);
+        mPasswordEntry.addTextChangedListener(this);
+
+        // Set selected property on so the view can send accessibility events.
+        mPasswordEntry.setSelected(true);
+
+        // Poke the wakelock any time the text is selected or modified
+        mPasswordEntry.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                mCallback.userActivity(0); // TODO: customize timeout for text?
+            }
+        });
+
+        mPasswordEntry.addTextChangedListener(new TextWatcher() {
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+            }
+
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            }
+
+            public void afterTextChanged(Editable s) {
+                if (mCallback != null) {
+                    mCallback.userActivity(0);
+                }
+            }
+        });
+        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
+        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
+        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
+        if (bouncerFrameView != null) {
+            mBouncerFrame = bouncerFrameView.getBackground();
+        }
+    }
+
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        // send focus to the password field
+        return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
+    }
+
+    /*
+     * Override this if you have a different string for "wrong password"
+     *
+     * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
+     */
+    protected int getWrongPasswordStringId() {
+        return R.string.kg_wrong_password;
+    }
+
+    protected void verifyPasswordAndUnlock() {
+        String entry = mPasswordEntry.getText().toString();
+        if (mLockPatternUtils.checkPassword(entry)) {
+            mCallback.reportSuccessfulUnlockAttempt();
+            mCallback.dismiss(true);
+        } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
+            // to avoid accidental lockout, only count attempts that are long enough to be a
+            // real password. This may require some tweaking.
+            mCallback.reportFailedUnlockAttempt();
+            if (0 == (mCallback.getFailedAttempts()
+                    % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
+                long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+                handleAttemptLockout(deadline);
+            }
+            mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
+        }
+        mPasswordEntry.setText("");
+    }
+
+    // Prevent user from using the PIN/Password entry until scheduled deadline.
+    protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
+        mPasswordEntry.setEnabled(false);
+        long elapsedRealtime = SystemClock.elapsedRealtime();
+        new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
+
+            @Override
+            public void onTick(long millisUntilFinished) {
+                int secondsRemaining = (int) (millisUntilFinished / 1000);
+                mSecurityMessageDisplay.setMessage(
+                        R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
+            }
+
+            @Override
+            public void onFinish() {
+                mSecurityMessageDisplay.setMessage("", false);
+                resetState();
+            }
+        }.start();
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        mCallback.userActivity(0);
+        return false;
+    }
+
+    @Override
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        // Check if this was the result of hitting the enter key
+        if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
+                || actionId == EditorInfo.IME_ACTION_NEXT) {
+            verifyPasswordAndUnlock();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean needsInput() {
+        return false;
+    }
+
+    @Override
+    public void onPause() {
+
+    }
+
+    @Override
+    public void onResume(int reason) {
+        reset();
+    }
+
+    @Override
+    public KeyguardSecurityCallback getCallback() {
+        return mCallback;
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        if (mCallback != null) {
+            mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
+        }
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+    }
+
+    // Cause a VIRTUAL_KEY vibration
+    public void doHapticKeyClick() {
+        if (mEnableHaptics) {
+            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
+                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+        }
+    }
+
+    @Override
+    public void showBouncer(int duration) {
+        KeyguardSecurityViewHelper.
+                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+        KeyguardSecurityViewHelper.
+                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
+    }
+}
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
new file mode 100644
index 0000000..6b8be69
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.LoginFilter;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import java.io.IOException;
+
+/**
+ * When the user forgets their password a bunch of times, we fall back on their
+ * account's login/password to unlock the phone (and reset their lock pattern).
+ */
+public class KeyguardAccountView extends LinearLayout implements KeyguardSecurityView,
+        View.OnClickListener, TextWatcher {
+    private static final int AWAKE_POKE_MILLIS = 30000;
+    private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
+    private static final String LOCK_PATTERN_CLASS = LOCK_PATTERN_PACKAGE + ".ChooseLockGeneric";
+
+    private KeyguardSecurityCallback mCallback;
+    private LockPatternUtils mLockPatternUtils;
+    private EditText mLogin;
+    private EditText mPassword;
+    private Button mOk;
+    public boolean mEnableFallback;
+    private SecurityMessageDisplay mSecurityMessageDisplay;
+
+    /**
+     * Shown while making asynchronous check of password.
+     */
+    private ProgressDialog mCheckingDialog;
+
+    public KeyguardAccountView(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardAccountView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardAccountView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mLockPatternUtils = new LockPatternUtils(getContext());
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mLogin = (EditText) findViewById(R.id.login);
+        mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } );
+        mLogin.addTextChangedListener(this);
+
+        mPassword = (EditText) findViewById(R.id.password);
+        mPassword.addTextChangedListener(this);
+
+        mOk = (Button) findViewById(R.id.ok);
+        mOk.setOnClickListener(this);
+
+        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
+        reset();
+    }
+
+    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+        mCallback = callback;
+    }
+
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+    }
+
+    public KeyguardSecurityCallback getCallback() {
+        return mCallback;
+    }
+
+
+    public void afterTextChanged(Editable s) {
+    }
+
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        if (mCallback != null) {
+            mCallback.userActivity(AWAKE_POKE_MILLIS);
+        }
+    }
+
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction,
+            Rect previouslyFocusedRect) {
+        // send focus to the login field
+        return mLogin.requestFocus(direction, previouslyFocusedRect);
+    }
+
+    public boolean needsInput() {
+        return true;
+    }
+
+    public void reset() {
+        // start fresh
+        mLogin.setText("");
+        mPassword.setText("");
+        mLogin.requestFocus();
+        boolean permLocked = mLockPatternUtils.isPermanentlyLocked();
+        mSecurityMessageDisplay.setMessage(permLocked ? R.string.kg_login_too_many_attempts :
+            R.string.kg_login_instructions, permLocked ? true : false);
+    }
+
+    /** {@inheritDoc} */
+    public void cleanUp() {
+        if (mCheckingDialog != null) {
+            mCheckingDialog.hide();
+        }
+        mCallback = null;
+        mLockPatternUtils = null;
+    }
+
+    public void onClick(View v) {
+        mCallback.userActivity(0);
+        if (v == mOk) {
+            asyncCheckPassword();
+        }
+    }
+
+    private void postOnCheckPasswordResult(final boolean success) {
+        // ensure this runs on UI thread
+        mLogin.post(new Runnable() {
+            public void run() {
+                if (success) {
+                    // clear out forgotten password
+                    mLockPatternUtils.setPermanentlyLocked(false);
+                    mLockPatternUtils.setLockPatternEnabled(false);
+                    mLockPatternUtils.saveLockPattern(null);
+
+                    // launch the 'choose lock pattern' activity so
+                    // the user can pick a new one if they want to
+                    Intent intent = new Intent();
+                    intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivityAsUser(intent,
+                            new UserHandle(mLockPatternUtils.getCurrentUser()));
+                    mCallback.reportSuccessfulUnlockAttempt();
+
+                    // dismiss keyguard
+                    mCallback.dismiss(true);
+                } else {
+                    mSecurityMessageDisplay.setMessage(R.string.kg_login_invalid_input, true);
+                    mPassword.setText("");
+                    mCallback.reportFailedUnlockAttempt();
+                }
+            }
+        });
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN
+                && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            if (mLockPatternUtils.isPermanentlyLocked()) {
+                mCallback.dismiss(false);
+            } else {
+                // TODO: mCallback.forgotPattern(false);
+            }
+            return true;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    /**
+     * Given the string the user entered in the 'username' field, find
+     * the stored account that they probably intended.  Prefer, in order:
+     *
+     *   - an exact match for what was typed, or
+     *   - a case-insensitive match for what was typed, or
+     *   - if they didn't include a domain, an exact match of the username, or
+     *   - if they didn't include a domain, a case-insensitive
+     *     match of the username.
+     *
+     * If there is a tie for the best match, choose neither --
+     * the user needs to be more specific.
+     *
+     * @return an account name from the database, or null if we can't
+     * find a single best match.
+     */
+    private Account findIntendedAccount(String username) {
+        Account[] accounts = AccountManager.get(mContext).getAccountsByTypeAsUser("com.google",
+                new UserHandle(mLockPatternUtils.getCurrentUser()));
+
+        // Try to figure out which account they meant if they
+        // typed only the username (and not the domain), or got
+        // the case wrong.
+
+        Account bestAccount = null;
+        int bestScore = 0;
+        for (Account a: accounts) {
+            int score = 0;
+            if (username.equals(a.name)) {
+                score = 4;
+            } else if (username.equalsIgnoreCase(a.name)) {
+                score = 3;
+            } else if (username.indexOf('@') < 0) {
+                int i = a.name.indexOf('@');
+                if (i >= 0) {
+                    String aUsername = a.name.substring(0, i);
+                    if (username.equals(aUsername)) {
+                        score = 2;
+                    } else if (username.equalsIgnoreCase(aUsername)) {
+                        score = 1;
+                    }
+                }
+            }
+            if (score > bestScore) {
+                bestAccount = a;
+                bestScore = score;
+            } else if (score == bestScore) {
+                bestAccount = null;
+            }
+        }
+        return bestAccount;
+    }
+
+    private void asyncCheckPassword() {
+        mCallback.userActivity(AWAKE_POKE_MILLIS);
+        final String login = mLogin.getText().toString();
+        final String password = mPassword.getText().toString();
+        Account account = findIntendedAccount(login);
+        if (account == null) {
+            postOnCheckPasswordResult(false);
+            return;
+        }
+        getProgressDialog().show();
+        Bundle options = new Bundle();
+        options.putString(AccountManager.KEY_PASSWORD, password);
+        AccountManager.get(mContext).confirmCredentialsAsUser(account, options, null /* activity */,
+                new AccountManagerCallback<Bundle>() {
+            public void run(AccountManagerFuture<Bundle> future) {
+                try {
+                    mCallback.userActivity(AWAKE_POKE_MILLIS);
+                    final Bundle result = future.getResult();
+                    final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+                    postOnCheckPasswordResult(verified);
+                } catch (OperationCanceledException e) {
+                    postOnCheckPasswordResult(false);
+                } catch (IOException e) {
+                    postOnCheckPasswordResult(false);
+                } catch (AuthenticatorException e) {
+                    postOnCheckPasswordResult(false);
+                } finally {
+                    mLogin.post(new Runnable() {
+                        public void run() {
+                            getProgressDialog().hide();
+                        }
+                    });
+                }
+            }
+        }, null /* handler */, new UserHandle(mLockPatternUtils.getCurrentUser()));
+    }
+
+    private Dialog getProgressDialog() {
+        if (mCheckingDialog == null) {
+            mCheckingDialog = new ProgressDialog(mContext);
+            mCheckingDialog.setMessage(
+                    mContext.getString(R.string.kg_login_checking_password));
+            mCheckingDialog.setIndeterminate(true);
+            mCheckingDialog.setCancelable(false);
+            mCheckingDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        }
+        return mCheckingDialog;
+    }
+
+    @Override
+    public void onPause() {
+
+    }
+
+    @Override
+    public void onResume(int reason) {
+        reset();
+    }
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    @Override
+    public void showBouncer(int duration) {
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+    }
+}
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
new file mode 100644
index 0000000..9a1aa5b
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.IActivityManager.WaitResult;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+
+import java.util.List;
+
+public abstract class KeyguardActivityLauncher {
+    private static final String TAG = KeyguardActivityLauncher.class.getSimpleName();
+    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+    private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
+    private static final Intent SECURE_CAMERA_INTENT =
+            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
+                    .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+    private static final Intent INSECURE_CAMERA_INTENT =
+            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+
+    abstract Context getContext();
+
+    abstract KeyguardSecurityCallback getCallback();
+
+    abstract LockPatternUtils getLockPatternUtils();
+
+    public static class CameraWidgetInfo {
+        public String contextPackage;
+        public int layoutId;
+    }
+
+    public CameraWidgetInfo getCameraWidgetInfo() {
+        CameraWidgetInfo info = new CameraWidgetInfo();
+        Intent intent = getCameraIntent();
+        PackageManager packageManager = getContext().getPackageManager();
+        final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
+                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
+        if (appList.size() == 0) {
+            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Nothing found");
+            return null;
+        }
+        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
+                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
+                getLockPatternUtils().getCurrentUser());
+        if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): resolved: " + resolved);
+        if (wouldLaunchResolverActivity(resolved, appList)) {
+            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Would launch resolver");
+            return info;
+        }
+        if (resolved == null || resolved.activityInfo == null) {
+            return null;
+        }
+        if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
+            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no metadata found");
+            return info;
+        }
+        int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
+        if (layoutId == 0) {
+            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no layout specified");
+            return info;
+        }
+        info.contextPackage = resolved.activityInfo.packageName;
+        info.layoutId = layoutId;
+        return info;
+    }
+
+    public void launchCamera(Handler worker, Runnable onSecureCameraStarted) {
+        LockPatternUtils lockPatternUtils = getLockPatternUtils();
+        if (lockPatternUtils.isSecure()) {
+            // Launch the secure version of the camera
+            if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) {
+                // TODO: Show disambiguation dialog instead.
+                // For now, we'll treat this like launching any other app from secure keyguard.
+                // When they do, user sees the system's ResolverActivity which lets them choose
+                // which secure camera to use.
+                launchActivity(SECURE_CAMERA_INTENT, false, false, null, null);
+            } else {
+                launchActivity(SECURE_CAMERA_INTENT, true, false, worker, onSecureCameraStarted);
+            }
+        } else {
+            // Launch the normal camera
+            launchActivity(INSECURE_CAMERA_INTENT, false, false, null, null);
+        }
+    }
+
+    public void launchWidgetPicker(int appWidgetId) {
+        Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
+
+        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+        pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
+        pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
+                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
+
+        Bundle options = new Bundle();
+        options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
+        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
+        pickIntent.addFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+        launchActivity(pickIntent, false, false, null, null);
+    }
+
+    /**
+     * Launches the said intent for the current foreground user.
+     *
+     * @param intent
+     * @param showsWhileLocked true if the activity can be run on top of keyguard.
+     *   See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
+     * @param useDefaultAnimations true if default transitions should be used, else suppressed.
+     * @param worker if supplied along with onStarted, used to launch the blocking activity call.
+     * @param onStarted if supplied along with worker, called after activity is started.
+     */
+    public void launchActivity(final Intent intent,
+            boolean showsWhileLocked,
+            boolean useDefaultAnimations,
+            final Handler worker,
+            final Runnable onStarted) {
+
+        final Context context = getContext();
+        final Bundle animation = useDefaultAnimations ? null
+                : ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
+        launchActivityWithAnimation(intent, showsWhileLocked, animation, worker, onStarted);
+    }
+
+    public void launchActivityWithAnimation(final Intent intent,
+            boolean showsWhileLocked,
+            final Bundle animation,
+            final Handler worker,
+            final Runnable onStarted) {
+
+        LockPatternUtils lockPatternUtils = getLockPatternUtils();
+        intent.addFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        boolean isSecure = lockPatternUtils.isSecure();
+        if (!isSecure || showsWhileLocked) {
+            if (!isSecure) {
+                dismissKeyguardOnNextActivity();
+            }
+            try {
+                if (DEBUG) Log.d(TAG, String.format("Starting activity for intent %s at %s",
+                        intent, SystemClock.uptimeMillis()));
+                startActivityForCurrentUser(intent, animation, worker, onStarted);
+            } catch (ActivityNotFoundException e) {
+                Log.w(TAG, "Activity not found for intent + " + intent.getAction());
+            }
+        } else {
+            // Create a runnable to start the activity and ask the user to enter their
+            // credentials.
+            KeyguardSecurityCallback callback = getCallback();
+            callback.setOnDismissAction(new OnDismissAction() {
+                @Override
+                public boolean onDismiss() {
+                    dismissKeyguardOnNextActivity();
+                    startActivityForCurrentUser(intent, animation, worker, onStarted);
+                    return true;
+                }
+            });
+            callback.dismiss(false);
+        }
+    }
+
+    private void dismissKeyguardOnNextActivity() {
+        try {
+            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+        } catch (RemoteException e) {
+            Log.w(TAG, "can't dismiss keyguard on launch");
+        }
+    }
+
+    private void startActivityForCurrentUser(final Intent intent, final Bundle options,
+            Handler worker, final Runnable onStarted) {
+        final UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
+        if (worker == null || onStarted == null) {
+            getContext().startActivityAsUser(intent, options, user);
+            return;
+        }
+        // if worker + onStarted are supplied, run blocking activity launch call in the background
+        worker.post(new Runnable(){
+            @Override
+            public void run() {
+                try {
+                    WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait(
+                            null /*caller*/,
+                            null /*caller pkg*/,
+                            intent,
+                            intent.resolveTypeIfNeeded(getContext().getContentResolver()),
+                            null /*resultTo*/,
+                            null /*resultWho*/,
+                            0 /*requestCode*/,
+                            Intent.FLAG_ACTIVITY_NEW_TASK,
+                            null /*profileFile*/,
+                            null /*profileFd*/,
+                            options,
+                            user.getIdentifier());
+                    if (DEBUG) Log.d(TAG, String.format("waitResult[%s,%s,%s,%s] at %s",
+                            result.result, result.thisTime, result.totalTime, result.who,
+                            SystemClock.uptimeMillis()));
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error starting activity", e);
+                    return;
+                }
+                try {
+                    onStarted.run();
+                } catch (Throwable t) {
+                    Log.w(TAG, "Error running onStarted callback", t);
+                }
+            }});
+    }
+
+    private Intent getCameraIntent() {
+        return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+    }
+
+    private boolean wouldLaunchResolverActivity(Intent intent) {
+        PackageManager packageManager = getContext().getPackageManager();
+        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
+                PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
+        List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
+                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
+        return wouldLaunchResolverActivity(resolved, appList);
+    }
+
+    private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
+        // If the list contains the above resolved activity, then it can't be
+        // ResolverActivity itself.
+        for (int i = 0; i < appList.size(); i++) {
+            ResolveInfo tmp = appList.get(i);
+            if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
+                    && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardCircleFramedDrawable.java b/packages/Keyguard/src/com/android/keyguard/KeyguardCircleFramedDrawable.java
new file mode 100644
index 0000000..63b61ad
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardCircleFramedDrawable.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+
+import android.util.Log;
+
+class KeyguardCircleFramedDrawable extends Drawable {
+
+    private final Bitmap mBitmap;
+    private final int mSize;
+    private final Paint mPaint;
+    private final float mShadowRadius;
+    private final float mStrokeWidth;
+    private final int mFrameColor;
+    private final int mHighlightColor;
+    private final int mFrameShadowColor;
+
+    private float mScale;
+    private Path mFramePath;
+    private Rect mSrcRect;
+    private RectF mDstRect;
+    private RectF mFrameRect;
+    private boolean mPressed;
+
+    public KeyguardCircleFramedDrawable(Bitmap bitmap, int size,
+            int frameColor, float strokeWidth,
+            int frameShadowColor, float shadowRadius,
+            int highlightColor) {
+        super();
+        mSize = size;
+        mShadowRadius = shadowRadius;
+        mFrameColor = frameColor;
+        mFrameShadowColor = frameShadowColor;
+        mStrokeWidth = strokeWidth;
+        mHighlightColor = highlightColor;
+
+        mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(mBitmap);
+
+        final int width = bitmap.getWidth();
+        final int height = bitmap.getHeight();
+        final int square = Math.min(width, height);
+
+        final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square);
+        final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
+        circleRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f);
+        circleRect.inset(mShadowRadius, mShadowRadius);
+
+        final Path fillPath = new Path();
+        fillPath.addArc(circleRect, 0f, 360f);
+
+        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+        // opaque circle matte
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(Color.BLACK);
+        mPaint.setStyle(Paint.Style.FILL);
+        canvas.drawPath(fillPath, mPaint);
+
+        // mask in the icon where the bitmap is opaque
+        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
+        canvas.drawBitmap(bitmap, cropRect, circleRect, mPaint);
+
+        // prepare paint for frame drawing
+        mPaint.setXfermode(null);
+
+        mScale = 1f;
+
+        mSrcRect = new Rect(0, 0, mSize, mSize);
+        mDstRect = new RectF(0, 0, mSize, mSize);
+        mFrameRect = new RectF(mDstRect);
+        mFramePath = new Path();
+    }
+
+    public void reset() {
+        mScale = 1f;
+        mPressed = false;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        // clear background
+        final float outside = Math.min(canvas.getWidth(), canvas.getHeight());
+        final float inside = mScale * outside;
+        final float pad = (outside - inside) / 2f;
+
+        mDstRect.set(pad, pad, outside - pad, outside - pad);
+        canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
+
+        mFrameRect.set(mDstRect);
+        mFrameRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f);
+        mFrameRect.inset(mShadowRadius, mShadowRadius);
+
+        mFramePath.reset();
+        mFramePath.addArc(mFrameRect, 0f, 360f);
+
+        // white frame
+        if (mPressed) {
+            mPaint.setStyle(Paint.Style.FILL);
+            mPaint.setColor(Color.argb((int) (0.33f * 255),
+                            Color.red(mHighlightColor),
+                            Color.green(mHighlightColor),
+                            Color.blue(mHighlightColor)));
+            canvas.drawPath(mFramePath, mPaint);
+        }
+        mPaint.setStrokeWidth(mStrokeWidth);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setColor(mPressed ? mHighlightColor : mFrameColor);
+        mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mFrameShadowColor);
+        canvas.drawPath(mFramePath, mPaint);
+    }
+
+    public void setScale(float scale) {
+        mScale = scale;
+    }
+
+    public float getScale() {
+        return mScale;
+    }
+
+    public void setPressed(boolean pressed) {
+        mPressed = pressed;
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+    }
+
+    public boolean verifyParams(float iconSize, int frameColor, float stroke,
+            int frameShadowColor, float shadowRadius, int highlightColor) {
+        return mSize == iconSize
+                && mFrameColor == frameColor
+                && mStrokeWidth == stroke
+                && mFrameShadowColor == frameShadowColor
+                && mShadowRadius == shadowRadius
+                && mHighlightColor == highlightColor;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
new file mode 100644
index 0000000..c2cd32f
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import java.lang.Math;
+
+public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
+
+    private static final String TAG = "FULKeyguardFaceUnlockView";
+    private static final boolean DEBUG = false;
+    private KeyguardSecurityCallback mKeyguardSecurityCallback;
+    private LockPatternUtils mLockPatternUtils;
+    private BiometricSensorUnlock mBiometricUnlock;
+    private View mFaceUnlockAreaView;
+    private ImageButton mCancelButton;
+    private SecurityMessageDisplay mSecurityMessageDisplay;
+    private View mEcaView;
+    private Drawable mBouncerFrame;
+
+    private boolean mIsShowing = false;
+    private final Object mIsShowingLock = new Object();
+
+    private int mLastRotation;
+    private boolean mWatchingRotation;
+    private final IWindowManager mWindowManager =
+            IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+
+    private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
+        public void onRotationChanged(int rotation) {
+            if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation);
+
+            // If the difference between the new rotation value and the previous rotation value is
+            // equal to 2, the rotation change was 180 degrees.  This stops the biometric unlock
+            // and starts it in the new position.  This is not performed for 90 degree rotations
+            // since a 90 degree rotation is a configuration change, which takes care of this for
+            // us.
+            if (Math.abs(rotation - mLastRotation) == 2) {
+                if (mBiometricUnlock != null) {
+                    mBiometricUnlock.stop();
+                    maybeStartBiometricUnlock();
+                }
+            }
+            mLastRotation = rotation;
+        }
+    };
+
+    public KeyguardFaceUnlockView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardFaceUnlockView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        initializeBiometricUnlockView();
+
+        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
+        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
+        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
+        if (bouncerFrameView != null) {
+            mBouncerFrame = bouncerFrameView.getBackground();
+        }
+    }
+
+    @Override
+    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+        mKeyguardSecurityCallback = callback;
+        // TODO: formalize this in the interface or factor it out
+        ((FaceUnlock)mBiometricUnlock).setKeyguardCallback(callback);
+    }
+
+    @Override
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+    }
+
+    @Override
+    public void reset() {
+
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
+        if (mBiometricUnlock != null) {
+            mBiometricUnlock.stop();
+        }
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
+        if (mWatchingRotation) {
+            try {
+                mWindowManager.removeRotationWatcher(mRotationWatcher);
+                mWatchingRotation = false;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception when removing rotation watcher");
+            }
+        }
+    }
+
+    @Override
+    public void onPause() {
+        if (DEBUG) Log.d(TAG, "onPause()");
+        if (mBiometricUnlock != null) {
+            mBiometricUnlock.stop();
+        }
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
+        if (mWatchingRotation) {
+            try {
+                mWindowManager.removeRotationWatcher(mRotationWatcher);
+                mWatchingRotation = false;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception when removing rotation watcher");
+            }
+        }
+    }
+
+    @Override
+    public void onResume(int reason) {
+        if (DEBUG) Log.d(TAG, "onResume()");
+        mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
+        if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
+          maybeStartBiometricUnlock();
+        }
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
+
+        // Registers a callback which handles stopping the biometric unlock and restarting it in
+        // the new position for a 180 degree rotation change.
+        if (!mWatchingRotation) {
+            try {
+                mLastRotation = mWindowManager.watchRotation(mRotationWatcher);
+                mWatchingRotation = true;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception when adding rotation watcher");
+            }
+        }
+    }
+
+    @Override
+    public boolean needsInput() {
+        return false;
+    }
+
+    @Override
+    public KeyguardSecurityCallback getCallback() {
+        return mKeyguardSecurityCallback;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        mBiometricUnlock.initializeView(mFaceUnlockAreaView);
+    }
+
+    private void initializeBiometricUnlockView() {
+        if (DEBUG) Log.d(TAG, "initializeBiometricUnlockView()");
+        mFaceUnlockAreaView = findViewById(R.id.face_unlock_area_view);
+        if (mFaceUnlockAreaView != null) {
+            mBiometricUnlock = new FaceUnlock(mContext);
+
+            mCancelButton = (ImageButton) findViewById(R.id.face_unlock_cancel_button);
+            mCancelButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mBiometricUnlock.stopAndShowBackup();
+                }
+            });
+        } else {
+            Log.w(TAG, "Couldn't find biometric unlock view");
+        }
+    }
+
+    /**
+     * Starts the biometric unlock if it should be started based on a number of factors.  If it
+     * should not be started, it either goes to the back up, or remains showing to prepare for
+     * it being started later.
+     */
+    private void maybeStartBiometricUnlock() {
+        if (DEBUG) Log.d(TAG, "maybeStartBiometricUnlock()");
+        if (mBiometricUnlock != null) {
+            KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+            final boolean backupIsTimedOut = (
+                    monitor.getFailedUnlockAttempts() >=
+                    LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
+            PowerManager powerManager = (PowerManager) mContext.getSystemService(
+                    Context.POWER_SERVICE);
+
+            boolean isShowing;
+            synchronized(mIsShowingLock) {
+                isShowing = mIsShowing;
+            }
+
+            // Don't start it if the screen is off or if it's not showing, but keep this view up
+            // because we want it here and ready for when the screen turns on or when it does start
+            // showing.
+            if (!powerManager.isScreenOn() || !isShowing) {
+                mBiometricUnlock.stop(); // It shouldn't be running but calling this can't hurt.
+                return;
+            }
+
+            // Although these same conditions are handled in KeyguardSecurityModel, they are still
+            // necessary here.  When a tablet is rotated 90 degrees, a configuration change is
+            // triggered and everything is torn down and reconstructed.  That means
+            // KeyguardSecurityModel gets a chance to take care of the logic and doesn't even
+            // reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed.
+            // However, for a 180 degree rotation, no configuration change is triggered, so only
+            // the logic here is capable of suppressing Face Unlock.
+            if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
+                    && monitor.isAlternateUnlockEnabled()
+                    && !monitor.getMaxBiometricUnlockAttemptsReached()
+                    && !backupIsTimedOut) {
+                mBiometricUnlock.start();
+            } else {
+                mBiometricUnlock.stopAndShowBackup();
+            }
+        }
+    }
+
+    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+        // We need to stop the biometric unlock when a phone call comes in
+        @Override
+        public void onPhoneStateChanged(int phoneState) {
+            if (DEBUG) Log.d(TAG, "onPhoneStateChanged(" + phoneState + ")");
+            if (phoneState == TelephonyManager.CALL_STATE_RINGING) {
+                if (mBiometricUnlock != null) {
+                    mBiometricUnlock.stopAndShowBackup();
+                }
+            }
+        }
+
+        @Override
+        public void onUserSwitching(int userId) {
+            if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")");
+            if (mBiometricUnlock != null) {
+                mBiometricUnlock.stop();
+            }
+            // No longer required; static value set by KeyguardViewMediator
+            // mLockPatternUtils.setCurrentUser(userId);
+        }
+
+        @Override
+        public void onUserSwitchComplete(int userId) {
+            if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")");
+            if (mBiometricUnlock != null) {
+                maybeStartBiometricUnlock();
+            }
+        }
+
+        @Override
+        public void onKeyguardVisibilityChanged(boolean showing) {
+            if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
+            boolean wasShowing = false;
+            synchronized(mIsShowingLock) {
+                wasShowing = mIsShowing;
+                mIsShowing = showing;
+            }
+            PowerManager powerManager = (PowerManager) mContext.getSystemService(
+                    Context.POWER_SERVICE);
+            if (mBiometricUnlock != null) {
+                if (!showing && wasShowing) {
+                    mBiometricUnlock.stop();
+                } else if (showing && powerManager.isScreenOn() && !wasShowing) {
+                    maybeStartBiometricUnlock();
+                }
+            }
+        }
+
+        @Override
+        public void onEmergencyCallAction() {
+            if (mBiometricUnlock != null) {
+                mBiometricUnlock.stop();
+            }
+        }
+    };
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    @Override
+    public void showBouncer(int duration) {
+        KeyguardSecurityViewHelper.
+                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+        KeyguardSecurityViewHelper.
+                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardGlowStripView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardGlowStripView.java
new file mode 100644
index 0000000..98a44a6
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardGlowStripView.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.LinearLayout;
+
+/**
+ * A layout which animates a strip of horizontal, pulsing dots on request. This is used
+ * to indicate the presence of pages to the left / right.
+ */
+public class KeyguardGlowStripView extends LinearLayout {
+    private static final int DURATION = 500;
+
+    private static final float SLIDING_WINDOW_SIZE = 0.4f;
+    private int mDotStripTop;
+    private int mHorizontalDotGap;
+
+    private int mDotSize;
+    private int mNumDots;
+    private Drawable mDotDrawable;
+    private boolean mLeftToRight = true;
+
+    private float mAnimationProgress = 0f;
+    private boolean mDrawDots = false;
+    private ValueAnimator mAnimator;
+    private Interpolator mDotAlphaInterpolator = new DecelerateInterpolator(0.5f);
+
+    public KeyguardGlowStripView(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardGlowStripView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardGlowStripView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyguardGlowStripView);
+        mDotSize = a.getDimensionPixelSize(R.styleable.KeyguardGlowStripView_dotSize, mDotSize);
+        mNumDots = a.getInt(R.styleable.KeyguardGlowStripView_numDots, mNumDots);
+        mDotDrawable = a.getDrawable(R.styleable.KeyguardGlowStripView_glowDot);
+        mLeftToRight = a.getBoolean(R.styleable.KeyguardGlowStripView_leftToRight, mLeftToRight);
+    }
+
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        int availableWidth = w - getPaddingLeft() - getPaddingRight();
+        mHorizontalDotGap = (availableWidth - mDotSize * mNumDots) /  (mNumDots - 1);
+        mDotStripTop = getPaddingTop();
+        invalidate();
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        if (!mDrawDots) return;
+
+        int xOffset = getPaddingLeft();
+        mDotDrawable.setBounds(0, 0, mDotSize, mDotSize);
+
+        for (int i = 0; i < mNumDots; i++) {
+            // We fudge the relative position to provide a fade in of the first dot and a fade
+            // out of the final dot.
+            float relativeDotPosition = SLIDING_WINDOW_SIZE / 2 + ((1.0f * i) / (mNumDots - 1)) *
+                    (1 - SLIDING_WINDOW_SIZE);
+            float distance = Math.abs(relativeDotPosition - mAnimationProgress);
+            float alpha = Math.max(0, 1 - distance / (SLIDING_WINDOW_SIZE / 2));
+
+            alpha = mDotAlphaInterpolator.getInterpolation(alpha);
+
+            canvas.save();
+            canvas.translate(xOffset, mDotStripTop);
+            mDotDrawable.setAlpha((int) (alpha * 255));
+            mDotDrawable.draw(canvas);
+            canvas.restore();
+            xOffset += mDotSize + mHorizontalDotGap;
+        }
+    }
+
+    public void makeEmGo() {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+        float from = mLeftToRight ? 0f : 1f;
+        float to = mLeftToRight ? 1f : 0f;
+        mAnimator = ValueAnimator.ofFloat(from, to);
+        mAnimator.setDuration(DURATION);
+        mAnimator.setInterpolator(new LinearInterpolator());
+        mAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mDrawDots = false;
+                // make sure we draw one frame at the end with everything gone.
+                invalidate();
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mDrawDots = true;
+            }
+        });
+        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mAnimationProgress = (Float) animation.getAnimatedValue();
+                invalidate();
+            }
+        });
+        mAnimator.start();
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
new file mode 100644
index 0000000..bc8c866
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -0,0 +1,1702 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.AlertDialog;
+import android.app.SearchManager;
+import android.app.admin.DevicePolicyManager;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.media.RemoteControlClient;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.RemoteViews.OnClickHandler;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+public class KeyguardHostView extends KeyguardViewBase {
+    private static final String TAG = "KeyguardHostView";
+
+    // Transport control states.
+    static final int TRANSPORT_GONE = 0;
+    static final int TRANSPORT_INVISIBLE = 1;
+    static final int TRANSPORT_VISIBLE = 2;
+
+    private int mTransportState = TRANSPORT_GONE;
+
+    // Use this to debug all of keyguard
+    public static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    public static boolean DEBUGXPORT = true; // debug music transport control
+
+    // Found in KeyguardAppWidgetPickActivity.java
+    static final int APPWIDGET_HOST_ID = 0x4B455947;
+
+    private final int MAX_WIDGETS = 5;
+
+    private AppWidgetHost mAppWidgetHost;
+    private AppWidgetManager mAppWidgetManager;
+    private KeyguardWidgetPager mAppWidgetContainer;
+    private KeyguardSecurityViewFlipper mSecurityViewContainer;
+    private KeyguardSelectorView mKeyguardSelectorView;
+    private KeyguardTransportControlView mTransportControl;
+    private boolean mIsVerifyUnlockOnly;
+    private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
+    private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
+    private int mAppWidgetToShow;
+
+    private boolean mCheckAppWidgetConsistencyOnBootCompleted = false;
+    private boolean mCleanupAppWidgetsOnBootCompleted = false;
+
+    protected OnDismissAction mDismissAction;
+
+    protected int mFailedAttempts;
+    private LockPatternUtils mLockPatternUtils;
+
+    private KeyguardSecurityModel mSecurityModel;
+    private KeyguardViewStateManager mViewStateManager;
+
+    private Rect mTempRect = new Rect();
+
+    private int mDisabledFeatures;
+
+    private boolean mCameraDisabled;
+
+    private boolean mSafeModeEnabled;
+
+    private boolean mUserSetupCompleted;
+
+    // User for whom this host view was created.  Final because we should never change the
+    // id without reconstructing an instance of KeyguardHostView. See note below...
+    private final int mUserId;
+
+    private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
+
+    private boolean mIsScreenOn;
+
+    protected int mClientGeneration;
+
+    protected boolean mShowSecurityWhenReturn;
+
+    private final Rect mInsets = new Rect();
+
+    private MyOnClickHandler mOnClickHandler = new MyOnClickHandler(this);
+
+    /*package*/ interface UserSwitcherCallback {
+        void hideSecurityView(int duration);
+        void showSecurityView();
+        void showUnlockHint();
+        void userActivity();
+    }
+
+    /*package*/ interface OnDismissAction {
+        /* returns true if the dismiss should be deferred */
+        boolean onDismiss();
+    }
+
+    public KeyguardHostView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardHostView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        if (DEBUG) Log.e(TAG, "KeyguardHostView()");
+
+        mLockPatternUtils = new LockPatternUtils(context);
+
+        // Note: This depends on KeyguardHostView getting reconstructed every time the
+        // user switches, since mUserId will be used for the entire session.
+        // Once created, keyguard should *never* re-use this instance with another user.
+        // In other words, mUserId should never change - hence it's marked final.
+        mUserId = mLockPatternUtils.getCurrentUser();
+
+        DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        if (dpm != null) {
+            mDisabledFeatures = getDisabledFeatures(dpm);
+            mCameraDisabled = dpm.getCameraDisabled(null);
+        }
+
+        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
+
+        // These need to be created with the user context...
+        Context userContext = null;
+        try {
+            final String packageName = "system";
+            userContext = mContext.createPackageContextAsUser(packageName, 0,
+                    new UserHandle(mUserId));
+
+        } catch (NameNotFoundException e) {
+            e.printStackTrace();
+            // This should never happen, but it's better to have no widgets than to crash.
+            userContext = context;
+        }
+
+        mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
+                Looper.myLooper());
+
+        cleanupAppWidgetIds();
+
+        mAppWidgetManager = AppWidgetManager.getInstance(userContext);
+
+        mSecurityModel = new KeyguardSecurityModel(context);
+
+        mViewStateManager = new KeyguardViewStateManager(this);
+
+        mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+
+        // Ensure we have the current state *before* we call showAppropriateWidgetPage()
+        getInitialTransportState();
+
+        if (mSafeModeEnabled) {
+            Log.v(TAG, "Keyguard widgets disabled by safe mode");
+        }
+        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) {
+            Log.v(TAG, "Keyguard widgets disabled by DPM");
+        }
+        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
+            Log.v(TAG, "Keyguard secure camera disabled by DPM");
+        }
+    }
+
+    public void announceCurrentSecurityMethod() {
+        View v = (View) getSecurityView(mCurrentSecuritySelection);
+        if (v != null) {
+            v.announceForAccessibility(v.getContentDescription());
+        }
+    }
+
+    private void getInitialTransportState() {
+        DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
+                .getCachedDisplayClientState();
+        mTransportState = (dcs.clearing ? TRANSPORT_GONE :
+            (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
+
+        if (DEBUG) Log.v(TAG, "Initial transport state: "
+                + mTransportState + ", pbstate=" + dcs.playbackState);
+    }
+
+    private void cleanupAppWidgetIds() {
+        // Since this method may delete a widget (which we can't do until boot completed) we
+        // may have to defer it until after boot complete.
+        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
+            mCleanupAppWidgetsOnBootCompleted = true;
+            return;
+        }
+        if (!mSafeModeEnabled && !widgetsDisabled()) {
+            // Clean up appWidgetIds that are bound to lockscreen, but not actually used
+            // This is only to clean up after another bug: we used to not call
+            // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
+            // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
+            // that are triggered by deleteAppWidgetId, which is why we're doing this
+            int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
+            int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
+            for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
+                int appWidgetId = appWidgetIdsBoundToHost[i];
+                if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
+                    Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
+                            + appWidgetId);
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                }
+            }
+        }
+    }
+
+    private static boolean contains(int[] array, int target) {
+        for (int value : array) {
+            if (value == target) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
+            new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onBootCompleted() {
+            if (mCheckAppWidgetConsistencyOnBootCompleted) {
+                checkAppWidgetConsistency();
+                mSwitchPageRunnable.run();
+                mCheckAppWidgetConsistencyOnBootCompleted = false;
+            }
+            if (mCleanupAppWidgetsOnBootCompleted) {
+                cleanupAppWidgetIds();
+                mCleanupAppWidgetsOnBootCompleted = false;
+            }
+        }
+        @Override
+        public void onUserSwitchComplete(int userId) {
+            if (mKeyguardMultiUserSelectorView != null) {
+                mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
+            }
+        }
+        @Override
+        void onMusicClientIdChanged(
+                int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
+            // Set transport state to invisible until we know music is playing (below)
+            if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
+                Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration);
+            }
+            mClientGeneration = clientGeneration;
+            final int newState = (clearing ? TRANSPORT_GONE
+                    : (mTransportState == TRANSPORT_VISIBLE ?
+                    TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
+            if (newState != mTransportState) {
+                mTransportState = newState;
+                if (DEBUGXPORT) Log.v(TAG, "update widget: transport state changed");
+                KeyguardHostView.this.post(mSwitchPageRunnable);
+            }
+        }
+        @Override
+        public void onMusicPlaybackStateChanged(int playbackState, long eventTime) {
+            if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState);
+            if (mTransportState != TRANSPORT_GONE) {
+                final int newState = (isMusicPlaying(playbackState) ?
+                        TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE);
+                if (newState != mTransportState) {
+                    mTransportState = newState;
+                    if (DEBUGXPORT) Log.v(TAG, "update widget: play state changed");
+                    KeyguardHostView.this.post(mSwitchPageRunnable);
+                }
+            }
+        }
+    };
+
+    private static final boolean isMusicPlaying(int playbackState) {
+        // This should agree with the list in AudioService.isPlaystateActive()
+        switch (playbackState) {
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private SlidingChallengeLayout mSlidingChallengeLayout;
+    private MultiPaneChallengeLayout mMultiPaneChallengeLayout;
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean result = super.onTouchEvent(ev);
+        mTempRect.set(0, 0, 0, 0);
+        offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect);
+        ev.offsetLocation(mTempRect.left, mTempRect.top);
+        result = mSecurityViewContainer.dispatchTouchEvent(ev) || result;
+        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
+        return result;
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.keyguardDoneDrawing();
+        }
+    }
+
+    private int getWidgetPosition(int id) {
+        final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer;
+        final int children = appWidgetContainer.getChildCount();
+        for (int i = 0; i < children; i++) {
+            final View content = appWidgetContainer.getWidgetPageAt(i).getContent();
+            if (content != null && content.getId() == id) {
+                return i;
+            } else if (content == null) {
+                // Attempt to track down bug #8886916
+                Log.w(TAG, "*** Null content at " + "i=" + i + ",id=" + id + ",N=" + children);
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        // Grab instances of and make any necessary changes to the main layouts. Create
+        // view state manager and wire up necessary listeners / callbacks.
+        View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
+        mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
+        mAppWidgetContainer.setVisibility(VISIBLE);
+        mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
+        mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
+        mAppWidgetContainer.setMinScale(0.5f);
+
+        mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
+        if (mSlidingChallengeLayout != null) {
+            mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager);
+        }
+        mAppWidgetContainer.setViewStateManager(mViewStateManager);
+        mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
+
+        mMultiPaneChallengeLayout =
+                (MultiPaneChallengeLayout) findViewById(R.id.multi_pane_challenge);
+        ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout :
+                mMultiPaneChallengeLayout;
+        challenge.setOnBouncerStateChangedListener(mViewStateManager);
+        mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration());
+        mViewStateManager.setPagedView(mAppWidgetContainer);
+        mViewStateManager.setChallengeLayout(challenge);
+        mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper);
+        mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
+        mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
+
+        setBackButtonEnabled(false);
+
+        addDefaultWidgets();
+
+        addWidgetsFromSettings();
+        if (!shouldEnableAddWidget()) {
+            mAppWidgetContainer.setAddWidgetEnabled(false);
+        }
+        checkAppWidgetConsistency();
+        mSwitchPageRunnable.run();
+        // This needs to be called after the pages are all added.
+        mViewStateManager.showUsabilityHints();
+
+        showPrimarySecurityScreen(false);
+        updateSecurityViews();
+    }
+
+    private void setBackButtonEnabled(boolean enabled) {
+        if (mContext instanceof Activity) return;  // always enabled in activity mode
+        setSystemUiVisibility(enabled ?
+                getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
+                getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+    }
+
+    private boolean shouldEnableAddWidget() {
+        return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
+    }
+
+    private int getDisabledFeatures(DevicePolicyManager dpm) {
+        int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+        if (dpm != null) {
+            final int currentUser = mLockPatternUtils.getCurrentUser();
+            disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser);
+        }
+        return disabledFeatures;
+    }
+
+    private boolean widgetsDisabled() {
+        boolean disabledByLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+        boolean disabledByDpm =
+                (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
+        boolean disabledByUser = !mLockPatternUtils.getWidgetsEnabled();
+        return disabledByLowRamDevice || disabledByDpm || disabledByUser;
+    }
+
+    private boolean cameraDisabledByDpm() {
+        return mCameraDisabled
+                || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
+    }
+
+    private void updateSecurityViews() {
+        int children = mSecurityViewContainer.getChildCount();
+        for (int i = 0; i < children; i++) {
+            updateSecurityView(mSecurityViewContainer.getChildAt(i));
+        }
+    }
+
+    private void updateSecurityView(View view) {
+        if (view instanceof KeyguardSecurityView) {
+            KeyguardSecurityView ksv = (KeyguardSecurityView) view;
+            ksv.setKeyguardCallback(mCallback);
+            ksv.setLockPatternUtils(mLockPatternUtils);
+            if (mViewStateManager.isBouncing()) {
+                ksv.showBouncer(0);
+            } else {
+                ksv.hideBouncer(0);
+            }
+        } else {
+            Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
+        }
+    }
+
+    void setLockPatternUtils(LockPatternUtils utils) {
+        mSecurityModel.setLockPatternUtils(utils);
+        mLockPatternUtils = utils;
+        updateSecurityViews();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mAppWidgetHost.startListening();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mAppWidgetHost.stopListening();
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
+    }
+
+    void addWidget(AppWidgetHostView view, int pageIndex) {
+        mAppWidgetContainer.addWidget(view, pageIndex);
+    }
+
+    private KeyguardWidgetPager.Callbacks mWidgetCallbacks
+            = new KeyguardWidgetPager.Callbacks() {
+        @Override
+        public void userActivity() {
+            KeyguardHostView.this.userActivity();
+        }
+
+        @Override
+        public void onUserActivityTimeoutChanged() {
+            KeyguardHostView.this.onUserActivityTimeoutChanged();
+        }
+
+        @Override
+        public void onAddView(View v) {
+            if (!shouldEnableAddWidget()) {
+                mAppWidgetContainer.setAddWidgetEnabled(false);
+            }
+        }
+
+        @Override
+        public void onRemoveView(View v, boolean deletePermanently) {
+            if (deletePermanently) {
+                final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+                if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
+                        appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                }
+            }
+        }
+
+        @Override
+        public void onRemoveViewAnimationCompleted() {
+            if (shouldEnableAddWidget()) {
+                mAppWidgetContainer.setAddWidgetEnabled(true);
+            }
+        }
+    };
+
+    public void initializeSwitchingUserState(boolean switching) {
+        if (!switching && mKeyguardMultiUserSelectorView != null) {
+            mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
+        }
+    }
+
+    public void userActivity() {
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.userActivity();
+        }
+    }
+
+    public void onUserActivityTimeoutChanged() {
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.onUserActivityTimeoutChanged();
+        }
+    }
+
+    @Override
+    public long getUserActivityTimeout() {
+        // Currently only considering user activity timeouts needed by widgets.
+        // Could also take into account longer timeouts for certain security views.
+        if (mAppWidgetContainer != null) {
+            return mAppWidgetContainer.getUserActivityTimeout();
+        }
+        return -1;
+    }
+
+    private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
+
+        public void userActivity(long timeout) {
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.userActivity(timeout);
+            }
+        }
+
+        public void dismiss(boolean authenticated) {
+            showNextSecurityScreenOrFinish(authenticated);
+        }
+
+        public boolean isVerifyUnlockOnly() {
+            return mIsVerifyUnlockOnly;
+        }
+
+        public void reportSuccessfulUnlockAttempt() {
+            KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts();
+            mLockPatternUtils.reportSuccessfulPasswordAttempt();
+        }
+
+        public void reportFailedUnlockAttempt() {
+            if (mCurrentSecuritySelection == SecurityMode.Biometric) {
+                KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt();
+            } else {
+                KeyguardHostView.this.reportFailedUnlockAttempt();
+            }
+        }
+
+        public int getFailedAttempts() {
+            return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
+        }
+
+        @Override
+        public void showBackupSecurity() {
+            KeyguardHostView.this.showBackupSecurityScreen();
+        }
+
+        @Override
+        public void setOnDismissAction(OnDismissAction action) {
+            KeyguardHostView.this.setOnDismissAction(action);
+        }
+
+    };
+
+    private void showDialog(String title, String message) {
+        final AlertDialog dialog = new AlertDialog.Builder(mContext)
+            .setTitle(title)
+            .setMessage(message)
+            .setNeutralButton(R.string.ok, null)
+            .create();
+        if (!(mContext instanceof Activity)) {
+            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        }
+        dialog.show();
+    }
+
+    private void showTimeoutDialog() {
+        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
+        int messageId = 0;
+
+        switch (mSecurityModel.getSecurityMode()) {
+            case Pattern:
+                messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
+                break;
+            case PIN:
+                messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
+                break;
+            case Password:
+                messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
+                break;
+        }
+
+        if (messageId != 0) {
+            final String message = mContext.getString(messageId,
+                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
+                    timeoutInSeconds);
+            showDialog(null, message);
+        }
+    }
+
+    private void showAlmostAtWipeDialog(int attempts, int remaining) {
+        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
+        String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
+                attempts, remaining);
+        showDialog(null, message);
+    }
+
+    private void showWipeDialog(int attempts) {
+        String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts);
+        showDialog(null, message);
+    }
+
+    private void showAlmostAtAccountLoginDialog() {
+        final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
+        final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
+                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
+        String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login,
+                count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
+        showDialog(null, message);
+    }
+
+    private void reportFailedUnlockAttempt() {
+        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+        final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
+
+        if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
+
+        SecurityMode mode = mSecurityModel.getSecurityMode();
+        final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
+
+        final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
+                .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser());
+
+        final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
+                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
+
+        final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
+                (failedAttemptsBeforeWipe - failedAttempts)
+                : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
+
+        boolean showTimeout = false;
+        if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
+            // If we reach this code, it means the user has installed a DevicePolicyManager
+            // that requests device wipe after N attempts.  Once we get below the grace
+            // period, we'll post this dialog every time as a clear warning until the
+            // bombshell hits and the device is wiped.
+            if (remainingBeforeWipe > 0) {
+                showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
+            } else {
+                // Too many attempts. The device will be wiped shortly.
+                Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
+                showWipeDialog(failedAttempts);
+            }
+        } else {
+            showTimeout =
+                (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
+            if (usingPattern && mEnableFallback) {
+                if (failedAttempts == failedAttemptWarning) {
+                    showAlmostAtAccountLoginDialog();
+                    showTimeout = false; // don't show both dialogs
+                } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
+                    mLockPatternUtils.setPermanentlyLocked(true);
+                    showSecurityScreen(SecurityMode.Account);
+                    // don't show timeout dialog because we show account unlock screen next
+                    showTimeout = false;
+                }
+            }
+        }
+        monitor.reportFailedUnlockAttempt();
+        mLockPatternUtils.reportFailedPasswordAttempt();
+        if (showTimeout) {
+            showTimeoutDialog();
+        }
+    }
+
+    /**
+     * Shows the primary security screen for the user. This will be either the multi-selector
+     * or the user's security method.
+     * @param turningOff true if the device is being turned off
+     */
+    void showPrimarySecurityScreen(boolean turningOff) {
+        SecurityMode securityMode = mSecurityModel.getSecurityMode();
+        if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
+        if (!turningOff &&
+                KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) {
+            // If we're not turning off, then allow biometric alternate.
+            // We'll reload it when the device comes back on.
+            securityMode = mSecurityModel.getAlternateFor(securityMode);
+        }
+        showSecurityScreen(securityMode);
+    }
+
+    /**
+     * Shows the backup security screen for the current security mode.  This could be used for
+     * password recovery screens but is currently only used for pattern unlock to show the
+     * account unlock screen and biometric unlock to show the user's normal unlock.
+     */
+    private void showBackupSecurityScreen() {
+        if (DEBUG) Log.d(TAG, "showBackupSecurity()");
+        SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection);
+        showSecurityScreen(backup);
+    }
+
+    public boolean showNextSecurityScreenIfPresent() {
+        SecurityMode securityMode = mSecurityModel.getSecurityMode();
+        // Allow an alternate, such as biometric unlock
+        securityMode = mSecurityModel.getAlternateFor(securityMode);
+        if (SecurityMode.None == securityMode) {
+            return false;
+        } else {
+            showSecurityScreen(securityMode); // switch to the alternate security view
+            return true;
+        }
+    }
+
+    private void showNextSecurityScreenOrFinish(boolean authenticated) {
+        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
+        boolean finish = false;
+        if (SecurityMode.None == mCurrentSecuritySelection) {
+            SecurityMode securityMode = mSecurityModel.getSecurityMode();
+            // Allow an alternate, such as biometric unlock
+            securityMode = mSecurityModel.getAlternateFor(securityMode);
+            if (SecurityMode.None == securityMode) {
+                finish = true; // no security required
+            } else {
+                showSecurityScreen(securityMode); // switch to the alternate security view
+            }
+        } else if (authenticated) {
+            switch (mCurrentSecuritySelection) {
+                case Pattern:
+                case Password:
+                case PIN:
+                case Account:
+                case Biometric:
+                    finish = true;
+                    break;
+
+                case SimPin:
+                case SimPuk:
+                    // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
+                    SecurityMode securityMode = mSecurityModel.getSecurityMode();
+                    if (securityMode != SecurityMode.None) {
+                        showSecurityScreen(securityMode);
+                    } else {
+                        finish = true;
+                    }
+                    break;
+
+                default:
+                    Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
+                    showPrimarySecurityScreen(false);
+                    break;
+            }
+        } else {
+            showPrimarySecurityScreen(false);
+        }
+        if (finish) {
+            // If the alternate unlock was suppressed, it can now be safely
+            // enabled because the user has left keyguard.
+            KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+
+            // If there's a pending runnable because the user interacted with a widget
+            // and we're leaving keyguard, then run it.
+            boolean deferKeyguardDone = false;
+            if (mDismissAction != null) {
+                deferKeyguardDone = mDismissAction.onDismiss();
+                mDismissAction = null;
+            }
+            if (mViewMediatorCallback != null) {
+                if (deferKeyguardDone) {
+                    mViewMediatorCallback.keyguardDonePending();
+                } else {
+                    mViewMediatorCallback.keyguardDone(true);
+                }
+            }
+        } else {
+            mViewStateManager.showBouncer(true);
+        }
+    }
+
+    private static class MyOnClickHandler extends OnClickHandler {
+
+        // weak reference to the hostView to avoid keeping a live reference
+        // due to Binder GC linkages to AppWidgetHost. By the same token,
+        // this click handler should not keep references to any large
+        // objects.
+        WeakReference<KeyguardHostView> mThis;
+
+        MyOnClickHandler(KeyguardHostView hostView) {
+            mThis = new WeakReference<KeyguardHostView>(hostView);
+        }
+
+        @Override
+        public boolean onClickHandler(final View view,
+                final android.app.PendingIntent pendingIntent,
+                final Intent fillInIntent) {
+            KeyguardHostView hostView = mThis.get();
+            if (hostView == null) {
+                return false;
+            }
+            if (pendingIntent.isActivity()) {
+                hostView.setOnDismissAction(new OnDismissAction() {
+                    public boolean onDismiss() {
+                        try {
+                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
+                            Context context = view.getContext();
+                            ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
+                                    0, 0,
+                                    view.getMeasuredWidth(), view.getMeasuredHeight());
+                            context.startIntentSender(
+                                    pendingIntent.getIntentSender(), fillInIntent,
+                                    Intent.FLAG_ACTIVITY_NEW_TASK,
+                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
+                        } catch (IntentSender.SendIntentException e) {
+                            android.util.Log.e(TAG, "Cannot send pending intent: ", e);
+                        } catch (Exception e) {
+                            android.util.Log.e(TAG, "Cannot send pending intent due to " +
+                                    "unknown exception: ", e);
+                        }
+                        return false;
+                    }
+                });
+
+                if (hostView.mViewStateManager.isChallengeShowing()) {
+                    hostView.mViewStateManager.showBouncer(true);
+                } else {
+                    hostView.mCallback.dismiss(false);
+                }
+                return true;
+            } else {
+                return super.onClickHandler(view, pendingIntent, fillInIntent);
+            }
+        };
+    };
+
+    // Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
+    // This avoids unwanted asynchronous events from messing with the state.
+    private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
+
+        @Override
+        public void userActivity(long timeout) {
+        }
+
+        @Override
+        public void showBackupSecurity() {
+        }
+
+        @Override
+        public void setOnDismissAction(OnDismissAction action) {
+        }
+
+        @Override
+        public void reportSuccessfulUnlockAttempt() {
+        }
+
+        @Override
+        public void reportFailedUnlockAttempt() {
+        }
+
+        @Override
+        public boolean isVerifyUnlockOnly() {
+            return false;
+        }
+
+        @Override
+        public int getFailedAttempts() {
+            return 0;
+        }
+
+        @Override
+        public void dismiss(boolean securityVerified) {
+        }
+    };
+
+    /**
+     * Sets an action to perform when keyguard is dismissed.
+     * @param action
+     */
+    protected void setOnDismissAction(OnDismissAction action) {
+        mDismissAction = action;
+    }
+
+    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
+        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
+        KeyguardSecurityView view = null;
+        final int children = mSecurityViewContainer.getChildCount();
+        for (int child = 0; child < children; child++) {
+            if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) {
+                view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child));
+                break;
+            }
+        }
+        int layoutId = getLayoutIdFor(securityMode);
+        if (view == null && layoutId != 0) {
+            final LayoutInflater inflater = LayoutInflater.from(mContext);
+            if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
+            View v = inflater.inflate(layoutId, mSecurityViewContainer, false);
+            mSecurityViewContainer.addView(v);
+            updateSecurityView(v);
+            view = (KeyguardSecurityView)v;
+        }
+
+        if (view instanceof KeyguardSelectorView) {
+            KeyguardSelectorView selectorView = (KeyguardSelectorView) view;
+            View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container);
+            selectorView.setCarrierArea(carrierText);
+        }
+
+        return view;
+    }
+
+    /**
+     * Switches to the given security view unless it's already being shown, in which case
+     * this is a no-op.
+     *
+     * @param securityMode
+     */
+    private void showSecurityScreen(SecurityMode securityMode) {
+        if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
+
+        if (securityMode == mCurrentSecuritySelection) return;
+
+        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
+        KeyguardSecurityView newView = getSecurityView(securityMode);
+
+        // Enter full screen mode if we're in SIM or Account screen
+        boolean fullScreenEnabled = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
+        boolean isSimOrAccount = securityMode == SecurityMode.SimPin
+                || securityMode == SecurityMode.SimPuk
+                || securityMode == SecurityMode.Account;
+        mAppWidgetContainer.setVisibility(
+                isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE);
+
+        if (mSlidingChallengeLayout != null) {
+            mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled);
+        }
+
+        // Emulate Activity life cycle
+        if (oldView != null) {
+            oldView.onPause();
+            oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
+        }
+        newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
+        newView.setKeyguardCallback(mCallback);
+
+        final boolean needsInput = newView.needsInput();
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.setNeedsInput(needsInput);
+        }
+
+        // Find and show this child.
+        final int childCount = mSecurityViewContainer.getChildCount();
+
+        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
+        for (int i = 0; i < childCount; i++) {
+            if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
+                mSecurityViewContainer.setDisplayedChild(i);
+                break;
+            }
+        }
+
+        if (securityMode == SecurityMode.None) {
+            // Discard current runnable if we're switching back to the selector view
+            setOnDismissAction(null);
+        }
+        if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
+            // we're showing account as a backup, provide a way to get back to primary
+            setBackButtonEnabled(true);
+        }
+        mCurrentSecuritySelection = securityMode;
+    }
+
+    @Override
+    public void onScreenTurnedOn() {
+        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+        mIsScreenOn = true;
+        showPrimarySecurityScreen(false);
+        getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON);
+
+        // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
+        // layout is blank but forcing a layout causes it to reappear (e.g. with with
+        // hierarchyviewer).
+        requestLayout();
+
+        if (mViewStateManager != null) {
+            mViewStateManager.showUsabilityHints();
+        }
+
+        requestFocus();
+    }
+
+    @Override
+    public void onScreenTurnedOff() {
+        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
+                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
+        mIsScreenOn = false;
+        // Once the screen turns off, we no longer consider this to be first boot and we want the
+        // biometric unlock to start next time keyguard is shown.
+        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+        // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
+        // turns off we reset that behavior
+        clearAppWidgetToShow();
+        checkAppWidgetConsistency();
+        showPrimarySecurityScreen(true);
+        getSecurityView(mCurrentSecuritySelection).onPause();
+        CameraWidgetFrame cameraPage = findCameraPage();
+        if (cameraPage != null) {
+            cameraPage.onScreenTurnedOff();
+        }
+
+        clearFocus();
+    }
+
+    public void clearAppWidgetToShow() {
+        mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
+    }
+
+    @Override
+    public void show() {
+        if (DEBUG) Log.d(TAG, "show()");
+        showPrimarySecurityScreen(false);
+    }
+
+    @Override
+    public void verifyUnlock() {
+        SecurityMode securityMode = mSecurityModel.getSecurityMode();
+        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.keyguardDone(true);
+            }
+        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
+                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
+                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
+            // can only verify unlock when in pattern/password mode
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.keyguardDone(false);
+            }
+        } else {
+            // otherwise, go to the unlock screen, see if they can verify it
+            mIsVerifyUnlockOnly = true;
+            showSecurityScreen(securityMode);
+        }
+    }
+
+    private int getSecurityViewIdForMode(SecurityMode securityMode) {
+        switch (securityMode) {
+            case None: return R.id.keyguard_selector_view;
+            case Pattern: return R.id.keyguard_pattern_view;
+            case PIN: return R.id.keyguard_pin_view;
+            case Password: return R.id.keyguard_password_view;
+            case Biometric: return R.id.keyguard_face_unlock_view;
+            case Account: return R.id.keyguard_account_view;
+            case SimPin: return R.id.keyguard_sim_pin_view;
+            case SimPuk: return R.id.keyguard_sim_puk_view;
+        }
+        return 0;
+    }
+
+    private int getLayoutIdFor(SecurityMode securityMode) {
+        switch (securityMode) {
+            case None: return R.layout.keyguard_selector_view;
+            case Pattern: return R.layout.keyguard_pattern_view;
+            case PIN: return R.layout.keyguard_pin_view;
+            case Password: return R.layout.keyguard_password_view;
+            case Biometric: return R.layout.keyguard_face_unlock_view;
+            case Account: return R.layout.keyguard_account_view;
+            case SimPin: return R.layout.keyguard_sim_pin_view;
+            case SimPuk: return R.layout.keyguard_sim_puk_view;
+            default:
+                return 0;
+        }
+    }
+
+    private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
+        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
+        if (appWidgetInfo != null) {
+            AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo);
+            addWidget(view, pageIndex);
+            return true;
+        } else {
+            if (updateDbIfFailed) {
+                Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + "  was null for user"
+                        + mUserId + ", deleting");
+                mAppWidgetHost.deleteAppWidgetId(appId);
+                mLockPatternUtils.removeAppWidget(appId);
+            }
+            return false;
+        }
+    }
+
+    private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks =
+        new CameraWidgetFrame.Callbacks() {
+            @Override
+            public void onLaunchingCamera() {
+                setSliderHandleAlpha(0);
+            }
+
+            @Override
+            public void onCameraLaunchedSuccessfully() {
+                if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) {
+                    mAppWidgetContainer.scrollLeft();
+                }
+                setSliderHandleAlpha(1);
+                mShowSecurityWhenReturn = true;
+            }
+
+            @Override
+            public void onCameraLaunchedUnsuccessfully() {
+                setSliderHandleAlpha(1);
+            }
+
+            private void setSliderHandleAlpha(float alpha) {
+                SlidingChallengeLayout slider =
+                        (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
+                if (slider != null) {
+                    slider.setHandleAlpha(alpha);
+                }
+            }
+        };
+
+    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
+        @Override
+        Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        KeyguardSecurityCallback getCallback() {
+            return mCallback;
+        }
+
+        @Override
+        LockPatternUtils getLockPatternUtils() {
+            return mLockPatternUtils;
+        }
+    };
+
+    private int numWidgets() {
+        final int childCount = mAppWidgetContainer.getChildCount();
+        int widgetCount = 0;
+        for (int i = 0; i < childCount; i++) {
+            if (mAppWidgetContainer.isWidgetPage(i)) {
+                widgetCount++;
+            }
+        }
+        return widgetCount;
+    }
+
+    private void addDefaultWidgets() {
+        if (!mSafeModeEnabled && !widgetsDisabled()) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
+            mAppWidgetContainer.addWidget(addWidget, 0);
+            View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
+            addWidgetButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    // Pass in an invalid widget id... the picker will allocate an ID for us
+                    mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
+                }
+            });
+        }
+
+        // We currently disable cameras in safe mode because we support loading 3rd party
+        // cameras we can't trust.  TODO: plumb safe mode into camera creation code and only
+        // inflate system-provided camera?
+        if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
+                && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
+            View cameraWidget =
+                    CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
+            if (cameraWidget != null) {
+                mAppWidgetContainer.addWidget(cameraWidget);
+            }
+        }
+
+        enableUserSelectorIfNecessary();
+    }
+
+    /**
+     * Create KeyguardTransportControlView on demand.
+     * @return
+     */
+    private KeyguardTransportControlView getOrCreateTransportControl() {
+        if (mTransportControl == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            mTransportControl = (KeyguardTransportControlView)
+                    inflater.inflate(R.layout.keyguard_transport_control_view, this, false);
+        }
+        return mTransportControl;
+    }
+
+    private int getInsertPageIndex() {
+        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
+        int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget);
+        if (insertionIndex < 0) {
+            insertionIndex = 0; // no add widget page found
+        } else {
+            insertionIndex++; // place after add widget
+        }
+        return insertionIndex;
+    }
+
+    private void addDefaultStatusWidget(int index) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
+        mAppWidgetContainer.addWidget(statusWidget, index);
+    }
+
+    private void addWidgetsFromSettings() {
+        if (mSafeModeEnabled || widgetsDisabled()) {
+            addDefaultStatusWidget(0);
+            return;
+        }
+
+        int insertionIndex = getInsertPageIndex();
+
+        // Add user-selected widget
+        final int[] widgets = mLockPatternUtils.getAppWidgets();
+
+        if (widgets == null) {
+            Log.d(TAG, "Problem reading widgets");
+        } else {
+            for (int i = widgets.length -1; i >= 0; i--) {
+                if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
+                    addDefaultStatusWidget(insertionIndex);
+                } else {
+                    // We add the widgets from left to right, starting after the first page after
+                    // the add page. We count down, since the order will be persisted from right
+                    // to left, starting after camera.
+                    addWidget(widgets[i], insertionIndex, true);
+                }
+            }
+        }
+    }
+
+    private int allocateIdForDefaultAppWidget() {
+        int appWidgetId;
+        Resources res = getContext().getResources();
+        ComponentName defaultAppWidget = new ComponentName(
+                res.getString(R.string.widget_default_package_name),
+                res.getString(R.string.widget_default_class_name));
+
+        // Note: we don't support configuring the widget
+        appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+
+        try {
+            mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
+            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+            appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+        return appWidgetId;
+    }
+
+    public void checkAppWidgetConsistency() {
+        // Since this method may bind a widget (which we can't do until boot completed) we
+        // may have to defer it until after boot complete.
+        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
+            mCheckAppWidgetConsistencyOnBootCompleted = true;
+            return;
+        }
+        final int childCount = mAppWidgetContainer.getChildCount();
+        boolean widgetPageExists = false;
+        for (int i = 0; i < childCount; i++) {
+            if (mAppWidgetContainer.isWidgetPage(i)) {
+                widgetPageExists = true;
+                break;
+            }
+        }
+        if (!widgetPageExists) {
+            final int insertPageIndex = getInsertPageIndex();
+
+            final boolean userAddedWidgetsEnabled = !widgetsDisabled();
+
+            boolean addedDefaultAppWidget = false;
+
+            if (!mSafeModeEnabled) {
+                if (userAddedWidgetsEnabled) {
+                    int appWidgetId = allocateIdForDefaultAppWidget();
+                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
+                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true);
+                    }
+                } else {
+                    // note: even if widgetsDisabledByDpm() returns true, we still bind/create
+                    // the default appwidget if possible
+                    int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId();
+                    if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+                        appWidgetId = allocateIdForDefaultAppWidget();
+                        if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
+                            mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId);
+                        }
+                    }
+                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
+                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false);
+                        if (!addedDefaultAppWidget) {
+                            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                            mLockPatternUtils.writeFallbackAppWidgetId(
+                                    AppWidgetManager.INVALID_APPWIDGET_ID);
+                        }
+                    }
+                }
+            }
+
+            // Use the built-in status/clock view if we can't inflate the default widget
+            if (!addedDefaultAppWidget) {
+                addDefaultStatusWidget(insertPageIndex);
+            }
+
+            // trigger DB updates only if user-added widgets are enabled
+            if (!mSafeModeEnabled && userAddedWidgetsEnabled) {
+                mAppWidgetContainer.onAddView(
+                        mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex);
+            }
+        }
+    }
+
+    Runnable mSwitchPageRunnable = new Runnable() {
+        @Override
+        public void run() {
+           showAppropriateWidgetPage();
+        }
+    };
+
+    static class SavedState extends BaseSavedState {
+        int transportState;
+        int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
+        Rect insets = new Rect();
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            this.transportState = in.readInt();
+            this.appWidgetToShow = in.readInt();
+            this.insets = in.readParcelable(null);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(this.transportState);
+            out.writeInt(this.appWidgetToShow);
+            out.writeParcelable(insets, 0);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        if (DEBUG) Log.d(TAG, "onSaveInstanceState, tstate=" + mTransportState);
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        // If the transport is showing, force it to show it on restore.
+        final boolean showing = mTransportControl != null
+                && mAppWidgetContainer.getWidgetPageIndex(mTransportControl) >= 0;
+        ss.transportState =  showing ? TRANSPORT_VISIBLE : mTransportState;
+        ss.appWidgetToShow = mAppWidgetToShow;
+        ss.insets.set(mInsets);
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        mTransportState = (ss.transportState);
+        mAppWidgetToShow = ss.appWidgetToShow;
+        setInsets(ss.insets);
+        if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState);
+        post(mSwitchPageRunnable);
+    }
+
+    @Override
+    protected boolean fitSystemWindows(Rect insets) {
+        setInsets(insets);
+        return true;
+    }
+
+    private void setInsets(Rect insets) {
+        mInsets.set(insets);
+        if (mSlidingChallengeLayout != null) mSlidingChallengeLayout.setInsets(mInsets);
+        if (mMultiPaneChallengeLayout != null) mMultiPaneChallengeLayout.setInsets(mInsets);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
+        if (hasWindowFocus && mShowSecurityWhenReturn) {
+            SlidingChallengeLayout slider =
+                (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
+            if (slider != null) {
+                slider.setHandleAlpha(1);
+                slider.showChallenge(true);
+            }
+            mShowSecurityWhenReturn = false;
+        }
+    }
+
+    private void showAppropriateWidgetPage() {
+        int state = mTransportState;
+        ensureTransportPresentOrRemoved(state);
+        int pageToShow = getAppropriateWidgetPage(state);
+        mAppWidgetContainer.setCurrentPage(pageToShow);
+    }
+
+    /**
+     * Examines the current state and adds the transport to the widget pager when the state changes.
+     *
+     * Showing the initial transport and keeping it around is a bit tricky because the signals
+     * coming from music players aren't always clear. Here's how the states are handled:
+     *
+     * {@link TRANSPORT_GONE} means we have no reason to show the transport - remove it if present.
+     *
+     * {@link TRANSPORT_INVISIBLE} means we have potential to show the transport because a music
+     * player is registered but not currently playing music (or we don't know the state yet). The
+     * code adds it conditionally on play state.
+     *
+     * {@link #TRANSPORT_VISIBLE} means a music player is active and transport should be showing.
+     *
+     * Once the transport is showing, we always show it until keyguard is dismissed. This state is
+     * maintained by onSave/RestoreInstanceState(). This state is cleared in
+     * {@link KeyguardViewManager#hide} when keyguard is dismissed, which causes the transport to be
+     * gone when keyguard is restarted until we get an update with the current state.
+     *
+     * @param state
+     */
+    private void ensureTransportPresentOrRemoved(int state) {
+        final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1;
+        final boolean visible = state == TRANSPORT_VISIBLE;
+        final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state);
+        if (!showing && (visible || shouldBeVisible)) {
+            if (DEBUGXPORT) Log.v(TAG, "add transport");
+            // insert to left of camera if it exists, otherwise after right-most widget
+            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
+            int position = 0; // handle no widget case
+            if (lastWidget >= 0) {
+                position = mAppWidgetContainer.isCameraPage(lastWidget) ?
+                        lastWidget : lastWidget + 1;
+            }
+            mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position);
+        } else if (showing && state == TRANSPORT_GONE) {
+            if (DEBUGXPORT) Log.v(TAG, "remove transport");
+            mAppWidgetContainer.removeWidget(getOrCreateTransportControl());
+            mTransportControl = null;
+            KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
+        }
+    }
+
+    private CameraWidgetFrame findCameraPage() {
+        for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
+            if (mAppWidgetContainer.isCameraPage(i)) {
+                return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i);
+            }
+        }
+        return null;
+    }
+
+    boolean isMusicPage(int pageIndex) {
+        return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
+    }
+
+    private int getAppropriateWidgetPage(int musicTransportState) {
+        // assumes at least one widget (besides camera + add)
+        if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
+            final int childCount = mAppWidgetContainer.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId()
+                        == mAppWidgetToShow) {
+                    return i;
+                }
+            }
+            mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+        // if music playing, show transport
+        if (musicTransportState == TRANSPORT_VISIBLE) {
+            if (DEBUG) Log.d(TAG, "Music playing, show transport");
+            return mAppWidgetContainer.getWidgetPageIndex(getOrCreateTransportControl());
+        }
+
+        // else show the right-most widget (except for camera)
+        int rightMost = mAppWidgetContainer.getChildCount() - 1;
+        if (mAppWidgetContainer.isCameraPage(rightMost)) {
+            rightMost--;
+        }
+        if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost);
+        return rightMost;
+    }
+
+    private void enableUserSelectorIfNecessary() {
+        if (!UserManager.supportsMultipleUsers()) {
+            return; // device doesn't support multi-user mode
+        }
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (um == null) {
+            Throwable t = new Throwable();
+            t.fillInStackTrace();
+            Log.e(TAG, "user service is null.", t);
+            return;
+        }
+
+        // if there are multiple users, we need to enable to multi-user switcher
+        final List<UserInfo> users = um.getUsers(true);
+        if (users == null) {
+            Throwable t = new Throwable();
+            t.fillInStackTrace();
+            Log.e(TAG, "list of users is null.", t);
+            return;
+        }
+
+        final View multiUserView = findViewById(R.id.keyguard_user_selector);
+        if (multiUserView == null) {
+            Throwable t = new Throwable();
+            t.fillInStackTrace();
+            Log.e(TAG, "can't find user_selector in layout.", t);
+            return;
+        }
+
+        if (users.size() > 1) {
+            if (multiUserView instanceof KeyguardMultiUserSelectorView) {
+                mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
+                mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
+                mKeyguardMultiUserSelectorView.addUsers(users);
+                UserSwitcherCallback callback = new UserSwitcherCallback() {
+                    @Override
+                    public void hideSecurityView(int duration) {
+                        mSecurityViewContainer.animate().alpha(0).setDuration(duration);
+                    }
+
+                    @Override
+                    public void showSecurityView() {
+                        mSecurityViewContainer.setAlpha(1.0f);
+                    }
+
+                    @Override
+                    public void showUnlockHint() {
+                        if (mKeyguardSelectorView != null) {
+                            mKeyguardSelectorView.showUsabilityHint();
+                        }
+                    }
+
+                    @Override
+                    public void userActivity() {
+                        if (mViewMediatorCallback != null) {
+                            mViewMediatorCallback.userActivity();
+                        }
+                    }
+                };
+                mKeyguardMultiUserSelectorView.setCallback(callback);
+            } else {
+                Throwable t = new Throwable();
+                t.fillInStackTrace();
+                if (multiUserView == null) {
+                    Log.e(TAG, "could not find the user_selector.", t);
+                } else {
+                    Log.e(TAG, "user_selector is the wrong type.", t);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void cleanUp() {
+        // Make sure we let go of all widgets and their package contexts promptly. If we don't do
+        // this, and the associated application is uninstalled, it can cause a soft reboot.
+        int count = mAppWidgetContainer.getChildCount();
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame frame = mAppWidgetContainer.getWidgetPageAt(i);
+            frame.removeAllViews();
+        }
+    }
+
+    /**
+     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+     * some cases where we wish to disable it, notably when the menu button placement or technology
+     * is prone to false positives.
+     *
+     * @return true if the menu key should be enabled
+     */
+    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+    private boolean shouldEnableMenuKey() {
+        final Resources res = getResources();
+        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+        return !configDisabled || isTestHarness || fileOverride;
+    }
+
+    public void goToWidget(int appWidgetId) {
+        mAppWidgetToShow = appWidgetId;
+        mSwitchPageRunnable.run();
+    }
+
+    public boolean handleMenuKey() {
+        // The following enables the MENU key to work for testing automation
+        if (shouldEnableMenuKey()) {
+            showNextSecurityScreenOrFinish(false);
+            return true;
+        }
+        return false;
+    }
+
+    public boolean handleBackKey() {
+        if (mCurrentSecuritySelection == SecurityMode.Account) {
+            // go back to primary screen and re-disable back
+            setBackButtonEnabled(false);
+            showPrimarySecurityScreen(false /*turningOff*/);
+            return true;
+        }
+        if (mCurrentSecuritySelection != SecurityMode.None) {
+            mCallback.dismiss(false);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     *  Dismisses the keyguard by going to the next screen or making it gone.
+     */
+    public void dismiss() {
+        showNextSecurityScreenOrFinish(false);
+    }
+
+    public void showAssistant() {
+        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
+
+        if (intent == null) return;
+
+        final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+                R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
+                getHandler(), null);
+
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        mActivityLauncher.launchActivityWithAnimation(
+                intent, false, opts.toBundle(), null, null);
+    }
+
+    public void dispatch(MotionEvent event) {
+        mAppWidgetContainer.handleExternalCameraEvent(event);
+    }
+
+    public void launchCamera() {
+        mActivityLauncher.launchCamera(getHandler(), null);
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardLinearLayout.java b/packages/Keyguard/src/com/android/keyguard/KeyguardLinearLayout.java
new file mode 100644
index 0000000..343fdcb
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardLinearLayout.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * A layout that arranges its children into a special type of grid.
+ */
+public class KeyguardLinearLayout extends LinearLayout {
+    int mTopChild = 0;
+
+    public KeyguardLinearLayout(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardLinearLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setTopChild(View child) {
+        int top = indexOfChild(child);
+        mTopChild = top;
+        invalidate();
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
new file mode 100644
index 0000000..ad59c02
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
@@ -0,0 +1,318 @@
+/*
+ * 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.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.TextView;
+
+import libcore.util.MutableInt;
+
+import java.lang.ref.WeakReference;
+
+import com.android.internal.widget.LockPatternUtils;
+
+/***
+ * Manages a number of views inside of the given layout. See below for a list of widgets.
+ */
+class KeyguardMessageArea extends TextView {
+    /** Handler token posted with accessibility announcement runnables. */
+    private static final Object ANNOUNCE_TOKEN = new Object();
+
+    /**
+     * Delay before speaking an accessibility announcement. Used to prevent
+     * lift-to-type from interrupting itself.
+     */
+    private static final long ANNOUNCEMENT_DELAY = 250;
+
+    static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging;
+    static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
+
+    static final int SECURITY_MESSAGE_DURATION = 5000;
+    protected static final int FADE_DURATION = 750;
+
+    private static final String TAG = "KeyguardMessageArea";
+
+    // are we showing battery information?
+    boolean mShowingBatteryInfo = false;
+
+    // is the bouncer up?
+    boolean mShowingBouncer = false;
+
+    // last known plugged in state
+    boolean mCharging = false;
+
+    // last known battery level
+    int mBatteryLevel = 100;
+
+    KeyguardUpdateMonitor mUpdateMonitor;
+
+    // Timeout before we reset the message to show charging/owner info
+    long mTimeout = SECURITY_MESSAGE_DURATION;
+
+    // Shadowed text values
+    protected boolean mBatteryCharged;
+    protected boolean mBatteryIsLow;
+
+    private Handler mHandler;
+
+    CharSequence mMessage;
+    boolean mShowingMessage;
+    private CharSequence mSeparator;
+    private LockPatternUtils mLockPatternUtils;
+
+    Runnable mClearMessageRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mMessage = null;
+            mShowingMessage = false;
+            if (mShowingBouncer) {
+                hideMessage(FADE_DURATION, true);
+            } else {
+                update();
+            }
+        }
+    };
+
+    public static class Helper implements SecurityMessageDisplay {
+        KeyguardMessageArea mMessageArea;
+        Helper(View v) {
+            mMessageArea = (KeyguardMessageArea) v.findViewById(R.id.keyguard_message_area);
+            if (mMessageArea == null) {
+                throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass());
+            }
+        }
+
+        public void setMessage(CharSequence msg, boolean important) {
+            if (!TextUtils.isEmpty(msg) && important) {
+                mMessageArea.mMessage = msg;
+                mMessageArea.securityMessageChanged();
+            }
+        }
+
+        public void setMessage(int resId, boolean important) {
+            if (resId != 0 && important) {
+                mMessageArea.mMessage = mMessageArea.getContext().getResources().getText(resId);
+                mMessageArea.securityMessageChanged();
+            }
+        }
+
+        public void setMessage(int resId, boolean important, Object... formatArgs) {
+            if (resId != 0 && important) {
+                mMessageArea.mMessage = mMessageArea.getContext().getString(resId, formatArgs);
+                mMessageArea.securityMessageChanged();
+            }
+        }
+
+        @Override
+        public void showBouncer(int duration) {
+            mMessageArea.hideMessage(duration, false);
+            mMessageArea.mShowingBouncer = true;
+        }
+
+        @Override
+        public void hideBouncer(int duration) {
+            mMessageArea.showMessage(duration);
+            mMessageArea.mShowingBouncer = false;
+        }
+
+        @Override
+        public void setTimeout(int timeoutMs) {
+            mMessageArea.mTimeout = timeoutMs;
+        }
+    }
+
+    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
+            mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow();
+            mCharging = status.status == BatteryManager.BATTERY_STATUS_CHARGING
+                     || status.status == BatteryManager.BATTERY_STATUS_FULL;
+            mBatteryLevel = status.level;
+            mBatteryCharged = status.isCharged();
+            mBatteryIsLow = status.isBatteryLow();
+            update();
+        }
+    };
+
+    public KeyguardMessageArea(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardMessageArea(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mLockPatternUtils = new LockPatternUtils(context);
+
+        // This is required to ensure marquee works
+        setSelected(true);
+
+        // Registering this callback immediately updates the battery state, among other things.
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
+        mUpdateMonitor.registerCallback(mInfoCallback);
+        mHandler = new Handler(Looper.myLooper());
+
+        mSeparator = getResources().getString(R.string.kg_text_message_separator);
+
+        update();
+    }
+
+    public void securityMessageChanged() {
+        setAlpha(1f);
+        mShowingMessage = true;
+        update();
+        mHandler.removeCallbacks(mClearMessageRunnable);
+        if (mTimeout > 0) {
+            mHandler.postDelayed(mClearMessageRunnable, mTimeout);
+        }
+        mHandler.removeCallbacksAndMessages(ANNOUNCE_TOKEN);
+        mHandler.postAtTime(new AnnounceRunnable(this, getText()), ANNOUNCE_TOKEN,
+                (SystemClock.uptimeMillis() + ANNOUNCEMENT_DELAY));
+    }
+
+    /**
+     * Update the status lines based on these rules:
+     * AlarmStatus: Alarm state always gets it's own line.
+     * Status1 is shared between help, battery status and generic unlock instructions,
+     * prioritized in that order.
+     * @param showStatusLines status lines are shown if true
+     */
+    void update() {
+        MutableInt icon = new MutableInt(0);
+        CharSequence status = concat(getChargeInfo(icon), getOwnerInfo(), getCurrentMessage());
+        setCompoundDrawablesWithIntrinsicBounds(icon.value, 0, 0, 0);
+        setText(status);
+    }
+
+    private CharSequence concat(CharSequence... args) {
+        StringBuilder b = new StringBuilder();
+        if (!TextUtils.isEmpty(args[0])) {
+            b.append(args[0]);
+        }
+        for (int i = 1; i < args.length; i++) {
+            CharSequence text = args[i];
+            if (!TextUtils.isEmpty(text)) {
+                if (b.length() > 0) {
+                    b.append(mSeparator);
+                }
+                b.append(text);
+            }
+        }
+        return b.toString();
+    }
+
+    CharSequence getCurrentMessage() {
+        return mShowingMessage ? mMessage : null;
+    }
+
+    String getOwnerInfo() {
+        ContentResolver res = getContext().getContentResolver();
+        String info = null;
+        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+        if (ownerInfoEnabled && !mShowingMessage) {
+            info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+        }
+        return info;
+    }
+
+    private CharSequence getChargeInfo(MutableInt icon) {
+        CharSequence string = null;
+        if (mShowingBatteryInfo && !mShowingMessage) {
+            // Battery status
+            if (mCharging) {
+                // Charging, charged or waiting to charge.
+                string = getContext().getString(mBatteryCharged
+                        ? R.string.keyguard_charged
+                        : R.string.keyguard_plugged_in, mBatteryLevel);
+                icon.value = CHARGING_ICON;
+            } else if (mBatteryIsLow) {
+                // Battery is low
+                string = getContext().getString(R.string.keyguard_low_battery);
+                icon.value = BATTERY_LOW_ICON;
+            }
+        }
+        return string;
+    }
+
+    private void hideMessage(int duration, boolean thenUpdate) {
+        if (duration > 0) {
+            Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f);
+            anim.setDuration(duration);
+            if (thenUpdate) {
+                anim.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                            public void onAnimationEnd(Animator animation) {
+                            update();
+                        }
+                });
+            }
+            anim.start();
+        } else {
+            setAlpha(0f);
+            if (thenUpdate) {
+                update();
+            }
+        }
+    }
+
+    private void showMessage(int duration) {
+        if (duration > 0) {
+            Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f);
+            anim.setDuration(duration);
+            anim.start();
+        } else {
+            setAlpha(1f);
+        }
+    }
+
+    /**
+     * Runnable used to delay accessibility announcements.
+     */
+    private static class AnnounceRunnable implements Runnable {
+        private final WeakReference<View> mHost;
+        private final CharSequence mTextToAnnounce;
+
+        public AnnounceRunnable(View host, CharSequence textToAnnounce) {
+            mHost = new WeakReference<View>(host);
+            mTextToAnnounce = textToAnnounce;
+        }
+
+        @Override
+        public void run() {
+            final View host = mHost.get();
+            if (host != null) {
+                host.announceForAccessibility(mTextToAnnounce);
+            }
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
new file mode 100644
index 0000000..aa2ae0e
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+class KeyguardMultiUserAvatar extends FrameLayout {
+    private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName();
+    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+
+    private ImageView mUserImage;
+    private TextView mUserName;
+    private UserInfo mUserInfo;
+    private static final float ACTIVE_ALPHA = 1.0f;
+    private static final float INACTIVE_ALPHA = 1.0f;
+    private static final float ACTIVE_SCALE = 1.5f;
+    private static final float ACTIVE_TEXT_ALPHA = 0f;
+    private static final float INACTIVE_TEXT_ALPHA = 0.5f;
+    private static final int SWITCH_ANIMATION_DURATION = 150;
+
+    private final float mActiveAlpha;
+    private final float mActiveScale;
+    private final float mActiveTextAlpha;
+    private final float mInactiveAlpha;
+    private final float mInactiveTextAlpha;
+    private final float mShadowRadius;
+    private final float mStroke;
+    private final float mIconSize;
+    private final int mFrameColor;
+    private final int mFrameShadowColor;
+    private final int mTextColor;
+    private final int mHighlightColor;
+
+    private boolean mTouched;
+
+    private boolean mActive;
+    private boolean mInit = true;
+    private KeyguardMultiUserSelectorView mUserSelector;
+    private KeyguardCircleFramedDrawable mFramed;
+    private boolean mPressLock;
+    private UserManager mUserManager;
+
+    public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
+            KeyguardMultiUserSelectorView userSelector, UserInfo info) {
+        KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar)
+                LayoutInflater.from(context).inflate(resId, userSelector, false);
+
+        icon.init(info, userSelector);
+        return icon;
+    }
+
+    public KeyguardMultiUserAvatar(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        Resources res = mContext.getResources();
+        mTextColor = res.getColor(R.color.keyguard_avatar_nick_color);
+        mIconSize = res.getDimension(R.dimen.keyguard_avatar_size);
+        mStroke = res.getDimension(R.dimen.keyguard_avatar_frame_stroke_width);
+        mShadowRadius = res.getDimension(R.dimen.keyguard_avatar_frame_shadow_radius);
+        mFrameColor = res.getColor(R.color.keyguard_avatar_frame_color);
+        mFrameShadowColor = res.getColor(R.color.keyguard_avatar_frame_shadow_color);
+        mHighlightColor = res.getColor(R.color.keyguard_avatar_frame_pressed_color);
+        mActiveTextAlpha = ACTIVE_TEXT_ALPHA;
+        mInactiveTextAlpha = INACTIVE_TEXT_ALPHA;
+        mActiveScale = ACTIVE_SCALE;
+        mActiveAlpha = ACTIVE_ALPHA;
+        mInactiveAlpha = INACTIVE_ALPHA;
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        mTouched = false;
+
+        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+    }
+
+    protected String rewriteIconPath(String path) {
+        return path;
+    }
+
+    public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) {
+        mUserInfo = user;
+        mUserSelector = userSelector;
+
+        mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar);
+        mUserName = (TextView) findViewById(R.id.keyguard_user_name);
+
+        mFramed = (KeyguardCircleFramedDrawable)
+                KeyguardViewMediator.getAvatarCache().get(user.id);
+
+        // If we can't find it or the params don't match, create the drawable again
+        if (mFramed == null
+                || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor,
+                        mShadowRadius, mHighlightColor)) {
+            Bitmap icon = null;
+            try {
+                icon = mUserManager.getUserIcon(user.id);
+            } catch (Exception e) {
+                if (DEBUG) Log.d(TAG, "failed to get profile icon " + user, e);
+            }
+
+            if (icon == null) {
+                icon = BitmapFactory.decodeResource(mContext.getResources(),
+                        com.android.internal.R.drawable.ic_contact_picture);
+            }
+
+            mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
+                    mFrameShadowColor, mShadowRadius, mHighlightColor);
+            KeyguardViewMediator.getAvatarCache().put(user.id, mFramed);
+        }
+
+        mFramed.reset();
+
+        mUserImage.setImageDrawable(mFramed);
+        mUserName.setText(mUserInfo.name);
+        setOnClickListener(mUserSelector);
+        mInit = false;
+    }
+
+    public void setActive(boolean active, boolean animate, final Runnable onComplete) {
+        if (mActive != active || mInit) {
+            mActive = active;
+
+            if (active) {
+                KeyguardLinearLayout parent = (KeyguardLinearLayout) getParent();
+                parent.setTopChild(this);
+                // TODO: Create an appropriate asset when string changes are possible.
+                setContentDescription(mUserName.getText()
+                        + ". " + mContext.getString(R.string.user_switched, ""));
+            } else {
+                setContentDescription(mUserName.getText());
+            }
+        }
+        updateVisualsForActive(mActive, animate, SWITCH_ANIMATION_DURATION, onComplete);
+    }
+
+    void updateVisualsForActive(boolean active, boolean animate, int duration,
+            final Runnable onComplete) {
+        final float finalAlpha = active ? mActiveAlpha : mInactiveAlpha;
+        final float initAlpha = active ? mInactiveAlpha : mActiveAlpha;
+        final float finalScale = active ? 1f : 1f / mActiveScale;
+        final float initScale = mFramed.getScale();
+        final int finalTextAlpha = active ? (int) (mActiveTextAlpha * 255) :
+                (int) (mInactiveTextAlpha * 255);
+        final int initTextAlpha = active ? (int) (mInactiveTextAlpha * 255) :
+                (int) (mActiveTextAlpha * 255);
+        int textColor = mTextColor;
+        mUserName.setTextColor(textColor);
+
+        if (animate && mTouched) {
+            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+            va.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    float r = animation.getAnimatedFraction();
+                    float scale = (1 - r) * initScale + r * finalScale;
+                    float alpha = (1 - r) * initAlpha + r * finalAlpha;
+                    int textAlpha = (int) ((1 - r) * initTextAlpha + r * finalTextAlpha);
+                    mFramed.setScale(scale);
+                    mUserImage.setAlpha(alpha);
+                    mUserName.setTextColor(Color.argb(textAlpha, 255, 255, 255));
+                    mUserImage.invalidate();
+                }
+            });
+            va.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (onComplete != null) {
+                        onComplete.run();
+                    }
+                }
+            });
+            va.setDuration(duration);
+            va.start();
+        } else {
+            mFramed.setScale(finalScale);
+            mUserImage.setAlpha(finalAlpha);
+            mUserName.setTextColor(Color.argb(finalTextAlpha, 255, 255, 255));
+            if (onComplete != null) {
+                post(onComplete);
+            }
+        }
+
+        mTouched = true;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        if (mPressLock && !pressed) {
+            return;
+        }
+
+        if (mPressLock || !pressed || isClickable()) {
+            super.setPressed(pressed);
+            mFramed.setPressed(pressed);
+            mUserImage.invalidate();
+        }
+    }
+
+    public void lockPressed(boolean pressed) {
+        mPressLock = pressed;
+        setPressed(pressed);
+    }
+
+    public UserInfo getUserInfo() {
+        return mUserInfo;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
new file mode 100644
index 0000000..7975d8e
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+
+public class KeyguardMultiUserSelectorView extends FrameLayout implements View.OnClickListener {
+    private static final String TAG = "KeyguardMultiUserSelectorView";
+
+    private ViewGroup mUsersGrid;
+    private KeyguardMultiUserAvatar mActiveUserAvatar;
+    private KeyguardHostView.UserSwitcherCallback mCallback;
+    private static final int FADE_OUT_ANIMATION_DURATION = 100;
+
+    public KeyguardMultiUserSelectorView(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    protected void onFinishInflate () {
+        mUsersGrid = (ViewGroup) findViewById(R.id.keyguard_users_grid);
+        mUsersGrid.removeAllViews();
+        setClipChildren(false);
+        setClipToPadding(false);
+
+    }
+
+    public void setCallback(KeyguardHostView.UserSwitcherCallback callback) {
+        mCallback = callback;
+    }
+
+    public void addUsers(Collection<UserInfo> userList) {
+        UserInfo activeUser;
+        try {
+            activeUser = ActivityManagerNative.getDefault().getCurrentUser();
+        } catch (RemoteException re) {
+            activeUser = null;
+        }
+
+        ArrayList<UserInfo> users = new ArrayList<UserInfo>(userList);
+        Collections.sort(users, mOrderAddedComparator);
+
+        for (UserInfo user: users) {
+            KeyguardMultiUserAvatar uv = createAndAddUser(user);
+            if (user.id == activeUser.id) {
+                mActiveUserAvatar = uv;
+            }
+            uv.setActive(false, false, null);
+        }
+        mActiveUserAvatar.lockPressed(true);
+    }
+
+    public void finalizeActiveUserView(boolean animate) {
+        if (animate) {
+            getHandler().postDelayed(new Runnable() {
+                    @Override
+                        public void run() {
+                        finalizeActiveUserNow(true);
+                    }
+                }, 500);
+        } else {
+            finalizeActiveUserNow(animate);
+        }
+    }
+
+    void finalizeActiveUserNow(boolean animate) {
+        mActiveUserAvatar.lockPressed(false);
+        mActiveUserAvatar.setActive(true, animate, null);
+    }
+
+    Comparator<UserInfo> mOrderAddedComparator = new Comparator<UserInfo>() {
+        @Override
+        public int compare(UserInfo lhs, UserInfo rhs) {
+            return (lhs.serialNumber - rhs.serialNumber);
+        }
+    };
+
+    private KeyguardMultiUserAvatar createAndAddUser(UserInfo user) {
+        KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml(
+                R.layout.keyguard_multi_user_avatar, mContext, this, user);
+        mUsersGrid.addView(uv);
+        return uv;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        if(event.getActionMasked() != MotionEvent.ACTION_CANCEL && mCallback != null) {
+            mCallback.userActivity();
+        }
+        return false;
+    }
+
+    private void setAllClickable(boolean clickable)
+    {
+        for(int i = 0; i < mUsersGrid.getChildCount(); i++) {
+            View v = mUsersGrid.getChildAt(i);
+            v.setClickable(clickable);
+            v.setPressed(false);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (!(v instanceof KeyguardMultiUserAvatar)) return;
+        final KeyguardMultiUserAvatar avatar = (KeyguardMultiUserAvatar) v;
+        if (avatar.isClickable()) { // catch race conditions
+            if (mActiveUserAvatar == avatar) {
+                // If they click the currently active user, show the unlock hint
+                mCallback.showUnlockHint();
+                return;
+            } else {
+                // Reset the previously active user to appear inactive
+                mCallback.hideSecurityView(FADE_OUT_ANIMATION_DURATION);
+                setAllClickable(false);
+                avatar.lockPressed(true);
+                mActiveUserAvatar.setActive(false, true, new Runnable() {
+                    @Override
+                    public void run() {
+                        mActiveUserAvatar = avatar;
+                        try {
+                            ActivityManagerNative.getDefault()
+                                    .switchUser(avatar.getUserInfo().id);
+                        } catch (RemoteException re) {
+                            Log.e(TAG, "Couldn't switch user " + re);
+                        }
+                    }
+                });
+            }
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
new file mode 100644
index 0000000..3d1c3f3
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView.OnEditorActionListener;
+
+/**
+ * Displays a PIN pad for unlocking.
+ */
+public class KeyguardPINView extends KeyguardAbsKeyInputView
+        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+
+    public KeyguardPINView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardPINView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    protected void resetState() {
+        if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) {
+            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
+        } else {
+            mSecurityMessageDisplay.setMessage(R.string.kg_pin_instructions, false);
+        }
+        mPasswordEntry.setEnabled(true);
+    }
+
+    @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        final View ok = findViewById(R.id.key_enter);
+        if (ok != null) {
+            ok.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    doHapticKeyClick();
+                    if (mPasswordEntry.isEnabled()) {
+                        verifyPasswordAndUnlock();
+                    }
+                }
+            });
+            ok.setOnHoverListener(new LiftToActivateListener(getContext()));
+        }
+
+        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+        // not a separate view
+        View pinDelete = findViewById(R.id.delete_button);
+        if (pinDelete != null) {
+            pinDelete.setVisibility(View.VISIBLE);
+            pinDelete.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    // check for time-based lockouts
+                    if (mPasswordEntry.isEnabled()) {
+                        CharSequence str = mPasswordEntry.getText();
+                        if (str.length() > 0) {
+                            mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                        }
+                    }
+                    doHapticKeyClick();
+                }
+            });
+            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    // check for time-based lockouts
+                    if (mPasswordEntry.isEnabled()) {
+                        mPasswordEntry.setText("");
+                    }
+                    doHapticKeyClick();
+                    return true;
+                }
+            });
+        }
+
+        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+
+        mPasswordEntry.requestFocus();
+    }
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    @Override
+    public int getWrongPasswordStringId() {
+        return R.string.kg_wrong_pin;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
new file mode 100644
index 0000000..4e3568b
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
+import android.text.method.TextKeyListener;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.TextView.OnEditorActionListener;
+
+import com.android.internal.widget.PasswordEntryKeyboardHelper;
+import com.android.internal.widget.PasswordEntryKeyboardView;
+
+import java.util.List;
+/**
+ * Displays an alphanumeric (latin-1) key entry for the user to enter
+ * an unlock password
+ */
+
+public class KeyguardPasswordView extends KeyguardAbsKeyInputView
+        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+
+    private final boolean mShowImeAtScreenOn;
+
+    InputMethodManager mImm;
+
+    public KeyguardPasswordView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardPasswordView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mShowImeAtScreenOn = context.getResources().
+                getBoolean(R.bool.kg_show_ime_at_screen_on);
+    }
+
+    protected void resetState() {
+        mSecurityMessageDisplay.setMessage(R.string.kg_password_instructions, false);
+        mPasswordEntry.setEnabled(true);
+    }
+
+    @Override
+    protected int getPasswordTextViewId() {
+        return R.id.passwordEntry;
+    }
+
+    @Override
+    public boolean needsInput() {
+        return true;
+    }
+
+    @Override
+    public void onResume(int reason) {
+        super.onResume(reason);
+        mPasswordEntry.requestFocus();
+        if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
+            mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mImm.hideSoftInputFromWindow(getWindowToken(), 0);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        boolean imeOrDeleteButtonVisible = false;
+
+        mImm = (InputMethodManager) getContext().getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+
+        mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
+        mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+        // Poke the wakelock any time the text is selected or modified
+        mPasswordEntry.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                mCallback.userActivity(0); // TODO: customize timeout for text?
+            }
+        });
+
+        mPasswordEntry.addTextChangedListener(new TextWatcher() {
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+            }
+
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            }
+
+            public void afterTextChanged(Editable s) {
+                if (mCallback != null) {
+                    mCallback.userActivity(0);
+                }
+            }
+        });
+
+        mPasswordEntry.requestFocus();
+
+        // If there's more than one IME, enable the IME switcher button
+        View switchImeButton = findViewById(R.id.switch_ime_button);
+        if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(mImm, false)) {
+            switchImeButton.setVisibility(View.VISIBLE);
+            imeOrDeleteButtonVisible = true;
+            switchImeButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    mCallback.userActivity(0); // Leave the screen on a bit longer
+                    mImm.showInputMethodPicker();
+                }
+            });
+        }
+
+        // If no icon is visible, reset the start margin on the password field so the text is
+        // still centered.
+        if (!imeOrDeleteButtonVisible) {
+            android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
+            if (params instanceof MarginLayoutParams) {
+                final MarginLayoutParams mlp = (MarginLayoutParams) params;
+                mlp.setMarginStart(0);
+                mPasswordEntry.setLayoutParams(params);
+            }
+        }
+    }
+
+    /**
+     * Method adapted from com.android.inputmethod.latin.Utils
+     *
+     * @param imm The input method manager
+     * @param shouldIncludeAuxiliarySubtypes
+     * @return true if we have multiple IMEs to choose from
+     */
+    private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
+            final boolean shouldIncludeAuxiliarySubtypes) {
+        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
+
+        // Number of the filtered IMEs
+        int filteredImisCount = 0;
+
+        for (InputMethodInfo imi : enabledImis) {
+            // We can return true immediately after we find two or more filtered IMEs.
+            if (filteredImisCount > 1) return true;
+            final List<InputMethodSubtype> subtypes =
+                    imm.getEnabledInputMethodSubtypeList(imi, true);
+            // IMEs that have no subtypes should be counted.
+            if (subtypes.isEmpty()) {
+                ++filteredImisCount;
+                continue;
+            }
+
+            int auxCount = 0;
+            for (InputMethodSubtype subtype : subtypes) {
+                if (subtype.isAuxiliary()) {
+                    ++auxCount;
+                }
+            }
+            final int nonAuxCount = subtypes.size() - auxCount;
+
+            // IMEs that have one or more non-auxiliary subtypes should be counted.
+            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+            // subtypes should be counted as well.
+            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+                ++filteredImisCount;
+                continue;
+            }
+        }
+
+        return filteredImisCount > 1
+        // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
+        // input method subtype (The current IME should be LatinIME.)
+                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
+    }
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    @Override
+    public int getWrongPasswordStringId() {
+        return R.string.kg_wrong_password;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
new file mode 100644
index 0000000..e7f1259
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternView;
+
+import java.io.IOException;
+import java.util.List;
+
+public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
+
+    private static final String TAG = "SecurityPatternView";
+    private static final boolean DEBUG = false;
+
+    // how long before we clear the wrong pattern
+    private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
+
+    // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK
+    private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
+
+    // how long we stay awake after the user hits the first dot.
+    private static final int UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS = 2000;
+
+    // how many cells the user has to cross before we poke the wakelock
+    private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
+
+    private int mFailedPatternAttemptsSinceLastTimeout = 0;
+    private int mTotalFailedPatternAttempts = 0;
+    private CountDownTimer mCountdownTimer = null;
+    private LockPatternUtils mLockPatternUtils;
+    private LockPatternView mLockPatternView;
+    private Button mForgotPatternButton;
+    private KeyguardSecurityCallback mCallback;
+    private boolean mEnableFallback;
+
+    /**
+     * Keeps track of the last time we poked the wake lock during dispatching of the touch event.
+     * Initialized to something guaranteed to make us poke the wakelock when the user starts
+     * drawing the pattern.
+     * @see #dispatchTouchEvent(android.view.MotionEvent)
+     */
+    private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
+
+    /**
+     * Useful for clearing out the wrong pattern after a delay
+     */
+    private Runnable mCancelPatternRunnable = new Runnable() {
+        public void run() {
+            mLockPatternView.clearPattern();
+        }
+    };
+    private Rect mTempRect = new Rect();
+    private SecurityMessageDisplay mSecurityMessageDisplay;
+    private View mEcaView;
+    private Drawable mBouncerFrame;
+
+    enum FooterMode {
+        Normal,
+        ForgotLockPattern,
+        VerifyUnlocked
+    }
+
+    public KeyguardPatternView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardPatternView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+        mCallback = callback;
+    }
+
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mLockPatternUtils = mLockPatternUtils == null
+                ? new LockPatternUtils(mContext) : mLockPatternUtils;
+
+        mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView);
+        mLockPatternView.setSaveEnabled(false);
+        mLockPatternView.setFocusable(false);
+        mLockPatternView.setOnPatternListener(new UnlockPatternListener());
+
+        // stealth mode will be the same for the life of this screen
+        mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());
+
+        // vibrate mode will be the same for the life of this screen
+        mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+
+        mForgotPatternButton = (Button) findViewById(R.id.forgot_password_button);
+        // note: some configurations don't have an emergency call area
+        if (mForgotPatternButton != null) {
+            mForgotPatternButton.setText(R.string.kg_forgot_pattern_button_text);
+            mForgotPatternButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    mCallback.showBackupSecurity();
+                }
+            });
+        }
+
+        setFocusableInTouchMode(true);
+
+        maybeEnableFallback(mContext);
+        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
+        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
+        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
+        if (bouncerFrameView != null) {
+            mBouncerFrame = bouncerFrameView.getBackground();
+        }
+    }
+
+    private void updateFooter(FooterMode mode) {
+        if (mForgotPatternButton == null) return; // no ECA? no footer
+
+        switch (mode) {
+            case Normal:
+                if (DEBUG) Log.d(TAG, "mode normal");
+                mForgotPatternButton.setVisibility(View.GONE);
+                break;
+            case ForgotLockPattern:
+                if (DEBUG) Log.d(TAG, "mode ForgotLockPattern");
+                mForgotPatternButton.setVisibility(View.VISIBLE);
+                break;
+            case VerifyUnlocked:
+                if (DEBUG) Log.d(TAG, "mode VerifyUnlocked");
+                mForgotPatternButton.setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean result = super.onTouchEvent(ev);
+        // as long as the user is entering a pattern (i.e sending a touch event that was handled
+        // by this screen), keep poking the wake lock so that the screen will stay on.
+        final long elapsed = SystemClock.elapsedRealtime() - mLastPokeTime;
+        if (result && (elapsed > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
+            mLastPokeTime = SystemClock.elapsedRealtime();
+        }
+        mTempRect.set(0, 0, 0, 0);
+        offsetRectIntoDescendantCoords(mLockPatternView, mTempRect);
+        ev.offsetLocation(mTempRect.left, mTempRect.top);
+        result = mLockPatternView.dispatchTouchEvent(ev) || result;
+        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
+        return result;
+    }
+
+    public void reset() {
+        // reset lock pattern
+        mLockPatternView.enableInput();
+        mLockPatternView.setEnabled(true);
+        mLockPatternView.clearPattern();
+
+        // if the user is currently locked out, enforce it.
+        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+        if (deadline != 0) {
+            handleAttemptLockout(deadline);
+        } else {
+            displayDefaultSecurityMessage();
+        }
+
+        // the footer depends on how many total attempts the user has failed
+        if (mCallback.isVerifyUnlockOnly()) {
+            updateFooter(FooterMode.VerifyUnlocked);
+        } else if (mEnableFallback &&
+                (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
+            updateFooter(FooterMode.ForgotLockPattern);
+        } else {
+            updateFooter(FooterMode.Normal);
+        }
+
+    }
+
+    private void displayDefaultSecurityMessage() {
+        if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) {
+            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
+        } else {
+            mSecurityMessageDisplay.setMessage(R.string.kg_pattern_instructions, false);
+        }
+    }
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    /** TODO: hook this up */
+    public void cleanUp() {
+        if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
+        mLockPatternUtils = null;
+        mLockPatternView.setOnPatternListener(null);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (hasWindowFocus) {
+            // when timeout dialog closes we want to update our state
+            reset();
+        }
+    }
+
+    private class UnlockPatternListener implements LockPatternView.OnPatternListener {
+
+        public void onPatternStart() {
+            mLockPatternView.removeCallbacks(mCancelPatternRunnable);
+        }
+
+        public void onPatternCleared() {
+        }
+
+        public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
+            // To guard against accidental poking of the wakelock, look for
+            // the user actually trying to draw a pattern of some minimal length.
+            if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
+                mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
+            } else {
+                // Give just a little extra time if they hit one of the first few dots
+                mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS);
+            }
+        }
+
+        public void onPatternDetected(List<LockPatternView.Cell> pattern) {
+            if (mLockPatternUtils.checkPattern(pattern)) {
+                mCallback.reportSuccessfulUnlockAttempt();
+                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
+                mTotalFailedPatternAttempts = 0;
+                mCallback.dismiss(true);
+            } else {
+                if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
+                    mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
+                }
+                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
+                if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
+                    mTotalFailedPatternAttempts++;
+                    mFailedPatternAttemptsSinceLastTimeout++;
+                    mCallback.reportFailedUnlockAttempt();
+                }
+                if (mFailedPatternAttemptsSinceLastTimeout
+                        >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
+                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+                    handleAttemptLockout(deadline);
+                } else {
+                    mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
+                    mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
+                }
+            }
+        }
+    }
+
+    private void maybeEnableFallback(Context context) {
+        // Ask the account manager if we have an account that can be used as a
+        // fallback in case the user forgets his pattern.
+        AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context));
+        accountAnalyzer.start();
+    }
+
+    private class AccountAnalyzer implements AccountManagerCallback<Bundle> {
+        private final AccountManager mAccountManager;
+        private final Account[] mAccounts;
+        private int mAccountIndex;
+
+        private AccountAnalyzer(AccountManager accountManager) {
+            mAccountManager = accountManager;
+            mAccounts = accountManager.getAccountsByTypeAsUser("com.google",
+                    new UserHandle(mLockPatternUtils.getCurrentUser()));
+        }
+
+        private void next() {
+            // if we are ready to enable the fallback or if we depleted the list of accounts
+            // then finish and get out
+            if (mEnableFallback || mAccountIndex >= mAccounts.length) {
+                return;
+            }
+
+            // lookup the confirmCredentials intent for the current account
+            mAccountManager.confirmCredentialsAsUser(mAccounts[mAccountIndex], null, null, this,
+                    null, new UserHandle(mLockPatternUtils.getCurrentUser()));
+        }
+
+        public void start() {
+            mEnableFallback = false;
+            mAccountIndex = 0;
+            next();
+        }
+
+        public void run(AccountManagerFuture<Bundle> future) {
+            try {
+                Bundle result = future.getResult();
+                if (result.getParcelable(AccountManager.KEY_INTENT) != null) {
+                    mEnableFallback = true;
+                }
+            } catch (OperationCanceledException e) {
+                // just skip the account if we are unable to query it
+            } catch (IOException e) {
+                // just skip the account if we are unable to query it
+            } catch (AuthenticatorException e) {
+                // just skip the account if we are unable to query it
+            } finally {
+                mAccountIndex++;
+                next();
+            }
+        }
+    }
+
+    private void handleAttemptLockout(long elapsedRealtimeDeadline) {
+        mLockPatternView.clearPattern();
+        mLockPatternView.setEnabled(false);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        if (mEnableFallback) {
+            updateFooter(FooterMode.ForgotLockPattern);
+        }
+
+        mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
+
+            @Override
+            public void onTick(long millisUntilFinished) {
+                final int secondsRemaining = (int) (millisUntilFinished / 1000);
+                mSecurityMessageDisplay.setMessage(
+                        R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
+            }
+
+            @Override
+            public void onFinish() {
+                mLockPatternView.setEnabled(true);
+                displayDefaultSecurityMessage();
+                // TODO mUnlockIcon.setVisibility(View.VISIBLE);
+                mFailedPatternAttemptsSinceLastTimeout = 0;
+                if (mEnableFallback) {
+                    updateFooter(FooterMode.ForgotLockPattern);
+                } else {
+                    updateFooter(FooterMode.Normal);
+                }
+            }
+
+        }.start();
+    }
+
+    @Override
+    public boolean needsInput() {
+        return false;
+    }
+
+    @Override
+    public void onPause() {
+        if (mCountdownTimer != null) {
+            mCountdownTimer.cancel();
+            mCountdownTimer = null;
+        }
+    }
+
+    @Override
+    public void onResume(int reason) {
+        reset();
+    }
+
+    @Override
+    public KeyguardSecurityCallback getCallback() {
+        return mCallback;
+    }
+
+    @Override
+    public void showBouncer(int duration) {
+        KeyguardSecurityViewHelper.
+                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+        KeyguardSecurityViewHelper.
+                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
new file mode 100644
index 0000000..4f139ad
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+
+public interface KeyguardSecurityCallback {
+
+    /**
+     * Dismiss the given security screen.
+     * @param securityVerified true if the user correctly entered credentials for the given screen.
+     */
+    void dismiss(boolean securityVerified);
+
+    /**
+     * Manually report user activity to keep the device awake. If timeout is 0,
+     * uses user-defined timeout.
+     * @param timeout
+     */
+    void userActivity(long timeout);
+
+    /**
+     * Checks if keyguard is in "verify credentials" mode.
+     * @return true if user has been asked to verify security.
+     */
+    boolean isVerifyUnlockOnly();
+
+    /**
+     * Call when user correctly enters their credentials
+     */
+    void reportSuccessfulUnlockAttempt();
+
+    /**
+     * Call when the user incorrectly enters their credentials
+     */
+    void reportFailedUnlockAttempt();
+
+    /**
+     * Gets the number of attempts thus far as reported by {@link #reportFailedUnlockAttempt()}
+     * @return number of failed attempts
+     */
+    int getFailedAttempts();
+
+    /**
+     * Shows the backup security for the current method.  If none available, this call is a no-op.
+     */
+    void showBackupSecurity();
+
+    /**
+     * Sets an action to perform after the user successfully enters their credentials.
+     * @param action
+     */
+    void setOnDismissAction(OnDismissAction action);
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
new file mode 100644
index 0000000..9d03c6a
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -0,0 +1,45 @@
+package com.android.keyguard;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class KeyguardSecurityContainer extends FrameLayout {
+    public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardSecurityContainer(Context context) {
+        this(null, null, 0);
+    }
+
+    public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    KeyguardSecurityViewFlipper getFlipper() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child instanceof KeyguardSecurityViewFlipper) {
+                return (KeyguardSecurityViewFlipper) child;
+            }
+        }
+        return null;
+    }
+
+    public void showBouncer(int duration) {
+        KeyguardSecurityViewFlipper flipper = getFlipper();
+        if (flipper != null) {
+            flipper.showBouncer(duration);
+        }
+    }
+
+    public void hideBouncer(int duration) {
+        KeyguardSecurityViewFlipper flipper = getFlipper();
+        if (flipper != null) {
+            flipper.hideBouncer(duration);
+        }
+    }
+}
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
new file mode 100644
index 0000000..4129e33
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.widget.LockPatternUtils;
+
+public class KeyguardSecurityModel {
+    /**
+     * The different types of security available for {@link Mode#UnlockScreen}.
+     * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
+     */
+    enum SecurityMode {
+        Invalid, // NULL state
+        None, // No security enabled
+        Pattern, // Unlock by drawing a pattern.
+        Password, // Unlock by entering an alphanumeric password
+        PIN, // Strictly numeric password
+        Biometric, // Unlock with a biometric key (e.g. finger print or face unlock)
+        Account, // Unlock by entering an account's login and password.
+        SimPin, // Unlock by entering a sim pin.
+        SimPuk // Unlock by entering a sim puk
+    }
+
+    private Context mContext;
+    private LockPatternUtils mLockPatternUtils;
+
+    KeyguardSecurityModel(Context context) {
+        mContext = context;
+        mLockPatternUtils = new LockPatternUtils(context);
+    }
+
+    void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+    }
+
+    /**
+     * Returns true if biometric unlock is installed and selected.  If this returns false there is
+     * no need to even construct the biometric unlock.
+     */
+    boolean isBiometricUnlockEnabled() {
+        return mLockPatternUtils.usingBiometricWeak()
+                && mLockPatternUtils.isBiometricWeakInstalled();
+    }
+
+    /**
+     * Returns true if a condition is currently suppressing the biometric unlock.  If this returns
+     * true there is no need to even construct the biometric unlock.
+     */
+    private boolean isBiometricUnlockSuppressed() {
+        KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+        final boolean backupIsTimedOut = monitor.getFailedUnlockAttempts() >=
+                LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
+        return monitor.getMaxBiometricUnlockAttemptsReached() || backupIsTimedOut
+                || !monitor.isAlternateUnlockEnabled()
+                || monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE;
+    }
+
+    SecurityMode getSecurityMode() {
+        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+        final IccCardConstants.State simState = updateMonitor.getSimState();
+        SecurityMode mode = SecurityMode.None;
+        if (simState == IccCardConstants.State.PIN_REQUIRED) {
+            mode = SecurityMode.SimPin;
+        } else if (simState == IccCardConstants.State.PUK_REQUIRED
+                && mLockPatternUtils.isPukUnlockScreenEnable()) {
+            mode = SecurityMode.SimPuk;
+        } else {
+            final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
+            switch (security) {
+                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
+                            SecurityMode.PIN : SecurityMode.None;
+                    break;
+                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
+                            SecurityMode.Password : SecurityMode.None;
+                    break;
+
+                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
+                    if (mLockPatternUtils.isLockPatternEnabled()) {
+                        mode = mLockPatternUtils.isPermanentlyLocked() ?
+                            SecurityMode.Account : SecurityMode.Pattern;
+                    }
+                    break;
+
+                default:
+                    throw new IllegalStateException("Unknown unlock mode:" + mode);
+            }
+        }
+        return mode;
+    }
+
+    /**
+     * Some unlock methods can have an alternate, such as biometric unlocks (e.g. face unlock).
+     * This function decides if an alternate unlock is available and returns it. Otherwise,
+     * returns @param mode.
+     *
+     * @param mode the mode we want the alternate for
+     * @return alternate or the given mode
+     */
+    SecurityMode getAlternateFor(SecurityMode mode) {
+        if (isBiometricUnlockEnabled() && !isBiometricUnlockSuppressed()
+                && (mode == SecurityMode.Password
+                        || mode == SecurityMode.PIN
+                        || mode == SecurityMode.Pattern)) {
+            return SecurityMode.Biometric;
+        }
+        return mode; // no alternate, return what was given
+    }
+
+    /**
+     * Some unlock methods can have a backup which gives the user another way to get into
+     * the device. This is currently only supported for Biometric and Pattern unlock.
+     *
+     * @return backup method or current security mode
+     */
+    SecurityMode getBackupSecurityMode(SecurityMode mode) {
+        switch(mode) {
+            case Biometric:
+                return getSecurityMode();
+            case Pattern:
+                return SecurityMode.Account;
+        }
+        return mode; // no backup, return current security mode
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
new file mode 100644
index 0000000..dfeacf3
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public interface KeyguardSecurityView {
+    static public final int SCREEN_ON = 1;
+    static public final int VIEW_REVEALED = 2;
+
+    /**
+     * Interface back to keyguard to tell it when security
+     * @param callback
+     */
+    void setKeyguardCallback(KeyguardSecurityCallback callback);
+
+    /**
+     * Set {@link LockPatternUtils} object. Useful for providing a mock interface.
+     * @param utils
+     */
+    void setLockPatternUtils(LockPatternUtils utils);
+
+    /**
+     * Reset the view and prepare to take input. This should do things like clearing the
+     * password or pattern and clear error messages.
+     */
+    void reset();
+
+    /**
+     * Emulate activity life cycle within the view. When called, the view should clean up
+     * and prepare to be removed.
+     */
+    void onPause();
+
+    /**
+     * Emulate activity life cycle within this view.  When called, the view should prepare itself
+     * to be shown.
+     * @param reason the root cause of the event.
+     */
+    void onResume(int reason);
+
+    /**
+     * Inquire whether this view requires IME (keyboard) interaction.
+     *
+     * @return true if IME interaction is required.
+     */
+    boolean needsInput();
+
+    /**
+     * Get {@link KeyguardSecurityCallback} for the given object
+     * @return KeyguardSecurityCallback
+     */
+    KeyguardSecurityCallback getCallback();
+
+    /**
+     * Instruct the view to show usability hints, if any.
+     *
+     */
+    void showUsabilityHint();
+
+    /**
+     * Place the security view into bouncer mode.
+     * Animate transisiton if duration is non-zero.
+     * @param duration millisends for the transisiton animation.
+     */
+    void showBouncer(int duration);
+
+    /**
+     * Place the security view into non-bouncer mode.
+     * Animate transisiton if duration is non-zero.
+     * @param duration millisends for the transisiton animation.
+     */
+    void hideBouncer(int duration);
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
new file mode 100644
index 0000000..70a0e44
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ViewFlipper;
+
+import com.android.internal.widget.LockPatternUtils;
+
+/**
+ * Subclass of the current view flipper that allows us to overload dispatchTouchEvent() so
+ * we can emulate {@link WindowManager.LayoutParams#FLAG_SLIPPERY} within a view hierarchy.
+ *
+ */
+public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView {
+    private static final String TAG = "KeyguardSecurityViewFlipper";
+    private static final boolean DEBUG = false;
+
+    private Rect mTempRect = new Rect();
+
+    public KeyguardSecurityViewFlipper(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardSecurityViewFlipper(Context context, AttributeSet attr) {
+        super(context, attr);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean result = super.onTouchEvent(ev);
+        mTempRect.set(0, 0, 0, 0);
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == View.VISIBLE) {
+                offsetRectIntoDescendantCoords(child, mTempRect);
+                ev.offsetLocation(mTempRect.left, mTempRect.top);
+                result = child.dispatchTouchEvent(ev) || result;
+                ev.offsetLocation(-mTempRect.left, -mTempRect.top);
+            }
+        }
+        return result;
+    }
+
+    KeyguardSecurityView getSecurityView() {
+        View child = getChildAt(getDisplayedChild());
+        if (child instanceof KeyguardSecurityView) {
+            return (KeyguardSecurityView) child;
+        }
+        return null;
+    }
+
+    @Override
+    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.setKeyguardCallback(callback);
+        }
+    }
+
+    @Override
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.setLockPatternUtils(utils);
+        }
+    }
+
+    @Override
+    public void reset() {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.reset();
+        }
+    }
+
+    @Override
+    public void onPause() {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.onPause();
+        }
+    }
+
+    @Override
+    public void onResume(int reason) {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.onResume(reason);
+        }
+    }
+
+    @Override
+    public boolean needsInput() {
+        KeyguardSecurityView ksv = getSecurityView();
+        return (ksv != null) ? ksv.needsInput() : false;
+    }
+
+    @Override
+    public KeyguardSecurityCallback getCallback() {
+        KeyguardSecurityView ksv = getSecurityView();
+        return (ksv != null) ? ksv.getCallback() : null;
+    }
+
+    @Override
+    public void showUsabilityHint() {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.showUsabilityHint();
+        }
+    }
+
+    @Override
+    public void showBouncer(int duration) {
+        KeyguardSecurityView active = getSecurityView();
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child instanceof KeyguardSecurityView) {
+                KeyguardSecurityView ksv = (KeyguardSecurityView) child;
+                ksv.showBouncer(ksv == active ? duration : 0);
+            }
+        }
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+        KeyguardSecurityView active = getSecurityView();
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child instanceof KeyguardSecurityView) {
+                KeyguardSecurityView ksv = (KeyguardSecurityView) child;
+                ksv.hideBouncer(ksv == active ? duration : 0);
+            }
+        }
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : new LayoutParams(p);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        final int widthMode = MeasureSpec.getMode(widthSpec);
+        final int heightMode = MeasureSpec.getMode(heightSpec);
+        if (DEBUG && widthMode != MeasureSpec.AT_MOST) {
+            Log.w(TAG, "onMeasure: widthSpec " + MeasureSpec.toString(widthSpec) +
+                    " should be AT_MOST");
+        }
+        if (DEBUG && heightMode != MeasureSpec.AT_MOST) {
+            Log.w(TAG, "onMeasure: heightSpec " + MeasureSpec.toString(heightSpec) +
+                    " should be AT_MOST");
+        }
+
+        final int widthSize = MeasureSpec.getSize(widthSpec);
+        final int heightSize = MeasureSpec.getSize(heightSpec);
+        int maxWidth = widthSize;
+        int maxHeight = heightSize;
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (lp.maxWidth > 0 && lp.maxWidth < maxWidth) {
+                maxWidth = lp.maxWidth;
+            }
+            if (lp.maxHeight > 0 && lp.maxHeight < maxHeight) {
+                maxHeight = lp.maxHeight;
+            }
+        }
+
+        final int wPadding = getPaddingLeft() + getPaddingRight();
+        final int hPadding = getPaddingTop() + getPaddingBottom();
+        maxWidth -= wPadding;
+        maxHeight -= hPadding;
+
+        int width = widthMode == MeasureSpec.EXACTLY ? widthSize : 0;
+        int height = heightMode == MeasureSpec.EXACTLY ? heightSize : 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            final int childWidthSpec = makeChildMeasureSpec(maxWidth, lp.width);
+            final int childHeightSpec = makeChildMeasureSpec(maxHeight, lp.height);
+
+            child.measure(childWidthSpec, childHeightSpec);
+
+            width = Math.max(width, Math.min(child.getMeasuredWidth(), widthSize - wPadding));
+            height = Math.max(height, Math.min(child.getMeasuredHeight(), heightSize - hPadding));
+        }
+        setMeasuredDimension(width + wPadding, height + hPadding);
+    }
+
+    private int makeChildMeasureSpec(int maxSize, int childDimen) {
+        final int mode;
+        final int size;
+        switch (childDimen) {
+            case LayoutParams.WRAP_CONTENT:
+                mode = MeasureSpec.AT_MOST;
+                size = maxSize;
+                break;
+            case LayoutParams.MATCH_PARENT:
+                mode = MeasureSpec.EXACTLY;
+                size = maxSize;
+                break;
+            default:
+                mode = MeasureSpec.EXACTLY;
+                size = Math.min(maxSize, childDimen);
+                break;
+        }
+        return MeasureSpec.makeMeasureSpec(size, mode);
+    }
+
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+        @ViewDebug.ExportedProperty(category = "layout")
+        public int maxWidth;
+
+        @ViewDebug.ExportedProperty(category = "layout")
+        public int maxHeight;
+
+        public LayoutParams(ViewGroup.LayoutParams other) {
+            super(other);
+        }
+
+        public LayoutParams(LayoutParams other) {
+            super(other);
+
+            maxWidth = other.maxWidth;
+            maxHeight = other.maxHeight;
+        }
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs,
+                    R.styleable.KeyguardSecurityViewFlipper_Layout, 0, 0);
+            maxWidth = a.getDimensionPixelSize(
+                    R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxWidth, 0);
+            maxHeight = a.getDimensionPixelSize(
+                    R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxHeight, 0);
+            a.recycle();
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewHelper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewHelper.java
new file mode 100644
index 0000000..67a6f52
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewHelper.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+/**
+ * Some common functions that are useful for KeyguardSecurityViews.
+ */
+public class KeyguardSecurityViewHelper {
+
+    public static void showBouncer(SecurityMessageDisplay securityMessageDisplay,
+            final View ecaView, Drawable bouncerFrame, int duration) {
+        if (securityMessageDisplay != null) {
+            securityMessageDisplay.showBouncer(duration);
+        }
+        if (ecaView != null) {
+            if (duration > 0) {
+                Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 0f);
+                anim.setDuration(duration);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    private boolean mCanceled;
+                    @Override
+                    public void onAnimationCancel(Animator animation) {
+                        // Fail safe and show the emergency button in onAnimationEnd()
+                        mCanceled = true;
+                        ecaView.setAlpha(1f);
+                    }
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        ecaView.setVisibility(mCanceled ? View.VISIBLE : View.INVISIBLE);
+                    }
+                });
+                anim.start();
+            } else {
+                ecaView.setAlpha(0f);
+                ecaView.setVisibility(View.INVISIBLE);
+            }
+        }
+        if (bouncerFrame != null) {
+            if (duration > 0) {
+                Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 0, 255);
+                anim.setDuration(duration);
+                anim.start();
+            } else {
+                bouncerFrame.setAlpha(255);
+            }
+        }
+    }
+
+    public static void hideBouncer(SecurityMessageDisplay securityMessageDisplay,
+            View ecaView, Drawable bouncerFrame, int duration) {
+        if (securityMessageDisplay != null) {
+            securityMessageDisplay.hideBouncer(duration);
+        }
+        if (ecaView != null) {
+            ecaView.setVisibility(View.VISIBLE);
+            if (duration > 0) {
+                Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 1f);
+                anim.setDuration(duration);
+                anim.start();
+            } else {
+                ecaView.setAlpha(1f);
+            }
+        }
+        if (bouncerFrame != null) {
+            if (duration > 0) {
+                Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 255, 0);
+                anim.setDuration(duration);
+                anim.start();
+            } else {
+                bouncerFrame.setAlpha(0);
+            }
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
new file mode 100644
index 0000000..63be102
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.animation.ObjectAnimator;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.app.SearchManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.multiwaveview.GlowPadView;
+import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
+
+public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView {
+    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+    private static final String TAG = "SecuritySelectorView";
+    private static final String ASSIST_ICON_METADATA_NAME =
+        "com.android.systemui.action_assist_icon";
+
+    private KeyguardSecurityCallback mCallback;
+    private GlowPadView mGlowPadView;
+    private ObjectAnimator mAnim;
+    private View mFadeView;
+    private boolean mIsBouncing;
+    private boolean mCameraDisabled;
+    private boolean mSearchDisabled;
+    private LockPatternUtils mLockPatternUtils;
+    private SecurityMessageDisplay mSecurityMessageDisplay;
+    private Drawable mBouncerFrame;
+
+    OnTriggerListener mOnTriggerListener = new OnTriggerListener() {
+
+        public void onTrigger(View v, int target) {
+            final int resId = mGlowPadView.getResourceIdForTarget(target);
+
+            switch (resId) {
+                case R.drawable.ic_action_assist_generic:
+                    Intent assistIntent =
+                            ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                            .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
+                    if (assistIntent != null) {
+                        mActivityLauncher.launchActivity(assistIntent, false, true, null, null);
+                    } else {
+                        Log.w(TAG, "Failed to get intent for assist activity");
+                    }
+                    mCallback.userActivity(0);
+                    break;
+
+                case R.drawable.ic_lockscreen_camera:
+                    mActivityLauncher.launchCamera(null, null);
+                    mCallback.userActivity(0);
+                    break;
+
+                case R.drawable.ic_lockscreen_unlock_phantom:
+                case R.drawable.ic_lockscreen_unlock:
+                    mCallback.userActivity(0);
+                    mCallback.dismiss(false);
+                break;
+            }
+        }
+
+        public void onReleased(View v, int handle) {
+            if (!mIsBouncing) {
+                doTransition(mFadeView, 1.0f);
+            }
+        }
+
+        public void onGrabbed(View v, int handle) {
+            mCallback.userActivity(0);
+            doTransition(mFadeView, 0.0f);
+        }
+
+        public void onGrabbedStateChange(View v, int handle) {
+
+        }
+
+        public void onFinishFinalAnimation() {
+
+        }
+
+    };
+
+    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+
+        @Override
+        public void onDevicePolicyManagerStateChanged() {
+            updateTargets();
+        }
+
+        @Override
+        public void onSimStateChanged(State simState) {
+            updateTargets();
+        }
+    };
+
+    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
+
+        @Override
+        KeyguardSecurityCallback getCallback() {
+            return mCallback;
+        }
+
+        @Override
+        LockPatternUtils getLockPatternUtils() {
+            return mLockPatternUtils;
+        }
+
+        @Override
+        Context getContext() {
+            return mContext;
+        }};
+
+    public KeyguardSelectorView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardSelectorView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLockPatternUtils = new LockPatternUtils(getContext());
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
+        mGlowPadView.setOnTriggerListener(mOnTriggerListener);
+        updateTargets();
+
+        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
+        View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame);
+        mBouncerFrame = bouncerFrameView.getBackground();
+    }
+
+    public void setCarrierArea(View carrierArea) {
+        mFadeView = carrierArea;
+    }
+
+    public boolean isTargetPresent(int resId) {
+        return mGlowPadView.getTargetPosition(resId) != -1;
+    }
+
+    @Override
+    public void showUsabilityHint() {
+        mGlowPadView.ping();
+    }
+
+    private void updateTargets() {
+        int currentUserHandle = mLockPatternUtils.getCurrentUser();
+        DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
+        int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUserHandle);
+        boolean secureCameraDisabled = mLockPatternUtils.isSecure()
+                && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
+        boolean cameraDisabledByAdmin = dpm.getCameraDisabled(null, currentUserHandle)
+                || secureCameraDisabled;
+        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext());
+        boolean disabledBySimState = monitor.isSimLocked();
+        boolean cameraTargetPresent =
+            isTargetPresent(R.drawable.ic_lockscreen_camera);
+        boolean searchTargetPresent =
+            isTargetPresent(R.drawable.ic_action_assist_generic);
+
+        if (cameraDisabledByAdmin) {
+            Log.v(TAG, "Camera disabled by Device Policy");
+        } else if (disabledBySimState) {
+            Log.v(TAG, "Camera disabled by Sim State");
+        }
+        boolean currentUserSetup = 0 != Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE,
+                0 /*default */,
+                currentUserHandle);
+        boolean searchActionAvailable =
+                ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
+        mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent
+                || !currentUserSetup;
+        mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent
+                || !currentUserSetup;
+        updateResources();
+    }
+
+    public void updateResources() {
+        // Update the search icon with drawable from the search .apk
+        if (!mSearchDisabled) {
+            Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                    .getAssistIntent(mContext, false, UserHandle.USER_CURRENT);
+            if (intent != null) {
+                // XXX Hack. We need to substitute the icon here but haven't formalized
+                // the public API. The "_google" metadata will be going away, so
+                // DON'T USE IT!
+                ComponentName component = intent.getComponent();
+                boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component,
+                        ASSIST_ICON_METADATA_NAME + "_google", R.drawable.ic_action_assist_generic);
+
+                if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component,
+                            ASSIST_ICON_METADATA_NAME, R.drawable.ic_action_assist_generic)) {
+                        Slog.w(TAG, "Couldn't grab icon from package " + component);
+                }
+            }
+        }
+
+        mGlowPadView.setEnableTarget(R.drawable.ic_lockscreen_camera, !mCameraDisabled);
+        mGlowPadView.setEnableTarget(R.drawable.ic_action_assist_generic, !mSearchDisabled);
+    }
+
+    void doTransition(View view, float to) {
+        if (mAnim != null) {
+            mAnim.cancel();
+        }
+        mAnim = ObjectAnimator.ofFloat(view, "alpha", to);
+        mAnim.start();
+    }
+
+    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+        mCallback = callback;
+    }
+
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+    }
+
+    @Override
+    public void reset() {
+        mGlowPadView.reset(false);
+    }
+
+    @Override
+    public boolean needsInput() {
+        return false;
+    }
+
+    @Override
+    public void onPause() {
+        KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mUpdateCallback);
+    }
+
+    @Override
+    public void onResume(int reason) {
+        KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mUpdateCallback);
+    }
+
+    @Override
+    public KeyguardSecurityCallback getCallback() {
+        return mCallback;
+    }
+
+    @Override
+    public void showBouncer(int duration) {
+        mIsBouncing = true;
+        KeyguardSecurityViewHelper.
+                showBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+        mIsBouncing = false;
+        KeyguardSecurityViewHelper.
+                hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
new file mode 100644
index 0000000..d7c5fe2
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
@@ -0,0 +1,147 @@
+/*
+ * 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.keyguard;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import android.app.Service;
+import android.content.Intent;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.widget.LockPatternUtils;
+
+public class KeyguardService extends Service {
+    static final String TAG = "KeyguardService";
+    static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
+    private KeyguardViewMediator mKeyguardViewMediator;
+
+    @Override
+    public void onCreate() {
+        if (mKeyguardViewMediator == null) {
+            mKeyguardViewMediator = new KeyguardViewMediator(
+                    KeyguardService.this, new LockPatternUtils(KeyguardService.this));
+        }
+        Log.v(TAG, "onCreate()");
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        // TODO
+    }
+
+    void checkPermission() {
+        if (getBaseContext().checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
+            Log.w(TAG, "Caller needs permission '" + PERMISSION + "' to call " + Debug.getCaller());
+            throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+                    + ", must have permission " + PERMISSION);
+        }
+    }
+
+    private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
+        public boolean isShowing() {
+            return mKeyguardViewMediator.isShowing();
+        }
+        public boolean isSecure() {
+            return mKeyguardViewMediator.isSecure();
+        }
+        public boolean isShowingAndNotHidden() {
+            return mKeyguardViewMediator.isShowingAndNotHidden();
+        }
+        public boolean isInputRestricted() {
+            return mKeyguardViewMediator.isInputRestricted();
+        }
+        public void verifyUnlock(IKeyguardExitCallback callback) {
+            mKeyguardViewMediator.verifyUnlock(callback);
+        }
+        public void keyguardDone(boolean authenticated, boolean wakeup) {
+            checkPermission();
+            mKeyguardViewMediator.keyguardDone(authenticated, wakeup);
+        }
+        public void setHidden(boolean isHidden) {
+            checkPermission();
+            mKeyguardViewMediator.setHidden(isHidden);
+        }
+        public void dismiss() {
+            mKeyguardViewMediator.dismiss();
+        }
+        public void onDreamingStarted() {
+            checkPermission();
+            mKeyguardViewMediator.onDreamingStarted();
+        }
+        public void onDreamingStopped() {
+            checkPermission();
+            mKeyguardViewMediator.onDreamingStopped();
+        }
+        public void onScreenTurnedOff(int reason) {
+            checkPermission();
+            mKeyguardViewMediator.onScreenTurnedOff(reason);
+        }
+        public void onScreenTurnedOn(IKeyguardShowCallback callback) {
+            checkPermission();
+            mKeyguardViewMediator.onScreenTurnedOn(callback);
+        }
+        public void setKeyguardEnabled(boolean enabled) {
+            checkPermission();
+            mKeyguardViewMediator.setKeyguardEnabled(enabled);
+        }
+        public boolean isDismissable() {
+            return mKeyguardViewMediator.isDismissable();
+        }
+        public void onSystemReady() {
+            checkPermission();
+            mKeyguardViewMediator.onSystemReady();
+        }
+        public void doKeyguardTimeout(Bundle options) {
+            checkPermission();
+            mKeyguardViewMediator.doKeyguardTimeout(options);
+        }
+        public void setCurrentUser(int userId) {
+            checkPermission();
+            mKeyguardViewMediator.setCurrentUser(userId);
+        }
+        public void showAssistant() {
+            checkPermission();
+            mKeyguardViewMediator.showAssistant();
+        }
+        public void dispatch(MotionEvent event) {
+            checkPermission();
+            mKeyguardViewMediator.dispatch(event);
+        }
+        public void launchCamera() {
+            checkPermission();
+            mKeyguardViewMediator.launchCamera();
+        }
+    };
+
+}
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
new file mode 100644
index 0000000..865a7c4
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import com.android.internal.telephony.ITelephony;
+
+import android.content.Context;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView.OnEditorActionListener;
+
+/**
+ * Displays a PIN pad for unlocking.
+ */
+public class KeyguardSimPinView extends KeyguardAbsKeyInputView
+        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+
+    private ProgressDialog mSimUnlockProgressDialog = null;
+    private volatile boolean mSimCheckInProgress;
+
+    public KeyguardSimPinView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardSimPinView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void resetState() {
+        mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
+        mPasswordEntry.setEnabled(true);
+    }
+
+    @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        final View ok = findViewById(R.id.key_enter);
+        if (ok != null) {
+            ok.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    doHapticKeyClick();
+                    verifyPasswordAndUnlock();
+                }
+            });
+        }
+
+        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+        // not a separate view
+        View pinDelete = findViewById(R.id.delete_button);
+        if (pinDelete != null) {
+            pinDelete.setVisibility(View.VISIBLE);
+            pinDelete.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    CharSequence str = mPasswordEntry.getText();
+                    if (str.length() > 0) {
+                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                    }
+                    doHapticKeyClick();
+                }
+            });
+            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    mPasswordEntry.setText("");
+                    doHapticKeyClick();
+                    return true;
+                }
+            });
+        }
+
+        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+
+        mPasswordEntry.requestFocus();
+    }
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    @Override
+    public void onPause() {
+        // dismiss the dialog.
+        if (mSimUnlockProgressDialog != null) {
+            mSimUnlockProgressDialog.dismiss();
+            mSimUnlockProgressDialog = null;
+        }
+    }
+
+    /**
+     * Since the IPC can block, we want to run the request in a separate thread
+     * with a callback.
+     */
+    private abstract class CheckSimPin extends Thread {
+        private final String mPin;
+
+        protected CheckSimPin(String pin) {
+            mPin = pin;
+        }
+
+        abstract void onSimCheckResponse(boolean success);
+
+        @Override
+        public void run() {
+            try {
+                final boolean result = ITelephony.Stub.asInterface(ServiceManager
+                        .checkService("phone")).supplyPin(mPin);
+                post(new Runnable() {
+                    public void run() {
+                        onSimCheckResponse(result);
+                    }
+                });
+            } catch (RemoteException e) {
+                post(new Runnable() {
+                    public void run() {
+                        onSimCheckResponse(false);
+                    }
+                });
+            }
+        }
+    }
+
+    private Dialog getSimUnlockProgressDialog() {
+        if (mSimUnlockProgressDialog == null) {
+            mSimUnlockProgressDialog = new ProgressDialog(mContext);
+            mSimUnlockProgressDialog.setMessage(
+                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
+            mSimUnlockProgressDialog.setIndeterminate(true);
+            mSimUnlockProgressDialog.setCancelable(false);
+            if (!(mContext instanceof Activity)) {
+                mSimUnlockProgressDialog.getWindow().setType(
+                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            }
+        }
+        return mSimUnlockProgressDialog;
+    }
+
+    @Override
+    protected void verifyPasswordAndUnlock() {
+        String entry = mPasswordEntry.getText().toString();
+        
+        if (entry.length() < 4) {
+            // otherwise, display a message to the user, and don't submit.
+            mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true);
+            mPasswordEntry.setText("");
+            mCallback.userActivity(0);
+            return;
+        }
+
+        getSimUnlockProgressDialog().show();
+
+        if (!mSimCheckInProgress) {
+            mSimCheckInProgress = true; // there should be only one
+            new CheckSimPin(mPasswordEntry.getText().toString()) {
+                void onSimCheckResponse(final boolean success) {
+                    post(new Runnable() {
+                        public void run() {
+                            if (mSimUnlockProgressDialog != null) {
+                                mSimUnlockProgressDialog.hide();
+                            }
+                            if (success) {
+                                // before closing the keyguard, report back that the sim is unlocked
+                                // so it knows right away.
+                                KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
+                                mCallback.dismiss(true);
+                            } else {
+                                mSecurityMessageDisplay.setMessage
+                                    (R.string.kg_password_wrong_pin_code, true);
+                                mPasswordEntry.setText("");
+                            }
+                            mCallback.userActivity(0);
+                            mSimCheckInProgress = false;
+                        }
+                    });
+                }
+            }.start();
+        }
+    }
+}
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
new file mode 100644
index 0000000..7424fab
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import com.android.internal.telephony.ITelephony;
+
+import android.content.Context;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView.OnEditorActionListener;
+
+/**
+ * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
+ */
+public class KeyguardSimPukView extends KeyguardAbsKeyInputView
+        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+
+    private ProgressDialog mSimUnlockProgressDialog = null;
+    private volatile boolean mCheckInProgress;
+    private String mPukText;
+    private String mPinText;
+    private StateMachine mStateMachine = new StateMachine();
+
+    private class StateMachine {
+        final int ENTER_PUK = 0;
+        final int ENTER_PIN = 1;
+        final int CONFIRM_PIN = 2;
+        final int DONE = 3;
+        private int state = ENTER_PUK;
+
+        public void next() {
+            int msg = 0;
+            if (state == ENTER_PUK) {
+                if (checkPuk()) {
+                    state = ENTER_PIN;
+                    msg = R.string.kg_puk_enter_pin_hint;
+                } else {
+                    msg = R.string.kg_invalid_sim_puk_hint;
+                }
+            } else if (state == ENTER_PIN) {
+                if (checkPin()) {
+                    state = CONFIRM_PIN;
+                    msg = R.string.kg_enter_confirm_pin_hint;
+                } else {
+                    msg = R.string.kg_invalid_sim_pin_hint;
+                }
+            } else if (state == CONFIRM_PIN) {
+                if (confirmPin()) {
+                    state = DONE;
+                    msg = R.string.keyguard_sim_unlock_progress_dialog_message;
+                    updateSim();
+                } else {
+                    state = ENTER_PIN; // try again?
+                    msg = R.string.kg_invalid_confirm_pin_hint;
+                }
+            }
+            mPasswordEntry.setText(null);
+            if (msg != 0) {
+                mSecurityMessageDisplay.setMessage(msg, true);
+            }
+        }
+
+        void reset() {
+            mPinText="";
+            mPukText="";
+            state = ENTER_PUK;
+            mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true);
+            mPasswordEntry.requestFocus();
+        }
+    }
+
+    public KeyguardSimPukView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardSimPukView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void resetState() {
+        mStateMachine.reset();
+        mPasswordEntry.setEnabled(true);
+    }
+
+    @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        final View ok = findViewById(R.id.key_enter);
+        if (ok != null) {
+            ok.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    doHapticKeyClick();
+                    verifyPasswordAndUnlock();
+                }
+            });
+        }
+
+        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+        // not a separate view
+        View pinDelete = findViewById(R.id.delete_button);
+        if (pinDelete != null) {
+            pinDelete.setVisibility(View.VISIBLE);
+            pinDelete.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    CharSequence str = mPasswordEntry.getText();
+                    if (str.length() > 0) {
+                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                    }
+                    doHapticKeyClick();
+                }
+            });
+            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    mPasswordEntry.setText("");
+                    doHapticKeyClick();
+                    return true;
+                }
+            });
+        }
+
+        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+
+        mPasswordEntry.requestFocus();
+
+        mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
+    }
+
+    @Override
+    public void showUsabilityHint() {
+    }
+
+    @Override
+    public void onPause() {
+        // dismiss the dialog.
+        if (mSimUnlockProgressDialog != null) {
+            mSimUnlockProgressDialog.dismiss();
+            mSimUnlockProgressDialog = null;
+        }
+    }
+
+    /**
+     * Since the IPC can block, we want to run the request in a separate thread
+     * with a callback.
+     */
+    private abstract class CheckSimPuk extends Thread {
+
+        private final String mPin, mPuk;
+
+        protected CheckSimPuk(String puk, String pin) {
+            mPuk = puk;
+            mPin = pin;
+        }
+
+        abstract void onSimLockChangedResponse(boolean success);
+
+        @Override
+        public void run() {
+            try {
+                final boolean result = ITelephony.Stub.asInterface(ServiceManager
+                        .checkService("phone")).supplyPuk(mPuk, mPin);
+
+                post(new Runnable() {
+                    public void run() {
+                        onSimLockChangedResponse(result);
+                    }
+                });
+            } catch (RemoteException e) {
+                post(new Runnable() {
+                    public void run() {
+                        onSimLockChangedResponse(false);
+                    }
+                });
+            }
+        }
+    }
+
+    private Dialog getSimUnlockProgressDialog() {
+        if (mSimUnlockProgressDialog == null) {
+            mSimUnlockProgressDialog = new ProgressDialog(mContext);
+            mSimUnlockProgressDialog.setMessage(
+                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
+            mSimUnlockProgressDialog.setIndeterminate(true);
+            mSimUnlockProgressDialog.setCancelable(false);
+            if (!(mContext instanceof Activity)) {
+                mSimUnlockProgressDialog.getWindow().setType(
+                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            }
+        }
+        return mSimUnlockProgressDialog;
+    }
+
+    private boolean checkPuk() {
+        // make sure the puk is at least 8 digits long.
+        if (mPasswordEntry.getText().length() >= 8) {
+            mPukText = mPasswordEntry.getText().toString();
+            return true;
+        }
+        return false;
+    }
+
+    private boolean checkPin() {
+        // make sure the PIN is between 4 and 8 digits
+        int length = mPasswordEntry.getText().length();
+        if (length >= 4 && length <= 8) {
+            mPinText = mPasswordEntry.getText().toString();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean confirmPin() {
+        return mPinText.equals(mPasswordEntry.getText().toString());
+    }
+
+    private void updateSim() {
+        getSimUnlockProgressDialog().show();
+
+        if (!mCheckInProgress) {
+            mCheckInProgress = true;
+            new CheckSimPuk(mPukText, mPinText) {
+                void onSimLockChangedResponse(final boolean success) {
+                    post(new Runnable() {
+                        public void run() {
+                            if (mSimUnlockProgressDialog != null) {
+                                mSimUnlockProgressDialog.hide();
+                            }
+                            if (success) {
+                                mCallback.dismiss(true);
+                            } else {
+                                mStateMachine.reset();
+                                mSecurityMessageDisplay.setMessage(R.string.kg_invalid_puk, true);
+                            }
+                            mCheckInProgress = false;
+                        }
+                    });
+                }
+            }.start();
+        }
+    }
+
+    @Override
+    protected void verifyPasswordAndUnlock() {
+        mStateMachine.next();
+    }
+}
+
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
new file mode 100644
index 0000000..0289a1f
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Typeface;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.GridLayout;
+import android.widget.TextView;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import libcore.icu.ICU;
+
+public class KeyguardStatusView extends GridLayout {
+    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static final String TAG = "KeyguardStatusView";
+
+    public static final int LOCK_ICON = 0; // R.drawable.ic_lock_idle_lock;
+    public static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm;
+    public static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging;
+    public static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
+
+    private SimpleDateFormat mDateFormat;
+    private LockPatternUtils mLockPatternUtils;
+
+    private TextView mDateView;
+    private TextView mAlarmStatusView;
+    private ClockView mClockView;
+
+    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
+
+        @Override
+        public void onTimeChanged() {
+            refresh();
+        }
+
+        @Override
+        void onKeyguardVisibilityChanged(boolean showing) {
+            if (showing) {
+                if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
+                refresh();
+            }
+        };
+    };
+
+    public KeyguardStatusView(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardStatusView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        Resources res = getContext().getResources();
+        final Locale locale = Locale.getDefault();
+        final String datePattern = res.getString(R.string.system_ui_date_pattern);
+        final String bestFormat = ICU.getBestDateTimePattern(datePattern, locale.toString());
+        mDateFormat = new SimpleDateFormat(bestFormat, locale);
+        mDateView = (TextView) findViewById(R.id.date);
+        mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
+        mClockView = (ClockView) findViewById(R.id.clock_view);
+        mLockPatternUtils = new LockPatternUtils(getContext());
+
+        // Use custom font in mDateView
+        mDateView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
+
+        // Required to get Marquee to work.
+        final View marqueeViews[] = { mDateView, mAlarmStatusView };
+        for (int i = 0; i < marqueeViews.length; i++) {
+            View v = marqueeViews[i];
+            if (v == null) {
+                throw new RuntimeException("Can't find widget at index " + i);
+            }
+            v.setSelected(true);
+        }
+        refresh();
+    }
+
+    protected void refresh() {
+        mClockView.updateTime();
+        refreshDate();
+        refreshAlarmStatus(); // might as well
+    }
+
+    void refreshAlarmStatus() {
+        // Update Alarm status
+        String nextAlarm = mLockPatternUtils.getNextAlarm();
+        if (!TextUtils.isEmpty(nextAlarm)) {
+            mAlarmStatusView.setText(nextAlarm);
+            mAlarmStatusView.setCompoundDrawablesWithIntrinsicBounds(ALARM_ICON, 0, 0, 0);
+            mAlarmStatusView.setVisibility(View.VISIBLE);
+        } else {
+            mAlarmStatusView.setVisibility(View.GONE);
+        }
+    }
+
+    void refreshDate() {
+        mDateView.setText(mDateFormat.format(new Date()));
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
+    }
+
+    public int getAppWidgetId() {
+        return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET;
+    }
+
+}
diff --git a/cmds/system_server/MODULE_LICENSE_APACHE2 b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusViewManager.java
similarity index 100%
copy from cmds/system_server/MODULE_LICENSE_APACHE2
copy to packages/Keyguard/src/com/android/keyguard/KeyguardStatusViewManager.java
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
new file mode 100644
index 0000000..2a5f979
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
@@ -0,0 +1,469 @@
+/*
+ * 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.
+ */
+
+package com.android.keyguard;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.AudioManager;
+import android.media.IRemoteControlDisplay;
+import android.media.MediaMetadataRetriever;
+import android.media.RemoteControlClient;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+/**
+ * This is the widget responsible for showing music controls in keyguard.
+ */
+public class KeyguardTransportControlView extends FrameLayout implements OnClickListener {
+
+    private static final int MSG_UPDATE_STATE = 100;
+    private static final int MSG_SET_METADATA = 101;
+    private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
+    private static final int MSG_SET_ARTWORK = 103;
+    private static final int MSG_SET_GENERATION_ID = 104;
+    private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
+    protected static final boolean DEBUG = false;
+    protected static final String TAG = "TransportControlView";
+
+    private ImageView mAlbumArt;
+    private TextView mTrackTitle;
+    private ImageView mBtnPrev;
+    private ImageView mBtnPlay;
+    private ImageView mBtnNext;
+    private int mClientGeneration;
+    private Metadata mMetadata = new Metadata();
+    private boolean mAttached;
+    private PendingIntent mClientIntent;
+    private int mTransportControlFlags;
+    private int mCurrentPlayState;
+    private AudioManager mAudioManager;
+    private IRemoteControlDisplayWeak mIRCD;
+
+    /**
+     * The metadata which should be populated into the view once we've been attached
+     */
+    private Bundle mPopulateMetadataWhenAttached = null;
+
+    // This handler is required to ensure messages from IRCD are handled in sequence and on
+    // the UI thread.
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_UPDATE_STATE:
+                if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2);
+                break;
+
+            case MSG_SET_METADATA:
+                if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj);
+                break;
+
+            case MSG_SET_TRANSPORT_CONTROLS:
+                if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2);
+                break;
+
+            case MSG_SET_ARTWORK:
+                if (mClientGeneration == msg.arg1) {
+                    mMetadata.bitmap = (Bitmap) msg.obj;
+                    KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(
+                            mMetadata.bitmap);
+                }
+                break;
+
+            case MSG_SET_GENERATION_ID:
+                if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
+                mClientGeneration = msg.arg1;
+                mClientIntent = (PendingIntent) msg.obj;
+                break;
+
+            }
+        }
+    };
+
+    /**
+     * This class is required to have weak linkage to the current TransportControlView
+     * because the remote process can hold a strong reference to this binder object and
+     * we can't predict when it will be GC'd in the remote process. Without this code, it
+     * would allow a heavyweight object to be held on this side of the binder when there's
+     * no requirement to run a GC on the other side.
+     */
+    private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub {
+        private WeakReference<Handler> mLocalHandler;
+
+        IRemoteControlDisplayWeak(Handler handler) {
+            mLocalHandler = new WeakReference<Handler>(handler);
+        }
+
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
+            Handler handler = mLocalHandler.get();
+            if (handler != null) {
+                handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
+            }
+        }
+
+        public void setMetadata(int generationId, Bundle metadata) {
+            Handler handler = mLocalHandler.get();
+            if (handler != null) {
+                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
+            }
+        }
+
+        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
+            Handler handler = mLocalHandler.get();
+            if (handler != null) {
+                handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
+                        .sendToTarget();
+            }
+        }
+
+        public void setArtwork(int generationId, Bitmap bitmap) {
+            Handler handler = mLocalHandler.get();
+            if (handler != null) {
+                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
+            }
+        }
+
+        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
+            Handler handler = mLocalHandler.get();
+            if (handler != null) {
+                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
+                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
+            }
+        }
+
+        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
+                boolean clearing) throws RemoteException {
+            Handler handler = mLocalHandler.get();
+            if (handler != null) {
+                handler.obtainMessage(MSG_SET_GENERATION_ID,
+                    clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
+            }
+        }
+    };
+
+    public KeyguardTransportControlView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        if (DEBUG) Log.v(TAG, "Create TCV " + this);
+        mAudioManager = new AudioManager(mContext);
+        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
+        mIRCD = new IRemoteControlDisplayWeak(mHandler);
+    }
+
+    private void updateTransportControls(int transportControlFlags) {
+        mTransportControlFlags = transportControlFlags;
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        mTrackTitle = (TextView) findViewById(R.id.title);
+        mTrackTitle.setSelected(true); // enable marquee
+        mAlbumArt = (ImageView) findViewById(R.id.albumart);
+        mBtnPrev = (ImageView) findViewById(R.id.btn_prev);
+        mBtnPlay = (ImageView) findViewById(R.id.btn_play);
+        mBtnNext = (ImageView) findViewById(R.id.btn_next);
+        final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext };
+        for (View view : buttons) {
+            view.setOnClickListener(this);
+        }
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (DEBUG) Log.v(TAG, "onAttachToWindow()");
+        if (mPopulateMetadataWhenAttached != null) {
+            updateMetadata(mPopulateMetadataWhenAttached);
+            mPopulateMetadataWhenAttached = null;
+        }
+        if (!mAttached) {
+            if (DEBUG) Log.v(TAG, "Registering TCV " + this);
+            mAudioManager.registerRemoteControlDisplay(mIRCD);
+        }
+        mAttached = true;
+    }
+
+    @Override
+    protected void onSizeChanged (int w, int h, int oldw, int oldh) {
+        if (mAttached) {
+            final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
+            int dim = Math.max(dm.widthPixels, dm.heightPixels);
+            if (DEBUG) Log.v(TAG, "TCV uses bitmap size=" + dim);
+            mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        if (DEBUG) Log.v(TAG, "onDetachFromWindow()");
+        super.onDetachedFromWindow();
+        if (mAttached) {
+            if (DEBUG) Log.v(TAG, "Unregistering TCV " + this);
+            mAudioManager.unregisterRemoteControlDisplay(mIRCD);
+        }
+        mAttached = false;
+    }
+
+    class Metadata {
+        private String artist;
+        private String trackTitle;
+        private String albumTitle;
+        private Bitmap bitmap;
+
+        public String toString() {
+            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]";
+        }
+    }
+
+    private String getMdString(Bundle data, int id) {
+        return data.getString(Integer.toString(id));
+    }
+
+    private void updateMetadata(Bundle data) {
+        if (mAttached) {
+            mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
+            mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE);
+            mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM);
+            populateMetadata();
+        } else {
+            mPopulateMetadataWhenAttached = data;
+        }
+    }
+
+    /**
+     * Populates the given metadata into the view
+     */
+    private void populateMetadata() {
+        StringBuilder sb = new StringBuilder();
+        int trackTitleLength = 0;
+        if (!TextUtils.isEmpty(mMetadata.trackTitle)) {
+            sb.append(mMetadata.trackTitle);
+            trackTitleLength = mMetadata.trackTitle.length();
+        }
+        if (!TextUtils.isEmpty(mMetadata.artist)) {
+            if (sb.length() != 0) {
+                sb.append(" - ");
+            }
+            sb.append(mMetadata.artist);
+        }
+        if (!TextUtils.isEmpty(mMetadata.albumTitle)) {
+            if (sb.length() != 0) {
+                sb.append(" - ");
+            }
+            sb.append(mMetadata.albumTitle);
+        }
+        mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE);
+        Spannable str = (Spannable) mTrackTitle.getText();
+        if (trackTitleLength != 0) {
+            str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength,
+                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            trackTitleLength++;
+        }
+        if (sb.length() > trackTitleLength) {
+            str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(),
+                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+
+        KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(
+                mMetadata.bitmap);
+        final int flags = mTransportControlFlags;
+        setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
+        setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
+        setVisibilityBasedOnFlag(mBtnPlay, flags,
+                RemoteControlClient.FLAG_KEY_MEDIA_PLAY
+                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
+                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
+                | RemoteControlClient.FLAG_KEY_MEDIA_STOP);
+
+        updatePlayPauseState(mCurrentPlayState);
+    }
+
+    private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
+        if ((flags & flag) != 0) {
+            view.setVisibility(View.VISIBLE);
+        } else {
+            view.setVisibility(View.GONE);
+        }
+    }
+
+    private void updatePlayPauseState(int state) {
+        if (DEBUG) Log.v(TAG,
+                "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
+        if (state == mCurrentPlayState) {
+            return;
+        }
+        final int imageResId;
+        final int imageDescId;
+        switch (state) {
+            case RemoteControlClient.PLAYSTATE_ERROR:
+                imageResId = R.drawable.stat_sys_warning;
+                // TODO use more specific image description string for warning, but here the "play"
+                //      message is still valid because this button triggers a play command.
+                imageDescId = R.string.keyguard_transport_play_description;
+                break;
+
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+                imageResId = R.drawable.ic_media_pause;
+                imageDescId = R.string.keyguard_transport_pause_description;
+                break;
+
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+                imageResId = R.drawable.ic_media_stop;
+                imageDescId = R.string.keyguard_transport_stop_description;
+                break;
+
+            case RemoteControlClient.PLAYSTATE_PAUSED:
+            default:
+                imageResId = R.drawable.ic_media_play;
+                imageDescId = R.string.keyguard_transport_play_description;
+                break;
+        }
+        mBtnPlay.setImageResource(imageResId);
+        mBtnPlay.setContentDescription(getResources().getString(imageDescId));
+        mCurrentPlayState = state;
+    }
+
+    static class SavedState extends BaseSavedState {
+        boolean clientPresent;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            this.clientPresent = in.readInt() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(this.clientPresent ? 1 : 0);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    public void onClick(View v) {
+        int keyCode = -1;
+        if (v == mBtnPrev) {
+            keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
+        } else if (v == mBtnNext) {
+            keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
+        } else if (v == mBtnPlay) {
+            keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
+
+        }
+        if (keyCode != -1) {
+            sendMediaButtonClick(keyCode);
+        }
+    }
+
+    private void sendMediaButtonClick(int keyCode) {
+        if (mClientIntent == null) {
+            // Shouldn't be possible because this view should be hidden in this case.
+            Log.e(TAG, "sendMediaButtonClick(): No client is currently registered");
+            return;
+        }
+        // use the registered PendingIntent that will be processed by the registered
+        //    media button event receiver, which is the component of mClientIntent
+        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        try {
+            mClientIntent.send(getContext(), 0, intent);
+        } catch (CanceledException e) {
+            Log.e(TAG, "Error sending intent for media button down: "+e);
+            e.printStackTrace();
+        }
+
+        keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
+        intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        try {
+            mClientIntent.send(getContext(), 0, intent);
+        } catch (CanceledException e) {
+            Log.e(TAG, "Error sending intent for media button up: "+e);
+            e.printStackTrace();
+        }
+    }
+
+    public boolean providesClock() {
+        return false;
+    }
+
+    private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
+        switch (state) {
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+                // actively playing or about to play
+                return true;
+            case RemoteControlClient.PLAYSTATE_NONE:
+                return false;
+            case RemoteControlClient.PLAYSTATE_STOPPED:
+            case RemoteControlClient.PLAYSTATE_PAUSED:
+            case RemoteControlClient.PLAYSTATE_ERROR:
+                // we have stopped playing, check how long ago
+                if (DEBUG) {
+                    if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
+                        Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
+                    } else {
+                        Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
+                    }
+                }
+                return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
+            default:
+                Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
+                return false;
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
new file mode 100644
index 0000000..734f517
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -0,0 +1,1040 @@
+/*
+ * 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 com.android.keyguard;
+
+import android.app.ActivityManagerNative;
+import android.app.IUserSwitchObserver;
+import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.graphics.Bitmap;
+
+import static android.os.BatteryManager.BATTERY_STATUS_FULL;
+import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
+import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
+import static android.os.BatteryManager.EXTRA_STATUS;
+import static android.os.BatteryManager.EXTRA_PLUGGED;
+import static android.os.BatteryManager.EXTRA_LEVEL;
+import static android.os.BatteryManager.EXTRA_HEALTH;
+import android.media.AudioManager;
+import android.media.IRemoteControlDisplay;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import com.google.android.collect.Lists;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Watches for updates that may be interesting to the keyguard, and provides
+ * the up to date information as well as a registration for callbacks that care
+ * to be updated.
+ *
+ * Note: under time crunch, this has been extended to include some stuff that
+ * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
+ * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
+ * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
+ */
+public class KeyguardUpdateMonitor {
+
+    private static final String TAG = "KeyguardUpdateMonitor";
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_SIM_STATES = DEBUG || false;
+    private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
+    private static final int LOW_BATTERY_THRESHOLD = 20;
+
+    // Callback messages
+    private static final int MSG_TIME_UPDATE = 301;
+    private static final int MSG_BATTERY_UPDATE = 302;
+    private static final int MSG_CARRIER_INFO_UPDATE = 303;
+    private static final int MSG_SIM_STATE_CHANGE = 304;
+    private static final int MSG_RINGER_MODE_CHANGED = 305;
+    private static final int MSG_PHONE_STATE_CHANGED = 306;
+    private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
+    private static final int MSG_DEVICE_PROVISIONED = 308;
+    private static final int MSG_DPM_STATE_CHANGED = 309;
+    private static final int MSG_USER_SWITCHING = 310;
+    private static final int MSG_USER_REMOVED = 311;
+    private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
+    protected static final int MSG_BOOT_COMPLETED = 313;
+    private static final int MSG_USER_SWITCH_COMPLETE = 314;
+    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
+    protected static final int MSG_SET_PLAYBACK_STATE = 316;
+    protected static final int MSG_USER_INFO_CHANGED = 317;
+    protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
+
+
+    private static KeyguardUpdateMonitor sInstance;
+
+    private final Context mContext;
+
+    // Telephony state
+    private IccCardConstants.State mSimState = IccCardConstants.State.READY;
+    private CharSequence mTelephonyPlmn;
+    private CharSequence mTelephonySpn;
+    private int mRingMode;
+    private int mPhoneState;
+    private boolean mKeyguardIsVisible;
+    private boolean mBootCompleted;
+
+    // Device provisioning state
+    private boolean mDeviceProvisioned;
+
+    // Battery status
+    private BatteryStatus mBatteryStatus;
+
+    // Password attempts
+    private int mFailedAttempts = 0;
+    private int mFailedBiometricUnlockAttempts = 0;
+
+    private boolean mAlternateUnlockEnabled;
+
+    private boolean mClockVisible;
+
+    private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
+            mCallbacks = Lists.newArrayList();
+    private ContentObserver mDeviceProvisionedObserver;
+
+    private boolean mSwitchingUser;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_TIME_UPDATE:
+                    handleTimeUpdate();
+                    break;
+                case MSG_BATTERY_UPDATE:
+                    handleBatteryUpdate((BatteryStatus) msg.obj);
+                    break;
+                case MSG_CARRIER_INFO_UPDATE:
+                    handleCarrierInfoUpdate();
+                    break;
+                case MSG_SIM_STATE_CHANGE:
+                    handleSimStateChange((SimArgs) msg.obj);
+                    break;
+                case MSG_RINGER_MODE_CHANGED:
+                    handleRingerModeChange(msg.arg1);
+                    break;
+                case MSG_PHONE_STATE_CHANGED:
+                    handlePhoneStateChanged((String)msg.obj);
+                    break;
+                case MSG_CLOCK_VISIBILITY_CHANGED:
+                    handleClockVisibilityChanged();
+                    break;
+                case MSG_DEVICE_PROVISIONED:
+                    handleDeviceProvisioned();
+                    break;
+                case MSG_DPM_STATE_CHANGED:
+                    handleDevicePolicyManagerStateChanged();
+                    break;
+                case MSG_USER_SWITCHING:
+                    handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj);
+                    break;
+                case MSG_USER_SWITCH_COMPLETE:
+                    handleUserSwitchComplete(msg.arg1);
+                    break;
+                case MSG_USER_REMOVED:
+                    handleUserRemoved(msg.arg1);
+                    break;
+                case MSG_KEYGUARD_VISIBILITY_CHANGED:
+                    handleKeyguardVisibilityChanged(msg.arg1);
+                    break;
+                case MSG_BOOT_COMPLETED:
+                    handleBootCompleted();
+                    break;
+                case MSG_SET_CURRENT_CLIENT_ID:
+                    handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj);
+                    break;
+                case MSG_SET_PLAYBACK_STATE:
+                    handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
+                    break;
+                case MSG_USER_INFO_CHANGED:
+                    handleUserInfoChanged(msg.arg1);
+                    break;
+                case MSG_REPORT_EMERGENCY_CALL_ACTION:
+                    handleReportEmergencyCallAction();
+                    break;
+            }
+        }
+    };
+
+    private AudioManager mAudioManager;
+
+    static class DisplayClientState {
+        public int clientGeneration;
+        public boolean clearing;
+        public PendingIntent intent;
+        public int playbackState;
+        public long playbackEventTime;
+    }
+
+    private DisplayClientState mDisplayClientState = new DisplayClientState();
+
+    /**
+     * This currently implements the bare minimum required to enable showing and hiding
+     * KeyguardTransportControl.  There's a lot of client state to maintain which is why
+     * KeyguardTransportControl maintains an independent connection while it's showing.
+     */
+    private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
+                new IRemoteControlDisplay.Stub() {
+
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
+            Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
+                    generationId, state, stateChangeTimeMs);
+            mHandler.sendMessage(msg);
+        }
+
+        public void setMetadata(int generationId, Bundle metadata) {
+
+        }
+
+        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
+
+        }
+
+        public void setArtwork(int generationId, Bitmap bitmap) {
+
+        }
+
+        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
+
+        }
+
+        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
+                boolean clearing) throws RemoteException {
+            Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID,
+                        clientGeneration, (clearing ? 1 : 0), mediaIntent);
+            mHandler.sendMessage(msg);
+        }
+    };
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (DEBUG) Log.d(TAG, "received broadcast " + action);
+
+            if (Intent.ACTION_TIME_TICK.equals(action)
+                    || Intent.ACTION_TIME_CHANGED.equals(action)
+                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+                mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
+            } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
+                mTelephonyPlmn = getTelephonyPlmnFrom(intent);
+                mTelephonySpn = getTelephonySpnFrom(intent);
+                mHandler.sendEmptyMessage(MSG_CARRIER_INFO_UPDATE);
+            } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+                final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
+                final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
+                final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
+                final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
+                final Message msg = mHandler.obtainMessage(
+                        MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
+                mHandler.sendMessage(msg);
+            } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
+                if (DEBUG_SIM_STATES) {
+                    Log.v(TAG, "action " + action + " state" +
+                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE));
+                }
+                mHandler.sendMessage(mHandler.obtainMessage(
+                        MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent)));
+            } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
+                        intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
+            } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
+                String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
+            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+                    .equals(action)) {
+                mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
+                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+                dispatchBootCompleted();
+            }
+        }
+    };
+
+    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
+
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,
+                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));
+            }
+        }
+    };
+
+    /**
+     * When we receive a
+     * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
+     * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
+     * we need a single object to pass to the handler.  This class helps decode
+     * the intent and provide a {@link SimCard.State} result.
+     */
+    private static class SimArgs {
+        public final IccCardConstants.State simState;
+
+        SimArgs(IccCardConstants.State state) {
+            simState = state;
+        }
+
+        static SimArgs fromIntent(Intent intent) {
+            IccCardConstants.State state;
+            if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
+                throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
+            }
+            String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+            if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+                final String absentReason = intent
+                    .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+
+                if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
+                        absentReason)) {
+                    state = IccCardConstants.State.PERM_DISABLED;
+                } else {
+                    state = IccCardConstants.State.ABSENT;
+                }
+            } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+                state = IccCardConstants.State.READY;
+            } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+                final String lockedReason = intent
+                        .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+                if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                    state = IccCardConstants.State.PIN_REQUIRED;
+                } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                    state = IccCardConstants.State.PUK_REQUIRED;
+                } else {
+                    state = IccCardConstants.State.UNKNOWN;
+                }
+            } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
+                state = IccCardConstants.State.NETWORK_LOCKED;
+            } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
+                        || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
+                // This is required because telephony doesn't return to "READY" after
+                // these state transitions. See bug 7197471.
+                state = IccCardConstants.State.READY;
+            } else {
+                state = IccCardConstants.State.UNKNOWN;
+            }
+            return new SimArgs(state);
+        }
+
+        public String toString() {
+            return simState.toString();
+        }
+    }
+
+    /* package */ static class BatteryStatus {
+        public final int status;
+        public final int level;
+        public final int plugged;
+        public final int health;
+        public BatteryStatus(int status, int level, int plugged, int health) {
+            this.status = status;
+            this.level = level;
+            this.plugged = plugged;
+            this.health = health;
+        }
+
+        /**
+         * Determine whether the device is plugged in (USB, power, or wireless).
+         * @return true if the device is plugged in.
+         */
+        boolean isPluggedIn() {
+            return plugged == BatteryManager.BATTERY_PLUGGED_AC
+                    || plugged == BatteryManager.BATTERY_PLUGGED_USB
+                    || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
+        }
+
+        /**
+         * Whether or not the device is charged. Note that some devices never return 100% for
+         * battery level, so this allows either battery level or status to determine if the
+         * battery is charged.
+         * @return true if the device is charged
+         */
+        public boolean isCharged() {
+            return status == BATTERY_STATUS_FULL || level >= 100;
+        }
+
+        /**
+         * Whether battery is low and needs to be charged.
+         * @return true if battery is low
+         */
+        public boolean isBatteryLow() {
+            return level < LOW_BATTERY_THRESHOLD;
+        }
+
+    }
+
+    public static KeyguardUpdateMonitor getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new KeyguardUpdateMonitor(context);
+        }
+        return sInstance;
+    }
+
+    /**
+     * IMPORTANT: Must be called from UI thread.
+     */
+    public void dispatchSetBackground(Bitmap bmp) {
+        if (DEBUG) Log.d(TAG, "dispatchSetBackground");
+        final int count = mCallbacks.size();
+        for (int i = 0; i < count; i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onSetBackground(bmp);
+            }
+        }
+    }
+
+    protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
+        mDisplayClientState.clientGeneration = clientGeneration;
+        mDisplayClientState.clearing = clearing;
+        mDisplayClientState.intent = p;
+        if (DEBUG)
+            Log.v(TAG, "handleSetGenerationId(g=" + clientGeneration + ", clear=" + clearing + ")");
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onMusicClientIdChanged(clientGeneration, clearing, p);
+            }
+        }
+    }
+
+    protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) {
+        if (DEBUG)
+            Log.v(TAG, "handleSetPlaybackState(gen=" + generationId
+                + ", state=" + playbackState + ", t=" + eventTime + ")");
+        mDisplayClientState.playbackState = playbackState;
+        mDisplayClientState.playbackEventTime = eventTime;
+        if (generationId == mDisplayClientState.clientGeneration) {
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onMusicPlaybackStateChanged(playbackState, eventTime);
+                }
+            }
+        } else {
+            Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current");
+        }
+    }
+
+    private void handleUserInfoChanged(int userId) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onUserInfoChanged(userId);
+            }
+        }
+    }
+
+    private KeyguardUpdateMonitor(Context context) {
+        mContext = context;
+
+        mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
+        // Since device can't be un-provisioned, we only need to register a content observer
+        // to update mDeviceProvisioned when we are...
+        if (!mDeviceProvisioned) {
+            watchForDeviceProvisioning();
+        }
+
+        // Take a guess at initial SIM state, battery status and PLMN until we get an update
+        mSimState = IccCardConstants.State.NOT_READY;
+        mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
+        mTelephonyPlmn = getDefaultPlmn();
+
+        // Watch for interesting updates
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_TIME_TICK);
+        filter.addAction(Intent.ACTION_TIME_CHANGED);
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
+        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        filter.addAction(Intent.ACTION_USER_REMOVED);
+        context.registerReceiver(mBroadcastReceiver, filter);
+
+        final IntentFilter bootCompleteFilter = new IntentFilter();
+        bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
+
+        final IntentFilter userInfoFilter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED);
+        context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, userInfoFilter,
+                null, null);
+
+        try {
+            ActivityManagerNative.getDefault().registerUserSwitchObserver(
+                    new IUserSwitchObserver.Stub() {
+                        @Override
+                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
+                                    newUserId, 0, reply));
+                            mSwitchingUser = true;
+                        }
+                        @Override
+                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
+                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
+                                    newUserId));
+                            mSwitchingUser = false;
+                        }
+                    });
+        } catch (RemoteException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    private boolean isDeviceProvisionedInSettingsDb() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    private void watchForDeviceProvisioning() {
+        mDeviceProvisionedObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                super.onChange(selfChange);
+                mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
+                if (mDeviceProvisioned) {
+                    mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
+                }
+                if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
+                false, mDeviceProvisionedObserver);
+
+        // prevent a race condition between where we check the flag and where we register the
+        // observer by grabbing the value once again...
+        boolean provisioned = isDeviceProvisionedInSettingsDb();
+        if (provisioned != mDeviceProvisioned) {
+            mDeviceProvisioned = provisioned;
+            if (mDeviceProvisioned) {
+                mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_DPM_STATE_CHANGED}
+     */
+    protected void handleDevicePolicyManagerStateChanged() {
+        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onDevicePolicyManagerStateChanged();
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_USER_SWITCHING}
+     */
+    protected void handleUserSwitching(int userId, IRemoteCallback reply) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onUserSwitching(userId);
+            }
+        }
+        try {
+            reply.sendResult(null);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_USER_SWITCH_COMPLETE}
+     */
+    protected void handleUserSwitchComplete(int userId) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onUserSwitchComplete(userId);
+            }
+        }
+    }
+
+    /**
+     * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If
+     * keyguard crashes sometime after boot, then it will never receive this
+     * broadcast and hence not handle the event. This method is ultimately called by
+     * PhoneWindowManager in this case.
+     */
+    protected void dispatchBootCompleted() {
+        if (!mBootCompleted) {
+            mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_BOOT_COMPLETED}
+     */
+    protected void handleBootCompleted() {
+        mBootCompleted = true;
+        mAudioManager = new AudioManager(mContext);
+        mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onBootCompleted();
+            }
+        }
+    }
+
+    /**
+     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
+     * destroyed.
+     */
+    public boolean hasBootCompleted() {
+        return mBootCompleted;
+    }
+
+    /**
+     * Handle {@link #MSG_USER_REMOVED}
+     */
+    protected void handleUserRemoved(int userId) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onUserRemoved(userId);
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_DEVICE_PROVISIONED}
+     */
+    protected void handleDeviceProvisioned() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onDeviceProvisioned();
+            }
+        }
+        if (mDeviceProvisionedObserver != null) {
+            // We don't need the observer anymore...
+            mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
+            mDeviceProvisionedObserver = null;
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_PHONE_STATE_CHANGED}
+     */
+    protected void handlePhoneStateChanged(String newState) {
+        if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
+        if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
+            mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+        } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
+            mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
+        } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
+            mPhoneState = TelephonyManager.CALL_STATE_RINGING;
+        }
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onPhoneStateChanged(mPhoneState);
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_RINGER_MODE_CHANGED}
+     */
+    protected void handleRingerModeChange(int mode) {
+        if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
+        mRingMode = mode;
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onRingerModeChanged(mode);
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_TIME_UPDATE}
+     */
+    private void handleTimeUpdate() {
+        if (DEBUG) Log.d(TAG, "handleTimeUpdate");
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onTimeChanged();
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_BATTERY_UPDATE}
+     */
+    private void handleBatteryUpdate(BatteryStatus status) {
+        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
+        final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
+        mBatteryStatus = status;
+        if (batteryUpdateInteresting) {
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onRefreshBatteryInfo(status);
+                }
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_CARRIER_INFO_UPDATE}
+     */
+    private void handleCarrierInfoUpdate() {
+        if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
+            + ", spn = " + mTelephonySpn);
+
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_SIM_STATE_CHANGE}
+     */
+    private void handleSimStateChange(SimArgs simArgs) {
+        final IccCardConstants.State state = simArgs.simState;
+
+        if (DEBUG) {
+            Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
+                    + "state resolved to " + state.toString());
+        }
+
+        if (state != IccCardConstants.State.UNKNOWN && state != mSimState) {
+            mSimState = state;
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onSimStateChanged(state);
+                }
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
+     */
+    private void handleClockVisibilityChanged() {
+        if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onClockVisibilityChanged();
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
+     */
+    private void handleKeyguardVisibilityChanged(int showing) {
+        if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
+        boolean isShowing = (showing == 1);
+        mKeyguardIsVisible = isShowing;
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onKeyguardVisibilityChanged(isShowing);
+            }
+        }
+    }
+
+    /**
+     * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
+     */
+    private void handleReportEmergencyCallAction() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onEmergencyCallAction();
+            }
+        }
+    }
+
+    public boolean isKeyguardVisible() {
+        return mKeyguardIsVisible;
+    }
+
+    public boolean isSwitchingUser() {
+        return mSwitchingUser;
+    }
+
+    private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
+        final boolean nowPluggedIn = current.isPluggedIn();
+        final boolean wasPluggedIn = old.isPluggedIn();
+        final boolean stateChangedWhilePluggedIn =
+            wasPluggedIn == true && nowPluggedIn == true
+            && (old.status != current.status);
+
+        // change in plug state is always interesting
+        if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
+            return true;
+        }
+
+        // change in battery level while plugged in
+        if (nowPluggedIn && old.level != current.level) {
+            return true;
+        }
+
+        // change where battery needs charging
+        if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION}
+     * @return The string to use for the plmn, or null if it should not be shown.
+     */
+    private CharSequence getTelephonyPlmnFrom(Intent intent) {
+        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
+            final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
+            return (plmn != null) ? plmn : getDefaultPlmn();
+        }
+        return null;
+    }
+
+    /**
+     * @return The default plmn (no service)
+     */
+    private CharSequence getDefaultPlmn() {
+        return mContext.getResources().getText(R.string.keyguard_carrier_default);
+    }
+
+    /**
+     * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
+     * @return The string to use for the plmn, or null if it should not be shown.
+     */
+    private CharSequence getTelephonySpnFrom(Intent intent) {
+        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
+            final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN);
+            if (spn != null) {
+                return spn;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Remove the given observer's callback.
+     *
+     * @param callback The callback to remove
+     */
+    public void removeCallback(KeyguardUpdateMonitorCallback callback) {
+        if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback);
+        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+            if (mCallbacks.get(i).get() == callback) {
+                mCallbacks.remove(i);
+            }
+        }
+    }
+
+    /**
+     * Register to receive notifications about general keyguard information
+     * (see {@link InfoCallback}.
+     * @param callback The callback to register
+     */
+    public void registerCallback(KeyguardUpdateMonitorCallback callback) {
+        if (DEBUG) Log.v(TAG, "*** register callback for " + callback);
+        // Prevent adding duplicate callbacks
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            if (mCallbacks.get(i).get() == callback) {
+                if (DEBUG) Log.e(TAG, "Object tried to add another callback",
+                        new Exception("Called by"));
+                return;
+            }
+        }
+        mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
+        removeCallback(null); // remove unused references
+        sendUpdates(callback);
+    }
+
+    private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
+        // Notify listener of the current state
+        callback.onRefreshBatteryInfo(mBatteryStatus);
+        callback.onTimeChanged();
+        callback.onRingerModeChanged(mRingMode);
+        callback.onPhoneStateChanged(mPhoneState);
+        callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
+        callback.onClockVisibilityChanged();
+        callback.onSimStateChanged(mSimState);
+        callback.onMusicClientIdChanged(
+                mDisplayClientState.clientGeneration,
+                mDisplayClientState.clearing,
+                mDisplayClientState.intent);
+        callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
+                mDisplayClientState.playbackEventTime);
+    }
+
+    public void sendKeyguardVisibilityChanged(boolean showing) {
+        if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
+        Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
+        message.arg1 = showing ? 1 : 0;
+        message.sendToTarget();
+    }
+
+    public void reportClockVisible(boolean visible) {
+        mClockVisible = visible;
+        mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
+    }
+
+    public IccCardConstants.State getSimState() {
+        return mSimState;
+    }
+
+    /**
+     * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
+     * have the information earlier than waiting for the intent
+     * broadcast from the telephony code.
+     *
+     * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
+     * through mHandler, this *must* be called from the UI thread.
+     */
+    public void reportSimUnlocked() {
+        handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
+    }
+
+    /**
+     * Report that the emergency call button has been pressed and the emergency dialer is
+     * about to be displayed.
+     *
+     * @param bypassHandler runs immediately.
+     *
+     * NOTE: Must be called from UI thread if bypassHandler == true.
+     */
+    public void reportEmergencyCallAction(boolean bypassHandler) {
+        if (!bypassHandler) {
+            mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
+        } else {
+            handleReportEmergencyCallAction();
+        }
+    }
+
+    public CharSequence getTelephonyPlmn() {
+        return mTelephonyPlmn;
+    }
+
+    public CharSequence getTelephonySpn() {
+        return mTelephonySpn;
+    }
+
+    /**
+     * @return Whether the device is provisioned (whether they have gone through
+     *   the setup wizard)
+     */
+    public boolean isDeviceProvisioned() {
+        return mDeviceProvisioned;
+    }
+
+    public int getFailedUnlockAttempts() {
+        return mFailedAttempts;
+    }
+
+    public void clearFailedUnlockAttempts() {
+        mFailedAttempts = 0;
+        mFailedBiometricUnlockAttempts = 0;
+    }
+
+    public void reportFailedUnlockAttempt() {
+        mFailedAttempts++;
+    }
+
+    public boolean isClockVisible() {
+        return mClockVisible;
+    }
+
+    public int getPhoneState() {
+        return mPhoneState;
+    }
+
+    public void reportFailedBiometricUnlockAttempt() {
+        mFailedBiometricUnlockAttempts++;
+    }
+
+    public boolean getMaxBiometricUnlockAttemptsReached() {
+        return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
+    }
+
+    public boolean isAlternateUnlockEnabled() {
+        return mAlternateUnlockEnabled;
+    }
+
+    public void setAlternateUnlockEnabled(boolean enabled) {
+        mAlternateUnlockEnabled = enabled;
+    }
+
+    public boolean isSimLocked() {
+        return isSimLocked(mSimState);
+    }
+
+    public static boolean isSimLocked(IccCardConstants.State state) {
+        return state == IccCardConstants.State.PIN_REQUIRED
+        || state == IccCardConstants.State.PUK_REQUIRED
+        || state == IccCardConstants.State.PERM_DISABLED;
+    }
+
+    public boolean isSimPinSecure() {
+        return isSimPinSecure(mSimState);
+    }
+
+    public static boolean isSimPinSecure(IccCardConstants.State state) {
+        final IccCardConstants.State simState = state;
+        return (simState == IccCardConstants.State.PIN_REQUIRED
+                || simState == IccCardConstants.State.PUK_REQUIRED
+                || simState == IccCardConstants.State.PERM_DISABLED);
+    }
+
+    public DisplayClientState getCachedDisplayClientState() {
+        return mDisplayClientState;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
new file mode 100644
index 0000000..e6dddab
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.graphics.Bitmap;
+import android.media.AudioManager;
+
+import com.android.internal.telephony.IccCardConstants;
+
+/**
+ * Callback for general information relevant to lock screen.
+ */
+class KeyguardUpdateMonitorCallback {
+    /**
+     * Called when the battery status changes, e.g. when plugged in or unplugged, charge
+     * level, etc. changes.
+     *
+     * @param status current battery status
+     */
+    void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { }
+
+    /**
+     * Called once per minute or when the time changes.
+     */
+    void onTimeChanged() { }
+
+    /**
+     * Called when the carrier PLMN or SPN changes.
+     *
+     * @param plmn The operator name of the registered network.  May be null if it shouldn't
+     *   be displayed.
+     * @param spn The service provider name.  May be null if it shouldn't be displayed.
+     */
+    void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { }
+
+    /**
+     * Called when the ringer mode changes.
+     * @param state the current ringer state, as defined in
+     * {@link AudioManager#RINGER_MODE_CHANGED_ACTION}
+     */
+    void onRingerModeChanged(int state) { }
+
+    /**
+     * Called when the phone state changes. String will be one of:
+     * {@link TelephonyManager#EXTRA_STATE_IDLE}
+     * {@link TelephonyManager@EXTRA_STATE_RINGING}
+     * {@link TelephonyManager#EXTRA_STATE_OFFHOOK
+     */
+    void onPhoneStateChanged(int phoneState) { }
+
+    /**
+     * Called when the visibility of the keyguard changes.
+     * @param showing Indicates if the keyguard is now visible.
+     */
+    void onKeyguardVisibilityChanged(boolean showing) { }
+
+    /**
+     * Called when visibility of lockscreen clock changes, such as when
+     * obscured by a widget.
+     */
+    void onClockVisibilityChanged() { }
+
+    /**
+     * Called when the device becomes provisioned
+     */
+    void onDeviceProvisioned() { }
+
+    /**
+     * Called when the device policy changes.
+     * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
+     */
+    void onDevicePolicyManagerStateChanged() { }
+
+    /**
+     * Called when the user change begins.
+     */
+    void onUserSwitching(int userId) { }
+
+    /**
+     * Called when the user change is complete.
+     */
+    void onUserSwitchComplete(int userId) { }
+
+    /**
+     * Called when the SIM state changes.
+     * @param simState
+     */
+    void onSimStateChanged(IccCardConstants.State simState) { }
+
+    /**
+     * Called when a user is removed.
+     */
+    void onUserRemoved(int userId) { }
+
+    /**
+     * Called when the user's info changed.
+     */
+    void onUserInfoChanged(int userId) { }
+
+    /**
+     * Called when boot completed.
+     *
+     * Note, this callback will only be received if boot complete occurs after registering with
+     * KeyguardUpdateMonitor.
+     */
+    void onBootCompleted() { }
+
+    /**
+     * Called when audio client attaches or detaches from AudioManager.
+     */
+    void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
+
+    /**
+     * Called when the audio playback state changes.
+     * @param playbackState
+     * @param eventTime
+     */
+    public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
+
+    /**
+     * Called when the emergency call button is pressed.
+     */
+    void onEmergencyCallAction() { }
+
+    public void onSetBackground(Bitmap bitmap) {
+        // THIS SPACE FOR RENT
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
new file mode 100644
index 0000000..bff1f93
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.app.Activity;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.IAudioService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.view.KeyEvent;
+import android.widget.FrameLayout;
+
+/**
+ * Base class for keyguard view.  {@link #reset} is where you should
+ * reset the state of your view.  Use the {@link KeyguardViewCallback} via
+ * {@link #getCallback()} to send information back (such as poking the wake lock,
+ * or finishing the keyguard).
+ *
+ * Handles intercepting of media keys that still work when the keyguard is
+ * showing.
+ */
+public abstract class KeyguardViewBase extends FrameLayout {
+
+    private AudioManager mAudioManager;
+    private TelephonyManager mTelephonyManager = null;
+    protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
+
+    // Whether the volume keys should be handled by keyguard. If true, then
+    // they will be handled here for specific media types such as music, otherwise
+    // the audio service will bring up the volume dialog.
+    private static final boolean KEYGUARD_MANAGES_VOLUME = true;
+
+    public KeyguardViewBase(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardViewBase(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    /**
+     * Called when the screen turned off.
+     */
+    abstract public void onScreenTurnedOff();
+
+    /**
+     * Called when the screen turned on.
+     */
+    abstract public void onScreenTurnedOn();
+
+    /**
+     * Called when the view needs to be shown.
+     */
+    abstract public void show();
+
+    /**
+     * Verify that the user can get past the keyguard securely.  This is called,
+     * for example, when the phone disables the keyguard but then wants to launch
+     * something else that requires secure access.
+     *
+     * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
+     */
+    abstract public void verifyUnlock();
+
+    /**
+     * Called before this view is being removed.
+     */
+    abstract public void cleanUp();
+
+    /**
+     * Gets the desired user activity timeout in milliseconds, or -1 if the
+     * default should be used.
+     */
+    abstract public long getUserActivityTimeout();
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (interceptMediaKey(event)) {
+            return true;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    /**
+     * Allows the media keys to work when the keyguard is showing.
+     * The media keys should be of no interest to the actual keyguard view(s),
+     * so intercepting them here should not be of any harm.
+     * @param event The key event
+     * @return whether the event was consumed as a media key.
+     */
+    private boolean interceptMediaKey(KeyEvent event) {
+        final int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
+                     * in-call to avoid music playback */
+                    if (mTelephonyManager == null) {
+                        mTelephonyManager = (TelephonyManager) getContext().getSystemService(
+                                Context.TELEPHONY_SERVICE);
+                    }
+                    if (mTelephonyManager != null &&
+                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+                        return true;  // suppress key event
+                    }
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
+                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                    handleMediaKeyEvent(event);
+                    return true;
+                }
+
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                    if (KEYGUARD_MANAGES_VOLUME) {
+                        synchronized (this) {
+                            if (mAudioManager == null) {
+                                mAudioManager = (AudioManager) getContext().getSystemService(
+                                        Context.AUDIO_SERVICE);
+                            }
+                        }
+                        // Volume buttons should only function for music (local or remote).
+                        // TODO: Actually handle MUTE.
+                        mAudioManager.adjustLocalOrRemoteStreamVolume(
+                                AudioManager.STREAM_MUSIC,
+                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                        ? AudioManager.ADJUST_RAISE
+                                        : AudioManager.ADJUST_LOWER);
+                        // Don't execute default volume behavior
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
+                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                    handleMediaKeyEvent(event);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    void handleMediaKeyEvent(KeyEvent keyEvent) {
+        IAudioService audioService = IAudioService.Stub.asInterface(
+                ServiceManager.checkService(Context.AUDIO_SERVICE));
+        if (audioService != null) {
+            try {
+                audioService.dispatchMediaKeyEvent(keyEvent);
+            } catch (RemoteException e) {
+                Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
+            }
+        } else {
+            Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
+        }
+    }
+
+    @Override
+    public void dispatchSystemUiVisibilityChanged(int visibility) {
+        super.dispatchSystemUiVisibilityChanged(visibility);
+
+        if (!(mContext instanceof Activity)) {
+            setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
+        }
+    }
+
+    public void setViewMediatorCallback(
+            KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
+        mViewMediatorCallback = viewMediatorCallback;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
new file mode 100644
index 0000000..2084a16
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.app.PendingIntent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewManager;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+/**
+ * Manages creating, showing, hiding and resetting the keyguard.  Calls back
+ * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke
+ * the wake lock and report that the keyguard is done, which is in turn,
+ * reported to this class by the current {@link KeyguardViewBase}.
+ */
+public class KeyguardViewManager {
+    private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static String TAG = "KeyguardViewManager";
+    public static boolean USE_UPPER_CASE = true;
+    public final static String IS_SWITCHING_USER = "is_switching_user";
+
+    // Timeout used for keypresses
+    static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+
+    private final Context mContext;
+    private final ViewManager mViewManager;
+    private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
+
+    private WindowManager.LayoutParams mWindowLayoutParams;
+    private boolean mNeedsInput = false;
+
+    private ViewManagerHost mKeyguardHost;
+    private KeyguardHostView mKeyguardView;
+
+    private boolean mScreenOn = false;
+    private LockPatternUtils mLockPatternUtils;
+
+    private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onSetBackground(Bitmap bmp) {
+            mKeyguardHost.setCustomBackground(bmp != null ?
+                    new BitmapDrawable(mContext.getResources(), bmp) : null);
+        }
+    };
+
+    public interface ShowListener {
+        void onShown(IBinder windowToken);
+    };
+
+    /**
+     * @param context Used to create views.
+     * @param viewManager Keyguard will be attached to this.
+     * @param callback Used to notify of changes.
+     * @param lockPatternUtils
+     */
+    public KeyguardViewManager(Context context, ViewManager viewManager,
+            KeyguardViewMediator.ViewMediatorCallback callback,
+            LockPatternUtils lockPatternUtils) {
+        mContext = context;
+        mViewManager = viewManager;
+        mViewMediatorCallback = callback;
+        mLockPatternUtils = lockPatternUtils;
+    }
+
+    /**
+     * Show the keyguard.  Will handle creating and attaching to the view manager
+     * lazily.
+     */
+    public synchronized void show(Bundle options) {
+        if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
+
+        boolean enableScreenRotation = shouldEnableScreenRotation();
+
+        maybeCreateKeyguardLocked(enableScreenRotation, false, options);
+        maybeEnableScreenRotation(enableScreenRotation);
+
+        // Disable common aspects of the system/status/navigation bars that are not appropriate or
+        // useful on any keyguard screen but can be re-shown by dialogs or SHOW_WHEN_LOCKED
+        // activities. Other disabled bits are handled by the KeyguardViewMediator talking
+        // directly to the status bar service.
+        int visFlags = View.STATUS_BAR_DISABLE_HOME;
+        if (shouldEnableTransparentBars()) {
+            visFlags |= View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS
+                      | View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION;
+        }
+        if (DEBUG) Log.v(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")");
+        mKeyguardHost.setSystemUiVisibility(visFlags);
+
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+        mKeyguardHost.setVisibility(View.VISIBLE);
+        mKeyguardView.show();
+        mKeyguardView.requestFocus();
+    }
+
+    private boolean shouldEnableScreenRotation() {
+        Resources res = mContext.getResources();
+        return SystemProperties.getBoolean("lockscreen.rot_override",false)
+                || res.getBoolean(R.bool.config_enableLockScreenRotation);
+    }
+
+    private boolean shouldEnableTransparentBars() {
+        Resources res = mContext.getResources();
+        return res.getBoolean(R.bool.config_enableLockScreenTransparentBars);
+    }
+
+    class ViewManagerHost extends FrameLayout {
+        private static final int BACKGROUND_COLOR = 0x70000000;
+
+        private Drawable mCustomBackground;
+
+        // This is a faster way to draw the background on devices without hardware acceleration
+        private final Drawable mBackgroundDrawable = new Drawable() {
+            @Override
+            public void draw(Canvas canvas) {
+                if (mCustomBackground != null) {
+                    final Rect bounds = mCustomBackground.getBounds();
+                    final int vWidth = getWidth();
+                    final int vHeight = getHeight();
+
+                    final int restore = canvas.save();
+                    canvas.translate(-(bounds.width() - vWidth) / 2,
+                            -(bounds.height() - vHeight) / 2);
+                    mCustomBackground.draw(canvas);
+                    canvas.restoreToCount(restore);
+                } else {
+                    canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC);
+                }
+            }
+
+            @Override
+            public void setAlpha(int alpha) {
+            }
+
+            @Override
+            public void setColorFilter(ColorFilter cf) {
+            }
+
+            @Override
+            public int getOpacity() {
+                return PixelFormat.TRANSLUCENT;
+            }
+        };
+
+        public ViewManagerHost(Context context) {
+            super(context);
+            setBackground(mBackgroundDrawable);
+        }
+
+        public void setCustomBackground(Drawable d) {
+            mCustomBackground = d;
+            if (d != null) {
+                d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
+            }
+            computeCustomBackgroundBounds();
+            invalidate();
+        }
+
+        private void computeCustomBackgroundBounds() {
+            if (mCustomBackground == null) return; // Nothing to do
+            if (!isLaidOut()) return; // We'll do this later
+
+            final int bgWidth = mCustomBackground.getIntrinsicWidth();
+            final int bgHeight = mCustomBackground.getIntrinsicHeight();
+            final int vWidth = getWidth();
+            final int vHeight = getHeight();
+
+            final float bgAspect = (float) bgWidth / bgHeight;
+            final float vAspect = (float) vWidth / vHeight;
+
+            if (bgAspect > vAspect) {
+                mCustomBackground.setBounds(0, 0, (int) (vHeight * bgAspect), vHeight);
+            } else {
+                mCustomBackground.setBounds(0, 0, vWidth, (int) (vWidth / bgAspect));
+            }
+        }
+
+        @Override
+        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+            super.onSizeChanged(w, h, oldw, oldh);
+            computeCustomBackgroundBounds();
+        }
+
+        @Override
+        protected void onConfigurationChanged(Configuration newConfig) {
+            super.onConfigurationChanged(newConfig);
+            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
+                // only propagate configuration messages if we're currently showing
+                maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null);
+            } else {
+                if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible");
+            }
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            if (mKeyguardView != null) {
+                // Always process back and menu keys, regardless of focus
+                if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                    int keyCode = event.getKeyCode();
+                    if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) {
+                        return true;
+                    } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) {
+                        return true;
+                    }
+                }
+                // Always process media keys, regardless of focus
+                if (mKeyguardView.dispatchKeyEvent(event)) {
+                    return true;
+                }
+            }
+            return super.dispatchKeyEvent(event);
+        }
+    }
+
+    SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
+
+    private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
+            Bundle options) {
+        if (mKeyguardHost != null) {
+            mKeyguardHost.saveHierarchyState(mStateContainer);
+        }
+
+        if (mKeyguardHost == null) {
+            if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
+
+            mKeyguardHost = new ViewManagerHost(mContext);
+
+            int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
+                    | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
+            if (!mNeedsInput) {
+                flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            }
+
+            final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
+            final int type = WindowManager.LayoutParams.TYPE_KEYGUARD;
+            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                    stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
+            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+            lp.windowAnimations = R.style.Animation_LockScreen;
+            lp.screenOrientation = enableScreenRotation ?
+                    ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+
+            if (ActivityManager.isHighEndGfx()) {
+                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+                lp.privateFlags |=
+                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
+            }
+            lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
+            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+            lp.setTitle("Keyguard");
+            mWindowLayoutParams = lp;
+            mViewManager.addView(mKeyguardHost, lp);
+
+            KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mBackgroundChanger);
+        }
+
+        if (force || mKeyguardView == null) {
+            mKeyguardHost.setCustomBackground(null);
+            mKeyguardHost.removeAllViews();
+            inflateKeyguardView(options);
+            mKeyguardView.requestFocus();
+        }
+        updateUserActivityTimeoutInWindowLayoutParams();
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+
+        mKeyguardHost.restoreHierarchyState(mStateContainer);
+    }
+
+    private void inflateKeyguardView(Bundle options) {
+        View v = mKeyguardHost.findViewById(R.id.keyguard_host_view);
+        if (v != null) {
+            mKeyguardHost.removeView(v);
+        }
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true);
+        mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view);
+        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
+        mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
+        mKeyguardView.initializeSwitchingUserState(options != null &&
+                options.getBoolean(IS_SWITCHING_USER));
+
+        // HACK
+        // The keyguard view will have set up window flags in onFinishInflate before we set
+        // the view mediator callback. Make sure it knows the correct IME state.
+        if (mViewMediatorCallback != null) {
+            KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
+                    R.id.keyguard_password_view);
+
+            if (kpv != null) {
+                mViewMediatorCallback.setNeedsInput(kpv.needsInput());
+            }
+        }
+
+        if (options != null) {
+            int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
+                    AppWidgetManager.INVALID_APPWIDGET_ID);
+            if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
+                mKeyguardView.goToWidget(widgetToShow);
+            }
+        }
+    }
+
+    public void updateUserActivityTimeout() {
+        updateUserActivityTimeoutInWindowLayoutParams();
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+    }
+
+    private void updateUserActivityTimeoutInWindowLayoutParams() {
+        // Use the user activity timeout requested by the keyguard view, if any.
+        if (mKeyguardView != null) {
+            long timeout = mKeyguardView.getUserActivityTimeout();
+            if (timeout >= 0) {
+                mWindowLayoutParams.userActivityTimeout = timeout;
+                return;
+            }
+        }
+
+        // Otherwise, use the default timeout.
+        mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
+    }
+
+    private void maybeEnableScreenRotation(boolean enableScreenRotation) {
+        // TODO: move this outside
+        if (enableScreenRotation) {
+            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!");
+            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
+        } else {
+            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!");
+            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        }
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+    }
+
+    public void setNeedsInput(boolean needsInput) {
+        mNeedsInput = needsInput;
+        if (mWindowLayoutParams != null) {
+            if (needsInput) {
+                mWindowLayoutParams.flags &=
+                    ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            } else {
+                mWindowLayoutParams.flags |=
+                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            }
+
+            try {
+                mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+            } catch (java.lang.IllegalArgumentException e) {
+                // TODO: Ensure this method isn't called on views that are changing...
+                Log.w(TAG,"Can't update input method on " + mKeyguardHost + " window not attached");
+            }
+        }
+    }
+
+    /**
+     * Reset the state of the view.
+     */
+    public synchronized void reset(Bundle options) {
+        if (DEBUG) Log.d(TAG, "reset()");
+        // User might have switched, check if we need to go back to keyguard
+        // TODO: It's preferable to stay and show the correct lockscreen or unlock if none
+        maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, options);
+    }
+
+    public synchronized void onScreenTurnedOff() {
+        if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
+        mScreenOn = false;
+        if (mKeyguardView != null) {
+            mKeyguardView.onScreenTurnedOff();
+        }
+    }
+
+    public synchronized void onScreenTurnedOn(final IKeyguardShowCallback callback) {
+        if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
+        mScreenOn = true;
+        if (mKeyguardView != null) {
+            mKeyguardView.onScreenTurnedOn();
+
+            // Caller should wait for this window to be shown before turning
+            // on the screen.
+            if (callback != null) {
+                if (mKeyguardHost.getVisibility() == View.VISIBLE) {
+                    // Keyguard may be in the process of being shown, but not yet
+                    // updated with the window manager...  give it a chance to do so.
+                    mKeyguardHost.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            IBinder token = null;
+                            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
+                                token = mKeyguardHost.getWindowToken();
+                            }
+                            try {
+                                callback.onShown(token);
+                            } catch (RemoteException e) {
+                                Slog.w(TAG, "Exception calling onShown():", e);
+                            }
+                        }
+                    });
+                } else {
+                    try {
+                        callback.onShown(null);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Exception calling onShown():", e);
+                    }
+                }
+            }
+        } else if (callback != null) {
+            try {
+                callback.onShown(null);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Exception calling onShown():", e);
+            }
+        }
+    }
+
+    public synchronized void verifyUnlock() {
+        if (DEBUG) Log.d(TAG, "verifyUnlock()");
+        show(null);
+        mKeyguardView.verifyUnlock();
+    }
+
+    /**
+     * Hides the keyguard view
+     */
+    public synchronized void hide() {
+        if (DEBUG) Log.d(TAG, "hide()");
+
+        if (mKeyguardHost != null) {
+            mKeyguardHost.setVisibility(View.GONE);
+
+            // We really only want to preserve keyguard state for configuration changes. Hence
+            // we should clear state of widgets (e.g. Music) when we hide keyguard so it can
+            // start with a fresh state when we return.
+            mStateContainer.clear();
+
+            // Don't do this right away, so we can let the view continue to animate
+            // as it goes away.
+            if (mKeyguardView != null) {
+                final KeyguardViewBase lastView = mKeyguardView;
+                mKeyguardView = null;
+                mKeyguardHost.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        synchronized (KeyguardViewManager.this) {
+                            lastView.cleanUp();
+                            // Let go of any large bitmaps.
+                            mKeyguardHost.setCustomBackground(null);
+                            mKeyguardHost.removeView(lastView);
+                        }
+                    }
+                }, 500);
+            }
+        }
+    }
+
+    /**
+     * Dismisses the keyguard by going to the next screen or making it gone.
+     */
+    public synchronized void dismiss() {
+        if (mScreenOn) {
+            mKeyguardView.dismiss();
+        }
+    }
+
+    /**
+     * @return Whether the keyguard is showing
+     */
+    public synchronized boolean isShowing() {
+        return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);
+    }
+
+    public void showAssistant() {
+        if (mKeyguardView != null) {
+            mKeyguardView.showAssistant();
+        }
+    }
+
+    public void dispatch(MotionEvent event) {
+        if (mKeyguardView != null) {
+            mKeyguardView.dispatch(event);
+        }
+    }
+
+    public void launchCamera() {
+        if (mKeyguardView != null) {
+            mKeyguardView.launchCamera();
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
new file mode 100644
index 0000000..ec3eb157
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -0,0 +1,1361 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.graphics.Bitmap;
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardShowCallback;
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.SearchManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.SoundPool;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.widget.LockPatternUtils;
+
+
+/**
+ * Mediates requests related to the keyguard.  This includes queries about the
+ * state of the keyguard, power management events that effect whether the keyguard
+ * should be shown or reset, callbacks to the phone window manager to notify
+ * it of when the keyguard is showing, and events from the keyguard view itself
+ * stating that the keyguard was succesfully unlocked.
+ *
+ * Note that the keyguard view is shown when the screen is off (as appropriate)
+ * so that once the screen comes on, it will be ready immediately.
+ *
+ * Example queries about the keyguard:
+ * - is {movement, key} one that should wake the keygaurd?
+ * - is the keyguard showing?
+ * - are input events restricted due to the state of the keyguard?
+ *
+ * Callbacks to the phone window manager:
+ * - the keyguard is showing
+ *
+ * Example external events that translate to keyguard view changes:
+ * - screen turned off -> reset the keyguard, and show it so it will be ready
+ *   next time the screen turns on
+ * - keyboard is slid open -> if the keyguard is not secure, hide it
+ *
+ * Events from the keyguard view:
+ * - user succesfully unlocked keyguard -> hide keyguard view, and no longer
+ *   restrict input events.
+ *
+ * Note: in addition to normal power managment events that effect the state of
+ * whether the keyguard should be showing, external apps and services may request
+ * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}.  When
+ * false, this will override all other conditions for turning on the keyguard.
+ *
+ * Threading and synchronization:
+ * This class is created by the initialization routine of the {@link WindowManagerPolicy},
+ * and runs on its thread.  The keyguard UI is created from that thread in the
+ * constructor of this class.  The apis may be called from other threads, including the
+ * {@link com.android.server.input.InputManagerService}'s and {@link android.view.WindowManager}'s.
+ * Therefore, methods on this class are synchronized, and any action that is pointed
+ * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI
+ * thread of the keyguard.
+ */
+public class KeyguardViewMediator {
+    private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
+    final static boolean DEBUG = false;
+    private final static boolean DBG_WAKE = false;
+
+    private final static String TAG = "KeyguardViewMediator";
+
+    private static final String DELAYED_KEYGUARD_ACTION =
+        "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
+
+    // used for handler messages
+    private static final int SHOW = 2;
+    private static final int HIDE = 3;
+    private static final int RESET = 4;
+    private static final int VERIFY_UNLOCK = 5;
+    private static final int NOTIFY_SCREEN_OFF = 6;
+    private static final int NOTIFY_SCREEN_ON = 7;
+    private static final int KEYGUARD_DONE = 9;
+    private static final int KEYGUARD_DONE_DRAWING = 10;
+    private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
+    private static final int SET_HIDDEN = 12;
+    private static final int KEYGUARD_TIMEOUT = 13;
+    private static final int SHOW_ASSISTANT = 14;
+    private static final int DISPATCH_EVENT = 15;
+    private static final int LAUNCH_CAMERA = 16;
+
+    /**
+     * The default amount of time we stay awake (used for all key input)
+     */
+    protected static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;
+
+    /**
+     * How long to wait after the screen turns off due to timeout before
+     * turning on the keyguard (i.e, the user has this much time to turn
+     * the screen back on without having to face the keyguard).
+     */
+    private static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000;
+
+    /**
+     * How long we'll wait for the {@link ViewMediatorCallback#keyguardDoneDrawing()}
+     * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)}
+     * that is reenabling the keyguard.
+     */
+    private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
+
+    /**
+     * Allow the user to expand the status bar when the keyguard is engaged
+     * (without a pattern or password).
+     */
+    private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true;
+
+    /** The stream type that the lock sounds are tied to. */
+    private int mMasterStreamType;
+
+    private Context mContext;
+    private AlarmManager mAlarmManager;
+    private AudioManager mAudioManager;
+    private StatusBarManager mStatusBarManager;
+    private boolean mSwitchingUser;
+
+    private boolean mSystemReady;
+
+    // Whether the next call to playSounds() should be skipped.  Defaults to
+    // true because the first lock (on boot) should be silent.
+    private boolean mSuppressNextLockSound = true;
+
+
+    /** High level access to the power manager for WakeLocks */
+    private PowerManager mPM;
+
+    /** UserManager for querying number of users */
+    private UserManager mUserManager;
+
+    /** SearchManager for determining whether or not search assistant is available */
+    private SearchManager mSearchManager;
+
+    /**
+     * Used to keep the device awake while to ensure the keyguard finishes opening before
+     * we sleep.
+     */
+    private PowerManager.WakeLock mShowKeyguardWakeLock;
+
+    private KeyguardViewManager mKeyguardViewManager;
+
+    // these are protected by synchronized (this)
+
+    /**
+     * External apps (like the phone app) can tell us to disable the keygaurd.
+     */
+    private boolean mExternallyEnabled = true;
+
+    /**
+     * Remember if an external call to {@link #setKeyguardEnabled} with value
+     * false caused us to hide the keyguard, so that we need to reshow it once
+     * the keygaurd is reenabled with another call with value true.
+     */
+    private boolean mNeedToReshowWhenReenabled = false;
+
+    // cached value of whether we are showing (need to know this to quickly
+    // answer whether the input should be restricted)
+    private boolean mShowing = false;
+
+    // true if the keyguard is hidden by another window
+    private boolean mHidden = false;
+
+    /**
+     * Helps remember whether the screen has turned on since the last time
+     * it turned off due to timeout. see {@link #onScreenTurnedOff(int)}
+     */
+    private int mDelayedShowingSequence;
+
+    /**
+     * If the user has disabled the keyguard, then requests to exit, this is
+     * how we'll ultimately let them know whether it was successful.  We use this
+     * var being non-null as an indicator that there is an in progress request.
+     */
+    private IKeyguardExitCallback mExitSecureCallback;
+
+    // the properties of the keyguard
+
+    private KeyguardUpdateMonitor mUpdateMonitor;
+
+    private boolean mScreenOn;
+
+    // last known state of the cellular connection
+    private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE;
+
+    /**
+     * we send this intent when the keyguard is dismissed.
+     */
+    private static final Intent USER_PRESENT_INTENT = new Intent(Intent.ACTION_USER_PRESENT)
+            .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                    | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+    /**
+     * {@link #setKeyguardEnabled} waits on this condition when it reenables
+     * the keyguard.
+     */
+    private boolean mWaitingUntilKeyguardVisible = false;
+    private LockPatternUtils mLockPatternUtils;
+    private boolean mKeyguardDonePending = false;
+
+    private SoundPool mLockSounds;
+    private int mLockSoundId;
+    private int mUnlockSoundId;
+    private int mLockSoundStreamId;
+
+    /**
+     * The volume applied to the lock/unlock sounds.
+     */
+    private final float mLockSoundVolume;
+
+    /**
+     * Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
+     */
+    private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
+
+    /**
+     * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}
+     * various things.
+     */
+    public interface ViewMediatorCallback {
+        /**
+         * Reports user activity and requests that the screen stay on.
+         */
+        void userActivity();
+
+        /**
+         * Reports user activity and requests that the screen stay on for at least
+         * the specified amount of time.
+         * @param millis The amount of time in millis.  This value is currently ignored.
+         */
+        void userActivity(long millis);
+
+        /**
+         * Report that the keyguard is done.
+         * @param authenticated Whether the user securely got past the keyguard.
+         *   the only reason for this to be false is if the keyguard was instructed
+         *   to appear temporarily to verify the user is supposed to get past the
+         *   keyguard, and the user fails to do so.
+         */
+        void keyguardDone(boolean authenticated);
+
+        /**
+         * Report that the keyguard is done drawing.
+         */
+        void keyguardDoneDrawing();
+
+        /**
+         * Tell ViewMediator that the current view needs IME input
+         * @param needsInput
+         */
+        void setNeedsInput(boolean needsInput);
+
+        /**
+         * Tell view mediator that the keyguard view's desired user activity timeout
+         * has changed and needs to be reapplied to the window.
+         */
+        void onUserActivityTimeoutChanged();
+
+        /**
+         * Report that the keyguard is dismissable, pending the next keyguardDone call.
+         */
+        void keyguardDonePending();
+    }
+
+    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+
+        @Override
+        public void onUserSwitching(int userId) {
+            // Note that the mLockPatternUtils user has already been updated from setCurrentUser.
+            // We need to force a reset of the views, since lockNow (called by
+            // ActivityManagerService) will not reconstruct the keyguard if it is already showing.
+            synchronized (KeyguardViewMediator.this) {
+                mSwitchingUser = true;
+                resetStateLocked(null);
+                adjustStatusBarLocked();
+                // When we switch users we want to bring the new user to the biometric unlock even
+                // if the current user has gone to the backup.
+                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+            }
+        }
+
+        @Override
+        public void onUserSwitchComplete(int userId) {
+            mSwitchingUser = false;
+        }
+
+        @Override
+        public void onUserRemoved(int userId) {
+            mLockPatternUtils.removeUser(userId);
+            sMultiUserAvatarCache.clear(userId);
+        }
+
+        @Override
+        public void onUserInfoChanged(int userId) {
+            sMultiUserAvatarCache.clear(userId);
+        }
+
+        @Override
+        void onPhoneStateChanged(int phoneState) {
+            synchronized (KeyguardViewMediator.this) {
+                if (TelephonyManager.CALL_STATE_IDLE == phoneState  // call ending
+                        && !mScreenOn                           // screen off
+                        && mExternallyEnabled) {                // not disabled by any app
+
+                    // note: this is a way to gracefully reenable the keyguard when the call
+                    // ends and the screen is off without always reenabling the keyguard
+                    // each time the screen turns off while in call (and having an occasional ugly
+                    // flicker while turning back on the screen and disabling the keyguard again).
+                    if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the "
+                            + "keyguard is showing");
+                    doKeyguardLocked(null);
+                }
+            }
+        };
+
+        @Override
+        public void onClockVisibilityChanged() {
+            adjustStatusBarLocked();
+        }
+
+        @Override
+        public void onDeviceProvisioned() {
+            sendUserPresentBroadcast();
+        }
+
+        @Override
+        public void onSimStateChanged(IccCardConstants.State simState) {
+            if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);
+
+            switch (simState) {
+                case NOT_READY:
+                case ABSENT:
+                    // only force lock screen in case of missing sim if user hasn't
+                    // gone through setup wizard
+                    synchronized (this) {
+                        if (!mUpdateMonitor.isDeviceProvisioned()) {
+                            if (!isShowing()) {
+                                if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing,"
+                                        + " we need to show the keyguard since the "
+                                        + "device isn't provisioned yet.");
+                                doKeyguardLocked(null);
+                            } else {
+                                resetStateLocked(null);
+                            }
+                        }
+                    }
+                    break;
+                case PIN_REQUIRED:
+                case PUK_REQUIRED:
+                    synchronized (this) {
+                        if (!isShowing()) {
+                            if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
+                                    + "showing; need to show keyguard so user can enter sim pin");
+                            doKeyguardLocked(null);
+                        } else {
+                            resetStateLocked(null);
+                        }
+                    }
+                    break;
+                case PERM_DISABLED:
+                    synchronized (this) {
+                        if (!isShowing()) {
+                            if (DEBUG) Log.d(TAG, "PERM_DISABLED and "
+                                  + "keygaurd isn't showing.");
+                            doKeyguardLocked(null);
+                        } else {
+                            if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+                                  + "show permanently disabled message in lockscreen.");
+                            resetStateLocked(null);
+                        }
+                    }
+                    break;
+                case READY:
+                    synchronized (this) {
+                        if (isShowing()) {
+                            resetStateLocked(null);
+                        }
+                    }
+                    break;
+            }
+        }
+
+    };
+
+    ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
+        public void userActivity() {
+            KeyguardViewMediator.this.userActivity();
+        }
+
+        public void userActivity(long holdMs) {
+            KeyguardViewMediator.this.userActivity(holdMs);
+        }
+
+        public void keyguardDone(boolean authenticated) {
+            KeyguardViewMediator.this.keyguardDone(authenticated, true);
+        }
+
+        public void keyguardDoneDrawing() {
+            mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING);
+        }
+
+        @Override
+        public void setNeedsInput(boolean needsInput) {
+            mKeyguardViewManager.setNeedsInput(needsInput);
+        }
+
+        @Override
+        public void onUserActivityTimeoutChanged() {
+            mKeyguardViewManager.updateUserActivityTimeout();
+        }
+
+        @Override
+        public void keyguardDonePending() {
+            mKeyguardDonePending = true;
+        }
+    };
+
+    private void userActivity() {
+        userActivity(AWAKE_INTERVAL_DEFAULT_MS);
+    }
+
+    public void userActivity(long holdMs) {
+        // We ignore the hold time.  Eventually we should remove it.
+        // Instead, the keyguard window has an explicit user activity timeout set on it.
+        mPM.userActivity(SystemClock.uptimeMillis(), false);
+    }
+
+    /**
+     * Construct a KeyguardViewMediator
+     * @param context
+     * @param lockPatternUtils optional mock interface for LockPatternUtils
+     */
+    public KeyguardViewMediator(Context context, LockPatternUtils lockPatternUtils) {
+        mContext = context;
+        mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
+        mShowKeyguardWakeLock.setReferenceCounted(false);
+
+        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
+
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
+
+        mLockPatternUtils = lockPatternUtils != null
+                ? lockPatternUtils : new LockPatternUtils(mContext);
+        mLockPatternUtils.setCurrentUser(UserHandle.USER_OWNER);
+
+        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+
+        mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
+                mLockPatternUtils);
+
+        final ContentResolver cr = mContext.getContentResolver();
+
+        mScreenOn = mPM.isScreenOn();
+
+        mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
+        String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
+        if (soundPath != null) {
+            mLockSoundId = mLockSounds.load(soundPath, 1);
+        }
+        if (soundPath == null || mLockSoundId == 0) {
+            Log.w(TAG, "failed to load lock sound from " + soundPath);
+        }
+        soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
+        if (soundPath != null) {
+            mUnlockSoundId = mLockSounds.load(soundPath, 1);
+        }
+        if (soundPath == null || mUnlockSoundId == 0) {
+            Log.w(TAG, "failed to load unlock sound from " + soundPath);
+        }
+        int lockSoundDefaultAttenuation = context.getResources().getInteger(
+                com.android.internal.R.integer.config_lockSoundVolumeDb);
+        mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
+    }
+
+    /**
+     * Let us know that the system is ready after startup.
+     */
+    public void onSystemReady() {
+        mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+        synchronized (this) {
+            if (DEBUG) Log.d(TAG, "onSystemReady");
+            mSystemReady = true;
+            mUpdateMonitor.registerCallback(mUpdateCallback);
+
+            // Send boot completed message if it hasn't already been sent.
+            mUpdateMonitor.dispatchBootCompleted();
+
+            // Suppress biometric unlock right after boot until things have settled if it is the
+            // selected security method, otherwise unsuppress it.  It must be unsuppressed if it is
+            // not the selected security method for the following reason:  if the user starts
+            // without a screen lock selected, the biometric unlock would be suppressed the first
+            // time they try to use it.
+            //
+            // Note that the biometric unlock will still not show if it is not the selected method.
+            // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the
+            // selected method.
+            if (mLockPatternUtils.usingBiometricWeak()
+                    && mLockPatternUtils.isBiometricWeakInstalled()) {
+                if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
+                mUpdateMonitor.setAlternateUnlockEnabled(false);
+            } else {
+                mUpdateMonitor.setAlternateUnlockEnabled(true);
+            }
+
+            doKeyguardLocked(null);
+        }
+        // Most services aren't available until the system reaches the ready state, so we
+        // send it here when the device first boots.
+        maybeSendUserPresentBroadcast();
+    }
+
+    /**
+     * Called to let us know the screen was turned off.
+     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
+     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
+     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+     */
+    public void onScreenTurnedOff(int why) {
+        synchronized (this) {
+            mScreenOn = false;
+            if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")");
+
+            mKeyguardDonePending = false;
+
+            // Lock immediately based on setting if secure (user has a pin/pattern/password).
+            // This also "locks" the device when not secure to provide easy access to the
+            // camera while preventing unwanted input.
+            final boolean lockImmediately =
+                mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
+
+            if (mExitSecureCallback != null) {
+                if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
+                try {
+                    mExitSecureCallback.onKeyguardExitResult(false);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+                }
+                mExitSecureCallback = null;
+                if (!mExternallyEnabled) {
+                    hideLocked();
+                }
+            } else if (mShowing) {
+                notifyScreenOffLocked();
+                resetStateLocked(null);
+            } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
+                   || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
+                doKeyguardLaterLocked();
+            } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
+                // Do not enable the keyguard if the prox sensor forced the screen off.
+            } else {
+                doKeyguardLocked(null);
+            }
+        }
+    }
+
+    private void doKeyguardLaterLocked() {
+        // if the screen turned off because of timeout or the user hit the power button
+        // and we don't need to lock immediately, set an alarm
+        // to enable it a little bit later (i.e, give the user a chance
+        // to turn the screen back on within a certain window without
+        // having to unlock the screen)
+        final ContentResolver cr = mContext.getContentResolver();
+
+        // From DisplaySettings
+        long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
+                KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
+
+        // From SecuritySettings
+        final long lockAfterTimeout = Settings.Secure.getInt(cr,
+                Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
+
+        // From DevicePolicyAdmin
+        final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
+                .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
+
+        long timeout;
+        if (policyTimeout > 0) {
+            // policy in effect. Make sure we don't go beyond policy limit.
+            displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
+            timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
+        } else {
+            timeout = lockAfterTimeout;
+        }
+
+        if (timeout <= 0) {
+            // Lock now
+            mSuppressNextLockSound = true;
+            doKeyguardLocked(null);
+        } else {
+            // Lock in the future
+            long when = SystemClock.elapsedRealtime() + timeout;
+            Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
+            intent.putExtra("seq", mDelayedShowingSequence);
+            PendingIntent sender = PendingIntent.getBroadcast(mContext,
+                    0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+            if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+                             + mDelayedShowingSequence);
+        }
+    }
+
+    private void cancelDoKeyguardLaterLocked() {
+        mDelayedShowingSequence++;
+    }
+
+    /**
+     * Let's us know the screen was turned on.
+     */
+    public void onScreenTurnedOn(IKeyguardShowCallback callback) {
+        synchronized (this) {
+            mScreenOn = true;
+            cancelDoKeyguardLaterLocked();
+            if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
+            if (callback != null) {
+                notifyScreenOnLocked(callback);
+            }
+        }
+        maybeSendUserPresentBroadcast();
+    }
+
+    private void maybeSendUserPresentBroadcast() {
+        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()
+                && mUserManager.getUsers(true).size() == 1) {
+            // Lock screen is disabled because the user has set the preference to "None".
+            // In this case, send out ACTION_USER_PRESENT here instead of in
+            // handleKeyguardDone()
+            sendUserPresentBroadcast();
+        }
+    }
+
+    /**
+     * A dream started.  We should lock after the usual screen-off lock timeout but only
+     * if there is a secure lock pattern.
+     */
+    public void onDreamingStarted() {
+        synchronized (this) {
+            if (mScreenOn && mLockPatternUtils.isSecure()) {
+                doKeyguardLaterLocked();
+            }
+        }
+    }
+
+    /**
+     * A dream stopped.
+     */
+    public void onDreamingStopped() {
+        synchronized (this) {
+            if (mScreenOn) {
+                cancelDoKeyguardLaterLocked();
+            }
+        }
+    }
+
+    /**
+     * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
+     * a way for external stuff to override normal keyguard behavior.  For instance
+     * the phone app disables the keyguard when it receives incoming calls.
+     */
+    public void setKeyguardEnabled(boolean enabled) {
+        synchronized (this) {
+            if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
+
+            mExternallyEnabled = enabled;
+
+            if (!enabled && mShowing) {
+                if (mExitSecureCallback != null) {
+                    if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring");
+                    // we're in the process of handling a request to verify the user
+                    // can get past the keyguard. ignore extraneous requests to disable / reenable
+                    return;
+                }
+
+                // hiding keyguard that is showing, remember to reshow later
+                if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
+                        + "disabling status bar expansion");
+                mNeedToReshowWhenReenabled = true;
+                hideLocked();
+            } else if (enabled && mNeedToReshowWhenReenabled) {
+                // reenabled after previously hidden, reshow
+                if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
+                        + "status bar expansion");
+                mNeedToReshowWhenReenabled = false;
+
+                if (mExitSecureCallback != null) {
+                    if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
+                    try {
+                        mExitSecureCallback.onKeyguardExitResult(false);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+                    }
+                    mExitSecureCallback = null;
+                    resetStateLocked(null);
+                } else {
+                    showLocked(null);
+
+                    // block until we know the keygaurd is done drawing (and post a message
+                    // to unblock us after a timeout so we don't risk blocking too long
+                    // and causing an ANR).
+                    mWaitingUntilKeyguardVisible = true;
+                    mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS);
+                    if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false");
+                    while (mWaitingUntilKeyguardVisible) {
+                        try {
+                            wait();
+                        } catch (InterruptedException e) {
+                            Thread.currentThread().interrupt();
+                        }
+                    }
+                    if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible");
+                }
+            }
+        }
+    }
+
+    /**
+     * @see android.app.KeyguardManager#exitKeyguardSecurely
+     */
+    public void verifyUnlock(IKeyguardExitCallback callback) {
+        synchronized (this) {
+            if (DEBUG) Log.d(TAG, "verifyUnlock");
+            if (!mUpdateMonitor.isDeviceProvisioned()) {
+                // don't allow this api when the device isn't provisioned
+                if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned");
+                try {
+                    callback.onKeyguardExitResult(false);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+                }
+            } else if (mExternallyEnabled) {
+                // this only applies when the user has externally disabled the
+                // keyguard.  this is unexpected and means the user is not
+                // using the api properly.
+                Log.w(TAG, "verifyUnlock called when not externally disabled");
+                try {
+                    callback.onKeyguardExitResult(false);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+                }
+            } else if (mExitSecureCallback != null) {
+                // already in progress with someone else
+                try {
+                    callback.onKeyguardExitResult(false);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+                }
+            } else {
+                mExitSecureCallback = callback;
+                verifyUnlockLocked();
+            }
+        }
+    }
+
+    /**
+     * Is the keyguard currently showing?
+     */
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    /**
+     * Is the keyguard currently showing and not being force hidden?
+     */
+    public boolean isShowingAndNotHidden() {
+        return mShowing && !mHidden;
+    }
+
+    /**
+     * Notify us when the keyguard is hidden by another window
+     */
+    public void setHidden(boolean isHidden) {
+        if (DEBUG) Log.d(TAG, "setHidden " + isHidden);
+        mUpdateMonitor.sendKeyguardVisibilityChanged(!isHidden);
+        mHandler.removeMessages(SET_HIDDEN);
+        Message msg = mHandler.obtainMessage(SET_HIDDEN, (isHidden ? 1 : 0), 0);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Handles SET_HIDDEN message sent by setHidden()
+     */
+    private void handleSetHidden(boolean isHidden) {
+        synchronized (KeyguardViewMediator.this) {
+            if (mHidden != isHidden) {
+                mHidden = isHidden;
+                updateActivityLockScreenState();
+                adjustStatusBarLocked();
+            }
+        }
+    }
+
+    /**
+     * Used by PhoneWindowManager to enable the keyguard due to a user activity timeout.
+     * This must be safe to call from any thread and with any window manager locks held.
+     */
+    public void doKeyguardTimeout(Bundle options) {
+        mHandler.removeMessages(KEYGUARD_TIMEOUT);
+        Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT, options);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Given the state of the keyguard, is the input restricted?
+     * Input is restricted when the keyguard is showing, or when the keyguard
+     * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet.
+     */
+    public boolean isInputRestricted() {
+        return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned();
+    }
+
+    /**
+     * Enable the keyguard if the settings are appropriate.
+     */
+    private void doKeyguardLocked(Bundle options) {
+        // if another app is disabling us, don't show
+        if (!mExternallyEnabled) {
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
+
+            // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes
+            // for an occasional ugly flicker in this situation:
+            // 1) receive a call with the screen on (no keyguard) or make a call
+            // 2) screen times out
+            // 3) user hits key to turn screen back on
+            // instead, we reenable the keyguard when we know the screen is off and the call
+            // ends (see the broadcast receiver below)
+            // TODO: clean this up when we have better support at the window manager level
+            // for apps that wish to be on top of the keyguard
+            return;
+        }
+
+        // if the keyguard is already showing, don't bother
+        if (mKeyguardViewManager.isShowing()) {
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
+            return;
+        }
+
+        // if the setup wizard hasn't run yet, don't show
+        final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim",
+                false);
+        final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
+        final IccCardConstants.State state = mUpdateMonitor.getSimState();
+        final boolean lockedOrMissing = state.isPinLocked()
+                || ((state == IccCardConstants.State.ABSENT
+                || state == IccCardConstants.State.PERM_DISABLED)
+                && requireSim);
+
+        if (!lockedOrMissing && !provisioned) {
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
+                    + " and the sim is not locked or missing");
+            return;
+        }
+
+        if (mUserManager.getUsers(true).size() < 2
+                && mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
+            return;
+        }
+
+        if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
+        showLocked(options);
+    }
+
+    /**
+     * Dismiss the keyguard through the security layers.
+     */
+    public void dismiss() {
+        if (mShowing && !mHidden) {
+            mKeyguardViewManager.dismiss();
+        }
+    }
+
+    /**
+     * Send message to keyguard telling it to reset its state.
+     * @param options options about how to show the keyguard
+     * @see #handleReset()
+     */
+    private void resetStateLocked(Bundle options) {
+        if (DEBUG) Log.e(TAG, "resetStateLocked");
+        Message msg = mHandler.obtainMessage(RESET, options);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Send message to keyguard telling it to verify unlock
+     * @see #handleVerifyUnlock()
+     */
+    private void verifyUnlockLocked() {
+        if (DEBUG) Log.d(TAG, "verifyUnlockLocked");
+        mHandler.sendEmptyMessage(VERIFY_UNLOCK);
+    }
+
+
+    /**
+     * Send a message to keyguard telling it the screen just turned on.
+     * @see #onScreenTurnedOff(int)
+     * @see #handleNotifyScreenOff
+     */
+    private void notifyScreenOffLocked() {
+        if (DEBUG) Log.d(TAG, "notifyScreenOffLocked");
+        mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF);
+    }
+
+    /**
+     * Send a message to keyguard telling it the screen just turned on.
+     * @see #onScreenTurnedOn()
+     * @see #handleNotifyScreenOn
+     */
+    private void notifyScreenOnLocked(IKeyguardShowCallback result) {
+        if (DEBUG) Log.d(TAG, "notifyScreenOnLocked");
+        Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_ON, result);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Send message to keyguard telling it to show itself
+     * @see #handleShow()
+     */
+    private void showLocked(Bundle options) {
+        if (DEBUG) Log.d(TAG, "showLocked");
+        // ensure we stay awake until we are finished displaying the keyguard
+        mShowKeyguardWakeLock.acquire();
+        Message msg = mHandler.obtainMessage(SHOW, options);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Send message to keyguard telling it to hide itself
+     * @see #handleHide()
+     */
+    private void hideLocked() {
+        if (DEBUG) Log.d(TAG, "hideLocked");
+        Message msg = mHandler.obtainMessage(HIDE);
+        mHandler.sendMessage(msg);
+    }
+
+    public boolean isSecure() {
+        return mLockPatternUtils.isSecure()
+            || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure();
+    }
+
+    /**
+     * Update the newUserId. Call while holding WindowManagerService lock.
+     * NOTE: Should only be called by KeyguardViewMediator in response to the user id changing.
+     *
+     * @param newUserId The id of the incoming user.
+     */
+    public void setCurrentUser(int newUserId) {
+        mLockPatternUtils.setCurrentUser(newUserId);
+    }
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DELAYED_KEYGUARD_ACTION.equals(intent.getAction())) {
+                final int sequence = intent.getIntExtra("seq", 0);
+                if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
+                        + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
+                synchronized (KeyguardViewMediator.this) {
+                    if (mDelayedShowingSequence == sequence) {
+                        // Don't play lockscreen SFX if the screen went off due to timeout.
+                        mSuppressNextLockSound = true;
+                        doKeyguardLocked(null);
+                    }
+                }
+            }
+        }
+    };
+
+    public void keyguardDone(boolean authenticated, boolean wakeup) {
+        mKeyguardDonePending = false;
+        synchronized (this) {
+            EventLog.writeEvent(70000, 2);
+            if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")");
+            Message msg = mHandler.obtainMessage(KEYGUARD_DONE, authenticated ? 1 : 0,
+                    wakeup ? 1 : 0);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    /**
+     * This handler will be associated with the policy thread, which will also
+     * be the UI thread of the keyguard.  Since the apis of the policy, and therefore
+     * this class, can be called by other threads, any action that directly
+     * interacts with the keyguard ui should be posted to this handler, rather
+     * than called directly.
+     */
+    private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case SHOW:
+                    handleShow((Bundle) msg.obj);
+                    return ;
+                case HIDE:
+                    handleHide();
+                    return ;
+                case RESET:
+                    handleReset((Bundle) msg.obj);
+                    return ;
+                case VERIFY_UNLOCK:
+                    handleVerifyUnlock();
+                    return;
+                case NOTIFY_SCREEN_OFF:
+                    handleNotifyScreenOff();
+                    return;
+                case NOTIFY_SCREEN_ON:
+                    handleNotifyScreenOn((IKeyguardShowCallback) msg.obj);
+                    return;
+                case KEYGUARD_DONE:
+                    handleKeyguardDone(msg.arg1 != 0, msg.arg2 != 0);
+                    return;
+                case KEYGUARD_DONE_DRAWING:
+                    handleKeyguardDoneDrawing();
+                    return;
+                case KEYGUARD_DONE_AUTHENTICATING:
+                    keyguardDone(true, true);
+                    return;
+                case SET_HIDDEN:
+                    handleSetHidden(msg.arg1 != 0);
+                    break;
+                case KEYGUARD_TIMEOUT:
+                    synchronized (KeyguardViewMediator.this) {
+                        doKeyguardLocked((Bundle) msg.obj);
+                    }
+                    break;
+                case SHOW_ASSISTANT:
+                    handleShowAssistant();
+                    break;
+                case DISPATCH_EVENT:
+                    handleDispatchEvent((MotionEvent) msg.obj);
+                    break;
+                case LAUNCH_CAMERA:
+                    handleLaunchCamera();
+                    break;
+            }
+        }
+    };
+
+    /**
+     * @see #keyguardDone
+     * @see #KEYGUARD_DONE
+     */
+    private void handleKeyguardDone(boolean authenticated, boolean wakeup) {
+        if (DEBUG) Log.d(TAG, "handleKeyguardDone");
+
+        if (authenticated) {
+            mUpdateMonitor.clearFailedUnlockAttempts();
+        }
+
+        if (mExitSecureCallback != null) {
+            try {
+                mExitSecureCallback.onKeyguardExitResult(authenticated);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call onKeyguardExitResult(" + authenticated + ")", e);
+            }
+
+            mExitSecureCallback = null;
+
+            if (authenticated) {
+                // after succesfully exiting securely, no need to reshow
+                // the keyguard when they've released the lock
+                mExternallyEnabled = true;
+                mNeedToReshowWhenReenabled = false;
+            }
+        }
+
+        handleHide();
+        sendUserPresentBroadcast();
+    }
+
+    protected void handleLaunchCamera() {
+        mKeyguardViewManager.launchCamera();
+    }
+
+    protected void handleDispatchEvent(MotionEvent event) {
+        mKeyguardViewManager.dispatch(event);
+    }
+
+    private void sendUserPresentBroadcast() {
+        final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
+        mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
+    }
+
+    /**
+     * @see #keyguardDoneDrawing
+     * @see #KEYGUARD_DONE_DRAWING
+     */
+    private void handleKeyguardDoneDrawing() {
+        synchronized(this) {
+            if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing");
+            if (mWaitingUntilKeyguardVisible) {
+                if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible");
+                mWaitingUntilKeyguardVisible = false;
+                notifyAll();
+
+                // there will usually be two of these sent, one as a timeout, and one
+                // as a result of the callback, so remove any remaining messages from
+                // the queue
+                mHandler.removeMessages(KEYGUARD_DONE_DRAWING);
+            }
+        }
+    }
+
+    private void playSounds(boolean locked) {
+        // User feedback for keyguard.
+
+        if (mSuppressNextLockSound) {
+            mSuppressNextLockSound = false;
+            return;
+        }
+
+        final ContentResolver cr = mContext.getContentResolver();
+        if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) {
+            final int whichSound = locked
+                ? mLockSoundId
+                : mUnlockSoundId;
+            mLockSounds.stop(mLockSoundStreamId);
+            // Init mAudioManager
+            if (mAudioManager == null) {
+                mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+                if (mAudioManager == null) return;
+                mMasterStreamType = mAudioManager.getMasterStreamType();
+            }
+            // If the stream is muted, don't play the sound
+            if (mAudioManager.isStreamMute(mMasterStreamType)) return;
+
+            mLockSoundStreamId = mLockSounds.play(whichSound,
+                    mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
+        }
+    }
+
+    private void updateActivityLockScreenState() {
+        try {
+            ActivityManagerNative.getDefault().setLockScreenShown(
+                    mShowing && !mHidden);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Handle message sent by {@link #showLocked}.
+     * @see #SHOW
+     */
+    private void handleShow(Bundle options) {
+        synchronized (KeyguardViewMediator.this) {
+            if (!mSystemReady) {
+                if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
+                return;
+            } else {
+                if (DEBUG) Log.d(TAG, "handleShow");
+            }
+
+            mKeyguardViewManager.show(options);
+            mShowing = true;
+            mKeyguardDonePending = false;
+            updateActivityLockScreenState();
+            adjustStatusBarLocked();
+            userActivity();
+            try {
+                ActivityManagerNative.getDefault().closeSystemDialogs("lock");
+            } catch (RemoteException e) {
+            }
+
+            // Do this at the end to not slow down display of the keyguard.
+            playSounds(true);
+
+            mShowKeyguardWakeLock.release();
+        }
+    }
+
+    /**
+     * Handle message sent by {@link #hideLocked()}
+     * @see #HIDE
+     */
+    private void handleHide() {
+        synchronized (KeyguardViewMediator.this) {
+            if (DEBUG) Log.d(TAG, "handleHide");
+
+            // only play "unlock" noises if not on a call (since the incall UI
+            // disables the keyguard)
+            if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
+                playSounds(false);
+            }
+
+            mKeyguardViewManager.hide();
+            mShowing = false;
+            mKeyguardDonePending = false;
+            updateActivityLockScreenState();
+            adjustStatusBarLocked();
+        }
+    }
+
+    private void adjustStatusBarLocked() {
+        if (mStatusBarManager == null) {
+            mStatusBarManager = (StatusBarManager)
+                    mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+        }
+        if (mStatusBarManager == null) {
+            Log.w(TAG, "Could not get status bar manager");
+        } else {
+            // Disable aspects of the system/status/navigation bars that must not be re-enabled by
+            // windows that appear on top, ever
+            int flags = StatusBarManager.DISABLE_NONE;
+            if (mShowing) {
+                // Permanently disable components not available when keyguard is enabled
+                // (like recents). Temporary enable/disable (e.g. the "back" button) are
+                // done in KeyguardHostView.
+                flags |= StatusBarManager.DISABLE_RECENT;
+                if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
+                    // showing secure lockscreen; disable expanding.
+                    flags |= StatusBarManager.DISABLE_EXPAND;
+                }
+                if (isSecure()) {
+                    // showing secure lockscreen; disable ticker.
+                    flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER;
+                }
+                if (!isAssistantAvailable()) {
+                    flags |= StatusBarManager.DISABLE_SEARCH;
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
+                        + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
+            }
+
+            if (!(mContext instanceof Activity)) {
+                mStatusBarManager.disable(flags);
+            }
+        }
+    }
+
+    /**
+     * Handle message sent by {@link #resetStateLocked(Bundle)}
+     * @see #RESET
+     */
+    private void handleReset(Bundle options) {
+        if (options == null) {
+            options = new Bundle();
+        }
+        options.putBoolean(KeyguardViewManager.IS_SWITCHING_USER, mSwitchingUser);
+        synchronized (KeyguardViewMediator.this) {
+            if (DEBUG) Log.d(TAG, "handleReset");
+            mKeyguardViewManager.reset(options);
+        }
+    }
+
+    /**
+     * Handle message sent by {@link #verifyUnlock}
+     * @see #VERIFY_UNLOCK
+     */
+    private void handleVerifyUnlock() {
+        synchronized (KeyguardViewMediator.this) {
+            if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
+            mKeyguardViewManager.verifyUnlock();
+            mShowing = true;
+            updateActivityLockScreenState();
+        }
+    }
+
+    /**
+     * Handle message sent by {@link #notifyScreenOffLocked()}
+     * @see #NOTIFY_SCREEN_OFF
+     */
+    private void handleNotifyScreenOff() {
+        synchronized (KeyguardViewMediator.this) {
+            if (DEBUG) Log.d(TAG, "handleNotifyScreenOff");
+            mKeyguardViewManager.onScreenTurnedOff();
+        }
+    }
+
+    /**
+     * Handle message sent by {@link #notifyScreenOnLocked()}
+     * @see #NOTIFY_SCREEN_ON
+     */
+    private void handleNotifyScreenOn(IKeyguardShowCallback callback) {
+        synchronized (KeyguardViewMediator.this) {
+            if (DEBUG) Log.d(TAG, "handleNotifyScreenOn");
+            mKeyguardViewManager.onScreenTurnedOn(callback);
+        }
+    }
+
+    public boolean isDismissable() {
+        return mKeyguardDonePending || !isSecure();
+    }
+
+    public void showAssistant() {
+        Message msg = mHandler.obtainMessage(SHOW_ASSISTANT);
+        mHandler.sendMessage(msg);
+    }
+
+    public void handleShowAssistant() {
+        mKeyguardViewManager.showAssistant();
+    }
+
+    private boolean isAssistantAvailable() {
+        return mSearchManager != null
+                && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
+    }
+
+    public static MultiUserAvatarCache getAvatarCache() {
+        return sMultiUserAvatarCache;
+    }
+
+    public void dispatch(MotionEvent event) {
+        Message msg = mHandler.obtainMessage(DISPATCH_EVENT, event);
+        mHandler.sendMessage(msg);
+    }
+
+    public void launchCamera() {
+        Message msg = mHandler.obtainMessage(LAUNCH_CAMERA);
+        mHandler.sendMessage(msg);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
new file mode 100644
index 0000000..d1862cd
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+
+public class KeyguardViewStateManager implements
+        SlidingChallengeLayout.OnChallengeScrolledListener,
+        ChallengeLayout.OnBouncerStateChangedListener {
+
+    private KeyguardWidgetPager mKeyguardWidgetPager;
+    private ChallengeLayout mChallengeLayout;
+    private KeyguardHostView mKeyguardHostView;
+    private int[] mTmpPoint = new int[2];
+    private int[] mTmpLoc = new int[2];
+
+    private KeyguardSecurityView mKeyguardSecurityContainer;
+    private static final int SCREEN_ON_HINT_DURATION = 1000;
+    private static final int SCREEN_ON_RING_HINT_DELAY = 300;
+    private static final boolean SHOW_INITIAL_PAGE_HINTS = false;
+    Handler mMainQueue = new Handler(Looper.myLooper());
+
+    int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
+
+    // Paged view state
+    private int mPageListeningToSlider = -1;
+    private int mCurrentPage = -1;
+    private int mPageIndexOnPageBeginMoving = -1;
+
+    int mChallengeTop = 0;
+
+    public KeyguardViewStateManager(KeyguardHostView hostView) {
+        mKeyguardHostView = hostView;
+    }
+
+    public void setPagedView(KeyguardWidgetPager pagedView) {
+        mKeyguardWidgetPager = pagedView;
+        updateEdgeSwiping();
+    }
+
+    public void setChallengeLayout(ChallengeLayout layout) {
+        mChallengeLayout = layout;
+        updateEdgeSwiping();
+    }
+
+    private void updateEdgeSwiping() {
+        if (mChallengeLayout != null && mKeyguardWidgetPager != null) {
+            if (mChallengeLayout.isChallengeOverlapping()) {
+                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true);
+            } else {
+                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false);
+            }
+        }
+    }
+
+    public boolean isChallengeShowing() {
+        if (mChallengeLayout != null) {
+            return mChallengeLayout.isChallengeShowing();
+        }
+        return false;
+    }
+
+    public boolean isChallengeOverlapping() {
+        if (mChallengeLayout != null) {
+            return mChallengeLayout.isChallengeOverlapping();
+        }
+        return false;
+    }
+
+    public void setSecurityViewContainer(KeyguardSecurityView container) {
+        mKeyguardSecurityContainer = container;
+    }
+
+    public void showBouncer(boolean show) {
+        CharSequence what = mKeyguardHostView.getContext().getResources().getText(
+                show ? R.string.keyguard_accessibility_show_bouncer
+                        : R.string.keyguard_accessibility_hide_bouncer);
+        mKeyguardHostView.announceForAccessibility(what);
+        mKeyguardHostView.announceCurrentSecurityMethod();
+        mChallengeLayout.showBouncer();
+    }
+
+    public boolean isBouncing() {
+        return mChallengeLayout.isBouncing();
+    }
+
+    public void fadeOutSecurity(int duration) {
+        ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
+    }
+
+    public void fadeInSecurity(int duration) {
+        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
+    }
+
+    public void onPageBeginMoving() {
+        if (mChallengeLayout.isChallengeOverlapping() &&
+                mChallengeLayout instanceof SlidingChallengeLayout) {
+            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
+            scl.fadeOutChallenge();
+            mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
+        }
+        // We use mAppWidgetToShow to show a particular widget after you add it--
+        // once the user swipes a page we clear that behavior
+        if (mKeyguardHostView != null) {
+            mKeyguardHostView.clearAppWidgetToShow();
+            mKeyguardHostView.setOnDismissAction(null);
+        }
+        if (mHideHintsRunnable != null) {
+            mMainQueue.removeCallbacks(mHideHintsRunnable);
+            mHideHintsRunnable = null;
+        }
+    }
+
+    public void onPageEndMoving() {
+        mPageIndexOnPageBeginMoving = -1;
+    }
+
+    public void onPageSwitching(View newPage, int newPageIndex) {
+        if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
+            boolean isCameraPage = newPage instanceof CameraWidgetFrame;
+            ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage);
+        }
+
+        // If the page we're settling to is the same as we started on, and the action of
+        // moving the page hid the security, we restore it immediately.
+        if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() &&
+                mChallengeLayout instanceof SlidingChallengeLayout) {
+            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
+            scl.fadeInChallenge();
+            mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1);
+        }
+        mPageIndexOnPageBeginMoving = -1;
+    }
+
+    public void onPageSwitched(View newPage, int newPageIndex) {
+        // Reset the previous page size and ensure the current page is sized appropriately.
+        // We only modify the page state if it is not currently under control by the slider.
+        // This prevents conflicts.
+
+        // If the page hasn't switched, don't bother with any of this
+        if (mCurrentPage == newPageIndex) return;
+
+        if (mKeyguardWidgetPager != null && mChallengeLayout != null) {
+            KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage);
+            if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage
+                    != mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) {
+                prevPage.resetSize();
+            }
+
+            KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex);
+            boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
+            if (challengeOverlapping && !newCurPage.isSmall()
+                    && mPageListeningToSlider != newPageIndex) {
+                newCurPage.shrinkWidget();
+            }
+        }
+
+        mCurrentPage = newPageIndex;
+    }
+
+    public void onPageBeginWarp() {
+        // fadeOutSecurity(WARP_FADE_DURATION);
+        // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, false);
+    }
+
+    public void onPageEndWarp() {
+        // fadeInSecurity(WARP_FADE_DURATION);
+        // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, true);
+    }
+
+    private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
+        mTmpPoint[0] = 0;
+        mTmpPoint[1] = top;
+        mapPoint((View) mChallengeLayout, frame, mTmpPoint);
+        return mTmpPoint[1];
+    }
+
+    /**
+     * Simple method to map a point from one view's coordinates to another's. Note: this method
+     * doesn't account for transforms, so if the views will be transformed, this should not be used.
+     *
+     * @param fromView The view to which the point is relative
+     * @param toView The view into which the point should be mapped
+     * @param pt The point
+     */
+    private void mapPoint(View fromView, View toView, int pt[]) {
+        fromView.getLocationInWindow(mTmpLoc);
+
+        int x = mTmpLoc[0];
+        int y = mTmpLoc[1];
+
+        toView.getLocationInWindow(mTmpLoc);
+        int vX = mTmpLoc[0];
+        int vY = mTmpLoc[1];
+
+        pt[0] += x - vX;
+        pt[1] += y - vY;
+    }
+
+    private void userActivity() {
+        if (mKeyguardHostView != null) {
+            mKeyguardHostView.onUserActivityTimeoutChanged();
+            mKeyguardHostView.userActivity();
+        }
+    }
+
+    @Override
+    public void onScrollStateChanged(int scrollState) {
+        if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
+
+        boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
+
+        if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
+            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
+            if (frame == null) return;
+
+            if (!challengeOverlapping) {
+                if (!mKeyguardWidgetPager.isPageMoving()) {
+                    frame.resetSize();
+                    userActivity();
+                } else {
+                    mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
+                }
+            }
+            if (frame.isSmall()) {
+                // This is to make sure that if the scroller animation gets cut off midway
+                // that the frame doesn't stay in a partial down position.
+                frame.setFrameHeight(frame.getSmallFrameHeight());
+            }
+            if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
+                frame.hideFrame(this);
+            }
+            updateEdgeSwiping();
+
+            if (mChallengeLayout.isChallengeShowing()) {
+                mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED);
+            } else {
+                mKeyguardSecurityContainer.onPause();
+            }
+            mPageListeningToSlider = -1;
+        } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
+            // Whether dragging or settling, if the last state was idle, we use this signal
+            // to update the current page who will receive events from the sliding challenge.
+            // We resize the frame as appropriate.
+            mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
+            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
+            if (frame == null) return;
+
+            // Skip showing the frame and shrinking the widget if we are
+            if (!mChallengeLayout.isBouncing()) {
+                if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
+                    frame.showFrame(this);
+                }
+
+                // As soon as the security begins sliding, the widget becomes small (if it wasn't
+                // small to begin with).
+                if (!frame.isSmall()) {
+                    // We need to fetch the final page, in case the pages are in motion.
+                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
+                    frame.shrinkWidget(false);
+                }
+            } else {
+                if (!frame.isSmall()) {
+                    // We need to fetch the final page, in case the pages are in motion.
+                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
+                }
+            }
+
+            // View is on the move.  Pause the security view until it completes.
+            mKeyguardSecurityContainer.onPause();
+        }
+        mLastScrollState = scrollState;
+    }
+
+    @Override
+    public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
+        mChallengeTop = challengeTop;
+        KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
+        if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
+            frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
+        }
+    }
+
+    private Runnable mHideHintsRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mKeyguardWidgetPager != null) {
+                mKeyguardWidgetPager.hideOutlinesAndSidePages();
+            }
+        }
+    };
+
+    public void showUsabilityHints() {
+        mMainQueue.postDelayed( new Runnable() {
+            @Override
+            public void run() {
+                mKeyguardSecurityContainer.showUsabilityHint();
+            }
+        } , SCREEN_ON_RING_HINT_DELAY);
+        if (SHOW_INITIAL_PAGE_HINTS) {
+            mKeyguardWidgetPager.showInitialPageHints();
+        }
+        if (mHideHintsRunnable != null) {
+            mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
+        }
+    }
+
+    // ChallengeLayout.OnBouncerStateChangedListener
+    @Override
+    public void onBouncerStateChanged(boolean bouncerActive) {
+        if (bouncerActive) {
+            mKeyguardWidgetPager.zoomOutToBouncer();
+        } else {
+            mKeyguardWidgetPager.zoomInFromBouncer();
+            if (mKeyguardHostView != null) {
+                mKeyguardHostView.setOnDismissAction(null);
+            }
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetCarousel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetCarousel.java
new file mode 100644
index 0000000..98b31b7
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetCarousel.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+
+public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
+
+    private float mAdjacentPagesAngle;
+    private static float MAX_SCROLL_PROGRESS = 1.3f;
+    private static float CAMERA_DISTANCE = 10000;
+    protected AnimatorSet mChildrenTransformsAnimator;
+    float[] mTmpTransform = new float[3];
+
+    public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardWidgetCarousel(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle);
+    }
+
+    protected float getMaxScrollProgress() {
+        return MAX_SCROLL_PROGRESS;
+    }
+
+    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+        View child = getChildAt(index);
+        if (child == null) return 0f;
+
+        boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
+        float scrollProgress = getScrollProgress(screenCenter, child, index);
+
+        if (isOverScrollChild(index, scrollProgress)) {
+            return 1.0f;
+        } else if ((showSidePages && inVisibleRange) || index == getNextPage()) {
+            scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
+            float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
+            return alpha;
+        } else {
+            return 0f;
+        }
+    }
+
+    public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+        boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
+        if (inVisibleRange) {
+            return super.getOutlineAlphaForPage(screenCenter, index, showSidePages);
+        } else {
+            return 0f;
+        }
+    }
+
+    private void updatePageAlphaValues(int screenCenter) {
+        if (mChildrenOutlineFadeAnimation != null) {
+            mChildrenOutlineFadeAnimation.cancel();
+            mChildrenOutlineFadeAnimation = null;
+        }
+        boolean showSidePages = mShowingInitialHints || isPageMoving();
+        if (!isReordering(false)) {
+            for (int i = 0; i < getChildCount(); i++) {
+                KeyguardWidgetFrame child = getWidgetPageAt(i);
+                if (child != null) {
+                    float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages);
+                    float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages);
+                    child.setBackgroundAlpha(outlineAlpha);
+                    child.setContentAlpha(contentAlpha);
+                }
+            }
+        }
+    }
+
+    public void showInitialPageHints() {
+        mShowingInitialHints = true;
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1;
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+            if (inVisibleRange) {
+                child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
+                child.setContentAlpha(1f);
+            } else {
+                child.setBackgroundAlpha(0f);
+                child.setContentAlpha(0f);
+            }
+        }
+    }
+
+    @Override
+    protected void screenScrolled(int screenCenter) {
+        mScreenCenter = screenCenter;
+        updatePageAlphaValues(screenCenter);
+        if (isReordering(false)) return;
+        for (int i = 0; i < getChildCount(); i++) {
+            KeyguardWidgetFrame v = getWidgetPageAt(i);
+            float scrollProgress = getScrollProgress(screenCenter, v, i);
+            float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
+            if (v == mDragView || v == null) continue;
+            v.setCameraDistance(CAMERA_DISTANCE);
+
+            if (isOverScrollChild(i, scrollProgress)) {
+                v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
+                v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
+            } else {
+                int width = v.getMeasuredWidth();
+                float pivotX = (width / 2f) + boundedProgress * (width / 2f);
+                float pivotY = v.getMeasuredHeight() / 2;
+                float rotationY = - mAdjacentPagesAngle * boundedProgress;
+                v.setPivotX(pivotX);
+                v.setPivotY(pivotY);
+                v.setRotationY(rotationY);
+                v.setOverScrollAmount(0f, false);
+            }
+            float alpha = v.getAlpha();
+            // If the view has 0 alpha, we set it to be invisible so as to prevent
+            // it from accepting touches
+            if (alpha == 0) {
+                v.setVisibility(INVISIBLE);
+            } else if (v.getVisibility() != VISIBLE) {
+                v.setVisibility(VISIBLE);
+            }
+        }
+    }
+
+    void animatePagesToNeutral() {
+        if (mChildrenTransformsAnimator != null) {
+            mChildrenTransformsAnimator.cancel();
+            mChildrenTransformsAnimator = null;
+        }
+
+        int count = getChildCount();
+        PropertyValuesHolder alpha;
+        PropertyValuesHolder outlineAlpha;
+        PropertyValuesHolder rotationY;
+        ArrayList<Animator> anims = new ArrayList<Animator>();
+
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
+            if (!inVisibleRange) {
+                child.setRotationY(0f);
+            }
+            alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
+            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
+                    KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
+            rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
+            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
+            child.setVisibility(VISIBLE);
+            if (!inVisibleRange) {
+                a.setInterpolator(mSlowFadeInterpolator);
+            }
+            anims.add(a);
+        }
+
+        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
+        mChildrenTransformsAnimator = new AnimatorSet();
+        mChildrenTransformsAnimator.playTogether(anims);
+
+        mChildrenTransformsAnimator.setDuration(duration);
+        mChildrenTransformsAnimator.start();
+    }
+
+    private void getTransformForPage(int screenCenter, int index, float[] transform) {
+        View child = getChildAt(index);
+        float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
+        float rotationY = - mAdjacentPagesAngle * boundedProgress;
+        int width = child.getMeasuredWidth();
+        float pivotX = (width / 2f) + boundedProgress * (width / 2f);
+        float pivotY = child.getMeasuredHeight() / 2;
+
+        transform[0] = pivotX;
+        transform[1] = pivotY;
+        transform[2] = rotationY;
+    }
+
+    Interpolator mFastFadeInterpolator = new Interpolator() {
+        Interpolator mInternal = new DecelerateInterpolator(1.5f);
+        float mFactor = 2.5f;
+        @Override
+        public float getInterpolation(float input) {
+            return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
+        }
+    };
+
+    Interpolator mSlowFadeInterpolator = new Interpolator() {
+        Interpolator mInternal = new AccelerateInterpolator(1.5f);
+        float mFactor = 1.3f;
+        @Override
+        public float getInterpolation(float input) {
+            input -= (1 - 1 / mFactor);
+            input = mFactor * Math.max(input, 0f);
+            return mInternal.getInterpolation(input);
+        }
+    };
+
+    void animatePagesToCarousel() {
+        if (mChildrenTransformsAnimator != null) {
+            mChildrenTransformsAnimator.cancel();
+            mChildrenTransformsAnimator = null;
+        }
+
+        int count = getChildCount();
+        PropertyValuesHolder alpha;
+        PropertyValuesHolder outlineAlpha;
+        PropertyValuesHolder rotationY;
+        PropertyValuesHolder pivotX;
+        PropertyValuesHolder pivotY;
+        ArrayList<Animator> anims = new ArrayList<Animator>();
+
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+            float finalAlpha = getAlphaForPage(mScreenCenter, i, true);
+            float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true);
+            getTransformForPage(mScreenCenter, i, mTmpTransform);
+
+            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
+
+            ObjectAnimator a;
+            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
+            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
+            pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
+            pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
+            rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
+
+            if (inVisibleRange) {
+                // for the central pages we animate into a rotated state
+                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
+                        pivotX, pivotY, rotationY);
+            } else {
+                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
+                a.setInterpolator(mFastFadeInterpolator);
+            }
+            anims.add(a);
+        }
+
+        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
+        mChildrenTransformsAnimator = new AnimatorSet();
+        mChildrenTransformsAnimator.playTogether(anims);
+
+        mChildrenTransformsAnimator.setDuration(duration);
+        mChildrenTransformsAnimator.start();
+    }
+
+    protected void reorderStarting() {
+        mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
+        animatePagesToNeutral();
+    }
+
+    protected boolean zoomIn(final Runnable onCompleteRunnable) {
+        animatePagesToCarousel();
+        return super.zoomIn(onCompleteRunnable);
+    }
+
+    @Override
+    protected void onEndReordering() {
+        super.onEndReordering();
+        mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
new file mode 100644
index 0000000..ab8a759
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class KeyguardWidgetFrame extends FrameLayout {
+    private final static PorterDuffXfermode sAddBlendMode =
+            new PorterDuffXfermode(PorterDuff.Mode.ADD);
+
+    static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f;
+    static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000;
+
+    // Temporarily disable this for the time being until we know why the gfx is messing up
+    static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true;
+
+    private int mGradientColor;
+    private LinearGradient mForegroundGradient;
+    private LinearGradient mLeftToRightGradient;
+    private LinearGradient mRightToLeftGradient;
+    private Paint mGradientPaint = new Paint();
+    boolean mLeftToRight = true;
+
+    private float mOverScrollAmount = 0f;
+    private final Rect mForegroundRect = new Rect();
+    private int mForegroundAlpha = 0;
+    private CheckLongPressHelper mLongPressHelper;
+    private Animator mFrameFade;
+    private boolean mIsSmall = false;
+    private Handler mWorkerHandler;
+
+    private float mBackgroundAlpha;
+    private float mContentAlpha;
+    private float mBackgroundAlphaMultiplier = 1.0f;
+    private Drawable mBackgroundDrawable;
+    private Rect mBackgroundRect = new Rect();
+
+    // These variables are all needed in order to size things properly before we're actually
+    // measured.
+    private int mSmallWidgetHeight;
+    private int mSmallFrameHeight;
+    private boolean mWidgetLockedSmall = false;
+    private int mMaxChallengeTop = -1;
+    private int mFrameStrokeAdjustment;
+    private boolean mPerformAppWidgetSizeUpdateOnBootComplete;
+
+    // This will hold the width value before we've actually been measured
+    private int mFrameHeight;
+
+    private boolean mIsHoveringOverDeleteDropTarget;
+
+    // Multiple callers may try and adjust the alpha of the frame. When a caller shows
+    // the outlines, we give that caller control, and nobody else can fade them out.
+    // This prevents animation conflicts.
+    private Object mBgAlphaController;
+
+    public KeyguardWidgetFrame(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardWidgetFrame(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardWidgetFrame(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        mLongPressHelper = new CheckLongPressHelper(this);
+
+        Resources res = context.getResources();
+        // TODO: this padding should really correspond to the padding embedded in the background
+        // drawable (ie. outlines).
+        float density = res.getDisplayMetrics().density;
+        int padding = (int) (res.getDisplayMetrics().density * 8);
+        setPadding(padding, padding, padding, padding);
+
+        mFrameStrokeAdjustment = 2 + (int) (2 * density);
+
+        // This will be overriden on phones based on the current security mode, however on tablets
+        // we need to specify a height.
+        mSmallWidgetHeight =
+                res.getDimensionPixelSize(R.dimen.kg_small_widget_height);
+        mBackgroundDrawable = res.getDrawable(R.drawable.kg_widget_bg_padded);
+        mGradientColor = res.getColor(R.color.kg_widget_pager_gradient);
+        mGradientPaint.setXfermode(sAddBlendMode);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        cancelLongPress();
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
+
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
+    }
+
+    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
+            new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onBootCompleted() {
+            if (mPerformAppWidgetSizeUpdateOnBootComplete) {
+                performAppWidgetSizeCallbacksIfNecessary();
+                mPerformAppWidgetSizeUpdateOnBootComplete = false;
+            }
+        }
+    };
+
+    void setIsHoveringOverDeleteDropTarget(boolean isHovering) {
+        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+            if (mIsHoveringOverDeleteDropTarget != isHovering) {
+                mIsHoveringOverDeleteDropTarget = isHovering;
+                int resId = isHovering ? R.string.keyguard_accessibility_delete_widget_start
+                        : R.string.keyguard_accessibility_delete_widget_end;
+                String text = getContext().getResources().getString(resId, getContentDescription());
+                announceForAccessibility(text);
+                invalidate();
+            }
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // Watch for longpress events at this level to make sure
+        // users can always pick up this widget
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mLongPressHelper.postCheckForLongPress(ev);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mLongPressHelper.onMove(ev);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mLongPressHelper.cancelLongPress();
+                break;
+        }
+
+        // Otherwise continue letting touch events fall through to children
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        // Watch for longpress events at this level to make sure
+        // users can always pick up this widget
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_MOVE:
+                mLongPressHelper.onMove(ev);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mLongPressHelper.cancelLongPress();
+                break;
+        }
+
+        // We return true here to ensure that we will get cancel / up signal
+        // even if none of our children have requested touch.
+        return true;
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        cancelLongPress();
+    }
+
+    @Override
+    public void cancelLongPress() {
+        super.cancelLongPress();
+        mLongPressHelper.cancelLongPress();
+    }
+
+
+    private void drawGradientOverlay(Canvas c) {
+        mGradientPaint.setShader(mForegroundGradient);
+        mGradientPaint.setAlpha(mForegroundAlpha);
+        c.drawRect(mForegroundRect, mGradientPaint);
+    }
+
+    private void drawHoveringOverDeleteOverlay(Canvas c) {
+        if (mIsHoveringOverDeleteDropTarget) {
+            c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR);
+        }
+    }
+
+    protected void drawBg(Canvas canvas) {
+        if (mBackgroundAlpha > 0.0f) {
+            Drawable bg = mBackgroundDrawable;
+
+            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
+            bg.setBounds(mBackgroundRect);
+            bg.draw(canvas);
+        }
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+            canvas.save();
+        }
+        drawBg(canvas);
+        super.dispatchDraw(canvas);
+        drawGradientOverlay(canvas);
+        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+            drawHoveringOverDeleteOverlay(canvas);
+            canvas.restore();
+        }
+    }
+
+    /**
+     * Because this view has fading outlines, it is essential that we enable hardware
+     * layers on the content (child) so that updating the alpha of the outlines doesn't
+     * result in the content layer being recreated.
+     */
+    public void enableHardwareLayersForContent() {
+        View widget = getContent();
+        if (widget != null && widget.isHardwareAccelerated()) {
+            widget.setLayerType(LAYER_TYPE_HARDWARE, null);
+        }
+    }
+
+    /**
+     * Because this view has fading outlines, it is essential that we enable hardware
+     * layers on the content (child) so that updating the alpha of the outlines doesn't
+     * result in the content layer being recreated.
+     */
+    public void disableHardwareLayersForContent() {
+        View widget = getContent();
+        if (widget != null) {
+            widget.setLayerType(LAYER_TYPE_NONE, null);
+        }
+    }
+
+    public View getContent() {
+        return getChildAt(0);
+    }
+
+    public int getContentAppWidgetId() {
+        View content = getContent();
+        if (content instanceof AppWidgetHostView) {
+            return ((AppWidgetHostView) content).getAppWidgetId();
+        } else if (content instanceof KeyguardStatusView) {
+            return ((KeyguardStatusView) content).getAppWidgetId();
+        } else {
+            return AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+    }
+
+    public float getBackgroundAlpha() {
+        return mBackgroundAlpha;
+    }
+
+    public void setBackgroundAlphaMultiplier(float multiplier) {
+        if (Float.compare(mBackgroundAlphaMultiplier, multiplier) != 0) {
+            mBackgroundAlphaMultiplier = multiplier;
+            invalidate();
+        }
+    }
+
+    public float getBackgroundAlphaMultiplier() {
+        return mBackgroundAlphaMultiplier;
+    }
+
+    public void setBackgroundAlpha(float alpha) {
+        if (Float.compare(mBackgroundAlpha, alpha) != 0) {
+            mBackgroundAlpha = alpha;
+            invalidate();
+        }
+    }
+
+    public float getContentAlpha() {
+        return mContentAlpha;
+    }
+
+    public void setContentAlpha(float alpha) {
+        mContentAlpha = alpha;
+        View content = getContent();
+        if (content != null) {
+            content.setAlpha(alpha);
+        }
+    }
+
+    /**
+     * Depending on whether the security is up, the widget size needs to change
+     *
+     * @param height The height of the widget, -1 for full height
+     */
+    private void setWidgetHeight(int height) {
+        boolean needLayout = false;
+        View widget = getContent();
+        if (widget != null) {
+            LayoutParams lp = (LayoutParams) widget.getLayoutParams();
+            if (lp.height != height) {
+                needLayout = true;
+                lp.height = height;
+            }
+        }
+        if (needLayout) {
+            requestLayout();
+        }
+    }
+
+    public void setMaxChallengeTop(int top) {
+        boolean dirty = mMaxChallengeTop != top;
+        mMaxChallengeTop = top;
+        mSmallWidgetHeight = top - getPaddingTop();
+        mSmallFrameHeight = top + getPaddingBottom();
+        if (dirty && mIsSmall) {
+            setWidgetHeight(mSmallWidgetHeight);
+            setFrameHeight(mSmallFrameHeight);
+        } else if (dirty && mWidgetLockedSmall) {
+            setWidgetHeight(mSmallWidgetHeight);
+        }
+    }
+
+    public boolean isSmall() {
+        return mIsSmall;
+    }
+
+    public void adjustFrame(int challengeTop) {
+        int frameHeight = challengeTop + getPaddingBottom();
+        setFrameHeight(frameHeight);
+    }
+
+    public void shrinkWidget(boolean alsoShrinkFrame) {
+        mIsSmall = true;
+        setWidgetHeight(mSmallWidgetHeight);
+
+        if (alsoShrinkFrame) {
+            setFrameHeight(mSmallFrameHeight);
+        }
+    }
+
+    public int getSmallFrameHeight() {
+        return mSmallFrameHeight;
+    }
+
+    public void shrinkWidget() {
+        shrinkWidget(true);
+    }
+
+    public void setWidgetLockedSmall(boolean locked) {
+        if (locked) {
+            setWidgetHeight(mSmallWidgetHeight);
+        }
+        mWidgetLockedSmall = locked;
+    }
+
+    public void resetSize() {
+        mIsSmall = false;
+        if (!mWidgetLockedSmall) {
+            setWidgetHeight(LayoutParams.MATCH_PARENT);
+        }
+        setFrameHeight(getMeasuredHeight());
+    }
+
+    public void setFrameHeight(int height) {
+        mFrameHeight = height;
+        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(mFrameHeight, getMeasuredHeight()));
+        mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,getMeasuredWidth() -
+                mFrameStrokeAdjustment, Math.min(getMeasuredHeight(), mFrameHeight) -
+                mFrameStrokeAdjustment);
+        updateGradient();
+        invalidate();
+    }
+
+    public void hideFrame(Object caller) {
+        fadeFrame(caller, false, 0f, KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_OUT_DURATION);
+    }
+
+    public void showFrame(Object caller) {
+        fadeFrame(caller, true, OUTLINE_ALPHA_MULTIPLIER,
+                KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_IN_DURATION);
+    }
+
+    public void fadeFrame(Object caller, boolean takeControl, float alpha, int duration) {
+        if (takeControl) {
+            mBgAlphaController = caller;
+        }
+
+        if (mBgAlphaController != caller && mBgAlphaController != null) {
+            return;
+        }
+
+        if (mFrameFade != null) {
+            mFrameFade.cancel();
+            mFrameFade = null;
+        }
+        PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", alpha);
+        mFrameFade = ObjectAnimator.ofPropertyValuesHolder(this, bgAlpha);
+        mFrameFade.setDuration(duration);
+        mFrameFade.start();
+    }
+
+    private void updateGradient() {
+        float x0 = mLeftToRight ? 0 : mForegroundRect.width();
+        float x1 = mLeftToRight ? mForegroundRect.width(): 0;
+        mLeftToRightGradient = new LinearGradient(x0, 0f, x1, 0f,
+                mGradientColor, 0, Shader.TileMode.CLAMP);
+        mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f,
+                mGradientColor, 0, Shader.TileMode.CLAMP);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        if (!mIsSmall) {
+            mFrameHeight = h;
+        }
+
+        // mFrameStrokeAdjustment is a cludge to prevent the overlay from drawing outside the
+        // rounded rect background.
+        mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,
+                w - mFrameStrokeAdjustment, Math.min(h, mFrameHeight) - mFrameStrokeAdjustment);
+
+        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(h, mFrameHeight));
+        updateGradient();
+        invalidate();
+    }
+
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        performAppWidgetSizeCallbacksIfNecessary();
+    }
+
+    private void performAppWidgetSizeCallbacksIfNecessary() {
+        View content = getContent();
+        if (!(content instanceof AppWidgetHostView)) return;
+
+        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
+            mPerformAppWidgetSizeUpdateOnBootComplete = true;
+            return;
+        }
+
+        // TODO: there's no reason to force the AppWidgetHostView to catch duplicate size calls.
+        // We can do that even more cheaply here. It's not an issue right now since we're in the
+        // system process and hence no binder calls.
+        AppWidgetHostView awhv = (AppWidgetHostView) content;
+        float density = getResources().getDisplayMetrics().density;
+
+        int width = (int) (content.getMeasuredWidth() / density);
+        int height = (int) (content.getMeasuredHeight() / density);
+        awhv.updateAppWidgetSize(null, width, height, width, height, true);
+    }
+
+    void setOverScrollAmount(float r, boolean left) {
+        if (Float.compare(mOverScrollAmount, r) != 0) {
+            mOverScrollAmount = r;
+            mForegroundGradient = left ? mLeftToRightGradient : mRightToLeftGradient;
+            mForegroundAlpha = (int) Math.round((0.5f * r * 255));
+
+            // We bump up the alpha of the outline to hide the fact that the overlay is drawing
+            // over the rounded part of the frame.
+            float bgAlpha = Math.min(OUTLINE_ALPHA_MULTIPLIER + r * (1 - OUTLINE_ALPHA_MULTIPLIER),
+                    1f);
+            setBackgroundAlpha(bgAlpha);
+            invalidate();
+        }
+    }
+
+    public void onActive(boolean isActive) {
+        // hook for subclasses
+    }
+
+    public boolean onUserInteraction(MotionEvent event) {
+        // hook for subclasses
+        return false;
+    }
+
+    public void onBouncerShowing(boolean showing) {
+        // hook for subclasses
+    }
+
+    public void setWorkerHandler(Handler workerHandler) {
+        mWorkerHandler = workerHandler;
+    }
+
+    public Handler getWorkerHandler() {
+        return mWorkerHandler;
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
new file mode 100644
index 0000000..f8857ab
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
@@ -0,0 +1,967 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.TextClock;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import java.util.ArrayList;
+import java.util.TimeZone;
+
+public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
+        OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener {
+
+    ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
+    private static float CAMERA_DISTANCE = 10000;
+    protected static float OVERSCROLL_MAX_ROTATION = 30;
+    private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
+
+    private static final int FLAG_HAS_LOCAL_HOUR = 0x1;
+    private static final int FLAG_HAS_LOCAL_MINUTE = 0x2;
+
+    protected KeyguardViewStateManager mViewStateManager;
+    private LockPatternUtils mLockPatternUtils;
+
+    // Related to the fading in / out background outlines
+    public static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
+    public static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
+    protected AnimatorSet mChildrenOutlineFadeAnimation;
+    protected int mScreenCenter;
+    private boolean mHasMeasure = false;
+    boolean showHintsAfterLayout = false;
+
+    private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
+    private static final String TAG = "KeyguardWidgetPager";
+    private boolean mCenterSmallWidgetsVertically;
+
+    private int mPage = 0;
+    private Callbacks mCallbacks;
+
+    private int mWidgetToResetAfterFadeOut;
+    protected boolean mShowingInitialHints = false;
+
+    // A temporary handle to the Add-Widget view
+    private View mAddWidgetView;
+    private int mLastWidthMeasureSpec;
+    private int mLastHeightMeasureSpec;
+
+    // Bouncer
+    private int mBouncerZoomInOutDuration = 250;
+    private float BOUNCER_SCALE_FACTOR = 0.67f;
+
+    // Background worker thread: used here for persistence, also made available to widget frames
+    private final HandlerThread mBackgroundWorkerThread;
+    private final Handler mBackgroundWorkerHandler;
+    private boolean mCameraEventInProgress;
+
+    public KeyguardWidgetPager(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardWidgetPager(Context context) {
+        this(null, null, 0);
+    }
+
+    public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+
+        setPageSwitchListener(this);
+
+        mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker");
+        mBackgroundWorkerThread.start();
+        mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper());
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        // Clean up the worker thread
+        mBackgroundWorkerThread.quit();
+    }
+
+    public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
+        mViewStateManager = viewStateManager;
+    }
+
+    public void setLockPatternUtils(LockPatternUtils l) {
+        mLockPatternUtils = l;
+    }
+
+    @Override
+    public void onPageSwitching(View newPage, int newPageIndex) {
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageSwitching(newPage, newPageIndex);
+        }
+    }
+
+    @Override
+    public void onPageSwitched(View newPage, int newPageIndex) {
+        boolean showingClock = false;
+        if (newPage instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) newPage;
+            if (vg.getChildAt(0) instanceof KeyguardStatusView) {
+                showingClock = true;
+            }
+        }
+
+        if (newPage != null &&
+                findClockInHierarchy(newPage) == (FLAG_HAS_LOCAL_HOUR | FLAG_HAS_LOCAL_MINUTE)) {
+            showingClock = true;
+        }
+
+        // Disable the status bar clock if we're showing the default status widget
+        if (showingClock) {
+            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
+        } else {
+            setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
+        }
+
+        // Extend the display timeout if the user switches pages
+        if (mPage != newPageIndex) {
+            int oldPageIndex = mPage;
+            mPage = newPageIndex;
+            userActivity();
+            KeyguardWidgetFrame oldWidgetPage = getWidgetPageAt(oldPageIndex);
+            if (oldWidgetPage != null) {
+                oldWidgetPage.onActive(false);
+            }
+            KeyguardWidgetFrame newWidgetPage = getWidgetPageAt(newPageIndex);
+            if (newWidgetPage != null) {
+                newWidgetPage.onActive(true);
+                newWidgetPage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+                newWidgetPage.requestAccessibilityFocus();
+            }
+            if (mParent != null && AccessibilityManager.getInstance(mContext).isEnabled()) {
+                AccessibilityEvent event = AccessibilityEvent.obtain(
+                        AccessibilityEvent.TYPE_VIEW_SCROLLED);
+                onInitializeAccessibilityEvent(event);
+                onPopulateAccessibilityEvent(event);
+                mParent.requestSendAccessibilityEvent(this, event);
+            }
+        }
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageSwitched(newPage, newPageIndex);
+        }
+    }
+
+    @Override
+    public void onPageBeginWarp() {
+        mViewStateManager.onPageBeginWarp();
+    }
+
+    @Override
+    public void onPageEndWarp() {
+        mViewStateManager.onPageEndWarp();
+    }
+
+    @Override
+    public void sendAccessibilityEvent(int eventType) {
+        if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) {
+            super.sendAccessibilityEvent(eventType);
+        }
+    }
+
+    private void updateWidgetFramesImportantForAccessibility() {
+        final int pageCount = getPageCount();
+        for (int i = 0; i < pageCount; i++) {
+            KeyguardWidgetFrame frame = getWidgetPageAt(i);
+            updateWidgetFrameImportantForAccessibility(frame);
+        }
+    }
+
+    private void updateWidgetFrameImportantForAccessibility(KeyguardWidgetFrame frame) {
+        if (frame.getContentAlpha() <= 0) {
+            frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        } else {
+            frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    private void userActivity() {
+        if (mCallbacks != null) {
+            mCallbacks.onUserActivityTimeoutChanged();
+            mCallbacks.userActivity();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return captureUserInteraction(ev) || super.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return captureUserInteraction(ev) || super.onInterceptTouchEvent(ev);
+    }
+
+    private boolean captureUserInteraction(MotionEvent ev) {
+        KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage());
+        return currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev);
+    }
+
+    public void showPagingFeedback() {
+        // Nothing yet.
+    }
+
+    public long getUserActivityTimeout() {
+        View page = getPageAt(mPage);
+        if (page instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) page;
+            View view = vg.getChildAt(0);
+            if (!(view instanceof KeyguardStatusView)
+                    && !(view instanceof KeyguardMultiUserSelectorView)) {
+                return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
+            }
+        }
+        return -1;
+    }
+
+    public void setCallbacks(Callbacks callbacks) {
+        mCallbacks = callbacks;
+    }
+
+    public interface Callbacks {
+        public void userActivity();
+        public void onUserActivityTimeoutChanged();
+        public void onAddView(View v);
+        public void onRemoveView(View v, boolean deletePermanently);
+        public void onRemoveViewAnimationCompleted();
+    }
+
+    public void addWidget(View widget) {
+        addWidget(widget, -1);
+    }
+
+    public void onRemoveView(View v, final boolean deletePermanently) {
+        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+        if (mCallbacks != null) {
+            mCallbacks.onRemoveView(v, deletePermanently);
+        }
+        mBackgroundWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.removeAppWidget(appWidgetId);
+            }
+        });
+    }
+
+    @Override
+    public void onRemoveViewAnimationCompleted() {
+        if (mCallbacks != null) {
+            mCallbacks.onRemoveViewAnimationCompleted();
+        }
+    }
+
+    public void onAddView(View v, final int index) {
+        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+        final int[] pagesRange = new int[mTempVisiblePagesRange.length];
+        getVisiblePages(pagesRange);
+        boundByReorderablePages(true, pagesRange);
+        if (mCallbacks != null) {
+            mCallbacks.onAddView(v);
+        }
+        // Subtract from the index to take into account pages before the reorderable
+        // pages (e.g. the "add widget" page)
+        mBackgroundWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
+            }
+        });
+    }
+
+    /*
+     * We wrap widgets in a special frame which handles drawing the over scroll foreground.
+     */
+    public void addWidget(View widget, int pageIndex) {
+        KeyguardWidgetFrame frame;
+        // All views contained herein should be wrapped in a KeyguardWidgetFrame
+        if (!(widget instanceof KeyguardWidgetFrame)) {
+            frame = new KeyguardWidgetFrame(getContext());
+            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                    LayoutParams.MATCH_PARENT);
+            lp.gravity = Gravity.TOP;
+
+            // The framework adds a default padding to AppWidgetHostView. We don't need this padding
+            // for the Keyguard, so we override it to be 0.
+            widget.setPadding(0,  0, 0, 0);
+            frame.addView(widget, lp);
+
+            // We set whether or not this widget supports vertical resizing.
+            if (widget instanceof AppWidgetHostView) {
+                AppWidgetHostView awhv = (AppWidgetHostView) widget;
+                AppWidgetProviderInfo info = awhv.getAppWidgetInfo();
+                if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
+                    frame.setWidgetLockedSmall(false);
+                } else {
+                    // Lock the widget to be small.
+                    frame.setWidgetLockedSmall(true);
+                    if (mCenterSmallWidgetsVertically) {
+                        lp.gravity = Gravity.CENTER;
+                    }
+                }
+            }
+        } else {
+            frame = (KeyguardWidgetFrame) widget;
+        }
+
+        ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+        frame.setOnLongClickListener(this);
+        frame.setWorkerHandler(mBackgroundWorkerHandler);
+
+        if (pageIndex == -1) {
+            addView(frame, pageLp);
+        } else {
+            addView(frame, pageIndex, pageLp);
+        }
+
+        // Update the frame content description.
+        View content = (widget == frame) ?  frame.getContent() : widget;
+        if (content != null) {
+            String contentDescription = mContext.getString(
+                R.string.keyguard_accessibility_widget,
+                content.getContentDescription());
+            frame.setContentDescription(contentDescription);
+        }
+        updateWidgetFrameImportantForAccessibility(frame);
+    }
+
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
+    @Override
+    public void addView(View child, int index) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, index);
+    }
+
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
+    @Override
+    public void addView(View child, int width, int height) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, width, height);
+    }
+
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
+    @Override
+    public void addView(View child, LayoutParams params) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, params);
+    }
+
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, index, params);
+    }
+
+    private void enforceKeyguardWidgetFrame(View child) {
+        if (!(child instanceof KeyguardWidgetFrame)) {
+            throw new IllegalArgumentException(
+                    "KeyguardWidgetPager children must be KeyguardWidgetFrames");
+        }
+    }
+
+    public KeyguardWidgetFrame getWidgetPageAt(int index) {
+        // This is always a valid cast as we've guarded the ability to
+        return (KeyguardWidgetFrame) getChildAt(index);
+    }
+
+    protected void onUnhandledTap(MotionEvent ev) {
+        showPagingFeedback();
+    }
+
+    @Override
+    protected void onPageBeginMoving() {
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageBeginMoving();
+        }
+        if (!isReordering(false)) {
+            showOutlinesAndSidePages();
+        }
+        userActivity();
+    }
+
+    @Override
+    protected void onPageEndMoving() {
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageEndMoving();
+        }
+
+        // In the reordering case, the pages will be faded appropriately on completion
+        // of the zoom in animation.
+        if (!isReordering(false)) {
+            hideOutlinesAndSidePages();
+        }
+    }
+
+    protected void enablePageContentLayers() {
+        int children = getChildCount();
+        for (int i = 0; i < children; i++) {
+            getWidgetPageAt(i).enableHardwareLayersForContent();
+        }
+    }
+
+    protected void disablePageContentLayers() {
+        int children = getChildCount();
+        for (int i = 0; i < children; i++) {
+            getWidgetPageAt(i).disableHardwareLayersForContent();
+        }
+    }
+
+    /*
+     * This interpolator emulates the rate at which the perceived scale of an object changes
+     * as its distance from a camera increases. When this interpolator is applied to a scale
+     * animation on a view, it evokes the sense that the object is shrinking due to moving away
+     * from the camera.
+     */
+    static class ZInterpolator implements TimeInterpolator {
+        private float focalLength;
+
+        public ZInterpolator(float foc) {
+            focalLength = foc;
+        }
+
+        public float getInterpolation(float input) {
+            return (1.0f - focalLength / (focalLength + input)) /
+                (1.0f - focalLength / (focalLength + 1.0f));
+        }
+    }
+
+    @Override
+    protected void overScroll(float amount) {
+        acceleratedOverScroll(amount);
+    }
+
+    float backgroundAlphaInterpolator(float r) {
+        return Math.min(1f, r);
+    }
+
+    private void updatePageAlphaValues(int screenCenter) {
+    }
+
+    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+        if (getPageWarpIndex() != -1) {
+            return index == getPageWarpIndex() ? 1.0f : 0.0f;
+        }
+        if (showSidePages) {
+            return 1f;
+        } else {
+            return index == mCurrentPage ? 1.0f : 0f;
+        }
+    }
+
+    public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+        if (showSidePages) {
+            return getAlphaForPage(screenCenter, index, showSidePages)
+                    * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER;
+        } else {
+            return 0f;
+        }
+    }
+
+    protected boolean isOverScrollChild(int index, float scrollProgress) {
+        boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
+        return (isInOverscroll && (index == 0 && scrollProgress < 0 ||
+                index == getChildCount() - 1 && scrollProgress > 0));
+    }
+
+    @Override
+    protected void screenScrolled(int screenCenter) {
+        mScreenCenter = screenCenter;
+        updatePageAlphaValues(screenCenter);
+        for (int i = 0; i < getChildCount(); i++) {
+            KeyguardWidgetFrame v = getWidgetPageAt(i);
+            if (v == mDragView) continue;
+            if (v != null) {
+                float scrollProgress = getScrollProgress(screenCenter, v, i);
+
+                v.setCameraDistance(mDensity * CAMERA_DISTANCE);
+
+                if (isOverScrollChild(i, scrollProgress) && PERFORM_OVERSCROLL_ROTATION) {
+                    float pivotX = v.getMeasuredWidth() / 2;
+                    float pivotY = v.getMeasuredHeight() / 2;
+                    v.setPivotX(pivotX);
+                    v.setPivotY(pivotY);
+                    v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
+                    v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
+                } else {
+                    v.setRotationY(0f);
+                    v.setOverScrollAmount(0, false);
+                }
+
+                float alpha = v.getAlpha();
+                // If the view has 0 alpha, we set it to be invisible so as to prevent
+                // it from accepting touches
+                if (alpha == 0) {
+                    v.setVisibility(INVISIBLE);
+                } else if (v.getVisibility() != VISIBLE) {
+                    v.setVisibility(VISIBLE);
+                }
+            }
+        }
+    }
+
+    public boolean isWidgetPage(int pageIndex) {
+        if (pageIndex < 0 || pageIndex >= getChildCount()) {
+            return false;
+        }
+        View v = getChildAt(pageIndex);
+        if (v != null && v instanceof KeyguardWidgetFrame) {
+            KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
+            return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the bounded set of pages that are re-orderable.  The range is fully inclusive.
+     */
+    @Override
+    void boundByReorderablePages(boolean isReordering, int[] range) {
+        if (isReordering) {
+            // Remove non-widget pages from the range
+            while (range[1] >= range[0] && !isWidgetPage(range[1])) {
+                range[1]--;
+            }
+            while (range[0] <= range[1] && !isWidgetPage(range[0])) {
+                range[0]++;
+            }
+        }
+    }
+
+    protected void reorderStarting() {
+        showOutlinesAndSidePages();
+    }
+
+    @Override
+    protected void onStartReordering() {
+        super.onStartReordering();
+        enablePageContentLayers();
+        reorderStarting();
+    }
+
+    @Override
+    protected void onEndReordering() {
+        super.onEndReordering();
+        hideOutlinesAndSidePages();
+    }
+
+    void showOutlinesAndSidePages() {
+        animateOutlinesAndSidePages(true);
+    }
+
+    void hideOutlinesAndSidePages() {
+        animateOutlinesAndSidePages(false);
+    }
+
+    void updateChildrenContentAlpha(float sidePageAlpha) {
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+            if (i != mCurrentPage) {
+                child.setBackgroundAlpha(sidePageAlpha);
+                child.setContentAlpha(0f);
+            } else {
+                child.setBackgroundAlpha(0f);
+                child.setContentAlpha(1f);
+            }
+        }
+    }
+
+    public void showInitialPageHints() {
+        mShowingInitialHints = true;
+        updateChildrenContentAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
+    }
+
+    @Override
+    void setCurrentPage(int currentPage) {
+        super.setCurrentPage(currentPage);
+        updateChildrenContentAlpha(0.0f);
+        updateWidgetFramesImportantForAccessibility();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mHasMeasure = false;
+    }
+
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mLastWidthMeasureSpec = widthMeasureSpec;
+        mLastHeightMeasureSpec = heightMeasureSpec;
+
+        int maxChallengeTop = -1;
+        View parent = (View) getParent();
+        boolean challengeShowing = false;
+        // Widget pages need to know where the top of the sliding challenge is so that they
+        // now how big the widget should be when the challenge is up. We compute it here and
+        // then propagate it to each of our children.
+        if (parent.getParent() instanceof SlidingChallengeLayout) {
+            SlidingChallengeLayout scl = (SlidingChallengeLayout) parent.getParent();
+            int top = scl.getMaxChallengeTop();
+
+            // This is a bit evil, but we need to map a coordinate relative to the SCL into a
+            // coordinate relative to our children, hence we subtract the top padding.s
+            maxChallengeTop = top - getPaddingTop();
+            challengeShowing = scl.isChallengeShowing();
+
+            int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                KeyguardWidgetFrame frame = getWidgetPageAt(i);
+                frame.setMaxChallengeTop(maxChallengeTop);
+                // On the very first measure pass, if the challenge is showing, we need to make sure
+                // that the widget on the current page is small.
+                if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
+                    frame.shrinkWidget();
+                }
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mHasMeasure = true;
+    }
+
+    void animateOutlinesAndSidePages(final boolean show) {
+        animateOutlinesAndSidePages(show, -1);
+    }
+
+    public void setWidgetToResetOnPageFadeOut(int widget) {
+        mWidgetToResetAfterFadeOut = widget;
+    }
+
+    public int getWidgetToResetOnPageFadeOut() {
+        return mWidgetToResetAfterFadeOut;
+    }
+
+    void animateOutlinesAndSidePages(final boolean show, int duration) {
+        if (mChildrenOutlineFadeAnimation != null) {
+            mChildrenOutlineFadeAnimation.cancel();
+            mChildrenOutlineFadeAnimation = null;
+        }
+        int count = getChildCount();
+        PropertyValuesHolder alpha;
+        ArrayList<Animator> anims = new ArrayList<Animator>();
+
+        if (duration == -1) {
+            duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
+                CHILDREN_OUTLINE_FADE_OUT_DURATION;
+        }
+
+        int curPage = getNextPage();
+        for (int i = 0; i < count; i++) {
+            float finalContentAlpha;
+            if (show) {
+                finalContentAlpha = getAlphaForPage(mScreenCenter, i, true);
+            } else if (!show && i == curPage) {
+                finalContentAlpha = 1f;
+            } else {
+                finalContentAlpha = 0f;
+            }
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+
+            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha);
+            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha);
+            anims.add(a);
+
+            float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i, true) : 0f;
+            child.fadeFrame(this, show, finalOutlineAlpha, duration);
+        }
+
+        mChildrenOutlineFadeAnimation = new AnimatorSet();
+        mChildrenOutlineFadeAnimation.playTogether(anims);
+
+        mChildrenOutlineFadeAnimation.setDuration(duration);
+        mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                if (show) {
+                    enablePageContentLayers();
+                }
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!show) {
+                    disablePageContentLayers();
+                    KeyguardWidgetFrame frame = getWidgetPageAt(mWidgetToResetAfterFadeOut);
+                    if (frame != null && !(frame == getWidgetPageAt(mCurrentPage) &&
+                            mViewStateManager.isChallengeOverlapping())) {
+                        frame.resetSize();
+                    }
+                    mWidgetToResetAfterFadeOut = -1;
+                    mShowingInitialHints = false;
+                }
+                updateWidgetFramesImportantForAccessibility();
+            }
+        });
+        mChildrenOutlineFadeAnimation.start();
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        // Disallow long pressing to reorder if the challenge is showing
+        boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() &&
+                mViewStateManager.isChallengeOverlapping();
+        if (!isChallengeOverlapping && startReordering()) {
+            return true;
+        }
+        return false;
+    }
+
+    public void removeWidget(View view) {
+        if (view instanceof KeyguardWidgetFrame) {
+            removeView(view);
+        } else {
+            // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget().
+            // This supports legacy hard-coded "widgets" like KeyguardTransportControlView.
+            int pos = getWidgetPageIndex(view);
+            if (pos != -1) {
+                KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos);
+                frame.removeView(view);
+                removeView(frame);
+            } else {
+                Slog.w(TAG, "removeWidget() can't find:" + view);
+            }
+        }
+    }
+
+    public int getWidgetPageIndex(View view) {
+        if (view instanceof KeyguardWidgetFrame) {
+            return indexOfChild(view);
+        } else {
+            // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget()
+            return indexOfChild((KeyguardWidgetFrame)view.getParent());
+        }
+    }
+
+    @Override
+    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {
+        KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
+        child.setIsHoveringOverDeleteDropTarget(isHovering);
+    }
+
+    // ChallengeLayout.OnBouncerStateChangedListener
+    @Override
+    public void onBouncerStateChanged(boolean bouncerActive) {
+        if (bouncerActive) {
+            zoomOutToBouncer();
+        } else {
+            zoomInFromBouncer();
+        }
+    }
+
+    void setBouncerAnimationDuration(int duration) {
+        mBouncerZoomInOutDuration = duration;
+    }
+
+    // Zoom in after the bouncer is dismissed
+    void zoomInFromBouncer() {
+        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+            mZoomInOutAnim.cancel();
+        }
+        final View currentPage = getPageAt(getCurrentPage());
+        if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) {
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(currentPage, "scaleX", 1f),
+                    ObjectAnimator.ofFloat(currentPage , "scaleY", 1f));
+            mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
+            mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
+            mZoomInOutAnim.start();
+        }
+        if (currentPage instanceof KeyguardWidgetFrame) {
+            ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false);
+        }
+    }
+
+    // Zoom out after the bouncer is initiated
+    void zoomOutToBouncer() {
+        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+            mZoomInOutAnim.cancel();
+        }
+        int curPage = getCurrentPage();
+        View currentPage = getPageAt(curPage);
+        if (shouldSetTopAlignedPivotForWidget(curPage)) {
+            currentPage.setPivotY(0);
+            // Note: we are working around the issue that setting the x-pivot to the same value as it
+            //       was does not actually work.
+            currentPage.setPivotX(0);
+            currentPage.setPivotX(currentPage.getMeasuredWidth() / 2);
+        }
+        if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) {
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR),
+                    ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR));
+            mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
+            mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
+            mZoomInOutAnim.start();
+        }
+        if (currentPage instanceof KeyguardWidgetFrame) {
+            ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true);
+        }
+    }
+
+    void setAddWidgetEnabled(boolean enabled) {
+        if (mAddWidgetView != null && enabled) {
+            addView(mAddWidgetView, 0);
+            // We need to force measure the PagedView so that the calls to update the scroll
+            // position below work
+            measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);
+            // Bump up the current page to account for the addition of the new page
+            setCurrentPage(mCurrentPage + 1);
+            mAddWidgetView = null;
+        } else if (mAddWidgetView == null && !enabled) {
+            View addWidget = findViewById(R.id.keyguard_add_widget);
+            if (addWidget != null) {
+                mAddWidgetView = addWidget;
+                removeView(addWidget);
+            }
+        }
+    }
+
+    boolean isAddPage(int pageIndex) {
+        View v = getChildAt(pageIndex);
+        return v != null && v.getId() == R.id.keyguard_add_widget;
+    }
+
+    boolean isCameraPage(int pageIndex) {
+        View v = getChildAt(pageIndex);
+        return v != null && v instanceof CameraWidgetFrame;
+    }
+
+    @Override
+    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
+        return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex);
+    }
+
+    /**
+     * Search given {@link View} hierarchy for {@link TextClock} instances that
+     * show various time components. Returns combination of
+     * {@link #FLAG_HAS_LOCAL_HOUR} and {@link #FLAG_HAS_LOCAL_MINUTE}.
+     */
+    private static int findClockInHierarchy(View view) {
+        if (view instanceof TextClock) {
+            return getClockFlags((TextClock) view);
+        } else if (view instanceof ViewGroup) {
+            int flags = 0;
+            final ViewGroup group = (ViewGroup) view;
+            final int size = group.getChildCount();
+            for (int i = 0; i < size; i++) {
+                flags |= findClockInHierarchy(group.getChildAt(i));
+            }
+            return flags;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Return combination of {@link #FLAG_HAS_LOCAL_HOUR} and
+     * {@link #FLAG_HAS_LOCAL_MINUTE} describing the time represented described
+     * by the given {@link TextClock}.
+     */
+    private static int getClockFlags(TextClock clock) {
+        int flags = 0;
+
+        final String timeZone = clock.getTimeZone();
+        if (timeZone != null && !TimeZone.getDefault().equals(TimeZone.getTimeZone(timeZone))) {
+            // Ignore clocks showing another timezone
+            return 0;
+        }
+
+        final CharSequence format = clock.getFormat();
+        final char hour = clock.is24HourModeEnabled() ? DateFormat.HOUR_OF_DAY
+                : DateFormat.HOUR;
+
+        if (DateFormat.hasDesignator(format, hour)) {
+            flags |= FLAG_HAS_LOCAL_HOUR;
+        }
+        if (DateFormat.hasDesignator(format, DateFormat.MINUTE)) {
+            flags |= FLAG_HAS_LOCAL_MINUTE;
+        }
+
+        return flags;
+    }
+
+    public void handleExternalCameraEvent(MotionEvent event) {
+        beginCameraEvent();
+        int cameraPage = getPageCount() - 1;
+        boolean endWarp = false;
+        if (isCameraPage(cameraPage) || mCameraEventInProgress) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    // Once we start dispatching camera events, we must continue to do so
+                    // to keep event dispatch happy.
+                    mCameraEventInProgress = true;
+                    userActivity();
+                    startWarp(cameraPage);
+                    break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mCameraEventInProgress = false;
+                    endWarp = true;
+                    break;
+            }
+            dispatchTouchEvent(event);
+            // This has to happen after the event has been handled by the real widget pager
+            if (endWarp) endWarp();
+        }
+        endCameraEvent();
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/LiftToActivateListener.java b/packages/Keyguard/src/com/android/keyguard/LiftToActivateListener.java
new file mode 100644
index 0000000..e59602b
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/LiftToActivateListener.java
@@ -0,0 +1,71 @@
+/*
+ * 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.keyguard;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+/**
+ * Hover listener that implements lift-to-activate interaction for
+ * accessibility. May be added to multiple views.
+ */
+class LiftToActivateListener implements View.OnHoverListener {
+    /** Manager used to query accessibility enabled state. */
+    private final AccessibilityManager mAccessibilityManager;
+
+    private boolean mCachedClickableState;
+
+    public LiftToActivateListener(Context context) {
+        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+    }
+
+    @Override
+    public boolean onHover(View v, MotionEvent event) {
+        // When touch exploration is turned on, lifting a finger while
+        // inside the view bounds should perform a click action.
+        if (mAccessibilityManager.isEnabled()
+                && mAccessibilityManager.isTouchExplorationEnabled()) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_HOVER_ENTER:
+                    // Lift-to-type temporarily disables double-tap
+                    // activation by setting the view as not clickable.
+                    mCachedClickableState = v.isClickable();
+                    v.setClickable(false);
+                    break;
+                case MotionEvent.ACTION_HOVER_EXIT:
+                    final int x = (int) event.getX();
+                    final int y = (int) event.getY();
+                    if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
+                            && (x < v.getWidth() - v.getPaddingRight())
+                            && (y < v.getHeight() - v.getPaddingBottom())) {
+                        v.performClick();
+                    }
+                    v.setClickable(mCachedClickableState);
+                    break;
+            }
+        }
+
+        // Pass the event to View.onHoverEvent() to handle accessibility.
+        v.onHoverEvent(event);
+
+        // Consume the event so it doesn't fall through to other views.
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/packages/Keyguard/src/com/android/keyguard/MultiPaneChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/MultiPaneChallengeLayout.java
new file mode 100644
index 0000000..67d0d5a
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/MultiPaneChallengeLayout.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.widget.LinearLayout;
+
+public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayout {
+    private static final String TAG = "MultiPaneChallengeLayout";
+
+    final int mOrientation;
+    private boolean mIsBouncing;
+
+    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+    public static final int VERTICAL = LinearLayout.VERTICAL;
+    public static final int ANIMATE_BOUNCE_DURATION = 350;
+
+    private KeyguardSecurityContainer mChallengeView;
+    private View mUserSwitcherView;
+    private View mScrimView;
+    private OnBouncerStateChangedListener mBouncerListener;
+
+    private final Rect mTempRect = new Rect();
+    private final Rect mZeroPadding = new Rect();
+    private final Rect mInsets = new Rect();
+
+    private final DisplayMetrics mDisplayMetrics;
+
+    private final OnClickListener mScrimClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            hideBouncer();
+        }
+    };
+
+    public MultiPaneChallengeLayout(Context context) {
+        this(context, null);
+    }
+
+    public MultiPaneChallengeLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0);
+        mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_android_orientation,
+                HORIZONTAL);
+        a.recycle();
+
+        final Resources res = getResources();
+        mDisplayMetrics = res.getDisplayMetrics();
+
+        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE);
+    }
+
+    public void setInsets(Rect insets) {
+        mInsets.set(insets);
+    }
+
+    @Override
+    public boolean isChallengeShowing() {
+        return true;
+    }
+
+    @Override
+    public boolean isChallengeOverlapping() {
+        return false;
+    }
+
+    @Override
+    public void showChallenge(boolean b) {
+    }
+
+    @Override
+    public int getBouncerAnimationDuration() {
+        return ANIMATE_BOUNCE_DURATION;
+    }
+
+    @Override
+    public void showBouncer() {
+        if (mIsBouncing) return;
+        mIsBouncing = true;
+        if (mScrimView != null) {
+            if (mChallengeView != null) {
+                mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION);
+            }
+
+            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
+            anim.setDuration(ANIMATE_BOUNCE_DURATION);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mScrimView.setVisibility(VISIBLE);
+                }
+            });
+            anim.start();
+        }
+        if (mBouncerListener != null) {
+            mBouncerListener.onBouncerStateChanged(true);
+        }
+    }
+
+    @Override
+    public void hideBouncer() {
+        if (!mIsBouncing) return;
+        mIsBouncing = false;
+        if (mScrimView != null) {
+            if (mChallengeView != null) {
+                mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION);
+            }
+
+            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
+            anim.setDuration(ANIMATE_BOUNCE_DURATION);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mScrimView.setVisibility(INVISIBLE);
+                }
+            });
+            anim.start();
+        }
+        if (mBouncerListener != null) {
+            mBouncerListener.onBouncerStateChanged(false);
+        }
+    }
+
+    @Override
+    public boolean isBouncing() {
+        return mIsBouncing;
+    }
+
+    @Override
+    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
+        mBouncerListener = listener;
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        if (mIsBouncing && child != mChallengeView) {
+            // Clear out of the bouncer if the user tries to move focus outside of
+            // the security challenge view.
+            hideBouncer();
+        }
+        super.requestChildFocus(child, focused);
+    }
+
+    void setScrimView(View scrim) {
+        if (mScrimView != null) {
+            mScrimView.setOnClickListener(null);
+        }
+        mScrimView = scrim;
+        if (mScrimView != null) {
+            mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f);
+            mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE);
+            mScrimView.setFocusable(true);
+            mScrimView.setOnClickListener(mScrimClickListener);
+        }
+    }
+
+    private int getVirtualHeight(LayoutParams lp, int height, int heightUsed) {
+        int virtualHeight = height;
+        final View root = getRootView();
+        if (root != null) {
+            // This calculation is super dodgy and relies on several assumptions.
+            // Specifically that the root of the window will be padded in for insets
+            // and that the window is LAYOUT_IN_SCREEN.
+            virtualHeight = mDisplayMetrics.heightPixels - root.getPaddingTop() - mInsets.top;
+        }
+        if (lp.childType == LayoutParams.CHILD_TYPE_WIDGET ||
+                lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
+            // Always measure the widget pager/user switcher as if there were no IME insets
+            // on the window. We want to avoid resizing widgets when possible as it can
+            // be ugly/expensive. This lets us simply clip them instead.
+            return virtualHeight - heightUsed;
+        } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
+            return height;
+        }
+        return Math.min(virtualHeight - heightUsed, height);
+    }
+
+    @Override
+    protected void onMeasure(final int widthSpec, final int heightSpec) {
+        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
+                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
+            throw new IllegalArgumentException(
+                    "MultiPaneChallengeLayout must be measured with an exact size");
+        }
+
+        final int width = MeasureSpec.getSize(widthSpec);
+        final int height = MeasureSpec.getSize(heightSpec);
+        setMeasuredDimension(width, height);
+
+        final int insetHeight = height - mInsets.top - mInsets.bottom;
+        final int insetHeightSpec = MeasureSpec.makeMeasureSpec(insetHeight, MeasureSpec.EXACTLY);
+
+        int widthUsed = 0;
+        int heightUsed = 0;
+
+        // First pass. Find the challenge view and measure the user switcher,
+        // which consumes space in the layout.
+        mChallengeView = null;
+        mUserSwitcherView = null;
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
+                if (mChallengeView != null) {
+                    throw new IllegalStateException(
+                            "There may only be one child of type challenge");
+                }
+                if (!(child instanceof KeyguardSecurityContainer)) {
+                    throw new IllegalArgumentException(
+                            "Challenge must be a KeyguardSecurityContainer");
+                }
+                mChallengeView = (KeyguardSecurityContainer) child;
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
+                if (mUserSwitcherView != null) {
+                    throw new IllegalStateException(
+                            "There may only be one child of type userSwitcher");
+                }
+                mUserSwitcherView = child;
+
+                if (child.getVisibility() == GONE) continue;
+
+                int adjustedWidthSpec = widthSpec;
+                int adjustedHeightSpec = insetHeightSpec;
+                if (lp.maxWidth >= 0) {
+                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+                            Math.min(lp.maxWidth, width), MeasureSpec.EXACTLY);
+                }
+                if (lp.maxHeight >= 0) {
+                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+                            Math.min(lp.maxHeight, insetHeight), MeasureSpec.EXACTLY);
+                }
+                // measureChildWithMargins will resolve layout direction for the LayoutParams
+                measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
+
+                // Only subtract out space from one dimension. Favor vertical.
+                // Offset by 1.5x to add some balance along the other edge.
+                if (Gravity.isVertical(lp.gravity)) {
+                    heightUsed += child.getMeasuredHeight() * 1.5f;
+                } else if (Gravity.isHorizontal(lp.gravity)) {
+                    widthUsed += child.getMeasuredWidth() * 1.5f;
+                }
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
+                setScrimView(child);
+                child.measure(widthSpec, heightSpec);
+            }
+        }
+
+        // Second pass. Measure everything that's left.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER ||
+                    lp.childType == LayoutParams.CHILD_TYPE_SCRIM ||
+                    child.getVisibility() == GONE) {
+                // Don't need to measure GONE children, and the user switcher was already measured.
+                continue;
+            }
+
+            final int virtualHeight = getVirtualHeight(lp, insetHeight, heightUsed);
+
+            int adjustedWidthSpec;
+            int adjustedHeightSpec;
+            if (lp.centerWithinArea > 0) {
+                if (mOrientation == HORIZONTAL) {
+                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+                            (int) ((width - widthUsed) * lp.centerWithinArea + 0.5f),
+                            MeasureSpec.EXACTLY);
+                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+                            virtualHeight, MeasureSpec.EXACTLY);
+                } else {
+                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+                            width - widthUsed, MeasureSpec.EXACTLY);
+                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+                            (int) (virtualHeight * lp.centerWithinArea + 0.5f),
+                            MeasureSpec.EXACTLY);
+                }
+            } else {
+                adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+                        width - widthUsed, MeasureSpec.EXACTLY);
+                adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+                        virtualHeight, MeasureSpec.EXACTLY);
+            }
+            if (lp.maxWidth >= 0) {
+                adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+                        Math.min(lp.maxWidth, MeasureSpec.getSize(adjustedWidthSpec)),
+                        MeasureSpec.EXACTLY);
+            }
+            if (lp.maxHeight >= 0) {
+                adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+                        Math.min(lp.maxHeight, MeasureSpec.getSize(adjustedHeightSpec)),
+                        MeasureSpec.EXACTLY);
+            }
+
+            measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final Rect padding = mTempRect;
+        padding.left = getPaddingLeft();
+        padding.top = getPaddingTop();
+        padding.right = getPaddingRight();
+        padding.bottom = getPaddingBottom();
+        final int width = r - l;
+        final int height = b - t;
+        final int insetHeight = height - mInsets.top - mInsets.bottom;
+
+        // Reserve extra space in layout for the user switcher by modifying
+        // local padding during this layout pass
+        if (mUserSwitcherView != null && mUserSwitcherView.getVisibility() != GONE) {
+            layoutWithGravity(width, insetHeight, mUserSwitcherView, padding, true);
+        }
+
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            // We did the user switcher above if we have one.
+            if (child == mUserSwitcherView || child.getVisibility() == GONE) continue;
+
+            if (child == mScrimView) {
+                child.layout(0, 0, width, height);
+                continue;
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
+                layoutWithGravity(width, insetHeight, child, mZeroPadding, false);
+                continue;
+            }
+
+            layoutWithGravity(width, insetHeight, child, padding, false);
+        }
+    }
+
+    private void layoutWithGravity(int width, int height, View child, Rect padding,
+            boolean adjustPadding) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+        final int heightUsed = padding.top + padding.bottom - getPaddingTop() - getPaddingBottom();
+        height = getVirtualHeight(lp, height, heightUsed);
+
+        final int gravity = Gravity.getAbsoluteGravity(lp.gravity, getLayoutDirection());
+
+        final boolean fixedLayoutSize = lp.centerWithinArea > 0;
+        final boolean fixedLayoutHorizontal = fixedLayoutSize && mOrientation == HORIZONTAL;
+        final boolean fixedLayoutVertical = fixedLayoutSize && mOrientation == VERTICAL;
+
+        final int adjustedWidth;
+        final int adjustedHeight;
+        if (fixedLayoutHorizontal) {
+            final int paddedWidth = width - padding.left - padding.right;
+            adjustedWidth = (int) (paddedWidth * lp.centerWithinArea + 0.5f);
+            adjustedHeight = height;
+        } else if (fixedLayoutVertical) {
+            final int paddedHeight = height - getPaddingTop() - getPaddingBottom();
+            adjustedWidth = width;
+            adjustedHeight = (int) (paddedHeight * lp.centerWithinArea + 0.5f);
+        } else {
+            adjustedWidth = width;
+            adjustedHeight = height;
+        }
+
+        final boolean isVertical = Gravity.isVertical(gravity);
+        final boolean isHorizontal = Gravity.isHorizontal(gravity);
+        final int childWidth = child.getMeasuredWidth();
+        final int childHeight = child.getMeasuredHeight();
+
+        int left = padding.left;
+        int top = padding.top;
+        int right = left + childWidth;
+        int bottom = top + childHeight;
+        switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
+            case Gravity.TOP:
+                top = fixedLayoutVertical ?
+                        padding.top + (adjustedHeight - childHeight) / 2 : padding.top;
+                bottom = top + childHeight;
+                if (adjustPadding && isVertical) {
+                    padding.top = bottom;
+                    padding.bottom += childHeight / 2;
+                }
+                break;
+            case Gravity.BOTTOM:
+                bottom = fixedLayoutVertical
+                        ? padding.top + height - (adjustedHeight - childHeight) / 2
+                        : padding.top + height;
+                top = bottom - childHeight;
+                if (adjustPadding && isVertical) {
+                    padding.bottom = height - top;
+                    padding.top += childHeight / 2;
+                }
+                break;
+            case Gravity.CENTER_VERTICAL:
+                top = padding.top + (height - childHeight) / 2;
+                bottom = top + childHeight;
+                break;
+        }
+        switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+            case Gravity.LEFT:
+                left = fixedLayoutHorizontal ?
+                        padding.left + (adjustedWidth - childWidth) / 2 : padding.left;
+                right = left + childWidth;
+                if (adjustPadding && isHorizontal && !isVertical) {
+                    padding.left = right;
+                    padding.right += childWidth / 2;
+                }
+                break;
+            case Gravity.RIGHT:
+                right = fixedLayoutHorizontal
+                        ? width - padding.right - (adjustedWidth - childWidth) / 2
+                        : width - padding.right;
+                left = right - childWidth;
+                if (adjustPadding && isHorizontal && !isVertical) {
+                    padding.right = width - left;
+                    padding.left += childWidth / 2;
+                }
+                break;
+            case Gravity.CENTER_HORIZONTAL:
+                final int paddedWidth = width - padding.left - padding.right;
+                left = (paddedWidth - childWidth) / 2;
+                right = left + childWidth;
+                break;
+        }
+        top += mInsets.top;
+        bottom += mInsets.top;
+        child.layout(left, top, right, bottom);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs, this);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
+                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
+                new LayoutParams(p);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    public static class LayoutParams extends MarginLayoutParams {
+
+        public float centerWithinArea = 0;
+
+        public int childType = 0;
+
+        public static final int CHILD_TYPE_NONE = 0;
+        public static final int CHILD_TYPE_WIDGET = 1;
+        public static final int CHILD_TYPE_CHALLENGE = 2;
+        public static final int CHILD_TYPE_USER_SWITCHER = 3;
+        public static final int CHILD_TYPE_SCRIM = 4;
+        public static final int CHILD_TYPE_PAGE_DELETE_DROP_TARGET = 7;
+
+        public int gravity = Gravity.NO_GRAVITY;
+
+        public int maxWidth = -1;
+        public int maxHeight = -1;
+
+        public LayoutParams() {
+            this(WRAP_CONTENT, WRAP_CONTENT);
+        }
+
+        LayoutParams(Context c, AttributeSet attrs, MultiPaneChallengeLayout parent) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs,
+                    R.styleable.MultiPaneChallengeLayout_Layout);
+
+            centerWithinArea = a.getFloat(
+                    R.styleable.MultiPaneChallengeLayout_Layout_layout_centerWithinArea, 0);
+            childType = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_childType,
+                    CHILD_TYPE_NONE);
+            gravity = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_gravity,
+                    Gravity.NO_GRAVITY);
+            maxWidth = a.getDimensionPixelSize(
+                    R.styleable.MultiPaneChallengeLayout_Layout_layout_maxWidth, -1);
+            maxHeight = a.getDimensionPixelSize(
+                    R.styleable.MultiPaneChallengeLayout_Layout_layout_maxHeight, -1);
+
+            // Default gravity settings based on type and parent orientation
+            if (gravity == Gravity.NO_GRAVITY) {
+                if (parent.mOrientation == HORIZONTAL) {
+                    switch (childType) {
+                        case CHILD_TYPE_WIDGET:
+                            gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
+                            break;
+                        case CHILD_TYPE_CHALLENGE:
+                            gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+                            break;
+                        case CHILD_TYPE_USER_SWITCHER:
+                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+                            break;
+                    }
+                } else {
+                    switch (childType) {
+                        case CHILD_TYPE_WIDGET:
+                            gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+                            break;
+                        case CHILD_TYPE_CHALLENGE:
+                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+                            break;
+                        case CHILD_TYPE_USER_SWITCHER:
+                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+                            break;
+                    }
+                }
+            }
+
+            a.recycle();
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            this((MarginLayoutParams) source);
+
+            centerWithinArea = source.centerWithinArea;
+            childType = source.childType;
+            gravity = source.gravity;
+            maxWidth = source.maxWidth;
+            maxHeight = source.maxHeight;
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java b/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
new file mode 100644
index 0000000..9930e72
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
@@ -0,0 +1,42 @@
+/*
+ * 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.keyguard;
+
+import android.graphics.drawable.Drawable;
+
+import java.util.HashMap;
+
+public class MultiUserAvatarCache {
+
+    private final HashMap<Integer, Drawable> mCache;
+
+    public MultiUserAvatarCache() {
+        mCache = new HashMap<Integer, Drawable>();
+    }
+
+    public void clear(int userId) {
+        mCache.remove(userId);
+    }
+
+    public Drawable get(int userId) {
+        return mCache.get(userId);
+    }
+
+    public void put(int userId, Drawable image) {
+        mCache.put(userId, image);
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
new file mode 100644
index 0000000..532670f
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.text.SpannableStringBuilder;
+import android.text.style.TextAppearanceSpan;
+import android.util.AttributeSet;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class NumPadKey extends Button {
+    // list of "ABC", etc per digit, starting with '0'
+    static String sKlondike[];
+
+    int mDigit = -1;
+    int mTextViewResId;
+    TextView mTextView = null;
+    boolean mEnableHaptics;
+
+    private View.OnClickListener mListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View thisView) {
+            if (mTextView == null) {
+                if (mTextViewResId > 0) {
+                    final View v = NumPadKey.this.getRootView().findViewById(mTextViewResId);
+                    if (v != null && v instanceof TextView) {
+                        mTextView = (TextView) v;
+                    }
+                }
+            }
+            // check for time-based lockouts
+            if (mTextView != null && mTextView.isEnabled()) {
+                mTextView.append(String.valueOf(mDigit));
+            }
+            doHapticKeyClick();
+        }
+    };
+
+    public NumPadKey(Context context) {
+        this(context, null);
+    }
+
+    public NumPadKey(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NumPadKey(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey);
+        mDigit = a.getInt(R.styleable.NumPadKey_digit, mDigit);
+        setTextViewResId(a.getResourceId(R.styleable.NumPadKey_textView, 0));
+
+        setOnClickListener(mListener);
+        setOnHoverListener(new LiftToActivateListener(context));
+        setAccessibilityDelegate(new ObscureSpeechDelegate(context));
+
+        mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
+
+        SpannableStringBuilder builder = new SpannableStringBuilder();
+        builder.append(String.valueOf(mDigit));
+        if (mDigit >= 0) {
+            if (sKlondike == null) {
+                sKlondike = context.getResources().getStringArray(
+                        R.array.lockscreen_num_pad_klondike);
+            }
+            if (sKlondike != null && sKlondike.length > mDigit) {
+                final String extra = sKlondike[mDigit];
+                final int extraLen = extra.length();
+                if (extraLen > 0) {
+                    builder.append(" ");
+                    builder.append(extra);
+                    builder.setSpan(
+                        new TextAppearanceSpan(context, R.style.TextAppearance_NumPadKey_Klondike),
+                        builder.length()-extraLen, builder.length(), 0);
+                }
+            }
+        }
+        setText(builder);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        // Reset the "announced headset" flag when detached.
+        ObscureSpeechDelegate.sAnnouncedHeadset = false;
+    }
+
+    public void setTextView(TextView tv) {
+        mTextView = tv;
+    }
+
+    public void setTextViewResId(int resId) {
+        mTextView = null;
+        mTextViewResId = resId;
+    }
+
+    // Cause a VIRTUAL_KEY vibration
+    public void doHapticKeyClick() {
+        if (mEnableHaptics) {
+            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
+                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/ObscureSpeechDelegate.java b/packages/Keyguard/src/com/android/keyguard/ObscureSpeechDelegate.java
new file mode 100644
index 0000000..573122a
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/ObscureSpeechDelegate.java
@@ -0,0 +1,101 @@
+/*
+ * 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.keyguard;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.AudioManager;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.internal.R;
+
+/**
+ * Accessibility delegate that obscures speech for a view when the user has
+ * not turned on the "speak passwords" preference and is not listening
+ * through headphones.
+ */
+class ObscureSpeechDelegate extends AccessibilityDelegate {
+    /** Whether any client has announced the "headset" notification. */
+    static boolean sAnnouncedHeadset = false;
+
+    private final ContentResolver mContentResolver;
+    private final AudioManager mAudioManager;
+
+    public ObscureSpeechDelegate(Context context) {
+        mContentResolver = context.getContentResolver();
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    @Override
+    public void sendAccessibilityEvent(View host, int eventType) {
+        super.sendAccessibilityEvent(host, eventType);
+
+        // Play the "headset required" announcement the first time the user
+        // places accessibility focus on a key.
+        if ((eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED)
+                && !sAnnouncedHeadset && shouldObscureSpeech()) {
+            sAnnouncedHeadset = true;
+            host.announceForAccessibility(host.getContext().getString(
+                    R.string.keyboard_headset_required_to_hear_password));
+        }
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(host, event);
+
+        if ((event.getEventType() != AccessibilityEvent.TYPE_ANNOUNCEMENT)
+                && shouldObscureSpeech()) {
+            event.getText().clear();
+            event.setContentDescription(host.getContext().getString(
+                    R.string.keyboard_password_character_no_headset));
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(host, info);
+
+        if (shouldObscureSpeech()) {
+            final Context ctx = host.getContext();
+            info.setText(null);
+            info.setContentDescription(
+                    ctx.getString(R.string.keyboard_password_character_no_headset));
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private boolean shouldObscureSpeech() {
+        // The user can optionally force speaking passwords.
+        if (Settings.Secure.getInt(mContentResolver,
+                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0) {
+            return false;
+        }
+
+        // Always speak if the user is listening through headphones.
+        if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) {
+            return false;
+        }
+
+        // Don't speak since this key is used to type a password.
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
new file mode 100644
index 0000000..666227c
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -0,0 +1,2709 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.Scroller;
+
+import java.util.ArrayList;
+
+/**
+ * An abstraction of the original Workspace which supports browsing through a
+ * sequential list of "pages"
+ */
+public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
+    private static final String TAG = "WidgetPagedView";
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_WARP = false;
+    protected static final int INVALID_PAGE = -1;
+    private static final int WARP_PEEK_ANIMATION_DURATION = 250;
+    private static final float WARP_ANIMATE_AMOUNT = -40.0f; // in dip
+
+    // the min drag distance for a fling to register, to prevent random page shifts
+    private static final int MIN_LENGTH_FOR_FLING = 25;
+
+    protected static final int PAGE_SNAP_ANIMATION_DURATION = 750;
+    protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
+    protected static final float NANOTIME_DIV = 1000000000.0f;
+
+    private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
+    private static final float OVERSCROLL_DAMP_FACTOR = 0.14f;
+
+    private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
+    // The page is moved more than halfway, automatically move to the next page on touch up.
+    private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
+
+    // The following constants need to be scaled based on density. The scaled versions will be
+    // assigned to the corresponding member variables below.
+    private static final int FLING_THRESHOLD_VELOCITY = 500;
+    private static final int MIN_SNAP_VELOCITY = 1500;
+    private static final int MIN_FLING_VELOCITY = 250;
+
+    // We are disabling touch interaction of the widget region for factory ROM.
+    private static final boolean DISABLE_TOUCH_INTERACTION = false;
+    private static final boolean DISABLE_TOUCH_SIDE_PAGES = true;
+    private static final boolean DISABLE_FLING_TO_DELETE = false;
+
+    static final int AUTOMATIC_PAGE_SPACING = -1;
+
+    protected int mFlingThresholdVelocity;
+    protected int mMinFlingVelocity;
+    protected int mMinSnapVelocity;
+
+    protected float mDensity;
+    protected float mSmoothingTime;
+    protected float mTouchX;
+
+    protected boolean mFirstLayout = true;
+
+    protected int mCurrentPage;
+    protected int mChildCountOnLastMeasure;
+
+    protected int mNextPage = INVALID_PAGE;
+    protected int mMaxScrollX;
+    protected Scroller mScroller;
+    private VelocityTracker mVelocityTracker;
+
+    private float mParentDownMotionX;
+    private float mParentDownMotionY;
+    private float mDownMotionX;
+    private float mDownMotionY;
+    private float mDownScrollX;
+    protected float mLastMotionX;
+    protected float mLastMotionXRemainder;
+    protected float mLastMotionY;
+    protected float mTotalMotionX;
+    private int mLastScreenCenter = -1;
+    private int[] mChildOffsets;
+    private int[] mChildRelativeOffsets;
+    private int[] mChildOffsetsWithLayoutScale;
+    private String mDeleteString; // Accessibility announcement when widget is deleted
+
+    protected final static int TOUCH_STATE_REST = 0;
+    protected final static int TOUCH_STATE_SCROLLING = 1;
+    protected final static int TOUCH_STATE_PREV_PAGE = 2;
+    protected final static int TOUCH_STATE_NEXT_PAGE = 3;
+    protected final static int TOUCH_STATE_REORDERING = 4;
+
+    protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
+    protected final static float TOUCH_SLOP_SCALE = 1.0f;
+
+    protected int mTouchState = TOUCH_STATE_REST;
+    protected boolean mForceScreenScrolled = false;
+
+    protected OnLongClickListener mLongClickListener;
+
+    protected int mTouchSlop;
+    private int mPagingTouchSlop;
+    private int mMaximumVelocity;
+    private int mMinimumWidth;
+    protected int mPageSpacing;
+    protected int mCellCountX = 0;
+    protected int mCellCountY = 0;
+    protected boolean mAllowOverScroll = true;
+    protected int mUnboundedScrollX;
+    protected int[] mTempVisiblePagesRange = new int[2];
+    protected boolean mForceDrawAllChildrenNextFrame;
+
+    // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
+    // it is equal to the scaled overscroll position. We use a separate value so as to prevent
+    // the screens from continuing to translate beyond the normal bounds.
+    protected int mOverScrollX;
+
+    // parameter that adjusts the layout to be optimized for pages with that scale factor
+    protected float mLayoutScale = 1.0f;
+
+    protected static final int INVALID_POINTER = -1;
+
+    protected int mActivePointerId = INVALID_POINTER;
+
+    private PageSwitchListener mPageSwitchListener;
+
+    protected ArrayList<Boolean> mDirtyPageContent;
+
+    // If true, syncPages and syncPageItems will be called to refresh pages
+    protected boolean mContentIsRefreshable = true;
+
+    // If true, modify alpha of neighboring pages as user scrolls left/right
+    protected boolean mFadeInAdjacentScreens = false;
+
+    // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
+    // to switch to a new page
+    protected boolean mUsePagingTouchSlop = true;
+
+    // If true, the subclass should directly update scrollX itself in its computeScroll method
+    // (SmoothPagedView does this)
+    protected boolean mDeferScrollUpdate = false;
+
+    protected boolean mIsPageMoving = false;
+
+    // All syncs and layout passes are deferred until data is ready.
+    protected boolean mIsDataReady = true;
+
+    // Scrolling indicator
+    private ValueAnimator mScrollIndicatorAnimator;
+    private View mScrollIndicator;
+    private int mScrollIndicatorPaddingLeft;
+    private int mScrollIndicatorPaddingRight;
+    private boolean mShouldShowScrollIndicator = false;
+    private boolean mShouldShowScrollIndicatorImmediately = false;
+    protected static final int sScrollIndicatorFadeInDuration = 150;
+    protected static final int sScrollIndicatorFadeOutDuration = 650;
+    protected static final int sScrollIndicatorFlashDuration = 650;
+
+    // The viewport whether the pages are to be contained (the actual view may be larger than the
+    // viewport)
+    private Rect mViewport = new Rect();
+
+    // Reordering
+    // We use the min scale to determine how much to expand the actually PagedView measured
+    // dimensions such that when we are zoomed out, the view is not clipped
+    private int REORDERING_DROP_REPOSITION_DURATION = 200;
+    protected int REORDERING_REORDER_REPOSITION_DURATION = 300;
+    protected int REORDERING_ZOOM_IN_OUT_DURATION = 250;
+    private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300;
+    private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f;
+    private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150;
+    private float mMinScale = 1f;
+    protected View mDragView;
+    protected AnimatorSet mZoomInOutAnim;
+    private Runnable mSidePageHoverRunnable;
+    private int mSidePageHoverIndex = -1;
+    // This variable's scope is only for the duration of startReordering() and endReordering()
+    private boolean mReorderingStarted = false;
+    // This variable's scope is for the duration of startReordering() and after the zoomIn()
+    // animation after endReordering()
+    private boolean mIsReordering;
+    // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition
+    private int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2;
+    private int mPostReorderingPreZoomInRemainingAnimationCount;
+    private Runnable mPostReorderingPreZoomInRunnable;
+
+    // Edge swiping
+    private boolean mOnlyAllowEdgeSwipes = false;
+    private boolean mDownEventOnEdge = false;
+    private int mEdgeSwipeRegionSize = 0;
+
+    // Convenience/caching
+    private Matrix mTmpInvMatrix = new Matrix();
+    private float[] mTmpPoint = new float[2];
+    private Rect mTmpRect = new Rect();
+    private Rect mAltTmpRect = new Rect();
+
+    // Fling to delete
+    private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
+    private float FLING_TO_DELETE_FRICTION = 0.035f;
+    // The degrees specifies how much deviation from the up vector to still consider a fling "up"
+    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
+    protected int mFlingToDeleteThresholdVelocity = -1400;
+    // Drag to delete
+    private boolean mDeferringForDelete = false;
+    private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
+    private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
+
+    // Drop to delete
+    private View mDeleteDropTarget;
+
+    // Bouncer
+    private boolean mTopAlignPageWhenShrinkingForBouncer = false;
+
+    // Page warping
+    private int mPageSwapIndex = -1; // the page we swapped out if needed
+    private int mPageWarpIndex = -1; // the page we intend to warp
+
+    private boolean mIsCameraEvent;
+    private float mWarpPeekAmount;
+
+    public interface PageSwitchListener {
+        void onPageSwitching(View newPage, int newPageIndex);
+        void onPageSwitched(View newPage, int newPageIndex);
+    }
+
+    public PagedView(Context context) {
+        this(context, null);
+    }
+
+    public PagedView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public PagedView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.PagedView, defStyle, 0);
+        setPageSpacing(a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0));
+        mScrollIndicatorPaddingLeft =
+            a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingLeft, 0);
+        mScrollIndicatorPaddingRight =
+                a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0);
+        a.recycle();
+
+        Resources r = getResources();
+        mEdgeSwipeRegionSize = r.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
+        mTopAlignPageWhenShrinkingForBouncer =
+                r.getBoolean(R.bool.kg_top_align_page_shrink_on_bouncer_visible);
+
+        setHapticFeedbackEnabled(false);
+        init();
+    }
+
+    /**
+     * Initializes various states for this workspace.
+     */
+    protected void init() {
+        mDirtyPageContent = new ArrayList<Boolean>();
+        mDirtyPageContent.ensureCapacity(32);
+        mScroller = new Scroller(getContext(), new ScrollInterpolator());
+        mCurrentPage = 0;
+
+        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+        mDensity = getResources().getDisplayMetrics().density;
+        mWarpPeekAmount = mDensity * WARP_ANIMATE_AMOUNT;
+
+        // Scale the fling-to-delete threshold by the density
+        mFlingToDeleteThresholdVelocity = (int) (mFlingToDeleteThresholdVelocity * mDensity);
+
+        mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
+        mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
+        mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
+        setOnHierarchyChangeListener(this);
+    }
+
+    void setDeleteDropTarget(View v) {
+        mDeleteDropTarget = v;
+    }
+
+    // Convenience methods to map points from self to parent and vice versa
+    float[] mapPointFromViewToParent(View v, float x, float y) {
+        mTmpPoint[0] = x;
+        mTmpPoint[1] = y;
+        v.getMatrix().mapPoints(mTmpPoint);
+        mTmpPoint[0] += v.getLeft();
+        mTmpPoint[1] += v.getTop();
+        return mTmpPoint;
+    }
+    float[] mapPointFromParentToView(View v, float x, float y) {
+        mTmpPoint[0] = x - v.getLeft();
+        mTmpPoint[1] = y - v.getTop();
+        v.getMatrix().invert(mTmpInvMatrix);
+        mTmpInvMatrix.mapPoints(mTmpPoint);
+        return mTmpPoint;
+    }
+
+    void updateDragViewTranslationDuringDrag() {
+        float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX;
+        float y = mLastMotionY - mDownMotionY;
+        mDragView.setTranslationX(x);
+        mDragView.setTranslationY(y);
+
+        if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y);
+    }
+
+    public void setMinScale(float f) {
+        mMinScale = f;
+        requestLayout();
+    }
+
+    @Override
+    public void setScaleX(float scaleX) {
+        super.setScaleX(scaleX);
+        if (isReordering(true)) {
+            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
+            mLastMotionX = p[0];
+            mLastMotionY = p[1];
+            updateDragViewTranslationDuringDrag();
+        }
+    }
+
+    // Convenience methods to get the actual width/height of the PagedView (since it is measured
+    // to be larger to account for the minimum possible scale)
+    int getViewportWidth() {
+        return mViewport.width();
+    }
+    int getViewportHeight() {
+        return mViewport.height();
+    }
+
+    // Convenience methods to get the offset ASSUMING that we are centering the pages in the
+    // PagedView both horizontally and vertically
+    int getViewportOffsetX() {
+        return (getMeasuredWidth() - getViewportWidth()) / 2;
+    }
+    int getViewportOffsetY() {
+        return (getMeasuredHeight() - getViewportHeight()) / 2;
+    }
+
+    public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
+        mPageSwitchListener = pageSwitchListener;
+        if (mPageSwitchListener != null) {
+            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
+        }
+    }
+
+    /**
+     * Called by subclasses to mark that data is ready, and that we can begin loading and laying
+     * out pages.
+     */
+    protected void setDataIsReady() {
+        mIsDataReady = true;
+    }
+
+    protected boolean isDataReady() {
+        return mIsDataReady;
+    }
+
+    /**
+     * Returns the index of the currently displayed page.
+     *
+     * @return The index of the currently displayed page.
+     */
+    int getCurrentPage() {
+        return mCurrentPage;
+    }
+
+    int getNextPage() {
+        return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
+    }
+
+    int getPageCount() {
+        return getChildCount();
+    }
+
+    View getPageAt(int index) {
+        return getChildAt(index);
+    }
+
+    protected int indexToPage(int index) {
+        return index;
+    }
+
+    /**
+     * Updates the scroll of the current page immediately to its final scroll position.  We use this
+     * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
+     * the previous tab page.
+     */
+    protected void updateCurrentPageScroll() {
+        int offset = getChildOffset(mCurrentPage);
+        int relOffset = getRelativeChildOffset(mCurrentPage);
+        int newX = offset - relOffset;
+        scrollTo(newX, 0);
+        mScroller.setFinalX(newX);
+        mScroller.forceFinished(true);
+    }
+
+    /**
+     * Sets the current page.
+     */
+    void setCurrentPage(int currentPage) {
+        notifyPageSwitching(currentPage);
+        if (!mScroller.isFinished()) {
+            mScroller.abortAnimation();
+        }
+        // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
+        // the default
+        if (getChildCount() == 0) {
+            return;
+        }
+
+        mForceScreenScrolled = true;
+        mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
+        updateCurrentPageScroll();
+        updateScrollingIndicator();
+        notifyPageSwitched();
+        invalidate();
+    }
+
+    public void setOnlyAllowEdgeSwipes(boolean enable) {
+        mOnlyAllowEdgeSwipes = enable;
+    }
+
+    protected void notifyPageSwitching(int whichPage) {
+        if (mPageSwitchListener != null) {
+            mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage);
+        }
+    }
+
+    protected void notifyPageSwitched() {
+        if (mPageSwitchListener != null) {
+            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
+        }
+    }
+
+    protected void pageBeginMoving() {
+        if (DEBUG_WARP) Log.v(TAG, "pageBeginMoving(" + mIsPageMoving + ")");
+        if (!mIsPageMoving) {
+            mIsPageMoving = true;
+            if (mPageWarpIndex != -1) {
+                onPageBeginWarp();
+                if (mPageSwapIndex != -1) {
+                    swapPages(mPageSwapIndex, mPageWarpIndex);
+                }
+            }
+            onPageBeginMoving();
+        }
+    }
+
+    protected void pageEndMoving() {
+        if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")");
+        if (mIsPageMoving) {
+            mIsPageMoving = false;
+            if (mPageWarpIndex != -1) {
+                if (mPageSwapIndex != -1) {
+                    swapPages(mPageSwapIndex, mPageWarpIndex);
+                    resetPageWarp();
+                }
+                onPageEndWarp();
+            }
+            onPageEndMoving();
+        }
+    }
+
+    private void resetPageWarp() {
+        // TODO: Verify pages have been reset correctly
+        mPageSwapIndex = -1;
+        mPageWarpIndex = -1;
+    }
+
+    protected boolean isPageMoving() {
+        return mIsPageMoving;
+    }
+
+    // a method that subclasses can override to add behavior
+    protected void onPageBeginMoving() {
+    }
+
+    // a method that subclasses can override to add behavior
+    protected void onPageEndMoving() {
+    }
+
+    /**
+     * Registers the specified listener on each page contained in this workspace.
+     *
+     * @param l The listener used to respond to long clicks.
+     */
+    @Override
+    public void setOnLongClickListener(OnLongClickListener l) {
+        mLongClickListener = l;
+        final int count = getPageCount();
+        for (int i = 0; i < count; i++) {
+            getPageAt(i).setOnLongClickListener(l);
+        }
+    }
+
+    @Override
+    public void scrollBy(int x, int y) {
+        scrollTo(mUnboundedScrollX + x, getScrollY() + y);
+    }
+
+    @Override
+    public void scrollTo(int x, int y) {
+        mUnboundedScrollX = x;
+
+        if (x < 0) {
+            super.scrollTo(0, y);
+            if (mAllowOverScroll) {
+                overScroll(x);
+            }
+        } else if (x > mMaxScrollX) {
+            super.scrollTo(mMaxScrollX, y);
+            if (mAllowOverScroll) {
+                overScroll(x - mMaxScrollX);
+            }
+        } else {
+            mOverScrollX = x;
+            super.scrollTo(x, y);
+        }
+
+        mTouchX = x;
+        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+
+        // Update the last motion events when scrolling
+        if (isReordering(true)) {
+            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
+            mLastMotionX = p[0];
+            mLastMotionY = p[1];
+            updateDragViewTranslationDuringDrag();
+        }
+    }
+
+    // we moved this functionality to a helper function so SmoothPagedView can reuse it
+    protected boolean computeScrollHelper() {
+        if (mScroller.computeScrollOffset()) {
+            // Don't bother scrolling if the page does not need to be moved
+            if (getScrollX() != mScroller.getCurrX()
+                || getScrollY() != mScroller.getCurrY()
+                || mOverScrollX != mScroller.getCurrX()) {
+                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+            }
+            invalidate();
+            return true;
+        } else if (mNextPage != INVALID_PAGE) {
+            mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
+            mNextPage = INVALID_PAGE;
+            notifyPageSwitched();
+
+            // We don't want to trigger a page end moving unless the page has settled
+            // and the user has stopped scrolling
+            if (mTouchState == TOUCH_STATE_REST) {
+                pageEndMoving();
+            }
+
+            onPostReorderingAnimationCompleted();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void computeScroll() {
+        computeScrollHelper();
+    }
+
+    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
+        return mTopAlignPageWhenShrinkingForBouncer;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (!mIsDataReady || getChildCount() == 0) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
+        // We measure the dimensions of the PagedView to be larger than the pages so that when we
+        // zoom out (and scale down), the view is still contained in the parent
+        View parent = (View) getParent();
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+        // NOTE: We multiply by 1.5f to account for the fact that depending on the offset of the
+        // viewport, we can be at most one and a half screens offset once we scale down
+        DisplayMetrics dm = getResources().getDisplayMetrics();
+        int maxSize = Math.max(dm.widthPixels, dm.heightPixels);
+        int parentWidthSize = (int) (1.5f * maxSize);
+        int parentHeightSize = maxSize;
+        int scaledWidthSize = (int) (parentWidthSize / mMinScale);
+        int scaledHeightSize = (int) (parentHeightSize / mMinScale);
+        mViewport.set(0, 0, widthSize, heightSize);
+
+        if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
+        // Return early if we aren't given a proper dimension
+        if (widthSize <= 0 || heightSize <= 0) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
+        /* Allow the height to be set as WRAP_CONTENT. This allows the particular case
+         * of the All apps view on XLarge displays to not take up more space then it needs. Width
+         * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
+         * each page to have the same width.
+         */
+        final int verticalPadding = getPaddingTop() + getPaddingBottom();
+        final int horizontalPadding = getPaddingLeft() + getPaddingRight();
+
+        // The children are given the same width and height as the workspace
+        // unless they were set to WRAP_CONTENT
+        if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
+        if (DEBUG) Log.d(TAG, "PagedView.scaledSize: " + scaledWidthSize + ", " + scaledHeightSize);
+        if (DEBUG) Log.d(TAG, "PagedView.parentSize: " + parentWidthSize + ", " + parentHeightSize);
+        if (DEBUG) Log.d(TAG, "PagedView.horizontalPadding: " + horizontalPadding);
+        if (DEBUG) Log.d(TAG, "PagedView.verticalPadding: " + verticalPadding);
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            // disallowing padding in paged view (just pass 0)
+            final View child = getPageAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            int childWidthMode;
+            if (lp.width == LayoutParams.WRAP_CONTENT) {
+                childWidthMode = MeasureSpec.AT_MOST;
+            } else {
+                childWidthMode = MeasureSpec.EXACTLY;
+            }
+
+            int childHeightMode;
+            if (lp.height == LayoutParams.WRAP_CONTENT) {
+                childHeightMode = MeasureSpec.AT_MOST;
+            } else {
+                childHeightMode = MeasureSpec.EXACTLY;
+            }
+
+            final int childWidthMeasureSpec =
+                MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
+            final int childHeightMeasureSpec =
+                MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
+
+            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+        }
+        setMeasuredDimension(scaledWidthSize, scaledHeightSize);
+
+        // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
+        // We also wait until we set the measured dimensions before flushing the cache as well, to
+        // ensure that the cache is filled with good values.
+        invalidateCachedOffsets();
+
+        if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) {
+            setCurrentPage(mCurrentPage);
+        }
+        mChildCountOnLastMeasure = getChildCount();
+
+        if (childCount > 0) {
+            if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getViewportWidth() + ", "
+                    + getChildWidth(0));
+
+            // Calculate the variable page spacing if necessary
+            if (mPageSpacing == AUTOMATIC_PAGE_SPACING) {
+                // The gap between pages in the PagedView should be equal to the gap from the page
+                // to the edge of the screen (so it is not visible in the current screen).  To
+                // account for unequal padding on each side of the paged view, we take the maximum
+                // of the left/right gap and use that as the gap between each page.
+                int offset = getRelativeChildOffset(0);
+                int spacing = Math.max(offset, widthSize - offset -
+                        getChildAt(0).getMeasuredWidth());
+                setPageSpacing(spacing);
+            }
+        }
+
+        updateScrollingIndicatorPosition();
+
+        if (childCount > 0) {
+            mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
+        } else {
+            mMaxScrollX = 0;
+        }
+    }
+
+    public void setPageSpacing(int pageSpacing) {
+        mPageSpacing = pageSpacing;
+        invalidateCachedOffsets();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!mIsDataReady || getChildCount() == 0) {
+            return;
+        }
+
+        if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
+        final int childCount = getChildCount();
+
+        int offsetX = getViewportOffsetX();
+        int offsetY = getViewportOffsetY();
+
+        // Update the viewport offsets
+        mViewport.offset(offsetX,  offsetY);
+
+        int childLeft = offsetX + getRelativeChildOffset(0);
+        for (int i = 0; i < childCount; i++) {
+            final View child = getPageAt(i);
+            int childTop = offsetY + getPaddingTop();
+            if (child.getVisibility() != View.GONE) {
+                final int childWidth = getScaledMeasuredWidth(child);
+                final int childHeight = child.getMeasuredHeight();
+
+                if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
+                child.layout(childLeft, childTop,
+                        childLeft + child.getMeasuredWidth(), childTop + childHeight);
+                childLeft += childWidth + mPageSpacing;
+            }
+        }
+
+        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
+            setHorizontalScrollBarEnabled(false);
+            updateCurrentPageScroll();
+            setHorizontalScrollBarEnabled(true);
+            mFirstLayout = false;
+        }
+        // If a page was swapped when we rebuilt the layout, swap it again now.
+        if (mPageSwapIndex  != -1) {
+            if (DEBUG_WARP) Log.v(TAG, "onLayout: swapping pages");
+            swapPages(mPageSwapIndex, mPageWarpIndex);
+        }
+    }
+
+    protected void screenScrolled(int screenCenter) {
+    }
+
+    @Override
+    public void onChildViewAdded(View parent, View child) {
+        // This ensures that when children are added, they get the correct transforms / alphas
+        // in accordance with any scroll effects.
+        mForceScreenScrolled = true;
+        invalidate();
+        invalidateCachedOffsets();
+    }
+
+    @Override
+    public void onChildViewRemoved(View parent, View child) {
+        mForceScreenScrolled = true;
+        invalidate();
+        invalidateCachedOffsets();
+    }
+
+    protected void invalidateCachedOffsets() {
+        int count = getChildCount();
+        if (count == 0) {
+            mChildOffsets = null;
+            mChildRelativeOffsets = null;
+            mChildOffsetsWithLayoutScale = null;
+            return;
+        }
+
+        mChildOffsets = new int[count];
+        mChildRelativeOffsets = new int[count];
+        mChildOffsetsWithLayoutScale = new int[count];
+        for (int i = 0; i < count; i++) {
+            mChildOffsets[i] = -1;
+            mChildRelativeOffsets[i] = -1;
+            mChildOffsetsWithLayoutScale[i] = -1;
+        }
+    }
+
+    protected int getChildOffset(int index) {
+        if (index < 0 || index > getChildCount() - 1) return 0;
+
+        int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
+                mChildOffsets : mChildOffsetsWithLayoutScale;
+
+        if (childOffsets != null && childOffsets[index] != -1) {
+            return childOffsets[index];
+        } else {
+            if (getChildCount() == 0)
+                return 0;
+
+            int offset = getRelativeChildOffset(0);
+            for (int i = 0; i < index; ++i) {
+                offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
+            }
+            if (childOffsets != null) {
+                childOffsets[index] = offset;
+            }
+            return offset;
+        }
+    }
+
+    protected int getRelativeChildOffset(int index) {
+        if (index < 0 || index > getChildCount() - 1) return 0;
+
+        if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) {
+            return mChildRelativeOffsets[index];
+        } else {
+            final int padding = getPaddingLeft() + getPaddingRight();
+            final int offset = getPaddingLeft() +
+                    (getViewportWidth() - padding - getChildWidth(index)) / 2;
+            if (mChildRelativeOffsets != null) {
+                mChildRelativeOffsets[index] = offset;
+            }
+            return offset;
+        }
+    }
+
+    protected int getScaledMeasuredWidth(View child) {
+        // This functions are called enough times that it actually makes a difference in the
+        // profiler -- so just inline the max() here
+        final int measuredWidth = child.getMeasuredWidth();
+        final int minWidth = mMinimumWidth;
+        final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
+        return (int) (maxWidth * mLayoutScale + 0.5f);
+    }
+
+    void boundByReorderablePages(boolean isReordering, int[] range) {
+        // Do nothing
+    }
+
+    // TODO: Fix this
+    protected void getVisiblePages(int[] range) {
+        range[0] = 0;
+        range[1] = getPageCount() - 1;
+
+        /*
+        final int pageCount = getChildCount();
+
+        if (pageCount > 0) {
+            final int screenWidth = getViewportWidth();
+            int leftScreen = 0;
+            int rightScreen = 0;
+            int offsetX = getViewportOffsetX() + getScrollX();
+            View currPage = getPageAt(leftScreen);
+            while (leftScreen < pageCount - 1 &&
+                    currPage.getX() + currPage.getWidth() -
+                    currPage.getPaddingRight() < offsetX) {
+                leftScreen++;
+                currPage = getPageAt(leftScreen);
+            }
+            rightScreen = leftScreen;
+            currPage = getPageAt(rightScreen + 1);
+            while (rightScreen < pageCount - 1 &&
+                    currPage.getX() - currPage.getPaddingLeft() < offsetX + screenWidth) {
+                rightScreen++;
+                currPage = getPageAt(rightScreen + 1);
+            }
+
+            // TEMP: this is a hacky way to ensure that animations to new pages are not clipped
+            // because we don't draw them while scrolling?
+            range[0] = Math.max(0, leftScreen - 1);
+            range[1] = Math.min(rightScreen + 1, getChildCount() - 1);
+        } else {
+            range[0] = -1;
+            range[1] = -1;
+        }
+        */
+    }
+
+    protected boolean shouldDrawChild(View child) {
+        return child.getAlpha() > 0;
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        int halfScreenSize = getViewportWidth() / 2;
+        // mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
+        // Otherwise it is equal to the scaled overscroll position.
+        int screenCenter = mOverScrollX + halfScreenSize;
+
+        if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
+            // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can
+            // set it for the next frame
+            mForceScreenScrolled = false;
+            screenScrolled(screenCenter);
+            mLastScreenCenter = screenCenter;
+        }
+
+        // Find out which screens are visible; as an optimization we only call draw on them
+        final int pageCount = getChildCount();
+        if (pageCount > 0) {
+            getVisiblePages(mTempVisiblePagesRange);
+            final int leftScreen = mTempVisiblePagesRange[0];
+            final int rightScreen = mTempVisiblePagesRange[1];
+            if (leftScreen != -1 && rightScreen != -1) {
+                final long drawingTime = getDrawingTime();
+                // Clip to the bounds
+                canvas.save();
+                canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
+                        getScrollY() + getBottom() - getTop());
+
+                // Draw all the children, leaving the drag view for last
+                for (int i = pageCount - 1; i >= 0; i--) {
+                    final View v = getPageAt(i);
+                    if (v == mDragView) continue;
+                    if (mForceDrawAllChildrenNextFrame ||
+                               (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
+                        drawChild(canvas, v, drawingTime);
+                    }
+                }
+                // Draw the drag view on top (if there is one)
+                if (mDragView != null) {
+                    drawChild(canvas, mDragView, drawingTime);
+                }
+
+                mForceDrawAllChildrenNextFrame = false;
+                canvas.restore();
+            }
+        }
+    }
+
+    @Override
+    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
+        int page = indexToPage(indexOfChild(child));
+        if (page != mCurrentPage || !mScroller.isFinished()) {
+            snapToPage(page);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        int focusablePage;
+        if (mNextPage != INVALID_PAGE) {
+            focusablePage = mNextPage;
+        } else {
+            focusablePage = mCurrentPage;
+        }
+        View v = getPageAt(focusablePage);
+        if (v != null) {
+            return v.requestFocus(direction, previouslyFocusedRect);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean dispatchUnhandledMove(View focused, int direction) {
+        if (direction == View.FOCUS_LEFT) {
+            if (getCurrentPage() > 0) {
+                snapToPage(getCurrentPage() - 1);
+                return true;
+            }
+        } else if (direction == View.FOCUS_RIGHT) {
+            if (getCurrentPage() < getPageCount() - 1) {
+                snapToPage(getCurrentPage() + 1);
+                return true;
+            }
+        }
+        return super.dispatchUnhandledMove(focused, direction);
+    }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
+            getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
+        }
+        if (direction == View.FOCUS_LEFT) {
+            if (mCurrentPage > 0) {
+                getPageAt(mCurrentPage - 1).addFocusables(views, direction, focusableMode);
+            }
+        } else if (direction == View.FOCUS_RIGHT){
+            if (mCurrentPage < getPageCount() - 1) {
+                getPageAt(mCurrentPage + 1).addFocusables(views, direction, focusableMode);
+            }
+        }
+    }
+
+    /**
+     * If one of our descendant views decides that it could be focused now, only
+     * pass that along if it's on the current page.
+     *
+     * This happens when live folders requery, and if they're off page, they
+     * end up calling requestFocus, which pulls it on page.
+     */
+    @Override
+    public void focusableViewAvailable(View focused) {
+        View current = getPageAt(mCurrentPage);
+        View v = focused;
+        while (true) {
+            if (v == current) {
+                super.focusableViewAvailable(focused);
+                return;
+            }
+            if (v == this) {
+                return;
+            }
+            ViewParent parent = v.getParent();
+            if (parent instanceof View) {
+                v = (View)v.getParent();
+            } else {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Return true if a tap at (x, y) should trigger a flip to the previous page.
+     */
+    protected boolean hitsPreviousPage(float x, float y) {
+        return (x < getViewportOffsetX() + getRelativeChildOffset(mCurrentPage) - mPageSpacing);
+    }
+
+    /**
+     * Return true if a tap at (x, y) should trigger a flip to the next page.
+     */
+    protected boolean hitsNextPage(float x, float y) {
+        return  (x > (getViewportOffsetX() + getViewportWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
+    }
+
+    /** Returns whether x and y originated within the buffered viewport */
+    private boolean isTouchPointInViewportWithBuffer(int x, int y) {
+        mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
+                mViewport.right + mViewport.width() / 2, mViewport.bottom);
+        return mTmpRect.contains(x, y);
+    }
+
+    /** Returns whether x and y originated within the current page view bounds */
+    private boolean isTouchPointInCurrentPage(int x, int y) {
+        View v = getPageAt(getCurrentPage());
+        if (v != null) {
+            mTmpRect.set((v.getLeft() - getScrollX()), 0, (v.getRight() - getScrollX()),
+                    v.getBottom());
+            return mTmpRect.contains(x, y);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (DISABLE_TOUCH_INTERACTION) {
+            return false;
+        }
+
+        /*
+         * This method JUST determines whether we want to intercept the motion.
+         * If we return true, onTouchEvent will be called and we do the actual
+         * scrolling there.
+         */
+        acquireVelocityTrackerAndAddMovement(ev);
+
+        // Skip touch handling if there are no pages to swipe
+        if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
+
+        /*
+         * Shortcut the most recurring case: the user is in the dragging
+         * state and he is moving his finger.  We want to intercept this
+         * motion.
+         */
+        final int action = ev.getAction();
+        if ((action == MotionEvent.ACTION_MOVE) &&
+                (mTouchState == TOUCH_STATE_SCROLLING)) {
+            return true;
+        }
+
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_MOVE: {
+                /*
+                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
+                 * whether the user has moved far enough from his original down touch.
+                 */
+                if (mActivePointerId != INVALID_POINTER) {
+                    if (mIsCameraEvent || determineScrollingStart(ev)) {
+                        startScrolling(ev);
+                    }
+                    break;
+                }
+                // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
+                // event. in that case, treat the first occurence of a move event as a ACTION_DOWN
+                // i.e. fall through to the next case (don't break)
+                // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
+                // while it's small- this was causing a crash before we checked for INVALID_POINTER)
+
+                break;
+            }
+
+            case MotionEvent.ACTION_DOWN: {
+                if (mIsCameraEvent) {
+                    animateWarpPageOnScreen();
+                }
+                // Remember where the motion event started
+                saveDownState(ev);
+
+                /*
+                 * If being flinged and user touches the screen, initiate drag;
+                 * otherwise don't.  mScroller.isFinished should be false when
+                 * being flinged.
+                 */
+                final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
+                final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
+                if (finishedScrolling) {
+                    setTouchState(TOUCH_STATE_REST);
+                    mScroller.abortAnimation();
+                } else {
+                    if (mIsCameraEvent || isTouchPointInViewportWithBuffer(
+                            (int) mDownMotionX, (int) mDownMotionY)) {
+                        setTouchState(TOUCH_STATE_SCROLLING);
+                    } else {
+                        setTouchState(TOUCH_STATE_REST);
+                    }
+                }
+
+                // check if this can be the beginning of a tap on the side of the pages
+                // to scroll the current page
+                if (!DISABLE_TOUCH_SIDE_PAGES) {
+                    if (mTouchState != TOUCH_STATE_PREV_PAGE
+                            && mTouchState != TOUCH_STATE_NEXT_PAGE) {
+                        if (getChildCount() > 0) {
+                            float x = ev.getX();
+                            float y = ev.getY();
+                            if (hitsPreviousPage(x, y)) {
+                                setTouchState(TOUCH_STATE_PREV_PAGE);
+                            } else if (hitsNextPage(x, y)) {
+                                setTouchState(TOUCH_STATE_NEXT_PAGE);
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                resetTouchState();
+                // Just intercept the touch event on up if we tap outside the strict viewport
+                if (!isTouchPointInCurrentPage((int) mLastMotionX, (int) mLastMotionY)) {
+                    return true;
+                }
+                break;
+
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                releaseVelocityTracker();
+                break;
+        }
+
+        /*
+         * The only time we want to intercept motion events is if we are in the
+         * drag mode.
+         */
+        return mTouchState != TOUCH_STATE_REST;
+    }
+
+    private void setTouchState(int touchState) {
+        if (mTouchState != touchState) {
+            onTouchStateChanged(touchState);
+            mTouchState = touchState;
+        }
+    }
+
+    void onTouchStateChanged(int newTouchState) {
+        if (DEBUG) {
+            Log.v(TAG, "onTouchStateChanged(old="+ mTouchState + ", new=" + newTouchState + ")");
+        }
+    }
+
+    /**
+     * Save the state when we get {@link MotionEvent#ACTION_DOWN}
+     * @param ev
+     */
+    private void saveDownState(MotionEvent ev) {
+        // Remember where the motion event started
+        mDownMotionX = mLastMotionX = ev.getX();
+        mDownMotionY = mLastMotionY = ev.getY();
+        mDownScrollX = getScrollX();
+        float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
+        mParentDownMotionX = p[0];
+        mParentDownMotionY = p[1];
+        mLastMotionXRemainder = 0;
+        mTotalMotionX = 0;
+        mActivePointerId = ev.getPointerId(0);
+
+        // Determine if the down event is within the threshold to be an edge swipe
+        int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
+        int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
+        if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
+            mDownEventOnEdge = true;
+        }
+    }
+
+    /*
+     * Determines if we should change the touch state to start scrolling after the
+     * user moves their touch point too far.
+     */
+    protected boolean determineScrollingStart(MotionEvent ev) {
+        // Disallow scrolling if we don't have a valid pointer index
+        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+        if (pointerIndex == -1) return false;
+
+        // Disallow scrolling if we started the gesture from outside the viewport
+        final float x = ev.getX(pointerIndex);
+        final float y = ev.getY(pointerIndex);
+        if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return false;
+
+        // If we're only allowing edge swipes, we break out early if the down event wasn't
+        // at the edge.
+        if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return false;
+
+        final int xDiff = (int) Math.abs(x - mLastMotionX);
+        final int yDiff = (int) Math.abs(y - mLastMotionY);
+
+        final int touchSlop = Math.round(TOUCH_SLOP_SCALE * mTouchSlop);
+        boolean xPaged = xDiff > mPagingTouchSlop;
+        boolean xMoved = xDiff > touchSlop;
+        boolean yMoved = yDiff > touchSlop;
+
+        return (xMoved || xPaged || yMoved) && (mUsePagingTouchSlop ? xPaged : xMoved);
+    }
+
+    private void startScrolling(MotionEvent ev) {
+        // Ignore if we don't have a valid pointer index
+        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+        if (pointerIndex == -1) return;
+
+        final float x = ev.getX(pointerIndex);
+        setTouchState(TOUCH_STATE_SCROLLING);
+        mTotalMotionX += Math.abs(mLastMotionX - x);
+        mLastMotionX = x;
+        mLastMotionXRemainder = 0;
+        mTouchX = getViewportOffsetX() + getScrollX();
+        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+        pageBeginMoving();
+    }
+
+    protected float getMaxScrollProgress() {
+        return 1.0f;
+    }
+
+    protected float getBoundedScrollProgress(int screenCenter, View v, int page) {
+        final int halfScreenSize = getViewportWidth() / 2;
+
+        screenCenter = Math.min(mScrollX + halfScreenSize, screenCenter);
+        screenCenter = Math.max(halfScreenSize,  screenCenter);
+
+        return getScrollProgress(screenCenter, v, page);
+    }
+
+    protected float getScrollProgress(int screenCenter, View v, int page) {
+        final int halfScreenSize = getViewportWidth() / 2;
+
+        int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing;
+        int delta = screenCenter - (getChildOffset(page) -
+                getRelativeChildOffset(page) + halfScreenSize);
+
+        float scrollProgress = delta / (totalDistance * 1.0f);
+        scrollProgress = Math.min(scrollProgress, getMaxScrollProgress());
+        scrollProgress = Math.max(scrollProgress, - getMaxScrollProgress());
+        return scrollProgress;
+    }
+
+    // This curve determines how the effect of scrolling over the limits of the page dimishes
+    // as the user pulls further and further from the bounds
+    private float overScrollInfluenceCurve(float f) {
+        f -= 1.0f;
+        return f * f * f + 1.0f;
+    }
+
+    protected void acceleratedOverScroll(float amount) {
+        int screenSize = getViewportWidth();
+
+        // We want to reach the max over scroll effect when the user has
+        // over scrolled half the size of the screen
+        float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
+
+        if (f == 0) return;
+
+        // Clamp this factor, f, to -1 < f < 1
+        if (Math.abs(f) >= 1) {
+            f /= Math.abs(f);
+        }
+
+        int overScrollAmount = (int) Math.round(f * screenSize);
+        if (amount < 0) {
+            mOverScrollX = overScrollAmount;
+            super.scrollTo(0, getScrollY());
+        } else {
+            mOverScrollX = mMaxScrollX + overScrollAmount;
+            super.scrollTo(mMaxScrollX, getScrollY());
+        }
+        invalidate();
+    }
+
+    protected void dampedOverScroll(float amount) {
+        int screenSize = getViewportWidth();
+
+        float f = (amount / screenSize);
+
+        if (f == 0) return;
+        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+        // Clamp this factor, f, to -1 < f < 1
+        if (Math.abs(f) >= 1) {
+            f /= Math.abs(f);
+        }
+
+        int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
+        if (amount < 0) {
+            mOverScrollX = overScrollAmount;
+            super.scrollTo(0, getScrollY());
+        } else {
+            mOverScrollX = mMaxScrollX + overScrollAmount;
+            super.scrollTo(mMaxScrollX, getScrollY());
+        }
+        invalidate();
+    }
+
+    protected void overScroll(float amount) {
+        dampedOverScroll(amount);
+    }
+
+    protected float maxOverScroll() {
+        // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
+        // exceed). Used to find out how much extra wallpaper we need for the over scroll effect
+        float f = 1.0f;
+        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+        return OVERSCROLL_DAMP_FACTOR * f;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (DISABLE_TOUCH_INTERACTION) {
+            return false;
+        }
+
+        // Skip touch handling if there are no pages to swipe
+        if (getChildCount() <= 0) return super.onTouchEvent(ev);
+
+        acquireVelocityTrackerAndAddMovement(ev);
+
+        final int action = ev.getAction();
+
+        switch (action & MotionEvent.ACTION_MASK) {
+        case MotionEvent.ACTION_DOWN:
+            /*
+             * If being flinged and user touches, stop the fling. isFinished
+             * will be false if being flinged.
+             */
+            if (!mScroller.isFinished()) {
+                mScroller.abortAnimation();
+            }
+
+            // Remember where the motion event started
+            saveDownState(ev);
+
+            if (mTouchState == TOUCH_STATE_SCROLLING) {
+                pageBeginMoving();
+            } else {
+                animateWarpPageOnScreen();
+            }
+            break;
+
+        case MotionEvent.ACTION_MOVE:
+            if (mTouchState == TOUCH_STATE_SCROLLING) {
+                // Scroll to follow the motion event
+                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+
+                if (pointerIndex == -1) return true;
+
+                final float x = ev.getX(pointerIndex);
+                final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
+
+                mTotalMotionX += Math.abs(deltaX);
+
+                // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
+                // keep the remainder because we are actually testing if we've moved from the last
+                // scrolled position (which is discrete).
+                if (Math.abs(deltaX) >= 1.0f) {
+                    mTouchX += deltaX;
+                    mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+                    if (!mDeferScrollUpdate) {
+                        scrollBy((int) deltaX, 0);
+                        if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
+                    } else {
+                        invalidate();
+                    }
+                    mLastMotionX = x;
+                    mLastMotionXRemainder = deltaX - (int) deltaX;
+                } else {
+                    awakenScrollBars();
+                }
+            } else if (mTouchState == TOUCH_STATE_REORDERING) {
+                // Update the last motion position
+                mLastMotionX = ev.getX();
+                mLastMotionY = ev.getY();
+
+                // Update the parent down so that our zoom animations take this new movement into
+                // account
+                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
+                mParentDownMotionX = pt[0];
+                mParentDownMotionY = pt[1];
+                updateDragViewTranslationDuringDrag();
+
+                // Find the closest page to the touch point
+                final int dragViewIndex = indexOfChild(mDragView);
+                int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE *
+                    getViewportWidth());
+                int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0]
+                        + bufferSize);
+                int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0]
+                        - bufferSize);
+
+                // Change the drag view if we are hovering over the drop target
+                boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
+                        (int) mParentDownMotionX, (int) mParentDownMotionY);
+                setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
+
+                if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
+                if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
+                if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
+                if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
+                if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
+                if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
+
+                float parentX = mParentDownMotionX;
+                int pageIndexToSnapTo = -1;
+                if (parentX < leftBufferEdge && dragViewIndex > 0) {
+                    pageIndexToSnapTo = dragViewIndex - 1;
+                } else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) {
+                    pageIndexToSnapTo = dragViewIndex + 1;
+                }
+
+                final int pageUnderPointIndex = pageIndexToSnapTo;
+                if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
+                    mTempVisiblePagesRange[0] = 0;
+                    mTempVisiblePagesRange[1] = getPageCount() - 1;
+                    boundByReorderablePages(true, mTempVisiblePagesRange);
+                    if (mTempVisiblePagesRange[0] <= pageUnderPointIndex &&
+                            pageUnderPointIndex <= mTempVisiblePagesRange[1] &&
+                            pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
+                        mSidePageHoverIndex = pageUnderPointIndex;
+                        mSidePageHoverRunnable = new Runnable() {
+                            @Override
+                            public void run() {
+                                // Update the down scroll position to account for the fact that the
+                                // current page is moved
+                                mDownScrollX = getChildOffset(pageUnderPointIndex)
+                                        - getRelativeChildOffset(pageUnderPointIndex);
+
+                                // Setup the scroll to the correct page before we swap the views
+                                snapToPage(pageUnderPointIndex);
+
+                                // For each of the pages between the paged view and the drag view,
+                                // animate them from the previous position to the new position in
+                                // the layout (as a result of the drag view moving in the layout)
+                                int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
+                                int lowerIndex = (dragViewIndex < pageUnderPointIndex) ?
+                                        dragViewIndex + 1 : pageUnderPointIndex;
+                                int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
+                                        dragViewIndex - 1 : pageUnderPointIndex;
+                                for (int i = lowerIndex; i <= upperIndex; ++i) {
+                                    View v = getChildAt(i);
+                                    // dragViewIndex < pageUnderPointIndex, so after we remove the
+                                    // drag view all subsequent views to pageUnderPointIndex will
+                                    // shift down.
+                                    int oldX = getViewportOffsetX() + getChildOffset(i);
+                                    int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);
+
+                                    // Animate the view translation from its old position to its new
+                                    // position
+                                    AnimatorSet anim = (AnimatorSet) v.getTag();
+                                    if (anim != null) {
+                                        anim.cancel();
+                                    }
+
+                                    v.setTranslationX(oldX - newX);
+                                    anim = new AnimatorSet();
+                                    anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
+                                    anim.playTogether(
+                                            ObjectAnimator.ofFloat(v, "translationX", 0f));
+                                    anim.start();
+                                    v.setTag(anim);
+                                }
+
+                                removeView(mDragView);
+                                onRemoveView(mDragView, false);
+                                addView(mDragView, pageUnderPointIndex);
+                                onAddView(mDragView, pageUnderPointIndex);
+                                mSidePageHoverIndex = -1;
+                            }
+                        };
+                        postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
+                    }
+                } else {
+                    removeCallbacks(mSidePageHoverRunnable);
+                    mSidePageHoverIndex = -1;
+                }
+            } else if (mIsCameraEvent || determineScrollingStart(ev)) {
+                startScrolling(ev);
+            }
+            break;
+
+        case MotionEvent.ACTION_UP:
+            if (mTouchState == TOUCH_STATE_SCROLLING) {
+                final int activePointerId = mActivePointerId;
+                final int pointerIndex = ev.findPointerIndex(activePointerId);
+                final float x = ev.getX(pointerIndex);
+                final VelocityTracker velocityTracker = mVelocityTracker;
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
+                final int deltaX = (int) (x - mDownMotionX);
+                final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
+                boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
+                        SIGNIFICANT_MOVE_THRESHOLD;
+
+                mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
+
+                boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
+                        Math.abs(velocityX) > mFlingThresholdVelocity;
+
+                // In the case that the page is moved far to one direction and then is flung
+                // in the opposite direction, we use a threshold to determine whether we should
+                // just return to the starting page, or if we should skip one further.
+                boolean returnToOriginalPage = false;
+                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
+                        Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
+                    returnToOriginalPage = true;
+                }
+
+                int finalPage;
+                // We give flings precedence over large moves, which is why we short-circuit our
+                // test for a large move if a fling has been registered. That is, a large
+                // move to the left and fling to the right will register as a fling to the right.
+                if (((isSignificantMove && deltaX > 0 && !isFling) ||
+                        (isFling && velocityX > 0)) && mCurrentPage > 0) {
+                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
+                    snapToPageWithVelocity(finalPage, velocityX);
+                } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
+                        (isFling && velocityX < 0)) &&
+                        mCurrentPage < getChildCount() - 1) {
+                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
+                    snapToPageWithVelocity(finalPage, velocityX);
+                } else {
+                    snapToDestination();
+                }
+            } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
+                // at this point we have not moved beyond the touch slop
+                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
+                // we can just page
+                int nextPage = Math.max(0, mCurrentPage - 1);
+                if (nextPage != mCurrentPage) {
+                    snapToPage(nextPage);
+                } else {
+                    snapToDestination();
+                }
+            } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
+                // at this point we have not moved beyond the touch slop
+                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
+                // we can just page
+                int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
+                if (nextPage != mCurrentPage) {
+                    snapToPage(nextPage);
+                } else {
+                    snapToDestination();
+                }
+            } else if (mTouchState == TOUCH_STATE_REORDERING) {
+                // Update the last motion position
+                mLastMotionX = ev.getX();
+                mLastMotionY = ev.getY();
+
+                // Update the parent down so that our zoom animations take this new movement into
+                // account
+                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
+                mParentDownMotionX = pt[0];
+                mParentDownMotionY = pt[1];
+                updateDragViewTranslationDuringDrag();
+                boolean handledFling = false;
+                if (!DISABLE_FLING_TO_DELETE) {
+                    // Check the velocity and see if we are flinging-to-delete
+                    PointF flingToDeleteVector = isFlingingToDelete();
+                    if (flingToDeleteVector != null) {
+                        onFlingToDelete(flingToDeleteVector);
+                        handledFling = true;
+                    }
+                }
+                if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
+                        (int) mParentDownMotionY)) {
+                    onDropToDelete();
+                }
+            } else {
+                onUnhandledTap(ev);
+            }
+
+            // Remove the callback to wait for the side page hover timeout
+            removeCallbacks(mSidePageHoverRunnable);
+            // End any intermediate reordering states
+            resetTouchState();
+            break;
+
+        case MotionEvent.ACTION_CANCEL:
+            if (mTouchState == TOUCH_STATE_SCROLLING) {
+                snapToDestination();
+            }
+            resetTouchState();
+            break;
+
+        case MotionEvent.ACTION_POINTER_UP:
+            onSecondaryPointerUp(ev);
+            break;
+        }
+
+        return true;
+    }
+
+    //public abstract void onFlingToDelete(View v);
+    public abstract void onRemoveView(View v, boolean deletePermanently);
+    public abstract void onRemoveViewAnimationCompleted();
+    public abstract void onAddView(View v, int index);
+
+    private void resetTouchState() {
+        releaseVelocityTracker();
+        endReordering();
+        setTouchState(TOUCH_STATE_REST);
+        mActivePointerId = INVALID_POINTER;
+        mDownEventOnEdge = false;
+    }
+
+    protected void onUnhandledTap(MotionEvent ev) {}
+
+    @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_SCROLL: {
+                    // Handle mouse (or ext. device) by shifting the page depending on the scroll
+                    final float vscroll;
+                    final float hscroll;
+                    if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+                        vscroll = 0;
+                        hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                    } else {
+                        vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                        hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+                    }
+                    if (hscroll != 0 || vscroll != 0) {
+                        if (hscroll > 0 || vscroll > 0) {
+                            scrollRight();
+                        } else {
+                            scrollLeft();
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+        return super.onGenericMotionEvent(event);
+    }
+
+    private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+    }
+
+    private void releaseVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    private void onSecondaryPointerUp(MotionEvent ev) {
+        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
+                MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+        final int pointerId = ev.getPointerId(pointerIndex);
+        if (pointerId == mActivePointerId) {
+            // This was our active pointer going up. Choose a new
+            // active pointer and adjust accordingly.
+            // TODO: Make this decision more intelligent.
+            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+            mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
+            mLastMotionY = ev.getY(newPointerIndex);
+            mLastMotionXRemainder = 0;
+            mActivePointerId = ev.getPointerId(newPointerIndex);
+            if (mVelocityTracker != null) {
+                mVelocityTracker.clear();
+            }
+        }
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        super.requestChildFocus(child, focused);
+        int page = indexToPage(indexOfChild(child));
+        if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
+            snapToPage(page);
+        }
+    }
+
+    protected int getChildIndexForRelativeOffset(int relativeOffset) {
+        final int childCount = getChildCount();
+        int left;
+        int right;
+        for (int i = 0; i < childCount; ++i) {
+            left = getRelativeChildOffset(i);
+            right = (left + getScaledMeasuredWidth(getPageAt(i)));
+            if (left <= relativeOffset && relativeOffset <= right) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    protected int getChildWidth(int index) {
+        // This functions are called enough times that it actually makes a difference in the
+        // profiler -- so just inline the max() here
+        final int measuredWidth = getPageAt(index).getMeasuredWidth();
+        final int minWidth = mMinimumWidth;
+        return (minWidth > measuredWidth) ? minWidth : measuredWidth;
+    }
+
+    int getPageNearestToPoint(float x) {
+        int index = 0;
+        for (int i = 0; i < getChildCount(); ++i) {
+            if (x < getChildAt(i).getRight() - getScrollX()) {
+                return index;
+            } else {
+                index++;
+            }
+        }
+        return Math.min(index, getChildCount() - 1);
+    }
+
+    int getPageNearestToCenterOfScreen() {
+        int minDistanceFromScreenCenter = Integer.MAX_VALUE;
+        int minDistanceFromScreenCenterIndex = -1;
+        int screenCenter = getViewportOffsetX() + getScrollX() + (getViewportWidth() / 2);
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; ++i) {
+            View layout = (View) getPageAt(i);
+            int childWidth = getScaledMeasuredWidth(layout);
+            int halfChildWidth = (childWidth / 2);
+            int childCenter = getViewportOffsetX() + getChildOffset(i) + halfChildWidth;
+            int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
+            if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
+                minDistanceFromScreenCenter = distanceFromScreenCenter;
+                minDistanceFromScreenCenterIndex = i;
+            }
+        }
+        return minDistanceFromScreenCenterIndex;
+    }
+
+    protected void snapToDestination() {
+        snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
+    }
+
+    private static class ScrollInterpolator implements Interpolator {
+        public ScrollInterpolator() {
+        }
+
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t*t*t*t*t + 1;
+        }
+    }
+
+    // We want the duration of the page snap animation to be influenced by the distance that
+    // the screen has to travel, however, we don't want this duration to be effected in a
+    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+    // of travel has on the overall snap duration.
+    float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    protected void snapToPageWithVelocity(int whichPage, int velocity) {
+        whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
+        int halfScreenSize = getViewportWidth() / 2;
+
+        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
+        if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
+                + getViewportWidth() + ", " + getChildWidth(whichPage));
+        final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
+        int delta = newX - mUnboundedScrollX;
+        int duration = 0;
+
+        if (Math.abs(velocity) < mMinFlingVelocity) {
+            // If the velocity is low enough, then treat this more as an automatic page advance
+            // as opposed to an apparent physical response to flinging
+            snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+            return;
+        }
+
+        // Here we compute a "distance" that will be used in the computation of the overall
+        // snap duration. This is a function of the actual distance that needs to be traveled;
+        // we keep this value close to half screen size in order to reduce the variance in snap
+        // duration as a function of the distance the page needs to travel.
+        float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / (2 * halfScreenSize));
+        float distance = halfScreenSize + halfScreenSize *
+                distanceInfluenceForSnapDuration(distanceRatio);
+
+        velocity = Math.abs(velocity);
+        velocity = Math.max(mMinSnapVelocity, velocity);
+
+        // we want the page's snap velocity to approximately match the velocity at which the
+        // user flings, so we scale the duration by a value near to the derivative of the scroll
+        // interpolator at zero, ie. 5. We use 4 to make it a little slower.
+        duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+
+        snapToPage(whichPage, delta, duration);
+    }
+
+    protected void snapToPage(int whichPage) {
+        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+    }
+    protected void snapToPageImmediately(int whichPage) {
+        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true);
+    }
+
+    protected void snapToPage(int whichPage, int duration) {
+        snapToPage(whichPage, duration, false);
+    }
+    protected void snapToPage(int whichPage, int duration, boolean immediate) {
+        whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
+
+        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
+        if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getViewportWidth() + ", "
+                + getChildWidth(whichPage));
+        int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
+        final int sX = mUnboundedScrollX;
+        final int delta = newX - sX;
+        snapToPage(whichPage, delta, duration, immediate);
+    }
+
+    protected void snapToPage(int whichPage, int delta, int duration) {
+        snapToPage(whichPage, delta, duration, false);
+    }
+
+    protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) {
+        if (mPageSwapIndex != -1 && whichPage == mPageSwapIndex) {
+            mNextPage = mPageWarpIndex; // jump to the warp page
+            if (DEBUG_WARP) Log.v(TAG, "snapToPage(" + whichPage + ") : reset mPageSwapIndex");
+        } else {
+            mNextPage = whichPage;
+        }
+
+        if (mPageWarpIndex != -1) {
+            animateWarpPageOffScreen();
+            resetPageWarp();
+        }
+
+        notifyPageSwitching(whichPage);
+        View focusedChild = getFocusedChild();
+        if (focusedChild != null && whichPage != mCurrentPage &&
+                focusedChild == getPageAt(mCurrentPage)) {
+            focusedChild.clearFocus();
+        }
+
+        pageBeginMoving();
+        awakenScrollBars(duration);
+        if (immediate) {
+            duration = 0;
+        } else if (duration == 0) {
+            duration = Math.abs(delta);
+        }
+
+        if (!mScroller.isFinished()) mScroller.abortAnimation();
+        mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
+
+        notifyPageSwitched();
+
+        // Trigger a compute() to finish switching pages if necessary
+        if (immediate) {
+            computeScroll();
+        }
+
+        mForceScreenScrolled = true;
+        invalidate();
+    }
+
+    public void scrollLeft() {
+        if (mScroller.isFinished()) {
+            if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
+        } else {
+            if (mNextPage > 0) snapToPage(mNextPage - 1);
+        }
+    }
+
+    public void scrollRight() {
+        if (mScroller.isFinished()) {
+            if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1);
+        } else {
+            if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1);
+        }
+    }
+
+    public int getPageForView(View v) {
+        int result = -1;
+        if (v != null) {
+            ViewParent vp = v.getParent();
+            int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                if (vp == getPageAt(i)) {
+                    return i;
+                }
+            }
+        }
+        return result;
+    }
+
+    public static class SavedState extends BaseSavedState {
+        int currentPage = -1;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            currentPage = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(currentPage);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    protected View getScrollingIndicator() {
+        return null;
+    }
+
+    protected boolean isScrollingIndicatorEnabled() {
+        return false;
+    }
+
+    Runnable hideScrollingIndicatorRunnable = new Runnable() {
+        @Override
+        public void run() {
+            hideScrollingIndicator(false);
+        }
+    };
+
+    protected void flashScrollingIndicator(boolean animated) {
+        removeCallbacks(hideScrollingIndicatorRunnable);
+        showScrollingIndicator(!animated);
+        postDelayed(hideScrollingIndicatorRunnable, sScrollIndicatorFlashDuration);
+    }
+
+    protected void showScrollingIndicator(boolean immediately) {
+        mShouldShowScrollIndicator = true;
+        mShouldShowScrollIndicatorImmediately = true;
+        if (getChildCount() <= 1) return;
+        if (!isScrollingIndicatorEnabled()) return;
+
+        mShouldShowScrollIndicator = false;
+        getScrollingIndicator();
+        if (mScrollIndicator != null) {
+            // Fade the indicator in
+            updateScrollingIndicatorPosition();
+            mScrollIndicator.setVisibility(View.VISIBLE);
+            cancelScrollingIndicatorAnimations();
+            if (immediately) {
+                mScrollIndicator.setAlpha(1f);
+            } else {
+                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f);
+                mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration);
+                mScrollIndicatorAnimator.start();
+            }
+        }
+    }
+
+    protected void cancelScrollingIndicatorAnimations() {
+        if (mScrollIndicatorAnimator != null) {
+            mScrollIndicatorAnimator.cancel();
+        }
+    }
+
+    protected void hideScrollingIndicator(boolean immediately) {
+        if (getChildCount() <= 1) return;
+        if (!isScrollingIndicatorEnabled()) return;
+
+        getScrollingIndicator();
+        if (mScrollIndicator != null) {
+            // Fade the indicator out
+            updateScrollingIndicatorPosition();
+            cancelScrollingIndicatorAnimations();
+            if (immediately) {
+                mScrollIndicator.setVisibility(View.INVISIBLE);
+                mScrollIndicator.setAlpha(0f);
+            } else {
+                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f);
+                mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration);
+                mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() {
+                    private boolean cancelled = false;
+                    @Override
+                    public void onAnimationCancel(android.animation.Animator animation) {
+                        cancelled = true;
+                    }
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        if (!cancelled) {
+                            mScrollIndicator.setVisibility(View.INVISIBLE);
+                        }
+                    }
+                });
+                mScrollIndicatorAnimator.start();
+            }
+        }
+    }
+
+    /**
+     * To be overridden by subclasses to determine whether the scroll indicator should stretch to
+     * fill its space on the track or not.
+     */
+    protected boolean hasElasticScrollIndicator() {
+        return true;
+    }
+
+    private void updateScrollingIndicator() {
+        if (getChildCount() <= 1) return;
+        if (!isScrollingIndicatorEnabled()) return;
+
+        getScrollingIndicator();
+        if (mScrollIndicator != null) {
+            updateScrollingIndicatorPosition();
+        }
+        if (mShouldShowScrollIndicator) {
+            showScrollingIndicator(mShouldShowScrollIndicatorImmediately);
+        }
+    }
+
+    private void updateScrollingIndicatorPosition() {
+        if (!isScrollingIndicatorEnabled()) return;
+        if (mScrollIndicator == null) return;
+        int numPages = getChildCount();
+        int pageWidth = getViewportWidth();
+        int lastChildIndex = Math.max(0, getChildCount() - 1);
+        int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex);
+        int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight;
+        int indicatorWidth = mScrollIndicator.getMeasuredWidth() -
+                mScrollIndicator.getPaddingLeft() - mScrollIndicator.getPaddingRight();
+
+        float offset = Math.max(0f, Math.min(1f, (float) getScrollX() / maxScrollX));
+        int indicatorSpace = trackWidth / numPages;
+        int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft;
+        if (hasElasticScrollIndicator()) {
+            if (mScrollIndicator.getMeasuredWidth() != indicatorSpace) {
+                mScrollIndicator.getLayoutParams().width = indicatorSpace;
+                mScrollIndicator.requestLayout();
+            }
+        } else {
+            int indicatorCenterOffset = indicatorSpace / 2 - indicatorWidth / 2;
+            indicatorPos += indicatorCenterOffset;
+        }
+        mScrollIndicator.setTranslationX(indicatorPos);
+    }
+
+    // Animate the drag view back to the original position
+    void animateDragViewToOriginalPosition() {
+        if (mDragView != null) {
+            AnimatorSet anim = new AnimatorSet();
+            anim.setDuration(REORDERING_DROP_REPOSITION_DURATION);
+            anim.playTogether(
+                    ObjectAnimator.ofFloat(mDragView, "translationX", 0f),
+                    ObjectAnimator.ofFloat(mDragView, "translationY", 0f));
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    onPostReorderingAnimationCompleted();
+                }
+            });
+            anim.start();
+        }
+    }
+
+    // "Zooms out" the PagedView to reveal more side pages
+    protected boolean zoomOut() {
+        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+            mZoomInOutAnim.cancel();
+        }
+
+        if (!(getScaleX() < 1f || getScaleY() < 1f)) {
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
+                    ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
+            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    // Show the delete drop target
+                    if (mDeleteDropTarget != null) {
+                        mDeleteDropTarget.setVisibility(View.VISIBLE);
+                        mDeleteDropTarget.animate().alpha(1f)
+                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
+                            .setListener(new AnimatorListenerAdapter() {
+                                @Override
+                                public void onAnimationStart(Animator animation) {
+                                    mDeleteDropTarget.setAlpha(0f);
+                                }
+                            });
+                    }
+                }
+            });
+            mZoomInOutAnim.start();
+            return true;
+        }
+        return false;
+    }
+
+    protected void onStartReordering() {
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            announceForAccessibility(mContext.getString(
+                    R.string.keyguard_accessibility_widget_reorder_start));
+        }
+
+        // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
+        setTouchState(TOUCH_STATE_REORDERING);
+        mIsReordering = true;
+
+        // Mark all the non-widget pages as invisible
+        getVisiblePages(mTempVisiblePagesRange);
+        boundByReorderablePages(true, mTempVisiblePagesRange);
+        for (int i = 0; i < getPageCount(); ++i) {
+            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
+                getPageAt(i).setAlpha(0f);
+            }
+        }
+
+        // We must invalidate to trigger a redraw to update the layers such that the drag view
+        // is always drawn on top
+        invalidate();
+    }
+
+    private void onPostReorderingAnimationCompleted() {
+        // Trigger the callback when reordering has settled
+        --mPostReorderingPreZoomInRemainingAnimationCount;
+        if (mPostReorderingPreZoomInRunnable != null &&
+                mPostReorderingPreZoomInRemainingAnimationCount == 0) {
+            mPostReorderingPreZoomInRunnable.run();
+            mPostReorderingPreZoomInRunnable = null;
+        }
+    }
+
+    protected void onEndReordering() {
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            if (mDeleteString != null) {
+                announceForAccessibility(mDeleteString);
+                mDeleteString = null;
+            } else {
+                announceForAccessibility(mContext.getString(
+                        R.string.keyguard_accessibility_widget_reorder_end));
+            }
+        }
+        mIsReordering = false;
+
+        // Mark all the non-widget pages as visible again
+        getVisiblePages(mTempVisiblePagesRange);
+        boundByReorderablePages(true, mTempVisiblePagesRange);
+        for (int i = 0; i < getPageCount(); ++i) {
+            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
+                getPageAt(i).setAlpha(1f);
+            }
+        }
+    }
+
+    public boolean startReordering() {
+        int dragViewIndex = getPageNearestToCenterOfScreen();
+        mTempVisiblePagesRange[0] = 0;
+        mTempVisiblePagesRange[1] = getPageCount() - 1;
+        boundByReorderablePages(true, mTempVisiblePagesRange);
+        mReorderingStarted = true;
+
+        // Check if we are within the reordering range
+        if (mTempVisiblePagesRange[0] <= dragViewIndex &&
+                dragViewIndex <= mTempVisiblePagesRange[1]) {
+            if (zoomOut()) {
+                // Find the drag view under the pointer
+                mDragView = getChildAt(dragViewIndex);
+
+                onStartReordering();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    boolean isReordering(boolean testTouchState) {
+        boolean state = mIsReordering;
+        if (testTouchState) {
+            state &= (mTouchState == TOUCH_STATE_REORDERING);
+        }
+        return state;
+    }
+    void endReordering() {
+        // For simplicity, we call endReordering sometimes even if reordering was never started.
+        // In that case, we don't want to do anything.
+        if (!mReorderingStarted) return;
+        mReorderingStarted = false;
+
+        // If we haven't flung-to-delete the current child, then we just animate the drag view
+        // back into position
+        final Runnable onCompleteRunnable = new Runnable() {
+            @Override
+            public void run() {
+                onEndReordering();
+            }
+        };
+        if (!mDeferringForDelete) {
+            mPostReorderingPreZoomInRunnable = new Runnable() {
+                public void run() {
+                    zoomIn(onCompleteRunnable);
+                };
+            };
+
+            mPostReorderingPreZoomInRemainingAnimationCount =
+                    NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
+            // Snap to the current page
+            snapToPage(indexOfChild(mDragView), 0);
+            // Animate the drag view back to the front position
+            animateDragViewToOriginalPosition();
+        } else {
+            // Handled in post-delete-animation-callbacks
+        }
+    }
+
+    // "Zooms in" the PagedView to highlight the current page
+    protected boolean zoomIn(final Runnable onCompleteRunnable) {
+        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+            mZoomInOutAnim.cancel();
+        }
+        if (getScaleX() < 1f || getScaleY() < 1f) {
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(this, "scaleX", 1f),
+                    ObjectAnimator.ofFloat(this, "scaleY", 1f));
+            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    // Hide the delete drop target
+                    if (mDeleteDropTarget != null) {
+                        mDeleteDropTarget.animate().alpha(0f)
+                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
+                            .setListener(new AnimatorListenerAdapter() {
+                                @Override
+                                public void onAnimationEnd(Animator animation) {
+                                    mDeleteDropTarget.setVisibility(View.GONE);
+                                }
+                            });
+                    }
+                }
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mDragView = null;
+                }
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mDragView = null;
+                    if (onCompleteRunnable != null) {
+                        onCompleteRunnable.run();
+                    }
+                }
+            });
+            mZoomInOutAnim.start();
+            return true;
+        } else {
+            if (onCompleteRunnable != null) {
+                onCompleteRunnable.run();
+            }
+        }
+        return false;
+    }
+
+    /*
+     * Flinging to delete - IN PROGRESS
+     */
+    private PointF isFlingingToDelete() {
+        ViewConfiguration config = ViewConfiguration.get(getContext());
+        mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
+
+        if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
+            // Do a quick dot product test to ensure that we are flinging upwards
+            PointF vel = new PointF(mVelocityTracker.getXVelocity(),
+                    mVelocityTracker.getYVelocity());
+            PointF upVec = new PointF(0f, -1f);
+            float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
+                    (vel.length() * upVec.length()));
+            if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) {
+                return vel;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creates an animation from the current drag view along its current velocity vector.
+     * For this animation, the alpha runs for a fixed duration and we update the position
+     * progressively.
+     */
+    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
+        private View mDragView;
+        private PointF mVelocity;
+        private Rect mFrom;
+        private long mPrevTime;
+        private float mFriction;
+
+        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
+
+        public FlingAlongVectorAnimatorUpdateListener(View dragView, PointF vel, Rect from,
+                long startTime, float friction) {
+            mDragView = dragView;
+            mVelocity = vel;
+            mFrom = from;
+            mPrevTime = startTime;
+            mFriction = 1f - (mDragView.getResources().getDisplayMetrics().density * friction);
+        }
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            float t = ((Float) animation.getAnimatedValue()).floatValue();
+            long curTime = AnimationUtils.currentAnimationTimeMillis();
+
+            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
+            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
+
+            mDragView.setTranslationX(mFrom.left);
+            mDragView.setTranslationY(mFrom.top);
+            mDragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
+
+            mVelocity.x *= mFriction;
+            mVelocity.y *= mFriction;
+            mPrevTime = curTime;
+        }
+    };
+
+    private Runnable createPostDeleteAnimationRunnable(final View dragView) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                int dragViewIndex = indexOfChild(dragView);
+
+                // For each of the pages around the drag view, animate them from the previous
+                // position to the new position in the layout (as a result of the drag view moving
+                // in the layout)
+                // NOTE: We can make an assumption here because we have side-bound pages that we
+                //       will always have pages to animate in from the left
+                getVisiblePages(mTempVisiblePagesRange);
+                boundByReorderablePages(true, mTempVisiblePagesRange);
+                boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
+                boolean slideFromLeft = (isLastWidgetPage ||
+                        dragViewIndex > mTempVisiblePagesRange[0]);
+
+                // Setup the scroll to the correct page before we swap the views
+                if (slideFromLeft) {
+                    snapToPageImmediately(dragViewIndex - 1);
+                }
+
+                int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
+                int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
+                int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
+                int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
+                ArrayList<Animator> animations = new ArrayList<Animator>();
+                for (int i = lowerIndex; i <= upperIndex; ++i) {
+                    View v = getChildAt(i);
+                    // dragViewIndex < pageUnderPointIndex, so after we remove the
+                    // drag view all subsequent views to pageUnderPointIndex will
+                    // shift down.
+                    int oldX = 0;
+                    int newX = 0;
+                    if (slideFromLeft) {
+                        if (i == 0) {
+                            // Simulate the page being offscreen with the page spacing
+                            oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
+                                    - mPageSpacing;
+                        } else {
+                            oldX = getViewportOffsetX() + getChildOffset(i - 1);
+                        }
+                        newX = getViewportOffsetX() + getChildOffset(i);
+                    } else {
+                        oldX = getChildOffset(i) - getChildOffset(i - 1);
+                        newX = 0;
+                    }
+
+                    // Animate the view translation from its old position to its new
+                    // position
+                    AnimatorSet anim = (AnimatorSet) v.getTag();
+                    if (anim != null) {
+                        anim.cancel();
+                    }
+
+                    // Note: Hacky, but we want to skip any optimizations to not draw completely
+                    // hidden views
+                    v.setAlpha(Math.max(v.getAlpha(), 0.01f));
+                    v.setTranslationX(oldX - newX);
+                    anim = new AnimatorSet();
+                    anim.playTogether(
+                            ObjectAnimator.ofFloat(v, "translationX", 0f),
+                            ObjectAnimator.ofFloat(v, "alpha", 1f));
+                    animations.add(anim);
+                    v.setTag(anim);
+                }
+
+                AnimatorSet slideAnimations = new AnimatorSet();
+                slideAnimations.playTogether(animations);
+                slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
+                slideAnimations.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        final Runnable onCompleteRunnable = new Runnable() {
+                            @Override
+                            public void run() {
+                                mDeferringForDelete = false;
+                                onEndReordering();
+                                onRemoveViewAnimationCompleted();
+                            }
+                        };
+                        zoomIn(onCompleteRunnable);
+                    }
+                });
+                slideAnimations.start();
+
+                removeView(dragView);
+                onRemoveView(dragView, true);
+            }
+        };
+    }
+
+    public void onFlingToDelete(PointF vel) {
+        final long startTime = AnimationUtils.currentAnimationTimeMillis();
+
+        // NOTE: Because it takes time for the first frame of animation to actually be
+        // called and we expect the animation to be a continuation of the fling, we have
+        // to account for the time that has elapsed since the fling finished.  And since
+        // we don't have a startDelay, we will always get call to update when we call
+        // start() (which we want to ignore).
+        final TimeInterpolator tInterpolator = new TimeInterpolator() {
+            private int mCount = -1;
+            private long mStartTime;
+            private float mOffset;
+            /* Anonymous inner class ctor */ {
+                mStartTime = startTime;
+            }
+
+            @Override
+            public float getInterpolation(float t) {
+                if (mCount < 0) {
+                    mCount++;
+                } else if (mCount == 0) {
+                    mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
+                            mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION);
+                    mCount++;
+                }
+                return Math.min(1f, mOffset + t);
+            }
+        };
+
+        final Rect from = new Rect();
+        final View dragView = mDragView;
+        from.left = (int) dragView.getTranslationX();
+        from.top = (int) dragView.getTranslationY();
+        AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
+                from, startTime, FLING_TO_DELETE_FRICTION);
+
+        mDeleteString = getContext().getResources()
+                .getString(R.string.keyguard_accessibility_widget_deleted,
+                        mDragView.getContentDescription());
+        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
+
+        // Create and start the animation
+        ValueAnimator mDropAnim = new ValueAnimator();
+        mDropAnim.setInterpolator(tInterpolator);
+        mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION);
+        mDropAnim.setFloatValues(0f, 1f);
+        mDropAnim.addUpdateListener(updateCb);
+        mDropAnim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                onAnimationEndRunnable.run();
+            }
+        });
+        mDropAnim.start();
+        mDeferringForDelete = true;
+    }
+
+    /* Drag to delete */
+    private boolean isHoveringOverDeleteDropTarget(int x, int y) {
+        if (mDeleteDropTarget != null) {
+            mAltTmpRect.set(0, 0, 0, 0);
+            View parent = (View) mDeleteDropTarget.getParent();
+            if (parent != null) {
+                parent.getGlobalVisibleRect(mAltTmpRect);
+            }
+            mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
+            mTmpRect.offset(-mAltTmpRect.left, -mAltTmpRect.top);
+            return mTmpRect.contains(x, y);
+        }
+        return false;
+    }
+
+    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {}
+
+    private void onDropToDelete() {
+        final View dragView = mDragView;
+
+        final float toScale = 0f;
+        final float toAlpha = 0f;
+
+        // Create and start the complex animation
+        ArrayList<Animator> animations = new ArrayList<Animator>();
+        AnimatorSet motionAnim = new AnimatorSet();
+        motionAnim.setInterpolator(new DecelerateInterpolator(2));
+        motionAnim.playTogether(
+                ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
+                ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
+        animations.add(motionAnim);
+
+        AnimatorSet alphaAnim = new AnimatorSet();
+        alphaAnim.setInterpolator(new LinearInterpolator());
+        alphaAnim.playTogether(
+                ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
+        animations.add(alphaAnim);
+
+        mDeleteString = getContext().getResources()
+                .getString(R.string.keyguard_accessibility_widget_deleted,
+                        mDragView.getContentDescription());
+        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
+
+        AnimatorSet anim = new AnimatorSet();
+        anim.playTogether(animations);
+        anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                onAnimationEndRunnable.run();
+            }
+        });
+        anim.start();
+
+        mDeferringForDelete = true;
+    }
+
+    /* Accessibility */
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setScrollable(getPageCount() > 1);
+        if (getCurrentPage() < getPageCount() - 1) {
+            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+        }
+        if (getCurrentPage() > 0) {
+            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setScrollable(true);
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+            event.setFromIndex(mCurrentPage);
+            event.setToIndex(mCurrentPage);
+            event.setItemCount(getChildCount());
+        }
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (super.performAccessibilityAction(action, arguments)) {
+            return true;
+        }
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                if (getCurrentPage() < getPageCount() - 1) {
+                    scrollRight();
+                    return true;
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                if (getCurrentPage() > 0) {
+                    scrollLeft();
+                    return true;
+                }
+            } break;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onHoverEvent(android.view.MotionEvent event) {
+        return true;
+    }
+
+    void beginCameraEvent() {
+        mIsCameraEvent = true;
+    }
+
+    void endCameraEvent() {
+        mIsCameraEvent = false;
+    }
+
+    private void animateWarpPageOnScreen() {
+        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen()");
+        if (mPageWarpIndex != -1) {
+            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
+            if (DEBUG_WARP) Log.v(TAG, "moving page on screen: Tx=" + v.getTranslationX());
+            v.animate().translationX(mWarpPeekAmount).setDuration(WARP_PEEK_ANIMATION_DURATION);
+        }
+    }
+
+    private void animateWarpPageOffScreen() {
+        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen()");
+        if (mPageWarpIndex != -1) {
+            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
+            if (DEBUG_WARP) Log.v(TAG, "moving page off screen: Tx=" + v.getTranslationX());
+            v.animate().translationX(0.0f).setDuration(WARP_PEEK_ANIMATION_DURATION);
+        }
+    }
+
+    /**
+     * Swaps the position of the views by setting the left and right edges appropriately.
+     */
+    void swapPages(int indexA, int indexB) {
+        View viewA = getPageAt(indexA);
+        View viewB = getPageAt(indexB);
+        if (viewA != viewB && viewA != null && viewB != null) {
+            int deltaX = viewA.getLeft() - viewB.getLeft();
+            viewA.offsetLeftAndRight(-deltaX);
+            viewB.offsetLeftAndRight(deltaX);
+        }
+    }
+
+    public void startWarp(int pageIndex) {
+        if (DEBUG_WARP) Log.v(TAG, "START WARP");
+        if (pageIndex != mCurrentPage + 1) {
+            mPageSwapIndex = mCurrentPage + 1;
+        }
+        mPageWarpIndex = pageIndex;
+    }
+
+    protected int getPageWarpIndex() {
+        return mPageWarpIndex;
+    }
+
+    public void endWarp() {
+        if (DEBUG_WARP) Log.v(TAG, "END WARP");
+        // mPageSwapIndex is reset in snapToPage() after the scroll animation completes
+    }
+
+    public void onPageBeginWarp() {
+
+    }
+
+    public void onPageEndWarp() {
+
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/SecurityMessageDisplay.java b/packages/Keyguard/src/com/android/keyguard/SecurityMessageDisplay.java
new file mode 100644
index 0000000..e2f91e3
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/SecurityMessageDisplay.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+public interface SecurityMessageDisplay {
+    public void setMessage(CharSequence msg, boolean important);
+
+    public void setMessage(int resId, boolean important);
+
+    public void setMessage(int resId, boolean important, Object... formatArgs);
+
+    public void setTimeout(int timeout_ms);
+
+    public void showBouncer(int animationDuration);
+
+    public void hideBouncer(int animationDuration);
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
new file mode 100644
index 0000000..9718c9b
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
@@ -0,0 +1,1267 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatProperty;
+import android.util.Log;
+import android.util.Property;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Interpolator;
+import android.widget.Scroller;
+
+/**
+ * This layout handles interaction with the sliding security challenge views
+ * that overlay/resize other keyguard contents.
+ */
+public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout {
+    private static final String TAG = "SlidingChallengeLayout";
+    private static final boolean DEBUG = false;
+
+    // The drag handle is measured in dp above & below the top edge of the
+    // challenge view; these parameters change based on whether the challenge 
+    // is open or closed.
+    private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp
+    private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
+    private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
+    private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
+
+    private static final int HANDLE_ANIMATE_DURATION = 250; // ms
+
+    // Drawn to show the drag handle in closed state; crossfades to the challenge view
+    // when challenge is fully visible
+    private boolean mEdgeCaptured;
+
+    private DisplayMetrics mDisplayMetrics;
+
+    // Initialized during measurement from child layoutparams
+    private View mExpandChallengeView;
+    private KeyguardSecurityContainer mChallengeView;
+    private View mScrimView;
+    private View mWidgetsView;
+
+    // Range: 0 (fully hidden) to 1 (fully visible)
+    private float mChallengeOffset = 1.f;
+    private boolean mChallengeShowing = true;
+    private boolean mChallengeShowingTargetState = true;
+    private boolean mWasChallengeShowing = true;
+    private boolean mIsBouncing = false;
+
+    private final Scroller mScroller;
+    private ObjectAnimator mFader;
+    private int mScrollState;
+    private OnChallengeScrolledListener mScrollListener;
+    private OnBouncerStateChangedListener mBouncerListener;
+
+    public static final int SCROLL_STATE_IDLE = 0;
+    public static final int SCROLL_STATE_DRAGGING = 1;
+    public static final int SCROLL_STATE_SETTLING = 2;
+    public static final int SCROLL_STATE_FADING = 3;
+
+    private static final int CHALLENGE_FADE_OUT_DURATION = 100;
+    private static final int CHALLENGE_FADE_IN_DURATION = 160;
+
+    private static final int MAX_SETTLE_DURATION = 600; // ms
+
+    // ID of the pointer in charge of a current drag
+    private int mActivePointerId = INVALID_POINTER;
+    private static final int INVALID_POINTER = -1;
+
+    // True if the user is currently dragging the slider
+    private boolean mDragging;
+    // True if the user may not drag until a new gesture begins
+    private boolean mBlockDrag;
+
+    private VelocityTracker mVelocityTracker;
+    private int mMinVelocity;
+    private int mMaxVelocity;
+    private float mGestureStartX, mGestureStartY; // where did you first touch the screen?
+    private int mGestureStartChallengeBottom; // where was the challenge at that time?
+
+    private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view
+    private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line
+    private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view
+    private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line
+
+    private int mDragHandleEdgeSlop;
+    private int mChallengeBottomBound; // Number of pixels from the top of the challenge view
+                                       // that should remain on-screen
+
+    private int mTouchSlop;
+    private int mTouchSlopSquare;
+
+    float mHandleAlpha;
+    float mFrameAlpha;
+    float mFrameAnimationTarget = Float.MIN_VALUE;
+    private ObjectAnimator mHandleAnimation;
+    private ObjectAnimator mFrameAnimation;
+
+    private boolean mHasGlowpad;
+    private final Rect mInsets = new Rect();
+
+    // We have an internal and external version, and we and them together.
+    private boolean mChallengeInteractiveExternal = true;
+    private boolean mChallengeInteractiveInternal = true;
+
+    static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
+            new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
+        @Override
+        public void setValue(SlidingChallengeLayout view, float value) {
+            view.mHandleAlpha = value;
+            view.invalidate();
+        }
+
+        @Override
+        public Float get(SlidingChallengeLayout view) {
+            return view.mHandleAlpha;
+        }
+    };
+
+    // True if at least one layout pass has happened since the view was attached.
+    private boolean mHasLayout;
+
+    private static final Interpolator sMotionInterpolator = new Interpolator() {
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    private static final Interpolator sHandleFadeInterpolator = new Interpolator() {
+        public float getInterpolation(float t) {
+            return t * t;
+        }
+    };
+
+    private final Runnable mEndScrollRunnable = new Runnable () {
+        public void run() {
+            completeChallengeScroll();
+        }
+    };
+
+    private final OnClickListener mScrimClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            hideBouncer();
+        }
+    };
+
+    private final OnClickListener mExpandChallengeClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (!isChallengeShowing()) {
+                showChallenge(true);
+            }
+        }
+    };
+
+    /**
+     * Listener interface that reports changes in scroll state of the challenge area.
+     */
+    public interface OnChallengeScrolledListener {
+        /**
+         * The scroll state itself changed.
+         *
+         * <p>scrollState will be one of the following:</p>
+         *
+         * <ul>
+         * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li>
+         * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging
+         * the challenge area.</li>
+         * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating
+         * into place.</li>
+         * </ul>
+         *
+         * <p>Do not perform expensive operations (e.g. layout)
+         * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p>
+         *
+         * @param scrollState The new scroll state of the challenge area.
+         */
+        public void onScrollStateChanged(int scrollState);
+
+        /**
+         * The precise position of the challenge area has changed.
+         *
+         * <p>NOTE: It is NOT safe to modify layout or call any View methods that may
+         * result in a requestLayout anywhere in your view hierarchy as a result of this call.
+         * It may be called during drawing.</p>
+         *
+         * @param scrollPosition New relative position of the challenge area.
+         *                       1.f = fully visible/ready to be interacted with.
+         *                       0.f = fully invisible/inaccessible to the user.
+         * @param challengeTop Position of the top edge of the challenge view in px in the
+         *                     SlidingChallengeLayout's coordinate system.
+         */
+        public void onScrollPositionChanged(float scrollPosition, int challengeTop);
+    }
+
+    public SlidingChallengeLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingChallengeLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        mScroller = new Scroller(context, sMotionInterpolator);
+
+        final ViewConfiguration vc = ViewConfiguration.get(context);
+        mMinVelocity = vc.getScaledMinimumFlingVelocity();
+        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
+
+        final Resources res = getResources();
+        mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
+
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mTouchSlopSquare = mTouchSlop * mTouchSlop;
+
+        mDisplayMetrics = res.getDisplayMetrics();
+        final float density = mDisplayMetrics.density;
+
+        // top half of the lock icon, plus another 25% to be sure
+        mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
+        mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f);
+        mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f);
+        mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
+
+        // how much space to account for in the handle when closed
+        mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
+
+        setWillNotDraw(false);
+        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE);
+    }
+
+    public void setInsets(Rect insets) {
+        mInsets.set(insets);
+    }
+
+    public void setHandleAlpha(float alpha) {
+        if (mExpandChallengeView != null) {
+            mExpandChallengeView.setAlpha(alpha);
+        }
+    }
+
+    public void setChallengeInteractive(boolean interactive) {
+        mChallengeInteractiveExternal = interactive;
+        if (mExpandChallengeView != null) {
+            mExpandChallengeView.setEnabled(interactive);
+        }
+    }
+
+    void animateHandle(boolean visible) {
+        if (mHandleAnimation != null) {
+            mHandleAnimation.cancel();
+            mHandleAnimation = null;
+        }
+        final float targetAlpha = visible ? 1.f : 0.f;
+        if (targetAlpha == mHandleAlpha) {
+            return;
+        }
+        mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha);
+        mHandleAnimation.setInterpolator(sHandleFadeInterpolator);
+        mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION);
+        mHandleAnimation.start();
+    }
+
+    private void sendInitialListenerUpdates() {
+        if (mScrollListener != null) {
+            int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0;
+            mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop);
+            mScrollListener.onScrollStateChanged(mScrollState);
+        }
+    }
+
+    public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) {
+        mScrollListener = listener;
+        if (mHasLayout) {
+            sendInitialListenerUpdates();
+        }
+    }
+
+    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
+        mBouncerListener = listener;
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        mHasLayout = false;
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        removeCallbacks(mEndScrollRunnable);
+        mHasLayout = false;
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        if (mIsBouncing && child != mChallengeView) {
+            // Clear out of the bouncer if the user tries to move focus outside of
+            // the security challenge view.
+            hideBouncer();
+        }
+        super.requestChildFocus(child, focused);
+    }
+
+    // We want the duration of the page snap animation to be influenced by the distance that
+    // the screen has to travel, however, we don't want this duration to be effected in a
+    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+    // of travel has on the overall snap duration.
+    float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    void setScrollState(int state) {
+        if (mScrollState != state) {
+            mScrollState = state;
+
+            animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
+            if (mScrollListener != null) {
+                mScrollListener.onScrollStateChanged(state);
+            }
+        }
+    }
+
+    void completeChallengeScroll() {
+        setChallengeShowing(mChallengeShowingTargetState);
+        mChallengeOffset = mChallengeShowing ? 1.f : 0.f;
+        setScrollState(SCROLL_STATE_IDLE);
+        mChallengeInteractiveInternal = true;
+        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
+    }
+
+    void setScrimView(View scrim) {
+        if (mScrimView != null) {
+            mScrimView.setOnClickListener(null);
+        }
+        mScrimView = scrim;
+        if (mScrimView != null) {
+            mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
+            mScrimView.setFocusable(true);
+            mScrimView.setOnClickListener(mScrimClickListener);
+        }
+    }
+
+    /**
+     * Animate the bottom edge of the challenge view to the given position.
+     *
+     * @param y desired final position for the bottom edge of the challenge view in px
+     * @param velocity velocity in
+     */
+    void animateChallengeTo(int y, int velocity) {
+        if (mChallengeView == null) {
+            // Nothing to do.
+            return;
+        }
+
+        cancelTransitionsInProgress();
+
+        mChallengeInteractiveInternal = false;
+        enableHardwareLayerForChallengeView();
+        final int sy = mChallengeView.getBottom();
+        final int dy = y - sy;
+        if (dy == 0) {
+            completeChallengeScroll();
+            return;
+        }
+
+        setScrollState(SCROLL_STATE_SETTLING);
+
+        final int childHeight = mChallengeView.getHeight();
+        final int halfHeight = childHeight / 2;
+        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight);
+        final float distance = halfHeight + halfHeight *
+                distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration = 0;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float childDelta = (float) Math.abs(dy) / childHeight;
+            duration = (int) ((childDelta + 1) * 100);
+        }
+        duration = Math.min(duration, MAX_SETTLE_DURATION);
+
+        mScroller.startScroll(0, sy, 0, dy, duration);
+        postInvalidateOnAnimation();
+    }
+
+    private void setChallengeShowing(boolean showChallenge) {
+        if (mChallengeShowing == showChallenge) {
+            return;
+        }
+        mChallengeShowing = showChallenge;
+
+        if (mExpandChallengeView == null || mChallengeView == null) {
+            // These might not be here yet if we haven't been through layout.
+            // If we haven't, the first layout pass will set everything up correctly
+            // based on mChallengeShowing as set above.
+            return;
+        }
+
+        if (mChallengeShowing) {
+            mExpandChallengeView.setVisibility(View.INVISIBLE);
+            mChallengeView.setVisibility(View.VISIBLE);
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                mChallengeView.requestAccessibilityFocus();
+                mChallengeView.announceForAccessibility(mContext.getString(
+                        R.string.keyguard_accessibility_unlock_area_expanded));
+            }
+        } else {
+            mExpandChallengeView.setVisibility(View.VISIBLE);
+            mChallengeView.setVisibility(View.INVISIBLE);
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                mExpandChallengeView.requestAccessibilityFocus();
+                mChallengeView.announceForAccessibility(mContext.getString(
+                        R.string.keyguard_accessibility_unlock_area_collapsed));
+            }
+        }
+    }
+
+    /**
+     * @return true if the challenge is at all visible.
+     */
+    public boolean isChallengeShowing() {
+        return mChallengeShowing;
+    }
+
+    @Override
+    public boolean isChallengeOverlapping() {
+        return mChallengeShowing;
+    }
+
+    @Override
+    public boolean isBouncing() {
+        return mIsBouncing;
+    }
+
+    @Override
+    public int getBouncerAnimationDuration() {
+        return HANDLE_ANIMATE_DURATION;
+    }
+
+    @Override
+    public void showBouncer() {
+        if (mIsBouncing) return;
+        mWasChallengeShowing = mChallengeShowing;
+        mIsBouncing = true;
+        showChallenge(true);
+        if (mScrimView != null) {
+            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
+            anim.setDuration(HANDLE_ANIMATE_DURATION);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mScrimView.setVisibility(VISIBLE);
+                }
+            });
+            anim.start();
+        }
+        if (mChallengeView != null) {
+            mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION);
+        }
+
+        if (mBouncerListener != null) {
+            mBouncerListener.onBouncerStateChanged(true);
+        }
+    }
+
+    @Override
+    public void hideBouncer() {
+        if (!mIsBouncing) return;
+        if (!mWasChallengeShowing) showChallenge(false);
+        mIsBouncing = false;
+
+        if (mScrimView != null) {
+            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
+            anim.setDuration(HANDLE_ANIMATE_DURATION);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mScrimView.setVisibility(GONE);
+                }
+            });
+            anim.start();
+        }
+        if (mChallengeView != null) {
+            mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION);
+        }
+        if (mBouncerListener != null) {
+            mBouncerListener.onBouncerStateChanged(false);
+        }
+    }
+
+    private int getChallengeMargin(boolean expanded) {
+        return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
+    }
+
+    private float getChallengeAlpha() {
+        float x = mChallengeOffset - 1;
+        return x * x * x + 1.f;
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
+        // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
+        // If there are one or more pointers in the challenge view before we take over
+        // touch events, onInterceptTouchEvent will set mBlockDrag.
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mGestureStartX = ev.getX();
+                mGestureStartY = ev.getY();
+                mBlockDrag = false;
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                resetTouch();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final int count = ev.getPointerCount();
+                for (int i = 0; i < count; i++) {
+                    final float x = ev.getX(i);
+                    final float y = ev.getY(i);
+                    if (!mIsBouncing && mActivePointerId == INVALID_POINTER
+                                && (crossedDragHandle(x, y, mGestureStartY)
+                                || (isInChallengeView(x, y) &&
+                                        mScrollState == SCROLL_STATE_SETTLING))) {
+                        mActivePointerId = ev.getPointerId(i);
+                        mGestureStartX = x;
+                        mGestureStartY = y;
+                        mGestureStartChallengeBottom = getChallengeBottom();
+                        mDragging = true;
+                        enableHardwareLayerForChallengeView();
+                    } else if (mChallengeShowing && isInChallengeView(x, y)) {
+                        mBlockDrag = true;
+                    }
+                }
+                break;
+        }
+
+        if (mBlockDrag || isChallengeInteractionBlocked()) {
+            mActivePointerId = INVALID_POINTER;
+            mDragging = false;
+        }
+
+        return mDragging;
+    }
+
+    private boolean isChallengeInteractionBlocked() {
+        return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal;
+    }
+
+    private void resetTouch() {
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+        mActivePointerId = INVALID_POINTER;
+        mDragging = mBlockDrag = false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mBlockDrag = false;
+                mGestureStartX = ev.getX();
+                mGestureStartY = ev.getY();
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                if (mDragging && !isChallengeInteractionBlocked()) {
+                    showChallenge(0);
+                }
+                resetTouch();
+                break;
+
+            case MotionEvent.ACTION_POINTER_UP:
+                if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) {
+                    break;
+                }
+            case MotionEvent.ACTION_UP:
+                if (mDragging && !isChallengeInteractionBlocked()) {
+                    mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
+                    showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
+                }
+                resetTouch();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (!mDragging && !mBlockDrag && !mIsBouncing) {
+                    final int count = ev.getPointerCount();
+                    for (int i = 0; i < count; i++) {
+                        final float x = ev.getX(i);
+                        final float y = ev.getY(i);
+
+                        if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
+                                (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
+                                && mActivePointerId == INVALID_POINTER
+                                && !isChallengeInteractionBlocked()) {
+                            mGestureStartX = x;
+                            mGestureStartY = y;
+                            mActivePointerId = ev.getPointerId(i);
+                            mGestureStartChallengeBottom = getChallengeBottom();
+                            mDragging = true;
+                            enableHardwareLayerForChallengeView();
+                            break;
+                        }
+                    }
+                }
+                // Not an else; this can be set above.
+                if (mDragging) {
+                    // No-op if already in this state, but set it here in case we arrived
+                    // at this point from either intercept or the above.
+                    setScrollState(SCROLL_STATE_DRAGGING);
+
+                    final int index = ev.findPointerIndex(mActivePointerId);
+                    if (index < 0) {
+                        // Oops, bogus state. We lost some touch events somewhere.
+                        // Just drop it with no velocity and let things settle.
+                        resetTouch();
+                        showChallenge(0);
+                        return true;
+                    }
+                    final float y = ev.getY(index);
+                    final float pos = Math.min(y - mGestureStartY,
+                            getLayoutBottom() - mChallengeBottomBound);
+
+                    moveChallengeTo(mGestureStartChallengeBottom + (int) pos);
+                }
+                break;
+        }
+        return true;
+    }
+
+    /**
+     * The lifecycle of touch events is subtle and it's very easy to do something
+     * that will cause bugs that will be nasty to track when overriding this method.
+     * Normally one should always override onInterceptTouchEvent instead.
+     *
+     * To put it another way, don't try this at home.
+     */
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        boolean handled = false;
+        if (action == MotionEvent.ACTION_DOWN) {
+            // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
+            mEdgeCaptured = false;
+        }
+        if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
+            // Normally we would need to do a lot of extra stuff here.
+            // We can only get away with this because we haven't padded in
+            // the widget pager or otherwise transformed it during layout.
+            // We also don't support things like splitting MotionEvents.
+
+            // We set handled to captured even if dispatch is returning false here so that
+            // we don't send a different view a busted or incomplete event stream.
+            handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
+        }
+
+        if (!handled && !mEdgeCaptured) {
+            handled = super.dispatchTouchEvent(ev);
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mEdgeCaptured = false;
+        }
+
+        return handled;
+    }
+
+    private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
+        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
+            return false;
+        }
+
+        final float x = ev.getX();
+        return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
+    }
+
+    /**
+     * We only want to add additional vertical space to the drag handle when the panel is fully
+     * closed.
+     */
+    private int getDragHandleSizeAbove() {
+        return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove;
+    }
+    private int getDragHandleSizeBelow() {
+        return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow;
+    }
+
+    private boolean isInChallengeView(float x, float y) {
+        return isPointInView(x, y, mChallengeView);
+    }
+
+    private boolean isInDragHandle(float x, float y) {
+        return isPointInView(x, y, mExpandChallengeView);
+    }
+
+    private boolean isPointInView(float x, float y, View view) {
+        if (view == null) {
+            return false;
+        }
+        return x >= view.getLeft() && y >= view.getTop()
+                && x < view.getRight() && y < view.getBottom();
+    }
+
+    private boolean crossedDragHandle(float x, float y, float initialY) {
+
+        final int challengeTop = mChallengeView.getTop();
+        final boolean horizOk = x >= 0 && x < getWidth();
+
+        final boolean vertOk;
+        if (mChallengeShowing) {
+            vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) &&
+                    y > challengeTop + getDragHandleSizeBelow();
+        } else {
+            vertOk = initialY > challengeTop + getDragHandleSizeBelow() &&
+                    y < challengeTop - getDragHandleSizeAbove();
+        }
+        return horizOk && vertOk;
+    }
+
+    private int makeChildMeasureSpec(int maxSize, int childDimen) {
+        final int mode;
+        final int size;
+        switch (childDimen) {
+            case LayoutParams.WRAP_CONTENT:
+                mode = MeasureSpec.AT_MOST;
+                size = maxSize;
+                break;
+            case LayoutParams.MATCH_PARENT:
+                mode = MeasureSpec.EXACTLY;
+                size = maxSize;
+                break;
+            default:
+                mode = MeasureSpec.EXACTLY;
+                size = Math.min(maxSize, childDimen);
+                break;
+        }
+        return MeasureSpec.makeMeasureSpec(size, mode);
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
+                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
+            throw new IllegalArgumentException(
+                    "SlidingChallengeLayout must be measured with an exact size");
+        }
+        final int width = MeasureSpec.getSize(widthSpec);
+        final int height = MeasureSpec.getSize(heightSpec);
+        setMeasuredDimension(width, height);
+
+        final int insetHeight = height - mInsets.top - mInsets.bottom;
+        final int insetHeightSpec = MeasureSpec.makeMeasureSpec(insetHeight, MeasureSpec.EXACTLY);
+
+        // Find one and only one challenge view.
+        final View oldChallengeView = mChallengeView;
+        final View oldExpandChallengeView = mChallengeView;
+        mChallengeView = null;
+        mExpandChallengeView = null;
+        final int count = getChildCount();
+
+        // First iteration through the children finds special children and sets any associated
+        // state.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
+                if (mChallengeView != null) {
+                    throw new IllegalStateException(
+                            "There may only be one child with layout_isChallenge=\"true\"");
+                }
+                if (!(child instanceof KeyguardSecurityContainer)) {
+                            throw new IllegalArgumentException(
+                                    "Challenge must be a KeyguardSecurityContainer");
+                }
+                mChallengeView = (KeyguardSecurityContainer) child;
+                if (mChallengeView != oldChallengeView) {
+                    mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
+                }
+                // We're going to play silly games with the frame's background drawable later.
+                if (!mHasLayout) {
+                    // Set up the margin correctly based on our content for the first run.
+                    mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
+                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
+                }
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
+                if (mExpandChallengeView != null) {
+                    throw new IllegalStateException(
+                            "There may only be one child with layout_childType"
+                            + "=\"expandChallengeHandle\"");
+                }
+                mExpandChallengeView = child;
+                if (mExpandChallengeView != oldExpandChallengeView) {
+                    mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE);
+                    mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener);
+                }
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
+                setScrimView(child);
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
+                mWidgetsView = child;
+            }
+        }
+
+        // We want to measure the challenge view first, since the KeyguardWidgetPager
+        // needs to do things its measure pass that are dependent on the challenge view
+        // having been measured.
+        if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) {
+            // This one's a little funny. If the IME is present - reported in the form
+            // of insets on the root view - we only give the challenge the space it would
+            // have had if the IME wasn't there in order to keep the rest of the layout stable.
+            // We base this on the layout_maxHeight on the challenge view. If it comes out
+            // negative or zero, either we didn't have a maxHeight or we're totally out of space,
+            // so give up and measure as if this rule weren't there.
+            int challengeHeightSpec = insetHeightSpec;
+            final View root = getRootView();
+            if (root != null) {
+                final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
+                final int windowHeight = mDisplayMetrics.heightPixels
+                        - root.getPaddingTop() - mInsets.top;
+                final int diff = windowHeight - insetHeight;
+                final int maxChallengeHeight = lp.maxHeight - diff;
+                if (maxChallengeHeight > 0) {
+                    challengeHeightSpec = makeChildMeasureSpec(maxChallengeHeight, lp.height);
+                }
+            }
+            measureChildWithMargins(mChallengeView, widthSpec, 0, challengeHeightSpec, 0);
+        }
+
+        // Measure the rest of the children
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            // Don't measure the challenge view twice!
+            if (child == mChallengeView) continue;
+
+            // Measure children. Widget frame measures special, so that we can ignore
+            // insets for the IME.
+            int parentWidthSpec = widthSpec, parentHeightSpec = insetHeightSpec;
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
+                final View root = getRootView();
+                if (root != null) {
+                    // This calculation is super dodgy and relies on several assumptions.
+                    // Specifically that the root of the window will be padded in for insets
+                    // and that the window is LAYOUT_IN_SCREEN.
+                    final int windowWidth = mDisplayMetrics.widthPixels;
+                    final int windowHeight = mDisplayMetrics.heightPixels
+                            - root.getPaddingTop() - mInsets.top;
+                    parentWidthSpec = MeasureSpec.makeMeasureSpec(
+                            windowWidth, MeasureSpec.EXACTLY);
+                    parentHeightSpec = MeasureSpec.makeMeasureSpec(
+                            windowHeight, MeasureSpec.EXACTLY);
+                }
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
+                // Allow scrim views to extend into the insets
+                parentWidthSpec = widthSpec;
+                parentHeightSpec = heightSpec;
+            }
+            measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int paddingLeft = getPaddingLeft();
+        final int paddingTop = getPaddingTop();
+        final int paddingRight = getPaddingRight();
+        final int paddingBottom = getPaddingBottom();
+        final int width = r - l;
+        final int height = b - t;
+
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) continue;
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
+                // Challenge views pin to the bottom, offset by a portion of their height,
+                // and center horizontally.
+                final int center = (paddingLeft + width - paddingRight) / 2;
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+                final int left = center - childWidth / 2;
+                final int layoutBottom = height - paddingBottom - lp.bottomMargin - mInsets.bottom;
+                // We use the top of the challenge view to position the handle, so
+                // we never want less than the handle size showing at the bottom.
+                final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
+                        * (1 - mChallengeOffset));
+                child.setAlpha(getChallengeAlpha());
+                child.layout(left, bottom - childHeight, left + childWidth, bottom);
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
+                final int center = (paddingLeft + width - paddingRight) / 2;
+                final int left = center - child.getMeasuredWidth() / 2;
+                final int right = left + child.getMeasuredWidth();
+                final int bottom = height - paddingBottom - lp.bottomMargin - mInsets.bottom;
+                final int top = bottom - child.getMeasuredHeight();
+                child.layout(left, top, right, bottom);
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
+                // Scrim views use the entire area, including padding & insets
+                child.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+            } else {
+                // Non-challenge views lay out from the upper left, layered.
+                child.layout(paddingLeft + lp.leftMargin,
+                        paddingTop + lp.topMargin + mInsets.top,
+                        paddingLeft + child.getMeasuredWidth(),
+                        paddingTop + child.getMeasuredHeight() + mInsets.top);
+            }
+        }
+
+        if (!mHasLayout) {
+            mHasLayout = true;
+        }
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+        if (DEBUG) {
+            final Paint debugPaint = new Paint();
+            debugPaint.setColor(0x40FF00CC);
+            // show the isInDragHandle() rect
+            c.drawRect(mDragHandleEdgeSlop,
+                    mChallengeView.getTop() - getDragHandleSizeAbove(),
+                    getWidth() - mDragHandleEdgeSlop,
+                    mChallengeView.getTop() + getDragHandleSizeBelow(),
+                    debugPaint);
+        }
+    }
+
+    public void computeScroll() {
+        super.computeScroll();
+
+        if (!mScroller.isFinished()) {
+            if (mChallengeView == null) {
+                // Can't scroll if the view is missing.
+                Log.e(TAG, "Challenge view missing in computeScroll");
+                mScroller.abortAnimation();
+                return;
+            }
+
+            mScroller.computeScrollOffset();
+            moveChallengeTo(mScroller.getCurrY());
+
+            if (mScroller.isFinished()) {
+                post(mEndScrollRunnable);
+            }
+        }
+    }
+
+    private void cancelTransitionsInProgress() {
+        if (!mScroller.isFinished()) {
+            mScroller.abortAnimation();
+            completeChallengeScroll();
+        }
+        if (mFader != null) {
+            mFader.cancel();
+        }
+    }
+
+    public void fadeInChallenge() {
+        fadeChallenge(true);
+    }
+
+    public void fadeOutChallenge() {
+        fadeChallenge(false);
+    }
+
+    public void fadeChallenge(final boolean show) {
+        if (mChallengeView != null) {
+
+            cancelTransitionsInProgress();
+            float alpha = show ? 1f : 0f;
+            int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION;
+            mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha);
+            mFader.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    onFadeStart(show);
+                }
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    onFadeEnd(show);
+                }
+            });
+            mFader.setDuration(duration);
+            mFader.start();
+        }
+    }
+
+    private int getMaxChallengeBottom() {
+        if (mChallengeView == null) return 0;
+        final int layoutBottom = getLayoutBottom();
+        final int challengeHeight = mChallengeView.getMeasuredHeight();
+
+        return (layoutBottom + challengeHeight - mChallengeBottomBound);
+    }
+
+    private int getMinChallengeBottom() {
+        return getLayoutBottom();
+    }
+
+
+    private void onFadeStart(boolean show) {
+        mChallengeInteractiveInternal = false;
+        enableHardwareLayerForChallengeView();
+
+        if (show) {
+            moveChallengeTo(getMinChallengeBottom());
+        }
+
+        setScrollState(SCROLL_STATE_FADING);
+    }
+
+    private void enableHardwareLayerForChallengeView() {
+        if (mChallengeView.isHardwareAccelerated()) {
+            mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
+        }
+    }
+
+    private void onFadeEnd(boolean show) {
+        mChallengeInteractiveInternal = true;
+        setChallengeShowing(show);
+
+        if (!show) {
+            moveChallengeTo(getMaxChallengeBottom());
+        }
+
+        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
+        mFader = null;
+        setScrollState(SCROLL_STATE_IDLE);
+    }
+
+    public int getMaxChallengeTop() {
+        if (mChallengeView == null) return 0;
+
+        final int layoutBottom = getLayoutBottom();
+        final int challengeHeight = mChallengeView.getMeasuredHeight();
+        return layoutBottom - challengeHeight - mInsets.top;
+    }
+
+    /**
+     * Move the bottom edge of mChallengeView to a new position and notify the listener
+     * if it represents a change in position. Changes made through this method will
+     * be stable across layout passes. If this method is called before first layout of
+     * this SlidingChallengeLayout it will have no effect.
+     *
+     * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system.
+     * @return true if the challenge view was moved
+     */
+    private boolean moveChallengeTo(int bottom) {
+        if (mChallengeView == null || !mHasLayout) {
+            return false;
+        }
+
+        final int layoutBottom = getLayoutBottom();
+        final int challengeHeight = mChallengeView.getHeight();
+
+        bottom = Math.max(getMinChallengeBottom(),
+                Math.min(bottom, getMaxChallengeBottom()));
+
+        float offset = 1.f - (float) (bottom - layoutBottom) /
+                (challengeHeight - mChallengeBottomBound);
+        mChallengeOffset = offset;
+        if (offset > 0 && !mChallengeShowing) {
+            setChallengeShowing(true);
+        }
+
+        mChallengeView.layout(mChallengeView.getLeft(),
+                bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
+
+        mChallengeView.setAlpha(getChallengeAlpha());
+        if (mScrollListener != null) {
+            mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
+        }
+        postInvalidateOnAnimation();
+        return true;
+    }
+
+    /**
+     * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with
+     * the bottom edge of mChallengeView when the challenge is fully opened.
+     */
+    private int getLayoutBottom() {
+        final int bottomMargin = (mChallengeView == null)
+                ? 0
+                : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
+        final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin
+                - mInsets.bottom;
+        return layoutBottom;
+    }
+
+    /**
+     * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'.
+     */
+    private int getChallengeBottom() {
+        if (mChallengeView == null) return 0;
+
+        return mChallengeView.getBottom();
+    }
+
+    /**
+     * Show or hide the challenge view, animating it if necessary.
+     * @param show true to show, false to hide
+     */
+    public void showChallenge(boolean show) {
+        showChallenge(show, 0);
+        if (!show) {
+            // Block any drags in progress so that callers can use this to disable dragging
+            // for other touch interactions.
+            mBlockDrag = true;
+        }
+    }
+
+    private void showChallenge(int velocity) {
+        boolean show = false;
+        if (Math.abs(velocity) > mMinVelocity) {
+            show = velocity < 0;
+        } else {
+            show = mChallengeOffset >= 0.5f;
+        }
+        showChallenge(show, velocity);
+    }
+
+    private void showChallenge(boolean show, int velocity) {
+        if (mChallengeView == null) {
+            setChallengeShowing(false);
+            return;
+        }
+
+        if (mHasLayout) {
+            mChallengeShowingTargetState = show;
+            final int layoutBottom = getLayoutBottom();
+            animateChallengeTo(show ? layoutBottom :
+                    layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity);
+        }
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
+                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
+                new LayoutParams(p);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    public static class LayoutParams extends MarginLayoutParams {
+        public int childType = CHILD_TYPE_NONE;
+        public static final int CHILD_TYPE_NONE = 0;
+        public static final int CHILD_TYPE_CHALLENGE = 2;
+        public static final int CHILD_TYPE_SCRIM = 4;
+        public static final int CHILD_TYPE_WIDGETS = 5;
+        public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6;
+
+        public int maxHeight;
+
+        public LayoutParams() {
+            this(MATCH_PARENT, WRAP_CONTENT);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            childType = source.childType;
+        }
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs,
+                    R.styleable.SlidingChallengeLayout_Layout);
+            childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType,
+                    CHILD_TYPE_NONE);
+            maxHeight = a.getDimensionPixelSize(
+                    R.styleable.SlidingChallengeLayout_Layout_layout_maxHeight, 0);
+            a.recycle();
+        }
+    }
+}
diff --git a/packages/Keyguard/test/Android.mk b/packages/Keyguard/test/Android.mk
new file mode 100644
index 0000000..15059c6
--- /dev/null
+++ b/packages/Keyguard/test/Android.mk
@@ -0,0 +1,29 @@
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := KeyguardTest
+
+# Remove these to verify permission checks are working correctly
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+# LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/packages/Keyguard/test/AndroidManifest.xml b/packages/Keyguard/test/AndroidManifest.xml
new file mode 100644
index 0000000..b801e4b
--- /dev/null
+++ b/packages/Keyguard/test/AndroidManifest.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.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.keyguard.test">
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17"/>
+    <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+    <application android:label="@string/app_name" android:icon="@drawable/app_icon">
+        <activity android:name=".KeyguardTestActivity"
+                android:label="@string/app_name"
+                android:theme="@android:style/Theme.Holo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/test/res/drawable-hdpi/app_icon.png
similarity index 100%
copy from core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png
copy to packages/Keyguard/test/res/drawable-hdpi/app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/test/res/drawable-mdpi/app_icon.png
similarity index 100%
copy from core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png
copy to packages/Keyguard/test/res/drawable-mdpi/app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/test/res/drawable-xhdpi/app_icon.png
similarity index 100%
copy from core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
copy to packages/Keyguard/test/res/drawable-xhdpi/app_icon.png
Binary files differ
diff --git a/packages/Keyguard/test/res/layout/keyguard_test_activity.xml b/packages/Keyguard/test/res/layout/keyguard_test_activity.xml
new file mode 100644
index 0000000..dab1088
--- /dev/null
+++ b/packages/Keyguard/test/res/layout/keyguard_test_activity.xml
@@ -0,0 +1,47 @@
+<?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.
+*/
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="center">
+
+    <Button android:id="@+id/do_keyguard"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/do_keyguard" />
+
+    <Button android:id="@+id/on_screen_turned_off"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/on_screen_turned_off" />
+
+    <Button android:id="@+id/on_screen_turned_on"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/on_screen_turned_on" />
+
+    <Button android:id="@+id/verify_unlock"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/verify_unlock" />
+
+</LinearLayout>
diff --git a/packages/Keyguard/test/res/menu/optionmenu.xml b/packages/Keyguard/test/res/menu/optionmenu.xml
new file mode 100644
index 0000000..22f300d
--- /dev/null
+++ b/packages/Keyguard/test/res/menu/optionmenu.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/none_menu_item"
+          android:title="@string/none_menu_item" />
+    <item android:id="@+id/pin_menu_item"
+          android:title="@string/pin_menu_item" />
+    <item android:id="@+id/password_menu_item"
+        android:title="@string/password_menu_item" />
+    <item android:id="@+id/pattern_menu_item"
+          android:title="@string/pattern_menu_item" />
+    <item android:id="@+id/sim_pin_menu_item"
+          android:title="@string/sim_pin_menu_item" />
+    <item android:id="@+id/sim_puk_menu_item"
+          android:title="@string/sim_puk_menu_item" />
+    <item android:id="@+id/add_widget_item"
+          android:title="@string/add_widget_item" />
+</menu>
diff --git a/packages/Keyguard/test/res/values/strings.xml b/packages/Keyguard/test/res/values/strings.xml
new file mode 100644
index 0000000..129204b
--- /dev/null
+++ b/packages/Keyguard/test/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">KeyguardTestActivity</string>
+    <string name="secure_app_name">UnifiedCamera</string>
+    <string name="none_menu_item">No security</string>
+    <string name="pin_menu_item">PIN</string>
+    <string name="password_menu_item">Password</string>
+    <string name="pattern_menu_item">Pattern</string>
+    <string name="sim_pin_menu_item">SIM PIN</string>
+    <string name="sim_puk_menu_item">SIM PUK</string>
+    <string name="add_widget_item">Choose widget...</string>
+    <string name="on_screen_turned_off">onScreenTurnedOff</string>
+    <string name="on_screen_turned_on">onScreenTurnedOn</string>
+    <string name="do_keyguard">doKeyguard</string>
+    <string name="verify_unlock">verifyUnlock</string>
+</resources>
diff --git a/packages/Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java b/packages/Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java
new file mode 100644
index 0000000..e89c10e
--- /dev/null
+++ b/packages/Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard.test;
+
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardService;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.WindowManagerPolicy;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternView.Cell;
+
+import java.util.List;
+
+public class KeyguardTestActivity extends Activity implements OnClickListener {
+    private static final String KEYGUARD_PACKAGE = "com.android.keyguard";
+    private static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+    private static final String TAG = "LockScreenTestActivity";
+    private static final int MODE_NONE = 0;
+    private static final int MODE_PIN = 1;
+    private static final int MODE_PASSWORD = 2;
+    private static final int MODE_PATTERN = 3;
+    private static final int MODE_SIM_PIN = 4;
+    private static final int MODE_SIM_PUK = 5;
+    private static final String SECURITY_MODE = "security_mode";
+    Handler mHandler = new Handler();
+
+    IKeyguardService mService = null;
+
+    KeyguardShowCallback mKeyguardShowCallback = new KeyguardShowCallback();
+    KeyguardExitCallback mKeyguardExitCallback = new KeyguardExitCallback();
+
+    RemoteServiceConnection mConnection;
+    private boolean mSentSystemReady;
+
+    class KeyguardShowCallback extends IKeyguardShowCallback.Stub {
+
+        @Override
+        public void onShown(IBinder windowToken) throws RemoteException {
+            Log.v(TAG, "Keyguard is shown, windowToken = " + windowToken);
+        }
+    }
+
+    class KeyguardExitCallback extends IKeyguardExitCallback.Stub {
+
+        @Override
+        public void onKeyguardExitResult(final boolean success) throws RemoteException {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    new AlertDialog.Builder(KeyguardTestActivity.this)
+                    .setMessage("Result: " + success)
+                    .setPositiveButton("OK", null)
+                    .show();
+                }
+            });
+        }
+    };
+
+    private class RemoteServiceConnection implements ServiceConnection {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            Log.v(TAG, "onServiceConnected()");
+            mService = IKeyguardService.Stub.asInterface(service);
+            try {
+                mService.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        new AlertDialog.Builder(KeyguardTestActivity.this)
+                            .setMessage("Oops! Keygued died")
+                            .setPositiveButton("OK", null)
+                            .show();
+                    }
+                }, 0);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Couldn't linkToDeath");
+                e.printStackTrace();
+            }
+//            try {
+//                mService.onSystemReady();
+//            } catch (RemoteException e) {
+//                Log.v(TAG, "Remote service died trying to call onSystemReady");
+//                e.printStackTrace();
+//            }
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            Log.v(TAG, "onServiceDisconnected()");
+            mService = null;
+        }
+    };
+
+    private void bindService() {
+        if (mConnection == null) {
+            mConnection = new RemoteServiceConnection();
+            Intent intent = new Intent();
+            intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+            Log.v(TAG, "BINDING SERVICE: " + KEYGUARD_CLASS);
+            if (!bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+                Log.v(TAG, "FAILED TO BIND TO KEYGUARD!");
+            }
+        } else {
+            Log.v(TAG, "Service already bound");
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.keyguard_test_activity);
+        final int[] buttons = {
+                R.id.on_screen_turned_off, R.id.on_screen_turned_on,
+                R.id.do_keyguard, R.id.verify_unlock
+        };
+        for (int i = 0; i < buttons.length; i++) {
+            findViewById(buttons[i]).setOnClickListener(this);
+        }
+        Log.v(TAG, "Binding service...");
+        bindService();
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(SECURITY_MODE, mSecurityMode);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        setMode(savedInstanceState.getInt(SECURITY_MODE));
+    }
+
+// TODO: Find a secure way to inject mock into keyguard...
+//    @Override
+//    public boolean onCreateOptionsMenu(Menu menu) {
+//        MenuInflater inflater = getMenuInflater();
+//        inflater.inflate(R.menu.optionmenu, menu);
+//        return true;
+//    }
+
+    private void setMode(int mode) {
+        mTestSimPin = false;
+        mTestSimPuk = false;
+        mLockPasswordEnabled = false;
+        mLockPatternEnabled = false;
+        switch(mode) {
+            case MODE_NONE:
+                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                break;
+            case MODE_PIN:
+                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+                mLockPasswordEnabled = true;
+                break;
+            case MODE_PASSWORD:
+                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+                mLockPasswordEnabled = true;
+                break;
+            case MODE_PATTERN:
+                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+                mLockPatternEnabled = true;
+                break;
+            case MODE_SIM_PIN:
+                mTestSimPin = true;
+                break;
+            case MODE_SIM_PUK:
+                mTestSimPuk = true;
+                break;
+        }
+        mSecurityMode = mode;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle item selection
+        switch (item.getItemId()) {
+            case R.id.none_menu_item:
+                setMode(MODE_NONE);
+                break;
+            case R.id.pin_menu_item:
+                setMode(MODE_PIN);
+                break;
+            case R.id.password_menu_item:
+                setMode(MODE_PASSWORD);
+                break;
+            case R.id.pattern_menu_item:
+                setMode(MODE_PATTERN);
+                break;
+            case R.id.sim_pin_menu_item:
+                setMode(MODE_SIM_PIN);
+                break;
+            case R.id.sim_puk_menu_item:
+                setMode(MODE_SIM_PUK);
+                break;
+            case R.id.add_widget_item:
+                startWidgetPicker();
+                break;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+        try {
+            mService.doKeyguardTimeout(null);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote service died");
+            e.printStackTrace();
+        }
+        return true;
+    }
+
+    private void startWidgetPicker() {
+        startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
+    }
+
+    @Override
+    public void onClick(View v) {
+        try {
+            switch (v.getId()) {
+            case R.id.on_screen_turned_on:
+                mService.onScreenTurnedOn(mKeyguardShowCallback);
+                break;
+            case R.id.on_screen_turned_off:
+                mService.onScreenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+                break;
+            case R.id.do_keyguard:
+                if (!mSentSystemReady) {
+                    mSentSystemReady = true;
+                    mService.onSystemReady();
+                }
+                mService.doKeyguardTimeout(null);
+                break;
+            case R.id.verify_unlock:
+                mService.doKeyguardTimeout(null);
+                // Wait for keyguard to lock and then try this...
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            mService.verifyUnlock(mKeyguardExitCallback);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Failed verifyUnlock()", e);
+                        }
+                    }
+                }, 5000);
+                break;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "onClick(): Failed due to remote exeption", e);
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        try {
+            if (mService != null) {
+                mService.setHidden(true);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote service died");
+            e.printStackTrace();
+        }
+    }
+
+    protected void onResume() {
+        super.onResume();
+        try {
+            if (mService != null) {
+                mService.setHidden(false);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote service died");
+            e.printStackTrace();
+        }
+    }
+
+    public int mSecurityModeMock;
+    private boolean mTestSimPin;
+    private boolean mTestSimPuk;
+    private boolean mLockPasswordEnabled;
+    public boolean mLockPatternEnabled;
+    private int mSecurityMode;
+
+    class LockPatternUtilsMock extends LockPatternUtils {
+        private long mDeadline;
+        public LockPatternUtilsMock(Context context) {
+            super(context);
+        }
+
+        @Override
+        public boolean checkPattern(List<Cell> pattern) {
+            return pattern.size() > 4;
+        }
+
+        @Override
+        public boolean checkPassword(String password) {
+            return password.length() > 4;
+        }
+        @Override
+        public long setLockoutAttemptDeadline() {
+            final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
+            mDeadline = deadline;
+            return deadline;
+        }
+        @Override
+        public boolean isLockScreenDisabled() {
+            return false;
+        }
+        @Override
+        public long getLockoutAttemptDeadline() {
+            return mDeadline;
+        }
+        @Override
+        public void reportFailedPasswordAttempt() {
+            // Ignored
+        }
+        @Override
+        public void reportSuccessfulPasswordAttempt() {
+            // Ignored
+        }
+        @Override
+        public boolean isLockPatternEnabled() {
+            return mLockPatternEnabled;
+        }
+
+        @Override
+        public boolean isLockPasswordEnabled() {
+            return mLockPasswordEnabled;
+        }
+
+        @Override
+        public int getKeyguardStoredPasswordQuality() {
+            return mSecurityModeMock;
+        }
+
+        public boolean isSecure() {
+            return mLockPatternEnabled || mLockPasswordEnabled || mTestSimPin || mTestSimPuk;
+        }
+
+    }
+}
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
new file mode 100644
index 0000000..9e7b969
--- /dev/null
+++ b/packages/PrintSpooler/Android.mk
@@ -0,0 +1,27 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := PrintSpooler
+
+LOCAL_JAVA_LIBRARIES := framework-base
+
+include $(BUILD_PACKAGE)
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
new file mode 100644
index 0000000..1e6954e
--- /dev/null
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.printspooler"
+        android:versionName="1"
+        android:versionCode="1">
+
+    <!-- Allows an application to call APIs that give it access to all print jobs
+         on the device. Usually an app can access only the print jobs it created. -->
+    <permission
+        android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"
+        android:label="@string/permlab_accessAllPrintJobs"
+        android:description="@string/permdesc_accessAllPrintJobs"
+        android:protectionLevel="signature" />
+
+    <!-- May be required by the settings and add printer activities of a
+         print service if the developer wants only trusted system code to
+         be able to launch these activities. -->
+    <permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+        android:label="@string/permlab_startPrintServiceConfigActivity"
+        android:description="@string/permdesc_startPrintServiceConfigActivity"
+        android:protectionLevel="signature" />
+
+    <uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
+
+    <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
+
+    <application
+            android:allowClearUserData="true"
+            android:label="@string/app_label"
+            android:allowBackup= "false"
+            android:supportsRtl="true">
+
+        <service
+            android:name=".PrintSpoolerService"
+            android:exported="true"
+            android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE">
+        </service>
+
+        <activity
+            android:name=".PrintJobConfigActivity"
+            android:configChanges="orientation|screenSize"
+            android:exported="false"
+            android:theme="@style/PrintJobConfigActivityTheme">
+        </activity>
+
+        <activity
+            android:name=".SelectPrinterActivity"
+            android:label="@string/all_printers_label"
+            android:theme="@style/SelectPrinterActivityTheme"
+            android:exported="false">
+        </activity>
+
+        <receiver
+            android:name=".NotificationController$NotificationBroadcastReceiver"
+            android:exported="false" >
+        </receiver>
+
+    </application>
+
+</manifest>
diff --git a/cmds/system_server/MODULE_LICENSE_APACHE2 b/packages/PrintSpooler/MODULE_LICENSE_APACHE2
similarity index 100%
rename from cmds/system_server/MODULE_LICENSE_APACHE2
rename to packages/PrintSpooler/MODULE_LICENSE_APACHE2
diff --git a/cmds/system_server/NOTICE b/packages/PrintSpooler/NOTICE
similarity index 100%
rename from cmds/system_server/NOTICE
rename to packages/PrintSpooler/NOTICE
diff --git a/packages/PrintSpooler/res/color/item_text_color.xml b/packages/PrintSpooler/res/color/item_text_color.xml
new file mode 100644
index 0000000..f580fbd
--- /dev/null
+++ b/packages/PrintSpooler/res/color/item_text_color.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+   <item android:state_enabled="true" android:color="#333333" />
+   <item android:color="#888888"/>
+</selector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/drawable-hdpi/stat_notify_cancelling.png b/packages/PrintSpooler/res/drawable-hdpi/stat_notify_cancelling.png
new file mode 100644
index 0000000..2757db0
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/stat_notify_cancelling.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/stat_notify_cancelling.png b/packages/PrintSpooler/res/drawable-mdpi/stat_notify_cancelling.png
new file mode 100644
index 0000000..c1b380a
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/stat_notify_cancelling.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/stat_notify_cancelling.png b/packages/PrintSpooler/res/drawable-xhdpi/stat_notify_cancelling.png
new file mode 100644
index 0000000..fedc00e
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/stat_notify_cancelling.png
Binary files differ
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
new file mode 100644
index 0000000..98b5cfe
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
@@ -0,0 +1,23 @@
+<?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:id="@+id/content_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:background="@color/container_background">
+</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
new file mode 100644
index 0000000..83019b9
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
@@ -0,0 +1,230 @@
+<?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"
+    android:background="@color/editable_background">
+
+    <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: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/label_pages">
+                </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>
+
+        <!-- Print button -->
+
+        <ImageView
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_marginTop="24dip"
+            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>
+
+    </LinearLayout>
+
+</ScrollView>
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
new file mode 100644
index 0000000..8bdb6c9
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml
@@ -0,0 +1,73 @@
+<?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:background="@color/editable_background"
+        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>
+
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="@color/separator">
+        </View>
+
+    </LinearLayout>
+
+    <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>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
new file mode 100644
index 0000000..6439b49
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -0,0 +1,70 @@
+<?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:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="16dip"
+        android:paddingEnd="16dip"
+        android:minHeight="?android:attr/listPreferredItemHeightSmall"
+        android:orientation="horizontal"
+        android:gravity="start|center_vertical">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="32dip"
+        android:layout_height="32dip"
+        android:layout_gravity="center_vertical"
+        android:layout_marginEnd="8dip"
+        android:duplicateParentState="true"
+        android:contentDescription="@null"
+        android:visibility="gone">
+    </ImageView>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:textIsSelectable="false"
+            android:gravity="top|start"
+            android:textColor="@color/item_text_color"
+            android:duplicateParentState="true">
+        </TextView>
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:textIsSelectable="false"
+            android:visibility="gone"
+            android:textColor="@color/print_option_title"
+            android:duplicateParentState="true">
+        </TextView>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
new file mode 100644
index 0000000..e86e9aa
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -0,0 +1,64 @@
+<?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:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <fragment
+        android:name="com.android.printspooler.SelectPrinterFragment"
+        android:id="@+id/select_printer_fragment"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+    </fragment>
+
+    <FrameLayout
+        android:id="@+id/empty_print_state"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:visibility="gone">
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:orientation="vertical">
+   
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="12dip"
+                android:src="@*android:drawable/ic_grayedout_printer"
+                android:contentDescription="@string/print_no_printers_found">
+            </ImageView>
+
+            <TextView
+                android:id="@+id/message"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:textColor="?android:attr/textColorSecondary"
+                android:text="@string/print_no_printers_found">
+            </TextView>
+
+        </LinearLayout>
+
+    </FrameLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
new file mode 100644
index 0000000..c3c5021
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
@@ -0,0 +1,52 @@
+<?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:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="8dip"
+    android:paddingEnd="8dip"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:orientation="vertical"
+    android:gravity="start|center_vertical">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textIsSelectable="false"
+        android:gravity="top|left"
+        android:textColor="@color/item_text_color"
+        android:duplicateParentState="true">
+    </TextView>
+
+    <TextView
+        android:id="@+id/subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textIsSelectable="false"
+        android:visibility="gone"
+        android:textColor="@color/print_option_title"
+        android:duplicateParentState="true">
+    </TextView>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/menu/select_printer_activity.xml b/packages/PrintSpooler/res/menu/select_printer_activity.xml
new file mode 100644
index 0000000..d4ce1cf
--- /dev/null
+++ b/packages/PrintSpooler/res/menu/select_printer_activity.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/action_search"
+        android:title="@string/search"
+        android:icon="@*android:drawable/ic_menu_search_holo_light"
+        android:actionViewClass="android.widget.SearchView"
+        android:showAsAction="ifRoom"
+        android:alphabeticShortcut="f"
+        android:imeOptions="actionSearch">
+    </item>
+
+    <item
+        android:id="@+id/action_add_printer"
+        android:title="@null"
+        android:icon="@*android:drawable/create_contact"
+        android:showAsAction="ifRoom"
+        android:alphabeticShortcut="a">
+    </item>
+
+</menu>
diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml
new file mode 100644
index 0000000..9972c96
--- /dev/null
+++ b/packages/PrintSpooler/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resources>
+
+    <color name="container_background">#FFFFFF</color>
+    <color name="important_text">#333333</color>
+    <color name="print_option_title">#888888</color>
+    <color name="separator">#CCCCCC</color>
+    <color name="editable_background">#F2F2F2</color>
+
+</resources>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
new file mode 100644
index 0000000..e5a9d5d
--- /dev/null
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<resources>
+
+    <integer name="page_option_value_all">0</integer>
+    <integer name="page_option_value_page_range">1</integer>
+
+    <integer-array name="page_options_values" translatable="false">
+        <item>@integer/page_option_value_all</item>
+        <item>@integer/page_option_value_page_range</item>
+    </integer-array>
+
+    <dimen name="print_dialog_frame_max_width_dip">400dip</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
new file mode 100644
index 0000000..41775a1
--- /dev/null
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -0,0 +1,164 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Title of the PrintSpooler application. [CHAR LIMIT=50] -->
+    <string name="app_label">Print Spooler</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 destination widget. [CHAR LIMIT=20] -->
+    <string name="label_destination">Destination</string>
+
+    <!-- Label of the copies count widget. [CHAR LIMIT=20] -->
+    <string name="label_copies">Copies</string>
+
+    <!-- Label of the paper size widget. [CHAR LIMIT=20] -->
+    <string name="label_paper_size">Paper Size</string>
+
+    <!-- Label of the color mode widget. [CHAR LIMIT=20] -->
+    <string name="label_color">Color</string>
+
+    <!-- Label of the orientation widget. [CHAR LIMIT=20] -->
+    <string name="label_orientation">Orientation</string>
+
+    <!-- Label of the page selection widget. [CHAR LIMIT=20] -->
+    <string name="label_pages">Pages (<xliff:g id="page_count" example="5">%1$s</xliff:g>)</string>
+
+    <!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=20] -->
+    <string name="pages_range_example">e.g. 1&#8211;5, 8, 11&#8211;13</string>
+
+    <!-- Title for the pring preview button .[CHAR LIMIT=30] -->
+    <string name="print_preview">Print preview</string>
+
+    <!-- Title for the pring preview button if there is no PDF viewer isntalled. [CHAR LIMIT=50] -->
+    <string name="install_for_print_preview">Install PDF viewer for preview</string>
+
+    <!-- Title of the message that the printing application crashed. [CHAR LIMIT=50] -->
+    <string name="printing_app_crashed">Printing app crashed</string>
+
+    <!-- Title if the number of pages in a printed document is unknown. [CHAR LIMIT=20] -->
+    <string name="page_count_unknown">unavailable</string>
+
+    <!-- Title for the temporary dialog show while an app is generating a print job. [CHAR LIMIT=30] -->
+    <string name="generating_print_job">Generating print job</string>
+
+    <!-- Title for the save as PDF option in the printer list. [CHAR LIMIT=30] -->
+    <string name="save_as_pdf">Save as PDF</string>
+
+    <!-- Title for the open all printers UI option in the printer list. [CHAR LIMIT=30] -->
+    <string name="all_printers">All printers&#8230;</string>
+
+    <!-- Select printer activity -->
+
+    <!-- Title for the share action bar menu item. [CHAR LIMIT=20] -->
+    <string name="search">Search</string>
+
+    <!-- Title for the select printer activity. [CHAR LIMIT=30] -->
+    <string name="all_printers_label">All printers</string>
+
+    <!-- Title of the button to install a print service. [CHAR LIMIT=25] -->
+    <string name="add_print_service_label">Add service</string>
+
+    <!-- Add printer dialog  -->
+
+    <!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] -->
+    <string name="choose_print_service">Choose print service</string>
+
+    <!-- Title for the prompt shown as a placeholder if no printers are found while searching. [CHAR LIMIT=50] -->
+    <string name="print_no_printers_found">No printers found</string>
+
+    <!-- Notifications -->
+
+    <!-- Template for the notificaiton 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] -->
+    <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] -->
+    <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] -->
+    <string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
+
+    <!-- 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] -->
+    <string name="restart">Restart</string>
+
+    <!-- Message that there is no connection to a printer. [CHAR LIMIT=40] -->
+    <string name="no_connection_to_printer">No connection to printer</string>
+
+    <!-- Label for an unknown reason for failed or blocked print job. [CHAR LIMIT=25] -->
+    <string name="reason_unknown">unknown</string>
+
+    <!-- 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> &#8211; unavailable</string>
+
+    <!-- Arrays -->
+
+    <!-- Color mode labels. -->
+    <string-array name="color_mode_labels">
+        <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
+        <item>Black &amp; White</item>
+        <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] -->
+        <item>Color</item>
+    </string-array>
+
+    <!-- Orientation labels. -->
+    <string-array name="orientation_labels">
+        <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] -->
+        <item>Portrait</item>
+        <!-- Orientation label: Landscape page orientation [CHAR LIMIT=30] -->
+        <item>Landscape</item>
+    </string-array>
+
+    <!-- Page options labels. -->
+    <string-array name="page_options_labels">
+        <!-- Page range option label: Print all pages [CHAR LIMIT=30] -->
+        <item>All</item>
+        <!-- Page range option label: Print a page range [CHAR LIMIT=30] -->
+        <item>Range</item>
+    </string-array>
+
+    <!-- Permissions -->
+
+    <!-- Title of an application permission, listed so the user can choose whether they want
+         to allow the application to do this. -->
+    <string name="permlab_accessAllPrintJobs" translatable="false">access all print jobs</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_accessAllPrintJobs" translatable="false">Allows the holder to access
+        print jobs created by another app. 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_startPrintServiceConfigActivity" translatable="false">start print
+        service configuration activities</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_startPrintServiceConfigActivity" translatable="false">Allows the
+        holder to start the configuration activities of a print service. Should never be needed
+        for normal apps.</string>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
new file mode 100644
index 0000000..f6db6be
--- /dev/null
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+
+<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>
+        <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+    </style>
+
+    <style name="PrintOptionEditTextStyle">
+         <item name="android:selectAllOnFocus">true</item>
+         <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+         <item name="android:singleLine">true</item>
+         <item name="android:ellipsize">end</item>
+    </style>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
new file mode 100644
index 0000000..bb41527
--- /dev/null
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<resources>
+
+    <style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.Holo.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>
+    </style>
+
+    <style name="SelectPrinterActivityTheme" parent="@android:style/Theme.Holo.Light">
+        <item name="android:actionBarStyle">@style/SelectPrinterActivityActionBarStyle</item>
+    </style>
+
+    <style name="SelectPrinterActivityActionBarStyle" parent="@android:style/Widget.Holo.ActionBar">
+        <item name="android:displayOptions">showTitle</item>
+    </style>
+
+</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
new file mode 100644
index 0000000..65af830
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -0,0 +1,625 @@
+/*
+ * 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.ComponentName;
+import android.content.Context;
+import android.content.Loader;
+import android.content.pm.ServiceInfo;
+import android.os.AsyncTask;
+import android.print.PrintManager;
+import android.print.PrinterDiscoverySession;
+import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.PrintServiceInfo;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import libcore.io.IoUtils;
+
+/**
+ * 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>> {
+    private static final String LOG_TAG = "FusedPrintersProvider";
+
+    private static final boolean DEBUG = false;
+
+    private static final double WEIGHT_DECAY_COEFFICIENT = 0.95f;
+
+    private static final int MAX_HISTORY_LENGTH = 50;
+
+    private static final int MAX_FAVORITE_PRINTER_COUNT = 4;
+
+    private final List<PrinterInfo> mPrinters =
+            new ArrayList<PrinterInfo>();
+
+    private final List<PrinterInfo> mFavoritePrinters =
+            new ArrayList<PrinterInfo>();
+
+    private final PersistenceManager mPersistenceManager;
+
+    private PrinterDiscoverySession mDiscoverySession;
+
+    private PrinterId mTrackedPrinter;
+
+    public FusedPrintersProvider(Context context) {
+        super(context);
+        mPersistenceManager = new PersistenceManager(context);
+    }
+
+    public void addHistoricalPrinter(PrinterInfo printer) {
+        mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
+    }
+
+    private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters) {
+        List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+        // Add the updated favorite printers.
+        final int favoritePrinterCount = mFavoritePrinters.size();
+        for (int i = 0; i < favoritePrinterCount; i++) {
+            PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
+            PrinterInfo updatedPrinter = discoveredPrinters.remove(
+                    favoritePrinter.getId());
+            if (updatedPrinter != null) {
+                printers.add(updatedPrinter);
+            } else {
+                printers.add(favoritePrinter);
+            }
+        }
+
+        // Add other updated printers.
+        final int printerCount = mPrinters.size();
+        for (int i = 0; i < printerCount; i++) {
+            PrinterInfo printer = mPrinters.get(i);
+            PrinterInfo updatedPrinter = discoveredPrinters.remove(
+                    printer.getId());
+            if (updatedPrinter != null) {
+                printers.add(updatedPrinter);
+            }
+        }
+
+        // Add the new printers, i.e. what is left.
+        printers.addAll(discoveredPrinters.values());
+
+        // Update the list of printers.
+        mPrinters.clear();
+        mPrinters.addAll(printers);
+
+        if (isStarted()) {
+            // Deliver the printers.
+            deliverResult(printers);
+        }
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode());
+        }
+        // The contract is that if we already have a valid,
+        // result the we have to deliver it immediately.
+        if (!mPrinters.isEmpty()) {
+            deliverResult(new ArrayList<PrinterInfo>(mPrinters));
+        }
+        // Always load the data to ensure discovery period is
+        // started and to make sure obsolete printers are updated.
+        onForceLoad();
+    }
+
+    @Override
+    protected void onStopLoading() {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onStopLoading() " + FusedPrintersProvider.this.hashCode());
+        }
+        onCancelLoad();
+    }
+
+    @Override
+    protected void onForceLoad() {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onForceLoad() " + FusedPrintersProvider.this.hashCode());
+        }
+        loadInternal();
+    }
+
+    private void loadInternal() {
+        if (mDiscoverySession == null) {
+            PrintManager printManager = (PrintManager) getContext()
+                    .getSystemService(Context.PRINT_SERVICE);
+            mDiscoverySession = printManager.createPrinterDiscoverySession();
+            mPersistenceManager.readPrinterHistory();
+        }
+        if (mPersistenceManager.isReadHistoryCompleted()
+                && !mDiscoverySession.isPrinterDiscoveryStarted()) {
+            mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
+                @Override
+                public void onPrintersChanged() {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "onPrintersChanged() count:"
+                                + mDiscoverySession.getPrinters().size()
+                                + " " + FusedPrintersProvider.this.hashCode());
+                    }
+                    updatePrinters(mDiscoverySession.getPrinters());
+                }
+            });
+            final int favoriteCount = mFavoritePrinters.size();
+            List<PrinterId> printerIds = new ArrayList<PrinterId>(favoriteCount);
+            for (int i = 0; i < favoriteCount; i++) {
+                printerIds.add(mFavoritePrinters.get(i).getId());
+            }
+            mDiscoverySession.startPrinterDisovery(printerIds);
+            List<PrinterInfo> printers = mDiscoverySession.getPrinters();
+            if (!printers.isEmpty()) {
+                updatePrinters(printers);
+            }
+        }
+    }
+
+    private void updatePrinters(List<PrinterInfo> printers) {
+        if (mPrinters.equals(printers)) {
+            return;
+        }
+        ArrayMap<PrinterId, PrinterInfo> printersMap =
+                new ArrayMap<PrinterId, PrinterInfo>();
+        final int printerCount = printers.size();
+        for (int i = 0; i < printerCount; i++) {
+            PrinterInfo printer = printers.get(i);
+            printersMap.put(printer.getId(), printer);
+        }
+        computeAndDeliverResult(printersMap);
+    }
+
+    @Override
+    protected boolean onCancelLoad() {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onCancelLoad() " + FusedPrintersProvider.this.hashCode());
+        }
+        return cancelInternal();
+    }
+
+    private boolean cancelInternal() {
+        if (mDiscoverySession != null
+                && mDiscoverySession.isPrinterDiscoveryStarted()) {
+            if (mTrackedPrinter != null) {
+                mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter);
+                mTrackedPrinter = null;
+            }
+            mDiscoverySession.stopPrinterDiscovery();
+            return true;
+        } else if (mPersistenceManager.isReadHistoryInProgress()) {
+            return mPersistenceManager.stopReadPrinterHistory();
+        }
+        return false;
+    }
+
+    @Override
+    protected void onReset() {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onReset() " + FusedPrintersProvider.this.hashCode());
+        }
+        onStopLoading();
+        mPrinters.clear();
+        if (mDiscoverySession != null) {
+            mDiscoverySession.destroy();
+            mDiscoverySession = null;
+        }
+    }
+
+    @Override
+    protected void onAbandon() {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onAbandon() " + FusedPrintersProvider.this.hashCode());
+        }
+        onStopLoading();
+    }
+
+    public void setTrackedPrinter(PrinterId printerId) {
+        if (isStarted() && mDiscoverySession != null
+                && mDiscoverySession.isPrinterDiscoveryStarted()) {
+            if (mTrackedPrinter != null) {
+                mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter);
+            }
+            mTrackedPrinter = printerId;
+            mDiscoverySession.startPrinterStateTracking(printerId);
+        }
+    }
+
+    private final class PersistenceManager {
+        private static final String PERSIST_FILE_NAME = "printer_history.xml";
+
+        private static final String TAG_PRINTERS = "printers";
+
+        private static final String TAG_PRINTER = "printer";
+        private static final String TAG_PRINTER_ID = "printerId";
+
+        private static final String ATTR_LOCAL_ID = "localId";
+        private static final String ATTR_SERVICE_NAME = "serviceName";
+
+        private static final String ATTR_NAME = "name";
+        private static final String ATTR_DESCRIPTION = "description";
+        private static final String ATTR_STATUS = "status";
+
+        private final AtomicFile mStatePersistFile;
+
+        private List<PrinterInfo> mHistoricalPrinters;
+
+        private boolean mReadHistoryCompleted;
+        private boolean mReadHistoryInProgress;
+
+        private ReadTask mReadTask;
+
+        private PersistenceManager(Context context) {
+            mStatePersistFile = new AtomicFile(new File(context.getFilesDir(),
+                    PERSIST_FILE_NAME));
+        }
+
+        public boolean isReadHistoryInProgress() {
+            return mReadHistoryInProgress;
+        }
+
+        public boolean isReadHistoryCompleted() {
+            return mReadHistoryCompleted;
+        }
+
+        public boolean stopReadPrinterHistory() {
+            final boolean cancelled = mReadTask.cancel(true);
+            mReadTask = null;
+            return cancelled;
+        }
+
+        public void readPrinterHistory() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "read history started "
+                        + FusedPrintersProvider.this.hashCode());
+            }
+            mReadHistoryInProgress = true;
+            mReadTask = new ReadTask();
+            mReadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void addPrinterAndWritePrinterHistory(PrinterInfo printer) {
+            if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) {
+                mHistoricalPrinters.remove(0);
+            }
+            mHistoricalPrinters.add(printer);
+            new WriteTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,
+                    new ArrayList<PrinterInfo>(mHistoricalPrinters));
+        }
+
+        private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) {
+            Map<PrinterId, PrinterRecord> recordMap =
+                    new ArrayMap<PrinterId, PrinterRecord>();
+
+            // Recompute the weights.
+            float currentWeight = 1.0f;
+            final int printerCount = printers.size();
+            for (int i = printerCount - 1; i >= 0; i--) {
+                PrinterInfo printer = printers.get(i);
+                // Aggregate weight for the same printer
+                PrinterRecord record = recordMap.get(printer.getId());
+                if (record == null) {
+                    record = new PrinterRecord(printer);
+                    recordMap.put(printer.getId(), record);
+                }
+                record.weight += currentWeight;
+                currentWeight *= WEIGHT_DECAY_COEFFICIENT;
+            }
+
+            // Soft the favorite printers.
+            List<PrinterRecord> favoriteRecords = new ArrayList<PrinterRecord>(
+                    recordMap.values());
+            Collections.sort(favoriteRecords);
+
+            // Write the favorites to the output.
+            final int favoriteCount = Math.min(favoriteRecords.size(),
+                    MAX_FAVORITE_PRINTER_COUNT);
+            List<PrinterInfo> favoritePrinters = new ArrayList<PrinterInfo>(favoriteCount);
+            for (int i = 0; i < favoriteCount; i++) {
+                PrinterInfo printer = favoriteRecords.get(i).printer;
+                favoritePrinters.add(printer);
+            }
+
+            return favoritePrinters;
+        }
+
+        private final class PrinterRecord implements Comparable<PrinterRecord> {
+            public final PrinterInfo printer;
+            public float weight;
+
+            public PrinterRecord(PrinterInfo printer) {
+                this.printer = printer;
+            }
+
+            @Override
+            public int compareTo(PrinterRecord another) {
+                return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
+            }
+        }
+
+        private final class ReadTask extends AsyncTask<Void, Void, List<PrinterInfo>> {
+            @Override
+            protected List<PrinterInfo> doInBackground(Void... args) {
+               return doReadPrinterHistory();
+            }
+
+            @Override
+            protected void onPostExecute(List<PrinterInfo> printers) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "read history completed "
+                            + FusedPrintersProvider.this.hashCode());
+                }
+
+                // Ignore printer records whose target services are not installed.
+                PrintManager printManager = (PrintManager) getContext()
+                        .getSystemService(Context.PRINT_SERVICE);
+                List<PrintServiceInfo> services = printManager
+                        .getInstalledPrintServices();
+
+                Set<ComponentName> installedComponents = new ArraySet<ComponentName>();
+                final int installedServiceCount = services.size();
+                for (int i = 0; i < installedServiceCount; i++) {
+                    ServiceInfo serviceInfo = services.get(i).getResolveInfo().serviceInfo;
+                    ComponentName componentName = new ComponentName(
+                            serviceInfo.packageName, serviceInfo.name);
+                    installedComponents.add(componentName);
+                }
+
+                final int printerCount = printers.size();
+                for (int i = printerCount - 1; i >= 0; i--) {
+                    ComponentName printerServiceName = printers.get(i).getId().getServiceName();
+                    if (!installedComponents.contains(printerServiceName.getPackageName())) {
+                        printers.remove(i);
+                    }
+                }
+
+                // Store the filtered list.
+                mHistoricalPrinters = printers;
+
+                // Compute the favorite printers.
+                mFavoritePrinters.clear();
+                mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters));
+
+                mReadHistoryInProgress = false;
+                mReadHistoryCompleted = true;
+
+                // Deliver the favorites.
+                Map<PrinterId, PrinterInfo> discoveredPrinters = Collections.emptyMap();
+                computeAndDeliverResult(discoveredPrinters);
+
+                // Start loading the available printers.
+                loadInternal();
+
+                // We are done.
+                mReadTask = null;
+            }
+
+            private List<PrinterInfo> doReadPrinterHistory() {
+                FileInputStream in = null;
+                try {
+                    in = mStatePersistFile.openRead();
+                } catch (FileNotFoundException fnfe) {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "No existing printer history "
+                                + FusedPrintersProvider.this.hashCode());
+                    }
+                    return new ArrayList<PrinterInfo>();
+                }
+                try {
+                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+                    XmlPullParser parser = Xml.newPullParser();
+                    parser.setInput(in, null);
+                    parseState(parser, printers);
+                    return printers;
+                } catch (IllegalStateException ise) {
+                    Slog.w(LOG_TAG, "Failed parsing ", ise);
+                } catch (NullPointerException npe) {
+                    Slog.w(LOG_TAG, "Failed parsing ", npe);
+                } catch (NumberFormatException nfe) {
+                    Slog.w(LOG_TAG, "Failed parsing ", nfe);
+                } catch (XmlPullParserException xppe) {
+                    Slog.w(LOG_TAG, "Failed parsing ", xppe);
+                } catch (IOException ioe) {
+                    Slog.w(LOG_TAG, "Failed parsing ", ioe);
+                } catch (IndexOutOfBoundsException iobe) {
+                    Slog.w(LOG_TAG, "Failed parsing ", iobe);
+                } finally {
+                    IoUtils.closeQuietly(in);
+                }
+
+                return Collections.emptyList();
+            }
+
+            private void parseState(XmlPullParser parser, List<PrinterInfo> outPrinters)
+                    throws IOException, XmlPullParserException {
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS);
+                parser.next();
+
+                while (parsePrinter(parser, outPrinters)) {
+                    // Be nice and respond to cancellation
+                    if (isCancelled()) {
+                        return;
+                    }
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS);
+            }
+
+            private boolean parsePrinter(XmlPullParser parser, List<PrinterInfo> outPrinters)
+                    throws IOException, XmlPullParserException {
+                skipEmptyTextTags(parser);
+                if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) {
+                    return false;
+                }
+
+                String name = parser.getAttributeValue(null, ATTR_NAME);
+                String description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
+                final int status = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATUS));
+
+                parser.next();
+
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID);
+                String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
+                ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
+                        null, ATTR_SERVICE_NAME));
+                PrinterId printerId =  new PrinterId(service, localId);
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
+                parser.next();
+
+                PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status);
+                builder.setDescription(description);
+                PrinterInfo printer = builder.build();
+
+                outPrinters.add(printer);
+
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "[RESTORED] " + printer);
+                }
+
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER);
+
+                return true;
+            }
+
+            private void expect(XmlPullParser parser, int type, String tag)
+                    throws IOException, XmlPullParserException {
+                if (!accept(parser, type, tag)) {
+                    throw new XmlPullParserException("Exepected event: " + type
+                            + " and tag: " + tag + " but got event: " + parser.getEventType()
+                            + " and tag:" + parser.getName());
+                }
+            }
+
+            private void skipEmptyTextTags(XmlPullParser parser)
+                    throws IOException, XmlPullParserException {
+                while (accept(parser, XmlPullParser.TEXT, null)
+                        && "\n".equals(parser.getText())) {
+                    parser.next();
+                }
+            }
+
+            private boolean accept(XmlPullParser parser, int type, String tag)
+                    throws IOException, XmlPullParserException {
+                if (parser.getEventType() != type) {
+                    return false;
+                }
+                if (tag != null) {
+                    if (!tag.equals(parser.getName())) {
+                        return false;
+                    }
+                } else if (parser.getName() != null) {
+                    return false;
+                }
+                return true;
+            }
+        };
+
+        private final class WriteTask extends AsyncTask<List<PrinterInfo>, Void, Void> {
+            @Override
+            protected Void doInBackground(List<PrinterInfo>... printers) {
+                doWritePrinterHistory(printers[0]);
+                return null;
+            }
+
+            private void doWritePrinterHistory(List<PrinterInfo> printers) {
+                FileOutputStream out = null;
+                try {
+                    out = mStatePersistFile.startWrite();
+
+                    XmlSerializer serializer = new FastXmlSerializer();
+                    serializer.setOutput(out, "utf-8");
+                    serializer.startDocument(null, true);
+                    serializer.startTag(null, TAG_PRINTERS);
+
+                    final int printerCount = printers.size();
+                    for (int i = 0; i < printerCount; i++) {
+                        PrinterInfo printer = printers.get(i);
+
+                        serializer.startTag(null, TAG_PRINTER);
+
+                        serializer.attribute(null, ATTR_NAME, printer.getName());
+                        // Historical printers are always stored as unavailable.
+                        serializer.attribute(null, ATTR_STATUS, String.valueOf(
+                                PrinterInfo.STATUS_UNAVAILABLE));
+                        String description = printer.getDescription();
+                        if (description != null) {
+                            serializer.attribute(null, ATTR_DESCRIPTION, description);
+                        }
+
+                        PrinterId printerId = printer.getId();
+                        serializer.startTag(null, TAG_PRINTER_ID);
+                        serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
+                        serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
+                                .flattenToString());
+                        serializer.endTag(null, TAG_PRINTER_ID);
+
+                        serializer.endTag(null, TAG_PRINTER);
+
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "[PERSISTED] " + printer);
+                        }
+                    }
+
+                    serializer.endTag(null, TAG_PRINTERS);
+                    serializer.endDocument();
+                    mStatePersistFile.finishWrite(out);
+
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "[PERSIST END]");
+                    }
+                } catch (IOException ioe) {
+                    Slog.w(LOG_TAG, "Failed to write printer history, restoring backup.", ioe);
+                    mStatePersistFile.failWrite(out);
+                } finally {
+                    IoUtils.closeQuietly(out);
+                }
+            }
+        };
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
new file mode 100644
index 0000000..dae7770
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
@@ -0,0 +1,271 @@
+/*
+ * 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.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.print.IPrintManager;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.provider.Settings;
+import android.util.Log;
+
+/**
+ * This class is responsible for updating the print notifications
+ * based on print job state transitions.
+ */
+public class NotificationController {
+    public static final boolean DEBUG = false;
+
+    public static final String LOG_TAG = "NotificationController";
+
+    private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
+    private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
+
+    private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
+    private static final String EXTRA_PRINTJOB_LABEL = "EXTRA_PRINTJOB_LABEL";
+    private static final String EXTRA_PRINTER_NAME = "EXTRA_PRINTER_NAME";
+
+    private final Context mContext;
+    private final NotificationManager mNotificationManager;
+
+    public NotificationController(Context context) {
+        mContext = context;
+        mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+    }
+
+    public void onPrintJobStateChanged(PrintJobInfo printJob) {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: "
+                    + printJob.getId().flattenToString() + " state:"
+                    + PrintJobInfo.stateToString(printJob.getState()));
+        }
+        switch (printJob.getState()) {
+            case PrintJobInfo.STATE_QUEUED:
+            case PrintJobInfo.STATE_STARTED: {
+                createPrintingNotification(printJob);
+            } break;
+
+            case PrintJobInfo.STATE_FAILED: {
+                createFailedNotification(printJob);
+            } break;
+
+            case PrintJobInfo.STATE_COMPLETED:
+            case PrintJobInfo.STATE_CANCELED: {
+                removeNotification(printJob.getId());
+            } break;
+
+            case PrintJobInfo.STATE_BLOCKED: {
+                createBlockedNotification(printJob);
+            } break;
+        }
+    }
+
+    private void createPrintingNotification(PrintJobInfo printJob) {
+        Notification.Builder builder = new Notification.Builder(mContext)
+                .setContentIntent(createContentIntent(printJob.getId()))
+                .setSmallIcon(com.android.internal.R.drawable.ic_print)
+                .setContentTitle(mContext.getString(R.string.printing_notification_title_template,
+                        printJob.getLabel()))
+                .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
+                        createCancelIntent(printJob))
+                .setContentText(printJob.getPrinterName())
+                .setWhen(System.currentTimeMillis())
+                .setOngoing(true)
+                .setShowWhen(true);
+        mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
+    }
+
+    private void createFailedNotification(PrintJobInfo printJob) {
+        Notification.Builder builder = new Notification.Builder(mContext)
+                .setContentIntent(createContentIntent(printJob.getId()))
+                .setSmallIcon(com.android.internal.R.drawable.ic_print_error)
+                .setContentTitle(mContext.getString(R.string.failed_notification_title_template,
+                        printJob.getLabel()))
+                .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
+                        createCancelIntent(printJob))
+                .addAction(android.R.drawable.ic_secure, mContext.getString(R.string.restart),
+                        createRestartIntent(printJob.getId()))
+                .setContentText(printJob.getPrinterName())
+                .setWhen(System.currentTimeMillis())
+                .setOngoing(true)
+                .setShowWhen(true);
+        mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
+    }
+
+    private void createBlockedNotification(PrintJobInfo printJob) {
+        Notification.Builder builder = new Notification.Builder(mContext)
+                .setContentIntent(createContentIntent(printJob.getId()))
+                .setSmallIcon(com.android.internal.R.drawable.ic_print_error)
+                .setContentTitle(mContext.getString(R.string.blocked_notification_title_template,
+                        printJob.getLabel()))
+                .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
+                        createCancelIntent(printJob))
+                .setContentText(printJob.getPrinterName())
+                .setWhen(System.currentTimeMillis())
+                .setOngoing(true)
+                .setShowWhen(true);
+        mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
+    }
+
+    private void removeNotification(PrintJobId printJobId) {
+        mNotificationManager.cancel(printJobId.flattenToString(), 0);
+    }
+
+    private PendingIntent createContentIntent(PrintJobId printJobId) {
+        Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
+        intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString());
+        return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+    }
+
+    private PendingIntent createCancelIntent(PrintJobInfo printJob) {
+        Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
+        intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
+        intent.putExtra(EXTRA_PRINT_JOB_ID, printJob.getId());
+        intent.putExtra(EXTRA_PRINTJOB_LABEL, printJob.getLabel());
+        intent.putExtra(EXTRA_PRINTER_NAME, printJob.getPrinterName());
+        return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+    }
+
+    private PendingIntent createRestartIntent(PrintJobId printJobId) {
+        Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
+        intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + printJobId.flattenToString());
+        intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId);
+        return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+    }
+
+    public static final class NotificationBroadcastReceiver extends BroadcastReceiver {
+        private static final String LOG_TAG = "NotificationBroadcastReceiver";
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
+                PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
+                String printJobLabel = intent.getExtras().getString(EXTRA_PRINTJOB_LABEL);
+                String printerName = intent.getExtras().getString(EXTRA_PRINTER_NAME);
+                handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
+            } else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
+                PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
+                handleRestartPrintJob(context, printJobId);
+            }
+        }
+
+        private void handleCancelPrintJob(final Context context, final PrintJobId printJobId,
+                final String printJobLabel, final String printerName) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
+            }
+
+            // Put up a notification that we are trying to cancel.
+            NotificationManager notificationManager = (NotificationManager)
+                    context.getSystemService(Context.NOTIFICATION_SERVICE);
+            Notification.Builder builder = new Notification.Builder(context)
+                    .setSmallIcon(R.drawable.stat_notify_cancelling)
+                    .setContentTitle(context.getString(
+                            R.string.cancelling_notification_title_template,
+                            printJobLabel))
+                    .setContentText(printerName)
+                    .setWhen(System.currentTimeMillis())
+                    .setOngoing(true)
+                    .setShowWhen(true);
+            notificationManager.notify(printJobId.flattenToString(), 0, builder.build());
+
+            // Call into the print manager service off the main thread since
+            // the print manager service may end up binding to the print spooler
+            // service which binding is handled on the main thread.
+            PowerManager powerManager = (PowerManager)
+                    context.getSystemService(Context.POWER_SERVICE);
+            final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    LOG_TAG);
+            wakeLock.acquire();
+
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    // We need to request the cancellation to be done by the print
+                    // manager service since it has to communicate with the managing
+                    // print service to request the cancellation. Also we need the
+                    // system service to be bound to the spooler since canceling a
+                    // print job will trigger persistence of current jobs which is
+                    // done on another thread and until it finishes the spooler has
+                    // to be kept around.
+                    try {
+                    IPrintManager printManager = IPrintManager.Stub.asInterface(
+                            ServiceManager.getService(Context.PRINT_SERVICE));
+                        printManager.cancelPrintJob(printJobId, PrintManager.APP_ID_ANY,
+                                UserHandle.myUserId());
+                    } catch (RemoteException re) {
+                        Log.i(LOG_TAG, "Error requestion print job cancellation", re);
+                    } finally {
+                        wakeLock.release();
+                    }
+                    return null;
+                }
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+        }
+
+        private void handleRestartPrintJob(final Context context, final PrintJobId printJobId) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "handleRestartPrintJob() printJobId:" + printJobId);
+            }
+
+            // Call into the print manager service off the main thread since
+            // the print manager service may end up binding to the print spooler
+            // service which binding is handled on the main thread.
+            PowerManager powerManager = (PowerManager)
+                    context.getSystemService(Context.POWER_SERVICE);
+            final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    LOG_TAG);
+            wakeLock.acquire();
+
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    // We need to request the restart to be done by the print manager
+                    // service since the latter must be bound to the spooler because
+                    // restarting a print job will trigger persistence of current jobs
+                    // which is done on another thread and until it finishes the spooler has
+                    // to be kept around.
+                    try {
+                        IPrintManager printManager = IPrintManager.Stub.asInterface(
+                                ServiceManager.getService(Context.PRINT_SERVICE));
+                        printManager.restartPrintJob(printJobId, PrintManager.APP_ID_ANY,
+                                UserHandle.myUserId());
+                    } catch (RemoteException re) {
+                        Log.i(LOG_TAG, "Error requestion print job restart", re);
+                    } finally {
+                        wakeLock.release();
+                    }
+                    return null;
+                }
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+        }
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
new file mode 100644
index 0000000..6dd8aa0a
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
@@ -0,0 +1,44 @@
+/*
+ * 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 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) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        if (widthMode == MeasureSpec.AT_MOST) {
+            final int receivedWidth = MeasureSpec.getSize(widthMeasureSpec);
+            final int computedWidth = Math.min(mMaxWidth, receivedWidth);
+            widthMeasureSpec = MeasureSpec.makeMeasureSpec(computedWidth,
+                    MeasureSpec.EXACTLY);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
new file mode 100644
index 0000000..8474115
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -0,0 +1,2503 @@
+/*
+ * 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.Context;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+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.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.text.Editable;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.text.TextWatcher;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.Log;
+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.ViewConfiguration;
+import android.view.ViewGroup;
+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.ImageView;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+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.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import libcore.io.IoUtils;
+
+/**
+ * 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 EXTRA_PRINT_DOCUMENT_ADAPTER = "printDocumentAdapter";
+    public static final String EXTRA_PRINT_JOB = "printJob";
+
+    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 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]*)+");
+
+    // The list of countries where Letter is the default paper size. Culled from
+    // the OpenOffice wiki at http://wiki.openoffice.org/wiki/DefaultPaperSize.
+    private static final Set<String> sLetterDefaultCountries = new ArraySet<String>();
+    static {
+        sLetterDefaultCountries.add("US");
+        sLetterDefaultCountries.add("CA");
+        sLetterDefaultCountries.add("BZ");
+        sLetterDefaultCountries.add("CL");
+        sLetterDefaultCountries.add("CR");
+        sLetterDefaultCountries.add("GT");
+        sLetterDefaultCountries.add("NI");
+        sLetterDefaultCountries.add("PA");
+        sLetterDefaultCountries.add("PR");
+        sLetterDefaultCountries.add("SV");
+        sLetterDefaultCountries.add("VE");
+        sLetterDefaultCountries.add("MX");
+        sLetterDefaultCountries.add("CO");
+        sLetterDefaultCountries.add("PH");
+    }
+
+    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;
+
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+
+        Bundle extras = getIntent().getExtras();
+
+        PrintJobInfo printJob = extras.getParcelable(EXTRA_PRINT_JOB);
+        if (printJob == null) {
+            throw new IllegalArgumentException("printJob cannot be null");
+        }
+
+        mPrintJobId = printJob.getId();
+        mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINT_DOCUMENT_ADAPTER);
+        if (mIPrintDocumentAdapter == null) {
+            throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
+        }
+
+        PrintAttributes attributes = printJob.getAttributes();
+        if (attributes != null) {
+            mCurrPrintAttributes.copyFrom(attributes);
+        }
+
+        setContentView(R.layout.print_job_config_activity_container);
+
+        mDocument = new Document();
+        mController = new PrintController(new RemotePrintDocumentAdapter(
+                IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
+                PrintSpoolerService.peekInstance().generateFileForPrintJob(mPrintJobId)));
+        mEditor = new Editor();
+
+        try {
+            mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
+        } catch (RemoteException re) {
+            finish();
+            return;
+        }
+
+        mController.initialize();
+        mEditor.initialize();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mEditor.refreshCurrentPrinter();
+    }
+
+    @Override
+    protected void onDestroy() {
+        // We can safely do the work in here since at this point
+        // the system is bound to our (spooler) process which
+        // guarantees that this process will not be killed.
+        if (mController.hasStarted()) {
+            mController.finish();
+        }
+        if (mEditor.isPrintConfirmed() && mController.isFinished()) {
+            PrintSpoolerService.peekInstance().setPrintJobState(mPrintJobId,
+                    PrintJobInfo.STATE_QUEUED, null);
+        } else {
+            PrintSpoolerService.peekInstance().setPrintJobState(mPrintJobId,
+                    PrintJobInfo.STATE_CANCELED, null);
+        }
+        mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
+        if (mGeneratingPrintJobDialog != null) {
+            mGeneratingPrintJobDialog.dismiss();
+            mGeneratingPrintJobDialog = null;
+        }
+        super.onDestroy();
+    }
+
+    public boolean onTouchEvent(MotionEvent event) {
+        if (!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 (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() {
+            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 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 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 {
+                PrintSpoolerService.peekInstance().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;
+            }
+
+            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.
+                PrintSpoolerService.peekInstance().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;
+                PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(
+                        mPrintJobId, null);
+            }
+
+            // 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 and we already have
+            // the requested pages, then nothing else to do.
+            if (!infoChanged && !layoutChanged
+                    && PageRangeUtils.contains(mDocument.pages, 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.
+                updatePrintJobPages(mDocument.pages, mRequestedPages);
+                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(CharSequence error, int sequence) {
+            if (mRequestCounter.get() != sequence) {
+                return;
+            }
+            mControllerState = CONTROLLER_STATE_FAILED;
+            // TODO: We need some UI for announcing an error.
+            Log.e(LOG_TAG, "Error during layout: " + error);
+            PrintJobConfigActivity.this.finish();
+        }
+
+        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 = PrintSpoolerService.peekInstance()
+                    .generateFileForPrintJob(mPrintJobId);
+            mDocument.info.setDataSize(file.length());
+
+            // Update the print job with the updated info.
+            PrintSpoolerService.peekInstance().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.
+                PrintSpoolerService.peekInstance().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.
+                PrintSpoolerService.peekInstance().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);
+                PrintSpoolerService.peekInstance().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.
+                PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
+                        writtenPages);
+            } else {
+                // We did not get the pages we requested, then the application
+                // misbehaves, so we fail quickly.
+                // TODO: We need some UI for announcing an error.
+                mControllerState = CONTROLLER_STATE_FAILED;
+                Log.e(LOG_TAG, "Received invalid pages from the app");
+                PrintJobConfigActivity.this.finish();
+            }
+        }
+
+        private void requestCreatePdfFileOrFinish() {
+            if (mEditor.isPrintingToPdf()) {
+                PrintJobInfo printJob = PrintSpoolerService.peekInstance()
+                        .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY);
+                Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+                intent.setType("application/pdf");
+                intent.putExtra(Intent.EXTRA_TITLE, printJob.getLabel());
+                startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE);
+            } else {
+                PrintJobConfigActivity.this.finish();
+            }
+        }
+
+        private void handleOnWriteFailed(CharSequence error, int sequence) {
+            if (mRequestCounter.get() != sequence) {
+                return;
+            }
+            mControllerState = CONTROLLER_STATE_FAILED;
+            Log.e(LOG_TAG, "Error during write: " + error);
+            PrintJobConfigActivity.this.finish();
+        }
+
+        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.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;
+        }
+    }
+
+    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 = PrintSpoolerService.peekInstance()
+                            .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY);
+                    if (printJob == null) {
+                        return null;
+                    }
+                    File file = PrintSpoolerService.peekInstance()
+                            .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 EditText mCopiesEditText;
+
+        private TextView mRangeOptionsTitle;
+        private TextView mPageRangeTitle;
+        private EditText mPageRangeEditText;
+
+        private Spinner mDestinationSpinner;
+        private final DestinationAdapter mDestinationSpinnerAdapter;
+
+        private Spinner mMediaSizeSpinner;
+        private final ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
+
+        private Spinner mColorModeSpinner;
+        private final ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
+
+        private Spinner mOrientationSpinner;
+        private final  ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
+
+        private Spinner mRangeOptionsSpinner;
+        private final ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
+
+        private final SimpleStringSplitter mStringCommaSplitter =
+                new SimpleStringSplitter(',');
+
+        private View mContentContainer;
+
+        private Button mPrintButton;
+
+        private PrinterId mNextPrinterId;
+
+        private PrinterInfo mCurrentPrinter;
+
+        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 (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
+                        startSelectPrinterActivity();
+                        return;
+                    }
+
+                    mCapabilitiesTimeout.remove();
+
+                    mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter
+                            .getItem(position);
+
+                    PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence(
+                            mPrintJobId, mCurrentPrinter);
+
+                    if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
+                        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 (mOldMediaSizeSelectionIndex
+                            == mMediaSizeSpinner.getSelectedItemPosition()) {
+                        mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
+                        return;
+                    }
+                    SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
+                    mCurrPrintAttributes.setMediaSize(mediaItem.value);
+                    if (!hasErrors()) {
+                        mController.update();
+                    }
+                } else if (spinner == mColorModeSpinner) {
+                    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();
+
+            // Media size.
+            MediaSize currMediaSize = mCurrPrintAttributes.getMediaSize();
+            if (currMediaSize == null) {
+                mCurrPrintAttributes.setMediaSize(defaults.getMediaSize());
+            } else {
+                MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
+                List<MediaSize> mediaSizes = capabilities.getMediaSizes();
+                final int mediaSizeCount = mediaSizes.size();
+                for (int i = 0; i < mediaSizeCount; i++) {
+                    MediaSize mediaSize = mediaSizes.get(i);
+                    if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
+                        mCurrPrintAttributes.setMediaSize(mediaSize);
+                        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);
+                PrintSpoolerService.peekInstance().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.
+
+                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 int mCurrentUi = UI_NONE;
+
+        private boolean mFavoritePrinterSelected;
+
+        public Editor() {
+            // Destination.
+            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() > 2) {
+                        mFavoritePrinterSelected = true;
+                        mDestinationSpinner.setSelection(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 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
+                                        && !mCapabilitiesTimeout.isPosted()) {
+                                    mCapabilitiesTimeout.post();
+                                    refreshCurrentPrinter();
+                                    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) {
+                                        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()) {
+                                        // 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();
+
+            mCurrentPrinter = mDestinationSpinnerAdapter.mFakePdfPrinter;
+            updatePrintAttributes(mCurrentPrinter.getCapabilities());
+
+            updateUi();
+        }
+
+        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 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;
+            }
+
+            switch (mCurrentUi) {
+                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();
+                                    }
+                                }
+                            });
+                        } 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();
+                                    }
+                                }
+                            });
+                        } break;
+                    }
+                } break;
+            }
+
+            mCurrentUi = ui;
+        }
+
+        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 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 postAnimateCommand) {
+            // 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).withLayer()
+                            .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            // Swap the old and the new content.
+                            contentContainer.removeAllViews();
+                            contentContainer.setScaleY(1.0f);
+                            contentContainer.addView(showingView);
+
+                            // Third animation - show the new content.
+                            AutoCancellingAnimator.animate(showingView).withLayer().alpha(1.0f)
+                                    .withEndAction(new Runnable() {
+                                @Override
+                                public void run() {
+                                    postAnimateCommand.run();
+                                }
+                            });
+                        }
+                    });
+                }
+            });
+        }
+
+        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.setText(MIN_COPIES_STRING);
+            mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
+            mCopiesEditText.selectAll();
+            if (!TextUtils.equals(mCopiesEditText.getText(), MIN_COPIES_STRING)) {
+                mIgnoreNextCopiesChange = true;
+            }
+            PrintSpoolerService.peekInstance().setPrintJobCopiesNoPersistence(
+                    mPrintJobId, MIN_COPIES);
+
+            // Destination.
+            mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
+            mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
+            mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+            if (mDestinationSpinnerAdapter.getCount() > 0 && mController.hasStarted()) {
+                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.addTextChangedListener(mRangeTextWatcher);
+
+            // 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);
+                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) {
+                String minCopiesString = String.valueOf(MIN_COPIES);
+                if (!TextUtils.equals(mCopiesEditText.getText(), minCopiesString)) {
+                    mIgnoreNextCopiesChange = true;
+                    mCopiesEditText.setText(minCopiesString);
+                }
+                mCopiesEditText.setEnabled(false);
+
+                // Media size
+                if (mMediaSizeSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) {
+                    mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
+                    mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
+                }
+                mMediaSizeSpinner.setEnabled(false);
+
+                // Color mode
+                if (mColorModeSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) {
+                    mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION;
+                    mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
+                }
+                mColorModeSpinner.setEnabled(false);
+
+                // Orientation
+                if (mOrientationSpinner.getSelectedItemPosition() != 0) {
+                    mIgnoreNextOrientationChange = true;
+                    mOrientationSpinner.setSelection(0);
+                }
+                mOrientationSpinner.setEnabled(false);
+
+                // Range
+                if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+                    mIgnoreNextRangeOptionChange = true;
+                    mRangeOptionsSpinner.setSelection(0);
+                }
+                mRangeOptionsSpinner.setEnabled(false);
+                mRangeOptionsTitle.setText(getString(R.string.label_pages,
+                        getString(R.string.page_count_unknown)));
+                if (!TextUtils.equals(mPageRangeEditText.getText(), "")) {
+                    mIgnoreNextRangeChange = true;
+                    mPageRangeEditText.setText("");
+                }
+
+                mPageRangeEditText.setEnabled(false);
+                mPageRangeEditText.setVisibility(View.INVISIBLE);
+                mPageRangeTitle.setVisibility(View.INVISIBLE);
+
+                // Print
+                mPrintButton.setEnabled(false);
+
+                return false;
+            } else {
+                boolean someAttributeSelectionChanged = false;
+
+                PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
+                PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
+                PrintAttributes defaultAttributes = printer.getCapabilities().getDefaults();
+
+                // Media size.
+                List<MediaSize> mediaSizes = capabilities.getMediaSizes();
+
+                // 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.equals(oldMediaSize)) {
+                            // 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);
+                        mCurrPrintAttributes.setMediaSize(mMediaSizeSpinnerAdapter
+                                .getItem(mediaSizeIndex).value);
+                        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 selectedColorModeIndex = Integer.numberOfTrailingZeros(
+                                    (colorModes & defaultAttributes.getColorMode()));
+                        setColorModeSpinnerSelectionNoCallback(selectedColorModeIndex);
+                        mCurrPrintAttributes.setColorMode(mColorModeSpinnerAdapter
+                                .getItem(selectedColorModeIndex).value);
+                        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();
+                    mRangeOptionsTitle.setText(getString(R.string.label_pages,
+                            (pageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
+                                    ? getString(R.string.page_count_unknown)
+                                    : String.valueOf(pageCount)));
+                } else {
+                    if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+                        mIgnoreNextRangeOptionChange = true;
+                        mRangeOptionsSpinner.setSelection(0);
+                    }
+                    mRangeOptionsSpinner.setEnabled(false);
+                    mRangeOptionsTitle.setText(getString(R.string.label_pages,
+                            getString(R.string.page_count_unknown)));
+                    mPageRangeEditText.setEnabled(false);
+                    mPageRangeEditText.setVisibility(View.INVISIBLE);
+                    mPageRangeTitle.setVisibility(View.INVISIBLE);
+                }
+
+                // Print/Print preview
+                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.selectAll();
+                    mCopiesEditText.requestFocus();
+                }
+
+                return someAttributeSelectionChanged;
+            }
+        }
+
+        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.title);
+                    String title = getString(R.string.printer_unavailable,
+                            mCurrentPrinter.getName());
+                    titleView.setText(title);
+                }
+            }
+        }
+
+        private final class DestinationAdapter extends BaseAdapter
+                implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>{
+            private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
+
+            private final PrinterInfo mFakePdfPrinter;
+
+            public DestinationAdapter() {
+                getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
+                mFakePdfPrinter = createFakePdfPrinter();
+            }
+
+            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() {
+                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) {
+                        return mFakePdfPrinter;
+                    }
+                } else {
+                    if (position < 1) {
+                        return mPrinters.get(position);
+                    }
+                    if (position == 1) {
+                        return mFakePdfPrinter;
+                    }
+                    if (position < getCount() - 1) {
+                        return mPrinters.get(position - 1);
+                    }
+                }
+                return null;
+            }
+
+            @Override
+            public long getItemId(int position) {
+                if (mPrinters.isEmpty()) {
+                    if (position == 0) {
+                        return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
+                    }
+                    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 (mPrinters.isEmpty()) {
+                    if (position == 0) {
+                        PrinterInfo printer = (PrinterInfo) getItem(position);
+                        title = printer.getName();
+                    } else if (position == 1) {
+                        title = getString(R.string.all_printers);
+                    }
+                } else {
+                    if (position == 1) {
+                        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.GONE);
+                }
+
+                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) {
+                // 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() {
+                final MediaSize defaultMediaSize;
+                String currentCountry = getResources().getConfiguration().locale.getCountry();
+                if (sLetterDefaultCountries.contains(currentCountry)) {
+                    defaultMediaSize = MediaSize.NA_LETTER;
+                } else {
+                    defaultMediaSize = MediaSize.ISO_A4;
+                }
+
+                PrinterId printerId = new PrinterId(getComponentName(), "PDF printer");
+
+                PrinterCapabilitiesInfo capabilities =
+                        new PrinterCapabilitiesInfo.Builder(printerId)
+                    .addMediaSize(MediaSize.ISO_A4, MediaSize.ISO_A4 == defaultMediaSize)
+                    .addMediaSize(MediaSize.NA_LETTER, MediaSize.NA_LETTER == defaultMediaSize)
+                    .addResolution(new Resolution("PDF resolution", "PDF resolution",
+                            300, 300), true)
+                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR
+                            | PrintAttributes.COLOR_MODE_MONOCHROME,
+                            PrintAttributes.COLOR_MODE_COLOR)
+                    .build();
+
+                return new PrinterInfo.Builder(printerId, getString(R.string.save_as_pdf),
+                        PrinterInfo.STATUS_IDLE)
+                    .setCapabilities(capabilities)
+                    .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();
+            }
+        }
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
new file mode 100644
index 0000000..d1d71cd
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -0,0 +1,1245 @@
+/*
+ * 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.PendingIntent;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintSpooler;
+import android.print.IPrintSpoolerCallbacks;
+import android.print.IPrintSpoolerClient;
+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.PrintDocumentInfo;
+import android.print.PrintJobId;
+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;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.util.FastXmlSerializer;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Service for exposing some of the {@link PrintSpooler} functionality to
+ * another process.
+ */
+public final class PrintSpoolerService extends Service {
+
+    private static final String LOG_TAG = "PrintSpoolerService";
+
+    private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
+
+    private static final boolean DEBUG_PERSISTENCE = false;
+
+    private static final boolean PERSISTNECE_MANAGER_ENABLED = true;
+
+    private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000;
+
+    private static final String PRINT_JOB_FILE_PREFIX = "print_job_";
+
+    private static final String PRINT_FILE_EXTENSION = "pdf";
+
+    private static final Object sLock = new Object();
+
+    private final Object mLock = new Object();
+
+    private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
+
+    private static PrintSpoolerService sInstance;
+
+    private IPrintSpoolerClient mClient;
+
+    private HandlerCaller mHandlerCaller;
+
+    private PersistenceManager mPersistanceManager;
+
+    private NotificationController mNotificationController;
+
+    public static PrintSpoolerService peekInstance() {
+        synchronized (sLock) {
+            return sInstance;
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandlerCaller = new HandlerCaller(this, getMainLooper(),
+                new HandlerCallerCallback(), false);
+
+        mPersistanceManager = new PersistenceManager();
+        mNotificationController = new NotificationController(PrintSpoolerService.this);
+
+        synchronized (mLock) {
+            mPersistanceManager.readStateLocked();
+            handleReadPrintJobsLocked();
+        }
+
+        synchronized (sLock) {
+            sInstance = this;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new IPrintSpooler.Stub() {
+            @Override
+            public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
+                    ComponentName componentName, int state, int appId, int sequence)
+                    throws RemoteException {
+                List<PrintJobInfo> printJobs = null;
+                try {
+                    printJobs = PrintSpoolerService.this.getPrintJobInfos(
+                            componentName, state, appId);
+                } finally {
+                    callback.onGetPrintJobInfosResult(printJobs, sequence);
+                }
+            }
+
+            @Override
+            public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
+                    int appId, int sequence) throws RemoteException {
+                PrintJobInfo printJob = null;
+                try {
+                    printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId);
+                } finally {
+                    callback.onGetPrintJobInfoResult(printJob, sequence);
+                }
+            }
+
+            @SuppressWarnings("deprecation")
+            @Override
+            public void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+                IPrintDocumentAdapter printAdapter) throws RemoteException {
+                PrintSpoolerService.this.createPrintJob(printJob);
+
+                Intent intent = new Intent(printJob.getId().flattenToString());
+                intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
+                intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
+                        printAdapter.asBinder());
+                intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
+
+                IntentSender sender = PendingIntent.getActivity(
+                        PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
+                        | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+
+                Message message = mHandlerCaller.obtainMessageO(
+                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
+                        printJob);
+                mHandlerCaller.executeOrSendMessage(message);
+
+                message = mHandlerCaller.obtainMessageOO(
+                        HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
+                        client, sender);
+                mHandlerCaller.executeOrSendMessage(message);
+
+                printJob.setCreationTime(System.currentTimeMillis());
+            }
+
+            @Override
+            public void setPrintJobState(PrintJobId printJobId, int state, String error,
+                    IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
+                boolean success = false;
+                try {
+                    success = PrintSpoolerService.this.setPrintJobState(
+                            printJobId, state, error);
+                } finally {
+                    callback.onSetPrintJobStateResult(success, sequece);
+                }
+            }
+
+            @Override
+            public void setPrintJobTag(PrintJobId printJobId, String tag,
+                    IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
+                boolean success = false;
+                try {
+                    success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag);
+                } finally {
+                    callback.onSetPrintJobTagResult(success, sequece);
+                }
+            }
+
+            @Override
+            public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
+                PrintSpoolerService.this.writePrintJobData(fd, printJobId);
+            }
+
+            @Override
+            public void setClient(IPrintSpoolerClient client) {
+                Message message = mHandlerCaller.obtainMessageO(
+                        HandlerCallerCallback.MSG_SET_CLIENT, client);
+                mHandlerCaller.executeOrSendMessage(message);
+            }
+
+            @Override
+            public void removeObsoletePrintJobs() {
+                PrintSpoolerService.this.removeObsoletePrintJobs();
+            }
+
+            @Override
+            protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+                PrintSpoolerService.this.dump(fd, writer, args);
+            }
+        };
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (mLock) {
+            String prefix = (args.length > 0) ? args[0] : "";
+            String tab = "  ";
+
+            pw.append(prefix).append("print jobs:").println();
+            final int printJobCount = mPrintJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = mPrintJobs.get(i);
+                pw.append(prefix).append(tab).append(printJob.toString());
+                pw.println();
+            }
+
+            pw.append(prefix).append("print job files:").println();
+            File[] files = getFilesDir().listFiles();
+            if (files != null) {
+                final int fileCount = files.length;
+                for (int i = 0; i < fileCount; i++) {
+                    File file = files[i];
+                    if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
+                        pw.append(prefix).append(tab).append(file.getName()).println();
+                    }
+                }
+            }
+        }
+    }
+
+    private void sendOnPrintJobQueued(PrintJobInfo printJob) {
+        Message message = mHandlerCaller.obtainMessageO(
+                HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
+        mHandlerCaller.executeOrSendMessage(message);
+    }
+
+    private void sendOnAllPrintJobsForServiceHandled(ComponentName service) {
+        Message message = mHandlerCaller.obtainMessageO(
+                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service);
+        mHandlerCaller.executeOrSendMessage(message);
+    }
+
+    private void sendOnAllPrintJobsHandled() {
+        Message message = mHandlerCaller.obtainMessage(
+                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED);
+        mHandlerCaller.executeOrSendMessage(message);
+    }
+
+    private final class HandlerCallerCallback implements HandlerCaller.Callback {
+        public static final int MSG_SET_CLIENT = 1;
+        public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 2;
+        public static final int MSG_ON_PRINT_JOB_QUEUED = 3;
+        public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 4;
+        public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 5;
+        public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 6;
+        public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 7;
+
+        @Override
+        public void executeMessage(Message message) {
+            switch (message.what) {
+                case MSG_SET_CLIENT: {
+                    synchronized (mLock) {
+                        mClient = (IPrintSpoolerClient) message.obj;
+                        if (mClient != null) {
+                            Message msg = mHandlerCaller.obtainMessage(
+                                    HandlerCallerCallback.MSG_CHECK_ALL_PRINTJOBS_HANDLED);
+                            mHandlerCaller.sendMessageDelayed(msg,
+                                    CHECK_ALL_PRINTJOBS_HANDLED_DELAY);
+                        }
+                    }
+                } break;
+
+                case MSG_START_PRINT_JOB_CONFIG_ACTIVITY: {
+                    SomeArgs args = (SomeArgs) message.obj;
+                    IPrintClient client = (IPrintClient) args.arg1;
+                    IntentSender sender = (IntentSender) args.arg2;
+                    args.recycle();
+                    try {
+                        client.startPrintJobConfigActivity(sender);
+                    } catch (RemoteException re) {
+                        Slog.i(LOG_TAG, "Error starting print job config activity!", re);
+                    }
+                } break;
+
+                case MSG_ON_PRINT_JOB_QUEUED: {
+                    PrintJobInfo printJob = (PrintJobInfo) message.obj;
+                    if (mClient != null) {
+                        try {
+                            mClient.onPrintJobQueued(printJob);
+                        } catch (RemoteException re) {
+                            Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
+                        }
+                    }
+                } break;
+
+                case MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: {
+                    ComponentName service = (ComponentName) message.obj;
+                    if (mClient != null) {
+                        try {
+                            mClient.onAllPrintJobsForServiceHandled(service);
+                        } catch (RemoteException re) {
+                            Slog.e(LOG_TAG, "Error notify for all print jobs per service"
+                                    + " handled.", re);
+                        }
+                    }
+                } break;
+
+                case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
+                    if (mClient != null) {
+                        try {
+                            mClient.onAllPrintJobsHandled();
+                        } catch (RemoteException re) {
+                            Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
+                        }
+                    }
+                } break;
+
+                case MSG_CHECK_ALL_PRINTJOBS_HANDLED: {
+                    checkAllPrintJobsHandled();
+                } break;
+
+                case MSG_ON_PRINT_JOB_STATE_CHANGED: {
+                    if (mClient != null) {
+                        PrintJobInfo printJob = (PrintJobInfo) message.obj;
+                        try {
+                            mClient.onPrintJobStateChanged(printJob);
+                        } catch (RemoteException re) {
+                            Slog.e(LOG_TAG, "Error notify for print job state change.", re);
+                        }
+                    }
+                } break;
+            }
+        }
+    }
+
+    public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName,
+            int state, int appId) {
+        List<PrintJobInfo> foundPrintJobs = null;
+        synchronized (mLock) {
+            final int printJobCount = mPrintJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = mPrintJobs.get(i);
+                PrinterId printerId = printJob.getPrinterId();
+                final boolean sameComponent = (componentName == null
+                        || (printerId != null
+                        && componentName.equals(printerId.getServiceName())));
+                final boolean sameAppId = appId == PrintManager.APP_ID_ANY
+                        || printJob.getAppId() == appId;
+                final boolean sameState = (state == printJob.getState())
+                        || (state == PrintJobInfo.STATE_ANY)
+                        || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
+                            && isStateVisibleToUser(printJob.getState()))
+                        || (state == PrintJobInfo.STATE_ANY_ACTIVE
+                            && isActiveState(printJob.getState()));
+                if (sameComponent && sameAppId && sameState) {
+                    if (foundPrintJobs == null) {
+                        foundPrintJobs = new ArrayList<PrintJobInfo>();
+                    }
+                    foundPrintJobs.add(printJob);
+                }
+            }
+        }
+        return foundPrintJobs;
+    }
+
+    private boolean isStateVisibleToUser(int state) {
+        return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
+                || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
+                || state == PrintJobInfo.STATE_BLOCKED));
+    }
+
+    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+        synchronized (mLock) {
+            final int printJobCount = mPrintJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = mPrintJobs.get(i);
+                if (printJob.getId().equals(printJobId)
+                        && (appId == PrintManager.APP_ID_ANY
+                        || appId == printJob.getAppId())) {
+                    return printJob;
+                }
+            }
+            return null;
+        }
+    }
+
+    public void createPrintJob(PrintJobInfo printJob) {
+        synchronized (mLock) {
+            addPrintJobLocked(printJob);
+            setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
+        }
+    }
+
+    private void handleReadPrintJobsLocked() {
+        // Make a map with the files for a print job since we may have
+        // to delete some. One example of getting orphan files if the
+        // spooler crashes while constructing a print job. We do not
+        // persist partially populated print jobs under construction to
+        // avoid special handling for various attributes missing.
+        ArrayMap<PrintJobId, File> fileForJobMap = null;
+        File[] files = getFilesDir().listFiles();
+        if (files != null) {
+            final int fileCount = files.length;
+            for (int i = 0; i < fileCount; i++) {
+                File file = files[i];
+                if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
+                    if (fileForJobMap == null) {
+                        fileForJobMap = new ArrayMap<PrintJobId, File>();
+                    }
+                    String printJobIdString = file.getName().substring(0,
+                            PRINT_JOB_FILE_PREFIX.length());
+                    PrintJobId printJobId = PrintJobId.unflattenFromString(
+                            printJobIdString);
+                    fileForJobMap.put(printJobId, file);
+                }
+            }
+        }
+
+        final int printJobCount = mPrintJobs.size();
+        for (int i = 0; i < printJobCount; i++) {
+            PrintJobInfo printJob = mPrintJobs.get(i);
+
+            // We want to have only the orphan files at the end.
+            if (fileForJobMap != null) {
+                fileForJobMap.remove(printJob.getId());
+            }
+
+            // Update the notification.
+            mNotificationController.onPrintJobStateChanged(printJob);
+            switch (printJob.getState()) {
+                case PrintJobInfo.STATE_QUEUED:
+                case PrintJobInfo.STATE_STARTED:
+                case PrintJobInfo.STATE_BLOCKED: {
+                    // We have a print job that was queued or started or blocked in
+                    // the past but the device battery died or a crash occurred. In
+                    // this case we assume the print job failed and let the user
+                    // decide whether to restart the job or just cancel it.
+                    setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+                            getString(R.string.no_connection_to_printer));
+                } break;
+            }
+        }
+
+        // Delete the orphan files.
+        if (fileForJobMap != null) {
+            final int orphanFileCount = fileForJobMap.size();
+            for (int i = 0; i < orphanFileCount; i++) {
+                File file = fileForJobMap.valueAt(i);
+                file.delete();
+            }
+        }
+    }
+
+    public void checkAllPrintJobsHandled() {
+        synchronized (mLock) {
+            if (!hasActivePrintJobsLocked()) {
+                notifyOnAllPrintJobsHandled();
+            }
+        }
+    }
+
+    public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
+        final PrintJobInfo printJob;
+        synchronized (mLock) {
+            printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+        }
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                FileInputStream in = null;
+                FileOutputStream out = null;
+                try {
+                    if (printJob != null) {
+                        File file = generateFileForPrintJob(printJobId);
+                        in = new FileInputStream(file);
+                        out = new FileOutputStream(fd.getFileDescriptor());
+                    }
+                    final byte[] buffer = new byte[8192];
+                    while (true) {
+                        final int readByteCount = in.read(buffer);
+                        if (readByteCount < 0) {
+                            return null;
+                        }
+                        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);
+                    IoUtils.closeQuietly(fd);
+                }
+                Log.i(LOG_TAG, "[END WRITE]");
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+    }
+
+    public File generateFileForPrintJob(PrintJobId printJobId) {
+        return new File(getFilesDir(), PRINT_JOB_FILE_PREFIX
+                + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
+    }
+
+    private void addPrintJobLocked(PrintJobInfo printJob) {
+        mPrintJobs.add(printJob);
+        if (DEBUG_PRINT_JOB_LIFECYCLE) {
+            Slog.i(LOG_TAG, "[ADD] " + printJob);
+        }
+    }
+
+    private void removeObsoletePrintJobs() {
+        synchronized (mLock) {
+            final int printJobCount = mPrintJobs.size();
+            for (int i = printJobCount - 1; i >= 0; i--) {
+                PrintJobInfo printJob = mPrintJobs.get(i);
+                if (isObsoleteState(printJob.getState())) {
+                    mPrintJobs.remove(i);
+                    if (DEBUG_PRINT_JOB_LIFECYCLE) {
+                        Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
+                    }
+                    removePrintJobFileLocked(printJob.getId());
+                }
+            }
+            mPersistanceManager.writeStateLocked();
+        }
+    }
+
+    private void removePrintJobFileLocked(PrintJobId printJobId) {
+        File file = generateFileForPrintJob(printJobId);
+        if (file.exists()) {
+            file.delete();
+            if (DEBUG_PRINT_JOB_LIFECYCLE) {
+                Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId);
+            }
+        }
+    }
+
+    public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
+        boolean success = false;
+
+        synchronized (mLock) {
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+            if (printJob != null) {
+                final int oldState = printJob.getState();
+                if (oldState == state) {
+                    return false;
+                }
+
+                success = true;
+
+                printJob.setState(state);
+                printJob.setStateReason(error);
+                mNotificationController.onPrintJobStateChanged(printJob);
+
+                if (DEBUG_PRINT_JOB_LIFECYCLE) {
+                    Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
+                }
+
+                switch (state) {
+                    case PrintJobInfo.STATE_COMPLETED:
+                    case PrintJobInfo.STATE_CANCELED:
+                        mPrintJobs.remove(printJob);
+                        removePrintJobFileLocked(printJob.getId());
+                        // $fall-through$
+
+                    case PrintJobInfo.STATE_FAILED: {
+                        PrinterId printerId = printJob.getPrinterId();
+                        if (printerId != null) {
+                            ComponentName service = printerId.getServiceName();
+                            if (!hasActivePrintJobsForServiceLocked(service)) {
+                                sendOnAllPrintJobsForServiceHandled(service);
+                            }
+                        }
+                    } break;
+
+                    case PrintJobInfo.STATE_QUEUED: {
+                        sendOnPrintJobQueued(new PrintJobInfo(printJob));
+                    }  break;
+                }
+
+                if (shouldPersistPrintJob(printJob)) {
+                    mPersistanceManager.writeStateLocked();
+                }
+
+                if (!hasActivePrintJobsLocked()) {
+                    notifyOnAllPrintJobsHandled();
+                }
+
+                Message message = mHandlerCaller.obtainMessageO(
+                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
+                        printJob);
+                mHandlerCaller.executeOrSendMessage(message);
+            }
+        }
+
+        return success;
+    }
+
+    public boolean hasActivePrintJobsLocked() {
+        final int printJobCount = mPrintJobs.size();
+        for (int i = 0; i < printJobCount; i++) {
+            PrintJobInfo printJob = mPrintJobs.get(i);
+            if (isActiveState(printJob.getState())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
+        final int printJobCount = mPrintJobs.size();
+        for (int i = 0; i < printJobCount; i++) {
+            PrintJobInfo printJob = mPrintJobs.get(i);
+            if (isActiveState(printJob.getState())
+                    && printJob.getPrinterId().getServiceName().equals(service)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isObsoleteState(int printJobState) {
+        return (isTeminalState(printJobState)
+                || printJobState == PrintJobInfo.STATE_QUEUED);
+    }
+
+    private boolean isActiveState(int printJobState) {
+        return printJobState == PrintJobInfo.STATE_CREATED
+                || printJobState == PrintJobInfo.STATE_QUEUED
+                || printJobState == PrintJobInfo.STATE_STARTED
+                || printJobState == PrintJobInfo.STATE_BLOCKED;
+    }
+
+    private boolean isTeminalState(int printJobState) {
+        return printJobState == PrintJobInfo.STATE_COMPLETED
+                || printJobState == PrintJobInfo.STATE_CANCELED;
+    }
+
+    public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
+        synchronized (mLock) {
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+            if (printJob != null) {
+                String printJobTag = printJob.getTag();
+                if (printJobTag == null) {
+                    if (tag == null) {
+                        return false;
+                    }
+                } else if (printJobTag.equals(tag)) {
+                    return false;
+                }
+                printJob.setTag(tag);
+                if (shouldPersistPrintJob(printJob)) {
+                    mPersistanceManager.writeStateLocked();
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
+        synchronized (mLock) {
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+            if (printJob != null) {
+                printJob.setCopies(copies);
+            }
+        }
+    }
+
+    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);
+            }
+        }
+    }
+
+    private boolean shouldPersistPrintJob(PrintJobInfo printJob) {
+        return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
+    }
+
+    private void notifyOnAllPrintJobsHandled() {
+        // This has to run on the tread that is persisting the current state
+        // since this call may result in the system unbinding from the spooler
+        // and as a result the spooler process may get killed before the write
+        // completes.
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                sendOnAllPrintJobsHandled();
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+    }
+
+    private final class PersistenceManager {
+        private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
+
+        private static final String TAG_SPOOLER = "spooler";
+        private static final String TAG_JOB = "job";
+
+        private static final String TAG_PRINTER_ID = "printerId";
+        private static final String TAG_PAGE_RANGE = "pageRange";
+        private static final String TAG_ATTRIBUTES = "attributes";
+        private static final String TAG_DOCUMENT_INFO = "documentInfo";
+
+        private static final String ATTR_ID = "id";
+        private static final String ATTR_LABEL = "label";
+        private static final String ATTR_LABEL_RES_ID = "labelResId";
+        private static final String ATTR_PACKAGE_NAME = "packageName";
+        private static final String ATTR_STATE = "state";
+        private static final String ATTR_APP_ID = "appId";
+        private static final String ATTR_USER_ID = "userId";
+        private static final String ATTR_TAG = "tag";
+        private static final String ATTR_CREATION_TIME = "creationTime";
+        private static final String ATTR_COPIES = "copies";
+        private static final String ATTR_PRINTER_NAME = "printerName";
+        private static final String ATTR_STATE_REASON = "stateReason";
+
+        private static final String TAG_MEDIA_SIZE = "mediaSize";
+        private static final String TAG_RESOLUTION = "resolution";
+        private static final String TAG_MARGINS = "margins";
+
+        private static final String ATTR_COLOR_MODE = "colorMode";
+
+        private static final String ATTR_LOCAL_ID = "localId";
+        private static final String ATTR_SERVICE_NAME = "serviceName";
+
+        private static final String ATTR_WIDTH_MILS = "widthMils";
+        private static final String ATTR_HEIGHT_MILS = "heightMils";
+
+        private static final String ATTR_HORIZONTAL_DPI = "horizontalDip";
+        private static final String ATTR_VERTICAL_DPI = "verticalDpi";
+
+        private static final String ATTR_LEFT_MILS = "leftMils";
+        private static final String ATTR_TOP_MILS = "topMils";
+        private static final String ATTR_RIGHT_MILS = "rightMils";
+        private static final String ATTR_BOTTOM_MILS = "bottomMils";
+
+        private static final String ATTR_START = "start";
+        private static final String ATTR_END = "end";
+
+        private static final String ATTR_NAME = "name";
+        private static final String ATTR_PAGE_COUNT = "pageCount";
+        private static final String ATTR_CONTENT_TYPE = "contentType";
+
+        private final AtomicFile mStatePersistFile;
+
+        private boolean mWriteStateScheduled;
+
+        private PersistenceManager() {
+            mStatePersistFile = new AtomicFile(new File(getFilesDir(),
+                    PERSIST_FILE_NAME));
+        }
+
+        public void writeStateLocked() {
+            if (!PERSISTNECE_MANAGER_ENABLED) {
+                return;
+            }
+            if (mWriteStateScheduled) {
+                return;
+            }
+            mWriteStateScheduled = true;
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    synchronized (mLock) {
+                        mWriteStateScheduled = false;
+                        doWriteStateLocked();
+                    }
+                    return null;
+                }
+            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+        }
+
+        private void doWriteStateLocked() {
+            if (DEBUG_PERSISTENCE) {
+                Log.i(LOG_TAG, "[PERSIST START]");
+            }
+            FileOutputStream out = null;
+            try {
+                out = mStatePersistFile.startWrite();
+
+                XmlSerializer serializer = new FastXmlSerializer();
+                serializer.setOutput(out, "utf-8");
+                serializer.startDocument(null, true);
+                serializer.startTag(null, TAG_SPOOLER);
+
+                List<PrintJobInfo> printJobs = mPrintJobs;
+
+                final int printJobCount = printJobs.size();
+                for (int j = 0; j < printJobCount; j++) {
+                    PrintJobInfo printJob = printJobs.get(j);
+
+                    serializer.startTag(null, TAG_JOB);
+
+                    serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
+                    serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
+                    serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
+                    serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
+                    serializer.attribute(null, ATTR_USER_ID, String.valueOf(printJob.getUserId()));
+                    String tag = printJob.getTag();
+                    if (tag != null) {
+                        serializer.attribute(null, ATTR_TAG, tag);
+                    }
+                    serializer.attribute(null, ATTR_CREATION_TIME, String.valueOf(
+                            printJob.getCreationTime()));
+                    serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
+                    String printerName = printJob.getPrinterName();
+                    if (!TextUtils.isEmpty(printerName)) {
+                        serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
+                    }
+                    String stateReason = printJob.getStateReason();
+                    if (!TextUtils.isEmpty(stateReason)) {
+                        serializer.attribute(null, ATTR_STATE_REASON, stateReason);
+                    }
+
+                    PrinterId printerId = printJob.getPrinterId();
+                    if (printerId != null) {
+                        serializer.startTag(null, TAG_PRINTER_ID);
+                        serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
+                        serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
+                                .flattenToString());
+                        serializer.endTag(null, TAG_PRINTER_ID);
+                    }
+
+                    PageRange[] pages = printJob.getPages();
+                    if (pages != null) {
+                        for (int i = 0; i < pages.length; i++) {
+                            serializer.startTag(null, TAG_PAGE_RANGE);
+                            serializer.attribute(null, ATTR_START, String.valueOf(
+                                    pages[i].getStart()));
+                            serializer.attribute(null, ATTR_END, String.valueOf(
+                                    pages[i].getEnd()));
+                            serializer.endTag(null, TAG_PAGE_RANGE);
+                        }
+                    }
+
+                    PrintAttributes attributes = printJob.getAttributes();
+                    if (attributes != null) {
+                        serializer.startTag(null, TAG_ATTRIBUTES);
+
+                        final int colorMode = attributes.getColorMode();
+                        serializer.attribute(null, ATTR_COLOR_MODE,
+                                String.valueOf(colorMode));
+
+                        MediaSize mediaSize = attributes.getMediaSize();
+                        if (mediaSize != null) {
+                            serializer.startTag(null, TAG_MEDIA_SIZE);
+                            serializer.attribute(null, ATTR_ID, mediaSize.getId());
+                            serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf(
+                                    mediaSize.getWidthMils()));
+                            serializer.attribute(null, ATTR_HEIGHT_MILS, String.valueOf(
+                                    mediaSize.getHeightMils()));
+                            // We prefer to store only the package name and
+                            // resource id and fallback to the label.
+                            if (!TextUtils.isEmpty(mediaSize.mPackageName)
+                                    && mediaSize.mLabelResId > 0) {
+                                serializer.attribute(null, ATTR_PACKAGE_NAME,
+                                        mediaSize.mPackageName);
+                                serializer.attribute(null, ATTR_LABEL_RES_ID,
+                                        String.valueOf(mediaSize.mLabelResId));
+                            } else {
+                                serializer.attribute(null, ATTR_LABEL,
+                                        mediaSize.getLabel(getPackageManager()));
+                            }
+                            serializer.endTag(null, TAG_MEDIA_SIZE);
+                        }
+
+                        Resolution resolution = attributes.getResolution();
+                        if (resolution != null) {
+                            serializer.startTag(null, TAG_RESOLUTION);
+                            serializer.attribute(null, ATTR_ID, resolution.getId());
+                            serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf(
+                                    resolution.getHorizontalDpi()));
+                            serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
+                                    resolution.getVerticalDpi()));
+                            serializer.attribute(null, ATTR_LABEL,
+                                    resolution.getLabel());
+                            serializer.endTag(null, TAG_RESOLUTION);
+                        }
+
+                        Margins margins = attributes.getMinMargins();
+                        if (margins != null) {
+                            serializer.startTag(null, TAG_MARGINS);
+                            serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(
+                                    margins.getLeftMils()));
+                            serializer.attribute(null, ATTR_TOP_MILS, String.valueOf(
+                                    margins.getTopMils()));
+                            serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf(
+                                    margins.getRightMils()));
+                            serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf(
+                                    margins.getBottomMils()));
+                            serializer.endTag(null, TAG_MARGINS);
+                        }
+
+                        serializer.endTag(null, TAG_ATTRIBUTES);
+                    }
+
+                    PrintDocumentInfo documentInfo = printJob.getDocumentInfo();
+                    if (documentInfo != null) {
+                        serializer.startTag(null, TAG_DOCUMENT_INFO);
+                        serializer.attribute(null, ATTR_NAME, documentInfo.getName());
+                        serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf(
+                                documentInfo.getContentType()));
+                        serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf(
+                                documentInfo.getPageCount()));
+                        serializer.endTag(null, TAG_DOCUMENT_INFO);
+                    }
+
+                    serializer.endTag(null, TAG_JOB);
+
+                    if (DEBUG_PERSISTENCE) {
+                        Log.i(LOG_TAG, "[PERSISTED] " + printJob);
+                    }
+                }
+
+                serializer.endTag(null, TAG_SPOOLER);
+                serializer.endDocument();
+                mStatePersistFile.finishWrite(out);
+                if (DEBUG_PERSISTENCE) {
+                    Log.i(LOG_TAG, "[PERSIST END]");
+                }
+            } catch (IOException e) {
+                Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
+                mStatePersistFile.failWrite(out);
+            } finally {
+                IoUtils.closeQuietly(out);
+            }
+        }
+
+        public void readStateLocked() {
+            if (!PERSISTNECE_MANAGER_ENABLED) {
+                return;
+            }
+            FileInputStream in = null;
+            try {
+                in = mStatePersistFile.openRead();
+            } catch (FileNotFoundException e) {
+                Log.i(LOG_TAG, "No existing print spooler state.");
+                return;
+            }
+            try {
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(in, null);
+                parseState(parser);
+            } catch (IllegalStateException ise) {
+                Slog.w(LOG_TAG, "Failed parsing ", ise);
+            } catch (NullPointerException npe) {
+                Slog.w(LOG_TAG, "Failed parsing ", npe);
+            } catch (NumberFormatException nfe) {
+                Slog.w(LOG_TAG, "Failed parsing ", nfe);
+            } catch (XmlPullParserException xppe) {
+                Slog.w(LOG_TAG, "Failed parsing ", xppe);
+            } catch (IOException ioe) {
+                Slog.w(LOG_TAG, "Failed parsing ", ioe);
+            } catch (IndexOutOfBoundsException iobe) {
+                Slog.w(LOG_TAG, "Failed parsing ", iobe);
+            } finally {
+                IoUtils.closeQuietly(in);
+            }
+        }
+
+        private void parseState(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            parser.next();
+            skipEmptyTextTags(parser);
+            expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER);
+            parser.next();
+
+            while (parsePrintJob(parser)) {
+                parser.next();
+            }
+
+            skipEmptyTextTags(parser);
+            expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER);
+        }
+
+        private boolean parsePrintJob(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            skipEmptyTextTags(parser);
+            if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
+                return false;
+            }
+
+            PrintJobInfo printJob = new PrintJobInfo();
+
+            PrintJobId printJobId = PrintJobId.unflattenFromString(
+                    parser.getAttributeValue(null, ATTR_ID));
+            printJob.setId(printJobId);
+            String label = parser.getAttributeValue(null, ATTR_LABEL);
+            printJob.setLabel(label);
+            final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE));
+            printJob.setState(state);
+            final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID));
+            printJob.setAppId(appId);
+            final int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USER_ID));
+            printJob.setUserId(userId);
+            String tag = parser.getAttributeValue(null, ATTR_TAG);
+            printJob.setTag(tag);
+            String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME);
+            printJob.setCreationTime(Long.parseLong(creationTime));
+            String copies = parser.getAttributeValue(null, ATTR_COPIES);
+            printJob.setCopies(Integer.parseInt(copies));
+            String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
+            printJob.setPrinterName(printerName);
+            String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
+            printJob.setStateReason(stateReason);
+
+            parser.next();
+
+            skipEmptyTextTags(parser);
+            if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
+                String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
+                ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
+                        null, ATTR_SERVICE_NAME));
+                printJob.setPrinterId(new PrinterId(service, localId));
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
+                parser.next();
+            }
+
+            skipEmptyTextTags(parser);
+            List<PageRange> pageRanges = null;
+            while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) {
+                final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START));
+                final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END));
+                PageRange pageRange = new PageRange(start, end);
+                if (pageRanges == null) {
+                    pageRanges = new ArrayList<PageRange>();
+                }
+                pageRanges.add(pageRange);
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE);
+                parser.next();
+            }
+            if (pageRanges != null) {
+                PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+                pageRanges.toArray(pageRangesArray);
+                printJob.setPages(pageRangesArray);
+            }
+
+            skipEmptyTextTags(parser);
+            if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) {
+
+                PrintAttributes.Builder builder = new PrintAttributes.Builder();
+
+                String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
+                builder.setColorMode(Integer.parseInt(colorMode));
+
+                parser.next();
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) {
+                    String id = parser.getAttributeValue(null, ATTR_ID);
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    final int widthMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_WIDTH_MILS));
+                    final int heightMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_HEIGHT_MILS));
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                    String labelResIdString = parser.getAttributeValue(null, ATTR_LABEL_RES_ID);
+                    final int labelResId = (labelResIdString != null)
+                            ? Integer.parseInt(labelResIdString) : 0;
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    MediaSize mediaSize = new MediaSize(id, label, packageName, labelResId,
+                                widthMils, heightMils);
+                    builder.setMediaSize(mediaSize);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE);
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) {
+                    String id = parser.getAttributeValue(null, ATTR_ID);
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_HORIZONTAL_DPI));
+                    final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_VERTICAL_DPI));
+                    Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
+                    builder.setResolution(resolution);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION);
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) {
+                    final int leftMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_LEFT_MILS));
+                    final int topMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_TOP_MILS));
+                    final int rightMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_RIGHT_MILS));
+                    final int bottomMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_BOTTOM_MILS));
+                    Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
+                    builder.setMinMargins(margins);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
+                    parser.next();
+                }
+
+                printJob.setAttributes(builder.build());
+
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
+                parser.next();
+            }
+
+            skipEmptyTextTags(parser);
+            if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) {
+                String name = parser.getAttributeValue(null, ATTR_NAME);
+                final int pageCount = Integer.parseInt(parser.getAttributeValue(null,
+                        ATTR_PAGE_COUNT));
+                final int contentType = Integer.parseInt(parser.getAttributeValue(null,
+                        ATTR_CONTENT_TYPE));
+                PrintDocumentInfo info = new PrintDocumentInfo.Builder(name)
+                        .setPageCount(pageCount)
+                        .setContentType(contentType).build();
+                printJob.setDocumentInfo(info);
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO);
+                parser.next();
+            }
+
+            mPrintJobs.add(printJob);
+
+            if (DEBUG_PERSISTENCE) {
+                Log.i(LOG_TAG, "[RESTORED] " + printJob);
+            }
+
+            skipEmptyTextTags(parser);
+            expect(parser, XmlPullParser.END_TAG, TAG_JOB);
+
+            return true;
+        }
+
+        private void expect(XmlPullParser parser, int type, String tag)
+                throws IOException, XmlPullParserException {
+            if (!accept(parser, type, tag)) {
+                throw new XmlPullParserException("Exepected event: " + type
+                        + " and tag: " + tag + " but got event: " + parser.getEventType()
+                        + " and tag:" + parser.getName());
+            }
+        }
+
+        private void skipEmptyTextTags(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            while (accept(parser, XmlPullParser.TEXT, null)
+                    && "\n".equals(parser.getText())) {
+                parser.next();
+            }
+        }
+
+        private boolean accept(XmlPullParser parser, int type, String tag)
+                throws IOException, XmlPullParserException {
+            if (parser.getEventType() != type) {
+                return false;
+            }
+            if (tag != null) {
+                if (!tag.equals(parser.getName())) {
+                    return false;
+                }
+            } else if (parser.getName() != null) {
+                return false;
+            }
+            return true;
+        }
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
new file mode 100644
index 0000000..fd14af9
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -0,0 +1,140 @@
+/*
+ * 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);
+        }
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java
new file mode 100644
index 0000000..141dbd1
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
new file mode 100644
index 0000000..c888e2c
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
@@ -0,0 +1,424 @@
+/*
+ * 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.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.app.ListFragment;
+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;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.PrintServiceInfo;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.ListView;
+import android.widget.SearchView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is a fragment for selecting a printer.
+ */
+public final class SelectPrinterFragment extends ListFragment {
+
+    private static final String LOG_TAG = "SelectPrinterFragment";
+
+    private static final int LOADER_ID_PRINTERS_LOADER = 1;
+
+    private static final String FRAGMRNT_TAG_ADD_PRINTER_DIALOG =
+            "FRAGMRNT_TAG_ADD_PRINTER_DIALOG";
+
+    private static final String FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS =
+            "FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS";
+
+    private final ArrayList<PrintServiceInfo> mAddPrinterServices =
+            new ArrayList<PrintServiceInfo>();
+
+    public static interface OnPrinterSelectedListener {
+        public void onPrinterSelected(PrinterId printerId);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        setListAdapter(new DestinationAdapter());
+        View emptyView = getActivity().findViewById(R.id.empty_print_state);
+        getListView().setEmptyView(emptyView);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        inflater.inflate(R.menu.select_printer_activity, menu);
+
+        MenuItem searchItem = menu.findItem(R.id.action_search);
+        SearchView searchView = (SearchView) searchItem.getActionView();
+        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+            @Override
+            public boolean onQueryTextSubmit(String query) {
+                return true;
+            }
+
+            @Override
+            public boolean onQueryTextChange(String searchString) {
+                ((DestinationAdapter) getListAdapter()).getFilter().filter(searchString);
+                return true;
+            }
+        });
+
+        if (mAddPrinterServices.isEmpty()) {
+            menu.removeItem(R.id.action_add_printer);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        updateAddPrintersAdapter();
+        getActivity().invalidateOptionsMenu();
+        super.onResume();
+    }
+
+    @Override
+    public void onListItemClick(ListView list, View view, int position, long id) {
+        PrinterInfo printer = (PrinterInfo) list.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");
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.action_add_printer) {
+            showAddPrinterSelectionDialog();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void updateAddPrintersAdapter() {
+        mAddPrinterServices.clear();
+
+        // Get all enabled print services.
+        PrintManager printManager = (PrintManager) getActivity()
+                .getSystemService(Context.PRINT_SERVICE);
+        List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices();
+
+        // No enabled print services - done.
+        if (enabledServices.isEmpty()) {
+            return;
+        }
+
+        // Find the services with valid add printers activities.
+        final int enabledServiceCount = enabledServices.size();
+        for (int i = 0; i < enabledServiceCount; i++) {
+            PrintServiceInfo enabledService = enabledServices.get(i);
+
+            // No add printers activity declared - done.
+            if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) {
+                continue;
+            }
+
+            ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
+            ComponentName addPrintersComponentName = new ComponentName(
+                    serviceInfo.packageName, enabledService.getAddPrintersActivityName());
+            Intent addPritnersIntent = new Intent()
+                .setComponent(addPrintersComponentName);
+
+            // The add printers activity is valid - add it.
+            PackageManager pm = getActivity().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())
+                                        == PackageManager.PERMISSION_GRANTED)) {
+                    mAddPrinterServices.add(enabledService);
+                }
+            }
+        }
+    }
+
+    private void showAddPrinterSelectionDialog() {
+        FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        Fragment oldFragment = getFragmentManager().findFragmentByTag(
+                FRAGMRNT_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,
+                mAddPrinterServices);
+        newFragment.setArguments(arguments);
+        transaction.add(newFragment, FRAGMRNT_TAG_ADD_PRINTER_DIALOG);
+        transaction.commit();
+    }
+
+    public static class AddPrinterAlertDialogFragment extends DialogFragment {
+
+        private static final String DEFAULT_MARKET_QUERY_STRING =
+                "market://search?q=print";
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+                    .setTitle(R.string.choose_print_service);
+
+            final List<PrintServiceInfo> printServices = (List<PrintServiceInfo>) (List<?>)
+                    getArguments().getParcelableArrayList(FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS);
+
+            ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
+                    android.R.layout.simple_list_item_1);
+            final int printServiceCount = printServices.size();
+            for (int i = 0; i < printServiceCount; i++) {
+                PrintServiceInfo printService = printServices.get(i);
+                adapter.add(printService.getResolveInfo().loadLabel(
+                        getActivity().getPackageManager()).toString());
+            }
+
+            builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    PrintServiceInfo printService = printServices.get(which);
+                    ComponentName componentName = new ComponentName(
+                            printService.getResolveInfo().serviceInfo.packageName,
+                            printService.getAddPrintersActivityName());
+                    Intent intent = new Intent(Intent.ACTION_MAIN);
+                    intent.setComponent(componentName);
+                    try {
+                        startActivity(intent);
+                    } catch (ActivityNotFoundException anfe) {
+                        Log.w(LOG_TAG, "Couldn't start settings activity", anfe);
+                    }
+                }
+            });
+
+            Uri marketUri = Uri.parse(DEFAULT_MARKET_QUERY_STRING);
+            final Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
+            if (getActivity().getPackageManager().resolveActivity(marketIntent, 0) != null) {
+                builder.setPositiveButton(R.string.add_print_service_label,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int whichButton) {
+                            try {
+                                startActivity(marketIntent);
+                            } catch (ActivityNotFoundException anfe) {
+                                Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
+                            }
+                        }
+                    });
+            }
+
+            return builder.create();
+        }
+    }
+
+    private final class DestinationAdapter extends BaseAdapter
+            implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>, Filterable {
+
+        private final Object mLock = new Object();
+
+        private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
+
+        private final List<PrinterInfo> mFilteredPrinters = new ArrayList<PrinterInfo>();
+
+        private CharSequence mLastSearchString;
+
+        public DestinationAdapter() {
+            getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
+        }
+
+        @Override
+        public Filter getFilter() {
+            return new Filter() {
+                @Override
+                protected FilterResults performFiltering(CharSequence constraint) {
+                    synchronized (mLock) {
+                        if (TextUtils.isEmpty(constraint)) {
+                            return null;
+                        }
+                        FilterResults results = new FilterResults();
+                        List<PrinterInfo> filteredPrinters = new ArrayList<PrinterInfo>();
+                        String constraintLowerCase = constraint.toString().toLowerCase();
+                        final int printerCount = mPrinters.size();
+                        for (int i = 0; i < printerCount; i++) {
+                            PrinterInfo printer = mPrinters.get(i);
+                            if (printer.getName().toLowerCase().contains(constraintLowerCase)) {
+                                filteredPrinters.add(printer);
+                            }
+                        }
+                        results.values = filteredPrinters;
+                        results.count = filteredPrinters.size();
+                        return results;
+                    }
+                }
+
+                @Override
+                @SuppressWarnings("unchecked")
+                protected void publishResults(CharSequence constraint, FilterResults results) {
+                    synchronized (mLock) {
+                        mLastSearchString = constraint;
+                        mFilteredPrinters.clear();
+                        if (results == null) {
+                            mFilteredPrinters.addAll(mPrinters);
+                        } else {
+                            List<PrinterInfo> printers = (List<PrinterInfo>) results.values;
+                            mFilteredPrinters.addAll(printers);
+                        }
+                    }
+                    notifyDataSetChanged();
+                }
+            };
+        }
+
+        @Override
+        public int getCount() {
+            synchronized (mLock) {
+                return mFilteredPrinters.size();
+            }
+        }
+
+        @Override
+        public Object getItem(int position) {
+            synchronized (mLock) {
+                return mFilteredPrinters.get(position);
+            }
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        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(
+                        R.layout.spinner_dropdown_item, parent, false);
+            }
+
+            CharSequence title = null;
+            CharSequence subtitle = null;
+
+            PrinterInfo printer = (PrinterInfo) getItem(position);
+            title = printer.getName();
+            try {
+                PackageManager pm = getActivity().getPackageManager();
+                PackageInfo packageInfo = pm.getPackageInfo(printer.getId()
+                        .getServiceName().getPackageName(), 0);
+                subtitle = packageInfo.applicationInfo.loadLabel(pm);
+            } 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);
+            }
+
+            return convertView;
+        }
+
+        @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();
+        }
+    }
+}
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index a2ea554..da929ae 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -9,6 +9,7 @@
 
 LOCAL_PACKAGE_NAME := SettingsProvider
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 include $(BUILD_PACKAGE)
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 3f04470..7b09092 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -137,6 +137,7 @@
     static class Network {
         String ssid = "";  // equals() and hashCode() need these to be non-null
         String key_mgmt = "";
+        boolean certUsed = false;
         final ArrayList<String> rawLines = new ArrayList<String>();
 
         public static Network readFromStream(BufferedReader in) {
@@ -167,6 +168,12 @@
                 ssid = line;
             } else if (line.startsWith("key_mgmt")) {
                 key_mgmt = line;
+            } else if (line.startsWith("client_cert=")) {
+                certUsed = true;
+            } else if (line.startsWith("ca_cert=")) {
+                certUsed = true;
+            } else if (line.startsWith("ca_path=")) {
+                certUsed = true;
             }
         }
 
@@ -246,6 +253,13 @@
 
         public void write(Writer w) throws IOException {
             for (Network net : mNetworks) {
+                if (net.certUsed) {
+                    // Networks that use certificates for authentication can't be restored
+                    // because the certificates they need don't get restored (because they
+                    // are stored in keystore, and can't be restored)
+                    continue;
+                }
+
                 net.write(w);
             }
         }
@@ -738,10 +752,12 @@
                 }
             }
 
+            // Intercept the keys and see if they need special handling
+            value = mSettingsHelper.onBackupValue(key, value);
+
             if (value == null) {
                 continue;
             }
-
             // Write the key and value in the intermediary array.
             byte[] keyBytes = key.getBytes();
             totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index a446e40..dd7a828 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -23,6 +23,8 @@
 import android.content.res.Configuration;
 import android.location.LocationManager;
 import android.media.AudioManager;
+import android.media.RingtoneManager;
+import android.net.Uri;
 import android.os.IPowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -33,6 +35,7 @@
 import java.util.Locale;
 
 public class SettingsHelper {
+    private static final String SILENT_RINGTONE = "_silent";
     private Context mContext;
     private AudioManager mAudioManager;
 
@@ -63,10 +66,60 @@
             setAutoRestore(Integer.parseInt(value) == 1);
         } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
             return false;
+        } else if (Settings.System.RINGTONE.equals(name)
+                || Settings.System.NOTIFICATION_SOUND.equals(name)) {
+            setRingtone(name, value);
+            return false;
         }
         return true;
     }
 
+    public String onBackupValue(String name, String value) {
+        // Special processing for backing up ringtones
+        if (Settings.System.RINGTONE.equals(name)
+                || Settings.System.NOTIFICATION_SOUND.equals(name)) {
+            if (value == null) {
+                // Silent ringtone
+                return SILENT_RINGTONE;
+            } else {
+                return getCanonicalRingtoneValue(value);
+            }
+        }
+        // Return the original value
+        return value;
+    }
+
+    /**
+     * Sets the ringtone of type specified by the name.
+     *
+     * @param name should be Settings.System.RINGTONE or Settings.System.NOTIFICATION_SOUND.
+     * @param value can be a canonicalized uri or "_silent" to indicate a silent (null) ringtone.
+     */
+    private void setRingtone(String name, String value) {
+        // If it's null, don't change the default
+        if (value == null) return;
+        Uri ringtoneUri = null;
+        if (SILENT_RINGTONE.equals(value)) {
+            ringtoneUri = null;
+        } else {
+            Uri canonicalUri = Uri.parse(value);
+            ringtoneUri = mContext.getContentResolver().uncanonicalize(canonicalUri);
+            if (ringtoneUri == null) {
+                // Unrecognized or invalid Uri, don't restore
+                return;
+            }
+        }
+        final int ringtoneType = Settings.System.RINGTONE.equals(name)
+                ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION;
+        RingtoneManager.setActualDefaultRingtoneUri(mContext, ringtoneType, ringtoneUri);
+    }
+
+    private String getCanonicalRingtoneValue(String value) {
+        final Uri ringtoneUri = Uri.parse(value);
+        final Uri canonicalUri = mContext.getContentResolver().canonicalize(ringtoneUri);
+        return canonicalUri == null ? null : canonicalUri.toString();
+    }
+
     private boolean isAlreadyConfiguredCriticalAccessibilitySetting(String name) {
         // These are the critical accessibility settings that are required for a
         // blind user to be able to interact with the device. If these settings are
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 0177504..bc02b0d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -33,6 +33,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.content.res.AssetFileDescriptor;
 import android.database.AbstractCursor;
 import android.database.Cursor;
@@ -49,7 +50,6 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.DrmStore;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -478,6 +478,13 @@
         try {
             final String value = c.moveToNext() ? c.getString(0) : null;
             if (value == null) {
+                // sanity-check the user before touching the db
+                final UserInfo user = mUserManager.getUserInfo(userHandle);
+                if (user == null) {
+                    // can happen due to races when deleting users; treat as benign
+                    return false;
+                }
+
                 final SecureRandom random = new SecureRandom();
                 final String newAndroidIdValue = Long.toHexString(random.nextLong());
                 final ContentValues values = new ContentValues();
@@ -491,7 +498,7 @@
                 Slog.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue
                         + "] for user " + userHandle);
                 // Write a dropbox entry if it's a restricted profile
-                if (mUserManager.getUserInfo(userHandle).isRestricted()) {
+                if (user.isRestricted()) {
                     DropBoxManager dbm = (DropBoxManager)
                             getContext().getSystemService(Context.DROPBOX_SERVICE);
                     if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
@@ -560,8 +567,7 @@
      * Fast path that avoids the use of chatty remoted Cursors.
      */
     @Override
-    public Bundle callFromPackage(String callingPackage, String method, String request,
-            Bundle args) {
+    public Bundle call(String method, String request, Bundle args) {
         int callingUser = UserHandle.getCallingUserId();
         if (args != null) {
             int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser);
@@ -616,7 +622,7 @@
 
         // Also need to take care of app op.
         if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SETTINGS, Binder.getCallingUid(),
-                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                getCallingPackage()) != AppOpsManager.MODE_ALLOWED) {
             return null;
         }
 
@@ -992,7 +998,7 @@
         /*
          * When a client attempts to openFile the default ringtone or
          * notification setting Uri, we will proxy the call to the current
-         * default ringtone's Uri (if it is in the DRM or media provider).
+         * default ringtone's Uri (if it is in the media provider).
          */
         int ringtoneType = RingtoneManager.getDefaultType(uri);
         // Above call returns -1 if the Uri doesn't match a default type
@@ -1003,22 +1009,9 @@
             Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
 
             if (soundUri != null) {
-                // Only proxy the openFile call to drm or media providers
+                // Proxy the openFile call to media provider
                 String authority = soundUri.getAuthority();
-                boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
-                if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
-
-                    if (isDrmAuthority) {
-                        try {
-                            // Check DRM access permission here, since once we
-                            // do the below call the DRM will be checking our
-                            // permission, not our caller's permission
-                            DrmStore.enforceAccessDrmPermission(context);
-                        } catch (SecurityException e) {
-                            throw new FileNotFoundException(e.getMessage());
-                        }
-                    }
-
+                if (authority.equals(MediaStore.AUTHORITY)) {
                     return context.getContentResolver().openFileDescriptor(soundUri, mode);
                 }
             }
@@ -1033,7 +1026,7 @@
         /*
          * When a client attempts to openFile the default ringtone or
          * notification setting Uri, we will proxy the call to the current
-         * default ringtone's Uri (if it is in the DRM or media provider).
+         * default ringtone's Uri (if it is in the media provider).
          */
         int ringtoneType = RingtoneManager.getDefaultType(uri);
         // Above call returns -1 if the Uri doesn't match a default type
@@ -1044,22 +1037,9 @@
             Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
 
             if (soundUri != null) {
-                // Only proxy the openFile call to drm or media providers
+                // Proxy the openFile call to media provider
                 String authority = soundUri.getAuthority();
-                boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
-                if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
-
-                    if (isDrmAuthority) {
-                        try {
-                            // Check DRM access permission here, since once we
-                            // do the below call the DRM will be checking our
-                            // permission, not our caller's permission
-                            DrmStore.enforceAccessDrmPermission(context);
-                        } catch (SecurityException e) {
-                            throw new FileNotFoundException(e.getMessage());
-                        }
-                    }
-
+                if (authority.equals(MediaStore.AUTHORITY)) {
                     ParcelFileDescriptor pfd = null;
                     try {
                         pfd = context.getContentResolver().openFileDescriptor(soundUri, mode);
diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk
index 1d4f4da7..a213965f 100644
--- a/packages/SharedStorageBackup/Android.mk
+++ b/packages/SharedStorageBackup/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_PACKAGE_NAME := SharedStorageBackup
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 include $(BUILD_PACKAGE)
 
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
index 7ebe096..0485334 100644
--- a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
@@ -57,7 +57,7 @@
                 int token, IBackupManager callbackBinder) {
             final FileDescriptor outFd = data.getFileDescriptor();
             try {
-                File obbDir = Environment.getExternalStorageAppObbDirectory(packageName);
+                File obbDir = Environment.buildExternalStorageAppObbDirs(packageName)[0];
                 if (obbDir != null) {
                     if (obbDir.exists()) {
                         ArrayList<File> obbList = allFileContents(obbDir);
@@ -106,7 +106,7 @@
                 long fileSize, int type, String path, long mode, long mtime,
                 int token, IBackupManager callbackBinder) {
             try {
-                File outFile = Environment.getExternalStorageAppObbDirectory(packageName);
+                File outFile = Environment.buildExternalStorageAppObbDirs(packageName)[0];
                 if (outFile != null) {
                     outFile = new File(outFile, path);
                 }
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index fc4c0f5..5bd48c6 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -9,5 +9,6 @@
 
 LOCAL_PACKAGE_NAME := Shell
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 include $(BUILD_PACKAGE)
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
new file mode 100644
index 0000000..3dc6a0f
--- /dev/null
+++ b/packages/Shell/res/values-af/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Tuisskerm"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutverslag vasgevang"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Raak om jou foutverslag te deel"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Foutverslae bevat data van die stelsel se verskillende loglêers af, insluitend persoonlike en private inligting. Deel foutverslae net met programme en mense wat jy vertrou."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Wys hierdie boodskap volgende keer"</string>
+</resources>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
new file mode 100644
index 0000000..c90a5f5
--- /dev/null
+++ b/packages/Shell/res/values-am/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"ቀፎ"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"የሳንካ ሪፖርት ተይዟል"</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/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
new file mode 100644
index 0000000..6a595d5
--- /dev/null
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"تم الحصول على تقرير الأخطاء"</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/Shell/res/values-be/strings.xml b/packages/Shell/res/values-be/strings.xml
new file mode 100644
index 0000000..e713975
--- /dev/null
+++ b/packages/Shell/res/values-be/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Абалонка"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Справаздача пра збой захавана"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Націсніце, каб падзяліцца сваёй справаздачай пра збой"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Справаздача пра памылку ўтрымлівае дадзеныя з гiсторыi сістэмных файлаў, у тым ліку персанальную і прыватную інфармацыю. Дзялiцеся справаздачамi пра збоi толькi з праверанымi карыстальнiкамi i прыкладаннямi."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"У наступны раз паказваць гэта паведамленне"</string>
+</resources>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
new file mode 100644
index 0000000..2fae953
--- /dev/null
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Команден ред"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчетът за програмни грешки е записан"</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/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
new file mode 100644
index 0000000..8bf368a
--- /dev/null
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Protecció"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"S\'ha registrat l\'informe d\'error"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Els informes d\'error contenen dades dels diferents fitxers de registre del sistema, inclosa informació privada i personal. Comparteix els informes d\'error només amb les aplicacions i amb les persones en qui confies."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra aquest missatge la propera vegada"</string>
+</resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
new file mode 100644
index 0000000..effdcb9
--- /dev/null
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Prostředí"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Byla vytvořena zpráva o chybě"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Zprávu o chybě můžete sdílet klepnutím."</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Zprávy o chybách obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Zprávy o chybách sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
+</resources>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
new file mode 100644
index 0000000..01ea42b
--- /dev/null
+++ b/packages/Shell/res/values-da/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Fejlrapporten er registreret"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Tryk for at dele din fejlrapport"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Fejlrapporter indeholder data fra systemets forskellige logfiler, herunder personlige og private oplysninger. Del kun fejlrapporter med apps og personer, du har tillid til."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne meddelelse næste gang"</string>
+</resources>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
new file mode 100644
index 0000000..99522b1
--- /dev/null
+++ b/packages/Shell/res/values-de/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Fehlerbericht erfasst"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Berühren, um Fehlerbericht zu teilen"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Fehlerberichte enthalten Daten aus verschiedenen Protokolldateien des Systems, darunter auch personenbezogene und private Daten. Teilen Sie Fehlerberichte nur mit Apps und Personen, denen Sie vertrauen."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Diese Nachricht nächstes Mal zeigen"</string>
+</resources>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
new file mode 100644
index 0000000..3669f78
--- /dev/null
+++ b/packages/Shell/res/values-el/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Κέλυφος"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</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/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..68708e0
--- /dev/null
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Touch to share your bug report"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
+</resources>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..f1ec75c
--- /dev/null
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de errores capturado"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Toca para compartir tu informe de errores."</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida la información personal y privada. Comparte los informes de errores únicamente con aplicaciones y personas en las que confíes."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
+</resources>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
new file mode 100644
index 0000000..7990672
--- /dev/null
+++ b/packages/Shell/res/values-es/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de error capturado"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Toca para compartir tu informe de error"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida información personal y privada. Comparte los informes de errores únicamente con aplicaciones y usuarios en los que confíes."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
+</resources>
diff --git a/packages/Shell/res/values-et/strings.xml b/packages/Shell/res/values-et/strings.xml
new file mode 100644
index 0000000..7788158
--- /dev/null
+++ b/packages/Shell/res/values-et/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Kest"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
+</resources>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
new file mode 100644
index 0000000..2d2c223
--- /dev/null
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"گزارش اشکال دریافت شد"</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/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
new file mode 100644
index 0000000..ee57279
--- /dev/null
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Komentotulkki"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Virheraportti tallennettu"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Jaa virheraportti koskettamalla tätä"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Virheraportit sisältävät järjestelmän lokitietoja, ja niihin voi sisältyä henkilökohtaisia ja yksityisiä tietoja. Jaa virheraportteja vain luotettaville sovelluksille ja käyttäjille."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Näytä tämä viesti seuraavalla kerralla"</string>
+</resources>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
new file mode 100644
index 0000000..1da6f1f
--- /dev/null
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bug enregistré"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bug"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bug contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bug qu\'avec les applications et les personnes que vous estimez fiables."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
+</resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
new file mode 100644
index 0000000..4ea0664
--- /dev/null
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"शेल"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</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/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
new file mode 100644
index 0000000..2c4ea23
--- /dev/null
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Ljuska"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Prijava programske pogreške snimljena je"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Prijave programskih pogrešaka sadržavaju podatke iz različitih datoteka zapisnika sustava, uključujući osobne i privatne informacije. Prijave programskih pogrešaka dijelite samo s aplikacijama i osobama koje smatrate pouzdanima."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži tu poruku sljedeći put"</string>
+</resources>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
new file mode 100644
index 0000000..8d684da
--- /dev/null
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Héj"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Programhiba-jelentés rögzítve"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Érintse meg a programhiba-jelentés megosztásához"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"A programhiba-jelentések a rendszer különféle naplófájljaiból származó adatokat tartalmaznak, köztük személyes és magánjellegű információkat is. Csak olyan alkalmazásokkal és személyekkel osszon meg programhiba-jelentéseket, amelyekben vagy akikben megbízik."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Üzenet mutatása legközelebb"</string>
+</resources>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
new file mode 100644
index 0000000..8ea2584
--- /dev/null
+++ b/packages/Shell/res/values-in/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Kerangka"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan bug tercatat"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Sentuh untuk membagikan laporan bug Anda"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Laporan bug berisi data dari berbagai file log sistem, termasuk informasi pribadi dan rahasia. Hanya bagikan laporan bug dengan aplikasi dan orang yang Anda percaya."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tampilkan pesan ini lain kali"</string>
+</resources>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
new file mode 100644
index 0000000..18a03fe
--- /dev/null
+++ b/packages/Shell/res/values-it/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Segnalazione di bug acquisita"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Tocca per condividere la segnalazione di bug"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Le segnalazioni di bug contengono dati da vari file di log del sistema, incluse informazioni personali e private. Condividi le segnalazioni di bug solo con app e persone attendibili."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra questo messaggio la prossima volta"</string>
+</resources>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
new file mode 100644
index 0000000..e7715e9
--- /dev/null
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"מעטפת"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"דוח הבאגים צולם"</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/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
new file mode 100644
index 0000000..88b9c14
--- /dev/null
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"シェル"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"バグレポートが記録されました"</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/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
new file mode 100644
index 0000000..d22a8b0
--- /dev/null
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"셸"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"버그 신고서 캡처됨"</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/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
new file mode 100644
index 0000000..3ac4820
--- /dev/null
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Apvalkalas"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Trikčių ataskaita užfiksuota"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Palieskite, kad bendrintumėte trikčių ataskaitą"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Trikčių ataskaitose pateikiami duomenys iš įvairių sistemos žurnalo failų, įskaitant asmeninę ir privačią informaciją. Trikčių ataskaitas bendrinkite tik su patikimomis programomis ir žmonėmis."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rodyti šį pranešimą kitą kartą"</string>
+</resources>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
new file mode 100644
index 0000000..3f7f7c1
--- /dev/null
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Aizsargs"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveidots kļūdu pārskats"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Pieskarieties, lai kopīgotu kļūdu pārskatu."</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Kļūdu pārskatā ir iekļauti dati no dažādiem sistēmas žurnālfailiem, tostarp personas dati un privāta informācija. Kļūdu pārskatus ieteicams kopīgot tikai ar uzticamām lietotnēm un lietotājiem."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rādīt šo ziņojumu nākamajā reizē"</string>
+</resources>
diff --git a/packages/Shell/res/values-ms/strings.xml b/packages/Shell/res/values-ms/strings.xml
new file mode 100644
index 0000000..8d1e4a2
--- /dev/null
+++ b/packages/Shell/res/values-ms/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
+</resources>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
new file mode 100644
index 0000000..96d53a6
--- /dev/null
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Kommandoliste"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Feilrapporten er lagret"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Trykk for å dele feilrapporten din"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Feilrapporter inkluderer data fra systemets forskjellige loggfiler. Dette omfatter personlig og privat informasjon. Du bør bare dele feilrapporter ned apper og folk du stoler på."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne meldingen neste gang"</string>
+</resources>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
new file mode 100644
index 0000000..5c32c73
--- /dev/null
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutenrapport vastgelegd"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Raak aan om uw foutenrapport te delen"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Foutenrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, waaronder persoonlijke en privégegevens. Deel foutenrapporten alleen met apps en mensen die u vertrouwt."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Dit bericht de volgende keer weergeven"</string>
+</resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
new file mode 100644
index 0000000..2e28f8d
--- /dev/null
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Powłoka"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Raport o błędach został zapisany"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Raporty o błędach zawierają dane z różnych plików dzienników systemu, w tym dane osobowe i prywatne. Udostępniaj je tylko aplikacjom i osobom, którym ufasz."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaż ten komunikat następnym razem"</string>
+</resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..1c465e0
--- /dev/null
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de erros capturado"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Toque para partilhar o relatório de erros"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de erros incluem dados de vários ficheiros de registo do sistema, nomeadamente informações pessoais e privadas. Partilhe relatórios de erros apenas com aplicações e pessoas fidedignas."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
+</resources>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
new file mode 100644
index 0000000..20f4cc9
--- /dev/null
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com aplicativos e pessoas nos quais você confia."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
+</resources>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
new file mode 100644
index 0000000..45c2b0a
--- /dev/null
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Raportul despre erori a fost creat"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Atingeți pentru a permite accesul la raportul despre erori"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Rapoartele despre erori conțin date din diferite fișiere de jurnal ale sistemului, inclusiv informații private și personale. Permiteți accesul la rapoartele despre erori numai aplicațiilor și persoanelor în care aveți încredere."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afișați acest mesaj data viitoare"</string>
+</resources>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
new file mode 100644
index 0000000..153e972
--- /dev/null
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Оболочка"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчет об ошибках сохранен"</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/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
new file mode 100644
index 0000000..99f36f9
--- /dev/null
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Prostredie"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Správa o chybách sa zaznamenala"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Dotykom môžete zdieľať správu o chybách"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
+</resources>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
new file mode 100644
index 0000000..8522d1b
--- /dev/null
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Lupina"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Poročilo o napaki je posneto"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Dotaknite se, če želite deliti sporočilo o napaki z drugimi"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Poročila o napakah vsebujejo podatke iz različnih dnevniških datotek sistema, vključno z osebnimi in zasebnimi podatki. Poročila o napakah delite samo z aplikacijami in ljudmi, ki jim zaupate."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži to sporočilo naslednjič"</string>
+</resources>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
new file mode 100644
index 0000000..bef6ff4
--- /dev/null
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештај о грешци је снимљен"</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/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
new file mode 100644
index 0000000..055dc41
--- /dev/null
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Skal"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Felrapporten har skapats"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Tryck om du vill dela felrapporten"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Felrapporter innehåller data från systemets olika loggfiler, inklusive personliga och privata uppgifter. Dela bara felrapporter med personer du litar på."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Visa det här meddelandet nästa gång"</string>
+</resources>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
new file mode 100644
index 0000000..b1d4407
--- /dev/null
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Ganda"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Ripoti ya hitilafu imenaswa"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Gusa ili ushiriki ripoti yako ya hitilafu"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Ripoti ya hitilafu ina data kutoka kwenye faili za kumbukumbu mbalimbali za mfumo, pamoja na maelezo ya kibinafsi na faragha. Shiriki ripoti ya hitilafu na programu na watu unaowaamini pekee."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Onyesha ujumbe huu wakati mwingine"</string>
+</resources>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
new file mode 100644
index 0000000..b484a42
--- /dev/null
+++ b/packages/Shell/res/values-th/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"จับภาพรายงานข้อบกพร่องแล้ว"</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/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
new file mode 100644
index 0000000..20d1b09
--- /dev/null
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Na-capture ang ulat ng bug"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Pindutin upang ibahagi ang iyong ulat ng bug"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Naglalaman ang mga ulat ng bug ng data mula sa iba\'t ibang file ng log ng system, kabilang ang personal at pribadong impormasyon. Magbahagi lang ng mga ulat ng bug sa apps at mga tao na pinagkakatiwalaan mo."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ipakita ang mensaheng ito sa susunod"</string>
+</resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
new file mode 100644
index 0000000..56db3fc
--- /dev/null
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Kabuk"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Hata raporu kaydedildi"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu mesajı göster"</string>
+</resources>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
new file mode 100644
index 0000000..68e68a8
--- /dev/null
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Оболонка"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Звіт про помилки створено"</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/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
new file mode 100644
index 0000000..ca4fcaa
--- /dev/null
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Báo cáo lỗi đã được chụp"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Chạm để chia sẻ báo cáo lỗi của bạn"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Các báo cáo lỗi chứa dữ liệu từ nhiều tệp nhật ký khác nhau của hệ thống, bao gồm cả thông tin cá nhân và riêng tư. Chỉ chia sẻ báo cáo lỗi với các ứng dụng và những người mà bạn tin tưởng."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Hiển thị thông báo này vào lần tới"</string>
+</resources>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..f1c385f
--- /dev/null
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"已抓取错误报告"</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/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..d3d3140
--- /dev/null
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"殼層"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</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/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
new file mode 100644
index 0000000..e524b80
--- /dev/null
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<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="3701846017049540910">"I-Shell"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Umbiko wesiphazamisi uthwetshuliwe"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Thinta ukuze wabelane ngombiko wakho wesiphazamisi"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Imibiko yeziphazamisi iqukethe idatha yamafayela wokungena ahlukile wesistimu, afaka ulwazi lomuntu siqu noma lobumfihlo. Yabelana kuphela ngemibiko yeziphazamisi nezinhlelo zokusebenza nabantu obathembayo."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bonisa lo mlayezo ngesikhathi esilandelayo"</string>
+</resources>
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 015c0cc..f8f064a 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -6,10 +6,11 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     src/com/android/systemui/EventLogTags.logtags
 
-LOCAL_JAVA_LIBRARIES := services telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUI
 LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 66080f3..260a3be 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,6 +1,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         package="com.android.systemui"
+        android:sharedUserId="android.uid.systemui"
         coreApp="true">
 
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@@ -23,6 +24,7 @@
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
 
     <!-- Networking and telephony -->
     <uses-permission android:name="android.permission.BLUETOOTH" />
@@ -37,7 +39,6 @@
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
-    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
     <uses-permission android:name="android.permission.MASTER_CLEAR" />
     <uses-permission android:name="android.permission.VIBRATE" />
 
@@ -51,7 +52,7 @@
     <uses-permission android:name="android.permission.START_ANY_ACTIVITY" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
-    
+
     <!-- WindowManager -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
@@ -64,6 +65,12 @@
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
 
+    <!-- Alarm clocks -->
+    <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+
+    <!-- Keyguard -->
+    <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+
     <application
         android:persistent="true"
         android:allowClearUserData="false"
@@ -71,6 +78,7 @@
         android:hardwareAccelerated="true"
         android:label="@string/app_label"
         android:icon="@*android:drawable/platlogo"
+        android:process="com.android.systemui"
         android:supportsRtl="true">
 
         <!-- Broadcast receiver that gets the broadcast at boot time and starts
@@ -184,29 +192,28 @@
             android:taskAffinity="com.android.systemui.net"
             android:excludeFromRecents="true" />
 
-        <!-- started from ... somewhere -->
+        <!-- platform logo easter egg activity -->
         <activity
-            android:name=".BeanBag"
+            android:name=".DessertCase"
             android:exported="true"
-            android:label="BeanBag"
-            android:icon="@drawable/redbean2"
-            android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+            android:label="@string/dessert_case"
+            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
             android:hardwareAccelerated="true"
             android:launchMode="singleInstance"
+            android:configChanges="orientation|screenSize"
             android:excludeFromRecents="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="com.android.internal.category.PLATLOGO" />
-<!--            <category android:name="android.intent.category.LAUNCHER" />-->
             </intent-filter>
         </activity>
 
-        <!-- Beans in space -->
+        <!-- a gallery of delicious treats -->
         <service
-            android:name=".BeanBagDream"
+            android:name=".DessertCaseDream"
             android:exported="true"
-            android:label="@string/jelly_bean_dream_name"
+            android:label="@string/dessert_case"
             android:enabled="false"
             >
             <intent-filter>
diff --git a/packages/SystemUI/assets/fonts/AndroidClock.ttf b/packages/SystemUI/assets/fonts/AndroidClock.ttf
deleted file mode 100644
index 7b550ee..0000000
--- a/packages/SystemUI/assets/fonts/AndroidClock.ttf
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/assets/fonts/AndroidClock2.ttf b/packages/SystemUI/assets/fonts/AndroidClock2.ttf
deleted file mode 100644
index a95d548..0000000
--- a/packages/SystemUI/assets/fonts/AndroidClock2.ttf
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/ic_sysbar_internal.psd b/packages/SystemUI/ic_sysbar_internal.psd
deleted file mode 100644
index 929c872..0000000
--- a/packages/SystemUI/ic_sysbar_internal.psd
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index c886eea..ab45d99 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -1,10 +1,3 @@
--keep class com.android.systemui.statusbar.tablet.TabletStatusBarService {
-  public void notificationIconsClicked(android.view.View);
-  public void systemInfoClicked(android.view.View);
-  public void recentButtonClicked(android.view.View);
-  public void toggleLightsOut(android.view.View);
-}
-
 -keep class com.android.systemui.statusbar.policy.KeyButtonView {
   public float getDrawingAlpha();
   public float getGlowAlpha();
diff --git a/packages/SystemUI/res/anim/heads_up_enter.xml b/packages/SystemUI/res/anim/heads_up_enter.xml
new file mode 100644
index 0000000..59eef42
--- /dev/null
+++ b/packages/SystemUI/res/anim/heads_up_enter.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        >
+    <translate
+        android:interpolator="@android:interpolator/overshoot"
+        android:fromYDelta="-50%" android:toYDelta="0"
+        android:duration="@android:integer/config_shortAnimTime" />
+    <alpha 
+        android:interpolator="@android:interpolator/decelerate_quad"
+        android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/packages/SystemUI/res/anim/priority_alert_exit.xml b/packages/SystemUI/res/anim/heads_up_exit.xml
similarity index 100%
rename from packages/SystemUI/res/anim/priority_alert_exit.xml
rename to packages/SystemUI/res/anim/heads_up_exit.xml
diff --git a/packages/SystemUI/res/anim/priority_alert_enter.xml b/packages/SystemUI/res/anim/priority_alert_enter.xml
deleted file mode 100644
index 4fd6a7c..0000000
--- a/packages/SystemUI/res/anim/priority_alert_enter.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        >
-    <scale
-        android:interpolator="@android:interpolator/overshoot"
-        android:fromXScale="0.7" android:toXScale="1.0"
-        android:fromYScale="0.7" android:toYScale="1.0"
-        android:pivotX="50%" android:pivotY="50%"
-        android:duration="@android:integer/config_shortAnimTime" />
-    <alpha 
-        android:interpolator="@android:interpolator/decelerate_quad"
-        android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_shortAnimTime" />
-</set>
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
index 121daae..73ae9f2 100644
--- a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
@@ -18,6 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:detachWallpaper="true"
      android:shareInterpolator="false"
      android:zAdjustment="normal">
   <!--scale android:fromXScale="2.0" android:toXScale="1.0"
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
index fa28cf4..7e257d9 100644
--- a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
@@ -18,6 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:detachWallpaper="true"
      android:shareInterpolator="false"
      android:zAdjustment="top">
   <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png
deleted file mode 100644
index a90c412..0000000
--- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png
deleted file mode 100644
index 9d6032c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png
deleted file mode 100644
index a8075d5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
index 5107bd1..e6af81e 100644
--- a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
+++ b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png
deleted file mode 100644
index aea8beb..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png
deleted file mode 100644
index ebefd20..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png
deleted file mode 100644
index 6f456f3..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png
deleted file mode 100644
index e592ae6..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
deleted file mode 100644
index c1f87a7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png
deleted file mode 100644
index 2d16eda..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png
deleted file mode 100644
index 0749413..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_diagram.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_diagram.png
deleted file mode 100644
index 944b1f0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_diagram.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_bottom.9.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_bottom.9.png
deleted file mode 100644
index 155a315..0000000
--- a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_bottom.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_top.9.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_top.9.png
deleted file mode 100644
index 3eb6fa2..0000000
--- a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_top.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_icon.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_icon.png
deleted file mode 100644
index 46bb891..0000000
--- a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/hd_off.png b/packages/SystemUI/res/drawable-hdpi/hd_off.png
deleted file mode 100644
index e7246cb..0000000
--- a/packages/SystemUI/res/drawable-hdpi/hd_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/hd_on.png b/packages/SystemUI/res/drawable-hdpi/hd_on.png
deleted file mode 100644
index 5360d42..0000000
--- a/packages/SystemUI/res/drawable-hdpi/hd_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png
new file mode 100644
index 0000000..3b952d0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png
deleted file mode 100644
index c02bd42..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_dnd.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_dnd.png
deleted file mode 100644
index 92bc75c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_dnd.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
deleted file mode 100644
index cd9a54a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
index fd33ef3..a93916f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notifications_normal.png
deleted file mode 100644
index 62afe76..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notifications_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
index ead184d..54dde82 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
deleted file mode 100644
index 203e232..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
index ca56ad4..092b561 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_pressed.png
deleted file mode 100644
index 1a14231..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
index 4436359..064860d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
deleted file mode 100644
index c86710d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_off_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_off_normal.png
deleted file mode 100644
index 4ca1ab8..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_off_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_off_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_off_pressed.png
deleted file mode 100644
index 85a4cd2..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_off_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_on_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_on_normal.png
deleted file mode 100644
index d0cb087..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_on_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_on_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_on_pressed.png
deleted file mode 100644
index c1c9e16..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_rotation_on_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
index 3ed7418..2d8d074 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_pressed.png
deleted file mode 100644
index 5e20eea..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
index ab66137..ece947a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
index e058bcd..5f2e95a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png
index e214c00..c100353 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
index 8d45fc5..63acea0 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png
index 6fd7910..beb0e05 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_100.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_100.png
index f3632f3..14832c5f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_100.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png
index 228f59a..603fff1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_28.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_28.png
index dc8510d..5556d6a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_28.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_43.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_43.png
index 77abaaa..0004633 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_43.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_57.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_57.png
index 403bfbc..abd336b 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_57.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_71.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_71.png
index c0ff12c..f23dda8 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_71.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_85.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_85.png
index 18e8864..c7482a9 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_85.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_bolt.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_bolt.png
deleted file mode 100644
index f7dca8b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_bolt.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_100.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_100.png
index 64db815..e8f92e2 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_100.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png
index 3965162..0d01eb5 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_28.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_28.png
index 4b14d62..3d66ffb 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_28.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_43.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_43.png
index 3f51ba5..3562cea 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_43.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_57.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_57.png
index aecf7e6..2b2ebf6 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_57.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_71.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_71.png
index 524bf73..f9f9537 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_71.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_85.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_85.png
index 80325c7..2c7532a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_85.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_unknown.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_unknown.png
index ceaa03b..ebcd336 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_unknown.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_unknown.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
index 8fb71ba..e417a19 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
index ac76535..be153d1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
index 090d235..ee88a1b 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png
index 841b7d9..0a29157 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png
index bb58171..9c1d8ef 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_certificate_info.png
new file mode 100644
index 0000000..1fdaaf9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_certificate_info.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_circle.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_circle.png
index f724ea5..f82a037 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_circle.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_circle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png
index ca73621..ed6c0db 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png
index 8ee38ee..e28c06a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
index 03c450c..18257e0 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png
index e20a061..7220968 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location.png
index 7e67171..c561446 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_location.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
new file mode 100644
index 0000000..7570610
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
new file mode 100644
index 0000000..b03d30c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
index a7bc3c5..cf510b4 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
index 012a4e8..263f07c 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
index 1a7618d..f3dc08f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png
index cac7192..8b6ecc2 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_0.png
index 39fff41..a14b8d8 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png
index f9ecb02..b226694 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png
index c7cfa21..cbabd61 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png
index 2268801..1e9fbfd 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png
index 16ecb6a..0676919 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png
index fb01687..12569d1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png
index fbbf225..3ad9e76 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png
index c151a64..7d5f6d0 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png
index 47e9ad5..2102263 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_0.png
index 97d84a9..c288137 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1.png
index 544dcf9..e20fdf7 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1x.png
index 5ca9892..c24cd4d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_2.png
index 7f050f8..79c9099 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3.png
index be1ed56..8cb1cec 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3g.png
index 5eab3c8..4f76f66 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4.png
index 502787b..9570dae 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4g.png
index 777f8fc..b23a043 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_e.png
index e436ed8..75de8cd 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_g.png
index 304c278..c0ae67c 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_h.png
index 26687ca..858afc8 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png
index 1a5a8aa..9dfde67 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png
index b0449e1..4fea255 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png
index 2f622c2..fa905cc 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png
index f5f76c2c..5b5b5d2 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
index a9dc907..6ff215b 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
index 89d2939..cf5e825 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png
index cceab0a..5128c0d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_network.png
index 3ed973b..05bb0a0 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_network.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_signal.png
index 0fb96d9..c7b035a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_signal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
index d8993f8..5d8fd07 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png
index b78f474..da77a35 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png
index 13ee0a5..c3f4729 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_0.png
index 7e7d068..6aa522b 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png
index b720720..c500691 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png
index 1a4c6d1..ae87896 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png
index 96cd8ab..e47ef7a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png
index 54bab4d..9fd1ae6 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_1.png
index 0a31297..2afa621 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_2.png
index 3e712ad..c873c55 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_3.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_3.png
index 565ae54..e3e0e8d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_4.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_4.png
index 2c30f8e..2762df5 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
index a9dc907..ebd2001 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
index 89d2939..cf5e825 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_no_network.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_no_network.png
index 6e4276f..a5e0bde 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_no_network.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_not_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_not_connected.png
index 6095942..c9e0a7c 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_not_connected.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
index d8993f8..5d8fd07 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_airplane_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_airplane_on.png
deleted file mode 100644
index 7096b73..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_airplane_on.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 84e6bc8..873ca7e 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 3071fb3..9d3cf53 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 782d214..288d36a 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_brightness.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_brightness.png
deleted file mode 100644
index e72fde8..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_brightness.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..8f4cb64
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.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 38e4f45..266d34d 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 c39f7b1..0298054 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_ime_default.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index c925a53..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
index 2e5dc3c..1233fca 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png
index a8f4daa..6768c1f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.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 58843bb..91e2edf 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 66cd57b..9ed15a7 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_quicksettings.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_quicksettings.png
deleted file mode 100644
index 2a94b5d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_quicksettings.png
+++ /dev/null
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 bf9f300..6f2915b 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 194c51f..3f3b692 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/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
deleted file mode 100644
index 02da243..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
deleted file mode 100644
index d645a3c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/pocket_drag_pattern.png b/packages/SystemUI/res/drawable-hdpi/pocket_drag_pattern.png
deleted file mode 100644
index b436fc5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/pocket_drag_pattern.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
deleted file mode 100644
index b5d85188..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
index 652f66f..080f2f2 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png
index d000f7e..8b45500 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
index 288d818..cbcb3e3 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png
index 2509321..da56dcc 100644
--- a/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_light.png b/packages/SystemUI/res/drawable-hdpi/search_light.png
index c8b5a2e..9a8f771 100644
--- a/packages/SystemUI/res/drawable-hdpi/search_light.png
+++ b/packages/SystemUI/res/drawable-hdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
index 3f36546..7b0fcc7 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
index 2b116bf..73e9c96 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png
index fc8dee1..2c55017 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_0.png
index f6b7df7..4ff22d2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png
index c920ec4..612b362 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png
index a51fd00..c971443 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_28.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_28.png
index 4e830a4..a6d4796 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_28.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_43.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_43.png
index 48e7122..67a6a73 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_43.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_57.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_57.png
index f807434..f972ebd 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_57.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_71.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_71.png
index 98c8dea..b707fa1 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_71.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_85.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_85.png
index 9700b1b..82d6545 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_85.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
index 554aaff5..fe33891 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim100.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim100.png
index 829378e..edd03e3 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim100.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim15.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim15.png
index 11ce50d..5d90d2b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim15.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim28.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim28.png
index 2d8fbe0..9e18046 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim28.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim43.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim43.png
index df0bb45..a2f2cf7 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim43.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim57.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim57.png
index f6fc90b..bd5d922 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim57.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim71.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim71.png
index b2a1bcd..9a02199 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim71.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim85.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim85.png
index 6ccced5..aa1b25c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim85.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
index 4a5d001..7ed4c78 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
index da61485..08c07b2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 551c672..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index aee2cf2..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 28bdabb..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index a6d4672..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index c9a6c8e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 83aa3c7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index e377608..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 24ad4de..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
index 15faa3a..804d1ac 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
index 4dbca1e..1d863e9 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
index c3cda8a..62970fe 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
index 6cdc111..6c3fbdc 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
index 9a3fa43..a5effe0 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
index 80f340f..b7071b9 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_lte.png
index d619f6b..bd145fa 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_lte.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..be38df8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
index 55272f5..432b166 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
index e5e6305..aa071c77 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
index f595ae1..194698a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
index f555fc9..0b4b368 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
index ecf1349..8887f2e0 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
index 918a9f9..87c3244 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
index f5d1479..8206cd8 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
index f58a19c..293f88c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
index 744b1fa..cb9c8ac 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
index bef4358..88eafcb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..9befc34
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
deleted file mode 100644
index 5503df1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.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
index 765548b..5ce8708 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
index cbd9b87..58f67d0 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
index 72e6821..b794c9a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
index a59c844..8f17b72 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
deleted file mode 100644
index 67f16b9..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
deleted file mode 100644
index a59c844..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
index a2ba6c4..da941c8 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
index 00b560c..0fd09d7 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
deleted file mode 100644
index fd8d2f2..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
index 92364d2..cfe43dd 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
deleted file mode 100644
index 3b4aaa1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
index 8cea4e9..92a5b1c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
deleted file mode 100644
index 873a317..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
index 94a4a35..9454cd8 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
deleted file mode 100644
index d2381fcc..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
index 93552cb..6cb18c7 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
index d5a78ca..dcf86c0 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
deleted file mode 100644
index 6e84546..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png
deleted file mode 100644
index c56905e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
index d9ec745..45ed7ca 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
deleted file mode 100644
index 11ffbde..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png
index ed31e8e..2dc2b17 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png
deleted file mode 100644
index 6583878..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
index a2aadd9..ece3450 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
deleted file mode 100644
index 2bb923e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
deleted file mode 100644
index 783ad175..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
deleted file mode 100644
index e499f9d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
index 7a39a97..0060eba 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 6b46001..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
index ca49f46..faf4153 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index 4ba2761..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
index 597c214..6a25705 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index 965e42c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
index 810a6b2..c609847 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index 2994c72..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
index 931daed..6248cfd 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
index 117cf19..8c3e896 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_bg_tile.png b/packages/SystemUI/res/drawable-hdpi/status_bar_bg_tile.png
deleted file mode 100644
index aee197c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_bg_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png
index 0c301ab..6feb622 100644
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
index ec0424a..42c773d 100644
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.png b/packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.png
deleted file mode 100644
index 017145e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.png
deleted file mode 100644
index 7466d1d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_hr.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_hr.9.png
deleted file mode 100644
index f5e6031..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_hr.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png
deleted file mode 100644
index 4650417..0000000
--- a/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notifications_normal.png
deleted file mode 100644
index a937a7d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notifications_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
index b0cca26..c526433 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_pressed.png
deleted file mode 100644
index f9489bb..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png
index d26aab0..13f6b7f 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_pressed.png
deleted file mode 100644
index c02c794..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png
index fb8c108..ecdb240 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_pressed.png
deleted file mode 100644
index 293debc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
index 1403416..7db72fb 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
index c35c34d..6158c01 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png
index 28df7e82..54afe32 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_0.png
index 3cc2ab4..d924756 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png
index 258e49b..b6388e1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png
index 075250a..969bff4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png
index b485967..610a018 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png
index a9e0a06..badebf5 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png
index b03296c..ff96e40 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png
index 2974c2f..52c9a74 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png
index 58b84fc..312a384 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png
index 6a4da0d..1211e0d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_0.png
index 4e2cb12..8177ef9 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1.png
index abadd36..ce85449 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1x.png
index a644516..3226db6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_2.png
index dd52748..ec4b0a6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3.png
index ecbed41..1498198 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3g.png
index 6471056..99484b1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4.png
index 964574d..656f9ef 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4g.png
index e34a1ab..f4f0035 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_e.png
index 2454d81..935a743 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_g.png
index d3e9a16..5510f6b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_h.png
index 43bccb3..c21352c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_lte.png
index 515788a..9298dae 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_r.png
index 071e569..da4093e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png
index b8b298b..b65abc6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png
index fb633cc..08e21d2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_in.png
deleted file mode 100644
index fb08a0c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_inout.png
deleted file mode 100644
index 013881f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png
index 58327c1..464ebbc 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_network.png
index f0e3410..c532510 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_network.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_signal.png
index 7c22391..f87944f 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_signal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_out.png
deleted file mode 100644
index a6ed1f9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png
index d4ecfb9..37da1f4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png
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 782ebfe..3f7c4b0 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 efca67e..956bb7c 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
index 677b471..86e2947 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
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
index 478b9ca..d8ab8ea 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index bbf897f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 292f5b7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 851892c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 8ad379e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index ca1800c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 1e71680..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 66dc694..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index b1cb4b8..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_1x.png
index 983ba67..3d82daf 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_3g.png
index fa5ffe9..dfbf1a4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_4g.png
index 859adb9..85721db 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_e.png
index 0d78728..4a2421c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_g.png
index 5290dc4..acc98b7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_h.png
index f034fbfd..64653eb 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_lte.png
index 8078424..f440755 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..ffb58ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..295d8fa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..d875faf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..f3235e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..6cd4809
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..9bbf17e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..c301366
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..56244b9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..d2af46d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..cee9234
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..91768a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
index 6872ec8..f3e9da2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
index 98520d3..a90aef9 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0.png
index 733563d..b477332 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0_fully.png
index 3ac0231..b477332 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1.png
deleted file mode 100644
index 50a3078..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1_fully.png
index 9e353da..36cb7e5 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2.png
deleted file mode 100644
index 5ff0ac6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2_fully.png
index 91ca89a..cc30aa1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3.png
deleted file mode 100644
index 784c5da..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3_fully.png
index 484d4b8..6f0b419 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4.png
deleted file mode 100644
index db06343..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4_fully.png
index 62130a0..01d47c5 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_flightmode.png
index 44d1afb..5171333 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_in.png
deleted file mode 100644
index f2bd618..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_inout.png
deleted file mode 100644
index 468dec9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_null.png
index 7bbe2cc..cd4056c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_out.png
deleted file mode 100644
index b2f7f59..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notifications_normal.png
deleted file mode 100644
index 78c4a5f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notifications_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
index a9dbc93..d13bc69 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_pressed.png
deleted file mode 100644
index 5bba00f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png
index b38ddd6..c98911c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_pressed.png
deleted file mode 100644
index 032ce42..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png
index d815761..bb99022 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_pressed.png
deleted file mode 100644
index 369bb61..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
index 6587c2d..5ba15a7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
index 833b7f0..c37ba79 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png
index 16743ef..2495830 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_0.png
index c8020e0..cdf76e2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png
index a968e96..7116084 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png
index 712cce4..8596aa6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png
index 5ac3715..1b81c42 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png
index 8b4c97c..03591c2a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png
index 835219c..ee72967 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png
index 7fea77c..162315c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png
index ec861fa..c472f2b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png
index 3bef9e7..e4bf4e2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_0.png
index 31637c2..d41a2c7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1.png
index 4bedf72..d45c0ad 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1x.png
index 0cb5f26..e5e2c27 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_2.png
index c779281..2f21063 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3.png
index 7e0f98d..db913dd 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3g.png
index c258489..e1760b4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4.png
index d479043..c098fd9 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4g.png
index e1ce328..d084a6b7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_e.png
index b1d5d5c..5c2e8e5 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_g.png
index b907713..f69c1f7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_h.png
index 6396b64..066efdd 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_lte.png
index 50e5011..d3b51c1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_r.png
index fd3b644..4fcc7bc 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png
index 07f514c..98b0104 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png
index 9ccd5aa..fc19c7a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_in.png
deleted file mode 100644
index efee374..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_inout.png
deleted file mode 100644
index e69f3f7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png
index bb1de06..2250282 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_network.png
index f465084..5ec4543 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_network.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_signal.png
index dc52a7b..b8f137c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_signal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_out.png
deleted file mode 100644
index 69f15e3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png
index bf1f50e..8290e1b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png
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 a1b8062..a53aef1 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 23318ae..e1b2145 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
index fcdbefe..dffc059 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
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
index 7f0cc51..c0209b0 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index f6d53bb..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 2fec581..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index df46db2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index d556d57..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 546cff9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 0ed7558..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 6de14dc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 0f0cf49..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_1x.png
index 2ac1a96..0d97960 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_3g.png
index 2625fab..f8e06e1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_4g.png
index 17a77b1..35be266 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_e.png
index e482a26..64727d3 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_g.png
index 05628d0..3b14d98 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_h.png
index 7dc5d96..c51c4b1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_lte.png
index 17ca21a..867a014 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..c54ceba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..383015e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..ab73c9f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..07a81a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..9303aee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..def4430
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..43c9fb2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..ddbd04a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..c8493ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..de04176
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..abee91e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
index 66b4741..b05bf78 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
index f8abf25..2f782cf 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0.png
index 9be8d23..6f457e0 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0_fully.png
index 0002165..6f457e0 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1.png
deleted file mode 100644
index d142737..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1_fully.png
index dc31490..45d733e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2.png
deleted file mode 100644
index 4e5b7d3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2_fully.png
index 6acb475..093387a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3.png
deleted file mode 100644
index 509d1752..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3_fully.png
index 5791615..2f32c4c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4.png
deleted file mode 100644
index 01b27ec..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4_fully.png
index c970e0e..8e9ba9c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_flightmode.png
index 9070357..1b45762 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_in.png
deleted file mode 100644
index e0b0f9b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_inout.png
deleted file mode 100644
index 2fb3c2e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_null.png
index 8691360..c18d103 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_out.png
deleted file mode 100644
index 0fe8012..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_out.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 194a843..2d8f81d 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 ed08779..61c6d11 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
index 542a93b..a67ed6d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
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
index e96f340..6101333 100644
--- 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
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 a345a4e..90eece6 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 96ea0c9..382cf23 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
index 70dc8af..ca1c8c4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
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
index db4d907..cfef88d 100644
--- 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
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 9f9afd4..a4b3b37 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 cc376c4..ee5f623 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
index ea4a8ca..ca3c541 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
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
index 73ef87b..78d4490 100644
--- 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
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
new file mode 100644
index 0000000..3d21350
--- /dev/null
+++ 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
new file mode 100644
index 0000000..40fbaec
--- /dev/null
+++ 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
new file mode 100644
index 0000000..77bef31
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
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
new file mode 100644
index 0000000..d79f5b7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_0.png
deleted file mode 100644
index db07305..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_0_fully.png
deleted file mode 100644
index 4518ad5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_0_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_1.png
deleted file mode 100644
index 3b6f74ad..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_1_fully.png
deleted file mode 100644
index 396d51d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_2.png
deleted file mode 100644
index bb90a95..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_2_fully.png
deleted file mode 100644
index 34dc19f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_3.png
deleted file mode 100644
index 64c2de2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_3_fully.png
deleted file mode 100644
index 9d93d2b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_4.png
deleted file mode 100644
index 28ae311..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_4_fully.png
deleted file mode 100644
index cd4f706..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_in.png
deleted file mode 100644
index cbce322..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_inout.png
deleted file mode 100644
index 6788da8..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_null.png
deleted file mode 100644
index 0f00fb0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_out.png
deleted file mode 100644
index db05c5f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-hdpi/ic_sysbar_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_0.png
deleted file mode 100644
index 9b99940..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_0_fully.png
deleted file mode 100644
index 2cd8c90..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_0_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_1.png
deleted file mode 100644
index f5363c3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_1_fully.png
deleted file mode 100644
index ded5029..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_2.png
deleted file mode 100644
index 01f4eb0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_2_fully.png
deleted file mode 100644
index 9963e97..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_3.png
deleted file mode 100644
index 3123cc9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_3_fully.png
deleted file mode 100644
index 34363fa..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_4.png
deleted file mode 100644
index 186844c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_4_fully.png
deleted file mode 100644
index 680f806..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_in.png
deleted file mode 100644
index 4d5bb0b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_inout.png
deleted file mode 100644
index 253d15c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_null.png
deleted file mode 100644
index 5d688aa..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_out.png
deleted file mode 100644
index 8198fdc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-mdpi/ic_sysbar_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_0.png
deleted file mode 100644
index a8691dc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_0_fully.png
deleted file mode 100644
index 77ade2f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_0_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_1.png
deleted file mode 100644
index 0974b2c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_1_fully.png
deleted file mode 100644
index 4be5612..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_2.png
deleted file mode 100644
index 79f8b88..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_2_fully.png
deleted file mode 100644
index 6167246..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_3.png
deleted file mode 100644
index d2ecd47..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_3_fully.png
deleted file mode 100644
index 92871c3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_4.png
deleted file mode 100644
index 4b86ca4..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_4_fully.png
deleted file mode 100644
index 200d1cb..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_in.png
deleted file mode 100644
index f4c5281..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_inout.png
deleted file mode 100644
index 42e2170..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_null.png
deleted file mode 100644
index eaff2c0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_out.png
deleted file mode 100644
index 9feb041..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw720dp-xhdpi/ic_sysbar_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notifications_normal.png
deleted file mode 100644
index a2787eb..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notifications_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
index 53a74c9..a137a80 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_pressed.png
deleted file mode 100644
index c9d50c0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png
index 57faad8..d9d8b13 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_pressed.png
deleted file mode 100644
index c736dcd..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png
index c8ff8a6..09e0a3c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_pressed.png
deleted file mode 100644
index 3add352..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
index d16e3d3..294ae48 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
index 53523f6..d59f0e92 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png
index 73db61d..0d5b50c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_0.png
index 3f87163..10c6905 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png
index 5fae5fe..a5d68e1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png
index 24c8fde..69d0461 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png
index 2e68d0f..df0948b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png
index 01af7f9..4409267 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png
index f5e4b7e..de0181b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png
index 2368f71..c3e4181 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png
index eeeed04..69a950d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png
index 6188ec3..04948ae 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_0.png
index cd41a810..ef8c677 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1.png
index 637c8bb..53bf4de 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1x.png
index c8348d4..5733b5d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_2.png
index b499d01..8d3dede 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3.png
index 589f41b..52df2f7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3g.png
index c756e15..503cc78 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4.png
index 0208cdb..b5c176d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4g.png
index 9cd1154..4c169ec 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_e.png
index 01c8876..5d09b042 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_g.png
index 5516e0f..94f332e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_h.png
index 8f411c3..1d2594b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_lte.png
index 0d344b9..22eec00 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_r.png
index ef65b74..99efc08 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png
index 6e51ecb..a6b0393 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png
index 7c8155c..ede64f1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_in.png
deleted file mode 100644
index fd5f0e52..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_inout.png
deleted file mode 100644
index 1f04910..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png
index ac010bf..e82ba13 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_network.png
index 74b5b92..7097b26 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_network.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_signal.png
index bcdd82d..43fbaeb 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_signal.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_out.png
deleted file mode 100644
index d95b997..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png
index 1e6aef5..83e7206 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png
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 633d864..61b4569 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 7b9613c..1a0312b 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
index 4665e2a..d04916e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
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
index 6d33a6e..d940d34 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index d3b57c3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index cc2256f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index e1f1ab9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 5a04dde..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 65c4fe1..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 066405f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index b704cdf..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 97d5d5b7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_1x.png
index a3d2b35..8a72b0a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_3g.png
index 8e13caa..4f1632d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_4g.png
index 23fcf42..fd9eb8b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_e.png
index 4370c22..aa0677e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_g.png
index 3504a75..cf1f099 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_h.png
index 21fc58c..441e9dd 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_lte.png
index 3cb8f3e..2614d61 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..d8db235
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..e00a33a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..21286bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..8be5950
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..7cdd393
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..07aa536
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..3ca6529
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..095a1a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..eb8e313
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..0f571e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..3edbd14
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
index 629b5f8..8299301 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
index 8e3e8b4..e171d53 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0.png
index 62d1d34..60ede0a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0_fully.png
index b263831..a22fa28 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1.png
deleted file mode 100644
index 6f9620e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1_fully.png
index 7adae9f..26a0543 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2.png
deleted file mode 100644
index 906b418..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2_fully.png
index ebdf136..ec31162 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3.png
deleted file mode 100644
index 1a2ab1c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3_fully.png
index c0170a6..26cd26f 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4.png
deleted file mode 100644
index 2cc587b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4_fully.png
index 11a26c6..25ed626 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_flightmode.png
index 9ede64c..fcbfac1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_in.png
deleted file mode 100644
index 3afb5b2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_inout.png
deleted file mode 100644
index fcf7f6e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_null.png
index 815de33..37da3339 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_out.png
deleted file mode 100644
index f153216..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
new file mode 100644
index 0000000..8da7945
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_open_normal.png
new file mode 100644
index 0000000..c0855b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_quicksettings_normal.png
new file mode 100644
index 0000000..e3fb992
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png
new file mode 100644
index 0000000..7b7e329
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png
new file mode 100644
index 0000000..a2342fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_default_user.png
new file mode 100644
index 0000000..07f16c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_0.png
new file mode 100644
index 0000000..5c378ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png
new file mode 100644
index 0000000..19809c2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png
new file mode 100644
index 0000000..cd34141
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png
new file mode 100644
index 0000000..5691f96
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png
new file mode 100644
index 0000000..56768dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png
new file mode 100644
index 0000000..094d4ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png
new file mode 100644
index 0000000..55ec5b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png
new file mode 100644
index 0000000..f92aac2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png
new file mode 100644
index 0000000..4329b67
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_0.png
new file mode 100644
index 0000000..6db5d0d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_1.png
new file mode 100644
index 0000000..41c1f89
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_1x.png
new file mode 100644
index 0000000..dea2bf2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_2.png
new file mode 100644
index 0000000..4faff9b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_3.png
new file mode 100644
index 0000000..2e84aa1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_3g.png
new file mode 100644
index 0000000..79c97fa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_4.png
new file mode 100644
index 0000000..742b5bb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_4g.png
new file mode 100644
index 0000000..3b297af
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_e.png
new file mode 100644
index 0000000..c5a7b8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_g.png
new file mode 100644
index 0000000..077b754
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_h.png
new file mode 100644
index 0000000..7907b02
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_lte.png
new file mode 100644
index 0000000..190d3f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_r.png
new file mode 100644
index 0000000..7c70da6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png
new file mode 100644
index 0000000..3577fbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png
new file mode 100644
index 0000000..0aae48b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png
new file mode 100644
index 0000000..2d2b106
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_no_network.png
new file mode 100644
index 0000000..330b96b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_no_signal.png
new file mode 100644
index 0000000..30fe798
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png
new file mode 100644
index 0000000..a2003fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png
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
new file mode 100644
index 0000000..8715a11
--- /dev/null
+++ 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
new file mode 100644
index 0000000..487a0b1
--- /dev/null
+++ 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
new file mode 100644
index 0000000..a7cff47
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
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
new file mode 100644
index 0000000..0a60bb6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_1x.png
new file mode 100644
index 0000000..c4507c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_3g.png
new file mode 100644
index 0000000..bfef649
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..c39658d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_e.png
new file mode 100644
index 0000000..0f2e79c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_g.png
new file mode 100644
index 0000000..d37b2929
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_h.png
new file mode 100644
index 0000000..96a1463
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_lte.png
new file mode 100644
index 0000000..9b5dbfa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..cc6155f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..4cb1410
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..7a0b11c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..12d5d6f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..08da7e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..6ecd2e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..9e7e3f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..bdd4f59
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..1eb0547
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..06e4480
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..f904325
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
new file mode 100644
index 0000000..1c847da2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
new file mode 100644
index 0000000..d0ab910
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_0.png
new file mode 100644
index 0000000..5950ef8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_0_fully.png
new file mode 100644
index 0000000..a930649
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_1_fully.png
new file mode 100644
index 0000000..9245462
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_2_fully.png
new file mode 100644
index 0000000..b5b8884
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_3_fully.png
new file mode 100644
index 0000000..11b5832
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_4_fully.png
new file mode 100644
index 0000000..ff8246e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_flightmode.png
new file mode 100644
index 0000000..4555731
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..e0c5408
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png
deleted file mode 100644
index b94b144..0000000
--- a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png
deleted file mode 100644
index b94b144..0000000
--- a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png
deleted file mode 100644
index c17c668d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/arrow_dashed.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
index ecc909a..e865f4c 100644
--- a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
+++ b/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png
deleted file mode 100644
index 43a407e..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png
deleted file mode 100644
index bf0c8cb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png
deleted file mode 100644
index 9b59b05..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png
deleted file mode 100644
index b517af6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
deleted file mode 100644
index 019f33a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png
deleted file mode 100644
index 6ce1bd3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png
deleted file mode 100644
index 0633543..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_diagram.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_diagram.png
deleted file mode 100644
index 5f08b52..0000000
--- a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_diagram.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_bottom.9.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_bottom.9.png
deleted file mode 100644
index b7f4523..0000000
--- a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_bottom.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_top.9.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_top.9.png
deleted file mode 100644
index fae17b1..0000000
--- a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_top.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_icon.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_icon.png
deleted file mode 100644
index e017e03..0000000
--- a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/hd_off.png b/packages/SystemUI/res/drawable-mdpi/hd_off.png
deleted file mode 100644
index 6c01b8a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/hd_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/hd_on.png b/packages/SystemUI/res/drawable-mdpi/hd_on.png
deleted file mode 100644
index de878ef..0000000
--- a/packages/SystemUI/res/drawable-mdpi/hd_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png
new file mode 100644
index 0000000..a0ab991
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png
deleted file mode 100644
index 05cdd9a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png
deleted file mode 100644
index fd2bcb2..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
deleted file mode 100644
index 5661eaf..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
index 667b13d..7ae6079 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notifications_normal.png
deleted file mode 100644
index 62afe76..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notifications_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
index 5dacccb..7cb52e3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
deleted file mode 100644
index f1f6b00..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
index f04aab1..ae5d263 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_pressed.png
deleted file mode 100644
index 549c5efd..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
index 09d2c55..32fbed4 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
deleted file mode 100644
index 322d1a7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_off_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_off_normal.png
deleted file mode 100644
index 77da014..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_off_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_off_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_off_pressed.png
deleted file mode 100644
index f132d5c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_off_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_on_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_on_normal.png
deleted file mode 100644
index 1637209..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_on_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_on_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_on_pressed.png
deleted file mode 100644
index 4d8fbde..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_rotation_on_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
index 44cfc5b..399db00 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_pressed.png
deleted file mode 100644
index 0c3fdcd..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
index 2d0c479..8ab2e1e 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
index 6a2906e..251fc30 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png
index d6590e2..27f08dd 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
index 46beb62..ac6c1cf0 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png
index c581919..8dd3d4d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_100.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_100.png
index 2f330f7..2a9bf50 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_100.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png
index 2a1637c..f59ba48 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_28.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_28.png
index 8457c2b..12f16dd 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_28.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_43.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_43.png
index f72fe4a..649c89d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_43.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_57.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_57.png
index 10e3275..95494e6 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_57.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_71.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_71.png
index ca1613c..dfd92ee 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_71.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_85.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_85.png
index 2bfe20d..dcabf3f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_85.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_bolt.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_bolt.png
deleted file mode 100644
index b01d7d0..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_bolt.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_100.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_100.png
index 480f579..2a05827 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_100.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png
index cee2a44..86d1158 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_28.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_28.png
index f2056db..076add9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_28.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_43.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_43.png
index 697d4ec..4bdae3c 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_43.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_57.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_57.png
index 9c53dd4..8353d91 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_57.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_71.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_71.png
index c967999..91bd62e 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_71.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_85.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_85.png
index 8df8234..a36d25d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_85.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_unknown.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_unknown.png
index c3a4ab4..a2e3cc9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_unknown.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_unknown.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
index d0ce4f6..b01b27f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
index 2116449..426b33d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
index 1cc6e62..0acf3a4 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png
index df5987c9..74df151 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png
index 753e9f7..56add92 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_certificate_info.png
new file mode 100644
index 0000000..3b49472
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_certificate_info.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_circle.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_circle.png
index 27904f2..3073986 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_circle.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_circle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png
index f7f8c42..2a0bc59 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png
index fb17e5ab..9b1cc58 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
index d90bdd3..a35c30d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png
index 3263c55..8c2dc68 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location.png
index 79f1f470..e285bba 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_location.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
new file mode 100644
index 0000000..7c73ace
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
new file mode 100644
index 0000000..867c57d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
index 1ff9cbc..8e080ff 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
index 0ec78c0..780cfc8 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
index b70df3d..3b7a284 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png
index 673d2e0..021ae6d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_0.png
index d46fced..3afbca4 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png
index ef5179f..2994632 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png
index 53dc47d..a89191f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png
index 359f445..b111939 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png
index 7ebebcd..98c8e25 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png
index 88cf8b6..8a8e323 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png
index db72661..625dbd9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png
index 6022a6a..c1063a9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png
index e493d3b..f145410 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_0.png
index 6668846..ea4ab18 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1.png
index 5c8dc82..52faded 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1x.png
index 01560e8..2f76529 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2.png
index 3082ff0..bcf825d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3.png
index 7966be8..f9de3ef 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3g.png
index a78c4d6..244280b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4.png
index dce07ae..f0bd70e 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4g.png
index 82bcb79..befe94d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_e.png
index 828a728..01a81ab 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_g.png
index f1a8017..abed290 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_h.png
index 9077d56..e4b1fad 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png
index d819f5c..da8ebce 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png
index d298624..776210b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png
index cb52c98..a5de26f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png
index 14550d5..b3d4524 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
index 4dd6401..da4ffa2 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
index 07ebd9c..e1c7972 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png
index bb1de06..0555eed 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_network.png
index cf2cc52..b27479a 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_network.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_signal.png
index dcd2dbd..9441f61 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_signal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
index d8eda87..b8c8b4e 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png
index d26beb5..f1753d6 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png
index 6ac70fa..19b95dd 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_0.png
index 9ab044d..42210a6 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png
index 1de33ba..60e38ad 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png
index 34c916d..8983380 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png
index 2f7a885..ff652df 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png
index f11cc08..8dd9c43 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_1.png
index e78ab6b..092ddbb 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_2.png
index 1b025f26..e10a1da 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_3.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_3.png
index 3036c86..bd235ae 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_4.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_4.png
index de000eb..5873b37 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
index 4dd6401..5d0ad7c 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
index 07ebd9c..e1c7972 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_no_network.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_no_network.png
index 72da3e8..7208427 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_no_network.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_not_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_not_connected.png
index f606a60..fdf34bf 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_not_connected.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
index d8eda87..b8c8b4e 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_airplane_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_airplane_on.png
deleted file mode 100644
index c33271b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_airplane_on.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 a00bc5b..225d924 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 72b5ffe..7779d57 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 8605701..37d17d2 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_brightness.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_brightness.png
deleted file mode 100644
index 4dbca6d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_brightness.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..2142147
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.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 dc3183b..5e70a07 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 5dff6e7..39a0c07 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_ime_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index cf12bb9..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
index 45183b0..4d9c21c 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png
index 8169fba..9f0570a 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.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 cc65b07..5bbf3fe 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 d0404bf..798f62f 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_quicksettings.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png
deleted file mode 100644
index 238df06..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png
+++ /dev/null
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 b07f611..f8e549a 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 47e209e..c7fda96 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/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
deleted file mode 100644
index 9c117ae..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
deleted file mode 100644
index 4f51201..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png b/packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png
deleted file mode 100644
index 3370aeb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 5744885..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
index 6f4d658..60dc3f2 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png
index f19dc93..4b7de52 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
index 10e4fd2..3ac7c40 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png
index be1cd31..295e91f 100644
--- a/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_light.png b/packages/SystemUI/res/drawable-mdpi/search_light.png
index 4b5b2a4..c355b6a 100644
--- a/packages/SystemUI/res/drawable-mdpi/search_light.png
+++ b/packages/SystemUI/res/drawable-mdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
index f345ca7..a02e21c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
index d95480d..4af2617 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png
index 4b0a74f..c6dc466 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_0.png
index edf244a..edcb1b3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_100.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_100.png
index 943332e..8e0ec0f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_100.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png
index d465337..b1b675b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_28.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_28.png
index 4b0ad71..868bbbc 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_28.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_43.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_43.png
index 70c40e8..890129e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_43.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_57.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_57.png
index aa0fde1..86279af 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_57.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_71.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_71.png
index 95688d0..de2aa4e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_71.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_85.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_85.png
index ac3b5f3..c008d6f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_85.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim0.png
index 31aa745..0c63793 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim100.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim100.png
index 2773a70..c16c289 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim100.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim15.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim15.png
index 4471eb9..f4f59b4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim15.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim28.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim28.png
index 0c2f994..1d2c557 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim28.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim43.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim43.png
index 98a3931..ebf7888 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim43.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim57.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim57.png
index 7443b59..b100728 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim57.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim71.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim71.png
index e791a88..8b8e872 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim71.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim85.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim85.png
index 51c106c..de78a9c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim85.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_charge_anim85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth.png
index 53a7364..bd4e1ae 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
index 3451fff..e82c6e4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 5076cf9..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 3ab8470..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 83538d4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index aa011ca..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 4cebc43..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index bd2b4ed..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 6de14dc..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 243dfea..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
index 8184f2c..36713ae 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
index 19780bd..1c9e313 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
index efba454..7b1b16f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
index a4455ae..02dc258 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
index e82f3f4..27417d8f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
index f8e13ab..f3a805c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_lte.png
index 17ca21a..8a8c3d9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_lte.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..fb2a6b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png
index a0c7a99..e5a8f95 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png
index b1f1e5b..c1c2b5c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png
index 8b31618..421eee8 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png
index 1a62682..bfd2494 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png
index ff51551..b1af6786 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png
index 0374142..9ad245b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png
index 8f881f2..69a1a97 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
index 7870cee..d865673 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
index 65404c2..6bd3189 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png
index 327f89d..f7f0e93 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..2e24f6f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
deleted file mode 100644
index 81c0c10..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.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
index 24bee66..bdf0f67 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
index faefe36..1e05a91 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
index 900a717..f4afa52 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
index 876d9ee..cb38896 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
deleted file mode 100644
index 436f16d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
deleted file mode 100644
index 876d9ee..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
index d93a661..ca02605 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png
index b39cc04..2dcbe28 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
deleted file mode 100644
index 4305351..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
index 4305be2..fe71893 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
deleted file mode 100644
index beb641b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
index 7b8ddc2..a6c61ff 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
deleted file mode 100644
index a4028cd..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
index fad1873..ba4a9d9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
deleted file mode 100644
index b5ed22b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
index cca7bf3..79c2ec1 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
index 5ce22de..14d1060 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
deleted file mode 100644
index 31c0936..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
deleted file mode 100644
index 7e9b752..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
index 2cebe85..4548617 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
deleted file mode 100644
index 3209234d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png
index 06b3913..ad5b2ff 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png
deleted file mode 100644
index 4f23dae..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
index fb70ba87..b4db0bb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
deleted file mode 100644
index 95c56ed..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
deleted file mode 100644
index 11b9a93..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
deleted file mode 100644
index 0f85ca0..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
index f39d0bb..3cc96ee 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 4f015d2..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
index b1314a6..34ae3bf 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index c451919..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
index 84746e7..cb3623a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index ce752b1..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
index d6e746d..4f9a8b0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index 3ecfff5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
index 6e1ac91..441de0c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
index 7c60bea..34abc98 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_bg_tile.png b/packages/SystemUI/res/drawable-mdpi/status_bar_bg_tile.png
deleted file mode 100644
index 6579ff9..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_bg_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png
index 5c577cb..bd1cd12 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
index 7efb502..20c8785 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
deleted file mode 100644
index 1fd5dd3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
deleted file mode 100644
index b2edd46..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_hr.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_hr.9.png
deleted file mode 100644
index f5e6031..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_hr.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png
deleted file mode 100644
index f334023..0000000
--- a/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png b/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png
deleted file mode 100644
index 87d8c41..0000000
--- a/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_android.png b/packages/SystemUI/res/drawable-nodpi/dessert_android.png
new file mode 100644
index 0000000..2b47c19
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_android.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_cupcake.png b/packages/SystemUI/res/drawable-nodpi/dessert_cupcake.png
new file mode 100644
index 0000000..7b48c10
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_cupcake.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_dandroid.png b/packages/SystemUI/res/drawable-nodpi/dessert_dandroid.png
new file mode 100644
index 0000000..8be85c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_dandroid.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_donut.png b/packages/SystemUI/res/drawable-nodpi/dessert_donut.png
new file mode 100644
index 0000000..167ced7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_donut.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_donutburger.png b/packages/SystemUI/res/drawable-nodpi/dessert_donutburger.png
new file mode 100644
index 0000000..9d77518a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_donutburger.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_eclair.png b/packages/SystemUI/res/drawable-nodpi/dessert_eclair.png
new file mode 100644
index 0000000..8d463eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_eclair.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_flan.png b/packages/SystemUI/res/drawable-nodpi/dessert_flan.png
new file mode 100644
index 0000000..d05e3de
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_flan.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_froyo.png b/packages/SystemUI/res/drawable-nodpi/dessert_froyo.png
new file mode 100644
index 0000000..ffd9994
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_froyo.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_gingerbread.png b/packages/SystemUI/res/drawable-nodpi/dessert_gingerbread.png
new file mode 100644
index 0000000..22bffbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_gingerbread.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_honeycomb.png b/packages/SystemUI/res/drawable-nodpi/dessert_honeycomb.png
new file mode 100644
index 0000000..0f51a43
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_honeycomb.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_ics.png b/packages/SystemUI/res/drawable-nodpi/dessert_ics.png
new file mode 100644
index 0000000..bdec60e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_ics.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_jandycane.png b/packages/SystemUI/res/drawable-nodpi/dessert_jandycane.png
new file mode 100644
index 0000000..ba1c7eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_jandycane.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_jellybean.png b/packages/SystemUI/res/drawable-nodpi/dessert_jellybean.png
new file mode 100644
index 0000000..5a2bcaa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_jellybean.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_keylimepie.png b/packages/SystemUI/res/drawable-nodpi/dessert_keylimepie.png
new file mode 100644
index 0000000..a8741ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_keylimepie.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_kitkat.png b/packages/SystemUI/res/drawable-nodpi/dessert_kitkat.png
new file mode 100644
index 0000000..4f2b03b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_kitkat.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_petitfour.png b/packages/SystemUI/res/drawable-nodpi/dessert_petitfour.png
new file mode 100644
index 0000000..3dc9d95
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_petitfour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/dessert_zombiegingerbread.png b/packages/SystemUI/res/drawable-nodpi/dessert_zombiegingerbread.png
new file mode 100644
index 0000000..7962c21
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/dessert_zombiegingerbread.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/jandycane.png b/packages/SystemUI/res/drawable-nodpi/jandycane.png
deleted file mode 100644
index 278cfec..0000000
--- a/packages/SystemUI/res/drawable-nodpi/jandycane.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png b/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png
deleted file mode 100644
index 47c89b1..0000000
--- a/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/redbean0.png b/packages/SystemUI/res/drawable-nodpi/redbean0.png
deleted file mode 100644
index b088939..0000000
--- a/packages/SystemUI/res/drawable-nodpi/redbean0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/redbean1.png b/packages/SystemUI/res/drawable-nodpi/redbean1.png
deleted file mode 100644
index 8fc8d9d..0000000
--- a/packages/SystemUI/res/drawable-nodpi/redbean1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/redbean2.png b/packages/SystemUI/res/drawable-nodpi/redbean2.png
deleted file mode 100644
index ef11ca8..0000000
--- a/packages/SystemUI/res/drawable-nodpi/redbean2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/redbeandroid.png b/packages/SystemUI/res/drawable-nodpi/redbeandroid.png
deleted file mode 100644
index 9aa3f82..0000000
--- a/packages/SystemUI/res/drawable-nodpi/redbeandroid.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 38bd0cd..3361e34 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 6d4825e..ed52bc3 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 baeb49e..b380327 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_brightness.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_brightness.png
deleted file mode 100644
index 77eae9a..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_brightness.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
index 202c8bc..8014b70 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
index 31bc09c..41a34e2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_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 0652753..49df31b 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 b8ea740..ac45bcd 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_ime_default.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index 2d5594c..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
index 5e8e7f6..11e3b65 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png
index 3529974..afcc487 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.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 bfec943..9fb4266 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 3a6a2d8..459d011 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 61f409d..e1cddde 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 5629cca..e459f2c 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 0c12c16..0ec4d23 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 ec38e6a..4dedcbe 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 23f976c..e55f2bf 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_brightness.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_brightness.png
deleted file mode 100644
index f5fcb04..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_brightness.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
index bef6de3..9c623e5 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
index 406eeab..a011aa1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_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 e3e683c..a39c3e5 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 1f3410d..80e988f 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_ime_default.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index bea5339d..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
index 1849a53a..24442343 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png
index c5fe4df..a3e32f4c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.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 a0ea296..4ef12b0d 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 54d9cda..8ef12a8 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 670fed9..c2977c0 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 a567e07..60ec10e 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/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png
new file mode 100644
index 0000000..6002cfb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.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 477df5f..8aa6e3a 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 5839fd0..e272b62 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 27b7ace..bf68b22 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_brightness.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_brightness.png
deleted file mode 100644
index f3dfb4f..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_brightness.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
index 75b5fbb..61a36e3 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
index a7a4ce3..52bf290 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_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 f753383..59ef663 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 b6e898e..cf3a5ff 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_ime_default.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index fb34efc..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
index f079b85..298b62f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png
index fa5f001..41f4b42 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.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 7690b47..2598954 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 8c50621..66853db 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 f2db326..c46fd026 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 93c737b..0e84d92 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/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png
new file mode 100644
index 0000000..586a738
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.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
new file mode 100644
index 0000000..7e96395e
--- /dev/null
+++ 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
new file mode 100644
index 0000000..cb94580
--- /dev/null
+++ 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
new file mode 100644
index 0000000..382ef39
--- /dev/null
+++ 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_highlight.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png
new file mode 100644
index 0000000..e5d4273
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png
new file mode 100644
index 0000000..1cc5009
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_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
new file mode 100644
index 0000000..8d7be53
--- /dev/null
+++ 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
new file mode 100644
index 0000000..613fba0
--- /dev/null
+++ 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_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
new file mode 100644
index 0000000..5ef7798
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_small.png
new file mode 100644
index 0000000..4a98e31
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_small.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
new file mode 100644
index 0000000..0511ad1
--- /dev/null
+++ 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
new file mode 100644
index 0000000..77fe9b2
--- /dev/null
+++ 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
new file mode 100644
index 0000000..ae78eb0
--- /dev/null
+++ 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
new file mode 100644
index 0000000..5b446b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png
new file mode 100644
index 0000000..8703e1d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_alarm.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_alarm.png
deleted file mode 100644
index 2f4cf9d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_0.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_0.png
deleted file mode 100644
index 80184ab..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_100.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_100.png
deleted file mode 100644
index f33f00e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_15.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_15.png
deleted file mode 100644
index 7f16039..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_15.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_28.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_28.png
deleted file mode 100644
index 83bfd39..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_28.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_43.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_43.png
deleted file mode 100644
index 2c85bcf..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_43.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_57.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_57.png
deleted file mode 100644
index ce1acbd..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_57.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_71.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_71.png
deleted file mode 100644
index df53bb0..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_71.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_85.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_85.png
deleted file mode 100644
index 44d8726..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_85.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim0.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim0.png
deleted file mode 100644
index 1a060e7..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim100.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim100.png
deleted file mode 100644
index 02fd013..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim15.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim15.png
deleted file mode 100644
index 496c5af..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim15.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim28.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim28.png
deleted file mode 100644
index e371412..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim28.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim43.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim43.png
deleted file mode 100644
index 13a0141..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim43.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim57.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim57.png
deleted file mode 100644
index bc6344a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim57.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim71.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim71.png
deleted file mode 100644
index 3a1bc96..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim71.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim85.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim85.png
deleted file mode 100644
index 12f5b99..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_battery_charge_anim85.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_bluetooth.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_bluetooth.png
deleted file mode 100644
index 31762a2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_bluetooth_connected.png
deleted file mode 100644
index c4376a2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_bluetooth_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_1x.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_1x.png
deleted file mode 100644
index 5691427..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_3g.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_3g.png
deleted file mode 100644
index 2464d9e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_4g.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_4g.png
deleted file mode 100644
index ffe90bc..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_e.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_e.png
deleted file mode 100644
index 823b3fa3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_g.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_g.png
deleted file mode 100644
index 1ac455c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_h.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_h.png
deleted file mode 100644
index 7a38b12..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_roam.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_roam.png
deleted file mode 100644
index 3861bfe..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_1x.png
deleted file mode 100644
index 2eb6246..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_3g.png
deleted file mode 100644
index 0ce5ec3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_4g.png
deleted file mode 100644
index 6bf2412..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_e.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_e.png
deleted file mode 100644
index 791de4d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_g.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_g.png
deleted file mode 100644
index 0712aa6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_h.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_h.png
deleted file mode 100644
index 2886e55..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_data_fully_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_ime_default.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index 47f0745c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_ime_pressed.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_ime_pressed.png
deleted file mode 100644
index 490504e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_0.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_0.png
deleted file mode 100644
index ac322ba..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_0_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_0_fully.png
deleted file mode 100644
index ac322ba..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_0_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_1.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_1.png
deleted file mode 100644
index f139bbe..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_1_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_1_fully.png
deleted file mode 100644
index af67018..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_2.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_2.png
deleted file mode 100644
index fe404e2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_2_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_2_fully.png
deleted file mode 100644
index 1ffa9b6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_3.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_3.png
deleted file mode 100644
index 75cd8ee..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_3_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_3_fully.png
deleted file mode 100644
index 666d1f6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_4.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_4.png
deleted file mode 100644
index da9607b..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_4_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_4_fully.png
deleted file mode 100644
index d05297f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_flightmode.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_flightmode.png
deleted file mode 100644
index 64d4e60..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_flightmode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_in.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_in.png
deleted file mode 100644
index 3d67766..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_inout.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_inout.png
deleted file mode 100644
index b74e070..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_null.png
deleted file mode 100644
index 709b181..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_out.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_out.png
deleted file mode 100644
index 24485e1..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_in.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_in.png
deleted file mode 100644
index 390d500..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_inout.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_inout.png
deleted file mode 100644
index 78998f9..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_out.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_out.png
deleted file mode 100644
index c539615..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_0.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_0.png
deleted file mode 100644
index 57675a2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_1.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_1.png
deleted file mode 100644
index eec0390..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_1_fully.png
deleted file mode 100644
index 900867a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_2.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_2.png
deleted file mode 100644
index 253bdac..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_2_fully.png
deleted file mode 100644
index b50576c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_3.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_3.png
deleted file mode 100644
index d69a171..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_3_fully.png
deleted file mode 100644
index 47df06f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_4.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_4.png
deleted file mode 100644
index 99184f0..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_4_fully.png
deleted file mode 100644
index 4a2ac51..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_null.png
deleted file mode 100644
index 4fd3a08..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_wifi_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_zoom_default.png
deleted file mode 100644
index 348afb5..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_zoom_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_zoom_pressed.png
deleted file mode 100644
index 2f20d67..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/ic_sysbar_zoom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_normal.9.png
deleted file mode 100644
index 88137e8..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_pressed.9.png
deleted file mode 100644
index 6507a51..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index a57c27a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4ac131a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/sysbar_notification_panel_bg.9.png
deleted file mode 100644
index 0c20ba2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/sysbar_notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_alarm.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_alarm.png
deleted file mode 100644
index 9b7c5d6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_0.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_0.png
deleted file mode 100644
index ea2918f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_100.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_100.png
deleted file mode 100644
index 906c818..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_15.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_15.png
deleted file mode 100644
index c855fa599d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_15.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_28.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_28.png
deleted file mode 100644
index cafa16f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_28.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_43.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_43.png
deleted file mode 100644
index 400c2ca..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_43.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_57.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_57.png
deleted file mode 100644
index 1aa0d82..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_57.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_71.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_71.png
deleted file mode 100644
index ac0bca1..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_71.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_85.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_85.png
deleted file mode 100644
index 2e76eee..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_85.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim0.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim0.png
deleted file mode 100644
index 8d54b97..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim100.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim100.png
deleted file mode 100644
index 784c4e7..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim15.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim15.png
deleted file mode 100644
index 6bc543c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim15.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim28.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim28.png
deleted file mode 100644
index ba449ac..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim28.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim43.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim43.png
deleted file mode 100644
index 13399f4..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim43.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim57.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim57.png
deleted file mode 100644
index e2a95ef..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim57.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim71.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim71.png
deleted file mode 100644
index 4c8ac28..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim71.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim85.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim85.png
deleted file mode 100644
index b3b9f52..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_battery_charge_anim85.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_bluetooth.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_bluetooth.png
deleted file mode 100644
index c4f0d78..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_bluetooth_connected.png
deleted file mode 100644
index 3034a47..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_bluetooth_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_1x.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_1x.png
deleted file mode 100644
index 5287c0f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_3g.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_3g.png
deleted file mode 100644
index d8a5ee8..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_4g.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_4g.png
deleted file mode 100644
index 11737ee..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_e.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_e.png
deleted file mode 100644
index 842faac..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_g.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_g.png
deleted file mode 100644
index 0548dd3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_h.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_h.png
deleted file mode 100644
index be79e0d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_roam.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_roam.png
deleted file mode 100644
index ee2e99e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_1x.png
deleted file mode 100644
index ee43332..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_3g.png
deleted file mode 100644
index 4e38c5d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_4g.png
deleted file mode 100644
index 6c08aa9..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_e.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_e.png
deleted file mode 100644
index 2e7c46d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_g.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_g.png
deleted file mode 100644
index 57f48fb..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_h.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_h.png
deleted file mode 100644
index f751a31..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_data_fully_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_ime_default.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index 33edce0..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_ime_pressed.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_ime_pressed.png
deleted file mode 100644
index 8bab6cf..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_0.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_0.png
deleted file mode 100644
index f931c60..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_0_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_0_fully.png
deleted file mode 100644
index f931c60..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_0_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_1.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_1.png
deleted file mode 100644
index 398f4d5..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_1_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_1_fully.png
deleted file mode 100644
index a0fc3f2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_2.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_2.png
deleted file mode 100644
index 5fe96a3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_2_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_2_fully.png
deleted file mode 100644
index 8a66255..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_3.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_3.png
deleted file mode 100644
index e785a7a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_3_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_3_fully.png
deleted file mode 100644
index 63be95d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_4.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_4.png
deleted file mode 100644
index 533bcdc..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_4_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_4_fully.png
deleted file mode 100644
index 566172e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_flightmode.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_flightmode.png
deleted file mode 100644
index f61c058..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_flightmode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_in.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_in.png
deleted file mode 100644
index 5c38d45..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_inout.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_inout.png
deleted file mode 100644
index 6a79695..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_null.png
deleted file mode 100644
index 67d5cbf..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_out.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_out.png
deleted file mode 100644
index 99dbe1b..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_in.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_in.png
deleted file mode 100644
index 6a73a89..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_inout.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_inout.png
deleted file mode 100644
index 7042f2b..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_out.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_out.png
deleted file mode 100644
index 3da781e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_0.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_0.png
deleted file mode 100644
index 1570dd2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_1.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_1.png
deleted file mode 100644
index 80a7a4a7..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_1_fully.png
deleted file mode 100644
index 9db1a84..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_2.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_2.png
deleted file mode 100644
index f9720f2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_2_fully.png
deleted file mode 100644
index 8567d11..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_3.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_3.png
deleted file mode 100644
index 5ee6d07..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_3_fully.png
deleted file mode 100644
index b38f7eb..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_4.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_4.png
deleted file mode 100644
index ec6e805..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_4_fully.png
deleted file mode 100644
index 9a79c54..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_null.png
deleted file mode 100644
index 1943e8c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_wifi_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_zoom_default.png
deleted file mode 100644
index 89d486f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_zoom_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_zoom_pressed.png
deleted file mode 100644
index b134436..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/ic_sysbar_zoom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_normal.9.png
deleted file mode 100644
index 798f589..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_pressed.9.png
deleted file mode 100644
index 73247e5..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 87c7be6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4362836..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/sysbar_notification_panel_bg.9.png
deleted file mode 100644
index 56cd238..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/sysbar_notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-tvdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-tvdpi/sysbar_notification_panel_bg.9.png
deleted file mode 100644
index 571a7a5..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-tvdpi/sysbar_notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_alarm.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_alarm.png
deleted file mode 100644
index 0f83f7a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_0.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_0.png
deleted file mode 100644
index 511923c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_100.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_100.png
deleted file mode 100644
index 61fa300..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_15.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_15.png
deleted file mode 100644
index daefb7c..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_15.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_28.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_28.png
deleted file mode 100644
index bc8c467..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_28.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_43.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_43.png
deleted file mode 100644
index a16c979..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_43.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_57.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_57.png
deleted file mode 100644
index 4778dc1..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_57.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_71.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_71.png
deleted file mode 100644
index 81693b6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_71.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_85.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_85.png
deleted file mode 100644
index e81bb8d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_85.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim0.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim0.png
deleted file mode 100644
index 9834f5a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim100.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim100.png
deleted file mode 100644
index b314f8b..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim15.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim15.png
deleted file mode 100644
index 59de3f2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim15.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim28.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim28.png
deleted file mode 100644
index 91397ed..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim28.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim43.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim43.png
deleted file mode 100644
index 268fea4..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim43.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim57.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim57.png
deleted file mode 100644
index 15ee476..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim57.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim71.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim71.png
deleted file mode 100644
index 4dead31..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim71.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim85.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim85.png
deleted file mode 100644
index 8b4563f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_battery_charge_anim85.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_bluetooth.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_bluetooth.png
deleted file mode 100644
index 2984394..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_bluetooth_connected.png
deleted file mode 100644
index 4b904b4..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_bluetooth_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_1x.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_1x.png
deleted file mode 100644
index 31af3c2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_3g.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_3g.png
deleted file mode 100644
index 4f5fa70..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_4g.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_4g.png
deleted file mode 100644
index e7eb85e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_e.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_e.png
deleted file mode 100644
index 79038f7..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_g.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_g.png
deleted file mode 100644
index c554b23..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_h.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_h.png
deleted file mode 100644
index e5c0780f0..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_roam.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_roam.png
deleted file mode 100644
index 0edc9b5..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_1x.png
deleted file mode 100644
index de93431..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_3g.png
deleted file mode 100644
index 9b01f30..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_4g.png
deleted file mode 100644
index a44d3a2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_e.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_e.png
deleted file mode 100644
index a4a93e3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_g.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_g.png
deleted file mode 100644
index 4f6f1ba..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_h.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_h.png
deleted file mode 100644
index bc135c3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_data_fully_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_ime_default.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index d670177..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_ime_pressed.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_ime_pressed.png
deleted file mode 100644
index c9f0302..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_0.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_0.png
deleted file mode 100644
index ccf1ba1..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_0_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_0_fully.png
deleted file mode 100644
index ccf1ba1..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_0_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_1.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_1.png
deleted file mode 100644
index 07937fe..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_1_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_1_fully.png
deleted file mode 100644
index ba1b077..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_2.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_2.png
deleted file mode 100644
index a705a89..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_2_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_2_fully.png
deleted file mode 100644
index 0187d12..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_3.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_3.png
deleted file mode 100644
index 0ed7d6f4..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_3_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_3_fully.png
deleted file mode 100644
index 24a6e5a..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_4.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_4.png
deleted file mode 100644
index 1a47801..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_4_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_4_fully.png
deleted file mode 100644
index d9648b6f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_flightmode.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_flightmode.png
deleted file mode 100644
index 620da77..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_flightmode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_in.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_in.png
deleted file mode 100644
index cf63e24..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_inout.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_inout.png
deleted file mode 100644
index 8f68e1f..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_null.png
deleted file mode 100644
index fa8735d..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_out.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_out.png
deleted file mode 100644
index 894c63b..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_in.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_in.png
deleted file mode 100644
index 1ec5b49..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_inout.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_inout.png
deleted file mode 100644
index 9ca3ca8..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_out.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_out.png
deleted file mode 100644
index 74241e0..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_0.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_0.png
deleted file mode 100644
index 9553241..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_1.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_1.png
deleted file mode 100644
index 4d70eb3..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_1_fully.png
deleted file mode 100644
index bfa3ad7..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_1_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_2.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_2.png
deleted file mode 100644
index f7e78d0..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_2_fully.png
deleted file mode 100644
index fc90385..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_2_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_3.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_3.png
deleted file mode 100644
index 931905e..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_3_fully.png
deleted file mode 100644
index f1fa45b..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_3_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_4.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_4.png
deleted file mode 100644
index 0dd11a2..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_4_fully.png
deleted file mode 100644
index 20991eb..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_null.png
deleted file mode 100644
index de573b6..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_wifi_signal_null.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_zoom_default.png
deleted file mode 100644
index dd8c498..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_zoom_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_zoom_pressed.png
deleted file mode 100644
index dc42157..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/ic_sysbar_zoom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_normal.9.png
deleted file mode 100644
index 2b46c89..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_pressed.9.png
deleted file mode 100644
index dd476b7..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 59908ad..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_blue_glow.9.png
deleted file mode 100644
index 3938502..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/sysbar_notification_panel_bg.9.png
deleted file mode 100644
index 3f05767..0000000
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/sysbar_notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/alert_bar_background_normal.9.png
deleted file mode 100644
index eb44262..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/alert_bar_background_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/alert_bar_background_pressed.9.png
deleted file mode 100644
index 887e006..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/alert_bar_background_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png
deleted file mode 100644
index c26ed9c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png
+++ /dev/null
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
index f3c0fca..83693c1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
+++ b/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png
deleted file mode 100644
index 35511d6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png
deleted file mode 100644
index a38b40f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal.9.png
deleted file mode 100644
index 5e601d2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable.9.png
deleted file mode 100644
index ed92cd0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable_focused.9.png
deleted file mode 100644
index f77dbfb..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_pressed.9.png
deleted file mode 100644
index e34107b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_selected.9.png
deleted file mode 100644
index 8f70177..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_diagram.png b/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_diagram.png
deleted file mode 100644
index 03f4732..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_diagram.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_divider_bottom.9.png b/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_divider_bottom.9.png
deleted file mode 100644
index 7bfdb46..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_divider_bottom.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_divider_top.9.png b/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_divider_top.9.png
deleted file mode 100644
index 4e20851..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_divider_top.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_icon.png b/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_icon.png
deleted file mode 100644
index 1c1b26b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/compat_mode_help_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/hd_off.png b/packages/SystemUI/res/drawable-xhdpi/hd_off.png
deleted file mode 100644
index 7f5bd88..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/hd_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/hd_on.png b/packages/SystemUI/res/drawable-xhdpi/hd_on.png
deleted file mode 100644
index 55305ce..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/hd_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png
new file mode 100644
index 0000000..42e5593
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png
deleted file mode 100644
index 2b2907b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_dnd.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_dnd.png
deleted file mode 100644
index 0e926ab..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_dnd.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
deleted file mode 100644
index 98455cf..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png
index 8758b02..aae807b7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notifications_normal.png
deleted file mode 100644
index 983302c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notifications_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
index c882e9a..b9afa44 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
deleted file mode 100644
index 992b50d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
index 56386f8..990f8bb 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_pressed.png
deleted file mode 100644
index 501c777..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
index 2d445279..96eaafe 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
deleted file mode 100644
index ddf2c7a..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_off_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_off_normal.png
deleted file mode 100644
index cebd6d8..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_off_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_off_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_off_pressed.png
deleted file mode 100644
index ef4d9a1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_off_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_on_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_on_normal.png
deleted file mode 100644
index 01146aa..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_on_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_on_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_on_pressed.png
deleted file mode 100644
index e8f01c5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_rotation_on_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
index 80fdb79..c0032e2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_pressed.png
deleted file mode 100644
index ac7c1a7..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
index 9a4239b..32e6c49 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
index 0af4f3d..79e4ff6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png
index 07e749a..3c0eac1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
index f9ab581..c553bc2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png
index 2b592cc..ff3bdf0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_100.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_100.png
index 2c56c9b..8bc6d17 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_100.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png
index 9895f71..39fccc8 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_28.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_28.png
index 323fa8b..70829a1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_28.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_43.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_43.png
index 98eea99..ebd97c8 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_43.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_57.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_57.png
index 64555c0..9d5be12 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_57.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_71.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_71.png
index ad8b15f..1ffa245 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_71.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_85.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_85.png
index 071b79b..b6aebe6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_85.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_bolt.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_bolt.png
deleted file mode 100644
index 0c5594d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_bolt.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_100.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_100.png
index 234bb63..37cb7c4 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_100.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png
index e3c6920..1a595ed 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_28.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_28.png
index 3dfbe4c..e36e68c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_28.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_43.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_43.png
index 3f493f1..e58f9c0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_43.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_57.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_57.png
index 0cce725..c7fafa4 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_57.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_71.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_71.png
index f6fff00..5dcec0e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_71.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_85.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_85.png
index 35ef746..6e81974 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_85.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_unknown.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_unknown.png
index f5fbbfb..1db2eb3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_unknown.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_unknown.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
index e312f8e..ce965c2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
index 44cd31b..273f363 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
index 62a518a..ac5b09d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png
index 653fa3f..37d7ac7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png
index 4ed4a9e..626e283 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_certificate_info.png
new file mode 100644
index 0000000..b3de2ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_certificate_info.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_circle.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_circle.png
index c7864ba..72c587d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_circle.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_circle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png
index 02c4a05..d18dbd9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png
index aa6be72..31230af 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
index fd9b677..d14a67f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png
index 7eabd10..bffbf55 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location.png
index b2033df..a52dc8d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
new file mode 100644
index 0000000..466470c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
new file mode 100644
index 0000000..6300bdc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
index 88ea017..92c6df0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
index 7573636..621c045 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
index 0098df49..b6daaf3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png
index 2d3638c..e888ac2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_0.png
index 7419be9..e303016 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png
index 471e1fa..abc9358 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png
index cb1eb0f..f88e3a4 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png
index 4311330..0419144 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png
index 637e079..515ffe7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png
index 8fdd7ff..9aff8aa 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png
index 8fca5f2..118de2d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png
index 125e33d..2e00303 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png
index acf4752..33ae551 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_0.png
index 25a5c53..2ef694e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1.png
index 1cbe239..58317e3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1x.png
index 9507162..2866e4c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1x.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_2.png
index deb8c87..57b8039 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3.png
index 7186579..0cb099c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3g.png
index 1aa2393..922f7ca 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4.png
index adafb2c..a857c32 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4g.png
index 0083754..82ced1e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_e.png
index 67e2e11..7ae8f90 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_e.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_g.png
index f47c63e..050cbcb 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_h.png
index 2421050..7440bc0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_h.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png
index 75c5c72..4212e49 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png
index cb4782e..2176a88 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png
index fd5fb17..fb09a26 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png
index c63bbfa..b52aec7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
index a0d588d..46fd826 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
index 341716d..c824b97 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png
index 402db43..9942e7a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_network.png
index 7f2be8c..f7571db 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_network.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_signal.png
index 15169b9..43a7d82 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_signal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
index b2ad34d..fb9ecd0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png
index 89680ce..1efdebf 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png
index 780a511..86de480 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_0.png
index 42fdbe8..5599069 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png
index eefe7ed..715e60a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png
index a2caca2..ed7f5b9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png
index 08c1abd..8f1464b 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png
index 8af72e51..b32c676 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_1.png
index 7d9f032..0702c31 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_2.png
index 896eacc..6693090 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_3.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_3.png
index 0224da1..ded4c67 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_4.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_4.png
index fe28671..c2e0da9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
index a0d588d..6cf0a4b 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
index 341716d..c824b97 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_no_network.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_no_network.png
index 4c6f1ff..22e0f8c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_no_network.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_not_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_not_connected.png
index a6dd06a..2344349 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_not_connected.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
index b2ad34d..fb9ecd0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_airplane_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_airplane_on.png
deleted file mode 100644
index 31ac35d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_airplane_on.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 bd60cd6..a2bb50a 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 7f05602..24897ce 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 5272c91..aaeeb1b 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_brightness.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_brightness.png
deleted file mode 100644
index bc024da..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_brightness.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..b0ea8e0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.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 c5bc5c9..ddee461 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 33e1801..23a7997 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_ime_default.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_default.png
deleted file mode 100644
index 2d77fb1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
index 155c788..e62dece 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png
index e84f3fb..958b2fe 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.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 5c9c0e5f..9f200c2 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 4db9e9d..43e9bc2 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_quicksettings.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_quicksettings.png
deleted file mode 100644
index bbf5f7e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_quicksettings.png
+++ /dev/null
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 f621d9c..5c0ba82 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 b530638..b76a0ca 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/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
deleted file mode 100644
index 35d85e1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
deleted file mode 100644
index bc1628f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/pocket_drag_pattern.png b/packages/SystemUI/res/drawable-xhdpi/pocket_drag_pattern.png
deleted file mode 100644
index 34431f4..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/pocket_drag_pattern.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png
deleted file mode 100644
index e1e08c6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
index 1d097c5..79d1b3c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png
index 80fc849..c57ec67 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
index 5bae56d..78a69f5 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png
index c096c7a..511537a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light.png b/packages/SystemUI/res/drawable-xhdpi/search_light.png
index 3aa890f..68b70eb 100644
--- a/packages/SystemUI/res/drawable-xhdpi/search_light.png
+++ b/packages/SystemUI/res/drawable-xhdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
index 4931304..24bdbb6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
index 5ba83b6..6ecd2d3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_more.png
index 16bf510..64327ba 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_more.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_notify_more.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png
index 19ad300..8bca860 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_0.png
index 2b47449..8ea54ee 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_100.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_100.png
index 36c61e1..877abf4 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_100.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png
index 00f3aca..94605c9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_28.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_28.png
index ae5d0ca..c4b77ec 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_28.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_43.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_43.png
index 201a33c..9983d60 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_43.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_57.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_57.png
index a0c9d3a..de09dc6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_57.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_71.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_71.png
index 6595973..99908696 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_71.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_85.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_85.png
index 40fce24..7a630f9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_85.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim0.png
index eee1bde..8a0a50f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim100.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim100.png
index c7fd719..58ff765 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim100.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim15.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim15.png
index 7bbbe27..ca14841 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim28.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim28.png
index 88c65f8..9b1a47c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim28.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim43.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim43.png
index f89e797..dd00668 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim43.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim57.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim57.png
index d58d5f6..556c710 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim57.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim71.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim71.png
index 1ea3ed2..b87eb87 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim71.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim85.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim85.png
index 7c89149..fe7c1af 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim85.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_charge_anim85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth.png
index 524b31b..757dbf3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth_connected.png
index 25eb75e..d431dc2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth_connected.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index bd31253..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 5ed365c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 5b22d20..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index b156b06..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index f850477..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index b261c1e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 7a59975..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index c0b1fea..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_1x.png
index cb2be9d..2204093 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_3g.png
index 61821c7..9f5e4af 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_4g.png
index 2594dd4..a95b9e1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_e.png
index 6f2619b..42ad245 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_g.png
index 7f7c6f2..fde5323 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_h.png
index 24830b6..c6cca3e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_lte.png
index 84348ad..84f5cb1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_lte.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..5228c29
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png
index 7a8d1f3..f64d582 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png
index 5f86bbb..31f5b90 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png
index 70e2011..881d5e8 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png
index c1d1cc3..2d80c4d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png
index c62d977..ad85c83 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png
index 86d30df..bde43c6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png
index b112748..914ac49 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
index bfc7d81..c83e9fe 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
index bea643f3a..48bca90 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png
index a8a89d6..15514340 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..a7f0017
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_gps_acquiring.png
deleted file mode 100644
index 263c591..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_gps_acquiring.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
index 2e64402..461535c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
index a8e8e0f..662d062 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
index d2d03cd..18be9c0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png
index 51b291c..f0c2f05 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_flash_anim0.png
deleted file mode 100644
index 23d30fe..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_flash_anim0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_flash_anim1.png
deleted file mode 100644
index 51b291c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png
index 0a28885..659275f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png
index bbe70cc..17c0d99 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
deleted file mode 100644
index 9943613..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png
index e25a55c..8a5a476 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
deleted file mode 100644
index 1fc1775..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png
index d1aefca..a6c12b2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
deleted file mode 100644
index 82b9741..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png
index c8c2c63..3fdc60e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
deleted file mode 100644
index 9f4979c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png
index b2e64b9..b09247e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_flightmode.png
index 7b43654..95c217c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.png
deleted file mode 100644
index cc9c49f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.png
deleted file mode 100644
index 5a313c5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
index 90b8c84..3b94b6b 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.png
deleted file mode 100644
index 373a4a4..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png
index fdd640c..75b002d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png
deleted file mode 100644
index a1a0646..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png
index d28972f..8c48af4 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.png
deleted file mode 100644
index d299daf..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.png
deleted file mode 100644
index dcfdb7b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.png
deleted file mode 100644
index fb8125a..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_0.png
index a834f79..e402ff6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 9185030..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1_fully.png
index 76f9f4a..313ce4e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index 17889bb..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2_fully.png
index 16b877b..546c7a8 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index e197eb6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3_fully.png
index b6cd98c..ec45d86 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index a87cd66..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4_fully.png
index 625c61d..459a1a2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
index 5881402..d6f752a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_bg_tile.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_bg_tile.png
deleted file mode 100644
index d01b117..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_bg_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png
index 98d0cfb..1fed081 100644
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
index 17f4169..b4e129c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_expand_default.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_expand_default.png
deleted file mode 100644
index 3abbe25..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_expand_default.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_expand_pressed.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_expand_pressed.png
deleted file mode 100644
index 041eac5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_expand_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_hr.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_hr.9.png
deleted file mode 100644
index 748b9f7..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_hr.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-xhdpi/title_bar_shadow.9.png
deleted file mode 100644
index 89f14db..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/title_bar_shadow.9.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
new file mode 100644
index 0000000..cebbb15
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png
new file mode 100644
index 0000000..586a738
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-xxhdpi/ic_menu_share.png
new file mode 100644
index 0000000..d450531
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png
new file mode 100644
index 0000000..fa7de0e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
new file mode 100644
index 0000000..afdee8f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
new file mode 100644
index 0000000..60579f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
new file mode 100644
index 0000000..abb9b18
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
new file mode 100644
index 0000000..a3cc08d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png
new file mode 100644
index 0000000..3d3c9bb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png
new file mode 100644
index 0000000..dd16165
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_alarm_on.png
new file mode 100644
index 0000000..1e8509b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_alarm_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png
new file mode 100644
index 0000000..b6cfaec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png
new file mode 100644
index 0000000..6ddf734
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_100.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_100.png
new file mode 100644
index 0000000..c04dc4b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png
new file mode 100644
index 0000000..e1e1b2e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_28.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_28.png
new file mode 100644
index 0000000..6ff8518
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_43.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_43.png
new file mode 100644
index 0000000..c0e94f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_57.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_57.png
new file mode 100644
index 0000000..175e14b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_71.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_71.png
new file mode 100644
index 0000000..ca6ba47
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_85.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_85.png
new file mode 100644
index 0000000..95017e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_orange.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_orange.png
new file mode 100644
index 0000000..2b333d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_orange.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_red.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_red.png
new file mode 100644
index 0000000..4c71154
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_red.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_white.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_white.png
new file mode 100644
index 0000000..976a36b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_white.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_0.png
new file mode 100644
index 0000000..82d4806
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_100.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_100.png
new file mode 100644
index 0000000..7d11599
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png
new file mode 100644
index 0000000..3b36bb9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_28.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_28.png
new file mode 100644
index 0000000..d36bd5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_43.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_43.png
new file mode 100644
index 0000000..a3f543a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_57.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_57.png
new file mode 100644
index 0000000..0208baf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_71.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_71.png
new file mode 100644
index 0000000..ea46076
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_85.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_85.png
new file mode 100644
index 0000000..4cbfea6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_unknown.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_unknown.png
new file mode 100644
index 0000000..5ae0221
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_unknown.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png
new file mode 100644
index 0000000..c5b7333
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png
new file mode 100644
index 0000000..ca1aef0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png
new file mode 100644
index 0000000..7c20110
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png
new file mode 100644
index 0000000..2697b5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png
new file mode 100644
index 0000000..b6443fa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_certificate_info.png
new file mode 100644
index 0000000..5d6f6c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_certificate_info.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_circle.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_circle.png
new file mode 100644
index 0000000..849d547
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_circle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_hour.png
new file mode 100644
index 0000000..57dd8a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_minute.png
new file mode 100644
index 0000000..a9b8ba5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png
new file mode 100644
index 0000000..07f16c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png
new file mode 100644
index 0000000..ab841d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location.png
new file mode 100644
index 0000000..3175636
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
new file mode 100644
index 0000000..920407d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
new file mode 100644
index 0000000..d6d4c70
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..5f6231c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..f02d0ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png
new file mode 100644
index 0000000..8e37884
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_settings.png
new file mode 100644
index 0000000..d1a72be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_0.png
new file mode 100644
index 0000000..76f39c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png
new file mode 100644
index 0000000..746b9ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png
new file mode 100644
index 0000000..6706ae2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png
new file mode 100644
index 0000000..55ba5ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png
new file mode 100644
index 0000000..547f875
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png
new file mode 100644
index 0000000..4d1dc75
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png
new file mode 100644
index 0000000..1f65ad5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png
new file mode 100644
index 0000000..aab9d27
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png
new file mode 100644
index 0000000..cd92c5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_0.png
new file mode 100644
index 0000000..eb4b855
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_1.png
new file mode 100644
index 0000000..edc44ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_1x.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_1x.png
new file mode 100644
index 0000000..ed1f7c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_2.png
new file mode 100644
index 0000000..5bd9b76
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_3.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_3.png
new file mode 100644
index 0000000..16196a03
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_3g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_3g.png
new file mode 100644
index 0000000..a4f4461
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_4.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_4.png
new file mode 100644
index 0000000..7b3d06d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_4g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_4g.png
new file mode 100644
index 0000000..7cdcdf4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_e.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_e.png
new file mode 100644
index 0000000..c9bed1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_g.png
new file mode 100644
index 0000000..b9aca9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_h.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_h.png
new file mode 100644
index 0000000..25edf97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png
new file mode 100644
index 0000000..0dc66b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png
new file mode 100644
index 0000000..b60cda6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png
new file mode 100644
index 0000000..b686376
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png
new file mode 100644
index 0000000..bfe2271
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png
new file mode 100644
index 0000000..1094bc3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png
new file mode 100644
index 0000000..1037b02
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png
new file mode 100644
index 0000000..b5def3e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_no_network.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_no_network.png
new file mode 100644
index 0000000..78fe964
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_no_signal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_no_signal.png
new file mode 100644
index 0000000..d2e27d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_no_signal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png
new file mode 100644
index 0000000..f5595e3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png
new file mode 100644
index 0000000..60e2bd3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_usb_device.png
new file mode 100644
index 0000000..99abb6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_usb_device.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_0.png
new file mode 100644
index 0000000..f1d9f21
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png
new file mode 100644
index 0000000..01274a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png
new file mode 100644
index 0000000..a02832d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png
new file mode 100644
index 0000000..7e55bbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png
new file mode 100644
index 0000000..eeb8989
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_1.png
new file mode 100644
index 0000000..dbae28c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_2.png
new file mode 100644
index 0000000..06e8d5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_3.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_3.png
new file mode 100644
index 0000000..bff132b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_4.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_4.png
new file mode 100644
index 0000000..636bd702
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_full_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png
new file mode 100644
index 0000000..7183a07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png
new file mode 100644
index 0000000..3746328
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_no_network.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_no_network.png
new file mode 100644
index 0000000..83402ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_no_network.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_not_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_not_connected.png
new file mode 100644
index 0000000..9c5a207
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_not_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png
new file mode 100644
index 0000000..dbf54ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png
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
new file mode 100644
index 0000000..79cfcee
--- /dev/null
+++ 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
new file mode 100644
index 0000000..7959f65
--- /dev/null
+++ 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
new file mode 100644
index 0000000..c3bfcfb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..aac3428
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png
new file mode 100644
index 0000000..0df6203
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png
new file mode 100644
index 0000000..b400b14
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_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
new file mode 100644
index 0000000..64f6a22
--- /dev/null
+++ 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
new file mode 100644
index 0000000..8fd36bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
new file mode 100644
index 0000000..55a266f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_small.png
new file mode 100644
index 0000000..97d1fbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_small.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
new file mode 100644
index 0000000..6f30e54
--- /dev/null
+++ 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
new file mode 100644
index 0000000..024ef8f
--- /dev/null
+++ 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
new file mode 100644
index 0000000..6e0b071
--- /dev/null
+++ 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
new file mode 100644
index 0000000..9a56987
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png
new file mode 100644
index 0000000..adcdcb7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..a446448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_dragging.9.png
new file mode 100644
index 0000000..c424ffe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png
new file mode 100644
index 0000000..a446448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..1fa1e62
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-xxhdpi/screenshot_panel.9.png
new file mode 100644
index 0000000..45259d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/screenshot_panel.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light.png b/packages/SystemUI/res/drawable-xxhdpi/search_light.png
new file mode 100644
index 0000000..faa97f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
new file mode 100644
index 0000000..5e733ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
new file mode 100644
index 0000000..ecc2c83
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_more.png
new file mode 100644
index 0000000..3c33a56
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_more.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png
new file mode 100644
index 0000000..d42d9d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_0.png
new file mode 100644
index 0000000..2d916d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_100.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_100.png
new file mode 100644
index 0000000..fe3c750
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png
new file mode 100644
index 0000000..a2bab6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_28.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_28.png
new file mode 100644
index 0000000..224be03
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_43.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_43.png
new file mode 100644
index 0000000..dabed32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_57.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_57.png
new file mode 100644
index 0000000..82d04c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_71.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_71.png
new file mode 100644
index 0000000..1d403c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_85.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_85.png
new file mode 100644
index 0000000..b917d37
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim0.png
new file mode 100644
index 0000000..1da84be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim100.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim100.png
new file mode 100644
index 0000000..17989b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim15.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim15.png
new file mode 100644
index 0000000..8733bc3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim28.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim28.png
new file mode 100644
index 0000000..54cc847
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim43.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim43.png
new file mode 100644
index 0000000..5d5ba2f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim57.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim57.png
new file mode 100644
index 0000000..6a5035e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim71.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim71.png
new file mode 100644
index 0000000..82a891f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim85.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim85.png
new file mode 100644
index 0000000..399bb97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_charge_anim85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_bluetooth.png
new file mode 100644
index 0000000..17ffdb9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_bluetooth_connected.png
new file mode 100644
index 0000000..6ec234e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_1x.png
new file mode 100644
index 0000000..ba64922
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_3g.png
new file mode 100644
index 0000000..5b57c1e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..64b8b26
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_e.png
new file mode 100644
index 0000000..02e7411
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_g.png
new file mode 100644
index 0000000..0a5dc61
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_h.png
new file mode 100644
index 0000000..96a747c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_lte.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_lte.png
new file mode 100644
index 0000000..46584bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..1f8549e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..21daf5c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..3397570
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..87039c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..a21f3c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..65b323f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..c5c3550
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..801cb3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..149d227
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..6edb37a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..2b01e9b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..ad34d49
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png
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
new file mode 100644
index 0000000..7b03a11
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
new file mode 100644
index 0000000..aabf0aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
new file mode 100644
index 0000000..654c2a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_roaming_cdma_0.png
new file mode 100644
index 0000000..1c544c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png
new file mode 100644
index 0000000..3c9d3e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png
new file mode 100644
index 0000000..065f1da
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png
new file mode 100644
index 0000000..da2da18
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png
new file mode 100644
index 0000000..30c5abf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png
new file mode 100644
index 0000000..e49fd0a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png
new file mode 100644
index 0000000..c5114e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_flightmode.png
new file mode 100644
index 0000000..155c222
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..b388b8f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png
new file mode 100644
index 0000000..99b2fff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_tty_mode.png
new file mode 100644
index 0000000..075208a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_0.png
new file mode 100644
index 0000000..bc272ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_1_fully.png
new file mode 100644
index 0000000..d032db3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_2_fully.png
new file mode 100644
index 0000000..562101b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_3_fully.png
new file mode 100644
index 0000000..ceb4163
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_4_fully.png
new file mode 100644
index 0000000..494b005
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..3da56ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png
new file mode 100644
index 0000000..d50ff85
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..5d27ccd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-xxhdpi/title_bar_shadow.9.png
new file mode 100644
index 0000000..e86f891
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/alert_bar_background.xml b/packages/SystemUI/res/drawable/alert_bar_background.xml
deleted file mode 100644
index 24b6aa3..0000000
--- a/packages/SystemUI/res/drawable/alert_bar_background.xml
+++ /dev/null
@@ -1,23 +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_pressed="true" 
-        android:drawable="@drawable/alert_bar_background_pressed" />
-    <item
-         android:drawable="@drawable/alert_bar_background_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/btn_default_small.xml b/packages/SystemUI/res/drawable/btn_default_small.xml
deleted file mode 100644
index 5485ea0..0000000
--- a/packages/SystemUI/res/drawable/btn_default_small.xml
+++ /dev/null
@@ -1,33 +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_window_focused="false" android:state_enabled="true"
-        android:drawable="@drawable/btn_default_small_normal" />
-    <item android:state_window_focused="false" android:state_enabled="false"
-        android:drawable="@drawable/btn_default_small_normal_disable" />
-    <item android:state_pressed="true" 
-        android:drawable="@drawable/btn_default_small_pressed" />
-    <item android:state_focused="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_default_small_selected" />
-    <item android:state_enabled="true"
-        android:drawable="@drawable/btn_default_small_normal" />
-    <item android:state_focused="true"
-        android:drawable="@drawable/btn_default_small_normal_disable_focused" />
-    <item
-         android:drawable="@drawable/btn_default_small_normal_disable" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/cling_button_bg.xml b/packages/SystemUI/res/drawable/cling_button_bg.xml
deleted file mode 100644
index d175f53..0000000
--- a/packages/SystemUI/res/drawable/cling_button_bg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@drawable/btn_cling_pressed" />
-    <item android:drawable="@drawable/btn_cling_normal" />
-</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/hd.xml b/packages/SystemUI/res/drawable/hd.xml
deleted file mode 100644
index 73867a2..0000000
--- a/packages/SystemUI/res/drawable/hd.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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_checked="false"
-          android:drawable="@drawable/hd_off" />
-    <item android:drawable="@drawable/hd_on" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml b/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml
new file mode 100644
index 0000000..59d9fcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+    <item android:state_pressed="true"
+          android:drawable="@drawable/heads_up_notification_bg_pressed" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_notify_rotation.xml b/packages/SystemUI/res/drawable/ic_notify_rotation.xml
deleted file mode 100644
index 11bc22c..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_rotation.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:constantSize="true">
-    <item android:state_checked="true" android:state_pressed="true">
-        <bitmap android:src="@drawable/ic_notify_rotation_on_pressed"
-                android:gravity="center" />
-    </item>
-    <item android:state_checked="true">
-        <bitmap android:src="@drawable/ic_notify_rotation_on_normal"
-                android:gravity="center" />
-    </item>
-    <item android:state_pressed="true">
-        <bitmap android:src="@drawable/ic_notify_rotation_off_pressed"
-                android:gravity="center" />
-    </item>
-    <item>
-        <bitmap android:src="@drawable/ic_notify_rotation_off_normal"
-                android:gravity="center" />
-    </item>
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_ime.xml b/packages/SystemUI/res/drawable/ic_sysbar_ime.xml
deleted file mode 100644
index 1accf00..0000000
--- a/packages/SystemUI/res/drawable/ic_sysbar_ime.xml
+++ /dev/null
@@ -1,21 +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_pressed="true" android:drawable="@drawable/ic_sysbar_ime_pressed" />
-    <item android:drawable="@drawable/ic_sysbar_ime_default" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml b/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml
deleted file mode 100644
index 97d0348..0000000
--- a/packages/SystemUI/res/drawable/ic_sysbar_zoom.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">
-    <item android:state_pressed="true" android:drawable="@drawable/ic_sysbar_zoom_pressed" />
-    <item android:state_selected="true" android:drawable="@drawable/ic_sysbar_zoom_pressed" />
-    <item android:drawable="@drawable/ic_sysbar_zoom_default" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/intruder_row_bg.xml b/packages/SystemUI/res/drawable/intruder_row_bg.xml
deleted file mode 100644
index 1c7c9c4..0000000
--- a/packages/SystemUI/res/drawable/intruder_row_bg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
-    <item android:state_pressed="true"  android:drawable="@drawable/intruder_bg_pressed" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/intruder_window_bg.9.png b/packages/SystemUI/res/drawable/intruder_window_bg.9.png
deleted file mode 100644
index caad169..0000000
--- a/packages/SystemUI/res/drawable/intruder_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml b/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml
deleted file mode 100644
index c83d878..0000000
--- a/packages/SystemUI/res/drawable/notify_panel_clock_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">
-    <item android:state_pressed="true"
-        android:drawable="@drawable/notify_panel_clock_bg_pressed" />
-    <item android:drawable="@drawable/notify_panel_clock_bg_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/pocket_drag_bg.xml b/packages/SystemUI/res/drawable/pocket_drag_bg.xml
deleted file mode 100644
index 573a702..0000000
--- a/packages/SystemUI/res/drawable/pocket_drag_bg.xml
+++ /dev/null
@@ -1,21 +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.
--->
-
-<bitmap
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:tileMode="repeat"
-    android:src="@drawable/pocket_drag_pattern"
-    />
diff --git a/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml b/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
deleted file mode 100644
index 393697c..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="false">
-    <item android:drawable="@drawable/stat_sys_gps_acquiring" android:duration="500" />
-    <item android:drawable="@*android:drawable/stat_sys_gps_on" android:duration="500" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml b/packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml
deleted file mode 100644
index 07dc446..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** 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.
-*/
--->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="false">
-    <item android:drawable="@drawable/stat_sys_roaming_cdma_flash_anim0" android:duration="800" />
-    <item android:drawable="@drawable/stat_sys_roaming_cdma_flash_anim1" android:duration="1200" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/status_bar_bg.xml b/packages/SystemUI/res/drawable/status_bar_bg.xml
deleted file mode 100644
index 403493b..0000000
--- a/packages/SystemUI/res/drawable/status_bar_bg.xml
+++ /dev/null
@@ -1,21 +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.
--->
-
-<bitmap
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:tileMode="repeat"
-    android:src="@drawable/status_bar_bg_tile"
-    />
diff --git a/packages/SystemUI/res/drawable/status_bar_expand.xml b/packages/SystemUI/res/drawable/status_bar_expand.xml
deleted file mode 100644
index f966920..0000000
--- a/packages/SystemUI/res/drawable/status_bar_expand.xml
+++ /dev/null
@@ -1,21 +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_pressed="true" android:drawable="@drawable/status_bar_expand_pressed" />
-    <item android:drawable="@drawable/status_bar_expand_default" />
-</selector>
-
diff --git a/packages/SystemUI/res/layout-land/status_bar_help.xml b/packages/SystemUI/res/layout-land/status_bar_help.xml
deleted file mode 100644
index a885b86..0000000
--- a/packages/SystemUI/res/layout-land/status_bar_help.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the combined status bar / notification panel window. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/status_bar_cling"
-    android:paddingStart="40dp"
-    android:paddingEnd="40dp"
-    android:background="#DD000000"
-    android:focusable="true"
-    android:orientation="horizontal" 
-    android:gravity="top|start"
-    >
-
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_weight="0"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="50dp"
-        android:gravity="center"
-        android:src="@drawable/arrow_dashed"
-        tools:ignore="ContentDescription" />
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        android:layout_marginTop="40dp"
-        >
-        <TextView
-            style="@style/ClingTitleText"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/status_bar_help_title" />
-
-        <TextView
-            style="@style/ClingText"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="30dp"
-            android:text="@string/status_bar_help_text" />
-
-        <Button
-            android:id="@+id/ok"
-            style="@style/ClingButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingStart="50dp"
-            android:paddingEnd="50dp"
-            android:text="@android:string/ok" />
-    </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
index 03ca729..aa7256b 100644
--- a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
@@ -23,7 +23,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    android:background="#FF000000"
+    android:background="@drawable/system_bar_background"
     >
 
     <FrameLayout android:id="@+id/rot0"
@@ -153,6 +153,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
@@ -297,6 +298,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 47db1c7..b9ad799 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -22,7 +22,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    android:background="#FF000000"
+    android:background="@drawable/system_bar_background"
     >
 
     <FrameLayout android:id="@+id/rot0"
@@ -149,6 +149,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
@@ -290,6 +291,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout/compat_mode_help.xml b/packages/SystemUI/res/layout/compat_mode_help.xml
deleted file mode 100644
index 566d07d..0000000
--- a/packages/SystemUI/res/layout/compat_mode_help.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:background="@drawable/compat_mode_help_bg"
-    >
-    <TextView
-        android:id="@+id/header"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="80dp"
-        android:layout_marginTop="80dp"
-        android:layout_marginEnd="80dp"
-        android:textSize="60sp"
-        android:maxLines="1"
-        android:shadowRadius="8"
-        android:shadowColor="#FF000000"
-        android:text="@string/compat_mode_help_header"
-        android:background="@drawable/compat_mode_help_divider_top"
-        />
-    <ImageView
-        android:id="@+id/diagram"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:src="@drawable/compat_mode_help_diagram"
-        android:contentDescription="@string/accessibility_compatibility_zoom_example"
-        />
-    <RelativeLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="190dp"
-        android:background="@drawable/compat_mode_help_divider_bottom"
-        android:layout_marginBottom="55dp"
-        android:layout_marginEnd="80dp"
-        android:layout_alignStart="@id/header"
-        android:layout_alignParentBottom="true"
-        >
-        <ImageView
-            android:id="@+id/icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentEnd="true"
-            android:layout_centerVertical="true"
-            android:src="@drawable/compat_mode_help_icon"
-            android:contentDescription="@string/accessibility_compatibility_zoom_button"
-            />
-        <TextView
-            android:id="@+id/explanation"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            android:layout_alignParentStart="true"
-            android:layout_toStartOf="@id/icon"
-            android:layout_marginEnd="10dp"
-            android:shadowRadius="4"
-            android:shadowColor="#FF000000"
-            android:textSize="28sp"
-            android:text="@string/compat_mode_help_body"
-            />
-    </RelativeLayout>
-    <Button
-        android:id="@+id/button"
-        android:layout_width="208dp"
-        android:layout_height="48dp"
-        android:layout_alignStart="@id/header"
-        android:layout_alignParentBottom="true"
-        android:layout_marginBottom="20dp"
-        android:textSize="28sp"
-        android:text="@android:string/ok"
-        />
-</RelativeLayout>
-
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
new file mode 100644
index 0000000..564dc51
--- /dev/null
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** 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 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!--    android:background="@drawable/status_bar_closed_default_background" -->
+<com.android.systemui.statusbar.policy.HeadsUpNotificationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:orientation="vertical"
+    >
+    <FrameLayout
+            android:layout_height="wrap_content"
+            android:layout_width="@dimen/notification_panel_width"
+            android:id="@+id/content_slider"
+            android:layout_marginStart="@dimen/notification_panel_margin_left"
+            >
+        <FrameLayout
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:id="@+id/content_holder"
+                android:background="@drawable/heads_up_window_bg"
+                />
+    </FrameLayout>
+</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout/intruder_alert.xml b/packages/SystemUI/res/layout/intruder_alert.xml
deleted file mode 100644
index c4141ae..0000000
--- a/packages/SystemUI/res/layout/intruder_alert.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<!--    android:background="@drawable/status_bar_closed_default_background" -->
-<com.android.systemui.statusbar.policy.IntruderAlertView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:orientation="vertical"
-    >
-    <FrameLayout
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:id="@+id/contentHolder"
-        android:background="@drawable/intruder_window_bg"
-        />
-<!--    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:src="@drawable/title_bar_shadow"
-        android:scaleType="fitXY"
-        /> -->
-</com.android.systemui.statusbar.policy.IntruderAlertView>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 09923a7..aa365ae 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -23,7 +23,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    android:background="#FF000000"
+    android:background="@drawable/system_bar_background"
     >
 
     <FrameLayout android:id="@+id/rot0"
@@ -145,15 +145,32 @@
                 />
         </LinearLayout>
 
-        <com.android.systemui.statusbar.policy.KeyButtonView
-            android:layout_width="80dp"
-            android:id="@+id/search_light"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_horizontal"
-            android:src="@drawable/search_light"
-            android:scaleType="center"
-            android:visibility="gone"
-            />
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <com.android.systemui.statusbar.policy.KeyButtonView
+                android:layout_width="80dp"
+                android:id="@+id/search_light"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:src="@drawable/search_light"
+                android:scaleType="center"
+                android:visibility="gone"
+                android:contentDescription="@string/accessibility_search_light"
+                />
+
+            <com.android.systemui.statusbar.policy.KeyButtonView
+                android:id="@+id/camera_button"
+                android:layout_height="match_parent"
+                android:layout_width="80dp"
+                android:layout_gravity="center_vertical|right"
+                android:src="@drawable/ic_sysbar_camera"
+                android:scaleType="center"
+                android:visibility="gone"
+                android:contentDescription="@string/accessibility_camera_button"
+                />
+        </FrameLayout>
 
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
@@ -297,8 +314,11 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
+        <!-- No camera button in landscape mode -->
+
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
index c41e9b9..f3b894c 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
@@ -19,14 +19,14 @@
         android:layout_height="match_parent"
         android:layout_gravity="top"
         android:orientation="vertical">
-    <ImageView
+    <com.android.systemui.BatteryMeterView
             android:id="@+id/image"
             android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
             android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-            android:layout_width="@dimen/qs_tile_icon_size"
-            android:layout_height="@dimen/qs_tile_icon_size"
+            android:layout_width="22dp"
+            android:layout_height="32dp"
+            android:padding="3dp"
             android:layout_gravity="top|center_horizontal"
-            android:scaleType="centerInside"
             />
     <TextView
             style="@style/TextAppearance.QuickSettings.TileView"
@@ -36,4 +36,4 @@
             android:layout_gravity="top|center_horizontal"
             android:gravity="top|center_horizontal"
             />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml b/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
new file mode 100644
index 0000000..4fa48eb
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
@@ -0,0 +1,39 @@
+<?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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="top"
+    android:orientation="vertical">
+    <ImageView
+        android:id="@+id/image"
+        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
+        android:layout_marginBottom="@dimen/qs_cawarn_tile_margin_below_icon"
+        android:layout_width="@dimen/qs_tile_icon_size"
+        android:layout_height="@dimen/qs_tile_icon_size"
+        android:layout_gravity="top|center_horizontal"
+        android:scaleType="centerInside"
+        />
+    <TextView
+        style="@style/TextAppearance.QuickSettings.CaCertWarning"
+        android:id="@+id/text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top|center_horizontal"
+        android:gravity="top|center_horizontal"
+        />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
index 34506b1..6bf31e0 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
@@ -13,32 +13,49 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_gravity="top"
-    android:orientation="vertical">
+    android:layout_gravity="top">
     <FrameLayout
+        android:id="@+id/rssi_images"
         android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
         android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
         android:layout_width="@dimen/qs_tile_icon_size"
         android:layout_height="@dimen/qs_tile_icon_size"
         android:layout_gravity="top|center_horizontal"
+        android:layout_centerHorizontal="true"
         >
         <ImageView
             android:id="@+id/rssi_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
+            android:layout_centerInParent="true"
             />
         <ImageView
             android:id="@+id/rssi_overlay_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
+            android:layout_centerInParent="true"
             />
     </FrameLayout>
+    <ImageView
+            android:id="@+id/activity_in"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_qs_signal_in"
+            android:layout_toRightOf="@id/rssi_images"
+            android:layout_alignBottom="@id/rssi_images"
+            />
+    <ImageView
+            android:id="@+id/activity_out"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_qs_signal_out"
+            android:layout_toRightOf="@id/rssi_images"
+            android:layout_alignBottom="@id/rssi_images"
+            />
     <TextView
         style="@style/TextAppearance.QuickSettings.TileView"
         android:id="@+id/rssi_textview"
@@ -47,5 +64,8 @@
         android:layout_gravity="top|center_horizontal"
         android:gravity="top|center_horizontal"
         android:text="@string/quick_settings_rssi_label"
+        android:layout_centerHorizontal="true"
+        android:layout_below="@id/rssi_images"
+        android:textAllCaps="@bool/quick_settings_rssi_tile_capitalization"
         />
-</LinearLayout>
\ No newline at end of file
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
new file mode 100644
index 0000000..e61c595
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="top">
+    <ImageView
+        android:id="@+id/image"
+        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
+        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
+        android:layout_width="@dimen/qs_tile_icon_size"
+        android:layout_height="@dimen/qs_tile_icon_size"
+        android:layout_gravity="top|center_horizontal"
+        android:layout_centerHorizontal="true"
+        android:scaleType="centerInside"
+        />
+    <ImageView
+            android:id="@+id/activity_in"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_qs_wifi_in"
+            android:layout_toRightOf="@id/image"
+            android:layout_alignBottom="@id/image"
+            />
+    <ImageView
+            android:id="@+id/activity_out"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_qs_wifi_out"
+            android:layout_toRightOf="@id/image"
+            android:layout_alignBottom="@id/image"
+            />
+    <TextView
+        style="@style/TextAppearance.QuickSettings.TileView"
+        android:id="@+id/text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top|center_horizontal"
+        android:gravity="top|center_horizontal"
+        android:layout_centerHorizontal="true"
+        android:layout_below="@id/image" 
+        />
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index aab5083..2b9cef91 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -20,8 +20,9 @@
 
 <com.android.systemui.statusbar.SignalClusterView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
+    android:layout_height="match_parent"
     android:layout_width="wrap_content"
+    android:gravity="center"
     android:orientation="horizontal"
     >
     <FrameLayout
@@ -38,12 +39,6 @@
             android:layout_centerVertical="true"
             android:scaleType="center"
             />
-        <ImageView
-            android:id="@+id/wifi_inout"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:layout_gravity="center|bottom"
-            />
     </FrameLayout>
     <View
         android:layout_height="6dp"
@@ -65,12 +60,6 @@
             android:layout_centerVertical="true"
             android:scaleType="center"
             />
-        <ImageView
-            android:id="@+id/wimax_inout"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:layout_gravity="center|bottom"
-            />
     </FrameLayout>
     -->
     <FrameLayout
@@ -97,12 +86,6 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 />
-            <ImageView
-                android:id="@+id/mobile_inout"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:layout_gravity="end|bottom"
-                />
         </FrameLayout>
     </FrameLayout>
     <ImageView
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index b27536d..d7312df 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -23,7 +23,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/status_bar"
-    android:background="@drawable/status_bar_background"
+    android:background="@drawable/system_bar_background"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -95,11 +95,13 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     />
-                <ImageView
+                <!-- battery must be padded below by 2px to match assets -->
+                <com.android.systemui.BatteryMeterView
                     android:id="@+id/battery"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:paddingStart="4dip"
+                    android:layout_height="16dp"
+                    android:layout_width="10.5dp"
+                    android:layout_marginBottom="2px"
+                    android:layout_marginStart="4dip"
                     />
             </LinearLayout>
     
diff --git a/packages/SystemUI/res/layout/status_bar_help.xml b/packages/SystemUI/res/layout/status_bar_help.xml
deleted file mode 100644
index f638767..0000000
--- a/packages/SystemUI/res/layout/status_bar_help.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the combined status bar / notification panel window. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/status_bar_cling"
-    android:paddingStart="40dp"
-    android:paddingEnd="40dp"
-    android:background="#DD000000"
-    android:focusable="true"
-    android:orientation="vertical" 
-    android:gravity="top|start"
-    >
-
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="50dp"
-        android:gravity="center"
-        android:src="@drawable/arrow_dashed"
-        tools:ignore="ContentDescription" />
-
-    <TextView
-        style="@style/ClingTitleText"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/status_bar_help_title" />
-
-    <TextView
-        style="@style/ClingText"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="30dp"
-        android:text="@string/status_bar_help_text" />
-
-    <Button
-        android:id="@+id/ok"
-        style="@style/ClingButton"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingStart="50dp"
-        android:paddingEnd="50dp"
-        android:text="@android:string/ok" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_icon.xml b/packages/SystemUI/res/layout/status_bar_icon.xml
deleted file mode 100644
index 063212e..0000000
--- a/packages/SystemUI/res/layout/status_bar_icon.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<!-- The icons are a fixed size so an app can't mess everything up with bogus images -->
-<!-- TODO: the icons are hard coded to 25x25 pixels.  Their size should come from a theme -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
-    android:layout_width="25dp" 
-    android:layout_height="25dp"
-    >
-
-    <com.android.systemui.statusbar.AnimatedImageView android:id="@+id/image"
-        android:layout_width="match_parent" 
-        android:layout_height="match_parent"
-        />
-
-    <TextView android:id="@+id/number"
-        android:layout_width="wrap_content" 
-        android:layout_height="wrap_content"
-        android:layout_gravity="end|bottom"
-        android:layout_marginEnd="1dp"
-        android:layout_marginBottom="1dp"
-        android:textSize="10sp"
-        android:textColor="#ffffffff"
-        android:background="@drawable/ic_notification_overlay"
-        android:gravity="center"
-        android:textStyle="bold"
-        />
-
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 7a5ff3c..f827967 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,4 +1,5 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.ExpandableNotificationRow
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     >
@@ -62,4 +63,4 @@
         android:padding="2dp"
         />
 
-</FrameLayout>
+</com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/layout/system_bar.xml b/packages/SystemUI/res/layout/system_bar.xml
deleted file mode 100644
index 28c9dc0..0000000
--- a/packages/SystemUI/res/layout/system_bar.xml
+++ /dev/null
@@ -1,151 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<!-- TabletStatusBarView extends FrameLayout -->
-<com.android.systemui.statusbar.tablet.TabletStatusBarView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:background="@drawable/system_bar_background"
-    >
-    
-    <FrameLayout
-        android:id="@+id/bar_contents_holder"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_gravity="bottom"
-        >
-        <RelativeLayout
-            android:id="@+id/bar_contents"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:clipChildren="false"
-            >
-
-            <!-- notification icons & panel access -->
-            <include layout="@layout/system_bar_notification_area" 
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_alignParentEnd="true"
-                android:layout_marginTop="1dp"
-                />
-
-            <!-- navigation controls -->
-            <LinearLayout
-                android:id="@+id/navigationArea"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_alignParentStart="true"
-                android:orientation="horizontal"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                    android:layout_width="@dimen/navigation_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_back"
-                    systemui:keyCode="4"
-                    android:contentDescription="@string/accessibility_back"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                    />
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                    android:layout_width="@dimen/navigation_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_home"
-                    systemui:keyCode="3"
-                    android:contentDescription="@string/accessibility_home"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                    />
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                    android:layout_width="@dimen/navigation_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_recent"
-                    android:contentDescription="@string/accessibility_recent"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                    />
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_menu_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_menu"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                    />
-            </LinearLayout>
-
-            <!-- fake space bar zone -->
-            <com.android.systemui.statusbar.policy.EventHole android:id="@+id/fake_space_bar"
-                android:layout_height="match_parent"
-                android:layout_width="0dp"
-                android:paddingStart="8dip"
-                android:paddingEnd="8dip"
-                android:layout_toEndOf="@+id/navigationArea"
-                android:layout_toStartOf="@+id/notificationArea"
-                android:visibility="gone"
-                />
-        </RelativeLayout>
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/bar_shadow_holder"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_gravity="bottom"
-        >
-        <!-- lights out shade -->
-        <RelativeLayout
-            android:id="@+id/bar_shadow"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="#FF000000"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:id="@+id/dot0"
-                android:layout_width="80dip"
-                android:layout_height="48dip"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:layout_alignParentStart="true"
-                android:layout_alignParentBottom="true"
-                />
-            <ImageView
-                android:id="@+id/dot1"
-                android:layout_width="80dip"
-                android:layout_height="48dip"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:layout_toEndOf="@+id/dot0"
-                android:layout_alignParentBottom="true"
-                />
-            <ImageView
-                android:id="@+id/dot2"
-                android:layout_width="80dip"
-                android:layout_height="48dip"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:layout_toEndOf="@+id/dot1"
-                android:layout_alignParentBottom="true"
-                />
-            <ImageView
-                android:id="@+id/dot3"
-                android:layout_width="80dip"
-                android:layout_height="48dip"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:layout_alignParentEnd="true"
-                android:layout_alignParentBottom="true"
-                />
-        </RelativeLayout>
-    </FrameLayout>
-</com.android.systemui.statusbar.tablet.TabletStatusBarView>
diff --git a/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml b/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml
deleted file mode 100644
index 9ad9e05..0000000
--- a/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.statusbar.tablet.CompatModePanel
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:paddingBottom="@dimen/panel_float"
-    android:paddingEnd="20dp"
-    >
-    <RadioGroup android:id="@+id/compat_mode_radio_group"
-        android:background="@*android:drawable/dialog_full_holo_dark"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:orientation="vertical"
-        android:padding="10dp"
-        >
-        <RadioButton android:id="@+id/compat_mode_off_radio"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/compat_mode_off" />
-        <RadioButton android:id="@+id/compat_mode_on_radio"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/compat_mode_on" />
-    </RadioGroup>
-</com.android.systemui.statusbar.tablet.CompatModePanel>
diff --git a/packages/SystemUI/res/layout/system_bar_input_methods_item.xml b/packages/SystemUI/res/layout/system_bar_input_methods_item.xml
deleted file mode 100644
index 1a95ec1..0000000
--- a/packages/SystemUI/res/layout/system_bar_input_methods_item.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:background="@drawable/status_bar_item_background"
-    android:orientation="vertical"
-    android:paddingEnd="6dip"
-    android:paddingStart="6dip"
-    android:paddingTop="5dip"
-    android:paddingBottom="5dip"
-    android:gravity="center_vertical">
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:gravity="center_vertical"
-        android:orientation="horizontal">
-        <LinearLayout
-            android:id="@+id/item_subtype"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:background="?android:attr/selectableItemBackground">
-            <RadioButton
-                android:id="@+id/item_radio"
-                android:layout_width="30dip"
-                android:layout_height="wrap_content"
-                android:focusable="false"
-                android:clickable="false" />
-            <ImageView
-                android:id="@+id/item_icon"
-                android:layout_width="@android:dimen/app_icon_size"
-                android:layout_height="wrap_content"
-                android:scaleType="fitCenter"
-                android:contentDescription="@null" />
-            <LinearLayout
-                android:orientation="vertical"
-                android:layout_width="0px"
-                android:layout_weight="1"
-                android:layout_height="wrap_content">
-                <TextView
-                    android:id="@+id/item_title"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:textAppearance="?android:attr/textAppearanceMedium"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:layout_marginBottom="2dip" />
-                <TextView
-                    android:id="@+id/item_subtitle"
-                    android:layout_marginTop="-4dip"
-                    android:layout_gravity="center_vertical|start"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:textAppearance="?android:attr/textAppearanceSmall" />
-            </LinearLayout>
-        </LinearLayout>
-        <View
-            android:id="@+id/item_vertical_separator"
-            android:layout_width="2dip"
-            android:layout_height="match_parent"
-            android:layout_marginBottom="5dip"
-            android:background="@android:drawable/divider_horizontal_dark" />
-        <ImageView
-            android:id="@+id/item_settings_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginStart="5dip"
-            android:layout_gravity="center_vertical"
-            android:paddingEnd="10dip"
-            android:paddingStart="10dip"
-            android:src="@drawable/ic_sysbar_quicksettings"
-            android:visibility="visible"
-            android:clickable="true"
-            android:focusable="true"
-            android:background="?android:attr/selectableItemBackground"
-            android:contentDescription="@string/accessibility_settings_button" />
-    </LinearLayout>
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dip"
-        android:background="@android:drawable/divider_horizontal_dark" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml b/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml
deleted file mode 100644
index 547f937..0000000
--- a/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.statusbar.tablet.InputMethodsPanel
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:paddingBottom="7dip"
-    android:orientation="vertical"
-    android:visibility="gone">
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1" />
-    <FrameLayout
-        android:id="@+id/glow"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:background="@drawable/recents_blue_glow">
-        <LinearLayout
-            android:layout_width="450dip"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="20dip"
-            android:orientation="vertical"
-            android:background="@drawable/notify_panel_clock_bg">
-            <!-- Hard keyboard switch -->
-            <LinearLayout
-                android:id="@+id/hard_keyboard_section"
-                android:layout_height="wrap_content"
-                android:layout_width="match_parent"
-                android:orientation="vertical">
-                <LinearLayout
-                    android:layout_height="wrap_content"
-                    android:layout_width="match_parent"
-                    android:orientation="horizontal">
-                    <TextView
-                        android:id="@+id/use_physical_keyboard_label"
-                        android:layout_width="0dip"
-                        android:layout_height="wrap_content"
-                        android:layout_weight="1"
-                        android:minHeight="?android:attr/listPreferredItemHeight"
-                        android:background="?android:attr/selectableItemBackground"
-                        android:orientation="vertical"
-                        android:paddingEnd="6dip"
-                        android:paddingStart="30dip"
-                        android:paddingTop="5dip"
-                        android:paddingBottom="5dip"
-                        android:gravity="center_vertical"
-                        android:singleLine="true"
-                        android:text="@string/status_bar_use_physical_keyboard"
-                        android:textAppearance="?android:attr/textAppearanceMedium"
-                        android:ellipsize="marquee" />
-                    <Switch
-                        android:id="@+id/hard_keyboard_switch"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_gravity="center_vertical"
-                        android:layout_marginEnd="16dip" />
-                </LinearLayout>
-                <View
-                    android:layout_width="match_parent"
-                    android:layout_height="1dip"
-                    android:background="@android:drawable/divider_horizontal_dark" />
-            </LinearLayout>
-
-            <!-- Input method list -->
-            <ScrollView
-                android:layout_width="wrap_content"
-                android:layout_height="0dip"
-                android:overScrollMode="ifContentScrolls"
-                android:layout_marginTop="3dip"
-                android:layout_weight="1"
-                android:scrollbarAlwaysDrawVerticalTrack="true"
-                android:scrollbarDefaultDelayBeforeFade="75000">
-                <LinearLayout
-                    android:id="@+id/input_method_menu_list"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:orientation="vertical" />
-            </ScrollView>
-
-            <!-- Configure input methods -->
-            <TextView
-                android:id="@+id/ime_settings_shortcut"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:minHeight="?android:attr/listPreferredItemHeight"
-                android:background="?android:attr/selectableItemBackground"
-                android:orientation="vertical"
-                android:paddingEnd="6dip"
-                android:paddingStart="30dip"
-                android:paddingTop="5dip"
-                android:paddingBottom="5dip"
-                android:gravity="center_vertical"
-                android:singleLine="true"
-                android:text="@string/status_bar_input_method_settings_configure_input_methods"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:ellipsize="marquee" />
-        </LinearLayout>
-    </FrameLayout>
-</com.android.systemui.statusbar.tablet.InputMethodsPanel>
diff --git a/packages/SystemUI/res/layout/system_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/system_bar_no_recent_apps.xml
deleted file mode 100644
index c023ef7..0000000
--- a/packages/SystemUI/res/layout/system_bar_no_recent_apps.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** Copyright 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.
-*/
--->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    >
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="20dp"
-        android:textColor="@android:color/holo_blue_light"
-        android:text="@string/status_bar_no_recent_apps"
-        android:gravity="start"
-        android:layout_gravity="bottom|start"
-    />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_notification_area.xml b/packages/SystemUI/res/layout/system_bar_notification_area.xml
deleted file mode 100644
index 2fd91ef..0000000
--- a/packages/SystemUI/res/layout/system_bar_notification_area.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<!-- notification icons & panel access -->
-<com.android.systemui.statusbar.tablet.NotificationArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:id="@+id/notificationArea"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
-    android:layout_alignParentEnd="true"
-    android:orientation="horizontal"
-    android:background="?android:attr/listChoiceBackgroundIndicator"
-    android:clickable="true"
-    >
-
-    <LinearLayout
-        android:id="@+id/feedbackIconArea"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:orientation="horizontal"
-        >
-
-        <com.android.systemui.statusbar.tablet.InputMethodButton
-            android:id="@+id/imeSwitchButton"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginStart="8dip"
-            android:src="@drawable/ic_sysbar_ime_default"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_ime_switch_button"
-            />
-
-        <com.android.systemui.statusbar.policy.CompatModeButton
-            android:id="@+id/compatModeButton"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginStart="8dip"
-            android:src="@drawable/ic_sysbar_zoom"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_compatibility_zoom_button"
-            />
-
-        <com.android.systemui.statusbar.tablet.NotificationIconArea
-            android:id="@+id/notificationIcons"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            >
-            <view
-                class="com.android.systemui.statusbar.tablet.NotificationIconArea$IconLayout"
-                android:id="@+id/icons"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_gravity="center_vertical"
-                android:layout_marginStart="8dp"
-                android:alpha="0.4"
-                />
-        </com.android.systemui.statusbar.tablet.NotificationIconArea>
-    </LinearLayout>
-
-    <LinearLayout
-        android:id="@+id/notificationTrigger"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:gravity="center"
-        >
-        <com.android.systemui.statusbar.policy.Clock
-            android:id="@+id/clock"
-            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:singleLine="true"
-            android:paddingStart="6dip"
-            android:layout_marginEnd="8dip"
-            android:gravity="center_vertical|start"
-            />
-
-        <TextView
-            android:id="@+id/network_text"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginEnd="6dip"
-            android:layout_marginStart="6dip"
-            android:gravity="center"
-            android:singleLine="true"
-            android:visibility="gone"
-            android:textSize="16sp"
-            android:textColor="#606060"
-            />
-
-        <LinearLayout
-            android:id="@+id/signal_battery_cluster"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginEnd="16dp"
-            android:orientation="horizontal"
-            android:gravity="center"
-            >
-            <include layout="@layout/signal_cluster_view" 
-                android:id="@+id/signal_cluster"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                />
-            <ImageView
-                android:id="@+id/bluetooth"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:paddingStart="4dip"
-                android:visibility="gone"
-                />
-            <ImageView
-                android:id="@+id/battery"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:paddingStart="4dip"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</com.android.systemui.statusbar.tablet.NotificationArea>
diff --git a/packages/SystemUI/res/layout/system_bar_notification_panel.xml b/packages/SystemUI/res/layout/system_bar_notification_panel.xml
deleted file mode 100644
index 58a6de3..0000000
--- a/packages/SystemUI/res/layout/system_bar_notification_panel.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<!--
-  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.
--->
-
-<!--    android:background="@drawable/system_bar_closed_default_background" -->
-<com.android.systemui.statusbar.tablet.NotificationPanel
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:id="@+id/content_parent"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:gravity="end"
-    >
-
-    <!-- lift the panel up off the status bar while leaving a touchable are -->
-    <Space
-        android:id="@+id/system_bar_notification_panel_bottom_space"
-        android:layout_height="56dp"
-        android:layout_width="478dp"
-        android:layout_alignParentEnd="true"
-        android:layout_alignParentBottom="true"
-        />
-
-    <LinearLayout
-        android:id="@+id/content_frame"
-        android:background="@drawable/notification_panel_bg"
-        android:layout_height="wrap_content"
-        android:layout_width="478dp"
-        android:orientation="vertical"
-        android:layout_alignParentEnd="true"
-        android:layout_above="@id/system_bar_notification_panel_bottom_space"
-        android:paddingBottom="8dp"
-        >
-
-        <include layout="@layout/system_bar_notification_panel_title"
-            android:layout_width="match_parent"
-            android:layout_height="130dp"
-            android:layout_above="@id/content_frame"
-            android:layout_alignParentEnd="true"
-            android:layout_weight="0"
-            />
-
-        <ScrollView
-
-            android:id="@+id/notification_scroller"
-            android:layout_height="wrap_content"
-            android:layout_width="match_parent"
-            android:overScrollMode="ifContentScrolls"
-            android:layout_weight="1"
-            >
-            <com.android.systemui.statusbar.policy.NotificationRowLayout
-                android:id="@+id/content"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="center_horizontal|bottom"
-                android:clickable="true"
-                android:focusable="true"
-                android:descendantFocusability="afterDescendants"
-                systemui:rowHeight="@dimen/notification_row_min_height"
-                />
-        </ScrollView>
-    </LinearLayout>
-</com.android.systemui.statusbar.tablet.NotificationPanel>
diff --git a/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml b/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
deleted file mode 100644
index d08fbce..0000000
--- a/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
+++ /dev/null
@@ -1,231 +0,0 @@
-<!--
-  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.
--->
-
-<com.android.systemui.statusbar.tablet.NotificationPanelTitle
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:id="@+id/title_area"
-    android:background="@drawable/system_bar_notification_header_bg"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:clickable="true"
-    android:orientation="vertical"
-    android:paddingStart="26dp"
-    android:paddingTop="14dp"
-    android:paddingEnd="26dp"
-    >
-
-    <TableLayout
-        android:id="@+id/icons"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentBottom="true"
-        android:layout_marginTop="16dp"
-        android:layout_marginBottom="16dp"
-        android:shrinkColumns="2,4"
-        android:stretchColumns="7"
-        >
-        <TableRow>
-
-            <!-- to keep the column ids stable we wrap disappearing views in
-                 frames -->
-            <FrameLayout
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:layout_gravity="center_vertical"
-                >
-                <ImageView
-                    android:id="@+id/bluetooth"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:paddingEnd="16dp"
-                    android:visibility="gone"
-                    android:contentDescription="@null"
-                    android:layout_gravity="center_vertical"
-                    />
-            </FrameLayout>
-
-            <!-- mobile data -->
-            <FrameLayout
-                android:id="@+id/mobile_icon"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:paddingEnd="6dp"
-                >
-
-                <ImageView
-                    android:id="@+id/mobile_signal"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:contentDescription="@null"
-                    />
-
-                <ImageView
-                    android:id="@+id/mobile_type"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:contentDescription="@null"
-                    />
-
-            </FrameLayout>
-            <TextView
-                android:id="@+id/mobile_text"
-                style="@style/SystemBarNotificationText"
-                android:layout_gravity="start|center_vertical"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingEnd="12dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:text="@string/status_bar_settings_settings_button"
-                />
-
-            <!-- wifi -->
-            <FrameLayout
-                android:id="@+id/wifi_icon"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:paddingEnd="6dp"
-                >
-
-                <ImageView
-                    android:id="@+id/wifi_signal"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:contentDescription="@null"
-                    />
-
-                <ImageView
-                    android:id="@+id/wifi_direction"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:contentDescription="@null"
-                    />
-
-            </FrameLayout>
-            <TextView
-                android:id="@+id/wifi_text"
-                style="@style/SystemBarNotificationText"
-                android:layout_gravity="start|center_vertical"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingEnd="12dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:text="@string/status_bar_settings_settings_button"
-                />
-
-            <ImageView
-                android:id="@+id/battery"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:scaleType="centerInside"
-                android:layout_gravity="center_vertical"
-                android:layout_alignBaseline="@id/wifi_signal"
-                android:paddingEnd="6dp"
-                android:contentDescription="@null"
-                />
-
-            <TextView
-                android:id="@+id/battery_text"
-                style="@style/SystemBarNotificationText"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingEnd="2dp"
-                android:singleLine="true"
-                android:text="@string/status_bar_settings_settings_button"
-                />
-
-            <!-- this will stretch to eat up available space -->
-            <View
-                android:layout_width="0dp"
-                android:layout_height="0dp"
-                />
-
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                >
-
-                <ImageView
-                    android:id="@+id/settings_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:src="@drawable/ic_sysbar_quicksettings"
-                    android:contentDescription="@string/accessibility_desc_quick_settings"
-                    />
-
-                <ImageView
-                    android:id="@+id/notification_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:src="@drawable/ic_notification_open"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_notifications_button"
-                    />
-            </FrameLayout>
-
-        </TableRow>
-    </TableLayout>
-
-    <LinearLayout
-        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="wrap_content"
-        android:paddingTop="@dimen/notification_panel_header_padding_top"
-        android:orientation="horizontal"
-        android:gravity="center_vertical"
-        android:baselineAligned="false"
-        >
-
-        <com.android.systemui.statusbar.policy.Clock
-            android:id="@+id/clock"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:textAppearance="@style/TextAppearance.SystemBar.Expanded.Clock"
-            />
-    
-        <com.android.systemui.statusbar.policy.DateView
-            android:id="@+id/date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:textAppearance="@style/TextAppearance.SystemBar.Expanded.Date"
-            />
-
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="48dp"
-            android:layout_weight="1"
-            />
-
-        <ImageView android:id="@+id/clear_all_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:scaleType="center"
-            android:src="@drawable/ic_notify_clear"
-            android:contentDescription="@string/accessibility_clear_all"
-            />
-    </LinearLayout>
-</com.android.systemui.statusbar.tablet.NotificationPanelTitle>
diff --git a/packages/SystemUI/res/layout/system_bar_notification_peek.xml b/packages/SystemUI/res/layout/system_bar_notification_peek.xml
deleted file mode 100644
index 3cff47b..0000000
--- a/packages/SystemUI/res/layout/system_bar_notification_peek.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<!--    android:background="@drawable/system_bar_closed_default_background" -->
-<com.android.systemui.statusbar.tablet.NotificationPeekPanel
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:background="@*android:drawable/dialog_full_holo_dark"
-    android:orientation="vertical"
-    >
-
-    <FrameLayout 
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal|bottom"
-        android:animationCache="false"
-        android:orientation="vertical"
-        android:background="@drawable/system_bar_background"
-        android:clickable="true"
-        android:focusable="true"
-        android:descendantFocusability="afterDescendants"
-        >
-    </FrameLayout>
-</com.android.systemui.statusbar.tablet.NotificationPeekPanel>
diff --git a/packages/SystemUI/res/layout/system_bar_pocket_panel.xml b/packages/SystemUI/res/layout/system_bar_pocket_panel.xml
deleted file mode 100644
index e4a6da4..0000000
--- a/packages/SystemUI/res/layout/system_bar_pocket_panel.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:background="@*android:drawable/dialog_full_holo_dark"
-    >
-    <TextView
-        android:id="@+id/description"
-        android:textAppearance="@android:style/TextAppearance.Small"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:textStyle="bold"
-        android:maxLines="1"
-        android:layout_alignParentBottom="true"
-        />
-
-    <FrameLayout
-        android:id="@+id/preview"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:layout_above="@+id/description"
-        android:descendantFocusability="blocksDescendants"
-        >
-        <ImageView
-            android:id="@+id/icon"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:scaleType="centerInside"
-            android:visibility="gone"
-            />
-        <TextView
-            android:id="@+id/alt"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:textAppearance="@android:style/TextAppearance.Large"
-            android:gravity="center"
-            android:visibility="gone"
-            />
-    </FrameLayout>
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_recent_item.xml b/packages/SystemUI/res/layout/system_bar_recent_item.xml
deleted file mode 100644
index 34f60b2..0000000
--- a/packages/SystemUI/res/layout/system_bar_recent_item.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<RelativeLayout android:id="@+id/recent_item"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="wrap_content">
-
-    <TextView android:id="@+id/app_label"
-        android:layout_width="@dimen/status_bar_recents_app_label_width"
-        android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_label_text_size"
-        android:fadingEdge="horizontal"
-        android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
-        android:scrollHorizontally="true"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-        android:layout_marginTop="32dip"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textColor="@color/status_bar_recents_app_label_color"
-        android:importantForAccessibility="no"
-    />
-
-    <FrameLayout android:id="@+id/app_thumbnail"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_toEndOf="@id/app_label"
-        android:layout_marginStart="@dimen/status_bar_recents_thumbnail_left_margin"
-        android:scaleType="center"
-        android:background="@drawable/recents_thumbnail_bg"
-        android:foreground="@drawable/recents_thumbnail_fg"
-        android:visibility="invisible">
-        <ImageView android:id="@+id/app_thumbnail_image"
-            android:layout_width="@dimen/status_bar_recents_thumbnail_width"
-            android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-        />
-    </FrameLayout>
-
-
-    <ImageView android:id="@+id/app_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_toEndOf="@id/app_label"
-        android:layout_marginStart="@dimen/status_bar_recents_app_icon_left_margin"
-        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-        android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
-        android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
-        android:scaleType="centerInside"
-        android:adjustViewBounds="true"
-        android:visibility="invisible"
-    />
-
-
-    <View android:id="@+id/recents_callout_line"
-        android:layout_width="@dimen/status_bar_recents_app_label_width"
-        android:layout_height="1dip"
-        android:layout_below="@id/app_label"
-        android:layout_marginTop="3dip"
-        android:layout_alignParentStart="true"
-        android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-        android:layout_toStartOf="@id/app_thumbnail"
-        android:layout_marginEnd="3dip"
-        android:background="@drawable/recents_callout_line"
-    />
-
-    <TextView android:id="@+id/app_description"
-        android:layout_width="@dimen/status_bar_recents_app_label_width"
-        android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_description_text_size"
-        android:fadingEdge="horizontal"
-        android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
-        android:scrollHorizontally="true"
-        android:layout_alignParentStart="true"
-        android:layout_below="@id/recents_callout_line"
-        android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-        android:layout_marginTop="3dip"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-    />
-
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
deleted file mode 100644
index 3d15d9b..0000000
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.systemui.recent.RecentsPanelView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:id="@+id/recents_root"
-    android:layout_height="match_parent"
-    android:layout_width="wrap_content"
-    android:clipToPadding="false"
-    android:clipChildren="false"
-    systemui:recentItemLayout="@layout/system_bar_recent_item"
-    >
-    <FrameLayout
-        android:id="@+id/recents_bg_protect"
-        android:background="@drawable/recents_bg_protect_tile"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_alignParentBottom="true"
-        android:layout_marginBottom="@*android:dimen/system_bar_height"
-        android:clipToPadding="false"
-        android:clipChildren="false">
-
-        <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="@dimen/status_bar_recents_right_glow_margin"
-            android:divider="@null"
-            android:stackFromBottom="true"
-            android:fadingEdge="vertical"
-            android:scrollbars="none"
-            android:fadingEdgeLength="20dip"
-            android:layout_gravity="bottom|start"
-            android:clipToPadding="false"
-            android:clipChildren="false"
-            android:fitsSystemWindows="true">
-
-            <LinearLayout android:id="@+id/recents_linear_layout"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:orientation="vertical"
-                android:clipToPadding="false"
-                android:clipChildren="false">
-            </LinearLayout>
-
-        </com.android.systemui.recent.RecentsVerticalScrollView>
-
-        <include layout="@layout/system_bar_no_recent_apps"
-            android:id="@+id/recents_no_apps"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginStart="58dip"
-            android:layout_marginBottom="36dip"
-            android:visibility="invisible" />
-
-    </FrameLayout>
-
-    <com.android.systemui.recent.StatusBarTouchProxy
-        android:id="@+id/status_bar_touch_proxy"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentStart="true"
-    />
-
-
-</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel_footer.xml b/packages/SystemUI/res/layout/system_bar_recent_panel_footer.xml
deleted file mode 100644
index 4d14d1f..0000000
--- a/packages/SystemUI/res/layout/system_bar_recent_panel_footer.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** Copyright 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.
-*/
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/listview_footer_padding"
-    android:layout_height="24dip"
-    android:layout_width="match_parent">
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_settings_view.xml b/packages/SystemUI/res/layout/system_bar_settings_view.xml
deleted file mode 100644
index 4987dd9..0000000
--- a/packages/SystemUI/res/layout/system_bar_settings_view.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<com.android.systemui.statusbar.tablet.SettingsView
-        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="wrap_content"
-        android:orientation="vertical"
-        >
-
-    <!-- Airplane mode -->
-    <LinearLayout
-            android:id="@+id/airplane"
-            style="@style/SystemBarPanelSettingsRow"
-            >
-        <ImageView
-                android:id="@+id/airplane_icon"
-                style="@style/SystemBarPanelSettingsIcon"
-                android:src="@drawable/ic_sysbar_airplane_on"
-                />
-        <TextView
-                android:id="@+id/airplane_label"
-                style="@style/SystemBarPanelSettingsContents"
-                android:text="@string/status_bar_settings_airplane"
-                />
-        <Switch
-                android:id="@+id/airplane_checkbox"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginEnd="5dp"
-                />
-    </LinearLayout>
-    <View style="@style/SystemBarPanelSettingsPanelSeparator" />
-
-    <!-- Network -->
-    <LinearLayout
-            android:id="@+id/network"
-            style="@style/SystemBarPanelSettingsRow"
-            >
-        <ImageView
-                android:id="@+id/network_icon"
-                style="@style/SystemBarPanelSettingsIcon"
-                android:src="@drawable/ic_sysbar_wifi_on"
-                />
-        <TextView
-                android:id="@+id/network_label"
-                style="@style/SystemBarPanelSettingsContents"
-                android:text="@string/status_bar_settings_wifi_button"
-                />
-    </LinearLayout>
-    <View style="@style/SystemBarPanelSettingsPanelSeparator" />
-
-    <!-- Rotation lock -->
-    <LinearLayout
-            android:id="@+id/rotate"
-            style="@style/SystemBarPanelSettingsRow"
-            >
-        <ImageView
-                android:id="@+id/rotate_icon"
-                style="@style/SystemBarPanelSettingsIcon"
-                android:src="@drawable/ic_sysbar_rotate_on"
-                />
-        <TextView
-                android:id="@+id/rotate_label"
-                style="@style/SystemBarPanelSettingsContents"
-                android:text="@string/status_bar_settings_auto_rotation"
-                />
-        <Switch
-                android:id="@+id/rotate_checkbox"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginEnd="5dp"
-                />
-    </LinearLayout>
-    <View
-            android:id="@+id/rotate_separator"
-            style="@style/SystemBarPanelSettingsPanelSeparator" />
-
-    <!-- Brightness -->
-    <LinearLayout style="@style/SystemBarPanelSettingsRow" >
-        <ImageView
-                android:id="@+id/brightness_icon"
-                style="@style/SystemBarPanelSettingsIcon"
-                android:src="@drawable/ic_sysbar_brightness"
-                />
-        <com.android.systemui.settings.ToggleSlider
-                android:id="@+id/brightness"
-                android:layout_width="0dp"
-                android:layout_height="fill_parent"
-                android:layout_weight="1"
-                android:layout_marginEnd="2dp"
-                systemui:text="@string/status_bar_settings_auto_brightness_label"
-                />
-    </LinearLayout>
-    <View style="@style/SystemBarPanelSettingsPanelSeparator" />
-
-    <!-- Notifications / Do not disturb -->
-    <LinearLayout
-            android:id="@+id/do_not_disturb"
-            style="@style/SystemBarPanelSettingsRow"
-            >
-        <ImageView
-                android:id="@+id/do_not_disturb_icon"
-                style="@style/SystemBarPanelSettingsIcon"
-                android:src="@drawable/ic_notification_open"
-                />
-        <TextView
-                style="@style/SystemBarPanelSettingsContents"
-                android:text="@string/status_bar_settings_notifications"
-                />
-        <Switch
-                android:id="@+id/do_not_disturb_checkbox"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginEnd="5dp"
-                />
-    </LinearLayout>
-    <View style="@style/SystemBarPanelSettingsPanelSeparator" />
-
-    <!-- Link to settings -->
-    <LinearLayout
-            android:id="@+id/settings"
-            style="@style/SystemBarPanelSettingsRow"
-            >
-
-        <ImageView
-                android:id="@+id/settings"
-                style="@style/SystemBarPanelSettingsIcon"
-                android:src="@drawable/ic_sysbar_quicksettings"
-                />
-        <TextView
-                style="@style/SystemBarPanelSettingsContents"
-                android:text="@string/status_bar_settings_settings_button"
-                />
-    </LinearLayout>
-    <View style="@style/SystemBarPanelSettingsPanelSeparator" />
-
-</com.android.systemui.statusbar.tablet.SettingsView>
-
diff --git a/packages/SystemUI/res/layout/system_bar_ticker_compat.xml b/packages/SystemUI/res/layout/system_bar_ticker_compat.xml
deleted file mode 100644
index 14cdc40..0000000
--- a/packages/SystemUI/res/layout/system_bar_ticker_compat.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal"
-    android:gravity="bottom"
-    >
-
-    <ImageView
-        android:id="@+id/large_icon"
-        android:layout_width="@android:dimen/notification_large_icon_width"
-        android:layout_height="@android:dimen/notification_large_icon_height"
-        android:scaleType="center"
-        android:visibility="gone"
-        />
-
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_weight="1"
-        android:background="@drawable/system_bar_ticker_background"
-        >
-        
-        <ImageView android:id="@+id/left_icon"
-            android:layout_width="64dp"
-            android:layout_height="match_parent"
-            android:scaleType="center"
-            android:visibility="gone"
-            />
-
-        <TextView android:id="@+id/text"
-            android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_vertical"
-            android:layout_marginStart="12dp"
-            android:gravity="center_vertical"
-            android:maxLines="2"
-            />
-
-        <ImageView android:id="@+id/right_icon"
-            android:layout_width="64dp"
-            android:layout_height="match_parent"
-            android:scaleType="center"
-            android:visibility="gone"
-            />
-
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_ticker_panel.xml b/packages/SystemUI/res/layout/system_bar_ticker_panel.xml
deleted file mode 100644
index 49d0405..0000000
--- a/packages/SystemUI/res/layout/system_bar_ticker_panel.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-
-    <View
-        android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_width="match_parent"
-        android:background="@drawable/system_bar_ticker_background"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentBottom="true"
-        android:clickable="false"
-        />
-
-    <ImageView
-        android:id="@+id/large_icon"
-        android:layout_width="@android:dimen/notification_large_icon_height"
-        android:layout_height="@android:dimen/notification_large_icon_width"
-        android:scaleType="center"
-        android:visibility="gone"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentBottom="true"
-        />
-
-    <FrameLayout
-        android:id="@+id/ticker_expanded"
-        android:layout_weight="1"
-        android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_width="match_parent"
-        android:layout_toEndOf="@id/large_icon"
-        android:layout_alignParentBottom="true"
-        android:layout_alignWithParentIfMissing="true"
-        />
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/universe.xml b/packages/SystemUI/res/layout/universe.xml
deleted file mode 100644
index 390c467..0000000
--- a/packages/SystemUI/res/layout/universe.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent" android:layout_height="match_parent">
-    <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
-        android:layout_centerHorizontal="true" android:layout_alignParentTop="true"
-        android:src="@drawable/bugdroid" android:scaleType="center" />
-
-    <Button android:id="@+id/close"
-        android:layout_width="wrap_content" android:layout_height="wrap_content"
-        android:layout_alignParentTop="true" android:layout_alignParentEnd="true"
-        android:text="@string/close_universe" />
-
-    <TextView android:id="@+id/title"
-        android:layout_width="match_parent" android:layout_height="wrap_content"
-        android:layout_below="@id/close" android:layout_centerHorizontal="true"
-        android:paddingBottom="16dp"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:gravity="center" />
-
-    <ImageView android:id="@+id/bottom"
-        android:layout_width="wrap_content" android:layout_height="wrap_content"
-        android:layout_below="@id/title" android:layout_centerHorizontal="true"
-        android:layout_marginTop="16dp" />
-</RelativeLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 60d6edc..9ddf42a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Stelsel-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Maak skoon"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Moenie steur nie"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Wys kennisgewings"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Verwyder uit lys"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Program Info"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Geen onlangse programme nie"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> oor"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie."\n"Gebruik net die laaier wat verskaf is."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Gebruik by verstek vir hierdie USB-toestel"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gebruik by verstek vir hierdie USB-toebehoorsel"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Laat USB-ontfouting toe?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Die rekenaar se RSA-sleutel-vingerafdruk is:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Die rekenaar se RSA-sleutel-vingerafdruk is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Laat altyd toe van hierdie rekenaar af"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoem om skerm te vul"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Strek om skerm te vul"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data gedeaktiveer"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobieldata gedeaktiveer"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data gedeaktiveer"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Jy het die gespesifiseerde data-gebruikslimiet bereik."\n\n"As jy data weer heraktiveer, kan jy deur jou diensverskaffer gehef word."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Jy het die gespesifiseerde data-gebruikslimiet bereik.\n\nAs jy data weer heraktiveer, kan jy deur jou diensverskaffer gehef word."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Heraktiveer data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ligging deur GPS gestel"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Verwyder alle kennisgewings."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Programinligting"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Maak toe"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Kennisgewings af"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tik hier om kennisgewings weer aan te skakel."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Die skerm sal outomaties draai."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skerm is in landskapsoriëntasie gesluit."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skerm is in portretoriëntasie gesluit."</string>
@@ -187,7 +182,10 @@
     <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_ime_label" msgid="7073463064369468429">"Invoermetode"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Ligging in gebruik"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Mediatoestel"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Net noodoproepe"</string>
@@ -203,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Kennisgewings verskyn hier"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Verkry enige tyd toegang tot hulle deur af te sleep."\n"Sleep weer af vir stelselkontroles."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Verkry enige tyd toegang tot hulle deur af te sleep.\nSleep weer af vir stelselkontroles."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Sleep rand van skerm om balk te wys"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Sleep van rand van skerm af om stelselbalk te wys"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 600ad6f..1d81ea7 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"የስርዓት UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"አጥራ"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"አይረብሹ"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"ማሳወቂያዎች አሳይ"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"ከዝርዝር አስወግድ"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"የትግበራ መረጃ"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"ምንም የቅርብ ጊዜ ትግበራዎች የሉም"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"የኃይል መሙያ አገናኝ።"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"ባትሪው እያነሰ ነው።"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ቀሪ"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።"\n" የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።\n የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
     <string name="battery_low_why" msgid="7279169609518386372">"የባትሪ ጥቅም"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ቅንብሮች"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"ለእዚህ USB  መሣሪያ በነባሪነት ተጠቀም"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"ለእዚህ USB  ተቀጥላ በነባሪነት ተጠቀም"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"የUSB ማረሚያ ይፈቀድ?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"የኮምፒውተሩ RSA ቁልፍ ጣት አሻራ ይሄ ነው፦"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"የኮምፒውተሩ RSA ቁልፍ ጣት አሻራ ይሄ ነው፦\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"ሁልጊዜ ከዚህ ኮምፒውተር ፍቀድ"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"ማያ እንዲሞላ አጉላ"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"ማያ ለመሙለት ሳብ"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"የተንቀሳቃሽ ውሂብ ቦዝኗል"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"ውሂብ ቦዝኗል"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"የተቀመጠውን የውሂብ አጠቃቀም ገደብ ላይ ደርሰሃል:: "\n\n"ውሂብን እንደገና መልሰህ ዳግም-ካነቃህ በከዋኙ ክፍያ ልትጠየቅበት ትችል ይሆናል::"</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"የተቀመጠውን የውሂብ አጠቃቀም ገደብ ላይ ደርሰሃል:: \n\nውሂብን እንደገና መልሰህ ዳግም-ካነቃህ በከዋኙ ክፍያ ልትጠየቅበት ትችል ይሆናል::"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"ውሂብ ድጋሚ አንቃ"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"የመተግበሪያ መረጃ"</string>
-    <string name="close_universe" msgid="3736513750241754348">"ዝጋ"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"ማሳወቂያዎች ጠፍተዋል"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"ማስታወቅያዎችን መልሶ ለማብራት እዚህ ጋር መታ አድርግ።"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ማያ ገጽ በራስ ሰር ይዞራል።"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ማያ ገጽ በወርድ ገፅ አቀማመጥ ተቆልፏል።"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ማያ ገጽ በቁም ገፅ አቀማመጥ ተቆልፏል።"</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ራስ-አዙር"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"አዙሪት ተቆልፏል"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"የግቤት ስልት"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"በስራ ላይ ያለው አካባቢ"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"አካባቢ"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"አካባቢ ጠፍቷል"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"የሚዲያ መሣሪያ"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"የአደጋ ጊዜ ጥሪዎች ብቻ"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"ማሳወቂያዎች እዚህ ላይ ይታያሉ"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"ወደ ታች በማንሸራተት በማንኛውም ጊዜ ይድረሱባቸው።"\n"Swipe የስርዓት መቆጣጠሪያዎችን ለማምጣት እንደገና ወደ ታች ያንሸራትቱ።"</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"ወደ ታች በማንሸራተት በማንኛውም ጊዜ ይድረሱባቸው።\nSwipe የስርዓት መቆጣጠሪያዎችን ለማምጣት እንደገና ወደ ታች ያንሸራትቱ።"</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"አሞሌውን ለማሳየት የማያ ገጹን ጠርዝ ላይ ያንሸራትቱ"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"አሞሌውን ለማሳየት ከማያ ገጹ ጠርዝ ጀምረው ያንሸራትቱ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 44dcac1..c31d6d9 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"واجهة مستخدم النظام"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"محو"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"عدم الإزعاج"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"إظهار التنبيهات"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"إزالة من القائمة"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"معلومات التطبيق"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"ليس هناك تطبيقات حديثة"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"توصيل الشاحن"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"انخفضت طاقة البطارية."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"المتبقي: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"شحن USB غير معتمد."\n"استخدم الشاحن الموفر فقط."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"استخدام البطارية"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"الإعدادات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"الاستخدام بشكل افتراضي لجهاز USB هذا"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"الاستخدام بشكل افتراضي لملحق USB هذا"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"هل تريد السماح بتصحيح أخطاء USB؟"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"الملف المرجعي الرئيسي لـ RSA في هذا الكمبيوتر هو:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"الملف المرجعي الرئيسي لـ RSA في هذا الكمبيوتر هو:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"السماح دائمًا من هذا الكمبيوتر"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"تكبير/تصغير لملء الشاشة"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"توسيع بملء الشاشة"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"تم تعطيل بيانات شبكة الجيل الرابع"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"تم تعطيل بيانات الجوال"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"تم تعطيل البيانات"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"لقد وصلت إلى حد استخدام البيانات المحدد. "\n" "\n" إذا أعدت تمكين البيانات ، فقد يتم تحصيل رسوم منك من قبل مشغل شبكة الجوال."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"لقد وصلت إلى حد استخدام البيانات المحدد. \n \n إذا أعدت تمكين البيانات ، فقد يتم تحصيل رسوم منك من قبل مشغل شبكة الجوال."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"إعادة تمكين البيانات"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"تم تعيين الموقع بواسطة GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"محو جميع الإشعارات."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"معلومات التطبيق"</string>
-    <string name="close_universe" msgid="3736513750241754348">"إغلاق"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"التنبيهات معطّلة"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"انقر هنا لإعادة تشغيل الإشعارات."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"سيتم تدوير الشاشة تلقائيًا."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"تم تأمين الشاشة في الاتجاه الأفقي."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"تم تأمين الشاشة في الاتجاه العمودي."</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"تدوير تلقائي"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"تم قفل التدوير"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"أسلوب الإدخال"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"الموقع المستخدم"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"الموقع"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"الموقع قيد الإيقاف"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"جهاز الوسائط"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"مكالمات طوارئ فقط"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"تظهر الإشعارات هنا"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"يمكنك الدخول إليها في أي وقت بالتمرير السريع إلى أسفل."\n"يمكنك التمرير السريع إلى أسفل مرة أخرى للوصول إلى عناصر تحكم النظام."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"يمكنك الدخول إليها في أي وقت بالتمرير السريع إلى أسفل.\nيمكنك التمرير السريع إلى أسفل مرة أخرى للوصول إلى عناصر تحكم النظام."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"مرر سريعًا لحافة الشاشة لإظهار الشريط"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"مرر سريعًا من حافة الشاشة لإظهار شريط النظام"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index d66e946..6608b79 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Інтэрфейс карыстальніка сістэмы"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ачысціць"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Не турбаваць"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Паказваць паведамленні"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Выдаліць са спісу"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Звесткі аб прыкладанні"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Апошніх прыкладанняў няма"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Падлучыце зарадную прыладу."</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Зарад батарэі становіцца нізкім."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Спроб засталося: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB-зарадка не падтрымліваецца."\n"Карыстайцеся толькі зарадкай для прылады."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB-зарадка не падтрымліваецца.\nКарыстайцеся толькі зарадкай для прылады."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Выкарыстанне батарэі"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налады"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Выкарыстоўваць налады па змаўчанні для дадзенай USB-прылады"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Выкарыстоўваць налады па змаўчанні для дадзенай USB-прылады"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Дазволіць адладку USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Адбiтак ключа RSA на гэтым камп\'ютары:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Адбiтак ключа RSA на гэтым камп\'ютары:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Заўсёды дазваляць з гэтага камп\'ютара"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Павял. на ўвесь экран"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Расцягн. на ўвесь экран"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Дадзеныя 4G адключаныя"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мабільная перадача дадзеных адключаная"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Дадзеныя адключаныя"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Вы перавысiлi ўсталяваны лiмiт на выкарыстанне. "\n\n"Калі вы паўторна ўключыце перадачу дадзеных, можа спаганяцца плата."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Вы перавысiлi ўсталяваны лiмiт на выкарыстанне. \n\nКалі вы паўторна ўключыце перадачу дадзеных, можа спаганяцца плата."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Паўторна ўключыць дадзеныя"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Інфармацыя пра прыкладанне"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Закрыць"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Паведамленні адключаны"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Націсніце тут, каб зноў уключыць апавяшчэнні."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран паварочваецца аўтаматычна."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Экран заблакiраваны ў альбомнай арыентацыі."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Экран заблакiраваны ў партрэтнай арыентацыі."</string>
@@ -189,7 +184,10 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Аўтапаварот"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Паварот забаронены"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Метад уводу"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Месцазнаходжанне выкарыстоўваецца"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Мультымедыйная прылада"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Толькі экстраныя выклікі"</string>
@@ -205,5 +203,9 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркасць"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Апавяшчэнні з\'яўляюцца тут"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Атрымлівайце доступ да іх у любы час, праводзячы пальцам уніз."\n"Правядзіце пальцам уніз яшчэ раз, каб атрымаць доступ да сродкаў кіравання сістэмай."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Атрымлівайце доступ да іх у любы час, праводзячы пальцам уніз.\nПравядзіце пальцам уніз яшчэ раз, каб атрымаць доступ да сродкаў кіравання сістэмай."</string>
+    <!-- no translation found for hideybar_confirmation_message (9050869548951044371) -->
+    <skip />
+    <!-- no translation found for hideybar_confirmation_message_long (7117692795163620626) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index d7094af..6194fd8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Системен ПИ"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Изчистване"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Не ме безпокойте"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Показване на известията"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Премахване от списъка"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Информация за приложението"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Няма скорошни приложения"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Включете зарядното устройство"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерията се изтощава."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB."\n"Използвайте само доставеното зарядно устройство."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB.\nИзползвайте само доставеното зарядно устройство."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Използване на батерията"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Използване по подразб. за това USB устройство"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Използване по подразб. за този аксесоар за USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Да се разреши ли отстраняването на грешки през USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Отпечатъкът на RSA ключа на компютъра е:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Отпечатъкът на RSA ключа на компютъра е:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Винаги да се разрешава от този компютър"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Мащаб – запълва екрана"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Разпъване – запълва екрана"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G данните са деактивирани"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобилните данни са деактивирани"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Трафикът на данни е деактивиран"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнахте определеното ограничение за използване на данни."\n\n"Ако ги активирате отново, е възможно да бъдете таксувани от оператора."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнахте определеното ограничение за използване на данни.\n\nАко ги активирате отново, е възможно да бъдете таксувани от оператора."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Активиране на данните отново"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Информация за приложението"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Затваряне"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Известията са изключени"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Докоснете тук, за да включите отново известията."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранът ще се завърта автоматично."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екранът е заключен в хоризонтална ориентация."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екранът е заключен във вертикална ориентация."</string>
@@ -187,7 +182,10 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автоматична ориентация"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Ориентацията е заключена"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Метод на въвеждане"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Използвано местоположение"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Мултимедийно устройство"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"Индикатор за силата на получения сигнал (RSSI)"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Само спешни обаждания"</string>
@@ -203,5 +201,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Известията се показват тук"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Осъществявайте достъп до тях по всяко време, като прекарате пръст надолу."\n"Направете го отново за системните контроли."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Осъществявайте достъп до тях по всяко време, като прекарате пръст надолу.\nНаправете го отново за системните контроли."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Прекарайте пръст по ръба на екрана, за да се покаже лентата"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Прекарайте пръст от ръба на екрана, за да се покаже системната лента"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a8d1e7b..eddeda3 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"IU del sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Esborra"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molesteu"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostra notificacions"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Elimina de la llista"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informació de l\'aplicació"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"No hi ha aplicacions recents"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Càrrega d\'USB no admesa."\n"Utilitza només el carregador proporcionat."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuració"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Utilitza de manera predet. per al dispositiu USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utilitza de manera predet. per a l\'accessori USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vols permetre la depuració USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"L\'empremta digital de la clau de l\'RSA de l\'equip és:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"L\'empremta digital de la clau de l\'RSA de l\'equip és:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Dóna sempre permís des d\'aquest equip"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom per omplir pantalla"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Estira per omplir pant."</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dades 4G desactivades"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dades mòbils desactivades"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dades desactivades"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Has arribat al límit especificat d\'utilització de dades."\n\n"Si has reactivat les dades, és possible que l\'operador et faci algun càrrec."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Has arribat al límit especificat d\'utilització de dades.\n\nSi has reactivat les dades, és possible que l\'operador et faci algun càrrec."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Torna a activar les dades"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informació de l\'aplicació"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Tanca"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notificacions desactivades"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Pica aquí per tornar a activar les notificacions."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girarà automàticament."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla està bloquejada en orientació horitzontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla està bloquejada en orientació vertical."</string>
@@ -189,7 +184,8 @@
     <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_ime_label" msgid="7073463064369468429">"Mètode d\'entrada"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Ubicació en ús"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Ubicació"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Ubicació desactivada"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositiu multimèdia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Només trucades d\'emergència"</string>
@@ -205,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Les notificacions apareixen aquí"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Accedeix-hi en qualsevol moment: només has de fer lliscar el dit cap avall."\n"Torna a fer lliscar el dit cap avall per fer que es mostrin els controls del sistema."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Accedeix-hi en qualsevol moment: només has de fer lliscar el dit cap avall.\nTorna a fer lliscar el dit cap avall per fer que es mostrin els controls del sistema."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Fes lliscar el dit per la vora de la pantalla perquè es mostri la barra"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Fes lliscar el dit des de la vora de la pantalla perquè es mostri la barra del sistema"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 86f069f..87ba67a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI systému"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Vymazat"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Nerušit"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Zobrazit upozornění"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Odebrat ze seznamu"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informace o aplikaci"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Žádné nové aplikace"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Nabíjení pomocí rozhraní USB není podporováno."\n"Používejte pouze nabíječku, která byla dodána se zařízením."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavení"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Pro toto zařízení USB použít jako výchozí"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Pro toto periferní zařízení USB použít jako výchozí"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Povolit ladění USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Digitální otisk RSA počítače je:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Digitální otisk RSA počítače je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Vždy povolit z tohoto počítače"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Přiblížit na celou obrazovku"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Na celou obrazovku"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datové přenosy 4G jsou zakázány"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilní data jsou zakázána"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Přenos dat vypnut"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosáhli jste stanoveného limitu využití dat."\n\n"Chcete-li datové připojení znovu zapnout, operátor vám může účtovat poplatky."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosáhli jste stanoveného limitu využití dat.\n\nChcete-li datové připojení znovu zapnout, operátor vám může účtovat poplatky."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Znovu povolit data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavena pomocí systému GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazat všechna oznámení."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informace o aplikaci"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Zavřít"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Oznámení jsou vypnuta"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Chcete-li oznámení znovu zapnout, klepněte sem."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka se automaticky otočí."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Obrazovka je uzamčena v orientaci na šířku."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Obrazovka je uzamčena v orientaci na výšku."</string>
@@ -189,7 +184,10 @@
     <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_ime_label" msgid="7073463064369468429">"Metoda zadávání dat"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Používaná poloha"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Mediální zařízení"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Pouze tísňová volání"</string>
@@ -205,5 +203,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Zde se zobrazují oznámení"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Můžete je kdykoli zobrazit tím, že přejedete prstem dolů."\n"Přejedete-li prstem dolů ještě jednou, zobrazí se ovládací prvky systému."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Můžete je kdykoli zobrazit tím, že přejedete prstem dolů.\nPřejedete-li prstem dolů ještě jednou, zobrazí se ovládací prvky systému."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Panel zobrazíte přejetím přes okraj obrazovky"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Systémový panel zobrazíte přejetím přes okraj obrazovky"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1bfe7c5..af4bb33 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"System-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ryd"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Forstyr ikke"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Vis meddelelser"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Fjern fra listen"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Oplysninger om appen"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Der er ingen seneste apps"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke."\n"Brug kun den medfølgende oplader."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Indstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Brug som standard til denne USB-enhed"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Brug som standard til dette USB-tilbehør"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vil du tillade USB-fejlretning?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Fingeraftrykket for computerens RSA-nøgle er:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Fingeraftrykket for computerens RSA-nøgle er:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Tillad altid fra denne computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom til fuld skærm"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Stræk til fuld skærm"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-data er deaktiveret"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobildata er deaktiveret"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Du har nået den angivne grænse for dataforbruget."\n\n"Hvis du genaktiverer data, kan dit mobilselskab opkræve ekstra."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Du har nået den angivne grænse for dataforbruget.\n\nHvis du genaktiverer data, kan dit mobilselskab opkræve ekstra."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Genaktiver data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle meddelelser."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Oplysninger om appen"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Luk"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Underretninger slået fra"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tryk her for at slå underretninger til igen."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skærmen er nu låst i stående retning."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Inputmetode"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Placering i brug"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Placering"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Placering fra"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medieenhed"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Kun nødopkald"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Underretninger vises her"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Få adgang til dem når som helst ved at stryge ned."\n"Stryg ned igen for at komme til systemindstillingerne."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Få adgang til dem når som helst ved at stryge ned.\nStryg ned igen for at komme til systemindstillingerne."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Stryg kanten af skærmen for at se bjælken"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Stryg fra skærmens kant for at se systembjælken"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index cb073d2..ec52ede 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"System-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Löschen"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Bitte nicht stören"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Benachrichtigungen zeigen"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Aus Liste entfernen"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App-Info"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Keine kürzlich geöffneten Apps"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt."\n"Verwenden Sie das mitgelieferte Aufladegerät."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Einstellungen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Standardmäßig für dieses USB-Gerät verwenden"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Standardmäßig für dieses USB-Zubehör verwenden"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB-Debugging zulassen?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Der Fingerabdruck des RSA-Schlüssels für diesen Computer lautet: "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Der Fingerabdruck des RSA-Schlüssels für diesen Computer lautet: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Von diesem Computer immer zulassen"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom auf Bildschirmgröße"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Auf Bildschirmgröße anpassen"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-Daten deaktiviert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilfunk Daten deaktiviert"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Sie haben die angegebenen Grenze für den Datenverbrauch erreicht."\n\n"Wenn Sie die Datennutzung erneut aktivieren, berechnet Ihr Mobilfunkanbieter unter Umständen zusätzliche Gebühren."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Sie haben die angegebenen Grenze für den Datenverbrauch erreicht.\n\nWenn Sie die Datennutzung erneut aktivieren, berechnet Ihr Mobilfunkanbieter unter Umständen zusätzliche Gebühren."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut aktivieren"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"App-Details"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Schließen"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Benachrichtigungen aus"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tippen Sie hier, um die Benachrichtigungen wieder zu aktivieren."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Bildschirm wird automatisch gedreht."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildschirm bleibt im Querformat."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildschirm bleibt im Hochformat."</string>
@@ -189,7 +184,10 @@
     <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_ime_label" msgid="7073463064369468429">"Eingabemethode"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Verwendeter Standort"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Mediengerät"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Nur Notrufe"</string>
@@ -205,5 +203,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Benachrichtigungen erscheinen hier"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Greifen Sie jederzeit auf sie zu, indem Sie nach unten wischen."\n"Wischen Sie für Systemeinstellungen erneut nach unten."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Greifen Sie jederzeit auf sie zu, indem Sie nach unten wischen.\nWischen Sie für Systemeinstellungen erneut nach unten."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Zum Einblenden der Leiste vom Rand wischen"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Zum Einblenden der Systemleiste vom Display-Rand weg wischen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 9baeb37..ab43081 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI συστήματ."</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Εκκαθάριση"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Μην ενοχλείτε"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Εμφάνιση ειδοποιήσεων"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Κατάργηση από τη λίστα"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Πληροφορίες εφαρμογής"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Δεν υπάρχουν πρόσφατες εφαρμογές"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Συνδέστε φορτιστή"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Η στάθμη της μπαταρίας είναι χαμηλή."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB."\n"Χρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB.\nΧρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ρυθμίσεις"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Χρήση από προεπιλογή για αυτή τη συσκευή USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Χρήση από προεπιλογή για αυτό το εξάρτημα USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB;"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Το μοναδικό χαρακτηριστικό του κλειδιού RSA είναι:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Το μοναδικό χαρακτηριστικό του κλειδιού RSA είναι:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Να επιτρέπεται πάντα από αυτόν τον υπολογιστή"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Ζουμ σε πλήρη οθόνη"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Προβoλή σε πλήρη οθ."</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Τα δεδομένα 4G απενεργοποιήθηκαν"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Τα δεδομένα κινητής τηλεφωνίας απενεργοποιήθηκαν"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Απενεργοποιήθηκαν τα δεδομένα"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Συμπληρώσατε το καθορισμένο όριο χρήσης δεδομένων."\n\n"Αν ενεργοποιήσετε ξανά τα δεδομένα, ενδέχεται να χρεωθείτε από την εταιρεία κινητής τηλεφωνίας."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Συμπληρώσατε το καθορισμένο όριο χρήσης δεδομένων.\n\nΑν ενεργοποιήσετε ξανά τα δεδομένα, ενδέχεται να χρεωθείτε από την εταιρεία κινητής τηλεφωνίας."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Νέα ενεργοποίηση δεδομένων"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Πληροφορίες εφαρμογής"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Κλείσιμο"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Ειδοποιήσεις ανενεργές"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Πατήστε εδώ για να ενεργοποιήσετε ξανά τις ειδοποιήσεις."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Θα γίνεται αυτόματη περιστροφή της οθόνης."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Η οθόνη έχει κλειδωθεί σε οριζόντιο προσανατολισμό."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Η οθόνη έχει κλειδωθεί σε κατακόρυφο προσανατολισμό."</string>
@@ -189,7 +184,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Αυτόματη περιστροφή"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Η περιστροφή είναι κλειδωμένη"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Μέθοδος εισαγωγής"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Τοποθεσία σε χρήση"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Τοποθεσία"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Τοποθεσία απενεργοποιημένη"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Συσκευή μέσων"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Μόνο κλήσεις έκτακτης ανάγκης"</string>
@@ -205,5 +201,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Οι ειδοποιήσεις εμφανίζονται εδώ"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Μεταβείτε σε αυτές ανά πάσα στιγμή σύροντας προς τα κάτω."\n"Σύρετε ξανά προς τα κάτω για τα στοιχεία ελέγχου συστήματος."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Μεταβείτε σε αυτές ανά πάσα στιγμή σύροντας προς τα κάτω.\nΣύρετε ξανά προς τα κάτω για τα στοιχεία ελέγχου συστήματος."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή συστήματος"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index deb7d09..6027553f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"System UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Clear"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Do not disturb"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Show notifications"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Remove from list"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App info"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"No recent apps"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported."\n"Use only the supplied charger."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Allow USB debugging?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Always allow from this computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Stretch to fill screen"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data disabled"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobile data disabled"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data disabled"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"You\'ve reached the specified data usage limit."\n\n"If you re-enable data, you may be charged by the operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"You\'ve reached the specified data usage limit.\n\nIf you re-enable data, you may be charged by the operator."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Reenable data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"App info"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Close"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notifications off"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tap here to turn notifications back on."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Screen will rotate automatically."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Screen is locked in landscape orientation."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Screen is locked in portrait orientation."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Input Method"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Location in use"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Location"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Location Off"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Media device"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Emergency Calls Only"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Notifications appear here"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Access them any time by swiping down."\n"Swipe down again for system controls."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Access them any time by swiping down.\nSwipe down again for system controls."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Swipe edge of screen to reveal bar"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Swipe from edge of screen to reveal system bar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 7306469..62f6c20 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"IU del sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Eliminar"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminar de la lista"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información de la aplicación"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Ninguna aplicación reciente"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Quedan <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB."\n"Usa sólo el cargador provisto."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Se usa de forma predeterminada para este dispositivo USB."</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Se usa de forma predeterminada para este accesorio USB."</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"¿Permitir depuración por USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"La huella digital de tu clave RSA es:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"La huella digital de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Permitir siempre desde esta computadora"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ocupar la pantalla"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Estirar p/ ocupar la pantalla"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datos de 4G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Se inhabilitaron los datos móviles"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Datos inhabilitados"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Alcanzaste el límite de uso de datos especificado."\n\n"Puede que tu operador te cobre por volver a activar datos."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Alcanzaste el límite de uso de datos especificado.\n\nPuede que tu operador te cobre por volver a activar datos."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Volver a activar datos"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Información de la aplicación"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Cerrar"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notificaciones desactivadas"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Toca aquí para volver a activar las notificaciones."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
@@ -189,7 +184,10 @@
     <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_ime_label" msgid="7073463064369468429">"Método de introducción"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Ubicación en uso"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimedia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Solo emergencia"</string>
@@ -205,5 +203,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí."</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido."\n"Vuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido.\nVuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Desliza el dedo desde el borde de la pantalla para mostrar la barra."</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Desliza el dedo desde el borde de la pantalla para mostrar la barra del sistema."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 6e5be0a..64c3cab 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"IU sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminar de la lista"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información de la aplicación"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"No hay aplicaciones recientes."</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB."\n"Utiliza solo el cargador proporcionado."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Usar de forma predeterminada para este dispositivo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Usar de forma predeterminada para este accesorio USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"¿Permitir depuración USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"La huella digital de tu clave RSA es:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"La huella digital de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Permitir siempre desde este ordenador"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ajustar"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Expandir para ajustar"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datos 4G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Datos móviles inhabilitados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Datos inhabilitados"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Has alcanzado el límite de uso de datos especificado."\n\n"Si vuelves a habilitar los datos, es posible que tu operador te cobre una tarifa adicional."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Has alcanzado el límite de uso de datos especificado.\n\nSi vuelves a habilitar los datos, es posible que tu operador te cobre una tarifa adicional."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Volver a habilitar los datos"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ubicación definida por GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Información de la aplicación"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Cerrar"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notificaciones desactivadas"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Toca aquí para volver a activar las notificaciones."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Método de entrada"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Ubicación en uso"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimedia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Solo llamadas de emergencia"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido."\n"Vuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido.\nVuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Desliza el borde de la pantalla para mostrar la barra"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Desliza el borde de la pantalla para mostrar la barra del sistema"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5737645..6d9c838 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Süsteemi UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Kustuta"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Mitte häirida"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Kuva teatised"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Loendist eemaldamine"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Rakenduse teave"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Uusi rakendusi pole"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> on alles"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB laadimist ei toetata."\n"Kasutage ainult tootja laadija."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Seaded"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Kasuta vaikimisi selle USB-seadme jaoks"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Vaikimisi kasuta seda USB-lisaseadet"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Kas luban USB silumise?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Arvuti RSA-võtme sõrmejälg:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Arvuti RSA-võtme sõrmejälg:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Luba alati sellest arvutist"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Suumi ekraani täitmiseks"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Venita ekraani täitmiseks"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G andmeside keelatud"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobiilne andmeside keelatud"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Andmekasutus keelatud."</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Olete jõudnud määratud andmekasutuse piirini."\n\n"Kui lülitate andmeside uuesti sisse, siis võib operaator teilt tasu võtta."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Olete jõudnud määratud andmekasutuse piirini.\n\nKui lülitate andmeside uuesti sisse, siis võib operaator teilt tasu võtta."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Luba andmeside uuesti"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Kustuta kõik teatised."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Rakenduse teave"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Sule"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Teatised väljas"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Teatiste uuesti sisselülitamiseks puudutage siin."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekraani pööramine toimub automaatselt."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekraan on lukustatud horisontaalsuunas."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekraan on lukustatud vertikaalsuunas."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Sisestusmeetod"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Kasutatav asukoht"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Meediaseade"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Ainult hädaabikõned"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Märguanded ilmuvad siia"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Juurdepääs igal ajal sõrmega alla pühkides."\n"Süsteemi juhtnuppude jaoks pühkige uuesti alla."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Juurdepääs igal ajal sõrmega alla pühkides.\nSüsteemi juhtnuppude jaoks pühkige uuesti alla."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Riba kuvamiseks pühkige ekraani serva"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Süsteemiriba kuvamiseks pühkige ekraani servast"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b15afcc..b095519 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"رابط کاربر سیستم"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"پاک کردن"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"مزاحم نشوید"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"نمایش اعلان‌ها"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"حذف از لیست"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"اطلاعات برنامه"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"برنامه جدیدی موجود نیست"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"شارژر را متصل کنید"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"باتری در حال کم شدن است."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> باقیمانده است"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"شارژ USB پشتیبانی نمی‌شود."\n"فقط از شارژر ارائه شده استفاده کنید."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"شارژ USB پشتیبانی نمی‌شود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"استفاده از باتری"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"استفاده به صورت پیش‌فرض برای این دستگاه USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"استفاده به صورت پیش‌فرض برای این دستگاه USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"اجازه به اشکال‌زدایی USB؟"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"اثر انگشت کلید RSA رایانه: "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"اثر انگشت کلید RSA رایانه: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"همیشه از این رایانه انجام شود"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"بزرگنمایی برای پر کردن صفحه"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"داده 4G غیر فعال شد"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"داده‌های تلفن همراه غیرفعال است"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"داده غیرفعال شد"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"به حداکثر محدوده مشخص شده برای استفاده از داده رسیده‌اید."\n\n"در صورت فعال کردن مجدد داده، ممکن است از طرف اپراتور برای شما هزینه محاسبه شود."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"به حداکثر محدوده مشخص شده برای استفاده از داده رسیده‌اید.\n\nدر صورت فعال کردن مجدد داده، ممکن است از طرف اپراتور برای شما هزینه محاسبه شود."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"فعال کردن مجدد داده"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی وجود ندارد"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل شد"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"مکان تنظیم شده توسط GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"پاک کردن تمام اعلان‌ها"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"اطلاعات برنامه"</string>
-    <string name="close_universe" msgid="3736513750241754348">"بستن"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"اعلان‌ها خاموش"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"برای روشن کردن مجدد اعلان‌ها، اینجا را ضربه بزنید."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار می‌چرخد."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در جهت افقی قفل است."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"صفحه اکنون در جهت عمودی قفل است."</string>
@@ -187,7 +182,10 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"چرخش خودکار"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"چرخش قفل شد"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"روش ورودی"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"موقعیت مکانی در حال استفاده"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"دستگاه رسانه"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"فقط تماس‌های اضطراری"</string>
@@ -203,5 +201,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"اعلان‌ها در اینجا نمایش داده می‌شوند"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"با کشیدن انگشت به طرف پایین به آنها دسترسی پیدا کنید."\n"برای کنترل‌های سیستم دوباره انگشت خود را به سمت پایین بکشید."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"با کشیدن انگشت به طرف پایین به آنها دسترسی پیدا کنید.\nبرای کنترل‌های سیستم دوباره انگشت خود را به سمت پایین بکشید."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"برای نمایش نوار، انگشت خود را از لبه‌ صفحه به داخل بکشید"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"برای نمایش نوار سیستم، انگشت خود را از لبه‌ صفحه به داخل بکشید"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index c5e0e21..06e1926 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Käyttöliitt."</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Tyhjennä"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Varattu"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Näytä ilmoitukset"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Poista luettelosta"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Sovelluksen tiedot"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Ei viimeisimpiä sovelluksia"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB-latausta ei tueta."\n"Käytä laitteen mukana tullutta laturia."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Asetukset"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Käytä oletuksena tällä USB-laitteella"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Käytä oletuksena tällä USB-lisälaitteella"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Sallitaanko USB-vianetsintä?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Tietokoneen RSA-avaintunnistetiedosto on:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Tietokoneen RSA-avaintunnistetiedosto on:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Salli aina tällä tietokoneella"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoomaa koko näyttöön"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Venytä koko näyttöön"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-tiedonsiirto pois käytöstä"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobiilitiedonsiirto pois käytöstä"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Tiedonsiirto pois käytöstä"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Tiedonsiirtoraja saavutettu."\n\n"Jos otat tiedonsiirron uudelleen käyttöön, operaattorisi voi veloittaa sinua."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Tiedonsiirtoraja saavutettu.\n\nJos otat tiedonsiirron uudelleen käyttöön, operaattorisi voi veloittaa sinua."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Ota tiedonsiirto käyttöön"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wifi yhdistetty"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Sijainti määritetty GPS:n avulla"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Tyhjennä kaikki ilmoitukset."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Sovelluksen tiedot"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Sulje"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Ilmoitukset pois käytöstä"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Ota ilmoitukset uudelleen käyttöön napauttamalla tätä."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ruutu kääntyy automaattisesti."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ruutu on lukittu vaakasuuntaan."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ruutu on lukittu pystysuuntaan."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Syöttötapa"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Sijainti käytössä"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medialaite"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Vain hätäpuhelut"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Ilmoitukset näkyvät tässä"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Näet ilmoitukset liu\'uttamalla sormea alas ruudulla."\n"Voit palauttaa järjestelmän ohjaimet näkyviin liu\'uttamalla sormea alas uudelleen."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Näet ilmoitukset liu\'uttamalla sormea alas ruudulla.\nVoit palauttaa järjestelmän ohjaimet näkyviin liu\'uttamalla sormea alas uudelleen."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Tuo palkki näkyviin liu\'uttamalla ruudun reunasta"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Tuo järjestelmäpalkki näkyviin liu\'uttamalla ruudun reunasta"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 616adf5..7db07e2 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"IU système"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ne pas déranger"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Afficher les notifications"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Supprimer de la liste"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informations sur l\'application"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Aucune application récente."</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non disponible."\n"Vous devez utiliser le chargeur fourni."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Utiliser par défaut pour ce périphérique USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Autoriser le débogage USB ?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Empreinte numérique de la clé RSA de l\'ordinateur : "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Empreinte numérique de la clé RSA de l\'ordinateur : \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Toujours autoriser sur cet ordinateur"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoomer pour remplir l\'écran"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Étirer pour remplir l\'écran"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Données 4G désactivées"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Données mobiles désactivées"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Vous avez atteint le plafond de consommation de données spécifié."\n\n"Si vous utilisez des données supplémentaires, celles-ci pourront être facturées par l\'opérateur."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Vous avez atteint le plafond de consommation de données spécifié.\n\nSi vous utilisez des données supplémentaires, celles-ci pourront être facturées par l\'opérateur."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Réactiver connexion données"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informations sur l\'application"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Fermer"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notifications désactivées"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Appuyez ici pour réactiver les notifications."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"L\'écran est verrouillé en mode paysage."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"L\'écran est verrouillé en mode portrait."</string>
@@ -189,7 +184,10 @@
     <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_ime_label" msgid="7073463064369468429">"Mode de saisie"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Utilisation des données de localisation"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Appareil multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Appels d\'urgence uniquement"</string>
@@ -205,5 +203,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Les notifications s’affichent ici"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Accédez-y à tout moment en faisant glisser le doigt vers le bas."\n"Répétez l\'opération pour accéder aux commandes du système."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Accédez-y à tout moment en faisant glisser le doigt vers le bas.\nRépétez l\'opération pour accéder aux commandes du système."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Faites glisser votre doigt sur le côté de l\'écran pour afficher la barre."</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Faites glisser votre doigt à partir d\'un côté de l\'écran pour afficher la barre système."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0342e18..862e2ef 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"सिस्‍टम UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"साफ़ करें"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"परेशान न करें"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"सूचनाएं दिखाएं"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"सूची से निकालें"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"एप्‍लिकेशन जानकारी"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"कोई हाल ही के एप्लिकेशन नहीं"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"चार्जर कनेक्‍ट करें"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"बैटरी कम हो रही है."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है."\n"केवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है.\nकेवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"बैटरी उपयोग"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"इस USB उपकरण के लिए डिफ़ॉल्‍ट रूप से उपयोग करें"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"इस USB एसेसरी के लिए डिफ़ॉल्‍ट रूप से उपयोग करें"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB डीबगिंग करने दें?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"कंप्यूटर का RSA कुंजी फ़िंगरप्रिंट है:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"कंप्यूटर का RSA कुंजी फ़िंगरप्रिंट है:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"इस कंप्यूटर से हमेशा अनुमति दें"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"स्‍क्रीन भरने हेतु ज़ूम करें"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"स्‍क्रीन को भरने के लिए खींचें"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G डेटा अक्षम"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"मोबाइल डेटा अक्षम"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"डेटा अक्षम"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"आप निर्दिष्ट डेटा उपयोग सीमा तक पहुंच चुके हैं."\n\n"यदि आप डेटा को पुनः सक्षम करते हैं, तो ऑपरेटर द्वारा आपसे शुल्क लिया जा सकता है."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"आप निर्दिष्ट डेटा उपयोग सीमा तक पहुंच चुके हैं.\n\nयदि आप डेटा को पुनः सक्षम करते हैं, तो ऑपरेटर द्वारा आपसे शुल्क लिया जा सकता है."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"डेटा पुन: सक्षम करें"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi कनेक्‍ट किया गया"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा सेट किया गया स्‍थान"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"सभी सूचनाएं साफ़ करें."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"एप्‍लिकेशन जानकारी"</string>
-    <string name="close_universe" msgid="3736513750241754348">"बंद करें"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"सूचनाएं बंद"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"सूचनाओं को पुन: चालू करने के लिए यहां टैप करें."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्‍क्रीन स्‍वचालित रूप से घूमेगी."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्‍क्रीन लैंडस्केप अभिविन्यास में लॉक है."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्‍क्रीन पोर्ट्रेट अभिविन्‍यास में लॉक है."</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"स्वत: रोटेट"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"रोटेशन लॉक किया गया"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"इनपुट विधि"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"उपयोग हो रहा स्थान"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"स्थान"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"स्थान बंद"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"मीडिया उपकरण"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"केवल आपातकालीन कॉल"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"चमक"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"सूचनाएं यहां दिखाई देती हैं"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"नीचे स्वाइप करके उन तक कभी भी पहुंचें."\n"सिस्टम नियंत्रणों के लिए पुन: नीचे स्वाइप करें."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"नीचे स्वाइप करके उन तक कभी भी पहुंचें.\nसिस्टम नियंत्रणों के लिए पुन: नीचे स्वाइप करें."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"बार दिखाने के लिए स्क्रीन के किनारे को स्वाइप करें"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"सिस्टम बार दिखाने के लिए स्क्रीन के किनारे से स्वाइप करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index c35b237..631d549 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI sustava"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Očisti"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ne uznemiravaj"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Prikaži obavijesti"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Ukloni s popisa"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informacije o aplikaciji"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nema nedavnih aplikacija"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano."\n"Upotrijebite samo priloženi punjač."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Koristi se prema zadanim postavkama za ovaj USB uređaj"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Koristi se prema zadanim postavkama za ovaj USB pribor"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Omogućiti rješavanje programske pogreške na USB-u?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Otisak prsta RSA ključa računala je: "\n" <xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Otisak prsta RSA ključa računala je: \n <xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Uvijek dopusti s ovog računala"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj i ispuni zaslon"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rastegni i ispuni zaslon"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Onemogućeni su 4G podaci"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Onemogućeni su mobilni podaci"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Podaci su onemogućeni"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosegnuli ste navedeno ograničenje upotrebe podataka."\n\n"Ako ponovo omogućite podatke, operator će vam to možda dodatno naplatiti."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosegnuli ste navedeno ograničenje upotrebe podataka.\n\nAko ponovo omogućite podatke, operator će vam to možda dodatno naplatiti."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Ponovo omogući podatke"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju utvrdio GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Brisanje svih obavijesti."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informacije o aplikaciji"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Zatvori"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Obavijesti isključene"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Dotaknite ovdje da biste ponovo uključili obavijesti."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon će se automatski zakrenuti."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaključan u pejzažnoj orijentaciji."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaključan u portretnoj orijentaciji."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Način unosa"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Lokacija u uporabi"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medijski uređaj"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Samo hitni pozivi"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Obavijesti se prikazuju ovdje"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Pristupite im u bilo kojem trenutku tako da prstom trznete prema dolje. "\n"Ponovo prstom trznite prema dolje za kontrole sustava."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Pristupite im u bilo kojem trenutku tako da prstom trznete prema dolje. \nPonovo prstom trznite prema dolje za kontrole sustava."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Prijeđite prstom po rubu zaslona da bi se prikazala traka"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Prijeđite prstom od ruba zaslona da bi se prikazala traka sustava"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index b71cc78..c1c9136 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Rendszer UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Törlés"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ne zavarjanak"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Értesítések megjelenítése"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eltávolítás a listából"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Alkalmazásinformáció"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nincs újabb alkalmazás"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Az USB-n keresztüli töltés nincs támogatva."\n"Használja a kapott töltőt."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Beállítások"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Alapértelmezett használat ehhez az USB-eszközhöz"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Alapértelmezett használat ehhez az USB-kiegészítőhöz"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Engedélyezi az USB hibakeresést?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"A számítógép RSA kulcs ujjlenyomata:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"A számítógép RSA kulcs ujjlenyomata:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Mindig engedélyezze erről a számítógépről"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Nagyítás a kitöltéshez"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Nyújtás kitöltéshez"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G adatforgalom letiltva"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobil adatforgalom letiltva"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Adatok letiltva"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Elérte a megadott adathasználati korlátot."\n\n"Ha újra engedélyezi az adatforgalmat, szolgáltatója díjat számolhat fel."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Elérte a megadott adathasználati korlátot.\n\nHa újra engedélyezi az adatforgalmat, szolgáltatója díjat számolhat fel."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Adatforgalom engedélyezése"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"A GPS beállította a helyet"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Minden értesítés törlése"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Alkalmazásinformáció"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Bezárás"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Értesítések kikapcsolva"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Itt érintse meg az értesítések bekapcsolásához."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A képernyő automatikusan forogni fog."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A képernyő zárolva van fekvő tájolásban."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A képernyő zárolva van álló tájolásban."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Beviteli módszer"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Használatban lévő hely"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Médiaeszköz"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Csak segélyhívások"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Az értesítések itt jelennek meg."</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Bármikor elérheti őket, ha lefelé húzza az ujját."\n"Húzza le az ujját még egyszer a rendszerbeállítások eléréséhez."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Bármikor elérheti őket, ha lefelé húzza az ujját.\nHúzza le az ujját még egyszer a rendszerbeállítások eléréséhez."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Csúsztassa ujját a képernyő szélén a sáv megjelenítéséhez"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Csúsztassa ujját a képernyő szélétől a rendszersáv megjelenítéséhez"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2c26b0d..6a702b9 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sistem UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Bersihkan"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Jangan ganggu"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Tampilkan pemberitahuan"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Hapus dari daftar"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info apl"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Tidak ada apl terbaru"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tersisa"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Pengisian daya USB tidak didukung."\n"Gunakan hanya pengisi daya yang disediakan."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Setelan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara default untuk perangkat USB ini"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara default untuk aksesori USB ini"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Izinkan debugging USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Sidik jari kunci RSA komputer adalah:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Sidik jari kunci RSA komputer adalah:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Selalu izinkan dari komputer ini"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Perbesar utk mengisi layar"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rentangkn utk mngisi layar"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data 4G dinonaktifkan"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Data seluler dinonaktifkan"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data dinonaktifkan"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Anda telah mencapai batas penggunaan data yang ditentukan."\n\n"Jika Anda mengaktifkan ulang data, Anda mungkin akan dikenai biaya oleh operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Anda telah mencapai batas penggunaan data yang ditentukan.\n\nJika Anda mengaktifkan ulang data, Anda mungkin akan dikenai biaya oleh operator."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Aktifkan ulang data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info aplikasi"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Tutup"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Pemberitahuan mati"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Ketuk di sini untuk menyalakan pemberitahuan lagi."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Layar dikunci dalam orientasi lanskap."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Layar dikunci dalam orientasi potret."</string>
@@ -187,7 +182,10 @@
     <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_ime_label" msgid="7073463064369468429">"Metode Masukan"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Lokasi penggunaan"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Perangkat media"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Panggilan Darurat Saja"</string>
@@ -203,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Pemberitahuan muncul di sini"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Akses kapan saja dengan menggesek ke bawah."\n"Gesek ke bawah sekali lagi untuk kontrol sistem."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Akses kapan saja dengan menggesek ke bawah.\nGesek ke bawah sekali lagi untuk kontrol sistem."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Gesek tepi layar untuk membuka bilah"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Gesek dari bagian tepi layar untuk membuka bilah sistem"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0665fb8..a350d38 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Cancella"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Non disturbare"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostra notifiche"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Rimuovi dall\'elenco"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informazioni applicazione"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nessuna app recente"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Ricarica tramite USB non supportata."\n"Utilizza solo il caricatore in dotazione."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Impostazioni"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Usa per impostazione predef. per dispositivo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Usa per impostazione predef. per accessorio USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Consentire debug USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Fingerprint della chiave RSA del computer: "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Fingerprint della chiave RSA del computer: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Consenti sempre da questo computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom per riempire schermo"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Estendi per riemp. schermo"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dati 4G disattivati"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dati mobili disattivati"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dati disabilati"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Hai raggiunto il limite di utilizzo dei dati specificato."\n\n"Se riattivi i dati, l\'operatore potrebbe addebitarti un costo."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Hai raggiunto il limite di utilizzo dei dati specificato.\n\nSe riattivi i dati, l\'operatore potrebbe addebitarti un costo."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Riattiva dati"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Posizione stabilita dal GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Cancella tutte le notifiche."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informazioni applicazione"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Chiudi"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notifiche disattivate"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tocca qui per riattivare le notifiche."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Lo schermo ruoterà automaticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Lo schermo è bloccato in orientamento orizzontale."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Lo schermo è bloccato in orientamento verticale."</string>
@@ -189,7 +184,8 @@
     <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_ime_label" msgid="7073463064369468429">"Metodo di immissione"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Posizione in uso"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Posizione"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Posizione non attiva"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimediale"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Solo chiamate di emergenza"</string>
@@ -205,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Le notifiche vengono visualizzate qui"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Puoi accedervi in qualsiasi momento scorrendo verso il basso."\n"Fai scorrere di nuovo verso il basso per visualizzare i controlli del sistema."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Puoi accedervi in qualsiasi momento scorrendo verso il basso.\nFai scorrere di nuovo verso il basso per visualizzare i controlli del sistema."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Fai scorrere il bordo dello schermo per visualizzare la barra"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Fai scorrere il dito dal bordo dello schermo per visualizzare la barra di sistema"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c75c039..b274dcc 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"ממשק משתמש של המערכת"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"נקה"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"נא לא להפריע"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"הצג התראות"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"הסר מהרשימה"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"פרטי יישום"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"אין יישומים אחרונים"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"חבר מטען"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"הסוללה נחלשת."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"טעינה באמצעות USB אינה נתמכת."\n"השתמש אך ורק במטען שסופק."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"טעינה באמצעות USB אינה נתמכת.\nהשתמש אך ורק במטען שסופק."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"צריכת סוללה"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"הגדרות"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"השתמש כברירת מחדל עבור מכשיר USB זה"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"השתמש כברירת מחדל עבור אביזר USB זה"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"האם לאפשר ניקוי באגים ב-USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"טביעת האצבע של מפתח ה-RSA של המחשב היא:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"טביעת האצבע של מפתח ה-RSA של המחשב היא:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"אפשר תמיד ממחשב זה"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"הגדל תצוגה כדי למלא את המסך"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"מתח כדי למלא את המסך"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"נתוני 4G מושבתים"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"נתונים לנייד מושבתים"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"הנתונים מושבתים"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"הגעת לגבול המוגדר של שימוש בנתונים."\n\n"אם תפעיל מחדש נתונים, ייתכן שתחויב על ידי הספק שלך."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"הגעת לגבול המוגדר של שימוש בנתונים.\n\nאם תפעיל מחדש נתונים, ייתכן שתחויב על ידי הספק שלך."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"הפעל מחדש את הנתונים"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi מחובר"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"פרטי יישום"</string>
-    <string name="close_universe" msgid="3736513750241754348">"סגור"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"מצב התראות כבוי"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"הקש כאן כדי להפעיל מחדש את ההתראות."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"המסך נעול כעת לרוחב."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"המסך נעול כעת לאורך."</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"סיבוב אוטומטי"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"סיבוב נעול"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"שיטת קלט"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"מיקום בשימוש"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"מיקום"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"מיקום כבוי"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"מכשיר מדיה"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"שיחות חירום בלבד"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"הודעות מופיעות כאן"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"גש אליהם בכל עת על ידי החלקה למטה."\n"החלק למטה שוב למעבר למרכז הבקרה של המערכת."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"גש אליהם בכל עת על ידי החלקה למטה.\nהחלק למטה שוב למעבר למרכז הבקרה של המערכת."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"החלק מקצה המסך כדי להציג את הסרגל"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"החלק מקצה המסך כדי להציג את סרגל המערכת"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index fe0b9af..7392ae9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"システムUI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"通知を消去"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"通知を非表示"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"通知を表示"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"リストから削除"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"アプリ情報"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"最近使ったアプリはありません"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"充電してください"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"電池が残り少なくなっています。"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"残り<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。"\n"付属の充電器をお使いください。"</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。\n付属の充電器をお使いください。"</string>
     <string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"このUSBデバイスにデフォルトで使用する"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"このUSBアクセサリにデフォルトで使用する"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USBデバッグを許可しますか?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"このパソコンのRSAキーのフィンガープリント:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"このパソコンのRSAキーのフィンガープリント:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"このパソコンからのUSBデバッグを常に許可する"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"画面サイズに合わせて拡大"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"画面サイズに合わせて拡大"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4Gデータが無効になりました"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"モバイルデータが無効になりました"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"データが無効になりました"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"指定したデータ使用上限に達しました。"\n\n"データ接続を再度有効にした場合、携帯通信会社の料金が発生する可能性があります。"</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"指定したデータ使用上限に達しました。\n\nデータ接続を再度有効にした場合、携帯通信会社の料金が発生する可能性があります。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"データ接続を再度有効にする"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"アプリ情報"</string>
-    <string name="close_universe" msgid="3736513750241754348">"閉じる"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"通知OFF"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"通知を再度ONにするにはここをタップします。"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"画面は横向きにロックされています。"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"画面は縦向きにロックされています。"</string>
@@ -189,7 +184,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自動回転"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"画面の向きをロック"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"入力方法"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"使用中のロケーション"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"現在地"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"現在地OFF"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"メディアデバイス"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"緊急通報のみ"</string>
@@ -205,5 +201,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"ここに通知が表示されます"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"下にスワイプすると、いつでも通知を表示できます。"\n"システムを管理するにはもう一度下にスワイプしてください。"</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"下にスワイプすると、いつでも通知を表示できます。\nシステムを管理するにはもう一度下にスワイプしてください。"</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"バーを表示するには、画面の端からスワイプします"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"システムバーを表示するには、画面の端からスワイプします"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index eb583e1..1437601 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"시스템 UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"지우기"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"응답 거부"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"알림 표시"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"목록에서 삭제"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"앱 정보"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"최근에 사용한 앱 없음"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"충전기를 연결하세요."</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"배터리가 얼마 남지 않았습니다."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> 남음"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다."\n"제공된 충전기만 사용하세요."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다.\n제공된 충전기만 사용하세요."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"설정"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"이 USB 기기에 기본값으로 사용"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"이 USB 액세서리에 기본값으로 사용"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB 디버깅을 허용하시겠습니까?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"컴퓨터 RSA 키 지문:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"컴퓨터 RSA 키 지문:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"이 컴퓨터에서 항상 허용"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"전체화면 모드로 확대"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"전체화면 모드로 확대"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G 데이터 사용중지됨"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"모바일 데이터 사용중지됨"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"데이터 사용중지됨"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"지정된 데이터 사용 한도에 도달했습니다."\n\n"데이터 연결을 다시 사용하면 통신사에서 요금이 부과될 수도 있습니다."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"지정된 데이터 사용 한도에 도달했습니다.\n\n데이터 연결을 다시 사용하면 통신사에서 요금이 부과될 수도 있습니다."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"데이터 연결 다시 사용"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"앱 정보"</string>
-    <string name="close_universe" msgid="3736513750241754348">"닫기"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"알림 사용 안함"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"알림을 다시 사용하려면 여기를 터치하세요."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"화면이 자동으로 회전됩니다."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"화면이 가로 방향으로 잠겨 있습니다."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"화면이 세로 방향으로 잠겨 있습니다."</string>
@@ -187,7 +182,10 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"자동 회전"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"회전 잠금"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"입력 방법"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"위치 사용 중"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"미디어 기기"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"긴급 통화만 허용"</string>
@@ -203,5 +201,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"알림이 여기에 표시됨"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"아래로 스와이프하여 언제든 액세스하세요."\n"한 번 더 아래로 스와이프하면 시스템 관리로 이동합니다."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"아래로 스와이프하여 언제든 액세스하세요.\n한 번 더 아래로 스와이프하면 시스템 관리로 이동합니다."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"화면 가장자리에서 스와이프하여 표시줄 표시"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"화면 가장자리에서 스와이프하여 시스템 표시줄 표시"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 77d9e9a..bf8662a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sistemos NS"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Išvalyti"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Netrukdyti"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Rodyti pranešimus"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Pašalinti iš sąrašo"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Programos informacija"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nėra naujausių programų"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Prijunkite įkroviklį"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumuliatorius senka."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB krovimas nepalaikomas."\n"Naudokite tik pateiktą įkroviklį."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Nustatymai"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Šiam USB įreng. naudoti pagal numat. nustatymus"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Šiam USB priedui naudoti pagal numat. nustatymus"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Leisti USB derinimą?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Šio kompiuterio RSA rakto kontrolinis kodas yra:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Šio kompiuterio RSA rakto kontrolinis kodas yra:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Visada leisti iš šio kompiuterio"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Keisti mast., kad atit. ekr."</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Ištempti, kad atit. ekr."</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G duomenys neleidžiami"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilieji duomenys neleidžiami"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Duomenys neleidžiami"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Pasiekėte nurodytą duomenų naudojimo apribojimą."\n\n"Jei iš naujo įgalinsite duomenis, jus gali apmokestinti operatorius."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Pasiekėte nurodytą duomenų naudojimo apribojimą.\n\nJei iš naujo įgalinsite duomenis, jus gali apmokestinti operatorius."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Iš naujo įgalinti duomenis"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Programos informacija"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Uždaryti"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Pranešimai išjungti"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Jei norite vėl įjungti pranešimus, palieskite čia."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Užrakintas ekranas yra horizontalios orientacijos."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Užrakintas ekranas yra vertikalios orientacijos."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Įvesties metodas"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Naudojama vieta"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Vietovė"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Vietovė išjungta"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medijos įrenginys"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Tik skambučiai pagalbos numeriu"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Pranešimai rodomi čia"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Perbraukę žemyn bet kuriuo metu pasieksite pranešimus."\n"Jei norite naudoti sistemos valdiklius, perbraukite žemyn dar kartą."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Perbraukę žemyn bet kuriuo metu pasieksite pranešimus.\nJei norite naudoti sistemos valdiklius, perbraukite žemyn dar kartą."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Jei norite, kad būtų rodoma juosta, perbraukite ekrano krašte"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Jei norite, kad būtų rodoma sistemos juosta, perbraukite iš ekrano krašto"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index f1a9727..b96a786 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sistēmas UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Notīrīt"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Netraucēt"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Rādīt paziņojumus"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Noņemšana no saraksta"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Lietotnes informācija"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nav nesen izmantotu lietotņu."</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Atlicis: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB lādēšana netiek atbalstīta."\n"Izmantojiet tikai komplektā iekļauto lādētāju."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Iestatījumi"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Pēc noklusējuma izmantot šai USB ierīcei"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Pēc noklusējuma izmantot šim USB piederumam"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vai atļaut USB atkļūdošanu?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Datora RSA atslēgas ciparfails: "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Datora RSA atslēgas ciparfails: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Vienmēr atļaut no šī datora"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Tālumm., lai aizp. ekr."</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Stiepiet, lai aizp. ekr."</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G dati atspējoti"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilie dati atspējoti"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dati atspējoti"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Ir sasniegts noteiktais datu lietošanas apjoma ierobežojums."\n\n"Ja atkārtoti iespējosiet datus, operators no jums var iekasēt maksu."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Ir sasniegts noteiktais datu lietošanas apjoma ierobežojums.\n\nJa atkārtoti iespējosiet datus, operators no jums var iekasēt maksu."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Atkārtoti iespējot datus"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Notīrīt visus paziņojumus"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informācija par lietotni"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Aizvērt"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Paziņojumi ir izslēgti"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Pieskarieties šeit, lai atkal ieslēgtu paziņojumus."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekrāns tagad ir bloķēts ainavas orientācijā."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekrāns tagad ir bloķēts portreta orientācijā."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Ievades metode"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Izmantotā atrašanās vieta"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Multivides ierīce"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Tikai ārkārtas izsaukumi"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Šeit tiek rādīti paziņojumi"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Piekļūstiet tiem jebkurā laikā, velkot uz leju."\n"Vēlreiz velciet, lai tiktu parādītas sistēmas vadīklas."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Piekļūstiet tiem jebkurā laikā, velkot uz leju.\nVēlreiz velciet, lai tiktu parādītas sistēmas vadīklas."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Velciet no ekrāna malas, lai piekļūtu joslai."</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Velciet no ekrāna malas, lai piekļūtu sistēmas joslai."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mcc262-mnc07/config.xml b/packages/SystemUI/res/values-mcc262-mnc07/config.xml
new file mode 100644
index 0000000..7b7b8f3
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc262-mnc07/config.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Whether or not the RSSI tile is capitalized or not. -->
+    <bool name="quick_settings_rssi_tile_capitalization">false</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index c99626d..5312ccb 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sistem UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Pdm bersih"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Jangan ganggu"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Tunjukkan pemberitahuan"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Alih keluar dari senarai"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Maklumat aplikasi"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Tiada aplikasi terbaharu"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Berbaki <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong."\n"Gunakan hanya pengecas yang dibekalkan."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara lalai untuk peranti USB ini"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara lalai untuk aksesori USB ini"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Benarkan penyahpepijatan USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Cap jari kekunci RSA komputer ialah:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Cap jari kekunci RSA komputer ialah:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Sentiasa benarkan komputer ini"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zum untuk memenuhi skrin"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Regang utk memenuhi skrin"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data 4G dilumpuhkan"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Data mudah alih dilumpuhkan"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data dilumpuhkan"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Anda telah mencapai had penggunaan data yang dinyatakan."\n\n"Jika anda mendayakan semula data, anda mungkin dikenakan caj oleh operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Anda telah mencapai had penggunaan data yang dinyatakan.\n\nJika anda mendayakan semula data, anda mungkin dikenakan caj oleh operator."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Dayakan semula data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi ditetapkan oleh GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Padamkan semua pemberitahuan."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Maklumat apl"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Tutup"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Pemberitahuan dimatikan"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Ketik di sini untuk menghidupkan kembali pemberitahuan."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrin akan berputar secara automatik."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrin dikunci dalam orientasi landskap."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrin dikunci dalam orientasi potret."</string>
@@ -187,7 +182,10 @@
     <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_ime_label" msgid="7073463064369468429">"Kaedah Input"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Lokasi sedang digunakan"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Peranti media"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Panggilan Kecemasan Sahaja"</string>
@@ -203,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Pemberitahuan dipaparkan di sini"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Akses panel pada bila-bila masa dengan meleret ke bawah."\n"Leret ke bawah sekali lagi untuk mendapatkan kawalan sistem."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Akses panel pada bila-bila masa dengan meleret ke bawah.\nLeret ke bawah sekali lagi untuk mendapatkan kawalan sistem."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Leret ke bahagian tepi skrin untuk menampakkan bar"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Leret dari tepi skrin untuk menampakkan bar sistem"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3d32563..778be83 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sys.gr.snitt"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Fjern"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ikke forstyrr"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Vis varslinger"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Fjern fra listen"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info om app"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Ingen nylige apper"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenværende"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke."\n"Bruk kun den medfølgende laderen."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Innstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Trådløse nettverk"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Bruk som standard for denne USB-enheten"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Bruk som standard for dette USB-tilbehøret"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vil du tillate USB-feilsøking?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Datamaskinens nøkkelfingeravtrykk for RSA er:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Datamaskinens nøkkelfingeravtrykk for RSA er:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Tillat alltid fra denne datamaskinen"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom for å fylle skjermen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Strekk for å fylle skjerm"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-data er deaktivert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobildata er deaktivert"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data deaktivert"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Du har nådd den angitte databruksgrensen."\n\n"Hvis du slår på igjen databruk, kan du bli belastet med kostnader av operatøren."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Du har nådd den angitte databruksgrensen.\n\nHvis du slår på igjen databruk, kan du bli belastet med kostnader av operatøren."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Aktiver data på nytt"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om app"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Lukk"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Varsler er deaktivert"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Trykk her for å aktivere varsler på nytt."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjermen roterer automatisk."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skjermen er låst i liggende retning."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skjermen er låst i stående retning."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Inndatametode"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Posisjon i bruk"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Sted"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Posisjon av"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medieenhet"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Bare nødanrop"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Varslene vises her"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Bruk dem når som helst ved å sveipe nedover."\n"Sveip nedover igjen for å gå til systemkontrollene."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Bruk dem når som helst ved å sveipe nedover.\nSveip nedover igjen for å gå til systemkontrollene."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Sveip på kanten av skjermen for å få frem feltet"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Sveip fra kanten på skjermen for å få frem systemfeltet"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 66f0a35..ab77839 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Systeem-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wissen"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Niet storen"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Meldingen weergeven"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Verwijderen uit lijst"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App-info"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Geen recente apps"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund."\n"Gebruik alleen de bijgeleverde oplader."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
@@ -59,19 +57,19 @@
     <string name="always_use_device" msgid="1450287437017315906">"Standaard gebruiken voor dit USB-apparaat"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Standaard gebruiken voor dit USB-accessoire"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB-foutopsporing toestaan?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"De vingerafdruk voor de RSA-sleutel van de computer is:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"De vingerafdruk voor de RSA-sleutel van de computer is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Altijd toestaan vanaf deze computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom om scherm te vullen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rek uit v. schermvulling"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Compatibiliteitszoom"</string>
     <string name="compat_mode_help_body" msgid="4946726776359270040">"Wanneer een app is ontworpen voor een kleiner scherm, wordt naast de klok een zoomknop weergegeven."</string>
-    <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Schermafbeelding opslaan..."</string>
-    <string name="screenshot_saving_title" msgid="8242282144535555697">"Schermafbeelding opslaan..."</string>
-    <string name="screenshot_saving_text" msgid="2419718443411738818">"Schermafbeelding wordt opgeslagen."</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"Schermafbeelding gemaakt."</string>
-    <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw schermafbeelding te bekijken."</string>
-    <string name="screenshot_failed_title" msgid="705781116746922771">"Schermafbeelding is niet gemaakt."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan schermafbeelding niet opslaan. Mogelijk is de opslag in gebruik."</string>
+    <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Screenshot opslaan..."</string>
+    <string name="screenshot_saving_title" msgid="8242282144535555697">"Screenshot opslaan..."</string>
+    <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot wordt opgeslagen."</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string>
+    <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw screenshot te bekijken."</string>
+    <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string>
+    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan screenshot niet opslaan. Mogelijk is de opslag in gebruik."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-gegevens uitgeschakeld"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobiele gegevens uitgeschakeld"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Gegevens uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"U heeft de gestelde limiet voor gegevensverbruik bereikt."\n\n"Als u gegevens opnieuw inschakelt, kunnen er kosten in rekening worden gebracht door uw provider."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"U heeft de gestelde limiet voor gegevensverbruik bereikt.\n\nAls u gegevens opnieuw inschakelt, kunnen er kosten in rekening worden gebracht door uw provider."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Gegevens opnieuw inschakelen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle meldingen wissen."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"App-info"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Sluiten"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Meldingen uit"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tik hier om meldingen weer in te schakelen."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Scherm wordt automatisch geroteerd."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Het scherm is nu vergrendeld in liggende stand."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Het scherm is nu vergrendeld in staande stand."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Invoermethode"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Locatie in gebruik"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Locatie"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Locatie uit"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Media-apparaat"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Alleen noodoproepen"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Meldingen worden hier weergegeven"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"U kunt de meldingen op elk gewenst moment openen door met uw vinger omlaag te vegen."\n"Veeg nogmaals met uw vinger omlaag om de systeembesturingselementen weer te geven."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"U kunt de meldingen op elk gewenst moment openen door met uw vinger omlaag te vegen.\nVeeg nogmaals met uw vinger omlaag om de systeembesturingselementen weer te geven."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Veeg vanaf de rand om balk weer te geven"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Veeg vanaf de rand van het scherm om de systeembalk weer te geven"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 67e54de..c94cfc8 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Interfejs"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wyczyść"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Nie przeszkadzać"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Pokaż powiadomienia"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Usuń z listy"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informacje o aplikacji"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Brak ostatnio uruchomionych aplikacji."</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane."\n"Należy używać tylko dołączonej ładowarki."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Ustawienia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Używaj domyślnie dla tego urządzenia USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Używaj domyślnie dla tego akcesorium USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Zezwalać na debugowanie USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Odcisk cyfrowy klucza RSA komputera to:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Odcisk cyfrowy klucza RSA komputera to:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Zawsze zezwalaj z tego komputera"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Powiększ, aby wypełnić ekran"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rozciągnij, aby wypełnić ekran"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Wyłączono transmisję danych 4G"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Transmisja danych została wyłączona"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Wyłączono transmisję danych"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Ustawiony limit transmisji danych został osiągnięty."\n\n"Jeśli ponownie włączysz przesyłanie danych, operator może naliczyć dodatkowe opłaty."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Ustawiony limit transmisji danych został osiągnięty.\n\nJeśli ponownie włączysz przesyłanie danych, operator może naliczyć dodatkowe opłaty."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Włącz transmisję danych"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"O aplikacji"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Zamknij"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Powiadomienia wyłączone"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Kliknij tutaj, by przywrócić powiadomienia."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran jest zablokowany w orientacji poziomej."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran jest zablokowany w orientacji pionowej."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Metoda wprowadzania"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Lokalizacja w użyciu"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Lokalizacja"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokalizacja wyłączona"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Urządzenie multimedialne"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Tylko połączenia alarmowe"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Tutaj pokazują się powiadomienia"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Możesz je otworzyć w dowolnej chwili, przesuwając w dół."\n"Przesuń jeszcze raz w dół, by otworzyć ustawienia systemowe."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Możesz je otworzyć w dowolnej chwili, przesuwając w dół.\nPrzesuń jeszcze raz w dół, by otworzyć ustawienia systemowe."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Przesuń palcem od krawędzi ekranu, by odkryć pasek"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Przesuń palcem od krawędzi ekranu, by odkryć pasek systemu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ffbfa88..c106329 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"IU do sist."</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Limpar"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Não incomodar"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificações"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Remover da lista"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informações da aplicação"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Não existem aplicações recentes"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Carregamento USB não suportado. "\n"Utilize apenas o carregador fornecido."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Definições"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Utilizar por predefinição para este aparelho USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utilizar por predefinição para este acessório USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Permitir depuração USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA do computador é:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA do computador é:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Permitir sempre a partir deste computador"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom para preencher o ecrã"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Esticar p. caber em ec. int."</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Os dados 4G estão desativados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Os dados móveis estão desativados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dados desativados"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Atingiu o limite de utilização de dados especificado."\n\n"Se voltar a ativar os dados, pode levar a uma cobrança por parte do operador."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Atingiu o limite de utilização de dados especificado.\n\nSe voltar a ativar os dados, pode levar a uma cobrança por parte do operador."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Reativar dados"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações da aplicação"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Fechar"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notificações desativadas"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Toque aqui para voltar a ativar as notificações."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"O ecrã está bloqueado na orientação horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"O ecrã está bloqueado na orientação vertical."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Método de Introdução"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Localização em utilizaçã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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Apenas Chamadas de Emergência"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"As notificações são apresentadas aqui"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Pode aceder em qualquer altura, deslizando rapidamente para baixo com o dedo."\n"Deslize novamente para baixo para aceder aos controlos do sistema."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Pode aceder em qualquer altura, deslizando rapidamente para baixo com o dedo.\nDeslize novamente para baixo para aceder aos controlos do sistema."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Deslize da extremidade do ecrã para revelar a barra"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Deslize da extremidade do ecrã para revelar a barra do sistema"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ffe4027..91e7f02 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Interf sist"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Limpar"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Não perturbe"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificações"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Remover da lista"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informações do aplicativo"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nenhum aplicativo recente"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado."\n"Use apenas o carregador fornecido."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Usar por padrão para este dispositivo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Permitir a depuração USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA deste computador é:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA deste computador é:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Sempre permitir a partir deste computador"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom p/ preencher a tela"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Ampliar p/ preencher tela"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dados 4G desativados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dados móveis desativados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dados desativados"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Você atingiu o limite de uso de dados especificados."\n\n"Se você reativá-los, poderá receber uma cobrança do operador."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Você atingiu o limite de uso de dados especificados.\n\nSe você reativá-los, poderá receber uma cobrança do operador."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Reativar dados"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações do aplicativo"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Fechar"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notificações desativadas"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Toque aqui para ativar as notificações novamente."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A tela está bloqueada na orientação paisagem."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A tela está bloqueada na orientação retrato."</string>
@@ -189,7 +184,10 @@
     <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_ime_label" msgid="7073463064369468429">"Método de entrada"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Local em uso"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo de mídia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Somente chamadas de emergência"</string>
@@ -205,5 +203,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"As notificações aparecem aqui"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Acesse a qualquer momento deslizando para baixo."\n"Deslize para baixo novamente para acessar os controles do sistema."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Acesse a qualquer momento deslizando para baixo.\nDeslize para baixo novamente para acessar os controles do sistema."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Deslize a borda da tela para ver a barra"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Deslize a partir da borda da tela ver a barra do sistema"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 9e5dbe1..d7772ed 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -22,10 +22,6 @@
     <!-- no translation found for app_label (7164937344850004466) -->
     <skip />
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Stizzar"</string>
-    <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
-    <skip />
-    <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
-    <skip />
     <!-- no translation found for status_bar_recent_remove_item_title (6026395868129852968) -->
     <skip />
     <!-- no translation found for status_bar_recent_inspect_item_title (7793624864528818569) -->
@@ -306,12 +302,6 @@
     <skip />
     <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) -->
     <skip />
-    <!-- no translation found for close_universe (3736513750241754348) -->
-    <skip />
-    <!-- no translation found for notifications_off_title (8936620513608443224) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (2529001315769385273) -->
-    <skip />
     <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
     <skip />
     <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
@@ -344,7 +334,9 @@
     <skip />
     <!-- no translation found for quick_settings_ime_label (7073463064369468429) -->
     <skip />
-    <!-- no translation found for quick_settings_location_label (3292451598267467545) -->
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
     <skip />
     <!-- no translation found for quick_settings_media_device_label (1302906836372603762) -->
     <skip />
@@ -378,4 +370,8 @@
     <skip />
     <!-- no translation found for status_bar_help_text (7874607155052076323) -->
     <skip />
+    <!-- no translation found for hideybar_confirmation_message (9050869548951044371) -->
+    <skip />
+    <!-- no translation found for hideybar_confirmation_message_long (7117692795163620626) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bea8141..42e2d48 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI sistem"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ștergeţi"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Nu deranjaţi"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Afişaţi notificări"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminaţi din listă"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informaţii despre aplicaţie"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Nu există aplicaţii recente"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Rămas: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. "\n"Utilizaţi numai încărcătorul furnizat."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Permiteţi depanarea USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Amprenta digitală din cheia RSA a computerului este:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Amprenta digitală din cheia RSA a computerului este:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Permiteţi întotdeauna de pe acest computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom pt. a umple ecranul"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Înt. pt. a umple ecranul"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datele 4G au fost dezactivate"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Datele mobile au fost dezactivate"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Utilizare date dezactivată"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Aţi atins limita specificată pentru utilizarea datelor."\n\n"Dacă reactivaţi datele, puteţi fi taxat(ă) de către operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Aţi atins limita specificată pentru utilizarea datelor.\n\nDacă reactivaţi datele, puteţi fi taxat(ă) de către operator."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Reactivaţi datele"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Locaţie setată prin GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeţi toate notificările."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informaţii despre aplicaţie"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Închideţi"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Notificările sunt dezactivate"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Apăsaţi aici pentru a reactiva notificările."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ecranul este blocat în orientarea de tip peisaj."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ecranul este blocat în orientarea de tip portret."</string>
@@ -187,7 +182,10 @@
     <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_ime_label" msgid="7073463064369468429">"Metodă de introducere"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Locaţie în uz"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispozitiv media"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Numai apeluri de urgenţă"</string>
@@ -203,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Notificările se afişează aici"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Accesaţi-le oricând glisând în jos."\n"Glisaţi în jos din nou pentru comenzile sistemului."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Accesaţi-le oricând glisând în jos.\nGlisaţi în jos din nou pentru comenzile sistemului."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Glisați dinspre marginea ecranului pentru a afișa bara"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Glisați dinspre marginea ecranului pentru a afișa bara de sistem"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5525ed8..233fee8a8 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Графический интерфейс системы"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Очистить"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Не беспокоить"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Показать уведомления"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Удалить из списка"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"О приложении"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Список недавно использованных приложений пуст."</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Подключите зарядное устройство"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается."\n"Используйте только зарядное устройство из комплекта поставки."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается.\nИспользуйте только зарядное устройство из комплекта поставки."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Подробнее"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Использовать по умолчанию для этого USB-устройства"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Использовать по умолчанию для этого USB-аксессуара"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Отладка по USB"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Цифровой отпечаток ключа RSA:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Цифровой отпечаток ключа RSA:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Всегда разрешать отладку с этого компьютера"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Подогнать по размерам экрана"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Растянуть на весь экран"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Передача данных по каналу 4G отключена"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Моб. Интернет отключен"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Передача данных отключена"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнут лимит трафика."\n\n"При восстановлении подключения оператор может взимать плату за передачу данных."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнут лимит трафика.\n\nПри восстановлении подключения оператор может взимать плату за передачу данных."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Восстановить подключение"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"О приложении"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Закрыть"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Уведомления отключены"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Нажмите здесь, чтобы снова включить уведомления."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран будет поворачиваться автоматически."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Выбрана только альбомная ориентация экрана."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Выбрана только книжная ориентация экрана."</string>
@@ -191,7 +186,10 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автоповорот"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Автоповорот выкл."</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Способ ввода"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Геосервис вкл."</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Режим медиа"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Экстр. вызов"</string>
@@ -207,5 +205,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Это панель уведомлений"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Ее можно открыть, пролистнув экран вниз."\n"Чтобы открыть настройки, проведите пальцем вниз ещё раз."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Ее можно открыть, пролистнув экран вниз.\nЧтобы открыть настройки, проведите пальцем вниз ещё раз."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Чтобы открыть панель, проведите пальцем от края к центру экрана"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Чтобы открыть панель навигации, проведите пальцем от края к центру экрана"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 79005f1..c54540c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI systému"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Vymazať"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Nerušiť"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Zobraziť upozornenia"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Odstrániť zo zoznamu"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informácie o aplikácii"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Žiadne nedávne aplikácie"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované."\n"Používajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Pre toto zariadenie USB použiť ako predvolené"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Pre toto periférne zar. USB použiť ako predvolené"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Povoliť ladenie USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Digitálny odtlačok RSA počítača je:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Digitálny odtlačok RSA počítača je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Vždy povoliť z tohto počítača"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Priblížiť na celú obrazovku"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dátové prenosy 4G sú zakázané"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilné dátové prenosy sú zakázané"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dáta boli zakázané"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosiahli ste stanovený limit využitia dát."\n\n"Ak dátové pripojenie znova povolíte, môže vám váš operátor účtovať poplatky."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosiahli ste stanovený limit využitia dát.\n\nAk dátové pripojenie znova povolíte, môže vám váš operátor účtovať poplatky."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Znova povoliť dátové prenosy"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informácie o aplikácii"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Zavrieť"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Upozornenia sú vypnuté"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Klepnutím sem upozornenia znova povolíte."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka sa automaticky otočí."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Obrazovka je uzamknutá v orientácii na šírku."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Obrazovka je uzamknutá v orientácii na výšku."</string>
@@ -189,7 +184,8 @@
     <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_ime_label" msgid="7073463064369468429">"Metóda vstupu"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Používaná poloha"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Poloha"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Poloha vypnutá"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Mediálne zariadenie"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Len tiesňové volania"</string>
@@ -205,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Tu sa zobrazujú upozornenia"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Môžete ich kedykoľvek zobraziť tak, že posuniete prstom nadol."\n"Ak posuniete prstom nadol ešte raz, zobrazia sa ovládacie prvky systému."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Môžete ich kedykoľvek zobraziť tak, že posuniete prstom nadol.\nAk posuniete prstom nadol ešte raz, zobrazia sa ovládacie prvky systému."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Panel zobrazíte posunutím cez okraj obrazovky"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Systémový panel zobrazíte posunutím cez okraj obrazovky"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 742361d..3fc4882 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sistemski uporabniški vmesnik"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Počisti"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ne moti"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Pokaži obvestila"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Odstrani s seznama"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Podatki o programu"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Ni nedavnih programov"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Polnjenje po povezavi USB ni podprto."\n"Uporabite priloženi polnilnik."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Privzeto uporabi za to napravo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Privzeto uporabi za ta dodatek USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Ali dovolite odpravljanje težav prek USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Računalnikov prstni odtis ključa RSA je:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Računalnikov prstni odtis ključa RSA je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Vedno dovoli iz tega računalnika"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Povečava čez cel zaslon"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Raztegnitev čez zaslon"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Podatki 4G so onemogočeni"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilni podatki so onemogočeni"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Podatki onemogočeni"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosegli ste omejitev količine prenesenih podatkov."\n\n"Če prenos podatkov znova omogočite, vam ga lahko operater zaračuna."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Dosegli ste omejitev količine prenesenih podatkov.\n\nČe prenos podatkov znova omogočite, vam ga lahko operater zaračuna."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Znova omogoči podatke"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Podatki o aplikaciji"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Zapri"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Obvestila so izklopljena"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Dotaknite se tukaj, da ponovno vklopite obvestila."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaklenjen v ležeči usmerjenosti."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaklenjen v pokončni usmerjenosti."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Način vnosa"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Mesto uporabe"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokacija izklopljena"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Predstavnostna naprava"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Le klici v sili"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Obvestila so prikazana tukaj"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Do njih lahko kadar koli dostopate tako, da povlečete navzdol."\n"Za prikaz sistemskih kontrolnikov znova povlecite navzdol."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Do njih lahko kadar koli dostopate tako, da povlečete navzdol.\nZa prikaz sistemskih kontrolnikov znova povlecite navzdol."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Vrstico prikažete tako, da povlečete z roba zaslona"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Sistemsko vrstico prikažete tako, da povlečete z roba zaslona"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3bf5052..7ba2da5 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI система"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Обриши"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Не узнемиравај"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Приказуј упозорења"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Уклањање са листе"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Информације о апликацији"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Нема недавних апликација"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Прикључите пуњач"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерија ће се ускоро испразнити."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"преостало је <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано."\n"Користите само приложени пуњач."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано.\nКористите само приложени пуњач."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Коришћење батерије"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подешавања"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Користи подразумевано за овај USB уређај"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Користи подразумевано за овај USB додатак"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Желите ли да дозволите отклањање USB грешака?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Дигитални отисак RSA кључа овог рачунара је:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Дигитални отисак RSA кључа овог рачунара је:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Увек дозволи са овог рачунара"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Зумирај на целом екрану"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Развуци на цео екран"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G подаци су онемогућени"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Подаци мобилне мреже су онемогућени"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Подаци су онемогућени"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигли сте наведено ограничење за коришћење података."\n\n"Ако поново омогућите податке, мобилни оператер ће вам можда наплатити."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигли сте наведено ограничење за коришћење података.\n\nАко поново омогућите податке, мобилни оператер ће вам можда наплатити."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Поново омогући податке"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Локацију је подесио GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Информације о апликацији"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Затвори"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Обавештења су искључена"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Додирните овде да бисте поново укључили обавештења."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран ће се аутоматски ротирати."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран је закључан у хоризонталном положају."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран је закључан у вертикалном положају."</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Аутоматско ротирање"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Ротирање је закључано"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Метод уноса"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Локација која се користи"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Локација"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Локација је искључена"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Медијски уређај"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Само хитни позиви"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Обавештења се појављују овде"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Приступите им у било ком тренутку листањем надоле."\n"Поново листајте надоле да би се приказале системске контроле."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Приступите им у било ком тренутку листањем надоле.\nПоново листајте надоле да би се приказале системске контроле."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Превуците по ивици екрана да би се приказала трака"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Превуците од ивице екрана да би се приказала системска трака"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 71eedd8..022e2f2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Gränssnitt"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ta bort"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Stör ej"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Visa aviseringar"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Ta bort från listan"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info om appen"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Inga nya appar"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> återstår"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB."\n"Använd endast den laddare som levererades med telefonen."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Inställningar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Använd som standard för den här USB-enheten"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Använd som standard för det här USB-tillbehöret"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Ska USB-felsökning tillåtas?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Fingeravtrycket för datorns RSA-nyckel är:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Fingeravtrycket för datorns RSA-nyckel är:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Tillåt alltid på den här datorn"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zooma för att fylla skärm"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Dra för att fylla skärmen"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data via 4G har inaktiverats"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobildata har inaktiverats"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Du har nått den angivna gränsen för dataanvändning."\n\n"Om du aktiverar data på nytt kan du bli debiterad av operatören."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Du har nått den angivna gränsen för dataanvändning.\n\nOm du aktiverar data på nytt kan du bli debiterad av operatören."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Återaktivera data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om appen"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Stäng"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Meddelanden inaktiverade"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Knacka lätt här om du vill aktivera meddelanden igen."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildskärmens riktning är nu låst i liggande format."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildskärmens riktning är nu låst i stående format."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Inmatningsmetod"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Plats som används"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Plats"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Plats har inaktiverats"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medieenhet"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Endast nödsamtal"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Meddelanden visas här"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Du kommer åt dem när som helst genom att dra nedåt."\n"Dra nedåt igen om du vill visa systemkontroller."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Du kommer åt dem när som helst genom att dra nedåt.\nDra nedåt igen om du vill visa systemkontroller."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Dra från kanten av skärmen om du vill visa fältet"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Dra från kanten av skärmen om du vill visa systemfältet"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index ccbc51f..27f556c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI ya Mfumo"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Futa"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Usisumbue"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Onyesha arifa"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Ondoa kwenye orodha"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Taarifa za programu-matumizi"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Hakuna programu za sasa"</string>
@@ -35,7 +33,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Unganisha chaja"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Betri inaisha."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> zimebakia"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi."\n" Tumia chaka iliyopeanwa."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Mipangilio"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Mtandao-Hewa"</string>
@@ -57,7 +55,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Kwa kifaa hiki cha USB tumia chaguo-msingi"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Tumia kama chaguo-msingi ya kifuasi hiki cha USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Ruhusu utatuaji wa USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Alama ya kidole ya kitufe cha RSA ya kompyuta ni:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Alama ya kidole ya kitufe cha RSA ya kompyuta ni:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Ruhusu kutoka kwenye kompyuta hii kila wakati"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Kuza ili kujaza skrini"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Tanua ili kujaza skrini"</string>
@@ -158,7 +156,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data ya 4G imelemazwa"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Data ya kifaa cha mkononi imelemazwa"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data imelemazwa"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Umefika kikomo maalum cha matumizi ya data. "\n" "\n" Ukiwezesha data tena, unaweza kutozwa na mtoa huduma."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Umefika kikomo maalum cha matumizi ya data. \n \n Ukiwezesha data tena, unaweza kutozwa na mtoa huduma."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Wezesha upya data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
@@ -166,9 +164,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Mahali pamewekwa na GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Futa arifa zote."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Taarifa ya programu"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Funga"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Arifa zimelemazwa"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Gonga hapa ili kuwezesha tena arifa."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrini itazunguka kiotomatiki."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrini imefungwa sasa katika uelekezo wa mandhari."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrini imefungwa katika uelekeo wa picha."</string>
@@ -185,7 +180,10 @@
     <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_ime_label" msgid="7073463064369468429">"Mbinu ya uingizaji"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Eneo linalotumika"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Kifaa cha midia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Simu za Dharura Pekee"</string>
@@ -201,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Arifa zitaonekana hapa"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Zifikie wakati wowote kwa kutelezesha chini."\n"Telezesha chini tena kupata vidhibiti vya mfumo."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Zifikie wakati wowote kwa kutelezesha chini.\nTelezesha chini tena kupata vidhibiti vya mfumo."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Papasa kwa kasi kutoka ukingo wa skrini ili kuonyesha upau"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Papasa kwa kasi kutoka ukingo wa skrini ili kuonyesha upau wa mfumo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index e42855c..b1fc00a 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -16,22 +16,10 @@
 */
 -->
 <resources>
-    <!-- size at which Notification icons will be drawn in the status bar -->
-    <dimen name="system_bar_icon_drawing_size">24dip</dimen>
-
-    <!-- opacity at which Notification icons will be drawn in the status bar -->
-    <item type="dimen" name="system_bar_icon_drawing_alpha">100%</item>
-
-    <!-- The width of the view containing non-menu status bar icons -->
-    <dimen name="system_bar_navigation_key_width">80dip</dimen>
-
-    <!-- The width of the view containing the menu status bar icon -->
-    <dimen name="system_bar_navigation_menu_key_width">80dip</dimen>
 
     <!-- ======================================== -->
     <!-- The following resources were recently moved from sw600dp; there may
-         be situations where they don't sync up perfectly with
-         PhoneStatusBar/TabletStatusBar. -->
+         be situations where they don't sync up perfectly with PhoneStatusBar. -->
     <!-- ======================================== -->
 
     <!-- The width of the ticker, including the icon -->
diff --git a/packages/SystemUI/res/values-sw720dp/styles.xml b/packages/SystemUI/res/values-sw720dp/styles.xml
deleted file mode 100644
index 5009395..0000000
--- a/packages/SystemUI/res/values-sw720dp/styles.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <style name="SystemBarNotificationText">
-        <item name="android:textSize">16sp</item>
-        <item name="android:textColor">#ff999999</item>
-    </style>
-
-    <style name="SystemBarPanelSettingsRow">
-        <item name="android:paddingRight">16dp</item>
-        <item name="android:layout_height">64dp</item>
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:orientation">horizontal</item>
-        <item name="android:background">?android:attr/listChoiceBackgroundIndicator</item>
-    </style>
-
-    <style name="SystemBarPanelSettingsIcon">
-        <item name="android:layout_height">match_parent</item>
-        <item name="android:layout_width">64dp</item>
-        <item name="android:scaleType">center</item>
-    </style>
-
-    <style name="SystemBarPanelSettingsContents">
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_width">0dp</item>
-        <item name="android:layout_weight">1</item>
-        <item name="android:layout_gravity">start|center_vertical</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:textSize">18sp</item>
-    </style>
-
-    <style name="SystemBarPanelSettingsPanelSeparator">
-        <item name="android:layout_marginEnd">0dp</item>
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">1dp</item>
-        <item name="android:background">@android:drawable/divider_horizontal_dark</item>
-    </style>
-
-    <style name="TextAppearance.SystemBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
-        <item name="android:textSize">30dp</item>
-        <item name="android:textStyle">normal</item>
-        <item name="android:textColor">@android:color/holo_blue_light</item>
-    </style>
-
-    <style name="TextAppearance.SystemBar.Expanded.Clock" parent="@style/TextAppearance.StatusBar.Expanded.Clock">
-        <item name="android:textSize">48dp</item>
-        <item name="android:fontFamily">sans-serif-light</item>
-        <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#ffffff</item>
-    </style>
-
-    <style name="TextAppearance.SystemBar.Expanded.Date" parent="@style/TextAppearance.StatusBar.Expanded.Date">
-        <item name="android:textSize">14dp</item>
-        <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#666666</item>
-        <item name="android:textAllCaps">true</item>
-    </style>
-
-</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 1429a3c..dc643c4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"ส่วนติดต่อผู้ใช้ของระบบ"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"ล้างข้อมูล"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"ห้ามรบกวน"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"แสดงการแจ้งเตือน"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"ลบจากรายการ"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ข้อมูลแอปพลิเคชัน"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"ไม่มีแอปพลิเคชันล่าสุด"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"เสียบที่ชาร์จ"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"แบตเตอรี่เหลือน้อย"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"เหลืออีก <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB"\n"ใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB\nใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
     <string name="battery_low_why" msgid="7279169609518386372">"การใช้แบตเตอรี่"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"การตั้งค่า"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์ USB นี้"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์เสริม USB นี้"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"อนุญาตให้แก้ไขข้อบกพร่อง USB หรือไม่"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"ลายนิ้วมือหลัก RSA ของคอมพิวเตอร์คือ:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"ลายนิ้วมือหลัก RSA ของคอมพิวเตอร์คือ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"อนุญาตจากคอมพิวเตอร์เครื่องนี้เสมอ"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"ขยายจนเต็มหน้าจอ"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"ยืดจนเต็มหน้าจอ"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"ปิดใช้งานข้อมูล 4G แล้ว"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"ปิดใช้งานข้อมูลมือถือแล้ว"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"ข้อมูลถูกปิดใช้งาน"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"คุณได้มาถึงขีดจำกัดการใช้ข้อมูลที่ระบุไว้แล้ว"\n\n"หากคุณเปิดใช้งานข้อมูลอีกครั้ง ผู้ให้บริการของคุณอาจเรียกเก็บค่าบริการ"</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"คุณได้มาถึงขีดจำกัดการใช้ข้อมูลที่ระบุไว้แล้ว\n\nหากคุณเปิดใช้งานข้อมูลอีกครั้ง ผู้ให้บริการของคุณอาจเรียกเก็บค่าบริการ"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"เปิดใช้งานข้อมูลอีกครั้ง"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"ตำแหน่งที่กำหนดโดย GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"ข้อมูลแอป"</string>
-    <string name="close_universe" msgid="3736513750241754348">"ปิด"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"การแจ้งเตือนปิดอยู่"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"แตะที่นี่เพื่อเปิดการแจ้งเตือนอีกครั้ง"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"หน้าจอจะหมุนโดยอัตโนมัติ"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวนอน"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวตั้ง"</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"หมุนอัตโนมัติ"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"ล็อกการหมุนแล้ว"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"วิธีป้อนข้อมูล"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"สถานที่ที่ใช้งาน"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"ตำแหน่ง"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ปิดตำแหน่ง"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"อุปกรณ์สื่อ"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"โทรฉุกเฉินเท่านั้น"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"การแจ้งเตือนจะแสดงขึ้นที่นี่"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"เข้าถึงได้ทุกเมื่อด้วยการกวาดนิ้วลง"\n"กวาดนิ้วลงอีกครั้งสำหรับการควบคุมระบบ"</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"เข้าถึงได้ทุกเมื่อด้วยการกวาดนิ้วลง\nกวาดนิ้วลงอีกครั้งสำหรับการควบคุมระบบ"</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"กวาดขอบของหน้าจอเพื่อแสดงแถบ"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"กวาดจากขอบของหน้าจอเพื่อแสดงแถบระบบ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c48db46..0053be4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI ng System"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"I-clear"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Huwag gambalain"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Magpakita ng notification"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Alisin mula sa listahan"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Impormasyon ng app"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Walang kamakailang apps"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> natitira"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Hindi sinusuportahan ang pag-charge sa USB."\n"Gamitin lang ang ibinigay na charger."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Mga Setting"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Gamitin bilang default para sa USB device"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gamitin bilang default sa USB accessory na ito"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Payagan ang pag-debug ng USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Ang RSA key fingerprint ng computer ay:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Ang RSA key fingerprint ng computer ay:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Palaging payagan mula sa computer na ito"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"I-zoom upang punan screen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"I-stretch upang mapuno screen"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Hindi pinapagana ang 4G na data"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Hindi pinapagana ang data ng mobile"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Hindi pinapagana ang data"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Naabot mo na ang tinukoy na limitasyon ng paggamit ng data."\n\n"Kung muli mong papaganahin ang data, maaari kang masingil ng operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Naabot mo na ang tinukoy na limitasyon ng paggamit ng data.\n\nKung muli mong papaganahin ang data, maaari kang masingil ng operator."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Muling paganahin ang data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasyong itinatakda ng GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"I-clear ang lahat ng notification."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Impormasyon ng app"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Isara"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Naka-off ang mga notification"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Tumapik dito upang muling i-on ang mga notification."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Awtomatikong iikot ang screen."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Naka-lock ang screen sa pahigang oryentasyon."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Naka-lock ang screen sa patayong oryentasyon."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Pamamaraan ng Pag-input"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Lokasyong ginagamit"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Device ng media"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Mga Pang-emergency na Tawag Lamang"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Dito lumalabas ang mga notification"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"I-access ang mga ito anumang oras sa pamamagitan ng pag-swipe pababa."\n"Muling mag-swipe pababa para sa mga kontrol ng system."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"I-access ang mga ito anumang oras sa pamamagitan ng pag-swipe pababa.\nMuling mag-swipe pababa para sa mga kontrol ng system."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Mag-swipe sa gilid ng screen upang ipakita ang bar"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Mag-swipe mula sa gilid ng screen upang ipakita ang system bar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d0dd099..f39f8bc 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Sist Arayüzü"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Temizle"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Rahatsız etmeyin"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Bildirimleri göster"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Listeden kaldır"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Uygulama bilgileri"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Son uygulama yok"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor."\n"Yalnızca ürünle birlikte verilen şarj cihazını kullanın."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Kablosuz"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Bu USB cihazı için varsayılan olarak kullan"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar için varsayılan olarak kullan"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB hata ayıklamasına izin verilsin mi?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Bilgisayarın RSA anahtarı parmak izi:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Bilgisayarın RSA anahtarı parmak izi:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Bu bilgisayardan her zaman izin ver"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Yakınlaştır (ekranı kaplasın)"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Genişlet (ekran kapansın)"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G verileri devre dışı"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobil veriler devre dışı"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Veriler devre dışı"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Belirtilen veri kullanım limitine ulaştınız."\n\n"Verileri yeniden etkinleştirirseniz, operatör sizden ücret talep edebilir."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Belirtilen veri kullanım limitine ulaştınız.\n\nVerileri yeniden etkinleştirirseniz, operatör sizden ücret talep edebilir."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Veriyi yeniden etkinleştir"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Uygulama bilgileri"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Kapat"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Bildirimler kapalı"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Bildirimleri tekrar açmak için buraya hafifçe vurun."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran yatay yönde kilitlendi."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran dikey yönde kilitlendi."</string>
@@ -187,7 +182,10 @@
     <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_ime_label" msgid="7073463064369468429">"Giriş Yöntemi"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Kullanılan konum"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medya cihazı"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Yalnızca Acil Çağrılar İçin"</string>
@@ -203,5 +201,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Bildirimler burada görünür"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Aşağıya hızlıca kaydırarak bunlara istediğiniz zaman erişebilirsiniz."\n"Sistem denetimleri için tekrar hızlıca aşağı kaydırın."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Aşağıya hızlıca kaydırarak bunlara istediğiniz zaman erişebilirsiniz.\nSistem denetimleri için tekrar hızlıca aşağı kaydırın."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Çubuğu görüntülemek için ekranın kenarından hızlıca kaydırın"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Sistem çubuğunu görüntülemek için ekranın kenarından hızlıca kaydırın"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5f059b4..18f67a2 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Інтерфейс системи"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Очист."</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Не турбувати"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Показувати сповіщення"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Видалити зі списку"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Інформація про програму"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Немає останніх програм"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"Підключіть зарядний пристрій"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Акумулятор розряджається."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується."\n"Використовуйте лише наданий у комплекті зарядний пристрій."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується.\nВикористовуйте лише наданий у комплекті зарядний пристрій."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Використання акумулятора"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Використовувати за умовчанням для пристрою USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Використовувати за умовчанням для аксесуара USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Дозволити налагодження USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Цифровий відбиток ключа RSA комп’ютера:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Цифровий відбиток ключа RSA комп’ютера:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Завжди дозволяти з цього комп’ютера"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Масштабув. на весь екран"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Розтягнути на весь екран"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Дані 4G вимкнено"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобільне передавання даних вимкнено"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Використання даних вимкнено"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Досягнуто вказаного ліміту використання даних."\n\n"Якщо ввімкнути використання даних знову, оператор може стягнути плату."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Досягнуто вказаного ліміту використання даних.\n\nЯкщо ввімкнути використання даних знову, оператор може стягнути плату."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Повторно ввімкнути дані"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Очистити всі сповіщення."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Інформація про програму"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Закрити"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Сповіщення вимкнено"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Торкніться тут, щоб знову ввімкнути сповіщення."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран обертатиметься автоматично."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран заблоковано в альбомній орієнтації."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран заблоковано в книжковій орієнтації."</string>
@@ -187,7 +182,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Обертати автоматично"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Обертання заблоковано"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Метод введення"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Поточне місцезнаходження"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Місцезнаходження"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Місцезнаходження вимкнено"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Носій"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Лише екстрені виклики"</string>
@@ -203,5 +199,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Сповіщення з’являються тут"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Отримуйте до них доступ будь-коли, провівши пальцем униз."\n"Знову проведіть униз, щоб відкрити елементи керування системи."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Отримуйте до них доступ будь-коли, провівши пальцем униз.\nЗнову проведіть униз, щоб відкрити елементи керування системи."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Гортайте від краю екрана, щоб з’явилась панель"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Проведіть пальцем від краю екрана, щоб з’явилась навігаційна панель"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index b56dd74..acc7e0e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Giao diện người dùng hệ thống"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Xóa"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Không làm phiền"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Hiển thị thông báo"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Xóa khỏi danh sách"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Thông tin về ứng dụng"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Không có ứng dụng nào gần đây"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> còn lại"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Không hỗ trợ sạc qua USB."\n"Chỉ sử dụng bộ sạc được cung cấp."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Cài đặt"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Sử dụng theo mặc định cho thiết bị USB này"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Sử dụng theo mặc định cho phụ kiện USB này"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Cho phép gỡ lỗi USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Tệp tham chiếu khóa RSA của máy tính là:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Tệp tham chiếu khóa RSA của máy tính là:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Luôn cho phép từ máy tính này"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"T.phóng để lấp đầy m.hình"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Giãn ra để lấp đầy m.hình"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Đã tắt dữ liệu 4G"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dữ liệu di động bị vô hiệu hóa"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Dữ liệu đã bị vô hiệu hóa"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Bạn đã đạt đến giới hạn sử dụng dữ liệu chỉ định."\n\n"Nếu bạn bật lại dữ liệu, bạn có thể bị nhà cung cấp tính phí."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Bạn đã đạt đến giới hạn sử dụng dữ liệu chỉ định.\n\nNếu bạn bật lại dữ liệu, bạn có thể bị nhà cung cấp tính phí."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Bật lại dữ liệu"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Thông tin về ứng dụng"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Đóng"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Tắt thông báo"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Chạm vào đây để bật lại thông báo."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Màn hình hiện bị khóa theo hướng ngang."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Màn hình hiện bị khóa theo hướng dọc."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Phương thức nhập"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Vị trí đang được sử dụng"</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>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Thiết bị phương tiện"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Chỉ cuộc gọi khẩn cấp"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Thông báo xuất hiện tại đây"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Truy cập vào chúng bất kỳ lúc nào bằng cách vuốt xuống."\n"Vuốt lại xuống để hiển thị các điều khiển hệ thống."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Truy cập vào chúng bất kỳ lúc nào bằng cách vuốt xuống.\nVuốt lại xuống để hiển thị các điều khiển hệ thống."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Vuốt cạnh màn hình để hiển thị thanh"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Vuốt từ cạnh màn hình để hiển thị thanh hệ thống"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d0811d9..0a62ee3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"系统用户界面"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"请勿打扰"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"显示通知"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"从列表中删除"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"应用信息"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"最近没有运行任何应用"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"请连接充电器"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"电池电量低。"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"还剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"不支持 USB 充电功能。"\n"只能使用随附的充电器充电。"</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"不支持 USB 充电功能。\n只能使用随附的充电器充电。"</string>
     <string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"默认情况下用于该 USB 设备"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"默认情况下用于该 USB 配件"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"允许 USB 调试吗?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"这台计算机的 RSA 密钥指纹如下:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"这台计算机的 RSA 密钥指纹如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"一律允许使用这台计算机进行调试"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"缩放以填满屏幕"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"拉伸以填满屏幕"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G 数据网络已停用"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"移动数据已停用"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"数据已停用"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已达到指定的数据流量上限。"\n\n"如果您重新启用数据,运营商可能会收取相应的费用。"</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已达到指定的数据流量上限。\n\n如果您重新启用数据,运营商可能会收取相应的费用。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"重新启用数据连接"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN 已连接"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"已通过 GPS 确定位置"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"应用信息"</string>
-    <string name="close_universe" msgid="3736513750241754348">"关闭"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"通知功能已停用"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"点按此处可重新启用通知功能。"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"屏幕锁定为横向模式。"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"屏幕锁定为纵向模式。"</string>
@@ -189,7 +184,10 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自动旋转"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"屏幕方向已锁定"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"输入法"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"位置信息"</string>
+    <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
+    <skip />
+    <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"媒体设备"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"只能拨打紧急呼救电话"</string>
@@ -205,5 +203,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"通知会显示在这里"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑动可随时查看通知。"\n"再次向下滑动可使用系统控制功能。"</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑动可随时查看通知。\n再次向下滑动可使用系统控制功能。"</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"从边缘向里滑可显示系统栏"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"从屏幕边缘向里滑动即可显示系统栏"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 170f15a..2cfdb59 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"系統 UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"勿干擾"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"顯示通知"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"從清單中移除"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"應用程式資訊"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"沒有最近使用的應用程式"</string>
@@ -37,7 +35,7 @@
     <string name="battery_low_title" msgid="2783104807551211639">"連接充電器"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"電池電量即將不足。"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。"\n"僅能使用隨附的充電器。"</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
     <string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"允許 USB 偵錯嗎?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"這台電腦的 RSA 金鑰指紋如下:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"這台電腦的 RSA 金鑰指紋如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"一律允許透過這台電腦進行"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
@@ -162,7 +160,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"已停用 4G 數據"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"已停用行動數據"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"數據已停用"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已達到指定的資料用量上限。"\n\n"如果您重新啟用數據傳輸,行動通訊業者可能會向您收費。"</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已達到指定的資料用量上限。\n\n如果您重新啟用數據傳輸,行動通訊業者可能會向您收費。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"重新啟用數據連線"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
@@ -170,9 +168,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"應用程式資訊"</string>
-    <string name="close_universe" msgid="3736513750241754348">"關閉"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"關閉通知"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"輕按這裡即可重新開啟通知。"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"螢幕會自動旋轉。"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"螢幕已鎖定為橫向模式。"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"螢幕已鎖定為垂直模式。"</string>
@@ -189,7 +184,8 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自動旋轉"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"已鎖定螢幕旋轉功能"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"輸入法"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"使用位置"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"定位"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"定位服務已關閉"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"媒體裝置"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"僅可撥打緊急電話"</string>
@@ -205,5 +201,7 @@
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"系統會在這裡顯示通知"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑動即可隨時存取通知。"\n"再次向下滑動即可使用系統控制項。"</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑動即可隨時存取通知。\n再次向下滑動即可使用系統控制項。"</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"滑動螢幕邊緣即可顯示導覽列"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"從螢幕邊緣向內滑動即可顯示導覽列"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8219ea7..007d338 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -21,8 +21,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"Uhlelo lwe-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Sula"</string>
-    <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ungaphazamisi"</string>
-    <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Bonisa izaziso"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Susa ohlwini"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Ulwazi lwensiza"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Azikho izinhlelo zokusebenza zakamuva"</string>
@@ -37,7 +35,7 @@
     <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_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> okusele"</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe."\n"Sebenzisa kuphela ishaja enikeziwe."</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="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"I-Wi-Fi"</string>
@@ -59,7 +57,7 @@
     <string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Sebenzisa ngokuzenzakalelayo kule-accessory ye-USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vumela ukulungisa iphutha le-USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"Izigxivizo zeminwe zokhiye we-RSA wekhompyutha ngu:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Izigxivizo zeminwe zokhiye we-RSA wekhompyutha ngu:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Hlala uvumela njalo kusuka kule khompyutha"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Sondeza ukugcwalisa isikrini"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Nweba ukugcwalisa isikrini"</string>
@@ -160,7 +158,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Idatha ye-4G ivimbelwe"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Idatha yefoni ivimbelwe"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Idatha ivimbelwe"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Usufike emkhawulweni wokusebenzisa i-ata. "\n\n"Uma uqla kabusha ukusebenza kwe-ata, kungenzek umhlinzeki akukhokhise."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Usufike emkhawulweni wokusebenzisa i-ata. \n\nUma uqla kabusha ukusebenza kwe-ata, kungenzek umhlinzeki akukhokhise."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Vumela futhi idatha"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
@@ -168,9 +166,6 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Indawo ihlelwe i-GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Susa zonke izaziso."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Ulwazi lohlelo lokusebenza"</string>
-    <string name="close_universe" msgid="3736513750241754348">"Vala"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Izaziso zivaliwe"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Thepha lapha ukuvula futhi izaziso."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Isikrini sizophenduka ngokuzenzakalela."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Isikrini sikhiyelwe ngomumo we-landscape."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Isikrini sikhiyelwe ngomumo we-portrait."</string>
@@ -187,7 +182,8 @@
     <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_ime_label" msgid="7073463064369468429">"Indlela yokungenayo"</string>
-    <string name="quick_settings_location_label" msgid="3292451598267467545">"Indawo iyasetshenziswa"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Indawo"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Indawo ivaliwe"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Idivayisi yemidiya"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Amakholi aphuthumayo kuphela"</string>
@@ -203,5 +199,7 @@
     <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="status_bar_help_title" msgid="1199237744086469217">"Izaziso zivela lapha"</string>
-    <string name="status_bar_help_text" msgid="7874607155052076323">"Kufinyelele noma kunini ngokuswayiphela phansi."\n"Swayiphela phansi futhi ngezilawuli zesistimu."</string>
+    <string name="status_bar_help_text" msgid="7874607155052076323">"Kufinyelele noma kunini ngokuswayiphela phansi.\nSwayiphela phansi futhi ngezilawuli zesistimu."</string>
+    <string name="hideybar_confirmation_message" msgid="9050869548951044371">"Swayipha unqenqema wesikrini ukuze uveze ibha"</string>
+    <string name="hideybar_confirmation_message_long" msgid="7117692795163620626">"Swayipha kusukela kunqenqema ukuze uveze ibha yesistimu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index cd6aaf6..bfb600d 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -40,4 +40,24 @@
         <item>@null</item>
     </array>
 
+    <!-- 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">
+        <item>73</item> <item>0</item>
+        <item>392</item><item>0</item>
+        <item>201</item><item>259</item>
+        <item>442</item><item>259</item>
+        <item>4</item>  <item>703</item>
+        <item>157</item><item>334</item>
+        <item>0</item>  <item>334</item>
+    </array>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index acb192d..2f0d0f9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -19,7 +19,10 @@
 <resources>
     <drawable name="notification_number_text_color">#ffffffff</drawable>
     <drawable name="ticker_background_color">#ff1d1d1d</drawable>
-    <drawable name="status_bar_background">#ff000000</drawable>
+    <drawable name="system_bar_background">#ff000000</drawable>
+    <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
+    <color name="system_bar_background_gradient_start">#8c000000</color> <!-- 55% black -->
+    <color name="system_bar_background_gradient_end">#00000000</color>
     <color name="notification_panel_solid_background">#ff000000</color>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
     <color name="status_bar_recents_app_label_color">#ffffffff</color>
@@ -27,12 +30,11 @@
     <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="intruder_bg_pressed">#ff33B5E5</drawable>
+    <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
     <drawable name="notification_header_bg">#FF000000</drawable>
-
-    <!-- ==================== system bar only ==================== -->
-    <drawable name="system_bar_background">#ff000000</drawable>
-    <!-- the darkening filter applied to notifications -->
-    <drawable name="notification_icon_area_smoke">#aa000000</drawable>
     <color name="notification_panel_scrim_color">#B0000000</color>
+    <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
+    <color name="batterymeter_charge_color">#FFFFFFFF</color>
+    <color name="batterymeter_bolt_color">#B2000000</color><!-- 70% black -->
+    <color name="status_bar_clock_color">#FFFFFFFF</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 92df9b9..3869db3 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -37,10 +37,6 @@
      interface.  This name is in the ComponentName flattened format (package/class)  -->
     <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
 
-    <!-- Component to be used as the system bar service.  Must implement the IStatusBar
-     interface.  This name is in the ComponentName flattened format (package/class)  -->
-    <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
-
     <!-- Whether or not we show the number in the bar. -->
     <bool name="config_statusBarShowNumber">false</bool>
 
@@ -91,6 +87,9 @@
     <!-- Whether rotation lock shows up in quick settings or not -->
     <bool name="quick_settings_show_rotation_lock">false</bool>
 
+    <!-- Whether or not the RSSI tile is capitalized or not. -->
+    <bool name="quick_settings_rssi_tile_capitalization">true</bool>
+
     <!-- Timeouts for brightness dialog to disappear -->
     <integer name="quick_settings_brightness_dialog_short_timeout">2000</integer>
     <integer name="quick_settings_brightness_dialog_long_timeout">4000</integer>
@@ -105,5 +104,11 @@
 
     <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
     <bool name="config_show4GForLTE">true</bool>
+
+    <!-- milliseconds before the heads up notification auto-dismisses. -->
+    <integer name="heads_up_notification_decay">3700</integer>
+
+    <!-- milliseconds before the heads up notification accepts touches. -->
+    <integer name="heads_up_sensitivity_delay">700</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f90f08a..cc78cb4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -89,7 +89,7 @@
     <dimen name="status_bar_icon_drawing_size">18dip</dimen>
 
     <!-- opacity at which Notification icons will be drawn in the status bar -->
-    <item type="dimen" name="status_bar_icon_drawing_alpha">65%</item>
+    <item type="dimen" name="status_bar_icon_drawing_alpha">75%</item>
 
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">0dp</dimen>
@@ -212,4 +212,12 @@
     <dimen name="qs_tile_margin_below_icon">17dp</dimen>
     <!-- Quick Settings tile geometry: icon size -->
     <dimen name="qs_tile_icon_size">32dp</dimen>
+    <!-- Quick Settings CA Cert Warning tile geometry: gap between icon and text -->
+    <dimen name="qs_cawarn_tile_margin_below_icon">3dp</dimen>
+
+    <!-- The width of the notification panel window: match_parent below sw600dp -->
+    <dimen name="notification_panel_width">-1dp</dimen>
+
+    <!-- used by DessertCase -->
+    <dimen name="dessert_case_cell_size">192dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
deleted file mode 100644
index 2cc3446..0000000
--- a/packages/SystemUI/res/values/ids.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2012 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-
-<resources>
-    <item type="id" name="expandable_tag" />
-    <item type="id" name="user_expanded_tag" />
-    <item type="id" name="user_lock_tag" />
-    <item type="id" name="status_bar_cling_stub" />
-</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5767e63..58865ab 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -24,17 +24,6 @@
          all of the currently visible notifications. [CHAR LIMIT=10]-->
     <string name="status_bar_clear_all_button">Clear</string>
 
-    <!-- The text for the button in the notification window-shade that turns
-         on do not disturb mode, where notifications no longer show their ticker,
-         no sound plays, and no icons are visible.  The windowshade continues to show
-         the notifications. [CHAR LIMIT=25]-->
-    <string name="status_bar_do_not_disturb_button">Do not disturb</string>
-
-    <!-- The text for the button in the notification window-shade that turns
-         off do not disturb mode.  After clicking this, notifications will be
-         shown again. [CHAR LIMIT=25] -->
-    <string name="status_bar_please_disturb_button">Show notifications</string>
-
     <!-- Title shown in recents popup for removing an application from the list -->
     <string name="status_bar_recent_remove_item_title">Remove from list</string>
 
@@ -171,12 +160,6 @@
          [CHAR LIMIT=25] -->
     <string name="compat_mode_off">Stretch to fill screen</string>
 
-    <!-- Compatibility mode help screen: header text. [CHAR LIMIT=50] -->
-    <string name="compat_mode_help_header">Compatibility zoom</string>
-
-    <!-- Compatibility mode help screen: body text. [CHAR LIMIT=150] -->
-    <string name="compat_mode_help_body">When an app was designed for a smaller screen, a zoom control will appear by the clock.</string>
-
     <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
     <string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
     <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->
@@ -209,6 +192,10 @@
     <string name="accessibility_menu">Menu</string>
     <!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_recent">Recent apps</string>
+    <!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_search_light">Search</string>
+    <!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_camera_button">Camera</string>
 
     <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_ime_switch_button">Switch input method button.</string>
@@ -429,6 +416,9 @@
     <!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] -->
     <string name="gps_notification_found_text">Location set by GPS</string>
 
+    <!-- Accessibility text describing the presence of active location requests by one or more apps -->
+    <string name="accessibility_location_active">Location requests active</string>
+
     <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_clear_all">Clear all notifications.</string>
 
@@ -436,16 +426,6 @@
          application -->
     <string name="status_bar_notification_inspect_item_title">App info</string>
 
-    <!-- [CHAR LIMIT=NONE] -->
-    <string name="close_universe">Close</string>
-
-    <!-- Title for the pseudo-notification shown when notifications are disabled (do-not-disturb
-         mode) -->
-    <string name="notifications_off_title">Notifications off</string>
-
-    <!-- Content text for do-not-disturb mode notification -->
-    <string name="notifications_off_text">Tap here to turn notifications back on.</string>
-
     <!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is on. [CHAR LIMIT=NONE] -->
     <string name="accessibility_rotation_lock_off">Screen will rotate automatically.</string>
 
@@ -455,8 +435,8 @@
     <!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is off. [CHAR LIMIT=NONE] -->
     <string name="accessibility_rotation_lock_on_portrait">Screen is locked in portrait orientation.</string>
 
-    <!-- Name of the Jelly Bean platlogo screensaver -->
-    <string name="jelly_bean_dream_name">BeanFlinger</string>
+    <!-- Name of the K-release easter egg: a display case for all our tastiest desserts. [CHAR LIMIT=30] -->
+    <string name="dessert_case">Dessert Case</string>
 
     <!-- Name of the launcher shortcut icon that allows dreams to be started immediately [CHAR LIMIT=20] -->
     <string name="start_dreams">Daydream</string>
@@ -485,7 +465,9 @@
     <!-- QuickSettings: IME [CHAR LIMIT=NONE] -->
     <string name="quick_settings_ime_label">Input Method</string>
     <!-- QuickSettings: Location [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_location_label">Location in use</string>
+    <string name="quick_settings_location_label">Location</string>
+    <!-- QuickSettings: Location (Off) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_location_off_label">Location Off</string>
     <!-- QuickSettings: Media device [CHAR LIMIT=NONE] -->
     <string name="quick_settings_media_device_label">Media device</string>
     <!-- QuickSettings: RSSI [CHAR LIMIT=NONE] -->
@@ -515,8 +497,14 @@
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
 
-    <!-- Title of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
-    <string name="status_bar_help_title">Notifications appear here</string>
-    <!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
-    <string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</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>
+
+    <!-- Shows up when there is a user SSL CA Cert installed on the
+         device.  Indicates to the user that SSL traffic can be intercepted.
+         If the text fits on one line (~14 chars), it should start with a
+         linebreak to position it correctly.  [CHAR LIMIT=45] -->
+    <string name="ssl_ca_cert_warning">Network may\nbe monitored</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 7ddf261..54f03bd 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -34,7 +34,7 @@
         <item name="android:wallpaperIntraOpenExitAnimation">@anim/wallpaper_recents_launch_from_launcher_exit</item>
     </style>
 
-    <style name="TextAppearance.StatusBar.IntruderAlert"
+    <style name="TextAppearance.StatusBar.HeadsUp"
         parent="@*android:style/TextAppearance.StatusBar">
     </style>
 
@@ -56,13 +56,7 @@
         <!-- Note: must be dp to fit in status bar -->
         <item name="android:textSize">16dp</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">@android:color/holo_blue_light</item>
-    </style>
-
-    <style name="TextAppearance.StatusBar.Date" parent="@*android:style/TextAppearance.StatusBar.Icon">
-        <item name="android:textSize">16dp</item>
-        <item name="android:textStyle">normal</item>
-        <item name="android:textColor">@android:color/holo_blue_light</item>
+        <item name="android:textColor">@color/status_bar_clock_color</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" />
@@ -122,6 +116,10 @@
         <item name="android:textColor">#ff3a3b39</item>
     </style>
 
+    <style name="TextAppearance.QuickSettings.CaCertWarning" parent="@style/TextAppearance.QuickSettings.TileView">
+        <item name="android:textAllCaps">false</item>
+    </style>
+
     <style name="TextAppearance.QuickSettings.TileView.User" parent="@style/TextAppearance.QuickSettings.TileView">
         <item name="android:background">#CC000000</item>
         <item name="android:padding">4dp</item>
@@ -154,9 +152,9 @@
     <style name="Animation.StatusBar">
     </style>
 
-    <style name="Animation.StatusBar.IntruderAlert">
-        <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
-        <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
+    <style name="Animation.StatusBar.HeadsUp">
+        <item name="android:windowEnterAnimation">@anim/heads_up_enter</item>
+        <item name="android:windowExitAnimation">@anim/heads_up_exit</item>
     </style>
 
     <style name="TextAppearance.StatusBar.PhoneTicker"
@@ -165,33 +163,4 @@
         <item name="android:textSize">14dp</item>
     </style>
     
-    <style name="ClingButton">
-        <item name="android:layout_width">wrap_content</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:paddingTop">10dp</item>
-        <item name="android:paddingBottom">15dp</item>
-        <item name="android:paddingLeft">35dp</item>
-        <item name="android:paddingRight">35dp</item>
-        <item name="android:textStyle">bold</item>
-        <item name="android:background">@drawable/cling_button_bg</item>
-    </style>
-    <style name="ClingTitleText">
-        <item name="android:layout_width">wrap_content</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginBottom">5dp</item>
-        <item name="android:textSize">23sp</item>
-        <item name="android:textColor">#49C0EC</item>
-        <item name="android:shadowColor">#000000</item>
-        <item name="android:shadowDy">2</item>
-        <item name="android:shadowRadius">2.0</item>
-    </style>
-    <style name="ClingText">
-        <item name="android:textSize">15sp</item>
-        <item name="android:textColor">#FFFFFF</item>
-        <item name="android:shadowColor">#000000</item>
-        <item name="android:shadowDy">2</item>
-        <item name="android:shadowRadius">2.0</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
-    </style>
-
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
new file mode 100755
index 0000000..150f132
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -0,0 +1,378 @@
+/*
+ * 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.systemui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class BatteryMeterView extends View implements DemoMode {
+    public static final String TAG = BatteryMeterView.class.getSimpleName();
+    public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
+
+    public static final boolean ENABLE_PERCENT = true;
+    public static final boolean SINGLE_DIGIT_PERCENT = false;
+    public static final boolean SHOW_100_PERCENT = false;
+
+    public static final int FULL = 96;
+    public static final int EMPTY = 4;
+
+    public static final float SUBPIXEL = 0.4f;  // inset rects for softer edges
+
+    int[] mColors;
+
+    boolean mShowPercent = true;
+    Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
+    int mButtonHeight;
+    private float mTextHeight, mWarningTextHeight;
+
+    private int mHeight;
+    private int mWidth;
+    private String mWarningString;
+    private final int mChargeColor;
+    private final float[] mBoltPoints;
+    private final Path mBoltPath = new Path();
+
+    private final RectF mFrame = new RectF();
+    private final RectF mButtonFrame = new RectF();
+    private final RectF mClipFrame = new RectF();
+    private final Rect mBoltFrame = new Rect();
+
+    private class BatteryTracker extends BroadcastReceiver {
+        // current battery status
+        int level;
+        String percentStr;
+        int plugType;
+        boolean plugged;
+        int health;
+        int status;
+        String technology;
+        int voltage;
+        int temperature;
+        boolean testmode = false;
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+                if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
+
+                level = (int)(100f
+                        * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
+                        / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
+
+                plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+                plugged = plugType != 0;
+                health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
+                        BatteryManager.BATTERY_HEALTH_UNKNOWN);
+                status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
+                        BatteryManager.BATTERY_STATUS_UNKNOWN);
+                technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
+                voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
+                temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
+
+                setContentDescription(
+                        context.getString(R.string.accessibility_battery_level, level));
+                postInvalidate();
+            } else if (action.equals(ACTION_LEVEL_TEST)) {
+                testmode = true;
+                post(new Runnable() {
+                    int curLevel = 0;
+                    int incr = 1;
+                    int saveLevel = level;
+                    int savePlugged = plugType;
+                    Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+                    @Override
+                    public void run() {
+                        if (curLevel < 0) {
+                            testmode = false;
+                            dummy.putExtra("level", saveLevel);
+                            dummy.putExtra("plugged", savePlugged);
+                            dummy.putExtra("testmode", false);
+                        } else {
+                            dummy.putExtra("level", curLevel);
+                            dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC : 0);
+                            dummy.putExtra("testmode", true);
+                        }
+                        getContext().sendBroadcast(dummy);
+
+                        if (!testmode) return;
+
+                        curLevel += incr;
+                        if (curLevel == 100) {
+                            incr *= -1;
+                        }
+                        postDelayed(this, 200);
+                    }
+                });
+            }
+        }
+    }
+
+    BatteryTracker mTracker = new BatteryTracker();
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        filter.addAction(ACTION_LEVEL_TEST);
+        getContext().registerReceiver(mTracker, filter);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        getContext().unregisterReceiver(mTracker);
+    }
+
+    public BatteryMeterView(Context context) {
+        this(context, null, 0);
+    }
+
+    public BatteryMeterView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final Resources res = context.getResources();
+        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
+        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
+
+        final int N = levels.length();
+        mColors = new int[2*N];
+        for (int i=0; i<N; i++) {
+            mColors[2*i] = levels.getInt(i, 0);
+            mColors[2*i+1] = colors.getColor(i, 0);
+        }
+        levels.recycle();
+        colors.recycle();
+        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);
+
+        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mFramePaint.setColor(res.getColor(R.color.batterymeter_frame_color));
+        mFramePaint.setDither(true);
+        mFramePaint.setStrokeWidth(0);
+        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+        mFramePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
+
+        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBatteryPaint.setDither(true);
+        mBatteryPaint.setStrokeWidth(0);
+        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint.setColor(0xFFFFFFFF);
+        Typeface font = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
+        mTextPaint.setTypeface(font);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mWarningTextPaint.setColor(mColors[1]);
+        font = Typeface.create("sans-serif", Typeface.BOLD);
+        mWarningTextPaint.setTypeface(font);
+        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+
+        mBoltPaint = new Paint();
+        mBoltPaint.setAntiAlias(true);
+        mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
+        mBoltPoints = loadBoltPoints(res);
+        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+    }
+
+    private static float[] loadBoltPoints(Resources res) {
+        final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+        int maxX = 0, maxY = 0;
+        for (int i = 0; i < pts.length; i += 2) {
+            maxX = Math.max(maxX, pts[i]);
+            maxY = Math.max(maxY, pts[i + 1]);
+        }
+        final float[] ptsF = new float[pts.length];
+        for (int i = 0; i < pts.length; i += 2) {
+            ptsF[i] = (float)pts[i] / maxX;
+            ptsF[i + 1] = (float)pts[i + 1] / maxY;
+        }
+        return ptsF;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        mHeight = h;
+        mWidth = w;
+        mWarningTextPaint.setTextSize(h * 0.75f);
+        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+    }
+
+    private int getColorForLevel(int percent) {
+        int thresh, color = 0;
+        for (int i=0; i<mColors.length; i+=2) {
+            thresh = mColors[i];
+            color = mColors[i+1];
+            if (percent <= thresh) return color;
+        }
+        return color;
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
+        final int level = tracker.level;
+        float drawFrac = (float) level / 100f;
+        final int pt = getPaddingTop();
+        final int pl = getPaddingLeft();
+        final int pr = getPaddingRight();
+        final int pb = getPaddingBottom();
+        int height = mHeight - pt - pb;
+        int width = mWidth - pl - pr;
+
+        mButtonHeight = (int) (height * 0.12f);
+
+        mFrame.set(0, 0, width, height);
+        mFrame.offset(pl, pt);
+
+        mButtonFrame.set(
+                mFrame.left + width * 0.25f,
+                mFrame.top,
+                mFrame.right - width * 0.25f,
+                mFrame.top + mButtonHeight + 5 /*cover frame border of intersecting area*/);
+
+        mButtonFrame.top += SUBPIXEL;
+        mButtonFrame.left += SUBPIXEL;
+        mButtonFrame.right -= SUBPIXEL;
+
+        mFrame.top += mButtonHeight;
+        mFrame.left += SUBPIXEL;
+        mFrame.top += SUBPIXEL;
+        mFrame.right -= SUBPIXEL;
+        mFrame.bottom -= SUBPIXEL;
+
+        // first, draw the battery shape
+        c.drawRect(mFrame, mFramePaint);
+
+        // fill 'er up
+        final int color = tracker.plugged ? mChargeColor : getColorForLevel(level);
+        mBatteryPaint.setColor(color);
+
+        if (level >= FULL) {
+            drawFrac = 1f;
+        } else if (level <= EMPTY) {
+            drawFrac = 0f;
+        }
+
+        c.drawRect(mButtonFrame, drawFrac == 1f ? mBatteryPaint : mFramePaint);
+
+        mClipFrame.set(mFrame);
+        mClipFrame.top += (mFrame.height() * (1f - drawFrac));
+
+        c.save(Canvas.CLIP_SAVE_FLAG);
+        c.clipRect(mClipFrame);
+        c.drawRect(mFrame, mBatteryPaint);
+        c.restore();
+
+        if (tracker.plugged) {
+            // draw the bolt
+            final int bl = (int)(mFrame.left + mFrame.width() / 4.5f);
+            final int bt = (int)(mFrame.top + mFrame.height() / 6f);
+            final int br = (int)(mFrame.right - mFrame.width() / 7f);
+            final int bb = (int)(mFrame.bottom - mFrame.height() / 10f);
+            if (mBoltFrame.left != bl || mBoltFrame.top != bt
+                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+                mBoltFrame.set(bl, bt, br, bb);
+                mBoltPath.reset();
+                mBoltPath.moveTo(
+                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+                for (int i = 2; i < mBoltPoints.length; i += 2) {
+                    mBoltPath.lineTo(
+                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+                }
+                mBoltPath.lineTo(
+                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+            }
+            c.drawPath(mBoltPath, mBoltPaint);
+        } else if (level <= EMPTY) {
+            final float x = mWidth * 0.5f;
+            final float y = (mHeight + mWarningTextHeight) * 0.48f;
+            c.drawText(mWarningString, x, y, mWarningTextPaint);
+        } else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
+            mTextPaint.setTextSize(height *
+                    (SINGLE_DIGIT_PERCENT ? 0.75f
+                            : (tracker.level == 100 ? 0.38f : 0.5f)));
+            mTextHeight = -mTextPaint.getFontMetrics().ascent;
+
+            final String str = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+            final float x = mWidth * 0.5f;
+            final float y = (mHeight + mTextHeight) * 0.47f;
+            c.drawText(str,
+                    x,
+                    y,
+                    mTextPaint);
+        }
+    }
+
+    private boolean mDemoMode;
+    private BatteryTracker mDemoTracker = new BatteryTracker();
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+            mDemoTracker.level = mTracker.level;
+            mDemoTracker.plugged = mTracker.plugged;
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            postInvalidate();
+        } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
+           String level = args.getString("level");
+           String plugged = args.getString("plugged");
+           if (level != null) {
+               mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
+           }
+           if (plugged != null) {
+               mDemoTracker.plugged = Boolean.parseBoolean(plugged);
+           }
+           postInvalidate();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBag.java b/packages/SystemUI/src/com/android/systemui/BeanBag.java
deleted file mode 100644
index f5a90ca..0000000
--- a/packages/SystemUI/src/com/android/systemui/BeanBag.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*);
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.animation.AnimatorSet;
-import android.animation.PropertyValuesHolder;
-import android.animation.ObjectAnimator;
-import android.animation.TimeAnimator;
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import java.util.HashMap;
-import java.util.Random;
-
-public class BeanBag extends Activity {
-    final static boolean DEBUG = false;
-
-    public static class Board extends FrameLayout
-    {
-        static Random sRNG = new Random();
-
-        static float lerp(float a, float b, float f) {
-            return (b-a)*f + a;
-        }
-
-        static float randfrange(float a, float b) {
-            return lerp(a, b, sRNG.nextFloat());
-        }
-
-        static int randsign() {
-            return sRNG.nextBoolean() ? 1 : -1;
-        }
-
-        static boolean flip() {
-            return sRNG.nextBoolean();
-        }
-
-        static float mag(float x, float y) {
-            return (float) Math.sqrt(x*x+y*y);
-        }
-
-        static float clamp(float x, float a, float b) {
-            return ((x<a)?a:((x>b)?b:x));
-        }
-
-        static float dot(float x1, float y1, float x2, float y2) {
-            return x1*x2+y1+y2;
-        }
-
-        static <E> E pick(E[] array) {
-            if (array.length == 0) return null;
-            return array[sRNG.nextInt(array.length)];
-        }
-
-        static int pickInt(int[] array) {
-            if (array.length == 0) return 0;
-            return array[sRNG.nextInt(array.length)];
-        }
-
-        static int NUM_BEANS = 40;
-        static float MIN_SCALE = 0.2f;
-        static float MAX_SCALE = 1f;
-
-        static float LUCKY = 0.001f;
-
-        static int MAX_RADIUS = (int)(576 * MAX_SCALE);
-
-        static int BEANS[] = {
-          R.drawable.redbean0,
-          R.drawable.redbean0,
-          R.drawable.redbean0,
-          R.drawable.redbean0,
-          R.drawable.redbean1,
-          R.drawable.redbean1,
-          R.drawable.redbean2,
-          R.drawable.redbean2,
-          R.drawable.redbeandroid,
-        };
-
-        static int COLORS[] = {
-            0xFF00CC00,
-            0xFFCC0000,
-            0xFF0000CC,
-            0xFFFFFF00,
-            0xFFFF8000,
-            0xFF00CCFF,
-            0xFFFF0080,
-            0xFF8000FF,
-            0xFFFF8080,
-            0xFF8080FF,
-            0xFFB0C0D0,
-            0xFFDDDDDD,
-            0xFF333333,
-        };
-
-        public class Bean extends ImageView {
-            public static final float VMAX = 1000.0f;
-            public static final float VMIN = 100.0f;
-
-            public float x, y, a;
-
-            public float va;
-            public float vx, vy;
-
-            public float r;
-
-            public float z;
-
-            public int h,w;
-
-            public boolean grabbed;
-            public float grabx, graby;
-            public long grabtime;
-            private float grabx_offset, graby_offset;
-
-            public Bean(Context context, AttributeSet as) {
-                super(context, as);
-            }
-
-            public String toString() {
-                return String.format("<bean (%.1f, %.1f) (%d x %d)>",
-                    getX(), getY(), getWidth(), getHeight());
-            }
-
-            private void pickBean() {
-                int beanId = pickInt(BEANS);
-                if (randfrange(0,1) <= LUCKY) {
-                    beanId = R.drawable.jandycane;
-                }
-                BitmapDrawable bean = (BitmapDrawable) getContext().getResources().getDrawable(beanId);
-                Bitmap beanBits = bean.getBitmap();
-                h=beanBits.getHeight();
-                w=beanBits.getWidth();
-
-                if (DEBUG) {
-                    bean.setAlpha(0x80);
-                }
-                this.setImageDrawable(bean);
-
-                Paint pt = new Paint();
-                final int color = pickInt(COLORS);
-                ColorMatrix CM = new ColorMatrix();
-                float[] M = CM.getArray();
-                // we assume the color information is in the red channel
-                /* R */ M[0]  = (float)((color & 0x00FF0000) >> 16) / 0xFF;
-                /* G */ M[5]  = (float)((color & 0x0000FF00) >> 8)  / 0xFF;
-                /* B */ M[10] = (float)((color & 0x000000FF))       / 0xFF;
-                pt.setColorFilter(new ColorMatrixColorFilter(M));
-                setLayerType(View.LAYER_TYPE_HARDWARE, (beanId == R.drawable.jandycane) ? null : pt);
-            }
-
-            public void reset() {
-                pickBean();
-
-                final float scale = lerp(MIN_SCALE,MAX_SCALE,z);
-                setScaleX(scale); setScaleY(scale);
-
-                r = 0.3f*Math.max(h,w)*scale;
-
-                a=(randfrange(0,360));
-                va = randfrange(-30,30);
-
-                vx = randfrange(-40,40) * z;
-                vy = randfrange(-40,40) * z;
-                final float boardh = boardHeight;
-                final float boardw = boardWidth;
-                //android.util.Log.d("BeanBag", "reset: w="+w+" h="+h);
-                if (flip()) {
-                    x=(vx < 0 ? boardw+2*r : -r*4f);
-                    y=(randfrange(0, boardh-3*r)*0.5f + ((vy < 0)?boardh*0.5f:0));
-                } else {
-                    y=(vy < 0 ? boardh+2*r : -r*4f);
-                    x=(randfrange(0, boardw-3*r)*0.5f + ((vx < 0)?boardw*0.5f:0));
-                }
-            }
-
-            public void update(float dt) {
-                if (grabbed) {
-//                    final float interval = (SystemClock.uptimeMillis() - grabtime) / 1000f;
-                    vx = (vx * 0.75f) + ((grabx - x) / dt) * 0.25f;
-                    x = grabx;
-                    vy = (vy * 0.75f) + ((graby - y) / dt) * 0.25f;;
-                    y = graby;
-                } else {
-                    x = (x + vx * dt);
-                    y = (y + vy * dt);
-                    a = (a + va * dt);
-                }
-            }
-
-            public float overlap(Bean other) {
-                final float dx = (x - other.x);
-                final float dy = (y - other.y);
-                return mag(dx, dy) - r - other.r;
-            }
-
-            @Override
-            public boolean onTouchEvent(MotionEvent e) {
-                switch (e.getAction()) {
-                    case MotionEvent.ACTION_DOWN:
-                        grabbed = true;
-                        grabx_offset = e.getRawX() - x;
-                        graby_offset = e.getRawY() - y;
-                        va = 0;
-                        // fall
-                    case MotionEvent.ACTION_MOVE:
-                        grabx = e.getRawX() - grabx_offset;
-                        graby = e.getRawY() - graby_offset;
-                        grabtime = e.getEventTime();
-                        break;
-                    case MotionEvent.ACTION_CANCEL:
-                    case MotionEvent.ACTION_UP:
-                        grabbed = false;
-                        float a = randsign() * clamp(mag(vx, vy) * 0.33f, 0, 1080f);
-                        va = randfrange(a*0.5f, a);
-                        break;
-                }
-                return true;
-            }
-        }
-
-        TimeAnimator mAnim;
-        private int boardWidth;
-        private int boardHeight;
-
-        public Board(Context context, AttributeSet as) {
-            super(context, as);
-
-            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
-
-            setWillNotDraw(!DEBUG);
-        }
-
-        private void reset() {
-//            android.util.Log.d("Nyandroid", "board reset");
-            removeAllViews();
-
-            final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams(
-                        ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-
-            for(int i=0; i<NUM_BEANS; i++) {
-                Bean nv = new Bean(getContext(), null);
-                addView(nv, wrap);
-                nv.z = ((float)i/NUM_BEANS);
-                nv.z *= nv.z;
-                nv.reset();
-                nv.x = (randfrange(0, boardWidth));
-                nv.y = (randfrange(0, boardHeight));
-            }
-
-            if (mAnim != null) {
-                mAnim.cancel();
-            }
-            mAnim = new TimeAnimator();
-            mAnim.setTimeListener(new TimeAnimator.TimeListener() {
-                private long lastPrint = 0;
-                public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
-                    if (DEBUG && totalTime - lastPrint > 5000) {
-                        lastPrint = totalTime;
-                        for (int i=0; i<getChildCount(); i++) {
-                            android.util.Log.d("BeanBag", "bean " + i + ": " + getChildAt(i));
-                        }
-                    }
-
-                    for (int i=0; i<getChildCount(); i++) {
-                        View v = getChildAt(i);
-                        if (!(v instanceof Bean)) continue;
-                        Bean nv = (Bean) v;
-                        nv.update(deltaTime / 1000f);
-
-                        for (int j=i+1; j<getChildCount(); j++) {
-                            View v2 = getChildAt(j);
-                            if (!(v2 instanceof Bean)) continue;
-                            Bean nv2 = (Bean) v2;
-                            final float overlap = nv.overlap(nv2);
-                        }
-
-                        nv.setRotation(nv.a);
-                        nv.setX(nv.x-nv.getPivotX());
-                        nv.setY(nv.y-nv.getPivotY());
-
-                        if (   nv.x < - MAX_RADIUS
-                            || nv.x > boardWidth + MAX_RADIUS
-                            || nv.y < -MAX_RADIUS
-                            || nv.y > boardHeight + MAX_RADIUS)
-                        {
-                            nv.reset();
-                        }
-                    }
-
-                    if (DEBUG) invalidate();
-                }
-            });
-        }
-
-        @Override
-        protected void onSizeChanged (int w, int h, int oldw, int oldh) {
-            super.onSizeChanged(w,h,oldw,oldh);
-            boardWidth = w;
-            boardHeight = h;
-//            android.util.Log.d("Nyandroid", "resized: " + w + "x" + h);
-        }
-
-        public void startAnimation() {
-            stopAnimation();
-            if (mAnim == null) {
-                post(new Runnable() { public void run() {
-                    reset();
-                    startAnimation();
-                } });
-            } else {
-                mAnim.start();
-            }
-        }
-
-        public void stopAnimation() {
-            if (mAnim != null) mAnim.cancel();
-        }
-
-        @Override
-        protected void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            stopAnimation();
-        }
-
-        @Override
-        public boolean isOpaque() {
-            return false;
-        }
-
-        @Override
-        public void onDraw(Canvas c) {
-            if (DEBUG) {
-                //android.util.Log.d("BeanBag", "onDraw");
-                Paint pt = new Paint();
-                pt.setAntiAlias(true);
-                pt.setStyle(Paint.Style.STROKE);
-                pt.setColor(0xFFFF0000);
-                pt.setStrokeWidth(4.0f);
-                c.drawRect(0, 0, getWidth(), getHeight(), pt);
-                pt.setColor(0xFFFFCC00);
-                pt.setStrokeWidth(1.0f);
-                for (int i=0; i<getChildCount(); i++) {
-                    Bean b = (Bean) getChildAt(i);
-                    final float a = (360-b.a)/180f*3.14159f;
-                    final float tx = b.getTranslationX();
-                    final float ty = b.getTranslationY();
-                    c.drawCircle(b.x, b.y, b.r, pt);
-                    c.drawCircle(tx, ty, 4, pt);
-                    c.drawLine(b.x, b.y, (float)(b.x+b.r*Math.sin(a)), (float)(b.y+b.r*Math.cos(a)), pt);
-                }
-            }
-        }
-    }
-
-    private Board mBoard;
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        // ACHIEVEMENT UNLOCKED
-        PackageManager pm = getPackageManager();
-        pm.setComponentEnabledSetting(new ComponentName(this, BeanBagDream.class),
-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
-
-        getWindow().addFlags(
-                  WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
-                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
-                );
-        mBoard = new Board(this, null);
-        setContentView(mBoard);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        mBoard.stopAnimation();
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        mBoard.startAnimation();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
deleted file mode 100644
index 39e4727..0000000
--- a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.service.dreams.DreamService;
-
-import com.android.systemui.BeanBag.Board;
-
-public class BeanBagDream extends DreamService {
-
-    private Board mBoard;
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        setInteractive(true);
-        setFullscreen(true);
-        mBoard = new Board(this, null);
-        setContentView(mBoard);
-    }
-
-    @Override
-    public void onDreamingStarted() {
-        super.onDreamingStarted();
-        mBoard.startAnimation();
-    }
-
-    @Override
-    public void onDreamingStopped() {
-        mBoard.stopAnimation();
-        super.onDreamingStopped();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
index d3ce30d..8e24eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/BootReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
@@ -21,7 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
-import android.util.Slog;
+import android.util.Log;
 
 /**
  * Performs a number of miscellaneous, non-system-critical actions
@@ -40,7 +40,7 @@
                 context.startService(loadavg);
             }
         } catch (Exception e) {
-            Slog.e(TAG, "Can't start load average service", e);
+            Log.e(TAG, "Can't start load average service", e);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/DemoMode.java b/packages/SystemUI/src/com/android/systemui/DemoMode.java
new file mode 100644
index 0000000..8d271e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DemoMode.java
@@ -0,0 +1,34 @@
+/*
+ * 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.systemui;
+
+import android.os.Bundle;
+
+public interface DemoMode {
+
+    void dispatchDemoCommand(String command, Bundle args);
+
+    public static final String ACTION_DEMO = "com.android.systemui.demo";
+
+    public static final String COMMAND_ENTER = "enter";
+    public static final String COMMAND_EXIT = "exit";
+    public static final String COMMAND_CLOCK = "clock";
+    public static final String COMMAND_BATTERY = "battery";
+    public static final String COMMAND_NETWORK = "network";
+    public static final String COMMAND_BARS = "bars";
+    public static final String COMMAND_STATUS = "status";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java
new file mode 100644
index 0000000..dd4c018
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCase.java
@@ -0,0 +1,66 @@
+/*
+ * 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.systemui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.util.Slog;
+import android.view.animation.DecelerateInterpolator;
+
+public class DessertCase extends Activity {
+    DessertCaseView mView;
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        PackageManager pm = getPackageManager();
+        final ComponentName cn = new ComponentName(this, DessertCaseDream.class);
+        if (pm.getComponentEnabledSetting(cn) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED");
+            pm.setComponentEnabledSetting(cn,
+                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+        }
+
+        mView = new DessertCaseView(this);
+
+        DessertCaseView.RescalingContainer container = new DessertCaseView.RescalingContainer(this);
+
+        container.setView(mView);
+
+        setContentView(container);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mView.postDelayed(new Runnable() {
+            public void run() {
+                mView.start();
+            }
+        }, 1000);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mView.stop();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
new file mode 100644
index 0000000..a627cf6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
@@ -0,0 +1,54 @@
+/*
+ * 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.systemui;
+
+import android.service.dreams.DreamService;
+
+public class DessertCaseDream extends DreamService {
+    private DessertCaseView mView;
+    private DessertCaseView.RescalingContainer mContainer;
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        setInteractive(false);
+
+        mView = new DessertCaseView(this);
+
+        mContainer = new DessertCaseView.RescalingContainer(this);
+
+        mContainer.setView(mView);
+
+        setContentView(mContainer);
+    }
+
+    @Override
+    public void onDreamingStarted() {
+        super.onDreamingStarted();
+        mView.postDelayed(new Runnable() {
+            public void run() {
+                mView.start();
+            }
+        }, 1000);
+    }
+
+    @Override
+    public void onDreamingStopped() {
+        super.onDreamingStopped();
+        mView.stop();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
new file mode 100644
index 0000000..99c59d5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
@@ -0,0 +1,505 @@
+/*
+ * 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.systemui;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.*;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class DessertCaseView extends FrameLayout {
+    private static final String TAG = DessertCaseView.class.getSimpleName();
+
+    private static final boolean DEBUG = false;
+
+    static final int START_DELAY = 5000;
+    static final int DELAY = 2000;
+    static final int DURATION = 500;
+
+    private static final int TAG_POS = 0x2000001;
+    private static final int TAG_SPAN = 0x2000002;
+
+    private static final int[] PASTRIES = {
+            R.drawable.dessert_kitkat,      // used with permission
+            R.drawable.dessert_android,     // thx irina
+    };
+
+    private static final int[] RARE_PASTRIES = {
+            R.drawable.dessert_cupcake,     // 2009
+            R.drawable.dessert_donut,       // 2009
+            R.drawable.dessert_eclair,      // 2009
+            R.drawable.dessert_froyo,       // 2010
+            R.drawable.dessert_gingerbread, // 2010
+            R.drawable.dessert_honeycomb,   // 2011
+            R.drawable.dessert_ics,         // 2011
+            R.drawable.dessert_jellybean,   // 2012
+    };
+
+    private static final int[] XRARE_PASTRIES = {
+            R.drawable.dessert_petitfour,   // the original and still delicious
+
+            R.drawable.dessert_donutburger, // remember kids, this was long before cronuts
+
+            R.drawable.dessert_flan,        //     sholes final approach
+                                            //     landing gear punted to flan
+                                            //     runway foam glistens
+                                            //         -- mcleron
+
+            R.drawable.dessert_keylimepie,  // from an alternative timeline
+    };
+    private static final int[] XXRARE_PASTRIES = {
+            R.drawable.dessert_zombiegingerbread, // thx hackbod
+            R.drawable.dessert_dandroid,    // thx morrildl
+            R.drawable.dessert_jandycane,   // thx nes
+    };
+
+    private static final int NUM_PASTRIES = PASTRIES.length + RARE_PASTRIES.length
+            + XRARE_PASTRIES.length + XXRARE_PASTRIES.length;
+
+    private SparseArray<Drawable> mDrawables = new SparseArray<Drawable>(NUM_PASTRIES);
+
+    private static final float[] MASK = {
+            0f,  0f,  0f,  0f, 255f,
+            0f,  0f,  0f,  0f, 255f,
+            0f,  0f,  0f,  0f, 255f,
+            1f,  0f,  0f,  0f, 0f
+    };
+
+    private static final float[] WHITE_MASK = {
+            0f,  0f,  0f,  0f, 255f,
+            0f,  0f,  0f,  0f, 255f,
+            0f,  0f,  0f,  0f, 255f,
+            -1f,  0f,  0f,  0f, 255f
+    };
+
+    public static final float SCALE = 0.25f; // natural display size will be SCALE*mCellSize
+
+    private static final float PROB_2X = 0.33f;
+    private static final float PROB_3X = 0.1f;
+    private static final float PROB_4X = 0.01f;
+
+    private boolean mStarted;
+
+    private int mCellSize;
+    private int mWidth, mHeight;
+    private int mRows, mColumns;
+    private View[] mCells;
+
+    private final Set<Point> mFreeList = new HashSet<Point>();
+
+    private final Handler mHandler = new Handler();
+
+    private final Runnable mJuggle = new Runnable() {
+        @Override
+        public void run() {
+            final int N = getChildCount();
+
+            final int K = 1; //irand(1,3);
+            for (int i=0; i<K; i++) {
+                final View child = getChildAt((int) (Math.random() * N));
+                place(child, true);
+            }
+
+            fillFreeList();
+
+            if (mStarted) {
+                mHandler.postDelayed(mJuggle, DELAY);
+            }
+        }
+    };
+
+    public DessertCaseView(Context context) {
+        this(context, null);
+    }
+
+    public DessertCaseView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DessertCaseView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final Resources res = getResources();
+
+        mStarted = false;
+
+        mCellSize = res.getDimensionPixelSize(R.dimen.dessert_case_cell_size);
+        final BitmapFactory.Options opts = new BitmapFactory.Options();
+        if (mCellSize < 512) { // assuming 512x512 images
+            opts.inSampleSize = 2;
+        }
+        for (int[] list : new int[][] { PASTRIES, RARE_PASTRIES, XRARE_PASTRIES, XXRARE_PASTRIES }) {
+            for (int resid : list) {
+                final BitmapDrawable d = new BitmapDrawable(res,
+                        BitmapFactory.decodeResource(res, resid, opts));
+                d.setColorFilter(new ColorMatrixColorFilter(MASK));
+                d.setBounds(0, 0, mCellSize, mCellSize);
+                mDrawables.append(resid, d);
+            }
+        }
+        if (DEBUG) setWillNotDraw(false);
+    }
+
+    public void start() {
+        if (!mStarted) {
+            mStarted = true;
+            fillFreeList(DURATION * 4);
+        }
+        mHandler.postDelayed(mJuggle, START_DELAY);
+    }
+
+    public void stop() {
+        mStarted = false;
+        mHandler.removeCallbacks(mJuggle);
+    }
+
+    int pick(int[] a) {
+        return a[(int)(Math.random()*a.length)];
+    }
+
+    <T> T pick(T[] a) {
+        return a[(int)(Math.random()*a.length)];
+    }
+
+    <T> T pick(SparseArray<T> sa) {
+        return sa.valueAt((int)(Math.random()*sa.size()));
+    }
+
+    float[] hsv = new float[] { 0, 1f, .85f };
+    int random_color() {
+//        return 0xFF000000 | (int) (Math.random() * (float) 0xFFFFFF); // totally random
+        final int COLORS = 12;
+        hsv[0] = irand(0,COLORS) * (360f/COLORS);
+        return Color.HSVToColor(hsv);
+    }
+
+    @Override
+    protected synchronized void onSizeChanged (int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (mWidth == w && mHeight == h) return;
+
+        final boolean wasStarted = mStarted;
+        if (wasStarted) {
+            stop();
+        }
+
+        mWidth = w;
+        mHeight = h;
+
+        mCells = null;
+        removeAllViewsInLayout();
+        mFreeList.clear();
+
+        mRows = mHeight / mCellSize;
+        mColumns = mWidth / mCellSize;
+
+        mCells = new View[mRows * mColumns];
+
+        if (DEBUG) Log.v(TAG, String.format("New dimensions: %dx%d", mColumns, mRows));
+
+        setScaleX(SCALE);
+        setScaleY(SCALE);
+        setTranslationX(0.5f * (mWidth - mCellSize * mColumns) * SCALE);
+        setTranslationY(0.5f * (mHeight - mCellSize * mRows) * SCALE);
+
+        for (int j=0; j<mRows; j++) {
+            for (int i=0; i<mColumns; i++) {
+                mFreeList.add(new Point(i,j));
+            }
+        }
+
+        if (wasStarted) {
+            start();
+        }
+    }
+
+    public void fillFreeList() {
+        fillFreeList(DURATION);
+    }
+
+    public synchronized void fillFreeList(int animationLen) {
+        final Context ctx = getContext();
+        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(mCellSize, mCellSize);
+
+        while (! mFreeList.isEmpty()) {
+            Point pt = mFreeList.iterator().next();
+            mFreeList.remove(pt);
+            final int i=pt.x;
+            final int j=pt.y;
+
+            if (mCells[j*mColumns+i] != null) continue;
+            final ImageView v = new ImageView(ctx);
+            v.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    place(v, true);
+                    postDelayed(new Runnable() { public void run() { fillFreeList(); } }, DURATION/2);
+                }
+            });
+
+            final int c = random_color();
+            v.setBackgroundColor(c);
+
+            final float which = frand();
+            final Drawable d;
+            if (which < 0.001f) {
+                d = mDrawables.get(pick(XXRARE_PASTRIES));
+            } else if (which < 0.01f) {
+                d = mDrawables.get(pick(XRARE_PASTRIES));
+            } else if (which < 0.5f) {
+                d = mDrawables.get(pick(RARE_PASTRIES));
+            } else if (which < 0.7f) {
+                d = mDrawables.get(pick(PASTRIES));
+            } else {
+                d = null;
+            }
+            if (d != null) {
+                v.getOverlay().add(d);
+            }
+
+            final Paint paint = new Paint();
+            v.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+
+            lp.width = lp.height = mCellSize;
+            addView(v, lp);
+            place(v, pt, false);
+            if (animationLen > 0) {
+                final float s = (Integer) v.getTag(TAG_SPAN);
+                v.setScaleX(0.5f * s);
+                v.setScaleY(0.5f * s);
+                v.setAlpha(0f);
+                v.animate().scaleX(s).scaleY(s).alpha(1f).setDuration(animationLen);
+            }
+        }
+    }
+
+    public void place(View v, boolean animate) {
+        place(v, new Point(irand(0, mColumns), irand(0, mRows)), animate);
+    }
+
+    private final HashSet<View> tmpSet = new HashSet<View>();
+    public synchronized void place(View v, Point pt, boolean animate) {
+        final int i = pt.x;
+        final int j = pt.y;
+        final float rnd = frand();
+        if (v.getTag(TAG_POS) != null) {
+            for (final Point oc : getOccupied(v)) {
+                mFreeList.add(oc);
+                mCells[oc.y*mColumns + oc.x] = null;
+            }
+        }
+        int scale = 1;
+        if (rnd < PROB_4X) {
+            if (!(i >= mColumns-3 || j >= mRows-3)) {
+                scale = 4;
+            }
+        } else if (rnd < PROB_3X) {
+            if (!(i >= mColumns-2 || j >= mRows-2)) {
+                scale = 3;
+            }
+        } else if (rnd < PROB_2X) {
+            if (!(i == mColumns-1 || j == mRows-1)) {
+                scale = 2;
+            }
+        }
+
+        v.setTag(TAG_POS, pt);
+        v.setTag(TAG_SPAN, scale);
+
+        tmpSet.clear();
+
+        final Point[] occupied = getOccupied(v);
+        for (final Point oc : occupied) {
+            final View squatter = mCells[oc.y*mColumns + oc.x];
+            if (squatter != null) {
+                tmpSet.add(squatter);
+            }
+        }
+
+        for (final View squatter : tmpSet) {
+            for (final Point sq : getOccupied(squatter)) {
+                mFreeList.add(sq);
+                mCells[sq.y*mColumns + sq.x] = null;
+            }
+            if (squatter != v) {
+                squatter.setTag(TAG_POS, null);
+                if (animate) {
+                    squatter.animate().scaleX(0.5f).scaleY(0.5f).alpha(0)
+                            .setDuration(DURATION)
+                            .setInterpolator(new AccelerateInterpolator())
+                            .setListener(new Animator.AnimatorListener() {
+                                public void onAnimationStart(Animator animator) { }
+                                public void onAnimationEnd(Animator animator) {
+                                    removeView(squatter);
+                                }
+                                public void onAnimationCancel(Animator animator) { }
+                                public void onAnimationRepeat(Animator animator) { }
+                            })
+                            .start();
+                } else {
+                    removeView(squatter);
+                }
+            }
+        }
+
+        for (final Point oc : occupied) {
+            mCells[oc.y*mColumns + oc.x] = v;
+            mFreeList.remove(oc);
+        }
+
+        final float rot = (float)irand(0, 4) * 90f;
+
+        if (animate) {
+            v.bringToFront();
+            AnimatorSet set1 = new AnimatorSet();
+            set1.playTogether(
+                    ObjectAnimator.ofFloat(v, View.SCALE_X, (float) scale),
+                    ObjectAnimator.ofFloat(v, View.SCALE_Y, (float) scale)
+            );
+            set1.setInterpolator(new AnticipateOvershootInterpolator());
+            set1.setDuration(DURATION);
+            set1.start();
+
+            AnimatorSet set2 = new AnimatorSet();
+            set2.playTogether(
+                    ObjectAnimator.ofFloat(v, View.ROTATION, rot),
+                    ObjectAnimator.ofFloat(v, View.X, i* mCellSize + (scale-1) * mCellSize /2),
+                    ObjectAnimator.ofFloat(v, View.Y, j* mCellSize + (scale-1) * mCellSize /2)
+            );
+            set2.setInterpolator(new DecelerateInterpolator());
+            set2.setDuration(DURATION);
+            set2.start();
+        } else {
+            v.setX(i * mCellSize + (scale-1) * mCellSize /2);
+            v.setY(j * mCellSize + (scale-1) * mCellSize /2);
+            v.setScaleX((float) scale);
+            v.setScaleY((float) scale);
+            v.setRotation(rot);
+        }
+    }
+
+    private Point[] getOccupied(View v) {
+        final int scale = (Integer) v.getTag(TAG_SPAN);
+        final Point pt = (Point)v.getTag(TAG_POS);
+        if (pt == null || scale == 0) return new Point[0];
+
+        final Point[] result = new Point[scale * scale];
+        int p=0;
+        for (int i=0; i<scale; i++) {
+            for (int j=0; j<scale; j++) {
+                result[p++] = new Point(pt.x + i, pt.y + j);
+            }
+        }
+        return result;
+    }
+
+    static float frand() {
+        return (float)(Math.random());
+    }
+
+    static float frand(float a, float b) {
+        return (frand() * (b-a) + a);
+    }
+
+    static int irand(int a, int b) {
+        return (int)(frand(a, b));
+    }
+
+    @Override
+    public void onDraw(Canvas c) {
+        super.onDraw(c);
+        if (!DEBUG) return;
+
+        Paint pt = new Paint();
+        pt.setStyle(Paint.Style.STROKE);
+        pt.setColor(0xFFCCCCCC);
+        pt.setStrokeWidth(2.0f);
+
+        final Rect check = new Rect();
+        final int N = getChildCount();
+        for (int i = 0; i < N; i++) {
+            View stone = getChildAt(i);
+
+            stone.getHitRect(check);
+
+            c.drawRect(check, pt);
+        }
+    }
+
+    public static class RescalingContainer extends FrameLayout {
+        private static final int SYSTEM_UI_MODE_800 = 0x00000800;
+        private DessertCaseView mView;
+        private float mDarkness;
+
+        public RescalingContainer(Context context) {
+            super(context);
+
+            setSystemUiVisibility(0
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | SYSTEM_UI_MODE_800
+            );
+        }
+
+        public void setView(DessertCaseView v) {
+            addView(v);
+            mView = v;
+        }
+
+        @Override
+        protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
+            final float w = right-left;
+            final float h = bottom-top;
+            final int w2 = (int) (w / mView.SCALE / 2);
+            final int h2 = (int) (h / mView.SCALE / 2);
+            final int cx = (int) (left + w * 0.5f);
+            final int cy = (int) (top + h * 0.5f);
+            mView.layout(cx - w2, cy - h2, cx + w2, cy + h2);
+        }
+
+        public void setDarkness(float p) {
+            mDarkness = p;
+            getDarkness();
+            final int x = (int) (p * 0xff);
+            setBackgroundColor(x << 24 & 0xFF000000);
+        }
+
+        public float getDarkness() {
+            return mDarkness;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index edfaf49..e1a4bb2 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -23,23 +23,23 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.os.Vibrator;
-import android.util.Slog;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.View.OnClickListener;
 
 public class ExpandHelper implements Gefingerpoken, OnClickListener {
     public interface Callback {
         View getChildAtRawPosition(float x, float y);
         View getChildAtPosition(float x, float y);
         boolean canChildBeExpanded(View v);
-        boolean setUserExpandedChild(View v, boolean userExpanded);
-        boolean setUserLockedChild(View v, boolean userLocked);
+        void setUserExpandedChild(View v, boolean userExpanded);
+        void setUserLockedChild(View v, boolean userLocked);
     }
 
     private static final String TAG = "ExpandHelper";
@@ -109,11 +109,11 @@
 
     private View mScrollView;
 
-    private OnScaleGestureListener mScaleGestureListener 
+    private OnScaleGestureListener mScaleGestureListener
             = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
         @Override
         public boolean onScaleBegin(ScaleGestureDetector detector) {
-            if (DEBUG_SCALE) Slog.v(TAG, "onscalebegin()");
+            if (DEBUG_SCALE) Log.v(TAG, "onscalebegin()");
             float focusX = detector.getFocusX();
             float focusY = detector.getFocusY();
 
@@ -126,7 +126,7 @@
 
         @Override
         public boolean onScale(ScaleGestureDetector detector) {
-            if (DEBUG_SCALE) Slog.v(TAG, "onscale() on " + mCurrView);
+            if (DEBUG_SCALE) Log.v(TAG, "onscale() on " + mCurrView);
             return true;
         }
 
@@ -143,7 +143,7 @@
             mView = v;
         }
         public void setHeight(float h) {
-            if (DEBUG_SCALE) Slog.v(TAG, "SetHeight: setting to " + h);
+            if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h);
             ViewGroup.LayoutParams lp = mView.getLayoutParams();
             lp.height = (int)h;
             mView.setLayoutParams(lp);
@@ -158,7 +158,7 @@
         }
         public int getNaturalHeight(int maximum) {
             ViewGroup.LayoutParams lp = mView.getLayoutParams();
-            if (DEBUG_SCALE) Slog.v(TAG, "Inspecting a child of type: " +
+            if (DEBUG_SCALE) Log.v(TAG, "Inspecting a child of type: " +
                     mView.getClass().getName());
             int oldHeight = lp.height;
             lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -181,7 +181,6 @@
      * @param callback the container that holds the items to be manipulated
      * @param small the smallest allowable size for the manuipulated items.
      * @param large the largest allowable size for the manuipulated items.
-     * @param scoller if non-null also manipulate the scroll position to obey the gravity.
      */
     public ExpandHelper(Context context, Callback callback, int small, int large) {
         mSmallSize = small;
@@ -230,7 +229,7 @@
     }
 
     private void updateExpansion() {
-        if (DEBUG_SCALE) Slog.v(TAG, "updateExpansion()");
+        if (DEBUG_SCALE) Log.v(TAG, "updateExpansion()");
         // are we scaling or dragging?
         float span = mSGD.getCurrentSpan() - mInitialTouchSpan;
         span *= USE_SPAN ? 1f : 0f;
@@ -270,10 +269,10 @@
     }
 
     private boolean isInside(View v, float x, float y) {
-        if (DEBUG) Slog.d(TAG, "isinside (" + x + ", " + y + ")");
+        if (DEBUG) Log.d(TAG, "isinside (" + x + ", " + y + ")");
 
         if (v == null) {
-            if (DEBUG) Slog.d(TAG, "isinside null subject");
+            if (DEBUG) Log.d(TAG, "isinside null subject");
             return false;
         }
         if (mEventSource != null) {
@@ -281,14 +280,14 @@
             mEventSource.getLocationOnScreen(location);
             x += location[0];
             y += location[1];
-            if (DEBUG) Slog.d(TAG, "  to global (" + x + ", " + y + ")");
+            if (DEBUG) Log.d(TAG, "  to global (" + x + ", " + y + ")");
         }
         int[] location = new int[2];
         v.getLocationOnScreen(location);
         x -= location[0];
         y -= location[1];
-        if (DEBUG) Slog.d(TAG, "  to local (" + x + ", " + y + ")");
-        if (DEBUG) Slog.d(TAG, "  inside (" + v.getWidth() + ", " + v.getHeight() + ")");
+        if (DEBUG) Log.d(TAG, "  to local (" + x + ", " + y + ")");
+        if (DEBUG) Log.d(TAG, "  inside (" + v.getWidth() + ", " + v.getHeight() + ")");
         boolean inside = (x > 0f && y > 0f && x < v.getWidth() & y < v.getHeight());
         return inside;
     }
@@ -307,10 +306,10 @@
 
     private float calculateGlow(float target, float actual) {
         // glow if overscale
-        if (DEBUG_GLOW) Slog.d(TAG, "target: " + target + " actual: " + actual);
+        if (DEBUG_GLOW) Log.d(TAG, "target: " + target + " actual: " + actual);
         float stretch = Math.abs((target - actual) / mMaximumStretch);
         float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
-        if (DEBUG_GLOW) Slog.d(TAG, "stretch: " + stretch + " strength: " + strength);
+        if (DEBUG_GLOW) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
         return (GLOW_BASE + strength * (1f - GLOW_BASE));
     }
 
@@ -348,7 +347,7 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
-        if (DEBUG_SCALE) Slog.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) +
+        if (DEBUG_SCALE) Log.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) +
                          " expanding=" + mExpanding +
                          (0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") +
                          (0 != (mExpansionStyle & PULL) ? " (pull)" : "") +
@@ -362,7 +361,7 @@
         mInitialTouchSpan = mSGD.getCurrentSpan();
         mLastFocusY = mInitialTouchFocusY;
         mLastSpanY = mInitialTouchSpan;
-        if (DEBUG_SCALE) Slog.d(TAG, "set initial span: " + mInitialTouchSpan);
+        if (DEBUG_SCALE) Log.d(TAG, "set initial span: " + mInitialTouchSpan);
 
         if (mExpanding) {
             return true;
@@ -376,7 +375,7 @@
                     xspan > mPullGestureMinXSpan &&
                     xspan > mSGD.getCurrentSpanY())) {
                 // detect a vertical pulling gesture with fingers somewhat separated
-                if (DEBUG_SCALE) Slog.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
+                if (DEBUG_SCALE) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
 
                 final View underFocus = findView(x, y);
                 if (underFocus != null) {
@@ -393,7 +392,7 @@
                 if (mWatchingForPull) {
                     final int yDiff = y - mLastMotionY;
                     if (yDiff > mTouchSlop) {
-                        if (DEBUG) Slog.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
+                        if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
                         mLastMotionY = y;
                         final View underFocus = findView(x, y);
                         if (underFocus != null) {
@@ -413,7 +412,7 @@
 
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                if (DEBUG) Slog.d(TAG, "up/cancel");
+                if (DEBUG) Log.d(TAG, "up/cancel");
                 finishExpanding(false);
                 clearView();
                 break;
@@ -425,7 +424,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         final int action = ev.getActionMasked();
-        if (DEBUG_SCALE) Slog.d(TAG, "touch: act=" + MotionEvent.actionToString(action) +
+        if (DEBUG_SCALE) Log.d(TAG, "touch: act=" + MotionEvent.actionToString(action) +
                 " expanding=" + mExpanding +
                 (0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") +
                 (0 != (mExpansionStyle & PULL) ? " (pull)" : "") +
@@ -484,14 +483,14 @@
 
             case MotionEvent.ACTION_POINTER_UP:
             case MotionEvent.ACTION_POINTER_DOWN:
-                if (DEBUG) Slog.d(TAG, "pointer change");
+                if (DEBUG) Log.d(TAG, "pointer change");
                 mInitialTouchY += mSGD.getFocusY() - mLastFocusY;
                 mInitialTouchSpan += mSGD.getCurrentSpan() - mLastSpanY;
                 break;
 
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
-                if (DEBUG) Slog.d(TAG, "up/cancel");
+                if (DEBUG) Log.d(TAG, "up/cancel");
                 finishExpanding(false);
                 clearView();
                 break;
@@ -505,20 +504,20 @@
             return;
         }
         mExpanding = true;
-        if (DEBUG) Slog.d(TAG, "scale type " + expandType + " beginning on view: " + v);
+        if (DEBUG) Log.d(TAG, "scale type " + expandType + " beginning on view: " + v);
         mCallback.setUserLockedChild(v, true);
         setView(v);
         setGlow(GLOW_BASE);
         mScaler.setView(v);
         mOldHeight = mScaler.getHeight();
         if (mCallback.canChildBeExpanded(v)) {
-            if (DEBUG) Slog.d(TAG, "working on an expandable child");
+            if (DEBUG) Log.d(TAG, "working on an expandable child");
             mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
         } else {
-            if (DEBUG) Slog.d(TAG, "working on a non-expandable child");
+            if (DEBUG) Log.d(TAG, "working on a non-expandable child");
             mNaturalHeight = mOldHeight;
         }
-        if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
+        if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight +
                     " mNaturalHeight: " + mNaturalHeight);
         v.getParent().requestDisallowInterceptTouchEvent(true);
     }
@@ -526,7 +525,7 @@
     private void finishExpanding(boolean force) {
         if (!mExpanding) return;
 
-        if (DEBUG) Slog.d(TAG, "scale in finishing on view: " + mCurrView);
+        if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mCurrView);
 
         float currentHeight = mScaler.getHeight();
         float targetHeight = mSmallSize;
@@ -552,11 +551,11 @@
         mExpanding = false;
         mExpansionStyle = NONE;
 
-        if (DEBUG) Slog.d(TAG, "wasClosed is: " + wasClosed);
-        if (DEBUG) Slog.d(TAG, "currentHeight is: " + currentHeight);
-        if (DEBUG) Slog.d(TAG, "mSmallSize is: " + mSmallSize);
-        if (DEBUG) Slog.d(TAG, "targetHeight is: " + targetHeight);
-        if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView);
+        if (DEBUG) Log.d(TAG, "wasClosed is: " + wasClosed);
+        if (DEBUG) Log.d(TAG, "currentHeight is: " + currentHeight);
+        if (DEBUG) Log.d(TAG, "mSmallSize is: " + mSmallSize);
+        if (DEBUG) Log.d(TAG, "targetHeight is: " + targetHeight);
+        if (DEBUG) Log.d(TAG, "scale was finished on view: " + mCurrView);
     }
 
     private void clearView() {
@@ -575,7 +574,7 @@
                 String debugLog = "Looking for glows: " +
                         (mCurrViewTopGlow != null ? "found top " : "didn't find top") +
                         (mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
-                Slog.v(TAG,  debugLog);
+                Log.v(TAG,  debugLog);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index cdd3d84..6fa863d 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui;
 
+import static android.opengl.GLES20.*;
+import static javax.microedition.khronos.egl.EGL10.*;
+
 import android.app.ActivityManager;
 import android.app.WallpaperManager;
 import android.content.BroadcastReceiver;
@@ -35,18 +38,16 @@
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
 
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
 
-import static android.opengl.GLES20.*;
-import static javax.microedition.khronos.egl.EGL10.*;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
 
 /**
  * Default built-in wallpaper that simply shows a static image.
@@ -139,7 +140,7 @@
                 "\nvoid main(void) {\n" +
                 "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
                 "}\n\n";
-    
+
         private static final int FLOAT_SIZE_BYTES = 4;
         private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
         private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
@@ -183,7 +184,7 @@
             }
 
             super.onCreate(surfaceHolder);
-            
+
             // TODO: Don't need this currently because the wallpaper service
             // will restart the image wallpaper whenever the image changes.
             //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
@@ -511,44 +512,44 @@
 
         private int loadTexture(Bitmap bitmap) {
             int[] textures = new int[1];
-    
+
             glActiveTexture(GL_TEXTURE0);
             glGenTextures(1, textures, 0);
             checkGlError();
-    
+
             int texture = textures[0];
             glBindTexture(GL_TEXTURE_2D, texture);
             checkGlError();
-            
+
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    
+
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    
+
             GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
             checkGlError();
 
             return texture;
         }
-        
+
         private int buildProgram(String vertex, String fragment) {
             int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
             if (vertexShader == 0) return 0;
-    
+
             int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
             if (fragmentShader == 0) return 0;
-    
+
             int program = glCreateProgram();
             glAttachShader(program, vertexShader);
             checkGlError();
-    
+
             glAttachShader(program, fragmentShader);
             checkGlError();
-    
+
             glLinkProgram(program);
             checkGlError();
-    
+
             int[] status = new int[1];
             glGetProgramiv(program, GL_LINK_STATUS, status, 0);
             if (status[0] != GL_TRUE) {
@@ -559,19 +560,19 @@
                 glDeleteProgram(program);
                 return 0;
             }
-    
+
             return program;
         }
 
         private int buildShader(String source, int type) {
             int shader = glCreateShader(type);
-    
+
             glShaderSource(shader, source);
             checkGlError();
-    
+
             glCompileShader(shader);
             checkGlError();
-    
+
             int[] status = new int[1];
             glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
             if (status[0] != GL_TRUE) {
@@ -580,7 +581,7 @@
                 glDeleteShader(shader);
                 return 0;
             }
-            
+
             return shader;
         }
 
@@ -607,24 +608,24 @@
 
         private boolean initGL(SurfaceHolder surfaceHolder) {
             mEgl = (EGL10) EGLContext.getEGL();
-    
+
             mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
             if (mEglDisplay == EGL_NO_DISPLAY) {
                 throw new RuntimeException("eglGetDisplay failed " +
                         GLUtils.getEGLErrorString(mEgl.eglGetError()));
             }
-            
+
             int[] version = new int[2];
             if (!mEgl.eglInitialize(mEglDisplay, version)) {
                 throw new RuntimeException("eglInitialize failed " +
                         GLUtils.getEGLErrorString(mEgl.eglGetError()));
             }
-    
+
             mEglConfig = chooseEglConfig();
             if (mEglConfig == null) {
                 throw new RuntimeException("eglConfig not initialized");
             }
-            
+
             mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
             if (mEglContext == EGL_NO_CONTEXT) {
                 throw new RuntimeException("createContext failed " +
@@ -666,7 +667,7 @@
                 throw new RuntimeException("createWindowSurface failed " +
                         GLUtils.getEGLErrorString(error));
             }
-    
+
             if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                 throw new RuntimeException("eglMakeCurrent failed " +
                         GLUtils.getEGLErrorString(mEgl.eglGetError()));
@@ -674,13 +675,13 @@
 
             return true;
         }
-        
-    
+
+
         EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
             int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
-            return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);            
+            return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);
         }
-    
+
         private EGLConfig chooseEglConfig() {
             int[] configsCount = new int[1];
             EGLConfig[] configs = new EGLConfig[1];
diff --git a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
index 2b45ad1..610e42b 100644
--- a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
+++ b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui;
 
-import com.android.internal.os.ProcessStats;
-
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -31,20 +29,22 @@
 import android.view.View;
 import android.view.WindowManager;
 
+import com.android.internal.os.ProcessCpuTracker;
+
 public class LoadAverageService extends Service {
     private View mView;
-    
-    private static final class Stats extends ProcessStats {
+
+    private static final class CpuTracker extends ProcessCpuTracker {
         String mLoadText;
         int mLoadWidth;
-        
+
         private final Paint mPaint;
-        
-        Stats(Paint paint) {
+
+        CpuTracker(Paint paint) {
             super(false);
             mPaint = paint;
         }
-        
+
         @Override
         public void onLoadChanged(float load1, float load5, float load15) {
             mLoadText = load1 + " / " + load5 + " / " + load15;
@@ -56,7 +56,7 @@
             return (int)mPaint.measureText(name);
         }
     }
-    
+
     private class LoadView extends View {
         private Handler mHandler = new Handler() {
             @Override
@@ -70,8 +70,8 @@
             }
         };
 
-        private final Stats mStats;
-        
+        private final CpuTracker mStats;
+
         private Paint mLoadPaint;
         private Paint mAddedPaint;
         private Paint mRemovedPaint;
@@ -150,7 +150,7 @@
             float descent = mLoadPaint.descent();
             mFH = (int)(descent - mAscent + .5f);
 
-            mStats = new Stats(mLoadPaint);
+            mStats = new CpuTracker(mLoadPaint);
             mStats.init();
             updateDisplay();
         }
@@ -179,14 +179,14 @@
             final int W = mNeededWidth;
             final int RIGHT = getWidth()-1;
 
-            final Stats stats = mStats;
+            final CpuTracker stats = mStats;
             final int userTime = stats.getLastUserTime();
             final int systemTime = stats.getLastSystemTime();
             final int iowaitTime = stats.getLastIoWaitTime();
             final int irqTime = stats.getLastIrqTime();
             final int softIrqTime = stats.getLastSoftIrqTime();
             final int idleTime = stats.getLastIdleTime();
-            
+
             final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime;
             if (totalTime == 0) {
                 return;
@@ -226,7 +226,7 @@
 
             int N = stats.countWorkingStats();
             for (int i=0; i<N; i++) {
-                Stats.Stats st = stats.getWorkingStats(i);
+                CpuTracker.Stats st = stats.getWorkingStats(i);
                 y += mFH;
                 top += mFH;
                 bottom += mFH;
@@ -259,17 +259,17 @@
         }
 
         void updateDisplay() {
-            final Stats stats = mStats;
+            final CpuTracker stats = mStats;
             final int NW = stats.countWorkingStats();
 
             int maxWidth = stats.mLoadWidth;
             for (int i=0; i<NW; i++) {
-                Stats.Stats st = stats.getWorkingStats(i);
+                CpuTracker.Stats st = stats.getWorkingStats(i);
                 if (st.nameWidth > maxWidth) {
                     maxWidth = st.nameWidth;
                 }
             }
-            
+
             int neededWidth = mPaddingLeft + mPaddingRight + maxWidth;
             int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW));
             if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
new file mode 100644
index 0000000..323905f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui;
+
+import android.view.Display;
+import android.view.View;
+
+public interface RecentsComponent {
+    void toggleRecents(Display display, int layoutDirection, View statusBarView);
+
+    void preloadRecentTasksList();
+
+    void cancelPreloadingRecentTasksList();
+
+    void closeRecents();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 1f29990..c7f0e17 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -32,7 +32,7 @@
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.EventLog;
-import android.util.Slog;
+import android.util.Log;
 import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.View;
@@ -43,27 +43,22 @@
 
 import com.android.internal.widget.multiwaveview.GlowPadView;
 import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
-
-import com.android.systemui.EventLogTags;
-import com.android.systemui.R;
-import com.android.systemui.recent.StatusBarTouchProxy;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarPanel;
+import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.tablet.StatusBarPanel;
-import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
 public class SearchPanelView extends FrameLayout implements
         StatusBarPanel, ActivityOptions.OnAnimationStartedListener {
     private static final int SEARCH_PANEL_HOLD_DURATION = 0;
     static final String TAG = "SearchPanelView";
-    static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
+    static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
     public static final boolean DEBUG_GESTURES = true;
     private static final String ASSIST_ICON_METADATA_NAME =
             "com.android.systemui.action_assist_icon";
     private final Context mContext;
     private BaseStatusBar mBar;
-    private StatusBarTouchProxy mStatusBarTouchProxy;
 
     private boolean mShowing;
     private View mSearchTargetsContainer;
@@ -94,11 +89,7 @@
 
         if (isKeyguardShowing) {
             // Have keyguard show the bouncer and launch the activity if the user succeeds.
-            try {
-                mWm.showAssistant();
-            } catch (RemoteException e) {
-                // too bad, so sad...
-            }
+            KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
             onAnimationStarted();
         } else {
             // Otherwise, keyguard isn't showing so launch it from here.
@@ -120,7 +111,7 @@
                 mContext.startActivityAsUser(intent, opts.toBundle(),
                         new UserHandle(UserHandle.USER_CURRENT));
             } catch (ActivityNotFoundException e) {
-                Slog.w(TAG, "Activity not found for " + intent.getAction());
+                Log.w(TAG, "Activity not found for " + intent.getAction());
                 onAnimationStarted();
             }
         }
@@ -172,7 +163,6 @@
         super.onFinishInflate();
         mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mSearchTargetsContainer = findViewById(R.id.search_panel_container);
-        mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
         // TODO: fetch views
         mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
         mGlowPadView.setOnTriggerListener(mGlowPadViewListener);
@@ -186,7 +176,7 @@
             if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component,
                     ASSIST_ICON_METADATA_NAME,
                     com.android.internal.R.drawable.ic_action_assist_generic)) {
-                if (DEBUG) Slog.v(TAG, "Couldn't grab icon for component " + component);
+                if (DEBUG) Log.v(TAG, "Couldn't grab icon for component " + component);
             }
         }
     }
@@ -200,14 +190,7 @@
     }
 
     public boolean isInContentArea(int x, int y) {
-        if (pointInside(x, y, mSearchTargetsContainer)) {
-            return true;
-        } else if (mStatusBarTouchProxy != null &&
-                pointInside(x, y, mStatusBarTouchProxy)) {
-            return true;
-        } else {
-            return false;
-        }
+        return pointInside(x, y, mSearchTargetsContainer);
     }
 
     private final OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
@@ -297,17 +280,6 @@
         mBar = bar;
     }
 
-    public void setStatusBarView(final View statusBarView) {
-        if (mStatusBarTouchProxy != null) {
-            mStatusBarTouchProxy.setStatusBar(statusBarView);
-//            mGlowPadView.setOnTouchListener(new OnTouchListener() {
-//                public boolean onTouch(View v, MotionEvent event) {
-//                    return statusBarView.onTouchEvent(event);
-//                }
-//            });
-        }
-    }
-
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (DEBUG_GESTURES) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index f824a8e..d38d828 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -19,18 +19,17 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.graphics.RectF;
 import android.os.Handler;
 import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.LinearInterpolator;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.LinearInterpolator;
 
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java
index 2110483c..cb624ad 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUI.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java
@@ -16,20 +16,33 @@
 
 package com.android.systemui;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
 import android.content.Context;
 import android.content.res.Configuration;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
+
 public abstract class SystemUI {
     public Context mContext;
+    public Map<Class<?>, Object> mComponents;
 
     public abstract void start();
-    
+
     protected void onConfigurationChanged(Configuration newConfig) {
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
     }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getComponent(Class<T> interfaceType) {
+        return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
+    }
+
+    public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {
+        if (mComponents != null) {
+            mComponents.put(interfaceType, component);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 1f3e942..ca5f7d1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -16,32 +16,26 @@
 
 package com.android.systemui;
 
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.util.Log;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
+import java.util.HashMap;
 
 public class SystemUIService extends Service {
-    static final String TAG = "SystemUIService";
+    private static final String TAG = "SystemUIService";
 
     /**
-     * The class names of the stuff to start.
+     * The classes of the stuff to start.
      */
-    final Object[] SERVICES = new Object[] {
-            0, // system bar or status bar, filled in below.
+    private final Class<?>[] SERVICES = new Class[] {
+            com.android.systemui.recent.Recents.class,
+            com.android.systemui.statusbar.SystemBars.class,
+            com.android.systemui.usb.StorageNotification.class,
             com.android.systemui.power.PowerUI.class,
             com.android.systemui.media.RingtonePlayer.class,
             com.android.systemui.settings.SettingsUI.class,
@@ -50,44 +44,15 @@
     /**
      * Hold a reference on the stuff we start.
      */
-    SystemUI[] mServices;
-
-    private Class chooseClass(Object o) {
-        if (o instanceof Integer) {
-            final String cl = getString((Integer)o);
-            try {
-                return getClassLoader().loadClass(cl);
-            } catch (ClassNotFoundException ex) {
-                throw new RuntimeException(ex);
-            }
-        } else if (o instanceof Class) {
-            return (Class)o;
-        } else {
-            throw new RuntimeException("Unknown system ui service: " + o);
-        }
-    }
+    private final SystemUI[] mServices = new SystemUI[SERVICES.length];
 
     @Override
     public void onCreate() {
-        // Tell the accessibility layer that this process will
-        // run as the current user, i.e. run across users.
-        AccessibilityManager.createAsSharedAcrossUsers(this);
-
-        // Pick status bar or system bar.
-        IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-        try {
-            SERVICES[0] = wm.hasSystemNavBar()
-                    ? R.string.config_systemBarComponent
-                    : R.string.config_statusBarComponent;
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Failing checking whether status bar can hide", e);
-        }
-
+        HashMap<Class<?>, Object> components = new HashMap<Class<?>, Object>();
         final int N = SERVICES.length;
-        mServices = new SystemUI[N];
         for (int i=0; i<N; i++) {
-            Class cl = chooseClass(SERVICES[i]);
-            Slog.d(TAG, "loading: " + cl);
+            Class<?> cl = SERVICES[i];
+            Log.d(TAG, "loading: " + cl);
             try {
                 mServices[i] = (SystemUI)cl.newInstance();
             } catch (IllegalAccessException ex) {
@@ -96,7 +61,8 @@
                 throw new RuntimeException(ex);
             }
             mServices[i].mContext = this;
-            Slog.d(TAG, "running: " + mServices[i]);
+            mServices[i].mComponents = components;
+            Log.d(TAG, "running: " + mServices[i]);
             mServices[i].start();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/UniverseBackground.java b/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
deleted file mode 100644
index f859880..0000000
--- a/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Matrix;
-import android.graphics.PixelFormat;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Slog;
-import android.view.Choreographer;
-import android.view.Display;
-import android.view.IWindowSession;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.animation.Transformation;
-import android.widget.FrameLayout;
-
-public class UniverseBackground extends FrameLayout {
-    static final String TAG = "UniverseBackground";
-    static final boolean SPEW = false;
-    static final boolean CHATTY = false;
-
-    final IWindowSession mSession;
-    final View mContent;
-    final View mBottomAnchor;
-
-    final Runnable mAnimationCallback = new Runnable() {
-        @Override
-        public void run() {
-            doAnimation(mChoreographer.getFrameTimeNanos());
-        }
-    };
-
-    // fling gesture tuning parameters, scaled to display density
-    private float mSelfExpandVelocityPx; // classic value: 2000px/s
-    private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
-    private float mFlingExpandMinVelocityPx; // classic value: 200px/s
-    private float mFlingCollapseMinVelocityPx; // classic value: 200px/s
-    private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1)
-    private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
-    private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
-
-    private float mExpandAccelPx; // classic value: 2000px/s/s
-    private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
-
-    static final int STATE_CLOSED = 0;
-    static final int STATE_OPENING = 1;
-    static final int STATE_OPEN = 2;
-    private int mState = STATE_CLOSED;
-
-    private float mDragStartX, mDragStartY;
-    private float mAverageX, mAverageY;
-
-    // position
-    private int[] mPositionTmp = new int[2];
-    private boolean mExpanded;
-    private boolean mExpandedVisible;
-
-    private boolean mTracking;
-    private VelocityTracker mVelocityTracker;
-
-    private Choreographer mChoreographer;
-    private boolean mAnimating;
-    private boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
-    private float mAnimY;
-    private float mAnimVel;
-    private float mAnimAccel;
-    private long mAnimLastTimeNanos;
-    private boolean mAnimatingReveal = false;
-
-    private int mYDelta = 0;
-    private Transformation mUniverseTransform = new Transformation();
-    private final float[] mTmpFloats = new float[9];
-
-    public UniverseBackground(Context context) {
-        super(context);
-        setBackgroundColor(0xff000000);
-        mSession = WindowManagerGlobal.getWindowSession();
-        mContent = View.inflate(context, R.layout.universe, null);
-        addView(mContent);
-        mContent.findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
-            @Override public void onClick(View v) {
-                animateCollapse();
-            }
-        });
-        mBottomAnchor = mContent.findViewById(R.id.bottom);
-        mChoreographer = Choreographer.getInstance();
-        loadDimens();
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        loadDimens();
-    }
-
-    private void loadDimens() {
-        final Resources res = getContext().getResources();
-        mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
-        mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity);
-        mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
-        mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
-
-        mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
-        mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
-
-        mExpandAccelPx = res.getDimension(R.dimen.expand_accel);
-        mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel);
-
-        mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
-    }
-
-    private void computeAveragePos(MotionEvent event) {
-        final int num = event.getPointerCount();
-        float x = 0, y = 0;
-        for (int i=0; i<num; i++) {
-            x += event.getX(i);
-            y += event.getY(i);
-        }
-        mAverageX = x / num;
-        mAverageY = y / num;
-    }
-
-    private void sendUniverseTransform() {
-        if (getWindowToken() != null) {
-            mUniverseTransform.getMatrix().getValues(mTmpFloats);
-            try {
-                mSession.setUniverseTransform(getWindowToken(), mUniverseTransform.getAlpha(),
-                        mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y],
-                        mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
-                        mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    public WindowManager.LayoutParams getLayoutParams() {
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND,
-                    0
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.OPAQUE);
-        // this will allow the window to run in an overlay on devices that support this
-        if (ActivityManager.isHighEndGfx()) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        }
-        lp.setTitle("UniverseBackground");
-        lp.windowAnimations = 0;
-        return lp;
-    }
-
-    private int getExpandedViewMaxHeight() {
-        return mBottomAnchor.getTop();
-    }
-
-    public void animateCollapse() {
-        animateCollapse(1.0f);
-    }
-
-    public void animateCollapse(float velocityMultiplier) {
-        if (SPEW) {
-            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
-                    + " mExpandedVisible=" + mExpandedVisible
-                    + " mExpanded=" + mExpanded
-                    + " mAnimating=" + mAnimating
-                    + " mAnimY=" + mAnimY
-                    + " mAnimVel=" + mAnimVel);
-        }
-
-        mState = STATE_CLOSED;
-        if (!mExpandedVisible) {
-            return;
-        }
-
-        int y;
-        if (mAnimating) {
-            y = (int)mAnimY;
-        } else {
-            y = getExpandedViewMaxHeight()-1;
-        }
-        // Let the fling think that we're open so it goes in the right direction
-        // and doesn't try to re-open the windowshade.
-        mExpanded = true;
-        prepareTracking(y, false);
-        performFling(y, -mSelfCollapseVelocityPx*velocityMultiplier, true);
-    }
-
-    private void updateUniverseScale() {
-        if (mYDelta > 0) {
-            int w = getWidth();
-            int h = getHeight();
-            float scale = (h-mYDelta+.5f) / (float)h;
-            mUniverseTransform.getMatrix().setScale(scale, scale, w/2, h);
-            if (CHATTY) Log.i(TAG, "w=" + w + " h=" + h + " scale=" + scale
-                    + ": " + mUniverseTransform);
-            sendUniverseTransform();
-            if (getVisibility() != VISIBLE) {
-                setVisibility(VISIBLE);
-            }
-        } else {
-            if (CHATTY) Log.i(TAG, "mYDelta=" + mYDelta);
-            mUniverseTransform.clear();
-            sendUniverseTransform();
-            if (getVisibility() == VISIBLE) {
-                setVisibility(GONE);
-            }
-        }
-    }
-
-    void resetLastAnimTime() {
-        mAnimLastTimeNanos = System.nanoTime();
-        if (SPEW) {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            Slog.d(TAG, "resetting last anim time=" + mAnimLastTimeNanos, t);
-        }
-    }
-
-    void doAnimation(long frameTimeNanos) {
-        if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation dt=" + (frameTimeNanos - mAnimLastTimeNanos));
-            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
-            incrementAnim(frameTimeNanos);
-            if (SPEW) {
-                Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            }
-
-            if (mAnimY >= getExpandedViewMaxHeight()-1 && !mClosing) {
-                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
-                mAnimating = false;
-                mYDelta = getExpandedViewMaxHeight();
-                updateUniverseScale();
-                mExpanded = true;
-                mState = STATE_OPEN;
-                return;
-            }
-
-            if (mAnimY <= 0 && mClosing) {
-                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
-                mAnimating = false;
-                mYDelta = 0;
-                updateUniverseScale();
-                mExpanded = false;
-                mState = STATE_CLOSED;
-                return;
-            }
-
-            mYDelta = (int)mAnimY;
-            updateUniverseScale();
-            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
-                    mAnimationCallback, null);
-        }
-    }
-
-    void stopTracking() {
-        mTracking = false;
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-    }
-
-    void incrementAnim(long frameTimeNanos) {
-        final long deltaNanos = Math.max(frameTimeNanos - mAnimLastTimeNanos, 0);
-        final float t = deltaNanos * 0.000000001f;                  // ns -> s
-        final float y = mAnimY;
-        final float v = mAnimVel;                                   // px/s
-        final float a = mAnimAccel;                                 // px/s/s
-        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
-        mAnimVel = v + (a*t);                                       // px/s
-        mAnimLastTimeNanos = frameTimeNanos;                        // ns
-        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
-        //        + " mAnimAccel=" + mAnimAccel);
-    }
-
-    void prepareTracking(int y, boolean opening) {
-        if (CHATTY) {
-            Slog.d(TAG, "panel: beginning to track the user's touch, y=" + y + " opening=" + opening);
-        }
-
-        mTracking = true;
-        mVelocityTracker = VelocityTracker.obtain();
-        if (opening) {
-            mAnimAccel = mExpandAccelPx;
-            mAnimVel = mFlingExpandMinVelocityPx;
-            mAnimY = y;
-            mAnimating = true;
-            mAnimatingReveal = true;
-            resetLastAnimTime();
-            mExpandedVisible = true;
-        }
-        if (mAnimating) {
-            mAnimating = false;
-            mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                    mAnimationCallback, null);
-        }
-    }
-
-    void performFling(int y, float vel, boolean always) {
-        if (CHATTY) {
-            Slog.d(TAG, "panel: will fling, y=" + y + " vel=" + vel);
-        }
-
-        mAnimatingReveal = false;
-
-        mAnimY = y;
-        mAnimVel = vel;
-
-        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
-        if (mExpanded) {
-            if (!always && (
-                    vel > mFlingCollapseMinVelocityPx
-                    || (y > (getExpandedViewMaxHeight()*(1f-mCollapseMinDisplayFraction)) &&
-                        vel > -mFlingExpandMinVelocityPx))) {
-                // We are expanded, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the expanded position.
-                mAnimAccel = mExpandAccelPx;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are expanded and are now going to animate away.
-                mAnimAccel = -mCollapseAccelPx;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        } else {
-            if (always || (
-                    vel > mFlingExpandMinVelocityPx
-                    || (y > (getExpandedViewMaxHeight()*(1f-mExpandMinDisplayFraction)) &&
-                        vel > -mFlingCollapseMinVelocityPx))) {
-                // We are collapsed, and they moved enough to allow us to
-                // expand.  Animate in the notifications.
-                mAnimAccel = mExpandAccelPx;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are collapsed, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the collapsed position.
-                mAnimAccel = -mCollapseAccelPx;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        }
-        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
-        //        + " mAnimAccel=" + mAnimAccel);
-
-        resetLastAnimTime();
-        mAnimating = true;
-        mClosing = mAnimAccel < 0;
-        mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                mAnimationCallback, null);
-        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
-                mAnimationCallback, null);
-
-        stopTracking();
-    }
-
-    private void trackMovement(MotionEvent event) {
-        mVelocityTracker.addMovement(event);
-    }
-
-    public boolean consumeEvent(MotionEvent event) {
-        if (mState == STATE_CLOSED) {
-            if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
-                // Second finger down, time to start opening!
-                computeAveragePos(event);
-                mDragStartX = mAverageX;
-                mDragStartY = mAverageY;
-                mYDelta = 0;
-                mUniverseTransform.clear();
-                sendUniverseTransform();
-                setVisibility(VISIBLE);
-                mState = STATE_OPENING;
-                prepareTracking((int)mDragStartY, true);
-                mVelocityTracker.clear();
-                trackMovement(event);
-                return true;
-            }
-            return false;
-        }
-
-        if (mState == STATE_OPENING) {
-            if (event.getActionMasked() == MotionEvent.ACTION_UP
-                    || event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
-                mVelocityTracker.computeCurrentVelocity(1000);
-                computeAveragePos(event);
-
-                float yVel = mVelocityTracker.getYVelocity();
-                boolean negative = yVel < 0;
-
-                float xVel = mVelocityTracker.getXVelocity();
-                if (xVel < 0) {
-                    xVel = -xVel;
-                }
-                if (xVel > mFlingGestureMaxXVelocityPx) {
-                    xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
-                }
-
-                float vel = (float)Math.hypot(yVel, xVel);
-                if (negative) {
-                    vel = -vel;
-                }
-
-                if (CHATTY) {
-                    Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
-                        mVelocityTracker.getXVelocity(),
-                        mVelocityTracker.getYVelocity(),
-                        xVel, yVel,
-                        vel));
-                }
-
-                performFling((int)mAverageY, vel, false);
-                mState = STATE_OPEN;
-                return true;
-            }
-
-            computeAveragePos(event);
-            mYDelta = (int)(mAverageY - mDragStartY);
-            if (mYDelta > getExpandedViewMaxHeight()) {
-                mYDelta = getExpandedViewMaxHeight();
-            }
-            updateUniverseScale();
-            return true;
-        }
-
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 8979fc2..f8b347c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -26,7 +26,6 @@
 import android.os.SystemClock;
 import android.util.Log;
 
-import java.lang.Thread;
 import java.util.LinkedList;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 0c6e59c..5b4bb2c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -28,10 +28,9 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.systemui.SystemUI;
-import com.google.android.collect.Maps;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -50,7 +49,7 @@
     private IAudioService mAudioService;
 
     private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG);
-    private final HashMap<IBinder, Client> mClients = Maps.newHashMap();
+    private final HashMap<IBinder, Client> mClients = new HashMap<IBinder, Client>();
 
     @Override
     public void start() {
@@ -61,7 +60,7 @@
         try {
             mAudioService.setRingtonePlayer(mCallback);
         } catch (RemoteException e) {
-            Slog.e(TAG, "Problem registering RingtonePlayer: " + e);
+            Log.e(TAG, "Problem registering RingtonePlayer: " + e);
         }
     }
 
@@ -82,7 +81,7 @@
 
         @Override
         public void binderDied() {
-            if (LOGD) Slog.d(TAG, "binderDied() token=" + mToken);
+            if (LOGD) Log.d(TAG, "binderDied() token=" + mToken);
             synchronized (mClients) {
                 mClients.remove(mToken);
             }
@@ -94,7 +93,7 @@
         @Override
         public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
             if (LOGD) {
-                Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+                Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
                         + Binder.getCallingUid() + ")");
             }
             Client client;
@@ -112,7 +111,7 @@
 
         @Override
         public void stop(IBinder token) {
-            if (LOGD) Slog.d(TAG, "stop(token=" + token + ")");
+            if (LOGD) Log.d(TAG, "stop(token=" + token + ")");
             Client client;
             synchronized (mClients) {
                 client = mClients.remove(token);
@@ -125,7 +124,7 @@
 
         @Override
         public boolean isPlaying(IBinder token) {
-            if (LOGD) Slog.d(TAG, "isPlaying(token=" + token + ")");
+            if (LOGD) Log.d(TAG, "isPlaying(token=" + token + ")");
             Client client;
             synchronized (mClients) {
                 client = mClients.get(token);
@@ -139,7 +138,7 @@
 
         @Override
         public void playAsync(Uri uri, UserHandle user, boolean looping, int streamType) {
-            if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
+            if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Async playback only available from system UID.");
             }
@@ -149,7 +148,7 @@
 
         @Override
         public void stopAsync() {
-            if (LOGD) Slog.d(TAG, "stopAsync()");
+            if (LOGD) Log.d(TAG, "stopAsync()");
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Async playback only available from system UID.");
             }
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index 888b76e..1ac8295 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -32,7 +32,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.util.Slog;
+import android.util.Log;
 import android.view.WindowManager;
 
 import com.android.systemui.R;
@@ -79,7 +79,7 @@
         try {
             policyService.snoozeLimit(template);
         } catch (RemoteException e) {
-            Slog.w(TAG, "problem snoozing network policy", e);
+            Log.w(TAG, "problem snoozing network policy", e);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index ccb711a..a08eb9b 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -16,10 +16,6 @@
 
 package com.android.systemui.power;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.Arrays;
-
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -27,15 +23,15 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
 import android.provider.Settings;
-import android.util.Slog;
+import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.TextView;
@@ -43,6 +39,10 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
 
@@ -126,19 +126,19 @@
                 int bucket = findBatteryLevelBucket(mBatteryLevel);
 
                 if (DEBUG) {
-                    Slog.d(TAG, "buckets   ....." + mLowBatteryAlertCloseLevel
+                    Log.d(TAG, "buckets   ....." + mLowBatteryAlertCloseLevel
                             + " .. " + mLowBatteryReminderLevels[0]
                             + " .. " + mLowBatteryReminderLevels[1]);
-                    Slog.d(TAG, "level          " + oldBatteryLevel + " --> " + mBatteryLevel);
-                    Slog.d(TAG, "status         " + oldBatteryStatus + " --> " + mBatteryStatus);
-                    Slog.d(TAG, "plugType       " + oldPlugType + " --> " + mPlugType);
-                    Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
-                    Slog.d(TAG, "bucket         " + oldBucket + " --> " + bucket);
-                    Slog.d(TAG, "plugged        " + oldPlugged + " --> " + plugged);
+                    Log.d(TAG, "level          " + oldBatteryLevel + " --> " + mBatteryLevel);
+                    Log.d(TAG, "status         " + oldBatteryStatus + " --> " + mBatteryStatus);
+                    Log.d(TAG, "plugType       " + oldPlugType + " --> " + mPlugType);
+                    Log.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
+                    Log.d(TAG, "bucket         " + oldBucket + " --> " + bucket);
+                    Log.d(TAG, "plugged        " + oldPlugged + " --> " + plugged);
                 }
 
                 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
-                    Slog.d(TAG, "showing invalid charger warning");
+                    Log.d(TAG, "showing invalid charger warning");
                     showInvalidChargerDialog();
                     return;
                 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
@@ -164,20 +164,20 @@
                     showLowBatteryWarning();
                 }
             } else {
-                Slog.w(TAG, "unknown intent: " + intent);
+                Log.w(TAG, "unknown intent: " + intent);
             }
         }
     };
 
     void dismissLowBatteryWarning() {
         if (mLowBatteryDialog != null) {
-            Slog.i(TAG, "closing low battery warning: level=" + mBatteryLevel);
+            Log.i(TAG, "closing low battery warning: level=" + mBatteryLevel);
             mLowBatteryDialog.dismiss();
         }
     }
 
     void showLowBatteryWarning() {
-        Slog.i(TAG,
+        Log.i(TAG,
                 ((mBatteryLevelTextView == null) ? "showing" : "updating")
                 + " low battery warning: level=" + mBatteryLevel
                 + " [" + findBatteryLevelBucket(mBatteryLevel) + "]");
@@ -234,7 +234,7 @@
 
     void playLowBatterySound() {
         if (DEBUG) {
-            Slog.i(TAG, "playing low battery sound. WOMP-WOMP!");
+            Log.i(TAG, "playing low battery sound. WOMP-WOMP!");
         }
 
         final ContentResolver cr = mContext.getContentResolver();
@@ -261,7 +261,7 @@
     }
 
     void showInvalidChargerDialog() {
-        Slog.d(TAG, "showing invalid charger dialog");
+        Log.d(TAG, "showing invalid charger dialog");
 
         dismissLowBatteryWarning();
 
@@ -283,7 +283,7 @@
         d.show();
         mInvalidChargerDialog = d;
     }
-    
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mLowBatteryAlertCloseLevel=");
         pw.println(mLowBatteryAlertCloseLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
new file mode 100644
index 0000000..b4d3edd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.recent;
+
+import android.graphics.drawable.ColorDrawable;
+
+public class ColorDrawableWithDimensions extends ColorDrawable {
+    private int mWidth;
+    private int mHeight;
+
+    public ColorDrawableWithDimensions(int color, int width, int height) {
+        super(color);
+        mWidth = width;
+        mHeight = height;
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mHeight;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
new file mode 100644
index 0000000..1cfc892
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.recent;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+public class FadedEdgeDrawHelper {
+    public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
+    public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
+    private View mScrollView;
+
+    private int mFadingEdgeLength;
+    private boolean mIsVertical;
+    private boolean mSoftwareRendered = false;
+    private Paint mBlackPaint;
+    private Paint mFadePaint;
+    private Matrix mFadeMatrix;
+    private LinearGradient mFade;
+
+    public static FadedEdgeDrawHelper create(Context context,
+            AttributeSet attrs, View scrollView, boolean isVertical) {
+        boolean isTablet = context.getResources().
+                getBoolean(R.bool.config_recents_interface_for_tablets);
+        if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
+            return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
+        } else {
+            return null;
+        }
+    }
+
+    public FadedEdgeDrawHelper(Context context,
+            AttributeSet attrs, View scrollView, boolean isVertical) {
+        mScrollView = scrollView;
+        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
+        mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
+                ViewConfiguration.get(context).getScaledFadingEdgeLength());
+        mIsVertical = isVertical;
+    }
+
+    public void onAttachedToWindowCallback(
+            LinearLayout layout, boolean hardwareAccelerated) {
+        mSoftwareRendered = !hardwareAccelerated;
+        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
+                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
+            mScrollView.setVerticalFadingEdgeEnabled(false);
+            mScrollView.setHorizontalFadingEdgeEnabled(false);
+        }
+    }
+
+    public void addViewCallback(View newLinearLayoutChild) {
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            final RecentsPanelView.ViewHolder holder =
+                    (RecentsPanelView.ViewHolder) newLinearLayoutChild.getTag();
+            holder.labelView.setDrawingCacheEnabled(true);
+            holder.labelView.buildDrawingCache();
+        }
+    }
+
+    public void drawCallback(Canvas canvas,
+            int left, int right, int top, int bottom, int scrollX, int scrollY,
+            float topFadingEdgeStrength, float bottomFadingEdgeStrength,
+            float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
+
+        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
+                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
+            if (mFadePaint == null) {
+                mFadePaint = new Paint();
+                mFadeMatrix = new Matrix();
+                // use use a height of 1, and then wack the matrix each time we
+                // actually use it.
+                mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
+                // PULL OUT THIS CONSTANT
+                mFadePaint.setShader(mFade);
+            }
+
+            // draw the fade effect
+            boolean drawTop = false;
+            boolean drawBottom = false;
+            boolean drawLeft = false;
+            boolean drawRight = false;
+
+            float topFadeStrength = 0.0f;
+            float bottomFadeStrength = 0.0f;
+            float leftFadeStrength = 0.0f;
+            float rightFadeStrength = 0.0f;
+
+            final float fadeHeight = mFadingEdgeLength;
+            int length = (int) fadeHeight;
+
+            // clip the fade length if top and bottom fades overlap
+            // overlapping fades produce odd-looking artifacts
+            if (mIsVertical && (top + length > bottom - length)) {
+                length = (bottom - top) / 2;
+            }
+
+            // also clip horizontal fades if necessary
+            if (!mIsVertical && (left + length > right - length)) {
+                length = (right - left) / 2;
+            }
+
+            if (mIsVertical) {
+                topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
+                drawTop = topFadeStrength * fadeHeight > 1.0f;
+                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
+                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
+            }
+
+            if (!mIsVertical) {
+                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
+                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
+                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
+                drawRight = rightFadeStrength * fadeHeight > 1.0f;
+            }
+
+            if (drawTop) {
+                mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
+                mFadeMatrix.postTranslate(left, top);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(left, top, right, top + length, mFadePaint);
+
+                if (mBlackPaint == null) {
+                    // Draw under the status bar at the top
+                    mBlackPaint = new Paint();
+                    mBlackPaint.setColor(0xFF000000);
+                }
+                canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
+            }
+
+            if (drawBottom) {
+                mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
+                mFadeMatrix.postRotate(180);
+                mFadeMatrix.postTranslate(left, bottom);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
+            }
+
+            if (drawLeft) {
+                mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
+                mFadeMatrix.postRotate(-90);
+                mFadeMatrix.postTranslate(left, top);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(left, top, left + length, bottom, mFadePaint);
+            }
+
+            if (drawRight) {
+                mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
+                mFadeMatrix.postRotate(90);
+                mFadeMatrix.postTranslate(right, top);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(right - length, top, right, bottom, mFadePaint);
+            }
+        }
+    }
+
+    public int getVerticalFadingEdgeLength() {
+        return mFadingEdgeLength;
+    }
+
+    public int getHorizontalFadingEdgeLength() {
+        return mFadingEdgeLength;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
index 2fc7dfc..84d13cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
@@ -19,18 +19,18 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
-import android.animation.Animator.AnimatorListener;
 import android.util.Log;
-import android.view.ViewTreeObserver;
 import android.view.View;
 import android.view.ViewPropertyAnimator;
+import android.view.ViewTreeObserver;
 
 /*
  *  This is a helper class that listens to updates from the corresponding animation.
  *  For the first two frames, it adjusts the current play time of the animation to
  *  prevent jank at the beginning of the animation
  */
-public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateListener {
+public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
+    implements ValueAnimator.AnimatorUpdateListener {
     private static final boolean DEBUG = false;
     private static final int MAX_DELAY = 1000;
     private static final int IDEAL_FRAME_DURATION = 16;
@@ -50,13 +50,14 @@
 
     public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
         mTarget = target;
-        vpa.setListener(new AnimatorListenerAdapter() {
-                public void onAnimationStart (Animator animation) {
-                    final ValueAnimator va = (ValueAnimator) animation;
-                    va.addUpdateListener(FirstFrameAnimatorHelper.this);
-                    onAnimationUpdate(va);
-                }
-            });
+        vpa.setListener(this);
+    }
+
+    // only used for ViewPropertyAnimators
+    public void onAnimationStart(Animator animation) {
+        final ValueAnimator va = (ValueAnimator) animation;
+        va.addUpdateListener(FirstFrameAnimatorHelper.this);
+        onAnimationUpdate(va);
     }
 
     public static void initializeDrawListener(View view) {
@@ -84,7 +85,11 @@
             mStartTime = currentTime;
         }
 
-        if (!mHandlingOnAnimationUpdate) {
+        if (!mHandlingOnAnimationUpdate &&
+            // If the current play time exceeds the duration, the animation
+            // will get finished, even if we call setCurrentPlayTime -- therefore
+            // don't adjust the animation in that case
+            animation.getCurrentPlayTime() < animation.getDuration()) {
             mHandlingOnAnimationUpdate = true;
             long frameNum = sGlobalFrameCounter - mStartFrame;
             // If we haven't drawn our first frame, reset the time to t = 0
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 02ddb73..c714d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -25,7 +25,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -37,7 +37,6 @@
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -46,7 +45,7 @@
 
 public class RecentTasksLoader implements View.OnTouchListener {
     static final String TAG = "RecentTasksLoader";
-    static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
+    static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
 
     private static final int DISPLAY_TASKS = 20;
     private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
@@ -63,8 +62,8 @@
     private Handler mHandler;
 
     private int mIconDpi;
-    private Bitmap mDefaultThumbnailBackground;
-    private Bitmap mDefaultIconBackground;
+    private ColorDrawableWithDimensions mDefaultThumbnailBackground;
+    private ColorDrawableWithDimensions mDefaultIconBackground;
     private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
 
     private boolean mFirstScreenful;
@@ -101,7 +100,7 @@
         // Render default icon (just a blank image)
         int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
         int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
-        mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
 
         // Render the default thumbnail background
         int thumbnailWidth =
@@ -111,9 +110,7 @@
         int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
 
         mDefaultThumbnailBackground =
-                Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
-        Canvas c = new Canvas(mDefaultThumbnailBackground);
-        c.drawColor(color);
+                new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
     }
 
     public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
@@ -126,11 +123,11 @@
         }
     }
 
-    public Bitmap getDefaultThumbnail() {
+    public Drawable getDefaultThumbnail() {
         return mDefaultThumbnailBackground;
     }
 
-    public Bitmap getDefaultIcon() {
+    public Drawable getDefaultIcon() {
         return mDefaultIconBackground;
     }
 
@@ -200,7 +197,7 @@
                 + td + ": " + thumbnail);
         synchronized (td) {
             if (thumbnail != null) {
-                td.setThumbnail(thumbnail);
+                td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
             } else {
                 td.setThumbnail(mDefaultThumbnailBackground);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
new file mode 100644
index 0000000..f5670e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -0,0 +1,222 @@
+/*
+ * 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.systemui.recent;
+
+import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.RecentsComponent;
+import com.android.systemui.SystemUI;
+
+public class Recents extends SystemUI implements RecentsComponent {
+    private static final String TAG = "Recents";
+    private static final boolean DEBUG = false;
+
+    @Override
+    public void start() {
+        putComponent(RecentsComponent.class, this);
+    }
+
+    @Override
+    public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
+        if (DEBUG) Log.d(TAG, "toggle recents panel");
+        try {
+            TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
+
+            Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
+            intent.setClassName("com.android.systemui",
+                    "com.android.systemui.recent.RecentsActivity");
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+            if (firstTask == null) {
+                if (RecentsActivity.forceOpaqueBackground(mContext)) {
+                    ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+                            R.anim.recents_launch_from_launcher_enter,
+                            R.anim.recents_launch_from_launcher_exit);
+                    mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
+                            UserHandle.USER_CURRENT));
+                } else {
+                    // The correct window animation will be applied via the activity's style
+                    mContext.startActivityAsUser(intent, new UserHandle(
+                            UserHandle.USER_CURRENT));
+                }
+
+            } else {
+                Bitmap first = null;
+                if (firstTask.getThumbnail() instanceof BitmapDrawable) {
+                    first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
+                } else {
+                    first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+                    Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
+                    d.draw(new Canvas(first));
+                }
+                final Resources res = mContext.getResources();
+
+                float thumbWidth = res
+                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
+                float thumbHeight = res
+                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
+                if (first == null) {
+                    throw new RuntimeException("Recents thumbnail is null");
+                }
+                if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
+                    first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
+                            true);
+                    if (first == null) {
+                        throw new RuntimeException("Recents thumbnail is null");
+                    }
+                }
+
+
+                DisplayMetrics dm = new DisplayMetrics();
+                display.getMetrics(dm);
+                // calculate it here, but consider moving it elsewhere
+                // first, determine which orientation you're in.
+                final Configuration config = res.getConfiguration();
+                int x, y;
+
+                if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                    float appLabelLeftMargin = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_app_label_left_margin);
+                    float appLabelWidth = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_app_label_width);
+                    float thumbLeftMargin = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_thumbnail_left_margin);
+                    float thumbBgPadding = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_thumbnail_bg_padding);
+
+                    float width = appLabelLeftMargin +
+                            +appLabelWidth
+                            + thumbLeftMargin
+                            + thumbWidth
+                            + 2 * thumbBgPadding;
+
+                    x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
+                            + thumbBgPadding + thumbLeftMargin);
+                    y = (int) (dm.heightPixels
+                            - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height)
+                            - thumbBgPadding);
+                    if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+                        x = dm.widthPixels - x - res.getDimensionPixelSize(
+                                R.dimen.status_bar_recents_thumbnail_width);
+                    }
+
+                } else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                    float thumbTopMargin = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_thumbnail_top_margin);
+                    float thumbBgPadding = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_thumbnail_bg_padding);
+                    float textPadding = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_text_description_padding);
+                    float labelTextSize = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_app_label_text_size);
+                    Paint p = new Paint();
+                    p.setTextSize(labelTextSize);
+                    float labelTextHeight = p.getFontMetricsInt().bottom
+                            - p.getFontMetricsInt().top;
+                    float descriptionTextSize = res.getDimensionPixelSize(
+                            R.dimen.status_bar_recents_app_description_text_size);
+                    p.setTextSize(descriptionTextSize);
+                    float descriptionTextHeight = p.getFontMetricsInt().bottom
+                            - p.getFontMetricsInt().top;
+
+                    float statusBarHeight = res.getDimensionPixelSize(
+                            com.android.internal.R.dimen.status_bar_height);
+                    float recentsItemTopPadding = statusBarHeight;
+
+                    float height = thumbTopMargin
+                            + thumbHeight
+                            + 2 * thumbBgPadding + textPadding + labelTextHeight
+                            + recentsItemTopPadding + textPadding + descriptionTextHeight;
+                    float recentsItemRightPadding = res
+                            .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
+                    float recentsScrollViewRightPadding = res
+                            .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
+                    x = (int) (dm.widthPixels - res
+                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
+                            - thumbBgPadding - recentsItemRightPadding
+                            - recentsScrollViewRightPadding);
+                    y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
+                            + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
+                }
+
+                ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
+                        statusBarView,
+                        first, x, y,
+                        new ActivityOptions.OnAnimationStartedListener() {
+                            public void onAnimationStarted() {
+                                Intent intent =
+                                        new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
+                                intent.setPackage("com.android.systemui");
+                                mContext.sendBroadcastAsUser(intent,
+                                        new UserHandle(UserHandle.USER_CURRENT));
+                            }
+                        });
+                intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
+                mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
+                        UserHandle.USER_CURRENT));
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.e(TAG, "Failed to launch RecentAppsIntent", e);
+        }
+    }
+
+    @Override
+    public void preloadRecentTasksList() {
+        if (DEBUG) Log.d(TAG, "preloading recents");
+        Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.recent.RecentsPreloadReceiver");
+        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+        RecentTasksLoader.getInstance(mContext).preloadFirstTask();
+    }
+
+    @Override
+    public void cancelPreloadingRecentTasksList() {
+        if (DEBUG) Log.d(TAG, "cancel preloading recents");
+        Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.recent.RecentsPreloadReceiver");
+        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+        RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
+    }
+
+    @Override
+    public void closeRecents() {
+        if (DEBUG) Log.d(TAG, "closing recents panel");
+        Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+        intent.setPackage("com.android.systemui");
+        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index 62030ad..818c2980 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -30,7 +30,7 @@
 import android.view.WindowManager;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.tablet.StatusBarPanel;
+import com.android.systemui.statusbar.StatusBarPanel;
 
 import java.util.List;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 217b7fd..be42bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -49,16 +49,17 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
-    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
     private HashSet<View> mRecycledViews;
     private int mNumItemsInOneScreenful;
+    private Runnable mOnScrollListener;
 
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
-        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
         mRecycledViews = new HashSet<View>();
     }
 
@@ -108,8 +109,8 @@
 
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
-            if (mPerformanceHelper != null) {
-                mPerformanceHelper.addViewCallback(view);
+            if (mFadedEdgeDrawHelper != null) {
+                mFadedEdgeDrawHelper.addViewCallback(view);
             }
 
             OnTouchListener noOpListener = new OnTouchListener() {
@@ -234,26 +235,10 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
+    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+        if (mFadedEdgeDrawHelper != null) {
 
-        if (mPerformanceHelper != null) {
-            int paddingLeft = mPaddingLeft;
-            final boolean offsetRequired = isPaddingOffsetRequired();
-            if (offsetRequired) {
-                paddingLeft += getLeftPaddingOffset();
-            }
-
-            int left = mScrollX + paddingLeft;
-            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-            int top = mScrollY + getFadeTop(offsetRequired);
-            int bottom = top + getFadeHeight(offsetRequired);
-
-            if (offsetRequired) {
-                right += getRightPaddingOffset();
-                bottom += getBottomPaddingOffset();
-            }
-            mPerformanceHelper.drawCallback(canvas,
+            mFadedEdgeDrawHelper.drawCallback(canvas,
                     left, right, top, bottom, mScrollX, mScrollY,
                     0, 0,
                     getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
@@ -261,9 +246,21 @@
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+       super.onScrollChanged(l, t, oldl, oldt);
+       if (mOnScrollListener != null) {
+           mOnScrollListener.run();
+       }
+    }
+
+    public void setOnScrollListener(Runnable listener) {
+        mOnScrollListener = listener;
+    }
+
+    @Override
     public int getVerticalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
         } else {
             return super.getVerticalFadingEdgeLength();
         }
@@ -271,8 +268,8 @@
 
     @Override
     public int getHorizontalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
         } else {
             return super.getHorizontalFadingEdgeLength();
         }
@@ -290,9 +287,8 @@
 
     @Override
     public void onAttachedToWindow() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onAttachedToWindowCallback(
-                    mCallback, mLinearLayout, isHardwareAccelerated());
+        if (mFadedEdgeDrawHelper != null) {
+            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index c64b954..788e843 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -23,12 +23,14 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Shader.TileMode;
 import android.graphics.drawable.BitmapDrawable;
@@ -61,21 +63,19 @@
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.StatusBarPanel;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.tablet.StatusBarPanel;
-import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
 import java.util.ArrayList;
 
 public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
         StatusBarPanel, Animator.AnimatorListener {
     static final String TAG = "RecentsPanelView";
-    static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
+    static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
     private PopupMenu mPopup;
     private View mRecentsScrim;
     private View mRecentsNoApps;
-    private ViewGroup mRecentsContainer;
-    private StatusBarTouchProxy mStatusBarTouchProxy;
+    private RecentsScrollView mRecentsContainer;
 
     private boolean mShowing;
     private boolean mWaitingToShow;
@@ -99,6 +99,8 @@
         public void setCallback(RecentsCallback callback);
         public void setMinSwipeAlpha(float minAlpha);
         public View findViewForTask(int persistentTaskId);
+        public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
+        public void setOnScrollListener(Runnable listener);
     }
 
     private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -114,7 +116,7 @@
     /* package */ final static class ViewHolder {
         View thumbnailView;
         ImageView thumbnailViewImage;
-        Bitmap thumbnailViewImageBitmap;
+        Drawable thumbnailViewDrawable;
         ImageView iconView;
         TextView labelView;
         TextView descriptionView;
@@ -152,7 +154,7 @@
             // the thumbnail later (if they both have the same dimensions)
             updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
             holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
-            holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+            holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
             holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
             holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
             holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -228,7 +230,7 @@
         public void recycleView(View v) {
             ViewHolder holder = (ViewHolder) v.getTag();
             updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-            holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+            holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
             holder.iconView.setVisibility(INVISIBLE);
             holder.iconView.animate().cancel();
             holder.labelView.setText(null);
@@ -271,13 +273,7 @@
     }
 
     public int numItemsInOneScreenful() {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                    = (RecentsScrollView) mRecentsContainer;
-            return scrollView.numItemsInOneScreenful();
-        }  else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
+        return mRecentsContainer.numItemsInOneScreenful();
     }
 
     private boolean pointInside(int x, int y, View v) {
@@ -289,14 +285,7 @@
     }
 
     public boolean isInContentArea(int x, int y) {
-        if (pointInside(x, y, mRecentsContainer)) {
-            return true;
-        } else if (mStatusBarTouchProxy != null &&
-                pointInside(x, y, mStatusBarTouchProxy)) {
-            return true;
-        } else {
-            return false;
-        }
+        return pointInside(x, y, (View) mRecentsContainer);
     }
 
     public void show(boolean show) {
@@ -430,12 +419,6 @@
         return mShowing;
     }
 
-    public void setStatusBarView(View statusBarView) {
-        if (mStatusBarTouchProxy != null) {
-            mStatusBarTouchProxy.setStatusBar(statusBarView);
-        }
-    }
-
     public void setRecentTasksLoader(RecentTasksLoader loader) {
         mRecentTasksLoader = loader;
     }
@@ -450,17 +433,16 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
-        mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
+        mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
+        mRecentsContainer.setOnScrollListener(new Runnable() {
+            public void run() {
+                // need to redraw the faded edges
+                invalidate();
+            }
+        });
         mListAdapter = new TaskDescriptionAdapter(mContext);
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                    = (RecentsScrollView) mRecentsContainer;
-            scrollView.setAdapter(mListAdapter);
-            scrollView.setCallback(this);
-        } else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
+        mRecentsContainer.setAdapter(mListAdapter);
+        mRecentsContainer.setCallback(this);
 
         mRecentsScrim = findViewById(R.id.recents_bg_protect);
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
@@ -477,11 +459,7 @@
     }
 
     public void setMinSwipeAlpha(float minAlpha) {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                = (RecentsScrollView) mRecentsContainer;
-            scrollView.setMinSwipeAlpha(minAlpha);
-        }
+        mRecentsContainer.setMinSwipeAlpha(minAlpha);
     }
 
     private void createCustomAnimations(LayoutTransition transitioner) {
@@ -503,23 +481,23 @@
         }
     }
 
-    private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
+    private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
         if (thumbnail != null) {
             // Should remove the default image in the frame
             // that this now covers, to improve scrolling speed.
             // That can't be done until the anim is complete though.
-            h.thumbnailViewImage.setImageBitmap(thumbnail);
+            h.thumbnailViewImage.setImageDrawable(thumbnail);
 
             // scale the image to fill the full width of the ImageView. do this only if
             // we haven't set a bitmap before, or if the bitmap size has changed
-            if (h.thumbnailViewImageBitmap == null ||
-                h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
-                h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
+            if (h.thumbnailViewDrawable == null ||
+                h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
+                h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
                 if (mFitThumbnailToXY) {
                     h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
                 } else {
                     Matrix scaleMatrix = new Matrix();
-                    float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+                    float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
                     scaleMatrix.setScale(scale, scale);
                     h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
                     h.thumbnailViewImage.setImageMatrix(scaleMatrix);
@@ -532,14 +510,14 @@
                 }
                 h.thumbnailView.setVisibility(View.VISIBLE);
             }
-            h.thumbnailViewImageBitmap = thumbnail;
+            h.thumbnailViewDrawable = thumbnail;
         }
     }
 
     void onTaskThumbnailLoaded(TaskDescription td) {
         synchronized (td) {
             if (mRecentsContainer != null) {
-                ViewGroup container = mRecentsContainer;
+                ViewGroup container = (ViewGroup) mRecentsContainer;
                 if (container instanceof RecentsScrollView) {
                     container = (ViewGroup) container.findViewById(
                             R.id.recents_linear_layout);
@@ -648,7 +626,7 @@
         final int items = mRecentTaskDescriptions != null
                 ? mRecentTaskDescriptions.size() : 0;
 
-        mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
+        ((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
 
         // Set description for accessibility
         int numRecentApps = mRecentTaskDescriptions != null
@@ -665,33 +643,33 @@
     }
 
     public boolean simulateClick(int persistentTaskId) {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                = (RecentsScrollView) mRecentsContainer;
-            View v = scrollView.findViewForTask(persistentTaskId);
-            if (v != null) {
-                handleOnClick(v);
-                return true;
-            }
+        View v = mRecentsContainer.findViewForTask(persistentTaskId);
+        if (v != null) {
+            handleOnClick(v);
+            return true;
         }
         return false;
     }
 
     public void handleOnClick(View view) {
-        ViewHolder holder = (ViewHolder)view.getTag();
+        ViewHolder holder = (ViewHolder) view.getTag();
         TaskDescription ad = holder.taskDescription;
         final Context context = view.getContext();
         final ActivityManager am = (ActivityManager)
                 context.getSystemService(Context.ACTIVITY_SERVICE);
-        Bitmap bm = holder.thumbnailViewImageBitmap;
-        boolean usingDrawingCache;
-        if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
-                bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
-            usingDrawingCache = false;
-        } else {
+
+        Bitmap bm = null;
+        boolean usingDrawingCache = true;
+        if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
+            bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
+            if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
+                    bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
+                usingDrawingCache = false;
+            }
+        }
+        if (usingDrawingCache) {
             holder.thumbnailViewImage.setDrawingCacheEnabled(true);
             bm = holder.thumbnailViewImage.getDrawingCache();
-            usingDrawingCache = true;
         }
         Bundle opts = (bm == null) ?
                 null :
@@ -714,6 +692,8 @@
                         new UserHandle(UserHandle.USER_CURRENT));
             } catch (SecurityException e) {
                 Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "Error launching activity " + intent, e);
             }
         }
         if (usingDrawingCache) {
@@ -784,7 +764,7 @@
         popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
             public boolean onMenuItemClick(MenuItem item) {
                 if (item.getItemId() == R.id.recent_remove_item) {
-                    mRecentsContainer.removeViewInLayout(selectedView);
+                    ((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
                 } else if (item.getItemId() == R.id.recent_inspect_item) {
                     ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
                     if (viewHolder != null) {
@@ -808,4 +788,26 @@
         });
         popup.show();
     }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        int paddingLeft = mPaddingLeft;
+        final boolean offsetRequired = isPaddingOffsetRequired();
+        if (offsetRequired) {
+            paddingLeft += getLeftPaddingOffset();
+        }
+
+        int left = mScrollX + paddingLeft;
+        int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+        int top = mScrollY + getFadeTop(offsetRequired);
+        int bottom = top + getFadeHeight(offsetRequired);
+
+        if (offsetRequired) {
+            right += getRightPaddingOffset();
+            bottom += getBottomPaddingOffset();
+        }
+        mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
deleted file mode 100644
index f17766b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.recent;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Shader;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-
-public class RecentsScrollViewPerformanceHelper {
-    public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
-    public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
-    private View mScrollView;
-
-    private int mFadingEdgeLength;
-    private boolean mIsVertical;
-    private boolean mSoftwareRendered = false;
-    private Paint mBlackPaint;
-    private Paint mFadePaint;
-    private Matrix mFadeMatrix;
-    private LinearGradient mFade;
-
-    public static RecentsScrollViewPerformanceHelper create(Context context,
-            AttributeSet attrs, View scrollView, boolean isVertical) {
-        boolean isTablet = context.getResources().
-                getBoolean(R.bool.config_recents_interface_for_tablets);
-        if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
-            return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
-        } else {
-            return null;
-        }
-    }
-
-    public RecentsScrollViewPerformanceHelper(Context context,
-            AttributeSet attrs, View scrollView, boolean isVertical) {
-        mScrollView = scrollView;
-        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
-        mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
-                ViewConfiguration.get(context).getScaledFadingEdgeLength());
-        mIsVertical = isVertical;
-    }
-
-    public void onAttachedToWindowCallback(
-            RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
-        mSoftwareRendered = !hardwareAccelerated;
-        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
-                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
-            mScrollView.setVerticalFadingEdgeEnabled(false);
-            mScrollView.setHorizontalFadingEdgeEnabled(false);
-        }
-    }
-
-    public void addViewCallback(View newLinearLayoutChild) {
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            final RecentsPanelView.ViewHolder holder =
-                    (RecentsPanelView.ViewHolder) newLinearLayoutChild.getTag();
-            holder.labelView.setDrawingCacheEnabled(true);
-            holder.labelView.buildDrawingCache();
-        }
-    }
-
-    public void drawCallback(Canvas canvas,
-            int left, int right, int top, int bottom, int scrollX, int scrollY,
-            float topFadingEdgeStrength, float bottomFadingEdgeStrength,
-            float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
-
-        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
-                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
-            if (mFadePaint == null) {
-                mFadePaint = new Paint();
-                mFadeMatrix = new Matrix();
-                // use use a height of 1, and then wack the matrix each time we
-                // actually use it.
-                mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
-                // PULL OUT THIS CONSTANT
-                mFadePaint.setShader(mFade);
-            }
-
-            // draw the fade effect
-            boolean drawTop = false;
-            boolean drawBottom = false;
-            boolean drawLeft = false;
-            boolean drawRight = false;
-
-            float topFadeStrength = 0.0f;
-            float bottomFadeStrength = 0.0f;
-            float leftFadeStrength = 0.0f;
-            float rightFadeStrength = 0.0f;
-
-            final float fadeHeight = mFadingEdgeLength;
-            int length = (int) fadeHeight;
-
-            // clip the fade length if top and bottom fades overlap
-            // overlapping fades produce odd-looking artifacts
-            if (mIsVertical && (top + length > bottom - length)) {
-                length = (bottom - top) / 2;
-            }
-
-            // also clip horizontal fades if necessary
-            if (!mIsVertical && (left + length > right - length)) {
-                length = (right - left) / 2;
-            }
-
-            if (mIsVertical) {
-                topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
-                drawTop = topFadeStrength * fadeHeight > 1.0f;
-                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
-                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
-            }
-
-            if (!mIsVertical) {
-                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
-                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
-                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
-                drawRight = rightFadeStrength * fadeHeight > 1.0f;
-            }
-
-            if (drawTop) {
-                mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
-                mFadeMatrix.postTranslate(left, top);
-                mFade.setLocalMatrix(mFadeMatrix);
-                canvas.drawRect(left, top, right, top + length, mFadePaint);
-
-                if (mBlackPaint == null) {
-                    // Draw under the status bar at the top
-                    mBlackPaint = new Paint();
-                    mBlackPaint.setColor(0xFF000000);
-                }
-                canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
-            }
-
-            if (drawBottom) {
-                mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
-                mFadeMatrix.postRotate(180);
-                mFadeMatrix.postTranslate(left, bottom);
-                mFade.setLocalMatrix(mFadeMatrix);
-                canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
-            }
-
-            if (drawLeft) {
-                mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
-                mFadeMatrix.postRotate(-90);
-                mFadeMatrix.postTranslate(left, top);
-                mFade.setLocalMatrix(mFadeMatrix);
-                canvas.drawRect(left, top, left + length, bottom, mFadePaint);
-            }
-
-            if (drawRight) {
-                mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
-                mFadeMatrix.postRotate(90);
-                mFadeMatrix.postTranslate(right, top);
-                mFade.setLocalMatrix(mFadeMatrix);
-                canvas.drawRect(right - length, top, right, bottom, mFadePaint);
-            }
-        }
-    }
-
-    public int getVerticalFadingEdgeLengthCallback() {
-        return mFadingEdgeLength;
-    }
-
-    public int getHorizontalFadingEdgeLengthCallback() {
-        return mFadingEdgeLength;
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 403c643f..6dddc39 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -21,7 +21,6 @@
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.FloatMath;
@@ -50,9 +49,10 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
-    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
     private HashSet<View> mRecycledViews;
     private int mNumItemsInOneScreenful;
+    private Runnable mOnScrollListener;
 
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
@@ -60,7 +60,7 @@
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
 
-        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
         mRecycledViews = new HashSet<View>();
     }
 
@@ -113,8 +113,8 @@
             }
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
-            if (mPerformanceHelper != null) {
-                mPerformanceHelper.addViewCallback(view);
+            if (mFadedEdgeDrawHelper != null) {
+                mFadedEdgeDrawHelper.addViewCallback(view);
             }
 
             OnTouchListener noOpListener = new OnTouchListener() {
@@ -244,36 +244,32 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        if (mPerformanceHelper != null) {
-            int paddingLeft = mPaddingLeft;
+    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+        if (mFadedEdgeDrawHelper != null) {
             final boolean offsetRequired = isPaddingOffsetRequired();
-            if (offsetRequired) {
-                paddingLeft += getLeftPaddingOffset();
-            }
-
-            int left = mScrollX + paddingLeft;
-            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-            int top = mScrollY + getFadeTop(offsetRequired);
-            int bottom = top + getFadeHeight(offsetRequired);
-
-            if (offsetRequired) {
-                right += getRightPaddingOffset();
-                bottom += getBottomPaddingOffset();
-            }
-            mPerformanceHelper.drawCallback(canvas,
-                    left, right, top, bottom, mScrollX, mScrollY,
+            mFadedEdgeDrawHelper.drawCallback(canvas,
+                    left, right, top + getFadeTop(offsetRequired), bottom, mScrollX, mScrollY,
                     getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
                     0, 0, mPaddingTop);
         }
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+       super.onScrollChanged(l, t, oldl, oldt);
+       if (mOnScrollListener != null) {
+           mOnScrollListener.run();
+       }
+    }
+
+    public void setOnScrollListener(Runnable listener) {
+        mOnScrollListener = listener;
+    }
+
+    @Override
     public int getVerticalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
         } else {
             return super.getVerticalFadingEdgeLength();
         }
@@ -281,8 +277,8 @@
 
     @Override
     public int getHorizontalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
         } else {
             return super.getHorizontalFadingEdgeLength();
         }
@@ -300,9 +296,8 @@
 
     @Override
     public void onAttachedToWindow() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onAttachedToWindowCallback(
-                    mCallback, mLinearLayout, isHardwareAccelerated());
+        if (mFadedEdgeDrawHelper != null) {
+            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java b/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java
deleted file mode 100644
index ded114f..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.recent;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-public class StatusBarTouchProxy extends FrameLayout {
-
-    private View mStatusBar;
-
-    public StatusBarTouchProxy(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void setStatusBar(View statusBar) {
-        mStatusBar = statusBar;
-    }
-
-    public boolean onTouchEvent (MotionEvent event) {
-        return mStatusBar.dispatchTouchEvent(event);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index 7e979b7..2bc2821 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -29,7 +29,7 @@
     final String packageName; // used to override animations (see onClick())
     final CharSequence description;
 
-    private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
+    private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
     private Drawable mIcon; // application package icon
     private CharSequence mLabel; // application package label
     private boolean mLoaded;
@@ -85,11 +85,11 @@
         mIcon = icon;
     }
 
-    public void setThumbnail(Bitmap thumbnail) {
+    public void setThumbnail(Drawable thumbnail) {
         mThumbnail = thumbnail;
     }
 
-    public Bitmap getThumbnail() {
+    public Drawable getThumbnail() {
         return mThumbnail;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index b5b393d..74d982a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -45,7 +45,6 @@
 import android.os.Process;
 import android.provider.MediaStore;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -198,6 +197,10 @@
             // Create screenshot directory if it doesn't exist
             mScreenshotDir.mkdirs();
 
+            // media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds
+            // for DATE_TAKEN
+            long dateSeconds = mImageTime / 1000;
+
             // Save the screenshot to the MediaStore
             ContentValues values = new ContentValues();
             ContentResolver resolver = context.getContentResolver();
@@ -205,8 +208,8 @@
             values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);
             values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);
             values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, mImageTime);
-            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, mImageTime);
-            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, mImageTime);
+            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, dateSeconds);
+            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, dateSeconds);
             values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
             values.put(MediaStore.Images.ImageColumns.WIDTH, mImageWidth);
             values.put(MediaStore.Images.ImageColumns.HEIGHT, mImageHeight);
@@ -220,12 +223,12 @@
             sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
 
             Intent chooserIntent = Intent.createChooser(sharingIntent, null);
-            chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK 
+            chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
                     | Intent.FLAG_ACTIVITY_NEW_TASK);
 
             mNotificationBuilder.addAction(R.drawable.ic_menu_share,
                      r.getString(com.android.internal.R.string.share),
-                     PendingIntent.getActivity(context, 0, chooserIntent, 
+                     PendingIntent.getActivity(context, 0, chooserIntent,
                              PendingIntent.FLAG_CANCEL_CURRENT));
 
             OutputStream out = resolver.openOutputStream(uri);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 6a0fe47..456b5fa 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -23,7 +23,6 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.util.Log;
 
 public class TakeScreenshotService extends Service {
     private static final String TAG = "TakeScreenshotService";
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index fdeead1..327e715 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -18,7 +18,6 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -30,9 +29,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.widget.CompoundButton;
 import android.widget.ImageView;
 
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 1b05084..ff79f04 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -16,19 +16,16 @@
 
 package com.android.systemui.settings;
 
-import com.android.systemui.R;
-
 import android.app.Dialog;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.ImageView;
 
-import java.lang.Runnable;
+import com.android.systemui.R;
 
 /** A dialog that provides controls for adjusting the screen brightness. */
 public class BrightnessDialog extends Dialog implements
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index 122f81e..036bd4f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.UserHandle;
 
 public abstract class CurrentUserTracker extends BroadcastReceiver {
 
@@ -54,4 +55,8 @@
     }
 
     public abstract void onUserSwitched(int newUserId);
+
+    public boolean isCurrentUserOwner() {
+        return mCurrentUserId == UserHandle.USER_OWNER;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java b/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java
index 1075a73..8bc72c9 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.settings;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -26,10 +23,13 @@
 import android.content.IntentFilter;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.systemui.SystemUI;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public class SettingsUI extends SystemUI {
     private static final String TAG = "SettingsUI";
     private static final boolean DEBUG = false;
@@ -42,7 +42,7 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (action.equals(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)) {
-                if (DEBUG) Slog.d(TAG, "showing brightness dialog");
+                if (DEBUG) Log.d(TAG, "showing brightness dialog");
 
                 if (mBrightnessDialog == null) {
                     mBrightnessDialog = new BrightnessDialog(mContext);
@@ -59,7 +59,7 @@
                 }
 
             } else {
-                Slog.w(TAG, "unknown intent: " + intent);
+                Log.w(TAG, "unknown intent: " + intent);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index c7c361c..d584043 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -21,10 +21,8 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.Slog;
 import android.view.View;
 import android.widget.CompoundButton;
-import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
 import android.widget.SeekBar;
 import android.widget.TextView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 78226c5..9839fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -20,7 +20,6 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.Slog;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.RemoteViews.RemoteView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 683824b..932fe20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2010 The Android Open Source Project
  *
@@ -17,52 +16,36 @@
 
 package com.android.systemui.statusbar;
 
-import android.service.notification.StatusBarNotification;
-import android.content.res.Configuration;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.widget.SizeAdaptiveLayout;
-import com.android.systemui.R;
-import com.android.systemui.SearchPanelView;
-import com.android.systemui.SystemUI;
-import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsActivity;
-import com.android.systemui.recent.TaskDescription;
-import com.android.systemui.statusbar.policy.NotificationRowLayout;
-import com.android.systemui.statusbar.tablet.StatusBarPanel;
-
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
 import android.app.KeyguardManager;
+import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.TaskStackBuilder;
-import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.Paint;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.Slog;
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.LayoutInflater;
@@ -79,6 +62,16 @@
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.widget.SizeAdaptiveLayout;
+import com.android.systemui.R;
+import com.android.systemui.RecentsComponent;
+import com.android.systemui.SearchPanelView;
+import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.policy.NotificationRowLayout;
+
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -94,10 +87,14 @@
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
     protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
     protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
-    protected static final int MSG_SHOW_INTRUDER = 1026;
-    protected static final int MSG_HIDE_INTRUDER = 1027;
+    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 boolean ENABLE_INTRUDERS = false;
+    protected static final boolean ENABLE_HEADS_UP = true;
+    // scores above this threshold should be displayed in heads up mode.
+    protected static final int INTERRUPTION_THRESHOLD = 11;
+    protected static final String SETTING_HEADS_UP = "heads_up_enabled";
 
     // Should match the value in PhoneWindowManager
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -113,7 +110,8 @@
     protected NotificationData mNotificationData = new NotificationData();
     protected NotificationRowLayout mPile;
 
-    protected StatusBarNotification mCurrentlyIntrudingNotification;
+    protected NotificationData.Entry mInterruptingNotificationEntry;
+    protected long mInterruptingNotificationTime;
 
     // used to notify status bar for suppressing notification LED
     protected boolean mPanelSlightlyVisible;
@@ -125,8 +123,14 @@
 
     protected int mCurrentUserId = 0;
 
-    protected int mLayoutDirection;
+    protected int mLayoutDirection = -1; // invalid
     private Locale mLocale;
+    protected boolean mUseHeadsUp = false;
+
+    protected IDreamManager mDreamManager;
+    KeyguardManager mKeyguardManager;
+    PowerManager mPowerManager;
+    protected int mRowHeight;
 
     // UI-specific methods
 
@@ -144,6 +148,8 @@
 
     private boolean mDeviceProvisioned = false;
 
+    private RecentsComponent mRecents;
+
     public IStatusBarService getStatusBarService() {
         return mBarService;
     }
@@ -168,7 +174,7 @@
         @Override
         public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
             if (DEBUG) {
-                Slog.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
+                Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
             }
             final boolean isActivity = pendingIntent.isActivity();
             if (isActivity) {
@@ -196,11 +202,28 @@
         }
     };
 
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+                userSwitched(mCurrentUserId);
+            }
+        }
+    };
+
     public void start() {
         mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
         mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
         mDisplay = mWindowManager.getDefaultDisplay();
 
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.checkService(DreamService.DREAM_SERVICE));
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+
         mProvisioningObserver.onChange(false); // set up
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
@@ -209,6 +232,8 @@
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
+        mRecents = getComponent(RecentsComponent.class);
+
         mLocale = mContext.getResources().getConfiguration().locale;
         mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
 
@@ -259,7 +284,7 @@
         }
 
         if (DEBUG) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
                    iconList.size(),
                    switches[0],
@@ -273,18 +298,7 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-                    if (true) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
-                    userSwitched(mCurrentUserId);
-                }
-            }}, filter);
-
-        mLocale = mContext.getResources().getConfiguration().locale;
+        mContext.registerReceiver(mBroadcastReceiver, filter);
     }
 
     public void userSwitched(int newUserId) {
@@ -295,7 +309,7 @@
         final int thisUserId = mCurrentUserId;
         final int notificationUserId = n.getUserId();
         if (DEBUG && MULTIUSER_DEBUG) {
-            Slog.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
+            Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
                     n, thisUserId, notificationUserId));
         }
         return notificationUserId == UserHandle.USER_ALL
@@ -304,17 +318,24 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
-        final Locale newLocale = mContext.getResources().getConfiguration().locale;
-        if (! newLocale.equals(mLocale)) {
-            mLocale = newLocale;
-            mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
-            refreshLayout(mLayoutDirection);
+        final Locale locale = mContext.getResources().getConfiguration().locale;
+        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
+        if (! locale.equals(mLocale) || ld != mLayoutDirection) {
+            if (DEBUG) {
+                Log.v(TAG, String.format(
+                        "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
+                        locale, ld));
+            }
+            mLocale = locale;
+            mLayoutDirection = ld;
+            refreshLayout(ld);
         }
     }
 
     protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
         View vetoButton = row.findViewById(R.id.veto);
-        if (n.isClearable()) {
+        if (n.isClearable() || (mInterruptingNotificationEntry != null
+                && mInterruptingNotificationEntry.row == row)) {
             final String _pkg = n.getPackageName();
             final String _tag = n.getTag();
             final int _id = n.getId();
@@ -348,7 +369,7 @@
                 ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
                 version = info.targetSdkVersion;
             } catch (NameNotFoundException ex) {
-                Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
+                Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
             }
             if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
                 content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
@@ -402,8 +423,7 @@
         }
     }
 
-    public void dismissIntruder() {
-        // pass
+    public void onHeadsUpDismissed() {
     }
 
     @Override
@@ -441,9 +461,6 @@
         mHandler.sendEmptyMessage(msg);
     }
 
-    protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
-            LayoutParams layoutParams);
-
     protected abstract WindowManager.LayoutParams getSearchLayoutParams(
             LayoutParams layoutParams);
 
@@ -487,141 +504,6 @@
 
     protected abstract View getStatusBarView();
 
-    protected void toggleRecentsActivity() {
-        try {
-
-            TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
-
-            Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
-            intent.setClassName("com.android.systemui",
-                    "com.android.systemui.recent.RecentsActivity");
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
-            if (firstTask == null) {
-                if (RecentsActivity.forceOpaqueBackground(mContext)) {
-                    ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                            R.anim.recents_launch_from_launcher_enter,
-                            R.anim.recents_launch_from_launcher_exit);
-                    mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
-                            UserHandle.USER_CURRENT));
-                } else {
-                    // The correct window animation will be applied via the activity's style
-                    mContext.startActivityAsUser(intent, new UserHandle(
-                            UserHandle.USER_CURRENT));
-                }
-
-            } else {
-                Bitmap first = firstTask.getThumbnail();
-                final Resources res = mContext.getResources();
-
-                float thumbWidth = res
-                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
-                float thumbHeight = res
-                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
-                if (first == null) {
-                    throw new RuntimeException("Recents thumbnail is null");
-                }
-                if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
-                    first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
-                            true);
-                    if (first == null) {
-                        throw new RuntimeException("Recents thumbnail is null");
-                    }
-                }
-
-
-                DisplayMetrics dm = new DisplayMetrics();
-                mDisplay.getMetrics(dm);
-                // calculate it here, but consider moving it elsewhere
-                // first, determine which orientation you're in.
-                // todo: move the system_bar layouts to sw600dp ?
-                final Configuration config = res.getConfiguration();
-                int x, y;
-
-                if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-                    float appLabelLeftMargin = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_left_margin);
-                    float appLabelWidth = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_width);
-                    float thumbLeftMargin = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_left_margin);
-                    float thumbBgPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_bg_padding);
-
-                    float width = appLabelLeftMargin +
-                            +appLabelWidth
-                            + thumbLeftMargin
-                            + thumbWidth
-                            + 2 * thumbBgPadding;
-
-                    x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
-                            + thumbBgPadding + thumbLeftMargin);
-                    y = (int) (dm.heightPixels
-                            - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height) - thumbBgPadding);
-                    if (mLayoutDirection == View.LAYOUT_DIRECTION_RTL) {
-                        x = dm.widthPixels - x - res
-                                .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
-                    }
-
-                } else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-                    float thumbTopMargin = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_top_margin);
-                    float thumbBgPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_bg_padding);
-                    float textPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_text_description_padding);
-                    float labelTextSize = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_text_size);
-                    Paint p = new Paint();
-                    p.setTextSize(labelTextSize);
-                    float labelTextHeight = p.getFontMetricsInt().bottom
-                            - p.getFontMetricsInt().top;
-                    float descriptionTextSize = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_app_description_text_size);
-                    p.setTextSize(descriptionTextSize);
-                    float descriptionTextHeight = p.getFontMetricsInt().bottom
-                            - p.getFontMetricsInt().top;
-
-                    float statusBarHeight = res
-                            .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-                    float recentsItemTopPadding = statusBarHeight;
-
-                    float height = thumbTopMargin
-                            + thumbHeight
-                            + 2 * thumbBgPadding + textPadding + labelTextHeight
-                            + recentsItemTopPadding + textPadding + descriptionTextHeight;
-                    float recentsItemRightPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
-                    float recentsScrollViewRightPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
-                    x = (int) (dm.widthPixels - res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
-                            - thumbBgPadding - recentsItemRightPadding - recentsScrollViewRightPadding);
-                    y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
-                            + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
-                }
-
-                ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
-                        getStatusBarView(),
-                        first, x, y,
-                        new ActivityOptions.OnAnimationStartedListener() {
-                            public void onAnimationStarted() {
-                                Intent intent = new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
-                                intent.setPackage("com.android.systemui");
-                                mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-                            }
-                        });
-                intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
-                mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
-                        UserHandle.USER_CURRENT));
-            }
-            return;
-        } catch (ActivityNotFoundException e) {
-            Log.e(TAG, "Failed to launch RecentAppsIntent", e);
-        }
-    }
-
     protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
         // additional optimization when we have software system buttons - start loading the recent
         // tasks on touch down
@@ -642,39 +524,41 @@
         }
     };
 
-    protected void preloadRecentTasksList() {
-        if (DEBUG) Slog.d(TAG, "preloading recents");
-        Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
-        intent.setClassName("com.android.systemui",
-                "com.android.systemui.recent.RecentsPreloadReceiver");
-        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+    protected void toggleRecentsActivity() {
+        if (mRecents != null) {
+            mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
+        }
+    }
 
-        RecentTasksLoader.getInstance(mContext).preloadFirstTask();
+    protected void preloadRecentTasksList() {
+        if (mRecents != null) {
+            mRecents.preloadRecentTasksList();
+        }
     }
 
     protected void cancelPreloadingRecentTasksList() {
-        if (DEBUG) Slog.d(TAG, "cancel preloading recents");
-        Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
-        intent.setClassName("com.android.systemui",
-                "com.android.systemui.recent.RecentsPreloadReceiver");
-        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-
-        RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
+        if (mRecents != null) {
+            mRecents.cancelPreloadingRecentTasksList();
+        }
     }
 
+    protected void closeRecents() {
+        if (mRecents != null) {
+            mRecents.closeRecents();
+        }
+    }
+
+    public abstract void resetHeadsUpDecayTimer();
+
     protected class H extends Handler {
         public void handleMessage(Message m) {
             Intent intent;
             switch (m.what) {
              case MSG_TOGGLE_RECENTS_PANEL:
-                 if (DEBUG) Slog.d(TAG, "toggle recents panel");
                  toggleRecentsActivity();
                  break;
              case MSG_CLOSE_RECENTS_PANEL:
-                 if (DEBUG) Slog.d(TAG, "closing recents panel");
-                 intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
-                 intent.setPackage("com.android.systemui");
-                 mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+                 closeRecents();
                  break;
              case MSG_PRELOAD_RECENT_APPS:
                   preloadRecentTasksList();
@@ -683,13 +567,13 @@
                   cancelPreloadingRecentTasksList();
                   break;
              case MSG_OPEN_SEARCH_PANEL:
-                 if (DEBUG) Slog.d(TAG, "opening search panel");
+                 if (DEBUG) Log.d(TAG, "opening search panel");
                  if (mSearchPanelView != null && mSearchPanelView.isAssistantAvailable()) {
                      mSearchPanelView.show(true, true);
                  }
                  break;
              case MSG_CLOSE_SEARCH_PANEL:
-                 if (DEBUG) Slog.d(TAG, "closing search panel");
+                 if (DEBUG) Log.d(TAG, "closing search panel");
                  if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
                      mSearchPanelView.show(false, true);
                  }
@@ -723,22 +607,23 @@
     protected void workAroundBadLayerDrawableOpacity(View v) {
     }
 
-    protected  boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
+    public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
         int minHeight =
                 mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight =
                 mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
         StatusBarNotification sbn = entry.notification;
-        RemoteViews oneU = sbn.getNotification().contentView;
-        RemoteViews large = sbn.getNotification().bigContentView;
-        if (oneU == null) {
+        RemoteViews contentView = sbn.getNotification().contentView;
+        RemoteViews bigContentView = sbn.getNotification().bigContentView;
+        if (contentView == null) {
             return false;
         }
 
         // create the row view
         LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+        ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
+                R.layout.status_bar_notification_row, parent, false);
 
         // for blaming (see SwipeHelper.setLongPressListener)
         row.setTag(sbn.getPackageName());
@@ -765,41 +650,38 @@
             content.setOnClickListener(null);
         }
 
-        // TODO(cwren) normalize variable names with those in updateNotification
-        View expandedOneU = null;
-        View expandedLarge = null;
+        View contentViewLocal = null;
+        View bigContentViewLocal = null;
         try {
-            expandedOneU = oneU.apply(mContext, adaptive, mOnClickHandler);
-            if (large != null) {
-                expandedLarge = large.apply(mContext, adaptive, mOnClickHandler);
+            contentViewLocal = contentView.apply(mContext, adaptive, mOnClickHandler);
+            if (bigContentView != null) {
+                bigContentViewLocal = bigContentView.apply(mContext, adaptive, mOnClickHandler);
             }
         }
         catch (RuntimeException e) {
             final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
-            Slog.e(TAG, "couldn't inflate view for notification " + ident, e);
+            Log.e(TAG, "couldn't inflate view for notification " + ident, e);
             return false;
         }
 
-        if (expandedOneU != null) {
+        if (contentViewLocal != null) {
             SizeAdaptiveLayout.LayoutParams params =
-                    new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
+                    new SizeAdaptiveLayout.LayoutParams(contentViewLocal.getLayoutParams());
             params.minHeight = minHeight;
             params.maxHeight = minHeight;
-            adaptive.addView(expandedOneU, params);
+            adaptive.addView(contentViewLocal, params);
         }
-        if (expandedLarge != null) {
+        if (bigContentViewLocal != null) {
             SizeAdaptiveLayout.LayoutParams params =
-                    new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
+                    new SizeAdaptiveLayout.LayoutParams(bigContentViewLocal.getLayoutParams());
             params.minHeight = minHeight+1;
             params.maxHeight = maxHeight;
-            adaptive.addView(expandedLarge, params);
+            adaptive.addView(bigContentViewLocal, params);
         }
         row.setDrawingCacheEnabled(true);
 
         applyLegacyRowBackground(sbn, content);
 
-        row.setTag(R.id.expandable_tag, Boolean.valueOf(large != null));
-
         if (MULTIUSER_DEBUG) {
             TextView debug = (TextView) row.findViewById(R.id.debug_info);
             if (debug != null) {
@@ -808,9 +690,10 @@
             }
         }
         entry.row = row;
+        entry.row.setRowHeight(mRowHeight);
         entry.content = content;
-        entry.expanded = expandedOneU;
-        entry.setLargeView(expandedLarge);
+        entry.expanded = contentViewLocal;
+        entry.setBigContentView(bigContentViewLocal);
 
         return true;
     }
@@ -819,13 +702,13 @@
         return new NotificationClicker(intent, pkg, tag, id);
     }
 
-    private class NotificationClicker implements View.OnClickListener {
+    protected class NotificationClicker implements View.OnClickListener {
         private PendingIntent mIntent;
         private String mPkg;
         private String mTag;
         private int mId;
 
-        NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
+        public NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
             mIntent = intent;
             mPkg = pkg;
             mTag = tag;
@@ -855,7 +738,7 @@
                     mIntent.send(mContext, 0, overlay);
                 } catch (PendingIntent.CanceledException e) {
                     // the stack trace isn't very helpful here.  Just log the exception message.
-                    Slog.w(TAG, "Sending contentIntent failed: " + e);
+                    Log.w(TAG, "Sending contentIntent failed: " + e);
                 }
 
                 KeyguardManager kgm =
@@ -872,9 +755,6 @@
             // close the shade if it was open
             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
             visibilityChanged(false);
-
-            // If this click was on the intruder alert, hide that instead
-//            mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
         }
     }
     /**
@@ -913,7 +793,7 @@
     protected StatusBarNotification removeNotificationViews(IBinder key) {
         NotificationData.Entry entry = mNotificationData.remove(key);
         if (entry == null) {
-            Slog.w(TAG, "removeNotification for unknown key: " + key);
+            Log.w(TAG, "removeNotification for unknown key: " + key);
             return null;
         }
         // Remove the expanded view.
@@ -925,10 +805,10 @@
         return entry.notification;
     }
 
-    protected StatusBarIconView addNotificationViews(IBinder key,
+    protected NotificationData.Entry createNotificationViews(IBinder key,
             StatusBarNotification notification) {
         if (DEBUG) {
-            Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
+            Log.d(TAG, "createNotificationViews(key=" + key + ", notification=" + notification);
         }
         // Construct the icon.
         final StatusBarIconView iconView = new StatusBarIconView(mContext,
@@ -953,51 +833,41 @@
                     + notification);
             return null;
         }
+        return entry;
+    }
 
+    protected void addNotificationViews(NotificationData.Entry entry) {
         // Add the expanded view and icon.
         int pos = mNotificationData.add(entry);
         if (DEBUG) {
-            Slog.d(TAG, "addNotificationViews: added at " + pos);
+            Log.d(TAG, "addNotificationViews: added at " + pos);
         }
         updateExpansionStates();
         updateNotificationIcons();
-
-        return iconView;
     }
 
-    protected boolean expandView(NotificationData.Entry entry, boolean expand) {
-        int rowHeight =
-                mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
-        ViewGroup.LayoutParams lp = entry.row.getLayoutParams();
-        if (entry.expandable() && expand) {
-            if (DEBUG) Slog.d(TAG, "setting expanded row height to WRAP_CONTENT");
-            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-        } else {
-            if (DEBUG) Slog.d(TAG, "setting collapsed row height to " + rowHeight);
-            lp.height = rowHeight;
-        }
-        entry.row.setLayoutParams(lp);
-        return expand;
+    private void addNotificationViews(IBinder key, StatusBarNotification notification) {
+        addNotificationViews(createNotificationViews(key, notification));
     }
 
     protected void updateExpansionStates() {
         int N = mNotificationData.size();
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = mNotificationData.get(i);
-            if (!entry.userLocked()) {
+            if (!entry.row.isUserLocked()) {
                 if (i == (N-1)) {
-                    if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
-                    expandView(entry, true);
+                    if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
+                    entry.row.setExpanded(true);
                 } else {
-                    if (!entry.userExpanded()) {
-                        if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
-                        expandView(entry, false);
+                    if (!entry.row.isUserExpanded()) {
+                        if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
+                        entry.row.setExpanded(false);
                     } else {
-                        if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i);
+                        if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
                     }
                 }
             } else {
-                if (DEBUG) Slog.d(TAG, "ignoring notification being held by user at " + i);
+                if (DEBUG) Log.d(TAG, "ignoring notification being held by user at " + i);
             }
         }
     }
@@ -1015,11 +885,11 @@
     }
 
     public void updateNotification(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
+        if (DEBUG) Log.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
 
         final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
         if (oldEntry == null) {
-            Slog.w(TAG, "updateNotification for unknown key: " + key);
+            Log.w(TAG, "updateNotification for unknown key: " + key);
             return;
         }
 
@@ -1032,13 +902,13 @@
         final RemoteViews bigContentView = notification.getNotification().bigContentView;
 
         if (DEBUG) {
-            Slog.d(TAG, "old notification: when=" + oldNotification.getNotification().when
+            Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
                     + " ongoing=" + oldNotification.isOngoing()
                     + " expanded=" + oldEntry.expanded
                     + " contentView=" + oldContentView
                     + " bigContentView=" + oldBigContentView
                     + " rowParent=" + oldEntry.row.getParent());
-            Slog.d(TAG, "new notification: when=" + notification.getNotification().when
+            Log.d(TAG, "new notification: when=" + notification.getNotification().when
                     + " ongoing=" + oldNotification.isOngoing()
                     + " contentView=" + contentView
                     + " bigContentView=" + bigContentView);
@@ -1055,8 +925,8 @@
                 && oldContentView.getLayoutId() == contentView.getLayoutId();
         // large view may be null
         boolean bigContentsUnchanged =
-                (oldEntry.getLargeView() == null && bigContentView == null)
-                || ((oldEntry.getLargeView() != null && bigContentView != null)
+                (oldEntry.getBigContentView() == null && bigContentView == null)
+                || ((oldEntry.getBigContentView() != null && bigContentView != null)
                     && bigContentView.getPackage() != null
                     && oldBigContentView.getPackage() != null
                     && oldBigContentView.getPackage().equals(bigContentView.getPackage())
@@ -1071,23 +941,23 @@
                         oldEntry.notification.getNotification().tickerText);
         boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
         if (contentsUnchanged && bigContentsUnchanged && (orderUnchanged || isTopAnyway)) {
-            if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
+            if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
             oldEntry.notification = notification;
             try {
-                // Reapply the RemoteViews
-                contentView.reapply(mContext, oldEntry.expanded, mOnClickHandler);
-                if (bigContentView != null && oldEntry.getLargeView() != null) {
-                    bigContentView.reapply(mContext, oldEntry.getLargeView(), mOnClickHandler);
+                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;
+                        updateNotificationViews(mInterruptingNotificationEntry, notification);
+                    }
                 }
-                // update the contentIntent
-                final PendingIntent contentIntent = notification.getNotification().contentIntent;
-                if (contentIntent != null) {
-                    final View.OnClickListener listener = makeClicker(contentIntent,
-                            notification.getPackageName(), notification.getTag(), notification.getId());
-                    oldEntry.content.setOnClickListener(listener);
-                } else {
-                    oldEntry.content.setOnClickListener(null);
-                }
+
                 // Update the icon.
                 final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
                         notification.getUser(),
@@ -1102,22 +972,22 @@
             }
             catch (RuntimeException e) {
                 // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+                Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
                 removeNotificationViews(key);
                 addNotificationViews(key, notification);
             }
         } else {
-            if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
-            if (DEBUG) Slog.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
-            if (DEBUG) Slog.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
-            if (DEBUG) Slog.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
-            final boolean wasExpanded = oldEntry.userExpanded();
+            if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
+            if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
+            if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
+            if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
+            final boolean wasExpanded = oldEntry.row.isUserExpanded();
             removeNotificationViews(key);
-            addNotificationViews(key, notification);
+            addNotificationViews(key, notification);  // will also replace the heads up
             if (wasExpanded) {
                 final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
-                expandView(newEntry, true);
-                newEntry.setUserExpanded(true);
+                newEntry.row.setExpanded(true);
+                newEntry.row.setUserExpanded(true);
             }
         }
 
@@ -1127,7 +997,7 @@
 
         // Is this for you?
         boolean isForCurrentUser = notificationIsForCurrentUser(notification);
-        if (DEBUG) Slog.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
+        if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
 
         // Restart the ticker if it's still running
         if (updateTicker && isForCurrentUser) {
@@ -1138,17 +1008,57 @@
         // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
 
-        // See if we need to update the intruder.
-        if (ENABLE_INTRUDERS && oldNotification == mCurrentlyIntrudingNotification) {
-            if (DEBUG) Slog.d(TAG, "updating the current intruder:" + notification);
-            // XXX: this is a hack for Alarms. The real implementation will need to *update*
-            // the intruder.
-            if (notification.getNotification().fullScreenIntent == null) { // TODO(dsandler): consistent logic with add()
-                if (DEBUG) Slog.d(TAG, "no longer intrudes!");
-                mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
-            }
+    private void updateNotificationViews(NotificationData.Entry entry,
+            StatusBarNotification notification) {
+        final RemoteViews contentView = notification.getNotification().contentView;
+        final RemoteViews bigContentView = notification.getNotification().bigContentView;
+        // Reapply the RemoteViews
+        contentView.reapply(mContext, entry.expanded, mOnClickHandler);
+        if (bigContentView != null && entry.getBigContentView() != null) {
+            bigContentView.reapply(mContext, entry.getBigContentView(), mOnClickHandler);
         }
+        // update the contentIntent
+        final PendingIntent contentIntent = notification.getNotification().contentIntent;
+        if (contentIntent != null) {
+            final View.OnClickListener listener = makeClicker(contentIntent,
+                    notification.getPackageName(), notification.getTag(), notification.getId());
+            entry.content.setOnClickListener(listener);
+        } else {
+            entry.content.setOnClickListener(null);
+        }
+    }
+
+    protected void notifyHeadsUpScreenOn(boolean screenOn) {
+        if (!screenOn && mInterruptingNotificationEntry != null) {
+            mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+        }
+    }
+
+    protected boolean shouldInterrupt(StatusBarNotification sbn) {
+        Notification notification = sbn.getNotification();
+        // some predicates to make the boolean logic legible
+        boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
+                || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
+                || notification.sound != null
+                || notification.vibrate != null;
+        boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
+        boolean isFullscreen = notification.fullScreenIntent != null;
+        boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
+                Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
+
+        boolean interrupt = (isFullscreen || (isHighPriority && isNoisy))
+                && isAllowed
+                && mPowerManager.isScreenOn()
+                && !mKeyguardManager.isKeyguardLocked();
+        try {
+            interrupt = interrupt && !mDreamManager.isDreaming();
+        } catch (RemoteException e) {
+            Log.d(TAG, "failed to query dream manager", e);
+        }
+        if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
+        return interrupt;
     }
 
     // Q: What kinds of notifications should show during setup?
@@ -1172,4 +1082,15 @@
         KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         return km.inKeyguardRestrictedInputMode();
     }
+
+    public void setInteracting(int barWindow, boolean interacting) {
+        // hook for subclasses
+    }
+
+    public void destroy() {
+        if (mSearchPanelView != null) {
+            mWindowManager.removeViewImmediate(mSearchPanelView);
+        }
+        mContext.unregisterReceiver(mBroadcastReceiver);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index cbbaab3..e8173b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -19,8 +19,8 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-
 import android.service.notification.StatusBarNotification;
+
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
@@ -56,6 +56,7 @@
     private static final int MSG_PRELOAD_RECENT_APPS        = 14 << MSG_SHIFT;
     private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 15 << MSG_SHIFT;
     private static final int MSG_SET_NAVIGATION_ICON_HINTS  = 16 << MSG_SHIFT;
+    private static final int MSG_SET_WINDOW_STATE           = 17 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -98,6 +99,7 @@
         public void hideSearchPanel();
         public void cancelPreloadRecentApps();
         public void setNavigationIconHints(int hints);
+        public void setWindowState(int window, int state);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -232,6 +234,13 @@
         }
     }
 
+    public void setWindowState(int window, int state) {
+        synchronized (mList) {
+            // don't coalesce these
+            mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -312,6 +321,9 @@
                 case MSG_SET_NAVIGATION_ICON_HINTS:
                     mCallbacks.setNavigationIconHints(msg.arg1);
                     break;
+                case MSG_SET_WINDOW_STATE:
+                    mCallbacks.setWindowState(msg.arg1, msg.arg2);
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 3ac1bcf..3a82753 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import android.app.StatusBarManager;
 import android.graphics.RectF;
 import android.view.MotionEvent;
 import android.view.View;
@@ -34,6 +35,7 @@
     RectF mInitialTouch = new RectF();
     private boolean mStarted;
     private boolean mSwapXY = false;
+    private boolean mDisabled;
 
     public DelegateViewHelper(View sourceView) {
         setSourceView(sourceView);
@@ -48,8 +50,7 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mSourceView == null || mDelegateView == null
-                || mBar.shouldDisableNavbarGestures()) {
+        if (mSourceView == null || mDelegateView == null || mBar.shouldDisableNavbarGestures()) {
             return false;
         }
 
@@ -57,8 +58,8 @@
         final float sourceX = mTempPoint[0];
         final float sourceY = mTempPoint[1];
 
-
-        switch (event.getAction()) {
+        final int action = event.getAction();
+        switch (action) {
             case MotionEvent.ACTION_DOWN:
                 mPanelShowing = mDelegateView.getVisibility() == View.VISIBLE;
                 mDownPoint[0] = event.getX();
@@ -71,7 +72,7 @@
             return false;
         }
 
-        if (!mPanelShowing && event.getAction() == MotionEvent.ACTION_MOVE) {
+        if (!mDisabled && !mPanelShowing && action == MotionEvent.ACTION_MOVE) {
             final int historySize = event.getHistorySize();
             for (int k = 0; k < historySize + 1; k++) {
                 float x = k < historySize ? event.getHistoricalX(k) : event.getX();
@@ -85,6 +86,12 @@
             }
         }
 
+        if (action == MotionEvent.ACTION_DOWN) {
+            mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, true);
+        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, false);
+        }
+
         mDelegateView.getLocationOnScreen(mTempPoint);
         final float delegateX = mTempPoint[0];
         final float delegateY = mTempPoint[1];
@@ -135,4 +142,8 @@
     public void setSwapXY(boolean swap) {
         mSwapXY = swap;
     }
+
+    public void setDisabled(boolean disabled) {
+        mDisabled = disabled;
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java b/packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java
deleted file mode 100644
index 9e44e71..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.app.StatusBarManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Slog;
-
-import com.android.systemui.statusbar.policy.Prefs;
-
-public class DoNotDisturb implements SharedPreferences.OnSharedPreferenceChangeListener {
-    private Context mContext;
-    private StatusBarManager mStatusBar;
-    SharedPreferences mPrefs;
-    private boolean mDoNotDisturb;
-
-    public DoNotDisturb(Context context) {
-        mContext = context;
-        mStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
-        mPrefs = Prefs.read(context);
-        mPrefs.registerOnSharedPreferenceChangeListener(this);
-        mDoNotDisturb = mPrefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
-        updateDisableRecord();
-    }
-
-    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
-        final boolean val = prefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF,
-                Prefs.DO_NOT_DISTURB_DEFAULT);
-        if (val != mDoNotDisturb) {
-            mDoNotDisturb = val;
-            updateDisableRecord();
-        }
-    }
-
-    private void updateDisableRecord() {
-        final int disabled = StatusBarManager.DISABLE_NOTIFICATION_ICONS
-                | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
-                | StatusBarManager.DISABLE_NOTIFICATION_TICKER;
-        mStatusBar.disable(mDoNotDisturb ? disabled : 0);
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
new file mode 100644
index 0000000..cd6495f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -0,0 +1,79 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+public class ExpandableNotificationRow extends FrameLayout {
+    private int mRowHeight;
+
+    /** does this row contain layouts that can adapt to row expansion */
+    private boolean mExpandable;
+    /** has the user manually expanded this row */
+    private boolean mUserExpanded;
+    /** is the user touching this row */
+    private boolean mUserLocked;
+
+    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public int getRowHeight() {
+        return mRowHeight;
+    }
+
+    public void setRowHeight(int rowHeight) {
+        this.mRowHeight = rowHeight;
+    }
+
+    public boolean isExpandable() {
+        return mExpandable;
+    }
+
+    public void setExpandable(boolean expandable) {
+        mExpandable = expandable;
+    }
+
+    public boolean isUserExpanded() {
+        return mUserExpanded;
+    }
+
+    public void setUserExpanded(boolean userExpanded) {
+        mUserExpanded = userExpanded;
+    }
+
+    public boolean isUserLocked() {
+        return mUserLocked;
+    }
+
+    public void setUserLocked(boolean userLocked) {
+        mUserLocked = userLocked;
+    }
+
+    public void setExpanded(boolean expand) {
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        if (expand && mExpandable) {
+            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            lp.height = mRowHeight;
+        }
+        setLayoutParams(lp);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
index 0f894a1..f2adaf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
@@ -16,6 +16,12 @@
 
 package com.android.systemui.statusbar;
 
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.MotionEvent;
+
 import java.io.BufferedWriter;
 import java.io.FileDescriptor;
 import java.io.FileWriter;
@@ -24,12 +30,6 @@
 import java.util.HashSet;
 import java.util.LinkedList;
 
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.view.MotionEvent;
-
 /**
  * Convenience class for capturing gestures for later analysis.
  */
@@ -46,7 +46,7 @@
             public MotionEvent event;
             public MotionEventRecord(long when, MotionEvent event) {
                 this.time = when;
-                this.event = event.copy();
+                this.event = MotionEvent.obtain(event);
             }
             String actionName(int action) {
                 switch (action) {
@@ -101,7 +101,7 @@
                 mDownTime = ev.getDownTime();
             } else {
                 if (mDownTime != ev.getDownTime()) {
-                    Slog.w(TAG, "Assertion failure in GestureRecorder: event downTime ("
+                    Log.w(TAG, "Assertion failure in GestureRecorder: event downTime ("
                             +ev.getDownTime()+") does not match gesture downTime ("+mDownTime+")");
                 }
             }
@@ -237,10 +237,10 @@
                     mGestures.add(mCurrentGesture);
                 }
                 if (DEBUG) {
-                    Slog.v(TAG, String.format("Wrote %d complete gestures to %s", mLastSaveLen, mLogfile));
+                    Log.v(TAG, String.format("Wrote %d complete gestures to %s", mLastSaveLen, mLogfile));
                 }
             } catch (IOException e) {
-                Slog.e(TAG, String.format("Couldn't write gestures to %s", mLogfile), e);
+                Log.e(TAG, String.format("Couldn't write gestures to %s", mLogfile), e);
                 mLastSaveLen = -1;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 2c7a2a8..5264998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -16,15 +16,15 @@
 
 package com.android.systemui.statusbar;
 
-import android.service.notification.StatusBarNotification;
 import android.os.IBinder;
+import android.service.notification.StatusBarNotification;
 import android.view.View;
 import android.widget.ImageView;
 
 import com.android.systemui.R;
 
-import java.util.Comparator;
 import java.util.ArrayList;
+import java.util.Comparator;
 
 /**
  * The list of currently displaying notifications.
@@ -34,53 +34,34 @@
         public IBinder key;
         public StatusBarNotification notification;
         public StatusBarIconView icon;
-        public View row; // the outer expanded view
+        public ExpandableNotificationRow row; // the outer expanded view
         public View content; // takes the click events and sends the PendingIntent
         public View expanded; // the inflated RemoteViews
         public ImageView largeIcon;
-        protected View expandedLarge;
+        private View expandedBig;
+        private boolean interruption;
         public Entry() {}
         public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
             this.key = key;
             this.notification = n;
             this.icon = ic;
         }
-        public void setLargeView(View expandedLarge) {
-            this.expandedLarge = expandedLarge;
-            writeBooleanTag(row, R.id.expandable_tag, expandedLarge != null);
+        public void setBigContentView(View bigContentView) {
+            this.expandedBig = bigContentView;
+            row.setExpandable(bigContentView != null);
         }
-        public View getLargeView() {
-            return expandedLarge;
-        }
-        /**
-         * Return whether the entry can be expanded.
-         */
-        public boolean expandable() {
-            return NotificationData.getIsExpandable(row);
-        }
-        /**
-         * Return whether the entry has been manually expanded by the user.
-         */
-        public boolean userExpanded() {
-            return NotificationData.getUserExpanded(row);
-        }
-        /**
-         * Set the flag indicating that this was manually expanded by the user.
-         */
-        public boolean setUserExpanded(boolean userExpanded) {
-            return NotificationData.setUserExpanded(row, userExpanded);
-        }
-        /**
-         * Return whether the entry is being touched by the user.
-         */
-        public boolean userLocked() {
-            return NotificationData.getUserLocked(row);
+        public View getBigContentView() {
+            return expandedBig;
         }
         /**
          * Set the flag indicating that this is being touched by the user.
          */
-        public boolean setUserLocked(boolean userLocked) {
-            return NotificationData.setUserLocked(row, userLocked);
+        public void setUserLocked(boolean userLocked) {
+            row.setUserLocked(userLocked);
+        }
+
+        public void setInterruption() {
+            interruption = true;
         }
     }
     private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
@@ -90,9 +71,13 @@
             final StatusBarNotification na = a.notification;
             final StatusBarNotification nb = b.notification;
             int d = na.getScore() - nb.getScore();
-            return (d != 0)
-                ? d
-                : (int)(na.getNotification().when - nb.getNotification().when);
+	    if (a.interruption != b.interruption) {
+	      return a.interruption ? 1 : -1;
+	    } else if (d != 0) {
+                return d;
+            } else {
+                return (int) (na.getNotification().when - nb.getNotification().when);
+            }
         }
     };
 
@@ -125,8 +110,8 @@
         return i;
     }
 
-    public int add(IBinder key, StatusBarNotification notification, View row, View content,
-            View expanded, StatusBarIconView icon) {
+    public int add(IBinder key, StatusBarNotification notification, ExpandableNotificationRow row,
+            View content, View expanded, StatusBarIconView icon) {
         Entry entry = new Entry();
         entry.key = key;
         entry.notification = notification;
@@ -171,55 +156,4 @@
         }
         return false;
     }
-
-    protected static boolean readBooleanTag(View view, int id)  {
-        if (view != null) {
-            Object value = view.getTag(id);
-            return value != null && value instanceof Boolean && ((Boolean) value).booleanValue();
-        }
-        return false;
-    }
-
-    protected static boolean writeBooleanTag(View view, int id, boolean value)  {
-        if (view != null) {
-            view.setTag(id, Boolean.valueOf(value));
-            return value;
-        }
-        return false;
-    }
-
-    /**
-     * Return whether the entry can be expanded.
-     */
-    public static boolean getIsExpandable(View row) {
-        return readBooleanTag(row, R.id.expandable_tag);
-    }
-
-    /**
-     * Return whether the entry has been manually expanded by the user.
-     */
-    public static boolean getUserExpanded(View row) {
-        return readBooleanTag(row, R.id.user_expanded_tag);
-    }
-
-    /**
-     * Set whether the entry has been manually expanded by the user.
-     */
-    public static boolean setUserExpanded(View row, boolean userExpanded) {
-        return writeBooleanTag(row, R.id.user_expanded_tag, userExpanded);
-    }
-
-    /**
-     * Return whether the entry is being touched by the user.
-     */
-    public static boolean getUserLocked(View row) {
-        return readBooleanTag(row, R.id.user_lock_tag);
-    }
-
-    /**
-     * Set whether the entry is being touched by the user.
-     */
-    public static boolean setUserLocked(View row, boolean userLocked) {
-        return writeBooleanTag(row, R.id.user_lock_tag, userLocked);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java b/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java
deleted file mode 100644
index 735ee25..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.CompoundButton;
-
-import com.android.systemui.statusbar.policy.AutoRotateController;
-
-public class RotationToggle extends CompoundButton
-        implements AutoRotateController.RotationLockCallbacks {
-    private AutoRotateController mRotater;
-
-    public RotationToggle(Context context) {
-        super(context);
-    }
-
-    public RotationToggle(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public RotationToggle(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mRotater = new AutoRotateController(getContext(), this, this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mRotater != null) {
-            mRotater.release();
-            mRotater = null;
-        }
-    }
-
-    @Override
-    public void setRotationLockControlVisibility(boolean show) {
-        setVisibility(show ? VISIBLE : GONE);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
new file mode 100644
index 0000000..aea9ec6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
@@ -0,0 +1,282 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * Manages a persistent connection to a service component defined in a secure setting.
+ *
+ * <p>If a valid service component is specified in the secure setting, starts it up and keeps it
+ * running; handling setting changes, package updates, component disabling, and unexpected
+ * process termination.
+ *
+ * <p>Clients can listen for important events using the supplied {@link Callbacks}.
+ */
+public class ServiceMonitor {
+    private static final int RECHECK_DELAY = 2000;
+    private static final int WAIT_FOR_STOP = 500;
+
+    public interface Callbacks {
+        /** The service does not exist or failed to bind */
+        void onNoService();
+        /** The service is about to start, this is a chance to perform cleanup and
+         * delay the start if necessary */
+        long onServiceStartAttempt();
+    }
+
+    // internal handler + messages used to serialize access to internal state
+    public static final int MSG_START_SERVICE = 1;
+    public static final int MSG_CONTINUE_START_SERVICE = 2;
+    public static final int MSG_STOP_SERVICE = 3;
+    public static final int MSG_PACKAGE_INTENT = 4;
+    public static final int MSG_CHECK_BOUND = 5;
+    public static final int MSG_SERVICE_DISCONNECTED = 6;
+
+    private final Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_START_SERVICE:
+                    startService();
+                    break;
+                case MSG_CONTINUE_START_SERVICE:
+                    continueStartService();
+                    break;
+                case MSG_STOP_SERVICE:
+                    stopService();
+                    break;
+                case MSG_PACKAGE_INTENT:
+                    packageIntent((Intent)msg.obj);
+                    break;
+                case MSG_CHECK_BOUND:
+                    checkBound();
+                    break;
+                case MSG_SERVICE_DISCONNECTED:
+                    serviceDisconnected((ComponentName)msg.obj);
+                    break;
+            }
+        }
+    };
+
+    private final ContentObserver mSettingObserver = new ContentObserver(mHandler) {
+        public void onChange(boolean selfChange) {
+            onChange(selfChange, null);
+        }
+
+        public void onChange(boolean selfChange, Uri uri) {
+            if (mDebug) Log.d(mTag, "onChange selfChange=" + selfChange + " uri=" + uri);
+            ComponentName cn = getComponentNameFromSetting();
+            if (cn == null && mServiceName == null || cn != null && cn.equals(mServiceName)) {
+                if (mDebug) Log.d(mTag, "skipping no-op restart");
+                return;
+            }
+            if (mBound) {
+                mHandler.sendEmptyMessage(MSG_STOP_SERVICE);
+            }
+            mHandler.sendEmptyMessageDelayed(MSG_START_SERVICE, WAIT_FOR_STOP);
+        }
+    };
+
+    private final class SC implements ServiceConnection, IBinder.DeathRecipient {
+        private ComponentName mName;
+        private IBinder mService;
+
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (mDebug) Log.d(mTag, "onServiceConnected name=" + name + " service=" + service);
+            mName = name;
+            mService = service;
+            try {
+                service.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                Log.w(mTag, "Error linking to death", e);
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            if (mDebug) Log.d(mTag, "onServiceDisconnected name=" + name);
+            boolean unlinked = mService.unlinkToDeath(this, 0);
+            if (mDebug) Log.d(mTag, "  unlinked=" + unlinked);
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
+        }
+
+        public void binderDied() {
+            if (mDebug) Log.d(mTag, "binderDied");
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
+        }
+    }
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String pkg = intent.getData().getSchemeSpecificPart();
+            if (mServiceName != null && mServiceName.getPackageName().equals(pkg)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_PACKAGE_INTENT, intent));
+            }
+        }
+    };
+
+    private final String mTag;
+    private final boolean mDebug;
+
+    private final Context mContext;
+    private final String mSettingKey;
+    private final Callbacks mCallbacks;
+
+    private ComponentName mServiceName;
+    private SC mServiceConnection;
+    private boolean mBound;
+
+    public ServiceMonitor(String ownerTag, boolean debug,
+            Context context, String settingKey, Callbacks callbacks) {
+        mTag = ownerTag + ".ServiceMonitor";
+        mDebug = debug;
+        mContext = context;
+        mSettingKey = settingKey;
+        mCallbacks = callbacks;
+    }
+
+    public void start() {
+        // listen for setting changes
+        ContentResolver cr = mContext.getContentResolver();
+        cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
+                false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);
+
+        // listen for package/component changes
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+
+        mHandler.sendEmptyMessage(MSG_START_SERVICE);
+    }
+
+    private ComponentName getComponentNameFromSetting() {
+        String cn = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                mSettingKey, UserHandle.USER_CURRENT);
+        return cn == null ? null : ComponentName.unflattenFromString(cn);
+    }
+
+    // everything below is called on the handler
+
+    private void packageIntent(Intent intent) {
+        if (mDebug) Log.d(mTag, "packageIntent intent=" + intent
+                + " extras=" + bundleToString(intent.getExtras()));
+        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
+            mHandler.sendEmptyMessage(MSG_START_SERVICE);
+        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
+            PackageManager pm = mContext.getPackageManager();
+            boolean serviceEnabled =
+                    pm.getApplicationEnabledSetting(mServiceName.getPackageName())
+                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                    && pm.getComponentEnabledSetting(mServiceName)
+                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+            if (mBound && !serviceEnabled) {
+                stopService();
+                scheduleCheckBound();
+            } else if (!mBound && serviceEnabled) {
+                startService();
+            }
+        }
+    }
+
+    private void stopService() {
+        if (mDebug) Log.d(mTag, "stopService");
+        boolean stopped = mContext.stopService(new Intent().setComponent(mServiceName));
+        if (mDebug) Log.d(mTag, "  stopped=" + stopped);
+        mContext.unbindService(mServiceConnection);
+        mBound = false;
+    }
+
+    private void startService() {
+        mServiceName = getComponentNameFromSetting();
+        if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
+        if (mServiceName == null) {
+            mBound = false;
+            mCallbacks.onNoService();
+        } else {
+            long delay = mCallbacks.onServiceStartAttempt();
+            mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
+        }
+    }
+
+    private void continueStartService() {
+        if (mDebug) Log.d(mTag, "continueStartService");
+        Intent intent = new Intent().setComponent(mServiceName);
+        try {
+            mServiceConnection = new SC();
+            mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            if (mDebug) Log.d(mTag, "mBound: " + mBound);
+        } catch (Throwable t) {
+            Log.w(mTag, "Error binding to service: " + mServiceName, t);
+        }
+        if (!mBound) {
+            mCallbacks.onNoService();
+        }
+    }
+
+    private void serviceDisconnected(ComponentName serviceName) {
+        if (mDebug) Log.d(mTag, "serviceDisconnected serviceName=" + serviceName
+                + " mServiceName=" + mServiceName);
+        if (serviceName.equals(mServiceName)) {
+            mBound = false;
+            scheduleCheckBound();
+        }
+    }
+
+    private void checkBound() {
+        if (mDebug) Log.d(mTag, "checkBound mBound=" + mBound);
+        if (!mBound) {
+            startService();
+        }
+    }
+
+    private void scheduleCheckBound() {
+        mHandler.removeMessages(MSG_CHECK_BOUND);
+        mHandler.sendEmptyMessageDelayed(MSG_CHECK_BOUND, RECHECK_DELAY);
+    }
+
+    private static String bundleToString(Bundle bundle) {
+        if (bundle == null) return null;
+        StringBuilder sb = new StringBuilder('{');
+        for (String key : bundle.keySet()) {
+            if (sb.length() > 1) sb.append(',');
+            Object v = bundle.get(key);
+            v = (v instanceof String[]) ? Arrays.asList((String[]) v) : v;
+            sb.append(key).append('=').append(v);
+        }
+        return sb.append('}').toString();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 46916f7..f1c8e01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -18,16 +18,15 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.Slog;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
-import com.android.systemui.statusbar.policy.NetworkController;
-
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkController;
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
 public class SignalClusterView
@@ -40,15 +39,15 @@
     NetworkController mNC;
 
     private boolean mWifiVisible = false;
-    private int mWifiStrengthId = 0, mWifiActivityId = 0;
+    private int mWifiStrengthId = 0;
     private boolean mMobileVisible = false;
-    private int mMobileStrengthId = 0, mMobileActivityId = 0, mMobileTypeId = 0;
+    private int mMobileStrengthId = 0, mMobileTypeId = 0;
     private boolean mIsAirplaneMode = false;
     private int mAirplaneIconId = 0;
     private String mWifiDescription, mMobileDescription, mMobileTypeDescription;
 
     ViewGroup mWifiGroup, mMobileGroup;
-    ImageView mWifi, mMobile, mWifiActivity, mMobileActivity, mMobileType, mAirplane;
+    ImageView mWifi, mMobile, mMobileType, mAirplane;
     View mSpacer;
 
     public SignalClusterView(Context context) {
@@ -64,7 +63,7 @@
     }
 
     public void setNetworkController(NetworkController nc) {
-        if (DEBUG) Slog.d(TAG, "NetworkController=" + nc);
+        if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
         mNC = nc;
     }
 
@@ -74,10 +73,8 @@
 
         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
-        mWifiActivity   = (ImageView) findViewById(R.id.wifi_inout);
         mMobileGroup    = (ViewGroup) findViewById(R.id.mobile_combo);
         mMobile         = (ImageView) findViewById(R.id.mobile_signal);
-        mMobileActivity = (ImageView) findViewById(R.id.mobile_inout);
         mMobileType     = (ImageView) findViewById(R.id.mobile_type);
         mSpacer         =             findViewById(R.id.spacer);
         mAirplane       = (ImageView) findViewById(R.id.airplane);
@@ -89,10 +86,8 @@
     protected void onDetachedFromWindow() {
         mWifiGroup      = null;
         mWifi           = null;
-        mWifiActivity   = null;
         mMobileGroup    = null;
         mMobile         = null;
-        mMobileActivity = null;
         mMobileType     = null;
         mSpacer         = null;
         mAirplane       = null;
@@ -101,22 +96,19 @@
     }
 
     @Override
-    public void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
-            String contentDescription) {
+    public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) {
         mWifiVisible = visible;
         mWifiStrengthId = strengthIcon;
-        mWifiActivityId = activityIcon;
         mWifiDescription = contentDescription;
 
         apply();
     }
 
     @Override
-    public void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
+    public void setMobileDataIndicators(boolean visible, int strengthIcon,
             int typeIcon, String contentDescription, String typeContentDescription) {
         mMobileVisible = visible;
         mMobileStrengthId = strengthIcon;
-        mMobileActivityId = activityIcon;
         mMobileTypeId = typeIcon;
         mMobileDescription = contentDescription;
         mMobileTypeDescription = typeContentDescription;
@@ -136,9 +128,9 @@
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         // Standard group layout onPopulateAccessibilityEvent() implementations
         // ignore content description, so populate manually
-        if (mWifiVisible && mWifiGroup.getContentDescription() != null)
+        if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
             event.getText().add(mWifiGroup.getContentDescription());
-        if (mMobileVisible && mMobileGroup.getContentDescription() != null)
+        if (mMobileVisible && mMobileGroup != null && mMobileGroup.getContentDescription() != null)
             event.getText().add(mMobileGroup.getContentDescription());
         return super.dispatchPopulateAccessibilityEvent(event);
     }
@@ -150,16 +142,11 @@
         if (mWifi != null) {
             mWifi.setImageDrawable(null);
         }
-        if (mWifiActivity != null) {
-            mWifiActivity.setImageDrawable(null);
-        }
 
         if (mMobile != null) {
             mMobile.setImageDrawable(null);
         }
-        if (mMobileActivity != null) {
-            mMobileActivity.setImageDrawable(null);
-        }
+
         if (mMobileType != null) {
             mMobileType.setImageDrawable(null);
         }
@@ -177,7 +164,6 @@
 
         if (mWifiVisible) {
             mWifi.setImageResource(mWifiStrengthId);
-            mWifiActivity.setImageResource(mWifiActivityId);
 
             mWifiGroup.setContentDescription(mWifiDescription);
             mWifiGroup.setVisibility(View.VISIBLE);
@@ -185,14 +171,13 @@
             mWifiGroup.setVisibility(View.GONE);
         }
 
-        if (DEBUG) Slog.d(TAG,
-                String.format("wifi: %s sig=%d act=%d",
+        if (DEBUG) Log.d(TAG,
+                String.format("wifi: %s sig=%d",
                     (mWifiVisible ? "VISIBLE" : "GONE"),
-                    mWifiStrengthId, mWifiActivityId));
+                    mWifiStrengthId));
 
         if (mMobileVisible && !mIsAirplaneMode) {
             mMobile.setImageResource(mMobileStrengthId);
-            mMobileActivity.setImageResource(mMobileActivityId);
             mMobileType.setImageResource(mMobileTypeId);
 
             mMobileGroup.setContentDescription(mMobileTypeDescription + " " + mMobileDescription);
@@ -214,10 +199,10 @@
             mSpacer.setVisibility(View.GONE);
         }
 
-        if (DEBUG) Slog.d(TAG,
-                String.format("mobile: %s sig=%d act=%d typ=%d",
+        if (DEBUG) Log.d(TAG,
+                String.format("mobile: %s sig=%d typ=%d",
                     (mMobileVisible ? "VISIBLE" : "GONE"),
-                    mMobileStrengthId, mMobileActivityId, mMobileTypeId));
+                    mMobileStrengthId, mMobileTypeId));
 
         mMobileType.setVisibility(
                 !mWifiVisible ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 39d56a4..9f9524b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -20,25 +20,23 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.Slog;
 import android.util.Log;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 
-import java.text.NumberFormat;
-
 import com.android.internal.statusbar.StatusBarIcon;
-
 import com.android.systemui.R;
 
+import java.text.NumberFormat;
+
 public class StatusBarIconView extends AnimatedImageView {
     private static final String TAG = "StatusBarIconView";
 
@@ -70,8 +68,6 @@
             final float scale = (float)imageBounds / (float)outerBounds;
             setScaleX(scale);
             setScaleY(scale);
-            final float alpha = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
-            setAlpha(alpha);
         }
 
         setScaleType(ImageView.ScaleType.CENTER);
@@ -85,8 +81,6 @@
         final float scale = (float)imageBounds / (float)outerBounds;
         setScaleX(scale);
         setScaleY(scale);
-        final float alpha = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
-        setAlpha(alpha);
     }
 
     private static boolean streq(String a, String b) {
@@ -151,7 +145,7 @@
     private boolean updateDrawable(boolean withClear) {
         Drawable drawable = getIcon(mIcon);
         if (drawable == null) {
-            Slog.w(TAG, "No icon for slot " + mSlot);
+            Log.w(TAG, "No icon for slot " + mSlot);
             return false;
         }
         if (withClear) {
@@ -168,7 +162,7 @@
     /**
      * Returns the right icon to use for this item, respecting the iconId and
      * iconPackage (if set)
-     * 
+     *
      * @param context Context to use to get resources if iconPackage is not set
      * @return Drawable for this item, or null if the package or item could not
      *         be found
@@ -185,7 +179,7 @@
                 r = context.getPackageManager()
                         .getResourcesForApplicationAsUser(icon.iconPackage, userId);
             } catch (PackageManager.NameNotFoundException ex) {
-                Slog.e(TAG, "Icon package not found: " + icon.iconPackage);
+                Log.e(TAG, "Icon package not found: " + icon.iconPackage);
                 return null;
             }
         } else {
@@ -195,11 +189,11 @@
         if (icon.iconId == 0) {
             return null;
         }
-        
+
         try {
             return r.getDrawable(icon.iconId);
         } catch (RuntimeException e) {
-            Slog.w(TAG, "Icon not found in "
+            Log.w(TAG, "Icon not found in "
                   + (icon.iconPackage != null ? icon.iconId : "<system>")
                   + ": " + Integer.toHexString(icon.iconId));
         }
@@ -287,7 +281,7 @@
     }
 
     public String toString() {
-        return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon 
+        return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon
             + " notification=" + mNotification + ")";
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPanel.java
new file mode 100644
index 0000000..272c321
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPanel.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+public interface StatusBarPanel {
+    public boolean isInContentArea(int x, int y);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
new file mode 100644
index 0000000..16fe1aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
@@ -0,0 +1,114 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.res.Configuration;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Ensure a single status bar service implementation is running at all times.
+ *
+ * <p>The implementation either comes from a service component running in a remote process (defined
+ * using a secure setting), else falls back to using the in-process implementation according
+ * to the product config.
+ */
+public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
+    private static final String TAG = "SystemBars";
+    private static final boolean DEBUG = true;
+    private static final int WAIT_FOR_BARS_TO_DIE = 500;
+
+    // manages the implementation coming from the remote process
+    private ServiceMonitor mServiceMonitor;
+
+    // in-process fallback implementation, per the product config
+    private BaseStatusBar mStatusBar;
+
+    @Override
+    public void start() {
+        if (DEBUG) Log.d(TAG, "start");
+        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
+                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
+        mServiceMonitor.start();  // will call onNoService if no remote service is found
+    }
+
+    @Override
+    public void onNoService() {
+        if (DEBUG) Log.d(TAG, "onNoService");
+        createStatusBarFromConfig();  // fallback to using an in-process implementation
+    }
+
+    @Override
+    public long onServiceStartAttempt() {
+        if (DEBUG) Log.d(TAG, "onServiceStartAttempt mStatusBar="+mStatusBar);
+        if (mStatusBar != null) {
+            // tear down the in-process version, we'll recreate it again if needed
+            mStatusBar.destroy();
+            mStatusBar = null;
+            return WAIT_FOR_BARS_TO_DIE;
+        }
+        return 0;
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        if (mStatusBar != null) {
+            mStatusBar.onConfigurationChanged(newConfig);
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mStatusBar != null) {
+            mStatusBar.dump(fd, pw, args);
+        }
+    }
+
+    private void createStatusBarFromConfig() {
+        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
+        final String clsName = mContext.getString(R.string.config_statusBarComponent);
+        if (clsName == null || clsName.length() == 0) {
+            throw andLog("No status bar component configured", null);
+        }
+        Class<?> cls = null;
+        try {
+            cls = mContext.getClassLoader().loadClass(clsName);
+        } catch (Throwable t) {
+            throw andLog("Error loading status bar component: " + clsName, t);
+        }
+        try {
+            mStatusBar = (BaseStatusBar) cls.newInstance();
+        } catch (Throwable t) {
+            throw andLog("Error creating status bar component: " + clsName, t);
+        }
+        mStatusBar.mContext = mContext;
+        mStatusBar.mComponents = mComponents;
+        mStatusBar.start();
+        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
+    }
+
+    private RuntimeException andLog(String msg, Throwable t) {
+        Log.w(TAG, msg, t);
+        throw new RuntimeException(msg, t);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
new file mode 100644
index 0000000..0c25c83
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -0,0 +1,183 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.ActivityManager;
+import android.content.res.Resources;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.GradientDrawable.Orientation;
+import android.graphics.drawable.TransitionDrawable;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+public class BarTransitions {
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_COLORS = false;
+
+    public static final int MODE_OPAQUE = 0;
+    public static final int MODE_SEMI_TRANSPARENT = 1;
+    public static final int MODE_TRANSPARENT = 2;
+    public static final int MODE_LIGHTS_OUT = 3;
+
+    public static final int LIGHTS_IN_DURATION = 250;
+    public static final int LIGHTS_OUT_DURATION = 750;
+    public static final int BACKGROUND_DURATION = 200;
+
+    private final String mTag;
+    private final View mView;
+    private final boolean mSupportsTransitions = ActivityManager.isHighEndGfx();
+
+    private final int mOpaque;
+    private final int mSemiTransparent;
+    private final int mGradientStart;
+    private final int mGradientEnd;
+
+    private int mMode;
+    private ValueAnimator mColorDrawableAnimator;
+    private boolean mColorDrawableShowing;
+
+    private final ColorDrawable mColorDrawable;
+    private final GradientDrawable mGradientDrawable;
+    private final TransitionDrawable mTransitionDrawable;
+    private final AnimatorUpdateListener mAnimatorListener = new AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animator) {
+            mColorDrawable.setColor((Integer) animator.getAnimatedValue());
+        }
+    };
+
+    public BarTransitions(View view) {
+        mTag = "BarTransitions." + view.getClass().getSimpleName();
+        mView = view;
+        final Resources res = mView.getContext().getResources();
+
+        if (DEBUG_COLORS) {
+            mOpaque = 0xff0000ff;
+            mSemiTransparent = 0x7f0000ff;
+            mGradientStart = 0x7fff0000;
+            mGradientEnd = 0x7f00ff00;
+        } else {
+            mOpaque = res.getColor(R.drawable.system_bar_background);
+            mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
+            mGradientStart = res.getColor(R.color.system_bar_background_gradient_start);
+            mGradientEnd = res.getColor(R.color.system_bar_background_gradient_end);
+        }
+
+        mColorDrawable = new ColorDrawable(mOpaque);
+        mGradientDrawable = new GradientDrawable(Orientation.BOTTOM_TOP,
+                new int[] { mGradientStart, mGradientEnd });
+        mTransitionDrawable = new TransitionDrawable(
+                new Drawable[] { mGradientDrawable, mColorDrawable });
+        mTransitionDrawable.setCrossFadeEnabled(true);
+        mTransitionDrawable.resetTransition();
+        if (mSupportsTransitions) {
+            mView.setBackground(mTransitionDrawable);
+        }
+    }
+
+    protected void setOrientation(GradientDrawable.Orientation orientation) {
+        if (orientation.equals(mGradientDrawable.getOrientation())) return; // GD doesn't check
+        if (DEBUG) Log.d(mTag, "setOrientation " + orientation);
+        mGradientDrawable.mutate();
+        mGradientDrawable.setOrientation(orientation);
+    }
+
+    public int getMode() {
+        return mMode;
+    }
+
+    public void transitionTo(int mode, boolean animate) {
+        if (mMode == mode) return;
+        int oldMode = mMode;
+        mMode = mode;
+        if (DEBUG) Log.d(mTag, String.format("%s -> %s animate=%s",
+                modeToString(oldMode), modeToString(mode),  animate));
+        if (mSupportsTransitions) {
+            onTransition(oldMode, mMode, animate);
+        }
+    }
+
+    private Integer getBackgroundColor(int mode) {
+        if (mode == MODE_SEMI_TRANSPARENT) return mSemiTransparent;
+        if (mode == MODE_OPAQUE) return mOpaque;
+        if (mode == MODE_LIGHTS_OUT) return mOpaque;
+        return null;
+    }
+
+    protected void onTransition(int oldMode, int newMode, boolean animate) {
+        applyModeBackground(oldMode, newMode, animate);
+    }
+
+    protected void applyModeBackground(int oldMode, int newMode, boolean animate) {
+        if (DEBUG) Log.d(mTag, String.format("applyModeBackground %s animate=%s",
+                modeToString(newMode), animate));
+        cancelColorAnimation();
+        Integer oldColor = getBackgroundColor(oldMode);
+        Integer newColor = getBackgroundColor(newMode);
+        if (newColor != null) {
+            if (animate && oldColor != null && !oldColor.equals(newColor)) {
+                startColorAnimation(oldColor, newColor);
+            } else if (!newColor.equals(mColorDrawable.getColor())) {
+                if (DEBUG) Log.d(mTag, String.format("setColor = %08x", newColor));
+                mColorDrawable.setColor(newColor);
+            }
+        }
+        if (oldColor != null && newColor == null && mColorDrawableShowing) {
+            if (DEBUG) Log.d(mTag, "Hide color layer");
+            if (animate) {
+                mTransitionDrawable.reverseTransition(BACKGROUND_DURATION);
+            } else {
+                mTransitionDrawable.resetTransition();
+            }
+            mColorDrawableShowing = false;
+        } else if (oldColor == null && newColor != null && !mColorDrawableShowing) {
+            if (DEBUG) Log.d(mTag, "Show color layer");
+            mTransitionDrawable.setCrossFadeEnabled(!animate);
+            mTransitionDrawable.startTransition(animate ? BACKGROUND_DURATION : 0);
+            mColorDrawableShowing = true;
+        }
+    }
+
+    private void startColorAnimation(int from, int to) {
+        if (DEBUG) Log.d(mTag, String.format("startColorAnimation %08x -> %08x", from, to));
+        mColorDrawableAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), from, to);
+        mColorDrawableAnimator.addUpdateListener(mAnimatorListener);
+        mColorDrawableAnimator.start();
+    }
+
+    private void cancelColorAnimation() {
+        if (mColorDrawableAnimator != null && mColorDrawableAnimator.isStarted()) {
+            mColorDrawableAnimator.cancel();
+            mColorDrawableAnimator = null;
+        }
+    }
+
+    public static String modeToString(int mode) {
+        if (mode == MODE_OPAQUE) return "MODE_OPAQUE";
+        if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
+        if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
+        if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
+        throw new IllegalArgumentException("Unknown mode " + mode);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CarrierLabel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CarrierLabel.java
deleted file mode 100644
index 66494e4..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CarrierLabel.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.internal.telephony.TelephonyIntents;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-import com.android.internal.R;
-
-/**
- * This widget display an analogic clock with two hands for hours and
- * minutes.
- */
-public class CarrierLabel extends TextView {
-    private boolean mAttached;
-
-    public CarrierLabel(Context context) {
-        this(context, null);
-    }
-
-    public CarrierLabel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CarrierLabel(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        updateNetworkName(false, null, false, null);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        if (!mAttached) {
-            mAttached = true;
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
-            getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mAttached) {
-            getContext().unregisterReceiver(mIntentReceiver);
-            mAttached = false;
-        }
-    }
-
-    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
-                updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
-                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
-            }
-        }
-    };
-
-    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-        if (false) {
-            Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
-        }
-        final String str;
-        // match logic in KeyguardStatusViewManager
-        final boolean plmnValid = showPlmn && !TextUtils.isEmpty(plmn);
-        final boolean spnValid = showSpn && !TextUtils.isEmpty(spn);
-        if (plmnValid && spnValid) {
-            str = plmn + "|" + spn;
-        } else if (plmnValid) {
-            str = plmn;
-        } else if (spnValid) {
-            str = spn;
-        } else {
-            str = "";
-        }
-        setText(str);
-    }
-
-
-}
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CloseDragHandle.java
deleted file mode 100644
index ee01489..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CloseDragHandle.java
+++ /dev/null
@@ -1,53 +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 com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-
-
-public class CloseDragHandle extends LinearLayout {
-    PhoneStatusBar mService;
-
-    public CloseDragHandle(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    /**
-     * Ensure that, if there is no target under us to receive the touch,
-     * that we process it ourself.  This makes sure that onInterceptTouchEvent()
-     * is always called for the entire gesture.
-     */
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            setPressed(true);
-        } else {
-            mService.interceptTouchEvent(event);
-        }
-        return true;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        return mService.interceptTouchEvent(event)
-                ? true : super.onInterceptTouchEvent(event);
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
new file mode 100644
index 0000000..aba7afa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -0,0 +1,151 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.DemoMode;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.policy.LocationController;
+
+public class DemoStatusIcons extends LinearLayout implements DemoMode {
+    private final LinearLayout mStatusIcons;
+    private final int mIconSize;
+
+    private boolean mDemoMode;
+
+    public DemoStatusIcons(LinearLayout statusIcons, int iconSize) {
+        super(statusIcons.getContext());
+        mStatusIcons = statusIcons;
+        mIconSize = iconSize;
+
+        setLayoutParams(mStatusIcons.getLayoutParams());
+        setOrientation(mStatusIcons.getOrientation());
+        setGravity(Gravity.CENTER_VERTICAL); // no LL.getGravity()
+        ViewGroup p = (ViewGroup) mStatusIcons.getParent();
+        p.addView(this, p.indexOfChild(mStatusIcons));
+    }
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+            mStatusIcons.setVisibility(View.GONE);
+            setVisibility(View.VISIBLE);
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            mStatusIcons.setVisibility(View.VISIBLE);
+            setVisibility(View.GONE);
+        } else if (mDemoMode && command.equals(COMMAND_STATUS)) {
+            String volume = args.getString("volume");
+            if (volume != null) {
+                int iconId = volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
+                        : volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate
+                        : 0;
+                updateSlot("volume", null, iconId);
+            }
+            String bt = args.getString("bluetooth");
+            if (bt != null) {
+                int iconId = bt.equals("disconnected") ? R.drawable.stat_sys_data_bluetooth
+                        : bt.equals("connected") ? R.drawable.stat_sys_data_bluetooth_connected
+                        : 0;
+                updateSlot("bluetooth", null, iconId);
+            }
+            String location = args.getString("location");
+            if (location != null) {
+                int iconId = location.equals("show") ? LocationController.LOCATION_STATUS_ICON_ID
+                        : 0;
+                updateSlot(LocationController.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
+            }
+            String alarm = args.getString("alarm");
+            if (alarm != null) {
+                int iconId = alarm.equals("show") ? R.drawable.stat_sys_alarm
+                        : 0;
+                updateSlot("alarm_clock", null, iconId);
+            }
+            String sync = args.getString("sync");
+            if (sync != null) {
+                int iconId = sync.equals("show") ? R.drawable.stat_sys_sync
+                        : 0;
+                updateSlot("sync_active", null, iconId);
+            }
+            String tty = args.getString("tty");
+            if (tty != null) {
+                int iconId = tty.equals("show") ? R.drawable.stat_sys_tty_mode
+                        : 0;
+                updateSlot("tty", null, iconId);
+            }
+            String eri = args.getString("eri");
+            if (eri != null) {
+                int iconId = eri.equals("show") ? R.drawable.stat_sys_roaming_cdma_0
+                        : 0;
+                updateSlot("cdma_eri", null, iconId);
+            }
+            String mute = args.getString("mute");
+            if (mute != null) {
+                int iconId = mute.equals("show") ? android.R.drawable.stat_notify_call_mute
+                        : 0;
+                updateSlot("mute", null, iconId);
+            }
+            String speakerphone = args.getString("speakerphone");
+            if (speakerphone != null) {
+                int iconId = speakerphone.equals("show") ? android.R.drawable.stat_sys_speakerphone
+                        : 0;
+                updateSlot("speakerphone", null, iconId);
+            }
+        }
+    }
+
+    private void updateSlot(String slot, String iconPkg, int iconId) {
+        if (!mDemoMode) return;
+        int removeIndex = -1;
+        for (int i = 0; i < getChildCount(); i++) {
+            StatusBarIconView v = (StatusBarIconView) getChildAt(i);
+            if (slot.equals(v.getTag())) {
+                if (iconId == 0) {
+                    removeIndex = i;
+                    break;
+                } else {
+                    StatusBarIcon icon = v.getStatusBarIcon();
+                    icon.iconPackage = iconPkg;
+                    icon.iconId = iconId;
+                    v.set(icon);
+                    v.updateDrawable();
+                    return;
+                }
+            }
+        }
+        if (iconId == 0) {
+            if (removeIndex != -1) {
+                removeViewAt(removeIndex);
+                return;
+            }
+        }
+        StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.CURRENT, iconId, 0, 0, "Demo");
+        StatusBarIconView v = new StatusBarIconView(mContext, null);
+        v.setTag(slot);
+        v.set(icon);
+        addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index 0640282..50ead3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -17,16 +17,11 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
-import android.os.Handler;
 import android.util.AttributeSet;
-import android.util.Slog;
 import android.view.View;
 import android.widget.LinearLayout;
 
-import com.android.internal.statusbar.StatusBarIcon;
-
 import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarIconView;
 
 public class IconMerger extends LinearLayout {
     private static final String TAG = "IconMerger";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
new file mode 100644
index 0000000..5c55f0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
@@ -0,0 +1,172 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+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.os.UserHandle;
+import android.util.Slog;
+import android.view.MotionEvent;
+
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardService;
+
+
+/**
+ * Facilitates event communication between navigation bar and keyguard.  Currently used to
+ * control WidgetPager in keyguard to expose the camera widget.
+ *
+ */
+public class KeyguardTouchDelegate {
+    // TODO: propagate changes to these to {@link KeyguardServiceDelegate}
+    static final String KEYGUARD_PACKAGE = "com.android.keyguard";
+    static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+
+    private static KeyguardTouchDelegate sInstance;
+
+    private volatile IKeyguardService mService;
+
+    protected static final boolean DEBUG = false;
+    protected static final String TAG = "KeyguardTouchDelegate";
+
+    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Slog.v(TAG, "Connected to keyguard");
+            mService = IKeyguardService.Stub.asInterface(service);
+
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Slog.v(TAG, "Disconnected from keyguard");
+            mService = null;
+            sInstance = null; // force reconnection if this goes away
+        }
+
+    };
+
+    private KeyguardTouchDelegate(Context context) {
+        Intent intent = new Intent();
+        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
+                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+            if (DEBUG) Slog.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+        } else {
+            if (DEBUG) Slog.v(TAG, "*** Keyguard started");
+        }
+    }
+
+    public static KeyguardTouchDelegate getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new KeyguardTouchDelegate(context);
+        }
+        return sInstance;
+    }
+
+    public boolean isSecure() {
+        final IKeyguardService service = mService;
+        if (service != null) {
+            try {
+                return service.isSecure();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException calling keyguard.isSecure()!", e);
+            }
+        } else {
+            Slog.w(TAG, "isSecure(): NO SERVICE!");
+        }
+        return false;
+    }
+
+    public boolean dispatch(MotionEvent event) {
+        final IKeyguardService service = mService;
+        if (service != null) {
+            try {
+                service.dispatch(event);
+                return true;
+            } catch (RemoteException e) {
+                // What to do?
+                Slog.e(TAG, "RemoteException sending event to keyguard!", e);
+            }
+        } else {
+            Slog.w(TAG, "dispatch(event): NO SERVICE!");
+        }
+        return false;
+    }
+
+    public boolean isInputRestricted() {
+        final IKeyguardService service = mService;
+        if (service != null) {
+            try {
+                return service.isInputRestricted();
+            } catch (RemoteException e) {
+                Slog.w(TAG , "Remote Exception", e);
+            }
+        } else {
+            Slog.w(TAG, "isInputRestricted(): NO SERVICE!");
+        }
+        return false;
+    }
+
+    public boolean isShowingAndNotHidden() {
+        final IKeyguardService service = mService;
+        if (service != null) {
+            try {
+                return service.isShowingAndNotHidden();
+            } catch (RemoteException e) {
+                Slog.w(TAG , "Remote Exception", e);
+            }
+        } else {
+            Slog.w(TAG, "isShowingAndNotHidden(): NO SERVICE!");
+        }
+        return false;
+    }
+
+    public void showAssistant() {
+        final IKeyguardService service = mService;
+        if (service != null) {
+            try {
+                service.showAssistant();
+            } catch (RemoteException e) {
+                // What to do?
+                Slog.e(TAG, "RemoteException launching assistant!", e);
+            }
+        } else {
+            Slog.w(TAG, "showAssistant(event): NO SERVICE!");
+        }
+    }
+
+    public void launchCamera() {
+        final IKeyguardService service = mService;
+        if (service != null) {
+            try {
+                service.launchCamera();
+            } catch (RemoteException e) {
+                // What to do?
+                Slog.e(TAG, "RemoteException launching camera!", e);
+            }
+        } else {
+            Slog.w(TAG, "dispatch(event): NO SERVICE!");
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
new file mode 100644
index 0000000..04922fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -0,0 +1,144 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.graphics.drawable.GradientDrawable.Orientation;
+import android.os.ServiceManager;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+public final class NavigationBarTransitions extends BarTransitions {
+
+    private final NavigationBarView mView;
+    private final IStatusBarService mBarService;
+
+    private boolean mLightsOut;
+
+    public NavigationBarTransitions(NavigationBarView view) {
+        super(view);
+        mView = view;
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+    }
+
+    public void init(boolean isVertical) {
+        setVertical(isVertical);
+        applyModeBackground(-1, getMode(), false /*animate*/);
+        applyMode(getMode(), false /*animate*/, true /*force*/);
+    }
+
+    public void setVertical(boolean isVertical) {
+        setOrientation(isVertical ? Orientation.RIGHT_LEFT : Orientation.BOTTOM_TOP);
+    }
+
+    @Override
+    protected void onTransition(int oldMode, int newMode, boolean animate) {
+        super.onTransition(oldMode, newMode, animate);
+        applyMode(newMode, animate, false /*force*/);
+    }
+
+    private void applyMode(int mode, boolean animate, boolean force) {
+        // apply to key buttons
+        final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT;
+        final float alpha = isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
+        setKeyButtonViewQuiescentAlpha(mView.getBackButton(), alpha, animate);
+        setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
+        setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
+        setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
+        setKeyButtonViewQuiescentAlpha(mView.getCameraButton(), alpha, animate);
+
+        // apply to lights out
+        applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force);
+    }
+
+    private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) {
+        if (button instanceof KeyButtonView) {
+            ((KeyButtonView) button).setQuiescentAlpha(alpha, animate);
+        }
+    }
+
+    private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
+        if (!force && lightsOut == mLightsOut) return;
+
+        mLightsOut = lightsOut;
+
+        final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
+        final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
+
+        // ok, everyone, stop it right there
+        navButtons.animate().cancel();
+        lowLights.animate().cancel();
+
+        final float navButtonsAlpha = lightsOut ? 0f : 1f;
+        final float lowLightsAlpha = lightsOut ? 1f : 0f;
+
+        if (!animate) {
+            navButtons.setAlpha(navButtonsAlpha);
+            lowLights.setAlpha(lowLightsAlpha);
+            lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
+        } else {
+            final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
+            navButtons.animate()
+                .alpha(navButtonsAlpha)
+                .setDuration(duration)
+                .start();
+
+            lowLights.setOnTouchListener(mLightsOutListener);
+            if (lowLights.getVisibility() == View.GONE) {
+                lowLights.setAlpha(0f);
+                lowLights.setVisibility(View.VISIBLE);
+            }
+            lowLights.animate()
+                .alpha(lowLightsAlpha)
+                .setDuration(duration)
+                .setInterpolator(new AccelerateInterpolator(2.0f))
+                .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator _a) {
+                        lowLights.setVisibility(View.GONE);
+                    }
+                })
+                .start();
+        }
+    }
+
+    private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
+        @Override
+        public boolean onTouch(View v, MotionEvent ev) {
+            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+                // even though setting the systemUI visibility below will turn these views
+                // on, we need them to come up faster so that they can catch this motion
+                // event
+                applyLightsOut(false, false, false);
+
+                try {
+                    mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+                } catch (android.os.RemoteException ex) {
+                }
+            }
+            return false;
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 54c4666..04885f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,51 +16,52 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.LayoutTransition;
+import android.app.ActivityManagerNative;
 import android.app.StatusBarManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Message;
-import android.os.ServiceManager;
+import android.os.RemoteException;
 import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.animation.AccelerateInterpolator;
+import android.util.Log;
 import android.view.Display;
 import android.view.MotionEvent;
-import android.view.View;
 import android.view.Surface;
+import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.DelegateViewHelper;
 import com.android.systemui.statusbar.policy.DeadZone;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public class NavigationBarView extends LinearLayout {
+    private static final int CAMERA_BUTTON_FADE_DURATION = 200;
     final static boolean DEBUG = false;
     final static String TAG = "PhoneStatusBar/NavigationBarView";
 
     final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
 
     // slippery nav bar when everything is disabled, e.g. during setup
-    final static boolean SLIPPERY_WHEN_DISABLED= true;
+    final static boolean SLIPPERY_WHEN_DISABLED = true;
 
-    final static boolean ANIMATE_HIDE_TRANSITION = false; // turned off because it introduces unsightly delay when videos goes to full screen
-
-    protected IStatusBarService mBarService;
     final Display mDisplay;
     View mCurrentView = null;
     View[] mRotatedViews = new View[4];
@@ -69,7 +70,7 @@
     boolean mVertical;
     boolean mScreenOn;
 
-    boolean mHidden, mLowProfile, mShowMenu;
+    boolean mShowMenu;
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
 
@@ -79,11 +80,41 @@
 
     private DelegateViewHelper mDelegateHelper;
     private DeadZone mDeadZone;
+    private final NavigationBarTransitions mBarTransitions;
 
     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
     final static int MSG_CHECK_INVALID_LAYOUT = 8686;
 
+    // used to disable the camera icon in navbar when disabled by DPM
+    private boolean mCameraDisabledByDpm;
+
+    private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
+        @Override
+        public boolean onTouch(View cameraButtonView, MotionEvent event) {
+            View searchLight = getSearchLight();
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    // disable search gesture while interacting with camera
+                    mDelegateHelper.setDisabled(true);
+                    cameraButtonView.animate().alpha(0.0f).setDuration(CAMERA_BUTTON_FADE_DURATION);
+                    if (searchLight != null) {
+                        searchLight.animate().alpha(0.0f).setDuration(CAMERA_BUTTON_FADE_DURATION);
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mDelegateHelper.setDisabled(false);
+                    cameraButtonView.animate().alpha(1.0f).setDuration(CAMERA_BUTTON_FADE_DURATION);
+                    if (searchLight != null) {
+                        searchLight.animate().alpha(1.0f).setDuration(CAMERA_BUTTON_FADE_DURATION);
+                    }
+                    break;
+            }
+            return KeyguardTouchDelegate.getInstance(getContext()).dispatch(event);
+        }
+    };
+
     private class H extends Handler {
         public void handleMessage(Message m) {
             switch (m.what) {
@@ -95,7 +126,7 @@
                     final int vh = mCurrentView.getHeight();
 
                     if (h != vh || w != vw) {
-                        Slog.w(TAG, String.format(
+                        Log.w(TAG, String.format(
                             "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
                             how, w, h, vw, vh));
                         if (WORKAROUND_INVALID_LAYOUT) {
@@ -107,6 +138,45 @@
         }
     }
 
+    public NavigationBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mDisplay = ((WindowManager)context.getSystemService(
+                Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+        final Resources res = mContext.getResources();
+        mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
+        mVertical = false;
+        mShowMenu = false;
+        mDelegateHelper = new DelegateViewHelper(this);
+
+        getIcons(res);
+
+        mBarTransitions = new NavigationBarTransitions(this);
+
+        mCameraDisabledByDpm = isCameraDisabledByDpm();
+        watchForDevicePolicyChanges();
+    }
+
+    private void watchForDevicePolicyChanges() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCameraDisabledByDpm = isCameraDisabledByDpm();
+                    }
+                });
+            }
+        }, filter);
+    }
+
+    public BarTransitions getBarTransitions() {
+        return mBarTransitions;
+    }
+
     public void setDelegateView(View view) {
         mDelegateHelper.setDelegateView(view);
     }
@@ -134,6 +204,10 @@
 
     private H mHandler = new H();
 
+    public View getCurrentView() {
+        return mCurrentView;
+    }
+
     public View getRecentsButton() {
         return mCurrentView.findViewById(R.id.recent_apps);
     }
@@ -155,23 +229,9 @@
         return mCurrentView.findViewById(R.id.search_light);
     }
 
-    public NavigationBarView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mHidden = false;
-
-        mDisplay = ((WindowManager)context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-
-        final Resources res = mContext.getResources();
-        mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
-        mVertical = false;
-        mShowMenu = false;
-        mDelegateHelper = new DelegateViewHelper(this);
-
-        getIcons(res);
+    // shown when keyguard is visible and camera is available
+    public View getCameraButton() {
+        return mCurrentView.findViewById(R.id.camera_button);
     }
 
     private void getIcons(Resources res) {
@@ -195,24 +255,6 @@
         setDisabledFlags(mDisabledFlags, true);
     }
 
-    View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
-        @Override
-        public boolean onTouch(View v, MotionEvent ev) {
-            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-                // even though setting the systemUI visibility below will turn these views
-                // on, we need them to come up faster so that they can catch this motion
-                // event
-                setLowProfile(false, false, false);
-
-                try {
-                    mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
-                } catch (android.os.RemoteException ex) {
-                }
-            }
-            return false;
-        }
-    };
-
     public void setNavigationIconHints(int hints) {
         setNavigationIconHints(hints, false);
     }
@@ -278,7 +320,31 @@
         getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
 
-        getSearchLight().setVisibility((disableHome && !disableSearch) ? View.VISIBLE : View.GONE);
+        final boolean shouldShowSearch = disableHome && !disableSearch;
+        getSearchLight().setVisibility(shouldShowSearch ? View.VISIBLE : View.GONE);
+        final View cameraButton = getCameraButton();
+        if (cameraButton != null) {
+            cameraButton.setVisibility(
+                    shouldShowSearch && !mCameraDisabledByDpm ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    private boolean isCameraDisabledByDpm() {
+        final DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        if (dpm != null) {
+            try {
+                final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+                final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
+                final  boolean disabledBecauseKeyguardSecure =
+                        (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
+                        && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
+                return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Can't get userId", e);
+            }
+        }
+        return false;
     }
 
     public void setSlippery(boolean newSlippery) {
@@ -309,77 +375,62 @@
         getMenuButton().setVisibility(mShowMenu ? View.VISIBLE : View.INVISIBLE);
     }
 
-    public void setLowProfile(final boolean lightsOut) {
-        setLowProfile(lightsOut, true, false);
-    }
-
-    public void setLowProfile(final boolean lightsOut, final boolean animate, final boolean force) {
-        if (!force && lightsOut == mLowProfile) return;
-
-        mLowProfile = lightsOut;
-
-        if (DEBUG) Slog.d(TAG, "setting lights " + (lightsOut?"out":"on"));
-
-        final View navButtons = mCurrentView.findViewById(R.id.nav_buttons);
-        final View lowLights = mCurrentView.findViewById(R.id.lights_out);
-
-        // ok, everyone, stop it right there
-        navButtons.animate().cancel();
-        lowLights.animate().cancel();
-
-        if (!animate) {
-            navButtons.setAlpha(lightsOut ? 0f : 1f);
-
-            lowLights.setAlpha(lightsOut ? 1f : 0f);
-            lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
-        } else {
-            navButtons.animate()
-                .alpha(lightsOut ? 0f : 1f)
-                .setDuration(lightsOut ? 750 : 250)
-                .start();
-
-            lowLights.setOnTouchListener(mLightsOutListener);
-            if (lowLights.getVisibility() == View.GONE) {
-                lowLights.setAlpha(0f);
-                lowLights.setVisibility(View.VISIBLE);
-            }
-            lowLights.animate()
-                .alpha(lightsOut ? 1f : 0f)
-                .setDuration(lightsOut ? 750 : 250)
-                .setInterpolator(new AccelerateInterpolator(2.0f))
-                .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator _a) {
-                        lowLights.setVisibility(View.GONE);
-                    }
-                })
-                .start();
-        }
-    }
-
-    public void setHidden(final boolean hide) {
-        if (hide == mHidden) return;
-
-        mHidden = hide;
-        Slog.d(TAG,
-            (hide ? "HIDING" : "SHOWING") + " navigation bar");
-
-        // bring up the lights no matter what
-        setLowProfile(false);
-    }
-
     @Override
     public void onFinishInflate() {
-        mRotatedViews[Surface.ROTATION_0] = 
+        mRotatedViews[Surface.ROTATION_0] =
         mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
 
         mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
-        
+
         mRotatedViews[Surface.ROTATION_270] = NAVBAR_ALWAYS_AT_RIGHT
                                                 ? findViewById(R.id.rot90)
                                                 : findViewById(R.id.rot270);
 
         mCurrentView = mRotatedViews[Surface.ROTATION_0];
+
+
+        final AccessibilityManager accessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (accessibilityManager.isEnabled()) {
+            // In accessibility mode, we add a simple click handler since swipe is tough to
+            // trigger near screen edges.
+            View camera = getCameraButton();
+            View searchLight = getSearchLight();
+            if (camera != null || searchLight != null) {
+                OnClickListener listener = new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        launchForAccessibilityClick(v);
+                    }
+                };
+                if (camera != null) {
+                    camera.setOnClickListener(listener);
+                }
+                if (searchLight != null) {
+                    searchLight.setOnClickListener(listener);
+                }
+            }
+        } else {
+            // Add a touch handler for camera icon for all view orientations.
+            for (int i = 0; i < mRotatedViews.length; i++) {
+                View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
+                if (cameraButton != null) {
+                    cameraButton.setOnTouchListener(mCameraTouchListener);
+                }
+            }
+        }
+    }
+
+    protected void launchForAccessibilityClick(View v) {
+        if (v == getCameraButton()) {
+            KeyguardTouchDelegate.getInstance(getContext()).launchCamera();
+        } else if (v == getSearchLight()) {
+            KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
+        }
+    }
+
+    public boolean isVertical() {
+        return mVertical;
     }
 
     public void reorient() {
@@ -393,12 +444,12 @@
         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
 
         // force the low profile & disabled states into compliance
-        setLowProfile(mLowProfile, false, true /* force */);
+        mBarTransitions.init(mVertical);
         setDisabledFlags(mDisabledFlags, true /* force */);
         setMenuVisibility(mShowMenu, true /* force */);
 
         if (DEBUG) {
-            Slog.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
+            Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
         }
 
         setNavigationIconHints(mNavigationIconHints, true);
@@ -412,13 +463,13 @@
 
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        if (DEBUG) Slog.d(TAG, String.format(
+        if (DEBUG) Log.d(TAG, String.format(
                     "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
 
         final boolean newVertical = w > 0 && h > w;
         if (newVertical != mVertical) {
             mVertical = newVertical;
-            //Slog.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
+            //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
             reorient();
         }
 
@@ -429,8 +480,8 @@
     /*
     @Override
     protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
-        if (DEBUG) Slog.d(TAG, String.format(
-                    "onLayout: %s (%d,%d,%d,%d)", 
+        if (DEBUG) Log.d(TAG, String.format(
+                    "onLayout: %s (%d,%d,%d,%d)",
                     changed?"changed":"notchanged", left, top, right, bottom));
         super.onLayout(changed, left, top, right, bottom);
     }
@@ -439,14 +490,14 @@
     // fails, any touch on the display will fix the layout.
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DEBUG) Slog.d(TAG, "onInterceptTouchEvent: " + ev.toString());
+        if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             postCheckForInvalidLayout("touch");
         }
         return super.onInterceptTouchEvent(ev);
     }
     */
-        
+
 
     private String getResourceName(int resId) {
         if (resId != 0) {
@@ -487,7 +538,7 @@
 
         getWindowVisibleDisplayFrame(r);
         final boolean offscreen = r.right > size.x || r.bottom > size.y;
-        pw.println("      window: " 
+        pw.println("      window: "
                 + r.toShortString()
                 + " " + visibilityToString(getWindowVisibility())
                 + (offscreen ? " OFFSCREEN!" : ""));
@@ -497,11 +548,9 @@
                         mCurrentView.getWidth(), mCurrentView.getHeight(),
                         visibilityToString(mCurrentView.getVisibility())));
 
-        pw.println(String.format("      disabled=0x%08x vertical=%s hidden=%s low=%s menu=%s",
+        pw.println(String.format("      disabled=0x%08x vertical=%s menu=%s",
                         mDisabledFlags,
                         mVertical ? "true" : "false",
-                        mHidden ? "true" : "false",
-                        mLowProfile ? "true" : "false",
                         mShowMenu ? "true" : "false"));
 
         final View back = getBackButton();
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 f33dc20..6be6d4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -22,7 +22,6 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.EventLog;
-import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 565a3f2..a3e35d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -16,21 +16,21 @@
 
 package com.android.systemui.statusbar.phone;
 
-import java.util.ArrayList;
-
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.Slog;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 
+import java.util.ArrayList;
+
 public class PanelBar extends FrameLayout {
     public static final boolean DEBUG = false;
     public static final String TAG = PanelBar.class.getSimpleName();
     public static final void LOG(String fmt, Object... args) {
         if (!DEBUG) return;
-        Slog.v(TAG, String.format(fmt, args));
+        Log.v(TAG, String.format(fmt, args));
     }
 
     public static final int STATE_CLOSED = 0;
@@ -66,7 +66,7 @@
 
     public void setPanelHolder(PanelHolder ph) {
         if (ph == null) {
-            Slog.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
+            Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
             return;
         }
         ph.setBar(this);
@@ -98,7 +98,7 @@
         // Allow subclasses to implement enable/disable semantics
         if (!panelsEnabled()) {
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                Slog.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
+                Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
                         (int) event.getX(), (int) event.getY()));
             }
             return false;
@@ -109,7 +109,7 @@
             final PanelView panel = selectPanelForTouch(event);
             if (panel == null) {
                 // panel is not there, so we'll eat the gesture
-                Slog.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
+                Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
                         (int) event.getX(), (int) event.getY()));
                 mTouchingPanel = null;
                 return true;
@@ -119,7 +119,7 @@
                     (enabled ? "" : " (disabled)"));
             if (!enabled) {
                 // panel is disabled, so we'll eat the gesture
-                Slog.v(TAG, String.format(
+                Log.v(TAG, String.format(
                         "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
                         panel, (int) event.getX(), (int) event.getY()));
                 mTouchingPanel = null;
@@ -194,11 +194,12 @@
             } else {
                 pv.setExpandedFraction(0); // just in case
                 pv.setVisibility(View.GONE);
+                pv.cancelPeek();
             }
         }
         if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
         if (!waiting && mState != STATE_CLOSED) {
-            // it's possible that nothing animated, so we replicate the termination 
+            // it's possible that nothing animated, so we replicate the termination
             // conditions of panelExpansionChanged here
             go(STATE_CLOSED);
             onAllPanelsCollapsed();
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 e351429..4b2c3e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -16,33 +16,32 @@
 
 package com.android.systemui.statusbar.phone;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayDeque;
-import java.util.Iterator;
-
 import android.animation.ObjectAnimator;
 import android.animation.TimeAnimator;
 import android.animation.TimeAnimator.TimeListener;
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.AttributeSet;
-import android.util.Slog;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.Iterator;
+
 public class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
     public static final String TAG = PanelView.class.getSimpleName();
 
     public static final boolean DEBUG_NAN = true; // http://b/7686690
 
-    public final void LOG(String fmt, Object... args) {
-        if (!DEBUG) return;
-        Slog.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
+    private final void logf(String fmt, Object... args) {
+        Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
     }
 
     public static final boolean BRAKES = false;
@@ -77,6 +76,7 @@
     private boolean mClosing;
     private boolean mRubberbanding;
     private boolean mTracking;
+    private int mTrackingPointer;
 
     private TimeAnimator mTimeAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -112,14 +112,14 @@
         }
         public void computeCurrentVelocity(long timebase) {
             if (FlingTracker.DEBUG) {
-                Slog.v("FlingTracker", "computing velocities for " + mEventBuf.size() + " events");
+                Log.v("FlingTracker", "computing velocities for " + mEventBuf.size() + " events");
             }
             mVX = mVY = 0;
             MotionEventCopy last = null;
             int i = 0;
             float totalweight = 0f;
             float weight = 10f;
-            for (final Iterator<MotionEventCopy> iter = mEventBuf.descendingIterator();
+            for (final Iterator<MotionEventCopy> iter = mEventBuf.iterator();
                     iter.hasNext();) {
                 final MotionEventCopy event = iter.next();
                 if (last != null) {
@@ -127,13 +127,22 @@
                     final float dx = (event.x - last.x);
                     final float dy = (event.y - last.y);
                     if (FlingTracker.DEBUG) {
-                        Slog.v("FlingTracker", String.format("   [%d] dx=%.1f dy=%.1f dt=%.0f vx=%.1f vy=%.1f",
-                                i,
+                        Log.v("FlingTracker", String.format(
+                                "   [%d] (t=%d %.1f,%.1f) dx=%.1f dy=%.1f dt=%f vx=%.1f vy=%.1f",
+                                i, event.t, event.x, event.y,
                                 dx, dy, dt,
                                 (dx/dt),
                                 (dy/dt)
                                 ));
                     }
+                    if (event.t == last.t) {
+                        // Really not sure what to do with events that happened at the same time,
+                        // so we'll skip subsequent events.
+                        if (DEBUG_NAN) {
+                            Log.v("FlingTracker", "skipping simultaneous event at t=" + event.t);
+                        }
+                        continue;
+                    }
                     mVX += weight * dx / dt;
                     mVY += weight * dy / dt;
                     totalweight += weight;
@@ -147,7 +156,7 @@
                 mVY /= totalweight;
             } else {
                 if (DEBUG_NAN) {
-                    Slog.v("FlingTracker", "computeCurrentVelocity warning: totalweight=0",
+                    Log.v("FlingTracker", "computeCurrentVelocity warning: totalweight=0",
                             new Throwable());
                 }
                 // so as not to contaminate the velocities with NaN
@@ -155,22 +164,22 @@
             }
 
             if (FlingTracker.DEBUG) {
-                Slog.v("FlingTracker", "computed: vx=" + mVX + " vy=" + mVY);
+                Log.v("FlingTracker", "computed: vx=" + mVX + " vy=" + mVY);
             }
         }
         public float getXVelocity() {
-            if (Float.isNaN(mVX)) {
+            if (Float.isNaN(mVX) || Float.isInfinite(mVX)) {
                 if (DEBUG_NAN) {
-                    Slog.v("FlingTracker", "warning: vx=NaN");
+                    Log.v("FlingTracker", "warning: vx=" + mVX);
                 }
                 mVX = 0;
             }
             return mVX;
         }
         public float getYVelocity() {
-            if (Float.isNaN(mVY)) {
+            if (Float.isNaN(mVY) || Float.isInfinite(mVX)) {
                 if (DEBUG_NAN) {
-                    Slog.v("FlingTracker", "warning: vx=NaN");
+                    Log.v("FlingTracker", "warning: vx=" + mVY);
                 }
                 mVY = 0;
             }
@@ -221,12 +230,12 @@
     }
 
     private void runPeekAnimation() {
-        if (DEBUG) LOG("peek to height=%.1f", mPeekHeight);
+        if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
         if (mTimeAnimator.isStarted()) {
             return;
         }
         if (mPeekAnimator == null) {
-            mPeekAnimator = ObjectAnimator.ofFloat(this, 
+            mPeekAnimator = ObjectAnimator.ofFloat(this,
                     "expandedHeight", mPeekHeight)
                 .setDuration(250);
         }
@@ -256,8 +265,8 @@
             }
         } else if (dtms > 0) {
             final float dt = dtms * 0.001f;                  // ms -> s
-            if (DEBUG) LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
-            if (DEBUG) LOG("tick: before: h=%d", (int) mExpandedHeight);
+            if (DEBUG) logf("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
+            if (DEBUG) logf("tick: before: h=%d", (int) mExpandedHeight);
 
             final float fh = getFullHeight();
             boolean braking = false;
@@ -295,7 +304,7 @@
                 h = fh;
             }
 
-            if (DEBUG) LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
+            if (DEBUG) logf("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
 
             setExpandedHeightInternal(h);
 
@@ -307,7 +316,7 @@
                 post(mStopAnimator);
             }
         } else {
-            Slog.v(TAG, "animationTick called with dtms=" + dtms + "; nothing to do (h="
+            Log.v(TAG, "animationTick called with dtms=" + dtms + "; nothing to do (h="
                     + mExpandedHeight + " v=" + mVel + ")");
         }
     }
@@ -339,7 +348,7 @@
 
         mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
 
-        mPeekHeight = res.getDimension(R.dimen.peek_height) 
+        mPeekHeight = res.getDimension(R.dimen.peek_height)
             + getPaddingBottom() // our window might have a dropshadow
             - (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
     }
@@ -367,19 +376,26 @@
 
         loadDimens();
 
-        if (DEBUG) LOG("handle view: " + mHandleView);
+        if (DEBUG) logf("handle view: " + mHandleView);
         if (mHandleView != null) {
             mHandleView.setOnTouchListener(new View.OnTouchListener() {
                 @Override
                 public boolean onTouch(View v, MotionEvent event) {
-                    final float y = event.getY();
-                    final float rawY = event.getRawY();
-                    if (DEBUG) LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
+                    int pointerIndex = event.findPointerIndex(mTrackingPointer);
+                    if (pointerIndex < 0) {
+                        pointerIndex = 0;
+                        mTrackingPointer = event.getPointerId(pointerIndex);
+                    }
+                    final float y = event.getY(pointerIndex);
+                    final float rawDelta = event.getRawY() - event.getY();
+                    final float rawY = y + rawDelta;
+                    if (DEBUG) logf("handle.onTouch: a=%s p=[%d,%d] y=%.1f rawY=%.1f off=%.1f",
                             MotionEvent.actionToString(event.getAction()),
+                            mTrackingPointer, pointerIndex,
                             y, rawY, mTouchOffset);
                     PanelView.this.getLocationOnScreen(mAbsPos);
 
-                    switch (event.getAction()) {
+                    switch (event.getActionMasked()) {
                         case MotionEvent.ACTION_DOWN:
                             mTracking = true;
                             mHandleView.setPressed(true);
@@ -389,13 +405,26 @@
                             trackMovement(event);
                             mTimeAnimator.cancel(); // end any outstanding animations
                             mBar.onTrackingStarted(PanelView.this);
-                            mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
+                            mTouchOffset = (rawY - mAbsPos[1]) - mExpandedHeight;
                             if (mExpandedHeight == 0) {
                                 mJustPeeked = true;
                                 runPeekAnimation();
                             }
                             break;
 
+                        case MotionEvent.ACTION_POINTER_UP:
+                            final int upPointer = event.getPointerId(event.getActionIndex());
+                            if (mTrackingPointer == upPointer) {
+                                // gesture is ongoing, find a new pointer to track
+                                final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                                final float newY = event.getY(newIndex);
+                                final float newRawY = newY + rawDelta;
+                                mTrackingPointer = event.getPointerId(newIndex);
+                                mTouchOffset = (newRawY - mAbsPos[1]) - mExpandedHeight;
+                                mInitialTouchY = newY;
+                            }
+                            break;
+
                         case MotionEvent.ACTION_MOVE:
                             final float h = rawY - mAbsPos[1] - mTouchOffset;
                             if (h > mPeekHeight) {
@@ -416,6 +445,7 @@
                         case MotionEvent.ACTION_CANCEL:
                             mFinalTouchY = y;
                             mTracking = false;
+                            mTrackingPointer = -1;
                             mHandleView.setPressed(false);
                             postInvalidate(); // catch the press state change
                             mBar.onTrackingStopped(PanelView.this);
@@ -461,7 +491,7 @@
                                 vel = -vel;
                             }
 
-                            if (DEBUG) LOG("gesture: dy=%f vel=(%f,%f) vlinear=%f",
+                            if (DEBUG) logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
                                     deltaY,
                                     xVel, yVel,
                                     vel);
@@ -476,7 +506,7 @@
     }
 
     public void fling(float vel, boolean always) {
-        if (DEBUG) LOG("fling: vel=%.3f, this=%s", vel, this);
+        if (DEBUG) logf("fling: vel=%.3f, this=%s", vel, this);
         mVel = vel;
 
         if (always||mVel != 0) {
@@ -496,7 +526,7 @@
 
     @Override
     protected void onViewAdded(View child) {
-        if (DEBUG) LOG("onViewAdded: " + child);
+        if (DEBUG) logf("onViewAdded: " + child);
     }
 
     public View getHandle() {
@@ -508,7 +538,7 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        if (DEBUG) LOG("onMeasure(%d, %d) -> (%d, %d)",
+        if (DEBUG) logf("onMeasure(%d, %d) -> (%d, %d)",
                 widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
 
         // Did one of our children change size?
@@ -528,7 +558,7 @@
 
 
     public void setExpandedHeight(float height) {
-        if (DEBUG) LOG("setExpandedHeight(%.1f)", height);
+        if (DEBUG) logf("setExpandedHeight(%.1f)", height);
         mRubberbanding = false;
         if (mTimeAnimator.isStarted()) {
             post(mStopAnimator);
@@ -539,7 +569,7 @@
 
     @Override
     protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
-        if (DEBUG) LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
+        if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
         super.onLayout(changed, left, top, right, bottom);
     }
 
@@ -547,7 +577,7 @@
         if (Float.isNaN(h)) {
             // If a NaN gets in here, it will freeze the Animators.
             if (DEBUG_NAN) {
-                Slog.v(TAG, "setExpandedHeightInternal: warning: h=NaN, using 0 instead",
+                Log.v(TAG, "setExpandedHeightInternal: warning: h=NaN, using 0 instead",
                         new Throwable());
             }
             h = 0;
@@ -563,7 +593,7 @@
 
         mExpandedHeight = h;
 
-        if (DEBUG) LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
+        if (DEBUG) logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
 
         requestLayout();
 //        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -575,7 +605,7 @@
 
     private float getFullHeight() {
         if (mFullHeight <= 0) {
-            if (DEBUG) LOG("Forcing measure() since fullHeight=" + mFullHeight);
+            if (DEBUG) logf("Forcing measure() since fullHeight=" + mFullHeight);
             measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
                     MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
         }
@@ -586,7 +616,7 @@
         if (Float.isNaN(frac)) {
             // If a NaN gets in here, it will freeze the Animators.
             if (DEBUG_NAN) {
-                Slog.v(TAG, "setExpandedFraction: frac=NaN, using 0 instead",
+                Log.v(TAG, "setExpandedFraction: frac=NaN, using 0 instead",
                         new Throwable());
             }
             frac = 0;
@@ -614,13 +644,17 @@
         return mClosing;
     }
 
+    public boolean isTracking() {
+        return mTracking;
+    }
+
     public void setBar(PanelBar panelBar) {
         mBar = panelBar;
     }
 
     public void collapse() {
         // TODO: abort animation or ongoing touch
-        if (DEBUG) LOG("collapse: " + this);
+        if (DEBUG) logf("collapse: " + this);
         if (!isFullyCollapsed()) {
             mTimeAnimator.cancel();
             mClosing = true;
@@ -631,12 +665,18 @@
     }
 
     public void expand() {
-        if (DEBUG) LOG("expand: " + this);
+        if (DEBUG) logf("expand: " + this);
         if (isFullyCollapsed()) {
             mBar.startOpeningPanel(this);
             fling(mSelfExpandVelocityPx, /*always=*/ true);
         } else if (DEBUG) {
-            if (DEBUG) LOG("skipping expansion: is expanded");
+            if (DEBUG) logf("skipping expansion: is expanded");
+        }
+    }
+
+    public void cancelPeek() {
+        if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
+            mPeekAnimator.cancel();
         }
     }
 
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 7d23e89..c47d0eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -16,9 +16,17 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.windowStateToString;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
@@ -26,12 +34,11 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
-import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.SharedPreferences;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Canvas;
@@ -42,20 +49,18 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
+import android.service.notification.StatusBarNotification;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
-import android.util.Slog;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -77,6 +82,7 @@
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.DemoMode;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -89,27 +95,25 @@
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.DateView;
-import com.android.systemui.statusbar.policy.IntruderAlertView;
+import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NotificationRowLayout;
 import com.android.systemui.statusbar.policy.OnSizeChangedListener;
-import com.android.systemui.statusbar.policy.Prefs;
+import com.android.systemui.statusbar.policy.RotationLockController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-public class PhoneStatusBar extends BaseStatusBar {
+public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
     static final String TAG = "PhoneStatusBar";
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
-    public static final boolean SPEW = DEBUG;
+    public static final boolean SPEW = false;
     public static final boolean DUMPTRUCK = true; // extra dumpsys info
     public static final boolean DEBUG_GESTURES = false;
 
-    public static final boolean DEBUG_CLINGS = false;
-
-    public static final boolean ENABLE_NOTIFICATION_PANEL_CLING = false;
+    public static final boolean DEBUG_WINDOW_STATE = true;
 
     public static final boolean SETTINGS_DRAG_SHORTCUT = true;
 
@@ -124,14 +128,15 @@
     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
     // 1020-1030 reserved for BaseStatusBar
 
-    // will likely move to a resource or other tunable param at some point
-    private static final int INTRUDER_ALERT_DECAY_MS = 0; // disabled, was 10000;
-
     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
     private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
     private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
 
+    private static final int STATUS_OR_NAV_TRANSIENT =
+            View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
+    private static final long AUTOHIDE_TIMEOUT_MS = 3000;
+
     // fling gesture tuning parameters, scaled to display density
     private float mSelfExpandVelocityPx; // classic value: 2000px/s
     private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
@@ -144,7 +149,7 @@
     private float mExpandAccelPx; // classic value: 2000px/s/s
     private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
 
-    private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little 
+    private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little
                                                     // faster than mSelfCollapseVelocityPx)
 
     PhoneStatusBarPolicy mIconPolicy;
@@ -154,28 +159,30 @@
     BatteryController mBatteryController;
     LocationController mLocationController;
     NetworkController mNetworkController;
+    RotationLockController mRotationLockController;
 
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
     int mIconHPadding = -1;
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
-
-    IDreamManager mDreamManager;
+    private float mHeadsUpVerticalOffset;
+    private int[] mPilePosition = new int[2];
 
     StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
+    private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
 
     int mPixelFormat;
     Object mQueueLock = new Object();
 
     // viewgroup containing the normal contents of the statusbar
     LinearLayout mStatusBarContents;
-    
+
     // right-hand icons
     LinearLayout mSystemIconArea;
-    
-    // left-hand icons 
+
+    // left-hand icons
     LinearLayout mStatusIcons;
     // the icons themselves
     IconMerger mNotificationIcons;
@@ -202,7 +209,7 @@
 
     // top bar
     View mNotificationPanelHeader;
-    View mDateTimeView; 
+    View mDateTimeView;
     View mClearButton;
     ImageView mSettingsButton, mNotificationButton;
 
@@ -222,11 +229,13 @@
     // the date view
     DateView mDateView;
 
-    // for immersive activities
-    private IntruderAlertView mIntruderAlertView;
+    // for heads up notifications
+    private HeadsUpNotificationView mHeadsUpNotificationView;
+    private int mHeadsUpNotificationDecay;
 
     // on-screen navigation buttons
     private NavigationBarView mNavigationBarView = null;
+    private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
 
     // the tracker view
     int mTrackingPosition; // the position of the top of the tracking view.
@@ -241,17 +250,9 @@
     boolean mTracking;
     VelocityTracker mVelocityTracker;
 
-    // help screen
-    private boolean mClingShown;
-    private ViewGroup mCling;
-    private boolean mSuppressStatusBarDrags; // while a cling is up, briefly deaden the bar to give things time to settle
-
     int[] mAbsPos = new int[2];
     Runnable mPostCollapseCleanup = null;
 
-    private Animator mLightsOutAnimation;
-    private Animator mLightsOnAnimation;
-
     // for disabling the status bar
     int mDisabled = 0;
 
@@ -262,7 +263,7 @@
 
     // XXX: gesture research
     private final GestureRecorder mGestureRec = DEBUG_GESTURES
-        ? new GestureRecorder("/sdcard/statusbar_gestures.dat") 
+        ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
         : null;
 
     private int mNavigationIconHints = 0;
@@ -271,7 +272,7 @@
         public void onAnimationEnd(Animator animation) {
             // double-check to avoid races
             if (mStatusBarContents.getAlpha() == 0) {
-                if (DEBUG) Slog.d(TAG, "makeIconsInvisible");
+                if (DEBUG) Log.d(TAG, "makeIconsInvisible");
                 mStatusBarContents.setVisibility(View.INVISIBLE);
             }
         }
@@ -287,7 +288,7 @@
                     Settings.Secure.USER_SETUP_COMPLETE,
                     0 /*default */,
                     mCurrentUserId);
-            if (MULTIUSER_DEBUG) Slog.d(TAG, String.format("User setup changed: " +
+            if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
                     "selfChange=%s userSetup=%s mUserSetup=%s",
                     selfChange, userSetup, mUserSetup));
             if (mSettingsButton != null && mHasFlipSettings) {
@@ -304,22 +305,59 @@
         }
     };
 
+    final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange) {
+            boolean wasUsing = mUseHeadsUp;
+            mUseHeadsUp = ENABLE_HEADS_UP && 0 != Settings.Global.getInt(
+                    mContext.getContentResolver(), SETTING_HEADS_UP, 0);
+            Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+            if (wasUsing != mUseHeadsUp) {
+                if (!mUseHeadsUp) {
+                    Log.d(TAG, "dismissing any existing heads up notification on disable event");
+                    mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+                    removeHeadsUpView();
+                } else {
+                    addHeadsUpView();
+                }
+            }
+        }
+    };
+
+    private int mInteractingWindows;
+    private boolean mAutohideSuspended;
+    private int mStatusBarMode;
+    private int mNavigationBarMode;
+    private Boolean mScreenOn;
+
+    private final Runnable mAutohide = new Runnable() {
+        @Override
+        public void run() {
+            int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
+            if (mSystemUiVisibility != requested) {
+                notifyUiVisibilityChanged(requested);
+            }
+        }};
+
     @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
-
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.checkService(DreamService.DREAM_SERVICE));
+        mDisplay.getSize(mCurrentDisplaySize);
 
         super.start(); // calls createAndAddWindows()
 
         addNavigationBar();
 
-        if (ENABLE_INTRUDERS) addIntruderView();
-
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext);
+
+        mHeadsUpObserver.onChange(true); // set up
+        if (ENABLE_HEADS_UP) {
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(SETTING_HEADS_UP), true,
+                    mHeadsUpObserver);
+        }
     }
 
     // ================================================================================
@@ -341,6 +379,7 @@
         mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
+                checkUserAutohide(v, event);
                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
                     if (mExpandedVisible) {
                         animateCollapsePanels();
@@ -351,7 +390,6 @@
 
         mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
         mStatusBarView.setBar(this);
-        
 
         PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
         mStatusBarView.setPanelHolder(holder);
@@ -375,10 +413,11 @@
             mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
                     R.color.notification_panel_solid_background)));
         }
-        if (ENABLE_INTRUDERS) {
-            mIntruderAlertView = (IntruderAlertView) View.inflate(context, R.layout.intruder_alert, null);
-            mIntruderAlertView.setVisibility(View.GONE);
-            mIntruderAlertView.setBar(this);
+        if (ENABLE_HEADS_UP) {
+            mHeadsUpNotificationView =
+                    (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null);
+            mHeadsUpNotificationView.setVisibility(View.GONE);
+            mHeadsUpNotificationView.setBar(this);
         }
         if (MULTIUSER_DEBUG) {
             mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
@@ -389,13 +428,19 @@
 
         try {
             boolean showNav = mWindowManagerService.hasNavigationBar();
-            if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav);
+            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
             if (showNav) {
                 mNavigationBarView =
                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
 
                 mNavigationBarView.setDisabledFlags(mDisabled);
                 mNavigationBarView.setBar(this);
+                mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
+                    @Override
+                    public boolean onTouch(View v, MotionEvent event) {
+                        checkUserAutohide(v, event);
+                        return false;
+                    }});
             }
         } catch (RemoteException ex) {
             // no window manager? good luck with that
@@ -486,9 +531,9 @@
         // Other icons
         mLocationController = new LocationController(mContext); // will post a notification
         mBatteryController = new BatteryController(mContext);
-        mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
         mNetworkController = new NetworkController(mContext);
         mBluetoothController = new BluetoothController(mContext);
+        mRotationLockController = new RotationLockController(mContext);
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
 
@@ -515,7 +560,7 @@
 
         mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
         mShowCarrierInPanel = (mCarrierLabel != null);
-        if (DEBUG) Slog.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel);
+        if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel);
         if (mShowCarrierInPanel) {
             mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE);
 
@@ -581,31 +626,18 @@
                 mQS.setService(this);
                 mQS.setBar(mStatusBarView);
                 mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
-                        mLocationController);
+                        mLocationController, mRotationLockController);
             } else {
                 mQS = null; // fly away, be free
             }
         }
 
-        mClingShown = ! (DEBUG_CLINGS 
-            || !Prefs.read(mContext).getBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, false));
-
-        if (!ENABLE_NOTIFICATION_PANEL_CLING || ActivityManager.isRunningInTestHarness()) {
-            mClingShown = true;
-        }
-
-//        final ImageView wimaxRSSI =
-//                (ImageView)sb.findViewById(R.id.wimax_signal);
-//        if (wimaxRSSI != null) {
-//            mNetworkController.addWimaxIconView(wimaxRSSI);
-//        }
-
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_SCREEN_ON);
+        filter.addAction(ACTION_DEMO);
         context.registerReceiver(mBroadcastReceiver, filter);
 
         // listen for USER_SETUP_COMPLETE setting (per-user)
@@ -620,31 +652,6 @@
     }
 
     @Override
-    protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
-        boolean opaque = false;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                layoutParams.width,
-                layoutParams.height,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
-        if (ActivityManager.isHighEndGfx()) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        } else {
-            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-            lp.dimAmount = 0.75f;
-        }
-        lp.gravity = Gravity.BOTTOM | Gravity.START;
-        lp.setTitle("RecentsPanel");
-        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-        | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-        return lp;
-    }
-
-    @Override
     protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
         boolean opaque = false;
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -670,8 +677,9 @@
     @Override
     protected void updateSearchPanel() {
         super.updateSearchPanel();
-        mSearchPanelView.setStatusBarView(mNavigationBarView);
-        mNavigationBarView.setDelegateView(mSearchPanelView);
+        if (mNavigationBarView != null) {
+            mNavigationBarView.setDelegateView(mSearchPanelView);
+        }
     }
 
     @Override
@@ -682,19 +690,23 @@
         // we want to freeze the sysui state wherever it is
         mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility);
 
-        WindowManager.LayoutParams lp =
-            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
-        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        mWindowManager.updateViewLayout(mNavigationBarView, lp);
+        if (mNavigationBarView != null) {
+            WindowManager.LayoutParams lp =
+                (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
+            lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            mWindowManager.updateViewLayout(mNavigationBarView, lp);
+        }
     }
 
     @Override
     public void hideSearchPanel() {
         super.hideSearchPanel();
-        WindowManager.LayoutParams lp =
-            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
-        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        mWindowManager.updateViewLayout(mNavigationBarView, lp);
+        if (mNavigationBarView != null) {
+            WindowManager.LayoutParams lp =
+                (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
+            lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            mWindowManager.updateViewLayout(mNavigationBarView, lp);
+        }
     }
 
     protected int getStatusBarGravity() {
@@ -767,7 +779,7 @@
 
     // For small-screen devices (read: phones) that lack hardware navigation buttons
     private void addNavigationBar() {
-        if (DEBUG) Slog.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
+        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
         if (mNavigationBarView == null) return;
 
         prepareNavigationBarView();
@@ -798,7 +810,7 @@
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.OPAQUE);
+                PixelFormat.TRANSLUCENT);
         // this will allow the navbar to run in an overlay on devices that support this
         if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
@@ -809,10 +821,9 @@
         return lp;
     }
 
-    private void addIntruderView() {
+    private void addHeadsUpView() {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -821,13 +832,18 @@
                     | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        //lp.y += height * 1.5; // FIXME
-        lp.setTitle("IntruderAlert");
+        lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        lp.gravity = Gravity.TOP;
+        lp.y = getStatusBarHeight();
+        lp.setTitle("Heads Up");
         lp.packageName = mContext.getPackageName();
-        lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
+        lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp;
 
-        mWindowManager.addView(mIntruderAlertView, lp);
+        mWindowManager.addView(mHeadsUpNotificationView, lp);
+    }
+
+    private void removeHeadsUpView() {
+        mWindowManager.removeView(mHeadsUpNotificationView);
     }
 
     public void refreshAllStatusBarIcons() {
@@ -846,7 +862,7 @@
     }
 
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+        if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
                 + " icon=" + icon);
         StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
         view.set(icon);
@@ -855,74 +871,47 @@
 
     public void updateIcon(String slot, int index, int viewIndex,
             StatusBarIcon old, StatusBarIcon icon) {
-        if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+        if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
                 + " old=" + old + " icon=" + icon);
         StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
         view.set(icon);
     }
 
     public void removeIcon(String slot, int index, int viewIndex) {
-        if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
+        if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
         mStatusIcons.removeViewAt(viewIndex);
     }
 
     public void addNotification(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) Slog.d(TAG, "addNotification score=" + notification.getScore());
-        StatusBarIconView iconView = addNotificationViews(key, notification);
-        if (iconView == null) return;
-
-        boolean immersive = false;
-        try {
-            immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
-            if (DEBUG) {
-                Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
-            }
-        } catch (RemoteException ex) {
+        if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore());
+        Entry shadeEntry = createNotificationViews(key, notification);
+        if (shadeEntry == null) {
+            return;
         }
+        if (mUseHeadsUp && shouldInterrupt(notification)) {
+            if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
+            Entry interruptionCandidate = new Entry(key, notification, null);
+            if (inflateViews(interruptionCandidate, mHeadsUpNotificationView.getHolder())) {
+                mInterruptingNotificationTime = System.currentTimeMillis();
+                mInterruptingNotificationEntry = interruptionCandidate;
+                shadeEntry.setInterruption();
 
-        /*
-         * DISABLED due to missing API
-        if (ENABLE_INTRUDERS && (
-                   // TODO(dsandler): Only if the screen is on
-                notification.notification.intruderView != null)) {
-            Slog.d(TAG, "Presenting high-priority notification");
-            // special new transient ticker mode
-            // 1. Populate mIntruderAlertView
+                // 1. Populate mHeadsUpNotificationView
+                mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
 
-            if (notification.notification.intruderView == null) {
-                Slog.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null");
-                return;
+                // 2. Animate mHeadsUpNotificationView in
+                mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+
+                // 3. Set alarm to age the notification off
+                resetHeadsUpDecayTimer();
             }
-
-            // bind the click event to the content area
-            PendingIntent contentIntent = notification.notification.contentIntent;
-            final View.OnClickListener listener = (contentIntent != null)
-                    ? new NotificationClicker(contentIntent,
-                            notification.pkg, notification.tag, notification.id)
-                    : null;
-
-            mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener);
-
-            mCurrentlyIntrudingNotification = notification;
-
-            // 2. Animate mIntruderAlertView in
-            mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
-
-            // 3. Set alarm to age the notification off (TODO)
-            mHandler.removeMessages(MSG_HIDE_INTRUDER);
-            if (INTRUDER_ALERT_DECAY_MS > 0) {
-                mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
-            }
-        } else
-         */
-
-        if (notification.getNotification().fullScreenIntent != null) {
+        } else if (notification.getNotification().fullScreenIntent != null) {
             // Stop screensaver if the notification has a full-screen intent.
             // (like an incoming phone call)
             awakenDreams();
 
             // not immersive & a full-screen alert should be shown
-            if (DEBUG) Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+            if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
             try {
                 notification.getNotification().fullScreenIntent.send();
             } catch (PendingIntent.CanceledException e) {
@@ -930,20 +919,29 @@
         } else {
             // usual case: status bar visible & not immersive
 
-            // show the ticker if there isn't an intruder too
-            if (mCurrentlyIntrudingNotification == null) {
+            // show the ticker if there isn't already a heads up
+            if (mInterruptingNotificationEntry == null) {
                 tick(null, notification, true);
             }
         }
-
+        addNotificationViews(shadeEntry);
         // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
     }
 
+    @Override
+    public void resetHeadsUpDecayTimer() {
+        if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
+                && mHeadsUpNotificationView.isClearable()) {
+            mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+            mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
+        }
+    }
+
     public void removeNotification(IBinder key) {
         StatusBarNotification old = removeNotificationViews(key);
-        if (SPEW) Slog.d(TAG, "removeNotification key=" + key + " old=" + old);
+        if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
 
         if (old != null) {
             // Cancel the ticker if it's still running
@@ -952,11 +950,13 @@
             // Recalculate the position of the sliding windows and the titles.
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
 
-            if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) {
-                mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+            if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
+                    && old == mInterruptingNotificationEntry.notification) {
+                mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
             }
 
-            if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0) {
+            if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
+                    && !mNotificationPanel.isTracking()) {
                 animateCollapsePanels();
             }
         }
@@ -1048,7 +1048,7 @@
         int N = mNotificationData.size();
 
         if (DEBUG) {
-            Slog.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);
+            Log.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);
         }
 
         ArrayList<View> toShow = new ArrayList<View>();
@@ -1085,10 +1085,10 @@
 
     protected void updateCarrierLabelVisibility(boolean force) {
         if (!mShowCarrierInPanel) return;
-        // The idea here is to only show the carrier label when there is enough room to see it, 
+        // The idea here is to only show the carrier label when there is enough room to see it,
         // i.e. when there aren't enough notifications to fill the panel.
-        if (DEBUG) {
-            Slog.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
+        if (SPEW) {
+            Log.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
                     mPile.getHeight(), mScrollView.getHeight(), mCarrierLabelHeight));
         }
 
@@ -1097,11 +1097,11 @@
             !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
             && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight)
             && mScrollView.getVisibility() == View.VISIBLE;
-        
+
         if (force || mCarrierLabelVisible != makeVisible) {
             mCarrierLabelVisible = makeVisible;
             if (DEBUG) {
-                Slog.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
+                Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
             }
             mCarrierLabel.animate().cancel();
             if (makeVisible) {
@@ -1131,13 +1131,13 @@
 
         final boolean clearable = any && mNotificationData.hasClearableItems();
 
-        if (DEBUG) {
-            Slog.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size()
+        if (SPEW) {
+            Log.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size()
                     + " any=" + any + " clearable=" + clearable);
         }
 
-        if (mHasFlipSettings 
-                && mFlipSettingsView != null 
+        if (mHasFlipSettings
+                && mFlipSettingsView != null
                 && mFlipSettingsView.getVisibility() == View.VISIBLE
                 && mScrollView.getVisibility() != View.VISIBLE) {
             // the flip settings panel is unequivocally showing; we should not be shown
@@ -1209,7 +1209,7 @@
         mDisabled = state;
 
         if (DEBUG) {
-            Slog.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)",
+            Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)",
                 old, state, diff));
         }
 
@@ -1236,7 +1236,7 @@
         flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
         flagdbg.append(((diff  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
         flagdbg.append(">");
-        Slog.d(TAG, flagdbg.toString());
+        Log.d(TAG, flagdbg.toString());
 
         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
             mSystemIconArea.animate().cancel();
@@ -1335,13 +1335,32 @@
                 case MSG_CLOSE_PANELS:
                     animateCollapsePanels();
                     break;
-                case MSG_SHOW_INTRUDER:
-                    setIntruderAlertVisibility(true);
+                case MSG_SHOW_HEADS_UP:
+                    setHeadsUpVisibility(true);
                     break;
-                case MSG_HIDE_INTRUDER:
-                    setIntruderAlertVisibility(false);
-                    mCurrentlyIntrudingNotification = null;
+                case MSG_HIDE_HEADS_UP:
+                    setHeadsUpVisibility(false);
                     break;
+                case MSG_ESCALATE_HEADS_UP:
+                    escalateHeadsUp();
+                    setHeadsUpVisibility(false);
+                    break;
+            }
+        }
+    }
+
+    /**  if the interrupting notification had a fullscreen intent, fire it now.  */
+    private void escalateHeadsUp() {
+        if (mInterruptingNotificationEntry != null) {
+            final StatusBarNotification sbn = mInterruptingNotificationEntry.notification;
+            final Notification notification = sbn.getNotification();
+            if (notification.fullScreenIntent != null) {
+                if (DEBUG)
+                    Log.d(TAG, "converting a heads up to fullScreen");
+                try {
+                    notification.fullScreenIntent.send();
+                } catch (PendingIntent.CanceledException e) {
+                }
             }
         }
     }
@@ -1358,9 +1377,13 @@
         }
     };
 
-    void makeExpandedVisible(boolean revealAfterDraw) {
-        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (mExpandedVisible) {
+    boolean panelsEnabled() {
+        return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0;
+    }
+
+    void makeExpandedVisible() {
+        if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+        if (mExpandedVisible || !panelsEnabled()) {
             return;
         }
 
@@ -1381,13 +1404,17 @@
         lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
         mWindowManager.updateViewLayout(mStatusBarWindow, lp);
 
-        // Updating the window layout will force an expensive traversal/redraw.
-        // Kick off the reveal animation after this is complete to avoid animation latency.
-        if (revealAfterDraw) {
-//            mHandler.post(mStartRevealAnimation);
-        }
-
         visibilityChanged(true);
+
+        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
+    }
+
+    private void releaseFocus() {
+        WindowManager.LayoutParams lp =
+                (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
+        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mWindowManager.updateViewLayout(mStatusBarWindow, lp);
     }
 
     public void animateCollapsePanels() {
@@ -1396,11 +1423,14 @@
 
     public void animateCollapsePanels(int flags) {
         if (SPEW) {
-            Slog.d(TAG, "animateCollapse():"
+            Log.d(TAG, "animateCollapse():"
                     + " mExpandedVisible=" + mExpandedVisible
                     + " flags=" + flags);
         }
 
+        // release focus immediately to kick off focus change transition
+        releaseFocus();
+
         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
             mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
             mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
@@ -1447,7 +1477,7 @@
         a.setStartDelay(d);
         return a;
     }
-    
+
     public Animator start(Animator a) {
         a.start();
         return a;
@@ -1464,8 +1494,8 @@
 
     @Override
     public void animateExpandNotificationsPanel() {
-        if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
+        if (!panelsEnabled()) {
             return ;
         }
 
@@ -1519,8 +1549,8 @@
 
     @Override
     public void animateExpandSettingsPanel() {
-        if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
+        if (!panelsEnabled()) {
             return;
         }
 
@@ -1576,7 +1606,7 @@
                 interpolator(mAccelerateInterpolator,
                         ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
                         )
-                    .setDuration(FLIP_DURATION_OUT), 
+                    .setDuration(FLIP_DURATION_OUT),
                 mScrollView, View.INVISIBLE));
         mSettingsButtonAnim = start(
             setVisibilityWhenDone(
@@ -1618,7 +1648,7 @@
     }
 
     void makeExpandedInvisible() {
-        if (SPEW) Slog.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
+        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
                 + " mExpandedVisible=" + mExpandedVisible);
 
         if (!mExpandedVisible) {
@@ -1670,17 +1700,19 @@
             mPostCollapseCleanup.run();
             mPostCollapseCleanup = null;
         }
+
+        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
     }
 
     /**
      * Enables or disables layers on the children of the notifications pile.
-     * 
+     *
      * When layers are enabled, this method attempts to enable layers for the minimal
      * number of children. Only children visible when the notification area is fully
      * expanded will receive a layer. The technique used in this method might cause
      * more children than necessary to get a layer (at most one extra child with the
      * current UI.)
-     * 
+     *
      * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE}
      */
     private void setPileLayers(int layerType) {
@@ -1693,7 +1725,7 @@
                 }
                 break;
             case View.LAYER_TYPE_HARDWARE:
-                final int[] location = new int[2]; 
+                final int[] location = new int[2];
                 mNotificationPanel.getLocationInWindow(location);
 
                 final int left = location[0];
@@ -1719,63 +1751,6 @@
         }
     }
 
-    public boolean isClinging() {
-        return mCling != null && mCling.getVisibility() == View.VISIBLE;
-    }
-
-    public void hideCling() {
-        if (isClinging()) {
-            mCling.animate().alpha(0f).setDuration(250).start();
-            mCling.setVisibility(View.GONE);
-            mSuppressStatusBarDrags = false;
-        }
-    }
-
-    public void showCling() {
-        // lazily inflate this to accommodate orientation change
-        final ViewStub stub = (ViewStub) mStatusBarWindow.findViewById(R.id.status_bar_cling_stub);
-        if (stub == null) {
-            mClingShown = true;
-            return; // no clings on this device
-        }
-
-        mSuppressStatusBarDrags = true;
-
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                mCling = (ViewGroup) stub.inflate();
-
-                mCling.setOnTouchListener(new View.OnTouchListener() {
-                    @Override
-                    public boolean onTouch(View v, MotionEvent event) {
-                        return true; // e eats everything
-                    }});
-                mCling.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
-                    @Override
-                    public void onClick(View v) {
-                        hideCling();
-                    }});
-
-                mCling.setAlpha(0f);
-                mCling.setVisibility(View.VISIBLE);
-                mCling.animate().alpha(1f);
-
-                mClingShown = true;
-                SharedPreferences.Editor editor = Prefs.edit(mContext);
-                editor.putBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, true);
-                editor.apply();
-
-                makeExpandedVisible(true); // enforce visibility in case the shade is still animating closed
-                animateExpandNotificationsPanel();
-
-                mSuppressStatusBarDrags = false;
-            }
-        }, 500);
-
-        animateExpandNotificationsPanel();
-    }
-
     public boolean interceptTouchEvent(MotionEvent event) {
         if (DEBUG_GESTURES) {
             if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -1786,11 +1761,11 @@
         }
 
         if (SPEW) {
-            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+            Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
                 + mDisabled + " mTracking=" + mTracking);
         } else if (CHATTY) {
             if (event.getAction() != MotionEvent.ACTION_MOVE) {
-                Slog.d(TAG, String.format(
+                Log.d(TAG, String.format(
                             "panel: %s at (%f, %f) mDisabled=0x%08x",
                             MotionEvent.actionToString(event.getAction()),
                             event.getRawX(), event.getRawY(), mDisabled));
@@ -1801,21 +1776,16 @@
             mGestureRec.add(event);
         }
 
-        // Cling (first-run help) handling.
-        // The cling is supposed to show the first time you drag, or even tap, the status bar.
-        // It should show the notification panel, then fade in after half a second, giving you 
-        // an explanation of what just happened, as well as teach you how to access quick
-        // settings (another drag). The user can dismiss the cling by clicking OK or by 
-        // dragging quick settings into view.
-        final int act = event.getActionMasked();
-        if (mSuppressStatusBarDrags) {
-            return true;
-        } else if (act == MotionEvent.ACTION_UP && !mClingShown) {
-            showCling();
-        } else {
-            hideCling();
+        if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
+            final boolean upOrCancel =
+                    event.getAction() == MotionEvent.ACTION_UP ||
+                    event.getAction() == MotionEvent.ACTION_CANCEL;
+            if (upOrCancel && !mExpandedVisible) {
+                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
+            } else {
+                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
+            }
         }
-
         return false;
     }
 
@@ -1832,6 +1802,27 @@
         if (mNavigationBarView != null) {
             mNavigationBarView.setNavigationIconHints(hints);
         }
+        checkBarModes();
+    }
+
+    @Override // CommandQueue
+    public void setWindowState(int window, int state) {
+        boolean showing = state == WINDOW_STATE_SHOWING;
+        if (mStatusBarWindow != null
+                && window == StatusBarManager.WINDOW_STATUS_BAR
+                && mStatusBarWindowState != state) {
+            mStatusBarWindowState = state;
+            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
+            if (!showing) {
+                mStatusBarView.collapseAllPanels(false);
+            }
+        }
+        if (mNavigationBarView != null
+                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
+                && mNavigationBarWindowState != state) {
+            mNavigationBarWindowState = state;
+            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
+        }
     }
 
     @Override // CommandQueue
@@ -1839,12 +1830,17 @@
         final int oldVal = mSystemUiVisibility;
         final int newVal = (oldVal&~mask) | (vis&mask);
         final int diff = newVal ^ oldVal;
-
+        if (DEBUG) Log.d(TAG, String.format(
+                "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
+                Integer.toHexString(vis), Integer.toHexString(mask),
+                Integer.toHexString(oldVal), Integer.toHexString(newVal),
+                Integer.toHexString(diff)));
         if (diff != 0) {
             mSystemUiVisibility = newVal;
 
-            if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
-                final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE));
+            // update low profile
+            if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+                final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0;
                 if (lightsOut) {
                     animateCollapsePanels();
                     if (mTicking) {
@@ -1852,56 +1848,141 @@
                     }
                 }
 
-                if (mNavigationBarView != null) {
-                    mNavigationBarView.setLowProfile(lightsOut);
-                }
-
-                setStatusBarLowProfile(lightsOut);
+                setAreThereNotifications();
             }
 
-            notifyUiVisibilityChanged();
+            // update status bar mode
+            final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
+                    View.STATUS_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS);
+
+            // update navigation bar mode
+            final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
+                    oldVal, newVal, mNavigationBarView.getBarTransitions(),
+                    View.NAVIGATION_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION);
+            final boolean sbModeChanged = sbMode != -1;
+            final boolean nbModeChanged = nbMode != -1;
+            boolean checkBarModes = false;
+            if (sbModeChanged && sbMode != mStatusBarMode) {
+                mStatusBarMode = sbMode;
+                checkBarModes = true;
+            }
+            if (nbModeChanged && nbMode != mNavigationBarMode) {
+                mNavigationBarMode = nbMode;
+                checkBarModes = true;
+            }
+            if (checkBarModes) {
+                checkBarModes();
+            }
+            if (sbModeChanged || nbModeChanged) {
+                // update transient bar autohide
+                if (sbMode == MODE_SEMI_TRANSPARENT || nbMode == MODE_SEMI_TRANSPARENT) {
+                    scheduleAutohide();
+                } else {
+                    cancelAutohide();
+                }
+            }
+
+            // ready to unhide
+            if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
+            }
+            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
+            }
+
+            // send updated sysui visibility to window manager
+            notifyUiVisibilityChanged(mSystemUiVisibility);
         }
     }
 
-    private void setStatusBarLowProfile(boolean lightsOut) {
-        if (mLightsOutAnimation == null) {
-            final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
-            final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
-            final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
-            final View battery = mStatusBarView.findViewById(R.id.battery);
-            final View clock = mStatusBarView.findViewById(R.id.clock);
-
-            final AnimatorSet lightsOutAnim = new AnimatorSet();
-            lightsOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
-                    ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
-                    ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
-                    ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
-                    ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
-                );
-            lightsOutAnim.setDuration(750);
-
-            final AnimatorSet lightsOnAnim = new AnimatorSet();
-            lightsOnAnim.playTogether(
-                    ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
-                );
-            lightsOnAnim.setDuration(250);
-
-            mLightsOutAnimation = lightsOutAnim;
-            mLightsOnAnimation = lightsOnAnim;
+    private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
+            int transientFlag, int transparentFlag) {
+        final int oldMode = barMode(oldVis, transientFlag, transparentFlag);
+        final int newMode = barMode(newVis, transientFlag, transparentFlag);
+        if (oldMode == newMode) {
+            return -1; // no mode change
         }
+        return newMode;
+    }
 
-        mLightsOutAnimation.cancel();
-        mLightsOnAnimation.cancel();
+    private int barMode(int vis, int transientFlag, int transparentFlag) {
+        return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
+                : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
+                : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
+                : MODE_OPAQUE;
+    }
 
-        final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation;
-        a.start();
+    private void checkBarModes() {
+        if (mDemoMode) return;
+        checkBarMode((mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0 ? MODE_OPAQUE
+                : mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
+        if (mNavigationBarView != null) {
+            checkBarMode(mNavigationBarMode,
+                    mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
+        }
+    }
 
-        setAreThereNotifications();
+    private void checkBarMode(int mode, int windowState, BarTransitions transitions) {
+        final boolean imeVisible = (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0;
+        final int finalMode = imeVisible ? MODE_OPAQUE : mode;
+        final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN;
+        transitions.transitionTo(finalMode, anim);
+    }
+
+    private final Runnable mCheckBarModes = new Runnable() {
+        @Override
+        public void run() {
+            checkBarModes();
+        }};
+
+    @Override
+    public void setInteracting(int barWindow, boolean interacting) {
+        mInteractingWindows = interacting
+                ? (mInteractingWindows | barWindow)
+                : (mInteractingWindows & ~barWindow);
+        if (mInteractingWindows != 0) {
+            suspendAutohide();
+        } else {
+            resumeSuspendedAutohide();
+        }
+        checkBarModes();
+    }
+
+    private void resumeSuspendedAutohide() {
+        if (mAutohideSuspended) {
+            scheduleAutohide();
+            mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
+        }
+    }
+
+    private void suspendAutohide() {
+        mHandler.removeCallbacks(mAutohide);
+        mHandler.removeCallbacks(mCheckBarModes);
+        mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
+    }
+
+    private void cancelAutohide() {
+        mAutohideSuspended = false;
+        mHandler.removeCallbacks(mAutohide);
+    }
+
+    private void scheduleAutohide() {
+        cancelAutohide();
+        mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
+    }
+
+    private void checkUserAutohide(View v, MotionEvent event) {
+        if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
+                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
+                && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
+                ) {
+            userAutohide();
+        }
+    }
+
+    private void userAutohide() {
+        cancelAutohide();
+        mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
     }
 
     private boolean areLightsOn() {
@@ -1917,16 +1998,16 @@
         }
     }
 
-    private void notifyUiVisibilityChanged() {
+    private void notifyUiVisibilityChanged(int vis) {
         try {
-            mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility);
+            mWindowManagerService.statusBarVisibilityChanged(vis);
         } catch (RemoteException ex) {
         }
     }
 
     public void topAppWindowChanged(boolean showMenu) {
         if (DEBUG) {
-            Slog.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
+            Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
         }
         if (mNavigationBarView != null) {
             mNavigationBarView.setMenuVisibility(showMenu);
@@ -1942,8 +2023,8 @@
             || ((vis & InputMethodService.IME_VISIBLE) != 0);
 
         mCommandQueue.setNavigationIconHints(
-                altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
-                        : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+                altBack ? (mNavigationIconHints | NAVIGATION_HINT_BACK_ALT)
+                        : (mNavigationIconHints & ~NAVIGATION_HINT_BACK_ALT));
         if (mQS != null) mQS.setImeWindowStatus(vis > 0);
     }
 
@@ -2041,6 +2122,20 @@
                     + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
         }
 
+        pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
+        pw.print("  mStatusBarWindowState=");
+        pw.println(windowStateToString(mStatusBarWindowState));
+        pw.print("  mStatusBarMode=");
+        pw.println(BarTransitions.modeToString(mStatusBarMode));
+        dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
+        if (mNavigationBarView != null) {
+            pw.print("  mNavigationBarWindowState=");
+            pw.println(windowStateToString(mNavigationBarWindowState));
+            pw.print("  mNavigationBarMode=");
+            pw.println(BarTransitions.modeToString(mNavigationBarMode));
+            dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
+        }
+
         pw.print("  mNavigationBarView=");
         if (mNavigationBarView == null) {
             pw.println("null");
@@ -2089,7 +2184,7 @@
                 mHandler.post(new Runnable() {
                         public void run() {
                             mStatusBarView.getLocationOnScreen(mAbsPos);
-                            Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                            Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
                                     + ") " + mStatusBarView.getWidth() + "x"
                                     + getStatusBarHeight());
                             mStatusBarView.debug();
@@ -2106,6 +2201,11 @@
         mNetworkController.dump(fd, pw, args);
     }
 
+    private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
+        pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
+        pw.println(BarTransitions.modeToString(transitions.getMode()));
+    }
+
     @Override
     public void createAndAddWindows() {
         addStatusBarWindow();
@@ -2124,7 +2224,8 @@
                 WindowManager.LayoutParams.TYPE_STATUS_BAR,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);
 
         lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
@@ -2161,7 +2262,7 @@
 
     @Override
     public void updateExpandedViewPos(int thingy) {
-        if (DEBUG) Slog.v(TAG, "updateExpandedViewPos");
+        if (SPEW) Log.v(TAG, "updateExpandedViewPos");
 
         // on larger devices, the notification panel is propped open a bit
         mNotificationPanel.setMinimumHeight(
@@ -2179,6 +2280,12 @@
             mSettingsPanel.setLayoutParams(lp);
         }
 
+        if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
+            mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
+            mPile.getLocationOnScreen(mPilePosition);
+            mHeadsUpVerticalOffset = mPilePosition[1] - mNaturalBarHeight;
+        }
+
         updateCarrierLabelVisibility(false);
     }
 
@@ -2186,7 +2293,7 @@
     void updateDisplaySize() {
         mDisplay.getMetrics(mDisplayMetrics);
         if (DEBUG_GESTURES) {
-            mGestureRec.tag("display", 
+            mGestureRec.tag("display",
                     String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
         }
     }
@@ -2229,7 +2336,7 @@
                             @Override
                             public void run() {
                                 if (DEBUG) {
-                                    Slog.v(TAG, "running post-collapse cleanup");
+                                    Log.v(TAG, "running post-collapse cleanup");
                                 }
                                 try {
                                     mPile.setViewRemoval(true);
@@ -2307,7 +2414,7 @@
 
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
-            if (DEBUG) Slog.v(TAG, "onReceive: " + intent);
+            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
@@ -2320,29 +2427,50 @@
                 animateCollapsePanels(flags);
             }
             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+                mScreenOn = false;
                 // no waiting!
                 makeExpandedInvisible();
                 notifyNavigationBarScreenOn(false);
-            }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                if (DEBUG) {
-                    Slog.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
-                }
-                mDisplay.getSize(mCurrentDisplaySize);
-
-                updateResources();
-                repositionNavigationBar();
-                updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-                updateShowSearchHoldoff();
+                notifyHeadsUpScreenOn(false);
             }
             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
+                mScreenOn = true;
                 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
                 repositionNavigationBar();
                 notifyNavigationBarScreenOn(true);
             }
+            else if (ACTION_DEMO.equals(action)) {
+                Bundle bundle = intent.getExtras();
+                if (bundle != null) {
+                    String command = bundle.getString("command", "").trim().toLowerCase();
+                    if (command.length() > 0) {
+                        try {
+                            dispatchDemoCommand(command, bundle);
+                        } catch (Throwable t) {
+                            Log.w(TAG, "Error running demo command, intent=" + intent, t);
+                        }
+                    }
+                }
+            }
         }
     };
 
+    // SystemUIService notifies SystemBars of configuration changes, which then calls down here
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig); // calls refreshLayout
+
+        if (DEBUG) {
+            Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
+        }
+        mDisplay.getSize(mCurrentDisplaySize);
+
+        updateResources();
+        repositionNavigationBar();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        updateShowSearchHoldoff();
+    }
+
     @Override
     public void userSwitched(int newUserId) {
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
@@ -2360,24 +2488,39 @@
                 mCurrentUserId);
     }
 
-    private void setIntruderAlertVisibility(boolean vis) {
-        if (!ENABLE_INTRUDERS) return;
-        if (DEBUG) {
-            Slog.v(TAG, (vis ? "showing" : "hiding") + " intruder alert window");
+    private void setHeadsUpVisibility(boolean vis) {
+        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;
         }
-        mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
     }
 
-    public void dismissIntruder() {
-        if (mCurrentlyIntrudingNotification == null) return;
+    public void animateHeadsUp(boolean animateInto, float frac) {
+        if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return;
+        frac = frac / 0.4f;
+        frac = frac < 1.0f ? frac : 1.0f;
+        float alpha = 1.0f - frac;
+        float offset = mHeadsUpVerticalOffset * frac;
+        offset = animateInto ? offset : 0f;
+        mHeadsUpNotificationView.setAlpha(alpha);
+        mHeadsUpNotificationView.setY(offset);
+    }
 
-        try {
-            mBarService.onNotificationClear(
-                    mCurrentlyIntrudingNotification.getPackageName(),
-                    mCurrentlyIntrudingNotification.getTag(),
-                    mCurrentlyIntrudingNotification.getId());
-        } catch (android.os.RemoteException ex) {
-            // oh well
+    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());
+            } catch (android.os.RemoteException ex) {
+                // oh well
+            }
         }
     }
 
@@ -2414,7 +2557,7 @@
             R.dimen.status_bar_icon_padding);
 
         if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
-//            Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
+//            Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
             mIconHPadding = newIconHPadding;
             mIconSize = newIconSize;
             //reloadAllNotificationIcons(); // reload the tray
@@ -2459,7 +2602,10 @@
             mNotificationPanelMinHeightFrac = 0f;
         }
 
-        if (false) Slog.v(TAG, "updateResources");
+        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
+        mRowHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
+
+        if (false) Log.v(TAG, "updateResources");
     }
 
     //
@@ -2480,7 +2626,7 @@
         public void run() {
             vibrate();
             SystemClock.sleep(250);
-            Slog.d(TAG, "startTracing");
+            Log.d(TAG, "startTracing");
             android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
             mHandler.postDelayed(mStopTracing, 10000);
         }
@@ -2489,7 +2635,7 @@
     Runnable mStopTracing = new Runnable() {
         public void run() {
             android.os.Debug.stopMethodTracing();
-            Slog.d(TAG, "stopTracing");
+            Log.d(TAG, "stopTracing");
             vibrate();
         }
     };
@@ -2539,4 +2685,78 @@
         public void setBounds(Rect bounds) {
         }
     }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        if (mStatusBarWindow != null) {
+            mWindowManager.removeViewImmediate(mStatusBarWindow);
+        }
+        if (mNavigationBarView != null) {
+            mWindowManager.removeViewImmediate(mNavigationBarView);
+        }
+        mContext.unregisterReceiver(mBroadcastReceiver);
+    }
+
+    private boolean mDemoModeAllowed;
+    private boolean mDemoMode;
+    private DemoStatusIcons mDemoStatusIcons;
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoModeAllowed) {
+            mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
+                    "sysui_demo_allowed", 0) != 0;
+        }
+        if (!mDemoModeAllowed) return;
+        if (command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+        } else if (command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            checkBarModes();
+        } else if (!mDemoMode) {
+            // automatically enter demo mode on first demo command
+            dispatchDemoCommand(COMMAND_ENTER, new Bundle());
+        }
+        boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
+        if (modeChange || command.equals(COMMAND_CLOCK)) {
+            dispatchDemoCommandToView(command, args, R.id.clock);
+        }
+        if (modeChange || command.equals(COMMAND_BATTERY)) {
+            dispatchDemoCommandToView(command, args, R.id.battery);
+        }
+        if (modeChange || command.equals(COMMAND_STATUS)) {
+            if (mDemoStatusIcons == null) {
+                mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
+            }
+            mDemoStatusIcons.dispatchDemoCommand(command, args);
+        }
+        if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
+            mNetworkController.dispatchDemoCommand(command, args);
+        }
+        if (command.equals(COMMAND_BARS)) {
+            String mode = args.getString("mode");
+            int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
+                    "transparent".equals(mode) ? MODE_TRANSPARENT :
+                    "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
+                    -1;
+            if (barMode != -1) {
+                boolean animate = true;
+                if (mStatusBarView != null) {
+                    mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
+                }
+                if (mNavigationBarView != null) {
+                    mNavigationBarView.getBarTransitions().transitionTo(barMode, animate);
+                }
+            }
+        }
+    }
+
+    private void dispatchDemoCommandToView(String command, Bundle args, int id) {
+        if (mStatusBarView == null) return;
+        View v = mStatusBarView.findViewById(id);
+        if (v instanceof DemoMode) {
+            ((DemoMode)v).dispatchDemoCommand(command, args);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 9b8bd22..8957a77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,28 +22,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.location.LocationManager;
 import android.media.AudioManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
 import android.os.Handler;
-import android.os.RemoteException;
-import android.os.storage.StorageManager;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.Slog;
+import android.util.Log;
 
-import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.EriInfo;
 import com.android.internal.telephony.cdma.TtyIntent;
-import com.android.server.am.BatteryStatsService;
 import com.android.systemui.R;
 
 /**
@@ -71,10 +56,6 @@
     private final StatusBarManager mService;
     private final Handler mHandler = new Handler();
 
-    // storage
-    private StorageManager mStorageManager;
-
-
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
     IccCardConstants.State mSimState = IccCardConstants.State.READY;
@@ -85,20 +66,6 @@
     // bluetooth device status
     private boolean mBluetoothEnabled = false;
 
-    // wifi
-    private static final int[][] sWifiSignalImages = {
-            { R.drawable.stat_sys_wifi_signal_1,
-              R.drawable.stat_sys_wifi_signal_2,
-              R.drawable.stat_sys_wifi_signal_3,
-              R.drawable.stat_sys_wifi_signal_4 },
-            { R.drawable.stat_sys_wifi_signal_1_fully,
-              R.drawable.stat_sys_wifi_signal_2_fully,
-              R.drawable.stat_sys_wifi_signal_3_fully,
-              R.drawable.stat_sys_wifi_signal_4_fully }
-        };
-    private static final int sWifiTemporarilyNotConnectedImage =
-            R.drawable.stat_sys_wifi_signal_0;
-
     private int mLastWifiSignalLevel = -1;
     private boolean mIsWifiConnected = false;
 
@@ -150,11 +117,6 @@
         filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
-        // storage
-        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
-        mStorageManager.registerListener(
-                new com.android.systemui.usb.StorageNotification(context));
-
         // TTY status
         mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0, null);
         mService.setIconVisibility("tty", false);
@@ -181,9 +143,8 @@
 
         // Sync state
         mService.setIcon("sync_active", R.drawable.stat_sys_sync, 0, null);
-        mService.setIcon("sync_failing", R.drawable.stat_sys_sync_error, 0, null);
         mService.setIconVisibility("sync_active", false);
-        mService.setIconVisibility("sync_failing", false);
+        // "sync_failing" is obsolete: b/1297963
 
         // volume
         mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);
@@ -199,10 +160,7 @@
     private final void updateSyncState(Intent intent) {
         if (!SHOW_SYNC_ICON) return;
         boolean isActive = intent.getBooleanExtra("active", false);
-        boolean isFailing = intent.getBooleanExtra("failing", false);
         mService.setIconVisibility("sync_active", isActive);
-        // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
-        //mService.setIconVisibility("sync_failing", isFailing && !isActive);
     }
 
     private final void updateSimState(Intent intent) {
@@ -284,17 +242,17 @@
         final String action = intent.getAction();
         final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
 
-        if (false) Slog.v(TAG, "updateTTY: enabled: " + enabled);
+        if (false) Log.v(TAG, "updateTTY: enabled: " + enabled);
 
         if (enabled) {
             // TTY is on
-            if (false) Slog.v(TAG, "updateTTY: set TTY on");
+            if (false) Log.v(TAG, "updateTTY: set TTY on");
             mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0,
                     mContext.getString(R.string.accessibility_tty_enabled));
             mService.setIconVisibility("tty", true);
         } else {
             // TTY is off
-            if (false) Slog.v(TAG, "updateTTY: set TTY off");
+            if (false) Log.v(TAG, "updateTTY: set TTY off");
             mService.setIconVisibility("tty", false);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
new file mode 100644
index 0000000..a492d76
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -0,0 +1,111 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.graphics.drawable.GradientDrawable.Orientation;
+import android.view.View;
+
+import com.android.systemui.R;
+
+public final class PhoneStatusBarTransitions extends BarTransitions {
+    private static final float ICON_ALPHA_WHEN_TRANSPARENT = 1;
+    private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK = 0.5f;
+    private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK = 0;
+
+    private final PhoneStatusBarView mView;
+    private final float mIconAlphaWhenOpaque;
+
+    private View mLeftSide, mStatusIcons, mSignalCluster, mBattery, mClock;
+    private Animator mCurrentAnimation;
+
+    public PhoneStatusBarTransitions(PhoneStatusBarView view) {
+        super(view);
+        mView = view;
+        final Resources res = mView.getContext().getResources();
+        mIconAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
+    }
+
+    public void init() {
+        mLeftSide = mView.findViewById(R.id.notification_icon_area);
+        mStatusIcons = mView.findViewById(R.id.statusIcons);
+        mSignalCluster = mView.findViewById(R.id.signal_cluster);
+        mBattery = mView.findViewById(R.id.battery);
+        mClock = mView.findViewById(R.id.clock);
+        setOrientation(Orientation.TOP_BOTTOM);
+        applyModeBackground(-1, getMode(), false /*animate*/);
+        applyMode(getMode(), false /*animate*/);
+    }
+
+    public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
+        return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha);
+    }
+
+    private float getNonBatteryClockAlphaFor(int mode) {
+        return mode == MODE_LIGHTS_OUT ? ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
+                : isTransparent(mode) ? ICON_ALPHA_WHEN_TRANSPARENT
+                : mIconAlphaWhenOpaque;
+    }
+
+    private float getBatteryClockAlpha(int mode) {
+        return mode == MODE_LIGHTS_OUT ? ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK
+                : getNonBatteryClockAlphaFor(mode);
+    }
+
+    private boolean isTransparent(int mode) {
+        return mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT;
+    }
+
+    @Override
+    protected void onTransition(int oldMode, int newMode, boolean animate) {
+        super.onTransition(oldMode, newMode, animate);
+        applyMode(newMode, animate);
+    }
+
+    private void applyMode(int mode, boolean animate) {
+        if (mLeftSide == null) return; // pre-init
+        float newAlpha = getNonBatteryClockAlphaFor(mode);
+        float newAlphaBC = getBatteryClockAlpha(mode);
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.cancel();
+        }
+        if (animate) {
+            AnimatorSet anims = new AnimatorSet();
+            anims.playTogether(
+                    animateTransitionTo(mLeftSide, newAlpha),
+                    animateTransitionTo(mStatusIcons, newAlpha),
+                    animateTransitionTo(mSignalCluster, newAlpha),
+                    animateTransitionTo(mBattery, newAlphaBC),
+                    animateTransitionTo(mClock, newAlphaBC)
+                    );
+            if (mode == MODE_LIGHTS_OUT) {
+                anims.setDuration(LIGHTS_OUT_DURATION);
+            }
+            anims.start();
+            mCurrentAnimation = anims;
+        } else {
+            mLeftSide.setAlpha(newAlpha);
+            mStatusIcons.setAlpha(newAlpha);
+            mSignalCluster.setAlpha(newAlpha);
+            mBattery.setAlpha(newAlphaBC);
+            mClock.setAlpha(newAlphaBC);
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index de9f750..d9ac7e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -17,13 +17,12 @@
 package com.android.systemui.statusbar.phone;
 
 import android.app.ActivityManager;
-import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.util.AttributeSet;
 import android.util.EventLog;
-import android.util.Slog;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -46,6 +45,7 @@
     PanelView mLastFullyOpenedPanel = null;
     PanelView mNotificationPanel, mSettingsPanel;
     private boolean mShouldFade;
+    private final PhoneStatusBarTransitions mBarTransitions;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -59,6 +59,11 @@
             mSettingsPanelDragzoneFrac = 0f;
         }
         mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f;
+        mBarTransitions = new PhoneStatusBarTransitions(this);
+    }
+
+    public BarTransitions getBarTransitions() {
+        return mBarTransitions;
     }
 
     public void setBar(PhoneStatusBar bar) {
@@ -74,6 +79,7 @@
         for (PanelView pv : mPanels) {
             pv.setRubberbandingEnabled(!mFullWidthNotifications);
         }
+        mBarTransitions.init();
     }
 
     @Override
@@ -89,7 +95,7 @@
 
     @Override
     public boolean panelsEnabled() {
-        return ((mBar.mDisabled & StatusBarManager.DISABLE_EXPAND) == 0);
+        return mBar.panelsEnabled();
     }
 
     @Override
@@ -114,9 +120,9 @@
 
         if (mFullWidthNotifications) {
             // No double swiping. If either panel is open, nothing else can be pulled down.
-            return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight()) 
-                        + mNotificationPanel.getExpandedHeight() > 0) 
-                    ? null 
+            return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight())
+                        + mNotificationPanel.getExpandedHeight() > 0)
+                    ? null
                     : mNotificationPanel;
         }
 
@@ -128,7 +134,7 @@
         float region = (w * mSettingsPanelDragzoneFrac);
 
         if (DEBUG) {
-            Slog.v(TAG, String.format(
+            Log.v(TAG, String.format(
                 "w=%.1f frac=%.3f region=%.1f min=%.1f x=%.1f w-x=%.1f",
                 w, mSettingsPanelDragzoneFrac, region, mSettingsPanelDragzoneMin, x, (w-x)));
         }
@@ -142,7 +148,7 @@
     @Override
     public void onPanelPeeked() {
         super.onPanelPeeked();
-        mBar.makeExpandedVisible(true);
+        mBar.makeExpandedVisible();
     }
 
     @Override
@@ -152,7 +158,7 @@
         // which is kind of tricky to determine
         mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded());
         if (DEBUG) {
-            Slog.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade);
+            Log.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade);
         }
         mFadingPanel = panel;
     }
@@ -202,7 +208,7 @@
         super.panelExpansionChanged(panel, frac);
 
         if (DEBUG) {
-            Slog.v(TAG, "panelExpansionChanged: f=" + frac);
+            Log.v(TAG, "panelExpansionChanged: f=" + frac);
         }
 
         if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
@@ -236,6 +242,8 @@
             panel.setAlpha(alpha);
         }
 
+        mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
+
         mBar.updateCarrierLabelVisibility(false);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 85bcd8b..36ba4d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -16,23 +16,12 @@
 
 package com.android.systemui.statusbar.phone;
 
-import com.android.internal.view.RotationPolicy;
-import com.android.systemui.R;
-
-import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-
+import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -57,10 +46,12 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.AlarmClock;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Profile;
 import android.provider.Settings;
+import android.security.KeyChain;
 import android.util.Log;
 import android.util.Pair;
 import android.view.LayoutInflater;
@@ -71,8 +62,20 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import java.util.ArrayList;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
 
+import java.util.ArrayList;
 
 /**
  *
@@ -90,6 +93,7 @@
     private ViewGroup mContainerView;
 
     private DisplayManager mDisplayManager;
+    private DevicePolicyManager mDevicePolicyManager;
     private WifiDisplayStatus mWifiDisplayStatus;
     private PhoneStatusBar mStatusBarService;
     private BluetoothState mBluetoothState;
@@ -97,8 +101,11 @@
     private WifiManager mWifiManager;
 
     private BluetoothController mBluetoothController;
+    private RotationLockController mRotationLockController;
+    private LocationController mLocationController;
 
     private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
+    private AsyncTask<Void, Void, Pair<Boolean, Boolean>> mQueryCertTask;
 
     private LevelListDrawable mBatteryLevels;
     private LevelListDrawable mChargingBatteryLevels;
@@ -113,16 +120,10 @@
     private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
             new ArrayList<QuickSettingsTileView>();
 
-    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
-            new RotationPolicy.RotationPolicyListener() {
-        @Override
-        public void onChange() {
-            mModel.onRotationLockChanged();
-        }
-    };
-
     public QuickSettings(Context context, QuickSettingsContainerView container) {
         mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+        mDevicePolicyManager
+            = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mContext = context;
         mContainerView = container;
         mModel = new QuickSettingsModel(context);
@@ -144,6 +145,7 @@
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
         mContext.registerReceiver(mReceiver, filter);
 
         IntentFilter profileFilter = new IntentFilter();
@@ -170,19 +172,42 @@
     }
 
     void setup(NetworkController networkController, BluetoothController bluetoothController,
-            BatteryController batteryController, LocationController locationController) {
+            BatteryController batteryController, LocationController locationController,
+            RotationLockController rotationLockController) {
         mBluetoothController = bluetoothController;
+        mRotationLockController = rotationLockController;
+        mLocationController = locationController;
 
         setupQuickSettings();
         updateWifiDisplayStatus();
         updateResources();
+        applyLocationEnabledStatus();
 
         networkController.addNetworkSignalChangedCallback(mModel);
         bluetoothController.addStateChangedCallback(mModel);
         batteryController.addStateChangedCallback(mModel);
-        locationController.addStateChangedCallback(mModel);
-        RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
-                UserHandle.USER_ALL);
+        locationController.addSettingsChangedCallback(mModel);
+        rotationLockController.addRotationLockControllerCallback(mModel);
+    }
+
+    private void queryForSslCaCerts() {
+        mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
+            @Override
+            protected Pair<Boolean, Boolean> doInBackground(Void... params) {
+                boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
+                boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
+
+                return Pair.create(hasCert, isManaged);
+            }
+            @Override
+            protected void onPostExecute(Pair<Boolean, Boolean> result) {
+                super.onPostExecute(result);
+                boolean hasCert = result.first;
+                boolean isManaged = result.second;
+                mModel.setSslCaCertWarningTileInfo(hasCert, isManaged);
+            }
+        };
+        mQueryCertTask.execute();
     }
 
     private void queryForUserInformation() {
@@ -258,6 +283,7 @@
         addTemporaryTiles(mContainerView, inflater);
 
         queryForUserInformation();
+        queryForSslCaCerts();
         mTilesSetUp = true;
     }
 
@@ -377,8 +403,9 @@
 
     private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
         // Wi-fi
-        final QuickSettingsBasicTile wifiTile
-                = new QuickSettingsBasicTile(mContext);
+        final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
         wifiTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -409,12 +436,15 @@
                     return true;
                 }} );
         }
-        mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
+        mModel.addWifiTile(wifiTile, new NetworkActivityCallback() {
             @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
+            public void refreshView(QuickSettingsTileView view, State state) {
                 WifiState wifiState = (WifiState) state;
-                wifiTile.setImageResource(wifiState.iconId);
-                wifiTile.setText(wifiState.label);
+                ImageView iv = (ImageView) view.findViewById(R.id.image);
+                iv.setImageResource(wifiState.iconId);
+                setActivity(view, wifiState);
+                TextView tv = (TextView) view.findViewById(R.id.text);
+                tv.setText(wifiState.label);
                 wifiTile.setContentDescription(mContext.getString(
                         R.string.accessibility_quick_settings_wifi,
                         wifiState.signalContentDescription,
@@ -438,7 +468,7 @@
                     startSettingsActivity(intent);
                 }
             });
-            mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() {
+            mModel.addRSSITile(rssiTile, new NetworkActivityCallback() {
                 @Override
                 public void refreshView(QuickSettingsTileView view, State state) {
                     RSSIState rssiState = (RSSIState) state;
@@ -454,6 +484,8 @@
                     } else {
                         iov.setImageDrawable(null);
                     }
+                    setActivity(view, rssiState);
+
                     tv.setText(state.label);
                     view.setContentDescription(mContext.getResources().getString(
                             R.string.accessibility_quick_settings_mobile,
@@ -471,18 +503,36 @@
                     = new QuickSettingsBasicTile(mContext);
             rotationLockTile.setOnClickListener(new View.OnClickListener() {
                 @Override
-                public void onClick(View v) {
-                    boolean locked = RotationPolicy.isRotationLocked(mContext);
-                    RotationPolicy.setRotationLock(mContext, !locked);
+                public void onClick(View view) {
+                    final boolean locked = mRotationLockController.isRotationLocked();
+                    mRotationLockController.setRotationLocked(!locked);
                 }
             });
-            mModel.addRotationLockTile(rotationLockTile,
-                    new QuickSettingsModel.BasicRefreshCallback(rotationLockTile));
+            mModel.addRotationLockTile(rotationLockTile, mRotationLockController,
+                    new QuickSettingsModel.RefreshCallback() {
+                        @Override
+                        public void refreshView(QuickSettingsTileView view, State state) {
+                            QuickSettingsModel.RotationLockState rotationLockState =
+                                    (QuickSettingsModel.RotationLockState) state;
+                            view.setVisibility(rotationLockState.visible
+                                    ? View.VISIBLE : View.GONE);
+                            if (state.iconId != 0) {
+                                // needed to flush any cached IDs
+                                rotationLockTile.setImageDrawable(null);
+                                rotationLockTile.setImageResource(state.iconId);
+                            }
+                            if (state.label != null) {
+                                rotationLockTile.setText(state.label);
+                            }
+                        }
+                    });
             parent.addView(rotationLockTile);
         }
 
         // Battery
-        final QuickSettingsBasicTile batteryTile = new QuickSettingsBasicTile(mContext);
+        final QuickSettingsTileView batteryTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
         batteryTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -494,9 +544,6 @@
             public void refreshView(QuickSettingsTileView unused, State state) {
                 QuickSettingsModel.BatteryState batteryState =
                         (QuickSettingsModel.BatteryState) state;
-                Drawable d = batteryState.pluggedIn
-                        ? mChargingBatteryLevels
-                        : mBatteryLevels;
                 String t;
                 if (batteryState.batteryLevel == 100) {
                     t = mContext.getString(R.string.quick_settings_battery_charged_label);
@@ -507,9 +554,7 @@
                         : mContext.getString(R.string.status_bar_settings_battery_meter_format,
                                 batteryState.batteryLevel);
                 }
-                batteryTile.setImageDrawable(d);
-                batteryTile.getImageView().setImageLevel(batteryState.batteryLevel);
-                batteryTile.setText(t);
+                ((TextView)batteryTile.findViewById(R.id.text)).setText(t);
                 batteryTile.setContentDescription(
                         mContext.getString(R.string.accessibility_quick_settings_battery, t));
             }
@@ -587,6 +632,35 @@
             parent.addView(bluetoothTile);
         }
 
+        // Location
+        final QuickSettingsBasicTile locationTile
+                = new QuickSettingsBasicTile(mContext);
+        locationTile.setImageResource(R.drawable.ic_qs_location_on);
+        locationTile.setTextResource(R.string.quick_settings_location_label);
+        locationTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+            }
+        });
+        if (LONG_PRESS_TOGGLES) {
+            locationTile.setOnLongClickListener(new View.OnLongClickListener() {
+                @Override
+                public boolean onLongClick(View v) {
+                    boolean newLocationEnabledState = !mLocationController.isLocationEnabled();
+                    if (mLocationController.setLocationEnabled(newLocationEnabledState)
+                            && newLocationEnabledState) {
+                        // If we've successfully switched from location off to on, close the
+                        // notifications tray to show the network location provider consent dialog.
+                        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+                        mContext.sendBroadcast(closeDialog);
+                    }
+                    return true; // Consume click
+                }} );
+        }
+        mModel.addLocationTile(locationTile,
+                new QuickSettingsModel.BasicRefreshCallback(locationTile));
+        parent.addView(locationTile);
     }
 
     private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
@@ -597,12 +671,7 @@
         alarmTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                // TODO: Jump into the alarm application
-                Intent intent = new Intent();
-                intent.setComponent(new ComponentName(
-                        "com.google.android.deskclock",
-                        "com.android.deskclock.AlarmClock"));
-                startSettingsActivity(intent);
+                startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
             }
         });
         mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
@@ -616,22 +685,6 @@
         });
         parent.addView(alarmTile);
 
-        // Location
-        final QuickSettingsBasicTile locationTile
-                = new QuickSettingsBasicTile(mContext);
-        locationTile.setImageResource(R.drawable.ic_qs_location);
-        locationTile.setTextResource(R.string.quick_settings_location_label);
-        locationTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
-            }
-        });
-        mModel.addLocationTile(locationTile,
-                new QuickSettingsModel.BasicRefreshCallback(locationTile)
-                        .setShowWhenEnabled(true));
-        parent.addView(locationTile);
-
         // Wifi Display
         QuickSettingsBasicTile wifiDisplayTile
                 = new QuickSettingsBasicTile(mContext);
@@ -704,6 +757,26 @@
         });
         parent.addView(imeTile);
         */
+
+        // SSL CA Cert Warning.
+        final QuickSettingsBasicTile sslCaCertWarningTile =
+                new QuickSettingsBasicTile(mContext, null, R.layout.quick_settings_tile_monitoring);
+        sslCaCertWarningTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                collapsePanels();
+                startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
+            }
+        });
+
+        sslCaCertWarningTile.setImageResource(
+                com.android.internal.R.drawable.indicator_input_error);
+        sslCaCertWarningTile.setTextResource(R.string.ssl_ca_cert_warning);
+
+        mModel.addSslCaCertWarningTile(sslCaCertWarningTile,
+                new QuickSettingsModel.BasicRefreshCallback(sslCaCertWarningTile)
+                        .setShowWhenEnabled(true));
+        parent.addView(sslCaCertWarningTile);
     }
 
     void updateResources() {
@@ -773,6 +846,10 @@
         mModel.onBluetoothStateChange(mBluetoothState);
     }
 
+    private void applyLocationEnabledStatus() {
+        mModel.onLocationSettingsChanged(mLocationController.isLocationEnabled());
+    }
+
     void reloadUserInfo() {
         if (mUserInfoTask != null) {
             mUserInfoTask.cancel(false);
@@ -780,6 +857,7 @@
         }
         if (mTilesSetUp) {
             queryForUserInformation();
+            queryForSslCaCerts();
         }
     }
 
@@ -808,6 +886,8 @@
                 if (mUseDefaultAvatar) {
                     queryForUserInformation();
                 }
+            } else if (KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
+                queryForSslCaCerts();
             }
         }
     };
@@ -832,4 +912,25 @@
 
         }
     };
+
+    private abstract static class NetworkActivityCallback
+            implements QuickSettingsModel.RefreshCallback {
+        private final long mDefaultDuration = new ValueAnimator().getDuration();
+        private final long mShortDuration = mDefaultDuration / 3;
+
+        public void setActivity(View view, ActivityState state) {
+            setVisibility(view.findViewById(R.id.activity_in), state.activityIn);
+            setVisibility(view.findViewById(R.id.activity_out), state.activityOut);
+        }
+
+        private void setVisibility(View view, boolean visible) {
+            final float newAlpha = visible ? 1 : 0;
+            if (view.getAlpha() != newAlpha) {
+                view.animate()
+                    .setDuration(visible ? mShortDuration : mDefaultDuration)
+                    .alpha(newAlpha)
+                    .start();
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
index 94b2fc7..099780c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import com.android.systemui.R;
-
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -26,6 +24,8 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.systemui.R;
+
 class QuickSettingsBasicTile extends QuickSettingsTileView {
     private final TextView mTextView;
     private final ImageView mImageView;
@@ -35,6 +35,10 @@
     }
 
     public QuickSettingsBasicTile(Context context, AttributeSet attrs) {
+        this(context, attrs, R.layout.quick_settings_tile_basic);
+    }
+
+    public QuickSettingsBasicTile(Context context, AttributeSet attrs, int layoutId) {
         super(context, attrs);
 
         setLayoutParams(new FrameLayout.LayoutParams(
@@ -42,8 +46,7 @@
             context.getResources().getDimensionPixelSize(R.dimen.quick_settings_cell_height)
         ));
         setBackgroundResource(R.drawable.qs_tile_background);
-        addView(LayoutInflater.from(context).inflate(
-                R.layout.quick_settings_tile_basic, null),
+        addView(LayoutInflater.from(context).inflate(layoutId, null),
                 new FrameLayout.LayoutParams(
                         FrameLayout.LayoutParams.MATCH_PARENT,
                         FrameLayout.LayoutParams.MATCH_PARENT));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 38c46c4..9d0418d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -39,22 +39,23 @@
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.internal.view.RotationPolicy;
 import com.android.systemui.R;
-import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback;
+import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
 
 import java.util.List;
 
-
 class QuickSettingsModel implements BluetoothStateChangeCallback,
         NetworkSignalChangedCallback,
         BatteryStateChangeCallback,
-        LocationGpsStateChangeCallback,
-        BrightnessStateChangeCallback {
+        BrightnessStateChangeCallback,
+        RotationLockControllerCallback,
+        LocationSettingsChangeCallback {
 
     // Sett InputMethoManagerService
     private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
@@ -69,13 +70,17 @@
         int batteryLevel;
         boolean pluggedIn;
     }
-    static class RSSIState extends State {
+    static class ActivityState extends State {
+        boolean activityIn;
+        boolean activityOut;
+    }
+    static class RSSIState extends ActivityState {
         int signalIconId;
         String signalContentDescription;
         int dataTypeIconId;
         String dataContentDescription;
     }
-    static class WifiState extends State {
+    static class WifiState extends ActivityState {
         String signalContentDescription;
         boolean connected;
     }
@@ -89,6 +94,9 @@
         boolean connected = false;
         String stateContentDescription;
     }
+    public static class RotationLockState extends State {
+        boolean visible = false;
+    }
 
     /** The callback to update a given tile. */
     interface RefreshCallback {
@@ -245,7 +253,7 @@
 
     private QuickSettingsTileView mRotationLockTile;
     private RefreshCallback mRotationLockCallback;
-    private State mRotationLockState = new State();
+    private RotationLockState mRotationLockState = new RotationLockState();
 
     private QuickSettingsTileView mBrightnessTile;
     private RefreshCallback mBrightnessCallback;
@@ -259,6 +267,12 @@
     private RefreshCallback mSettingsCallback;
     private State mSettingsState = new State();
 
+    private QuickSettingsTileView mSslCaCertWarningTile;
+    private RefreshCallback mSslCaCertWarningCallback;
+    private State mSslCaCertWarningState = new State();
+
+    private RotationLockController mRotationLockController;
+
     public QuickSettingsModel(Context context) {
         mContext = context;
         mHandler = new Handler();
@@ -413,13 +427,14 @@
         if (string == null) return null;
         final int length = string.length();
         if (string.endsWith(".")) {
-            string.substring(0, length - 1);
+            return string.substring(0, length - 1);
         }
         return string;
     }
     // NetworkSignalChanged callback
     @Override
     public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+            boolean activityIn, boolean activityOut,
             String wifiSignalContentDescription, String enabledDesc) {
         // TODO: If view is in awaiting state, disable
         Resources r = mContext.getResources();
@@ -428,6 +443,8 @@
         boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
         mWifiState.enabled = enabled;
         mWifiState.connected = wifiConnected;
+        mWifiState.activityIn = enabled && activityIn;
+        mWifiState.activityOut = enabled && activityOut;
         if (wifiConnected) {
             mWifiState.iconId = wifiSignalIconId;
             mWifiState.label = removeDoubleQuotes(enabledDesc);
@@ -458,7 +475,8 @@
     @Override
     public void onMobileDataSignalChanged(
             boolean enabled, int mobileSignalIconId, String signalContentDescription,
-            int dataTypeIconId, String dataContentDescription, String enabledDesc) {
+            int dataTypeIconId, boolean activityIn, boolean activityOut,
+            String dataContentDescription,String enabledDesc) {
         if (deviceHasMobileData()) {
             // TODO: If view is in awaiting state, disable
             Resources r = mContext.getResources();
@@ -471,6 +489,8 @@
             mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
                     ? dataTypeIconId
                     : 0;
+            mRSSIState.activityIn = enabled && activityIn;
+            mRSSIState.activityOut = enabled && activityOut;
             mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
                     ? dataContentDescription
                     : r.getString(R.string.accessibility_no_data);
@@ -551,11 +571,17 @@
         mLocationCallback = cb;
         mLocationCallback.refreshView(mLocationTile, mLocationState);
     }
-    // LocationController callback
+
     @Override
-    public void onLocationGpsStateChanged(boolean inUse, String description) {
-        mLocationState.enabled = inUse;
-        mLocationState.label = description;
+    public void onLocationSettingsChanged(boolean locationEnabled) {
+        int textResId = locationEnabled ? R.string.quick_settings_location_label
+                : R.string.quick_settings_location_off_label;
+        String label = mContext.getText(textResId).toString();
+        int locationIconId = locationEnabled
+                ? R.drawable.ic_qs_location_on : R.drawable.ic_qs_location_off;
+        mLocationState.enabled = locationEnabled;
+        mLocationState.label = label;
+        mLocationState.iconId = locationIconId;
         mLocationCallback.refreshView(mLocationTile, mLocationState);
     }
 
@@ -574,7 +600,7 @@
         } catch (SettingNotFoundException e) {
         }
 
-        mBugreportState.enabled = enabled;
+        mBugreportState.enabled = enabled && mUserTracker.isCurrentUserOwner();
         mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
     }
 
@@ -681,25 +707,29 @@
     }
 
     // Rotation lock
-    void addRotationLockTile(QuickSettingsTileView view, RefreshCallback cb) {
+    void addRotationLockTile(QuickSettingsTileView view,
+            RotationLockController rotationLockController,
+            RefreshCallback cb) {
         mRotationLockTile = view;
         mRotationLockCallback = cb;
+        mRotationLockController = rotationLockController;
         onRotationLockChanged();
     }
     void onRotationLockChanged() {
-        boolean locked = RotationPolicy.isRotationLocked(mContext);
-        mRotationLockState.enabled = locked;
-        mRotationLockState.iconId = locked
+        onRotationLockStateChanged(mRotationLockController.isRotationLocked(),
+                mRotationLockController.isRotationLockAffordanceVisible());
+    }
+    @Override
+    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+        mRotationLockState.visible = affordanceVisible;
+        mRotationLockState.enabled = rotationLocked;
+        mRotationLockState.iconId = rotationLocked
                 ? R.drawable.ic_qs_rotation_locked
                 : R.drawable.ic_qs_auto_rotate;
-        mRotationLockState.label = locked
+        mRotationLockState.label = rotationLocked
                 ? mContext.getString(R.string.quick_settings_rotation_locked_label)
                 : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-
-        // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
-        if (mRotationLockTile != null && mRotationLockCallback != null) {
-            mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
-        }
+        mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
     }
     void refreshRotationLockTile() {
         if (mRotationLockTile != null) {
@@ -731,4 +761,23 @@
     void refreshBrightnessTile() {
         onBrightnessLevelChanged();
     }
+
+    // SSL CA Cert warning.
+    public void addSslCaCertWarningTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mSslCaCertWarningTile = view;
+        mSslCaCertWarningCallback = cb;
+        // Set a sane default while we wait for the AsyncTask to finish (no cert).
+        setSslCaCertWarningTileInfo(false, true);
+    }
+    public void setSslCaCertWarningTileInfo(boolean hasCert, boolean isManaged) {
+        Resources r = mContext.getResources();
+        mSslCaCertWarningState.enabled = hasCert;
+        if (isManaged) {
+            mSslCaCertWarningState.iconId = R.drawable.ic_qs_certificate_info;
+        } else {
+            mSslCaCertWarningState.iconId = android.R.drawable.stat_notify_error;
+        }
+        mSslCaCertWarningState.label = r.getString(R.string.ssl_ca_cert_warning);
+        mSslCaCertWarningCallback.refreshView(mSslCaCertWarningTile, mSslCaCertWarningState);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
index 33335631..c10a0d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
@@ -16,28 +16,24 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.LayoutTransition;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.EventLog;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
 
 public class SettingsPanelView extends PanelView {
     public static final boolean DEBUG_GESTURES = true;
@@ -85,10 +81,11 @@
     }
 
     public void setup(NetworkController networkController, BluetoothController bluetoothController,
-            BatteryController batteryController, LocationController locationController) {
+            BatteryController batteryController, LocationController locationController,
+            RotationLockController rotationLockController) {
         if (mQS != null) {
             mQS.setup(networkController, bluetoothController, batteryController,
-                    locationController);
+                    locationController, rotationLockController);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 5620e1b..e77b420 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -16,18 +16,17 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.StatusBarManager;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.widget.FrameLayout;
 import android.widget.ScrollView;
-import android.widget.TextSwitcher;
 
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
@@ -113,6 +112,10 @@
         if (!handled) {
             handled = super.onTouchEvent(ev);
         }
+        final int action = ev.getAction();
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
+        }
         return handled;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
index f3f6a80..a6ce288 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
@@ -16,31 +16,29 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.service.notification.StatusBarNotification;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.text.StaticLayout;
+import android.service.notification.StatusBarNotification;
 import android.text.Layout.Alignment;
+import android.text.StaticLayout;
 import android.text.TextPaint;
 import android.view.View;
 import android.view.animation.AnimationUtils;
+import android.widget.ImageSwitcher;
 import android.widget.TextSwitcher;
 import android.widget.TextView;
-import android.widget.ImageSwitcher;
-
-import java.util.ArrayList;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.CharSequences;
-
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBarIconView;
 
+import java.util.ArrayList;
+
 public abstract class Ticker {
     private static final int TICKER_SEGMENT_DELAY = 3000;
-    
+
     private Context mContext;
     private Handler mHandler = new Handler();
     private ArrayList<Segment> mSegments = new ArrayList();
@@ -192,7 +190,7 @@
             if (n.getPackageName().equals(seg.notification.getPackageName())
                     && n.getNotification().icon == seg.notification.getNotification().icon
                     && n.getNotification().iconLevel == seg.notification.getNotification().iconLevel
-                    && CharSequences.equals(seg.notification.getNotification().tickerText,
+                    && charSequencesEqual(seg.notification.getNotification().tickerText,
                         n.getNotification().tickerText)) {
                 return;
             }
@@ -218,20 +216,34 @@
         if (initialCount == 0 && mSegments.size() > 0) {
             Segment seg = mSegments.get(0);
             seg.first = false;
-            
+
             mIconSwitcher.setAnimateFirstView(false);
             mIconSwitcher.reset();
             mIconSwitcher.setImageDrawable(seg.icon);
-            
+
             mTextSwitcher.setAnimateFirstView(false);
             mTextSwitcher.reset();
             mTextSwitcher.setText(seg.getText());
-            
+
             tickerStarting();
             scheduleAdvance();
         }
     }
 
+    private static boolean charSequencesEqual(CharSequence a, CharSequence b) {
+        if (a.length() != b.length()) {
+            return false;
+        }
+
+        int length = a.length();
+        for (int i = 0; i < length; i++) {
+            if (a.charAt(i) != b.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public void removeEntry(StatusBarNotification n) {
         for (int i=mSegments.size()-1; i>=0; i--) {
             Segment seg = mSegments.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingPatternView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingPatternView.java
deleted file mode 100644
index d2ed5ff..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingPatternView.java
+++ /dev/null
@@ -1,70 +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 com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Paint;
-import android.graphics.Canvas;
-
-public class TrackingPatternView extends View {
-    private Bitmap mTexture;
-    private Paint mPaint;
-    private int mTextureWidth;
-    private int mTextureHeight;
-    
-    public TrackingPatternView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mTexture = BitmapFactory.decodeResource(getResources(), 
-                com.android.internal.R.drawable.status_bar_background);
-        mTextureWidth = mTexture.getWidth();
-        mTextureHeight = mTexture.getHeight();
-
-        mPaint = new Paint();
-        mPaint.setDither(false);
-    }
-
-    @Override
-    public void onDraw(Canvas canvas) {
-        final Bitmap texture = mTexture;
-        final Paint paint = mPaint;
-
-        final int width = getWidth();
-        final int height = getHeight();
-
-        final int textureWidth = mTextureWidth;
-        final int textureHeight = mTextureHeight;
-
-        int x = 0;
-        int y;
-
-        while (x < width) {
-            y = 0;
-            while (y < height) {
-                canvas.drawBitmap(texture, x, y, paint);
-                y += textureHeight;
-            }
-            x += textureWidth;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
deleted file mode 100644
index 3c8276d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.policy;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Slog;
-import android.widget.CompoundButton;
-
-public class AirplaneModeController extends BroadcastReceiver
-        implements CompoundButton.OnCheckedChangeListener {
-    private static final String TAG = "StatusBar.AirplaneModeController";
-
-    private Context mContext;
-    private CompoundButton mCheckBox;
-
-    private boolean mAirplaneMode;
-
-    public AirplaneModeController(Context context, CompoundButton checkbox) {
-        mContext = context;
-        mAirplaneMode = getAirplaneMode();
-        mCheckBox = checkbox;
-        checkbox.setChecked(mAirplaneMode);
-        checkbox.setOnCheckedChangeListener(this);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        context.registerReceiver(this, filter);
-
-    }
-
-    public void release() {
-        mContext.unregisterReceiver(this);
-    }
-
-    public void onCheckedChanged(CompoundButton view, boolean checked) {
-        if (checked != mAirplaneMode) {
-            mAirplaneMode = checked;
-            unsafe(checked);
-        }
-    }
-
-    public void onReceive(Context context, Intent intent) {
-        if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
-            final boolean enabled = intent.getBooleanExtra("state", false);
-            if (enabled != mAirplaneMode) {
-                mAirplaneMode = enabled;
-                mCheckBox.setChecked(enabled);
-            }
-        }
-    }
-
-    private boolean getAirplaneMode() {
-        ContentResolver cr = mContext.getContentResolver();
-        return 0 != Settings.Global.getInt(cr, Settings.Global.AIRPLANE_MODE_ON, 0);
-    }
-
-    // TODO: Fix this racy API by adding something better to TelephonyManager or
-    // ConnectivityService.
-    private void unsafe(final boolean enabled) {
-        AsyncTask.execute(new Runnable() {
-                public void run() {
-                    Settings.Global.putInt(
-                            mContext.getContentResolver(),
-                            Settings.Global.AIRPLANE_MODE_ON,
-                            enabled ? 1 : 0);
-                    Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                    intent.putExtra("state", enabled);
-                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-                }
-            });
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
deleted file mode 100644
index 7d58032..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.policy;
-
-import com.android.internal.view.RotationPolicy;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.widget.CompoundButton;
-
-public final class AutoRotateController implements CompoundButton.OnCheckedChangeListener {
-    private final Context mContext;
-    private final CompoundButton mCheckbox;
-    private final RotationLockCallbacks mCallbacks;
-
-    private boolean mAutoRotation;
-
-    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
-            new RotationPolicy.RotationPolicyListener() {
-        @Override
-        public void onChange() {
-            updateState();
-        }
-    };
-
-    public AutoRotateController(Context context, CompoundButton checkbox,
-            RotationLockCallbacks callbacks) {
-        mContext = context;
-        mCheckbox = checkbox;
-        mCallbacks = callbacks;
-
-        mCheckbox.setOnCheckedChangeListener(this);
-
-        RotationPolicy.registerRotationPolicyListener(context, mRotationPolicyListener,
-                UserHandle.USER_ALL);
-        updateState();
-    }
-
-    public void onCheckedChanged(CompoundButton view, boolean checked) {
-        if (checked != mAutoRotation) {
-            mAutoRotation = checked;
-            RotationPolicy.setRotationLock(mContext, !checked);
-        }
-    }
-
-    public void release() {
-        RotationPolicy.unregisterRotationPolicyListener(mContext,
-                mRotationPolicyListener);
-    }
-
-    private void updateState() {
-        mAutoRotation = !RotationPolicy.isRotationLocked(mContext);
-        mCheckbox.setChecked(mAutoRotation);
-
-        boolean visible = RotationPolicy.isRotationLockToggleVisible(mContext);
-        mCallbacks.setRotationLockControlVisibility(visible);
-        mCheckbox.setEnabled(visible);
-    }
-
-    public interface RotationLockCallbacks {
-        void setRotationLockControlVisibility(boolean show);
-    }
-}
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 716341f..575b44e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -16,20 +16,18 @@
 
 package com.android.systemui.statusbar.policy;
 
-import java.util.ArrayList;
-
-import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.BatteryManager;
-import android.util.Slog;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.systemui.R;
 
+import java.util.ArrayList;
+
 public class BatteryController extends BroadcastReceiver {
     private static final String TAG = "StatusBar.BatteryController";
 
@@ -73,7 +71,7 @@
 
             boolean plugged = false;
             switch (status) {
-                case BatteryManager.BATTERY_STATUS_CHARGING: 
+                case BatteryManager.BATTERY_STATUS_CHARGING:
                 case BatteryManager.BATTERY_STATUS_FULL:
                     plugged = true;
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index fece57e..0e53f0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -23,10 +23,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -35,11 +31,6 @@
 public class BluetoothController extends BroadcastReceiver {
     private static final String TAG = "StatusBar.BluetoothController";
 
-    private Context mContext;
-    private ArrayList<ImageView> mIconViews = new ArrayList<ImageView>();
-
-    private int mIconId = R.drawable.stat_sys_data_bluetooth;
-    private int mContentDescriptionId = 0;
     private boolean mEnabled = false;
 
     private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
@@ -48,7 +39,6 @@
             new ArrayList<BluetoothStateChangeCallback>();
 
     public BluetoothController(Context context) {
-        mContext = context;
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -59,16 +49,11 @@
         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
             handleAdapterStateChange(adapter.getState());
-            handleConnectionStateChange(adapter.getConnectionState());
         }
-        refreshViews();
+        fireCallbacks();
         updateBondedBluetoothDevices();
     }
 
-    public void addIconView(ImageView v) {
-        mIconViews.add(v);
-    }
-
     public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
         mChangeCallbacks.add(cb);
     }
@@ -84,14 +69,8 @@
         if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
             handleAdapterStateChange(
                     intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
-        } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
-            handleConnectionStateChange(
-                    intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
-                        BluetoothAdapter.STATE_DISCONNECTED));
-        } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
-            // Fall through and update bonded devices and refresh view
         }
-        refreshViews();
+        fireCallbacks();
         updateBondedBluetoothDevices();
     }
 
@@ -111,31 +90,11 @@
         }
     }
 
-    public void handleAdapterStateChange(int adapterState) {
+    private void handleAdapterStateChange(int adapterState) {
         mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
     }
 
-    public void handleConnectionStateChange(int connectionState) {
-        final boolean connected = (connectionState == BluetoothAdapter.STATE_CONNECTED);
-        if (connected) {
-            mIconId = R.drawable.stat_sys_data_bluetooth_connected;
-            mContentDescriptionId = R.string.accessibility_bluetooth_connected;
-        } else {
-            mIconId = R.drawable.stat_sys_data_bluetooth;
-            mContentDescriptionId = R.string.accessibility_bluetooth_disconnected;
-        }
-    }
-
-    public void refreshViews() {
-        int N = mIconViews.size();
-        for (int i=0; i<N; i++) {
-            ImageView v = mIconViews.get(i);
-            v.setImageResource(mIconId);
-            v.setVisibility(mEnabled ? View.VISIBLE : View.GONE);
-            v.setContentDescription((mContentDescriptionId == 0)
-                    ? null
-                    : mContext.getString(mContentDescriptionId));
-        }
+    private void fireCallbacks() {
         for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
             cb.onBluetoothStateChange(mEnabled);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index bff6cda..8ced1c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -20,24 +20,17 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.format.DateFormat;
 import android.text.style.CharacterStyle;
-import android.text.style.ForegroundColorSpan;
 import android.text.style.RelativeSizeSpan;
-import android.text.style.RelativeSizeSpan;
-import android.text.style.StyleSpan;
 import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
 import android.widget.TextView;
 
+import com.android.systemui.DemoMode;
+
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Locale;
@@ -45,12 +38,10 @@
 
 import libcore.icu.LocaleData;
 
-import com.android.internal.R;
-
 /**
  * Digital clock for the status bar.
  */
-public class Clock extends TextView {
+public class Clock extends TextView implements DemoMode {
     private boolean mAttached;
     private Calendar mCalendar;
     private String mClockFormatString;
@@ -133,6 +124,7 @@
     };
 
     final void updateClock() {
+        if (mDemoMode) return;
         mCalendar.setTimeInMillis(System.currentTimeMillis());
         setText(getSmallTime());
     }
@@ -204,9 +196,33 @@
                 return formatted;
             }
         }
- 
+
         return result;
 
     }
+
+    private boolean mDemoMode;
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            updateClock();
+        } else if (mDemoMode && command.equals(COMMAND_CLOCK)) {
+            String millis = args.getString("millis");
+            String hhmm = args.getString("hhmm");
+            if (millis != null) {
+                mCalendar.setTimeInMillis(Long.parseLong(millis));
+            } else if (hhmm != null && hhmm.length() == 4) {
+                int hh = Integer.parseInt(hhmm.substring(0, 2));
+                int mm = Integer.parseInt(hhmm.substring(2));
+                mCalendar.set(Calendar.HOUR, hh);
+                mCalendar.set(Calendar.MINUTE, mm);
+            }
+            setText(getSmallTime());
+        }
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
deleted file mode 100644
index 2d951c2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
+++ /dev/null
@@ -1,61 +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 com.android.systemui.statusbar.policy;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.RemoteException;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-public class CompatModeButton extends ImageView {
-    private static final boolean DEBUG = false;
-    private static final String TAG = "StatusBar.CompatModeButton";
-
-    private ActivityManager mAM;
-
-    public CompatModeButton(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CompatModeButton(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs);
-
-        setClickable(true);
-
-        mAM = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-
-        refresh();
-    }
-
-    public void refresh() {
-        int mode = mAM.getFrontActivityScreenCompatMode();
-        if (mode == ActivityManager.COMPAT_MODE_UNKNOWN) {
-            // If in an unknown state, don't change.
-            return;
-        }
-        final boolean vis = (mode != ActivityManager.COMPAT_MODE_NEVER
-                          && mode != ActivityManager.COMPAT_MODE_ALWAYS);
-        if (DEBUG) Slog.d(TAG, "compat mode is " + mode + "; icon will " + (vis ? "show" : "hide"));
-        setVisibility(vis ? View.VISIBLE : View.GONE);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java
deleted file mode 100644
index 225ebc1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-
-public class CurrentUserTracker extends BroadcastReceiver {
-
-    private int mCurrentUserId;
-
-    public CurrentUserTracker(Context context) {
-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        context.registerReceiver(this, filter);
-        mCurrentUserId = ActivityManager.getCurrentUser();
-    }
-
-    public int getCurrentUserId() {
-        return mCurrentUserId;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-            mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 27a3a15..16e2e07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
 import android.widget.TextView;
@@ -36,9 +37,10 @@
 public class DateView extends TextView {
     private static final String TAG = "DateView";
 
-    private boolean mAttachedToWindow;
-    private boolean mWindowVisible;
-    private boolean mUpdating;
+    private final Date mCurrentTime = new Date();
+
+    private SimpleDateFormat mDateFormat;
+    private String mLastText;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -48,6 +50,10 @@
                     || Intent.ACTION_TIME_CHANGED.equals(action)
                     || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
                     || Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+                if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+                    // need to get a fresh date format
+                    mDateFormat = null;
+                }
                 updateClock();
             }
         }
@@ -60,75 +66,39 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mAttachedToWindow = true;
-        setUpdates();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_TIME_TICK);
+        filter.addAction(Intent.ACTION_TIME_CHANGED);
+        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
+        mContext.registerReceiver(mIntentReceiver, filter, null, null);
+
+        updateClock();
     }
-    
+
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mAttachedToWindow = false;
-        setUpdates();
-    }
 
-    @Override
-    protected void onWindowVisibilityChanged(int visibility) {
-        super.onWindowVisibilityChanged(visibility);
-        mWindowVisible = visibility == VISIBLE;
-        setUpdates();
-    }
-
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-        setUpdates();
-    }
-
-    @Override
-    protected int getSuggestedMinimumWidth() {
-        // makes the large background bitmap not force us to full width
-        return 0;
+        mDateFormat = null; // reload the locale next time
+        mContext.unregisterReceiver(mIntentReceiver);
     }
 
     protected void updateClock() {
-        final String dateFormat = getContext().getString(R.string.system_ui_date_pattern);
-        final Locale l = Locale.getDefault();
-        String fmt = ICU.getBestDateTimePattern(dateFormat, l.toString());
-        SimpleDateFormat sdf = new SimpleDateFormat(fmt, l);
-        setText(sdf.format(new Date()));
-    }
-
-    private boolean isVisible() {
-        View v = this;
-        while (true) {
-            if (v.getVisibility() != VISIBLE) {
-                return false;
-            }
-            final ViewParent parent = v.getParent();
-            if (parent instanceof View) {
-                v = (View)parent;
-            } else {
-                return true;
-            }
+        if (mDateFormat == null) {
+            final String dateFormat = getContext().getString(R.string.system_ui_date_pattern);
+            final Locale l = Locale.getDefault();
+            final String fmt = ICU.getBestDateTimePattern(dateFormat, l.toString());
+            mDateFormat = new SimpleDateFormat(fmt, l);
         }
-    }
 
-    private void setUpdates() {
-        boolean update = mAttachedToWindow && mWindowVisible && isVisible();
-        if (update != mUpdating) {
-            mUpdating = update;
-            if (update) {
-                // Register for Intent broadcasts for the clock and battery
-                IntentFilter filter = new IntentFilter();
-                filter.addAction(Intent.ACTION_TIME_TICK);
-                filter.addAction(Intent.ACTION_TIME_CHANGED);
-                filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-                filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-                mContext.registerReceiver(mIntentReceiver, filter, null, null);
-                updateClock();
-            } else {
-                mContext.unregisterReceiver(mIntentReceiver);
-            }
+        mCurrentTime.setTime(System.currentTimeMillis());
+
+        final String text = mDateFormat.format(mCurrentTime);
+        if (!text.equals(mLastText)) {
+            setText(text);
+            mLastText = text;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 6eb88be..dca5e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -22,7 +22,7 @@
 import android.graphics.Canvas;
 import android.os.SystemClock;
 import android.util.AttributeSet;
-import android.util.Slog;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -75,7 +75,7 @@
         mVertical = (index == VERTICAL);
 
         if (DEBUG)
-            Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
+            Log.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
                     + (mVertical ? " vertical" : " horizontal"));
 
         setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
@@ -106,7 +106,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (DEBUG) {
-            Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
+            Log.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
         }
 
         final int action = event.getAction();
@@ -114,12 +114,12 @@
             poke(event);
         } else if (action == MotionEvent.ACTION_DOWN) {
             if (DEBUG) {
-                Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
+                Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
             }
             int size = (int) getSize(event.getEventTime());
             if ((mVertical && event.getX() < size) || event.getY() < size) {
                 if (CHATTY) {
-                    Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
+                    Log.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
                 }
                 if (mShouldFlash) {
                     post(mDebugFlash);
@@ -134,7 +134,7 @@
     public void poke(MotionEvent event) {
         mLastPokeTime = event.getEventTime();
         if (DEBUG)
-            Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
+            Log.v(TAG, "poked! size=" + getSize(mLastPokeTime));
         if (mShouldFlash) postInvalidate();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java
deleted file mode 100644
index 94c8aa5..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.policy;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.widget.CompoundButton;
-
-public class DoNotDisturbController implements CompoundButton.OnCheckedChangeListener,
-        SharedPreferences.OnSharedPreferenceChangeListener {
-    private static final String TAG = "StatusBar.DoNotDisturbController";
-
-    SharedPreferences mPrefs;
-    private Context mContext;
-    private CompoundButton mCheckBox;
-
-    private boolean mDoNotDisturb;
-
-    public DoNotDisturbController(Context context, CompoundButton checkbox) {
-        mContext = context;
-
-        mPrefs = Prefs.read(context);
-        mPrefs.registerOnSharedPreferenceChangeListener(this);
-        mDoNotDisturb = mPrefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
-
-        mCheckBox = checkbox;
-        checkbox.setOnCheckedChangeListener(this);
-
-        checkbox.setChecked(!mDoNotDisturb);
-    }
-
-    // The checkbox is ON for notifications coming in and OFF for Do not disturb, so we
-    // don't have a double negative.
-    public void onCheckedChanged(CompoundButton view, boolean checked) {
-        //Slog.d(TAG, "onCheckedChanged checked=" + checked + " mDoNotDisturb=" + mDoNotDisturb);
-        final boolean value = !checked;
-        if (value != mDoNotDisturb) {
-            SharedPreferences.Editor editor = Prefs.edit(mContext);
-            editor.putBoolean(Prefs.DO_NOT_DISTURB_PREF, value);
-            editor.apply();
-        }
-    }
-    
-    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
-        final boolean val = prefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF,
-                Prefs.DO_NOT_DISTURB_DEFAULT);
-        if (val != mDoNotDisturb) {
-            mDoNotDisturb = val;
-            mCheckBox.setChecked(!val);
-        }
-    }
-
-    public void release() {
-        mPrefs.unregisterOnSharedPreferenceChangeListener(this);
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
deleted file mode 100644
index 47e758c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
+++ /dev/null
@@ -1,99 +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 com.android.systemui.statusbar.policy;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Region;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.ServiceManager;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.HapticFeedbackConstants;
-import android.view.IWindowManager;
-import android.view.InputDevice;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewTreeObserver;
-import android.widget.RemoteViews.RemoteView;
-
-import com.android.systemui.R;
-
-public class EventHole extends View implements ViewTreeObserver.OnComputeInternalInsetsListener {
-    private static final String TAG = "StatusBar.EventHole";
-
-    private boolean mWindowVis;
-    private int[] mLoc = new int[2];
-
-    public EventHole(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public EventHole(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onWindowVisibilityChanged(int visibility) {
-        super.onWindowVisibilityChanged(visibility);
-        mWindowVis = visibility == View.VISIBLE;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
-    }
-
-    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-        final boolean visible = isShown() && mWindowVis && getWidth() > 0 && getHeight() > 0;
-        final int[] loc = mLoc;
-        getLocationInWindow(loc);
-        final int l = loc[0];
-        final int r = l + getWidth();
-        final int t = loc[1];
-        final int b = t + getHeight();
-        
-        View top = this;
-        while (top.getParent() instanceof View) {
-            top = (View)top.getParent();
-        }
-
-        if (visible) {
-            info.setTouchableInsets(
-                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-            info.touchableRegion.set(0, 0, top.getWidth(), top.getHeight());
-            info.touchableRegion.op(l, t, r, b, Region.Op.DIFFERENCE);
-        } else {
-            info.setTouchableInsets(
-                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
-        }
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FixedSizeDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FixedSizeDrawable.java
deleted file mode 100644
index 8f2f5f9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FixedSizeDrawable.java
+++ /dev/null
@@ -1,66 +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 com.android.systemui.statusbar.policy;
-
-import android.graphics.drawable.Drawable;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Rect;
-import android.util.Slog;
-
-public class FixedSizeDrawable extends Drawable {
-    Drawable mDrawable;
-    int mLeft;
-    int mTop;
-    int mRight;
-    int mBottom;
-
-    public FixedSizeDrawable(Drawable that) {
-        mDrawable = that;
-    }
-
-    public void setFixedBounds(int l, int t, int r, int b) {
-        mLeft = l;
-        mTop = t;
-        mRight = r;
-        mBottom = b;
-    }
-
-    public void setBounds(Rect bounds) {
-        mDrawable.setBounds(mLeft, mTop, mRight, mBottom);
-    }
-
-    public void setBounds(int l, int t, int r, int b) {
-        mDrawable.setBounds(mLeft, mTop, mRight, mBottom);
-    }
-
-    public void draw(Canvas canvas) {
-        mDrawable.draw(canvas);
-    }
-
-    public int getOpacity() {
-        return mDrawable.getOpacity();
-    }
-
-    public void setAlpha(int alpha) {
-        mDrawable.setAlpha(alpha);
-    }
-
-    public void setColorFilter(ColorFilter cf) {
-        mDrawable.setColorFilter(cf);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
new file mode 100644
index 0000000..f1fda78
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.Notification;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.NotificationData;
+
+public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback {
+    private static final String TAG = "HeadsUpNotificationView";
+    private static final boolean DEBUG = false;
+    private static final boolean SPEW = DEBUG;
+
+    Rect mTmpRect = new Rect();
+
+    private final int mTouchSensitivityDelay;
+    private SwipeHelper mSwipeHelper;
+
+    private BaseStatusBar mBar;
+    private ExpandHelper mExpandHelper;
+    private long mStartTouchTime;
+
+    private ViewGroup mContentHolder;
+    private ViewGroup mContentSlider;
+
+    private NotificationData.Entry mHeadsUp;
+
+    public HeadsUpNotificationView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public HeadsUpNotificationView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mTouchSensitivityDelay = getResources().getInteger(R.integer.heads_up_sensitivity_delay);
+        if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
+    }
+
+    public void setBar(BaseStatusBar bar) {
+        mBar = bar;
+    }
+
+    public ViewGroup getHolder() {
+        return mContentHolder;
+    }
+
+    public boolean setNotification(NotificationData.Entry headsUp) {
+        mHeadsUp = headsUp;
+        mHeadsUp.row.setExpanded(false);
+        if (mContentHolder == null) {
+            // too soon!
+            return false;
+        }
+        mContentHolder.setX(0);
+        mContentHolder.setVisibility(View.VISIBLE);
+        mContentHolder.setAlpha(1f);
+        mContentHolder.removeAllViews();
+        mContentHolder.addView(mHeadsUp.row);
+        mSwipeHelper.snapChild(mContentSlider, 1f);
+        mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+        return true;
+    }
+
+    public boolean isClearable() {
+        return mHeadsUp == null || mHeadsUp.notification.isClearable();
+    }
+
+    public void setMargin(int notificationPanelMarginPx) {
+        if (SPEW) Log.v(TAG, "setMargin() " + notificationPanelMarginPx);
+        if (mContentSlider != null) {
+            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentSlider.getLayoutParams();
+            lp.setMarginStart(notificationPanelMarginPx);
+            mContentSlider.setLayoutParams(lp);
+        }
+    }
+
+    // LinearLayout methods
+
+    @Override
+    public void onDraw(android.graphics.Canvas c) {
+        super.onDraw(c);
+        if (DEBUG) {
+            //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+            //        + getMeasuredHeight() + "px");
+            c.save();
+            c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
+                    android.graphics.Region.Op.DIFFERENCE);
+            c.drawColor(0xFFcc00cc);
+            c.restore();
+        }
+    }
+
+    // ViewGroup methods
+
+    @Override
+    public void onAttachedToWindow() {
+        float densityScale = getResources().getDisplayMetrics().density;
+        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
+        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+
+        int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
+        int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
+        mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
+
+        mContentHolder = (ViewGroup) findViewById(R.id.content_holder);
+        mContentSlider = (ViewGroup) findViewById(R.id.content_slider);
+
+        if (mHeadsUp != null) {
+            // whoops, we're on already!
+            setNotification(mHeadsUp);
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
+        if (System.currentTimeMillis() < mStartTouchTime) {
+            return true;
+        }
+        return mSwipeHelper.onInterceptTouchEvent(ev)
+                || mExpandHelper.onInterceptTouchEvent(ev)
+                || super.onInterceptTouchEvent(ev);
+    }
+
+    // View methods
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (System.currentTimeMillis() < mStartTouchTime) {
+            return false;
+        }
+        mBar.resetHeadsUpDecayTimer();
+        return mSwipeHelper.onTouchEvent(ev)
+                || mExpandHelper.onTouchEvent(ev)
+                || super.onTouchEvent(ev);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        float densityScale = getResources().getDisplayMetrics().density;
+        mSwipeHelper.setDensityScale(densityScale);
+        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
+        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
+    }
+
+    // ExpandHelper.Callback methods
+
+    @Override
+    public View getChildAtRawPosition(float x, float y) {
+        return getChildAtPosition(x, y);
+    }
+
+    @Override
+    public View getChildAtPosition(float x, float y) {
+        return mHeadsUp == null ? null : mHeadsUp.row;
+    }
+
+    @Override
+    public boolean canChildBeExpanded(View v) {
+        return mHeadsUp != null && mHeadsUp.row == v && mHeadsUp.row.isExpandable();
+    }
+
+    @Override
+    public void setUserExpandedChild(View v, boolean userExpanded) {
+        if (mHeadsUp != null && mHeadsUp.row == v) {
+            mHeadsUp.row.setUserExpanded(userExpanded);
+        }
+    }
+
+    @Override
+    public void setUserLockedChild(View v, boolean userLocked) {
+        if (mHeadsUp != null && mHeadsUp.row == v) {
+            mHeadsUp.row.setUserLocked(userLocked);
+        }
+    }
+
+    // SwipeHelper.Callback methods
+
+    @Override
+    public boolean canChildBeDismissed(View v) {
+        return true;
+    }
+
+    @Override
+    public void onChildDismissed(View v) {
+        Log.v(TAG, "User swiped heads up to dismiss");
+        mBar.onHeadsUpDismissed();
+    }
+
+    @Override
+    public void onBeginDrag(View v) {
+    }
+
+    @Override
+    public void onDragCancelled(View v) {
+        mContentHolder.setAlpha(1f); // sometimes this isn't quite reset
+    }
+
+    @Override
+    public View getChildAtPosition(MotionEvent ev) {
+        return mContentSlider;
+    }
+
+    @Override
+    public View getChildContentView(View v) {
+        return mContentSlider;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IntruderAlertView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IntruderAlertView.java
deleted file mode 100644
index ee5c863..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IntruderAlertView.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-
-import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.statusbar.BaseStatusBar;
-
-import java.util.HashMap;
-
-public class IntruderAlertView extends LinearLayout implements SwipeHelper.Callback {
-    private static final String TAG = "IntruderAlertView";
-    private static final boolean DEBUG = false;
-
-    Rect mTmpRect = new Rect();
-
-    private SwipeHelper mSwipeHelper;
-    
-    BaseStatusBar mBar;
-    private ViewGroup mContentHolder;
-    
-    private RemoteViews mIntruderRemoteViews;
-    private OnClickListener mOnClickListener;
-
-    public IntruderAlertView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public IntruderAlertView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        setOrientation(LinearLayout.VERTICAL);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        float densityScale = getResources().getDisplayMetrics().density;
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
-        
-        mContentHolder = (ViewGroup) findViewById(R.id.contentHolder);
-        if (mIntruderRemoteViews != null) {
-            // whoops, we're on already!
-            applyIntruderContent(mIntruderRemoteViews, mOnClickListener);
-        }
-    }
-    
-    public void setBar(BaseStatusBar bar) {
-        mBar = bar;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        return mSwipeHelper.onInterceptTouchEvent(ev) ||
-            super.onInterceptTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return mSwipeHelper.onTouchEvent(ev) ||
-            super.onTouchEvent(ev);
-    }
-
-    public boolean canChildBeDismissed(View v) {
-        return true;
-    }
-
-    public void onChildDismissed(View v) {
-        Slog.v(TAG, "User swiped intruder to dismiss");
-        mBar.dismissIntruder();
-    }
-
-    public void onBeginDrag(View v) {
-    }
-
-    public void onDragCancelled(View v) {
-        mContentHolder.setAlpha(1f); // sometimes this isn't quite reset
-    }
-
-    public View getChildAtPosition(MotionEvent ev) {
-        return mContentHolder;
-    }
-
-    public View getChildContentView(View v) {
-        return v;
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        float densityScale = getResources().getDisplayMetrics().density;
-        mSwipeHelper.setDensityScale(densityScale);
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
-    }
-
-    @Override
-    public void onDraw(android.graphics.Canvas c) {
-        super.onDraw(c);
-        if (DEBUG) {
-            //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
-            //        + getMeasuredHeight() + "px");
-            c.save();
-            c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
-                    android.graphics.Region.Op.DIFFERENCE);
-            c.drawColor(0xFFcc00cc);
-            c.restore();
-        }
-    }
-
-    public void applyIntruderContent(RemoteViews intruderView, OnClickListener listener) {
-        if (DEBUG) {
-            Slog.v(TAG, "applyIntruderContent: view=" + intruderView + " listener=" + listener);
-        }
-        mIntruderRemoteViews = intruderView;
-        mOnClickListener = listener;
-        if (mContentHolder == null) { 
-            // too soon!
-            return;
-        }
-        mContentHolder.setX(0);
-        mContentHolder.setVisibility(View.VISIBLE);
-        mContentHolder.setAlpha(1f);
-        mContentHolder.removeAllViews();
-        final View content = intruderView.apply(getContext(), mContentHolder);
-        if (listener != null) {
-            content.setOnClickListener(listener);
-            
-            //content.setBackgroundResource(R.drawable.intruder_row_bg);
-            Drawable bg = getResources().getDrawable(R.drawable.intruder_row_bg);
-            if (bg == null) {
-                Log.e(TAG, String.format("Can't find background drawable id=0x%08x", R.drawable.intruder_row_bg));
-            } else {
-                content.setBackgroundDrawable(bg);
-            }
-        }
-        mContentHolder.addView(content);
-        
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 82d6a99..55fb95d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -16,21 +16,19 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.hardware.input.InputManager;
-import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.ServiceManager;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
+import android.util.Log;
 import android.view.HapticFeedbackConstants;
-import android.view.IWindowManager;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -38,15 +36,17 @@
 import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 
 import com.android.systemui.R;
 
 public class KeyButtonView extends ImageView {
     private static final String TAG = "StatusBar.KeyButtonView";
+    private static final boolean DEBUG = false;
 
     final float GLOW_MAX_SCALE_FACTOR = 1.8f;
-    final float BUTTON_QUIESCENT_ALPHA = 0.70f;
+    public static final float DEFAULT_QUIESCENT_ALPHA = 0.70f;
 
     long mDownTime;
     int mCode;
@@ -54,14 +54,16 @@
     Drawable mGlowBG;
     int mGlowWidth, mGlowHeight;
     float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
+    float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA;
     boolean mSupportsLongpress = true;
     RectF mRect = new RectF(0f,0f,0f,0f);
     AnimatorSet mPressedAnim;
+    Animator mAnimateToQuiescent = new ObjectAnimator();
 
     Runnable mCheckLongPress = new Runnable() {
         public void run() {
             if (isPressed()) {
-                // Slog.d("KeyButtonView", "longpressed: " + this);
+                // Log.d("KeyButtonView", "longpressed: " + this);
                 if (mCode != 0) {
                     sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
                     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
@@ -84,16 +86,16 @@
                 defStyle, 0);
 
         mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
-        
+
         mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
 
         mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground);
         if (mGlowBG != null) {
-            setDrawingAlpha(BUTTON_QUIESCENT_ALPHA);
+            setDrawingAlpha(mQuiescentAlpha);
             mGlowWidth = mGlowBG.getIntrinsicWidth();
             mGlowHeight = mGlowBG.getIntrinsicHeight();
         }
-        
+
         a.recycle();
 
         setClickable(true);
@@ -121,6 +123,26 @@
         super.onDraw(canvas);
     }
 
+    public void setQuiescentAlpha(float alpha, boolean animate) {
+        mAnimateToQuiescent.cancel();
+        alpha = Math.min(Math.max(alpha, 0), 1);
+        if (alpha == mQuiescentAlpha) return;
+        mQuiescentAlpha = alpha;
+        if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha);
+        if (mGlowBG != null) {
+            if (animate) {
+                mAnimateToQuiescent = animateToQuiescent();
+                mAnimateToQuiescent.start();
+            } else {
+                setDrawingAlpha(mQuiescentAlpha);
+            }
+        }
+    }
+
+    private ObjectAnimator animateToQuiescent() {
+        return ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha);
+    }
+
     public float getDrawingAlpha() {
         if (mGlowBG == null) return 0;
         return mDrawingAlpha;
@@ -183,10 +205,10 @@
                 }
                 final AnimatorSet as = mPressedAnim = new AnimatorSet();
                 if (pressed) {
-                    if (mGlowScale < GLOW_MAX_SCALE_FACTOR) 
+                    if (mGlowScale < GLOW_MAX_SCALE_FACTOR)
                         mGlowScale = GLOW_MAX_SCALE_FACTOR;
-                    if (mGlowAlpha < BUTTON_QUIESCENT_ALPHA)
-                        mGlowAlpha = BUTTON_QUIESCENT_ALPHA;
+                    if (mGlowAlpha < mQuiescentAlpha)
+                        mGlowAlpha = mQuiescentAlpha;
                     setDrawingAlpha(1f);
                     as.playTogether(
                         ObjectAnimator.ofFloat(this, "glowAlpha", 1f),
@@ -194,10 +216,12 @@
                     );
                     as.setDuration(50);
                 } else {
+                    mAnimateToQuiescent.cancel();
+                    mAnimateToQuiescent = animateToQuiescent();
                     as.playTogether(
                         ObjectAnimator.ofFloat(this, "glowAlpha", 0f),
                         ObjectAnimator.ofFloat(this, "glowScale", 1f),
-                        ObjectAnimator.ofFloat(this, "drawingAlpha", BUTTON_QUIESCENT_ALPHA)
+                        mAnimateToQuiescent
                     );
                     as.setDuration(500);
                 }
@@ -213,7 +237,7 @@
 
         switch (action) {
             case MotionEvent.ACTION_DOWN:
-                //Slog.d("KeyButtonView", "press");
+                //Log.d("KeyButtonView", "press");
                 mDownTime = SystemClock.uptimeMillis();
                 setPressed(true);
                 if (mCode != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 68d048d..312bba3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -16,127 +16,209 @@
 
 package com.android.systemui.statusbar.policy;
 
-import java.util.ArrayList;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.StatusBarManager;
 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.location.LocationManager;
+import android.os.Handler;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 
-// private NM API
-import android.app.INotificationManager;
-
 import com.android.systemui.R;
 
-public class LocationController extends BroadcastReceiver {
-    private static final String TAG = "StatusBar.LocationController";
+import java.util.ArrayList;
+import java.util.List;
 
-    private static final int GPS_NOTIFICATION_ID = 374203-122084;
+/**
+ * A controller to manage changes of location related states and update the views accordingly.
+ */
+public class LocationController extends BroadcastReceiver {
+    // The name of the placeholder corresponding to the location request status icon.
+    // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
+    public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
+    public static final int LOCATION_STATUS_ICON_ID
+        = R.drawable.stat_sys_device_access_location_found;
+
+    private static final int[] mHighPowerRequestAppOpArray
+        = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
 
     private Context mContext;
 
-    private INotificationManager mNotificationService;
+    private AppOpsManager mAppOpsManager;
+    private StatusBarManager mStatusBarManager;
 
-    private ArrayList<LocationGpsStateChangeCallback> mChangeCallbacks =
-            new ArrayList<LocationGpsStateChangeCallback>();
+    private boolean mAreActiveLocationRequests;
 
-    public interface LocationGpsStateChangeCallback {
-        public void onLocationGpsStateChanged(boolean inUse, String description);
+    private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
+            new ArrayList<LocationSettingsChangeCallback>();
+
+    /**
+     * A callback for change in location settings (the user has enabled/disabled location).
+     */
+    public interface LocationSettingsChangeCallback {
+        /**
+         * Called whenever location settings change.
+         *
+         * @param locationEnabled A value of true indicates that at least one type of location
+         *                        is enabled in settings.
+         */
+        public void onLocationSettingsChanged(boolean locationEnabled);
     }
 
     public LocationController(Context context) {
         mContext = context;
 
         IntentFilter filter = new IntentFilter();
-        filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
-        filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
+        filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
         context.registerReceiver(this, filter);
 
-        NotificationManager nm = (NotificationManager)context.getSystemService(
-                Context.NOTIFICATION_SERVICE);
-        mNotificationService = nm.getService();
+        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mStatusBarManager
+                = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+
+        // Register to listen for changes in location settings.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        context.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
+                    locationSettingsChanged();
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, new Handler());
+
+        // Examine the current location state and initialize the status view.
+        updateActiveLocationRequests();
+        refreshViews();
     }
 
-    public void addStateChangedCallback(LocationGpsStateChangeCallback cb) {
-        mChangeCallbacks.add(cb);
+    /**
+     * Add a callback to listen for changes in location settings.
+     */
+    public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+        mSettingsChangeCallbacks.add(cb);
+    }
+
+    /**
+     * Enable or disable location in settings.
+     *
+     * <p>This will attempt to enable/disable every type of location setting
+     * (e.g. high and balanced power).
+     *
+     * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
+     * If the user doesn't accept, network location won't be enabled.
+     *
+     * @return true if attempt to change setting was successful.
+     */
+    public boolean setLocationEnabled(boolean enabled) {
+        int currentUserId = ActivityManager.getCurrentUser();
+        if (isUserLocationRestricted(currentUserId)) {
+            return false;
+        }
+        final ContentResolver cr = mContext.getContentResolver();
+        // When enabling location, a user consent dialog will pop up, and the
+        // setting won't be fully enabled until the user accepts the agreement.
+        int mode = enabled
+                ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
+        // QuickSettings always runs as the owner, so specifically set the settings
+        // for the current foreground user.
+        return Settings.Secure
+                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+    }
+
+    /**
+     * Returns true if location isn't disabled in settings.
+     */
+    public boolean isLocationEnabled() {
+        ContentResolver resolver = mContext.getContentResolver();
+        // QuickSettings always runs as the owner, so specifically retrieve the settings
+        // for the current foreground user.
+        int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
+                Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
+        return mode != Settings.Secure.LOCATION_MODE_OFF;
+    }
+
+    /**
+     * Returns true if the current user is restricted from using location.
+     */
+    private boolean isUserLocationRestricted(int userId) {
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        return um.hasUserRestriction(
+                UserManager.DISALLOW_SHARE_LOCATION,
+                new UserHandle(userId));
+    }
+
+    /**
+     * Returns true if there currently exist active high power location requests.
+     */
+    private boolean areActiveHighPowerLocationRequests() {
+        List<AppOpsManager.PackageOps> packages
+            = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
+        // AppOpsManager can return null when there is no requested data.
+        if (packages != null) {
+            final int numPackages = packages.size();
+            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+                if (opEntries != null) {
+                    final int numOps = opEntries.size();
+                    for (int opInd = 0; opInd < numOps; opInd++) {
+                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+                        // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
+                        // of the mHighPowerRequestAppOpArray filter, but checking defensively.
+                        if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+                            if (opEntry.isRunning()) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    // Updates the status view based on the current state of location requests.
+    private void refreshViews() {
+        if (mAreActiveLocationRequests) {
+            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
+                    mContext.getString(R.string.accessibility_location_active));
+        } else {
+            mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
+        }
+    }
+
+    // Reads the active location requests and updates the status view if necessary.
+    private void updateActiveLocationRequests() {
+        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
+        mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+        if (mAreActiveLocationRequests != hadActiveLocationRequests) {
+            refreshViews();
+        }
+    }
+
+    private void locationSettingsChanged() {
+        boolean isEnabled = isLocationEnabled();
+        for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
+            cb.onLocationSettingsChanged(isEnabled);
+        }
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
-        final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
-
-        boolean visible;
-        int iconId, textResId;
-
-        if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
-            // GPS is getting fixes
-            iconId = com.android.internal.R.drawable.stat_sys_gps_on;
-            textResId = R.string.gps_notification_found_text;
-            visible = true;
-        } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
-            // GPS is off
-            visible = false;
-            iconId = textResId = 0;
-        } else {
-            // GPS is on, but not receiving fixes
-            iconId = R.drawable.stat_sys_gps_acquiring_anim;
-            textResId = R.string.gps_notification_searching_text;
-            visible = true;
-        }
-        
-        try {
-            if (visible) {
-                Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
-                gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-                PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0,
-                        gpsIntent, 0, null, UserHandle.CURRENT);
-                String text = mContext.getText(textResId).toString();
-
-                Notification n = new Notification.Builder(mContext)
-                    .setSmallIcon(iconId)
-                    .setContentTitle(text)
-                    .setOngoing(true)
-                    .setContentIntent(pendingIntent)
-                    .getNotification();
-
-                // Notification.Builder will helpfully fill these out for you no matter what you do
-                n.tickerView = null;
-                n.tickerText = null;
-                
-                n.priority = Notification.PRIORITY_HIGH;
-
-                int[] idOut = new int[1];
-                mNotificationService.enqueueNotificationWithTag(
-                        mContext.getPackageName(), mContext.getBasePackageName(),
-                        null, 
-                        GPS_NOTIFICATION_ID, 
-                        n,
-                        idOut,
-                        UserHandle.USER_ALL);
-
-                for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
-                    cb.onLocationGpsStateChanged(true, text);
-                }
-            } else {
-                mNotificationService.cancelNotificationWithTag(
-                        mContext.getPackageName(), null,
-                        GPS_NOTIFICATION_ID, UserHandle.USER_ALL);
-
-                for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
-                    cb.onLocationGpsStateChanged(false, null);
-                }
-            }
-        } catch (android.os.RemoteException ex) {
-            // well, it was worth a shot
+        if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
+            updateActiveLocationRequests();
         }
     }
 }
-
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 73752e5..09f1695 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -27,27 +27,24 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wimax.WimaxManagerConstants;
-import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.RemoteException;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
-import android.util.Slog;
+import android.util.Log;
 import android.view.View;
-import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.internal.util.AsyncChannel;
-import com.android.server.am.BatteryStatsService;
+import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 
 import java.io.FileDescriptor;
@@ -56,12 +53,14 @@
 import java.util.List;
 import java.util.Locale;
 
-public class NetworkController extends BroadcastReceiver {
+public class NetworkController extends BroadcastReceiver implements DemoMode {
     // debug
     static final String TAG = "StatusBar.NetworkController";
     static final boolean DEBUG = false;
     static final boolean CHATTY = false; // additional diagnostics, but not logspew
 
+    private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
+
     // telephony
     boolean mHspaDataDistinguishable;
     final TelephonyManager mPhone;
@@ -85,7 +84,6 @@
     int mQSDataTypeIconId;
     int mAirplaneIconId;
     boolean mDataActive;
-    int mMobileActivityIconId; // overlay arrows for data direction
     int mLastSignalLevel;
     boolean mShowPhoneRSSIForData = false;
     boolean mShowAtLeastThreeGees = false;
@@ -105,7 +103,6 @@
     String mWifiSsid;
     int mWifiIconId = 0;
     int mQSWifiIconId = 0;
-    int mWifiActivityIconId = 0; // overlay arrows for wifi direction
     int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
 
     // bluetooth
@@ -139,13 +136,6 @@
 
     // our ui
     Context mContext;
-    ArrayList<ImageView> mPhoneSignalIconViews = new ArrayList<ImageView>();
-    ArrayList<ImageView> mDataDirectionIconViews = new ArrayList<ImageView>();
-    ArrayList<ImageView> mDataDirectionOverlayIconViews = new ArrayList<ImageView>();
-    ArrayList<ImageView> mWifiIconViews = new ArrayList<ImageView>();
-    ArrayList<ImageView> mWimaxIconViews = new ArrayList<ImageView>();
-    ArrayList<ImageView> mCombinedSignalIconViews = new ArrayList<ImageView>();
-    ArrayList<ImageView> mDataTypeIconViews = new ArrayList<ImageView>();
     ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
     ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
     ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
@@ -155,7 +145,6 @@
             new ArrayList<NetworkSignalChangedCallback>();
     int mLastPhoneSignalIconId = -1;
     int mLastDataDirectionIconId = -1;
-    int mLastDataDirectionOverlayIconId = -1;
     int mLastWifiIconId = -1;
     int mLastWimaxIconId = -1;
     int mLastCombinedSignalIconId = -1;
@@ -166,22 +155,21 @@
 
     boolean mDataAndWifiStacked = false;
 
-    // yuck -- stop doing this here and put it in the framework
-    IBatteryStats mBatteryStats;
-
     public interface SignalCluster {
-        void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
+        void setWifiIndicators(boolean visible, int strengthIcon,
                 String contentDescription);
-        void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
+        void setMobileDataIndicators(boolean visible, int strengthIcon,
                 int typeIcon, String contentDescription, String typeContentDescription);
         void setIsAirplaneMode(boolean is, int airplaneIcon);
     }
 
     public interface NetworkSignalChangedCallback {
         void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
-                String wifitSignalContentDescriptionId, String description);
+                boolean activityIn, boolean activityOut,
+                String wifiSignalContentDescriptionId, String description);
         void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
                 String mobileSignalContentDescriptionId, int dataTypeIconId,
+                boolean activityIn, boolean activityOut,
                 String dataTypeContentDescriptionId, String description);
         void onAirplaneModeChanged(boolean enabled);
     }
@@ -253,9 +241,6 @@
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode();
 
-        // yuck
-        mBatteryStats = BatteryStatsService.getService();
-
         mLastLocale = mContext.getResources().getConfiguration().locale;
     }
 
@@ -271,33 +256,6 @@
         return (mServiceState != null && mServiceState.isEmergencyOnly());
     }
 
-    public void addPhoneSignalIconView(ImageView v) {
-        mPhoneSignalIconViews.add(v);
-    }
-
-    public void addDataDirectionIconView(ImageView v) {
-        mDataDirectionIconViews.add(v);
-    }
-
-    public void addDataDirectionOverlayIconView(ImageView v) {
-        mDataDirectionOverlayIconViews.add(v);
-    }
-
-    public void addWifiIconView(ImageView v) {
-        mWifiIconViews.add(v);
-    }
-    public void addWimaxIconView(ImageView v) {
-        mWimaxIconViews.add(v);
-    }
-
-    public void addCombinedSignalIconView(ImageView v) {
-        mCombinedSignalIconViews.add(v);
-    }
-
-    public void addDataTypeIconView(ImageView v) {
-        mDataTypeIconViews.add(v);
-    }
-
     public void addCombinedLabelView(TextView v) {
         mCombinedLabelViews.add(v);
     }
@@ -325,11 +283,11 @@
     }
 
     public void refreshSignalCluster(SignalCluster cluster) {
+        if (mDemoMode) return;
         cluster.setWifiIndicators(
                 // only show wifi in the cluster if connected or if wifi-only
                 mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
                 mWifiIconId,
-                mWifiActivityIconId,
                 mContentDescriptionWifi);
 
         if (mIsWimaxEnabled && mWimaxConnected) {
@@ -337,7 +295,6 @@
             cluster.setMobileDataIndicators(
                     true,
                     mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
-                    mMobileActivityIconId,
                     mDataTypeIconId,
                     mContentDescriptionWimax,
                     mContentDescriptionDataType);
@@ -346,7 +303,6 @@
             cluster.setMobileDataIndicators(
                     mHasMobileDataFeature,
                     mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
-                    mMobileActivityIconId,
                     mDataTypeIconId,
                     mContentDescriptionPhoneSignal,
                     mContentDescriptionDataType);
@@ -359,22 +315,33 @@
         boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
         String wifiDesc = wifiEnabled ?
                 mWifiSsid : null;
-        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, mContentDescriptionWifi, wifiDesc);
+        boolean wifiIn = wifiEnabled && mWifiSsid != null
+                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
+        boolean wifiOut = wifiEnabled && mWifiSsid != null
+                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
+        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
+                mContentDescriptionWifi, wifiDesc);
 
+        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
+        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
         if (isEmergencyOnly()) {
             cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
-                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mContentDescriptionDataType,
-                    null);
+                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                    mContentDescriptionDataType, null);
         } else {
             if (mIsWimaxEnabled && mWimaxConnected) {
                 // Wimax is special
                 cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId,
+                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
                         mContentDescriptionDataType, mNetworkName);
             } else {
                 // Normal mobile data
                 cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId,
+                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
                         mContentDescriptionDataType, mNetworkName);
             }
         }
@@ -429,7 +396,7 @@
         @Override
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
             if (DEBUG) {
-                Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
                     ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
             }
             mSignalStrength = signalStrength;
@@ -440,7 +407,8 @@
         @Override
         public void onServiceStateChanged(ServiceState state) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceStateChanged state=" + state.getState());
+                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+                        + " dataState=" + state.getDataRegState());
             }
             mServiceState = state;
             updateTelephonySignalStrength();
@@ -452,7 +420,7 @@
         @Override
         public void onCallStateChanged(int state, String incomingNumber) {
             if (DEBUG) {
-                Slog.d(TAG, "onCallStateChanged state=" + state);
+                Log.d(TAG, "onCallStateChanged state=" + state);
             }
             // In cdma, if a voice call is made, RSSI should switch to 1x.
             if (isCdma()) {
@@ -464,7 +432,7 @@
         @Override
         public void onDataConnectionStateChanged(int state, int networkType) {
             if (DEBUG) {
-                Slog.d(TAG, "onDataConnectionStateChanged: state=" + state
+                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
                         + " type=" + networkType);
             }
             mDataState = state;
@@ -477,7 +445,7 @@
         @Override
         public void onDataActivity(int direction) {
             if (DEBUG) {
-                Slog.d(TAG, "onDataActivity: direction=" + direction);
+                Log.d(TAG, "onDataActivity: direction=" + direction);
             }
             mDataActivity = direction;
             updateDataIcon();
@@ -516,10 +484,16 @@
 
     private boolean hasService() {
         if (mServiceState != null) {
-            switch (mServiceState.getState()) {
-                case ServiceState.STATE_OUT_OF_SERVICE:
+            // Consider the device to be in service if either voice or data service is available.
+            // Some SIM cards are marketed as data-only and do not support voice service, and on
+            // these SIM cards, we want to show signal bars for data service as well as the "no
+            // service" or "emergency calls only" text that indicates that voice is not available.
+            switch(mServiceState.getVoiceRegState()) {
                 case ServiceState.STATE_POWER_OFF:
                     return false;
+                case ServiceState.STATE_OUT_OF_SERVICE:
+                case ServiceState.STATE_EMERGENCY_ONLY:
+                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
                 default:
                     return true;
             }
@@ -539,13 +513,13 @@
 
     private final void updateTelephonySignalStrength() {
         if (!hasService()) {
-            if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: !hasService()");
+            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
             mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
             mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
             mDataSignalIconId = R.drawable.stat_sys_signal_null;
         } else {
             if (mSignalStrength == null) {
-                if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
+                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
                 mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
                 mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
                 mDataSignalIconId = R.drawable.stat_sys_signal_null;
@@ -556,7 +530,7 @@
                 int[] iconList;
                 if (isCdma() && mAlwaysShowCdmaRssi) {
                     mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
-                    if(DEBUG) Slog.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
                             + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
                             + " instead of level=" + mSignalStrength.getLevel());
                 } else {
@@ -591,8 +565,8 @@
         if (mIsWimaxEnabled && mWimaxConnected) {
             // wimax is a special 4g network not handled by telephony
             mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-            mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
-            mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
+            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
             mContentDescriptionDataType = mContext.getString(
                     R.string.accessibility_data_connection_4g);
         } else {
@@ -611,8 +585,8 @@
                 case TelephonyManager.NETWORK_TYPE_EDGE:
                     if (!mShowAtLeastThreeGees) {
                         mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_e;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_edge);
                         break;
@@ -621,8 +595,8 @@
                     }
                 case TelephonyManager.NETWORK_TYPE_UMTS:
                     mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
-                    mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
                     mContentDescriptionDataType = mContext.getString(
                             R.string.accessibility_data_connection_3g);
                     break;
@@ -632,14 +606,14 @@
                 case TelephonyManager.NETWORK_TYPE_HSPAP:
                     if (mHspaDataDistinguishable) {
                         mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_h;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_3_5g);
                     } else {
                         mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_3g);
                     }
@@ -648,8 +622,8 @@
                     if (!mShowAtLeastThreeGees) {
                         // display 1xRTT for IS95A/B
                         mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_cdma);
                         break;
@@ -659,8 +633,8 @@
                 case TelephonyManager.NETWORK_TYPE_1xRTT:
                     if (!mShowAtLeastThreeGees) {
                         mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_cdma);
                         break;
@@ -672,8 +646,8 @@
                 case TelephonyManager.NETWORK_TYPE_EVDO_B:
                 case TelephonyManager.NETWORK_TYPE_EHRPD:
                     mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
-                    mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
                     mContentDescriptionDataType = mContext.getString(
                             R.string.accessibility_data_connection_3g);
                     break;
@@ -681,14 +655,14 @@
                     boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
                     if (show4GforLTE) {
                         mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_4g);
                     } else {
                         mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_lte;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_lte;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_lte);
                     }
@@ -696,14 +670,14 @@
                 default:
                     if (!mShowAtLeastThreeGees) {
                         mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_g;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_gprs);
                     } else {
                         mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
-                        mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
                         mContentDescriptionDataType = mContext.getString(
                                 R.string.accessibility_data_connection_3g);
                     }
@@ -713,12 +687,12 @@
 
         if (isCdma()) {
             if (isCdmaEri()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
-                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
             }
         } else if (mPhone.isNetworkRoaming()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
-                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
         }
     }
 
@@ -792,22 +766,13 @@
             }
         }
 
-        // yuck - this should NOT be done by the status bar
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
-        } catch (RemoteException e) {
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
         mDataDirectionIconId = iconId;
         mDataConnected = visible;
     }
 
     void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
         if (false) {
-            Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
                     + " showPlmn=" + showPlmn + " plmn=" + plmn);
         }
         StringBuilder str = new StringBuilder();
@@ -841,7 +806,7 @@
                         mWifiChannel.sendMessage(Message.obtain(this,
                                 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
                     } else {
-                        Slog.e(TAG, "Failed to connect to wifi");
+                        Log.e(TAG, "Failed to connect to wifi");
                     }
                     break;
                 case WifiManager.DATA_ACTIVITY_NOTIFICATION:
@@ -973,7 +938,7 @@
 
     private void updateConnectivity(Intent intent) {
         if (CHATTY) {
-            Slog.d(TAG, "updateConnectivity: intent=" + intent);
+            Log.d(TAG, "updateConnectivity: intent=" + intent);
         }
 
         final ConnectivityManager connManager = (ConnectivityManager) mContext
@@ -993,8 +958,8 @@
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
 
         if (CHATTY) {
-            Slog.d(TAG, "updateConnectivity: networkInfo=" + info);
-            Slog.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
+            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
+            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
         }
 
         mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
@@ -1020,7 +985,6 @@
         Context context = mContext;
 
         int combinedSignalIconId = 0;
-        int combinedActivityIconId = 0;
         String combinedLabel = "";
         String wifiLabel = "";
         String mobileLabel = "";
@@ -1058,56 +1022,23 @@
             // Now for things that should only be shown when actually using mobile data.
             if (mDataConnected) {
                 combinedSignalIconId = mDataSignalIconId;
-                switch (mDataActivity) {
-                    case TelephonyManager.DATA_ACTIVITY_IN:
-                        mMobileActivityIconId = R.drawable.stat_sys_signal_in;
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_OUT:
-                        mMobileActivityIconId = R.drawable.stat_sys_signal_out;
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_INOUT:
-                        mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
-                        break;
-                    default:
-                        mMobileActivityIconId = 0;
-                        break;
-                }
 
                 combinedLabel = mobileLabel;
-                combinedActivityIconId = mMobileActivityIconId;
                 combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
                 mContentDescriptionCombinedSignal = mContentDescriptionDataType;
-            } else {
-                mMobileActivityIconId = 0;
             }
         }
 
         if (mWifiConnected) {
             if (mWifiSsid == null) {
                 wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
-                mWifiActivityIconId = 0; // no wifis, no bits
             } else {
                 wifiLabel = mWifiSsid;
                 if (DEBUG) {
                     wifiLabel += "xxxxXXXXxxxxXXXX";
                 }
-                switch (mWifiActivity) {
-                    case WifiManager.DATA_ACTIVITY_IN:
-                        mWifiActivityIconId = R.drawable.stat_sys_wifi_in;
-                        break;
-                    case WifiManager.DATA_ACTIVITY_OUT:
-                        mWifiActivityIconId = R.drawable.stat_sys_wifi_out;
-                        break;
-                    case WifiManager.DATA_ACTIVITY_INOUT:
-                        mWifiActivityIconId = R.drawable.stat_sys_wifi_inout;
-                        break;
-                    case WifiManager.DATA_ACTIVITY_NONE:
-                        mWifiActivityIconId = 0;
-                        break;
-                }
             }
 
-            combinedActivityIconId = mWifiActivityIconId;
             combinedLabel = wifiLabel;
             combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
             mContentDescriptionCombinedSignal = mContentDescriptionWifi;
@@ -1138,7 +1069,7 @@
             // look again; your radios are now airplanes
             mContentDescriptionPhoneSignal = mContext.getString(
                     R.string.accessibility_airplane_mode);
-            mAirplaneIconId = R.drawable.stat_sys_signal_flightmode;
+            mAirplaneIconId = FLIGHT_MODE_ICON;
             mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
             mQSPhoneSignalIconId = 0;
 
@@ -1172,17 +1103,17 @@
             mQSDataTypeIconId = 0;
             if (isCdma()) {
                 if (isCdmaEri()) {
-                    mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
-                    mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
                 }
             } else if (mPhone.isNetworkRoaming()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
-                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
             }
         }
 
         if (DEBUG) {
-            Slog.d(TAG, "refreshViews connected={"
+            Log.d(TAG, "refreshViews connected={"
                     + (mWifiConnected?" wifi":"")
                     + (mDataConnected?" data":"")
                     + " } level="
@@ -1190,7 +1121,6 @@
                     + " combinedSignalIconId=0x"
                     + Integer.toHexString(combinedSignalIconId)
                     + "/" + getResourceName(combinedSignalIconId)
-                    + " combinedActivityIconId=0x" + Integer.toHexString(combinedActivityIconId)
                     + " mobileLabel=" + mobileLabel
                     + " wifiLabel=" + wifiLabel
                     + " emergencyOnly=" + emergencyOnly
@@ -1208,8 +1138,12 @@
                     + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
         }
 
+        // update QS
+        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+            notifySignalsChangedCallbacks(cb);
+        }
+
         if (mLastPhoneSignalIconId          != mPhoneSignalIconId
-         || mLastDataDirectionOverlayIconId != combinedActivityIconId
          || mLastWifiIconId                 != mWifiIconId
          || mLastWimaxIconId                != mWimaxIconId
          || mLastDataTypeIconId             != mDataTypeIconId
@@ -1220,9 +1154,6 @@
             for (SignalCluster cluster : mSignalClusters) {
                 refreshSignalCluster(cluster);
             }
-            for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
-                notifySignalsChangedCallbacks(cb);
-            }
         }
 
         if (mLastAirplaneMode != mAirplaneMode) {
@@ -1236,105 +1167,30 @@
         // the phone icon on phones
         if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
             mLastPhoneSignalIconId = mPhoneSignalIconId;
-            N = mPhoneSignalIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mPhoneSignalIconViews.get(i);
-                if (mPhoneSignalIconId == 0) {
-                    v.setVisibility(View.GONE);
-                } else {
-                    v.setVisibility(View.VISIBLE);
-                    v.setImageResource(mPhoneSignalIconId);
-                    v.setContentDescription(mContentDescriptionPhoneSignal);
-                }
-            }
         }
 
         // the data icon on phones
         if (mLastDataDirectionIconId != mDataDirectionIconId) {
             mLastDataDirectionIconId = mDataDirectionIconId;
-            N = mDataDirectionIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mDataDirectionIconViews.get(i);
-                v.setImageResource(mDataDirectionIconId);
-                v.setContentDescription(mContentDescriptionDataType);
-            }
         }
 
         // the wifi icon on phones
         if (mLastWifiIconId != mWifiIconId) {
             mLastWifiIconId = mWifiIconId;
-            N = mWifiIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mWifiIconViews.get(i);
-                if (mWifiIconId == 0) {
-                    v.setVisibility(View.GONE);
-                } else {
-                    v.setVisibility(View.VISIBLE);
-                    v.setImageResource(mWifiIconId);
-                    v.setContentDescription(mContentDescriptionWifi);
-                }
-            }
         }
 
         // the wimax icon on phones
         if (mLastWimaxIconId != mWimaxIconId) {
             mLastWimaxIconId = mWimaxIconId;
-            N = mWimaxIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mWimaxIconViews.get(i);
-                if (mWimaxIconId == 0) {
-                    v.setVisibility(View.GONE);
-                } else {
-                    v.setVisibility(View.VISIBLE);
-                    v.setImageResource(mWimaxIconId);
-                    v.setContentDescription(mContentDescriptionWimax);
-                }
-           }
         }
         // the combined data signal icon
         if (mLastCombinedSignalIconId != combinedSignalIconId) {
             mLastCombinedSignalIconId = combinedSignalIconId;
-            N = mCombinedSignalIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mCombinedSignalIconViews.get(i);
-                v.setImageResource(combinedSignalIconId);
-                v.setContentDescription(mContentDescriptionCombinedSignal);
-            }
         }
 
         // the data network type overlay
         if (mLastDataTypeIconId != mDataTypeIconId) {
             mLastDataTypeIconId = mDataTypeIconId;
-            N = mDataTypeIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mDataTypeIconViews.get(i);
-                if (mDataTypeIconId == 0) {
-                    v.setVisibility(View.GONE);
-                } else {
-                    v.setVisibility(View.VISIBLE);
-                    v.setImageResource(mDataTypeIconId);
-                    v.setContentDescription(mContentDescriptionDataType);
-                }
-            }
-        }
-
-        // the data direction overlay
-        if (mLastDataDirectionOverlayIconId != combinedActivityIconId) {
-            if (DEBUG) {
-                Slog.d(TAG, "changing data overlay icon id to " + combinedActivityIconId);
-            }
-            mLastDataDirectionOverlayIconId = combinedActivityIconId;
-            N = mDataDirectionOverlayIconViews.size();
-            for (int i=0; i<N; i++) {
-                final ImageView v = mDataDirectionOverlayIconViews.get(i);
-                if (combinedActivityIconId == 0) {
-                    v.setVisibility(View.GONE);
-                } else {
-                    v.setVisibility(View.VISIBLE);
-                    v.setImageResource(combinedActivityIconId);
-                    v.setContentDescription(mContentDescriptionDataType);
-                }
-            }
         }
 
         // the combinedLabel in the notification panel
@@ -1493,10 +1349,6 @@
         pw.print(Integer.toHexString(mLastDataDirectionIconId));
         pw.print("/");
         pw.println(getResourceName(mLastDataDirectionIconId));
-        pw.print("  mLastDataDirectionOverlayIconId=0x");
-        pw.print(Integer.toHexString(mLastDataDirectionOverlayIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataDirectionOverlayIconId));
         pw.print("  mLastWifiIconId=0x");
         pw.print(Integer.toHexString(mLastWifiIconId));
         pw.print("/");
@@ -1527,4 +1379,88 @@
         }
     }
 
+    private boolean mDemoMode;
+    private int mDemoInetCondition;
+    private int mDemoWifiLevel;
+    private int mDemoDataTypeIconId;
+    private int mDemoMobileLevel;
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+            mDemoWifiLevel = mWifiLevel;
+            mDemoInetCondition = mInetCondition;
+            mDemoDataTypeIconId = mDataTypeIconId;
+            mDemoMobileLevel = mLastSignalLevel;
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            for (SignalCluster cluster : mSignalClusters) {
+                refreshSignalCluster(cluster);
+            }
+        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
+            String airplane = args.getString("airplane");
+            if (airplane != null) {
+                boolean show = airplane.equals("show");
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
+                }
+            }
+            String fully = args.getString("fully");
+            if (fully != null) {
+                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
+            }
+            String wifi = args.getString("wifi");
+            if (wifi != null) {
+                boolean show = wifi.equals("show");
+                String level = args.getString("level");
+                if (level != null) {
+                    mDemoWifiLevel = level.equals("null") ? -1
+                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
+                }
+                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
+                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setWifiIndicators(
+                            show,
+                            iconId,
+                            "Demo");
+                }
+            }
+            String mobile = args.getString("mobile");
+            if (mobile != null) {
+                boolean show = mobile.equals("show");
+                String datatype = args.getString("datatype");
+                if (datatype != null) {
+                    mDemoDataTypeIconId =
+                            datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
+                            datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
+                            datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
+                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
+                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
+                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
+                            datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
+                            datatype.equals("roam")
+                                    ? R.drawable.stat_sys_data_fully_connected_roam :
+                            0;
+                }
+                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
+                String level = args.getString("level");
+                if (level != null) {
+                    mDemoMobileLevel = level.equals("null") ? -1
+                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
+                }
+                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
+                        icons[mDemoInetCondition][mDemoMobileLevel];
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setMobileDataIndicators(
+                            show,
+                            iconId,
+                            mDemoDataTypeIconId,
+                            "Demo",
+                            "Demo");
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 89eed1b..259422d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -16,34 +16,29 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.LinearLayout;
 
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 
 import java.util.HashMap;
 
-public class NotificationRowLayout 
-        extends LinearLayout 
+public class NotificationRowLayout
+        extends LinearLayout
         implements SwipeHelper.Callback, ExpandHelper.Callback
 {
     private static final String TAG = "NotificationRowLayout";
@@ -61,7 +56,7 @@
     HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
 
     private SwipeHelper mSwipeHelper;
-    
+
     private OnSizeChangedListener mOnSizeChangedListener;
 
     // Flag set during notification removal animation to avoid causing too much work until
@@ -80,18 +75,18 @@
         mRealLayoutTransition = new LayoutTransition();
         mRealLayoutTransition.setAnimateParentHierarchy(true);
         setLayoutTransitionsEnabled(true);
-        
+
         setOrientation(LinearLayout.VERTICAL);
 
         if (DEBUG) {
             setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                 @Override
                 public void onChildViewAdded(View parent, View child) {
-                    Slog.d(TAG, "view added: " + child + "; new count: " + getChildCount());
+                    Log.d(TAG, "view added: " + child + "; new count: " + getChildCount());
                 }
                 @Override
                 public void onChildViewRemoved(View parent, View child) {
-                    Slog.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
+                    Log.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
                 }
             });
 
@@ -155,19 +150,24 @@
     }
 
     public boolean canChildBeExpanded(View v) {
-        return NotificationData.getIsExpandable(v);
+        return v instanceof ExpandableNotificationRow
+                && ((ExpandableNotificationRow) v).isExpandable();
     }
 
-    public boolean setUserExpandedChild(View v, boolean userExpanded) {
-        return NotificationData.setUserExpanded(v, userExpanded);
+    public void setUserExpandedChild(View v, boolean userExpanded) {
+        if (v instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) v).setUserExpanded(userExpanded);
+        }
     }
 
-    public boolean setUserLockedChild(View v, boolean userLocked) {
-        return NotificationData.setUserLocked(v, userLocked);
+    public void setUserLockedChild(View v, boolean userLocked) {
+        if (v instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) v).setUserLocked(userLocked);
+        }
     }
 
     public void onChildDismissed(View v) {
-        if (DEBUG) Slog.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
+        if (DEBUG) Log.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
         final View veto = v.findViewById(R.id.veto);
         if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
             veto.performClick();
@@ -231,7 +231,7 @@
      * get removed properly.
      */
     public void setViewRemoval(boolean removeViews) {
-        if (DEBUG) Slog.v(TAG, "setViewRemoval: " + removeViews);
+        if (DEBUG) Log.v(TAG, "setViewRemoval: " + removeViews);
         mRemoveViews = removeViews;
     }
 
@@ -266,7 +266,7 @@
         super.onDraw(c);
         if (DEBUG) logLayoutTransition();
         if (DEBUG) {
-            //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+            //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
             //        + getMeasuredHeight() + "px");
             c.save();
             c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
index 5d2198e..f339401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
@@ -22,13 +22,6 @@
 public class Prefs {
     private static final String SHARED_PREFS_NAME = "status_bar";
 
-    // a boolean
-    public static final String DO_NOT_DISTURB_PREF = "do_not_disturb";
-    public static final boolean DO_NOT_DISTURB_DEFAULT = false;
-
-    public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help";
-    public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help";
-
     public static SharedPreferences read(Context context) {
         return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
new file mode 100644
index 0000000..6f61ec8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.policy;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.internal.view.RotationPolicy;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public final class RotationLockController {
+    private final Context mContext;
+    private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
+            new CopyOnWriteArrayList<RotationLockControllerCallback>();
+
+    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
+            new RotationPolicy.RotationPolicyListener() {
+        @Override
+        public void onChange() {
+            notifyChanged();
+        }
+    };
+
+    public interface RotationLockControllerCallback {
+        public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
+    }
+
+    public RotationLockController(Context context) {
+        mContext = context;
+        notifyChanged();
+        if (RotationPolicy.isRotationLockToggleSupported(mContext)) {
+            RotationPolicy.registerRotationPolicyListener(mContext,
+                    mRotationPolicyListener, UserHandle.USER_ALL);
+        }
+    }
+
+    public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
+        mCallbacks.add(callback);
+    }
+
+    public boolean isRotationLocked() {
+        if (RotationPolicy.isRotationLockToggleSupported(mContext)) {
+            return RotationPolicy.isRotationLocked(mContext);
+        }
+        return false;
+    }
+
+    public void setRotationLocked(boolean locked) {
+        if (RotationPolicy.isRotationLockToggleSupported(mContext)) {
+            RotationPolicy.setRotationLock(mContext, locked);
+        }
+    }
+
+    public boolean isRotationLockAffordanceVisible() {
+        if (RotationPolicy.isRotationLockToggleSupported(mContext)) {
+            return RotationPolicy.isRotationLockToggleVisible(mContext);
+        }
+        return false;
+    }
+
+    public void release() {
+        if (RotationPolicy.isRotationLockToggleSupported(mContext)) {
+            RotationPolicy.unregisterRotationPolicyListener(mContext,
+                    mRotationPolicyListener);
+        }
+    }
+
+    private void notifyChanged() {
+        for (RotationLockControllerCallback callback : mCallbacks) {
+            callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
+                    RotationPolicy.isRotationLockToggleVisible(mContext));
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 4b2c65e..67ba879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -23,11 +23,11 @@
 
     //GSM/UMTS
     static final int[][] TELEPHONY_SIGNAL_STRENGTH = {
-        { R.drawable.stat_sys_signal_0,
-          R.drawable.stat_sys_signal_1,
-          R.drawable.stat_sys_signal_2,
-          R.drawable.stat_sys_signal_3,
-          R.drawable.stat_sys_signal_4 },
+        { R.drawable.stat_sys_signal_0_fully,
+          R.drawable.stat_sys_signal_1_fully,
+          R.drawable.stat_sys_signal_2_fully,
+          R.drawable.stat_sys_signal_3_fully,
+          R.drawable.stat_sys_signal_4_fully },
         { R.drawable.stat_sys_signal_0_fully,
           R.drawable.stat_sys_signal_1_fully,
           R.drawable.stat_sys_signal_2_fully,
@@ -49,11 +49,11 @@
     };
 
     static final int[][] TELEPHONY_SIGNAL_STRENGTH_ROAMING = {
-        { R.drawable.stat_sys_signal_0,
-          R.drawable.stat_sys_signal_1,
-          R.drawable.stat_sys_signal_2,
-          R.drawable.stat_sys_signal_3,
-          R.drawable.stat_sys_signal_4 },
+        { R.drawable.stat_sys_signal_0_fully,
+          R.drawable.stat_sys_signal_1_fully,
+          R.drawable.stat_sys_signal_2_fully,
+          R.drawable.stat_sys_signal_3_fully,
+          R.drawable.stat_sys_signal_4_fully },
         { R.drawable.stat_sys_signal_0_fully,
           R.drawable.stat_sys_signal_1_fully,
           R.drawable.stat_sys_signal_2_fully,
@@ -61,92 +61,132 @@
           R.drawable.stat_sys_signal_4_fully }
     };
 
+    static final int[] QS_DATA_R = {
+        R.drawable.ic_qs_signal_r,
+        R.drawable.ic_qs_signal_full_r
+    };
+
     static final int[][] DATA_SIGNAL_STRENGTH = TELEPHONY_SIGNAL_STRENGTH;
 
     //***** Data connection icons
 
     //GSM/UMTS
     static final int[][] DATA_G = {
-            { R.drawable.stat_sys_data_connected_g,
-              R.drawable.stat_sys_data_connected_g,
-              R.drawable.stat_sys_data_connected_g,
-              R.drawable.stat_sys_data_connected_g },
+            { R.drawable.stat_sys_data_fully_connected_g,
+              R.drawable.stat_sys_data_fully_connected_g,
+              R.drawable.stat_sys_data_fully_connected_g,
+              R.drawable.stat_sys_data_fully_connected_g },
             { R.drawable.stat_sys_data_fully_connected_g,
               R.drawable.stat_sys_data_fully_connected_g,
               R.drawable.stat_sys_data_fully_connected_g,
               R.drawable.stat_sys_data_fully_connected_g }
         };
 
+    static final int[] QS_DATA_G = {
+        R.drawable.ic_qs_signal_g,
+        R.drawable.ic_qs_signal_full_g
+    };
+
     static final int[][] DATA_3G = {
-            { R.drawable.stat_sys_data_connected_3g,
-              R.drawable.stat_sys_data_connected_3g,
-              R.drawable.stat_sys_data_connected_3g,
-              R.drawable.stat_sys_data_connected_3g },
+            { R.drawable.stat_sys_data_fully_connected_3g,
+              R.drawable.stat_sys_data_fully_connected_3g,
+              R.drawable.stat_sys_data_fully_connected_3g,
+              R.drawable.stat_sys_data_fully_connected_3g },
             { R.drawable.stat_sys_data_fully_connected_3g,
               R.drawable.stat_sys_data_fully_connected_3g,
               R.drawable.stat_sys_data_fully_connected_3g,
               R.drawable.stat_sys_data_fully_connected_3g }
         };
 
+    static final int[] QS_DATA_3G = {
+        R.drawable.ic_qs_signal_3g,
+        R.drawable.ic_qs_signal_full_3g
+    };
+
     static final int[][] DATA_E = {
-            { R.drawable.stat_sys_data_connected_e,
-              R.drawable.stat_sys_data_connected_e,
-              R.drawable.stat_sys_data_connected_e,
-              R.drawable.stat_sys_data_connected_e },
+            { R.drawable.stat_sys_data_fully_connected_e,
+              R.drawable.stat_sys_data_fully_connected_e,
+              R.drawable.stat_sys_data_fully_connected_e,
+              R.drawable.stat_sys_data_fully_connected_e },
             { R.drawable.stat_sys_data_fully_connected_e,
               R.drawable.stat_sys_data_fully_connected_e,
               R.drawable.stat_sys_data_fully_connected_e,
               R.drawable.stat_sys_data_fully_connected_e }
         };
 
+    static final int[] QS_DATA_E = {
+        R.drawable.ic_qs_signal_e,
+        R.drawable.ic_qs_signal_full_e
+    };
+
     //3.5G
     static final int[][] DATA_H = {
-            { R.drawable.stat_sys_data_connected_h,
-              R.drawable.stat_sys_data_connected_h,
-              R.drawable.stat_sys_data_connected_h,
-              R.drawable.stat_sys_data_connected_h },
+            { R.drawable.stat_sys_data_fully_connected_h,
+              R.drawable.stat_sys_data_fully_connected_h,
+              R.drawable.stat_sys_data_fully_connected_h,
+              R.drawable.stat_sys_data_fully_connected_h },
             { R.drawable.stat_sys_data_fully_connected_h,
               R.drawable.stat_sys_data_fully_connected_h,
               R.drawable.stat_sys_data_fully_connected_h,
               R.drawable.stat_sys_data_fully_connected_h }
     };
 
+    static final int[] QS_DATA_H = {
+                R.drawable.ic_qs_signal_h,
+                R.drawable.ic_qs_signal_full_h
+    };
+
     //CDMA
     // Use 3G icons for EVDO data and 1x icons for 1XRTT data
     static final int[][] DATA_1X = {
-            { R.drawable.stat_sys_data_connected_1x,
-              R.drawable.stat_sys_data_connected_1x,
-              R.drawable.stat_sys_data_connected_1x,
-              R.drawable.stat_sys_data_connected_1x },
+            { R.drawable.stat_sys_data_fully_connected_1x,
+              R.drawable.stat_sys_data_fully_connected_1x,
+              R.drawable.stat_sys_data_fully_connected_1x,
+              R.drawable.stat_sys_data_fully_connected_1x },
             { R.drawable.stat_sys_data_fully_connected_1x,
               R.drawable.stat_sys_data_fully_connected_1x,
               R.drawable.stat_sys_data_fully_connected_1x,
               R.drawable.stat_sys_data_fully_connected_1x }
             };
 
+    static final int[] QS_DATA_1X = {
+        R.drawable.ic_qs_signal_1x,
+        R.drawable.ic_qs_signal_full_1x
+    };
+
     // LTE and eHRPD
     static final int[][] DATA_4G = {
-            { R.drawable.stat_sys_data_connected_4g,
-              R.drawable.stat_sys_data_connected_4g,
-              R.drawable.stat_sys_data_connected_4g,
-              R.drawable.stat_sys_data_connected_4g },
+            { R.drawable.stat_sys_data_fully_connected_4g,
+              R.drawable.stat_sys_data_fully_connected_4g,
+              R.drawable.stat_sys_data_fully_connected_4g,
+              R.drawable.stat_sys_data_fully_connected_4g },
             { R.drawable.stat_sys_data_fully_connected_4g,
               R.drawable.stat_sys_data_fully_connected_4g,
               R.drawable.stat_sys_data_fully_connected_4g,
               R.drawable.stat_sys_data_fully_connected_4g }
         };
 
+    static final int[] QS_DATA_4G = {
+        R.drawable.ic_qs_signal_4g,
+        R.drawable.ic_qs_signal_full_4g
+    };
+
     // LTE branded "LTE"
     static final int[][] DATA_LTE = {
-            { R.drawable.stat_sys_data_connected_lte,
-                    R.drawable.stat_sys_data_connected_lte,
-                    R.drawable.stat_sys_data_connected_lte,
-                    R.drawable.stat_sys_data_connected_lte },
+            { R.drawable.stat_sys_data_fully_connected_lte,
+                    R.drawable.stat_sys_data_fully_connected_lte,
+                    R.drawable.stat_sys_data_fully_connected_lte,
+                    R.drawable.stat_sys_data_fully_connected_lte },
             { R.drawable.stat_sys_data_fully_connected_lte,
                     R.drawable.stat_sys_data_fully_connected_lte,
                     R.drawable.stat_sys_data_fully_connected_lte,
                     R.drawable.stat_sys_data_fully_connected_lte }
     };
 
+    static final int[] QS_DATA_LTE = {
+        R.drawable.ic_qs_signal_lte,
+        R.drawable.ic_qs_signal_full_lte
+    };
+
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
deleted file mode 100644
index 70f9ac8..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.policy;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.Vibrator;
-import android.media.AudioManager;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.widget.CompoundButton;
-
-import com.android.systemui.settings.ToggleSlider;
-
-public class VolumeController implements ToggleSlider.Listener {
-    private static final String TAG = "StatusBar.VolumeController";
-    private static final int STREAM = AudioManager.STREAM_NOTIFICATION;
-
-    private Context mContext;
-    private ToggleSlider mControl;
-    private AudioManager mAudioManager;
-
-    private boolean mMute;
-    private int mVolume;
-    // Is there a vibrator
-    private final boolean mHasVibrator;
-
-    public VolumeController(Context context, ToggleSlider control) {
-        mContext = context;
-        mControl = control;
-
-        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
-
-        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
-
-        mMute = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
-        mVolume = mAudioManager.getStreamVolume(STREAM);
-
-        control.setOnChangedListener(this);
-    }
-
-    @Override
-    public void onInit(ToggleSlider control) {
-        control.setMax(mAudioManager.getStreamMaxVolume(STREAM));
-        control.setValue(mVolume);
-        control.setChecked(mMute);
-    }
-
-    public void onChanged(ToggleSlider view, boolean tracking, boolean mute, int level) {
-        if (!tracking) {
-            if (mute) {
-                mAudioManager.setRingerMode(
-                        mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
-                                     : AudioManager.RINGER_MODE_SILENT);
-            } else {
-                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-                mAudioManager.setStreamVolume(STREAM, level, AudioManager.FLAG_PLAY_SOUND);
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
index 8cc0338..57ddf7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -21,10 +21,10 @@
 class WifiIcons {
     static final int[][] WIFI_SIGNAL_STRENGTH = {
             { R.drawable.stat_sys_wifi_signal_0,
-              R.drawable.stat_sys_wifi_signal_1,
-              R.drawable.stat_sys_wifi_signal_2,
-              R.drawable.stat_sys_wifi_signal_3,
-              R.drawable.stat_sys_wifi_signal_4 },
+              R.drawable.stat_sys_wifi_signal_1_fully,
+              R.drawable.stat_sys_wifi_signal_2_fully,
+              R.drawable.stat_sys_wifi_signal_3_fully,
+              R.drawable.stat_sys_wifi_signal_4_fully },
             { R.drawable.stat_sys_wifi_signal_0,
               R.drawable.stat_sys_wifi_signal_1_fully,
               R.drawable.stat_sys_wifi_signal_2_fully,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
index d3d4338..4877828 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
@@ -1,28 +1,27 @@
-/*

- * 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.

- */

-

-package com.android.systemui.statusbar.policy;

-

-import com.android.systemui.statusbar.policy.TelephonyIcons;

-import com.android.systemui.R;

-

-class WimaxIcons {

-    static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH;

-

-    static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0];

-

-    static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon

-}

+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.statusbar.policy.TelephonyIcons;
+
+class WimaxIcons {
+    static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH;
+
+    static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0];
+
+    static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
deleted file mode 100644
index 8c4ae19..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.tablet;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.RemoteException;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-
-import com.android.systemui.R;
-
-public class CompatModePanel extends FrameLayout implements StatusBarPanel,
-        View.OnClickListener {
-    private static final boolean DEBUG = TabletStatusBar.DEBUG;
-    private static final String TAG = "CompatModePanel";
-
-    private ActivityManager mAM;
-
-    private boolean mAttached = false;
-    private Context mContext;
-    private RadioButton mOnButton, mOffButton;
-
-    private View mTrigger;
-//    private InputMethodButton mInputMethodSwitchButton;
-
-    public CompatModePanel(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-        mAM = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-    }
-
-    @Override
-    public void onFinishInflate() {
-        mOnButton  = (RadioButton) findViewById(R.id.compat_mode_on_radio);
-        mOffButton = (RadioButton) findViewById(R.id.compat_mode_off_radio);
-        mOnButton.setOnClickListener(this);
-        mOffButton.setOnClickListener(this);
-
-        refresh();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mAttached) {
-            mAttached = false;
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (!mAttached) {
-            mAttached = true;
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v == mOnButton) {
-            mAM.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_ENABLED);
-        } else if (v == mOffButton) {
-            mAM.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_DISABLED);
-        }
-    }
-
-    @Override
-    public boolean isInContentArea(int x, int y) {
-        return false;
-    }
-
-    @Override
-    public boolean dispatchHoverEvent(MotionEvent event) {
-        // Ignore hover events outside of this panel bounds since such events
-        // generate spurious accessibility events with the panel content when
-        // tapping outside of it, thus confusing the user.
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
-            return super.dispatchHoverEvent(event);
-        }
-        return true;
-    }
-
-    public void setTrigger(View v) {
-        mTrigger = v;
-    }
-
-    public void openPanel() {
-        setVisibility(View.VISIBLE);
-        if (mTrigger != null) mTrigger.setSelected(true);
-        refresh();
-    }
-
-    public void closePanel() {
-        setVisibility(View.GONE);
-        if (mTrigger != null) mTrigger.setSelected(false);
-    }
-
-    private void refresh() {
-        int mode = mAM.getFrontActivityScreenCompatMode();
-        if (mode == ActivityManager.COMPAT_MODE_ALWAYS
-                || mode == ActivityManager.COMPAT_MODE_NEVER) {
-            // No longer have something to switch.
-            closePanel();
-            return;
-        }
-        final boolean on = (mode == ActivityManager.COMPAT_MODE_ENABLED);
-        mOnButton.setChecked(on);
-        mOffButton.setChecked(!on);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
deleted file mode 100644
index fa8aa6d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.content.Context;
-import android.os.IBinder;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-import java.util.List;
-
-public class InputMethodButton extends ImageView {
-
-    private static final String  TAG = "StatusBar/InputMethodButton";
-    private static final boolean DEBUG = false;
-
-    // These values are defined in Settings application.
-    private static final int ID_IME_BUTTON_VISIBILITY_AUTO = 0;
-    private static final int ID_IME_BUTTON_VISIBILITY_ALWAYS_SHOW = 1;
-    private static final int ID_IME_BUTTON_VISIBILITY_ALWAYS_HIDE = 2;
-
-    // other services we wish to talk to
-    private final InputMethodManager mImm;
-    private final int mId;
-    private ImageView mIcon;
-    private IBinder mToken;
-    private boolean mShowButton = false;
-    private boolean mScreenLocked = false;
-    private boolean mHardKeyboardAvailable;
-
-    // Please refer to InputMethodManagerService.TAG_TRY_SUPPRESSING_IME_SWITCHER
-    private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
-
-    public InputMethodButton(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        // Resource Id of the input method button. This id is defined in status_bar.xml
-        mId = getId();
-        // IME hookup
-        mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        mIcon = (ImageView) findViewById(mId);
-
-        refreshStatusIcon();
-    }
-
-    // Refer to InputMethodManagerService.needsToShowImeSwitchOngoingNotification()
-    private boolean needsToShowIMEButtonWhenVisibilityAuto() {
-        List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
-        final int N = imis.size();
-        if (N > 2) return true;
-        if (N < 1) return false;
-        int nonAuxCount = 0;
-        int auxCount = 0;
-        InputMethodSubtype nonAuxSubtype = null;
-        InputMethodSubtype auxSubtype = null;
-        for(int i = 0; i < N; ++i) {
-            final InputMethodInfo imi = imis.get(i);
-            final List<InputMethodSubtype> subtypes = mImm.getEnabledInputMethodSubtypeList(
-                    imi, true);
-            final int subtypeCount = subtypes.size();
-            if (subtypeCount == 0) {
-                ++nonAuxCount;
-            } else {
-                for (int j = 0; j < subtypeCount; ++j) {
-                    final InputMethodSubtype subtype = subtypes.get(j);
-                    if (!subtype.isAuxiliary()) {
-                        ++nonAuxCount;
-                        nonAuxSubtype = subtype;
-                    } else {
-                        ++auxCount;
-                        auxSubtype = subtype;
-                    }
-                }
-            }
-        }
-        if (nonAuxCount > 1 || auxCount > 1) {
-            return true;
-        } else if (nonAuxCount == 1 && auxCount == 1) {
-            if (nonAuxSubtype != null && auxSubtype != null
-                    && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
-                            || auxSubtype.overridesImplicitlyEnabledSubtype()
-                            || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
-                    && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private boolean needsToShowIMEButton() {
-        if (!mShowButton || mScreenLocked) return false;
-
-        if (mHardKeyboardAvailable) {
-            return true;
-        }
-
-        final int visibility = loadInputMethodSelectorVisibility();
-        switch (visibility) {
-            case ID_IME_BUTTON_VISIBILITY_AUTO:
-                return needsToShowIMEButtonWhenVisibilityAuto();
-            case ID_IME_BUTTON_VISIBILITY_ALWAYS_SHOW:
-                return true;
-            case ID_IME_BUTTON_VISIBILITY_ALWAYS_HIDE:
-                return false;
-        }
-        return false;
-    }
-
-    private void refreshStatusIcon() {
-        if (mIcon == null) {
-            return;
-        }
-        if (!needsToShowIMEButton()) {
-            setVisibility(View.GONE);
-            return;
-        } else {
-            setVisibility(View.VISIBLE);
-        }
-        mIcon.setImageResource(R.drawable.ic_sysbar_ime);
-    }
-
-    private int loadInputMethodSelectorVisibility() {
-        return Settings.Secure.getInt(getContext().getContentResolver(),
-                Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, ID_IME_BUTTON_VISIBILITY_AUTO);
-    }
-
-    public void setIconImage(int resId) {
-        if (mIcon != null) {
-            mIcon.setImageResource(resId);
-        }
-    }
-
-    public void setImeWindowStatus(IBinder token, boolean showButton) {
-        mToken = token;
-        mShowButton = showButton;
-        refreshStatusIcon();
-    }
-
-    public void setHardKeyboardStatus(boolean available) {
-        if (mHardKeyboardAvailable != available) {
-            mHardKeyboardAvailable = available;
-            refreshStatusIcon();
-        }
-    }
-
-    public void setScreenLocked(boolean locked) {
-        mScreenLocked = locked;
-        refreshStatusIcon();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
deleted file mode 100644
index 8924087..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.tablet;
-
-import com.android.systemui.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.IBinder;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Pair;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-public class InputMethodsPanel extends LinearLayout implements StatusBarPanel,
-        View.OnClickListener {
-    private static final boolean DEBUG = TabletStatusBar.DEBUG;
-    private static final String TAG = "InputMethodsPanel";
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            onPackageChanged();
-        }
-    };
-
-    private final InputMethodManager mImm;
-    private final IntentFilter mIntentFilter = new IntentFilter();
-    private final HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>> mRadioViewAndImiMap =
-            new HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>>();
-    private final TreeMap<InputMethodInfo, List<InputMethodSubtype>>
-            mEnabledInputMethodAndSubtypesCache =
-                    new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
-                            new InputMethodComparator());
-
-    private boolean mAttached = false;
-    private boolean mPackageChanged = false;
-    private Context mContext;
-    private IBinder mToken;
-    private InputMethodButton mInputMethodSwitchButton;
-    private LinearLayout mInputMethodMenuList;
-    private boolean mHardKeyboardAvailable;
-    private boolean mHardKeyboardEnabled;
-    private OnHardKeyboardEnabledChangeListener mHardKeyboardEnabledChangeListener;
-    private LinearLayout mHardKeyboardSection;
-    private Switch mHardKeyboardSwitch;
-    private PackageManager mPackageManager;
-    private String mEnabledInputMethodAndSubtypesCacheStr;
-    private String mLastSystemLocaleString;
-    private View mConfigureImeShortcut;
-
-    private class InputMethodComparator implements Comparator<InputMethodInfo> {
-        @Override
-        public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
-            if (imi2 == null) return 0;
-            if (imi1 == null) return 1;
-            if (mPackageManager == null) {
-                return imi1.getId().compareTo(imi2.getId());
-            }
-            CharSequence imiId1 = imi1.loadLabel(mPackageManager) + "/" + imi1.getId();
-            CharSequence imiId2 = imi2.loadLabel(mPackageManager) + "/" + imi2.getId();
-            return imiId1.toString().compareTo(imiId2.toString());
-        }
-    }
-
-    public InputMethodsPanel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public InputMethodsPanel(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mContext = context;
-        mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
-        mIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-        mIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        mIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        mIntentFilter.addDataScheme("package");
-    }
-
-    public void setHardKeyboardEnabledChangeListener(
-            OnHardKeyboardEnabledChangeListener listener) {
-        mHardKeyboardEnabledChangeListener = listener;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mAttached) {
-            getContext().unregisterReceiver(mBroadcastReceiver);
-            mAttached = false;
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (!mAttached) {
-            getContext().registerReceiver(mBroadcastReceiver, mIntentFilter);
-            mAttached = true;
-        }
-    }
-
-    @Override
-    public void onFinishInflate() {
-        mInputMethodMenuList = (LinearLayout) findViewById(R.id.input_method_menu_list);
-        mHardKeyboardSection = (LinearLayout) findViewById(R.id.hard_keyboard_section);
-        mHardKeyboardSwitch = (Switch) findViewById(R.id.hard_keyboard_switch);
-        mConfigureImeShortcut = findViewById(R.id.ime_settings_shortcut);
-        mConfigureImeShortcut.setOnClickListener(this);
-        // TODO: If configurations for IME are not changed, do not update
-        // by checking onConfigurationChanged.
-        updateUiElements();
-    }
-
-    @Override
-    public boolean isInContentArea(int x, int y) {
-        return false;
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (view == mConfigureImeShortcut) {
-            showConfigureInputMethods();
-            closePanel(true);
-        }
-    }
-
-    @Override
-    public boolean dispatchHoverEvent(MotionEvent event) {
-        // Ignore hover events outside of this panel bounds since such events
-        // generate spurious accessibility events with the panel content when
-        // tapping outside of it, thus confusing the user.
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
-            return super.dispatchHoverEvent(event);
-        }
-        return true;
-    }
-
-    private void updateHardKeyboardEnabled() {
-        if (mHardKeyboardAvailable) {
-            final boolean checked = mHardKeyboardSwitch.isChecked();
-            if (mHardKeyboardEnabled != checked) {
-                mHardKeyboardEnabled = checked;
-                if (mHardKeyboardEnabledChangeListener != null)
-                    mHardKeyboardEnabledChangeListener.onHardKeyboardEnabledChange(checked);
-            }
-        }
-    }
-
-    public void openPanel() {
-        setVisibility(View.VISIBLE);
-        updateUiElements();
-        if (mInputMethodSwitchButton != null) {
-            mInputMethodSwitchButton.setIconImage(R.drawable.ic_sysbar_ime_pressed);
-        }
-    }
-
-    public void closePanel(boolean closeKeyboard) {
-        setVisibility(View.GONE);
-        if (mInputMethodSwitchButton != null) {
-            mInputMethodSwitchButton.setIconImage(R.drawable.ic_sysbar_ime);
-        }
-        if (closeKeyboard) {
-            mImm.hideSoftInputFromWindow(getWindowToken(), 0);
-        }
-    }
-
-    private void startActivity(Intent intent) {
-        mContext.startActivity(intent);
-    }
-
-    private void showConfigureInputMethods() {
-        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        startActivity(intent);
-    }
-
-    private View createInputMethodItem(
-            final InputMethodInfo imi, final InputMethodSubtype subtype) {
-        final CharSequence subtypeName;
-        if (subtype == null || subtype.overridesImplicitlyEnabledSubtype()) {
-            subtypeName = null;
-        } else {
-            subtypeName = getSubtypeName(imi, subtype);
-        }
-        final CharSequence imiName = getIMIName(imi);
-        final Drawable icon = getSubtypeIcon(imi, subtype);
-        final View view = View.inflate(mContext, R.layout.system_bar_input_methods_item, null);
-        final ImageView subtypeIcon = (ImageView)view.findViewById(R.id.item_icon);
-        final TextView itemTitle = (TextView)view.findViewById(R.id.item_title);
-        final TextView itemSubtitle = (TextView)view.findViewById(R.id.item_subtitle);
-        final ImageView settingsIcon = (ImageView)view.findViewById(R.id.item_settings_icon);
-        final View subtypeView = view.findViewById(R.id.item_subtype);
-        if (subtypeName == null) {
-            itemTitle.setText(imiName);
-            itemSubtitle.setVisibility(View.GONE);
-        } else {
-            itemTitle.setText(subtypeName);
-            itemSubtitle.setVisibility(View.VISIBLE);
-            itemSubtitle.setText(imiName);
-        }
-        subtypeIcon.setImageDrawable(icon);
-        subtypeIcon.setContentDescription(itemTitle.getText());
-        final String settingsActivity = imi.getSettingsActivity();
-        if (!TextUtils.isEmpty(settingsActivity)) {
-            settingsIcon.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View arg0) {
-                    Intent intent = new Intent(Intent.ACTION_MAIN);
-                    intent.setClassName(imi.getPackageName(), settingsActivity);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
-                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                    startActivity(intent);
-                    closePanel(true);
-                }
-            });
-        } else {
-            // Do not show the settings icon if the IME does not have a settings preference
-            view.findViewById(R.id.item_vertical_separator).setVisibility(View.GONE);
-            settingsIcon.setVisibility(View.GONE);
-        }
-        mRadioViewAndImiMap.put(
-                subtypeView, new Pair<InputMethodInfo, InputMethodSubtype> (imi, subtype));
-        subtypeView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype =
-                        updateRadioButtonsByView(v);
-                closePanel(false);
-                setInputMethodAndSubtype(imiAndSubtype.first, imiAndSubtype.second);
-            }
-        });
-        return view;
-    }
-
-    private void updateUiElements() {
-        updateHardKeyboardSection();
-
-        // TODO: Reuse subtype views.
-        mInputMethodMenuList.removeAllViews();
-        mRadioViewAndImiMap.clear();
-        mPackageManager = mContext.getPackageManager();
-
-        Map<InputMethodInfo, List<InputMethodSubtype>> enabledIMIs =
-                getEnabledInputMethodAndSubtypeList();
-        Set<InputMethodInfo> cachedImiSet = enabledIMIs.keySet();
-        for (InputMethodInfo imi: cachedImiSet) {
-            List<InputMethodSubtype> subtypes = enabledIMIs.get(imi);
-            if (subtypes == null || subtypes.size() == 0) {
-                mInputMethodMenuList.addView(
-                        createInputMethodItem(imi, null));
-                continue;
-            }
-            for (InputMethodSubtype subtype: subtypes) {
-                mInputMethodMenuList.addView(createInputMethodItem(imi, subtype));
-            }
-        }
-        updateRadioButtons();
-    }
-
-    public void setImeToken(IBinder token) {
-        mToken = token;
-    }
-
-    public void setImeSwitchButton(InputMethodButton imb) {
-        mInputMethodSwitchButton = imb;
-    }
-
-    private void setInputMethodAndSubtype(InputMethodInfo imi, InputMethodSubtype subtype) {
-        if (mToken != null) {
-            mImm.setInputMethodAndSubtype(mToken, imi.getId(), subtype);
-        } else {
-            Log.w(TAG, "IME Token is not set yet.");
-        }
-    }
-
-    public void setHardKeyboardStatus(boolean available, boolean enabled) {
-        if (mHardKeyboardAvailable != available || mHardKeyboardEnabled != enabled) {
-            mHardKeyboardAvailable = available;
-            mHardKeyboardEnabled = enabled;
-            updateHardKeyboardSection();
-        }
-    }
-
-    private void updateHardKeyboardSection() {
-        if (mHardKeyboardAvailable) {
-            mHardKeyboardSection.setVisibility(View.VISIBLE);
-            if (mHardKeyboardSwitch.isChecked() != mHardKeyboardEnabled) {
-                mHardKeyboardSwitch.setChecked(mHardKeyboardEnabled);
-                updateHardKeyboardEnabled();
-            }
-        } else {
-            mHardKeyboardSection.setVisibility(View.GONE);
-        }
-    }
-
-    // Turn on the selected radio button when the user chooses the item
-    private Pair<InputMethodInfo, InputMethodSubtype> updateRadioButtonsByView(View selectedView) {
-        Pair<InputMethodInfo, InputMethodSubtype> selectedImiAndSubtype = null;
-        if (mRadioViewAndImiMap.containsKey(selectedView)) {
-            for (View radioView: mRadioViewAndImiMap.keySet()) {
-                RadioButton subtypeRadioButton =
-                        (RadioButton) radioView.findViewById(R.id.item_radio);
-                if (subtypeRadioButton == null) {
-                    Log.w(TAG, "RadioButton was not found in the selected subtype view");
-                    return null;
-                }
-                if (radioView == selectedView) {
-                    Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype =
-                        mRadioViewAndImiMap.get(radioView);
-                    selectedImiAndSubtype = imiAndSubtype;
-                    subtypeRadioButton.setChecked(true);
-                } else {
-                    subtypeRadioButton.setChecked(false);
-                }
-            }
-        }
-        return selectedImiAndSubtype;
-    }
-
-    private void updateRadioButtons() {
-        updateRadioButtonsByImiAndSubtype(
-                getCurrentInputMethodInfo(), mImm.getCurrentInputMethodSubtype());
-    }
-
-    // Turn on the selected radio button at startup
-    private void updateRadioButtonsByImiAndSubtype(
-            InputMethodInfo imi, InputMethodSubtype subtype) {
-        if (imi == null) return;
-        if (DEBUG) {
-            Log.d(TAG, "Update radio buttons by " + imi.getId() + ", " + subtype);
-        }
-        for (View radioView: mRadioViewAndImiMap.keySet()) {
-            RadioButton subtypeRadioButton =
-                    (RadioButton) radioView.findViewById(R.id.item_radio);
-            if (subtypeRadioButton == null) {
-                Log.w(TAG, "RadioButton was not found in the selected subtype view");
-                return;
-            }
-            Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype =
-                    mRadioViewAndImiMap.get(radioView);
-            if (imiAndSubtype.first.getId().equals(imi.getId())
-                    && (imiAndSubtype.second == null || imiAndSubtype.second.equals(subtype))) {
-                subtypeRadioButton.setChecked(true);
-            } else {
-                subtypeRadioButton.setChecked(false);
-            }
-        }
-    }
-
-    private TreeMap<InputMethodInfo, List<InputMethodSubtype>>
-            getEnabledInputMethodAndSubtypeList() {
-        String newEnabledIMIs = Settings.Secure.getString(
-                mContext.getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS);
-        String currentSystemLocaleString =
-                mContext.getResources().getConfiguration().locale.toString();
-        if (!TextUtils.equals(mEnabledInputMethodAndSubtypesCacheStr, newEnabledIMIs)
-                || !TextUtils.equals(mLastSystemLocaleString, currentSystemLocaleString)
-                || mPackageChanged) {
-            mEnabledInputMethodAndSubtypesCache.clear();
-            final List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
-            for (InputMethodInfo imi: imis) {
-                mEnabledInputMethodAndSubtypesCache.put(imi,
-                        mImm.getEnabledInputMethodSubtypeList(imi, true));
-            }
-            mEnabledInputMethodAndSubtypesCacheStr = newEnabledIMIs;
-            mPackageChanged = false;
-            mLastSystemLocaleString = currentSystemLocaleString;
-        }
-        return mEnabledInputMethodAndSubtypesCache;
-    }
-
-    private InputMethodInfo getCurrentInputMethodInfo() {
-        String curInputMethodId = Settings.Secure.getString(getContext()
-                .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
-        Set<InputMethodInfo> cachedImiSet = mEnabledInputMethodAndSubtypesCache.keySet();
-        // 1. Search IMI in cache
-        for (InputMethodInfo imi: cachedImiSet) {
-            if (imi.getId().equals(curInputMethodId)) {
-                return imi;
-            }
-        }
-        // 2. Get current enabled IMEs and search IMI
-        cachedImiSet = getEnabledInputMethodAndSubtypeList().keySet();
-        for (InputMethodInfo imi: cachedImiSet) {
-            if (imi.getId().equals(curInputMethodId)) {
-                return imi;
-            }
-        }
-        return null;
-    }
-
-    private CharSequence getIMIName(InputMethodInfo imi) {
-        if (imi == null) return null;
-        return imi.loadLabel(mPackageManager);
-    }
-
-    private CharSequence getSubtypeName(InputMethodInfo imi, InputMethodSubtype subtype) {
-        if (imi == null || subtype == null) return null;
-        if (DEBUG) {
-            Log.d(TAG, "Get text from: " + imi.getPackageName() + subtype.getNameResId()
-                    + imi.getServiceInfo().applicationInfo);
-        }
-        return subtype.getDisplayName(
-                mContext, imi.getPackageName(), imi.getServiceInfo().applicationInfo);
-    }
-
-    private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
-        if (imi != null) {
-            if (DEBUG) {
-                Log.d(TAG, "Update icons of IME: " + imi.getPackageName());
-                if (subtype != null) {
-                    Log.d(TAG, "subtype =" + subtype.getLocale() + "," + subtype.getMode());
-                }
-            }
-            if (subtype != null) {
-                return mPackageManager.getDrawable(imi.getPackageName(), subtype.getIconResId(),
-                        imi.getServiceInfo().applicationInfo);
-            } else if (imi.getSubtypeCount() > 0) {
-                return mPackageManager.getDrawable(imi.getPackageName(),
-                        imi.getSubtypeAt(0).getIconResId(),
-                        imi.getServiceInfo().applicationInfo);
-            } else {
-                try {
-                    return mPackageManager.getApplicationInfo(
-                            imi.getPackageName(), 0).loadIcon(mPackageManager);
-                } catch (PackageManager.NameNotFoundException e) {
-                    Log.w(TAG, "IME can't be found: " + imi.getPackageName());
-                }
-            }
-        }
-        return null;
-    }
-
-    private void onPackageChanged() {
-        if (DEBUG) {
-            Log.d(TAG, "onPackageChanged.");
-        }
-        mPackageChanged = true;
-    }
-
-    public interface OnHardKeyboardEnabledChangeListener {
-        public void onHardKeyboardEnabledChange(boolean enabled);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java
deleted file mode 100644
index 42bdf3d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.tablet;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.LinearLayout;
-
-public class NotificationArea extends LinearLayout {
-
-    public NotificationArea(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        if (super.onRequestSendAccessibilityEvent(child, event)) {
-            // The event is coming from a descendant like battery but append
-            // the content of the entire notification area so accessibility
-            // services can choose how to present the content to the user.
-            AccessibilityEvent record = AccessibilityEvent.obtain();
-            onInitializeAccessibilityEvent(record);
-            dispatchPopulateAccessibilityEvent(record);
-            event.appendRecord(record);
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java
deleted file mode 100644
index 3d6c1a2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.ImageView;
-import android.view.MotionEvent;
-
-import com.android.systemui.R;
-
-
-public class NotificationIconArea extends RelativeLayout {
-    private static final String TAG = "NotificationIconArea";
-
-    IconLayout mIconLayout;
-
-    public NotificationIconArea(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mIconLayout = (IconLayout)findViewById(R.id.icons);
-    }
-
-    static class IconLayout extends LinearLayout {
-        public IconLayout(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public boolean onInterceptTouchEvent(MotionEvent e) {
-            return true;
-        }
-    }
-}
-
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationLinearLayout.java
deleted file mode 100644
index 9ecb2e4..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationLinearLayout.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-public class NotificationLinearLayout extends LinearLayout {
-    private static final String TAG = "NotificationLinearLayout";
-
-    Drawable mItemGlow;
-    int mInsetLeft;
-    Rect mTmp = new Rect();
-
-    public NotificationLinearLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationLinearLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        final Resources res = context.getResources();
-
-        mItemGlow = res.getDrawable(R.drawable.notify_item_glow_bottom);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationLinearLayout,
-                defStyle, 0);
-        mInsetLeft = a.getDimensionPixelSize(R.styleable.NotificationLinearLayout_insetLeft, 0);
-        a.recycle();
-    }
-
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-        setWillNotDraw(false);
-    }
-
-    @Override
-    public void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        final Rect padding = mTmp;
-        final Drawable glow = mItemGlow;
-        glow.getPadding(padding);
-        final int glowHeight = glow.getIntrinsicHeight();
-        final int insetLeft = mInsetLeft;
-
-        final int N = getChildCount();
-        for (int i=0; i<N; i++) {
-            final View child = getChildAt(i);
-
-            final int childBottom = child.getBottom();
-
-            glow.setBounds(child.getLeft() - padding.left + insetLeft, childBottom,
-                    child.getRight() - padding.right, childBottom + glowHeight);
-            glow.draw(canvas);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
deleted file mode 100644
index 87fc6fc..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-
-import com.android.systemui.ExpandHelper;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NotificationRowLayout;
-
-public class NotificationPanel extends RelativeLayout implements StatusBarPanel,
-        View.OnClickListener {
-    private ExpandHelper mExpandHelper;
-    private NotificationRowLayout latestItems;
-
-    static final String TAG = "Tablet/NotificationPanel";
-    static final boolean DEBUG = false;
-
-    final static int PANEL_FADE_DURATION = 150;
-
-    boolean mShowing;
-    boolean mHasClearableNotifications = false;
-    int mNotificationCount = 0;
-    NotificationPanelTitle mTitleArea;
-    ImageView mSettingsButton;
-    ImageView mNotificationButton;
-    View mNotificationScroller;
-    ViewGroup mContentFrame;
-    Rect mContentArea = new Rect();
-    View mSettingsView;
-    ViewGroup mContentParent;
-    TabletStatusBar mBar;
-    View mClearButton;
-    static Interpolator sAccelerateInterpolator = new AccelerateInterpolator();
-    static Interpolator sDecelerateInterpolator = new DecelerateInterpolator();
-
-    // amount to slide mContentParent down by when mContentFrame is missing
-    float mContentFrameMissingTranslation;
-
-    Choreographer mChoreo = new Choreographer();
-
-    public NotificationPanel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationPanel(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public void setBar(TabletStatusBar b) {
-        mBar = b;
-    }
-
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-
-        setWillNotDraw(false);
-
-        mContentParent = (ViewGroup)findViewById(R.id.content_parent);
-        mContentParent.bringToFront();
-        mTitleArea = (NotificationPanelTitle) findViewById(R.id.title_area);
-        mTitleArea.setPanel(this);
-
-        mSettingsButton = (ImageView) findViewById(R.id.settings_button);
-        mNotificationButton = (ImageView) findViewById(R.id.notification_button);
-
-        mNotificationScroller = findViewById(R.id.notification_scroller);
-        mContentFrame = (ViewGroup)findViewById(R.id.content_frame);
-        mContentFrameMissingTranslation = 0; // not needed with current assets
-
-        // the "X" that appears in place of the clock when the panel is showing notifications
-        mClearButton = findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-
-        mShowing = false;
-    }
-
-    @Override
-    protected void onAttachedToWindow () {
-        super.onAttachedToWindow();
-        latestItems = (NotificationRowLayout) findViewById(R.id.content);
-        int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
-        int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
-        mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight);
-        mExpandHelper.setEventSource(this);
-        mExpandHelper.setGravity(Gravity.BOTTOM);
-    }
-
-    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            mBar.clearAll();
-        }
-    };
-
-    public View getClearButton() {
-        return mClearButton;
-    }
-
-    public void show(boolean show, boolean animate) {
-        if (animate) {
-            if (mShowing != show) {
-                mShowing = show;
-                if (show) {
-                    setVisibility(View.VISIBLE);
-                    // Don't start the animation until we've created the layer, which is done
-                    // right before we are drawn
-                    mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                    getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
-                } else {
-                    mChoreo.startAnimation(show);
-                }
-            }
-        } else {
-            mShowing = show;
-            setVisibility(show ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    /**
-     * This is used only when we've created a hardware layer and are waiting until it's
-     * been created in order to start the appearing animation.
-     */
-    private ViewTreeObserver.OnPreDrawListener mPreDrawListener =
-            new ViewTreeObserver.OnPreDrawListener() {
-        @Override
-        public boolean onPreDraw() {
-            getViewTreeObserver().removeOnPreDrawListener(this);
-            mChoreo.startAnimation(true);
-            return false;
-        }
-    };
-
-    /**
-     * Whether the panel is showing, or, if it's animating, whether it will be
-     * when the animation is done.
-     */
-    public boolean isShowing() {
-        return mShowing;
-    }
-
-    @Override
-    public void onVisibilityChanged(View v, int vis) {
-        super.onVisibilityChanged(v, vis);
-        // when we hide, put back the notifications
-        if (vis != View.VISIBLE) {
-            if (mSettingsView != null) removeSettingsView();
-            mNotificationScroller.setVisibility(View.VISIBLE);
-            mNotificationScroller.setAlpha(1f);
-            mNotificationScroller.scrollTo(0, 0);
-            updatePanelModeButtons();
-        }
-    }
-
-    @Override
-    public boolean dispatchHoverEvent(MotionEvent event) {
-        // Ignore hover events outside of this panel bounds since such events
-        // generate spurious accessibility events with the panel content when
-        // tapping outside of it, thus confusing the user.
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
-            return super.dispatchHoverEvent(event);
-        }
-        return true;
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-    final int keyCode = event.getKeyCode();
-        switch (keyCode) {
-            // We exclusively handle the back key by hiding this panel.
-            case KeyEvent.KEYCODE_BACK: {
-                if (event.getAction() == KeyEvent.ACTION_UP) {
-                    mBar.animateCollapsePanels();
-                }
-                return true;
-            }
-            // We react to the home key but let the system handle it.
-            case KeyEvent.KEYCODE_HOME: {
-                if (event.getAction() == KeyEvent.ACTION_UP) {
-                    mBar.animateCollapsePanels();
-                }
-            } break;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    /*
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-
-        if (DEBUG) Slog.d(TAG, String.format("PANEL: onLayout: (%d, %d, %d, %d)", l, t, r, b));
-    }
-
-    @Override
-    public void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        
-        if (DEBUG) {
-            Slog.d(TAG, String.format("PANEL: onSizeChanged: (%d -> %d, %d -> %d)",
-                        oldw, w, oldh, h));
-        }
-    }
-    */
-
-    public void onClick(View v) {
-        if (mSettingsButton.isEnabled() && v == mTitleArea) {
-            swapPanels();
-        }
-    }
-
-    public void setNotificationCount(int n) {
-        mNotificationCount = n;
-    }
-
-    public void setContentFrameVisible(final boolean showing, boolean animate) {
-    }
-
-    public void swapPanels() {
-        final View toShow, toHide;
-        if (mSettingsView == null) {
-            addSettingsView();
-            toShow = mSettingsView;
-            toHide = mNotificationScroller;
-        } else {
-            toShow = mNotificationScroller;
-            toHide = mSettingsView;
-        }
-        Animator a = ObjectAnimator.ofFloat(toHide, "alpha", 1f, 0f)
-                .setDuration(PANEL_FADE_DURATION);
-        a.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator _a) {
-                toHide.setVisibility(View.GONE);
-                if (toShow != null) {
-                    toShow.setVisibility(View.VISIBLE);
-                    if (toShow == mSettingsView || mNotificationCount > 0) {
-                        ObjectAnimator.ofFloat(toShow, "alpha", 0f, 1f)
-                                .setDuration(PANEL_FADE_DURATION)
-                                .start();
-                    }
-
-                    if (toHide == mSettingsView) {
-                        removeSettingsView();
-                    }
-                }
-                updateClearButton();
-                updatePanelModeButtons();
-            }
-        });
-        a.start();
-    }
- 
-    public void updateClearButton() {
-        if (mBar != null) {
-            final boolean showX 
-                = (isShowing()
-                        && mHasClearableNotifications
-                        && mNotificationScroller.getVisibility() == View.VISIBLE);
-            getClearButton().setVisibility(showX ? View.VISIBLE : View.INVISIBLE);
-        }
-    }
-
-    public void setClearable(boolean clearable) {
-        mHasClearableNotifications = clearable;
-    }
-
-    public void updatePanelModeButtons() {
-        final boolean settingsVisible = (mSettingsView != null);
-        mSettingsButton.setVisibility(!settingsVisible && mSettingsButton.isEnabled() ? View.VISIBLE : View.GONE);
-        mNotificationButton.setVisibility(settingsVisible ? View.VISIBLE : View.GONE);
-    }
-
-    public boolean isInContentArea(int x, int y) {
-        mContentArea.left = mContentFrame.getLeft() + mContentFrame.getPaddingLeft();
-        mContentArea.top = mContentFrame.getTop() + mContentFrame.getPaddingTop()
-            + (int)mContentParent.getTranslationY(); // account for any adjustment
-        mContentArea.right = mContentFrame.getRight() - mContentFrame.getPaddingRight();
-        mContentArea.bottom = mContentFrame.getBottom() - mContentFrame.getPaddingBottom();
-
-        offsetDescendantRectToMyCoords(mContentParent, mContentArea);
-        return mContentArea.contains(x, y);
-    }
-
-    void removeSettingsView() {
-        if (mSettingsView != null) {
-            mContentFrame.removeView(mSettingsView);
-            mSettingsView = null;
-        }
-    }
-
-    // NB: it will be invisible until you show it
-    void addSettingsView() {
-        LayoutInflater infl = LayoutInflater.from(getContext());
-        mSettingsView = infl.inflate(R.layout.system_bar_settings_view, mContentFrame, false);
-        mSettingsView.setVisibility(View.GONE);
-        mContentFrame.addView(mSettingsView);
-    }
-
-    private class Choreographer implements Animator.AnimatorListener {
-        boolean mVisible;
-        int mPanelHeight;
-        AnimatorSet mContentAnim;
-
-        // should group this into a multi-property animation
-        final static int OPEN_DURATION = 250;
-        final static int CLOSE_DURATION = 250;
-
-        // the panel will start to appear this many px from the end
-        final int HYPERSPACE_OFFRAMP = 200;
-
-        Choreographer() {
-        }
-
-        void createAnimation(boolean appearing) {
-            // mVisible: previous state; appearing: new state
-            
-            float start, end;
-
-            // 0: on-screen
-            // height: off-screen
-            float y = mContentParent.getTranslationY();
-            if (appearing) {
-                // we want to go from near-the-top to the top, unless we're half-open in the right
-                // general vicinity
-                end = 0;
-                if (mNotificationCount == 0) {
-                    end += mContentFrameMissingTranslation;
-                }
-                start = HYPERSPACE_OFFRAMP+end;
-            } else {
-                start = y;
-                end = y + HYPERSPACE_OFFRAMP;
-            }
-
-            Animator posAnim = ObjectAnimator.ofFloat(mContentParent, "translationY",
-                    start, end);
-            posAnim.setInterpolator(appearing ? sDecelerateInterpolator : sAccelerateInterpolator);
-
-            if (mContentAnim != null && mContentAnim.isRunning()) {
-                mContentAnim.cancel();
-            }
-
-            Animator fadeAnim = ObjectAnimator.ofFloat(mContentParent, "alpha",
-                    appearing ? 1.0f : 0.0f);
-            fadeAnim.setInterpolator(appearing ? sAccelerateInterpolator : sDecelerateInterpolator);
-
-            mContentAnim = new AnimatorSet();
-            mContentAnim
-                .play(fadeAnim)
-                .with(posAnim)
-                ;
-            mContentAnim.setDuration((DEBUG?10:1)*(appearing ? OPEN_DURATION : CLOSE_DURATION));
-            mContentAnim.addListener(this);
-        }
-
-        void startAnimation(boolean appearing) {
-            if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
-
-            createAnimation(appearing);
-            mContentAnim.start();
-
-            mVisible = appearing;
-
-            // we want to start disappearing promptly
-            if (!mVisible) updateClearButton();
-        }
-
-        public void onAnimationCancel(Animator animation) {
-            if (DEBUG) Slog.d(TAG, "onAnimationCancel");
-        }
-
-        public void onAnimationEnd(Animator animation) {
-            if (DEBUG) Slog.d(TAG, "onAnimationEnd");
-            if (! mVisible) {
-                setVisibility(View.GONE);
-            }
-            mContentParent.setLayerType(View.LAYER_TYPE_NONE, null);
-            mContentAnim = null;
-
-            // we want to show the X lazily
-            if (mVisible) updateClearButton();
-        }
-
-        public void onAnimationRepeat(Animator animation) {
-        }
-
-        public void onAnimationStart(Animator animation) {
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        MotionEvent cancellation = MotionEvent.obtain(ev);
-        cancellation.setAction(MotionEvent.ACTION_CANCEL);
-
-        boolean intercept = mExpandHelper.onInterceptTouchEvent(ev) ||
-                super.onInterceptTouchEvent(ev);
-        if (intercept) {
-            latestItems.onInterceptTouchEvent(cancellation);
-        }
-        return intercept;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean handled = mExpandHelper.onTouchEvent(ev) ||
-                super.onTouchEvent(ev);
-        return handled;
-    }
-
-    public void setSettingsEnabled(boolean settingsEnabled) {
-        if (mSettingsButton != null) {
-            mSettingsButton.setEnabled(settingsEnabled);
-            mSettingsButton.setVisibility(settingsEnabled ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    public void refreshLayout(int layoutDirection) {
-        // Force asset reloading
-        mSettingsButton.setImageDrawable(null);
-        mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
-
-        // Force asset reloading
-        mNotificationButton.setImageDrawable(null);
-        mNotificationButton.setImageResource(R.drawable.ic_notifications);
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java
deleted file mode 100644
index d180ab9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.tablet;
-
-import java.util.ArrayList;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.SoundEffectConstants;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.RelativeLayout;
-
-import com.android.systemui.R;
-
-
-public class NotificationPanelTitle extends RelativeLayout implements View.OnClickListener {
-    private NotificationPanel mPanel;
-    private ArrayList<View> buttons;
-    private View mSettingsButton;
-
-    public NotificationPanelTitle(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        buttons = new ArrayList<View>();
-        setOnClickListener(this);
-    }
-
-    public void setPanel(NotificationPanel p) {
-        mPanel = p;
-    }
-
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-        buttons.add(mSettingsButton = findViewById(R.id.settings_button));
-        buttons.add(findViewById(R.id.notification_button));
-    }
-
-    @Override
-    public void setPressed(boolean pressed) {
-        super.setPressed(pressed);
-        for (View button : buttons) {
-            if (button != null) {
-                button.setPressed(pressed);
-            }
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent e) {
-        if (!mSettingsButton.isEnabled())
-            return false;
-        switch (e.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                setPressed(true);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                final int x = (int) e.getX();
-                final int y = (int) e.getY();
-                setPressed(x > 0 && x < getWidth() && y > 0 && y < getHeight());
-                break;
-            case MotionEvent.ACTION_UP:
-                if (isPressed()) {
-                    playSoundEffect(SoundEffectConstants.CLICK);
-                    mPanel.swapPanels();
-                    setPressed(false);
-                }
-                break;
-            case MotionEvent.ACTION_CANCEL:
-                setPressed(false);
-                break;
-        }
-        return true;
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (mSettingsButton.isEnabled() && v == this) {
-            mPanel.swapPanels();
-        }
-    }
-
-    @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        if (super.onRequestSendAccessibilityEvent(child, event)) {
-            AccessibilityEvent record = AccessibilityEvent.obtain();
-            onInitializeAccessibilityEvent(record);
-            dispatchPopulateAccessibilityEvent(record);
-            event.appendRecord(record);
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
deleted file mode 100644
index ba28306..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.RelativeLayout;
-
-public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel {
-    TabletStatusBar mBar;
-
-    public NotificationPeekPanel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationPeekPanel(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public boolean isInContentArea(int x, int y) {
-        final int l = getPaddingLeft();
-        final int r = getWidth() - getPaddingRight();
-        final int t = getPaddingTop();
-        final int b = getHeight() - getPaddingBottom();
-        return x >= l && x < r && y >= t && y < b;
-    }
-
-    public void setBar(TabletStatusBar bar) {
-        mBar = bar;
-    }
-
-    // We don't really want to intercept the touch event, but we *do* want to reset the fade timer
-    // in case the user is interacting with some custom controls or something.
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        mBar.resetNotificationPeekFadeTimer();
-        return false;
-    }
-
-    @Override
-    public boolean dispatchHoverEvent(MotionEvent event) {
-        // Ignore hover events outside of this panel bounds since such events
-        // generate spurious accessibility events with the panel content when
-        // tapping outside of it, thus confusing the user.
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
-            return super.dispatchHoverEvent(event);
-        }
-        return true;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/PanelBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/PanelBackgroundView.java
deleted file mode 100644
index 9ac933f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/PanelBackgroundView.java
+++ /dev/null
@@ -1,70 +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 com.android.systemui.statusbar.tablet;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class PanelBackgroundView extends View {
-    /*
-    private Bitmap mTexture;
-    private Paint mPaint;
-    private int mTextureWidth;
-    private int mTextureHeight;
-    */
-
-    public PanelBackgroundView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        /*
-        mTexture = BitmapFactory.decodeResource(getResources(),
-                com.android.internal.R.drawable.status_bar_background);
-        mTextureWidth = mTexture.getWidth();
-        mTextureHeight = mTexture.getHeight();
-
-        mPaint = new Paint();
-        mPaint.setDither(false);
-        */
-    }
-
-    @Override
-    public void onDraw(Canvas canvas) {
-        /*
-        final Bitmap texture = mTexture;
-        final Paint paint = mPaint;
-
-        final int width = getWidth();
-        final int height = getHeight();
-
-        final int textureWidth = mTextureWidth;
-        final int textureHeight = mTextureHeight;
-
-        int x = 0;
-        int y;
-
-        while (x < width) {
-            y = 0;
-            while (y < height) {
-                canvas.drawBitmap(texture, x, y, paint);
-                y += textureHeight;
-            }
-            x += textureWidth;
-        }
-        */
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
deleted file mode 100644
index e0dcbcd..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.app.StatusBarManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.widget.LinearLayout;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.settings.BrightnessController;
-import com.android.systemui.settings.ToggleSlider;
-import com.android.systemui.statusbar.policy.AirplaneModeController;
-import com.android.systemui.statusbar.policy.AutoRotateController;
-import com.android.systemui.statusbar.policy.DoNotDisturbController;
-import com.android.systemui.statusbar.policy.VolumeController;
-
-public class SettingsView extends LinearLayout implements View.OnClickListener {
-    static final String TAG = "SettingsView";
-
-    AirplaneModeController mAirplane;
-    AutoRotateController mRotate;
-    BrightnessController mBrightness;
-    DoNotDisturbController mDoNotDisturb;
-    View mRotationLockContainer;
-    View mRotationLockSeparator;
-
-    public SettingsView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SettingsView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        final Context context = getContext();
-
-        mAirplane = new AirplaneModeController(context,
-                (CompoundButton)findViewById(R.id.airplane_checkbox));
-        findViewById(R.id.network).setOnClickListener(this);
-
-        mRotationLockContainer = findViewById(R.id.rotate);
-        mRotationLockSeparator = findViewById(R.id.rotate_separator);
-        mRotate = new AutoRotateController(context,
-                (CompoundButton)findViewById(R.id.rotate_checkbox),
-                new AutoRotateController.RotationLockCallbacks() {
-                    @Override
-                    public void setRotationLockControlVisibility(boolean show) {
-                        mRotationLockContainer.setVisibility(show ? View.VISIBLE : View.GONE);
-                        mRotationLockSeparator.setVisibility(show ? View.VISIBLE : View.GONE);
-                    }
-                });
-
-        mBrightness = new BrightnessController(context,
-                (ImageView)findViewById(R.id.brightness_icon),
-                (ToggleSlider)findViewById(R.id.brightness));
-        mDoNotDisturb = new DoNotDisturbController(context,
-                (CompoundButton)findViewById(R.id.do_not_disturb_checkbox));
-        findViewById(R.id.settings).setOnClickListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mAirplane.release();
-        mDoNotDisturb.release();
-        mRotate.release();
-    }
-
-    public void onClick(View v) {
-        switch (v.getId()) {
-            case R.id.network:
-                onClickNetwork();
-                break;
-            case R.id.settings:
-                onClickSettings();
-                break;
-        }
-    }
-
-    private StatusBarManager getStatusBarManager() {
-        return (StatusBarManager)getContext().getSystemService(Context.STATUS_BAR_SERVICE);
-    }
-
-    // Network
-    // ----------------------------
-    private void onClickNetwork() {
-        getContext().startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-        getStatusBarManager().collapsePanels();
-    }
-
-    // Settings
-    // ----------------------------
-    private void onClickSettings() {
-        getContext().startActivityAsUser(new Intent(Settings.ACTION_SETTINGS)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
-                new UserHandle(UserHandle.USER_CURRENT));
-        getStatusBarManager().collapsePanels();
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
deleted file mode 100644
index 2924cc9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.DragEvent;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-public class ShirtPocket extends ImageView {
-    private static final boolean DEBUG = false;
-    private static final String  TAG = "StatusBar/ShirtPocket";
-
-    private ClipData mClipping = null;
-
-    private ImageView mPreviewIcon;
-
-    public static class DropZone extends View {
-        ShirtPocket mPocket;
-        public DropZone(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-        public void setPocket(ShirtPocket p) {
-            mPocket = p;
-        }
-
-        public void onAttachedToWindow() {
-            super.onAttachedToWindow();
-            if (mPocket.holding()) {
-                show(false);
-            } else {
-                hide(false);
-            }
-        }
-
-        // Drag API notes: we must be visible to receive drag events
-        private void show(boolean animate) {
-            setTranslationY(0f);
-            if (animate) {
-                setAlpha(0f);
-                ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).start();
-            } else {
-                setAlpha(1f);
-            }
-        }
-
-        private void hide(boolean animate) {
-            AnimatorListenerAdapter onEnd = new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator _a) {
-                    DropZone.this.setTranslationY(getHeight() + 2);
-                    DropZone.this.setAlpha(0f);
-                }
-            };
-            if (animate) {
-                Animator a = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 0f);
-                a.addListener(onEnd);
-                a.start();
-            } else {
-                onEnd.onAnimationEnd(null);
-            }
-        }
-
-        @Override
-        public boolean onDragEvent(DragEvent event) {
-            if (DEBUG) Slog.d(TAG, "onDragEvent: " + event);
-            switch (event.getAction()) {
-                // We want to appear whenever a potential drag takes off from anywhere in the UI.
-                case DragEvent.ACTION_DRAG_STARTED:
-                    show(true);
-                    break;
-                case DragEvent.ACTION_DRAG_ENTERED:
-                    if (DEBUG) Slog.d(TAG, "entered!");
-                    // XXX: TODO
-                    break;
-                case DragEvent.ACTION_DRAG_EXITED:
-                    if (DEBUG) Slog.d(TAG, "exited!");
-                    break;
-                case DragEvent.ACTION_DROP:
-                    if (DEBUG) Slog.d(TAG, "dropped!");
-                    mPocket.stash(event.getClipData());
-                    break;
-                case DragEvent.ACTION_DRAG_ENDED:
-                    hide(true);
-                    break;
-            }
-            return true; // we want everything, thank you
-        }
-    }
-
-    public ShirtPocket(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    // TODO: "pin area" panel, dragging things out
-    ObjectAnimator mAnimHide, mAnimShow;
-    
-    protected void onAttachedToWindow() {
-    }
-
-    public boolean holding() {
-        return (mClipping != null);
-    }
-
-    private void stash(ClipData clipping) {
-        mClipping = clipping;
-        if (mClipping != null) {
-            setVisibility(View.VISIBLE);
-            Bitmap icon = mClipping.getIcon();
-//            mDescription.setText(mClipping.getDescription().getLabel());
-            if (icon != null) {
-                setImageBitmap(icon);
-            } else {
-                if (mClipping.getItemCount() > 0) {
-                    // TODO: figure out how to visualize every kind of ClipData!
-                    //mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext()));
-                }
-            }
-        } else {
-            setVisibility(View.GONE);
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-        if (action == MotionEvent.ACTION_DOWN) {
-            final ClipData clip = mClipping;
-            if (clip != null) {
-                final Bitmap icon = clip.getIcon();
-                DragShadowBuilder shadow;
-                if (icon != null) {
-                    shadow = new DragShadowBuilder(this) {
-                        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
-                            shadowSize.set(icon.getWidth(), icon.getHeight());
-                            shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
-                        }
-                        public void onDrawShadow(Canvas canvas) {
-                            canvas.drawBitmap(icon, 0, 0, new Paint());
-                        }
-                    };
-                } else {
-                    // uhhh, what now?
-                    shadow = new DragShadowBuilder(this);
-                }
-
-                startDrag(clip, shadow, null, 0);
-
-                // TODO: only discard the clipping if it was accepted
-                stash(null);
-
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /*
-    private boolean isInViewContentArea(View v, int x, int y) {
-        final int l = v.getPaddingLeft();
-        final int r = v.getWidth() - v.getPaddingRight();
-        final int t = v.getPaddingTop();
-        final int b = v.getHeight() - v.getPaddingBottom();
-        return x >= l && x < r && y >= t && y < b;
-    }
-
-    View.OnTouchListener mWindowTouchListener = new View.OnTouchListener() {
-        public boolean onTouch(View v, MotionEvent ev) {
-            final int action = ev.getAction();
-            if (action == MotionEvent.ACTION_OUTSIDE
-                    || (action == MotionEvent.ACTION_DOWN
-                        && !isInViewContentArea(mWindow, (int)ev.getX(), (int)ev.getY()))) {
-                hideWindow();
-                return true;
-            } else if (action == MotionEvent.ACTION_DOWN) {
-                final ClipData clip = mClipping;
-                if (clip != null) {
-                    final Bitmap icon = clip.getIcon();
-                    DragShadowBuilder shadow;
-                    if (icon != null) {
-                        shadow = new DragShadowBuilder(v) {
-                            public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
-                                shadowSize.set(icon.getWidth(), icon.getHeight());
-                                shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
-                            }
-                            public void onDrawShadow(Canvas canvas) {
-                                canvas.drawBitmap(icon, 0, 0, new Paint());
-                            }
-                        };
-                    } else {
-                        // uhhh, what now?
-                        shadow = new DragShadowBuilder(mWindow.findViewById(R.id.preview));
-                    }
-
-                    v.startDrag(clip, shadow, null, 0);
-
-                    // TODO: only discard the clipping if it was accepted
-                    stash(null);
-
-                    return true;
-                }
-            }
-            return false;
-        }
-    };
-    */
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/StatusBarPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/StatusBarPanel.java
deleted file mode 100644
index 8fa01d5..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/StatusBarPanel.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-public interface StatusBarPanel {
-    public boolean isInContentArea(int x, int y);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
deleted file mode 100644
index bfa1b63..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ /dev/null
@@ -1,1545 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.StatusBarManager;
-import android.service.notification.StatusBarNotification;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.inputmethodservice.InputMethodService;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.SoundEffectConstants;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.DoNotDisturb;
-import com.android.systemui.statusbar.NotificationData;
-import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.SignalClusterView;
-import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CompatModeButton;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NotificationRowLayout;
-import com.android.systemui.statusbar.policy.Prefs;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-public class TabletStatusBar extends BaseStatusBar implements
-        InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
-    public static final boolean DEBUG = false;
-    public static final boolean DEBUG_COMPAT_HELP = false;
-    public static final String TAG = "TabletStatusBar";
-
-
-    public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
-    public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
-    public static final int MSG_OPEN_NOTIFICATION_PEEK = 1002;
-    public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003;
-    // 1020-1029 reserved for BaseStatusBar
-    public static final int MSG_SHOW_CHROME = 1030;
-    public static final int MSG_HIDE_CHROME = 1031;
-    public static final int MSG_OPEN_INPUT_METHODS_PANEL = 1040;
-    public static final int MSG_CLOSE_INPUT_METHODS_PANEL = 1041;
-    public static final int MSG_OPEN_COMPAT_MODE_PANEL = 1050;
-    public static final int MSG_CLOSE_COMPAT_MODE_PANEL = 1051;
-    public static final int MSG_STOP_TICKER = 2000;
-
-    // Fitts' Law assistance for LatinIME; see policy.EventHole
-    private static final boolean FAKE_SPACE_BAR = true;
-
-    // Notification "peeking" (flyover preview of individual notifications)
-    final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
-    final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms
-
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
-    private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
-
-    // The height of the bar, as definied by the build.  It may be taller if we're plugged
-    // into hdmi.
-    int mNaturalBarHeight = -1;
-    int mIconSize = -1;
-    int mIconHPadding = -1;
-    int mNavIconWidth = -1;
-    int mMenuNavIconWidth = -1;
-    private int mMaxNotificationIcons = 5;
-
-    TabletStatusBarView mStatusBarView;
-    View mNotificationArea;
-    View mNotificationTrigger;
-    NotificationIconArea mNotificationIconArea;
-    ViewGroup mNavigationArea;
-
-    boolean mNotificationDNDMode;
-    NotificationData.Entry mNotificationDNDDummyEntry;
-
-    ImageView mBackButton;
-    View mHomeButton;
-    View mMenuButton;
-    View mRecentButton;
-    private boolean mAltBackButtonEnabledForIme;
-
-    ViewGroup mFeedbackIconArea; // notification icons, IME icon, compat icon
-    InputMethodButton mInputMethodSwitchButton;
-    CompatModeButton mCompatModeButton;
-
-    NotificationPanel mNotificationPanel;
-    WindowManager.LayoutParams mNotificationPanelParams;
-    NotificationPeekPanel mNotificationPeekWindow;
-    ViewGroup mNotificationPeekRow;
-    int mNotificationPeekIndex;
-    IBinder mNotificationPeekKey;
-    LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight;
-
-    int mNotificationPeekTapDuration;
-    int mNotificationFlingVelocity;
-
-    BatteryController mBatteryController;
-    BluetoothController mBluetoothController;
-    LocationController mLocationController;
-    NetworkController mNetworkController;
-    DoNotDisturb mDoNotDisturb;
-
-    ViewGroup mBarContents;
-
-    // hide system chrome ("lights out") support
-    View mShadow;
-
-    NotificationIconArea.IconLayout mIconLayout;
-
-    TabletTicker mTicker;
-
-    View mFakeSpaceBar;
-    KeyEvent mSpaceBarKeyEvent = null;
-
-    View mCompatibilityHelpDialog = null;
-
-    // for disabling the status bar
-    int mDisabled = 0;
-
-    private InputMethodsPanel mInputMethodsPanel;
-    private CompatModePanel mCompatModePanel;
-
-    private int mSystemUiVisibility = 0;
-
-    private int mNavigationIconHints = 0;
-
-    private int mShowSearchHoldoff = 0;
-
-    public Context getContext() { return mContext; }
-
-    private Runnable mShowSearchPanel = new Runnable() {
-        public void run() {
-            showSearchPanel();
-        }
-    };
-
-    private View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
-        public boolean onTouch(View v, MotionEvent event) {
-            switch(event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    if (!shouldDisableNavbarGestures() && !inKeyguardRestrictedInputMode()) {
-                        mHandler.removeCallbacks(mShowSearchPanel);
-                        mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
-                    }
-                break;
-
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    mHandler.removeCallbacks(mShowSearchPanel);
-                break;
-            }
-            return false;
-        }
-    };
-
-    @Override
-    protected void createAndAddWindows() {
-        addStatusBarWindow();
-        addPanelWindows();
-    }
-
-    private void addStatusBarWindow() {
-        final View sb = makeStatusBarView();
-
-        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.OPAQUE);
-
-        // We explicitly leave FLAG_HARDWARE_ACCELERATED out of the flags.  The status bar occupies
-        // very little screen real-estate and is updated fairly frequently.  By using CPU rendering
-        // for the status bar, we prevent the GPU from having to wake up just to do these small
-        // updates, which should help keep power consumption down.
-
-        lp.gravity = getStatusBarGravity();
-        lp.setTitle("SystemBar");
-        lp.packageName = mContext.getPackageName();
-        mWindowManager.addView(sb, lp);
-    }
-
-    protected void addPanelWindows() {
-        final Context context = mContext;
-        final Resources res = mContext.getResources();
-
-        // Notification Panel
-        mNotificationPanel = (NotificationPanel)View.inflate(context,
-                R.layout.system_bar_notification_panel, null);
-        mNotificationPanel.setBar(this);
-        mNotificationPanel.show(false, false);
-        mNotificationPanel.setOnTouchListener(
-                new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel));
-
-        // the battery icon
-        mBatteryController.addIconView((ImageView)mNotificationPanel.findViewById(R.id.battery));
-        mBatteryController.addLabelView(
-                (TextView)mNotificationPanel.findViewById(R.id.battery_text));
-
-        // Bt
-        mBluetoothController.addIconView(
-                (ImageView)mNotificationPanel.findViewById(R.id.bluetooth));
-
-        // network icons: either a combo icon that switches between mobile and data, or distinct
-        // mobile and data icons
-        final ImageView mobileRSSI =
-                (ImageView)mNotificationPanel.findViewById(R.id.mobile_signal);
-        if (mobileRSSI != null) {
-            mNetworkController.addPhoneSignalIconView(mobileRSSI);
-        }
-        final ImageView wifiRSSI =
-                (ImageView)mNotificationPanel.findViewById(R.id.wifi_signal);
-        if (wifiRSSI != null) {
-            mNetworkController.addWifiIconView(wifiRSSI);
-        }
-        mNetworkController.addWifiLabelView(
-                (TextView)mNotificationPanel.findViewById(R.id.wifi_text));
-
-        mNetworkController.addDataTypeIconView(
-                (ImageView)mNotificationPanel.findViewById(R.id.mobile_type));
-        mNetworkController.addMobileLabelView(
-                (TextView)mNotificationPanel.findViewById(R.id.mobile_text));
-        mNetworkController.addCombinedLabelView(
-                (TextView)mBarContents.findViewById(R.id.network_text));
-
-        mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel);
-
-        WindowManager.LayoutParams lp = mNotificationPanelParams = new WindowManager.LayoutParams(
-                res.getDimensionPixelSize(R.dimen.notification_panel_width),
-                getNotificationPanelHeight(),
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.BOTTOM | Gravity.END;
-        lp.setTitle("NotificationPanel");
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-        lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation
-//        lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
-
-        mWindowManager.addView(mNotificationPanel, lp);
-
-        // Search Panel
-        mStatusBarView.setBar(this);
-        mHomeButton.setOnTouchListener(mHomeSearchActionListener);
-        updateSearchPanel();
-
-        // Input methods Panel
-        mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
-                R.layout.system_bar_input_methods_panel, null);
-        mInputMethodsPanel.setHardKeyboardEnabledChangeListener(this);
-        mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
-                MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
-        mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
-        mStatusBarView.setIgnoreChildren(2, mInputMethodSwitchButton, mInputMethodsPanel);
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.BOTTOM | Gravity.END;
-        lp.setTitle("InputMethodsPanel");
-        lp.windowAnimations = R.style.Animation_RecentPanel;
-
-        mWindowManager.addView(mInputMethodsPanel, lp);
-
-        // Compatibility mode selector panel
-        mCompatModePanel = (CompatModePanel) View.inflate(context,
-                R.layout.system_bar_compat_mode_panel, null);
-        mCompatModePanel.setOnTouchListener(new TouchOutsideListener(
-                MSG_CLOSE_COMPAT_MODE_PANEL, mCompatModePanel));
-        mCompatModePanel.setTrigger(mCompatModeButton);
-        mCompatModePanel.setVisibility(View.GONE);
-        mStatusBarView.setIgnoreChildren(3, mCompatModeButton, mCompatModePanel);
-        lp = new WindowManager.LayoutParams(
-                250,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.BOTTOM | Gravity.END;
-        lp.setTitle("CompatModePanel");
-        lp.windowAnimations = android.R.style.Animation_Dialog;
-
-        mWindowManager.addView(mCompatModePanel, lp);
-
-        mRecentButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
-
-        mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
-        mPile.removeAllViews();
-        mPile.setLongPressListener(getNotificationLongClicker());
-
-        ScrollView scroller = (ScrollView)mPile.getParent();
-        scroller.setFillViewport(true);
-    }
-
-    @Override
-    protected int getExpandedViewMaxHeight() {
-        return getNotificationPanelHeight();
-    }
-
-    private int getNotificationPanelHeight() {
-        final Resources res = mContext.getResources();
-        final Display d = mWindowManager.getDefaultDisplay();
-        final Point size = new Point();
-        d.getRealSize(size);
-        return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height), size.y);
-    }
-
-    @Override
-    public void start() {
-        super.start(); // will add the main bar view
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        loadDimens();
-        mNotificationPanelParams.height = getNotificationPanelHeight();
-        mWindowManager.updateViewLayout(mNotificationPanel, mNotificationPanelParams);
-        mShowSearchHoldoff = mContext.getResources().getInteger(
-                R.integer.config_show_search_delay);
-        updateSearchPanel();
-    }
-
-    @Override
-    protected void refreshLayout(int layoutDirection) {
-        mNotificationPanel.refreshLayout(layoutDirection);
-    }
-
-    protected void loadDimens() {
-        final Resources res = mContext.getResources();
-
-        mNaturalBarHeight = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.navigation_bar_height);
-
-        int newIconSize = res.getDimensionPixelSize(
-            com.android.internal.R.dimen.system_bar_icon_size);
-        int newIconHPadding = res.getDimensionPixelSize(
-            R.dimen.status_bar_icon_padding);
-        int newNavIconWidth = res.getDimensionPixelSize(R.dimen.navigation_key_width);
-        int newMenuNavIconWidth = res.getDimensionPixelSize(R.dimen.navigation_menu_key_width);
-
-        if (mNavigationArea != null && newNavIconWidth != mNavIconWidth) {
-            mNavIconWidth = newNavIconWidth;
-
-            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                     mNavIconWidth, ViewGroup.LayoutParams.MATCH_PARENT);
-            mBackButton.setLayoutParams(lp);
-            mHomeButton.setLayoutParams(lp);
-            mRecentButton.setLayoutParams(lp);
-        }
-
-        if (mNavigationArea != null && newMenuNavIconWidth != mMenuNavIconWidth) {
-            mMenuNavIconWidth = newMenuNavIconWidth;
-
-            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                     mMenuNavIconWidth, ViewGroup.LayoutParams.MATCH_PARENT);
-            mMenuButton.setLayoutParams(lp);
-        }
-
-        if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
-//            Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
-            mIconHPadding = newIconHPadding;
-            mIconSize = newIconSize;
-            reloadAllNotificationIcons(); // reload the tray
-        }
-
-        final int numIcons = res.getInteger(R.integer.config_maxNotificationIcons);
-        if (numIcons != mMaxNotificationIcons) {
-            mMaxNotificationIcons = numIcons;
-            if (DEBUG) Slog.d(TAG, "max notification icons: " + mMaxNotificationIcons);
-            reloadAllNotificationIcons();
-        }
-    }
-
-    @Override
-    public View getStatusBarView() {
-        return mStatusBarView;
-    }
-
-    protected View makeStatusBarView() {
-        final Context context = mContext;
-
-        loadDimens();
-
-        final TabletStatusBarView sb = (TabletStatusBarView)View.inflate(
-                context, R.layout.system_bar, null);
-        mStatusBarView = sb;
-
-        sb.setHandler(mHandler);
-
-        try {
-            // Sanity-check that someone hasn't set up the config wrong and asked for a navigation
-            // bar on a tablet that has only the system bar
-            if (mWindowManagerService.hasNavigationBar()) {
-                Slog.e(TAG, "Tablet device cannot show navigation bar and system bar");
-            }
-        } catch (RemoteException ex) {
-        }
-
-        mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);
-
-        // the whole right-hand side of the bar
-        mNotificationArea = sb.findViewById(R.id.notificationArea);
-        mNotificationArea.setOnTouchListener(new NotificationTriggerTouchListener());
-
-        // the button to open the notification area
-        mNotificationTrigger = sb.findViewById(R.id.notificationTrigger);
-
-        // the more notifications icon
-        mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
-
-        // where the icons go
-        mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
-
-        mNotificationPeekTapDuration = ViewConfiguration.getTapTimeout();
-        mNotificationFlingVelocity = 300; // px/s
-
-        mTicker = new TabletTicker(this);
-
-        // The icons
-        mLocationController = new LocationController(mContext); // will post a notification
-
-        // watch the PREF_DO_NOT_DISTURB and convert to appropriate disable() calls
-        mDoNotDisturb = new DoNotDisturb(mContext);
-
-        mBatteryController = new BatteryController(mContext);
-        mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
-        mBluetoothController = new BluetoothController(mContext);
-        mBluetoothController.addIconView((ImageView)sb.findViewById(R.id.bluetooth));
-
-        mNetworkController = new NetworkController(mContext);
-        final SignalClusterView signalCluster =
-                (SignalClusterView)sb.findViewById(R.id.signal_cluster);
-        mNetworkController.addSignalCluster(signalCluster);
-
-        // The navigation buttons
-        mBackButton = (ImageView)sb.findViewById(R.id.back);
-        mNavigationArea = (ViewGroup) sb.findViewById(R.id.navigationArea);
-        mHomeButton = mNavigationArea.findViewById(R.id.home);
-        mMenuButton = mNavigationArea.findViewById(R.id.menu);
-        mRecentButton = mNavigationArea.findViewById(R.id.recent_apps);
-        mRecentButton.setOnClickListener(mOnClickListener);
-
-        LayoutTransition lt = new LayoutTransition();
-        lt.setDuration(250);
-        // don't wait for these transitions; we just want icons to fade in/out, not move around
-        lt.setDuration(LayoutTransition.CHANGE_APPEARING, 0);
-        lt.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 0);
-        lt.addTransitionListener(new LayoutTransition.TransitionListener() {
-            public void endTransition(LayoutTransition transition, ViewGroup container,
-                    View view, int transitionType) {
-                // ensure the menu button doesn't stick around on the status bar after it's been
-                // removed
-                mBarContents.invalidate();
-            }
-            public void startTransition(LayoutTransition transition, ViewGroup container,
-                    View view, int transitionType) {}
-        });
-        mNavigationArea.setLayoutTransition(lt);
-        // no multi-touch on the nav buttons
-        mNavigationArea.setMotionEventSplittingEnabled(false);
-
-        // The bar contents buttons
-        mFeedbackIconArea = (ViewGroup)sb.findViewById(R.id.feedbackIconArea);
-        mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton);
-        // Overwrite the lister
-        mInputMethodSwitchButton.setOnClickListener(mOnClickListener);
-
-        mCompatModeButton = (CompatModeButton) sb.findViewById(R.id.compatModeButton);
-        mCompatModeButton.setOnClickListener(mOnClickListener);
-        mCompatModeButton.setVisibility(View.GONE);
-
-        // for redirecting errant bar taps to the IME
-        mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar);
-
-        // "shadows" of the status bar features, for lights-out mode
-        mShadow = sb.findViewById(R.id.bar_shadow);
-        mShadow.setOnTouchListener(
-            new View.OnTouchListener() {
-                public boolean onTouch(View v, MotionEvent ev) {
-                    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-                        // even though setting the systemUI visibility below will turn these views
-                        // on, we need them to come up faster so that they can catch this motion
-                        // event
-                        mShadow.setVisibility(View.GONE);
-                        mBarContents.setVisibility(View.VISIBLE);
-
-                        try {
-                            mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
-                        } catch (RemoteException ex) {
-                            // system process dead
-                        }
-                    }
-                    return false;
-                }
-            });
-
-        // tuning parameters
-        final int LIGHTS_GOING_OUT_SYSBAR_DURATION = 750;
-        final int LIGHTS_GOING_OUT_SHADOW_DURATION = 750;
-        final int LIGHTS_GOING_OUT_SHADOW_DELAY    = 0;
-
-        final int LIGHTS_COMING_UP_SYSBAR_DURATION = 200;
-//        final int LIGHTS_COMING_UP_SYSBAR_DELAY    = 50;
-        final int LIGHTS_COMING_UP_SHADOW_DURATION = 0;
-
-        LayoutTransition xition = new LayoutTransition();
-        xition.setAnimator(LayoutTransition.APPEARING,
-               ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1f));
-        xition.setDuration(LayoutTransition.APPEARING, LIGHTS_COMING_UP_SYSBAR_DURATION);
-        xition.setStartDelay(LayoutTransition.APPEARING, 0);
-        xition.setAnimator(LayoutTransition.DISAPPEARING,
-               ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
-        xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_GOING_OUT_SYSBAR_DURATION);
-        xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
-        ((ViewGroup)sb.findViewById(R.id.bar_contents_holder)).setLayoutTransition(xition);
-
-        xition = new LayoutTransition();
-        xition.setAnimator(LayoutTransition.APPEARING,
-               ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
-        xition.setDuration(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DURATION);
-        xition.setStartDelay(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DELAY);
-        xition.setAnimator(LayoutTransition.DISAPPEARING,
-               ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
-        xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_COMING_UP_SHADOW_DURATION);
-        xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
-        ((ViewGroup)sb.findViewById(R.id.bar_shadow_holder)).setLayoutTransition(xition);
-
-        // set the initial view visibility
-        setAreThereNotifications();
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        context.registerReceiver(mBroadcastReceiver, filter);
-
-        return sb;
-    }
-
-    @Override
-    protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                (int) mContext.getResources().getDimension(R.dimen.status_bar_recents_width),
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.BOTTOM | Gravity.START;
-        lp.setTitle("RecentsPanel");
-        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-            | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-
-        return lp;
-    }
-
-    @Override
-    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
-        boolean opaque = false;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
-        if (ActivityManager.isHighEndGfx()) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        } else {
-            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-            lp.dimAmount = 0.7f;
-        }
-        lp.gravity = Gravity.BOTTOM | Gravity.START;
-        lp.setTitle("SearchPanel");
-        // TODO: Define custom animation for Search panel
-        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-        return lp;
-    }
-
-    @Override
-    protected void updateSearchPanel() {
-        super.updateSearchPanel();
-        mSearchPanelView.setStatusBarView(mStatusBarView);
-        mStatusBarView.setDelegateView(mSearchPanelView);
-    }
-
-    @Override
-    public void showSearchPanel() {
-        super.showSearchPanel();
-        WindowManager.LayoutParams lp =
-            (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
-        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        mWindowManager.updateViewLayout(mStatusBarView, lp);
-    }
-
-    @Override
-    public void hideSearchPanel() {
-        super.hideSearchPanel();
-        WindowManager.LayoutParams lp =
-            (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
-        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        mWindowManager.updateViewLayout(mStatusBarView, lp);
-    }
-
-    public int getStatusBarHeight() {
-        return mStatusBarView != null ? mStatusBarView.getHeight()
-                : mContext.getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_height);
-    }
-
-    protected int getStatusBarGravity() {
-        return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
-    }
-
-    public void onBarHeightChanged(int height) {
-        final WindowManager.LayoutParams lp
-                = (WindowManager.LayoutParams)mStatusBarView.getLayoutParams();
-        if (lp == null) {
-            // haven't been added yet
-            return;
-        }
-        if (lp.height != height) {
-            lp.height = height;
-            mWindowManager.updateViewLayout(mStatusBarView, lp);
-        }
-    }
-
-    @Override
-    protected BaseStatusBar.H createHandler() {
-        return new TabletStatusBar.H();
-    }
-
-    private class H extends BaseStatusBar.H {
-        public void handleMessage(Message m) {
-            super.handleMessage(m);
-            switch (m.what) {
-                case MSG_OPEN_NOTIFICATION_PEEK:
-                    if (DEBUG) Slog.d(TAG, "opening notification peek window; arg=" + m.arg1);
-
-                    if (m.arg1 >= 0) {
-                        final int N = mNotificationData.size();
-
-                        if (!mNotificationDNDMode) {
-                            if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
-                                NotificationData.Entry entry = mNotificationData.get(N-1-mNotificationPeekIndex);
-                                entry.icon.setBackgroundColor(0);
-                                mNotificationPeekIndex = -1;
-                                mNotificationPeekKey = null;
-                            }
-                        }
-
-                        final int peekIndex = m.arg1;
-                        if (peekIndex < N) {
-                            //Slog.d(TAG, "loading peek: " + peekIndex);
-                            NotificationData.Entry entry =
-                                mNotificationDNDMode
-                                    ? mNotificationDNDDummyEntry
-                                    : mNotificationData.get(N-1-peekIndex);
-                            NotificationData.Entry copy = new NotificationData.Entry(
-                                    entry.key,
-                                    entry.notification,
-                                    entry.icon);
-                            inflateViews(copy, mNotificationPeekRow);
-
-                            if (mNotificationDNDMode) {
-                                copy.content.setOnClickListener(new View.OnClickListener() {
-                                    public void onClick(View v) {
-                                        SharedPreferences.Editor editor = Prefs.edit(mContext);
-                                        editor.putBoolean(Prefs.DO_NOT_DISTURB_PREF, false);
-                                        editor.apply();
-                                        animateCollapsePanels();
-                                        visibilityChanged(false);
-                                    }
-                                });
-                            }
-
-                            entry.icon.setBackgroundColor(0x20FFFFFF);
-
-//                          mNotificationPeekRow.setLayoutTransition(
-//                              peekIndex < mNotificationPeekIndex
-//                                  ? mNotificationPeekScrubLeft
-//                                  : mNotificationPeekScrubRight);
-
-                            mNotificationPeekRow.removeAllViews();
-                            mNotificationPeekRow.addView(copy.row);
-
-                            mNotificationPeekWindow.setVisibility(View.VISIBLE);
-                            mNotificationPanel.show(false, true);
-
-                            mNotificationPeekIndex = peekIndex;
-                            mNotificationPeekKey = entry.key;
-                        }
-                    }
-                    break;
-                case MSG_CLOSE_NOTIFICATION_PEEK:
-                    if (DEBUG) Slog.d(TAG, "closing notification peek window");
-                    mNotificationPeekWindow.setVisibility(View.GONE);
-                    mNotificationPeekRow.removeAllViews();
-
-                    final int N = mNotificationData.size();
-                    if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
-                        NotificationData.Entry entry =
-                            mNotificationDNDMode
-                                ? mNotificationDNDDummyEntry
-                                : mNotificationData.get(N-1-mNotificationPeekIndex);
-                        entry.icon.setBackgroundColor(0);
-                    }
-
-                    mNotificationPeekIndex = -1;
-                    mNotificationPeekKey = null;
-                    break;
-                case MSG_OPEN_NOTIFICATION_PANEL:
-                    if (DEBUG) Slog.d(TAG, "opening notifications panel");
-                    if (!mNotificationPanel.isShowing()) {
-                        mNotificationPanel.show(true, true);
-                        mNotificationArea.setVisibility(View.INVISIBLE);
-                        mTicker.halt();
-                    }
-                    break;
-                case MSG_CLOSE_NOTIFICATION_PANEL:
-                    if (DEBUG) Slog.d(TAG, "closing notifications panel");
-                    if (mNotificationPanel.isShowing()) {
-                        mNotificationPanel.show(false, true);
-                        mNotificationArea.setVisibility(View.VISIBLE);
-                    }
-                    break;
-                case MSG_OPEN_INPUT_METHODS_PANEL:
-                    if (DEBUG) Slog.d(TAG, "opening input methods panel");
-                    if (mInputMethodsPanel != null) mInputMethodsPanel.openPanel();
-                    break;
-                case MSG_CLOSE_INPUT_METHODS_PANEL:
-                    if (DEBUG) Slog.d(TAG, "closing input methods panel");
-                    if (mInputMethodsPanel != null) mInputMethodsPanel.closePanel(false);
-                    break;
-                case MSG_OPEN_COMPAT_MODE_PANEL:
-                    if (DEBUG) Slog.d(TAG, "opening compat panel");
-                    if (mCompatModePanel != null) mCompatModePanel.openPanel();
-                    break;
-                case MSG_CLOSE_COMPAT_MODE_PANEL:
-                    if (DEBUG) Slog.d(TAG, "closing compat panel");
-                    if (mCompatModePanel != null) mCompatModePanel.closePanel();
-                    break;
-                case MSG_SHOW_CHROME:
-                    if (DEBUG) Slog.d(TAG, "hiding shadows (lights on)");
-                    mBarContents.setVisibility(View.VISIBLE);
-                    mShadow.setVisibility(View.GONE);
-                    mSystemUiVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
-                    notifyUiVisibilityChanged();
-                    break;
-                case MSG_HIDE_CHROME:
-                    if (DEBUG) Slog.d(TAG, "showing shadows (lights out)");
-                    animateCollapsePanels();
-                    visibilityChanged(false);
-                    mBarContents.setVisibility(View.GONE);
-                    mShadow.setVisibility(View.VISIBLE);
-                    mSystemUiVisibility |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
-                    notifyUiVisibilityChanged();
-                    break;
-                case MSG_STOP_TICKER:
-                    mTicker.halt();
-                    break;
-            }
-        }
-    }
-
-    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        if (DEBUG) Slog.d(TAG, "addIcon(" + slot + ") -> " + icon);
-    }
-
-    public void updateIcon(String slot, int index, int viewIndex,
-            StatusBarIcon old, StatusBarIcon icon) {
-        if (DEBUG) Slog.d(TAG, "updateIcon(" + slot + ") -> " + icon);
-    }
-
-    public void removeIcon(String slot, int index, int viewIndex) {
-        if (DEBUG) Slog.d(TAG, "removeIcon(" + slot + ")");
-    }
-
-    public void addNotification(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) Slog.d(TAG, "addNotification(" + key + " -> " + notification + ")");
-        addNotificationViews(key, notification);
-
-        final boolean immersive = isImmersive();
-        if (false && immersive) {
-            // TODO: immersive mode popups for tablet
-        } else if (notification.getNotification().fullScreenIntent != null) {
-            // not immersive & a full-screen alert should be shown
-            Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;"
-                    + " sending fullScreenIntent");
-            try {
-                notification.getNotification().fullScreenIntent.send();
-            } catch (PendingIntent.CanceledException e) {
-            }
-        } else {
-            tick(key, notification, true);
-        }
-
-        setAreThereNotifications();
-    }
-
-    public void removeNotification(IBinder key) {
-        if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ")");
-        removeNotificationViews(key);
-        mTicker.remove(key);
-        setAreThereNotifications();
-    }
-
-    public void showClock(boolean show) {
-        View clock = mBarContents.findViewById(R.id.clock);
-        View network_text = mBarContents.findViewById(R.id.network_text);
-        if (clock != null) {
-            clock.setVisibility(show ? View.VISIBLE : View.GONE);
-        }
-        if (network_text != null) {
-            network_text.setVisibility((!show) ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    public void disable(int state) {
-        int old = mDisabled;
-        int diff = state ^ old;
-        mDisabled = state;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
-            boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
-            Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
-            showClock(show);
-        }
-        if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-            boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0;
-            Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
-            mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE);
-        }
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.i(TAG, "DISABLE_EXPAND: yes");
-                animateCollapsePanels();
-                visibilityChanged(false);
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            mNotificationDNDMode = Prefs.read(mContext)
-                        .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
-
-            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes" + (mNotificationDNDMode?" (DND)":""));
-                mTicker.halt();
-            } else {
-                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no" + (mNotificationDNDMode?" (DND)":""));
-            }
-
-            // refresh icons to show either notifications or the DND message
-            reloadAllNotificationIcons();
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
-            }
-        }
-        if ((diff & (StatusBarManager.DISABLE_RECENT
-                        | StatusBarManager.DISABLE_BACK
-                        | StatusBarManager.DISABLE_HOME)) != 0) {
-            setNavigationVisibility(state);
-
-            if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
-                // close recents if it's visible
-                mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
-                mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
-            }
-        }
-    }
-
-    private void setNavigationVisibility(int visibility) {
-        boolean disableHome = ((visibility & StatusBarManager.DISABLE_HOME) != 0);
-        boolean disableRecent = ((visibility & StatusBarManager.DISABLE_RECENT) != 0);
-        boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0);
-
-        mBackButton.setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
-        mHomeButton.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
-        mRecentButton.setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
-
-        mInputMethodSwitchButton.setScreenLocked(
-                (visibility & StatusBarManager.DISABLE_SYSTEM_INFO) != 0);
-    }
-
-    private boolean hasTicker(Notification n) {
-        return n.tickerView != null || !TextUtils.isEmpty(n.tickerText);
-    }
-
-    @Override
-    protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
-        // Don't show the ticker when the windowshade is open.
-        if (mNotificationPanel.isShowing()) {
-            return;
-        }
-        // If they asked for FLAG_ONLY_ALERT_ONCE, then only show this notification
-        // if it's a new notification.
-        if (!firstTime && (n.getNotification().flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
-            return;
-        }
-        // Show the ticker if one is requested. Also don't do this
-        // until status bar window is attached to the window manager,
-        // because...  well, what's the point otherwise?  And trying to
-        // run a ticker without being attached will crash!
-        if (hasTicker(n.getNotification()) && mStatusBarView.getWindowToken() != null) {
-            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
-                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
-                mTicker.add(key, n);
-                mFeedbackIconArea.setVisibility(View.GONE);
-            }
-        }
-    }
-
-    // called by TabletTicker when it's done with all queued ticks
-    public void doneTicking() {
-        mFeedbackIconArea.setVisibility(View.VISIBLE);
-    }
-
-    public void animateExpandNotificationsPanel() {
-        mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
-        mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
-    }
-
-    public void animateCollapsePanels() {
-        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
-    }
-
-    public void animateCollapsePanels(int flags) {
-        if ((flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
-        }
-        if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
-        }
-        if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
-        }
-        if ((flags & CommandQueue.FLAG_EXCLUDE_INPUT_METHODS_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
-        }
-        if ((flags & CommandQueue.FLAG_EXCLUDE_COMPAT_MODE_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
-        }
-
-    }
-
-    @Override
-    public void animateExpandSettingsPanel() {
-        // TODO: Implement when TabletStatusBar begins to be used.
-    }
-
-    @Override // CommandQueue
-    public void setNavigationIconHints(int hints) {
-        if (hints == mNavigationIconHints) return;
-
-        if (DEBUG) {
-            android.widget.Toast.makeText(mContext,
-                "Navigation icon hints = " + hints,
-                500).show();
-        }
-
-        mNavigationIconHints = hints;
-
-        mBackButton.setAlpha(
-            (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f);
-        mHomeButton.setAlpha(
-            (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f);
-        mRecentButton.setAlpha(
-            (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f);
-
-        mBackButton.setImageResource(
-            (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
-                ? R.drawable.ic_sysbar_back_ime
-                : R.drawable.ic_sysbar_back);
-    }
-
-    private void notifyUiVisibilityChanged() {
-        try {
-            mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility);
-        } catch (RemoteException ex) {
-        }
-    }
-
-    @Override // CommandQueue
-    public void setSystemUiVisibility(int vis, int mask) {
-        final int oldVal = mSystemUiVisibility;
-        final int newVal = (oldVal&~mask) | (vis&mask);
-        final int diff = newVal ^ oldVal;
-
-        if (diff != 0) {
-            mSystemUiVisibility = newVal;
-
-            if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
-                mHandler.removeMessages(MSG_HIDE_CHROME);
-                mHandler.removeMessages(MSG_SHOW_CHROME);
-                mHandler.sendEmptyMessage(0 == (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE)
-                        ? MSG_SHOW_CHROME : MSG_HIDE_CHROME);
-            }
-
-            notifyUiVisibilityChanged();
-        }
-    }
-
-    public void setLightsOn(boolean on) {
-        // Policy note: if the frontmost activity needs the menu key, we assume it is a legacy app
-        // that can't handle lights-out mode.
-        if (mMenuButton.getVisibility() == View.VISIBLE) {
-            on = true;
-        }
-
-        Slog.v(TAG, "setLightsOn(" + on + ")");
-        if (on) {
-            setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
-        } else {
-            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
-        }
-    }
-
-    public void topAppWindowChanged(boolean showMenu) {
-        if (DEBUG) {
-            Slog.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
-        }
-        mMenuButton.setVisibility(showMenu ? View.VISIBLE : View.GONE);
-
-        // See above re: lights-out policy for legacy apps.
-        if (showMenu) setLightsOn(true);
-
-        mCompatModeButton.refresh();
-        if (mCompatModeButton.getVisibility() == View.VISIBLE) {
-            if (DEBUG_COMPAT_HELP
-                    || ! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) {
-                showCompatibilityHelp();
-            }
-        } else {
-            hideCompatibilityHelp();
-            mCompatModePanel.closePanel();
-        }
-    }
-
-    private void showCompatibilityHelp() {
-        if (mCompatibilityHelpDialog != null) {
-            return;
-        }
-
-        mCompatibilityHelpDialog = View.inflate(mContext, R.layout.compat_mode_help, null);
-        View button = mCompatibilityHelpDialog.findViewById(R.id.button);
-
-        button.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                hideCompatibilityHelp();
-                SharedPreferences.Editor editor = Prefs.edit(mContext);
-                editor.putBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, true);
-                editor.apply();
-            }
-        });
-
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                PixelFormat.TRANSLUCENT);
-        lp.setTitle("CompatibilityModeDialog");
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-        lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
-
-        mWindowManager.addView(mCompatibilityHelpDialog, lp);
-    }
-
-    private void hideCompatibilityHelp() {
-        if (mCompatibilityHelpDialog != null) {
-            mWindowManager.removeView(mCompatibilityHelpDialog);
-            mCompatibilityHelpDialog = null;
-        }
-    }
-
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
-        mInputMethodSwitchButton.setImeWindowStatus(token,
-                (vis & InputMethodService.IME_ACTIVE) != 0);
-        updateNotificationIcons();
-        mInputMethodsPanel.setImeToken(token);
-
-        boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
-            || ((vis & InputMethodService.IME_VISIBLE) != 0);
-        mAltBackButtonEnabledForIme = altBack;
-
-        mCommandQueue.setNavigationIconHints(
-                altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
-                        : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
-
-        if (FAKE_SPACE_BAR) {
-            mFakeSpaceBar.setVisibility(((vis & InputMethodService.IME_VISIBLE) != 0)
-                    ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    @Override
-    public void setHardKeyboardStatus(boolean available, boolean enabled) {
-        if (DEBUG) {
-            Slog.d(TAG, "Set hard keyboard status: available=" + available
-                    + ", enabled=" + enabled);
-        }
-        mInputMethodSwitchButton.setHardKeyboardStatus(available);
-        updateNotificationIcons();
-        mInputMethodsPanel.setHardKeyboardStatus(available, enabled);
-    }
-
-    @Override
-    public void onHardKeyboardEnabledChange(boolean enabled) {
-        try {
-            mBarService.setHardKeyboardEnabled(enabled);
-        } catch (RemoteException ex) {
-        }
-    }
-
-    private boolean isImmersive() {
-        try {
-            return ActivityManagerNative.getDefault().isTopActivityImmersive();
-            //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
-        } catch (RemoteException ex) {
-            // the end is nigh
-            return false;
-        }
-    }
-
-    @Override
-    protected void setAreThereNotifications() {
-        if (mNotificationPanel != null) {
-            mNotificationPanel.setClearable(isDeviceProvisioned() && mNotificationData.hasClearableItems());
-        }
-    }
-
-    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            if (v == mRecentButton) {
-                onClickRecentButton();
-            } else if (v == mInputMethodSwitchButton) {
-                onClickInputMethodSwitchButton();
-            } else if (v == mCompatModeButton) {
-                onClickCompatModeButton();
-            }
-        }
-    };
-
-    public void onClickRecentButton() {
-        if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
-            toggleRecentApps();
-        }
-    }
-
-    public void onClickInputMethodSwitchButton() {
-        if (DEBUG) Slog.d(TAG, "clicked input methods panel; disabled=" + mDisabled);
-        int msg = (mInputMethodsPanel.getVisibility() == View.GONE) ?
-                MSG_OPEN_INPUT_METHODS_PANEL : MSG_CLOSE_INPUT_METHODS_PANEL;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
-    }
-
-    public void onClickCompatModeButton() {
-        int msg = (mCompatModePanel.getVisibility() == View.GONE) ?
-                MSG_OPEN_COMPAT_MODE_PANEL : MSG_CLOSE_COMPAT_MODE_PANEL;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
-    }
-
-    private class NotificationTriggerTouchListener implements View.OnTouchListener {
-        VelocityTracker mVT;
-        float mInitialTouchX, mInitialTouchY;
-        int mTouchSlop;
-
-        public NotificationTriggerTouchListener() {
-            mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
-        }
-
-        private Runnable mHiliteOnR = new Runnable() { public void run() {
-            mNotificationArea.setBackgroundResource(
-                com.android.internal.R.drawable.list_selector_pressed_holo_dark);
-        }};
-        public void hilite(final boolean on) {
-            if (on) {
-                mNotificationArea.postDelayed(mHiliteOnR, 100);
-            } else {
-                mNotificationArea.removeCallbacks(mHiliteOnR);
-                mNotificationArea.setBackground(null);
-            }
-        }
-
-        public boolean onTouch(View v, MotionEvent event) {
-//            Slog.d(TAG, String.format("touch: (%.1f, %.1f) initial: (%.1f, %.1f)",
-//                        event.getX(),
-//                        event.getY(),
-//                        mInitialTouchX,
-//                        mInitialTouchY));
-
-            if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-                return true;
-            }
-
-            final int action = event.getAction();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                    mVT = VelocityTracker.obtain();
-                    mInitialTouchX = event.getX();
-                    mInitialTouchY = event.getY();
-                    hilite(true);
-                    // fall through
-                case MotionEvent.ACTION_OUTSIDE:
-                case MotionEvent.ACTION_MOVE:
-                    // check for fling
-                    if (mVT != null) {
-                        mVT.addMovement(event);
-                        mVT.computeCurrentVelocity(1000); // pixels per second
-                        // require a little more oomph once we're already in peekaboo mode
-                        if (mVT.getYVelocity() < -mNotificationFlingVelocity) {
-                            animateExpandNotificationsPanel();
-                            visibilityChanged(true);
-                            hilite(false);
-                            mVT.recycle();
-                            mVT = null;
-                        }
-                    }
-                    return true;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    hilite(false);
-                    if (mVT != null) {
-                        if (action == MotionEvent.ACTION_UP
-                         // was this a sloppy tap?
-                         && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
-                         && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
-                         // dragging off the bottom doesn't count
-                         && (int)event.getY() < v.getBottom()) {
-                            animateExpandNotificationsPanel();
-                            visibilityChanged(true);
-                            v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-                            v.playSoundEffect(SoundEffectConstants.CLICK);
-                        }
-
-                        mVT.recycle();
-                        mVT = null;
-                        return true;
-                    }
-            }
-            return false;
-        }
-    }
-
-    public void resetNotificationPeekFadeTimer() {
-        if (DEBUG) {
-            Slog.d(TAG, "setting peek fade timer for " + NOTIFICATION_PEEK_FADE_DELAY
-                + "ms from now");
-        }
-        mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
-        mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
-                NOTIFICATION_PEEK_FADE_DELAY);
-    }
-
-    private void reloadAllNotificationIcons() {
-        if (mIconLayout == null) return;
-        mIconLayout.removeAllViews();
-        updateNotificationIcons();
-    }
-
-    @Override
-    protected void updateNotificationIcons() {
-        // XXX: need to implement a new limited linear layout class
-        // to avoid removing & readding everything
-
-        if (mIconLayout == null) return;
-
-        // first, populate the main notification panel
-        loadNotificationPanel();
-
-        final LinearLayout.LayoutParams params
-            = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
-
-        // alternate behavior in DND mode
-        if (mNotificationDNDMode) {
-            if (mIconLayout.getChildCount() == 0) {
-                final Notification dndNotification = new Notification.Builder(mContext)
-                    .setContentTitle(mContext.getText(R.string.notifications_off_title))
-                    .setContentText(mContext.getText(R.string.notifications_off_text))
-                    .setSmallIcon(R.drawable.ic_notification_dnd)
-                    .setOngoing(true)
-                    .getNotification();
-
-                final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd",
-                        dndNotification);
-                iconView.setImageResource(R.drawable.ic_notification_dnd);
-                iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-                iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
-
-                mNotificationDNDDummyEntry = new NotificationData.Entry(
-                        null, new StatusBarNotification("", 0, "", 0, 0, Notification.PRIORITY_MAX,
-                                dndNotification, android.os.Process.myUserHandle()), iconView);
-
-                mIconLayout.addView(iconView, params);
-            }
-
-            return;
-        } else if (0 != (mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) {
-            // if icons are disabled but we're not in DND mode, this is probably Setup and we should
-            // just leave the area totally empty
-            return;
-        }
-
-        int N = mNotificationData.size();
-
-        if (DEBUG) {
-            Slog.d(TAG, "refreshing icons: " + N + " notifications, mIconLayout=" + mIconLayout);
-        }
-
-        ArrayList<View> toShow = new ArrayList<View>();
-
-        // Extra Special Icons
-        // The IME switcher and compatibility mode icons take the place of notifications. You didn't
-        // need to see all those new emails, did you?
-        int maxNotificationIconsCount = mMaxNotificationIcons;
-        if (mInputMethodSwitchButton.getVisibility() != View.GONE) maxNotificationIconsCount --;
-        if (mCompatModeButton.getVisibility()        != View.GONE) maxNotificationIconsCount --;
-
-        final boolean provisioned = isDeviceProvisioned();
-        // If the device hasn't been through Setup, we only show system notifications
-        for (int i=0; toShow.size()< maxNotificationIconsCount; i++) {
-            if (i >= N) break;
-            Entry ent = mNotificationData.get(N-i-1);
-            if ((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
-                    || showNotificationEvenIfUnprovisioned(ent.notification)) {
-                toShow.add(ent.icon);
-            }
-        }
-
-        ArrayList<View> toRemove = new ArrayList<View>();
-        for (int i=0; i<mIconLayout.getChildCount(); i++) {
-            View child = mIconLayout.getChildAt(i);
-            if (!toShow.contains(child)) {
-                toRemove.add(child);
-            }
-        }
-
-        for (View remove : toRemove) {
-            mIconLayout.removeView(remove);
-        }
-
-        for (int i=0; i<toShow.size(); i++) {
-            View v = toShow.get(i);
-            v.setPadding(mIconHPadding, 0, mIconHPadding, 0);
-            if (v.getParent() == null) {
-                mIconLayout.addView(v, i, params);
-            }
-        }
-    }
-
-    private void loadNotificationPanel() {
-        int N = mNotificationData.size();
-
-        ArrayList<View> toShow = new ArrayList<View>();
-
-        final boolean provisioned = isDeviceProvisioned();
-        // If the device hasn't been through Setup, we only show system notifications
-        for (int i=0; i<N; i++) {
-            Entry ent = mNotificationData.get(N-i-1);
-            if (provisioned || showNotificationEvenIfUnprovisioned(ent.notification)) {
-                toShow.add(ent.row);
-            }
-        }
-
-        ArrayList<View> toRemove = new ArrayList<View>();
-        for (int i=0; i<mPile.getChildCount(); i++) {
-            View child = mPile.getChildAt(i);
-            if (!toShow.contains(child)) {
-                toRemove.add(child);
-            }
-        }
-
-        for (View remove : toRemove) {
-            mPile.removeView(remove);
-        }
-
-        for (int i=0; i<toShow.size(); i++) {
-            View v = toShow.get(i);
-            if (v.getParent() == null) {
-                // the notification panel has the most important things at the bottom
-                mPile.addView(v, Math.min(toShow.size()-1-i, mPile.getChildCount()));
-            }
-        }
-
-        mNotificationPanel.setNotificationCount(toShow.size());
-        mNotificationPanel.setSettingsEnabled(isDeviceProvisioned());
-    }
-
-    @Override
-    protected void workAroundBadLayerDrawableOpacity(View v) {
-        Drawable bgd = v.getBackground();
-        if (!(bgd instanceof LayerDrawable)) return;
-
-        LayerDrawable d = (LayerDrawable) bgd;
-        v.setBackground(null);
-        d.setOpacity(PixelFormat.TRANSLUCENT);
-        v.setBackground(d);
-    }
-
-    public void clearAll() {
-        try {
-            mBarService.onClearAllNotifications();
-        } catch (RemoteException ex) {
-            // system process is dead if we're here.
-        }
-        animateCollapsePanels();
-        visibilityChanged(false);
-    }
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                int flags = CommandQueue.FLAG_EXCLUDE_NONE;
-                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                    String reason = intent.getStringExtra("reason");
-                    if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
-                        flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
-                    }
-                }
-                animateCollapsePanels(flags);
-            }
-        }
-    };
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.print("mDisabled=0x");
-        pw.println(Integer.toHexString(mDisabled));
-        pw.println("mNetworkController:");
-        mNetworkController.dump(fd, pw, args);
-    }
-
-    @Override
-    protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
-        if (parent == null || entry == null) return false;
-        return parent.indexOfChild(entry.row) == parent.getChildCount()-1;
-    }
-
-    @Override
-    protected void haltTicker() {
-        mTicker.halt();
-    }
-
-    @Override
-    protected void updateExpandedViewPos(int expandedPosition) {
-    }
-
-    @Override
-    protected boolean shouldDisableNavbarGestures() {
-        return mNotificationPanel.getVisibility() == View.VISIBLE
-                || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
-    }
-}
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
deleted file mode 100644
index 30d49ca..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.DelegateViewHelper;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-public class TabletStatusBarView extends FrameLayout {
-    private Handler mHandler;
-
-    private final int MAX_PANELS = 5;
-    private final View[] mIgnoreChildren = new View[MAX_PANELS];
-    private final View[] mPanels = new View[MAX_PANELS];
-    private final int[] mPos = new int[2];
-    private DelegateViewHelper mDelegateHelper;
-
-    public TabletStatusBarView(Context context) {
-        this(context, null);
-    }
-
-    public TabletStatusBarView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mDelegateHelper = new DelegateViewHelper(this);
-    }
-
-    public void setDelegateView(View view) {
-        mDelegateHelper.setDelegateView(view);
-    }
-
-    public void setBar(BaseStatusBar phoneStatusBar) {
-        mDelegateHelper.setBar(phoneStatusBar);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mDelegateHelper != null) {
-            mDelegateHelper.onInterceptTouchEvent(event);
-        }
-        return true;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        // Find the view we wish to grab events from in order to detect search gesture.
-        // Depending on the device, this will be one of the id's listed below.
-        // If we don't find one, we'll use the view provided in the constructor above (this view).
-        View view = findViewById(R.id.navigationArea);
-        if (view == null) {
-            view = findViewById(R.id.nav_buttons);
-        }
-        mDelegateHelper.setSourceView(view);
-        mDelegateHelper.setInitialTouchRegion(view);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            if (TabletStatusBar.DEBUG) {
-                Slog.d(TabletStatusBar.TAG, "TabletStatusBarView intercepting touch event: " + ev);
-            }
-            // do not close the recents panel here- the intended behavior is that recents is dismissed
-            // on touch up when clicking on status bar buttons
-            // TODO: should we be closing the notification panel and input methods panel?
-            mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
-            mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
-            mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL);
-            mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL);
-            mHandler.removeMessages(TabletStatusBar.MSG_STOP_TICKER);
-            mHandler.sendEmptyMessage(TabletStatusBar.MSG_STOP_TICKER);
-
-            for (int i=0; i < mPanels.length; i++) {
-                if (mPanels[i] != null && mPanels[i].getVisibility() == View.VISIBLE) {
-                    if (eventInside(mIgnoreChildren[i], ev)) {
-                        if (TabletStatusBar.DEBUG) {
-                            Slog.d(TabletStatusBar.TAG,
-                                    "TabletStatusBarView eating event for view: "
-                                    + mIgnoreChildren[i]);
-                        }
-                        return true;
-                    }
-                }
-            }
-        }
-        if (TabletStatusBar.DEBUG) {
-            Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
-        }
-        if (mDelegateHelper != null && mDelegateHelper.onInterceptTouchEvent(ev)) {
-            return true;
-        }
-        return super.onInterceptTouchEvent(ev);
-    }
-
-    private boolean eventInside(View v, MotionEvent ev) {
-        // assume that x and y are window coords because we are.
-        final int x = (int)ev.getX();
-        final int y = (int)ev.getY();
-
-        final int[] p = mPos;
-        v.getLocationInWindow(p);
-
-        final int l = p[0];
-        final int t = p[1];
-        final int r = p[0] + v.getWidth();
-        final int b = p[1] + v.getHeight();
-
-        return x >= l && x < r && y >= t && y < b;
-    }
-
-    public void setHandler(Handler h) {
-        mHandler = h;
-    }
-
-    /**
-     * Let the status bar know that if you tap on ignore while panel is showing, don't do anything.
-     *
-     * Debounces taps on, say, a popup's trigger when the popup is already showing.
-     */
-    public void setIgnoreChildren(int index, View ignore, View panel) {
-        mIgnoreChildren[index] = ignore;
-        mPanels[index] = panel;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
deleted file mode 100644
index 095c441..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tablet;
-
-import java.util.Arrays;
-
-import android.animation.LayoutTransition;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.service.notification.StatusBarNotification;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.statusbar.StatusBarIcon;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarIconView;
-
-public class TabletTicker
-        extends Handler
-        implements LayoutTransition.TransitionListener {
-
-    private static final String TAG = "StatusBar.TabletTicker";
-
-    private static final boolean CLICKABLE_TICKER = true;
-
-    // 3 is enough to let us see most cases, but not get so far behind that it's too annoying.
-    private static final int QUEUE_LENGTH = 3;
-
-    private static final int MSG_ADVANCE = 1;
-
-    private static final int ADVANCE_DELAY = 5000; // 5 seconds
-
-    private final Context mContext;
-    private final WindowManager mWindowManager;
-
-    private ViewGroup mWindow;
-    private IBinder mCurrentKey;
-    private StatusBarNotification mCurrentNotification;
-    private View mCurrentView;
-
-    private IBinder[] mKeys = new IBinder[QUEUE_LENGTH];
-    private StatusBarNotification[] mQueue = new StatusBarNotification[QUEUE_LENGTH];
-    private int mQueuePos;
-
-    private final int mLargeIconHeight;
-
-    private TabletStatusBar mBar;
-
-    private LayoutTransition mLayoutTransition;
-    private boolean mWindowShouldClose;
-
-    public TabletTicker(TabletStatusBar bar) {
-        mBar = bar;
-        mContext = bar.getContext();
-        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-        final Resources res = mContext.getResources();
-        mLargeIconHeight = res.getDimensionPixelSize(
-                android.R.dimen.notification_large_icon_height);
-    }
-
-    public void add(IBinder key, StatusBarNotification notification) {
-        if (false) {
-            Slog.d(TAG, "add 1 mCurrentNotification=" + mCurrentNotification
-                    + " mQueuePos=" + mQueuePos + " mQueue=" + Arrays.toString(mQueue));
-        }
-
-        // If it's already in here, remove whatever's in there and put the new one at the end.
-        remove(key, false);
-
-        mKeys[mQueuePos] = key;
-        mQueue[mQueuePos] = notification;
-
-        // If nothing is running now, start the next one.
-        if (mQueuePos == 0 && mCurrentNotification == null) {
-            sendEmptyMessage(MSG_ADVANCE);
-        }
-
-        if (mQueuePos < QUEUE_LENGTH - 1) {
-            mQueuePos++;
-        }
-    }
-
-    public void remove(IBinder key) {
-        remove(key, true);
-    }
-
-    public void remove(IBinder key, boolean advance) {
-        if (mCurrentKey == key) {
-            // Showing now
-            if (advance) {
-                removeMessages(MSG_ADVANCE);
-                sendEmptyMessage(MSG_ADVANCE);
-            }
-        } else {
-            // In the queue
-            for (int i=0; i<QUEUE_LENGTH; i++) {
-                if (mKeys[i] == key) {
-                    for (; i<QUEUE_LENGTH-1; i++) {
-                        mKeys[i] = mKeys[i+1];
-                        mQueue[i] = mQueue[i+1];
-                    }
-                    mKeys[QUEUE_LENGTH-1] = null;
-                    mQueue[QUEUE_LENGTH-1] = null;
-                    if (mQueuePos > 0) {
-                        mQueuePos--;
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    public void halt() {
-        removeMessages(MSG_ADVANCE);
-        if (mCurrentView != null || mQueuePos != 0) {
-            for (int i=0; i<QUEUE_LENGTH; i++) {
-                mKeys[i] = null;
-                mQueue[i] = null;
-            }
-            mQueuePos = 0;
-            sendEmptyMessage(MSG_ADVANCE);
-        }
-    }
-
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-            case MSG_ADVANCE:
-                advance();
-                break;
-        }
-    }
-
-    private void advance() {
-        // Out with the old...
-        if (mCurrentView != null) {
-            if (mWindow != null) {
-                mWindow.removeView(mCurrentView);
-            }
-            mCurrentView = null;
-            mCurrentKey = null;
-            mCurrentNotification = null;
-        }
-
-        // In with the new...
-        dequeue();
-        while (mCurrentNotification != null) {
-            mCurrentView = makeTickerView(mCurrentNotification);
-            if (mCurrentView != null) {
-                if (mWindow == null) {
-                    mWindow = makeWindow();
-                    mWindowManager.addView(mWindow, mWindow.getLayoutParams());
-                }
-
-                mWindow.addView(mCurrentView);
-                sendEmptyMessageDelayed(MSG_ADVANCE, ADVANCE_DELAY);
-                break;
-            }
-            dequeue();
-        }
-
-        // if there's nothing left, close the window
-        mWindowShouldClose = (mCurrentView == null && mWindow != null);
-    }
-
-    private void dequeue() {
-        mCurrentKey = mKeys[0];
-        mCurrentNotification = mQueue[0];
-        if (false) {
-            Slog.d(TAG, "dequeue mQueuePos=" + mQueuePos + " mQueue=" + Arrays.toString(mQueue));
-        }
-        final int N = mQueuePos;
-        for (int i=0; i<N; i++) {
-            mKeys[i] = mKeys[i+1];
-            mQueue[i] = mQueue[i+1];
-        }
-        mKeys[N] = null;
-        mQueue[N] = null;
-        if (mQueuePos > 0) {
-            mQueuePos--;
-        }
-    }
-
-    private ViewGroup makeWindow() {
-        final Resources res = mContext.getResources();
-        final FrameLayout view = new FrameLayout(mContext);
-        final int width = res.getDimensionPixelSize(R.dimen.notification_ticker_width);
-        int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-        if (CLICKABLE_TICKER) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        } else {
-            windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-        }
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, mLargeIconHeight,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, windowFlags,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.BOTTOM | Gravity.END;
-//        lp.windowAnimations = com.android.internal.R.style.Animation_Toast;
-
-        mLayoutTransition = new LayoutTransition();
-        mLayoutTransition.addTransitionListener(this);
-        view.setLayoutTransition(mLayoutTransition);
-        lp.setTitle("NotificationTicker");
-        view.setLayoutParams(lp);
-        return view;
-    }
-
-    public void startTransition(LayoutTransition transition, ViewGroup container,
-            View view, int transitionType) {}
-
-    public void endTransition(LayoutTransition transition, ViewGroup container,
-            View view, int transitionType) {
-        if (mWindowShouldClose) {
-            mWindowManager.removeView(mWindow);
-            mWindow = null;
-            mWindowShouldClose = false;
-            mBar.doneTicking();
-        }
-    }
-
-    private View makeTickerView(StatusBarNotification notification) {
-        final Notification n = notification.getNotification();
-
-        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-
-        ViewGroup group;
-        int layoutId;
-        int iconId;
-        if (n.largeIcon != null) {
-            iconId = R.id.right_icon;
-        } else {
-            iconId = R.id.left_icon;
-        }
-        if (n.tickerView != null) {
-            group = (ViewGroup)inflater.inflate(R.layout.system_bar_ticker_panel, null, false);
-            ViewGroup content = (FrameLayout) group.findViewById(R.id.ticker_expanded);
-            View expanded = null;
-            Exception exception = null;
-            try {
-                expanded = n.tickerView.apply(mContext, content);
-            }
-            catch (RuntimeException e) {
-                exception = e;
-            }
-            if (expanded == null) {
-                final String ident = notification.getPackageName()
-                        + "/0x" + Integer.toHexString(notification.getId());
-                Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
-                return null;
-            }
-            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, 
-                    ViewGroup.LayoutParams.MATCH_PARENT);
-            content.addView(expanded, lp);
-        } else if (n.tickerText != null) {
-            group = (ViewGroup)inflater.inflate(R.layout.system_bar_ticker_compat, mWindow, false);
-            final Drawable icon = StatusBarIconView.getIcon(mContext,
-                    new StatusBarIcon(notification.getPackageName(), notification.getUser(), n.icon, n.iconLevel, 0,
-                            n.tickerText));
-            ImageView iv = (ImageView)group.findViewById(iconId);
-            iv.setImageDrawable(icon);
-            iv.setVisibility(View.VISIBLE);
-            TextView tv = (TextView)group.findViewById(R.id.text);
-            tv.setText(n.tickerText);
-        } else {
-            throw new RuntimeException("tickerView==null && tickerText==null");
-        }
-        ImageView largeIcon = (ImageView)group.findViewById(R.id.large_icon);
-        if (n.largeIcon != null) {
-            largeIcon.setImageBitmap(n.largeIcon);
-            largeIcon.setVisibility(View.VISIBLE);
-            final ViewGroup.LayoutParams lp = largeIcon.getLayoutParams();
-            final int statusBarHeight = mBar.getStatusBarHeight();
-            if (n.largeIcon.getHeight() <= statusBarHeight) {
-                // for smallish largeIcons, it looks a little odd to have them floating halfway up
-                // the ticker, so we vertically center them in the status bar area instead
-                lp.height = statusBarHeight;
-            } else {
-                lp.height = mLargeIconHeight;
-            }
-            largeIcon.setLayoutParams(lp);
-        }
-
-        if (CLICKABLE_TICKER) {
-            PendingIntent contentIntent = notification.getNotification().contentIntent;
-            if (contentIntent != null) {
-                // create the usual notification clicker, but chain it together with a halt() call
-                // to abort the ticker too
-                final View.OnClickListener clicker = mBar.makeClicker(contentIntent,
-                        notification.getPackageName(), notification.getTag(), notification.getId());
-                group.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        halt();
-                        clicker.onClick(v);
-                    }
-                });
-            } else {
-                group.setOnClickListener(null);
-            }
-        }
-
-        return group;
-    }
-}
-
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 dc5de02..a53b25a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -16,15 +16,15 @@
 
 package com.android.systemui.statusbar.tv;
 
-import android.service.notification.StatusBarNotification;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.statusbar.BaseStatusBar;
-
 import android.os.IBinder;
+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.BaseStatusBar;
+
 /*
  * Status bar implementation for "large screen" products that mostly present no on-screen nav
  */
@@ -92,14 +92,12 @@
     public void setNavigationIconHints(int hints) {
     }
 
-    @Override
-    protected void createAndAddWindows() {
+    @Override // CommandQueue
+    public void setWindowState(int window, int state) {
     }
 
     @Override
-    protected WindowManager.LayoutParams getRecentsLayoutParams(
-            LayoutParams layoutParams) {
-        return null;
+    protected void createAndAddWindows() {
     }
 
     @Override
@@ -143,6 +141,10 @@
     }
 
     @Override
+    public void resetHeadsUpDecayTimer() {
+    }
+
+    @Override
     public void animateExpandSettingsPanel() {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 06696fe..2c36ab7 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -29,22 +29,19 @@
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
-import android.util.Slog;
+import android.util.Log;
 
-public class StorageNotification extends StorageEventListener {
+import com.android.systemui.SystemUI;
+
+public class StorageNotification extends SystemUI {
     private static final String TAG = "StorageNotification";
     private static final boolean DEBUG = false;
 
     private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
 
     /**
-     * Binder context for this service
-     */
-    private Context mContext;
-    
-    /**
      * The notification that is shown when a USB mass storage host
-     * is connected. 
+     * is connected.
      * <p>
      * This is lazily created, so use {@link #setUsbStorageNotification()}.
      */
@@ -66,32 +63,40 @@
 
     private Handler        mAsyncEventHandler;
 
-    public StorageNotification(Context context) {
-        mContext = context;
+    private class StorageNotificationEventListener extends StorageEventListener {
+        public void onUsbMassStorageConnectionChanged(final boolean connected) {
+            mAsyncEventHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onUsbMassStorageConnectionChangedAsync(connected);
+                }
+            });
+        }
+        public void onStorageStateChanged(final String path,
+                final String oldState, final String newState) {
+            mAsyncEventHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onStorageStateChangedAsync(path, oldState, newState);
+                }
+            });
+        }
+    }
 
-        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+    @Override
+    public void start() {
+        mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
         final boolean connected = mStorageManager.isUsbMassStorageConnected();
-        if (DEBUG) Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)",
+        if (DEBUG) Log.d(TAG, String.format( "Startup with UMS connection %s (media state %s)",
                 mUmsAvailable, Environment.getExternalStorageState()));
-        
+
         HandlerThread thr = new HandlerThread("SystemUI StorageNotification");
         thr.start();
         mAsyncEventHandler = new Handler(thr.getLooper());
 
-        onUsbMassStorageConnectionChanged(connected);
-    }
-
-    /*
-     * @override com.android.os.storage.StorageEventListener
-     */
-    @Override
-    public void onUsbMassStorageConnectionChanged(final boolean connected) {
-        mAsyncEventHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                onUsbMassStorageConnectionChangedAsync(connected);
-            }
-        });
+        StorageNotificationEventListener listener = new StorageNotificationEventListener();
+        listener.onUsbMassStorageConnectionChanged(connected);
+        mStorageManager.registerListener(listener);
     }
 
     private void onUsbMassStorageConnectionChangedAsync(boolean connected) {
@@ -102,7 +107,7 @@
          */
         String st = Environment.getExternalStorageState();
 
-        if (DEBUG) Slog.i(TAG, String.format("UMS connection changed to %s (media state %s)",
+        if (DEBUG) Log.i(TAG, String.format("UMS connection changed to %s (media state %s)",
                 connected, st));
 
         if (connected && (st.equals(
@@ -115,21 +120,8 @@
         updateUsbMassStorageNotification(connected);
     }
 
-    /*
-     * @override com.android.os.storage.StorageEventListener
-     */
-    @Override
-    public void onStorageStateChanged(final String path, final String oldState, final String newState) {
-        mAsyncEventHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                onStorageStateChangedAsync(path, oldState, newState);
-            }
-        });
-    }
-
     private void onStorageStateChangedAsync(String path, String oldState, String newState) {
-        if (DEBUG) Slog.i(TAG, String.format(
+        if (DEBUG) Log.i(TAG, String.format(
                 "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
         if (newState.equals(Environment.MEDIA_SHARED)) {
             /*
@@ -225,7 +217,7 @@
             setMediaStorageNotification(
                     com.android.internal.R.string.ext_media_unmountable_notification_title,
                     com.android.internal.R.string.ext_media_unmountable_notification_message,
-                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi); 
+                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
             updateUsbMassStorageNotification(mUmsAvailable);
         } else if (newState.equals(Environment.MEDIA_REMOVED)) {
             /*
@@ -250,7 +242,7 @@
                     true, true, null);
             updateUsbMassStorageNotification(false);
         } else {
-            Slog.w(TAG, String.format("Ignoring unknown state {%s}", newState));
+            Log.w(TAG, String.format("Ignoring unknown state {%s}", newState));
         }
     }
 
@@ -291,7 +283,7 @@
         if (notificationManager == null) {
             return;
         }
-        
+
         if (visible) {
             Resources r = Resources.getSystem();
             CharSequence title = r.getText(titleId);
@@ -308,7 +300,7 @@
             } else {
                 mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
             }
-                
+
             mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
 
             mUsbStorageNotification.tickerText = title;
@@ -337,7 +329,7 @@
                 mUsbStorageNotification.fullScreenIntent = pi;
             }
         }
-    
+
         final int notificationId = mUsbStorageNotification.icon;
         if (visible) {
             notificationManager.notifyAsUser(null, notificationId, mUsbStorageNotification,
@@ -381,7 +373,7 @@
             final int notificationId = mMediaStorageNotification.icon;
             notificationManager.cancel(notificationId);
         }
-        
+
         if (visible) {
             Resources r = Resources.getSystem();
             CharSequence title = r.getText(titleId);
@@ -410,7 +402,7 @@
             mMediaStorageNotification.icon = icon;
             mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
         }
-    
+
         final int notificationId = mMediaStorageNotification.icon;
         if (visible) {
             notificationManager.notifyAsUser(null, notificationId,
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
index ff06630..b5f98ad 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -16,22 +16,19 @@
 
 package com.android.systemui.usb;
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.net.Uri;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
-
 import com.android.systemui.R;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 2c25236..7abfc88 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -23,9 +23,7 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.Typeface;
 import android.hardware.usb.IUsbManager;
-import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -35,12 +33,9 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CheckBox;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
-
 import com.android.systemui.R;
 
 public class UsbDebuggingActivity extends AlertActivity
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 6e88d0d..1e69fc5 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.usb;
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -25,8 +24,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.hardware.usb.IUsbManager;
-import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -42,7 +41,6 @@
 
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
-
 import com.android.systemui.R;
 
 public class UsbPermissionActivity extends AlertActivity
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index e61ef8a..0ed2a54 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.usb;
 
-import com.android.internal.R;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AlertDialog;
@@ -24,31 +23,30 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.DialogInterface.OnCancelListener;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageEventListener;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.widget.ImageView;
+import android.os.storage.IMountService;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
 import android.widget.Button;
+import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.util.Log;
+
+import com.android.internal.R;
 
 import java.util.List;
 
@@ -96,7 +94,7 @@
             switchDisplay(on);
         }
     };
-    
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -107,7 +105,7 @@
                 Log.w(TAG, "Failed to get StorageManager");
             }
         }
-        
+
         mUIHandler = new Handler();
 
         HandlerThread thr = new HandlerThread("SystemUI UsbStorageActivity");
@@ -186,7 +184,7 @@
     @Override
     protected void onPause() {
         super.onPause();
-        
+
         unregisterReceiver(mUsbStateReceiver);
         if (mStorageManager == null && mStorageListener != null) {
             mStorageManager.unregisterListener(mStorageListener);
@@ -258,7 +256,7 @@
                 // will be hidden once USB mass storage kicks in (or fails)
             }
         });
-        
+
         // things to do elsewhere
         mAsyncStorageHandler.post(new Runnable() {
             @Override
diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk
index ac84125..4c80a26 100644
--- a/packages/VpnDialogs/Android.mk
+++ b/packages/VpnDialogs/Android.mk
@@ -22,6 +22,8 @@
 
 LOCAL_CERTIFICATE := platform
 
+LOCAL_PRIVILEGED_MODULE := true
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := VpnDialogs
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 96de1b9..3d5654a 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -65,11 +65,18 @@
         }
 
         try {
-            mConfig = getIntent().getParcelableExtra("config");
 
             mService = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
+            mConfig = mService.getVpnConfig();
+
+            // mConfig can be null if we are a restricted user, in that case don't show this dialog
+            if (mConfig == null) {
+                finish();
+                return;
+            }
+
             View view = View.inflate(this, R.layout.manage, null);
             if (mConfig.session != null) {
                 ((TextView) view.findViewById(R.id.session)).setText(mConfig.session);
@@ -140,7 +147,7 @@
         mHandler.removeMessages(0);
 
         if (!isFinishing()) {
-            if (mConfig.startTime != 0) {
+            if (mConfig.startTime != -1) {
                 long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
                 mDuration.setText(String.format("%02d:%02d:%02d",
                         seconds / 3600, seconds / 60 % 60, seconds % 60));
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
new file mode 100644
index 0000000..09b41fd
--- /dev/null
+++ b/packages/WallpaperCropper/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_PACKAGE_NAME := WallpaperCropper
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
new file mode 100644
index 0000000..27755bd
--- /dev/null
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.wallpapercropper" >
+        <uses-permission android:name="android.permission.SET_WALLPAPER" />
+        <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+
+        <application android:requiredForAllUsers="true">
+        <activity
+            android:name="WallpaperCropActivity"
+            android:theme="@style/Theme.WallpaperCropper"
+            android:label="@string/crop_wallpaper"
+            android:finishOnCloseSystemDialogs="true">
+            <intent-filter>
+                <action android:name="android.service.wallpaper.CROP_AND_SET_WALLPAPER" />
+                <data android:mimeType="image/*" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        </application>
+</manifest>
diff --git a/cmds/system_server/MODULE_LICENSE_APACHE2 b/packages/WallpaperCropper/proguard.flags
similarity index 100%
copy from cmds/system_server/MODULE_LICENSE_APACHE2
copy to packages/WallpaperCropper/proguard.flags
diff --git a/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..53cf687
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..35cda8e
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..b52dc37
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml b/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml
new file mode 100644
index 0000000..1622742
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml
@@ -0,0 +1,34 @@
+<?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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:actionButtonStyle"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+    <TextView style="?android:actionBarTabTextStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="start|center_vertical"
+        android:paddingRight="20dp"
+        android:drawableLeft="@drawable/ic_actionbar_accept"
+        android:drawablePadding="8dp"
+        android:gravity="center_vertical"
+        android:text="@string/wallpaper_instructions" />
+</FrameLayout>
diff --git a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
new file mode 100644
index 0000000..6dc7e35
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
@@ -0,0 +1,39 @@
+<?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.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/wallpaper_cropper"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <com.android.wallpapercropper.CropView
+        android:id="@+id/cropView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+    <ProgressBar
+        android:id="@+id/loading"
+        style="@android:style/Widget.Holo.ProgressBar.Large"
+        android:visibility="invisible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:indeterminate="true"
+        android:indeterminateOnly="true"
+        android:background="@android:color/transparent" />
+</RelativeLayout>
diff --git a/packages/WallpaperCropper/res/values/strings.xml b/packages/WallpaperCropper/res/values/strings.xml
new file mode 100644
index 0000000..2b8111d
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="crop_wallpaper">Crop wallpaper</string>
+    <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper -->
+    <string name="wallpaper_instructions">Set wallpaper</string>
+</resources>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
new file mode 100644
index 0000000..2b63fe0
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<resources>
+    <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Holo">
+        <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowActionBarOverlay">true</item>
+    </style>
+
+    <style name="WallpaperCropperActionBar" parent="android:style/Widget.Holo.ActionBar">
+        <item name="android:displayOptions">showCustom</item>
+        <item name="android:background">#88000000</item>
+    </style>
+</resources>
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
new file mode 100644
index 0000000..a671ed2
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.common;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.os.Build;
+import android.util.FloatMath;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class BitmapUtils {
+    private static final String TAG = "BitmapUtils";
+    private static final int DEFAULT_JPEG_QUALITY = 90;
+    public static final int UNCONSTRAINED = -1;
+
+    private BitmapUtils(){}
+
+    /*
+     * Compute the sample size as a function of minSideLength
+     * and maxNumOfPixels.
+     * minSideLength is used to specify that minimal width or height of a
+     * bitmap.
+     * maxNumOfPixels is used to specify the maximal size in pixels that is
+     * tolerable in terms of memory usage.
+     *
+     * The function returns a sample size based on the constraints.
+     * Both size and minSideLength can be passed in as UNCONSTRAINED,
+     * which indicates no care of the corresponding constraint.
+     * The functions prefers returning a sample size that
+     * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
+     *
+     * Also, the function rounds up the sample size to a power of 2 or multiple
+     * of 8 because BitmapFactory only honors sample size this way.
+     * For example, BitmapFactory downsamples an image by 2 even though the
+     * request is 3. So we round up the sample size to avoid OOM.
+     */
+    public static int computeSampleSize(int width, int height,
+            int minSideLength, int maxNumOfPixels) {
+        int initialSize = computeInitialSampleSize(
+                width, height, minSideLength, maxNumOfPixels);
+
+        return initialSize <= 8
+                ? Utils.nextPowerOf2(initialSize)
+                : (initialSize + 7) / 8 * 8;
+    }
+
+    private static int computeInitialSampleSize(int w, int h,
+            int minSideLength, int maxNumOfPixels) {
+        if (maxNumOfPixels == UNCONSTRAINED
+                && minSideLength == UNCONSTRAINED) return 1;
+
+        int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
+                (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
+
+        if (minSideLength == UNCONSTRAINED) {
+            return lowerBound;
+        } else {
+            int sampleSize = Math.min(w / minSideLength, h / minSideLength);
+            return Math.max(sampleSize, lowerBound);
+        }
+    }
+
+    // This computes a sample size which makes the longer side at least
+    // minSideLength long. If that's not possible, return 1.
+    public static int computeSampleSizeLarger(int w, int h,
+            int minSideLength) {
+        int initialSize = Math.max(w / minSideLength, h / minSideLength);
+        if (initialSize <= 1) return 1;
+
+        return initialSize <= 8
+                ? Utils.prevPowerOf2(initialSize)
+                : initialSize / 8 * 8;
+    }
+
+    // Find the min x that 1 / x >= scale
+    public static int computeSampleSizeLarger(float scale) {
+        int initialSize = (int) FloatMath.floor(1f / scale);
+        if (initialSize <= 1) return 1;
+
+        return initialSize <= 8
+                ? Utils.prevPowerOf2(initialSize)
+                : initialSize / 8 * 8;
+    }
+
+    // Find the max x that 1 / x <= scale.
+    public static int computeSampleSize(float scale) {
+        Utils.assertTrue(scale > 0);
+        int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
+        return initialSize <= 8
+                ? Utils.nextPowerOf2(initialSize)
+                : (initialSize + 7) / 8 * 8;
+    }
+
+    public static Bitmap resizeBitmapByScale(
+            Bitmap bitmap, float scale, boolean recycle) {
+        int width = Math.round(bitmap.getWidth() * scale);
+        int height = Math.round(bitmap.getHeight() * scale);
+        if (width == bitmap.getWidth()
+                && height == bitmap.getHeight()) return bitmap;
+        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
+        Canvas canvas = new Canvas(target);
+        canvas.scale(scale, scale);
+        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+        canvas.drawBitmap(bitmap, 0, 0, paint);
+        if (recycle) bitmap.recycle();
+        return target;
+    }
+
+    private static Bitmap.Config getConfig(Bitmap bitmap) {
+        Bitmap.Config config = bitmap.getConfig();
+        if (config == null) {
+            config = Bitmap.Config.ARGB_8888;
+        }
+        return config;
+    }
+
+    public static Bitmap resizeDownBySideLength(
+            Bitmap bitmap, int maxLength, boolean recycle) {
+        int srcWidth = bitmap.getWidth();
+        int srcHeight = bitmap.getHeight();
+        float scale = Math.min(
+                (float) maxLength / srcWidth, (float) maxLength / srcHeight);
+        if (scale >= 1.0f) return bitmap;
+        return resizeBitmapByScale(bitmap, scale, recycle);
+    }
+
+    public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
+        int w = bitmap.getWidth();
+        int h = bitmap.getHeight();
+        if (w == size && h == size) return bitmap;
+
+        // scale the image so that the shorter side equals to the target;
+        // the longer side will be center-cropped.
+        float scale = (float) size / Math.min(w,  h);
+
+        Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
+        int width = Math.round(scale * bitmap.getWidth());
+        int height = Math.round(scale * bitmap.getHeight());
+        Canvas canvas = new Canvas(target);
+        canvas.translate((size - width) / 2f, (size - height) / 2f);
+        canvas.scale(scale, scale);
+        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+        canvas.drawBitmap(bitmap, 0, 0, paint);
+        if (recycle) bitmap.recycle();
+        return target;
+    }
+
+    public static void recycleSilently(Bitmap bitmap) {
+        if (bitmap == null) return;
+        try {
+            bitmap.recycle();
+        } catch (Throwable t) {
+            Log.w(TAG, "unable recycle bitmap", t);
+        }
+    }
+
+    public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
+        if (rotation == 0) return source;
+        int w = source.getWidth();
+        int h = source.getHeight();
+        Matrix m = new Matrix();
+        m.postRotate(rotation);
+        Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
+        if (recycle) source.recycle();
+        return bitmap;
+    }
+
+    public static Bitmap createVideoThumbnail(String filePath) {
+        // MediaMetadataRetriever is available on API Level 8
+        // but is hidden until API Level 10
+        Class<?> clazz = null;
+        Object instance = null;
+        try {
+            clazz = Class.forName("android.media.MediaMetadataRetriever");
+            instance = clazz.newInstance();
+
+            Method method = clazz.getMethod("setDataSource", String.class);
+            method.invoke(instance, filePath);
+
+            // The method name changes between API Level 9 and 10.
+            if (Build.VERSION.SDK_INT <= 9) {
+                return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
+            } else {
+                byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
+                if (data != null) {
+                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+                    if (bitmap != null) return bitmap;
+                }
+                return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
+            }
+        } catch (IllegalArgumentException ex) {
+            // Assume this is a corrupt video file
+        } catch (RuntimeException ex) {
+            // Assume this is a corrupt video file.
+        } catch (InstantiationException e) {
+            Log.e(TAG, "createVideoThumbnail", e);
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "createVideoThumbnail", e);
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "createVideoThumbnail", e);
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "createVideoThumbnail", e);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "createVideoThumbnail", e);
+        } finally {
+            try {
+                if (instance != null) {
+                    clazz.getMethod("release").invoke(instance);
+                }
+            } catch (Exception ignored) {
+            }
+        }
+        return null;
+    }
+
+    public static byte[] compressToBytes(Bitmap bitmap) {
+        return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
+    }
+
+    public static byte[] compressToBytes(Bitmap bitmap, int quality) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
+        bitmap.compress(CompressFormat.JPEG, quality, baos);
+        return baos.toByteArray();
+    }
+
+    public static boolean isSupportedByRegionDecoder(String mimeType) {
+        if (mimeType == null) return false;
+        mimeType = mimeType.toLowerCase();
+        return mimeType.startsWith("image/") &&
+                (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
+    }
+
+    public static boolean isRotationSupported(String mimeType) {
+        if (mimeType == null) return false;
+        mimeType = mimeType.toLowerCase();
+        return mimeType.equals("image/jpeg");
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java
new file mode 100644
index 0000000..614a081
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.common;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+public class Utils {
+    private static final String TAG = "Utils";
+    private static final String DEBUG_TAG = "GalleryDebug";
+
+    private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
+    private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
+
+    private static long[] sCrcTable = new long[256];
+
+    private static final boolean IS_DEBUG_BUILD =
+            Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug");
+
+    private static final String MASK_STRING = "********************************";
+
+    // Throws AssertionError if the input is false.
+    public static void assertTrue(boolean cond) {
+        if (!cond) {
+            throw new AssertionError();
+        }
+    }
+
+    // Throws AssertionError with the message. We had a method having the form
+    //   assertTrue(boolean cond, String message, Object ... args);
+    // However a call to that method will cause memory allocation even if the
+    // condition is false (due to autoboxing generated by "Object ... args"),
+    // so we don't use that anymore.
+    public static void fail(String message, Object ... args) {
+        throw new AssertionError(
+                args.length == 0 ? message : String.format(message, args));
+    }
+
+    // Throws NullPointerException if the input is null.
+    public static <T> T checkNotNull(T object) {
+        if (object == null) throw new NullPointerException();
+        return object;
+    }
+
+    // Returns true if two input Object are both null or equal
+    // to each other.
+    public static boolean equals(Object a, Object b) {
+        return (a == b) || (a == null ? false : a.equals(b));
+    }
+
+    // Returns the next power of two.
+    // Returns the input if it is already power of 2.
+    // Throws IllegalArgumentException if the input is <= 0 or
+    // the answer overflows.
+    public static int nextPowerOf2(int n) {
+        if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n);
+        n -= 1;
+        n |= n >> 16;
+        n |= n >> 8;
+        n |= n >> 4;
+        n |= n >> 2;
+        n |= n >> 1;
+        return n + 1;
+    }
+
+    // Returns the previous power of two.
+    // Returns the input if it is already power of 2.
+    // Throws IllegalArgumentException if the input is <= 0
+    public static int prevPowerOf2(int n) {
+        if (n <= 0) throw new IllegalArgumentException();
+        return Integer.highestOneBit(n);
+    }
+
+    // Returns the input value x clamped to the range [min, max].
+    public static int clamp(int x, int min, int max) {
+        if (x > max) return max;
+        if (x < min) return min;
+        return x;
+    }
+
+    // Returns the input value x clamped to the range [min, max].
+    public static float clamp(float x, float min, float max) {
+        if (x > max) return max;
+        if (x < min) return min;
+        return x;
+    }
+
+    // Returns the input value x clamped to the range [min, max].
+    public static long clamp(long x, long min, long max) {
+        if (x > max) return max;
+        if (x < min) return min;
+        return x;
+    }
+
+    public static boolean isOpaque(int color) {
+        return color >>> 24 == 0xFF;
+    }
+
+    public static void swap(int[] array, int i, int j) {
+        int temp = array[i];
+        array[i] = array[j];
+        array[j] = temp;
+    }
+
+    /**
+     * A function thats returns a 64-bit crc for string
+     *
+     * @param in input string
+     * @return a 64-bit crc value
+     */
+    public static final long crc64Long(String in) {
+        if (in == null || in.length() == 0) {
+            return 0;
+        }
+        return crc64Long(getBytes(in));
+    }
+
+    static {
+        // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
+        long part;
+        for (int i = 0; i < 256; i++) {
+            part = i;
+            for (int j = 0; j < 8; j++) {
+                long x = ((int) part & 1) != 0 ? POLY64REV : 0;
+                part = (part >> 1) ^ x;
+            }
+            sCrcTable[i] = part;
+        }
+    }
+
+    public static final long crc64Long(byte[] buffer) {
+        long crc = INITIALCRC;
+        for (int k = 0, n = buffer.length; k < n; ++k) {
+            crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
+        }
+        return crc;
+    }
+
+    public static byte[] getBytes(String in) {
+        byte[] result = new byte[in.length() * 2];
+        int output = 0;
+        for (char ch : in.toCharArray()) {
+            result[output++] = (byte) (ch & 0xFF);
+            result[output++] = (byte) (ch >> 8);
+        }
+        return result;
+    }
+
+    public static void closeSilently(Closeable c) {
+        if (c == null) return;
+        try {
+            c.close();
+        } catch (IOException t) {
+            Log.w(TAG, "close fail ", t);
+        }
+    }
+
+    public static int compare(long a, long b) {
+        return a < b ? -1 : a == b ? 0 : 1;
+    }
+
+    public static int ceilLog2(float value) {
+        int i;
+        for (i = 0; i < 31; i++) {
+            if ((1 << i) >= value) break;
+        }
+        return i;
+    }
+
+    public static int floorLog2(float value) {
+        int i;
+        for (i = 0; i < 31; i++) {
+            if ((1 << i) > value) break;
+        }
+        return i - 1;
+    }
+
+    public static void closeSilently(ParcelFileDescriptor fd) {
+        try {
+            if (fd != null) fd.close();
+        } catch (Throwable t) {
+            Log.w(TAG, "fail to close", t);
+        }
+    }
+
+    public static void closeSilently(Cursor cursor) {
+        try {
+            if (cursor != null) cursor.close();
+        } catch (Throwable t) {
+            Log.w(TAG, "fail to close", t);
+        }
+    }
+
+    public static float interpolateAngle(
+            float source, float target, float progress) {
+        // interpolate the angle from source to target
+        // We make the difference in the range of [-179, 180], this is the
+        // shortest path to change source to target.
+        float diff = target - source;
+        if (diff < 0) diff += 360f;
+        if (diff > 180) diff -= 360f;
+
+        float result = source + diff * progress;
+        return result < 0 ? result + 360f : result;
+    }
+
+    public static float interpolateScale(
+            float source, float target, float progress) {
+        return source + progress * (target - source);
+    }
+
+    public static String ensureNotNull(String value) {
+        return value == null ? "" : value;
+    }
+
+    public static float parseFloatSafely(String content, float defaultValue) {
+        if (content == null) return defaultValue;
+        try {
+            return Float.parseFloat(content);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    public static int parseIntSafely(String content, int defaultValue) {
+        if (content == null) return defaultValue;
+        try {
+            return Integer.parseInt(content);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    public static boolean isNullOrEmpty(String exifMake) {
+        return TextUtils.isEmpty(exifMake);
+    }
+
+    public static void waitWithoutInterrupt(Object object) {
+        try {
+            object.wait();
+        } catch (InterruptedException e) {
+            Log.w(TAG, "unexpected interrupt: " + object);
+        }
+    }
+
+    public static boolean handleInterrruptedException(Throwable e) {
+        // A helper to deal with the interrupt exception
+        // If an interrupt detected, we will setup the bit again.
+        if (e instanceof InterruptedIOException
+                || e instanceof InterruptedException) {
+            Thread.currentThread().interrupt();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return String with special XML characters escaped.
+     */
+    public static String escapeXml(String s) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0, len = s.length(); i < len; ++i) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '<':  sb.append("&lt;"); break;
+                case '>':  sb.append("&gt;"); break;
+                case '\"': sb.append("&quot;"); break;
+                case '\'': sb.append("&#039;"); break;
+                case '&':  sb.append("&amp;"); break;
+                default: sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String getUserAgent(Context context) {
+        PackageInfo packageInfo;
+        try {
+            packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+        } catch (NameNotFoundException e) {
+            throw new IllegalStateException("getPackageInfo failed");
+        }
+        return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s",
+                packageInfo.packageName,
+                packageInfo.versionName,
+                Build.BRAND,
+                Build.DEVICE,
+                Build.MODEL,
+                Build.ID,
+                Build.VERSION.SDK_INT,
+                Build.VERSION.RELEASE,
+                Build.VERSION.INCREMENTAL);
+    }
+
+    public static String[] copyOf(String[] source, int newSize) {
+        String[] result = new String[newSize];
+        newSize = Math.min(source.length, newSize);
+        System.arraycopy(source, 0, result, 0, newSize);
+        return result;
+    }
+
+    // Mask information for debugging only. It returns <code>info.toString()</code> directly
+    // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****")
+    // in release build to protect the information (e.g. for privacy issue).
+    public static String maskDebugInfo(Object info) {
+        if (info == null) return null;
+        String s = info.toString();
+        int length = Math.min(s.length(), MASK_STRING.length());
+        return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length);
+    }
+
+    // This method should be ONLY used for debugging.
+    public static void debug(String message, Object ... args) {
+        Log.v(DEBUG_TAG, String.format(message, args));
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java
new file mode 100644
index 0000000..7fb9f22
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+class ByteBufferInputStream extends InputStream {
+
+    private ByteBuffer mBuf;
+
+    public ByteBufferInputStream(ByteBuffer buf) {
+        mBuf = buf;
+    }
+
+    @Override
+    public int read() {
+        if (!mBuf.hasRemaining()) {
+            return -1;
+        }
+        return mBuf.get() & 0xFF;
+    }
+
+    @Override
+    public int read(byte[] bytes, int off, int len) {
+        if (!mBuf.hasRemaining()) {
+            return -1;
+        }
+
+        len = Math.min(len, mBuf.remaining());
+        mBuf.get(bytes, off, len);
+        return len;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java
new file mode 100644
index 0000000..dfd4a1a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+class CountedDataInputStream extends FilterInputStream {
+
+    private int mCount = 0;
+
+    // allocate a byte buffer for a long value;
+    private final byte mByteArray[] = new byte[8];
+    private final ByteBuffer mByteBuffer = ByteBuffer.wrap(mByteArray);
+
+    protected CountedDataInputStream(InputStream in) {
+        super(in);
+    }
+
+    public int getReadByteCount() {
+        return mCount;
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        int r = in.read(b);
+        mCount += (r >= 0) ? r : 0;
+        return r;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int r = in.read(b, off, len);
+        mCount += (r >= 0) ? r : 0;
+        return r;
+    }
+
+    @Override
+    public int read() throws IOException {
+        int r = in.read();
+        mCount += (r >= 0) ? 1 : 0;
+        return r;
+    }
+
+    @Override
+    public long skip(long length) throws IOException {
+        long skip = in.skip(length);
+        mCount += skip;
+        return skip;
+    }
+
+    public void skipOrThrow(long length) throws IOException {
+        if (skip(length) != length) throw new EOFException();
+    }
+
+    public void skipTo(long target) throws IOException {
+        long cur = mCount;
+        long diff = target - cur;
+        assert(diff >= 0);
+        skipOrThrow(diff);
+    }
+
+    public void readOrThrow(byte[] b, int off, int len) throws IOException {
+        int r = read(b, off, len);
+        if (r != len) throw new EOFException();
+    }
+
+    public void readOrThrow(byte[] b) throws IOException {
+        readOrThrow(b, 0, b.length);
+    }
+
+    public void setByteOrder(ByteOrder order) {
+        mByteBuffer.order(order);
+    }
+
+    public ByteOrder getByteOrder() {
+        return mByteBuffer.order();
+    }
+
+    public short readShort() throws IOException {
+        readOrThrow(mByteArray, 0 ,2);
+        mByteBuffer.rewind();
+        return mByteBuffer.getShort();
+    }
+
+    public int readUnsignedShort() throws IOException {
+        return readShort() & 0xffff;
+    }
+
+    public int readInt() throws IOException {
+        readOrThrow(mByteArray, 0 , 4);
+        mByteBuffer.rewind();
+        return mByteBuffer.getInt();
+    }
+
+    public long readUnsignedInt() throws IOException {
+        return readInt() & 0xffffffffL;
+    }
+
+    public long readLong() throws IOException {
+        readOrThrow(mByteArray, 0 , 8);
+        mByteBuffer.rewind();
+        return mByteBuffer.getLong();
+    }
+
+    public String readString(int n) throws IOException {
+        byte buf[] = new byte[n];
+        readOrThrow(buf);
+        return new String(buf, "UTF8");
+    }
+
+    public String readString(int n, Charset charset) throws IOException {
+        byte buf[] = new byte[n];
+        readOrThrow(buf);
+        return new String(buf, charset);
+    }
+}
\ No newline at end of file
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java
new file mode 100644
index 0000000..8422382
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class stores the EXIF header in IFDs according to the JPEG
+ * specification. It is the result produced by {@link ExifReader}.
+ *
+ * @see ExifReader
+ * @see IfdData
+ */
+class ExifData {
+    private static final String TAG = "ExifData";
+    private static final byte[] USER_COMMENT_ASCII = {
+            0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
+    };
+    private static final byte[] USER_COMMENT_JIS = {
+            0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    private static final byte[] USER_COMMENT_UNICODE = {
+            0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
+    };
+
+    private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
+    private byte[] mThumbnail;
+    private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
+    private final ByteOrder mByteOrder;
+
+    ExifData(ByteOrder order) {
+        mByteOrder = order;
+    }
+
+    /**
+     * Gets the compressed thumbnail. Returns null if there is no compressed
+     * thumbnail.
+     *
+     * @see #hasCompressedThumbnail()
+     */
+    protected byte[] getCompressedThumbnail() {
+        return mThumbnail;
+    }
+
+    /**
+     * Sets the compressed thumbnail.
+     */
+    protected void setCompressedThumbnail(byte[] thumbnail) {
+        mThumbnail = thumbnail;
+    }
+
+    /**
+     * Returns true it this header contains a compressed thumbnail.
+     */
+    protected boolean hasCompressedThumbnail() {
+        return mThumbnail != null;
+    }
+
+    /**
+     * Adds an uncompressed strip.
+     */
+    protected void setStripBytes(int index, byte[] strip) {
+        if (index < mStripBytes.size()) {
+            mStripBytes.set(index, strip);
+        } else {
+            for (int i = mStripBytes.size(); i < index; i++) {
+                mStripBytes.add(null);
+            }
+            mStripBytes.add(strip);
+        }
+    }
+
+    /**
+     * Gets the strip count.
+     */
+    protected int getStripCount() {
+        return mStripBytes.size();
+    }
+
+    /**
+     * Gets the strip at the specified index.
+     *
+     * @exceptions #IndexOutOfBoundException
+     */
+    protected byte[] getStrip(int index) {
+        return mStripBytes.get(index);
+    }
+
+    /**
+     * Returns true if this header contains uncompressed strip.
+     */
+    protected boolean hasUncompressedStrip() {
+        return mStripBytes.size() != 0;
+    }
+
+    /**
+     * Gets the byte order.
+     */
+    protected ByteOrder getByteOrder() {
+        return mByteOrder;
+    }
+
+    /**
+     * Returns the {@link IfdData} object corresponding to a given IFD if it
+     * exists or null.
+     */
+    protected IfdData getIfdData(int ifdId) {
+        if (ExifTag.isValidIfd(ifdId)) {
+            return mIfdDatas[ifdId];
+        }
+        return null;
+    }
+
+    /**
+     * Adds IFD data. If IFD data of the same type already exists, it will be
+     * replaced by the new data.
+     */
+    protected void addIfdData(IfdData data) {
+        mIfdDatas[data.getId()] = data;
+    }
+
+    /**
+     * Returns the {@link IfdData} object corresponding to a given IFD or
+     * generates one if none exist.
+     */
+    protected IfdData getOrCreateIfdData(int ifdId) {
+        IfdData ifdData = mIfdDatas[ifdId];
+        if (ifdData == null) {
+            ifdData = new IfdData(ifdId);
+            mIfdDatas[ifdId] = ifdData;
+        }
+        return ifdData;
+    }
+
+    /**
+     * Returns the tag with a given TID in the given IFD if the tag exists.
+     * Otherwise returns null.
+     */
+    protected ExifTag getTag(short tag, int ifd) {
+        IfdData ifdData = mIfdDatas[ifd];
+        return (ifdData == null) ? null : ifdData.getTag(tag);
+    }
+
+    /**
+     * Adds the given ExifTag to its default IFD and returns an existing ExifTag
+     * with the same TID or null if none exist.
+     */
+    protected ExifTag addTag(ExifTag tag) {
+        if (tag != null) {
+            int ifd = tag.getIfd();
+            return addTag(tag, ifd);
+        }
+        return null;
+    }
+
+    /**
+     * Adds the given ExifTag to the given IFD and returns an existing ExifTag
+     * with the same TID or null if none exist.
+     */
+    protected ExifTag addTag(ExifTag tag, int ifdId) {
+        if (tag != null && ExifTag.isValidIfd(ifdId)) {
+            IfdData ifdData = getOrCreateIfdData(ifdId);
+            return ifdData.setTag(tag);
+        }
+        return null;
+    }
+
+    protected void clearThumbnailAndStrips() {
+        mThumbnail = null;
+        mStripBytes.clear();
+    }
+
+    /**
+     * Removes the thumbnail and its related tags. IFD1 will be removed.
+     */
+    protected void removeThumbnailData() {
+        clearThumbnailAndStrips();
+        mIfdDatas[IfdId.TYPE_IFD_1] = null;
+    }
+
+    /**
+     * Removes the tag with a given TID and IFD.
+     */
+    protected void removeTag(short tagId, int ifdId) {
+        IfdData ifdData = mIfdDatas[ifdId];
+        if (ifdData == null) {
+            return;
+        }
+        ifdData.removeTag(tagId);
+    }
+
+    /**
+     * Decodes the user comment tag into string as specified in the EXIF
+     * standard. Returns null if decoding failed.
+     */
+    protected String getUserComment() {
+        IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
+        if (ifdData == null) {
+            return null;
+        }
+        ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
+        if (tag == null) {
+            return null;
+        }
+        if (tag.getComponentCount() < 8) {
+            return null;
+        }
+
+        byte[] buf = new byte[tag.getComponentCount()];
+        tag.getBytes(buf);
+
+        byte[] code = new byte[8];
+        System.arraycopy(buf, 0, code, 0, 8);
+
+        try {
+            if (Arrays.equals(code, USER_COMMENT_ASCII)) {
+                return new String(buf, 8, buf.length - 8, "US-ASCII");
+            } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
+                return new String(buf, 8, buf.length - 8, "EUC-JP");
+            } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
+                return new String(buf, 8, buf.length - 8, "UTF-16");
+            } else {
+                return null;
+            }
+        } catch (UnsupportedEncodingException e) {
+            Log.w(TAG, "Failed to decode the user comment");
+            return null;
+        }
+    }
+
+    /**
+     * Returns a list of all {@link ExifTag}s in the ExifData or null if there
+     * are none.
+     */
+    protected List<ExifTag> getAllTags() {
+        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+        for (IfdData d : mIfdDatas) {
+            if (d != null) {
+                ExifTag[] tags = d.getAllTags();
+                if (tags != null) {
+                    for (ExifTag t : tags) {
+                        ret.add(t);
+                    }
+                }
+            }
+        }
+        if (ret.size() == 0) {
+            return null;
+        }
+        return ret;
+    }
+
+    /**
+     * Returns a list of all {@link ExifTag}s in a given IFD or null if there
+     * are none.
+     */
+    protected List<ExifTag> getAllTagsForIfd(int ifd) {
+        IfdData d = mIfdDatas[ifd];
+        if (d == null) {
+            return null;
+        }
+        ExifTag[] tags = d.getAllTags();
+        if (tags == null) {
+            return null;
+        }
+        ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
+        for (ExifTag t : tags) {
+            ret.add(t);
+        }
+        if (ret.size() == 0) {
+            return null;
+        }
+        return ret;
+    }
+
+    /**
+     * Returns a list of all {@link ExifTag}s with a given TID or null if there
+     * are none.
+     */
+    protected List<ExifTag> getAllTagsForTagId(short tag) {
+        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+        for (IfdData d : mIfdDatas) {
+            if (d != null) {
+                ExifTag t = d.getTag(tag);
+                if (t != null) {
+                    ret.add(t);
+                }
+            }
+        }
+        if (ret.size() == 0) {
+            return null;
+        }
+        return ret;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof ExifData) {
+            ExifData data = (ExifData) obj;
+            if (data.mByteOrder != mByteOrder ||
+                    data.mStripBytes.size() != mStripBytes.size() ||
+                    !Arrays.equals(data.mThumbnail, mThumbnail)) {
+                return false;
+            }
+            for (int i = 0; i < mStripBytes.size(); i++) {
+                if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
+                    return false;
+                }
+            }
+            for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+                IfdData ifd1 = data.getIfdData(i);
+                IfdData ifd2 = getIfdData(i);
+                if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java
new file mode 100644
index 0000000..a1cf0fc
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java
@@ -0,0 +1,2407 @@
+/*
+ * 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.gallery3d.exif;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.SparseIntArray;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel.MapMode;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * This class provides methods and constants for reading and writing jpeg file
+ * metadata. It contains a collection of ExifTags, and a collection of
+ * definitions for creating valid ExifTags. The collection of ExifTags can be
+ * updated by: reading new ones from a file, deleting or adding existing ones,
+ * or building new ExifTags from a tag definition. These ExifTags can be written
+ * to a valid jpeg image as exif metadata.
+ * <p>
+ * Each ExifTag has a tag ID (TID) and is stored in a specific image file
+ * directory (IFD) as specified by the exif standard. A tag definition can be
+ * looked up with a constant that is a combination of TID and IFD. This
+ * definition has information about the type, number of components, and valid
+ * IFDs for a tag.
+ *
+ * @see ExifTag
+ */
+public class ExifInterface {
+    public static final int TAG_NULL = -1;
+    public static final int IFD_NULL = -1;
+    public static final int DEFINITION_NULL = 0;
+
+    /**
+     * Tag constants for Jeita EXIF 2.2
+     */
+
+    // IFD 0
+    public static final int TAG_IMAGE_WIDTH =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0100);
+    public static final int TAG_IMAGE_LENGTH =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0101); // Image height
+    public static final int TAG_BITS_PER_SAMPLE =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0102);
+    public static final int TAG_COMPRESSION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0103);
+    public static final int TAG_PHOTOMETRIC_INTERPRETATION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0106);
+    public static final int TAG_IMAGE_DESCRIPTION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x010E);
+    public static final int TAG_MAKE =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x010F);
+    public static final int TAG_MODEL =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0110);
+    public static final int TAG_STRIP_OFFSETS =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0111);
+    public static final int TAG_ORIENTATION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0112);
+    public static final int TAG_SAMPLES_PER_PIXEL =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0115);
+    public static final int TAG_ROWS_PER_STRIP =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0116);
+    public static final int TAG_STRIP_BYTE_COUNTS =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0117);
+    public static final int TAG_X_RESOLUTION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x011A);
+    public static final int TAG_Y_RESOLUTION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x011B);
+    public static final int TAG_PLANAR_CONFIGURATION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x011C);
+    public static final int TAG_RESOLUTION_UNIT =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0128);
+    public static final int TAG_TRANSFER_FUNCTION =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x012D);
+    public static final int TAG_SOFTWARE =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0131);
+    public static final int TAG_DATE_TIME =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0132);
+    public static final int TAG_ARTIST =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x013B);
+    public static final int TAG_WHITE_POINT =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x013E);
+    public static final int TAG_PRIMARY_CHROMATICITIES =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x013F);
+    public static final int TAG_Y_CB_CR_COEFFICIENTS =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0211);
+    public static final int TAG_Y_CB_CR_SUB_SAMPLING =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0212);
+    public static final int TAG_Y_CB_CR_POSITIONING =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0213);
+    public static final int TAG_REFERENCE_BLACK_WHITE =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x0214);
+    public static final int TAG_COPYRIGHT =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x8298);
+    public static final int TAG_EXIF_IFD =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x8769);
+    public static final int TAG_GPS_IFD =
+        defineTag(IfdId.TYPE_IFD_0, (short) 0x8825);
+    // IFD 1
+    public static final int TAG_JPEG_INTERCHANGE_FORMAT =
+        defineTag(IfdId.TYPE_IFD_1, (short) 0x0201);
+    public static final int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH =
+        defineTag(IfdId.TYPE_IFD_1, (short) 0x0202);
+    // IFD Exif Tags
+    public static final int TAG_EXPOSURE_TIME =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829A);
+    public static final int TAG_F_NUMBER =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829D);
+    public static final int TAG_EXPOSURE_PROGRAM =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8822);
+    public static final int TAG_SPECTRAL_SENSITIVITY =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8824);
+    public static final int TAG_ISO_SPEED_RATINGS =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8827);
+    public static final int TAG_OECF =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8828);
+    public static final int TAG_EXIF_VERSION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9000);
+    public static final int TAG_DATE_TIME_ORIGINAL =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9003);
+    public static final int TAG_DATE_TIME_DIGITIZED =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9004);
+    public static final int TAG_COMPONENTS_CONFIGURATION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9101);
+    public static final int TAG_COMPRESSED_BITS_PER_PIXEL =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9102);
+    public static final int TAG_SHUTTER_SPEED_VALUE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9201);
+    public static final int TAG_APERTURE_VALUE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9202);
+    public static final int TAG_BRIGHTNESS_VALUE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9203);
+    public static final int TAG_EXPOSURE_BIAS_VALUE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9204);
+    public static final int TAG_MAX_APERTURE_VALUE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9205);
+    public static final int TAG_SUBJECT_DISTANCE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9206);
+    public static final int TAG_METERING_MODE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9207);
+    public static final int TAG_LIGHT_SOURCE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9208);
+    public static final int TAG_FLASH =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9209);
+    public static final int TAG_FOCAL_LENGTH =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x920A);
+    public static final int TAG_SUBJECT_AREA =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9214);
+    public static final int TAG_MAKER_NOTE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x927C);
+    public static final int TAG_USER_COMMENT =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9286);
+    public static final int TAG_SUB_SEC_TIME =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9290);
+    public static final int TAG_SUB_SEC_TIME_ORIGINAL =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9291);
+    public static final int TAG_SUB_SEC_TIME_DIGITIZED =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9292);
+    public static final int TAG_FLASHPIX_VERSION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA000);
+    public static final int TAG_COLOR_SPACE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA001);
+    public static final int TAG_PIXEL_X_DIMENSION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA002);
+    public static final int TAG_PIXEL_Y_DIMENSION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA003);
+    public static final int TAG_RELATED_SOUND_FILE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA004);
+    public static final int TAG_INTEROPERABILITY_IFD =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA005);
+    public static final int TAG_FLASH_ENERGY =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20B);
+    public static final int TAG_SPATIAL_FREQUENCY_RESPONSE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20C);
+    public static final int TAG_FOCAL_PLANE_X_RESOLUTION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20E);
+    public static final int TAG_FOCAL_PLANE_Y_RESOLUTION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20F);
+    public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA210);
+    public static final int TAG_SUBJECT_LOCATION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA214);
+    public static final int TAG_EXPOSURE_INDEX =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA215);
+    public static final int TAG_SENSING_METHOD =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA217);
+    public static final int TAG_FILE_SOURCE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA300);
+    public static final int TAG_SCENE_TYPE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA301);
+    public static final int TAG_CFA_PATTERN =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA302);
+    public static final int TAG_CUSTOM_RENDERED =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA401);
+    public static final int TAG_EXPOSURE_MODE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA402);
+    public static final int TAG_WHITE_BALANCE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA403);
+    public static final int TAG_DIGITAL_ZOOM_RATIO =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA404);
+    public static final int TAG_FOCAL_LENGTH_IN_35_MM_FILE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA405);
+    public static final int TAG_SCENE_CAPTURE_TYPE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA406);
+    public static final int TAG_GAIN_CONTROL =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA407);
+    public static final int TAG_CONTRAST =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA408);
+    public static final int TAG_SATURATION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA409);
+    public static final int TAG_SHARPNESS =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40A);
+    public static final int TAG_DEVICE_SETTING_DESCRIPTION =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40B);
+    public static final int TAG_SUBJECT_DISTANCE_RANGE =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40C);
+    public static final int TAG_IMAGE_UNIQUE_ID =
+        defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA420);
+    // IFD GPS tags
+    public static final int TAG_GPS_VERSION_ID =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 0);
+    public static final int TAG_GPS_LATITUDE_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 1);
+    public static final int TAG_GPS_LATITUDE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 2);
+    public static final int TAG_GPS_LONGITUDE_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 3);
+    public static final int TAG_GPS_LONGITUDE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 4);
+    public static final int TAG_GPS_ALTITUDE_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 5);
+    public static final int TAG_GPS_ALTITUDE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 6);
+    public static final int TAG_GPS_TIME_STAMP =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 7);
+    public static final int TAG_GPS_SATTELLITES =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 8);
+    public static final int TAG_GPS_STATUS =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 9);
+    public static final int TAG_GPS_MEASURE_MODE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 10);
+    public static final int TAG_GPS_DOP =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 11);
+    public static final int TAG_GPS_SPEED_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 12);
+    public static final int TAG_GPS_SPEED =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 13);
+    public static final int TAG_GPS_TRACK_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 14);
+    public static final int TAG_GPS_TRACK =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 15);
+    public static final int TAG_GPS_IMG_DIRECTION_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 16);
+    public static final int TAG_GPS_IMG_DIRECTION =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 17);
+    public static final int TAG_GPS_MAP_DATUM =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 18);
+    public static final int TAG_GPS_DEST_LATITUDE_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 19);
+    public static final int TAG_GPS_DEST_LATITUDE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 20);
+    public static final int TAG_GPS_DEST_LONGITUDE_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 21);
+    public static final int TAG_GPS_DEST_LONGITUDE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 22);
+    public static final int TAG_GPS_DEST_BEARING_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 23);
+    public static final int TAG_GPS_DEST_BEARING =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 24);
+    public static final int TAG_GPS_DEST_DISTANCE_REF =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 25);
+    public static final int TAG_GPS_DEST_DISTANCE =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 26);
+    public static final int TAG_GPS_PROCESSING_METHOD =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 27);
+    public static final int TAG_GPS_AREA_INFORMATION =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 28);
+    public static final int TAG_GPS_DATE_STAMP =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 29);
+    public static final int TAG_GPS_DIFFERENTIAL =
+        defineTag(IfdId.TYPE_IFD_GPS, (short) 30);
+    // IFD Interoperability tags
+    public static final int TAG_INTEROPERABILITY_INDEX =
+        defineTag(IfdId.TYPE_IFD_INTEROPERABILITY, (short) 1);
+
+    /**
+     * Tags that contain offset markers. These are included in the banned
+     * defines.
+     */
+    private static HashSet<Short> sOffsetTags = new HashSet<Short>();
+    static {
+        sOffsetTags.add(getTrueTagKey(TAG_GPS_IFD));
+        sOffsetTags.add(getTrueTagKey(TAG_EXIF_IFD));
+        sOffsetTags.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT));
+        sOffsetTags.add(getTrueTagKey(TAG_INTEROPERABILITY_IFD));
+        sOffsetTags.add(getTrueTagKey(TAG_STRIP_OFFSETS));
+    }
+
+    /**
+     * Tags with definitions that cannot be overridden (banned defines).
+     */
+    protected static HashSet<Short> sBannedDefines = new HashSet<Short>(sOffsetTags);
+    static {
+        sBannedDefines.add(getTrueTagKey(TAG_NULL));
+        sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+        sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS));
+    }
+
+    /**
+     * Returns the constant representing a tag with a given TID and default IFD.
+     */
+    public static int defineTag(int ifdId, short tagId) {
+        return (tagId & 0x0000ffff) | (ifdId << 16);
+    }
+
+    /**
+     * Returns the TID for a tag constant.
+     */
+    public static short getTrueTagKey(int tag) {
+        // Truncate
+        return (short) tag;
+    }
+
+    /**
+     * Returns the default IFD for a tag constant.
+     */
+    public static int getTrueIfd(int tag) {
+        return tag >>> 16;
+    }
+
+    /**
+     * Constants for {@link TAG_ORIENTATION}. They can be interpreted as
+     * follows:
+     * <ul>
+     * <li>TOP_LEFT is the normal orientation.</li>
+     * <li>TOP_RIGHT is a left-right mirror.</li>
+     * <li>BOTTOM_LEFT is a 180 degree rotation.</li>
+     * <li>BOTTOM_RIGHT is a top-bottom mirror.</li>
+     * <li>LEFT_TOP is mirrored about the top-left<->bottom-right axis.</li>
+     * <li>RIGHT_TOP is a 90 degree clockwise rotation.</li>
+     * <li>LEFT_BOTTOM is mirrored about the top-right<->bottom-left axis.</li>
+     * <li>RIGHT_BOTTOM is a 270 degree clockwise rotation.</li>
+     * </ul>
+     */
+    public static interface Orientation {
+        public static final short TOP_LEFT = 1;
+        public static final short TOP_RIGHT = 2;
+        public static final short BOTTOM_LEFT = 3;
+        public static final short BOTTOM_RIGHT = 4;
+        public static final short LEFT_TOP = 5;
+        public static final short RIGHT_TOP = 6;
+        public static final short LEFT_BOTTOM = 7;
+        public static final short RIGHT_BOTTOM = 8;
+    }
+
+    /**
+     * Constants for {@link TAG_Y_CB_CR_POSITIONING}
+     */
+    public static interface YCbCrPositioning {
+        public static final short CENTERED = 1;
+        public static final short CO_SITED = 2;
+    }
+
+    /**
+     * Constants for {@link TAG_COMPRESSION}
+     */
+    public static interface Compression {
+        public static final short UNCOMPRESSION = 1;
+        public static final short JPEG = 6;
+    }
+
+    /**
+     * Constants for {@link TAG_RESOLUTION_UNIT}
+     */
+    public static interface ResolutionUnit {
+        public static final short INCHES = 2;
+        public static final short CENTIMETERS = 3;
+    }
+
+    /**
+     * Constants for {@link TAG_PHOTOMETRIC_INTERPRETATION}
+     */
+    public static interface PhotometricInterpretation {
+        public static final short RGB = 2;
+        public static final short YCBCR = 6;
+    }
+
+    /**
+     * Constants for {@link TAG_PLANAR_CONFIGURATION}
+     */
+    public static interface PlanarConfiguration {
+        public static final short CHUNKY = 1;
+        public static final short PLANAR = 2;
+    }
+
+    /**
+     * Constants for {@link TAG_EXPOSURE_PROGRAM}
+     */
+    public static interface ExposureProgram {
+        public static final short NOT_DEFINED = 0;
+        public static final short MANUAL = 1;
+        public static final short NORMAL_PROGRAM = 2;
+        public static final short APERTURE_PRIORITY = 3;
+        public static final short SHUTTER_PRIORITY = 4;
+        public static final short CREATIVE_PROGRAM = 5;
+        public static final short ACTION_PROGRAM = 6;
+        public static final short PROTRAIT_MODE = 7;
+        public static final short LANDSCAPE_MODE = 8;
+    }
+
+    /**
+     * Constants for {@link TAG_METERING_MODE}
+     */
+    public static interface MeteringMode {
+        public static final short UNKNOWN = 0;
+        public static final short AVERAGE = 1;
+        public static final short CENTER_WEIGHTED_AVERAGE = 2;
+        public static final short SPOT = 3;
+        public static final short MULTISPOT = 4;
+        public static final short PATTERN = 5;
+        public static final short PARTAIL = 6;
+        public static final short OTHER = 255;
+    }
+
+    /**
+     * Constants for {@link TAG_FLASH} As the definition in Jeita EXIF 2.2
+     * standard, we can treat this constant as bitwise flag.
+     * <p>
+     * e.g.
+     * <p>
+     * short flash = FIRED | RETURN_STROBE_RETURN_LIGHT_DETECTED |
+     * MODE_AUTO_MODE
+     */
+    public static interface Flash {
+        // LSB
+        public static final short DID_NOT_FIRED = 0;
+        public static final short FIRED = 1;
+        // 1st~2nd bits
+        public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
+        public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
+        public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
+        // 3rd~4th bits
+        public static final short MODE_UNKNOWN = 0 << 3;
+        public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
+        public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
+        public static final short MODE_AUTO_MODE = 3 << 3;
+        // 5th bit
+        public static final short FUNCTION_PRESENT = 0 << 5;
+        public static final short FUNCTION_NO_FUNCTION = 1 << 5;
+        // 6th bit
+        public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
+        public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
+    }
+
+    /**
+     * Constants for {@link TAG_COLOR_SPACE}
+     */
+    public static interface ColorSpace {
+        public static final short SRGB = 1;
+        public static final short UNCALIBRATED = (short) 0xFFFF;
+    }
+
+    /**
+     * Constants for {@link TAG_EXPOSURE_MODE}
+     */
+    public static interface ExposureMode {
+        public static final short AUTO_EXPOSURE = 0;
+        public static final short MANUAL_EXPOSURE = 1;
+        public static final short AUTO_BRACKET = 2;
+    }
+
+    /**
+     * Constants for {@link TAG_WHITE_BALANCE}
+     */
+    public static interface WhiteBalance {
+        public static final short AUTO = 0;
+        public static final short MANUAL = 1;
+    }
+
+    /**
+     * Constants for {@link TAG_SCENE_CAPTURE_TYPE}
+     */
+    public static interface SceneCapture {
+        public static final short STANDARD = 0;
+        public static final short LANDSCAPE = 1;
+        public static final short PROTRAIT = 2;
+        public static final short NIGHT_SCENE = 3;
+    }
+
+    /**
+     * Constants for {@link TAG_COMPONENTS_CONFIGURATION}
+     */
+    public static interface ComponentsConfiguration {
+        public static final short NOT_EXIST = 0;
+        public static final short Y = 1;
+        public static final short CB = 2;
+        public static final short CR = 3;
+        public static final short R = 4;
+        public static final short G = 5;
+        public static final short B = 6;
+    }
+
+    /**
+     * Constants for {@link TAG_LIGHT_SOURCE}
+     */
+    public static interface LightSource {
+        public static final short UNKNOWN = 0;
+        public static final short DAYLIGHT = 1;
+        public static final short FLUORESCENT = 2;
+        public static final short TUNGSTEN = 3;
+        public static final short FLASH = 4;
+        public static final short FINE_WEATHER = 9;
+        public static final short CLOUDY_WEATHER = 10;
+        public static final short SHADE = 11;
+        public static final short DAYLIGHT_FLUORESCENT = 12;
+        public static final short DAY_WHITE_FLUORESCENT = 13;
+        public static final short COOL_WHITE_FLUORESCENT = 14;
+        public static final short WHITE_FLUORESCENT = 15;
+        public static final short STANDARD_LIGHT_A = 17;
+        public static final short STANDARD_LIGHT_B = 18;
+        public static final short STANDARD_LIGHT_C = 19;
+        public static final short D55 = 20;
+        public static final short D65 = 21;
+        public static final short D75 = 22;
+        public static final short D50 = 23;
+        public static final short ISO_STUDIO_TUNGSTEN = 24;
+        public static final short OTHER = 255;
+    }
+
+    /**
+     * Constants for {@link TAG_SENSING_METHOD}
+     */
+    public static interface SensingMethod {
+        public static final short NOT_DEFINED = 1;
+        public static final short ONE_CHIP_COLOR = 2;
+        public static final short TWO_CHIP_COLOR = 3;
+        public static final short THREE_CHIP_COLOR = 4;
+        public static final short COLOR_SEQUENTIAL_AREA = 5;
+        public static final short TRILINEAR = 7;
+        public static final short COLOR_SEQUENTIAL_LINEAR = 8;
+    }
+
+    /**
+     * Constants for {@link TAG_FILE_SOURCE}
+     */
+    public static interface FileSource {
+        public static final short DSC = 3;
+    }
+
+    /**
+     * Constants for {@link TAG_SCENE_TYPE}
+     */
+    public static interface SceneType {
+        public static final short DIRECT_PHOTOGRAPHED = 1;
+    }
+
+    /**
+     * Constants for {@link TAG_GAIN_CONTROL}
+     */
+    public static interface GainControl {
+        public static final short NONE = 0;
+        public static final short LOW_UP = 1;
+        public static final short HIGH_UP = 2;
+        public static final short LOW_DOWN = 3;
+        public static final short HIGH_DOWN = 4;
+    }
+
+    /**
+     * Constants for {@link TAG_CONTRAST}
+     */
+    public static interface Contrast {
+        public static final short NORMAL = 0;
+        public static final short SOFT = 1;
+        public static final short HARD = 2;
+    }
+
+    /**
+     * Constants for {@link TAG_SATURATION}
+     */
+    public static interface Saturation {
+        public static final short NORMAL = 0;
+        public static final short LOW = 1;
+        public static final short HIGH = 2;
+    }
+
+    /**
+     * Constants for {@link TAG_SHARPNESS}
+     */
+    public static interface Sharpness {
+        public static final short NORMAL = 0;
+        public static final short SOFT = 1;
+        public static final short HARD = 2;
+    }
+
+    /**
+     * Constants for {@link TAG_SUBJECT_DISTANCE}
+     */
+    public static interface SubjectDistance {
+        public static final short UNKNOWN = 0;
+        public static final short MACRO = 1;
+        public static final short CLOSE_VIEW = 2;
+        public static final short DISTANT_VIEW = 3;
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_LATITUDE_REF},
+     * {@link TAG_GPS_DEST_LATITUDE_REF}
+     */
+    public static interface GpsLatitudeRef {
+        public static final String NORTH = "N";
+        public static final String SOUTH = "S";
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_LONGITUDE_REF},
+     * {@link TAG_GPS_DEST_LONGITUDE_REF}
+     */
+    public static interface GpsLongitudeRef {
+        public static final String EAST = "E";
+        public static final String WEST = "W";
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_ALTITUDE_REF}
+     */
+    public static interface GpsAltitudeRef {
+        public static final short SEA_LEVEL = 0;
+        public static final short SEA_LEVEL_NEGATIVE = 1;
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_STATUS}
+     */
+    public static interface GpsStatus {
+        public static final String IN_PROGRESS = "A";
+        public static final String INTEROPERABILITY = "V";
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_MEASURE_MODE}
+     */
+    public static interface GpsMeasureMode {
+        public static final String MODE_2_DIMENSIONAL = "2";
+        public static final String MODE_3_DIMENSIONAL = "3";
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_SPEED_REF},
+     * {@link TAG_GPS_DEST_DISTANCE_REF}
+     */
+    public static interface GpsSpeedRef {
+        public static final String KILOMETERS = "K";
+        public static final String MILES = "M";
+        public static final String KNOTS = "N";
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_TRACK_REF},
+     * {@link TAG_GPS_IMG_DIRECTION_REF}, {@link TAG_GPS_DEST_BEARING_REF}
+     */
+    public static interface GpsTrackRef {
+        public static final String TRUE_DIRECTION = "T";
+        public static final String MAGNETIC_DIRECTION = "M";
+    }
+
+    /**
+     * Constants for {@link TAG_GPS_DIFFERENTIAL}
+     */
+    public static interface GpsDifferential {
+        public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
+        public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
+    }
+
+    private static final String NULL_ARGUMENT_STRING = "Argument is null";
+    private ExifData mData = new ExifData(DEFAULT_BYTE_ORDER);
+    public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
+
+    public ExifInterface() {
+        mGPSDateStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+    }
+
+    /**
+     * Reads the exif tags from a byte array, clearing this ExifInterface
+     * object's existing exif tags.
+     *
+     * @param jpeg a byte array containing a jpeg compressed image.
+     * @throws IOException
+     */
+    public void readExif(byte[] jpeg) throws IOException {
+        readExif(new ByteArrayInputStream(jpeg));
+    }
+
+    /**
+     * Reads the exif tags from an InputStream, clearing this ExifInterface
+     * object's existing exif tags.
+     *
+     * @param inStream an InputStream containing a jpeg compressed image.
+     * @throws IOException
+     */
+    public void readExif(InputStream inStream) throws IOException {
+        if (inStream == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        ExifData d = null;
+        try {
+            d = new ExifReader(this).read(inStream);
+        } catch (ExifInvalidFormatException e) {
+            throw new IOException("Invalid exif format : " + e);
+        }
+        mData = d;
+    }
+
+    /**
+     * Reads the exif tags from a file, clearing this ExifInterface object's
+     * existing exif tags.
+     *
+     * @param inFileName a string representing the filepath to jpeg file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public void readExif(String inFileName) throws FileNotFoundException, IOException {
+        if (inFileName == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        InputStream is = null;
+        try {
+            is = (InputStream) new BufferedInputStream(new FileInputStream(inFileName));
+            readExif(is);
+        } catch (IOException e) {
+            closeSilently(is);
+            throw e;
+        }
+        is.close();
+    }
+
+    /**
+     * Sets the exif tags, clearing this ExifInterface object's existing exif
+     * tags.
+     *
+     * @param tags a collection of exif tags to set.
+     */
+    public void setExif(Collection<ExifTag> tags) {
+        clearExif();
+        setTags(tags);
+    }
+
+    /**
+     * Clears this ExifInterface object's existing exif tags.
+     */
+    public void clearExif() {
+        mData = new ExifData(DEFAULT_BYTE_ORDER);
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg image,
+     * removing prior exif tags.
+     *
+     * @param jpeg a byte array containing a jpeg compressed image.
+     * @param exifOutStream an OutputStream to which the jpeg image with added
+     *            exif tags will be written.
+     * @throws IOException
+     */
+    public void writeExif(byte[] jpeg, OutputStream exifOutStream) throws IOException {
+        if (jpeg == null || exifOutStream == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream s = getExifWriterStream(exifOutStream);
+        s.write(jpeg, 0, jpeg.length);
+        s.flush();
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg compressed
+     * bitmap, removing prior exif tags.
+     *
+     * @param bmap a bitmap to compress and write exif into.
+     * @param exifOutStream the OutputStream to which the jpeg image with added
+     *            exif tags will be written.
+     * @throws IOException
+     */
+    public void writeExif(Bitmap bmap, OutputStream exifOutStream) throws IOException {
+        if (bmap == null || exifOutStream == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream s = getExifWriterStream(exifOutStream);
+        bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
+        s.flush();
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg stream,
+     * removing prior exif tags.
+     *
+     * @param jpegStream an InputStream containing a jpeg compressed image.
+     * @param exifOutStream an OutputStream to which the jpeg image with added
+     *            exif tags will be written.
+     * @throws IOException
+     */
+    public void writeExif(InputStream jpegStream, OutputStream exifOutStream) throws IOException {
+        if (jpegStream == null || exifOutStream == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream s = getExifWriterStream(exifOutStream);
+        doExifStreamIO(jpegStream, s);
+        s.flush();
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg image,
+     * removing prior exif tags.
+     *
+     * @param jpeg a byte array containing a jpeg compressed image.
+     * @param exifOutFileName a String containing the filepath to which the jpeg
+     *            image with added exif tags will be written.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public void writeExif(byte[] jpeg, String exifOutFileName) throws FileNotFoundException,
+            IOException {
+        if (jpeg == null || exifOutFileName == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream s = null;
+        try {
+            s = getExifWriterStream(exifOutFileName);
+            s.write(jpeg, 0, jpeg.length);
+            s.flush();
+        } catch (IOException e) {
+            closeSilently(s);
+            throw e;
+        }
+        s.close();
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg compressed
+     * bitmap, removing prior exif tags.
+     *
+     * @param bmap a bitmap to compress and write exif into.
+     * @param exifOutFileName a String containing the filepath to which the jpeg
+     *            image with added exif tags will be written.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public void writeExif(Bitmap bmap, String exifOutFileName) throws FileNotFoundException,
+            IOException {
+        if (bmap == null || exifOutFileName == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream s = null;
+        try {
+            s = getExifWriterStream(exifOutFileName);
+            bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
+            s.flush();
+        } catch (IOException e) {
+            closeSilently(s);
+            throw e;
+        }
+        s.close();
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg stream,
+     * removing prior exif tags.
+     *
+     * @param jpegStream an InputStream containing a jpeg compressed image.
+     * @param exifOutFileName a String containing the filepath to which the jpeg
+     *            image with added exif tags will be written.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public void writeExif(InputStream jpegStream, String exifOutFileName)
+            throws FileNotFoundException, IOException {
+        if (jpegStream == null || exifOutFileName == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream s = null;
+        try {
+            s = getExifWriterStream(exifOutFileName);
+            doExifStreamIO(jpegStream, s);
+            s.flush();
+        } catch (IOException e) {
+            closeSilently(s);
+            throw e;
+        }
+        s.close();
+    }
+
+    /**
+     * Writes the tags from this ExifInterface object into a jpeg file, removing
+     * prior exif tags.
+     *
+     * @param jpegFileName a String containing the filepath for a jpeg file.
+     * @param exifOutFileName a String containing the filepath to which the jpeg
+     *            image with added exif tags will be written.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public void writeExif(String jpegFileName, String exifOutFileName)
+            throws FileNotFoundException, IOException {
+        if (jpegFileName == null || exifOutFileName == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        InputStream is = null;
+        try {
+            is = new FileInputStream(jpegFileName);
+            writeExif(is, exifOutFileName);
+        } catch (IOException e) {
+            closeSilently(is);
+            throw e;
+        }
+        is.close();
+    }
+
+    /**
+     * Wraps an OutputStream object with an ExifOutputStream. Exif tags in this
+     * ExifInterface object will be added to a jpeg image written to this
+     * stream, removing prior exif tags. Other methods of this ExifInterface
+     * object should not be called until the returned OutputStream has been
+     * closed.
+     *
+     * @param outStream an OutputStream to wrap.
+     * @return an OutputStream that wraps the outStream parameter, and adds exif
+     *         metadata. A jpeg image should be written to this stream.
+     */
+    public OutputStream getExifWriterStream(OutputStream outStream) {
+        if (outStream == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        ExifOutputStream eos = new ExifOutputStream(outStream, this);
+        eos.setExifData(mData);
+        return eos;
+    }
+
+    /**
+     * Returns an OutputStream object that writes to a file. Exif tags in this
+     * ExifInterface object will be added to a jpeg image written to this
+     * stream, removing prior exif tags. Other methods of this ExifInterface
+     * object should not be called until the returned OutputStream has been
+     * closed.
+     *
+     * @param exifOutFileName an String containing a filepath for a jpeg file.
+     * @return an OutputStream that writes to the exifOutFileName file, and adds
+     *         exif metadata. A jpeg image should be written to this stream.
+     * @throws FileNotFoundException
+     */
+    public OutputStream getExifWriterStream(String exifOutFileName) throws FileNotFoundException {
+        if (exifOutFileName == null) {
+            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+        }
+        OutputStream out = null;
+        try {
+            out = (OutputStream) new FileOutputStream(exifOutFileName);
+        } catch (FileNotFoundException e) {
+            closeSilently(out);
+            throw e;
+        }
+        return getExifWriterStream(out);
+    }
+
+    /**
+     * Attempts to do an in-place rewrite the exif metadata in a file for the
+     * given tags. If tags do not exist or do not have the same size as the
+     * existing exif tags, this method will fail.
+     *
+     * @param filename a String containing a filepath for a jpeg file with exif
+     *            tags to rewrite.
+     * @param tags tags that will be written into the jpeg file over existing
+     *            tags if possible.
+     * @return true if success, false if could not overwrite. If false, no
+     *         changes are made to the file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public boolean rewriteExif(String filename, Collection<ExifTag> tags)
+            throws FileNotFoundException, IOException {
+        RandomAccessFile file = null;
+        InputStream is = null;
+        boolean ret;
+        try {
+            File temp = new File(filename);
+            is = new BufferedInputStream(new FileInputStream(temp));
+
+            // Parse beginning of APP1 in exif to find size of exif header.
+            ExifParser parser = null;
+            try {
+                parser = ExifParser.parse(is, this);
+            } catch (ExifInvalidFormatException e) {
+                throw new IOException("Invalid exif format : ", e);
+            }
+            long exifSize = parser.getOffsetToExifEndFromSOF();
+
+            // Free up resources
+            is.close();
+            is = null;
+
+            // Open file for memory mapping.
+            file = new RandomAccessFile(temp, "rw");
+            long fileLength = file.length();
+            if (fileLength < exifSize) {
+                throw new IOException("Filesize changed during operation");
+            }
+
+            // Map only exif header into memory.
+            ByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, exifSize);
+
+            // Attempt to overwrite tag values without changing lengths (avoids
+            // file copy).
+            ret = rewriteExif(buf, tags);
+        } catch (IOException e) {
+            closeSilently(file);
+            throw e;
+        } finally {
+            closeSilently(is);
+        }
+        file.close();
+        return ret;
+    }
+
+    /**
+     * Attempts to do an in-place rewrite the exif metadata in a ByteBuffer for
+     * the given tags. If tags do not exist or do not have the same size as the
+     * existing exif tags, this method will fail.
+     *
+     * @param buf a ByteBuffer containing a jpeg file with existing exif tags to
+     *            rewrite.
+     * @param tags tags that will be written into the jpeg ByteBuffer over
+     *            existing tags if possible.
+     * @return true if success, false if could not overwrite. If false, no
+     *         changes are made to the ByteBuffer.
+     * @throws IOException
+     */
+    public boolean rewriteExif(ByteBuffer buf, Collection<ExifTag> tags) throws IOException {
+        ExifModifier mod = null;
+        try {
+            mod = new ExifModifier(buf, this);
+            for (ExifTag t : tags) {
+                mod.modifyTag(t);
+            }
+            return mod.commit();
+        } catch (ExifInvalidFormatException e) {
+            throw new IOException("Invalid exif format : " + e);
+        }
+    }
+
+    /**
+     * Attempts to do an in-place rewrite of the exif metadata. If this fails,
+     * fall back to overwriting file. This preserves tags that are not being
+     * rewritten.
+     *
+     * @param filename a String containing a filepath for a jpeg file.
+     * @param tags tags that will be written into the jpeg file over existing
+     *            tags if possible.
+     * @throws FileNotFoundException
+     * @throws IOException
+     * @see #rewriteExif
+     */
+    public void forceRewriteExif(String filename, Collection<ExifTag> tags)
+            throws FileNotFoundException,
+            IOException {
+        // Attempt in-place write
+        if (!rewriteExif(filename, tags)) {
+            // Fall back to doing a copy
+            ExifData tempData = mData;
+            mData = new ExifData(DEFAULT_BYTE_ORDER);
+            FileInputStream is = null;
+            ByteArrayOutputStream bytes = null;
+            try {
+                is = new FileInputStream(filename);
+                bytes = new ByteArrayOutputStream();
+                doExifStreamIO(is, bytes);
+                byte[] imageBytes = bytes.toByteArray();
+                readExif(imageBytes);
+                setTags(tags);
+                writeExif(imageBytes, filename);
+            } catch (IOException e) {
+                closeSilently(is);
+                throw e;
+            } finally {
+                is.close();
+                // Prevent clobbering of mData
+                mData = tempData;
+            }
+        }
+    }
+
+    /**
+     * Attempts to do an in-place rewrite of the exif metadata using the tags in
+     * this ExifInterface object. If this fails, fall back to overwriting file.
+     * This preserves tags that are not being rewritten.
+     *
+     * @param filename a String containing a filepath for a jpeg file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     * @see #rewriteExif
+     */
+    public void forceRewriteExif(String filename) throws FileNotFoundException, IOException {
+        forceRewriteExif(filename, getAllTags());
+    }
+
+    /**
+     * Get the exif tags in this ExifInterface object or null if none exist.
+     *
+     * @return a List of {@link ExifTag}s.
+     */
+    public List<ExifTag> getAllTags() {
+        return mData.getAllTags();
+    }
+
+    /**
+     * Returns a list of ExifTags that share a TID (which can be obtained by
+     * calling {@link #getTrueTagKey} on a defined tag constant) or null if none
+     * exist.
+     *
+     * @param tagId a TID as defined in the exif standard (or with
+     *            {@link #defineTag}).
+     * @return a List of {@link ExifTag}s.
+     */
+    public List<ExifTag> getTagsForTagId(short tagId) {
+        return mData.getAllTagsForTagId(tagId);
+    }
+
+    /**
+     * Returns a list of ExifTags that share an IFD (which can be obtained by
+     * calling {@link #getTrueIFD} on a defined tag constant) or null if none
+     * exist.
+     *
+     * @param ifdId an IFD as defined in the exif standard (or with
+     *            {@link #defineTag}).
+     * @return a List of {@link ExifTag}s.
+     */
+    public List<ExifTag> getTagsForIfdId(int ifdId) {
+        return mData.getAllTagsForIfd(ifdId);
+    }
+
+    /**
+     * Gets an ExifTag for an IFD other than the tag's default.
+     *
+     * @see #getTag
+     */
+    public ExifTag getTag(int tagId, int ifdId) {
+        if (!ExifTag.isValidIfd(ifdId)) {
+            return null;
+        }
+        return mData.getTag(getTrueTagKey(tagId), ifdId);
+    }
+
+    /**
+     * Returns the ExifTag in that tag's default IFD for a defined tag constant
+     * or null if none exists.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @return an {@link ExifTag} or null if none exists.
+     */
+    public ExifTag getTag(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTag(tagId, ifdId);
+    }
+
+    /**
+     * Gets a tag value for an IFD other than the tag's default.
+     *
+     * @see #getTagValue
+     */
+    public Object getTagValue(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        return (t == null) ? null : t.getValue();
+    }
+
+    /**
+     * Returns the value of the ExifTag in that tag's default IFD for a defined
+     * tag constant or null if none exists or the value could not be cast into
+     * the return type.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @return the value of the ExifTag or null if none exists.
+     */
+    public Object getTagValue(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagValue(tagId, ifdId);
+    }
+
+    /*
+     * Getter methods that are similar to getTagValue. Null is returned if the
+     * tag value cannot be cast into the return type.
+     */
+
+    /**
+     * @see #getTagValue
+     */
+    public String getTagStringValue(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return null;
+        }
+        return t.getValueAsString();
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public String getTagStringValue(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagStringValue(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Long getTagLongValue(int tagId, int ifdId) {
+        long[] l = getTagLongValues(tagId, ifdId);
+        if (l == null || l.length <= 0) {
+            return null;
+        }
+        return new Long(l[0]);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Long getTagLongValue(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagLongValue(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Integer getTagIntValue(int tagId, int ifdId) {
+        int[] l = getTagIntValues(tagId, ifdId);
+        if (l == null || l.length <= 0) {
+            return null;
+        }
+        return new Integer(l[0]);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Integer getTagIntValue(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagIntValue(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Byte getTagByteValue(int tagId, int ifdId) {
+        byte[] l = getTagByteValues(tagId, ifdId);
+        if (l == null || l.length <= 0) {
+            return null;
+        }
+        return new Byte(l[0]);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Byte getTagByteValue(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagByteValue(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Rational getTagRationalValue(int tagId, int ifdId) {
+        Rational[] l = getTagRationalValues(tagId, ifdId);
+        if (l == null || l.length == 0) {
+            return null;
+        }
+        return new Rational(l[0]);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Rational getTagRationalValue(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagRationalValue(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public long[] getTagLongValues(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return null;
+        }
+        return t.getValueAsLongs();
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public long[] getTagLongValues(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagLongValues(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public int[] getTagIntValues(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return null;
+        }
+        return t.getValueAsInts();
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public int[] getTagIntValues(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagIntValues(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public byte[] getTagByteValues(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return null;
+        }
+        return t.getValueAsBytes();
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public byte[] getTagByteValues(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagByteValues(tagId, ifdId);
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Rational[] getTagRationalValues(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return null;
+        }
+        return t.getValueAsRationals();
+    }
+
+    /**
+     * @see #getTagValue
+     */
+    public Rational[] getTagRationalValues(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return getTagRationalValues(tagId, ifdId);
+    }
+
+    /**
+     * Checks whether a tag has a defined number of elements.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @return true if the tag has a defined number of elements.
+     */
+    public boolean isTagCountDefined(int tagId) {
+        int info = getTagInfo().get(tagId);
+        // No value in info can be zero, as all tags have a non-zero type
+        if (info == 0) {
+            return false;
+        }
+        return getComponentCountFromInfo(info) != ExifTag.SIZE_UNDEFINED;
+    }
+
+    /**
+     * Gets the defined number of elements for a tag.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @return the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the
+     *         tag or the number of elements is not defined.
+     */
+    public int getDefinedTagCount(int tagId) {
+        int info = getTagInfo().get(tagId);
+        if (info == 0) {
+            return ExifTag.SIZE_UNDEFINED;
+        }
+        return getComponentCountFromInfo(info);
+    }
+
+    /**
+     * Gets the number of elements for an ExifTag in a given IFD.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @param ifdId the IFD containing the ExifTag to check.
+     * @return the number of elements in the ExifTag, if the tag's size is
+     *         undefined this will return the actual number of elements that is
+     *         in the ExifTag's value.
+     */
+    public int getActualTagCount(int tagId, int ifdId) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return 0;
+        }
+        return t.getComponentCount();
+    }
+
+    /**
+     * Gets the default IFD for a tag.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @return the default IFD for a tag definition or {@link #IFD_NULL} if no
+     *         definition exists.
+     */
+    public int getDefinedTagDefaultIfd(int tagId) {
+        int info = getTagInfo().get(tagId);
+        if (info == DEFINITION_NULL) {
+            return IFD_NULL;
+        }
+        return getTrueIfd(tagId);
+    }
+
+    /**
+     * Gets the defined type for a tag.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @return the type.
+     * @see ExifTag#getDataType()
+     */
+    public short getDefinedTagType(int tagId) {
+        int info = getTagInfo().get(tagId);
+        if (info == 0) {
+            return -1;
+        }
+        return getTypeFromInfo(info);
+    }
+
+    /**
+     * Returns true if tag TID is one of the following: {@link TAG_EXIF_IFD},
+     * {@link TAG_GPS_IFD}, {@link TAG_JPEG_INTERCHANGE_FORMAT},
+     * {@link TAG_STRIP_OFFSETS}, {@link TAG_INTEROPERABILITY_IFD}
+     * <p>
+     * Note: defining tags with these TID's is disallowed.
+     *
+     * @param tag a tag's TID (can be obtained from a defined tag constant with
+     *            {@link #getTrueTagKey}).
+     * @return true if the TID is that of an offset tag.
+     */
+    protected static boolean isOffsetTag(short tag) {
+        return sOffsetTags.contains(tag);
+    }
+
+    /**
+     * Creates a tag for a defined tag constant in a given IFD if that IFD is
+     * allowed for the tag.  This method will fail anytime the appropriate
+     * {@link ExifTag#setValue} for this tag's datatype would fail.
+     *
+     * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @param ifdId the IFD that the tag should be in.
+     * @param val the value of the tag to set.
+     * @return an ExifTag object or null if one could not be constructed.
+     * @see #buildTag
+     */
+    public ExifTag buildTag(int tagId, int ifdId, Object val) {
+        int info = getTagInfo().get(tagId);
+        if (info == 0 || val == null) {
+            return null;
+        }
+        short type = getTypeFromInfo(info);
+        int definedCount = getComponentCountFromInfo(info);
+        boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
+        if (!ExifInterface.isIfdAllowed(info, ifdId)) {
+            return null;
+        }
+        ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
+        if (!t.setValue(val)) {
+            return null;
+        }
+        return t;
+    }
+
+    /**
+     * Creates a tag for a defined tag constant in the tag's default IFD.
+     *
+     * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @param val the tag's value.
+     * @return an ExifTag object.
+     */
+    public ExifTag buildTag(int tagId, Object val) {
+        int ifdId = getTrueIfd(tagId);
+        return buildTag(tagId, ifdId, val);
+    }
+
+    protected ExifTag buildUninitializedTag(int tagId) {
+        int info = getTagInfo().get(tagId);
+        if (info == 0) {
+            return null;
+        }
+        short type = getTypeFromInfo(info);
+        int definedCount = getComponentCountFromInfo(info);
+        boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
+        int ifdId = getTrueIfd(tagId);
+        ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
+        return t;
+    }
+
+    /**
+     * Sets the value of an ExifTag if it exists in the given IFD. The value
+     * must be the correct type and length for that ExifTag.
+     *
+     * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @param ifdId the IFD that the ExifTag is in.
+     * @param val the value to set.
+     * @return true if success, false if the ExifTag doesn't exist or the value
+     *         is the wrong type/length.
+     * @see #setTagValue
+     */
+    public boolean setTagValue(int tagId, int ifdId, Object val) {
+        ExifTag t = getTag(tagId, ifdId);
+        if (t == null) {
+            return false;
+        }
+        return t.setValue(val);
+    }
+
+    /**
+     * Sets the value of an ExifTag if it exists it's default IFD. The value
+     * must be the correct type and length for that ExifTag.
+     *
+     * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @param val the value to set.
+     * @return true if success, false if the ExifTag doesn't exist or the value
+     *         is the wrong type/length.
+     */
+    public boolean setTagValue(int tagId, Object val) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        return setTagValue(tagId, ifdId, val);
+    }
+
+    /**
+     * Puts an ExifTag into this ExifInterface object's tags, removing a
+     * previous ExifTag with the same TID and IFD. The IFD it is put into will
+     * be the one the tag was created with in {@link #buildTag}.
+     *
+     * @param tag an ExifTag to put into this ExifInterface's tags.
+     * @return the previous ExifTag with the same TID and IFD or null if none
+     *         exists.
+     */
+    public ExifTag setTag(ExifTag tag) {
+        return mData.addTag(tag);
+    }
+
+    /**
+     * Puts a collection of ExifTags into this ExifInterface objects's tags. Any
+     * previous ExifTags with the same TID and IFDs will be removed.
+     *
+     * @param tags a Collection of ExifTags.
+     * @see #setTag
+     */
+    public void setTags(Collection<ExifTag> tags) {
+        for (ExifTag t : tags) {
+            setTag(t);
+        }
+    }
+
+    /**
+     * Removes the ExifTag for a tag constant from the given IFD.
+     *
+     * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     * @param ifdId the IFD of the ExifTag to remove.
+     */
+    public void deleteTag(int tagId, int ifdId) {
+        mData.removeTag(getTrueTagKey(tagId), ifdId);
+    }
+
+    /**
+     * Removes the ExifTag for a tag constant from that tag's default IFD.
+     *
+     * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     */
+    public void deleteTag(int tagId) {
+        int ifdId = getDefinedTagDefaultIfd(tagId);
+        deleteTag(tagId, ifdId);
+    }
+
+    /**
+     * Creates a new tag definition in this ExifInterface object for a given TID
+     * and default IFD. Creating a definition with the same TID and default IFD
+     * as a previous definition will override it.
+     *
+     * @param tagId the TID for the tag.
+     * @param defaultIfd the default IFD for the tag.
+     * @param tagType the type of the tag (see {@link ExifTag#getDataType()}).
+     * @param defaultComponentCount the number of elements of this tag's type in
+     *            the tags value.
+     * @param allowedIfds the IFD's this tag is allowed to be put in.
+     * @return the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or
+     *         {@link #TAG_NULL} if the definition could not be made.
+     */
+    public int setTagDefinition(short tagId, int defaultIfd, short tagType,
+            short defaultComponentCount, int[] allowedIfds) {
+        if (sBannedDefines.contains(tagId)) {
+            return TAG_NULL;
+        }
+        if (ExifTag.isValidType(tagType) && ExifTag.isValidIfd(defaultIfd)) {
+            int tagDef = defineTag(defaultIfd, tagId);
+            if (tagDef == TAG_NULL) {
+                return TAG_NULL;
+            }
+            int[] otherDefs = getTagDefinitionsForTagId(tagId);
+            SparseIntArray infos = getTagInfo();
+            // Make sure defaultIfd is in allowedIfds
+            boolean defaultCheck = false;
+            for (int i : allowedIfds) {
+                if (defaultIfd == i) {
+                    defaultCheck = true;
+                }
+                if (!ExifTag.isValidIfd(i)) {
+                    return TAG_NULL;
+                }
+            }
+            if (!defaultCheck) {
+                return TAG_NULL;
+            }
+
+            int ifdFlags = getFlagsFromAllowedIfds(allowedIfds);
+            // Make sure no identical tags can exist in allowedIfds
+            if (otherDefs != null) {
+                for (int def : otherDefs) {
+                    int tagInfo = infos.get(def);
+                    int allowedFlags = getAllowedIfdFlagsFromInfo(tagInfo);
+                    if ((ifdFlags & allowedFlags) != 0) {
+                        return TAG_NULL;
+                    }
+                }
+            }
+            getTagInfo().put(tagDef, ifdFlags << 24 | (tagType << 16) | defaultComponentCount);
+            return tagDef;
+        }
+        return TAG_NULL;
+    }
+
+    protected int getTagDefinition(short tagId, int defaultIfd) {
+        return getTagInfo().get(defineTag(defaultIfd, tagId));
+    }
+
+    protected int[] getTagDefinitionsForTagId(short tagId) {
+        int[] ifds = IfdData.getIfds();
+        int[] defs = new int[ifds.length];
+        int counter = 0;
+        SparseIntArray infos = getTagInfo();
+        for (int i : ifds) {
+            int def = defineTag(i, tagId);
+            if (infos.get(def) != DEFINITION_NULL) {
+                defs[counter++] = def;
+            }
+        }
+        if (counter == 0) {
+            return null;
+        }
+
+        return Arrays.copyOfRange(defs, 0, counter);
+    }
+
+    protected int getTagDefinitionForTag(ExifTag tag) {
+        short type = tag.getDataType();
+        int count = tag.getComponentCount();
+        int ifd = tag.getIfd();
+        return getTagDefinitionForTag(tag.getTagId(), type, count, ifd);
+    }
+
+    protected int getTagDefinitionForTag(short tagId, short type, int count, int ifd) {
+        int[] defs = getTagDefinitionsForTagId(tagId);
+        if (defs == null) {
+            return TAG_NULL;
+        }
+        SparseIntArray infos = getTagInfo();
+        int ret = TAG_NULL;
+        for (int i : defs) {
+            int info = infos.get(i);
+            short def_type = getTypeFromInfo(info);
+            int def_count = getComponentCountFromInfo(info);
+            int[] def_ifds = getAllowedIfdsFromInfo(info);
+            boolean valid_ifd = false;
+            for (int j : def_ifds) {
+                if (j == ifd) {
+                    valid_ifd = true;
+                    break;
+                }
+            }
+            if (valid_ifd && type == def_type
+                    && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) {
+                ret = i;
+                break;
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Removes a tag definition for given defined tag constant.
+     *
+     * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+     */
+    public void removeTagDefinition(int tagId) {
+        getTagInfo().delete(tagId);
+    }
+
+    /**
+     * Resets tag definitions to the default ones.
+     */
+    public void resetTagDefinitions() {
+        mTagInfo = null;
+    }
+
+    /**
+     * Returns the thumbnail from IFD1 as a bitmap, or null if none exists.
+     *
+     * @return the thumbnail as a bitmap.
+     */
+    public Bitmap getThumbnailBitmap() {
+        if (mData.hasCompressedThumbnail()) {
+            byte[] thumb = mData.getCompressedThumbnail();
+            return BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
+        } else if (mData.hasUncompressedStrip()) {
+            // TODO: implement uncompressed
+        }
+        return null;
+    }
+
+    /**
+     * Returns the thumbnail from IFD1 as a byte array, or null if none exists.
+     * The bytes may either be an uncompressed strip as specified in the exif
+     * standard or a jpeg compressed image.
+     *
+     * @return the thumbnail as a byte array.
+     */
+    public byte[] getThumbnailBytes() {
+        if (mData.hasCompressedThumbnail()) {
+            return mData.getCompressedThumbnail();
+        } else if (mData.hasUncompressedStrip()) {
+            // TODO: implement this
+        }
+        return null;
+    }
+
+    /**
+     * Returns the thumbnail if it is jpeg compressed, or null if none exists.
+     *
+     * @return the thumbnail as a byte array.
+     */
+    public byte[] getThumbnail() {
+        return mData.getCompressedThumbnail();
+    }
+
+    /**
+     * Check if thumbnail is compressed.
+     *
+     * @return true if the thumbnail is compressed.
+     */
+    public boolean isThumbnailCompressed() {
+        return mData.hasCompressedThumbnail();
+    }
+
+    /**
+     * Check if thumbnail exists.
+     *
+     * @return true if a compressed thumbnail exists.
+     */
+    public boolean hasThumbnail() {
+        // TODO: add back in uncompressed strip
+        return mData.hasCompressedThumbnail();
+    }
+
+    // TODO: uncompressed thumbnail setters
+
+    /**
+     * Sets the thumbnail to be a jpeg compressed image. Clears any prior
+     * thumbnail.
+     *
+     * @param thumb a byte array containing a jpeg compressed image.
+     * @return true if the thumbnail was set.
+     */
+    public boolean setCompressedThumbnail(byte[] thumb) {
+        mData.clearThumbnailAndStrips();
+        mData.setCompressedThumbnail(thumb);
+        return true;
+    }
+
+    /**
+     * Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior
+     * thumbnail.
+     *
+     * @param thumb a bitmap to compress to a jpeg thumbnail.
+     * @return true if the thumbnail was set.
+     */
+    public boolean setCompressedThumbnail(Bitmap thumb) {
+        ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
+        if (!thumb.compress(Bitmap.CompressFormat.JPEG, 90, thumbnail)) {
+            return false;
+        }
+        return setCompressedThumbnail(thumbnail.toByteArray());
+    }
+
+    /**
+     * Clears the compressed thumbnail if it exists.
+     */
+    public void removeCompressedThumbnail() {
+        mData.setCompressedThumbnail(null);
+    }
+
+    // Convenience methods:
+
+    /**
+     * Decodes the user comment tag into string as specified in the EXIF
+     * standard. Returns null if decoding failed.
+     */
+    public String getUserComment() {
+        return mData.getUserComment();
+    }
+
+    /**
+     * Returns the Orientation ExifTag value for a given number of degrees.
+     *
+     * @param degrees the amount an image is rotated in degrees.
+     */
+    public static short getOrientationValueForRotation(int degrees) {
+        degrees %= 360;
+        if (degrees < 0) {
+            degrees += 360;
+        }
+        if (degrees < 90) {
+            return Orientation.TOP_LEFT; // 0 degrees
+        } else if (degrees < 180) {
+            return Orientation.RIGHT_TOP; // 90 degrees cw
+        } else if (degrees < 270) {
+            return Orientation.BOTTOM_LEFT; // 180 degrees
+        } else {
+            return Orientation.RIGHT_BOTTOM; // 270 degrees cw
+        }
+    }
+
+    /**
+     * Returns the rotation degrees corresponding to an ExifTag Orientation
+     * value.
+     *
+     * @param orientation the ExifTag Orientation value.
+     */
+    public static int getRotationForOrientationValue(short orientation) {
+        switch (orientation) {
+            case Orientation.TOP_LEFT:
+                return 0;
+            case Orientation.RIGHT_TOP:
+                return 90;
+            case Orientation.BOTTOM_LEFT:
+                return 180;
+            case Orientation.RIGHT_BOTTOM:
+                return 270;
+            default:
+                return 0;
+        }
+    }
+
+    /**
+     * Gets the double representation of the GPS latitude or longitude
+     * coordinate.
+     *
+     * @param coordinate an array of 3 Rationals representing the degrees,
+     *            minutes, and seconds of the GPS location as defined in the
+     *            exif specification.
+     * @param reference a GPS reference reperesented by a String containing "N",
+     *            "S", "E", or "W".
+     * @return the GPS coordinate represented as degrees + minutes/60 +
+     *         seconds/3600
+     */
+    public static double convertLatOrLongToDouble(Rational[] coordinate, String reference) {
+        try {
+            double degrees = coordinate[0].toDouble();
+            double minutes = coordinate[1].toDouble();
+            double seconds = coordinate[2].toDouble();
+            double result = degrees + minutes / 60.0 + seconds / 3600.0;
+            if ((reference.equals("S") || reference.equals("W"))) {
+                return -result;
+            }
+            return result;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Gets the GPS latitude and longitude as a pair of doubles from this
+     * ExifInterface object's tags, or null if the necessary tags do not exist.
+     *
+     * @return an array of 2 doubles containing the latitude, and longitude
+     *         respectively.
+     * @see #convertLatOrLongToDouble
+     */
+    public double[] getLatLongAsDoubles() {
+        Rational[] latitude = getTagRationalValues(TAG_GPS_LATITUDE);
+        String latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF);
+        Rational[] longitude = getTagRationalValues(TAG_GPS_LONGITUDE);
+        String longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF);
+        if (latitude == null || longitude == null || latitudeRef == null || longitudeRef == null
+                || latitude.length < 3 || longitude.length < 3) {
+            return null;
+        }
+        double[] latLon = new double[2];
+        latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef);
+        latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef);
+        return latLon;
+    }
+
+    private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
+    private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss";
+    private final DateFormat mDateTimeStampFormat = new SimpleDateFormat(DATETIME_FORMAT_STR);
+    private final DateFormat mGPSDateStampFormat = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
+    private final Calendar mGPSTimeStampCalendar = Calendar
+            .getInstance(TimeZone.getTimeZone("UTC"));
+
+    /**
+     * Creates, formats, and sets the DateTimeStamp tag for one of:
+     * {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED},
+     * {@link #TAG_DATE_TIME_ORIGINAL}.
+     *
+     * @param tagId one of the DateTimeStamp tags.
+     * @param timestamp a timestamp to format.
+     * @param timezone a TimeZone object.
+     * @return true if success, false if the tag could not be set.
+     */
+    public boolean addDateTimeStampTag(int tagId, long timestamp, TimeZone timezone) {
+        if (tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED
+                || tagId == TAG_DATE_TIME_ORIGINAL) {
+            mDateTimeStampFormat.setTimeZone(timezone);
+            ExifTag t = buildTag(tagId, mDateTimeStampFormat.format(timestamp));
+            if (t == null) {
+                return false;
+            }
+            setTag(t);
+        } else {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Creates and sets all to the GPS tags for a give latitude and longitude.
+     *
+     * @param latitude a GPS latitude coordinate.
+     * @param longitude a GPS longitude coordinate.
+     * @return true if success, false if they could not be created or set.
+     */
+    public boolean addGpsTags(double latitude, double longitude) {
+        ExifTag latTag = buildTag(TAG_GPS_LATITUDE, toExifLatLong(latitude));
+        ExifTag longTag = buildTag(TAG_GPS_LONGITUDE, toExifLatLong(longitude));
+        ExifTag latRefTag = buildTag(TAG_GPS_LATITUDE_REF,
+                latitude >= 0 ? ExifInterface.GpsLatitudeRef.NORTH
+                        : ExifInterface.GpsLatitudeRef.SOUTH);
+        ExifTag longRefTag = buildTag(TAG_GPS_LONGITUDE_REF,
+                longitude >= 0 ? ExifInterface.GpsLongitudeRef.EAST
+                        : ExifInterface.GpsLongitudeRef.WEST);
+        if (latTag == null || longTag == null || latRefTag == null || longRefTag == null) {
+            return false;
+        }
+        setTag(latTag);
+        setTag(longTag);
+        setTag(latRefTag);
+        setTag(longRefTag);
+        return true;
+    }
+
+    /**
+     * Creates and sets the GPS timestamp tag.
+     *
+     * @param timestamp a GPS timestamp.
+     * @return true if success, false if could not be created or set.
+     */
+    public boolean addGpsDateTimeStampTag(long timestamp) {
+        ExifTag t = buildTag(TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format(timestamp));
+        if (t == null) {
+            return false;
+        }
+        setTag(t);
+        mGPSTimeStampCalendar.setTimeInMillis(timestamp);
+        t = buildTag(TAG_GPS_TIME_STAMP, new Rational[] {
+                new Rational(mGPSTimeStampCalendar.get(Calendar.HOUR_OF_DAY), 1),
+                new Rational(mGPSTimeStampCalendar.get(Calendar.MINUTE), 1),
+                new Rational(mGPSTimeStampCalendar.get(Calendar.SECOND), 1)
+        });
+        if (t == null) {
+            return false;
+        }
+        setTag(t);
+        return true;
+    }
+
+    private static Rational[] toExifLatLong(double value) {
+        // convert to the format dd/1 mm/1 ssss/100
+        value = Math.abs(value);
+        int degrees = (int) value;
+        value = (value - degrees) * 60;
+        int minutes = (int) value;
+        value = (value - minutes) * 6000;
+        int seconds = (int) value;
+        return new Rational[] {
+                new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)
+        };
+    }
+
+    private void doExifStreamIO(InputStream is, OutputStream os) throws IOException {
+        byte[] buf = new byte[1024];
+        int ret = is.read(buf, 0, 1024);
+        while (ret != -1) {
+            os.write(buf, 0, ret);
+            ret = is.read(buf, 0, 1024);
+        }
+    }
+
+    protected static void closeSilently(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            } catch (Throwable e) {
+                // ignored
+            }
+        }
+    }
+
+    private SparseIntArray mTagInfo = null;
+
+    protected SparseIntArray getTagInfo() {
+        if (mTagInfo == null) {
+            mTagInfo = new SparseIntArray();
+            initTagInfo();
+        }
+        return mTagInfo;
+    }
+
+    private void initTagInfo() {
+        /**
+         * We put tag information in a 4-bytes integer. The first byte a bitmask
+         * representing the allowed IFDs of the tag, the second byte is the data
+         * type, and the last two byte are a short value indicating the default
+         * component count of this tag.
+         */
+        // IFD0 tags
+        int[] ifdAllowedIfds = {
+                IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1
+        };
+        int ifdFlags = getFlagsFromAllowedIfds(ifdAllowedIfds) << 24;
+        mTagInfo.put(ExifInterface.TAG_MAKE,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_IMAGE_WIDTH,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_IMAGE_LENGTH,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_BITS_PER_SAMPLE,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3);
+        mTagInfo.put(ExifInterface.TAG_COMPRESSION,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_ORIENTATION, ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16
+                | 1);
+        mTagInfo.put(ExifInterface.TAG_SAMPLES_PER_PIXEL,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_PLANAR_CONFIGURATION,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_Y_CB_CR_POSITIONING,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_X_RESOLUTION,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_Y_RESOLUTION,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_RESOLUTION_UNIT,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_STRIP_OFFSETS,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_ROWS_PER_STRIP,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_STRIP_BYTE_COUNTS,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_TRANSFER_FUNCTION,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
+        mTagInfo.put(ExifInterface.TAG_WHITE_POINT,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
+        mTagInfo.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
+        mTagInfo.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
+        mTagInfo.put(ExifInterface.TAG_DATE_TIME,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | 20);
+        mTagInfo.put(ExifInterface.TAG_IMAGE_DESCRIPTION,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_MAKE,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_MODEL,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_SOFTWARE,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_ARTIST,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_COPYRIGHT,
+                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_EXIF_IFD,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_IFD,
+                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        // IFD1 tags
+        int[] ifd1AllowedIfds = {
+            IfdId.TYPE_IFD_1
+        };
+        int ifdFlags1 = getFlagsFromAllowedIfds(ifd1AllowedIfds) << 24;
+        mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT,
+                ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
+                ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        // Exif tags
+        int[] exifAllowedIfds = {
+            IfdId.TYPE_IFD_EXIF
+        };
+        int exifFlags = getFlagsFromAllowedIfds(exifAllowedIfds) << 24;
+        mTagInfo.put(ExifInterface.TAG_EXIF_VERSION,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+        mTagInfo.put(ExifInterface.TAG_FLASHPIX_VERSION,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+        mTagInfo.put(ExifInterface.TAG_COLOR_SPACE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+        mTagInfo.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_PIXEL_X_DIMENSION,
+                exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_PIXEL_Y_DIMENSION,
+                exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_MAKER_NOTE,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_USER_COMMENT,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_RELATED_SOUND_FILE,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | 13);
+        mTagInfo.put(ExifInterface.TAG_DATE_TIME_ORIGINAL,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
+        mTagInfo.put(ExifInterface.TAG_DATE_TIME_DIGITIZED,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
+        mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_IMAGE_UNIQUE_ID,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | 33);
+        mTagInfo.put(ExifInterface.TAG_EXPOSURE_TIME,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_F_NUMBER,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_EXPOSURE_PROGRAM,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY,
+                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_ISO_SPEED_RATINGS,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_OECF,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE,
+                exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_APERTURE_VALUE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_BRIGHTNESS_VALUE,
+                exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
+                exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_MAX_APERTURE_VALUE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_METERING_MODE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_LIGHT_SOURCE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_FLASH,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SUBJECT_AREA,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_FLASH_ENERGY,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SUBJECT_LOCATION,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_EXPOSURE_INDEX,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SENSING_METHOD,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_FILE_SOURCE,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SCENE_TYPE,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_CFA_PATTERN,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_CUSTOM_RENDERED,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_EXPOSURE_MODE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_WHITE_BALANCE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GAIN_CONTROL,
+                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_CONTRAST,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SATURATION,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_SHARPNESS,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
+                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
+                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_INTEROPERABILITY_IFD, exifFlags
+                | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+        // GPS tag
+        int[] gpsAllowedIfds = {
+            IfdId.TYPE_IFD_GPS
+        };
+        int gpsFlags = getFlagsFromAllowedIfds(gpsAllowedIfds) << 24;
+        mTagInfo.put(ExifInterface.TAG_GPS_VERSION_ID,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 4);
+        mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE,
+                gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
+        mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE,
+                gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
+        mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE_REF,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_TIME_STAMP,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
+        mTagInfo.put(ExifInterface.TAG_GPS_SATTELLITES,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_GPS_STATUS,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_MEASURE_MODE,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_DOP,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_SPEED_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_SPEED,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_TRACK_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_TRACK,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_MAP_DATUM,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+        mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+        mTagInfo.put(ExifInterface.TAG_GPS_PROCESSING_METHOD,
+                gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_GPS_AREA_INFORMATION,
+                gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+        mTagInfo.put(ExifInterface.TAG_GPS_DATE_STAMP,
+                gpsFlags | ExifTag.TYPE_ASCII << 16 | 11);
+        mTagInfo.put(ExifInterface.TAG_GPS_DIFFERENTIAL,
+                gpsFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 11);
+        // Interoperability tag
+        int[] interopAllowedIfds = {
+            IfdId.TYPE_IFD_INTEROPERABILITY
+        };
+        int interopFlags = getFlagsFromAllowedIfds(interopAllowedIfds) << 24;
+        mTagInfo.put(TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16
+                | ExifTag.SIZE_UNDEFINED);
+    }
+
+    protected static int getAllowedIfdFlagsFromInfo(int info) {
+        return info >>> 24;
+    }
+
+    protected static int[] getAllowedIfdsFromInfo(int info) {
+        int ifdFlags = getAllowedIfdFlagsFromInfo(info);
+        int[] ifds = IfdData.getIfds();
+        ArrayList<Integer> l = new ArrayList<Integer>();
+        for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+            int flag = (ifdFlags >> i) & 1;
+            if (flag == 1) {
+                l.add(ifds[i]);
+            }
+        }
+        if (l.size() <= 0) {
+            return null;
+        }
+        int[] ret = new int[l.size()];
+        int j = 0;
+        for (int i : l) {
+            ret[j++] = i;
+        }
+        return ret;
+    }
+
+    protected static boolean isIfdAllowed(int info, int ifd) {
+        int[] ifds = IfdData.getIfds();
+        int ifdFlags = getAllowedIfdFlagsFromInfo(info);
+        for (int i = 0; i < ifds.length; i++) {
+            if (ifd == ifds[i] && ((ifdFlags >> i) & 1) == 1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected static int getFlagsFromAllowedIfds(int[] allowedIfds) {
+        if (allowedIfds == null || allowedIfds.length == 0) {
+            return 0;
+        }
+        int flags = 0;
+        int[] ifds = IfdData.getIfds();
+        for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+            for (int j : allowedIfds) {
+                if (ifds[i] == j) {
+                    flags |= 1 << i;
+                    break;
+                }
+            }
+        }
+        return flags;
+    }
+
+    protected static short getTypeFromInfo(int info) {
+        return (short) ((info >> 16) & 0x0ff);
+    }
+
+    protected static int getComponentCountFromInfo(int info) {
+        return info & 0x0ffff;
+    }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
new file mode 100644
index 0000000..bf923ec
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+public class ExifInvalidFormatException extends Exception {
+    public ExifInvalidFormatException(String meg) {
+        super(meg);
+    }
+}
\ No newline at end of file
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java
new file mode 100644
index 0000000..f00362b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+class ExifModifier {
+    public static final String TAG = "ExifModifier";
+    public static final boolean DEBUG = false;
+    private final ByteBuffer mByteBuffer;
+    private final ExifData mTagToModified;
+    private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
+    private final ExifInterface mInterface;
+    private int mOffsetBase;
+
+    private static class TagOffset {
+        final int mOffset;
+        final ExifTag mTag;
+
+        TagOffset(ExifTag tag, int offset) {
+            mTag = tag;
+            mOffset = offset;
+        }
+    }
+
+    protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException,
+            ExifInvalidFormatException {
+        mByteBuffer = byteBuffer;
+        mOffsetBase = byteBuffer.position();
+        mInterface = iRef;
+        InputStream is = null;
+        try {
+            is = new ByteBufferInputStream(byteBuffer);
+            // Do not require any IFD;
+            ExifParser parser = ExifParser.parse(is, mInterface);
+            mTagToModified = new ExifData(parser.getByteOrder());
+            mOffsetBase += parser.getTiffStartPosition();
+            mByteBuffer.position(0);
+        } finally {
+            ExifInterface.closeSilently(is);
+        }
+    }
+
+    protected ByteOrder getByteOrder() {
+        return mTagToModified.getByteOrder();
+    }
+
+    protected boolean commit() throws IOException, ExifInvalidFormatException {
+        InputStream is = null;
+        try {
+            is = new ByteBufferInputStream(mByteBuffer);
+            int flag = 0;
+            IfdData[] ifdDatas = new IfdData[] {
+                    mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
+                    mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
+                    mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
+                    mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
+                    mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
+            };
+
+            if (ifdDatas[IfdId.TYPE_IFD_0] != null) {
+                flag |= ExifParser.OPTION_IFD_0;
+            }
+            if (ifdDatas[IfdId.TYPE_IFD_1] != null) {
+                flag |= ExifParser.OPTION_IFD_1;
+            }
+            if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) {
+                flag |= ExifParser.OPTION_IFD_EXIF;
+            }
+            if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) {
+                flag |= ExifParser.OPTION_IFD_GPS;
+            }
+            if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
+                flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
+            }
+
+            ExifParser parser = ExifParser.parse(is, flag, mInterface);
+            int event = parser.next();
+            IfdData currIfd = null;
+            while (event != ExifParser.EVENT_END) {
+                switch (event) {
+                    case ExifParser.EVENT_START_OF_IFD:
+                        currIfd = ifdDatas[parser.getCurrentIfd()];
+                        if (currIfd == null) {
+                            parser.skipRemainingTagsInCurrentIfd();
+                        }
+                        break;
+                    case ExifParser.EVENT_NEW_TAG:
+                        ExifTag oldTag = parser.getTag();
+                        ExifTag newTag = currIfd.getTag(oldTag.getTagId());
+                        if (newTag != null) {
+                            if (newTag.getComponentCount() != oldTag.getComponentCount()
+                                    || newTag.getDataType() != oldTag.getDataType()) {
+                                return false;
+                            } else {
+                                mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
+                                currIfd.removeTag(oldTag.getTagId());
+                                if (currIfd.getTagCount() == 0) {
+                                    parser.skipRemainingTagsInCurrentIfd();
+                                }
+                            }
+                        }
+                        break;
+                }
+                event = parser.next();
+            }
+            for (IfdData ifd : ifdDatas) {
+                if (ifd != null && ifd.getTagCount() > 0) {
+                    return false;
+                }
+            }
+            modify();
+        } finally {
+            ExifInterface.closeSilently(is);
+        }
+        return true;
+    }
+
+    private void modify() {
+        mByteBuffer.order(getByteOrder());
+        for (TagOffset tagOffset : mTagOffsets) {
+            writeTagValue(tagOffset.mTag, tagOffset.mOffset);
+        }
+    }
+
+    private void writeTagValue(ExifTag tag, int offset) {
+        if (DEBUG) {
+            Log.v(TAG, "modifying tag to: \n" + tag.toString());
+            Log.v(TAG, "at offset: " + offset);
+        }
+        mByteBuffer.position(offset + mOffsetBase);
+        switch (tag.getDataType()) {
+            case ExifTag.TYPE_ASCII:
+                byte buf[] = tag.getStringByte();
+                if (buf.length == tag.getComponentCount()) {
+                    buf[buf.length - 1] = 0;
+                    mByteBuffer.put(buf);
+                } else {
+                    mByteBuffer.put(buf);
+                    mByteBuffer.put((byte) 0);
+                }
+                break;
+            case ExifTag.TYPE_LONG:
+            case ExifTag.TYPE_UNSIGNED_LONG:
+                for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+                    mByteBuffer.putInt((int) tag.getValueAt(i));
+                }
+                break;
+            case ExifTag.TYPE_RATIONAL:
+            case ExifTag.TYPE_UNSIGNED_RATIONAL:
+                for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+                    Rational v = tag.getRational(i);
+                    mByteBuffer.putInt((int) v.getNumerator());
+                    mByteBuffer.putInt((int) v.getDenominator());
+                }
+                break;
+            case ExifTag.TYPE_UNDEFINED:
+            case ExifTag.TYPE_UNSIGNED_BYTE:
+                buf = new byte[tag.getComponentCount()];
+                tag.getBytes(buf);
+                mByteBuffer.put(buf);
+                break;
+            case ExifTag.TYPE_UNSIGNED_SHORT:
+                for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+                    mByteBuffer.putShort((short) tag.getValueAt(i));
+                }
+                break;
+        }
+    }
+
+    public void modifyTag(ExifTag tag) {
+        mTagToModified.addTag(tag);
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java
new file mode 100644
index 0000000..7ca05f2e
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+
+/**
+ * This class provides a way to replace the Exif header of a JPEG image.
+ * <p>
+ * Below is an example of writing EXIF data into a file
+ *
+ * <pre>
+ * public static void writeExif(byte[] jpeg, ExifData exif, String path) {
+ *     OutputStream os = null;
+ *     try {
+ *         os = new FileOutputStream(path);
+ *         ExifOutputStream eos = new ExifOutputStream(os);
+ *         // Set the exif header
+ *         eos.setExifData(exif);
+ *         // Write the original jpeg out, the header will be add into the file.
+ *         eos.write(jpeg);
+ *     } catch (FileNotFoundException e) {
+ *         e.printStackTrace();
+ *     } catch (IOException e) {
+ *         e.printStackTrace();
+ *     } finally {
+ *         if (os != null) {
+ *             try {
+ *                 os.close();
+ *             } catch (IOException e) {
+ *                 e.printStackTrace();
+ *             }
+ *         }
+ *     }
+ * }
+ * </pre>
+ */
+class ExifOutputStream extends FilterOutputStream {
+    private static final String TAG = "ExifOutputStream";
+    private static final boolean DEBUG = false;
+    private static final int STREAMBUFFER_SIZE = 0x00010000; // 64Kb
+
+    private static final int STATE_SOI = 0;
+    private static final int STATE_FRAME_HEADER = 1;
+    private static final int STATE_JPEG_DATA = 2;
+
+    private static final int EXIF_HEADER = 0x45786966;
+    private static final short TIFF_HEADER = 0x002A;
+    private static final short TIFF_BIG_ENDIAN = 0x4d4d;
+    private static final short TIFF_LITTLE_ENDIAN = 0x4949;
+    private static final short TAG_SIZE = 12;
+    private static final short TIFF_HEADER_SIZE = 8;
+    private static final int MAX_EXIF_SIZE = 65535;
+
+    private ExifData mExifData;
+    private int mState = STATE_SOI;
+    private int mByteToSkip;
+    private int mByteToCopy;
+    private byte[] mSingleByteArray = new byte[1];
+    private ByteBuffer mBuffer = ByteBuffer.allocate(4);
+    private final ExifInterface mInterface;
+
+    protected ExifOutputStream(OutputStream ou, ExifInterface iRef) {
+        super(new BufferedOutputStream(ou, STREAMBUFFER_SIZE));
+        mInterface = iRef;
+    }
+
+    /**
+     * Sets the ExifData to be written into the JPEG file. Should be called
+     * before writing image data.
+     */
+    protected void setExifData(ExifData exifData) {
+        mExifData = exifData;
+    }
+
+    /**
+     * Gets the Exif header to be written into the JPEF file.
+     */
+    protected ExifData getExifData() {
+        return mExifData;
+    }
+
+    private int requestByteToBuffer(int requestByteCount, byte[] buffer
+            , int offset, int length) {
+        int byteNeeded = requestByteCount - mBuffer.position();
+        int byteToRead = length > byteNeeded ? byteNeeded : length;
+        mBuffer.put(buffer, offset, byteToRead);
+        return byteToRead;
+    }
+
+    /**
+     * Writes the image out. The input data should be a valid JPEG format. After
+     * writing, it's Exif header will be replaced by the given header.
+     */
+    @Override
+    public void write(byte[] buffer, int offset, int length) throws IOException {
+        while ((mByteToSkip > 0 || mByteToCopy > 0 || mState != STATE_JPEG_DATA)
+                && length > 0) {
+            if (mByteToSkip > 0) {
+                int byteToProcess = length > mByteToSkip ? mByteToSkip : length;
+                length -= byteToProcess;
+                mByteToSkip -= byteToProcess;
+                offset += byteToProcess;
+            }
+            if (mByteToCopy > 0) {
+                int byteToProcess = length > mByteToCopy ? mByteToCopy : length;
+                out.write(buffer, offset, byteToProcess);
+                length -= byteToProcess;
+                mByteToCopy -= byteToProcess;
+                offset += byteToProcess;
+            }
+            if (length == 0) {
+                return;
+            }
+            switch (mState) {
+                case STATE_SOI:
+                    int byteRead = requestByteToBuffer(2, buffer, offset, length);
+                    offset += byteRead;
+                    length -= byteRead;
+                    if (mBuffer.position() < 2) {
+                        return;
+                    }
+                    mBuffer.rewind();
+                    if (mBuffer.getShort() != JpegHeader.SOI) {
+                        throw new IOException("Not a valid jpeg image, cannot write exif");
+                    }
+                    out.write(mBuffer.array(), 0, 2);
+                    mState = STATE_FRAME_HEADER;
+                    mBuffer.rewind();
+                    writeExifData();
+                    break;
+                case STATE_FRAME_HEADER:
+                    // We ignore the APP1 segment and copy all other segments
+                    // until SOF tag.
+                    byteRead = requestByteToBuffer(4, buffer, offset, length);
+                    offset += byteRead;
+                    length -= byteRead;
+                    // Check if this image data doesn't contain SOF.
+                    if (mBuffer.position() == 2) {
+                        short tag = mBuffer.getShort();
+                        if (tag == JpegHeader.EOI) {
+                            out.write(mBuffer.array(), 0, 2);
+                            mBuffer.rewind();
+                        }
+                    }
+                    if (mBuffer.position() < 4) {
+                        return;
+                    }
+                    mBuffer.rewind();
+                    short marker = mBuffer.getShort();
+                    if (marker == JpegHeader.APP1) {
+                        mByteToSkip = (mBuffer.getShort() & 0x0000ffff) - 2;
+                        mState = STATE_JPEG_DATA;
+                    } else if (!JpegHeader.isSofMarker(marker)) {
+                        out.write(mBuffer.array(), 0, 4);
+                        mByteToCopy = (mBuffer.getShort() & 0x0000ffff) - 2;
+                    } else {
+                        out.write(mBuffer.array(), 0, 4);
+                        mState = STATE_JPEG_DATA;
+                    }
+                    mBuffer.rewind();
+            }
+        }
+        if (length > 0) {
+            out.write(buffer, offset, length);
+        }
+    }
+
+    /**
+     * Writes the one bytes out. The input data should be a valid JPEG format.
+     * After writing, it's Exif header will be replaced by the given header.
+     */
+    @Override
+    public void write(int oneByte) throws IOException {
+        mSingleByteArray[0] = (byte) (0xff & oneByte);
+        write(mSingleByteArray);
+    }
+
+    /**
+     * Equivalent to calling write(buffer, 0, buffer.length).
+     */
+    @Override
+    public void write(byte[] buffer) throws IOException {
+        write(buffer, 0, buffer.length);
+    }
+
+    private void writeExifData() throws IOException {
+        if (mExifData == null) {
+            return;
+        }
+        if (DEBUG) {
+            Log.v(TAG, "Writing exif data...");
+        }
+        ArrayList<ExifTag> nullTags = stripNullValueTags(mExifData);
+        createRequiredIfdAndTag();
+        int exifSize = calculateAllOffset();
+        if (exifSize + 8 > MAX_EXIF_SIZE) {
+            throw new IOException("Exif header is too large (>64Kb)");
+        }
+        OrderedDataOutputStream dataOutputStream = new OrderedDataOutputStream(out);
+        dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+        dataOutputStream.writeShort(JpegHeader.APP1);
+        dataOutputStream.writeShort((short) (exifSize + 8));
+        dataOutputStream.writeInt(EXIF_HEADER);
+        dataOutputStream.writeShort((short) 0x0000);
+        if (mExifData.getByteOrder() == ByteOrder.BIG_ENDIAN) {
+            dataOutputStream.writeShort(TIFF_BIG_ENDIAN);
+        } else {
+            dataOutputStream.writeShort(TIFF_LITTLE_ENDIAN);
+        }
+        dataOutputStream.setByteOrder(mExifData.getByteOrder());
+        dataOutputStream.writeShort(TIFF_HEADER);
+        dataOutputStream.writeInt(8);
+        writeAllTags(dataOutputStream);
+        writeThumbnail(dataOutputStream);
+        for (ExifTag t : nullTags) {
+            mExifData.addTag(t);
+        }
+    }
+
+    private ArrayList<ExifTag> stripNullValueTags(ExifData data) {
+        ArrayList<ExifTag> nullTags = new ArrayList<ExifTag>();
+        for(ExifTag t : data.getAllTags()) {
+            if (t.getValue() == null && !ExifInterface.isOffsetTag(t.getTagId())) {
+                data.removeTag(t.getTagId(), t.getIfd());
+                nullTags.add(t);
+            }
+        }
+        return nullTags;
+    }
+
+    private void writeThumbnail(OrderedDataOutputStream dataOutputStream) throws IOException {
+        if (mExifData.hasCompressedThumbnail()) {
+            dataOutputStream.write(mExifData.getCompressedThumbnail());
+        } else if (mExifData.hasUncompressedStrip()) {
+            for (int i = 0; i < mExifData.getStripCount(); i++) {
+                dataOutputStream.write(mExifData.getStrip(i));
+            }
+        }
+    }
+
+    private void writeAllTags(OrderedDataOutputStream dataOutputStream) throws IOException {
+        writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_0), dataOutputStream);
+        writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_EXIF), dataOutputStream);
+        IfdData interoperabilityIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+        if (interoperabilityIfd != null) {
+            writeIfd(interoperabilityIfd, dataOutputStream);
+        }
+        IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+        if (gpsIfd != null) {
+            writeIfd(gpsIfd, dataOutputStream);
+        }
+        IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+        if (ifd1 != null) {
+            writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_1), dataOutputStream);
+        }
+    }
+
+    private void writeIfd(IfdData ifd, OrderedDataOutputStream dataOutputStream)
+            throws IOException {
+        ExifTag[] tags = ifd.getAllTags();
+        dataOutputStream.writeShort((short) tags.length);
+        for (ExifTag tag : tags) {
+            dataOutputStream.writeShort(tag.getTagId());
+            dataOutputStream.writeShort(tag.getDataType());
+            dataOutputStream.writeInt(tag.getComponentCount());
+            if (DEBUG) {
+                Log.v(TAG, "\n" + tag.toString());
+            }
+            if (tag.getDataSize() > 4) {
+                dataOutputStream.writeInt(tag.getOffset());
+            } else {
+                ExifOutputStream.writeTagValue(tag, dataOutputStream);
+                for (int i = 0, n = 4 - tag.getDataSize(); i < n; i++) {
+                    dataOutputStream.write(0);
+                }
+            }
+        }
+        dataOutputStream.writeInt(ifd.getOffsetToNextIfd());
+        for (ExifTag tag : tags) {
+            if (tag.getDataSize() > 4) {
+                ExifOutputStream.writeTagValue(tag, dataOutputStream);
+            }
+        }
+    }
+
+    private int calculateOffsetOfIfd(IfdData ifd, int offset) {
+        offset += 2 + ifd.getTagCount() * TAG_SIZE + 4;
+        ExifTag[] tags = ifd.getAllTags();
+        for (ExifTag tag : tags) {
+            if (tag.getDataSize() > 4) {
+                tag.setOffset(offset);
+                offset += tag.getDataSize();
+            }
+        }
+        return offset;
+    }
+
+    private void createRequiredIfdAndTag() throws IOException {
+        // IFD0 is required for all file
+        IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
+        if (ifd0 == null) {
+            ifd0 = new IfdData(IfdId.TYPE_IFD_0);
+            mExifData.addIfdData(ifd0);
+        }
+        ExifTag exifOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_EXIF_IFD);
+        if (exifOffsetTag == null) {
+            throw new IOException("No definition for crucial exif tag: "
+                    + ExifInterface.TAG_EXIF_IFD);
+        }
+        ifd0.setTag(exifOffsetTag);
+
+        // Exif IFD is required for all files.
+        IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
+        if (exifIfd == null) {
+            exifIfd = new IfdData(IfdId.TYPE_IFD_EXIF);
+            mExifData.addIfdData(exifIfd);
+        }
+
+        // GPS IFD
+        IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+        if (gpsIfd != null) {
+            ExifTag gpsOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_GPS_IFD);
+            if (gpsOffsetTag == null) {
+                throw new IOException("No definition for crucial exif tag: "
+                        + ExifInterface.TAG_GPS_IFD);
+            }
+            ifd0.setTag(gpsOffsetTag);
+        }
+
+        // Interoperability IFD
+        IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+        if (interIfd != null) {
+            ExifTag interOffsetTag = mInterface
+                    .buildUninitializedTag(ExifInterface.TAG_INTEROPERABILITY_IFD);
+            if (interOffsetTag == null) {
+                throw new IOException("No definition for crucial exif tag: "
+                        + ExifInterface.TAG_INTEROPERABILITY_IFD);
+            }
+            exifIfd.setTag(interOffsetTag);
+        }
+
+        IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+
+        // thumbnail
+        if (mExifData.hasCompressedThumbnail()) {
+
+            if (ifd1 == null) {
+                ifd1 = new IfdData(IfdId.TYPE_IFD_1);
+                mExifData.addIfdData(ifd1);
+            }
+
+            ExifTag offsetTag = mInterface
+                    .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+            if (offsetTag == null) {
+                throw new IOException("No definition for crucial exif tag: "
+                        + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+            }
+
+            ifd1.setTag(offsetTag);
+            ExifTag lengthTag = mInterface
+                    .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+            if (lengthTag == null) {
+                throw new IOException("No definition for crucial exif tag: "
+                        + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+            }
+
+            lengthTag.setValue(mExifData.getCompressedThumbnail().length);
+            ifd1.setTag(lengthTag);
+
+            // Get rid of tags for uncompressed if they exist.
+            ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
+            ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
+        } else if (mExifData.hasUncompressedStrip()) {
+            if (ifd1 == null) {
+                ifd1 = new IfdData(IfdId.TYPE_IFD_1);
+                mExifData.addIfdData(ifd1);
+            }
+            int stripCount = mExifData.getStripCount();
+            ExifTag offsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_STRIP_OFFSETS);
+            if (offsetTag == null) {
+                throw new IOException("No definition for crucial exif tag: "
+                        + ExifInterface.TAG_STRIP_OFFSETS);
+            }
+            ExifTag lengthTag = mInterface
+                    .buildUninitializedTag(ExifInterface.TAG_STRIP_BYTE_COUNTS);
+            if (lengthTag == null) {
+                throw new IOException("No definition for crucial exif tag: "
+                        + ExifInterface.TAG_STRIP_BYTE_COUNTS);
+            }
+            long[] lengths = new long[stripCount];
+            for (int i = 0; i < mExifData.getStripCount(); i++) {
+                lengths[i] = mExifData.getStrip(i).length;
+            }
+            lengthTag.setValue(lengths);
+            ifd1.setTag(offsetTag);
+            ifd1.setTag(lengthTag);
+            // Get rid of tags for compressed if they exist.
+            ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
+            ifd1.removeTag(ExifInterface
+                    .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+        } else if (ifd1 != null) {
+            // Get rid of offset and length tags if there is no thumbnail.
+            ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
+            ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
+            ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
+            ifd1.removeTag(ExifInterface
+                    .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+        }
+    }
+
+    private int calculateAllOffset() {
+        int offset = TIFF_HEADER_SIZE;
+        IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
+        offset = calculateOffsetOfIfd(ifd0, offset);
+        ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_EXIF_IFD)).setValue(offset);
+
+        IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
+        offset = calculateOffsetOfIfd(exifIfd, offset);
+
+        IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+        if (interIfd != null) {
+            exifIfd.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD))
+                    .setValue(offset);
+            offset = calculateOffsetOfIfd(interIfd, offset);
+        }
+
+        IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+        if (gpsIfd != null) {
+            ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD)).setValue(offset);
+            offset = calculateOffsetOfIfd(gpsIfd, offset);
+        }
+
+        IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+        if (ifd1 != null) {
+            ifd0.setOffsetToNextIfd(offset);
+            offset = calculateOffsetOfIfd(ifd1, offset);
+        }
+
+        // thumbnail
+        if (mExifData.hasCompressedThumbnail()) {
+            ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT))
+                    .setValue(offset);
+            offset += mExifData.getCompressedThumbnail().length;
+        } else if (mExifData.hasUncompressedStrip()) {
+            int stripCount = mExifData.getStripCount();
+            long[] offsets = new long[stripCount];
+            for (int i = 0; i < mExifData.getStripCount(); i++) {
+                offsets[i] = offset;
+                offset += mExifData.getStrip(i).length;
+            }
+            ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS)).setValue(
+                    offsets);
+        }
+        return offset;
+    }
+
+    static void writeTagValue(ExifTag tag, OrderedDataOutputStream dataOutputStream)
+            throws IOException {
+        switch (tag.getDataType()) {
+            case ExifTag.TYPE_ASCII:
+                byte buf[] = tag.getStringByte();
+                if (buf.length == tag.getComponentCount()) {
+                    buf[buf.length - 1] = 0;
+                    dataOutputStream.write(buf);
+                } else {
+                    dataOutputStream.write(buf);
+                    dataOutputStream.write(0);
+                }
+                break;
+            case ExifTag.TYPE_LONG:
+            case ExifTag.TYPE_UNSIGNED_LONG:
+                for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+                    dataOutputStream.writeInt((int) tag.getValueAt(i));
+                }
+                break;
+            case ExifTag.TYPE_RATIONAL:
+            case ExifTag.TYPE_UNSIGNED_RATIONAL:
+                for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+                    dataOutputStream.writeRational(tag.getRational(i));
+                }
+                break;
+            case ExifTag.TYPE_UNDEFINED:
+            case ExifTag.TYPE_UNSIGNED_BYTE:
+                buf = new byte[tag.getComponentCount()];
+                tag.getBytes(buf);
+                dataOutputStream.write(buf);
+                break;
+            case ExifTag.TYPE_UNSIGNED_SHORT:
+                for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+                    dataOutputStream.writeShort((short) tag.getValueAt(i));
+                }
+                break;
+        }
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java
new file mode 100644
index 0000000..5467d42
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * This class provides a low-level EXIF parsing API. Given a JPEG format
+ * InputStream, the caller can request which IFD's to read via
+ * {@link #parse(InputStream, int)} with given options.
+ * <p>
+ * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
+ * parser.
+ *
+ * <pre>
+ * void parse() {
+ *     ExifParser parser = ExifParser.parse(mImageInputStream,
+ *             ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
+ *     int event = parser.next();
+ *     while (event != ExifParser.EVENT_END) {
+ *         switch (event) {
+ *             case ExifParser.EVENT_START_OF_IFD:
+ *                 break;
+ *             case ExifParser.EVENT_NEW_TAG:
+ *                 ExifTag tag = parser.getTag();
+ *                 if (!tag.hasValue()) {
+ *                     parser.registerForTagValue(tag);
+ *                 } else {
+ *                     processTag(tag);
+ *                 }
+ *                 break;
+ *             case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
+ *                 tag = parser.getTag();
+ *                 if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
+ *                     processTag(tag);
+ *                 }
+ *                 break;
+ *         }
+ *         event = parser.next();
+ *     }
+ * }
+ *
+ * void processTag(ExifTag tag) {
+ *     // process the tag as you like.
+ * }
+ * </pre>
+ */
+class ExifParser {
+    private static final boolean LOGV = false;
+    private static final String TAG = "ExifParser";
+    /**
+     * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
+     * know which IFD we are in.
+     */
+    public static final int EVENT_START_OF_IFD = 0;
+    /**
+     * When the parser reaches a new tag. Call {@link #getTag()}to get the
+     * corresponding tag.
+     */
+    public static final int EVENT_NEW_TAG = 1;
+    /**
+     * When the parser reaches the value area of tag that is registered by
+     * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
+     * to get the corresponding tag.
+     */
+    public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
+
+    /**
+     * When the parser reaches the compressed image area.
+     */
+    public static final int EVENT_COMPRESSED_IMAGE = 3;
+    /**
+     * When the parser reaches the uncompressed image strip. Call
+     * {@link #getStripIndex()} to get the index of the strip.
+     *
+     * @see #getStripIndex()
+     * @see #getStripCount()
+     */
+    public static final int EVENT_UNCOMPRESSED_STRIP = 4;
+    /**
+     * When there is nothing more to parse.
+     */
+    public static final int EVENT_END = 5;
+
+    /**
+     * Option bit to request to parse IFD0.
+     */
+    public static final int OPTION_IFD_0 = 1 << 0;
+    /**
+     * Option bit to request to parse IFD1.
+     */
+    public static final int OPTION_IFD_1 = 1 << 1;
+    /**
+     * Option bit to request to parse Exif-IFD.
+     */
+    public static final int OPTION_IFD_EXIF = 1 << 2;
+    /**
+     * Option bit to request to parse GPS-IFD.
+     */
+    public static final int OPTION_IFD_GPS = 1 << 3;
+    /**
+     * Option bit to request to parse Interoperability-IFD.
+     */
+    public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
+    /**
+     * Option bit to request to parse thumbnail.
+     */
+    public static final int OPTION_THUMBNAIL = 1 << 5;
+
+    protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
+    protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
+
+    // TIFF header
+    protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
+    protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
+    protected static final short TIFF_HEADER_TAIL = 0x002A;
+
+    protected static final int TAG_SIZE = 12;
+    protected static final int OFFSET_SIZE = 2;
+
+    private static final Charset US_ASCII = Charset.forName("US-ASCII");
+
+    protected static final int DEFAULT_IFD0_OFFSET = 8;
+
+    private final CountedDataInputStream mTiffStream;
+    private final int mOptions;
+    private int mIfdStartOffset = 0;
+    private int mNumOfTagInIfd = 0;
+    private int mIfdType;
+    private ExifTag mTag;
+    private ImageEvent mImageEvent;
+    private int mStripCount;
+    private ExifTag mStripSizeTag;
+    private ExifTag mJpegSizeTag;
+    private boolean mNeedToParseOffsetsInCurrentIfd;
+    private boolean mContainExifData = false;
+    private int mApp1End;
+    private int mOffsetToApp1EndFromSOF = 0;
+    private byte[] mDataAboveIfd0;
+    private int mIfd0Position;
+    private int mTiffStartPosition;
+    private final ExifInterface mInterface;
+
+    private static final short TAG_EXIF_IFD = ExifInterface
+            .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
+    private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
+    private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
+            .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
+    private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
+            .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+    private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
+            .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+    private static final short TAG_STRIP_OFFSETS = ExifInterface
+            .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
+    private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
+            .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
+
+    private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
+
+    private boolean isIfdRequested(int ifdType) {
+        switch (ifdType) {
+            case IfdId.TYPE_IFD_0:
+                return (mOptions & OPTION_IFD_0) != 0;
+            case IfdId.TYPE_IFD_1:
+                return (mOptions & OPTION_IFD_1) != 0;
+            case IfdId.TYPE_IFD_EXIF:
+                return (mOptions & OPTION_IFD_EXIF) != 0;
+            case IfdId.TYPE_IFD_GPS:
+                return (mOptions & OPTION_IFD_GPS) != 0;
+            case IfdId.TYPE_IFD_INTEROPERABILITY:
+                return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
+        }
+        return false;
+    }
+
+    private boolean isThumbnailRequested() {
+        return (mOptions & OPTION_THUMBNAIL) != 0;
+    }
+
+    private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
+            throws IOException, ExifInvalidFormatException {
+        if (inputStream == null) {
+            throw new IOException("Null argument inputStream to ExifParser");
+        }
+        if (LOGV) {
+            Log.v(TAG, "Reading exif...");
+        }
+        mInterface = iRef;
+        mContainExifData = seekTiffData(inputStream);
+        mTiffStream = new CountedDataInputStream(inputStream);
+        mOptions = options;
+        if (!mContainExifData) {
+            return;
+        }
+
+        parseTiffHeader();
+        long offset = mTiffStream.readUnsignedInt();
+        if (offset > Integer.MAX_VALUE) {
+            throw new ExifInvalidFormatException("Invalid offset " + offset);
+        }
+        mIfd0Position = (int) offset;
+        mIfdType = IfdId.TYPE_IFD_0;
+        if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
+            registerIfd(IfdId.TYPE_IFD_0, offset);
+            if (offset != DEFAULT_IFD0_OFFSET) {
+                mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
+                read(mDataAboveIfd0);
+            }
+        }
+    }
+
+    /**
+     * Parses the the given InputStream with the given options
+     *
+     * @exception IOException
+     * @exception ExifInvalidFormatException
+     */
+    protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
+            throws IOException, ExifInvalidFormatException {
+        return new ExifParser(inputStream, options, iRef);
+    }
+
+    /**
+     * Parses the the given InputStream with default options; that is, every IFD
+     * and thumbnaill will be parsed.
+     *
+     * @exception IOException
+     * @exception ExifInvalidFormatException
+     * @see #parse(InputStream, int)
+     */
+    protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
+            throws IOException, ExifInvalidFormatException {
+        return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
+                | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
+                | OPTION_THUMBNAIL, iRef);
+    }
+
+    /**
+     * Moves the parser forward and returns the next parsing event
+     *
+     * @exception IOException
+     * @exception ExifInvalidFormatException
+     * @see #EVENT_START_OF_IFD
+     * @see #EVENT_NEW_TAG
+     * @see #EVENT_VALUE_OF_REGISTERED_TAG
+     * @see #EVENT_COMPRESSED_IMAGE
+     * @see #EVENT_UNCOMPRESSED_STRIP
+     * @see #EVENT_END
+     */
+    protected int next() throws IOException, ExifInvalidFormatException {
+        if (!mContainExifData) {
+            return EVENT_END;
+        }
+        int offset = mTiffStream.getReadByteCount();
+        int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
+        if (offset < endOfTags) {
+            mTag = readTag();
+            if (mTag == null) {
+                return next();
+            }
+            if (mNeedToParseOffsetsInCurrentIfd) {
+                checkOffsetOrImageTag(mTag);
+            }
+            return EVENT_NEW_TAG;
+        } else if (offset == endOfTags) {
+            // There is a link to ifd1 at the end of ifd0
+            if (mIfdType == IfdId.TYPE_IFD_0) {
+                long ifdOffset = readUnsignedLong();
+                if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
+                    if (ifdOffset != 0) {
+                        registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
+                    }
+                }
+            } else {
+                int offsetSize = 4;
+                // Some camera models use invalid length of the offset
+                if (mCorrespondingEvent.size() > 0) {
+                    offsetSize = mCorrespondingEvent.firstEntry().getKey() -
+                            mTiffStream.getReadByteCount();
+                }
+                if (offsetSize < 4) {
+                    Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
+                } else {
+                    long ifdOffset = readUnsignedLong();
+                    if (ifdOffset != 0) {
+                        Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
+                    }
+                }
+            }
+        }
+        while (mCorrespondingEvent.size() != 0) {
+            Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
+            Object event = entry.getValue();
+            try {
+                skipTo(entry.getKey());
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
+                        " for " + event.getClass().getName() + ", the file may be broken.");
+                continue;
+            }
+            if (event instanceof IfdEvent) {
+                mIfdType = ((IfdEvent) event).ifd;
+                mNumOfTagInIfd = mTiffStream.readUnsignedShort();
+                mIfdStartOffset = entry.getKey();
+
+                if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
+                    Log.w(TAG, "Invalid size of IFD " + mIfdType);
+                    return EVENT_END;
+                }
+
+                mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
+                if (((IfdEvent) event).isRequested) {
+                    return EVENT_START_OF_IFD;
+                } else {
+                    skipRemainingTagsInCurrentIfd();
+                }
+            } else if (event instanceof ImageEvent) {
+                mImageEvent = (ImageEvent) event;
+                return mImageEvent.type;
+            } else {
+                ExifTagEvent tagEvent = (ExifTagEvent) event;
+                mTag = tagEvent.tag;
+                if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
+                    readFullTagValue(mTag);
+                    checkOffsetOrImageTag(mTag);
+                }
+                if (tagEvent.isRequested) {
+                    return EVENT_VALUE_OF_REGISTERED_TAG;
+                }
+            }
+        }
+        return EVENT_END;
+    }
+
+    /**
+     * Skips the tags area of current IFD, if the parser is not in the tag area,
+     * nothing will happen.
+     *
+     * @throws IOException
+     * @throws ExifInvalidFormatException
+     */
+    protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
+        int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
+        int offset = mTiffStream.getReadByteCount();
+        if (offset > endOfTags) {
+            return;
+        }
+        if (mNeedToParseOffsetsInCurrentIfd) {
+            while (offset < endOfTags) {
+                mTag = readTag();
+                offset += TAG_SIZE;
+                if (mTag == null) {
+                    continue;
+                }
+                checkOffsetOrImageTag(mTag);
+            }
+        } else {
+            skipTo(endOfTags);
+        }
+        long ifdOffset = readUnsignedLong();
+        // For ifd0, there is a link to ifd1 in the end of all tags
+        if (mIfdType == IfdId.TYPE_IFD_0
+                && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
+            if (ifdOffset > 0) {
+                registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
+            }
+        }
+    }
+
+    private boolean needToParseOffsetsInCurrentIfd() {
+        switch (mIfdType) {
+            case IfdId.TYPE_IFD_0:
+                return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
+                        || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
+                        || isIfdRequested(IfdId.TYPE_IFD_1);
+            case IfdId.TYPE_IFD_1:
+                return isThumbnailRequested();
+            case IfdId.TYPE_IFD_EXIF:
+                // The offset to interoperability IFD is located in Exif IFD
+                return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * If {@link #next()} return {@link #EVENT_NEW_TAG} or
+     * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
+     * corresponding tag.
+     * <p>
+     * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
+     * of the value is greater than 4 bytes. One should call
+     * {@link ExifTag#hasValue()} to check if the tag contains value. If there
+     * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
+     * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
+     * pointed by the offset.
+     * <p>
+     * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
+     * tag will have already been read except for tags of undefined type. For
+     * tags of undefined type, call one of the read methods to get the value.
+     *
+     * @see #registerForTagValue(ExifTag)
+     * @see #read(byte[])
+     * @see #read(byte[], int, int)
+     * @see #readLong()
+     * @see #readRational()
+     * @see #readString(int)
+     * @see #readString(int, Charset)
+     */
+    protected ExifTag getTag() {
+        return mTag;
+    }
+
+    /**
+     * Gets number of tags in the current IFD area.
+     */
+    protected int getTagCountInCurrentIfd() {
+        return mNumOfTagInIfd;
+    }
+
+    /**
+     * Gets the ID of current IFD.
+     *
+     * @see IfdId#TYPE_IFD_0
+     * @see IfdId#TYPE_IFD_1
+     * @see IfdId#TYPE_IFD_GPS
+     * @see IfdId#TYPE_IFD_INTEROPERABILITY
+     * @see IfdId#TYPE_IFD_EXIF
+     */
+    protected int getCurrentIfd() {
+        return mIfdType;
+    }
+
+    /**
+     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+     * get the index of this strip.
+     *
+     * @see #getStripCount()
+     */
+    protected int getStripIndex() {
+        return mImageEvent.stripIndex;
+    }
+
+    /**
+     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+     * get the number of strip data.
+     *
+     * @see #getStripIndex()
+     */
+    protected int getStripCount() {
+        return mStripCount;
+    }
+
+    /**
+     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+     * get the strip size.
+     */
+    protected int getStripSize() {
+        if (mStripSizeTag == null)
+            return 0;
+        return (int) mStripSizeTag.getValueAt(0);
+    }
+
+    /**
+     * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
+     * the image data size.
+     */
+    protected int getCompressedImageSize() {
+        if (mJpegSizeTag == null) {
+            return 0;
+        }
+        return (int) mJpegSizeTag.getValueAt(0);
+    }
+
+    private void skipTo(int offset) throws IOException {
+        mTiffStream.skipTo(offset);
+        while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
+            mCorrespondingEvent.pollFirstEntry();
+        }
+    }
+
+    /**
+     * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
+     * not contain the value if the size of the value is greater than 4 bytes.
+     * When the value is not available here, call this method so that the parser
+     * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
+     * where the value is located.
+     *
+     * @see #EVENT_VALUE_OF_REGISTERED_TAG
+     */
+    protected void registerForTagValue(ExifTag tag) {
+        if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
+            mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
+        }
+    }
+
+    private void registerIfd(int ifdType, long offset) {
+        // Cast unsigned int to int since the offset is always smaller
+        // than the size of APP1 (65536)
+        mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
+    }
+
+    private void registerCompressedImage(long offset) {
+        mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
+    }
+
+    private void registerUncompressedStrip(int stripIndex, long offset) {
+        mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
+                , stripIndex));
+    }
+
+    private ExifTag readTag() throws IOException, ExifInvalidFormatException {
+        short tagId = mTiffStream.readShort();
+        short dataFormat = mTiffStream.readShort();
+        long numOfComp = mTiffStream.readUnsignedInt();
+        if (numOfComp > Integer.MAX_VALUE) {
+            throw new ExifInvalidFormatException(
+                    "Number of component is larger then Integer.MAX_VALUE");
+        }
+        // Some invalid image file contains invalid data type. Ignore those tags
+        if (!ExifTag.isValidType(dataFormat)) {
+            Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
+            mTiffStream.skip(4);
+            return null;
+        }
+        // TODO: handle numOfComp overflow
+        ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
+                ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
+        int dataSize = tag.getDataSize();
+        if (dataSize > 4) {
+            long offset = mTiffStream.readUnsignedInt();
+            if (offset > Integer.MAX_VALUE) {
+                throw new ExifInvalidFormatException(
+                        "offset is larger then Integer.MAX_VALUE");
+            }
+            // Some invalid images put some undefined data before IFD0.
+            // Read the data here.
+            if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
+                byte[] buf = new byte[(int) numOfComp];
+                System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
+                        buf, 0, (int) numOfComp);
+                tag.setValue(buf);
+            } else {
+                tag.setOffset((int) offset);
+            }
+        } else {
+            boolean defCount = tag.hasDefinedCount();
+            // Set defined count to 0 so we can add \0 to non-terminated strings
+            tag.setHasDefinedCount(false);
+            // Read value
+            readFullTagValue(tag);
+            tag.setHasDefinedCount(defCount);
+            mTiffStream.skip(4 - dataSize);
+            // Set the offset to the position of value.
+            tag.setOffset(mTiffStream.getReadByteCount() - 4);
+        }
+        return tag;
+    }
+
+    /**
+     * Check the tag, if the tag is one of the offset tag that points to the IFD
+     * or image the caller is interested in, register the IFD or image.
+     */
+    private void checkOffsetOrImageTag(ExifTag tag) {
+        // Some invalid formattd image contains tag with 0 size.
+        if (tag.getComponentCount() == 0) {
+            return;
+        }
+        short tid = tag.getTagId();
+        int ifd = tag.getIfd();
+        if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
+            if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
+                    || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
+                registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
+            }
+        } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
+            if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
+                registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
+            }
+        } else if (tid == TAG_INTEROPERABILITY_IFD
+                && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
+            if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
+                registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
+            }
+        } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
+                && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
+            if (isThumbnailRequested()) {
+                registerCompressedImage(tag.getValueAt(0));
+            }
+        } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
+                && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
+            if (isThumbnailRequested()) {
+                mJpegSizeTag = tag;
+            }
+        } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
+            if (isThumbnailRequested()) {
+                if (tag.hasValue()) {
+                    for (int i = 0; i < tag.getComponentCount(); i++) {
+                        if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
+                            registerUncompressedStrip(i, tag.getValueAt(i));
+                        } else {
+                            registerUncompressedStrip(i, tag.getValueAt(i));
+                        }
+                    }
+                } else {
+                    mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
+                }
+            }
+        } else if (tid == TAG_STRIP_BYTE_COUNTS
+                && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
+                &&isThumbnailRequested() && tag.hasValue()) {
+            mStripSizeTag = tag;
+        }
+    }
+
+    private boolean checkAllowed(int ifd, int tagId) {
+        int info = mInterface.getTagInfo().get(tagId);
+        if (info == ExifInterface.DEFINITION_NULL) {
+            return false;
+        }
+        return ExifInterface.isIfdAllowed(info, ifd);
+    }
+
+    protected void readFullTagValue(ExifTag tag) throws IOException {
+        // Some invalid images contains tags with wrong size, check it here
+        short type = tag.getDataType();
+        if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
+                type == ExifTag.TYPE_UNSIGNED_BYTE) {
+            int size = tag.getComponentCount();
+            if (mCorrespondingEvent.size() > 0) {
+                if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
+                        + size) {
+                    Object event = mCorrespondingEvent.firstEntry().getValue();
+                    if (event instanceof ImageEvent) {
+                        // Tag value overlaps thumbnail, ignore thumbnail.
+                        Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
+                        Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
+                        Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
+                    } else {
+                        // Tag value overlaps another tag, shorten count
+                        if (event instanceof IfdEvent) {
+                            Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
+                                    + " overlaps value for tag: \n" + tag.toString());
+                        } else if (event instanceof ExifTagEvent) {
+                            Log.w(TAG, "Tag value for tag: \n"
+                                    + ((ExifTagEvent) event).tag.toString()
+                                    + " overlaps value for tag: \n" + tag.toString());
+                        }
+                        size = mCorrespondingEvent.firstEntry().getKey()
+                                - mTiffStream.getReadByteCount();
+                        Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
+                                + " setting count to: " + size);
+                        tag.forceSetComponentCount(size);
+                    }
+                }
+            }
+        }
+        switch (tag.getDataType()) {
+            case ExifTag.TYPE_UNSIGNED_BYTE:
+            case ExifTag.TYPE_UNDEFINED: {
+                byte buf[] = new byte[tag.getComponentCount()];
+                read(buf);
+                tag.setValue(buf);
+            }
+                break;
+            case ExifTag.TYPE_ASCII:
+                tag.setValue(readString(tag.getComponentCount()));
+                break;
+            case ExifTag.TYPE_UNSIGNED_LONG: {
+                long value[] = new long[tag.getComponentCount()];
+                for (int i = 0, n = value.length; i < n; i++) {
+                    value[i] = readUnsignedLong();
+                }
+                tag.setValue(value);
+            }
+                break;
+            case ExifTag.TYPE_UNSIGNED_RATIONAL: {
+                Rational value[] = new Rational[tag.getComponentCount()];
+                for (int i = 0, n = value.length; i < n; i++) {
+                    value[i] = readUnsignedRational();
+                }
+                tag.setValue(value);
+            }
+                break;
+            case ExifTag.TYPE_UNSIGNED_SHORT: {
+                int value[] = new int[tag.getComponentCount()];
+                for (int i = 0, n = value.length; i < n; i++) {
+                    value[i] = readUnsignedShort();
+                }
+                tag.setValue(value);
+            }
+                break;
+            case ExifTag.TYPE_LONG: {
+                int value[] = new int[tag.getComponentCount()];
+                for (int i = 0, n = value.length; i < n; i++) {
+                    value[i] = readLong();
+                }
+                tag.setValue(value);
+            }
+                break;
+            case ExifTag.TYPE_RATIONAL: {
+                Rational value[] = new Rational[tag.getComponentCount()];
+                for (int i = 0, n = value.length; i < n; i++) {
+                    value[i] = readRational();
+                }
+                tag.setValue(value);
+            }
+                break;
+        }
+        if (LOGV) {
+            Log.v(TAG, "\n" + tag.toString());
+        }
+    }
+
+    private void parseTiffHeader() throws IOException,
+            ExifInvalidFormatException {
+        short byteOrder = mTiffStream.readShort();
+        if (LITTLE_ENDIAN_TAG == byteOrder) {
+            mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+        } else if (BIG_ENDIAN_TAG == byteOrder) {
+            mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+        } else {
+            throw new ExifInvalidFormatException("Invalid TIFF header");
+        }
+
+        if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
+            throw new ExifInvalidFormatException("Invalid TIFF header");
+        }
+    }
+
+    private boolean seekTiffData(InputStream inputStream) throws IOException,
+            ExifInvalidFormatException {
+        CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
+        if (dataStream.readShort() != JpegHeader.SOI) {
+            throw new ExifInvalidFormatException("Invalid JPEG format");
+        }
+
+        short marker = dataStream.readShort();
+        while (marker != JpegHeader.EOI
+                && !JpegHeader.isSofMarker(marker)) {
+            int length = dataStream.readUnsignedShort();
+            // Some invalid formatted image contains multiple APP1,
+            // try to find the one with Exif data.
+            if (marker == JpegHeader.APP1) {
+                int header = 0;
+                short headerTail = 0;
+                if (length >= 8) {
+                    header = dataStream.readInt();
+                    headerTail = dataStream.readShort();
+                    length -= 6;
+                    if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
+                        mTiffStartPosition = dataStream.getReadByteCount();
+                        mApp1End = length;
+                        mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
+                        return true;
+                    }
+                }
+            }
+            if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
+                Log.w(TAG, "Invalid JPEG format.");
+                return false;
+            }
+            marker = dataStream.readShort();
+        }
+        return false;
+    }
+
+    protected int getOffsetToExifEndFromSOF() {
+        return mOffsetToApp1EndFromSOF;
+    }
+
+    protected int getTiffStartPosition() {
+        return mTiffStartPosition;
+    }
+
+    /**
+     * Reads bytes from the InputStream.
+     */
+    protected int read(byte[] buffer, int offset, int length) throws IOException {
+        return mTiffStream.read(buffer, offset, length);
+    }
+
+    /**
+     * Equivalent to read(buffer, 0, buffer.length).
+     */
+    protected int read(byte[] buffer) throws IOException {
+        return mTiffStream.read(buffer);
+    }
+
+    /**
+     * Reads a String from the InputStream with US-ASCII charset. The parser
+     * will read n bytes and convert it to ascii string. This is used for
+     * reading values of type {@link ExifTag#TYPE_ASCII}.
+     */
+    protected String readString(int n) throws IOException {
+        return readString(n, US_ASCII);
+    }
+
+    /**
+     * Reads a String from the InputStream with the given charset. The parser
+     * will read n bytes and convert it to string. This is used for reading
+     * values of type {@link ExifTag#TYPE_ASCII}.
+     */
+    protected String readString(int n, Charset charset) throws IOException {
+        if (n > 0) {
+            return mTiffStream.readString(n, charset);
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
+     * InputStream.
+     */
+    protected int readUnsignedShort() throws IOException {
+        return mTiffStream.readShort() & 0xffff;
+    }
+
+    /**
+     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
+     * InputStream.
+     */
+    protected long readUnsignedLong() throws IOException {
+        return readLong() & 0xffffffffL;
+    }
+
+    /**
+     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
+     * InputStream.
+     */
+    protected Rational readUnsignedRational() throws IOException {
+        long nomi = readUnsignedLong();
+        long denomi = readUnsignedLong();
+        return new Rational(nomi, denomi);
+    }
+
+    /**
+     * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
+     */
+    protected int readLong() throws IOException {
+        return mTiffStream.readInt();
+    }
+
+    /**
+     * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
+     */
+    protected Rational readRational() throws IOException {
+        int nomi = readLong();
+        int denomi = readLong();
+        return new Rational(nomi, denomi);
+    }
+
+    private static class ImageEvent {
+        int stripIndex;
+        int type;
+
+        ImageEvent(int type) {
+            this.stripIndex = 0;
+            this.type = type;
+        }
+
+        ImageEvent(int type, int stripIndex) {
+            this.type = type;
+            this.stripIndex = stripIndex;
+        }
+    }
+
+    private static class IfdEvent {
+        int ifd;
+        boolean isRequested;
+
+        IfdEvent(int ifd, boolean isInterestedIfd) {
+            this.ifd = ifd;
+            this.isRequested = isInterestedIfd;
+        }
+    }
+
+    private static class ExifTagEvent {
+        ExifTag tag;
+        boolean isRequested;
+
+        ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
+            this.tag = tag;
+            this.isRequested = isRequireByUser;
+        }
+    }
+
+    /**
+     * Gets the byte order of the current InputStream.
+     */
+    protected ByteOrder getByteOrder() {
+        return mTiffStream.getByteOrder();
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java
new file mode 100644
index 0000000..68e972f
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class reads the EXIF header of a JPEG file and stores it in
+ * {@link ExifData}.
+ */
+class ExifReader {
+    private static final String TAG = "ExifReader";
+
+    private final ExifInterface mInterface;
+
+    ExifReader(ExifInterface iRef) {
+        mInterface = iRef;
+    }
+
+    /**
+     * Parses the inputStream and and returns the EXIF data in an
+     * {@link ExifData}.
+     *
+     * @throws ExifInvalidFormatException
+     * @throws IOException
+     */
+    protected ExifData read(InputStream inputStream) throws ExifInvalidFormatException,
+            IOException {
+        ExifParser parser = ExifParser.parse(inputStream, mInterface);
+        ExifData exifData = new ExifData(parser.getByteOrder());
+        ExifTag tag = null;
+
+        int event = parser.next();
+        while (event != ExifParser.EVENT_END) {
+            switch (event) {
+                case ExifParser.EVENT_START_OF_IFD:
+                    exifData.addIfdData(new IfdData(parser.getCurrentIfd()));
+                    break;
+                case ExifParser.EVENT_NEW_TAG:
+                    tag = parser.getTag();
+                    if (!tag.hasValue()) {
+                        parser.registerForTagValue(tag);
+                    } else {
+                        exifData.getIfdData(tag.getIfd()).setTag(tag);
+                    }
+                    break;
+                case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
+                    tag = parser.getTag();
+                    if (tag.getDataType() == ExifTag.TYPE_UNDEFINED) {
+                        parser.readFullTagValue(tag);
+                    }
+                    exifData.getIfdData(tag.getIfd()).setTag(tag);
+                    break;
+                case ExifParser.EVENT_COMPRESSED_IMAGE:
+                    byte buf[] = new byte[parser.getCompressedImageSize()];
+                    if (buf.length == parser.read(buf)) {
+                        exifData.setCompressedThumbnail(buf);
+                    } else {
+                        Log.w(TAG, "Failed to read the compressed thumbnail");
+                    }
+                    break;
+                case ExifParser.EVENT_UNCOMPRESSED_STRIP:
+                    buf = new byte[parser.getStripSize()];
+                    if (buf.length == parser.read(buf)) {
+                        exifData.setStripBytes(parser.getStripIndex(), buf);
+                    } else {
+                        Log.w(TAG, "Failed to read the strip bytes");
+                    }
+                    break;
+            }
+            event = parser.next();
+        }
+        return exifData;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java
new file mode 100644
index 0000000..b8b3872
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * This class stores information of an EXIF tag. For more information about
+ * defined EXIF tags, please read the Jeita EXIF 2.2 standard. Tags should be
+ * instantiated using {@link ExifInterface#buildTag}.
+ *
+ * @see ExifInterface
+ */
+public class ExifTag {
+    /**
+     * The BYTE type in the EXIF standard. An 8-bit unsigned integer.
+     */
+    public static final short TYPE_UNSIGNED_BYTE = 1;
+    /**
+     * The ASCII type in the EXIF standard. An 8-bit byte containing one 7-bit
+     * ASCII code. The final byte is terminated with NULL.
+     */
+    public static final short TYPE_ASCII = 2;
+    /**
+     * The SHORT type in the EXIF standard. A 16-bit (2-byte) unsigned integer
+     */
+    public static final short TYPE_UNSIGNED_SHORT = 3;
+    /**
+     * The LONG type in the EXIF standard. A 32-bit (4-byte) unsigned integer
+     */
+    public static final short TYPE_UNSIGNED_LONG = 4;
+    /**
+     * The RATIONAL type of EXIF standard. It consists of two LONGs. The first
+     * one is the numerator and the second one expresses the denominator.
+     */
+    public static final short TYPE_UNSIGNED_RATIONAL = 5;
+    /**
+     * The UNDEFINED type in the EXIF standard. An 8-bit byte that can take any
+     * value depending on the field definition.
+     */
+    public static final short TYPE_UNDEFINED = 7;
+    /**
+     * The SLONG type in the EXIF standard. A 32-bit (4-byte) signed integer
+     * (2's complement notation).
+     */
+    public static final short TYPE_LONG = 9;
+    /**
+     * The SRATIONAL type of EXIF standard. It consists of two SLONGs. The first
+     * one is the numerator and the second one is the denominator.
+     */
+    public static final short TYPE_RATIONAL = 10;
+
+    private static Charset US_ASCII = Charset.forName("US-ASCII");
+    private static final int TYPE_TO_SIZE_MAP[] = new int[11];
+    private static final int UNSIGNED_SHORT_MAX = 65535;
+    private static final long UNSIGNED_LONG_MAX = 4294967295L;
+    private static final long LONG_MAX = Integer.MAX_VALUE;
+    private static final long LONG_MIN = Integer.MIN_VALUE;
+
+    static {
+        TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_BYTE] = 1;
+        TYPE_TO_SIZE_MAP[TYPE_ASCII] = 1;
+        TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_SHORT] = 2;
+        TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_LONG] = 4;
+        TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_RATIONAL] = 8;
+        TYPE_TO_SIZE_MAP[TYPE_UNDEFINED] = 1;
+        TYPE_TO_SIZE_MAP[TYPE_LONG] = 4;
+        TYPE_TO_SIZE_MAP[TYPE_RATIONAL] = 8;
+    }
+
+    static final int SIZE_UNDEFINED = 0;
+
+    // Exif TagId
+    private final short mTagId;
+    // Exif Tag Type
+    private final short mDataType;
+    // If tag has defined count
+    private boolean mHasDefinedDefaultComponentCount;
+    // Actual data count in tag (should be number of elements in value array)
+    private int mComponentCountActual;
+    // The ifd that this tag should be put in
+    private int mIfd;
+    // The value (array of elements of type Tag Type)
+    private Object mValue;
+    // Value offset in exif header.
+    private int mOffset;
+
+    private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyy:MM:dd kk:mm:ss");
+
+    /**
+     * Returns true if the given IFD is a valid IFD.
+     */
+    public static boolean isValidIfd(int ifdId) {
+        return ifdId == IfdId.TYPE_IFD_0 || ifdId == IfdId.TYPE_IFD_1
+                || ifdId == IfdId.TYPE_IFD_EXIF || ifdId == IfdId.TYPE_IFD_INTEROPERABILITY
+                || ifdId == IfdId.TYPE_IFD_GPS;
+    }
+
+    /**
+     * Returns true if a given type is a valid tag type.
+     */
+    public static boolean isValidType(short type) {
+        return type == TYPE_UNSIGNED_BYTE || type == TYPE_ASCII ||
+                type == TYPE_UNSIGNED_SHORT || type == TYPE_UNSIGNED_LONG ||
+                type == TYPE_UNSIGNED_RATIONAL || type == TYPE_UNDEFINED ||
+                type == TYPE_LONG || type == TYPE_RATIONAL;
+    }
+
+    // Use builtTag in ExifInterface instead of constructor.
+    ExifTag(short tagId, short type, int componentCount, int ifd,
+            boolean hasDefinedComponentCount) {
+        mTagId = tagId;
+        mDataType = type;
+        mComponentCountActual = componentCount;
+        mHasDefinedDefaultComponentCount = hasDefinedComponentCount;
+        mIfd = ifd;
+        mValue = null;
+    }
+
+    /**
+     * Gets the element size of the given data type in bytes.
+     *
+     * @see #TYPE_ASCII
+     * @see #TYPE_LONG
+     * @see #TYPE_RATIONAL
+     * @see #TYPE_UNDEFINED
+     * @see #TYPE_UNSIGNED_BYTE
+     * @see #TYPE_UNSIGNED_LONG
+     * @see #TYPE_UNSIGNED_RATIONAL
+     * @see #TYPE_UNSIGNED_SHORT
+     */
+    public static int getElementSize(short type) {
+        return TYPE_TO_SIZE_MAP[type];
+    }
+
+    /**
+     * Returns the ID of the IFD this tag belongs to.
+     *
+     * @see IfdId#TYPE_IFD_0
+     * @see IfdId#TYPE_IFD_1
+     * @see IfdId#TYPE_IFD_EXIF
+     * @see IfdId#TYPE_IFD_GPS
+     * @see IfdId#TYPE_IFD_INTEROPERABILITY
+     */
+    public int getIfd() {
+        return mIfd;
+    }
+
+    protected void setIfd(int ifdId) {
+        mIfd = ifdId;
+    }
+
+    /**
+     * Gets the TID of this tag.
+     */
+    public short getTagId() {
+        return mTagId;
+    }
+
+    /**
+     * Gets the data type of this tag
+     *
+     * @see #TYPE_ASCII
+     * @see #TYPE_LONG
+     * @see #TYPE_RATIONAL
+     * @see #TYPE_UNDEFINED
+     * @see #TYPE_UNSIGNED_BYTE
+     * @see #TYPE_UNSIGNED_LONG
+     * @see #TYPE_UNSIGNED_RATIONAL
+     * @see #TYPE_UNSIGNED_SHORT
+     */
+    public short getDataType() {
+        return mDataType;
+    }
+
+    /**
+     * Gets the total data size in bytes of the value of this tag.
+     */
+    public int getDataSize() {
+        return getComponentCount() * getElementSize(getDataType());
+    }
+
+    /**
+     * Gets the component count of this tag.
+     */
+
+    // TODO: fix integer overflows with this
+    public int getComponentCount() {
+        return mComponentCountActual;
+    }
+
+    /**
+     * Sets the component count of this tag. Call this function before
+     * setValue() if the length of value does not match the component count.
+     */
+    protected void forceSetComponentCount(int count) {
+        mComponentCountActual = count;
+    }
+
+    /**
+     * Returns true if this ExifTag contains value; otherwise, this tag will
+     * contain an offset value that is determined when the tag is written.
+     */
+    public boolean hasValue() {
+        return mValue != null;
+    }
+
+    /**
+     * Sets integer values into this tag. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_SHORT}. This method will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+     * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+     * <li>The value overflows.</li>
+     * <li>The value.length does NOT match the component count in the definition
+     * for this tag.</li>
+     * </ul>
+     */
+    public boolean setValue(int[] value) {
+        if (checkBadComponentCount(value.length)) {
+            return false;
+        }
+        if (mDataType != TYPE_UNSIGNED_SHORT && mDataType != TYPE_LONG &&
+                mDataType != TYPE_UNSIGNED_LONG) {
+            return false;
+        }
+        if (mDataType == TYPE_UNSIGNED_SHORT && checkOverflowForUnsignedShort(value)) {
+            return false;
+        } else if (mDataType == TYPE_UNSIGNED_LONG && checkOverflowForUnsignedLong(value)) {
+            return false;
+        }
+
+        long[] data = new long[value.length];
+        for (int i = 0; i < value.length; i++) {
+            data[i] = value[i];
+        }
+        mValue = data;
+        mComponentCountActual = value.length;
+        return true;
+    }
+
+    /**
+     * Sets integer value into this tag. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_SHORT}, or {@link #TYPE_LONG}. This method
+     * will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+     * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+     * <li>The value overflows.</li>
+     * <li>The component count in the definition of this tag is not 1.</li>
+     * </ul>
+     */
+    public boolean setValue(int value) {
+        return setValue(new int[] {
+                value
+        });
+    }
+
+    /**
+     * Sets long values into this tag. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+     * <li>The value overflows.</li>
+     * <li>The value.length does NOT match the component count in the definition
+     * for this tag.</li>
+     * </ul>
+     */
+    public boolean setValue(long[] value) {
+        if (checkBadComponentCount(value.length) || mDataType != TYPE_UNSIGNED_LONG) {
+            return false;
+        }
+        if (checkOverflowForUnsignedLong(value)) {
+            return false;
+        }
+        mValue = value;
+        mComponentCountActual = value.length;
+        return true;
+    }
+
+    /**
+     * Sets long values into this tag. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+     * <li>The value overflows.</li>
+     * <li>The component count in the definition for this tag is not 1.</li>
+     * </ul>
+     */
+    public boolean setValue(long value) {
+        return setValue(new long[] {
+                value
+        });
+    }
+
+    /**
+     * Sets a string value into this tag. This method should be used for tags of
+     * type {@link #TYPE_ASCII}. The string is converted to an ASCII string.
+     * Characters that cannot be converted are replaced with '?'. The length of
+     * the string must be equal to either (component count -1) or (component
+     * count). The final byte will be set to the string null terminator '\0',
+     * overwriting the last character in the string if the value.length is equal
+     * to the component count. This method will fail if:
+     * <ul>
+     * <li>The data type is not {@link #TYPE_ASCII} or {@link #TYPE_UNDEFINED}.</li>
+     * <li>The length of the string is not equal to (component count -1) or
+     * (component count) in the definition for this tag.</li>
+     * </ul>
+     */
+    public boolean setValue(String value) {
+        if (mDataType != TYPE_ASCII && mDataType != TYPE_UNDEFINED) {
+            return false;
+        }
+
+        byte[] buf = value.getBytes(US_ASCII);
+        byte[] finalBuf = buf;
+        if (buf.length > 0) {
+            finalBuf = (buf[buf.length - 1] == 0 || mDataType == TYPE_UNDEFINED) ? buf : Arrays
+                .copyOf(buf, buf.length + 1);
+        } else if (mDataType == TYPE_ASCII && mComponentCountActual == 1) {
+            finalBuf = new byte[] { 0 };
+        }
+        int count = finalBuf.length;
+        if (checkBadComponentCount(count)) {
+            return false;
+        }
+        mComponentCountActual = count;
+        mValue = finalBuf;
+        return true;
+    }
+
+    /**
+     * Sets Rational values into this tag. This method should be used for tags
+     * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
+     * method will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
+     * or {@link #TYPE_RATIONAL}.</li>
+     * <li>The value overflows.</li>
+     * <li>The value.length does NOT match the component count in the definition
+     * for this tag.</li>
+     * </ul>
+     *
+     * @see Rational
+     */
+    public boolean setValue(Rational[] value) {
+        if (checkBadComponentCount(value.length)) {
+            return false;
+        }
+        if (mDataType != TYPE_UNSIGNED_RATIONAL && mDataType != TYPE_RATIONAL) {
+            return false;
+        }
+        if (mDataType == TYPE_UNSIGNED_RATIONAL && checkOverflowForUnsignedRational(value)) {
+            return false;
+        } else if (mDataType == TYPE_RATIONAL && checkOverflowForRational(value)) {
+            return false;
+        }
+
+        mValue = value;
+        mComponentCountActual = value.length;
+        return true;
+    }
+
+    /**
+     * Sets a Rational value into this tag. This method should be used for tags
+     * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
+     * method will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
+     * or {@link #TYPE_RATIONAL}.</li>
+     * <li>The value overflows.</li>
+     * <li>The component count in the definition for this tag is not 1.</li>
+     * </ul>
+     *
+     * @see Rational
+     */
+    public boolean setValue(Rational value) {
+        return setValue(new Rational[] {
+                value
+        });
+    }
+
+    /**
+     * Sets byte values into this tag. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
+     * will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+     * {@link #TYPE_UNDEFINED} .</li>
+     * <li>The length does NOT match the component count in the definition for
+     * this tag.</li>
+     * </ul>
+     */
+    public boolean setValue(byte[] value, int offset, int length) {
+        if (checkBadComponentCount(length)) {
+            return false;
+        }
+        if (mDataType != TYPE_UNSIGNED_BYTE && mDataType != TYPE_UNDEFINED) {
+            return false;
+        }
+        mValue = new byte[length];
+        System.arraycopy(value, offset, mValue, 0, length);
+        mComponentCountActual = length;
+        return true;
+    }
+
+    /**
+     * Equivalent to setValue(value, 0, value.length).
+     */
+    public boolean setValue(byte[] value) {
+        return setValue(value, 0, value.length);
+    }
+
+    /**
+     * Sets byte value into this tag. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
+     * will fail if:
+     * <ul>
+     * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+     * {@link #TYPE_UNDEFINED} .</li>
+     * <li>The component count in the definition for this tag is not 1.</li>
+     * </ul>
+     */
+    public boolean setValue(byte value) {
+        return setValue(new byte[] {
+                value
+        });
+    }
+
+    /**
+     * Sets the value for this tag using an appropriate setValue method for the
+     * given object. This method will fail if:
+     * <ul>
+     * <li>The corresponding setValue method for the class of the object passed
+     * in would fail.</li>
+     * <li>There is no obvious way to cast the object passed in into an EXIF tag
+     * type.</li>
+     * </ul>
+     */
+    public boolean setValue(Object obj) {
+        if (obj == null) {
+            return false;
+        } else if (obj instanceof Short) {
+            return setValue(((Short) obj).shortValue() & 0x0ffff);
+        } else if (obj instanceof String) {
+            return setValue((String) obj);
+        } else if (obj instanceof int[]) {
+            return setValue((int[]) obj);
+        } else if (obj instanceof long[]) {
+            return setValue((long[]) obj);
+        } else if (obj instanceof Rational) {
+            return setValue((Rational) obj);
+        } else if (obj instanceof Rational[]) {
+            return setValue((Rational[]) obj);
+        } else if (obj instanceof byte[]) {
+            return setValue((byte[]) obj);
+        } else if (obj instanceof Integer) {
+            return setValue(((Integer) obj).intValue());
+        } else if (obj instanceof Long) {
+            return setValue(((Long) obj).longValue());
+        } else if (obj instanceof Byte) {
+            return setValue(((Byte) obj).byteValue());
+        } else if (obj instanceof Short[]) {
+            // Nulls in this array are treated as zeroes.
+            Short[] arr = (Short[]) obj;
+            int[] fin = new int[arr.length];
+            for (int i = 0; i < arr.length; i++) {
+                fin[i] = (arr[i] == null) ? 0 : arr[i].shortValue() & 0x0ffff;
+            }
+            return setValue(fin);
+        } else if (obj instanceof Integer[]) {
+            // Nulls in this array are treated as zeroes.
+            Integer[] arr = (Integer[]) obj;
+            int[] fin = new int[arr.length];
+            for (int i = 0; i < arr.length; i++) {
+                fin[i] = (arr[i] == null) ? 0 : arr[i].intValue();
+            }
+            return setValue(fin);
+        } else if (obj instanceof Long[]) {
+            // Nulls in this array are treated as zeroes.
+            Long[] arr = (Long[]) obj;
+            long[] fin = new long[arr.length];
+            for (int i = 0; i < arr.length; i++) {
+                fin[i] = (arr[i] == null) ? 0 : arr[i].longValue();
+            }
+            return setValue(fin);
+        } else if (obj instanceof Byte[]) {
+            // Nulls in this array are treated as zeroes.
+            Byte[] arr = (Byte[]) obj;
+            byte[] fin = new byte[arr.length];
+            for (int i = 0; i < arr.length; i++) {
+                fin[i] = (arr[i] == null) ? 0 : arr[i].byteValue();
+            }
+            return setValue(fin);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Sets a timestamp to this tag. The method converts the timestamp with the
+     * format of "yyyy:MM:dd kk:mm:ss" and calls {@link #setValue(String)}. This
+     * method will fail if the data type is not {@link #TYPE_ASCII} or the
+     * component count of this tag is not 20 or undefined.
+     *
+     * @param time the number of milliseconds since Jan. 1, 1970 GMT
+     * @return true on success
+     */
+    public boolean setTimeValue(long time) {
+        // synchronized on TIME_FORMAT as SimpleDateFormat is not thread safe
+        synchronized (TIME_FORMAT) {
+            return setValue(TIME_FORMAT.format(new Date(time)));
+        }
+    }
+
+    /**
+     * Gets the value as a String. This method should be used for tags of type
+     * {@link #TYPE_ASCII}.
+     *
+     * @return the value as a String, or null if the tag's value does not exist
+     *         or cannot be converted to a String.
+     */
+    public String getValueAsString() {
+        if (mValue == null) {
+            return null;
+        } else if (mValue instanceof String) {
+            return (String) mValue;
+        } else if (mValue instanceof byte[]) {
+            return new String((byte[]) mValue, US_ASCII);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the value as a String. This method should be used for tags of type
+     * {@link #TYPE_ASCII}.
+     *
+     * @param defaultValue the String to return if the tag's value does not
+     *            exist or cannot be converted to a String.
+     * @return the tag's value as a String, or the defaultValue.
+     */
+    public String getValueAsString(String defaultValue) {
+        String s = getValueAsString();
+        if (s == null) {
+            return defaultValue;
+        }
+        return s;
+    }
+
+    /**
+     * Gets the value as a byte array. This method should be used for tags of
+     * type {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+     *
+     * @return the value as a byte array, or null if the tag's value does not
+     *         exist or cannot be converted to a byte array.
+     */
+    public byte[] getValueAsBytes() {
+        if (mValue instanceof byte[]) {
+            return (byte[]) mValue;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the value as a byte. If there are more than 1 bytes in this value,
+     * gets the first byte. This method should be used for tags of type
+     * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+     *
+     * @param defaultValue the byte to return if tag's value does not exist or
+     *            cannot be converted to a byte.
+     * @return the tag's value as a byte, or the defaultValue.
+     */
+    public byte getValueAsByte(byte defaultValue) {
+        byte[] b = getValueAsBytes();
+        if (b == null || b.length < 1) {
+            return defaultValue;
+        }
+        return b[0];
+    }
+
+    /**
+     * Gets the value as an array of Rationals. This method should be used for
+     * tags of type {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+     *
+     * @return the value as as an array of Rationals, or null if the tag's value
+     *         does not exist or cannot be converted to an array of Rationals.
+     */
+    public Rational[] getValueAsRationals() {
+        if (mValue instanceof Rational[]) {
+            return (Rational[]) mValue;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the value as a Rational. If there are more than 1 Rationals in this
+     * value, gets the first one. This method should be used for tags of type
+     * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+     *
+     * @param defaultValue the Rational to return if tag's value does not exist
+     *            or cannot be converted to a Rational.
+     * @return the tag's value as a Rational, or the defaultValue.
+     */
+    public Rational getValueAsRational(Rational defaultValue) {
+        Rational[] r = getValueAsRationals();
+        if (r == null || r.length < 1) {
+            return defaultValue;
+        }
+        return r[0];
+    }
+
+    /**
+     * Gets the value as a Rational. If there are more than 1 Rationals in this
+     * value, gets the first one. This method should be used for tags of type
+     * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+     *
+     * @param defaultValue the numerator of the Rational to return if tag's
+     *            value does not exist or cannot be converted to a Rational (the
+     *            denominator will be 1).
+     * @return the tag's value as a Rational, or the defaultValue.
+     */
+    public Rational getValueAsRational(long defaultValue) {
+        Rational defaultVal = new Rational(defaultValue, 1);
+        return getValueAsRational(defaultVal);
+    }
+
+    /**
+     * Gets the value as an array of ints. This method should be used for tags
+     * of type {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
+     *
+     * @return the value as as an array of ints, or null if the tag's value does
+     *         not exist or cannot be converted to an array of ints.
+     */
+    public int[] getValueAsInts() {
+        if (mValue == null) {
+            return null;
+        } else if (mValue instanceof long[]) {
+            long[] val = (long[]) mValue;
+            int[] arr = new int[val.length];
+            for (int i = 0; i < val.length; i++) {
+                arr[i] = (int) val[i]; // Truncates
+            }
+            return arr;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the value as an int. If there are more than 1 ints in this value,
+     * gets the first one. This method should be used for tags of type
+     * {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
+     *
+     * @param defaultValue the int to return if tag's value does not exist or
+     *            cannot be converted to an int.
+     * @return the tag's value as a int, or the defaultValue.
+     */
+    public int getValueAsInt(int defaultValue) {
+        int[] i = getValueAsInts();
+        if (i == null || i.length < 1) {
+            return defaultValue;
+        }
+        return i[0];
+    }
+
+    /**
+     * Gets the value as an array of longs. This method should be used for tags
+     * of type {@link #TYPE_UNSIGNED_LONG}.
+     *
+     * @return the value as as an array of longs, or null if the tag's value
+     *         does not exist or cannot be converted to an array of longs.
+     */
+    public long[] getValueAsLongs() {
+        if (mValue instanceof long[]) {
+            return (long[]) mValue;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the value or null if none exists. If there are more than 1 longs in
+     * this value, gets the first one. This method should be used for tags of
+     * type {@link #TYPE_UNSIGNED_LONG}.
+     *
+     * @param defaultValue the long to return if tag's value does not exist or
+     *            cannot be converted to a long.
+     * @return the tag's value as a long, or the defaultValue.
+     */
+    public long getValueAsLong(long defaultValue) {
+        long[] l = getValueAsLongs();
+        if (l == null || l.length < 1) {
+            return defaultValue;
+        }
+        return l[0];
+    }
+
+    /**
+     * Gets the tag's value or null if none exists.
+     */
+    public Object getValue() {
+        return mValue;
+    }
+
+    /**
+     * Gets a long representation of the value.
+     *
+     * @param defaultValue value to return if there is no value or value is a
+     *            rational with a denominator of 0.
+     * @return the tag's value as a long, or defaultValue if no representation
+     *         exists.
+     */
+    public long forceGetValueAsLong(long defaultValue) {
+        long[] l = getValueAsLongs();
+        if (l != null && l.length >= 1) {
+            return l[0];
+        }
+        byte[] b = getValueAsBytes();
+        if (b != null && b.length >= 1) {
+            return b[0];
+        }
+        Rational[] r = getValueAsRationals();
+        if (r != null && r.length >= 1 && r[0].getDenominator() != 0) {
+            return (long) r[0].toDouble();
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Gets a string representation of the value.
+     */
+    public String forceGetValueAsString() {
+        if (mValue == null) {
+            return "";
+        } else if (mValue instanceof byte[]) {
+            if (mDataType == TYPE_ASCII) {
+                return new String((byte[]) mValue, US_ASCII);
+            } else {
+                return Arrays.toString((byte[]) mValue);
+            }
+        } else if (mValue instanceof long[]) {
+            if (((long[]) mValue).length == 1) {
+                return String.valueOf(((long[]) mValue)[0]);
+            } else {
+                return Arrays.toString((long[]) mValue);
+            }
+        } else if (mValue instanceof Object[]) {
+            if (((Object[]) mValue).length == 1) {
+                Object val = ((Object[]) mValue)[0];
+                if (val == null) {
+                    return "";
+                } else {
+                    return val.toString();
+                }
+            } else {
+                return Arrays.toString((Object[]) mValue);
+            }
+        } else {
+            return mValue.toString();
+        }
+    }
+
+    /**
+     * Gets the value for type {@link #TYPE_ASCII}, {@link #TYPE_LONG},
+     * {@link #TYPE_UNDEFINED}, {@link #TYPE_UNSIGNED_BYTE},
+     * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_UNSIGNED_SHORT}. For
+     * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}, call
+     * {@link #getRational(int)} instead.
+     *
+     * @exception IllegalArgumentException if the data type is
+     *                {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+     */
+    protected long getValueAt(int index) {
+        if (mValue instanceof long[]) {
+            return ((long[]) mValue)[index];
+        } else if (mValue instanceof byte[]) {
+            return ((byte[]) mValue)[index];
+        }
+        throw new IllegalArgumentException("Cannot get integer value from "
+                + convertTypeToString(mDataType));
+    }
+
+    /**
+     * Gets the {@link #TYPE_ASCII} data.
+     *
+     * @exception IllegalArgumentException If the type is NOT
+     *                {@link #TYPE_ASCII}.
+     */
+    protected String getString() {
+        if (mDataType != TYPE_ASCII) {
+            throw new IllegalArgumentException("Cannot get ASCII value from "
+                    + convertTypeToString(mDataType));
+        }
+        return new String((byte[]) mValue, US_ASCII);
+    }
+
+    /*
+     * Get the converted ascii byte. Used by ExifOutputStream.
+     */
+    protected byte[] getStringByte() {
+        return (byte[]) mValue;
+    }
+
+    /**
+     * Gets the {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL} data.
+     *
+     * @exception IllegalArgumentException If the type is NOT
+     *                {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+     */
+    protected Rational getRational(int index) {
+        if ((mDataType != TYPE_RATIONAL) && (mDataType != TYPE_UNSIGNED_RATIONAL)) {
+            throw new IllegalArgumentException("Cannot get RATIONAL value from "
+                    + convertTypeToString(mDataType));
+        }
+        return ((Rational[]) mValue)[index];
+    }
+
+    /**
+     * Equivalent to getBytes(buffer, 0, buffer.length).
+     */
+    protected void getBytes(byte[] buf) {
+        getBytes(buf, 0, buf.length);
+    }
+
+    /**
+     * Gets the {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE} data.
+     *
+     * @param buf the byte array in which to store the bytes read.
+     * @param offset the initial position in buffer to store the bytes.
+     * @param length the maximum number of bytes to store in buffer. If length >
+     *            component count, only the valid bytes will be stored.
+     * @exception IllegalArgumentException If the type is NOT
+     *                {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+     */
+    protected void getBytes(byte[] buf, int offset, int length) {
+        if ((mDataType != TYPE_UNDEFINED) && (mDataType != TYPE_UNSIGNED_BYTE)) {
+            throw new IllegalArgumentException("Cannot get BYTE value from "
+                    + convertTypeToString(mDataType));
+        }
+        System.arraycopy(mValue, 0, buf, offset,
+                (length > mComponentCountActual) ? mComponentCountActual : length);
+    }
+
+    /**
+     * Gets the offset of this tag. This is only valid if this data size > 4 and
+     * contains an offset to the location of the actual value.
+     */
+    protected int getOffset() {
+        return mOffset;
+    }
+
+    /**
+     * Sets the offset of this tag.
+     */
+    protected void setOffset(int offset) {
+        mOffset = offset;
+    }
+
+    protected void setHasDefinedCount(boolean d) {
+        mHasDefinedDefaultComponentCount = d;
+    }
+
+    protected boolean hasDefinedCount() {
+        return mHasDefinedDefaultComponentCount;
+    }
+
+    private boolean checkBadComponentCount(int count) {
+        if (mHasDefinedDefaultComponentCount && (mComponentCountActual != count)) {
+            return true;
+        }
+        return false;
+    }
+
+    private static String convertTypeToString(short type) {
+        switch (type) {
+            case TYPE_UNSIGNED_BYTE:
+                return "UNSIGNED_BYTE";
+            case TYPE_ASCII:
+                return "ASCII";
+            case TYPE_UNSIGNED_SHORT:
+                return "UNSIGNED_SHORT";
+            case TYPE_UNSIGNED_LONG:
+                return "UNSIGNED_LONG";
+            case TYPE_UNSIGNED_RATIONAL:
+                return "UNSIGNED_RATIONAL";
+            case TYPE_UNDEFINED:
+                return "UNDEFINED";
+            case TYPE_LONG:
+                return "LONG";
+            case TYPE_RATIONAL:
+                return "RATIONAL";
+            default:
+                return "";
+        }
+    }
+
+    private boolean checkOverflowForUnsignedShort(int[] value) {
+        for (int v : value) {
+            if (v > UNSIGNED_SHORT_MAX || v < 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkOverflowForUnsignedLong(long[] value) {
+        for (long v : value) {
+            if (v < 0 || v > UNSIGNED_LONG_MAX) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkOverflowForUnsignedLong(int[] value) {
+        for (int v : value) {
+            if (v < 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkOverflowForUnsignedRational(Rational[] value) {
+        for (Rational v : value) {
+            if (v.getNumerator() < 0 || v.getDenominator() < 0
+                    || v.getNumerator() > UNSIGNED_LONG_MAX
+                    || v.getDenominator() > UNSIGNED_LONG_MAX) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkOverflowForRational(Rational[] value) {
+        for (Rational v : value) {
+            if (v.getNumerator() < LONG_MIN || v.getDenominator() < LONG_MIN
+                    || v.getNumerator() > LONG_MAX
+                    || v.getDenominator() > LONG_MAX) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof ExifTag) {
+            ExifTag tag = (ExifTag) obj;
+            if (tag.mTagId != this.mTagId
+                    || tag.mComponentCountActual != this.mComponentCountActual
+                    || tag.mDataType != this.mDataType) {
+                return false;
+            }
+            if (mValue != null) {
+                if (tag.mValue == null) {
+                    return false;
+                } else if (mValue instanceof long[]) {
+                    if (!(tag.mValue instanceof long[])) {
+                        return false;
+                    }
+                    return Arrays.equals((long[]) mValue, (long[]) tag.mValue);
+                } else if (mValue instanceof Rational[]) {
+                    if (!(tag.mValue instanceof Rational[])) {
+                        return false;
+                    }
+                    return Arrays.equals((Rational[]) mValue, (Rational[]) tag.mValue);
+                } else if (mValue instanceof byte[]) {
+                    if (!(tag.mValue instanceof byte[])) {
+                        return false;
+                    }
+                    return Arrays.equals((byte[]) mValue, (byte[]) tag.mValue);
+                } else {
+                    return mValue.equals(tag.mValue);
+                }
+            } else {
+                return tag.mValue == null;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("tag id: %04X\n", mTagId) + "ifd id: " + mIfd + "\ntype: "
+                + convertTypeToString(mDataType) + "\ncount: " + mComponentCountActual
+                + "\noffset: " + mOffset + "\nvalue: " + forceGetValueAsString() + "\n";
+    }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java
new file mode 100644
index 0000000..093944a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class stores all the tags in an IFD.
+ *
+ * @see ExifData
+ * @see ExifTag
+ */
+class IfdData {
+
+    private final int mIfdId;
+    private final Map<Short, ExifTag> mExifTags = new HashMap<Short, ExifTag>();
+    private int mOffsetToNextIfd = 0;
+    private static final int[] sIfds = {
+            IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1, IfdId.TYPE_IFD_EXIF,
+            IfdId.TYPE_IFD_INTEROPERABILITY, IfdId.TYPE_IFD_GPS
+    };
+    /**
+     * Creates an IfdData with given IFD ID.
+     *
+     * @see IfdId#TYPE_IFD_0
+     * @see IfdId#TYPE_IFD_1
+     * @see IfdId#TYPE_IFD_EXIF
+     * @see IfdId#TYPE_IFD_GPS
+     * @see IfdId#TYPE_IFD_INTEROPERABILITY
+     */
+    IfdData(int ifdId) {
+        mIfdId = ifdId;
+    }
+
+    static protected int[] getIfds() {
+        return sIfds;
+    }
+
+    /**
+     * Get a array the contains all {@link ExifTag} in this IFD.
+     */
+    protected ExifTag[] getAllTags() {
+        return mExifTags.values().toArray(new ExifTag[mExifTags.size()]);
+    }
+
+    /**
+     * Gets the ID of this IFD.
+     *
+     * @see IfdId#TYPE_IFD_0
+     * @see IfdId#TYPE_IFD_1
+     * @see IfdId#TYPE_IFD_EXIF
+     * @see IfdId#TYPE_IFD_GPS
+     * @see IfdId#TYPE_IFD_INTEROPERABILITY
+     */
+    protected int getId() {
+        return mIfdId;
+    }
+
+    /**
+     * Gets the {@link ExifTag} with given tag id. Return null if there is no
+     * such tag.
+     */
+    protected ExifTag getTag(short tagId) {
+        return mExifTags.get(tagId);
+    }
+
+    /**
+     * Adds or replaces a {@link ExifTag}.
+     */
+    protected ExifTag setTag(ExifTag tag) {
+        tag.setIfd(mIfdId);
+        return mExifTags.put(tag.getTagId(), tag);
+    }
+
+    protected boolean checkCollision(short tagId) {
+        return mExifTags.get(tagId) != null;
+    }
+
+    /**
+     * Removes the tag of the given ID
+     */
+    protected void removeTag(short tagId) {
+        mExifTags.remove(tagId);
+    }
+
+    /**
+     * Gets the tags count in the IFD.
+     */
+    protected int getTagCount() {
+        return mExifTags.size();
+    }
+
+    /**
+     * Sets the offset of next IFD.
+     */
+    protected void setOffsetToNextIfd(int offset) {
+        mOffsetToNextIfd = offset;
+    }
+
+    /**
+     * Gets the offset of next IFD.
+     */
+    protected int getOffsetToNextIfd() {
+        return mOffsetToNextIfd;
+    }
+
+    /**
+     * Returns true if all tags in this two IFDs are equal. Note that tags of
+     * IFDs offset or thumbnail offset will be ignored.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof IfdData) {
+            IfdData data = (IfdData) obj;
+            if (data.getId() == mIfdId && data.getTagCount() == getTagCount()) {
+                ExifTag[] tags = data.getAllTags();
+                for (ExifTag tag : tags) {
+                    if (ExifInterface.isOffsetTag(tag.getTagId())) {
+                        continue;
+                    }
+                    ExifTag tag2 = mExifTags.get(tag.getTagId());
+                    if (!tag.equals(tag2)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java
new file mode 100644
index 0000000..7842edb
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+/**
+ * The constants of the IFD ID defined in EXIF spec.
+ */
+public interface IfdId {
+    public static final int TYPE_IFD_0 = 0;
+    public static final int TYPE_IFD_1 = 1;
+    public static final int TYPE_IFD_EXIF = 2;
+    public static final int TYPE_IFD_INTEROPERABILITY = 3;
+    public static final int TYPE_IFD_GPS = 4;
+    /* This is used in ExifData to allocate enough IfdData */
+    static final int TYPE_IFD_COUNT = 5;
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java
new file mode 100644
index 0000000..e3e787e
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+class JpegHeader {
+    public static final short SOI =  (short) 0xFFD8;
+    public static final short APP1 = (short) 0xFFE1;
+    public static final short APP0 = (short) 0xFFE0;
+    public static final short EOI = (short) 0xFFD9;
+
+    /**
+     *  SOF (start of frame). All value between SOF0 and SOF15 is SOF marker except for DHT, JPG,
+     *  and DAC marker.
+     */
+    public static final short SOF0 = (short) 0xFFC0;
+    public static final short SOF15 = (short) 0xFFCF;
+    public static final short DHT = (short) 0xFFC4;
+    public static final short JPG = (short) 0xFFC8;
+    public static final short DAC = (short) 0xFFCC;
+
+    public static final boolean isSofMarker(short marker) {
+        return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG
+                && marker != DAC;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
new file mode 100644
index 0000000..428e6b9
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+class OrderedDataOutputStream extends FilterOutputStream {
+    private final ByteBuffer mByteBuffer = ByteBuffer.allocate(4);
+
+    public OrderedDataOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    public OrderedDataOutputStream setByteOrder(ByteOrder order) {
+        mByteBuffer.order(order);
+        return this;
+    }
+
+    public OrderedDataOutputStream writeShort(short value) throws IOException {
+        mByteBuffer.rewind();
+        mByteBuffer.putShort(value);
+        out.write(mByteBuffer.array(), 0, 2);
+        return this;
+    }
+
+    public OrderedDataOutputStream writeInt(int value) throws IOException {
+        mByteBuffer.rewind();
+        mByteBuffer.putInt(value);
+        out.write(mByteBuffer.array());
+        return this;
+    }
+
+    public OrderedDataOutputStream writeRational(Rational rational) throws IOException {
+        writeInt((int) rational.getNumerator());
+        writeInt((int) rational.getDenominator());
+        return this;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java
new file mode 100644
index 0000000..591d63f
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+/**
+ * The rational data type of EXIF tag. Contains a pair of longs representing the
+ * numerator and denominator of a Rational number.
+ */
+public class Rational {
+
+    private final long mNumerator;
+    private final long mDenominator;
+
+    /**
+     * Create a Rational with a given numerator and denominator.
+     *
+     * @param nominator
+     * @param denominator
+     */
+    public Rational(long nominator, long denominator) {
+        mNumerator = nominator;
+        mDenominator = denominator;
+    }
+
+    /**
+     * Create a copy of a Rational.
+     */
+    public Rational(Rational r) {
+        mNumerator = r.mNumerator;
+        mDenominator = r.mDenominator;
+    }
+
+    /**
+     * Gets the numerator of the rational.
+     */
+    public long getNumerator() {
+        return mNumerator;
+    }
+
+    /**
+     * Gets the denominator of the rational
+     */
+    public long getDenominator() {
+        return mDenominator;
+    }
+
+    /**
+     * Gets the rational value as type double. Will cause a divide-by-zero error
+     * if the denominator is 0.
+     */
+    public double toDouble() {
+        return mNumerator / (double) mDenominator;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Rational) {
+            Rational data = (Rational) obj;
+            return mNumerator == data.mNumerator && mDenominator == data.mDenominator;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return mNumerator + "/" + mDenominator;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java
new file mode 100644
index 0000000..2e77b90
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.util.Log;
+
+import com.android.gallery3d.common.Utils;
+
+import java.util.WeakHashMap;
+
+// BasicTexture is a Texture corresponds to a real GL texture.
+// The state of a BasicTexture indicates whether its data is loaded to GL memory.
+// If a BasicTexture is loaded into GL memory, it has a GL texture id.
+public abstract class BasicTexture implements Texture {
+
+    @SuppressWarnings("unused")
+    private static final String TAG = "BasicTexture";
+    protected static final int UNSPECIFIED = -1;
+
+    protected static final int STATE_UNLOADED = 0;
+    protected static final int STATE_LOADED = 1;
+    protected static final int STATE_ERROR = -1;
+
+    // Log a warning if a texture is larger along a dimension
+    private static final int MAX_TEXTURE_SIZE = 4096;
+
+    protected int mId = -1;
+    protected int mState;
+
+    protected int mWidth = UNSPECIFIED;
+    protected int mHeight = UNSPECIFIED;
+
+    protected int mTextureWidth;
+    protected int mTextureHeight;
+
+    private boolean mHasBorder;
+
+    protected GLCanvas mCanvasRef = null;
+    private static WeakHashMap<BasicTexture, Object> sAllTextures
+            = new WeakHashMap<BasicTexture, Object>();
+    private static ThreadLocal sInFinalizer = new ThreadLocal();
+
+    protected BasicTexture(GLCanvas canvas, int id, int state) {
+        setAssociatedCanvas(canvas);
+        mId = id;
+        mState = state;
+        synchronized (sAllTextures) {
+            sAllTextures.put(this, null);
+        }
+    }
+
+    protected BasicTexture() {
+        this(null, 0, STATE_UNLOADED);
+    }
+
+    protected void setAssociatedCanvas(GLCanvas canvas) {
+        mCanvasRef = canvas;
+    }
+
+    /**
+     * Sets the content size of this texture. In OpenGL, the actual texture
+     * size must be of power of 2, the size of the content may be smaller.
+     */
+    public void setSize(int width, int height) {
+        mWidth = width;
+        mHeight = height;
+        mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0;
+        mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0;
+        if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) {
+            Log.w(TAG, String.format("texture is too large: %d x %d",
+                    mTextureWidth, mTextureHeight), new Exception());
+        }
+    }
+
+    public boolean isFlippedVertically() {
+      return false;
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    // Returns the width rounded to the next power of 2.
+    public int getTextureWidth() {
+        return mTextureWidth;
+    }
+
+    // Returns the height rounded to the next power of 2.
+    public int getTextureHeight() {
+        return mTextureHeight;
+    }
+
+    // Returns true if the texture has one pixel transparent border around the
+    // actual content. This is used to avoid jigged edges.
+    //
+    // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap
+    // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially
+    // covered by the texture will use the color of the edge texel. If we add
+    // the transparent border, the color of the edge texel will be mixed with
+    // appropriate amount of transparent.
+    //
+    // Currently our background is black, so we can draw the thumbnails without
+    // enabling blending.
+    public boolean hasBorder() {
+        return mHasBorder;
+    }
+
+    protected void setBorder(boolean hasBorder) {
+        mHasBorder = hasBorder;
+    }
+
+    @Override
+    public void draw(GLCanvas canvas, int x, int y) {
+        canvas.drawTexture(this, x, y, getWidth(), getHeight());
+    }
+
+    @Override
+    public void draw(GLCanvas canvas, int x, int y, int w, int h) {
+        canvas.drawTexture(this, x, y, w, h);
+    }
+
+    // onBind is called before GLCanvas binds this texture.
+    // It should make sure the data is uploaded to GL memory.
+    abstract protected boolean onBind(GLCanvas canvas);
+
+    // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D).
+    abstract protected int getTarget();
+
+    public boolean isLoaded() {
+        return mState == STATE_LOADED;
+    }
+
+    // recycle() is called when the texture will never be used again,
+    // so it can free all resources.
+    public void recycle() {
+        freeResource();
+    }
+
+    // yield() is called when the texture will not be used temporarily,
+    // so it can free some resources.
+    // The default implementation unloads the texture from GL memory, so
+    // the subclass should make sure it can reload the texture to GL memory
+    // later, or it will have to override this method.
+    public void yield() {
+        freeResource();
+    }
+
+    private void freeResource() {
+        GLCanvas canvas = mCanvasRef;
+        if (canvas != null && mId != -1) {
+            canvas.unloadTexture(this);
+            mId = -1; // Don't free it again.
+        }
+        mState = STATE_UNLOADED;
+        setAssociatedCanvas(null);
+    }
+
+    @Override
+    protected void finalize() {
+        sInFinalizer.set(BasicTexture.class);
+        recycle();
+        sInFinalizer.set(null);
+    }
+
+    // This is for deciding if we can call Bitmap's recycle().
+    // We cannot call Bitmap's recycle() in finalizer because at that point
+    // the finalizer of Bitmap may already be called so recycle() will crash.
+    public static boolean inFinalizer() {
+        return sInFinalizer.get() != null;
+    }
+
+    public static void yieldAllTextures() {
+        synchronized (sAllTextures) {
+            for (BasicTexture t : sAllTextures.keySet()) {
+                t.yield();
+            }
+        }
+    }
+
+    public static void invalidateAllTextures() {
+        synchronized (sAllTextures) {
+            for (BasicTexture t : sAllTextures.keySet()) {
+                t.mState = STATE_UNLOADED;
+                t.setAssociatedCanvas(null);
+            }
+        }
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
new file mode 100644
index 0000000..100b0b3b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+
+import junit.framework.Assert;
+
+// BitmapTexture is a texture whose content is specified by a fixed Bitmap.
+//
+// The texture does not own the Bitmap. The user should make sure the Bitmap
+// is valid during the texture's lifetime. When the texture is recycled, it
+// does not free the Bitmap.
+public class BitmapTexture extends UploadedTexture {
+    protected Bitmap mContentBitmap;
+
+    public BitmapTexture(Bitmap bitmap) {
+        this(bitmap, false);
+    }
+
+    public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
+        super(hasBorder);
+        Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+        mContentBitmap = bitmap;
+    }
+
+    @Override
+    protected void onFreeBitmap(Bitmap bitmap) {
+        // Do nothing.
+    }
+
+    @Override
+    protected Bitmap onGetBitmap() {
+        return mContentBitmap;
+    }
+
+    public Bitmap getBitmap() {
+        return mContentBitmap;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java
new file mode 100644
index 0000000..305e905
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import javax.microedition.khronos.opengles.GL11;
+
+//
+// GLCanvas gives a convenient interface to draw using OpenGL.
+//
+// When a rectangle is specified in this interface, it means the region
+// [x, x+width) * [y, y+height)
+//
+public interface GLCanvas {
+
+    public GLId getGLId();
+
+    // Tells GLCanvas the size of the underlying GL surface. This should be
+    // called before first drawing and when the size of GL surface is changed.
+    // This is called by GLRoot and should not be called by the clients
+    // who only want to draw on the GLCanvas. Both width and height must be
+    // nonnegative.
+    public abstract void setSize(int width, int height);
+
+    // Clear the drawing buffers. This should only be used by GLRoot.
+    public abstract void clearBuffer();
+
+    public abstract void clearBuffer(float[] argb);
+
+    // Sets and gets the current alpha, alpha must be in [0, 1].
+    public abstract void setAlpha(float alpha);
+
+    public abstract float getAlpha();
+
+    // (current alpha) = (current alpha) * alpha
+    public abstract void multiplyAlpha(float alpha);
+
+    // Change the current transform matrix.
+    public abstract void translate(float x, float y, float z);
+
+    public abstract void translate(float x, float y);
+
+    public abstract void scale(float sx, float sy, float sz);
+
+    public abstract void rotate(float angle, float x, float y, float z);
+
+    public abstract void multiplyMatrix(float[] mMatrix, int offset);
+
+    // Pushes the configuration state (matrix, and alpha) onto
+    // a private stack.
+    public abstract void save();
+
+    // Same as save(), but only save those specified in saveFlags.
+    public abstract void save(int saveFlags);
+
+    public static final int SAVE_FLAG_ALL = 0xFFFFFFFF;
+    public static final int SAVE_FLAG_ALPHA = 0x01;
+    public static final int SAVE_FLAG_MATRIX = 0x02;
+
+    // Pops from the top of the stack as current configuration state (matrix,
+    // alpha, and clip). This call balances a previous call to save(), and is
+    // used to remove all modifications to the configuration state since the
+    // last save call.
+    public abstract void restore();
+
+    // Draws a line using the specified paint from (x1, y1) to (x2, y2).
+    // (Both end points are included).
+    public abstract void drawLine(float x1, float y1, float x2, float y2, GLPaint paint);
+
+    // Draws a rectangle using the specified paint from (x1, y1) to (x2, y2).
+    // (Both end points are included).
+    public abstract void drawRect(float x1, float y1, float x2, float y2, GLPaint paint);
+
+    // Fills the specified rectangle with the specified color.
+    public abstract void fillRect(float x, float y, float width, float height, int color);
+
+    // Draws a texture to the specified rectangle.
+    public abstract void drawTexture(
+            BasicTexture texture, int x, int y, int width, int height);
+
+    public abstract void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
+            int uvBuffer, int indexBuffer, int indexCount);
+
+    // Draws the source rectangle part of the texture to the target rectangle.
+    public abstract void drawTexture(BasicTexture texture, RectF source, RectF target);
+
+    // Draw a texture with a specified texture transform.
+    public abstract void drawTexture(BasicTexture texture, float[] mTextureTransform,
+                int x, int y, int w, int h);
+
+    // Draw two textures to the specified rectangle. The actual texture used is
+    // from * (1 - ratio) + to * ratio
+    // The two textures must have the same size.
+    public abstract void drawMixed(BasicTexture from, int toColor,
+            float ratio, int x, int y, int w, int h);
+
+    // Draw a region of a texture and a specified color to the specified
+    // rectangle. The actual color used is from * (1 - ratio) + to * ratio.
+    // The region of the texture is defined by parameter "src". The target
+    // rectangle is specified by parameter "target".
+    public abstract void drawMixed(BasicTexture from, int toColor,
+            float ratio, RectF src, RectF target);
+
+    // Unloads the specified texture from the canvas. The resource allocated
+    // to draw the texture will be released. The specified texture will return
+    // to the unloaded state. This function should be called only from
+    // BasicTexture or its descendant
+    public abstract boolean unloadTexture(BasicTexture texture);
+
+    // Delete the specified buffer object, similar to unloadTexture.
+    public abstract void deleteBuffer(int bufferId);
+
+    // Delete the textures and buffers in GL side. This function should only be
+    // called in the GL thread.
+    public abstract void deleteRecycledResources();
+
+    // Dump statistics information and clear the counters. For debug only.
+    public abstract void dumpStatisticsAndClear();
+
+    public abstract void beginRenderTarget(RawTexture texture);
+
+    public abstract void endRenderTarget();
+
+    /**
+     * Sets texture parameters to use GL_CLAMP_TO_EDGE for both
+     * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T. Sets texture parameters to be
+     * GL_LINEAR for GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER.
+     * bindTexture() must be called prior to this.
+     *
+     * @param texture The texture to set parameters on.
+     */
+    public abstract void setTextureParameters(BasicTexture texture);
+
+    /**
+     * Initializes the texture to a size by calling texImage2D on it.
+     *
+     * @param texture The texture to initialize the size.
+     * @param format The texture format (e.g. GL_RGBA)
+     * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
+     */
+    public abstract void initializeTextureSize(BasicTexture texture, int format, int type);
+
+    /**
+     * Initializes the texture to a size by calling texImage2D on it.
+     *
+     * @param texture The texture to initialize the size.
+     * @param bitmap The bitmap to initialize the bitmap with.
+     */
+    public abstract void initializeTexture(BasicTexture texture, Bitmap bitmap);
+
+    /**
+     * Calls glTexSubImage2D to upload a bitmap to the texture.
+     *
+     * @param texture The target texture to write to.
+     * @param xOffset Specifies a texel offset in the x direction within the
+     *            texture array.
+     * @param yOffset Specifies a texel offset in the y direction within the
+     *            texture array.
+     * @param format The texture format (e.g. GL_RGBA)
+     * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
+     */
+    public abstract void texSubImage2D(BasicTexture texture, int xOffset, int yOffset,
+            Bitmap bitmap,
+            int format, int type);
+
+    /**
+     * Generates buffers and uploads the buffer data.
+     *
+     * @param buffer The buffer to upload
+     * @return The buffer ID that was generated.
+     */
+    public abstract int uploadBuffer(java.nio.FloatBuffer buffer);
+
+    /**
+     * Generates buffers and uploads the element array buffer data.
+     *
+     * @param buffer The buffer to upload
+     * @return The buffer ID that was generated.
+     */
+    public abstract int uploadBuffer(java.nio.ByteBuffer buffer);
+
+    /**
+     * After LightCycle makes GL calls, this method is called to restore the GL
+     * configuration to the one expected by GLCanvas.
+     */
+    public abstract void recoverFromLightCycle();
+
+    /**
+     * Gets the bounds given by x, y, width, and height as well as the internal
+     * matrix state. There is no special handling for non-90-degree rotations.
+     * It only considers the lower-left and upper-right corners as the bounds.
+     *
+     * @param bounds The output bounds to write to.
+     * @param x The left side of the input rectangle.
+     * @param y The bottom of the input rectangle.
+     * @param width The width of the input rectangle.
+     * @param height The height of the input rectangle.
+     */
+    public abstract void getBounds(Rect bounds, int x, int y, int width, int height);
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
new file mode 100644
index 0000000..4ead131
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.opengl.Matrix;
+import android.util.Log;
+
+import com.android.gallery3d.util.IntArray;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class GLES20Canvas implements GLCanvas {
+    // ************** Constants **********************
+    private static final String TAG = GLES20Canvas.class.getSimpleName();
+    private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
+    private static final float OPAQUE_ALPHA = 0.95f;
+
+    private static final int COORDS_PER_VERTEX = 2;
+    private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE;
+
+    private static final int COUNT_FILL_VERTEX = 4;
+    private static final int COUNT_LINE_VERTEX = 2;
+    private static final int COUNT_RECT_VERTEX = 4;
+    private static final int OFFSET_FILL_RECT = 0;
+    private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX;
+    private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX;
+
+    private static final float[] BOX_COORDINATES = {
+            0, 0, // Fill rectangle
+            1, 0,
+            0, 1,
+            1, 1,
+            0, 0, // Draw line
+            1, 1,
+            0, 0, // Draw rectangle outline
+            0, 1,
+            1, 1,
+            1, 0,
+    };
+
+    private static final float[] BOUNDS_COORDINATES = {
+        0, 0, 0, 1,
+        1, 1, 0, 1,
+    };
+
+    private static final String POSITION_ATTRIBUTE = "aPosition";
+    private static final String COLOR_UNIFORM = "uColor";
+    private static final String MATRIX_UNIFORM = "uMatrix";
+    private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix";
+    private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler";
+    private static final String ALPHA_UNIFORM = "uAlpha";
+    private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate";
+
+    private static final String DRAW_VERTEX_SHADER = ""
+            + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+            + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+            + "void main() {\n"
+            + "  vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+            + "  gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+            + "}\n";
+
+    private static final String DRAW_FRAGMENT_SHADER = ""
+            + "precision mediump float;\n"
+            + "uniform vec4 " + COLOR_UNIFORM + ";\n"
+            + "void main() {\n"
+            + "  gl_FragColor = " + COLOR_UNIFORM + ";\n"
+            + "}\n";
+
+    private static final String TEXTURE_VERTEX_SHADER = ""
+            + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+            + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n"
+            + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+            + "varying vec2 vTextureCoord;\n"
+            + "void main() {\n"
+            + "  vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+            + "  gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+            + "  vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n"
+            + "}\n";
+
+    private static final String MESH_VERTEX_SHADER = ""
+            + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+            + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+            + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n"
+            + "varying vec2 vTextureCoord;\n"
+            + "void main() {\n"
+            + "  vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+            + "  gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+            + "  vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n"
+            + "}\n";
+
+    private static final String TEXTURE_FRAGMENT_SHADER = ""
+            + "precision mediump float;\n"
+            + "varying vec2 vTextureCoord;\n"
+            + "uniform float " + ALPHA_UNIFORM + ";\n"
+            + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n"
+            + "void main() {\n"
+            + "  gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
+            + "  gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+            + "}\n";
+
+    private static final String OES_TEXTURE_FRAGMENT_SHADER = ""
+            + "#extension GL_OES_EGL_image_external : require\n"
+            + "precision mediump float;\n"
+            + "varying vec2 vTextureCoord;\n"
+            + "uniform float " + ALPHA_UNIFORM + ";\n"
+            + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n"
+            + "void main() {\n"
+            + "  gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
+            + "  gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+            + "}\n";
+
+    private static final int INITIAL_RESTORE_STATE_SIZE = 8;
+    private static final int MATRIX_SIZE = 16;
+
+    // Keep track of restore state
+    private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE];
+    private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE];
+    private IntArray mSaveFlags = new IntArray();
+
+    private int mCurrentAlphaIndex = 0;
+    private int mCurrentMatrixIndex = 0;
+
+    // Viewport size
+    private int mWidth;
+    private int mHeight;
+
+    // Projection matrix
+    private float[] mProjectionMatrix = new float[MATRIX_SIZE];
+
+    // Screen size for when we aren't bound to a texture
+    private int mScreenWidth;
+    private int mScreenHeight;
+
+    // GL programs
+    private int mDrawProgram;
+    private int mTextureProgram;
+    private int mOesTextureProgram;
+    private int mMeshProgram;
+
+    // GL buffer containing BOX_COORDINATES
+    private int mBoxCoordinates;
+
+    // Handle indices -- common
+    private static final int INDEX_POSITION = 0;
+    private static final int INDEX_MATRIX = 1;
+
+    // Handle indices -- draw
+    private static final int INDEX_COLOR = 2;
+
+    // Handle indices -- texture
+    private static final int INDEX_TEXTURE_MATRIX = 2;
+    private static final int INDEX_TEXTURE_SAMPLER = 3;
+    private static final int INDEX_ALPHA = 4;
+
+    // Handle indices -- mesh
+    private static final int INDEX_TEXTURE_COORD = 2;
+
+    private abstract static class ShaderParameter {
+        public int handle;
+        protected final String mName;
+
+        public ShaderParameter(String name) {
+            mName = name;
+        }
+
+        public abstract void loadHandle(int program);
+    }
+
+    private static class UniformShaderParameter extends ShaderParameter {
+        public UniformShaderParameter(String name) {
+            super(name);
+        }
+
+        @Override
+        public void loadHandle(int program) {
+            handle = GLES20.glGetUniformLocation(program, mName);
+            checkError();
+        }
+    }
+
+    private static class AttributeShaderParameter extends ShaderParameter {
+        public AttributeShaderParameter(String name) {
+            super(name);
+        }
+
+        @Override
+        public void loadHandle(int program) {
+            handle = GLES20.glGetAttribLocation(program, mName);
+            checkError();
+        }
+    }
+
+    ShaderParameter[] mDrawParameters = {
+            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+            new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR
+    };
+    ShaderParameter[] mTextureParameters = {
+            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+            new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
+            new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+            new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+    };
+    ShaderParameter[] mOesTextureParameters = {
+            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+            new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
+            new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+            new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+    };
+    ShaderParameter[] mMeshParameters = {
+            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+            new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD
+            new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+            new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+    };
+
+    private final IntArray mUnboundTextures = new IntArray();
+    private final IntArray mDeleteBuffers = new IntArray();
+
+    // Keep track of statistics for debugging
+    private int mCountDrawMesh = 0;
+    private int mCountTextureRect = 0;
+    private int mCountFillRect = 0;
+    private int mCountDrawLine = 0;
+
+    // Buffer for framebuffer IDs -- we keep track so we can switch the attached
+    // texture.
+    private int[] mFrameBuffer = new int[1];
+
+    // Bound textures.
+    private ArrayList<RawTexture> mTargetTextures = new ArrayList<RawTexture>();
+
+    // Temporary variables used within calculations
+    private final float[] mTempMatrix = new float[32];
+    private final float[] mTempColor = new float[4];
+    private final RectF mTempSourceRect = new RectF();
+    private final RectF mTempTargetRect = new RectF();
+    private final float[] mTempTextureMatrix = new float[MATRIX_SIZE];
+    private final int[] mTempIntArray = new int[1];
+
+    private static final GLId mGLId = new GLES20IdImpl();
+
+    public GLES20Canvas() {
+        Matrix.setIdentityM(mTempTextureMatrix, 0);
+        Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
+        mAlphas[mCurrentAlphaIndex] = 1f;
+        mTargetTextures.add(null);
+
+        FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES);
+        mBoxCoordinates = uploadBuffer(boxBuffer);
+
+        int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER);
+        int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER);
+        int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER);
+        int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER);
+        int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER);
+        int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
+                OES_TEXTURE_FRAGMENT_SHADER);
+
+        mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters);
+        mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader,
+                mTextureParameters);
+        mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader,
+                mOesTextureParameters);
+        mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters);
+        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+        checkError();
+    }
+
+    private static FloatBuffer createBuffer(float[] values) {
+        // First create an nio buffer, then create a VBO from it.
+        int size = values.length * FLOAT_SIZE;
+        FloatBuffer buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder())
+                .asFloatBuffer();
+        buffer.put(values, 0, values.length).position(0);
+        return buffer;
+    }
+
+    private int assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params) {
+        int program = GLES20.glCreateProgram();
+        checkError();
+        if (program == 0) {
+            throw new RuntimeException("Cannot create GL program: " + GLES20.glGetError());
+        }
+        GLES20.glAttachShader(program, vertexShader);
+        checkError();
+        GLES20.glAttachShader(program, fragmentShader);
+        checkError();
+        GLES20.glLinkProgram(program);
+        checkError();
+        int[] mLinkStatus = mTempIntArray;
+        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, mLinkStatus, 0);
+        if (mLinkStatus[0] != GLES20.GL_TRUE) {
+            Log.e(TAG, "Could not link program: ");
+            Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+            GLES20.glDeleteProgram(program);
+            program = 0;
+        }
+        for (int i = 0; i < params.length; i++) {
+            params[i].loadHandle(program);
+        }
+        return program;
+    }
+
+    private static int loadShader(int type, String shaderCode) {
+        // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
+        // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
+        int shader = GLES20.glCreateShader(type);
+
+        // add the source code to the shader and compile it
+        GLES20.glShaderSource(shader, shaderCode);
+        checkError();
+        GLES20.glCompileShader(shader);
+        checkError();
+
+        return shader;
+    }
+
+    @Override
+    public void setSize(int width, int height) {
+        mWidth = width;
+        mHeight = height;
+        GLES20.glViewport(0, 0, mWidth, mHeight);
+        checkError();
+        Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
+        Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1);
+        if (getTargetTexture() == null) {
+            mScreenWidth = width;
+            mScreenHeight = height;
+            Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0);
+            Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1);
+        }
+    }
+
+    @Override
+    public void clearBuffer() {
+        GLES20.glClearColor(0f, 0f, 0f, 1f);
+        checkError();
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        checkError();
+    }
+
+    @Override
+    public void clearBuffer(float[] argb) {
+        GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]);
+        checkError();
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        checkError();
+    }
+
+    @Override
+    public float getAlpha() {
+        return mAlphas[mCurrentAlphaIndex];
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        mAlphas[mCurrentAlphaIndex] = alpha;
+    }
+
+    @Override
+    public void multiplyAlpha(float alpha) {
+        setAlpha(getAlpha() * alpha);
+    }
+
+    @Override
+    public void translate(float x, float y, float z) {
+        Matrix.translateM(mMatrices, mCurrentMatrixIndex, x, y, z);
+    }
+
+    // This is a faster version of translate(x, y, z) because
+    // (1) we knows z = 0, (2) we inline the Matrix.translateM call,
+    // (3) we unroll the loop
+    @Override
+    public void translate(float x, float y) {
+        int index = mCurrentMatrixIndex;
+        float[] m = mMatrices;
+        m[index + 12] += m[index + 0] * x + m[index + 4] * y;
+        m[index + 13] += m[index + 1] * x + m[index + 5] * y;
+        m[index + 14] += m[index + 2] * x + m[index + 6] * y;
+        m[index + 15] += m[index + 3] * x + m[index + 7] * y;
+    }
+
+    @Override
+    public void scale(float sx, float sy, float sz) {
+        Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz);
+    }
+
+    @Override
+    public void rotate(float angle, float x, float y, float z) {
+        if (angle == 0f) {
+            return;
+        }
+        float[] temp = mTempMatrix;
+        Matrix.setRotateM(temp, 0, angle, x, y, z);
+        float[] matrix = mMatrices;
+        int index = mCurrentMatrixIndex;
+        Matrix.multiplyMM(temp, MATRIX_SIZE, matrix, index, temp, 0);
+        System.arraycopy(temp, MATRIX_SIZE, matrix, index, MATRIX_SIZE);
+    }
+
+    @Override
+    public void multiplyMatrix(float[] matrix, int offset) {
+        float[] temp = mTempMatrix;
+        float[] currentMatrix = mMatrices;
+        int index = mCurrentMatrixIndex;
+        Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset);
+        System.arraycopy(temp, 0, currentMatrix, index, 16);
+    }
+
+    @Override
+    public void save() {
+        save(SAVE_FLAG_ALL);
+    }
+
+    @Override
+    public void save(int saveFlags) {
+        boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
+        if (saveAlpha) {
+            float currentAlpha = getAlpha();
+            mCurrentAlphaIndex++;
+            if (mAlphas.length <= mCurrentAlphaIndex) {
+                mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2);
+            }
+            mAlphas[mCurrentAlphaIndex] = currentAlpha;
+        }
+        boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
+        if (saveMatrix) {
+            int currentIndex = mCurrentMatrixIndex;
+            mCurrentMatrixIndex += MATRIX_SIZE;
+            if (mMatrices.length <= mCurrentMatrixIndex) {
+                mMatrices = Arrays.copyOf(mMatrices, mMatrices.length * 2);
+            }
+            System.arraycopy(mMatrices, currentIndex, mMatrices, mCurrentMatrixIndex, MATRIX_SIZE);
+        }
+        mSaveFlags.add(saveFlags);
+    }
+
+    @Override
+    public void restore() {
+        int restoreFlags = mSaveFlags.removeLast();
+        boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
+        if (restoreAlpha) {
+            mCurrentAlphaIndex--;
+        }
+        boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
+        if (restoreMatrix) {
+            mCurrentMatrixIndex -= MATRIX_SIZE;
+        }
+    }
+
+    @Override
+    public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
+        draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1,
+                paint);
+        mCountDrawLine++;
+    }
+
+    @Override
+    public void drawRect(float x, float y, float width, float height, GLPaint paint) {
+        draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint);
+        mCountDrawLine++;
+    }
+
+    private void draw(int type, int offset, int count, float x, float y, float width, float height,
+            GLPaint paint) {
+        draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth());
+    }
+
+    private void draw(int type, int offset, int count, float x, float y, float width, float height,
+            int color, float lineWidth) {
+        prepareDraw(offset, color, lineWidth);
+        draw(mDrawParameters, type, count, x, y, width, height);
+    }
+
+    private void prepareDraw(int offset, int color, float lineWidth) {
+        GLES20.glUseProgram(mDrawProgram);
+        checkError();
+        if (lineWidth > 0) {
+            GLES20.glLineWidth(lineWidth);
+            checkError();
+        }
+        float[] colorArray = getColor(color);
+        boolean blendingEnabled = (colorArray[3] < 1f);
+        enableBlending(blendingEnabled);
+        if (blendingEnabled) {
+            GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]);
+            checkError();
+        }
+
+        GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0);
+        setPosition(mDrawParameters, offset);
+        checkError();
+    }
+
+    private float[] getColor(int color) {
+        float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha();
+        float red = ((color >>> 16) & 0xFF) / 255f * alpha;
+        float green = ((color >>> 8) & 0xFF) / 255f * alpha;
+        float blue = (color & 0xFF) / 255f * alpha;
+        mTempColor[0] = red;
+        mTempColor[1] = green;
+        mTempColor[2] = blue;
+        mTempColor[3] = alpha;
+        return mTempColor;
+    }
+
+    private void enableBlending(boolean enableBlending) {
+        if (enableBlending) {
+            GLES20.glEnable(GLES20.GL_BLEND);
+            checkError();
+        } else {
+            GLES20.glDisable(GLES20.GL_BLEND);
+            checkError();
+        }
+    }
+
+    private void setPosition(ShaderParameter[] params, int offset) {
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates);
+        checkError();
+        GLES20.glVertexAttribPointer(params[INDEX_POSITION].handle, COORDS_PER_VERTEX,
+                GLES20.GL_FLOAT, false, VERTEX_STRIDE, offset * VERTEX_STRIDE);
+        checkError();
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+        checkError();
+    }
+
+    private void draw(ShaderParameter[] params, int type, int count, float x, float y, float width,
+            float height) {
+        setMatrix(params, x, y, width, height);
+        int positionHandle = params[INDEX_POSITION].handle;
+        GLES20.glEnableVertexAttribArray(positionHandle);
+        checkError();
+        GLES20.glDrawArrays(type, 0, count);
+        checkError();
+        GLES20.glDisableVertexAttribArray(positionHandle);
+        checkError();
+    }
+
+    private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height) {
+        Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
+        Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
+        Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0);
+        GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, mTempMatrix, MATRIX_SIZE);
+        checkError();
+    }
+
+    @Override
+    public void fillRect(float x, float y, float width, float height, int color) {
+        draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height,
+                color, 0f);
+        mCountFillRect++;
+    }
+
+    @Override
+    public void drawTexture(BasicTexture texture, int x, int y, int width, int height) {
+        if (width <= 0 || height <= 0) {
+            return;
+        }
+        copyTextureCoordinates(texture, mTempSourceRect);
+        mTempTargetRect.set(x, y, x + width, y + height);
+        convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
+        drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
+    }
+
+    private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) {
+        int left = 0;
+        int top = 0;
+        int right = texture.getWidth();
+        int bottom = texture.getHeight();
+        if (texture.hasBorder()) {
+            left = 1;
+            top = 1;
+            right -= 1;
+            bottom -= 1;
+        }
+        outRect.set(left, top, right, bottom);
+    }
+
+    @Override
+    public void drawTexture(BasicTexture texture, RectF source, RectF target) {
+        if (target.width() <= 0 || target.height() <= 0) {
+            return;
+        }
+        mTempSourceRect.set(source);
+        mTempTargetRect.set(target);
+
+        convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
+        drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
+    }
+
+    @Override
+    public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w,
+            int h) {
+        if (w <= 0 || h <= 0) {
+            return;
+        }
+        mTempTargetRect.set(x, y, x + w, y + h);
+        drawTextureRect(texture, textureTransform, mTempTargetRect);
+    }
+
+    private void drawTextureRect(BasicTexture texture, RectF source, RectF target) {
+        setTextureMatrix(source);
+        drawTextureRect(texture, mTempTextureMatrix, target);
+    }
+
+    private void setTextureMatrix(RectF source) {
+        mTempTextureMatrix[0] = source.width();
+        mTempTextureMatrix[5] = source.height();
+        mTempTextureMatrix[12] = source.left;
+        mTempTextureMatrix[13] = source.top;
+    }
+
+    // This function changes the source coordinate to the texture coordinates.
+    // It also clips the source and target coordinates if it is beyond the
+    // bound of the texture.
+    private static void convertCoordinate(RectF source, RectF target, BasicTexture texture) {
+        int width = texture.getWidth();
+        int height = texture.getHeight();
+        int texWidth = texture.getTextureWidth();
+        int texHeight = texture.getTextureHeight();
+        // Convert to texture coordinates
+        source.left /= texWidth;
+        source.right /= texWidth;
+        source.top /= texHeight;
+        source.bottom /= texHeight;
+
+        // Clip if the rendering range is beyond the bound of the texture.
+        float xBound = (float) width / texWidth;
+        if (source.right > xBound) {
+            target.right = target.left + target.width() * (xBound - source.left) / source.width();
+            source.right = xBound;
+        }
+        float yBound = (float) height / texHeight;
+        if (source.bottom > yBound) {
+            target.bottom = target.top + target.height() * (yBound - source.top) / source.height();
+            source.bottom = yBound;
+        }
+    }
+
+    private void drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target) {
+        ShaderParameter[] params = prepareTexture(texture);
+        setPosition(params, OFFSET_FILL_RECT);
+        GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0);
+        checkError();
+        if (texture.isFlippedVertically()) {
+            save(SAVE_FLAG_MATRIX);
+            translate(0, target.centerY());
+            scale(1, -1, 1);
+            translate(0, -target.centerY());
+        }
+        draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top,
+                target.width(), target.height());
+        if (texture.isFlippedVertically()) {
+            restore();
+        }
+        mCountTextureRect++;
+    }
+
+    private ShaderParameter[] prepareTexture(BasicTexture texture) {
+        ShaderParameter[] params;
+        int program;
+        if (texture.getTarget() == GLES20.GL_TEXTURE_2D) {
+            params = mTextureParameters;
+            program = mTextureProgram;
+        } else {
+            params = mOesTextureParameters;
+            program = mOesTextureProgram;
+        }
+        prepareTexture(texture, program, params);
+        return params;
+    }
+
+    private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) {
+        GLES20.glUseProgram(program);
+        checkError();
+        enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        checkError();
+        texture.onBind(this);
+        GLES20.glBindTexture(texture.getTarget(), texture.getId());
+        checkError();
+        GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0);
+        checkError();
+        GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha());
+        checkError();
+    }
+
+    @Override
+    public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer,
+            int indexBuffer, int indexCount) {
+        prepareTexture(texture, mMeshProgram, mMeshParameters);
+
+        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
+        checkError();
+
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer);
+        checkError();
+        int positionHandle = mMeshParameters[INDEX_POSITION].handle;
+        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
+                VERTEX_STRIDE, 0);
+        checkError();
+
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer);
+        checkError();
+        int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle;
+        GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
+                false, VERTEX_STRIDE, 0);
+        checkError();
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+        checkError();
+
+        GLES20.glEnableVertexAttribArray(positionHandle);
+        checkError();
+        GLES20.glEnableVertexAttribArray(texCoordHandle);
+        checkError();
+
+        setMatrix(mMeshParameters, x, y, 1, 1);
+        GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0);
+        checkError();
+
+        GLES20.glDisableVertexAttribArray(positionHandle);
+        checkError();
+        GLES20.glDisableVertexAttribArray(texCoordHandle);
+        checkError();
+        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
+        checkError();
+        mCountDrawMesh++;
+    }
+
+    @Override
+    public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) {
+        copyTextureCoordinates(texture, mTempSourceRect);
+        mTempTargetRect.set(x, y, x + w, y + h);
+        drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect);
+    }
+
+    @Override
+    public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) {
+        if (target.width() <= 0 || target.height() <= 0) {
+            return;
+        }
+        save(SAVE_FLAG_ALPHA);
+
+        float currentAlpha = getAlpha();
+        float cappedRatio = Math.min(1f, Math.max(0f, ratio));
+
+        float textureAlpha = (1f - cappedRatio) * currentAlpha;
+        setAlpha(textureAlpha);
+        drawTexture(texture, source, target);
+
+        float colorAlpha = cappedRatio * currentAlpha;
+        setAlpha(colorAlpha);
+        fillRect(target.left, target.top, target.width(), target.height(), toColor);
+
+        restore();
+    }
+
+    @Override
+    public boolean unloadTexture(BasicTexture texture) {
+        boolean unload = texture.isLoaded();
+        if (unload) {
+            synchronized (mUnboundTextures) {
+                mUnboundTextures.add(texture.getId());
+            }
+        }
+        return unload;
+    }
+
+    @Override
+    public void deleteBuffer(int bufferId) {
+        synchronized (mUnboundTextures) {
+            mDeleteBuffers.add(bufferId);
+        }
+    }
+
+    @Override
+    public void deleteRecycledResources() {
+        synchronized (mUnboundTextures) {
+            IntArray ids = mUnboundTextures;
+            if (mUnboundTextures.size() > 0) {
+                mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
+                ids.clear();
+            }
+
+            ids = mDeleteBuffers;
+            if (ids.size() > 0) {
+                mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
+                ids.clear();
+            }
+        }
+    }
+
+    @Override
+    public void dumpStatisticsAndClear() {
+        String line = String.format("MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh,
+                mCountTextureRect, mCountFillRect, mCountDrawLine);
+        mCountDrawMesh = 0;
+        mCountTextureRect = 0;
+        mCountFillRect = 0;
+        mCountDrawLine = 0;
+        Log.d(TAG, line);
+    }
+
+    @Override
+    public void endRenderTarget() {
+        RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1);
+        RawTexture texture = getTargetTexture();
+        setRenderTarget(oldTexture, texture);
+        restore(); // restore matrix and alpha
+    }
+
+    @Override
+    public void beginRenderTarget(RawTexture texture) {
+        save(); // save matrix and alpha and blending
+        RawTexture oldTexture = getTargetTexture();
+        mTargetTextures.add(texture);
+        setRenderTarget(oldTexture, texture);
+    }
+
+    private RawTexture getTargetTexture() {
+        return mTargetTextures.get(mTargetTextures.size() - 1);
+    }
+
+    private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) {
+        if (oldTexture == null && texture != null) {
+            GLES20.glGenFramebuffers(1, mFrameBuffer, 0);
+            checkError();
+            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]);
+            checkError();
+        } else if (oldTexture != null && texture == null) {
+            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+            checkError();
+            GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0);
+            checkError();
+        }
+
+        if (texture == null) {
+            setSize(mScreenWidth, mScreenHeight);
+        } else {
+            setSize(texture.getWidth(), texture.getHeight());
+
+            if (!texture.isLoaded()) {
+                texture.prepare(this);
+            }
+
+            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
+                    texture.getTarget(), texture.getId(), 0);
+            checkError();
+
+            checkFramebufferStatus();
+        }
+    }
+
+    private static void checkFramebufferStatus() {
+        int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
+        if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
+            String msg = "";
+            switch (status) {
+                case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+                    msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+                    break;
+                case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+                    msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+                    break;
+                case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+                    msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+                    break;
+                case GLES20.GL_FRAMEBUFFER_UNSUPPORTED:
+                    msg = "GL_FRAMEBUFFER_UNSUPPORTED";
+                    break;
+            }
+            throw new RuntimeException(msg + ":" + Integer.toHexString(status));
+        }
+    }
+
+    @Override
+    public void setTextureParameters(BasicTexture texture) {
+        int target = texture.getTarget();
+        GLES20.glBindTexture(target, texture.getId());
+        checkError();
+        GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+    }
+
+    @Override
+    public void initializeTextureSize(BasicTexture texture, int format, int type) {
+        int target = texture.getTarget();
+        GLES20.glBindTexture(target, texture.getId());
+        checkError();
+        int width = texture.getTextureWidth();
+        int height = texture.getTextureHeight();
+        GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
+    }
+
+    @Override
+    public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
+        int target = texture.getTarget();
+        GLES20.glBindTexture(target, texture.getId());
+        checkError();
+        GLUtils.texImage2D(target, 0, bitmap, 0);
+    }
+
+    @Override
+    public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
+            int format, int type) {
+        int target = texture.getTarget();
+        GLES20.glBindTexture(target, texture.getId());
+        checkError();
+        GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
+    }
+
+    @Override
+    public int uploadBuffer(FloatBuffer buf) {
+        return uploadBuffer(buf, FLOAT_SIZE);
+    }
+
+    @Override
+    public int uploadBuffer(ByteBuffer buf) {
+        return uploadBuffer(buf, 1);
+    }
+
+    private int uploadBuffer(Buffer buffer, int elementSize) {
+        mGLId.glGenBuffers(1, mTempIntArray, 0);
+        checkError();
+        int bufferId = mTempIntArray[0];
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId);
+        checkError();
+        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * elementSize, buffer,
+                GLES20.GL_STATIC_DRAW);
+        checkError();
+        return bufferId;
+    }
+
+    public static void checkError() {
+        int error = GLES20.glGetError();
+        if (error != 0) {
+            Throwable t = new Throwable();
+            Log.e(TAG, "GL error: " + error, t);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static void printMatrix(String message, float[] m, int offset) {
+        StringBuilder b = new StringBuilder(message);
+        for (int i = 0; i < MATRIX_SIZE; i++) {
+            b.append(' ');
+            if (i % 4 == 0) {
+                b.append('\n');
+            }
+            b.append(m[offset + i]);
+        }
+        Log.v(TAG, b.toString());
+    }
+
+    @Override
+    public void recoverFromLightCycle() {
+        GLES20.glViewport(0, 0, mWidth, mHeight);
+        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+        checkError();
+    }
+
+    @Override
+    public void getBounds(Rect bounds, int x, int y, int width, int height) {
+        Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
+        Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
+        Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0);
+        Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4);
+        bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]);
+        bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]);
+        bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]);
+        bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]);
+        bounds.sort();
+    }
+
+    @Override
+    public GLId getGLId() {
+        return mGLId;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
new file mode 100644
index 0000000..6cd7149
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
@@ -0,0 +1,42 @@
+package com.android.gallery3d.glrenderer;
+
+import android.opengl.GLES20;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+public class GLES20IdImpl implements GLId {
+    private final int[] mTempIntArray = new int[1];
+
+    @Override
+    public int generateTexture() {
+        GLES20.glGenTextures(1, mTempIntArray, 0);
+        GLES20Canvas.checkError();
+        return mTempIntArray[0];
+    }
+
+    @Override
+    public void glGenBuffers(int n, int[] buffers, int offset) {
+        GLES20.glGenBuffers(n, buffers, offset);
+        GLES20Canvas.checkError();
+    }
+
+    @Override
+    public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) {
+        GLES20.glDeleteTextures(n, textures, offset);
+        GLES20Canvas.checkError();
+    }
+
+
+    @Override
+    public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) {
+        GLES20.glDeleteBuffers(n, buffers, offset);
+        GLES20Canvas.checkError();
+    }
+
+    @Override
+    public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) {
+        GLES20.glDeleteFramebuffers(n, buffers, offset);
+        GLES20Canvas.checkError();
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java
new file mode 100644
index 0000000..3cec558
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+// This mimics corresponding GL functions.
+public interface GLId {
+    public int generateTexture();
+
+    public void glGenBuffers(int n, int[] buffers, int offset);
+
+    public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset);
+
+    public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset);
+
+    public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset);
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
new file mode 100644
index 0000000..16b2206
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import junit.framework.Assert;
+
+public class GLPaint {
+    private float mLineWidth = 1f;
+    private int mColor = 0;
+
+    public void setColor(int color) {
+        mColor = color;
+    }
+
+    public int getColor() {
+        return mColor;
+    }
+
+    public void setLineWidth(float width) {
+        Assert.assertTrue(width >= 0);
+        mLineWidth = width;
+    }
+
+    public float getLineWidth() {
+        return mLineWidth;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java
new file mode 100644
index 0000000..93f0fdf
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.util.Log;
+
+import javax.microedition.khronos.opengles.GL11;
+
+public class RawTexture extends BasicTexture {
+    private static final String TAG = "RawTexture";
+
+    private final boolean mOpaque;
+    private boolean mIsFlipped;
+
+    public RawTexture(int width, int height, boolean opaque) {
+        mOpaque = opaque;
+        setSize(width, height);
+    }
+
+    @Override
+    public boolean isOpaque() {
+        return mOpaque;
+    }
+
+    @Override
+    public boolean isFlippedVertically() {
+        return mIsFlipped;
+    }
+
+    public void setIsFlippedVertically(boolean isFlipped) {
+        mIsFlipped = isFlipped;
+    }
+
+    protected void prepare(GLCanvas canvas) {
+        GLId glId = canvas.getGLId();
+        mId = glId.generateTexture();
+        canvas.initializeTextureSize(this, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
+        canvas.setTextureParameters(this);
+        mState = STATE_LOADED;
+        setAssociatedCanvas(canvas);
+    }
+
+    @Override
+    protected boolean onBind(GLCanvas canvas) {
+        if (isLoaded()) return true;
+        Log.w(TAG, "lost the content due to context change");
+        return false;
+    }
+
+    @Override
+     public void yield() {
+         // we cannot free the texture because we have no backup.
+     }
+
+    @Override
+    protected int getTarget() {
+        return GL11.GL_TEXTURE_2D;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java
new file mode 100644
index 0000000..3dcae4a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+
+// Texture is a rectangular image which can be drawn on GLCanvas.
+// The isOpaque() function gives a hint about whether the texture is opaque,
+// so the drawing can be done faster.
+//
+// This is the current texture hierarchy:
+//
+// Texture
+// -- ColorTexture
+// -- FadeInTexture
+// -- BasicTexture
+//    -- UploadedTexture
+//       -- BitmapTexture
+//       -- Tile
+//       -- ResourceTexture
+//          -- NinePatchTexture
+//       -- CanvasTexture
+//          -- StringTexture
+//
+public interface Texture {
+    public int getWidth();
+    public int getHeight();
+    public void draw(GLCanvas canvas, int x, int y);
+    public void draw(GLCanvas canvas, int x, int y, int w, int h);
+    public boolean isOpaque();
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
new file mode 100644
index 0000000..f41a979
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.opengl.GLUtils;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+
+import javax.microedition.khronos.opengles.GL11;
+
+// UploadedTextures use a Bitmap for the content of the texture.
+//
+// Subclasses should implement onGetBitmap() to provide the Bitmap and
+// implement onFreeBitmap(mBitmap) which will be called when the Bitmap
+// is not needed anymore.
+//
+// isContentValid() is meaningful only when the isLoaded() returns true.
+// It means whether the content needs to be updated.
+//
+// The user of this class should call recycle() when the texture is not
+// needed anymore.
+//
+// By default an UploadedTexture is opaque (so it can be drawn faster without
+// blending). The user or subclass can override it using setOpaque().
+public abstract class UploadedTexture extends BasicTexture {
+
+    // To prevent keeping allocation the borders, we store those used borders here.
+    // Since the length will be power of two, it won't use too much memory.
+    private static HashMap<BorderKey, Bitmap> sBorderLines =
+            new HashMap<BorderKey, Bitmap>();
+    private static BorderKey sBorderKey = new BorderKey();
+
+    @SuppressWarnings("unused")
+    private static final String TAG = "Texture";
+    private boolean mContentValid = true;
+
+    // indicate this textures is being uploaded in background
+    private boolean mIsUploading = false;
+    private boolean mOpaque = true;
+    private boolean mThrottled = false;
+    private static int sUploadedCount;
+    private static final int UPLOAD_LIMIT = 100;
+
+    protected Bitmap mBitmap;
+    private int mBorder;
+
+    protected UploadedTexture() {
+        this(false);
+    }
+
+    protected UploadedTexture(boolean hasBorder) {
+        super(null, 0, STATE_UNLOADED);
+        if (hasBorder) {
+            setBorder(true);
+            mBorder = 1;
+        }
+    }
+
+    protected void setIsUploading(boolean uploading) {
+        mIsUploading = uploading;
+    }
+
+    public boolean isUploading() {
+        return mIsUploading;
+    }
+
+    private static class BorderKey implements Cloneable {
+        public boolean vertical;
+        public Config config;
+        public int length;
+
+        @Override
+        public int hashCode() {
+            int x = config.hashCode() ^ length;
+            return vertical ? x : -x;
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            if (!(object instanceof BorderKey)) return false;
+            BorderKey o = (BorderKey) object;
+            return vertical == o.vertical
+                    && config == o.config && length == o.length;
+        }
+
+        @Override
+        public BorderKey clone() {
+            try {
+                return (BorderKey) super.clone();
+            } catch (CloneNotSupportedException e) {
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+    protected void setThrottled(boolean throttled) {
+        mThrottled = throttled;
+    }
+
+    private static Bitmap getBorderLine(
+            boolean vertical, Config config, int length) {
+        BorderKey key = sBorderKey;
+        key.vertical = vertical;
+        key.config = config;
+        key.length = length;
+        Bitmap bitmap = sBorderLines.get(key);
+        if (bitmap == null) {
+            bitmap = vertical
+                    ? Bitmap.createBitmap(1, length, config)
+                    : Bitmap.createBitmap(length, 1, config);
+            sBorderLines.put(key.clone(), bitmap);
+        }
+        return bitmap;
+    }
+
+    private Bitmap getBitmap() {
+        if (mBitmap == null) {
+            mBitmap = onGetBitmap();
+            int w = mBitmap.getWidth() + mBorder * 2;
+            int h = mBitmap.getHeight() + mBorder * 2;
+            if (mWidth == UNSPECIFIED) {
+                setSize(w, h);
+            }
+        }
+        return mBitmap;
+    }
+
+    private void freeBitmap() {
+        Assert.assertTrue(mBitmap != null);
+        onFreeBitmap(mBitmap);
+        mBitmap = null;
+    }
+
+    @Override
+    public int getWidth() {
+        if (mWidth == UNSPECIFIED) getBitmap();
+        return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+        if (mWidth == UNSPECIFIED) getBitmap();
+        return mHeight;
+    }
+
+    protected abstract Bitmap onGetBitmap();
+
+    protected abstract void onFreeBitmap(Bitmap bitmap);
+
+    protected void invalidateContent() {
+        if (mBitmap != null) freeBitmap();
+        mContentValid = false;
+        mWidth = UNSPECIFIED;
+        mHeight = UNSPECIFIED;
+    }
+
+    /**
+     * Whether the content on GPU is valid.
+     */
+    public boolean isContentValid() {
+        return isLoaded() && mContentValid;
+    }
+
+    /**
+     * Updates the content on GPU's memory.
+     * @param canvas
+     */
+    public void updateContent(GLCanvas canvas) {
+        if (!isLoaded()) {
+            if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
+                return;
+            }
+            uploadToCanvas(canvas);
+        } else if (!mContentValid) {
+            Bitmap bitmap = getBitmap();
+            int format = GLUtils.getInternalFormat(bitmap);
+            int type = GLUtils.getType(bitmap);
+            canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+            freeBitmap();
+            mContentValid = true;
+        }
+    }
+
+    public static void resetUploadLimit() {
+        sUploadedCount = 0;
+    }
+
+    public static boolean uploadLimitReached() {
+        return sUploadedCount > UPLOAD_LIMIT;
+    }
+
+    private void uploadToCanvas(GLCanvas canvas) {
+
+        Bitmap bitmap = getBitmap();
+        if (bitmap != null) {
+            try {
+                int bWidth = bitmap.getWidth();
+                int bHeight = bitmap.getHeight();
+                int width = bWidth + mBorder * 2;
+                int height = bHeight + mBorder * 2;
+                int texWidth = getTextureWidth();
+                int texHeight = getTextureHeight();
+
+                Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+
+                // Upload the bitmap to a new texture.
+                mId = canvas.getGLId().generateTexture();
+                canvas.setTextureParameters(this);
+
+                if (bWidth == texWidth && bHeight == texHeight) {
+                    canvas.initializeTexture(this, bitmap);
+                } else {
+                    int format = GLUtils.getInternalFormat(bitmap);
+                    int type = GLUtils.getType(bitmap);
+                    Config config = bitmap.getConfig();
+
+                    canvas.initializeTextureSize(this, format, type);
+                    canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+
+                    if (mBorder > 0) {
+                        // Left border
+                        Bitmap line = getBorderLine(true, config, texHeight);
+                        canvas.texSubImage2D(this, 0, 0, line, format, type);
+
+                        // Top border
+                        line = getBorderLine(false, config, texWidth);
+                        canvas.texSubImage2D(this, 0, 0, line, format, type);
+                    }
+
+                    // Right border
+                    if (mBorder + bWidth < texWidth) {
+                        Bitmap line = getBorderLine(true, config, texHeight);
+                        canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type);
+                    }
+
+                    // Bottom border
+                    if (mBorder + bHeight < texHeight) {
+                        Bitmap line = getBorderLine(false, config, texWidth);
+                        canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type);
+                    }
+                }
+            } finally {
+                freeBitmap();
+            }
+            // Update texture state.
+            setAssociatedCanvas(canvas);
+            mState = STATE_LOADED;
+            mContentValid = true;
+        } else {
+            mState = STATE_ERROR;
+            throw new RuntimeException("Texture load fail, no bitmap");
+        }
+    }
+
+    @Override
+    protected boolean onBind(GLCanvas canvas) {
+        updateContent(canvas);
+        return isContentValid();
+    }
+
+    @Override
+    protected int getTarget() {
+        return GL11.GL_TEXTURE_2D;
+    }
+
+    public void setOpaque(boolean isOpaque) {
+        mOpaque = isOpaque;
+    }
+
+    @Override
+    public boolean isOpaque() {
+        return mOpaque;
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        if (mBitmap != null) freeBitmap();
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java b/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java
new file mode 100644
index 0000000..2c4dc2c
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.util;
+
+public class IntArray {
+    private static final int INIT_CAPACITY = 8;
+
+    private int mData[] = new int[INIT_CAPACITY];
+    private int mSize = 0;
+
+    public void add(int value) {
+        if (mData.length == mSize) {
+            int temp[] = new int[mSize + mSize];
+            System.arraycopy(mData, 0, temp, 0, mSize);
+            mData = temp;
+        }
+        mData[mSize++] = value;
+    }
+
+    public int removeLast() {
+        mSize--;
+        return mData[mSize];
+    }
+
+    public int size() {
+        return mSize;
+    }
+
+    // For testing only
+    public int[] toArray(int[] result) {
+        if (result == null || result.length < mSize) {
+            result = new int[mSize];
+        }
+        System.arraycopy(mData, 0, result, 0, mSize);
+        return result;
+    }
+
+    public int[] getInternalArray() {
+        return mData;
+    }
+
+    public void clear() {
+        mSize = 0;
+        if (mData.length != INIT_CAPACITY) mData = new int[INIT_CAPACITY];
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
new file mode 100644
index 0000000..5f64018
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
@@ -0,0 +1,260 @@
+/*
+ * 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.photos;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.util.Log;
+
+import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.BitmapTexture;
+import com.android.photos.views.TiledImageRenderer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using
+ * {@link BitmapRegionDecoder} to wrap a local file
+ */
+@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
+
+    private static final String TAG = "BitmapRegionTileSource";
+
+    private static final boolean REUSE_BITMAP =
+            Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
+    private static final int GL_SIZE_LIMIT = 2048;
+    // This must be no larger than half the size of the GL_SIZE_LIMIT
+    // due to decodePreview being allowed to be up to 2x the size of the target
+    private static final int MAX_PREVIEW_SIZE = 1024;
+
+    BitmapRegionDecoder mDecoder;
+    int mWidth;
+    int mHeight;
+    int mTileSize;
+    private BasicTexture mPreview;
+    private final int mRotation;
+
+    // For use only by getTile
+    private Rect mWantRegion = new Rect();
+    private Rect mOverlapRegion = new Rect();
+    private BitmapFactory.Options mOptions;
+    private Canvas mCanvas;
+
+    public BitmapRegionTileSource(Context context, String path, int previewSize, int rotation) {
+        this(null, context, path, null, 0, previewSize, rotation);
+    }
+
+    public BitmapRegionTileSource(Context context, Uri uri, int previewSize, int rotation) {
+        this(null, context, null, uri, 0, previewSize, rotation);
+    }
+
+    public BitmapRegionTileSource(Resources res,
+            Context context, int resId, int previewSize, int rotation) {
+        this(res, context, null, null, resId, previewSize, rotation);
+    }
+
+    private BitmapRegionTileSource(Resources res,
+            Context context, String path, Uri uri, int resId, int previewSize, int rotation) {
+        mTileSize = TiledImageRenderer.suggestedTileSize(context);
+        mRotation = rotation;
+        try {
+            if (path != null) {
+                mDecoder = BitmapRegionDecoder.newInstance(path, true);
+            } else if (uri != null) {
+                InputStream is = context.getContentResolver().openInputStream(uri);
+                BufferedInputStream bis = new BufferedInputStream(is);
+                mDecoder = BitmapRegionDecoder.newInstance(bis, true);
+            } else {
+                InputStream is = res.openRawResource(resId);
+                BufferedInputStream bis = new BufferedInputStream(is);
+                mDecoder = BitmapRegionDecoder.newInstance(bis, true);
+            }
+            mWidth = mDecoder.getWidth();
+            mHeight = mDecoder.getHeight();
+        } catch (IOException e) {
+            Log.w("BitmapRegionTileSource", "ctor failed", e);
+        }
+        mOptions = new BitmapFactory.Options();
+        mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        mOptions.inPreferQualityOverSpeed = true;
+        mOptions.inTempStorage = new byte[16 * 1024];
+        if (previewSize != 0) {
+            previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE);
+            // Although this is the same size as the Bitmap that is likely already
+            // loaded, the lifecycle is different and interactions are on a different
+            // thread. Thus to simplify, this source will decode its own bitmap.
+            Bitmap preview = decodePreview(res, context, path, uri, resId, previewSize);
+            if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
+                mPreview = new BitmapTexture(preview);
+            } else {
+                Log.w(TAG, String.format(
+                        "Failed to create preview of apropriate size! "
+                        + " in: %dx%d, out: %dx%d",
+                        mWidth, mHeight,
+                        preview.getWidth(), preview.getHeight()));
+            }
+        }
+    }
+
+    @Override
+    public int getTileSize() {
+        return mTileSize;
+    }
+
+    @Override
+    public int getImageWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getImageHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public BasicTexture getPreview() {
+        return mPreview;
+    }
+
+    @Override
+    public int getRotation() {
+        return mRotation;
+    }
+
+    @Override
+    public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
+        int tileSize = getTileSize();
+        if (!REUSE_BITMAP) {
+            return getTileWithoutReusingBitmap(level, x, y, tileSize);
+        }
+
+        int t = tileSize << level;
+        mWantRegion.set(x, y, x + t, y + t);
+
+        if (bitmap == null) {
+            bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888);
+        }
+
+        mOptions.inSampleSize = (1 << level);
+        mOptions.inBitmap = bitmap;
+
+        try {
+            bitmap = mDecoder.decodeRegion(mWantRegion, mOptions);
+        } finally {
+            if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) {
+                mOptions.inBitmap = null;
+            }
+        }
+
+        if (bitmap == null) {
+            Log.w("BitmapRegionTileSource", "fail in decoding region");
+        }
+        return bitmap;
+    }
+
+    private Bitmap getTileWithoutReusingBitmap(
+            int level, int x, int y, int tileSize) {
+
+        int t = tileSize << level;
+        mWantRegion.set(x, y, x + t, y + t);
+
+        mOverlapRegion.set(0, 0, mWidth, mHeight);
+
+        mOptions.inSampleSize = (1 << level);
+        Bitmap bitmap = mDecoder.decodeRegion(mOverlapRegion, mOptions);
+
+        if (bitmap == null) {
+            Log.w(TAG, "fail in decoding region");
+        }
+
+        if (mWantRegion.equals(mOverlapRegion)) {
+            return bitmap;
+        }
+
+        Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
+        if (mCanvas == null) {
+            mCanvas = new Canvas();
+        }
+        mCanvas.setBitmap(result);
+        mCanvas.drawBitmap(bitmap,
+                (mOverlapRegion.left - mWantRegion.left) >> level,
+                (mOverlapRegion.top - mWantRegion.top) >> level, null);
+        mCanvas.setBitmap(null);
+        return result;
+    }
+
+    /**
+     * Note that the returned bitmap may have a long edge that's longer
+     * than the targetSize, but it will always be less than 2x the targetSize
+     */
+    private Bitmap decodePreview(
+            Resources res, Context context, String file, Uri uri, int resId, int targetSize) {
+        float scale = (float) targetSize / Math.max(mWidth, mHeight);
+        mOptions.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
+        mOptions.inJustDecodeBounds = false;
+
+        Bitmap result = null;
+        if (file != null) {
+            result = BitmapFactory.decodeFile(file, mOptions);
+        } else if (uri != null) {
+            try {
+                InputStream is = context.getContentResolver().openInputStream(uri);
+                BufferedInputStream bis = new BufferedInputStream(is);
+                result = BitmapFactory.decodeStream(bis, null, mOptions);
+            } catch (IOException e) {
+                Log.w("BitmapRegionTileSource", "getting preview failed", e);
+            }
+        } else {
+            result = BitmapFactory.decodeResource(res, resId, mOptions);
+        }
+        if (result == null) {
+            return null;
+        }
+
+        // We need to resize down if the decoder does not support inSampleSize
+        // or didn't support the specified inSampleSize (some decoders only do powers of 2)
+        scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight()));
+
+        if (scale <= 0.5) {
+            result = BitmapUtils.resizeBitmapByScale(result, scale, true);
+        }
+        return ensureGLCompatibleBitmap(result);
+    }
+
+    private static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
+        if (bitmap == null || bitmap.getConfig() != null) {
+            return bitmap;
+        }
+        Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
+        bitmap.recycle();
+        return newBitmap;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java b/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java
new file mode 100644
index 0000000..8a05051
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java
@@ -0,0 +1,438 @@
+/*
+ * 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.photos.views;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLSurfaceView.Renderer;
+import android.opengl.GLUtils;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A TextureView that supports blocking rendering for synchronous drawing
+ */
+public class BlockingGLTextureView extends TextureView
+        implements SurfaceTextureListener {
+
+    private RenderThread mRenderThread;
+
+    public BlockingGLTextureView(Context context) {
+        super(context);
+        setSurfaceTextureListener(this);
+    }
+
+    public void setRenderer(Renderer renderer) {
+        if (mRenderThread != null) {
+            throw new IllegalArgumentException("Renderer already set");
+        }
+        mRenderThread = new RenderThread(renderer);
+    }
+
+    public void render() {
+        mRenderThread.render();
+    }
+
+    public void destroy() {
+        if (mRenderThread != null) {
+            mRenderThread.finish();
+            mRenderThread = null;
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
+            int height) {
+        mRenderThread.setSurface(surface);
+        mRenderThread.setSize(width, height);
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
+            int height) {
+        mRenderThread.setSize(width, height);
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        if (mRenderThread != null) {
+            mRenderThread.setSurface(null);
+        }
+        return false;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            destroy();
+        } catch (Throwable t) {
+            // Ignore
+        }
+        super.finalize();
+    }
+
+    /**
+     * An EGL helper class.
+     */
+
+    private static class EglHelper {
+        private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        private static final int EGL_OPENGL_ES2_BIT = 4;
+
+        EGL10 mEgl;
+        EGLDisplay mEglDisplay;
+        EGLSurface mEglSurface;
+        EGLConfig mEglConfig;
+        EGLContext mEglContext;
+
+        private EGLConfig chooseEglConfig() {
+            int[] configsCount = new int[1];
+            EGLConfig[] configs = new EGLConfig[1];
+            int[] configSpec = getConfig();
+            if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+                throw new IllegalArgumentException("eglChooseConfig failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            } else if (configsCount[0] > 0) {
+                return configs[0];
+            }
+            return null;
+        }
+
+        private static int[] getConfig() {
+            return new int[] {
+                    EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                    EGL10.EGL_RED_SIZE, 8,
+                    EGL10.EGL_GREEN_SIZE, 8,
+                    EGL10.EGL_BLUE_SIZE, 8,
+                    EGL10.EGL_ALPHA_SIZE, 8,
+                    EGL10.EGL_DEPTH_SIZE, 0,
+                    EGL10.EGL_STENCIL_SIZE, 0,
+                    EGL10.EGL_NONE
+            };
+        }
+
+        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+            int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+            return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
+        }
+
+        /**
+         * Initialize EGL for a given configuration spec.
+         */
+        public void start() {
+            /*
+             * Get an EGL instance
+             */
+            mEgl = (EGL10) EGLContext.getEGL();
+
+            /*
+             * Get to the default display.
+             */
+            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+                throw new RuntimeException("eglGetDisplay failed");
+            }
+
+            /*
+             * We can now initialize EGL for that display
+             */
+            int[] version = new int[2];
+            if (!mEgl.eglInitialize(mEglDisplay, version)) {
+                throw new RuntimeException("eglInitialize failed");
+            }
+            mEglConfig = chooseEglConfig();
+
+            /*
+            * Create an EGL context. We want to do this as rarely as we can, because an
+            * EGL context is a somewhat heavy object.
+            */
+            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+            if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
+                mEglContext = null;
+                throwEglException("createContext");
+            }
+
+            mEglSurface = null;
+        }
+
+        /**
+         * Create an egl surface for the current SurfaceTexture surface. If a surface
+         * already exists, destroy it before creating the new surface.
+         *
+         * @return true if the surface was created successfully.
+         */
+        public boolean createSurface(SurfaceTexture surface) {
+            /*
+             * Check preconditions.
+             */
+            if (mEgl == null) {
+                throw new RuntimeException("egl not initialized");
+            }
+            if (mEglDisplay == null) {
+                throw new RuntimeException("eglDisplay not initialized");
+            }
+            if (mEglConfig == null) {
+                throw new RuntimeException("mEglConfig not initialized");
+            }
+
+            /*
+             *  The window size has changed, so we need to create a new
+             *  surface.
+             */
+            destroySurfaceImp();
+
+            /*
+             * Create an EGL surface we can render into.
+             */
+            if (surface != null) {
+                mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
+            } else {
+                mEglSurface = null;
+            }
+
+            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+                int error = mEgl.eglGetError();
+                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                }
+                return false;
+            }
+
+            /*
+             * Before we can issue GL commands, we need to make sure
+             * the context is current and bound to a surface.
+             */
+            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                /*
+                 * Could not make the context current, probably because the underlying
+                 * SurfaceView surface has been destroyed.
+                 */
+                logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * Create a GL object for the current EGL context.
+         */
+        public GL10 createGL() {
+            return (GL10) mEglContext.getGL();
+        }
+
+        /**
+         * Display the current render surface.
+         * @return the EGL error code from eglSwapBuffers.
+         */
+        public int swap() {
+            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                return mEgl.eglGetError();
+            }
+            return EGL10.EGL_SUCCESS;
+        }
+
+        public void destroySurface() {
+            destroySurfaceImp();
+        }
+
+        private void destroySurfaceImp() {
+            if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
+                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+                        EGL10.EGL_NO_SURFACE,
+                        EGL10.EGL_NO_CONTEXT);
+                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+                mEglSurface = null;
+            }
+        }
+
+        public void finish() {
+            if (mEglContext != null) {
+                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+                mEglContext = null;
+            }
+            if (mEglDisplay != null) {
+                mEgl.eglTerminate(mEglDisplay);
+                mEglDisplay = null;
+            }
+        }
+
+        private void throwEglException(String function) {
+            throwEglException(function, mEgl.eglGetError());
+        }
+
+        public static void throwEglException(String function, int error) {
+            String message = formatEglError(function, error);
+            throw new RuntimeException(message);
+        }
+
+        public static void logEglErrorAsWarning(String tag, String function, int error) {
+            Log.w(tag, formatEglError(function, error));
+        }
+
+        public static String formatEglError(String function, int error) {
+            return function + " failed: " + error;
+        }
+
+    }
+
+    private static class RenderThread extends Thread {
+        private static final int INVALID = -1;
+        private static final int RENDER = 1;
+        private static final int CHANGE_SURFACE = 2;
+        private static final int RESIZE_SURFACE = 3;
+        private static final int FINISH = 4;
+
+        private EglHelper mEglHelper = new EglHelper();
+
+        private Object mLock = new Object();
+        private int mExecMsgId = INVALID;
+        private SurfaceTexture mSurface;
+        private Renderer mRenderer;
+        private int mWidth, mHeight;
+
+        private boolean mFinished = false;
+        private GL10 mGL;
+
+        public RenderThread(Renderer renderer) {
+            super("RenderThread");
+            mRenderer = renderer;
+            start();
+        }
+
+        private void checkRenderer() {
+            if (mRenderer == null) {
+                throw new IllegalArgumentException("Renderer is null!");
+            }
+        }
+
+        private void checkSurface() {
+            if (mSurface == null) {
+                throw new IllegalArgumentException("surface is null!");
+            }
+        }
+
+        public void setSurface(SurfaceTexture surface) {
+            // If the surface is null we're being torn down, don't need a
+            // renderer then
+            if (surface != null) {
+                checkRenderer();
+            }
+            mSurface = surface;
+            exec(CHANGE_SURFACE);
+        }
+
+        public void setSize(int width, int height) {
+            checkRenderer();
+            checkSurface();
+            mWidth = width;
+            mHeight = height;
+            exec(RESIZE_SURFACE);
+        }
+
+        public void render() {
+            checkRenderer();
+            if (mSurface != null) {
+                exec(RENDER);
+                mSurface.updateTexImage();
+            }
+        }
+
+        public void finish() {
+            mSurface = null;
+            exec(FINISH);
+            try {
+                join();
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        }
+
+        private void exec(int msgid) {
+            synchronized (mLock) {
+                if (mExecMsgId != INVALID) {
+                    throw new IllegalArgumentException(
+                            "Message already set - multithreaded access?");
+                }
+                mExecMsgId = msgid;
+                mLock.notify();
+                try {
+                    mLock.wait();
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        private void handleMessageLocked(int what) {
+            switch (what) {
+            case CHANGE_SURFACE:
+                if (mEglHelper.createSurface(mSurface)) {
+                    mGL = mEglHelper.createGL();
+                    mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
+                }
+                break;
+            case RESIZE_SURFACE:
+                mRenderer.onSurfaceChanged(mGL, mWidth, mHeight);
+                break;
+            case RENDER:
+                mRenderer.onDrawFrame(mGL);
+                mEglHelper.swap();
+                break;
+            case FINISH:
+                mEglHelper.destroySurface();
+                mEglHelper.finish();
+                mFinished = true;
+                break;
+            }
+        }
+
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                mEglHelper.start();
+                while (!mFinished) {
+                    while (mExecMsgId == INVALID) {
+                        try {
+                            mLock.wait();
+                        } catch (InterruptedException e) {
+                            // Ignore
+                        }
+                    }
+                    handleMessageLocked(mExecMsgId);
+                    mExecMsgId = INVALID;
+                    mLock.notify();
+                }
+                mExecMsgId = FINISH;
+            }
+        }
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
new file mode 100644
index 0000000..c4e493b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -0,0 +1,825 @@
+/*
+ * 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.photos.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.v4.util.LongSparseArray;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Pools.Pool;
+import android.util.Pools.SynchronizedPool;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.GLCanvas;
+import com.android.gallery3d.glrenderer.UploadedTexture;
+
+/**
+ * Handles laying out, decoding, and drawing of tiles in GL
+ */
+public class TiledImageRenderer {
+    public static final int SIZE_UNKNOWN = -1;
+
+    private static final String TAG = "TiledImageRenderer";
+    private static final int UPLOAD_LIMIT = 1;
+
+    /*
+     *  This is the tile state in the CPU side.
+     *  Life of a Tile:
+     *      ACTIVATED (initial state)
+     *              --> IN_QUEUE - by queueForDecode()
+     *              --> RECYCLED - by recycleTile()
+     *      IN_QUEUE --> DECODING - by decodeTile()
+     *               --> RECYCLED - by recycleTile)
+     *      DECODING --> RECYCLING - by recycleTile()
+     *               --> DECODED  - by decodeTile()
+     *               --> DECODE_FAIL - by decodeTile()
+     *      RECYCLING --> RECYCLED - by decodeTile()
+     *      DECODED --> ACTIVATED - (after the decoded bitmap is uploaded)
+     *      DECODED --> RECYCLED - by recycleTile()
+     *      DECODE_FAIL -> RECYCLED - by recycleTile()
+     *      RECYCLED --> ACTIVATED - by obtainTile()
+     */
+    private static final int STATE_ACTIVATED = 0x01;
+    private static final int STATE_IN_QUEUE = 0x02;
+    private static final int STATE_DECODING = 0x04;
+    private static final int STATE_DECODED = 0x08;
+    private static final int STATE_DECODE_FAIL = 0x10;
+    private static final int STATE_RECYCLING = 0x20;
+    private static final int STATE_RECYCLED = 0x40;
+
+    private static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
+
+    // TILE_SIZE must be 2^N
+    private int mTileSize;
+
+    private TileSource mModel;
+    private BasicTexture mPreview;
+    protected int mLevelCount;  // cache the value of mScaledBitmaps.length
+
+    // The mLevel variable indicates which level of bitmap we should use.
+    // Level 0 means the original full-sized bitmap, and a larger value means
+    // a smaller scaled bitmap (The width and height of each scaled bitmap is
+    // half size of the previous one). If the value is in [0, mLevelCount), we
+    // use the bitmap in mScaledBitmaps[mLevel] for display, otherwise the value
+    // is mLevelCount
+    private int mLevel = 0;
+
+    private int mOffsetX;
+    private int mOffsetY;
+
+    private int mUploadQuota;
+    private boolean mRenderComplete;
+
+    private final RectF mSourceRect = new RectF();
+    private final RectF mTargetRect = new RectF();
+
+    private final LongSparseArray<Tile> mActiveTiles = new LongSparseArray<Tile>();
+
+    // The following three queue are guarded by mQueueLock
+    private final Object mQueueLock = new Object();
+    private final TileQueue mRecycledQueue = new TileQueue();
+    private final TileQueue mUploadQueue = new TileQueue();
+    private final TileQueue mDecodeQueue = new TileQueue();
+
+    // The width and height of the full-sized bitmap
+    protected int mImageWidth = SIZE_UNKNOWN;
+    protected int mImageHeight = SIZE_UNKNOWN;
+
+    protected int mCenterX;
+    protected int mCenterY;
+    protected float mScale;
+    protected int mRotation;
+
+    private boolean mLayoutTiles;
+
+    // Temp variables to avoid memory allocation
+    private final Rect mTileRange = new Rect();
+    private final Rect mActiveRange[] = {new Rect(), new Rect()};
+
+    private TileDecoder mTileDecoder;
+    private boolean mBackgroundTileUploaded;
+
+    private int mViewWidth, mViewHeight;
+    private View mParent;
+
+    /**
+     * Interface for providing tiles to a {@link TiledImageRenderer}
+     */
+    public static interface TileSource {
+
+        /**
+         * If the source does not care about the tile size, it should use
+         * {@link TiledImageRenderer#suggestedTileSize(Context)}
+         */
+        public int getTileSize();
+        public int getImageWidth();
+        public int getImageHeight();
+        public int getRotation();
+
+        /**
+         * Return a Preview image if available. This will be used as the base layer
+         * if higher res tiles are not yet available
+         */
+        public BasicTexture getPreview();
+
+        /**
+         * The tile returned by this method can be specified this way: Assuming
+         * the image size is (width, height), first take the intersection of (0,
+         * 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). If
+         * in extending the region, we found some part of the region is outside
+         * the image, those pixels are filled with black.
+         *
+         * If level > 0, it does the same operation on a down-scaled version of
+         * the original image (down-scaled by a factor of 2^level), but (x, y)
+         * still refers to the coordinate on the original image.
+         *
+         * The method would be called by the decoder thread.
+         */
+        public Bitmap getTile(int level, int x, int y, Bitmap reuse);
+    }
+
+    public static int suggestedTileSize(Context context) {
+        return isHighResolution(context) ? 512 : 256;
+    }
+
+    private static boolean isHighResolution(Context context) {
+        DisplayMetrics metrics = new DisplayMetrics();
+        WindowManager wm = (WindowManager)
+                context.getSystemService(Context.WINDOW_SERVICE);
+        wm.getDefaultDisplay().getMetrics(metrics);
+        return metrics.heightPixels > 2048 ||  metrics.widthPixels > 2048;
+    }
+
+    public TiledImageRenderer(View parent) {
+        mParent = parent;
+        mTileDecoder = new TileDecoder();
+        mTileDecoder.start();
+    }
+
+    public int getViewWidth() {
+        return mViewWidth;
+    }
+
+    public int getViewHeight() {
+        return mViewHeight;
+    }
+
+    private void invalidate() {
+        mParent.postInvalidate();
+    }
+
+    public void setModel(TileSource model, int rotation) {
+        if (mModel != model) {
+            mModel = model;
+            notifyModelInvalidated();
+        }
+        if (mRotation != rotation) {
+            mRotation = rotation;
+            mLayoutTiles = true;
+        }
+    }
+
+    private void calculateLevelCount() {
+        if (mPreview != null) {
+            mLevelCount = Math.max(0, Utils.ceilLog2(
+                mImageWidth / (float) mPreview.getWidth()));
+        } else {
+            int levels = 1;
+            int maxDim = Math.max(mImageWidth, mImageHeight);
+            int t = mTileSize;
+            while (t < maxDim) {
+                t <<= 1;
+                levels++;
+            }
+            mLevelCount = levels;
+        }
+    }
+
+    public void notifyModelInvalidated() {
+        invalidateTiles();
+        if (mModel == null) {
+            mImageWidth = 0;
+            mImageHeight = 0;
+            mLevelCount = 0;
+            mPreview = null;
+        } else {
+            mImageWidth = mModel.getImageWidth();
+            mImageHeight = mModel.getImageHeight();
+            mPreview = mModel.getPreview();
+            mTileSize = mModel.getTileSize();
+            calculateLevelCount();
+        }
+        mLayoutTiles = true;
+    }
+
+    public void setViewSize(int width, int height) {
+        mViewWidth = width;
+        mViewHeight = height;
+    }
+
+    public void setPosition(int centerX, int centerY, float scale) {
+        if (mCenterX == centerX && mCenterY == centerY
+                && mScale == scale) {
+            return;
+        }
+        mCenterX = centerX;
+        mCenterY = centerY;
+        mScale = scale;
+        mLayoutTiles = true;
+    }
+
+    // Prepare the tiles we want to use for display.
+    //
+    // 1. Decide the tile level we want to use for display.
+    // 2. Decide the tile levels we want to keep as texture (in addition to
+    //    the one we use for display).
+    // 3. Recycle unused tiles.
+    // 4. Activate the tiles we want.
+    private void layoutTiles() {
+        if (mViewWidth == 0 || mViewHeight == 0 || !mLayoutTiles) {
+            return;
+        }
+        mLayoutTiles = false;
+
+        // The tile levels we want to keep as texture is in the range
+        // [fromLevel, endLevel).
+        int fromLevel;
+        int endLevel;
+
+        // We want to use a texture larger than or equal to the display size.
+        mLevel = Utils.clamp(Utils.floorLog2(1f / mScale), 0, mLevelCount);
+
+        // We want to keep one more tile level as texture in addition to what
+        // we use for display. So it can be faster when the scale moves to the
+        // next level. We choose the level closest to the current scale.
+        if (mLevel != mLevelCount) {
+            Rect range = mTileRange;
+            getRange(range, mCenterX, mCenterY, mLevel, mScale, mRotation);
+            mOffsetX = Math.round(mViewWidth / 2f + (range.left - mCenterX) * mScale);
+            mOffsetY = Math.round(mViewHeight / 2f + (range.top - mCenterY) * mScale);
+            fromLevel = mScale * (1 << mLevel) > 0.75f ? mLevel - 1 : mLevel;
+        } else {
+            // Activate the tiles of the smallest two levels.
+            fromLevel = mLevel - 2;
+            mOffsetX = Math.round(mViewWidth / 2f - mCenterX * mScale);
+            mOffsetY = Math.round(mViewHeight / 2f - mCenterY * mScale);
+        }
+
+        fromLevel = Math.max(0, Math.min(fromLevel, mLevelCount - 2));
+        endLevel = Math.min(fromLevel + 2, mLevelCount);
+
+        Rect range[] = mActiveRange;
+        for (int i = fromLevel; i < endLevel; ++i) {
+            getRange(range[i - fromLevel], mCenterX, mCenterY, i, mRotation);
+        }
+
+        // If rotation is transient, don't update the tile.
+        if (mRotation % 90 != 0) {
+            return;
+        }
+
+        synchronized (mQueueLock) {
+            mDecodeQueue.clean();
+            mUploadQueue.clean();
+            mBackgroundTileUploaded = false;
+
+            // Recycle unused tiles: if the level of the active tile is outside the
+            // range [fromLevel, endLevel) or not in the visible range.
+            int n = mActiveTiles.size();
+            for (int i = 0; i < n; i++) {
+                Tile tile = mActiveTiles.valueAt(i);
+                int level = tile.mTileLevel;
+                if (level < fromLevel || level >= endLevel
+                        || !range[level - fromLevel].contains(tile.mX, tile.mY)) {
+                    mActiveTiles.removeAt(i);
+                    i--;
+                    n--;
+                    recycleTile(tile);
+                }
+            }
+        }
+
+        for (int i = fromLevel; i < endLevel; ++i) {
+            int size = mTileSize << i;
+            Rect r = range[i - fromLevel];
+            for (int y = r.top, bottom = r.bottom; y < bottom; y += size) {
+                for (int x = r.left, right = r.right; x < right; x += size) {
+                    activateTile(x, y, i);
+                }
+            }
+        }
+        invalidate();
+    }
+
+    private void invalidateTiles() {
+        synchronized (mQueueLock) {
+            mDecodeQueue.clean();
+            mUploadQueue.clean();
+
+            // TODO(xx): disable decoder
+            int n = mActiveTiles.size();
+            for (int i = 0; i < n; i++) {
+                Tile tile = mActiveTiles.valueAt(i);
+                recycleTile(tile);
+            }
+            mActiveTiles.clear();
+        }
+    }
+
+    private void getRange(Rect out, int cX, int cY, int level, int rotation) {
+        getRange(out, cX, cY, level, 1f / (1 << (level + 1)), rotation);
+    }
+
+    // If the bitmap is scaled by the given factor "scale", return the
+    // rectangle containing visible range. The left-top coordinate returned is
+    // aligned to the tile boundary.
+    //
+    // (cX, cY) is the point on the original bitmap which will be put in the
+    // center of the ImageViewer.
+    private void getRange(Rect out,
+            int cX, int cY, int level, float scale, int rotation) {
+
+        double radians = Math.toRadians(-rotation);
+        double w = mViewWidth;
+        double h = mViewHeight;
+
+        double cos = Math.cos(radians);
+        double sin = Math.sin(radians);
+        int width = (int) Math.ceil(Math.max(
+                Math.abs(cos * w - sin * h), Math.abs(cos * w + sin * h)));
+        int height = (int) Math.ceil(Math.max(
+                Math.abs(sin * w + cos * h), Math.abs(sin * w - cos * h)));
+
+        int left = (int) Math.floor(cX - width / (2f * scale));
+        int top = (int) Math.floor(cY - height / (2f * scale));
+        int right = (int) Math.ceil(left + width / scale);
+        int bottom = (int) Math.ceil(top + height / scale);
+
+        // align the rectangle to tile boundary
+        int size = mTileSize << level;
+        left = Math.max(0, size * (left / size));
+        top = Math.max(0, size * (top / size));
+        right = Math.min(mImageWidth, right);
+        bottom = Math.min(mImageHeight, bottom);
+
+        out.set(left, top, right, bottom);
+    }
+
+    public void freeTextures() {
+        mLayoutTiles = true;
+
+        mTileDecoder.finishAndWait();
+        synchronized (mQueueLock) {
+            mUploadQueue.clean();
+            mDecodeQueue.clean();
+            Tile tile = mRecycledQueue.pop();
+            while (tile != null) {
+                tile.recycle();
+                tile = mRecycledQueue.pop();
+            }
+        }
+
+        int n = mActiveTiles.size();
+        for (int i = 0; i < n; i++) {
+            Tile texture = mActiveTiles.valueAt(i);
+            texture.recycle();
+        }
+        mActiveTiles.clear();
+        mTileRange.set(0, 0, 0, 0);
+
+        while (sTilePool.acquire() != null) {}
+    }
+
+    public boolean draw(GLCanvas canvas) {
+        layoutTiles();
+        uploadTiles(canvas);
+
+        mUploadQuota = UPLOAD_LIMIT;
+        mRenderComplete = true;
+
+        int level = mLevel;
+        int rotation = mRotation;
+        int flags = 0;
+        if (rotation != 0) {
+            flags |= GLCanvas.SAVE_FLAG_MATRIX;
+        }
+
+        if (flags != 0) {
+            canvas.save(flags);
+            if (rotation != 0) {
+                int centerX = mViewWidth / 2, centerY = mViewHeight / 2;
+                canvas.translate(centerX, centerY);
+                canvas.rotate(rotation, 0, 0, 1);
+                canvas.translate(-centerX, -centerY);
+            }
+        }
+        try {
+            if (level != mLevelCount) {
+                int size = (mTileSize << level);
+                float length = size * mScale;
+                Rect r = mTileRange;
+
+                for (int ty = r.top, i = 0; ty < r.bottom; ty += size, i++) {
+                    float y = mOffsetY + i * length;
+                    for (int tx = r.left, j = 0; tx < r.right; tx += size, j++) {
+                        float x = mOffsetX + j * length;
+                        drawTile(canvas, tx, ty, level, x, y, length);
+                    }
+                }
+            } else if (mPreview != null) {
+                mPreview.draw(canvas, mOffsetX, mOffsetY,
+                        Math.round(mImageWidth * mScale),
+                        Math.round(mImageHeight * mScale));
+            }
+        } finally {
+            if (flags != 0) {
+                canvas.restore();
+            }
+        }
+
+        if (mRenderComplete) {
+            if (!mBackgroundTileUploaded) {
+                uploadBackgroundTiles(canvas);
+            }
+        } else {
+            invalidate();
+        }
+        return mRenderComplete || mPreview != null;
+    }
+
+    private void uploadBackgroundTiles(GLCanvas canvas) {
+        mBackgroundTileUploaded = true;
+        int n = mActiveTiles.size();
+        for (int i = 0; i < n; i++) {
+            Tile tile = mActiveTiles.valueAt(i);
+            if (!tile.isContentValid()) {
+                queueForDecode(tile);
+            }
+        }
+    }
+
+   private void queueForDecode(Tile tile) {
+       synchronized (mQueueLock) {
+           if (tile.mTileState == STATE_ACTIVATED) {
+               tile.mTileState = STATE_IN_QUEUE;
+               if (mDecodeQueue.push(tile)) {
+                   mQueueLock.notifyAll();
+               }
+           }
+       }
+    }
+
+    private void decodeTile(Tile tile) {
+        synchronized (mQueueLock) {
+            if (tile.mTileState != STATE_IN_QUEUE) {
+                return;
+            }
+            tile.mTileState = STATE_DECODING;
+        }
+        boolean decodeComplete = tile.decode();
+        synchronized (mQueueLock) {
+            if (tile.mTileState == STATE_RECYCLING) {
+                tile.mTileState = STATE_RECYCLED;
+                if (tile.mDecodedTile != null) {
+                    sTilePool.release(tile.mDecodedTile);
+                    tile.mDecodedTile = null;
+                }
+                mRecycledQueue.push(tile);
+                return;
+            }
+            tile.mTileState = decodeComplete ? STATE_DECODED : STATE_DECODE_FAIL;
+            if (!decodeComplete) {
+                return;
+            }
+            mUploadQueue.push(tile);
+        }
+        invalidate();
+    }
+
+    private Tile obtainTile(int x, int y, int level) {
+        synchronized (mQueueLock) {
+            Tile tile = mRecycledQueue.pop();
+            if (tile != null) {
+                tile.mTileState = STATE_ACTIVATED;
+                tile.update(x, y, level);
+                return tile;
+            }
+            return new Tile(x, y, level);
+        }
+    }
+
+    private void recycleTile(Tile tile) {
+        synchronized (mQueueLock) {
+            if (tile.mTileState == STATE_DECODING) {
+                tile.mTileState = STATE_RECYCLING;
+                return;
+            }
+            tile.mTileState = STATE_RECYCLED;
+            if (tile.mDecodedTile != null) {
+                sTilePool.release(tile.mDecodedTile);
+                tile.mDecodedTile = null;
+            }
+            mRecycledQueue.push(tile);
+        }
+    }
+
+    private void activateTile(int x, int y, int level) {
+        long key = makeTileKey(x, y, level);
+        Tile tile = mActiveTiles.get(key);
+        if (tile != null) {
+            if (tile.mTileState == STATE_IN_QUEUE) {
+                tile.mTileState = STATE_ACTIVATED;
+            }
+            return;
+        }
+        tile = obtainTile(x, y, level);
+        mActiveTiles.put(key, tile);
+    }
+
+    private Tile getTile(int x, int y, int level) {
+        return mActiveTiles.get(makeTileKey(x, y, level));
+    }
+
+    private static long makeTileKey(int x, int y, int level) {
+        long result = x;
+        result = (result << 16) | y;
+        result = (result << 16) | level;
+        return result;
+    }
+
+    private void uploadTiles(GLCanvas canvas) {
+        int quota = UPLOAD_LIMIT;
+        Tile tile = null;
+        while (quota > 0) {
+            synchronized (mQueueLock) {
+                tile = mUploadQueue.pop();
+            }
+            if (tile == null) {
+                break;
+            }
+            if (!tile.isContentValid()) {
+                if (tile.mTileState == STATE_DECODED) {
+                    tile.updateContent(canvas);
+                    --quota;
+                } else {
+                    Log.w(TAG, "Tile in upload queue has invalid state: " + tile.mTileState);
+                }
+            }
+        }
+        if (tile != null) {
+            invalidate();
+        }
+    }
+
+    // Draw the tile to a square at canvas that locates at (x, y) and
+    // has a side length of length.
+    private void drawTile(GLCanvas canvas,
+            int tx, int ty, int level, float x, float y, float length) {
+        RectF source = mSourceRect;
+        RectF target = mTargetRect;
+        target.set(x, y, x + length, y + length);
+        source.set(0, 0, mTileSize, mTileSize);
+
+        Tile tile = getTile(tx, ty, level);
+        if (tile != null) {
+            if (!tile.isContentValid()) {
+                if (tile.mTileState == STATE_DECODED) {
+                    if (mUploadQuota > 0) {
+                        --mUploadQuota;
+                        tile.updateContent(canvas);
+                    } else {
+                        mRenderComplete = false;
+                    }
+                } else if (tile.mTileState != STATE_DECODE_FAIL){
+                    mRenderComplete = false;
+                    queueForDecode(tile);
+                }
+            }
+            if (drawTile(tile, canvas, source, target)) {
+                return;
+            }
+        }
+        if (mPreview != null) {
+            int size = mTileSize << level;
+            float scaleX = (float) mPreview.getWidth() / mImageWidth;
+            float scaleY = (float) mPreview.getHeight() / mImageHeight;
+            source.set(tx * scaleX, ty * scaleY, (tx + size) * scaleX,
+                    (ty + size) * scaleY);
+            canvas.drawTexture(mPreview, source, target);
+        }
+    }
+
+    private boolean drawTile(
+            Tile tile, GLCanvas canvas, RectF source, RectF target) {
+        while (true) {
+            if (tile.isContentValid()) {
+                canvas.drawTexture(tile, source, target);
+                return true;
+            }
+
+            // Parent can be divided to four quads and tile is one of the four.
+            Tile parent = tile.getParentTile();
+            if (parent == null) {
+                return false;
+            }
+            if (tile.mX == parent.mX) {
+                source.left /= 2f;
+                source.right /= 2f;
+            } else {
+                source.left = (mTileSize + source.left) / 2f;
+                source.right = (mTileSize + source.right) / 2f;
+            }
+            if (tile.mY == parent.mY) {
+                source.top /= 2f;
+                source.bottom /= 2f;
+            } else {
+                source.top = (mTileSize + source.top) / 2f;
+                source.bottom = (mTileSize + source.bottom) / 2f;
+            }
+            tile = parent;
+        }
+    }
+
+    private class Tile extends UploadedTexture {
+        public int mX;
+        public int mY;
+        public int mTileLevel;
+        public Tile mNext;
+        public Bitmap mDecodedTile;
+        public volatile int mTileState = STATE_ACTIVATED;
+
+        public Tile(int x, int y, int level) {
+            mX = x;
+            mY = y;
+            mTileLevel = level;
+        }
+
+        @Override
+        protected void onFreeBitmap(Bitmap bitmap) {
+            sTilePool.release(bitmap);
+        }
+
+        boolean decode() {
+            // Get a tile from the original image. The tile is down-scaled
+            // by (1 << mTilelevel) from a region in the original image.
+            try {
+                Bitmap reuse = sTilePool.acquire();
+                if (reuse != null && reuse.getWidth() != mTileSize) {
+                    reuse = null;
+                }
+                mDecodedTile = mModel.getTile(mTileLevel, mX, mY, reuse);
+            } catch (Throwable t) {
+                Log.w(TAG, "fail to decode tile", t);
+            }
+            return mDecodedTile != null;
+        }
+
+        @Override
+        protected Bitmap onGetBitmap() {
+            Utils.assertTrue(mTileState == STATE_DECODED);
+
+            // We need to override the width and height, so that we won't
+            // draw beyond the boundaries.
+            int rightEdge = ((mImageWidth - mX) >> mTileLevel);
+            int bottomEdge = ((mImageHeight - mY) >> mTileLevel);
+            setSize(Math.min(mTileSize, rightEdge), Math.min(mTileSize, bottomEdge));
+
+            Bitmap bitmap = mDecodedTile;
+            mDecodedTile = null;
+            mTileState = STATE_ACTIVATED;
+            return bitmap;
+        }
+
+        // We override getTextureWidth() and getTextureHeight() here, so the
+        // texture can be re-used for different tiles regardless of the actual
+        // size of the tile (which may be small because it is a tile at the
+        // boundary).
+        @Override
+        public int getTextureWidth() {
+            return mTileSize;
+        }
+
+        @Override
+        public int getTextureHeight() {
+            return mTileSize;
+        }
+
+        public void update(int x, int y, int level) {
+            mX = x;
+            mY = y;
+            mTileLevel = level;
+            invalidateContent();
+        }
+
+        public Tile getParentTile() {
+            if (mTileLevel + 1 == mLevelCount) {
+                return null;
+            }
+            int size = mTileSize << (mTileLevel + 1);
+            int x = size * (mX / size);
+            int y = size * (mY / size);
+            return getTile(x, y, mTileLevel + 1);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("tile(%s, %s, %s / %s)",
+                    mX / mTileSize, mY / mTileSize, mLevel, mLevelCount);
+        }
+    }
+
+    private static class TileQueue {
+        private Tile mHead;
+
+        public Tile pop() {
+            Tile tile = mHead;
+            if (tile != null) {
+                mHead = tile.mNext;
+            }
+            return tile;
+        }
+
+        public boolean push(Tile tile) {
+            if (contains(tile)) {
+                Log.w(TAG, "Attempting to add a tile already in the queue!");
+                return false;
+            }
+            boolean wasEmpty = mHead == null;
+            tile.mNext = mHead;
+            mHead = tile;
+            return wasEmpty;
+        }
+
+        private boolean contains(Tile tile) {
+            Tile other = mHead;
+            while (other != null) {
+                if (other == tile) {
+                    return true;
+                }
+                other = other.mNext;
+            }
+            return false;
+        }
+
+        public void clean() {
+            mHead = null;
+        }
+    }
+
+    private class TileDecoder extends Thread {
+
+        public void finishAndWait() {
+            interrupt();
+            try {
+                join();
+            } catch (InterruptedException e) {
+                Log.w(TAG, "Interrupted while waiting for TileDecoder thread to finish!");
+            }
+        }
+
+        private Tile waitForTile() throws InterruptedException {
+            synchronized (mQueueLock) {
+                while (true) {
+                    Tile tile = mDecodeQueue.pop();
+                    if (tile != null) {
+                        return tile;
+                    }
+                    mQueueLock.wait();
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!isInterrupted()) {
+                    Tile tile = waitForTile();
+                    decodeTile(tile);
+                }
+            } catch (InterruptedException ex) {
+                // We were finished
+            }
+        }
+
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
new file mode 100644
index 0000000..36cb438
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
@@ -0,0 +1,386 @@
+/*
+ * 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.photos.views;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.RectF;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.Choreographer;
+import android.view.Choreographer.FrameCallback;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.GLES20Canvas;
+import com.android.photos.views.TiledImageRenderer.TileSource;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}
+ * or {@link BlockingGLTextureView}.
+ */
+public class TiledImageView extends FrameLayout {
+
+    private static final boolean USE_TEXTURE_VIEW = false;
+    private static final boolean IS_SUPPORTED =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+    private static final boolean USE_CHOREOGRAPHER =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+
+    private BlockingGLTextureView mTextureView;
+    private GLSurfaceView mGLSurfaceView;
+    private boolean mInvalPending = false;
+    private FrameCallback mFrameCallback;
+
+    protected static class ImageRendererWrapper {
+        // Guarded by locks
+        public float scale;
+        public int centerX, centerY;
+        int rotation;
+        public TileSource source;
+        Runnable isReadyCallback;
+
+        // GL thread only
+        TiledImageRenderer image;
+    }
+
+    private float[] mValues = new float[9];
+
+    // -------------------------
+    // Guarded by mLock
+    // -------------------------
+    protected Object mLock = new Object();
+    protected ImageRendererWrapper mRenderer;
+
+    public static boolean isTilingSupported() {
+        return IS_SUPPORTED;
+    }
+
+    public TiledImageView(Context context) {
+        this(context, null);
+    }
+
+    public TiledImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        if (!IS_SUPPORTED) {
+            return;
+        }
+
+        mRenderer = new ImageRendererWrapper();
+        mRenderer.image = new TiledImageRenderer(this);
+        View view;
+        if (USE_TEXTURE_VIEW) {
+            mTextureView = new BlockingGLTextureView(context);
+            mTextureView.setRenderer(new TileRenderer());
+            view = mTextureView;
+        } else {
+            mGLSurfaceView = new GLSurfaceView(context);
+            mGLSurfaceView.setEGLContextClientVersion(2);
+            mGLSurfaceView.setRenderer(new TileRenderer());
+            mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+            view = mGLSurfaceView;
+        }
+        addView(view, new LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+        //setTileSource(new ColoredTiles());
+    }
+
+    public void destroy() {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        if (USE_TEXTURE_VIEW) {
+            mTextureView.destroy();
+        } else {
+            mGLSurfaceView.queueEvent(mFreeTextures);
+        }
+    }
+
+    private Runnable mFreeTextures = new Runnable() {
+
+        @Override
+        public void run() {
+            mRenderer.image.freeTextures();
+        }
+    };
+
+    public void onPause() {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        if (!USE_TEXTURE_VIEW) {
+            mGLSurfaceView.onPause();
+        }
+    }
+
+    public void onResume() {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        if (!USE_TEXTURE_VIEW) {
+            mGLSurfaceView.onResume();
+        }
+    }
+
+    public void setTileSource(TileSource source, Runnable isReadyCallback) {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        synchronized (mLock) {
+            mRenderer.source = source;
+            mRenderer.isReadyCallback = isReadyCallback;
+            mRenderer.centerX = source != null ? source.getImageWidth() / 2 : 0;
+            mRenderer.centerY = source != null ? source.getImageHeight() / 2 : 0;
+            mRenderer.rotation = source != null ? source.getRotation() : 0;
+            mRenderer.scale = 0;
+            updateScaleIfNecessaryLocked(mRenderer);
+        }
+        invalidate();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right,
+            int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        synchronized (mLock) {
+            updateScaleIfNecessaryLocked(mRenderer);
+        }
+    }
+
+    private void updateScaleIfNecessaryLocked(ImageRendererWrapper renderer) {
+        if (renderer == null || renderer.source == null
+                || renderer.scale > 0 || getWidth() == 0) {
+            return;
+        }
+        renderer.scale = Math.min(
+                (float) getWidth() / (float) renderer.source.getImageWidth(),
+                (float) getHeight() / (float) renderer.source.getImageHeight());
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        if (USE_TEXTURE_VIEW) {
+            mTextureView.render();
+        }
+        super.dispatchDraw(canvas);
+    }
+
+    @SuppressLint("NewApi")
+    @Override
+    public void setTranslationX(float translationX) {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        super.setTranslationX(translationX);
+    }
+
+    @Override
+    public void invalidate() {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        if (USE_TEXTURE_VIEW) {
+            super.invalidate();
+            mTextureView.invalidate();
+        } else {
+            if (USE_CHOREOGRAPHER) {
+                invalOnVsync();
+            } else {
+                mGLSurfaceView.requestRender();
+            }
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+    private void invalOnVsync() {
+        if (!mInvalPending) {
+            mInvalPending = true;
+            if (mFrameCallback == null) {
+                mFrameCallback = new FrameCallback() {
+                    @Override
+                    public void doFrame(long frameTimeNanos) {
+                        mInvalPending = false;
+                        mGLSurfaceView.requestRender();
+                    }
+                };
+            }
+            Choreographer.getInstance().postFrameCallback(mFrameCallback);
+        }
+    }
+
+    private RectF mTempRectF = new RectF();
+    public void positionFromMatrix(Matrix matrix) {
+        if (!IS_SUPPORTED) {
+            return;
+        }
+        if (mRenderer.source != null) {
+            final int rotation = mRenderer.source.getRotation();
+            final boolean swap = !(rotation % 180 == 0);
+            final int width = swap ? mRenderer.source.getImageHeight()
+                    : mRenderer.source.getImageWidth();
+            final int height = swap ? mRenderer.source.getImageWidth()
+                    : mRenderer.source.getImageHeight();
+            mTempRectF.set(0, 0, width, height);
+            matrix.mapRect(mTempRectF);
+            matrix.getValues(mValues);
+            int cx = width / 2;
+            int cy = height / 2;
+            float scale = mValues[Matrix.MSCALE_X];
+            int xoffset = Math.round((getWidth() - mTempRectF.width()) / 2 / scale);
+            int yoffset = Math.round((getHeight() - mTempRectF.height()) / 2 / scale);
+            if (rotation == 90 || rotation == 180) {
+                cx += (mTempRectF.left / scale) - xoffset;
+            } else {
+                cx -= (mTempRectF.left / scale) - xoffset;
+            }
+            if (rotation == 180 || rotation == 270) {
+                cy += (mTempRectF.top / scale) - yoffset;
+            } else {
+                cy -= (mTempRectF.top / scale) - yoffset;
+            }
+            mRenderer.scale = scale;
+            mRenderer.centerX = swap ? cy : cx;
+            mRenderer.centerY = swap ? cx : cy;
+            invalidate();
+        }
+    }
+
+    private class TileRenderer implements Renderer {
+
+        private GLES20Canvas mCanvas;
+
+        @Override
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            mCanvas = new GLES20Canvas();
+            BasicTexture.invalidateAllTextures();
+            mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
+        }
+
+        @Override
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            mCanvas.setSize(width, height);
+            mRenderer.image.setViewSize(width, height);
+        }
+
+        @Override
+        public void onDrawFrame(GL10 gl) {
+            mCanvas.clearBuffer();
+            Runnable readyCallback;
+            synchronized (mLock) {
+                readyCallback = mRenderer.isReadyCallback;
+                mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
+                mRenderer.image.setPosition(mRenderer.centerX, mRenderer.centerY,
+                        mRenderer.scale);
+            }
+            boolean complete = mRenderer.image.draw(mCanvas);
+            if (complete && readyCallback != null) {
+                synchronized (mLock) {
+                    // Make sure we don't trample on a newly set callback/source
+                    // if it changed while we were rendering
+                    if (mRenderer.isReadyCallback == readyCallback) {
+                        mRenderer.isReadyCallback = null;
+                    }
+                }
+                if (readyCallback != null) {
+                    post(readyCallback);
+                }
+            }
+        }
+
+    }
+
+    @SuppressWarnings("unused")
+    private static class ColoredTiles implements TileSource {
+        private static final int[] COLORS = new int[] {
+            Color.RED,
+            Color.BLUE,
+            Color.YELLOW,
+            Color.GREEN,
+            Color.CYAN,
+            Color.MAGENTA,
+            Color.WHITE,
+        };
+
+        private Paint mPaint = new Paint();
+        private Canvas mCanvas = new Canvas();
+
+        @Override
+        public int getTileSize() {
+            return 256;
+        }
+
+        @Override
+        public int getImageWidth() {
+            return 16384;
+        }
+
+        @Override
+        public int getImageHeight() {
+            return 8192;
+        }
+
+        @Override
+        public int getRotation() {
+            return 0;
+        }
+
+        @Override
+        public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
+            int tileSize = getTileSize();
+            if (bitmap == null) {
+                bitmap = Bitmap.createBitmap(tileSize, tileSize,
+                        Bitmap.Config.ARGB_8888);
+            }
+            mCanvas.setBitmap(bitmap);
+            mCanvas.drawColor(COLORS[level]);
+            mPaint.setColor(Color.BLACK);
+            mPaint.setTextSize(20);
+            mPaint.setTextAlign(Align.CENTER);
+            mCanvas.drawText(x + "x" + y, 128, 128, mPaint);
+            tileSize <<= level;
+            x /= tileSize;
+            y /= tileSize;
+            mCanvas.drawText(x + "x" + y + " @ " + level, 128, 30, mPaint);
+            mCanvas.setBitmap(null);
+            return bitmap;
+        }
+
+        @Override
+        public BasicTexture getPreview() {
+            return null;
+        }
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
new file mode 100644
index 0000000..ecebd642
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+/* Copied from Launcher3 */
+package com.android.wallpapercropper;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.ViewConfiguration;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+
+import com.android.photos.views.TiledImageRenderer.TileSource;
+import com.android.photos.views.TiledImageView;
+
+public class CropView extends TiledImageView implements OnScaleGestureListener {
+
+    private ScaleGestureDetector mScaleGestureDetector;
+    private long mTouchDownTime;
+    private float mFirstX, mFirstY;
+    private float mLastX, mLastY;
+    private float mMinScale;
+    private boolean mTouchEnabled = true;
+    private RectF mTempEdges = new RectF();
+    TouchCallback mTouchCallback;
+
+    public interface TouchCallback {
+        void onTouchDown();
+        void onTap();
+    }
+
+    public CropView(Context context) {
+        this(context, null);
+    }
+
+    public CropView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mScaleGestureDetector = new ScaleGestureDetector(context, this);
+    }
+
+    private void getEdgesHelper(RectF edgesOut) {
+        final float width = getWidth();
+        final float height = getHeight();
+        final float imageWidth = mRenderer.source.getImageWidth();
+        final float imageHeight = mRenderer.source.getImageHeight();
+        final float scale = mRenderer.scale;
+        float centerX = (width / 2f - mRenderer.centerX + (imageWidth - width) / 2f)
+                * scale + width / 2f;
+        float centerY = (height / 2f - mRenderer.centerY + (imageHeight - height) / 2f)
+                * scale + height / 2f;
+        float leftEdge = centerX - imageWidth / 2f * scale;
+        float rightEdge = centerX + imageWidth / 2f * scale;
+        float topEdge = centerY - imageHeight / 2f * scale;
+        float bottomEdge = centerY + imageHeight / 2f * scale;
+
+        edgesOut.left = leftEdge;
+        edgesOut.right = rightEdge;
+        edgesOut.top = topEdge;
+        edgesOut.bottom = bottomEdge;
+    }
+
+    public RectF getCrop() {
+        final RectF edges = mTempEdges;
+        getEdgesHelper(edges);
+        final float scale = mRenderer.scale;
+
+        float cropLeft = -edges.left / scale;
+        float cropTop = -edges.top / scale;
+        float cropRight = cropLeft + getWidth() / scale;
+        float cropBottom = cropTop + getHeight() / scale;
+
+        return new RectF(cropLeft, cropTop, cropRight, cropBottom);
+    }
+
+    public Point getSourceDimensions() {
+        return new Point(mRenderer.source.getImageWidth(), mRenderer.source.getImageHeight());
+    }
+
+    public void setTileSource(TileSource source, Runnable isReadyCallback) {
+        super.setTileSource(source, isReadyCallback);
+        updateMinScale(getWidth(), getHeight(), source, true);
+    }
+
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        updateMinScale(w, h, mRenderer.source, false);
+    }
+
+    public void setScale(float scale) {
+        synchronized (mLock) {
+            mRenderer.scale = scale;
+        }
+    }
+
+    private void updateMinScale(int w, int h, TileSource source, boolean resetScale) {
+        synchronized (mLock) {
+            if (resetScale) {
+                mRenderer.scale = 1;
+            }
+            if (source != null) {
+                mMinScale = Math.max(w / (float) source.getImageWidth(),
+                        h / (float) source.getImageHeight());
+                mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
+            }
+        }
+    }
+
+    @Override
+    public boolean onScaleBegin(ScaleGestureDetector detector) {
+        return true;
+    }
+
+    @Override
+    public boolean onScale(ScaleGestureDetector detector) {
+        // Don't need the lock because this will only fire inside of
+        // onTouchEvent
+        mRenderer.scale *= detector.getScaleFactor();
+        mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
+        invalidate();
+        return true;
+    }
+
+    @Override
+    public void onScaleEnd(ScaleGestureDetector detector) {
+    }
+
+    public void moveToUpperLeft() {
+        if (getWidth() == 0 || getHeight() == 0) {
+            final ViewTreeObserver observer = getViewTreeObserver();
+            observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+                    public void onGlobalLayout() {
+                        moveToUpperLeft();
+                        getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                    }
+                });
+        }
+        final RectF edges = mTempEdges;
+        getEdgesHelper(edges);
+        final float scale = mRenderer.scale;
+        mRenderer.centerX += Math.ceil(edges.left / scale);
+        mRenderer.centerY += Math.ceil(edges.top / scale);
+    }
+
+    public void setTouchEnabled(boolean enabled) {
+        mTouchEnabled = enabled;
+    }
+
+    public void setTouchCallback(TouchCallback cb) {
+        mTouchCallback = cb;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+        final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
+        final int skipIndex = pointerUp ? event.getActionIndex() : -1;
+
+        // Determine focal point
+        float sumX = 0, sumY = 0;
+        final int count = event.getPointerCount();
+        for (int i = 0; i < count; i++) {
+            if (skipIndex == i)
+                continue;
+            sumX += event.getX(i);
+            sumY += event.getY(i);
+        }
+        final int div = pointerUp ? count - 1 : count;
+        float x = sumX / div;
+        float y = sumY / div;
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mFirstX = x;
+            mFirstY = y;
+            mTouchDownTime = System.currentTimeMillis();
+            if (mTouchCallback != null) {
+                mTouchCallback.onTouchDown();
+            }
+        } else if (action == MotionEvent.ACTION_UP) {
+            ViewConfiguration config = ViewConfiguration.get(getContext());
+
+            float squaredDist = (mFirstX - x) * (mFirstX - x) + (mFirstY - y) * (mFirstY - y);
+            float slop = config.getScaledTouchSlop() * config.getScaledTouchSlop();
+            long now = System.currentTimeMillis();
+            // only do this if it's a small movement
+            if (mTouchCallback != null &&
+                    squaredDist < slop &&
+                    now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
+                mTouchCallback.onTap();
+            }
+        }
+
+        if (!mTouchEnabled) {
+            return true;
+        }
+
+        synchronized (mLock) {
+            mScaleGestureDetector.onTouchEvent(event);
+            switch (action) {
+                case MotionEvent.ACTION_MOVE:
+                    mRenderer.centerX += (mLastX - x) / mRenderer.scale;
+                    mRenderer.centerY += (mLastY - y) / mRenderer.scale;
+                    invalidate();
+                    break;
+            }
+            if (mRenderer.source != null) {
+                // Adjust position so that the wallpaper covers the entire area
+                // of the screen
+                final RectF edges = mTempEdges;
+                getEdgesHelper(edges);
+                final float scale = mRenderer.scale;
+                if (edges.left > 0) {
+                    mRenderer.centerX += Math.ceil(edges.left / scale);
+                }
+                if (edges.right < getWidth()) {
+                    mRenderer.centerX += (edges.right - getWidth()) / scale;
+                }
+                if (edges.top > 0) {
+                    mRenderer.centerY += Math.ceil(edges.top / scale);
+                }
+                if (edges.bottom < getHeight()) {
+                    mRenderer.centerY += (edges.bottom - getHeight()) / scale;
+                }
+            }
+        }
+
+        mLastX = x;
+        mLastY = y;
+        return true;
+    }
+}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
new file mode 100644
index 0000000..af48652
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -0,0 +1,647 @@
+/*
+ * 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.
+ */
+/* Copied from Launcher3 */
+package com.android.wallpapercropper;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.gallery3d.common.Utils;
+import com.android.photos.BitmapRegionTileSource;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class WallpaperCropActivity extends Activity {
+    private static final String LOGTAG = "Launcher3.CropActivity";
+
+    protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
+    protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
+    private static final int DEFAULT_COMPRESS_QUALITY = 90;
+    /**
+     * The maximum bitmap size we allow to be returned through the intent.
+     * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
+     * have some overhead to hit so that we go way below the limit here to make
+     * sure the intent stays below 1MB.We should consider just returning a byte
+     * array instead of a Bitmap instance to avoid overhead.
+     */
+    public static final int MAX_BMAP_IN_INTENT = 750000;
+    private static final float WALLPAPER_SCREENS_SPAN = 2f;
+
+    protected CropView mCropView;
+    protected Uri mUri;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        init();
+    }
+
+    protected void init() {
+        setContentView(R.layout.wallpaper_cropper);
+
+        mCropView = (CropView) findViewById(R.id.cropView);
+
+        Intent cropIntent = this.getIntent();
+        final Uri imageUri = cropIntent.getData();
+
+        mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
+        mCropView.setTouchEnabled(true);
+        // Action bar
+        // Show the custom action bar view
+        final ActionBar actionBar = getActionBar();
+        actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
+        actionBar.getCustomView().setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        boolean finishActivityWhenDone = true;
+                        cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
+                    }
+                });
+    }
+
+    public static String getSharedPreferencesKey() {
+        return WallpaperCropActivity.class.getName();
+    }
+
+    // As a ratio of screen height, the total distance we want the parallax effect to span
+    // horizontally
+    private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
+        float aspectRatio = width / (float) height;
+
+        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
+        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
+        // We will use these two data points to extrapolate how much the wallpaper parallax effect
+        // to span (ie travel) at any aspect ratio:
+
+        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
+        final float ASPECT_RATIO_PORTRAIT = 10/16f;
+        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
+        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
+
+        // To find out the desired width at different aspect ratios, we use the following two
+        // formulas, where the coefficient on x is the aspect ratio (width/height):
+        //   (16/10)x + y = 1.5
+        //   (10/16)x + y = 1.2
+        // We solve for x and y and end up with a final formula:
+        final float x =
+            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
+            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
+        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
+        return x * aspectRatio + y;
+    }
+
+    static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
+        Point minDims = new Point();
+        Point maxDims = new Point();
+        windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+
+        int maxDim = Math.max(maxDims.x, maxDims.y);
+        int minDim = Math.max(minDims.x, minDims.y);
+
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            Point realSize = new Point();
+            windowManager.getDefaultDisplay().getRealSize(realSize);
+            maxDim = Math.max(realSize.x, realSize.y);
+            minDim = Math.min(realSize.x, realSize.y);
+        }
+
+        // We need to ensure that there is enough extra space in the wallpaper
+        // for the intended
+        // parallax effects
+        final int defaultWidth, defaultHeight;
+        if (isScreenLarge(res)) {
+            defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+            defaultHeight = maxDim;
+        } else {
+            defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+            defaultHeight = maxDim;
+        }
+        return new Point(defaultWidth, defaultHeight);
+    }
+
+    protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
+
+        BitmapCropTask cropTask = new BitmapCropTask(this,
+                filePath, null, 0, 0, true, false, null);
+        final Point bounds = cropTask.getImageBounds();
+        Runnable onEndCrop = new Runnable() {
+            public void run() {
+                updateWallpaperDimensions(bounds.x, bounds.y);
+                if (finishActivityWhenDone) {
+                    setResult(Activity.RESULT_OK);
+                    finish();
+                }
+            }
+        };
+        cropTask.setOnEndRunnable(onEndCrop);
+        cropTask.setNoCrop(true);
+        cropTask.execute();
+    }
+
+    protected void cropImageAndSetWallpaper(
+            Resources res, int resId, final boolean finishActivityWhenDone) {
+        // crop this image and scale it down to the default wallpaper size for
+        // this device
+        Point inSize = mCropView.getSourceDimensions();
+        Point outSize = getDefaultWallpaperSize(getResources(),
+                getWindowManager());
+        RectF crop = getMaxCropRect(
+                inSize.x, inSize.y, outSize.x, outSize.y, false);
+        Runnable onEndCrop = new Runnable() {
+            public void run() {
+                // Passing 0, 0 will cause launcher to revert to using the
+                // default wallpaper size
+                updateWallpaperDimensions(0, 0);
+                if (finishActivityWhenDone) {
+                    setResult(Activity.RESULT_OK);
+                    finish();
+                }
+            }
+        };
+        BitmapCropTask cropTask = new BitmapCropTask(res, resId,
+                crop, outSize.x, outSize.y,
+                true, false, onEndCrop);
+        cropTask.execute();
+    }
+
+    private static boolean isScreenLarge(Resources res) {
+        Configuration config = res.getConfiguration();
+        return config.smallestScreenWidthDp >= 720;
+    }
+
+    protected void cropImageAndSetWallpaper(Uri uri,
+            OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
+     // Get the crop
+        Point inSize = mCropView.getSourceDimensions();
+
+        Point minDims = new Point();
+        Point maxDims = new Point();
+        Display d = getWindowManager().getDefaultDisplay();
+        d.getCurrentSizeRange(minDims, maxDims);
+
+        Point displaySize = new Point();
+        d.getSize(displaySize);
+
+        int maxDim = Math.max(maxDims.x, maxDims.y);
+        final int minDim = Math.min(minDims.x, minDims.y);
+        int defaultWidth;
+        if (isScreenLarge(getResources())) {
+            defaultWidth = (int) (maxDim *
+                    wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+        } else {
+            defaultWidth = Math.max((int)
+                    (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+        }
+
+        boolean isPortrait = displaySize.x < displaySize.y;
+        int portraitHeight;
+        if (isPortrait) {
+            portraitHeight = mCropView.getHeight();
+        } else {
+            // TODO: how to actually get the proper portrait height?
+            // This is not quite right:
+            portraitHeight = Math.max(maxDims.x, maxDims.y);
+        }
+        if (android.os.Build.VERSION.SDK_INT >=
+                android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            Point realSize = new Point();
+            d.getRealSize(realSize);
+            portraitHeight = Math.max(realSize.x, realSize.y);
+        }
+        // Get the crop
+        RectF cropRect = mCropView.getCrop();
+        float cropScale = mCropView.getWidth() / (float) cropRect.width();
+
+        // ADJUST CROP WIDTH
+        // Extend the crop all the way to the right, for parallax
+        float extraSpaceToRight = inSize.x - cropRect.right;
+        // Cap the amount of extra width
+        float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
+        extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
+
+        cropRect.right += extraSpaceToRight;
+
+        // ADJUST CROP HEIGHT
+        if (isPortrait) {
+            cropRect.bottom = cropRect.top + portraitHeight / cropScale;
+        } else { // LANDSCAPE
+            float extraPortraitHeight =
+                    portraitHeight / cropScale - cropRect.height();
+            float expandHeight =
+                    Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
+                            extraPortraitHeight / 2);
+            cropRect.top -= expandHeight;
+            cropRect.bottom += expandHeight;
+        }
+        final int outWidth = (int) Math.round(cropRect.width() * cropScale);
+        final int outHeight = (int) Math.round(cropRect.height() * cropScale);
+
+        Runnable onEndCrop = new Runnable() {
+            public void run() {
+                updateWallpaperDimensions(outWidth, outHeight);
+                if (finishActivityWhenDone) {
+                    setResult(Activity.RESULT_OK);
+                    finish();
+                }
+            }
+        };
+        BitmapCropTask cropTask = new BitmapCropTask(uri,
+                cropRect, outWidth, outHeight, true, false, onEndCrop);
+        if (onBitmapCroppedHandler != null) {
+            cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
+        }
+        cropTask.execute();
+    }
+
+    public interface OnBitmapCroppedHandler {
+        public void onBitmapCropped(byte[] imageBytes);
+    }
+
+    protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
+        Uri mInUri = null;
+        Context mContext;
+        String mInFilePath;
+        byte[] mInImageBytes;
+        int mInResId = 0;
+        InputStream mInStream;
+        RectF mCropBounds = null;
+        int mOutWidth, mOutHeight;
+        int mRotation = 0; // for now
+        protected final WallpaperManager mWPManager;
+        String mOutputFormat = "jpg"; // for now
+        boolean mSetWallpaper;
+        boolean mSaveCroppedBitmap;
+        Bitmap mCroppedBitmap;
+        Runnable mOnEndRunnable;
+        Resources mResources;
+        OnBitmapCroppedHandler mOnBitmapCroppedHandler;
+        boolean mNoCrop;
+
+        public BitmapCropTask(Context c, String filePath,
+                RectF cropBounds, int outWidth, int outHeight,
+                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            mContext = c;
+            mInFilePath = filePath;
+            mWPManager = WallpaperManager.getInstance(getApplicationContext());
+            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+        }
+
+        public BitmapCropTask(byte[] imageBytes,
+                RectF cropBounds, int outWidth, int outHeight,
+                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            mInImageBytes = imageBytes;
+            mWPManager = WallpaperManager.getInstance(getApplicationContext());
+            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+        }
+
+        public BitmapCropTask(Uri inUri,
+                RectF cropBounds, int outWidth, int outHeight,
+                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            mInUri = inUri;
+            mWPManager = WallpaperManager.getInstance(getApplicationContext());
+            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+        }
+
+        public BitmapCropTask(Resources res, int inResId,
+                RectF cropBounds, int outWidth, int outHeight,
+                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            mInResId = inResId;
+            mResources = res;
+            mWPManager = WallpaperManager.getInstance(getApplicationContext());
+            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+        }
+
+        private void init(RectF cropBounds, int outWidth, int outHeight,
+                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            mCropBounds = cropBounds;
+            mOutWidth = outWidth;
+            mOutHeight = outHeight;
+            mSetWallpaper = setWallpaper;
+            mSaveCroppedBitmap = saveCroppedBitmap;
+            mOnEndRunnable = onEndRunnable;
+        }
+
+        public void setOnBitmapCropped(OnBitmapCroppedHandler handler) {
+            mOnBitmapCroppedHandler = handler;
+        }
+
+        public void setNoCrop(boolean value) {
+            mNoCrop = value;
+        }
+
+        public void setOnEndRunnable(Runnable onEndRunnable) {
+            mOnEndRunnable = onEndRunnable;
+        }
+
+        // Helper to setup input stream
+        private void regenerateInputStream() {
+            if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
+                Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
+                        "image byte array given");
+            } else {
+                Utils.closeSilently(mInStream);
+                try {
+                    if (mInUri != null) {
+                        mInStream = new BufferedInputStream(
+                                getContentResolver().openInputStream(mInUri));
+                    } else if (mInFilePath != null) {
+                        mInStream = mContext.openFileInput(mInFilePath);
+                    } else if (mInImageBytes != null) {
+                        mInStream = new BufferedInputStream(
+                                new ByteArrayInputStream(mInImageBytes));
+                    } else {
+                        mInStream = new BufferedInputStream(
+                                mResources.openRawResource(mInResId));
+                    }
+                } catch (FileNotFoundException e) {
+                    Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
+                }
+            }
+        }
+
+        public Point getImageBounds() {
+            regenerateInputStream();
+            if (mInStream != null) {
+                BitmapFactory.Options options = new BitmapFactory.Options();
+                options.inJustDecodeBounds = true;
+                BitmapFactory.decodeStream(mInStream, null, options);
+                if (options.outWidth != 0 && options.outHeight != 0) {
+                    return new Point(options.outWidth, options.outHeight);
+                }
+            }
+            return null;
+        }
+
+        public void setCropBounds(RectF cropBounds) {
+            mCropBounds = cropBounds;
+        }
+
+        public Bitmap getCroppedBitmap() {
+            return mCroppedBitmap;
+        }
+        public boolean cropBitmap() {
+            boolean failure = false;
+
+            regenerateInputStream();
+
+            if (mNoCrop && mInStream != null) {
+                try {
+                    mWPManager.setStream(mInStream);
+                } catch (IOException e) {
+                    Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+                    failure = true;
+                }
+                if (mOnEndRunnable != null) {
+                    mOnEndRunnable.run();
+                }
+                return !failure;
+            }
+            if (mInStream != null) {
+                // Find crop bounds (scaled to original image size)
+                Rect roundedTrueCrop = new Rect();
+                mCropBounds.roundOut(roundedTrueCrop);
+
+                if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
+                    Log.w(LOGTAG, "crop has bad values for full size image");
+                    failure = true;
+                    return false;
+                }
+
+                // See how much we're reducing the size of the image
+                int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth,
+                        roundedTrueCrop.height() / mOutHeight);
+
+                // Attempt to open a region decoder
+                BitmapRegionDecoder decoder = null;
+                try {
+                    decoder = BitmapRegionDecoder.newInstance(mInStream, true);
+                } catch (IOException e) {
+                    Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
+                }
+
+                Bitmap crop = null;
+                if (decoder != null) {
+                    // Do region decoding to get crop bitmap
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    if (scaleDownSampleSize > 1) {
+                        options.inSampleSize = scaleDownSampleSize;
+                    }
+                    crop = decoder.decodeRegion(roundedTrueCrop, options);
+                    decoder.recycle();
+                }
+
+                if (crop == null) {
+                    // BitmapRegionDecoder has failed, try to crop in-memory
+                    regenerateInputStream();
+                    Bitmap fullSize = null;
+                    if (mInStream != null) {
+                        BitmapFactory.Options options = new BitmapFactory.Options();
+                        if (scaleDownSampleSize > 1) {
+                            options.inSampleSize = scaleDownSampleSize;
+                        }
+                        fullSize = BitmapFactory.decodeStream(mInStream, null, options);
+                    }
+                    if (fullSize != null) {
+                        crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
+                                roundedTrueCrop.top, roundedTrueCrop.width(),
+                                roundedTrueCrop.height());
+                    }
+                }
+
+                if (crop == null) {
+                    Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
+                    failure = true;
+                    return false;
+                }
+                if (mOutWidth > 0 && mOutHeight > 0) {
+                    Matrix m = new Matrix();
+                    RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
+                    if (mRotation > 0) {
+                        m.setRotate(mRotation);
+                        m.mapRect(cropRect);
+                    }
+                    RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
+                    m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+                    m.preRotate(mRotation);
+                    Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
+                            (int) returnRect.height(), Bitmap.Config.ARGB_8888);
+                    if (tmp != null) {
+                        Canvas c = new Canvas(tmp);
+                        c.drawBitmap(crop, m, new Paint());
+                        crop = tmp;
+                    }
+                } else if (mRotation > 0) {
+                    Matrix m = new Matrix();
+                    m.setRotate(mRotation);
+                    Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),
+                            crop.getHeight(), m, true);
+                    if (tmp != null) {
+                        crop = tmp;
+                    }
+                }
+
+                if (mSaveCroppedBitmap) {
+                    mCroppedBitmap = crop;
+                }
+
+                // Get output compression format
+                CompressFormat cf =
+                        convertExtensionToCompressFormat(getFileExtension(mOutputFormat));
+
+                // Compress to byte array
+                ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+                if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
+                    // If we need to set to the wallpaper, set it
+                    if (mSetWallpaper && mWPManager != null) {
+                        if (mWPManager == null) {
+                            Log.w(LOGTAG, "no wallpaper manager");
+                            failure = true;
+                        } else {
+                            try {
+                                byte[] outByteArray = tmpOut.toByteArray();
+                                mWPManager.setStream(new ByteArrayInputStream(outByteArray));
+                                if (mOnBitmapCroppedHandler != null) {
+                                    mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
+                                }
+                            } catch (IOException e) {
+                                Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+                                failure = true;
+                            }
+                        }
+                    }
+                    if (mOnEndRunnable != null) {
+                        mOnEndRunnable.run();
+                    }
+                } else {
+                    Log.w(LOGTAG, "cannot compress bitmap");
+                    failure = true;
+                }
+            }
+            return !failure; // True if any of the operations failed
+        }
+
+        @Override
+        protected Boolean doInBackground(Void... params) {
+            return cropBitmap();
+        }
+
+        @Override
+        protected void onPostExecute(Boolean result) {
+            setResult(Activity.RESULT_OK);
+            finish();
+        }
+    }
+
+    protected void updateWallpaperDimensions(int width, int height) {
+        String spKey = getSharedPreferencesKey();
+        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
+        SharedPreferences.Editor editor = sp.edit();
+        if (width != 0 && height != 0) {
+            editor.putInt(WALLPAPER_WIDTH_KEY, width);
+            editor.putInt(WALLPAPER_HEIGHT_KEY, height);
+        } else {
+            editor.remove(WALLPAPER_WIDTH_KEY);
+            editor.remove(WALLPAPER_HEIGHT_KEY);
+        }
+        editor.commit();
+
+        suggestWallpaperDimension(getResources(),
+                sp, getWindowManager(), WallpaperManager.getInstance(this));
+    }
+
+    static public void suggestWallpaperDimension(Resources res,
+            final SharedPreferences sharedPrefs,
+            WindowManager windowManager,
+            final WallpaperManager wallpaperManager) {
+        final Point defaultWallpaperSize =
+                WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
+
+        new Thread("suggestWallpaperDimension") {
+            public void run() {
+                // If we have saved a wallpaper width/height, use that instead
+                int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
+                int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
+                wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
+            }
+        }.start();
+    }
+
+
+    protected static RectF getMaxCropRect(
+            int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
+        RectF cropRect = new RectF();
+        // Get a crop rect that will fit this
+        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
+             cropRect.top = 0;
+             cropRect.bottom = inHeight;
+             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
+             cropRect.right = inWidth - cropRect.left;
+             if (leftAligned) {
+                 cropRect.right -= cropRect.left;
+                 cropRect.left = 0;
+             }
+        } else {
+            cropRect.left = 0;
+            cropRect.right = inWidth;
+            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
+            cropRect.bottom = inHeight - cropRect.top;
+        }
+        return cropRect;
+    }
+
+    protected static CompressFormat convertExtensionToCompressFormat(String extension) {
+        return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
+    }
+
+    protected static String getFileExtension(String requestFormat) {
+        String outputFormat = (requestFormat == null)
+                ? "jpg"
+                : requestFormat;
+        outputFormat = outputFormat.toLowerCase();
+        return (outputFormat.equals("png") || outputFormat.equals("gif"))
+                ? "png" // We don't support gif compression.
+                : "jpg";
+    }
+}
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
new file mode 100644
index 0000000..d9566d5
--- /dev/null
+++ b/packages/services/PacProcessor/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 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
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := PacProcessor
+LOCAL_CERTIFICATE := platform
+
+LOCAL_REQUIRED_MODULES := libjni_pacprocessor
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/services/PacProcessor/AndroidManifest.xml b/packages/services/PacProcessor/AndroidManifest.xml
new file mode 100644
index 0000000..6740c16
--- /dev/null
+++ b/packages/services/PacProcessor/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.pacprocessor">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:label="@string/app_name">
+
+        <service android:name=".PacService"
+            android:exported="true">
+        </service>
+
+    </application>
+
+</manifest>
diff --git a/packages/services/PacProcessor/com/android/net/IProxyService.aidl b/packages/services/PacProcessor/com/android/net/IProxyService.aidl
new file mode 100644
index 0000000..4e54aba
--- /dev/null
+++ b/packages/services/PacProcessor/com/android/net/IProxyService.aidl
@@ -0,0 +1,27 @@
+/**
+ * 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.net;
+
+/** @hide */
+interface IProxyService
+{
+    String resolvePacFile(String host, String url);
+
+    oneway void setPacFile(String scriptContents);
+
+    oneway void startPacSystem();
+    oneway void stopPacSystem();
+}
diff --git a/packages/services/PacProcessor/jni/Android.mk b/packages/services/PacProcessor/jni/Android.mk
new file mode 100644
index 0000000..f16c90b
--- /dev/null
+++ b/packages/services/PacProcessor/jni/Android.mk
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    jni_init.cpp \
+    com_android_pacprocessor_PacNative.cpp
+
+LOCAL_C_INCLUDES += \
+    external/chromium-libpac/src
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroidfw \
+    libandroid_runtime \
+    liblog \
+    libutils \
+    libnativehelper \
+    libpac
+
+LOCAL_MODULE := libjni_pacprocessor
+LOCAL_MODULE_TAGS := optional
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
new file mode 100644
index 0000000..c5aa13b
--- /dev/null
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PacProcessor"
+
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include "android_runtime/AndroidRuntime.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "proxy_resolver_v8.h"
+
+namespace android {
+
+class ProxyErrorLogger : public net::ProxyErrorListener {
+public:
+    ~ProxyErrorLogger() {
+
+    }
+    void AlertMessage(String16 message) {
+        String8 str(message);
+        ALOGD("Alert: %s", str.string());
+    }
+    void ErrorMessage(String16 message) {
+        String8 str(message);
+        ALOGE("Error: %s", str.string());
+    }
+};
+
+net::ProxyResolverV8* proxyResolver = NULL;
+ProxyErrorLogger* logger = NULL;
+bool pacSet = false;
+
+String16 jstringToString16(JNIEnv* env, jstring jstr) {
+    const jchar* str = env->GetStringCritical(jstr, 0);
+    String16 str16(str, env->GetStringLength(jstr));
+    env->ReleaseStringCritical(jstr, str);
+    return str16;
+}
+
+jstring string16ToJstring(JNIEnv* env, String16 string) {
+    const char16_t* str = string.string();
+    size_t len = string.size();
+
+    return env->NewString(str, len);
+}
+
+static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* env, 
+        jobject) {
+    if (proxyResolver == NULL) {
+        logger = new ProxyErrorLogger();
+        proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault(),
+                logger);
+        pacSet = false;
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* env, 
+        jobject) {
+    if (proxyResolver != NULL) {
+        delete logger;
+        delete proxyResolver;
+        logger = NULL;
+        proxyResolver = NULL;
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+static jboolean com_android_pacprocessor_PacNative_setProxyScriptNativeLocked(JNIEnv* env, jobject,
+        jstring script) {
+    String16 script16 = jstringToString16(env, script);
+
+    if (proxyResolver == NULL) {
+        ALOGE("V8 Parser not started when setting PAC script");
+        return JNI_TRUE;
+    }
+
+    if (proxyResolver->SetPacScript(script16) != OK) {
+        ALOGE("Unable to set PAC script");
+        return JNI_TRUE;
+    }
+    pacSet = true;
+
+    return JNI_FALSE;
+}
+
+static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(JNIEnv* env, jobject,
+        jstring url, jstring host) {
+    String16 url16 = jstringToString16(env, url);
+    String16 host16 = jstringToString16(env, host);
+    String16 ret;
+
+    if (proxyResolver == NULL) {
+        ALOGE("V8 Parser not initialized when running PAC script");
+        return NULL;
+    }
+
+    if (!pacSet) {
+        ALOGW("Attempting to run PAC with no script set");
+        return NULL;
+    }
+
+    if (proxyResolver->GetProxyForURL(url16, host16, &ret) != OK) {
+        String8 ret8(ret);
+        ALOGE("Error Running PAC: %s", ret8.string());
+        return NULL;
+    }
+
+    jstring jret = string16ToJstring(env, ret);
+
+    return jret;
+}
+
+static JNINativeMethod gMethods[] = {
+    { "createV8ParserNativeLocked", "()Z",
+        (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked},
+    { "destroyV8ParserNativeLocked", "()Z",
+        (void*)com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked},
+    { "setProxyScriptNativeLocked", "(Ljava/lang/String;)Z",
+        (void*)com_android_pacprocessor_PacNative_setProxyScriptNativeLocked},
+    { "makeProxyRequestNativeLocked", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+        (void*)com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked},
+};
+
+int register_com_android_pacprocessor_PacNative(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/pacprocessor/PacNative",
+            gMethods, NELEM(gMethods));
+}
+
+} /* namespace android */
diff --git a/packages/services/PacProcessor/jni/jni_init.cpp b/packages/services/PacProcessor/jni/jni_init.cpp
new file mode 100644
index 0000000..bda33fb
--- /dev/null
+++ b/packages/services/PacProcessor/jni/jni_init.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PacProcessor"
+
+#include <utils/Log.h>
+#include "jni.h"
+
+namespace android {
+    extern int register_com_android_pacprocessor_PacNative(JNIEnv *env);
+}
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+    JNIEnv *env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("ERROR: GetEnv failed");
+        return -1;
+    }
+
+    register_com_android_pacprocessor_PacNative(env);
+
+    return JNI_VERSION_1_6;
+}
diff --git a/packages/services/PacProcessor/res/values/strings.xml b/packages/services/PacProcessor/res/values/strings.xml
new file mode 100644
index 0000000..301a2b6
--- /dev/null
+++ b/packages/services/PacProcessor/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">PacProcessor</string>
+
+</resources>
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java
new file mode 100644
index 0000000..c67fe9f
--- /dev/null
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java
@@ -0,0 +1,86 @@
+/**
+ * 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.pacprocessor;
+
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class PacNative {
+    private static final String TAG = "PacProxy";
+
+    private String mCurrentPac;
+
+    private boolean mIsActive;
+
+    // Only make native calls from inside synchronized blocks.
+    private native boolean createV8ParserNativeLocked();
+    private native boolean destroyV8ParserNativeLocked();
+
+    private native boolean setProxyScriptNativeLocked(String script);
+
+    private native String makeProxyRequestNativeLocked(String url, String host);
+
+    static {
+        System.loadLibrary("jni_pacprocessor");
+    }
+
+    PacNative() {
+
+    }
+
+    public synchronized boolean startPacSupport() {
+        if (createV8ParserNativeLocked()) {
+            Log.e(TAG, "Unable to Create v8 Proxy Parser.");
+            return true;
+        }
+        mIsActive = true;
+        return false;
+    }
+
+    public synchronized boolean stopPacSupport() {
+        if (mIsActive) {
+            if (destroyV8ParserNativeLocked()) {
+                Log.e(TAG, "Unable to Destroy v8 Proxy Parser.");
+                return true;
+            }
+            mIsActive = false;
+        }
+        return false;
+    }
+
+    public synchronized boolean setCurrentProxyScript(String script) {
+        if (setProxyScriptNativeLocked(script)) {
+            Log.e(TAG, "Unable to parse proxy script.");
+            return true;
+        }
+        return false;
+    }
+
+    public synchronized String makeProxyRequest(String url, String host) {
+        String ret = makeProxyRequestNativeLocked(url, host);
+        if ((ret == null) || (ret.length() == 0)) {
+            Log.e(TAG, "v8 Proxy request failed.");
+            ret = null;
+        }
+        return ret;
+    }
+
+    public synchronized boolean isActive() {
+        return mIsActive;
+    }
+}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
new file mode 100644
index 0000000..c6b76f1
--- /dev/null
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -0,0 +1,115 @@
+/**
+ * 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.pacprocessor;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.net.IProxyService;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class PacService extends Service {
+    private static final String TAG = "PacService";
+
+    private PacNative mPacNative;
+    private ProxyServiceStub mStub;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (mPacNative == null) {
+            mPacNative = new PacNative();
+            mStub = new ProxyServiceStub(mPacNative);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mPacNative != null) {
+            mPacNative.stopPacSupport();
+            mPacNative = null;
+            mStub = null;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mPacNative == null) {
+            mPacNative = new PacNative();
+            mStub = new ProxyServiceStub(mPacNative);
+        }
+        return mStub;
+    }
+
+    private static class ProxyServiceStub extends IProxyService.Stub {
+        private final PacNative mPacNative;
+
+        public ProxyServiceStub(PacNative pacNative) {
+            mPacNative = pacNative;
+        }
+
+        @Override
+        public String resolvePacFile(String host, String url) throws RemoteException {
+            try {
+                // Check for characters that could be used for an injection attack.
+                new URL(url);
+                for (char c : host.toCharArray()) {
+                    if (!Character.isLetterOrDigit(c) && (c != '.') && (c != '-')) {
+                        throw new RemoteException("Invalid host was passed");
+                    }
+                }
+                return mPacNative.makeProxyRequest(url, host);
+            } catch (MalformedURLException e) {
+                throw new RemoteException("Invalid URL was passed");
+            }
+        }
+
+        @Override
+        public void setPacFile(String script) throws RemoteException {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                Log.e(TAG, "Only system user is allowed to call setPacFile");
+                throw new SecurityException();
+            }
+            mPacNative.setCurrentProxyScript(script);
+        }
+
+        @Override
+        public void startPacSystem() throws RemoteException {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                Log.e(TAG, "Only system user is allowed to call startPacSystem");
+                throw new SecurityException();
+            }
+            mPacNative.startPacSupport();
+        }
+
+        @Override
+        public void stopPacSystem() throws RemoteException {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                Log.e(TAG, "Only system user is allowed to call stopPacSystem");
+                throw new SecurityException();
+            }
+            mPacNative.stopPacSupport();
+        }
+    }
+}
diff --git a/packages/services/Proxy/Android.mk b/packages/services/Proxy/Android.mk
new file mode 100644
index 0000000..d5546b2
--- /dev/null
+++ b/packages/services/Proxy/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ProxyHandler
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/services/Proxy/AndroidManifest.xml b/packages/services/Proxy/AndroidManifest.xml
new file mode 100644
index 0000000..bbcd6b9
--- /dev/null
+++ b/packages/services/Proxy/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        package="com.android.proxyhandler"
+        coreApp="true">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:label="@string/app_label"
+        android:process="com.android.proxyhandler">
+
+        <service android:name=".ProxyService"
+            android:exported="true">
+        </service>
+
+    </application>
+</manifest>
diff --git a/packages/services/Proxy/com/android/net/IProxyCallback.aidl b/packages/services/Proxy/com/android/net/IProxyCallback.aidl
new file mode 100644
index 0000000..26b2a3f
--- /dev/null
+++ b/packages/services/Proxy/com/android/net/IProxyCallback.aidl
@@ -0,0 +1,22 @@
+/**
+ * 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.net;
+
+/** @hide */
+interface IProxyCallback
+{
+    oneway void getProxyPort(IBinder callback);
+}
diff --git a/packages/services/Proxy/com/android/net/IProxyPortListener.aidl b/packages/services/Proxy/com/android/net/IProxyPortListener.aidl
new file mode 100644
index 0000000..fa4caf3
--- /dev/null
+++ b/packages/services/Proxy/com/android/net/IProxyPortListener.aidl
@@ -0,0 +1,22 @@
+/**
+ * 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.net;
+
+/** @hide */
+interface IProxyPortListener
+{
+    oneway void setProxyPort(int port);
+}
diff --git a/packages/services/Proxy/res/values/strings.xml b/packages/services/Proxy/res/values/strings.xml
new file mode 100644
index 0000000..6188d79
--- /dev/null
+++ b/packages/services/Proxy/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label">ProxyHandler</string>
+
+</resources>
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
new file mode 100644
index 0000000..596435a
--- /dev/null
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -0,0 +1,271 @@
+/**
+ * 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.proxyhandler;
+
+import android.net.ProxyProperties;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.net.IProxyPortListener;
+import com.google.android.collect.Lists;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @hide
+ */
+public class ProxyServer extends Thread {
+
+    private static final String CONNECT = "CONNECT";
+    private static final String HTTP_OK = "HTTP/1.1 200 OK\n";
+
+    private static final String TAG = "ProxyServer";
+
+    private ExecutorService threadExecutor;
+
+    public boolean mIsRunning = false;
+
+    private ServerSocket serverSocket;
+    private int mPort;
+    private IProxyPortListener mCallback;
+
+    private class ProxyConnection implements Runnable {
+        private Socket connection;
+
+        private ProxyConnection(Socket connection) {
+            this.connection = connection;
+        }
+
+        @Override
+        public void run() {
+            try {
+                String requestLine = getLine(connection.getInputStream());
+                if (requestLine == null) {
+                    connection.close();
+                    return;
+                }
+                String[] splitLine = requestLine.split(" ");
+                if (splitLine.length < 3) {
+                    connection.close();
+                    return;
+                }
+                String requestType = splitLine[0];
+                String urlString = splitLine[1];
+
+                String host = "";
+                int port = 80;
+
+                if (requestType.equals(CONNECT)) {
+                    String[] hostPortSplit = urlString.split(":");
+                    host = hostPortSplit[0];
+                    try {
+                        port = Integer.parseInt(hostPortSplit[1]);
+                    } catch (NumberFormatException nfe) {
+                        port = 443;
+                    }
+                    urlString = "Https://" + host + ":" + port;
+                } else {
+                    try {
+                        URI url = new URI(urlString);
+                        host = url.getHost();
+                        port = url.getPort();
+                        if (port < 0) {
+                            port = 80;
+                        }
+                    } catch (URISyntaxException e) {
+                        connection.close();
+                        return;
+                    }
+                }
+
+                List<Proxy> list = Lists.newArrayList();
+                try {
+                    list = ProxySelector.getDefault().select(new URI(urlString));
+                } catch (URISyntaxException e) {
+                    e.printStackTrace();
+                }
+                Socket server = null;
+                for (Proxy proxy : list) {
+                    try {
+                        if (!proxy.equals(Proxy.NO_PROXY)) {
+                            // Only Inets created by PacProxySelector.
+                            InetSocketAddress inetSocketAddress =
+                                    (InetSocketAddress)list.get(0).address();
+                            server = new Socket(inetSocketAddress.getAddress(),
+                                    inetSocketAddress.getPort());
+                            sendLine(server, requestLine);
+                        } else {
+                            server = new Socket(host, port);
+                            if (requestType.equals(CONNECT)) {
+                                while (getLine(connection.getInputStream()).length() != 0);
+                                // No proxy to respond so we must.
+                                sendLine(connection, HTTP_OK);
+                            } else {
+                                sendLine(server, requestLine);
+                            }
+                        }
+                    } catch (IOException ioe) {
+
+                    }
+                    if (server != null) {
+                        break;
+                    }
+                }
+                if (server == null) {
+                    server = new Socket(host, port);
+                    if (requestType.equals(CONNECT)) {
+                        while (getLine(connection.getInputStream()).length() != 0);
+                        // No proxy to respond so we must.
+                        sendLine(connection, HTTP_OK);
+                    } else {
+                        sendLine(server, requestLine);
+                    }
+                }
+                // Pass data back and forth until complete.
+                SocketConnect.connect(connection, server);
+            } catch (IOException e) {
+                Log.d(TAG, "Problem Proxying", e);
+            }
+            try {
+                connection.close();
+            } catch (IOException ioe) {
+
+            }
+        }
+
+        private String getLine(InputStream inputStream) throws IOException {
+            StringBuffer buffer = new StringBuffer();
+            int byteBuffer = inputStream.read();
+            if (byteBuffer < 0) return "";
+            do {
+                if (byteBuffer != '\r') {
+                    buffer.append((char)byteBuffer);
+                }
+                byteBuffer = inputStream.read();
+            } while ((byteBuffer != '\n') && (byteBuffer >= 0));
+
+            return buffer.toString();
+        }
+
+        private void sendLine(Socket socket, String line) throws IOException {
+            OutputStream os = socket.getOutputStream();
+            os.write(line.getBytes());
+            os.write('\r');
+            os.write('\n');
+            os.flush();
+        }
+    }
+
+    public ProxyServer() {
+        threadExecutor = Executors.newCachedThreadPool();
+        mPort = -1;
+        mCallback = null;
+    }
+
+    @Override
+    public void run() {
+        try {
+            serverSocket = new ServerSocket(0);
+
+            if (serverSocket != null) {
+                setPort(serverSocket.getLocalPort());
+
+                while (mIsRunning) {
+                    try {
+                        Socket socket = serverSocket.accept();
+                        // Only receive local connections.
+                        if (socket.getInetAddress().isLoopbackAddress()) {
+                            ProxyConnection parser = new ProxyConnection(socket);
+
+                            threadExecutor.execute(parser);
+                        } else {
+                            socket.close();
+                        }
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        } catch (SocketException e) {
+            Log.e(TAG, "Failed to start proxy server", e);
+        } catch (IOException e1) {
+            Log.e(TAG, "Failed to start proxy server", e1);
+        }
+
+        mIsRunning = false;
+    }
+
+    public synchronized void setPort(int port) {
+        if (mCallback != null) {
+            try {
+                mCallback.setProxyPort(port);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Proxy failed to report port to PacManager", e);
+            }
+        }
+        mPort = port;
+    }
+
+    public synchronized void setCallback(IProxyPortListener callback) {
+        if (mPort != -1) {
+            try {
+                callback.setProxyPort(mPort);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Proxy failed to report port to PacManager", e);
+            }
+        }
+        mCallback = callback;
+    }
+
+    public synchronized void startServer() {
+        mIsRunning = true;
+        start();
+    }
+
+    public synchronized void stopServer() {
+        mIsRunning = false;
+        if (serverSocket != null) {
+            try {
+                serverSocket.close();
+                serverSocket = null;
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public boolean isBound() {
+        return (mPort != -1);
+    }
+
+    public int getPort() {
+        return mPort;
+    }
+}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
new file mode 100644
index 0000000..109435c
--- /dev/null
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
@@ -0,0 +1,75 @@
+/**
+ * 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.proxyhandler;
+
+import android.app.Service;
+import android.content.Intent;
+import android.net.Proxy;
+import android.net.ProxyProperties;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.text.TextUtils;
+
+import com.android.net.IProxyCallback;
+import com.android.net.IProxyPortListener;
+
+/**
+ * @hide
+ */
+public class ProxyService extends Service {
+
+    private static ProxyServer server = null;
+
+    /** Keep these values up-to-date with PacManager.java */
+    public static final String KEY_PROXY = "keyProxy";
+    public static final String HOST = "localhost";
+    // STOPSHIP This being a static port means it can be hijacked by other apps.
+    public static final int PORT = 8182;
+    public static final String EXCL_LIST = "";
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (server == null) {
+            server = new ProxyServer();
+            server.startServer();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (server != null) {
+            server.stopServer();
+            server = null;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new IProxyCallback.Stub() {
+            @Override
+            public void getProxyPort(IBinder callback) throws RemoteException {
+                if (server != null) {
+                    IProxyPortListener portListener = IProxyPortListener.Stub.asInterface(callback);
+                    if (portListener != null) {
+                        server.setCallback(portListener);
+                    }
+                }
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/SocketConnect.java b/packages/services/Proxy/src/com/android/proxyhandler/SocketConnect.java
new file mode 100644
index 0000000..0d7df7f
--- /dev/null
+++ b/packages/services/Proxy/src/com/android/proxyhandler/SocketConnect.java
@@ -0,0 +1,59 @@
+package com.android.proxyhandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * @hide
+ */
+public class SocketConnect extends Thread {
+
+    private InputStream from;
+    private OutputStream to;
+
+    public SocketConnect(Socket from, Socket to) throws IOException {
+        this.from = from.getInputStream();
+        this.to = to.getOutputStream();
+        start();
+    }
+
+    @Override
+    public void run() {
+        final byte[] buffer = new byte[512];
+
+        try {
+            while (true) {
+                int r = from.read(buffer);
+                if (r < 0) {
+                    break;
+                }
+                to.write(buffer, 0, r);
+            }
+            from.close();
+            to.close();
+        } catch (IOException io) {
+
+        }
+    }
+
+    public static void connect(Socket first, Socket second) {
+        try {
+            SocketConnect sc1 = new SocketConnect(first, second);
+            SocketConnect sc2 = new SocketConnect(second, first);
+            try {
+                sc1.join();
+            } catch (InterruptedException e) {
+            }
+            try {
+                sc2.join();
+            } catch (InterruptedException e) {
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+}
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
new file mode 100644
index 0000000..57c9675
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.app.StatusBarManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManagerPolicy.WindowState;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import java.io.PrintWriter;
+
+/**
+ * Controls state/behavior specific to a system bar window.
+ */
+public class BarController {
+    private static final boolean DEBUG = false;
+
+    private static final int TRANSIENT_BAR_NONE = 0;
+    private static final int TRANSIENT_BAR_SHOWING = 1;
+    private static final int TRANSIENT_BAR_HIDING = 2;
+
+    private static final int TRANSPARENT_ANIMATION_DELAY_MS = 1000;
+
+    private final String mTag;
+    private final int mTransientFlag;
+    private final int mUnhideFlag;
+    private final int mTransparentFlag;
+    private final int mStatusBarManagerId;
+    private final Handler mHandler;
+    private final Object mServiceAquireLock = new Object();
+    private IStatusBarService mStatusBarService;
+
+    private WindowState mWin;
+    private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
+    private int mTransientBarState;
+    private boolean mPendingShow;
+    private long mLastTransparent;
+
+    public BarController(String tag, int transientFlag, int unhideFlag, int transparentFlag,
+            int statusBarManagerId) {
+        mTag = "BarController." + tag;
+        mTransientFlag = transientFlag;
+        mUnhideFlag = unhideFlag;
+        mTransparentFlag = transparentFlag;
+        mStatusBarManagerId = statusBarManagerId;
+        mHandler = new Handler();
+    }
+
+    public void setWindow(WindowState win) {
+        mWin = win;
+    }
+
+    public boolean isHidden() {
+        return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
+    }
+
+    public void showTransient() {
+        if (mWin != null) {
+            setTransientBarState(TRANSIENT_BAR_SHOWING);
+        }
+    }
+
+    public boolean isTransientShowing() {
+        return mTransientBarState == TRANSIENT_BAR_SHOWING;
+    }
+
+    public boolean wasRecentlyTransparent() {
+        return (SystemClock.uptimeMillis() - mLastTransparent) < TRANSPARENT_ANIMATION_DELAY_MS;
+    }
+
+    public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
+        if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
+                (vis & mTransientFlag) == 0) {
+            // sysui requests hide
+            setTransientBarState(TRANSIENT_BAR_HIDING);
+            setBarShowingLw(false);
+        } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
+            // sysui ready to unhide
+            setBarShowingLw(true);
+        }
+    }
+
+    public boolean setBarShowingLw(final boolean show) {
+        if (mWin == null) return false;
+        if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
+            mPendingShow = true;
+            return false;
+        }
+        final boolean wasVis = mWin.isVisibleLw();
+        final boolean wasAnim = mWin.isAnimatingLw();
+        final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true);
+        final int state = computeStateLw(wasVis, wasAnim, mWin, change);
+        updateStateLw(state);
+        return change;
+    }
+
+    private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
+        if (win.hasDrawnLw()) {
+            final boolean vis = win.isVisibleLw();
+            final boolean anim = win.isAnimatingLw();
+            if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
+                return StatusBarManager.WINDOW_STATE_HIDDEN;
+            } else if (change) {
+                if (wasVis && vis && !wasAnim && anim) {
+                    return StatusBarManager.WINDOW_STATE_HIDING;
+                } else {
+                    return StatusBarManager.WINDOW_STATE_SHOWING;
+                }
+            }
+        }
+        return mState;
+    }
+
+    private void updateStateLw(final int state) {
+        if (state != mState) {
+            mState = state;
+            if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.setWindowState(mStatusBarManagerId, state);
+                        }
+                    } catch (RemoteException e) {
+                        if (DEBUG) Slog.w(mTag, "Error posting window state", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+    }
+
+    public boolean checkHiddenLw() {
+        if (mWin != null && mWin.hasDrawnLw()) {
+            if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
+                updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
+            }
+            if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
+                // Finished animating out, clean up and reset style
+                setTransientBarState(TRANSIENT_BAR_NONE);
+                if (mPendingShow) {
+                    setBarShowingLw(true);
+                    mPendingShow = false;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean checkShowTransientBarLw() {
+        if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
+            return false;
+        } else if (mWin == null) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
+            return false;
+        } else if (mWin.isDisplayedLw()) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public int updateVisibilityLw(boolean allowed, int oldVis, int vis) {
+        if (mWin == null) return vis;
+        if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
+            if (allowed) {
+                vis |= mTransientFlag;
+                if ((oldVis & mTransientFlag) == 0) {
+                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
+                }
+            } else {
+                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
+            }
+        }
+        if (mTransientBarState != TRANSIENT_BAR_NONE) {
+            vis |= mTransientFlag;  // ignore clear requests until transition completes
+            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
+        }
+        if ((vis & mTransparentFlag) != 0 || (oldVis & mTransparentFlag) != 0) {
+            mLastTransparent = SystemClock.uptimeMillis();
+        }
+        return vis;
+    }
+
+    private void setTransientBarState(int state) {
+        if (mWin != null && state != mTransientBarState) {
+            if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
+                mLastTransparent = SystemClock.uptimeMillis();
+            }
+            mTransientBarState = state;
+            if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
+        }
+    }
+
+    private IStatusBarService getStatusBarService() {
+        synchronized (mServiceAquireLock) {
+            if (mStatusBarService == null) {
+                mStatusBarService = IStatusBarService.Stub.asInterface(
+                        ServiceManager.getService("statusbar"));
+            }
+            return mStatusBarService;
+        }
+    }
+
+    private static String transientBarStateToString(int state) {
+        if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
+        if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
+        if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
+        throw new IllegalArgumentException("Unknown state " + state);
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        if (mWin != null) {
+            pw.print(prefix); pw.println(mTag);
+            pw.print(prefix); pw.print("  "); pw.print("mState"); pw.print('=');
+            pw.println(StatusBarManager.windowStateToString(mState));
+            pw.print(prefix); pw.print("  "); pw.print("mTransientBar"); pw.print('=');
+            pw.println(transientBarStateToString(mTransientBarState));
+        }
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index b978863..7c0735b 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -265,7 +265,7 @@
 
         // next: bug report, if enabled
         if (Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0) {
+                Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
             mItems.add(
                 new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
                         R.string.global_action_bug_report) {
@@ -349,16 +349,24 @@
         return dialog;
     }
 
+    private UserInfo getCurrentUser() {
+        try {
+            return ActivityManagerNative.getDefault().getCurrentUser();
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    private boolean isCurrentUserOwner() {
+        UserInfo currentUser = getCurrentUser();
+        return currentUser == null || currentUser.isPrimary();
+    }
+
     private void addUsersToMenu(ArrayList<Action> items) {
         List<UserInfo> users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
                 .getUsers();
         if (users.size() > 1) {
-            UserInfo currentUser;
-            try {
-                currentUser = ActivityManagerNative.getDefault().getCurrentUser();
-            } catch (RemoteException re) {
-                currentUser = null;
-            }
+            UserInfo currentUser = getCurrentUser();
             for (final UserInfo user : users) {
                 boolean isCurrentUser = currentUser == null
                         ? user.id == 0 : (currentUser.id == user.id);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index b72bb2b..417527c 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -102,7 +102,8 @@
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
             case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
                 handleMediaKeyEvent(event);
                 return true;
             }
@@ -215,7 +216,8 @@
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
             case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
                 handleMediaKeyEvent(event);
                 return true;
             }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 6b28e8e..11913ee 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,7 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
+import android.view.ViewConfiguration;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
@@ -49,6 +50,7 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -58,6 +60,7 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.ActionMode;
@@ -65,6 +68,7 @@
 import android.view.Gravity;
 import android.view.IRotationWatcher;
 import android.view.IWindowManager;
+import android.view.InputEvent;
 import android.view.InputQueue;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -77,6 +81,7 @@
 import android.view.ViewGroup;
 import android.view.ViewManager;
 import android.view.ViewParent;
+import android.view.ViewRootImpl;
 import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
@@ -139,6 +144,22 @@
     private ActionMenuPresenterCallback mActionMenuPresenterCallback;
     private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
 
+    // The icon resource has been explicitly set elsewhere
+    // and should not be overwritten with a default.
+    static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
+
+    // The logo resource has been explicitly set elsewhere
+    // and should not be overwritten with a default.
+    static final int FLAG_RESOURCE_SET_LOGO = 1 << 1;
+
+    // The icon resource is currently configured to use the system fallback
+    // as no default was previously specified. Anything can override this.
+    static final int FLAG_RESOURCE_SET_ICON_FALLBACK = 1 << 2;
+
+    int mResourcesSetFlags;
+    int mIconRes;
+    int mLogoRes;
+
     private DrawableFeatureState[] mDrawables;
 
     private PanelFeatureState[] mPanels;
@@ -520,7 +541,8 @@
     @Override
     public final void openPanel(int featureId, KeyEvent event) {
         if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
-                mActionBar.isOverflowReserved()) {
+                mActionBar.isOverflowReserved() &&
+                !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
             if (mActionBar.getVisibility() == View.VISIBLE) {
                 mActionBar.showOverflowMenu();
             }
@@ -529,7 +551,7 @@
         }
     }
 
-    private void openPanel(PanelFeatureState st, KeyEvent event) {
+    private void openPanel(final PanelFeatureState st, KeyEvent event) {
         // System.out.println("Open panel: isOpen=" + st.isOpen);
 
         // Already open, return
@@ -627,7 +649,6 @@
             }
         }
 
-        st.isOpen = true;
         st.isHandled = false;
 
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -645,15 +666,17 @@
         }
 
         lp.windowAnimations = st.windowAnimations;
-        
+
         wm.addView(st.decorView, lp);
+        st.isOpen = true;
         // Log.v(TAG, "Adding main menu to window manager.");
     }
 
     @Override
     public final void closePanel(int featureId) {
         if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
-                mActionBar.isOverflowReserved()) {
+                mActionBar.isOverflowReserved() &&
+                !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
             mActionBar.hideOverflowMenu();
         } else if (featureId == FEATURE_CONTEXT_MENU) {
             closeContextMenu();
@@ -816,7 +839,8 @@
             boolean playSoundEffect = false;
             final PanelFeatureState st = getPanelState(featureId, true);
             if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
-                    mActionBar.isOverflowReserved()) {
+                    mActionBar.isOverflowReserved() &&
+                    !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
                 if (mActionBar.getVisibility() == View.VISIBLE) {
                     if (!mActionBar.isOverflowMenuShowing()) {
                         if (!isDestroyed() && preparePanel(st, event)) {
@@ -994,7 +1018,9 @@
     }
 
     private void reopenMenu(boolean toggleMenuMode) {
-        if (mActionBar != null && mActionBar.isOverflowReserved()) {
+        if (mActionBar != null && mActionBar.isOverflowReserved() &&
+                (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
+                        mActionBar.isOverflowMenuShowPending())) {
             final Callback cb = getCallback();
             if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
                 if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
@@ -1393,6 +1419,75 @@
         }
     }
 
+    @Override
+    public void setIcon(int resId) {
+        mIconRes = resId;
+        mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
+        mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
+        if (mActionBar != null) {
+            mActionBar.setIcon(resId);
+        }
+    }
+
+    @Override
+    public void setDefaultIcon(int resId) {
+        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) {
+            return;
+        }
+        mIconRes = resId;
+        if (mActionBar != null && (!mActionBar.hasIcon() ||
+                (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
+            if (resId != 0) {
+                mActionBar.setIcon(resId);
+                mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
+            } else {
+                mActionBar.setIcon(getContext().getPackageManager().getDefaultActivityIcon());
+                mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
+            }
+        }
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        mLogoRes = resId;
+        mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
+        if (mActionBar != null) {
+            mActionBar.setLogo(resId);
+        }
+    }
+
+    @Override
+    public void setDefaultLogo(int resId) {
+        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) {
+            return;
+        }
+        mLogoRes = resId;
+        if (mActionBar != null && !mActionBar.hasLogo()) {
+            mActionBar.setLogo(resId);
+        }
+    }
+
+    @Override
+    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
+        getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);
+
+    }
+
+    @Override
+    public void injectInputEvent(InputEvent event) {
+        getViewRootImpl().dispatchInputEvent(event);
+    }
+
+    private ViewRootImpl getViewRootImpl() {
+        if (mDecor != null) {
+            ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
+            if (viewRootImpl != null) {
+                return viewRootImpl;
+            }
+        }
+        throw new IllegalStateException("view not added");
+    }
+
     /**
      * Request that key events come to this activity. Use this if your activity
      * has no views with focus, but the activity still wants a chance to process
@@ -2919,6 +3014,13 @@
                         mActionBar.initIndeterminateProgress();
                     }
 
+                    final ActionBarOverlayLayout abol = (ActionBarOverlayLayout) findViewById(
+                            com.android.internal.R.id.action_bar_overlay_layout);
+                    if (abol != null) {
+                        abol.setOverlayMode(
+                                (localFeatures & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0);
+                    }
+
                     boolean splitActionBar = false;
                     final boolean splitWhenNarrow =
                             (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
@@ -2946,6 +3048,20 @@
                                 "incompatible window decor! Ignoring request.");
                     }
 
+                    if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
+                            (mIconRes != 0 && !mActionBar.hasIcon())) {
+                        mActionBar.setIcon(mIconRes);
+                    } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
+                            mIconRes == 0 && !mActionBar.hasIcon()) {
+                        mActionBar.setIcon(
+                                getContext().getPackageManager().getDefaultActivityIcon());
+                        mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
+                    }
+                    if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
+                            (mLogoRes != 0 && !mActionBar.hasLogo())) {
+                        mActionBar.setLogo(mLogoRes);
+                    }
+
                     // Post the panel invalidate for later; avoid application onCreateOptionsMenu
                     // being called in the middle of onCreate or similar.
                     mDecor.post(new Runnable() {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b0cd11ae..7f93c28 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -21,6 +21,7 @@
 import android.app.IUiModeManager;
 import android.app.ProgressDialog;
 import android.app.SearchManager;
+import android.app.StatusBarManager;
 import android.app.UiModeManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -94,8 +95,7 @@
 
 import com.android.internal.R;
 import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.keyguard.KeyguardViewManager;
-import com.android.internal.policy.impl.keyguard.KeyguardViewMediator;
+import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.widget.PointerLocationView;
@@ -114,7 +114,7 @@
  * WindowManagerPolicy implementation for the Android phone UI.  This
  * introduces a new method suffix, Lp, for an internal lock of the
  * PhoneWindowManager.  This is used to protect some internal state, and
- * can be acquired with either thw Lw and Li lock held, so has the restrictions
+ * can be acquired with either the Lw and Li lock held, so has the restrictions
  * of both of those when held.
  */
 public class PhoneWindowManager implements WindowManagerPolicy {
@@ -162,7 +162,15 @@
      * of the screen to change.
      */
     static final int SYSTEM_UI_CHANGING_LAYOUT =
-            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
+              View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+            | View.SYSTEM_UI_FLAG_FULLSCREEN
+            | View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS
+            | View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION;
+
+    /**
+     * Keyguard stuff
+     */
+    private WindowState mKeyguardScrim;
 
     /* Table of Application Launch keys.  Maps from key codes to intent categories.
      *
@@ -209,13 +217,13 @@
 
     // Vibrator pattern for haptic feedback of virtual key press.
     long[] mVirtualKeyVibePattern;
-    
+
     // Vibrator pattern for a short vibration.
     long[] mKeyboardTapVibePattern;
 
     // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
     long[] mSafeModeDisabledVibePattern;
-    
+
     // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
     long[] mSafeModeEnabledVibePattern;
 
@@ -225,7 +233,6 @@
     boolean mHeadless;
     boolean mSafeMode;
     WindowState mStatusBar = null;
-    boolean mHasSystemNavBar;
     int mStatusBarHeight;
     WindowState mNavigationBar = null;
     boolean mHasNavigationBar = false;
@@ -236,7 +243,7 @@
     int[] mNavigationBarWidthForRotation = new int[4];
 
     WindowState mKeyguard = null;
-    KeyguardViewMediator mKeyguardMediator;
+    KeyguardServiceDelegate mKeyguardDelegate;
     GlobalActions mGlobalActions;
     volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
     boolean mPendingPowerKeyUpCanceled;
@@ -268,6 +275,10 @@
     int mDemoHdmiRotation;
     boolean mDemoHdmiRotationLock;
 
+    // Default display does not rotate, apps that require non-default orientation will have to
+    // have the orientation emulated.
+    private boolean mForceDefaultOrientation = false;
+
     int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
     int mUserRotation = Surface.ROTATION_0;
     boolean mAccelerometerDefault;
@@ -284,42 +295,25 @@
     boolean mOrientationSensorEnabled = false;
     int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mHasSoftInput = false;
-    
+
     int mPointerLocationMode = 0; // guarded by mLock
 
     // The last window we were told about in focusChanged.
     WindowState mFocusedWindow;
     IApplicationToken mFocusedApp;
 
-    private static final class PointerLocationInputEventReceiver extends InputEventReceiver {
-        private final PointerLocationView mView;
-
-        public PointerLocationInputEventReceiver(InputChannel inputChannel, Looper looper,
-                PointerLocationView view) {
-            super(inputChannel, looper);
-            mView = view;
-        }
-
+    private final class PointerLocationPointerEventListener implements PointerEventListener {
         @Override
-        public void onInputEvent(InputEvent event) {
-            boolean handled = false;
-            try {
-                if (event instanceof MotionEvent
-                        && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-                    final MotionEvent motionEvent = (MotionEvent)event;
-                    mView.addPointerEvent(motionEvent);
-                    handled = true;
-                }
-            } finally {
-                finishInputEvent(event, handled);
+        public void onPointerEvent(MotionEvent motionEvent) {
+            if (mPointerLocationView != null) {
+                mPointerLocationView.addPointerEvent(motionEvent);
             }
         }
     }
 
     // Pointer location view state, only modified on the mHandler Looper.
-    PointerLocationInputEventReceiver mPointerLocationInputEventReceiver;
+    PointerLocationPointerEventListener mPointerLocationPointerEventListener;
     PointerLocationView mPointerLocationView;
-    InputChannel mPointerLocationInputChannel;
 
     // The current size of the screen; really; extends into the overscan area of
     // the screen and doesn't account for any system elements like the status bar.
@@ -381,7 +375,7 @@
     static final Rect mTmpContentFrame = new Rect();
     static final Rect mTmpVisibleFrame = new Rect();
     static final Rect mTmpNavigationFrame = new Rect();
-    
+
     WindowState mTopFullscreenOpaqueWindowState;
     boolean mTopIsFullscreen;
     boolean mForceStatusBar;
@@ -456,11 +450,16 @@
     private boolean mPowerKeyTriggered;
     private long mPowerKeyTime;
 
+    /* The number of steps between min and max brightness */
+    private static final int BRIGHTNESS_STEPS = 10;
+
     SettingsObserver mSettingsObserver;
     ShortcutManager mShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
     boolean mHavePendingMediaKeyRepeatWithWakeLock;
 
+    private int mCurrentUserId;
+
     // Maps global key codes to the components that will handle them.
     private GlobalKeyManager mGlobalKeyManager;
 
@@ -530,7 +529,7 @@
                     Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.System.getUriFor(
-                    "fancy_rotation_anim"), false, this,
+                    Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS), false, this,
                     UserHandle.USER_ALL);
             updateSettings();
         }
@@ -540,20 +539,36 @@
             updateRotation(false);
         }
     }
-    
+
     class MyOrientationListener extends WindowOrientationListener {
         MyOrientationListener(Context context, Handler handler) {
             super(context, handler);
         }
-        
+
         @Override
         public void onProposedRotationChanged(int rotation) {
-            if (localLOGV) Log.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
+            if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
             updateRotation(false);
         }
     }
     MyOrientationListener mOrientationListener;
 
+    private final BarController mStatusBarController = new BarController("StatusBar",
+            View.STATUS_BAR_TRANSIENT,
+            View.STATUS_BAR_UNHIDE,
+            View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS,
+            StatusBarManager.WINDOW_STATUS_BAR);
+
+    private final BarController mNavigationBarController = new BarController("NavigationBar",
+            View.NAVIGATION_BAR_TRANSIENT,
+            View.NAVIGATION_BAR_UNHIDE,
+            View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION,
+            StatusBarManager.WINDOW_NAVIGATION_BAR);
+
+    private TransientNavigationConfirmation mTransientNavigationConfirmation;
+
+    private SystemGesturesPointerEventListener mSystemGestures;
+
     IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
             if (mStatusBarService == null) {
@@ -599,11 +614,11 @@
         }
         return true;
     }
-    
+
     /*
      * Various use cases for invoking this function
      * screen turning off, should always disable listeners if already enabled
-     * screen turned on and current app has sensor based orientation, enable listeners 
+     * screen turned on and current app has sensor based orientation, enable listeners
      * if not already enabled
      * screen turned on and current app does not have sensor orientation, disable listeners if
      * already enabled
@@ -617,7 +632,7 @@
         }
         //Could have been invoked due to screen turning on or off or
         //change of the currently visible window's orientation
-        if (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+
+        if (localLOGV) Slog.v(TAG, "Screen status="+mScreenOnEarly+
                 ", current orientation="+mCurrentAppOrientation+
                 ", SensorEnabled="+mOrientationSensorEnabled);
         boolean disable = true;
@@ -627,15 +642,15 @@
                 //enable listener if not already enabled
                 if (!mOrientationSensorEnabled) {
                     mOrientationListener.enable();
-                    if(localLOGV) Log.v(TAG, "Enabling listeners");
+                    if(localLOGV) Slog.v(TAG, "Enabling listeners");
                     mOrientationSensorEnabled = true;
                 }
-            } 
-        } 
+            }
+        }
         //check if sensors need to be disabled
         if (disable && mOrientationSensorEnabled) {
             mOrientationListener.disable();
-            if(localLOGV) Log.v(TAG, "Disabling listeners");
+            if(localLOGV) Slog.v(TAG, "Disabling listeners");
             mOrientationSensorEnabled = false;
         }
     }
@@ -679,7 +694,7 @@
     }
 
     private long getScreenshotChordLongPressDelay() {
-        if (mKeyguardMediator.isShowing()) {
+        if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
             return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
                     ViewConfiguration.getGlobalActionKeyTimeout());
@@ -742,7 +757,7 @@
         if (keyguardShowing) {
             // since it took two seconds of long press to bring this up,
             // poke the wake lock so they have some time to see the dialog.
-            mKeyguardMediator.userActivity();
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
     }
 
@@ -835,10 +850,6 @@
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
         mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-        if (!mHeadless) {
-            // don't create KeyguardViewMediator if headless
-            mKeyguardMediator = new KeyguardViewMediator(context, null);
-        }
         mHandler = new PolicyHandler();
         mOrientationListener = new MyOrientationListener(mContext, mHandler);
         try {
@@ -911,6 +922,35 @@
         filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
         context.registerReceiver(mMultiuserReceiver, filter);
 
+        // monitor for system gestures
+        mSystemGestures = new SystemGesturesPointerEventListener(context,
+                new SystemGesturesPointerEventListener.Callbacks() {
+                    @Override
+                    public void onSwipeFromTop() {
+                        if (mStatusBar != null) {
+                            requestTransientBars(mStatusBar);
+                        }
+                    }
+                    @Override
+                    public void onSwipeFromBottom() {
+                        if (mNavigationBar != null && mNavigationBarOnBottom) {
+                            requestTransientBars(mNavigationBar);
+                        }
+                    }
+                    @Override
+                    public void onSwipeFromRight() {
+                        if (mNavigationBar != null && !mNavigationBarOnBottom) {
+                            requestTransientBars(mNavigationBar);
+                        }
+                    }
+                    @Override
+                    public void onDebug() {
+                        // no-op
+                    }
+                });
+        mTransientNavigationConfirmation = new TransientNavigationConfirmation(mContext);
+        mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
+
         mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mLongPressVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_longPressVibePattern);
@@ -962,19 +1002,21 @@
 
     @Override
     public void setInitialDisplaySize(Display display, int width, int height, int density) {
-        if (display.getDisplayId() != Display.DEFAULT_DISPLAY) {
-            throw new IllegalArgumentException("Can only set the default display");
+        // This method might be called before the policy has been fully initialized
+        // or for other displays we don't care about.
+        if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) {
+            return;
         }
         mDisplay = display;
 
+        final Resources res = mContext.getResources();
         int shortSize, longSize;
         if (width > height) {
             shortSize = height;
             longSize = width;
             mLandscapeRotation = Surface.ROTATION_0;
             mSeascapeRotation = Surface.ROTATION_180;
-            if (mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_reverseDefaultRotation)) {
+            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
                 mPortraitRotation = Surface.ROTATION_90;
                 mUpsideDownRotation = Surface.ROTATION_270;
             } else {
@@ -986,8 +1028,7 @@
             longSize = height;
             mPortraitRotation = Surface.ROTATION_0;
             mUpsideDownRotation = Surface.ROTATION_180;
-            if (mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_reverseDefaultRotation)) {
+            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
                 mLandscapeRotation = Surface.ROTATION_270;
                 mSeascapeRotation = Surface.ROTATION_90;
             } else {
@@ -996,68 +1037,42 @@
             }
         }
 
-        mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_height);
+        mStatusBarHeight =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
 
         // Height of the navigation bar when presented horizontally at bottom
         mNavigationBarHeightForRotation[mPortraitRotation] =
         mNavigationBarHeightForRotation[mUpsideDownRotation] =
-                mContext.getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_height);
+                res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
         mNavigationBarHeightForRotation[mLandscapeRotation] =
-        mNavigationBarHeightForRotation[mSeascapeRotation] =
-                mContext.getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_height_landscape);
+        mNavigationBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_height_landscape);
 
         // Width of the navigation bar when presented vertically along one side
         mNavigationBarWidthForRotation[mPortraitRotation] =
         mNavigationBarWidthForRotation[mUpsideDownRotation] =
         mNavigationBarWidthForRotation[mLandscapeRotation] =
         mNavigationBarWidthForRotation[mSeascapeRotation] =
-                mContext.getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_width);
+                res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
 
         // SystemUI (status bar) layout policy
         int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density;
+        int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density;
 
-        if (shortSizeDp < 600) {
-            // 0-599dp: "phone" UI with a separate status & navigation bar
-            mHasSystemNavBar = false;
-            mNavigationBarCanMove = true;
-        } else if (shortSizeDp < 720) {
-            // 600+dp: "phone" UI with modifications for larger screens
-            mHasSystemNavBar = false;
-            mNavigationBarCanMove = false;
-        }
+        // Allow the navigation bar to move on small devices (phones).
+        mNavigationBarCanMove = shortSizeDp < 600;
 
-        if (!mHasSystemNavBar) {
-            mHasNavigationBar = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_showNavigationBar);
-            // Allow a system property to override this. Used by the emulator.
-            // See also hasNavigationBar().
-            String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
-            if (! "".equals(navBarOverride)) {
-                if      (navBarOverride.equals("1")) mHasNavigationBar = false;
-                else if (navBarOverride.equals("0")) mHasNavigationBar = true;
-            }
-        } else {
+        mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
+        // Allow a system property to override this. Used by the emulator.
+        // See also hasNavigationBar().
+        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+        if ("1".equals(navBarOverride)) {
             mHasNavigationBar = false;
+        } else if ("0".equals(navBarOverride)) {
+            mHasNavigationBar = true;
         }
 
-        if (mHasSystemNavBar) {
-            // The system bar is always at the bottom.  If you are watching
-            // a video in landscape, we don't need to hide it if we can still
-            // show a 16:9 aspect ratio with it.
-            int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density;
-            int barHeightDp = mNavigationBarHeightForRotation[mLandscapeRotation]
-                    * DisplayMetrics.DENSITY_DEFAULT / density;
-            int aspect = ((shortSizeDp-barHeightDp) * 16) / longSizeDp;
-            // We have computed the aspect ratio with the bar height taken
-            // out to be 16:aspect.  If this is less than 9, then hiding
-            // the navigation bar will provide more useful space for wide
-            // screen movies.
-            mCanHideNavigationBar = aspect < 9;
-        } else if (mHasNavigationBar) {
+        if (mHasNavigationBar) {
             // The navigation bar is at the right in landscape; it seems always
             // useful to hide it for showing a video.
             mCanHideNavigationBar = true;
@@ -1073,6 +1088,20 @@
             mDemoHdmiRotation = mLandscapeRotation;
         }
         mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
+
+        // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per
+        // http://developer.android.com/guide/practices/screens_support.html#range
+        mForceDefaultOrientation = longSizeDp >= 960 && shortSizeDp >= 720 &&
+                res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) &&
+                // For debug purposes the next line turns this feature off with:
+                // $ adb shell setprop config.override_forced_orient true
+                // $ adb shell wm size reset
+                !"true".equals(SystemProperties.get("config.override_forced_orient"));
+    }
+
+    @Override
+    public boolean isDefaultOrientationForced() {
+        return mForceDefaultOrientation;
     }
 
     @Override
@@ -1135,6 +1164,9 @@
                 mHasSoftInput = hasSoftInput;
                 updateRotation = true;
             }
+            if (mTransientNavigationConfirmation != null) {
+                mTransientNavigationConfirmation.loadSetting();
+            }
         }
         if (updateRotation) {
             updateRotation(true);
@@ -1166,23 +1198,16 @@
             lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
             wm.addView(mPointerLocationView, lp);
 
-            mPointerLocationInputChannel =
-                    mWindowManagerFuncs.monitorInput("PointerLocationView");
-            mPointerLocationInputEventReceiver =
-                    new PointerLocationInputEventReceiver(mPointerLocationInputChannel,
-                            Looper.myLooper(), mPointerLocationView);
+            mPointerLocationPointerEventListener = new PointerLocationPointerEventListener();
+            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationPointerEventListener);
         }
     }
 
     private void disablePointerLocation() {
-        if (mPointerLocationInputEventReceiver != null) {
-            mPointerLocationInputEventReceiver.dispose();
-            mPointerLocationInputEventReceiver = null;
-        }
-
-        if (mPointerLocationInputChannel != null) {
-            mPointerLocationInputChannel.dispose();
-            mPointerLocationInputChannel = null;
+        if (mPointerLocationPointerEventListener != null) {
+            mWindowManagerFuncs.unregisterPointerEventListener(
+                    mPointerLocationPointerEventListener);
+            mPointerLocationPointerEventListener = null;
         }
 
         if (mPointerLocationView != null) {
@@ -1233,6 +1258,7 @@
             case TYPE_DREAM:
             case TYPE_INPUT_METHOD:
             case TYPE_WALLPAPER:
+            case TYPE_PRIVATE_PRESENTATION:
                 // The window manager will check these.
                 break;
             case TYPE_PHONE:
@@ -1279,6 +1305,7 @@
             case TYPE_DISPLAY_OVERLAY:
             case TYPE_HIDDEN_NAV_CONSUMER:
             case TYPE_KEYGUARD:
+            case TYPE_KEYGUARD_SCRIM:
             case TYPE_KEYGUARD_DIALOG:
             case TYPE_MAGNIFICATION_OVERLAY:
             case TYPE_NAVIGATION_BAR:
@@ -1294,6 +1321,7 @@
             case TYPE_SYSTEM_DIALOG:
             case TYPE_UNIVERSE_BACKGROUND:
             case TYPE_VOLUME_OVERLAY:
+            case TYPE_PRIVATE_PRESENTATION:
                 break;
         }
 
@@ -1303,11 +1331,11 @@
                         != PackageManager.PERMISSION_GRANTED;
     }
 
+    @Override
     public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
         switch (attrs.type) {
             case TYPE_SYSTEM_OVERLAY:
             case TYPE_SECURE_SYSTEM_OVERLAY:
-            case TYPE_TOAST:
                 // These types of windows can't receive input events.
                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -1331,11 +1359,8 @@
         }
     }
 
-    private boolean isBuiltInKeyboardVisible() {
-        return mHaveBuiltInKeyboard && !isHidden(mLidKeyboardAccessibility);
-    }
-
     /** {@inheritDoc} */
+    @Override
     public void adjustConfigurationLw(Configuration config, int keyboardPresence,
             int navigationPresence) {
         mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0;
@@ -1361,6 +1386,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public int windowTypeToLayerLw(int type) {
         if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
             return 2;
@@ -1368,6 +1394,8 @@
         switch (type) {
         case TYPE_UNIVERSE_BACKGROUND:
             return 1;
+        case TYPE_PRIVATE_PRESENTATION:
+            return 2;
         case TYPE_WALLPAPER:
             // wallpaper is at the bottom, though the window manager may move it.
             return 2;
@@ -1396,60 +1424,64 @@
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
             return 11;
+        case TYPE_KEYGUARD_SCRIM:
+            // the safety window that shows behind keyguard while keyguard is starting
+            return 12;
         case TYPE_KEYGUARD:
             // the keyguard; nothing on top of these can take focus, since they are
             // responsible for power management when displayed.
-            return 12;
-        case TYPE_KEYGUARD_DIALOG:
             return 13;
-        case TYPE_STATUS_BAR_SUB_PANEL:
+        case TYPE_KEYGUARD_DIALOG:
             return 14;
-        case TYPE_STATUS_BAR:
+        case TYPE_STATUS_BAR_SUB_PANEL:
             return 15;
-        case TYPE_STATUS_BAR_PANEL:
+        case TYPE_STATUS_BAR:
             return 16;
+        case TYPE_STATUS_BAR_PANEL:
+            return 17;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 17;
+            return 18;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 18;
+            return 19;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
-            return 19;
+            return 20;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
-            return 20;
+            return 21;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 21;
+            return 22;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 22;
+            return 23;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 23;
+            return 24;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 24;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 25;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 26;
+        case TYPE_BOOT_PROGRESS:
+            return 27;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 27;
-        case TYPE_HIDDEN_NAV_CONSUMER:
             return 28;
+        case TYPE_HIDDEN_NAV_CONSUMER:
+            return 29;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return 2;
     }
 
     /** {@inheritDoc} */
+    @Override
     public int subWindowTypeToLayerLw(int type) {
         switch (type) {
         case TYPE_APPLICATION_PANEL:
@@ -1466,18 +1498,16 @@
         return 0;
     }
 
+    @Override
     public int getMaxWallpaperLayer() {
         return windowTypeToLayerLw(TYPE_STATUS_BAR);
     }
 
+    @Override
     public int getAboveUniverseLayer() {
         return windowTypeToLayerLw(TYPE_SYSTEM_ERROR);
     }
 
-    public boolean hasSystemNavBar() {
-        return mHasSystemNavBar;
-    }
-
     public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
         if (mHasNavigationBar) {
             // For a basic navigation bar, when we are in landscape mode we place
@@ -1490,10 +1520,6 @@
     }
 
     public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
-        if (mHasSystemNavBar) {
-            // For the system navigation bar, we always place it at the bottom.
-            return fullHeight - mNavigationBarHeightForRotation[rotation];
-        }
         if (mHasNavigationBar) {
             // For a basic navigation bar, when we are in portrait mode we place
             // the navigation bar to the bottom.
@@ -1509,15 +1535,11 @@
     }
 
     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
-        // If we don't have a system nav bar, then there is a separate status
-        // bar at the top of the display.  We don't count that as part of the
-        // fixed decor, since it can hide; however, for purposes of configurations,
+        // There is a separate status bar at the top of the display.  We don't count that as part
+        // of the fixed decor, since it can hide; however, for purposes of configurations,
         // we do want to exclude it since applications can't generally use that part
         // of the screen.
-        if (!mHasSystemNavBar) {
-            return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
-        }
-        return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation);
+        return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
     }
 
     @Override
@@ -1534,6 +1556,7 @@
             case TYPE_DREAM:
             case TYPE_UNIVERSE_BACKGROUND:
             case TYPE_KEYGUARD:
+            case TYPE_KEYGUARD_SCRIM:
                 return false;
             default:
                 return true;
@@ -1544,7 +1567,7 @@
     @Override
     public View addStartingWindow(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
-            int icon, int windowFlags) {
+            int icon, int logo, int windowFlags) {
         if (!SHOW_STARTING_ANIMATIONS) {
             return null;
         }
@@ -1598,9 +1621,12 @@
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
 
             if (!compatInfo.supportsScreen()) {
-                win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
+                win.addFlags(WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW);
             }
 
+            win.setDefaultIcon(icon);
+            win.setDefaultLogo(logo);
+
             win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
                     WindowManager.LayoutParams.MATCH_PARENT);
 
@@ -1696,6 +1722,7 @@
                     }
                 }
                 mStatusBar = win;
+                mStatusBarController.setWindow(win);
                 break;
             case TYPE_NAVIGATION_BAR:
                 mContext.enforceCallingOrSelfPermission(
@@ -1707,7 +1734,8 @@
                     }
                 }
                 mNavigationBar = win;
-                if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
+                mNavigationBarController.setWindow(win);
+                if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
             case TYPE_NAVIGATION_BAR_PANEL:
                 mContext.enforceCallingOrSelfPermission(
@@ -1730,6 +1758,13 @@
                 }
                 mKeyguard = win;
                 break;
+            case TYPE_KEYGUARD_SCRIM:
+                if (mKeyguardScrim != null) {
+                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                }
+                mKeyguardScrim = win;
+                break;
+
         }
         return WindowManagerGlobal.ADD_OKAY;
     }
@@ -1738,10 +1773,17 @@
     public void removeWindowLw(WindowState win) {
         if (mStatusBar == win) {
             mStatusBar = null;
+            mStatusBarController.setWindow(null);
         } else if (mKeyguard == win) {
+            Log.v(TAG, "Removing keyguard window (Did it crash?)");
             mKeyguard = null;
-        } else if (mNavigationBar == win) {
+            mKeyguardDelegate.showScrim();
+        } else if (mKeyguardScrim == win) {
+            Log.v(TAG, "Removing keyguard scrim");
+            mKeyguardScrim = null;
+        } if (mNavigationBar == win) {
             mNavigationBar = null;
+            mNavigationBarController.setWindow(null);
         }
     }
 
@@ -1980,6 +2022,7 @@
             if (attrs != null) {
                 final int type = attrs.type;
                 if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
+                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
                         || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
                     // the "app" is keyguard, so give it the key
                     return 0;
@@ -2085,6 +2128,43 @@
                 mHandler.post(mScreenshotRunnable);
             }
             return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP
+                || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) {
+            if (down) {
+                int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
+
+                // Disable autobrightness if it's on
+                int auto = Settings.System.getIntForUser(
+                        mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS_MODE,
+                        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+                        UserHandle.USER_CURRENT_OR_SELF);
+                if (auto != 0) {
+                    Settings.System.putIntForUser(mContext.getContentResolver(),
+                            Settings.System.SCREEN_BRIGHTNESS_MODE,
+                            Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+                            UserHandle.USER_CURRENT_OR_SELF);
+                }
+
+                int min = mPowerManager.getMinimumScreenBrightnessSetting();
+                int max = mPowerManager.getMaximumScreenBrightnessSetting();
+                int step = (max - min + BRIGHTNESS_STEPS - 1) / BRIGHTNESS_STEPS * direction;
+                int brightness = Settings.System.getIntForUser(mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS,
+                        mPowerManager.getDefaultScreenBrightnessSetting(),
+                        UserHandle.USER_CURRENT_OR_SELF);
+                brightness += step;
+                // Make sure we don't go beyond the limits.
+                brightness = Math.min(max, brightness);
+                brightness = Math.max(min, brightness);
+
+                Settings.System.putIntForUser(mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS, brightness,
+                        UserHandle.USER_CURRENT_OR_SELF);
+                Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
+                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF);
+            }
+            return -1;
         }
 
         // Shortcuts are invoked through Search+key, so intercept those here
@@ -2102,7 +2182,7 @@
                     if (shortcutIntent != null) {
                         shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                         try {
-                            mContext.startActivity(shortcutIntent);
+                            mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
                         } catch (ActivityNotFoundException ex) {
                             Slog.w(TAG, "Dropping shortcut key combination because "
                                     + "the activity to which it is registered was not found: "
@@ -2128,7 +2208,7 @@
                 if (shortcutIntent != null) {
                     shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     try {
-                        mContext.startActivity(shortcutIntent);
+                        mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
                     } catch (ActivityNotFoundException ex) {
                         Slog.w(TAG, "Dropping shortcut key combination because "
                                 + "the activity to which it is registered was not found: "
@@ -2146,7 +2226,7 @@
                 Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 try {
-                    mContext.startActivity(intent);
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                 } catch (ActivityNotFoundException ex) {
                     Slog.w(TAG, "Dropping application launch key because "
                             + "the activity to which it is registered was not found: "
@@ -2293,7 +2373,7 @@
             if (searchManager != null) {
                 searchManager.stopSearch();
             }
-            mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         } catch (ActivityNotFoundException e) {
             Slog.w(TAG, "No activity to handle assist long press action.", e);
         }
@@ -2308,7 +2388,7 @@
                     | Intent.FLAG_ACTIVITY_SINGLE_TOP
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             try {
-                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+                mContext.startActivityAsUser(intent, UserHandle.CURRENT);
             } catch (ActivityNotFoundException e) {
                 Slog.w(TAG, "No activity to handle assist action.", e);
             }
@@ -2372,12 +2452,12 @@
      * given the situation with the keyguard.
      */
     void launchHomeFromHotKey() {
-        if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotHidden()) {
             // don't launch home if keyguard showing
-        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
+        } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
             // when in keyguard restricted mode, must first verify unlock
             // before launching home
-            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
+            mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
                 public void onKeyguardExitResult(boolean success) {
                     if (success) {
                         try {
@@ -2400,13 +2480,15 @@
         }
     }
 
-    /**
-     * A delayed callback use to determine when it is okay to re-allow applications
-     * to use certain system UI flags.  This is used to prevent applications from
-     * spamming system UI changes that prevent the navigation bar from being shown.
-     */
-    final Runnable mAllowSystemUiDelay = new Runnable() {
-        @Override public void run() {
+    private final Runnable mClearHideNavigationFlag = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+                // Clear flags.
+                mForceClearedSystemUiFlags &=
+                        ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            }
+            mWindowManagerFuncs.reevaluateStatusBarVisibility();
         }
     };
 
@@ -2430,7 +2512,7 @@
                     if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                         // When the user taps down, we re-show the nav bar.
                         boolean changed = false;
-                        synchronized (mLock) {
+                        synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
                             // Any user activity always causes us to show the
                             // navigation controls, if they had been hidden.
                             // We also clear the low profile and only content
@@ -2452,16 +2534,7 @@
                             if (mForceClearedSystemUiFlags != newVal) {
                                 mForceClearedSystemUiFlags = newVal;
                                 changed = true;
-                                mHandler.postDelayed(new Runnable() {
-                                    @Override public void run() {
-                                        synchronized (mLock) {
-                                            // Clear flags.
-                                            mForceClearedSystemUiFlags &=
-                                                    ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-                                        }
-                                        mWindowManagerFuncs.reevaluateStatusBarVisibility();
-                                    }
-                                }, 1000);
+                                mHandler.postDelayed(mClearHideNavigationFlag, 1000);
                             }
                         }
                         if (changed) {
@@ -2485,6 +2558,9 @@
 
     @Override
     public int adjustSystemUiVisibilityLw(int visibility) {
+        mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+        mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+
         // Reset any bits in mForceClearingStatusBarVisibility that
         // are now clear.
         mResettingSystemUiFlags &= visibility;
@@ -2586,8 +2662,8 @@
         mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
         mRestrictedScreenLeft = mUnrestrictedScreenLeft;
         mRestrictedScreenTop = mUnrestrictedScreenTop;
-        mRestrictedScreenWidth = mUnrestrictedScreenWidth;
-        mRestrictedScreenHeight = mUnrestrictedScreenHeight;
+        mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
+        mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
         mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
                 = mCurLeft = mUnrestrictedScreenLeft;
         mDockTop = mContentTop = mStableTop = mStableFullscreenTop
@@ -2612,13 +2688,17 @@
         if (isDefaultDisplay) {
             // For purposes of putting out fake window up to steal focus, we will
             // drive nav being hidden only by whether it is requested.
-            boolean navVisible = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+            final int sysui = mLastSystemUiFlags;
+            boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+            boolean navTransparent = (sysui & View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION) != 0;
+            boolean transientAllowed = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
+            navTransparent &= !transientAllowed;  // transient trumps transparent
 
             // When the navigation bar isn't visible, we put up a fake
             // input window to catch all touch events.  This way we can
             // detect when the user presses anywhere to bring back the nav
             // bar and ensure the application doesn't see the event.
-            if (navVisible) {
+            if (navVisible || transientAllowed) {
                 if (mHideNavFakeWindow != null) {
                     mHideNavFakeWindow.dismiss();
                     mHideNavFakeWindow = null;
@@ -2635,7 +2715,9 @@
             // then take that into account.
             navVisible |= !mCanHideNavigationBar;
 
+            boolean updateSysUiVisibility = false;
             if (mNavigationBar != null) {
+                boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
                 // Force the navigation bar to its appropriate place and
                 // size.  We need to do this directly, instead of relying on
                 // it to bubble up from the nav bar, because this needs to
@@ -2647,17 +2729,20 @@
                             - mNavigationBarHeightForRotation[displayRotation];
                     mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
                     mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
-                    if (navVisible) {
-                        mNavigationBar.showLw(true);
+                    if (transientNavBarShowing || navTransparent) {
+                        mNavigationBarController.setBarShowingLw(true);
+                    } else if (navVisible) {
+                        mNavigationBarController.setBarShowingLw(true);
                         mDockBottom = mTmpNavigationFrame.top;
                         mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
                         mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
                     } else {
                         // We currently want to hide the navigation UI.
-                        mNavigationBar.hideLw(true);
+                        mNavigationBarController.setBarShowingLw(false);
                     }
-                    if (navVisible && !mNavigationBar.isAnimatingLw()) {
-                        // If the nav bar is currently requested to be visible,
+                    if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()
+                            && !mNavigationBarController.wasRecentlyTransparent()) {
+                        // If the opaque nav bar is currently requested to be visible,
                         // and not in the process of animating on or off, then
                         // we can tell the app that it is covered by it.
                         mSystemBottom = mTmpNavigationFrame.top;
@@ -2668,16 +2753,19 @@
                             - mNavigationBarWidthForRotation[displayRotation];
                     mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
                     mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
-                    if (navVisible) {
-                        mNavigationBar.showLw(true);
+                    if (transientNavBarShowing || navTransparent) {
+                        mNavigationBarController.setBarShowingLw(true);
+                    } else if (navVisible) {
+                        mNavigationBarController.setBarShowingLw(true);
                         mDockRight = mTmpNavigationFrame.left;
                         mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
                         mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
                     } else {
                         // We currently want to hide the navigation UI.
-                        mNavigationBar.hideLw(true);
+                        mNavigationBarController.setBarShowingLw(false);
                     }
-                    if (navVisible && !mNavigationBar.isAnimatingLw()) {
+                    if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()
+                            && !mNavigationBarController.wasRecentlyTransparent()) {
                         // If the nav bar is currently requested to be visible,
                         // and not in the process of animating on or off, then
                         // we can tell the app that it is covered by it.
@@ -2694,9 +2782,12 @@
                 // And compute the final frame.
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
                         mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame);
-                if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
+                if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
+                if (mNavigationBarController.checkHiddenLw()) {
+                    updateSysUiVisibility = true;
+                }
             }
-            if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
+            if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
                     mDockLeft, mDockTop, mDockRight, mDockBottom));
 
             // decide where the status bar goes ahead of time
@@ -2720,9 +2811,12 @@
                 // For layout, the status bar is always at the top with our fixed height.
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
 
+                boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+                boolean statusBarTransparent = (sysui & View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS) != 0;
+
                 // If the status bar is hidden, we don't want to cause
                 // windows behind it to scroll.
-                if (mStatusBar.isVisibleLw()) {
+                if (mStatusBar.isVisibleLw() && !statusBarTransient) {
                     // Status bar may go away, so the screen area it occupies
                     // is available to apps but just covering them when the
                     // status bar is visible.
@@ -2733,24 +2827,33 @@
                     mContentLeft = mCurLeft = mDockLeft;
                     mContentRight = mCurRight = mDockRight;
 
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
                         String.format(
                             "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
                             mDockLeft, mDockTop, mDockRight, mDockBottom,
                             mContentLeft, mContentTop, mContentRight, mContentBottom,
                             mCurLeft, mCurTop, mCurRight, mCurBottom));
                 }
-                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()) {
-                    // If the status bar is currently requested to be visible,
+                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
+                        && !statusBarTransient && !statusBarTransparent
+                        && !mStatusBarController.wasRecentlyTransparent()) {
+                    // If the opaque status bar is currently requested to be visible,
                     // and not in the process of animating on or off, then
                     // we can tell the app that it is covered by it.
                     mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
                 }
+                if (mStatusBarController.checkHiddenLw()) {
+                    updateSysUiVisibility = true;
+                }
+            }
+            if (updateSysUiVisibility) {
+                updateSystemUiVisibilityLw();
             }
         }
     }
 
     /** {@inheritDoc} */
+    @Override
     public int getSystemDecorRectLw(Rect systemRect) {
         systemRect.left = mSystemLeft;
         systemRect.top = mSystemTop;
@@ -2761,6 +2864,11 @@
         return 0;
     }
 
+    @Override
+    public void getContentRectLw(Rect r) {
+        r.set(mContentLeft, mContentTop, mContentRight, mContentBottom);
+    }
+
     void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
             boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
         if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
@@ -2840,9 +2948,7 @@
         final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
                 (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
         if (needsToOffsetInputMethodTarget) {
-            if (DEBUG_LAYOUT) {
-                Slog.i(TAG, "Offset ime target window by the last ime window state");
-            }
+            if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
             offsetInputMethodWindowLw(mLastInputMethodWindow);
         }
 
@@ -2879,15 +2985,15 @@
             pf.left = df.left = of.left = cf.left = vf.left = mDockLeft;
             pf.top = df.top = of.top = cf.top = vf.top = mDockTop;
             pf.right = df.right = of.right = cf.right = vf.right = mDockRight;
-            pf.bottom = df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom;
+            // IM dock windows always go above the nav bar.
+            pf.bottom = df.bottom = of.bottom = cf.bottom = vf.bottom = mStableBottom;
             // IM dock windows always go to the bottom of the screen.
             attrs.gravity = Gravity.BOTTOM;
             mDockLayer = win.getSurfaceLayer();
         } else {
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
                     == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
-                if (DEBUG_LAYOUT)
-                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
                             + "): IN_SCREEN, INSET_DECOR");
                 // This is the case for a normal activity window: we want it
                 // to cover all of the screen space, and it can take care of
@@ -2917,11 +3023,9 @@
                                 ? mRestrictedScreenTop+mRestrictedScreenHeight
                                 : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
 
-                        if (DEBUG_LAYOUT) {
-                            Log.v(TAG, String.format(
+                        if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
                                         "Laying out status bar window: (%d,%d - %d,%d)",
                                         pf.left, pf.top, pf.right, pf.bottom));
-                        }
                     } else if ((attrs.flags&FLAG_LAYOUT_IN_OVERSCAN) != 0
                             && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
@@ -3003,8 +3107,8 @@
             } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
                     & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                             | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
-                if (DEBUG_LAYOUT)
-                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
+                        "): IN_SCREEN");
                 // A window that has requested to fill the entire screen just
                 // gets everything, period.
                 if (attrs.type == TYPE_STATUS_BAR_PANEL
@@ -3018,11 +3122,9 @@
                     pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar
                                           ? mRestrictedScreenTop+mRestrictedScreenHeight
                                           : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-                    if (DEBUG_LAYOUT) {
-                        Log.v(TAG, String.format(
+                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
                                     "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
                                     pf.left, pf.top, pf.right, pf.bottom));
-                    }
                 } else if (attrs.type == TYPE_NAVIGATION_BAR
                         || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
                     // The navigation bar has Real Ultimate Power.
@@ -3032,11 +3134,9 @@
                             + mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop
                             + mUnrestrictedScreenHeight;
-                    if (DEBUG_LAYOUT) {
-                        Log.v(TAG, String.format(
+                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
                                     "Laying out navigation bar window: (%d,%d - %d,%d)",
                                     pf.left, pf.top, pf.right, pf.bottom));
-                    }
                 } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
                                 || attrs.type == TYPE_BOOT_PROGRESS)
                         && ((fl & FLAG_FULLSCREEN) != 0)) {
@@ -3056,14 +3156,14 @@
                             + mOverscanScreenWidth;
                     pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
                             + mOverscanScreenHeight;
-                } else if (attrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
-                    // The wallpaper mostly goes into the overscan region.
-                    pf.left = df.left = of.left = cf.left = mRestrictedOverscanScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mRestrictedOverscanScreenTop;
+                } else if (attrs.type == TYPE_WALLPAPER) {
+                    // The wallpaper also has Real Ultimate Power.
+                    pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
                     pf.right = df.right = of.right = cf.right
-                            = mRestrictedOverscanScreenLeft + mRestrictedOverscanScreenWidth;
+                            = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = of.bottom = cf.bottom
-                            = mRestrictedOverscanScreenTop + mRestrictedOverscanScreenHeight;
+                            = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                 } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0
                         && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                         && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
@@ -3077,11 +3177,12 @@
                             = mOverscanScreenTop + mOverscanScreenHeight;
                 } else if (mCanHideNavigationBar
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
-                        && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                        && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        && (attrs.type == TYPE_TOAST
+                            || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
                     // Asking for layout as if the nav bar is hidden, lets the
                     // application extend into the unrestricted screen area.  We
-                    // only do this for application windows to ensure no window that
+                    // only do this for application windows (or toasts) to ensure no window that
                     // can be above the nav bar can do this.
                     // XXX This assumes that an app asking for this will also
                     // ask for layout in only content.  We can't currently figure out
@@ -3112,14 +3213,14 @@
                     vf.set(cf);
                 }
             } else if (attached != null) {
-                if (DEBUG_LAYOUT)
-                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
+                        "): attached to " + attached);
                 // A child window should be placed inside of the same visible
                 // frame that its parent had.
                 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf);
             } else {
-                if (DEBUG_LAYOUT)
-                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
+                        "): normal window");
                 // Otherwise, a normal window must be placed inside the content
                 // of all screen decorations.
                 if (attrs.type == TYPE_STATUS_BAR_PANEL) {
@@ -3161,13 +3262,14 @@
             }
         }
 
-        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
+        // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
+        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {
             df.left = df.top = of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
             df.right = df.bottom = of.right = of.bottom = cf.right = cf.bottom
                     = vf.right = vf.bottom = 10000;
         }
 
-        if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
+        if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
                 + ": sim=#" + Integer.toHexString(sim)
                 + " attach=" + attached + " type=" + attrs.type 
                 + String.format(" flags=0x%08x", fl)
@@ -3197,7 +3299,7 @@
         if (mCurBottom > top) {
             mCurBottom = top;
         }
-        if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom="
+        if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
                 + mDockBottom + " mContentBottom="
                 + mContentBottom + " mCurBottom=" + mCurBottom);
     }
@@ -3231,7 +3333,8 @@
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
                 + win.isVisibleOrBehindKeyguardLw());
         if (mTopFullscreenOpaqueWindowState == null && (win.getAttrs().privateFlags
-                &WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_NAV_BAR) != 0) {
+                &WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_NAV_BAR) != 0
+                || (win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD)) {
             if (mForcingShowNavBarLayer < 0) {
                 mForcingShowNavBar = true;
                 mForcingShowNavBarLayer = win.getSurfaceLayer();
@@ -3264,21 +3367,20 @@
                     && attrs.x == 0 && attrs.y == 0
                     && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
                     && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
-                if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
+                if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                 mTopFullscreenOpaqueWindowState = win;
                 if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win);
                     mHideLockScreen = true;
                     mForceStatusBarFromKeyguard = false;
                 }
                 if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
                         && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win);
                     mDismissKeyguard = mWinDismissingKeyguard == win ?
                             DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                     mWinDismissingKeyguard = win;
-                    mForceStatusBarFromKeyguard =
-                            mShowingLockscreen && mKeyguardMediator.isSecure();
+                    mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
                 }
                 if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                     mAllowLockscreenWhenOn = true;
@@ -3306,17 +3408,19 @@
         }
 
         if (mStatusBar != null) {
-            if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar
+            if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
                     + " forcefkg=" + mForceStatusBarFromKeyguard
                     + " top=" + mTopFullscreenOpaqueWindowState);
             if (mForceStatusBar || mForceStatusBarFromKeyguard) {
-                if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced");
-                if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
+                if (mStatusBarController.setBarShowingLw(true)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                }
             } else if (mTopFullscreenOpaqueWindowState != null) {
                 if (localLOGV) {
-                    Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
+                    Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
                             + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
-                    Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
+                    Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
                             + " lp.flags=0x" + Integer.toHexString(lp.flags));
                 }
                 topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
@@ -3325,30 +3429,22 @@
                 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
                 // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
                 // case though.
-                if (topIsFullscreen) {
-                    if (DEBUG_LAYOUT) Log.v(TAG, "** HIDING status bar");
-                    if (mStatusBar.hideLw(true)) {
+                if (mStatusBarController.isTransientShowing()) {
+                    if (mStatusBarController.setBarShowingLw(true)) {
                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
-
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                            try {
-                                IStatusBarService statusbar = getStatusBarService();
-                                if (statusbar != null) {
-                                    statusbar.collapsePanels();
-                                }
-                            } catch (RemoteException ex) {
-                                // re-acquire status bar service next time it is needed.
-                                mStatusBarService = null;
-                            }
-                        }});
-                    } else if (DEBUG_LAYOUT) {
-                        Log.v(TAG, "Preventing status bar from hiding by policy");
+                    }
+                } else if (topIsFullscreen) {
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
+                    if (mStatusBarController.setBarShowingLw(false)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    } else {
+                        if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
                     }
                 } else {
-                    if (DEBUG_LAYOUT) Log.v(TAG, "** SHOWING status bar: top is not fullscreen");
-                    if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
+                    if (mStatusBarController.setBarShowingLw(true)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    }
                 }
             }
         }
@@ -3358,19 +3454,19 @@
         // Hide the key guard if a visible window explicitly specifies that it wants to be
         // displayed when the screen is locked.
         if (mKeyguard != null) {
-            if (localLOGV) Log.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
+            if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
                     + mHideLockScreen);
-            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardMediator.isSecure()) {
+            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardDelegate.isSecure()) {
                 if (mKeyguard.hideLw(true)) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
                             | FINISH_LAYOUT_REDO_CONFIG
                             | FINISH_LAYOUT_REDO_WALLPAPER;
                 }
-                if (mKeyguardMediator.isShowing()) {
+                if (mKeyguardDelegate.isShowing()) {
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            mKeyguardMediator.keyguardDone(false, false);
+                            mKeyguardDelegate.keyguardDone(false, false);
                         }
                     });
                 }
@@ -3380,7 +3476,7 @@
                             | FINISH_LAYOUT_REDO_CONFIG
                             | FINISH_LAYOUT_REDO_WALLPAPER;
                 }
-                mKeyguardMediator.setHidden(true);
+                mKeyguardDelegate.setHidden(true);
             } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
                 // This is the case of keyguard isSecure() and not mHideLockScreen.
                 if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
@@ -3390,11 +3486,11 @@
                                 | FINISH_LAYOUT_REDO_CONFIG
                                 | FINISH_LAYOUT_REDO_WALLPAPER;
                     }
-                    mKeyguardMediator.setHidden(false);
+                    mKeyguardDelegate.setHidden(false);
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            mKeyguardMediator.dismiss();
+                            mKeyguardDelegate.dismiss();
                         }
                     });
                 }
@@ -3405,7 +3501,7 @@
                             | FINISH_LAYOUT_REDO_CONFIG
                             | FINISH_LAYOUT_REDO_WALLPAPER;
                 }
-                mKeyguardMediator.setHidden(false);
+                mKeyguardDelegate.setHidden(false);
             }
         }
 
@@ -3455,11 +3551,7 @@
         updateRotation(true);
 
         if (lidOpen) {
-            if (keyguardIsShowingTq()) {
-                mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(KeyEvent.KEYCODE_POWER);
-            } else {
-                mPowerManager.wakeUp(SystemClock.uptimeMillis());
-            }
+            mPowerManager.wakeUp(SystemClock.uptimeMillis());
         } else if (!mLidControlsSleep) {
             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
@@ -3541,7 +3633,8 @@
                 keycode == KeyEvent.KEYCODE_VOLUME_UP
                             ? AudioManager.ADJUST_RAISE
                             : AudioManager.ADJUST_LOWER,
-                    0);
+                    0,
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
         } finally {
@@ -3636,10 +3729,10 @@
         // the same as if it were open and in front.
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (mKeyguardMediator == null ? false :
+        final boolean keyguardActive = (mKeyguardDelegate == null ? false :
                                             (isScreenOn ?
-                                                mKeyguardMediator.isShowingAndNotHidden() :
-                                                mKeyguardMediator.isShowing()));
+                                                mKeyguardDelegate.isShowingAndNotHidden() :
+                                                mKeyguardDelegate.isShowing()));
 
         if (keyCode == KeyEvent.KEYCODE_POWER) {
             policyFlags |= WindowManagerPolicy.FLAG_WAKE;
@@ -3676,13 +3769,7 @@
             // to wake the device but don't pass the key to the application.
             result = 0;
             if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
-                if (keyguardActive) {
-                    // If the keyguard is showing, let it wake the device when ready.
-                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
-                } else {
-                    // Otherwise, wake the device ourselves.
-                    result |= ACTION_WAKE_UP;
-                }
+                result |= ACTION_WAKE_UP;
             }
         }
 
@@ -3802,6 +3889,8 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
+                    mTransientNavigationConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+                            isTransientNavigationAllowed(mLastSystemUiFlags));
                     if (isScreenOn && !mPowerKeyTriggered
                             && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                         mPowerKeyTriggered = true;
@@ -3865,7 +3954,8 @@
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
             case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
                 if ((result & ACTION_PASS_TO_USER) == 0) {
                     // Only do this if we would otherwise not pass it to the user. In that
                     // case, the PhoneWindow class will do the same thing, except it will
@@ -3933,6 +4023,7 @@
             case KeyEvent.KEYCODE_MEDIA_REWIND:
             case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
             case KeyEvent.KEYCODE_CAMERA:
                 return false;
         }
@@ -3948,13 +4039,7 @@
         final boolean isWakeMotion = (policyFlags
                 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
         if (isWakeMotion) {
-            if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) {
-                // If the keyguard is showing, let it decide what to do with the wake motion.
-                mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
-            } else {
-                // Otherwise, wake the device ourselves.
-                result |= ACTION_WAKE_UP;
-            }
+            result |= ACTION_WAKE_UP;
         }
         return result;
     }
@@ -4040,12 +4125,12 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
-                if (mKeyguardMediator != null) {
-                    mKeyguardMediator.onDreamingStarted();
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.onDreamingStarted();
                 }
             } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
-                if (mKeyguardMediator != null) {
-                    mKeyguardMediator.onDreamingStopped();
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.onDreamingStopped();
                 }
             }
         }
@@ -4064,7 +4149,7 @@
                 // force a re-application of focused window sysui visibility.
                 // the window may never have been shown for this user
                 // e.g. the keyguard when going through the new-user setup flow
-                synchronized(mLock) {
+                synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
                     mLastSystemUiFlags = 0;
                     updateSystemUiVisibilityLw();
                 }
@@ -4072,6 +4157,24 @@
         }
     };
 
+    private void requestTransientBars(WindowState swipeTarget) {
+        synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+            boolean sb = mStatusBarController.checkShowTransientBarLw();
+            boolean nb = mNavigationBarController.checkShowTransientBarLw();
+            if (sb || nb) {
+                WindowState barTarget = sb ? mStatusBar : mNavigationBar;
+                if (sb ^ nb && barTarget != swipeTarget) {
+                    if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
+                    return;
+                }
+                if (sb) mStatusBarController.showTransient();
+                if (nb) mNavigationBarController.showTransient();
+                mTransientNavigationConfirmation.confirmCurrentPrompt();
+                updateSystemUiVisibilityLw();
+            }
+        }
+    }
+
     @Override
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
@@ -4079,8 +4182,8 @@
             mScreenOnEarly = false;
             mScreenOnFully = false;
         }
-        if (mKeyguardMediator != null) {
-            mKeyguardMediator.onScreenTurnedOff(why);
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.onScreenTurnedOff(why);
         }
         synchronized (mLock) {
             updateOrientationListenerLp();
@@ -4107,9 +4210,9 @@
     }
 
     private void waitForKeyguard(final ScreenOnListener screenOnListener) {
-        if (mKeyguardMediator != null) {
+        if (mKeyguardDelegate != null) {
             if (screenOnListener != null) {
-                mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
+                mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() {
                     @Override
                     public void onShown(IBinder windowToken) {
                         waitForKeyguardWindowDrawn(windowToken, screenOnListener);
@@ -4117,10 +4220,10 @@
                 });
                 return;
             } else {
-                mKeyguardMediator.onScreenTurnedOn(null);
+                mKeyguardDelegate.onScreenTurnedOn(null);
             }
         } else {
-            Slog.i(TAG, "No keyguard mediator!");
+            Slog.i(TAG, "No keyguard interface!");
         }
         finishScreenTurningOn(screenOnListener);
     }
@@ -4175,21 +4278,21 @@
 
     /** {@inheritDoc} */
     public void enableKeyguard(boolean enabled) {
-        if (mKeyguardMediator != null) {
-            mKeyguardMediator.setKeyguardEnabled(enabled);
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.setKeyguardEnabled(enabled);
         }
     }
 
     /** {@inheritDoc} */
     public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
-        if (mKeyguardMediator != null) {
-            mKeyguardMediator.verifyUnlock(callback);
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.verifyUnlock(callback);
         }
     }
 
     private boolean keyguardIsShowingTq() {
-        if (mKeyguardMediator == null) return false;
-        return mKeyguardMediator.isShowingAndNotHidden();
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isShowingAndNotHidden();
     }
 
 
@@ -4200,26 +4303,26 @@
 
     /** {@inheritDoc} */
     public boolean isKeyguardSecure() {
-        if (mKeyguardMediator == null) return false;
-        return mKeyguardMediator.isSecure();
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isSecure();
     }
 
     /** {@inheritDoc} */
     public boolean inKeyguardRestrictedKeyInputMode() {
-        if (mKeyguardMediator == null) return false;
-        return mKeyguardMediator.isInputRestricted();
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isInputRestricted();
     }
 
     public void dismissKeyguardLw() {
-        if (mKeyguardMediator.isShowing()) {
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { 
             mHandler.post(new Runnable() {
                 public void run() {
-                    if (mKeyguardMediator.isDismissable()) {
+                    if (mKeyguardDelegate.isDismissable()) {
                         // Can we just finish the keyguard straight away?
-                        mKeyguardMediator.keyguardDone(false, true);
+                        mKeyguardDelegate.keyguardDone(false, true);
                     } else {
                         // ask the keyguard to prompt the user to authenticate if necessary
-                        mKeyguardMediator.dismiss();
+                        mKeyguardDelegate.dismiss();
                     }
                 }
             });
@@ -4254,6 +4357,10 @@
                         );
         }
 
+        if (mForceDefaultOrientation) {
+            return Surface.ROTATION_0;
+        }
+
         synchronized (mLock) {
             int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
             if (sensorRotation < 0) {
@@ -4462,7 +4569,7 @@
                 ? HapticFeedbackConstants.SAFE_MODE_ENABLED
                 : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
     }
-    
+
     static long[] getLongIntArray(Resources r, int resid) {
         int[] ar = r.getIntArray(resid);
         if (ar == null) {
@@ -4474,17 +4581,19 @@
         }
         return out;
     }
-    
+
     /** {@inheritDoc} */
+    @Override
     public void systemReady() {
-        if (mKeyguardMediator != null) {
-            // tell the keyguard
-            mKeyguardMediator.onSystemReady();
+        if (!mHeadless) {
+            mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
+            mKeyguardDelegate.onSystemReady();
         }
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
             mHandler.post(new Runnable() {
+                @Override
                 public void run() {
                     updateSettings();
                 }
@@ -4591,8 +4700,8 @@
         public void run() {
             synchronized (this) {
                 if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
-                if (mKeyguardMediator != null) {
-                    mKeyguardMediator.doKeyguardTimeout(options);
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.doKeyguardTimeout(options);
                 }
                 mLockScreenTimerActive = false;
                 options = null;
@@ -4620,7 +4729,7 @@
     private void updateLockScreenTimeout() {
         synchronized (mScreenLockTimeout) {
             boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly &&
-                    mKeyguardMediator != null && mKeyguardMediator.isSecure());
+                    mKeyguardDelegate != null && mKeyguardDelegate.isSecure());
             if (mLockScreenTimerActive != enable) {
                 if (enable) {
                     if (localLOGV) Log.v(TAG, "setting lockscreen timer");
@@ -4635,6 +4744,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void enableScreenAfterBoot() {
         readLidState();
         applyLidSwitchState();
@@ -4676,7 +4786,7 @@
      *  <li>The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME
      *  <li>The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME
      * </ul>
-     * @return
+     * @return A dock intent.
      */
     Intent createHomeDockIntent() {
         Intent intent = null;
@@ -4701,8 +4811,8 @@
         ActivityInfo ai = null;
         ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
                 intent,
-                PackageManager.MATCH_DEFAULT_ONLY,
-                UserHandle.USER_CURRENT);
+                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
+                mCurrentUserId);
         if (info != null) {
             ai = info.activityInfo;
         }
@@ -4731,7 +4841,7 @@
 
         mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
     }
-    
+
     /**
      * goes to the home screen
      * @return whether it did anything
@@ -4783,7 +4893,8 @@
         }
         return true;
     }
-    
+
+    @Override
     public void setCurrentOrientationLw(int newOrientation) {
         synchronized (mLock) {
             if (newOrientation != mCurrentAppOrientation) {
@@ -4807,18 +4918,20 @@
         ringTone.setStreamType(AudioManager.STREAM_MUSIC);
         ringTone.play();
     }
+
     private boolean isGlobalAccessibilityGestureEnabled() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
     }
 
+    @Override
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
         if (!mVibrator.hasVibrator()) {
             return false;
         }
         final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
-        if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) {
+        if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotHidden())) {
             return false;
         }
         long[] pattern = null;
@@ -4848,7 +4961,7 @@
             owningPackage = win.getOwningPackage();
         } else {
             owningUid = android.os.Process.myUid();
-            owningPackage = mContext.getBasePackageName();
+            owningPackage = mContext.getOpPackageName();
         }
         if (pattern.length == 1) {
             // One-shot vibration
@@ -4866,19 +4979,20 @@
 
     @Override
     public void keepScreenOnStoppedLw() {
-        if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
+        if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotHidden()) {
             long curTime = SystemClock.uptimeMillis();
-            mPowerManager.userActivity(curTime, false);
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
     }
 
     private int updateSystemUiVisibilityLw() {
         // If there is no window focused, there will be nobody to handle the events
         // anyway, so just hang on in whatever state we're in until things settle down.
-        if (mFocusedWindow == null) {
+        WindowState win = mFocusedWindow != null ? mFocusedWindow : mTopFullscreenOpaqueWindowState;
+        if (win == null) {
             return 0;
         }
-        if (mFocusedWindow.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) {
+        if (win.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) {
             // We are updating at a point where the keyguard has gotten
             // focus, but we were last in a state where the top window is
             // hiding it.  This is probably because the keyguard as been
@@ -4887,23 +5001,25 @@
             // will quickly lose focus once it correctly gets hidden.
             return 0;
         }
-        int tmpVisibility = mFocusedWindow.getSystemUiVisibility()
+
+        int tmpVisibility = win.getSystemUiVisibility()
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
-        if (mForcingShowNavBar && mFocusedWindow.getSurfaceLayer() < mForcingShowNavBarLayer) {
+        if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
             tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
         }
-        final int visibility = tmpVisibility;
-        int diff = visibility ^ mLastSystemUiFlags;
-        final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
+        final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
+        final int diff = visibility ^ mLastSystemUiFlags;
+        final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
         if (diff == 0 && mLastFocusNeedsMenu == needsMenu
-                && mFocusedApp == mFocusedWindow.getAppToken()) {
+                && mFocusedApp == win.getAppToken()) {
             return 0;
         }
         mLastSystemUiFlags = visibility;
         mLastFocusNeedsMenu = needsMenu;
-        mFocusedApp = mFocusedWindow.getAppToken();
+        mFocusedApp = win.getAppToken();
         mHandler.post(new Runnable() {
+                @Override
                 public void run() {
                     try {
                         IStatusBarService statusbar = getStatusBarService();
@@ -4920,8 +5036,70 @@
         return diff;
     }
 
+    private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
+        // prevent status bar interaction from clearing certain flags
+        boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR;
+        if (statusBarHasFocus) {
+            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE
+                    | View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS
+                    | View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION;
+            vis = (vis & ~flags) | (mLastSystemUiFlags & flags);
+        }
+
+        // update status bar
+        boolean transientAllowed =
+                (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
+        boolean hideStatusBarWM =
+                (win.getAttrs().flags
+                        & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+        boolean hideStatusBarSysui =
+                (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+
+        boolean transientStatusBarAllowed =
+                mStatusBar != null && (
+                hideStatusBarWM
+                || (hideStatusBarSysui && transientAllowed)
+                || statusBarHasFocus);
+
+        if (mStatusBarController.isTransientShowing()
+                && !transientStatusBarAllowed && hideStatusBarSysui) {
+            // clear the clearable flags instead
+            int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
+            if (newVal != mResettingSystemUiFlags) {
+                mResettingSystemUiFlags = newVal;
+                mWindowManagerFuncs.reevaluateStatusBarVisibility();
+            }
+        }
+
+        vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
+
+        // update navigation bar
+        boolean oldTransientNav = isTransientNavigationAllowed(oldVis);
+        boolean isTransientNav = isTransientNavigationAllowed(vis);
+        if (win != null && oldTransientNav != isTransientNav) {
+            final String pkg = win.getOwningPackage();
+            mTransientNavigationConfirmation.transientNavigationChanged(pkg, isTransientNav);
+        }
+        vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
+
+        // don't send low profile updates if the system bars are hidden
+        if (mStatusBarController.isHidden() && mNavigationBarController.isHidden()) {
+            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        }
+        return vis;
+    }
+
+    private boolean isTransientNavigationAllowed(int vis) {
+        return mNavigationBar != null
+                && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                && (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
+    }
+
     // Use this instead of checking config_showNavigationBar so that it can be consistently
     // overridden by qemu.hw.mainkeys in the emulator.
+    @Override
     public boolean hasNavigationBar() {
         return mHasNavigationBar;
     }
@@ -4934,8 +5112,9 @@
 
     @Override
     public void setCurrentUserLw(int newUserId) {
-        if (mKeyguardMediator != null) {
-            mKeyguardMediator.setCurrentUser(newUserId);
+        mCurrentUserId = newUserId;
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.setCurrentUser(newUserId);
         }
         if (mStatusBarService != null) {
             try {
@@ -4948,11 +5127,6 @@
     }
 
     @Override
-    public void showAssistant() {
-        mKeyguardMediator.showAssistant();
-    }
-
-    @Override
     public boolean canMagnifyWindow(int windowType) {
         switch (windowType) {
             case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
@@ -5132,5 +5306,7 @@
         pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
                 pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
         pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
+        mStatusBarController.dump(pw, prefix);
+        mNavigationBarController.dump(pw, prefix);
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
new file mode 100644
index 0000000..4ff9315
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.content.Context;
+import android.util.Slog;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+/*
+ * Listens for system-wide input gestures, firing callbacks when detected.
+ * @hide
+ */
+public class SystemGesturesPointerEventListener implements PointerEventListener {
+    private static final String TAG = "SystemGestures";
+    private static final boolean DEBUG = false;
+    private static final long SWIPE_TIMEOUT_MS = 500;
+    private static final int MAX_TRACKED_POINTERS = 32;  // max per input system
+    private static final int UNTRACKED_POINTER = -1;
+
+    private static final int SWIPE_NONE = 0;
+    private static final int SWIPE_FROM_TOP = 1;
+    private static final int SWIPE_FROM_BOTTOM = 2;
+    private static final int SWIPE_FROM_RIGHT = 3;
+
+    private final int mSwipeStartThreshold;
+    private final int mSwipeDistanceThreshold;
+    private final Callbacks mCallbacks;
+    private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS];
+    private final float[] mDownX = new float[MAX_TRACKED_POINTERS];
+    private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
+    private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
+
+    int screenHeight;
+    int screenWidth;
+    private int mDownPointers;
+    private boolean mSwipeFireable;
+    private boolean mDebugFireable;
+
+    public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
+        mCallbacks = checkNull("callbacks", callbacks);
+        mSwipeStartThreshold = checkNull("context", context).getResources()
+                .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+        mSwipeDistanceThreshold = mSwipeStartThreshold;
+        if (DEBUG) Slog.d(TAG,  "mSwipeStartThreshold=" + mSwipeStartThreshold
+                + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold);
+    }
+
+    private static <T> T checkNull(String name, T arg) {
+        if (arg == null) {
+            throw new IllegalArgumentException(name + " must not be null");
+        }
+        return arg;
+    }
+
+    @Override
+    public void onPointerEvent(MotionEvent event) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mSwipeFireable = true;
+                mDebugFireable = true;
+                mDownPointers = 0;
+                captureDown(event, 0);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                captureDown(event, event.getActionIndex());
+                if (mDebugFireable) {
+                    mDebugFireable = event.getPointerCount() < 5;
+                    if (!mDebugFireable) {
+                        if (DEBUG) Slog.d(TAG, "Firing debug");
+                        mCallbacks.onDebug();
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mSwipeFireable) {
+                    final int swipe = detectSwipe(event);
+                    mSwipeFireable = swipe == SWIPE_NONE;
+                    if (swipe == SWIPE_FROM_TOP) {
+                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
+                        mCallbacks.onSwipeFromTop();
+                    } else if (swipe == SWIPE_FROM_BOTTOM) {
+                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom");
+                        mCallbacks.onSwipeFromBottom();
+                    } else if (swipe == SWIPE_FROM_RIGHT) {
+                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
+                        mCallbacks.onSwipeFromRight();
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mSwipeFireable = false;
+                mDebugFireable = false;
+                break;
+            default:
+                if (DEBUG) Slog.d(TAG, "Ignoring " + event);
+        }
+    }
+
+    private void captureDown(MotionEvent event, int pointerIndex) {
+        final int pointerId = event.getPointerId(pointerIndex);
+        final int i = findIndex(pointerId);
+        if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
+                " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
+        if (i != UNTRACKED_POINTER) {
+            mDownX[i] = event.getX(pointerIndex);
+            mDownY[i] = event.getY(pointerIndex);
+            mDownTime[i] = event.getEventTime();
+            if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
+                    " down x=" + mDownX[i] + " y=" + mDownY[i]);
+        }
+    }
+
+    private int findIndex(int pointerId) {
+        for (int i = 0; i < mDownPointers; i++) {
+            if (mDownPointerId[i] == pointerId) {
+                return i;
+            }
+        }
+        if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) {
+            return UNTRACKED_POINTER;
+        }
+        mDownPointerId[mDownPointers++] = pointerId;
+        return mDownPointers - 1;
+    }
+
+    private int detectSwipe(MotionEvent move) {
+        final int historySize = move.getHistorySize();
+        final int pointerCount = move.getPointerCount();
+        for (int p = 0; p < pointerCount; p++) {
+            final int pointerId = move.getPointerId(p);
+            final int i = findIndex(pointerId);
+            if (i != UNTRACKED_POINTER) {
+                for (int h = 0; h < historySize; h++) {
+                    final long time = move.getHistoricalEventTime(h);
+                    final float x = move.getHistoricalX(p, h);
+                    final float y = move.getHistoricalY(p,  h);
+                    final int swipe = detectSwipe(i, time, x, y);
+                    if (swipe != SWIPE_NONE) {
+                        return swipe;
+                    }
+                }
+                final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p));
+                if (swipe != SWIPE_NONE) {
+                    return swipe;
+                }
+            }
+        }
+        return SWIPE_NONE;
+    }
+
+    private int detectSwipe(int i, long time, float x, float y) {
+        final float fromX = mDownX[i];
+        final float fromY = mDownY[i];
+        final long elapsed = time - mDownTime[i];
+        if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i]
+                + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed);
+        if (fromY <= mSwipeStartThreshold
+                && y > fromY + mSwipeDistanceThreshold
+                && elapsed < SWIPE_TIMEOUT_MS) {
+            return SWIPE_FROM_TOP;
+        }
+        if (fromY >= screenHeight - mSwipeStartThreshold
+                && y < fromY - mSwipeDistanceThreshold
+                && elapsed < SWIPE_TIMEOUT_MS) {
+            return SWIPE_FROM_BOTTOM;
+        }
+        if (fromX >= screenWidth - mSwipeStartThreshold
+                && x < fromX - mSwipeDistanceThreshold
+                && elapsed < SWIPE_TIMEOUT_MS) {
+            return SWIPE_FROM_RIGHT;
+        }
+        return SWIPE_NONE;
+    }
+
+    interface Callbacks {
+        void onSwipeFromTop();
+        void onSwipeFromBottom();
+        void onSwipeFromRight();
+        void onDebug();
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
new file mode 100644
index 0000000..8613088
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.Toast;
+
+import com.android.internal.R;
+
+import java.util.Arrays;
+
+/**
+ *  Helper to manage showing/hiding a confirmation prompt when the transient navigation bar
+ *  is hidden.
+ */
+public class TransientNavigationConfirmation {
+    private static final String TAG = "TransientNavigationConfirmation";
+    private static final boolean DEBUG = false;
+
+    private final Context mContext;
+    private final H mHandler;
+    private final ArraySet<String> mConfirmedPackages = new ArraySet<String>();
+    private final long mShowDelayMs;
+    private final long mPanicThresholdMs;
+
+    private Toast mToast;
+    private String mLastPackage;
+    private String mPromptPackage;
+    private long mPanicTime;
+    private String mPanicPackage;
+
+    public TransientNavigationConfirmation(Context context) {
+        mContext = context;
+        mHandler = new H();
+        mShowDelayMs = getNavBarExitDuration() * 3;
+        mPanicThresholdMs = context.getResources()
+                .getInteger(R.integer.config_transient_navigation_confirmation_panic);
+    }
+
+    private long getNavBarExitDuration() {
+        Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit);
+        return exit != null ? exit.getDuration() : 0;
+    }
+
+    public void loadSetting() {
+        if (DEBUG) Slog.d(TAG, "loadSetting()");
+        mConfirmedPackages.clear();
+        String packages = null;
+        try {
+            packages = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+                    UserHandle.USER_CURRENT);
+            if (packages != null) {
+                mConfirmedPackages.addAll(Arrays.asList(packages.split(",")));
+                if (DEBUG) Slog.d(TAG, "Loaded mConfirmedPackages=" + mConfirmedPackages);
+            }
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error loading confirmations, packages=" + packages, t);
+        }
+    }
+
+    private void saveSetting() {
+        if (DEBUG) Slog.d(TAG, "saveSetting()");
+        try {
+            final String packages = TextUtils.join(",", mConfirmedPackages);
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+                    packages,
+                    UserHandle.USER_CURRENT);
+            if (DEBUG) Slog.d(TAG, "Saved packages=" + packages);
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error saving confirmations, mConfirmedPackages=" + mConfirmedPackages, t);
+        }
+    }
+
+    public void transientNavigationChanged(String pkg, boolean isNavTransient) {
+        if (pkg == null) {
+            return;
+        }
+        mHandler.removeMessages(H.SHOW);
+        if (isNavTransient) {
+            mLastPackage = pkg;
+            if (!mConfirmedPackages.contains(pkg)) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, pkg), mShowDelayMs);
+            }
+        } else {
+            mLastPackage = null;
+            mHandler.sendEmptyMessage(H.HIDE);
+        }
+    }
+
+    public void onPowerKeyDown(boolean isScreenOn, long time, boolean transientNavigationAllowed) {
+        if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
+            // turning the screen back on within the panic threshold
+            unconfirmPackage(mPanicPackage);
+        }
+        if (isScreenOn && transientNavigationAllowed) {
+            // turning the screen off, remember if we were hiding the transient nav
+            mPanicTime = time;
+            mPanicPackage = mLastPackage;
+        } else {
+            mPanicTime = 0;
+            mPanicPackage = null;
+        }
+    }
+
+    public void confirmCurrentPrompt() {
+        mHandler.post(confirmAction(mPromptPackage));
+    }
+
+    private void unconfirmPackage(String pkg) {
+        if (pkg != null) {
+            if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + pkg);
+            mConfirmedPackages.remove(pkg);
+            saveSetting();
+        }
+    }
+
+    private void handleHide() {
+        if (mToast != null) {
+            if (DEBUG) Slog.d(TAG,
+                    "Hiding transient navigation confirmation for " + mPromptPackage);
+            mToast.cancel();
+            mToast = null;
+        }
+    }
+
+    private void handleShow(String pkg) {
+        mPromptPackage = pkg;
+        if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + pkg);
+
+        // create the confirmation toast bar
+        final int msg = R.string.transient_navigation_confirmation;
+        mToast = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE);
+        mToast.setAction(R.string.ok, confirmAction(pkg));
+
+        // we will be hiding the nav bar, so layout as if it's already hidden
+        mToast.getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+
+        // show the confirmation
+        mToast.show();
+    }
+
+    private Runnable confirmAction(final String pkg) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                if (pkg != null && !mConfirmedPackages.contains(pkg)) {
+                    if (DEBUG) Slog.d(TAG, "Confirming transient navigation for " + pkg);
+                    mConfirmedPackages.add(pkg);
+                    saveSetting();
+                }
+                handleHide();
+            }
+        };
+    }
+
+    private final class H extends Handler {
+        private static final int SHOW = 0;
+        private static final int HIDE = 1;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case SHOW:
+                    handleShow((String)msg.obj);
+                    break;
+                case HIDE:
+                    handleHide();
+                    break;
+            }
+        }
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java
deleted file mode 100644
index e65a716f..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.view.View;
-
-interface BiometricSensorUnlock {
-    /**
-     * Initializes the view provided for the biometric unlock UI to work within.  The provided area
-     * completely covers the backup unlock mechanism.
-     * @param biometricUnlockView View provided for the biometric unlock UI.
-     */
-    public void initializeView(View biometricUnlockView);
-
-    /**
-     * Indicates whether the biometric unlock is running.  Before
-     * {@link BiometricSensorUnlock#start} is called, isRunning() returns false.  After a successful
-     * call to {@link BiometricSensorUnlock#start}, isRunning() returns true until the biometric
-     * unlock completes, {@link BiometricSensorUnlock#stop} has been called, or an error has
-     * forced the biometric unlock to stop.
-     * @return whether the biometric unlock is currently running.
-     */
-    public boolean isRunning();
-
-    /**
-     * Stops and removes the biometric unlock and shows the backup unlock
-     */
-    public void stopAndShowBackup();
-
-    /**
-     * Binds to the biometric unlock service and starts the unlock procedure.  Called on the UI
-     * thread.
-     * @return false if it can't be started or the backup should be used.
-     */
-    public boolean start();
-
-    /**
-     * Stops the biometric unlock procedure and unbinds from the service.  Called on the UI thread.
-     * @return whether the biometric unlock was running when called.
-     */
-    public boolean stop();
-
-    /**
-     * Cleans up any resources used by the biometric unlock.
-     */
-    public void cleanUp();
-
-    /**
-     * Gets the Device Policy Manager quality of the biometric unlock sensor
-     * (e.g., PASSWORD_QUALITY_BIOMETRIC_WEAK).
-     * @return biometric unlock sensor quality, as defined by Device Policy Manager.
-     */
-    public int getQuality();
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
deleted file mode 100644
index 762711d..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-
-import com.android.internal.R;
-import com.android.internal.policy.impl.keyguard.KeyguardActivityLauncher.CameraWidgetInfo;
-
-public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
-    private static final String TAG = CameraWidgetFrame.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
-    private static final int WIDGET_ANIMATION_DURATION = 250; // ms
-    private static final int WIDGET_WAIT_DURATION = 650; // ms
-    private static final int RECOVERY_DELAY = 1000; // ms
-
-    interface Callbacks {
-        void onLaunchingCamera();
-        void onCameraLaunchedSuccessfully();
-        void onCameraLaunchedUnsuccessfully();
-    }
-
-    private final Handler mHandler = new Handler();
-    private final KeyguardActivityLauncher mActivityLauncher;
-    private final Callbacks mCallbacks;
-    private final CameraWidgetInfo mWidgetInfo;
-    private final WindowManager mWindowManager;
-    private final Point mRenderedSize = new Point();
-    private final int[] mTmpLoc = new int[2];
-    private final Rect mTmpRect = new Rect();
-
-    private long mLaunchCameraStart;
-    private boolean mActive;
-    private boolean mTransitioning;
-    private boolean mDown;
-
-    private FixedSizeFrameLayout mPreview;
-    private View mFullscreenPreview;
-
-    private final Runnable mTransitionToCameraRunnable = new Runnable() {
-        @Override
-        public void run() {
-            transitionToCamera();
-        }};
-
-    private final Runnable mTransitionToCameraEndAction = new Runnable() {
-        @Override
-        public void run() {
-            if (!mTransitioning)
-                return;
-            Handler worker =  getWorkerHandler() != null ? getWorkerHandler() : mHandler;
-            mLaunchCameraStart = SystemClock.uptimeMillis();
-            if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart);
-            mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
-        }};
-
-    private final Runnable mPostTransitionToCameraEndAction = new Runnable() {
-        @Override
-        public void run() {
-            mHandler.post(mTransitionToCameraEndAction);
-        }};
-
-    private final Runnable mRecoverRunnable = new Runnable() {
-        @Override
-        public void run() {
-            recover();
-        }};
-
-    private final Runnable mRenderRunnable = new Runnable() {
-        @Override
-        public void run() {
-            render();
-        }};
-
-    private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() {
-        @Override
-        public void run() {
-            onSecureCameraActivityStarted();
-        }
-    };
-
-    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
-        private boolean mShowing;
-        void onKeyguardVisibilityChanged(boolean showing) {
-            if (mShowing == showing)
-                return;
-            mShowing = showing;
-            CameraWidgetFrame.this.onKeyguardVisibilityChanged(mShowing);
-        };
-    };
-
-    private static final class FixedSizeFrameLayout extends FrameLayout {
-        int width;
-        int height;
-
-        FixedSizeFrameLayout(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            measureChildren(
-                    MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-            setMeasuredDimension(width, height);
-        }
-    }
-
-    private CameraWidgetFrame(Context context, Callbacks callbacks,
-            KeyguardActivityLauncher activityLauncher,
-            CameraWidgetInfo widgetInfo, View previewWidget) {
-        super(context);
-        mCallbacks = callbacks;
-        mActivityLauncher = activityLauncher;
-        mWidgetInfo = widgetInfo;
-        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback);
-
-        mPreview = new FixedSizeFrameLayout(context);
-        mPreview.addView(previewWidget);
-        addView(mPreview);
-
-        View clickBlocker = new View(context);
-        clickBlocker.setBackgroundColor(Color.TRANSPARENT);
-        clickBlocker.setOnClickListener(this);
-        addView(clickBlocker);
-
-        setContentDescription(context.getString(R.string.keyguard_accessibility_camera));
-        if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId());
-    }
-
-    public static CameraWidgetFrame create(Context context, Callbacks callbacks,
-            KeyguardActivityLauncher launcher) {
-        if (context == null || callbacks == null || launcher == null)
-            return null;
-
-        CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo();
-        if (widgetInfo == null)
-            return null;
-        View previewWidget = getPreviewWidget(context, widgetInfo);
-        if (previewWidget == null)
-            return null;
-
-        return new CameraWidgetFrame(context, callbacks, launcher, widgetInfo, previewWidget);
-    }
-
-    private static View getPreviewWidget(Context context, CameraWidgetInfo widgetInfo) {
-        return widgetInfo.layoutId > 0 ?
-                inflateWidgetView(context, widgetInfo) :
-                inflateGenericWidgetView(context);
-    }
-
-    private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) {
-        if (DEBUG) Log.d(TAG, "inflateWidgetView: " + widgetInfo.contextPackage);
-        View widgetView = null;
-        Exception exception = null;
-        try {
-            Context cameraContext = context.createPackageContext(
-                    widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
-            LayoutInflater cameraInflater = (LayoutInflater)
-                    cameraContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            cameraInflater = cameraInflater.cloneInContext(cameraContext);
-            widgetView = cameraInflater.inflate(widgetInfo.layoutId, null, false);
-        } catch (NameNotFoundException e) {
-            exception = e;
-        } catch (RuntimeException e) {
-            exception = e;
-        }
-        if (exception != null) {
-            Log.w(TAG, "Error creating camera widget view", exception);
-        }
-        return widgetView;
-    }
-
-    private static View inflateGenericWidgetView(Context context) {
-        if (DEBUG) Log.d(TAG, "inflateGenericWidgetView");
-        ImageView iv = new ImageView(context);
-        iv.setImageResource(com.android.internal.R.drawable.ic_lockscreen_camera);
-        iv.setScaleType(ScaleType.CENTER);
-        iv.setBackgroundColor(Color.argb(127, 0, 0, 0));
-        return iv;
-    }
-
-    private void render() {
-        final View root = getRootView();
-        final int width = root.getWidth();
-        final int height = root.getHeight();
-        if (mRenderedSize.x == width && mRenderedSize.y == height) {
-            if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", width, height));
-            return;
-        }
-        if (width == 0 || height == 0) {
-            return;
-        }
-
-        mPreview.width = width;
-        mPreview.height = height;
-        mPreview.requestLayout();
-
-        final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight();
-        final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-
-        final float pvScaleX = (float) thisWidth / width;
-        final float pvScaleY = (float) thisHeight / height;
-        final float pvScale = Math.min(pvScaleX, pvScaleY);
-
-        final int pvWidth = (int) (pvScale * width);
-        final int pvHeight = (int) (pvScale * height);
-
-        final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0;
-        final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0;
-
-        mPreview.setPivotX(0);
-        mPreview.setPivotY(0);
-        mPreview.setScaleX(pvScale);
-        mPreview.setScaleY(pvScale);
-        mPreview.setTranslationX(pvTransX);
-        mPreview.setTranslationY(pvTransY);
-
-        mRenderedSize.set(width, height);
-        if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s",
-                width, height, instanceId()));
-    }
-
-    private void transitionToCamera() {
-        if (mTransitioning || mDown) return;
-
-        mTransitioning = true;
-
-        enableWindowExitAnimation(false);
-
-        mPreview.getLocationInWindow(mTmpLoc);
-        final float pvHeight = mPreview.getHeight() * mPreview.getScaleY();
-        final float pvCenter = mTmpLoc[1] + pvHeight / 2f;
-
-        final ViewGroup root = (ViewGroup) getRootView();
-        if (mFullscreenPreview == null) {
-            mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo);
-            mFullscreenPreview.setClickable(false);
-            root.addView(mFullscreenPreview);
-        }
-
-        root.getWindowVisibleDisplayFrame(mTmpRect);
-        final float fsHeight = mTmpRect.height();
-        final float fsCenter = mTmpRect.top + fsHeight / 2;
-
-        final float fsScaleY = pvHeight / fsHeight;
-        final float fsTransY = pvCenter - fsCenter;
-        final float fsScaleX = mPreview.getScaleX();
-
-        mPreview.setVisibility(View.GONE);
-        mFullscreenPreview.setVisibility(View.VISIBLE);
-        mFullscreenPreview.setTranslationY(fsTransY);
-        mFullscreenPreview.setScaleX(fsScaleX);
-        mFullscreenPreview.setScaleY(fsScaleY);
-        mFullscreenPreview
-            .animate()
-            .scaleX(1)
-            .scaleY(1)
-            .translationX(0)
-            .translationY(0)
-            .setDuration(WIDGET_ANIMATION_DURATION)
-            .withEndAction(mPostTransitionToCameraEndAction)
-            .start();
-        mCallbacks.onLaunchingCamera();
-    }
-
-    private void recover() {
-        if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
-        mCallbacks.onCameraLaunchedUnsuccessfully();
-        reset();
-    }
-
-    @Override
-    public void setOnLongClickListener(OnLongClickListener l) {
-        // ignore
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (DEBUG) Log.d(TAG, "clicked");
-        if (mTransitioning) return;
-        if (mActive) {
-            cancelTransitionToCamera();
-            transitionToCamera();
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (DEBUG) Log.d(TAG, "onDetachedFromWindow: instance " + instanceId()
-                + " at " + SystemClock.uptimeMillis());
-        super.onDetachedFromWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
-        cancelTransitionToCamera();
-        mHandler.removeCallbacks(mRecoverRunnable);
-    }
-
-    @Override
-    public void onActive(boolean isActive) {
-        mActive = isActive;
-        if (mActive) {
-            rescheduleTransitionToCamera();
-        } else {
-            reset();
-        }
-    }
-
-    @Override
-    public boolean onUserInteraction(MotionEvent event) {
-        if (mTransitioning) {
-            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning");
-            return true;
-        }
-
-        getLocationOnScreen(mTmpLoc);
-        int rawBottom = mTmpLoc[1] + getHeight();
-        if (event.getRawY() > rawBottom) {
-            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
-            return true;
-        }
-
-        int action = event.getAction();
-        mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE;
-        if (mActive) {
-            rescheduleTransitionToCamera();
-        }
-        if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten");
-        return false;
-    }
-
-    @Override
-    protected void onFocusLost() {
-        if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis());
-        cancelTransitionToCamera();
-        super.onFocusLost();
-    }
-
-    public void onScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, "onScreenTurnedOff");
-        reset();
-    }
-
-    private void rescheduleTransitionToCamera() {
-        if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis());
-        mHandler.removeCallbacks(mTransitionToCameraRunnable);
-        mHandler.postDelayed(mTransitionToCameraRunnable, WIDGET_WAIT_DURATION);
-    }
-
-    private void cancelTransitionToCamera() {
-        if (DEBUG) Log.d(TAG, "cancelTransitionToCamera at " + SystemClock.uptimeMillis());
-        mHandler.removeCallbacks(mTransitionToCameraRunnable);
-    }
-
-    private void onCameraLaunched() {
-        mCallbacks.onCameraLaunchedSuccessfully();
-        reset();
-    }
-
-    private void reset() {
-        if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
-        mLaunchCameraStart = 0;
-        mTransitioning = false;
-        mDown = false;
-        cancelTransitionToCamera();
-        mHandler.removeCallbacks(mRecoverRunnable);
-        mPreview.setVisibility(View.VISIBLE);
-        if (mFullscreenPreview != null) {
-            mFullscreenPreview.animate().cancel();
-            mFullscreenPreview.setVisibility(View.GONE);
-        }
-        enableWindowExitAnimation(true);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
-                w, h, oldw, oldh, SystemClock.uptimeMillis()));
-        mHandler.post(mRenderRunnable);
-        super.onSizeChanged(w, h, oldw, oldh);
-    }
-
-    @Override
-    public void onBouncerShowing(boolean showing) {
-        if (showing) {
-            mTransitioning = false;
-            mHandler.post(mRecoverRunnable);
-        }
-    }
-
-    private void enableWindowExitAnimation(boolean isEnabled) {
-        View root = getRootView();
-        ViewGroup.LayoutParams lp = root.getLayoutParams();
-        if (!(lp instanceof WindowManager.LayoutParams))
-            return;
-        WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
-        int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
-        if (newWindowAnimations != wlp.windowAnimations) {
-            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations
-                    + " at " + SystemClock.uptimeMillis());
-            wlp.windowAnimations = newWindowAnimations;
-            mWindowManager.updateViewLayout(root, wlp);
-        }
-    }
-
-    private void onKeyguardVisibilityChanged(boolean showing) {
-        if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing
-                + " at " + SystemClock.uptimeMillis());
-        if (mTransitioning && !showing) {
-            mTransitioning = false;
-            mHandler.removeCallbacks(mRecoverRunnable);
-            if (mLaunchCameraStart > 0) {
-                long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
-                if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
-                mLaunchCameraStart = 0;
-                onCameraLaunched();
-            }
-        }
-    }
-
-    private void onSecureCameraActivityStarted() {
-        if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis());
-        mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY);
-    }
-
-    private String instanceId() {
-        return Integer.toHexString(hashCode());
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
deleted file mode 100644
index a38e86d..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.widget.LockPatternUtils;
-
-public class CarrierText extends TextView {
-    private static CharSequence mSeparator;
-
-    private LockPatternUtils mLockPatternUtils;
-
-    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
-        private CharSequence mPlmn;
-        private CharSequence mSpn;
-        private State mSimState;
-
-        @Override
-        public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
-            mPlmn = plmn;
-            mSpn = spn;
-            updateCarrierText(mSimState, mPlmn, mSpn);
-        }
-
-        @Override
-        public void onSimStateChanged(IccCardConstants.State simState) {
-            mSimState = simState;
-            updateCarrierText(mSimState, mPlmn, mSpn);
-        }
-    };
-    /**
-     * The status of this lock screen. Primarily used for widgets on LockScreen.
-     */
-    private static enum StatusMode {
-        Normal, // Normal case (sim card present, it's not locked)
-        NetworkLocked, // SIM card is 'network locked'.
-        SimMissing, // SIM card is missing.
-        SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
-        SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
-        SimLocked, // SIM card is currently locked
-        SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
-        SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
-    }
-
-    public CarrierText(Context context) {
-        this(context, null);
-    }
-
-    public CarrierText(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mLockPatternUtils = new LockPatternUtils(mContext);
-    }
-
-    protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
-        CharSequence text = getCarrierTextForSimState(simState, plmn, spn);
-        if (KeyguardViewManager.USE_UPPER_CASE) {
-            setText(text != null ? text.toString().toUpperCase() : null);
-        } else {
-            setText(text);
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mSeparator = getResources().getString(R.string.kg_text_message_separator);
-        setSelected(true); // Allow marquee to work.
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
-    }
-
-    /**
-     * Top-level function for creating carrier text. Makes text based on simState, PLMN
-     * and SPN as well as device capabilities, such as being emergency call capable.
-     *
-     * @param simState
-     * @param plmn
-     * @param spn
-     * @return
-     */
-    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
-            CharSequence plmn, CharSequence spn) {
-        CharSequence carrierText = null;
-        StatusMode status = getStatusForIccState(simState);
-        switch (status) {
-            case Normal:
-                carrierText = concatenate(plmn, spn);
-                break;
-
-            case SimNotReady:
-                carrierText = null; // nothing to display yet.
-                break;
-
-            case NetworkLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        mContext.getText(R.string.lockscreen_network_locked_message), plmn);
-                break;
-
-            case SimMissing:
-                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
-                // This depends on mPlmn containing the text "Emergency calls only" when the radio
-                // has some connectivity. Otherwise, it should be null or empty and just show
-                // "No SIM card"
-                carrierText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
-                        plmn);
-                break;
-
-            case SimPermDisabled:
-                carrierText = getContext().getText(
-                        R.string.lockscreen_permanent_disabled_sim_message_short);
-                break;
-
-            case SimMissingLocked:
-                carrierText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
-                        plmn);
-                break;
-
-            case SimLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_sim_locked_message),
-                        plmn);
-                break;
-
-            case SimPukLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_sim_puk_locked_message),
-                        plmn);
-                break;
-        }
-
-        return carrierText;
-    }
-
-    /*
-     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
-     */
-    private CharSequence makeCarrierStringOnEmergencyCapable(
-            CharSequence simMessage, CharSequence emergencyCallMessage) {
-        if (mLockPatternUtils.isEmergencyCallCapable()) {
-            return concatenate(simMessage, emergencyCallMessage);
-        }
-        return simMessage;
-    }
-
-    /**
-     * Determine the current status of the lock screen given the SIM state and other stuff.
-     */
-    private StatusMode getStatusForIccState(IccCardConstants.State simState) {
-        // Since reading the SIM may take a while, we assume it is present until told otherwise.
-        if (simState == null) {
-            return StatusMode.Normal;
-        }
-
-        final boolean missingAndNotProvisioned =
-                !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
-                && (simState == IccCardConstants.State.ABSENT ||
-                        simState == IccCardConstants.State.PERM_DISABLED);
-
-        // Assume we're NETWORK_LOCKED if not provisioned
-        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
-        switch (simState) {
-            case ABSENT:
-                return StatusMode.SimMissing;
-            case NETWORK_LOCKED:
-                return StatusMode.SimMissingLocked;
-            case NOT_READY:
-                return StatusMode.SimNotReady;
-            case PIN_REQUIRED:
-                return StatusMode.SimLocked;
-            case PUK_REQUIRED:
-                return StatusMode.SimPukLocked;
-            case READY:
-                return StatusMode.Normal;
-            case PERM_DISABLED:
-                return StatusMode.SimPermDisabled;
-            case UNKNOWN:
-                return StatusMode.SimMissing;
-        }
-        return StatusMode.SimMissing;
-    }
-
-    private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
-        final boolean plmnValid = !TextUtils.isEmpty(plmn);
-        final boolean spnValid = !TextUtils.isEmpty(spn);
-        if (plmnValid && spnValid) {
-            return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
-        } else if (plmnValid) {
-            return plmn;
-        } else if (spnValid) {
-            return spn;
-        } else {
-            return "";
-        }
-    }
-
-    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
-            String plmn, String spn) {
-        int carrierHelpTextId = 0;
-        StatusMode status = getStatusForIccState(simState);
-        switch (status) {
-            case NetworkLocked:
-                carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled;
-                break;
-
-            case SimMissing:
-                carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long;
-                break;
-
-            case SimPermDisabled:
-                carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions;
-                break;
-
-            case SimMissingLocked:
-                carrierHelpTextId = R.string.lockscreen_missing_sim_instructions;
-                break;
-
-            case Normal:
-            case SimLocked:
-            case SimPukLocked:
-                break;
-        }
-
-        return mContext.getText(carrierHelpTextId);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/ChallengeLayout.java
deleted file mode 100644
index 8ece559..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/ChallengeLayout.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-/**
- * Interface implemented by ViewGroup-derived layouts that implement
- * special logic for presenting security challenges to the user.
- */
-public interface ChallengeLayout {
-    /**
-     * @return true if the security challenge area of this layout is currently visible
-     */
-    boolean isChallengeShowing();
-
-    /**
-     * @return true if the challenge area significantly overlaps other content
-     */
-    boolean isChallengeOverlapping();
-
-    /**
-     * Show or hide the challenge layout.
-     *
-     * If you want to show the challenge layout in bouncer mode where applicable,
-     * use {@link #showBouncer()} instead.
-     *
-     * @param b true to show, false to hide
-     */
-    void showChallenge(boolean b);
-
-    /**
-     * Show the bouncer challenge. This may block access to other child views.
-     */
-    void showBouncer();
-
-    /**
-     * Hide the bouncer challenge if it is currently showing.
-     * This may restore previously blocked access to other child views.
-     */
-    void hideBouncer();
-
-    /**
-     * Returns true if the challenge is currently in bouncer mode,
-     * potentially blocking access to other child views.
-     */
-    boolean isBouncing();
-
-    /**
-     * Returns the duration of the bounce animation.
-     */
-    int getBouncerAnimationDuration();
-
-    /**
-     * Set a listener that will respond to changes in bouncer state.
-     *
-     * @param listener listener to register
-     */
-    void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener);
-
-    /**
-     * Listener interface that reports changes in bouncer state.
-     * The bouncer is
-     */
-    public interface OnBouncerStateChangedListener {
-        /**
-         * Called when the bouncer state changes.
-         * The bouncer is activated when the user must pass a security challenge
-         * to proceed with the requested action.
-         *
-         * <p>This differs from simply showing or hiding the security challenge
-         * as the bouncer will prevent interaction with other elements of the UI.
-         * If the user attempts to escape from the bouncer, it will be dismissed,
-         * this method will be called with false as the parameter, and the action
-         * should be canceled. If the security component reports a successful
-         * authentication and the containing code calls hideBouncer() as a result,
-         * this method will also be called with a false parameter. It is up to the
-         * caller of hideBouncer to be ready for this.</p>
-         *
-         * @param bouncerActive true if the bouncer is now active,
-         *                      false if the bouncer was dismissed.
-         */
-        public void onBouncerStateChanged(boolean bouncerActive);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java b/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java
deleted file mode 100644
index 4825e23..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-public class CheckLongPressHelper {
-    private View mView;
-    private boolean mHasPerformedLongPress;
-    private CheckForLongPress mPendingCheckForLongPress;
-    private float mDownX, mDownY;
-    private int mLongPressTimeout;
-    private int mScaledTouchSlop;
-
-    class CheckForLongPress implements Runnable {
-        public void run() {
-            if ((mView.getParent() != null) && mView.hasWindowFocus()
-                    && !mHasPerformedLongPress) {
-                if (mView.performLongClick()) {
-                    mView.setPressed(false);
-                    mHasPerformedLongPress = true;
-                }
-            }
-        }
-    }
-
-    public CheckLongPressHelper(View v) {
-        mScaledTouchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
-        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
-        mView = v;
-    }
-
-    public void postCheckForLongPress(MotionEvent ev) {
-        mDownX = ev.getX();
-        mDownY = ev.getY();
-        mHasPerformedLongPress = false;
-
-        if (mPendingCheckForLongPress == null) {
-            mPendingCheckForLongPress = new CheckForLongPress();
-        }
-        mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout);
-    }
-
-    public void onMove(MotionEvent ev) {
-        float x = ev.getX();
-        float y = ev.getY();
-        boolean xMoved = Math.abs(mDownX - x) > mScaledTouchSlop;
-        boolean yMoved = Math.abs(mDownY - y) > mScaledTouchSlop;
-
-        if (xMoved || yMoved) {
-            cancelLongPress();
-        }
-    }
-
-    public void cancelLongPress() {
-        mHasPerformedLongPress = false;
-        if (mPendingCheckForLongPress != null) {
-            mView.removeCallbacks(mPendingCheckForLongPress);
-            mPendingCheckForLongPress = null;
-        }
-    }
-
-    public boolean hasPerformedLongPress() {
-        return mHasPerformedLongPress;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java b/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java
deleted file mode 100644
index 34bf6e7..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.graphics.Typeface;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import java.lang.ref.WeakReference;
-import java.text.DateFormatSymbols;
-import java.util.Calendar;
-import com.android.internal.R;
-
-/**
- * Displays the time
- */
-public class ClockView extends RelativeLayout {
-    private static final String ANDROID_CLOCK_FONT_FILE = "/system/fonts/AndroidClock.ttf";
-    private final static String M12 = "h:mm";
-    private final static String M24 = "HH:mm";
-
-    private Calendar mCalendar;
-    private String mFormat;
-    private TextView mTimeView;
-    private AmPm mAmPm;
-    private ContentObserver mFormatChangeObserver;
-    private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced
-
-    /* called by system on minute ticks */
-    private final Handler mHandler = new Handler();
-    private BroadcastReceiver mIntentReceiver;
-
-    private static class TimeChangedReceiver extends BroadcastReceiver {
-        private WeakReference<ClockView> mClock;
-        private Context mContext;
-
-        public TimeChangedReceiver(ClockView clock) {
-            mClock = new WeakReference<ClockView>(clock);
-            mContext = clock.getContext();
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // Post a runnable to avoid blocking the broadcast.
-            final boolean timezoneChanged =
-                    intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
-            final ClockView clock = mClock.get();
-            if (clock != null) {
-                clock.mHandler.post(new Runnable() {
-                    public void run() {
-                        if (timezoneChanged) {
-                            clock.mCalendar = Calendar.getInstance();
-                        }
-                        clock.updateTime();
-                    }
-                });
-            } else {
-                try {
-                    mContext.unregisterReceiver(this);
-                } catch (RuntimeException e) {
-                    // Shouldn't happen
-                }
-            }
-        }
-    };
-
-    static class AmPm {
-        private TextView mAmPmTextView;
-        private String mAmString, mPmString;
-
-        AmPm(View parent, Typeface tf) {
-            // No longer used, uncomment if we decide to use AM/PM indicator again
-            // mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm);
-            if (mAmPmTextView != null && tf != null) {
-                mAmPmTextView.setTypeface(tf);
-            }
-
-            String[] ampm = new DateFormatSymbols().getAmPmStrings();
-            mAmString = ampm[0];
-            mPmString = ampm[1];
-        }
-
-        void setShowAmPm(boolean show) {
-            if (mAmPmTextView != null) {
-                mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE);
-            }
-        }
-
-        void setIsMorning(boolean isMorning) {
-            if (mAmPmTextView != null) {
-                mAmPmTextView.setText(isMorning ? mAmString : mPmString);
-            }
-        }
-    }
-
-    private static class FormatChangeObserver extends ContentObserver {
-        private WeakReference<ClockView> mClock;
-        private Context mContext;
-        public FormatChangeObserver(ClockView clock) {
-            super(new Handler());
-            mClock = new WeakReference<ClockView>(clock);
-            mContext = clock.getContext();
-        }
-        @Override
-        public void onChange(boolean selfChange) {
-            ClockView digitalClock = mClock.get();
-            if (digitalClock != null) {
-                digitalClock.setDateFormat();
-                digitalClock.updateTime();
-            } else {
-                try {
-                    mContext.getContentResolver().unregisterContentObserver(this);
-                } catch (RuntimeException e) {
-                    // Shouldn't happen
-                }
-            }
-        }
-    }
-
-    public ClockView(Context context) {
-        this(context, null);
-    }
-
-    public ClockView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mTimeView = (TextView) findViewById(R.id.clock_text);
-        mTimeView.setTypeface(Typeface.createFromFile(ANDROID_CLOCK_FONT_FILE));
-        mAmPm = new AmPm(this, null);
-        mCalendar = Calendar.getInstance();
-        setDateFormat();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        mAttached++;
-
-        /* monitor time ticks, time changed, timezone */
-        if (mIntentReceiver == null) {
-            mIntentReceiver = new TimeChangedReceiver(this);
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_TIME_TICK);
-            filter.addAction(Intent.ACTION_TIME_CHANGED);
-            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-            mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.OWNER, filter, null, null );
-        }
-
-        /* monitor 12/24-hour display preference */
-        if (mFormatChangeObserver == null) {
-            mFormatChangeObserver = new FormatChangeObserver(this);
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.System.CONTENT_URI, true, mFormatChangeObserver);
-        }
-
-        updateTime();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        mAttached--;
-
-        if (mIntentReceiver != null) {
-            mContext.unregisterReceiver(mIntentReceiver);
-        }
-        if (mFormatChangeObserver != null) {
-            mContext.getContentResolver().unregisterContentObserver(
-                    mFormatChangeObserver);
-        }
-
-        mFormatChangeObserver = null;
-        mIntentReceiver = null;
-    }
-
-    void updateTime(Calendar c) {
-        mCalendar = c;
-        updateTime();
-    }
-
-    public void updateTime() {
-        mCalendar.setTimeInMillis(System.currentTimeMillis());
-
-        CharSequence newTime = DateFormat.format(mFormat, mCalendar);
-        mTimeView.setText(newTime);
-        mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0);
-    }
-
-    private void setDateFormat() {
-        mFormat = android.text.format.DateFormat.is24HourFormat(getContext()) ? M24 : M12;
-        mAmPm.setShowAmPm(mFormat.equals(M12));
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
deleted file mode 100644
index c68bab5..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
+++ /dev/null
@@ -1,132 +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 com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.Button;
-
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.widget.LockPatternUtils;
-
-/**
- * This class implements a smart emergency button that updates itself based
- * on telephony state.  When the phone is idle, it is an emergency call button.
- * When there's a call in progress, it presents an appropriate message and
- * allows the user to return to the call.
- */
-public class EmergencyButton extends Button {
-
-    private static final int EMERGENCY_CALL_TIMEOUT = 10000; // screen timeout after starting e.d.
-    private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
-
-    KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
-
-        @Override
-        public void onSimStateChanged(State simState) {
-            int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState();
-            updateEmergencyCallButton(simState, phoneState);
-        }
-
-        void onPhoneStateChanged(int phoneState) {
-            State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState();
-            updateEmergencyCallButton(simState, phoneState);
-        };
-    };
-    private LockPatternUtils mLockPatternUtils;
-    private PowerManager mPowerManager;
-
-    public EmergencyButton(Context context) {
-        this(context, null);
-    }
-
-    public EmergencyButton(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mLockPatternUtils = new LockPatternUtils(mContext);
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                takeEmergencyCallAction();
-            }
-        });
-        int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState();
-        State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState();
-        updateEmergencyCallButton(simState, phoneState);
-    }
-
-    /**
-     * Shows the emergency dialer or returns the user to the existing call.
-     */
-    public void takeEmergencyCallAction() {
-        // TODO: implement a shorter timeout once new PowerManager API is ready.
-        // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
-        mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
-        if (TelephonyManager.getDefault().getCallState()
-                == TelephonyManager.CALL_STATE_OFFHOOK) {
-            mLockPatternUtils.resumeCall();
-        } else {
-            Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            getContext().startActivityAsUser(intent,
-                    new UserHandle(mLockPatternUtils.getCurrentUser()));
-        }
-    }
-
-    private void updateEmergencyCallButton(State simState, int phoneState) {
-        boolean enabled = false;
-        if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
-            enabled = true; // always show "return to call" if phone is off-hook
-        } else if (mLockPatternUtils.isEmergencyCallCapable()) {
-            boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimLocked();
-            if (simLocked) {
-                // Some countries can't handle emergency calls while SIM is locked.
-                enabled = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
-            } else {
-                // True if we need to show a secure screen (pin/pattern/SIM pin/SIM puk);
-                // hides emergency button on "Slide" screen if device is not secure.
-                enabled = mLockPatternUtils.isSecure();
-            }
-        }
-        mLockPatternUtils.updateEmergencyCallButtonState(this, phoneState, enabled,
-                KeyguardViewManager.USE_UPPER_CASE, false);
-    }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java
deleted file mode 100644
index cfe1ef4..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.internal.R;
-
-public class EmergencyCarrierArea extends LinearLayout {
-
-    private CarrierText mCarrierText;
-    private EmergencyButton mEmergencyButton;
-
-    public EmergencyCarrierArea(Context context) {
-        super(context);
-    }
-
-    public EmergencyCarrierArea(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mCarrierText = (CarrierText) findViewById(R.id.carrier_text);
-        mEmergencyButton = (EmergencyButton) findViewById(R.id.emergency_call_button);
-
-        // The emergency button overlaps the carrier text, only noticeable when highlighted.
-        // So temporarily hide the carrier text while the emergency button is pressed.
-        mEmergencyButton.setOnTouchListener(new OnTouchListener(){
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                switch(event.getAction()) {
-                    case MotionEvent.ACTION_DOWN:
-                        mCarrierText.animate().alpha(0);
-                        break;
-                    case MotionEvent.ACTION_UP:
-                        mCarrierText.animate().alpha(1);
-                        break;
-                }
-                return false;
-            }});
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
deleted file mode 100644
index e58eb5b..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.policy.IFaceLockCallback;
-import com.android.internal.policy.IFaceLockInterface;
-import com.android.internal.widget.LockPatternUtils;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.View;
-
-public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
-
-    private static final boolean DEBUG = false;
-    private static final String TAG = "FULLockscreen";
-
-    private final Context mContext;
-    private final LockPatternUtils mLockPatternUtils;
-
-    // TODO: is mServiceRunning needed or can we just use mIsRunning or check if mService is null?
-    private boolean mServiceRunning = false;
-    // TODO: now that the code has been restructure to do almost all operations from a handler, this
-    // lock may no longer be necessary.
-    private final Object mServiceRunningLock = new Object();
-    private IFaceLockInterface mService;
-    private boolean mBoundToService = false;
-    private View mFaceUnlockView;
-
-    private Handler mHandler;
-    private final int MSG_SERVICE_CONNECTED = 0;
-    private final int MSG_SERVICE_DISCONNECTED = 1;
-    private final int MSG_UNLOCK = 2;
-    private final int MSG_CANCEL = 3;
-    private final int MSG_REPORT_FAILED_ATTEMPT = 4;
-    private final int MSG_POKE_WAKELOCK = 5;
-
-    // TODO: This was added for the purpose of adhering to what the biometric interface expects
-    // the isRunning() function to return.  However, it is probably not necessary to have both
-    // mRunning and mServiceRunning.  I'd just rather wait to change that logic.
-    private volatile boolean mIsRunning = false;
-
-    // So the user has a consistent amount of time when brought to the backup method from Face
-    // Unlock
-    private final int BACKUP_LOCK_TIMEOUT = 5000;
-
-    KeyguardSecurityCallback mKeyguardScreenCallback;
-
-    /**
-     * Stores some of the structures that Face Unlock will need to access and creates the handler
-     * will be used to execute messages on the UI thread.
-     */
-    public FaceUnlock(Context context) {
-        mContext = context;
-        mLockPatternUtils = new LockPatternUtils(context);
-        mHandler = new Handler(this);
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback) {
-        mKeyguardScreenCallback = keyguardScreenCallback;
-    }
-
-    /**
-     * Stores and displays the view that Face Unlock is allowed to draw within.
-     * TODO: since the layout object will eventually be shared by multiple biometric unlock
-     * methods, we will have to add our other views (background, cancel button) here.
-     */
-    public void initializeView(View biometricUnlockView) {
-        Log.d(TAG, "initializeView()");
-        mFaceUnlockView = biometricUnlockView;
-    }
-
-    /**
-     * Indicates whether Face Unlock is currently running.
-     */
-    public boolean isRunning() {
-        return mIsRunning;
-    }
-
-    /**
-     * Dismisses face unlock and goes to the backup lock
-     */
-    public void stopAndShowBackup() {
-        if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
-        mHandler.sendEmptyMessage(MSG_CANCEL);
-    }
-
-    /**
-     * Binds to the Face Unlock service.  Face Unlock will be started when the bind completes.  The
-     * Face Unlock view is displayed to hide the backup lock while the service is starting up.
-     * Called on the UI thread.
-     */
-    public boolean start() {
-        if (DEBUG) Log.d(TAG, "start()");
-        if (mHandler.getLooper() != Looper.myLooper()) {
-            Log.e(TAG, "start() called off of the UI thread");
-        }
-
-        if (mIsRunning) {
-            Log.w(TAG, "start() called when already running");
-        }
-
-        if (!mBoundToService) {
-            Log.d(TAG, "Binding to Face Unlock service for user="
-                    + mLockPatternUtils.getCurrentUser());
-            mContext.bindServiceAsUser(new Intent(IFaceLockInterface.class.getName()),
-                    mConnection,
-                    Context.BIND_AUTO_CREATE,
-                    new UserHandle(mLockPatternUtils.getCurrentUser()));
-            mBoundToService = true;
-        } else {
-            Log.w(TAG, "Attempt to bind to Face Unlock when already bound");
-        }
-
-        mIsRunning = true;
-        return true;
-    }
-
-    /**
-     * Stops Face Unlock and unbinds from the service.  Called on the UI thread.
-     */
-    public boolean stop() {
-        if (DEBUG) Log.d(TAG, "stop()");
-        if (mHandler.getLooper() != Looper.myLooper()) {
-            Log.e(TAG, "stop() called from non-UI thread");
-        }
-
-        // Clearing any old service connected messages.
-        mHandler.removeMessages(MSG_SERVICE_CONNECTED);
-
-        boolean mWasRunning = mIsRunning;
-
-        stopUi();
-
-        if (mBoundToService) {
-            if (mService != null) {
-                try {
-                    mService.unregisterCallback(mFaceUnlockCallback);
-                } catch (RemoteException e) {
-                    // Not much we can do
-                }
-            }
-            Log.d(TAG, "Unbinding from Face Unlock service");
-            mContext.unbindService(mConnection);
-            mBoundToService = false;
-        } else {
-            // This is usually not an error when this happens.  Sometimes we will tell it to
-            // unbind multiple times because it's called from both onWindowFocusChanged and
-            // onDetachedFromWindow.
-            if (DEBUG) Log.d(TAG, "Attempt to unbind from Face Unlock when not bound");
-        }
-        mIsRunning = false;
-        return mWasRunning;
-    }
-
-    /**
-     * Frees up resources used by Face Unlock and stops it if it is still running.
-     */
-    public void cleanUp() {
-        if (DEBUG) Log.d(TAG, "cleanUp()");
-        if (mService != null) {
-            try {
-                mService.unregisterCallback(mFaceUnlockCallback);
-            } catch (RemoteException e) {
-                // Not much we can do
-            }
-            stopUi();
-            mService = null;
-        }
-    }
-
-    /**
-     * Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK.
-     */
-    public int getQuality() {
-        return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
-    }
-
-    /**
-     * Handles messages such that everything happens on the UI thread in a deterministic order.
-     * Calls from the Face Unlock service come from binder threads.  Calls from lockscreen typically
-     * come from the UI thread.  This makes sure there are no race conditions between those calls.
-     */
-    public boolean handleMessage(Message msg) {
-        switch (msg.what) {
-            case MSG_SERVICE_CONNECTED:
-                handleServiceConnected();
-                break;
-            case MSG_SERVICE_DISCONNECTED:
-                handleServiceDisconnected();
-                break;
-            case MSG_UNLOCK:
-                handleUnlock(msg.arg1);
-                break;
-            case MSG_CANCEL:
-                handleCancel();
-                break;
-            case MSG_REPORT_FAILED_ATTEMPT:
-                handleReportFailedAttempt();
-                break;
-            case MSG_POKE_WAKELOCK:
-                handlePokeWakelock(msg.arg1);
-                break;
-            default:
-                Log.e(TAG, "Unhandled message");
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Tells the service to start its UI via an AIDL interface.  Called when the
-     * onServiceConnected() callback is received.
-     */
-    void handleServiceConnected() {
-        Log.d(TAG, "handleServiceConnected()");
-
-        // It is possible that an unbind has occurred in the time between the bind and when this
-        // function is reached.  If an unbind has already occurred, proceeding on to call startUi()
-        // can result in a fatal error.  Note that the onServiceConnected() callback is
-        // asynchronous, so this possibility would still exist if we executed this directly in
-        // onServiceConnected() rather than using a handler.
-        if (!mBoundToService) {
-            Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
-            return;
-        }
-
-        try {
-            mService.registerCallback(mFaceUnlockCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString());
-            mService = null;
-            mBoundToService = false;
-            mIsRunning = false;
-            return;
-        }
-
-        if (mFaceUnlockView != null) {
-            IBinder windowToken = mFaceUnlockView.getWindowToken();
-            if (windowToken != null) {
-                // When switching between portrait and landscape view while Face Unlock is running,
-                // the screen will eventually go dark unless we poke the wakelock when Face Unlock
-                // is restarted.
-                mKeyguardScreenCallback.userActivity(0);
-
-                int[] position;
-                position = new int[2];
-                mFaceUnlockView.getLocationInWindow(position);
-                startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(),
-                        mFaceUnlockView.getHeight());
-            } else {
-                Log.e(TAG, "windowToken is null in handleServiceConnected()");
-            }
-        }
-    }
-
-    /**
-     * Called when the onServiceDisconnected() callback is received.  This should not happen during
-     * normal operation.  It indicates an error has occurred.
-     */
-    void handleServiceDisconnected() {
-        Log.e(TAG, "handleServiceDisconnected()");
-        // TODO: this lock may no longer be needed now that everything is being called from a
-        // handler
-        synchronized (mServiceRunningLock) {
-            mService = null;
-            mServiceRunning = false;
-        }
-        mBoundToService = false;
-        mIsRunning = false;
-    }
-
-    /**
-     * Stops the Face Unlock service and tells the device to grant access to the user.
-     */
-    void handleUnlock(int authenticatedUserId) {
-        if (DEBUG) Log.d(TAG, "handleUnlock()");
-        stop();
-        int currentUserId = mLockPatternUtils.getCurrentUser();
-        if (authenticatedUserId == currentUserId) {
-            if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
-            mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
-            mKeyguardScreenCallback.dismiss(true);
-        } else {
-            Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
-                    ") because the current user is " + currentUserId);
-        }
-    }
-
-    /**
-     * Stops the Face Unlock service and goes to the backup lock.
-     */
-    void handleCancel() {
-        if (DEBUG) Log.d(TAG, "handleCancel()");
-        // We are going to the backup method, so we don't want to see Face Unlock again until the
-        // next time the user visits keyguard.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
-
-        mKeyguardScreenCallback.showBackupSecurity();
-        stop();
-        mKeyguardScreenCallback.userActivity(BACKUP_LOCK_TIMEOUT);
-    }
-
-    /**
-     * Increments the number of failed Face Unlock attempts.
-     */
-    void handleReportFailedAttempt() {
-        if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()");
-        // We are going to the backup method, so we don't want to see Face Unlock again until the
-        // next time the user visits keyguard.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
-
-        mKeyguardScreenCallback.reportFailedUnlockAttempt();
-    }
-
-    /**
-     * If the screen is on, pokes the wakelock to keep the screen alive and active for a specific
-     * amount of time.
-     */
-    void handlePokeWakelock(int millis) {
-      PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-      if (powerManager.isScreenOn()) {
-        mKeyguardScreenCallback.userActivity(millis);
-      }
-    }
-
-    /**
-     * Implements service connection methods.
-     */
-    private ServiceConnection mConnection = new ServiceConnection() {
-        /**
-         * Called when the Face Unlock service connects after calling bind().
-         */
-        public void onServiceConnected(ComponentName className, IBinder iservice) {
-            Log.d(TAG, "Connected to Face Unlock service");
-            mService = IFaceLockInterface.Stub.asInterface(iservice);
-            mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED);
-        }
-
-        /**
-         * Called if the Face Unlock service unexpectedly disconnects.  This indicates an error.
-         */
-        public void onServiceDisconnected(ComponentName className) {
-            Log.e(TAG, "Unexpected disconnect from Face Unlock service");
-            mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED);
-        }
-    };
-
-    /**
-     * Tells the Face Unlock service to start displaying its UI and start processing.
-     */
-    private void startUi(IBinder windowToken, int x, int y, int w, int h) {
-        if (DEBUG) Log.d(TAG, "startUi()");
-        synchronized (mServiceRunningLock) {
-            if (!mServiceRunning) {
-                Log.d(TAG, "Starting Face Unlock");
-                try {
-                    mService.startUi(windowToken, x, y, w, h,
-                            mLockPatternUtils.isBiometricWeakLivelinessEnabled());
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
-                    return;
-                }
-                mServiceRunning = true;
-            } else {
-                Log.w(TAG, "startUi() attempted while running");
-            }
-        }
-    }
-
-    /**
-     * Tells the Face Unlock service to stop displaying its UI and stop processing.
-     */
-    private void stopUi() {
-        if (DEBUG) Log.d(TAG, "stopUi()");
-        // Note that attempting to stop Face Unlock when it's not running is not an issue.
-        // Face Unlock can return, which stops it and then we try to stop it when the
-        // screen is turned off.  That's why we check.
-        synchronized (mServiceRunningLock) {
-            if (mServiceRunning) {
-                Log.d(TAG, "Stopping Face Unlock");
-                try {
-                    mService.stopUi();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString());
-                }
-                mServiceRunning = false;
-            } else {
-                // This is usually not an error when this happens.  Sometimes we will tell it to
-                // stop multiple times because it's called from both onWindowFocusChanged and
-                // onDetachedFromWindow.
-                if (DEBUG) Log.d(TAG, "stopUi() attempted while not running");
-            }
-        }
-    }
-
-    /**
-     * Implements the AIDL biometric unlock service callback interface.
-     */
-    private final IFaceLockCallback mFaceUnlockCallback = new IFaceLockCallback.Stub() {
-        /**
-         * Called when Face Unlock wants to grant access to the user.
-         */
-        public void unlock() {
-            if (DEBUG) Log.d(TAG, "unlock()");
-            Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1);
-            mHandler.sendMessage(message);
-        }
-
-        /**
-         * Called when Face Unlock wants to go to the backup.
-         */
-        public void cancel() {
-            if (DEBUG) Log.d(TAG, "cancel()");
-            mHandler.sendEmptyMessage(MSG_CANCEL);
-        }
-
-        /**
-         * Called when Face Unlock wants to increment the number of failed attempts.
-         */
-        public void reportFailedAttempt() {
-            if (DEBUG) Log.d(TAG, "reportFailedAttempt()");
-            mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT);
-        }
-
-        /**
-         * Called when Face Unlock wants to keep the screen alive and active for a specific amount
-         * of time.
-         */
-        public void pokeWakelock(int millis) {
-            if (DEBUG) Log.d(TAG, "pokeWakelock() for " + millis + "ms");
-            Message message = mHandler.obtainMessage(MSG_POKE_WAKELOCK, millis, -1);
-            mHandler.sendMessage(message);
-        }
-
-    };
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
deleted file mode 100644
index cc520dc..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.CountDownTimer;
-import android.os.SystemClock;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-/**
- * Base class for PIN and password unlock screens.
- */
-public abstract class KeyguardAbsKeyInputView extends LinearLayout
-        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
-    protected KeyguardSecurityCallback mCallback;
-    protected TextView mPasswordEntry;
-    protected LockPatternUtils mLockPatternUtils;
-    protected SecurityMessageDisplay mSecurityMessageDisplay;
-    protected View mEcaView;
-    private Drawable mBouncerFrame;
-    protected boolean mEnableHaptics;
-
-    // To avoid accidental lockout due to events while the device in in the pocket, ignore
-    // any passwords with length less than or equal to this length.
-    protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
-
-    public KeyguardAbsKeyInputView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-        mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        if (hasWindowFocus) {
-            reset();
-        }
-    }
-
-    public void reset() {
-        // start fresh
-        mPasswordEntry.setText("");
-        mPasswordEntry.requestFocus();
-
-        // if the user is currently locked out, enforce it.
-        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
-        if (deadline != 0) {
-            handleAttemptLockout(deadline);
-        } else {
-            resetState();
-        }
-    }
-
-    protected abstract int getPasswordTextViewId();
-    protected abstract void resetState();
-
-    @Override
-    protected void onFinishInflate() {
-        mLockPatternUtils = new LockPatternUtils(mContext);
-
-        mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
-        mPasswordEntry.setOnEditorActionListener(this);
-        mPasswordEntry.addTextChangedListener(this);
-
-        // Set selected property on so the view can send accessibility events.
-        mPasswordEntry.setSelected(true);
-
-        // Poke the wakelock any time the text is selected or modified
-        mPasswordEntry.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                mCallback.userActivity(0); // TODO: customize timeout for text?
-            }
-        });
-
-        mPasswordEntry.addTextChangedListener(new TextWatcher() {
-            public void onTextChanged(CharSequence s, int start, int before, int count) {
-            }
-
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            }
-
-            public void afterTextChanged(Editable s) {
-                if (mCallback != null) {
-                    mCallback.userActivity(0);
-                }
-            }
-        });
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
-        if (bouncerFrameView != null) {
-            mBouncerFrame = bouncerFrameView.getBackground();
-        }
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        // send focus to the password field
-        return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
-    }
-
-    /*
-     * Override this if you have a different string for "wrong password"
-     *
-     * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
-     */
-    protected int getWrongPasswordStringId() {
-        return R.string.kg_wrong_password;
-    }
-
-    protected void verifyPasswordAndUnlock() {
-        String entry = mPasswordEntry.getText().toString();
-        if (mLockPatternUtils.checkPassword(entry)) {
-            mCallback.reportSuccessfulUnlockAttempt();
-            mCallback.dismiss(true);
-        } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
-            // to avoid accidental lockout, only count attempts that are long enough to be a
-            // real password. This may require some tweaking.
-            mCallback.reportFailedUnlockAttempt();
-            if (0 == (mCallback.getFailedAttempts()
-                    % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
-                long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
-                handleAttemptLockout(deadline);
-            }
-            mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
-        }
-        mPasswordEntry.setText("");
-    }
-
-    // Prevent user from using the PIN/Password entry until scheduled deadline.
-    protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
-        mPasswordEntry.setEnabled(false);
-        long elapsedRealtime = SystemClock.elapsedRealtime();
-        new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
-
-            @Override
-            public void onTick(long millisUntilFinished) {
-                int secondsRemaining = (int) (millisUntilFinished / 1000);
-                mSecurityMessageDisplay.setMessage(
-                        R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
-            }
-
-            @Override
-            public void onFinish() {
-                mSecurityMessageDisplay.setMessage("", false);
-                resetState();
-            }
-        }.start();
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        mCallback.userActivity(0);
-        return false;
-    }
-
-    @Override
-    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-        // Check if this was the result of hitting the enter key
-        if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
-                || actionId == EditorInfo.IME_ACTION_NEXT) {
-            verifyPasswordAndUnlock();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean needsInput() {
-        return false;
-    }
-
-    @Override
-    public void onPause() {
-
-    }
-
-    @Override
-    public void onResume(int reason) {
-        reset();
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        if (mCallback != null) {
-            mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
-        }
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-    }
-
-    @Override
-    public void afterTextChanged(Editable s) {
-    }
-
-    // Cause a VIRTUAL_KEY vibration
-    public void doHapticKeyClick() {
-        if (mEnableHaptics) {
-            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
-                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
-                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
-        }
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-}
-
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAccountView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAccountView.java
deleted file mode 100644
index e0e7128..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAccountView.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.LoginFilter;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.R;
-
-import java.io.IOException;
-
-/**
- * When the user forgets their password a bunch of times, we fall back on their
- * account's login/password to unlock the phone (and reset their lock pattern).
- */
-public class KeyguardAccountView extends LinearLayout implements KeyguardSecurityView,
-        View.OnClickListener, TextWatcher {
-    private static final int AWAKE_POKE_MILLIS = 30000;
-    private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
-    private static final String LOCK_PATTERN_CLASS = LOCK_PATTERN_PACKAGE + ".ChooseLockGeneric";
-
-    private KeyguardSecurityCallback mCallback;
-    private LockPatternUtils mLockPatternUtils;
-    private EditText mLogin;
-    private EditText mPassword;
-    private Button mOk;
-    public boolean mEnableFallback;
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-
-    /**
-     * Shown while making asynchronous check of password.
-     */
-    private ProgressDialog mCheckingDialog;
-
-    public KeyguardAccountView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardAccountView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardAccountView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mLockPatternUtils = new LockPatternUtils(getContext());
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mLogin = (EditText) findViewById(R.id.login);
-        mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } );
-        mLogin.addTextChangedListener(this);
-
-        mPassword = (EditText) findViewById(R.id.password);
-        mPassword.addTextChangedListener(this);
-
-        mOk = (Button) findViewById(R.id.ok);
-        mOk.setOnClickListener(this);
-
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        reset();
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-
-    public void afterTextChanged(Editable s) {
-    }
-
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-    }
-
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-        if (mCallback != null) {
-            mCallback.userActivity(AWAKE_POKE_MILLIS);
-        }
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction,
-            Rect previouslyFocusedRect) {
-        // send focus to the login field
-        return mLogin.requestFocus(direction, previouslyFocusedRect);
-    }
-
-    public boolean needsInput() {
-        return true;
-    }
-
-    public void reset() {
-        // start fresh
-        mLogin.setText("");
-        mPassword.setText("");
-        mLogin.requestFocus();
-        boolean permLocked = mLockPatternUtils.isPermanentlyLocked();
-        mSecurityMessageDisplay.setMessage(permLocked ? R.string.kg_login_too_many_attempts :
-            R.string.kg_login_instructions, permLocked ? true : false);
-    }
-
-    /** {@inheritDoc} */
-    public void cleanUp() {
-        if (mCheckingDialog != null) {
-            mCheckingDialog.hide();
-        }
-        mCallback = null;
-        mLockPatternUtils = null;
-    }
-
-    public void onClick(View v) {
-        mCallback.userActivity(0);
-        if (v == mOk) {
-            asyncCheckPassword();
-        }
-    }
-
-    private void postOnCheckPasswordResult(final boolean success) {
-        // ensure this runs on UI thread
-        mLogin.post(new Runnable() {
-            public void run() {
-                if (success) {
-                    // clear out forgotten password
-                    mLockPatternUtils.setPermanentlyLocked(false);
-                    mLockPatternUtils.setLockPatternEnabled(false);
-                    mLockPatternUtils.saveLockPattern(null);
-
-                    // launch the 'choose lock pattern' activity so
-                    // the user can pick a new one if they want to
-                    Intent intent = new Intent();
-                    intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivityAsUser(intent,
-                            new UserHandle(mLockPatternUtils.getCurrentUser()));
-                    mCallback.reportSuccessfulUnlockAttempt();
-
-                    // dismiss keyguard
-                    mCallback.dismiss(true);
-                } else {
-                    mSecurityMessageDisplay.setMessage(R.string.kg_login_invalid_input, true);
-                    mPassword.setText("");
-                    mCallback.reportFailedUnlockAttempt();
-                }
-            }
-        });
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-            if (mLockPatternUtils.isPermanentlyLocked()) {
-                mCallback.dismiss(false);
-            } else {
-                // TODO: mCallback.forgotPattern(false);
-            }
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    /**
-     * Given the string the user entered in the 'username' field, find
-     * the stored account that they probably intended.  Prefer, in order:
-     *
-     *   - an exact match for what was typed, or
-     *   - a case-insensitive match for what was typed, or
-     *   - if they didn't include a domain, an exact match of the username, or
-     *   - if they didn't include a domain, a case-insensitive
-     *     match of the username.
-     *
-     * If there is a tie for the best match, choose neither --
-     * the user needs to be more specific.
-     *
-     * @return an account name from the database, or null if we can't
-     * find a single best match.
-     */
-    private Account findIntendedAccount(String username) {
-        Account[] accounts = AccountManager.get(mContext).getAccountsByTypeAsUser("com.google",
-                new UserHandle(mLockPatternUtils.getCurrentUser()));
-
-        // Try to figure out which account they meant if they
-        // typed only the username (and not the domain), or got
-        // the case wrong.
-
-        Account bestAccount = null;
-        int bestScore = 0;
-        for (Account a: accounts) {
-            int score = 0;
-            if (username.equals(a.name)) {
-                score = 4;
-            } else if (username.equalsIgnoreCase(a.name)) {
-                score = 3;
-            } else if (username.indexOf('@') < 0) {
-                int i = a.name.indexOf('@');
-                if (i >= 0) {
-                    String aUsername = a.name.substring(0, i);
-                    if (username.equals(aUsername)) {
-                        score = 2;
-                    } else if (username.equalsIgnoreCase(aUsername)) {
-                        score = 1;
-                    }
-                }
-            }
-            if (score > bestScore) {
-                bestAccount = a;
-                bestScore = score;
-            } else if (score == bestScore) {
-                bestAccount = null;
-            }
-        }
-        return bestAccount;
-    }
-
-    private void asyncCheckPassword() {
-        mCallback.userActivity(AWAKE_POKE_MILLIS);
-        final String login = mLogin.getText().toString();
-        final String password = mPassword.getText().toString();
-        Account account = findIntendedAccount(login);
-        if (account == null) {
-            postOnCheckPasswordResult(false);
-            return;
-        }
-        getProgressDialog().show();
-        Bundle options = new Bundle();
-        options.putString(AccountManager.KEY_PASSWORD, password);
-        AccountManager.get(mContext).confirmCredentialsAsUser(account, options, null /* activity */,
-                new AccountManagerCallback<Bundle>() {
-            public void run(AccountManagerFuture<Bundle> future) {
-                try {
-                    mCallback.userActivity(AWAKE_POKE_MILLIS);
-                    final Bundle result = future.getResult();
-                    final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
-                    postOnCheckPasswordResult(verified);
-                } catch (OperationCanceledException e) {
-                    postOnCheckPasswordResult(false);
-                } catch (IOException e) {
-                    postOnCheckPasswordResult(false);
-                } catch (AuthenticatorException e) {
-                    postOnCheckPasswordResult(false);
-                } finally {
-                    mLogin.post(new Runnable() {
-                        public void run() {
-                            getProgressDialog().hide();
-                        }
-                    });
-                }
-            }
-        }, null /* handler */, new UserHandle(mLockPatternUtils.getCurrentUser()));
-    }
-
-    private Dialog getProgressDialog() {
-        if (mCheckingDialog == null) {
-            mCheckingDialog = new ProgressDialog(mContext);
-            mCheckingDialog.setMessage(
-                    mContext.getString(R.string.kg_login_checking_password));
-            mCheckingDialog.setIndeterminate(true);
-            mCheckingDialog.setCancelable(false);
-            mCheckingDialog.getWindow().setType(
-                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        }
-        return mCheckingDialog;
-    }
-
-    @Override
-    public void onPause() {
-
-    }
-
-    @Override
-    public void onResume(int reason) {
-        reset();
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-    }
-}
-
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java
deleted file mode 100644
index 6539db3..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
-import android.app.IActivityManager.WaitResult;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.view.WindowManager;
-
-import com.android.internal.policy.impl.keyguard.KeyguardHostView.OnDismissAction;
-import com.android.internal.widget.LockPatternUtils;
-
-import java.util.List;
-
-public abstract class KeyguardActivityLauncher {
-    private static final String TAG = KeyguardActivityLauncher.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
-    private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
-    private static final Intent SECURE_CAMERA_INTENT =
-            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
-                    .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-    private static final Intent INSECURE_CAMERA_INTENT =
-            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
-
-    abstract Context getContext();
-
-    abstract KeyguardSecurityCallback getCallback();
-
-    abstract LockPatternUtils getLockPatternUtils();
-
-    public static class CameraWidgetInfo {
-        public String contextPackage;
-        public int layoutId;
-    }
-
-    public CameraWidgetInfo getCameraWidgetInfo() {
-        CameraWidgetInfo info = new CameraWidgetInfo();
-        Intent intent = getCameraIntent();
-        PackageManager packageManager = getContext().getPackageManager();
-        final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
-        if (appList.size() == 0) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Nothing found");
-            return null;
-        }
-        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
-                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
-                getLockPatternUtils().getCurrentUser());
-        if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): resolved: " + resolved);
-        if (wouldLaunchResolverActivity(resolved, appList)) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Would launch resolver");
-            return info;
-        }
-        if (resolved == null || resolved.activityInfo == null) {
-            return null;
-        }
-        if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no metadata found");
-            return info;
-        }
-        int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
-        if (layoutId == 0) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no layout specified");
-            return info;
-        }
-        info.contextPackage = resolved.activityInfo.packageName;
-        info.layoutId = layoutId;
-        return info;
-    }
-
-    public void launchCamera(Handler worker, Runnable onSecureCameraStarted) {
-        LockPatternUtils lockPatternUtils = getLockPatternUtils();
-        if (lockPatternUtils.isSecure()) {
-            // Launch the secure version of the camera
-            if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) {
-                // TODO: Show disambiguation dialog instead.
-                // For now, we'll treat this like launching any other app from secure keyguard.
-                // When they do, user sees the system's ResolverActivity which lets them choose
-                // which secure camera to use.
-                launchActivity(SECURE_CAMERA_INTENT, false, false, null, null);
-            } else {
-                launchActivity(SECURE_CAMERA_INTENT, true, false, worker, onSecureCameraStarted);
-            }
-        } else {
-            // Launch the normal camera
-            launchActivity(INSECURE_CAMERA_INTENT, false, false, null, null);
-        }
-    }
-
-    public void launchWidgetPicker(int appWidgetId) {
-        Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
-
-        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-        pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
-        pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
-                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
-
-        Bundle options = new Bundle();
-        options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
-        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
-        pickIntent.addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
-        launchActivity(pickIntent, false, false, null, null);
-    }
-
-    /**
-     * Launches the said intent for the current foreground user.
-     *
-     * @param intent
-     * @param showsWhileLocked true if the activity can be run on top of keyguard.
-     *   See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
-     * @param useDefaultAnimations true if default transitions should be used, else suppressed.
-     * @param worker if supplied along with onStarted, used to launch the blocking activity call.
-     * @param onStarted if supplied along with worker, called after activity is started.
-     */
-    public void launchActivity(final Intent intent,
-            boolean showsWhileLocked,
-            boolean useDefaultAnimations,
-            final Handler worker,
-            final Runnable onStarted) {
-
-        final Context context = getContext();
-        final Bundle animation = useDefaultAnimations ? null
-                : ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
-        launchActivityWithAnimation(intent, showsWhileLocked, animation, worker, onStarted);
-    }
-
-    public void launchActivityWithAnimation(final Intent intent,
-            boolean showsWhileLocked,
-            final Bundle animation,
-            final Handler worker,
-            final Runnable onStarted) {
-
-        LockPatternUtils lockPatternUtils = getLockPatternUtils();
-        intent.addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        boolean isSecure = lockPatternUtils.isSecure();
-        if (!isSecure || showsWhileLocked) {
-            if (!isSecure) {
-                dismissKeyguardOnNextActivity();
-            }
-            try {
-                if (DEBUG) Log.d(TAG, String.format("Starting activity for intent %s at %s",
-                        intent, SystemClock.uptimeMillis()));
-                startActivityForCurrentUser(intent, animation, worker, onStarted);
-            } catch (ActivityNotFoundException e) {
-                Log.w(TAG, "Activity not found for intent + " + intent.getAction());
-            }
-        } else {
-            // Create a runnable to start the activity and ask the user to enter their
-            // credentials.
-            KeyguardSecurityCallback callback = getCallback();
-            callback.setOnDismissAction(new OnDismissAction() {
-                @Override
-                public boolean onDismiss() {
-                    dismissKeyguardOnNextActivity();
-                    startActivityForCurrentUser(intent, animation, worker, onStarted);
-                    return true;
-                }
-            });
-            callback.dismiss(false);
-        }
-    }
-
-    private void dismissKeyguardOnNextActivity() {
-        try {
-            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-        } catch (RemoteException e) {
-            Log.w(TAG, "can't dismiss keyguard on launch");
-        }
-    }
-
-    private void startActivityForCurrentUser(final Intent intent, final Bundle options,
-            Handler worker, final Runnable onStarted) {
-        final UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
-        if (worker == null || onStarted == null) {
-            getContext().startActivityAsUser(intent, options, user);
-            return;
-        }
-        // if worker + onStarted are supplied, run blocking activity launch call in the background
-        worker.post(new Runnable(){
-            @Override
-            public void run() {
-                try {
-                    WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait(
-                            null /*caller*/,
-                            null /*caller pkg*/,
-                            intent,
-                            intent.resolveTypeIfNeeded(getContext().getContentResolver()),
-                            null /*resultTo*/,
-                            null /*resultWho*/,
-                            0 /*requestCode*/,
-                            Intent.FLAG_ACTIVITY_NEW_TASK,
-                            null /*profileFile*/,
-                            null /*profileFd*/,
-                            options,
-                            user.getIdentifier());
-                    if (DEBUG) Log.d(TAG, String.format("waitResult[%s,%s,%s,%s] at %s",
-                            result.result, result.thisTime, result.totalTime, result.who,
-                            SystemClock.uptimeMillis()));
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Error starting activity", e);
-                    return;
-                }
-                try {
-                    onStarted.run();
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onStarted callback", t);
-                }
-            }});
-    }
-
-    private Intent getCameraIntent() {
-        return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
-    }
-
-    private boolean wouldLaunchResolverActivity(Intent intent) {
-        PackageManager packageManager = getContext().getPackageManager();
-        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
-                PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
-        List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
-        return wouldLaunchResolverActivity(resolved, appList);
-    }
-
-    private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
-        // If the list contains the above resolved activity, then it can't be
-        // ResolverActivity itself.
-        for (int i = 0; i < appList.size(); i++) {
-            ResolveInfo tmp = appList.get(i);
-            if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
-                    && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
-                return false;
-            }
-        }
-        return true;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
deleted file mode 100644
index fe32099..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-
-import android.util.Log;
-
-class KeyguardCircleFramedDrawable extends Drawable {
-
-    private final Bitmap mBitmap;
-    private final int mSize;
-    private final Paint mPaint;
-    private final float mShadowRadius;
-    private final float mStrokeWidth;
-    private final int mFrameColor;
-    private final int mHighlightColor;
-    private final int mFrameShadowColor;
-
-    private float mScale;
-    private Path mFramePath;
-    private Rect mSrcRect;
-    private RectF mDstRect;
-    private RectF mFrameRect;
-    private boolean mPressed;
-
-    public KeyguardCircleFramedDrawable(Bitmap bitmap, int size,
-            int frameColor, float strokeWidth,
-            int frameShadowColor, float shadowRadius,
-            int highlightColor) {
-        super();
-        mSize = size;
-        mShadowRadius = shadowRadius;
-        mFrameColor = frameColor;
-        mFrameShadowColor = frameShadowColor;
-        mStrokeWidth = strokeWidth;
-        mHighlightColor = highlightColor;
-
-        mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(mBitmap);
-
-        final int width = bitmap.getWidth();
-        final int height = bitmap.getHeight();
-        final int square = Math.min(width, height);
-
-        final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square);
-        final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
-        circleRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f);
-        circleRect.inset(mShadowRadius, mShadowRadius);
-
-        final Path fillPath = new Path();
-        fillPath.addArc(circleRect, 0f, 360f);
-
-        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
-
-        // opaque circle matte
-        mPaint = new Paint();
-        mPaint.setAntiAlias(true);
-        mPaint.setColor(Color.BLACK);
-        mPaint.setStyle(Paint.Style.FILL);
-        canvas.drawPath(fillPath, mPaint);
-
-        // mask in the icon where the bitmap is opaque
-        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
-        canvas.drawBitmap(bitmap, cropRect, circleRect, mPaint);
-
-        // prepare paint for frame drawing
-        mPaint.setXfermode(null);
-
-        mScale = 1f;
-
-        mSrcRect = new Rect(0, 0, mSize, mSize);
-        mDstRect = new RectF(0, 0, mSize, mSize);
-        mFrameRect = new RectF(mDstRect);
-        mFramePath = new Path();
-    }
-
-    public void reset() {
-        mScale = 1f;
-        mPressed = false;
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        // clear background
-        final float outside = Math.min(canvas.getWidth(), canvas.getHeight());
-        final float inside = mScale * outside;
-        final float pad = (outside - inside) / 2f;
-
-        mDstRect.set(pad, pad, outside - pad, outside - pad);
-        canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
-
-        mFrameRect.set(mDstRect);
-        mFrameRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f);
-        mFrameRect.inset(mShadowRadius, mShadowRadius);
-
-        mFramePath.reset();
-        mFramePath.addArc(mFrameRect, 0f, 360f);
-
-        // white frame
-        if (mPressed) {
-            mPaint.setStyle(Paint.Style.FILL);
-            mPaint.setColor(Color.argb((int) (0.33f * 255),
-                            Color.red(mHighlightColor),
-                            Color.green(mHighlightColor),
-                            Color.blue(mHighlightColor)));
-            canvas.drawPath(mFramePath, mPaint);
-        }
-        mPaint.setStrokeWidth(mStrokeWidth);
-        mPaint.setStyle(Paint.Style.STROKE);
-        mPaint.setColor(mPressed ? mHighlightColor : mFrameColor);
-        mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mFrameShadowColor);
-        canvas.drawPath(mFramePath, mPaint);
-    }
-
-    public void setScale(float scale) {
-        mScale = scale;
-    }
-
-    public float getScale() {
-        return mScale;
-    }
-
-    public void setPressed(boolean pressed) {
-        mPressed = pressed;
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-    }
-
-    public boolean verifyParams(float iconSize, int frameColor, float stroke,
-            int frameShadowColor, float shadowRadius, int highlightColor) {
-        return mSize == iconSize
-                && mFrameColor == frameColor
-                && mStrokeWidth == stroke
-                && mFrameShadowColor == frameShadowColor
-                && mShadowRadius == shadowRadius
-                && mHighlightColor == highlightColor;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
deleted file mode 100644
index 7315aad..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-import java.lang.Math;
-
-public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
-
-    private static final String TAG = "FULKeyguardFaceUnlockView";
-    private static final boolean DEBUG = false;
-    private KeyguardSecurityCallback mKeyguardSecurityCallback;
-    private LockPatternUtils mLockPatternUtils;
-    private BiometricSensorUnlock mBiometricUnlock;
-    private View mFaceUnlockAreaView;
-    private ImageButton mCancelButton;
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-    private View mEcaView;
-    private Drawable mBouncerFrame;
-
-    private boolean mIsShowing = false;
-    private final Object mIsShowingLock = new Object();
-
-    private int mLastRotation;
-    private boolean mWatchingRotation;
-    private final IWindowManager mWindowManager =
-            IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
-
-    private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
-        public void onRotationChanged(int rotation) {
-            if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation);
-
-            // If the difference between the new rotation value and the previous rotation value is
-            // equal to 2, the rotation change was 180 degrees.  This stops the biometric unlock
-            // and starts it in the new position.  This is not performed for 90 degree rotations
-            // since a 90 degree rotation is a configuration change, which takes care of this for
-            // us.
-            if (Math.abs(rotation - mLastRotation) == 2) {
-                if (mBiometricUnlock != null) {
-                    mBiometricUnlock.stop();
-                    maybeStartBiometricUnlock();
-                }
-            }
-            mLastRotation = rotation;
-        }
-    };
-
-    public KeyguardFaceUnlockView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardFaceUnlockView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        initializeBiometricUnlockView();
-
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
-        if (bouncerFrameView != null) {
-            mBouncerFrame = bouncerFrameView.getBackground();
-        }
-    }
-
-    @Override
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mKeyguardSecurityCallback = callback;
-        // TODO: formalize this in the interface or factor it out
-        ((FaceUnlock)mBiometricUnlock).setKeyguardCallback(callback);
-    }
-
-    @Override
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    @Override
-    public void reset() {
-
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
-        if (mBiometricUnlock != null) {
-            mBiometricUnlock.stop();
-        }
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
-        if (mWatchingRotation) {
-            try {
-                mWindowManager.removeRotationWatcher(mRotationWatcher);
-                mWatchingRotation = false;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception when removing rotation watcher");
-            }
-        }
-    }
-
-    @Override
-    public void onPause() {
-        if (DEBUG) Log.d(TAG, "onPause()");
-        if (mBiometricUnlock != null) {
-            mBiometricUnlock.stop();
-        }
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
-        if (mWatchingRotation) {
-            try {
-                mWindowManager.removeRotationWatcher(mRotationWatcher);
-                mWatchingRotation = false;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception when removing rotation watcher");
-            }
-        }
-    }
-
-    @Override
-    public void onResume(int reason) {
-        if (DEBUG) Log.d(TAG, "onResume()");
-        mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
-        if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
-          maybeStartBiometricUnlock();
-        }
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
-
-        // Registers a callback which handles stopping the biometric unlock and restarting it in
-        // the new position for a 180 degree rotation change.
-        if (!mWatchingRotation) {
-            try {
-                mLastRotation = mWindowManager.watchRotation(mRotationWatcher);
-                mWatchingRotation = true;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception when adding rotation watcher");
-            }
-        }
-    }
-
-    @Override
-    public boolean needsInput() {
-        return false;
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        return mKeyguardSecurityCallback;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-        mBiometricUnlock.initializeView(mFaceUnlockAreaView);
-    }
-
-    private void initializeBiometricUnlockView() {
-        if (DEBUG) Log.d(TAG, "initializeBiometricUnlockView()");
-        mFaceUnlockAreaView = findViewById(R.id.face_unlock_area_view);
-        if (mFaceUnlockAreaView != null) {
-            mBiometricUnlock = new FaceUnlock(mContext);
-
-            mCancelButton = (ImageButton) findViewById(R.id.face_unlock_cancel_button);
-            mCancelButton.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    mBiometricUnlock.stopAndShowBackup();
-                }
-            });
-        } else {
-            Log.w(TAG, "Couldn't find biometric unlock view");
-        }
-    }
-
-    /**
-     * Starts the biometric unlock if it should be started based on a number of factors.  If it
-     * should not be started, it either goes to the back up, or remains showing to prepare for
-     * it being started later.
-     */
-    private void maybeStartBiometricUnlock() {
-        if (DEBUG) Log.d(TAG, "maybeStartBiometricUnlock()");
-        if (mBiometricUnlock != null) {
-            KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-            final boolean backupIsTimedOut = (
-                    monitor.getFailedUnlockAttempts() >=
-                    LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
-            PowerManager powerManager = (PowerManager) mContext.getSystemService(
-                    Context.POWER_SERVICE);
-
-            boolean isShowing;
-            synchronized(mIsShowingLock) {
-                isShowing = mIsShowing;
-            }
-
-            // Don't start it if the screen is off or if it's not showing, but keep this view up
-            // because we want it here and ready for when the screen turns on or when it does start
-            // showing.
-            if (!powerManager.isScreenOn() || !isShowing) {
-                mBiometricUnlock.stop(); // It shouldn't be running but calling this can't hurt.
-                return;
-            }
-
-            // Although these same conditions are handled in KeyguardSecurityModel, they are still
-            // necessary here.  When a tablet is rotated 90 degrees, a configuration change is
-            // triggered and everything is torn down and reconstructed.  That means
-            // KeyguardSecurityModel gets a chance to take care of the logic and doesn't even
-            // reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed.
-            // However, for a 180 degree rotation, no configuration change is triggered, so only
-            // the logic here is capable of suppressing Face Unlock.
-            if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
-                    && monitor.isAlternateUnlockEnabled()
-                    && !monitor.getMaxBiometricUnlockAttemptsReached()
-                    && !backupIsTimedOut) {
-                mBiometricUnlock.start();
-            } else {
-                mBiometricUnlock.stopAndShowBackup();
-            }
-        }
-    }
-
-    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
-        // We need to stop the biometric unlock when a phone call comes in
-        @Override
-        public void onPhoneStateChanged(int phoneState) {
-            if (DEBUG) Log.d(TAG, "onPhoneStateChanged(" + phoneState + ")");
-            if (phoneState == TelephonyManager.CALL_STATE_RINGING) {
-                if (mBiometricUnlock != null) {
-                    mBiometricUnlock.stopAndShowBackup();
-                }
-            }
-        }
-
-        @Override
-        public void onUserSwitching(int userId) {
-            if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")");
-            if (mBiometricUnlock != null) {
-                mBiometricUnlock.stop();
-            }
-            // No longer required; static value set by KeyguardViewMediator
-            // mLockPatternUtils.setCurrentUser(userId);
-        }
-
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")");
-            if (mBiometricUnlock != null) {
-                maybeStartBiometricUnlock();
-            }
-        }
-
-        @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
-            boolean wasShowing = false;
-            synchronized(mIsShowingLock) {
-                wasShowing = mIsShowing;
-                mIsShowing = showing;
-            }
-            PowerManager powerManager = (PowerManager) mContext.getSystemService(
-                    Context.POWER_SERVICE);
-            if (mBiometricUnlock != null) {
-                if (!showing && wasShowing) {
-                    mBiometricUnlock.stop();
-                } else if (showing && powerManager.isScreenOn() && !wasShowing) {
-                    maybeStartBiometricUnlock();
-                }
-            }
-        }
-    };
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardGlowStripView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardGlowStripView.java
deleted file mode 100644
index e1c95f0..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardGlowStripView.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.widget.LinearLayout;
-
-import com.android.internal.R;
-
-/**
- * A layout which animates a strip of horizontal, pulsing dots on request. This is used
- * to indicate the presence of pages to the left / right.
- */
-public class KeyguardGlowStripView extends LinearLayout {
-    private static final int DURATION = 500;
-
-    private static final float SLIDING_WINDOW_SIZE = 0.4f;
-    private int mDotStripTop;
-    private int mHorizontalDotGap;
-
-    private int mDotSize;
-    private int mNumDots;
-    private Drawable mDotDrawable;
-    private boolean mLeftToRight = true;
-
-    private float mAnimationProgress = 0f;
-    private boolean mDrawDots = false;
-    private ValueAnimator mAnimator;
-    private Interpolator mDotAlphaInterpolator = new DecelerateInterpolator(0.5f);
-
-    public KeyguardGlowStripView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardGlowStripView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardGlowStripView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyguardGlowStripView);
-        mDotSize = a.getDimensionPixelSize(R.styleable.KeyguardGlowStripView_dotSize, mDotSize);
-        mNumDots = a.getInt(R.styleable.KeyguardGlowStripView_numDots, mNumDots);
-        mDotDrawable = a.getDrawable(R.styleable.KeyguardGlowStripView_glowDot);
-        mLeftToRight = a.getBoolean(R.styleable.KeyguardGlowStripView_leftToRight, mLeftToRight);
-    }
-
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        int availableWidth = w - getPaddingLeft() - getPaddingRight();
-        mHorizontalDotGap = (availableWidth - mDotSize * mNumDots) /  (mNumDots - 1);
-        mDotStripTop = getPaddingTop();
-        invalidate();
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-
-        if (!mDrawDots) return;
-
-        int xOffset = getPaddingLeft();
-        mDotDrawable.setBounds(0, 0, mDotSize, mDotSize);
-
-        for (int i = 0; i < mNumDots; i++) {
-            // We fudge the relative position to provide a fade in of the first dot and a fade
-            // out of the final dot.
-            float relativeDotPosition = SLIDING_WINDOW_SIZE / 2 + ((1.0f * i) / (mNumDots - 1)) *
-                    (1 - SLIDING_WINDOW_SIZE);
-            float distance = Math.abs(relativeDotPosition - mAnimationProgress);
-            float alpha = Math.max(0, 1 - distance / (SLIDING_WINDOW_SIZE / 2));
-
-            alpha = mDotAlphaInterpolator.getInterpolation(alpha);
-
-            canvas.save();
-            canvas.translate(xOffset, mDotStripTop);
-            mDotDrawable.setAlpha((int) (alpha * 255));
-            mDotDrawable.draw(canvas);
-            canvas.restore();
-            xOffset += mDotSize + mHorizontalDotGap;
-        }
-    }
-
-    public void makeEmGo() {
-        if (mAnimator != null) {
-            mAnimator.cancel();
-        }
-        float from = mLeftToRight ? 0f : 1f;
-        float to = mLeftToRight ? 1f : 0f;
-        mAnimator = ValueAnimator.ofFloat(from, to);
-        mAnimator.setDuration(DURATION);
-        mAnimator.setInterpolator(new LinearInterpolator());
-        mAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mDrawDots = false;
-                // make sure we draw one frame at the end with everything gone.
-                invalidate();
-            }
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mDrawDots = true;
-            }
-        });
-        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mAnimationProgress = (Float) animation.getAnimatedValue();
-                invalidate();
-            }
-        });
-        mAnimator.start();
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
deleted file mode 100644
index c3077c7..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ /dev/null
@@ -1,1684 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.AlertDialog;
-import android.app.SearchManager;
-import android.app.admin.DevicePolicyManager;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.media.RemoteControlClient;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
-import android.widget.RemoteViews.OnClickHandler;
-
-import com.android.internal.R;
-import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.internal.policy.impl.keyguard.KeyguardUpdateMonitor.DisplayClientState;
-import com.android.internal.widget.LockPatternUtils;
-
-import java.io.File;
-import java.util.List;
-
-public class KeyguardHostView extends KeyguardViewBase {
-    private static final String TAG = "KeyguardHostView";
-    // Transport control states.
-    static final int TRANSPORT_GONE = 0;
-    static final int TRANSPORT_INVISIBLE = 1;
-    static final int TRANSPORT_VISIBLE = 2;
-
-    private int mTransportState = TRANSPORT_GONE;
-
-    // Use this to debug all of keyguard
-    public static boolean DEBUG = KeyguardViewMediator.DEBUG;
-    public static boolean DEBUGXPORT = true; // debug music transport control
-
-    // Found in KeyguardAppWidgetPickActivity.java
-    static final int APPWIDGET_HOST_ID = 0x4B455947;
-
-    private final int MAX_WIDGETS = 5;
-
-    private AppWidgetHost mAppWidgetHost;
-    private AppWidgetManager mAppWidgetManager;
-    private KeyguardWidgetPager mAppWidgetContainer;
-    private KeyguardSecurityViewFlipper mSecurityViewContainer;
-    private KeyguardSelectorView mKeyguardSelectorView;
-    private KeyguardTransportControlView mTransportControl;
-    private boolean mIsVerifyUnlockOnly;
-    private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
-    private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
-    private int mAppWidgetToShow;
-
-    private boolean mCheckAppWidgetConsistencyOnBootCompleted = false;
-    private boolean mCleanupAppWidgetsOnBootCompleted = false;
-
-    protected OnDismissAction mDismissAction;
-
-    protected int mFailedAttempts;
-    private LockPatternUtils mLockPatternUtils;
-
-    private KeyguardSecurityModel mSecurityModel;
-    private KeyguardViewStateManager mViewStateManager;
-
-    private Rect mTempRect = new Rect();
-
-    private int mDisabledFeatures;
-
-    private boolean mCameraDisabled;
-
-    private boolean mSafeModeEnabled;
-
-    private boolean mUserSetupCompleted;
-
-    // User for whom this host view was created.  Final because we should never change the
-    // id without reconstructing an instance of KeyguardHostView. See note below...
-    private final int mUserId;
-
-    private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
-
-    protected int mClientGeneration;
-
-    /*package*/ interface UserSwitcherCallback {
-        void hideSecurityView(int duration);
-        void showSecurityView();
-        void showUnlockHint();
-        void userActivity();
-    }
-
-    /*package*/ interface OnDismissAction {
-        /* returns true if the dismiss should be deferred */
-        boolean onDismiss();
-    }
-
-    public KeyguardHostView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardHostView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        if (DEBUG) Log.e(TAG, "KeyguardHostView()");
-
-        mLockPatternUtils = new LockPatternUtils(context);
-
-        // Note: This depends on KeyguardHostView getting reconstructed every time the
-        // user switches, since mUserId will be used for the entire session.
-        // Once created, keyguard should *never* re-use this instance with another user.
-        // In other words, mUserId should never change - hence it's marked final.
-        mUserId = mLockPatternUtils.getCurrentUser();
-
-        DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-            mDisabledFeatures = getDisabledFeatures(dpm);
-            mCameraDisabled = dpm.getCameraDisabled(null);
-        }
-
-        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
-
-        // These need to be created with the user context...
-        Context userContext = null;
-        try {
-            final String packageName = "system";
-            userContext = mContext.createPackageContextAsUser(packageName, 0,
-                    new UserHandle(mUserId));
-
-        } catch (NameNotFoundException e) {
-            e.printStackTrace();
-            // This should never happen, but it's better to have no widgets than to crash.
-            userContext = context;
-        }
-
-        mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
-                Looper.myLooper());
-
-        cleanupAppWidgetIds();
-
-        mAppWidgetManager = AppWidgetManager.getInstance(userContext);
-
-        mSecurityModel = new KeyguardSecurityModel(context);
-
-        mViewStateManager = new KeyguardViewStateManager(this);
-
-        mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
-
-        // Ensure we have the current state *before* we call showAppropriateWidgetPage()
-        getInitialTransportState();
-
-        if (mSafeModeEnabled) {
-            Log.v(TAG, "Keyguard widgets disabled by safe mode");
-        }
-        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) {
-            Log.v(TAG, "Keyguard widgets disabled by DPM");
-        }
-        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
-            Log.v(TAG, "Keyguard secure camera disabled by DPM");
-        }
-    }
-
-    private void getInitialTransportState() {
-        DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
-                .getCachedDisplayClientState();
-        mTransportState = (dcs.clearing ? TRANSPORT_GONE :
-            (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
-
-        if (DEBUG) Log.v(TAG, "Initial transport state: "
-                + mTransportState + ", pbstate=" + dcs.playbackState);
-    }
-
-    private void cleanupAppWidgetIds() {
-        // Since this method may delete a widget (which we can't do until boot completed) we
-        // may have to defer it until after boot complete.
-        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
-            mCleanupAppWidgetsOnBootCompleted = true;
-            return;
-        }
-        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
-            // Clean up appWidgetIds that are bound to lockscreen, but not actually used
-            // This is only to clean up after another bug: we used to not call
-            // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
-            // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
-            // that are triggered by deleteAppWidgetId, which is why we're doing this
-            int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
-            int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
-            for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
-                int appWidgetId = appWidgetIdsBoundToHost[i];
-                if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
-                    Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
-                            + appWidgetId);
-                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                }
-            }
-        }
-    }
-
-    private static boolean contains(int[] array, int target) {
-        for (int value : array) {
-            if (value == target) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
-            new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onBootCompleted() {
-            if (mCheckAppWidgetConsistencyOnBootCompleted) {
-                checkAppWidgetConsistency();
-                mSwitchPageRunnable.run();
-                mCheckAppWidgetConsistencyOnBootCompleted = false;
-            }
-            if (mCleanupAppWidgetsOnBootCompleted) {
-                cleanupAppWidgetIds();
-                mCleanupAppWidgetsOnBootCompleted = false;
-            }
-        }
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            if (mKeyguardMultiUserSelectorView != null) {
-                mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
-            }
-        }
-        @Override
-        void onMusicClientIdChanged(
-                int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
-            // Set transport state to invisible until we know music is playing (below)
-            if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
-                Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration);
-            }
-            mClientGeneration = clientGeneration;
-            final int newState = (clearing ? TRANSPORT_GONE
-                    : (mTransportState == TRANSPORT_VISIBLE ?
-                    TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
-            if (newState != mTransportState) {
-                mTransportState = newState;
-                if (DEBUGXPORT) Log.v(TAG, "update widget: transport state changed");
-                KeyguardHostView.this.post(mSwitchPageRunnable);
-            }
-        }
-        @Override
-        public void onMusicPlaybackStateChanged(int playbackState, long eventTime) {
-            if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState);
-            if (mTransportState != TRANSPORT_GONE) {
-                final int newState = (isMusicPlaying(playbackState) ?
-                        TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE);
-                if (newState != mTransportState) {
-                    mTransportState = newState;
-                    if (DEBUGXPORT) Log.v(TAG, "update widget: play state changed");
-                    KeyguardHostView.this.post(mSwitchPageRunnable);
-                }
-            }
-        }
-    };
-
-    private static final boolean isMusicPlaying(int playbackState) {
-        // This should agree with the list in AudioService.isPlaystateActive()
-        switch (playbackState) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private SlidingChallengeLayout mSlidingChallengeLayout;
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean result = super.onTouchEvent(ev);
-        mTempRect.set(0, 0, 0, 0);
-        offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect);
-        ev.offsetLocation(mTempRect.left, mTempRect.top);
-        result = mSecurityViewContainer.dispatchTouchEvent(ev) || result;
-        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
-        return result;
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.keyguardDoneDrawing();
-        }
-    }
-
-    private int getWidgetPosition(int id) {
-        final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer;
-        final int children = appWidgetContainer.getChildCount();
-        for (int i = 0; i < children; i++) {
-            final View content = appWidgetContainer.getWidgetPageAt(i).getContent();
-            if (content != null && content.getId() == id) {
-                return i;
-            } else if (content == null) {
-                // Attempt to track down bug #8886916
-                Log.w(TAG, "*** Null content at " + "i=" + i + ",id=" + id + ",N=" + children);
-            }
-        }
-        return -1;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        // Grab instances of and make any necessary changes to the main layouts. Create
-        // view state manager and wire up necessary listeners / callbacks.
-        View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
-        mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
-        mAppWidgetContainer.setVisibility(VISIBLE);
-        mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
-        mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
-        mAppWidgetContainer.setMinScale(0.5f);
-
-        mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
-        if (mSlidingChallengeLayout != null) {
-            mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager);
-        }
-        mAppWidgetContainer.setViewStateManager(mViewStateManager);
-        mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
-
-        ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout :
-            (ChallengeLayout) findViewById(R.id.multi_pane_challenge);
-        challenge.setOnBouncerStateChangedListener(mViewStateManager);
-        mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration());
-        mViewStateManager.setPagedView(mAppWidgetContainer);
-        mViewStateManager.setChallengeLayout(challenge);
-        mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper);
-        mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
-        mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
-
-        setBackButtonEnabled(false);
-
-        addDefaultWidgets();
-
-        addWidgetsFromSettings();
-        if (!shouldEnableAddWidget()) {
-            mAppWidgetContainer.setAddWidgetEnabled(false);
-        }
-        checkAppWidgetConsistency();
-        mSwitchPageRunnable.run();
-        // This needs to be called after the pages are all added.
-        mViewStateManager.showUsabilityHints();
-
-        showPrimarySecurityScreen(false);
-        updateSecurityViews();
-    }
-
-    private void setBackButtonEnabled(boolean enabled) {
-        if (mContext instanceof Activity) return;  // always enabled in activity mode
-        setSystemUiVisibility(enabled ?
-                getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
-                getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
-    }
-
-    private boolean shouldEnableAddWidget() {
-        return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
-    }
-
-    private int getDisabledFeatures(DevicePolicyManager dpm) {
-        int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
-        if (dpm != null) {
-            final int currentUser = mLockPatternUtils.getCurrentUser();
-            disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser);
-        }
-        return disabledFeatures;
-    }
-
-    private boolean widgetsDisabledByDpm() {
-        return (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
-    }
-
-    private boolean cameraDisabledByDpm() {
-        return mCameraDisabled
-                || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
-    }
-
-    private void updateSecurityViews() {
-        int children = mSecurityViewContainer.getChildCount();
-        for (int i = 0; i < children; i++) {
-            updateSecurityView(mSecurityViewContainer.getChildAt(i));
-        }
-    }
-
-    private void updateSecurityView(View view) {
-        if (view instanceof KeyguardSecurityView) {
-            KeyguardSecurityView ksv = (KeyguardSecurityView) view;
-            ksv.setKeyguardCallback(mCallback);
-            ksv.setLockPatternUtils(mLockPatternUtils);
-            if (mViewStateManager.isBouncing()) {
-                ksv.showBouncer(0);
-            } else {
-                ksv.hideBouncer(0);
-            }
-        } else {
-            Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
-        }
-    }
-
-    void setLockPatternUtils(LockPatternUtils utils) {
-        mSecurityModel.setLockPatternUtils(utils);
-        mLockPatternUtils = utils;
-        updateSecurityViews();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mAppWidgetHost.startListening();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mAppWidgetHost.stopListening();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
-    }
-
-    void addWidget(AppWidgetHostView view, int pageIndex) {
-        mAppWidgetContainer.addWidget(view, pageIndex);
-    }
-
-    private KeyguardWidgetPager.Callbacks mWidgetCallbacks
-            = new KeyguardWidgetPager.Callbacks() {
-        @Override
-        public void userActivity() {
-            KeyguardHostView.this.userActivity();
-        }
-
-        @Override
-        public void onUserActivityTimeoutChanged() {
-            KeyguardHostView.this.onUserActivityTimeoutChanged();
-        }
-
-        @Override
-        public void onAddView(View v) {
-            if (!shouldEnableAddWidget()) {
-                mAppWidgetContainer.setAddWidgetEnabled(false);
-            }
-        }
-
-        @Override
-        public void onRemoveView(View v, boolean deletePermanently) {
-            if (deletePermanently) {
-                final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-                if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
-                        appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
-                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                }
-            }
-        }
-
-        @Override
-        public void onRemoveViewAnimationCompleted() {
-            if (shouldEnableAddWidget()) {
-                mAppWidgetContainer.setAddWidgetEnabled(true);
-            }
-        }
-    };
-
-    public void initializeSwitchingUserState(boolean switching) {
-        if (!switching && mKeyguardMultiUserSelectorView != null) {
-            mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
-        }
-    }
-
-    public void userActivity() {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.userActivity();
-        }
-    }
-
-    public void onUserActivityTimeoutChanged() {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.onUserActivityTimeoutChanged();
-        }
-    }
-
-    @Override
-    public long getUserActivityTimeout() {
-        // Currently only considering user activity timeouts needed by widgets.
-        // Could also take into account longer timeouts for certain security views.
-        if (mAppWidgetContainer != null) {
-            return mAppWidgetContainer.getUserActivityTimeout();
-        }
-        return -1;
-    }
-
-    private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
-
-        public void userActivity(long timeout) {
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.userActivity(timeout);
-            }
-        }
-
-        public void dismiss(boolean authenticated) {
-            showNextSecurityScreenOrFinish(authenticated);
-        }
-
-        public boolean isVerifyUnlockOnly() {
-            return mIsVerifyUnlockOnly;
-        }
-
-        public void reportSuccessfulUnlockAttempt() {
-            KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts();
-            mLockPatternUtils.reportSuccessfulPasswordAttempt();
-        }
-
-        public void reportFailedUnlockAttempt() {
-            if (mCurrentSecuritySelection == SecurityMode.Biometric) {
-                KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt();
-            } else {
-                KeyguardHostView.this.reportFailedUnlockAttempt();
-            }
-        }
-
-        public int getFailedAttempts() {
-            return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
-        }
-
-        @Override
-        public void showBackupSecurity() {
-            KeyguardHostView.this.showBackupSecurityScreen();
-        }
-
-        @Override
-        public void setOnDismissAction(OnDismissAction action) {
-            KeyguardHostView.this.setOnDismissAction(action);
-        }
-
-    };
-
-    private void showDialog(String title, String message) {
-        final AlertDialog dialog = new AlertDialog.Builder(mContext)
-            .setTitle(title)
-            .setMessage(message)
-            .setNeutralButton(com.android.internal.R.string.ok, null)
-            .create();
-        if (!(mContext instanceof Activity)) {
-            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        }
-        dialog.show();
-    }
-
-    private void showTimeoutDialog() {
-        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
-        int messageId = 0;
-
-        switch (mSecurityModel.getSecurityMode()) {
-            case Pattern:
-                messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
-                break;
-            case PIN:
-                messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
-                break;
-            case Password:
-                messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
-                break;
-        }
-
-        if (messageId != 0) {
-            final String message = mContext.getString(messageId,
-                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
-                    timeoutInSeconds);
-            showDialog(null, message);
-        }
-    }
-
-    private void showAlmostAtWipeDialog(int attempts, int remaining) {
-        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
-        String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
-                attempts, remaining);
-        showDialog(null, message);
-    }
-
-    private void showWipeDialog(int attempts) {
-        String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts);
-        showDialog(null, message);
-    }
-
-    private void showAlmostAtAccountLoginDialog() {
-        final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
-        final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
-                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
-        String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login,
-                count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
-        showDialog(null, message);
-    }
-
-    private void reportFailedUnlockAttempt() {
-        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
-
-        if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
-
-        SecurityMode mode = mSecurityModel.getSecurityMode();
-        final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
-
-        final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
-                .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser());
-
-        final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
-                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
-
-        final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
-                (failedAttemptsBeforeWipe - failedAttempts)
-                : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
-
-        boolean showTimeout = false;
-        if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
-            // If we reach this code, it means the user has installed a DevicePolicyManager
-            // that requests device wipe after N attempts.  Once we get below the grace
-            // period, we'll post this dialog every time as a clear warning until the
-            // bombshell hits and the device is wiped.
-            if (remainingBeforeWipe > 0) {
-                showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
-            } else {
-                // Too many attempts. The device will be wiped shortly.
-                Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
-                showWipeDialog(failedAttempts);
-            }
-        } else {
-            showTimeout =
-                (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
-            if (usingPattern && mEnableFallback) {
-                if (failedAttempts == failedAttemptWarning) {
-                    showAlmostAtAccountLoginDialog();
-                    showTimeout = false; // don't show both dialogs
-                } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
-                    mLockPatternUtils.setPermanentlyLocked(true);
-                    showSecurityScreen(SecurityMode.Account);
-                    // don't show timeout dialog because we show account unlock screen next
-                    showTimeout = false;
-                }
-            }
-        }
-        monitor.reportFailedUnlockAttempt();
-        mLockPatternUtils.reportFailedPasswordAttempt();
-        if (showTimeout) {
-            showTimeoutDialog();
-        }
-    }
-
-    /**
-     * Shows the primary security screen for the user. This will be either the multi-selector
-     * or the user's security method.
-     * @param turningOff true if the device is being turned off
-     */
-    void showPrimarySecurityScreen(boolean turningOff) {
-        SecurityMode securityMode = mSecurityModel.getSecurityMode();
-        if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
-        if (!turningOff &&
-                KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) {
-            // If we're not turning off, then allow biometric alternate.
-            // We'll reload it when the device comes back on.
-            securityMode = mSecurityModel.getAlternateFor(securityMode);
-        }
-        showSecurityScreen(securityMode);
-    }
-
-    /**
-     * Shows the backup security screen for the current security mode.  This could be used for
-     * password recovery screens but is currently only used for pattern unlock to show the
-     * account unlock screen and biometric unlock to show the user's normal unlock.
-     */
-    private void showBackupSecurityScreen() {
-        if (DEBUG) Log.d(TAG, "showBackupSecurity()");
-        SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection);
-        showSecurityScreen(backup);
-    }
-
-    public boolean showNextSecurityScreenIfPresent() {
-        SecurityMode securityMode = mSecurityModel.getSecurityMode();
-        // Allow an alternate, such as biometric unlock
-        securityMode = mSecurityModel.getAlternateFor(securityMode);
-        if (SecurityMode.None == securityMode) {
-            return false;
-        } else {
-            showSecurityScreen(securityMode); // switch to the alternate security view
-            return true;
-        }
-    }
-
-    private void showNextSecurityScreenOrFinish(boolean authenticated) {
-        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
-        boolean finish = false;
-        if (SecurityMode.None == mCurrentSecuritySelection) {
-            SecurityMode securityMode = mSecurityModel.getSecurityMode();
-            // Allow an alternate, such as biometric unlock
-            securityMode = mSecurityModel.getAlternateFor(securityMode);
-            if (SecurityMode.None == securityMode) {
-                finish = true; // no security required
-            } else {
-                showSecurityScreen(securityMode); // switch to the alternate security view
-            }
-        } else if (authenticated) {
-            switch (mCurrentSecuritySelection) {
-                case Pattern:
-                case Password:
-                case PIN:
-                case Account:
-                case Biometric:
-                    finish = true;
-                    break;
-
-                case SimPin:
-                case SimPuk:
-                    // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
-                    SecurityMode securityMode = mSecurityModel.getSecurityMode();
-                    if (securityMode != SecurityMode.None) {
-                        showSecurityScreen(securityMode);
-                    } else {
-                        finish = true;
-                    }
-                    break;
-
-                default:
-                    Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
-                    showPrimarySecurityScreen(false);
-                    break;
-            }
-        } else {
-            showPrimarySecurityScreen(false);
-        }
-        if (finish) {
-            // If the alternate unlock was suppressed, it can now be safely
-            // enabled because the user has left keyguard.
-            KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-
-            // If there's a pending runnable because the user interacted with a widget
-            // and we're leaving keyguard, then run it.
-            boolean deferKeyguardDone = false;
-            if (mDismissAction != null) {
-                deferKeyguardDone = mDismissAction.onDismiss();
-                mDismissAction = null;
-            }
-            if (mViewMediatorCallback != null) {
-                if (deferKeyguardDone) {
-                    mViewMediatorCallback.keyguardDonePending();
-                } else {
-                    mViewMediatorCallback.keyguardDone(true);
-                }
-            }
-        } else {
-            mViewStateManager.showBouncer(true);
-        }
-    }
-
-    private OnClickHandler mOnClickHandler = new OnClickHandler() {
-        @Override
-        public boolean onClickHandler(final View view,
-                final android.app.PendingIntent pendingIntent,
-                final Intent fillInIntent) {
-            if (pendingIntent.isActivity()) {
-                setOnDismissAction(new OnDismissAction() {
-                    public boolean onDismiss() {
-                        try {
-                              // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                              Context context = view.getContext();
-                              ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
-                                      0, 0,
-                                      view.getMeasuredWidth(), view.getMeasuredHeight());
-                              context.startIntentSender(
-                                      pendingIntent.getIntentSender(), fillInIntent,
-                                      Intent.FLAG_ACTIVITY_NEW_TASK,
-                                      Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(TAG, "Cannot send pending intent: ", e);
-                        } catch (Exception e) {
-                            android.util.Log.e(TAG, "Cannot send pending intent due to " +
-                                    "unknown exception: ", e);
-                        }
-                        return false;
-                    }
-                });
-
-                if (mViewStateManager.isChallengeShowing()) {
-                    mViewStateManager.showBouncer(true);
-                } else {
-                    mCallback.dismiss(false);
-                }
-                return true;
-            } else {
-                return super.onClickHandler(view, pendingIntent, fillInIntent);
-            }
-        };
-    };
-
-    // Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
-    // This avoids unwanted asynchronous events from messing with the state.
-    private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
-
-        @Override
-        public void userActivity(long timeout) {
-        }
-
-        @Override
-        public void showBackupSecurity() {
-        }
-
-        @Override
-        public void setOnDismissAction(OnDismissAction action) {
-        }
-
-        @Override
-        public void reportSuccessfulUnlockAttempt() {
-        }
-
-        @Override
-        public void reportFailedUnlockAttempt() {
-        }
-
-        @Override
-        public boolean isVerifyUnlockOnly() {
-            return false;
-        }
-
-        @Override
-        public int getFailedAttempts() {
-            return 0;
-        }
-
-        @Override
-        public void dismiss(boolean securityVerified) {
-        }
-    };
-
-    protected boolean mShowSecurityWhenReturn;
-
-    @Override
-    public void reset() {
-        mIsVerifyUnlockOnly = false;
-        mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_status_view));
-    }
-
-    /**
-     * Sets an action to perform when keyguard is dismissed.
-     * @param action
-     */
-    protected void setOnDismissAction(OnDismissAction action) {
-        mDismissAction = action;
-    }
-
-    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
-        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
-        KeyguardSecurityView view = null;
-        final int children = mSecurityViewContainer.getChildCount();
-        for (int child = 0; child < children; child++) {
-            if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) {
-                view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child));
-                break;
-            }
-        }
-        int layoutId = getLayoutIdFor(securityMode);
-        if (view == null && layoutId != 0) {
-            final LayoutInflater inflater = LayoutInflater.from(mContext);
-            if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
-            View v = inflater.inflate(layoutId, mSecurityViewContainer, false);
-            mSecurityViewContainer.addView(v);
-            updateSecurityView(v);
-            view = (KeyguardSecurityView)v;
-        }
-
-        if (view instanceof KeyguardSelectorView) {
-            KeyguardSelectorView selectorView = (KeyguardSelectorView) view;
-            View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container);
-            selectorView.setCarrierArea(carrierText);
-        }
-
-        return view;
-    }
-
-    /**
-     * Switches to the given security view unless it's already being shown, in which case
-     * this is a no-op.
-     *
-     * @param securityMode
-     */
-    private void showSecurityScreen(SecurityMode securityMode) {
-        if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
-
-        if (securityMode == mCurrentSecuritySelection) return;
-
-        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
-        KeyguardSecurityView newView = getSecurityView(securityMode);
-
-        // Enter full screen mode if we're in SIM or Account screen
-        boolean fullScreenEnabled = getResources().getBoolean(
-                com.android.internal.R.bool.kg_sim_puk_account_full_screen);
-        boolean isSimOrAccount = securityMode == SecurityMode.SimPin
-                || securityMode == SecurityMode.SimPuk
-                || securityMode == SecurityMode.Account;
-        mAppWidgetContainer.setVisibility(
-                isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE);
-
-        if (mSlidingChallengeLayout != null) {
-            mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled);
-        }
-
-        // Emulate Activity life cycle
-        if (oldView != null) {
-            oldView.onPause();
-            oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
-        }
-        newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
-        newView.setKeyguardCallback(mCallback);
-
-        final boolean needsInput = newView.needsInput();
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.setNeedsInput(needsInput);
-        }
-
-        // Find and show this child.
-        final int childCount = mSecurityViewContainer.getChildCount();
-
-        mSecurityViewContainer.setInAnimation(
-                AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in));
-        mSecurityViewContainer.setOutAnimation(
-                AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out));
-        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
-        for (int i = 0; i < childCount; i++) {
-            if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
-                mSecurityViewContainer.setDisplayedChild(i);
-                break;
-            }
-        }
-
-        if (securityMode == SecurityMode.None) {
-            // Discard current runnable if we're switching back to the selector view
-            setOnDismissAction(null);
-        }
-        if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
-            // we're showing account as a backup, provide a way to get back to primary
-            setBackButtonEnabled(true);
-        }
-        mCurrentSecuritySelection = securityMode;
-    }
-
-    @Override
-    public void onScreenTurnedOn() {
-        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
-        showPrimarySecurityScreen(false);
-        getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON);
-
-        // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
-        // layout is blank but forcing a layout causes it to reappear (e.g. with with
-        // hierarchyviewer).
-        requestLayout();
-
-        if (mViewStateManager != null) {
-            mViewStateManager.showUsabilityHints();
-        }
-        requestFocus();
-    }
-
-    @Override
-    public void onScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
-                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
-        // Once the screen turns off, we no longer consider this to be first boot and we want the
-        // biometric unlock to start next time keyguard is shown.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-        // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
-        // turns off we reset that behavior
-        clearAppWidgetToShow();
-        checkAppWidgetConsistency();
-        showPrimarySecurityScreen(true);
-        getSecurityView(mCurrentSecuritySelection).onPause();
-        CameraWidgetFrame cameraPage = findCameraPage();
-        if (cameraPage != null) {
-            cameraPage.onScreenTurnedOff();
-        }
-        clearFocus();
-    }
-
-    public void clearAppWidgetToShow() {
-        mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-    }
-
-    @Override
-    public void show() {
-        if (DEBUG) Log.d(TAG, "show()");
-        showPrimarySecurityScreen(false);
-    }
-
-    private boolean isSecure() {
-        SecurityMode mode = mSecurityModel.getSecurityMode();
-        switch (mode) {
-            case Pattern:
-                return mLockPatternUtils.isLockPatternEnabled();
-            case Password:
-            case PIN:
-                return mLockPatternUtils.isLockPasswordEnabled();
-            case SimPin:
-            case SimPuk:
-            case Account:
-                return true;
-            case None:
-                return false;
-            default:
-                throw new IllegalStateException("Unknown security mode " + mode);
-        }
-    }
-
-    @Override
-    public void wakeWhenReadyTq(int keyCode) {
-        if (DEBUG) Log.d(TAG, "onWakeKey");
-        if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) {
-            if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
-            showSecurityScreen(SecurityMode.None);
-        } else {
-            if (DEBUG) Log.d(TAG, "poking wake lock immediately");
-        }
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.wakeUp();
-        }
-    }
-
-    @Override
-    public void verifyUnlock() {
-        SecurityMode securityMode = mSecurityModel.getSecurityMode();
-        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.keyguardDone(true);
-            }
-        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
-                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
-                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
-            // can only verify unlock when in pattern/password mode
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.keyguardDone(false);
-            }
-        } else {
-            // otherwise, go to the unlock screen, see if they can verify it
-            mIsVerifyUnlockOnly = true;
-            showSecurityScreen(securityMode);
-        }
-    }
-
-    private int getSecurityViewIdForMode(SecurityMode securityMode) {
-        switch (securityMode) {
-            case None: return R.id.keyguard_selector_view;
-            case Pattern: return R.id.keyguard_pattern_view;
-            case PIN: return R.id.keyguard_pin_view;
-            case Password: return R.id.keyguard_password_view;
-            case Biometric: return R.id.keyguard_face_unlock_view;
-            case Account: return R.id.keyguard_account_view;
-            case SimPin: return R.id.keyguard_sim_pin_view;
-            case SimPuk: return R.id.keyguard_sim_puk_view;
-        }
-        return 0;
-    }
-
-    private int getLayoutIdFor(SecurityMode securityMode) {
-        switch (securityMode) {
-            case None: return R.layout.keyguard_selector_view;
-            case Pattern: return R.layout.keyguard_pattern_view;
-            case PIN: return R.layout.keyguard_pin_view;
-            case Password: return R.layout.keyguard_password_view;
-            case Biometric: return R.layout.keyguard_face_unlock_view;
-            case Account: return R.layout.keyguard_account_view;
-            case SimPin: return R.layout.keyguard_sim_pin_view;
-            case SimPuk: return R.layout.keyguard_sim_puk_view;
-            default:
-                return 0;
-        }
-    }
-
-    private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
-        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
-        if (appWidgetInfo != null) {
-            AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo);
-            addWidget(view, pageIndex);
-            return true;
-        } else {
-            if (updateDbIfFailed) {
-                Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + "  was null for user"
-                        + mUserId + ", deleting");
-                mAppWidgetHost.deleteAppWidgetId(appId);
-                mLockPatternUtils.removeAppWidget(appId);
-            }
-            return false;
-        }
-    }
-
-    private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks =
-        new CameraWidgetFrame.Callbacks() {
-            @Override
-            public void onLaunchingCamera() {
-                setSliderHandleAlpha(0);
-            }
-
-            @Override
-            public void onCameraLaunchedSuccessfully() {
-                if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) {
-                    mAppWidgetContainer.scrollLeft();
-                }
-                setSliderHandleAlpha(1);
-                mShowSecurityWhenReturn = true;
-            }
-
-            @Override
-            public void onCameraLaunchedUnsuccessfully() {
-                setSliderHandleAlpha(1);
-            }
-
-            private void setSliderHandleAlpha(float alpha) {
-                SlidingChallengeLayout slider =
-                        (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
-                if (slider != null) {
-                    slider.setHandleAlpha(alpha);
-                }
-            }
-        };
-
-    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
-        @Override
-        Context getContext() {
-            return mContext;
-        }
-
-        @Override
-        KeyguardSecurityCallback getCallback() {
-            return mCallback;
-        }
-
-        @Override
-        LockPatternUtils getLockPatternUtils() {
-            return mLockPatternUtils;
-        }
-    };
-
-    private int numWidgets() {
-        final int childCount = mAppWidgetContainer.getChildCount();
-        int widgetCount = 0;
-        for (int i = 0; i < childCount; i++) {
-            if (mAppWidgetContainer.isWidgetPage(i)) {
-                widgetCount++;
-            }
-        }
-        return widgetCount;
-    }
-
-    private void addDefaultWidgets() {
-        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
-            LayoutInflater inflater = LayoutInflater.from(mContext);
-            View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
-            mAppWidgetContainer.addWidget(addWidget, 0);
-            View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
-            addWidgetButton.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    // Pass in an invalid widget id... the picker will allocate an ID for us
-                    mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
-                }
-            });
-        }
-
-        // We currently disable cameras in safe mode because we support loading 3rd party
-        // cameras we can't trust.  TODO: plumb safe mode into camera creation code and only
-        // inflate system-provided camera?
-        if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
-                && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
-            View cameraWidget =
-                    CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
-            if (cameraWidget != null) {
-                mAppWidgetContainer.addWidget(cameraWidget);
-            }
-        }
-
-        enableUserSelectorIfNecessary();
-    }
-
-    /**
-     * Create KeyguardTransportControlView on demand.
-     * @return
-     */
-    private KeyguardTransportControlView getOrCreateTransportControl() {
-        if (mTransportControl == null) {
-            LayoutInflater inflater = LayoutInflater.from(mContext);
-            mTransportControl = (KeyguardTransportControlView)
-                    inflater.inflate(R.layout.keyguard_transport_control_view, this, false);
-        }
-        return mTransportControl;
-    }
-
-    private int getInsertPageIndex() {
-        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
-        int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget);
-        if (insertionIndex < 0) {
-            insertionIndex = 0; // no add widget page found
-        } else {
-            insertionIndex++; // place after add widget
-        }
-        return insertionIndex;
-    }
-
-    private void addDefaultStatusWidget(int index) {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
-        mAppWidgetContainer.addWidget(statusWidget, index);
-    }
-
-    private void addWidgetsFromSettings() {
-        if (mSafeModeEnabled || widgetsDisabledByDpm()) {
-            return;
-        }
-
-        int insertionIndex = getInsertPageIndex();
-
-        // Add user-selected widget
-        final int[] widgets = mLockPatternUtils.getAppWidgets();
-
-        if (widgets == null) {
-            Log.d(TAG, "Problem reading widgets");
-        } else {
-            for (int i = widgets.length -1; i >= 0; i--) {
-                if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
-                    addDefaultStatusWidget(insertionIndex);
-                } else {
-                    // We add the widgets from left to right, starting after the first page after
-                    // the add page. We count down, since the order will be persisted from right
-                    // to left, starting after camera.
-                    addWidget(widgets[i], insertionIndex, true);
-                }
-            }
-        }
-    }
-
-    private int allocateIdForDefaultAppWidget() {
-        int appWidgetId;
-        Resources res = getContext().getResources();
-        ComponentName defaultAppWidget = new ComponentName(
-                res.getString(R.string.widget_default_package_name),
-                res.getString(R.string.widget_default_class_name));
-
-        // Note: we don't support configuring the widget
-        appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
-        try {
-            mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
-
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
-            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-            appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-        return appWidgetId;
-    }
-    public void checkAppWidgetConsistency() {
-        // Since this method may bind a widget (which we can't do until boot completed) we
-        // may have to defer it until after boot complete.
-        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
-            mCheckAppWidgetConsistencyOnBootCompleted = true;
-            return;
-        }
-        final int childCount = mAppWidgetContainer.getChildCount();
-        boolean widgetPageExists = false;
-        for (int i = 0; i < childCount; i++) {
-            if (mAppWidgetContainer.isWidgetPage(i)) {
-                widgetPageExists = true;
-                break;
-            }
-        }
-        if (!widgetPageExists) {
-            final int insertPageIndex = getInsertPageIndex();
-
-            final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm();
-            boolean addedDefaultAppWidget = false;
-
-            if (!mSafeModeEnabled) {
-                if (userAddedWidgetsEnabled) {
-                    int appWidgetId = allocateIdForDefaultAppWidget();
-                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true);
-                    }
-                } else {
-                    // note: even if widgetsDisabledByDpm() returns true, we still bind/create
-                    // the default appwidget if possible
-                    int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId();
-                    if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        appWidgetId = allocateIdForDefaultAppWidget();
-                        if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                            mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId);
-                        }
-                    }
-                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false);
-                        if (!addedDefaultAppWidget) {
-                            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                            mLockPatternUtils.writeFallbackAppWidgetId(
-                                    AppWidgetManager.INVALID_APPWIDGET_ID);
-                        }
-                    }
-                }
-            }
-
-            // Use the built-in status/clock view if we can't inflate the default widget
-            if (!addedDefaultAppWidget) {
-                addDefaultStatusWidget(insertPageIndex);
-            }
-
-            // trigger DB updates only if user-added widgets are enabled
-            if (!mSafeModeEnabled && userAddedWidgetsEnabled) {
-                mAppWidgetContainer.onAddView(
-                        mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex);
-            }
-        }
-    }
-
-    Runnable mSwitchPageRunnable = new Runnable() {
-        @Override
-        public void run() {
-           showAppropriateWidgetPage();
-        }
-    };
-
-    static class SavedState extends BaseSavedState {
-        int transportState;
-        int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            this.transportState = in.readInt();
-            this.appWidgetToShow = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(this.transportState);
-            out.writeInt(this.appWidgetToShow);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        if (DEBUG) Log.d(TAG, "onSaveInstanceState, tstate=" + mTransportState);
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-        // If the transport is showing, force it to show it on restore.
-        final boolean showing = mTransportControl != null
-                && mAppWidgetContainer.getWidgetPageIndex(mTransportControl) >= 0;
-        ss.transportState =  showing ? TRANSPORT_VISIBLE : mTransportState;
-        ss.appWidgetToShow = mAppWidgetToShow;
-        return ss;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-        mTransportState = (ss.transportState);
-        mAppWidgetToShow = ss.appWidgetToShow;
-        if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState);
-        post(mSwitchPageRunnable);
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-        if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
-        if (hasWindowFocus && mShowSecurityWhenReturn) {
-            SlidingChallengeLayout slider =
-                (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
-            if (slider != null) {
-                slider.setHandleAlpha(1);
-                slider.showChallenge(true);
-            }
-            mShowSecurityWhenReturn = false;
-        }
-    }
-
-    private void showAppropriateWidgetPage() {
-        int state = mTransportState;
-        ensureTransportPresentOrRemoved(state);
-        int pageToShow = getAppropriateWidgetPage(state);
-        mAppWidgetContainer.setCurrentPage(pageToShow);
-    }
-
-    /**
-     * Examines the current state and adds the transport to the widget pager when the state changes.
-     *
-     * Showing the initial transport and keeping it around is a bit tricky because the signals
-     * coming from music players aren't always clear. Here's how the states are handled:
-     *
-     * {@link TRANSPORT_GONE} means we have no reason to show the transport - remove it if present.
-     *
-     * {@link TRANSPORT_INVISIBLE} means we have potential to show the transport because a music
-     * player is registered but not currently playing music (or we don't know the state yet). The
-     * code adds it conditionally on play state.
-     *
-     * {@link #TRANSPORT_VISIBLE} means a music player is active and transport should be showing.
-     *
-     * Once the transport is showing, we always show it until keyguard is dismissed. This state is
-     * maintained by onSave/RestoreInstanceState(). This state is cleared in
-     * {@link KeyguardViewManager#hide} when keyguard is dismissed, which causes the transport to be
-     * gone when keyguard is restarted until we get an update with the current state.
-     *
-     * @param state
-     */
-    private void ensureTransportPresentOrRemoved(int state) {
-        final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1;
-        final boolean visible = state == TRANSPORT_VISIBLE;
-        final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state);
-        if (!showing && (visible || shouldBeVisible)) {
-            if (DEBUGXPORT) Log.v(TAG, "add transport");
-            // insert to left of camera if it exists, otherwise after right-most widget
-            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
-            int position = 0; // handle no widget case
-            if (lastWidget >= 0) {
-                position = mAppWidgetContainer.isCameraPage(lastWidget) ?
-                        lastWidget : lastWidget + 1;
-            }
-            mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position);
-        } else if (showing && state == TRANSPORT_GONE) {
-            if (DEBUGXPORT) Log.v(TAG, "remove transport");
-            mAppWidgetContainer.removeWidget(getOrCreateTransportControl());
-            mTransportControl = null;
-        }
-    }
-
-    private CameraWidgetFrame findCameraPage() {
-        for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
-            if (mAppWidgetContainer.isCameraPage(i)) {
-                return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i);
-            }
-        }
-        return null;
-    }
-
-    boolean isMusicPage(int pageIndex) {
-        return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
-    }
-
-    private int getAppropriateWidgetPage(int musicTransportState) {
-        // assumes at least one widget (besides camera + add)
-        if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
-            final int childCount = mAppWidgetContainer.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId()
-                        == mAppWidgetToShow) {
-                    return i;
-                }
-            }
-            mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-        // if music playing, show transport
-        if (musicTransportState == TRANSPORT_VISIBLE) {
-            if (DEBUG) Log.d(TAG, "Music playing, show transport");
-            return mAppWidgetContainer.getWidgetPageIndex(getOrCreateTransportControl());
-        }
-
-        // else show the right-most widget (except for camera)
-        int rightMost = mAppWidgetContainer.getChildCount() - 1;
-        if (mAppWidgetContainer.isCameraPage(rightMost)) {
-            rightMost--;
-        }
-        if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost);
-        return rightMost;
-    }
-
-    private void enableUserSelectorIfNecessary() {
-        if (!UserManager.supportsMultipleUsers()) {
-            return; // device doesn't support multi-user mode
-        }
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um == null) {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            Log.e(TAG, "user service is null.", t);
-            return;
-        }
-
-        // if there are multiple users, we need to enable to multi-user switcher
-        final List<UserInfo> users = um.getUsers(true);
-        if (users == null) {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            Log.e(TAG, "list of users is null.", t);
-            return;
-        }
-
-        final View multiUserView = findViewById(R.id.keyguard_user_selector);
-        if (multiUserView == null) {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            Log.e(TAG, "can't find user_selector in layout.", t);
-            return;
-        }
-
-        if (users.size() > 1) {
-            if (multiUserView instanceof KeyguardMultiUserSelectorView) {
-                mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
-                mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
-                mKeyguardMultiUserSelectorView.addUsers(users);
-                UserSwitcherCallback callback = new UserSwitcherCallback() {
-                    @Override
-                    public void hideSecurityView(int duration) {
-                        mSecurityViewContainer.animate().alpha(0).setDuration(duration);
-                    }
-
-                    @Override
-                    public void showSecurityView() {
-                        mSecurityViewContainer.setAlpha(1.0f);
-                    }
-
-                    @Override
-                    public void showUnlockHint() {
-                        if (mKeyguardSelectorView != null) {
-                            mKeyguardSelectorView.showUsabilityHint();
-                        }
-                    }
-
-                    @Override
-                    public void userActivity() {
-                        if (mViewMediatorCallback != null) {
-                            mViewMediatorCallback.userActivity();
-                        }
-                    }
-                };
-                mKeyguardMultiUserSelectorView.setCallback(callback);
-            } else {
-                Throwable t = new Throwable();
-                t.fillInStackTrace();
-                if (multiUserView == null) {
-                    Log.e(TAG, "could not find the user_selector.", t);
-                } else {
-                    Log.e(TAG, "user_selector is the wrong type.", t);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void cleanUp() {
-        // Make sure we let go of all widgets and their package contexts promptly. If we don't do
-        // this, and the associated application is uninstalled, it can cause a soft reboot.
-        int count = mAppWidgetContainer.getChildCount();
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame frame = mAppWidgetContainer.getWidgetPageAt(i);
-            frame.removeAllViews();
-        }
-    }
-
-    /**
-     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
-     * some cases where we wish to disable it, notably when the menu button placement or technology
-     * is prone to false positives.
-     *
-     * @return true if the menu key should be enabled
-     */
-    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
-    private boolean shouldEnableMenuKey() {
-        final Resources res = getResources();
-        final boolean configDisabled = res.getBoolean(
-                com.android.internal.R.bool.config_disableMenuKeyInLockScreen);
-        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
-        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
-        return !configDisabled || isTestHarness || fileOverride;
-    }
-
-    public void goToUserSwitcher() {
-        mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector));
-    }
-
-    public void goToWidget(int appWidgetId) {
-        mAppWidgetToShow = appWidgetId;
-        mSwitchPageRunnable.run();
-    }
-
-    public boolean handleMenuKey() {
-        // The following enables the MENU key to work for testing automation
-        if (shouldEnableMenuKey()) {
-            showNextSecurityScreenOrFinish(false);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean handleBackKey() {
-        if (mCurrentSecuritySelection == SecurityMode.Account) {
-            // go back to primary screen and re-disable back
-            setBackButtonEnabled(false);
-            showPrimarySecurityScreen(false /*turningOff*/);
-            return true;
-        }
-        if (mCurrentSecuritySelection != SecurityMode.None) {
-            mCallback.dismiss(false);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     *  Dismisses the keyguard by going to the next screen or making it gone.
-     */
-    public void dismiss() {
-        showNextSecurityScreenOrFinish(false);
-    }
-
-    public void showAssistant() {
-        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-
-        if (intent == null) return;
-
-        final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
-                getHandler(), null);
-
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        mActivityLauncher.launchActivityWithAnimation(
-                intent, false, opts.toBundle(), null, null);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardLinearLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardLinearLayout.java
deleted file mode 100644
index 0fc54cd..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardLinearLayout.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-/**
- * A layout that arranges its children into a special type of grid.
- */
-public class KeyguardLinearLayout extends LinearLayout {
-    int mTopChild = 0;
-
-    public KeyguardLinearLayout(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardLinearLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardLinearLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public void setTopChild(View child) {
-        int top = indexOfChild(child);
-        mTopChild = top;
-        invalidate();
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
deleted file mode 100644
index 9b58803..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.BatteryManager;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.widget.TextView;
-
-import libcore.util.MutableInt;
-
-import java.lang.ref.WeakReference;
-
-import com.android.internal.R;
-import com.android.internal.widget.ILockSettings;
-import com.android.internal.widget.LockPatternUtils;
-
-/***
- * Manages a number of views inside of the given layout. See below for a list of widgets.
- */
-class KeyguardMessageArea extends TextView {
-    /** Handler token posted with accessibility announcement runnables. */
-    private static final Object ANNOUNCE_TOKEN = new Object();
-
-    /**
-     * Delay before speaking an accessibility announcement. Used to prevent
-     * lift-to-type from interrupting itself.
-     */
-    private static final long ANNOUNCEMENT_DELAY = 250;
-
-    static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging;
-    static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
-
-    static final int SECURITY_MESSAGE_DURATION = 5000;
-    protected static final int FADE_DURATION = 750;
-
-    private static final String TAG = "KeyguardMessageArea";
-
-    // are we showing battery information?
-    boolean mShowingBatteryInfo = false;
-
-    // is the bouncer up?
-    boolean mShowingBouncer = false;
-
-    // last known plugged in state
-    boolean mCharging = false;
-
-    // last known battery level
-    int mBatteryLevel = 100;
-
-    KeyguardUpdateMonitor mUpdateMonitor;
-
-    // Timeout before we reset the message to show charging/owner info
-    long mTimeout = SECURITY_MESSAGE_DURATION;
-
-    // Shadowed text values
-    protected boolean mBatteryCharged;
-    protected boolean mBatteryIsLow;
-
-    private Handler mHandler;
-
-    CharSequence mMessage;
-    boolean mShowingMessage;
-    private CharSequence mSeparator;
-    private LockPatternUtils mLockPatternUtils;
-
-    Runnable mClearMessageRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mMessage = null;
-            mShowingMessage = false;
-            if (mShowingBouncer) {
-                hideMessage(FADE_DURATION, true);
-            } else {
-                update();
-            }
-        }
-    };
-
-    public static class Helper implements SecurityMessageDisplay {
-        KeyguardMessageArea mMessageArea;
-        Helper(View v) {
-            mMessageArea = (KeyguardMessageArea) v.findViewById(R.id.keyguard_message_area);
-            if (mMessageArea == null) {
-                throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass());
-            }
-        }
-
-        public void setMessage(CharSequence msg, boolean important) {
-            if (!TextUtils.isEmpty(msg) && important) {
-                mMessageArea.mMessage = msg;
-                mMessageArea.securityMessageChanged();
-            }
-        }
-
-        public void setMessage(int resId, boolean important) {
-            if (resId != 0 && important) {
-                mMessageArea.mMessage = mMessageArea.getContext().getResources().getText(resId);
-                mMessageArea.securityMessageChanged();
-            }
-        }
-
-        public void setMessage(int resId, boolean important, Object... formatArgs) {
-            if (resId != 0 && important) {
-                mMessageArea.mMessage = mMessageArea.getContext().getString(resId, formatArgs);
-                mMessageArea.securityMessageChanged();
-            }
-        }
-
-        @Override
-        public void showBouncer(int duration) {
-            mMessageArea.hideMessage(duration, false);
-            mMessageArea.mShowingBouncer = true;
-        }
-
-        @Override
-        public void hideBouncer(int duration) {
-            mMessageArea.showMessage(duration);
-            mMessageArea.mShowingBouncer = false;
-        }
-
-        @Override
-        public void setTimeout(int timeoutMs) {
-            mMessageArea.mTimeout = timeoutMs;
-        }
-    }
-
-    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
-            mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow();
-            mCharging = status.status == BatteryManager.BATTERY_STATUS_CHARGING
-                     || status.status == BatteryManager.BATTERY_STATUS_FULL;
-            mBatteryLevel = status.level;
-            mBatteryCharged = status.isCharged();
-            mBatteryIsLow = status.isBatteryLow();
-            update();
-        }
-    };
-
-    public KeyguardMessageArea(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardMessageArea(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mLockPatternUtils = new LockPatternUtils(context);
-
-        // This is required to ensure marquee works
-        setSelected(true);
-
-        // Registering this callback immediately updates the battery state, among other things.
-        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
-        mUpdateMonitor.registerCallback(mInfoCallback);
-        mHandler = new Handler(Looper.myLooper());
-
-        mSeparator = getResources().getString(R.string.kg_text_message_separator);
-
-        update();
-    }
-
-    public void securityMessageChanged() {
-        setAlpha(1f);
-        mShowingMessage = true;
-        update();
-        mHandler.removeCallbacks(mClearMessageRunnable);
-        if (mTimeout > 0) {
-            mHandler.postDelayed(mClearMessageRunnable, mTimeout);
-        }
-        mHandler.removeCallbacksAndMessages(ANNOUNCE_TOKEN);
-        mHandler.postAtTime(new AnnounceRunnable(this, getText()), ANNOUNCE_TOKEN,
-                (SystemClock.uptimeMillis() + ANNOUNCEMENT_DELAY));
-    }
-
-    /**
-     * Update the status lines based on these rules:
-     * AlarmStatus: Alarm state always gets it's own line.
-     * Status1 is shared between help, battery status and generic unlock instructions,
-     * prioritized in that order.
-     * @param showStatusLines status lines are shown if true
-     */
-    void update() {
-        MutableInt icon = new MutableInt(0);
-        CharSequence status = concat(getChargeInfo(icon), getOwnerInfo(), getCurrentMessage());
-        setCompoundDrawablesWithIntrinsicBounds(icon.value, 0, 0, 0);
-        setText(status);
-    }
-
-    private CharSequence concat(CharSequence... args) {
-        StringBuilder b = new StringBuilder();
-        if (!TextUtils.isEmpty(args[0])) {
-            b.append(args[0]);
-        }
-        for (int i = 1; i < args.length; i++) {
-            CharSequence text = args[i];
-            if (!TextUtils.isEmpty(text)) {
-                if (b.length() > 0) {
-                    b.append(mSeparator);
-                }
-                b.append(text);
-            }
-        }
-        return b.toString();
-    }
-
-    CharSequence getCurrentMessage() {
-        return mShowingMessage ? mMessage : null;
-    }
-
-    String getOwnerInfo() {
-        ContentResolver res = getContext().getContentResolver();
-        String info = null;
-        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
-        if (ownerInfoEnabled && !mShowingMessage) {
-            info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
-        }
-        return info;
-    }
-
-    private CharSequence getChargeInfo(MutableInt icon) {
-        CharSequence string = null;
-        if (mShowingBatteryInfo && !mShowingMessage) {
-            // Battery status
-            if (mCharging) {
-                // Charging, charged or waiting to charge.
-                string = getContext().getString(mBatteryCharged
-                        ? com.android.internal.R.string.lockscreen_charged
-                        : com.android.internal.R.string.lockscreen_plugged_in, mBatteryLevel);
-                icon.value = CHARGING_ICON;
-            } else if (mBatteryIsLow) {
-                // Battery is low
-                string = getContext().getString(
-                        com.android.internal.R.string.lockscreen_low_battery);
-                icon.value = BATTERY_LOW_ICON;
-            }
-        }
-        return string;
-    }
-
-    private void hideMessage(int duration, boolean thenUpdate) {
-        if (duration > 0) {
-            Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f);
-            anim.setDuration(duration);
-            if (thenUpdate) {
-                anim.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                            public void onAnimationEnd(Animator animation) {
-                            update();
-                        }
-                });
-            }
-            anim.start();
-        } else {
-            setAlpha(0f);
-            if (thenUpdate) {
-                update();
-            }
-        }
-    }
-
-    private void showMessage(int duration) {
-        if (duration > 0) {
-            Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f);
-            anim.setDuration(duration);
-            anim.start();
-        } else {
-            setAlpha(1f);
-        }
-    }
-
-    /**
-     * Runnable used to delay accessibility announcements.
-     */
-    private static class AnnounceRunnable implements Runnable {
-        private final WeakReference<View> mHost;
-        private final CharSequence mTextToAnnounce;
-
-        public AnnounceRunnable(View host, CharSequence textToAnnounce) {
-            mHost = new WeakReference<View>(host);
-            mTextToAnnounce = textToAnnounce;
-        }
-
-        @Override
-        public void run() {
-            final View host = mHost.get();
-            if (host != null) {
-                host.announceForAccessibility(mTextToAnnounce);
-            }
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
deleted file mode 100644
index 387e0ce..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.R;
-
-class KeyguardMultiUserAvatar extends FrameLayout {
-    private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
-
-    private ImageView mUserImage;
-    private TextView mUserName;
-    private UserInfo mUserInfo;
-    private static final float ACTIVE_ALPHA = 1.0f;
-    private static final float INACTIVE_ALPHA = 1.0f;
-    private static final float ACTIVE_SCALE = 1.5f;
-    private static final float ACTIVE_TEXT_ALPHA = 0f;
-    private static final float INACTIVE_TEXT_ALPHA = 0.5f;
-    private static final int SWITCH_ANIMATION_DURATION = 150;
-
-    private final float mActiveAlpha;
-    private final float mActiveScale;
-    private final float mActiveTextAlpha;
-    private final float mInactiveAlpha;
-    private final float mInactiveTextAlpha;
-    private final float mShadowRadius;
-    private final float mStroke;
-    private final float mIconSize;
-    private final int mFrameColor;
-    private final int mFrameShadowColor;
-    private final int mTextColor;
-    private final int mHighlightColor;
-
-    private boolean mTouched;
-
-    private boolean mActive;
-    private boolean mInit = true;
-    private KeyguardMultiUserSelectorView mUserSelector;
-    private KeyguardCircleFramedDrawable mFramed;
-    private boolean mPressLock;
-
-    public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
-            KeyguardMultiUserSelectorView userSelector, UserInfo info) {
-        KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar)
-                LayoutInflater.from(context).inflate(resId, userSelector, false);
-
-        icon.init(info, userSelector);
-        return icon;
-    }
-
-    public KeyguardMultiUserAvatar(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        Resources res = mContext.getResources();
-        mTextColor = res.getColor(R.color.keyguard_avatar_nick_color);
-        mIconSize = res.getDimension(R.dimen.keyguard_avatar_size);
-        mStroke = res.getDimension(R.dimen.keyguard_avatar_frame_stroke_width);
-        mShadowRadius = res.getDimension(R.dimen.keyguard_avatar_frame_shadow_radius);
-        mFrameColor = res.getColor(R.color.keyguard_avatar_frame_color);
-        mFrameShadowColor = res.getColor(R.color.keyguard_avatar_frame_shadow_color);
-        mHighlightColor = res.getColor(R.color.keyguard_avatar_frame_pressed_color);
-        mActiveTextAlpha = ACTIVE_TEXT_ALPHA;
-        mInactiveTextAlpha = INACTIVE_TEXT_ALPHA;
-        mActiveScale = ACTIVE_SCALE;
-        mActiveAlpha = ACTIVE_ALPHA;
-        mInactiveAlpha = INACTIVE_ALPHA;
-
-        mTouched = false;
-
-        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-    }
-
-    protected String rewriteIconPath(String path) {
-        if (!this.getClass().getName().contains("internal")) {
-            return path.replace("system", "data");
-        }
-        return path;
-    }
-
-    public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) {
-        mUserInfo = user;
-        mUserSelector = userSelector;
-
-        mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar);
-        mUserName = (TextView) findViewById(R.id.keyguard_user_name);
-
-        mFramed = (KeyguardCircleFramedDrawable)
-                KeyguardViewMediator.getAvatarCache().get(user.id);
-
-        // If we can't find it or the params don't match, create the drawable again
-        if (mFramed == null
-                || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor,
-                        mShadowRadius, mHighlightColor)) {
-            Bitmap icon = null;
-            try {
-                icon = BitmapFactory.decodeFile(rewriteIconPath(user.iconPath));
-            } catch (Exception e) {
-                if (DEBUG) Log.d(TAG, "failed to open profile icon " + user.iconPath, e);
-            }
-
-            if (icon == null) {
-                icon = BitmapFactory.decodeResource(mContext.getResources(),
-                        com.android.internal.R.drawable.ic_contact_picture);
-            }
-
-            mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
-                    mFrameShadowColor, mShadowRadius, mHighlightColor);
-            KeyguardViewMediator.getAvatarCache().put(user.id, mFramed);
-        }
-
-        mFramed.reset();
-
-        mUserImage.setImageDrawable(mFramed);
-        mUserName.setText(mUserInfo.name);
-        setOnClickListener(mUserSelector);
-        mInit = false;
-    }
-
-    public void setActive(boolean active, boolean animate, final Runnable onComplete) {
-        if (mActive != active || mInit) {
-            mActive = active;
-
-            if (active) {
-                KeyguardLinearLayout parent = (KeyguardLinearLayout) getParent();
-                parent.setTopChild(this);
-                // TODO: Create an appropriate asset when string changes are possible.
-                setContentDescription(mUserName.getText()
-                        + ". " + mContext.getString(R.string.user_switched, ""));
-            } else {
-                setContentDescription(mUserName.getText());
-            }
-        }
-        updateVisualsForActive(mActive, animate, SWITCH_ANIMATION_DURATION, onComplete);
-    }
-
-    void updateVisualsForActive(boolean active, boolean animate, int duration,
-            final Runnable onComplete) {
-        final float finalAlpha = active ? mActiveAlpha : mInactiveAlpha;
-        final float initAlpha = active ? mInactiveAlpha : mActiveAlpha;
-        final float finalScale = active ? 1f : 1f / mActiveScale;
-        final float initScale = mFramed.getScale();
-        final int finalTextAlpha = active ? (int) (mActiveTextAlpha * 255) :
-                (int) (mInactiveTextAlpha * 255);
-        final int initTextAlpha = active ? (int) (mInactiveTextAlpha * 255) :
-                (int) (mActiveTextAlpha * 255);
-        int textColor = mTextColor;
-        mUserName.setTextColor(textColor);
-
-        if (animate && mTouched) {
-            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-            va.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float r = animation.getAnimatedFraction();
-                    float scale = (1 - r) * initScale + r * finalScale;
-                    float alpha = (1 - r) * initAlpha + r * finalAlpha;
-                    int textAlpha = (int) ((1 - r) * initTextAlpha + r * finalTextAlpha);
-                    mFramed.setScale(scale);
-                    mUserImage.setAlpha(alpha);
-                    mUserName.setTextColor(Color.argb(textAlpha, 255, 255, 255));
-                    mUserImage.invalidate();
-                }
-            });
-            va.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (onComplete != null) {
-                        onComplete.run();
-                    }
-                }
-            });
-            va.setDuration(duration);
-            va.start();
-        } else {
-            mFramed.setScale(finalScale);
-            mUserImage.setAlpha(finalAlpha);
-            mUserName.setTextColor(Color.argb(finalTextAlpha, 255, 255, 255));
-            if (onComplete != null) {
-                post(onComplete);
-            }
-        }
-
-        mTouched = true;
-    }
-
-    @Override
-    public void setPressed(boolean pressed) {
-        if (mPressLock && !pressed) {
-            return;
-        }
-
-        if (mPressLock || !pressed || isClickable()) {
-            super.setPressed(pressed);
-            mFramed.setPressed(pressed);
-            mUserImage.invalidate();
-        }
-    }
-
-    public void lockPressed(boolean pressed) {
-        mPressLock = pressed;
-        setPressed(pressed);
-    }
-
-    public UserInfo getUserInfo() {
-        return mUserInfo;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
deleted file mode 100644
index f9ea5bb..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.ActivityManagerNative;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.RemoteException;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-
-public class KeyguardMultiUserSelectorView extends FrameLayout implements View.OnClickListener {
-    private static final String TAG = "KeyguardMultiUserSelectorView";
-
-    private ViewGroup mUsersGrid;
-    private KeyguardMultiUserAvatar mActiveUserAvatar;
-    private KeyguardHostView.UserSwitcherCallback mCallback;
-    private static final int FADE_OUT_ANIMATION_DURATION = 100;
-
-    public KeyguardMultiUserSelectorView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    protected void onFinishInflate () {
-        mUsersGrid = (ViewGroup) findViewById(R.id.keyguard_users_grid);
-        mUsersGrid.removeAllViews();
-        setClipChildren(false);
-        setClipToPadding(false);
-
-    }
-
-    public void setCallback(KeyguardHostView.UserSwitcherCallback callback) {
-        mCallback = callback;
-    }
-
-    public void addUsers(Collection<UserInfo> userList) {
-        UserInfo activeUser;
-        try {
-            activeUser = ActivityManagerNative.getDefault().getCurrentUser();
-        } catch (RemoteException re) {
-            activeUser = null;
-        }
-
-        ArrayList<UserInfo> users = new ArrayList<UserInfo>(userList);
-        Collections.sort(users, mOrderAddedComparator);
-
-        for (UserInfo user: users) {
-            KeyguardMultiUserAvatar uv = createAndAddUser(user);
-            if (user.id == activeUser.id) {
-                mActiveUserAvatar = uv;
-            }
-            uv.setActive(false, false, null);
-        }
-        mActiveUserAvatar.lockPressed(true);
-    }
-
-    public void finalizeActiveUserView(boolean animate) {
-        if (animate) {
-            getHandler().postDelayed(new Runnable() {
-                    @Override
-                        public void run() {
-                        finalizeActiveUserNow(true);
-                    }
-                }, 500);
-        } else {
-            finalizeActiveUserNow(animate);
-        }
-    }
-
-    void finalizeActiveUserNow(boolean animate) {
-        mActiveUserAvatar.lockPressed(false);
-        mActiveUserAvatar.setActive(true, animate, null);
-    }
-
-    Comparator<UserInfo> mOrderAddedComparator = new Comparator<UserInfo>() {
-        @Override
-        public int compare(UserInfo lhs, UserInfo rhs) {
-            return (lhs.serialNumber - rhs.serialNumber);
-        }
-    };
-
-    private KeyguardMultiUserAvatar createAndAddUser(UserInfo user) {
-        KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml(
-                R.layout.keyguard_multi_user_avatar, mContext, this, user);
-        mUsersGrid.addView(uv);
-        return uv;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if(event.getActionMasked() != MotionEvent.ACTION_CANCEL && mCallback != null) {
-            mCallback.userActivity();
-        }
-        return false;
-    }
-
-    private void setAllClickable(boolean clickable)
-    {
-        for(int i = 0; i < mUsersGrid.getChildCount(); i++) {
-            View v = mUsersGrid.getChildAt(i);
-            v.setClickable(clickable);
-            v.setPressed(false);
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (!(v instanceof KeyguardMultiUserAvatar)) return;
-        final KeyguardMultiUserAvatar avatar = (KeyguardMultiUserAvatar) v;
-        if (avatar.isClickable()) { // catch race conditions
-            if (mActiveUserAvatar == avatar) {
-                // If they click the currently active user, show the unlock hint
-                mCallback.showUnlockHint();
-                return;
-            } else {
-                // Reset the previously active user to appear inactive
-                mCallback.hideSecurityView(FADE_OUT_ANIMATION_DURATION);
-                setAllClickable(false);
-                avatar.lockPressed(true);
-                mActiveUserAvatar.setActive(false, true, new Runnable() {
-                    @Override
-                    public void run() {
-                        mActiveUserAvatar = avatar;
-                        if (this.getClass().getName().contains("internal")) {
-                            try {
-                                ActivityManagerNative.getDefault()
-                                        .switchUser(avatar.getUserInfo().id);
-                            } catch (RemoteException re) {
-                                Log.e(TAG, "Couldn't switch user " + re);
-                            }
-                        } else {
-                            setAllClickable(true);
-                        }
-                    }
-                });
-            }
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
deleted file mode 100644
index fa80352..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextWatcher;
-import android.text.method.DigitsKeyListener;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.internal.R;
-
-/**
- * Displays a PIN pad for unlocking.
- */
-public class KeyguardPINView extends KeyguardAbsKeyInputView
-        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
-
-    public KeyguardPINView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardPINView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    protected void resetState() {
-        if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) {
-            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
-        } else {
-            mSecurityMessageDisplay.setMessage(R.string.kg_pin_instructions, false);
-        }
-        mPasswordEntry.setEnabled(true);
-    }
-
-    @Override
-    protected int getPasswordTextViewId() {
-        return R.id.pinEntry;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        final View ok = findViewById(R.id.key_enter);
-        if (ok != null) {
-            ok.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    doHapticKeyClick();
-                    if (mPasswordEntry.isEnabled()) {
-                        verifyPasswordAndUnlock();
-                    }
-                }
-            });
-            ok.setOnHoverListener(new LiftToActivateListener(getContext()));
-        }
-
-        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
-        // not a separate view
-        View pinDelete = findViewById(R.id.delete_button);
-        if (pinDelete != null) {
-            pinDelete.setVisibility(View.VISIBLE);
-            pinDelete.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    // check for time-based lockouts
-                    if (mPasswordEntry.isEnabled()) {
-                        CharSequence str = mPasswordEntry.getText();
-                        if (str.length() > 0) {
-                            mPasswordEntry.setText(str.subSequence(0, str.length()-1));
-                        }
-                    }
-                    doHapticKeyClick();
-                }
-            });
-            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
-                public boolean onLongClick(View v) {
-                    // check for time-based lockouts
-                    if (mPasswordEntry.isEnabled()) {
-                        mPasswordEntry.setText("");
-                    }
-                    doHapticKeyClick();
-                    return true;
-                }
-            });
-        }
-
-        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
-        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
-                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-
-        mPasswordEntry.requestFocus();
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public int getWrongPasswordStringId() {
-        return R.string.kg_wrong_pin;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
deleted file mode 100644
index d52c993..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextWatcher;
-import android.text.method.DigitsKeyListener;
-import android.text.method.TextKeyListener;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.internal.R;
-import com.android.internal.widget.PasswordEntryKeyboardHelper;
-import com.android.internal.widget.PasswordEntryKeyboardView;
-
-import java.util.List;
-/**
- * Displays an alphanumeric (latin-1) key entry for the user to enter
- * an unlock password
- */
-
-public class KeyguardPasswordView extends KeyguardAbsKeyInputView
-        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
-
-    private final boolean mShowImeAtScreenOn;
-
-    InputMethodManager mImm;
-
-    public KeyguardPasswordView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardPasswordView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mShowImeAtScreenOn = context.getResources().
-                getBoolean(R.bool.kg_show_ime_at_screen_on);
-    }
-
-    protected void resetState() {
-        mSecurityMessageDisplay.setMessage(R.string.kg_password_instructions, false);
-        mPasswordEntry.setEnabled(true);
-    }
-
-    @Override
-    protected int getPasswordTextViewId() {
-        return R.id.passwordEntry;
-    }
-
-    @Override
-    public boolean needsInput() {
-        return true;
-    }
-
-    @Override
-    public void onResume(int reason) {
-        super.onResume(reason);
-        mPasswordEntry.requestFocus();
-        if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
-            mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
-        }
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        mImm.hideSoftInputFromWindow(getWindowToken(), 0);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        boolean imeOrDeleteButtonVisible = false;
-
-        mImm = (InputMethodManager) getContext().getSystemService(
-                Context.INPUT_METHOD_SERVICE);
-
-        mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
-        mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_VARIATION_PASSWORD);
-
-        // Poke the wakelock any time the text is selected or modified
-        mPasswordEntry.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                mCallback.userActivity(0); // TODO: customize timeout for text?
-            }
-        });
-
-        mPasswordEntry.addTextChangedListener(new TextWatcher() {
-            public void onTextChanged(CharSequence s, int start, int before, int count) {
-            }
-
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            }
-
-            public void afterTextChanged(Editable s) {
-                if (mCallback != null) {
-                    mCallback.userActivity(0);
-                }
-            }
-        });
-
-        mPasswordEntry.requestFocus();
-
-        // If there's more than one IME, enable the IME switcher button
-        View switchImeButton = findViewById(R.id.switch_ime_button);
-        if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(mImm, false)) {
-            switchImeButton.setVisibility(View.VISIBLE);
-            imeOrDeleteButtonVisible = true;
-            switchImeButton.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    mCallback.userActivity(0); // Leave the screen on a bit longer
-                    mImm.showInputMethodPicker();
-                }
-            });
-        }
-
-        // If no icon is visible, reset the start margin on the password field so the text is
-        // still centered.
-        if (!imeOrDeleteButtonVisible) {
-            android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
-            if (params instanceof MarginLayoutParams) {
-                final MarginLayoutParams mlp = (MarginLayoutParams) params;
-                mlp.setMarginStart(0);
-                mPasswordEntry.setLayoutParams(params);
-            }
-        }
-    }
-
-    /**
-     * Method adapted from com.android.inputmethod.latin.Utils
-     *
-     * @param imm The input method manager
-     * @param shouldIncludeAuxiliarySubtypes
-     * @return true if we have multiple IMEs to choose from
-     */
-    private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
-            final boolean shouldIncludeAuxiliarySubtypes) {
-        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
-
-        // Number of the filtered IMEs
-        int filteredImisCount = 0;
-
-        for (InputMethodInfo imi : enabledImis) {
-            // We can return true immediately after we find two or more filtered IMEs.
-            if (filteredImisCount > 1) return true;
-            final List<InputMethodSubtype> subtypes =
-                    imm.getEnabledInputMethodSubtypeList(imi, true);
-            // IMEs that have no subtypes should be counted.
-            if (subtypes.isEmpty()) {
-                ++filteredImisCount;
-                continue;
-            }
-
-            int auxCount = 0;
-            for (InputMethodSubtype subtype : subtypes) {
-                if (subtype.isAuxiliary()) {
-                    ++auxCount;
-                }
-            }
-            final int nonAuxCount = subtypes.size() - auxCount;
-
-            // IMEs that have one or more non-auxiliary subtypes should be counted.
-            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
-            // subtypes should be counted as well.
-            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
-                ++filteredImisCount;
-                continue;
-            }
-        }
-
-        return filteredImisCount > 1
-        // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
-        // input method subtype (The current IME should be LatinIME.)
-                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public int getWrongPasswordStringId() {
-        return R.string.kg_wrong_password;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java
deleted file mode 100644
index e114b78..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternView;
-import com.android.internal.R;
-
-import java.io.IOException;
-import java.util.List;
-
-public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
-
-    private static final String TAG = "SecurityPatternView";
-    private static final boolean DEBUG = false;
-
-    // how long before we clear the wrong pattern
-    private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
-
-    // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK
-    private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
-
-    // how long we stay awake after the user hits the first dot.
-    private static final int UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS = 2000;
-
-    // how many cells the user has to cross before we poke the wakelock
-    private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
-
-    private int mFailedPatternAttemptsSinceLastTimeout = 0;
-    private int mTotalFailedPatternAttempts = 0;
-    private CountDownTimer mCountdownTimer = null;
-    private LockPatternUtils mLockPatternUtils;
-    private LockPatternView mLockPatternView;
-    private Button mForgotPatternButton;
-    private KeyguardSecurityCallback mCallback;
-    private boolean mEnableFallback;
-
-    /**
-     * Keeps track of the last time we poked the wake lock during dispatching of the touch event.
-     * Initialized to something guaranteed to make us poke the wakelock when the user starts
-     * drawing the pattern.
-     * @see #dispatchTouchEvent(android.view.MotionEvent)
-     */
-    private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
-
-    /**
-     * Useful for clearing out the wrong pattern after a delay
-     */
-    private Runnable mCancelPatternRunnable = new Runnable() {
-        public void run() {
-            mLockPatternView.clearPattern();
-        }
-    };
-    private Rect mTempRect = new Rect();
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-    private View mEcaView;
-    private Drawable mBouncerFrame;
-
-    enum FooterMode {
-        Normal,
-        ForgotLockPattern,
-        VerifyUnlocked
-    }
-
-    public KeyguardPatternView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardPatternView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mLockPatternUtils = mLockPatternUtils == null
-                ? new LockPatternUtils(mContext) : mLockPatternUtils;
-
-        mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView);
-        mLockPatternView.setSaveEnabled(false);
-        mLockPatternView.setFocusable(false);
-        mLockPatternView.setOnPatternListener(new UnlockPatternListener());
-
-        // stealth mode will be the same for the life of this screen
-        mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());
-
-        // vibrate mode will be the same for the life of this screen
-        mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
-
-        mForgotPatternButton = (Button) findViewById(R.id.forgot_password_button);
-        // note: some configurations don't have an emergency call area
-        if (mForgotPatternButton != null) {
-            mForgotPatternButton.setText(R.string.kg_forgot_pattern_button_text);
-            mForgotPatternButton.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    mCallback.showBackupSecurity();
-                }
-            });
-        }
-
-        setFocusableInTouchMode(true);
-
-        maybeEnableFallback(mContext);
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
-        if (bouncerFrameView != null) {
-            mBouncerFrame = bouncerFrameView.getBackground();
-        }
-    }
-
-    private void updateFooter(FooterMode mode) {
-        if (mForgotPatternButton == null) return; // no ECA? no footer
-
-        switch (mode) {
-            case Normal:
-                if (DEBUG) Log.d(TAG, "mode normal");
-                mForgotPatternButton.setVisibility(View.GONE);
-                break;
-            case ForgotLockPattern:
-                if (DEBUG) Log.d(TAG, "mode ForgotLockPattern");
-                mForgotPatternButton.setVisibility(View.VISIBLE);
-                break;
-            case VerifyUnlocked:
-                if (DEBUG) Log.d(TAG, "mode VerifyUnlocked");
-                mForgotPatternButton.setVisibility(View.GONE);
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean result = super.onTouchEvent(ev);
-        // as long as the user is entering a pattern (i.e sending a touch event that was handled
-        // by this screen), keep poking the wake lock so that the screen will stay on.
-        final long elapsed = SystemClock.elapsedRealtime() - mLastPokeTime;
-        if (result && (elapsed > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
-            mLastPokeTime = SystemClock.elapsedRealtime();
-        }
-        mTempRect.set(0, 0, 0, 0);
-        offsetRectIntoDescendantCoords(mLockPatternView, mTempRect);
-        ev.offsetLocation(mTempRect.left, mTempRect.top);
-        result = mLockPatternView.dispatchTouchEvent(ev) || result;
-        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
-        return result;
-    }
-
-    public void reset() {
-        // reset lock pattern
-        mLockPatternView.enableInput();
-        mLockPatternView.setEnabled(true);
-        mLockPatternView.clearPattern();
-
-        // if the user is currently locked out, enforce it.
-        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
-        if (deadline != 0) {
-            handleAttemptLockout(deadline);
-        } else {
-            displayDefaultSecurityMessage();
-        }
-
-        // the footer depends on how many total attempts the user has failed
-        if (mCallback.isVerifyUnlockOnly()) {
-            updateFooter(FooterMode.VerifyUnlocked);
-        } else if (mEnableFallback &&
-                (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
-            updateFooter(FooterMode.ForgotLockPattern);
-        } else {
-            updateFooter(FooterMode.Normal);
-        }
-
-    }
-
-    private void displayDefaultSecurityMessage() {
-        if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) {
-            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
-        } else {
-            mSecurityMessageDisplay.setMessage(R.string.kg_pattern_instructions, false);
-        }
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    /** TODO: hook this up */
-    public void cleanUp() {
-        if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
-        mLockPatternUtils = null;
-        mLockPatternView.setOnPatternListener(null);
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-        if (hasWindowFocus) {
-            // when timeout dialog closes we want to update our state
-            reset();
-        }
-    }
-
-    private class UnlockPatternListener implements LockPatternView.OnPatternListener {
-
-        public void onPatternStart() {
-            mLockPatternView.removeCallbacks(mCancelPatternRunnable);
-        }
-
-        public void onPatternCleared() {
-        }
-
-        public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
-            // To guard against accidental poking of the wakelock, look for
-            // the user actually trying to draw a pattern of some minimal length.
-            if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
-                mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
-            } else {
-                // Give just a little extra time if they hit one of the first few dots
-                mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS);
-            }
-        }
-
-        public void onPatternDetected(List<LockPatternView.Cell> pattern) {
-            if (mLockPatternUtils.checkPattern(pattern)) {
-                mCallback.reportSuccessfulUnlockAttempt();
-                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
-                mTotalFailedPatternAttempts = 0;
-                mCallback.dismiss(true);
-            } else {
-                if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
-                    mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
-                }
-                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
-                if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
-                    mTotalFailedPatternAttempts++;
-                    mFailedPatternAttemptsSinceLastTimeout++;
-                    mCallback.reportFailedUnlockAttempt();
-                }
-                if (mFailedPatternAttemptsSinceLastTimeout
-                        >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
-                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
-                    handleAttemptLockout(deadline);
-                } else {
-                    mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
-                    mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
-                }
-            }
-        }
-    }
-
-    private void maybeEnableFallback(Context context) {
-        // Ask the account manager if we have an account that can be used as a
-        // fallback in case the user forgets his pattern.
-        AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context));
-        accountAnalyzer.start();
-    }
-
-    private class AccountAnalyzer implements AccountManagerCallback<Bundle> {
-        private final AccountManager mAccountManager;
-        private final Account[] mAccounts;
-        private int mAccountIndex;
-
-        private AccountAnalyzer(AccountManager accountManager) {
-            mAccountManager = accountManager;
-            mAccounts = accountManager.getAccountsByTypeAsUser("com.google",
-                    new UserHandle(mLockPatternUtils.getCurrentUser()));
-        }
-
-        private void next() {
-            // if we are ready to enable the fallback or if we depleted the list of accounts
-            // then finish and get out
-            if (mEnableFallback || mAccountIndex >= mAccounts.length) {
-                return;
-            }
-
-            // lookup the confirmCredentials intent for the current account
-            mAccountManager.confirmCredentialsAsUser(mAccounts[mAccountIndex], null, null, this,
-                    null, new UserHandle(mLockPatternUtils.getCurrentUser()));
-        }
-
-        public void start() {
-            mEnableFallback = false;
-            mAccountIndex = 0;
-            next();
-        }
-
-        public void run(AccountManagerFuture<Bundle> future) {
-            try {
-                Bundle result = future.getResult();
-                if (result.getParcelable(AccountManager.KEY_INTENT) != null) {
-                    mEnableFallback = true;
-                }
-            } catch (OperationCanceledException e) {
-                // just skip the account if we are unable to query it
-            } catch (IOException e) {
-                // just skip the account if we are unable to query it
-            } catch (AuthenticatorException e) {
-                // just skip the account if we are unable to query it
-            } finally {
-                mAccountIndex++;
-                next();
-            }
-        }
-    }
-
-    private void handleAttemptLockout(long elapsedRealtimeDeadline) {
-        mLockPatternView.clearPattern();
-        mLockPatternView.setEnabled(false);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        if (mEnableFallback) {
-            updateFooter(FooterMode.ForgotLockPattern);
-        }
-
-        mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
-
-            @Override
-            public void onTick(long millisUntilFinished) {
-                final int secondsRemaining = (int) (millisUntilFinished / 1000);
-                mSecurityMessageDisplay.setMessage(
-                        R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
-            }
-
-            @Override
-            public void onFinish() {
-                mLockPatternView.setEnabled(true);
-                displayDefaultSecurityMessage();
-                // TODO mUnlockIcon.setVisibility(View.VISIBLE);
-                mFailedPatternAttemptsSinceLastTimeout = 0;
-                if (mEnableFallback) {
-                    updateFooter(FooterMode.ForgotLockPattern);
-                } else {
-                    updateFooter(FooterMode.Normal);
-                }
-            }
-
-        }.start();
-    }
-
-    @Override
-    public boolean needsInput() {
-        return false;
-    }
-
-    @Override
-    public void onPause() {
-        if (mCountdownTimer != null) {
-            mCountdownTimer.cancel();
-            mCountdownTimer = null;
-        }
-    }
-
-    @Override
-    public void onResume(int reason) {
-        reset();
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityCallback.java
deleted file mode 100644
index 7e6c108..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityCallback.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.policy.impl.keyguard.KeyguardHostView.OnDismissAction;
-
-public interface KeyguardSecurityCallback {
-
-    /**
-     * Dismiss the given security screen.
-     * @param securityVerified true if the user correctly entered credentials for the given screen.
-     */
-    void dismiss(boolean securityVerified);
-
-    /**
-     * Manually report user activity to keep the device awake. If timeout is 0,
-     * uses user-defined timeout.
-     * @param timeout
-     */
-    void userActivity(long timeout);
-
-    /**
-     * Checks if keyguard is in "verify credentials" mode.
-     * @return true if user has been asked to verify security.
-     */
-    boolean isVerifyUnlockOnly();
-
-    /**
-     * Call when user correctly enters their credentials
-     */
-    void reportSuccessfulUnlockAttempt();
-
-    /**
-     * Call when the user incorrectly enters their credentials
-     */
-    void reportFailedUnlockAttempt();
-
-    /**
-     * Gets the number of attempts thus far as reported by {@link #reportFailedUnlockAttempt()}
-     * @return number of failed attempts
-     */
-    int getFailedAttempts();
-
-    /**
-     * Shows the backup security for the current method.  If none available, this call is a no-op.
-     */
-    void showBackupSecurity();
-
-    /**
-     * Sets an action to perform after the user successfully enters their credentials.
-     * @param action
-     */
-    void setOnDismissAction(OnDismissAction action);
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
deleted file mode 100644
index 375a96a..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.internal.R;
-
-public class KeyguardSecurityContainer extends FrameLayout {
-    public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardSecurityContainer(Context context) {
-        this(null, null, 0);
-    }
-
-    public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    KeyguardSecurityViewFlipper getFlipper() {
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof KeyguardSecurityViewFlipper) {
-                return (KeyguardSecurityViewFlipper) child;
-            }
-        }
-        return null;
-    }
-
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewFlipper flipper = getFlipper();
-        if (flipper != null) {
-            flipper.showBouncer(duration);
-        }
-    }
-
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewFlipper flipper = getFlipper();
-        if (flipper != null) {
-            flipper.hideBouncer(duration);
-        }
-    }
-}
-
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
deleted file mode 100644
index 7a69586..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.widget.LockPatternUtils;
-
-public class KeyguardSecurityModel {
-    /**
-     * The different types of security available for {@link Mode#UnlockScreen}.
-     * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
-     */
-    enum SecurityMode {
-        Invalid, // NULL state
-        None, // No security enabled
-        Pattern, // Unlock by drawing a pattern.
-        Password, // Unlock by entering an alphanumeric password
-        PIN, // Strictly numeric password
-        Biometric, // Unlock with a biometric key (e.g. finger print or face unlock)
-        Account, // Unlock by entering an account's login and password.
-        SimPin, // Unlock by entering a sim pin.
-        SimPuk // Unlock by entering a sim puk
-    }
-
-    private Context mContext;
-    private LockPatternUtils mLockPatternUtils;
-
-    KeyguardSecurityModel(Context context) {
-        mContext = context;
-        mLockPatternUtils = new LockPatternUtils(context);
-    }
-
-    void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    /**
-     * Returns true if biometric unlock is installed and selected.  If this returns false there is
-     * no need to even construct the biometric unlock.
-     */
-    boolean isBiometricUnlockEnabled() {
-        return mLockPatternUtils.usingBiometricWeak()
-                && mLockPatternUtils.isBiometricWeakInstalled();
-    }
-
-    /**
-     * Returns true if a condition is currently suppressing the biometric unlock.  If this returns
-     * true there is no need to even construct the biometric unlock.
-     */
-    private boolean isBiometricUnlockSuppressed() {
-        KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final boolean backupIsTimedOut = monitor.getFailedUnlockAttempts() >=
-                LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
-        return monitor.getMaxBiometricUnlockAttemptsReached() || backupIsTimedOut
-                || !monitor.isAlternateUnlockEnabled()
-                || monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE;
-    }
-
-    SecurityMode getSecurityMode() {
-        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final IccCardConstants.State simState = updateMonitor.getSimState();
-        SecurityMode mode = SecurityMode.None;
-        if (simState == IccCardConstants.State.PIN_REQUIRED) {
-            mode = SecurityMode.SimPin;
-        } else if (simState == IccCardConstants.State.PUK_REQUIRED
-                && mLockPatternUtils.isPukUnlockScreenEnable()) {
-            mode = SecurityMode.SimPuk;
-        } else {
-            final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
-            switch (security) {
-                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
-                            SecurityMode.PIN : SecurityMode.None;
-                    break;
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
-                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
-                            SecurityMode.Password : SecurityMode.None;
-                    break;
-
-                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
-                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
-                    if (mLockPatternUtils.isLockPatternEnabled()) {
-                        mode = mLockPatternUtils.isPermanentlyLocked() ?
-                            SecurityMode.Account : SecurityMode.Pattern;
-                    }
-                    break;
-
-                default:
-                    throw new IllegalStateException("Unknown unlock mode:" + mode);
-            }
-        }
-        return mode;
-    }
-
-    /**
-     * Some unlock methods can have an alternate, such as biometric unlocks (e.g. face unlock).
-     * This function decides if an alternate unlock is available and returns it. Otherwise,
-     * returns @param mode.
-     *
-     * @param mode the mode we want the alternate for
-     * @return alternate or the given mode
-     */
-    SecurityMode getAlternateFor(SecurityMode mode) {
-        if (isBiometricUnlockEnabled() && !isBiometricUnlockSuppressed()
-                && (mode == SecurityMode.Password
-                        || mode == SecurityMode.PIN
-                        || mode == SecurityMode.Pattern)) {
-            return SecurityMode.Biometric;
-        }
-        return mode; // no alternate, return what was given
-    }
-
-    /**
-     * Some unlock methods can have a backup which gives the user another way to get into
-     * the device. This is currently only supported for Biometric and Pattern unlock.
-     *
-     * @return backup method or current security mode
-     */
-    SecurityMode getBackupSecurityMode(SecurityMode mode) {
-        switch(mode) {
-            case Biometric:
-                return getSecurityMode();
-            case Pattern:
-                return SecurityMode.Account;
-        }
-        return mode; // no backup, return current security mode
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityView.java
deleted file mode 100644
index a3ac39c..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityView.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.widget.LockPatternUtils;
-
-public interface KeyguardSecurityView {
-    static public final int SCREEN_ON = 1;
-    static public final int VIEW_REVEALED = 2;
-
-    /**
-     * Interface back to keyguard to tell it when security
-     * @param callback
-     */
-    void setKeyguardCallback(KeyguardSecurityCallback callback);
-
-    /**
-     * Set {@link LockPatternUtils} object. Useful for providing a mock interface.
-     * @param utils
-     */
-    void setLockPatternUtils(LockPatternUtils utils);
-
-    /**
-     * Reset the view and prepare to take input. This should do things like clearing the
-     * password or pattern and clear error messages.
-     */
-    void reset();
-
-    /**
-     * Emulate activity life cycle within the view. When called, the view should clean up
-     * and prepare to be removed.
-     */
-    void onPause();
-
-    /**
-     * Emulate activity life cycle within this view.  When called, the view should prepare itself
-     * to be shown.
-     * @param reason the root cause of the event.
-     */
-    void onResume(int reason);
-
-    /**
-     * Inquire whether this view requires IME (keyboard) interaction.
-     *
-     * @return true if IME interaction is required.
-     */
-    boolean needsInput();
-
-    /**
-     * Get {@link KeyguardSecurityCallback} for the given object
-     * @return KeyguardSecurityCallback
-     */
-    KeyguardSecurityCallback getCallback();
-
-    /**
-     * Instruct the view to show usability hints, if any.
-     *
-     */
-    void showUsabilityHint();
-
-    /**
-     * Place the security view into bouncer mode.
-     * Animate transisiton if duration is non-zero.
-     * @param duration millisends for the transisiton animation.
-     */
-    void showBouncer(int duration);
-
-    /**
-     * Place the security view into non-bouncer mode.
-     * Animate transisiton if duration is non-zero.
-     * @param duration millisends for the transisiton animation.
-     */
-    void hideBouncer(int duration);
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java
deleted file mode 100644
index aa31b00..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ViewFlipper;
-
-/**
- * Subclass of the current view flipper that allows us to overload dispatchTouchEvent() so
- * we can emulate {@link WindowManager.LayoutParams#FLAG_SLIPPERY} within a view hierarchy.
- *
- */
-public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView {
-    private static final String TAG = "KeyguardSecurityViewFlipper";
-    private static final boolean DEBUG = false;
-
-    private Rect mTempRect = new Rect();
-
-    public KeyguardSecurityViewFlipper(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardSecurityViewFlipper(Context context, AttributeSet attr) {
-        super(context, attr);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean result = super.onTouchEvent(ev);
-        mTempRect.set(0, 0, 0, 0);
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child.getVisibility() == View.VISIBLE) {
-                offsetRectIntoDescendantCoords(child, mTempRect);
-                ev.offsetLocation(mTempRect.left, mTempRect.top);
-                result = child.dispatchTouchEvent(ev) || result;
-                ev.offsetLocation(-mTempRect.left, -mTempRect.top);
-            }
-        }
-        return result;
-    }
-
-    KeyguardSecurityView getSecurityView() {
-        View child = getChildAt(getDisplayedChild());
-        if (child instanceof KeyguardSecurityView) {
-            return (KeyguardSecurityView) child;
-        }
-        return null;
-    }
-
-    @Override
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        KeyguardSecurityView ksv = getSecurityView();
-        if (ksv != null) {
-            ksv.setKeyguardCallback(callback);
-        }
-    }
-
-    @Override
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        KeyguardSecurityView ksv = getSecurityView();
-        if (ksv != null) {
-            ksv.setLockPatternUtils(utils);
-        }
-    }
-
-    @Override
-    public void reset() {
-        KeyguardSecurityView ksv = getSecurityView();
-        if (ksv != null) {
-            ksv.reset();
-        }
-    }
-
-    @Override
-    public void onPause() {
-        KeyguardSecurityView ksv = getSecurityView();
-        if (ksv != null) {
-            ksv.onPause();
-        }
-    }
-
-    @Override
-    public void onResume(int reason) {
-        KeyguardSecurityView ksv = getSecurityView();
-        if (ksv != null) {
-            ksv.onResume(reason);
-        }
-    }
-
-    @Override
-    public boolean needsInput() {
-        KeyguardSecurityView ksv = getSecurityView();
-        return (ksv != null) ? ksv.needsInput() : false;
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        KeyguardSecurityView ksv = getSecurityView();
-        return (ksv != null) ? ksv.getCallback() : null;
-    }
-
-    @Override
-    public void showUsabilityHint() {
-        KeyguardSecurityView ksv = getSecurityView();
-        if (ksv != null) {
-            ksv.showUsabilityHint();
-        }
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityView active = getSecurityView();
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof KeyguardSecurityView) {
-                KeyguardSecurityView ksv = (KeyguardSecurityView) child;
-                ksv.showBouncer(ksv == active ? duration : 0);
-            }
-        }
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityView active = getSecurityView();
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof KeyguardSecurityView) {
-                KeyguardSecurityView ksv = (KeyguardSecurityView) child;
-                ksv.hideBouncer(ksv == active ? duration : 0);
-            }
-        }
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : new LayoutParams(p);
-    }
-
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected void onMeasure(int widthSpec, int heightSpec) {
-        final int widthMode = MeasureSpec.getMode(widthSpec);
-        final int heightMode = MeasureSpec.getMode(heightSpec);
-        if (DEBUG && widthMode != MeasureSpec.AT_MOST) {
-            Log.w(TAG, "onMeasure: widthSpec " + MeasureSpec.toString(widthSpec) +
-                    " should be AT_MOST");
-        }
-        if (DEBUG && heightMode != MeasureSpec.AT_MOST) {
-            Log.w(TAG, "onMeasure: heightSpec " + MeasureSpec.toString(heightSpec) +
-                    " should be AT_MOST");
-        }
-
-        final int widthSize = MeasureSpec.getSize(widthSpec);
-        final int heightSize = MeasureSpec.getSize(heightSpec);
-        int maxWidth = widthSize;
-        int maxHeight = heightSize;
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.maxWidth > 0 && lp.maxWidth < maxWidth) {
-                maxWidth = lp.maxWidth;
-            }
-            if (lp.maxHeight > 0 && lp.maxHeight < maxHeight) {
-                maxHeight = lp.maxHeight;
-            }
-        }
-
-        final int wPadding = getPaddingLeft() + getPaddingRight();
-        final int hPadding = getPaddingTop() + getPaddingBottom();
-        maxWidth -= wPadding;
-        maxHeight -= hPadding;
-
-        int width = widthMode == MeasureSpec.EXACTLY ? widthSize : 0;
-        int height = heightMode == MeasureSpec.EXACTLY ? heightSize : 0;
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            final int childWidthSpec = makeChildMeasureSpec(maxWidth, lp.width);
-            final int childHeightSpec = makeChildMeasureSpec(maxHeight, lp.height);
-
-            child.measure(childWidthSpec, childHeightSpec);
-
-            width = Math.max(width, Math.min(child.getMeasuredWidth(), widthSize - wPadding));
-            height = Math.max(height, Math.min(child.getMeasuredHeight(), heightSize - hPadding));
-        }
-        setMeasuredDimension(width + wPadding, height + hPadding);
-    }
-
-    private int makeChildMeasureSpec(int maxSize, int childDimen) {
-        final int mode;
-        final int size;
-        switch (childDimen) {
-            case LayoutParams.WRAP_CONTENT:
-                mode = MeasureSpec.AT_MOST;
-                size = maxSize;
-                break;
-            case LayoutParams.MATCH_PARENT:
-                mode = MeasureSpec.EXACTLY;
-                size = maxSize;
-                break;
-            default:
-                mode = MeasureSpec.EXACTLY;
-                size = Math.min(maxSize, childDimen);
-                break;
-        }
-        return MeasureSpec.makeMeasureSpec(size, mode);
-    }
-
-    public static class LayoutParams extends FrameLayout.LayoutParams {
-        @ViewDebug.ExportedProperty(category = "layout")
-        public int maxWidth;
-
-        @ViewDebug.ExportedProperty(category = "layout")
-        public int maxHeight;
-
-        public LayoutParams(ViewGroup.LayoutParams other) {
-            super(other);
-        }
-
-        public LayoutParams(LayoutParams other) {
-            super(other);
-
-            maxWidth = other.maxWidth;
-            maxHeight = other.maxHeight;
-        }
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs,
-                    R.styleable.KeyguardSecurityViewFlipper_Layout, 0, 0);
-            maxWidth = a.getDimensionPixelSize(
-                    R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxWidth, 0);
-            maxHeight = a.getDimensionPixelSize(
-                    R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxHeight, 0);
-            a.recycle();
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewHelper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewHelper.java
deleted file mode 100644
index 3d59f8d..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewHelper.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.graphics.drawable.Drawable;
-import android.view.View;
-
-/**
- * Some common functions that are useful for KeyguardSecurityViews.
- */
-public class KeyguardSecurityViewHelper {
-
-    public static void showBouncer(SecurityMessageDisplay securityMessageDisplay,
-            final View ecaView, Drawable bouncerFrame, int duration) {
-        if (securityMessageDisplay != null) {
-            securityMessageDisplay.showBouncer(duration);
-        }
-        if (ecaView != null) {
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 0f);
-                anim.setDuration(duration);
-                anim.addListener(new AnimatorListenerAdapter() {
-                    private boolean mCanceled;
-                    @Override
-                    public void onAnimationCancel(Animator animation) {
-                        // Fail safe and show the emergency button in onAnimationEnd()
-                        mCanceled = true;
-                        ecaView.setAlpha(1f);
-                    }
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        ecaView.setVisibility(mCanceled ? View.VISIBLE : View.INVISIBLE);
-                    }
-                });
-                anim.start();
-            } else {
-                ecaView.setAlpha(0f);
-                ecaView.setVisibility(View.INVISIBLE);
-            }
-        }
-        if (bouncerFrame != null) {
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 0, 255);
-                anim.setDuration(duration);
-                anim.start();
-            } else {
-                bouncerFrame.setAlpha(255);
-            }
-        }
-    }
-
-    public static void hideBouncer(SecurityMessageDisplay securityMessageDisplay,
-            View ecaView, Drawable bouncerFrame, int duration) {
-        if (securityMessageDisplay != null) {
-            securityMessageDisplay.hideBouncer(duration);
-        }
-        if (ecaView != null) {
-            ecaView.setVisibility(View.VISIBLE);
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 1f);
-                anim.setDuration(duration);
-                anim.start();
-            } else {
-                ecaView.setAlpha(1f);
-            }
-        }
-        if (bouncerFrame != null) {
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 255, 0);
-                anim.setDuration(duration);
-                anim.start();
-            } else {
-                bouncerFrame.setAlpha(0);
-            }
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
deleted file mode 100644
index 6859042..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.ObjectAnimator;
-import android.app.SearchManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.multiwaveview.GlowPadView;
-import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
-import com.android.internal.R;
-
-public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView {
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
-    private static final String TAG = "SecuritySelectorView";
-    private static final String ASSIST_ICON_METADATA_NAME =
-        "com.android.systemui.action_assist_icon";
-
-    private KeyguardSecurityCallback mCallback;
-    private GlowPadView mGlowPadView;
-    private ObjectAnimator mAnim;
-    private View mFadeView;
-    private boolean mIsBouncing;
-    private boolean mCameraDisabled;
-    private boolean mSearchDisabled;
-    private LockPatternUtils mLockPatternUtils;
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-    private Drawable mBouncerFrame;
-
-    OnTriggerListener mOnTriggerListener = new OnTriggerListener() {
-
-        public void onTrigger(View v, int target) {
-            final int resId = mGlowPadView.getResourceIdForTarget(target);
-            switch (resId) {
-                case com.android.internal.R.drawable.ic_action_assist_generic:
-                    Intent assistIntent =
-                            ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                            .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-                    if (assistIntent != null) {
-                        mActivityLauncher.launchActivity(assistIntent, false, true, null, null);
-                    } else {
-                        Log.w(TAG, "Failed to get intent for assist activity");
-                    }
-                    mCallback.userActivity(0);
-                    break;
-
-                case com.android.internal.R.drawable.ic_lockscreen_camera:
-                    mActivityLauncher.launchCamera(null, null);
-                    mCallback.userActivity(0);
-                    break;
-
-                case com.android.internal.R.drawable.ic_lockscreen_unlock_phantom:
-                case com.android.internal.R.drawable.ic_lockscreen_unlock:
-                    mCallback.userActivity(0);
-                    mCallback.dismiss(false);
-                break;
-            }
-        }
-
-        public void onReleased(View v, int handle) {
-            if (!mIsBouncing) {
-                doTransition(mFadeView, 1.0f);
-            }
-        }
-
-        public void onGrabbed(View v, int handle) {
-            mCallback.userActivity(0);
-            doTransition(mFadeView, 0.0f);
-        }
-
-        public void onGrabbedStateChange(View v, int handle) {
-
-        }
-
-        public void onFinishFinalAnimation() {
-
-        }
-
-    };
-
-    KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
-
-        @Override
-        public void onDevicePolicyManagerStateChanged() {
-            updateTargets();
-        }
-
-        @Override
-        public void onSimStateChanged(State simState) {
-            updateTargets();
-        }
-    };
-
-    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
-
-        @Override
-        KeyguardSecurityCallback getCallback() {
-            return mCallback;
-        }
-
-        @Override
-        LockPatternUtils getLockPatternUtils() {
-            return mLockPatternUtils;
-        }
-
-        @Override
-        Context getContext() {
-            return mContext;
-        }};
-
-    public KeyguardSelectorView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardSelectorView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mLockPatternUtils = new LockPatternUtils(getContext());
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
-        mGlowPadView.setOnTriggerListener(mOnTriggerListener);
-        updateTargets();
-
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame);
-        mBouncerFrame = bouncerFrameView.getBackground();
-    }
-
-    public void setCarrierArea(View carrierArea) {
-        mFadeView = carrierArea;
-    }
-
-    public boolean isTargetPresent(int resId) {
-        return mGlowPadView.getTargetPosition(resId) != -1;
-    }
-
-    @Override
-    public void showUsabilityHint() {
-        mGlowPadView.ping();
-    }
-
-    private void updateTargets() {
-        int currentUserHandle = mLockPatternUtils.getCurrentUser();
-        DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
-        int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUserHandle);
-        boolean secureCameraDisabled = mLockPatternUtils.isSecure()
-                && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
-        boolean cameraDisabledByAdmin = dpm.getCameraDisabled(null, currentUserHandle)
-                || secureCameraDisabled;
-        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext());
-        boolean disabledBySimState = monitor.isSimLocked();
-        boolean cameraTargetPresent =
-            isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_camera);
-        boolean searchTargetPresent =
-            isTargetPresent(com.android.internal.R.drawable.ic_action_assist_generic);
-
-        if (cameraDisabledByAdmin) {
-            Log.v(TAG, "Camera disabled by Device Policy");
-        } else if (disabledBySimState) {
-            Log.v(TAG, "Camera disabled by Sim State");
-        }
-        boolean currentUserSetup = 0 != Settings.Secure.getIntForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE,
-                0 /*default */,
-                currentUserHandle);
-        boolean searchActionAvailable =
-                ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
-        mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent
-                || !currentUserSetup;
-        mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent
-                || !currentUserSetup;
-        updateResources();
-    }
-
-    public void updateResources() {
-        // Update the search icon with drawable from the search .apk
-        if (!mSearchDisabled) {
-            Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                    .getAssistIntent(mContext, false, UserHandle.USER_CURRENT);
-            if (intent != null) {
-                // XXX Hack. We need to substitute the icon here but haven't formalized
-                // the public API. The "_google" metadata will be going away, so
-                // DON'T USE IT!
-                ComponentName component = intent.getComponent();
-                boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component,
-                        ASSIST_ICON_METADATA_NAME + "_google",
-                        com.android.internal.R.drawable.ic_action_assist_generic);
-
-                if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component,
-                            ASSIST_ICON_METADATA_NAME,
-                            com.android.internal.R.drawable.ic_action_assist_generic)) {
-                        Slog.w(TAG, "Couldn't grab icon from package " + component);
-                }
-            }
-        }
-
-        mGlowPadView.setEnableTarget(com.android.internal.R.drawable
-                .ic_lockscreen_camera, !mCameraDisabled);
-        mGlowPadView.setEnableTarget(com.android.internal.R.drawable
-                .ic_action_assist_generic, !mSearchDisabled);
-    }
-
-    void doTransition(View view, float to) {
-        if (mAnim != null) {
-            mAnim.cancel();
-        }
-        mAnim = ObjectAnimator.ofFloat(view, "alpha", to);
-        mAnim.start();
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    @Override
-    public void reset() {
-        mGlowPadView.reset(false);
-    }
-
-    @Override
-    public boolean needsInput() {
-        return false;
-    }
-
-    @Override
-    public void onPause() {
-        KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mInfoCallback);
-    }
-
-    @Override
-    public void onResume(int reason) {
-        KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mInfoCallback);
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-        mIsBouncing = true;
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        mIsBouncing = false;
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
new file mode 100644
index 0000000..56a282b
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -0,0 +1,308 @@
+package com.android.internal.policy.impl.keyguard;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy.OnKeyguardExitResult;
+
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.widget.LockPatternUtils;
+
+/**
+ * A local class that keeps a cache of keyguard state that can be restored in the event
+ * keyguard crashes. It currently also allows runtime-selectable
+ * local or remote instances of keyguard.
+ */
+public class KeyguardServiceDelegate {
+    // TODO: propagate changes to these to {@link KeyguardTouchDelegate}
+    public static final String KEYGUARD_PACKAGE = "com.android.keyguard";
+    public static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+
+    private static final String TAG = "KeyguardServiceDelegate";
+    private static final boolean DEBUG = true;
+    protected KeyguardServiceWrapper mKeyguardService;
+    private View mScrim; // shown if keyguard crashes
+    private KeyguardState mKeyguardState = new KeyguardState();
+
+    /* package */ static final class KeyguardState {
+        boolean showing;
+        boolean showingAndNotHidden;
+        boolean inputRestricted;
+        boolean hidden;
+        boolean secure;
+        boolean dreaming;
+        boolean systemIsReady;
+        public boolean enabled;
+        public boolean dismissable;
+        public int offReason;
+        public int currentUser;
+        public boolean screenIsOn;
+    };
+
+    public interface ShowListener {
+        public void onShown(IBinder windowToken);
+    }
+
+    // A delegate class to map a particular invocation with a ShowListener object.
+    private final class KeyguardShowDelegate extends IKeyguardShowCallback.Stub {
+        private ShowListener mShowListener;
+
+        KeyguardShowDelegate(ShowListener showListener) {
+            mShowListener = showListener;
+        }
+
+        @Override
+        public void onShown(IBinder windowToken) throws RemoteException {
+            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
+            if (mShowListener != null) {
+                mShowListener.onShown(windowToken);
+            }
+            hideScrim();
+        }
+    };
+
+    // A delegate class to map a particular invocation with an OnKeyguardExitResult object.
+    private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub {
+        private OnKeyguardExitResult mOnKeyguardExitResult;
+
+        KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) {
+            mOnKeyguardExitResult = onKeyguardExitResult;
+        }
+
+        @Override
+        public void onKeyguardExitResult(boolean success) throws RemoteException {
+            if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****");
+            if (mOnKeyguardExitResult != null) {
+                mOnKeyguardExitResult.onKeyguardExitResult(success);
+            }
+        }
+    };
+
+    public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
+        Intent intent = new Intent();
+        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+        mScrim = createScrim(context);
+        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
+                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+            if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+        } else {
+            if (DEBUG) Log.v(TAG, "*** Keyguard started");
+        }
+    }
+
+    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
+            mKeyguardService = new KeyguardServiceWrapper(
+                    IKeyguardService.Stub.asInterface(service));
+            if (mKeyguardState.systemIsReady) {
+                // If the system is ready, it means keyguard crashed and restarted.
+                mKeyguardService.onSystemReady();
+                // This is used to hide the scrim once keyguard displays.
+                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null));
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
+            mKeyguardService = null;
+        }
+
+    };
+
+    public boolean isShowing() {
+        if (mKeyguardService != null) {
+            mKeyguardState.showing = mKeyguardService.isShowing();
+        }
+        return mKeyguardState.showing;
+    }
+
+    public boolean isShowingAndNotHidden() {
+        if (mKeyguardService != null) {
+            mKeyguardState.showingAndNotHidden = mKeyguardService.isShowingAndNotHidden();
+        }
+        return mKeyguardState.showingAndNotHidden;
+    }
+
+    public boolean isInputRestricted() {
+        if (mKeyguardService != null) {
+            mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
+        }
+        return mKeyguardState.inputRestricted;
+    }
+
+    public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) {
+        if (mKeyguardService != null) {
+            mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult));
+        }
+    }
+
+    public void keyguardDone(boolean authenticated, boolean wakeup) {
+        if (mKeyguardService != null) {
+            mKeyguardService.keyguardDone(authenticated, wakeup);
+        }
+    }
+
+    public void setHidden(boolean isHidden) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setHidden(isHidden);
+        }
+        mKeyguardState.hidden = isHidden;
+    }
+
+    public void dismiss() {
+        if (mKeyguardService != null) {
+            mKeyguardService.dismiss();
+        }
+    }
+
+    public boolean isSecure() {
+        if (mKeyguardService != null) {
+            mKeyguardState.secure = mKeyguardService.isSecure();
+        }
+        return mKeyguardState.secure;
+    }
+
+    public void onDreamingStarted() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onDreamingStarted();
+        }
+        mKeyguardState.dreaming = true;
+    }
+
+    public void onDreamingStopped() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onDreamingStopped();
+        }
+        mKeyguardState.dreaming = false;
+    }
+
+    public void onScreenTurnedOn(final ShowListener showListener) {
+        if (mKeyguardService != null) {
+            if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + showListener + ")");
+            mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(showListener));
+        } else {
+            // try again when we establish a connection
+            Slog.w(TAG, "onScreenTurnedOn(): no keyguard service!");
+            // This shouldn't happen, but if it does, invoke the listener immediately
+            // to avoid a dark screen...
+            showListener.onShown(null);
+        }
+        mKeyguardState.screenIsOn = true;
+    }
+
+    public void onScreenTurnedOff(int why) {
+        if (mKeyguardService != null) {
+            mKeyguardService.onScreenTurnedOff(why);
+        }
+        mKeyguardState.offReason = why;
+        mKeyguardState.screenIsOn = false;
+    }
+
+    public void setKeyguardEnabled(boolean enabled) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setKeyguardEnabled(enabled);
+        }
+        mKeyguardState.enabled = enabled;
+    }
+
+    public boolean isDismissable() {
+        if (mKeyguardService != null) {
+            mKeyguardState.dismissable = mKeyguardService.isDismissable();
+        }
+        return mKeyguardState.dismissable;
+    }
+
+    public void onSystemReady() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onSystemReady();
+        } else {
+            if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready");
+            mKeyguardState.systemIsReady = true;
+        }
+    }
+
+    public void doKeyguardTimeout(Bundle options) {
+        if (mKeyguardService != null) {
+            mKeyguardService.doKeyguardTimeout(options);
+        }
+    }
+
+    public void showAssistant() {
+        if (mKeyguardService != null) {
+            mKeyguardService.showAssistant();
+        }
+    }
+
+    public void setCurrentUser(int newUserId) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setCurrentUser(newUserId);
+        }
+        mKeyguardState.currentUser = newUserId;
+    }
+
+    private static final View createScrim(Context context) {
+        View view = new View(context);
+
+        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
+                ;
+
+        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
+        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        lp.setTitle("KeyguardScrim");
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        wm.addView(view, lp);
+        view.setVisibility(View.GONE);
+        // Disable pretty much everything in statusbar until keyguard comes back and we know
+        // the state of the world.
+        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
+                | View.STATUS_BAR_DISABLE_BACK
+                | View.STATUS_BAR_DISABLE_RECENT
+                | View.STATUS_BAR_DISABLE_EXPAND
+                | View.STATUS_BAR_DISABLE_SEARCH);
+        return view;
+    }
+
+    public void showScrim() {
+        mScrim.post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.setVisibility(View.VISIBLE);
+            }
+        });
+    }
+
+    public void hideScrim() {
+        mScrim.post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.setVisibility(View.GONE);
+            }
+        });
+    }
+
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
new file mode 100644
index 0000000..83be1a8
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl.keyguard;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.MotionEvent;
+
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardService;
+
+/**
+ * A wrapper class for KeyguardService.  It implements IKeyguardService to ensure the interface
+ * remains consistent.
+ *
+ */
+public class KeyguardServiceWrapper implements IKeyguardService {
+    private IKeyguardService mService;
+    private String TAG = "KeyguardServiceWrapper";
+
+    public KeyguardServiceWrapper(IKeyguardService service) {
+        mService = service;
+    }
+
+    public boolean isShowing() {
+        try {
+            return mService.isShowing();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+        return false;
+    }
+
+    public boolean isSecure() {
+        try {
+            return mService.isSecure();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+        return false; // TODO cache state
+    }
+
+    public boolean isShowingAndNotHidden() {
+        try {
+            return mService.isShowingAndNotHidden();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+        return false; // TODO cache state
+    }
+
+    public boolean isInputRestricted() {
+        try {
+            return mService.isInputRestricted();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+        return false; // TODO cache state
+    }
+
+    public boolean isDismissable() {
+        try {
+            return mService.isDismissable();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+        return true; // TODO cache state
+    }
+
+    public void verifyUnlock(IKeyguardExitCallback callback) {
+        try {
+            mService.verifyUnlock(callback);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void keyguardDone(boolean authenticated, boolean wakeup) {
+        try {
+            mService.keyguardDone(authenticated, wakeup);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void setHidden(boolean isHidden) {
+        try {
+            mService.setHidden(isHidden);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void dismiss() {
+        try {
+            mService.dismiss();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void onDreamingStarted() {
+        try {
+            mService.onDreamingStarted();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void onDreamingStopped() {
+        try {
+            mService.onDreamingStopped();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void onScreenTurnedOff(int reason) {
+        try {
+            mService.onScreenTurnedOff(reason);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void onScreenTurnedOn(IKeyguardShowCallback result) {
+        try {
+            mService.onScreenTurnedOn(result);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void setKeyguardEnabled(boolean enabled) {
+        try {
+            mService.setKeyguardEnabled(enabled);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void onSystemReady() {
+        try {
+            mService.onSystemReady();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void doKeyguardTimeout(Bundle options) {
+        try {
+            mService.doKeyguardTimeout(options);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void setCurrentUser(int userId) {
+        try {
+            mService.setCurrentUser(userId);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    public void showAssistant() {
+        // Not used by PhoneWindowManager
+    }
+
+    public void dispatch(MotionEvent event) {
+        // Not used by PhoneWindowManager.  See code in {@link NavigationBarView}
+    }
+
+    public void launchCamera() {
+        // Not used by PhoneWindowManager.  See code in {@link NavigationBarView}
+    }
+
+    @Override
+    public IBinder asBinder() {
+        return mService.asBinder();
+    }
+
+}
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
deleted file mode 100644
index ab364ee..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.telephony.ITelephony;
-
-import android.content.Context;
-import android.app.Activity;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextWatcher;
-import android.text.method.DigitsKeyListener;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.internal.R;
-
-/**
- * Displays a PIN pad for unlocking.
- */
-public class KeyguardSimPinView extends KeyguardAbsKeyInputView
-        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
-
-    private ProgressDialog mSimUnlockProgressDialog = null;
-    private volatile boolean mSimCheckInProgress;
-
-    public KeyguardSimPinView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardSimPinView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void resetState() {
-        mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
-        mPasswordEntry.setEnabled(true);
-    }
-
-    @Override
-    protected int getPasswordTextViewId() {
-        return R.id.pinEntry;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        final View ok = findViewById(R.id.key_enter);
-        if (ok != null) {
-            ok.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    doHapticKeyClick();
-                    verifyPasswordAndUnlock();
-                }
-            });
-        }
-
-        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
-        // not a separate view
-        View pinDelete = findViewById(R.id.delete_button);
-        if (pinDelete != null) {
-            pinDelete.setVisibility(View.VISIBLE);
-            pinDelete.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    CharSequence str = mPasswordEntry.getText();
-                    if (str.length() > 0) {
-                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
-                    }
-                    doHapticKeyClick();
-                }
-            });
-            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
-                public boolean onLongClick(View v) {
-                    mPasswordEntry.setText("");
-                    doHapticKeyClick();
-                    return true;
-                }
-            });
-        }
-
-        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
-        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
-                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-
-        mPasswordEntry.requestFocus();
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public void onPause() {
-        // dismiss the dialog.
-        if (mSimUnlockProgressDialog != null) {
-            mSimUnlockProgressDialog.dismiss();
-            mSimUnlockProgressDialog = null;
-        }
-    }
-
-    /**
-     * Since the IPC can block, we want to run the request in a separate thread
-     * with a callback.
-     */
-    private abstract class CheckSimPin extends Thread {
-        private final String mPin;
-
-        protected CheckSimPin(String pin) {
-            mPin = pin;
-        }
-
-        abstract void onSimCheckResponse(boolean success);
-
-        @Override
-        public void run() {
-            try {
-                final boolean result = ITelephony.Stub.asInterface(ServiceManager
-                        .checkService("phone")).supplyPin(mPin);
-                post(new Runnable() {
-                    public void run() {
-                        onSimCheckResponse(result);
-                    }
-                });
-            } catch (RemoteException e) {
-                post(new Runnable() {
-                    public void run() {
-                        onSimCheckResponse(false);
-                    }
-                });
-            }
-        }
-    }
-
-    private Dialog getSimUnlockProgressDialog() {
-        if (mSimUnlockProgressDialog == null) {
-            mSimUnlockProgressDialog = new ProgressDialog(mContext);
-            mSimUnlockProgressDialog.setMessage(
-                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
-            mSimUnlockProgressDialog.setIndeterminate(true);
-            mSimUnlockProgressDialog.setCancelable(false);
-            if (!(mContext instanceof Activity)) {
-                mSimUnlockProgressDialog.getWindow().setType(
-                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            }
-        }
-        return mSimUnlockProgressDialog;
-    }
-
-    @Override
-    protected void verifyPasswordAndUnlock() {
-        String entry = mPasswordEntry.getText().toString();
-        
-        if (entry.length() < 4) {
-            // otherwise, display a message to the user, and don't submit.
-            mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true);
-            mPasswordEntry.setText("");
-            mCallback.userActivity(0);
-            return;
-        }
-
-        getSimUnlockProgressDialog().show();
-
-        if (!mSimCheckInProgress) {
-            mSimCheckInProgress = true; // there should be only one
-            new CheckSimPin(mPasswordEntry.getText().toString()) {
-                void onSimCheckResponse(final boolean success) {
-                    post(new Runnable() {
-                        public void run() {
-                            if (mSimUnlockProgressDialog != null) {
-                                mSimUnlockProgressDialog.hide();
-                            }
-                            if (success) {
-                                // before closing the keyguard, report back that the sim is unlocked
-                                // so it knows right away.
-                                KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
-                                mCallback.dismiss(true);
-                            } else {
-                                mSecurityMessageDisplay.setMessage
-                                    (R.string.kg_password_wrong_pin_code, true);
-                                mPasswordEntry.setText("");
-                            }
-                            mCallback.userActivity(0);
-                            mSimCheckInProgress = false;
-                        }
-                    });
-                }
-            }.start();
-        }
-    }
-}
-
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
deleted file mode 100644
index e5b4b73..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextWatcher;
-import android.text.method.DigitsKeyListener;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.internal.telephony.ITelephony;
-
-import com.android.internal.R;
-
-/**
- * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
- */
-public class KeyguardSimPukView extends KeyguardAbsKeyInputView
-        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
-
-    private ProgressDialog mSimUnlockProgressDialog = null;
-    private volatile boolean mCheckInProgress;
-    private String mPukText;
-    private String mPinText;
-    private StateMachine mStateMachine = new StateMachine();
-
-    private class StateMachine {
-        final int ENTER_PUK = 0;
-        final int ENTER_PIN = 1;
-        final int CONFIRM_PIN = 2;
-        final int DONE = 3;
-        private int state = ENTER_PUK;
-
-        public void next() {
-            int msg = 0;
-            if (state == ENTER_PUK) {
-                if (checkPuk()) {
-                    state = ENTER_PIN;
-                    msg = R.string.kg_puk_enter_pin_hint;
-                } else {
-                    msg = R.string.kg_invalid_sim_puk_hint;
-                }
-            } else if (state == ENTER_PIN) {
-                if (checkPin()) {
-                    state = CONFIRM_PIN;
-                    msg = R.string.kg_enter_confirm_pin_hint;
-                } else {
-                    msg = R.string.kg_invalid_sim_pin_hint;
-                }
-            } else if (state == CONFIRM_PIN) {
-                if (confirmPin()) {
-                    state = DONE;
-                    msg =
-                        com.android.internal.R.string.lockscreen_sim_unlock_progress_dialog_message;
-                    updateSim();
-                } else {
-                    state = ENTER_PIN; // try again?
-                    msg = R.string.kg_invalid_confirm_pin_hint;
-                }
-            }
-            mPasswordEntry.setText(null);
-            if (msg != 0) {
-                mSecurityMessageDisplay.setMessage(msg, true);
-            }
-        }
-
-        void reset() {
-            mPinText="";
-            mPukText="";
-            state = ENTER_PUK;
-            mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true);
-            mPasswordEntry.requestFocus();
-        }
-    }
-
-    public KeyguardSimPukView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardSimPukView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void resetState() {
-        mStateMachine.reset();
-        mPasswordEntry.setEnabled(true);
-    }
-
-    @Override
-    protected int getPasswordTextViewId() {
-        return R.id.pinEntry;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        final View ok = findViewById(R.id.key_enter);
-        if (ok != null) {
-            ok.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    doHapticKeyClick();
-                    verifyPasswordAndUnlock();
-                }
-            });
-        }
-
-        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
-        // not a separate view
-        View pinDelete = findViewById(R.id.delete_button);
-        if (pinDelete != null) {
-            pinDelete.setVisibility(View.VISIBLE);
-            pinDelete.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    CharSequence str = mPasswordEntry.getText();
-                    if (str.length() > 0) {
-                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
-                    }
-                    doHapticKeyClick();
-                }
-            });
-            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
-                public boolean onLongClick(View v) {
-                    mPasswordEntry.setText("");
-                    doHapticKeyClick();
-                    return true;
-                }
-            });
-        }
-
-        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
-        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
-                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-
-        mPasswordEntry.requestFocus();
-
-        mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public void onPause() {
-        // dismiss the dialog.
-        if (mSimUnlockProgressDialog != null) {
-            mSimUnlockProgressDialog.dismiss();
-            mSimUnlockProgressDialog = null;
-        }
-    }
-
-    /**
-     * Since the IPC can block, we want to run the request in a separate thread
-     * with a callback.
-     */
-    private abstract class CheckSimPuk extends Thread {
-
-        private final String mPin, mPuk;
-
-        protected CheckSimPuk(String puk, String pin) {
-            mPuk = puk;
-            mPin = pin;
-        }
-
-        abstract void onSimLockChangedResponse(boolean success);
-
-        @Override
-        public void run() {
-            try {
-                final boolean result = ITelephony.Stub.asInterface(ServiceManager
-                        .checkService("phone")).supplyPuk(mPuk, mPin);
-
-                post(new Runnable() {
-                    public void run() {
-                        onSimLockChangedResponse(result);
-                    }
-                });
-            } catch (RemoteException e) {
-                post(new Runnable() {
-                    public void run() {
-                        onSimLockChangedResponse(false);
-                    }
-                });
-            }
-        }
-    }
-
-    private Dialog getSimUnlockProgressDialog() {
-        if (mSimUnlockProgressDialog == null) {
-            mSimUnlockProgressDialog = new ProgressDialog(mContext);
-            mSimUnlockProgressDialog.setMessage(
-                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
-            mSimUnlockProgressDialog.setIndeterminate(true);
-            mSimUnlockProgressDialog.setCancelable(false);
-            if (!(mContext instanceof Activity)) {
-                mSimUnlockProgressDialog.getWindow().setType(
-                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            }
-        }
-        return mSimUnlockProgressDialog;
-    }
-
-    private boolean checkPuk() {
-        // make sure the puk is at least 8 digits long.
-        if (mPasswordEntry.getText().length() >= 8) {
-            mPukText = mPasswordEntry.getText().toString();
-            return true;
-        }
-        return false;
-    }
-
-    private boolean checkPin() {
-        // make sure the PIN is between 4 and 8 digits
-        int length = mPasswordEntry.getText().length();
-        if (length >= 4 && length <= 8) {
-            mPinText = mPasswordEntry.getText().toString();
-            return true;
-        }
-        return false;
-    }
-
-    public boolean confirmPin() {
-        return mPinText.equals(mPasswordEntry.getText().toString());
-    }
-
-    private void updateSim() {
-        getSimUnlockProgressDialog().show();
-
-        if (!mCheckInProgress) {
-            mCheckInProgress = true;
-            new CheckSimPuk(mPukText, mPinText) {
-                void onSimLockChangedResponse(final boolean success) {
-                    post(new Runnable() {
-                        public void run() {
-                            if (mSimUnlockProgressDialog != null) {
-                                mSimUnlockProgressDialog.hide();
-                            }
-                            if (success) {
-                                mCallback.dismiss(true);
-                            } else {
-                                mStateMachine.reset();
-                                mSecurityMessageDisplay.setMessage(R.string.kg_invalid_puk, true);
-                            }
-                            mCheckInProgress = false;
-                        }
-                    });
-                }
-            }.start();
-        }
-    }
-
-    @Override
-    protected void verifyPasswordAndUnlock() {
-        mStateMachine.next();
-    }
-}
-
-
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java
deleted file mode 100644
index d938cec..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Typeface;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.View;
-import android.widget.GridLayout;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-import libcore.icu.ICU;
-
-public class KeyguardStatusView extends GridLayout {
-    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
-    private static final String TAG = "KeyguardStatusView";
-
-    public static final int LOCK_ICON = 0; // R.drawable.ic_lock_idle_lock;
-    public static final int ALARM_ICON = com.android.internal.R.drawable.ic_lock_idle_alarm;
-    public static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging;
-    public static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
-
-    private SimpleDateFormat mDateFormat;
-    private LockPatternUtils mLockPatternUtils;
-
-    private TextView mDateView;
-    private TextView mAlarmStatusView;
-    private ClockView mClockView;
-
-    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
-
-        @Override
-        public void onTimeChanged() {
-            refresh();
-        }
-
-        @Override
-        void onKeyguardVisibilityChanged(boolean showing) {
-            if (showing) {
-                if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
-                refresh();
-            }
-        };
-    };
-
-    public KeyguardStatusView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardStatusView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        Resources res = getContext().getResources();
-        final Locale locale = Locale.getDefault();
-        final String datePattern =
-                res.getString(com.android.internal.R.string.system_ui_date_pattern);
-        final String bestFormat = ICU.getBestDateTimePattern(datePattern, locale.toString());
-        mDateFormat = new SimpleDateFormat(bestFormat, locale);
-        mDateView = (TextView) findViewById(R.id.date);
-        mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
-        mClockView = (ClockView) findViewById(R.id.clock_view);
-        mLockPatternUtils = new LockPatternUtils(getContext());
-
-        // Use custom font in mDateView
-        mDateView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
-
-        // Required to get Marquee to work.
-        final View marqueeViews[] = { mDateView, mAlarmStatusView };
-        for (int i = 0; i < marqueeViews.length; i++) {
-            View v = marqueeViews[i];
-            if (v == null) {
-                throw new RuntimeException("Can't find widget at index " + i);
-            }
-            v.setSelected(true);
-        }
-        refresh();
-    }
-
-    protected void refresh() {
-        mClockView.updateTime();
-        refreshDate();
-        refreshAlarmStatus(); // might as well
-    }
-
-    void refreshAlarmStatus() {
-        // Update Alarm status
-        String nextAlarm = mLockPatternUtils.getNextAlarm();
-        if (!TextUtils.isEmpty(nextAlarm)) {
-            maybeSetUpperCaseText(mAlarmStatusView, nextAlarm);
-            mAlarmStatusView.setCompoundDrawablesWithIntrinsicBounds(ALARM_ICON, 0, 0, 0);
-            mAlarmStatusView.setVisibility(View.VISIBLE);
-        } else {
-            mAlarmStatusView.setVisibility(View.GONE);
-        }
-    }
-
-    void refreshDate() {
-        maybeSetUpperCaseText(mDateView, mDateFormat.format(new Date()));
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
-    }
-
-    public int getAppWidgetId() {
-        return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET;
-    }
-
-    private void maybeSetUpperCaseText(TextView textView, CharSequence text) {
-        if (KeyguardViewManager.USE_UPPER_CASE) {
-            textView.setText(text != null ? text.toString().toUpperCase() : null);
-        } else {
-            textView.setText(text);
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
deleted file mode 100644
index 5e3b7da..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.media.AudioManager;
-import android.media.IRemoteControlDisplay;
-import android.media.MediaMetadataRetriever;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.text.style.ForegroundColorSpan;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.R;
-
-import java.lang.ref.WeakReference;
-/**
- * This is the widget responsible for showing music controls in keyguard.
- */
-public class KeyguardTransportControlView extends FrameLayout implements OnClickListener {
-
-    private static final int MSG_UPDATE_STATE = 100;
-    private static final int MSG_SET_METADATA = 101;
-    private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
-    private static final int MSG_SET_ARTWORK = 103;
-    private static final int MSG_SET_GENERATION_ID = 104;
-    private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
-    protected static final boolean DEBUG = false;
-    protected static final String TAG = "TransportControlView";
-
-    private ImageView mAlbumArt;
-    private TextView mTrackTitle;
-    private ImageView mBtnPrev;
-    private ImageView mBtnPlay;
-    private ImageView mBtnNext;
-    private int mClientGeneration;
-    private Metadata mMetadata = new Metadata();
-    private boolean mAttached;
-    private PendingIntent mClientIntent;
-    private int mTransportControlFlags;
-    private int mCurrentPlayState;
-    private AudioManager mAudioManager;
-    private IRemoteControlDisplayWeak mIRCD;
-
-    /**
-     * The metadata which should be populated into the view once we've been attached
-     */
-    private Bundle mPopulateMetadataWhenAttached = null;
-
-    // This handler is required to ensure messages from IRCD are handled in sequence and on
-    // the UI thread.
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case MSG_UPDATE_STATE:
-                if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2);
-                break;
-
-            case MSG_SET_METADATA:
-                if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj);
-                break;
-
-            case MSG_SET_TRANSPORT_CONTROLS:
-                if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2);
-                break;
-
-            case MSG_SET_ARTWORK:
-                if (mClientGeneration == msg.arg1) {
-                    if (mMetadata.bitmap != null) {
-                        mMetadata.bitmap.recycle();
-                    }
-                    mMetadata.bitmap = (Bitmap) msg.obj;
-                    mAlbumArt.setImageBitmap(mMetadata.bitmap);
-                }
-                break;
-
-            case MSG_SET_GENERATION_ID:
-                if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
-                mClientGeneration = msg.arg1;
-                mClientIntent = (PendingIntent) msg.obj;
-                break;
-
-            }
-        }
-    };
-
-    /**
-     * This class is required to have weak linkage to the current TransportControlView
-     * because the remote process can hold a strong reference to this binder object and
-     * we can't predict when it will be GC'd in the remote process. Without this code, it
-     * would allow a heavyweight object to be held on this side of the binder when there's
-     * no requirement to run a GC on the other side.
-     */
-    private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub {
-        private WeakReference<Handler> mLocalHandler;
-
-        IRemoteControlDisplayWeak(Handler handler) {
-            mLocalHandler = new WeakReference<Handler>(handler);
-        }
-
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
-                long currentPosMs, float speed) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
-            }
-        }
-
-        public void setMetadata(int generationId, Bundle metadata) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
-            }
-        }
-
-        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
-                        .sendToTarget();
-            }
-        }
-
-        public void setArtwork(int generationId, Bitmap bitmap) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
-            }
-        }
-
-        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
-                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
-            }
-        }
-
-        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
-                boolean clearing) throws RemoteException {
-            Handler handler = mLocalHandler.get();
-            if (handler != null) {
-                handler.obtainMessage(MSG_SET_GENERATION_ID,
-                    clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
-            }
-        }
-    };
-
-    public KeyguardTransportControlView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        if (DEBUG) Log.v(TAG, "Create TCV " + this);
-        mAudioManager = new AudioManager(mContext);
-        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
-        mIRCD = new IRemoteControlDisplayWeak(mHandler);
-    }
-
-    private void updateTransportControls(int transportControlFlags) {
-        mTransportControlFlags = transportControlFlags;
-    }
-
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-        mTrackTitle = (TextView) findViewById(R.id.title);
-        mTrackTitle.setSelected(true); // enable marquee
-        mAlbumArt = (ImageView) findViewById(R.id.albumart);
-        mBtnPrev = (ImageView) findViewById(R.id.btn_prev);
-        mBtnPlay = (ImageView) findViewById(R.id.btn_play);
-        mBtnNext = (ImageView) findViewById(R.id.btn_next);
-        final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext };
-        for (View view : buttons) {
-            view.setOnClickListener(this);
-        }
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (DEBUG) Log.v(TAG, "onAttachToWindow()");
-        if (mPopulateMetadataWhenAttached != null) {
-            updateMetadata(mPopulateMetadataWhenAttached);
-            mPopulateMetadataWhenAttached = null;
-        }
-        if (!mAttached) {
-            if (DEBUG) Log.v(TAG, "Registering TCV " + this);
-            mAudioManager.registerRemoteControlDisplay(mIRCD);
-        }
-        mAttached = true;
-    }
-
-    @Override
-    protected void onSizeChanged (int w, int h, int oldw, int oldh) {
-        if (mAttached) {
-            int dim = Math.min(512, Math.max(w, h));
-            if (DEBUG) Log.v(TAG, "TCV uses bitmap size=" + dim);
-            mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
-        }
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        if (DEBUG) Log.v(TAG, "onDetachFromWindow()");
-        super.onDetachedFromWindow();
-        if (mAttached) {
-            if (DEBUG) Log.v(TAG, "Unregistering TCV " + this);
-            mAudioManager.unregisterRemoteControlDisplay(mIRCD);
-        }
-        mAttached = false;
-    }
-
-    class Metadata {
-        private String artist;
-        private String trackTitle;
-        private String albumTitle;
-        private Bitmap bitmap;
-
-        public String toString() {
-            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]";
-        }
-    }
-
-    private String getMdString(Bundle data, int id) {
-        return data.getString(Integer.toString(id));
-    }
-
-    private void updateMetadata(Bundle data) {
-        if (mAttached) {
-            mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
-            mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE);
-            mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM);
-            populateMetadata();
-        } else {
-            mPopulateMetadataWhenAttached = data;
-        }
-    }
-
-    /**
-     * Populates the given metadata into the view
-     */
-    private void populateMetadata() {
-        StringBuilder sb = new StringBuilder();
-        int trackTitleLength = 0;
-        if (!TextUtils.isEmpty(mMetadata.trackTitle)) {
-            sb.append(mMetadata.trackTitle);
-            trackTitleLength = mMetadata.trackTitle.length();
-        }
-        if (!TextUtils.isEmpty(mMetadata.artist)) {
-            if (sb.length() != 0) {
-                sb.append(" - ");
-            }
-            sb.append(mMetadata.artist);
-        }
-        if (!TextUtils.isEmpty(mMetadata.albumTitle)) {
-            if (sb.length() != 0) {
-                sb.append(" - ");
-            }
-            sb.append(mMetadata.albumTitle);
-        }
-        mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE);
-        Spannable str = (Spannable) mTrackTitle.getText();
-        if (trackTitleLength != 0) {
-            str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength,
-                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            trackTitleLength++;
-        }
-        if (sb.length() > trackTitleLength) {
-            str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(),
-                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-        }
-
-        mAlbumArt.setImageBitmap(mMetadata.bitmap);
-        final int flags = mTransportControlFlags;
-        setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
-        setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
-        setVisibilityBasedOnFlag(mBtnPlay, flags,
-                RemoteControlClient.FLAG_KEY_MEDIA_PLAY
-                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
-                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
-                | RemoteControlClient.FLAG_KEY_MEDIA_STOP);
-
-        updatePlayPauseState(mCurrentPlayState);
-    }
-
-    private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
-        if ((flags & flag) != 0) {
-            view.setVisibility(View.VISIBLE);
-        } else {
-            view.setVisibility(View.GONE);
-        }
-    }
-
-    private void updatePlayPauseState(int state) {
-        if (DEBUG) Log.v(TAG,
-                "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
-        if (state == mCurrentPlayState) {
-            return;
-        }
-        final int imageResId;
-        final int imageDescId;
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                imageResId = com.android.internal.R.drawable.stat_sys_warning;
-                // TODO use more specific image description string for warning, but here the "play"
-                //      message is still valid because this button triggers a play command.
-                imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-                imageResId = com.android.internal.R.drawable.ic_media_pause;
-                imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                imageResId = com.android.internal.R.drawable.ic_media_stop;
-                imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            default:
-                imageResId = com.android.internal.R.drawable.ic_media_play;
-                imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
-                break;
-        }
-        mBtnPlay.setImageResource(imageResId);
-        mBtnPlay.setContentDescription(getResources().getString(imageDescId));
-        mCurrentPlayState = state;
-    }
-
-    static class SavedState extends BaseSavedState {
-        boolean clientPresent;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            this.clientPresent = in.readInt() != 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(this.clientPresent ? 1 : 0);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    public void onClick(View v) {
-        int keyCode = -1;
-        if (v == mBtnPrev) {
-            keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
-        } else if (v == mBtnNext) {
-            keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
-        } else if (v == mBtnPlay) {
-            keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
-
-        }
-        if (keyCode != -1) {
-            sendMediaButtonClick(keyCode);
-        }
-    }
-
-    private void sendMediaButtonClick(int keyCode) {
-        if (mClientIntent == null) {
-            // Shouldn't be possible because this view should be hidden in this case.
-            Log.e(TAG, "sendMediaButtonClick(): No client is currently registered");
-            return;
-        }
-        // use the registered PendingIntent that will be processed by the registered
-        //    media button event receiver, which is the component of mClientIntent
-        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
-        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        try {
-            mClientIntent.send(getContext(), 0, intent);
-        } catch (CanceledException e) {
-            Log.e(TAG, "Error sending intent for media button down: "+e);
-            e.printStackTrace();
-        }
-
-        keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
-        intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        try {
-            mClientIntent.send(getContext(), 0, intent);
-        } catch (CanceledException e) {
-            Log.e(TAG, "Error sending intent for media button up: "+e);
-            e.printStackTrace();
-        }
-    }
-
-    public boolean providesClock() {
-        return false;
-    }
-
-    private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                // actively playing or about to play
-                return true;
-            case RemoteControlClient.PLAYSTATE_NONE:
-                return false;
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                // we have stopped playing, check how long ago
-                if (DEBUG) {
-                    if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
-                        Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
-                    } else {
-                        Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
-                    }
-                }
-                return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
-            default:
-                Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
-                return false;
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
deleted file mode 100644
index 5a64586..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ /dev/null
@@ -1,983 +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 com.android.internal.policy.impl.keyguard;
-
-import android.app.ActivityManagerNative;
-import android.app.IUserSwitchObserver;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.graphics.Bitmap;
-
-import static android.os.BatteryManager.BATTERY_STATUS_FULL;
-import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
-import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
-import static android.os.BatteryManager.EXTRA_STATUS;
-import static android.os.BatteryManager.EXTRA_PLUGGED;
-import static android.os.BatteryManager.EXTRA_LEVEL;
-import static android.os.BatteryManager.EXTRA_HEALTH;
-import android.media.AudioManager;
-import android.media.IRemoteControlDisplay;
-import android.os.BatteryManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IRemoteCallback;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.TelephonyIntents;
-
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import com.android.internal.R;
-import com.google.android.collect.Lists;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * Watches for updates that may be interesting to the keyguard, and provides
- * the up to date information as well as a registration for callbacks that care
- * to be updated.
- *
- * Note: under time crunch, this has been extended to include some stuff that
- * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
- * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
- * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
- */
-public class KeyguardUpdateMonitor {
-
-    private static final String TAG = "KeyguardUpdateMonitor";
-    private static final boolean DEBUG = false;
-    private static final boolean DEBUG_SIM_STATES = DEBUG || false;
-    private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
-    private static final int LOW_BATTERY_THRESHOLD = 20;
-
-    // Callback messages
-    private static final int MSG_TIME_UPDATE = 301;
-    private static final int MSG_BATTERY_UPDATE = 302;
-    private static final int MSG_CARRIER_INFO_UPDATE = 303;
-    private static final int MSG_SIM_STATE_CHANGE = 304;
-    private static final int MSG_RINGER_MODE_CHANGED = 305;
-    private static final int MSG_PHONE_STATE_CHANGED = 306;
-    private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
-    private static final int MSG_DEVICE_PROVISIONED = 308;
-    private static final int MSG_DPM_STATE_CHANGED = 309;
-    private static final int MSG_USER_SWITCHING = 310;
-    private static final int MSG_USER_REMOVED = 311;
-    private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
-    protected static final int MSG_BOOT_COMPLETED = 313;
-    private static final int MSG_USER_SWITCH_COMPLETE = 314;
-    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
-    protected static final int MSG_SET_PLAYBACK_STATE = 316;
-    protected static final int MSG_USER_INFO_CHANGED = 317;
-
-
-    private static KeyguardUpdateMonitor sInstance;
-
-    private final Context mContext;
-
-    // Telephony state
-    private IccCardConstants.State mSimState = IccCardConstants.State.READY;
-    private CharSequence mTelephonyPlmn;
-    private CharSequence mTelephonySpn;
-    private int mRingMode;
-    private int mPhoneState;
-    private boolean mKeyguardIsVisible;
-    private boolean mBootCompleted;
-
-    // Device provisioning state
-    private boolean mDeviceProvisioned;
-
-    // Battery status
-    private BatteryStatus mBatteryStatus;
-
-    // Password attempts
-    private int mFailedAttempts = 0;
-    private int mFailedBiometricUnlockAttempts = 0;
-
-    private boolean mAlternateUnlockEnabled;
-
-    private boolean mClockVisible;
-
-    private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
-            mCallbacks = Lists.newArrayList();
-    private ContentObserver mDeviceProvisionedObserver;
-
-    private boolean mSwitchingUser;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_TIME_UPDATE:
-                    handleTimeUpdate();
-                    break;
-                case MSG_BATTERY_UPDATE:
-                    handleBatteryUpdate((BatteryStatus) msg.obj);
-                    break;
-                case MSG_CARRIER_INFO_UPDATE:
-                    handleCarrierInfoUpdate();
-                    break;
-                case MSG_SIM_STATE_CHANGE:
-                    handleSimStateChange((SimArgs) msg.obj);
-                    break;
-                case MSG_RINGER_MODE_CHANGED:
-                    handleRingerModeChange(msg.arg1);
-                    break;
-                case MSG_PHONE_STATE_CHANGED:
-                    handlePhoneStateChanged((String)msg.obj);
-                    break;
-                case MSG_CLOCK_VISIBILITY_CHANGED:
-                    handleClockVisibilityChanged();
-                    break;
-                case MSG_DEVICE_PROVISIONED:
-                    handleDeviceProvisioned();
-                    break;
-                case MSG_DPM_STATE_CHANGED:
-                    handleDevicePolicyManagerStateChanged();
-                    break;
-                case MSG_USER_SWITCHING:
-                    handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj);
-                    break;
-                case MSG_USER_SWITCH_COMPLETE:
-                    handleUserSwitchComplete(msg.arg1);
-                    break;
-                case MSG_USER_REMOVED:
-                    handleUserRemoved(msg.arg1);
-                    break;
-                case MSG_KEYGUARD_VISIBILITY_CHANGED:
-                    handleKeyguardVisibilityChanged(msg.arg1);
-                    break;
-                case MSG_BOOT_COMPLETED:
-                    handleBootCompleted();
-                    break;
-                case MSG_SET_CURRENT_CLIENT_ID:
-                    handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj);
-                    break;
-                case MSG_SET_PLAYBACK_STATE:
-                    handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
-                    break;
-                case MSG_USER_INFO_CHANGED:
-                    handleUserInfoChanged(msg.arg1);
-                    break;
-            }
-        }
-    };
-
-    private AudioManager mAudioManager;
-
-    static class DisplayClientState {
-        public int clientGeneration;
-        public boolean clearing;
-        public PendingIntent intent;
-        public int playbackState;
-        public long playbackEventTime;
-    }
-
-    private DisplayClientState mDisplayClientState = new DisplayClientState();
-
-    /**
-     * This currently implements the bare minimum required to enable showing and hiding
-     * KeyguardTransportControl.  There's a lot of client state to maintain which is why
-     * KeyguardTransportControl maintains an independent connection while it's showing.
-     */
-    private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
-                new IRemoteControlDisplay.Stub() {
-
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
-                long currentPosMs, float speed) {
-            Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
-                    generationId, state, stateChangeTimeMs);
-            mHandler.sendMessage(msg);
-        }
-
-        public void setMetadata(int generationId, Bundle metadata) {
-
-        }
-
-        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
-
-        }
-
-        public void setArtwork(int generationId, Bitmap bitmap) {
-
-        }
-
-        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
-
-        }
-
-        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
-                boolean clearing) throws RemoteException {
-            Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID,
-                        clientGeneration, (clearing ? 1 : 0), mediaIntent);
-            mHandler.sendMessage(msg);
-        }
-    };
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (DEBUG) Log.d(TAG, "received broadcast " + action);
-
-            if (Intent.ACTION_TIME_TICK.equals(action)
-                    || Intent.ACTION_TIME_CHANGED.equals(action)
-                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
-            } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
-                mTelephonyPlmn = getTelephonyPlmnFrom(intent);
-                mTelephonySpn = getTelephonySpnFrom(intent);
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
-            } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
-                final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
-                final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
-                final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
-                final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
-                final Message msg = mHandler.obtainMessage(
-                        MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
-                mHandler.sendMessage(msg);
-            } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
-                if (DEBUG_SIM_STATES) {
-                    Log.v(TAG, "action " + action + " state" +
-                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE));
-                }
-                mHandler.sendMessage(mHandler.obtainMessage(
-                        MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent)));
-            } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
-                        intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
-            } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
-                String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
-            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
-                    .equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
-            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
-                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
-            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_BOOT_COMPLETED));
-            }
-        }
-    };
-
-    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
-
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,
-                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));
-            }
-        }
-    };
-
-    /**
-     * When we receive a
-     * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
-     * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
-     * we need a single object to pass to the handler.  This class helps decode
-     * the intent and provide a {@link SimCard.State} result.
-     */
-    private static class SimArgs {
-        public final IccCardConstants.State simState;
-
-        SimArgs(IccCardConstants.State state) {
-            simState = state;
-        }
-
-        static SimArgs fromIntent(Intent intent) {
-            IccCardConstants.State state;
-            if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
-                throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
-            }
-            String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
-            if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-                final String absentReason = intent
-                    .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
-
-                if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
-                        absentReason)) {
-                    state = IccCardConstants.State.PERM_DISABLED;
-                } else {
-                    state = IccCardConstants.State.ABSENT;
-                }
-            } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-                state = IccCardConstants.State.READY;
-            } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-                final String lockedReason = intent
-                        .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
-                if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                    state = IccCardConstants.State.PIN_REQUIRED;
-                } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                    state = IccCardConstants.State.PUK_REQUIRED;
-                } else {
-                    state = IccCardConstants.State.UNKNOWN;
-                }
-            } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
-                state = IccCardConstants.State.NETWORK_LOCKED;
-            } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
-                        || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
-                // This is required because telephony doesn't return to "READY" after
-                // these state transitions. See bug 7197471.
-                state = IccCardConstants.State.READY;
-            } else {
-                state = IccCardConstants.State.UNKNOWN;
-            }
-            return new SimArgs(state);
-        }
-
-        public String toString() {
-            return simState.toString();
-        }
-    }
-
-    /* package */ static class BatteryStatus {
-        public final int status;
-        public final int level;
-        public final int plugged;
-        public final int health;
-        public BatteryStatus(int status, int level, int plugged, int health) {
-            this.status = status;
-            this.level = level;
-            this.plugged = plugged;
-            this.health = health;
-        }
-
-        /**
-         * Determine whether the device is plugged in (USB, power, or wireless).
-         * @return true if the device is plugged in.
-         */
-        boolean isPluggedIn() {
-            return plugged == BatteryManager.BATTERY_PLUGGED_AC
-                    || plugged == BatteryManager.BATTERY_PLUGGED_USB
-                    || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
-        }
-
-        /**
-         * Whether or not the device is charged. Note that some devices never return 100% for
-         * battery level, so this allows either battery level or status to determine if the
-         * battery is charged.
-         * @return true if the device is charged
-         */
-        public boolean isCharged() {
-            return status == BATTERY_STATUS_FULL || level >= 100;
-        }
-
-        /**
-         * Whether battery is low and needs to be charged.
-         * @return true if battery is low
-         */
-        public boolean isBatteryLow() {
-            return level < LOW_BATTERY_THRESHOLD;
-        }
-
-    }
-
-    public static KeyguardUpdateMonitor getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new KeyguardUpdateMonitor(context);
-        }
-        return sInstance;
-    }
-
-    protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
-        mDisplayClientState.clientGeneration = clientGeneration;
-        mDisplayClientState.clearing = clearing;
-        mDisplayClientState.intent = p;
-        if (DEBUG)
-            Log.v(TAG, "handleSetGenerationId(g=" + clientGeneration + ", clear=" + clearing + ")");
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onMusicClientIdChanged(clientGeneration, clearing, p);
-            }
-        }
-    }
-
-    protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) {
-        if (DEBUG)
-            Log.v(TAG, "handleSetPlaybackState(gen=" + generationId
-                + ", state=" + playbackState + ", t=" + eventTime + ")");
-        mDisplayClientState.playbackState = playbackState;
-        mDisplayClientState.playbackEventTime = eventTime;
-        if (generationId == mDisplayClientState.clientGeneration) {
-            for (int i = 0; i < mCallbacks.size(); i++) {
-                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-                if (cb != null) {
-                    cb.onMusicPlaybackStateChanged(playbackState, eventTime);
-                }
-            }
-        } else {
-            Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current");
-        }
-    }
-
-    private void handleUserInfoChanged(int userId) {
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onUserInfoChanged(userId);
-            }
-        }
-    }
-
-    private KeyguardUpdateMonitor(Context context) {
-        mContext = context;
-
-        mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
-        // Since device can't be un-provisioned, we only need to register a content observer
-        // to update mDeviceProvisioned when we are...
-        if (!mDeviceProvisioned) {
-            watchForDeviceProvisioning();
-        }
-
-        // Take a guess at initial SIM state, battery status and PLMN until we get an update
-        mSimState = IccCardConstants.State.NOT_READY;
-        mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
-        mTelephonyPlmn = getDefaultPlmn();
-
-        // Watch for interesting updates
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_TIME_TICK);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
-        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
-        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
-        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-        filter.addAction(Intent.ACTION_USER_REMOVED);
-        context.registerReceiver(mBroadcastReceiver, filter);
-
-        final IntentFilter bootCompleteFilter = new IntentFilter();
-        bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
-
-        final IntentFilter userInfoFilter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED);
-        context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, userInfoFilter,
-                null, null);
-
-        try {
-            ActivityManagerNative.getDefault().registerUserSwitchObserver(
-                    new IUserSwitchObserver.Stub() {
-                        @Override
-                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
-                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
-                                    newUserId, 0, reply));
-                            mSwitchingUser = true;
-                        }
-                        @Override
-                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
-                                    newUserId));
-                            mSwitchingUser = false;
-                        }
-                    });
-        } catch (RemoteException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-    }
-
-    private boolean isDeviceProvisionedInSettingsDb() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-    }
-
-    private void watchForDeviceProvisioning() {
-        mDeviceProvisionedObserver = new ContentObserver(mHandler) {
-            @Override
-            public void onChange(boolean selfChange) {
-                super.onChange(selfChange);
-                mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
-                if (mDeviceProvisioned) {
-                    mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
-                }
-                if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
-            }
-        };
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
-                false, mDeviceProvisionedObserver);
-
-        // prevent a race condition between where we check the flag and where we register the
-        // observer by grabbing the value once again...
-        boolean provisioned = isDeviceProvisionedInSettingsDb();
-        if (provisioned != mDeviceProvisioned) {
-            mDeviceProvisioned = provisioned;
-            if (mDeviceProvisioned) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_DPM_STATE_CHANGED}
-     */
-    protected void handleDevicePolicyManagerStateChanged() {
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onDevicePolicyManagerStateChanged();
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_USER_SWITCHING}
-     */
-    protected void handleUserSwitching(int userId, IRemoteCallback reply) {
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onUserSwitching(userId);
-            }
-        }
-        try {
-            reply.sendResult(null);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_USER_SWITCH_COMPLETE}
-     */
-    protected void handleUserSwitchComplete(int userId) {
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onUserSwitchComplete(userId);
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_BOOT_COMPLETED}
-     */
-    protected void handleBootCompleted() {
-        mBootCompleted = true;
-        mAudioManager = new AudioManager(mContext);
-        mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onBootCompleted();
-            }
-        }
-    }
-
-    /**
-     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
-     * destroyed.
-     */
-    public boolean hasBootCompleted() {
-        return mBootCompleted;
-    }
-
-    /**
-     * Handle {@link #MSG_USER_REMOVED}
-     */
-    protected void handleUserRemoved(int userId) {
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onUserRemoved(userId);
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_DEVICE_PROVISIONED}
-     */
-    protected void handleDeviceProvisioned() {
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onDeviceProvisioned();
-            }
-        }
-        if (mDeviceProvisionedObserver != null) {
-            // We don't need the observer anymore...
-            mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
-            mDeviceProvisionedObserver = null;
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_PHONE_STATE_CHANGED}
-     */
-    protected void handlePhoneStateChanged(String newState) {
-        if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
-        if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
-            mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-        } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
-            mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
-        } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
-            mPhoneState = TelephonyManager.CALL_STATE_RINGING;
-        }
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onPhoneStateChanged(mPhoneState);
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_RINGER_MODE_CHANGED}
-     */
-    protected void handleRingerModeChange(int mode) {
-        if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
-        mRingMode = mode;
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onRingerModeChanged(mode);
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_TIME_UPDATE}
-     */
-    private void handleTimeUpdate() {
-        if (DEBUG) Log.d(TAG, "handleTimeUpdate");
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onTimeChanged();
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_BATTERY_UPDATE}
-     */
-    private void handleBatteryUpdate(BatteryStatus status) {
-        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
-        final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
-        mBatteryStatus = status;
-        if (batteryUpdateInteresting) {
-            for (int i = 0; i < mCallbacks.size(); i++) {
-                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-                if (cb != null) {
-                    cb.onRefreshBatteryInfo(status);
-                }
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_CARRIER_INFO_UPDATE}
-     */
-    private void handleCarrierInfoUpdate() {
-        if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
-            + ", spn = " + mTelephonySpn);
-
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_SIM_STATE_CHANGE}
-     */
-    private void handleSimStateChange(SimArgs simArgs) {
-        final IccCardConstants.State state = simArgs.simState;
-
-        if (DEBUG) {
-            Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
-                    + "state resolved to " + state.toString());
-        }
-
-        if (state != IccCardConstants.State.UNKNOWN && state != mSimState) {
-            mSimState = state;
-            for (int i = 0; i < mCallbacks.size(); i++) {
-                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-                if (cb != null) {
-                    cb.onSimStateChanged(state);
-                }
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
-     */
-    private void handleClockVisibilityChanged() {
-        if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onClockVisibilityChanged();
-            }
-        }
-    }
-
-    /**
-     * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
-     */
-    private void handleKeyguardVisibilityChanged(int showing) {
-        if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
-        boolean isShowing = (showing == 1);
-        mKeyguardIsVisible = isShowing;
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onKeyguardVisibilityChanged(isShowing);
-            }
-        }
-    }
-
-    public boolean isKeyguardVisible() {
-        return mKeyguardIsVisible;
-    }
-
-    public boolean isSwitchingUser() {
-        return mSwitchingUser;
-    }
-
-    private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
-        final boolean nowPluggedIn = current.isPluggedIn();
-        final boolean wasPluggedIn = old.isPluggedIn();
-        final boolean stateChangedWhilePluggedIn =
-            wasPluggedIn == true && nowPluggedIn == true
-            && (old.status != current.status);
-
-        // change in plug state is always interesting
-        if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
-            return true;
-        }
-
-        // change in battery level while plugged in
-        if (nowPluggedIn && old.level != current.level) {
-            return true;
-        }
-
-        // change where battery needs charging
-        if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION}
-     * @return The string to use for the plmn, or null if it should not be shown.
-     */
-    private CharSequence getTelephonyPlmnFrom(Intent intent) {
-        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
-            final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
-            return (plmn != null) ? plmn : getDefaultPlmn();
-        }
-        return null;
-    }
-
-    /**
-     * @return The default plmn (no service)
-     */
-    private CharSequence getDefaultPlmn() {
-        return mContext.getResources().getText(R.string.lockscreen_carrier_default);
-    }
-
-    /**
-     * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
-     * @return The string to use for the plmn, or null if it should not be shown.
-     */
-    private CharSequence getTelephonySpnFrom(Intent intent) {
-        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
-            final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN);
-            if (spn != null) {
-                return spn;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Remove the given observer's callback.
-     *
-     * @param callback The callback to remove
-     */
-    public void removeCallback(KeyguardUpdateMonitorCallback callback) {
-        if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback);
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            if (mCallbacks.get(i).get() == callback) {
-                mCallbacks.remove(i);
-            }
-        }
-    }
-
-    /**
-     * Register to receive notifications about general keyguard information
-     * (see {@link InfoCallback}.
-     * @param callback The callback to register
-     */
-    public void registerCallback(KeyguardUpdateMonitorCallback callback) {
-        if (DEBUG) Log.v(TAG, "*** register callback for " + callback);
-        // Prevent adding duplicate callbacks
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            if (mCallbacks.get(i).get() == callback) {
-                if (DEBUG) Log.e(TAG, "Object tried to add another callback",
-                        new Exception("Called by"));
-                return;
-            }
-        }
-        mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
-        removeCallback(null); // remove unused references
-        sendUpdates(callback);
-    }
-
-    private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
-        // Notify listener of the current state
-        callback.onRefreshBatteryInfo(mBatteryStatus);
-        callback.onTimeChanged();
-        callback.onRingerModeChanged(mRingMode);
-        callback.onPhoneStateChanged(mPhoneState);
-        callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
-        callback.onClockVisibilityChanged();
-        callback.onSimStateChanged(mSimState);
-        callback.onMusicClientIdChanged(
-                mDisplayClientState.clientGeneration,
-                mDisplayClientState.clearing,
-                mDisplayClientState.intent);
-        callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
-                mDisplayClientState.playbackEventTime);
-    }
-
-    public void sendKeyguardVisibilityChanged(boolean showing) {
-        if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
-        Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
-        message.arg1 = showing ? 1 : 0;
-        message.sendToTarget();
-    }
-
-    public void reportClockVisible(boolean visible) {
-        mClockVisible = visible;
-        mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
-    }
-
-    public IccCardConstants.State getSimState() {
-        return mSimState;
-    }
-
-    /**
-     * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
-     * have the information earlier than waiting for the intent
-     * broadcast from the telephony code.
-     *
-     * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
-     * through mHandler, this *must* be called from the UI thread.
-     */
-    public void reportSimUnlocked() {
-        handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
-    }
-
-    public CharSequence getTelephonyPlmn() {
-        return mTelephonyPlmn;
-    }
-
-    public CharSequence getTelephonySpn() {
-        return mTelephonySpn;
-    }
-
-    /**
-     * @return Whether the device is provisioned (whether they have gone through
-     *   the setup wizard)
-     */
-    public boolean isDeviceProvisioned() {
-        return mDeviceProvisioned;
-    }
-
-    public int getFailedUnlockAttempts() {
-        return mFailedAttempts;
-    }
-
-    public void clearFailedUnlockAttempts() {
-        mFailedAttempts = 0;
-        mFailedBiometricUnlockAttempts = 0;
-    }
-
-    public void reportFailedUnlockAttempt() {
-        mFailedAttempts++;
-    }
-
-    public boolean isClockVisible() {
-        return mClockVisible;
-    }
-
-    public int getPhoneState() {
-        return mPhoneState;
-    }
-
-    public void reportFailedBiometricUnlockAttempt() {
-        mFailedBiometricUnlockAttempts++;
-    }
-
-    public boolean getMaxBiometricUnlockAttemptsReached() {
-        return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
-    }
-
-    public boolean isAlternateUnlockEnabled() {
-        return mAlternateUnlockEnabled;
-    }
-
-    public void setAlternateUnlockEnabled(boolean enabled) {
-        mAlternateUnlockEnabled = enabled;
-    }
-
-    public boolean isSimLocked() {
-        return isSimLocked(mSimState);
-    }
-
-    public static boolean isSimLocked(IccCardConstants.State state) {
-        return state == IccCardConstants.State.PIN_REQUIRED
-        || state == IccCardConstants.State.PUK_REQUIRED
-        || state == IccCardConstants.State.PERM_DISABLED;
-    }
-
-    public boolean isSimPinSecure() {
-        return isSimPinSecure(mSimState);
-    }
-
-    public static boolean isSimPinSecure(IccCardConstants.State state) {
-        final IccCardConstants.State simState = state;
-        return (simState == IccCardConstants.State.PIN_REQUIRED
-                || simState == IccCardConstants.State.PUK_REQUIRED
-                || simState == IccCardConstants.State.PERM_DISABLED);
-    }
-
-    public DisplayClientState getCachedDisplayClientState() {
-        return mDisplayClientState;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
deleted file mode 100644
index 41816db..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.media.AudioManager;
-
-import com.android.internal.telephony.IccCardConstants;
-
-/**
- * Callback for general information relevant to lock screen.
- */
-class KeyguardUpdateMonitorCallback {
-    /**
-     * Called when the battery status changes, e.g. when plugged in or unplugged, charge
-     * level, etc. changes.
-     *
-     * @param status current battery status
-     */
-    void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { }
-
-    /**
-     * Called once per minute or when the time changes.
-     */
-    void onTimeChanged() { }
-
-    /**
-     * Called when the carrier PLMN or SPN changes.
-     *
-     * @param plmn The operator name of the registered network.  May be null if it shouldn't
-     *   be displayed.
-     * @param spn The service provider name.  May be null if it shouldn't be displayed.
-     */
-    void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { }
-
-    /**
-     * Called when the ringer mode changes.
-     * @param state the current ringer state, as defined in
-     * {@link AudioManager#RINGER_MODE_CHANGED_ACTION}
-     */
-    void onRingerModeChanged(int state) { }
-
-    /**
-     * Called when the phone state changes. String will be one of:
-     * {@link TelephonyManager#EXTRA_STATE_IDLE}
-     * {@link TelephonyManager@EXTRA_STATE_RINGING}
-     * {@link TelephonyManager#EXTRA_STATE_OFFHOOK
-     */
-    void onPhoneStateChanged(int phoneState) { }
-
-    /**
-     * Called when the visibility of the keyguard changes.
-     * @param showing Indicates if the keyguard is now visible.
-     */
-    void onKeyguardVisibilityChanged(boolean showing) { }
-
-    /**
-     * Called when visibility of lockscreen clock changes, such as when
-     * obscured by a widget.
-     */
-    void onClockVisibilityChanged() { }
-
-    /**
-     * Called when the device becomes provisioned
-     */
-    void onDeviceProvisioned() { }
-
-    /**
-     * Called when the device policy changes.
-     * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
-     */
-    void onDevicePolicyManagerStateChanged() { }
-
-    /**
-     * Called when the user change begins.
-     */
-    void onUserSwitching(int userId) { }
-
-    /**
-     * Called when the user change is complete.
-     */
-    void onUserSwitchComplete(int userId) { }
-
-    /**
-     * Called when the SIM state changes.
-     * @param simState
-     */
-    void onSimStateChanged(IccCardConstants.State simState) { }
-
-    /**
-     * Called when a user is removed.
-     */
-    void onUserRemoved(int userId) { }
-
-    /**
-     * Called when the user's info changed.
-     */
-    void onUserInfoChanged(int userId) { }
-
-    /**
-     * Called when boot completed.
-     *
-     * Note, this callback will only be received if boot complete occurs after registering with
-     * KeyguardUpdateMonitor.
-     */
-    void onBootCompleted() { }
-
-    /**
-     * Called when audio client attaches or detaches from AudioManager.
-     */
-    void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
-
-    /**
-     * Called when the audio playback state changes.
-     * @param playbackState
-     * @param eventTime
-     */
-    public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
deleted file mode 100644
index 6fcacd3..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.IAudioService;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.view.KeyEvent;
-import android.widget.FrameLayout;
-
-/**
- * Base class for keyguard view.  {@link #reset} is where you should
- * reset the state of your view.  Use the {@link KeyguardViewCallback} via
- * {@link #getCallback()} to send information back (such as poking the wake lock,
- * or finishing the keyguard).
- *
- * Handles intercepting of media keys that still work when the keyguard is
- * showing.
- */
-public abstract class KeyguardViewBase extends FrameLayout {
-
-    private static final int BACKGROUND_COLOR = 0x70000000;
-    private AudioManager mAudioManager;
-    private TelephonyManager mTelephonyManager = null;
-    protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
-
-    // Whether the volume keys should be handled by keyguard. If true, then
-    // they will be handled here for specific media types such as music, otherwise
-    // the audio service will bring up the volume dialog.
-    private static final boolean KEYGUARD_MANAGES_VOLUME = true;
-
-    // This is a faster way to draw the background on devices without hardware acceleration
-    private static final Drawable mBackgroundDrawable = new Drawable() {
-        @Override
-        public void draw(Canvas canvas) {
-            canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC);
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-
-        @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
-    };
-
-    public KeyguardViewBase(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardViewBase(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        resetBackground();
-    }
-
-    public void resetBackground() {
-        setBackground(mBackgroundDrawable);
-    }
-
-    /**
-     * Called when you need to reset the state of your view.
-     */
-    abstract public void reset();
-
-    /**
-     * Called when the screen turned off.
-     */
-    abstract public void onScreenTurnedOff();
-
-    /**
-     * Called when the screen turned on.
-     */
-    abstract public void onScreenTurnedOn();
-
-    /**
-     * Called when the view needs to be shown.
-     */
-    abstract public void show();
-
-    /**
-     * Called when a key has woken the device to give us a chance to adjust our
-     * state according the the key.  We are responsible for waking the device
-     * (by poking the wake lock) once we are ready.
-     *
-     * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
-     * Be sure not to take any action that takes a long time; any significant
-     * action should be posted to a handler.
-     *
-     * @param keyCode The wake key, which may be relevant for configuring the
-     *   keyguard.  May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking for a reason
-     *   other than a key press.
-     */
-    abstract public void wakeWhenReadyTq(int keyCode);
-
-    /**
-     * Verify that the user can get past the keyguard securely.  This is called,
-     * for example, when the phone disables the keyguard but then wants to launch
-     * something else that requires secure access.
-     *
-     * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
-     */
-    abstract public void verifyUnlock();
-
-    /**
-     * Called before this view is being removed.
-     */
-    abstract public void cleanUp();
-
-    /**
-     * Gets the desired user activity timeout in milliseconds, or -1 if the
-     * default should be used.
-     */
-    abstract public long getUserActivityTimeout();
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (interceptMediaKey(event)) {
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    /**
-     * Allows the media keys to work when the keyguard is showing.
-     * The media keys should be of no interest to the actual keyguard view(s),
-     * so intercepting them here should not be of any harm.
-     * @param event The key event
-     * @return whether the event was consumed as a media key.
-     */
-    private boolean interceptMediaKey(KeyEvent event) {
-        final int keyCode = event.getKeyCode();
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_MEDIA_PLAY:
-                case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
-                     * in-call to avoid music playback */
-                    if (mTelephonyManager == null) {
-                        mTelephonyManager = (TelephonyManager) getContext().getSystemService(
-                                Context.TELEPHONY_SERVICE);
-                    }
-                    if (mTelephonyManager != null &&
-                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
-                        return true;  // suppress key event
-                    }
-                case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK:
-                case KeyEvent.KEYCODE_MEDIA_STOP:
-                case KeyEvent.KEYCODE_MEDIA_NEXT:
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                case KeyEvent.KEYCODE_MEDIA_REWIND:
-                case KeyEvent.KEYCODE_MEDIA_RECORD:
-                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
-                    handleMediaKeyEvent(event);
-                    return true;
-                }
-
-                case KeyEvent.KEYCODE_VOLUME_UP:
-                case KeyEvent.KEYCODE_VOLUME_DOWN:
-                case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                    if (KEYGUARD_MANAGES_VOLUME) {
-                        synchronized (this) {
-                            if (mAudioManager == null) {
-                                mAudioManager = (AudioManager) getContext().getSystemService(
-                                        Context.AUDIO_SERVICE);
-                            }
-                        }
-                        // Volume buttons should only function for music (local or remote).
-                        // TODO: Actually handle MUTE.
-                        mAudioManager.adjustLocalOrRemoteStreamVolume(
-                                AudioManager.STREAM_MUSIC,
-                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                        ? AudioManager.ADJUST_RAISE
-                                        : AudioManager.ADJUST_LOWER);
-                        // Don't execute default volume behavior
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-        } else if (event.getAction() == KeyEvent.ACTION_UP) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK:
-                case KeyEvent.KEYCODE_MEDIA_PLAY:
-                case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_STOP:
-                case KeyEvent.KEYCODE_MEDIA_NEXT:
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                case KeyEvent.KEYCODE_MEDIA_REWIND:
-                case KeyEvent.KEYCODE_MEDIA_RECORD:
-                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
-                    handleMediaKeyEvent(event);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    void handleMediaKeyEvent(KeyEvent keyEvent) {
-        IAudioService audioService = IAudioService.Stub.asInterface(
-                ServiceManager.checkService(Context.AUDIO_SERVICE));
-        if (audioService != null) {
-            try {
-                audioService.dispatchMediaKeyEvent(keyEvent);
-            } catch (RemoteException e) {
-                Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
-            }
-        } else {
-            Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
-        }
-    }
-
-    @Override
-    public void dispatchSystemUiVisibilityChanged(int visibility) {
-        super.dispatchSystemUiVisibilityChanged(visibility);
-
-        if (!(mContext instanceof Activity)) {
-            setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
-        }
-    }
-
-    public void setViewMediatorCallback(
-            KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
-        mViewMediatorCallback = viewMediatorCallback;
-    }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
deleted file mode 100644
index 30c95fb..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcelable;
-import android.os.SystemProperties;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewManager;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-/**
- * Manages creating, showing, hiding and resetting the keyguard.  Calls back
- * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke
- * the wake lock and report that the keyguard is done, which is in turn,
- * reported to this class by the current {@link KeyguardViewBase}.
- */
-public class KeyguardViewManager {
-    private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
-    private static String TAG = "KeyguardViewManager";
-    public static boolean USE_UPPER_CASE = true;
-    public final static String IS_SWITCHING_USER = "is_switching_user";
-
-    // Timeout used for keypresses
-    static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
-
-    private final Context mContext;
-    private final ViewManager mViewManager;
-    private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
-
-    private WindowManager.LayoutParams mWindowLayoutParams;
-    private boolean mNeedsInput = false;
-
-    private FrameLayout mKeyguardHost;
-    private KeyguardHostView mKeyguardView;
-
-    private boolean mScreenOn = false;
-    private LockPatternUtils mLockPatternUtils;
-
-    public interface ShowListener {
-        void onShown(IBinder windowToken);
-    };
-
-    /**
-     * @param context Used to create views.
-     * @param viewManager Keyguard will be attached to this.
-     * @param callback Used to notify of changes.
-     * @param lockPatternUtils
-     */
-    public KeyguardViewManager(Context context, ViewManager viewManager,
-            KeyguardViewMediator.ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils) {
-        mContext = context;
-        mViewManager = viewManager;
-        mViewMediatorCallback = callback;
-        mLockPatternUtils = lockPatternUtils;
-    }
-
-    /**
-     * Show the keyguard.  Will handle creating and attaching to the view manager
-     * lazily.
-     */
-    public synchronized void show(Bundle options) {
-        if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
-
-        boolean enableScreenRotation = shouldEnableScreenRotation();
-
-        maybeCreateKeyguardLocked(enableScreenRotation, false, options);
-        maybeEnableScreenRotation(enableScreenRotation);
-
-        // Disable common aspects of the system/status/navigation bars that are not appropriate or
-        // useful on any keyguard screen but can be re-shown by dialogs or SHOW_WHEN_LOCKED
-        // activities. Other disabled bits are handled by the KeyguardViewMediator talking
-        // directly to the status bar service.
-        final int visFlags = View.STATUS_BAR_DISABLE_HOME;
-        if (DEBUG) Log.v(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")");
-        mKeyguardHost.setSystemUiVisibility(visFlags);
-
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-        mKeyguardHost.setVisibility(View.VISIBLE);
-        mKeyguardView.show();
-        mKeyguardView.requestFocus();
-    }
-
-    private boolean shouldEnableScreenRotation() {
-        Resources res = mContext.getResources();
-        return SystemProperties.getBoolean("lockscreen.rot_override",false)
-                || res.getBoolean(com.android.internal.R.bool.config_enableLockScreenRotation);
-    }
-
-    class ViewManagerHost extends FrameLayout {
-        public ViewManagerHost(Context context) {
-            super(context);
-            setFitsSystemWindows(true);
-        }
-
-        @Override
-        protected boolean fitSystemWindows(Rect insets) {
-            Log.v("TAG", "bug 7643792: fitSystemWindows(" + insets.toShortString() + ")");
-            return super.fitSystemWindows(insets);
-        }
-
-        @Override
-        protected void onConfigurationChanged(Configuration newConfig) {
-            super.onConfigurationChanged(newConfig);
-            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                // only propagate configuration messages if we're currently showing
-                maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null);
-            } else {
-                if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible");
-            }
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            if (mKeyguardView != null) {
-                // Always process back and menu keys, regardless of focus
-                if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                    int keyCode = event.getKeyCode();
-                    if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) {
-                        return true;
-                    } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) {
-                        return true;
-                    }
-                }
-                // Always process media keys, regardless of focus
-                if (mKeyguardView.dispatchKeyEvent(event)) {
-                    return true;
-                }
-            }
-            return super.dispatchKeyEvent(event);
-        }
-    }
-
-    SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
-
-    private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
-            Bundle options) {
-        final boolean isActivity = (mContext instanceof Activity); // for test activity
-
-        if (mKeyguardHost != null) {
-            mKeyguardHost.saveHierarchyState(mStateContainer);
-        }
-
-        if (mKeyguardHost == null) {
-            if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
-
-            mKeyguardHost = new ViewManagerHost(mContext);
-
-            int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
-                    | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-
-            if (!mNeedsInput) {
-                flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-            }
-            if (ActivityManager.isHighEndGfx()) {
-                flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-            }
-
-            final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
-            final int type = isActivity ? WindowManager.LayoutParams.TYPE_APPLICATION
-                    : WindowManager.LayoutParams.TYPE_KEYGUARD;
-            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
-            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-            lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
-            lp.screenOrientation = enableScreenRotation ?
-                    ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-
-            if (ActivityManager.isHighEndGfx()) {
-                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-                lp.privateFlags |=
-                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
-            }
-            lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
-            if (isActivity) {
-                lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-            }
-            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
-            lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard");
-            mWindowLayoutParams = lp;
-            mViewManager.addView(mKeyguardHost, lp);
-        }
-
-        if (force || mKeyguardView == null) {
-            inflateKeyguardView(options);
-            mKeyguardView.requestFocus();
-        }
-        updateUserActivityTimeoutInWindowLayoutParams();
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-
-        mKeyguardHost.restoreHierarchyState(mStateContainer);
-    }
-
-    private void inflateKeyguardView(Bundle options) {
-        View v = mKeyguardHost.findViewById(R.id.keyguard_host_view);
-        if (v != null) {
-            mKeyguardHost.removeView(v);
-        }
-        // TODO: Remove once b/7094175 is fixed
-        if (false) Slog.d(TAG, "inflateKeyguardView: b/7094175 mContext.config="
-                + mContext.getResources().getConfiguration());
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true);
-        mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view);
-        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
-        mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
-        mKeyguardView.initializeSwitchingUserState(options != null &&
-                options.getBoolean(IS_SWITCHING_USER));
-
-        // HACK
-        // The keyguard view will have set up window flags in onFinishInflate before we set
-        // the view mediator callback. Make sure it knows the correct IME state.
-        if (mViewMediatorCallback != null) {
-            KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
-                    R.id.keyguard_password_view);
-
-            if (kpv != null) {
-                mViewMediatorCallback.setNeedsInput(kpv.needsInput());
-            }
-        }
-
-        if (options != null) {
-            int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
-                    AppWidgetManager.INVALID_APPWIDGET_ID);
-            if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                mKeyguardView.goToWidget(widgetToShow);
-            }
-        }
-    }
-
-    public void updateUserActivityTimeout() {
-        updateUserActivityTimeoutInWindowLayoutParams();
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-    }
-
-    private void updateUserActivityTimeoutInWindowLayoutParams() {
-        // Use the user activity timeout requested by the keyguard view, if any.
-        if (mKeyguardView != null) {
-            long timeout = mKeyguardView.getUserActivityTimeout();
-            if (timeout >= 0) {
-                mWindowLayoutParams.userActivityTimeout = timeout;
-                return;
-            }
-        }
-
-        // Otherwise, use the default timeout.
-        mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
-    }
-
-    private void maybeEnableScreenRotation(boolean enableScreenRotation) {
-        // TODO: move this outside
-        if (enableScreenRotation) {
-            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!");
-            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
-        } else {
-            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!");
-            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-        }
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-    }
-
-    public void setNeedsInput(boolean needsInput) {
-        mNeedsInput = needsInput;
-        if (mWindowLayoutParams != null) {
-            if (needsInput) {
-                mWindowLayoutParams.flags &=
-                    ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-            } else {
-                mWindowLayoutParams.flags |=
-                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-            }
-
-            try {
-                mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-            } catch (java.lang.IllegalArgumentException e) {
-                // TODO: Ensure this method isn't called on views that are changing...
-                Log.w(TAG,"Can't update input method on " + mKeyguardHost + " window not attached");
-            }
-        }
-    }
-
-    /**
-     * Reset the state of the view.
-     */
-    public synchronized void reset(Bundle options) {
-        if (DEBUG) Log.d(TAG, "reset()");
-        // User might have switched, check if we need to go back to keyguard
-        // TODO: It's preferable to stay and show the correct lockscreen or unlock if none
-        maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, options);
-    }
-
-    public synchronized void onScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
-        mScreenOn = false;
-        if (mKeyguardView != null) {
-            mKeyguardView.onScreenTurnedOff();
-        }
-    }
-
-    public synchronized void onScreenTurnedOn(
-            final KeyguardViewManager.ShowListener showListener) {
-        if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
-        mScreenOn = true;
-        if (mKeyguardView != null) {
-            mKeyguardView.onScreenTurnedOn();
-
-            // Caller should wait for this window to be shown before turning
-            // on the screen.
-            if (showListener != null) {
-                if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                    // Keyguard may be in the process of being shown, but not yet
-                    // updated with the window manager...  give it a chance to do so.
-                    mKeyguardHost.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                                showListener.onShown(mKeyguardHost.getWindowToken());
-                            } else {
-                                showListener.onShown(null);
-                            }
-                        }
-                    });
-                } else {
-                    showListener.onShown(null);
-                }
-            }
-        } else if (showListener != null) {
-            showListener.onShown(null);
-        }
-    }
-
-    public synchronized void verifyUnlock() {
-        if (DEBUG) Log.d(TAG, "verifyUnlock()");
-        show(null);
-        mKeyguardView.verifyUnlock();
-    }
-
-    /**
-     * A key has woken the device.  We use this to potentially adjust the state
-     * of the lock screen based on the key.
-     *
-     * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
-     * Be sure not to take any action that takes a long time; any significant
-     * action should be posted to a handler.
-     *
-     * @param keyCode The wake key.  May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking
-     * for a reason other than a key press.
-     */
-    public boolean wakeWhenReadyTq(int keyCode) {
-        if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
-        if (mKeyguardView != null) {
-            mKeyguardView.wakeWhenReadyTq(keyCode);
-            return true;
-        }
-        Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
-        return false;
-    }
-
-    /**
-     * Hides the keyguard view
-     */
-    public synchronized void hide() {
-        if (DEBUG) Log.d(TAG, "hide()");
-
-        if (mKeyguardHost != null) {
-            mKeyguardHost.setVisibility(View.GONE);
-
-            // We really only want to preserve keyguard state for configuration changes. Hence
-            // we should clear state of widgets (e.g. Music) when we hide keyguard so it can
-            // start with a fresh state when we return.
-            mStateContainer.clear();
-
-            // Don't do this right away, so we can let the view continue to animate
-            // as it goes away.
-            if (mKeyguardView != null) {
-                final KeyguardViewBase lastView = mKeyguardView;
-                mKeyguardView = null;
-                mKeyguardHost.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        synchronized (KeyguardViewManager.this) {
-                            lastView.cleanUp();
-                            mKeyguardHost.removeView(lastView);
-                        }
-                    }
-                }, 500);
-            }
-        }
-    }
-
-    /**
-     * Dismisses the keyguard by going to the next screen or making it gone.
-     */
-    public synchronized void dismiss() {
-        if (mScreenOn) {
-            mKeyguardView.dismiss();
-        }
-    }
-
-    /**
-     * @return Whether the keyguard is showing
-     */
-    public synchronized boolean isShowing() {
-        return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);
-    }
-
-    public void showAssistant() {
-        if (mKeyguardView != null) {
-            mKeyguardView.showAssistant();
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
deleted file mode 100644
index 885cb45..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-
-import android.app.Activity;
-import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.SearchManager;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.media.SoundPool;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
-import android.util.EventLog;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.widget.LockPatternUtils;
-
-
-/**
- * Mediates requests related to the keyguard.  This includes queries about the
- * state of the keyguard, power management events that effect whether the keyguard
- * should be shown or reset, callbacks to the phone window manager to notify
- * it of when the keyguard is showing, and events from the keyguard view itself
- * stating that the keyguard was succesfully unlocked.
- *
- * Note that the keyguard view is shown when the screen is off (as appropriate)
- * so that once the screen comes on, it will be ready immediately.
- *
- * Example queries about the keyguard:
- * - is {movement, key} one that should wake the keygaurd?
- * - is the keyguard showing?
- * - are input events restricted due to the state of the keyguard?
- *
- * Callbacks to the phone window manager:
- * - the keyguard is showing
- *
- * Example external events that translate to keyguard view changes:
- * - screen turned off -> reset the keyguard, and show it so it will be ready
- *   next time the screen turns on
- * - keyboard is slid open -> if the keyguard is not secure, hide it
- *
- * Events from the keyguard view:
- * - user succesfully unlocked keyguard -> hide keyguard view, and no longer
- *   restrict input events.
- *
- * Note: in addition to normal power managment events that effect the state of
- * whether the keyguard should be showing, external apps and services may request
- * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}.  When
- * false, this will override all other conditions for turning on the keyguard.
- *
- * Threading and synchronization:
- * This class is created by the initialization routine of the {@link WindowManagerPolicy},
- * and runs on its thread.  The keyguard UI is created from that thread in the
- * constructor of this class.  The apis may be called from other threads, including the
- * {@link com.android.server.input.InputManagerService}'s and {@link android.view.WindowManager}'s.
- * Therefore, methods on this class are synchronized, and any action that is pointed
- * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI
- * thread of the keyguard.
- */
-public class KeyguardViewMediator {
-    private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
-    final static boolean DEBUG = false;
-    private final static boolean DBG_WAKE = false;
-
-    private final static String TAG = "KeyguardViewMediator";
-
-    private static final String DELAYED_KEYGUARD_ACTION =
-        "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
-
-    // used for handler messages
-    private static final int SHOW = 2;
-    private static final int HIDE = 3;
-    private static final int RESET = 4;
-    private static final int VERIFY_UNLOCK = 5;
-    private static final int NOTIFY_SCREEN_OFF = 6;
-    private static final int NOTIFY_SCREEN_ON = 7;
-    private static final int WAKE_WHEN_READY = 8;
-    private static final int KEYGUARD_DONE = 9;
-    private static final int KEYGUARD_DONE_DRAWING = 10;
-    private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
-    private static final int SET_HIDDEN = 12;
-    private static final int KEYGUARD_TIMEOUT = 13;
-    private static final int SHOW_ASSISTANT = 14;
-
-    /**
-     * The default amount of time we stay awake (used for all key input)
-     */
-    protected static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;
-
-    /**
-     * How long to wait after the screen turns off due to timeout before
-     * turning on the keyguard (i.e, the user has this much time to turn
-     * the screen back on without having to face the keyguard).
-     */
-    private static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000;
-
-    /**
-     * How long we'll wait for the {@link ViewMediatorCallback#keyguardDoneDrawing()}
-     * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)}
-     * that is reenabling the keyguard.
-     */
-    private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
-
-    /**
-     * Allow the user to expand the status bar when the keyguard is engaged
-     * (without a pattern or password).
-     */
-    private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true;
-
-    /** The stream type that the lock sounds are tied to. */
-    private int mMasterStreamType;
-
-    private Context mContext;
-    private AlarmManager mAlarmManager;
-    private AudioManager mAudioManager;
-    private StatusBarManager mStatusBarManager;
-    private boolean mShowLockIcon;
-    private boolean mShowingLockIcon;
-    private boolean mSwitchingUser;
-
-    private boolean mSystemReady;
-
-    // Whether the next call to playSounds() should be skipped.  Defaults to
-    // true because the first lock (on boot) should be silent.
-    private boolean mSuppressNextLockSound = true;
-
-
-    /** High level access to the power manager for WakeLocks */
-    private PowerManager mPM;
-
-    /** UserManager for querying number of users */
-    private UserManager mUserManager;
-
-    /** SearchManager for determining whether or not search assistant is available */
-    private SearchManager mSearchManager;
-
-    /**
-     * Used to keep the device awake while to ensure the keyguard finishes opening before
-     * we sleep.
-     */
-    private PowerManager.WakeLock mShowKeyguardWakeLock;
-
-    /**
-     * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)}
-     * is called to make sure the device doesn't sleep before it has a chance to poke
-     * the wake lock.
-     * @see #wakeWhenReady(int)
-     */
-    private PowerManager.WakeLock mWakeAndHandOff;
-
-    private KeyguardViewManager mKeyguardViewManager;
-
-    // these are protected by synchronized (this)
-
-    /**
-     * External apps (like the phone app) can tell us to disable the keygaurd.
-     */
-    private boolean mExternallyEnabled = true;
-
-    /**
-     * Remember if an external call to {@link #setKeyguardEnabled} with value
-     * false caused us to hide the keyguard, so that we need to reshow it once
-     * the keygaurd is reenabled with another call with value true.
-     */
-    private boolean mNeedToReshowWhenReenabled = false;
-
-    // cached value of whether we are showing (need to know this to quickly
-    // answer whether the input should be restricted)
-    private boolean mShowing = false;
-
-    // true if the keyguard is hidden by another window
-    private boolean mHidden = false;
-
-    /**
-     * Helps remember whether the screen has turned on since the last time
-     * it turned off due to timeout. see {@link #onScreenTurnedOff(int)}
-     */
-    private int mDelayedShowingSequence;
-
-    /**
-     * If the user has disabled the keyguard, then requests to exit, this is
-     * how we'll ultimately let them know whether it was successful.  We use this
-     * var being non-null as an indicator that there is an in progress request.
-     */
-    private WindowManagerPolicy.OnKeyguardExitResult mExitSecureCallback;
-
-    // the properties of the keyguard
-
-    private KeyguardUpdateMonitor mUpdateMonitor;
-
-    private boolean mScreenOn;
-
-    // last known state of the cellular connection
-    private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE;
-
-    /**
-     * we send this intent when the keyguard is dismissed.
-     */
-    private Intent mUserPresentIntent;
-
-    /**
-     * {@link #setKeyguardEnabled} waits on this condition when it reenables
-     * the keyguard.
-     */
-    private boolean mWaitingUntilKeyguardVisible = false;
-    private LockPatternUtils mLockPatternUtils;
-    private boolean mKeyguardDonePending = false;
-
-    private SoundPool mLockSounds;
-    private int mLockSoundId;
-    private int mUnlockSoundId;
-    private int mLockSoundStreamId;
-
-    /**
-     * The volume applied to the lock/unlock sounds.
-     */
-    private final float mLockSoundVolume;
-
-    /**
-     * Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
-     */
-    private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
-
-    /**
-     * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}
-     * various things.
-     */
-    public interface ViewMediatorCallback {
-
-        /**
-         * Wake the device immediately.
-         */
-        void wakeUp();
-
-        /**
-         * Reports user activity and requests that the screen stay on.
-         */
-        void userActivity();
-
-        /**
-         * Reports user activity and requests that the screen stay on for at least
-         * the specified amount of time.
-         * @param millis The amount of time in millis.  This value is currently ignored.
-         */
-        void userActivity(long millis);
-
-        /**
-         * Report that the keyguard is done.
-         * @param authenticated Whether the user securely got past the keyguard.
-         *   the only reason for this to be false is if the keyguard was instructed
-         *   to appear temporarily to verify the user is supposed to get past the
-         *   keyguard, and the user fails to do so.
-         */
-        void keyguardDone(boolean authenticated);
-
-        /**
-         * Report that the keyguard is done drawing.
-         */
-        void keyguardDoneDrawing();
-
-        /**
-         * Tell ViewMediator that the current view needs IME input
-         * @param needsInput
-         */
-        void setNeedsInput(boolean needsInput);
-
-        /**
-         * Tell view mediator that the keyguard view's desired user activity timeout
-         * has changed and needs to be reapplied to the window.
-         */
-        void onUserActivityTimeoutChanged();
-
-        /**
-         * Report that the keyguard is dismissable, pending the next keyguardDone call.
-         */
-        void keyguardDonePending();
-    }
-
-    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
-
-        @Override
-        public void onUserSwitching(int userId) {
-            // Note that the mLockPatternUtils user has already been updated from setCurrentUser.
-            // We need to force a reset of the views, since lockNow (called by
-            // ActivityManagerService) will not reconstruct the keyguard if it is already showing.
-            synchronized (KeyguardViewMediator.this) {
-                mSwitchingUser = true;
-                resetStateLocked(null);
-                adjustStatusBarLocked();
-                // When we switch users we want to bring the new user to the biometric unlock even
-                // if the current user has gone to the backup.
-                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-            }
-        }
-
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            mSwitchingUser = false;
-        }
-
-        @Override
-        public void onUserRemoved(int userId) {
-            mLockPatternUtils.removeUser(userId);
-            sMultiUserAvatarCache.clear(userId);
-        }
-
-        @Override
-        public void onUserInfoChanged(int userId) {
-            sMultiUserAvatarCache.clear(userId);
-        }
-
-        @Override
-        void onPhoneStateChanged(int phoneState) {
-            synchronized (KeyguardViewMediator.this) {
-                if (TelephonyManager.CALL_STATE_IDLE == phoneState  // call ending
-                        && !mScreenOn                           // screen off
-                        && mExternallyEnabled) {                // not disabled by any app
-
-                    // note: this is a way to gracefully reenable the keyguard when the call
-                    // ends and the screen is off without always reenabling the keyguard
-                    // each time the screen turns off while in call (and having an occasional ugly
-                    // flicker while turning back on the screen and disabling the keyguard again).
-                    if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the "
-                            + "keyguard is showing");
-                    doKeyguardLocked();
-                }
-            }
-        };
-
-        @Override
-        public void onClockVisibilityChanged() {
-            adjustStatusBarLocked();
-        }
-
-        @Override
-        public void onDeviceProvisioned() {
-            sendUserPresentBroadcast();
-        }
-
-        @Override
-        public void onSimStateChanged(IccCardConstants.State simState) {
-            if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);
-
-            switch (simState) {
-                case NOT_READY:
-                case ABSENT:
-                    // only force lock screen in case of missing sim if user hasn't
-                    // gone through setup wizard
-                    synchronized (this) {
-                        if (!mUpdateMonitor.isDeviceProvisioned()) {
-                            if (!isShowing()) {
-                                if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing,"
-                                        + " we need to show the keyguard since the "
-                                        + "device isn't provisioned yet.");
-                                doKeyguardLocked();
-                            } else {
-                                resetStateLocked(null);
-                            }
-                        }
-                    }
-                    break;
-                case PIN_REQUIRED:
-                case PUK_REQUIRED:
-                    synchronized (this) {
-                        if (!isShowing()) {
-                            if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
-                                    + "showing; need to show keyguard so user can enter sim pin");
-                            doKeyguardLocked();
-                        } else {
-                            resetStateLocked(null);
-                        }
-                    }
-                    break;
-                case PERM_DISABLED:
-                    synchronized (this) {
-                        if (!isShowing()) {
-                            if (DEBUG) Log.d(TAG, "PERM_DISABLED and "
-                                  + "keygaurd isn't showing.");
-                            doKeyguardLocked();
-                        } else {
-                            if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
-                                  + "show permanently disabled message in lockscreen.");
-                            resetStateLocked(null);
-                        }
-                    }
-                    break;
-                case READY:
-                    synchronized (this) {
-                        if (isShowing()) {
-                            resetStateLocked(null);
-                        }
-                    }
-                    break;
-            }
-        }
-
-    };
-
-    ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
-        public void wakeUp() {
-            KeyguardViewMediator.this.wakeUp();
-        }
-
-        public void userActivity() {
-            KeyguardViewMediator.this.userActivity();
-        }
-
-        public void userActivity(long holdMs) {
-            KeyguardViewMediator.this.userActivity(holdMs);
-        }
-
-        public void keyguardDone(boolean authenticated) {
-            KeyguardViewMediator.this.keyguardDone(authenticated, true);
-        }
-
-        public void keyguardDoneDrawing() {
-            mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING);
-        }
-
-        @Override
-        public void setNeedsInput(boolean needsInput) {
-            mKeyguardViewManager.setNeedsInput(needsInput);
-        }
-
-        @Override
-        public void onUserActivityTimeoutChanged() {
-            mKeyguardViewManager.updateUserActivityTimeout();
-        }
-
-        @Override
-        public void keyguardDonePending() {
-            mKeyguardDonePending = true;
-        }
-    };
-
-    public void wakeUp() {
-        mPM.wakeUp(SystemClock.uptimeMillis());
-    }
-
-    public void userActivity() {
-        userActivity(AWAKE_INTERVAL_DEFAULT_MS);
-    }
-
-    public void userActivity(long holdMs) {
-        // We ignore the hold time.  Eventually we should remove it.
-        // Instead, the keyguard window has an explicit user activity timeout set on it.
-        mPM.userActivity(SystemClock.uptimeMillis(), false);
-    }
-
-    /**
-     * Construct a KeyguardViewMediator
-     * @param context
-     * @param lockPatternUtils optional mock interface for LockPatternUtils
-     */
-    public KeyguardViewMediator(Context context, LockPatternUtils lockPatternUtils) {
-        mContext = context;
-        mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
-        mShowKeyguardWakeLock.setReferenceCounted(false);
-
-        mWakeAndHandOff = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "keyguardWakeAndHandOff");
-        mWakeAndHandOff.setReferenceCounted(false);
-
-        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
-
-        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
-        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
-
-        mLockPatternUtils = lockPatternUtils != null
-                ? lockPatternUtils : new LockPatternUtils(mContext);
-        mLockPatternUtils.setCurrentUser(UserHandle.USER_OWNER);
-
-        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-
-        mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
-                mLockPatternUtils);
-
-        mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT);
-        mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
-                | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
-        final ContentResolver cr = mContext.getContentResolver();
-        mShowLockIcon = (Settings.System.getInt(cr, "show_status_bar_lock", 0) == 1);
-
-        mScreenOn = mPM.isScreenOn();
-
-        mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
-        String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
-        if (soundPath != null) {
-            mLockSoundId = mLockSounds.load(soundPath, 1);
-        }
-        if (soundPath == null || mLockSoundId == 0) {
-            Log.w(TAG, "failed to load lock sound from " + soundPath);
-        }
-        soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
-        if (soundPath != null) {
-            mUnlockSoundId = mLockSounds.load(soundPath, 1);
-        }
-        if (soundPath == null || mUnlockSoundId == 0) {
-            Log.w(TAG, "failed to load unlock sound from " + soundPath);
-        }
-        int lockSoundDefaultAttenuation = context.getResources().getInteger(
-                com.android.internal.R.integer.config_lockSoundVolumeDb);
-        mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
-    }
-
-    /**
-     * Let us know that the system is ready after startup.
-     */
-    public void onSystemReady() {
-        mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        synchronized (this) {
-            if (DEBUG) Log.d(TAG, "onSystemReady");
-            mSystemReady = true;
-            mUpdateMonitor.registerCallback(mUpdateCallback);
-
-            // Suppress biometric unlock right after boot until things have settled if it is the
-            // selected security method, otherwise unsuppress it.  It must be unsuppressed if it is
-            // not the selected security method for the following reason:  if the user starts
-            // without a screen lock selected, the biometric unlock would be suppressed the first
-            // time they try to use it.
-            //
-            // Note that the biometric unlock will still not show if it is not the selected method.
-            // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the
-            // selected method.
-            if (mLockPatternUtils.usingBiometricWeak()
-                    && mLockPatternUtils.isBiometricWeakInstalled()) {
-                if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
-                mUpdateMonitor.setAlternateUnlockEnabled(false);
-            } else {
-                mUpdateMonitor.setAlternateUnlockEnabled(true);
-            }
-
-            doKeyguardLocked();
-        }
-        // Most services aren't available until the system reaches the ready state, so we
-        // send it here when the device first boots.
-        maybeSendUserPresentBroadcast();
-    }
-
-    /**
-     * Called to let us know the screen was turned off.
-     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
-     */
-    public void onScreenTurnedOff(int why) {
-        synchronized (this) {
-            mScreenOn = false;
-            if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")");
-
-            mKeyguardDonePending = false;
-
-            // Lock immediately based on setting if secure (user has a pin/pattern/password).
-            // This also "locks" the device when not secure to provide easy access to the
-            // camera while preventing unwanted input.
-            final boolean lockImmediately =
-                mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
-
-            if (mExitSecureCallback != null) {
-                if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
-                mExitSecureCallback.onKeyguardExitResult(false);
-                mExitSecureCallback = null;
-                if (!mExternallyEnabled) {
-                    hideLocked();
-                }
-            } else if (mShowing) {
-                notifyScreenOffLocked();
-                resetStateLocked(null);
-            } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
-                   || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
-                doKeyguardLaterLocked();
-            } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
-                // Do not enable the keyguard if the prox sensor forced the screen off.
-            } else {
-                doKeyguardLocked();
-            }
-        }
-    }
-
-    private void doKeyguardLaterLocked() {
-        // if the screen turned off because of timeout or the user hit the power button
-        // and we don't need to lock immediately, set an alarm
-        // to enable it a little bit later (i.e, give the user a chance
-        // to turn the screen back on within a certain window without
-        // having to unlock the screen)
-        final ContentResolver cr = mContext.getContentResolver();
-
-        // From DisplaySettings
-        long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
-                KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
-
-        // From SecuritySettings
-        final long lockAfterTimeout = Settings.Secure.getInt(cr,
-                Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
-                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
-
-        // From DevicePolicyAdmin
-        final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
-                .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
-
-        long timeout;
-        if (policyTimeout > 0) {
-            // policy in effect. Make sure we don't go beyond policy limit.
-            displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
-            timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
-        } else {
-            timeout = lockAfterTimeout;
-        }
-
-        if (timeout <= 0) {
-            // Lock now
-            mSuppressNextLockSound = true;
-            doKeyguardLocked();
-        } else {
-            // Lock in the future
-            long when = SystemClock.elapsedRealtime() + timeout;
-            Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
-            intent.putExtra("seq", mDelayedShowingSequence);
-            PendingIntent sender = PendingIntent.getBroadcast(mContext,
-                    0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
-            if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
-                             + mDelayedShowingSequence);
-        }
-    }
-
-    private void cancelDoKeyguardLaterLocked() {
-        mDelayedShowingSequence++;
-    }
-
-    /**
-     * Let's us know the screen was turned on.
-     */
-    public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) {
-        synchronized (this) {
-            mScreenOn = true;
-            cancelDoKeyguardLaterLocked();
-            if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
-            if (showListener != null) {
-                notifyScreenOnLocked(showListener);
-            }
-        }
-        maybeSendUserPresentBroadcast();
-    }
-
-    private void maybeSendUserPresentBroadcast() {
-        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()
-                && mUserManager.getUsers(true).size() == 1) {
-            // Lock screen is disabled because the user has set the preference to "None".
-            // In this case, send out ACTION_USER_PRESENT here instead of in
-            // handleKeyguardDone()
-            sendUserPresentBroadcast();
-        }
-    }
-
-    /**
-     * A dream started.  We should lock after the usual screen-off lock timeout but only
-     * if there is a secure lock pattern.
-     */
-    public void onDreamingStarted() {
-        synchronized (this) {
-            if (mScreenOn && mLockPatternUtils.isSecure()) {
-                doKeyguardLaterLocked();
-            }
-        }
-    }
-
-    /**
-     * A dream stopped.
-     */
-    public void onDreamingStopped() {
-        synchronized (this) {
-            if (mScreenOn) {
-                cancelDoKeyguardLaterLocked();
-            }
-        }
-    }
-
-    /**
-     * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
-     * a way for external stuff to override normal keyguard behavior.  For instance
-     * the phone app disables the keyguard when it receives incoming calls.
-     */
-    public void setKeyguardEnabled(boolean enabled) {
-        synchronized (this) {
-            if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
-
-            mExternallyEnabled = enabled;
-
-            if (!enabled && mShowing) {
-                if (mExitSecureCallback != null) {
-                    if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring");
-                    // we're in the process of handling a request to verify the user
-                    // can get past the keyguard. ignore extraneous requests to disable / reenable
-                    return;
-                }
-
-                // hiding keyguard that is showing, remember to reshow later
-                if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
-                        + "disabling status bar expansion");
-                mNeedToReshowWhenReenabled = true;
-                hideLocked();
-            } else if (enabled && mNeedToReshowWhenReenabled) {
-                // reenabled after previously hidden, reshow
-                if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
-                        + "status bar expansion");
-                mNeedToReshowWhenReenabled = false;
-
-                if (mExitSecureCallback != null) {
-                    if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
-                    mExitSecureCallback.onKeyguardExitResult(false);
-                    mExitSecureCallback = null;
-                    resetStateLocked(null);
-                } else {
-                    showLocked(null);
-
-                    // block until we know the keygaurd is done drawing (and post a message
-                    // to unblock us after a timeout so we don't risk blocking too long
-                    // and causing an ANR).
-                    mWaitingUntilKeyguardVisible = true;
-                    mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS);
-                    if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false");
-                    while (mWaitingUntilKeyguardVisible) {
-                        try {
-                            wait();
-                        } catch (InterruptedException e) {
-                            Thread.currentThread().interrupt();
-                        }
-                    }
-                    if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible");
-                }
-            }
-        }
-    }
-
-    /**
-     * @see android.app.KeyguardManager#exitKeyguardSecurely
-     */
-    public void verifyUnlock(WindowManagerPolicy.OnKeyguardExitResult callback) {
-        synchronized (this) {
-            if (DEBUG) Log.d(TAG, "verifyUnlock");
-            if (!mUpdateMonitor.isDeviceProvisioned()) {
-                // don't allow this api when the device isn't provisioned
-                if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned");
-                callback.onKeyguardExitResult(false);
-            } else if (mExternallyEnabled) {
-                // this only applies when the user has externally disabled the
-                // keyguard.  this is unexpected and means the user is not
-                // using the api properly.
-                Log.w(TAG, "verifyUnlock called when not externally disabled");
-                callback.onKeyguardExitResult(false);
-            } else if (mExitSecureCallback != null) {
-                // already in progress with someone else
-                callback.onKeyguardExitResult(false);
-            } else {
-                mExitSecureCallback = callback;
-                verifyUnlockLocked();
-            }
-        }
-    }
-
-    /**
-     * Is the keyguard currently showing?
-     */
-    public boolean isShowing() {
-        return mShowing;
-    }
-
-    /**
-     * Is the keyguard currently showing and not being force hidden?
-     */
-    public boolean isShowingAndNotHidden() {
-        return mShowing && !mHidden;
-    }
-
-    /**
-     * Notify us when the keyguard is hidden by another window
-     */
-    public void setHidden(boolean isHidden) {
-        if (DEBUG) Log.d(TAG, "setHidden " + isHidden);
-        mUpdateMonitor.sendKeyguardVisibilityChanged(!isHidden);
-        mHandler.removeMessages(SET_HIDDEN);
-        Message msg = mHandler.obtainMessage(SET_HIDDEN, (isHidden ? 1 : 0), 0);
-        mHandler.sendMessage(msg);
-    }
-
-    /**
-     * Handles SET_HIDDEN message sent by setHidden()
-     */
-    private void handleSetHidden(boolean isHidden) {
-        synchronized (KeyguardViewMediator.this) {
-            if (mHidden != isHidden) {
-                mHidden = isHidden;
-                updateActivityLockScreenState();
-                adjustStatusBarLocked();
-            }
-        }
-    }
-
-    /**
-     * Used by PhoneWindowManager to enable the keyguard due to a user activity timeout.
-     * This must be safe to call from any thread and with any window manager locks held.
-     */
-    public void doKeyguardTimeout(Bundle options) {
-        mHandler.removeMessages(KEYGUARD_TIMEOUT);
-        Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT, options);
-        mHandler.sendMessage(msg);
-    }
-
-    /**
-     * Given the state of the keyguard, is the input restricted?
-     * Input is restricted when the keyguard is showing, or when the keyguard
-     * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet.
-     */
-    public boolean isInputRestricted() {
-        return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned();
-    }
-
-    private void doKeyguardLocked() {
-        doKeyguardLocked(null);
-    }
-
-    /**
-     * Enable the keyguard if the settings are appropriate.
-     */
-    private void doKeyguardLocked(Bundle options) {
-        // if another app is disabling us, don't show
-        if (!mExternallyEnabled) {
-            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
-
-            // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes
-            // for an occasional ugly flicker in this situation:
-            // 1) receive a call with the screen on (no keyguard) or make a call
-            // 2) screen times out
-            // 3) user hits key to turn screen back on
-            // instead, we reenable the keyguard when we know the screen is off and the call
-            // ends (see the broadcast receiver below)
-            // TODO: clean this up when we have better support at the window manager level
-            // for apps that wish to be on top of the keyguard
-            return;
-        }
-
-        // if the keyguard is already showing, don't bother
-        if (mKeyguardViewManager.isShowing()) {
-            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
-            return;
-        }
-
-        // if the setup wizard hasn't run yet, don't show
-        final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim",
-                false);
-        final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
-        final IccCardConstants.State state = mUpdateMonitor.getSimState();
-        final boolean lockedOrMissing = state.isPinLocked()
-                || ((state == IccCardConstants.State.ABSENT
-                || state == IccCardConstants.State.PERM_DISABLED)
-                && requireSim);
-
-        if (!lockedOrMissing && !provisioned) {
-            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
-                    + " and the sim is not locked or missing");
-            return;
-        }
-
-        if (mUserManager.getUsers(true).size() < 2
-                && mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {
-            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
-        showLocked(options);
-    }
-
-    /**
-     * Dismiss the keyguard through the security layers.
-     */
-    public void dismiss() {
-        if (mShowing && !mHidden) {
-            mKeyguardViewManager.dismiss();
-        }
-    }
-
-    /**
-     * Send message to keyguard telling it to reset its state.
-     * @param options options about how to show the keyguard
-     * @see #handleReset()
-     */
-    private void resetStateLocked(Bundle options) {
-        if (DEBUG) Log.e(TAG, "resetStateLocked");
-        Message msg = mHandler.obtainMessage(RESET, options);
-        mHandler.sendMessage(msg);
-    }
-
-    /**
-     * Send message to keyguard telling it to verify unlock
-     * @see #handleVerifyUnlock()
-     */
-    private void verifyUnlockLocked() {
-        if (DEBUG) Log.d(TAG, "verifyUnlockLocked");
-        mHandler.sendEmptyMessage(VERIFY_UNLOCK);
-    }
-
-
-    /**
-     * Send a message to keyguard telling it the screen just turned on.
-     * @see #onScreenTurnedOff(int)
-     * @see #handleNotifyScreenOff
-     */
-    private void notifyScreenOffLocked() {
-        if (DEBUG) Log.d(TAG, "notifyScreenOffLocked");
-        mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF);
-    }
-
-    /**
-     * Send a message to keyguard telling it the screen just turned on.
-     * @see #onScreenTurnedOn()
-     * @see #handleNotifyScreenOn
-     */
-    private void notifyScreenOnLocked(KeyguardViewManager.ShowListener showListener) {
-        if (DEBUG) Log.d(TAG, "notifyScreenOnLocked");
-        Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_ON, showListener);
-        mHandler.sendMessage(msg);
-    }
-
-    /**
-     * Send message to keyguard telling it about a wake key so it can adjust
-     * its state accordingly and then poke the wake lock when it is ready.
-     * @param keyCode The wake key.
-     * @see #handleWakeWhenReady
-     * @see #onWakeKeyWhenKeyguardShowingTq(int)
-     */
-    private void wakeWhenReady(int keyCode) {
-        if (DBG_WAKE) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
-
-        /**
-         * acquire the handoff lock that will keep the cpu running.  this will
-         * be released once the keyguard has set itself up and poked the other wakelock
-         * in {@link #handleWakeWhenReady(int)}
-         */
-        mWakeAndHandOff.acquire();
-
-        Message msg = mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0);
-        mHandler.sendMessage(msg);
-    }
-
-    /**
-     * Send message to keyguard telling it to show itself
-     * @see #handleShow()
-     */
-    private void showLocked(Bundle options) {
-        if (DEBUG) Log.d(TAG, "showLocked");
-        // ensure we stay awake until we are finished displaying the keyguard
-        mShowKeyguardWakeLock.acquire();
-        Message msg = mHandler.obtainMessage(SHOW, options);
-        mHandler.sendMessage(msg);
-    }
-
-    /**
-     * Send message to keyguard telling it to hide itself
-     * @see #handleHide()
-     */
-    private void hideLocked() {
-        if (DEBUG) Log.d(TAG, "hideLocked");
-        Message msg = mHandler.obtainMessage(HIDE);
-        mHandler.sendMessage(msg);
-    }
-
-    public boolean isSecure() {
-        return mLockPatternUtils.isSecure()
-            || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure();
-    }
-
-    /**
-     * Update the newUserId. Call while holding WindowManagerService lock.
-     * NOTE: Should only be called by KeyguardViewMediator in response to the user id changing.
-     *
-     * @param newUserId The id of the incoming user.
-     */
-    public void setCurrentUser(int newUserId) {
-        mLockPatternUtils.setCurrentUser(newUserId);
-    }
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (DELAYED_KEYGUARD_ACTION.equals(intent.getAction())) {
-                final int sequence = intent.getIntExtra("seq", 0);
-                if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
-                        + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
-                synchronized (KeyguardViewMediator.this) {
-                    if (mDelayedShowingSequence == sequence) {
-                        // Don't play lockscreen SFX if the screen went off due to timeout.
-                        mSuppressNextLockSound = true;
-                        doKeyguardLocked();
-                    }
-                }
-            }
-        }
-    };
-
-    /**
-     * When a key is received when the screen is off and the keyguard is showing,
-     * we need to decide whether to actually turn on the screen, and if so, tell
-     * the keyguard to prepare itself and poke the wake lock when it is ready.
-     *
-     * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}.
-     * Be sure not to take any action that takes a long time; any significant
-     * action should be posted to a handler.
-     *
-     * @param keyCode The keycode of the key that woke the device
-     */
-    public void onWakeKeyWhenKeyguardShowingTq(int keyCode) {
-        if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")");
-
-        // give the keyguard view manager a chance to adjust the state of the
-        // keyguard based on the key that woke the device before poking
-        // the wake lock
-        wakeWhenReady(keyCode);
-    }
-
-    /**
-     * When a wake motion such as an external mouse movement is received when the screen
-     * is off and the keyguard is showing, we need to decide whether to actually turn
-     * on the screen, and if so, tell the keyguard to prepare itself and poke the wake
-     * lock when it is ready.
-     *
-     * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}.
-     * Be sure not to take any action that takes a long time; any significant
-     * action should be posted to a handler.
-     */
-    public void onWakeMotionWhenKeyguardShowingTq() {
-        if (DEBUG) Log.d(TAG, "onWakeMotionWhenKeyguardShowing()");
-
-        // give the keyguard view manager a chance to adjust the state of the
-        // keyguard based on the key that woke the device before poking
-        // the wake lock
-        wakeWhenReady(KeyEvent.KEYCODE_UNKNOWN);
-    }
-
-    public void keyguardDone(boolean authenticated, boolean wakeup) {
-        mKeyguardDonePending = false;
-        synchronized (this) {
-            EventLog.writeEvent(70000, 2);
-            if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")");
-            Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
-            msg.arg1 = wakeup ? 1 : 0;
-            mHandler.sendMessage(msg);
-
-            if (authenticated) {
-                mUpdateMonitor.clearFailedUnlockAttempts();
-            }
-
-            if (mExitSecureCallback != null) {
-                mExitSecureCallback.onKeyguardExitResult(authenticated);
-                mExitSecureCallback = null;
-
-                if (authenticated) {
-                    // after succesfully exiting securely, no need to reshow
-                    // the keyguard when they've released the lock
-                    mExternallyEnabled = true;
-                    mNeedToReshowWhenReenabled = false;
-                }
-            }
-        }
-    }
-
-    /**
-     * This handler will be associated with the policy thread, which will also
-     * be the UI thread of the keyguard.  Since the apis of the policy, and therefore
-     * this class, can be called by other threads, any action that directly
-     * interacts with the keyguard ui should be posted to this handler, rather
-     * than called directly.
-     */
-    private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case SHOW:
-                    handleShow((Bundle) msg.obj);
-                    return ;
-                case HIDE:
-                    handleHide();
-                    return ;
-                case RESET:
-                    handleReset((Bundle) msg.obj);
-                    return ;
-                case VERIFY_UNLOCK:
-                    handleVerifyUnlock();
-                    return;
-                case NOTIFY_SCREEN_OFF:
-                    handleNotifyScreenOff();
-                    return;
-                case NOTIFY_SCREEN_ON:
-                    handleNotifyScreenOn((KeyguardViewManager.ShowListener)msg.obj);
-                    return;
-                case WAKE_WHEN_READY:
-                    handleWakeWhenReady(msg.arg1);
-                    return;
-                case KEYGUARD_DONE:
-                    handleKeyguardDone(msg.arg1 != 0);
-                    return;
-                case KEYGUARD_DONE_DRAWING:
-                    handleKeyguardDoneDrawing();
-                    return;
-                case KEYGUARD_DONE_AUTHENTICATING:
-                    keyguardDone(true, true);
-                    return;
-                case SET_HIDDEN:
-                    handleSetHidden(msg.arg1 != 0);
-                    break;
-                case KEYGUARD_TIMEOUT:
-                    synchronized (KeyguardViewMediator.this) {
-                        doKeyguardLocked((Bundle) msg.obj);
-                    }
-                    break;
-                case SHOW_ASSISTANT:
-                    handleShowAssistant();
-                    break;
-            }
-        }
-    };
-
-    /**
-     * @see #keyguardDone
-     * @see #KEYGUARD_DONE
-     */
-    private void handleKeyguardDone(boolean wakeup) {
-        if (DEBUG) Log.d(TAG, "handleKeyguardDone");
-        handleHide();
-        if (wakeup) {
-            wakeUp();
-        }
-
-        sendUserPresentBroadcast();
-    }
-
-    private void sendUserPresentBroadcast() {
-        if (!(mContext instanceof Activity)) {
-            final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
-            mContext.sendBroadcastAsUser(mUserPresentIntent, currentUser);
-        }
-    }
-
-    /**
-     * @see #keyguardDoneDrawing
-     * @see #KEYGUARD_DONE_DRAWING
-     */
-    private void handleKeyguardDoneDrawing() {
-        synchronized(this) {
-            if (false) Log.d(TAG, "handleKeyguardDoneDrawing");
-            if (mWaitingUntilKeyguardVisible) {
-                if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible");
-                mWaitingUntilKeyguardVisible = false;
-                notifyAll();
-
-                // there will usually be two of these sent, one as a timeout, and one
-                // as a result of the callback, so remove any remaining messages from
-                // the queue
-                mHandler.removeMessages(KEYGUARD_DONE_DRAWING);
-            }
-        }
-    }
-
-    private void playSounds(boolean locked) {
-        // User feedback for keyguard.
-
-        if (mSuppressNextLockSound) {
-            mSuppressNextLockSound = false;
-            return;
-        }
-
-        final ContentResolver cr = mContext.getContentResolver();
-        if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) {
-            final int whichSound = locked
-                ? mLockSoundId
-                : mUnlockSoundId;
-            mLockSounds.stop(mLockSoundStreamId);
-            // Init mAudioManager
-            if (mAudioManager == null) {
-                mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-                if (mAudioManager == null) return;
-                mMasterStreamType = mAudioManager.getMasterStreamType();
-            }
-            // If the stream is muted, don't play the sound
-            if (mAudioManager.isStreamMute(mMasterStreamType)) return;
-
-            mLockSoundStreamId = mLockSounds.play(whichSound,
-                    mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
-        }
-    }
-
-    private void updateActivityLockScreenState() {
-        try {
-            ActivityManagerNative.getDefault().setLockScreenShown(
-                    mShowing && !mHidden);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #showLocked}.
-     * @see #SHOW
-     */
-    private void handleShow(Bundle options) {
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleShow");
-            if (!mSystemReady) return;
-
-            mKeyguardViewManager.show(options);
-            mShowing = true;
-            mKeyguardDonePending = false;
-            updateActivityLockScreenState();
-            adjustStatusBarLocked();
-            userActivity();
-            try {
-                ActivityManagerNative.getDefault().closeSystemDialogs("lock");
-            } catch (RemoteException e) {
-            }
-
-            // Do this at the end to not slow down display of the keyguard.
-            playSounds(true);
-
-            mShowKeyguardWakeLock.release();
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #hideLocked()}
-     * @see #HIDE
-     */
-    private void handleHide() {
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleHide");
-            if (mWakeAndHandOff.isHeld()) {
-                Log.w(TAG, "attempt to hide the keyguard while waking, ignored");
-                return;
-            }
-
-            // only play "unlock" noises if not on a call (since the incall UI
-            // disables the keyguard)
-            if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
-                playSounds(false);
-            }
-
-            mKeyguardViewManager.hide();
-            mShowing = false;
-            mKeyguardDonePending = false;
-            updateActivityLockScreenState();
-            adjustStatusBarLocked();
-        }
-    }
-
-    private void adjustStatusBarLocked() {
-        if (mStatusBarManager == null) {
-            mStatusBarManager = (StatusBarManager)
-                    mContext.getSystemService(Context.STATUS_BAR_SERVICE);
-        }
-        if (mStatusBarManager == null) {
-            Log.w(TAG, "Could not get status bar manager");
-        } else {
-            if (mShowLockIcon) {
-                // Give feedback to user when secure keyguard is active and engaged
-                if (mShowing && isSecure()) {
-                    if (!mShowingLockIcon) {
-                        String contentDescription = mContext.getString(
-                                com.android.internal.R.string.status_bar_device_locked);
-                        mStatusBarManager.setIcon("secure",
-                                com.android.internal.R.drawable.stat_sys_secure, 0,
-                                contentDescription);
-                        mShowingLockIcon = true;
-                    }
-                } else {
-                    if (mShowingLockIcon) {
-                        mStatusBarManager.removeIcon("secure");
-                        mShowingLockIcon = false;
-                    }
-                }
-            }
-
-            // Disable aspects of the system/status/navigation bars that must not be re-enabled by
-            // windows that appear on top, ever
-            int flags = StatusBarManager.DISABLE_NONE;
-            if (mShowing) {
-                // Permanently disable components not available when keyguard is enabled
-                // (like recents). Temporary enable/disable (e.g. the "back" button) are
-                // done in KeyguardHostView.
-                flags |= StatusBarManager.DISABLE_RECENT;
-                if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
-                    // showing secure lockscreen; disable expanding.
-                    flags |= StatusBarManager.DISABLE_EXPAND;
-                }
-                if (isSecure()) {
-                    // showing secure lockscreen; disable ticker.
-                    flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER;
-                }
-                if (!isAssistantAvailable()) {
-                    flags |= StatusBarManager.DISABLE_SEARCH;
-                }
-            }
-
-            if (DEBUG) {
-                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
-                        + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
-            }
-
-            if (!(mContext instanceof Activity)) {
-                mStatusBarManager.disable(flags);
-            }
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #wakeWhenReady(int)}
-     * @param keyCode The key that woke the device.
-     * @see #WAKE_WHEN_READY
-     */
-    private void handleWakeWhenReady(int keyCode) {
-        synchronized (KeyguardViewMediator.this) {
-            if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")");
-
-            // this should result in a call to 'poke wakelock' which will set a timeout
-            // on releasing the wakelock
-            if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) {
-                // poke wakelock ourselves if keyguard is no longer active
-                Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves");
-                userActivity();
-            }
-
-            /**
-             * Now that the keyguard is ready and has poked the wake lock, we can
-             * release the handoff wakelock
-             */
-            mWakeAndHandOff.release();
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #resetStateLocked(Bundle)}
-     * @see #RESET
-     */
-    private void handleReset(Bundle options) {
-        if (options == null) {
-            options = new Bundle();
-        }
-        options.putBoolean(KeyguardViewManager.IS_SWITCHING_USER, mSwitchingUser);
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleReset");
-            mKeyguardViewManager.reset(options);
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #verifyUnlock}
-     * @see #VERIFY_UNLOCK
-     */
-    private void handleVerifyUnlock() {
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
-            mKeyguardViewManager.verifyUnlock();
-            mShowing = true;
-            updateActivityLockScreenState();
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #notifyScreenOffLocked()}
-     * @see #NOTIFY_SCREEN_OFF
-     */
-    private void handleNotifyScreenOff() {
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleNotifyScreenOff");
-            mKeyguardViewManager.onScreenTurnedOff();
-        }
-    }
-
-    /**
-     * Handle message sent by {@link #notifyScreenOnLocked()}
-     * @see #NOTIFY_SCREEN_ON
-     */
-    private void handleNotifyScreenOn(KeyguardViewManager.ShowListener showListener) {
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleNotifyScreenOn");
-            mKeyguardViewManager.onScreenTurnedOn(showListener);
-        }
-    }
-
-    public boolean isDismissable() {
-        return mKeyguardDonePending || !isSecure();
-    }
-
-    public void showAssistant() {
-        Message msg = mHandler.obtainMessage(SHOW_ASSISTANT);
-        mHandler.sendMessage(msg);
-    }
-
-    public void handleShowAssistant() {
-        mKeyguardViewManager.showAssistant();
-    }
-
-    private boolean isAssistantAvailable() {
-        return mSearchManager != null
-                && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
-    }
-
-    public static MultiUserAvatarCache getAvatarCache() {
-        return sMultiUserAvatarCache;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
deleted file mode 100644
index 4410063..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.view.View;
-
-public class KeyguardViewStateManager implements
-        SlidingChallengeLayout.OnChallengeScrolledListener,
-        ChallengeLayout.OnBouncerStateChangedListener {
-
-    private KeyguardWidgetPager mKeyguardWidgetPager;
-    private ChallengeLayout mChallengeLayout;
-    private KeyguardHostView mKeyguardHostView;
-    private int[] mTmpPoint = new int[2];
-    private int[] mTmpLoc = new int[2];
-
-    private KeyguardSecurityView mKeyguardSecurityContainer;
-    private static final int SCREEN_ON_HINT_DURATION = 1000;
-    private static final int SCREEN_ON_RING_HINT_DELAY = 300;
-    Handler mMainQueue = new Handler(Looper.myLooper());
-
-    int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
-
-    // Paged view state
-    private int mPageListeningToSlider = -1;
-    private int mCurrentPage = -1;
-    private int mPageIndexOnPageBeginMoving = -1;
-
-    int mChallengeTop = 0;
-
-    public KeyguardViewStateManager(KeyguardHostView hostView) {
-        mKeyguardHostView = hostView;
-    }
-
-    public void setPagedView(KeyguardWidgetPager pagedView) {
-        mKeyguardWidgetPager = pagedView;
-        updateEdgeSwiping();
-    }
-
-    public void setChallengeLayout(ChallengeLayout layout) {
-        mChallengeLayout = layout;
-        updateEdgeSwiping();
-    }
-
-    private void updateEdgeSwiping() {
-        if (mChallengeLayout != null && mKeyguardWidgetPager != null) {
-            if (mChallengeLayout.isChallengeOverlapping()) {
-                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true);
-            } else {
-                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false);
-            }
-        }
-    }
-
-    public boolean isChallengeShowing() {
-        if (mChallengeLayout != null) {
-            return mChallengeLayout.isChallengeShowing();
-        }
-        return false;
-    }
-
-    public boolean isChallengeOverlapping() {
-        if (mChallengeLayout != null) {
-            return mChallengeLayout.isChallengeOverlapping();
-        }
-        return false;
-    }
-
-    public void setSecurityViewContainer(KeyguardSecurityView container) {
-        mKeyguardSecurityContainer = container;
-    }
-
-    public void showBouncer(boolean show) {
-        mChallengeLayout.showBouncer();
-    }
-
-    public boolean isBouncing() {
-        return mChallengeLayout.isBouncing();
-    }
-
-    public void fadeOutSecurity(int duration) {
-        ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
-    }
-
-    public void fadeInSecurity(int duration) {
-        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
-    }
-
-    public void onPageBeginMoving() {
-        if (mChallengeLayout.isChallengeOverlapping() &&
-                mChallengeLayout instanceof SlidingChallengeLayout) {
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            scl.fadeOutChallenge();
-            mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
-        }
-        // We use mAppWidgetToShow to show a particular widget after you add it--
-        // once the user swipes a page we clear that behavior
-        if (mKeyguardHostView != null) {
-            mKeyguardHostView.clearAppWidgetToShow();
-            mKeyguardHostView.setOnDismissAction(null);
-        }
-        if (mHideHintsRunnable != null) {
-            mMainQueue.removeCallbacks(mHideHintsRunnable);
-            mHideHintsRunnable = null;
-        }
-    }
-
-    public void onPageEndMoving() {
-        mPageIndexOnPageBeginMoving = -1;
-    }
-
-    public void onPageSwitching(View newPage, int newPageIndex) {
-        if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
-            boolean isCameraPage = newPage instanceof CameraWidgetFrame;
-            ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage);
-        }
-
-        // If the page we're settling to is the same as we started on, and the action of
-        // moving the page hid the security, we restore it immediately.
-        if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() &&
-                mChallengeLayout instanceof SlidingChallengeLayout) {
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            scl.fadeInChallenge();
-            mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1);
-        }
-        mPageIndexOnPageBeginMoving = -1;
-    }
-
-    public void onPageSwitched(View newPage, int newPageIndex) {
-        // Reset the previous page size and ensure the current page is sized appropriately.
-        // We only modify the page state if it is not currently under control by the slider.
-        // This prevents conflicts.
-
-        // If the page hasn't switched, don't bother with any of this
-        if (mCurrentPage == newPageIndex) return;
-
-        if (mKeyguardWidgetPager != null && mChallengeLayout != null) {
-            KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage);
-            if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage
-                    != mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) {
-                prevPage.resetSize();
-            }
-
-            KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex);
-            boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
-            if (challengeOverlapping && !newCurPage.isSmall()
-                    && mPageListeningToSlider != newPageIndex) {
-                newCurPage.shrinkWidget();
-            }
-        }
-
-        mCurrentPage = newPageIndex;
-    }
-
-    private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
-        mTmpPoint[0] = 0;
-        mTmpPoint[1] = top;
-        mapPoint((View) mChallengeLayout, frame, mTmpPoint);
-        return mTmpPoint[1];
-    }
-
-    /**
-     * Simple method to map a point from one view's coordinates to another's. Note: this method
-     * doesn't account for transforms, so if the views will be transformed, this should not be used.
-     *
-     * @param fromView The view to which the point is relative
-     * @param toView The view into which the point should be mapped
-     * @param pt The point
-     */
-    private void mapPoint(View fromView, View toView, int pt[]) {
-        fromView.getLocationInWindow(mTmpLoc);
-
-        int x = mTmpLoc[0];
-        int y = mTmpLoc[1];
-
-        toView.getLocationInWindow(mTmpLoc);
-        int vX = mTmpLoc[0];
-        int vY = mTmpLoc[1];
-
-        pt[0] += x - vX;
-        pt[1] += y - vY;
-    }
-
-    private void userActivity() {
-        if (mKeyguardHostView != null) {
-            mKeyguardHostView.onUserActivityTimeoutChanged();
-            mKeyguardHostView.userActivity();
-        }
-    }
-
-    @Override
-    public void onScrollStateChanged(int scrollState) {
-        if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
-
-        boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
-
-        if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
-            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
-            if (frame == null) return;
-
-            if (!challengeOverlapping) {
-                if (!mKeyguardWidgetPager.isPageMoving()) {
-                    frame.resetSize();
-                    userActivity();
-                } else {
-                    mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
-                }
-            }
-            if (frame.isSmall()) {
-                // This is to make sure that if the scroller animation gets cut off midway
-                // that the frame doesn't stay in a partial down position.
-                frame.setFrameHeight(frame.getSmallFrameHeight());
-            }
-            if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
-                frame.hideFrame(this);
-            }
-            updateEdgeSwiping();
-
-            if (mChallengeLayout.isChallengeShowing()) {
-                mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED);
-            } else {
-                mKeyguardSecurityContainer.onPause();
-            }
-            mPageListeningToSlider = -1;
-        } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
-            // Whether dragging or settling, if the last state was idle, we use this signal
-            // to update the current page who will receive events from the sliding challenge.
-            // We resize the frame as appropriate.
-            mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
-            if (frame == null) return;
-
-            // Skip showing the frame and shrinking the widget if we are
-            if (!mChallengeLayout.isBouncing()) {
-                if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
-                    frame.showFrame(this);
-                }
-
-                // As soon as the security begins sliding, the widget becomes small (if it wasn't
-                // small to begin with).
-                if (!frame.isSmall()) {
-                    // We need to fetch the final page, in case the pages are in motion.
-                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-                    frame.shrinkWidget(false);
-                }
-            } else {
-                if (!frame.isSmall()) {
-                    // We need to fetch the final page, in case the pages are in motion.
-                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-                }
-            }
-
-            // View is on the move.  Pause the security view until it completes.
-            mKeyguardSecurityContainer.onPause();
-        }
-        mLastScrollState = scrollState;
-    }
-
-    @Override
-    public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
-        mChallengeTop = challengeTop;
-        KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
-        if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
-            frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
-        }
-    }
-
-    private Runnable mHideHintsRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (mKeyguardWidgetPager != null) {
-                mKeyguardWidgetPager.hideOutlinesAndSidePages();
-            }
-        }
-    };
-
-    public void showUsabilityHints() {
-        mMainQueue.postDelayed( new Runnable() {
-            @Override
-            public void run() {
-                mKeyguardSecurityContainer.showUsabilityHint();
-            }
-        } , SCREEN_ON_RING_HINT_DELAY);
-        mKeyguardWidgetPager.showInitialPageHints();
-        if (mHideHintsRunnable != null) {
-            mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
-        }
-    }
-
-    // ChallengeLayout.OnBouncerStateChangedListener
-    @Override
-    public void onBouncerStateChanged(boolean bouncerActive) {
-        if (bouncerActive) {
-            mKeyguardWidgetPager.zoomOutToBouncer();
-        } else {
-            mKeyguardWidgetPager.zoomInFromBouncer();
-            if (mKeyguardHostView != null) {
-                mKeyguardHostView.setOnDismissAction(null);
-            }
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
deleted file mode 100644
index 257fd27..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-
-public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
-
-    private float mAdjacentPagesAngle;
-    private static float MAX_SCROLL_PROGRESS = 1.3f;
-    private static float CAMERA_DISTANCE = 10000;
-    protected AnimatorSet mChildrenTransformsAnimator;
-    float[] mTmpTransform = new float[3];
-
-    public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetCarousel(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle);
-    }
-
-    protected float getMaxScrollProgress() {
-        return MAX_SCROLL_PROGRESS;
-    }
-
-    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        View child = getChildAt(index);
-        if (child == null) return 0f;
-
-        boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
-        float scrollProgress = getScrollProgress(screenCenter, child, index);
-
-        if (isOverScrollChild(index, scrollProgress)) {
-            return 1.0f;
-        } else if ((showSidePages && inVisibleRange) || index == getNextPage()) {
-            scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
-            float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
-            return alpha;
-        } else {
-            return 0f;
-        }
-    }
-
-    public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
-        if (inVisibleRange) {
-            return super.getOutlineAlphaForPage(screenCenter, index, showSidePages);
-        } else {
-            return 0f;
-        }
-    }
-
-    private void updatePageAlphaValues(int screenCenter) {
-        if (mChildrenOutlineFadeAnimation != null) {
-            mChildrenOutlineFadeAnimation.cancel();
-            mChildrenOutlineFadeAnimation = null;
-        }
-        boolean showSidePages = mShowingInitialHints || isPageMoving();
-        if (!isReordering(false)) {
-            for (int i = 0; i < getChildCount(); i++) {
-                KeyguardWidgetFrame child = getWidgetPageAt(i);
-                if (child != null) {
-                    float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages);
-                    float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages);
-                    child.setBackgroundAlpha(outlineAlpha);
-                    child.setContentAlpha(contentAlpha);
-                }
-            }
-        }
-    }
-
-    public void showInitialPageHints() {
-        mShowingInitialHints = true;
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1;
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            if (inVisibleRange) {
-                child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
-                child.setContentAlpha(1f);
-            } else {
-                child.setBackgroundAlpha(0f);
-                child.setContentAlpha(0f);
-            }
-        }
-    }
-
-    @Override
-    protected void screenScrolled(int screenCenter) {
-        mScreenCenter = screenCenter;
-        updatePageAlphaValues(screenCenter);
-        if (isReordering(false)) return;
-        for (int i = 0; i < getChildCount(); i++) {
-            KeyguardWidgetFrame v = getWidgetPageAt(i);
-            float scrollProgress = getScrollProgress(screenCenter, v, i);
-            float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
-            if (v == mDragView || v == null) continue;
-            v.setCameraDistance(CAMERA_DISTANCE);
-
-            if (isOverScrollChild(i, scrollProgress)) {
-                v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
-                v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
-            } else {
-                int width = v.getMeasuredWidth();
-                float pivotX = (width / 2f) + boundedProgress * (width / 2f);
-                float pivotY = v.getMeasuredHeight() / 2;
-                float rotationY = - mAdjacentPagesAngle * boundedProgress;
-                v.setPivotX(pivotX);
-                v.setPivotY(pivotY);
-                v.setRotationY(rotationY);
-                v.setOverScrollAmount(0f, false);
-            }
-            float alpha = v.getAlpha();
-            // If the view has 0 alpha, we set it to be invisible so as to prevent
-            // it from accepting touches
-            if (alpha == 0) {
-                v.setVisibility(INVISIBLE);
-            } else if (v.getVisibility() != VISIBLE) {
-                v.setVisibility(VISIBLE);
-            }
-        }
-    }
-
-    void animatePagesToNeutral() {
-        if (mChildrenTransformsAnimator != null) {
-            mChildrenTransformsAnimator.cancel();
-            mChildrenTransformsAnimator = null;
-        }
-
-        int count = getChildCount();
-        PropertyValuesHolder alpha;
-        PropertyValuesHolder outlineAlpha;
-        PropertyValuesHolder rotationY;
-        ArrayList<Animator> anims = new ArrayList<Animator>();
-
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
-            if (!inVisibleRange) {
-                child.setRotationY(0f);
-            }
-            alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
-            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
-                    KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
-            rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
-            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
-            child.setVisibility(VISIBLE);
-            if (!inVisibleRange) {
-                a.setInterpolator(mSlowFadeInterpolator);
-            }
-            anims.add(a);
-        }
-
-        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
-        mChildrenTransformsAnimator = new AnimatorSet();
-        mChildrenTransformsAnimator.playTogether(anims);
-
-        mChildrenTransformsAnimator.setDuration(duration);
-        mChildrenTransformsAnimator.start();
-    }
-
-    private void getTransformForPage(int screenCenter, int index, float[] transform) {
-        View child = getChildAt(index);
-        float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
-        float rotationY = - mAdjacentPagesAngle * boundedProgress;
-        int width = child.getMeasuredWidth();
-        float pivotX = (width / 2f) + boundedProgress * (width / 2f);
-        float pivotY = child.getMeasuredHeight() / 2;
-
-        transform[0] = pivotX;
-        transform[1] = pivotY;
-        transform[2] = rotationY;
-    }
-
-    Interpolator mFastFadeInterpolator = new Interpolator() {
-        Interpolator mInternal = new DecelerateInterpolator(1.5f);
-        float mFactor = 2.5f;
-        @Override
-        public float getInterpolation(float input) {
-            return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
-        }
-    };
-
-    Interpolator mSlowFadeInterpolator = new Interpolator() {
-        Interpolator mInternal = new AccelerateInterpolator(1.5f);
-        float mFactor = 1.3f;
-        @Override
-        public float getInterpolation(float input) {
-            input -= (1 - 1 / mFactor);
-            input = mFactor * Math.max(input, 0f);
-            return mInternal.getInterpolation(input);
-        }
-    };
-
-    void animatePagesToCarousel() {
-        if (mChildrenTransformsAnimator != null) {
-            mChildrenTransformsAnimator.cancel();
-            mChildrenTransformsAnimator = null;
-        }
-
-        int count = getChildCount();
-        PropertyValuesHolder alpha;
-        PropertyValuesHolder outlineAlpha;
-        PropertyValuesHolder rotationY;
-        PropertyValuesHolder pivotX;
-        PropertyValuesHolder pivotY;
-        ArrayList<Animator> anims = new ArrayList<Animator>();
-
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            float finalAlpha = getAlphaForPage(mScreenCenter, i, true);
-            float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true);
-            getTransformForPage(mScreenCenter, i, mTmpTransform);
-
-            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
-
-            ObjectAnimator a;
-            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
-            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
-            pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
-            pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
-            rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
-
-            if (inVisibleRange) {
-                // for the central pages we animate into a rotated state
-                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
-                        pivotX, pivotY, rotationY);
-            } else {
-                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
-                a.setInterpolator(mFastFadeInterpolator);
-            }
-            anims.add(a);
-        }
-
-        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
-        mChildrenTransformsAnimator = new AnimatorSet();
-        mChildrenTransformsAnimator.playTogether(anims);
-
-        mChildrenTransformsAnimator.setDuration(duration);
-        mChildrenTransformsAnimator.start();
-    }
-
-    protected void reorderStarting() {
-        mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
-        animatePagesToNeutral();
-    }
-
-    protected boolean zoomIn(final Runnable onCompleteRunnable) {
-        animatePagesToCarousel();
-        return super.zoomIn(onCompleteRunnable);
-    }
-
-    @Override
-    protected void onEndReordering() {
-        super.onEndReordering();
-        mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
deleted file mode 100644
index babb9cb..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.internal.R;
-
-public class KeyguardWidgetFrame extends FrameLayout {
-    private final static PorterDuffXfermode sAddBlendMode =
-            new PorterDuffXfermode(PorterDuff.Mode.ADD);
-
-    static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f;
-    static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000;
-
-    // Temporarily disable this for the time being until we know why the gfx is messing up
-    static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true;
-
-    private int mGradientColor;
-    private LinearGradient mForegroundGradient;
-    private LinearGradient mLeftToRightGradient;
-    private LinearGradient mRightToLeftGradient;
-    private Paint mGradientPaint = new Paint();
-    boolean mLeftToRight = true;
-
-    private float mOverScrollAmount = 0f;
-    private final Rect mForegroundRect = new Rect();
-    private int mForegroundAlpha = 0;
-    private CheckLongPressHelper mLongPressHelper;
-    private Animator mFrameFade;
-    private boolean mIsSmall = false;
-    private Handler mWorkerHandler;
-
-    private float mBackgroundAlpha;
-    private float mContentAlpha;
-    private float mBackgroundAlphaMultiplier = 1.0f;
-    private Drawable mBackgroundDrawable;
-    private Rect mBackgroundRect = new Rect();
-
-    // These variables are all needed in order to size things properly before we're actually
-    // measured.
-    private int mSmallWidgetHeight;
-    private int mSmallFrameHeight;
-    private boolean mWidgetLockedSmall = false;
-    private int mMaxChallengeTop = -1;
-    private int mFrameStrokeAdjustment;
-    private boolean mPerformAppWidgetSizeUpdateOnBootComplete;
-
-    // This will hold the width value before we've actually been measured
-    private int mFrameHeight;
-
-    private boolean mIsHoveringOverDeleteDropTarget;
-
-    // Multiple callers may try and adjust the alpha of the frame. When a caller shows
-    // the outlines, we give that caller control, and nobody else can fade them out.
-    // This prevents animation conflicts.
-    private Object mBgAlphaController;
-
-    public KeyguardWidgetFrame(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardWidgetFrame(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetFrame(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mLongPressHelper = new CheckLongPressHelper(this);
-
-        Resources res = context.getResources();
-        // TODO: this padding should really correspond to the padding embedded in the background
-        // drawable (ie. outlines).
-        float density = res.getDisplayMetrics().density;
-        int padding = (int) (res.getDisplayMetrics().density * 8);
-        setPadding(padding, padding, padding, padding);
-
-        mFrameStrokeAdjustment = 2 + (int) (2 * density);
-
-        // This will be overriden on phones based on the current security mode, however on tablets
-        // we need to specify a height.
-        mSmallWidgetHeight =
-                res.getDimensionPixelSize(com.android.internal.R.dimen.kg_small_widget_height);
-        mBackgroundDrawable = res.getDrawable(R.drawable.kg_widget_bg_padded);
-        mGradientColor = res.getColor(com.android.internal.R.color.kg_widget_pager_gradient);
-        mGradientPaint.setXfermode(sAddBlendMode);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        cancelLongPress();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
-
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
-    }
-
-    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
-            new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onBootCompleted() {
-            if (mPerformAppWidgetSizeUpdateOnBootComplete) {
-                performAppWidgetSizeCallbacksIfNecessary();
-                mPerformAppWidgetSizeUpdateOnBootComplete = false;
-            }
-        }
-    };
-
-    void setIsHoveringOverDeleteDropTarget(boolean isHovering) {
-        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
-            if (mIsHoveringOverDeleteDropTarget != isHovering) {
-                mIsHoveringOverDeleteDropTarget = isHovering;
-                invalidate();
-            }
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        // Watch for longpress events at this level to make sure
-        // users can always pick up this widget
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mLongPressHelper.postCheckForLongPress(ev);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                mLongPressHelper.onMove(ev);
-                break;
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mLongPressHelper.cancelLongPress();
-                break;
-        }
-
-        // Otherwise continue letting touch events fall through to children
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        // Watch for longpress events at this level to make sure
-        // users can always pick up this widget
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_MOVE:
-                mLongPressHelper.onMove(ev);
-                break;
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mLongPressHelper.cancelLongPress();
-                break;
-        }
-
-        // We return true here to ensure that we will get cancel / up signal
-        // even if none of our children have requested touch.
-        return true;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        super.requestDisallowInterceptTouchEvent(disallowIntercept);
-        cancelLongPress();
-    }
-
-    @Override
-    public void cancelLongPress() {
-        super.cancelLongPress();
-        mLongPressHelper.cancelLongPress();
-    }
-
-
-    private void drawGradientOverlay(Canvas c) {
-        mGradientPaint.setShader(mForegroundGradient);
-        mGradientPaint.setAlpha(mForegroundAlpha);
-        c.drawRect(mForegroundRect, mGradientPaint);
-    }
-
-    private void drawHoveringOverDeleteOverlay(Canvas c) {
-        if (mIsHoveringOverDeleteDropTarget) {
-            c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR);
-        }
-    }
-
-    protected void drawBg(Canvas canvas) {
-        if (mBackgroundAlpha > 0.0f) {
-            Drawable bg = mBackgroundDrawable;
-
-            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
-            bg.setBounds(mBackgroundRect);
-            bg.draw(canvas);
-        }
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
-            canvas.save();
-        }
-        drawBg(canvas);
-        super.dispatchDraw(canvas);
-        drawGradientOverlay(canvas);
-        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
-            drawHoveringOverDeleteOverlay(canvas);
-            canvas.restore();
-        }
-    }
-
-    /**
-     * Because this view has fading outlines, it is essential that we enable hardware
-     * layers on the content (child) so that updating the alpha of the outlines doesn't
-     * result in the content layer being recreated.
-     */
-    public void enableHardwareLayersForContent() {
-        View widget = getContent();
-        if (widget != null) {
-            widget.setLayerType(LAYER_TYPE_HARDWARE, null);
-        }
-    }
-
-    /**
-     * Because this view has fading outlines, it is essential that we enable hardware
-     * layers on the content (child) so that updating the alpha of the outlines doesn't
-     * result in the content layer being recreated.
-     */
-    public void disableHardwareLayersForContent() {
-        View widget = getContent();
-        if (widget != null) {
-            widget.setLayerType(LAYER_TYPE_NONE, null);
-        }
-    }
-
-    public void enableHardwareLayers() {
-        setLayerType(LAYER_TYPE_HARDWARE, null);
-    }
-
-    public void disableHardwareLayers() {
-        setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    public View getContent() {
-        return getChildAt(0);
-    }
-
-    public int getContentAppWidgetId() {
-        View content = getContent();
-        if (content instanceof AppWidgetHostView) {
-            return ((AppWidgetHostView) content).getAppWidgetId();
-        } else if (content instanceof KeyguardStatusView) {
-            return ((KeyguardStatusView) content).getAppWidgetId();
-        } else {
-            return AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-    }
-
-    public float getBackgroundAlpha() {
-        return mBackgroundAlpha;
-    }
-
-    public void setBackgroundAlphaMultiplier(float multiplier) {
-        if (Float.compare(mBackgroundAlphaMultiplier, multiplier) != 0) {
-            mBackgroundAlphaMultiplier = multiplier;
-            invalidate();
-        }
-    }
-
-    public float getBackgroundAlphaMultiplier() {
-        return mBackgroundAlphaMultiplier;
-    }
-
-    public void setBackgroundAlpha(float alpha) {
-        if (Float.compare(mBackgroundAlpha, alpha) != 0) {
-            mBackgroundAlpha = alpha;
-            invalidate();
-        }
-    }
-
-    public float getContentAlpha() {
-        return mContentAlpha;
-    }
-
-    public void setContentAlpha(float alpha) {
-        mContentAlpha = alpha;
-        View content = getContent();
-        if (content != null) {
-            content.setAlpha(alpha);
-        }
-    }
-
-    /**
-     * Depending on whether the security is up, the widget size needs to change
-     * 
-     * @param height The height of the widget, -1 for full height
-     */
-    private void setWidgetHeight(int height) {
-        boolean needLayout = false;
-        View widget = getContent();
-        if (widget != null) {
-            LayoutParams lp = (LayoutParams) widget.getLayoutParams();
-            if (lp.height != height) {
-                needLayout = true;
-                lp.height = height;
-            }
-        }
-        if (needLayout) {
-            requestLayout();
-        }
-    }
-
-    public void setMaxChallengeTop(int top) {
-        boolean dirty = mMaxChallengeTop != top;
-        mMaxChallengeTop = top;
-        mSmallWidgetHeight = top - getPaddingTop();
-        mSmallFrameHeight = top + getPaddingBottom();
-        if (dirty && mIsSmall) {
-            setWidgetHeight(mSmallWidgetHeight);
-            setFrameHeight(mSmallFrameHeight);
-        } else if (dirty && mWidgetLockedSmall) {
-            setWidgetHeight(mSmallWidgetHeight);
-        }
-    }
-
-    public boolean isSmall() {
-        return mIsSmall;
-    }
-
-    public void adjustFrame(int challengeTop) {
-        int frameHeight = challengeTop + getPaddingBottom();
-        setFrameHeight(frameHeight);
-    }
-
-    public void shrinkWidget(boolean alsoShrinkFrame) {
-        mIsSmall = true;
-        setWidgetHeight(mSmallWidgetHeight);
-
-        if (alsoShrinkFrame) {
-            setFrameHeight(mSmallFrameHeight);
-        }
-    }
-
-    public int getSmallFrameHeight() {
-        return mSmallFrameHeight;
-    }
-
-    public void shrinkWidget() {
-        shrinkWidget(true);
-    }
-
-    public void setWidgetLockedSmall(boolean locked) {
-        if (locked) {
-            setWidgetHeight(mSmallWidgetHeight);
-        }
-        mWidgetLockedSmall = locked;
-    }
-
-    public void resetSize() {
-        mIsSmall = false;
-        if (!mWidgetLockedSmall) {
-            setWidgetHeight(LayoutParams.MATCH_PARENT);
-        }
-        setFrameHeight(getMeasuredHeight());
-    }
-
-    public void setFrameHeight(int height) {
-        mFrameHeight = height;
-        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(mFrameHeight, getMeasuredHeight()));
-        mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,getMeasuredWidth() -
-                mFrameStrokeAdjustment, Math.min(getMeasuredHeight(), mFrameHeight) -
-                mFrameStrokeAdjustment);
-        updateGradient();
-        invalidate();
-    }
-
-    public void hideFrame(Object caller) {
-        fadeFrame(caller, false, 0f, KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_OUT_DURATION);
-    }
-
-    public void showFrame(Object caller) {
-        fadeFrame(caller, true, OUTLINE_ALPHA_MULTIPLIER,
-                KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_IN_DURATION);
-    }
-
-    public void fadeFrame(Object caller, boolean takeControl, float alpha, int duration) {
-        if (takeControl) {
-            mBgAlphaController = caller;
-        }
-
-        if (mBgAlphaController != caller && mBgAlphaController != null) {
-            return;
-        }
-
-        if (mFrameFade != null) {
-            mFrameFade.cancel();
-            mFrameFade = null;
-        }
-        PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", alpha);
-        mFrameFade = ObjectAnimator.ofPropertyValuesHolder(this, bgAlpha);
-        mFrameFade.setDuration(duration);
-        mFrameFade.start();
-    }
-
-    private void updateGradient() {
-        float x0 = mLeftToRight ? 0 : mForegroundRect.width();
-        float x1 = mLeftToRight ? mForegroundRect.width(): 0;
-        mLeftToRightGradient = new LinearGradient(x0, 0f, x1, 0f,
-                mGradientColor, 0, Shader.TileMode.CLAMP);
-        mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f,
-                mGradientColor, 0, Shader.TileMode.CLAMP);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        if (!mIsSmall) {
-            mFrameHeight = h;
-        }
-
-        // mFrameStrokeAdjustment is a cludge to prevent the overlay from drawing outside the
-        // rounded rect background.
-        mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,
-                w - mFrameStrokeAdjustment, Math.min(h, mFrameHeight) - mFrameStrokeAdjustment);
-
-        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(h, mFrameHeight));
-        updateGradient();
-        invalidate();
-    }
-
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        performAppWidgetSizeCallbacksIfNecessary();
-    }
-
-    private void performAppWidgetSizeCallbacksIfNecessary() {
-        View content = getContent();
-        if (!(content instanceof AppWidgetHostView)) return;
-
-        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
-            mPerformAppWidgetSizeUpdateOnBootComplete = true;
-            return;
-        }
-
-        // TODO: there's no reason to force the AppWidgetHostView to catch duplicate size calls.
-        // We can do that even more cheaply here. It's not an issue right now since we're in the
-        // system process and hence no binder calls.
-        AppWidgetHostView awhv = (AppWidgetHostView) content;
-        float density = getResources().getDisplayMetrics().density;
-
-        int width = (int) (content.getMeasuredWidth() / density);
-        int height = (int) (content.getMeasuredHeight() / density);
-        awhv.updateAppWidgetSize(null, width, height, width, height, true);
-    }
-
-    void setOverScrollAmount(float r, boolean left) {
-        if (Float.compare(mOverScrollAmount, r) != 0) {
-            mOverScrollAmount = r;
-            mForegroundGradient = left ? mLeftToRightGradient : mRightToLeftGradient;
-            mForegroundAlpha = (int) Math.round((0.5f * r * 255));
-
-            // We bump up the alpha of the outline to hide the fact that the overlay is drawing
-            // over the rounded part of the frame.
-            float bgAlpha = Math.min(OUTLINE_ALPHA_MULTIPLIER + r * (1 - OUTLINE_ALPHA_MULTIPLIER),
-                    1f);
-            setBackgroundAlpha(bgAlpha);
-            invalidate();
-        }
-    }
-
-    public void onActive(boolean isActive) {
-        // hook for subclasses
-    }
-
-    public boolean onUserInteraction(MotionEvent event) {
-        // hook for subclasses
-        return false;
-    }
-
-    public void onBouncerShowing(boolean showing) {
-        // hook for subclasses
-    }
-
-    public void setWorkerHandler(Handler workerHandler) {
-        mWorkerHandler = workerHandler;
-    }
-
-    public Handler getWorkerHandler() {
-        return mWorkerHandler;
-    }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
deleted file mode 100644
index 770fafc..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ /dev/null
@@ -1,926 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.TextClock;
-
-import com.android.internal.widget.LockPatternUtils;
-
-import java.util.ArrayList;
-import java.util.TimeZone;
-
-public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
-        OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener {
-
-    ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
-    private static float CAMERA_DISTANCE = 10000;
-    protected static float OVERSCROLL_MAX_ROTATION = 30;
-    private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
-
-    private static final int FLAG_HAS_LOCAL_HOUR = 0x1;
-    private static final int FLAG_HAS_LOCAL_MINUTE = 0x2;
-
-    protected KeyguardViewStateManager mViewStateManager;
-    private LockPatternUtils mLockPatternUtils;
-
-    // Related to the fading in / out background outlines
-    public static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
-    public static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
-    protected AnimatorSet mChildrenOutlineFadeAnimation;
-    protected int mScreenCenter;
-    private boolean mHasMeasure = false;
-    boolean showHintsAfterLayout = false;
-
-    private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
-    private static final String TAG = "KeyguardWidgetPager";
-    private boolean mCenterSmallWidgetsVertically;
-
-    private int mPage = 0;
-    private Callbacks mCallbacks;
-
-    private int mWidgetToResetAfterFadeOut;
-    protected boolean mShowingInitialHints = false;
-
-    // A temporary handle to the Add-Widget view
-    private View mAddWidgetView;
-    private int mLastWidthMeasureSpec;
-    private int mLastHeightMeasureSpec;
-
-    // Bouncer
-    private int mBouncerZoomInOutDuration = 250;
-    private float BOUNCER_SCALE_FACTOR = 0.67f;
-
-    // Background worker thread: used here for persistence, also made available to widget frames
-    private final HandlerThread mBackgroundWorkerThread;
-    private final Handler mBackgroundWorkerHandler;
-
-    public KeyguardWidgetPager(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetPager(Context context) {
-        this(null, null, 0);
-    }
-
-    public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-
-        setPageSwitchListener(this);
-
-        mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker");
-        mBackgroundWorkerThread.start();
-        mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper());
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        // Clean up the worker thread
-        mBackgroundWorkerThread.quit();
-    }
-
-    public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
-        mViewStateManager = viewStateManager;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils l) {
-        mLockPatternUtils = l;
-    }
-
-    @Override
-    public void onPageSwitching(View newPage, int newPageIndex) {
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageSwitching(newPage, newPageIndex);
-        }
-    }
-
-    @Override
-    public void onPageSwitched(View newPage, int newPageIndex) {
-        boolean showingClock = false;
-        if (newPage instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) newPage;
-            if (vg.getChildAt(0) instanceof KeyguardStatusView) {
-                showingClock = true;
-            }
-        }
-
-        if (newPage != null &&
-                findClockInHierarchy(newPage) == (FLAG_HAS_LOCAL_HOUR | FLAG_HAS_LOCAL_MINUTE)) {
-            showingClock = true;
-        }
-
-        // Disable the status bar clock if we're showing the default status widget
-        if (showingClock) {
-            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
-        } else {
-            setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
-        }
-
-        // Extend the display timeout if the user switches pages
-        if (mPage != newPageIndex) {
-            int oldPageIndex = mPage;
-            mPage = newPageIndex;
-            userActivity();
-            KeyguardWidgetFrame oldWidgetPage = getWidgetPageAt(oldPageIndex);
-            if (oldWidgetPage != null) {
-                oldWidgetPage.onActive(false);
-            }
-            KeyguardWidgetFrame newWidgetPage = getWidgetPageAt(newPageIndex);
-            if (newWidgetPage != null) {
-                newWidgetPage.onActive(true);
-                newWidgetPage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-                newWidgetPage.requestAccessibilityFocus();
-            }
-            if (mParent != null && AccessibilityManager.getInstance(mContext).isEnabled()) {
-                AccessibilityEvent event = AccessibilityEvent.obtain(
-                        AccessibilityEvent.TYPE_VIEW_SCROLLED);
-                onInitializeAccessibilityEvent(event);
-                onPopulateAccessibilityEvent(event);
-                mParent.requestSendAccessibilityEvent(this, event);
-            }
-        }
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageSwitched(newPage, newPageIndex);
-        }
-    }
-
-    @Override
-    public void sendAccessibilityEvent(int eventType) {
-        if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) {
-            super.sendAccessibilityEvent(eventType);
-        }
-    }
-
-    private void updateWidgetFramesImportantForAccessibility() {
-        final int pageCount = getPageCount();
-        for (int i = 0; i < pageCount; i++) {
-            KeyguardWidgetFrame frame = getWidgetPageAt(i);
-            updateWidgetFrameImportantForAccessibility(frame);
-        }
-    }
-
-    private void updateWidgetFrameImportantForAccessibility(KeyguardWidgetFrame frame) {
-        if (frame.getContentAlpha() <= 0) {
-            frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-        } else {
-            frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-    }
-
-    private void userActivity() {
-        if (mCallbacks != null) {
-            mCallbacks.onUserActivityTimeoutChanged();
-            mCallbacks.userActivity();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return captureUserInteraction(ev) || super.onTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return captureUserInteraction(ev) || super.onInterceptTouchEvent(ev);
-    }
-
-    private boolean captureUserInteraction(MotionEvent ev) {
-        KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage());
-        return currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev);
-    }
-
-    public void showPagingFeedback() {
-        // Nothing yet.
-    }
-
-    public long getUserActivityTimeout() {
-        View page = getPageAt(mPage);
-        if (page instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) page;
-            View view = vg.getChildAt(0);
-            if (!(view instanceof KeyguardStatusView)
-                    && !(view instanceof KeyguardMultiUserSelectorView)) {
-                return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
-            }
-        }
-        return -1;
-    }
-
-    public void setCallbacks(Callbacks callbacks) {
-        mCallbacks = callbacks;
-    }
-
-    public interface Callbacks {
-        public void userActivity();
-        public void onUserActivityTimeoutChanged();
-        public void onAddView(View v);
-        public void onRemoveView(View v, boolean deletePermanently);
-        public void onRemoveViewAnimationCompleted();
-    }
-
-    public void addWidget(View widget) {
-        addWidget(widget, -1);
-    }
-
-    public void onRemoveView(View v, final boolean deletePermanently) {
-        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        if (mCallbacks != null) {
-            mCallbacks.onRemoveView(v, deletePermanently);
-        }
-        mBackgroundWorkerHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mLockPatternUtils.removeAppWidget(appWidgetId);
-            }
-        });
-    }
-
-    @Override
-    public void onRemoveViewAnimationCompleted() {
-        if (mCallbacks != null) {
-            mCallbacks.onRemoveViewAnimationCompleted();
-        }
-    }
-
-    public void onAddView(View v, final int index) {
-        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        final int[] pagesRange = new int[mTempVisiblePagesRange.length];
-        getVisiblePages(pagesRange);
-        boundByReorderablePages(true, pagesRange);
-        if (mCallbacks != null) {
-            mCallbacks.onAddView(v);
-        }
-        // Subtract from the index to take into account pages before the reorderable
-        // pages (e.g. the "add widget" page)
-        mBackgroundWorkerHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
-            }
-        });
-    }
-
-    /*
-     * We wrap widgets in a special frame which handles drawing the over scroll foreground.
-     */
-    public void addWidget(View widget, int pageIndex) {
-        KeyguardWidgetFrame frame;
-        // All views contained herein should be wrapped in a KeyguardWidgetFrame
-        if (!(widget instanceof KeyguardWidgetFrame)) {
-            frame = new KeyguardWidgetFrame(getContext());
-            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
-                    LayoutParams.MATCH_PARENT);
-            lp.gravity = Gravity.TOP;
-
-            // The framework adds a default padding to AppWidgetHostView. We don't need this padding
-            // for the Keyguard, so we override it to be 0.
-            widget.setPadding(0,  0, 0, 0);
-            frame.addView(widget, lp);
-
-            // We set whether or not this widget supports vertical resizing.
-            if (widget instanceof AppWidgetHostView) {
-                AppWidgetHostView awhv = (AppWidgetHostView) widget;
-                AppWidgetProviderInfo info = awhv.getAppWidgetInfo();
-                if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
-                    frame.setWidgetLockedSmall(false);
-                } else {
-                    // Lock the widget to be small.
-                    frame.setWidgetLockedSmall(true);
-                    if (mCenterSmallWidgetsVertically) {
-                        lp.gravity = Gravity.CENTER;
-                    }
-                }
-            }
-        } else {
-            frame = (KeyguardWidgetFrame) widget;
-        }
-
-        ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-        frame.setOnLongClickListener(this);
-        frame.setWorkerHandler(mBackgroundWorkerHandler);
-
-        if (pageIndex == -1) {
-            addView(frame, pageLp);
-        } else {
-            addView(frame, pageIndex, pageLp);
-        }
-
-        // Update the frame content description.
-        View content = (widget == frame) ?  frame.getContent() : widget;
-        if (content != null) {
-            String contentDescription = mContext.getString(
-                com.android.internal.R.string.keyguard_accessibility_widget,
-                content.getContentDescription());
-            frame.setContentDescription(contentDescription);
-        }
-        updateWidgetFrameImportantForAccessibility(frame);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, int index) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, index);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, int width, int height) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, width, height);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, LayoutParams params) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, params);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, int index, LayoutParams params) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, index, params);
-    }
-
-    private void enforceKeyguardWidgetFrame(View child) {
-        if (!(child instanceof KeyguardWidgetFrame)) {
-            throw new IllegalArgumentException(
-                    "KeyguardWidgetPager children must be KeyguardWidgetFrames");
-        }
-    }
-
-    public KeyguardWidgetFrame getWidgetPageAt(int index) {
-        // This is always a valid cast as we've guarded the ability to
-        return (KeyguardWidgetFrame) getChildAt(index);
-    }
-
-    protected void onUnhandledTap(MotionEvent ev) {
-        showPagingFeedback();
-    }
-
-    @Override
-    protected void onPageBeginMoving() {
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageBeginMoving();
-        }
-        if (!isReordering(false)) {
-            showOutlinesAndSidePages();
-        }
-        userActivity();
-    }
-
-    @Override
-    protected void onPageEndMoving() {
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageEndMoving();
-        }
-
-        // In the reordering case, the pages will be faded appropriately on completion
-        // of the zoom in animation.
-        if (!isReordering(false)) {
-            hideOutlinesAndSidePages();
-        }
-    }
-
-    protected void enablePageContentLayers() {
-        int children = getChildCount();
-        for (int i = 0; i < children; i++) {
-            getWidgetPageAt(i).enableHardwareLayersForContent();
-        }
-    }
-
-    protected void disablePageContentLayers() {
-        int children = getChildCount();
-        for (int i = 0; i < children; i++) {
-            getWidgetPageAt(i).disableHardwareLayersForContent();
-        }
-    }
-
-    /*
-     * This interpolator emulates the rate at which the perceived scale of an object changes
-     * as its distance from a camera increases. When this interpolator is applied to a scale
-     * animation on a view, it evokes the sense that the object is shrinking due to moving away
-     * from the camera.
-     */
-    static class ZInterpolator implements TimeInterpolator {
-        private float focalLength;
-
-        public ZInterpolator(float foc) {
-            focalLength = foc;
-        }
-
-        public float getInterpolation(float input) {
-            return (1.0f - focalLength / (focalLength + input)) /
-                (1.0f - focalLength / (focalLength + 1.0f));
-        }
-    }
-
-    @Override
-    protected void overScroll(float amount) {
-        acceleratedOverScroll(amount);
-    }
-
-    float backgroundAlphaInterpolator(float r) {
-        return Math.min(1f, r);
-    }
-
-    private void updatePageAlphaValues(int screenCenter) {
-    }
-
-    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        if (showSidePages) {
-            return 1f;
-        } else {
-            return index == mCurrentPage ? 1.0f : 0f;
-        }
-    }
-
-    public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        if (showSidePages) {
-            return getAlphaForPage(screenCenter, index, showSidePages)
-                    * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER;
-        } else {
-            return 0f;
-        }
-    }
-
-    protected boolean isOverScrollChild(int index, float scrollProgress) {
-        boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
-        return (isInOverscroll && (index == 0 && scrollProgress < 0 ||
-                index == getChildCount() - 1 && scrollProgress > 0));
-    }
-
-    @Override
-    protected void screenScrolled(int screenCenter) {
-        mScreenCenter = screenCenter;
-        updatePageAlphaValues(screenCenter);
-        for (int i = 0; i < getChildCount(); i++) {
-            KeyguardWidgetFrame v = getWidgetPageAt(i);
-            if (v == mDragView) continue;
-            if (v != null) {
-                float scrollProgress = getScrollProgress(screenCenter, v, i);
-
-                v.setCameraDistance(mDensity * CAMERA_DISTANCE);
-
-                if (isOverScrollChild(i, scrollProgress) && PERFORM_OVERSCROLL_ROTATION) {
-                    float pivotX = v.getMeasuredWidth() / 2;
-                    float pivotY = v.getMeasuredHeight() / 2;
-                    v.setPivotX(pivotX);
-                    v.setPivotY(pivotY);
-                    v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
-                    v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
-                } else {
-                    v.setRotationY(0f);
-                    v.setOverScrollAmount(0, false);
-                }
-
-                float alpha = v.getAlpha();
-                // If the view has 0 alpha, we set it to be invisible so as to prevent
-                // it from accepting touches
-                if (alpha == 0) {
-                    v.setVisibility(INVISIBLE);
-                } else if (v.getVisibility() != VISIBLE) {
-                    v.setVisibility(VISIBLE);
-                }
-            }
-        }
-    }
-
-    public boolean isWidgetPage(int pageIndex) {
-        if (pageIndex < 0 || pageIndex >= getChildCount()) {
-            return false;
-        }
-        View v = getChildAt(pageIndex);
-        if (v != null && v instanceof KeyguardWidgetFrame) {
-            KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
-            return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-        return false;
-    }
-
-    /**
-     * Returns the bounded set of pages that are re-orderable.  The range is fully inclusive.
-     */
-    @Override
-    void boundByReorderablePages(boolean isReordering, int[] range) {
-        if (isReordering) {
-            // Remove non-widget pages from the range
-            while (range[1] >= range[0] && !isWidgetPage(range[1])) {
-                range[1]--;
-            }
-            while (range[0] <= range[1] && !isWidgetPage(range[0])) {
-                range[0]++;
-            }
-        }
-    }
-
-    protected void reorderStarting() {
-        showOutlinesAndSidePages();
-    }
-
-    @Override
-    protected void onStartReordering() {
-        super.onStartReordering();
-        enablePageContentLayers();
-        reorderStarting();
-    }
-
-    @Override
-    protected void onEndReordering() {
-        super.onEndReordering();
-        hideOutlinesAndSidePages();
-    }
-
-    void showOutlinesAndSidePages() {
-        animateOutlinesAndSidePages(true);
-    }
-
-    void hideOutlinesAndSidePages() {
-        animateOutlinesAndSidePages(false);
-    }
-
-    void updateChildrenContentAlpha(float sidePageAlpha) {
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            if (i != mCurrentPage) {
-                child.setBackgroundAlpha(sidePageAlpha);
-                child.setContentAlpha(0f);
-            } else {
-                child.setBackgroundAlpha(0f);
-                child.setContentAlpha(1f);
-            }
-        }
-    }
-
-    public void showInitialPageHints() {
-        mShowingInitialHints = true;
-        updateChildrenContentAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
-    }
-
-    @Override
-    void setCurrentPage(int currentPage) {
-        super.setCurrentPage(currentPage);
-        updateChildrenContentAlpha(0.0f);
-        updateWidgetFramesImportantForAccessibility();
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mHasMeasure = false;
-    }
-
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        mLastWidthMeasureSpec = widthMeasureSpec;
-        mLastHeightMeasureSpec = heightMeasureSpec;
-
-        int maxChallengeTop = -1;
-        View parent = (View) getParent();
-        boolean challengeShowing = false;
-        // Widget pages need to know where the top of the sliding challenge is so that they
-        // now how big the widget should be when the challenge is up. We compute it here and
-        // then propagate it to each of our children.
-        if (parent.getParent() instanceof SlidingChallengeLayout) {
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) parent.getParent();
-            int top = scl.getMaxChallengeTop();
-
-            // This is a bit evil, but we need to map a coordinate relative to the SCL into a
-            // coordinate relative to our children, hence we subtract the top padding.s
-            maxChallengeTop = top - getPaddingTop();
-            challengeShowing = scl.isChallengeShowing();
-
-            int count = getChildCount();
-            for (int i = 0; i < count; i++) {
-                KeyguardWidgetFrame frame = getWidgetPageAt(i);
-                frame.setMaxChallengeTop(maxChallengeTop);
-                // On the very first measure pass, if the challenge is showing, we need to make sure
-                // that the widget on the current page is small.
-                if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
-                    frame.shrinkWidget();
-                }
-            }
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        mHasMeasure = true;
-    }
-
-    void animateOutlinesAndSidePages(final boolean show) {
-        animateOutlinesAndSidePages(show, -1);
-    }
-
-    public void setWidgetToResetOnPageFadeOut(int widget) {
-        mWidgetToResetAfterFadeOut = widget;
-    }
-
-    public int getWidgetToResetOnPageFadeOut() {
-        return mWidgetToResetAfterFadeOut;
-    }
-
-    void animateOutlinesAndSidePages(final boolean show, int duration) {
-        if (mChildrenOutlineFadeAnimation != null) {
-            mChildrenOutlineFadeAnimation.cancel();
-            mChildrenOutlineFadeAnimation = null;
-        }
-        int count = getChildCount();
-        PropertyValuesHolder alpha;
-        ArrayList<Animator> anims = new ArrayList<Animator>();
-
-        if (duration == -1) {
-            duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
-                CHILDREN_OUTLINE_FADE_OUT_DURATION;
-        }
-
-        int curPage = getNextPage();
-        for (int i = 0; i < count; i++) {
-            float finalContentAlpha;
-            if (show) {
-                finalContentAlpha = getAlphaForPage(mScreenCenter, i, true);
-            } else if (!show && i == curPage) {
-                finalContentAlpha = 1f;
-            } else {
-                finalContentAlpha = 0f;
-            }
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-
-            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha);
-            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha);
-            anims.add(a);
-
-            float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i, true) : 0f;
-            child.fadeFrame(this, show, finalOutlineAlpha, duration);
-        }
-
-        mChildrenOutlineFadeAnimation = new AnimatorSet();
-        mChildrenOutlineFadeAnimation.playTogether(anims);
-
-        mChildrenOutlineFadeAnimation.setDuration(duration);
-        mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                if (show) {
-                    enablePageContentLayers();
-                }
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!show) {
-                    disablePageContentLayers();
-                    KeyguardWidgetFrame frame = getWidgetPageAt(mWidgetToResetAfterFadeOut);
-                    if (frame != null && !(frame == getWidgetPageAt(mCurrentPage) &&
-                            mViewStateManager.isChallengeOverlapping())) {
-                        frame.resetSize();
-                    }
-                    mWidgetToResetAfterFadeOut = -1;
-                    mShowingInitialHints = false;
-                }
-                updateWidgetFramesImportantForAccessibility();
-            }
-        });
-        mChildrenOutlineFadeAnimation.start();
-    }
-
-    @Override
-    public boolean onLongClick(View v) {
-        // Disallow long pressing to reorder if the challenge is showing
-        boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() &&
-                mViewStateManager.isChallengeOverlapping();
-        if (!isChallengeOverlapping && startReordering()) {
-            return true;
-        }
-        return false;
-    }
-
-    public void removeWidget(View view) {
-        if (view instanceof KeyguardWidgetFrame) {
-            removeView(view);
-        } else {
-            // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget().
-            // This supports legacy hard-coded "widgets" like KeyguardTransportControlView.
-            int pos = getWidgetPageIndex(view);
-            if (pos != -1) {
-                KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos);
-                frame.removeView(view);
-                removeView(frame);
-            } else {
-                Slog.w(TAG, "removeWidget() can't find:" + view);
-            }
-        }
-    }
-
-    public int getWidgetPageIndex(View view) {
-        if (view instanceof KeyguardWidgetFrame) {
-            return indexOfChild(view);
-        } else {
-            // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget()
-            return indexOfChild((KeyguardWidgetFrame)view.getParent());
-        }
-    }
-
-    @Override
-    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {
-        KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
-        child.setIsHoveringOverDeleteDropTarget(isHovering);
-    }
-
-    // ChallengeLayout.OnBouncerStateChangedListener
-    @Override
-    public void onBouncerStateChanged(boolean bouncerActive) {
-        if (bouncerActive) {
-            zoomOutToBouncer();
-        } else {
-            zoomInFromBouncer();
-        }
-    }
-
-    void setBouncerAnimationDuration(int duration) {
-        mBouncerZoomInOutDuration = duration;
-    }
-
-    // Zoom in after the bouncer is dismissed
-    void zoomInFromBouncer() {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-        final View currentPage = getPageAt(getCurrentPage());
-        if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(currentPage, "scaleX", 1f),
-                    ObjectAnimator.ofFloat(currentPage , "scaleY", 1f));
-            mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
-            mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
-            mZoomInOutAnim.start();
-        }
-        if (currentPage instanceof KeyguardWidgetFrame) {
-            ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false);
-        }
-    }
-
-    // Zoom out after the bouncer is initiated
-    void zoomOutToBouncer() {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-        int curPage = getCurrentPage();
-        View currentPage = getPageAt(curPage);
-        if (shouldSetTopAlignedPivotForWidget(curPage)) {
-            currentPage.setPivotY(0);
-            // Note: we are working around the issue that setting the x-pivot to the same value as it
-            //       was does not actually work.
-            currentPage.setPivotX(0);
-            currentPage.setPivotX(currentPage.getMeasuredWidth() / 2);
-        }
-        if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR),
-                    ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR));
-            mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
-            mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
-            mZoomInOutAnim.start();
-        }
-        if (currentPage instanceof KeyguardWidgetFrame) {
-            ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true);
-        }
-    }
-
-    void setAddWidgetEnabled(boolean enabled) {
-        if (mAddWidgetView != null && enabled) {
-            addView(mAddWidgetView, 0);
-            // We need to force measure the PagedView so that the calls to update the scroll
-            // position below work
-            measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);
-            // Bump up the current page to account for the addition of the new page
-            setCurrentPage(mCurrentPage + 1);
-            mAddWidgetView = null;
-        } else if (mAddWidgetView == null && !enabled) {
-            View addWidget = findViewById(com.android.internal.R.id.keyguard_add_widget);
-            if (addWidget != null) {
-                mAddWidgetView = addWidget;
-                removeView(addWidget);
-            }
-        }
-    }
-
-    boolean isAddPage(int pageIndex) {
-        View v = getChildAt(pageIndex);
-        return v != null && v.getId() == com.android.internal.R.id.keyguard_add_widget;
-    }
-
-    boolean isCameraPage(int pageIndex) {
-        View v = getChildAt(pageIndex);
-        return v != null && v instanceof CameraWidgetFrame;
-    }
-
-    @Override
-    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
-        return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex);
-    }
-
-    /**
-     * Search given {@link View} hierarchy for {@link TextClock} instances that
-     * show various time components. Returns combination of
-     * {@link #FLAG_HAS_LOCAL_HOUR} and {@link #FLAG_HAS_LOCAL_MINUTE}.
-     */
-    private static int findClockInHierarchy(View view) {
-        if (view instanceof TextClock) {
-            return getClockFlags((TextClock) view);
-        } else if (view instanceof ViewGroup) {
-            int flags = 0;
-            final ViewGroup group = (ViewGroup) view;
-            final int size = group.getChildCount();
-            for (int i = 0; i < size; i++) {
-                flags |= findClockInHierarchy(group.getChildAt(i));
-            }
-            return flags;
-        } else {
-            return 0;
-        }
-    }
-
-    /**
-     * Return combination of {@link #FLAG_HAS_LOCAL_HOUR} and
-     * {@link #FLAG_HAS_LOCAL_MINUTE} describing the time represented described
-     * by the given {@link TextClock}.
-     */
-    private static int getClockFlags(TextClock clock) {
-        int flags = 0;
-
-        final String timeZone = clock.getTimeZone();
-        if (timeZone != null && !TimeZone.getDefault().equals(TimeZone.getTimeZone(timeZone))) {
-            // Ignore clocks showing another timezone
-            return 0;
-        }
-
-        final CharSequence format = clock.getFormat();
-        final char hour = clock.is24HourModeEnabled() ? DateFormat.HOUR_OF_DAY
-                : DateFormat.HOUR;
-
-        if (DateFormat.hasDesignator(format, hour)) {
-            flags |= FLAG_HAS_LOCAL_HOUR;
-        }
-        if (DateFormat.hasDesignator(format, DateFormat.MINUTE)) {
-            flags |= FLAG_HAS_LOCAL_MINUTE;
-        }
-
-        return flags;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java b/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java
deleted file mode 100644
index 818108c..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-
-/**
- * Hover listener that implements lift-to-activate interaction for
- * accessibility. May be added to multiple views.
- */
-class LiftToActivateListener implements View.OnHoverListener {
-    /** Manager used to query accessibility enabled state. */
-    private final AccessibilityManager mAccessibilityManager;
-
-    private boolean mCachedClickableState;
-
-    public LiftToActivateListener(Context context) {
-        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
-                Context.ACCESSIBILITY_SERVICE);
-    }
-
-    @Override
-    public boolean onHover(View v, MotionEvent event) {
-        // When touch exploration is turned on, lifting a finger while
-        // inside the view bounds should perform a click action.
-        if (mAccessibilityManager.isEnabled()
-                && mAccessibilityManager.isTouchExplorationEnabled()) {
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                    // Lift-to-type temporarily disables double-tap
-                    // activation by setting the view as not clickable.
-                    mCachedClickableState = v.isClickable();
-                    v.setClickable(false);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    final int x = (int) event.getX();
-                    final int y = (int) event.getY();
-                    if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
-                            && (x < v.getWidth() - v.getPaddingRight())
-                            && (y < v.getHeight() - v.getPaddingBottom())) {
-                        v.performClick();
-                    }
-                    v.setClickable(mCachedClickableState);
-                    break;
-            }
-        }
-
-        // Pass the event to View.onHoverEvent() to handle accessibility.
-        v.onHoverEvent(event);
-
-        // Consume the event so it doesn't fall through to other views.
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
deleted file mode 100644
index 0ca46c3..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.R;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayout {
-    private static final String TAG = "MultiPaneChallengeLayout";
-
-    final int mOrientation;
-    private boolean mIsBouncing;
-
-    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
-    public static final int VERTICAL = LinearLayout.VERTICAL;
-    public static final int ANIMATE_BOUNCE_DURATION = 350;
-
-    private KeyguardSecurityContainer mChallengeView;
-    private View mUserSwitcherView;
-    private View mScrimView;
-    private OnBouncerStateChangedListener mBouncerListener;
-
-    private final Rect mTempRect = new Rect();
-    private final Rect mZeroPadding = new Rect();
-
-    private final DisplayMetrics mDisplayMetrics;
-
-    private final OnClickListener mScrimClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            hideBouncer();
-        }
-    };
-
-    public MultiPaneChallengeLayout(Context context) {
-        this(context, null);
-    }
-
-    public MultiPaneChallengeLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        final TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0);
-        mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_orientation,
-                HORIZONTAL);
-        a.recycle();
-
-        final Resources res = getResources();
-        mDisplayMetrics = res.getDisplayMetrics();
-
-        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE);
-    }
-
-    @Override
-    public boolean isChallengeShowing() {
-        return true;
-    }
-
-    @Override
-    public boolean isChallengeOverlapping() {
-        return false;
-    }
-
-    @Override
-    public void showChallenge(boolean b) {
-    }
-
-    @Override
-    public int getBouncerAnimationDuration() {
-        return ANIMATE_BOUNCE_DURATION;
-    }
-
-    @Override
-    public void showBouncer() {
-        if (mIsBouncing) return;
-        mIsBouncing = true;
-        if (mScrimView != null) {
-            if (mChallengeView != null) {
-                mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION);
-            }
-
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
-            anim.setDuration(ANIMATE_BOUNCE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mScrimView.setVisibility(VISIBLE);
-                }
-            });
-            anim.start();
-        }
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(true);
-        }
-    }
-
-    @Override
-    public void hideBouncer() {
-        if (!mIsBouncing) return;
-        mIsBouncing = false;
-        if (mScrimView != null) {
-            if (mChallengeView != null) {
-                mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION);
-            }
-
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
-            anim.setDuration(ANIMATE_BOUNCE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mScrimView.setVisibility(INVISIBLE);
-                }
-            });
-            anim.start();
-        }
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(false);
-        }
-    }
-
-    @Override
-    public boolean isBouncing() {
-        return mIsBouncing;
-    }
-
-    @Override
-    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
-        mBouncerListener = listener;
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        if (mIsBouncing && child != mChallengeView) {
-            // Clear out of the bouncer if the user tries to move focus outside of
-            // the security challenge view.
-            hideBouncer();
-        }
-        super.requestChildFocus(child, focused);
-    }
-
-    void setScrimView(View scrim) {
-        if (mScrimView != null) {
-            mScrimView.setOnClickListener(null);
-        }
-        mScrimView = scrim;
-        mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f);
-        mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE);
-        mScrimView.setFocusable(true);
-        mScrimView.setOnClickListener(mScrimClickListener);
-    }
-
-    private int getVirtualHeight(LayoutParams lp, int height, int heightUsed) {
-        int virtualHeight = height;
-        final View root = getRootView();
-        if (root != null) {
-            // This calculation is super dodgy and relies on several assumptions.
-            // Specifically that the root of the window will be padded in for insets
-            // and that the window is LAYOUT_IN_SCREEN.
-            virtualHeight = mDisplayMetrics.heightPixels - root.getPaddingTop();
-        }
-        if (lp.childType == LayoutParams.CHILD_TYPE_WIDGET ||
-                lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
-            // Always measure the widget pager/user switcher as if there were no IME insets
-            // on the window. We want to avoid resizing widgets when possible as it can
-            // be ugly/expensive. This lets us simply clip them instead.
-            return virtualHeight - heightUsed;
-        } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
-            return height;
-        }
-        return Math.min(virtualHeight - heightUsed, height);
-    }
-
-    @Override
-    protected void onMeasure(final int widthSpec, final int heightSpec) {
-        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
-                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
-            throw new IllegalArgumentException(
-                    "MultiPaneChallengeLayout must be measured with an exact size");
-        }
-
-        final int width = MeasureSpec.getSize(widthSpec);
-        final int height = MeasureSpec.getSize(heightSpec);
-        setMeasuredDimension(width, height);
-
-        int widthUsed = 0;
-        int heightUsed = 0;
-
-        // First pass. Find the challenge view and measure the user switcher,
-        // which consumes space in the layout.
-        mChallengeView = null;
-        mUserSwitcherView = null;
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
-                if (mChallengeView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child of type challenge");
-                }
-                if (!(child instanceof KeyguardSecurityContainer)) {
-                    throw new IllegalArgumentException(
-                            "Challenge must be a KeyguardSecurityContainer");
-                }
-                mChallengeView = (KeyguardSecurityContainer) child;
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
-                if (mUserSwitcherView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child of type userSwitcher");
-                }
-                mUserSwitcherView = child;
-
-                if (child.getVisibility() == GONE) continue;
-
-                int adjustedWidthSpec = widthSpec;
-                int adjustedHeightSpec = heightSpec;
-                if (lp.maxWidth >= 0) {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            Math.min(lp.maxWidth, width), MeasureSpec.EXACTLY);
-                }
-                if (lp.maxHeight >= 0) {
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            Math.min(lp.maxHeight, height), MeasureSpec.EXACTLY);
-                }
-                // measureChildWithMargins will resolve layout direction for the LayoutParams
-                measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
-
-                // Only subtract out space from one dimension. Favor vertical.
-                // Offset by 1.5x to add some balance along the other edge.
-                if (Gravity.isVertical(lp.gravity)) {
-                    heightUsed += child.getMeasuredHeight() * 1.5f;
-                } else if (Gravity.isHorizontal(lp.gravity)) {
-                    widthUsed += child.getMeasuredWidth() * 1.5f;
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
-                setScrimView(child);
-                child.measure(widthSpec, heightSpec);
-            }
-        }
-
-        // Second pass. Measure everything that's left.
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER ||
-                    lp.childType == LayoutParams.CHILD_TYPE_SCRIM ||
-                    child.getVisibility() == GONE) {
-                // Don't need to measure GONE children, and the user switcher was already measured.
-                continue;
-            }
-
-            final int virtualHeight = getVirtualHeight(lp, height, heightUsed);
-
-            int adjustedWidthSpec;
-            int adjustedHeightSpec;
-            if (lp.centerWithinArea > 0) {
-                if (mOrientation == HORIZONTAL) {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            (int) ((width - widthUsed) * lp.centerWithinArea + 0.5f),
-                            MeasureSpec.EXACTLY);
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            virtualHeight, MeasureSpec.EXACTLY);
-                } else {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            width - widthUsed, MeasureSpec.EXACTLY);
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            (int) (virtualHeight * lp.centerWithinArea + 0.5f),
-                            MeasureSpec.EXACTLY);
-                }
-            } else {
-                adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                        width - widthUsed, MeasureSpec.EXACTLY);
-                adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                        virtualHeight, MeasureSpec.EXACTLY);
-            }
-            if (lp.maxWidth >= 0) {
-                adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                        Math.min(lp.maxWidth, MeasureSpec.getSize(adjustedWidthSpec)),
-                        MeasureSpec.EXACTLY);
-            }
-            if (lp.maxHeight >= 0) {
-                adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                        Math.min(lp.maxHeight, MeasureSpec.getSize(adjustedHeightSpec)),
-                        MeasureSpec.EXACTLY);
-            }
-
-            measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final Rect padding = mTempRect;
-        padding.left = getPaddingLeft();
-        padding.top = getPaddingTop();
-        padding.right = getPaddingRight();
-        padding.bottom = getPaddingBottom();
-        final int width = r - l;
-        final int height = b - t;
-
-        // Reserve extra space in layout for the user switcher by modifying
-        // local padding during this layout pass
-        if (mUserSwitcherView != null && mUserSwitcherView.getVisibility() != GONE) {
-            layoutWithGravity(width, height, mUserSwitcherView, padding, true);
-        }
-
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            // We did the user switcher above if we have one.
-            if (child == mUserSwitcherView || child.getVisibility() == GONE) continue;
-
-            if (child == mScrimView) {
-                child.layout(0, 0, width, height);
-                continue;
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
-                layoutWithGravity(width, height, child, mZeroPadding, false);
-                continue;
-            }
-
-            layoutWithGravity(width, height, child, padding, false);
-        }
-    }
-
-    private void layoutWithGravity(int width, int height, View child, Rect padding,
-            boolean adjustPadding) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-        final int heightUsed = padding.top + padding.bottom - getPaddingTop() - getPaddingBottom();
-        height = getVirtualHeight(lp, height, heightUsed);
-
-        final int gravity = Gravity.getAbsoluteGravity(lp.gravity, getLayoutDirection());
-
-        final boolean fixedLayoutSize = lp.centerWithinArea > 0;
-        final boolean fixedLayoutHorizontal = fixedLayoutSize && mOrientation == HORIZONTAL;
-        final boolean fixedLayoutVertical = fixedLayoutSize && mOrientation == VERTICAL;
-
-        final int adjustedWidth;
-        final int adjustedHeight;
-        if (fixedLayoutHorizontal) {
-            final int paddedWidth = width - padding.left - padding.right;
-            adjustedWidth = (int) (paddedWidth * lp.centerWithinArea + 0.5f);
-            adjustedHeight = height;
-        } else if (fixedLayoutVertical) {
-            final int paddedHeight = height - getPaddingTop() - getPaddingBottom();
-            adjustedWidth = width;
-            adjustedHeight = (int) (paddedHeight * lp.centerWithinArea + 0.5f);
-        } else {
-            adjustedWidth = width;
-            adjustedHeight = height;
-        }
-
-        final boolean isVertical = Gravity.isVertical(gravity);
-        final boolean isHorizontal = Gravity.isHorizontal(gravity);
-        final int childWidth = child.getMeasuredWidth();
-        final int childHeight = child.getMeasuredHeight();
-
-        int left = padding.left;
-        int top = padding.top;
-        int right = left + childWidth;
-        int bottom = top + childHeight;
-        switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.TOP:
-                top = fixedLayoutVertical ?
-                        padding.top + (adjustedHeight - childHeight) / 2 : padding.top;
-                bottom = top + childHeight;
-                if (adjustPadding && isVertical) {
-                    padding.top = bottom;
-                    padding.bottom += childHeight / 2;
-                }
-                break;
-            case Gravity.BOTTOM:
-                bottom = fixedLayoutVertical
-                        ? padding.top + height - (adjustedHeight - childHeight) / 2
-                        : padding.top + height;
-                top = bottom - childHeight;
-                if (adjustPadding && isVertical) {
-                    padding.bottom = height - top;
-                    padding.top += childHeight / 2;
-                }
-                break;
-            case Gravity.CENTER_VERTICAL:
-                top = padding.top + (height - childHeight) / 2;
-                bottom = top + childHeight;
-                break;
-        }
-        switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.LEFT:
-                left = fixedLayoutHorizontal ?
-                        padding.left + (adjustedWidth - childWidth) / 2 : padding.left;
-                right = left + childWidth;
-                if (adjustPadding && isHorizontal && !isVertical) {
-                    padding.left = right;
-                    padding.right += childWidth / 2;
-                }
-                break;
-            case Gravity.RIGHT:
-                right = fixedLayoutHorizontal
-                        ? width - padding.right - (adjustedWidth - childWidth) / 2
-                        : width - padding.right;
-                left = right - childWidth;
-                if (adjustPadding && isHorizontal && !isVertical) {
-                    padding.right = width - left;
-                    padding.left += childWidth / 2;
-                }
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-                final int paddedWidth = width - padding.left - padding.right;
-                left = (paddedWidth - childWidth) / 2;
-                right = left + childWidth;
-                break;
-        }
-        child.layout(left, top, right, bottom);
-    }
-
-    @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs, this);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
-                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
-                new LayoutParams(p);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams();
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    public static class LayoutParams extends MarginLayoutParams {
-
-        public float centerWithinArea = 0;
-
-        public int childType = 0;
-
-        public static final int CHILD_TYPE_NONE = 0;
-        public static final int CHILD_TYPE_WIDGET = 1;
-        public static final int CHILD_TYPE_CHALLENGE = 2;
-        public static final int CHILD_TYPE_USER_SWITCHER = 3;
-        public static final int CHILD_TYPE_SCRIM = 4;
-        public static final int CHILD_TYPE_PAGE_DELETE_DROP_TARGET = 7;
-
-        public int gravity = Gravity.NO_GRAVITY;
-
-        public int maxWidth = -1;
-        public int maxHeight = -1;
-
-        public LayoutParams() {
-            this(WRAP_CONTENT, WRAP_CONTENT);
-        }
-
-        LayoutParams(Context c, AttributeSet attrs, MultiPaneChallengeLayout parent) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs,
-                    R.styleable.MultiPaneChallengeLayout_Layout);
-
-            centerWithinArea = a.getFloat(
-                    R.styleable.MultiPaneChallengeLayout_Layout_layout_centerWithinArea, 0);
-            childType = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_childType,
-                    CHILD_TYPE_NONE);
-            gravity = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_gravity,
-                    Gravity.NO_GRAVITY);
-            maxWidth = a.getDimensionPixelSize(
-                    R.styleable.MultiPaneChallengeLayout_Layout_layout_maxWidth, -1);
-            maxHeight = a.getDimensionPixelSize(
-                    R.styleable.MultiPaneChallengeLayout_Layout_layout_maxHeight, -1);
-
-            // Default gravity settings based on type and parent orientation
-            if (gravity == Gravity.NO_GRAVITY) {
-                if (parent.mOrientation == HORIZONTAL) {
-                    switch (childType) {
-                        case CHILD_TYPE_WIDGET:
-                            gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
-                            break;
-                        case CHILD_TYPE_CHALLENGE:
-                            gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
-                            break;
-                        case CHILD_TYPE_USER_SWITCHER:
-                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-                            break;
-                    }
-                } else {
-                    switch (childType) {
-                        case CHILD_TYPE_WIDGET:
-                            gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
-                            break;
-                        case CHILD_TYPE_CHALLENGE:
-                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-                            break;
-                        case CHILD_TYPE_USER_SWITCHER:
-                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-                            break;
-                    }
-                }
-            }
-
-            a.recycle();
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(LayoutParams source) {
-            this((MarginLayoutParams) source);
-
-            centerWithinArea = source.centerWithinArea;
-            childType = source.childType;
-            gravity = source.gravity;
-            maxWidth = source.maxWidth;
-            maxHeight = source.maxHeight;
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java
deleted file mode 100644
index 7969c7d..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.graphics.drawable.Drawable;
-
-import java.util.HashMap;
-
-public class MultiUserAvatarCache {
-
-    private final HashMap<Integer, Drawable> mCache;
-
-    public MultiUserAvatarCache() {
-        mCache = new HashMap<Integer, Drawable>();
-    }
-
-    public void clear(int userId) {
-        mCache.remove(userId);
-    }
-
-    public Drawable get(int userId) {
-        return mCache.get(userId);
-    }
-
-    public void put(int userId, Drawable image) {
-        mCache.put(userId, image);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
deleted file mode 100644
index a0038bc..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.text.SpannableStringBuilder;
-import android.text.style.TextAppearanceSpan;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-public class NumPadKey extends Button {
-    // list of "ABC", etc per digit, starting with '0'
-    static String sKlondike[];
-
-    int mDigit = -1;
-    int mTextViewResId;
-    TextView mTextView = null;
-    boolean mEnableHaptics;
-
-    private View.OnClickListener mListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View thisView) {
-            if (mTextView == null) {
-                if (mTextViewResId > 0) {
-                    final View v = NumPadKey.this.getRootView().findViewById(mTextViewResId);
-                    if (v != null && v instanceof TextView) {
-                        mTextView = (TextView) v;
-                    }
-                }
-            }
-            // check for time-based lockouts
-            if (mTextView != null && mTextView.isEnabled()) {
-                mTextView.append(String.valueOf(mDigit));
-            }
-            doHapticKeyClick();
-        }
-    };
-
-    public NumPadKey(Context context) {
-        this(context, null);
-    }
-
-    public NumPadKey(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NumPadKey(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey);
-        mDigit = a.getInt(R.styleable.NumPadKey_digit, mDigit);
-        setTextViewResId(a.getResourceId(R.styleable.NumPadKey_textView, 0));
-
-        setOnClickListener(mListener);
-        setOnHoverListener(new LiftToActivateListener(context));
-        setAccessibilityDelegate(new ObscureSpeechDelegate(context));
-
-        mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
-
-        SpannableStringBuilder builder = new SpannableStringBuilder();
-        builder.append(String.valueOf(mDigit));
-        if (mDigit >= 0) {
-            if (sKlondike == null) {
-                sKlondike = context.getResources().getStringArray(
-                        R.array.lockscreen_num_pad_klondike);
-            }
-            if (sKlondike != null && sKlondike.length > mDigit) {
-                final String extra = sKlondike[mDigit];
-                final int extraLen = extra.length();
-                if (extraLen > 0) {
-                    builder.append(" ");
-                    builder.append(extra);
-                    builder.setSpan(
-                        new TextAppearanceSpan(context, R.style.TextAppearance_NumPadKey_Klondike),
-                        builder.length()-extraLen, builder.length(), 0);
-                }
-            }
-        }
-        setText(builder);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        // Reset the "announced headset" flag when detached.
-        ObscureSpeechDelegate.sAnnouncedHeadset = false;
-    }
-
-    public void setTextView(TextView tv) {
-        mTextView = tv;
-    }
-
-    public void setTextViewResId(int resId) {
-        mTextView = null;
-        mTextViewResId = resId;
-    }
-
-    // Cause a VIRTUAL_KEY vibration
-    public void doHapticKeyClick() {
-        if (mEnableHaptics) {
-            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
-                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
-                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java
deleted file mode 100644
index af043ab..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.media.AudioManager;
-import android.provider.Settings;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.android.internal.R;
-
-/**
- * Accessibility delegate that obscures speech for a view when the user has
- * not turned on the "speak passwords" preference and is not listening
- * through headphones.
- */
-class ObscureSpeechDelegate extends AccessibilityDelegate {
-    /** Whether any client has announced the "headset" notification. */
-    static boolean sAnnouncedHeadset = false;
-
-    private final ContentResolver mContentResolver;
-    private final AudioManager mAudioManager;
-
-    public ObscureSpeechDelegate(Context context) {
-        mContentResolver = context.getContentResolver();
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-    }
-
-    @Override
-    public void sendAccessibilityEvent(View host, int eventType) {
-        super.sendAccessibilityEvent(host, eventType);
-
-        // Play the "headset required" announcement the first time the user
-        // places accessibility focus on a key.
-        if ((eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED)
-                && !sAnnouncedHeadset && shouldObscureSpeech()) {
-            sAnnouncedHeadset = true;
-            host.announceForAccessibility(host.getContext().getString(
-                    R.string.keyboard_headset_required_to_hear_password));
-        }
-    }
-
-    @Override
-    public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(host, event);
-
-        if ((event.getEventType() != AccessibilityEvent.TYPE_ANNOUNCEMENT)
-                && shouldObscureSpeech()) {
-            event.getText().clear();
-            event.setContentDescription(host.getContext().getString(
-                    R.string.keyboard_password_character_no_headset));
-        }
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(host, info);
-
-        if (shouldObscureSpeech()) {
-            final Context ctx = host.getContext();
-            info.setText(null);
-            info.setContentDescription(
-                    ctx.getString(R.string.keyboard_password_character_no_headset));
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    private boolean shouldObscureSpeech() {
-        // The user can optionally force speaking passwords.
-        if (Settings.Secure.getInt(mContentResolver,
-                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0) {
-            return false;
-        }
-
-        // Always speak if the user is listening through headphones.
-        if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) {
-            return false;
-        }
-
-        // Don't speak since this key is used to type a password.
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
deleted file mode 100644
index 10562e8..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ /dev/null
@@ -1,2569 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.widget.Scroller;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-
-/**
- * An abstraction of the original Workspace which supports browsing through a
- * sequential list of "pages"
- */
-public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
-    private static final String TAG = "WidgetPagedView";
-    private static final boolean DEBUG = false;
-    protected static final int INVALID_PAGE = -1;
-
-    // the min drag distance for a fling to register, to prevent random page shifts
-    private static final int MIN_LENGTH_FOR_FLING = 25;
-
-    protected static final int PAGE_SNAP_ANIMATION_DURATION = 750;
-    protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
-    protected static final float NANOTIME_DIV = 1000000000.0f;
-
-    private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
-    private static final float OVERSCROLL_DAMP_FACTOR = 0.14f;
-
-    private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
-    // The page is moved more than halfway, automatically move to the next page on touch up.
-    private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
-
-    // The following constants need to be scaled based on density. The scaled versions will be
-    // assigned to the corresponding member variables below.
-    private static final int FLING_THRESHOLD_VELOCITY = 500;
-    private static final int MIN_SNAP_VELOCITY = 1500;
-    private static final int MIN_FLING_VELOCITY = 250;
-
-    // We are disabling touch interaction of the widget region for factory ROM.
-    private static final boolean DISABLE_TOUCH_INTERACTION = false;
-    private static final boolean DISABLE_TOUCH_SIDE_PAGES = true;
-    private static final boolean DISABLE_FLING_TO_DELETE = false;
-
-    static final int AUTOMATIC_PAGE_SPACING = -1;
-
-    protected int mFlingThresholdVelocity;
-    protected int mMinFlingVelocity;
-    protected int mMinSnapVelocity;
-
-    protected float mDensity;
-    protected float mSmoothingTime;
-    protected float mTouchX;
-
-    protected boolean mFirstLayout = true;
-
-    protected int mCurrentPage;
-    protected int mChildCountOnLastMeasure;
-
-    protected int mNextPage = INVALID_PAGE;
-    protected int mMaxScrollX;
-    protected Scroller mScroller;
-    private VelocityTracker mVelocityTracker;
-
-    private float mParentDownMotionX;
-    private float mParentDownMotionY;
-    private float mDownMotionX;
-    private float mDownMotionY;
-    private float mDownScrollX;
-    protected float mLastMotionX;
-    protected float mLastMotionXRemainder;
-    protected float mLastMotionY;
-    protected float mTotalMotionX;
-    private int mLastScreenCenter = -1;
-    private int[] mChildOffsets;
-    private int[] mChildRelativeOffsets;
-    private int[] mChildOffsetsWithLayoutScale;
-
-    protected final static int TOUCH_STATE_REST = 0;
-    protected final static int TOUCH_STATE_SCROLLING = 1;
-    protected final static int TOUCH_STATE_PREV_PAGE = 2;
-    protected final static int TOUCH_STATE_NEXT_PAGE = 3;
-    protected final static int TOUCH_STATE_REORDERING = 4;
-
-    protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
-
-    protected int mTouchState = TOUCH_STATE_REST;
-    protected boolean mForceScreenScrolled = false;
-
-    protected OnLongClickListener mLongClickListener;
-
-    protected int mTouchSlop;
-    private int mPagingTouchSlop;
-    private int mMaximumVelocity;
-    private int mMinimumWidth;
-    protected int mPageSpacing;
-    protected int mCellCountX = 0;
-    protected int mCellCountY = 0;
-    protected boolean mAllowOverScroll = true;
-    protected int mUnboundedScrollX;
-    protected int[] mTempVisiblePagesRange = new int[2];
-    protected boolean mForceDrawAllChildrenNextFrame;
-
-    // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
-    // it is equal to the scaled overscroll position. We use a separate value so as to prevent
-    // the screens from continuing to translate beyond the normal bounds.
-    protected int mOverScrollX;
-
-    // parameter that adjusts the layout to be optimized for pages with that scale factor
-    protected float mLayoutScale = 1.0f;
-
-    protected static final int INVALID_POINTER = -1;
-
-    protected int mActivePointerId = INVALID_POINTER;
-
-    private PageSwitchListener mPageSwitchListener;
-
-    protected ArrayList<Boolean> mDirtyPageContent;
-
-    // If true, syncPages and syncPageItems will be called to refresh pages
-    protected boolean mContentIsRefreshable = true;
-
-    // If true, modify alpha of neighboring pages as user scrolls left/right
-    protected boolean mFadeInAdjacentScreens = false;
-
-    // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
-    // to switch to a new page
-    protected boolean mUsePagingTouchSlop = true;
-
-    // If true, the subclass should directly update scrollX itself in its computeScroll method
-    // (SmoothPagedView does this)
-    protected boolean mDeferScrollUpdate = false;
-
-    protected boolean mIsPageMoving = false;
-
-    // All syncs and layout passes are deferred until data is ready.
-    protected boolean mIsDataReady = true;
-
-    // Scrolling indicator
-    private ValueAnimator mScrollIndicatorAnimator;
-    private View mScrollIndicator;
-    private int mScrollIndicatorPaddingLeft;
-    private int mScrollIndicatorPaddingRight;
-    private boolean mShouldShowScrollIndicator = false;
-    private boolean mShouldShowScrollIndicatorImmediately = false;
-    protected static final int sScrollIndicatorFadeInDuration = 150;
-    protected static final int sScrollIndicatorFadeOutDuration = 650;
-    protected static final int sScrollIndicatorFlashDuration = 650;
-
-    // The viewport whether the pages are to be contained (the actual view may be larger than the
-    // viewport)
-    private Rect mViewport = new Rect();
-
-    // Reordering
-    // We use the min scale to determine how much to expand the actually PagedView measured
-    // dimensions such that when we are zoomed out, the view is not clipped
-    private int REORDERING_DROP_REPOSITION_DURATION = 200;
-    protected int REORDERING_REORDER_REPOSITION_DURATION = 300;
-    protected int REORDERING_ZOOM_IN_OUT_DURATION = 250;
-    private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300;
-    private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f;
-    private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150;
-    private float mMinScale = 1f;
-    protected View mDragView;
-    protected AnimatorSet mZoomInOutAnim;
-    private Runnable mSidePageHoverRunnable;
-    private int mSidePageHoverIndex = -1;
-    // This variable's scope is only for the duration of startReordering() and endReordering()
-    private boolean mReorderingStarted = false;
-    // This variable's scope is for the duration of startReordering() and after the zoomIn()
-    // animation after endReordering()
-    private boolean mIsReordering;
-    // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition
-    private int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2;
-    private int mPostReorderingPreZoomInRemainingAnimationCount;
-    private Runnable mPostReorderingPreZoomInRunnable;
-
-    // Edge swiping
-    private boolean mOnlyAllowEdgeSwipes = false;
-    private boolean mDownEventOnEdge = false;
-    private int mEdgeSwipeRegionSize = 0;
-
-    // Convenience/caching
-    private Matrix mTmpInvMatrix = new Matrix();
-    private float[] mTmpPoint = new float[2];
-    private Rect mTmpRect = new Rect();
-    private Rect mAltTmpRect = new Rect();
-
-    // Fling to delete
-    private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
-    private float FLING_TO_DELETE_FRICTION = 0.035f;
-    // The degrees specifies how much deviation from the up vector to still consider a fling "up"
-    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
-    protected int mFlingToDeleteThresholdVelocity = -1400;
-    // Drag to delete
-    private boolean mDeferringForDelete = false;
-    private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
-    private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
-
-    // Drop to delete
-    private View mDeleteDropTarget;
-
-    // Bouncer
-    private boolean mTopAlignPageWhenShrinkingForBouncer = false;
-
-    public interface PageSwitchListener {
-        void onPageSwitching(View newPage, int newPageIndex);
-        void onPageSwitched(View newPage, int newPageIndex);
-    }
-
-    public PagedView(Context context) {
-        this(context, null);
-    }
-
-    public PagedView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public PagedView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.PagedView, defStyle, 0);
-        setPageSpacing(a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0));
-        mScrollIndicatorPaddingLeft =
-            a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingLeft, 0);
-        mScrollIndicatorPaddingRight =
-                a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0);
-        a.recycle();
-
-        Resources r = getResources();
-        mEdgeSwipeRegionSize = r.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
-        mTopAlignPageWhenShrinkingForBouncer =
-                r.getBoolean(R.bool.kg_top_align_page_shrink_on_bouncer_visible);
-
-        setHapticFeedbackEnabled(false);
-        init();
-    }
-
-    /**
-     * Initializes various states for this workspace.
-     */
-    protected void init() {
-        mDirtyPageContent = new ArrayList<Boolean>();
-        mDirtyPageContent.ensureCapacity(32);
-        mScroller = new Scroller(getContext(), new ScrollInterpolator());
-        mCurrentPage = 0;
-
-        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
-        mTouchSlop = configuration.getScaledTouchSlop();
-        mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
-        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mDensity = getResources().getDisplayMetrics().density;
-
-        // Scale the fling-to-delete threshold by the density
-        mFlingToDeleteThresholdVelocity =
-                (int) (mFlingToDeleteThresholdVelocity * mDensity);
-
-        mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
-        mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
-        mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
-        setOnHierarchyChangeListener(this);
-    }
-
-    void setDeleteDropTarget(View v) {
-        mDeleteDropTarget = v;
-    }
-
-    // Convenience methods to map points from self to parent and vice versa
-    float[] mapPointFromViewToParent(View v, float x, float y) {
-        mTmpPoint[0] = x;
-        mTmpPoint[1] = y;
-        v.getMatrix().mapPoints(mTmpPoint);
-        mTmpPoint[0] += v.getLeft();
-        mTmpPoint[1] += v.getTop();
-        return mTmpPoint;
-    }
-    float[] mapPointFromParentToView(View v, float x, float y) {
-        mTmpPoint[0] = x - v.getLeft();
-        mTmpPoint[1] = y - v.getTop();
-        v.getMatrix().invert(mTmpInvMatrix);
-        mTmpInvMatrix.mapPoints(mTmpPoint);
-        return mTmpPoint;
-    }
-
-    void updateDragViewTranslationDuringDrag() {
-        float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX;
-        float y = mLastMotionY - mDownMotionY;
-        mDragView.setTranslationX(x);
-        mDragView.setTranslationY(y);
-
-        if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y);
-    }
-
-    public void setMinScale(float f) {
-        mMinScale = f;
-        requestLayout();
-    }
-
-    @Override
-    public void setScaleX(float scaleX) {
-        super.setScaleX(scaleX);
-        if (isReordering(true)) {
-            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
-            mLastMotionX = p[0];
-            mLastMotionY = p[1];
-            updateDragViewTranslationDuringDrag();
-        }
-    }
-
-    // Convenience methods to get the actual width/height of the PagedView (since it is measured
-    // to be larger to account for the minimum possible scale)
-    int getViewportWidth() {
-        return mViewport.width();
-    }
-    int getViewportHeight() {
-        return mViewport.height();
-    }
-
-    // Convenience methods to get the offset ASSUMING that we are centering the pages in the
-    // PagedView both horizontally and vertically
-    int getViewportOffsetX() {
-        return (getMeasuredWidth() - getViewportWidth()) / 2;
-    }
-    int getViewportOffsetY() {
-        return (getMeasuredHeight() - getViewportHeight()) / 2;
-    }
-
-    public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
-        mPageSwitchListener = pageSwitchListener;
-        if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
-        }
-    }
-
-    /**
-     * Called by subclasses to mark that data is ready, and that we can begin loading and laying
-     * out pages.
-     */
-    protected void setDataIsReady() {
-        mIsDataReady = true;
-    }
-
-    protected boolean isDataReady() {
-        return mIsDataReady;
-    }
-
-    /**
-     * Returns the index of the currently displayed page.
-     *
-     * @return The index of the currently displayed page.
-     */
-    int getCurrentPage() {
-        return mCurrentPage;
-    }
-
-    int getNextPage() {
-        return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
-    }
-
-    int getPageCount() {
-        return getChildCount();
-    }
-
-    View getPageAt(int index) {
-        return getChildAt(index);
-    }
-
-    protected int indexToPage(int index) {
-        return index;
-    }
-
-    /**
-     * Updates the scroll of the current page immediately to its final scroll position.  We use this
-     * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
-     * the previous tab page.
-     */
-    protected void updateCurrentPageScroll() {
-        int offset = getChildOffset(mCurrentPage);
-        int relOffset = getRelativeChildOffset(mCurrentPage);
-        int newX = offset - relOffset;
-        scrollTo(newX, 0);
-        mScroller.setFinalX(newX);
-        mScroller.forceFinished(true);
-    }
-
-    /**
-     * Sets the current page.
-     */
-    void setCurrentPage(int currentPage) {
-        notifyPageSwitching(currentPage);
-        if (!mScroller.isFinished()) {
-            mScroller.abortAnimation();
-        }
-        // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
-        // the default
-        if (getChildCount() == 0) {
-            return;
-        }
-
-        mForceScreenScrolled = true;
-        mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
-        updateCurrentPageScroll();
-        updateScrollingIndicator();
-        notifyPageSwitched();
-        invalidate();
-    }
-
-    public void setOnlyAllowEdgeSwipes(boolean enable) {
-        mOnlyAllowEdgeSwipes = enable;
-    }
-
-    protected void notifyPageSwitching(int whichPage) {
-        if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage);
-        }
-    }
-
-    protected void notifyPageSwitched() {
-        if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
-        }
-    }
-
-    protected void pageBeginMoving() {
-        if (!mIsPageMoving) {
-            mIsPageMoving = true;
-            onPageBeginMoving();
-        }
-    }
-
-    protected void pageEndMoving() {
-        if (mIsPageMoving) {
-            mIsPageMoving = false;
-            onPageEndMoving();
-        }
-    }
-
-    protected boolean isPageMoving() {
-        return mIsPageMoving;
-    }
-
-    // a method that subclasses can override to add behavior
-    protected void onPageBeginMoving() {
-    }
-
-    // a method that subclasses can override to add behavior
-    protected void onPageEndMoving() {
-    }
-
-    /**
-     * Registers the specified listener on each page contained in this workspace.
-     *
-     * @param l The listener used to respond to long clicks.
-     */
-    @Override
-    public void setOnLongClickListener(OnLongClickListener l) {
-        mLongClickListener = l;
-        final int count = getPageCount();
-        for (int i = 0; i < count; i++) {
-            getPageAt(i).setOnLongClickListener(l);
-        }
-    }
-
-    @Override
-    public void scrollBy(int x, int y) {
-        scrollTo(mUnboundedScrollX + x, getScrollY() + y);
-    }
-
-    @Override
-    public void scrollTo(int x, int y) {
-        mUnboundedScrollX = x;
-
-        if (x < 0) {
-            super.scrollTo(0, y);
-            if (mAllowOverScroll) {
-                overScroll(x);
-            }
-        } else if (x > mMaxScrollX) {
-            super.scrollTo(mMaxScrollX, y);
-            if (mAllowOverScroll) {
-                overScroll(x - mMaxScrollX);
-            }
-        } else {
-            mOverScrollX = x;
-            super.scrollTo(x, y);
-        }
-
-        mTouchX = x;
-        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-
-        // Update the last motion events when scrolling
-        if (isReordering(true)) {
-            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
-            mLastMotionX = p[0];
-            mLastMotionY = p[1];
-            updateDragViewTranslationDuringDrag();
-        }
-    }
-
-    // we moved this functionality to a helper function so SmoothPagedView can reuse it
-    protected boolean computeScrollHelper() {
-        if (mScroller.computeScrollOffset()) {
-            // Don't bother scrolling if the page does not need to be moved
-            if (getScrollX() != mScroller.getCurrX()
-                || getScrollY() != mScroller.getCurrY()
-                || mOverScrollX != mScroller.getCurrX()) {
-                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
-            }
-            invalidate();
-            return true;
-        } else if (mNextPage != INVALID_PAGE) {
-            mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
-            mNextPage = INVALID_PAGE;
-            notifyPageSwitched();
-
-            // We don't want to trigger a page end moving unless the page has settled
-            // and the user has stopped scrolling
-            if (mTouchState == TOUCH_STATE_REST) {
-                pageEndMoving();
-            }
-
-            onPostReorderingAnimationCompleted();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void computeScroll() {
-        computeScrollHelper();
-    }
-
-    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
-        return mTopAlignPageWhenShrinkingForBouncer;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (!mIsDataReady || getChildCount() == 0) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
-        // We measure the dimensions of the PagedView to be larger than the pages so that when we
-        // zoom out (and scale down), the view is still contained in the parent
-        View parent = (View) getParent();
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-        // NOTE: We multiply by 1.5f to account for the fact that depending on the offset of the
-        // viewport, we can be at most one and a half screens offset once we scale down
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        int maxSize = Math.max(dm.widthPixels, dm.heightPixels);
-        int parentWidthSize = (int) (1.5f * maxSize);
-        int parentHeightSize = maxSize;
-        int scaledWidthSize = (int) (parentWidthSize / mMinScale);
-        int scaledHeightSize = (int) (parentHeightSize / mMinScale);
-        mViewport.set(0, 0, widthSize, heightSize);
-
-        if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
-        // Return early if we aren't given a proper dimension
-        if (widthSize <= 0 || heightSize <= 0) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
-        /* Allow the height to be set as WRAP_CONTENT. This allows the particular case
-         * of the All apps view on XLarge displays to not take up more space then it needs. Width
-         * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
-         * each page to have the same width.
-         */
-        final int verticalPadding = getPaddingTop() + getPaddingBottom();
-        final int horizontalPadding = getPaddingLeft() + getPaddingRight();
-
-        // The children are given the same width and height as the workspace
-        // unless they were set to WRAP_CONTENT
-        if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
-        if (DEBUG) Log.d(TAG, "PagedView.scaledSize: " + scaledWidthSize + ", " + scaledHeightSize);
-        if (DEBUG) Log.d(TAG, "PagedView.parentSize: " + parentWidthSize + ", " + parentHeightSize);
-        if (DEBUG) Log.d(TAG, "PagedView.horizontalPadding: " + horizontalPadding);
-        if (DEBUG) Log.d(TAG, "PagedView.verticalPadding: " + verticalPadding);
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            // disallowing padding in paged view (just pass 0)
-            final View child = getPageAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            int childWidthMode;
-            if (lp.width == LayoutParams.WRAP_CONTENT) {
-                childWidthMode = MeasureSpec.AT_MOST;
-            } else {
-                childWidthMode = MeasureSpec.EXACTLY;
-            }
-
-            int childHeightMode;
-            if (lp.height == LayoutParams.WRAP_CONTENT) {
-                childHeightMode = MeasureSpec.AT_MOST;
-            } else {
-                childHeightMode = MeasureSpec.EXACTLY;
-            }
-
-            final int childWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
-            final int childHeightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
-
-            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-        }
-        setMeasuredDimension(scaledWidthSize, scaledHeightSize);
-
-        // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
-        // We also wait until we set the measured dimensions before flushing the cache as well, to
-        // ensure that the cache is filled with good values.
-        invalidateCachedOffsets();
-
-        if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) {
-            setCurrentPage(mCurrentPage);
-        }
-        mChildCountOnLastMeasure = getChildCount();
-
-        if (childCount > 0) {
-            if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getViewportWidth() + ", "
-                    + getChildWidth(0));
-
-            // Calculate the variable page spacing if necessary
-            if (mPageSpacing == AUTOMATIC_PAGE_SPACING) {
-                // The gap between pages in the PagedView should be equal to the gap from the page
-                // to the edge of the screen (so it is not visible in the current screen).  To
-                // account for unequal padding on each side of the paged view, we take the maximum
-                // of the left/right gap and use that as the gap between each page.
-                int offset = getRelativeChildOffset(0);
-                int spacing = Math.max(offset, widthSize - offset -
-                        getChildAt(0).getMeasuredWidth());
-                setPageSpacing(spacing);
-            }
-        }
-
-        updateScrollingIndicatorPosition();
-
-        if (childCount > 0) {
-            mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
-        } else {
-            mMaxScrollX = 0;
-        }
-    }
-
-    public void setPageSpacing(int pageSpacing) {
-        mPageSpacing = pageSpacing;
-        invalidateCachedOffsets();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (!mIsDataReady || getChildCount() == 0) {
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
-        final int childCount = getChildCount();
-
-        int offsetX = getViewportOffsetX();
-        int offsetY = getViewportOffsetY();
-
-        // Update the viewport offsets
-        mViewport.offset(offsetX,  offsetY);
-
-        int childLeft = offsetX + getRelativeChildOffset(0);
-        for (int i = 0; i < childCount; i++) {
-            final View child = getPageAt(i);
-            int childTop = offsetY + getPaddingTop();
-            if (child.getVisibility() != View.GONE) {
-                final int childWidth = getScaledMeasuredWidth(child);
-                final int childHeight = child.getMeasuredHeight();
-
-                if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
-                child.layout(childLeft, childTop,
-                        childLeft + child.getMeasuredWidth(), childTop + childHeight);
-                childLeft += childWidth + mPageSpacing;
-            }
-        }
-
-        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
-            setHorizontalScrollBarEnabled(false);
-            updateCurrentPageScroll();
-            setHorizontalScrollBarEnabled(true);
-            mFirstLayout = false;
-        }
-    }
-
-    protected void screenScrolled(int screenCenter) {
-    }
-
-    @Override
-    public void onChildViewAdded(View parent, View child) {
-        // This ensures that when children are added, they get the correct transforms / alphas
-        // in accordance with any scroll effects.
-        mForceScreenScrolled = true;
-        invalidate();
-        invalidateCachedOffsets();
-    }
-
-    @Override
-    public void onChildViewRemoved(View parent, View child) {
-        mForceScreenScrolled = true;
-        invalidate();
-        invalidateCachedOffsets();
-    }
-
-    protected void invalidateCachedOffsets() {
-        int count = getChildCount();
-        if (count == 0) {
-            mChildOffsets = null;
-            mChildRelativeOffsets = null;
-            mChildOffsetsWithLayoutScale = null;
-            return;
-        }
-
-        mChildOffsets = new int[count];
-        mChildRelativeOffsets = new int[count];
-        mChildOffsetsWithLayoutScale = new int[count];
-        for (int i = 0; i < count; i++) {
-            mChildOffsets[i] = -1;
-            mChildRelativeOffsets[i] = -1;
-            mChildOffsetsWithLayoutScale[i] = -1;
-        }
-    }
-
-    protected int getChildOffset(int index) {
-        if (index < 0 || index > getChildCount() - 1) return 0;
-
-        int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
-                mChildOffsets : mChildOffsetsWithLayoutScale;
-
-        if (childOffsets != null && childOffsets[index] != -1) {
-            return childOffsets[index];
-        } else {
-            if (getChildCount() == 0)
-                return 0;
-
-            int offset = getRelativeChildOffset(0);
-            for (int i = 0; i < index; ++i) {
-                offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
-            }
-            if (childOffsets != null) {
-                childOffsets[index] = offset;
-            }
-            return offset;
-        }
-    }
-
-    protected int getRelativeChildOffset(int index) {
-        if (index < 0 || index > getChildCount() - 1) return 0;
-
-        if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) {
-            return mChildRelativeOffsets[index];
-        } else {
-            final int padding = getPaddingLeft() + getPaddingRight();
-            final int offset = getPaddingLeft() +
-                    (getViewportWidth() - padding - getChildWidth(index)) / 2;
-            if (mChildRelativeOffsets != null) {
-                mChildRelativeOffsets[index] = offset;
-            }
-            return offset;
-        }
-    }
-
-    protected int getScaledMeasuredWidth(View child) {
-        // This functions are called enough times that it actually makes a difference in the
-        // profiler -- so just inline the max() here
-        final int measuredWidth = child.getMeasuredWidth();
-        final int minWidth = mMinimumWidth;
-        final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
-        return (int) (maxWidth * mLayoutScale + 0.5f);
-    }
-
-    void boundByReorderablePages(boolean isReordering, int[] range) {
-        // Do nothing
-    }
-
-    // TODO: Fix this
-    protected void getVisiblePages(int[] range) {
-        range[0] = 0;
-        range[1] = getPageCount() - 1;
-
-        /*
-        final int pageCount = getChildCount();
-
-        if (pageCount > 0) {
-            final int screenWidth = getViewportWidth();
-            int leftScreen = 0;
-            int rightScreen = 0;
-            int offsetX = getViewportOffsetX() + getScrollX();
-            View currPage = getPageAt(leftScreen);
-            while (leftScreen < pageCount - 1 &&
-                    currPage.getX() + currPage.getWidth() -
-                    currPage.getPaddingRight() < offsetX) {
-                leftScreen++;
-                currPage = getPageAt(leftScreen);
-            }
-            rightScreen = leftScreen;
-            currPage = getPageAt(rightScreen + 1);
-            while (rightScreen < pageCount - 1 &&
-                    currPage.getX() - currPage.getPaddingLeft() < offsetX + screenWidth) {
-                rightScreen++;
-                currPage = getPageAt(rightScreen + 1);
-            }
-
-            // TEMP: this is a hacky way to ensure that animations to new pages are not clipped
-            // because we don't draw them while scrolling?
-            range[0] = Math.max(0, leftScreen - 1);
-            range[1] = Math.min(rightScreen + 1, getChildCount() - 1);
-        } else {
-            range[0] = -1;
-            range[1] = -1;
-        }
-        */
-    }
-
-    protected boolean shouldDrawChild(View child) {
-        return child.getAlpha() > 0;
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        int halfScreenSize = getViewportWidth() / 2;
-        // mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
-        // Otherwise it is equal to the scaled overscroll position.
-        int screenCenter = mOverScrollX + halfScreenSize;
-
-        if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
-            // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can
-            // set it for the next frame
-            mForceScreenScrolled = false;
-            screenScrolled(screenCenter);
-            mLastScreenCenter = screenCenter;
-        }
-
-        // Find out which screens are visible; as an optimization we only call draw on them
-        final int pageCount = getChildCount();
-        if (pageCount > 0) {
-            getVisiblePages(mTempVisiblePagesRange);
-            final int leftScreen = mTempVisiblePagesRange[0];
-            final int rightScreen = mTempVisiblePagesRange[1];
-            if (leftScreen != -1 && rightScreen != -1) {
-                final long drawingTime = getDrawingTime();
-                // Clip to the bounds
-                canvas.save();
-                canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
-                        getScrollY() + getBottom() - getTop());
-
-                // Draw all the children, leaving the drag view for last
-                for (int i = pageCount - 1; i >= 0; i--) {
-                    final View v = getPageAt(i);
-                    if (v == mDragView) continue;
-                    if (mForceDrawAllChildrenNextFrame ||
-                               (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
-                        drawChild(canvas, v, drawingTime);
-                    }
-                }
-                // Draw the drag view on top (if there is one)
-                if (mDragView != null) {
-                    drawChild(canvas, mDragView, drawingTime);
-                }
-
-                mForceDrawAllChildrenNextFrame = false;
-                canvas.restore();
-            }
-        }
-    }
-
-    @Override
-    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
-        int page = indexToPage(indexOfChild(child));
-        if (page != mCurrentPage || !mScroller.isFinished()) {
-            snapToPage(page);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        int focusablePage;
-        if (mNextPage != INVALID_PAGE) {
-            focusablePage = mNextPage;
-        } else {
-            focusablePage = mCurrentPage;
-        }
-        View v = getPageAt(focusablePage);
-        if (v != null) {
-            return v.requestFocus(direction, previouslyFocusedRect);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean dispatchUnhandledMove(View focused, int direction) {
-        if (direction == View.FOCUS_LEFT) {
-            if (getCurrentPage() > 0) {
-                snapToPage(getCurrentPage() - 1);
-                return true;
-            }
-        } else if (direction == View.FOCUS_RIGHT) {
-            if (getCurrentPage() < getPageCount() - 1) {
-                snapToPage(getCurrentPage() + 1);
-                return true;
-            }
-        }
-        return super.dispatchUnhandledMove(focused, direction);
-    }
-
-    @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
-            getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
-        }
-        if (direction == View.FOCUS_LEFT) {
-            if (mCurrentPage > 0) {
-                getPageAt(mCurrentPage - 1).addFocusables(views, direction, focusableMode);
-            }
-        } else if (direction == View.FOCUS_RIGHT){
-            if (mCurrentPage < getPageCount() - 1) {
-                getPageAt(mCurrentPage + 1).addFocusables(views, direction, focusableMode);
-            }
-        }
-    }
-
-    /**
-     * If one of our descendant views decides that it could be focused now, only
-     * pass that along if it's on the current page.
-     *
-     * This happens when live folders requery, and if they're off page, they
-     * end up calling requestFocus, which pulls it on page.
-     */
-    @Override
-    public void focusableViewAvailable(View focused) {
-        View current = getPageAt(mCurrentPage);
-        View v = focused;
-        while (true) {
-            if (v == current) {
-                super.focusableViewAvailable(focused);
-                return;
-            }
-            if (v == this) {
-                return;
-            }
-            ViewParent parent = v.getParent();
-            if (parent instanceof View) {
-                v = (View)v.getParent();
-            } else {
-                return;
-            }
-        }
-    }
-
-    /**
-     * Return true if a tap at (x, y) should trigger a flip to the previous page.
-     */
-    protected boolean hitsPreviousPage(float x, float y) {
-        return (x < getViewportOffsetX() + getRelativeChildOffset(mCurrentPage) - mPageSpacing);
-    }
-
-    /**
-     * Return true if a tap at (x, y) should trigger a flip to the next page.
-     */
-    protected boolean hitsNextPage(float x, float y) {
-        return  (x > (getViewportOffsetX() + getViewportWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
-    }
-
-    /** Returns whether x and y originated within the buffered viewport */
-    private boolean isTouchPointInViewportWithBuffer(int x, int y) {
-        mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
-                mViewport.right + mViewport.width() / 2, mViewport.bottom);
-        return mTmpRect.contains(x, y);
-    }
-
-    /** Returns whether x and y originated within the current page view bounds */
-    private boolean isTouchPointInCurrentPage(int x, int y) {
-        View v = getPageAt(getCurrentPage());
-        if (v != null) {
-            mTmpRect.set((v.getLeft() - getScrollX()), 0, (v.getRight() - getScrollX()),
-                    v.getBottom());
-            return mTmpRect.contains(x, y);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DISABLE_TOUCH_INTERACTION) {
-            return false;
-        }
-
-        /*
-         * This method JUST determines whether we want to intercept the motion.
-         * If we return true, onTouchEvent will be called and we do the actual
-         * scrolling there.
-         */
-        acquireVelocityTrackerAndAddMovement(ev);
-
-        // Skip touch handling if there are no pages to swipe
-        if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
-
-        /*
-         * Shortcut the most recurring case: the user is in the dragging
-         * state and he is moving his finger.  We want to intercept this
-         * motion.
-         */
-        final int action = ev.getAction();
-        if ((action == MotionEvent.ACTION_MOVE) &&
-                (mTouchState == TOUCH_STATE_SCROLLING)) {
-            return true;
-        }
-
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_MOVE: {
-                /*
-                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
-                 * whether the user has moved far enough from his original down touch.
-                 */
-                if (mActivePointerId != INVALID_POINTER) {
-                    determineScrollingStart(ev);
-                    break;
-                }
-                // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
-                // event. in that case, treat the first occurence of a move event as a ACTION_DOWN
-                // i.e. fall through to the next case (don't break)
-                // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
-                // while it's small- this was causing a crash before we checked for INVALID_POINTER)
-            }
-
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                // Remember location of down touch
-                mDownMotionX = x;
-                mDownMotionY = y;
-                mDownScrollX = getScrollX();
-                mLastMotionX = x;
-                mLastMotionY = y;
-                float[] p = mapPointFromViewToParent(this, x, y);
-                mParentDownMotionX = p[0];
-                mParentDownMotionY = p[1];
-                mLastMotionXRemainder = 0;
-                mTotalMotionX = 0;
-                mActivePointerId = ev.getPointerId(0);
-
-                // Determine if the down event is within the threshold to be an edge swipe
-                int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
-                int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
-                if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
-                    mDownEventOnEdge = true;
-                }
-
-                /*
-                 * If being flinged and user touches the screen, initiate drag;
-                 * otherwise don't.  mScroller.isFinished should be false when
-                 * being flinged.
-                 */
-                final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
-                final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
-                if (finishedScrolling) {
-                    mTouchState = TOUCH_STATE_REST;
-                    mScroller.abortAnimation();
-                } else {
-                    if (isTouchPointInViewportWithBuffer((int) mDownMotionX, (int) mDownMotionY)) {
-                        mTouchState = TOUCH_STATE_SCROLLING;
-                    } else {
-                        mTouchState = TOUCH_STATE_REST;
-                    }
-                }
-
-                // check if this can be the beginning of a tap on the side of the pages
-                // to scroll the current page
-                if (!DISABLE_TOUCH_SIDE_PAGES) {
-                    if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
-                        if (getChildCount() > 0) {
-                            if (hitsPreviousPage(x, y)) {
-                                mTouchState = TOUCH_STATE_PREV_PAGE;
-                            } else if (hitsNextPage(x, y)) {
-                                mTouchState = TOUCH_STATE_NEXT_PAGE;
-                            }
-                        }
-                    }
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                resetTouchState();
-                // Just intercept the touch event on up if we tap outside the strict viewport
-                if (!isTouchPointInCurrentPage((int) mLastMotionX, (int) mLastMotionY)) {
-                    return true;
-                }
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-                onSecondaryPointerUp(ev);
-                releaseVelocityTracker();
-                break;
-        }
-
-        /*
-         * The only time we want to intercept motion events is if we are in the
-         * drag mode.
-         */
-        return mTouchState != TOUCH_STATE_REST;
-    }
-
-    protected void determineScrollingStart(MotionEvent ev) {
-        determineScrollingStart(ev, 1.0f);
-    }
-
-    /*
-     * Determines if we should change the touch state to start scrolling after the
-     * user moves their touch point too far.
-     */
-    protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
-        // Disallow scrolling if we don't have a valid pointer index
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        if (pointerIndex == -1) return;
-
-        // Disallow scrolling if we started the gesture from outside the viewport
-        final float x = ev.getX(pointerIndex);
-        final float y = ev.getY(pointerIndex);
-        if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
-
-        // If we're only allowing edge swipes, we break out early if the down event wasn't
-        // at the edge.
-        if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return;
-
-        final int xDiff = (int) Math.abs(x - mLastMotionX);
-        final int yDiff = (int) Math.abs(y - mLastMotionY);
-
-        final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
-        boolean xPaged = xDiff > mPagingTouchSlop;
-        boolean xMoved = xDiff > touchSlop;
-        boolean yMoved = yDiff > touchSlop;
-
-        if (xMoved || xPaged || yMoved) {
-            if (mUsePagingTouchSlop ? xPaged : xMoved) {
-                // Scroll if the user moved far enough along the X axis
-                mTouchState = TOUCH_STATE_SCROLLING;
-                mTotalMotionX += Math.abs(mLastMotionX - x);
-                mLastMotionX = x;
-                mLastMotionXRemainder = 0;
-                mTouchX = getViewportOffsetX() + getScrollX();
-                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-                pageBeginMoving();
-            }
-        }
-    }
-
-    protected float getMaxScrollProgress() {
-        return 1.0f;
-    }
-
-    protected float getBoundedScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getViewportWidth() / 2;
-
-        screenCenter = Math.min(mScrollX + halfScreenSize, screenCenter);
-        screenCenter = Math.max(halfScreenSize,  screenCenter);
-
-        return getScrollProgress(screenCenter, v, page);
-    }
-
-    protected float getScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getViewportWidth() / 2;
-
-        int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing;
-        int delta = screenCenter - (getChildOffset(page) -
-                getRelativeChildOffset(page) + halfScreenSize);
-
-        float scrollProgress = delta / (totalDistance * 1.0f);
-        scrollProgress = Math.min(scrollProgress, getMaxScrollProgress());
-        scrollProgress = Math.max(scrollProgress, - getMaxScrollProgress());
-        return scrollProgress;
-    }
-
-    // This curve determines how the effect of scrolling over the limits of the page dimishes
-    // as the user pulls further and further from the bounds
-    private float overScrollInfluenceCurve(float f) {
-        f -= 1.0f;
-        return f * f * f + 1.0f;
-    }
-
-    protected void acceleratedOverScroll(float amount) {
-        int screenSize = getViewportWidth();
-
-        // We want to reach the max over scroll effect when the user has
-        // over scrolled half the size of the screen
-        float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
-
-        if (f == 0) return;
-
-        // Clamp this factor, f, to -1 < f < 1
-        if (Math.abs(f) >= 1) {
-            f /= Math.abs(f);
-        }
-
-        int overScrollAmount = (int) Math.round(f * screenSize);
-        if (amount < 0) {
-            mOverScrollX = overScrollAmount;
-            super.scrollTo(0, getScrollY());
-        } else {
-            mOverScrollX = mMaxScrollX + overScrollAmount;
-            super.scrollTo(mMaxScrollX, getScrollY());
-        }
-        invalidate();
-    }
-
-    protected void dampedOverScroll(float amount) {
-        int screenSize = getViewportWidth();
-
-        float f = (amount / screenSize);
-
-        if (f == 0) return;
-        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-
-        // Clamp this factor, f, to -1 < f < 1
-        if (Math.abs(f) >= 1) {
-            f /= Math.abs(f);
-        }
-
-        int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
-        if (amount < 0) {
-            mOverScrollX = overScrollAmount;
-            super.scrollTo(0, getScrollY());
-        } else {
-            mOverScrollX = mMaxScrollX + overScrollAmount;
-            super.scrollTo(mMaxScrollX, getScrollY());
-        }
-        invalidate();
-    }
-
-    protected void overScroll(float amount) {
-        dampedOverScroll(amount);
-    }
-
-    protected float maxOverScroll() {
-        // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
-        // exceed). Used to find out how much extra wallpaper we need for the over scroll effect
-        float f = 1.0f;
-        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-        return OVERSCROLL_DAMP_FACTOR * f;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (DISABLE_TOUCH_INTERACTION) {
-            return false;
-        }
-
-        // Skip touch handling if there are no pages to swipe
-        if (getChildCount() <= 0) return super.onTouchEvent(ev);
-
-        acquireVelocityTrackerAndAddMovement(ev);
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN:
-            /*
-             * If being flinged and user touches, stop the fling. isFinished
-             * will be false if being flinged.
-             */
-            if (!mScroller.isFinished()) {
-                mScroller.abortAnimation();
-            }
-
-            // Remember where the motion event started
-            mDownMotionX = mLastMotionX = ev.getX();
-            mDownMotionY = mLastMotionY = ev.getY();
-            mDownScrollX = getScrollX();
-            float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-            mParentDownMotionX = p[0];
-            mParentDownMotionY = p[1];
-            mLastMotionXRemainder = 0;
-            mTotalMotionX = 0;
-            mActivePointerId = ev.getPointerId(0);
-
-            // Determine if the down event is within the threshold to be an edge swipe
-            int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
-            int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
-            if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
-                mDownEventOnEdge = true;
-            }
-
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                pageBeginMoving();
-            }
-            break;
-
-        case MotionEvent.ACTION_MOVE:
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                // Scroll to follow the motion event
-                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-
-                if (pointerIndex == -1) return true;
-
-                final float x = ev.getX(pointerIndex);
-                final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
-
-                mTotalMotionX += Math.abs(deltaX);
-
-                // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
-                // keep the remainder because we are actually testing if we've moved from the last
-                // scrolled position (which is discrete).
-                if (Math.abs(deltaX) >= 1.0f) {
-                    mTouchX += deltaX;
-                    mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-                    if (!mDeferScrollUpdate) {
-                        scrollBy((int) deltaX, 0);
-                        if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
-                    } else {
-                        invalidate();
-                    }
-                    mLastMotionX = x;
-                    mLastMotionXRemainder = deltaX - (int) deltaX;
-                } else {
-                    awakenScrollBars();
-                }
-            } else if (mTouchState == TOUCH_STATE_REORDERING) {
-                // Update the last motion position
-                mLastMotionX = ev.getX();
-                mLastMotionY = ev.getY();
-
-                // Update the parent down so that our zoom animations take this new movement into
-                // account
-                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-                mParentDownMotionX = pt[0];
-                mParentDownMotionY = pt[1];
-                updateDragViewTranslationDuringDrag();
-
-                // Find the closest page to the touch point
-                final int dragViewIndex = indexOfChild(mDragView);
-                int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE *
-                    getViewportWidth());
-                int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0]
-                        + bufferSize);
-                int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0]
-                        - bufferSize);
-
-                // Change the drag view if we are hovering over the drop target
-                boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
-                        (int) mParentDownMotionX, (int) mParentDownMotionY);
-                setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
-
-                if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
-                if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
-                if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
-                if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
-                if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
-                if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
-
-                float parentX = mParentDownMotionX;
-                int pageIndexToSnapTo = -1;
-                if (parentX < leftBufferEdge && dragViewIndex > 0) {
-                    pageIndexToSnapTo = dragViewIndex - 1;
-                } else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) {
-                    pageIndexToSnapTo = dragViewIndex + 1;
-                }
-
-                final int pageUnderPointIndex = pageIndexToSnapTo;
-                if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
-                    mTempVisiblePagesRange[0] = 0;
-                    mTempVisiblePagesRange[1] = getPageCount() - 1;
-                    boundByReorderablePages(true, mTempVisiblePagesRange);
-                    if (mTempVisiblePagesRange[0] <= pageUnderPointIndex &&
-                            pageUnderPointIndex <= mTempVisiblePagesRange[1] &&
-                            pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
-                        mSidePageHoverIndex = pageUnderPointIndex;
-                        mSidePageHoverRunnable = new Runnable() {
-                            @Override
-                            public void run() {
-                                // Update the down scroll position to account for the fact that the
-                                // current page is moved
-                                mDownScrollX = getChildOffset(pageUnderPointIndex)
-                                        - getRelativeChildOffset(pageUnderPointIndex);
-
-                                // Setup the scroll to the correct page before we swap the views
-                                snapToPage(pageUnderPointIndex);
-
-                                // For each of the pages between the paged view and the drag view,
-                                // animate them from the previous position to the new position in
-                                // the layout (as a result of the drag view moving in the layout)
-                                int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
-                                int lowerIndex = (dragViewIndex < pageUnderPointIndex) ?
-                                        dragViewIndex + 1 : pageUnderPointIndex;
-                                int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
-                                        dragViewIndex - 1 : pageUnderPointIndex;
-                                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                                    View v = getChildAt(i);
-                                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                                    // drag view all subsequent views to pageUnderPointIndex will
-                                    // shift down.
-                                    int oldX = getViewportOffsetX() + getChildOffset(i);
-                                    int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);
-
-                                    // Animate the view translation from its old position to its new
-                                    // position
-                                    AnimatorSet anim = (AnimatorSet) v.getTag();
-                                    if (anim != null) {
-                                        anim.cancel();
-                                    }
-
-                                    v.setTranslationX(oldX - newX);
-                                    anim = new AnimatorSet();
-                                    anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
-                                    anim.playTogether(
-                                            ObjectAnimator.ofFloat(v, "translationX", 0f));
-                                    anim.start();
-                                    v.setTag(anim);
-                                }
-
-                                removeView(mDragView);
-                                onRemoveView(mDragView, false);
-                                addView(mDragView, pageUnderPointIndex);
-                                onAddView(mDragView, pageUnderPointIndex);
-                                mSidePageHoverIndex = -1;
-                            }
-                        };
-                        postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
-                    }
-                } else {
-                    removeCallbacks(mSidePageHoverRunnable);
-                    mSidePageHoverIndex = -1;
-                }
-            } else {
-                determineScrollingStart(ev);
-            }
-            break;
-
-        case MotionEvent.ACTION_UP:
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                final int activePointerId = mActivePointerId;
-                final int pointerIndex = ev.findPointerIndex(activePointerId);
-                final float x = ev.getX(pointerIndex);
-                final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
-                final int deltaX = (int) (x - mDownMotionX);
-                final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
-                boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
-                        SIGNIFICANT_MOVE_THRESHOLD;
-
-                mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
-
-                boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
-                        Math.abs(velocityX) > mFlingThresholdVelocity;
-
-                // In the case that the page is moved far to one direction and then is flung
-                // in the opposite direction, we use a threshold to determine whether we should
-                // just return to the starting page, or if we should skip one further.
-                boolean returnToOriginalPage = false;
-                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
-                        Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
-                    returnToOriginalPage = true;
-                }
-
-                int finalPage;
-                // We give flings precedence over large moves, which is why we short-circuit our
-                // test for a large move if a fling has been registered. That is, a large
-                // move to the left and fling to the right will register as a fling to the right.
-                if (((isSignificantMove && deltaX > 0 && !isFling) ||
-                        (isFling && velocityX > 0)) && mCurrentPage > 0) {
-                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
-                    snapToPageWithVelocity(finalPage, velocityX);
-                } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
-                        (isFling && velocityX < 0)) &&
-                        mCurrentPage < getChildCount() - 1) {
-                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
-                    snapToPageWithVelocity(finalPage, velocityX);
-                } else {
-                    snapToDestination();
-                }
-            } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
-                // at this point we have not moved beyond the touch slop
-                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
-                // we can just page
-                int nextPage = Math.max(0, mCurrentPage - 1);
-                if (nextPage != mCurrentPage) {
-                    snapToPage(nextPage);
-                } else {
-                    snapToDestination();
-                }
-            } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
-                // at this point we have not moved beyond the touch slop
-                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
-                // we can just page
-                int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
-                if (nextPage != mCurrentPage) {
-                    snapToPage(nextPage);
-                } else {
-                    snapToDestination();
-                }
-            } else if (mTouchState == TOUCH_STATE_REORDERING) {
-                // Update the last motion position
-                mLastMotionX = ev.getX();
-                mLastMotionY = ev.getY();
-
-                // Update the parent down so that our zoom animations take this new movement into
-                // account
-                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-                mParentDownMotionX = pt[0];
-                mParentDownMotionY = pt[1];
-                updateDragViewTranslationDuringDrag();
-                boolean handledFling = false;
-                if (!DISABLE_FLING_TO_DELETE) {
-                    // Check the velocity and see if we are flinging-to-delete
-                    PointF flingToDeleteVector = isFlingingToDelete();
-                    if (flingToDeleteVector != null) {
-                        onFlingToDelete(flingToDeleteVector);
-                        handledFling = true;
-                    }
-                }
-                if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
-                        (int) mParentDownMotionY)) {
-                    onDropToDelete();
-                }
-            } else {
-                onUnhandledTap(ev);
-            }
-
-            // Remove the callback to wait for the side page hover timeout
-            removeCallbacks(mSidePageHoverRunnable);
-            // End any intermediate reordering states
-            resetTouchState();
-            break;
-
-        case MotionEvent.ACTION_CANCEL:
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                snapToDestination();
-            }
-            resetTouchState();
-            break;
-
-        case MotionEvent.ACTION_POINTER_UP:
-            onSecondaryPointerUp(ev);
-            break;
-        }
-
-        return true;
-    }
-
-    //public abstract void onFlingToDelete(View v);
-    public abstract void onRemoveView(View v, boolean deletePermanently);
-    public abstract void onRemoveViewAnimationCompleted();
-    public abstract void onAddView(View v, int index);
-
-    private void resetTouchState() {
-        releaseVelocityTracker();
-        endReordering();
-        mTouchState = TOUCH_STATE_REST;
-        mActivePointerId = INVALID_POINTER;
-        mDownEventOnEdge = false;
-    }
-
-    protected void onUnhandledTap(MotionEvent ev) {}
-
-    @Override
-    public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_SCROLL: {
-                    // Handle mouse (or ext. device) by shifting the page depending on the scroll
-                    final float vscroll;
-                    final float hscroll;
-                    if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
-                        vscroll = 0;
-                        hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-                    } else {
-                        vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-                        hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
-                    }
-                    if (hscroll != 0 || vscroll != 0) {
-                        if (hscroll > 0 || vscroll > 0) {
-                            scrollRight();
-                        } else {
-                            scrollLeft();
-                        }
-                        return true;
-                    }
-                }
-            }
-        }
-        return super.onGenericMotionEvent(event);
-    }
-
-    private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-    }
-
-    private void releaseVelocityTracker() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-    }
-
-    private void onSecondaryPointerUp(MotionEvent ev) {
-        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
-                MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-        final int pointerId = ev.getPointerId(pointerIndex);
-        if (pointerId == mActivePointerId) {
-            // This was our active pointer going up. Choose a new
-            // active pointer and adjust accordingly.
-            // TODO: Make this decision more intelligent.
-            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-            mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
-            mLastMotionY = ev.getY(newPointerIndex);
-            mLastMotionXRemainder = 0;
-            mActivePointerId = ev.getPointerId(newPointerIndex);
-            if (mVelocityTracker != null) {
-                mVelocityTracker.clear();
-            }
-        }
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        super.requestChildFocus(child, focused);
-        int page = indexToPage(indexOfChild(child));
-        if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
-            snapToPage(page);
-        }
-    }
-
-    protected int getChildIndexForRelativeOffset(int relativeOffset) {
-        final int childCount = getChildCount();
-        int left;
-        int right;
-        for (int i = 0; i < childCount; ++i) {
-            left = getRelativeChildOffset(i);
-            right = (left + getScaledMeasuredWidth(getPageAt(i)));
-            if (left <= relativeOffset && relativeOffset <= right) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    protected int getChildWidth(int index) {
-        // This functions are called enough times that it actually makes a difference in the
-        // profiler -- so just inline the max() here
-        final int measuredWidth = getPageAt(index).getMeasuredWidth();
-        final int minWidth = mMinimumWidth;
-        return (minWidth > measuredWidth) ? minWidth : measuredWidth;
-    }
-
-    int getPageNearestToPoint(float x) {
-        int index = 0;
-        for (int i = 0; i < getChildCount(); ++i) {
-            if (x < getChildAt(i).getRight() - getScrollX()) {
-                return index;
-            } else {
-                index++;
-            }
-        }
-        return Math.min(index, getChildCount() - 1);
-    }
-
-    int getPageNearestToCenterOfScreen() {
-        int minDistanceFromScreenCenter = Integer.MAX_VALUE;
-        int minDistanceFromScreenCenterIndex = -1;
-        int screenCenter = getViewportOffsetX() + getScrollX() + (getViewportWidth() / 2);
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; ++i) {
-            View layout = (View) getPageAt(i);
-            int childWidth = getScaledMeasuredWidth(layout);
-            int halfChildWidth = (childWidth / 2);
-            int childCenter = getViewportOffsetX() + getChildOffset(i) + halfChildWidth;
-            int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
-            if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
-                minDistanceFromScreenCenter = distanceFromScreenCenter;
-                minDistanceFromScreenCenterIndex = i;
-            }
-        }
-        return minDistanceFromScreenCenterIndex;
-    }
-
-    protected void snapToDestination() {
-        snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
-    }
-
-    private static class ScrollInterpolator implements Interpolator {
-        public ScrollInterpolator() {
-        }
-
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t*t*t*t*t + 1;
-        }
-    }
-
-    // We want the duration of the page snap animation to be influenced by the distance that
-    // the screen has to travel, however, we don't want this duration to be effected in a
-    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
-    // of travel has on the overall snap duration.
-    float distanceInfluenceForSnapDuration(float f) {
-        f -= 0.5f; // center the values about 0.
-        f *= 0.3f * Math.PI / 2.0f;
-        return (float) Math.sin(f);
-    }
-
-    protected void snapToPageWithVelocity(int whichPage, int velocity) {
-        whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
-        int halfScreenSize = getViewportWidth() / 2;
-
-        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
-        if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
-                + getViewportWidth() + ", " + getChildWidth(whichPage));
-        final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
-        int delta = newX - mUnboundedScrollX;
-        int duration = 0;
-
-        if (Math.abs(velocity) < mMinFlingVelocity) {
-            // If the velocity is low enough, then treat this more as an automatic page advance
-            // as opposed to an apparent physical response to flinging
-            snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
-            return;
-        }
-
-        // Here we compute a "distance" that will be used in the computation of the overall
-        // snap duration. This is a function of the actual distance that needs to be traveled;
-        // we keep this value close to half screen size in order to reduce the variance in snap
-        // duration as a function of the distance the page needs to travel.
-        float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / (2 * halfScreenSize));
-        float distance = halfScreenSize + halfScreenSize *
-                distanceInfluenceForSnapDuration(distanceRatio);
-
-        velocity = Math.abs(velocity);
-        velocity = Math.max(mMinSnapVelocity, velocity);
-
-        // we want the page's snap velocity to approximately match the velocity at which the
-        // user flings, so we scale the duration by a value near to the derivative of the scroll
-        // interpolator at zero, ie. 5. We use 4 to make it a little slower.
-        duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-
-        snapToPage(whichPage, delta, duration);
-    }
-
-    protected void snapToPage(int whichPage) {
-        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
-    }
-    protected void snapToPageImmediately(int whichPage) {
-        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true);
-    }
-
-    protected void snapToPage(int whichPage, int duration) {
-        snapToPage(whichPage, duration, false);
-    }
-    protected void snapToPage(int whichPage, int duration, boolean immediate) {
-        whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
-
-        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
-        if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getViewportWidth() + ", "
-                + getChildWidth(whichPage));
-        int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
-        final int sX = mUnboundedScrollX;
-        final int delta = newX - sX;
-        snapToPage(whichPage, delta, duration, immediate);
-    }
-
-    protected void snapToPage(int whichPage, int delta, int duration) {
-        snapToPage(whichPage, delta, duration, false);
-    }
-    protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) {
-        mNextPage = whichPage;
-        notifyPageSwitching(whichPage);
-        View focusedChild = getFocusedChild();
-        if (focusedChild != null && whichPage != mCurrentPage &&
-                focusedChild == getPageAt(mCurrentPage)) {
-            focusedChild.clearFocus();
-        }
-
-        pageBeginMoving();
-        awakenScrollBars(duration);
-        if (immediate) {
-            duration = 0;
-        } else if (duration == 0) {
-            duration = Math.abs(delta);
-        }
-
-        if (!mScroller.isFinished()) mScroller.abortAnimation();
-        mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
-
-        notifyPageSwitched();
-
-        // Trigger a compute() to finish switching pages if necessary
-        if (immediate) {
-            computeScroll();
-        }
-
-        mForceScreenScrolled = true;
-        invalidate();
-    }
-
-    public void scrollLeft() {
-        if (mScroller.isFinished()) {
-            if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
-        } else {
-            if (mNextPage > 0) snapToPage(mNextPage - 1);
-        }
-    }
-
-    public void scrollRight() {
-        if (mScroller.isFinished()) {
-            if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1);
-        } else {
-            if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1);
-        }
-    }
-
-    public int getPageForView(View v) {
-        int result = -1;
-        if (v != null) {
-            ViewParent vp = v.getParent();
-            int count = getChildCount();
-            for (int i = 0; i < count; i++) {
-                if (vp == getPageAt(i)) {
-                    return i;
-                }
-            }
-        }
-        return result;
-    }
-
-    public static class SavedState extends BaseSavedState {
-        int currentPage = -1;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            currentPage = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(currentPage);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR =
-                new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    protected View getScrollingIndicator() {
-        return null;
-    }
-
-    protected boolean isScrollingIndicatorEnabled() {
-        return false;
-    }
-
-    Runnable hideScrollingIndicatorRunnable = new Runnable() {
-        @Override
-        public void run() {
-            hideScrollingIndicator(false);
-        }
-    };
-
-    protected void flashScrollingIndicator(boolean animated) {
-        removeCallbacks(hideScrollingIndicatorRunnable);
-        showScrollingIndicator(!animated);
-        postDelayed(hideScrollingIndicatorRunnable, sScrollIndicatorFlashDuration);
-    }
-
-    protected void showScrollingIndicator(boolean immediately) {
-        mShouldShowScrollIndicator = true;
-        mShouldShowScrollIndicatorImmediately = true;
-        if (getChildCount() <= 1) return;
-        if (!isScrollingIndicatorEnabled()) return;
-
-        mShouldShowScrollIndicator = false;
-        getScrollingIndicator();
-        if (mScrollIndicator != null) {
-            // Fade the indicator in
-            updateScrollingIndicatorPosition();
-            mScrollIndicator.setVisibility(View.VISIBLE);
-            cancelScrollingIndicatorAnimations();
-            if (immediately) {
-                mScrollIndicator.setAlpha(1f);
-            } else {
-                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f);
-                mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration);
-                mScrollIndicatorAnimator.start();
-            }
-        }
-    }
-
-    protected void cancelScrollingIndicatorAnimations() {
-        if (mScrollIndicatorAnimator != null) {
-            mScrollIndicatorAnimator.cancel();
-        }
-    }
-
-    protected void hideScrollingIndicator(boolean immediately) {
-        if (getChildCount() <= 1) return;
-        if (!isScrollingIndicatorEnabled()) return;
-
-        getScrollingIndicator();
-        if (mScrollIndicator != null) {
-            // Fade the indicator out
-            updateScrollingIndicatorPosition();
-            cancelScrollingIndicatorAnimations();
-            if (immediately) {
-                mScrollIndicator.setVisibility(View.INVISIBLE);
-                mScrollIndicator.setAlpha(0f);
-            } else {
-                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f);
-                mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration);
-                mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() {
-                    private boolean cancelled = false;
-                    @Override
-                    public void onAnimationCancel(android.animation.Animator animation) {
-                        cancelled = true;
-                    }
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        if (!cancelled) {
-                            mScrollIndicator.setVisibility(View.INVISIBLE);
-                        }
-                    }
-                });
-                mScrollIndicatorAnimator.start();
-            }
-        }
-    }
-
-    /**
-     * To be overridden by subclasses to determine whether the scroll indicator should stretch to
-     * fill its space on the track or not.
-     */
-    protected boolean hasElasticScrollIndicator() {
-        return true;
-    }
-
-    private void updateScrollingIndicator() {
-        if (getChildCount() <= 1) return;
-        if (!isScrollingIndicatorEnabled()) return;
-
-        getScrollingIndicator();
-        if (mScrollIndicator != null) {
-            updateScrollingIndicatorPosition();
-        }
-        if (mShouldShowScrollIndicator) {
-            showScrollingIndicator(mShouldShowScrollIndicatorImmediately);
-        }
-    }
-
-    private void updateScrollingIndicatorPosition() {
-        if (!isScrollingIndicatorEnabled()) return;
-        if (mScrollIndicator == null) return;
-        int numPages = getChildCount();
-        int pageWidth = getViewportWidth();
-        int lastChildIndex = Math.max(0, getChildCount() - 1);
-        int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex);
-        int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight;
-        int indicatorWidth = mScrollIndicator.getMeasuredWidth() -
-                mScrollIndicator.getPaddingLeft() - mScrollIndicator.getPaddingRight();
-
-        float offset = Math.max(0f, Math.min(1f, (float) getScrollX() / maxScrollX));
-        int indicatorSpace = trackWidth / numPages;
-        int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft;
-        if (hasElasticScrollIndicator()) {
-            if (mScrollIndicator.getMeasuredWidth() != indicatorSpace) {
-                mScrollIndicator.getLayoutParams().width = indicatorSpace;
-                mScrollIndicator.requestLayout();
-            }
-        } else {
-            int indicatorCenterOffset = indicatorSpace / 2 - indicatorWidth / 2;
-            indicatorPos += indicatorCenterOffset;
-        }
-        mScrollIndicator.setTranslationX(indicatorPos);
-    }
-
-    // Animate the drag view back to the original position
-    void animateDragViewToOriginalPosition() {
-        if (mDragView != null) {
-            AnimatorSet anim = new AnimatorSet();
-            anim.setDuration(REORDERING_DROP_REPOSITION_DURATION);
-            anim.playTogether(
-                    ObjectAnimator.ofFloat(mDragView, "translationX", 0f),
-                    ObjectAnimator.ofFloat(mDragView, "translationY", 0f));
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    onPostReorderingAnimationCompleted();
-                }
-            });
-            anim.start();
-        }
-    }
-
-    // "Zooms out" the PagedView to reveal more side pages
-    protected boolean zoomOut() {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-
-        if (!(getScaleX() < 1f || getScaleY() < 1f)) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
-                    ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
-            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    // Show the delete drop target
-                    if (mDeleteDropTarget != null) {
-                        mDeleteDropTarget.setVisibility(View.VISIBLE);
-                        mDeleteDropTarget.animate().alpha(1f)
-                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
-                            .setListener(new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationStart(Animator animation) {
-                                    mDeleteDropTarget.setAlpha(0f);
-                                }
-                            });
-                    }
-                }
-            });
-            mZoomInOutAnim.start();
-            return true;
-        }
-        return false;
-    }
-
-    protected void onStartReordering() {
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            announceForAccessibility(mContext.getString(
-                    R.string.keyguard_accessibility_widget_reorder_start));
-        }
-
-        // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
-        mTouchState = TOUCH_STATE_REORDERING;
-        mIsReordering = true;
-
-        // Mark all the non-widget pages as invisible
-        getVisiblePages(mTempVisiblePagesRange);
-        boundByReorderablePages(true, mTempVisiblePagesRange);
-        for (int i = 0; i < getPageCount(); ++i) {
-            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
-                getPageAt(i).setAlpha(0f);
-            }
-        }
-
-        // We must invalidate to trigger a redraw to update the layers such that the drag view
-        // is always drawn on top
-        invalidate();
-    }
-
-    private void onPostReorderingAnimationCompleted() {
-        // Trigger the callback when reordering has settled
-        --mPostReorderingPreZoomInRemainingAnimationCount;
-        if (mPostReorderingPreZoomInRunnable != null &&
-                mPostReorderingPreZoomInRemainingAnimationCount == 0) {
-            mPostReorderingPreZoomInRunnable.run();
-            mPostReorderingPreZoomInRunnable = null;
-        }
-    }
-
-    protected void onEndReordering() {
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            announceForAccessibility(mContext.getString(
-                    R.string.keyguard_accessibility_widget_reorder_end));
-        }
-        mIsReordering = false;
-
-        // Mark all the non-widget pages as visible again
-        getVisiblePages(mTempVisiblePagesRange);
-        boundByReorderablePages(true, mTempVisiblePagesRange);
-        for (int i = 0; i < getPageCount(); ++i) {
-            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
-                getPageAt(i).setAlpha(1f);
-            }
-        }
-    }
-
-    public boolean startReordering() {
-        int dragViewIndex = getPageNearestToCenterOfScreen();
-        mTempVisiblePagesRange[0] = 0;
-        mTempVisiblePagesRange[1] = getPageCount() - 1;
-        boundByReorderablePages(true, mTempVisiblePagesRange);
-        mReorderingStarted = true;
-
-        // Check if we are within the reordering range
-        if (mTempVisiblePagesRange[0] <= dragViewIndex &&
-                dragViewIndex <= mTempVisiblePagesRange[1]) {
-            if (zoomOut()) {
-                // Find the drag view under the pointer
-                mDragView = getChildAt(dragViewIndex);
-
-                onStartReordering();
-            }
-            return true;
-        }
-        return false;
-    }
-
-    boolean isReordering(boolean testTouchState) {
-        boolean state = mIsReordering;
-        if (testTouchState) {
-            state &= (mTouchState == TOUCH_STATE_REORDERING);
-        }
-        return state;
-    }
-    void endReordering() {
-        // For simplicity, we call endReordering sometimes even if reordering was never started.
-        // In that case, we don't want to do anything.
-        if (!mReorderingStarted) return;
-        mReorderingStarted = false;
-
-        // If we haven't flung-to-delete the current child, then we just animate the drag view
-        // back into position
-        final Runnable onCompleteRunnable = new Runnable() {
-            @Override
-            public void run() {
-                onEndReordering();
-            }
-        };
-        if (!mDeferringForDelete) {
-            mPostReorderingPreZoomInRunnable = new Runnable() {
-                public void run() {
-                    zoomIn(onCompleteRunnable);
-                };
-            };
-
-            mPostReorderingPreZoomInRemainingAnimationCount =
-                    NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
-            // Snap to the current page
-            snapToPage(indexOfChild(mDragView), 0);
-            // Animate the drag view back to the front position
-            animateDragViewToOriginalPosition();
-        } else {
-            // Handled in post-delete-animation-callbacks
-        }
-    }
-
-    // "Zooms in" the PagedView to highlight the current page
-    protected boolean zoomIn(final Runnable onCompleteRunnable) {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-        if (getScaleX() < 1f || getScaleY() < 1f) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(this, "scaleX", 1f),
-                    ObjectAnimator.ofFloat(this, "scaleY", 1f));
-            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    // Hide the delete drop target
-                    if (mDeleteDropTarget != null) {
-                        mDeleteDropTarget.animate().alpha(0f)
-                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
-                            .setListener(new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationEnd(Animator animation) {
-                                    mDeleteDropTarget.setVisibility(View.GONE);
-                                }
-                            });
-                    }
-                }
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mDragView = null;
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mDragView = null;
-                    if (onCompleteRunnable != null) {
-                        onCompleteRunnable.run();
-                    }
-                }
-            });
-            mZoomInOutAnim.start();
-            return true;
-        } else {
-            if (onCompleteRunnable != null) {
-                onCompleteRunnable.run();
-            }
-        }
-        return false;
-    }
-
-    /*
-     * Flinging to delete - IN PROGRESS
-     */
-    private PointF isFlingingToDelete() {
-        ViewConfiguration config = ViewConfiguration.get(getContext());
-        mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
-
-        if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
-            // Do a quick dot product test to ensure that we are flinging upwards
-            PointF vel = new PointF(mVelocityTracker.getXVelocity(),
-                    mVelocityTracker.getYVelocity());
-            PointF upVec = new PointF(0f, -1f);
-            float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
-                    (vel.length() * upVec.length()));
-            if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) {
-                return vel;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Creates an animation from the current drag view along its current velocity vector.
-     * For this animation, the alpha runs for a fixed duration and we update the position
-     * progressively.
-     */
-    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
-        private View mDragView;
-        private PointF mVelocity;
-        private Rect mFrom;
-        private long mPrevTime;
-        private float mFriction;
-
-        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
-        public FlingAlongVectorAnimatorUpdateListener(View dragView, PointF vel, Rect from,
-                long startTime, float friction) {
-            mDragView = dragView;
-            mVelocity = vel;
-            mFrom = from;
-            mPrevTime = startTime;
-            mFriction = 1f - (mDragView.getResources().getDisplayMetrics().density * friction);
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            float t = ((Float) animation.getAnimatedValue()).floatValue();
-            long curTime = AnimationUtils.currentAnimationTimeMillis();
-
-            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
-            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
-            mDragView.setTranslationX(mFrom.left);
-            mDragView.setTranslationY(mFrom.top);
-            mDragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
-            mVelocity.x *= mFriction;
-            mVelocity.y *= mFriction;
-            mPrevTime = curTime;
-        }
-    };
-
-    private Runnable createPostDeleteAnimationRunnable(final View dragView) {
-        return new Runnable() {
-            @Override
-            public void run() {
-                int dragViewIndex = indexOfChild(dragView);
-
-                // For each of the pages around the drag view, animate them from the previous
-                // position to the new position in the layout (as a result of the drag view moving
-                // in the layout)
-                // NOTE: We can make an assumption here because we have side-bound pages that we
-                //       will always have pages to animate in from the left
-                getVisiblePages(mTempVisiblePagesRange);
-                boundByReorderablePages(true, mTempVisiblePagesRange);
-                boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
-                boolean slideFromLeft = (isLastWidgetPage ||
-                        dragViewIndex > mTempVisiblePagesRange[0]);
-
-                // Setup the scroll to the correct page before we swap the views
-                if (slideFromLeft) {
-                    snapToPageImmediately(dragViewIndex - 1);
-                }
-
-                int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
-                int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
-                int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
-                int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
-                ArrayList<Animator> animations = new ArrayList<Animator>();
-                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                    View v = getChildAt(i);
-                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                    // drag view all subsequent views to pageUnderPointIndex will
-                    // shift down.
-                    int oldX = 0;
-                    int newX = 0;
-                    if (slideFromLeft) {
-                        if (i == 0) {
-                            // Simulate the page being offscreen with the page spacing
-                            oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
-                                    - mPageSpacing;
-                        } else {
-                            oldX = getViewportOffsetX() + getChildOffset(i - 1);
-                        }
-                        newX = getViewportOffsetX() + getChildOffset(i);
-                    } else {
-                        oldX = getChildOffset(i) - getChildOffset(i - 1);
-                        newX = 0;
-                    }
-
-                    // Animate the view translation from its old position to its new
-                    // position
-                    AnimatorSet anim = (AnimatorSet) v.getTag();
-                    if (anim != null) {
-                        anim.cancel();
-                    }
-
-                    // Note: Hacky, but we want to skip any optimizations to not draw completely
-                    // hidden views
-                    v.setAlpha(Math.max(v.getAlpha(), 0.01f));
-                    v.setTranslationX(oldX - newX);
-                    anim = new AnimatorSet();
-                    anim.playTogether(
-                            ObjectAnimator.ofFloat(v, "translationX", 0f),
-                            ObjectAnimator.ofFloat(v, "alpha", 1f));
-                    animations.add(anim);
-                    v.setTag(anim);
-                }
-
-                AnimatorSet slideAnimations = new AnimatorSet();
-                slideAnimations.playTogether(animations);
-                slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
-                slideAnimations.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        final Runnable onCompleteRunnable = new Runnable() {
-                            @Override
-                            public void run() {
-                                mDeferringForDelete = false;
-                                onEndReordering();
-                                onRemoveViewAnimationCompleted();
-                            }
-                        };
-                        zoomIn(onCompleteRunnable);
-                    }
-                });
-                slideAnimations.start();
-
-                removeView(dragView);
-                onRemoveView(dragView, true);
-            }
-        };
-    }
-
-    public void onFlingToDelete(PointF vel) {
-        final long startTime = AnimationUtils.currentAnimationTimeMillis();
-
-        // NOTE: Because it takes time for the first frame of animation to actually be
-        // called and we expect the animation to be a continuation of the fling, we have
-        // to account for the time that has elapsed since the fling finished.  And since
-        // we don't have a startDelay, we will always get call to update when we call
-        // start() (which we want to ignore).
-        final TimeInterpolator tInterpolator = new TimeInterpolator() {
-            private int mCount = -1;
-            private long mStartTime;
-            private float mOffset;
-            /* Anonymous inner class ctor */ {
-                mStartTime = startTime;
-            }
-
-            @Override
-            public float getInterpolation(float t) {
-                if (mCount < 0) {
-                    mCount++;
-                } else if (mCount == 0) {
-                    mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
-                            mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION);
-                    mCount++;
-                }
-                return Math.min(1f, mOffset + t);
-            }
-        };
-
-        final Rect from = new Rect();
-        final View dragView = mDragView;
-        from.left = (int) dragView.getTranslationX();
-        from.top = (int) dragView.getTranslationY();
-        AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
-                from, startTime, FLING_TO_DELETE_FRICTION);
-
-        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
-
-        // Create and start the animation
-        ValueAnimator mDropAnim = new ValueAnimator();
-        mDropAnim.setInterpolator(tInterpolator);
-        mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION);
-        mDropAnim.setFloatValues(0f, 1f);
-        mDropAnim.addUpdateListener(updateCb);
-        mDropAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                onAnimationEndRunnable.run();
-            }
-        });
-        mDropAnim.start();
-        mDeferringForDelete = true;
-    }
-
-    /* Drag to delete */
-    private boolean isHoveringOverDeleteDropTarget(int x, int y) {
-        if (mDeleteDropTarget != null) {
-            mAltTmpRect.set(0, 0, 0, 0);
-            View parent = (View) mDeleteDropTarget.getParent();
-            if (parent != null) {
-                parent.getGlobalVisibleRect(mAltTmpRect);
-            }
-            mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
-            mTmpRect.offset(-mAltTmpRect.left, -mAltTmpRect.top);
-            return mTmpRect.contains(x, y);
-        }
-        return false;
-    }
-
-    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {}
-
-    private void onDropToDelete() {
-        final View dragView = mDragView;
-
-        final float toScale = 0f;
-        final float toAlpha = 0f;
-
-        // Create and start the complex animation
-        ArrayList<Animator> animations = new ArrayList<Animator>();
-        AnimatorSet motionAnim = new AnimatorSet();
-        motionAnim.setInterpolator(new DecelerateInterpolator(2));
-        motionAnim.playTogether(
-                ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
-                ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
-        animations.add(motionAnim);
-
-        AnimatorSet alphaAnim = new AnimatorSet();
-        alphaAnim.setInterpolator(new LinearInterpolator());
-        alphaAnim.playTogether(
-                ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
-        animations.add(alphaAnim);
-
-        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
-
-        AnimatorSet anim = new AnimatorSet();
-        anim.playTogether(animations);
-        anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
-        anim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                onAnimationEndRunnable.run();
-            }
-        });
-        anim.start();
-
-        mDeferringForDelete = true;
-    }
-
-    /* Accessibility */
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setScrollable(getPageCount() > 1);
-        if (getCurrentPage() < getPageCount() - 1) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-        }
-        if (getCurrentPage() > 0) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
-        }
-    }
-
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
-        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
-            event.setFromIndex(mCurrentPage);
-            event.setToIndex(mCurrentPage);
-            event.setItemCount(getChildCount());
-        }
-    }
-
-    @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
-            return true;
-        }
-        switch (action) {
-            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                if (getCurrentPage() < getPageCount() - 1) {
-                    scrollRight();
-                    return true;
-                }
-            } break;
-            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                if (getCurrentPage() > 0) {
-                    scrollLeft();
-                    return true;
-                }
-            } break;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onHoverEvent(android.view.MotionEvent event) {
-        return true;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
deleted file mode 100644
index 7760279..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-public interface SecurityMessageDisplay {
-    public void setMessage(CharSequence msg, boolean important);
-
-    public void setMessage(int resId, boolean important);
-
-    public void setMessage(int resId, boolean important, Object... formatArgs);
-
-    public void setTimeout(int timeout_ms);
-
-    public void showBouncer(int animationDuration);
-
-    public void hideBouncer(int animationDuration);
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
deleted file mode 100644
index 073225f..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ /dev/null
@@ -1,1244 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl.keyguard;
-
-import com.android.internal.R;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.FloatProperty;
-import android.util.Log;
-import android.util.Property;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
-
-/**
- * This layout handles interaction with the sliding security challenge views
- * that overlay/resize other keyguard contents.
- */
-public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout {
-    private static final String TAG = "SlidingChallengeLayout";
-    private static final boolean DEBUG = false;
-
-    // The drag handle is measured in dp above & below the top edge of the
-    // challenge view; these parameters change based on whether the challenge 
-    // is open or closed.
-    private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp
-    private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
-    private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
-    private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
-
-    private static final int HANDLE_ANIMATE_DURATION = 250; // ms
-
-    // Drawn to show the drag handle in closed state; crossfades to the challenge view
-    // when challenge is fully visible
-    private boolean mEdgeCaptured;
-
-    private DisplayMetrics mDisplayMetrics;
-
-    // Initialized during measurement from child layoutparams
-    private View mExpandChallengeView;
-    private KeyguardSecurityContainer mChallengeView;
-    private View mScrimView;
-    private View mWidgetsView;
-
-    // Range: 0 (fully hidden) to 1 (fully visible)
-    private float mChallengeOffset = 1.f;
-    private boolean mChallengeShowing = true;
-    private boolean mChallengeShowingTargetState = true;
-    private boolean mWasChallengeShowing = true;
-    private boolean mIsBouncing = false;
-
-    private final Scroller mScroller;
-    private ObjectAnimator mFader;
-    private int mScrollState;
-    private OnChallengeScrolledListener mScrollListener;
-    private OnBouncerStateChangedListener mBouncerListener;
-
-    public static final int SCROLL_STATE_IDLE = 0;
-    public static final int SCROLL_STATE_DRAGGING = 1;
-    public static final int SCROLL_STATE_SETTLING = 2;
-    public static final int SCROLL_STATE_FADING = 3;
-
-    private static final int CHALLENGE_FADE_OUT_DURATION = 100;
-    private static final int CHALLENGE_FADE_IN_DURATION = 160;
-
-    private static final int MAX_SETTLE_DURATION = 600; // ms
-
-    // ID of the pointer in charge of a current drag
-    private int mActivePointerId = INVALID_POINTER;
-    private static final int INVALID_POINTER = -1;
-
-    // True if the user is currently dragging the slider
-    private boolean mDragging;
-    // True if the user may not drag until a new gesture begins
-    private boolean mBlockDrag;
-
-    private VelocityTracker mVelocityTracker;
-    private int mMinVelocity;
-    private int mMaxVelocity;
-    private float mGestureStartX, mGestureStartY; // where did you first touch the screen?
-    private int mGestureStartChallengeBottom; // where was the challenge at that time?
-
-    private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view
-    private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line
-    private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view
-    private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line
-
-    private int mDragHandleEdgeSlop;
-    private int mChallengeBottomBound; // Number of pixels from the top of the challenge view
-                                       // that should remain on-screen
-
-    private int mTouchSlop;
-    private int mTouchSlopSquare;
-
-    float mHandleAlpha;
-    float mFrameAlpha;
-    float mFrameAnimationTarget = Float.MIN_VALUE;
-    private ObjectAnimator mHandleAnimation;
-    private ObjectAnimator mFrameAnimation;
-
-    private boolean mHasGlowpad;
-
-    // We have an internal and external version, and we and them together.
-    private boolean mChallengeInteractiveExternal = true;
-    private boolean mChallengeInteractiveInternal = true;
-
-    static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
-            new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
-        @Override
-        public void setValue(SlidingChallengeLayout view, float value) {
-            view.mHandleAlpha = value;
-            view.invalidate();
-        }
-
-        @Override
-        public Float get(SlidingChallengeLayout view) {
-            return view.mHandleAlpha;
-        }
-    };
-
-    // True if at least one layout pass has happened since the view was attached.
-    private boolean mHasLayout;
-
-    private static final Interpolator sMotionInterpolator = new Interpolator() {
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t * t * t * t * t + 1.0f;
-        }
-    };
-
-    private static final Interpolator sHandleFadeInterpolator = new Interpolator() {
-        public float getInterpolation(float t) {
-            return t * t;
-        }
-    };
-
-    private final Runnable mEndScrollRunnable = new Runnable () {
-        public void run() {
-            completeChallengeScroll();
-        }
-    };
-
-    private final OnClickListener mScrimClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            hideBouncer();
-        }
-    };
-
-    private final OnClickListener mExpandChallengeClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (!isChallengeShowing()) {
-                showChallenge(true);
-            }
-        }
-    };
-
-    /**
-     * Listener interface that reports changes in scroll state of the challenge area.
-     */
-    public interface OnChallengeScrolledListener {
-        /**
-         * The scroll state itself changed.
-         *
-         * <p>scrollState will be one of the following:</p>
-         *
-         * <ul>
-         * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li>
-         * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging
-         * the challenge area.</li>
-         * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating
-         * into place.</li>
-         * </ul>
-         *
-         * <p>Do not perform expensive operations (e.g. layout)
-         * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p>
-         *
-         * @param scrollState The new scroll state of the challenge area.
-         */
-        public void onScrollStateChanged(int scrollState);
-
-        /**
-         * The precise position of the challenge area has changed.
-         *
-         * <p>NOTE: It is NOT safe to modify layout or call any View methods that may
-         * result in a requestLayout anywhere in your view hierarchy as a result of this call.
-         * It may be called during drawing.</p>
-         *
-         * @param scrollPosition New relative position of the challenge area.
-         *                       1.f = fully visible/ready to be interacted with.
-         *                       0.f = fully invisible/inaccessible to the user.
-         * @param challengeTop Position of the top edge of the challenge view in px in the
-         *                     SlidingChallengeLayout's coordinate system.
-         */
-        public void onScrollPositionChanged(float scrollPosition, int challengeTop);
-    }
-
-    public SlidingChallengeLayout(Context context) {
-        this(context, null);
-    }
-
-    public SlidingChallengeLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mScroller = new Scroller(context, sMotionInterpolator);
-
-        final ViewConfiguration vc = ViewConfiguration.get(context);
-        mMinVelocity = vc.getScaledMinimumFlingVelocity();
-        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
-
-        final Resources res = getResources();
-        mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
-
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mTouchSlopSquare = mTouchSlop * mTouchSlop;
-
-        mDisplayMetrics = res.getDisplayMetrics();
-        final float density = mDisplayMetrics.density;
-
-        // top half of the lock icon, plus another 25% to be sure
-        mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
-        mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f);
-        mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f);
-        mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
-
-        // how much space to account for in the handle when closed
-        mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
-
-        setWillNotDraw(false);
-        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE);
-    }
-
-    public void setHandleAlpha(float alpha) {
-        if (mExpandChallengeView != null) {
-            mExpandChallengeView.setAlpha(alpha);
-        }
-    }
-
-    public void setChallengeInteractive(boolean interactive) {
-        mChallengeInteractiveExternal = interactive;
-        if (mExpandChallengeView != null) {
-            mExpandChallengeView.setEnabled(interactive);
-        }
-    }
-
-    void animateHandle(boolean visible) {
-        if (mHandleAnimation != null) {
-            mHandleAnimation.cancel();
-            mHandleAnimation = null;
-        }
-        final float targetAlpha = visible ? 1.f : 0.f;
-        if (targetAlpha == mHandleAlpha) {
-            return;
-        }
-        mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha);
-        mHandleAnimation.setInterpolator(sHandleFadeInterpolator);
-        mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION);
-        mHandleAnimation.start();
-    }
-
-    private void sendInitialListenerUpdates() {
-        if (mScrollListener != null) {
-            int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0;
-            mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop);
-            mScrollListener.onScrollStateChanged(mScrollState);
-        }
-    }
-
-    public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) {
-        mScrollListener = listener;
-        if (mHasLayout) {
-            sendInitialListenerUpdates();
-        }
-    }
-
-    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
-        mBouncerListener = listener;
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        mHasLayout = false;
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        removeCallbacks(mEndScrollRunnable);
-        mHasLayout = false;
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        if (mIsBouncing && child != mChallengeView) {
-            // Clear out of the bouncer if the user tries to move focus outside of
-            // the security challenge view.
-            hideBouncer();
-        }
-        super.requestChildFocus(child, focused);
-    }
-
-    // We want the duration of the page snap animation to be influenced by the distance that
-    // the screen has to travel, however, we don't want this duration to be effected in a
-    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
-    // of travel has on the overall snap duration.
-    float distanceInfluenceForSnapDuration(float f) {
-        f -= 0.5f; // center the values about 0.
-        f *= 0.3f * Math.PI / 2.0f;
-        return (float) Math.sin(f);
-    }
-
-    void setScrollState(int state) {
-        if (mScrollState != state) {
-            mScrollState = state;
-
-            animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
-            if (mScrollListener != null) {
-                mScrollListener.onScrollStateChanged(state);
-            }
-        }
-    }
-
-    void completeChallengeScroll() {
-        setChallengeShowing(mChallengeShowingTargetState);
-        mChallengeOffset = mChallengeShowing ? 1.f : 0.f;
-        setScrollState(SCROLL_STATE_IDLE);
-        mChallengeInteractiveInternal = true;
-        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    void setScrimView(View scrim) {
-        if (mScrimView != null) {
-            mScrimView.setOnClickListener(null);
-        }
-        mScrimView = scrim;
-        mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
-        mScrimView.setFocusable(true);
-        mScrimView.setOnClickListener(mScrimClickListener);
-    }
-
-    /**
-     * Animate the bottom edge of the challenge view to the given position.
-     *
-     * @param y desired final position for the bottom edge of the challenge view in px
-     * @param velocity velocity in
-     */
-    void animateChallengeTo(int y, int velocity) {
-        if (mChallengeView == null) {
-            // Nothing to do.
-            return;
-        }
-
-        cancelTransitionsInProgress();
-
-        mChallengeInteractiveInternal = false;
-        mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
-        final int sy = mChallengeView.getBottom();
-        final int dy = y - sy;
-        if (dy == 0) {
-            completeChallengeScroll();
-            return;
-        }
-
-        setScrollState(SCROLL_STATE_SETTLING);
-
-        final int childHeight = mChallengeView.getHeight();
-        final int halfHeight = childHeight / 2;
-        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight);
-        final float distance = halfHeight + halfHeight *
-                distanceInfluenceForSnapDuration(distanceRatio);
-
-        int duration = 0;
-        velocity = Math.abs(velocity);
-        if (velocity > 0) {
-            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-        } else {
-            final float childDelta = (float) Math.abs(dy) / childHeight;
-            duration = (int) ((childDelta + 1) * 100);
-        }
-        duration = Math.min(duration, MAX_SETTLE_DURATION);
-
-        mScroller.startScroll(0, sy, 0, dy, duration);
-        postInvalidateOnAnimation();
-    }
-
-    private void setChallengeShowing(boolean showChallenge) {
-        if (mChallengeShowing == showChallenge) {
-            return;
-        }
-        mChallengeShowing = showChallenge;
-
-        if (mExpandChallengeView == null || mChallengeView == null) {
-            // These might not be here yet if we haven't been through layout.
-            // If we haven't, the first layout pass will set everything up correctly
-            // based on mChallengeShowing as set above.
-            return;
-        }
-
-        if (mChallengeShowing) {
-            mExpandChallengeView.setVisibility(View.INVISIBLE);
-            mChallengeView.setVisibility(View.VISIBLE);
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                mChallengeView.requestAccessibilityFocus();
-                mChallengeView.announceForAccessibility(mContext.getString(
-                        R.string.keyguard_accessibility_unlock_area_expanded));
-            }
-        } else {
-            mExpandChallengeView.setVisibility(View.VISIBLE);
-            mChallengeView.setVisibility(View.INVISIBLE);
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                mExpandChallengeView.requestAccessibilityFocus();
-                mChallengeView.announceForAccessibility(mContext.getString(
-                        R.string.keyguard_accessibility_unlock_area_collapsed));
-            }
-        }
-    }
-
-    /**
-     * @return true if the challenge is at all visible.
-     */
-    public boolean isChallengeShowing() {
-        return mChallengeShowing;
-    }
-
-    @Override
-    public boolean isChallengeOverlapping() {
-        return mChallengeShowing;
-    }
-
-    @Override
-    public boolean isBouncing() {
-        return mIsBouncing;
-    }
-
-    @Override
-    public int getBouncerAnimationDuration() {
-        return HANDLE_ANIMATE_DURATION;
-    }
-
-    @Override
-    public void showBouncer() {
-        if (mIsBouncing) return;
-        mWasChallengeShowing = mChallengeShowing;
-        mIsBouncing = true;
-        showChallenge(true);
-        if (mScrimView != null) {
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
-            anim.setDuration(HANDLE_ANIMATE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mScrimView.setVisibility(VISIBLE);
-                }
-            });
-            anim.start();
-        }
-        if (mChallengeView != null) {
-            mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION);
-        }
-
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(true);
-        }
-    }
-
-    @Override
-    public void hideBouncer() {
-        if (!mIsBouncing) return;
-        if (!mWasChallengeShowing) showChallenge(false);
-        mIsBouncing = false;
-
-        if (mScrimView != null) {
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
-            anim.setDuration(HANDLE_ANIMATE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mScrimView.setVisibility(GONE);
-                }
-            });
-            anim.start();
-        }
-        if (mChallengeView != null) {
-            mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION);
-        }
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(false);
-        }
-    }
-
-    private int getChallengeMargin(boolean expanded) {
-        return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
-    }
-
-    private float getChallengeAlpha() {
-        float x = mChallengeOffset - 1;
-        return x * x * x + 1.f;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
-        // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
-        // If there are one or more pointers in the challenge view before we take over
-        // touch events, onInterceptTouchEvent will set mBlockDrag.
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        final int action = ev.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mGestureStartX = ev.getX();
-                mGestureStartY = ev.getY();
-                mBlockDrag = false;
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                resetTouch();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                final int count = ev.getPointerCount();
-                for (int i = 0; i < count; i++) {
-                    final float x = ev.getX(i);
-                    final float y = ev.getY(i);
-                    if (!mIsBouncing && mActivePointerId == INVALID_POINTER
-                                && (crossedDragHandle(x, y, mGestureStartY)
-                                || (isInChallengeView(x, y) &&
-                                        mScrollState == SCROLL_STATE_SETTLING))) {
-                        mActivePointerId = ev.getPointerId(i);
-                        mGestureStartX = x;
-                        mGestureStartY = y;
-                        mGestureStartChallengeBottom = getChallengeBottom();
-                        mDragging = true;
-                        mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
-                    } else if (mChallengeShowing && isInChallengeView(x, y)) {
-                        mBlockDrag = true;
-                    }
-                }
-                break;
-        }
-
-        if (mBlockDrag || isChallengeInteractionBlocked()) {
-            mActivePointerId = INVALID_POINTER;
-            mDragging = false;
-        }
-
-        return mDragging;
-    }
-
-    private boolean isChallengeInteractionBlocked() {
-        return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal;
-    }
-
-    private void resetTouch() {
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-        mActivePointerId = INVALID_POINTER;
-        mDragging = mBlockDrag = false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        final int action = ev.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mBlockDrag = false;
-                mGestureStartX = ev.getX();
-                mGestureStartY = ev.getY();
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                if (mDragging && !isChallengeInteractionBlocked()) {
-                    showChallenge(0);
-                }
-                resetTouch();
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-                if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) {
-                    break;
-                }
-            case MotionEvent.ACTION_UP:
-                if (mDragging && !isChallengeInteractionBlocked()) {
-                    mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
-                    showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
-                }
-                resetTouch();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (!mDragging && !mBlockDrag && !mIsBouncing) {
-                    final int count = ev.getPointerCount();
-                    for (int i = 0; i < count; i++) {
-                        final float x = ev.getX(i);
-                        final float y = ev.getY(i);
-
-                        if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
-                                (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
-                                && mActivePointerId == INVALID_POINTER
-                                && !isChallengeInteractionBlocked()) {
-                            mGestureStartX = x;
-                            mGestureStartY = y;
-                            mActivePointerId = ev.getPointerId(i);
-                            mGestureStartChallengeBottom = getChallengeBottom();
-                            mDragging = true;
-                            mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
-                            break;
-                        }
-                    }
-                }
-                // Not an else; this can be set above.
-                if (mDragging) {
-                    // No-op if already in this state, but set it here in case we arrived
-                    // at this point from either intercept or the above.
-                    setScrollState(SCROLL_STATE_DRAGGING);
-
-                    final int index = ev.findPointerIndex(mActivePointerId);
-                    if (index < 0) {
-                        // Oops, bogus state. We lost some touch events somewhere.
-                        // Just drop it with no velocity and let things settle.
-                        resetTouch();
-                        showChallenge(0);
-                        return true;
-                    }
-                    final float y = ev.getY(index);
-                    final float pos = Math.min(y - mGestureStartY,
-                            getLayoutBottom() - mChallengeBottomBound);
-
-                    moveChallengeTo(mGestureStartChallengeBottom + (int) pos);
-                }
-                break;
-        }
-        return true;
-    }
-
-    /**
-     * The lifecycle of touch events is subtle and it's very easy to do something
-     * that will cause bugs that will be nasty to track when overriding this method.
-     * Normally one should always override onInterceptTouchEvent instead.
-     *
-     * To put it another way, don't try this at home.
-     */
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        final int action = ev.getActionMasked();
-        boolean handled = false;
-        if (action == MotionEvent.ACTION_DOWN) {
-            // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
-            mEdgeCaptured = false;
-        }
-        if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
-            // Normally we would need to do a lot of extra stuff here.
-            // We can only get away with this because we haven't padded in
-            // the widget pager or otherwise transformed it during layout.
-            // We also don't support things like splitting MotionEvents.
-
-            // We set handled to captured even if dispatch is returning false here so that
-            // we don't send a different view a busted or incomplete event stream.
-            handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
-        }
-
-        if (!handled && !mEdgeCaptured) {
-            handled = super.dispatchTouchEvent(ev);
-        }
-
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            mEdgeCaptured = false;
-        }
-
-        return handled;
-    }
-
-    private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
-        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
-            return false;
-        }
-
-        final float x = ev.getX();
-        return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
-    }
-
-    /**
-     * We only want to add additional vertical space to the drag handle when the panel is fully
-     * closed.
-     */
-    private int getDragHandleSizeAbove() {
-        return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove;
-    }
-    private int getDragHandleSizeBelow() {
-        return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow;
-    }
-
-    private boolean isInChallengeView(float x, float y) {
-        return isPointInView(x, y, mChallengeView);
-    }
-
-    private boolean isInDragHandle(float x, float y) {
-        return isPointInView(x, y, mExpandChallengeView);
-    }
-
-    private boolean isPointInView(float x, float y, View view) {
-        if (view == null) {
-            return false;
-        }
-        return x >= view.getLeft() && y >= view.getTop()
-                && x < view.getRight() && y < view.getBottom();
-    }
-
-    private boolean crossedDragHandle(float x, float y, float initialY) {
-
-        final int challengeTop = mChallengeView.getTop();
-        final boolean horizOk = x >= 0 && x < getWidth();
-
-        final boolean vertOk;
-        if (mChallengeShowing) {
-            vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) &&
-                    y > challengeTop + getDragHandleSizeBelow();
-        } else {
-            vertOk = initialY > challengeTop + getDragHandleSizeBelow() &&
-                    y < challengeTop - getDragHandleSizeAbove();
-        }
-        return horizOk && vertOk;
-    }
-
-    private int makeChildMeasureSpec(int maxSize, int childDimen) {
-        final int mode;
-        final int size;
-        switch (childDimen) {
-            case LayoutParams.WRAP_CONTENT:
-                mode = MeasureSpec.AT_MOST;
-                size = maxSize;
-                break;
-            case LayoutParams.MATCH_PARENT:
-                mode = MeasureSpec.EXACTLY;
-                size = maxSize;
-                break;
-            default:
-                mode = MeasureSpec.EXACTLY;
-                size = Math.min(maxSize, childDimen);
-                break;
-        }
-        return MeasureSpec.makeMeasureSpec(size, mode);
-    }
-
-    @Override
-    protected void onMeasure(int widthSpec, int heightSpec) {
-        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
-                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
-            throw new IllegalArgumentException(
-                    "SlidingChallengeLayout must be measured with an exact size");
-        }
-
-        final int width = MeasureSpec.getSize(widthSpec);
-        final int height = MeasureSpec.getSize(heightSpec);
-        setMeasuredDimension(width, height);
-
-        // Find one and only one challenge view.
-        final View oldChallengeView = mChallengeView;
-        final View oldExpandChallengeView = mChallengeView;
-        mChallengeView = null;
-        mExpandChallengeView = null;
-        final int count = getChildCount();
-
-        // First iteration through the children finds special children and sets any associated
-        // state.
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
-                if (mChallengeView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child with layout_isChallenge=\"true\"");
-                }
-                if (!(child instanceof KeyguardSecurityContainer)) {
-                            throw new IllegalArgumentException(
-                                    "Challenge must be a KeyguardSecurityContainer");
-                }
-                mChallengeView = (KeyguardSecurityContainer) child;
-                if (mChallengeView != oldChallengeView) {
-                    mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
-                }
-                // We're going to play silly games with the frame's background drawable later.
-                if (!mHasLayout) {
-                    // Set up the margin correctly based on our content for the first run.
-                    mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
-                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
-                if (mExpandChallengeView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child with layout_childType"
-                            + "=\"expandChallengeHandle\"");
-                }
-                mExpandChallengeView = child;
-                if (mExpandChallengeView != oldExpandChallengeView) {
-                    mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE);
-                    mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener);
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
-                setScrimView(child);
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
-                mWidgetsView = child;
-            }
-        }
-
-        // We want to measure the challenge view first, since the KeyguardWidgetPager
-        // needs to do things its measure pass that are dependent on the challenge view
-        // having been measured.
-        if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) {
-            // This one's a little funny. If the IME is present - reported in the form
-            // of insets on the root view - we only give the challenge the space it would
-            // have had if the IME wasn't there in order to keep the rest of the layout stable.
-            // We base this on the layout_maxHeight on the challenge view. If it comes out
-            // negative or zero, either we didn't have a maxHeight or we're totally out of space,
-            // so give up and measure as if this rule weren't there.
-            int challengeHeightSpec = heightSpec;
-            final View root = getRootView();
-            if (root != null) {
-                final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
-                final int specSize = MeasureSpec.getSize(heightSpec);
-                final int windowHeight = mDisplayMetrics.heightPixels - root.getPaddingTop();
-                final int diff = windowHeight - specSize;
-                final int maxChallengeHeight = lp.maxHeight - diff;
-                if (maxChallengeHeight > 0) {
-                    challengeHeightSpec = makeChildMeasureSpec(maxChallengeHeight, lp.height);
-                }
-            }
-            measureChildWithMargins(mChallengeView, widthSpec, 0, challengeHeightSpec, 0);
-        }
-
-        // Measure the rest of the children
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-            // Don't measure the challenge view twice!
-            if (child == mChallengeView) continue;
-
-            // Measure children. Widget frame measures special, so that we can ignore
-            // insets for the IME.
-            int parentWidthSpec = widthSpec, parentHeightSpec = heightSpec;
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
-                final View root = getRootView();
-                if (root != null) {
-                    // This calculation is super dodgy and relies on several assumptions.
-                    // Specifically that the root of the window will be padded in for insets
-                    // and that the window is LAYOUT_IN_SCREEN.
-                    final int windowWidth = mDisplayMetrics.widthPixels;
-                    final int windowHeight = mDisplayMetrics.heightPixels - root.getPaddingTop();
-                    parentWidthSpec = MeasureSpec.makeMeasureSpec(
-                            windowWidth, MeasureSpec.EXACTLY);
-                    parentHeightSpec = MeasureSpec.makeMeasureSpec(
-                            windowHeight, MeasureSpec.EXACTLY);
-                }
-            }
-            measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final int paddingLeft = getPaddingLeft();
-        final int paddingTop = getPaddingTop();
-        final int paddingRight = getPaddingRight();
-        final int paddingBottom = getPaddingBottom();
-        final int width = r - l;
-        final int height = b - t;
-
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-
-            if (child.getVisibility() == GONE) continue;
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
-                // Challenge views pin to the bottom, offset by a portion of their height,
-                // and center horizontally.
-                final int center = (paddingLeft + width - paddingRight) / 2;
-                final int childWidth = child.getMeasuredWidth();
-                final int childHeight = child.getMeasuredHeight();
-                final int left = center - childWidth / 2;
-                final int layoutBottom = height - paddingBottom - lp.bottomMargin;
-                // We use the top of the challenge view to position the handle, so
-                // we never want less than the handle size showing at the bottom.
-                final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
-                        * (1 - mChallengeOffset));
-                child.setAlpha(getChallengeAlpha());
-                child.layout(left, bottom - childHeight, left + childWidth, bottom);
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
-                final int center = (paddingLeft + width - paddingRight) / 2;
-                final int left = center - child.getMeasuredWidth() / 2;
-                final int right = left + child.getMeasuredWidth();
-                final int bottom = height - paddingBottom - lp.bottomMargin;
-                final int top = bottom - child.getMeasuredHeight();
-                child.layout(left, top, right, bottom);
-            } else {
-                // Non-challenge views lay out from the upper left, layered.
-                child.layout(paddingLeft + lp.leftMargin,
-                        paddingTop + lp.topMargin,
-                        paddingLeft + child.getMeasuredWidth(),
-                        paddingTop + child.getMeasuredHeight());
-            }
-        }
-
-        if (!mHasLayout) {
-            mHasLayout = true;
-        }
-    }
-
-    @Override
-    public void draw(Canvas c) {
-        super.draw(c);
-        if (DEBUG) {
-            final Paint debugPaint = new Paint();
-            debugPaint.setColor(0x40FF00CC);
-            // show the isInDragHandle() rect
-            c.drawRect(mDragHandleEdgeSlop,
-                    mChallengeView.getTop() - getDragHandleSizeAbove(),
-                    getWidth() - mDragHandleEdgeSlop,
-                    mChallengeView.getTop() + getDragHandleSizeBelow(),
-                    debugPaint);
-        }
-    }
-
-    public void computeScroll() {
-        super.computeScroll();
-
-        if (!mScroller.isFinished()) {
-            if (mChallengeView == null) {
-                // Can't scroll if the view is missing.
-                Log.e(TAG, "Challenge view missing in computeScroll");
-                mScroller.abortAnimation();
-                return;
-            }
-
-            mScroller.computeScrollOffset();
-            moveChallengeTo(mScroller.getCurrY());
-
-            if (mScroller.isFinished()) {
-                post(mEndScrollRunnable);
-            }
-        }
-    }
-
-    private void cancelTransitionsInProgress() {
-        if (!mScroller.isFinished()) {
-            mScroller.abortAnimation();
-            completeChallengeScroll();
-        }
-        if (mFader != null) {
-            mFader.cancel();
-        }
-    }
-
-    public void fadeInChallenge() {
-        fadeChallenge(true);
-    }
-
-    public void fadeOutChallenge() {
-        fadeChallenge(false);
-    }
-
-    public void fadeChallenge(final boolean show) {
-        if (mChallengeView != null) {
-
-            cancelTransitionsInProgress();
-            float alpha = show ? 1f : 0f;
-            int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION;
-            mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha);
-            mFader.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    onFadeStart(show);
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    onFadeEnd(show);
-                }
-            });
-            mFader.setDuration(duration);
-            mFader.start();
-        }
-    }
-
-    private int getMaxChallengeBottom() {
-        if (mChallengeView == null) return 0;
-        final int layoutBottom = getLayoutBottom();
-        final int challengeHeight = mChallengeView.getMeasuredHeight();
-
-        return (layoutBottom + challengeHeight - mChallengeBottomBound);
-    }
-
-    private int getMinChallengeBottom() {
-        return getLayoutBottom();
-    }
-
-
-    private void onFadeStart(boolean show) {
-        mChallengeInteractiveInternal = false;
-        mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
-
-        if (show) {
-            moveChallengeTo(getMinChallengeBottom());
-        }
-
-        setScrollState(SCROLL_STATE_FADING);
-    }
-
-    private void onFadeEnd(boolean show) {
-        mChallengeInteractiveInternal = true;
-        setChallengeShowing(show);
-
-        if (!show) {
-            moveChallengeTo(getMaxChallengeBottom());
-        }
-
-        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
-        mFader = null;
-        setScrollState(SCROLL_STATE_IDLE);
-    }
-
-    public int getMaxChallengeTop() {
-        if (mChallengeView == null) return 0;
-
-        final int layoutBottom = getLayoutBottom();
-        final int challengeHeight = mChallengeView.getMeasuredHeight();
-        return layoutBottom - challengeHeight;
-    }
-
-    /**
-     * Move the bottom edge of mChallengeView to a new position and notify the listener
-     * if it represents a change in position. Changes made through this method will
-     * be stable across layout passes. If this method is called before first layout of
-     * this SlidingChallengeLayout it will have no effect.
-     *
-     * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system.
-     * @return true if the challenge view was moved
-     */
-    private boolean moveChallengeTo(int bottom) {
-        if (mChallengeView == null || !mHasLayout) {
-            return false;
-        }
-
-        final int layoutBottom = getLayoutBottom();
-        final int challengeHeight = mChallengeView.getHeight();
-
-        bottom = Math.max(getMinChallengeBottom(),
-                Math.min(bottom, getMaxChallengeBottom()));
-
-        float offset = 1.f - (float) (bottom - layoutBottom) /
-                (challengeHeight - mChallengeBottomBound);
-        mChallengeOffset = offset;
-        if (offset > 0 && !mChallengeShowing) {
-            setChallengeShowing(true);
-        }
-
-        mChallengeView.layout(mChallengeView.getLeft(),
-                bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
-
-        mChallengeView.setAlpha(getChallengeAlpha());
-        if (mScrollListener != null) {
-            mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
-        }
-        postInvalidateOnAnimation();
-        return true;
-    }
-
-    /**
-     * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with
-     * the bottom edge of mChallengeView when the challenge is fully opened.
-     */
-    private int getLayoutBottom() {
-        final int bottomMargin = (mChallengeView == null)
-                ? 0
-                : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
-        final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin;
-        return layoutBottom;
-    }
-
-    /**
-     * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'.
-     */
-    private int getChallengeBottom() {
-        if (mChallengeView == null) return 0;
-
-        return mChallengeView.getBottom();
-    }
-
-    /**
-     * Show or hide the challenge view, animating it if necessary.
-     * @param show true to show, false to hide
-     */
-    public void showChallenge(boolean show) {
-        showChallenge(show, 0);
-        if (!show) {
-            // Block any drags in progress so that callers can use this to disable dragging
-            // for other touch interactions.
-            mBlockDrag = true;
-        }
-    }
-
-    private void showChallenge(int velocity) {
-        boolean show = false;
-        if (Math.abs(velocity) > mMinVelocity) {
-            show = velocity < 0;
-        } else {
-            show = mChallengeOffset >= 0.5f;
-        }
-        showChallenge(show, velocity);
-    }
-
-    private void showChallenge(boolean show, int velocity) {
-        if (mChallengeView == null) {
-            setChallengeShowing(false);
-            return;
-        }
-
-        if (mHasLayout) {
-            mChallengeShowingTargetState = show;
-            final int layoutBottom = getLayoutBottom();
-            animateChallengeTo(show ? layoutBottom :
-                    layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity);
-        }
-    }
-
-    @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
-                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
-                new LayoutParams(p);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams();
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    public static class LayoutParams extends MarginLayoutParams {
-        public int childType = CHILD_TYPE_NONE;
-        public static final int CHILD_TYPE_NONE = 0;
-        public static final int CHILD_TYPE_CHALLENGE = 2;
-        public static final int CHILD_TYPE_SCRIM = 4;
-        public static final int CHILD_TYPE_WIDGETS = 5;
-        public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6;
-
-        public int maxHeight;
-
-        public LayoutParams() {
-            this(MATCH_PARENT, WRAP_CONTENT);
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(LayoutParams source) {
-            super(source);
-
-            childType = source.childType;
-        }
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs,
-                    R.styleable.SlidingChallengeLayout_Layout);
-            childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType,
-                    CHILD_TYPE_NONE);
-            maxHeight = a.getDimensionPixelSize(
-                    R.styleable.SlidingChallengeLayout_Layout_layout_maxHeight, 0);
-            a.recycle();
-        }
-    }
-}
diff --git a/preloaded-classes b/preloaded-classes
index 8d1d1a5..cb2ace3 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -663,8 +663,8 @@
 android.net.wifi.WifiManager
 android.net.wifi.WifiManager$ServiceHandler
 android.net.wifi.WifiNative
-android.nfc.INdefPushCallback
-android.nfc.INdefPushCallback$Stub
+android.nfc.IAppCallback
+android.nfc.IAppCallback$Stub
 android.nfc.INfcAdapter
 android.nfc.INfcAdapter$Stub
 android.nfc.INfcAdapter$Stub$Proxy
@@ -1209,18 +1209,13 @@
 android.webkit.BrowserFrame$ConfigCallback
 android.webkit.CallbackProxy
 android.webkit.CookieManager
-android.webkit.CookieManagerClassic
 android.webkit.CookieSyncManager
 android.webkit.DeviceMotionAndOrientationManager
 android.webkit.GeolocationPermissions
-android.webkit.GeolocationPermissionsClassic
-android.webkit.GeolocationPermissionsClassic$1
-android.webkit.GeolocationPermissionsClassic$2
 android.webkit.HTML5Audio
 android.webkit.HTML5VideoViewProxy
 android.webkit.JWebCoreJavaBridge
 android.webkit.JavascriptInterface
-android.webkit.JniUtil
 android.webkit.L10nUtils
 android.webkit.MockGeolocation
 android.webkit.OverScrollGlow
@@ -1232,44 +1227,20 @@
 android.webkit.ViewManager$3
 android.webkit.ViewStateSerializer
 android.webkit.WebBackForwardList
-android.webkit.WebBackForwardListClassic
 android.webkit.WebCoreThreadWatchdog
 android.webkit.WebHistoryItem
-android.webkit.WebHistoryItemClassic
 android.webkit.WebIconDatabase
-android.webkit.WebIconDatabaseClassic
-android.webkit.WebIconDatabaseClassic$EventHandler
-android.webkit.WebIconDatabaseClassic$EventHandler$1
 android.webkit.WebSettings
 android.webkit.WebSettings$LayoutAlgorithm
 android.webkit.WebSettings$PluginState
 android.webkit.WebSettings$RenderPriority
 android.webkit.WebSettings$ZoomDensity
-android.webkit.WebSettingsClassic
-android.webkit.WebSettingsClassic$AutoFillProfile
-android.webkit.WebSettingsClassic$EventHandler
-android.webkit.WebSettingsClassic$EventHandler$1
 android.webkit.WebStorage
-android.webkit.WebStorageClassic
-android.webkit.WebStorageClassic$1
-android.webkit.WebStorageClassic$2
 android.webkit.WebSyncManager
 android.webkit.WebSyncManager$SyncHandler
 android.webkit.WebView
 android.webkit.WebView$PrivateAccess
-android.webkit.WebViewClassic
-android.webkit.WebViewClassic$Factory
-android.webkit.WebViewClassic$OnTrimMemoryListener
-android.webkit.WebViewClassic$PackageListener
-android.webkit.WebViewClassic$PageSwapDelegate
-android.webkit.WebViewClassic$PrivateHandler
-android.webkit.WebViewClassic$ProxyReceiver
-android.webkit.WebViewClassic$SelectionHandleAlpha
-android.webkit.WebViewClassic$TitleBarDelegate
-android.webkit.WebViewClassic$TrustStorageListener
-android.webkit.WebViewClassic$ViewSizeData
 android.webkit.WebViewClient
-android.webkit.WebViewCore
 android.webkit.WebViewCore$AutoFillData
 android.webkit.WebViewCore$DrawData
 android.webkit.WebViewCore$EventHub
@@ -1280,9 +1251,8 @@
 android.webkit.WebViewCore$WebCoreThread
 android.webkit.WebViewCore$WebCoreThread$1
 android.webkit.WebViewDatabase
-android.webkit.WebViewDatabaseClassic
-android.webkit.WebViewDatabaseClassic$1
 android.webkit.WebViewFactory
+android.webkit.WebViewFactory$Preloader
 android.webkit.WebViewFactoryProvider
 android.webkit.WebViewFactoryProvider$Statics
 android.webkit.WebViewInputDispatcher
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 5d913f3..6e944ef 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -36,12 +36,13 @@
     libhardware_legacy \
     libskia \
     libgui \
-    libui
+    libui \
+    libinput
 
 LOCAL_C_INCLUDES := \
     external/skia/include/core
 
-LOCAL_MODULE:= libinput
+LOCAL_MODULE:= libinputservice
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index f4e1cec..4d70d5f 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -36,9 +36,9 @@
 #include <errno.h>
 #include <assert.h>
 
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/KeyCharacterMap.h>
+#include <input/VirtualKeyMap.h>
 
 #include <string.h>
 #include <stdint.h>
@@ -162,7 +162,7 @@
         next(NULL),
         fd(fd), id(id), path(path), identifier(identifier),
         classes(0), configuration(NULL), virtualKeyMap(NULL),
-        ffEffectPlaying(false), ffEffectId(-1),
+        ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
         timestampOverrideSec(0), timestampOverrideUsec(0) {
     memset(keyBitmask, 0, sizeof(keyBitmask));
     memset(absBitmask, 0, sizeof(absBitmask));
@@ -195,7 +195,7 @@
 const int EventHub::EPOLL_MAX_EVENTS;
 
 EventHub::EventHub(void) :
-        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1),
+        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
         mOpeningDevices(0), mClosingDevices(0),
         mNeedToSendFinishedDeviceScan(false),
         mNeedToReopenDevices(false), mNeedToScanDevices(true),
@@ -269,6 +269,13 @@
     return device->classes;
 }
 
+int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device == NULL) return 0;
+    return device->controllerNumber;
+}
+
 void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
@@ -1230,6 +1237,10 @@
         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
     }
 
+    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) {
+        device->controllerNumber = getNextControllerNumberLocked(device);
+    }
+
     // Register with epoll.
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
@@ -1341,6 +1352,27 @@
     return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
 }
 
+int32_t EventHub::getNextControllerNumberLocked(Device* device) {
+    if (mControllerNumbers.isFull()) {
+        ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
+                device->identifier.name.string());
+        return 0;
+    }
+    // Since the controller number 0 is reserved for non-controllers, translate all numbers up by
+    // one
+    return static_cast<int32_t>(mControllerNumbers.markFirstUnmarkedBit() + 1);
+}
+
+void EventHub::releaseControllerNumberLocked(Device* device) {
+    int32_t num = device->controllerNumber;
+    device->controllerNumber= 0;
+    if (num == 0) {
+        return;
+    }
+    mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
+}
+
+
 bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
     if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
         return false;
@@ -1392,6 +1424,8 @@
         }
     }
 
+    releaseControllerNumberLocked(device);
+
     mDevices.removeItem(device->id);
     device->close();
 
@@ -1521,6 +1555,7 @@
             dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
             dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
             dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
+            dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
             dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
             dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
                     "product=0x%04x, version=0x%04x\n",
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index c93fc7a..ae28f01 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -18,12 +18,12 @@
 #ifndef _RUNTIME_EVENT_HUB_H
 #define _RUNTIME_EVENT_HUB_H
 
-#include <androidfw/Input.h>
-#include <androidfw/InputDevice.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <input/Keyboard.h>
+#include <input/KeyLayoutMap.h>
+#include <input/KeyCharacterMap.h>
+#include <input/VirtualKeyMap.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Log.h>
@@ -33,6 +33,7 @@
 #include <utils/PropertyMap.h>
 #include <utils/Vector.h>
 #include <utils/KeyedVector.h>
+#include <utils/BitSet.h>
 
 #include <linux/input.h>
 #include <sys/epoll.h>
@@ -179,6 +180,8 @@
 
     virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
 
+    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const = 0;
+
     virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
 
     virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
@@ -263,6 +266,8 @@
 
     virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const;
 
+    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const;
+
     virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
 
     virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
@@ -343,6 +348,8 @@
         bool ffEffectPlaying;
         int16_t ffEffectId; // initially -1
 
+        int32_t controllerNumber;
+
         int32_t timestampOverrideSec;
         int32_t timestampOverrideUsec;
 
@@ -384,6 +391,9 @@
 
     bool isExternalDeviceLocked(Device* device);
 
+    int32_t getNextControllerNumberLocked(Device* device);
+    void releaseControllerNumberLocked(Device* device);
+
     // Protect all internal state.
     mutable Mutex mLock;
 
@@ -398,6 +408,8 @@
 
     int32_t mNextDeviceId;
 
+    BitSet32 mControllerNumbers;
+
     KeyedVector<int32_t, Device*> mDevices;
 
     Device *mOpeningDevices;
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index c04a935..1f5504c 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -17,7 +17,7 @@
 #ifndef _UI_INPUT_APPLICATION_H
 #define _UI_INPUT_APPLICATION_H
 
-#include <androidfw/Input.h>
+#include <input/Input.h>
 
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 23a846b..9e7a15d 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -84,6 +84,8 @@
 // Log a warning when an event takes longer than this to process, even if an ANR does not occur.
 const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
 
+// Number of recent events to keep for debugging purposes.
+const size_t RECENT_QUEUE_MAX_SIZE = 10;
 
 static inline nsecs_t now() {
     return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -455,6 +457,14 @@
     return needWake;
 }
 
+void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
+    entry->refCount += 1;
+    mRecentQueue.enqueueAtTail(entry);
+    if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) {
+        mRecentQueue.dequeueAtHead()->release();
+    }
+}
+
 sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
         int32_t x, int32_t y) {
     // Traverse windows from front to back to find touched window.
@@ -624,6 +634,7 @@
     if (entry == mNextUnblockedEvent) {
         mNextUnblockedEvent = NULL;
     }
+    addRecentEventLocked(entry);
     entry->release();
 }
 
@@ -1264,21 +1275,7 @@
             // Try to assign the pointer to the first foreground window we find, if there is one.
             newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
             if (newTouchedWindowHandle == NULL) {
-                // There is no touched window.  If this is an initial down event
-                // then wait for a window to appear that will handle the touch.  This is
-                // to ensure that we report an ANR in the case where an application has started
-                // but not yet put up a window and the user is starting to get impatient.
-                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
-                        && mFocusedApplicationHandle != NULL) {
-                    injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                            mFocusedApplicationHandle, NULL, nextWakeupTime,
-                            "Waiting because there is no touchable window that can "
-                            "handle the event but there is focused application that may "
-                            "eventually add a new window when it finishes starting up.");
-                    goto Unresponsive;
-                }
-
-                ALOGI("Dropping event because there is no touched window.");
+                ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
                 injectionResult = INPUT_EVENT_INJECTION_FAILED;
                 goto Failed;
             }
@@ -3161,6 +3158,31 @@
 
     nsecs_t currentTime = now();
 
+    // Dump recently dispatched or dropped events from oldest to newest.
+    if (!mRecentQueue.isEmpty()) {
+        dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
+        for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
+            dump.append(INDENT2);
+            entry->appendDescription(dump);
+            dump.appendFormat(", age=%0.1fms\n",
+                    (currentTime - entry->eventTime) * 0.000001f);
+        }
+    } else {
+        dump.append(INDENT "RecentQueue: <empty>\n");
+    }
+
+    // Dump event currently being dispatched.
+    if (mPendingEvent) {
+        dump.append(INDENT "PendingEvent:\n");
+        dump.append(INDENT2);
+        mPendingEvent->appendDescription(dump);
+        dump.appendFormat(", age=%0.1fms\n",
+                (currentTime - mPendingEvent->eventTime) * 0.000001f);
+    } else {
+        dump.append(INDENT "PendingEvent: <none>\n");
+    }
+
+    // Dump inbound events from oldest to newest.
     if (!mInboundQueue.isEmpty()) {
         dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
         for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
@@ -3383,6 +3405,7 @@
             & InputDispatcher::doNotifyANRLockedInterruptible);
     commandEntry->inputApplicationHandle = applicationHandle;
     commandEntry->inputWindowHandle = windowHandle;
+    commandEntry->reason = reason;
 }
 
 void InputDispatcher::doNotifyConfigurationChangedInterruptible(
@@ -3412,7 +3435,8 @@
     mLock.unlock();
 
     nsecs_t newTimeout = mPolicy->notifyANR(
-            commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle);
+            commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
+            commandEntry->reason);
 
     mLock.lock();
 
@@ -3809,7 +3833,8 @@
 }
 
 void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const {
-    msg.append("ConfigurationChangedEvent()");
+    msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x",
+            policyFlags);
 }
 
 
@@ -3824,7 +3849,8 @@
 }
 
 void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("DeviceResetEvent(deviceId=%d)", deviceId);
+    msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x",
+            deviceId, policyFlags);
 }
 
 
@@ -3846,8 +3872,11 @@
 }
 
 void InputDispatcher::KeyEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("KeyEvent(action=%d, deviceId=%d, source=0x%08x)",
-            action, deviceId, source);
+    msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, "
+            "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
+            "repeatCount=%d), policyFlags=0x%08x",
+            deviceId, source, action, flags, keyCode, scanCode, metaState,
+            repeatCount, policyFlags);
 }
 
 void InputDispatcher::KeyEntry::recycle() {
@@ -3884,8 +3913,19 @@
 }
 
 void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("MotionEvent(action=%d, deviceId=%d, source=0x%08x, displayId=%d)",
-            action, deviceId, source, displayId);
+    msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, "
+            "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, "
+            "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
+            deviceId, source, action, flags, metaState, buttonState, edgeFlags,
+            xPrecision, yPrecision, displayId);
+    for (uint32_t i = 0; i < pointerCount; i++) {
+        if (i) {
+            msg.append(", ");
+        }
+        msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id,
+                pointerCoords[i].getX(), pointerCoords[i].getY());
+    }
+    msg.appendFormat("]), policyFlags=0x%08x", policyFlags);
 }
 
 
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 430721e..190e7b2 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -17,8 +17,8 @@
 #ifndef _UI_INPUT_DISPATCHER_H
 #define _UI_INPUT_DISPATCHER_H
 
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
@@ -202,7 +202,8 @@
     /* Notifies the system that an application is not responding.
      * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputWindowHandle>& inputWindowHandle) = 0;
+            const sp<InputWindowHandle>& inputWindowHandle,
+            const String8& reason) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
@@ -596,6 +597,7 @@
         KeyEntry* keyEntry;
         sp<InputApplicationHandle> inputApplicationHandle;
         sp<InputWindowHandle> inputWindowHandle;
+        String8 reason;
         int32_t userActivityEventType;
         uint32_t seq;
         bool handled;
@@ -846,6 +848,7 @@
 
     EventEntry* mPendingEvent;
     Queue<EventEntry> mInboundQueue;
+    Queue<EventEntry> mRecentQueue;
     Queue<CommandEntry> mCommandQueue;
 
     void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
@@ -856,6 +859,9 @@
     // Cleans up input state when dropping an inbound event.
     void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
 
+    // Adds an event to a queue of recent events for debugging purposes.
+    void addRecentEventLocked(EventEntry* entry);
+
     // App switch latency optimization.
     bool mAppSwitchSawKeyDown;
     nsecs_t mAppSwitchDueTime;
diff --git a/services/input/InputListener.h b/services/input/InputListener.h
index cd7c25a..78ae10f 100644
--- a/services/input/InputListener.h
+++ b/services/input/InputListener.h
@@ -17,7 +17,7 @@
 #ifndef _UI_INPUT_LISTENER_H
 #define _UI_INPUT_LISTENER_H
 
-#include <androidfw/Input.h>
+#include <input/Input.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
diff --git a/services/input/InputManager.h b/services/input/InputManager.h
index 29584c9..a213b2d 100644
--- a/services/input/InputManager.h
+++ b/services/input/InputManager.h
@@ -25,8 +25,8 @@
 #include "InputReader.h"
 #include "InputDispatcher.h"
 
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
 #include <utils/Timers.h>
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index e229755..feed31c 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -42,8 +42,8 @@
 #include "InputReader.h"
 
 #include <cutils/log.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/Keyboard.h>
+#include <input/VirtualKeyMap.h>
 
 #include <stddef.h>
 #include <stdlib.h>
@@ -354,8 +354,9 @@
 
     InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
     uint32_t classes = mEventHub->getDeviceClasses(deviceId);
+    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
 
-    InputDevice* device = createDeviceLocked(deviceId, identifier, classes);
+    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
     device->configure(when, &mConfig, 0);
     device->reset(when);
 
@@ -395,10 +396,10 @@
     delete device;
 }
 
-InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
+InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
         const InputDeviceIdentifier& identifier, uint32_t classes) {
     InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
-            identifier, classes);
+            controllerNumber, identifier, classes);
 
     // External devices.
     if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
@@ -843,8 +844,8 @@
 // --- InputDevice ---
 
 InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
-        const InputDeviceIdentifier& identifier, uint32_t classes) :
-        mContext(context), mId(id), mGeneration(generation),
+        int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
+        mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
         mIdentifier(identifier), mClasses(classes),
         mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
 }
@@ -995,7 +996,8 @@
 }
 
 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
-    outDeviceInfo->initialize(mId, mGeneration, mIdentifier, mAlias, mIsExternal);
+    outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
+            mIsExternal);
 
     size_t numMappers = mMappers.size();
     for (size_t i = 0; i < numMappers; i++) {
@@ -2631,6 +2633,7 @@
             info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
                     y.fuzz, y.resolution);
         }
+        info->setButtonUnderPad(mParameters.hasButtonUnderPad);
     }
 }
 
@@ -2796,6 +2799,9 @@
         mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
     }
 
+    mParameters.hasButtonUnderPad=
+            getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD);
+
     String8 deviceTypeString;
     if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
             deviceTypeString)) {
@@ -4650,6 +4656,14 @@
                 mCurrentFingerIdBits, positions);
     }
 
+    // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
+    // to NEUTRAL, then we should not generate tap event.
+    if (mPointerGesture.lastGestureMode != PointerGesture::HOVER
+            && mPointerGesture.lastGestureMode != PointerGesture::TAP
+            && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) {
+        mPointerGesture.resetTap();
+    }
+
     // Pick a new active touch id if needed.
     // Choose an arbitrary pointer that just went down, if there is one.
     // Otherwise choose an arbitrary remaining pointer.
@@ -4858,8 +4872,12 @@
                 }
             } else {
 #if DEBUG_GESTURES
-                ALOGD("Gestures: Not a TAP, %0.3fms since down",
-                        (when - mPointerGesture.tapDownTime) * 0.000001f);
+                if (mPointerGesture.tapDownTime != LLONG_MIN) {
+                    ALOGD("Gestures: Not a TAP, %0.3fms since down",
+                            (when - mPointerGesture.tapDownTime) * 0.000001f);
+                } else {
+                    ALOGD("Gestures: Not a TAP, incompatible mode transitions");
+                }
 #endif
             }
         }
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 0189ba7..a8bb636 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -21,9 +21,9 @@
 #include "PointerController.h"
 #include "InputListener.h"
 
-#include <androidfw/Input.h>
-#include <androidfw/VelocityControl.h>
-#include <androidfw/VelocityTracker.h>
+#include <input/Input.h>
+#include <input/VelocityControl.h>
+#include <input/VelocityTracker.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
@@ -409,7 +409,7 @@
 
 protected:
     // These members are protected so they can be instrumented by test cases.
-    virtual InputDevice* createDeviceLocked(int32_t deviceId,
+    virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
             const InputDeviceIdentifier& identifier, uint32_t classes);
 
     class ContextImpl : public InputReaderContext {
@@ -507,16 +507,17 @@
 /* Represents the state of a single input device. */
 class InputDevice {
 public:
-    InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
-            const InputDeviceIdentifier& identifier, uint32_t classes);
+    InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t
+            controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes);
     ~InputDevice();
 
     inline InputReaderContext* getContext() { return mContext; }
-    inline int32_t getId() { return mId; }
-    inline int32_t getGeneration() { return mGeneration; }
-    inline const String8& getName() { return mIdentifier.name; }
-    inline uint32_t getClasses() { return mClasses; }
-    inline uint32_t getSources() { return mSources; }
+    inline int32_t getId() const { return mId; }
+    inline int32_t getControllerNumber() const { return mControllerNumber; }
+    inline int32_t getGeneration() const { return mGeneration; }
+    inline const String8& getName() const { return mIdentifier.name; }
+    inline uint32_t getClasses() const { return mClasses; }
+    inline uint32_t getSources() const { return mSources; }
 
     inline bool isExternal() { return mIsExternal; }
     inline void setExternal(bool external) { mIsExternal = external; }
@@ -573,6 +574,7 @@
 private:
     InputReaderContext* mContext;
     int32_t mId;
+    int32_t mControllerNumber;
     int32_t mGeneration;
     InputDeviceIdentifier mIdentifier;
     String8 mAlias;
@@ -1205,6 +1207,7 @@
         bool hasAssociatedDisplay;
         bool associatedDisplayIsExternal;
         bool orientationAware;
+        bool hasButtonUnderPad;
 
         enum GestureMode {
             GESTURE_MODE_POINTER,
@@ -1282,6 +1285,9 @@
             if (haveSizeBias) {
                 *outSize += sizeBias;
             }
+            if (*outSize < 0) {
+                *outSize = 0;
+            }
         }
     } mCalibration;
 
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 7bd3af7..136870a 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -17,8 +17,8 @@
 #ifndef _UI_INPUT_WINDOW_H
 #define _UI_INPUT_WINDOW_H
 
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 #include <utils/String8.h>
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index fd68b61..790c0bb 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -20,7 +20,7 @@
 #include "SpriteController.h"
 
 #include <ui/DisplayInfo.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
 #include <utils/BitSet.h>
 #include <utils/RefBase.h>
 #include <utils/Looper.h>
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index 211e64b..9278f41 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -17,7 +17,8 @@
     libui \
     libskia \
     libstlport \
-    libinput
+    libinput \
+    libinputservice
 
 static_libraries := \
     libgtest \
@@ -40,7 +41,7 @@
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
     $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
-    $(eval include $(BUILD_EXECUTABLE)) \
+    $(eval include $(BUILD_NATIVE_TEST)) \
 )
 
 # Build the manual test programs.
diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp
index ed2b4a5..26b4fab 100644
--- a/services/input/tests/InputDispatcher_test.cpp
+++ b/services/input/tests/InputDispatcher_test.cpp
@@ -50,7 +50,8 @@
     }
 
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputWindowHandle>& inputWindowHandle) {
+            const sp<InputWindowHandle>& inputWindowHandle,
+            const String8& reason) {
         return 0;
     }
 
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 14065d2..f068732 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -472,6 +472,10 @@
         return device ? device->identifier : InputDeviceIdentifier();
     }
 
+    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const {
+        return 0;
+    }
+
     virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
         Device* device = getDevice(deviceId);
         if (device) {
@@ -928,22 +932,24 @@
         mNextDevice = device;
     }
 
-    InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+    InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name,
+            uint32_t classes) {
         InputDeviceIdentifier identifier;
         identifier.name = name;
         int32_t generation = deviceId + 1;
-        return new InputDevice(&mContext, deviceId, generation, identifier, classes);
+        return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
+                classes);
     }
 
 protected:
-    virtual InputDevice* createDeviceLocked(int32_t deviceId,
+    virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
             const InputDeviceIdentifier& identifier, uint32_t classes) {
         if (mNextDevice) {
             InputDevice* device = mNextDevice;
             mNextDevice = NULL;
             return device;
         }
-        return InputReader::createDeviceLocked(deviceId, identifier, classes);
+        return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes);
     }
 
     friend class InputReaderTest;
@@ -988,10 +994,10 @@
         mFakeEventHub->assertQueueIsEmpty();
     }
 
-    FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId,
+    FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
             const String8& name, uint32_t classes, uint32_t sources,
             const PropertyMap* configuration) {
-        InputDevice* device = mReader->newDevice(deviceId, name, classes);
+        InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
         FakeInputMapper* mapper = new FakeInputMapper(device, sources);
         device->addMapper(mapper);
         mReader->setNextDevice(device);
@@ -1028,7 +1034,7 @@
 
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
 
@@ -1055,7 +1061,7 @@
 
 TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
 
@@ -1082,7 +1088,7 @@
 
 TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
 
@@ -1109,7 +1115,7 @@
 
 TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->addSupportedKeyCode(AKEYCODE_A);
     mapper->addSupportedKeyCode(AKEYCODE_B);
@@ -1153,7 +1159,7 @@
 
 TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
 
     mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
@@ -1177,6 +1183,7 @@
     static const char* DEVICE_NAME;
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
+    static const int32_t DEVICE_CONTROLLER_NUMBER;
     static const uint32_t DEVICE_CLASSES;
 
     sp<FakeEventHub> mFakeEventHub;
@@ -1196,7 +1203,7 @@
         InputDeviceIdentifier identifier;
         identifier.name = DEVICE_NAME;
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
-                identifier, DEVICE_CLASSES);
+                DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
     }
 
     virtual void TearDown() {
@@ -1212,6 +1219,7 @@
 const char* InputDeviceTest::DEVICE_NAME = "device";
 const int32_t InputDeviceTest::DEVICE_ID = 1;
 const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
+const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
 const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD
         | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK;
 
@@ -1365,6 +1373,7 @@
     static const char* DEVICE_NAME;
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
+    static const int32_t DEVICE_CONTROLLER_NUMBER;
     static const uint32_t DEVICE_CLASSES;
 
     sp<FakeEventHub> mFakeEventHub;
@@ -1381,7 +1390,7 @@
         InputDeviceIdentifier identifier;
         identifier.name = DEVICE_NAME;
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
-                identifier, DEVICE_CLASSES);
+                DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
 
         mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
     }
@@ -1461,6 +1470,7 @@
 const char* InputMapperTest::DEVICE_NAME = "device";
 const int32_t InputMapperTest::DEVICE_ID = 1;
 const int32_t InputMapperTest::DEVICE_GENERATION = 2;
+const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
 const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests
 
 
diff --git a/services/java/Android.mk b/services/java/Android.mk
index 95b28d9..8c3d0f0 100644
--- a/services/java/Android.mk
+++ b/services/java/Android.mk
@@ -11,7 +11,7 @@
 
 LOCAL_MODULE:= services
 
-LOCAL_JAVA_LIBRARIES := android.policy telephony-common
+LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
 
 include $(BUILD_JAVA_LIBRARY)
 
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index fa758a8..3d804ef 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -38,11 +38,11 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.text.TextUtils;
-import android.text.format.Time;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.TimeUtils;
 
+import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
@@ -53,48 +53,55 @@
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.TimeZone;
 
+import static android.app.AlarmManager.RTC_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
+
 import com.android.internal.util.LocalLog;
 
 class AlarmManagerService extends IAlarmManager.Stub {
     // The threshold for how long an alarm can be late before we print a
     // warning message.  The time duration is in milliseconds.
     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
-    
-    private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP;
-    private static final int RTC_MASK = 1 << AlarmManager.RTC;
-    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP; 
-    private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME;
-    private static final int TIME_CHANGED_MASK = 1 << 16;
 
-    // Alignment quantum for inexact repeating alarms
-    private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
+    private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
+    private static final int RTC_MASK = 1 << RTC;
+    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; 
+    private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
+    private static final int TIME_CHANGED_MASK = 1 << 16;
+    private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
+
+    // Mask for testing whether a given alarm type is wakeup vs non-wakeup
+    private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
 
     private static final String TAG = "AlarmManager";
     private static final String ClockReceiver_TAG = "ClockReceiver";
     private static final boolean localLOGV = false;
+    private static final boolean DEBUG_BATCH = localLOGV || false;
+    private static final boolean DEBUG_VALIDATE = localLOGV || false;
     private static final int ALARM_EVENT = 1;
     private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
     
     private static final Intent mBackgroundIntent
             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
+    private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
     
+    private static final boolean WAKEUP_STATS = false;
+
     private final Context mContext;
 
     private final LocalLog mLog = new LocalLog(TAG);
 
     private Object mLock = new Object();
-    
-    private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
-    private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>();
-    private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>();
-    private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>();
-    private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder();
-    
+
     private int mDescriptor;
+    private long mNextWakeup;
+    private long mNextNonWakeup;
     private int mBroadcastRefCount = 0;
     private PowerManager.WakeLock mWakeLock;
     private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
@@ -106,14 +113,297 @@
     private final PendingIntent mTimeTickSender;
     private final PendingIntent mDateChangeSender;
 
+    class WakeupEvent {
+        public long when;
+        public int uid;
+        public String action;
+
+        public WakeupEvent(long theTime, int theUid, String theAction) {
+            when = theTime;
+            uid = theUid;
+            action = theAction;
+        }
+    }
+
+    private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
+    private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
+
+    static final class Batch {
+        long start;     // These endpoints are always in ELAPSED
+        long end;
+        boolean standalone; // certain "batches" don't participate in coalescing
+
+        final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
+
+        Batch() {
+            start = 0;
+            end = Long.MAX_VALUE;
+        }
+
+        Batch(Alarm seed) {
+            start = seed.whenElapsed;
+            end = seed.maxWhen;
+            alarms.add(seed);
+        }
+
+        int size() {
+            return alarms.size();
+        }
+
+        Alarm get(int index) {
+            return alarms.get(index);
+        }
+
+        boolean canHold(long whenElapsed, long maxWhen) {
+            return (end >= whenElapsed) && (start <= maxWhen);
+        }
+
+        boolean add(Alarm alarm) {
+            boolean newStart = false;
+            // narrows the batch if necessary; presumes that canHold(alarm) is true
+            int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
+            if (index < 0) {
+                index = 0 - index - 1;
+            }
+            alarms.add(index, alarm);
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "Adding " + alarm + " to " + this);
+            }
+            if (alarm.whenElapsed > start) {
+                start = alarm.whenElapsed;
+                newStart = true;
+            }
+            if (alarm.maxWhen < end) {
+                end = alarm.maxWhen;
+            }
+
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "    => now " + this);
+            }
+            return newStart;
+        }
+
+        boolean remove(final PendingIntent operation) {
+            boolean didRemove = false;
+            long newStart = 0;  // recalculate endpoints as we go
+            long newEnd = Long.MAX_VALUE;
+            for (int i = 0; i < alarms.size(); ) {
+                Alarm alarm = alarms.get(i);
+                if (alarm.operation.equals(operation)) {
+                    alarms.remove(i);
+                    didRemove = true;
+                } else {
+                    if (alarm.whenElapsed > newStart) {
+                        newStart = alarm.whenElapsed;
+                    }
+                    if (alarm.maxWhen < newEnd) {
+                        newEnd = alarm.maxWhen;
+                    }
+                    i++;
+                }
+            }
+            if (didRemove) {
+                // commit the new batch bounds
+                start = newStart;
+                end = newEnd;
+            }
+            return didRemove;
+        }
+
+        boolean remove(final String packageName) {
+            boolean didRemove = false;
+            long newStart = 0;  // recalculate endpoints as we go
+            long newEnd = Long.MAX_VALUE;
+            for (int i = 0; i < alarms.size(); ) {
+                Alarm alarm = alarms.get(i);
+                if (alarm.operation.getTargetPackage().equals(packageName)) {
+                    alarms.remove(i);
+                    didRemove = true;
+                } else {
+                    if (alarm.whenElapsed > newStart) {
+                        newStart = alarm.whenElapsed;
+                    }
+                    if (alarm.maxWhen < newEnd) {
+                        newEnd = alarm.maxWhen;
+                    }
+                    i++;
+                }
+            }
+            if (didRemove) {
+                // commit the new batch bounds
+                start = newStart;
+                end = newEnd;
+            }
+            return didRemove;
+        }
+
+        boolean remove(final int userHandle) {
+            boolean didRemove = false;
+            long newStart = 0;  // recalculate endpoints as we go
+            long newEnd = Long.MAX_VALUE;
+            for (int i = 0; i < alarms.size(); ) {
+                Alarm alarm = alarms.get(i);
+                if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
+                    alarms.remove(i);
+                    didRemove = true;
+                } else {
+                    if (alarm.whenElapsed > newStart) {
+                        newStart = alarm.whenElapsed;
+                    }
+                    if (alarm.maxWhen < newEnd) {
+                        newEnd = alarm.maxWhen;
+                    }
+                    i++;
+                }
+            }
+            if (didRemove) {
+                // commit the new batch bounds
+                start = newStart;
+                end = newEnd;
+            }
+            return didRemove;
+        }
+
+        boolean hasPackage(final String packageName) {
+            final int N = alarms.size();
+            for (int i = 0; i < N; i++) {
+                Alarm a = alarms.get(i);
+                if (a.operation.getTargetPackage().equals(packageName)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean hasWakeups() {
+            final int N = alarms.size();
+            for (int i = 0; i < N; i++) {
+                Alarm a = alarms.get(i);
+                // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
+                if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder b = new StringBuilder(40);
+            b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
+            b.append(" num="); b.append(size());
+            b.append(" start="); b.append(start);
+            b.append(" end="); b.append(end);
+            if (standalone) {
+                b.append(" STANDALONE");
+            }
+            b.append('}');
+            return b.toString();
+        }
+    }
+
+    static class BatchTimeOrder implements Comparator<Batch> {
+        public int compare(Batch b1, Batch b2) {
+            long when1 = b1.start;
+            long when2 = b2.start;
+            if (when1 - when2 > 0) {
+                return 1;
+            }
+            if (when1 - when2 < 0) {
+                return -1;
+            }
+            return 0;
+        }
+    }
+    
+    // minimum recurrence period or alarm futurity for us to be able to fuzz it
+    private static final long MIN_FUZZABLE_INTERVAL = 10000;
+    private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
+    private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+
+    static long convertToElapsed(long when, int type) {
+        final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
+        if (isRtc) {
+            when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
+        }
+        return when;
+    }
+
+    // Apply a heuristic to { recurrence interval, futurity of the trigger time } to
+    // calculate the end of our nominal delivery window for the alarm.
+    static long maxTriggerTime(long now, long triggerAtTime, long interval) {
+        // Current heuristic: batchable window is 75% of either the recurrence interval
+        // [for a periodic alarm] or of the time from now to the desired delivery time,
+        // with a minimum delay/interval of 10 seconds, under which we will simply not
+        // defer the alarm.
+        long futurity = (interval == 0)
+                ? (triggerAtTime - now)
+                : interval;
+        if (futurity < MIN_FUZZABLE_INTERVAL) {
+            futurity = 0;
+        }
+        return triggerAtTime + (long)(.75 * futurity);
+    }
+
+    // returns true if the batch was added at the head
+    static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
+        int index = Collections.binarySearch(list, newBatch, sBatchOrder);
+        if (index < 0) {
+            index = 0 - index - 1;
+        }
+        list.add(index, newBatch);
+        return (index == 0);
+    }
+
+    // Return the index of the matching batch, or -1 if none found.
+    int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
+        final int N = mAlarmBatches.size();
+        for (int i = 0; i < N; i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (!b.standalone && b.canHold(whenElapsed, maxWhen)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
+    void rebatchAllAlarms() {
+        synchronized (mLock) {
+            rebatchAllAlarmsLocked(true);
+        }
+    }
+
+    void rebatchAllAlarmsLocked(boolean doValidate) {
+        ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
+        mAlarmBatches.clear();
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        final int oldBatches = oldSet.size();
+        for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
+            Batch batch = oldSet.get(batchNum);
+            final int N = batch.size();
+            for (int i = 0; i < N; i++) {
+                Alarm a = batch.get(i);
+                long whenElapsed = convertToElapsed(a.when, a.type);
+                long maxElapsed = (a.whenElapsed == a.maxWhen)
+                        ? whenElapsed
+                                : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
+                setImplLocked(a.type, a.when, whenElapsed, maxElapsed,
+                        a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource);
+            }
+        }
+    }
+
     private static final class InFlight extends Intent {
         final PendingIntent mPendingIntent;
+        final WorkSource mWorkSource;
         final Pair<String, ComponentName> mTarget;
         final BroadcastStats mBroadcastStats;
         final FilterStats mFilterStats;
 
-        InFlight(AlarmManagerService service, PendingIntent pendingIntent) {
+        InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource) {
             mPendingIntent = pendingIntent;
+            mWorkSource = workSource;
             Intent intent = pendingIntent.getIntent();
             mTarget = intent != null
                     ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
@@ -166,6 +456,7 @@
     public AlarmManagerService(Context context) {
         mContext = context;
         mDescriptor = init();
+        mNextWakeup = mNextNonWakeup = 0;
 
         // We have to set current TimeZone info to kernel
         // because kernel doesn't keep this after reboot
@@ -179,7 +470,8 @@
         
         mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
-                        Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0,
+                        Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                        | Intent.FLAG_RECEIVER_FOREGROUND), 0,
                         UserHandle.ALL);
         Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
@@ -206,77 +498,170 @@
             super.finalize();
         }
     }
-    
-    public void set(int type, long triggerAtTime, PendingIntent operation) {
-        setRepeating(type, triggerAtTime, 0, operation);
+
+    @Override
+    public void set(int type, long triggerAtTime, long windowLength, long interval,
+            PendingIntent operation, WorkSource workSource) {
+        if (workSource != null) {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.UPDATE_DEVICE_STATS,
+                    "AlarmManager.set");
+        }
+
+        set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
     }
-    
-    public void setRepeating(int type, long triggerAtTime, long interval, 
-            PendingIntent operation) {
+
+    public void set(int type, long triggerAtTime, long windowLength, long interval,
+            PendingIntent operation, boolean isStandalone, WorkSource workSource) {
         if (operation == null) {
             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
             return;
         }
+
+        // Sanity check the window length.  This will catch people mistakenly
+        // trying to pass an end-of-window timestamp rather than a duration.
+        if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
+            Slog.w(TAG, "Window length " + windowLength
+                    + "ms suspiciously long; limiting to 1 hour");
+            windowLength = AlarmManager.INTERVAL_HOUR;
+        }
+
+        if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
+            throw new IllegalArgumentException("Invalid alarm type " + type);
+        }
+
+        if (triggerAtTime < 0) {
+            final long who = Binder.getCallingUid();
+            final long what = Binder.getCallingPid();
+            Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
+                    + " pid=" + what);
+            triggerAtTime = 0;
+        }
+
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        final long triggerElapsed = convertToElapsed(triggerAtTime, type);
+        final long maxElapsed;
+        if (windowLength == AlarmManager.WINDOW_EXACT) {
+            maxElapsed = triggerElapsed;
+        } else if (windowLength < 0) {
+            maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
+        } else {
+            maxElapsed = triggerElapsed + windowLength;
+        }
+
         synchronized (mLock) {
-            Alarm alarm = new Alarm();
-            alarm.type = type;
-            alarm.when = triggerAtTime;
-            alarm.repeatInterval = interval;
-            alarm.operation = operation;
-
-            // Remove this alarm if already scheduled.
-            removeLocked(operation);
-
-            if (localLOGV) Slog.v(TAG, "set: " + alarm);
-
-            int index = addAlarmLocked(alarm);
-            if (index == 0) {
-                setLocked(alarm);
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "set(" + operation + ") : type=" + type
+                        + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
+                        + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
+                        + " interval=" + interval + " standalone=" + isStandalone);
             }
+            setImplLocked(type, triggerAtTime, triggerElapsed, maxElapsed,
+                    interval, operation, isStandalone, true, workSource);
         }
     }
-    
-    public void setInexactRepeating(int type, long triggerAtTime, long interval, 
-            PendingIntent operation) {
-        if (operation == null) {
-            Slog.w(TAG, "setInexactRepeating ignored because there is no intent");
-            return;
-        }
 
-        if (interval <= 0) {
-            Slog.w(TAG, "setInexactRepeating ignored because interval " + interval
-                    + " is invalid");
-            return;
-        }
+    private void setImplLocked(int type, long when, long whenElapsed, long maxWhen, long interval,
+            PendingIntent operation, boolean isStandalone, boolean doValidate,
+            WorkSource workSource) {
+        Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation, workSource);
+        removeLocked(operation);
 
-        // If the requested interval isn't a multiple of 15 minutes, just treat it as exact
-        if (interval % QUANTUM != 0) {
-            if (localLOGV) Slog.v(TAG, "Interval " + interval + " not a quantum multiple");
-            setRepeating(type, triggerAtTime, interval, operation);
-            return;
-        }
-
-        // Translate times into the ELAPSED timebase for alignment purposes so that
-        // alignment never tries to match against wall clock times.
-        final boolean isRtc = (type == AlarmManager.RTC || type == AlarmManager.RTC_WAKEUP);
-        final long skew = (isRtc)
-                ? System.currentTimeMillis() - SystemClock.elapsedRealtime()
-                : 0;
-
-        // Slip forward to the next ELAPSED-timebase quantum after the stated time.  If
-        // we're *at* a quantum point, leave it alone.
-        final long adjustedTriggerTime;
-        long offset = (triggerAtTime - skew) % QUANTUM;
-        if (offset != 0) {
-            adjustedTriggerTime = triggerAtTime - offset + QUANTUM;
+        boolean reschedule;
+        int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
+        if (whichBatch < 0) {
+            Batch batch = new Batch(a);
+            batch.standalone = isStandalone;
+            reschedule = addBatchLocked(mAlarmBatches, batch);
         } else {
-            adjustedTriggerTime = triggerAtTime;
+            Batch batch = mAlarmBatches.get(whichBatch);
+            reschedule = batch.add(a);
+            if (reschedule) {
+                // The start time of this batch advanced, so batch ordering may
+                // have just been broken.  Move it to where it now belongs.
+                mAlarmBatches.remove(whichBatch);
+                addBatchLocked(mAlarmBatches, batch);
+            }
         }
 
-        // Set the alarm based on the quantum-aligned start time
-        if (localLOGV) Slog.v(TAG, "setInexactRepeating: type=" + type + " interval=" + interval
-                + " trigger=" + adjustedTriggerTime + " orig=" + triggerAtTime);
-        setRepeating(type, adjustedTriggerTime, interval, operation);
+        if (DEBUG_VALIDATE) {
+            if (doValidate && !validateConsistencyLocked()) {
+                Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
+                        + " when(hex)=" + Long.toHexString(when)
+                        + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
+                        + " interval=" + interval + " op=" + operation
+                        + " standalone=" + isStandalone);
+                rebatchAllAlarmsLocked(false);
+                reschedule = true;
+            }
+        }
+
+        if (reschedule) {
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    private void logBatchesLocked() {
+        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+        PrintWriter pw = new PrintWriter(bs);
+        final long nowRTC = System.currentTimeMillis();
+        final long nowELAPSED = SystemClock.elapsedRealtime();
+        final int NZ = mAlarmBatches.size();
+        for (int iz = 0; iz < NZ; iz++) {
+            Batch bz = mAlarmBatches.get(iz);
+            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
+            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
+            pw.flush();
+            Slog.v(TAG, bs.toString());
+            bs.reset();
+        }
+    }
+
+    private boolean validateConsistencyLocked() {
+        if (DEBUG_VALIDATE) {
+            long lastTime = Long.MIN_VALUE;
+            final int N = mAlarmBatches.size();
+            for (int i = 0; i < N; i++) {
+                Batch b = mAlarmBatches.get(i);
+                if (b.start >= lastTime) {
+                    // duplicate start times are okay because of standalone batches
+                    lastTime = b.start;
+                } else {
+                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
+                    logBatchesLocked();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private Batch findFirstWakeupBatchLocked() {
+        final int N = mAlarmBatches.size();
+        for (int i = 0; i < N; i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (b.hasWakeups()) {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    private void rescheduleKernelAlarmsLocked() {
+        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
+        // prior to that which contains no wakeups, we schedule that as well.
+        if (mAlarmBatches.size() > 0) {
+            final Batch firstWakeup = findFirstWakeupBatchLocked();
+            final Batch firstBatch = mAlarmBatches.get(0);
+            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+                mNextWakeup = firstWakeup.start;
+                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+            }
+            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
+                mNextNonWakeup = firstBatch.start;
+                setLocked(ELAPSED_REALTIME, firstBatch.start);
+            }
+        }
     }
 
     public void setTime(long millis) {
@@ -338,163 +723,88 @@
     }
     
     public void removeLocked(PendingIntent operation) {
-        removeLocked(mRtcWakeupAlarms, operation);
-        removeLocked(mRtcAlarms, operation);
-        removeLocked(mElapsedRealtimeWakeupAlarms, operation);
-        removeLocked(mElapsedRealtimeAlarms, operation);
-    }
-
-    private void removeLocked(ArrayList<Alarm> alarmList,
-            PendingIntent operation) {
-        if (alarmList.size() <= 0) {
-            return;
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(operation);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
         }
 
-        // iterator over the list removing any it where the intent match
-        Iterator<Alarm> it = alarmList.iterator();
-        
-        while (it.hasNext()) {
-            Alarm alarm = it.next();
-            if (alarm.operation.equals(operation)) {
-                it.remove();
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
             }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
         }
     }
 
     public void removeLocked(String packageName) {
-        removeLocked(mRtcWakeupAlarms, packageName);
-        removeLocked(mRtcAlarms, packageName);
-        removeLocked(mElapsedRealtimeWakeupAlarms, packageName);
-        removeLocked(mElapsedRealtimeAlarms, packageName);
-    }
-
-    private void removeLocked(ArrayList<Alarm> alarmList,
-            String packageName) {
-        if (alarmList.size() <= 0) {
-            return;
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(packageName);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
         }
 
-        // iterator over the list removing any it where the intent match
-        Iterator<Alarm> it = alarmList.iterator();
-        
-        while (it.hasNext()) {
-            Alarm alarm = it.next();
-            if (alarm.operation.getTargetPackage().equals(packageName)) {
-                it.remove();
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(package) changed bounds; rebatching");
             }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
         }
     }
 
     public void removeUserLocked(int userHandle) {
-        removeUserLocked(mRtcWakeupAlarms, userHandle);
-        removeUserLocked(mRtcAlarms, userHandle);
-        removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle);
-        removeUserLocked(mElapsedRealtimeAlarms, userHandle);
-    }
-
-    private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) {
-        if (alarmList.size() <= 0) {
-            return;
-        }
-
-        // iterator over the list removing any it where the intent match
-        Iterator<Alarm> it = alarmList.iterator();
-
-        while (it.hasNext()) {
-            Alarm alarm = it.next();
-            if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
-                it.remove();
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(userHandle);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
             }
         }
-    }
-    
-    public boolean lookForPackageLocked(String packageName) {
-        return lookForPackageLocked(mRtcWakeupAlarms, packageName)
-                || lookForPackageLocked(mRtcAlarms, packageName)
-                || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
-                || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(user) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
     }
 
-    private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
-        for (int i=alarmList.size()-1; i>=0; i--) {
-            if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
+    public boolean lookForPackageLocked(String packageName) {
+        for (int i = 0; i < mAlarmBatches.size(); i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (b.hasPackage(packageName)) {
                 return true;
             }
         }
         return false;
     }
-    
-    private ArrayList<Alarm> getAlarmList(int type) {
-        switch (type) {
-            case AlarmManager.RTC_WAKEUP:              return mRtcWakeupAlarms;
-            case AlarmManager.RTC:                     return mRtcAlarms;
-            case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms;
-            case AlarmManager.ELAPSED_REALTIME:        return mElapsedRealtimeAlarms;
-        }
-        
-        return null;
-    }
-    
-    private int addAlarmLocked(Alarm alarm) {
-        ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
-        
-        int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
-        if (index < 0) {
-            index = 0 - index - 1;
-        }
-        if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
-        alarmList.add(index, alarm);
 
-        if (localLOGV) {
-            // Display the list of alarms for this alarm type
-            Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
-            int position = 0;
-            for (Alarm a : alarmList) {
-                Time time = new Time();
-                time.set(a.when);
-                String timeStr = time.format("%b %d %I:%M:%S %p");
-                Slog.v(TAG, position + ": " + timeStr
-                        + " " + a.operation.getTargetPackage());
-                position += 1;
-            }
-        }
-        
-        return index;
-    }
-    
-    public long timeToNextAlarm() {
-        long nextAlarm = Long.MAX_VALUE;
-        synchronized (mLock) {
-            for (int i=AlarmManager.RTC_WAKEUP;
-                    i<=AlarmManager.ELAPSED_REALTIME; i++) {
-                ArrayList<Alarm> alarmList = getAlarmList(i);
-                if (alarmList.size() > 0) {
-                    Alarm a = alarmList.get(0);
-                    if (a.when < nextAlarm) {
-                        nextAlarm = a.when;
-                    }
-                }
-            }
-        }
-        return nextAlarm;
-    }
-    
-    private void setLocked(Alarm alarm)
+    private void setLocked(int type, long when)
     {
         if (mDescriptor != -1)
         {
             // The kernel never triggers alarms with negative wakeup times
             // so we ensure they are positive.
             long alarmSeconds, alarmNanoseconds;
-            if (alarm.when < 0) {
+            if (when < 0) {
                 alarmSeconds = 0;
                 alarmNanoseconds = 0;
             } else {
-                alarmSeconds = alarm.when / 1000;
-                alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
+                alarmSeconds = when / 1000;
+                alarmNanoseconds = (when % 1000) * 1000 * 1000;
             }
             
-            set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
+            set(mDescriptor, type, alarmSeconds, alarmNanoseconds);
         }
         else
         {
@@ -502,7 +812,7 @@
             msg.what = ALARM_EVENT;
             
             mHandler.removeMessages(ALARM_EVENT);
-            mHandler.sendMessageAtTime(msg, alarm.when);
+            mHandler.sendMessageAtTime(msg, when);
         }
     }
     
@@ -518,29 +828,28 @@
         
         synchronized (mLock) {
             pw.println("Current Alarm Manager state:");
-            if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
-                final long now = System.currentTimeMillis();
-                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-                pw.println(" ");
-                pw.print("  Realtime wakeup (now=");
-                        pw.print(sdf.format(new Date(now))); pw.println("):");
-                if (mRtcWakeupAlarms.size() > 0) {
-                    dumpAlarmList(pw, mRtcWakeupAlarms, "  ", "RTC_WAKEUP", now);
-                }
-                if (mRtcAlarms.size() > 0) {
-                    dumpAlarmList(pw, mRtcAlarms, "  ", "RTC", now);
-                }
-            }
-            if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
-                final long now = SystemClock.elapsedRealtime();
-                pw.println(" ");
-                pw.print("  Elapsed realtime wakeup (now=");
-                        TimeUtils.formatDuration(now, pw); pw.println("):");
-                if (mElapsedRealtimeWakeupAlarms.size() > 0) {
-                    dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, "  ", "ELAPSED_WAKEUP", now);
-                }
-                if (mElapsedRealtimeAlarms.size() > 0) {
-                    dumpAlarmList(pw, mElapsedRealtimeAlarms, "  ", "ELAPSED", now);
+            final long nowRTC = System.currentTimeMillis();
+            final long nowELAPSED = SystemClock.elapsedRealtime();
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+            pw.print("nowRTC="); pw.print(nowRTC);
+            pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
+            pw.print(" nowELAPSED="); pw.println(nowELAPSED);
+
+            long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
+            long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
+            pw.print("Next alarm: "); pw.print(mNextNonWakeup);
+                    pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
+            pw.print("Next wakeup: "); pw.print(mNextWakeup);
+                    pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
+
+            if (mAlarmBatches.size() > 0) {
+                pw.println();
+                pw.print("Pending alarm batches: ");
+                pw.println(mAlarmBatches.size());
+                for (Batch b : mAlarmBatches) {
+                    pw.print(b); pw.println(':');
+                    dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC);
                 }
             }
 
@@ -643,6 +952,26 @@
                             pw.println();
                 }
             }
+
+            if (WAKEUP_STATS) {
+                pw.println();
+                pw.println("  Recent Wakeup History:");
+                long last = -1;
+                for (WakeupEvent event : mRecentWakeups) {
+                    pw.print("    "); pw.print(sdf.format(new Date(event.when)));
+                    pw.print('|');
+                    if (last < 0) {
+                        pw.print('0');
+                    } else {
+                        pw.print(event.when - last);
+                    }
+                    last = event.when;
+                    pw.print('|'); pw.print(event.uid);
+                    pw.print('|'); pw.print(event.action);
+                    pw.println();
+                }
+                pw.println();
+            }
         }
     }
 
@@ -655,74 +984,78 @@
             a.dump(pw, prefix + "  ", now);
         }
     }
-    
+
+    private static final String labelForType(int type) {
+        switch (type) {
+        case RTC: return "RTC";
+        case RTC_WAKEUP : return "RTC_WAKEUP";
+        case ELAPSED_REALTIME : return "ELAPSED";
+        case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
+        default:
+            break;
+        }
+        return "--unknown--";
+    }
+
+    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
+            String prefix, long nowELAPSED, long nowRTC) {
+        for (int i=list.size()-1; i>=0; i--) {
+            Alarm a = list.get(i);
+            final String label = labelForType(a.type);
+            long now = (a.type <= RTC) ? nowRTC : nowELAPSED;
+            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
+                    pw.print(": "); pw.println(a);
+            a.dump(pw, prefix + "  ", now);
+        }
+    }
+
     private native int init();
     private native void close(int fd);
     private native void set(int fd, int type, long seconds, long nanoseconds);
     private native int waitForAlarm(int fd);
     private native int setKernelTimezone(int fd, int minuteswest);
 
-    private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
-                                     ArrayList<Alarm> triggerList,
-                                     long now)
-    {
-        Iterator<Alarm> it = alarmList.iterator();
-        ArrayList<Alarm> repeats = new ArrayList<Alarm>();
-        
-        while (it.hasNext())
-        {
-            Alarm alarm = it.next();
-
-            if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
-
-            if (alarm.when > now) {
-                // don't fire alarms in the future
+    private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+        // batches are temporally sorted, so we need only pull from the
+        // start of the list until we either empty it or hit a batch
+        // that is not yet deliverable
+        while (mAlarmBatches.size() > 0) {
+            Batch batch = mAlarmBatches.get(0);
+            if (batch.start > nowELAPSED) {
+                // Everything else is scheduled for the future
                 break;
             }
-            
-            // If the alarm is late, then print a warning message.
-            // Note that this can happen if the user creates a new event on
-            // the Calendar app with a reminder that is in the past. In that
-            // case, the reminder alarm will fire immediately.
-            if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
-                Slog.v(TAG, "alarm is late! alarm time: " + alarm.when
-                        + " now: " + now + " delay (in seconds): "
-                        + (now - alarm.when) / 1000);
-            }
 
-            // Recurring alarms may have passed several alarm intervals while the
-            // phone was asleep or off, so pass a trigger count when sending them.
-            if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm);
-            alarm.count = 1;
-            if (alarm.repeatInterval > 0) {
-                // this adjustment will be zero if we're late by
-                // less than one full repeat interval
-                alarm.count += (now - alarm.when) / alarm.repeatInterval;
-            }
-            triggerList.add(alarm);
-            
-            // remove the alarm from the list
-            it.remove();
-            
-            // if it repeats queue it up to be read-added to the list
-            if (alarm.repeatInterval > 0) {
-                repeats.add(alarm);
-            }
-        }
+            // We will (re)schedule some alarms now; don't let that interfere
+            // with delivery of this current batch
+            mAlarmBatches.remove(0);
 
-        // reset any repeating alarms.
-        it = repeats.iterator();
-        while (it.hasNext()) {
-            Alarm alarm = it.next();
-            alarm.when += alarm.count * alarm.repeatInterval;
-            addAlarmLocked(alarm);
-        }
-        
-        if (alarmList.size() > 0) {
-            setLocked(alarmList.get(0));
+            final int N = batch.size();
+            for (int i = 0; i < N; i++) {
+                Alarm alarm = batch.get(i);
+                alarm.count = 1;
+                triggerList.add(alarm);
+
+                // Recurring alarms may have passed several alarm intervals while the
+                // phone was asleep or off, so pass a trigger count when sending them.
+                if (alarm.repeatInterval > 0) {
+                    // this adjustment will be zero if we're late by
+                    // less than one full repeat interval
+                    alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
+
+                    // Also schedule its next recurrence
+                    final long delta = alarm.count * alarm.repeatInterval;
+                    final long nextElapsed = alarm.whenElapsed + delta;
+                    setImplLocked(alarm.type, alarm.when + delta, nextElapsed,
+                            maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
+                            alarm.repeatInterval, alarm.operation, batch.standalone, true,
+                            alarm.workSource);
+                }
+
+            }
         }
     }
-    
+
     /**
      * This Comparator sorts Alarms into increasing time order.
      */
@@ -744,15 +1077,23 @@
         public int type;
         public int count;
         public long when;
+        public long whenElapsed;    // 'when' in the elapsed time base
+        public long maxWhen;        // also in the elapsed time base
         public long repeatInterval;
         public PendingIntent operation;
+        public WorkSource workSource;
         
-        public Alarm() {
-            when = 0;
-            repeatInterval = 0;
-            operation = null;
+        public Alarm(int _type, long _when, long _whenElapsed, long _maxWhen,
+                long _interval, PendingIntent _op, WorkSource _ws) {
+            type = _type;
+            when = _when;
+            whenElapsed = _whenElapsed;
+            maxWhen = _maxWhen;
+            repeatInterval = _interval;
+            operation = _op;
+            workSource = _ws;
         }
-        
+
         @Override
         public String toString()
         {
@@ -769,13 +1110,33 @@
 
         public void dump(PrintWriter pw, String prefix, long now) {
             pw.print(prefix); pw.print("type="); pw.print(type);
+                    pw.print(" whenElapsed="); pw.print(whenElapsed);
                     pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
                     pw.print(" repeatInterval="); pw.print(repeatInterval);
                     pw.print(" count="); pw.println(count);
             pw.print(prefix); pw.print("operation="); pw.println(operation);
         }
     }
-    
+
+    void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
+        final int numBatches = batches.size();
+        for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
+            Batch b = batches.get(nextBatch);
+            if (b.start > nowELAPSED) {
+                break;
+            }
+
+            final int numAlarms = b.alarms.size();
+            for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
+                Alarm a = b.alarms.get(nextAlarm);
+                WakeupEvent e = new WakeupEvent(nowRTC,
+                        a.operation.getCreatorUid(),
+                        a.operation.getIntent().getAction());
+                mRecentWakeups.add(e);
+            }
+        }
+    }
+
     private class AlarmThread extends Thread
     {
         public AlarmThread()
@@ -785,14 +1146,20 @@
         
         public void run()
         {
+            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
+
             while (true)
             {
                 int result = waitForAlarm(mDescriptor);
-                
-                ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
-                
+
+                triggerList.clear();
+
                 if ((result & TIME_CHANGED_MASK) != 0) {
+                    if (DEBUG_BATCH) {
+                        Slog.v(TAG, "Time changed notification from kernel; rebatching");
+                    }
                     remove(mTimeTickSender);
+                    rebatchAllAlarms();
                     mClockReceiver.scheduleTimeTickEvent();
                     Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -807,22 +1174,28 @@
                         TAG, "Checking for alarms... rtc=" + nowRTC
                         + ", elapsed=" + nowELAPSED);
 
-                    if ((result & RTC_WAKEUP_MASK) != 0)
-                        triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
-                    
-                    if ((result & RTC_MASK) != 0)
-                        triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
-                    
-                    if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0)
-                        triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED);
-                    
-                    if ((result & ELAPSED_REALTIME_MASK) != 0)
-                        triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED);
-                    
-                    // now trigger the alarms
-                    Iterator<Alarm> it = triggerList.iterator();
-                    while (it.hasNext()) {
-                        Alarm alarm = it.next();
+                    if (WAKEUP_STATS) {
+                        if ((result & IS_WAKEUP_MASK) != 0) {
+                            long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
+                            int n = 0;
+                            for (WakeupEvent event : mRecentWakeups) {
+                                if (event.when > newEarliest) break;
+                                n++; // number of now-stale entries at the list head
+                            }
+                            for (int i = 0; i < n; i++) {
+                                mRecentWakeups.remove();
+                            }
+
+                            recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
+                        }
+                    }
+
+                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                    rescheduleKernelAlarmsLocked();
+
+                    // now deliver the alarm intents
+                    for (int i=0; i<triggerList.size(); i++) {
+                        Alarm alarm = triggerList.get(i);
                         try {
                             if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
                             alarm.operation.send(mContext, 0,
@@ -832,11 +1205,11 @@
                             
                             // we have an active broadcast so stay awake.
                             if (mBroadcastRefCount == 0) {
-                                setWakelockWorkSource(alarm.operation);
+                                setWakelockWorkSource(alarm.operation, alarm.workSource);
                                 mWakeLock.acquire();
                             }
                             final InFlight inflight = new InFlight(AlarmManagerService.this,
-                                    alarm.operation);
+                                    alarm.operation, alarm.workSource);
                             mInFlight.add(inflight);
                             mBroadcastRefCount++;
 
@@ -856,8 +1229,8 @@
                             } else {
                                 fs.nesting++;
                             }
-                            if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
-                                    || alarm.type == AlarmManager.RTC_WAKEUP) {
+                            if (alarm.type == ELAPSED_REALTIME_WAKEUP
+                                    || alarm.type == RTC_WAKEUP) {
                                 bs.numWakeup++;
                                 fs.numWakeup++;
                                 ActivityManagerNative.noteWakeupAlarm(
@@ -878,8 +1251,18 @@
         }
     }
 
-    void setWakelockWorkSource(PendingIntent pi) {
+    /**
+     * Attribute blame for a WakeLock.
+     * @param pi PendingIntent to attribute blame to if ws is null.
+     * @param ws WorkSource to attribute blame.
+     */
+    void setWakelockWorkSource(PendingIntent pi, WorkSource ws) {
         try {
+            if (ws != null) {
+                mWakeLock.setWorkSource(ws);
+                return;
+            }
+
             final int uid = ActivityManagerNative.getDefault()
                     .getUidForIntentSender(pi.getTarget());
             if (uid >= 0) {
@@ -906,17 +1289,13 @@
                 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
                 synchronized (mLock) {
                     final long nowRTC = System.currentTimeMillis();
-                    triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
-                    triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
-                    triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC);
-                    triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC);
+                    final long nowELAPSED = SystemClock.elapsedRealtime();
+                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
                 }
                 
                 // now trigger the alarms without the lock held
-                Iterator<Alarm> it = triggerList.iterator();
-                while (it.hasNext())
-                {
-                    Alarm alarm = it.next();
+                for (int i=0; i<triggerList.size(); i++) {
+                    Alarm alarm = triggerList.get(i);
                     try {
                         alarm.operation.send();
                     } catch (PendingIntent.CanceledException e) {
@@ -942,7 +1321,10 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
-            	scheduleTimeTickEvent();
+                if (DEBUG_BATCH) {
+                    Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
+                }
+                scheduleTimeTickEvent();
             } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
                 // Since the kernel does not keep track of DST, we need to
                 // reset the TZ information at the beginning of each day
@@ -951,7 +1333,7 @@
                 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
                 int gmtOffset = zone.getOffset(System.currentTimeMillis());
                 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
-            	scheduleDateChangedEvent();
+                scheduleDateChangedEvent();
             }
         }
         
@@ -963,10 +1345,11 @@
             // the top of the next minute.
             final long tickEventDelay = nextTime - currentTime;
 
-            set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
-                    mTimeTickSender);
+            final WorkSource workSource = null; // Let system take blame for time tick events.
+            set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+                    0, mTimeTickSender, true, workSource);
         }
-	
+
         public void scheduleDateChangedEvent() {
             Calendar calendar = Calendar.getInstance();
             calendar.setTimeInMillis(System.currentTimeMillis());
@@ -975,8 +1358,9 @@
             calendar.set(Calendar.SECOND, 0);
             calendar.set(Calendar.MILLISECOND, 0);
             calendar.add(Calendar.DAY_OF_MONTH, 1);
-      
-            set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
+
+            final WorkSource workSource = null; // Let system take blame for date change events.
+            set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
         }
     }
     
@@ -1092,7 +1476,8 @@
                 } else {
                     // the next of our alarms is now in flight.  reattribute the wakelock.
                     if (mInFlight.size() > 0) {
-                        setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
+                        InFlight inFlight = mInFlight.get(0);
+                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource);
                     } else {
                         // should never happen
                         mLog.w("Alarm wakelock still held but sent queue empty");
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 20ad636..a1a0d47 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -41,6 +41,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Log;
 import android.util.Pair;
@@ -99,6 +100,8 @@
     }
 
     public final static class Op {
+        public final int uid;
+        public final String packageName;
         public final int op;
         public int mode;
         public int duration;
@@ -106,18 +109,20 @@
         public long rejectTime;
         public int nesting;
 
-        public Op(int _op) {
+        public Op(int _uid, String _packageName, int _op) {
+            uid = _uid;
+            packageName = _packageName;
             op = _op;
-            mode = AppOpsManager.MODE_ALLOWED;
+            mode = AppOpsManager.opToDefaultMode(op);
         }
     }
 
     final SparseArray<ArrayList<Callback>> mOpModeWatchers
             = new SparseArray<ArrayList<Callback>>();
-    final HashMap<String, ArrayList<Callback>> mPackageModeWatchers
-            = new HashMap<String, ArrayList<Callback>>();
-    final HashMap<IBinder, Callback> mModeWatchers
-            = new HashMap<IBinder, Callback>();
+    final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
+            = new ArrayMap<String, ArrayList<Callback>>();
+    final ArrayMap<IBinder, Callback> mModeWatchers
+            = new ArrayMap<IBinder, Callback>();
 
     public final class Callback implements DeathRecipient {
         final IAppOpsCallback mCallback;
@@ -140,12 +145,53 @@
         }
     }
 
+    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
+
+    public final class ClientState extends Binder implements DeathRecipient {
+        final IBinder mAppToken;
+        final int mPid;
+        final ArrayList<Op> mStartedOps;
+
+        public ClientState(IBinder appToken) {
+            mAppToken = appToken;
+            mPid = Binder.getCallingPid();
+            if (appToken instanceof Binder) {
+                // For local clients, there is no reason to track them.
+                mStartedOps = null;
+            } else {
+                mStartedOps = new ArrayList<Op>();
+                try {
+                    mAppToken.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "ClientState{" +
+                    "mAppToken=" + mAppToken +
+                    ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
+                    '}';
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (AppOpsService.this) {
+                for (int i=mStartedOps.size()-1; i>=0; i--) {
+                    finishOperationLocked(mStartedOps.get(i));
+                }
+                mClients.remove(mAppToken);
+            }
+        }
+    }
+
     public AppOpsService(File storagePath) {
         mFile = new AtomicFile(storagePath);
         mHandler = new Handler();
         readState();
     }
-    
+
     public void publish(Context context) {
         mContext = context;
         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
@@ -333,7 +379,7 @@
                         }
                         repCbs.addAll(cbs);
                     }
-                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
                         // If going into the default mode, prune this op
                         // if there is nothing else interesting in it.
                         pruneOp(op, uid, packageName);
@@ -380,23 +426,34 @@
         HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
         synchronized (this) {
             boolean changed = false;
-            for (int i=0; i<mUidOps.size(); i++) {
+            for (int i=mUidOps.size()-1; i>=0; i--) {
                 HashMap<String, Ops> packages = mUidOps.valueAt(i);
-                for (Map.Entry<String, Ops> ent : packages.entrySet()) {
+                Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry<String, Ops> ent = it.next();
                     String packageName = ent.getKey();
                     Ops pkgOps = ent.getValue();
-                    for (int j=0; j<pkgOps.size(); j++) {
+                    for (int j=pkgOps.size()-1; j>=0; j--) {
                         Op curOp = pkgOps.valueAt(j);
-                        if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
-                            curOp.mode = AppOpsManager.MODE_ALLOWED;
+                        if (AppOpsManager.opAllowsReset(curOp.op)
+                                && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+                            curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
                             changed = true;
                             callbacks = addCallbacks(callbacks, packageName, curOp.op,
                                     mOpModeWatchers.get(curOp.op));
                             callbacks = addCallbacks(callbacks, packageName, curOp.op,
                                     mPackageModeWatchers.get(packageName));
-                            pruneOp(curOp, mUidOps.keyAt(i), packageName);
+                            if (curOp.time == 0 && curOp.rejectTime == 0) {
+                                pkgOps.removeAt(j);
+                            }
                         }
                     }
+                    if (pkgOps.size() == 0) {
+                        it.remove();
+                    }
+                }
+                if (packages.size() == 0) {
+                    mUidOps.removeAt(i);
                 }
             }
             if (changed) {
@@ -452,21 +509,18 @@
             Callback cb = mModeWatchers.remove(callback.asBinder());
             if (cb != null) {
                 cb.unlinkToDeath();
-                for (int i=0; i<mOpModeWatchers.size(); i++) {
+                for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
                     ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
                     cbs.remove(cb);
                     if (cbs.size() <= 0) {
                         mOpModeWatchers.removeAt(i);
                     }
                 }
-                if (mPackageModeWatchers.size() > 0) {
-                    Iterator<ArrayList<Callback>> it = mPackageModeWatchers.values().iterator();
-                    while (it.hasNext()) {
-                        ArrayList<Callback> cbs = it.next();
-                        cbs.remove(cb);
-                        if (cbs.size() <= 0) {
-                            it.remove();
-                        }
+                for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
+                    ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
+                    cbs.remove(cb);
+                    if (cbs.size() <= 0) {
+                        mPackageModeWatchers.removeAt(i);
                     }
                 }
             }
@@ -474,19 +528,42 @@
     }
 
     @Override
+    public IBinder getToken(IBinder clientToken) {
+        synchronized (this) {
+            ClientState cs = mClients.get(clientToken);
+            if (cs == null) {
+                cs = new ClientState(clientToken);
+                mClients.put(clientToken, cs);
+            }
+            return cs;
+        }
+    }
+
+    @Override
     public int checkOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         synchronized (this) {
             Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
             if (op == null) {
-                return AppOpsManager.MODE_ALLOWED;
+                return AppOpsManager.opToDefaultMode(code);
             }
             return op.mode;
         }
     }
 
     @Override
+    public int checkPackage(int uid, String packageName) {
+        synchronized (this) {
+            if (getOpsLocked(uid, packageName, true) != null) {
+                return AppOpsManager.MODE_ALLOWED;
+            } else {
+                return AppOpsManager.MODE_ERRORED;
+            }
+        }
+    }
+
+    @Override
     public int noteOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
@@ -495,7 +572,7 @@
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName);
-                return AppOpsManager.MODE_IGNORED;
+                return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
             if (op.duration == -1) {
@@ -520,15 +597,16 @@
     }
 
     @Override
-    public int startOperation(int code, int uid, String packageName) {
+    public int startOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
+        ClientState client = (ClientState)token;
         synchronized (this) {
             Ops ops = getOpsLocked(uid, packageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName);
-                return AppOpsManager.MODE_IGNORED;
+                return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -547,32 +625,46 @@
                 op.duration = -1;
             }
             op.nesting++;
+            if (client.mStartedOps != null) {
+                client.mStartedOps.add(op);
+            }
             return AppOpsManager.MODE_ALLOWED;
         }
     }
 
     @Override
-    public void finishOperation(int code, int uid, String packageName) {
+    public void finishOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
+        ClientState client = (ClientState)token;
         synchronized (this) {
             Op op = getOpLocked(code, uid, packageName, true);
             if (op == null) {
                 return;
             }
-            if (op.nesting <= 1) {
-                if (op.nesting == 1) {
-                    op.duration = (int)(System.currentTimeMillis() - op.time);
-                    op.time += op.duration;
-                } else {
-                    Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName
-                        + " code " + code + " time=" + op.time + " duration=" + op.duration
-                        + " nesting=" + op.nesting);
+            if (client.mStartedOps != null) {
+                if (!client.mStartedOps.remove(op)) {
+                    throw new IllegalStateException("Operation not started: uid" + op.uid
+                            + " pkg=" + op.packageName + " op=" + op.op);
                 }
-                op.nesting = 0;
-            } else {
-                op.nesting--;
             }
+            finishOperationLocked(op);
+        }
+    }
+
+    void finishOperationLocked(Op op) {
+        if (op.nesting <= 1) {
+            if (op.nesting == 1) {
+                op.duration = (int)(System.currentTimeMillis() - op.time);
+                op.time += op.duration;
+            } else {
+                Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
+                        + op.packageName + " code " + op.op + " time=" + op.time
+                        + " duration=" + op.duration + " nesting=" + op.nesting);
+            }
+            op.nesting = 0;
+        } else {
+            op.nesting--;
         }
     }
 
@@ -623,6 +715,9 @@
                         pkgUid = mContext.getPackageManager().getPackageUid(packageName,
                                 UserHandle.getUserId(uid));
                     } catch (NameNotFoundException e) {
+                        if ("media".equals(packageName)) {
+                            pkgUid = Process.MEDIA_UID;
+                        }
                     }
                     if (pkgUid != uid) {
                         // Oops!  The package name is not valid for the uid they are calling
@@ -670,7 +765,7 @@
             if (!edit) {
                 return null;
             }
-            op = new Op(code);
+            op = new Op(ops.uid, ops.packageName, code);
             ops.put(code, op);
         }
         if (edit) {
@@ -780,7 +875,7 @@
 
             String tagName = parser.getName();
             if (tagName.equals("op")) {
-                Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n")));
+                Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
                 String mode = parser.getAttributeValue(null, "m");
                 if (mode != null) {
                     op.mode = Integer.parseInt(mode);
@@ -853,7 +948,7 @@
                             AppOpsManager.OpEntry op = ops.get(j);
                             out.startTag(null, "op");
                             out.attribute(null, "n", Integer.toString(op.getOp()));
-                            if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
+                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
                                 out.attribute(null, "m", Integer.toString(op.getMode()));
                             }
                             long time = op.getTime();
@@ -900,6 +995,62 @@
         synchronized (this) {
             pw.println("Current AppOps Service state:");
             final long now = System.currentTimeMillis();
+            boolean needSep = false;
+            if (mOpModeWatchers.size() > 0) {
+                needSep = true;
+                pw.println("  Op mode watchers:");
+                for (int i=0; i<mOpModeWatchers.size(); i++) {
+                    pw.print("    Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
+                    pw.println(":");
+                    ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
+                    for (int j=0; j<callbacks.size(); j++) {
+                        pw.print("      #"); pw.print(j); pw.print(": ");
+                        pw.println(callbacks.get(j));
+                    }
+                }
+            }
+            if (mPackageModeWatchers.size() > 0) {
+                needSep = true;
+                pw.println("  Package mode watchers:");
+                for (int i=0; i<mPackageModeWatchers.size(); i++) {
+                    pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
+                    pw.println(":");
+                    ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
+                    for (int j=0; j<callbacks.size(); j++) {
+                        pw.print("      #"); pw.print(j); pw.print(": ");
+                        pw.println(callbacks.get(j));
+                    }
+                }
+            }
+            if (mModeWatchers.size() > 0) {
+                needSep = true;
+                pw.println("  All mode watchers:");
+                for (int i=0; i<mModeWatchers.size(); i++) {
+                    pw.print("    "); pw.print(mModeWatchers.keyAt(i));
+                    pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
+                }
+            }
+            if (mClients.size() > 0) {
+                needSep = true;
+                pw.println("  Clients:");
+                for (int i=0; i<mClients.size(); i++) {
+                    pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
+                    ClientState cs = mClients.valueAt(i);
+                    pw.print("      "); pw.println(cs);
+                    if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
+                        pw.println("      Started ops:");
+                        for (int j=0; j<cs.mStartedOps.size(); j++) {
+                            Op op = cs.mStartedOps.get(j);
+                            pw.print("        "); pw.print("uid="); pw.print(op.uid);
+                            pw.print(" pkg="); pw.print(op.packageName);
+                            pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
+                        }
+                    }
+                }
+            }
+            if (needSep) {
+                pw.println();
+            }
             for (int i=0; i<mUidOps.size(); i++) {
                 pw.print("  Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":");
                 HashMap<String, Ops> pkgOps = mUidOps.valueAt(i);
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index d5715a5..203cca6 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -27,7 +27,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -37,6 +36,7 @@
 
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
@@ -63,16 +63,14 @@
     AppWidgetService(Context context) {
         mContext = context;
 
-        HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state");
-        handlerThread.start();
-        mSaveStateHandler = new Handler(handlerThread.getLooper());
+        mSaveStateHandler = BackgroundThread.getHandler();
 
         mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
         AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
         mAppWidgetServices.append(0, primary);
     }
 
-    public void systemReady(boolean safeMode) {
+    public void systemRunning(boolean safeMode) {
         mSafeMode = safeMode;
 
         mAppWidgetServices.get(0).systemReady(safeMode);
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index fb2828b..69ae846 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -86,9 +86,12 @@
 
 class AppWidgetServiceImpl {
 
+    private static final String KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
+    private static final int KEYGUARD_HOST_ID = 0x4b455947;
     private static final String TAG = "AppWidgetServiceImpl";
     private static final String SETTINGS_FILENAME = "appwidgets.xml";
     private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
+    private static final int CURRENT_VERSION = 1; // Bump if the stored widgets need to be upgraded.
 
     private static boolean DBG = false;
 
@@ -1654,7 +1657,7 @@
             out.setOutput(stream, "utf-8");
             out.startDocument(null, true);
             out.startTag(null, "gs");
-
+            out.attribute(null, "version", String.valueOf(CURRENT_VERSION));
             int providerIndex = 0;
             N = mInstalledProviders.size();
             for (int i = 0; i < N; i++) {
@@ -1723,6 +1726,7 @@
     @SuppressWarnings("unused")
     void readStateFromFileLocked(FileInputStream stream) {
         boolean success = false;
+        int version = 0;
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(stream, null);
@@ -1734,7 +1738,14 @@
                 type = parser.next();
                 if (type == XmlPullParser.START_TAG) {
                     String tag = parser.getName();
-                    if ("p".equals(tag)) {
+                    if ("gs".equals(tag)) {
+                        String attributeValue = parser.getAttributeValue(null, "version");
+                        try {
+                            version = Integer.parseInt(attributeValue);
+                        } catch (NumberFormatException e) {
+                            version = 0;
+                        }
+                    } else if ("p".equals(tag)) {
                         // TODO: do we need to check that this package has the same signature
                         // as before?
                         String pkg = parser.getAttributeValue(null, "pkg");
@@ -1873,6 +1884,8 @@
             for (int i = mHosts.size() - 1; i >= 0; i--) {
                 pruneHostLocked(mHosts.get(i));
             }
+            // upgrade the database if needed
+            performUpgrade(version);
         } else {
             // failed reading, clean up
             Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
@@ -1886,6 +1899,31 @@
         }
     }
 
+    private void performUpgrade(int fromVersion) {
+        if (fromVersion < CURRENT_VERSION) {
+            Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to " + CURRENT_VERSION
+                    + " for user " + mUserId);
+        }
+
+        int version = fromVersion;
+
+        // Update 1: keyguard moved from package "android" to "com.android.keyguard"
+        if (version == 0) {
+            for (int i = 0; i < mHosts.size(); i++) {
+                Host host = mHosts.get(i);
+                if (host != null && "android".equals(host.packageName)
+                        && host.hostId == KEYGUARD_HOST_ID) {
+                    host.packageName = KEYGUARD_HOST_PACKAGE;
+                }
+            }
+            version = 1;
+        }
+
+        if (version != CURRENT_VERSION) {
+            throw new IllegalStateException("Failed to upgrade widget database");
+        }
+    }
+
     static File getSettingsFile(int userId) {
         return new File(Environment.getUserSystemDirectory(userId), SETTINGS_FILENAME);
     }
diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/java/com/android/server/AssetAtlasService.java
new file mode 100644
index 0000000..26b4652
--- /dev/null
+++ b/services/java/com/android/server/AssetAtlasService.java
@@ -0,0 +1,735 @@
+/*
+ * 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.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Atlas;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.drawable.Drawable;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.view.GraphicBuffer;
+import android.view.IAssetAtlas;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This service is responsible for packing preloaded bitmaps into a single
+ * atlas texture. The resulting texture can be shared across processes to
+ * reduce overall memory usage.
+ *
+ * @hide
+ */
+public class AssetAtlasService extends IAssetAtlas.Stub {
+    /**
+     * Name of the <code>AssetAtlasService</code>.
+     */
+    public static final String ASSET_ATLAS_SERVICE = "assetatlas";
+
+    private static final String LOG_TAG = "Atlas";
+
+    // Turns debug logs on/off. Debug logs are kept to a minimum and should
+    // remain on to diagnose issues
+    private static final boolean DEBUG_ATLAS = true;
+
+    // When set to true the content of the atlas will be saved to disk
+    // in /data/system/atlas.png. The shared GraphicBuffer may be empty
+    private static final boolean DEBUG_ATLAS_TEXTURE = false;
+
+    // Minimum size in pixels to consider for the resulting texture
+    private static final int MIN_SIZE = 768;
+    // Maximum size in pixels to consider for the resulting texture
+    private static final int MAX_SIZE = 2048;
+    // Increment in number of pixels between size variants when looking
+    // for the best texture dimensions
+    private static final int STEP = 64;
+
+    // This percentage of the total number of pixels represents the minimum
+    // number of pixels we want to be able to pack in the atlas
+    private static final float PACKING_THRESHOLD = 0.8f;
+
+    // Defines the number of int fields used to represent a single entry
+    // in the atlas map. This number defines the size of the array returned
+    // by the getMap(). See the mAtlasMap field for more information
+    private static final int ATLAS_MAP_ENTRY_FIELD_COUNT = 4;
+
+    // Specifies how our GraphicBuffer will be used. To get proper swizzling
+    // the buffer will be written to using OpenGL (from JNI) so we can leave
+    // the software flag set to "never"
+    private static final int GRAPHIC_BUFFER_USAGE = GraphicBuffer.USAGE_SW_READ_NEVER |
+            GraphicBuffer.USAGE_SW_WRITE_NEVER | GraphicBuffer.USAGE_HW_TEXTURE;
+
+    // This boolean is set to true if an atlas was successfully
+    // computed and rendered
+    private final AtomicBoolean mAtlasReady = new AtomicBoolean(false);
+
+    private final Context mContext;
+
+    // Version name of the current build, used to identify changes to assets list
+    private final String mVersionName;
+
+    // Holds the atlas' data. This buffer can be mapped to
+    // OpenGL using an EGLImage
+    private GraphicBuffer mBuffer;
+
+    // Describes how bitmaps are placed in the atlas. Each bitmap is
+    // represented by several entries in the array:
+    // int0: SkBitmap*, the native bitmap object
+    // int1: x position
+    // int2: y position
+    // int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+    // NOTE: This will need to be handled differently to support 64 bit pointers
+    private int[] mAtlasMap;
+
+    /**
+     * Creates a new service. Upon creating, the service will gather the list of
+     * assets to consider for packing into the atlas and spawn a new thread to
+     * start the packing work.
+     *
+     * @param context The context giving access to preloaded resources
+     */
+    public AssetAtlasService(Context context) {
+        mContext = context;
+        mVersionName = queryVersionName(context);
+
+        ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>(300);
+        int totalPixelCount = 0;
+
+        // 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) {
+                bitmaps.add(bitmap);
+                totalPixelCount += bitmap.getWidth() * bitmap.getHeight();
+            }
+        }
+
+        // Our algorithms perform better when the bitmaps are first sorted
+        // The comparator will sort the bitmap by width first, then by height
+        Collections.sort(bitmaps, new Comparator<Bitmap>() {
+            @Override
+            public int compare(Bitmap b1, Bitmap b2) {
+                if (b1.getWidth() == b2.getWidth()) {
+                    return b2.getHeight() - b1.getHeight();
+                }
+                return b2.getWidth() - b1.getWidth();
+            }
+        });
+
+        // Kick off the packing work on a worker thread
+        new Thread(new Renderer(bitmaps, totalPixelCount)).start();
+    }
+
+    /**
+     * Queries the version name stored in framework's AndroidManifest.
+     * The version name can be used to identify possible changes to
+     * framework resources.
+     *
+     * @see #getBuildIdentifier(String)
+     */
+    private static String queryVersionName(Context context) {
+        try {
+            String packageName = context.getPackageName();
+            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+            return info.versionName;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(LOG_TAG, "Could not get package info", e);
+        }
+        return null;
+    }
+
+    /**
+     * Callback invoked by the server thread to indicate we can now run
+     * 3rd party code.
+     */
+    public void systemRunning() {
+    }
+
+    /**
+     * The renderer does all the work:
+     */
+    private class Renderer implements Runnable {
+        private final ArrayList<Bitmap> mBitmaps;
+        private final int mPixelCount;
+
+        private int mNativeBitmap;
+
+        // Used for debugging only
+        private Bitmap mAtlasBitmap;
+
+        Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) {
+            mBitmaps = bitmaps;
+            mPixelCount = pixelCount;
+        }
+
+        /**
+         * 1. On first boot or after every update, brute-force through all the
+         *    possible atlas configurations and look for the best one (maximimize
+         *    number of packed assets and minimize texture size)
+         *    a. If a best configuration was computed, write it out to disk for
+         *       future use
+         * 2. Read best configuration from disk
+         * 3. Compute the packing using the best configuration
+         * 4. Allocate a GraphicBuffer
+         * 5. Render assets in the buffer
+         */
+        @Override
+        public void run() {
+            Configuration config = chooseConfiguration(mBitmaps, mPixelCount, mVersionName);
+            if (DEBUG_ATLAS) Log.d(LOG_TAG, "Loaded configuration: " + config);
+
+            if (config != null) {
+                mBuffer = GraphicBuffer.create(config.width, config.height,
+                        PixelFormat.RGBA_8888, GRAPHIC_BUFFER_USAGE);
+
+                if (mBuffer != null) {
+                    Atlas atlas = new Atlas(config.type, config.width, config.height, config.flags);
+                    if (renderAtlas(mBuffer, atlas, config.count)) {
+                        mAtlasReady.set(true);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Renders a list of bitmaps into the atlas. The position of each bitmap
+         * was decided by the packing algorithm and will be honored by this
+         * method. If need be this method will also rotate bitmaps.
+         *
+         * @param buffer The buffer to render the atlas entries into
+         * @param atlas The atlas to pack the bitmaps into
+         * @param packCount The number of bitmaps that will be packed in the atlas
+         *
+         * @return true if the atlas was rendered, false otherwise
+         */
+        @SuppressWarnings("MismatchedReadAndWriteOfArray")
+        private boolean renderAtlas(GraphicBuffer buffer, Atlas atlas, int packCount) {
+            // Use a Source blend mode to improve performance, the target bitmap
+            // will be zero'd out so there's no need to waste time applying blending
+            final Paint paint = new Paint();
+            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+
+            // We always render the atlas into a bitmap. This bitmap is then
+            // uploaded into the GraphicBuffer using OpenGL to swizzle the content
+            final Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight());
+            if (canvas == null) return false;
+
+            final Atlas.Entry entry = new Atlas.Entry();
+
+            mAtlasMap = new int[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
+            int[] atlasMap = mAtlasMap;
+            int mapIndex = 0;
+
+            boolean result = false;
+            try {
+                final long startRender = System.nanoTime();
+                final int count = mBitmaps.size();
+
+                for (int i = 0; i < count; i++) {
+                    final Bitmap bitmap = mBitmaps.get(i);
+                    if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
+                        // We have more bitmaps to pack than the current configuration
+                        // says, we were most likely not able to detect a change in the
+                        // list of preloaded drawables, abort and delete the configuration
+                        if (mapIndex >= mAtlasMap.length) {
+                            deleteDataFile();
+                            break;
+                        }
+
+                        canvas.save();
+                        canvas.translate(entry.x, entry.y);
+                        if (entry.rotated) {
+                            canvas.translate(bitmap.getHeight(), 0.0f);
+                            canvas.rotate(90.0f);
+                        }
+                        canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
+                        canvas.restore();
+
+                        atlasMap[mapIndex++] = bitmap.mNativeBitmap;
+                        atlasMap[mapIndex++] = entry.x;
+                        atlasMap[mapIndex++] = entry.y;
+                        atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
+                    }
+                }
+
+                final long endRender = System.nanoTime();
+                if (mNativeBitmap != 0) {
+                    result = nUploadAtlas(buffer, mNativeBitmap);
+                }
+
+                final long endUpload = System.nanoTime();
+                if (DEBUG_ATLAS) {
+                    float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
+                    float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
+                    Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
+                            renderDuration + uploadDuration, renderDuration, uploadDuration));
+                }
+
+            } finally {
+                releaseCanvas(canvas);
+            }
+
+            return result;
+        }
+
+        /**
+         * Returns a Canvas for the specified buffer. If {@link #DEBUG_ATLAS_TEXTURE}
+         * is turned on, the returned Canvas will render into a local bitmap that
+         * will then be saved out to disk for debugging purposes.
+         * @param width
+         * @param height
+         */
+        private Canvas acquireCanvas(int width, int height) {
+            if (DEBUG_ATLAS_TEXTURE) {
+                mAtlasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+                return new Canvas(mAtlasBitmap);
+            } else {
+                Canvas canvas = new Canvas();
+                mNativeBitmap = nAcquireAtlasCanvas(canvas, width, height);
+                return canvas;
+            }
+        }
+
+        /**
+         * Releases the canvas used to render into the buffer. Calling this method
+         * will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE}
+         * is turend on, calling this method will write the content of the atlas
+         * to disk in /data/system/atlas.png for debugging.
+         */
+        private void releaseCanvas(Canvas canvas) {
+            if (DEBUG_ATLAS_TEXTURE) {
+                canvas.setBitmap(null);
+
+                File systemDirectory = new File(Environment.getDataDirectory(), "system");
+                File dataFile = new File(systemDirectory, "atlas.png");
+
+                try {
+                    FileOutputStream out = new FileOutputStream(dataFile);
+                    mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+                    out.close();
+                } catch (FileNotFoundException e) {
+                    // Ignore
+                } catch (IOException e) {
+                    // Ignore
+                }
+
+                mAtlasBitmap.recycle();
+                mAtlasBitmap = null;
+            } else {
+                nReleaseAtlasCanvas(canvas, mNativeBitmap);
+            }
+        }
+    }
+
+    private static native int nAcquireAtlasCanvas(Canvas canvas, int width, int height);
+    private static native void nReleaseAtlasCanvas(Canvas canvas, int bitmap);
+    private static native boolean nUploadAtlas(GraphicBuffer buffer, int bitmap);
+
+    @Override
+    public boolean isCompatible(int ppid) {
+        return ppid == android.os.Process.myPpid();
+    }
+
+    @Override
+    public GraphicBuffer getBuffer() throws RemoteException {
+        return mAtlasReady.get() ? mBuffer : null;
+    }
+
+    @Override
+    public int[] getMap() throws RemoteException {
+        return mAtlasReady.get() ? mAtlasMap : null;
+    }
+
+    /**
+     * Finds the best atlas configuration to pack the list of supplied bitmaps.
+     * This method takes advantage of multi-core systems by spawning a number
+     * of threads equal to the number of available cores.
+     */
+    private static Configuration computeBestConfiguration(
+            ArrayList<Bitmap> bitmaps, int pixelCount) {
+        if (DEBUG_ATLAS) Log.d(LOG_TAG, "Computing best atlas configuration...");
+
+        long begin = System.nanoTime();
+        List<WorkerResult> results = Collections.synchronizedList(new ArrayList<WorkerResult>());
+
+        // Don't bother with an extra thread if there's only one processor
+        int cpuCount = Runtime.getRuntime().availableProcessors();
+        if (cpuCount == 1) {
+            new ComputeWorker(MIN_SIZE, MAX_SIZE, STEP, bitmaps, pixelCount, results, null).run();
+        } else {
+            int start = MIN_SIZE;
+            int end = MAX_SIZE - (cpuCount - 1) * STEP;
+            int step = STEP * cpuCount;
+
+            final CountDownLatch signal = new CountDownLatch(cpuCount);
+
+            for (int i = 0; i < cpuCount; i++, start += STEP, end += STEP) {
+                ComputeWorker worker = new ComputeWorker(start, end, step,
+                        bitmaps, pixelCount, results, signal);
+                new Thread(worker, "Atlas Worker #" + (i + 1)).start();
+            }
+
+            try {
+                signal.await(10, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                Log.w(LOG_TAG, "Could not complete configuration computation");
+                return null;
+            }
+        }
+
+        // Maximize the number of packed bitmaps, minimize the texture size
+        Collections.sort(results, new Comparator<WorkerResult>() {
+            @Override
+            public int compare(WorkerResult r1, WorkerResult r2) {
+                int delta = r2.count - r1.count;
+                if (delta != 0) return delta;
+                return r1.width * r1.height - r2.width * r2.height;
+            }
+        });
+
+        if (DEBUG_ATLAS) {
+            float delay = (System.nanoTime() - begin) / 1000.0f / 1000.0f / 1000.0f;
+            Log.d(LOG_TAG, String.format("Found best atlas configuration in %.2fs", delay));
+        }
+
+        WorkerResult result = results.get(0);
+        return new Configuration(result.type, result.width, result.height, result.count);
+    }
+
+    /**
+     * Returns the path to the file containing the best computed
+     * atlas configuration.
+     */
+    private static File getDataFile() {
+        File systemDirectory = new File(Environment.getDataDirectory(), "system");
+        return new File(systemDirectory, "framework_atlas.config");
+    }
+
+    private static void deleteDataFile() {
+        Log.w(LOG_TAG, "Current configuration inconsistent with assets list");
+        if (!getDataFile().delete()) {
+            Log.w(LOG_TAG, "Could not delete the current configuration");
+        }
+    }
+
+    private File getFrameworkResourcesFile() {
+        return new File(mContext.getApplicationInfo().sourceDir);
+    }
+
+    /**
+     * Returns the best known atlas configuration. This method will either
+     * read the configuration from disk or start a brute-force search
+     * and save the result out to disk.
+     */
+    private Configuration chooseConfiguration(ArrayList<Bitmap> bitmaps, int pixelCount,
+            String versionName) {
+        Configuration config = null;
+
+        final File dataFile = getDataFile();
+        if (dataFile.exists()) {
+            config = readConfiguration(dataFile, versionName);
+        }
+
+        if (config == null) {
+            config = computeBestConfiguration(bitmaps, pixelCount);
+            if (config != null) writeConfiguration(config, dataFile, versionName);
+        }
+
+        return config;
+    }
+
+    /**
+     * Writes the specified atlas configuration to the specified file.
+     */
+    private void writeConfiguration(Configuration config, File file, String versionName) {
+        BufferedWriter writer = null;
+        try {
+            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
+            writer.write(getBuildIdentifier(versionName));
+            writer.newLine();
+            writer.write(config.type.toString());
+            writer.newLine();
+            writer.write(String.valueOf(config.width));
+            writer.newLine();
+            writer.write(String.valueOf(config.height));
+            writer.newLine();
+            writer.write(String.valueOf(config.count));
+            writer.newLine();
+            writer.write(String.valueOf(config.flags));
+            writer.newLine();
+        } catch (FileNotFoundException e) {
+            Log.w(LOG_TAG, "Could not write " + file, e);
+        } catch (IOException e) {
+            Log.w(LOG_TAG, "Could not write " + file, e);
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads an atlas configuration from the specified file. This method
+     * returns null if an error occurs or if the configuration is invalid.
+     */
+    private Configuration readConfiguration(File file, String versionName) {
+        BufferedReader reader = null;
+        Configuration config = null;
+        try {
+            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+
+            if (checkBuildIdentifier(reader, versionName)) {
+                Atlas.Type type = Atlas.Type.valueOf(reader.readLine());
+                int width = readInt(reader, MIN_SIZE, MAX_SIZE);
+                int height = readInt(reader, MIN_SIZE, MAX_SIZE);
+                int count = readInt(reader, 0, Integer.MAX_VALUE);
+                int flags = readInt(reader, Integer.MIN_VALUE, Integer.MAX_VALUE);
+
+                config = new Configuration(type, width, height, count, flags);
+            }
+        } catch (IllegalArgumentException e) {
+            Log.w(LOG_TAG, "Invalid parameter value in " + file, e);
+        } catch (FileNotFoundException e) {
+            Log.w(LOG_TAG, "Could not read " + file, e);
+        } catch (IOException e) {
+            Log.w(LOG_TAG, "Could not read " + file, e);
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+        return config;
+    }
+
+    private static int readInt(BufferedReader reader, int min, int max) throws IOException {
+        return Math.max(min, Math.min(max, Integer.parseInt(reader.readLine())));
+    }
+
+    /**
+     * Compares the next line in the specified buffered reader to the current
+     * build identifier. Returns whether the two values are equal.
+     *
+     * @see #getBuildIdentifier(String)
+     */
+    private boolean checkBuildIdentifier(BufferedReader reader, String versionName)
+            throws IOException {
+        String deviceBuildId = getBuildIdentifier(versionName);
+        String buildId = reader.readLine();
+        return deviceBuildId.equals(buildId);
+    }
+
+    /**
+     * Returns an identifier for the current build that can be used to detect
+     * likely changes to framework resources. The build identifier is made of
+     * several distinct values:
+     *
+     * build fingerprint/framework version name/file size of framework resources apk
+     *
+     * Only the build fingerprint should be necessary on user builds but
+     * the other values are useful to detect changes on eng builds during
+     * development.
+     *
+     * This identifier does not attempt to be exact: a new identifier does not
+     * necessarily mean the preloaded drawables have changed. It is important
+     * however that whenever the list of preloaded drawables changes, this
+     * identifier changes as well.
+     *
+     * @see #checkBuildIdentifier(java.io.BufferedReader, String)
+     */
+    private String getBuildIdentifier(String versionName) {
+        return SystemProperties.get("ro.build.fingerprint", "") + '/' + versionName + '/' +
+                String.valueOf(getFrameworkResourcesFile().length());
+    }
+
+    /**
+     * Atlas configuration. Specifies the algorithm, dimensions and flags to use.
+     */
+    private static class Configuration {
+        final Atlas.Type type;
+        final int width;
+        final int height;
+        final int count;
+        final int flags;
+
+        Configuration(Atlas.Type type, int width, int height, int count) {
+            this(type, width, height, count, Atlas.FLAG_DEFAULTS);
+        }
+
+        Configuration(Atlas.Type type, int width, int height, int count, int flags) {
+            this.type = type;
+            this.width = width;
+            this.height = height;
+            this.count = count;
+            this.flags = flags;
+        }
+
+        @Override
+        public String toString() {
+            return type.toString() + " (" + width + "x" + height + ") flags=0x" +
+                    Integer.toHexString(flags) + " count=" + count;
+        }
+    }
+
+    /**
+     * Used during the brute-force search to gather information about each
+     * variant of the packing algorithm.
+     */
+    private static class WorkerResult {
+        Atlas.Type type;
+        int width;
+        int height;
+        int count;
+
+        WorkerResult(Atlas.Type type, int width, int height, int count) {
+            this.type = type;
+            this.width = width;
+            this.height = height;
+            this.count = count;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s %dx%d", type.toString(), width, height);
+        }
+    }
+
+    /**
+     * A compute worker will try a finite number of variations of the packing
+     * algorithms and save the results in a supplied list.
+     */
+    private static class ComputeWorker implements Runnable {
+        private final int mStart;
+        private final int mEnd;
+        private final int mStep;
+        private final List<Bitmap> mBitmaps;
+        private final List<WorkerResult> mResults;
+        private final CountDownLatch mSignal;
+        private final int mThreshold;
+
+        /**
+         * Creates a new compute worker to brute-force through a range of
+         * packing algorithms variants.
+         *
+         * @param start The minimum texture width to try
+         * @param end The maximum texture width to try
+         * @param step The number of pixels to increment the texture width by at each step
+         * @param bitmaps The list of bitmaps to pack in the atlas
+         * @param pixelCount The total number of pixels occupied by the list of bitmaps
+         * @param results The list of results in which to save the brute-force search results
+         * @param signal Latch to decrement when this worker is done, may be null
+         */
+        ComputeWorker(int start, int end, int step, List<Bitmap> bitmaps, int pixelCount,
+                List<WorkerResult> results, CountDownLatch signal) {
+            mStart = start;
+            mEnd = end;
+            mStep = step;
+            mBitmaps = bitmaps;
+            mResults = results;
+            mSignal = signal;
+
+            // Minimum number of pixels we want to be able to pack
+            int threshold = (int) (pixelCount * PACKING_THRESHOLD);
+            // Make sure we can find at least one configuration
+            while (threshold > MAX_SIZE * MAX_SIZE) {
+                threshold >>= 1;
+            }
+            mThreshold = threshold;
+        }
+
+        @Override
+        public void run() {
+            if (DEBUG_ATLAS) Log.d(LOG_TAG, "Running " + Thread.currentThread().getName());
+
+            Atlas.Entry entry = new Atlas.Entry();
+            for (Atlas.Type type : Atlas.Type.values()) {
+                for (int width = mStart; width < mEnd; width += mStep) {
+                    for (int height = MIN_SIZE; height < MAX_SIZE; height += STEP) {
+                        // If the atlas is not big enough, skip it
+                        if (width * height <= mThreshold) continue;
+
+                        final int count = packBitmaps(type, width, height, entry);
+                        if (count > 0) {
+                            mResults.add(new WorkerResult(type, width, height, count));
+                            // If we were able to pack everything let's stop here
+                            // Increasing the height further won't make things better
+                            if (count == mBitmaps.size()) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (mSignal != null) {
+                mSignal.countDown();
+            }
+        }
+
+        private int packBitmaps(Atlas.Type type, int width, int height, Atlas.Entry entry) {
+            int total = 0;
+            Atlas atlas = new Atlas(type, width, height);
+
+            final int count = mBitmaps.size();
+            for (int i = 0; i < count; i++) {
+                final Bitmap bitmap = mBitmaps.get(i);
+                if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
+                    total++;
+                }
+            }
+
+            return total;
+        }
+    }
+}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a537e99..a04ee14 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1305,9 +1305,6 @@
                 mTransports.put(name, transport);
             } else {
                 mTransports.remove(name);
-                if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) {
-                    mCurrentTransport = null;
-                }
                 // Nothing further to do in the unregistration case
                 return;
             }
@@ -1995,6 +1992,15 @@
                     return;
                 }
 
+                if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+                    // The app has been force-stopped or cleared or just installed,
+                    // and not yet launched out of that state, so just as it won't
+                    // receive broadcasts, we won't run it for backup.
+                    addBackupTrace("skipping - stopped");
+                    executeNextState(BackupState.RUNNING_QUEUE);
+                    return;
+                }
+
                 IBackupAgent agent = null;
                 try {
                     mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
@@ -2877,7 +2883,7 @@
             // Save associated .obb content if it exists and we did save the apk
             // check for .obb and save those too
             final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
-            final File obbDir = userEnv.getExternalStorageAppObbDirectory(pkg.packageName);
+            final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
             if (obbDir != null) {
                 if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
                 File[] obbFiles = obbDir.listFiles();
@@ -5358,47 +5364,53 @@
     }
 
     // Enable/disable the backup service
+    @Override
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupEnabled");
 
         Slog.i(TAG, "Backup enabled => " + enable);
 
-        boolean wasEnabled = mEnabled;
-        synchronized (this) {
-            Settings.Secure.putInt(mContext.getContentResolver(),
-                    Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
-            mEnabled = enable;
-        }
+        long oldId = Binder.clearCallingIdentity();
+        try {
+            boolean wasEnabled = mEnabled;
+            synchronized (this) {
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
+                mEnabled = enable;
+            }
 
-        synchronized (mQueueLock) {
-            if (enable && !wasEnabled && mProvisioned) {
-                // if we've just been enabled, start scheduling backup passes
-                startBackupAlarmsLocked(BACKUP_INTERVAL);
-            } else if (!enable) {
-                // No longer enabled, so stop running backups
-                if (DEBUG) Slog.i(TAG, "Opting out of backup");
+            synchronized (mQueueLock) {
+                if (enable && !wasEnabled && mProvisioned) {
+                    // if we've just been enabled, start scheduling backup passes
+                    startBackupAlarmsLocked(BACKUP_INTERVAL);
+                } else if (!enable) {
+                    // No longer enabled, so stop running backups
+                    if (DEBUG) Slog.i(TAG, "Opting out of backup");
 
-                mAlarmManager.cancel(mRunBackupIntent);
+                    mAlarmManager.cancel(mRunBackupIntent);
 
-                // This also constitutes an opt-out, so we wipe any data for
-                // this device from the backend.  We start that process with
-                // an alarm in order to guarantee wakelock states.
-                if (wasEnabled && mProvisioned) {
-                    // NOTE: we currently flush every registered transport, not just
-                    // the currently-active one.
-                    HashSet<String> allTransports;
-                    synchronized (mTransports) {
-                        allTransports = new HashSet<String>(mTransports.keySet());
+                    // This also constitutes an opt-out, so we wipe any data for
+                    // this device from the backend.  We start that process with
+                    // an alarm in order to guarantee wakelock states.
+                    if (wasEnabled && mProvisioned) {
+                        // NOTE: we currently flush every registered transport, not just
+                        // the currently-active one.
+                        HashSet<String> allTransports;
+                        synchronized (mTransports) {
+                            allTransports = new HashSet<String>(mTransports.keySet());
+                        }
+                        // build the set of transports for which we are posting an init
+                        for (String transport : allTransports) {
+                            recordInitPendingLocked(true, transport);
+                        }
+                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
+                                mRunInitIntent);
                     }
-                    // build the set of transports for which we are posting an init
-                    for (String transport : allTransports) {
-                        recordInitPendingLocked(true, transport);
-                    }
-                    mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
-                            mRunInitIntent);
                 }
             }
+        } finally {
+            Binder.restoreCallingIdentity(oldId);
         }
     }
 
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 1f2947d..5f3f894 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.os.BatteryStats;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.am.BatteryStatsService;
 
@@ -25,9 +26,12 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.BatteryManager;
+import android.os.BatteryProperties;
 import android.os.Binder;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.IBatteryPropertiesListener;
+import android.os.IBatteryPropertiesRegistrar;
 import android.os.IBinder;
 import android.os.DropBoxManager;
 import android.os.RemoteException;
@@ -88,8 +92,7 @@
     private int mCriticalBatteryLevel;
 
     private static final int DUMP_MAX_LENGTH = 24 * 1024;
-    private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "-u" };
-    private static final String BATTERY_STATS_SERVICE_NAME = "batteryinfo";
+    private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
 
     private static final String DUMPSYS_DATA_PATH = "/data/system/";
 
@@ -102,20 +105,8 @@
 
     private final Object mLock = new Object();
 
-    /* Begin native fields: All of these fields are set by native code. */
-    private boolean mAcOnline;
-    private boolean mUsbOnline;
-    private boolean mWirelessOnline;
-    private int mBatteryStatus;
-    private int mBatteryHealth;
-    private boolean mBatteryPresent;
-    private int mBatteryLevel;
-    private int mBatteryVoltage;
-    private int mBatteryTemperature;
-    private String mBatteryTechnology;
+    private BatteryProperties mBatteryProps;
     private boolean mBatteryLevelCritical;
-    /* End native fields. */
-
     private int mLastBatteryStatus;
     private int mLastBatteryHealth;
     private boolean mLastBatteryPresent;
@@ -143,7 +134,8 @@
 
     private boolean mSentLowBatteryBroadcast = false;
 
-    private native void native_update();
+    private BatteryListener mBatteryPropertiesListener;
+    private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
 
     public BatteryService(Context context, LightsService lights) {
         mContext = context;
@@ -160,17 +152,21 @@
         mShutdownBatteryTemperature = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shutdownBatteryTemperature);
 
-        mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
-
         // watch for invalid charger messages if the invalid_charger switch exists
         if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
             mInvalidChargerObserver.startObserving(
                     "DEVPATH=/devices/virtual/switch/invalid_charger");
         }
 
-        // set initial status
-        synchronized (mLock) {
-            updateLocked();
+        mBatteryPropertiesListener = new BatteryListener();
+
+        IBinder b = ServiceManager.getService("batterypropreg");
+        mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);
+
+        try {
+            mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
+        } catch (RemoteException e) {
+            // Should never happen.
         }
     }
 
@@ -194,16 +190,16 @@
     private boolean isPoweredLocked(int plugTypeSet) {
         // assume we are powered if battery state is unknown so
         // the "stay on while plugged in" option will work.
-        if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+        if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mAcOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mUsbOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mWirelessOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
             return true;
         }
         return false;
@@ -223,7 +219,7 @@
      */
     public int getBatteryLevel() {
         synchronized (mLock) {
-            return mBatteryLevel;
+            return mBatteryProps.batteryLevel;
         }
     }
 
@@ -232,7 +228,7 @@
      */
     public boolean isBatteryLow() {
         synchronized (mLock) {
-            return mBatteryPresent && mBatteryLevel <= mLowBatteryWarningLevel;
+            return mBatteryProps.batteryPresent && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel;
         }
     }
 
@@ -248,7 +244,7 @@
     private void shutdownIfNoPowerLocked() {
         // shut down gracefully if our battery is critically low and we are not powered.
         // wait until the system has booted before attempting to display the shutdown dialog.
-        if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+        if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -267,7 +263,7 @@
         // shut down gracefully if temperature is too high (> 68.0C by default)
         // wait until the system has booted before attempting to display the
         // shutdown dialog.
-        if (mBatteryTemperature > mShutdownBatteryTemperature) {
+        if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -282,13 +278,13 @@
         }
     }
 
-    private void updateLocked() {
-        if (!mUpdatesStopped) {
-            // Update the values of mAcOnline, et. all.
-            native_update();
-
-            // Process the new values.
-            processValuesLocked();
+    private void update(BatteryProperties props) {
+        synchronized (mLock) {
+            if (!mUpdatesStopped) {
+                mBatteryProps = props;
+                // Process the new values.
+                processValuesLocked();
+            }
         }
     }
 
@@ -296,12 +292,12 @@
         boolean logOutlier = false;
         long dischargeDuration = 0;
 
-        mBatteryLevelCritical = (mBatteryLevel <= mCriticalBatteryLevel);
-        if (mAcOnline) {
+        mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
+        if (mBatteryProps.chargerAcOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
-        } else if (mUsbOnline) {
+        } else if (mBatteryProps.chargerUsbOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
-        } else if (mWirelessOnline) {
+        } else if (mBatteryProps.chargerWirelessOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
         } else {
             mPlugType = BATTERY_PLUGGED_NONE;
@@ -309,25 +305,27 @@
 
         if (DEBUG) {
             Slog.d(TAG, "Processing new values: "
-                    + "mAcOnline=" + mAcOnline
-                    + ", mUsbOnline=" + mUsbOnline
-                    + ", mWirelessOnline=" + mWirelessOnline
-                    + ", mBatteryStatus=" + mBatteryStatus
-                    + ", mBatteryHealth=" + mBatteryHealth
-                    + ", mBatteryPresent=" + mBatteryPresent
-                    + ", mBatteryLevel=" + mBatteryLevel
-                    + ", mBatteryTechnology=" + mBatteryTechnology
-                    + ", mBatteryVoltage=" + mBatteryVoltage
-                    + ", mBatteryTemperature=" + mBatteryTemperature
+                    + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
+                    + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
+                    + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
+                    + ", batteryStatus=" + mBatteryProps.batteryStatus
+                    + ", batteryHealth=" + mBatteryProps.batteryHealth
+                    + ", batteryPresent=" + mBatteryProps.batteryPresent
+                    + ", batteryLevel=" + mBatteryProps.batteryLevel
+                    + ", batteryTechnology=" + mBatteryProps.batteryTechnology
+                    + ", batteryVoltage=" + mBatteryProps.batteryVoltage
+                    + ", batteryCurrentNow=" + mBatteryProps.batteryCurrentNow
+                    + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter
+                    + ", batteryTemperature=" + mBatteryProps.batteryTemperature
                     + ", mBatteryLevelCritical=" + mBatteryLevelCritical
                     + ", mPlugType=" + mPlugType);
         }
 
         // Let the battery stats keep track of the current level.
         try {
-            mBatteryStats.setBatteryState(mBatteryStatus, mBatteryHealth,
-                    mPlugType, mBatteryLevel, mBatteryTemperature,
-                    mBatteryVoltage);
+            mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
+                    mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
+                    mBatteryProps.batteryVoltage);
         } catch (RemoteException e) {
             // Should never happen.
         }
@@ -335,13 +333,13 @@
         shutdownIfNoPowerLocked();
         shutdownIfOverTempLocked();
 
-        if (mBatteryStatus != mLastBatteryStatus ||
-                mBatteryHealth != mLastBatteryHealth ||
-                mBatteryPresent != mLastBatteryPresent ||
-                mBatteryLevel != mLastBatteryLevel ||
+        if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+                mBatteryProps.batteryHealth != mLastBatteryHealth ||
+                mBatteryProps.batteryPresent != mLastBatteryPresent ||
+                mBatteryProps.batteryLevel != mLastBatteryLevel ||
                 mPlugType != mLastPlugType ||
-                mBatteryVoltage != mLastBatteryVoltage ||
-                mBatteryTemperature != mLastBatteryTemperature ||
+                mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
+                mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
                 mInvalidCharger != mLastInvalidCharger) {
 
             if (mPlugType != mLastPlugType) {
@@ -350,33 +348,33 @@
 
                     // There's no value in this data unless we've discharged at least once and the
                     // battery level has changed; so don't log until it does.
-                    if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryLevel) {
+                    if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
                         dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
                         logOutlier = true;
                         EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
-                                mDischargeStartLevel, mBatteryLevel);
+                                mDischargeStartLevel, mBatteryProps.batteryLevel);
                         // make sure we see a discharge event before logging again
                         mDischargeStartTime = 0;
                     }
                 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
                     // charging -> discharging or we just powered up
                     mDischargeStartTime = SystemClock.elapsedRealtime();
-                    mDischargeStartLevel = mBatteryLevel;
+                    mDischargeStartLevel = mBatteryProps.batteryLevel;
                 }
             }
-            if (mBatteryStatus != mLastBatteryStatus ||
-                    mBatteryHealth != mLastBatteryHealth ||
-                    mBatteryPresent != mLastBatteryPresent ||
+            if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+                    mBatteryProps.batteryHealth != mLastBatteryHealth ||
+                    mBatteryProps.batteryPresent != mLastBatteryPresent ||
                     mPlugType != mLastPlugType) {
                 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
-                        mBatteryStatus, mBatteryHealth, mBatteryPresent ? 1 : 0,
-                        mPlugType, mBatteryTechnology);
+                        mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
+                        mPlugType, mBatteryProps.batteryTechnology);
             }
-            if (mBatteryLevel != mLastBatteryLevel ||
-                    mBatteryVoltage != mLastBatteryVoltage ||
-                    mBatteryTemperature != mLastBatteryTemperature) {
+            if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
+                // Don't do this just from voltage or temperature changes, that is
+                // too noisy.
                 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
-                        mBatteryLevel, mBatteryVoltage, mBatteryTemperature);
+                        mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
             }
             if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
                     mPlugType == BATTERY_PLUGGED_NONE) {
@@ -396,8 +394,8 @@
              *   (becomes <= mLowBatteryWarningLevel).
              */
             final boolean sendBatteryLow = !plugged
-                    && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
-                    && mBatteryLevel <= mLowBatteryWarningLevel
+                    && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+                    && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
                     && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
 
             sendIntentLocked();
@@ -456,13 +454,13 @@
                 logOutlierLocked(dischargeDuration);
             }
 
-            mLastBatteryStatus = mBatteryStatus;
-            mLastBatteryHealth = mBatteryHealth;
-            mLastBatteryPresent = mBatteryPresent;
-            mLastBatteryLevel = mBatteryLevel;
+            mLastBatteryStatus = mBatteryProps.batteryStatus;
+            mLastBatteryHealth = mBatteryProps.batteryHealth;
+            mLastBatteryPresent = mBatteryProps.batteryPresent;
+            mLastBatteryLevel = mBatteryProps.batteryLevel;
             mLastPlugType = mPlugType;
-            mLastBatteryVoltage = mBatteryVoltage;
-            mLastBatteryTemperature = mBatteryTemperature;
+            mLastBatteryVoltage = mBatteryProps.batteryVoltage;
+            mLastBatteryTemperature = mBatteryProps.batteryTemperature;
             mLastBatteryLevelCritical = mBatteryLevelCritical;
             mLastInvalidCharger = mInvalidCharger;
         }
@@ -474,29 +472,29 @@
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
 
-        int icon = getIconLocked(mBatteryLevel);
+        int icon = getIconLocked(mBatteryProps.batteryLevel);
 
-        intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);
-        intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);
-        intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);
-        intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);
+        intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
+        intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
+        intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
+        intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
         intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
         intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
         intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
-        intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);
-        intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);
-        intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
+        intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
+        intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
+        intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
         intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
 
         if (DEBUG) {
-            Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED.  level:" + mBatteryLevel +
-                    ", scale:" + BATTERY_SCALE + ", status:" + mBatteryStatus +
-                    ", health:" + mBatteryHealth +  ", present:" + mBatteryPresent +
-                    ", voltage: " + mBatteryVoltage +
-                    ", temperature: " + mBatteryTemperature +
-                    ", technology: " + mBatteryTechnology +
-                    ", AC powered:" + mAcOnline + ", USB powered:" + mUsbOnline +
-                    ", Wireless powered:" + mWirelessOnline +
+            Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED.  level:" + mBatteryProps.batteryLevel +
+                    ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
+                    ", health:" + mBatteryProps.batteryHealth +  ", present:" + mBatteryProps.batteryPresent +
+                    ", voltage: " + mBatteryProps.batteryVoltage +
+                    ", temperature: " + mBatteryProps.batteryTemperature +
+                    ", technology: " + mBatteryProps.batteryTechnology +
+                    ", AC powered:" + mBatteryProps.chargerAcOnline + ", USB powered:" + mBatteryProps.chargerUsbOnline +
+                    ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
                     ", icon:" + icon  + ", invalid charger:" + mInvalidCharger);
         }
 
@@ -509,7 +507,7 @@
     }
 
     private void logBatteryStatsLocked() {
-        IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);
+        IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
         if (batteryInfoService == null) return;
 
         DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
@@ -519,7 +517,7 @@
         FileOutputStream dumpStream = null;
         try {
             // dump the service to a file
-            dumpFile = new File(DUMPSYS_DATA_PATH + BATTERY_STATS_SERVICE_NAME + ".dump");
+            dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
             dumpStream = new FileOutputStream(dumpFile);
             batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
             FileUtils.sync(dumpStream);
@@ -558,14 +556,14 @@
                 long durationThreshold = Long.parseLong(durationThresholdString);
                 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
                 if (duration <= durationThreshold &&
-                        mDischargeStartLevel - mBatteryLevel >= dischargeThreshold) {
+                        mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
                     // If the discharge cycle is bad enough we want to know about it.
                     logBatteryStatsLocked();
                 }
                 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
                         " discharge threshold: " + dischargeThreshold);
                 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
-                        (mDischargeStartLevel - mBatteryLevel));
+                        (mDischargeStartLevel - mBatteryProps.batteryLevel));
             } catch (NumberFormatException e) {
                 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
                         durationThresholdString + " or " + dischargeThresholdString);
@@ -575,14 +573,14 @@
     }
 
     private int getIconLocked(int level) {
-        if (mBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
+        if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
             return com.android.internal.R.drawable.stat_sys_battery_charge;
-        } else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+        } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
             return com.android.internal.R.drawable.stat_sys_battery;
-        } else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
-                || mBatteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
+        } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
+                || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
             if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
-                    && mBatteryLevel >= 100) {
+                    && mBatteryProps.batteryLevel >= 100) {
                 return com.android.internal.R.drawable.stat_sys_battery_charge;
             } else {
                 return com.android.internal.R.drawable.stat_sys_battery;
@@ -609,32 +607,41 @@
                 if (mUpdatesStopped) {
                     pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");
                 }
-                pw.println("  AC powered: " + mAcOnline);
-                pw.println("  USB powered: " + mUsbOnline);
-                pw.println("  Wireless powered: " + mWirelessOnline);
-                pw.println("  status: " + mBatteryStatus);
-                pw.println("  health: " + mBatteryHealth);
-                pw.println("  present: " + mBatteryPresent);
-                pw.println("  level: " + mBatteryLevel);
+                pw.println("  AC powered: " + mBatteryProps.chargerAcOnline);
+                pw.println("  USB powered: " + mBatteryProps.chargerUsbOnline);
+                pw.println("  Wireless powered: " + mBatteryProps.chargerWirelessOnline);
+                pw.println("  status: " + mBatteryProps.batteryStatus);
+                pw.println("  health: " + mBatteryProps.batteryHealth);
+                pw.println("  present: " + mBatteryProps.batteryPresent);
+                pw.println("  level: " + mBatteryProps.batteryLevel);
                 pw.println("  scale: " + BATTERY_SCALE);
-                pw.println("  voltage:" + mBatteryVoltage);
-                pw.println("  temperature: " + mBatteryTemperature);
-                pw.println("  technology: " + mBatteryTechnology);
+                pw.println("  voltage: " + mBatteryProps.batteryVoltage);
+
+                if (mBatteryProps.batteryCurrentNow != Integer.MIN_VALUE) {
+                    pw.println("  current now: " + mBatteryProps.batteryCurrentNow);
+                }
+
+                if (mBatteryProps.batteryChargeCounter != Integer.MIN_VALUE) {
+                    pw.println("  charge counter: " + mBatteryProps.batteryChargeCounter);
+                }
+
+                pw.println("  temperature: " + mBatteryProps.batteryTemperature);
+                pw.println("  technology: " + mBatteryProps.batteryTechnology);
             } else if (args.length == 3 && "set".equals(args[0])) {
                 String key = args[1];
                 String value = args[2];
                 try {
                     boolean update = true;
                     if ("ac".equals(key)) {
-                        mAcOnline = Integer.parseInt(value) != 0;
+                        mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
                     } else if ("usb".equals(key)) {
-                        mUsbOnline = Integer.parseInt(value) != 0;
+                        mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
                     } else if ("wireless".equals(key)) {
-                        mWirelessOnline = Integer.parseInt(value) != 0;
+                        mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
                     } else if ("status".equals(key)) {
-                        mBatteryStatus = Integer.parseInt(value);
+                        mBatteryProps.batteryStatus = Integer.parseInt(value);
                     } else if ("level".equals(key)) {
-                        mBatteryLevel = Integer.parseInt(value);
+                        mBatteryProps.batteryLevel = Integer.parseInt(value);
                     } else if ("invalid".equals(key)) {
                         mInvalidCharger = Integer.parseInt(value);
                     } else {
@@ -642,15 +649,24 @@
                         update = false;
                     }
                     if (update) {
-                        mUpdatesStopped = true;
-                        processValuesLocked();
+                        long ident = Binder.clearCallingIdentity();
+                        try {
+                            mUpdatesStopped = true;
+                            processValuesLocked();
+                        } finally {
+                            Binder.restoreCallingIdentity(ident);
+                        }
                     }
                 } catch (NumberFormatException ex) {
                     pw.println("Bad value: " + value);
                 }
             } else if (args.length == 1 && "reset".equals(args[0])) {
-                mUpdatesStopped = false;
-                updateLocked();
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mUpdatesStopped = false;
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             } else {
                 pw.println("Dump current battery state, or:");
                 pw.println("  set ac|usb|wireless|status|level|invalid <value>");
@@ -659,15 +675,6 @@
         }
     }
 
-    private final UEventObserver mPowerSupplyObserver = new UEventObserver() {
-        @Override
-        public void onUEvent(UEventObserver.UEvent event) {
-            synchronized (mLock) {
-                updateLocked();
-            }
-        }
-    };
-
     private final UEventObserver mInvalidChargerObserver = new UEventObserver() {
         @Override
         public void onUEvent(UEventObserver.UEvent event) {
@@ -675,7 +682,6 @@
             synchronized (mLock) {
                 if (mInvalidCharger != invalidCharger) {
                     mInvalidCharger = invalidCharger;
-                    updateLocked();
                 }
             }
         }
@@ -709,8 +715,8 @@
          * Synchronize on BatteryService.
          */
         public void updateLightsLocked() {
-            final int level = mBatteryLevel;
-            final int status = mBatteryStatus;
+            final int level = mBatteryProps.batteryLevel;
+            final int status = mBatteryProps.batteryStatus;
             if (level < mLowBatteryWarningLevel) {
                 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
                     // Solid red when battery is charging
@@ -735,4 +741,10 @@
             }
         }
     }
+
+    private final class BatteryListener extends IBatteryPropertiesListener.Stub {
+        public void batteryPropertiesChanged(BatteryProperties props) {
+            BatteryService.this.update(props);
+       }
+    }
 }
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index bea2cca..d2d5280 100644
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -34,7 +34,6 @@
 import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -120,7 +119,6 @@
     // used inside handler thread
     private boolean mEnable;
     private int mState;
-    private HandlerThread mThread;
     private final BluetoothHandler mHandler;
     private int mErrorRecoveryRetryCounter;
 
@@ -194,9 +192,7 @@
     };
 
     BluetoothManagerService(Context context) {
-        mThread = new HandlerThread("BluetoothManager");
-        mThread.start();
-        mHandler = new BluetoothHandler(mThread.getLooper());
+        mHandler = new BluetoothHandler(IoThread.get().getLooper());
 
         mContext = context;
         mBluetooth = null;
@@ -647,10 +643,9 @@
                             Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
                             mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
                             Intent i = new Intent(IBluetooth.class.getName());
-                            if (!mContext.bindServiceAsUser(i, mConnection,
-                                  Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
+                            if (!doBind(i, mConnection,
+                                    Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
                                 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
-                                Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
                             } else {
                                 mBinding = true;
                             }
@@ -792,11 +787,21 @@
                         } // else must be SERVICE_IBLUETOOTH
 
                         //Remove timeout
-                            mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
 
                         mBinding = false;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
+                        try {
+                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
+                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
+                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
+                                Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
+                            }
+                        } catch (RemoteException e) {
+                            Log.e(TAG,"Unable to call configHciSnoopLog", e);
+                        }
+
                         if (mConnection.isGetNameAddressOnly()) {
                             //Request GET NAME AND ADDRESS
                             Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
@@ -1022,10 +1027,8 @@
                 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
                 mConnection.setGetNameAddressOnly(false);
                 Intent i = new Intent(IBluetooth.class.getName());
-                if (!mContext.bindServiceAsUser(i, mConnection,Context.BIND_AUTO_CREATE,
-                                          UserHandle.CURRENT)) {
+                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
                     mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
-                    Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
                 } else {
                     mBinding = true;
                 }
@@ -1064,6 +1067,16 @@
         }
     }
 
+    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
+            Log.e(TAG, "Fail to bind to: " + intent);
+            return false;
+        }
+        return true;
+    }
+
     private void handleDisable() {
         synchronized(mConnection) {
             // don't need to disable if GetNameAddressOnly is set,
@@ -1116,10 +1129,7 @@
                     if (mContext.getPackageManager().hasSystemFeature(
                                                      PackageManager.FEATURE_BLUETOOTH_LE)) {
                         Intent i = new Intent(IBluetoothGatt.class.getName());
-                        if (!mContext.bindServiceAsUser(i, mConnection, Context.BIND_AUTO_CREATE,
-                                                        UserHandle.CURRENT)) {
-                            Log.e(TAG, "Fail to bind to: " + IBluetoothGatt.class.getName());
-                        }
+                        doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
                     }
                 } else {
                     //If Bluetooth is off, send service down event to proxy objects, and unbind
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 3dade37..da1b254 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -127,6 +127,7 @@
             addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
                     -LOG_SIZE, "APANIC_THREADS");
             addAuditErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_AUDIT");
+            addFsckErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_FSCK");
         } else {
             if (db != null) db.addText("SYSTEM_RESTART", headers);
         }
@@ -203,4 +204,31 @@
         Slog.i(TAG, "Copied " + sb.toString().length() + " worth of audits to DropBox");
         db.addText(tag, headers + sb.toString());
     }
+
+    private static void addFsckErrorsToDropBox(DropBoxManager db,  SharedPreferences prefs,
+            String headers, int maxSize, String tag) throws IOException {
+        boolean upload_needed = false;
+        if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
+        Slog.i(TAG, "Checking for fsck errors");
+
+        File file = new File("/dev/fscklogs/log");
+        long fileTime = file.lastModified();
+        if (fileTime <= 0) return;  // File does not exist
+
+        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        StringBuilder sb = new StringBuilder();
+        for (String line : log.split("\n")) {
+            if (line.contains("FILE SYSTEM WAS MODIFIED")) {
+                upload_needed = true;
+                break;
+            }
+        }
+
+        if (upload_needed) {
+            addFileToDropBox(db, prefs, headers, "/dev/fscklogs/log", maxSize, tag);
+        }
+
+        // Remove the file so we don't re-upload if the runtime restarts.
+        file.delete();
+    }
 }
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index 0bf03b5..069ae23 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -122,7 +122,9 @@
         try {
             return super.onTransact(code, data, reply, flags);
         } catch (RuntimeException e) {
-            Slog.w("clipboard", "Exception: ", e);
+            if (!(e instanceof SecurityException)) {
+                Slog.wtf("clipboard", "Exception: ", e);
+            }
             throw e;
         }
         
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java
index c316733..710fb9d 100644
--- a/services/java/com/android/server/CommonTimeManagementService.java
+++ b/services/java/com/android/server/CommonTimeManagementService.java
@@ -40,6 +40,8 @@
 import android.os.SystemProperties;
 import android.util.Log;
 
+import com.android.server.net.BaseNetworkObserver;
+
 /**
  * @hide
  * <p>CommonTimeManagementService manages the configuration of the native Common Time service,
@@ -104,9 +106,7 @@
     /*
      * Callback handler implementations.
      */
-    private INetworkManagementEventObserver mIfaceObserver =
-        new INetworkManagementEventObserver.Stub() {
-
+    private INetworkManagementEventObserver mIfaceObserver = new BaseNetworkObserver() {
         public void interfaceStatusChanged(String iface, boolean up) {
             reevaluateServiceState();
         }
@@ -119,9 +119,6 @@
         public void interfaceRemoved(String iface) {
             reevaluateServiceState();
         }
-        public void limitReached(String limitName, String iface) { }
-
-        public void interfaceClassDataActivityChanged(String label, boolean active) {}
     };
 
     private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() {
@@ -153,7 +150,7 @@
         mContext = context;
     }
 
-    void systemReady() {
+    void systemRunning() {
         if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) {
             Log.i(TAG, "No common time service detected on this platform.  " +
                        "Common time services will be unavailable.");
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cb4e89c..3f13f3a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -31,10 +31,12 @@
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
+import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothTetheringDataTracker;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -56,13 +58,12 @@
 import android.net.INetworkStatsService;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.Uri;
 import android.net.LinkProperties.CompareResult;
+import android.net.LinkQualityInfo;
 import android.net.MobileDataStateTracker;
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.NetworkStateTracker;
@@ -70,6 +71,8 @@
 import android.net.Proxy;
 import android.net.ProxyProperties;
 import android.net.RouteInfo;
+import android.net.SamplingDataTracker;
+import android.net.Uri;
 import android.net.wifi.WifiStateTracker;
 import android.net.wimax.WimaxManagerConstants;
 import android.os.AsyncTask;
@@ -86,7 +89,6 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -97,10 +99,12 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
@@ -110,7 +114,9 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
@@ -140,9 +146,12 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.GregorianCalendar;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -170,6 +179,23 @@
     private static final String FAIL_FAST_TIME_MS =
             "persist.radio.fail_fast_time_ms";
 
+    private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED =
+            "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED";
+
+    private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0;
+
+    private PendingIntent mSampleIntervalElapsedIntent;
+
+    // Set network sampling interval at 12 minutes, this way, even if the timers get
+    // aggregated, it will fire at around 15 minutes, which should allow us to
+    // aggregate this timer with other timers (specially the socket keep alive timers)
+    private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60);
+
+    // start network sampling a minute after booting ...
+    private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60);
+
+    AlarmManager mAlarmManager;
+
     // used in recursive route setting to add gateways for the host for which
     // a host route was requested.
     private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
@@ -178,7 +204,8 @@
 
     private KeyStore mKeyStore;
 
-    private Vpn mVpn;
+    @GuardedBy("mVpns")
+    private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
     private VpnCallback mVpnCallback = new VpnCallback();
 
     private boolean mLockdownEnabled;
@@ -230,7 +257,6 @@
 
     private Object mDnsLock = new Object();
     private int mNumDnsEntries;
-    private boolean mDnsOverridden = false;
 
     private boolean mTestMode;
     private static ConnectivityService sServiceInstance;
@@ -247,6 +273,9 @@
     private static final boolean TO_DEFAULT_TABLE = true;
     private static final boolean TO_SECONDARY_TABLE = false;
 
+    private static final boolean EXEMPT = true;
+    private static final boolean UNEXEMPT = false;
+
     /**
      * used internally as a delayed event to make us switch back to the
      * default network
@@ -302,28 +331,27 @@
     private static final int EVENT_SET_DEPENDENCY_MET = 10;
 
     /**
-     * used internally to restore DNS properties back to the
-     * default network
-     */
-    private static final int EVENT_RESTORE_DNS = 11;
-
-    /**
      * used internally to send a sticky broadcast delayed.
      */
-    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12;
+    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11;
 
     /**
      * Used internally to
      * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
      */
-    private static final int EVENT_SET_POLICY_DATA_ENABLE = 13;
+    private static final int EVENT_SET_POLICY_DATA_ENABLE = 12;
 
-    private static final int EVENT_VPN_STATE_CHANGED = 14;
+    private static final int EVENT_VPN_STATE_CHANGED = 13;
 
     /**
      * Used internally to disable fail fast of mobile data
      */
-    private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15;
+    private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
+
+    /**
+     * user internally to indicate that data sampling interval is up
+     */
+    private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
 
     /** Handler used for internal events. */
     private InternalHandler mHandler;
@@ -344,10 +372,19 @@
 
     private InetAddress mDefaultDns;
 
+    // Lock for protecting access to mAddedRoutes and mExemptAddresses
+    private final Object mRoutesLock = new Object();
+
     // this collection is used to refcount the added routes - if there are none left
     // it's time to remove the route from the route table
+    @GuardedBy("mRoutesLock")
     private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
 
+    // this collection corresponds to the entries of mAddedRoutes that have routing exemptions
+    // used to handle cleanup of exempt rules
+    @GuardedBy("mRoutesLock")
+    private Collection<LinkAddress> mExemptAddresses = new ArrayList<LinkAddress>();
+
     // used in DBG mode to track inet condition reports
     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
     private ArrayList mInetLog;
@@ -360,6 +397,8 @@
     // track the global proxy.
     private ProxyProperties mGlobalProxy = null;
 
+    private PacManager mPacManager = null;
+
     private SettingsObserver mSettingsObserver;
 
     NetworkConfig[] mNetConfigs;
@@ -379,13 +418,12 @@
     // the set of network types that can only be enabled by system/sig apps
     List mProtectedNetworks;
 
+    private DataConnectionStats mDataConnectionStats;
+
     private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
 
     TelephonyManager mTelephonyManager;
 
-    // We only want one checkMobileProvisioning after booting.
-    volatile boolean mFirstProvisioningCheckStarted = false;
-
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         // Currently, omitting a NetworkFactory will create one internally
@@ -461,6 +499,7 @@
                 com.android.internal.R.array.radioAttributes);
         for (String raString : raStrings) {
             RadioAttributes r = new RadioAttributes(raString);
+            if (VDBG) log("raString=" + raString + " r=" + r);
             if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
                 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
                 continue;
@@ -481,6 +520,7 @@
         for (String naString : naStrings) {
             try {
                 NetworkConfig n = new NetworkConfig(naString);
+                if (VDBG) log("naString=" + naString + " config=" + n);
                 if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
                     loge("Error in networkAttributes - ignoring attempt to define type " +
                             n.type);
@@ -507,6 +547,7 @@
                 // ignore it - leave the entry null
             }
         }
+        if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
 
         mProtectedNetworks = new ArrayList<Integer>();
         int[] protectedNetworks = context.getResources().getIntArray(
@@ -589,9 +630,12 @@
 
         mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
 
-        mVpn = new Vpn(mContext, mVpnCallback, mNetd, this);
-        mVpn.startMonitoring(mContext, mTrackerHandler);
-
+        //set up the listener for user state for creating user VPNs
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_STARTING);
+        intentFilter.addAction(Intent.ACTION_USER_STOPPING);
+        mContext.registerReceiverAsUser(
+                mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
         mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
 
         try {
@@ -609,8 +653,37 @@
         mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
         mSettingsObserver.observe(mContext);
 
-        mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
-        loadGlobalProxy();
+        mDataConnectionStats = new DataConnectionStats(mContext);
+        mDataConnectionStats.startMonitoring();
+
+        // start network sampling ..
+        Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null);
+        mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
+                SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0);
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        String action = intent.getAction();
+                        if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) {
+                            mHandler.sendMessage(mHandler.obtainMessage
+                                    (EVENT_SAMPLE_INTERVAL_ELAPSED));
+                        }
+                    }
+                },
+                new IntentFilter(filter));
+
+        mPacManager = new PacManager(mContext);
+
+        filter = new IntentFilter();
+        filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
+        mContext.registerReceiver(mProvisioningReceiver, filter);
     }
 
     /**
@@ -879,6 +952,45 @@
         return getNetworkInfo(mActiveDefaultNetwork, uid);
     }
 
+    /**
+     * Find the first Provisioning network.
+     *
+     * @return NetworkInfo or null if none.
+     */
+    private NetworkInfo getProvisioningNetworkInfo() {
+        enforceAccessPermission();
+
+        // Find the first Provisioning Network
+        NetworkInfo provNi = null;
+        for (NetworkInfo ni : getAllNetworkInfo()) {
+            if (ni.isConnectedToProvisioningNetwork()) {
+                provNi = ni;
+                break;
+            }
+        }
+        if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi);
+        return provNi;
+    }
+
+    /**
+     * Find the first Provisioning network or the ActiveDefaultNetwork
+     * if there is no Provisioning network
+     *
+     * @return NetworkInfo or null if none.
+     */
+    @Override
+    public NetworkInfo getProvisioningOrActiveNetworkInfo() {
+        enforceAccessPermission();
+
+        NetworkInfo provNi = getProvisioningNetworkInfo();
+        if (provNi == null) {
+            final int uid = Binder.getCallingUid();
+            provNi = getNetworkInfo(mActiveDefaultNetwork, uid);
+        }
+        if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi);
+        return provNi;
+    }
+
     public NetworkInfo getActiveNetworkInfoUnfiltered() {
         enforceAccessPermission();
         if (isNetworkTypeValid(mActiveDefaultNetwork)) {
@@ -1241,8 +1353,10 @@
                                 feature);
                     }
                     if (network.reconnect()) {
+                        if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED");
                         return PhoneConstants.APN_REQUEST_STARTED;
                     } else {
+                        if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED");
                         return PhoneConstants.APN_REQUEST_FAILED;
                     }
                 } else {
@@ -1254,9 +1368,11 @@
                             mNetRequestersPids[usedNetworkType].add(currentPid);
                         }
                     }
+                    if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature.");
                     return -1;
                 }
             }
+            if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE");
             return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
          } finally {
             if (DBG) {
@@ -1290,11 +1406,12 @@
             }
         }
         if (found && u != null) {
+            if (VDBG) log("stopUsingNetworkFeature: X");
             // stop regardless of how many other time this proc had called start
             return stopUsingNetworkFeature(u, true);
         } else {
             // none found!
-            if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring");
+            if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring");
             return 1;
         }
     }
@@ -1458,7 +1575,7 @@
         try {
             InetAddress addr = InetAddress.getByAddress(hostAddress);
             LinkProperties lp = tracker.getLinkProperties();
-            boolean ok = addRouteToAddress(lp, addr);
+            boolean ok = addRouteToAddress(lp, addr, EXEMPT);
             if (DBG) log("requestRouteToHostAddress ok=" + ok);
             return ok;
         } catch (UnknownHostException e) {
@@ -1470,24 +1587,25 @@
         return false;
     }
 
-    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p, r, 0, ADD, toDefaultTable);
+    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
+            boolean exempt) {
+        return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt);
     }
 
     private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p, r, 0, REMOVE, toDefaultTable);
+        return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT);
     }
 
-    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
-        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
+    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) {
+        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt);
     }
 
     private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
-        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
+        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT);
     }
 
     private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
-            boolean toDefaultTable) {
+            boolean toDefaultTable, boolean exempt) {
         RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
         if (bestRoute == null) {
             bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
@@ -1502,11 +1620,11 @@
                 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
             }
         }
-        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable);
+        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt);
     }
 
     private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
-            boolean toDefaultTable) {
+            boolean toDefaultTable, boolean exempt) {
         if ((lp == null) || (r == null)) {
             if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
             return false;
@@ -1535,15 +1653,25 @@
                                                         bestRoute.getGateway(),
                                                         ifaceName);
                 }
-                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
+                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt);
             }
         }
         if (doAdd) {
             if (VDBG) log("Adding " + r + " for interface " + ifaceName);
             try {
                 if (toDefaultTable) {
-                    mAddedRoutes.add(r);  // only track default table - only one apps can effect
-                    mNetd.addRoute(ifaceName, r);
+                    synchronized (mRoutesLock) {
+                        // only track default table - only one apps can effect
+                        mAddedRoutes.add(r);
+                        mNetd.addRoute(ifaceName, r);
+                        if (exempt) {
+                            LinkAddress dest = r.getDestination();
+                            if (!mExemptAddresses.contains(dest)) {
+                                mNetd.setHostExemption(dest);
+                                mExemptAddresses.add(dest);
+                            }
+                        }
+                    }
                 } else {
                     mNetd.addSecondaryRoute(ifaceName, r);
                 }
@@ -1556,18 +1684,25 @@
             // if we remove this one and there are no more like it, then refcount==0 and
             // we can remove it from the table
             if (toDefaultTable) {
-                mAddedRoutes.remove(r);
-                if (mAddedRoutes.contains(r) == false) {
-                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
-                    try {
-                        mNetd.removeRoute(ifaceName, r);
-                    } catch (Exception e) {
-                        // never crash - catch them all
-                        if (VDBG) loge("Exception trying to remove a route: " + e);
-                        return false;
+                synchronized (mRoutesLock) {
+                    mAddedRoutes.remove(r);
+                    if (mAddedRoutes.contains(r) == false) {
+                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+                        try {
+                            mNetd.removeRoute(ifaceName, r);
+                            LinkAddress dest = r.getDestination();
+                            if (mExemptAddresses.contains(dest)) {
+                                mNetd.clearHostExemption(dest);
+                                mExemptAddresses.remove(dest);
+                            }
+                        } catch (Exception e) {
+                            // never crash - catch them all
+                            if (VDBG) loge("Exception trying to remove a route: " + e);
+                            return false;
+                        }
+                    } else {
+                        if (VDBG) log("not removing " + r + " as it's still in use");
                     }
-                } else {
-                    if (VDBG) log("not removing " + r + " as it's still in use");
                 }
             } else {
                 if (VDBG) log("Removing " + r + " for interface " + ifaceName);
@@ -1744,6 +1879,16 @@
                 "ConnectivityService");
     }
 
+    private void enforceMarkNetworkSocketPermission() {
+        //Media server special case
+        if (Binder.getCallingUid() == Process.MEDIA_UID) {
+            return;
+        }
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MARK_NETWORK_SOCKET,
+                "ConnectivityService");
+    }
+
     /**
      * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
      * network, we ignore it. If it is for the active network, we send out a
@@ -1849,6 +1994,9 @@
          */
         if (mNetConfigs[prevNetType].isDefault()) {
             if (mActiveDefaultNetwork == prevNetType) {
+                if (DBG) {
+                    log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType);
+                }
                 mActiveDefaultNetwork = -1;
             }
 
@@ -1859,6 +2007,7 @@
 //            if (mActiveDefaultNetwork != -1) {
 //                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
 //            }
+
             for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
                 if (checkType == prevNetType) continue;
                 if (mNetConfigs[checkType] == null) continue;
@@ -1873,6 +2022,7 @@
 // optimization should work and we need to investigate why it doesn't work.
 // This could be related to how DEACTIVATE_DATA_CALL is reporting its
 // complete before it is really complete.
+
 //                if (!mNetTrackers[checkType].isAvailable()) continue;
 
 //                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
@@ -2041,6 +2191,9 @@
     }
 
     void systemReady() {
+        mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
+        loadGlobalProxy();
+
         synchronized(this) {
             mSystemReady = true;
             if (mInitialBroadcast != null) {
@@ -2071,10 +2224,11 @@
     };
 
     private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
-        if ((type != mNetworkPreference &&
-                    mNetConfigs[mActiveDefaultNetwork].priority >
-                    mNetConfigs[type].priority) ||
-                mNetworkPreference == mActiveDefaultNetwork) return false;
+        if (((type != mNetworkPreference)
+                      && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority))
+                   || (mNetworkPreference == mActiveDefaultNetwork)) {
+            return false;
+        }
         return true;
     }
 
@@ -2088,6 +2242,11 @@
         final NetworkStateTracker thisNet = mNetTrackers[newNetType];
         final String thisIface = thisNet.getLinkProperties().getInterfaceName();
 
+        if (VDBG) {
+            log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface
+                    + " isFailover" + isFailover);
+        }
+
         // if this is a default net and other default is running
         // kill the one not preferred
         if (mNetConfigs[newNetType].isDefault()) {
@@ -2138,6 +2297,7 @@
         }
         thisNet.setTeardownRequested(false);
         updateNetworkSettings(thisNet);
+        updateMtuSizeSettings(thisNet);
         handleConnectivityChange(newNetType, false);
         sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
 
@@ -2169,15 +2329,26 @@
             }
         }
 
+        if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info);
         thisNet.captivePortalCheckComplete();
     }
 
     /** @hide */
+    @Override
     public void captivePortalCheckComplete(NetworkInfo info) {
         enforceConnectivityInternalPermission();
+        if (DBG) log("captivePortalCheckComplete: ni=" + info);
         mNetTrackers[info.getType()].captivePortalCheckComplete();
     }
 
+    /** @hide */
+    @Override
+    public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
+        enforceConnectivityInternalPermission();
+        if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal);
+        mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
+    }
+
     /**
      * Setup data activity tracking for the given network interface.
      *
@@ -2238,6 +2409,11 @@
      */
     private void handleConnectivityChange(int netType, boolean doReset) {
         int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+        boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
+        if (VDBG) {
+            log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset
+                    + " resetMask=" + resetMask);
+        }
 
         /*
          * If a non-default network is enabled, add the host routes that
@@ -2302,10 +2478,12 @@
             }
         }
         mCurrentLinkProperties[netType] = newLp;
-        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
+        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);
 
         if (resetMask != 0 || resetDns) {
+            if (VDBG) log("handleConnectivityChange: resetting");
             if (curLp != null) {
+                if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp);
                 for (String iface : curLp.getAllInterfaceNames()) {
                     if (TextUtils.isEmpty(iface) == false) {
                         if (resetMask != 0) {
@@ -2315,7 +2493,11 @@
                             // Tell VPN the interface is down. It is a temporary
                             // but effective fix to make VPN aware of the change.
                             if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
-                                mVpn.interfaceStatusChanged(iface, false);
+                                synchronized(mVpns) {
+                                    for (int i = 0; i < mVpns.size(); i++) {
+                                        mVpns.valueAt(i).interfaceStatusChanged(iface, false);
+                                    }
+                                }
                             }
                         }
                         if (resetDns) {
@@ -2338,6 +2520,7 @@
         // Update 464xlat state.
         NetworkStateTracker tracker = mNetTrackers[netType];
         if (mClat.requiresClat(netType, tracker)) {
+
             // If the connection was previously using clat, but is not using it now, stop the clat
             // daemon. Normally, this happens automatically when the connection disconnects, but if
             // the disconnect is not reported, or if the connection's LinkProperties changed for
@@ -2374,13 +2557,13 @@
      * returns a boolean indicating the routes changed
      */
     private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
-            boolean isLinkDefault) {
+            boolean isLinkDefault, boolean exempt) {
         Collection<RouteInfo> routesToAdd = null;
         CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
         if (curLp != null) {
             // check for the delta between the current set and the new
-            routeDiff = curLp.compareRoutes(newLp);
+            routeDiff = curLp.compareAllRoutes(newLp);
             dnsDiff = curLp.compareDnses(newLp);
         } else if (newLp != null) {
             routeDiff.added = newLp.getAllRoutes();
@@ -2391,6 +2574,7 @@
 
         for (RouteInfo r : routeDiff.removed) {
             if (isLinkDefault || ! r.isDefaultRoute()) {
+                if (VDBG) log("updateRoutes: default remove route r=" + r);
                 removeRoute(curLp, r, TO_DEFAULT_TABLE);
             }
             if (isLinkDefault == false) {
@@ -2410,7 +2594,7 @@
                 }
                 if (newLp != null) {
                     for (InetAddress newDns : newLp.getDnses()) {
-                        addRouteToAddress(newLp, newDns);
+                        addRouteToAddress(newLp, newDns, exempt);
                     }
                 }
             } else {
@@ -2419,28 +2603,30 @@
                     removeRouteToAddress(curLp, oldDns);
                 }
                 for (InetAddress newDns : dnsDiff.added) {
-                    addRouteToAddress(newLp, newDns);
+                    addRouteToAddress(newLp, newDns, exempt);
                 }
             }
         }
 
         for (RouteInfo r :  routeDiff.added) {
             if (isLinkDefault || ! r.isDefaultRoute()) {
-                addRoute(newLp, r, TO_DEFAULT_TABLE);
+                addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
             } else {
                 // add to a secondary route table
-                addRoute(newLp, r, TO_SECONDARY_TABLE);
+                addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT);
 
                 // many radios add a default route even when we don't want one.
                 // remove the default route unless somebody else has asked for it
                 String ifaceName = newLp.getInterfaceName();
-                if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
-                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
-                    try {
-                        mNetd.removeRoute(ifaceName, r);
-                    } catch (Exception e) {
-                        // never crash - catch them all
-                        if (DBG) loge("Exception trying to remove a route: " + e);
+                synchronized (mRoutesLock) {
+                    if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
+                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+                        try {
+                            mNetd.removeRoute(ifaceName, r);
+                        } catch (Exception e) {
+                            // never crash - catch them all
+                            if (DBG) loge("Exception trying to remove a route: " + e);
+                        }
                     }
                 }
             }
@@ -2449,13 +2635,33 @@
         return routesChanged;
     }
 
-
    /**
+     * Reads the network specific MTU size from reources.
+     * and set it on it's iface.
+     */
+   private void updateMtuSizeSettings(NetworkStateTracker nt) {
+       final String iface = nt.getLinkProperties().getInterfaceName();
+       final int mtu = nt.getLinkProperties().getMtu();
+
+       if (mtu < 68 || mtu > 10000) {
+           loge("Unexpected mtu value: " + nt);
+           return;
+       }
+
+       try {
+           if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
+           mNetd.setMtu(iface, mtu);
+       } catch (Exception e) {
+           Slog.e(TAG, "exception in setMtu()" + e);
+       }
+   }
+
+    /**
      * Reads the network specific TCP buffer sizes from SystemProperties
      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
      * wide use
      */
-   private void updateNetworkSettings(NetworkStateTracker nt) {
+    private void updateNetworkSettings(NetworkStateTracker nt) {
         String key = nt.getTcpBufferSizesPropName();
         String bufferSizes = key == null ? null : SystemProperties.get(key);
 
@@ -2477,7 +2683,7 @@
         }
     }
 
-   /**
+    /**
      * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
      * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
      *
@@ -2560,7 +2766,7 @@
 
     // Caller must grab mDnsLock.
     private void updateDnsLocked(String network, String iface,
-            Collection<InetAddress> dnses, String domains) {
+            Collection<InetAddress> dnses, String domains, boolean defaultDns) {
         int last = 0;
         if (dnses.size() == 0 && mDefaultDns != null) {
             dnses = new ArrayList();
@@ -2572,7 +2778,10 @@
 
         try {
             mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
-            mNetd.setDefaultInterfaceForDns(iface);
+            if (defaultDns) {
+                mNetd.setDefaultInterfaceForDns(iface);
+            }
+
             for (InetAddress dns : dnses) {
                 ++last;
                 String key = "net.dns" + last;
@@ -2599,9 +2808,7 @@
             if (mNetConfigs[netType].isDefault()) {
                 String network = nt.getNetworkInfo().getTypeName();
                 synchronized (mDnsLock) {
-                    if (!mDnsOverridden) {
-                        updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains());
-                    }
+                    updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true);
                 }
             } else {
                 try {
@@ -2725,27 +2932,33 @@
         public void handleMessage(Message msg) {
             NetworkInfo info;
             switch (msg.what) {
-                case NetworkStateTracker.EVENT_STATE_CHANGED:
+                case NetworkStateTracker.EVENT_STATE_CHANGED: {
                     info = (NetworkInfo) msg.obj;
-                    int type = info.getType();
                     NetworkInfo.State state = info.getState();
 
                     if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
-                            (state == NetworkInfo.State.DISCONNECTED)) {
+                            (state == NetworkInfo.State.DISCONNECTED) ||
+                            (state == NetworkInfo.State.SUSPENDED)) {
                         log("ConnectivityChange for " +
                             info.getTypeName() + ": " +
                             state + "/" + info.getDetailedState());
                     }
 
-                    // After booting we'll check once for mobile provisioning
-                    // if we've provisioned by and connected.
-                    if (!mFirstProvisioningCheckStarted
+                    // Since mobile has the notion of a network/apn that can be used for
+                    // provisioning we need to check every time we're connected as
+                    // CaptiveProtalTracker won't detected it because DCT doesn't report it
+                    // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its
+                    // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which
+                    // is received by MDST and sent here as EVENT_STATE_CHANGED.
+                    if (ConnectivityManager.isNetworkTypeMobile(info.getType())
                             && (0 != Settings.Global.getInt(mContext.getContentResolver(),
                                         Settings.Global.DEVICE_PROVISIONED, 0))
-                            && (state == NetworkInfo.State.CONNECTED)) {
-                        log("check provisioning after booting");
-                        mFirstProvisioningCheckStarted = true;
-                        checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null);
+                            && (((state == NetworkInfo.State.CONNECTED)
+                                    && (info.getType() == ConnectivityManager.TYPE_MOBILE))
+                                || info.isConnectedToProvisioningNetwork())) {
+                        log("ConnectivityChange checkMobileProvisioning for"
+                                + " TYPE_MOBILE or ProvisioningNetwork");
+                        checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS);
                     }
 
                     EventLogTags.writeConnectivityStateChanged(
@@ -2757,6 +2970,29 @@
                     } else if (info.getDetailedState() ==
                             DetailedState.CAPTIVE_PORTAL_CHECK) {
                         handleCaptivePortalTrackerCheck(info);
+                    } else if (info.isConnectedToProvisioningNetwork()) {
+                        /**
+                         * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING
+                         * for now its an in between network, its a network that
+                         * is actually a default network but we don't want it to be
+                         * announced as such to keep background applications from
+                         * trying to use it. It turns out that some still try so we
+                         * take the additional step of clearing any default routes
+                         * to the link that may have incorrectly setup by the lower
+                         * levels.
+                         */
+                        LinkProperties lp = getLinkProperties(info.getType());
+                        if (DBG) {
+                            log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp);
+                        }
+
+                        // Clear any default routes setup by the radio so
+                        // any activity by applications trying to use this
+                        // connection will fail until the provisioning network
+                        // is enabled.
+                        for (RouteInfo r : lp.getRoutes()) {
+                            removeRoute(lp, r, TO_DEFAULT_TABLE);
+                        }
                     } else if (state == NetworkInfo.State.DISCONNECTED) {
                         handleDisconnect(info);
                     } else if (state == NetworkInfo.State.SUSPENDED) {
@@ -2775,18 +3011,21 @@
                         mLockdownTracker.onNetworkInfoChanged(info);
                     }
                     break;
-                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
+                }
+                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: {
                     info = (NetworkInfo) msg.obj;
                     // TODO: Temporary allowing network configuration
                     //       change not resetting sockets.
                     //       @see bug/4455071
                     handleConnectivityChange(info.getType(), false);
                     break;
-                case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
+                }
+                case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
                     info = (NetworkInfo) msg.obj;
-                    type = info.getType();
+                    int type = info.getType();
                     updateNetworkSettings(mNetTrackers[type]);
                     break;
+                }
             }
         }
     }
@@ -2800,7 +3039,7 @@
         public void handleMessage(Message msg) {
             NetworkInfo info;
             switch (msg.what) {
-                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
+                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: {
                     String causedBy = null;
                     synchronized (ConnectivityService.this) {
                         if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
@@ -2813,56 +3052,44 @@
                         log("NetTransition Wakelock for " + causedBy + " released by timeout");
                     }
                     break;
-                case EVENT_RESTORE_DEFAULT_NETWORK:
+                }
+                case EVENT_RESTORE_DEFAULT_NETWORK: {
                     FeatureUser u = (FeatureUser)msg.obj;
                     u.expire();
                     break;
-                case EVENT_INET_CONDITION_CHANGE:
-                {
+                }
+                case EVENT_INET_CONDITION_CHANGE: {
                     int netType = msg.arg1;
                     int condition = msg.arg2;
                     handleInetConditionChange(netType, condition);
                     break;
                 }
-                case EVENT_INET_CONDITION_HOLD_END:
-                {
+                case EVENT_INET_CONDITION_HOLD_END: {
                     int netType = msg.arg1;
                     int sequence = msg.arg2;
                     handleInetConditionHoldEnd(netType, sequence);
                     break;
                 }
-                case EVENT_SET_NETWORK_PREFERENCE:
-                {
+                case EVENT_SET_NETWORK_PREFERENCE: {
                     int preference = msg.arg1;
                     handleSetNetworkPreference(preference);
                     break;
                 }
-                case EVENT_SET_MOBILE_DATA:
-                {
+                case EVENT_SET_MOBILE_DATA: {
                     boolean enabled = (msg.arg1 == ENABLED);
                     handleSetMobileData(enabled);
                     break;
                 }
-                case EVENT_APPLY_GLOBAL_HTTP_PROXY:
-                {
+                case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
                     handleDeprecatedGlobalHttpProxy();
                     break;
                 }
-                case EVENT_SET_DEPENDENCY_MET:
-                {
+                case EVENT_SET_DEPENDENCY_MET: {
                     boolean met = (msg.arg1 == ENABLED);
                     handleSetDependencyMet(msg.arg2, met);
                     break;
                 }
-                case EVENT_RESTORE_DNS:
-                {
-                    if (mActiveDefaultNetwork != -1) {
-                        handleDnsConfigurationChange(mActiveDefaultNetwork);
-                    }
-                    break;
-                }
-                case EVENT_SEND_STICKY_BROADCAST_INTENT:
-                {
+                case EVENT_SEND_STICKY_BROADCAST_INTENT: {
                     Intent intent = (Intent)msg.obj;
                     sendStickyBroadcast(intent);
                     break;
@@ -2891,6 +3118,11 @@
                         log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1
                                 + " != tag:" + tag);
                     }
+                    break;
+                }
+                case EVENT_SAMPLE_INTERVAL_ELAPSED: {
+                    handleNetworkSamplingTimeout();
+                    break;
                 }
             }
         }
@@ -2978,12 +3210,6 @@
         return mTethering.getTetheredIfaces();
     }
 
-    @Override
-    public String[] getTetheredIfacePairs() {
-        enforceTetherAccessPermission();
-        return mTethering.getTetheredIfacePairs();
-    }
-
     public String[] getTetheringErroredIfaces() {
         enforceTetherAccessPermission();
         return mTethering.getErroredIfaces();
@@ -3119,13 +3345,15 @@
         // of proxy info to all the JVMs.
         // enforceAccessPermission();
         synchronized (mProxyLock) {
-            if (mGlobalProxy != null) return mGlobalProxy;
-            return (mDefaultProxyDisabled ? null : mDefaultProxy);
+            ProxyProperties ret = mGlobalProxy;
+            if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
+            return ret;
         }
     }
 
     public void setGlobalProxy(ProxyProperties proxyProperties) {
         enforceConnectivityInternalPermission();
+
         synchronized (mProxyLock) {
             if (proxyProperties == mGlobalProxy) return;
             if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
@@ -3134,11 +3362,16 @@
             String host = "";
             int port = 0;
             String exclList = "";
-            if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
+            String pacFileUrl = "";
+            if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
+                    !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
                 mGlobalProxy = new ProxyProperties(proxyProperties);
                 host = mGlobalProxy.getHost();
                 port = mGlobalProxy.getPort();
                 exclList = mGlobalProxy.getExclusionList();
+                if (proxyProperties.getPacFileUrl() != null) {
+                    pacFileUrl = proxyProperties.getPacFileUrl();
+                }
             } else {
                 mGlobalProxy = null;
             }
@@ -3149,6 +3382,7 @@
                 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
                 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                         exclList);
+                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -3166,8 +3400,14 @@
         int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
         String exclList = Settings.Global.getString(res,
                 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
-        if (!TextUtils.isEmpty(host)) {
-            ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
+        String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
+        if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
+            ProxyProperties proxyProperties;
+            if (!TextUtils.isEmpty(pacFileUrl)) {
+                proxyProperties = new ProxyProperties(pacFileUrl);
+            } else {
+                proxyProperties = new ProxyProperties(host, port, exclList);
+            }
             synchronized (mProxyLock) {
                 mGlobalProxy = proxyProperties;
             }
@@ -3185,7 +3425,8 @@
     }
 
     private void handleApplyDefaultProxy(ProxyProperties proxy) {
-        if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
+        if (proxy != null && TextUtils.isEmpty(proxy.getHost())
+                && TextUtils.isEmpty(proxy.getPacFileUrl())) {
             proxy = null;
         }
         synchronized (mProxyLock) {
@@ -3205,6 +3446,10 @@
                 Settings.Global.HTTP_PROXY);
         if (!TextUtils.isEmpty(proxy)) {
             String data[] = proxy.split(":");
+            if (data.length == 0) {
+                return;
+            }
+
             String proxyHost =  data[0];
             int proxyPort = 8080;
             if (data.length > 1) {
@@ -3221,6 +3466,7 @@
 
     private void sendProxyBroadcast(ProxyProperties proxy) {
         if (proxy == null) proxy = new ProxyProperties("", 0, "");
+        if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
         if (DBG) log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
@@ -3315,8 +3561,12 @@
         throwIfLockdownEnabled();
         try {
             int type = mActiveDefaultNetwork;
+            int user = UserHandle.getUserId(Binder.getCallingUid());
             if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
-                mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
+                synchronized(mVpns) {
+                    mVpns.get(user).protect(socket,
+                            mNetTrackers[type].getLinkProperties().getInterfaceName());
+                }
                 return true;
             }
         } catch (Exception e) {
@@ -3340,7 +3590,27 @@
     @Override
     public boolean prepareVpn(String oldPackage, String newPackage) {
         throwIfLockdownEnabled();
-        return mVpn.prepare(oldPackage, newPackage);
+        int user = UserHandle.getUserId(Binder.getCallingUid());
+        synchronized(mVpns) {
+            return mVpns.get(user).prepare(oldPackage, newPackage);
+        }
+    }
+
+    @Override
+    public void markSocketAsUser(ParcelFileDescriptor socket, int uid) {
+        enforceMarkNetworkSocketPermission();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            int mark = mNetd.getMarkForUid(uid);
+            // Clear the mark on the socket if no mark is needed to prevent socket reuse issues
+            if (mark == -1) {
+                mark = 0;
+            }
+            NetworkUtils.markSocket(socket.getFd(), mark);
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /**
@@ -3353,7 +3623,10 @@
     @Override
     public ParcelFileDescriptor establishVpn(VpnConfig config) {
         throwIfLockdownEnabled();
-        return mVpn.establish(config);
+        int user = UserHandle.getUserId(Binder.getCallingUid());
+        synchronized(mVpns) {
+            return mVpns.get(user).establish(config);
+        }
     }
 
     /**
@@ -3367,7 +3640,10 @@
         if (egress == null) {
             throw new IllegalStateException("Missing active network connection");
         }
-        mVpn.startLegacyVpn(profile, mKeyStore, egress);
+        int user = UserHandle.getUserId(Binder.getCallingUid());
+        synchronized(mVpns) {
+            mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
+        }
     }
 
     /**
@@ -3379,7 +3655,24 @@
     @Override
     public LegacyVpnInfo getLegacyVpnInfo() {
         throwIfLockdownEnabled();
-        return mVpn.getLegacyVpnInfo();
+        int user = UserHandle.getUserId(Binder.getCallingUid());
+        synchronized(mVpns) {
+            return mVpns.get(user).getLegacyVpnInfo();
+        }
+    }
+
+    /**
+     * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
+     * not available in ConnectivityManager.
+     * Permissions are checked in Vpn class.
+     * @hide
+     */
+    @Override
+    public VpnConfig getVpnConfig() {
+        int user = UserHandle.getUserId(Binder.getCallingUid());
+        synchronized(mVpns) {
+            return mVpns.get(user).getVpnConfig();
+        }
     }
 
     /**
@@ -3400,7 +3693,7 @@
             mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget();
         }
 
-        public void override(List<String> dnsServers, List<String> searchDomains) {
+        public void override(String iface, List<String> dnsServers, List<String> searchDomains) {
             if (dnsServers == null) {
                 restore();
                 return;
@@ -3432,8 +3725,7 @@
 
             // Apply DNS changes.
             synchronized (mDnsLock) {
-                updateDnsLocked("VPN", "VPN", addresses, domains);
-                mDnsOverridden = true;
+                updateDnsLocked("VPN", iface, addresses, domains, false);
             }
 
             // Temporarily disable the default proxy (not global).
@@ -3448,12 +3740,6 @@
         }
 
         public void restore() {
-            synchronized (mDnsLock) {
-                if (mDnsOverridden) {
-                    mDnsOverridden = false;
-                    mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
-                }
-            }
             synchronized (mProxyLock) {
                 mDefaultProxyDisabled = false;
                 if (mGlobalProxy == null && mDefaultProxy != null) {
@@ -3461,6 +3747,67 @@
                 }
             }
         }
+
+        public void protect(ParcelFileDescriptor socket) {
+            try {
+                final int mark = mNetd.getMarkForProtect();
+                NetworkUtils.markSocket(socket.getFd(), mark);
+            } catch (RemoteException e) {
+            }
+        }
+
+        public void setRoutes(String interfaze, List<RouteInfo> routes) {
+            for (RouteInfo route : routes) {
+                try {
+                    mNetd.setMarkedForwardingRoute(interfaze, route);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
+        public void setMarkedForwarding(String interfaze) {
+            try {
+                mNetd.setMarkedForwarding(interfaze);
+            } catch (RemoteException e) {
+            }
+        }
+
+        public void clearMarkedForwarding(String interfaze) {
+            try {
+                mNetd.clearMarkedForwarding(interfaze);
+            } catch (RemoteException e) {
+            }
+        }
+
+        public void addUserForwarding(String interfaze, int uid) {
+            int uidStart = uid * UserHandle.PER_USER_RANGE;
+            int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1;
+            addUidForwarding(interfaze, uidStart, uidEnd);
+        }
+
+        public void clearUserForwarding(String interfaze, int uid) {
+            int uidStart = uid * UserHandle.PER_USER_RANGE;
+            int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1;
+            clearUidForwarding(interfaze, uidStart, uidEnd);
+        }
+
+        public void addUidForwarding(String interfaze, int uidStart, int uidEnd) {
+            try {
+                mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd);
+                mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
+            } catch (RemoteException e) {
+            }
+
+        }
+
+        public void clearUidForwarding(String interfaze, int uidStart, int uidEnd) {
+            try {
+                mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
+                mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd);
+            } catch (RemoteException e) {
+            }
+
+        }
     }
 
     @Override
@@ -3481,7 +3828,11 @@
             final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
             final VpnProfile profile = VpnProfile.decode(
                     profileName, mKeyStore.get(Credentials.VPN + profileName));
-            setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpn, profile));
+            int user = UserHandle.getUserId(Binder.getCallingUid());
+            synchronized(mVpns) {
+                setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),
+                            profile));
+            }
         } else {
             setLockdownTracker(null);
         }
@@ -3561,72 +3912,122 @@
                          enabled));
     }
 
+    private boolean isMobileDataStateTrackerReady() {
+        MobileDataStateTracker mdst =
+                (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+        return (mdst != null) && (mdst.isReady());
+    }
+
+    /**
+     * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
+     */
+
+    /**
+     * No connection was possible to the network.
+     * This is NOT a warm sim.
+     */
+    private static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
+
+    /**
+     * A connection was made to the internet, all is well.
+     * This is NOT a warm sim.
+     */
+    private static final int CMP_RESULT_CODE_CONNECTABLE = 1;
+
+    /**
+     * A connection was made but no dns server was available to resolve a name to address.
+     * This is NOT a warm sim since provisioning network is supported.
+     */
+    private static final int CMP_RESULT_CODE_NO_DNS = 2;
+
+    /**
+     * A connection was made but could not open a TCP connection.
+     * This is NOT a warm sim since provisioning network is supported.
+     */
+    private static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 3;
+
+    /**
+     * A connection was made but there was a redirection, we appear to be in walled garden.
+     * This is an indication of a warm sim on a mobile network such as T-Mobile.
+     */
+    private static final int CMP_RESULT_CODE_REDIRECTED = 4;
+
+    /**
+     * The mobile network is a provisioning network.
+     * This is an indication of a warm sim on a mobile network such as AT&T.
+     */
+    private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5;
+
+    private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false);
+
     @Override
-    public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
-            final ResultReceiver resultReceiver) {
-        log("checkMobileProvisioning: E sendNotification=" + sendNotification
-                + " suggestedTimeOutMs=" + suggestedTimeOutMs
-                + " resultReceiver=" + resultReceiver);
-        enforceChangePermission();
-
-        mFirstProvisioningCheckStarted = true;
-
-        int timeOutMs = suggestedTimeOutMs;
-        if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
-            timeOutMs = CheckMp.MAX_TIMEOUT_MS;
-        }
-
-        // Check that mobile networks are supported
-        if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE)
-                || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) {
-            log("checkMobileProvisioning: X no mobile network");
-            if (resultReceiver != null) {
-                resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null);
-            }
-            return timeOutMs;
-        }
+    public int checkMobileProvisioning(int suggestedTimeOutMs) {
+        int timeOutMs = -1;
+        if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs);
+        enforceConnectivityInternalPermission();
 
         final long token = Binder.clearCallingIdentity();
         try {
+            timeOutMs = suggestedTimeOutMs;
+            if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
+                timeOutMs = CheckMp.MAX_TIMEOUT_MS;
+            }
+
+            // Check that mobile networks are supported
+            if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE)
+                    || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) {
+                if (DBG) log("checkMobileProvisioning: X no mobile network");
+                return timeOutMs;
+            }
+
+            // If we're already checking don't do it again
+            // TODO: Add a queue of results...
+            if (mIsCheckingMobileProvisioning.getAndSet(true)) {
+                if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment");
+                return timeOutMs;
+            }
+
+            // Start off with notification off
+            setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null);
+
             CheckMp checkMp = new CheckMp(mContext, this);
             CheckMp.CallBack cb = new CheckMp.CallBack() {
                 @Override
                 void onComplete(Integer result) {
-                    log("CheckMp.onComplete: result=" + result);
-                    if (resultReceiver != null) {
-                        log("CheckMp.onComplete: send result");
-                        resultReceiver.send(result, null);
-                    }
+                    if (DBG) log("CheckMp.onComplete: result=" + result);
                     NetworkInfo ni =
                             mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo();
                     switch(result) {
-                        case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE:
-                        case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: {
-                            log("CheckMp.onComplete: ignore, connected or no connection");
+                        case CMP_RESULT_CODE_CONNECTABLE:
+                        case CMP_RESULT_CODE_NO_CONNECTION:
+                        case CMP_RESULT_CODE_NO_DNS:
+                        case CMP_RESULT_CODE_NO_TCP_CONNECTION: {
+                            if (DBG) log("CheckMp.onComplete: ignore, connected or no connection");
                             break;
                         }
-                        case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: {
-                            log("CheckMp.onComplete: warm sim");
+                        case CMP_RESULT_CODE_REDIRECTED: {
+                            if (DBG) log("CheckMp.onComplete: warm sim");
                             String url = getMobileProvisioningUrl();
                             if (TextUtils.isEmpty(url)) {
                                 url = getMobileRedirectedProvisioningUrl();
                             }
                             if (TextUtils.isEmpty(url) == false) {
-                                log("CheckMp.onComplete: warm sim (redirected), url=" + url);
-                                setNotificationVisible(true, ni, url);
+                                if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url);
+                                setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(),
+                                        url);
                             } else {
-                                log("CheckMp.onComplete: warm sim (redirected), no url");
+                                if (DBG) log("CheckMp.onComplete: warm (redirected), no url");
                             }
                             break;
                         }
-                        case ConnectivityManager.CMP_RESULT_CODE_NO_DNS:
-                        case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: {
+                        case CMP_RESULT_CODE_PROVISIONING_NETWORK: {
                             String url = getMobileProvisioningUrl();
                             if (TextUtils.isEmpty(url) == false) {
-                                log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url);
-                                setNotificationVisible(true, ni, url);
+                                if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url);
+                                setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(),
+                                        url);
                             } else {
-                                log("CheckMp.onComplete: warm sim (no dns/tcp), no url");
+                                if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url");
                             }
                             break;
                         }
@@ -3635,16 +4036,16 @@
                             break;
                         }
                     }
+                    mIsCheckingMobileProvisioning.set(false);
                 }
             };
             CheckMp.Params params =
                     new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
-            log("checkMobileProvisioning: params=" + params);
-            setNotificationVisible(false, null, null);
+            if (DBG) log("checkMobileProvisioning: params=" + params);
             checkMp.execute(params);
         } finally {
             Binder.restoreCallingIdentity(token);
-            log("checkMobileProvisioning: X");
+            if (DBG) log("checkMobileProvisioning: X");
         }
         return timeOutMs;
     }
@@ -3716,27 +4117,72 @@
          * a known address that fetches the data we expect.
          */
         private synchronized Integer isMobileOk(Params params) {
-            Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+            Integer result = CMP_RESULT_CODE_NO_CONNECTION;
             Uri orgUri = Uri.parse(params.mUrl);
             Random rand = new Random();
             mParams = params;
 
+            if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
+                result = CMP_RESULT_CODE_NO_CONNECTION;
+                log("isMobileOk: X not mobile capable result=" + result);
+                return result;
+            }
+
+            // See if we've already determined we've got a provisioning connection,
+            // if so we don't need to do anything active.
+            MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
+                    mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+            boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
+            log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning);
+
+            MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
+                    mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+            boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
+            log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning);
+
+            if (isDefaultProvisioning || isHipriProvisioning) {
+                result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
+                log("isMobileOk: X default || hipri is provisioning result=" + result);
+                return result;
+            }
+
             try {
-                if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
-                    log("isMobileOk: not mobile capable");
-                    result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
-                    return result;
-                }
-
-                // Enable fail fast as we'll do retries here and use a
-                // hipri connection so the default connection stays active.
-                log("isMobileOk: start hipri url=" + params.mUrl);
-                mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
-                mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                        Phone.FEATURE_ENABLE_HIPRI, new Binder());
-
                 // Continue trying to connect until time has run out
                 long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs;
+
+                if (!mCs.isMobileDataStateTrackerReady()) {
+                    // Wait for MobileDataStateTracker to be ready.
+                    if (DBG) log("isMobileOk: mdst is not ready");
+                    while(SystemClock.elapsedRealtime() < endTime) {
+                        if (mCs.isMobileDataStateTrackerReady()) {
+                            // Enable fail fast as we'll do retries here and use a
+                            // hipri connection so the default connection stays active.
+                            if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data");
+                            mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
+                            break;
+                        }
+                        sleep(1);
+                    }
+                }
+
+                log("isMobileOk: start hipri url=" + params.mUrl);
+
+                // First wait until we can start using hipri
+                Binder binder = new Binder();
+                while(SystemClock.elapsedRealtime() < endTime) {
+                    int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+                            Phone.FEATURE_ENABLE_HIPRI, binder);
+                    if ((ret == PhoneConstants.APN_ALREADY_ACTIVE)
+                        || (ret == PhoneConstants.APN_REQUEST_STARTED)) {
+                            log("isMobileOk: hipri started");
+                            break;
+                    }
+                    if (VDBG) log("isMobileOk: hipri not started yet");
+                    result = CMP_RESULT_CODE_NO_CONNECTION;
+                    sleep(1);
+                }
+
+                // Continue trying to connect until time has run out
                 while(SystemClock.elapsedRealtime() < endTime) {
                     try {
                         // Wait for hipri to connect.
@@ -3745,13 +4191,26 @@
                         NetworkInfo.State state = mCs
                                 .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
                         if (state != NetworkInfo.State.CONNECTED) {
-                            log("isMobileOk: not connected ni=" +
+                            if (true/*VDBG*/) {
+                                log("isMobileOk: not connected ni=" +
                                     mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
+                            }
                             sleep(1);
-                            result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+                            result = CMP_RESULT_CODE_NO_CONNECTION;
                             continue;
                         }
 
+                        // Hipri has started check if this is a provisioning url
+                        MobileDataStateTracker mdst = (MobileDataStateTracker)
+                                mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+                        if (mdst.isProvisioningNetwork()) {
+                            result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
+                            if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result);
+                            return result;
+                        } else {
+                            if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue");
+                        }
+
                         // Get of the addresses associated with the url host. We need to use the
                         // address otherwise HttpURLConnection object will use the name to get
                         // the addresses and is will try every address but that will bypass the
@@ -3761,8 +4220,8 @@
                         try {
                             addresses = InetAddress.getAllByName(orgUri.getHost());
                         } catch (UnknownHostException e) {
-                            log("isMobileOk: UnknownHostException");
-                            result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS;
+                            result = CMP_RESULT_CODE_NO_DNS;
+                            log("isMobileOk: X UnknownHostException result=" + result);
                             return result;
                         }
                         log("isMobileOk: addresses=" + inetAddressesToString(addresses));
@@ -3770,8 +4229,8 @@
                         // Get the type of addresses supported by this link
                         LinkProperties lp = mCs.getLinkProperties(
                                 ConnectivityManager.TYPE_MOBILE_HIPRI);
-                        boolean linkHasIpv4 = hasIPv4Address(lp);
-                        boolean linkHasIpv6 = hasIPv6Address(lp);
+                        boolean linkHasIpv4 = lp.hasIPv4Address();
+                        boolean linkHasIpv6 = lp.hasIPv6Address();
                         log("isMobileOk: linkHasIpv4=" + linkHasIpv4
                                 + " linkHasIpv6=" + linkHasIpv6);
 
@@ -3826,25 +4285,38 @@
                                 urlConn.setAllowUserInteraction(false);
                                 urlConn.setRequestProperty("Connection", "close");
                                 int responseCode = urlConn.getResponseCode();
-                                if (responseCode == 204) {
-                                    result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE;
-                                } else {
-                                    result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED;
-                                }
-                                log("isMobileOk: connected responseCode=" + responseCode);
+
+                                // For debug display the headers
+                                Map<String, List<String>> headers = urlConn.getHeaderFields();
+                                log("isMobileOk: headers=" + headers);
+
+                                // Close the connection
                                 urlConn.disconnect();
                                 urlConn = null;
-                                return result;
+
+                                if (responseCode == 204) {
+                                    // Return
+                                    result = CMP_RESULT_CODE_CONNECTABLE;
+                                    log("isMobileOk: X expected responseCode=" + responseCode
+                                            + " result=" + result);
+                                    return result;
+                                } else {
+                                    // Retry to be sure this was redirected, we've gotten
+                                    // occasions where a server returned 200 even though
+                                    // the device didn't have a "warm" sim.
+                                    log("isMobileOk: not expected responseCode=" + responseCode);
+                                    result = CMP_RESULT_CODE_REDIRECTED;
+                                }
                             } catch (Exception e) {
                                 log("isMobileOk: HttpURLConnection Exception e=" + e);
+                                result = CMP_RESULT_CODE_NO_TCP_CONNECTION;
                                 if (urlConn != null) {
                                     urlConn.disconnect();
                                     urlConn = null;
                                 }
                             }
                         }
-                        result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION;
-                        log("isMobileOk: loops|timed out");
+                        log("isMobileOk: X loops|timed out result=" + result);
                         return result;
                     } catch (Exception e) {
                         log("isMobileOk: Exception e=" + e);
@@ -3857,6 +4329,23 @@
                 mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
                 mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                         Phone.FEATURE_ENABLE_HIPRI);
+
+                // Wait for hipri to disconnect.
+                long endTime = SystemClock.elapsedRealtime() + 5000;
+
+                while(SystemClock.elapsedRealtime() < endTime) {
+                    NetworkInfo.State state = mCs
+                            .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
+                    if (state != NetworkInfo.State.DISCONNECTED) {
+                        if (VDBG) {
+                            log("isMobileOk: connected ni=" +
+                                mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
+                        }
+                        sleep(1);
+                        continue;
+                    }
+                }
+
                 log("isMobileOk: X result=" + result);
             }
             return result;
@@ -3917,29 +4406,59 @@
             }
         }
 
-        public boolean hasIPv4Address(LinkProperties lp) {
-            return lp.hasIPv4Address();
-        }
-
-        // Not implemented in LinkProperties, do it here.
-        public boolean hasIPv6Address(LinkProperties lp) {
-            for (LinkAddress address : lp.getLinkAddresses()) {
-              if (address.getAddress() instanceof Inet6Address) {
-                return true;
-              }
-            }
-            return false;
-        }
-
         private void log(String s) {
             Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
         }
     }
 
-    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+    // TODO: Move to ConnectivityManager and make public?
+    private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION =
+            "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION";
 
-    private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) {
-        log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url);
+    private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) {
+                handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL"));
+            }
+        }
+    };
+
+    private void handleMobileProvisioningAction(String url) {
+        // Notication mark notification as not visible
+        setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null);
+
+        // If provisioning network handle as a special case,
+        // otherwise launch browser with the intent directly.
+        NetworkInfo ni = getProvisioningNetworkInfo();
+        if ((ni != null) && ni.isConnectedToProvisioningNetwork()) {
+            if (DBG) log("handleMobileProvisioningAction: on provisioning network");
+            MobileDataStateTracker mdst = (MobileDataStateTracker)
+                    mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+            mdst.enableMobileProvisioning(url);
+        } else {
+            if (DBG) log("handleMobileProvisioningAction: on default network");
+            Intent newIntent =
+                    new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+            newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+                    Intent.FLAG_ACTIVITY_NEW_TASK);
+            try {
+                mContext.startActivity(newIntent);
+            } catch (ActivityNotFoundException e) {
+                loge("handleMobileProvisioningAction: startActivity failed" + e);
+            }
+        }
+    }
+
+    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+    private volatile boolean mIsNotificationVisible = false;
+
+    private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo,
+            String url) {
+        if (DBG) {
+            log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType
+                + " extraInfo=" + extraInfo + " url=" + url);
+        }
 
         Resources r = Resources.getSystem();
         NotificationManager notificationManager = (NotificationManager) mContext
@@ -3949,50 +4468,64 @@
             CharSequence title;
             CharSequence details;
             int icon;
-            switch (networkInfo.getType()) {
+            Intent intent;
+            Notification notification = new Notification();
+            switch (networkType) {
                 case ConnectivityManager.TYPE_WIFI:
-                    log("setNotificationVisible: TYPE_WIFI");
                     title = r.getString(R.string.wifi_available_sign_in, 0);
                     details = r.getString(R.string.network_available_sign_in_detailed,
-                            networkInfo.getExtraInfo());
+                            extraInfo);
                     icon = R.drawable.stat_notify_wifi_in_range;
+                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+                    intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+                            Intent.FLAG_ACTIVITY_NEW_TASK);
+                    notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
                     break;
                 case ConnectivityManager.TYPE_MOBILE:
                 case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                    log("setNotificationVisible: TYPE_MOBILE|HIPRI");
                     title = r.getString(R.string.network_available_sign_in, 0);
                     // TODO: Change this to pull from NetworkInfo once a printable
                     // name has been added to it
                     details = mTelephonyManager.getNetworkOperatorName();
                     icon = R.drawable.stat_notify_rssi_in_range;
+                    intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
+                    intent.putExtra("EXTRA_URL", url);
+                    intent.setFlags(0);
+                    notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
                     break;
                 default:
-                    log("setNotificationVisible: other type=" + networkInfo.getType());
                     title = r.getString(R.string.network_available_sign_in, 0);
                     details = r.getString(R.string.network_available_sign_in_detailed,
-                            networkInfo.getExtraInfo());
+                            extraInfo);
                     icon = R.drawable.stat_notify_rssi_in_range;
+                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+                    intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+                            Intent.FLAG_ACTIVITY_NEW_TASK);
+                    notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
                     break;
             }
 
-            Notification notification = new Notification();
             notification.when = 0;
             notification.icon = icon;
             notification.flags = Notification.FLAG_AUTO_CANCEL;
-            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-            intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
-                    Intent.FLAG_ACTIVITY_NEW_TASK);
-            notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
             notification.tickerText = title;
             notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
 
-            log("setNotificaitionVisible: notify notificaiton=" + notification);
-            notificationManager.notify(NOTIFICATION_ID, 1, notification);
+            try {
+                notificationManager.notify(NOTIFICATION_ID, 1, notification);
+            } catch (NullPointerException npe) {
+                loge("setNotificaitionVisible: visible notificationManager npe=" + npe);
+                npe.printStackTrace();
+            }
         } else {
-            log("setNotificaitionVisible: cancel");
-            notificationManager.cancel(NOTIFICATION_ID, 1);
+            try {
+                notificationManager.cancel(NOTIFICATION_ID, 1);
+            } catch (NullPointerException npe) {
+                loge("setNotificaitionVisible: cancel notificationManager npe=" + npe);
+                npe.printStackTrace();
+            }
         }
-        log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url);
+        mIsNotificationVisible = visible;
     }
 
     /** Location to an updatable file listing carrier provisioning urls.
@@ -4086,7 +4619,9 @@
         return null;
     }
 
-    private String getMobileRedirectedProvisioningUrl() {
+    @Override
+    public String getMobileRedirectedProvisioningUrl() {
+        enforceConnectivityInternalPermission();
         String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING);
         if (TextUtils.isEmpty(url)) {
             url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url);
@@ -4094,14 +4629,15 @@
         return url;
     }
 
+    @Override
     public String getMobileProvisioningUrl() {
         enforceConnectivityInternalPermission();
         String url = getProvisioningUrlBaseFromFile(PROVISIONING);
         if (TextUtils.isEmpty(url)) {
             url = mContext.getResources().getString(R.string.mobile_provisioning_url);
-            log("getProvisioningUrl: mobile_provisioining_url from resource =" + url);
+            log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url);
         } else {
-            log("getProvisioningUrl: mobile_provisioning_url from File =" + url);
+            log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url);
         }
         // populate the iccid, imei and phone number in the provisioning url.
         if (!TextUtils.isEmpty(url)) {
@@ -4117,4 +4653,152 @@
 
         return url;
     }
+
+    @Override
+    public void setProvisioningNotificationVisible(boolean visible, int networkType,
+            String extraInfo, String url) {
+        enforceConnectivityInternalPermission();
+        setProvNotificationVisible(visible, networkType, extraInfo, url);
+    }
+
+    @Override
+    public void setAirplaneMode(boolean enable) {
+        enforceConnectivityInternalPermission();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            final ContentResolver cr = mContext.getContentResolver();
+            Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
+            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+            intent.putExtra("state", enable);
+            mContext.sendBroadcast(intent);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void onUserStart(int userId) {
+        synchronized(mVpns) {
+            Vpn userVpn = mVpns.get(userId);
+            if (userVpn != null) {
+                loge("Starting user already has a VPN");
+                return;
+            }
+            userVpn = new Vpn(mContext, mVpnCallback, mNetd, this, userId);
+            mVpns.put(userId, userVpn);
+            userVpn.startMonitoring(mContext, mTrackerHandler);
+        }
+    }
+
+    private void onUserStop(int userId) {
+        synchronized(mVpns) {
+            Vpn userVpn = mVpns.get(userId);
+            if (userVpn == null) {
+                loge("Stopping user has no VPN");
+                return;
+            }
+            mVpns.delete(userId);
+        }
+    }
+
+    private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+            if (userId == UserHandle.USER_NULL) return;
+
+            if (Intent.ACTION_USER_STARTING.equals(action)) {
+                onUserStart(userId);
+            } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+                onUserStop(userId);
+            }
+        }
+    };
+
+    @Override
+    public LinkQualityInfo getLinkQualityInfo(int networkType) {
+        enforceAccessPermission();
+        if (isNetworkTypeValid(networkType)) {
+            return mNetTrackers[networkType].getLinkQualityInfo();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public LinkQualityInfo getActiveLinkQualityInfo() {
+        enforceAccessPermission();
+        if (isNetworkTypeValid(mActiveDefaultNetwork)) {
+            return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public LinkQualityInfo[] getAllLinkQualityInfo() {
+        enforceAccessPermission();
+        final ArrayList<LinkQualityInfo> result = Lists.newArrayList();
+        for (NetworkStateTracker tracker : mNetTrackers) {
+            if (tracker != null) {
+                LinkQualityInfo li = tracker.getLinkQualityInfo();
+                if (li != null) {
+                    result.add(li);
+                }
+            }
+        }
+
+        return result.toArray(new LinkQualityInfo[result.size()]);
+    }
+
+    /* Infrastructure for network sampling */
+
+    private void handleNetworkSamplingTimeout() {
+
+        log("Sampling interval elapsed, updating statistics ..");
+
+        // initialize list of interfaces ..
+        Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample =
+                new HashMap<String, SamplingDataTracker.SamplingSnapshot>();
+        for (NetworkStateTracker tracker : mNetTrackers) {
+            if (tracker != null) {
+                String ifaceName = tracker.getNetworkInterfaceName();
+                if (ifaceName != null) {
+                    mapIfaceToSample.put(ifaceName, null);
+                }
+            }
+        }
+
+        // Read samples for all interfaces
+        SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample);
+
+        // process samples for all networks
+        for (NetworkStateTracker tracker : mNetTrackers) {
+            if (tracker != null) {
+                String ifaceName = tracker.getNetworkInterfaceName();
+                SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName);
+                if (ss != null) {
+                    // end the previous sampling cycle
+                    tracker.stopSampling(ss);
+                    // start a new sampling cycle ..
+                    tracker.startSampling(ss);
+                }
+            }
+        }
+
+        log("Done.");
+
+        int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
+                DEFAULT_SAMPLING_INTERVAL_IN_SECONDS);
+
+        if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
+
+        setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent);
+    }
+
+    void setAlarm(int timeoutInMilliseconds, PendingIntent intent) {
+        long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
+    }
 }
diff --git a/services/java/com/android/server/ConsumerIrService.java b/services/java/com/android/server/ConsumerIrService.java
new file mode 100644
index 0000000..07f2a41
--- /dev/null
+++ b/services/java/com/android/server/ConsumerIrService.java
@@ -0,0 +1,130 @@
+/*
+ * 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.hardware.input.InputManager;
+import android.hardware.IConsumerIrService;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Binder;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Slog;
+import android.view.InputDevice;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+public class ConsumerIrService extends IConsumerIrService.Stub {
+    private static final String TAG = "ConsumerIrService";
+
+    private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
+
+    private static native int halOpen();
+    private static native int halTransmit(int halObject, int carrierFrequency, int[] pattern);
+    private static native int[] halGetCarrierFrequencies(int halObject);
+
+    private final Context mContext;
+    private final PowerManager.WakeLock mWakeLock;
+    private final int mHal;
+    private final Object mHalLock = new Object();
+
+    ConsumerIrService(Context context) {
+        mContext = context;
+        PowerManager pm = (PowerManager)context.getSystemService(
+                Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mWakeLock.setReferenceCounted(true);
+
+        mHal = halOpen();
+        if (mHal == 0) {
+            Slog.w(TAG, "No IR HAL loaded");
+        }
+    }
+
+    @Override
+    public boolean hasIrEmitter() {
+        return mHal != 0;
+    }
+
+    private void throwIfNoIrEmitter() {
+        if (mHal == 0) {
+            throw new UnsupportedOperationException("IR emitter not available");
+        }
+    }
+
+
+    @Override
+    public void transmit(String packageName, int carrierFrequency, int[] pattern) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires TRANSMIT_IR permission");
+        }
+
+        long totalXmitTime = 0;
+
+        for (int slice : pattern) {
+            if (slice <= 0) {
+                throw new IllegalArgumentException("Non-positive IR slice");
+            }
+            totalXmitTime += slice;
+        }
+
+        if (totalXmitTime > MAX_XMIT_TIME ) {
+            throw new IllegalArgumentException("IR pattern too long");
+        }
+
+        throwIfNoIrEmitter();
+
+        // Right now there is no mechanism to ensure fair queing of IR requests
+        synchronized (mHalLock) {
+            int err = halTransmit(mHal, carrierFrequency, pattern);
+
+            if (err < 0) {
+                Slog.e(TAG, "Error transmitting: " + err);
+            }
+        }
+    }
+
+    @Override
+    public int[] getCarrierFrequencies() {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires TRANSMIT_IR permission");
+        }
+
+        throwIfNoIrEmitter();
+
+        synchronized(mHalLock) {
+            return halGetCarrierFrequencies(mHal);
+        }
+    }
+}
diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/java/com/android/server/CountryDetectorService.java
index fc76277..a478b2f 100644
--- a/services/java/com/android/server/CountryDetectorService.java
+++ b/services/java/com/android/server/CountryDetectorService.java
@@ -20,6 +20,7 @@
 import java.io.PrintWriter;
 import java.util.HashMap;
 
+import com.android.internal.os.BackgroundThread;
 import com.android.server.location.ComprehensiveCountryDetector;
 
 import android.content.Context;
@@ -29,8 +30,6 @@
 import android.location.ICountryListener;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
-import android.os.Process;
 import android.os.RemoteException;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -98,11 +97,12 @@
     }
 
     @Override
-    public Country detectCountry() throws RemoteException {
+    public Country detectCountry() {
         if (!mSystemReady) {
-            throw new RemoteException();
+            return null;   // server not yet active
+        } else {
+            return mCountryDetector.detectCountry();
         }
-        return mCountryDetector.detectCountry();
     }
 
     /**
@@ -167,10 +167,9 @@
         }
     }
 
-    void systemReady() {
+    void systemRunning() {
         // Shall we wait for the initialization finish.
-        Thread thread = new Thread(this, "CountryDetectorService");
-        thread.start();
+        BackgroundThread.getHandler().post(this);
     }
 
     private void initialize() {
@@ -187,12 +186,9 @@
     }
 
     public void run() {
-        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-        Looper.prepare();
         mHandler = new Handler();
         initialize();
         mSystemReady = true;
-        Looper.loop();
     }
 
     protected void setCountryListener(final CountryListener listener) {
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 7ecd2c0..8cc80f7 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -16,11 +16,15 @@
 
 package com.android.server;
 
+import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+
+import com.android.internal.R;
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.org.conscrypt.TrustedCertificateStore;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -30,6 +34,9 @@
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DeviceAdminReceiver;
@@ -48,7 +55,9 @@
 import android.content.pm.Signature;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -66,7 +75,12 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.Credentials;
+import android.security.IKeyChainService;
+import android.security.KeyChain;
+import android.security.KeyChain.KeyChainConnection;
 import android.util.AtomicFile;
+import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
@@ -75,6 +89,7 @@
 import android.view.IWindowManager;
 import android.view.WindowManagerPolicy;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -82,8 +97,15 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.security.KeyStore.TrustedCertificateEntry;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -107,6 +129,8 @@
     protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
             = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
 
+    private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+
     private static final boolean DBG = false;
 
     final Context mContext;
@@ -114,9 +138,16 @@
 
     IPowerManager mIPowerManager;
     IWindowManager mIWindowManager;
+    NotificationManager mNotificationManager;
 
     private DeviceOwner mDeviceOwner;
 
+    /**
+     * Whether or not device admin feature is supported. If it isn't return defaults for all
+     * public methods.
+     */
+    private boolean mHasFeature;
+
     public static class DevicePolicyData {
         int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         int mActivePasswordLength = 0;
@@ -161,7 +192,12 @@
                         handlePasswordExpirationNotification(getUserData(userHandle));
                     }
                 });
-            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+            }
+            if (Intent.ACTION_BOOT_COMPLETED.equals(action)
+                    || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
+                manageMonitoringCertificateNotification(intent);
+            }
+            if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 removeUserData(userHandle);
             } else if (Intent.ACTION_USER_STARTED.equals(action)
                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -503,13 +539,20 @@
      */
     public DevicePolicyManagerService(Context context) {
         mContext = context;
+        mHasFeature = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_DEVICE_ADMIN);
         mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
+        if (!mHasFeature) {
+            // Skip the rest of the initialization
+            return;
+        }
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BOOT_COMPLETED);
         filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
         filter.addAction(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_STARTED);
+        filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -619,6 +662,14 @@
         return mIWindowManager;
     }
 
+    private NotificationManager getNotificationManager() {
+        if (mNotificationManager == null) {
+            mNotificationManager =
+                    (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        }
+        return mNotificationManager;
+    }
+
     ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
         ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
         if (admin != null
@@ -722,6 +773,9 @@
     }
 
     public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         enforceCrossUserPermission(userHandle);
         Intent resolveIntent = new Intent();
         resolveIntent.setComponent(adminName);
@@ -1011,6 +1065,9 @@
     }
 
     public void systemReady() {
+        if (!mHasFeature) {
+            return;
+        }
         synchronized (this) {
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
             loadDeviceOwner();
@@ -1037,13 +1094,73 @@
         }
     }
 
+    private void manageMonitoringCertificateNotification(Intent intent) {
+        final NotificationManager notificationManager = getNotificationManager();
+
+        final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
+        if (! hasCert) {
+            if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+                UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+                for (UserInfo user : um.getUsers()) {
+                    notificationManager.cancelAsUser(
+                            null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
+                }
+            }
+            return;
+        }
+        final boolean isManaged = getDeviceOwner() != null;
+        int smallIconId;
+        String contentText;
+        if (isManaged) {
+            contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
+                    getDeviceOwnerName());
+            smallIconId = R.drawable.stat_sys_certificate_info;
+        } else {
+            contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
+            smallIconId = android.R.drawable.stat_sys_warning;
+        }
+
+        Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
+        dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        dialogIntent.setPackage("com.android.settings");
+        // Notification will be sent individually to all users. The activity should start as
+        // whichever user is current when it starts.
+        PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
+
+        Notification noti = new Notification.Builder(mContext)
+            .setSmallIcon(smallIconId)
+            .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
+            .setContentText(contentText)
+            .setContentIntent(notifyIntent)
+            .setPriority(Notification.PRIORITY_HIGH)
+            .setShowWhen(false)
+            .build();
+
+        // If this is a boot intent, this will fire for each user. But if this is a storage changed
+        // intent, it will fire once, so we need to notify all users.
+        if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            for (UserInfo user : um.getUsers()) {
+                notificationManager.notifyAsUser(
+                        null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
+            }
+        } else {
+            notificationManager.notifyAsUser(
+                    null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
+        }
+    }
+
     /**
      * @param adminReceiver The admin to add
      * @param refreshing true = update an active admin, no error
      */
     public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+                android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
         enforceCrossUserPermission(userHandle);
 
         DevicePolicyData policy = getUserData(userHandle);
@@ -1085,6 +1202,9 @@
     }
 
     public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
@@ -1092,6 +1212,9 @@
     }
 
     public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1102,7 +1225,12 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
     public List<ComponentName> getActiveAdmins(int userHandle) {
+        if (!mHasFeature) {
+            return Collections.EMPTY_LIST;
+        }
+
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1119,6 +1247,9 @@
     }
 
     public boolean packageHasActiveAdmins(String packageName, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1133,6 +1264,9 @@
     }
 
     public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1146,7 +1280,7 @@
                     return;
                 }
                 mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+                        android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
             }
             long ident = Binder.clearCallingIdentity();
             try {
@@ -1158,6 +1292,9 @@
     }
 
     public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         validateQualityConstant(quality);
         enforceCrossUserPermission(userHandle);
 
@@ -1175,6 +1312,9 @@
     }
 
     public int getPasswordQuality(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -1197,6 +1337,9 @@
     }
 
     public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1212,6 +1355,9 @@
     }
 
     public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1234,6 +1380,9 @@
     }
 
     public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1249,6 +1398,9 @@
     }
 
     public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1271,6 +1423,9 @@
     }
 
     public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1301,6 +1456,9 @@
      * Returns 0 if not configured.
      */
     public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0L;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who != null) {
@@ -1346,6 +1504,9 @@
     }
 
     public long getPasswordExpiration(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0L;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             return getPasswordExpirationLocked(who, userHandle);
@@ -1353,6 +1514,9 @@
     }
 
     public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1368,6 +1532,9 @@
     }
 
     public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1405,6 +1572,9 @@
     }
 
     public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1427,6 +1597,9 @@
     }
 
     public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1442,6 +1615,9 @@
     }
 
     public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1464,6 +1640,9 @@
     }
 
     public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1479,6 +1658,9 @@
     }
 
     public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1501,6 +1683,9 @@
     }
 
     public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1516,6 +1701,9 @@
     }
 
     public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1538,6 +1726,9 @@
     }
 
     public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1553,6 +1744,9 @@
     }
 
     public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1575,6 +1769,9 @@
     }
 
     public boolean isActivePasswordSufficient(int userHandle) {
+        if (!mHasFeature) {
+            return true;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1610,6 +1807,9 @@
     }
 
     public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
@@ -1626,6 +1826,9 @@
     }
 
     public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1651,6 +1854,9 @@
     }
 
     public boolean resetPassword(String password, int flags, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         int quality;
         synchronized (this) {
@@ -1772,6 +1978,9 @@
     }
 
     public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1817,6 +2026,9 @@
     }
 
     public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             long time = 0;
@@ -1842,6 +2054,9 @@
     }
 
     public void lockNow() {
+        if (!mHasFeature) {
+            return;
+        }
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
@@ -1870,6 +2085,76 @@
         return !"".equals(state);
     }
 
+    public boolean installCaCert(byte[] certBuffer) throws RemoteException {
+        mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
+        KeyChainConnection keyChainConnection = null;
+        byte[] pemCert;
+        try {
+            X509Certificate cert = parseCert(certBuffer);
+            pemCert =  Credentials.convertToPem(cert);
+        } catch (CertificateException ce) {
+            Log.e(TAG, "Problem converting cert", ce);
+            return false;
+        } catch (IOException ioe) {
+            Log.e(TAG, "Problem reading cert", ioe);
+            return false;
+        }
+        try {
+            keyChainConnection = KeyChain.bind(mContext);
+            try {
+                keyChainConnection.getService().installCaCertificate(pemCert);
+                return true;
+            } finally {
+                if (keyChainConnection != null) {
+                    keyChainConnection.close();
+                    keyChainConnection = null;
+                }
+            }
+        } catch (InterruptedException e1) {
+            Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
+            Thread.currentThread().interrupt();
+        }
+        return false;
+    }
+
+    private static X509Certificate parseCert(byte[] certBuffer)
+            throws CertificateException, IOException {
+        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+        return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
+                certBuffer));
+    }
+
+    public void uninstallCaCert(final byte[] certBuffer) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
+        TrustedCertificateStore certStore = new TrustedCertificateStore();
+        String alias = null;
+        try {
+            X509Certificate cert = parseCert(certBuffer);
+            alias = certStore.getCertificateAlias(cert);
+        } catch (CertificateException ce) {
+            Log.e(TAG, "Problem creating X509Certificate", ce);
+            return;
+        } catch (IOException ioe) {
+            Log.e(TAG, "Problem reading certificate", ioe);
+            return;
+        }
+        try {
+            KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
+            IKeyChainService service = keyChainConnection.getService();
+            try {
+                service.deleteCaCertificate(alias);
+            } catch (RemoteException e) {
+                Log.e(TAG, "from CaCertUninstaller: ", e);
+            } finally {
+                keyChainConnection.close();
+                keyChainConnection = null;
+            }
+        } catch (InterruptedException ie) {
+            Log.w(TAG, "CaCertUninstaller: ", ie);
+            Thread.currentThread().interrupt();
+        }
+    }
+
     void wipeDataLocked(int flags) {
         // If the SD card is encrypted and non-removable, we have to force a wipe.
         boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
@@ -1892,6 +2177,9 @@
     }
 
     public void wipeData(int flags, final int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
@@ -1927,6 +2215,9 @@
     }
 
     public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -1957,6 +2248,9 @@
 
     public void setActivePasswordState(int quality, int length, int letters, int uppercase,
             int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -2023,12 +2317,14 @@
             try {
                 policy.mFailedPasswordAttempts++;
                 saveSettingsLocked(userHandle);
-                int max = getMaximumFailedPasswordsForWipe(null, userHandle);
-                if (max > 0 && policy.mFailedPasswordAttempts >= max) {
-                    wipeDeviceOrUserLocked(0, userHandle);
+                if (mHasFeature) {
+                    int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+                    if (max > 0 && policy.mFailedPasswordAttempts >= max) {
+                        wipeDeviceOrUserLocked(0, userHandle);
+                    }
+                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
+                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                 }
-                sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
-                        DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -2048,8 +2344,10 @@
                     policy.mFailedPasswordAttempts = 0;
                     policy.mPasswordOwner = -1;
                     saveSettingsLocked(userHandle);
-                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
-                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
+                    if (mHasFeature) {
+                        sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
+                                DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
+                    }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -2059,6 +2357,9 @@
 
     public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
             String exclusionList, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized(this) {
             if (who == null) {
@@ -2109,6 +2410,9 @@
     }
 
     public ComponentName getGlobalProxyAdmin(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized(this) {
             DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -2170,6 +2474,9 @@
      * status (for all admins).
      */
     public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+        if (!mHasFeature) {
+            return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // Check for permissions
@@ -2221,6 +2528,9 @@
      * active admins.
      */
     public boolean getStorageEncryption(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // Check for permissions if a particular caller is specified
@@ -2247,6 +2557,9 @@
      * Get the current encryption status of the device.
      */
     public int getStorageEncryptionStatus(int userHandle) {
+        if (!mHasFeature) {
+            // Ok to return current status.
+        }
         enforceCrossUserPermission(userHandle);
         return getEncryptionStatus();
     }
@@ -2295,6 +2608,9 @@
      * Disables all device cameras according to the specified admin.
      */
     public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -2315,6 +2631,9 @@
      * active admins.
      */
     public boolean getCameraDisabled(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         synchronized (this) {
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
@@ -2338,6 +2657,9 @@
      * Selectively disable keyguard features.
      */
     public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -2358,6 +2680,9 @@
      * or the aggregate of all active admins if who is null.
      */
     public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who != null) {
@@ -2378,7 +2703,10 @@
     }
 
     @Override
-    public boolean setDeviceOwner(String packageName) {
+    public boolean setDeviceOwner(String packageName, String ownerName) {
+        if (!mHasFeature) {
+            return false;
+        }
         if (packageName == null
                 || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
             throw new IllegalArgumentException("Invalid package name " + packageName
@@ -2386,7 +2714,7 @@
         }
         synchronized (this) {
             if (mDeviceOwner == null && !isDeviceProvisioned()) {
-                mDeviceOwner = new DeviceOwner(packageName);
+                mDeviceOwner = new DeviceOwner(packageName, ownerName);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             } else {
@@ -2399,6 +2727,9 @@
 
     @Override
     public boolean isDeviceOwner(String packageName) {
+        if (!mHasFeature) {
+            return false;
+        }
         synchronized (this) {
             return mDeviceOwner != null
                     && mDeviceOwner.getPackageName().equals(packageName);
@@ -2407,6 +2738,9 @@
 
     @Override
     public String getDeviceOwner() {
+        if (!mHasFeature) {
+            return null;
+        }
         synchronized (this) {
             if (mDeviceOwner != null) {
                 return mDeviceOwner.getPackageName();
@@ -2415,6 +2749,20 @@
         return null;
     }
 
+    @Override
+    public String getDeviceOwnerName() {
+        if (!mHasFeature) {
+            return null;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getName();
+            }
+        }
+        return null;
+    }
+
     private boolean isDeviceProvisioned() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
@@ -2488,15 +2836,18 @@
     static class DeviceOwner {
         private static final String DEVICE_OWNER_XML = "device_owner.xml";
         private static final String TAG_DEVICE_OWNER = "device-owner";
+        private static final String ATTR_NAME = "name";
         private static final String ATTR_PACKAGE = "package";
         private String mPackageName;
+        private String mOwnerName;
 
         DeviceOwner() {
             readOwnerFile();
         }
 
-        DeviceOwner(String packageName) {
+        DeviceOwner(String packageName, String ownerName) {
             this.mPackageName = packageName;
+            this.mOwnerName = ownerName;
         }
 
         static boolean isRegistered() {
@@ -2508,6 +2859,10 @@
             return mPackageName;
         }
 
+        String getName() {
+            return mOwnerName;
+        }
+
         static boolean isInstalled(String packageName, PackageManager pm) {
             try {
                 PackageInfo pi;
@@ -2539,6 +2894,7 @@
                             "Device Owner file does not start with device-owner tag: found " + tag);
                 }
                 mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
                 input.close();
             } catch (XmlPullParserException xppe) {
                 Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
@@ -2563,6 +2919,9 @@
                 out.startDocument(null, true);
                 out.startTag(null, TAG_DEVICE_OWNER);
                 out.attribute(null, ATTR_PACKAGE, mPackageName);
+                if (mOwnerName != null) {
+                    out.attribute(null, ATTR_NAME, mOwnerName);
+                }
                 out.endTag(null, TAG_DEVICE_OWNER);
                 out.endDocument();
                 out.flush();
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index 5008270..29b04da 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Debug;
 import android.os.DropBoxManager;
 import android.os.FileUtils;
@@ -265,8 +266,13 @@
     }
 
     public boolean isTagEnabled(String tag) {
-        return !"disabled".equals(Settings.Global.getString(
-                mContentResolver, Settings.Global.DROPBOX_TAG_PREFIX + tag));
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return !"disabled".equals(Settings.Global.getString(
+                    mContentResolver, Settings.Global.DROPBOX_TAG_PREFIX + tag));
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis) {
diff --git a/services/java/com/android/server/FgThread.java b/services/java/com/android/server/FgThread.java
new file mode 100644
index 0000000..3b655f2
--- /dev/null
+++ b/services/java/com/android/server/FgThread.java
@@ -0,0 +1,65 @@
+/*
+ * 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.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * Shared singleton foreground thread for the system.  This is a thread for regular
+ * foreground service operations, which shouldn't be blocked by anything running in
+ * the background.  In particular, the shared background thread could be doing
+ * relatively long-running operations like saving state to disk (in addition to
+ * simply being a background priority), which can cause operations scheduled on it
+ * to be delayed for a user-noticeable amount of time.
+ */
+public final class FgThread extends HandlerThread {
+    private static FgThread sInstance;
+    private static Handler sHandler;
+
+    private FgThread() {
+        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new FgThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+            sHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    android.os.Process.setCanSelfBackground(false);
+                }
+            });
+        }
+    }
+
+    public static FgThread get() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/java/com/android/server/IdleMaintenanceService.java
index 584d4bc..b0a1aca 100644
--- a/services/java/com/android/server/IdleMaintenanceService.java
+++ b/services/java/com/android/server/IdleMaintenanceService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.Activity;
+import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -24,12 +25,13 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.Slog;
 
 /**
  * This service observes the device state and when applicable sends
@@ -69,6 +71,9 @@
     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";
+
     private static final Intent sIdleMaintenanceStartIntent;
     static {
         sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
@@ -115,10 +120,10 @@
         mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
                 intent, PendingIntent.FLAG_UPDATE_CURRENT);
 
-        register(mContext.getMainLooper());
+        register(mHandler);
     }
 
-    public void register(Looper looper) {
+    public void register(Handler handler) {
         IntentFilter intentFilter = new IntentFilter();
 
         // Alarm actions.
@@ -136,7 +141,12 @@
         intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
 
         mContext.registerReceiverAsUser(this, UserHandle.ALL,
-                intentFilter, null, new Handler(looper));
+                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) {
@@ -149,7 +159,7 @@
         mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
     }
 
-    private void updateIdleMaintenanceState() {
+    private void updateIdleMaintenanceState(boolean noisy) {
         if (mIdleMaintenanceStarted) {
             // Idle maintenance can be interrupted by user activity, or duration
             // time out, or low battery.
@@ -170,9 +180,9 @@
                             getNextIdleMaintenanceIntervalStartFromNow());
                 }
             }
-        } else if (deviceStatePermitsIdleMaintenanceStart()
-                && lastUserActivityPermitsIdleMaintenanceStart()
-                && lastRunPermitsIdleMaintenanceStart()) {
+        } 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);
@@ -182,8 +192,8 @@
                     isBatteryCharging() ? 1 : 0);
             mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
             sendIdleMaintenanceStartIntent();
-        } else if (lastUserActivityPermitsIdleMaintenanceStart()) {
-             if (lastRunPermitsIdleMaintenanceStart()) {
+        } 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.
@@ -204,6 +214,10 @@
 
     private void sendIdleMaintenanceStartIntent() {
         mWakeLock.acquire();
+        try {
+            ActivityManagerNative.getDefault().performIdleMaintenance();
+        } catch (RemoteException e) {
+        }
         mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
                 null, this, mHandler, Activity.RESULT_OK, null, null);
     }
@@ -214,25 +228,37 @@
                 null, this, mHandler, Activity.RESULT_OK, null, null);
     }
 
-    private boolean deviceStatePermitsIdleMaintenanceStart() {
+    private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
         final int minBatteryLevel = isBatteryCharging()
                 ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
                 : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
-        return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+        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() {
+    private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
         // The last time the user poked the device is above the threshold.
-        return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+        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() {
+    private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
         // Enough time passed since the last maintenance run.
-        return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
+        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() {
@@ -266,7 +292,7 @@
             // next release. The only client for this for now is internal an holds
             // a wake lock correctly.
             if (mIdleMaintenanceStarted) {
-                updateIdleMaintenanceState();
+                updateIdleMaintenanceState(false);
             }
         } else if (Intent.ACTION_SCREEN_ON.equals(action)
                 || Intent.ACTION_DREAMING_STOPPED.equals(action)) {
@@ -276,7 +302,7 @@
             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.
-            updateIdleMaintenanceState();
+            updateIdleMaintenanceState(false);
         } else if (Intent.ACTION_SCREEN_OFF.equals(action)
                 || Intent.ACTION_DREAMING_STARTED.equals(action)) {
             mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
@@ -285,7 +311,12 @@
             // 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)) {
-            updateIdleMaintenanceState();
+            updateIdleMaintenanceState(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;
+            updateIdleMaintenanceState(true);
         } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
                 || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
             // We were holding a wake lock while broadcasting the idle maintenance
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c916857..794d274 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -791,6 +791,11 @@
         // InputMethodFileManager should be reset when the user is changed
         mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
         final String defaultImiId = mSettings.getSelectedInputMethod();
+        // For secondary users, the list of enabled IMEs may not have been updated since the
+        // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
+        // not be empty even if the IME has been uninstalled by the primary user.
+        // Even in such cases, IMMS works fine because it will find the most applicable
+        // IME for that user.
         final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
         if (DEBUG) {
             Slog.d(TAG, "Switch user: " + newUserId + " current ime = " + defaultImiId);
@@ -812,13 +817,13 @@
             // The input method manager only throws security exceptions, so let's
             // log all others.
             if (!(e instanceof SecurityException)) {
-                Slog.e(TAG, "Input Method Manager Crash", e);
+                Slog.wtf(TAG, "Input Method Manager Crash", e);
             }
             throw e;
         }
     }
 
-    public void systemReady(StatusBarManagerService statusBar) {
+    public void systemRunning(StatusBarManagerService statusBar) {
         synchronized (mMethodMap) {
             if (DEBUG) {
                 Slog.d(TAG, "--- systemReady");
@@ -894,7 +899,8 @@
             Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
                     + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
                     + " calling userId = " + userId + ", foreground user id = "
-                    + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
+                    + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
+                    + InputMethodUtils.getApiCallStack());
         }
         if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
             return true;
@@ -914,7 +920,8 @@
             }
             return true;
         }
-        Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
+        Slog.w(TAG, "--- IPC called from background users. Ignore. \n"
+                + InputMethodUtils.getStackTrace());
         return false;
     }
 
@@ -962,19 +969,25 @@
     }
 
     /**
-     * @param imi if null, returns enabled subtypes for the current imi
+     * @param imiId if null, returns enabled subtypes for the current imi
      * @return enabled subtypes of the specified imi
      */
     @Override
-    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
+    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
             boolean allowsImplicitlySelectedSubtypes) {
         // TODO: Make this work even for non-current users?
         if (!calledFromValidUser()) {
-            return Collections.emptyList();
+            return Collections.<InputMethodSubtype>emptyList();
         }
         synchronized (mMethodMap) {
-            if (imi == null && mCurMethodId != null) {
+            final InputMethodInfo imi;
+            if (imiId == null && mCurMethodId != null) {
                 imi = mMethodMap.get(mCurMethodId);
+            } else {
+                imi = mMethodMap.get(imiId);
+            }
+            if (imi == null) {
+                return Collections.<InputMethodSubtype>emptyList();
             }
             return mSettings.getEnabledInputMethodSubtypeListLocked(
                     mContext, imi, allowsImplicitlySelectedSubtypes);
@@ -1205,7 +1218,7 @@
         mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
         if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
-                | Context.BIND_NOT_VISIBLE)) {
+                | Context.BIND_NOT_VISIBLE | Context.BIND_SHOWING_UI)) {
             mLastBindTime = SystemClock.uptimeMillis();
             mHaveConnection = true;
             mCurId = info.getId();
@@ -1506,23 +1519,16 @@
                 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
                 if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
                     // Used to load label
-                    final PackageManager pm = mContext.getPackageManager();
                     final CharSequence title = mRes.getText(
                             com.android.internal.R.string.select_input_method);
-                    final CharSequence imiLabel = imi.loadLabel(pm);
-                    final CharSequence summary = mCurrentSubtype != null
-                            ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext,
-                                        imi.getPackageName(), imi.getServiceInfo().applicationInfo),
-                                                (TextUtils.isEmpty(imiLabel) ?
-                                                        "" : " - " + imiLabel))
-                            : imiLabel;
+                    final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
+                            mContext, imi, mCurrentSubtype);
 
                     mImeSwitcherNotification.setLatestEventInfo(
                             mContext, title, summary, mImeSwitchPendingIntent);
                     if (mNotificationManager != null) {
                         if (DEBUG) {
-                            Slog.d(TAG, "--- show notification: label =  " + imiLabel
-                                    + ", summary = " + summary);
+                            Slog.d(TAG, "--- show notification: label =  " + summary);
                         }
                         mNotificationManager.notifyAsUser(null,
                                 com.android.internal.R.string.select_input_method,
@@ -2153,6 +2159,21 @@
     }
 
     @Override
+    public boolean shouldOfferSwitchingToNextInputMethod(IBinder token) {
+        if (!calledFromValidUser()) {
+            return false;
+        }
+        synchronized (mMethodMap) {
+            final ImeSubtypeListItem nextSubtype = mImListManager.getNextInputMethod(
+                    false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+            if (nextSubtype == null) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    @Override
     public InputMethodSubtype getLastInputMethodSubtype() {
         if (!calledFromValidUser()) {
             return null;
@@ -2475,7 +2496,7 @@
             HashMap<String, InputMethodInfo> map, boolean resetDefaultEnabledIme) {
         if (DEBUG) {
             Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
-                    + " \n ------ \n" + getStackTrace());
+                    + " \n ------ \n" + InputMethodUtils.getStackTrace());
         }
         list.clear();
         map.clear();
@@ -3470,22 +3491,6 @@
         }
     }
 
-    // ----------------------------------------------------------------------
-    // Utilities for debug
-    private static String getStackTrace() {
-        final StringBuilder sb = new StringBuilder();
-        try {
-            throw new RuntimeException();
-        } catch (RuntimeException e) {
-            final StackTraceElement[] frames = e.getStackTrace();
-            // Start at 1 because the first frame is here and we don't care about it
-            for (int j = 1; j < frames.length; ++j) {
-                sb.append(frames[j].toString() + "\n");
-            }
-        }
-        return sb.toString();
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 35345f5..64b0487 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -18,9 +18,9 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -29,15 +29,16 @@
 
 import android.net.Uri;
 import android.util.FastImmutableArraySet;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.LogPrinter;
 import android.util.Printer;
-import android.util.StringBuilderPrinter;
 
 import android.content.Intent;
 import android.content.IntentFilter;
+import com.android.internal.util.FastPrintWriter;
 
 /**
  * {@hide}
@@ -46,7 +47,6 @@
     final private static String TAG = "IntentResolver";
     final private static boolean DEBUG = false;
     final private static boolean localLOGV = DEBUG || false;
-    final private static boolean VALIDATE = false;
 
     public void addFilter(F f) {
         if (localLOGV) {
@@ -67,21 +67,11 @@
             register_intent_filter(f, f.actionsIterator(),
                     mTypedActionToFilter, "      TypedAction: ");
         }
-
-        if (VALIDATE) {
-            mOldResolver.addFilter(f);
-            verifyDataStructures(f);
-        }
     }
 
     public void removeFilter(F f) {
         removeFilterInternal(f);
         mFilters.remove(f);
-
-        if (VALIDATE) {
-            mOldResolver.removeFilter(f);
-            verifyDataStructures(f);
-        }
     }
 
     void removeFilterInternal(F f) {
@@ -240,8 +230,8 @@
                 ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
 
         if (debug) Slog.v(
-            TAG, "Resolving type " + resolvedType + " scheme " + scheme
-            + " of intent " + intent);
+            TAG, "Resolving type=" + resolvedType + " scheme=" + scheme
+            + " defaultOnly=" + defaultOnly + " userId=" + userId + " of " + intent);
 
         F[] firstTypeCut = null;
         F[] secondTypeCut = null;
@@ -260,26 +250,28 @@
                         // Not a wild card, so we can just look for all filters that
                         // completely match or wildcards whose base type matches.
                         firstTypeCut = mTypeToFilter.get(resolvedType);
-                        if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
+                        if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));
                         secondTypeCut = mWildTypeToFilter.get(baseType);
-                        if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
+                        if (debug) Slog.v(TAG, "Second type cut: "
+                                + Arrays.toString(secondTypeCut));
                     } else {
                         // We can match anything with our base type.
                         firstTypeCut = mBaseTypeToFilter.get(baseType);
-                        if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
+                        if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));
                         secondTypeCut = mWildTypeToFilter.get(baseType);
-                        if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
+                        if (debug) Slog.v(TAG, "Second type cut: "
+                                + Arrays.toString(secondTypeCut));
                     }
                     // Any */* types always apply, but we only need to do this
                     // if the intent type was not already */*.
                     thirdTypeCut = mWildTypeToFilter.get("*");
-                    if (debug) Slog.v(TAG, "Third type cut: " + thirdTypeCut);
+                    if (debug) Slog.v(TAG, "Third type cut: " + Arrays.toString(thirdTypeCut));
                 } else if (intent.getAction() != null) {
                     // The intent specified any type ({@literal *}/*).  This
                     // can be a whole heck of a lot of things, so as a first
                     // cut let's use the action instead.
                     firstTypeCut = mTypedActionToFilter.get(intent.getAction());
-                    if (debug) Slog.v(TAG, "Typed Action list: " + firstTypeCut);
+                    if (debug) Slog.v(TAG, "Typed Action list: " + Arrays.toString(firstTypeCut));
                 }
             }
         }
@@ -289,7 +281,7 @@
         // on the authority and path by directly matching each resulting filter).
         if (scheme != null) {
             schemeCut = mSchemeToFilter.get(scheme);
-            if (debug) Slog.v(TAG, "Scheme list: " + schemeCut);
+            if (debug) Slog.v(TAG, "Scheme list: " + Arrays.toString(schemeCut));
         }
 
         // If the intent does not specify any data -- either a MIME type or
@@ -297,7 +289,7 @@
         // data.
         if (resolvedType == null && scheme == null && intent.getAction() != null) {
             firstTypeCut = mActionToFilter.get(intent.getAction());
-            if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
+            if (debug) Slog.v(TAG, "Action list: " + Arrays.toString(firstTypeCut));
         }
 
         FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
@@ -319,20 +311,10 @@
         }
         sortResults(finalList);
 
-        if (VALIDATE) {
-            List<R> oldList = mOldResolver.queryIntent(intent, resolvedType, defaultOnly, userId);
-            if (oldList.size() != finalList.size()) {
-                ValidationFailure here = new ValidationFailure();
-                here.fillInStackTrace();
-                Log.wtf(TAG, "Query result " + intent + " size is " + finalList.size()
-                        + "; old implementation is " + oldList.size(), here);
-            }
-        }
-
         if (debug) {
             Slog.v(TAG, "Final result list:");
-            for (R r : finalList) {
-                Slog.v(TAG, "  " + r);
+            for (int i=0; i<finalList.size(); i++) {
+                Slog.v(TAG, "  " + finalList.get(i));
             }
         }
         return finalList;
@@ -379,7 +361,7 @@
         out.print(prefix); out.println(filter);
     }
 
-    private final void addFilter(HashMap<String, F[]> map, String name, F filter) {
+    private final void addFilter(ArrayMap<String, F[]> map, String name, F filter) {
         F[] array = map.get(name);
         if (array == null) {
             array = newArray(2);
@@ -464,7 +446,7 @@
     }
 
     private final int register_intent_filter(F filter, Iterator<String> i,
-            HashMap<String, F[]> dest, String prefix) {
+            ArrayMap<String, F[]> dest, String prefix) {
         if (i == null) {
             return 0;
         }
@@ -480,7 +462,7 @@
     }
 
     private final int unregister_intent_filter(F filter, Iterator<String> i,
-            HashMap<String, F[]> dest, String prefix) {
+            ArrayMap<String, F[]> dest, String prefix) {
         if (i == null) {
             return 0;
         }
@@ -495,7 +477,7 @@
         return num;
     }
 
-    private final void remove_all_objects(HashMap<String, F[]> map, String name,
+    private final void remove_all_objects(ArrayMap<String, F[]> map, String name,
             Object object) {
         F[] array = map.get(name);
         if (array != null) {
@@ -540,6 +522,16 @@
 
         final boolean excludingStopped = intent.isExcludingStopped();
 
+        final Printer logPrinter;
+        final PrintWriter logPrintWriter;
+        if (debug) {
+            logPrinter = new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM);
+            logPrintWriter = new FastPrintWriter(logPrinter);
+        } else {
+            logPrinter = null;
+            logPrintWriter = null;
+        }
+
         final int N = src != null ? src.length : 0;
         boolean hasNonDefaults = false;
         int i;
@@ -574,11 +566,17 @@
             match = filter.match(action, resolvedType, scheme, data, categories, TAG);
             if (match >= 0) {
                 if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +
-                        Integer.toHexString(match));
+                        Integer.toHexString(match) + " hasDefault="
+                        + filter.hasCategory(Intent.CATEGORY_DEFAULT));
                 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                     final R oneResult = newResult(filter, match, userId);
                     if (oneResult != null) {
                         dest.add(oneResult);
+                        if (debug) {
+                            dumpFilter(logPrintWriter, "    ", filter);
+                            logPrintWriter.flush();
+                            filter.dump(logPrinter, "    ");
+                        }
                     }
                 } else {
                     hasNonDefaults = true;
@@ -598,8 +596,12 @@
             }
         }
 
-        if (dest.size() == 0 && hasNonDefaults) {
-            Slog.w(TAG, "resolveIntent failed: found match, but none with Intent.CATEGORY_DEFAULT");
+        if (hasNonDefaults) {
+            if (dest.size() == 0) {
+                Slog.w(TAG, "resolveIntent failed: found match, but none with CATEGORY_DEFAULT");
+            } else if (dest.size() > 1) {
+                Slog.w(TAG, "resolveIntent: multiple matches, only some with CATEGORY_DEFAULT");
+            }
         }
     }
 
@@ -613,120 +615,6 @@
         }
     };
 
-    static class ValidationFailure extends RuntimeException {
-    }
-
-    private void verifyDataStructures(IntentFilter src) {
-        compareMaps(src, "mTypeToFilter", mTypeToFilter, mOldResolver.mTypeToFilter);
-        compareMaps(src, "mBaseTypeToFilter", mBaseTypeToFilter, mOldResolver.mBaseTypeToFilter);
-        compareMaps(src, "mWildTypeToFilter", mWildTypeToFilter, mOldResolver.mWildTypeToFilter);
-        compareMaps(src, "mSchemeToFilter", mSchemeToFilter, mOldResolver.mSchemeToFilter);
-        compareMaps(src, "mActionToFilter", mActionToFilter, mOldResolver.mActionToFilter);
-        compareMaps(src, "mTypedActionToFilter", mTypedActionToFilter, mOldResolver.mTypedActionToFilter);
-    }
-
-    private void compareMaps(IntentFilter src, String name, HashMap<String, F[]> cur,
-            HashMap<String, ArrayList<F>> old) {
-        if (cur.size() != old.size()) {
-            StringBuilder missing = new StringBuilder(128);
-            for (Map.Entry<String, ArrayList<F>> e : old.entrySet()) {
-                final F[] curArray = cur.get(e.getKey());
-                if (curArray == null) {
-                    if (missing.length() > 0) {
-                        missing.append(' ');
-                    }
-                    missing.append(e.getKey());
-                }
-            }
-            StringBuilder extra = new StringBuilder(128);
-            for (Map.Entry<String, F[]> e : cur.entrySet()) {
-                if (old.get(e.getKey()) == null) {
-                    if (extra.length() > 0) {
-                        extra.append(' ');
-                    }
-                    extra.append(e.getKey());
-                }
-            }
-            StringBuilder srcStr = new StringBuilder(1024);
-            StringBuilderPrinter printer = new StringBuilderPrinter(srcStr);
-            src.dump(printer, "");
-            ValidationFailure here = new ValidationFailure();
-            here.fillInStackTrace();
-            Log.wtf(TAG, "New map " + name + " size is " + cur.size()
-                    + "; old implementation is " + old.size()
-                    + "; missing: " + missing.toString()
-                    + "; extra: " + extra.toString()
-                    + "; src: " + srcStr.toString(), here);
-            return;
-        }
-        for (Map.Entry<String, ArrayList<F>> e : old.entrySet()) {
-            final F[] curArray = cur.get(e.getKey());
-            int curLen = curArray != null ? curArray.length : 0;
-            if (curLen == 0) {
-                ValidationFailure here = new ValidationFailure();
-                here.fillInStackTrace();
-                Log.wtf(TAG, "New map " + name + " doesn't contain expected key "
-                        + e.getKey() + " (array=" + curArray + ")");
-                return;
-            }
-            while (curLen > 0 && curArray[curLen-1] == null) {
-                curLen--;
-            }
-            final ArrayList<F> oldArray = e.getValue();
-            final int oldLen = oldArray.size();
-            if (curLen != oldLen) {
-                ValidationFailure here = new ValidationFailure();
-                here.fillInStackTrace();
-                Log.wtf(TAG, "New map " + name + " entry " + e.getKey() + " size is "
-                        + curLen + "; old implementation is " + oldLen, here);
-                return;
-            }
-            for (int i=0; i<oldLen; i++) {
-                F f = oldArray.get(i);
-                boolean found = false;
-                for (int j=0; j<curLen; j++) {
-                    if (curArray[j] == f) {
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    ValidationFailure here = new ValidationFailure();
-                    here.fillInStackTrace();
-                    Log.wtf(TAG, "New map " + name + " entry + " + e.getKey()
-                            + " doesn't contain expected filter " + f, here);
-                }
-            }
-            for (int i=0; i<curLen; i++) {
-                if (curArray[i] == null) {
-                    ValidationFailure here = new ValidationFailure();
-                    here.fillInStackTrace();
-                    Log.wtf(TAG, "New map " + name + " entry + " + e.getKey()
-                            + " has unexpected null at " + i + "; array: " + curArray, here);
-                    break;
-                }
-            }
-        }
-    }
-
-    private final IntentResolverOld<F, R> mOldResolver = new IntentResolverOld<F, R>() {
-        @Override protected boolean isPackageForFilter(String packageName, F filter) {
-            return IntentResolver.this.isPackageForFilter(packageName, filter);
-        }
-        @Override protected boolean allowFilterResult(F filter, List<R> dest) {
-            return IntentResolver.this.allowFilterResult(filter, dest);
-        }
-        @Override protected boolean isFilterStopped(F filter, int userId) {
-            return IntentResolver.this.isFilterStopped(filter, userId);
-        }
-        @Override protected R newResult(F filter, int match, int userId) {
-            return IntentResolver.this.newResult(filter, match, userId);
-        }
-        @Override protected void sortResults(List<R> results) {
-            IntentResolver.this.sortResults(results);
-        }
-    };
-
     /**
      * All filters that have been registered.
      */
@@ -736,14 +624,14 @@
      * All of the MIME types that have been registered, such as "image/jpeg",
      * "image/*", or "{@literal *}/*".
      */
-    private final HashMap<String, F[]> mTypeToFilter = new HashMap<String, F[]>();
+    private final ArrayMap<String, F[]> mTypeToFilter = new ArrayMap<String, F[]>();
 
     /**
      * The base names of all of all fully qualified MIME types that have been
      * registered, such as "image" or "*".  Wild card MIME types such as
      * "image/*" will not be here.
      */
-    private final HashMap<String, F[]> mBaseTypeToFilter = new HashMap<String, F[]>();
+    private final ArrayMap<String, F[]> mBaseTypeToFilter = new ArrayMap<String, F[]>();
 
     /**
      * The base names of all of the MIME types with a sub-type wildcard that
@@ -752,21 +640,21 @@
      * included here.  This also includes the "*" for the "{@literal *}/*"
      * MIME type.
      */
-    private final HashMap<String, F[]> mWildTypeToFilter = new HashMap<String, F[]>();
+    private final ArrayMap<String, F[]> mWildTypeToFilter = new ArrayMap<String, F[]>();
 
     /**
      * All of the URI schemes (such as http) that have been registered.
      */
-    private final HashMap<String, F[]> mSchemeToFilter = new HashMap<String, F[]>();
+    private final ArrayMap<String, F[]> mSchemeToFilter = new ArrayMap<String, F[]>();
 
     /**
      * All of the actions that have been registered, but only those that did
      * not specify data.
      */
-    private final HashMap<String, F[]> mActionToFilter = new HashMap<String, F[]>();
+    private final ArrayMap<String, F[]> mActionToFilter = new ArrayMap<String, F[]>();
 
     /**
      * All of the actions that have been registered and specified a MIME type.
      */
-    private final HashMap<String, F[]> mTypedActionToFilter = new HashMap<String, F[]>();
+    private final ArrayMap<String, F[]> mTypedActionToFilter = new ArrayMap<String, F[]>();
 }
diff --git a/services/java/com/android/server/IntentResolverOld.java b/services/java/com/android/server/IntentResolverOld.java
deleted file mode 100644
index 94a2379..0000000
--- a/services/java/com/android/server/IntentResolverOld.java
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import android.net.Uri;
-import android.util.FastImmutableArraySet;
-import android.util.Log;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.LogPrinter;
-import android.util.Printer;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-
-/**
- * Temporary for verification of new implementation.
- * {@hide}
- */
-public abstract class IntentResolverOld<F extends IntentFilter, R extends Object> {
-    final private static String TAG = "IntentResolver";
-    final private static boolean DEBUG = false;
-    final private static boolean localLOGV = DEBUG || false;
-
-    public void addFilter(F f) {
-        if (localLOGV) {
-            Slog.v(TAG, "Adding filter: " + f);
-            f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
-            Slog.v(TAG, "    Building Lookup Maps:");
-        }
-
-        mFilters.add(f);
-        int numS = register_intent_filter(f, f.schemesIterator(),
-                mSchemeToFilter, "      Scheme: ");
-        int numT = register_mime_types(f, "      Type: ");
-        if (numS == 0 && numT == 0) {
-            register_intent_filter(f, f.actionsIterator(),
-                    mActionToFilter, "      Action: ");
-        }
-        if (numT != 0) {
-            register_intent_filter(f, f.actionsIterator(),
-                    mTypedActionToFilter, "      TypedAction: ");
-        }
-    }
-
-    public void removeFilter(F f) {
-        removeFilterInternal(f);
-        mFilters.remove(f);
-    }
-
-    void removeFilterInternal(F f) {
-        if (localLOGV) {
-            Slog.v(TAG, "Removing filter: " + f);
-            f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
-            Slog.v(TAG, "    Cleaning Lookup Maps:");
-        }
-
-        int numS = unregister_intent_filter(f, f.schemesIterator(),
-                mSchemeToFilter, "      Scheme: ");
-        int numT = unregister_mime_types(f, "      Type: ");
-        if (numS == 0 && numT == 0) {
-            unregister_intent_filter(f, f.actionsIterator(),
-                    mActionToFilter, "      Action: ");
-        }
-        if (numT != 0) {
-            unregister_intent_filter(f, f.actionsIterator(),
-                    mTypedActionToFilter, "      TypedAction: ");
-        }
-    }
-
-    boolean dumpMap(PrintWriter out, String titlePrefix, String title,
-            String prefix, Map<String, ArrayList<F>> map, String packageName,
-            boolean printFilter) {
-        String eprefix = prefix + "  ";
-        String fprefix = prefix + "    ";
-        boolean printedSomething = false;
-        Printer printer = null;
-        for (Map.Entry<String, ArrayList<F>> e : map.entrySet()) {
-            ArrayList<F> a = e.getValue();
-            final int N = a.size();
-            boolean printedHeader = false;
-            for (int i=0; i<N; i++) {
-                F filter = a.get(i);
-                if (packageName != null && !isPackageForFilter(packageName, filter)) {
-                    continue;
-                }
-                if (title != null) {
-                    out.print(titlePrefix); out.println(title);
-                    title = null;
-                }
-                if (!printedHeader) {
-                    out.print(eprefix); out.print(e.getKey()); out.println(":");
-                    printedHeader = true;
-                }
-                printedSomething = true;
-                dumpFilter(out, fprefix, filter);
-                if (printFilter) {
-                    if (printer == null) {
-                        printer = new PrintWriterPrinter(out);
-                    }
-                    filter.dump(printer, fprefix + "  ");
-                }
-            }
-        }
-        return printedSomething;
-    }
-
-    public boolean dump(PrintWriter out, String title, String prefix, String packageName,
-            boolean printFilter) {
-        String innerPrefix = prefix + "  ";
-        String sepPrefix = "\n" + prefix;
-        String curPrefix = title + "\n" + prefix;
-        if (dumpMap(out, curPrefix, "Full MIME Types:", innerPrefix,
-                mTypeToFilter, packageName, printFilter)) {
-            curPrefix = sepPrefix;
-        }
-        if (dumpMap(out, curPrefix, "Base MIME Types:", innerPrefix,
-                mBaseTypeToFilter, packageName, printFilter)) {
-            curPrefix = sepPrefix;
-        }
-        if (dumpMap(out, curPrefix, "Wild MIME Types:", innerPrefix,
-                mWildTypeToFilter, packageName, printFilter)) {
-            curPrefix = sepPrefix;
-        }
-        if (dumpMap(out, curPrefix, "Schemes:", innerPrefix,
-                mSchemeToFilter, packageName, printFilter)) {
-            curPrefix = sepPrefix;
-        }
-        if (dumpMap(out, curPrefix, "Non-Data Actions:", innerPrefix,
-                mActionToFilter, packageName, printFilter)) {
-            curPrefix = sepPrefix;
-        }
-        if (dumpMap(out, curPrefix, "MIME Typed Actions:", innerPrefix,
-                mTypedActionToFilter, packageName, printFilter)) {
-            curPrefix = sepPrefix;
-        }
-        return curPrefix == sepPrefix;
-    }
-
-    private class IteratorWrapper implements Iterator<F> {
-        private final Iterator<F> mI;
-        private F mCur;
-
-        IteratorWrapper(Iterator<F> it) {
-            mI = it;
-        }
-
-        public boolean hasNext() {
-            return mI.hasNext();
-        }
-
-        public F next() {
-            return (mCur = mI.next());
-        }
-
-        public void remove() {
-            if (mCur != null) {
-                removeFilterInternal(mCur);
-            }
-            mI.remove();
-        }
-
-    }
-
-    /**
-     * Returns an iterator allowing filters to be removed.
-     */
-    public Iterator<F> filterIterator() {
-        return new IteratorWrapper(mFilters.iterator());
-    }
-
-    /**
-     * Returns a read-only set of the filters.
-     */
-    public Set<F> filterSet() {
-        return Collections.unmodifiableSet(mFilters);
-    }
-
-    public List<R> queryIntentFromList(Intent intent, String resolvedType, 
-            boolean defaultOnly, ArrayList<ArrayList<F>> listCut, int userId) {
-        ArrayList<R> resultList = new ArrayList<R>();
-
-        final boolean debug = localLOGV ||
-                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
-
-        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
-        final String scheme = intent.getScheme();
-        int N = listCut.size();
-        for (int i = 0; i < N; ++i) {
-            buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, listCut.get(i), resultList, userId);
-        }
-        sortResults(resultList);
-        return resultList;
-    }
-
-    public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
-            int userId) {
-        String scheme = intent.getScheme();
-
-        ArrayList<R> finalList = new ArrayList<R>();
-
-        final boolean debug = localLOGV ||
-                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
-
-        if (debug) Slog.v(
-            TAG, "Resolving type " + resolvedType + " scheme " + scheme
-            + " of intent " + intent);
-
-        ArrayList<F> firstTypeCut = null;
-        ArrayList<F> secondTypeCut = null;
-        ArrayList<F> thirdTypeCut = null;
-        ArrayList<F> schemeCut = null;
-
-        // If the intent includes a MIME type, then we want to collect all of
-        // the filters that match that MIME type.
-        if (resolvedType != null) {
-            int slashpos = resolvedType.indexOf('/');
-            if (slashpos > 0) {
-                final String baseType = resolvedType.substring(0, slashpos);
-                if (!baseType.equals("*")) {
-                    if (resolvedType.length() != slashpos+2
-                            || resolvedType.charAt(slashpos+1) != '*') {
-                        // Not a wild card, so we can just look for all filters that
-                        // completely match or wildcards whose base type matches.
-                        firstTypeCut = mTypeToFilter.get(resolvedType);
-                        if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
-                        secondTypeCut = mWildTypeToFilter.get(baseType);
-                        if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
-                    } else {
-                        // We can match anything with our base type.
-                        firstTypeCut = mBaseTypeToFilter.get(baseType);
-                        if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
-                        secondTypeCut = mWildTypeToFilter.get(baseType);
-                        if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
-                    }
-                    // Any */* types always apply, but we only need to do this
-                    // if the intent type was not already */*.
-                    thirdTypeCut = mWildTypeToFilter.get("*");
-                    if (debug) Slog.v(TAG, "Third type cut: " + thirdTypeCut);
-                } else if (intent.getAction() != null) {
-                    // The intent specified any type ({@literal *}/*).  This
-                    // can be a whole heck of a lot of things, so as a first
-                    // cut let's use the action instead.
-                    firstTypeCut = mTypedActionToFilter.get(intent.getAction());
-                    if (debug) Slog.v(TAG, "Typed Action list: " + firstTypeCut);
-                }
-            }
-        }
-
-        // If the intent includes a data URI, then we want to collect all of
-        // the filters that match its scheme (we will further refine matches
-        // on the authority and path by directly matching each resulting filter).
-        if (scheme != null) {
-            schemeCut = mSchemeToFilter.get(scheme);
-            if (debug) Slog.v(TAG, "Scheme list: " + schemeCut);
-        }
-
-        // If the intent does not specify any data -- either a MIME type or
-        // a URI -- then we will only be looking for matches against empty
-        // data.
-        if (resolvedType == null && scheme == null && intent.getAction() != null) {
-            firstTypeCut = mActionToFilter.get(intent.getAction());
-            if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
-        }
-
-        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
-        if (firstTypeCut != null) {
-            buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, firstTypeCut, finalList, userId);
-        }
-        if (secondTypeCut != null) {
-            buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, secondTypeCut, finalList, userId);
-        }
-        if (thirdTypeCut != null) {
-            buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, thirdTypeCut, finalList, userId);
-        }
-        if (schemeCut != null) {
-            buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, schemeCut, finalList, userId);
-        }
-        sortResults(finalList);
-
-        if (debug) {
-            Slog.v(TAG, "Final result list:");
-            for (R r : finalList) {
-                Slog.v(TAG, "  " + r);
-            }
-        }
-        return finalList;
-    }
-
-    /**
-     * Control whether the given filter is allowed to go into the result
-     * list.  Mainly intended to prevent adding multiple filters for the
-     * same target object.
-     */
-    protected boolean allowFilterResult(F filter, List<R> dest) {
-        return true;
-    }
-
-    /**
-     * Returns whether the object associated with the given filter is
-     * "stopped," that is whether it should not be included in the result
-     * if the intent requests to excluded stopped objects.
-     */
-    protected boolean isFilterStopped(F filter, int userId) {
-        return false;
-    }
-
-    /**
-     * Returns whether this filter is owned by this package. This must be
-     * implemented to provide correct filtering of Intents that have
-     * specified a package name they are to be delivered to.
-     */
-    protected abstract boolean isPackageForFilter(String packageName, F filter);
-    
-    @SuppressWarnings("unchecked")
-    protected R newResult(F filter, int match, int userId) {
-        return (R)filter;
-    }
-
-    @SuppressWarnings("unchecked")
-    protected void sortResults(List<R> results) {
-        Collections.sort(results, mResolvePrioritySorter);
-    }
-
-    protected void dumpFilter(PrintWriter out, String prefix, F filter) {
-        out.print(prefix); out.println(filter);
-    }
-
-    private final int register_mime_types(F filter, String prefix) {
-        final Iterator<String> i = filter.typesIterator();
-        if (i == null) {
-            return 0;
-        }
-
-        int num = 0;
-        while (i.hasNext()) {
-            String name = i.next();
-            num++;
-            if (localLOGV) Slog.v(TAG, prefix + name);
-            String baseName = name;
-            final int slashpos = name.indexOf('/');
-            if (slashpos > 0) {
-                baseName = name.substring(0, slashpos).intern();
-            } else {
-                name = name + "/*";
-            }
-
-            ArrayList<F> array = mTypeToFilter.get(name);
-            if (array == null) {
-                //Slog.v(TAG, "Creating new array for " + name);
-                array = new ArrayList<F>();
-                mTypeToFilter.put(name, array);
-            }
-            array.add(filter);
-
-            if (slashpos > 0) {
-                array = mBaseTypeToFilter.get(baseName);
-                if (array == null) {
-                    //Slog.v(TAG, "Creating new array for " + name);
-                    array = new ArrayList<F>();
-                    mBaseTypeToFilter.put(baseName, array);
-                }
-                array.add(filter);
-            } else {
-                array = mWildTypeToFilter.get(baseName);
-                if (array == null) {
-                    //Slog.v(TAG, "Creating new array for " + name);
-                    array = new ArrayList<F>();
-                    mWildTypeToFilter.put(baseName, array);
-                }
-                array.add(filter);
-            }
-        }
-
-        return num;
-    }
-
-    private final int unregister_mime_types(F filter, String prefix) {
-        final Iterator<String> i = filter.typesIterator();
-        if (i == null) {
-            return 0;
-        }
-
-        int num = 0;
-        while (i.hasNext()) {
-            String name = i.next();
-            num++;
-            if (localLOGV) Slog.v(TAG, prefix + name);
-            String baseName = name;
-            final int slashpos = name.indexOf('/');
-            if (slashpos > 0) {
-                baseName = name.substring(0, slashpos).intern();
-            } else {
-                name = name + "/*";
-            }
-
-            if (!remove_all_objects(mTypeToFilter.get(name), filter)) {
-                mTypeToFilter.remove(name);
-            }
-
-            if (slashpos > 0) {
-                if (!remove_all_objects(mBaseTypeToFilter.get(baseName), filter)) {
-                    mBaseTypeToFilter.remove(baseName);
-                }
-            } else {
-                if (!remove_all_objects(mWildTypeToFilter.get(baseName), filter)) {
-                    mWildTypeToFilter.remove(baseName);
-                }
-            }
-        }
-        return num;
-    }
-
-    private final int register_intent_filter(F filter, Iterator<String> i,
-            HashMap<String, ArrayList<F>> dest, String prefix) {
-        if (i == null) {
-            return 0;
-        }
-
-        int num = 0;
-        while (i.hasNext()) {
-            String name = i.next();
-            num++;
-            if (localLOGV) Slog.v(TAG, prefix + name);
-            ArrayList<F> array = dest.get(name);
-            if (array == null) {
-                //Slog.v(TAG, "Creating new array for " + name);
-                array = new ArrayList<F>();
-                dest.put(name, array);
-            }
-            array.add(filter);
-        }
-        return num;
-    }
-
-    private final int unregister_intent_filter(F filter, Iterator<String> i,
-            HashMap<String, ArrayList<F>> dest, String prefix) {
-        if (i == null) {
-            return 0;
-        }
-
-        int num = 0;
-        while (i.hasNext()) {
-            String name = i.next();
-            num++;
-            if (localLOGV) Slog.v(TAG, prefix + name);
-            if (!remove_all_objects(dest.get(name), filter)) {
-                dest.remove(name);
-            }
-        }
-        return num;
-    }
-
-    private final boolean remove_all_objects(List<F> list, Object object) {
-        if (list != null) {
-            int N = list.size();
-            for (int idx=0; idx<N; idx++) {
-                if (list.get(idx) == object) {
-                    list.remove(idx);
-                    idx--;
-                    N--;
-                }
-            }
-            return N > 0;
-        }
-        return false;
-    }
-
-    private static FastImmutableArraySet<String> getFastIntentCategories(Intent intent) {
-        final Set<String> categories = intent.getCategories();
-        if (categories == null) {
-            return null;
-        }
-        return new FastImmutableArraySet<String>(categories.toArray(new String[categories.size()]));
-    }
-
-    private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
-            boolean debug, boolean defaultOnly,
-            String resolvedType, String scheme, List<F> src, List<R> dest, int userId) {
-        final String action = intent.getAction();
-        final Uri data = intent.getData();
-        final String packageName = intent.getPackage();
-
-        final boolean excludingStopped = intent.isExcludingStopped();
-
-        final int N = src != null ? src.size() : 0;
-        boolean hasNonDefaults = false;
-        int i;
-        for (i=0; i<N; i++) {
-            F filter = src.get(i);
-            int match;
-            if (debug) Slog.v(TAG, "Matching against filter " + filter);
-
-            if (excludingStopped && isFilterStopped(filter, userId)) {
-                if (debug) {
-                    Slog.v(TAG, "  Filter's target is stopped; skipping");
-                }
-                continue;
-            }
-
-            // Is delivery being limited to filters owned by a particular package?
-            if (packageName != null && !isPackageForFilter(packageName, filter)) {
-                if (debug) {
-                    Slog.v(TAG, "  Filter is not from package " + packageName + "; skipping");
-                }
-                continue;
-            }
-
-            // Do we already have this one?
-            if (!allowFilterResult(filter, dest)) {
-                if (debug) {
-                    Slog.v(TAG, "  Filter's target already added");
-                }
-                continue;
-            }
-
-            match = filter.match(action, resolvedType, scheme, data, categories, TAG);
-            if (match >= 0) {
-                if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +
-                        Integer.toHexString(match));
-                if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
-                    final R oneResult = newResult(filter, match, userId);
-                    if (oneResult != null) {
-                        dest.add(oneResult);
-                    }
-                } else {
-                    hasNonDefaults = true;
-                }
-            } else {
-                if (debug) {
-                    String reason;
-                    switch (match) {
-                        case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
-                        case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
-                        case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
-                        case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
-                        default: reason = "unknown reason"; break;
-                    }
-                    Slog.v(TAG, "  Filter did not match: " + reason);
-                }
-            }
-        }
-
-        if (dest.size() == 0 && hasNonDefaults) {
-            Slog.w(TAG, "resolveIntent failed: found match, but none with Intent.CATEGORY_DEFAULT");
-        }
-    }
-
-    // Sorts a List of IntentFilter objects into descending priority order.
-    @SuppressWarnings("rawtypes")
-    private static final Comparator mResolvePrioritySorter = new Comparator() {
-        public int compare(Object o1, Object o2) {
-            final int q1 = ((IntentFilter) o1).getPriority();
-            final int q2 = ((IntentFilter) o2).getPriority();
-            return (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0);
-        }
-    };
-
-    /**
-     * All filters that have been registered.
-     */
-    final HashSet<F> mFilters = new HashSet<F>();
-
-    /**
-     * All of the MIME types that have been registered, such as "image/jpeg",
-     * "image/*", or "{@literal *}/*".
-     */
-    final HashMap<String, ArrayList<F>> mTypeToFilter
-            = new HashMap<String, ArrayList<F>>();
-
-    /**
-     * The base names of all of all fully qualified MIME types that have been
-     * registered, such as "image" or "*".  Wild card MIME types such as
-     * "image/*" will not be here.
-     */
-    final HashMap<String, ArrayList<F>> mBaseTypeToFilter
-            = new HashMap<String, ArrayList<F>>();
-
-    /**
-     * The base names of all of the MIME types with a sub-type wildcard that
-     * have been registered.  For example, a filter with "image/*" will be
-     * included here as "image" but one with "image/jpeg" will not be
-     * included here.  This also includes the "*" for the "{@literal *}/*"
-     * MIME type.
-     */
-    final HashMap<String, ArrayList<F>> mWildTypeToFilter
-            = new HashMap<String, ArrayList<F>>();
-
-    /**
-     * All of the URI schemes (such as http) that have been registered.
-     */
-    final HashMap<String, ArrayList<F>> mSchemeToFilter
-            = new HashMap<String, ArrayList<F>>();
-
-    /**
-     * All of the actions that have been registered, but only those that did
-     * not specify data.
-     */
-    final HashMap<String, ArrayList<F>> mActionToFilter
-            = new HashMap<String, ArrayList<F>>();
-
-    /**
-     * All of the actions that have been registered and specified a MIME type.
-     */
-    final HashMap<String, ArrayList<F>> mTypedActionToFilter
-            = new HashMap<String, ArrayList<F>>();
-}
-
diff --git a/services/java/com/android/server/IoThread.java b/services/java/com/android/server/IoThread.java
new file mode 100644
index 0000000..09f2af7
--- /dev/null
+++ b/services/java/com/android/server/IoThread.java
@@ -0,0 +1,62 @@
+/*
+ * 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.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * Shared singleton I/O thread for the system.  This is a thread for non-background
+ * service operations that can potential block briefly on network IO operations
+ * (not waiting for data itself, but communicating with network daemons).
+ */
+public final class IoThread extends HandlerThread {
+    private static IoThread sInstance;
+    private static Handler sHandler;
+
+    private IoThread() {
+        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new IoThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+            sHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    android.os.Process.setCanSelfBackground(false);
+                }
+            });
+        }
+    }
+
+    public static IoThread get() {
+        synchronized (IoThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (IoThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index f784030..3e8770e 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -47,7 +47,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -63,6 +62,9 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.location.FlpHardwareProvider;
+import com.android.server.location.FusedProxy;
 import com.android.server.location.GeocoderProxy;
 import com.android.server.location.GeofenceProxy;
 import com.android.server.location.GeofenceManager;
@@ -93,7 +95,6 @@
     public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final String WAKELOCK_KEY = TAG;
-    private static final String THREAD_NAME = TAG;
 
     // Location resolution level: no location data whatsoever
     private static final int RESOLUTION_LEVEL_NONE = 0;
@@ -110,7 +111,7 @@
             android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
 
     private static final String NETWORK_LOCATION_SERVICE_ACTION =
-            "com.android.location.service.v2.NetworkLocationProvider";
+            "com.android.location.service.v3.NetworkLocationProvider";
     private static final String FUSED_LOCATION_SERVICE_ACTION =
             "com.android.location.service.FusedLocationProvider";
 
@@ -118,6 +119,9 @@
 
     private static final long NANOS_PER_MILLI = 1000000L;
 
+    // The maximum interval a location request can have and still be considered "high power".
+    private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
+
     // Location Providers may sometimes deliver location updates
     // slightly faster that requested - provide grace period so
     // we don't unnecessarily filter events that are otherwise on
@@ -143,7 +147,6 @@
     private LocationWorkerHandler mLocationHandler;
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
-    private HandlerThread mHandlerThread;
 
     // --- fields below are protected by mLock ---
     // Set of providers that are explicitly enabled
@@ -200,7 +203,7 @@
         // most startup is deferred until systemReady()
     }
 
-    public void systemReady() {
+    public void systemRunning() {
         synchronized (mLock) {
             if (D) Log.d(TAG, "systemReady()");
 
@@ -211,9 +214,7 @@
             mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
             // prepare worker thread
-            mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
-            mHandlerThread.start();
-            mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
+            mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
 
             // prepare mLocationHandler's dependents
             mLocationFudger = new LocationFudger(mContext, mLocationHandler);
@@ -222,9 +223,13 @@
             mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
 
             // Monitor for app ops mode changes.
-            AppOpsManager.Callback callback = new AppOpsManager.Callback() {
-                public void opChanged(int op, String packageName) {
+            AppOpsManager.OnOpChangedListener callback
+                    = new AppOpsManager.OnOpChangedInternalListener() {
+                public void onOpChanged(int op, String packageName) {
                     synchronized (mLock) {
+                        for (Receiver receiver : mReceivers.values()) {
+                            receiver.updateMonitoring(true);
+                        }
                         applyAllProviderRequirementsLocked();
                     }
                 }
@@ -416,17 +421,30 @@
             Slog.e(TAG,  "no geocoder provider found");
         }
 
+        // bind to fused provider
+        FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
+        FusedProxy fusedProxy = FusedProxy.createAndBind(
+                mContext,
+                mLocationHandler,
+                flpHardwareProvider.getLocationHardware(),
+                com.android.internal.R.bool.config_enableFusedLocationOverlay,
+                com.android.internal.R.string.config_fusedLocationProviderPackageName,
+                com.android.internal.R.array.config_locationProviderPackageNames);
+        if(fusedProxy == null) {
+            Slog.e(TAG, "No FusedProvider found.");
+        }
+
         // bind to geofence provider
         GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
                 com.android.internal.R.bool.config_enableGeofenceOverlay,
                 com.android.internal.R.string.config_geofenceProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames,
                 mLocationHandler,
-                gpsProvider.getGpsGeofenceProxy());
+                gpsProvider.getGpsGeofenceProxy(),
+                flpHardwareProvider.getGeofenceHardware());
         if (provider == null) {
             Slog.e(TAG,  "no geofence provider found");
         }
-
     }
 
     /**
@@ -459,15 +477,21 @@
 
         final ILocationListener mListener;
         final PendingIntent mPendingIntent;
+        final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
+        final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
         final Object mKey;
 
         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
 
+        // True if app ops has started monitoring this receiver for locations.
+        boolean mOpMonitoring;
+        // True if app ops has started monitoring this receiver for high power (gps) locations.
+        boolean mOpHighPowerMonitoring;
         int mPendingBroadcasts;
         PowerManager.WakeLock mWakeLock;
 
         Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
-                String packageName) {
+                String packageName, WorkSource workSource, boolean hideFromAppOps) {
             mListener = listener;
             mPendingIntent = intent;
             if (listener != null) {
@@ -479,10 +503,20 @@
             mUid = uid;
             mPid = pid;
             mPackageName = packageName;
+            if (workSource != null && workSource.size() <= 0) {
+                workSource = null;
+            }
+            mWorkSource = workSource;
+            mHideFromAppOps = hideFromAppOps;
+
+            updateMonitoring(true);
 
             // construct/configure wakelock
             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
-            mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName));
+            if (workSource == null) {
+                workSource = new WorkSource(mUid, mPackageName);
+            }
+            mWakeLock.setWorkSource(workSource);
         }
 
         @Override
@@ -515,6 +549,83 @@
             return s.toString();
         }
 
+        /**
+         * Update AppOp monitoring for this receiver.
+         *
+         * @param allow If true receiver is currently active, if false it's been removed.
+         */
+        public void updateMonitoring(boolean allow) {
+            if (mHideFromAppOps) {
+                return;
+            }
+
+            boolean requestingLocation = false;
+            boolean requestingHighPowerLocation = false;
+            if (allow) {
+                // See if receiver has any enabled update records.  Also note if any update records
+                // are high power (has a high power provider with an interval under a threshold).
+                for (UpdateRecord updateRecord : mUpdateRecords.values()) {
+                    if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
+                        requestingLocation = true;
+                        LocationProviderInterface locationProvider
+                            = mProvidersByName.get(updateRecord.mProvider);
+                        ProviderProperties properties = locationProvider != null
+                                ? locationProvider.getProperties() : null;
+                        if (properties != null
+                                && properties.mPowerRequirement == Criteria.POWER_HIGH
+                                && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
+                            requestingHighPowerLocation = true;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // First update monitoring of any location request (including high power).
+            mOpMonitoring = updateMonitoring(
+                    requestingLocation,
+                    mOpMonitoring,
+                    AppOpsManager.OP_MONITOR_LOCATION);
+
+            // Now update monitoring of high power requests only.
+            boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
+            mOpHighPowerMonitoring = updateMonitoring(
+                    requestingHighPowerLocation,
+                    mOpHighPowerMonitoring,
+                    AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
+            if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
+                // Send an intent to notify that a high power request has been added/removed.
+                Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+            }
+        }
+
+        /**
+         * Update AppOps monitoring for a single location request and op type.
+         *
+         * @param allowMonitoring True if monitoring is allowed for this request/op.
+         * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
+         * @param op AppOps code for the op to update.
+         * @return True if monitoring is on for this request/op after updating.
+         */
+        private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
+                int op) {
+            if (!currentlyMonitoring) {
+                if (allowMonitoring) {
+                    return mAppOps.startOpNoThrow(op, mUid, mPackageName)
+                            == AppOpsManager.MODE_ALLOWED;
+                }
+            } else {
+                if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
+                        != AppOpsManager.MODE_ALLOWED) {
+                    mAppOps.finishOp(op, mUid, mPackageName);
+                    return false;
+                }
+            }
+
+            return currentlyMonitoring;
+        }
+
         public boolean isListener() {
             return mListener != null;
         }
@@ -600,6 +711,10 @@
         }
 
         public boolean callProviderEnabledLocked(String provider, boolean enabled) {
+            // First update AppOp monitoring.
+            // An app may get/lose location access as providers are enabled/disabled.
+            updateMonitoring(true);
+
             if (mListener != null) {
                 try {
                     synchronized (this) {
@@ -866,6 +981,20 @@
         }
     }
 
+    /**
+     * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
+     * for battery).
+     */
+    private void checkDeviceStatsAllowed() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.UPDATE_DEVICE_STATS, null);
+    }
+
+    private void checkUpdateAppOpsAllowed() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
+    }
+
     public static int resolutionLevelToOp(int allowedResolutionLevel) {
         if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
             if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1028,6 +1157,8 @@
         if (changesMade) {
             mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
                     UserHandle.ALL);
+            mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
+                    UserHandle.ALL);
         }
     }
 
@@ -1107,7 +1238,18 @@
                     if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
                         LocationRequest locationRequest = record.mRequest;
                         if (locationRequest.getInterval() <= thresholdInterval) {
-                            worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
+                            if (record.mReceiver.mWorkSource != null
+                                    && record.mReceiver.mWorkSource.size() > 0
+                                    && record.mReceiver.mWorkSource.getName(0) != null) {
+                                // Assign blame to another work source.
+                                // Can only assign blame if the WorkSource contains names.
+                                worksource.add(record.mReceiver.mWorkSource);
+                            } else {
+                                // Assign blame to caller.
+                                worksource.add(
+                                        record.mReceiver.mUid,
+                                        record.mReceiver.mPackageName);
+                            }
                         }
                     }
                 }
@@ -1182,11 +1324,12 @@
     }
 
     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
-            String packageName) {
+            String packageName, WorkSource workSource, boolean hideFromAppOps) {
         IBinder binder = listener.asBinder();
         Receiver receiver = mReceivers.get(binder);
         if (receiver == null) {
-            receiver = new Receiver(listener, null, pid, uid, packageName);
+            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
+                    hideFromAppOps);
             mReceivers.put(binder, receiver);
 
             try {
@@ -1199,10 +1342,12 @@
         return receiver;
     }
 
-    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName) {
+    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
+            WorkSource workSource, boolean hideFromAppOps) {
         Receiver receiver = mReceivers.get(intent);
         if (receiver == null) {
-            receiver = new Receiver(null, intent, pid, uid, packageName);
+            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
+                    hideFromAppOps);
             mReceivers.put(intent, receiver);
         }
         return receiver;
@@ -1264,16 +1409,16 @@
     }
 
     private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
-            int pid, int uid, String packageName) {
+            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
         if (intent == null && listener == null) {
             throw new IllegalArgumentException("need either listener or intent");
         } else if (intent != null && listener != null) {
             throw new IllegalArgumentException("cannot register both listener and intent");
         } else if (intent != null) {
             checkPendingIntent(intent);
-            return getReceiverLocked(intent, pid, uid, packageName);
+            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
         } else {
-            return getReceiverLocked(listener, pid, uid, packageName);
+            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
         }
     }
 
@@ -1285,6 +1430,14 @@
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
                 request.getProvider());
+        WorkSource workSource = request.getWorkSource();
+        if (workSource != null && workSource.size() > 0) {
+            checkDeviceStatsAllowed();
+        }
+        boolean hideFromAppOps = request.getHideFromAppOps();
+        if (hideFromAppOps) {
+            checkUpdateAppOpsAllowed();
+        }
         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
 
         final int pid = Binder.getCallingPid();
@@ -1298,7 +1451,7 @@
 
             synchronized (mLock) {
                 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
-                        packageName);
+                        packageName, workSource, hideFromAppOps);
                 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
             }
         } finally {
@@ -1320,7 +1473,7 @@
                 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
         LocationProviderInterface provider = mProvidersByName.get(name);
         if (provider == null) {
-            throw new IllegalArgumentException("provider doesn't exisit: " + provider);
+            throw new IllegalArgumentException("provider doesn't exist: " + provider);
         }
 
         UpdateRecord record = new UpdateRecord(name, request, receiver);
@@ -1336,6 +1489,9 @@
             // Notify the listener that updates are currently disabled
             receiver.callProviderEnabledLocked(name, false);
         }
+        // Update the monitoring here just in case multiple location requests were added to the
+        // same receiver (this request may be high power and the initial might not have been).
+        receiver.updateMonitoring(true);
     }
 
     @Override
@@ -1347,7 +1503,10 @@
         final int uid = Binder.getCallingUid();
 
         synchronized (mLock) {
-            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName);
+            WorkSource workSource = null;
+            boolean hideFromAppOps = false;
+            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
+                    packageName, workSource, hideFromAppOps);
 
             // providers may use public location API's, need to clear identity
             long identity = Binder.clearCallingIdentity();
@@ -1369,6 +1528,8 @@
             }
         }
 
+        receiver.updateMonitoring(false);
+
         // Record which providers were associated with this listener
         HashSet<String> providers = new HashSet<String>();
         HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
@@ -1613,8 +1774,12 @@
 
     @Override
     public boolean isProviderEnabled(String provider) {
+        // TODO: remove this check in next release, see b/10696351
         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
                 provider);
+
+        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+        // so we discourage its use
         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
 
         int uid = Binder.getCallingUid();
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index d52a8e2..cd746cf 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManagerNative;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -27,6 +28,9 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.media.AudioManager;
+import android.media.AudioService;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.RemoteException;
@@ -36,7 +40,9 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
+import android.security.KeyStore;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.widget.ILockSettings;
@@ -57,6 +63,7 @@
  */
 public class LockSettingsService extends ILockSettings.Stub {
 
+    private static final String PERMISSION = "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE";
     private final DatabaseHelper mOpenHelper;
     private static final String TAG = "LockSettingsService";
 
@@ -74,11 +81,14 @@
     private static final String LOCK_PASSWORD_FILE = "password.key";
 
     private final Context mContext;
+    private LockPatternUtils mLockPatternUtils;
 
     public LockSettingsService(Context context) {
         mContext = context;
         // Open the database
         mOpenHelper = new DatabaseHelper(mContext);
+
+        mLockPatternUtils = new LockPatternUtils(context);
     }
 
     public void systemReady() {
@@ -143,20 +153,12 @@
         }
     }
 
-    private static final void checkWritePermission(int userId) {
-        final int callingUid = Binder.getCallingUid();
-        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
-            throw new SecurityException("uid=" + callingUid
-                    + " not authorized to write lock settings");
-        }
+    private final void checkWritePermission(int userId) {
+        mContext.checkCallingOrSelfPermission(PERMISSION);
     }
 
-    private static final void checkPasswordReadPermission(int userId) {
-        final int callingUid = Binder.getCallingUid();
-        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
-            throw new SecurityException("uid=" + callingUid
-                    + " not authorized to read lock password");
-        }
+    private final void checkPasswordReadPermission(int userId) {
+        mContext.checkCallingOrSelfPermission(PERMISSION);
     }
 
     private final void checkReadPermission(String requestedKey, int userId) {
@@ -257,15 +259,42 @@
         return new File(getLockPatternFilename(userId)).length() > 0;
     }
 
+    private void maybeUpdateKeystore(String password, int userId) {
+        if (userId == UserHandle.USER_OWNER) {
+            final KeyStore keyStore = KeyStore.getInstance();
+            // Conditionally reset the keystore if empty. If non-empty, we are just
+            // switching key guard type
+            if (TextUtils.isEmpty(password) && keyStore.isEmpty()) {
+                keyStore.reset();
+            } else {
+                // Update the keystore password
+                keyStore.password(password);
+            }
+        }
+    }
+
     @Override
-    public void setLockPattern(byte[] hash, int userId) throws RemoteException {
+    public void setLockPattern(String pattern, int userId) throws RemoteException {
         checkWritePermission(userId);
 
+        maybeUpdateKeystore(pattern, userId);
+
+        final byte[] hash = LockPatternUtils.patternToHash(
+                LockPatternUtils.stringToPattern(pattern));
         writeFile(getLockPatternFilename(userId), hash);
     }
 
     @Override
-    public boolean checkPattern(byte[] hash, int userId) throws RemoteException {
+    public void setLockPassword(String password, int userId) throws RemoteException {
+        checkWritePermission(userId);
+
+        maybeUpdateKeystore(password, userId);
+
+        writeFile(getLockPasswordFilename(userId), mLockPatternUtils.passwordToHash(password));
+    }
+
+    @Override
+    public boolean checkPattern(String pattern, int userId) throws RemoteException {
         checkPasswordReadPermission(userId);
         try {
             // Read all the bytes from the file
@@ -277,25 +306,23 @@
                 return true;
             }
             // Compare the hash from the file with the entered pattern's hash
-            return Arrays.equals(stored, hash);
+            final byte[] hash = LockPatternUtils.patternToHash(
+                    LockPatternUtils.stringToPattern(pattern));
+            final boolean matched = Arrays.equals(stored, hash);
+            if (matched && !TextUtils.isEmpty(pattern)) {
+                maybeUpdateKeystore(pattern, userId);
+            }
+            return matched;
         } catch (FileNotFoundException fnfe) {
             Slog.e(TAG, "Cannot read file " + fnfe);
-            return true;
         } catch (IOException ioe) {
             Slog.e(TAG, "Cannot read file " + ioe);
-            return true;
         }
+        return true;
     }
 
     @Override
-    public void setLockPassword(byte[] hash, int userId) throws RemoteException {
-        checkWritePermission(userId);
-
-        writeFile(getLockPasswordFilename(userId), hash);
-    }
-
-    @Override
-    public boolean checkPassword(byte[] hash, int userId) throws RemoteException {
+    public boolean checkPassword(String password, int userId) throws RemoteException {
         checkPasswordReadPermission(userId);
 
         try {
@@ -308,14 +335,18 @@
                 return true;
             }
             // Compare the hash from the file with the entered password's hash
-            return Arrays.equals(stored, hash);
+            final byte[] hash = mLockPatternUtils.passwordToHash(password);
+            final boolean matched = Arrays.equals(stored, hash);
+            if (matched && !TextUtils.isEmpty(password)) {
+                maybeUpdateKeystore(password, userId);
+            }
+            return matched;
         } catch (FileNotFoundException fnfe) {
             Slog.e(TAG, "Cannot read file " + fnfe);
-            return true;
         } catch (IOException ioe) {
             Slog.e(TAG, "Cannot read file " + ioe);
-            return true;
         }
+        return true;
     }
 
     @Override
@@ -398,7 +429,7 @@
         private static final String TAG = "LockSettingsDB";
         private static final String DATABASE_NAME = "locksettings.db";
 
-        private static final int DATABASE_VERSION = 1;
+        private static final int DATABASE_VERSION = 2;
 
         public DatabaseHelper(Context context) {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -431,7 +462,44 @@
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
-            // Nothing yet
+            int upgradeVersion = oldVersion;
+            if (upgradeVersion == 1) {
+                // Set the initial value for {@link LockPatternUtils#LOCKSCREEN_WIDGETS_ENABLED}
+                // during upgrade based on whether each user previously had widgets in keyguard.
+                maybeEnableWidgetSettingForUsers(db);
+                upgradeVersion = 2;
+            }
+
+            if (upgradeVersion != DATABASE_VERSION) {
+                Log.w(TAG, "Failed to upgrade database!");
+            }
+        }
+
+        private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) {
+            final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+            final ContentResolver cr = mContext.getContentResolver();
+            final List<UserInfo> users = um.getUsers();
+            for (int i = 0; i < users.size(); i++) {
+                final int userId = users.get(i).id;
+                final boolean enabled = mLockPatternUtils.hasWidgetsEnabledInKeyguard(userId);
+                Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled="
+                        + enabled + ", w[]=" + mLockPatternUtils.getAppWidgets());
+                loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled);
+            }
+        }
+
+        private void loadSetting(SQLiteDatabase db, String key, int userId, boolean value) {
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement(
+                        "INSERT OR REPLACE INTO locksettings(name,user,value) VALUES(?,?,?);");
+                stmt.bindString(1, key);
+                stmt.bindLong(2, userId);
+                stmt.bindLong(3, value ? 1 : 0);
+                stmt.execute();
+            } finally {
+                if (stmt != null) stmt.close();
+            }
         }
     }
 
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index e670ef9..6ab86f5 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.Manifest;
+import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -190,6 +191,8 @@
     /** When defined, base template for user-specific {@link StorageVolume}. */
     private StorageVolume mEmulatedTemplate;
 
+    // TODO: separate storage volumes on per-user basis
+
     @GuardedBy("mVolumesLock")
     private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList();
     /** Map from path to {@link StorageVolume} */
@@ -492,7 +495,6 @@
         }
     };
 
-    private final HandlerThread mHandlerThread;
     private final Handler mHandler;
 
     void waitForAsecScan() {
@@ -828,7 +830,7 @@
             }
 
             if (code == VoldResponseCode.VolumeDiskInserted) {
-                new Thread() {
+                new Thread("MountService#VolumeDiskInserted") {
                     @Override
                     public void run() {
                         try {
@@ -1115,7 +1117,7 @@
             /*
              * USB mass storage disconnected while enabled
              */
-            new Thread() {
+            new Thread("MountService#AvailabilityChange") {
                 @Override
                 public void run() {
                     try {
@@ -1314,9 +1316,9 @@
         // XXX: This will go away soon in favor of IMountServiceObserver
         mPms = (PackageManagerService) ServiceManager.getService("package");
 
-        mHandlerThread = new HandlerThread("MountService");
-        mHandlerThread.start();
-        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
+        HandlerThread hthread = new HandlerThread(TAG);
+        hthread.start();
+        mHandler = new MountServiceHandler(hthread.getLooper());
 
         // Watch for user changes
         final IntentFilter userFilter = new IntentFilter();
@@ -1338,7 +1340,7 @@
                 idleMaintenanceFilter, null, mHandler);
 
         // Add OBB Action Handler to MountService thread.
-        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
+        mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
 
         /*
          * Create the connection to vold with a maximum queue of twice the
@@ -2127,6 +2129,85 @@
     }
 
     @Override
+    public int mkdirs(String callingPkg, String appPath) {
+        final int userId = UserHandle.getUserId(Binder.getCallingUid());
+        final UserEnvironment userEnv = new UserEnvironment(userId);
+
+        // Validate that reported package name belongs to caller
+        final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
+                Context.APP_OPS_SERVICE);
+        appOps.checkPackage(Binder.getCallingUid(), callingPkg);
+
+        try {
+            appPath = new File(appPath).getCanonicalPath();
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
+            return -1;
+        }
+
+        // Try translating the app path into a vold path, but require that it
+        // belong to the calling package.
+        String voldPath = maybeTranslatePathForVold(appPath,
+                userEnv.buildExternalStorageAppDataDirs(callingPkg),
+                userEnv.buildExternalStorageAppDataDirsForVold(callingPkg));
+        if (voldPath != null) {
+            try {
+                mConnector.execute("volume", "mkdirs", voldPath);
+                return 0;
+            } catch (NativeDaemonConnectorException e) {
+                return e.getCode();
+            }
+        }
+
+        voldPath = maybeTranslatePathForVold(appPath,
+                userEnv.buildExternalStorageAppObbDirs(callingPkg),
+                userEnv.buildExternalStorageAppObbDirsForVold(callingPkg));
+        if (voldPath != null) {
+            try {
+                mConnector.execute("volume", "mkdirs", voldPath);
+                return 0;
+            } catch (NativeDaemonConnectorException e) {
+                return e.getCode();
+            }
+        }
+
+        throw new SecurityException("Invalid mkdirs path: " + appPath);
+    }
+
+    /**
+     * Translate the given path from an app-visible path to a vold-visible path,
+     * but only if it's under the given whitelisted paths.
+     *
+     * @param path a canonicalized app-visible path.
+     * @param appPaths list of app-visible paths that are allowed.
+     * @param voldPaths list of vold-visible paths directly corresponding to the
+     *            allowed app-visible paths argument.
+     * @return a vold-visible path representing the original path, or
+     *         {@code null} if the given path didn't have an app-to-vold
+     *         mapping.
+     */
+    @VisibleForTesting
+    public static String maybeTranslatePathForVold(
+            String path, File[] appPaths, File[] voldPaths) {
+        if (appPaths.length != voldPaths.length) {
+            throw new IllegalStateException("Paths must be 1:1 mapping");
+        }
+
+        for (int i = 0; i < appPaths.length; i++) {
+            final String appPath = appPaths[i].getAbsolutePath();
+            if (path.startsWith(appPath)) {
+                path = new File(voldPaths[i], path.substring(appPath.length() + 1))
+                        .getAbsolutePath();
+                if (!path.endsWith("/")) {
+                    path = path + "/";
+                }
+                return path;
+            }
+        }
+        return null;
+    }
+
+    @Override
     public StorageVolume[] getVolumeList() {
         final int callingUserId = UserHandle.getCallingUserId();
         final boolean accessAll = (mContext.checkPermission(
@@ -2606,6 +2687,7 @@
     @VisibleForTesting
     public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
         // TODO: allow caller to provide Environment for full testing
+        // TODO: extend to support OBB mounts on secondary external storage
 
         // Only adjust paths when storage is emulated
         if (!Environment.isExternalStorageEmulated()) {
@@ -2618,10 +2700,10 @@
         final UserEnvironment userEnv = new UserEnvironment(userId);
 
         // /storage/emulated/0
-        final String externalPath = userEnv.getExternalStorageDirectory().toString();
+        final String externalPath = userEnv.getExternalStorageDirectory().getAbsolutePath();
         // /storage/emulated_legacy
         final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
-                .toString();
+                .getAbsolutePath();
 
         if (path.startsWith(externalPath)) {
             path = path.substring(externalPath.length() + 1);
@@ -2637,18 +2719,19 @@
             path = path.substring(obbPath.length() + 1);
 
             if (forVold) {
-                return new File(Environment.getEmulatedStorageObbSource(), path).toString();
+                return new File(Environment.getEmulatedStorageObbSource(), path).getAbsolutePath();
             } else {
                 final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
-                return new File(ownerEnv.getExternalStorageObbDirectory(), path).toString();
+                return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
+                        .getAbsolutePath();
             }
         }
 
         // Handle normal external storage paths
         if (forVold) {
-            return new File(Environment.getEmulatedStorageSource(userId), path).toString();
+            return new File(Environment.getEmulatedStorageSource(userId), path).getAbsolutePath();
         } else {
-            return new File(userEnv.getExternalStorageDirectory(), path).toString();
+            return new File(userEnv.getExternalDirsForApp()[0], path).getAbsolutePath();
         }
     }
 
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 0a91919..417d6d8 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -18,8 +18,8 @@
 
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
+import android.os.Build;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Message;
 import android.os.SystemClock;
 import android.util.LocalLog;
@@ -81,9 +81,7 @@
 
     @Override
     public void run() {
-        HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
-        thread.start();
-        mCallbackHandler = new Handler(thread.getLooper(), this);
+        mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
 
         while (true) {
             try {
@@ -108,13 +106,24 @@
         return true;
     }
 
+    private LocalSocketAddress determineSocketAddress() {
+        // If we're testing, set up a socket in a namespace that's accessible to test code.
+        // In order to ensure that unprivileged apps aren't able to impersonate native daemons on
+        // production devices, even if said native daemons ill-advisedly pick a socket name that
+        // starts with __test__, only allow this on debug builds.
+        if (mSocket.startsWith("__test__") && Build.IS_DEBUGGABLE) {
+            return new LocalSocketAddress(mSocket);
+        } else {
+            return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);
+        }
+    }
+
     private void listenToSocket() throws IOException {
         LocalSocket socket = null;
 
         try {
             socket = new LocalSocket();
-            LocalSocketAddress address = new LocalSocketAddress(mSocket,
-                    LocalSocketAddress.Namespace.RESERVED);
+            LocalSocketAddress address = determineSocketAddress();
 
             socket.connect(address);
 
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 3b84c732..92f99c2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -24,13 +24,14 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
+import static com.android.server.NetworkManagementService.NetdResponseCode.GetMarkResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsResult;
+import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
@@ -43,18 +44,21 @@
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.INetworkManagementService;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 
+import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.util.Preconditions;
 import com.android.server.NativeDaemonConnector.Command;
@@ -91,6 +95,7 @@
     private static final String TAG = "NetworkManagementService";
     private static final boolean DBG = false;
     private static final String NETD_TAG = "NetdConnector";
+    private static final String NETD_SOCKET_NAME = "netd";
 
     private static final String ADD = "add";
     private static final String REMOVE = "remove";
@@ -113,6 +118,7 @@
         public static final int TetherInterfaceListResult = 111;
         public static final int TetherDnsFwdTgtListResult = 112;
         public static final int TtyListResult             = 113;
+        public static final int TetheringStatsListResult  = 114;
 
         public static final int TetherStatusResult        = 210;
         public static final int IpFwdStatusResult         = 211;
@@ -124,10 +130,12 @@
         public static final int TetheringStatsResult      = 221;
         public static final int DnsProxyQueryResult       = 222;
         public static final int ClatdStatusResult         = 223;
+        public static final int GetMarkResult             = 225;
 
         public static final int InterfaceChange           = 600;
         public static final int BandwidthControl          = 601;
         public static final int InterfaceClassActivity    = 613;
+        public static final int InterfaceAddressChange    = 614;
     }
 
     /**
@@ -181,7 +189,7 @@
      *
      * @param context  Binder context for this service
      */
-    private NetworkManagementService(Context context) {
+    private NetworkManagementService(Context context, String socket) {
         mContext = context;
 
         if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
@@ -189,15 +197,16 @@
         }
 
         mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160);
+                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160);
         mThread = new Thread(mConnector, NETD_TAG);
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
     }
 
-    public static NetworkManagementService create(Context context) throws InterruptedException {
-        final NetworkManagementService service = new NetworkManagementService(context);
+    static NetworkManagementService create(Context context,
+            String socket) throws InterruptedException {
+        final NetworkManagementService service = new NetworkManagementService(context, socket);
         final CountDownLatch connectedSignal = service.mConnectedSignal;
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
         service.mThread.start();
@@ -207,6 +216,10 @@
         return service;
     }
 
+    public static NetworkManagementService create(Context context) throws InterruptedException {
+        return create(context, NETD_SOCKET_NAME);
+    }
+
     public void systemReady() {
         prepareNativeDaemon();
         if (DBG) Slog.d(TAG, "Prepared");
@@ -343,6 +356,14 @@
 
         SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
 
+        if (mBandwidthControlEnabled) {
+            try {
+                IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME))
+                        .noteNetworkStatsEnabled();
+            } catch (RemoteException e) {
+            }
+        }
+
         // push any existing quota or UID rules
         synchronized (mQuotaLock) {
             int size = mActiveQuotas.size();
@@ -380,6 +401,36 @@
         setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
     }
 
+    /**
+     * Notify our observers of a new or updated interface address.
+     */
+    private void notifyAddressUpdated(String address, String iface, int flags, int scope) {
+        final int length = mObservers.beginBroadcast();
+        for (int i = 0; i < length; i++) {
+            try {
+                mObservers.getBroadcastItem(i).addressUpdated(address, iface, flags, scope);
+            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
+            }
+        }
+        mObservers.finishBroadcast();
+    }
+
+    /**
+     * Notify our observers of a deleted interface address.
+     */
+    private void notifyAddressRemoved(String address, String iface, int flags, int scope) {
+        final int length = mObservers.beginBroadcast();
+        for (int i = 0; i < length; i++) {
+            try {
+                mObservers.getBroadcastItem(i).addressRemoved(address, iface, flags, scope);
+            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
+            }
+        }
+        mObservers.finishBroadcast();
+    }
+
     //
     // Netd Callback handling
     //
@@ -462,6 +513,33 @@
                     notifyInterfaceClassActivity(cooked[3], isActive);
                     return true;
                     // break;
+            case NetdResponseCode.InterfaceAddressChange:
+                    /*
+                     * A network address change occurred
+                     * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
+                     *         "NNN Address removed <addr> <iface> <flags> <scope>"
+                     */
+                    String msg = String.format("Invalid event from daemon (%s)", raw);
+                    if (cooked.length < 6 || !cooked[1].equals("Address")) {
+                        throw new IllegalStateException(msg);
+                    }
+
+                    int flags;
+                    int scope;
+                    try {
+                        flags = Integer.parseInt(cooked[5]);
+                        scope = Integer.parseInt(cooked[6]);
+                    } catch(NumberFormatException e) {
+                        throw new IllegalStateException(msg);
+                    }
+
+                    if (cooked[2].equals("updated")) {
+                        notifyAddressUpdated(cooked[3], cooked[4], flags, scope);
+                    } else {
+                        notifyAddressRemoved(cooked[3], cooked[4], flags, scope);
+                    }
+                    return true;
+                    // break;
             default: break;
             }
             return false;
@@ -762,6 +840,18 @@
     }
 
     @Override
+    public void setMtu(String iface, int mtu) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        final NativeDaemonEvent event;
+        try {
+            event = mConnector.execute("interface", "setmtu", iface, mtu);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
     public void shutdown() {
         // TODO: remove from aidl if nobody calls externally
         mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
@@ -990,7 +1080,8 @@
                 mConnector.execute("softap", "set", wlanIface);
             } else {
                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                        getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey));
+                                   "broadcast", "6", getSecurityType(wifiConfig),
+                                   new SensitiveArg(wifiConfig.preSharedKey));
             }
             mConnector.execute("softap", "startap");
         } catch (NativeDaemonConnectorException e) {
@@ -1039,7 +1130,8 @@
                 mConnector.execute("softap", "set", wlanIface);
             } else {
                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                        getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey));
+                                   "broadcast", "6", getSecurityType(wifiConfig),
+                                   new SensitiveArg(wifiConfig.preSharedKey));
             }
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
@@ -1283,55 +1375,42 @@
     }
 
     @Override
-    public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
+    public NetworkStats getNetworkStatsTethering() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        if (ifacePairs.length % 2 != 0) {
-            throw new IllegalArgumentException(
-                    "unexpected ifacePairs; length=" + ifacePairs.length);
-        }
-
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
-        for (int i = 0; i < ifacePairs.length; i += 2) {
-            final String ifaceIn = ifacePairs[i];
-            final String ifaceOut = ifacePairs[i + 1];
-            if (ifaceIn != null && ifaceOut != null) {
-                stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
-            }
-        }
-        return stats;
-    }
-
-    private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
-        final NativeDaemonEvent event;
         try {
-            event = mConnector.execute("bandwidth", "gettetherstats", ifaceIn, ifaceOut);
+            final NativeDaemonEvent[] events = mConnector.executeForList(
+                    "bandwidth", "gettetherstats");
+            for (NativeDaemonEvent event : events) {
+                if (event.getCode() != TetheringStatsListResult) continue;
+
+                // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
+                final StringTokenizer tok = new StringTokenizer(event.getMessage());
+                try {
+                    final String ifaceIn = tok.nextToken();
+                    final String ifaceOut = tok.nextToken();
+
+                    final NetworkStats.Entry entry = new NetworkStats.Entry();
+                    entry.iface = ifaceOut;
+                    entry.uid = UID_TETHERING;
+                    entry.set = SET_DEFAULT;
+                    entry.tag = TAG_NONE;
+                    entry.rxBytes = Long.parseLong(tok.nextToken());
+                    entry.rxPackets = Long.parseLong(tok.nextToken());
+                    entry.txBytes = Long.parseLong(tok.nextToken());
+                    entry.txPackets = Long.parseLong(tok.nextToken());
+                    stats.combineValues(entry);
+                } catch (NoSuchElementException e) {
+                    throw new IllegalStateException("problem parsing tethering stats: " + event);
+                } catch (NumberFormatException e) {
+                    throw new IllegalStateException("problem parsing tethering stats: " + event);
+                }
+            }
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
-
-        event.checkCode(TetheringStatsResult);
-
-        // 221 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
-        final StringTokenizer tok = new StringTokenizer(event.getMessage());
-        tok.nextToken();
-        tok.nextToken();
-
-        try {
-            final NetworkStats.Entry entry = new NetworkStats.Entry();
-            entry.iface = ifaceIn;
-            entry.uid = UID_TETHERING;
-            entry.set = SET_DEFAULT;
-            entry.tag = TAG_NONE;
-            entry.rxBytes = Long.parseLong(tok.nextToken());
-            entry.rxPackets = Long.parseLong(tok.nextToken());
-            entry.txBytes = Long.parseLong(tok.nextToken());
-            entry.txPackets = Long.parseLong(tok.nextToken());
-            return entry;
-        } catch (NumberFormatException e) {
-            throw new IllegalStateException(
-                    "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
-        }
+        return stats;
     }
 
     @Override
@@ -1366,6 +1445,149 @@
     }
 
     @Override
+    public void setUidRangeRoute(String iface, int uid_start, int uid_end) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark",
+                    "uid", "add", iface, uid_start, uid_end);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearUidRangeRoute(String iface, int uid_start, int uid_end) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark",
+                    "uid", "remove", iface, uid_start, uid_end);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void setMarkedForwarding(String iface) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark", "rule", "add", iface);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearMarkedForwarding(String iface) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark", "rule", "remove", iface);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public int getMarkForUid(int uid) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        final NativeDaemonEvent event;
+        try {
+            event = mConnector.execute("interface", "fwmark", "get", "mark", uid);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+        event.checkCode(GetMarkResult);
+        return Integer.parseInt(event.getMessage());
+    }
+
+    @Override
+    public int getMarkForProtect() {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        final NativeDaemonEvent event;
+        try {
+            event = mConnector.execute("interface", "fwmark", "get", "protect");
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+        event.checkCode(GetMarkResult);
+        return Integer.parseInt(event.getMessage());
+    }
+
+    @Override
+    public void setMarkedForwardingRoute(String iface, RouteInfo route) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            LinkAddress dest = route.getDestination();
+            mConnector.execute("interface", "fwmark", "route", "add", iface,
+                    dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearMarkedForwardingRoute(String iface, RouteInfo route) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            LinkAddress dest = route.getDestination();
+            mConnector.execute("interface", "fwmark", "route", "remove", iface,
+                    dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void setHostExemption(LinkAddress host) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark", "exempt", "add", host);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearHostExemption(LinkAddress host) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark", "exempt", "remove", host);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearDnsInterfaceForUidRange(int uid_start, int uid_end) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("resolver", "clearifaceforuidrange", uid_start, uid_end);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearDnsInterfaceMaps() {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("resolver", "clearifacemapping");
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+
+    @Override
     public void flushDefaultDnsCache() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index 3bfd190..fddb54e 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -71,7 +71,6 @@
 
     // NTP lookup is done on this thread and handler
     private Handler mHandler;
-    private HandlerThread mThread;
     private AlarmManager mAlarmManager;
     private PendingIntent mPendingPollIntent;
     private SettingsObserver mSettingsObserver;
@@ -109,14 +108,14 @@
     }
 
     /** Initialize the receivers and initiate the first NTP request */
-    public void systemReady() {
+    public void systemRunning() {
         registerForTelephonyIntents();
         registerForAlarms();
         registerForConnectivityIntents();
 
-        mThread = new HandlerThread(TAG);
-        mThread.start();
-        mHandler = new MyHandler(mThread.getLooper());
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mHandler = new MyHandler(thread.getLooper());
         // Check the network time on the new thread
         mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
 
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 29780c0..b881934 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -75,6 +75,9 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
 
+import com.android.internal.R;
+
+import com.android.internal.notification.NotificationScorer;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -199,6 +202,8 @@
     private static final String TAG_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
 
+    private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+
     private class NotificationListenerInfo implements DeathRecipient {
         INotificationListener listener;
         ComponentName component;
@@ -707,7 +712,7 @@
             intent.setComponent(name);
 
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
-                    com.android.internal.R.string.notification_listener_binding_label);
+                    R.string.notification_listener_binding_label);
             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                     mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
 
@@ -1297,19 +1302,19 @@
 
         Resources resources = mContext.getResources();
         mDefaultNotificationColor = resources.getColor(
-                com.android.internal.R.color.config_defaultNotificationColor);
+                R.color.config_defaultNotificationColor);
         mDefaultNotificationLedOn = resources.getInteger(
-                com.android.internal.R.integer.config_defaultNotificationLedOn);
+                R.integer.config_defaultNotificationLedOn);
         mDefaultNotificationLedOff = resources.getInteger(
-                com.android.internal.R.integer.config_defaultNotificationLedOff);
+                R.integer.config_defaultNotificationLedOff);
 
         mDefaultVibrationPattern = getLongArray(resources,
-                com.android.internal.R.array.config_defaultNotificationVibePattern,
+                R.array.config_defaultNotificationVibePattern,
                 VIBRATE_PATTERN_MAXLEN,
                 DEFAULT_VIBRATE_PATTERN);
 
         mFallbackVibrationPattern = getLongArray(resources,
-                com.android.internal.R.array.config_notificationFallbackVibePattern,
+                R.array.config_notificationFallbackVibePattern,
                 VIBRATE_PATTERN_MAXLEN,
                 DEFAULT_VIBRATE_PATTERN);
 
@@ -1344,6 +1349,24 @@
 
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
+
+        // spin up NotificationScorers
+        String[] notificationScorerNames = resources.getStringArray(
+                R.array.config_notificationScorers);
+        for (String scorerName : notificationScorerNames) {
+            try {
+                Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName);
+                NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
+                scorer.initialize(mContext);
+                mScorers.add(scorer);
+            } catch (ClassNotFoundException e) {
+                Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
+            } catch (InstantiationException e) {
+                Slog.w(TAG, "Couldn't instantiate scorer " + scorerName + ".", e);
+            } catch (IllegalAccessException e) {
+                Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
+            }
+        }
     }
 
     /**
@@ -1476,7 +1499,7 @@
             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
             try {
                 record.callback.show();
-                scheduleTimeoutLocked(record, false);
+                scheduleTimeoutLocked(record);
                 return;
             } catch (RemoteException e) {
                 Slog.w(TAG, "Object died trying to show notification " + record.callback
@@ -1516,12 +1539,14 @@
         }
     }
 
-    private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
+    private void scheduleTimeoutLocked(ToastRecord r)
     {
-        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
-        long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
         mHandler.removeCallbacksAndMessages(r);
-        mHandler.sendMessageDelayed(m, delay);
+        if (r.duration != Toast.LENGTH_INFINITE) {
+            Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
+            long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+            mHandler.sendMessageDelayed(m, delay);
+        }
     }
 
     private void handleTimeout(ToastRecord record)
@@ -1599,8 +1624,10 @@
 
     // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
     // uid/pid of another application)
-    public void enqueueNotificationInternal(String pkg, String basePkg, int callingUid,
-            int callingPid, String tag, int id, Notification notification, int[] idOut, int userId)
+
+    public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
+            final int callingPid, final String tag, final int id, final Notification notification,
+            int[] idOut, int incomingUserId)
     {
         if (DBG) {
             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
@@ -1608,8 +1635,8 @@
         checkCallerIsSystemOrSameApp(pkg);
         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
 
-        userId = ActivityManager.handleIncomingUser(callingPid,
-                callingUid, userId, true, false, "enqueueNotification", pkg);
+        final int userId = ActivityManager.handleIncomingUser(callingPid,
+                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
         final UserHandle user = new UserHandle(userId);
 
         // Limit the number of notifications that any given package except the android
@@ -1651,244 +1678,284 @@
             }
         }
 
-        // === Scoring ===
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
 
-        // 0. Sanitize inputs
-        notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX);
-        // Migrate notification flags to scores
-        if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
-            if (notification.priority < Notification.PRIORITY_MAX) notification.priority = Notification.PRIORITY_MAX;
-        } else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
-            if (notification.priority < Notification.PRIORITY_HIGH) notification.priority = Notification.PRIORITY_HIGH;
-        }
+                // === Scoring ===
 
-        // 1. initial score: buckets of 10, around the app 
-        int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
-
-        // 2. Consult external heuristics (TBD)
-
-        // 3. Apply local rules
-
-        // blocked apps
-        if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
-            if (!isSystemNotification) {
-                score = JUNK_SCORE;
-                Slog.e(TAG, "Suppressing notification from package " + pkg + " by user request.");
-            }
-        }
-
-        if (DBG) {
-            Slog.v(TAG, "Assigned score=" + score + " to " + notification);
-        }
-
-        if (score < SCORE_DISPLAY_THRESHOLD) {
-            // Notification will be blocked because the score is too low.
-            return;
-        }
-
-        // Should this notification make noise, vibe, or use the LED?
-        final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
-
-        synchronized (mNotificationList) {
-            final StatusBarNotification n = new StatusBarNotification(
-                    pkg, id, tag, callingUid, callingPid, score, notification, user);
-            NotificationRecord r = new NotificationRecord(n);
-            NotificationRecord old = null;
-
-            int index = indexOfNotificationLocked(pkg, tag, id, userId);
-            if (index < 0) {
-                mNotificationList.add(r);
-            } else {
-                old = mNotificationList.remove(index);
-                mNotificationList.add(index, r);
-                // Make sure we don't lose the foreground service state.
-                if (old != null) {
-                    notification.flags |=
-                        old.getNotification().flags&Notification.FLAG_FOREGROUND_SERVICE;
+                // 0. Sanitize inputs
+                notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
+                        Notification.PRIORITY_MAX);
+                // Migrate notification flags to scores
+                if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
+                    if (notification.priority < Notification.PRIORITY_MAX) {
+                        notification.priority = Notification.PRIORITY_MAX;
+                    }
+                } else if (SCORE_ONGOING_HIGHER &&
+                        0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
+                    if (notification.priority < Notification.PRIORITY_HIGH) {
+                        notification.priority = Notification.PRIORITY_HIGH;
+                    }
                 }
-            }
 
-            // Ensure if this is a foreground service that the proper additional
-            // flags are set.
-            if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
-                notification.flags |= Notification.FLAG_ONGOING_EVENT
-                        | Notification.FLAG_NO_CLEAR;
-            }
+                // 1. initial score: buckets of 10, around the app
+                int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
 
-            final int currentUser;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                currentUser = ActivityManager.getCurrentUser();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+                // 2. Consult external heuristics (TBD)
 
-            if (notification.icon != 0) {
-                if (old != null && old.statusBarKey != null) {
-                    r.statusBarKey = old.statusBarKey;
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        mStatusBar.updateNotification(r.statusBarKey, n);
-                    }
-                    finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                } else {
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        r.statusBarKey = mStatusBar.addNotification(n);
-                        if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
-                                && canInterrupt) {
-                            mAttentionLight.pulse();
+                // 3. Apply local rules
+
+                int initialScore = score;
+                if (!mScorers.isEmpty()) {
+                    if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
+                    for (NotificationScorer scorer : mScorers) {
+                        try {
+                            score = scorer.getScore(notification, score);
+                        } catch (Throwable t) {
+                            Slog.w(TAG, "Scorer threw on .getScore.", t);
                         }
                     }
-                    finally {
-                        Binder.restoreCallingIdentity(identity);
+                    if (DBG) Slog.v(TAG, "Final score is " + score + ".");
+                }
+
+                // add extra to indicate score modified by NotificationScorer
+                notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
+                        score != initialScore);
+
+                // blocked apps
+                if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
+                    if (!isSystemNotification) {
+                        score = JUNK_SCORE;
+                        Slog.e(TAG, "Suppressing notification from package " + pkg
+                                + " by user request.");
                     }
                 }
-                // Send accessibility events only for the current user.
-                if (currentUser == userId) {
-                    sendAccessibilityEvent(notification, pkg);
+
+                if (DBG) {
+                    Slog.v(TAG, "Assigned score=" + score + " to " + notification);
                 }
 
-                notifyPostedLocked(r);
-            } else {
-                Slog.e(TAG, "Not posting notification with icon==0: " + notification);
-                if (old != null && old.statusBarKey != null) {
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        mStatusBar.removeNotification(old.statusBarKey);
-                    }
-                    finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-
-                    notifyRemovedLocked(r);
-                }
-                // ATTENTION: in a future release we will bail out here
-                // so that we do not play sounds, show lights, etc. for invalid notifications
-                Slog.e(TAG, "WARNING: In a future release this will crash the app: " + n.getPackageName());
-            }
-
-            // If we're not supposed to beep, vibrate, etc. then don't.
-            if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
-                    && (!(old != null
-                        && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
-                    && (r.getUserId() == UserHandle.USER_ALL ||
-                        (r.getUserId() == userId && r.getUserId() == currentUser))
-                    && canInterrupt
-                    && mSystemReady) {
-
-                final AudioManager audioManager = (AudioManager) mContext
-                .getSystemService(Context.AUDIO_SERVICE);
-
-                // sound
-
-                // should we use the default notification sound? (indicated either by DEFAULT_SOUND
-                // or because notification.sound is pointing at Settings.System.NOTIFICATION_SOUND)
-                final boolean useDefaultSound =
-                       (notification.defaults & Notification.DEFAULT_SOUND) != 0
-                    || Settings.System.DEFAULT_NOTIFICATION_URI.equals(notification.sound);
-
-                Uri soundUri = null;
-                boolean hasValidSound = false;
-
-                if (useDefaultSound) {
-                    soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
-
-                    // check to see if the default notification sound is silent
-                    ContentResolver resolver = mContext.getContentResolver();
-                    hasValidSound = Settings.System.getString(resolver,
-                           Settings.System.NOTIFICATION_SOUND) != null;
-                } else if (notification.sound != null) {
-                    soundUri = notification.sound;
-                    hasValidSound = (soundUri != null);
+                if (score < SCORE_DISPLAY_THRESHOLD) {
+                    // Notification will be blocked because the score is too low.
+                    return;
                 }
 
-                if (hasValidSound) {
-                    boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
-                    int audioStreamType;
-                    if (notification.audioStreamType >= 0) {
-                        audioStreamType = notification.audioStreamType;
+                // Should this notification make noise, vibe, or use the LED?
+                final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
+
+                synchronized (mNotificationList) {
+                    final StatusBarNotification n = new StatusBarNotification(
+                            pkg, id, tag, callingUid, callingPid, score, notification, user);
+                    NotificationRecord r = new NotificationRecord(n);
+                    NotificationRecord old = null;
+
+                    int index = indexOfNotificationLocked(pkg, tag, id, userId);
+                    if (index < 0) {
+                        mNotificationList.add(r);
                     } else {
-                        audioStreamType = DEFAULT_STREAM_TYPE;
+                        old = mNotificationList.remove(index);
+                        mNotificationList.add(index, r);
+                        // Make sure we don't lose the foreground service state.
+                        if (old != null) {
+                            notification.flags |=
+                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
+                        }
                     }
-                    mSoundNotification = r;
-                    // do not play notifications if stream volume is 0
-                    // (typically because ringer mode is silent) or if speech recognition is active.
-                    if ((audioManager.getStreamVolume(audioStreamType) != 0)
-                            && !audioManager.isSpeechRecognitionActive()) {
-                        final long identity = Binder.clearCallingIdentity();
-                        try {
-                            final IRingtonePlayer player = mAudioService.getRingtonePlayer();
-                            if (player != null) {
-                                player.playAsync(soundUri, user, looping, audioStreamType);
+
+                    // Ensure if this is a foreground service that the proper additional
+                    // flags are set.
+                    if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+                        notification.flags |= Notification.FLAG_ONGOING_EVENT
+                                | Notification.FLAG_NO_CLEAR;
+                    }
+
+                    final int currentUser;
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        currentUser = ActivityManager.getCurrentUser();
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+
+                    if (notification.icon != 0) {
+                        if (old != null && old.statusBarKey != null) {
+                            r.statusBarKey = old.statusBarKey;
+                            long identity = Binder.clearCallingIdentity();
+                            try {
+                                mStatusBar.updateNotification(r.statusBarKey, n);
                             }
-                        } catch (RemoteException e) {
-                        } finally {
-                            Binder.restoreCallingIdentity(identity);
+                            finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
+                        } else {
+                            long identity = Binder.clearCallingIdentity();
+                            try {
+                                r.statusBarKey = mStatusBar.addNotification(n);
+                                if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
+                                        && canInterrupt) {
+                                    mAttentionLight.pulse();
+                                }
+                            }
+                            finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
+                        }
+                        // Send accessibility events only for the current user.
+                        if (currentUser == userId) {
+                            sendAccessibilityEvent(notification, pkg);
+                        }
+
+                        notifyPostedLocked(r);
+                    } else {
+                        Slog.e(TAG, "Not posting notification with icon==0: " + notification);
+                        if (old != null && old.statusBarKey != null) {
+                            long identity = Binder.clearCallingIdentity();
+                            try {
+                                mStatusBar.removeNotification(old.statusBarKey);
+                            }
+                            finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
+
+                            notifyRemovedLocked(r);
+                        }
+                        // ATTENTION: in a future release we will bail out here
+                        // so that we do not play sounds, show lights, etc. for invalid notifications
+                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
+                                + n.getPackageName());
+                    }
+
+                    // If we're not supposed to beep, vibrate, etc. then don't.
+                    if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
+                            && (!(old != null
+                                && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
+                            && (r.getUserId() == UserHandle.USER_ALL ||
+                                (r.getUserId() == userId && r.getUserId() == currentUser))
+                            && canInterrupt
+                            && mSystemReady) {
+
+                        final AudioManager audioManager = (AudioManager) mContext
+                        .getSystemService(Context.AUDIO_SERVICE);
+
+                        // sound
+
+                        // should we use the default notification sound? (indicated either by
+                        // DEFAULT_SOUND or because notification.sound is pointing at
+                        // Settings.System.NOTIFICATION_SOUND)
+                        final boolean useDefaultSound =
+                               (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
+                                       Settings.System.DEFAULT_NOTIFICATION_URI
+                                               .equals(notification.sound);
+
+                        Uri soundUri = null;
+                        boolean hasValidSound = false;
+
+                        if (useDefaultSound) {
+                            soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+
+                            // check to see if the default notification sound is silent
+                            ContentResolver resolver = mContext.getContentResolver();
+                            hasValidSound = Settings.System.getString(resolver,
+                                   Settings.System.NOTIFICATION_SOUND) != null;
+                        } else if (notification.sound != null) {
+                            soundUri = notification.sound;
+                            hasValidSound = (soundUri != null);
+                        }
+
+                        if (hasValidSound) {
+                            boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
+                            int audioStreamType;
+                            if (notification.audioStreamType >= 0) {
+                                audioStreamType = notification.audioStreamType;
+                            } else {
+                                audioStreamType = DEFAULT_STREAM_TYPE;
+                            }
+                            mSoundNotification = r;
+                            // do not play notifications if stream volume is 0 (typically because
+                            // ringer mode is silent) or if there is a user of exclusive audio focus
+                            if ((audioManager.getStreamVolume(audioStreamType) != 0)
+                                    && !audioManager.isAudioFocusExclusive()) {
+                                final long identity = Binder.clearCallingIdentity();
+                                try {
+                                    final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                                    if (player != null) {
+                                        player.playAsync(soundUri, user, looping, audioStreamType);
+                                    }
+                                } catch (RemoteException e) {
+                                } finally {
+                                    Binder.restoreCallingIdentity(identity);
+                                }
+                            }
+                        }
+
+                        // vibrate
+                        // Does the notification want to specify its own vibration?
+                        final boolean hasCustomVibrate = notification.vibrate != null;
+
+                        // new in 4.2: if there was supposed to be a sound and we're in vibrate
+                        // mode, and no other vibration is specified, we fall back to vibration
+                        final boolean convertSoundToVibration =
+                                   !hasCustomVibrate
+                                && hasValidSound
+                                && (audioManager.getRingerMode()
+                                           == AudioManager.RINGER_MODE_VIBRATE);
+
+                        // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
+                        final boolean useDefaultVibrate =
+                                (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
+
+                        if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
+                                && !(audioManager.getRingerMode()
+                                        == AudioManager.RINGER_MODE_SILENT)) {
+                            mVibrateNotification = r;
+
+                            if (useDefaultVibrate || convertSoundToVibration) {
+                                // Escalate privileges so we can use the vibrator even if the
+                                // notifying app does not have the VIBRATE permission.
+                                long identity = Binder.clearCallingIdentity();
+                                try {
+                                    mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
+                                        useDefaultVibrate ? mDefaultVibrationPattern
+                                            : mFallbackVibrationPattern,
+                                        ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+                                                ? 0: -1);
+                                } finally {
+                                    Binder.restoreCallingIdentity(identity);
+                                }
+                            } else if (notification.vibrate.length > 1) {
+                                // If you want your own vibration pattern, you need the VIBRATE
+                                // permission
+                                mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
+                                        notification.vibrate,
+                                    ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+                                            ? 0: -1);
+                            }
+                        }
+                    }
+
+                    // light
+                    // the most recent thing gets the light
+                    mLights.remove(old);
+                    if (mLedNotification == old) {
+                        mLedNotification = null;
+                    }
+                    //Slog.i(TAG, "notification.lights="
+                    //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS)
+                    //                  != 0));
+                    if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
+                            && canInterrupt) {
+                        mLights.add(r);
+                        updateLightsLocked();
+                    } else {
+                        if (old != null
+                                && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) {
+                            updateLightsLocked();
                         }
                     }
                 }
-
-                // vibrate
-                // Does the notification want to specify its own vibration?
-                final boolean hasCustomVibrate = notification.vibrate != null;
-
-                // new in 4.2: if there was supposed to be a sound and we're in vibrate mode,
-                // and no other vibration is specified, we fall back to vibration
-                final boolean convertSoundToVibration =
-                           !hasCustomVibrate
-                        && hasValidSound
-                        && (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
-
-                // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
-                final boolean useDefaultVibrate =
-                        (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
-
-                if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
-                        && !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) {
-                    mVibrateNotification = r;
-
-                    if (useDefaultVibrate || convertSoundToVibration) {
-                        // Escalate privileges so we can use the vibrator even if the notifying app
-                        // does not have the VIBRATE permission.
-                        long identity = Binder.clearCallingIdentity();
-                        try {
-                            mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
-                                useDefaultVibrate ? mDefaultVibrationPattern
-                                    : mFallbackVibrationPattern,
-                                ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
-                        } finally {
-                            Binder.restoreCallingIdentity(identity);
-                        }
-                    } else if (notification.vibrate.length > 1) {
-                        // If you want your own vibration pattern, you need the VIBRATE permission
-                        mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(), notification.vibrate,
-                            ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
-                    }
-                }
             }
-
-            // light
-            // the most recent thing gets the light
-            mLights.remove(old);
-            if (mLedNotification == old) {
-                mLedNotification = null;
-            }
-            //Slog.i(TAG, "notification.lights="
-            //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
-            if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
-                    && canInterrupt) {
-                mLights.add(r);
-                updateLightsLocked();
-            } else {
-                if (old != null
-                        && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) {
-                    updateLightsLocked();
-                }
-            }
-        }
+        });
 
         idOut[0] = id;
     }
@@ -1980,29 +2047,39 @@
      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
      * and none of the {@code mustNotHaveFlags}.
      */
-    private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
-            int mustNotHaveFlags, boolean sendDelete, int userId) {
-        EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag, userId,
-                mustHaveFlags, mustNotHaveFlags);
+    private void cancelNotification(final String pkg, final String tag, final int id,
+            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
+            final int userId) {
+        // In enqueueNotificationInternal notifications are added by scheduling the
+        // work on the worker handler. Hence, we also schedule the cancel on this
+        // handler to avoid a scenario where an add notification call followed by a
+        // remove notification call ends up in not removing the notification.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag, userId,
+                        mustHaveFlags, mustNotHaveFlags);
 
-        synchronized (mNotificationList) {
-            int index = indexOfNotificationLocked(pkg, tag, id, userId);
-            if (index >= 0) {
-                NotificationRecord r = mNotificationList.get(index);
+                synchronized (mNotificationList) {
+                    int index = indexOfNotificationLocked(pkg, tag, id, userId);
+                    if (index >= 0) {
+                        NotificationRecord r = mNotificationList.get(index);
 
-                if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
-                    return;
+                        if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
+                            return;
+                        }
+                        if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
+                            return;
+                        }
+
+                        mNotificationList.remove(index);
+
+                        cancelNotificationLocked(r, sendDelete);
+                        updateLightsLocked();
+                    }
                 }
-                if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
-                    return;
-                }
-
-                mNotificationList.remove(index);
-
-                cancelNotificationLocked(r, sendDelete);
-                updateLightsLocked();
             }
-        }
+        });
     }
 
     /**
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index faa72a2..e0f415b 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -417,7 +417,15 @@
                 int keyId = clientInfo.mClientIds.indexOfValue(id);
                 if (keyId != -1) {
                     clientId = clientInfo.mClientIds.keyAt(keyId);
+                } else {
+                    // This can happen because of race conditions. For example,
+                    // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
+                    // and we may get in this situation.
+                    Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
+                    handled = false;
+                    return handled;
                 }
+
                 switch (code) {
                     case NativeResponseCode.SERVICE_FOUND:
                         /* NNN uniqueId serviceName regType domain */
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/java/com/android/server/PreferredComponent.java
index bb22545..a7af252 100644
--- a/services/java/com/android/server/PreferredComponent.java
+++ b/services/java/com/android/server/PreferredComponent.java
@@ -33,8 +33,16 @@
 import java.util.List;
 
 public class PreferredComponent {
+    private static final String TAG_SET = "set";
+    private static final String ATTR_ALWAYS = "always"; // boolean
+    private static final String ATTR_MATCH = "match"; // number
+    private static final String ATTR_NAME = "name"; // component name
+    private static final String ATTR_SET = "set"; // number
+
     public final int mMatch;
     public final ComponentName mComponent;
+    // Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
+    public boolean mAlways;
 
     private final String[] mSetPackages;
     private final String[] mSetClasses;
@@ -50,10 +58,11 @@
     }
 
     public PreferredComponent(Callbacks callbacks, int match, ComponentName[] set,
-            ComponentName component) {
+            ComponentName component, boolean always) {
         mCallbacks = callbacks;
         mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
         mComponent = component;
+        mAlways = always;
         mShortComponent = component.flattenToShortString();
         mParseError = null;
         if (set != null) {
@@ -71,7 +80,7 @@
                 }
                 myPackages[i] = cn.getPackageName().intern();
                 myClasses[i] = cn.getClassName().intern();
-                myComponents[i] = cn.flattenToShortString().intern();
+                myComponents[i] = cn.flattenToShortString();
             }
             mSetPackages = myPackages;
             mSetClasses = myClasses;
@@ -86,15 +95,17 @@
     public PreferredComponent(Callbacks callbacks, XmlPullParser parser)
             throws XmlPullParserException, IOException {
         mCallbacks = callbacks;
-        mShortComponent = parser.getAttributeValue(null, "name");
+        mShortComponent = parser.getAttributeValue(null, ATTR_NAME);
         mComponent = ComponentName.unflattenFromString(mShortComponent);
         if (mComponent == null) {
             mParseError = "Bad activity name " + mShortComponent;
         }
-        String matchStr = parser.getAttributeValue(null, "match");
+        String matchStr = parser.getAttributeValue(null, ATTR_MATCH);
         mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
-        String setCountStr = parser.getAttributeValue(null, "set");
+        String setCountStr = parser.getAttributeValue(null, ATTR_SET);
         int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
+        String alwaysStr = parser.getAttributeValue(null, ATTR_ALWAYS);
+        mAlways = alwaysStr != null ? Boolean.parseBoolean(alwaysStr) : true;
 
         String[] myPackages = setCount > 0 ? new String[setCount] : null;
         String[] myClasses = setCount > 0 ? new String[setCount] : null;
@@ -115,8 +126,8 @@
             String tagName = parser.getName();
             //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
             //        + parser.getDepth() + " tag=" + tagName);
-            if (tagName.equals("set")) {
-                String name = parser.getAttributeValue(null, "name");
+            if (tagName.equals(TAG_SET)) {
+                String name = parser.getAttributeValue(null, ATTR_NAME);
                 if (name == null) {
                     if (mParseError == null) {
                         mParseError = "No name in set tag in preferred activity "
@@ -166,16 +177,17 @@
 
     public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
         final int NS = mSetClasses != null ? mSetClasses.length : 0;
-        serializer.attribute(null, "name", mShortComponent);
+        serializer.attribute(null, ATTR_NAME, mShortComponent);
         if (full) {
             if (mMatch != 0) {
-                serializer.attribute(null, "match", Integer.toHexString(mMatch));
+                serializer.attribute(null, ATTR_MATCH, Integer.toHexString(mMatch));
             }
-            serializer.attribute(null, "set", Integer.toString(NS));
+            serializer.attribute(null, ATTR_ALWAYS, Boolean.toString(mAlways));
+            serializer.attribute(null, ATTR_SET, Integer.toString(NS));
             for (int s=0; s<NS; s++) {
-                serializer.startTag(null, "set");
-                serializer.attribute(null, "name", mSetComponents[s]);
-                serializer.endTag(null, "set");
+                serializer.startTag(null, TAG_SET);
+                serializer.attribute(null, ATTR_NAME, mSetComponents[s]);
+                serializer.endTag(null, TAG_SET);
             }
         }
     }
@@ -207,9 +219,10 @@
         out.print(prefix); out.print(
                 Integer.toHexString(System.identityHashCode(ident)));
                 out.print(' ');
-                out.print(mComponent.flattenToShortString());
-                out.print(" match=0x");
-                out.println( Integer.toHexString(mMatch));
+                out.println(mShortComponent);
+        out.print(prefix); out.print(" mMatch=0x");
+                out.print(Integer.toHexString(mMatch));
+                out.print(" mAlways="); out.println(mAlways);
         if (mSetComponents != null) {
             out.print(prefix); out.println("  Selected from:");
             for (int i=0; i<mSetComponents.length; i++) {
diff --git a/services/java/com/android/server/ProcessMap.java b/services/java/com/android/server/ProcessMap.java
deleted file mode 100644
index 6b26403..0000000
--- a/services/java/com/android/server/ProcessMap.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server;
-
-import android.util.SparseArray;
-
-import java.util.HashMap;
-
-public class ProcessMap<E> {
-    final HashMap<String, SparseArray<E>> mMap
-            = new HashMap<String, SparseArray<E>>();
-    
-    public E get(String name, int uid) {
-        SparseArray<E> uids = mMap.get(name);
-        if (uids == null) return null;
-        return uids.get(uid);
-    }
-    
-    public E put(String name, int uid, E value) {
-        SparseArray<E> uids = mMap.get(name);
-        if (uids == null) {
-            uids = new SparseArray<E>(2);
-            mMap.put(name, uids);
-        }
-        uids.put(uid, value);
-        return value;
-    }
-    
-    public void remove(String name, int uid) {
-        SparseArray<E> uids = mMap.get(name);
-        if (uids != null) {
-            uids.remove(uid);
-            if (uids.size() == 0) {
-                mMap.remove(name);
-            }
-        }
-    }
-    
-    public HashMap<String, SparseArray<E>> getMap() {
-        return mMap;
-    }
-}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index c21d8c6..f207c08 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -399,6 +399,15 @@
         mCurrentUserId = newUserId;
     }
 
+    @Override
+    public void setWindowState(int window, int state) {
+        if (mBar != null) {
+            try {
+                mBar.setWindowState(window, state);
+            } catch (RemoteException ex) {}
+        }
+    }
+
     private void enforceStatusBar() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
                 "StatusBarManagerService");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9455017..ef50df7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -44,6 +44,7 @@
 import android.util.Slog;
 import android.view.WindowManager;
 
+import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.server.accessibility.AccessibilityManagerService;
@@ -62,6 +63,7 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
+import com.android.server.print.PrintManagerService;
 import com.android.server.search.SearchManagerService;
 import com.android.server.usb.UsbService;
 import com.android.server.wifi.WifiService;
@@ -74,7 +76,7 @@
 import java.util.Timer;
 import java.util.TimerTask;
 
-class ServerThread extends Thread {
+class ServerThread {
     private static final String TAG = "SystemServer";
     private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
     private static final String ENCRYPTED_STATE = "1";
@@ -86,8 +88,7 @@
         Log.wtf(TAG, "BOOT FAILURE " + msg, e);
     }
 
-    @Override
-    public void run() {
+    public void initAndLoop() {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
             SystemClock.uptimeMillis());
 
@@ -153,30 +154,7 @@
         CommonTimeManagementService commonTimeMgmtService = null;
         InputManagerService inputManager = null;
         TelephonyRegistry telephonyRegistry = null;
-
-        // Create a shared handler thread for UI within the system server.
-        // This thread is used by at least the following components:
-        // - WindowManagerPolicy
-        // - KeyguardViewManager
-        // - DisplayManagerService
-        HandlerThread uiHandlerThread = new HandlerThread("UI");
-        uiHandlerThread.start();
-        Handler uiHandler = new Handler(uiHandlerThread.getLooper());
-        uiHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                //Looper.myLooper().setMessageLogging(new LogPrinter(
-                //        Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
-                android.os.Process.setThreadPriority(
-                        android.os.Process.THREAD_PRIORITY_FOREGROUND);
-                android.os.Process.setCanSelfBackground(false);
-
-                // For debug builds, log event loop stalls to dropbox for analysis.
-                if (StrictMode.conditionallyEnableDebugLogging()) {
-                    Slog.i(TAG, "Enabled StrictMode logging for UI Looper");
-                }
-            }
-        });
+        ConsumerIrService consumerIr = null;
 
         // Create a handler thread just for the window manager to enjoy.
         HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
@@ -198,8 +176,9 @@
             }
         });
 
-        // Critical services...
+        // bootstrap services
         boolean onlyCore = false;
+        boolean firstBoot = false;
         try {
             // Wait for installd to finished starting up so that it has a chance to
             // create critical directories such as /data/user with the appropriate
@@ -214,9 +193,23 @@
 
             Slog.i(TAG, "Activity Manager");
             context = ActivityManagerService.main(factoryTest);
+        } catch (RuntimeException e) {
+            Slog.e("System", "******************************************");
+            Slog.e("System", "************ Failure starting bootstrap service", e);
+        }
 
+        boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
+        boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
+        boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
+        boolean disableTelephony = SystemProperties.getBoolean("config.disable_telephony", false);
+        boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false);
+        boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
+        boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
+        boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
+
+        try {
             Slog.i(TAG, "Display Manager");
-            display = new DisplayManagerService(context, wmHandler, uiHandler);
+            display = new DisplayManagerService(context, wmHandler);
             ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
 
             Slog.i(TAG, "Telephony Registry");
@@ -224,8 +217,7 @@
             ServiceManager.addService("telephony.registry", telephonyRegistry);
 
             Slog.i(TAG, "Scheduling Policy");
-            ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
-                    new SchedulingPolicyService());
+            ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
 
             AttributeCache.init(context);
 
@@ -248,7 +240,6 @@
             pm = PackageManagerService.main(context, installer,
                     factoryTest != SystemServer.FACTORY_TEST_OFF,
                     onlyCore);
-            boolean firstBoot = false;
             try {
                 firstBoot = pm.isFirstBoot();
             } catch (RemoteException e) {
@@ -267,6 +258,7 @@
 
             // The AccountManager must come before the ContentService
             try {
+                // TODO: seems like this should be disable-able, but req'd by ContentService
                 Slog.i(TAG, "Account Manager");
                 accountManager = new AccountManagerService(context);
                 ServiceManager.addService(Context.ACCOUNT_SERVICE, accountManager);
@@ -292,10 +284,15 @@
             vibrator = new VibratorService(context);
             ServiceManager.addService("vibrator", vibrator);
 
+            Slog.i(TAG, "Consumer IR Service");
+            consumerIr = new ConsumerIrService(context);
+            ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
+
             // only initialize the power service after we have started the
             // lights service, content providers and the battery service.
             power.init(context, lights, ActivityManagerService.self(), battery,
-                    BatteryStatsService.getService(), display);
+                    BatteryStatsService.getService(),
+                    ActivityManagerService.self().getAppOpsService(), display);
 
             Slog.i(TAG, "Alarm Manager");
             alarm = new AlarmManagerService(context);
@@ -304,14 +301,14 @@
             Slog.i(TAG, "Init Watchdog");
             Watchdog.getInstance().init(context, battery, power, alarm,
                     ActivityManagerService.self());
+            Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");
 
             Slog.i(TAG, "Input Manager");
             inputManager = new InputManagerService(context, wmHandler);
 
             Slog.i(TAG, "Window Manager");
             wm = WindowManagerService.main(context, power, display, inputManager,
-                    uiHandler, wmHandler,
-                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
+                    wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                     !firstBoot, onlyCore);
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
@@ -334,12 +331,13 @@
             } else if (!context.getPackageManager().hasSystemFeature
                        (PackageManager.FEATURE_BLUETOOTH)) {
                 Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
+            } else if (disableBluetooth) {
+                Slog.i(TAG, "Bluetooth Service disabled by config");
             } else {
                 Slog.i(TAG, "Bluetooth Manager Service");
                 bluetooth = new BluetoothManagerService(context);
                 ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
             }
-
         } catch (RuntimeException e) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting core service", e);
@@ -356,23 +354,28 @@
         TextServicesManagerService tsms = null;
         LockSettingsService lockSettings = null;
         DreamManagerService dreamy = null;
+        AssetAtlasService atlas = null;
+        PrintManagerService printManager = null;
 
         // Bring up services needed for UI.
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
-            try {
-                Slog.i(TAG, "Input Method Service");
-                imm = new InputMethodManagerService(context, wm);
-                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
-            } catch (Throwable e) {
-                reportWtf("starting Input Manager Service", e);
-            }
+            //if (!disableNonCoreServices) { // TODO: View depends on these; mock them?
+            if (true) {
+                try {
+                    Slog.i(TAG, "Input Method Service");
+                    imm = new InputMethodManagerService(context, wm);
+                    ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
+                } catch (Throwable e) {
+                    reportWtf("starting Input Manager Service", e);
+                }
 
-            try {
-                Slog.i(TAG, "Accessibility Manager");
-                ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
-                        new AccessibilityManagerService(context));
-            } catch (Throwable e) {
-                reportWtf("starting Accessibility Manager", e);
+                try {
+                    Slog.i(TAG, "Accessibility Manager");
+                    ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
+                            new AccessibilityManagerService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting Accessibility Manager", e);
+                }
             }
         }
 
@@ -397,7 +400,8 @@
         }
 
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
-            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+            if (!disableStorage &&
+                !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
                 try {
                     /*
                      * NotificationManagerService is dependant on MountService,
@@ -411,116 +415,130 @@
                 }
             }
 
-            try {
-                Slog.i(TAG,  "LockSettingsService");
-                lockSettings = new LockSettingsService(context);
-                ServiceManager.addService("lock_settings", lockSettings);
-            } catch (Throwable e) {
-                reportWtf("starting LockSettingsService service", e);
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG,  "LockSettingsService");
+                    lockSettings = new LockSettingsService(context);
+                    ServiceManager.addService("lock_settings", lockSettings);
+                } catch (Throwable e) {
+                    reportWtf("starting LockSettingsService service", e);
+                }
+
+                try {
+                    Slog.i(TAG, "Device Policy");
+                    devicePolicy = new DevicePolicyManagerService(context);
+                    ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
+                } catch (Throwable e) {
+                    reportWtf("starting DevicePolicyService", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Device Policy");
-                devicePolicy = new DevicePolicyManagerService(context);
-                ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
-            } catch (Throwable e) {
-                reportWtf("starting DevicePolicyService", e);
+            if (!disableSystemUI) {
+                try {
+                    Slog.i(TAG, "Status Bar");
+                    statusBar = new StatusBarManagerService(context, wm);
+                    ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
+                } catch (Throwable e) {
+                    reportWtf("starting StatusBarManagerService", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Status Bar");
-                statusBar = new StatusBarManagerService(context, wm);
-                ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
-            } catch (Throwable e) {
-                reportWtf("starting StatusBarManagerService", e);
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Clipboard Service");
+                    ServiceManager.addService(Context.CLIPBOARD_SERVICE,
+                            new ClipboardService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting Clipboard Service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Clipboard Service");
-                ServiceManager.addService(Context.CLIPBOARD_SERVICE,
-                        new ClipboardService(context));
-            } catch (Throwable e) {
-                reportWtf("starting Clipboard Service", e);
+            if (!disableNetwork) {
+                try {
+                    Slog.i(TAG, "NetworkManagement Service");
+                    networkManagement = NetworkManagementService.create(context);
+                    ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
+                } catch (Throwable e) {
+                    reportWtf("starting NetworkManagement Service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "NetworkManagement Service");
-                networkManagement = NetworkManagementService.create(context);
-                ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
-            } catch (Throwable e) {
-                reportWtf("starting NetworkManagement Service", e);
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Text Service Manager Service");
+                    tsms = new TextServicesManagerService(context);
+                    ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
+                } catch (Throwable e) {
+                    reportWtf("starting Text Service Manager Service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Text Service Manager Service");
-                tsms = new TextServicesManagerService(context);
-                ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
-            } catch (Throwable e) {
-                reportWtf("starting Text Service Manager Service", e);
+            if (!disableNetwork) {
+                try {
+                    Slog.i(TAG, "NetworkStats Service");
+                    networkStats = new NetworkStatsService(context, networkManagement, alarm);
+                    ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
+                } catch (Throwable e) {
+                    reportWtf("starting NetworkStats Service", e);
+                }
+
+                try {
+                    Slog.i(TAG, "NetworkPolicy Service");
+                    networkPolicy = new NetworkPolicyManagerService(
+                            context, ActivityManagerService.self(), power,
+                            networkStats, networkManagement);
+                    ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
+                } catch (Throwable e) {
+                    reportWtf("starting NetworkPolicy Service", e);
+                }
+
+               try {
+                    Slog.i(TAG, "Wi-Fi P2pService");
+                    wifiP2p = new WifiP2pService(context);
+                    ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);
+                } catch (Throwable e) {
+                    reportWtf("starting Wi-Fi P2pService", e);
+                }
+
+               try {
+                    Slog.i(TAG, "Wi-Fi Service");
+                    wifi = new WifiService(context);
+                    ServiceManager.addService(Context.WIFI_SERVICE, wifi);
+                } catch (Throwable e) {
+                    reportWtf("starting Wi-Fi Service", e);
+                }
+
+                try {
+                    Slog.i(TAG, "Connectivity Service");
+                    connectivity = new ConnectivityService(
+                            context, networkManagement, networkStats, networkPolicy);
+                    ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
+                    networkStats.bindConnectivityManager(connectivity);
+                    networkPolicy.bindConnectivityManager(connectivity);
+                    wifi.checkAndStartWifi();
+                    wifiP2p.connectivityServiceReady();
+                } catch (Throwable e) {
+                    reportWtf("starting Connectivity Service", e);
+                }
+
+                try {
+                    Slog.i(TAG, "Network Service Discovery Service");
+                    serviceDiscovery = NsdService.create(context);
+                    ServiceManager.addService(
+                            Context.NSD_SERVICE, serviceDiscovery);
+                } catch (Throwable e) {
+                    reportWtf("starting Service Discovery Service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "NetworkStats Service");
-                networkStats = new NetworkStatsService(context, networkManagement, alarm);
-                ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
-            } catch (Throwable e) {
-                reportWtf("starting NetworkStats Service", e);
-            }
-
-            try {
-                Slog.i(TAG, "NetworkPolicy Service");
-                networkPolicy = new NetworkPolicyManagerService(
-                        context, ActivityManagerService.self(), power,
-                        networkStats, networkManagement);
-                ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
-            } catch (Throwable e) {
-                reportWtf("starting NetworkPolicy Service", e);
-            }
-
-           try {
-                Slog.i(TAG, "Wi-Fi P2pService");
-                wifiP2p = new WifiP2pService(context);
-                ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);
-            } catch (Throwable e) {
-                reportWtf("starting Wi-Fi P2pService", e);
-            }
-
-           try {
-                Slog.i(TAG, "Wi-Fi Service");
-                wifi = new WifiService(context);
-                ServiceManager.addService(Context.WIFI_SERVICE, wifi);
-            } catch (Throwable e) {
-                reportWtf("starting Wi-Fi Service", e);
-            }
-
-            try {
-                Slog.i(TAG, "Connectivity Service");
-                connectivity = new ConnectivityService(
-                        context, networkManagement, networkStats, networkPolicy);
-                ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
-                networkStats.bindConnectivityManager(connectivity);
-                networkPolicy.bindConnectivityManager(connectivity);
-                wifi.checkAndStartWifi();
-                wifiP2p.connectivityServiceReady();
-            } catch (Throwable e) {
-                reportWtf("starting Connectivity Service", e);
-            }
-
-            try {
-                Slog.i(TAG, "Network Service Discovery Service");
-                serviceDiscovery = NsdService.create(context);
-                ServiceManager.addService(
-                        Context.NSD_SERVICE, serviceDiscovery);
-            } catch (Throwable e) {
-                reportWtf("starting Service Discovery Service", e);
-            }
-
-            try {
-                Slog.i(TAG, "UpdateLock Service");
-                ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
-                        new UpdateLockService(context));
-            } catch (Throwable e) {
-                reportWtf("starting UpdateLockService", e);
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "UpdateLock Service");
+                    ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
+                            new UpdateLockService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting UpdateLockService", e);
+                }
             }
 
             /*
@@ -528,7 +546,7 @@
              * AppWidget Provider. Make sure MountService is completely started
              * first before continuing.
              */
-            if (mountService != null) {
+            if (mountService != null && !onlyCore) {
                 mountService.waitForAsecScan();
             }
 
@@ -563,28 +581,32 @@
                 reportWtf("starting DeviceStorageMonitor service", e);
             }
 
-            try {
-                Slog.i(TAG, "Location Manager");
-                location = new LocationManagerService(context);
-                ServiceManager.addService(Context.LOCATION_SERVICE, location);
-            } catch (Throwable e) {
-                reportWtf("starting Location Manager", e);
+            if (!disableLocation) {
+                try {
+                    Slog.i(TAG, "Location Manager");
+                    location = new LocationManagerService(context);
+                    ServiceManager.addService(Context.LOCATION_SERVICE, location);
+                } catch (Throwable e) {
+                    reportWtf("starting Location Manager", e);
+                }
+
+                try {
+                    Slog.i(TAG, "Country Detector");
+                    countryDetector = new CountryDetectorService(context);
+                    ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
+                } catch (Throwable e) {
+                    reportWtf("starting Country Detector", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Country Detector");
-                countryDetector = new CountryDetectorService(context);
-                ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
-            } catch (Throwable e) {
-                reportWtf("starting Country Detector", e);
-            }
-
-            try {
-                Slog.i(TAG, "Search Service");
-                ServiceManager.addService(Context.SEARCH_SERVICE,
-                        new SearchManagerService(context));
-            } catch (Throwable e) {
-                reportWtf("starting Search Service", e);
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Search Service");
+                    ServiceManager.addService(Context.SEARCH_SERVICE,
+                            new SearchManagerService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting Search Service", e);
+                }
             }
 
             try {
@@ -595,8 +617,8 @@
                 reportWtf("starting DropBoxManagerService", e);
             }
 
-            if (context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_enableWallpaperService)) {
+            if (!disableNonCoreServices && context.getResources().getBoolean(
+                        R.bool.config_enableWallpaperService)) {
                 try {
                     Slog.i(TAG, "Wallpaper Service");
                     if (!headless) {
@@ -608,7 +630,7 @@
                 }
             }
 
-            if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+            if (!disableMedia && !"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
                 try {
                     Slog.i(TAG, "Audio Service");
                     ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
@@ -617,39 +639,45 @@
                 }
             }
 
-            try {
-                Slog.i(TAG, "Dock Observer");
-                // Listen for dock station changes
-                dock = new DockObserver(context);
-            } catch (Throwable e) {
-                reportWtf("starting DockObserver", e);
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Dock Observer");
+                    // Listen for dock station changes
+                    dock = new DockObserver(context);
+                } catch (Throwable e) {
+                    reportWtf("starting DockObserver", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Wired Accessory Manager");
-                // Listen for wired headset changes
-                inputManager.setWiredAccessoryCallbacks(
-                        new WiredAccessoryManager(context, inputManager));
-            } catch (Throwable e) {
-                reportWtf("starting WiredAccessoryManager", e);
+            if (!disableMedia) {
+                try {
+                    Slog.i(TAG, "Wired Accessory Manager");
+                    // Listen for wired headset changes
+                    inputManager.setWiredAccessoryCallbacks(
+                            new WiredAccessoryManager(context, inputManager));
+                } catch (Throwable e) {
+                    reportWtf("starting WiredAccessoryManager", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "USB Service");
-                // Manage USB host and device support
-                usb = new UsbService(context);
-                ServiceManager.addService(Context.USB_SERVICE, usb);
-            } catch (Throwable e) {
-                reportWtf("starting UsbService", e);
-            }
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "USB Service");
+                    // Manage USB host and device support
+                    usb = new UsbService(context);
+                    ServiceManager.addService(Context.USB_SERVICE, usb);
+                } catch (Throwable e) {
+                    reportWtf("starting UsbService", e);
+                }
 
-            try {
-                Slog.i(TAG, "Serial Service");
-                // Serial port support
-                serial = new SerialService(context);
-                ServiceManager.addService(Context.SERIAL_SERVICE, serial);
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting SerialService", e);
+                try {
+                    Slog.i(TAG, "Serial Service");
+                    // Serial port support
+                    serial = new SerialService(context);
+                    ServiceManager.addService(Context.SERIAL_SERVICE, serial);
+                } catch (Throwable e) {
+                    Slog.e(TAG, "Failure starting SerialService", e);
+                }
             }
 
             try {
@@ -667,27 +695,29 @@
                 reportWtf("starting UiModeManagerService", e);
             }
 
-            try {
-                Slog.i(TAG, "Backup Service");
-                ServiceManager.addService(Context.BACKUP_SERVICE,
-                        new BackupManagerService(context));
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Backup Service", e);
-            }
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Backup Service");
+                    ServiceManager.addService(Context.BACKUP_SERVICE,
+                            new BackupManagerService(context));
+                } catch (Throwable e) {
+                    Slog.e(TAG, "Failure starting Backup Service", e);
+                }
 
-            try {
-                Slog.i(TAG, "AppWidget Service");
-                appWidget = new AppWidgetService(context);
-                ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
-            } catch (Throwable e) {
-                reportWtf("starting AppWidget Service", e);
-            }
+                try {
+                    Slog.i(TAG, "AppWidget Service");
+                    appWidget = new AppWidgetService(context);
+                    ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
+                } catch (Throwable e) {
+                    reportWtf("starting AppWidget Service", e);
+                }
 
-            try {
-                Slog.i(TAG, "Recognition Service");
-                recognition = new RecognitionManagerService(context);
-            } catch (Throwable e) {
-                reportWtf("starting Recognition Service", e);
+                try {
+                    Slog.i(TAG, "Recognition Service");
+                    recognition = new RecognitionManagerService(context);
+                } catch (Throwable e) {
+                    reportWtf("starting Recognition Service", e);
+                }
             }
 
             try {
@@ -709,30 +739,36 @@
                 reportWtf("starting SamplingProfiler Service", e);
             }
 
-            try {
-                Slog.i(TAG, "NetworkTimeUpdateService");
-                networkTimeUpdater = new NetworkTimeUpdateService(context);
-            } catch (Throwable e) {
-                reportWtf("starting NetworkTimeUpdate service", e);
+            if (!disableNetwork) {
+                try {
+                    Slog.i(TAG, "NetworkTimeUpdateService");
+                    networkTimeUpdater = new NetworkTimeUpdateService(context);
+                } catch (Throwable e) {
+                    reportWtf("starting NetworkTimeUpdate service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "CommonTimeManagementService");
-                commonTimeMgmtService = new CommonTimeManagementService(context);
-                ServiceManager.addService("commontime_management", commonTimeMgmtService);
-            } catch (Throwable e) {
-                reportWtf("starting CommonTimeManagementService service", e);
+            if (!disableMedia) {
+                try {
+                    Slog.i(TAG, "CommonTimeManagementService");
+                    commonTimeMgmtService = new CommonTimeManagementService(context);
+                    ServiceManager.addService("commontime_management", commonTimeMgmtService);
+                } catch (Throwable e) {
+                    reportWtf("starting CommonTimeManagementService service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "CertBlacklister");
-                CertBlacklister blacklister = new CertBlacklister(context);
-            } catch (Throwable e) {
-                reportWtf("starting CertBlacklister", e);
+            if (!disableNetwork) {
+                try {
+                    Slog.i(TAG, "CertBlacklister");
+                    CertBlacklister blacklister = new CertBlacklister(context);
+                } catch (Throwable e) {
+                    reportWtf("starting CertBlacklister", e);
+                }
             }
-            
-            if (context.getResources().getBoolean(
-                    com.android.internal.R.bool.config_dreamsSupported)) {
+
+            if (!disableNonCoreServices && 
+                context.getResources().getBoolean(R.bool.config_dreamsSupported)) {
                 try {
                     Slog.i(TAG, "Dreams Service");
                     // Dreams (interactive idle-time views, a/k/a screen savers)
@@ -743,12 +779,30 @@
                 }
             }
 
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Assets Atlas Service");
+                    atlas = new AssetAtlasService(context);
+                    ServiceManager.addService(AssetAtlasService.ASSET_ATLAS_SERVICE, atlas);
+                } catch (Throwable e) {
+                    reportWtf("starting AssetAtlasService", e);
+                }
+            }
+
             try {
                 Slog.i(TAG, "IdleMaintenanceService");
                 new IdleMaintenanceService(context, battery);
             } catch (Throwable e) {
                 reportWtf("starting IdleMaintenanceService", e);
             }
+
+            try {
+                Slog.i(TAG, "Print Service");
+                printManager = new PrintManagerService(context);
+                ServiceManager.addService(Context.PRINT_SERVICE, printManager);
+            } catch (Throwable e) {
+                reportWtf("starting Print Service", e);
+            }
         }
 
         // Before things start rolling, be sure we have decided whether
@@ -773,10 +827,12 @@
             reportWtf("making Vibrator Service ready", e);
         }
 
-        try {
-            lockSettings.systemReady();
-        } catch (Throwable e) {
-            reportWtf("making Lock Settings Service ready", e);
+        if (lockSettings != null) {
+            try {
+                lockSettings.systemReady();
+            } catch (Throwable e) {
+                reportWtf("making Lock Settings Service ready", e);
+            }
         }
 
         if (devicePolicy != null) {
@@ -855,8 +911,10 @@
         final TextServicesManagerService textServiceManagerServiceF = tsms;
         final StatusBarManagerService statusBarF = statusBar;
         final DreamManagerService dreamyF = dreamy;
+        final AssetAtlasService atlasF = atlas;
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
+        final PrintManagerService printManagerF = printManager;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -872,7 +930,9 @@
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
-                if (!headless) startSystemUi(contextF);
+                if (!headless) {
+                    startSystemUi(contextF);
+                }
                 try {
                     if (mountServiceF != null) mountServiceF.systemReady();
                 } catch (Throwable e) {
@@ -934,60 +994,73 @@
                 // third party code...
 
                 try {
-                    if (appWidgetF != null) appWidgetF.systemReady(safeMode);
+                    if (appWidgetF != null) appWidgetF.systemRunning(safeMode);
                 } catch (Throwable e) {
-                    reportWtf("making App Widget Service ready", e);
+                    reportWtf("Notifying AppWidgetService running", e);
                 }
                 try {
-                    if (wallpaperF != null) wallpaperF.systemReady();
+                    if (wallpaperF != null) wallpaperF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making Wallpaper Service ready", e);
+                    reportWtf("Notifying WallpaperService running", e);
                 }
                 try {
-                    if (immF != null) immF.systemReady(statusBarF);
+                    if (immF != null) immF.systemRunning(statusBarF);
                 } catch (Throwable e) {
-                    reportWtf("making Input Method Service ready", e);
+                    reportWtf("Notifying InputMethodService running", e);
                 }
                 try {
-                    if (locationF != null) locationF.systemReady();
+                    if (locationF != null) locationF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making Location Service ready", e);
+                    reportWtf("Notifying Location Service running", e);
                 }
                 try {
-                    if (countryDetectorF != null) countryDetectorF.systemReady();
+                    if (countryDetectorF != null) countryDetectorF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making Country Detector Service ready", e);
+                    reportWtf("Notifying CountryDetectorService running", e);
                 }
                 try {
-                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
+                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making Network Time Service ready", e);
+                    reportWtf("Notifying NetworkTimeService running", e);
                 }
                 try {
-                    if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady();
+                    if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making Common time management service ready", e);
+                    reportWtf("Notifying CommonTimeManagementService running", e);
                 }
                 try {
-                    if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
+                    if (textServiceManagerServiceF != null)
+                        textServiceManagerServiceF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making Text Services Manager Service ready", e);
+                    reportWtf("Notifying TextServicesManagerService running", e);
                 }
                 try {
-                    if (dreamyF != null) dreamyF.systemReady();
+                    if (dreamyF != null) dreamyF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making DreamManagerService ready", e);
+                    reportWtf("Notifying DreamManagerService running", e);
+                }
+                try {
+                    if (atlasF != null) atlasF.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying AssetAtlasService running", e);
                 }
                 try {
                     // TODO(BT) Pass parameter to input manager
-                    if (inputManagerF != null) inputManagerF.systemReady();
+                    if (inputManagerF != null) inputManagerF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making InputManagerService ready", e);
+                    reportWtf("Notifying InputManagerService running", e);
                 }
+
                 try {
-                    if (telephonyRegistryF != null) telephonyRegistryF.systemReady();
+                    if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
                 } catch (Throwable e) {
-                    reportWtf("making TelephonyRegistry ready", e);
+                    reportWtf("Notifying TelephonyRegistry running", e);
+                }
+
+                try {
+                    if (printManagerF != null) printManagerF.systemRuning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying PrintManagerService running", e);
                 }
             }
         });
@@ -1025,11 +1098,9 @@
     private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;
 
     /**
-     * This method is called from Zygote to initialize the system. This will cause the native
-     * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
-     * up into init2() to start the Android services.
+     * Called to initialize native system services.
      */
-    native public static void init1(String[] args);
+    private static native void nativeInit();
 
     public static void main(String[] args) {
         if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
@@ -1063,13 +1134,15 @@
         Environment.setUserRequired(true);
 
         System.loadLibrary("android_servers");
-        init1(args);
-    }
 
-    public static final void init2() {
         Slog.i(TAG, "Entered the Android system server!");
-        Thread thr = new ServerThread();
-        thr.setName("android.server.ServerThread");
-        thr.start();
+
+        // Initialize native services.
+        nativeInit();
+
+        // This used to be its own separate thread, but now it is
+        // just the loop we run on the main thread.
+        ServerThread thr = new ServerThread();
+        thr.initAndLoop();
     }
 }
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 17260d5..699d79e 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -178,7 +178,7 @@
         mConnectedApns = new ArrayList<String>();
     }
 
-    public void systemReady() {
+    public void systemRunning() {
         // Watch for interesting updates
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 7dd9988..0964767 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -76,7 +76,7 @@
             new HashMap<String, SpellCheckerBindGroup>();
     private final TextServicesSettings mSettings;
 
-    public void systemReady() {
+    public void systemRunning() {
         if (!mSystemReady) {
             mSystemReady = true;
         }
@@ -154,6 +154,8 @@
                         mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
                 // TODO: Update for each locale
                 SpellCheckerInfo sci = getCurrentSpellChecker(null);
+                // If no spell checker is enabled, just return. The user should explicitly
+                // enable the spell checker.
                 if (sci == null) return;
                 final String packageName = sci.getPackageName();
                 final int change = isPackageDisappearing(packageName);
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/TwilightService.java
index 154de1c..0356faa 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/java/com/android/server/TwilightService.java
@@ -520,7 +520,7 @@
             Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
             PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
             mAlarmManager.cancel(pendingIntent);
-            mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
+            mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent);
         }
     };
 
diff --git a/services/java/com/android/server/UiThread.java b/services/java/com/android/server/UiThread.java
new file mode 100644
index 0000000..60d73aa
--- /dev/null
+++ b/services/java/com/android/server/UiThread.java
@@ -0,0 +1,71 @@
+/*
+ * 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.os.Handler;
+import android.os.HandlerThread;
+import android.os.StrictMode;
+import android.util.Slog;
+
+/**
+ * Shared singleton thread for showing UI.  This is a foreground thread, and in
+ * additional should not have operations that can take more than a few ms scheduled
+ * on it to avoid UI jank.
+ */
+public final class UiThread extends HandlerThread {
+    private static UiThread sInstance;
+    private static Handler sHandler;
+
+    private UiThread() {
+        super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new UiThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+            sHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    //Looper.myLooper().setMessageLogging(new LogPrinter(
+                    //        Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
+                    android.os.Process.setCanSelfBackground(false);
+
+                    // For debug builds, log event loop stalls to dropbox for analysis.
+                    if (StrictMode.conditionallyEnableDebugLogging()) {
+                        Slog.i("UiThread", "Enabled StrictMode logging for UI thread");
+                    }
+                }
+            });
+        }
+    }
+
+    public static UiThread get() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index 21d3111..28eb948 100644
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
+import android.os.BatteryStats;
 import android.os.Handler;
 import android.os.IVibratorService;
 import android.os.PowerManager;
@@ -143,7 +144,8 @@
         mWakeLock.setReferenceCounted(true);
 
         mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
-        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
+                BatteryStats.SERVICE_NAME));
 
         mVibrations = new LinkedList<Vibration>();
 
@@ -340,7 +342,8 @@
     // Lock held on mVibrations
     private void startVibrationLocked(final Vibration vib) {
         try {
-            int mode = mAppOpsService.startOperation(AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName);
+            int mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+                    AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
                 if (mode == AppOpsManager.MODE_ERRORED) {
                     Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
@@ -364,7 +367,8 @@
     private void reportFinishVibrationLocked() {
         if (mCurrentVibration != null) {
             try {
-                mAppOpsService.finishOperation(AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
+                mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+                        AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
                         mCurrentVibration.mPackageName);
             } catch (RemoteException e) {
             }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 6823f136..162add4 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -449,7 +449,7 @@
         }
     }
 
-    public void systemReady() {
+    public void systemRunning() {
         if (DEBUG) Slog.v(TAG, "systemReady");
         WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER);
         switchWallpaper(wallpaper, null);
@@ -821,6 +821,11 @@
             int serviceUserId = wallpaper.userId;
             ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
                     PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
+            if (si == null) {
+                // The wallpaper component we're trying to use doesn't exist
+                Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
+                return false;
+            }
             if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
                 String msg = "Selected service does not require "
                         + android.Manifest.permission.BIND_WALLPAPER
@@ -885,7 +890,8 @@
                     Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
                             mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
                     0, null, new UserHandle(serviceUserId)));
-            if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE,
+            if (!mContext.bindServiceAsUser(intent, newConn,
+                    Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI,
                     new UserHandle(serviceUserId))) {
                 String msg = "Unable to bind service: "
                         + componentName;
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 3aec4ea..616090e 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -33,7 +33,6 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.os.Process;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -59,20 +58,7 @@
     // Set this to true to have the watchdog record kernel thread stacks when it fires
     static final boolean RECORD_KERNEL_THREADS = true;
 
-    static final int MONITOR = 2718;
-
-    static final int TIME_TO_RESTART = DB ? 15*1000 : 60*1000;
-    static final int TIME_TO_WAIT = TIME_TO_RESTART / 2;
-
-    static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60;   // 5 minutes
-    static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60;        // 3 minutes
-    static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
-
-    static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0;                 // never force reboot
-    static final int REBOOT_DEFAULT_START_TIME = 3*60*60;                  // 3:00am
-    static final int REBOOT_DEFAULT_WINDOW = 60*60;                        // within 1 hour
-
-    static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
+    static final int TIME_TO_WAIT = DB ? 5*1000 : 30*1000;
 
     static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
         "/system/bin/mediaserver",
@@ -83,100 +69,99 @@
     static Watchdog sWatchdog;
 
     /* This handler will be used to post message back onto the main thread */
-    final Handler mHandler;
-    final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
+    final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>();
+    final HandlerChecker mMonitorChecker;
     ContentResolver mResolver;
     BatteryService mBattery;
     PowerManagerService mPower;
     AlarmManagerService mAlarm;
     ActivityManagerService mActivity;
-    boolean mCompleted;
-    Monitor mCurrentMonitor;
 
     int mPhonePid;
     IActivityController mController;
     boolean mAllowRestart = true;
 
-    final Calendar mCalendar = Calendar.getInstance();
-    int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
-    int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
-    boolean mNeedScheduledCheck;
-    PendingIntent mCheckupIntent;
-    PendingIntent mRebootIntent;
-
-    long mBootTime;
-    int mRebootInterval;
-
-    boolean mReqRebootNoWait;     // should wait for one interval before reboot?
-    int mReqRebootInterval = -1;  // >= 0 if a reboot has been requested
-    int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
-    int mReqRebootWindow = -1;    // >= 0 if a specific window has been requested
-    int mReqMinScreenOff = -1;    // >= 0 if a specific screen off time has been requested
-    int mReqMinNextAlarm = -1;    // >= 0 if specific time to next alarm has been requested
-    int mReqRecheckInterval= -1;  // >= 0 if a specific recheck interval has been requested
-
     /**
-     * Used for scheduling monitor callbacks and checking memory usage.
+     * Used for checking status of handle threads and scheduling monitor callbacks.
      */
-    final class HeartbeatHandler extends Handler {
-        HeartbeatHandler(Looper looper) {
-            super(looper);
+    public final class HandlerChecker implements Runnable {
+        private final Handler mHandler;
+        private final String mName;
+        private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
+        private boolean mCompleted;
+        private Monitor mCurrentMonitor;
+
+        HandlerChecker(Handler handler, String name) {
+            mHandler = handler;
+            mName = name;
         }
 
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MONITOR: {
-                    // See if we should force a reboot.
-                    int rebootInterval = mReqRebootInterval >= 0
-                            ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL;
-                    if (mRebootInterval != rebootInterval) {
-                        mRebootInterval = rebootInterval;
-                        // We have been running long enough that a reboot can
-                        // be considered...
-                        checkReboot(false);
-                    }
+        public void addMonitor(Monitor monitor) {
+            mMonitors.add(monitor);
+        }
 
-                    final int size = mMonitors.size();
-                    for (int i = 0 ; i < size ; i++) {
-                        synchronized (Watchdog.this) {
-                            mCurrentMonitor = mMonitors.get(i);
-                        }
-                        mCurrentMonitor.monitor();
-                    }
+        public void scheduleCheckLocked() {
+            if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) {
+                // If the target looper is or just recently was idling, then
+                // there is no reason to enqueue our checker on it since that
+                // is as good as it not being deadlocked.  This avoid having
+                // to do a context switch to check the thread.  Note that we
+                // only do this if mCheckReboot is false and we have no
+                // monitors, since those would need to be executed at this point.
+                mCompleted = true;
+                return;
+            }
+            mCompleted = false;
+            mCurrentMonitor = null;
+            mHandler.postAtFrontOfQueue(this);
+        }
 
-                    synchronized (Watchdog.this) {
-                        mCompleted = true;
-                        mCurrentMonitor = null;
-                    }
-                } break;
+        public boolean isCompletedLocked() {
+            return mCompleted;
+        }
+
+        public Thread getThread() {
+            return mHandler.getLooper().getThread();
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public String describeBlockedStateLocked() {
+            if (mCurrentMonitor == null) {
+                return "Blocked in handler on " + mName + " (" + getThread().getName() + ")";
+            } else {
+                return "Blocked in monitor " + mCurrentMonitor.getClass().getName()
+                        + " on " + mName + " (" + getThread().getName() + ")";
             }
         }
-    }
 
-    final class RebootReceiver extends BroadcastReceiver {
         @Override
-        public void onReceive(Context c, Intent intent) {
-            if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot.");
-            checkReboot(true);
+        public void run() {
+            final int size = mMonitors.size();
+            for (int i = 0 ; i < size ; i++) {
+                synchronized (Watchdog.this) {
+                    mCurrentMonitor = mMonitors.get(i);
+                }
+                mCurrentMonitor.monitor();
+            }
+
+            synchronized (Watchdog.this) {
+                mCompleted = true;
+                mCurrentMonitor = null;
+            }
         }
     }
 
     final class RebootRequestReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context c, Intent intent) {
-            mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0;
-            mReqRebootInterval = intent.getIntExtra("interval", -1);
-            mReqRebootStartTime = intent.getIntExtra("startTime", -1);
-            mReqRebootWindow = intent.getIntExtra("window", -1);
-            mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
-            mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
-            mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
-            EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT,
-                    mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
-                            mReqRecheckInterval, mReqRebootStartTime,
-                    mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
-            checkReboot(true);
+            if (intent.getIntExtra("nowait", 0) != 0) {
+                rebootSystem("Received ACTION_REBOOT broadcast");
+                return;
+            }
+            Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent);
         }
     }
 
@@ -194,9 +179,23 @@
 
     private Watchdog() {
         super("watchdog");
-        // Explicitly bind the HeartbeatHandler to run on the ServerThread, so
-        // that it can't get accidentally bound to another thread.
-        mHandler = new HeartbeatHandler(Looper.getMainLooper());
+        // Initialize handler checkers for each common thread we want to check.  Note
+        // that we are not currently checking the background thread, since it can
+        // potentially hold longer running operations with no guarantees about the timeliness
+        // of operations there.
+
+        // The shared foreground thread is the main checker.  It is where we
+        // will also dispatch monitor checks and do other work.
+        mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread");
+        mHandlerCheckers.add(mMonitorChecker);
+        // Add checker for main thread.  We only do a quick check since there
+        // can be UI running on the thread.
+        mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
+                "main thread"));
+        // Add checker for shared UI thread.
+        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread"));
+        // And also check IO thread.
+        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread"));
     }
 
     public void init(Context context, BatteryService battery,
@@ -208,16 +207,9 @@
         mAlarm = alarm;
         mActivity = activity;
 
-        context.registerReceiver(new RebootReceiver(),
-                new IntentFilter(REBOOT_ACTION));
-        mRebootIntent = PendingIntent.getBroadcast(context,
-                0, new Intent(REBOOT_ACTION), 0);
-
         context.registerReceiver(new RebootRequestReceiver(),
                 new IntentFilter(Intent.ACTION_REBOOT),
                 android.Manifest.permission.REBOOT, null);
-
-        mBootTime = System.currentTimeMillis();
     }
 
     public void processStarted(String name, int pid) {
@@ -243,87 +235,19 @@
     public void addMonitor(Monitor monitor) {
         synchronized (this) {
             if (isAlive()) {
-                throw new RuntimeException("Monitors can't be added while the Watchdog is running");
+                throw new RuntimeException("Monitors can't be added once the Watchdog is running");
             }
-            mMonitors.add(monitor);
+            mMonitorChecker.addMonitor(monitor);
         }
     }
 
-    void checkReboot(boolean fromAlarm) {
-        int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
-                : REBOOT_DEFAULT_INTERVAL;
-        mRebootInterval = rebootInterval;
-        if (rebootInterval <= 0) {
-            // No reboot interval requested.
-            if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!");
-            mAlarm.remove(mRebootIntent);
-            return;
-        }
-
-        long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
-                : REBOOT_DEFAULT_START_TIME;
-        long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
-                : REBOOT_DEFAULT_WINDOW) * 1000;
-        long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
-                : MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
-
-        retrieveBrutalityAmount();
-
-        long realStartTime;
-        long now;
-
+    public void addThread(Handler thread, String name) {
         synchronized (this) {
-            now = System.currentTimeMillis();
-            realStartTime = computeCalendarTime(mCalendar, now,
-                    rebootStartTime);
-
-            long rebootIntervalMillis = rebootInterval*24*60*60*1000;
-            if (DB || mReqRebootNoWait ||
-                    (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
-                if (fromAlarm && rebootWindowMillis <= 0) {
-                    // No reboot window -- just immediately reboot.
-                    EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
-                            (int)rebootIntervalMillis, (int)rebootStartTime*1000,
-                            (int)rebootWindowMillis, "");
-                    rebootSystem("Checkin scheduled forced");
-                    return;
-                }
-
-                // Are we within the reboot window?
-                if (now < realStartTime) {
-                    // Schedule alarm for next check interval.
-                    realStartTime = computeCalendarTime(mCalendar,
-                            now, rebootStartTime);
-                } else if (now < (realStartTime+rebootWindowMillis)) {
-                    String doit = shouldWeBeBrutalLocked(now);
-                    EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
-                            (int)rebootInterval, (int)rebootStartTime*1000,
-                            (int)rebootWindowMillis, doit != null ? doit : "");
-                    if (doit == null) {
-                        rebootSystem("Checked scheduled range");
-                        return;
-                    }
-
-                    // Schedule next alarm either within the window or in the
-                    // next interval.
-                    if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
-                        realStartTime = computeCalendarTime(mCalendar,
-                                now + rebootIntervalMillis, rebootStartTime);
-                    } else {
-                        realStartTime = now + recheckInterval;
-                    }
-                } else {
-                    // Schedule alarm for next check interval.
-                    realStartTime = computeCalendarTime(mCalendar,
-                            now + rebootIntervalMillis, rebootStartTime);
-                }
+            if (isAlive()) {
+                throw new RuntimeException("Threads can't be added once the Watchdog is running");
             }
+            mHandlerCheckers.add(new HandlerChecker(thread, name));
         }
-
-        if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for "
-                + ((realStartTime-now)/1000/60) + "m from now");
-        mAlarm.remove(mRebootIntent);
-        mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
     }
 
     /**
@@ -335,82 +259,55 @@
         pms.reboot(false, reason, false);
     }
 
-    /**
-     * Load the current Gservices settings for when
-     * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
-     * Must not be called with the lock held.
-     */
-    void retrieveBrutalityAmount() {
-        mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff
-                : MEMCHECK_DEFAULT_MIN_SCREEN_OFF) * 1000;
-        mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm
-                : MEMCHECK_DEFAULT_MIN_ALARM) * 1000;
+    private boolean haveAllCheckersCompletedLocked() {
+        for (int i=0; i<mHandlerCheckers.size(); i++) {
+            HandlerChecker hc = mHandlerCheckers.get(i);
+            if (!hc.isCompletedLocked()) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    /**
-     * Determine whether it is a good time to kill, crash, or otherwise
-     * plunder the current situation for the overall long-term benefit of
-     * the world.
-     *
-     * @param curTime The current system time.
-     * @return Returns null if this is a good time, else a String with the
-     * text of why it is not a good time.
-     */
-    String shouldWeBeBrutalLocked(long curTime) {
-        if (mBattery == null || !mBattery.isPowered(BatteryManager.BATTERY_PLUGGED_ANY)) {
-            return "battery";
+    private ArrayList<HandlerChecker> getBlockedCheckersLocked() {
+        ArrayList<HandlerChecker> checkers = new ArrayList<HandlerChecker>();
+        for (int i=0; i<mHandlerCheckers.size(); i++) {
+            HandlerChecker hc = mHandlerCheckers.get(i);
+            if (!hc.isCompletedLocked()) {
+                checkers.add(hc);
+            }
         }
-
-        if (mMinScreenOff >= 0 && (mPower == null ||
-                mPower.timeSinceScreenWasLastOn() < mMinScreenOff)) {
-            return "screen";
-        }
-
-        if (mMinAlarm >= 0 && (mAlarm == null ||
-                mAlarm.timeToNextAlarm() < mMinAlarm)) {
-            return "alarm";
-        }
-
-        return null;
+        return checkers;
     }
 
-    static long computeCalendarTime(Calendar c, long curTime,
-            long secondsSinceMidnight) {
-
-        // start with now
-        c.setTimeInMillis(curTime);
-
-        int val = (int)secondsSinceMidnight / (60*60);
-        c.set(Calendar.HOUR_OF_DAY, val);
-        secondsSinceMidnight -= val * (60*60);
-        val = (int)secondsSinceMidnight / 60;
-        c.set(Calendar.MINUTE, val);
-        c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
-        c.set(Calendar.MILLISECOND, 0);
-
-        long newTime = c.getTimeInMillis();
-        if (newTime < curTime) {
-            // The given time (in seconds since midnight) has already passed for today, so advance
-            // by one day (due to daylight savings, etc., the delta may differ from 24 hours).
-            c.add(Calendar.DAY_OF_MONTH, 1);
-            newTime = c.getTimeInMillis();
+    private String describeCheckersLocked(ArrayList<HandlerChecker> checkers) {
+        StringBuilder builder = new StringBuilder(128);
+        for (int i=0; i<checkers.size(); i++) {
+            if (builder.length() > 0) {
+                builder.append(", ");
+            }
+            builder.append(checkers.get(i).describeBlockedStateLocked());
         }
-
-        return newTime;
+        return builder.toString();
     }
 
     @Override
     public void run() {
         boolean waitedHalf = false;
         while (true) {
-            mCompleted = false;
-            mHandler.sendEmptyMessage(MONITOR);
-
-
-            final String name;
+            final ArrayList<HandlerChecker> blockedCheckers;
+            final String subject;
             final boolean allowRestart;
             synchronized (this) {
                 long timeout = TIME_TO_WAIT;
+                if (!waitedHalf) {
+                    // If we are not at the half-point of waiting, perform a
+                    // new set of checks.  Otherwise we are still waiting for a previous set.
+                    for (int i=0; i<mHandlerCheckers.size(); i++) {
+                        HandlerChecker hc = mHandlerCheckers.get(i);
+                        hc.scheduleCheckLocked();
+                    }
+                }
 
                 // NOTE: We use uptimeMillis() here because we do not want to increment the time we
                 // wait while asleep. If the device is asleep then the thing that we are waiting
@@ -426,7 +323,7 @@
                     timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
                 }
 
-                if (mCompleted) {
+                if (haveAllCheckersCompletedLocked()) {
                     // The monitors have returned.
                     waitedHalf = false;
                     continue;
@@ -443,15 +340,15 @@
                     continue;
                 }
 
-                name = (mCurrentMonitor != null) ?
-                    mCurrentMonitor.getClass().getName() : "null";
+                blockedCheckers = getBlockedCheckersLocked();
+                subject = describeCheckersLocked(blockedCheckers);
                 allowRestart = mAllowRestart;
             }
 
             // If we got here, that means that the system is most likely hung.
             // First collect stack traces from all threads of the system process.
             // Then kill this process so that the system will restart.
-            EventLog.writeEvent(EventLogTags.WATCHDOG, name);
+            EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
 
             ArrayList<Integer> pids = new ArrayList<Integer>();
             pids.add(Process.myPid());
@@ -487,7 +384,7 @@
                     public void run() {
                         mActivity.addErrorToDropBox(
                                 "watchdog", null, "system_server", null, null,
-                                name, null, stack, null);
+                                subject, null, stack, null);
                     }
                 };
             dropboxThread.start();
@@ -504,7 +401,7 @@
                 try {
                     Binder.setDumpDisabled("Service dumps disabled due to hung system process.");
                     // 1 = keep waiting, -1 = kill system
-                    int res = controller.systemNotResponding(name);
+                    int res = controller.systemNotResponding(subject);
                     if (res >= 0) {
                         Slog.i(TAG, "Activity controller requested to coninue to wait");
                         waitedHalf = false;
@@ -520,7 +417,16 @@
             } else if (!allowRestart) {
                 Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
             } else {
-                Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
+                Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
+                for (int i=0; i<blockedCheckers.size(); i++) {
+                    Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:");
+                    StackTraceElement[] stackTrace
+                            = blockedCheckers.get(i).getThread().getStackTrace();
+                    for (StackTraceElement element: stackTrace) {
+                        Slog.w(TAG, "    at " + element);
+                    }
+                }
+                Slog.w(TAG, "*** GOODBYE!");
                 Process.killProcess(Process.myPid());
                 System.exit(10);
             }
diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/java/com/android/server/WiredAccessoryManager.java
index d5c9c8f..415fcc1 100644
--- a/services/java/com/android/server/WiredAccessoryManager.java
+++ b/services/java/com/android/server/WiredAccessoryManager.java
@@ -44,6 +44,7 @@
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * <p>WiredAccessoryManager monitors for a wired headset on the main board or dock using
@@ -408,11 +409,11 @@
             public String getDevName() { return mDevName; }
 
             public String getDevPath() {
-                return String.format("/devices/virtual/switch/%s", mDevName);
+                return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName);
             }
 
             public String getSwitchStatePath() {
-                return String.format("/sys/class/switch/%s/state", mDevName);
+                return String.format(Locale.US, "/sys/class/switch/%s/state", mDevName);
             }
 
             public boolean checkSwitchExists() {
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index f1e4b0c..83e69d6f 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2694,7 +2694,10 @@
             | AccessibilityNodeInfo.ACTION_COPY
             | AccessibilityNodeInfo.ACTION_PASTE
             | AccessibilityNodeInfo.ACTION_CUT
-            | AccessibilityNodeInfo.ACTION_SET_SELECTION;
+            | AccessibilityNodeInfo.ACTION_SET_SELECTION
+            | AccessibilityNodeInfo.ACTION_EXPAND
+            | AccessibilityNodeInfo.ACTION_COLLAPSE
+            | AccessibilityNodeInfo.ACTION_DISMISS;
 
         private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
             AccessibilityEvent.TYPE_VIEW_CLICKED
@@ -2817,7 +2820,8 @@
 
         public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
             final int callingUid = Binder.getCallingUid();
-            if (callingUid == Process.SYSTEM_UID
+            if (callingUid == 0
+                    || callingUid == Process.SYSTEM_UID
                     || callingUid == Process.SHELL_UID) {
                 return mCurrentUserId;
             }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 18b46fb..1b8876d 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -41,6 +41,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * This class is a strategy for performing touch exploration. It
@@ -52,10 +53,8 @@
  *   <li>2. One finger moving fast around performs gestures.</li>
  *   <li>3. Two close fingers moving in the same direction perform a drag.</li>
  *   <li>4. Multi-finger gestures are delivered to view hierarchy.</li>
- *   <li>5. Pointers that have not moved more than a specified distance after they
- *          went down are considered inactive.</li>
- *   <li>6. Two fingers moving in different directions are considered a multi-finger gesture.</li>
- *   <li>7. Double tapping clicks on the on the last touch explored location of it was in
+ *   <li>5. Two fingers moving in different directions are considered a multi-finger gesture.</li>
+ *   <li>7. Double tapping clicks on the on the last touch explored location if it was in
  *          a window that does not take focus, otherwise the click is within the accessibility
  *          focused rectangle.</li>
  *   <li>7. Tapping and holding for a while performs a long press in a similar fashion
@@ -102,9 +101,6 @@
     // The timeout after which we are no longer trying to detect a gesture.
     private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000;
 
-    // Temporary array for storing pointer IDs.
-    private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
-
     // Timeout before trying to decide what the user is trying to do.
     private final int mDetermineUserIntentTimeout;
 
@@ -129,11 +125,11 @@
     // Handler for performing asynchronous operations.
     private final Handler mHandler;
 
-    // Command for delayed sending of a hover enter event.
-    private final SendHoverDelayed mSendHoverEnterDelayed;
+    // Command for delayed sending of a hover enter and move event.
+    private final SendHoverEnterAndMoveDelayed mSendHoverEnterAndMoveDelayed;
 
     // Command for delayed sending of a hover exit event.
-    private final SendHoverDelayed mSendHoverExitDelayed;
+    private final SendHoverExitDelayed mSendHoverExitDelayed;
 
     // Command for delayed sending of touch exploration end events.
     private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed;
@@ -220,7 +216,7 @@
     public TouchExplorer(Context context, AccessibilityManagerService service) {
         mContext = context;
         mAms = service;
-        mReceivedPointerTracker = new ReceivedPointerTracker(context);
+        mReceivedPointerTracker = new ReceivedPointerTracker();
         mInjectedPointerTracker = new InjectedPointerTracker();
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
@@ -234,8 +230,8 @@
         mGestureLibrary.setOrientationStyle(8);
         mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE);
         mGestureLibrary.load();
-        mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
-        mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
+        mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed();
+        mSendHoverExitDelayed = new SendHoverExitDelayed();
         mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
                 AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END,
                 mDetermineUserIntentTimeout);
@@ -283,12 +279,12 @@
             } break;
         }
         // Remove all pending callbacks.
-        mSendHoverEnterDelayed.remove();
-        mSendHoverExitDelayed.remove();
-        mPerformLongPressDelayed.remove();
-        mExitGestureDetectionModeDelayed.remove();
-        mSendTouchExplorationEndDelayed.remove();
-        mSendTouchInteractionEndDelayed.remove();
+        mSendHoverEnterAndMoveDelayed.cancel();
+        mSendHoverExitDelayed.cancel();
+        mPerformLongPressDelayed.cancel();
+        mExitGestureDetectionModeDelayed.cancel();
+        mSendTouchExplorationEndDelayed.cancel();
+        mSendTouchInteractionEndDelayed.cancel();
         // Reset the pointer trackers.
         mReceivedPointerTracker.clear();
         mInjectedPointerTracker.clear();
@@ -347,7 +343,7 @@
         // last hover exit event.
         if (mSendTouchExplorationEndDelayed.isPending()
                 && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
-                    mSendTouchExplorationEndDelayed.remove();
+                    mSendTouchExplorationEndDelayed.cancel();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
         }
 
@@ -355,7 +351,7 @@
         // last hover exit and the touch exploration gesture end events.
         if (mSendTouchInteractionEndDelayed.isPending()
                 && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
-            mSendTouchInteractionEndDelayed.remove();
+            mSendTouchInteractionEndDelayed.cancel();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
         }
 
@@ -390,95 +386,82 @@
     private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent rawEvent,
             int policyFlags) {
         ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-        final int activePointerCount = receivedTracker.getActivePointerCount();
 
         mVelocityTracker.addMovement(rawEvent);
 
         mDoubleTapDetector.onMotionEvent(event, policyFlags);
 
         switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_DOWN: {
                 mAms.onTouchInteractionStart();
+
                 // Pre-feed the motion events to the gesture detector since we
                 // have a distance slop before getting into gesture detection
                 // mode and not using the points within this slop significantly
                 // decreases the quality of gesture recognition.
                 handleMotionEventGestureDetecting(rawEvent, policyFlags);
-                //$FALL-THROUGH$
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                switch (activePointerCount) {
-                    case 0: {
-                        throw new IllegalStateException("The must always be one active pointer in"
-                                + "touch exploring state!");
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
+
+                // If we still have not notified the user for the last
+                // touch, we figure out what to do. If were waiting
+                // we resent the delayed callback and wait again.
+                mSendHoverEnterAndMoveDelayed.cancel();
+                mSendHoverExitDelayed.cancel();
+                mPerformLongPressDelayed.cancel();
+
+                if (mSendTouchExplorationEndDelayed.isPending()) {
+                    mSendTouchExplorationEndDelayed.forceSendAndRemove();
+                }
+
+                if (mSendTouchInteractionEndDelayed.isPending()) {
+                    mSendTouchInteractionEndDelayed.forceSendAndRemove();
+                }
+
+                // If we have the first tap, schedule a long press and break
+                // since we do not want to schedule hover enter because
+                // the delayed callback will kick in before the long click.
+                // This would lead to a state transition resulting in long
+                // pressing the item below the double taped area which is
+                // not necessary where accessibility focus is.
+                if (mDoubleTapDetector.firstTapDetected()) {
+                    // We got a tap now post a long press action.
+                    mPerformLongPressDelayed.post(event, policyFlags);
+                    break;
+                }
+                if (!mTouchExplorationInProgress) {
+                    if (!mSendHoverEnterAndMoveDelayed.isPending()) {
+                        // Deliver hover enter with a delay to have a chance
+                        // to detect what the user is trying to do.
+                        final int pointerId = receivedTracker.getPrimaryPointerId();
+                        final int pointerIdBits = (1 << pointerId);
+                        mSendHoverEnterAndMoveDelayed.post(event, true, pointerIdBits,
+                                policyFlags);
                     }
-                    case 1: {
-                        // If we still have not notified the user for the last
-                        // touch, we figure out what to do. If were waiting
-                        // we resent the delayed callback and wait again.
-                        if (mSendHoverEnterDelayed.isPending()) {
-                            mSendHoverEnterDelayed.remove();
-                            mSendHoverExitDelayed.remove();
-                        }
-
-                        if (mSendTouchExplorationEndDelayed.isPending()) {
-                            mSendTouchExplorationEndDelayed.forceSendAndRemove();
-                        }
-
-                        if (mSendTouchInteractionEndDelayed.isPending()) {
-                            mSendTouchInteractionEndDelayed.forceSendAndRemove();
-                        }
-
-                        // Every pointer that goes down is active until it moves or
-                        // another one goes down. Hence, having more than one pointer
-                        // down we have already send the interaction start event.
-                        if (event.getPointerCount() == 1) {
-                            sendAccessibilityEvent(
-                                    AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
-                        }
-
-                        mPerformLongPressDelayed.remove();
-
-                        // If we have the first tap schedule a long press and break
-                        // since we do not want to schedule hover enter because
-                        // the delayed callback will kick in before the long click.
-                        // This would lead to a state transition resulting in long
-                        // pressing the item below the double taped area which is
-                        // not necessary where accessibility focus is.
-                        if (mDoubleTapDetector.firstTapDetected()) {
-                            // We got a tap now post a long press action.
-                            mPerformLongPressDelayed.post(event, policyFlags);
-                            break;
-                        }
-                        if (!mTouchExplorationInProgress) {
-                            // Deliver hover enter with a delay to have a chance
-                            // to detect what the user is trying to do.
-                            final int pointerId = receivedTracker.getPrimaryActivePointerId();
-                            final int pointerIdBits = (1 << pointerId);
-                            mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
-                        }
-                    } break;
-                    default: {
-                        /* do nothing - let the code for ACTION_MOVE decide what to do */
-                    } break;
+                    // Cache the event until we discern exploration from gesturing.
+                    mSendHoverEnterAndMoveDelayed.addEvent(event);
                 }
             } break;
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                /* do nothing - let the code for ACTION_MOVE decide what to do */
+            } break;
             case MotionEvent.ACTION_MOVE: {
-                final int pointerId = receivedTracker.getPrimaryActivePointerId();
+                final int pointerId = receivedTracker.getPrimaryPointerId();
                 final int pointerIndex = event.findPointerIndex(pointerId);
                 final int pointerIdBits = (1 << pointerId);
-                switch (activePointerCount) {
-                    case 0: {
-                        /* do nothing - no active pointers so we swallow the event */
-                    } break;
+                switch (event.getPointerCount()) {
                     case 1: {
                         // We have not started sending events since we try to
                         // figure out what the user is doing.
-                        if (mSendHoverEnterDelayed.isPending()) {
+                        if (mSendHoverEnterAndMoveDelayed.isPending()) {
                             // Pre-feed the motion events to the gesture detector since we
                             // have a distance slop before getting into gesture detection
                             // mode and not using the points within this slop significantly
                             // decreases the quality of gesture recognition.
                             handleMotionEventGestureDetecting(rawEvent, policyFlags);
+
+                            // Cache the event until we discern exploration from gesturing.
+                            mSendHoverEnterAndMoveDelayed.addEvent(event);
+
                             // It is *important* to use the distance traveled by the pointers
                             // on the screen which may or may not be magnified.
                             final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
@@ -500,9 +483,9 @@
                                     // clear the current state and try to detect.
                                     mCurrentState = STATE_GESTURE_DETECTING;
                                     mVelocityTracker.clear();
-                                    mSendHoverEnterDelayed.remove();
-                                    mSendHoverExitDelayed.remove();
-                                    mPerformLongPressDelayed.remove();
+                                    mSendHoverEnterAndMoveDelayed.cancel();
+                                    mSendHoverExitDelayed.cancel();
+                                    mPerformLongPressDelayed.cancel();
                                     mExitGestureDetectionModeDelayed.post();
                                     // Send accessibility event to announce the start
                                     // of gesture recognition.
@@ -511,9 +494,9 @@
                                 } else {
                                     // We have just decided that the user is touch,
                                     // exploring so start sending events.
-                                    mSendHoverEnterDelayed.forceSendAndRemove();
-                                    mSendHoverExitDelayed.remove();
-                                    mPerformLongPressDelayed.remove();
+                                    mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
+                                    mSendHoverExitDelayed.cancel();
+                                    mPerformLongPressDelayed.cancel();
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
                                             pointerIdBits, policyFlags);
                                 }
@@ -532,11 +515,11 @@
                                 final double moveDelta = Math.hypot(deltaX, deltaY);
                                 // The user has moved enough for us to decide.
                                 if (moveDelta > mTouchSlop) {
-                                    mPerformLongPressDelayed.remove();
+                                    mPerformLongPressDelayed.cancel();
                                 }
                             }
-                            // The user is wither double tapping or performing long
-                            // press so do not send move events yet.
+                            // The user is either double tapping or performing a long
+                            // press, so do not send move events yet.
                             if (mDoubleTapDetector.firstTapDetected()) {
                                 break;
                             }
@@ -548,14 +531,14 @@
                     case 2: {
                         // More than one pointer so the user is not touch exploring
                         // and now we have to decide whether to delegate or drag.
-                        if (mSendHoverEnterDelayed.isPending()) {
+                        if (mSendHoverEnterAndMoveDelayed.isPending()) {
                             // We have not started sending events so cancel
                             // scheduled sending events.
-                            mSendHoverEnterDelayed.remove();
-                            mSendHoverExitDelayed.remove();
-                            mPerformLongPressDelayed.remove();
+                            mSendHoverEnterAndMoveDelayed.cancel();
+                            mSendHoverExitDelayed.cancel();
+                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.remove();
+                            mPerformLongPressDelayed.cancel();
                             // If the user is touch exploring the second pointer may be
                             // performing a double tap to activate an item without need
                             // for the user to lift his exploring finger.
@@ -590,21 +573,21 @@
                         } else {
                             // Two pointers moving arbitrary are delegated to the view hierarchy.
                             mCurrentState = STATE_DELEGATING;
-                            sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                            sendDownForAllNotInjectedPointers(event, policyFlags);
                         }
                         mVelocityTracker.clear();
                     } break;
                     default: {
                         // More than one pointer so the user is not touch exploring
                         // and now we have to decide whether to delegate or drag.
-                        if (mSendHoverEnterDelayed.isPending()) {
+                        if (mSendHoverEnterAndMoveDelayed.isPending()) {
                             // We have not started sending events so cancel
                             // scheduled sending events.
-                            mSendHoverEnterDelayed.remove();
-                            mSendHoverExitDelayed.remove();
-                            mPerformLongPressDelayed.remove();
+                            mSendHoverEnterAndMoveDelayed.cancel();
+                            mSendHoverExitDelayed.cancel();
+                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.remove();
+                            mPerformLongPressDelayed.cancel();
                             // We are sending events so send exit and gesture
                             // end since we transition to another state.
                             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -612,43 +595,34 @@
 
                         // More than two pointers are delegated to the view hierarchy.
                         mCurrentState = STATE_DELEGATING;
-                        sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                        sendDownForAllNotInjectedPointers(event, policyFlags);
                         mVelocityTracker.clear();
                     }
                 }
             } break;
-            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_UP: {
                 mAms.onTouchInteractionEnd();
                 // We know that we do not need the pre-fed gesture points are not
                 // needed anymore since the last pointer just went up.
                 mStrokeBuffer.clear();
-                //$FALL-THROUGH$
-            case MotionEvent.ACTION_POINTER_UP: {
-                final int pointerId = receivedTracker.getLastReceivedUpPointerId();
+                final int pointerId = event.getPointerId(event.getActionIndex());
                 final int pointerIdBits = (1 << pointerId);
-                switch (activePointerCount) {
-                    case 0: {
-                        // If the pointer that went up was not active we have nothing to do.
-                        if (!receivedTracker.wasLastReceivedUpPointerActive()) {
-                            break;
-                        }
 
-                        mPerformLongPressDelayed.remove();
-
-                        // If we have not delivered the enter schedule exit.
-                        if (mSendHoverEnterDelayed.isPending()) {
-                            mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags);
-                        } else {
-                            // The user is touch exploring so we send events for end.
-                            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-                        }
-
-                        if (!mSendTouchInteractionEndDelayed.isPending()) {
-                            mSendTouchInteractionEndDelayed.post();
-                        }
-                    } break;
-                }
+                mPerformLongPressDelayed.cancel();
                 mVelocityTracker.clear();
+
+                if (mSendHoverEnterAndMoveDelayed.isPending()) {
+                    // If we have not delivered the enter schedule an exit.
+                    mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
+                } else {
+                    // The user is touch exploring so we send events for end.
+                    sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+                }
+
+                if (!mSendTouchInteractionEndDelayed.isPending()) {
+                    mSendTouchInteractionEndDelayed.post();
+                }
+
             } break;
             case MotionEvent.ACTION_CANCEL: {
                 clear(event, policyFlags);
@@ -676,29 +650,19 @@
                 if (mDraggingPointerId != INVALID_POINTER_ID) {
                     sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
                 }
-                sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                sendDownForAllNotInjectedPointers(event, policyFlags);
             } break;
             case MotionEvent.ACTION_MOVE: {
-                final int activePointerCount = mReceivedPointerTracker.getActivePointerCount();
-                switch (activePointerCount) {
+                switch (event.getPointerCount()) {
                     case 1: {
                         // do nothing
                     } break;
                     case 2: {
                         if (isDraggingGesture(event)) {
-                            // If the dragging pointer are closer that a given distance we
-                            // use the location of the primary one. Otherwise, we take the
-                            // middle between the pointers.
-                            int[] pointerIds = mTempPointerIds;
-                            mReceivedPointerTracker.populateActivePointerIds(pointerIds);
-
-                            final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
-                            final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
-
-                            final float firstPtrX = event.getX(firstPtrIndex);
-                            final float firstPtrY = event.getY(firstPtrIndex);
-                            final float secondPtrX = event.getX(secondPtrIndex);
-                            final float secondPtrY = event.getY(secondPtrIndex);
+                            final float firstPtrX = event.getX(0);
+                            final float firstPtrY = event.getY(0);
+                            final float secondPtrX = event.getX(1);
+                            final float secondPtrY = event.getY(1);
 
                             final float deltaX = firstPtrX - secondPtrX;
                             final float deltaY = firstPtrY - secondPtrY;
@@ -718,8 +682,8 @@
                             // Send an event to the end of the drag gesture.
                             sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
                                     policyFlags);
-                            // Deliver all active pointers to the view hierarchy.
-                            sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                            // Deliver all pointers to the view hierarchy.
+                            sendDownForAllNotInjectedPointers(event, policyFlags);
                         }
                     } break;
                     default: {
@@ -727,8 +691,8 @@
                         // Send an event to the end of the drag gesture.
                         sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
                                 policyFlags);
-                        // Deliver all active pointers to the view hierarchy.
-                        sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                        // Deliver all pointers to the view hierarchy.
+                        sendDownForAllNotInjectedPointers(event, policyFlags);
                     }
                 }
             } break;
@@ -771,37 +735,21 @@
                 throw new IllegalStateException("Delegating state can only be reached if "
                         + "there is at least one pointer down!");
             }
-            case MotionEvent.ACTION_MOVE: {
-                // Check  whether some other pointer became active because they have moved
-                // a given distance and if such exist send them to the view hierarchy
-                final int notInjectedCount = getNotInjectedActivePointerCount(
-                        mReceivedPointerTracker, mInjectedPointerTracker);
-                if (notInjectedCount > 0) {
-                    MotionEvent prototype = MotionEvent.obtain(event);
-                    sendDownForAllActiveNotInjectedPointers(prototype, policyFlags);
-                }
-            } break;
-            case MotionEvent.ACTION_UP:
-                // Announce the end of a new touch interaction.
-                sendAccessibilityEvent(
-                        AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
-                //$FALL-THROUGH$
-            case MotionEvent.ACTION_POINTER_UP: {
+            case MotionEvent.ACTION_UP: {
+                // Announce the end of a the touch interaction.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
                 mAms.onTouchInteractionEnd();
                 mLongPressingPointerId = -1;
                 mLongPressingPointerDeltaX = 0;
                 mLongPressingPointerDeltaY = 0;
-                // No active pointers => go to initial state.
-                if (mReceivedPointerTracker.getActivePointerCount() == 0) {
-                    mCurrentState = STATE_TOUCH_EXPLORING;
-                }
+                mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
                 clear(event, policyFlags);
             } break;
         }
-        // Deliver the event striping out inactive pointers.
-        sendMotionEventStripInactivePointers(event, policyFlags);
+        // Deliver the event.
+        sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags);
     }
 
     private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) {
@@ -826,12 +774,10 @@
             } break;
             case MotionEvent.ACTION_UP: {
                 mAms.onTouchInteractionEnd();
-                // Announce the end of gesture recognition.
-                sendAccessibilityEvent(
-                        AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-                // Announce the end of a new touch interaction.
-                sendAccessibilityEvent(
-                        AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+                // Announce the end of the gesture recognition.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+                // Announce the end of a the touch interaction.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
 
                 float x = event.getX();
                 float y = event.getY();
@@ -858,7 +804,7 @@
                 }
 
                 mStrokeBuffer.clear();
-                mExitGestureDetectionModeDelayed.remove();
+                mExitGestureDetectionModeDelayed.cancel();
                 mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
@@ -889,40 +835,26 @@
     }
 
     /**
-     * Sends down events to the view hierarchy for all active pointers which are
+     * Sends down events to the view hierarchy for all pointers which are
      * not already being delivered i.e. pointers that are not yet injected.
      *
      * @param prototype The prototype from which to create the injected events.
      * @param policyFlags The policy flags associated with the event.
      */
-    private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) {
-        ReceivedPointerTracker receivedPointers = mReceivedPointerTracker;
+    private void sendDownForAllNotInjectedPointers(MotionEvent prototype, int policyFlags) {
         InjectedPointerTracker injectedPointers = mInjectedPointerTracker;
+
+        // Inject the injected pointers.
         int pointerIdBits = 0;
         final int pointerCount = prototype.getPointerCount();
-
-        // Find which pointers are already injected.
         for (int i = 0; i < pointerCount; i++) {
             final int pointerId = prototype.getPointerId(i);
-            if (injectedPointers.isInjectedPointerDown(pointerId)) {
-                pointerIdBits |= (1 << pointerId);
-            }
-        }
-
-        // Inject the active and not injected pointers.
-        for (int i = 0; i < pointerCount; i++) {
-            final int pointerId = prototype.getPointerId(i);
-            // Skip inactive pointers.
-            if (!receivedPointers.isActivePointer(pointerId)) {
-                continue;
-            }
             // Do not send event for already delivered pointers.
-            if (injectedPointers.isInjectedPointerDown(pointerId)) {
-                continue;
+            if (!injectedPointers.isInjectedPointerDown(pointerId)) {
+                pointerIdBits |= (1 << pointerId);
+                final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
+                sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
             }
-            pointerIdBits |= (1 << pointerId);
-            final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
-            sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
         }
     }
 
@@ -959,7 +891,7 @@
     }
 
     /**
-     * Sends up events to the view hierarchy for all active pointers which are
+     * Sends up events to the view hierarchy for all pointers which are
      * already being delivered i.e. pointers that are injected.
      *
      * @param prototype The prototype from which to create the injected events.
@@ -982,58 +914,13 @@
     }
 
     /**
-     * Sends a motion event by first stripping the inactive pointers.
-     *
-     * @param prototype The prototype from which to create the injected event.
-     * @param policyFlags The policy flags associated with the event.
-     */
-    private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) {
-        ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-
-        // All pointers active therefore we just inject the event as is.
-        if (prototype.getPointerCount() == receivedTracker.getActivePointerCount()) {
-            sendMotionEvent(prototype, prototype.getAction(), ALL_POINTER_ID_BITS, policyFlags);
-            return;
-        }
-
-        // No active pointers and the one that just went up was not
-        // active, therefore we have nothing to do.
-        if (receivedTracker.getActivePointerCount() == 0
-                && !receivedTracker.wasLastReceivedUpPointerActive()) {
-            return;
-        }
-
-        // If the action pointer going up/down is not active we have nothing to do.
-        // However, for moves we keep going to report moves of active pointers.
-        final int actionMasked = prototype.getActionMasked();
-        final int actionPointerId = prototype.getPointerId(prototype.getActionIndex());
-        if (actionMasked != MotionEvent.ACTION_MOVE) {
-            if (!receivedTracker.isActiveOrWasLastActiveUpPointer(actionPointerId)) {
-                return;
-            }
-        }
-
-        // If the pointer is active or the pointer that just went up
-        // was active we keep the pointer data in the event.
-        int pointerIdBits = 0;
-        final int pointerCount = prototype.getPointerCount();
-        for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
-            final int pointerId = prototype.getPointerId(pointerIndex);
-            if (receivedTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
-                pointerIdBits |= (1 << pointerId);
-            }
-        }
-        sendMotionEvent(prototype, prototype.getAction(), pointerIdBits, policyFlags);
-    }
-
-    /**
      * Sends an up and down events.
      *
      * @param prototype The prototype from which to create the injected events.
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) {
-        // Tap with the pointer that last explored - we may have inactive pointers.
+        // Tap with the pointer that last explored.
         final int pointerId = prototype.getPointerId(prototype.getActionIndex());
         final int pointerIdBits = (1 << pointerId);
         sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags);
@@ -1215,9 +1102,9 @@
             }
 
             // Remove pending event deliveries.
-            mSendHoverEnterDelayed.remove();
-            mSendHoverExitDelayed.remove();
-            mPerformLongPressDelayed.remove();
+            mSendHoverEnterAndMoveDelayed.cancel();
+            mSendHoverExitDelayed.cancel();
+            mPerformLongPressDelayed.cancel();
 
             if (mSendTouchExplorationEndDelayed.isPending()) {
                 mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -1307,21 +1194,16 @@
      */
     private boolean isDraggingGesture(MotionEvent event) {
         ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-        int[] pointerIds = mTempPointerIds;
-        receivedTracker.populateActivePointerIds(pointerIds);
 
-        final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
-        final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
+        final float firstPtrX = event.getX(0);
+        final float firstPtrY = event.getY(0);
+        final float secondPtrX = event.getX(1);
+        final float secondPtrY = event.getY(1);
 
-        final float firstPtrX = event.getX(firstPtrIndex);
-        final float firstPtrY = event.getY(firstPtrIndex);
-        final float secondPtrX = event.getX(secondPtrIndex);
-        final float secondPtrY = event.getY(secondPtrIndex);
-
-        final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(firstPtrIndex);
-        final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(firstPtrIndex);
-        final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(secondPtrIndex);
-        final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(secondPtrIndex);
+        final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(0);
+        final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(0);
+        final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(1);
+        final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(1);
 
         return GestureUtils.isDraggingGesture(firstPtrDownX, firstPtrDownY, secondPtrDownX,
                 secondPtrDownY, firstPtrX, firstPtrY, secondPtrX, secondPtrY,
@@ -1350,16 +1232,6 @@
     }
 
     /**
-     * @return The number of non injected active pointers.
-     */
-    private int getNotInjectedActivePointerCount(ReceivedPointerTracker receivedTracker,
-            InjectedPointerTracker injectedTracker) {
-        final int pointerState = receivedTracker.getActivePointers()
-                & ~injectedTracker.getInjectedPointersDown();
-        return Integer.bitCount(pointerState);
-    }
-
-    /**
      * Class for delayed exiting from gesture detecting mode.
      */
     private final class ExitGestureDetectionModeDelayed implements Runnable {
@@ -1368,7 +1240,7 @@
             mHandler.postDelayed(this, EXIT_GESTURE_DETECTION_TIMEOUT);
         }
 
-        public void remove() {
+        public void cancel() {
             mHandler.removeCallbacks(this);
         }
 
@@ -1396,21 +1268,21 @@
             mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout());
         }
 
-        public void remove() {
-            if (isPending()) {
+        public void cancel() {
+            if (mEvent != null) {
                 mHandler.removeCallbacks(this);
                 clear();
             }
         }
 
-        public boolean isPending() {
-            return (mEvent != null);
+        private boolean isPending() {
+            return mHandler.hasCallbacks(this);
         }
 
         @Override
         public void run() {
-            // Active pointers should not be zero when running this command.
-            if (mReceivedPointerTracker.getActivePointerCount() == 0) {
+            // Pointers should not be zero when running this command.
+            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
                 return;
             }
 
@@ -1461,14 +1333,11 @@
             sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
 
             mCurrentState = STATE_DELEGATING;
-            sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
+            sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags);
             clear();
         }
 
         private void clear() {
-            if (!isPending()) {
-                return;
-            }
             mEvent.recycle();
             mEvent = null;
             mPolicyFlags = 0;
@@ -1476,59 +1345,114 @@
     }
 
     /**
-     * Class for delayed sending of hover events.
+     * Class for delayed sending of hover enter and move events.
      */
-    class SendHoverDelayed implements Runnable {
-        private final String LOG_TAG_SEND_HOVER_DELAYED = SendHoverDelayed.class.getName();
+    class SendHoverEnterAndMoveDelayed implements Runnable {
+        private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed";
 
-        private final int mHoverAction;
-        private final boolean mGestureStarted;
+        private final List<MotionEvent> mEvents = new ArrayList<MotionEvent>();
+
+        private int mPointerIdBits;
+        private int mPolicyFlags;
+
+        public void post(MotionEvent event, boolean touchExplorationInProgress,
+                int pointerIdBits, int policyFlags) {
+            cancel();
+            addEvent(event);
+            mPointerIdBits = pointerIdBits;
+            mPolicyFlags = policyFlags;
+            mHandler.postDelayed(this, mDetermineUserIntentTimeout);
+        }
+
+        public void addEvent(MotionEvent event) {
+            mEvents.add(MotionEvent.obtain(event));
+        }
+
+        public void cancel() {
+            if (isPending()) {
+                mHandler.removeCallbacks(this);
+                clear();
+            }
+        }
+
+        private boolean isPending() {
+            return mHandler.hasCallbacks(this);
+        }
+
+        private void clear() {
+            mPointerIdBits = -1;
+            mPolicyFlags = 0;
+            final int eventCount = mEvents.size();
+            for (int i = eventCount - 1; i >= 0; i--) {
+                mEvents.remove(i).recycle();
+            }
+        }
+
+        public void forceSendAndRemove() {
+            if (isPending()) {
+                run();
+                cancel();
+            }
+        }
+
+        public void run() {
+            // Send an accessibility event to announce the touch exploration start.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+
+            if (!mEvents.isEmpty()) {
+                // Deliver a down event.
+                sendMotionEvent(mEvents.get(0), MotionEvent.ACTION_HOVER_ENTER,
+                        mPointerIdBits, mPolicyFlags);
+                if (DEBUG) {
+                    Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
+                            "Injecting motion event: ACTION_HOVER_ENTER");
+                }
+
+                // Deliver move events.
+                final int eventCount = mEvents.size();
+                for (int i = 1; i < eventCount; i++) {
+                    sendMotionEvent(mEvents.get(i), MotionEvent.ACTION_HOVER_MOVE,
+                            mPointerIdBits, mPolicyFlags);
+                    if (DEBUG) {
+                        Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
+                                "Injecting motion event: ACTION_HOVER_MOVE");
+                    }
+                }
+            }
+            clear();
+        }
+    }
+
+    /**
+     * Class for delayed sending of hover exit events.
+     */
+    class SendHoverExitDelayed implements Runnable {
+        private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed";
 
         private MotionEvent mPrototype;
         private int mPointerIdBits;
         private int mPolicyFlags;
 
-        public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
-            mHoverAction = hoverAction;
-            mGestureStarted = gestureStarted;
-        }
-
-        public void post(MotionEvent prototype, boolean touchExplorationInProgress,
-                int pointerIdBits, int policyFlags) {
-            remove();
+        public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) {
+            cancel();
             mPrototype = MotionEvent.obtain(prototype);
             mPointerIdBits = pointerIdBits;
             mPolicyFlags = policyFlags;
             mHandler.postDelayed(this, mDetermineUserIntentTimeout);
         }
 
-        public float getX() {
+        public void cancel() {
             if (isPending()) {
-                return mPrototype.getX();
+                mHandler.removeCallbacks(this);
+                clear();
             }
-            return 0;
-        }
-
-        public float getY() {
-            if (isPending()) {
-                return mPrototype.getY();
-            }
-            return 0;
-        }
-
-        public void remove() {
-            mHandler.removeCallbacks(this);
-            clear();
         }
 
         private boolean isPending() {
-            return (mPrototype != null);
+            return mHandler.hasCallbacks(this);
         }
 
         private void clear() {
-            if (!isPending()) {
-                return;
-            }
             mPrototype.recycle();
             mPrototype = null;
             mPointerIdBits = -1;
@@ -1538,29 +1462,25 @@
         public void forceSendAndRemove() {
             if (isPending()) {
                 run();
-                remove();
+                cancel();
             }
         }
 
         public void run() {
             if (DEBUG) {
-                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event: "
-                        + MotionEvent.actionToString(mHoverAction));
-                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
-                        "touchExplorationGestureStarted" : "touchExplorationGestureEnded");
+                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:"
+                        + " ACTION_HOVER_EXIT");
             }
-            if (mGestureStarted) {
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
-            } else {
-                if (!mSendTouchExplorationEndDelayed.isPending()) {
-                    mSendTouchExplorationEndDelayed.post();
-                }
-                if (mSendTouchInteractionEndDelayed.isPending()) {
-                    mSendTouchInteractionEndDelayed.remove();
-                    mSendTouchInteractionEndDelayed.post();
-                }
+            sendMotionEvent(mPrototype, MotionEvent.ACTION_HOVER_EXIT,
+                    mPointerIdBits, mPolicyFlags);
+            if (!mSendTouchExplorationEndDelayed.isPending()) {
+                mSendTouchExplorationEndDelayed.cancel();
+                mSendTouchExplorationEndDelayed.post();
             }
-            sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
+            if (mSendTouchInteractionEndDelayed.isPending()) {
+                  mSendTouchInteractionEndDelayed.cancel();
+                mSendTouchInteractionEndDelayed.post();
+            }
             clear();
         }
     }
@@ -1574,7 +1494,7 @@
             mDelay = delay;
         }
 
-        public void remove() {
+        public void cancel() {
             mHandler.removeCallbacks(this);
         }
 
@@ -1589,7 +1509,7 @@
         public void forceSendAndRemove() {
             if (isPending()) {
                 run();
-                remove();
+                cancel();
             }
         }
 
@@ -1736,15 +1656,6 @@
     class ReceivedPointerTracker {
         private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
 
-        // The coefficient by which to multiply
-        // ViewConfiguration.#getScaledTouchSlop()
-        // to compute #mThresholdActivePointer.
-        private static final int COEFFICIENT_ACTIVE_POINTER = 2;
-
-        // Pointers that moved less than mThresholdActivePointer
-        // are considered active i.e. are ignored.
-        private final double mThresholdActivePointer;
-
         // Keep track of where and when a pointer went down.
         private final float[] mReceivedPointerDownX = new float[MAX_POINTER_COUNT];
         private final float[] mReceivedPointerDownY = new float[MAX_POINTER_COUNT];
@@ -1756,36 +1667,19 @@
         // The edge flags of the last received down event.
         private int mLastReceivedDownEdgeFlags;
 
-        // Which down pointers are active.
-        private int mActivePointers;
-
-        // Primary active pointer which is either the first that went down
-        // or if it goes up the next active that most recently went down.
-        private int mPrimaryActivePointerId;
-
-        // Flag indicating that there is at least one active pointer moving.
-        private boolean mHasMovingActivePointer;
+        // Primary pointer which is either the first that went down
+        // or if it goes up the next one that most recently went down.
+        private int mPrimaryPointerId;
 
         // Keep track of the last up pointer data.
         private long mLastReceivedUpPointerDownTime;
         private int mLastReceivedUpPointerId;
-        private boolean mLastReceivedUpPointerActive;
         private float mLastReceivedUpPointerDownX;
         private float mLastReceivedUpPointerDownY;
 
         private MotionEvent mLastReceivedEvent;
 
         /**
-         * Creates a new instance.
-         *
-         * @param context Context for looking up resources.
-         */
-        public ReceivedPointerTracker(Context context) {
-            mThresholdActivePointer =
-                ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER;
-        }
-
-        /**
          * Clears the internals state.
          */
         public void clear() {
@@ -1793,12 +1687,9 @@
             Arrays.fill(mReceivedPointerDownY, 0);
             Arrays.fill(mReceivedPointerDownTime, 0);
             mReceivedPointersDown = 0;
-            mActivePointers = 0;
-            mPrimaryActivePointerId = 0;
-            mHasMovingActivePointer = false;
+            mPrimaryPointerId = 0;
             mLastReceivedUpPointerDownTime = 0;
             mLastReceivedUpPointerId = 0;
-            mLastReceivedUpPointerActive = false;
             mLastReceivedUpPointerDownX = 0;
             mLastReceivedUpPointerDownY = 0;
         }
@@ -1822,9 +1713,6 @@
                 case MotionEvent.ACTION_POINTER_DOWN: {
                     handleReceivedPointerDown(event.getActionIndex(), event);
                 } break;
-                case MotionEvent.ACTION_MOVE: {
-                    handleReceivedPointerMove(event);
-                } break;
                 case MotionEvent.ACTION_UP: {
                     handleReceivedPointerUp(event.getActionIndex(), event);
                 } break;
@@ -1833,7 +1721,7 @@
                 } break;
             }
             if (DEBUG) {
-                Slog.i(LOG_TAG_RECEIVED_POINTER_TRACKER, "Received pointer: " + toString());
+                Slog.i(LOG_TAG_RECEIVED_POINTER_TRACKER, "Received pointer:\n" + toString());
             }
         }
 
@@ -1852,20 +1740,6 @@
         }
 
         /**
-         * @return The bits of the pointers that are active.
-         */
-        public int getActivePointers() {
-            return mActivePointers;
-        }
-
-        /**
-         * @return The number of down input  pointers that are active.
-         */
-        public int getActivePointerCount() {
-            return Integer.bitCount(mActivePointers);
-        }
-
-        /**
          * Whether an received pointer is down.
          *
          * @param pointerId The unique pointer id.
@@ -1877,17 +1751,6 @@
         }
 
         /**
-         * Whether an input pointer is active.
-         *
-         * @param pointerId The unique pointer id.
-         * @return True if the pointer is active.
-         */
-        public boolean isActivePointer(int pointerId) {
-            final int pointerFlag = (1 << pointerId);
-            return (mActivePointers & pointerFlag) != 0;
-        }
-
-        /**
          * @param pointerId The unique pointer id.
          * @return The X coordinate where the pointer went down.
          */
@@ -1914,11 +1777,11 @@
         /**
          * @return The id of the primary pointer.
          */
-        public int getPrimaryActivePointerId() {
-            if (mPrimaryActivePointerId == INVALID_POINTER_ID) {
-                mPrimaryActivePointerId = findPrimaryActivePointer();
+        public int getPrimaryPointerId() {
+            if (mPrimaryPointerId == INVALID_POINTER_ID) {
+                mPrimaryPointerId = findPrimaryPointerId();
             }
-            return mPrimaryActivePointerId;
+            return mPrimaryPointerId;
         }
 
         /**
@@ -1929,14 +1792,6 @@
         }
 
         /**
-         * @return The id of the last received pointer that went up.
-         */
-        public int getLastReceivedUpPointerId() {
-            return mLastReceivedUpPointerId;
-        }
-
-
-        /**
          * @return The down X of the last received pointer that went up.
          */
         public float getLastReceivedUpPointerDownX() {
@@ -1958,39 +1813,6 @@
         }
 
         /**
-         * @return Whether the last received pointer that went up was active.
-         */
-        public boolean wasLastReceivedUpPointerActive() {
-            return mLastReceivedUpPointerActive;
-        }
-        /**
-         * Populates the active pointer IDs to the given array.
-         * <p>
-         * Note: The client is responsible for providing large enough array.
-         *
-         * @param outPointerIds The array to which to write the active pointers.
-         */
-        public void populateActivePointerIds(int[] outPointerIds) {
-            int index = 0;
-            for (int idBits = mActivePointers; idBits != 0; ) {
-                final int id = Integer.numberOfTrailingZeros(idBits);
-                idBits &= ~(1 << id);
-                outPointerIds[index] = id;
-                index++;
-            }
-        }
-
-        /**
-         * @param pointerId The unique pointer id.
-         * @return Whether the pointer is active or was the last active than went up.
-         */
-        public boolean isActiveOrWasLastActiveUpPointer(int pointerId) {
-            return (isActivePointer(pointerId)
-                    || (mLastReceivedUpPointerId == pointerId
-                            && mLastReceivedUpPointerActive));
-        }
-
-        /**
          * Handles a received pointer down event.
          *
          * @param pointerIndex The index of the pointer that has changed.
@@ -2002,7 +1824,6 @@
 
             mLastReceivedUpPointerId = 0;
             mLastReceivedUpPointerDownTime = 0;
-            mLastReceivedUpPointerActive = false;
             mLastReceivedUpPointerDownX = 0;
             mLastReceivedUpPointerDownX = 0;
 
@@ -2013,25 +1834,7 @@
             mReceivedPointerDownY[pointerId] = event.getY(pointerIndex);
             mReceivedPointerDownTime[pointerId] = event.getEventTime();
 
-            if (!mHasMovingActivePointer) {
-                // If still no moving active pointers every
-                // down pointer is the only active one.
-                mActivePointers = pointerFlag;
-                mPrimaryActivePointerId = pointerId;
-            } else {
-                // If at least one moving active pointer every
-                // subsequent down pointer is active.
-                mActivePointers |= pointerFlag;
-            }
-        }
-
-        /**
-         * Handles a received pointer move event.
-         *
-         * @param event The event to be handled.
-         */
-        private void handleReceivedPointerMove(MotionEvent event) {
-            detectActivePointers(event);
+            mPrimaryPointerId = pointerId;
         }
 
         /**
@@ -2046,80 +1849,38 @@
 
             mLastReceivedUpPointerId = pointerId;
             mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId);
-            mLastReceivedUpPointerActive = isActivePointer(pointerId);
             mLastReceivedUpPointerDownX = mReceivedPointerDownX[pointerId];
             mLastReceivedUpPointerDownY = mReceivedPointerDownY[pointerId];
 
             mReceivedPointersDown &= ~pointerFlag;
-            mActivePointers &= ~pointerFlag;
             mReceivedPointerDownX[pointerId] = 0;
             mReceivedPointerDownY[pointerId] = 0;
             mReceivedPointerDownTime[pointerId] = 0;
 
-            if (mActivePointers == 0) {
-                mHasMovingActivePointer = false;
-            }
-            if (mPrimaryActivePointerId == pointerId) {
-                mPrimaryActivePointerId = INVALID_POINTER_ID;
+            if (mPrimaryPointerId == pointerId) {
+                mPrimaryPointerId = INVALID_POINTER_ID;
             }
         }
 
         /**
-         * Detects the active pointers in an event.
-         *
-         * @param event The event to examine.
+         * @return The primary pointer id.
          */
-        private void detectActivePointers(MotionEvent event) {
-            for (int i = 0, count = event.getPointerCount(); i < count; i++) {
-                final int pointerId = event.getPointerId(i);
-                if (mHasMovingActivePointer) {
-                    // If already active => nothing to do.
-                    if (isActivePointer(pointerId)) {
-                        continue;
-                    }
-                }
-                // Active pointers are ones that moved more than a given threshold.
-                final float pointerDeltaMove = computePointerDeltaMove(i, event);
-                if (pointerDeltaMove > mThresholdActivePointer) {
-                    final int pointerFlag = (1 << pointerId);
-                    mActivePointers |= pointerFlag;
-                    mHasMovingActivePointer = true;
-                }
-            }
-        }
-
-        /**
-         * @return The primary active pointer.
-         */
-        private int findPrimaryActivePointer() {
-            int primaryActivePointerId = INVALID_POINTER_ID;
+        private int findPrimaryPointerId() {
+            int primaryPointerId = INVALID_POINTER_ID;
             long minDownTime = Long.MAX_VALUE;
-            // Find the active pointer that went down first.
-            for (int i = 0, count = mReceivedPointerDownTime.length; i < count; i++) {
-                if (isActivePointer(i)) {
-                    final long downPointerTime = mReceivedPointerDownTime[i];
-                    if (downPointerTime < minDownTime) {
-                        minDownTime = downPointerTime;
-                        primaryActivePointerId = i;
-                    }
+
+            // Find the pointer that went down first.
+            int pointerIdBits = mReceivedPointersDown;
+            while (pointerIdBits > 0) {
+                final int pointerId = Integer.numberOfTrailingZeros(pointerIdBits);
+                pointerIdBits &= ~(1 << pointerId);
+                final long downPointerTime = mReceivedPointerDownTime[pointerId];
+                if (downPointerTime < minDownTime) {
+                    minDownTime = downPointerTime;
+                    primaryPointerId = pointerId;
                 }
             }
-            return primaryActivePointerId;
-        }
-
-        /**
-         * Computes the move for a given action pointer index since the
-         * corresponding pointer went down.
-         *
-         * @param pointerIndex The action pointer index.
-         * @param event The event to examine.
-         * @return The distance the pointer has moved.
-         */
-        private float computePointerDeltaMove(int pointerIndex, MotionEvent event) {
-            final int pointerId = event.getPointerId(pointerIndex);
-            final float deltaX = event.getX(pointerIndex) - mReceivedPointerDownX[pointerId];
-            final float deltaY = event.getY(pointerIndex) - mReceivedPointerDownY[pointerId];
-            return (float) Math.hypot(deltaX, deltaY);
+            return primaryPointerId;
         }
 
         @Override
@@ -2136,18 +1897,8 @@
                 }
             }
             builder.append("]");
-            builder.append("\nActive pointers #");
-            builder.append(getActivePointerCount());
-            builder.append(" [ ");
-            for (int i = 0; i < MAX_POINTER_COUNT; i++) {
-                if (isActivePointer(i)) {
-                    builder.append(i);
-                    builder.append(" ");
-                }
-            }
-            builder.append("]");
-            builder.append("\nPrimary active pointer id [ ");
-            builder.append(getPrimaryActivePointerId());
+            builder.append("\nPrimary pointer id [ ");
+            builder.append(getPrimaryPointerId());
             builder.append(" ]");
             builder.append("\n=========================");
             return builder.toString();
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 0fbde37..dd9ae4c 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -47,6 +47,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCacheListener;
+import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
@@ -56,10 +57,10 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -74,6 +75,7 @@
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.FgThread;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
 
@@ -113,7 +115,6 @@
     private final PackageManager mPackageManager;
     private UserManager mUserManager;
 
-    private HandlerThread mMessageThread;
     private final MessageHandler mMessageHandler;
 
     // Messages that can be sent on mHandler
@@ -234,9 +235,7 @@
         mContext = context;
         mPackageManager = packageManager;
 
-        mMessageThread = new HandlerThread("AccountManagerService");
-        mMessageThread.start();
-        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
+        mMessageHandler = new MessageHandler(FgThread.get().getLooper());
 
         mAuthenticatorCache = authenticatorCache;
         mAuthenticatorCache.setListener(this, null /* Handler */);
@@ -269,6 +268,21 @@
         }, UserHandle.ALL, userFilter, null, null);
     }
 
+    @Override
+    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+            throws RemoteException {
+        try {
+            return super.onTransact(code, data, reply, flags);
+        } catch (RuntimeException e) {
+            // The account manager only throws security exceptions, so let's
+            // log all others.
+            if (!(e instanceof SecurityException)) {
+                Slog.wtf(TAG, "Account Manager Crash", e);
+            }
+            throw e;
+        }
+    }
+
     public void systemReady() {
     }
 
@@ -583,15 +597,18 @@
         try {
             new Session(fromAccounts, null, account.type, false,
                     false /* stripAuthTokenFromResult */) {
+                @Override
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", getAccountCredentialsForClone"
                             + ", " + account.type;
                 }
 
+                @Override
                 public void run() throws RemoteException {
                     mAuthenticator.getAccountCredentialsForCloning(this, account);
                 }
 
+                @Override
                 public void onResult(Bundle result) {
                     if (result != null) {
                         if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
@@ -616,11 +633,13 @@
         try {
             new Session(targetUser, null, account.type, false,
                     false /* stripAuthTokenFromResult */) {
+                @Override
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", getAccountCredentialsForClone"
                             + ", " + account.type;
                 }
 
+                @Override
                 public void run() throws RemoteException {
                     // Confirm that the owner's account still exists before this step.
                     UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
@@ -635,6 +654,7 @@
                     }
                 }
 
+                @Override
                 public void onResult(Bundle result) {
                     if (result != null) {
                         if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
@@ -649,6 +669,7 @@
                     }
                 }
 
+                @Override
                 public void onError(int errorCode, String errorMessage) {
                     super.onError(errorCode,  errorMessage);
                     // TODO: Show error notification to user
@@ -777,6 +798,7 @@
             mAccount = account;
         }
 
+        @Override
         public void run() throws RemoteException {
             try {
                 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
@@ -785,6 +807,7 @@
             }
         }
 
+        @Override
         public void onResult(Bundle result) {
             IAccountManagerResponse response = getResponseAndClose();
             if (response != null) {
@@ -810,6 +833,7 @@
             }
         }
 
+        @Override
         protected String toDebugString(long now) {
             return super.toDebugString(now) + ", hasFeatures"
                     + ", " + mAccount
@@ -866,15 +890,18 @@
             mAccount = account;
         }
 
+        @Override
         protected String toDebugString(long now) {
             return super.toDebugString(now) + ", removeAccount"
                     + ", account " + mAccount;
         }
 
+        @Override
         public void run() throws RemoteException {
             mAuthenticator.getAccountRemovalAllowed(this, mAccount);
         }
 
+        @Override
         public void onResult(Bundle result) {
             if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
                     && !result.containsKey(AccountManager.KEY_INTENT)) {
@@ -1215,16 +1242,19 @@
         try {
             new Session(accounts, response, accountType, false,
                     false /* stripAuthTokenFromResult */) {
+                @Override
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", getAuthTokenLabel"
                             + ", " + accountType
                             + ", authTokenType " + authTokenType;
                 }
 
+                @Override
                 public void run() throws RemoteException {
                     mAuthenticator.getAuthTokenLabel(this, authTokenType);
                 }
 
+                @Override
                 public void onResult(Bundle result) {
                     if (result != null) {
                         String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
@@ -1302,6 +1332,7 @@
 
             new Session(accounts, response, account.type, expectActivityLaunch,
                     false /* stripAuthTokenFromResult */) {
+                @Override
                 protected String toDebugString(long now) {
                     if (loginOptions != null) loginOptions.keySet();
                     return super.toDebugString(now) + ", getAuthToken"
@@ -1311,6 +1342,7 @@
                             + ", notifyOnAuthFailure " + notifyOnAuthFailure;
                 }
 
+                @Override
                 public void run() throws RemoteException {
                     // If the caller doesn't have permission then create and return the
                     // "grant permission" intent instead of the "getAuthToken" intent.
@@ -1321,6 +1353,7 @@
                     }
                 }
 
+                @Override
                 public void onResult(Bundle result) {
                     if (result != null) {
                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
@@ -1485,11 +1518,13 @@
         try {
             new Session(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */) {
+                @Override
                 public void run() throws RemoteException {
                     mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
                             options);
                 }
 
+                @Override
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", addAccount"
                             + ", accountType " + accountType
@@ -1510,7 +1545,10 @@
             int userId) {
         // Only allow the system process to read accounts of other users
         if (userId != UserHandle.getCallingUserId()
-                && Binder.getCallingUid() != Process.myUid()) {
+                && Binder.getCallingUid() != Process.myUid()
+                && mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("User " + UserHandle.getCallingUserId()
                     + " trying to confirm account credentials for " + userId);
         }
@@ -1530,9 +1568,11 @@
         try {
             new Session(accounts, response, account.type, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */) {
+                @Override
                 public void run() throws RemoteException {
                     mAuthenticator.confirmCredentials(this, account, options);
                 }
+                @Override
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", confirmCredentials"
                             + ", " + account;
@@ -1563,9 +1603,11 @@
         try {
             new Session(accounts, response, account.type, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */) {
+                @Override
                 public void run() throws RemoteException {
                     mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
                 }
+                @Override
                 protected String toDebugString(long now) {
                     if (loginOptions != null) loginOptions.keySet();
                     return super.toDebugString(now) + ", updateCredentials"
@@ -1596,9 +1638,11 @@
         try {
             new Session(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */) {
+                @Override
                 public void run() throws RemoteException {
                     mAuthenticator.editProperties(this, mAccountType);
                 }
+                @Override
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", editProperties"
                             + ", accountType " + accountType;
@@ -1624,6 +1668,7 @@
             mFeatures = features;
         }
 
+        @Override
         public void run() throws RemoteException {
             synchronized (mAccounts.cacheLock) {
                 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
@@ -1661,6 +1706,7 @@
             }
         }
 
+        @Override
         public void onResult(Bundle result) {
             mNumResults++;
             if (result == null) {
@@ -1699,6 +1745,7 @@
         }
 
 
+        @Override
         protected String toDebugString(long now) {
             return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
                     + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
@@ -1779,7 +1826,10 @@
         int callingUid = Binder.getCallingUid();
         // Only allow the system process to read accounts of other users
         if (userId != UserHandle.getCallingUserId()
-                && callingUid != Process.myUid()) {
+                && callingUid != Process.myUid()
+                && mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("User " + UserHandle.getCallingUserId()
                     + " trying to get account for " + userId);
         }
@@ -2108,9 +2158,31 @@
             }
         }
 
+        @Override
         public void onResult(Bundle result) {
             mNumResults++;
-            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
+            Intent intent = null;
+            if (result != null
+                    && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+                /*
+                 * The Authenticator API allows third party authenticators to
+                 * supply arbitrary intents to other apps that they can run,
+                 * this can be very bad when those apps are in the system like
+                 * the System Settings.
+                 */
+                PackageManager pm = mContext.getPackageManager();
+                ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+                int targetUid = resolveInfo.activityInfo.applicationInfo.uid;
+                int authenticatorUid = Binder.getCallingUid();
+                if (PackageManager.SIGNATURE_MATCH !=
+                        pm.checkSignatures(authenticatorUid, targetUid)) {
+                    throw new SecurityException(
+                            "Activity to be started with KEY_INTENT must " +
+                            "share Authenticator's signatures");
+                }
+            }
+            if (result != null
+                    && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
                 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
                 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
                 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
@@ -2220,6 +2292,7 @@
             super(looper);
         }
 
+        @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MESSAGE_TIMED_OUT:
@@ -2537,7 +2610,7 @@
         return userId;
     }
 
-    private boolean inSystemImage(int callingUid) {
+    private boolean isPrivileged(int callingUid) {
         final int callingUserId = UserHandle.getUserId(callingUid);
 
         final PackageManager userPackageManager;
@@ -2553,7 +2626,7 @@
             try {
                 PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
                 if (packageInfo != null
-                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
                     return true;
                 }
             } catch (PackageManager.NameNotFoundException e) {
@@ -2564,7 +2637,7 @@
     }
 
     private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
-        final boolean inSystemImage = inSystemImage(callerUid);
+        final boolean isPrivileged = isPrivileged(callerUid);
         final boolean fromAuthenticator = account != null
                 && hasAuthenticatorUid(account.type, callerUid);
         final boolean hasExplicitGrants = account != null
@@ -2575,7 +2648,7 @@
                     + ": is authenticator? " + fromAuthenticator
                     + ", has explicit permission? " + hasExplicitGrants);
         }
-        return fromAuthenticator || hasExplicitGrants || inSystemImage;
+        return fromAuthenticator || hasExplicitGrants || isPrivileged;
     }
 
     private boolean hasAuthenticatorUid(String accountType, int callingUid) {
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 5c24e67..27ca7a0 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -20,13 +20,15 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
+import android.os.Handler;
+import android.util.ArrayMap;
+import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.TransferPipe;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityManagerService.NeededUriGrants;
 
@@ -52,14 +54,15 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
 
-public class ActiveServices {
+public final class ActiveServices {
     static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
     static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
+    static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
+    static final boolean DEBUG_DELAYED_STATS = DEBUG_DELAYED_SERVICE;
     static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
     static final String TAG = ActivityManagerService.TAG;
     static final String TAG_MU = ActivityManagerService.TAG_MU;
@@ -67,6 +70,9 @@
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
 
+    // How long we wait for a service to finish executing.
+    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
+
     // How long a service needs to be running until restarting its process
     // is no longer considered to be a relaunch of the service.
     static final int SERVICE_RESTART_DURATION = 5*1000;
@@ -89,16 +95,24 @@
     // LRU background list.
     static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
 
+    // How long we wait for a background started service to stop itself before
+    // allowing the next pending start to run.
+    static final int BG_START_TIMEOUT = 15*1000;
+
     final ActivityManagerService mAm;
 
-    final ServiceMap mServiceMap = new ServiceMap();
+    // Maximum number of services that we allow to start in the background
+    // at the same time.
+    final int mMaxStartingBackground;
+
+    final SparseArray<ServiceMap> mServiceMap = new SparseArray<ServiceMap>();
 
     /**
      * All currently bound service connections.  Keys are the IBinder of
      * the client's IServiceConnection.
      */
-    final HashMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
-            = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
+    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
+            = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
 
     /**
      * List of services that we have been asked to start,
@@ -116,104 +130,148 @@
             = new ArrayList<ServiceRecord>();
 
     /**
-     * List of services that are in the process of being stopped.
+     * List of services that are in the process of being destroyed.
      */
-    final ArrayList<ServiceRecord> mStoppingServices
+    final ArrayList<ServiceRecord> mDestroyingServices
             = new ArrayList<ServiceRecord>();
 
-    static class ServiceMap {
+    static final class DelayingProcess extends ArrayList<ServiceRecord> {
+        long timeoout;
+    }
 
-        private final SparseArray<HashMap<ComponentName, ServiceRecord>> mServicesByNamePerUser
-                = new SparseArray<HashMap<ComponentName, ServiceRecord>>();
-        private final SparseArray<HashMap<Intent.FilterComparison, ServiceRecord>>
-                mServicesByIntentPerUser = new SparseArray<
-                    HashMap<Intent.FilterComparison, ServiceRecord>>();
+    /**
+     * Information about services for a single user.
+     */
+    class ServiceMap extends Handler {
+        final int mUserId;
+        final ArrayMap<ComponentName, ServiceRecord> mServicesByName
+                = new ArrayMap<ComponentName, ServiceRecord>();
+        final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
+                = new ArrayMap<Intent.FilterComparison, ServiceRecord>();
 
-        ServiceRecord getServiceByName(ComponentName name, int callingUser) {
-            // TODO: Deal with global services
-            if (DEBUG_MU)
-                Slog.v(TAG_MU, "getServiceByName(" + name + "), callingUser = " + callingUser);
-            return getServices(callingUser).get(name);
+        final ArrayList<ServiceRecord> mDelayedStartList
+                = new ArrayList<ServiceRecord>();
+        /* XXX eventually I'd like to have this based on processes instead of services.
+         * That is, if we try to start two services in a row both running in the same
+         * process, this should be one entry in mStartingBackground for that one process
+         * that remains until all services in it are done.
+        final ArrayMap<ProcessRecord, DelayingProcess> mStartingBackgroundMap
+                = new ArrayMap<ProcessRecord, DelayingProcess>();
+        final ArrayList<DelayingProcess> mStartingProcessList
+                = new ArrayList<DelayingProcess>();
+        */
+
+        final ArrayList<ServiceRecord> mStartingBackground
+                = new ArrayList<ServiceRecord>();
+
+        static final int MSG_BG_START_TIMEOUT = 1;
+
+        ServiceMap(int userId) {
+            mUserId = userId;
         }
 
-        ServiceRecord getServiceByName(ComponentName name) {
-            return getServiceByName(name, -1);
-        }
-
-        ServiceRecord getServiceByIntent(Intent.FilterComparison filter, int callingUser) {
-            // TODO: Deal with global services
-            if (DEBUG_MU)
-                Slog.v(TAG_MU, "getServiceByIntent(" + filter + "), callingUser = " + callingUser);
-            return getServicesByIntent(callingUser).get(filter);
-        }
-
-        ServiceRecord getServiceByIntent(Intent.FilterComparison filter) {
-            return getServiceByIntent(filter, -1);
-        }
-
-        void putServiceByName(ComponentName name, int callingUser, ServiceRecord value) {
-            // TODO: Deal with global services
-            getServices(callingUser).put(name, value);
-        }
-
-        void putServiceByIntent(Intent.FilterComparison filter, int callingUser,
-                ServiceRecord value) {
-            // TODO: Deal with global services
-            getServicesByIntent(callingUser).put(filter, value);
-        }
-
-        void removeServiceByName(ComponentName name, int callingUser) {
-            // TODO: Deal with global services
-            ServiceRecord removed = getServices(callingUser).remove(name);
-            if (DEBUG_MU)
-                Slog.v(TAG, "removeServiceByName user=" + callingUser + " name=" + name
-                        + " removed=" + removed);
-        }
-
-        void removeServiceByIntent(Intent.FilterComparison filter, int callingUser) {
-            // TODO: Deal with global services
-            ServiceRecord removed = getServicesByIntent(callingUser).remove(filter);
-            if (DEBUG_MU)
-                Slog.v(TAG_MU, "removeServiceByIntent user=" + callingUser + " intent=" + filter
-                        + " removed=" + removed);
-        }
-
-        Collection<ServiceRecord> getAllServices(int callingUser) {
-            // TODO: Deal with global services
-            return getServices(callingUser).values();
-        }
-
-        private HashMap<ComponentName, ServiceRecord> getServices(int callingUser) {
-            HashMap<ComponentName, ServiceRecord> map = mServicesByNamePerUser.get(callingUser);
-            if (map == null) {
-                map = new HashMap<ComponentName, ServiceRecord>();
-                mServicesByNamePerUser.put(callingUser, map);
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_BG_START_TIMEOUT: {
+                    synchronized (mAm) {
+                        rescheduleDelayedStarts();
+                    }
+                } break;
             }
-            return map;
         }
 
-        private HashMap<Intent.FilterComparison, ServiceRecord> getServicesByIntent(
-                int callingUser) {
-            HashMap<Intent.FilterComparison, ServiceRecord> map
-                    = mServicesByIntentPerUser.get(callingUser);
-            if (map == null) {
-                map = new HashMap<Intent.FilterComparison, ServiceRecord>();
-                mServicesByIntentPerUser.put(callingUser, map);
+        void ensureNotStartingBackground(ServiceRecord r) {
+            if (mStartingBackground.remove(r)) {
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer background starting: " + r);
+                rescheduleDelayedStarts();
             }
-            return map;
+            if (mDelayedStartList.remove(r)) {
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer delaying start: " + r);
+            }
+        }
+
+        void rescheduleDelayedStarts() {
+            removeMessages(MSG_BG_START_TIMEOUT);
+            final long now = SystemClock.uptimeMillis();
+            for (int i=0, N=mStartingBackground.size(); i<N; i++) {
+                ServiceRecord r = mStartingBackground.get(i);
+                if (r.startingBgTimeout <= now) {
+                    Slog.i(TAG, "Waited long enough for: " + r);
+                    mStartingBackground.remove(i);
+                    N--;
+                }
+            }
+            while (mDelayedStartList.size() > 0
+                    && mStartingBackground.size() < mMaxStartingBackground) {
+                ServiceRecord r = mDelayedStartList.remove(0);
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+                if (r.pendingStarts.size() <= 0) {
+                    Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+                            + " delayedStop=" + r.delayedStop);
+                }
+                if (DEBUG_DELAYED_SERVICE) {
+                    if (mDelayedStartList.size() > 0) {
+                        Slog.v(TAG, "Remaining delayed list:");
+                        for (int i=0; i<mDelayedStartList.size(); i++) {
+                            Slog.v(TAG, "  #" + i + ": " + mDelayedStartList.get(i));
+                        }
+                    }
+                }
+                r.delayed = false;
+                startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true);
+            }
+            if (mStartingBackground.size() > 0) {
+                ServiceRecord next = mStartingBackground.get(0);
+                long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
+                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next
+                        + ", can delay others up to " + when);
+                Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
+                sendMessageAtTime(msg, when);
+            }
+            if (mStartingBackground.size() < mMaxStartingBackground) {
+                mAm.backgroundServicesFinishedLocked(mUserId);
+            }
         }
     }
 
     public ActiveServices(ActivityManagerService service) {
         mAm = service;
+        mMaxStartingBackground = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
+    }
+
+    ServiceRecord getServiceByName(ComponentName name, int callingUser) {
+        // TODO: Deal with global services
+        if (DEBUG_MU)
+            Slog.v(TAG_MU, "getServiceByName(" + name + "), callingUser = " + callingUser);
+        return getServiceMap(callingUser).mServicesByName.get(name);
+    }
+
+    boolean hasBackgroundServices(int callingUser) {
+        ServiceMap smap = mServiceMap.get(callingUser);
+        return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
+    }
+
+    private ServiceMap getServiceMap(int callingUser) {
+        ServiceMap smap = mServiceMap.get(callingUser);
+        if (smap == null) {
+            smap = new ServiceMap(callingUser);
+            mServiceMap.put(callingUser, smap);
+        }
+        return smap;
+    }
+
+    ArrayMap<ComponentName, ServiceRecord> getServices(int callingUser) {
+        return getServiceMap(callingUser).mServicesByName;
     }
 
     ComponentName startServiceLocked(IApplicationThread caller,
             Intent service, String resolvedType,
             int callingPid, int callingUid, int userId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
+        if (DEBUG_DELAYED_STATS) Slog.v(TAG, "startService: " + service
                 + " type=" + resolvedType + " args=" + service.getExtras());
 
+        final boolean callerFg;
         if (caller != null) {
             final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
             if (callerApp == null) {
@@ -222,11 +280,15 @@
                         + " (pid=" + Binder.getCallingPid()
                         + ") when starting service " + service);
             }
+            callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+        } else {
+            callerFg = true;
         }
 
+
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType,
-                    callingPid, callingUid, userId, true);
+                    callingPid, callingUid, userId, true, callerFg);
         if (res == null) {
             return null;
         }
@@ -240,28 +302,132 @@
         if (unscheduleServiceRestartLocked(r)) {
             if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
         }
+        r.lastActivity = SystemClock.uptimeMillis();
         r.startRequested = true;
-        r.callStart = false;
+        r.delayedStop = false;
         r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                 service, neededGrants));
-        r.lastActivity = SystemClock.uptimeMillis();
+
+        final ServiceMap smap = getServiceMap(r.userId);
+        boolean addToStarting = false;
+        if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
+            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
+            if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
+                // If this is not coming from a foreground caller, then we may want
+                // to delay the start if there are already other background services
+                // that are starting.  This is to avoid process start spam when lots
+                // of applications are all handling things like connectivity broadcasts.
+                // We only do this for cached processes, because otherwise an application
+                // can have assumptions about calling startService() for a service to run
+                // in its own process, and for that process to not be killed before the
+                // service is started.  This is especially the case for receivers, which
+                // may start a service in onReceive() to do some additional work and have
+                // initialized some global state as part of that.
+                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
+                        + proc);
+                if (r.delayed) {
+                    // This service is already scheduled for a delayed start; just leave
+                    // it still waiting.
+                    if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Continuing to delay: " + r);
+                    return r.name;
+                }
+                if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
+                    // Something else is starting, delay!
+                    Slog.i(TAG, "Delaying start of: " + r);
+                    smap.mDelayedStartList.add(r);
+                    r.delayed = true;
+                    return r.name;
+                }
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying: " + r);
+                addToStarting = true;
+            } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+                // We slightly loosen when we will enqueue this new service as a background
+                // starting service we are waiting for, to also include processes that are
+                // currently running other services or receivers.
+                addToStarting = true;
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+            } else if (DEBUG_DELAYED_STATS) {
+                StringBuilder sb = new StringBuilder(128);
+                sb.append("Not potential delay (state=").append(proc.curProcState)
+                        .append(' ').append(proc.adjType);
+                String reason = proc.makeAdjReason();
+                if (reason != null) {
+                    sb.append(' ');
+                    sb.append(reason);
+                }
+                sb.append("): ");
+                sb.append(r.toString());
+                Slog.v(TAG, sb.toString());
+            }
+        } else if (DEBUG_DELAYED_STATS) {
+            if (callerFg) {
+                Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+                        + callingUid + " pid=" + callingPid + "): " + r);
+            } else if (r.app != null) {
+                Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r);
+            } else {
+                Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r);
+            }
+        }
+
+        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
+    }
+
+    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
+            ServiceRecord r, boolean callerFg, boolean addToStarting) {
+        ProcessStats.ServiceState stracker = r.getTracker();
+        if (stracker != null) {
+            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+        }
+        r.callStart = false;
         synchronized (r.stats.getBatteryStats()) {
             r.stats.startRunningLocked();
         }
-        String error = bringUpServiceLocked(r, service.getFlags(), false);
+        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
         if (error != null) {
             return new ComponentName("!!", error);
         }
+
+        if (r.startRequested && addToStarting) {
+            boolean first = smap.mStartingBackground.size() == 0;
+            smap.mStartingBackground.add(r);
+            r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
+            if (DEBUG_DELAYED_SERVICE) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
+            } else if (DEBUG_DELAYED_STATS) {
+                Slog.v(TAG, "Starting background (first=" + first + "): " + r);
+            }
+            if (first) {
+                smap.rescheduleDelayedStarts();
+            }
+        } else if (callerFg) {
+            smap.ensureNotStartingBackground(r);
+        }
+
         return r.name;
     }
 
     private void stopServiceLocked(ServiceRecord service) {
+        if (service.delayed) {
+            // If service isn't actually running, but is is being held in the
+            // delayed list, then we need to keep it started but note that it
+            // should be stopped once no longer delayed.
+            if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Delaying stop of pending: " + service);
+            service.delayedStop = true;
+            return;
+        }
         synchronized (service.stats.getBatteryStats()) {
             service.stats.stopRunningLocked();
         }
         service.startRequested = false;
+        if (service.tracker != null) {
+            service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                    SystemClock.uptimeMillis());
+        }
         service.callStart = false;
-        bringDownServiceLocked(service, false);
+        bringDownServiceIfNeededLocked(service, false, false);
     }
 
     int stopServiceLocked(IApplicationThread caller, Intent service,
@@ -279,7 +445,7 @@
 
         // If this service is active, make sure it is stopped.
         ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
-                Binder.getCallingPid(), Binder.getCallingUid(), userId, false);
+                Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);
         if (r != null) {
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
@@ -299,7 +465,7 @@
     IBinder peekServiceLocked(Intent service, String resolvedType) {
         ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
                 Binder.getCallingPid(), Binder.getCallingUid(),
-                UserHandle.getCallingUserId(), false);
+                UserHandle.getCallingUserId(), false, false);
 
         IBinder ret = null;
         if (r != null) {
@@ -354,11 +520,15 @@
 
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.stopRunningLocked();
-                r.startRequested = false;
-                r.callStart = false;
             }
+            r.startRequested = false;
+            if (r.tracker != null) {
+                r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                        SystemClock.uptimeMillis());
+            }
+            r.callStart = false;
             final long origId = Binder.clearCallingIdentity();
-            bringDownServiceLocked(r, false);
+            bringDownServiceIfNeededLocked(r, false, false);
             Binder.restoreCallingIdentity(origId);
             return true;
         }
@@ -387,11 +557,12 @@
                     if (r.app != null) {
                         updateServiceForegroundLocked(r.app, true);
                     }
+                    getServiceMap(r.userId).ensureNotStartingBackground(r);
                 } else {
                     if (r.isForeground) {
                         r.isForeground = false;
                         if (r.app != null) {
-                            mAm.updateLruProcessLocked(r.app, false);
+                            mAm.updateLruProcessLocked(r.app, false, false);
                             updateServiceForegroundLocked(r.app, true);
                         }
                     }
@@ -409,7 +580,8 @@
 
     private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
         boolean anyForeground = false;
-        for (ServiceRecord sr : proc.services) {
+        for (int i=proc.services.size()-1; i>=0; i--) {
+            ServiceRecord sr = proc.services.valueAt(i);
             if (sr.isForeground) {
                 anyForeground = true;
                 break;
@@ -439,7 +611,7 @@
 
         ActivityRecord activity = null;
         if (token != null) {
-            activity = mAm.mMainStack.isInStackLocked(token);
+            activity = ActivityRecord.isInStackLocked(token);
             if (activity == null) {
                 Slog.w(TAG, "Binding with unknown activity: " + token);
                 return 0;
@@ -469,9 +641,11 @@
             }
         }
 
+        final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType,
-                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true);
+                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
         if (res == null) {
             return 0;
         }
@@ -488,6 +662,18 @@
                         + s);
             }
 
+            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
+                s.lastActivity = SystemClock.uptimeMillis();
+                if (!s.hasAutoCreateConnections()) {
+                    // This is the first binding, let the tracker know.
+                    ProcessStats.ServiceState stracker = s.getTracker();
+                    if (stracker != null) {
+                        stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
+                                s.lastActivity);
+                    }
+                }
+            }
+
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
             ConnectionRecord c = new ConnectionRecord(b, activity,
                     connection, flags, clientLabel, clientIntent);
@@ -519,7 +705,7 @@
 
             if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                 s.lastActivity = SystemClock.uptimeMillis();
-                if (bringUpServiceLocked(s, service.getFlags(), false) != null) {
+                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                     return 0;
                 }
             }
@@ -549,11 +735,14 @@
                 // and the service had previously asked to be told when
                 // rebound, then do so.
                 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
-                    requestServiceBindingLocked(s, b.intent, true);
+                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                 }
             } else if (!b.intent.requested) {
-                requestServiceBindingLocked(s, b.intent, false);
+                requestServiceBindingLocked(s, b.intent, callerFg, false);
             }
+
+            getServiceMap(s.userId).ensureNotStartingBackground(s);
+
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -574,36 +763,32 @@
                     b.binder = service;
                     b.requested = true;
                     b.received = true;
-                    if (r.connections.size() > 0) {
-                        Iterator<ArrayList<ConnectionRecord>> it
-                                = r.connections.values().iterator();
-                        while (it.hasNext()) {
-                            ArrayList<ConnectionRecord> clist = it.next();
-                            for (int i=0; i<clist.size(); i++) {
-                                ConnectionRecord c = clist.get(i);
-                                if (!filter.equals(c.binding.intent.intent)) {
-                                    if (DEBUG_SERVICE) Slog.v(
-                                            TAG, "Not publishing to: " + c);
-                                    if (DEBUG_SERVICE) Slog.v(
-                                            TAG, "Bound intent: " + c.binding.intent.intent);
-                                    if (DEBUG_SERVICE) Slog.v(
-                                            TAG, "Published intent: " + intent);
-                                    continue;
-                                }
-                                if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
-                                try {
-                                    c.conn.connected(r.name, service);
-                                } catch (Exception e) {
-                                    Slog.w(TAG, "Failure sending service " + r.name +
-                                          " to connection " + c.conn.asBinder() +
-                                          " (in " + c.binding.client.processName + ")", e);
-                                }
+                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
+                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+                        for (int i=0; i<clist.size(); i++) {
+                            ConnectionRecord c = clist.get(i);
+                            if (!filter.equals(c.binding.intent.intent)) {
+                                if (DEBUG_SERVICE) Slog.v(
+                                        TAG, "Not publishing to: " + c);
+                                if (DEBUG_SERVICE) Slog.v(
+                                        TAG, "Bound intent: " + c.binding.intent.intent);
+                                if (DEBUG_SERVICE) Slog.v(
+                                        TAG, "Published intent: " + intent);
+                                continue;
+                            }
+                            if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
+                            try {
+                                c.conn.connected(r.name, service);
+                            } catch (Exception e) {
+                                Slog.w(TAG, "Failure sending service " + r.name +
+                                      " to connection " + c.conn.asBinder() +
+                                      " (in " + c.binding.client.processName + ")", e);
                             }
                         }
                     }
                 }
 
-                serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
+                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -649,12 +834,21 @@
                         + " at " + b + ": apps="
                         + (b != null ? b.apps.size() : 0));
 
-                boolean inStopping = mStoppingServices.contains(r);
+                boolean inDestroying = mDestroyingServices.contains(r);
                 if (b != null) {
-                    if (b.apps.size() > 0 && !inStopping) {
+                    if (b.apps.size() > 0 && !inDestroying) {
                         // Applications have already bound since the last
                         // unbind, so just rebind right here.
-                        requestServiceBindingLocked(r, b, true);
+                        boolean inFg = false;
+                        for (int i=b.apps.size()-1; i>=0; i--) {
+                            ProcessRecord client = b.apps.valueAt(i).client;
+                            if (client != null && client.setSchedGroup
+                                    != Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                                inFg = true;
+                                break;
+                            }
+                        }
+                        requestServiceBindingLocked(r, b, inFg, true);
                     } else {
                         // Note to tell the service the next time there is
                         // a new client.
@@ -662,7 +856,7 @@
                     }
                 }
 
-                serviceDoneExecutingLocked(r, inStopping);
+                serviceDoneExecutingLocked(r, inDestroying, false);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -671,7 +865,7 @@
 
     private final ServiceRecord findServiceLocked(ComponentName name,
             IBinder token, int userId) {
-        ServiceRecord r = mServiceMap.getServiceByName(name, userId);
+        ServiceRecord r = getServiceByName(name, userId);
         return r == token ? r : null;
     }
 
@@ -701,7 +895,7 @@
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
             String resolvedType, int callingPid, int callingUid, int userId,
-            boolean createIfNeeded) {
+            boolean createIfNeeded, boolean callingFromFg) {
         ServiceRecord r = null;
         if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
                 + " type=" + resolvedType + " callingUid=" + callingUid);
@@ -709,12 +903,14 @@
         userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
                 false, true, "service", null);
 
-        if (service.getComponent() != null) {
-            r = mServiceMap.getServiceByName(service.getComponent(), userId);
+        ServiceMap smap = getServiceMap(userId);
+        final ComponentName comp = service.getComponent();
+        if (comp != null) {
+            r = smap.mServicesByName.get(comp);
         }
         if (r == null) {
             Intent.FilterComparison filter = new Intent.FilterComparison(service);
-            r = mServiceMap.getServiceByIntent(filter, userId);
+            r = smap.mServicesByIntent.get(filter);
         }
         if (r == null) {
             try {
@@ -735,14 +931,15 @@
                     if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                             sInfo.name, sInfo.flags)) {
                         userId = 0;
+                        smap = getServiceMap(0);
                     }
                     sInfo = new ServiceInfo(sInfo);
                     sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                 }
-                r = mServiceMap.getServiceByName(name, userId);
+                r = smap.mServicesByName.get(name);
                 if (r == null && createIfNeeded) {
-                    Intent.FilterComparison filter = new Intent.FilterComparison(
-                            service.cloneFilter());
+                    Intent.FilterComparison filter
+                            = new Intent.FilterComparison(service.cloneFilter());
                     ServiceRestarter res = new ServiceRestarter();
                     BatteryStatsImpl.Uid.Pkg.Serv ss = null;
                     BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
@@ -751,10 +948,10 @@
                                 sInfo.applicationInfo.uid, sInfo.packageName,
                                 sInfo.name);
                     }
-                    r = new ServiceRecord(mAm, ss, name, filter, sInfo, res);
+                    r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                     res.setService(r);
-                    mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r);
-                    mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r);
+                    smap.mServicesByName.put(name, r);
+                    smap.mServicesByIntent.put(filter, r);
 
                     // Make sure this component isn't in the pending list.
                     int N = mPendingServices.size();
@@ -790,40 +987,55 @@
                         + " requires " + r.permission);
                 return new ServiceLookupResult(null, r.permission);
             }
+            if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
+                    resolvedType, r.appInfo)) {
+                return null;
+            }
             return new ServiceLookupResult(r, null);
         }
         return null;
     }
 
-    private final void bumpServiceExecutingLocked(ServiceRecord r, String why) {
-        if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING "
+    private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
+        if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING "
                 + why + " of " + r + " in app " + r.app);
-        else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING "
+        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING "
                 + why + " of " + r.shortName);
         long now = SystemClock.uptimeMillis();
-        if (r.executeNesting == 0 && r.app != null) {
-            if (r.app.executingServices.size() == 0) {
-                Message msg = mAm.mHandler.obtainMessage(
-                        ActivityManagerService.SERVICE_TIMEOUT_MSG);
-                msg.obj = r.app;
-                mAm.mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
+        if (r.executeNesting == 0) {
+            r.executeFg = fg;
+            ProcessStats.ServiceState stracker = r.getTracker();
+            if (stracker != null) {
+                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
             }
-            r.app.executingServices.add(r);
+            if (r.app != null) {
+                r.app.executingServices.add(r);
+                r.app.execServicesFg |= fg;
+                if (r.app.executingServices.size() == 1) {
+                    scheduleServiceTimeoutLocked(r.app);
+                }
+            }
+        } else if (r.app != null && fg && !r.app.execServicesFg) {
+            r.app.execServicesFg = true;
+            scheduleServiceTimeoutLocked(r.app);
         }
+        r.executeFg |= fg;
         r.executeNesting++;
         r.executingStart = now;
     }
 
     private final boolean requestServiceBindingLocked(ServiceRecord r,
-            IntentBindRecord i, boolean rebind) {
+            IntentBindRecord i, boolean execInFg, boolean rebind) {
         if (r.app == null || r.app.thread == null) {
             // If service is not currently running, can't yet bind.
             return false;
         }
         if ((!i.requested || rebind) && i.apps.size() > 0) {
             try {
-                bumpServiceExecutingLocked(r, "bind");
-                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
+                bumpServiceExecutingLocked(r, execInFg, "bind");
+                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
+                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
+                        r.app.repProcState);
                 if (!rebind) {
                     i.requested = true;
                 }
@@ -932,6 +1144,7 @@
         }
 
         if (!mRestartingServices.contains(r)) {
+            r.createdFromFg = false;
             mRestartingServices.add(r);
         }
 
@@ -952,7 +1165,7 @@
         if (!mRestartingServices.contains(r)) {
             return;
         }
-        bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
+        bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
     }
 
     private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
@@ -966,12 +1179,12 @@
     }
 
     private final String bringUpServiceLocked(ServiceRecord r,
-            int intentFlags, boolean whileRestarting) {
+            int intentFlags, boolean execInFg, boolean whileRestarting) {
         //Slog.i(TAG, "Bring up service:");
         //r.dump("  ");
 
         if (r.app != null && r.app.thread != null) {
-            sendServiceArgsLocked(r, false);
+            sendServiceArgsLocked(r, execInFg, false);
             return null;
         }
 
@@ -986,6 +1199,13 @@
         // restarting state.
         mRestartingServices.remove(r);
 
+        // Make sure this service is no longer considered delayed, we are starting it now.
+        if (r.delayed) {
+            if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+            getServiceMap(r.userId).mDelayedStartList.remove(r);
+            r.delayed = false;
+        }
+
         // Make sure that the user who owns this service is started.  If not,
         // we don't want to allow it to run.
         if (mAm.mStartedUsers.get(r.userId) == null) {
@@ -994,7 +1214,7 @@
                     + r.appInfo.uid + " for service "
                     + r.intent.getIntent() + ": user " + r.userId + " is stopped";
             Slog.w(TAG, msg);
-            bringDownServiceLocked(r, true);
+            bringDownServiceLocked(r);
             return msg;
         }
 
@@ -1013,13 +1233,13 @@
         ProcessRecord app;
 
         if (!isolated) {
-            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
-            if (DEBUG_MU)
-                Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
+            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
+            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+                        + " app=" + app);
             if (app != null && app.thread != null) {
                 try {
-                    app.addPackage(r.appInfo.packageName);
-                    realStartServiceLocked(r, app);
+                    app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
+                    realStartServiceLocked(r, app, execInFg);
                     return null;
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Exception when starting service " + r.shortName, e);
@@ -1042,13 +1262,13 @@
         // to be executed when the app comes up.
         if (app == null) {
             if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
-                    "service", r.name, false, isolated)) == null) {
+                    "service", r.name, false, isolated, false)) == null) {
                 String msg = "Unable to launch app "
                         + r.appInfo.packageName + "/"
                         + r.appInfo.uid + " for service "
                         + r.intent.getIntent() + ": process is bad";
                 Slog.w(TAG, msg);
-                bringDownServiceLocked(r, true);
+                bringDownServiceLocked(r);
                 return msg;
             }
             if (isolated) {
@@ -1060,21 +1280,29 @@
             mPendingServices.add(r);
         }
 
+        if (r.delayedStop) {
+            // Oh and hey we've already been asked to stop!
+            r.delayedStop = false;
+            if (r.startRequested) {
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+                stopServiceLocked(r);
+            }
+        }
+
         return null;
     }
 
-    private final void requestServiceBindingsLocked(ServiceRecord r) {
-        Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
-        while (bindings.hasNext()) {
-            IntentBindRecord i = bindings.next();
-            if (!requestServiceBindingLocked(r, i, false)) {
+    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) {
+        for (int i=r.bindings.size()-1; i>=0; i--) {
+            IntentBindRecord ibr = r.bindings.valueAt(i);
+            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                 break;
             }
         }
     }
 
     private final void realStartServiceLocked(ServiceRecord r,
-            ProcessRecord app) throws RemoteException {
+            ProcessRecord app, boolean execInFg) throws RemoteException {
         if (app.thread == null) {
             throw new RemoteException();
         }
@@ -1085,19 +1313,24 @@
         r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
 
         app.services.add(r);
-        bumpServiceExecutingLocked(r, "create");
-        mAm.updateLruProcessLocked(app, true);
+        bumpServiceExecutingLocked(r, execInFg, "create");
+        mAm.updateLruProcessLocked(app, true, false);
 
         boolean created = false;
         try {
+            String nameTerm;
+            int lastPeriod = r.shortName.lastIndexOf('.');
+            nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
             EventLogTags.writeAmCreateService(
-                    r.userId, System.identityHashCode(r), r.shortName, r.app.pid);
+                    r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.startLaunchedLocked();
             }
             mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
+            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
             app.thread.scheduleCreateService(r, r.serviceInfo,
-                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
+                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
+                    app.repProcState);
             r.postNotification();
             created = true;
         } finally {
@@ -1107,7 +1340,7 @@
             }
         }
 
-        requestServiceBindingsLocked(r);
+        requestServiceBindingsLocked(r, execInFg);
 
         // If the service is in the started state, and there are no
         // pending arguments, then fake up one so its onStartCommand() will
@@ -1117,10 +1350,25 @@
                     null, null));
         }
 
-        sendServiceArgsLocked(r, true);
+        sendServiceArgsLocked(r, execInFg, true);
+
+        if (r.delayed) {
+            if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+            getServiceMap(r.userId).mDelayedStartList.remove(r);
+            r.delayed = false;
+        }
+
+        if (r.delayedStop) {
+            // Oh and hey we've already been asked to stop!
+            r.delayedStop = false;
+            if (r.startRequested) {
+                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+                stopServiceLocked(r);
+            }
+        }
     }
 
-    private final void sendServiceArgsLocked(ServiceRecord r,
+    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
             boolean oomAdjusted) {
         final int N = r.pendingStarts.size();
         if (N == 0) {
@@ -1146,7 +1394,7 @@
                     mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                             si.getUriPermissionsLocked());
                 }
-                bumpServiceExecutingLocked(r, "start");
+                bumpServiceExecutingLocked(r, execInFg, "start");
                 if (!oomAdjusted) {
                     oomAdjusted = true;
                     mAm.updateOomAdjLocked(r.app);
@@ -1171,60 +1419,72 @@
         }
     }
 
-    private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
+    private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
+        // Are we still explicitly being asked to run?
+        if (r.startRequested) {
+            return true;
+        }
+
+        // Is someone still bound to us keepign us running?
+        if (!knowConn) {
+            hasConn = r.hasAutoCreateConnections();
+        }
+        if (hasConn) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
+            boolean hasConn) {
         //Slog.i(TAG, "Bring down service:");
         //r.dump("  ");
 
-        // Does it still need to run?
-        if (!force && r.startRequested) {
+        if (isServiceNeeded(r, knowConn, hasConn)) {
             return;
         }
-        if (r.connections.size() > 0) {
-            if (!force) {
-                // XXX should probably keep a count of the number of auto-create
-                // connections directly in the service.
-                Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
-                while (it.hasNext()) {
-                    ArrayList<ConnectionRecord> cr = it.next();
-                    for (int i=0; i<cr.size(); i++) {
-                        if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
-                            return;
-                        }
-                    }
-                }
-            }
 
-            // Report to all of the connections that the service is no longer
-            // available.
-            Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
-            while (it.hasNext()) {
-                ArrayList<ConnectionRecord> c = it.next();
-                for (int i=0; i<c.size(); i++) {
-                    ConnectionRecord cr = c.get(i);
-                    // There is still a connection to the service that is
-                    // being brought down.  Mark it as dead.
-                    cr.serviceDead = true;
-                    try {
-                        cr.conn.connected(r.name, null);
-                    } catch (Exception e) {
-                        Slog.w(TAG, "Failure disconnecting service " + r.name +
-                              " to connection " + c.get(i).conn.asBinder() +
-                              " (in " + c.get(i).binding.client.processName + ")", e);
-                    }
+        // Are we in the process of launching?
+        if (mPendingServices.contains(r)) {
+            return;
+        }
+
+        bringDownServiceLocked(r);
+    }
+
+    private final void bringDownServiceLocked(ServiceRecord r) {
+        //Slog.i(TAG, "Bring down service:");
+        //r.dump("  ");
+
+        // Report to all of the connections that the service is no longer
+        // available.
+        for (int conni=r.connections.size()-1; conni>=0; conni--) {
+            ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
+            for (int i=0; i<c.size(); i++) {
+                ConnectionRecord cr = c.get(i);
+                // There is still a connection to the service that is
+                // being brought down.  Mark it as dead.
+                cr.serviceDead = true;
+                try {
+                    cr.conn.connected(r.name, null);
+                } catch (Exception e) {
+                    Slog.w(TAG, "Failure disconnecting service " + r.name +
+                          " to connection " + c.get(i).conn.asBinder() +
+                          " (in " + c.get(i).binding.client.processName + ")", e);
                 }
             }
         }
 
         // Tell the service that it has been unbound.
-        if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
-            Iterator<IntentBindRecord> it = r.bindings.values().iterator();
-            while (it.hasNext()) {
-                IntentBindRecord ibr = it.next();
+        if (r.app != null && r.app.thread != null) {
+            for (int i=r.bindings.size()-1; i>=0; i--) {
+                IntentBindRecord ibr = r.bindings.valueAt(i);
                 if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
                         + ": hasBound=" + ibr.hasBound);
-                if (r.app != null && r.app.thread != null && ibr.hasBound) {
+                if (ibr.hasBound) {
                     try {
-                        bumpServiceExecutingLocked(r, "bring down unbind");
+                        bumpServiceExecutingLocked(r, false, "bring down unbind");
                         mAm.updateOomAdjLocked(r.app);
                         ibr.hasBound = false;
                         r.app.thread.scheduleUnbindService(r,
@@ -1232,7 +1492,7 @@
                     } catch (Exception e) {
                         Slog.w(TAG, "Exception when unbinding service "
                                 + r.shortName, e);
-                        serviceDoneExecutingLocked(r, true);
+                        serviceDoneExecutingLocked(r, true, true);
                     }
                 }
             }
@@ -1242,8 +1502,9 @@
         EventLogTags.writeAmDestroyService(
                 r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1);
 
-        mServiceMap.removeServiceByName(r.name, r.userId);
-        mServiceMap.removeServiceByIntent(r.intent, r.userId);
+        final ServiceMap smap = getServiceMap(r.userId);
+        smap.mServicesByName.remove(r.name);
+        smap.mServicesByIntent.remove(r.intent);
         r.totalRestartCount = 0;
         unscheduleServiceRestartLocked(r);
 
@@ -1274,14 +1535,14 @@
             r.app.services.remove(r);
             if (r.app.thread != null) {
                 try {
-                    bumpServiceExecutingLocked(r, "stop");
-                    mStoppingServices.add(r);
+                    bumpServiceExecutingLocked(r, false, "destroy");
+                    mDestroyingServices.add(r);
                     mAm.updateOomAdjLocked(r.app);
                     r.app.thread.scheduleStopService(r);
                 } catch (Exception e) {
-                    Slog.w(TAG, "Exception when stopping service "
+                    Slog.w(TAG, "Exception when destroying service "
                             + r.shortName, e);
-                    serviceDoneExecutingLocked(r, true);
+                    serviceDoneExecutingLocked(r, true, true);
                 }
                 updateServiceForegroundLocked(r.app, false);
             } else {
@@ -1300,6 +1561,19 @@
         if (r.restarter instanceof ServiceRestarter) {
            ((ServiceRestarter)r.restarter).setService(null);
         }
+
+        int memFactor = mAm.mProcessStats.getMemFactorLocked();
+        long now = SystemClock.uptimeMillis();
+        if (r.tracker != null) {
+            r.tracker.setStarted(false, memFactor, now);
+            r.tracker.setBound(false, memFactor, now);
+            if (r.executeNesting == 0) {
+                r.tracker.clearCurrentOwner(r);
+                r.tracker = null;
+            }
+        }
+
+        smap.ensureNotStartingBackground(r);
     }
 
     void removeConnectionLocked(
@@ -1344,7 +1618,7 @@
             if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                     && b.intent.hasBound) {
                 try {
-                    bumpServiceExecutingLocked(s, "unbind");
+                    bumpServiceExecutingLocked(s, false, "unbind");
                     mAm.updateOomAdjLocked(s.app);
                     b.intent.hasBound = false;
                     // Assume the client doesn't want to know about a rebind;
@@ -1353,18 +1627,25 @@
                     s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
-                    serviceDoneExecutingLocked(s, true);
+                    serviceDoneExecutingLocked(s, true, true);
                 }
             }
 
             if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
-                bringDownServiceLocked(s, false);
+                boolean hasAutoCreate = s.hasAutoCreateConnections();
+                if (!hasAutoCreate) {
+                    if (s.tracker != null) {
+                        s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
+                                SystemClock.uptimeMillis());
+                    }
+                }
+                bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
             }
         }
     }
 
     void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
-        boolean inStopping = mStoppingServices.contains(r);
+        boolean inDestroying = mDestroyingServices.contains(r);
         if (r != null) {
             if (type == 1) {
                 // This is a call from a service start...  take care of
@@ -1417,7 +1698,7 @@
                 }
             }
             final long origId = Binder.clearCallingIdentity();
-            serviceDoneExecutingLocked(r, inStopping);
+            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
             Binder.restoreCallingIdentity(origId);
         } else {
             Slog.w(TAG, "Done executing unknown service from pid "
@@ -1425,28 +1706,49 @@
         }
     }
 
-    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
+    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
+            boolean finishing) {
         if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
                 + ": nesting=" + r.executeNesting
-                + ", inStopping=" + inStopping + ", app=" + r.app);
+                + ", inDestroying=" + inDestroying + ", app=" + r.app);
         else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
         r.executeNesting--;
-        if (r.executeNesting <= 0 && r.app != null) {
-            if (DEBUG_SERVICE) Slog.v(TAG,
-                    "Nesting at 0 of " + r.shortName);
-            r.app.executingServices.remove(r);
-            if (r.app.executingServices.size() == 0) {
-                if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
-                        "No more executingServices of " + r.shortName);
-                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
-            }
-            if (inStopping) {
+        if (r.executeNesting <= 0) {
+            if (r.app != null) {
                 if (DEBUG_SERVICE) Slog.v(TAG,
-                        "doneExecuting remove stopping " + r);
-                mStoppingServices.remove(r);
-                r.bindings.clear();
+                        "Nesting at 0 of " + r.shortName);
+                r.app.execServicesFg = false;
+                r.app.executingServices.remove(r);
+                if (r.app.executingServices.size() == 0) {
+                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
+                            "No more executingServices of " + r.shortName);
+                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
+                } else if (r.executeFg) {
+                    // Need to re-evaluate whether the app still needs to be in the foreground.
+                    for (int i=r.app.executingServices.size()-1; i>=0; i--) {
+                        if (r.app.executingServices.valueAt(i).executeFg) {
+                            r.app.execServicesFg = true;
+                            break;
+                        }
+                    }
+                }
+                if (inDestroying) {
+                    if (DEBUG_SERVICE) Slog.v(TAG,
+                            "doneExecuting remove destroying " + r);
+                    mDestroyingServices.remove(r);
+                    r.bindings.clear();
+                }
+                mAm.updateOomAdjLocked(r.app);
             }
-            mAm.updateOomAdjLocked(r.app);
+            r.executeFg = false;
+            if (r.tracker != null) {
+                r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
+                        SystemClock.uptimeMillis());
+                if (finishing) {
+                    r.tracker.clearCurrentOwner(r);
+                    r.tracker = null;
+                }
+            }
         }
     }
 
@@ -1465,7 +1767,8 @@
 
                     mPendingServices.remove(i);
                     i--;
-                    realStartServiceLocked(sr, proc);
+                    proc.addPackage(sr.appInfo.packageName, mAm.mProcessStats);
+                    realStartServiceLocked(sr, proc, sr.createdFromFg);
                     didSomething = true;
                 }
             } catch (Exception e) {
@@ -1503,17 +1806,18 @@
                 sr.isolatedProc = null;
                 mPendingServices.remove(i);
                 i--;
-                bringDownServiceLocked(sr, true);
+                bringDownServiceLocked(sr);
             }
         }
     }
 
     private boolean collectForceStopServicesLocked(String name, int userId,
             boolean evenPersistent, boolean doit,
-            HashMap<ComponentName, ServiceRecord> services,
+            ArrayMap<ComponentName, ServiceRecord> services,
             ArrayList<ServiceRecord> result) {
         boolean didSomething = false;
-        for (ServiceRecord service : services.values()) {
+        for (int i=0; i<services.size(); i++) {
+            ServiceRecord service = services.valueAt(i);
             if ((name == null || service.packageName.equals(name))
                     && (service.app == null || evenPersistent || !service.app.persistent)) {
                 if (!doit) {
@@ -1536,17 +1840,17 @@
         boolean didSomething = false;
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
         if (userId == UserHandle.USER_ALL) {
-            for (int i=0; i<mServiceMap.mServicesByNamePerUser.size(); i++) {
+            for (int i=0; i<mServiceMap.size(); i++) {
                 didSomething |= collectForceStopServicesLocked(name, userId, evenPersistent,
-                        doit, mServiceMap.mServicesByNamePerUser.valueAt(i), services);
+                        doit, mServiceMap.valueAt(i).mServicesByName, services);
                 if (!doit && didSomething) {
                     return true;
                 }
             }
         } else {
-            HashMap<ComponentName, ServiceRecord> items
-                    = mServiceMap.mServicesByNamePerUser.get(userId);
-            if (items != null) {
+            ServiceMap smap = mServiceMap.get(userId);
+            if (smap != null) {
+                ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName;
                 didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
                         doit, items, services);
             }
@@ -1554,14 +1858,16 @@
 
         int N = services.size();
         for (int i=0; i<N; i++) {
-            bringDownServiceLocked(services.get(i), true);
+            bringDownServiceLocked(services.get(i));
         }
         return didSomething;
     }
 
     void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
-        for (ServiceRecord sr : mServiceMap.getAllServices(tr.userId)) {
+        ArrayMap<ComponentName, ServiceRecord> alls = getServices(tr.userId);
+        for (int i=0; i<alls.size(); i++) {
+            ServiceRecord sr = alls.valueAt(i);
             if (sr.packageName.equals(component.getPackageName())) {
                 services.add(sr);
             }
@@ -1578,7 +1884,9 @@
                     sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
                             sr.makeNextStartId(), baseIntent, null));
                     if (sr.app != null && sr.app.thread != null) {
-                        sendServiceArgsLocked(sr, false);
+                        // We always run in the foreground, since this is called as
+                        // part of the "remove task" UI operation.
+                        sendServiceArgsLocked(sr, true, false);
                     }
                 }
             }
@@ -1595,22 +1903,18 @@
                 Iterator<ServiceRecord> it = app.services.iterator();
                 while (it.hasNext()) {
                     ServiceRecord r = it.next();
-                    if (r.connections.size() > 0) {
-                        Iterator<ArrayList<ConnectionRecord>> jt
-                                = r.connections.values().iterator();
-                        while (jt.hasNext()) {
-                            ArrayList<ConnectionRecord> cl = jt.next();
-                            for (int i=0; i<cl.size(); i++) {
-                                ConnectionRecord c = cl.get(i);
-                                if (c.binding.client != app) {
-                                    try {
-                                        //c.conn.connected(r.className, null);
-                                    } catch (Exception e) {
-                                        // todo: this should be asynchronous!
-                                        Slog.w(TAG, "Exception thrown disconnected servce "
-                                              + r.shortName
-                                              + " from app " + app.processName, e);
-                                    }
+                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
+                        ArrayList<ConnectionRecord> cl = r.connections.valueAt(conni);
+                        for (int i=0; i<cl.size(); i++) {
+                            ConnectionRecord c = cl.get(i);
+                            if (c.binding.client != app) {
+                                try {
+                                    //c.conn.connected(r.className, null);
+                                } catch (Exception e) {
+                                    // todo: this should be asynchronous!
+                                    Slog.w(TAG, "Exception thrown disconnected servce "
+                                          + r.shortName
+                                          + " from app " + app.processName, e);
                                 }
                             }
                         }
@@ -1620,84 +1924,80 @@
         }
 
         // Clean up any connections this application has to other services.
-        if (app.connections.size() > 0) {
-            Iterator<ConnectionRecord> it = app.connections.iterator();
-            while (it.hasNext()) {
-                ConnectionRecord r = it.next();
-                removeConnectionLocked(r, app, null);
-            }
+        for (int i=app.connections.size()-1; i>=0; i--) {
+            ConnectionRecord r = app.connections.valueAt(i);
+            removeConnectionLocked(r, app, null);
         }
         app.connections.clear();
 
-        if (app.services.size() != 0) {
+        for (int i=app.services.size()-1; i>=0; i--) {
             // Any services running in the application need to be placed
             // back in the pending list.
-            Iterator<ServiceRecord> it = app.services.iterator();
-            while (it.hasNext()) {
-                ServiceRecord sr = it.next();
-                synchronized (sr.stats.getBatteryStats()) {
-                    sr.stats.stopLaunchedLocked();
-                }
-                sr.app = null;
-                sr.isolatedProc = null;
-                sr.executeNesting = 0;
-                if (mStoppingServices.remove(sr)) {
-                    if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
-                }
+            ServiceRecord sr = app.services.valueAt(i);
+            synchronized (sr.stats.getBatteryStats()) {
+                sr.stats.stopLaunchedLocked();
+            }
+            sr.app = null;
+            sr.isolatedProc = null;
+            sr.executeNesting = 0;
+            sr.forceClearTracker();
+            if (mDestroyingServices.remove(sr)) {
+                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+            }
 
-                boolean hasClients = sr.bindings.size() > 0;
-                if (hasClients) {
-                    Iterator<IntentBindRecord> bindings
-                            = sr.bindings.values().iterator();
-                    while (bindings.hasNext()) {
-                        IntentBindRecord b = bindings.next();
-                        if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
-                                + ": shouldUnbind=" + b.hasBound);
-                        b.binder = null;
-                        b.requested = b.received = b.hasBound = false;
-                    }
-                }
+            final int numClients = sr.bindings.size();
+            for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
+                IntentBindRecord b = sr.bindings.valueAt(bindingi);
+                if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+                        + ": shouldUnbind=" + b.hasBound);
+                b.binder = null;
+                b.requested = b.received = b.hasBound = false;
+            }
 
-                if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
-                        &ApplicationInfo.FLAG_PERSISTENT) == 0) {
-                    Slog.w(TAG, "Service crashed " + sr.crashCount
-                            + " times, stopping: " + sr);
-                    EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
-                            sr.userId, sr.crashCount, sr.shortName, app.pid);
-                    bringDownServiceLocked(sr, true);
-                } else if (!allowRestart) {
-                    bringDownServiceLocked(sr, true);
-                } else {
-                    boolean canceled = scheduleServiceRestartLocked(sr, true);
+            if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
+                    &ApplicationInfo.FLAG_PERSISTENT) == 0) {
+                Slog.w(TAG, "Service crashed " + sr.crashCount
+                        + " times, stopping: " + sr);
+                EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
+                        sr.userId, sr.crashCount, sr.shortName, app.pid);
+                bringDownServiceLocked(sr);
+            } else if (!allowRestart) {
+                bringDownServiceLocked(sr);
+            } else {
+                boolean canceled = scheduleServiceRestartLocked(sr, true);
 
-                    // Should the service remain running?  Note that in the
-                    // extreme case of so many attempts to deliver a command
-                    // that it failed we also will stop it here.
-                    if (sr.startRequested && (sr.stopIfKilled || canceled)) {
-                        if (sr.pendingStarts.size() == 0) {
-                            sr.startRequested = false;
-                            if (!hasClients) {
-                                // Whoops, no reason to restart!
-                                bringDownServiceLocked(sr, true);
-                            }
+                // Should the service remain running?  Note that in the
+                // extreme case of so many attempts to deliver a command
+                // that it failed we also will stop it here.
+                if (sr.startRequested && (sr.stopIfKilled || canceled)) {
+                    if (sr.pendingStarts.size() == 0) {
+                        sr.startRequested = false;
+                        if (sr.tracker != null) {
+                            sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                                    SystemClock.uptimeMillis());
+                        }
+                        if (!sr.hasAutoCreateConnections()) {
+                            // Whoops, no reason to restart!
+                            bringDownServiceLocked(sr);
                         }
                     }
                 }
             }
+        }
 
-            if (!allowRestart) {
-                app.services.clear();
-            }
+        if (!allowRestart) {
+            app.services.clear();
         }
 
         // Make sure we have no more records on the stopping list.
-        int i = mStoppingServices.size();
+        int i = mDestroyingServices.size();
         while (i > 0) {
             i--;
-            ServiceRecord sr = mStoppingServices.get(i);
+            ServiceRecord sr = mDestroyingServices.get(i);
             if (sr.app == app) {
-                mStoppingServices.remove(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
+                sr.forceClearTracker();
+                mDestroyingServices.remove(i);
+                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
             }
         }
 
@@ -1732,7 +2032,8 @@
             info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
         }
 
-        for (ArrayList<ConnectionRecord> connl : r.connections.values()) {
+        for (int conni=r.connections.size()-1; conni>=0; conni--) {
+            ArrayList<ConnectionRecord> connl = r.connections.valueAt(conni);
             for (int i=0; i<connl.size(); i++) {
                 ConnectionRecord conn = connl.get(i);
                 if (conn.clientLabel != 0) {
@@ -1758,12 +2059,10 @@
                     uid) == PackageManager.PERMISSION_GRANTED) {
                 int[] users = mAm.getUsersLocked();
                 for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
-                    if (mServiceMap.getAllServices(users[ui]).size() > 0) {
-                        Iterator<ServiceRecord> it = mServiceMap.getAllServices(
-                                users[ui]).iterator();
-                        while (it.hasNext() && res.size() < maxNum) {
-                            res.add(makeRunningServiceInfoLocked(it.next()));
-                        }
+                    ArrayMap<ComponentName, ServiceRecord> alls = getServices(users[ui]);
+                    for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
+                        ServiceRecord sr = alls.valueAt(i);
+                        res.add(makeRunningServiceInfoLocked(sr));
                     }
                 }
 
@@ -1776,12 +2075,10 @@
                 }
             } else {
                 int userId = UserHandle.getUserId(uid);
-                if (mServiceMap.getAllServices(userId).size() > 0) {
-                    Iterator<ServiceRecord> it
-                            = mServiceMap.getAllServices(userId).iterator();
-                    while (it.hasNext() && res.size() < maxNum) {
-                        res.add(makeRunningServiceInfoLocked(it.next()));
-                    }
+                ArrayMap<ComponentName, ServiceRecord> alls = getServices(userId);
+                for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
+                    ServiceRecord sr = alls.valueAt(i);
+                    res.add(makeRunningServiceInfoLocked(sr));
                 }
 
                 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
@@ -1803,9 +2100,10 @@
 
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
         int userId = UserHandle.getUserId(Binder.getCallingUid());
-        ServiceRecord r = mServiceMap.getServiceByName(name, userId);
+        ServiceRecord r = getServiceByName(name, userId);
         if (r != null) {
-            for (ArrayList<ConnectionRecord> conn : r.connections.values()) {
+            for (int conni=r.connections.size()-1; conni>=0; conni--) {
+                ArrayList<ConnectionRecord> conn = r.connections.valueAt(conni);
                 for (int i=0; i<conn.size(); i++) {
                     if (conn.get(i).clientIntent != null) {
                         return conn.get(i).clientIntent;
@@ -1823,12 +2121,12 @@
             if (proc.executingServices.size() == 0 || proc.thread == null) {
                 return;
             }
-            long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
-            Iterator<ServiceRecord> it = proc.executingServices.iterator();
+            long maxTime = SystemClock.uptimeMillis() -
+                    (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
             ServiceRecord timeout = null;
             long nextTime = 0;
-            while (it.hasNext()) {
-                ServiceRecord sr = it.next();
+            for (int i=proc.executingServices.size()-1; i>=0; i--) {
+                ServiceRecord sr = proc.executingServices.valueAt(i);
                 if (sr.executingStart < maxTime) {
                     timeout = sr;
                     break;
@@ -1844,7 +2142,8 @@
                 Message msg = mAm.mHandler.obtainMessage(
                         ActivityManagerService.SERVICE_TIMEOUT_MSG);
                 msg.obj = proc;
-                mAm.mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
+                mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
+                        ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
             }
         }
 
@@ -1853,12 +2152,25 @@
         }
     }
 
+    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
+        if (proc.executingServices.size() == 0 || proc.thread == null) {
+            return;
+        }
+        long now = SystemClock.uptimeMillis();
+        Message msg = mAm.mHandler.obtainMessage(
+                ActivityManagerService.SERVICE_TIMEOUT_MSG);
+        msg.obj = proc;
+        mAm.mHandler.sendMessageAtTime(msg,
+                proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
+    }
+
     /**
      * Prints a list of ServiceRecords (dumpsys activity services)
      */
-    boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+    void dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         boolean needSep = false;
+        boolean printedAnything = false;
 
         ItemMatcher matcher = new ItemMatcher();
         matcher.build(args, opti);
@@ -1867,14 +2179,13 @@
         try {
             int[] users = mAm.getUsersLocked();
             for (int user : users) {
-                if (mServiceMap.getAllServices(user).size() > 0) {
-                    boolean printed = false;
+                ServiceMap smap = getServiceMap(user);
+                boolean printed = false;
+                if (smap.mServicesByName.size() > 0) {
                     long nowReal = SystemClock.elapsedRealtime();
-                    Iterator<ServiceRecord> it = mServiceMap.getAllServices(
-                            user).iterator();
                     needSep = false;
-                    while (it.hasNext()) {
-                        ServiceRecord r = it.next();
+                    for (int si=0; si<smap.mServicesByName.size(); si++) {
+                        ServiceRecord r = smap.mServicesByName.valueAt(si);
                         if (!matcher.match(r, r.name)) {
                             continue;
                         }
@@ -1882,12 +2193,13 @@
                             continue;
                         }
                         if (!printed) {
-                            if (user != 0) {
+                            if (printedAnything) {
                                 pw.println();
                             }
                             pw.println("  User " + user + " active services:");
                             printed = true;
                         }
+                        printedAnything = true;
                         if (needSep) {
                             pw.println();
                         }
@@ -1907,7 +2219,8 @@
                             pw.println(r.connections.size());
                             if (r.connections.size() > 0) {
                                 pw.println("    Connections:");
-                                for (ArrayList<ConnectionRecord> clist : r.connections.values()) {
+                                for (int conni=0; conni<r.connections.size(); conni++) {
+                                    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                                     for (int i = 0; i < clist.size(); i++) {
                                         ConnectionRecord conn = clist.get(i);
                                         pw.print("      ");
@@ -1943,11 +2256,49 @@
                             needSep = true;
                         }
                     }
-                    needSep = printed;
+                    needSep |= printed;
+                }
+                printed = false;
+                for (int si=0, SN=smap.mDelayedStartList.size(); si<SN; si++) {
+                    ServiceRecord r = smap.mDelayedStartList.get(si);
+                    if (!matcher.match(r, r.name)) {
+                        continue;
+                    }
+                    if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (printedAnything) {
+                            pw.println();
+                        }
+                        pw.println("  User " + user + " delayed start services:");
+                        printed = true;
+                    }
+                    printedAnything = true;
+                    pw.print("  * Delayed start "); pw.println(r);
+                }
+                printed = false;
+                for (int si=0, SN=smap.mStartingBackground.size(); si<SN; si++) {
+                    ServiceRecord r = smap.mStartingBackground.get(si);
+                    if (!matcher.match(r, r.name)) {
+                        continue;
+                    }
+                    if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (printedAnything) {
+                            pw.println();
+                        }
+                        pw.println("  User " + user + " starting in background:");
+                        printed = true;
+                    }
+                    printedAnything = true;
+                    pw.print("  * Starting bg "); pw.println(r);
                 }
             }
         } catch (Exception e) {
-            Log.w(TAG, "Exception in dumpServicesLocked: " + e);
+            Slog.w(TAG, "Exception in dumpServicesLocked", e);
         }
 
         if (mPendingServices.size() > 0) {
@@ -1960,8 +2311,9 @@
                 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
                     continue;
                 }
+                printedAnything = true;
                 if (!printed) {
-                    if (needSep) pw.println(" ");
+                    if (needSep) pw.println();
                     needSep = true;
                     pw.println("  Pending services:");
                     printed = true;
@@ -1982,8 +2334,9 @@
                 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
                     continue;
                 }
+                printedAnything = true;
                 if (!printed) {
-                    if (needSep) pw.println(" ");
+                    if (needSep) pw.println();
                     needSep = true;
                     pw.println("  Restarting services:");
                     printed = true;
@@ -1994,59 +2347,58 @@
             needSep = true;
         }
 
-        if (mStoppingServices.size() > 0) {
+        if (mDestroyingServices.size() > 0) {
             boolean printed = false;
-            for (int i=0; i<mStoppingServices.size(); i++) {
-                ServiceRecord r = mStoppingServices.get(i);
+            for (int i=0; i< mDestroyingServices.size(); i++) {
+                ServiceRecord r = mDestroyingServices.get(i);
                 if (!matcher.match(r, r.name)) {
                     continue;
                 }
                 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
                     continue;
                 }
+                printedAnything = true;
                 if (!printed) {
-                    if (needSep) pw.println(" ");
+                    if (needSep) pw.println();
                     needSep = true;
-                    pw.println("  Stopping services:");
+                    pw.println("  Destroying services:");
                     printed = true;
                 }
-                pw.print("  * Stopping "); pw.println(r);
+                pw.print("  * Destroy "); pw.println(r);
                 r.dump(pw, "    ");
             }
             needSep = true;
         }
 
         if (dumpAll) {
-            if (mServiceConnections.size() > 0) {
-                boolean printed = false;
-                Iterator<ArrayList<ConnectionRecord>> it
-                        = mServiceConnections.values().iterator();
-                while (it.hasNext()) {
-                    ArrayList<ConnectionRecord> r = it.next();
-                    for (int i=0; i<r.size(); i++) {
-                        ConnectionRecord cr = r.get(i);
-                        if (!matcher.match(cr.binding.service, cr.binding.service.name)) {
-                            continue;
-                        }
-                        if (dumpPackage != null && (cr.binding.client == null
-                                || !dumpPackage.equals(cr.binding.client.info.packageName))) {
-                            continue;
-                        }
-                        if (!printed) {
-                            if (needSep) pw.println(" ");
-                            needSep = true;
-                            pw.println("  Connection bindings to services:");
-                            printed = true;
-                        }
-                        pw.print("  * "); pw.println(cr);
-                        cr.dump(pw, "    ");
+            boolean printed = false;
+            for (int ic=0; ic<mServiceConnections.size(); ic++) {
+                ArrayList<ConnectionRecord> r = mServiceConnections.valueAt(ic);
+                for (int i=0; i<r.size(); i++) {
+                    ConnectionRecord cr = r.get(i);
+                    if (!matcher.match(cr.binding.service, cr.binding.service.name)) {
+                        continue;
                     }
+                    if (dumpPackage != null && (cr.binding.client == null
+                            || !dumpPackage.equals(cr.binding.client.info.packageName))) {
+                        continue;
+                    }
+                    printedAnything = true;
+                    if (!printed) {
+                        if (needSep) pw.println();
+                        needSep = true;
+                        pw.println("  Connection bindings to services:");
+                        printed = true;
+                    }
+                    pw.print("  * "); pw.println(cr);
+                    cr.dump(pw, "    ");
                 }
-                needSep = true;
             }
         }
 
-        return needSep;
+        if (!printedAnything) {
+            pw.println("  (nothing)");
+        }
     }
 
     /**
@@ -2065,7 +2417,9 @@
             int[] users = mAm.getUsersLocked();
             if ("all".equals(name)) {
                 for (int user : users) {
-                    for (ServiceRecord r1 : mServiceMap.getAllServices(user)) {
+                    ArrayMap<ComponentName, ServiceRecord> alls = getServices(user);
+                    for (int i=0; i<alls.size(); i++) {
+                        ServiceRecord r1 = alls.valueAt(i);
                         services.add(r1);
                     }
                 }
@@ -2084,7 +2438,9 @@
                 }
 
                 for (int user : users) {
-                    for (ServiceRecord r1 : mServiceMap.getAllServices(user)) {
+                    ArrayMap<ComponentName, ServiceRecord> alls = getServices(user);
+                    for (int i=0; i<alls.size(); i++) {
+                        ServiceRecord r1 = alls.valueAt(i);
                         if (componentName != null) {
                             if (r1.name.equals(componentName)) {
                                 services.add(r1);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6fccee0..15f798d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -17,28 +17,59 @@
 package com.android.server.am;
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
 import android.app.AppOpsManager;
 import android.appwidget.AppWidgetManager;
+import android.util.ArrayMap;
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ProcessStats;
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.ProcessStats;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.MemInfoReader;
+import com.android.internal.util.Preconditions;
 import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
-import com.android.server.ProcessMap;
+import com.android.internal.app.ProcessMap;
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.AppTransition;
+import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
 
 import dalvik.system.Zygote;
 
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -84,6 +115,7 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PathPermission;
@@ -124,7 +156,9 @@
 import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.format.DateUtils;
 import android.text.format.Time;
+import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
@@ -132,6 +166,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.util.Xml;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -139,7 +174,6 @@
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
@@ -166,41 +200,45 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
-public final class ActivityManagerService  extends ActivityManagerNative
+public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
     private static final String USER_DATA_DIR = "/data/user/";
     static final String TAG = "ActivityManager";
     static final String TAG_MU = "ActivityManagerServiceMU";
     static final boolean DEBUG = false;
     static final boolean localLOGV = DEBUG;
+    static final boolean DEBUG_BACKUP = localLOGV || false;
+    static final boolean DEBUG_BROADCAST = localLOGV || false;
+    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_CLEANUP = localLOGV || false;
+    static final boolean DEBUG_CONFIGURATION = localLOGV || false;
+    static final boolean DEBUG_FOCUS = false;
+    static final boolean DEBUG_IMMERSIVE = localLOGV || false;
+    static final boolean DEBUG_MU = localLOGV || false;
+    static final boolean DEBUG_OOM_ADJ = localLOGV || false;
+    static final boolean DEBUG_PAUSE = localLOGV || false;
+    static final boolean DEBUG_POWER = localLOGV || false;
+    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
+    static final boolean DEBUG_PROCESS_OBSERVERS = localLOGV || false;
+    static final boolean DEBUG_PROCESSES = localLOGV || false;
+    static final boolean DEBUG_PROVIDER = localLOGV || false;
+    static final boolean DEBUG_RESULTS = localLOGV || false;
+    static final boolean DEBUG_SERVICE = localLOGV || false;
+    static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
+    static final boolean DEBUG_STACK = localLOGV || false;
     static final boolean DEBUG_SWITCH = localLOGV || false;
     static final boolean DEBUG_TASKS = localLOGV || false;
     static final boolean DEBUG_THUMBNAILS = localLOGV || false;
-    static final boolean DEBUG_PAUSE = localLOGV || false;
-    static final boolean DEBUG_OOM_ADJ = localLOGV || false;
     static final boolean DEBUG_TRANSITION = localLOGV || false;
-    static final boolean DEBUG_BROADCAST = localLOGV || false;
-    static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
-    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
-    static final boolean DEBUG_SERVICE = localLOGV || false;
-    static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
-    static final boolean DEBUG_VISBILITY = localLOGV || false;
-    static final boolean DEBUG_PROCESSES = localLOGV || false;
-    static final boolean DEBUG_PROCESS_OBSERVERS = localLOGV || false;
-    static final boolean DEBUG_CLEANUP = localLOGV || false;
-    static final boolean DEBUG_PROVIDER = localLOGV || false;
     static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
     static final boolean DEBUG_USER_LEAVING = localLOGV || false;
-    static final boolean DEBUG_RESULTS = localLOGV || false;
-    static final boolean DEBUG_BACKUP = localLOGV || false;
-    static final boolean DEBUG_CONFIGURATION = localLOGV || false;
-    static final boolean DEBUG_POWER = localLOGV || false;
-    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
-    static final boolean DEBUG_MU = localLOGV || false;
-    static final boolean DEBUG_IMMERSIVE = localLOGV || false;
-    static final boolean VALIDATE_TOKENS = false;
+    static final boolean DEBUG_VISBILITY = localLOGV || false;
+    static final boolean DEBUG_PSS = localLOGV || false;
+    static final boolean DEBUG_LOCKSCREEN = localLOGV || false;
+    static final boolean VALIDATE_TOKENS = true;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
-    
+
     // Control over CPU and battery monitoring.
     static final long BATTERY_STATS_TIME = 30*60*1000;      // write battery stats every 30 minutes.
     static final boolean MONITOR_CPU_USAGE = true;
@@ -210,14 +248,14 @@
 
     // The flags that are set for all calls we make to the package manager.
     static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
-    
+
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
     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 = 20;
-    
+
     // Amount of time after a call to stopAppSwitches() during which we will
     // prevent further untrusted switches from happening.
     static final long APP_SWITCH_DELAY_TIME = 5*1000;
@@ -238,6 +276,13 @@
     // The minimum amount of time between successive GC requests for a process.
     static final int GC_MIN_INTERVAL = 60*1000;
 
+    // The minimum amount of time between successive PSS requests for a process.
+    static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
+
+    // The minimum amount of time between successive PSS requests for a process
+    // when the request is due to the memory state being lowered.
+    static final int FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
+
     // The rate at which we check for apps using excessive power -- 15 mins.
     static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
 
@@ -266,14 +311,19 @@
     // Maximum number of users we allow to be running at a time.
     static final int MAX_RUNNING_USERS = 3;
 
-    // How long to wait in getTopActivityExtras for the activity to respond with the result.
-    static final int PENDING_ACTIVITY_RESULT_TIMEOUT = 2*2000;
+    // How long to wait in getAssistContextExtras for the activity and foreground services
+    // to respond with the result.
+    static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
+
+    // Maximum number of persisted Uri grants a package is allowed
+    static final int MAX_PERSISTED_URI_GRANTS = 128;
 
     static final int MY_PID = Process.myPid();
-    
+
     static final String[] EMPTY_STRING_ARRAY = new String[0];
 
-    public ActivityStack mMainStack;
+    /** Run all ActivityStacks through this */
+    ActivityStackSupervisor mStackSupervisor;
 
     public IntentFirewall mIntentFirewall;
 
@@ -289,14 +339,22 @@
      * due to app switches being disabled.
      */
     static class PendingActivityLaunch {
-        ActivityRecord r;
-        ActivityRecord sourceRecord;
-        int startFlags;
+        final ActivityRecord r;
+        final ActivityRecord sourceRecord;
+        final int startFlags;
+        final ActivityStack stack;
+
+        PendingActivityLaunch(ActivityRecord _r, ActivityRecord _sourceRecord,
+                int _startFlags, ActivityStack _stack) {
+            r = _r;
+            sourceRecord = _sourceRecord;
+            startFlags = _startFlags;
+            stack = _stack;
+        }
     }
-    
+
     final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
             = new ArrayList<PendingActivityLaunch>();
-    
 
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
@@ -332,18 +390,18 @@
     /**
      * List of intents that were used to start the most recent tasks.
      */
-    final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
+    private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
 
-    public class PendingActivityExtras extends Binder implements Runnable {
+    public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
         public boolean haveResult = false;
         public Bundle result = null;
-        public PendingActivityExtras(ActivityRecord _activity) {
+        public PendingAssistExtras(ActivityRecord _activity) {
             activity = _activity;
         }
         @Override
         public void run() {
-            Slog.w(TAG, "getTopActivityExtras failed: timeout retrieving from " + activity);
+            Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity);
             synchronized (this) {
                 haveResult = true;
                 notifyAll();
@@ -351,8 +409,8 @@
         }
     }
 
-    final ArrayList<PendingActivityExtras> mPendingActivityExtras
-            = new ArrayList<PendingActivityExtras>();
+    final ArrayList<PendingAssistExtras> mPendingAssistExtras
+            = new ArrayList<PendingAssistExtras>();
 
     /**
      * Process management.
@@ -368,6 +426,12 @@
     final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
 
     /**
+     * Tracking long-term execution of processes to look for abuse and other
+     * bad app behavior.
+     */
+    final ProcessStatsService mProcessStats;
+
+    /**
      * The currently running isolated processes.
      */
     final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<ProcessRecord>();
@@ -382,7 +446,7 @@
      * The currently running heavy-weight process, if any.
      */
     ProcessRecord mHeavyWeightProcess = null;
-    
+
     /**
      * The last time that various processes have crashed.
      */
@@ -416,51 +480,64 @@
         int pid;
         IBinder token;
     }
-    final SparseArray<ForegroundToken> mForegroundProcesses
-            = new SparseArray<ForegroundToken>();
-    
+    final SparseArray<ForegroundToken> mForegroundProcesses = new SparseArray<ForegroundToken>();
+
     /**
      * List of records for processes that someone had tried to start before the
      * system was ready.  We don't start them at that point, but ensure they
      * are started by the time booting is complete.
      */
-    final ArrayList<ProcessRecord> mProcessesOnHold
-            = new ArrayList<ProcessRecord>();
+    final ArrayList<ProcessRecord> mProcessesOnHold = new ArrayList<ProcessRecord>();
 
     /**
      * List of persistent applications that are in the process
      * of being started.
      */
-    final ArrayList<ProcessRecord> mPersistentStartingProcesses
-            = new ArrayList<ProcessRecord>();
+    final ArrayList<ProcessRecord> mPersistentStartingProcesses = new ArrayList<ProcessRecord>();
 
     /**
      * Processes that are being forcibly torn down.
      */
-    final ArrayList<ProcessRecord> mRemovedProcesses
-            = new ArrayList<ProcessRecord>();
+    final ArrayList<ProcessRecord> mRemovedProcesses = new ArrayList<ProcessRecord>();
 
     /**
      * List of running applications, sorted by recent usage.
      * The first entry in the list is the least recently used.
-     * It contains ApplicationRecord objects.  This list does NOT include
-     * any persistent application records (since we never want to exit them).
      */
-    final ArrayList<ProcessRecord> mLruProcesses
-            = new ArrayList<ProcessRecord>();
+    final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();
+
+    /**
+     * Where in mLruProcesses that the processes hosting activities start.
+     */
+    int mLruProcessActivityStart = 0;
+
+    /**
+     * Where in mLruProcesses that the processes hosting services start.
+     * This is after (lower index) than mLruProcessesActivityStart.
+     */
+    int mLruProcessServiceStart = 0;
 
     /**
      * List of processes that should gc as soon as things are idle.
      */
-    final ArrayList<ProcessRecord> mProcessesToGc
-            = new ArrayList<ProcessRecord>();
+    final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
+
+    /**
+     * Processes we want to collect PSS data from.
+     */
+    final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
+
+    /**
+     * Last time we requested PSS data of all processes.
+     */
+    long mLastFullPssTime = SystemClock.uptimeMillis();
 
     /**
      * This is the process holding what we currently consider to be
      * the "home" activity.
      */
     ProcessRecord mHomeProcess;
-    
+
     /**
      * This is the process holding the activity the user last visited that
      * is in a different process from the one they are currently in.
@@ -505,11 +582,6 @@
     final CompatModePackages mCompatModePackages;
 
     /**
-     * Set of PendingResultRecord objects that are currently active.
-     */
-    final HashSet mPendingResultRecords = new HashSet();
-
-    /**
      * Set of IntentSenderRecord objects that are currently active.
      */
     final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
@@ -538,7 +610,8 @@
      * broadcasts.  Hash keys are the receiver IBinder, hash value is
      * a ReceiverList.
      */
-    final HashMap mRegisteredReceivers = new HashMap();
+    final HashMap<IBinder, ReceiverList> mRegisteredReceivers =
+            new HashMap<IBinder, ReceiverList>();
 
     /**
      * Resolver for broadcast intents to registered receivers.
@@ -585,8 +658,8 @@
      * by the user ID the sticky is for, and can include UserHandle.USER_ALL
      * for stickies that are sent to all users.
      */
-    final SparseArray<HashMap<String, ArrayList<Intent>>> mStickyBroadcasts =
-            new SparseArray<HashMap<String, ArrayList<Intent>>>();
+    final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
+            new SparseArray<ArrayMap<String, ArrayList<Intent>>>();
 
     final ActiveServices mServices;
 
@@ -600,13 +673,8 @@
      * List of PendingThumbnailsRecord objects of clients who are still
      * waiting to receive all of the thumbnails for a task.
      */
-    final ArrayList mPendingThumbnails = new ArrayList();
-
-    /**
-     * List of HistoryRecord objects that have been finished and must
-     * still report back to a pending thumbnail receiver.
-     */
-    final ArrayList mCancelledThumbnails = new ArrayList();
+    final ArrayList<PendingThumbnailsRecord> mPendingThumbnails =
+            new ArrayList<PendingThumbnailsRecord>();
 
     final ProviderMap mProviderMap;
 
@@ -619,10 +687,28 @@
             = new ArrayList<ContentProviderRecord>();
 
     /**
-     * Global set of specific Uri permissions that have been granted.
+     * File storing persisted {@link #mGrantedUriPermissions}.
      */
-    final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
-            = new SparseArray<HashMap<Uri, UriPermission>>();
+    private final AtomicFile mGrantFile;
+
+    /** XML constants used in {@link #mGrantFile} */
+    private static final String TAG_URI_GRANTS = "uri-grants";
+    private static final String TAG_URI_GRANT = "uri-grant";
+    private static final String ATTR_USER_HANDLE = "userHandle";
+    private static final String ATTR_SOURCE_PKG = "sourcePkg";
+    private static final String ATTR_TARGET_PKG = "targetPkg";
+    private static final String ATTR_URI = "uri";
+    private static final String ATTR_MODE_FLAGS = "modeFlags";
+    private static final String ATTR_CREATED_TIME = "createdTime";
+
+    /**
+     * Global set of specific {@link Uri} permissions that have been granted.
+     * This optimized lookup structure maps from {@link UriPermission#targetUid}
+     * to {@link UriPermission#uri} to {@link UriPermission}.
+     */
+    @GuardedBy("this")
+    private final SparseArray<ArrayMap<Uri, UriPermission>>
+            mGrantedUriPermissions = new SparseArray<ArrayMap<Uri, UriPermission>>();
 
     CoreSettingsObserver mCoreSettingsObserver;
 
@@ -647,12 +733,12 @@
      * any user id that can impact battery performance.
      */
     final BatteryStatsService mBatteryStatsService;
-    
+
     /**
      * Information about component usage
      */
     final UsageStatsService mUsageStatsService;
-    
+
     /**
      * Information about and control over application operations
      */
@@ -670,7 +756,7 @@
      * configurations.
      */
     int mConfigurationSeq = 0;
-    
+
     /**
      * Hardware-reported OpenGLES version.
      */
@@ -686,7 +772,7 @@
      * Temporary to avoid allocations.  Protected by main lock.
      */
     final StringBuilder mStringBuilder = new StringBuilder(256);
-    
+
     /**
      * Used to control how we initialize the service.
      */
@@ -707,7 +793,7 @@
     int mFactoryTest;
 
     boolean mCheckedForSetup;
-    
+
     /**
      * The time at which we will allow normal application switches again,
      * after a call to {@link #stopAppSwitches()}.
@@ -719,7 +805,7 @@
      * is set; any switches after that will clear the time.
      */
     boolean mDidAppSwitch;
-    
+
     /**
      * Last time (in realtime) at which we checked for power usage.
      */
@@ -752,14 +838,6 @@
     boolean mShuttingDown = false;
 
     /**
-     * Task identifier that activities are currently being started
-     * in.  Incremented each time a new task is created.
-     * todo: Replace this with a TokenSpace class that generates non-repeating
-     * integers that won't wrap.
-     */
-    int mCurTask = 1;
-
-    /**
      * Current sequence id for oom_adj computation traversal.
      */
     int mAdjSeq = 0;
@@ -770,36 +848,66 @@
     int mLruSeq = 0;
 
     /**
-     * Keep track of the non-hidden/empty process we last found, to help
-     * determine how to distribute hidden/empty processes next time.
+     * Keep track of the non-cached/empty process we last found, to help
+     * determine how to distribute cached/empty processes next time.
      */
-    int mNumNonHiddenProcs = 0;
+    int mNumNonCachedProcs = 0;
 
     /**
-     * Keep track of the number of hidden procs, to balance oom adj
+     * Keep track of the number of cached hidden procs, to balance oom adj
      * distribution between those and empty procs.
      */
-    int mNumHiddenProcs = 0;
+    int mNumCachedHiddenProcs = 0;
 
     /**
      * Keep track of the number of service processes we last found, to
      * determine on the next iteration which should be B services.
      */
     int mNumServiceProcs = 0;
+    int mNewNumAServiceProcs = 0;
     int mNewNumServiceProcs = 0;
 
     /**
-     * System monitoring: number of processes that died since the last
-     * N procs were started.
+     * Allow the current computed overall memory level of the system to go down?
+     * This is set to false when we are killing processes for reasons other than
+     * memory management, so that the now smaller process list will not be taken as
+     * an indication that memory is tighter.
      */
-    int[] mProcDeaths = new int[20];
-    
+    boolean mAllowLowerMemLevel = false;
+
+    /**
+     * The last computed memory level, for holding when we are in a state that
+     * processes are going away for other reasons.
+     */
+    int mLastMemoryLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+
+    /**
+     * The last total number of process we have, to determine if changes actually look
+     * like a shrinking number of process due to lower RAM.
+     */
+    int mLastNumProcesses;
+
+    /**
+     * The uptime of the last time we performed idle maintenance.
+     */
+    long mLastIdleTime = SystemClock.uptimeMillis();
+
+    /**
+     * Total time spent with RAM that has been added in the past since the last idle time.
+     */
+    long mLowRamTimeSinceLastIdle = 0;
+
+    /**
+     * If RAM is currently low, when that horrible situatin started.
+     */
+    long mLowRamStartTime = 0;
+
     /**
      * This is set if we had to do a delayed dexopt of an app before launching
      * it, to increasing the ANR timeouts in that case.
      */
     boolean mDidDexOpt;
-    
+
     String mDebugApp = null;
     boolean mWaitForDebugger = false;
     boolean mDebugTransient = false;
@@ -835,19 +943,19 @@
             = new ArrayList<ProcessChangeItem>();
 
     /**
-     * Runtime statistics collection thread.  This object's lock is used to
+     * Runtime CPU use collection thread.  This object's lock is used to
      * protect all related state.
      */
-    final Thread mProcessStatsThread;
-    
+    final Thread mProcessCpuThread;
+
     /**
      * Used to collect process stats when showing not responding dialog.
-     * Protected by mProcessStatsThread.
+     * Protected by mProcessCpuThread.
      */
-    final ProcessStats mProcessStats = new ProcessStats(
+    final ProcessCpuTracker mProcessCpuTracker = new ProcessCpuTracker(
             MONITOR_THREAD_CPU_USAGE);
     final AtomicLong mLastCpuTime = new AtomicLong(0);
-    final AtomicBoolean mProcessStatsMutexFree = new AtomicBoolean(true);
+    final AtomicBoolean mProcessCpuMutexFree = new AtomicBoolean(true);
 
     long mLastWriteTime = 0;
 
@@ -862,7 +970,7 @@
      */
     boolean mBooted = false;
 
-    int mProcessLimit = ProcessList.MAX_HIDDEN_APPS;
+    int mProcessLimit = ProcessList.MAX_CACHED_APPS;
     int mProcessLimitOverride = -1;
 
     WindowManagerService mWindowManager;
@@ -870,8 +978,7 @@
     static ActivityManagerService mSelf;
     static ActivityThread mSystemThread;
 
-    private int mCurrentUserId = 0;
-    private int[] mCurrentUserArray = new int[] { 0 };
+    int mCurrentUserId = 0;
     private UserManagerService mUserManager;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -889,6 +996,7 @@
             mAppThread = thread;
         }
 
+        @Override
         public void binderDied() {
             if (localLOGV) Slog.v(
                 TAG, "Death received in " + this
@@ -917,20 +1025,23 @@
     static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
     static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
     static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
-    static final int CLEAR_DNS_CACHE = 28;
-    static final int UPDATE_HTTP_PROXY = 29;
+    static final int CLEAR_DNS_CACHE_MSG = 28;
+    static final int UPDATE_HTTP_PROXY_MSG = 29;
     static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30;
     static final int DISPATCH_PROCESSES_CHANGED = 31;
     static final int DISPATCH_PROCESS_DIED = 32;
-    static final int REPORT_MEM_USAGE = 33;
+    static final int REPORT_MEM_USAGE_MSG = 33;
     static final int REPORT_USER_SWITCH_MSG = 34;
     static final int CONTINUE_USER_SWITCH_MSG = 35;
     static final int USER_SWITCH_TIMEOUT_MSG = 36;
     static final int IMMERSIVE_MODE_LOCK_MSG = 37;
+    static final int PERSIST_URI_GRANTS_MSG = 38;
+    static final int REQUEST_ALL_PSS_MSG = 39;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
     static final int FIRST_COMPAT_MODE_MSG = 300;
+    static final int FIRST_SUPERVISOR_STACK_MSG = 100;
 
     AlertDialog mUidAlert;
     CompatModeDialog mCompatModeDialog;
@@ -947,10 +1058,11 @@
         //    if (localLOGV) Slog.v(TAG, "Handler started!");
         //}
 
+        @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case SHOW_ERROR_MSG: {
-                HashMap data = (HashMap) msg.obj;
+                HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
                 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                         Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
                 synchronized (ActivityManagerService.this) {
@@ -985,18 +1097,18 @@
                         }
                     }
                 }
-                
+
                 ensureBootCompleted();
             } break;
             case SHOW_NOT_RESPONDING_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    HashMap data = (HashMap) msg.obj;
+                    HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
                     ProcessRecord proc = (ProcessRecord)data.get("app");
                     if (proc != null && proc.anrDialog != null) {
                         Slog.e(TAG, "App already has anr dialog: " + proc);
                         return;
                     }
-                    
+
                     Intent intent = new Intent("android.intent.action.ANR");
                     if (!mProcessesReady) {
                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -1017,7 +1129,7 @@
                         killAppAtUsersRequest(proc, null);
                     }
                 }
-                
+
                 ensureBootCompleted();
             } break;
             case SHOW_STRICT_MODE_VIOLATION_MSG: {
@@ -1105,7 +1217,7 @@
                     }
                 }
             } break;
-            case CLEAR_DNS_CACHE: {
+            case CLEAR_DNS_CACHE_MSG: {
                 synchronized (ActivityManagerService.this) {
                     for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                         ProcessRecord r = mLruProcesses.get(i);
@@ -1119,22 +1231,24 @@
                     }
                 }
             } break;
-            case UPDATE_HTTP_PROXY: {
+            case UPDATE_HTTP_PROXY_MSG: {
                 ProxyProperties proxy = (ProxyProperties)msg.obj;
                 String host = "";
                 String port = "";
                 String exclList = "";
+                String pacFileUrl = null;
                 if (proxy != null) {
                     host = proxy.getHost();
                     port = Integer.toString(proxy.getPort());
                     exclList = proxy.getExclusionList();
+                    pacFileUrl = proxy.getPacFileUrl();
                 }
                 synchronized (ActivityManagerService.this) {
                     for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                         ProcessRecord r = mLruProcesses.get(i);
                         if (r.thread != null) {
                             try {
-                                r.thread.setHttpProxy(host, port, exclList);
+                                r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
                             } catch (RemoteException ex) {
                                 Slog.w(TAG, "Failed to update http proxy for: " +
                                         r.info.processName);
@@ -1189,9 +1303,11 @@
                 synchronized (ActivityManagerService.this) {
                     int appid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
-                    String pkg = (String) msg.obj;
+                    Bundle bundle = (Bundle)msg.obj;
+                    String pkg = bundle.getString("pkg");
+                    String reason = bundle.getString("reason");
                     forceStopPackageLocked(pkg, appid, restart, false, true, false,
-                            UserHandle.USER_ALL);
+                            UserHandle.USER_ALL, reason);
                 }
             } break;
             case FINALIZE_PENDING_INTENT_MSG: {
@@ -1202,13 +1318,13 @@
                 if (inm == null) {
                     return;
                 }
-                
+
                 ActivityRecord root = (ActivityRecord)msg.obj;
                 ProcessRecord process = root.app;
                 if (process == null) {
                     return;
                 }
-                
+
                 try {
                     Context context = mContext.createPackageContext(process.info.packageName, 0);
                     String text = mContext.getString(R.string.heavy_weight_notification,
@@ -1226,7 +1342,7 @@
                             PendingIntent.getActivityAsUser(mContext, 0, root.intent,
                                     PendingIntent.FLAG_CANCEL_CURRENT, null,
                                     new UserHandle(root.userId)));
-                    
+
                     try {
                         int[] outId = new int[1];
                         inm.enqueueNotificationWithTag("android", "android", null,
@@ -1301,64 +1417,176 @@
                 dispatchProcessDied(pid, uid);
                 break;
             }
-            case REPORT_MEM_USAGE: {
-                boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
-                if (!isDebuggable) {
-                    return;
-                }
-                synchronized (ActivityManagerService.this) {
-                    long now = SystemClock.uptimeMillis();
-                    if (now < (mLastMemUsageReportTime+5*60*1000)) {
-                        // Don't report more than every 5 minutes to somewhat
-                        // avoid spamming.
-                        return;
-                    }
-                    mLastMemUsageReportTime = now;
-                }
+            case REPORT_MEM_USAGE_MSG: {
+                final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
                 Thread thread = new Thread() {
                     @Override public void run() {
-                        StringBuilder dropBuilder = new StringBuilder(1024);
-                        StringBuilder logBuilder = new StringBuilder(1024);
-                        StringWriter oomSw = new StringWriter();
-                        PrintWriter oomPw = new PrintWriter(oomSw);
-                        StringWriter catSw = new StringWriter();
-                        PrintWriter catPw = new PrintWriter(catSw);
-                        String[] emptyArgs = new String[] { };
+                        final SparseArray<ProcessMemInfo> infoMap
+                                = new SparseArray<ProcessMemInfo>(memInfos.size());
+                        for (int i=0, N=memInfos.size(); i<N; i++) {
+                            ProcessMemInfo mi = memInfos.get(i);
+                            infoMap.put(mi.pid, mi);
+                        }
+                        updateCpuStatsNow();
+                        synchronized (mProcessCpuThread) {
+                            final int N = mProcessCpuTracker.countStats();
+                            for (int i=0; i<N; i++) {
+                                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                                if (st.vsize > 0) {
+                                    long pss = Debug.getPss(st.pid, null);
+                                    if (pss > 0) {
+                                        if (infoMap.indexOfKey(st.pid) < 0) {
+                                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+                                                    ProcessList.NATIVE_ADJ, -1, "native", null);
+                                            mi.pss = pss;
+                                            memInfos.add(mi);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                        long totalPss = 0;
+                        for (int i=0, N=memInfos.size(); i<N; i++) {
+                            ProcessMemInfo mi = memInfos.get(i);
+                            if (mi.pss == 0) {
+                                mi.pss = Debug.getPss(mi.pid, null);
+                            }
+                            totalPss += mi.pss;
+                        }
+                        Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+                            @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+                                if (lhs.oomAdj != rhs.oomAdj) {
+                                    return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+                                }
+                                if (lhs.pss != rhs.pss) {
+                                    return lhs.pss < rhs.pss ? 1 : -1;
+                                }
+                                return 0;
+                            }
+                        });
+
                         StringBuilder tag = new StringBuilder(128);
                         StringBuilder stack = new StringBuilder(128);
                         tag.append("Low on memory -- ");
-                        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw,
-                                tag, stack);
+                        appendMemBucket(tag, totalPss, "total", false);
+                        appendMemBucket(stack, totalPss, "total", true);
+
+                        StringBuilder logBuilder = new StringBuilder(1024);
+                        logBuilder.append("Low on memory:\n");
+
+                        boolean firstLine = true;
+                        int lastOomAdj = Integer.MIN_VALUE;
+                        for (int i=0, N=memInfos.size(); i<N; i++) {
+                            ProcessMemInfo mi = memInfos.get(i);
+
+                            if (mi.oomAdj != ProcessList.NATIVE_ADJ
+                                    && (mi.oomAdj < ProcessList.SERVICE_ADJ
+                                            || mi.oomAdj == ProcessList.HOME_APP_ADJ
+                                            || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+                                if (lastOomAdj != mi.oomAdj) {
+                                    lastOomAdj = mi.oomAdj;
+                                    if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                                        tag.append(" / ");
+                                    }
+                                    if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+                                        if (firstLine) {
+                                            stack.append(":");
+                                            firstLine = false;
+                                        }
+                                        stack.append("\n\t at ");
+                                    } else {
+                                        stack.append("$");
+                                    }
+                                } else {
+                                    tag.append(" ");
+                                    stack.append("$");
+                                }
+                                if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                                    appendMemBucket(tag, mi.pss, mi.name, false);
+                                }
+                                appendMemBucket(stack, mi.pss, mi.name, true);
+                                if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+                                        && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+                                    stack.append("(");
+                                    for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+                                        if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+                                            stack.append(DUMP_MEM_OOM_LABEL[k]);
+                                            stack.append(":");
+                                            stack.append(DUMP_MEM_OOM_ADJ[k]);
+                                        }
+                                    }
+                                    stack.append(")");
+                                }
+                            }
+
+                            logBuilder.append("  ");
+                            logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
+                            logBuilder.append(' ');
+                            logBuilder.append(ProcessList.makeProcStateString(mi.procState));
+                            logBuilder.append(' ');
+                            ProcessList.appendRamKb(logBuilder, mi.pss);
+                            logBuilder.append(" kB: ");
+                            logBuilder.append(mi.name);
+                            logBuilder.append(" (");
+                            logBuilder.append(mi.pid);
+                            logBuilder.append(") ");
+                            logBuilder.append(mi.adjType);
+                            logBuilder.append('\n');
+                            if (mi.adjReason != null) {
+                                logBuilder.append("                      ");
+                                logBuilder.append(mi.adjReason);
+                                logBuilder.append('\n');
+                            }
+                        }
+
+                        logBuilder.append("           ");
+                        ProcessList.appendRamKb(logBuilder, totalPss);
+                        logBuilder.append(" kB: TOTAL\n");
+
+                        long[] infos = new long[Debug.MEMINFO_COUNT];
+                        Debug.getMemInfo(infos);
+                        logBuilder.append("  MemInfo: ");
+                        logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+                        logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+                        logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+                        logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+                        logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+                        if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+                            logBuilder.append("  ZRAM: ");
+                            logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
+                            logBuilder.append(" kB RAM, ");
+                            logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
+                            logBuilder.append(" kB swap total, ");
+                            logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
+                            logBuilder.append(" kB swap free\n");
+                        }
+                        Slog.i(TAG, logBuilder.toString());
+
+                        StringBuilder dropBuilder = new StringBuilder(1024);
+                        /*
+                        StringWriter oomSw = new StringWriter();
+                        PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
+                        StringWriter catSw = new StringWriter();
+                        PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+                        String[] emptyArgs = new String[] { };
+                        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw);
+                        oomPw.flush();
+                        String oomString = oomSw.toString();
+                        */
                         dropBuilder.append(stack);
                         dropBuilder.append('\n');
                         dropBuilder.append('\n');
-                        String oomString = oomSw.toString();
+                        dropBuilder.append(logBuilder);
+                        dropBuilder.append('\n');
+                        /*
                         dropBuilder.append(oomString);
                         dropBuilder.append('\n');
-                        logBuilder.append(oomString);
-                        try {
-                            java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
-                                    "procrank", });
-                            final InputStreamReader converter = new InputStreamReader(
-                                    proc.getInputStream());
-                            BufferedReader in = new BufferedReader(converter);
-                            String line;
-                            while (true) {
-                                line = in.readLine();
-                                if (line == null) {
-                                    break;
-                                }
-                                if (line.length() > 0) {
-                                    logBuilder.append(line);
-                                    logBuilder.append('\n');
-                                }
-                                dropBuilder.append(line);
-                                dropBuilder.append('\n');
-                            }
-                            converter.close();
-                        } catch (IOException e) {
-                        }
+                        */
+                        StringWriter catSw = new StringWriter();
                         synchronized (ActivityManagerService.this) {
+                            PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+                            String[] emptyArgs = new String[] { };
                             catPw.println();
                             dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
                             catPw.println();
@@ -1366,11 +1594,13 @@
                                     false, false, null);
                             catPw.println();
                             dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+                            catPw.flush();
                         }
                         dropBuilder.append(catSw.toString());
                         addErrorToDropBox("lowmem", null, "system_server", null,
                                 null, tag.toString(), dropBuilder.toString(), null, null);
-                        Slog.i(TAG, logBuilder.toString());
+                        //Slog.i(TAG, "Sent to dropbox:");
+                        //Slog.i(TAG, dropBuilder.toString());
                         synchronized (ActivityManagerService.this) {
                             long now = SystemClock.uptimeMillis();
                             if (mLastMemUsageReportTime < now) {
@@ -1409,6 +1639,72 @@
                 }
                 break;
             }
+            case PERSIST_URI_GRANTS_MSG: {
+                writeGrantedUriPermissions();
+                break;
+            }
+            case REQUEST_ALL_PSS_MSG: {
+                requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+                break;
+            }
+            }
+        }
+    };
+
+    static final int COLLECT_PSS_BG_MSG = 1;
+
+    final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case COLLECT_PSS_BG_MSG: {
+                int i=0, num=0;
+                long start = SystemClock.uptimeMillis();
+                long[] tmp = new long[1];
+                do {
+                    ProcessRecord proc;
+                    int procState;
+                    int pid;
+                    synchronized (ActivityManagerService.this) {
+                        if (i >= mPendingPssProcesses.size()) {
+                            if (DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num + " of " + i
+                                    + " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
+                            mPendingPssProcesses.clear();
+                            return;
+                        }
+                        proc = mPendingPssProcesses.get(i);
+                        procState = proc.pssProcState;
+                        if (proc.thread != null && procState == proc.setProcState) {
+                            pid = proc.pid;
+                        } else {
+                            proc = null;
+                            pid = 0;
+                        }
+                        i++;
+                    }
+                    if (proc != null) {
+                        long pss = Debug.getPss(pid, tmp);
+                        synchronized (ActivityManagerService.this) {
+                            if (proc.thread != null && proc.setProcState == procState
+                                    && proc.pid == pid) {
+                                num++;
+                                proc.lastPssTime = SystemClock.uptimeMillis();
+                                proc.baseProcessTracker.addPss(pss, tmp[0], true, proc.pkgList);
+                                if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
+                                        + ": " + pss + " lastPss=" + proc.lastPss
+                                        + " state=" + ProcessList.makeProcStateString(procState));
+                                if (proc.initialIdlePss == 0) {
+                                    proc.initialIdlePss = pss;
+                                }
+                                proc.lastPss = pss;
+                                if (procState >= ActivityManager.PROCESS_STATE_HOME) {
+                                    proc.lastCachedPss = pss;
+                                }
+                            }
+                        }
+                    }
+                } while (true);
+            }
             }
         }
     };
@@ -1417,7 +1713,8 @@
         try {
             ActivityManagerService m = mSelf;
 
-            ServiceManager.addService("activity", m, true);
+            ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);
+            ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);
             ServiceManager.addService("meminfo", new MemBinder(m));
             ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
             ServiceManager.addService("dbinfo", new DbBinder(m));
@@ -1430,19 +1727,19 @@
                 mSelf.mContext.getPackageManager().getApplicationInfo(
                             "android", STOCK_PM_FLAGS);
             mSystemThread.installSystemApplicationInfo(info);
-       
+
             synchronized (mSelf) {
-                ProcessRecord app = mSelf.newProcessRecordLocked(
-                        mSystemThread.getApplicationThread(), info,
+                ProcessRecord app = mSelf.newProcessRecordLocked(info,
                         info.processName, false);
                 app.persistent = true;
                 app.pid = MY_PID;
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
+                app.makeActive(mSystemThread.getApplicationThread(), mSelf.mProcessStats);
                 mSelf.mProcessNames.put(app.processName, app.uid, app);
                 synchronized (mSelf.mPidsSelfLocked) {
                     mSelf.mPidsSelfLocked.put(app.pid, app);
                 }
-                mSelf.updateLruProcessLocked(app, true);
+                mSelf.updateLruProcessLocked(app, true, false);
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException(
@@ -1452,6 +1749,8 @@
 
     public void setWindowManager(WindowManagerService wm) {
         mWindowManager = wm;
+        mStackSupervisor.setWindowManager(wm);
+        wm.createStack(HOME_STACK_ID, -1, StackBox.TASK_STACK_GOES_OVER, 1.0f);
     }
 
     public void startObservingNativeCrashes() {
@@ -1480,9 +1779,10 @@
         context.setTheme(android.R.style.Theme_Holo);
         m.mContext = context;
         m.mFactoryTest = factoryTest;
-        m.mMainStack = new ActivityStack(m, context, true, thr.mLooper);
         m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface());
 
+        m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper);
+
         m.mBatteryStatsService.publish(context);
         m.mUsageStatsService.publish(context);
         m.mAppOpsService.publish(context);
@@ -1493,14 +1793,18 @@
         }
 
         m.startRunning(null, null, null, null);
-        
+
         return context;
     }
 
     public static ActivityManagerService self() {
         return mSelf;
     }
-    
+
+    public IAppOpsService getAppOpsService() {
+        return mAppOpsService;
+    }
+
     static class AThread extends Thread {
         ActivityManagerService mService;
         Looper mLooper;
@@ -1510,6 +1814,7 @@
             super("ActivityManager");
         }
 
+        @Override
         public void run() {
             Looper.prepare();
 
@@ -1522,6 +1827,7 @@
             synchronized (this) {
                 mService = m;
                 mLooper = Looper.myLooper();
+                Watchdog.getInstance().addThread(new Handler(mLooper), getName());
                 notifyAll();
             }
 
@@ -1559,8 +1865,7 @@
                 return;
             }
 
-            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args,
-                    false, null, null, null);
+            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
         }
     }
 
@@ -1620,9 +1925,9 @@
                 return;
             }
 
-            synchronized (mActivityManagerService.mProcessStatsThread) {
-                pw.print(mActivityManagerService.mProcessStats.printCurrentLoad());
-                pw.print(mActivityManagerService.mProcessStats.printCurrentState(
+            synchronized (mActivityManagerService.mProcessCpuThread) {
+                pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
+                pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
                         SystemClock.uptimeMillis()));
             }
         }
@@ -1630,9 +1935,9 @@
 
     private ActivityManagerService() {
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
-        
-        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
-        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+
+        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
+        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
 
@@ -1650,9 +1955,13 @@
                 : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
         mBatteryStatsService.getActiveStatistics().setCallback(this);
 
-        mUsageStatsService = new UsageStatsService(new File(
-                systemDir, "usagestats").toString());
+        mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
+
+        mUsageStatsService = new UsageStatsService(new File(systemDir, "usagestats").toString());
         mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"));
+
+        mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
+
         mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
 
         // User 0 is the first and only user that runs at boot.
@@ -1667,14 +1976,15 @@
         mConfiguration.setLocale(Locale.getDefault());
 
         mConfigurationSeq = mConfiguration.seq = 1;
-        mProcessStats.init();
-        
+        mProcessCpuTracker.init();
+
         mCompatModePackages = new CompatModePackages(this, systemDir);
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
 
-        mProcessStatsThread = new Thread("ProcessStats") {
+        mProcessCpuThread = new Thread("CpuTracker") {
+            @Override
             public void run() {
                 while (true) {
                     try {
@@ -1689,7 +1999,7 @@
                                     nextCpuDelay = nextWriteDelay;
                                 }
                                 if (nextCpuDelay > 0) {
-                                    mProcessStatsMutexFree.set(true);
+                                    mProcessCpuMutexFree.set(true);
                                     this.wait(nextCpuDelay);
                                 }
                             }
@@ -1702,7 +2012,7 @@
                 }
             }
         };
-        mProcessStatsThread.start();
+        mProcessCpuThread.start();
     }
 
     @Override
@@ -1712,7 +2022,9 @@
             // We need to tell all apps about the system property change.
             ArrayList<IBinder> procs = new ArrayList<IBinder>();
             synchronized(this) {
-                for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+                final int NP = mProcessNames.getMap().size();
+                for (int ip=0; ip<NP; ip++) {
+                    SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
                     final int NA = apps.size();
                     for (int ia=0; ia<NA; ia++) {
                         ProcessRecord app = apps.valueAt(ia);
@@ -1739,7 +2051,7 @@
             // The activity manager only throws security exceptions, so let's
             // log all others.
             if (!(e instanceof SecurityException)) {
-                Slog.e(TAG, "Activity Manager Crash", e);
+                Slog.wtf(TAG, "Activity Manager Crash", e);
             }
             throw e;
         }
@@ -1750,16 +2062,16 @@
         if (mLastCpuTime.get() >= now - MONITOR_CPU_MIN_TIME) {
             return;
         }
-        if (mProcessStatsMutexFree.compareAndSet(true, false)) {
-            synchronized (mProcessStatsThread) {
-                mProcessStatsThread.notify();
+        if (mProcessCpuMutexFree.compareAndSet(true, false)) {
+            synchronized (mProcessCpuThread) {
+                mProcessCpuThread.notify();
             }
         }
     }
 
     void updateCpuStatsNow() {
-        synchronized (mProcessStatsThread) {
-            mProcessStatsMutexFree.set(false);
+        synchronized (mProcessCpuThread) {
+            mProcessCpuMutexFree.set(false);
             final long now = SystemClock.uptimeMillis();
             boolean haveNewCpuStats = false;
 
@@ -1767,19 +2079,19 @@
                     mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) {
                 mLastCpuTime.set(now);
                 haveNewCpuStats = true;
-                mProcessStats.update();
-                //Slog.i(TAG, mProcessStats.printCurrentState());
+                mProcessCpuTracker.update();
+                //Slog.i(TAG, mProcessCpu.printCurrentState());
                 //Slog.i(TAG, "Total CPU usage: "
-                //        + mProcessStats.getTotalCpuPercent() + "%");
+                //        + mProcessCpu.getTotalCpuPercent() + "%");
 
                 // Slog the cpu usage if the property is set.
                 if ("true".equals(SystemProperties.get("events.cpu"))) {
-                    int user = mProcessStats.getLastUserTime();
-                    int system = mProcessStats.getLastSystemTime();
-                    int iowait = mProcessStats.getLastIoWaitTime();
-                    int irq = mProcessStats.getLastIrqTime();
-                    int softIrq = mProcessStats.getLastSoftIrqTime();
-                    int idle = mProcessStats.getLastIdleTime();
+                    int user = mProcessCpuTracker.getLastUserTime();
+                    int system = mProcessCpuTracker.getLastSystemTime();
+                    int iowait = mProcessCpuTracker.getLastIoWaitTime();
+                    int irq = mProcessCpuTracker.getLastIrqTime();
+                    int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
+                    int idle = mProcessCpuTracker.getLastIdleTime();
 
                     int total = user + system + iowait + irq + softIrq + idle;
                     if (total == 0) total = 1;
@@ -1793,8 +2105,8 @@
                             (softIrq * 100) / total);
                 }
             }
-            
-            long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
+
+            long[] cpuSpeedTimes = mProcessCpuTracker.getLastCpuSpeedTimes();
             final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
             synchronized(bstats) {
                 synchronized(mPidsSelfLocked) {
@@ -1803,9 +2115,9 @@
                             int perc = bstats.startAddingCpuLocked();
                             int totalUTime = 0;
                             int totalSTime = 0;
-                            final int N = mProcessStats.countStats();
+                            final int N = mProcessCpuTracker.countStats();
                             for (int i=0; i<N; i++) {
-                                ProcessStats.Stats st = mProcessStats.getStats(i);
+                                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
                                 if (!st.working) {
                                     continue;
                                 }
@@ -1820,6 +2132,15 @@
                                             st.rel_stime-otherSTime);
                                     ps.addSpeedStepTimes(cpuSpeedTimes);
                                     pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
+                                } else if (st.uid >= Process.FIRST_APPLICATION_UID) {
+                                    BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
+                                    if (ps == null) {
+                                        st.batteryStats = ps = bstats.getProcessStatsLocked(st.uid,
+                                                "(Unknown)");
+                                    }
+                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
+                                            st.rel_stime-otherSTime);
+                                    ps.addSpeedStepTimes(cpuSpeedTimes);
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps =
                                             bstats.getProcessStatsLocked(st.name, st.pid);
@@ -1843,7 +2164,7 @@
             }
         }
     }
-    
+
     @Override
     public void batteryNeedsCpuUpdate() {
         updateCpuStatsNow();
@@ -1881,7 +2202,9 @@
 
     final void setFocusedActivityLocked(ActivityRecord r) {
         if (mFocusedActivity != r) {
+            if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r);
             mFocusedActivity = r;
+            mStackSupervisor.setFocusedStack(r);
             if (r != null) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
@@ -1889,6 +2212,31 @@
         }
     }
 
+    @Override
+    public void setFocusedStack(int stackId) {
+        if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: stackId=" + stackId);
+        synchronized (ActivityManagerService.this) {
+            ActivityStack stack = mStackSupervisor.getStack(stackId);
+            if (stack != null) {
+                ActivityRecord r = stack.topRunningActivityLocked(null);
+                if (r != null) {
+                    setFocusedActivityLocked(r);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void notifyActivityDrawn(IBinder token) {
+        if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
+        synchronized (this) {
+            ActivityRecord r= mStackSupervisor.isInAnyStackLocked(token);
+            if (r != null) {
+                r.task.stack.notifyActivityDrawnLocked(r);
+            }
+        }
+    }
+
     final void applyUpdateLockStateLocked(ActivityRecord r) {
         // Modifications to the UpdateLock state are done on our handler, outside
         // the activity manager's locks.  The new state is determined based on the
@@ -1899,77 +2247,124 @@
                 mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
     }
 
-    private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) {
-        // put it on the LRU to keep track of when it should be exited.
-        int lrui = mLruProcesses.indexOf(app);
-        if (lrui >= 0) mLruProcesses.remove(lrui);
-        
-        int i = mLruProcesses.size()-1;
-        int skipTop = 0;
-        
-        app.lruSeq = mLruSeq;
-        
-        // compute the new weight for this process.
-        app.lastActivityTime = SystemClock.uptimeMillis();
+    final void showAskCompatModeDialogLocked(ActivityRecord r) {
+        Message msg = Message.obtain();
+        msg.what = SHOW_COMPAT_MODE_DIALOG_MSG;
+        msg.obj = r.task.askedCompatMode ? null : r;
+        mHandler.sendMessage(msg);
+    }
+
+    private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
+            String what, Object obj, ProcessRecord srcApp) {
+        app.lastActivityTime = now;
+
         if (app.activities.size() > 0) {
-            // If this process has activities, we more strongly want to keep
-            // it around.
-            app.lruWeight = app.lastActivityTime;
-        } else if (app.pubProviders.size() > 0) {
-            // If this process contains content providers, we want to keep
-            // it a little more strongly.
-            app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;
-            // Also don't let it kick out the first few "real" hidden processes.
-            skipTop = ProcessList.MIN_HIDDEN_APPS;
-        } else {
-            // If this process doesn't have activities, we less strongly
-            // want to keep it around, and generally want to avoid getting
-            // in front of any very recently used activities.
-            app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;
-            // Also don't let it kick out the first few "real" hidden processes.
-            skipTop = ProcessList.MIN_HIDDEN_APPS;
+            // Don't want to touch dependent processes that are hosting activities.
+            return index;
         }
 
-        while (i >= 0) {
-            ProcessRecord p = mLruProcesses.get(i);
-            // If this app shouldn't be in front of the first N background
-            // apps, then skip over that many that are currently hidden.
-            if (skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
-                skipTop--;
-            }
-            if (p.lruWeight <= app.lruWeight || i < bestPos) {
-                mLruProcesses.add(i+1, app);
-                break;
-            }
-            i--;
+        int lrui = mLruProcesses.lastIndexOf(app);
+        if (lrui < 0) {
+            Log.wtf(TAG, "Adding dependent process " + app + " not on LRU list: "
+                    + what + " " + obj + " from " + srcApp);
+            return index;
         }
-        if (i < 0) {
-            mLruProcesses.add(0, app);
+
+        if (lrui >= index) {
+            // Don't want to cause this to move dependent processes *back* in the
+            // list as if they were less frequently used.
+            return index;
         }
-        
+
+        if (lrui >= mLruProcessActivityStart) {
+            // Don't want to touch dependent processes that are hosting activities.
+            return index;
+        }
+
+        mLruProcesses.remove(lrui);
+        if (index > 0) {
+            index--;
+        }
+        mLruProcesses.add(index, app);
+        return index;
+    }
+
+    final void removeLruProcessLocked(ProcessRecord app) {
+        int lrui = mLruProcesses.lastIndexOf(app);
+        if (lrui >= 0) {
+            if (lrui <= mLruProcessActivityStart) {
+                mLruProcessActivityStart--;
+            }
+            if (lrui <= mLruProcessServiceStart) {
+                mLruProcessServiceStart--;
+            }
+            mLruProcesses.remove(lrui);
+        }
+    }
+
+    final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj, boolean activityChange) {
+        final boolean hasActivity = app.activities.size() > 0;
+        final boolean hasService = false; // not impl yet. app.services.size() > 0;
+        if (!activityChange && hasActivity) {
+            // The process has activties, so we are only going to allow activity-based
+            // adjustments move it.  It should be kept in the front of the list with other
+            // processes that have activities, and we don't want those to change their
+            // order except due to activity operations.
+            return;
+        }
+
+        mLruSeq++;
+        final long now = SystemClock.uptimeMillis();
+        app.lastActivityTime = now;
+
+        int lrui = mLruProcesses.lastIndexOf(app);
+
+        if (lrui >= 0) {
+            if (lrui < mLruProcessActivityStart) {
+                mLruProcessActivityStart--;
+            }
+            if (lrui < mLruProcessServiceStart) {
+                mLruProcessServiceStart--;
+            }
+            mLruProcesses.remove(lrui);
+        }
+
+        int nextIndex;
+        if (hasActivity) {
+            // Process has activities, put it at the very tipsy-top.
+            mLruProcesses.add(app);
+            nextIndex = mLruProcessActivityStart;
+        } else if (hasService) {
+            // Process has services, put it at the top of the service list.
+            mLruProcesses.add(mLruProcessActivityStart, app);
+            nextIndex = mLruProcessServiceStart;
+            mLruProcessActivityStart++;
+        } else  {
+            // Process not otherwise of interest, it goes to the top of the non-service area.
+            mLruProcesses.add(mLruProcessServiceStart, app);
+            nextIndex = mLruProcessServiceStart-1;
+            mLruProcessActivityStart++;
+            mLruProcessServiceStart++;
+        }
+
         // If the app is currently using a content provider or service,
         // bump those processes as well.
-        if (app.connections.size() > 0) {
-            for (ConnectionRecord cr : app.connections) {
-                if (cr.binding != null && cr.binding.service != null
-                        && cr.binding.service.app != null
-                        && cr.binding.service.app.lruSeq != mLruSeq) {
-                    updateLruProcessInternalLocked(cr.binding.service.app, i+1);
-                }
+        for (int j=app.connections.size()-1; j>=0; j--) {
+            ConnectionRecord cr = app.connections.valueAt(j);
+            if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
+                    && cr.binding.service.app != null
+                    && cr.binding.service.app.lruSeq != mLruSeq) {
+                nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
+                        "service connection", cr, app);
             }
         }
         for (int j=app.conProviders.size()-1; j>=0; j--) {
             ContentProviderRecord cpr = app.conProviders.get(j).provider;
             if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
-                updateLruProcessInternalLocked(cpr.proc, i+1);
+                nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
+                        "provider reference", cpr, app);
             }
         }
-    }
-
-    final void updateLruProcessLocked(ProcessRecord app,
-            boolean oomAdj) {
-        mLruSeq++;
-        updateLruProcessInternalLocked(app, 0);
 
         //Slog.i(TAG, "Putting proc to front: " + app.processName);
         if (oomAdj) {
@@ -1977,14 +2372,12 @@
         }
     }
 
-    final ProcessRecord getProcessRecordLocked(
-            String processName, int uid) {
+    final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
         if (uid == Process.SYSTEM_UID) {
             // The system gets to run in any process.  If there are multiple
             // processes with the same uid, just pick the first (this
             // should never happen).
-            SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
-                    processName);
+            SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
             if (procs == null) return null;
             final int N = procs.size();
             for (int i = 0; i < N; i++) {
@@ -1992,6 +2385,27 @@
             }
         }
         ProcessRecord proc = mProcessNames.get(processName, uid);
+        if (false && proc != null && !keepIfLarge
+                && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
+                && proc.lastCachedPss >= 4000) {
+            // Turn this condition on to cause killing to happen regularly, for testing.
+            if (proc.baseProcessTracker != null) {
+                proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+            }
+            killUnneededProcessLocked(proc, Long.toString(proc.lastCachedPss)
+                    + "k from cached");
+        } else if (proc != null && !keepIfLarge
+                && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+                && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
+            if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
+            if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
+                if (proc.baseProcessTracker != null) {
+                    proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+                }
+                killUnneededProcessLocked(proc, Long.toString(proc.lastCachedPss)
+                        + "k from cached");
+            }
+        }
         return proc;
     }
 
@@ -2004,21 +2418,21 @@
         } catch (RemoteException e) {
         }
     }
-    
+
     boolean isNextTransitionForward() {
         int transit = mWindowManager.getPendingAppTransition();
         return transit == AppTransition.TRANSIT_ACTIVITY_OPEN
                 || transit == AppTransition.TRANSIT_TASK_OPEN
                 || transit == AppTransition.TRANSIT_TASK_TO_FRONT;
     }
-    
+
     final ProcessRecord startProcessLocked(String processName,
             ApplicationInfo info, boolean knownToBeDead, int intentFlags,
             String hostingType, ComponentName hostingName, boolean allowWhileBooting,
-            boolean isolated) {
+            boolean isolated, boolean keepIfLarge) {
         ProcessRecord app;
         if (!isolated) {
-            app = getProcessRecordLocked(processName, info.uid);
+            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
         } else {
             // If this is an isolated process, it can't re-use an existing process.
             app = null;
@@ -2039,14 +2453,14 @@
                 // come up (we have a pid but not yet its thread), so keep it.
                 if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
                 // If this is a new package in the process, add the package to the list
-                app.addPackage(info.packageName);
+                app.addPackage(info.packageName, mProcessStats);
                 return app;
-            } else {
-                // An application record is attached to a previous process,
-                // clean it up now.
-                if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app);
-                handleAppDiedLocked(app, true, true);
             }
+
+            // An application record is attached to a previous process,
+            // clean it up now.
+            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app);
+            handleAppDiedLocked(app, true, true);
         }
 
         String hostingNameStr = hostingName != null
@@ -2082,7 +2496,7 @@
         }
 
         if (app == null) {
-            app = newProcessRecordLocked(null, info, processName, isolated);
+            app = newProcessRecordLocked(info, processName, isolated);
             if (app == null) {
                 Slog.w(TAG, "Failed making new process record for "
                         + processName + "/" + info.uid + " isolated=" + isolated);
@@ -2094,7 +2508,7 @@
             }
         } else {
             // If this is a new package in the process, add the package to the list
-            app.addPackage(info.packageName);
+            app.addPackage(info.packageName, mProcessStats);
         }
 
         // If the system is not ready yet, then hold off on starting this
@@ -2116,7 +2530,7 @@
     boolean isAllowedWhileBooting(ApplicationInfo ai) {
         return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
     }
-    
+
     private final void startProcessLocked(ProcessRecord app,
             String hostingType, String hostingNameStr) {
         if (app.pid > 0 && app.pid != MY_PID) {
@@ -2132,10 +2546,7 @@
         mProcessesOnHold.remove(app);
 
         updateCpuStats();
-        
-        System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
-        mProcDeaths[0] = 0;
-        
+
         try {
             int uid = app.uid;
 
@@ -2218,16 +2629,16 @@
                     app.batteryStats.incStartsLocked();
                 }
             }
-            
+
             EventLog.writeEvent(EventLogTags.AM_PROC_START,
                     UserHandle.getUserId(uid), startResult.pid, uid,
                     app.processName, hostingType,
                     hostingNameStr != null ? hostingNameStr : "");
-            
+
             if (app.persistent) {
                 Watchdog.getInstance().processStarted(app.processName, startResult.pid);
             }
-            
+
             StringBuilder buf = mStringBuilder;
             buf.setLength(0);
             buf.append("Start proc ");
@@ -2269,14 +2680,31 @@
         }
     }
 
-    void updateUsageStats(ActivityRecord resumedComponent, boolean resumed) {
+    void updateUsageStats(ActivityRecord component, boolean resumed) {
+        if (DEBUG_SWITCH) Slog.d(TAG, "updateUsageStats: comp=" + component + "res=" + resumed);
+        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         if (resumed) {
-            mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
+            mUsageStatsService.noteResumeComponent(component.realActivity);
+            synchronized (stats) {
+                stats.noteActivityResumedLocked(component.app.uid);
+            }
         } else {
-            mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
+            mUsageStatsService.notePauseComponent(component.realActivity);
+            synchronized (stats) {
+                stats.noteActivityPausedLocked(component.app.uid);
+            }
         }
     }
 
+    Intent getHomeIntent() {
+        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
+        intent.setComponent(mTopComponent);
+        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            intent.addCategory(Intent.CATEGORY_HOME);
+        }
+        return intent;
+    }
+
     boolean startHomeActivityLocked(int userId) {
         if (mHeadless) {
             // Added because none of the other calls to ensureBootCompleted seem to fire
@@ -2292,13 +2720,7 @@
             // error message and don't try to start anything.
             return false;
         }
-        Intent intent = new Intent(
-            mTopAction,
-            mTopData != null ? Uri.parse(mTopData) : null);
-        intent.setComponent(mTopComponent);
-        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
-            intent.addCategory(Intent.CATEGORY_HOME);
-        }
+        Intent intent = getHomeIntent();
         ActivityInfo aInfo =
             resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
         if (aInfo != null) {
@@ -2309,11 +2731,10 @@
             aInfo = new ActivityInfo(aInfo);
             aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
             ProcessRecord app = getProcessRecordLocked(aInfo.processName,
-                    aInfo.applicationInfo.uid);
+                    aInfo.applicationInfo.uid, true);
             if (app == null || app.instrumentationClass == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                mMainStack.startActivityLocked(null, intent, null, aInfo,
-                        null, null, 0, 0, 0, null, 0, null, false, null);
+                mStackSupervisor.startHomeActivity(intent, aInfo);
             }
         }
 
@@ -2331,7 +2752,7 @@
                         intent,
                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                             flags, userId);
-    
+
                 if (info != null) {
                     ai = info.activityInfo;
                 }
@@ -2351,7 +2772,7 @@
         if (mCheckedForSetup) {
             return;
         }
-        
+
         // We will show this screen if the current one is a different
         // version than the last one shown, and we are not running in
         // low-level factory test mode.
@@ -2360,12 +2781,12 @@
                 Settings.Global.getInt(resolver,
                         Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
             mCheckedForSetup = true;
-            
+
             // See if we should be showing the platform update setup UI.
             Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
             List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
                     .queryIntentActivities(intent, PackageManager.GET_META_DATA);
-            
+
             // We don't allow third party apps to replace this.
             ResolveInfo ri = null;
             for (int i=0; ris != null && i<ris.size(); i++) {
@@ -2375,7 +2796,7 @@
                     break;
                 }
             }
-            
+
             if (ri != null) {
                 String vers = ri.activityInfo.metaData != null
                         ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
@@ -2390,13 +2811,13 @@
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     intent.setComponent(new ComponentName(
                             ri.activityInfo.packageName, ri.activityInfo.name));
-                    mMainStack.startActivityLocked(null, intent, null, ri.activityInfo,
+                    mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo,
                             null, null, 0, 0, 0, null, 0, null, false, null);
                 }
             }
         }
     }
-    
+
     CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
         return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
     }
@@ -2407,6 +2828,7 @@
         }
     }
 
+    @Override
     public int getFrontActivityScreenCompatMode() {
         enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
         synchronized (this) {
@@ -2414,6 +2836,7 @@
         }
     }
 
+    @Override
     public void setFrontActivityScreenCompatMode(int mode) {
         enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
                 "setFrontActivityScreenCompatMode");
@@ -2422,6 +2845,7 @@
         }
     }
 
+    @Override
     public int getPackageScreenCompatMode(String packageName) {
         enforceNotIsolatedCaller("getPackageScreenCompatMode");
         synchronized (this) {
@@ -2429,6 +2853,7 @@
         }
     }
 
+    @Override
     public void setPackageScreenCompatMode(String packageName, int mode) {
         enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
                 "setPackageScreenCompatMode");
@@ -2437,6 +2862,7 @@
         }
     }
 
+    @Override
     public boolean getPackageAskScreenCompat(String packageName) {
         enforceNotIsolatedCaller("getPackageAskScreenCompat");
         synchronized (this) {
@@ -2444,6 +2870,7 @@
         }
     }
 
+    @Override
     public void setPackageAskScreenCompat(String packageName, boolean ask) {
         enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
                 "setPackageAskScreenCompat");
@@ -2452,11 +2879,6 @@
         }
     }
 
-    void reportResumedActivityLocked(ActivityRecord r) {
-        //Slog.i(TAG, "**** REPORT RESUME: " + r);
-        updateUsageStats(r, true);
-    }
-
     private void dispatchProcessesChanged() {
         int N;
         synchronized (this) {
@@ -2469,6 +2891,7 @@
             mPendingProcessChanges.clear();
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "*** Delivering " + N + " process changes");
         }
+
         int i = mProcessObservers.beginBroadcast();
         while (i > 0) {
             i--;
@@ -2520,12 +2943,13 @@
         }
         for (int i=0; i<N; i++) {
             PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
-            mMainStack.startActivityUncheckedLocked(pal.r, pal.sourceRecord,
-                    pal.startFlags, doResume && i == (N-1), null);
+            mStackSupervisor.startActivityUncheckedLocked(pal.r, pal.sourceRecord, pal.startFlags,
+                    doResume && i == (N-1), null);
         }
         mPendingActivityLaunches.clear();
     }
 
+    @Override
     public final int startActivity(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags,
@@ -2535,6 +2959,7 @@
                 startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
     }
 
+    @Override
     public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags,
@@ -2542,11 +2967,13 @@
         enforceNotIsolatedCaller("startActivity");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivity", null);
-        return mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
+        // TODO: Switch to user app stacks here.
+        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                 null, null, options, userId);
     }
 
+    @Override
     public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, String profileFile,
@@ -2555,12 +2982,14 @@
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityAndWait", null);
         WaitResult res = new WaitResult();
-        mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
+        // TODO: Switch to user app stacks here.
+        mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                 res, null, options, UserHandle.getCallingUserId());
         return res;
     }
 
+    @Override
     public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, Configuration config,
@@ -2568,12 +2997,14 @@
         enforceNotIsolatedCaller("startActivityWithConfig");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityWithConfig", null);
-        int ret = mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
-                resultTo, resultWho, requestCode, startFlags,
+        // TODO: Switch to user app stacks here.
+        int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
+                resolvedType, resultTo, resultWho, requestCode, startFlags,
                 null, null, null, config, options, userId);
         return ret;
     }
 
+    @Override
     public int startActivityIntentSender(IApplicationThread caller,
             IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
@@ -2583,20 +3014,20 @@
         if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
-        
+
         IIntentSender sender = intent.getTarget();
         if (!(sender instanceof PendingIntentRecord)) {
             throw new IllegalArgumentException("Bad PendingIntent object");
         }
-        
+
         PendingIntentRecord pir = (PendingIntentRecord)sender;
-        
+
         synchronized (this) {
             // If this is coming from the currently resumed activity, it is
             // effectively saying that app switches are allowed at this point.
-            if (mMainStack.mResumedActivity != null
-                    && mMainStack.mResumedActivity.info.applicationInfo.uid ==
-                            Binder.getCallingUid()) {
+            final ActivityStack stack = getFocusedStack();
+            if (stack.mResumedActivity != null &&
+                    stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
                 mAppSwitchesAllowedTime = 0;
             }
         }
@@ -2604,7 +3035,8 @@
                 resultTo, resultWho, requestCode, flagsMask, flagsValues, options);
         return ret;
     }
-    
+
+    @Override
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent, Bundle options) {
         // Refuse possible leaked file descriptors
@@ -2613,7 +3045,7 @@
         }
 
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(callingActivity);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(callingActivity);
             if (r == null) {
                 ActivityOptions.abort(options);
                 return false;
@@ -2629,6 +3061,8 @@
             // And we are resetting to find the next component...
             intent.setComponent(null);
 
+            final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
+
             ActivityInfo aInfo = null;
             try {
                 List<ResolveInfo> resolves =
@@ -2649,6 +3083,12 @@
                         if (i<N) {
                             aInfo = resolves.get(i).activityInfo;
                         }
+                        if (debug) {
+                            Slog.v(TAG, "Next matching activity: found current " + r.packageName
+                                    + "/" + r.info.name);
+                            Slog.v(TAG, "Next matching activity: next is " + aInfo.packageName
+                                    + "/" + aInfo.name);
+                        }
                         break;
                     }
                 }
@@ -2658,6 +3098,7 @@
             if (aInfo == null) {
                 // Nobody who is next!
                 ActivityOptions.abort(options);
+                if (debug) Slog.d(TAG, "Next matching activity: nothing found");
                 return false;
             }
 
@@ -2687,7 +3128,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            int res = mMainStack.startActivityLocked(r.app.thread, intent,
+            int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
                     r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null,
                     resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, 0,
                     options, false, null);
@@ -2708,19 +3149,22 @@
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityInPackage", null);
 
-        int ret = mMainStack.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
+        // TODO: Switch to user app stacks here.
+        int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags,
                 null, null, null, null, options, userId);
         return ret;
     }
 
+    @Override
     public final int startActivities(IApplicationThread caller, String callingPackage,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle options,
             int userId) {
         enforceNotIsolatedCaller("startActivities");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivity", null);
-        int ret = mMainStack.startActivities(caller, -1, callingPackage, intents,
+        // TODO: Switch to user app stacks here.
+        int ret = mStackSupervisor.startActivities(caller, -1, callingPackage, intents,
                 resolvedTypes, resultTo, options, userId);
         return ret;
     }
@@ -2731,7 +3175,8 @@
 
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityInPackage", null);
-        int ret = mMainStack.startActivities(null, uid, callingPackage, intents, resolvedTypes,
+        // TODO: Switch to user app stacks here.
+        int ret = mStackSupervisor.startActivities(null, uid, callingPackage, intents, resolvedTypes,
                 resultTo, options, userId);
         return ret;
     }
@@ -2764,31 +3209,42 @@
         mRecentTasks.add(0, task);
     }
 
-    public void setRequestedOrientation(IBinder token,
-            int requestedOrientation) {
+    @Override
+    public void reportActivityFullyDrawn(IBinder token) {
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return;
+            }
+            r.reportFullyDrawnLocked();
+        }
+    }
+
+    @Override
+    public void setRequestedOrientation(IBinder token, int requestedOrientation) {
+        synchronized (this) {
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return;
             }
             final long origId = Binder.clearCallingIdentity();
             mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
-                    mConfiguration,
-                    r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
+                    mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false, false)) {
-                    mMainStack.resumeTopActivityLocked(null);
+                    mStackSupervisor.resumeTopActivitiesLocked();
                 }
             }
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    @Override
     public int getRequestedOrientation(IBinder token) {
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
@@ -2798,13 +3254,14 @@
 
     /**
      * This is the internal entry point for handling Activity.finish().
-     * 
+     *
      * @param token The Binder token referencing the Activity we want to finish.
      * @param resultCode Result code, if any, from this Activity.
      * @param resultData Result data (Intent), if any, from this Activity.
-     * 
+     *
      * @return Returns true if the activity successfully finished, or false if it is still running.
      */
+    @Override
     public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
         // Refuse possible leaked file descriptors
         if (resultData != null && resultData.hasFileDescriptors() == true) {
@@ -2812,9 +3269,13 @@
         }
 
         synchronized(this) {
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return true;
+            }
             if (mController != null) {
                 // Find the first activity that is not finishing.
-                ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
+                ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
                 if (next != null) {
                     // ask watcher if this is allowed
                     boolean resumeOK = true;
@@ -2824,20 +3285,21 @@
                         mController = null;
                         Watchdog.getInstance().setActivityController(null);
                     }
-    
+
                     if (!resumeOK) {
                         return false;
                     }
                 }
             }
             final long origId = Binder.clearCallingIdentity();
-            boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
+            boolean res = r.task.stack.requestFinishActivityLocked(token, resultCode,
                     resultData, "app-request", true);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
+    @Override
     public final void finishHeavyWeightApp() {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -2848,31 +3310,29 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        
+
         synchronized(this) {
             if (mHeavyWeightProcess == null) {
                 return;
             }
-            
+
             ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(
                     mHeavyWeightProcess.activities);
             for (int i=0; i<activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
                 if (!r.finishing) {
-                    int index = mMainStack.indexOfTokenLocked(r.appToken);
-                    if (index >= 0) {
-                        mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
-                                null, "finish-heavy", true);
-                    }
+                    r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                            null, "finish-heavy", true);
                 }
             }
-            
+
             mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                     mHeavyWeightProcess.userId, 0));
             mHeavyWeightProcess = null;
         }
     }
-    
+
+    @Override
     public void crashApplication(int uid, int initialPid, String packageName,
             String message) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
@@ -2884,10 +3344,10 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        
+
         synchronized(this) {
             ProcessRecord proc = null;
-            
+
             // Figure out which process to kill.  We don't trust that initialPid
             // still has any relation to current pids, so must scan through the
             // list.
@@ -2901,21 +3361,19 @@
                         proc = p;
                         break;
                     }
-                    for (String str : p.pkgList) {
-                        if (str.equals(packageName)) {
-                            proc = p;
-                        }
+                    if (p.pkgList.containsKey(packageName)) {
+                        proc = p;
                     }
                 }
             }
-            
+
             if (proc == null) {
                 Slog.w(TAG, "crashApplication: nothing for uid=" + uid
                         + " initialPid=" + initialPid
                         + " packageName=" + packageName);
                 return;
             }
-            
+
             if (proc.thread != null) {
                 if (proc.pid == Process.myPid()) {
                     Log.w(TAG, "crashApplication: trying to crash self!");
@@ -2930,61 +3388,66 @@
             }
         }
     }
-    
+
+    @Override
     public final void finishSubActivity(IBinder token, String resultWho,
             int requestCode) {
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            mMainStack.finishSubActivityLocked(token, resultWho, requestCode);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r != null) {
+                r.task.stack.finishSubActivityLocked(r, resultWho, requestCode);
+            }
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    @Override
     public boolean finishActivityAffinity(IBinder token) {
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            boolean res = mMainStack.finishActivityAffinityLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            boolean res = false;
+            if (r != null) {
+                res = r.task.stack.finishActivityAffinityLocked(r);
+            }
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
+    @Override
     public boolean willActivityBeVisible(IBinder token) {
         synchronized(this) {
-            int i;
-            for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-                if (r.appToken == token) {
-                    return true;
-                }
-                if (r.fullscreen && !r.finishing) {
-                    return false;
-                }
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                return stack.willActivityBeVisibleLocked(token);
             }
-            return true;
+            return false;
         }
     }
-    
+
+    @Override
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim) {
         synchronized(this) {
-            ActivityRecord self = mMainStack.isInStackLocked(token);
+            ActivityRecord self = ActivityRecord.isInStackLocked(token);
             if (self == null) {
                 return;
             }
 
             final long origId = Binder.clearCallingIdentity();
-            
+
             if (self.state == ActivityState.RESUMED
                     || self.state == ActivityState.PAUSING) {
                 mWindowManager.overridePendingAppTransition(packageName,
                         enterAnim, exitAnim, null);
             }
-            
+
             Binder.restoreCallingIdentity(origId);
         }
     }
-    
+
     /**
      * Main function for removing an existing process from the activity manager
      * as a result of that process going away.  Clears out all connections
@@ -2994,28 +3457,17 @@
             boolean restarting, boolean allowRestart) {
         cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
         if (!restarting) {
-            mLruProcesses.remove(app);
+            removeLruProcessLocked(app);
         }
 
         if (mProfileProc == app) {
             clearProfilerLocked();
         }
 
-        // Just in case...
-        if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
-            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
-                    "App died while pausing: " + mMainStack.mPausingActivity);
-            mMainStack.mPausingActivity = null;
-        }
-        if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
-            mMainStack.mLastPausedActivity = null;
-        }
-
-        // Remove this application's activities from active lists.
-        boolean hasVisibleActivities = mMainStack.removeHistoryRecordsForAppLocked(app);
+        mStackSupervisor.handleAppDiedLocked(app, restarting);
 
         app.activities.clear();
-        
+
         if (app.instrumentationClass != null) {
             Slog.w(TAG, "Crash of app " + app.processName
                   + " running instrumentation " + app.instrumentationClass);
@@ -3023,19 +3475,6 @@
             info.putString("shortMsg", "Process crashed.");
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
-
-        if (!restarting) {
-            if (!mMainStack.resumeTopActivityLocked(null)) {
-                // If there was nothing to resume, and we are not already
-                // restarting this process, but there is a visible activity that
-                // is hosted by the process...  then make sure all visible
-                // activities are running, taking care of restarting this
-                // process.
-                if (hasVisibleActivities) {
-                    mMainStack.ensureActivitiesVisibleLocked(null, 0);
-                }
-            }
-        }
     }
 
     private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
@@ -3060,11 +3499,69 @@
         return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
     }
 
+    final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
+        // If there are no longer any background processes running,
+        // and the app that died was not running instrumentation,
+        // then tell everyone we are now low on memory.
+        boolean haveBg = false;
+        for (int i=mLruProcesses.size()-1; i>=0; i--) {
+            ProcessRecord rec = mLruProcesses.get(i);
+            if (rec.thread != null
+                    && rec.setProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                haveBg = true;
+                break;
+            }
+        }
+
+        if (!haveBg) {
+            boolean doReport = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+            if (doReport) {
+                long now = SystemClock.uptimeMillis();
+                if (now < (mLastMemUsageReportTime+5*60*1000)) {
+                    doReport = false;
+                } else {
+                    mLastMemUsageReportTime = now;
+                }
+            }
+            final ArrayList<ProcessMemInfo> memInfos
+                    = doReport ? new ArrayList<ProcessMemInfo>(mLruProcesses.size()) : null;
+            EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
+            long now = SystemClock.uptimeMillis();
+            for (int i=mLruProcesses.size()-1; i>=0; i--) {
+                ProcessRecord rec = mLruProcesses.get(i);
+                if (rec == dyingProc || rec.thread == null) {
+                    continue;
+                }
+                if (doReport) {
+                    memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
+                            rec.setProcState, rec.adjType, rec.makeAdjReason()));
+                }
+                if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+                    // The low memory report is overriding any current
+                    // state for a GC request.  Make sure to do
+                    // heavy/important/visible/foreground processes first.
+                    if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                        rec.lastRequestedGc = 0;
+                    } else {
+                        rec.lastRequestedGc = rec.lastLowMemory;
+                    }
+                    rec.reportLowMemory = true;
+                    rec.lastLowMemory = now;
+                    mProcessesToGc.remove(rec);
+                    addProcessToGcListLocked(rec);
+                }
+            }
+            if (doReport) {
+                Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
+                mHandler.sendMessage(msg);
+            }
+            scheduleAppGcsLocked();
+        }
+    }
+
     final void appDiedLocked(ProcessRecord app, int pid,
             IApplicationThread thread) {
 
-        mProcDeaths[0]++;
-        
         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         synchronized (stats) {
             stats.noteProcessDiedLocked(app.info.uid, pid);
@@ -3073,54 +3570,29 @@
         // Clean up already done if the process has been re-started.
         if (app.pid == pid && app.thread != null &&
                 app.thread.asBinder() == thread.asBinder()) {
-            if (!app.killedBackground) {
+            boolean doLowMem = app.instrumentationClass == null;
+            boolean doOomAdj = doLowMem;
+            if (!app.killedByAm) {
                 Slog.i(TAG, "Process " + app.processName + " (pid " + pid
                         + ") has died.");
+                mAllowLowerMemLevel = true;
+            } else {
+                // Note that we always want to do oom adj to update our state with the
+                // new number of procs.
+                mAllowLowerMemLevel = false;
+                doLowMem = false;
             }
             EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
             if (DEBUG_CLEANUP) Slog.v(
                 TAG, "Dying app: " + app + ", pid: " + pid
                 + ", thread: " + thread.asBinder());
-            boolean doLowMem = app.instrumentationClass == null;
             handleAppDiedLocked(app, false, true);
 
+            if (doOomAdj) {
+                updateOomAdjLocked();
+            }
             if (doLowMem) {
-                // If there are no longer any background processes running,
-                // and the app that died was not running instrumentation,
-                // then tell everyone we are now low on memory.
-                boolean haveBg = false;
-                for (int i=mLruProcesses.size()-1; i>=0; i--) {
-                    ProcessRecord rec = mLruProcesses.get(i);
-                    if (rec.thread != null && rec.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
-                        haveBg = true;
-                        break;
-                    }
-                }
-                
-                if (!haveBg) {
-                    EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
-                    long now = SystemClock.uptimeMillis();
-                    for (int i=mLruProcesses.size()-1; i>=0; i--) {
-                        ProcessRecord rec = mLruProcesses.get(i);
-                        if (rec != app && rec.thread != null &&
-                                (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
-                            // The low memory report is overriding any current
-                            // state for a GC request.  Make sure to do
-                            // heavy/important/visible/foreground processes first.
-                            if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                                rec.lastRequestedGc = 0;
-                            } else {
-                                rec.lastRequestedGc = rec.lastLowMemory;
-                            }
-                            rec.reportLowMemory = true;
-                            rec.lastLowMemory = now;
-                            mProcessesToGc.remove(rec);
-                            addProcessToGcListLocked(rec);
-                        }
-                    }
-                    mHandler.sendEmptyMessage(REPORT_MEM_USAGE);
-                    scheduleAppGcsLocked();
-                }
+                doLowMemReportIfNeededLocked(app);
             }
         } else if (app.pid != pid) {
             // A new process has already been started.
@@ -3144,7 +3616,7 @@
      * @return file containing stack traces, or null if no dump file is configured
      */
     public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,
-            ProcessStats processStats, SparseArray<Boolean> lastPids, String[] nativeProcs) {
+            ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
         String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
         if (tracesPath == null || tracesPath.length() == 0) {
             return null;
@@ -3169,15 +3641,16 @@
             return null;
         }
 
-        dumpStackTraces(tracesPath, firstPids, processStats, lastPids, nativeProcs);
+        dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativeProcs);
         return tracesFile;
     }
 
     private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
-            ProcessStats processStats, SparseArray<Boolean> lastPids, String[] nativeProcs) {
+            ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
         // Use a FileObserver to detect when traces finish writing.
         // The order of traces is considered important to maintain for legibility.
         FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
+            @Override
             public synchronized void onEvent(int event, String path) { notify(); }
         };
 
@@ -3200,23 +3673,23 @@
             }
 
             // Next measure CPU usage.
-            if (processStats != null) {
-                processStats.init();
+            if (processCpuTracker != null) {
+                processCpuTracker.init();
                 System.gc();
-                processStats.update();
+                processCpuTracker.update();
                 try {
-                    synchronized (processStats) {
-                        processStats.wait(500); // measure over 1/2 second.
+                    synchronized (processCpuTracker) {
+                        processCpuTracker.wait(500); // measure over 1/2 second.
                     }
                 } catch (InterruptedException e) {
                 }
-                processStats.update();
+                processCpuTracker.update();
 
                 // We'll take the stack crawls of just the top apps using CPU.
-                final int N = processStats.countWorkingStats();
+                final int N = processCpuTracker.countWorkingStats();
                 int numProcs = 0;
                 for (int i=0; i<N && numProcs<5; i++) {
-                    ProcessStats.Stats stats = processStats.getWorkingStats(i);
+                    ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
                     if (lastPids.indexOfKey(stats.pid) >= 0) {
                         numProcs++;
                         try {
@@ -3303,7 +3776,7 @@
             File lastTracesFile = null;
             File curTracesFile = null;
             for (int i=9; i>=0; i--) {
-                String name = String.format("slow%02d.txt", i);
+                String name = String.format(Locale.US, "slow%02d.txt", i);
                 curTracesFile = new File(tracesDir, name);
                 if (curTracesFile.exists()) {
                     if (lastTracesFile != null) {
@@ -3343,7 +3816,7 @@
         if (MONITOR_CPU_USAGE) {
             updateCpuStatsNow();
         }
-        
+
         synchronized (this) {
             // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
             if (mShuttingDown) {
@@ -3356,7 +3829,7 @@
                 Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
                 return;
             }
-            
+
             // In case we come through here for the same app before completing
             // this one, mark as anring now so we will bail out.
             app.notResponding = true;
@@ -3367,11 +3840,11 @@
 
             // Dump thread traces as quickly as we can, starting with "interesting" processes.
             firstPids.add(app.pid);
-    
+
             int parentPid = app.pid;
             if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
             if (parentPid != app.pid) firstPids.add(parentPid);
-    
+
             if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
 
             for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
@@ -3397,6 +3870,7 @@
             info.append(" (").append(activity.shortComponentName).append(")");
         }
         info.append("\n");
+        info.append("PID: ").append(app.pid).append("\n");
         if (annotation != null) {
             info.append("Reason: ").append(annotation).append("\n");
         }
@@ -3404,21 +3878,21 @@
             info.append("Parent: ").append(parent.shortComponentName).append("\n");
         }
 
-        final ProcessStats processStats = new ProcessStats(true);
+        final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
 
-        File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids, null);
+        File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, null);
 
         String cpuInfo = null;
         if (MONITOR_CPU_USAGE) {
             updateCpuStatsNow();
-            synchronized (mProcessStatsThread) {
-                cpuInfo = mProcessStats.printCurrentState(anrTime);
+            synchronized (mProcessCpuThread) {
+                cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
             }
-            info.append(processStats.printCurrentLoad());
+            info.append(processCpuTracker.printCurrentLoad());
             info.append(cpuInfo);
         }
 
-        info.append(processStats.printCurrentState(anrTime));
+        info.append(processCpuTracker.printCurrentState(anrTime));
 
         Slog.e(TAG, info.toString());
         if (tracesFile == null) {
@@ -3434,7 +3908,13 @@
                 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
                 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
                 if (res != 0) {
-                    if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
+                    if (res < 0 && app.pid != MY_PID) {
+                        Process.killProcess(app.pid);
+                    } else {
+                        synchronized (this) {
+                            mServices.scheduleServiceTimeoutLocked(app);
+                        }
+                    }
                     return;
                 }
             } catch (RemoteException e) {
@@ -3446,25 +3926,22 @@
         // Unless configured otherwise, swallow ANRs in background processes & kill the process.
         boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-        
+
         synchronized (this) {
             if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
-                Slog.w(TAG, "Killing " + app + ": background ANR");
-                EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                        app.processName, app.setAdj, "background ANR");
-                Process.killProcessQuiet(app.pid);
+                killUnneededProcessLocked(app, "background ANR");
                 return;
             }
-    
+
             // Set the app's notResponding state, and look up the errorReportReceiver
             makeAppNotRespondingLocked(app,
                     activity != null ? activity.shortComponentName : null,
                     annotation != null ? "ANR " + annotation : "ANR",
                     info.toString());
-    
+
             // Bring up the infamous App Not Responding dialog
             Message msg = Message.obtain();
-            HashMap map = new HashMap();
+            HashMap<String, Object> map = new HashMap<String, Object>();
             msg.what = SHOW_NOT_RESPONDING_MSG;
             msg.obj = map;
             msg.arg1 = aboveSystem ? 1 : 0;
@@ -3472,7 +3949,7 @@
             if (activity != null) {
                 map.put("activity", activity);
             }
-    
+
             mHandler.sendMessage(msg);
         }
     }
@@ -3500,7 +3977,8 @@
             });
         }
     }
-    
+
+    @Override
     public boolean clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, int userId) {
         enforceNotIsolatedCaller("clearApplicationUserData");
@@ -3532,17 +4010,21 @@
                         android.Manifest.permission.CLEAR_APP_USER_DATA,
                         pid, uid, -1, true)
                         == PackageManager.PERMISSION_GRANTED) {
-                    forceStopPackageLocked(packageName, pkgUid);
+                    forceStopPackageLocked(packageName, pkgUid, "clear data");
                 } else {
                     throw new SecurityException("PID " + pid + " does not have permission "
                             + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data"
                                     + " of package " + packageName);
                 }
             }
-            
+
             try {
-                //clear application user data
+                // Clear application user data
                 pm.clearApplicationUserData(packageName, observer, userId);
+
+                // Remove all permissions granted from/to this package
+                removeUriPermissionsForPackageLocked(packageName, userId, true);
+
                 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
@@ -3556,6 +4038,7 @@
         return true;
     }
 
+    @Override
     public void killBackgroundProcesses(final String packageName, int userId) {
         if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
                 != PackageManager.PERMISSION_GRANTED &&
@@ -3592,6 +4075,7 @@
         }
     }
 
+    @Override
     public void killAllBackgroundProcesses() {
         if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -3602,12 +4086,14 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        
+
         long callingId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
                 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
-                for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+                final int NP = mProcessNames.getMap().size();
+                for (int ip=0; ip<NP; ip++) {
+                    SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
                     final int NA = apps.size();
                     for (int ia=0; ia<NA; ia++) {
                         ProcessRecord app = apps.valueAt(ia);
@@ -3617,23 +4103,27 @@
                         }
                         if (app.removed) {
                             procs.add(app);
-                        } else if (app.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+                        } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
                             app.removed = true;
                             procs.add(app);
                         }
                     }
                 }
-                
+
                 int N = procs.size();
                 for (int i=0; i<N; i++) {
                     removeProcessLocked(procs.get(i), false, true, "kill all background");
                 }
+                mAllowLowerMemLevel = true;
+                updateOomAdjLocked();
+                doLowMemReportIfNeededLocked(null);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
     }
 
+    @Override
     public void forceStopPackage(final String packageName, int userId) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -3644,7 +4134,8 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+        final int callingPid = Binder.getCallingPid();
+        userId = handleIncomingUser(callingPid, Binder.getCallingUid(),
                 userId, true, true, "forceStopPackage", null);
         long callingId = Binder.clearCallingIdentity();
         try {
@@ -3670,7 +4161,7 @@
                                 + packageName + ": " + e);
                     }
                     if (isUserRunningLocked(user, false)) {
-                        forceStopPackageLocked(packageName, pkgUid);
+                        forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
                     }
                 }
             }
@@ -3682,7 +4173,8 @@
     /*
      * The pkg name and app id have to be specified.
      */
-    public void killApplicationWithAppId(String pkg, int appid) {
+    @Override
+    public void killApplicationWithAppId(String pkg, int appid, String reason) {
         if (pkg == null) {
             return;
         }
@@ -3698,7 +4190,10 @@
             Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
             msg.arg1 = appid;
             msg.arg2 = 0;
-            msg.obj = pkg;
+            Bundle bundle = new Bundle();
+            bundle.putString("pkg", pkg);
+            bundle.putString("reason", reason);
+            msg.obj = bundle;
             mHandler.sendMessage(msg);
         } else {
             throw new SecurityException(callerUid + " cannot kill pkg: " +
@@ -3706,6 +4201,7 @@
         }
     }
 
+    @Override
     public void closeSystemDialogs(String reason) {
         enforceNotIsolatedCaller("closeSystemDialogs");
 
@@ -3743,39 +4239,69 @@
         }
         mWindowManager.closeSystemDialogs(reason);
 
-        for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
-                r.stack.finishActivityLocked(r, i,
-                        Activity.RESULT_CANCELED, null, "close-sys", true);
-            }
-        }
+        mStackSupervisor.closeSystemDialogsLocked();
 
         broadcastIntentLocked(null, null, intent, null,
                 null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
                 Process.SYSTEM_UID, UserHandle.USER_ALL);
     }
 
-    public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
-            throws RemoteException {
+    @Override
+    public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) {
         enforceNotIsolatedCaller("getProcessMemoryInfo");
         Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
         for (int i=pids.length-1; i>=0; i--) {
+            ProcessRecord proc;
+            int oomAdj;
+            synchronized (this) {
+                synchronized (mPidsSelfLocked) {
+                    proc = mPidsSelfLocked.get(pids[i]);
+                    oomAdj = proc != null ? proc.setAdj : 0;
+                }
+            }
             infos[i] = new Debug.MemoryInfo();
             Debug.getMemoryInfo(pids[i], infos[i]);
+            if (proc != null) {
+                synchronized (this) {
+                    if (proc.thread != null && proc.setAdj == oomAdj) {
+                        // Record this for posterity if the process has been stable.
+                        proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
+                                infos[i].getTotalUss(), false, proc.pkgList);
+                    }
+                }
+            }
         }
         return infos;
     }
 
-    public long[] getProcessPss(int[] pids) throws RemoteException {
+    @Override
+    public long[] getProcessPss(int[] pids) {
         enforceNotIsolatedCaller("getProcessPss");
         long[] pss = new long[pids.length];
         for (int i=pids.length-1; i>=0; i--) {
-            pss[i] = Debug.getPss(pids[i]);
+            ProcessRecord proc;
+            int oomAdj;
+            synchronized (this) {
+                synchronized (mPidsSelfLocked) {
+                    proc = mPidsSelfLocked.get(pids[i]);
+                    oomAdj = proc != null ? proc.setAdj : 0;
+                }
+            }
+            long[] tmpUss = new long[1];
+            pss[i] = Debug.getPss(pids[i], tmpUss);
+            if (proc != null) {
+                synchronized (this) {
+                    if (proc.thread != null && proc.setAdj == oomAdj) {
+                        // Record this for posterity if the process has been stable.
+                        proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false, proc.pkgList);
+                    }
+                }
+            }
         }
         return pss;
     }
 
+    @Override
     public void killApplicationProcess(String processName, int uid) {
         if (processName == null) {
             return;
@@ -3785,7 +4311,7 @@
         // Only the system server can kill an application
         if (callerUid == Process.SYSTEM_UID) {
             synchronized (this) {
-                ProcessRecord app = getProcessRecordLocked(processName, uid);
+                ProcessRecord app = getProcessRecordLocked(processName, uid, true);
                 if (app != null && app.thread != null) {
                     try {
                         app.thread.scheduleSuicide();
@@ -3803,9 +4329,9 @@
         }
     }
 
-    private void forceStopPackageLocked(final String packageName, int uid) {
+    private void forceStopPackageLocked(final String packageName, int uid, String reason) {
         forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
-                false, true, false, UserHandle.getUserId(uid));
+                false, true, false, UserHandle.getUserId(uid), reason);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         if (!mProcessesReady) {
@@ -3820,8 +4346,8 @@
                 MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
     }
 
-    private void forceStopUserLocked(int userId) {
-        forceStopPackageLocked(null, -1, false, false, true, false, userId);
+    private void forceStopUserLocked(int userId, String reason) {
+        forceStopPackageLocked(null, -1, false, false, true, false, userId, reason);
         Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                 | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -3841,7 +4367,9 @@
         // same UID (except for the system or root user), and all whose name
         // matches the package name.
         final String procNamePrefix = packageName != null ? (packageName + ":") : null;
-        for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+        final int NP = mProcessNames.getMap().size();
+        for (int ip=0; ip<NP; ip++) {
+            SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
             final int NA = apps.size();
             for (int ia=0; ia<NA; ia++) {
                 ProcessRecord app = apps.valueAt(ia);
@@ -3880,7 +4408,7 @@
                     if (userId != UserHandle.USER_ALL && app.userId != userId) {
                         continue;
                     }
-                    if (!app.pkgList.contains(packageName)) {
+                    if (!app.pkgList.containsKey(packageName)) {
                         continue;
                     }
                 }
@@ -3893,17 +4421,18 @@
                 procs.add(app);
             }
         }
-        
+
         int N = procs.size();
         for (int i=0; i<N; i++) {
             removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
         }
+        updateOomAdjLocked();
         return N > 0;
     }
 
     private final boolean forceStopPackageLocked(String name, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
-            boolean evenPersistent, int userId) {
+            boolean evenPersistent, int userId, String reason) {
         int i;
         int N;
 
@@ -3921,15 +4450,15 @@
 
         if (doit) {
             if (name != null) {
-                Slog.i(TAG, "Force stopping package " + name + " appid=" + appId
-                        + " user=" + userId);
+                Slog.i(TAG, "Force stopping " + name + " appid=" + appId
+                        + " user=" + userId + ": " + reason);
             } else {
-                Slog.i(TAG, "Force stopping user " + userId);
+                Slog.i(TAG, "Force stopping u" + userId + ": " + reason);
             }
 
-            Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
-            while (badApps.hasNext()) {
-                SparseArray<Long> ba = badApps.next();
+            final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+            for (int ip=pmap.size()-1; ip>=0; ip--) {
+                SparseArray<Long> ba = pmap.valueAt(ip);
                 for (i=ba.size()-1; i>=0; i--) {
                     boolean remove = false;
                     final int entUid = ba.keyAt(i);
@@ -3951,45 +4480,20 @@
                     }
                 }
                 if (ba.size() == 0) {
-                    badApps.remove();
+                    pmap.removeAt(ip);
                 }
             }
         }
 
         boolean didSomething = killPackageProcessesLocked(name, appId, userId,
                 -100, callerWillRestart, true, doit, evenPersistent,
-                name == null ? ("force stop user " + userId) : ("force stop " + name));
-        
-        TaskRecord lastTask = null;
-        for (i=0; i<mMainStack.mHistory.size(); i++) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            final boolean samePackage = r.packageName.equals(name)
-                    || (name == null && r.userId == userId);
-            if ((userId == UserHandle.USER_ALL || r.userId == userId)
-                    && (samePackage || r.task == lastTask)
-                    && (r.app == null || evenPersistent || !r.app.persistent)) {
-                if (!doit) {
-                    if (r.finishing) {
-                        // If this activity is just finishing, then it is not
-                        // interesting as far as something to stop.
-                        continue;
-                    }
-                    return true;
-                }
-                didSomething = true;
-                Slog.i(TAG, "  Force finishing activity " + r);
-                if (samePackage) {
-                    if (r.app != null) {
-                        r.app.removed = true;
-                    }
-                    r.app = null;
-                }
-                lastTask = r.task;
-                if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                        null, "force-stop", true)) {
-                    i--;
-                }
+                name == null ? ("stop user " + userId) : ("stop " + name));
+
+        if (mStackSupervisor.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+            if (!doit) {
+                return true;
             }
+            didSomething = true;
         }
 
         if (mServices.forceStopLocked(name, userId, evenPersistent, doit)) {
@@ -4017,6 +4521,9 @@
             removeDyingProviderLocked(null, providers.get(i), true);
         }
 
+        // Remove transient permissions granted from/to this package/user
+        removeUriPermissionsForPackageLocked(name, userId, false);
+
         if (name == null) {
             // Remove pending intents.  For now we only do this when force
             // stopping users, because we have some problems when doing this
@@ -4077,11 +4584,11 @@
                 }
             }
             if (mBooted) {
-                mMainStack.resumeTopActivityLocked(null);
-                mMainStack.scheduleIdleLocked();
+                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.scheduleIdleLocked();
             }
         }
-        
+
         return didSomething;
     }
 
@@ -4107,11 +4614,10 @@
                 mPidsSelfLocked.remove(pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
-            Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
+            killUnneededProcessLocked(app, reason);
             handleAppDiedLocked(app, true, allowRestart);
-            mLruProcesses.remove(app);
-            Process.killProcessQuiet(pid);
-            
+            removeLruProcessLocked(app);
+
             if (app.persistent && !app.isolated) {
                 if (!callerWillRestart) {
                     addAppLocked(app.info, false);
@@ -4122,7 +4628,7 @@
         } else {
             mRemovedProcesses.add(app);
         }
-        
+
         return needRestart;
     }
 
@@ -4134,9 +4640,9 @@
             if (knownApp != null && knownApp.thread == null) {
                 mPidsSelfLocked.remove(pid);
                 gone = true;
-            }        
+            }
         }
-        
+
         if (gone) {
             Slog.w(TAG, "Process " + app + " failed to attach");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
@@ -4152,9 +4658,7 @@
             checkAppInLaunchingProvidersLocked(app, true);
             // Take care of any services that are waiting for the process.
             mServices.processStartTimedOutLocked(app);
-            EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, pid,
-                    app.processName, app.setAdj, "start timeout");
-            Process.killProcessQuiet(pid);
+            killUnneededProcessLocked(app, "start timeout");
             if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
                 Slog.w(TAG, "Unattached app died before backup, skipping");
                 try {
@@ -4216,38 +4720,38 @@
         if (localLOGV) Slog.v(
                 TAG, "Binding process pid " + pid + " to record " + app);
 
-        String processName = app.processName;
+        final String processName = app.processName;
         try {
             AppDeathRecipient adr = new AppDeathRecipient(
                     app, pid, thread);
             thread.asBinder().linkToDeath(adr, 0);
             app.deathRecipient = adr;
         } catch (RemoteException e) {
-            app.resetPackageList();
+            app.resetPackageList(mProcessStats);
             startProcessLocked(app, "link fail", processName);
             return false;
         }
 
         EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
-        
-        app.thread = thread;
+
+        app.makeActive(thread, mProcessStats);
         app.curAdj = app.setAdj = -100;
-        app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
-        app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
         app.forcingToForeground = null;
         app.foregroundServices = false;
         app.hasShownUi = false;
         app.debugging = false;
+        app.cached = false;
 
         mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
 
         boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
-        List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
+        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
 
         if (!normalMode) {
             Slog.i(TAG, "Launching preboot mode app: " + app);
         }
-        
+
         if (localLOGV) Slog.v(
             TAG, "New app record " + app
             + " thread=" + thread.asBinder() + " pid=" + pid);
@@ -4285,7 +4789,7 @@
                         || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
                         || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
             }
-            
+
             ensurePackageDexOpt(app.instrumentationInfo != null
                     ? app.instrumentationInfo.packageName
                     : app.info.packageName);
@@ -4307,7 +4811,7 @@
                     isRestrictedBackupMode || !normalMode, app.persistent,
                     new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                     mCoreSettingsObserver.getCoreSettingsLocked());
-            updateLruProcessLocked(app, false);
+            updateLruProcessLocked(app, false, false);
             app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
         } catch (Exception e) {
             // todo: Yikes!  What should we do?  For now we will try to
@@ -4315,7 +4819,7 @@
             // an infinite loop of restarting processes...
             Slog.w(TAG, "Exception thrown during bind!", e);
 
-            app.resetPackageList();
+            app.resetPackageList(mProcessStats);
             app.unlinkDeathRecipient();
             startProcessLocked(app, "bind fail", processName);
             return false;
@@ -4331,23 +4835,13 @@
         boolean didSomething = false;
 
         // See if the top visible activity is waiting to run in this process...
-        ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
-        if (hr != null && normalMode) {
-            if (hr.app == null && app.uid == hr.info.applicationInfo.uid
-                    && processName.equals(hr.processName)) {
-                try {
-                    if (mHeadless) {
-                        Slog.e(TAG, "Starting activities not supported on headless device: " + hr);
-                    } else if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
-                        didSomething = true;
-                    }
-                } catch (Exception e) {
-                    Slog.w(TAG, "Exception in new application when starting activity "
-                          + hr.intent.getComponent().flattenToShortString(), e);
-                    badApp = true;
+        if (normalMode) {
+            try {
+                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
+                    didSomething = true;
                 }
-            } else {
-                mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
+            } catch (Exception e) {
+                badApp = true;
             }
         }
 
@@ -4363,7 +4857,7 @@
         // Check if a next-broadcast receiver is in this process...
         if (!badApp && isPendingBroadcastProcessLocked(pid)) {
             try {
-                didSomething = sendPendingBroadcastsLocked(app);
+                didSomething |= sendPendingBroadcastsLocked(app);
             } catch (Exception e) {
                 // If the app died trying to launch the receiver we declare it 'bad'
                 badApp = true;
@@ -4398,6 +4892,7 @@
         return true;
     }
 
+    @Override
     public final void attachApplication(IApplicationThread thread) {
         synchronized (this) {
             int callingPid = Binder.getCallingPid();
@@ -4407,13 +4902,16 @@
         }
     }
 
+    @Override
     public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
         final long origId = Binder.clearCallingIdentity();
-        ActivityRecord r = mMainStack.activityIdleInternal(token, false, config);
-        if (stopProfiling) {
-            synchronized (this) {
-                if (mProfileProc == r.app) {
-                    if (mProfileFd != null) {
+        synchronized (this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                ActivityRecord r =
+                        mStackSupervisor.activityIdleInternalLocked(token, false, config);
+                if (stopProfiling) {
+                    if ((mProfileProc == r.app) && (mProfileFd != null)) {
                         try {
                             mProfileFd.close();
                         } catch (IOException e) {
@@ -4436,21 +4934,24 @@
         }
     }
 
+    @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
         enforceNotIsolatedCaller("showBootMessage");
         mWindowManager.showBootMessage(msg, always);
     }
 
+    @Override
     public void dismissKeyguardOnNextActivity() {
         enforceNotIsolatedCaller("dismissKeyguardOnNextActivity");
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
+                if (DEBUG_LOCKSCREEN) logLockScreen("");
                 if (mLockScreenShown) {
                     mLockScreenShown = false;
                     comeOutOfSleepIfNeededLocked();
                 }
-                mMainStack.dismissKeyguardOnNextActivityLocked();
+                mStackSupervisor.setDismissKeyguard(true);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -4468,7 +4969,8 @@
                 if (pkgs != null) {
                     for (String pkg : pkgs) {
                         synchronized (ActivityManagerService.this) {
-                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0)) {
+                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0,
+                                    "finished booting")) {
                                 setResultCode(Activity.RESULT_OK);
                                 return;
                             }
@@ -4506,10 +5008,22 @@
                         final int userId = mStartedUsers.keyAt(i);
                         Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                        broadcastIntentLocked(null, null, intent,
-                                null, null, 0, null, null,
+                        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+                        broadcastIntentLocked(null, null, intent, null,
+                                new IIntentReceiver.Stub() {
+                                    @Override
+                                    public void performReceive(Intent intent, int resultCode,
+                                            String data, Bundle extras, boolean ordered,
+                                            boolean sticky, int sendingUser) {
+                                        synchronized (ActivityManagerService.this) {
+                                            requestPssAllProcsLocked(SystemClock.uptimeMillis(),
+                                                    true, false);
+                                        }
+                                    }
+                                },
+                                0, null, null,
                                 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
-                                AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
+                                AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
                                 userId);
                     }
                 }
@@ -4536,18 +5050,31 @@
         }
     }
 
+    @Override
     public final void activityResumed(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
-        mMainStack.activityResumed(token);
+        synchronized(this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                ActivityRecord.activityResumedLocked(token);
+            }
+        }
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public final void activityPaused(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
-        mMainStack.activityPaused(token, false);
+        synchronized(this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                stack.activityPausedLocked(token, false);
+            }
+        }
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
             CharSequence description) {
         if (localLOGV) Slog.v(
@@ -4563,9 +5090,9 @@
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            r = mMainStack.isInStackLocked(token);
+            r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.stack.activityStoppedLocked(r, icicle, thumbnail, description);
+                r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
             }
         }
 
@@ -4578,11 +5105,18 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public final void activityDestroyed(IBinder token) {
         if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
-        mMainStack.activityDestroyed(token);
+        synchronized (this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                stack.activityDestroyedLocked(token);
+            }
+        }
     }
     
+    @Override
     public String getCallingPackage(IBinder token) {
         synchronized (this) {
             ActivityRecord r = getCallingRecordLocked(token);
@@ -4590,6 +5124,7 @@
         }
     }
 
+    @Override
     public ComponentName getCallingActivity(IBinder token) {
         synchronized (this) {
             ActivityRecord r = getCallingRecordLocked(token);
@@ -4598,16 +5133,17 @@
     }
 
     private ActivityRecord getCallingRecordLocked(IBinder token) {
-        ActivityRecord r = mMainStack.isInStackLocked(token);
+        ActivityRecord r = ActivityRecord.isInStackLocked(token);
         if (r == null) {
             return null;
         }
         return r.resultTo;
     }
 
+    @Override
     public ComponentName getActivityClassForToken(IBinder token) {
         synchronized(this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return null;
             }
@@ -4615,9 +5151,10 @@
         }
     }
 
+    @Override
     public String getPackageForToken(IBinder token) {
         synchronized(this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return null;
             }
@@ -4625,6 +5162,7 @@
         }
     }
 
+    @Override
     public IIntentSender getIntentSender(int type,
             String packageName, IBinder token, String resultWho,
             int requestCode, Intent[] intents, String[] resolvedTypes,
@@ -4695,7 +5233,7 @@
             }
         }
     }
-    
+
     IIntentSender getIntentSenderLocked(int type, String packageName,
             int callingUid, int userId, IBinder token, String resultWho,
             int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
@@ -4704,7 +5242,7 @@
             Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
         ActivityRecord activity = null;
         if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
-            activity = mMainStack.isInStackLocked(token);
+            activity = ActivityRecord.isInStackLocked(token);
             if (activity == null) {
                 return null;
             }
@@ -4761,6 +5299,7 @@
         return rec;
     }
 
+    @Override
     public void cancelIntentSender(IIntentSender sender) {
         if (!(sender instanceof PendingIntentRecord)) {
             return;
@@ -4794,6 +5333,7 @@
         }
     }
 
+    @Override
     public String getPackageForIntentSender(IIntentSender pendingResult) {
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return null;
@@ -4806,6 +5346,7 @@
         return null;
     }
 
+    @Override
     public int getUidForIntentSender(IIntentSender sender) {
         if (sender instanceof PendingIntentRecord) {
             try {
@@ -4817,6 +5358,7 @@
         return -1;
     }
 
+    @Override
     public boolean isIntentSenderTargetedToPackage(IIntentSender pendingResult) {
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return false;
@@ -4838,6 +5380,7 @@
         return false;
     }
 
+    @Override
     public boolean isIntentSenderAnActivity(IIntentSender pendingResult) {
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return false;
@@ -4853,6 +5396,7 @@
         return false;
     }
 
+    @Override
     public Intent getIntentForIntentSender(IIntentSender pendingResult) {
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return null;
@@ -4865,16 +5409,18 @@
         return null;
     }
 
+    @Override
     public void setProcessLimit(int max) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessLimit()");
         synchronized (this) {
-            mProcessLimit = max < 0 ? ProcessList.MAX_HIDDEN_APPS : max;
+            mProcessLimit = max < 0 ? ProcessList.MAX_CACHED_APPS : max;
             mProcessLimitOverride = max;
         }
         trimApplications();
     }
 
+    @Override
     public int getProcessLimit() {
         synchronized (this) {
             return mProcessLimitOverride;
@@ -4900,7 +5446,8 @@
             updateOomAdjLocked();
         }
     }
-    
+
+    @Override
     public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessForeground()");
@@ -4924,6 +5471,7 @@
                 }
                 if (isForeground && token != null) {
                     ForegroundToken newToken = new ForegroundToken() {
+                        @Override
                         public void binderDied() {
                             foregroundTokenDied(this);
                         }
@@ -4958,6 +5506,7 @@
             mActivityManagerService = activityManagerService;
         }
 
+        @Override
         public boolean checkPermission(String permission, int pid, int uid) {
             return mActivityManagerService.checkPermission(permission, pid,
                     uid) == PackageManager.PERMISSION_GRANTED;
@@ -4965,12 +5514,14 @@
     }
 
     class IntentFirewallInterface implements IntentFirewall.AMSInterface {
+        @Override
         public int checkComponentPermission(String permission, int pid, int uid,
                 int owningUid, boolean exported) {
             return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
                     owningUid, exported);
         }
 
+        @Override
         public Object getAMSLock() {
             return ActivityManagerService.this;
         }
@@ -5009,6 +5560,7 @@
      * 
      * This can be called with or without the global lock held.
      */
+    @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
             return PackageManager.PERMISSION_DENIED;
@@ -5130,19 +5682,61 @@
         return readMet && writeMet;
     }
 
-    private final boolean checkUriPermissionLocked(Uri uri, int uid,
-            int modeFlags) {
+    private ProviderInfo getProviderInfoLocked(String authority, int userHandle) {
+        ProviderInfo pi = null;
+        ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userHandle);
+        if (cpr != null) {
+            pi = cpr.info;
+        } else {
+            try {
+                pi = AppGlobals.getPackageManager().resolveContentProvider(
+                        authority, PackageManager.GET_URI_PERMISSION_PATTERNS, userHandle);
+            } catch (RemoteException ex) {
+            }
+        }
+        return pi;
+    }
+
+    private UriPermission findUriPermissionLocked(int targetUid, Uri uri) {
+        ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+        if (targetUris != null) {
+            return targetUris.get(uri);
+        } else {
+            return null;
+        }
+    }
+
+    private UriPermission findOrCreateUriPermissionLocked(
+            String sourcePkg, String targetPkg, int targetUid, Uri uri) {
+        ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+        if (targetUris == null) {
+            targetUris = Maps.newArrayMap();
+            mGrantedUriPermissions.put(targetUid, targetUris);
+        }
+
+        UriPermission perm = targetUris.get(uri);
+        if (perm == null) {
+            perm = new UriPermission(sourcePkg, targetPkg, targetUid, uri);
+            targetUris.put(uri, perm);
+        }
+
+        return perm;
+    }
+
+    private final boolean checkUriPermissionLocked(
+            Uri uri, int uid, int modeFlags, int minStrength) {
         // Root gets to do everything.
         if (uid == 0) {
             return true;
         }
-        HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+        ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
         if (perms == null) return false;
         UriPermission perm = perms.get(uri);
         if (perm == null) return false;
-        return (modeFlags&perm.modeFlags) == modeFlags;
+        return perm.getStrength(modeFlags) >= minStrength;
     }
 
+    @Override
     public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
         enforceNotIsolatedCaller("checkUriPermission");
 
@@ -5159,7 +5753,7 @@
             return PackageManager.PERMISSION_GRANTED;
         }
         synchronized(this) {
-            return checkUriPermissionLocked(uri, uid, modeFlags)
+            return checkUriPermissionLocked(uri, uid, modeFlags, UriPermission.STRENGTH_OWNED)
                     ? PackageManager.PERMISSION_GRANTED
                     : PackageManager.PERMISSION_DENIED;
         }
@@ -5176,6 +5770,7 @@
      */
     int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
             Uri uri, int modeFlags, int lastTargetUid) {
+        final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
         if (modeFlags == 0) {
@@ -5196,20 +5791,8 @@
             return -1;
         }
 
-        String name = uri.getAuthority();
-        ProviderInfo pi = null;
-        ContentProviderRecord cpr = mProviderMap.getProviderByName(name,
-                UserHandle.getUserId(callingUid));
-        if (cpr != null) {
-            pi = cpr.info;
-        } else {
-            try {
-                pi = pm.resolveContentProvider(name,
-                        PackageManager.GET_URI_PERMISSION_PATTERNS,
-                        UserHandle.getUserId(callingUid));
-            } catch (RemoteException ex) {
-            }
-        }
+        final String authority = uri.getAuthority();
+        final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid));
         if (pi == null) {
             Slog.w(TAG, "No content provider found for permission check: " + uri.toSafeString());
             return -1;
@@ -5284,7 +5867,10 @@
         // this uri?
         if (callingUid != Process.myUid()) {
             if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
-                if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
+                // Require they hold a strong enough Uri permission
+                final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
+                        : UriPermission.STRENGTH_OWNED;
+                if (!checkUriPermissionLocked(uri, callingUid, modeFlags, minStrength)) {
                     throw new SecurityException("Uid " + callingUid
                             + " does not have permission to uri " + uri);
                 }
@@ -5294,6 +5880,7 @@
         return targetUid;
     }
 
+    @Override
     public int checkGrantUriPermission(int callingUid, String targetPkg,
             Uri uri, int modeFlags) {
         enforceNotIsolatedCaller("checkGrantUriPermission");
@@ -5302,8 +5889,9 @@
         }
     }
 
-    void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg,
-            Uri uri, int modeFlags, UriPermissionOwner owner) {
+    void grantUriPermissionUncheckedLocked(
+            int targetUid, String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
+        final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
         if (modeFlags == 0) {
@@ -5316,33 +5904,17 @@
 
         if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
                 "Granting " + targetPkg + "/" + targetUid + " permission to " + uri);
-        
-        HashMap<Uri, UriPermission> targetUris
-                = mGrantedUriPermissions.get(targetUid);
-        if (targetUris == null) {
-            targetUris = new HashMap<Uri, UriPermission>();
-            mGrantedUriPermissions.put(targetUid, targetUris);
+
+        final String authority = uri.getAuthority();
+        final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(targetUid));
+        if (pi == null) {
+            Slog.w(TAG, "No content provider found for grant: " + uri.toSafeString());
+            return;
         }
 
-        UriPermission perm = targetUris.get(uri);
-        if (perm == null) {
-            perm = new UriPermission(targetUid, uri);
-            targetUris.put(uri, perm);
-        }
-
-        perm.modeFlags |= modeFlags;
-        if (owner == null) {
-            perm.globalModeFlags |= modeFlags;
-        } else {
-            if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
-                 perm.readOwners.add(owner);
-                 owner.addReadPermission(perm);
-            }
-            if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
-                 perm.writeOwners.add(owner);
-                 owner.addWritePermission(perm);
-            }
-        }
+        final UriPermission perm = findOrCreateUriPermissionLocked(
+                pi.packageName, targetPkg, targetUid, uri);
+        perm.grantModes(modeFlags, persistable, owner);
     }
 
     void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
@@ -5364,10 +5936,10 @@
         final int targetUid;
         final int flags;
 
-        NeededUriGrants(String _targetPkg, int _targetUid, int _flags) {
-            targetPkg = _targetPkg;
-            targetUid = _targetUid;
-            flags = _flags;
+        NeededUriGrants(String targetPkg, int targetUid, int flags) {
+            this.targetPkg = targetPkg;
+            this.targetUid = targetUid;
+            this.flags = flags;
         }
     }
 
@@ -5394,12 +5966,13 @@
         if (data == null && clip == null) {
             return null;
         }
+
         if (data != null) {
-            int target = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
+            int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
                 mode, needed != null ? needed.targetUid : -1);
-            if (target > 0) {
+            if (targetUid > 0) {
                 if (needed == null) {
-                    needed = new NeededUriGrants(targetPkg, target, mode);
+                    needed = new NeededUriGrants(targetPkg, targetUid, mode);
                 }
                 needed.add(data);
             }
@@ -5408,12 +5981,12 @@
             for (int i=0; i<clip.getItemCount(); i++) {
                 Uri uri = clip.getItemAt(i).getUri();
                 if (uri != null) {
-                    int target = -1;
-                    target = checkGrantUriPermissionLocked(callingUid, targetPkg, uri,
+                    int targetUid = -1;
+                    targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri,
                             mode, needed != null ? needed.targetUid : -1);
-                    if (target > 0) {
+                    if (targetUid > 0) {
                         if (needed == null) {
-                            needed = new NeededUriGrants(targetPkg, target, mode);
+                            needed = new NeededUriGrants(targetPkg, targetUid, mode);
                         }
                         needed.add(uri);
                     }
@@ -5457,6 +6030,7 @@
         grantUriPermissionUncheckedFromIntentLocked(needed, owner);
     }
 
+    @Override
     public void grantUriPermission(IApplicationThread caller, String targetPkg,
             Uri uri, int modeFlags) {
         enforceNotIsolatedCaller("grantUriPermission");
@@ -5474,6 +6048,10 @@
                 throw new IllegalArgumentException("null uri");
             }
 
+            // Persistable only supported through Intents
+            Preconditions.checkFlagsArgument(modeFlags,
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
             grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
                     null);
         }
@@ -5482,45 +6060,25 @@
     void removeUriPermissionIfNeededLocked(UriPermission perm) {
         if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
                 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
-            HashMap<Uri, UriPermission> perms
-                    = mGrantedUriPermissions.get(perm.uid);
+            ArrayMap<Uri, UriPermission> perms
+                    = mGrantedUriPermissions.get(perm.targetUid);
             if (perms != null) {
                 if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                        "Removing " + perm.uid + " permission to " + perm.uri);
+                        "Removing " + perm.targetUid + " permission to " + perm.uri);
                 perms.remove(perm.uri);
                 if (perms.size() == 0) {
-                    mGrantedUriPermissions.remove(perm.uid);
+                    mGrantedUriPermissions.remove(perm.targetUid);
                 }
             }
         }
     }
 
-    private void revokeUriPermissionLocked(int callingUid, Uri uri,
-            int modeFlags) {
-        modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
-                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-        if (modeFlags == 0) {
-            return;
-        }
+    private void revokeUriPermissionLocked(int callingUid, Uri uri, int modeFlags) {
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
 
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                "Revoking all granted permissions to " + uri);
-        
         final IPackageManager pm = AppGlobals.getPackageManager();
-
         final String authority = uri.getAuthority();
-        ProviderInfo pi = null;
-        int userId = UserHandle.getUserId(callingUid);
-        ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
-        if (cpr != null) {
-            pi = cpr.info;
-        } else {
-            try {
-                pi = pm.resolveContentProvider(authority,
-                        PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
-            } catch (RemoteException ex) {
-            }
-        }
+        final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid));
         if (pi == null) {
             Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString());
             return;
@@ -5536,13 +6094,15 @@
             //}
         }
 
+        boolean persistChanged = false;
+
         // Go through all of the permissions and remove any that match.
         final List<String> SEGMENTS = uri.getPathSegments();
         if (SEGMENTS != null) {
             final int NS = SEGMENTS.size();
             int N = mGrantedUriPermissions.size();
             for (int i=0; i<N; i++) {
-                HashMap<Uri, UriPermission> perms
+                ArrayMap<Uri, UriPermission> perms
                         = mGrantedUriPermissions.valueAt(i);
                 Iterator<UriPermission> it = perms.values().iterator();
             toploop:
@@ -5565,8 +6125,8 @@
                         }
                     }
                     if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                            "Revoking " + perm.uid + " permission to " + perm.uri);
-                    perm.clearModes(modeFlags);
+                            "Revoking " + perm.targetUid + " permission to " + perm.uri);
+                    persistChanged |= perm.clearModes(modeFlags, true);
                     if (perm.modeFlags == 0) {
                         it.remove();
                     }
@@ -5579,8 +6139,13 @@
                 }
             }
         }
+
+        if (persistChanged) {
+            schedulePersistUriGrants();
+        }
     }
 
+    @Override
     public void revokeUriPermission(IApplicationThread caller, Uri uri,
             int modeFlags) {
         enforceNotIsolatedCaller("revokeUriPermission");
@@ -5603,19 +6168,8 @@
             }
 
             final IPackageManager pm = AppGlobals.getPackageManager();
-
             final String authority = uri.getAuthority();
-            ProviderInfo pi = null;
-            ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, r.userId);
-            if (cpr != null) {
-                pi = cpr.info;
-            } else {
-                try {
-                    pi = pm.resolveContentProvider(authority,
-                            PackageManager.GET_URI_PERMISSION_PATTERNS, r.userId);
-                } catch (RemoteException ex) {
-                }
-            }
+            final ProviderInfo pi = getProviderInfoLocked(authority, r.userId);
             if (pi == null) {
                 Slog.w(TAG, "No content provider found for permission revoke: "
                         + uri.toSafeString());
@@ -5626,6 +6180,54 @@
         }
     }
 
+    /**
+     * Remove any {@link UriPermission} granted <em>from</em> or <em>to</em> the
+     * given package.
+     *
+     * @param packageName Package name to match, or {@code null} to apply to all
+     *            packages.
+     * @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
+     *            to all users.
+     * @param persistable If persistable grants should be removed.
+     */
+    private void removeUriPermissionsForPackageLocked(
+            String packageName, int userHandle, boolean persistable) {
+        if (userHandle == UserHandle.USER_ALL && packageName == null) {
+            throw new IllegalArgumentException("Must narrow by either package or user");
+        }
+
+        boolean persistChanged = false;
+
+        final int size = mGrantedUriPermissions.size();
+        for (int i = 0; i < size; i++) {
+            // Only inspect grants matching user
+            if (userHandle == UserHandle.USER_ALL
+                    || userHandle == UserHandle.getUserId(mGrantedUriPermissions.keyAt(i))) {
+                final Iterator<UriPermission> it = mGrantedUriPermissions.valueAt(i)
+                        .values().iterator();
+                while (it.hasNext()) {
+                    final UriPermission perm = it.next();
+
+                    // Only inspect grants matching package
+                    if (packageName == null || perm.sourcePkg.equals(packageName)
+                            || perm.targetPkg.equals(packageName)) {
+                        persistChanged |= perm.clearModes(~0, persistable);
+
+                        // Only remove when no modes remain; any persisted grants
+                        // will keep this alive.
+                        if (perm.modeFlags == 0) {
+                            it.remove();
+                        }
+                    }
+                }
+            }
+        }
+
+        if (persistChanged) {
+            schedulePersistUriGrants();
+        }
+    }
+
     @Override
     public IBinder newUriPermissionOwner(String name) {
         enforceNotIsolatedCaller("newUriPermissionOwner");
@@ -5677,6 +6279,224 @@
         }
     }
 
+    private void schedulePersistUriGrants() {
+        if (!mHandler.hasMessages(PERSIST_URI_GRANTS_MSG)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG),
+                    10 * DateUtils.SECOND_IN_MILLIS);
+        }
+    }
+
+    private void writeGrantedUriPermissions() {
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "writeGrantedUriPermissions()");
+
+        // Snapshot permissions so we can persist without lock
+        ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
+        synchronized (this) {
+            final int size = mGrantedUriPermissions.size();
+            for (int i = 0 ; i < size; i++) {
+                for (UriPermission perm : mGrantedUriPermissions.valueAt(i).values()) {
+                    if (perm.persistedModeFlags != 0) {
+                        persist.add(perm.snapshot());
+                    }
+                }
+            }
+        }
+
+        FileOutputStream fos = null;
+        try {
+            fos = mGrantFile.startWrite();
+
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, "utf-8");
+            out.startDocument(null, true);
+            out.startTag(null, TAG_URI_GRANTS);
+            for (UriPermission.Snapshot perm : persist) {
+                out.startTag(null, TAG_URI_GRANT);
+                writeIntAttribute(out, ATTR_USER_HANDLE, perm.userHandle);
+                out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
+                out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
+                out.attribute(null, ATTR_URI, String.valueOf(perm.uri));
+                writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
+                writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
+                out.endTag(null, TAG_URI_GRANT);
+            }
+            out.endTag(null, TAG_URI_GRANTS);
+            out.endDocument();
+
+            mGrantFile.finishWrite(fos);
+        } catch (IOException e) {
+            if (fos != null) {
+                mGrantFile.failWrite(fos);
+            }
+        }
+    }
+
+    private void readGrantedUriPermissionsLocked() {
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "readGrantedUriPermissions()");
+
+        final long now = System.currentTimeMillis();
+
+        FileInputStream fis = null;
+        try {
+            fis = mGrantFile.openRead();
+            final XmlPullParser in = Xml.newPullParser();
+            in.setInput(fis, null);
+
+            int type;
+            while ((type = in.next()) != END_DOCUMENT) {
+                final String tag = in.getName();
+                if (type == START_TAG) {
+                    if (TAG_URI_GRANT.equals(tag)) {
+                        final int userHandle = readIntAttribute(in, ATTR_USER_HANDLE);
+                        final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
+                        final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
+                        final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
+                        final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
+                        final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
+
+                        // Sanity check that provider still belongs to source package
+                        final ProviderInfo pi = getProviderInfoLocked(
+                                uri.getAuthority(), userHandle);
+                        if (pi != null && sourcePkg.equals(pi.packageName)) {
+                            int targetUid = -1;
+                            try {
+                                targetUid = AppGlobals.getPackageManager()
+                                        .getPackageUid(targetPkg, userHandle);
+                            } catch (RemoteException e) {
+                            }
+                            if (targetUid != -1) {
+                                final UriPermission perm = findOrCreateUriPermissionLocked(
+                                        sourcePkg, targetPkg, targetUid, uri);
+                                perm.initPersistedModes(modeFlags, createdTime);
+                            }
+                        } else {
+                            Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
+                                    + " but instead found " + pi);
+                        }
+                    }
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // Missing grants is okay
+        } catch (IOException e) {
+            Log.wtf(TAG, "Failed reading Uri grants", e);
+        } catch (XmlPullParserException e) {
+            Log.wtf(TAG, "Failed reading Uri grants", e);
+        } finally {
+            IoUtils.closeQuietly(fis);
+        }
+    }
+
+    @Override
+    public void takePersistableUriPermission(Uri uri, int modeFlags) {
+        enforceNotIsolatedCaller("takePersistableUriPermission");
+
+        Preconditions.checkFlagsArgument(modeFlags,
+                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+        synchronized (this) {
+            final int callingUid = Binder.getCallingUid();
+            final UriPermission perm = findUriPermissionLocked(callingUid, uri);
+            if (perm == null) {
+                Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
+                        + uri.toSafeString());
+                return;
+            }
+
+            boolean persistChanged = perm.takePersistableModes(modeFlags);
+            persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
+
+            if (persistChanged) {
+                schedulePersistUriGrants();
+            }
+        }
+    }
+
+    @Override
+    public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+        enforceNotIsolatedCaller("releasePersistableUriPermission");
+
+        Preconditions.checkFlagsArgument(modeFlags,
+                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+        synchronized (this) {
+            final int callingUid = Binder.getCallingUid();
+
+            final UriPermission perm = findUriPermissionLocked(callingUid, uri);
+            if (perm == null) {
+                Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
+                        + uri.toSafeString());
+                return;
+            }
+
+            final boolean persistChanged = perm.releasePersistableModes(modeFlags);
+            removeUriPermissionIfNeededLocked(perm);
+            if (persistChanged) {
+                schedulePersistUriGrants();
+            }
+        }
+    }
+
+    /**
+     * Prune any older {@link UriPermission} for the given UID until outstanding
+     * persisted grants are below {@link #MAX_PERSISTED_URI_GRANTS}.
+     *
+     * @return if any mutations occured that require persisting.
+     */
+    private boolean maybePrunePersistedUriGrantsLocked(int uid) {
+        final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+        if (perms == null) return false;
+        if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
+
+        final ArrayList<UriPermission> persisted = Lists.newArrayList();
+        for (UriPermission perm : perms.values()) {
+            if (perm.persistedModeFlags != 0) {
+                persisted.add(perm);
+            }
+        }
+
+        final int trimCount = persisted.size() - MAX_PERSISTED_URI_GRANTS;
+        if (trimCount <= 0) return false;
+
+        Collections.sort(persisted, new UriPermission.PersistedTimeComparator());
+        for (int i = 0; i < trimCount; i++) {
+            final UriPermission perm = persisted.get(i);
+
+            if (DEBUG_URI_PERMISSION) {
+                Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
+            }
+
+            perm.releasePersistableModes(~0);
+            removeUriPermissionIfNeededLocked(perm);
+        }
+
+        return true;
+    }
+
+    @Override
+    public ParceledListSlice<android.content.UriPermission> getPersistedUriPermissions() {
+        enforceNotIsolatedCaller("getPersistedUriPermissions");
+
+        synchronized (this) {
+            final int callingUid = Binder.getCallingUid();
+            final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+            final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+            if (perms == null) {
+                Slog.w(TAG, "No permission grants found for UID " + callingUid);
+            } else {
+                final int size = perms.size();
+                for (int i = 0; i < size; i++) {
+                    final UriPermission perm = perms.valueAt(i);
+                    if (perm.persistedModeFlags != 0) {
+                        result.add(perm.buildPersistedPublicApiObject());
+                    }
+                }
+            }
+            return new ParceledListSlice<android.content.UriPermission>(result);
+        }
+    }
+
+    @Override
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
         synchronized (this) {
             ProcessRecord app =
@@ -5691,14 +6511,15 @@
         }
     }
 
+    @Override
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
         final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
-        final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
+        final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ);
         outInfo.availMem = Process.getFreeMemory();
         outInfo.totalMem = Process.getTotalMemory();
         outInfo.threshold = homeAppMem;
-        outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
-        outInfo.hiddenAppThreshold = hiddenAppMem;
+        outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2));
+        outInfo.hiddenAppThreshold = cachedAppMem;
         outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
                 ProcessList.SERVICE_ADJ);
         outInfo.visibleAppThreshold = mProcessList.getMemLevel(
@@ -5711,12 +6532,12 @@
     // TASK MANAGEMENT
     // =========================================================
 
-    public List getTasks(int maxNum, int flags,
+    @Override
+    public List<RunningTaskInfo> getTasks(int maxNum, int flags,
                          IThumbnailReceiver receiver) {
-        ArrayList list = new ArrayList();
+        ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
 
-        PendingThumbnailsRecord pending = null;
-        IApplicationThread topThumbnail = null;
+        PendingThumbnailsRecord pending = new PendingThumbnailsRecord(receiver);
         ActivityRecord topRecord = null;
 
         synchronized(this) {
@@ -5742,88 +6563,20 @@
                 throw new SecurityException(msg);
             }
 
-            int pos = mMainStack.mHistory.size()-1;
-            ActivityRecord next =
-                pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
-            ActivityRecord top = null;
-            TaskRecord curTask = null;
-            int numActivities = 0;
-            int numRunning = 0;
-            while (pos >= 0 && maxNum > 0) {
-                final ActivityRecord r = next;
-                pos--;
-                next = pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
+            // TODO: Improve with MRU list from all ActivityStacks.
+            topRecord = mStackSupervisor.getTasksLocked(maxNum, receiver, pending, list);
 
-                // Initialize state for next task if needed.
-                if (top == null ||
-                        (top.state == ActivityState.INITIALIZING
-                            && top.task == r.task)) {
-                    top = r;
-                    curTask = r.task;
-                    numActivities = numRunning = 0;
-                }
-
-                // Add 'r' into the current task.
-                numActivities++;
-                if (r.app != null && r.app.thread != null) {
-                    numRunning++;
-                }
-
-                if (localLOGV) Slog.v(
-                    TAG, r.intent.getComponent().flattenToShortString()
-                    + ": task=" + r.task);
-
-                // If the next one is a different task, generate a new
-                // TaskInfo entry for what we have.
-                if (next == null || next.task != curTask) {
-                    ActivityManager.RunningTaskInfo ci
-                            = new ActivityManager.RunningTaskInfo();
-                    ci.id = curTask.taskId;
-                    ci.baseActivity = r.intent.getComponent();
-                    ci.topActivity = top.intent.getComponent();
-                    if (top.thumbHolder != null) {
-                        ci.description = top.thumbHolder.lastDescription;
-                    }
-                    ci.numActivities = numActivities;
-                    ci.numRunning = numRunning;
-                    //System.out.println(
-                    //    "#" + maxNum + ": " + " descr=" + ci.description);
-                    if (ci.thumbnail == null && receiver != null) {
-                        if (localLOGV) Slog.v(
-                            TAG, "State=" + top.state + "Idle=" + top.idle
-                            + " app=" + top.app
-                            + " thr=" + (top.app != null ? top.app.thread : null));
-                        if (top.state == ActivityState.RESUMED
-                                || top.state == ActivityState.PAUSING) {
-                            if (top.idle && top.app != null
-                                && top.app.thread != null) {
-                                topRecord = top;
-                                topThumbnail = top.app.thread;
-                            } else {
-                                top.thumbnailNeeded = true;
-                            }
-                        }
-                        if (pending == null) {
-                            pending = new PendingThumbnailsRecord(receiver);
-                        }
-                        pending.pendingRecords.add(top);
-                    }
-                    list.add(ci);
-                    maxNum--;
-                    top = null;
-                }
-            }
-
-            if (pending != null) {
+            if (!pending.pendingRecords.isEmpty()) {
                 mPendingThumbnails.add(pending);
             }
         }
 
         if (localLOGV) Slog.v(TAG, "We have pending thumbnails: " + pending);
 
-        if (topThumbnail != null) {
+        if (topRecord != null) {
             if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
             try {
+                IApplicationThread topThumbnail = topRecord.app.thread;
                 topThumbnail.requestThumbnail(topRecord.appToken);
             } catch (Exception e) {
                 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
@@ -5845,6 +6598,7 @@
         return list;
     }
 
+    @Override
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
             int flags, int userId) {
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
@@ -5889,7 +6643,8 @@
                     }
                     rti.origActivity = tr.origActivity;
                     rti.description = tr.lastDescription;
-                    
+                    rti.stackId = tr.stack.mStackId;
+
                     if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
                         // Check whether this activity is currently available.
                         try {
@@ -5917,56 +6672,74 @@
         }
     }
 
-    private TaskRecord taskForIdLocked(int id) {
+    private TaskRecord recentTaskForIdLocked(int id) {
         final int N = mRecentTasks.size();
-        for (int i=0; i<N; i++) {
-            TaskRecord tr = mRecentTasks.get(i);
-            if (tr.taskId == id) {
-                return tr;
+            for (int i=0; i<N; i++) {
+                TaskRecord tr = mRecentTasks.get(i);
+                if (tr.taskId == id) {
+                    return tr;
+                }
             }
-        }
-        return null;
+            return null;
     }
 
+    @Override
     public ActivityManager.TaskThumbnails getTaskThumbnails(int id) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnails()");
-            TaskRecord tr = taskForIdLocked(id);
+            TaskRecord tr = recentTaskForIdLocked(id);
             if (tr != null) {
-                return mMainStack.getTaskThumbnailsLocked(tr);
+                return tr.getTaskThumbnailsLocked();
             }
         }
         return null;
     }
 
+    @Override
     public Bitmap getTaskTopThumbnail(int id) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskTopThumbnail()");
-            TaskRecord tr = taskForIdLocked(id);
+            TaskRecord tr = recentTaskForIdLocked(id);
             if (tr != null) {
-                return mMainStack.getTaskTopThumbnailLocked(tr);
+                return tr.getTaskTopThumbnailLocked();
             }
         }
         return null;
     }
 
+    @Override
     public boolean removeSubTask(int taskId, int subTaskIndex) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
                     "removeSubTask()");
             long ident = Binder.clearCallingIdentity();
             try {
-                return mMainStack.removeTaskActivitiesLocked(taskId, subTaskIndex,
-                        true) != null;
+                TaskRecord tr = recentTaskForIdLocked(taskId);
+                if (tr != null) {
+                    return tr.removeTaskActivitiesLocked(subTaskIndex, true) != null;
+                }
+                return false;
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
     }
 
+    private void killUnneededProcessLocked(ProcessRecord pr, String reason) {
+        if (!pr.killedByAm) {
+            Slog.i(TAG, "Killing " + pr.toShortString() + " (adj " + pr.setAdj + "): " + reason);
+            EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
+                    pr.processName, pr.setAdj, reason);
+            pr.killedByAm = true;
+            Process.killProcessQuiet(pr.pid);
+        }
+    }
+
     private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) {
+        mRecentTasks.remove(tr);
+        mStackSupervisor.removeTask(tr);
         final boolean killProcesses = (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0;
         Intent baseIntent = new Intent(
                 tr.intent != null ? tr.intent : tr.affinityIntent);
@@ -5983,14 +6756,15 @@
             // Find any running processes associated with this app.
             final String pkg = component.getPackageName();
             ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
-            HashMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
-            for (SparseArray<ProcessRecord> uids : pmap.values()) {
-                for (int i=0; i<uids.size(); i++) {
-                    ProcessRecord proc = uids.valueAt(i);
+            ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
+            for (int i=0; i<pmap.size(); i++) {
+                SparseArray<ProcessRecord> uids = pmap.valueAt(i);
+                for (int j=0; j<uids.size(); j++) {
+                    ProcessRecord proc = uids.valueAt(j);
                     if (proc.userId != tr.userId) {
                         continue;
                     }
-                    if (!proc.pkgList.contains(pkg)) {
+                    if (!proc.pkgList.containsKey(pkg)) {
                         continue;
                     }
                     procs.add(proc);
@@ -6000,12 +6774,12 @@
             // Kill the running processes.
             for (int i=0; i<procs.size(); i++) {
                 ProcessRecord pr = procs.get(i);
+                if (pr == mHomeProcess) {
+                    // Don't kill the home process along with tasks from the same package.
+                    continue;
+                }
                 if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
-                    Slog.i(TAG, "Killing " + pr.toShortString() + ": remove task");
-                    EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
-                            pr.processName, pr.setAdj, "remove task");
-                    pr.killedBackground = true;
-                    Process.killProcessQuiet(pr.pid);
+                    killUnneededProcessLocked(pr, "remove task");
                 } else {
                     pr.waitingToKill = "remove task";
                 }
@@ -6013,43 +6787,30 @@
         }
     }
 
+    @Override
     public boolean removeTask(int taskId, int flags) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
                     "removeTask()");
             long ident = Binder.clearCallingIdentity();
             try {
-                ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1,
-                        false);
-                if (r != null) {
-                    mRecentTasks.remove(r.task);
-                    cleanUpRemovedTaskLocked(r.task, flags);
-                    return true;
-                } else {
-                    TaskRecord tr = null;
-                    int i=0;
-                    while (i < mRecentTasks.size()) {
-                        TaskRecord t = mRecentTasks.get(i);
-                        if (t.taskId == taskId) {
-                            tr = t;
-                            break;
-                        }
-                        i++;
+                TaskRecord tr = recentTaskForIdLocked(taskId);
+                if (tr != null) {
+                    ActivityRecord r = tr.removeTaskActivitiesLocked(-1, false);
+                    if (r != null) {
+                        cleanUpRemovedTaskLocked(tr, flags);
+                        return true;
                     }
-                    if (tr != null) {
-                        if (tr.numActivities <= 0) {
-                            // Caller is just removing a recent task that is
-                            // not actively running.  That is easy!
-                            mRecentTasks.remove(i);
-                            cleanUpRemovedTaskLocked(tr, flags);
-                            return true;
-                        } else {
-                            Slog.w(TAG, "removeTask: task " + taskId
-                                    + " does not have activities to remove, "
-                                    + " but numActivities=" + tr.numActivities
-                                    + ": " + tr);
-                        }
+                    if (tr.mActivities.size() == 0) {
+                        // Caller is just removing a recent task that is
+                        // not actively running.  That is easy!
+                        cleanUpRemovedTaskLocked(tr, flags);
+                        return true;
                     }
+                    Slog.w(TAG, "removeTask: task " + taskId
+                            + " does not have activities to remove, "
+                            + " but numActivities=" + tr.numActivities
+                            + ": " + tr);
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -6058,50 +6819,15 @@
         return false;
     }
     
-    private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
-        int j;
-        TaskRecord startTask = ((ActivityRecord)mMainStack.mHistory.get(startIndex)).task; 
-        TaskRecord jt = startTask;
-        
-        // First look backwards
-        for (j=startIndex-1; j>=0; j--) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
-            if (r.task != jt) {
-                jt = r.task;
-                if (affinity.equals(jt.affinity)) {
-                    return j;
-                }
-            }
-        }
-        
-        // Now look forwards
-        final int N = mMainStack.mHistory.size();
-        jt = startTask;
-        for (j=startIndex+1; j<N; j++) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
-            if (r.task != jt) {
-                if (affinity.equals(jt.affinity)) {
-                    return j;
-                }
-                jt = r.task;
-            }
-        }
-        
-        // Might it be at the top?
-        if (affinity.equals(((ActivityRecord)mMainStack.mHistory.get(N-1)).task.affinity)) {
-            return N-1;
-        }
-        
-        return -1;
-    }
-    
     /**
      * TODO: Add mController hook
      */
+    @Override
     public void moveTaskToFront(int task, int flags, Bundle options) {
         enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
                 "moveTaskToFront()");
 
+        if (DEBUG_STACK) Slog.d(TAG, "moveTaskToFront: moving task=" + task);
         synchronized(this) {
             if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
                     Binder.getCallingUid(), "Task to front")) {
@@ -6110,34 +6836,7 @@
             }
             final long origId = Binder.clearCallingIdentity();
             try {
-                TaskRecord tr = taskForIdLocked(task);
-                if (tr != null) {
-                    if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
-                        mMainStack.mUserLeaving = true;
-                    }
-                    if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
-                        // Caller wants the home activity moved with it.  To accomplish this,
-                        // we'll just move the home task to the top first.
-                        mMainStack.moveHomeToFrontLocked();
-                    }
-                    mMainStack.moveTaskToFrontLocked(tr, null, options);
-                    return;
-                }
-                for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
-                    ActivityRecord hr = (ActivityRecord)mMainStack.mHistory.get(i);
-                    if (hr.task.taskId == task) {
-                        if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
-                            mMainStack.mUserLeaving = true;
-                        }
-                        if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
-                            // Caller wants the home activity moved with it.  To accomplish this,
-                            // we'll just move the home task to the top first.
-                            mMainStack.moveHomeToFrontLocked();
-                        }
-                        mMainStack.moveTaskToFrontLocked(hr.task, null, options);
-                        return;
-                    }
-                }
+                mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -6145,21 +6844,29 @@
         }
     }
 
-    public void moveTaskToBack(int task) {
+    @Override
+    public void moveTaskToBack(int taskId) {
         enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
                 "moveTaskToBack()");
 
         synchronized(this) {
-            if (mMainStack.mResumedActivity != null
-                    && mMainStack.mResumedActivity.task.taskId == task) {
-                if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
-                        Binder.getCallingUid(), "Task to back")) {
-                    return;
+            TaskRecord tr = recentTaskForIdLocked(taskId);
+            if (tr != null) {
+                if (DEBUG_STACK) Slog.d(TAG, "moveTaskToBack: moving task=" + tr);
+                ActivityStack stack = tr.stack;
+                if (stack.mResumedActivity != null && stack.mResumedActivity.task == tr) {
+                    if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+                            Binder.getCallingUid(), "Task to back")) {
+                        return;
+                    }
+                }
+                final long origId = Binder.clearCallingIdentity();
+                try {
+                    stack.moveTaskToBackLocked(taskId, null);
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
                 }
             }
-            final long origId = Binder.clearCallingIdentity();
-            mMainStack.moveTaskToBackLocked(task, null);
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -6172,19 +6879,21 @@
      *                of a task; if true it will work for any activity in a task.
      * @return Returns true if the move completed, false if not.
      */
+    @Override
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
         enforceNotIsolatedCaller("moveActivityTaskToBack");
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            int taskId = getTaskForActivityLocked(token, !nonRoot);
+            int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
             if (taskId >= 0) {
-                return mMainStack.moveTaskToBackLocked(taskId, null);
+                return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId, null);
             }
             Binder.restoreCallingIdentity(origId);
         }
         return false;
     }
 
+    @Override
     public void moveTaskBackwards(int task) {
         enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
                 "moveTaskBackwards()");
@@ -6204,27 +6913,151 @@
         Slog.e(TAG, "moveTaskBackwards not yet implemented!");
     }
 
-    public int getTaskForActivity(IBinder token, boolean onlyRoot) {
-        synchronized(this) {
-            return getTaskForActivityLocked(token, onlyRoot);
+    @Override
+    public int createStack(int taskId, int relativeStackBoxId, int position, float weight) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "createStack()");
+        if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" +
+                relativeStackBoxId + " position=" + position + " weight=" + weight);
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                int stackId = mStackSupervisor.createStack();
+                mWindowManager.createStack(stackId, relativeStackBoxId, position, weight);
+                if (taskId > 0) {
+                    moveTaskToStack(taskId, stackId, true);
+                }
+                return stackId;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
-    int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
-        final int N = mMainStack.mHistory.size();
-        TaskRecord lastTask = null;
-        for (int i=0; i<N; i++) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            if (r.appToken == token) {
-                if (!onlyRoot || lastTask != r.task) {
-                    return r.task.taskId;
-                }
-                return -1;
-            }
-            lastTask = r.task;
+    @Override
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "moveTaskToStack()");
+        if (stackId == HOME_STACK_ID) {
+            Slog.e(TAG, "moveTaskToStack: Attempt to move task " + taskId + " to home stack",
+                    new RuntimeException("here").fillInStackTrace());
         }
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG_STACK) Slog.d(TAG, "moveTaskToStack: moving task=" + taskId + " to stackId="
+                        + stackId + " toTop=" + toTop);
+                mStackSupervisor.moveTaskToStack(taskId, stackId, toTop);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
 
-        return -1;
+    @Override
+    public void resizeStackBox(int stackBoxId, float weight) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizeStackBox()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mWindowManager.resizeStackBox(stackBoxId, weight);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private ArrayList<StackInfo> getStacks() {
+        synchronized (this) {
+            ArrayList<ActivityManager.StackInfo> list = new ArrayList<ActivityManager.StackInfo>();
+            ArrayList<ActivityStack> stacks = mStackSupervisor.getStacks();
+            for (ActivityStack stack : stacks) {
+                ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
+                int stackId = stack.mStackId;
+                stackInfo.stackId = stackId;
+                stackInfo.bounds = mWindowManager.getStackBounds(stackId);
+                ArrayList<TaskRecord> tasks = stack.getAllTasks();
+                final int numTasks = tasks.size();
+                int[] taskIds = new int[numTasks];
+                String[] taskNames = new String[numTasks];
+                for (int i = 0; i < numTasks; ++i) {
+                    final TaskRecord task = tasks.get(i);
+                    taskIds[i] = task.taskId;
+                    taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
+                            : task.realActivity != null ? task.realActivity.flattenToString()
+                            : task.getTopActivity() != null ? task.getTopActivity().packageName
+                            : "unknown";
+                }
+                stackInfo.taskIds = taskIds;
+                stackInfo.taskNames = taskNames;
+                list.add(stackInfo);
+            }
+            return list;
+        }
+    }
+
+    private void addStackInfoToStackBoxInfo(StackBoxInfo stackBoxInfo, List<StackInfo> stackInfos) {
+        final int stackId = stackBoxInfo.stackId;
+        if (stackId >= 0) {
+            for (StackInfo stackInfo : stackInfos) {
+                if (stackId == stackInfo.stackId) {
+                    stackBoxInfo.stack = stackInfo;
+                    stackInfos.remove(stackInfo);
+                    return;
+                }
+            }
+        } else {
+            addStackInfoToStackBoxInfo(stackBoxInfo.children[0], stackInfos);
+            addStackInfoToStackBoxInfo(stackBoxInfo.children[1], stackInfos);
+        }
+    }
+
+    @Override
+    public List<StackBoxInfo> getStackBoxes() {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "getStackBoxes()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
+            synchronized (this) {
+                List<StackInfo> stackInfos = getStacks();
+                for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
+                    addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
+                }
+            }
+            return stackBoxInfos;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public StackBoxInfo getStackBoxInfo(int stackBoxId) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "getStackBoxInfo()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
+            StackBoxInfo info = null;
+            synchronized (this) {
+                List<StackInfo> stackInfos = getStacks();
+                for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
+                    addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
+                    if (stackBoxInfo.stackBoxId == stackBoxId) {
+                        info = stackBoxInfo;
+                    }
+                }
+            }
+            return info;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public int getTaskForActivity(IBinder token, boolean onlyRoot) {
+        synchronized(this) {
+            return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
+        }
     }
 
     // =========================================================
@@ -6241,14 +7074,14 @@
 
     final void sendPendingThumbnail(ActivityRecord r, IBinder token,
             Bitmap thumbnail, CharSequence description, boolean always) {
-        TaskRecord task = null;
-        ArrayList receivers = null;
+        TaskRecord task;
+        ArrayList<PendingThumbnailsRecord> receivers = null;
 
         //System.out.println("Send pending thumbnail: " + r);
 
         synchronized(this) {
             if (r == null) {
-                r = mMainStack.isInStackLocked(token);
+                r = ActivityRecord.isInStackLocked(token);
                 if (r == null) {
                     return;
                 }
@@ -6268,12 +7101,11 @@
             int N = mPendingThumbnails.size();
             int i=0;
             while (i<N) {
-                PendingThumbnailsRecord pr =
-                    (PendingThumbnailsRecord)mPendingThumbnails.get(i);
+                PendingThumbnailsRecord pr = mPendingThumbnails.get(i);
                 //System.out.println("Looking in " + pr.pendingRecords);
                 if (pr.pendingRecords.remove(r)) {
                     if (receivers == null) {
-                        receivers = new ArrayList();
+                        receivers = new ArrayList<PendingThumbnailsRecord>();
                     }
                     receivers.add(pr);
                     if (pr.pendingRecords.size() == 0) {
@@ -6291,8 +7123,7 @@
             final int N = receivers.size();
             for (int i=0; i<N; i++) {
                 try {
-                    PendingThumbnailsRecord pr =
-                        (PendingThumbnailsRecord)receivers.get(i);
+                    PendingThumbnailsRecord pr = receivers.get(i);
                     pr.receiver.newThumbnail(
                         task != null ? task.taskId : -1, thumbnail, description);
                     if (pr.finished) {
@@ -6322,6 +7153,7 @@
         int userId = app.userId;
         if (providers != null) {
             int N = providers.size();
+            app.pubProviders.ensureCapacity(N + app.pubProviders.size());
             for (int i=0; i<N; i++) {
                 ProviderInfo cpi =
                     (ProviderInfo)providers.get(i);
@@ -6347,7 +7179,7 @@
                 if (DEBUG_MU)
                     Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
                 app.pubProviders.put(cpi.name, cpr);
-                app.addPackage(cpi.applicationInfo.packageName);
+                app.addPackage(cpi.applicationInfo.packageName, mProcessStats);
                 ensurePackageDexOpt(cpi.applicationInfo.packageName);
             }
         }
@@ -6393,7 +7225,7 @@
             }
         }
         
-        HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+        ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
         if (perms != null) {
             for (Map.Entry<Uri, UriPermission> uri : perms.entrySet()) {
                 if (uri.getKey().getAuthority().equals(cpi.authority)) {
@@ -6531,7 +7363,7 @@
                         // make sure to count it as being accessed and thus
                         // back up on the LRU list.  This is good because
                         // content providers are often expensive to start.
-                        updateLruProcessLocked(cpr.proc, false);
+                        updateLruProcessLocked(cpr.proc, false, false);
                     }
                 }
 
@@ -6647,7 +7479,7 @@
 
                 if (DEBUG_PROVIDER) {
                     RuntimeException e = new RuntimeException("here");
-                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.uid
+                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
                           + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
                 }
 
@@ -6681,7 +7513,7 @@
                         ProcessRecord proc = startProcessLocked(cpi.processName,
                                 cpr.appInfo, false, 0, "content provider",
                                 new ComponentName(cpi.applicationInfo.packageName,
-                                        cpi.name), false, false);
+                                        cpi.name), false, false, false);
                         if (proc == null) {
                             Slog.w(TAG, "Unable to launch app "
                                     + cpi.applicationInfo.packageName + "/"
@@ -6991,6 +7823,31 @@
         }
     }
 
+    @Override
+    public void appNotRespondingViaProvider(IBinder connection) {
+        enforceCallingPermission(
+                android.Manifest.permission.REMOVE_TASKS, "appNotRespondingViaProvider()");
+
+        final ContentProviderConnection conn = (ContentProviderConnection) connection;
+        if (conn == null) {
+            Slog.w(TAG, "ContentProviderConnection is null");
+            return;
+        }
+
+        final ProcessRecord host = conn.provider.proc;
+        if (host == null) {
+            Slog.w(TAG, "Failed to find hosting ProcessRecord");
+            return;
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            appNotResponding(host, null, null, false, "ContentProvider not responding");
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     public static final void installSystemProviders() {
         List<ProviderInfo> providers;
         synchronized (mSelf) {
@@ -7055,8 +7912,8 @@
     // GLOBAL MANAGEMENT
     // =========================================================
 
-    final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
-            ApplicationInfo info, String customProcess, boolean isolated) {
+    final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
+            boolean isolated) {
         String proc = customProcess != null ? customProcess : info.processName;
         BatteryStatsImpl.Uid.Proc ps = null;
         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
@@ -7064,7 +7921,6 @@
         if (isolated) {
             int userId = UserHandle.getUserId(uid);
             int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
-            uid = 0;
             while (true) {
                 if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
                         || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
@@ -7085,24 +7941,24 @@
         synchronized (stats) {
             ps = stats.getProcessStatsLocked(info.uid, proc);
         }
-        return new ProcessRecord(ps, thread, info, proc, uid);
+        return new ProcessRecord(ps, info, proc, uid);
     }
 
     final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
         ProcessRecord app;
         if (!isolated) {
-            app = getProcessRecordLocked(info.processName, info.uid);
+            app = getProcessRecordLocked(info.processName, info.uid, true);
         } else {
             app = null;
         }
 
         if (app == null) {
-            app = newProcessRecordLocked(null, info, null, isolated);
+            app = newProcessRecordLocked(info, null, isolated);
             mProcessNames.put(info.processName, app.uid, app);
             if (isolated) {
                 mIsolatedProcesses.put(app.uid, app);
             }
-            updateLruProcessLocked(app, true);
+            updateLruProcessLocked(app, true, false);
         }
 
         // This package really, really can not be stopped.
@@ -7133,13 +7989,10 @@
                 "unhandledBack()");
 
         synchronized(this) {
-            int count = mMainStack.mHistory.size();
-            if (DEBUG_SWITCH) Slog.d(
-                TAG, "Performing unhandledBack(): stack size = " + count);
-            if (count > 1) {
-                final long origId = Binder.clearCallingIdentity();
-                mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1),
-                        count-1, Activity.RESULT_CANCELED, null, "unhandled-back", true);
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                getFocusedStack().unhandledBackLocked();
+            } finally {
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -7162,7 +8015,7 @@
             sCallerIdentity.set(new Identity(
                     Binder.getCallingPid(), Binder.getCallingUid()));
             try {
-                pfd = cph.provider.openFile(null, uri, "r");
+                pfd = cph.provider.openFile(null, uri, "r", null);
             } catch (FileNotFoundException e) {
                 // do nothing; pfd will be returned null
             } finally {
@@ -7180,7 +8033,7 @@
 
     // Actually is sleeping or shutting down or whatever else in the future
     // is an inactive state.
-    public boolean isSleeping() {
+    public boolean isSleepingOrShuttingDown() {
         return mSleeping || mShuttingDown;
     }
 
@@ -7197,7 +8050,7 @@
 
             if (!mSleeping) {
                 mSleeping = true;
-                mMainStack.stopIfSleepingLocked();
+                mStackSupervisor.goingToSleepLocked();
 
                 // Initialize the wake times of all processes.
                 checkExcessivePowerUsageLocked(false);
@@ -7208,69 +8061,59 @@
         }
     }
 
+    @Override
     public boolean shutdown(int timeout) {
         if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.SHUTDOWN);
         }
-        
+
         boolean timedout = false;
-        
+
         synchronized(this) {
             mShuttingDown = true;
             updateEventDispatchingLocked();
-
-            if (mMainStack.mResumedActivity != null) {
-                mMainStack.stopIfSleepingLocked();
-                final long endTime = System.currentTimeMillis() + timeout;
-                while (mMainStack.mResumedActivity != null
-                        || mMainStack.mPausingActivity != null) {
-                    long delay = endTime - System.currentTimeMillis();
-                    if (delay <= 0) {
-                        Slog.w(TAG, "Activity manager shutdown timed out");
-                        timedout = true;
-                        break;
-                    }
-                    try {
-                        this.wait();
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
+            timedout = mStackSupervisor.shutdownLocked(timeout);
         }
 
         mAppOpsService.shutdown();
         mUsageStatsService.shutdown();
         mBatteryStatsService.shutdown();
-        
+        synchronized (this) {
+            mProcessStats.shutdownLocked();
+        }
+
         return timedout;
     }
     
     public final void activitySlept(IBinder token) {
-        if (localLOGV) Slog.v(
-            TAG, "Activity slept: token=" + token);
-
-        ActivityRecord r = null;
+        if (localLOGV) Slog.v(TAG, "Activity slept: token=" + token);
 
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            r = mMainStack.isInStackLocked(token);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                mMainStack.activitySleptLocked(r);
+                mStackSupervisor.activitySleptLocked(r);
             }
         }
 
         Binder.restoreCallingIdentity(origId);
     }
 
+    void logLockScreen(String msg) {
+        if (DEBUG_LOCKSCREEN) Slog.d(TAG, Debug.getCallers(2) + ":" + msg +
+                " mLockScreenShown=" + mLockScreenShown + " mWentToSleep=" +
+                mWentToSleep + " mSleeping=" + mSleeping + " mDismissKeyguardOnNextActivity=" +
+                mStackSupervisor.mDismissKeyguardOnNextActivity);
+    }
+
     private void comeOutOfSleepIfNeededLocked() {
         if (!mWentToSleep && !mLockScreenShown) {
             if (mSleeping) {
                 mSleeping = false;
-                mMainStack.awakeFromSleepingLocked();
-                mMainStack.resumeTopActivityLocked(null);
+                mStackSupervisor.comeOutOfSleepIfNeededLocked();
             }
         }
     }
@@ -7301,8 +8144,14 @@
         }
 
         synchronized(this) {
-            mLockScreenShown = shown;
-            comeOutOfSleepIfNeededLocked();
+            long ident = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG_LOCKSCREEN) logLockScreen(" shown=" + shown);
+                mLockScreenShown = shown;
+                comeOutOfSleepIfNeededLocked();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
@@ -7360,33 +8209,36 @@
         enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
                 "setDebugApp()");
 
-        // Note that this is not really thread safe if there are multiple
-        // callers into it at the same time, but that's not a situation we
-        // care about.
-        if (persistent) {
-            final ContentResolver resolver = mContext.getContentResolver();
-            Settings.Global.putString(
-                resolver, Settings.Global.DEBUG_APP,
-                packageName);
-            Settings.Global.putInt(
-                resolver, Settings.Global.WAIT_FOR_DEBUGGER,
-                waitForDebugger ? 1 : 0);
-        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            // Note that this is not really thread safe if there are multiple
+            // callers into it at the same time, but that's not a situation we
+            // care about.
+            if (persistent) {
+                final ContentResolver resolver = mContext.getContentResolver();
+                Settings.Global.putString(
+                    resolver, Settings.Global.DEBUG_APP,
+                    packageName);
+                Settings.Global.putInt(
+                    resolver, Settings.Global.WAIT_FOR_DEBUGGER,
+                    waitForDebugger ? 1 : 0);
+            }
 
-        synchronized (this) {
-            if (!persistent) {
-                mOrigDebugApp = mDebugApp;
-                mOrigWaitForDebugger = mWaitForDebugger;
+            synchronized (this) {
+                if (!persistent) {
+                    mOrigDebugApp = mDebugApp;
+                    mOrigWaitForDebugger = mWaitForDebugger;
+                }
+                mDebugApp = packageName;
+                mWaitForDebugger = waitForDebugger;
+                mDebugTransient = !persistent;
+                if (packageName != null) {
+                    forceStopPackageLocked(packageName, -1, false, false, true, true,
+                            UserHandle.USER_ALL, "set debug app");
+                }
             }
-            mDebugApp = packageName;
-            mWaitForDebugger = waitForDebugger;
-            mDebugTransient = !persistent;
-            if (packageName != null) {
-                final long origId = Binder.clearCallingIdentity();
-                forceStopPackageLocked(packageName, -1, false, false, true, true,
-                        UserHandle.USER_ALL);
-                Binder.restoreCallingIdentity(origId);
-            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -7427,6 +8279,7 @@
         }
     }
 
+    @Override
     public void setAlwaysFinish(boolean enabled) {
         enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
                 "setAlwaysFinish()");
@@ -7440,6 +8293,7 @@
         }
     }
 
+    @Override
     public void setActivityController(IActivityController controller) {
         enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "setActivityController()");
@@ -7449,6 +8303,7 @@
         }
     }
 
+    @Override
     public void setUserIsMonkey(boolean userIsMonkey) {
         synchronized (this) {
             synchronized (mPidsSelfLocked) {
@@ -7466,6 +8321,7 @@
         }
     }
 
+    @Override
     public boolean isUserAMonkey() {
         synchronized (this) {
             // If there is a controller also implies the user is a monkey.
@@ -7489,8 +8345,8 @@
         return KEY_DISPATCHING_TIMEOUT;
     }
 
-
-    public long inputDispatchingTimedOut(int pid, final boolean aboveSystem) {
+    @Override
+    public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
         if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -7505,7 +8361,7 @@
             timeout = getInputDispatchingTimeoutLocked(proc);
         }
 
-        if (!inputDispatchingTimedOut(proc, null, null, aboveSystem)) {
+        if (!inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
             return -1;
         }
 
@@ -7518,13 +8374,20 @@
      */
     public boolean inputDispatchingTimedOut(final ProcessRecord proc,
             final ActivityRecord activity, final ActivityRecord parent,
-            final boolean aboveSystem) {
+            final boolean aboveSystem, String reason) {
         if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.FILTER_EVENTS);
         }
 
+        final String annotation;
+        if (reason == null) {
+            annotation = "Input dispatching timed out";
+        } else {
+            annotation = "Input dispatching timed out (" + reason + ")";
+        }
+
         if (proc != null) {
             synchronized (this) {
                 if (proc.debugging) {
@@ -7540,7 +8403,7 @@
                 if (proc.instrumentationClass != null) {
                     Bundle info = new Bundle();
                     info.putString("shortMsg", "keyDispatchingTimedOut");
-                    info.putString("longMsg", "Timed out while dispatching key event");
+                    info.putString("longMsg", annotation);
                     finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
                     return true;
                 }
@@ -7548,7 +8411,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    appNotResponding(proc, activity, parent, aboveSystem, "keyDispatchingTimedOut");
+                    appNotResponding(proc, activity, parent, aboveSystem, annotation);
                 }
             });
         }
@@ -7556,33 +8419,34 @@
         return true;
     }
 
-    public Bundle getTopActivityExtras(int requestType) {
+    public Bundle getAssistContextExtras(int requestType) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
-                "getTopActivityExtras()");
-        PendingActivityExtras pae;
+                "getAssistContextExtras()");
+        PendingAssistExtras pae;
         Bundle extras = new Bundle();
         synchronized (this) {
-            ActivityRecord activity = mMainStack.mResumedActivity;
+            ActivityRecord activity = getFocusedStack().mResumedActivity;
             if (activity == null) {
-                Slog.w(TAG, "getTopActivityExtras failed: no resumed activity");
+                Slog.w(TAG, "getAssistContextExtras failed: no resumed activity");
                 return null;
             }
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             if (activity.app == null || activity.app.thread == null) {
-                Slog.w(TAG, "getTopActivityExtras failed: no process for " + activity);
+                Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
                 return extras;
             }
             if (activity.app.pid == Binder.getCallingPid()) {
-                Slog.w(TAG, "getTopActivityExtras failed: request process same as " + activity);
+                Slog.w(TAG, "getAssistContextExtras failed: request process same as " + activity);
                 return extras;
             }
-            pae = new PendingActivityExtras(activity);
+            pae = new PendingAssistExtras(activity);
             try {
-                activity.app.thread.requestActivityExtras(activity.appToken, pae, requestType);
-                mPendingActivityExtras.add(pae);
-                mHandler.postDelayed(pae, PENDING_ACTIVITY_RESULT_TIMEOUT);
+                activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
+                        requestType);
+                mPendingAssistExtras.add(pae);
+                mHandler.postDelayed(pae, PENDING_ASSIST_EXTRAS_TIMEOUT);
             } catch (RemoteException e) {
-                Slog.w(TAG, "getTopActivityExtras failed: crash calling " + activity);
+                Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
                 return extras;
             }
         }
@@ -7598,14 +8462,14 @@
             }
         }
         synchronized (this) {
-            mPendingActivityExtras.remove(pae);
+            mPendingAssistExtras.remove(pae);
             mHandler.removeCallbacks(pae);
         }
         return extras;
     }
 
-    public void reportTopActivityExtras(IBinder token, Bundle extras) {
-        PendingActivityExtras pae = (PendingActivityExtras)token;
+    public void reportAssistContextExtras(IBinder token, Bundle extras) {
+        PendingAssistExtras pae = (PendingAssistExtras)token;
         synchronized (pae) {
             pae.result = extras;
             pae.haveResult = true;
@@ -7621,15 +8485,60 @@
         }
     }
 
+    @Override
     public void unregisterProcessObserver(IProcessObserver observer) {
         synchronized (this) {
             mProcessObservers.unregister(observer);
         }
     }
 
+    @Override
+    public boolean convertFromTranslucent(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return false;
+                }
+                if (r.changeWindowTranslucency(true)) {
+                    mWindowManager.setAppFullscreen(token, true);
+                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+                    return true;
+                }
+                return false;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public boolean convertToTranslucent(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return false;
+                }
+                if (r.changeWindowTranslucency(false)) {
+                    r.task.stack.convertToTranslucent(r);
+                    mWindowManager.setAppFullscreen(token, false);
+                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+                    return true;
+                }
+                return false;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
-            final ActivityRecord r = mMainStack.isInStackLocked(token);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 throw new IllegalArgumentException();
             }
@@ -7645,9 +8554,10 @@
         }
     }
 
+    @Override
     public boolean isImmersive(IBinder token) {
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 throw new IllegalArgumentException();
             }
@@ -7658,7 +8568,7 @@
     public boolean isTopActivityImmersive() {
         enforceNotIsolatedCaller("startActivity");
         synchronized (this) {
-            ActivityRecord r = mMainStack.topRunningActivityLocked(null);
+            ActivityRecord r = getFocusedStack().topRunningActivityLocked(null);
             return (r != null) ? r.immersive : false;
         }
     }
@@ -7717,7 +8627,7 @@
         String reason = (pReason == null) ? "Unknown" : pReason;
         // XXX Note: don't acquire main activity lock here, because the window
         // manager calls in with its locks held.
-        
+
         boolean killed = false;
         synchronized (mPidsSelfLocked) {
             int[] types = new int[pids.length];
@@ -7732,12 +8642,12 @@
                     }
                 }
             }
-            
-            // If the worst oom_adj is somewhere in the hidden proc LRU range,
-            // then constrain it so we will kill all hidden procs.
-            if (worstType < ProcessList.HIDDEN_APP_MAX_ADJ
-                    && worstType > ProcessList.HIDDEN_APP_MIN_ADJ) {
-                worstType = ProcessList.HIDDEN_APP_MIN_ADJ;
+
+            // If the worst oom_adj is somewhere in the cached proc LRU range,
+            // then constrain it so we will kill all cached procs.
+            if (worstType < ProcessList.CACHED_APP_MAX_ADJ
+                    && worstType > ProcessList.CACHED_APP_MIN_ADJ) {
+                worstType = ProcessList.CACHED_APP_MIN_ADJ;
             }
 
             // If this is not a secure call, don't let it kill processes that
@@ -7753,13 +8663,9 @@
                     continue;
                 }
                 int adj = proc.setAdj;
-                if (adj >= worstType && !proc.killedBackground) {
-                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
-                    EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId, proc.pid,
-                            proc.processName, adj, reason);
+                if (adj >= worstType && !proc.killedByAm) {
+                    killUnneededProcessLocked(proc, reason);
                     killed = true;
-                    proc.killedBackground = true;
-                    Process.killProcessQuiet(pids[i]);
                 }
             }
         }
@@ -7801,13 +8707,9 @@
                 if (proc == null) continue;
 
                 final int adj = proc.setAdj;
-                if (adj > belowAdj && !proc.killedBackground) {
-                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
-                    EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId,
-                            proc.pid, proc.processName, adj, reason);
+                if (adj > belowAdj && !proc.killedByAm) {
+                    killUnneededProcessLocked(proc, reason);
                     killed = true;
-                    proc.killedBackground = true;
-                    Process.killProcessQuiet(pid);
                 }
             }
         }
@@ -7853,6 +8755,95 @@
         }
     }
 
+    @Override
+    public void restart() {
+        if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission "
+                    + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+        }
+
+        Log.i(TAG, "Sending shutdown broadcast...");
+
+        BroadcastReceiver br = new BroadcastReceiver() {
+            @Override public void onReceive(Context context, Intent intent) {
+                // Now the broadcast is done, finish up the low-level shutdown.
+                Log.i(TAG, "Shutting down activity manager...");
+                shutdown(10000);
+                Log.i(TAG, "Shutdown complete, restarting!");
+                Process.killProcess(Process.myPid());
+                System.exit(10);
+            }
+        };
+
+        // First send the high-level shut down broadcast.
+        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
+        /* For now we are not doing a clean shutdown, because things seem to get unhappy.
+        mContext.sendOrderedBroadcastAsUser(intent,
+                UserHandle.ALL, null, br, mHandler, 0, null, null);
+        */
+        br.onReceive(mContext, intent);
+    }
+
+    private long getLowRamTimeSinceIdle(long now) {
+        return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now-mLowRamStartTime) : 0);
+    }
+
+    @Override
+    public void performIdleMaintenance() {
+        if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission "
+                    + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+        }
+
+        synchronized (this) {
+            final long now = SystemClock.uptimeMillis();
+            final long timeSinceLastIdle = now - mLastIdleTime;
+            final long lowRamSinceLastIdle = getLowRamTimeSinceIdle(now);
+            mLastIdleTime = now;
+            mLowRamTimeSinceLastIdle = 0;
+            if (mLowRamStartTime != 0) {
+                mLowRamStartTime = now;
+            }
+
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Idle maintenance over ");
+            TimeUtils.formatDuration(timeSinceLastIdle, sb);
+            sb.append(" low RAM for ");
+            TimeUtils.formatDuration(lowRamSinceLastIdle, sb);
+            Slog.i(TAG, sb.toString());
+
+            // If at least 1/3 of our time since the last idle period has been spent
+            // with RAM low, then we want to kill processes.
+            boolean doKilling = lowRamSinceLastIdle > (timeSinceLastIdle/3);
+
+            for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+                ProcessRecord proc = mLruProcesses.get(i);
+                if (proc.notCachedSinceIdle) {
+                    if (proc.setProcState > ActivityManager.PROCESS_STATE_TOP
+                            && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
+                        if (doKilling && proc.initialIdlePss != 0
+                                && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+                            killUnneededProcessLocked(proc, "idle maint (pss " + proc.lastPss
+                                    + " from " + proc.initialIdlePss + ")");
+                        }
+                    }
+                } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
+                    proc.notCachedSinceIdle = true;
+                    proc.initialIdlePss = 0;
+                    proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
+                            mSleeping, now);
+                }
+            }
+
+            mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
+            mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
+        }
+    }
+
     public final void startRunning(String pkg, String cls, String action,
             String data) {
         synchronized(this) {
@@ -7880,9 +8871,17 @@
             resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
         boolean alwaysFinishActivities = Settings.Global.getInt(
             resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+        boolean forceRtl = Settings.Global.getInt(
+                resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
+        // Transfer any global setting for forcing RTL layout, into a System Property
+        SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
 
         Configuration configuration = new Configuration();
         Settings.System.getConfiguration(resolver, configuration);
+        if (forceRtl) {
+            // This will take care of setting the correct layout direction flags
+            configuration.setLayoutDirection(configuration.locale);
+        }
 
         synchronized (this) {
             mDebugApp = mOrigDebugApp = debugApp;
@@ -7899,7 +8898,7 @@
         // no need to synchronize(this) just to read & return the value
         return mSystemReady;
     }
-    
+
     private static File getCalledPreBootReceiversFile() {
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
@@ -8146,6 +9145,10 @@
 
         retrieveSettings();
 
+        synchronized (this) {
+            readGrantedUriPermissionsLocked();
+        }
+
         if (goingCallback != null) goingCallback.run();
         
         synchronized (this) {
@@ -8207,7 +9210,7 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-            mMainStack.resumeTopActivityLocked(null);
+            mStackSupervisor.resumeTopActivitiesLocked();
             sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
         }
     }
@@ -8275,10 +9278,7 @@
             }
             if (app.pid > 0 && app.pid != MY_PID) {
                 handleAppCrashLocked(app);
-                Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
-                EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                        app.processName, app.setAdj, "user's request after error");
-                Process.killProcessQuiet(app.pid);
+                killUnneededProcessLocked(app, "user request after error");
             }
         }
     }
@@ -8302,15 +9302,7 @@
                     + " has crashed too many times: killing!");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                     app.userId, app.info.processName, app.uid);
-            for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-                if (r.app == app) {
-                    Slog.w(TAG, "  Force finishing activity "
-                        + r.intent.getComponent().flattenToShortString());
-                    r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "crashed", false);
-                }
-            }
+            mStackSupervisor.handleAppCrashLocked(app);
             if (!app.persistent) {
                 // We don't want to start this process again until the user
                 // explicitly does so...  but for persistent process, we really
@@ -8330,61 +9322,32 @@
                 // annoy the user repeatedly.  Unless it is persistent, since those
                 // processes run critical code.
                 removeProcessLocked(app, false, false, "crash");
-                mMainStack.resumeTopActivityLocked(null);
+                mStackSupervisor.resumeTopActivitiesLocked();
                 return false;
             }
-            mMainStack.resumeTopActivityLocked(null);
+            mStackSupervisor.resumeTopActivitiesLocked();
         } else {
-            ActivityRecord r = mMainStack.topRunningActivityLocked(null);
-            if (r != null && r.app == app) {
-                // If the top running activity is from this crashing
-                // process, then terminate it to avoid getting in a loop.
-                Slog.w(TAG, "  Force finishing activity "
-                        + r.intent.getComponent().flattenToShortString());
-                int index = mMainStack.indexOfActivityLocked(r);
-                r.stack.finishActivityLocked(r, index,
-                        Activity.RESULT_CANCELED, null, "crashed", false);
-                // Also terminate any activities below it that aren't yet
-                // stopped, to avoid a situation where one will get
-                // re-start our crashing activity once it gets resumed again.
-                index--;
-                if (index >= 0) {
-                    r = (ActivityRecord)mMainStack.mHistory.get(index);
-                    if (r.state == ActivityState.RESUMED
-                            || r.state == ActivityState.PAUSING
-                            || r.state == ActivityState.PAUSED) {
-                        if (!r.isHomeActivity || mHomeProcess != r.app) {
-                            Slog.w(TAG, "  Force finishing activity "
-                                    + r.intent.getComponent().flattenToShortString());
-                            r.stack.finishActivityLocked(r, index,
-                                    Activity.RESULT_CANCELED, null, "crashed", false);
-                        }
-                    }
-                }
-            }
+            mStackSupervisor.finishTopRunningActivityLocked(app);
         }
 
         // Bump up the crash count of any services currently running in the proc.
-        if (app.services.size() != 0) {
+        for (int i=app.services.size()-1; i>=0; i--) {
             // Any services running in the application need to be placed
             // back in the pending list.
-            Iterator<ServiceRecord> it = app.services.iterator();
-            while (it.hasNext()) {
-                ServiceRecord sr = it.next();
-                sr.crashCount++;
-            }
+            ServiceRecord sr = app.services.valueAt(i);
+            sr.crashCount++;
         }
 
         // If the crashing process is what we consider to be the "home process" and it has been
         // replaced by a third-party app, clear the package preferred activities from packages
         // with a home activity running in the process to prevent a repeatedly crashing app
         // from blocking the user to manually clear the list.
-        if (app == mHomeProcess && mHomeProcess.activities.size() > 0
+        final ArrayList<ActivityRecord> activities = app.activities;
+        if (app == mHomeProcess && activities.size() > 0
                     && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-            Iterator it = mHomeProcess.activities.iterator();
-            while (it.hasNext()) {
-                ActivityRecord r = (ActivityRecord)it.next();
-                if (r.isHomeActivity) {
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.isHomeActivity()) {
                     Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
                     try {
                         ActivityThread.getPackageManager()
@@ -8670,7 +9633,9 @@
         }
 
         synchronized (this) {
-            for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+            final int NP = mProcessNames.getMap().size();
+            for (int ip=0; ip<NP; ip++) {
+                SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
                 final int NA = apps.size();
                 for (int ia=0; ia<NA; ia++) {
                     ProcessRecord p = apps.valueAt(ia);
@@ -8711,7 +9676,8 @@
             int flags = process.info.flags;
             IPackageManager pm = AppGlobals.getPackageManager();
             sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
-            for (String pkg : process.pkgList) {
+            for (int ip=0; ip<process.pkgList.size(); ip++) {
+                String pkg = process.pkgList.keyAt(ip);
                 sb.append("Package: ").append(pkg);
                 try {
                     PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId());
@@ -9029,9 +9995,9 @@
     }
 
     static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) {
-        if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+        if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
             if (currApp != null) {
-                currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
+                currApp.lru = adj - ProcessList.CACHED_APP_MIN_ADJ + 1;
             }
             return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
         } else if (adj >= ProcessList.SERVICE_B_ADJ) {
@@ -9344,39 +10310,28 @@
 
         // No piece of data specified, dump everything.
         synchronized (this) {
-            boolean needSep;
-            needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
-            if (needSep) {
-                pw.println(" ");
-            }
+            dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+            pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
-            needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
-            if (needSep) {
-                pw.println(" ");
-            }
+            dumpBroadcastsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+            pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
-            needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll, dumpPackage);
-            if (needSep) {
-                pw.println(" ");
-            }
+            dumpProvidersLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+            pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
-            needSep = mServices.dumpServicesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
-            if (needSep) {
-                pw.println(" ");
-            }
+            mServices.dumpServicesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+            pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
-            needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
-            if (needSep) {
-                pw.println(" ");
-            }
+            dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+            pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
@@ -9385,57 +10340,32 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+    void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
-        pw.println("  Main stack:");
-        dumpHistoryList(fd, pw, mMainStack.mHistory, "  ", "Hist", true, !dumpAll, dumpClient,
+
+        boolean printedAnything = mStackSupervisor.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient,
                 dumpPackage);
-        pw.println(" ");
-        pw.println("  Running activities (most recent first):");
-        dumpHistoryList(fd, pw, mMainStack.mLRUActivities, "  ", "Run", false, !dumpAll, false,
-                dumpPackage);
-        if (mMainStack.mWaitingVisibleActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting for another to become visible:");
-            dumpHistoryList(fd, pw, mMainStack.mWaitingVisibleActivities, "  ", "Wait", false,
-                    !dumpAll, false, dumpPackage);
-        }
-        if (mMainStack.mStoppingActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting to stop:");
-            dumpHistoryList(fd, pw, mMainStack.mStoppingActivities, "  ", "Stop", false,
-                    !dumpAll, false, dumpPackage);
-        }
-        if (mMainStack.mGoingToSleepActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting to sleep:");
-            dumpHistoryList(fd, pw, mMainStack.mGoingToSleepActivities, "  ", "Sleep", false,
-                    !dumpAll, false, dumpPackage);
-        }
-        if (mMainStack.mFinishingActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting to finish:");
-            dumpHistoryList(fd, pw, mMainStack.mFinishingActivities, "  ", "Fin", false,
-                    !dumpAll, false, dumpPackage);
+        boolean needSep = printedAnything;
+
+        boolean printed = ActivityStackSupervisor.printThisActivity(pw, mFocusedActivity,
+                dumpPackage, needSep, "  mFocusedActivity: ");
+        if (printed) {
+            printedAnything = true;
+            needSep = false;
         }
 
-        pw.println(" ");
-        if (mMainStack.mPausingActivity != null) {
-            pw.println("  mPausingActivity: " + mMainStack.mPausingActivity);
-        }
-        pw.println("  mResumedActivity: " + mMainStack.mResumedActivity);
-        pw.println("  mFocusedActivity: " + mFocusedActivity);
-        if (dumpAll) {
-            pw.println("  mLastPausedActivity: " + mMainStack.mLastPausedActivity);
-            pw.println("  mSleepTimeout: " + mMainStack.mSleepTimeout);
-            pw.println("  mDismissKeyguardOnNextActivity: "
-                    + mMainStack.mDismissKeyguardOnNextActivity);
+        if (dumpPackage == null) {
+            if (needSep) {
+                pw.println();
+            }
+            needSep = true;
+            printedAnything = true;
+            mStackSupervisor.dump(pw, "  ");
         }
 
         if (mRecentTasks.size() > 0) {
-            pw.println();
-            pw.println("  Recent tasks:");
+            boolean printedHeader = false;
 
             final int N = mRecentTasks.size();
             for (int i=0; i<N; i++) {
@@ -9446,6 +10376,14 @@
                         continue;
                     }
                 }
+                if (!printedHeader) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    pw.println("  Recent tasks:");
+                    printedHeader = true;
+                    printedAnything = true;
+                }
                 pw.print("  * Recent #"); pw.print(i); pw.print(": ");
                         pw.println(tr);
                 if (dumpAll) {
@@ -9453,33 +10391,34 @@
                 }
             }
         }
-        
-        if (dumpAll) {
-            pw.println(" ");
-            pw.println("  mCurTask: " + mCurTask);
+
+        if (!printedAnything) {
+            pw.println("  (nothing)");
         }
-        
-        return true;
     }
 
-    boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+    void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
+        boolean printedAnything = false;
         int numPers = 0;
 
         pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
 
         if (dumpAll) {
-            for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
+            final int NP = mProcessNames.getMap().size();
+            for (int ip=0; ip<NP; ip++) {
+                SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
                 final int NA = procs.size();
                 for (int ia=0; ia<NA; ia++) {
                     ProcessRecord r = procs.valueAt(ia);
-                    if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                    if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                         continue;
                     }
                     if (!needSep) {
                         pw.println("  All known processes:");
                         needSep = true;
+                        printedAnything = true;
                     }
                     pw.print(r.persistent ? "  *PERS*" : "  *APP*");
                         pw.print(" UID "); pw.print(procs.keyAt(ia));
@@ -9493,41 +10432,55 @@
         }
 
         if (mIsolatedProcesses.size() > 0) {
-            if (needSep) pw.println(" ");
-            needSep = true;
-            pw.println("  Isolated process list (sorted by uid):");
+            boolean printed = false;
             for (int i=0; i<mIsolatedProcesses.size(); i++) {
                 ProcessRecord r = mIsolatedProcesses.valueAt(i);
-                if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                     continue;
                 }
+                if (!printed) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    pw.println("  Isolated process list (sorted by uid):");
+                    printedAnything = true;
+                    printed = true;
+                    needSep = true;
+                }
                 pw.println(String.format("%sIsolated #%2d: %s",
                         "    ", i, r.toString()));
             }
         }
 
         if (mLruProcesses.size() > 0) {
-            if (needSep) pw.println(" ");
+            if (needSep) {
+                pw.println();
+            }
+            pw.print("  Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size());
+                    pw.print(" total, non-act at ");
+                    pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+                    pw.print(", non-svc at ");
+                    pw.print(mLruProcesses.size()-mLruProcessServiceStart);
+                    pw.println("):");
+            dumpProcessOomList(pw, this, mLruProcesses, "    ", "Proc", "PERS", false, dumpPackage);
             needSep = true;
-            pw.println("  Process LRU list (sorted by oom_adj):");
-            dumpProcessOomList(pw, this, mLruProcesses, "    ",
-                    "Proc", "PERS", false, dumpPackage);
-            needSep = true;
+            printedAnything = true;
         }
 
-        if (dumpAll) {
+        if (dumpAll || dumpPackage != null) {
             synchronized (mPidsSelfLocked) {
                 boolean printed = false;
                 for (int i=0; i<mPidsSelfLocked.size(); i++) {
                     ProcessRecord r = mPidsSelfLocked.valueAt(i);
-                    if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                    if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                         continue;
                     }
                     if (!printed) {
-                        if (needSep) pw.println(" ");
+                        if (needSep) pw.println();
                         needSep = true;
                         pw.println("  PID mappings:");
                         printed = true;
+                        printedAnything = true;
                     }
                     pw.print("    PID #"); pw.print(mPidsSelfLocked.keyAt(i));
                         pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
@@ -9542,14 +10495,15 @@
                     ProcessRecord r = mPidsSelfLocked.get( 
                             mForegroundProcesses.valueAt(i).pid);
                     if (dumpPackage != null && (r == null
-                            || !dumpPackage.equals(r.info.packageName))) {
+                            || !r.pkgList.containsKey(dumpPackage))) {
                         continue;
                     }
                     if (!printed) {
-                        if (needSep) pw.println(" ");
+                        if (needSep) pw.println();
                         needSep = true;
                         pw.println("  Foreground Processes:");
                         printed = true;
+                        printedAnything = true;
                     }
                     pw.print("    PID #"); pw.print(mForegroundProcesses.keyAt(i));
                             pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
@@ -9558,24 +10512,27 @@
         }
         
         if (mPersistentStartingProcesses.size() > 0) {
-            if (needSep) pw.println(" ");
+            if (needSep) pw.println();
             needSep = true;
+            printedAnything = true;
             pw.println("  Persisent processes that are starting:");
             dumpProcessList(pw, this, mPersistentStartingProcesses, "    ",
                     "Starting Norm", "Restarting PERS", dumpPackage);
         }
 
         if (mRemovedProcesses.size() > 0) {
-            if (needSep) pw.println(" ");
+            if (needSep) pw.println();
             needSep = true;
+            printedAnything = true;
             pw.println("  Processes that are being removed:");
             dumpProcessList(pw, this, mRemovedProcesses, "    ",
                     "Removed Norm", "Removed PERS", dumpPackage);
         }
         
         if (mProcessesOnHold.size() > 0) {
-            if (needSep) pw.println(" ");
+            if (needSep) pw.println();
             needSep = true;
+            printedAnything = true;
             pw.println("  Processes that are on old until the system is ready:");
             dumpProcessList(pw, this, mProcessesOnHold, "    ",
                     "OnHold Norm", "OnHold PERS", dumpPackage);
@@ -9586,23 +10543,25 @@
         if (mProcessCrashTimes.getMap().size() > 0) {
             boolean printed = false;
             long now = SystemClock.uptimeMillis();
-            for (Map.Entry<String, SparseArray<Long>> procs
-                    : mProcessCrashTimes.getMap().entrySet()) {
-                String pname = procs.getKey();
-                SparseArray<Long> uids = procs.getValue();
+            final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+            final int NP = pmap.size();
+            for (int ip=0; ip<NP; ip++) {
+                String pname = pmap.keyAt(ip);
+                SparseArray<Long> uids = pmap.valueAt(ip);
                 final int N = uids.size();
                 for (int i=0; i<N; i++) {
                     int puid = uids.keyAt(i);
                     ProcessRecord r = mProcessNames.get(pname, puid);
                     if (dumpPackage != null && (r == null
-                            || !dumpPackage.equals(r.info.packageName))) {
+                            || !r.pkgList.containsKey(dumpPackage))) {
                         continue;
                     }
                     if (!printed) {
-                        if (needSep) pw.println(" ");
+                        if (needSep) pw.println();
                         needSep = true;
                         pw.println("  Time since processes crashed:");
                         printed = true;
+                        printedAnything = true;
                     }
                     pw.print("    Process "); pw.print(pname);
                             pw.print(" uid "); pw.print(puid);
@@ -9615,22 +10574,24 @@
 
         if (mBadProcesses.getMap().size() > 0) {
             boolean printed = false;
-            for (Map.Entry<String, SparseArray<Long>> procs
-                    : mBadProcesses.getMap().entrySet()) {
-                String pname = procs.getKey();
-                SparseArray<Long> uids = procs.getValue();
+            final ArrayMap<String, SparseArray<Long>> pmap = mBadProcesses.getMap();
+            final int NP = pmap.size();
+            for (int ip=0; ip<NP; ip++) {
+                String pname = pmap.keyAt(ip);
+                SparseArray<Long> uids = pmap.valueAt(ip);
                 final int N = uids.size();
                 for (int i=0; i<N; i++) {
                     int puid = uids.keyAt(i);
                     ProcessRecord r = mProcessNames.get(pname, puid);
                     if (dumpPackage != null && (r == null
-                            || !dumpPackage.equals(r.info.packageName))) {
+                            || !r.pkgList.containsKey(dumpPackage))) {
                         continue;
                     }
                     if (!printed) {
-                        if (needSep) pw.println(" ");
+                        if (needSep) pw.println();
                         needSep = true;
                         pw.println("  Bad processes:");
+                        printedAnything = true;
                     }
                     pw.print("    Bad process "); pw.print(pname);
                             pw.print(" uid "); pw.print(puid);
@@ -9640,42 +10601,66 @@
             }
         }
 
-        pw.println();
-        pw.println("  mStartedUsers:");
-        for (int i=0; i<mStartedUsers.size(); i++) {
-            UserStartedState uss = mStartedUsers.valueAt(i);
-            pw.print("    User #"); pw.print(uss.mHandle.getIdentifier());
-                    pw.print(": "); uss.dump("", pw);
+        if (dumpPackage == null) {
+            pw.println();
+            needSep = false;
+            pw.println("  mStartedUsers:");
+            for (int i=0; i<mStartedUsers.size(); i++) {
+                UserStartedState uss = mStartedUsers.valueAt(i);
+                pw.print("    User #"); pw.print(uss.mHandle.getIdentifier());
+                        pw.print(": "); uss.dump("", pw);
+            }
+            pw.print("  mStartedUserArray: [");
+            for (int i=0; i<mStartedUserArray.length; i++) {
+                if (i > 0) pw.print(", ");
+                pw.print(mStartedUserArray[i]);
+            }
+            pw.println("]");
+            pw.print("  mUserLru: [");
+            for (int i=0; i<mUserLru.size(); i++) {
+                if (i > 0) pw.print(", ");
+                pw.print(mUserLru.get(i));
+            }
+            pw.println("]");
+            if (dumpAll) {
+                pw.print("  mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
+            }
         }
-        pw.print("  mStartedUserArray: [");
-        for (int i=0; i<mStartedUserArray.length; i++) {
-            if (i > 0) pw.print(", ");
-            pw.print(mStartedUserArray[i]);
+        if (mHomeProcess != null && (dumpPackage == null
+                || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+            if (needSep) {
+                pw.println();
+                needSep = false;
+            }
+            pw.println("  mHomeProcess: " + mHomeProcess);
         }
-        pw.println("]");
-        pw.print("  mUserLru: [");
-        for (int i=0; i<mUserLru.size(); i++) {
-            if (i > 0) pw.print(", ");
-            pw.print(mUserLru.get(i));
+        if (mPreviousProcess != null && (dumpPackage == null
+                || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+            if (needSep) {
+                pw.println();
+                needSep = false;
+            }
+            pw.println("  mPreviousProcess: " + mPreviousProcess);
         }
-        pw.println("]");
-        if (dumpAll) {
-            pw.print("  mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
-        }
-        pw.println("  mHomeProcess: " + mHomeProcess);
-        pw.println("  mPreviousProcess: " + mPreviousProcess);
         if (dumpAll) {
             StringBuilder sb = new StringBuilder(128);
             sb.append("  mPreviousProcessVisibleTime: ");
             TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
             pw.println(sb);
         }
-        if (mHeavyWeightProcess != null) {
+        if (mHeavyWeightProcess != null && (dumpPackage == null
+                || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
+            if (needSep) {
+                pw.println();
+                needSep = false;
+            }
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
-        pw.println("  mConfiguration: " + mConfiguration);
+        if (dumpPackage == null) {
+            pw.println("  mConfiguration: " + mConfiguration);
+        }
         if (dumpAll) {
-            pw.println("  mConfigWillChange: " + mMainStack.mConfigWillChange);
+            pw.println("  mConfigWillChange: " + getFocusedStack().mConfigWillChange);
             if (mCompatModePackages.getPackages().size() > 0) {
                 boolean printed = false;
                 for (Map.Entry<String, Integer> entry
@@ -9694,57 +10679,92 @@
                 }
             }
         }
-        if (mSleeping || mWentToSleep || mLockScreenShown) {
-            pw.println("  mSleeping=" + mSleeping + " mWentToSleep=" + mWentToSleep
-                    + " mLockScreenShown " + mLockScreenShown);
-        }
-        if (mShuttingDown) {
-            pw.println("  mShuttingDown=" + mShuttingDown);
+        if (dumpPackage == null) {
+            if (mSleeping || mWentToSleep || mLockScreenShown) {
+                pw.println("  mSleeping=" + mSleeping + " mWentToSleep=" + mWentToSleep
+                        + " mLockScreenShown " + mLockScreenShown);
+            }
+            if (mShuttingDown) {
+                pw.println("  mShuttingDown=" + mShuttingDown);
+            }
         }
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
-            pw.println("  mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
-                    + " mDebugTransient=" + mDebugTransient
-                    + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
+            if (dumpPackage == null || dumpPackage.equals(mDebugApp)
+                    || dumpPackage.equals(mOrigDebugApp)) {
+                if (needSep) {
+                    pw.println();
+                    needSep = false;
+                }
+                pw.println("  mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
+                        + " mDebugTransient=" + mDebugTransient
+                        + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
+            }
         }
         if (mOpenGlTraceApp != null) {
-            pw.println("  mOpenGlTraceApp=" + mOpenGlTraceApp);
+            if (dumpPackage == null || dumpPackage.equals(mOpenGlTraceApp)) {
+                if (needSep) {
+                    pw.println();
+                    needSep = false;
+                }
+                pw.println("  mOpenGlTraceApp=" + mOpenGlTraceApp);
+            }
         }
         if (mProfileApp != null || mProfileProc != null || mProfileFile != null
                 || mProfileFd != null) {
-            pw.println("  mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
-            pw.println("  mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
-            pw.println("  mProfileType=" + mProfileType + " mAutoStopProfiler="
-                    + mAutoStopProfiler);
+            if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
+                if (needSep) {
+                    pw.println();
+                    needSep = false;
+                }
+                pw.println("  mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
+                pw.println("  mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
+                pw.println("  mProfileType=" + mProfileType + " mAutoStopProfiler="
+                        + mAutoStopProfiler);
+            }
         }
-        if (mAlwaysFinishActivities || mController != null) {
-            pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities
-                    + " mController=" + mController);
+        if (dumpPackage == null) {
+            if (mAlwaysFinishActivities || mController != null) {
+                pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities
+                        + " mController=" + mController);
+            }
+            if (dumpAll) {
+                pw.println("  Total persistent processes: " + numPers);
+                pw.println("  mStartRunning=" + mStartRunning
+                        + " mProcessesReady=" + mProcessesReady
+                        + " mSystemReady=" + mSystemReady);
+                pw.println("  mBooting=" + mBooting
+                        + " mBooted=" + mBooted
+                        + " mFactoryTest=" + mFactoryTest);
+                pw.print("  mLastPowerCheckRealtime=");
+                        TimeUtils.formatDuration(mLastPowerCheckRealtime, pw);
+                        pw.println("");
+                pw.print("  mLastPowerCheckUptime=");
+                        TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
+                        pw.println("");
+                pw.println("  mGoingToSleep=" + mStackSupervisor.mGoingToSleep);
+                pw.println("  mLaunchingActivity=" + mStackSupervisor.mLaunchingActivity);
+                pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
+                pw.println("  mNumNonCachedProcs=" + mNumNonCachedProcs
+                        + " (" + mLruProcesses.size() + " total)"
+                        + " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
+                        + " mNumServiceProcs=" + mNumServiceProcs
+                        + " mNewNumServiceProcs=" + mNewNumServiceProcs);
+                pw.println("  mAllowLowerMemLevel=" + mAllowLowerMemLevel
+                        + " mLastMemoryLevel" + mLastMemoryLevel
+                        + " mLastNumProcesses" + mLastNumProcesses);
+                long now = SystemClock.uptimeMillis();
+                pw.print("  mLastIdleTime=");
+                        TimeUtils.formatDuration(now, mLastIdleTime, pw);
+                        pw.print(" mLowRamSinceLastIdle=");
+                        TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
+                        pw.println();
+            }
         }
-        if (dumpAll) {
-            pw.println("  Total persistent processes: " + numPers);
-            pw.println("  mStartRunning=" + mStartRunning
-                    + " mProcessesReady=" + mProcessesReady
-                    + " mSystemReady=" + mSystemReady);
-            pw.println("  mBooting=" + mBooting
-                    + " mBooted=" + mBooted
-                    + " mFactoryTest=" + mFactoryTest);
-            pw.print("  mLastPowerCheckRealtime=");
-                    TimeUtils.formatDuration(mLastPowerCheckRealtime, pw);
-                    pw.println("");
-            pw.print("  mLastPowerCheckUptime=");
-                    TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
-                    pw.println("");
-            pw.println("  mGoingToSleep=" + mMainStack.mGoingToSleep);
-            pw.println("  mLaunchingActivity=" + mMainStack.mLaunchingActivity);
-            pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
-            pw.println("  mNumNonHiddenProcs=" + mNumNonHiddenProcs
-                    + " mNumHiddenProcs=" + mNumHiddenProcs
-                    + " mNumServiceProcs=" + mNumServiceProcs
-                    + " mNewNumServiceProcs=" + mNewNumServiceProcs);
+
+        if (!printedAnything) {
+            pw.println("  (nothing)");
         }
-        
-        return true;
     }
 
     boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args,
@@ -9758,7 +10778,7 @@
                     continue;
                 }
                 if (!printed) {
-                    if (needSep) pw.println(" ");
+                    if (needSep) pw.println();
                     needSep = true;
                     pw.println("  Processes that are waiting to GC:");
                     printed = true;
@@ -9776,37 +10796,56 @@
         return needSep;
     }
 
+    void printOomLevel(PrintWriter pw, String name, int adj) {
+        pw.print("    ");
+        if (adj >= 0) {
+            pw.print(' ');
+            if (adj < 10) pw.print(' ');
+        } else {
+            if (adj > -10) pw.print(' ');
+        }
+        pw.print(adj);
+        pw.print(": ");
+        pw.print(name);
+        pw.print(" (");
+        pw.print(mProcessList.getMemLevel(adj)/1024);
+        pw.println(" kB)");
+    }
+
     boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll) {
         boolean needSep = false;
 
         if (mLruProcesses.size() > 0) {
-            if (needSep) pw.println(" ");
+            if (needSep) pw.println();
             needSep = true;
             pw.println("  OOM levels:");
-            pw.print("    SYSTEM_ADJ: "); pw.println(ProcessList.SYSTEM_ADJ);
-            pw.print("    PERSISTENT_PROC_ADJ: "); pw.println(ProcessList.PERSISTENT_PROC_ADJ);
-            pw.print("    FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ);
-            pw.print("    VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ);
-            pw.print("    PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ);
-            pw.print("    HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ);
-            pw.print("    BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
-            pw.print("    SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ);
-            pw.print("    HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
-            pw.print("    PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ);
-            pw.print("    SERVICE_B_ADJ: "); pw.println(ProcessList.SERVICE_B_ADJ);
-            pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ);
-            pw.print("    HIDDEN_APP_MAX_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MAX_ADJ);
+            printOomLevel(pw, "SYSTEM_ADJ", ProcessList.SYSTEM_ADJ);
+            printOomLevel(pw, "PERSISTENT_PROC_ADJ", ProcessList.PERSISTENT_PROC_ADJ);
+            printOomLevel(pw, "FOREGROUND_APP_ADJ", ProcessList.FOREGROUND_APP_ADJ);
+            printOomLevel(pw, "VISIBLE_APP_ADJ", ProcessList.VISIBLE_APP_ADJ);
+            printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", ProcessList.PERCEPTIBLE_APP_ADJ);
+            printOomLevel(pw, "BACKUP_APP_ADJ", ProcessList.BACKUP_APP_ADJ);
+            printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            printOomLevel(pw, "SERVICE_ADJ", ProcessList.SERVICE_ADJ);
+            printOomLevel(pw, "HOME_APP_ADJ", ProcessList.HOME_APP_ADJ);
+            printOomLevel(pw, "PREVIOUS_APP_ADJ", ProcessList.PREVIOUS_APP_ADJ);
+            printOomLevel(pw, "SERVICE_B_ADJ", ProcessList.SERVICE_B_ADJ);
+            printOomLevel(pw, "CACHED_APP_MIN_ADJ", ProcessList.CACHED_APP_MIN_ADJ);
+            printOomLevel(pw, "CACHED_APP_MAX_ADJ", ProcessList.CACHED_APP_MAX_ADJ);
 
-            if (needSep) pw.println(" ");
-            needSep = true;
-            pw.println("  Process OOM control:");
-            dumpProcessOomList(pw, this, mLruProcesses, "    ",
-                    "Proc", "PERS", true, null);
+            if (needSep) pw.println();
+            pw.print("  Process OOM control ("); pw.print(mLruProcesses.size());
+                    pw.print(" total, non-act at ");
+                    pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+                    pw.print(", non-svc at ");
+                    pw.print(mLruProcesses.size()-mLruProcessServiceStart);
+                    pw.println("):");
+            dumpProcessOomList(pw, this, mLruProcesses, "    ", "Proc", "PERS", true, null);
             needSep = true;
         }
 
-        needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null);
+        dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null);
 
         pw.println();
         pw.println("  mHomeProcess: " + mHomeProcess);
@@ -9920,32 +10959,10 @@
      */
     protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
-        ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
-
-        if ("all".equals(name)) {
-            synchronized (this) {
-                for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
-                    activities.add(r1);
-                }
-            }
-        } else if ("top".equals(name)) {
-            synchronized (this) {
-                final int N = mMainStack.mHistory.size();
-                if (N > 0) {
-                    activities.add((ActivityRecord)mMainStack.mHistory.get(N-1));
-                }
-            }
-        } else {
-            ItemMatcher matcher = new ItemMatcher();
-            matcher.build(name);
-
-            synchronized (this) {
-                for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
-                    if (matcher.match(r1, r1.intent.getComponent())) {
-                        activities.add(r1);
-                    }
-                }
-            }
+        ArrayList<ActivityRecord> activities;
+        
+        synchronized (this) {
+            activities = mStackSupervisor.getDumpActivitiesLocked(name);
         }
 
         if (activities.size() <= 0) {
@@ -9953,12 +10970,12 @@
         }
 
         String[] newArgs = new String[args.length - opti];
-        if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
+        System.arraycopy(args, opti, newArgs, 0, args.length - opti);
 
         TaskRecord lastTask = null;
         boolean needSep = false;
         for (int i=activities.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)activities.get(i);
+            ActivityRecord r = activities.get(i);
             if (needSep) {
                 pw.println();
             }
@@ -10016,10 +11033,11 @@
         }
     }
 
-    boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+    void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
         boolean onlyHistory = false;
+        boolean printedAnything = false;
 
         if ("history".equals(dumpPackage)) {
             if (opti < args.length && "-s".equals(args[opti])) {
@@ -10044,6 +11062,7 @@
                         pw.println("  Registered Receivers:");
                         needSep = true;
                         printed = true;
+                        printedAnything = true;
                     }
                     pw.print("  * "); pw.println(r);
                     r.dump(pw, "    ");
@@ -10054,11 +11073,13 @@
                     "\n  Receiver Resolver Table:" : "  Receiver Resolver Table:",
                     "    ", dumpPackage, false)) {
                 needSep = true;
+                printedAnything = true;
             }
         }
 
         for (BroadcastQueue q : mBroadcastQueues) {
             needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
+            printedAnything |= needSep;
         }
 
         needSep = true;
@@ -10069,6 +11090,7 @@
                     pw.println();
                 }
                 needSep = true;
+                printedAnything = true;
                 pw.print("  Sticky broadcasts for user ");
                         pw.print(mStickyBroadcasts.keyAt(user)); pw.println(":");
                 StringBuilder sb = new StringBuilder(128);
@@ -10106,21 +11128,26 @@
             pw.println("  mHandler:");
             mHandler.dump(new PrintWriterPrinter(pw), "    ");
             needSep = true;
+            printedAnything = true;
         }
         
-        return needSep;
+        if (!printedAnything) {
+            pw.println("  (nothing)");
+        }
     }
 
-    boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+    void dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
-        boolean needSep = true;
+        boolean needSep;
+        boolean printedAnything = false;
 
         ItemMatcher matcher = new ItemMatcher();
         matcher.build(args, opti);
 
         pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)");
 
-        mProviderMap.dumpProvidersLocked(pw, dumpAll);
+        needSep = mProviderMap.dumpProvidersLocked(pw, dumpAll, dumpPackage);
+        printedAnything |= needSep;
 
         if (mLaunchingProviders.size() > 0) {
             boolean printed = false;
@@ -10130,10 +11157,11 @@
                     continue;
                 }
                 if (!printed) {
-                    if (needSep) pw.println(" ");
+                    if (needSep) pw.println();
                     needSep = true;
                     pw.println("  Launching content providers:");
                     printed = true;
+                    printedAnything = true;
                 }
                 pw.print("  Launching #"); pw.print(i); pw.print(": ");
                         pw.println(r);
@@ -10141,13 +11169,29 @@
         }
 
         if (mGrantedUriPermissions.size() > 0) {
-            if (needSep) pw.println();
-            needSep = true;
-            pw.println("Granted Uri Permissions:");
+            boolean printed = false;
+            int dumpUid = -2;
+            if (dumpPackage != null) {
+                try {
+                    dumpUid = mContext.getPackageManager().getPackageUid(dumpPackage, 0);
+                } catch (NameNotFoundException e) {
+                    dumpUid = -1;
+                }
+            }
             for (int i=0; i<mGrantedUriPermissions.size(); i++) {
                 int uid = mGrantedUriPermissions.keyAt(i);
-                HashMap<Uri, UriPermission> perms
+                if (dumpUid >= -1 && UserHandle.getAppId(uid) != dumpUid) {
+                    continue;
+                }
+                ArrayMap<Uri, UriPermission> perms
                         = mGrantedUriPermissions.valueAt(i);
+                if (!printed) {
+                    if (needSep) pw.println();
+                    needSep = true;
+                    pw.println("  Granted Uri Permissions:");
+                    printed = true;
+                    printedAnything = true;
+                }
                 pw.print("  * UID "); pw.print(uid);
                         pw.println(" holds:");
                 for (UriPermission perm : perms.values()) {
@@ -10157,18 +11201,20 @@
                     }
                 }
             }
-            needSep = true;
         }
-        
-        return needSep;
+
+        if (!printedAnything) {
+            pw.println("  (nothing)");
+        }
     }
 
-    boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+    void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
-        boolean needSep = false;
-        
+        boolean printed = false;
+
+        pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
+
         if (mIntentSenderRecords.size() > 0) {
-            boolean printed = false;
             Iterator<WeakReference<PendingIntentRecord>> it
                     = mIntentSenderRecords.values().iterator();
             while (it.hasNext()) {
@@ -10178,11 +11224,7 @@
                         || !dumpPackage.equals(rec.key.packageName))) {
                     continue;
                 }
-                if (!printed) {
-                    pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
-                    printed = true;
-                }
-                needSep = true;
+                printed = true;
                 if (rec != null) {
                     pw.print("  * "); pw.println(rec);
                     if (dumpAll) {
@@ -10193,87 +11235,12 @@
                 }
             }
         }
-        
-        return needSep;
-    }
 
-    private static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list,
-            String prefix, String label, boolean complete, boolean brief, boolean client,
-            String dumpPackage) {
-        TaskRecord lastTask = null;
-        boolean needNL = false;
-        final String innerPrefix = prefix + "      ";
-        final String[] args = new String[0];
-        for (int i=list.size()-1; i>=0; i--) {
-            final ActivityRecord r = (ActivityRecord)list.get(i);
-            if (dumpPackage != null && !dumpPackage.equals(r.packageName)) {
-                continue;
-            }
-            final boolean full = !brief && (complete || !r.isInHistory());
-            if (needNL) {
-                pw.println(" ");
-                needNL = false;
-            }
-            if (lastTask != r.task) {
-                lastTask = r.task;
-                pw.print(prefix);
-                pw.print(full ? "* " : "  ");
-                pw.println(lastTask);
-                if (full) {
-                    lastTask.dump(pw, prefix + "  ");
-                } else if (complete) {
-                    // Complete + brief == give a summary.  Isn't that obvious?!?
-                    if (lastTask.intent != null) {
-                        pw.print(prefix); pw.print("  ");
-                                pw.println(lastTask.intent.toInsecureStringWithClip());
-                    }
-                }
-            }
-            pw.print(prefix); pw.print(full ? "  * " : "    "); pw.print(label);
-            pw.print(" #"); pw.print(i); pw.print(": ");
-            pw.println(r);
-            if (full) {
-                r.dump(pw, innerPrefix);
-            } else if (complete) {
-                // Complete + brief == give a summary.  Isn't that obvious?!?
-                pw.print(innerPrefix); pw.println(r.intent.toInsecureString());
-                if (r.app != null) {
-                    pw.print(innerPrefix); pw.println(r.app);
-                }
-            }
-            if (client && r.app != null && r.app.thread != null) {
-                // flush anything that is already in the PrintWriter since the thread is going
-                // to write to the file descriptor directly
-                pw.flush();
-                try {
-                    TransferPipe tp = new TransferPipe();
-                    try {
-                        r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
-                                r.appToken, innerPrefix, args);
-                        // Short timeout, since blocking here can
-                        // deadlock with the application.
-                        tp.go(fd, 2000);
-                    } finally {
-                        tp.kill();
-                    }
-                } catch (IOException e) {
-                    pw.println(innerPrefix + "Failure while dumping the activity: " + e);
-                } catch (RemoteException e) {
-                    pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
-                }
-                needNL = true;
-            }
+        if (!printed) {
+            pw.println("  (nothing)");
         }
     }
 
-    private static String buildOomTag(String prefix, String space, int val, int base) {
-        if (val == base) {
-            if (space == null) return prefix;
-            return prefix + "  ";
-        }
-        return prefix + "+" + Integer.toString(val-base);
-    }
-    
     private static final int dumpProcessList(PrintWriter pw,
             ActivityManagerService service, List list,
             String prefix, String normalLabel, String persistentLabel,
@@ -10304,7 +11271,7 @@
                 = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
         for (int i=0; i<origList.size(); i++) {
             ProcessRecord r = origList.get(i);
-            if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+            if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                 continue;
             }
             list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
@@ -10313,7 +11280,7 @@
         if (list.size() <= 0) {
             return false;
         }
- 
+
         Comparator<Pair<ProcessRecord, Integer>> comparator
                 = new Comparator<Pair<ProcessRecord, Integer>>() {
             @Override
@@ -10338,58 +11305,50 @@
 
         for (int i=list.size()-1; i>=0; i--) {
             ProcessRecord r = list.get(i).first;
-            String oomAdj;
-            if (r.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
-                oomAdj = buildOomTag("bak", "  ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ);
-            } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) {
-                oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ);
-            } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
-                oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
-                oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
-                oomAdj = buildOomTag("svc  ", null, r.setAdj, ProcessList.SERVICE_ADJ);
-            } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
-                oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                oomAdj = buildOomTag("hvy  ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("vis  ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-                oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
-                oomAdj = buildOomTag("pers ", null, r.setAdj, ProcessList.PERSISTENT_PROC_ADJ);
-            } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) {
-                oomAdj = buildOomTag("sys  ", null, r.setAdj, ProcessList.SYSTEM_ADJ);
-            } else {
-                oomAdj = Integer.toString(r.setAdj);
-            }
-            String schedGroup;
+            String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
+            char schedGroup;
             switch (r.setSchedGroup) {
                 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
-                    schedGroup = "B";
+                    schedGroup = 'B';
                     break;
                 case Process.THREAD_GROUP_DEFAULT:
-                    schedGroup = "F";
+                    schedGroup = 'F';
                     break;
                 default:
-                    schedGroup = Integer.toString(r.setSchedGroup);
+                    schedGroup = '?';
                     break;
             }
-            String foreground;
+            char foreground;
             if (r.foregroundActivities) {
-                foreground = "A";
+                foreground = 'A';
             } else if (r.foregroundServices) {
-                foreground = "S";
+                foreground = 'S';
             } else {
-                foreground = " ";
+                foreground = ' ';
             }
-            pw.println(String.format("%s%s #%2d: adj=%s/%s%s trm=%2d %s (%s)",
-                    prefix, (r.persistent ? persistentLabel : normalLabel),
-                    (origList.size()-1)-list.get(i).second, oomAdj, schedGroup,
-                    foreground, r.trimMemoryLevel, r.toShortString(), r.adjType));
+            String procState = ProcessList.makeProcStateString(r.curProcState);
+            pw.print(prefix);
+            pw.print(r.persistent ? persistentLabel : normalLabel);
+            pw.print(" #");
+            int num = (origList.size()-1)-list.get(i).second;
+            if (num < 10) pw.print(' ');
+            pw.print(num);
+            pw.print(": ");
+            pw.print(oomAdj);
+            pw.print(' ');
+            pw.print(schedGroup);
+            pw.print('/');
+            pw.print(foreground);
+            pw.print('/');
+            pw.print(procState);
+            pw.print(" trm:");
+            if (r.trimMemoryLevel < 10) pw.print(' ');
+            pw.print(r.trimMemoryLevel);
+            pw.print(' ');
+            pw.print(r.toShortString());
+            pw.print(" (");
+            pw.print(r.adjType);
+            pw.println(')');
             if (r.adjSource != null || r.adjTarget != null) {
                 pw.print(prefix);
                 pw.print("    ");
@@ -10415,17 +11374,20 @@
                 pw.print(prefix);
                 pw.print("    ");
                 pw.print("oom: max="); pw.print(r.maxAdj);
-                pw.print(" hidden="); pw.print(r.hiddenAdj);
-                pw.print(" client="); pw.print(r.clientHiddenAdj);
-                pw.print(" empty="); pw.print(r.emptyAdj);
                 pw.print(" curRaw="); pw.print(r.curRawAdj);
                 pw.print(" setRaw="); pw.print(r.setRawAdj);
                 pw.print(" cur="); pw.print(r.curAdj);
                 pw.print(" set="); pw.println(r.setAdj);
                 pw.print(prefix);
                 pw.print("    ");
+                pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
+                pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
+                pw.print(" lastPss="); pw.print(r.lastPss);
+                pw.print(" lastCachedPss="); pw.println(r.lastCachedPss);
+                pw.print(prefix);
+                pw.print("    ");
                 pw.print("keeping="); pw.print(r.keeping);
-                pw.print(" hidden="); pw.print(r.hidden);
+                pw.print(" cached="); pw.print(r.cached);
                 pw.print(" empty="); pw.print(r.empty);
                 pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
 
@@ -10566,23 +11528,37 @@
     }
 
     final static class MemItem {
+        final boolean isProc;
         final String label;
         final String shortLabel;
         final long pss;
         final int id;
+        final boolean hasActivities;
         ArrayList<MemItem> subitems;
 
-        public MemItem(String _label, String _shortLabel, long _pss, int _id) {
+        public MemItem(String _label, String _shortLabel, long _pss, int _id,
+                boolean _hasActivities) {
+            isProc = true;
             label = _label;
             shortLabel = _shortLabel;
             pss = _pss;
             id = _id;
+            hasActivities = _hasActivities;
+        }
+
+        public MemItem(String _label, String _shortLabel, long _pss, int _id) {
+            isProc = false;
+            label = _label;
+            shortLabel = _shortLabel;
+            pss = _pss;
+            id = _id;
+            hasActivities = false;
         }
     }
 
-    static final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items,
-            boolean sort) {
-        if (sort) {
+    static final void dumpMemItems(PrintWriter pw, String prefix, String tag,
+            ArrayList<MemItem> items, boolean sort, boolean isCompact) {
+        if (sort && !isCompact) {
             Collections.sort(items, new Comparator<MemItem>() {
                 @Override
                 public int compare(MemItem lhs, MemItem rhs) {
@@ -10598,9 +11574,19 @@
 
         for (int i=0; i<items.size(); i++) {
             MemItem mi = items.get(i);
-            pw.print(prefix); pw.printf("%7d kB: ", mi.pss); pw.println(mi.label);
+            if (!isCompact) {
+                pw.print(prefix); pw.printf("%7d kB: ", mi.pss); pw.println(mi.label);
+            } else if (mi.isProc) {
+                pw.print("proc,"); pw.print(tag); pw.print(","); pw.print(mi.shortLabel);
+                pw.print(","); pw.print(mi.id); pw.print(","); pw.print(mi.pss);
+                pw.println(mi.hasActivities ? ",a" : ",e");
+            } else {
+                pw.print(tag); pw.print(","); pw.print(mi.shortLabel); pw.print(",");
+                pw.println(mi.pss);
+            }
             if (mi.subitems != null) {
-                dumpMemItems(pw, prefix + "           ", mi.subitems, true);
+                dumpMemItems(pw, prefix + "           ", mi.shortLabel, mi.subitems,
+                        true, isCompact);
             }
         }
     }
@@ -10634,23 +11620,37 @@
     }
 
     static final int[] DUMP_MEM_OOM_ADJ = new int[] {
+            ProcessList.NATIVE_ADJ,
             ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
-            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
-            ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
-            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
+            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
+            ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
+            ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
+            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ
     };
     static final String[] DUMP_MEM_OOM_LABEL = new String[] {
+            "Native",
             "System", "Persistent", "Foreground",
-            "Visible", "Perceptible", "Heavy Weight",
-            "Backup", "A Services", "Home", "Previous",
-            "B Services", "Background"
+            "Visible", "Perceptible",
+            "Heavy Weight", "Backup",
+            "A Services", "Home",
+            "Previous", "B Services", "Cached"
+    };
+    static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
+            "native",
+            "sys", "pers", "fore",
+            "vis", "percept",
+            "heavy", "backup",
+            "servicea", "home",
+            "prev", "serviceb", "cached"
     };
 
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
-            PrintWriter pw, String prefix, String[] args, boolean brief,
-            PrintWriter categoryPw, StringBuilder outTag, StringBuilder outStack) {
-        boolean dumpAll = false;
+            PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
+        boolean dumpDetails = false;
+        boolean dumpFullDetails = false;
+        boolean dumpDalvik = false;
         boolean oomOnly = false;
+        boolean isCompact = false;
         
         int opti = 0;
         while (opti < args.length) {
@@ -10660,12 +11660,20 @@
             }
             opti++;
             if ("-a".equals(opt)) {
-                dumpAll = true;
+                dumpDetails = true;
+                dumpFullDetails = true;
+                dumpDalvik = true;
+            } else if ("-d".equals(opt)) {
+                dumpDalvik = true;
+            } else if ("-c".equals(opt)) {
+                isCompact = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
             } else if ("-h".equals(opt)) {
-                pw.println("meminfo dump options: [-a] [--oom] [process]");
+                pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
                 pw.println("  -a: include all available information for each process.");
+                pw.println("  -d: include dalvik details when dumping process details.");
+                pw.println("  -c: dump in a compact machine-parseable representation.");
                 pw.println("  --oom: only show processes organized by oom adj.");
                 pw.println("If [process] is specified it can be the name or ");
                 pw.println("pid of a specific process to dump.");
@@ -10684,14 +11692,13 @@
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
 
-        if (procs.size() == 1 || isCheckinRequest) {
-            dumpAll = true;
+        if (!brief && !oomOnly && (procs.size() == 1 || isCheckinRequest)) {
+            dumpDetails = true;
         }
 
-        if (isCheckinRequest) {
+        if (isCheckinRequest || isCompact) {
             // short checkin version
-            pw.println(uptime + "," + realtime);
-            pw.flush();
+            pw.print("time,"); pw.print(uptime); pw.print(","); pw.println(realtime);
         } else {
             pw.println("Applications Memory Usage (kB):");
             pw.println("Uptime: " + uptime + " Realtime: " + realtime);
@@ -10701,43 +11708,74 @@
         System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
 
         ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+        final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
         long nativePss=0, dalvikPss=0, otherPss=0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
         long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
         ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
                 new ArrayList[DUMP_MEM_OOM_LABEL.length];
+        final long[] tmpLong = new long[1];
 
         long totalPss = 0;
+        long cachedPss = 0;
 
+        Debug.MemoryInfo mi = null;
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
-            ProcessRecord r = procs.get(i);
-            if (r.thread != null) {
-                if (!isCheckinRequest && dumpAll) {
-                    pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
-                    pw.flush();
+            final ProcessRecord r = procs.get(i);
+            final IApplicationThread thread;
+            final int pid;
+            final int oomAdj;
+            final boolean hasActivities;
+            synchronized (this) {
+                thread = r.thread;
+                pid = r.pid;
+                oomAdj = r.getSetAdjWithServices();
+                hasActivities = r.hasActivities;
+            }
+            if (thread != null) {
+                if (!isCheckinRequest && dumpDetails) {
+                    pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
                 }
-                Debug.MemoryInfo mi = null;
-                if (dumpAll) {
+                if (mi == null) {
+                    mi = new Debug.MemoryInfo();
+                }
+                if (dumpDetails || (!brief && !oomOnly)) {
+                    Debug.getMemoryInfo(pid, mi);
+                } else {
+                    mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
+                    mi.dalvikPrivateDirty = (int)tmpLong[0];
+                }
+                if (dumpDetails) {
                     try {
-                        mi = r.thread.dumpMemInfo(fd, isCheckinRequest, dumpAll, innerArgs);
+                        pw.flush();
+                        thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
+                                dumpDalvik, innerArgs);
                     } catch (RemoteException e) {
                         if (!isCheckinRequest) {
                             pw.println("Got RemoteException!");
                             pw.flush();
                         }
                     }
-                } else {
-                    mi = new Debug.MemoryInfo();
-                    Debug.getMemoryInfo(r.pid, mi);
+                }
+
+                final long myTotalPss = mi.getTotalPss();
+                final long myTotalUss = mi.getTotalUss();
+
+                synchronized (this) {
+                    if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
+                        // Record this for posterity if the process has been stable.
+                        r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true, r.pkgList);
+                    }
                 }
 
                 if (!isCheckinRequest && mi != null) {
-                    long myTotalPss = mi.getTotalPss();
                     totalPss += myTotalPss;
-                    MemItem pssItem = new MemItem(r.processName + " (pid " + r.pid + ")",
-                            r.processName, myTotalPss, 0);
+                    MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
+                            (hasActivities ? " / activities)" : ")"),
+                            r.processName, myTotalPss, pid, hasActivities);
                     procMems.add(pssItem);
+                    procMemsMap.put(pid, pssItem);
 
                     nativePss += mi.nativePss;
                     dalvikPss += mi.dalvikPss;
@@ -10748,8 +11786,12 @@
                         otherPss -= mem;
                     }
 
+                    if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+                        cachedPss += myTotalPss;
+                    }
+
                     for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
-                        if (r.setAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
+                        if (oomAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
                                 || oomIndex == (oomPss.length-1)) {
                             oomPss[oomIndex] += myTotalPss;
                             if (oomProcs[oomIndex] == null) {
@@ -10764,6 +11806,48 @@
         }
 
         if (!isCheckinRequest && procs.size() > 1) {
+            // If we are showing aggregations, also look for native processes to
+            // include so that our aggregations are more accurate.
+            updateCpuStatsNow();
+            synchronized (mProcessCpuThread) {
+                final int N = mProcessCpuTracker.countStats();
+                for (int i=0; i<N; i++) {
+                    ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                    if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+                        if (mi == null) {
+                            mi = new Debug.MemoryInfo();
+                        }
+                        if (!brief && !oomOnly) {
+                            Debug.getMemoryInfo(st.pid, mi);
+                        } else {
+                            mi.nativePss = (int)Debug.getPss(st.pid, tmpLong);
+                            mi.nativePrivateDirty = (int)tmpLong[0];
+                        }
+
+                        final long myTotalPss = mi.getTotalPss();
+                        totalPss += myTotalPss;
+
+                        MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
+                                st.name, myTotalPss, st.pid, false);
+                        procMems.add(pssItem);
+
+                        nativePss += mi.nativePss;
+                        dalvikPss += mi.dalvikPss;
+                        otherPss += mi.otherPss;
+                        for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+                            long mem = mi.getOtherPss(j);
+                            miscPss[j] += mem;
+                            otherPss -= mem;
+                        }
+                        oomPss[0] += myTotalPss;
+                        if (oomProcs[0] == null) {
+                            oomProcs[0] = new ArrayList<MemItem>();
+                        }
+                        oomProcs[0].add(pssItem);
+                    }
+                }
+            }
+
             ArrayList<MemItem> catMems = new ArrayList<MemItem>();
 
             catMems.add(new MemItem("Native", "Native", nativePss, -1));
@@ -10777,7 +11861,8 @@
             ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
             for (int j=0; j<oomPss.length; j++) {
                 if (oomPss[j] != 0) {
-                    String label = DUMP_MEM_OOM_LABEL[j];
+                    String label = isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
+                            : DUMP_MEM_OOM_LABEL[j];
                     MemItem item = new MemItem(label, label, oomPss[j],
                             DUMP_MEM_OOM_ADJ[j]);
                     item.subitems = oomProcs[j];
@@ -10785,107 +11870,137 @@
                 }
             }
 
-            if (outTag != null || outStack != null) {
-                if (outTag != null) {
-                    appendMemBucket(outTag, totalPss, "total", false);
-                }
-                if (outStack != null) {
-                    appendMemBucket(outStack, totalPss, "total", true);
-                }
-                boolean firstLine = true;
-                for (int i=0; i<oomMems.size(); i++) {
-                    MemItem miCat = oomMems.get(i);
-                    if (miCat.subitems == null || miCat.subitems.size() < 1) {
-                        continue;
-                    }
-                    if (miCat.id < ProcessList.SERVICE_ADJ
-                            || miCat.id == ProcessList.HOME_APP_ADJ
-                            || miCat.id == ProcessList.PREVIOUS_APP_ADJ) {
-                        if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
-                            outTag.append(" / ");
-                        }
-                        if (outStack != null) {
-                            if (miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
-                                if (firstLine) {
-                                    outStack.append(":");
-                                    firstLine = false;
-                                }
-                                outStack.append("\n\t at ");
-                            } else {
-                                outStack.append("$");
-                            }
-                        }
-                        for (int j=0; j<miCat.subitems.size(); j++) {
-                            MemItem mi = miCat.subitems.get(j);
-                            if (j > 0) {
-                                if (outTag != null) {
-                                    outTag.append(" ");
-                                }
-                                if (outStack != null) {
-                                    outStack.append("$");
-                                }
-                            }
-                            if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
-                                appendMemBucket(outTag, mi.pss, mi.shortLabel, false);
-                            }
-                            if (outStack != null) {
-                                appendMemBucket(outStack, mi.pss, mi.shortLabel, true);
-                            }
-                        }
-                        if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
-                            outStack.append("(");
-                            for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
-                                if (DUMP_MEM_OOM_ADJ[k] == miCat.id) {
-                                    outStack.append(DUMP_MEM_OOM_LABEL[k]);
-                                    outStack.append(":");
-                                    outStack.append(DUMP_MEM_OOM_ADJ[k]);
-                                }
-                            }
-                            outStack.append(")");
-                        }
-                    }
-                }
-            }
-
-            if (!brief && !oomOnly) {
+            if (!brief && !oomOnly && !isCompact) {
                 pw.println();
                 pw.println("Total PSS by process:");
-                dumpMemItems(pw, "  ", procMems, true);
+                dumpMemItems(pw, "  ", "proc", procMems, true, isCompact);
                 pw.println();
             }
-            pw.println("Total PSS by OOM adjustment:");
-            dumpMemItems(pw, "  ", oomMems, false);
-            if (!oomOnly) {
-                PrintWriter out = categoryPw != null ? categoryPw : pw;
-                out.println();
-                out.println("Total PSS by category:");
-                dumpMemItems(out, "  ", catMems, true);
+            if (!isCompact) {
+                pw.println("Total PSS by OOM adjustment:");
             }
-            pw.println();
-            pw.print("Total PSS: "); pw.print(totalPss); pw.println(" kB");
-            final int[] SINGLE_LONG_FORMAT = new int[] {
-                Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
-            };
-            long[] longOut = new long[1];
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            longOut[0] = 0;
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            longOut[0] = 0;
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            longOut[0] = 0;
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            pw.print("      KSM: "); pw.print(sharing); pw.print(" kB saved from shared ");
-                    pw.print(shared); pw.println(" kB");
-            pw.print("           "); pw.print(unshared); pw.print(" kB unshared; ");
-                    pw.print(voltile); pw.println(" kB volatile");
+            dumpMemItems(pw, "  ", "oom", oomMems, false, isCompact);
+            if (!brief && !oomOnly) {
+                PrintWriter out = categoryPw != null ? categoryPw : pw;
+                if (!isCompact) {
+                    out.println();
+                    out.println("Total PSS by category:");
+                }
+                dumpMemItems(out, "  ", "cat", catMems, true, isCompact);
+            }
+            if (!isCompact) {
+                pw.println();
+            }
+            MemInfoReader memInfo = new MemInfoReader();
+            memInfo.readMemInfo();
+            if (!brief) {
+                if (!isCompact) {
+                    pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
+                    pw.println(" kB");
+                    pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
+                            + memInfo.getFreeSizeKb()); pw.print(" kB (");
+                            pw.print(cachedPss); pw.print(" cached pss + ");
+                            pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
+                            pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
+                } else {
+                    pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
+                    pw.print(cachedPss + memInfo.getCachedSizeKb()
+                            + memInfo.getFreeSizeKb()); pw.print(",");
+                    pw.println(totalPss - cachedPss);
+                }
+            }
+            if (!isCompact) {
+                pw.print(" Used RAM: "); pw.print(totalPss - cachedPss
+                        + memInfo.getBuffersSizeKb() + memInfo.getShmemSizeKb()
+                        + memInfo.getSlabSizeKb()); pw.print(" kB (");
+                        pw.print(totalPss - cachedPss); pw.print(" used pss + ");
+                        pw.print(memInfo.getBuffersSizeKb()); pw.print(" buffers + ");
+                        pw.print(memInfo.getShmemSizeKb()); pw.print(" shmem + ");
+                        pw.print(memInfo.getSlabSizeKb()); pw.println(" slab)");
+                pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb()
+                        - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                        - memInfo.getBuffersSizeKb() - memInfo.getShmemSizeKb()
+                        - memInfo.getSlabSizeKb()); pw.println(" kB");
+            }
+            if (!brief) {
+                if (memInfo.getZramTotalSizeKb() != 0) {
+                    if (!isCompact) {
+                        pw.print("     ZRAM: "); pw.print(memInfo.getZramTotalSizeKb());
+                                pw.print(" kB physical used for ");
+                                pw.print(memInfo.getSwapTotalSizeKb()
+                                        - memInfo.getSwapFreeSizeKb());
+                                pw.print(" kB in swap (");
+                                pw.print(memInfo.getSwapTotalSizeKb());
+                                pw.println(" kB total swap)");
+                    } else {
+                        pw.print("zram,"); pw.print(memInfo.getZramTotalSizeKb()); pw.print(",");
+                                pw.print(memInfo.getSwapTotalSizeKb()); pw.print(",");
+                                pw.println(memInfo.getSwapFreeSizeKb());
+                    }
+                }
+                final int[] SINGLE_LONG_FORMAT = new int[] {
+                    Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+                };
+                long[] longOut = new long[1];
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                longOut[0] = 0;
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                longOut[0] = 0;
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                longOut[0] = 0;
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                if (!isCompact) {
+                    if (sharing != 0 || shared != 0 || unshared != 0 || voltile != 0) {
+                        pw.print("      KSM: "); pw.print(sharing);
+                                pw.print(" kB saved from shared ");
+                                pw.print(shared); pw.println(" kB");
+                        pw.print("           "); pw.print(unshared); pw.print(" kB unshared; ");
+                                pw.print(voltile); pw.println(" kB volatile");
+                    }
+                    pw.print("   Tuning: ");
+                    pw.print(ActivityManager.staticGetMemoryClass());
+                    pw.print(" (large ");
+                    pw.print(ActivityManager.staticGetLargeMemoryClass());
+                    pw.print("), oom ");
+                    pw.print(mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024);
+                    pw.print(" kB");
+                    pw.print(", restore limit ");
+                    pw.print(mProcessList.getCachedRestoreThresholdKb());
+                    pw.print(" kB");
+                    if (ActivityManager.isLowRamDeviceStatic()) {
+                        pw.print(" (low-ram)");
+                    }
+                    if (ActivityManager.isHighEndGfx()) {
+                        pw.print(" (high-end-gfx)");
+                    }
+                    pw.println();
+                } else {
+                    pw.print("ksm,"); pw.print(sharing); pw.print(",");
+                    pw.print(shared); pw.print(","); pw.print(unshared); pw.print(",");
+                    pw.println(voltile);
+                    pw.print("tuning,");
+                    pw.print(ActivityManager.staticGetMemoryClass());
+                    pw.print(',');
+                    pw.print(ActivityManager.staticGetLargeMemoryClass());
+                    pw.print(',');
+                    pw.print(mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024);
+                    if (ActivityManager.isLowRamDeviceStatic()) {
+                        pw.print(",low-ram");
+                    }
+                    if (ActivityManager.isHighEndGfx()) {
+                        pw.print(",high-end-gfx");
+                    }
+                    pw.println();
+                }
+            }
         }
     }
 
@@ -10938,13 +12053,9 @@
                 if (!capp.persistent && capp.thread != null
                         && capp.pid != 0
                         && capp.pid != MY_PID) {
-                    Slog.i(TAG, "Kill " + capp.processName
-                            + " (pid " + capp.pid + "): provider " + cpr.info.name
-                            + " in dying process " + (proc != null ? proc.processName : "??"));
-                    EventLog.writeEvent(EventLogTags.AM_KILL, capp.userId, capp.pid,
-                            capp.processName, capp.setAdj, "dying provider "
-                                    + cpr.name.toShortString());
-                    Process.killProcessQuiet(capp.pid);
+                    killUnneededProcessLocked(capp, "depends on provider "
+                            + cpr.name.flattenToShortString()
+                            + " in dying proc " + (proc != null ? proc.processName : "??"));
                 }
             } else if (capp.thread != null && conn.provider.provider != null) {
                 try {
@@ -10963,20 +12074,21 @@
         }
         return inLaunching;
     }
-    
+
     /**
      * Main code for cleaning up a process when it has gone away.  This is
-     * called both as a result of the process dying, or directly when stopping 
+     * called both as a result of the process dying, or directly when stopping
      * a process when running in single process mode.
      */
     private final void cleanUpApplicationRecordLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart, int index) {
         if (index >= 0) {
-            mLruProcesses.remove(index);
+            removeLruProcessLocked(app);
         }
 
         mProcessesToGc.remove(app);
-        
+        mPendingPssProcesses.remove(app);
+
         // Dismiss any open dialogs.
         if (app.crashDialog != null && !app.forceCrashReport) {
             app.crashDialog.dismiss();
@@ -10993,10 +12105,10 @@
 
         app.crashing = false;
         app.notResponding = false;
-        
-        app.resetPackageList();
+
+        app.resetPackageList(mProcessStats);
         app.unlinkDeathRecipient();
-        app.thread = null;
+        app.makeInactive(mProcessStats);
         app.forcingToForeground = null;
         app.foregroundServices = false;
         app.foregroundActivities = false;
@@ -11008,29 +12120,25 @@
         boolean restart = false;
 
         // Remove published content providers.
-        if (!app.pubProviders.isEmpty()) {
-            Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator();
-            while (it.hasNext()) {
-                ContentProviderRecord cpr = it.next();
-
-                final boolean always = app.bad || !allowRestart;
-                if (removeDyingProviderLocked(app, cpr, always) || always) {
-                    // We left the provider in the launching list, need to
-                    // restart it.
-                    restart = true;
-                }
-
-                cpr.provider = null;
-                cpr.proc = null;
+        for (int i=app.pubProviders.size()-1; i>=0; i--) {
+            ContentProviderRecord cpr = app.pubProviders.valueAt(i);
+            final boolean always = app.bad || !allowRestart;
+            if (removeDyingProviderLocked(app, cpr, always) || always) {
+                // We left the provider in the launching list, need to
+                // restart it.
+                restart = true;
             }
-            app.pubProviders.clear();
+
+            cpr.provider = null;
+            cpr.proc = null;
         }
-        
+        app.pubProviders.clear();
+
         // Take care of any launching providers waiting for this process.
         if (checkAppInLaunchingProvidersLocked(app, false)) {
             restart = true;
         }
-        
+
         // Unregister from connected content providers.
         if (!app.conProviders.isEmpty()) {
             for (int i=0; i<app.conProviders.size(); i++) {
@@ -11057,18 +12165,15 @@
                 }
             }
         }
-        
+
         skipCurrentReceiverLocked(app);
 
         // Unregister any receivers.
-        if (app.receivers.size() > 0) {
-            Iterator<ReceiverList> it = app.receivers.iterator();
-            while (it.hasNext()) {
-                removeReceiverLocked(it.next());
-            }
-            app.receivers.clear();
+        for (int i=app.receivers.size()-1; i>=0; i--) {
+            removeReceiverLocked(app.receivers.valueAt(i));
         }
-        
+        app.receivers.clear();
+
         // If the app is undergoing backup, tell the backup manager about it
         if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
             if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App "
@@ -11435,7 +12540,7 @@
                     : new ComponentName("android", "FullBackupAgent");
             // startProcessLocked() returns existing proc's record if it's already running
             ProcessRecord proc = startProcessLocked(app.processName, app,
-                    false, 0, "backup", hostingName, false, false);
+                    false, 0, "backup", hostingName, false, false, false);
             if (proc == null) {
                 Slog.e(TAG, "Unable to start backup agent process " + r);
                 return false;
@@ -11555,7 +12660,7 @@
     private final List getStickiesLocked(String action, IntentFilter filter,
             List cur, int userId) {
         final ContentResolver resolver = mContext.getContentResolver();
-        HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
+        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
         if (stickies == null) {
             return cur;
         }
@@ -11613,7 +12718,7 @@
                             + ") when registering receiver " + receiver);
                 }
                 if (callerApp.info.uid != Process.SYSTEM_UID &&
-                        !callerApp.pkgList.contains(callerPackage)) {
+                        !callerApp.pkgList.containsKey(callerPackage)) {
                     throw new SecurityException("Given caller package " + callerPackage
                             + " is not running in process " + callerApp);
                 }
@@ -11706,7 +12811,7 @@
                     Intent intent = (Intent)allSticky.get(i);
                     BroadcastQueue queue = broadcastQueueForIntent(intent);
                     BroadcastRecord r = new BroadcastRecord(queue, intent, null,
-                            null, -1, -1, null, AppOpsManager.OP_NONE, receivers, null, 0,
+                            null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
                             null, null, false, true, true, -1);
                     queue.enqueueParallelBroadcastLocked(r);
                     queue.scheduleBroadcastsLocked();
@@ -11725,14 +12830,13 @@
             boolean doTrim = false;
 
             synchronized(this) {
-                ReceiverList rl
-                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                 if (rl != null) {
                     if (rl.curBroadcast != null) {
                         BroadcastRecord r = rl.curBroadcast;
                         final boolean doNext = finishReceiverLocked(
                                 receiver.asBinder(), r.resultCode, r.resultData,
-                                r.resultExtras, r.resultAbort, true);
+                                r.resultExtras, r.resultAbort);
                         if (doNext) {
                             doTrim = true;
                             r.queue.processNextBroadcast(false);
@@ -11967,7 +13071,8 @@
                         String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                         if (list != null && (list.length > 0)) {
                             for (String pkg : list) {
-                                forceStopPackageLocked(pkg, -1, false, true, true, false, userId);
+                                forceStopPackageLocked(pkg, -1, false, true, true, false, userId,
+                                        "storage unmount");
                             }
                             sendPackageBroadcastLocked(
                                     IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list, userId);
@@ -11976,17 +13081,22 @@
                         Uri data = intent.getData();
                         String ssp;
                         if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+                            boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(
+                                    intent.getAction());
                             if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
                                 forceStopPackageLocked(ssp,
                                         intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true,
-                                        false, userId);
+                                        false, userId, removed ? "pkg removed" : "pkg changed");
                             }
-                            if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                            if (removed) {
                                 sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                         new String[] {ssp}, userId);
                                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                                     mAppOpsService.packageRemoved(
                                             intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
+
+                                    // Remove all permissions granted from/to this package
+                                    removeUriPermissionsForPackageLocked(ssp, userId, true);
                                 }
                             }
                         }
@@ -12023,12 +13133,12 @@
         }
 
         if (intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) {
-            mHandler.sendEmptyMessage(CLEAR_DNS_CACHE);
+            mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
         }
 
         if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
             ProxyProperties proxy = intent.getParcelableExtra("proxy");
-            mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY, proxy));
+            mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
         }
 
         // Add to the sticky list if requested.
@@ -12057,7 +13167,7 @@
                 // But first, if this is not a broadcast to all users, then
                 // make sure it doesn't conflict with an existing broadcast to
                 // all users.
-                HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
+                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
                         UserHandle.USER_ALL);
                 if (stickies != null) {
                     ArrayList<Intent> list = stickies.get(intent.getAction());
@@ -12074,9 +13184,9 @@
                     }
                 }
             }
-            HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
+            ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
             if (stickies == null) {
-                stickies = new HashMap<String, ArrayList<Intent>>();
+                stickies = new ArrayMap<String, ArrayList<Intent>>();
                 mStickyBroadcasts.put(userId, stickies);
             }
             ArrayList<Intent> list = stickies.get(intent.getAction());
@@ -12133,8 +13243,8 @@
             // components to be launched.
             final BroadcastQueue queue = broadcastQueueForIntent(intent);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
-                    callerPackage, callingPid, callingUid, requiredPermission, appOp,
-                    registeredReceivers, resultTo, resultCode, resultData, map,
+                    callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
+                    appOp, registeredReceivers, resultTo, resultCode, resultData, map,
                     ordered, sticky, false, userId);
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing parallel broadcast " + r);
@@ -12223,9 +13333,9 @@
                 || resultTo != null) {
             BroadcastQueue queue = broadcastQueueForIntent(intent);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
-                    callerPackage, callingPid, callingUid, requiredPermission, appOp,
-                    receivers, resultTo, resultCode, resultData, map, ordered,
-                    sticky, false, userId);
+                    callerPackage, callingPid, callingUid, resolvedType,
+                    requiredPermission, appOp, receivers, resultTo, resultCode,
+                    resultData, map, ordered, sticky, false, userId);
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing ordered broadcast " + r
                     + ": prev had " + queue.mOrderedBroadcasts.size());
@@ -12329,7 +13439,7 @@
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
             }
-            HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
+            ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
             if (stickies != null) {
                 ArrayList<Intent> list = stickies.get(intent.getAction());
                 if (list != null) {
@@ -12353,16 +13463,20 @@
     }
 
     private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort,
-            boolean explicit) {
+            String resultData, Bundle resultExtras, boolean resultAbort) {
         final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
         if (r == null) {
             Slog.w(TAG, "finishReceiver called but not found on queue");
             return false;
         }
 
-        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
-                explicit);
+        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false);
+    }
+
+    void backgroundServicesFinishedLocked(int userId) {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.backgroundServicesFinishedLocked(userId);
+        }
     }
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -12377,7 +13491,7 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             boolean doNext = false;
-            BroadcastRecord r = null;
+            BroadcastRecord r;
 
             synchronized(this) {
                 r = broadcastRecordForReceiverLocked(who);
@@ -12450,7 +13564,8 @@
 
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
-            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId);
+            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId,
+                    "start instr");
             ProcessRecord app = addAppLocked(ai, false);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
@@ -12517,7 +13632,8 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, app.userId);
+        forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, app.userId,
+                "finished inst");
     }
 
     public void finishInstrumentation(IApplicationThread target,
@@ -12563,6 +13679,10 @@
         return config;
     }
 
+    ActivityStack getFocusedStack() {
+        return mStackSupervisor.getFocusedStack();
+    }
+
     public Configuration getConfiguration() {
         Configuration ci;
         synchronized(this) {
@@ -12624,9 +13744,7 @@
         if (mHeadless) return true;
 
         int changes = 0;
-        
-        boolean kept = true;
-        
+
         if (values != null) {
             Configuration newConfig = new Configuration(mConfiguration);
             changes = newConfig.updateFrom(values);
@@ -12704,25 +13822,27 @@
                 }
             }
         }
-        
+
+        boolean kept = true;
+        final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
         if (changes != 0 && starting == null) {
             // If the configuration changed, and the caller is not already
             // in the process of starting an activity, then find the top
             // activity to check if its configuration needs to change.
-            starting = mMainStack.topRunningActivityLocked(null);
+            starting = mainStack.topRunningActivityLocked(null);
         }
-        
+
         if (starting != null) {
-            kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
+            kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
             // And we need to make sure at this point that all other activities
             // are made visible with the correct configuration.
-            mMainStack.ensureActivitiesVisibleLocked(starting, changes);
+            mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
         }
-        
+
         if (values != null && mWindowManager != null) {
             mWindowManager.setNewConfiguration(mConfiguration);
         }
-        
+
         return kept;
     }
 
@@ -12738,7 +13858,7 @@
         return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                 && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH);
     }
-    
+
     /**
      * Save the locale.  You must be inside a synchronized (this) block.
      */
@@ -12764,96 +13884,13 @@
 
     public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
             Intent resultData) {
-        ComponentName dest = destIntent.getComponent();
 
         synchronized (this) {
-            ActivityRecord srec = ActivityRecord.forToken(token);
-            if (srec == null) {
-                return false;
+            final ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                return stack.navigateUpToLocked(token, destIntent, resultCode, resultData);
             }
-            ArrayList<ActivityRecord> history = srec.stack.mHistory;
-            final int start = history.indexOf(srec);
-            if (start < 0) {
-                // Current activity is not in history stack; do nothing.
-                return false;
-            }
-            int finishTo = start - 1;
-            ActivityRecord parent = null;
-            boolean foundParentInTask = false;
-            if (dest != null) {
-                TaskRecord tr = srec.task;
-                for (int i = start - 1; i >= 0; i--) {
-                    ActivityRecord r = history.get(i);
-                    if (tr != r.task) {
-                        // Couldn't find parent in the same task; stop at the one above this.
-                        // (Root of current task; in-app "home" behavior)
-                        // Always at least finish the current activity.
-                        finishTo = Math.min(start - 1, i + 1);
-                        parent = history.get(finishTo);
-                        break;
-                    } else if (r.info.packageName.equals(dest.getPackageName()) &&
-                            r.info.name.equals(dest.getClassName())) {
-                        finishTo = i;
-                        parent = r;
-                        foundParentInTask = true;
-                        break;
-                    }
-                }
-            }
-
-            if (mController != null) {
-                ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
-                if (next != null) {
-                    // ask watcher if this is allowed
-                    boolean resumeOK = true;
-                    try {
-                        resumeOK = mController.activityResuming(next.packageName);
-                    } catch (RemoteException e) {
-                        mController = null;
-                        Watchdog.getInstance().setActivityController(null);
-                    }
-
-                    if (!resumeOK) {
-                        return false;
-                    }
-                }
-            }
-            final long origId = Binder.clearCallingIdentity();
-            for (int i = start; i > finishTo; i--) {
-                ActivityRecord r = history.get(i);
-                mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
-                        "navigate-up", true);
-                // Only return the supplied result for the first activity finished
-                resultCode = Activity.RESULT_CANCELED;
-                resultData = null;
-            }
-
-            if (parent != null && foundParentInTask) {
-                final int parentLaunchMode = parent.info.launchMode;
-                final int destIntentFlags = destIntent.getFlags();
-                if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
-                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
-                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
-                        (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                    parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
-                } else {
-                    try {
-                        ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
-                                destIntent.getComponent(), 0, srec.userId);
-                        int res = mMainStack.startActivityLocked(srec.app.thread, destIntent,
-                                null, aInfo, parent.appToken, null,
-                                0, -1, parent.launchedFromUid, parent.launchedFromPackage,
-                                0, null, true, null);
-                        foundParentInTask = res == ActivityManager.START_SUCCESS;
-                    } catch (RemoteException e) {
-                        foundParentInTask = false;
-                    }
-                    mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
-                            resultData, "navigate-up", true);
-                }
-            }
-            Binder.restoreCallingIdentity(origId);
-            return foundParentInTask;
+            return false;
         }
     }
 
@@ -12899,36 +13936,25 @@
         return null;
     }
 
-    private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj, int clientHiddenAdj,
-            int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
+    private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
+            boolean doingAll, long now) {
         if (mAdjSeq == app.adjSeq) {
-            // This adjustment has already been computed.  If we are calling
-            // from the top, we may have already computed our adjustment with
-            // an earlier hidden adjustment that isn't really for us... if
-            // so, use the new hidden adjustment.
-            if (!recursed && app.hidden) {
-                if (app.hasActivities) {
-                    app.curAdj = app.curRawAdj = app.nonStoppingAdj = hiddenAdj;
-                } else if (app.hasClientActivities) {
-                    app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientHiddenAdj;
-                } else {
-                    app.curAdj = app.curRawAdj = app.nonStoppingAdj = emptyAdj;
-                }
-            }
+            // This adjustment has already been computed.
             return app.curRawAdj;
         }
 
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
             app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            return (app.curAdj=app.curRawAdj=ProcessList.HIDDEN_APP_MAX_ADJ);
+            app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+            return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
         }
 
         app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
         app.adjSource = null;
         app.adjTarget = null;
         app.empty = false;
-        app.hidden = false;
+        app.cached = false;
         app.hasClientActivities = false;
 
         final int activitiesSize = app.activities.size();
@@ -12938,11 +13964,12 @@
             // below foreground, so it is not worth doing work for it.
             app.adjType = "fixed";
             app.adjSeq = mAdjSeq;
-            app.curRawAdj = app.nonStoppingAdj = app.maxAdj;
+            app.curRawAdj = app.maxAdj;
             app.hasActivities = false;
             app.foregroundActivities = false;
             app.keeping = true;
             app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+            app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
             // System process can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
             // facilitate this, here we need to determine whether or not it
@@ -12962,6 +13989,9 @@
                     }
                 }
             }
+            if (!app.systemNoUi) {
+                app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+            }
             return (app.curAdj=app.maxAdj);
         }
 
@@ -12973,6 +14003,7 @@
         // important to least, and assign an appropriate OOM adjustment.
         int adj;
         int schedGroup;
+        int procState;
         boolean foregroundActivities = false;
         boolean interesting = false;
         BroadcastQueue queue;
@@ -12984,12 +14015,14 @@
             foregroundActivities = true;
             interesting = true;
             app.hasActivities = true;
+            procState = ActivityManager.PROCESS_STATE_TOP;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
             interesting = true;
+            procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
         } else if ((queue = isReceivingBroadcast(app)) != null) {
             // An app that is currently receiving a broadcast also
             // counts as being in the foreground for OOM killer purposes.
@@ -12999,36 +14032,50 @@
             schedGroup = (queue == mFgBroadcastQueue)
                     ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "broadcast";
+            procState = ActivityManager.PROCESS_STATE_RECEIVER;
         } else if (app.executingServices.size() > 0) {
             // An app that is currently executing a service callback also
             // counts as being in the foreground.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_DEFAULT;
+            schedGroup = app.execServicesFg ?
+                    Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "exec-service";
+            procState = ActivityManager.PROCESS_STATE_SERVICE;
+            //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
         } else {
-            // Assume process is hidden (has activities); we will correct
-            // later if this is not the case.
-            adj = hiddenAdj;
+            // As far as we know the process is empty.  We may change our mind later.
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            app.hidden = true;
-            app.adjType = "bg-act";
+            // At this point we don't actually know the adjustment.  Use the cached adj
+            // value that the caller wants us to.
+            adj = cachedAdj;
+            procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+            app.cached = true;
+            app.empty = true;
+            app.adjType = "cch-empty";
         }
 
-        boolean hasStoppingActivities = false;
-
         // Examine all activities if not already foreground.
         if (!foregroundActivities && activitiesSize > 0) {
             for (int j = 0; j < activitiesSize; j++) {
                 final ActivityRecord r = app.activities.get(j);
+                if (r.app != app) {
+                    Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
+                            + app + "?!?");
+                    continue;
+                }
+                app.hasActivities = true;
                 if (r.visible) {
                     // App has a visible activity; only upgrade adjustment.
                     if (adj > ProcessList.VISIBLE_APP_ADJ) {
                         adj = ProcessList.VISIBLE_APP_ADJ;
                         app.adjType = "visible";
                     }
+                    if (procState > ActivityManager.PROCESS_STATE_TOP) {
+                        procState = ActivityManager.PROCESS_STATE_TOP;
+                    }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
-                    app.hidden = false;
-                    app.hasActivities = true;
+                    app.cached = false;
+                    app.empty = false;
                     foregroundActivities = true;
                     break;
                 } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
@@ -13036,32 +14083,39 @@
                         adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                         app.adjType = "pausing";
                     }
-                    app.hidden = false;
+                    if (procState > ActivityManager.PROCESS_STATE_TOP) {
+                        procState = ActivityManager.PROCESS_STATE_TOP;
+                    }
+                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    app.cached = false;
+                    app.empty = false;
                     foregroundActivities = true;
                 } else if (r.state == ActivityState.STOPPING) {
-                    // We will apply the actual adjustment later, because
-                    // we want to allow this process to immediately go through
-                    // any memory trimming that is in effect.
-                    app.hidden = false;
+                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                        app.adjType = "stopping";
+                    }
+                    // For the process state, we will at this point consider the
+                    // process to be cached.  It will be cached either as an activity
+                    // or empty depending on whether the activity is finishing.  We do
+                    // this so that we can treat the process as cached for purposes of
+                    // memory trimming (determing current memory level, trim command to
+                    // send to process) since there can be an arbitrary number of stopping
+                    // processes and they should soon all go into the cached state.
+                    if (!r.finishing) {
+                        if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                            procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+                        }
+                    }
+                    app.cached = false;
+                    app.empty = false;
                     foregroundActivities = true;
-                    hasStoppingActivities = true;
+                } else {
+                    if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                        procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+                        app.adjType = "cch-act";
+                    }
                 }
-                if (r.app == app) {
-                    app.hasActivities = true;
-                }
-            }
-        }
-
-        if (adj == hiddenAdj && !app.hasActivities) {
-            if (app.hasClientActivities) {
-                adj = clientHiddenAdj;
-                app.adjType = "bg-client-act";
-            } else {
-                // Whoops, this process is completely empty as far as we know
-                // at this point.
-                adj = emptyAdj;
-                app.empty = true;
-                app.adjType = "bg-empty";
             }
         }
 
@@ -13069,13 +14123,15 @@
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                app.hidden = false;
+                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                app.cached = false;
                 app.adjType = "fg-service";
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             } else if (app.forcingToForeground != null) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                app.hidden = false;
+                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                app.cached = false;
                 app.adjType = "force-fg";
                 app.adjSource = app.forcingToForeground;
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13086,32 +14142,46 @@
             interesting = true;
         }
 
-        if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
-            // We don't want to kill the current heavy-weight process.
-            adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            app.hidden = false;
-            app.adjType = "heavy";
+        if (app == mHeavyWeightProcess) {
+            if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                // We don't want to kill the current heavy-weight process.
+                adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
+                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                app.cached = false;
+                app.adjType = "heavy";
+            }
+            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
+                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+            }
         }
 
-        if (adj > ProcessList.HOME_APP_ADJ && app == mHomeProcess) {
-            // This process is hosting what we currently consider to be the
-            // home app, so we don't want to let it go into the background.
-            adj = ProcessList.HOME_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            app.hidden = false;
-            app.adjType = "home";
+        if (app == mHomeProcess) {
+            if (adj > ProcessList.HOME_APP_ADJ) {
+                // This process is hosting what we currently consider to be the
+                // home app, so we don't want to let it go into the background.
+                adj = ProcessList.HOME_APP_ADJ;
+                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                app.cached = false;
+                app.adjType = "home";
+            }
+            if (procState > ActivityManager.PROCESS_STATE_HOME) {
+                procState = ActivityManager.PROCESS_STATE_HOME;
+            }
         }
 
-        if (adj > ProcessList.PREVIOUS_APP_ADJ && app == mPreviousProcess
-                && app.activities.size() > 0) {
-            // This was the previous process that showed UI to the user.
-            // We want to try to keep it around more aggressively, to give
-            // a good experience around switching between two apps.
-            adj = ProcessList.PREVIOUS_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            app.hidden = false;
-            app.adjType = "previous";
+        if (app == mPreviousProcess && app.activities.size() > 0) {
+            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
+                // This was the previous process that showed UI to the user.
+                // We want to try to keep it around more aggressively, to give
+                // a good experience around switching between two apps.
+                adj = ProcessList.PREVIOUS_APP_ADJ;
+                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                app.cached = false;
+                app.adjType = "previous";
+            }
+            if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+                procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+            }
         }
 
         if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
@@ -13122,330 +14192,348 @@
         // this gives us a baseline and makes sure we don't get into an
         // infinite recursion.
         app.adjSeq = mAdjSeq;
-        app.curRawAdj = app.nonStoppingAdj = adj;
+        app.curRawAdj = adj;
+        app.hasStartedServices = false;
 
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
             if (adj > ProcessList.BACKUP_APP_ADJ) {
                 if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
                 adj = ProcessList.BACKUP_APP_ADJ;
+                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+                }
                 app.adjType = "backup";
-                app.hidden = false;
+                app.cached = false;
+            }
+            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
+                procState = ActivityManager.PROCESS_STATE_BACKUP;
             }
         }
 
-        if (app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
-            final long now = SystemClock.uptimeMillis();
-            // This process is more important if the top activity is
-            // bound to the service.
-            Iterator<ServiceRecord> jt = app.services.iterator();
-            while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
-                ServiceRecord s = jt.next();
-                if (s.startRequested) {
-                    if (app.hasShownUi && app != mHomeProcess) {
-                        // If this process has shown some UI, let it immediately
-                        // go to the LRU list because it may be pretty heavy with
-                        // UI stuff.  We'll tag it with a label just to help
-                        // debug and understand what is going on.
+        for (int is = app.services.size()-1;
+                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                        || procState > ActivityManager.PROCESS_STATE_TOP);
+                is--) {
+            ServiceRecord s = app.services.valueAt(is);
+            if (s.startRequested) {
+                app.hasStartedServices = true;
+                if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
+                    procState = ActivityManager.PROCESS_STATE_SERVICE;
+                }
+                if (app.hasShownUi && app != mHomeProcess) {
+                    // If this process has shown some UI, let it immediately
+                    // go to the LRU list because it may be pretty heavy with
+                    // UI stuff.  We'll tag it with a label just to help
+                    // debug and understand what is going on.
+                    if (adj > ProcessList.SERVICE_ADJ) {
+                        app.adjType = "cch-started-ui-services";
+                    }
+                } else {
+                    if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+                        // This service has seen some activity within
+                        // recent memory, so we will keep its process ahead
+                        // of the background processes.
                         if (adj > ProcessList.SERVICE_ADJ) {
-                            app.adjType = "started-bg-ui-services";
-                        }
-                    } else {
-                        if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
-                            // This service has seen some activity within
-                            // recent memory, so we will keep its process ahead
-                            // of the background processes.
-                            if (adj > ProcessList.SERVICE_ADJ) {
-                                adj = ProcessList.SERVICE_ADJ;
-                                app.adjType = "started-services";
-                                app.hidden = false;
-                            }
-                        }
-                        // If we have let the service slide into the background
-                        // state, still have some text describing what it is doing
-                        // even though the service no longer has an impact.
-                        if (adj > ProcessList.SERVICE_ADJ) {
-                            app.adjType = "started-bg-services";
+                            adj = ProcessList.SERVICE_ADJ;
+                            app.adjType = "started-services";
+                            app.cached = false;
                         }
                     }
-                    // Don't kill this process because it is doing work; it
-                    // has said it is doing work.
-                    app.keeping = true;
-                }
-                if (s.connections.size() > 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
-                    Iterator<ArrayList<ConnectionRecord>> kt
-                            = s.connections.values().iterator();
-                    while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
-                        ArrayList<ConnectionRecord> clist = kt.next();
-                        for (int i=0; i<clist.size() && adj > ProcessList.FOREGROUND_APP_ADJ; i++) {
-                            // XXX should compute this based on the max of
-                            // all connected clients.
-                            ConnectionRecord cr = clist.get(i);
-                            if (cr.binding.client == app) {
-                                // Binding to ourself is not interesting.
-                                continue;
-                            }
-                            if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
-                                ProcessRecord client = cr.binding.client;
-                                int clientAdj = adj;
-                                int myHiddenAdj = hiddenAdj;
-                                if (myHiddenAdj > client.hiddenAdj) {
-                                    if (client.hiddenAdj >= ProcessList.VISIBLE_APP_ADJ) {
-                                        myHiddenAdj = client.hiddenAdj;
-                                    } else {
-                                        myHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
-                                    }
-                                }
-                                int myClientHiddenAdj = clientHiddenAdj;
-                                if (myClientHiddenAdj > client.clientHiddenAdj) {
-                                    if (client.clientHiddenAdj >= ProcessList.VISIBLE_APP_ADJ) {
-                                        myClientHiddenAdj = client.clientHiddenAdj;
-                                    } else {
-                                        myClientHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
-                                    }
-                                }
-                                int myEmptyAdj = emptyAdj;
-                                if (myEmptyAdj > client.emptyAdj) {
-                                    if (client.emptyAdj >= ProcessList.VISIBLE_APP_ADJ) {
-                                        myEmptyAdj = client.emptyAdj;
-                                    } else {
-                                        myEmptyAdj = ProcessList.VISIBLE_APP_ADJ;
-                                    }
-                                }
-                                clientAdj = computeOomAdjLocked(client, myHiddenAdj,
-                                        myClientHiddenAdj, myEmptyAdj, TOP_APP, true, doingAll);
-                                String adjType = null;
-                                if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
-                                    // Not doing bind OOM management, so treat
-                                    // this guy more like a started service.
-                                    if (app.hasShownUi && app != mHomeProcess) {
-                                        // If this process has shown some UI, let it immediately
-                                        // go to the LRU list because it may be pretty heavy with
-                                        // UI stuff.  We'll tag it with a label just to help
-                                        // debug and understand what is going on.
-                                        if (adj > clientAdj) {
-                                            adjType = "bound-bg-ui-services";
-                                        }
-                                        app.hidden = false;
-                                        clientAdj = adj;
-                                    } else {
-                                        if (now >= (s.lastActivity
-                                                + ActiveServices.MAX_SERVICE_INACTIVITY)) {
-                                            // This service has not seen activity within
-                                            // recent memory, so allow it to drop to the
-                                            // LRU list if there is no other reason to keep
-                                            // it around.  We'll also tag it with a label just
-                                            // to help debug and undertand what is going on.
-                                            if (adj > clientAdj) {
-                                                adjType = "bound-bg-services";
-                                            }
-                                            clientAdj = adj;
-                                        }
-                                    }
-                                } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
-                                    if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
-                                        // If this connection is keeping the service
-                                        // created, then we want to try to better follow
-                                        // its memory management semantics for activities.
-                                        // That is, if it is sitting in the background
-                                        // LRU list as a hidden process (with activities),
-                                        // we don't want the service it is connected to
-                                        // to go into the empty LRU and quickly get killed,
-                                        // because I'll we'll do is just end up restarting
-                                        // the service.
-                                        app.hasClientActivities |= client.hasActivities;
-                                    }
-                                }
-                                if (adj > clientAdj) {
-                                    // If this process has recently shown UI, and
-                                    // the process that is binding to it is less
-                                    // important than being visible, then we don't
-                                    // care about the binding as much as we care
-                                    // about letting this process get into the LRU
-                                    // list to be killed and restarted if needed for
-                                    // memory.
-                                    if (app.hasShownUi && app != mHomeProcess
-                                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                                        adjType = "bound-bg-ui-services";
-                                    } else {
-                                        if ((cr.flags&(Context.BIND_ABOVE_CLIENT
-                                                |Context.BIND_IMPORTANT)) != 0) {
-                                            adj = clientAdj;
-                                        } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
-                                                && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
-                                                && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                                            adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                                        } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
-                                            adj = clientAdj;
-                                        } else {
-                                            app.pendingUiClean = true;
-                                            if (adj > ProcessList.VISIBLE_APP_ADJ) {
-                                                adj = ProcessList.VISIBLE_APP_ADJ;
-                                            }
-                                        }
-                                        if (!client.hidden) {
-                                            app.hidden = false;
-                                        }
-                                        if (client.keeping) {
-                                            app.keeping = true;
-                                        }
-                                        adjType = "service";
-                                    }
-                                }
-                                if (adjType != null) {
-                                    app.adjType = adjType;
-                                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo
-                                            .REASON_SERVICE_IN_USE;
-                                    app.adjSource = cr.binding.client;
-                                    app.adjSourceOom = clientAdj;
-                                    app.adjTarget = s.name;
-                                }
-                                if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
-                                    if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
-                                        schedGroup = Process.THREAD_GROUP_DEFAULT;
-                                    }
-                                }
-                            }
-                            final ActivityRecord a = cr.activity;
-                            if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
-                                if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
-                                        (a.visible || a.state == ActivityState.RESUMED
-                                         || a.state == ActivityState.PAUSING)) {
-                                    adj = ProcessList.FOREGROUND_APP_ADJ;
-                                    if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
-                                        schedGroup = Process.THREAD_GROUP_DEFAULT;
-                                    }
-                                    app.hidden = false;
-                                    app.adjType = "service";
-                                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo
-                                            .REASON_SERVICE_IN_USE;
-                                    app.adjSource = a;
-                                    app.adjSourceOom = adj;
-                                    app.adjTarget = s.name;
-                                }
-                            }
-                        }
+                    // If we have let the service slide into the background
+                    // state, still have some text describing what it is doing
+                    // even though the service no longer has an impact.
+                    if (adj > ProcessList.SERVICE_ADJ) {
+                        app.adjType = "cch-started-services";
                     }
                 }
+                // Don't kill this process because it is doing work; it
+                // has said it is doing work.
+                app.keeping = true;
             }
-            
-            // Finally, if this process has active services running in it, we
-            // would like to avoid killing it unless it would prevent the current
-            // application from running.  By default we put the process in
-            // with the rest of the background processes; as we scan through
-            // its services we may bump it up from there.
-            if (adj > hiddenAdj) {
-                adj = hiddenAdj;
-                app.hidden = false;
-                app.adjType = "bg-services";
-            }
-        }
-
-        if (app.pubProviders.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
-            Iterator<ContentProviderRecord> jt = app.pubProviders.values().iterator();
-            while (jt.hasNext() && (adj > ProcessList.FOREGROUND_APP_ADJ
-                    || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
-                ContentProviderRecord cpr = jt.next();
-                for (int i = cpr.connections.size()-1;
-                        i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
-                        i--) {
-                    ContentProviderConnection conn = cpr.connections.get(i);
-                    ProcessRecord client = conn.client;
-                    if (client == app) {
-                        // Being our own client is not interesting.
+            for (int conni = s.connections.size()-1;
+                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                            || procState > ActivityManager.PROCESS_STATE_TOP);
+                    conni--) {
+                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+                for (int i = 0;
+                        i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
+                                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                                || procState > ActivityManager.PROCESS_STATE_TOP);
+                        i++) {
+                    // XXX should compute this based on the max of
+                    // all connected clients.
+                    ConnectionRecord cr = clist.get(i);
+                    if (cr.binding.client == app) {
+                        // Binding to ourself is not interesting.
                         continue;
                     }
-                    int myHiddenAdj = hiddenAdj;
-                    if (myHiddenAdj > client.hiddenAdj) {
-                        if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
-                            myHiddenAdj = client.hiddenAdj;
+                    if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
+                        ProcessRecord client = cr.binding.client;
+                        int clientAdj = computeOomAdjLocked(client, cachedAdj,
+                                TOP_APP, doingAll, now);
+                        int clientProcState = client.curProcState;
+                        if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                            // If the other app is cached for any reason, for purposes here
+                            // we are going to consider it empty.  The specific cached state
+                            // doesn't propagate except under certain conditions.
+                            clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                        }
+                        String adjType = null;
+                        if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+                            // Not doing bind OOM management, so treat
+                            // this guy more like a started service.
+                            if (app.hasShownUi && app != mHomeProcess) {
+                                // If this process has shown some UI, let it immediately
+                                // go to the LRU list because it may be pretty heavy with
+                                // UI stuff.  We'll tag it with a label just to help
+                                // debug and understand what is going on.
+                                if (adj > clientAdj) {
+                                    adjType = "cch-bound-ui-services";
+                                }
+                                app.cached = false;
+                                clientAdj = adj;
+                                clientProcState = procState;
+                            } else {
+                                if (now >= (s.lastActivity
+                                        + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+                                    // This service has not seen activity within
+                                    // recent memory, so allow it to drop to the
+                                    // LRU list if there is no other reason to keep
+                                    // it around.  We'll also tag it with a label just
+                                    // to help debug and undertand what is going on.
+                                    if (adj > clientAdj) {
+                                        adjType = "cch-bound-services";
+                                    }
+                                    clientAdj = adj;
+                                }
+                            }
+                        } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+                            if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
+                                // If this connection is keeping the service
+                                // created, then we want to try to better follow
+                                // its memory management semantics for activities.
+                                // That is, if it is sitting in the background
+                                // LRU list as a cached process (with activities),
+                                // we don't want the service it is connected to
+                                // to go into the empty LRU and quickly get killed,
+                                // because all we'll do is just end up restarting
+                                // the service.
+                                if (client.hasActivities) {
+                                    if (procState >
+                                            ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT) {
+                                        procState =
+                                                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+                                        app.adjType = "cch-client-act";
+                                    }
+                                    app.hasClientActivities = true;
+                                }
+                            }
+                        }
+                        if (adj > clientAdj) {
+                            // If this process has recently shown UI, and
+                            // the process that is binding to it is less
+                            // important than being visible, then we don't
+                            // care about the binding as much as we care
+                            // about letting this process get into the LRU
+                            // list to be killed and restarted if needed for
+                            // memory.
+                            if (app.hasShownUi && app != mHomeProcess
+                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                adjType = "cch-bound-ui-services";
+                            } else {
+                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
+                                        |Context.BIND_IMPORTANT)) != 0) {
+                                    adj = clientAdj;
+                                } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
+                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                    adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                                } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
+                                    adj = clientAdj;
+                                } else {
+                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
+                                        adj = ProcessList.VISIBLE_APP_ADJ;
+                                    }
+                                }
+                                if (!client.cached) {
+                                    app.cached = false;
+                                }
+                                if (client.keeping) {
+                                    app.keeping = true;
+                                }
+                                adjType = "service";
+                            }
+                        }
+                        if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+                            if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+                                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                            }
+                            if (clientProcState <=
+                                    ActivityManager.PROCESS_STATE_PERSISTENT_UI &&
+                                    clientProcState >=
+                                            ActivityManager.PROCESS_STATE_PERSISTENT) {
+                                // Persistent processes don't allow us to become top.
+                                // However the top process DOES allow us to become top,
+                                // because in that case we are running because the current
+                                // top process wants us, so we should be counted as part
+                                // of the top set and not just running for some random
+                                // unknown reason in the background.
+                                clientProcState =
+                                        ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                            }
                         } else {
-                            myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
+                            if (clientProcState <
+                                    ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+                                clientProcState =
+                                        ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+                            }
+                        }
+                        if (procState > clientProcState) {
+                            procState = clientProcState;
+                        }
+                        if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+                                && (cr.flags&Context.BIND_SHOWING_UI) != 0) {
+                            app.pendingUiClean = true;
+                        }
+                        if (adjType != null) {
+                            app.adjType = adjType;
+                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+                                    .REASON_SERVICE_IN_USE;
+                            app.adjSource = cr.binding.client;
+                            app.adjSourceOom = clientAdj;
+                            app.adjTarget = s.name;
                         }
                     }
-                    int myClientHiddenAdj = clientHiddenAdj;
-                    if (myClientHiddenAdj > client.clientHiddenAdj) {
-                        if (client.clientHiddenAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-                            myClientHiddenAdj = client.clientHiddenAdj;
-                        } else {
-                            myClientHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
+                    final ActivityRecord a = cr.activity;
+                    if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+                        if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
+                                (a.visible || a.state == ActivityState.RESUMED
+                                 || a.state == ActivityState.PAUSING)) {
+                            adj = ProcessList.FOREGROUND_APP_ADJ;
+                            if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+                                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                            }
+                            app.cached = false;
+                            app.adjType = "service";
+                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+                                    .REASON_SERVICE_IN_USE;
+                            app.adjSource = a;
+                            app.adjSourceOom = adj;
+                            app.adjTarget = s.name;
                         }
                     }
-                    int myEmptyAdj = emptyAdj;
-                    if (myEmptyAdj > client.emptyAdj) {
-                        if (client.emptyAdj > ProcessList.FOREGROUND_APP_ADJ) {
-                            myEmptyAdj = client.emptyAdj;
-                        } else {
-                            myEmptyAdj = ProcessList.FOREGROUND_APP_ADJ;
-                        }
-                    }
-                    int clientAdj = computeOomAdjLocked(client, myHiddenAdj,
-                            myClientHiddenAdj, myEmptyAdj, TOP_APP, true, doingAll);
-                    if (adj > clientAdj) {
-                        if (app.hasShownUi && app != mHomeProcess
-                                && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                            app.adjType = "bg-ui-provider";
-                        } else {
-                            adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
-                                    ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
-                            app.adjType = "provider";
-                        }
-                        if (!client.hidden) {
-                            app.hidden = false;
-                        }
-                        if (client.keeping) {
-                            app.keeping = true;
-                        }
-                        app.adjTypeCode = ActivityManager.RunningAppProcessInfo
-                                .REASON_PROVIDER_IN_USE;
-                        app.adjSource = client;
-                        app.adjSourceOom = clientAdj;
-                        app.adjTarget = cpr.name;
-                    }
-                    if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
-                        schedGroup = Process.THREAD_GROUP_DEFAULT;
-                    }
                 }
-                // If the provider has external (non-framework) process
-                // dependencies, ensure that its adjustment is at least
-                // FOREGROUND_APP_ADJ.
-                if (cpr.hasExternalProcessHandles()) {
-                    if (adj > ProcessList.FOREGROUND_APP_ADJ) {
-                        adj = ProcessList.FOREGROUND_APP_ADJ;
-                        schedGroup = Process.THREAD_GROUP_DEFAULT;
-                        app.hidden = false;
-                        app.keeping = true;
+            }
+        }
+
+        for (int provi = app.pubProviders.size()-1;
+                provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                        || procState > ActivityManager.PROCESS_STATE_TOP);
+                provi--) {
+            ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
+            for (int i = cpr.connections.size()-1;
+                    i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                            || procState > ActivityManager.PROCESS_STATE_TOP);
+                    i--) {
+                ContentProviderConnection conn = cpr.connections.get(i);
+                ProcessRecord client = conn.client;
+                if (client == app) {
+                    // Being our own client is not interesting.
+                    continue;
+                }
+                int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+                int clientProcState = client.curProcState;
+                if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                    // If the other app is cached for any reason, for purposes here
+                    // we are going to consider it empty.
+                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                }
+                if (adj > clientAdj) {
+                    if (app.hasShownUi && app != mHomeProcess
+                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        app.adjType = "cch-ui-provider";
+                    } else {
+                        adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
+                                ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
                         app.adjType = "provider";
-                        app.adjTarget = cpr.name;
                     }
+                    app.cached &= client.cached;
+                    app.keeping |= client.keeping;
+                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+                            .REASON_PROVIDER_IN_USE;
+                    app.adjSource = client;
+                    app.adjSourceOom = clientAdj;
+                    app.adjTarget = cpr.name;
+                }
+                if (clientProcState <=
+                        ActivityManager.PROCESS_STATE_PERSISTENT_UI &&
+                        clientProcState >=
+                                ActivityManager.PROCESS_STATE_PERSISTENT) {
+                    // Persistent processes don't allow us to become top.
+                    // However the top process DOES allow us to become top,
+                    // because in that case we are running because the current
+                    // top process wants us, so we should be counted as part
+                    // of the top set and not just running for some random
+                    // unknown reason in the background.
+                    clientProcState =
+                            ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                }
+                if (procState > clientProcState) {
+                    procState = clientProcState;
+                }
+                if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                }
+            }
+            // If the provider has external (non-framework) process
+            // dependencies, ensure that its adjustment is at least
+            // FOREGROUND_APP_ADJ.
+            if (cpr.hasExternalProcessHandles()) {
+                if (adj > ProcessList.FOREGROUND_APP_ADJ) {
+                    adj = ProcessList.FOREGROUND_APP_ADJ;
+                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    app.cached = false;
+                    app.keeping = true;
+                    app.adjType = "provider";
+                    app.adjTarget = cpr.name;
+                }
+                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
                 }
             }
         }
 
         if (adj == ProcessList.SERVICE_ADJ) {
             if (doingAll) {
-                app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3);
+                app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
                 mNewNumServiceProcs++;
+                //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
+                if (!app.serviceb) {
+                    // This service isn't far enough down on the LRU list to
+                    // normally be a B service, but if we are low on RAM and it
+                    // is large we want to force it down since we would prefer to
+                    // keep launcher over it.
+                    if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+                            && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
+                        app.serviceHighRam = true;
+                        app.serviceb = true;
+                        //Slog.i(TAG, "ADJ " + app + " high ram!");
+                    } else {
+                        mNewNumAServiceProcs++;
+                        //Slog.i(TAG, "ADJ " + app + " not high ram!");
+                    }
+                } else {
+                    app.serviceHighRam = false;
+                }
             }
             if (app.serviceb) {
                 adj = ProcessList.SERVICE_B_ADJ;
             }
-        } else {
-            app.serviceb = false;
-        }
-
-        app.nonStoppingAdj = adj;
-
-        if (hasStoppingActivities) {
-            // Only upgrade adjustment.
-            if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                app.adjType = "stopping";
-            }
         }
 
         app.curRawAdj = adj;
@@ -13458,28 +14546,18 @@
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             }
         }
-        if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) {
+        if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
             app.keeping = true;
         }
 
-        if (app.hasAboveClient) {
-            // If this process has bound to any services with BIND_ABOVE_CLIENT,
-            // then we need to drop its adjustment to be lower than the service's
-            // in order to honor the request.  We want to drop it by one adjustment
-            // level...  but there is special meaning applied to various levels so
-            // we will skip some of them.
-            if (adj < ProcessList.FOREGROUND_APP_ADJ) {
-                // System process will not get dropped, ever
-            } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
-                adj = ProcessList.VISIBLE_APP_ADJ;
-            } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-            } else if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) {
-                adj = ProcessList.HIDDEN_APP_MIN_ADJ;
-            } else if (adj < ProcessList.HIDDEN_APP_MAX_ADJ) {
-                adj++;
-            }
-        }
+        // Do final modification to adj.  Everything we do between here and applying
+        // the final setAdj must be done in this function, because we will also use
+        // it when computing the final cached adj later.  Note that we don't need to
+        // worry about this for max adj above, since max adj will always be used to
+        // keep it out of the cached vaues.
+        adj = app.modifyRawOomAdj(adj);
+
+        app.curProcState = procState;
 
         int importance = app.memImportance;
         if (importance == 0 || adj != app.curAdj || schedGroup != app.curSchedGroup) {
@@ -13490,7 +14568,7 @@
                 // interesting in this process then we will push it to the
                 // background importance.
                 importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+            } else if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
                 importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
             } else if (adj >= ProcessList.SERVICE_B_ADJ) {
                 importance =  ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
@@ -13565,6 +14643,47 @@
     }
 
     /**
+     * Schedule PSS collection of a process.
+     */
+    void requestPssLocked(ProcessRecord proc, int procState) {
+        if (mPendingPssProcesses.contains(proc)) {
+            return;
+        }
+        if (mPendingPssProcesses.size() == 0) {
+            mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+        }
+        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of: " + proc);
+        proc.pssProcState = procState;
+        mPendingPssProcesses.add(proc);
+    }
+
+    /**
+     * Schedule PSS collection of all processes.
+     */
+    void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
+        if (!always) {
+            if (now < (mLastFullPssTime +
+                    (memLowered ? FULL_PSS_LOWERED_INTERVAL : FULL_PSS_MIN_INTERVAL))) {
+                return;
+            }
+        }
+        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of all procs!  memLowered=" + memLowered);
+        mLastFullPssTime = now;
+        mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
+        mPendingPssProcesses.clear();
+        for (int i=mLruProcesses.size()-1; i>=0; i--) {
+            ProcessRecord app = mLruProcesses.get(i);
+            if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
+                app.pssProcState = app.setProcState;
+                app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
+                        mSleeping, now);
+                mPendingPssProcesses.add(app);
+            }
+        }
+        mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+    }
+
+    /**
      * Ask a given process to GC right now.
      */
     final void performAppGcLocked(ProcessRecord app) {
@@ -13594,8 +14713,7 @@
             }
         }
         return !processingBroadcasts
-                && (mSleeping || (mMainStack.mResumedActivity != null &&
-                        mMainStack.mResumedActivity.idle));
+                && (mSleeping || mStackSupervisor.allResumedActivitiesIdle());
     }
     
     /**
@@ -13771,24 +14889,18 @@
                         stats.reportExcessiveWakeLocked(app.info.uid, app.processName,
                                 realtimeSince, wtimeUsed);
                     }
-                    Slog.w(TAG, "Excessive wake lock in " + app.processName
-                            + " (pid " + app.pid + "): held " + wtimeUsed
+                    killUnneededProcessLocked(app, "excessive wake held " + wtimeUsed
                             + " during " + realtimeSince);
-                    EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                            app.processName, app.setAdj, "excessive wake lock");
-                    Process.killProcessQuiet(app.pid);
+                    app.baseProcessTracker.reportExcessiveWake(app.pkgList);
                 } else if (doCpuKills && uptimeSince > 0
                         && ((cputimeUsed*100)/uptimeSince) >= 50) {
                     synchronized (stats) {
                         stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
                                 uptimeSince, cputimeUsed);
                     }
-                    Slog.w(TAG, "Excessive CPU in " + app.processName
-                            + " (pid " + app.pid + "): used " + cputimeUsed
+                    killUnneededProcessLocked(app, "excessive cpu " + cputimeUsed
                             + " during " + uptimeSince);
-                    EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                            app.processName, app.setAdj, "excessive cpu");
-                    Process.killProcessQuiet(app.pid);
+                    app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
                 } else {
                     app.lastWakeTime = wtime;
                     app.lastCpuTime = app.curCpuTime;
@@ -13797,22 +14909,10 @@
         }
     }
 
-    private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj,
-            int clientHiddenAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) {
-        app.hiddenAdj = hiddenAdj;
-        app.clientHiddenAdj = clientHiddenAdj;
-        app.emptyAdj = emptyAdj;
-
-        if (app.thread == null) {
-            return false;
-        }
-
-        final boolean wasKeeping = app.keeping;
-
+    private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
+            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
         boolean success = true;
 
-        computeOomAdjLocked(app, hiddenAdj, clientHiddenAdj, emptyAdj, TOP_APP, false, doingAll);
-
         if (app.curRawAdj != app.setRawAdj) {
             if (wasKeeping && !app.keeping) {
                 // This app is no longer something we want to keep.  Note
@@ -13847,11 +14947,7 @@
                     + " to " + app.curSchedGroup);
             if (app.waitingToKill != null &&
                     app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
-                Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
-                EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                        app.processName, app.setAdj, app.waitingToKill);
-                app.killedBackground = true;
-                Process.killProcessQuiet(app.pid);
+                killUnneededProcessLocked(app, app.waitingToKill);
                 success = false;
             } else {
                 if (true) {
@@ -13873,37 +14969,105 @@
                         }
                     }
                 }
+                Process.setSwappiness(app.pid,
+                        app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE);
+            }
+        }
+        if (app.repProcState != app.curProcState) {
+            app.repProcState = app.curProcState;
+            if (!reportingProcessState && app.thread != null) {
+                try {
+                    if (false) {
+                        //RuntimeException h = new RuntimeException("here");
+                        Slog.i(TAG, "Sending new process state " + app.repProcState
+                                + " to " + app /*, h*/);
+                    }
+                    app.thread.setProcessState(app.repProcState);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState,
+                app.setProcState)) {
+            app.lastStateTime = now;
+            app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
+                    mSleeping, now);
+            if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+                    + ProcessList.makeProcStateString(app.setProcState) + " to "
+                    + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
+                    + (app.nextPssTime-now) + ": " + app);
+        } else {
+            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
+                    && now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) {
+                requestPssLocked(app, app.setProcState);
+                app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
+                        mSleeping, now);
+            } else if (false && DEBUG_PSS) {
+                Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
+            }
+        }
+        if (app.setProcState != app.curProcState) {
+            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+                    "Proc state change of " + app.processName
+                    + " to " + app.curProcState);
+            app.setProcState = app.curProcState;
+            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
+                app.notCachedSinceIdle = false;
+            }
+            if (!doingAll) {
+                setProcessTrackerState(app, mProcessStats.getMemFactorLocked(), now);
+            } else {
+                app.procStateChanged = true;
             }
         }
         return success;
     }
 
-    private final ActivityRecord resumedAppLocked() {
-        ActivityRecord resumedActivity = mMainStack.mResumedActivity;
-        if (resumedActivity == null || resumedActivity.app == null) {
-            resumedActivity = mMainStack.mPausingActivity;
-            if (resumedActivity == null || resumedActivity.app == null) {
-                resumedActivity = mMainStack.topRunningActivityLocked(null);
-            }
+    private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
+        if (proc.thread != null && proc.baseProcessTracker != null) {
+            proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
         }
-        return resumedActivity;
+    }
+
+    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
+            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+        if (app.thread == null) {
+            return false;
+        }
+
+        final boolean wasKeeping = app.keeping;
+
+        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
+
+        return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll,
+                reportingProcessState, now);
+    }
+
+    private final ActivityRecord resumedAppLocked() {
+        return mStackSupervisor.resumedAppLocked();
     }
 
     final boolean updateOomAdjLocked(ProcessRecord app) {
+        return updateOomAdjLocked(app, false);
+    }
+
+    final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
-        int curAdj = app.curAdj;
-        final boolean wasHidden = curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
-            && curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
+        final boolean wasCached = app.cached;
 
         mAdjSeq++;
 
-        boolean success = updateOomAdjLocked(app, app.hiddenAdj, app.clientHiddenAdj,
-                app.emptyAdj, TOP_APP, false);
-        final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
-            && app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
-        if (nowHidden != wasHidden) {
-            // Changed to/from hidden state, so apps after it in the LRU
+        // This is the desired cached adjusment we want to tell it to use.
+        // If our app is currently cached, we know it, and that is it.  Otherwise,
+        // we don't know it yet, and it needs to now be cached we will then
+        // need to do a complete oom adj.
+        final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
+                ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
+        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState,
+                SystemClock.uptimeMillis());
+        if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
+            // Changed to/from cached state, so apps after it in the LRU
             // list may also be changed.
             updateOomAdjLocked();
         }
@@ -13913,7 +15077,9 @@
     final void updateOomAdjLocked() {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
-        final long oldTime = SystemClock.uptimeMillis() - ProcessList.MAX_EMPTY_TIME;
+        final long now = SystemClock.uptimeMillis();
+        final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
+        final int N = mLruProcesses.size();
 
         if (false) {
             RuntimeException e = new RuntimeException();
@@ -13923,143 +15089,154 @@
 
         mAdjSeq++;
         mNewNumServiceProcs = 0;
+        mNewNumAServiceProcs = 0;
 
         final int emptyProcessLimit;
-        final int hiddenProcessLimit;
+        final int cachedProcessLimit;
         if (mProcessLimit <= 0) {
-            emptyProcessLimit = hiddenProcessLimit = 0;
+            emptyProcessLimit = cachedProcessLimit = 0;
         } else if (mProcessLimit == 1) {
             emptyProcessLimit = 1;
-            hiddenProcessLimit = 0;
+            cachedProcessLimit = 0;
         } else {
-            emptyProcessLimit = (mProcessLimit*2)/3;
-            hiddenProcessLimit = mProcessLimit - emptyProcessLimit;
+            emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
+            cachedProcessLimit = mProcessLimit - emptyProcessLimit;
         }
 
         // Let's determine how many processes we have running vs.
         // how many slots we have for background processes; we may want
         // to put multiple processes in a slot of there are enough of
         // them.
-        int numSlots = (ProcessList.HIDDEN_APP_MAX_ADJ
-                - ProcessList.HIDDEN_APP_MIN_ADJ + 1) / 2;
-        int numEmptyProcs = mLruProcesses.size()-mNumNonHiddenProcs-mNumHiddenProcs;
-        if (numEmptyProcs > hiddenProcessLimit) {
-            // If there are more empty processes than our limit on hidden
-            // processes, then use the hidden process limit for the factor.
+        int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
+                - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
+        int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
+        if (numEmptyProcs > cachedProcessLimit) {
+            // If there are more empty processes than our limit on cached
+            // processes, then use the cached process limit for the factor.
             // This ensures that the really old empty processes get pushed
             // down to the bottom, so if we are running low on memory we will
-            // have a better chance at keeping around more hidden processes
+            // have a better chance at keeping around more cached processes
             // instead of a gazillion empty processes.
-            numEmptyProcs = hiddenProcessLimit;
+            numEmptyProcs = cachedProcessLimit;
         }
         int emptyFactor = numEmptyProcs/numSlots;
         if (emptyFactor < 1) emptyFactor = 1;
-        int hiddenFactor = (mNumHiddenProcs > 0 ? mNumHiddenProcs : 1)/numSlots;
-        if (hiddenFactor < 1) hiddenFactor = 1;
-        int stepHidden = 0;
+        int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
+        if (cachedFactor < 1) cachedFactor = 1;
+        int stepCached = 0;
         int stepEmpty = 0;
-        int numHidden = 0;
+        int numCached = 0;
         int numEmpty = 0;
         int numTrimming = 0;
 
-        mNumNonHiddenProcs = 0;
-        mNumHiddenProcs = 0;
+        mNumNonCachedProcs = 0;
+        mNumCachedHiddenProcs = 0;
 
         // First update the OOM adjustment for each of the
         // application processes based on their current state.
-        int i = mLruProcesses.size();
-        int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
-        int nextHiddenAdj = curHiddenAdj+1;
-        int curEmptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
+        int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
+        int nextCachedAdj = curCachedAdj+1;
+        int curClientCachedAdj = curCachedAdj+1;
+        int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
         int nextEmptyAdj = curEmptyAdj+2;
-        int curClientHiddenAdj = curEmptyAdj;
-        while (i > 0) {
-            i--;
+        for (int i=N-1; i>=0; i--) {
             ProcessRecord app = mLruProcesses.get(i);
-            //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
-            updateOomAdjLocked(app, curHiddenAdj, curClientHiddenAdj, curEmptyAdj, TOP_APP, true);
-            if (!app.killedBackground) {
-                if (app.curRawAdj == curHiddenAdj && app.hasActivities) {
-                    // This process was assigned as a hidden process...  step the
-                    // hidden level.
-                    mNumHiddenProcs++;
-                    if (curHiddenAdj != nextHiddenAdj) {
-                        stepHidden++;
-                        if (stepHidden >= hiddenFactor) {
-                            stepHidden = 0;
-                            curHiddenAdj = nextHiddenAdj;
-                            nextHiddenAdj += 2;
-                            if (nextHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
-                                nextHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
-                            }
-                            if (curClientHiddenAdj <= curHiddenAdj) {
-                                curClientHiddenAdj = curHiddenAdj + 1;
-                                if (curClientHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
-                                    curClientHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
+            if (!app.killedByAm && app.thread != null) {
+                app.procStateChanged = false;
+                final boolean wasKeeping = app.keeping;
+                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+
+                // If we haven't yet assigned the final cached adj
+                // to the process, do that now.
+                if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
+                    switch (app.curProcState) {
+                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                            // This process is a cached process holding activities...
+                            // assign it the next cached value for that type, and then
+                            // step that cached level.
+                            app.curRawAdj = curCachedAdj;
+                            app.curAdj = app.modifyRawOomAdj(curCachedAdj);
+                            if (curCachedAdj != nextCachedAdj) {
+                                stepCached++;
+                                if (stepCached >= cachedFactor) {
+                                    stepCached = 0;
+                                    curCachedAdj = nextCachedAdj;
+                                    nextCachedAdj += 2;
+                                    if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+                                        nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+                                    }
+                                    if (curClientCachedAdj <= curCachedAdj) {
+                                        curClientCachedAdj = curCachedAdj + 1;
+                                        if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+                                            curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+                                        }
+                                    }
                                 }
                             }
-                        }
-                    }
-                    numHidden++;
-                    if (numHidden > hiddenProcessLimit) {
-                        Slog.i(TAG, "No longer want " + app.processName
-                                + " (pid " + app.pid + "): hidden #" + numHidden);
-                        EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                                app.processName, app.setAdj, "too many background");
-                        app.killedBackground = true;
-                        Process.killProcessQuiet(app.pid);
-                    }
-                } else if (app.curRawAdj == curHiddenAdj && app.hasClientActivities) {
-                    // This process has a client that has activities.  We will have
-                    // given it the current hidden adj; here we will just leave it
-                    // without stepping the hidden adj.
-                    curClientHiddenAdj++;
-                    if (curClientHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
-                        curClientHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
-                    }
-                } else {
-                    if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curHiddenAdj) {
-                        // This process was assigned as an empty process...  step the
-                        // empty level.
-                        if (curEmptyAdj != nextEmptyAdj) {
-                            stepEmpty++;
-                            if (stepEmpty >= emptyFactor) {
-                                stepEmpty = 0;
-                                curEmptyAdj = nextEmptyAdj;
-                                nextEmptyAdj += 2;
-                                if (nextEmptyAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
-                                    nextEmptyAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
+                            break;
+                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                            // Special case for cached client processes...  just step
+                            // down from after regular cached processes.
+                            app.curRawAdj = curClientCachedAdj;
+                            app.curAdj = app.modifyRawOomAdj(curClientCachedAdj);
+                            curClientCachedAdj++;
+                            if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+                                curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+                            }
+                            break;
+                        default:
+                            // For everything else, assign next empty cached process
+                            // level and bump that up.  Note that this means that
+                            // long-running services that have dropped down to the
+                            // cached level will be treated as empty (since their process
+                            // state is still as a service), which is what we want.
+                            app.curRawAdj = curEmptyAdj;
+                            app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
+                            if (curEmptyAdj != nextEmptyAdj) {
+                                stepEmpty++;
+                                if (stepEmpty >= emptyFactor) {
+                                    stepEmpty = 0;
+                                    curEmptyAdj = nextEmptyAdj;
+                                    nextEmptyAdj += 2;
+                                    if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+                                        nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
+                                    }
                                 }
                             }
-                        }
-                    } else if (app.curRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
-                        mNumNonHiddenProcs++;
+                            break;
                     }
-                    if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
-                            && !app.hasClientActivities) {
+                }
+
+                applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);
+
+                // Count the number of process types.
+                switch (app.curProcState) {
+                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                        mNumCachedHiddenProcs++;
+                        numCached++;
+                        if (numCached > cachedProcessLimit) {
+                            killUnneededProcessLocked(app, "cached #" + numCached);
+                        }
+                        break;
+                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
                         if (numEmpty > ProcessList.TRIM_EMPTY_APPS
                                 && app.lastActivityTime < oldTime) {
-                            Slog.i(TAG, "No longer want " + app.processName
-                                    + " (pid " + app.pid + "): empty for "
-                                    + ((oldTime+ProcessList.MAX_EMPTY_TIME-app.lastActivityTime)
-                                            / 1000) + "s");
-                            EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                                    app.processName, app.setAdj, "old background process");
-                            app.killedBackground = true;
-                            Process.killProcessQuiet(app.pid);
+                            killUnneededProcessLocked(app, "empty for "
+                                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
+                                    / 1000) + "s");
                         } else {
                             numEmpty++;
                             if (numEmpty > emptyProcessLimit) {
-                                Slog.i(TAG, "No longer want " + app.processName
-                                        + " (pid " + app.pid + "): empty #" + numEmpty);
-                                EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                                        app.processName, app.setAdj, "too many background");
-                                app.killedBackground = true;
-                                Process.killProcessQuiet(app.pid);
+                                killUnneededProcessLocked(app, "empty #" + numEmpty);
                             }
                         }
-                    }
+                        break;
+                    default:
+                        mNumNonCachedProcs++;
+                        break;
                 }
+
                 if (app.isolated && app.services.size() <= 0) {
                     // If this is an isolated process, and there are no
                     // services running in it, then the process is no longer
@@ -14067,16 +15244,11 @@
                     // definition not re-use the same process again, and it is
                     // good to avoid having whatever code was running in them
                     // left sitting around after no longer needed.
-                    Slog.i(TAG, "Isolated process " + app.processName
-                            + " (pid " + app.pid + ") no longer needed");
-                    EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
-                            app.processName, app.setAdj, "isolated not needed");
-                    app.killedBackground = true;
-                    Process.killProcessQuiet(app.pid);
+                    killUnneededProcessLocked(app, "isolated not needed");
                 }
-                if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
-                        && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
-                        && !app.killedBackground) {
+
+                if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
+                        && !app.killedByAm) {
                     numTrimming++;
                 }
             }
@@ -14090,32 +15262,72 @@
         // are managing to keep around is less than half the maximum we desire;
         // if we are keeping a good number around, we'll let them use whatever
         // memory they want.
-        if (numHidden <= ProcessList.TRIM_HIDDEN_APPS
+        final int numCachedAndEmpty = numCached + numEmpty;
+        int memFactor;
+        if (numCached <= ProcessList.TRIM_CACHED_APPS
                 && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
-            final int numHiddenAndEmpty = numHidden + numEmpty;
-            final int N = mLruProcesses.size();
+            if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
+                memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+            } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
+                memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
+            } else {
+                memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+            }
+        } else {
+            memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+        }
+        // We always allow the memory level to go up (better).  We only allow it to go
+        // down if we are in a state where that is allowed, *and* the total number of processes
+        // has gone down since last time.
+        if (DEBUG_OOM_ADJ) Slog.d(TAG, "oom: memFactor=" + memFactor + " last=" + mLastMemoryLevel
+                + " allowLow=" + mAllowLowerMemLevel + " numProcs=" + mLruProcesses.size()
+                + " last=" + mLastNumProcesses);
+        if (memFactor > mLastMemoryLevel) {
+            if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
+                memFactor = mLastMemoryLevel;
+                if (DEBUG_OOM_ADJ) Slog.d(TAG, "Keeping last mem factor!");
+            }
+        }
+        mLastMemoryLevel = memFactor;
+        mLastNumProcesses = mLruProcesses.size();
+        boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
+        final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+        if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
+            if (mLowRamStartTime == 0) {
+                mLowRamStartTime = now;
+            }
+            int step = 0;
+            int fgTrimLevel;
+            switch (memFactor) {
+                case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                    fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+                    break;
+                case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                    fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+                    break;
+                default:
+                    fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+                    break;
+            }
             int factor = numTrimming/3;
             int minFactor = 2;
             if (mHomeProcess != null) minFactor++;
             if (mPreviousProcess != null) minFactor++;
             if (factor < minFactor) factor = minFactor;
-            int step = 0;
-            int fgTrimLevel;
-            if (numHiddenAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
-                fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
-            } else if (numHiddenAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
-                fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
-            } else {
-                fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
-            }
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
-            for (i=0; i<N; i++) {
+            for (int i=N-1; i>=0; i--) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
-                        && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
-                        && !app.killedBackground) {
+                if (allChanged || app.procStateChanged) {
+                    setProcessTrackerState(app, trackerMemFactor, now);
+                    app.procStateChanged = false;
+                }
+                if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
+                        && !app.killedByAm) {
                     if (app.trimMemoryLevel < curLevel && app.thread != null) {
                         try {
+                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+                                    "Trimming memory of " + app.processName
+                                    + " to " + curLevel);
                             app.thread.scheduleTrimMemory(curLevel);
                         } catch (RemoteException e) {
                         }
@@ -14129,7 +15341,7 @@
                                 // be in a consistent state at this point.
                                 // For these apps we will also finish their activities
                                 // to help them free memory.
-                                mMainStack.scheduleDestroyActivities(app, false, "trim");
+                                mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
                             }
                         }
                     }
@@ -14146,10 +15358,13 @@
                                 break;
                         }
                     }
-                } else if (app.nonStoppingAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                             && app.thread != null) {
                         try {
+                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+                                    "Trimming memory of heavy-weight " + app.processName
+                                    + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
                             app.thread.scheduleTrimMemory(
                                     ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
                         } catch (RemoteException e) {
@@ -14157,14 +15372,17 @@
                     }
                     app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
                 } else {
-                    if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
-                            && app.pendingUiClean) {
+                    if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+                            || app.systemNoUi) && app.pendingUiClean) {
                         // If this application is now in the background and it
                         // had done UI, then give it the special trim level to
                         // have it free UI resources.
                         final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
                         if (app.trimMemoryLevel < level && app.thread != null) {
                             try {
+                                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+                                        "Trimming memory of bg-ui " + app.processName
+                                        + " to " + level);
                                 app.thread.scheduleTrimMemory(level);
                             } catch (RemoteException e) {
                             }
@@ -14173,6 +15391,9 @@
                     }
                     if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
                         try {
+                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+                                    "Trimming memory of fg " + app.processName
+                                    + " to " + fgTrimLevel);
                             app.thread.scheduleTrimMemory(fgTrimLevel);
                         } catch (RemoteException e) {
                         }
@@ -14181,14 +15402,24 @@
                 }
             }
         } else {
-            final int N = mLruProcesses.size();
-            for (i=0; i<N; i++) {
+            if (mLowRamStartTime != 0) {
+                mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
+                mLowRamStartTime = 0;
+            }
+            for (int i=N-1; i>=0; i--) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
-                        && app.pendingUiClean) {
+                if (allChanged || app.procStateChanged) {
+                    setProcessTrackerState(app, trackerMemFactor, now);
+                    app.procStateChanged = false;
+                }
+                if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+                        || app.systemNoUi) && app.pendingUiClean) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                             && app.thread != null) {
                         try {
+                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+                                    "Trimming memory of ui hidden " + app.processName
+                                    + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                             app.thread.scheduleTrimMemory(
                                     ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                         } catch (RemoteException e) {
@@ -14203,7 +15434,25 @@
         if (mAlwaysFinishActivities) {
             // Need to do this on its own message because the stack may not
             // be in a consistent state at this point.
-            mMainStack.scheduleDestroyActivities(null, false, "always-finish");
+            mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");
+        }
+
+        if (allChanged) {
+            requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
+        }
+
+        if (mProcessStats.shouldWriteNowLocked(now)) {
+            mHandler.post(new Runnable() {
+                @Override public void run() {
+                    synchronized (ActivityManagerService.this) {
+                        mProcessStats.writeStateAsyncLocked();
+                    }
+                }
+            });
+        }
+
+        if (DEBUG_OOM_ADJ) {
+            Slog.d(TAG, "Did OOM ADJ in " + (SystemClock.uptimeMillis()-now) + "ms");
         }
     }
 
@@ -14225,6 +15474,7 @@
                     if (app.pid > 0 && app.pid != MY_PID) {
                         EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
                                 app.processName, app.setAdj, "empty");
+                        app.killedByAm = true;
                         Process.killProcessQuiet(app.pid);
                     } else {
                         try {
@@ -14378,7 +15628,7 @@
         }
 
         if (proc == null) {
-            HashMap<String, SparseArray<ProcessRecord>> all
+            ArrayMap<String, SparseArray<ProcessRecord>> all
                     = mProcessNames.getMap();
             SparseArray<ProcessRecord> procs = all.get(process);
             if (procs != null && procs.size() > 0) {
@@ -14503,7 +15753,6 @@
                 }
 
                 mCurrentUserId = userId;
-                mCurrentUserArray = new int[] { userId };
                 final Integer userIdInt = Integer.valueOf(userId);
                 mUserLru.remove(userIdInt);
                 mUserLru.add(userIdInt);
@@ -14569,7 +15818,7 @@
                     }
                 }
 
-                boolean haveActivities = mMainStack.switchUserLocked(userId, uss);
+                boolean haveActivities = mStackSupervisor.switchUserLocked(userId, uss);
                 if (!haveActivities) {
                     startHomeActivityLocked(userId);
                 }
@@ -14730,10 +15979,11 @@
                 final int userId = uss.mHandle.getIdentifier();
                 Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null,
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
-                        false, false, MY_PID, Process.SYSTEM_UID, userId);
+                        true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
             int num = mUserLru.size();
             int i = 0;
@@ -14825,6 +16075,7 @@
                 final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
                 stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                 stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
                 final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
                 // This is the result receiver for the final shutdown broadcast.
                 final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
@@ -14884,7 +16135,7 @@
 
                 // Clean up all state and processes associated with the user.
                 // Kill all the processes for the user.
-                forceStopUserLocked(userId);
+                forceStopUserLocked(userId, "finish user");
             }
         }
 
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index aa82be3..2c0b83b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -16,12 +16,14 @@
 
 package com.android.server.am;
 
+import android.os.Trace;
+import com.android.internal.R.styleable;
 import com.android.internal.app.ResolverActivity;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
 
-import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -54,8 +56,11 @@
  * An entry in the history stack, representing an activity.
  */
 final class ActivityRecord {
+    static final String TAG = ActivityManagerService.TAG;
+    static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
+    final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
+
     final ActivityManagerService service; // owner
-    final ActivityStack stack; // owner
     final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
     final int launchedFromUid; // always the uid who started the activity.
@@ -69,22 +74,29 @@
     final String processName; // process where this component wants to run
     final String taskAffinity; // as per ActivityInfo.taskAffinity
     final boolean stateNotNeeded; // As per ActivityInfo.flags
-    final boolean fullscreen; // covers the full screen?
+    boolean fullscreen; // covers the full screen?
     final boolean noDisplay;  // activity is not displayed?
     final boolean componentSpecified;  // did caller specifiy an explicit component?
-    final boolean isHomeActivity; // do we consider this to be a home activity?
+
+    static final int APPLICATION_ACTIVITY_TYPE = 0;
+    static final int HOME_ACTIVITY_TYPE = 1;
+    static final int RECENTS_ACTIVITY_TYPE = 2;
+    int mActivityType;
+
     final String baseDir;   // where activity source (resources etc) located
     final String resDir;   // where public activity source (public resources etc) located
     final String dataDir;   // where activity data should go
     CharSequence nonLocalizedLabel;  // the label information from the package mgr.
     int labelRes;           // the label information from the package mgr.
     int icon;               // resource identifier of activity's icon.
+    int logo;               // resource identifier of activity's logo.
     int theme;              // resource identifier of activity's theme.
     int realTheme;          // actual theme resource we will use, never 0.
     int windowFlags;        // custom window flags for preview window.
     TaskRecord task;        // the task this is in.
     ThumbnailHolder thumbHolder; // where our thumbnails should go.
-    long launchTime;        // when we starting launching this activity
+    long displayStartTime;  // when we started launching this activity
+    long fullyDrawnStartTime; // when we started launching this activity
     long startTime;         // last time this activity was started
     long lastVisibleTime;   // last time this activity became visible
     long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
@@ -95,9 +107,9 @@
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
     final int requestCode;  // code given by requester (resultTo)
-    ArrayList results;      // pending ActivityResult objs we have received
+    ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
-    ArrayList newIntents;   // any pending new intents for single-top mode
+    ArrayList<Intent> newIntents; // any pending new intents for single-top mode
     ActivityOptions pendingOptions; // most recently given options
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
@@ -128,15 +140,16 @@
     long lastLaunchTime;    // time of last lauch of this activity
 
     String stringName;      // for caching of toString().
-    
+
     private boolean inHistory;  // are we in the history stack?
+    final ActivityStackSupervisor mStackSupervisor;
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
                 pw.print(" processName="); pw.println(processName);
         pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
-                pw.print(" launchedFromPackage="); pw.println(launchedFromPackage);
+                pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
                 pw.print(" userId="); pw.println(userId);
         pw.print(prefix); pw.print("app="); pw.println(app);
         pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
@@ -152,7 +165,7 @@
         pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
         pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
                 pw.print(" componentSpecified="); pw.print(componentSpecified);
-                pw.print(" isHomeActivity="); pw.println(isHomeActivity);
+                pw.print(" mActivityType="); pw.println(mActivityType);
         pw.print(prefix); pw.print("compat="); pw.print(compat);
                 pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
                 pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
@@ -182,7 +195,7 @@
         if (newIntents != null && newIntents.size() > 0) {
             pw.print(prefix); pw.println("Pending New Intents:");
             for (int i=0; i<newIntents.size(); i++) {
-                Intent intent = (Intent)newIntents.get(i);
+                Intent intent = newIntents.get(i);
                 pw.print(prefix); pw.print("  - ");
                 if (intent == null) {
                     pw.println("null");
@@ -210,7 +223,7 @@
                 if (lastLaunchTime == 0) pw.print("0");
                 else TimeUtils.formatDuration(lastLaunchTime, now, pw);
                 pw.println();
-        pw.print(prefix); pw.print(" haveState="); pw.print(haveState);
+        pw.print(prefix); pw.print("haveState="); pw.print(haveState);
                 pw.print(" icicle="); pw.println(icicle);
         pw.print(prefix); pw.print("state="); pw.print(state);
                 pw.print(" stopped="); pw.print(stopped);
@@ -228,6 +241,8 @@
         pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
                 pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
                 pw.print(" forceNewConfig="); pw.println(forceNewConfig);
+        pw.print(prefix); pw.print("mActivityType=");
+                pw.println(activityTypeToString(mActivityType));
         pw.print(prefix); pw.print("thumbHolder: ");
                 pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
                 if (thumbHolder != null) {
@@ -235,10 +250,10 @@
                     pw.print(" desc="); pw.print(thumbHolder.lastDescription);
                 }
                 pw.println();
-        if (launchTime != 0 || startTime != 0) {
-            pw.print(prefix); pw.print("launchTime=");
-                    if (launchTime == 0) pw.print("0");
-                    else TimeUtils.formatDuration(launchTime, now, pw);
+        if (displayStartTime != 0 || startTime != 0) {
+            pw.print(prefix); pw.print("displayStartTime=");
+                    if (displayStartTime == 0) pw.print("0");
+                    else TimeUtils.formatDuration(displayStartTime, now, pw);
                     pw.print(" startTime=");
                     if (startTime == 0) pw.print("0");
                     else TimeUtils.formatDuration(startTime, now, pw);
@@ -269,36 +284,33 @@
             weakActivity = new WeakReference<ActivityRecord>(activity);
         }
 
-        @Override public void windowsDrawn() throws RemoteException {
+        @Override public void windowsDrawn() {
             ActivityRecord activity = weakActivity.get();
             if (activity != null) {
                 activity.windowsDrawn();
             }
         }
 
-        @Override public void windowsVisible() throws RemoteException {
+        @Override public void windowsVisible() {
             ActivityRecord activity = weakActivity.get();
             if (activity != null) {
                 activity.windowsVisible();
             }
         }
 
-        @Override public void windowsGone() throws RemoteException {
+        @Override public void windowsGone() {
             ActivityRecord activity = weakActivity.get();
             if (activity != null) {
                 activity.windowsGone();
             }
         }
 
-        @Override public boolean keyDispatchingTimedOut() throws RemoteException {
+        @Override public boolean keyDispatchingTimedOut(String reason) {
             ActivityRecord activity = weakActivity.get();
-            if (activity != null) {
-                return activity.keyDispatchingTimedOut();
-            }
-            return false;
+            return activity != null && activity.keyDispatchingTimedOut(reason);
         }
 
-        @Override public long getKeyDispatchingTimeout() throws RemoteException {
+        @Override public long getKeyDispatchingTimeout() {
             ActivityRecord activity = weakActivity.get();
             if (activity != null) {
                 return activity.getKeyDispatchingTimeout();
@@ -306,6 +318,7 @@
             return 0;
         }
 
+        @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(128);
             sb.append("Token{");
@@ -326,13 +339,16 @@
         }
     }
 
-    ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
+    boolean isNotResolverActivity() {
+        return !ResolverActivity.class.getName().equals(realActivity.getClassName());
+    }
+
+    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
             ActivityRecord _resultTo, String _resultWho, int _reqCode,
-            boolean _componentSpecified) {
+            boolean _componentSpecified, ActivityStackSupervisor supervisor) {
         service = _service;
-        stack = _stack;
         appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
@@ -361,6 +377,7 @@
         thumbnailNeeded = false;
         idle = false;
         hasBeenLaunched = false;
+        mStackSupervisor = supervisor;
 
         // This starts out true, since the initial state of an activity
         // is that we have everything, and we shouldn't never consider it
@@ -390,6 +407,7 @@
                 labelRes = app.labelRes;
             }
             icon = aInfo.getIconResource();
+            logo = aInfo.getLogoResource();
             theme = aInfo.getThemeResource();
             realTheme = theme;
             if (realTheme == 0) {
@@ -413,10 +431,10 @@
             if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
                 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
             }
-            
+
             packageName = aInfo.applicationInfo.packageName;
             launchMode = aInfo.launchMode;
-            
+
             AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
                     realTheme, com.android.internal.R.styleable.Window, userId);
             fullscreen = ent != null && !ent.array.getBoolean(
@@ -425,29 +443,22 @@
                     com.android.internal.R.styleable.Window_windowIsTranslucent, false);
             noDisplay = ent != null && ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowNoDisplay, false);
-            
-            if (!_componentSpecified || _launchedFromUid == Process.myUid()
-                    || _launchedFromUid == 0) {
-                // If we know the system has determined the component, then
-                // we can consider this to be a home activity...
-                if (Intent.ACTION_MAIN.equals(_intent.getAction()) &&
-                        _intent.hasCategory(Intent.CATEGORY_HOME) &&
-                        _intent.getCategories().size() == 1 &&
-                        _intent.getData() == null &&
-                        _intent.getType() == null &&
-                        (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                        !ResolverActivity.class.getName().equals(realActivity.getClassName())) {
-                    // This sure looks like a home activity!
-                    // Note the last check is so we don't count the resolver
-                    // activity as being home...  really, we don't care about
-                    // doing anything special with something that comes from
-                    // the core framework package.
-                    isHomeActivity = true;
-                } else {
-                    isHomeActivity = false;
-                }
+
+            if ((!_componentSpecified || _launchedFromUid == Process.myUid()
+                    || _launchedFromUid == 0) &&
+                    Intent.ACTION_MAIN.equals(_intent.getAction()) &&
+                    _intent.hasCategory(Intent.CATEGORY_HOME) &&
+                    _intent.getCategories().size() == 1 &&
+                    _intent.getData() == null &&
+                    _intent.getType() == null &&
+                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                    isNotResolverActivity()) {
+                // This sure looks like a home activity!
+                mActivityType = HOME_ACTIVITY_TYPE;
+            } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
+                mActivityType = RECENTS_ACTIVITY_TYPE;
             } else {
-                isHomeActivity = false;
+                mActivityType = APPLICATION_ACTIVITY_TYPE;
             }
 
             immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
@@ -462,12 +473,15 @@
             packageName = null;
             fullscreen = true;
             noDisplay = false;
-            isHomeActivity = false;
+            mActivityType = APPLICATION_ACTIVITY_TYPE;
             immersive = false;
         }
     }
 
     void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
+        if (task != null && task.removeActivity(this)) {
+            mStackSupervisor.removeTask(task);
+        }
         if (inHistory && !finishing) {
             if (task != null) {
                 task.numActivities--;
@@ -490,6 +504,25 @@
         }
     }
 
+    boolean changeWindowTranslucency(boolean toOpaque) {
+        if (fullscreen == toOpaque) {
+            return false;
+        }
+        AttributeCache.Entry ent =
+                AttributeCache.instance().get(packageName, realTheme, styleable.Window, userId);
+        if (ent == null
+                || !ent.array.getBoolean(styleable.Window_windowIsTranslucent, false)
+                || ent.array.getBoolean(styleable.Window_windowIsFloating, false)) {
+            return false;
+        }
+
+        // Keep track of the number of fullscreen activities in this task.
+        task.numFullscreen += toOpaque ? +1 : -1;
+
+        fullscreen = toOpaque;
+        return true;
+    }
+
     void putInHistory() {
         if (!inHistory) {
             inHistory = true;
@@ -504,6 +537,7 @@
             inHistory = false;
             if (task != null && !finishing) {
                 task.numActivities--;
+                task = null;
             }
             clearOptionsLocked();
         }
@@ -513,6 +547,18 @@
         return inHistory;
     }
 
+    boolean isHomeActivity() {
+        return mActivityType == HOME_ACTIVITY_TYPE;
+    }
+
+    boolean isRecentsActivity() {
+        return mActivityType == RECENTS_ACTIVITY_TYPE;
+    }
+
+    boolean isApplicationActivity() {
+        return mActivityType == APPLICATION_ACTIVITY_TYPE;
+    }
+
     void makeFinishing() {
         if (!finishing) {
             finishing = true;
@@ -525,6 +571,11 @@
         }
     }
 
+    boolean isRootActivity() {
+        ArrayList<ActivityRecord> activities = task.mActivities;
+        return activities.size() == 0 || this == task.mActivities.get(0);
+    }
+
     UriPermissionOwner getUriPermissionsLocked() {
         if (uriPermissions == null) {
             uriPermissions = new UriPermissionOwner(service, this);
@@ -538,7 +589,7 @@
         ActivityResult r = new ActivityResult(from, resultWho,
         		requestCode, resultCode, resultData);
         if (results == null) {
-            results = new ArrayList();
+            results = new ArrayList<ResultInfo>();
         }
         results.add(r);
     }
@@ -563,17 +614,16 @@
 
     void addNewIntentLocked(Intent intent) {
         if (newIntents == null) {
-            newIntents = new ArrayList();
+            newIntents = new ArrayList<Intent>();
         }
         newIntents.add(intent);
     }
-    
+
     /**
      * Deliver a new Intent to an existing activity, so that its onNewIntent()
      * method will be called at the proper time.
      */
     final void deliverNewIntentLocked(int callingUid, Intent intent) {
-        boolean sent = false;
         // The activity now gets access to the data associated with this Intent.
         service.grantUriPermissionFromIntentLocked(callingUid, packageName,
                 intent, getUriPermissionsLocked());
@@ -582,15 +632,16 @@
         // device is sleeping, then all activities are stopped, so in that
         // case we will deliver it if this is the current top activity on its
         // stack.
+        boolean unsent = true;
         if ((state == ActivityState.RESUMED || (service.mSleeping
-                        && stack.topRunningActivityLocked(null) == this))
+                        && task.stack.topRunningActivityLocked(null) == this))
                 && app != null && app.thread != null) {
             try {
                 ArrayList<Intent> ar = new ArrayList<Intent>();
                 intent = new Intent(intent);
                 ar.add(intent);
                 app.thread.scheduleNewIntent(ar, appToken);
-                sent = true;
+                unsent = false;
             } catch (RemoteException e) {
                 Slog.w(ActivityManagerService.TAG,
                         "Exception thrown sending new intent to " + this, e);
@@ -599,7 +650,7 @@
                         "Exception thrown sending new intent to " + this, e);
             }
         }
-        if (!sent) {
+        if (unsent) {
             addNewIntentLocked(new Intent(intent));
         }
     }
@@ -701,9 +752,6 @@
     }
 
     void updateThumbnail(Bitmap newThumbnail, CharSequence description) {
-        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-            // This is a logical break in the task; it repre
-        }
         if (thumbHolder != null) {
             if (newThumbnail != null) {
                 if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
@@ -727,8 +775,8 @@
 
     boolean continueLaunchTickingLocked() {
         if (launchTickTime != 0) {
-            Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG);
-            msg.obj = this;
+            final ActivityStack stack = task.stack;
+            Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
             stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
             stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
             return true;
@@ -738,7 +786,7 @@
 
     void finishLaunchTickingLocked() {
         launchTickTime = 0;
-        stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
+        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
     }
 
     // IApplicationToken
@@ -750,50 +798,91 @@
         // so it is best to leave as-is.
         return app != null && !app.crashing && !app.notResponding;
     }
-    
+
     public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
             service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
         }
     }
-    
+
     public void stopFreezingScreenLocked(boolean force) {
         if (force || frozenBeforeDestroy) {
             frozenBeforeDestroy = false;
             service.mWindowManager.stopAppFreezingScreen(appToken, force);
         }
     }
-    
+
+    public void reportFullyDrawnLocked() {
+        final long curTime = SystemClock.uptimeMillis();
+        if (displayStartTime != 0) {
+            reportLaunchTimeLocked(curTime);
+        }
+        if (fullyDrawnStartTime != 0) {
+            final ActivityStack stack = task.stack;
+            final long thisTime = curTime - fullyDrawnStartTime;
+            final long totalTime = stack.mFullyDrawnStartTime != 0
+                    ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
+            if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
+                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
+                EventLog.writeEvent(EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME,
+                        userId, System.identityHashCode(this), shortComponentName,
+                        thisTime, totalTime);
+                StringBuilder sb = service.mStringBuilder;
+                sb.setLength(0);
+                sb.append("Fully drawn ");
+                sb.append(shortComponentName);
+                sb.append(": ");
+                TimeUtils.formatDuration(thisTime, sb);
+                if (thisTime != totalTime) {
+                    sb.append(" (total ");
+                    TimeUtils.formatDuration(totalTime, sb);
+                    sb.append(")");
+                }
+                Log.i(ActivityManagerService.TAG, sb.toString());
+            }
+            if (totalTime > 0) {
+                service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
+            }
+            fullyDrawnStartTime = 0;
+            stack.mFullyDrawnStartTime = 0;
+        }
+    }
+
+    private void reportLaunchTimeLocked(final long curTime) {
+        final ActivityStack stack = task.stack;
+        final long thisTime = curTime - displayStartTime;
+        final long totalTime = stack.mLaunchStartTime != 0
+                ? (curTime - stack.mLaunchStartTime) : thisTime;
+        if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
+            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
+            EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
+                    userId, System.identityHashCode(this), shortComponentName,
+                    thisTime, totalTime);
+            StringBuilder sb = service.mStringBuilder;
+            sb.setLength(0);
+            sb.append("Displayed ");
+            sb.append(shortComponentName);
+            sb.append(": ");
+            TimeUtils.formatDuration(thisTime, sb);
+            if (thisTime != totalTime) {
+                sb.append(" (total ");
+                TimeUtils.formatDuration(totalTime, sb);
+                sb.append(")");
+            }
+            Log.i(ActivityManagerService.TAG, sb.toString());
+        }
+        mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
+        if (totalTime > 0) {
+            service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
+        }
+        displayStartTime = 0;
+        stack.mLaunchStartTime = 0;
+    }
+
     public void windowsDrawn() {
         synchronized(service) {
-            if (launchTime != 0) {
-                final long curTime = SystemClock.uptimeMillis();
-                final long thisTime = curTime - launchTime;
-                final long totalTime = stack.mInitialStartTime != 0
-                        ? (curTime - stack.mInitialStartTime) : thisTime;
-                if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
-                    EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
-                            userId, System.identityHashCode(this), shortComponentName,
-                            thisTime, totalTime);
-                    StringBuilder sb = service.mStringBuilder;
-                    sb.setLength(0);
-                    sb.append("Displayed ");
-                    sb.append(shortComponentName);
-                    sb.append(": ");
-                    TimeUtils.formatDuration(thisTime, sb);
-                    if (thisTime != totalTime) {
-                        sb.append(" (total ");
-                        TimeUtils.formatDuration(totalTime, sb);
-                        sb.append(")");
-                    }
-                    Log.i(ActivityManagerService.TAG, sb.toString());
-                }
-                stack.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
-                if (totalTime > 0) {
-                    service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
-                }
-                launchTime = 0;
-                stack.mInitialStartTime = 0;
+            if (displayStartTime != 0) {
+                reportLaunchTimeLocked(SystemClock.uptimeMillis());
             }
             startTime = 0;
             finishLaunchTickingLocked();
@@ -802,7 +891,7 @@
 
     public void windowsVisible() {
         synchronized(service) {
-            stack.reportActivityVisibleLocked(this);
+            mStackSupervisor.reportActivityVisibleLocked(this);
             if (ActivityManagerService.DEBUG_SWITCH) Log.v(
                     ActivityManagerService.TAG, "windowsVisible(): " + this);
             if (!nowVisible) {
@@ -812,27 +901,24 @@
                     // Instead of doing the full stop routine here, let's just
                     // hide any activities we now can, and let them stop when
                     // the normal idle happens.
-                    stack.processStoppingActivitiesLocked(false);
+                    mStackSupervisor.processStoppingActivitiesLocked(false);
                 } else {
                     // If this activity was already idle, then we now need to
                     // make sure we perform the full stop of any activities
                     // that are waiting to do so.  This is because we won't
                     // do that while they are still waiting for this one to
                     // become visible.
-                    final int N = stack.mWaitingVisibleActivities.size();
+                    final int N = mStackSupervisor.mWaitingVisibleActivities.size();
                     if (N > 0) {
                         for (int i=0; i<N; i++) {
-                            ActivityRecord r = (ActivityRecord)
-                                stack.mWaitingVisibleActivities.get(i);
+                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
                             r.waitingVisible = false;
                             if (ActivityManagerService.DEBUG_SWITCH) Log.v(
                                     ActivityManagerService.TAG,
                                     "Was waiting for visible: " + r);
                         }
-                        stack.mWaitingVisibleActivities.clear();
-                        Message msg = Message.obtain();
-                        msg.what = ActivityStack.IDLE_NOW_MSG;
-                        stack.mHandler.sendMessage(msg);
+                        mStackSupervisor.mWaitingVisibleActivities.clear();
+                        mStackSupervisor.scheduleIdleLocked();
                     }
                 }
                 service.scheduleAppGcsLocked();
@@ -845,12 +931,13 @@
                 ActivityManagerService.TAG, "windowsGone(): " + this);
         nowVisible = false;
     }
-    
+
     private ActivityRecord getWaitingHistoryRecordLocked() {
         // First find the real culprit...  if we are waiting
         // for another app to start, then we have paused dispatching
         // for this activity.
         ActivityRecord r = this;
+        final ActivityStack stack = task.stack;
         if (r.waitingVisible) {
             // Hmmm, who might we be waiting for?
             r = stack.mResumedActivity;
@@ -862,20 +949,20 @@
                 r = this;
             }
         }
-        
+
         return r;
     }
 
-    public boolean keyDispatchingTimedOut() {
+    public boolean keyDispatchingTimedOut(String reason) {
         ActivityRecord r;
         ProcessRecord anrApp;
         synchronized(service) {
             r = getWaitingHistoryRecordLocked();
             anrApp = r != null ? r.app : null;
         }
-        return service.inputDispatchingTimedOut(anrApp, r, this, false);
+        return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
     }
-    
+
     /** Returns the key dispatching timeout for this application token. */
     public long getKeyDispatchingTimeout() {
         synchronized(service) {
@@ -889,7 +976,7 @@
      * currently pausing, or is resumed.
      */
     public boolean isInterestingToUserLocked() {
-        return visible || nowVisible || state == ActivityState.PAUSING || 
+        return visible || nowVisible || state == ActivityState.PAUSING ||
                 state == ActivityState.RESUMED;
     }
 
@@ -900,20 +987,66 @@
         if (app != null && app.thread != null) {
             try {
                 app.thread.scheduleSleeping(appToken, _sleeping);
-                if (sleeping && !stack.mGoingToSleepActivities.contains(this)) {
-                    stack.mGoingToSleepActivities.add(this);
+                if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
+                    mStackSupervisor.mGoingToSleepActivities.add(this);
                 }
                 sleeping = _sleeping;
             } catch (RemoteException e) {
-                Slog.w(ActivityStack.TAG, "Exception thrown when sleeping: "
-                        + intent.getComponent(), e);
+                Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e);
             }
         }
     }
-    
+
+    static void activityResumedLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
+        r.icicle = null;
+        r.haveState = false;
+    }
+
+    static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r == null) {
+            return -1;
+        }
+        final TaskRecord task = r.task;
+        switch (task.mActivities.indexOf(r)) {
+            case -1: return -1;
+            case 0: return task.taskId;
+            default: return onlyRoot ? -1 : task.taskId;
+        }
+    }
+
+    static ActivityRecord isInStackLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r != null) {
+            return r.task.stack.isInStackLocked(token);
+        }
+        return null;
+    }
+
+    static ActivityStack getStackLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+        if (r != null) {
+            return r.task.stack;
+        }
+        return null;
+    }
+
+    private String activityTypeToString(int type) {
+        switch (type) {
+            case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
+            case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
+            case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
+            default: return Integer.toString(type);
+        }
+    }
+
+    @Override
     public String toString() {
         if (stringName != null) {
-            return stringName;
+            return stringName + " t" + (task == null ? -1 : task.taskId) +
+                    (finishing ? " f}" : "}");
         }
         StringBuilder sb = new StringBuilder(128);
         sb.append("ActivityRecord{");
@@ -922,7 +1055,7 @@
         sb.append(userId);
         sb.append(' ');
         sb.append(intent.getComponent().flattenToShortString());
-        sb.append('}');
-        return stringName = sb.toString();
+        stringName = sb.toString();
+        return toString();
     }
 }
diff --git a/services/java/com/android/server/am/ActivityResult.java b/services/java/com/android/server/am/ActivityResult.java
index 12eba34..6d5bdeb 100644
--- a/services/java/com/android/server/am/ActivityResult.java
+++ b/services/java/com/android/server/am/ActivityResult.java
@@ -23,7 +23,7 @@
 /**
  * Pending result information to send back to an activity.
  */
-class ActivityResult extends ResultInfo {
+final class ActivityResult extends ResultInfo {
     final ActivityRecord mFrom;
     
     public ActivityResult(ActivityRecord from, String resultWho,
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c344023..28c87d1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -16,33 +16,48 @@
 
 package com.android.server.am;
 
-import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.ActivityManagerService.localLOGV;
+import static com.android.server.am.ActivityManagerService.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
+import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerService.DEBUG_TRANSITION;
+import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
+import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
+import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS;
 
-import com.android.internal.app.HeavyWeightSwitcherActivity;
+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_SAVED_STATE;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+
+import android.os.Trace;
 import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
+import com.android.internal.util.Objects;
+import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.wm.AppTransition;
+import com.android.server.wm.TaskGroup;
+import com.android.server.wm.WindowManagerService;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
-import android.app.IActivityManager;
-import android.app.IThumbnailRetriever;
-import android.app.IApplicationThread;
-import android.app.PendingIntent;
+import android.app.IActivityController;
+import android.app.IThumbnailReceiver;
 import android.app.ResultInfo;
-import android.app.IActivityManager.WaitResult;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.IIntentSender;
 import android.content.Intent;
-import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -54,17 +69,15 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 
-import java.io.IOException;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -74,28 +87,6 @@
  * State and management of a single stack of activities.
  */
 final class ActivityStack {
-    static final String TAG = ActivityManagerService.TAG;
-    static final boolean localLOGV = ActivityManagerService.localLOGV;
-    static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
-    static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE;
-    static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY;
-    static final boolean DEBUG_USER_LEAVING = ActivityManagerService.DEBUG_USER_LEAVING;
-    static final boolean DEBUG_TRANSITION = ActivityManagerService.DEBUG_TRANSITION;
-    static final boolean DEBUG_RESULTS = ActivityManagerService.DEBUG_RESULTS;
-    static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
-    static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
-    static final boolean DEBUG_CLEANUP = ActivityManagerService.DEBUG_CLEANUP;
-    
-    static final boolean DEBUG_STATES = false;
-    static final boolean DEBUG_ADD_REMOVE = false;
-    static final boolean DEBUG_SAVED_STATE = false;
-    static final boolean DEBUG_APP = false;
-
-    static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
-    
-    // How long we wait until giving up on the last activity telling us it
-    // is idle.
-    static final int IDLE_TIMEOUT = 10*1000;
 
     // Ticks during which we check progress while waiting for an app to launch.
     static final int LAUNCH_TICK = 500;
@@ -110,28 +101,26 @@
     // from the application in order to get its saved state.
     static final int STOP_TIMEOUT = 10*1000;
 
-    // How long we can hold the sleep wake lock before giving up.
-    static final int SLEEP_TIMEOUT = 5*1000;
-
-    // How long we can hold the launch wake lock before giving up.
-    static final int LAUNCH_TIMEOUT = 10*1000;
-
     // How long we wait until giving up on an activity telling us it has
     // finished destroying itself.
     static final int DESTROY_TIMEOUT = 10*1000;
-    
+
     // How long until we reset a task when the user returns to it.  Currently
     // disabled.
     static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
-    
+
     // How long between activity launches that we consider safe to not warn
     // the user about an unexpected activity being launched on top.
     static final long START_WARN_TIME = 5*1000;
-    
+
     // Set to false to disable the preview that is shown while a new activity
     // is being started.
     static final boolean SHOW_APP_STARTING_PREVIEW = true;
-    
+
+    // How long to wait for all background Activities to redraw following a call to
+    // convertToTranslucent().
+    static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
+
     enum ActivityState {
         INITIALIZING,
         RESUMED,
@@ -145,20 +134,20 @@
     }
 
     final ActivityManagerService mService;
-    final boolean mMainStack;
-    
+    final WindowManagerService mWindowManager;
+
     final Context mContext;
-    
+
     /**
      * The back history of all previous (and possibly still
-     * running) activities.  It contains HistoryRecord objects.
+     * running) activities.  It contains #TaskRecord objects.
      */
-    final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
+    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
 
     /**
      * Used for validating app tokens with window manager.
      */
-    final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>();
+    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
 
     /**
      * List of running activities, sorted by recent usage.
@@ -168,71 +157,10 @@
     final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
 
     /**
-     * List of activities that are waiting for a new activity
-     * to become visible before completing whatever operation they are
-     * supposed to do.
-     */
-    final ArrayList<ActivityRecord> mWaitingVisibleActivities
-            = new ArrayList<ActivityRecord>();
-
-    /**
-     * List of activities that are ready to be stopped, but waiting
-     * for the next activity to settle down before doing so.  It contains
-     * HistoryRecord objects.
-     */
-    final ArrayList<ActivityRecord> mStoppingActivities
-            = new ArrayList<ActivityRecord>();
-
-    /**
-     * List of activities that are in the process of going to sleep.
-     */
-    final ArrayList<ActivityRecord> mGoingToSleepActivities
-            = new ArrayList<ActivityRecord>();
-
-    /**
      * Animations that for the current transition have requested not to
      * be considered for the transition animation.
      */
-    final ArrayList<ActivityRecord> mNoAnimActivities
-            = new ArrayList<ActivityRecord>();
-
-    /**
-     * List of activities that are ready to be finished, but waiting
-     * for the previous activity to settle down before doing so.  It contains
-     * HistoryRecord objects.
-     */
-    final ArrayList<ActivityRecord> mFinishingActivities
-            = new ArrayList<ActivityRecord>();
-    
-    /**
-     * List of people waiting to find out about the next launched activity.
-     */
-    final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
-            = new ArrayList<IActivityManager.WaitResult>();
-    
-    /**
-     * List of people waiting to find out about the next visible activity.
-     */
-    final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
-            = new ArrayList<IActivityManager.WaitResult>();
-
-    final ArrayList<UserStartedState> mStartingUsers
-            = new ArrayList<UserStartedState>();
-
-    /**
-     * Set when the system is going to sleep, until we have
-     * successfully paused the current activity and released our wake lock.
-     * At that point the system is allowed to actually sleep.
-     */
-    final PowerManager.WakeLock mGoingToSleep;
-
-    /**
-     * We don't want to allow the device to go to sleep while in the process
-     * of launching an activity.  This is primarily to allow alarm intent
-     * receivers to launch an activity and get that to run before the device
-     * goes back to sleep.
-     */
-    final PowerManager.WakeLock mLaunchingActivity;
+    final ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<ActivityRecord>();
 
     /**
      * When we are in the process of pausing an activity, before starting the
@@ -248,40 +176,42 @@
     ActivityRecord mLastPausedActivity = null;
 
     /**
+     * Activities that specify No History must be removed once the user navigates away from them.
+     * If the device goes to sleep with such an activity in the paused state then we save it here
+     * and finish it later if another activity replaces it on wakeup.
+     */
+    ActivityRecord mLastNoHistoryActivity = null;
+
+    /**
      * Current activity that is resumed, or null if there is none.
      */
     ActivityRecord mResumedActivity = null;
-    
+
     /**
      * This is the last activity that has been started.  It is only used to
      * identify when multiple activities are started at once so that the user
      * can be warned they may not be in the activity they think they are.
      */
     ActivityRecord mLastStartedActivity = null;
-    
+
+    // The topmost Activity passed to convertToTranslucent(). When non-null it means we are
+    // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they
+    // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the
+    // Activity in mTranslucentActivityWaiting is notified via
+    // Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last
+    // background activity being drawn then the same call will be made with a true value.
+    ActivityRecord mTranslucentActivityWaiting = null;
+    ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent =
+            new ArrayList<ActivityRecord>();
+
     /**
      * Set when we know we are going to be calling updateConfiguration()
      * soon, so want to skip intermediate config checks.
      */
     boolean mConfigWillChange;
 
-    /**
-     * Set to indicate whether to issue an onUserLeaving callback when a
-     * newly launched activity is being brought in front of us.
-     */
-    boolean mUserLeaving = false;
-    
-    long mInitialStartTime = 0;
-    
-    /**
-     * Set when we have taken too long waiting to go to sleep.
-     */
-    boolean mSleepTimeout = false;
-
-    /**
-     * Dismiss the keyguard after the next activity is displayed?
-     */
-    boolean mDismissKeyguardOnNextActivity = false;
+    long mLaunchStartTime = 0;
+    long mFullyDrawnStartTime = 0;
 
     /**
      * Save the most recent screenshot for reuse. This keeps Recents from taking two identical
@@ -293,18 +223,19 @@
     int mThumbnailWidth = -1;
     int mThumbnailHeight = -1;
 
-    private int mCurrentUser;
+    int mCurrentUser;
 
-    static final int SLEEP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG;
+    final int mStackId;
+
+    /** Run all ActivityStacks through this */
+    final ActivityStackSupervisor mStackSupervisor;
+
     static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
-    static final int IDLE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
-    static final int IDLE_NOW_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
-    static final int LAUNCH_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
-    static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
-    static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
-    static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
-    static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 8;
-    static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 9;
+    static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
+    static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
+    static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
+    static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
+    static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
 
     static class ScheduleDestroyArgs {
         final ProcessRecord mOwner;
@@ -323,22 +254,13 @@
         //public Handler() {
         //    if (localLOGV) Slog.v(TAG, "Handler started!");
         //}
-        public ActivityStackHandler(Looper looper) {
+        ActivityStackHandler(Looper looper) {
             super(looper);
         }
 
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case SLEEP_TIMEOUT_MSG: {
-                    synchronized (mService) {
-                        if (mService.isSleeping()) {
-                            Slog.w(TAG, "Sleep timeout!  Sleeping now.");
-                            mSleepTimeout = true;
-                            checkReadyForSleepLocked();
-                        }
-                    }
-                } break;
                 case PAUSE_TIMEOUT_MSG: {
                     ActivityRecord r = (ActivityRecord)msg.obj;
                     // We don't at this point know if the activity is fullscreen,
@@ -346,33 +268,16 @@
                     Slog.w(TAG, "Activity pause timeout for " + r);
                     synchronized (mService) {
                         if (r.app != null) {
-                            mService.logAppTooSlow(r.app, r.pauseTime,
-                                    "pausing " + r);
+                            mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
                         }
+                        activityPausedLocked(r.appToken, true);
                     }
-
-                    activityPaused(r != null ? r.appToken : null, true);
-                } break;
-                case IDLE_TIMEOUT_MSG: {
-                    if (mService.mDidDexOpt) {
-                        mService.mDidDexOpt = false;
-                        Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
-                        nmsg.obj = msg.obj;
-                        mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
-                        return;
-                    }
-                    // We don't at this point know if the activity is fullscreen,
-                    // so we need to be conservative and assume it isn't.
-                    ActivityRecord r = (ActivityRecord)msg.obj;
-                    Slog.w(TAG, "Activity idle timeout for " + r);
-                    activityIdleInternal(r != null ? r.appToken : null, true, null);
                 } break;
                 case LAUNCH_TICK_MSG: {
                     ActivityRecord r = (ActivityRecord)msg.obj;
                     synchronized (mService) {
                         if (r.continueLaunchTickingLocked()) {
-                            mService.logAppTooSlow(r.app, r.launchTickTime,
-                                    "launching " + r);
+                            mService.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
                         }
                     }
                 } break;
@@ -381,29 +286,8 @@
                     // We don't at this point know if the activity is fullscreen,
                     // so we need to be conservative and assume it isn't.
                     Slog.w(TAG, "Activity destroy timeout for " + r);
-                    activityDestroyed(r != null ? r.appToken : null);
-                } break;
-                case IDLE_NOW_MSG: {
-                    ActivityRecord r = (ActivityRecord)msg.obj;
-                    activityIdleInternal(r != null ? r.appToken : null, false, null);
-                } break;
-                case LAUNCH_TIMEOUT_MSG: {
-                    if (mService.mDidDexOpt) {
-                        mService.mDidDexOpt = false;
-                        Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
-                        mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
-                        return;
-                    }
                     synchronized (mService) {
-                        if (mLaunchingActivity.isHeld()) {
-                            Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
-                            mLaunchingActivity.release();
-                        }
-                    }
-                } break;
-                case RESUME_TOP_ACTIVITY_MSG: {
-                    synchronized (mService) {
-                        resumeTopActivityLocked(null);
+                        activityDestroyedLocked(r != null ? r.appToken : null);
                     }
                 } break;
                 case STOP_TIMEOUT_MSG: {
@@ -422,48 +306,59 @@
                     synchronized (mService) {
                         destroyActivitiesLocked(args.mOwner, args.mOomAdj, args.mReason);
                     }
-                }
+                } break;
+                case TRANSLUCENT_TIMEOUT_MSG: {
+                    synchronized (mService) {
+                        notifyActivityDrawnLocked(null);
+                    }
+                } break;
             }
         }
     }
 
-    ActivityStack(ActivityManagerService service, Context context, boolean mainStack, Looper looper) {
-        mHandler = new ActivityStackHandler(looper);
-        mService = service;
-        mContext = context;
-        mMainStack = mainStack;
-        PowerManager pm =
-            (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
-        mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
-        mLaunchingActivity.setReferenceCounted(false);
+    private int numActivities() {
+        int count = 0;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            count += mTaskHistory.get(taskNdx).mActivities.size();
+        }
+        return count;
     }
 
-    private boolean okToShow(ActivityRecord r) {
+    ActivityStack(ActivityManagerService service, Context context, Looper looper, int stackId) {
+        mHandler = new ActivityStackHandler(looper);
+        mService = service;
+        mWindowManager = service.mWindowManager;
+        mStackSupervisor = service.mStackSupervisor;
+        mContext = context;
+        mStackId = stackId;
+        mCurrentUser = service.mCurrentUserId;
+    }
+
+    boolean okToShow(ActivityRecord r) {
         return r.userId == mCurrentUser
                 || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
     }
 
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
-        int i = mHistory.size()-1;
-        while (i >= 0) {
-            ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && r != notTop && okToShow(r)) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            ActivityRecord r = mTaskHistory.get(taskNdx).topRunningActivityLocked(notTop);
+            if (r != null) {
                 return r;
             }
-            i--;
         }
         return null;
     }
 
     final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
-        int i = mHistory.size()-1;
-        while (i >= 0) {
-            ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
-                return r;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = activities.get(activityNdx);
+                if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
+                    return r;
+                }
             }
-            i--;
         }
         return null;
     }
@@ -471,88 +366,146 @@
     /**
      * This is a simplified version of topRunningActivityLocked that provides a number of
      * optional skip-over modes.  It is intended for use with the ActivityController hook only.
-     * 
+     *
      * @param token If non-null, any history records matching this token will be skipped.
      * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
-     * 
+     *
      * @return Returns the HistoryRecord of the next activity on the stack.
      */
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
-        int i = mHistory.size()-1;
-        while (i >= 0) {
-            ActivityRecord r = mHistory.get(i);
-            // Note: the taskId check depends on real taskId fields being non-zero
-            if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
-                    && okToShow(r)) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.taskId == taskId) {
+                continue;
+            }
+            ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int i = activities.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = activities.get(i);
+                // Note: the taskId check depends on real taskId fields being non-zero
+                if (!r.finishing && (token != r.appToken) && okToShow(r)) {
+                    return r;
+                }
+            }
+        }
+        return null;
+    }
+
+    final ActivityRecord topActivity() {
+        // Iterate to find the first non-empty task stack. Note that this code can
+        // be simplified once we stop storing tasks with empty mActivities lists.
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                return activities.get(activityNdx);
+            }
+        }
+        return null;
+    }
+
+    final TaskRecord topTask() {
+        final int size = mTaskHistory.size();
+        if (size > 0) {
+            return mTaskHistory.get(size - 1);
+        }
+        return null;
+    }
+
+    TaskRecord taskForIdLocked(int id) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.taskId == id) {
+                return task;
+            }
+        }
+        return null;
+    }
+
+    ActivityRecord isInStackLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r != null) {
+            final TaskRecord task = r.task;
+            if (task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+                if (task.stack != this) Slog.w(TAG,
+                    "Illegal state! task does not point to stack it is in.");
                 return r;
             }
-            i--;
         }
         return null;
     }
 
-    final int indexOfTokenLocked(IBinder token) {
-        return mHistory.indexOf(ActivityRecord.forToken(token));
-    }
-
-    final int indexOfActivityLocked(ActivityRecord r) {
-        return mHistory.indexOf(r);
-    }
-
-    final ActivityRecord isInStackLocked(IBinder token) {
-        ActivityRecord r = ActivityRecord.forToken(token);
-        if (mHistory.contains(r)) {
-            return r;
+    boolean containsApp(ProcessRecord app) {
+        if (app == null) {
+            return false;
         }
-        return null;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.finishing) {
+                    continue;
+                }
+                if (r.app == app) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
-    private final boolean updateLRUListLocked(ActivityRecord r) {
+    final boolean updateLRUListLocked(ActivityRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
         return hadit;
     }
 
+    final boolean isHomeStack() {
+        return mStackId == HOME_STACK_ID;
+    }
+
     /**
      * Returns the top activity in any existing task matching the given
      * Intent.  Returns null if no such task is found.
      */
-    private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
+    ActivityRecord findTaskLocked(ActivityRecord target) {
+        Intent intent = target.intent;
+        ActivityInfo info = target.info;
         ComponentName cls = intent.getComponent();
         if (info.targetActivity != null) {
             cls = new ComponentName(info.packageName, info.targetActivity);
         }
-
-        TaskRecord cp = null;
-
         final int userId = UserHandle.getUserId(info.applicationInfo.uid);
-        final int N = mHistory.size();
-        for (int i=(N-1); i>=0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && r.task != cp && r.userId == userId
-                    && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                cp = r.task;
-                //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
-                //        + "/aff=" + r.task.affinity + " to new cls="
-                //        + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
-                if (r.task.affinity != null) {
-                    if (r.task.affinity.equals(info.taskAffinity)) {
-                        //Slog.i(TAG, "Found matching affinity!");
-                        return r;
-                    }
-                } else if (r.task.intent != null
-                        && r.task.intent.getComponent().equals(cls)) {
-                    //Slog.i(TAG, "Found matching class!");
-                    //dump();
-                    //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
-                    return r;
-                } else if (r.task.affinityIntent != null
-                        && r.task.affinityIntent.getComponent().equals(cls)) {
-                    //Slog.i(TAG, "Found matching class!");
-                    //dump();
-                    //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
+
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.userId != userId) {
+                // Looking for a different task.
+                continue;
+            }
+            final ActivityRecord r = task.getTopActivity();
+            if (r == null || r.finishing || r.userId != userId ||
+                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+                continue;
+            }
+
+            //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
+            //        + "/aff=" + r.task.affinity + " to new cls="
+            //        + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
+            if (task.affinity != null) {
+                if (task.affinity.equals(info.taskAffinity)) {
+                    //Slog.i(TAG, "Found matching affinity!");
                     return r;
                 }
+            } else if (task.intent != null && task.intent.getComponent().equals(cls)) {
+                //Slog.i(TAG, "Found matching class!");
+                //dump();
+                //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
+                return r;
+            } else if (task.affinityIntent != null
+                    && task.affinityIntent.getComponent().equals(cls)) {
+                //Slog.i(TAG, "Found matching class!");
+                //dump();
+                //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
+                return r;
             }
         }
 
@@ -564,18 +517,22 @@
      * is the same as the given activity.  Returns null if no such activity
      * is found.
      */
-    private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
+    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
         ComponentName cls = intent.getComponent();
         if (info.targetActivity != null) {
             cls = new ComponentName(info.packageName, info.targetActivity);
         }
         final int userId = UserHandle.getUserId(info.applicationInfo.uid);
 
-        final int N = mHistory.size();
-        for (int i=(N-1); i>=0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if (!r.finishing) {
-                if (r.intent.getComponent().equals(cls) && r.userId == userId) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.userId != mCurrentUser) {
+                return null;
+            }
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = activities.get(activityNdx);
+                if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) {
                     //Slog.i(TAG, "Found matching class!");
                     //dump();
                     //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
@@ -587,343 +544,129 @@
         return null;
     }
 
-    final void showAskCompatModeDialogLocked(ActivityRecord r) {
-        Message msg = Message.obtain();
-        msg.what = ActivityManagerService.SHOW_COMPAT_MODE_DIALOG_MSG;
-        msg.obj = r.task.askedCompatMode ? null : r;
-        mService.mHandler.sendMessage(msg);
-    }
-
     /*
      * Move the activities around in the stack to bring a user to the foreground.
      * @return whether there are any activities for the specified user.
      */
-    final boolean switchUserLocked(int userId, UserStartedState uss) {
+    final boolean switchUserLocked(int userId) {
+        if (VALIDATE_TOKENS) {
+            validateAppTokensLocked();
+        }
+        if (mCurrentUser == userId) {
+            return true;
+        }
         mCurrentUser = userId;
-        mStartingUsers.add(uss);
 
-        // Only one activity? Nothing to do...
-        if (mHistory.size() < 2)
-            return false;
-
+        // Move userId's tasks to the top.
         boolean haveActivities = false;
-        // Check if the top activity is from the new user.
-        ActivityRecord top = mHistory.get(mHistory.size() - 1);
-        if (top.userId == userId) return true;
-        // Otherwise, move the user's activities to the top.
-        int N = mHistory.size();
-        int i = 0;
-        while (i < N) {
-            ActivityRecord r = mHistory.get(i);
-            if (r.userId == userId) {
-                ActivityRecord moveToTop = mHistory.remove(i);
-                mHistory.add(moveToTop);
-                // No need to check the top one now
-                N--;
+        int index = mTaskHistory.size();
+        for (int i = 0; i < index; ++i) {
+            TaskRecord task = mTaskHistory.get(i);
+            if (task.userId == userId) {
                 haveActivities = true;
-            } else {
-                i++;
+                mTaskHistory.remove(i);
+                mTaskHistory.add(task);
+                --index;
             }
         }
-        // Transition from the old top to the new top
-        resumeTopActivityLocked(top);
+
         return haveActivities;
     }
 
-    final boolean realStartActivityLocked(ActivityRecord r,
-            ProcessRecord app, boolean andResume, boolean checkConfig)
-            throws RemoteException {
+    void minimalResumeActivityLocked(ActivityRecord r) {
+        r.state = ActivityState.RESUMED;
+        if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
+                + " (starting new instance)");
+        r.stopped = false;
+        mResumedActivity = r;
+        r.task.touchActiveTime();
+        mService.addRecentTaskLocked(r.task);
+        completeResumeLocked(r);
+        mStackSupervisor.checkReadyForSleepLocked();
+        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
+    }
 
-        r.startFreezingScreenLocked(app, 0);
-        mService.mWindowManager.setAppVisibility(r.appToken, true);
-
-        // schedule launch ticks to collect information about slow apps.
-        r.startLaunchTickingLocked();
-
-        // Have the window manager re-evaluate the orientation of
-        // the screen based on the new activity order.  Note that
-        // as a result of this, it can call back into the activity
-        // manager with a new orientation.  We don't care about that,
-        // because the activity is not currently running so we are
-        // just restarting it anyway.
-        if (checkConfig) {
-            Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
-                    mService.mConfiguration,
-                    r.mayFreezeScreenLocked(app) ? r.appToken : null);
-            mService.updateConfigurationLocked(config, r, false, false);
+    private void startLaunchTraces() {
+        if (mFullyDrawnStartTime != 0)  {
+            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
         }
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
+    }
 
-        r.app = app;
-        app.waitingToKill = null;
-        r.launchCount++;
-        r.lastLaunchTime = SystemClock.uptimeMillis();
-
-        if (localLOGV) Slog.v(TAG, "Launching: " + r);
-
-        int idx = app.activities.indexOf(r);
-        if (idx < 0) {
-            app.activities.add(r);
+    private void stopFullyDrawnTraceIfNeeded() {
+        if (mFullyDrawnStartTime != 0 && mLaunchStartTime == 0) {
+            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
+            mFullyDrawnStartTime = 0;
         }
-        mService.updateLruProcessLocked(app, true);
+    }
 
-        try {
-            if (app.thread == null) {
-                throw new RemoteException();
+    void setLaunchTime(ActivityRecord r) {
+        if (r.displayStartTime == 0) {
+            r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis();
+            if (mLaunchStartTime == 0) {
+                startLaunchTraces();
+                mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime;
             }
-            List<ResultInfo> results = null;
-            List<Intent> newIntents = null;
-            if (andResume) {
-                results = r.results;
-                newIntents = r.newIntents;
-            }
-            if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
-                    + " icicle=" + r.icicle
-                    + " with results=" + results + " newIntents=" + newIntents
-                    + " andResume=" + andResume);
-            if (andResume) {
-                EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
-                        r.userId, System.identityHashCode(r),
-                        r.task.taskId, r.shortComponentName);
-            }
-            if (r.isHomeActivity) {
-                mService.mHomeProcess = app;
-            }
-            mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
-            r.sleeping = false;
-            r.forceNewConfig = false;
-            showAskCompatModeDialogLocked(r);
-            r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
-            String profileFile = null;
-            ParcelFileDescriptor profileFd = null;
-            boolean profileAutoStop = false;
-            if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
-                if (mService.mProfileProc == null || mService.mProfileProc == app) {
-                    mService.mProfileProc = app;
-                    profileFile = mService.mProfileFile;
-                    profileFd = mService.mProfileFd;
-                    profileAutoStop = mService.mAutoStopProfiler;
-                }
-            }
-            app.hasShownUi = true;
-            app.pendingUiClean = true;
-            if (profileFd != null) {
-                try {
-                    profileFd = profileFd.dup();
-                } catch (IOException e) {
-                    profileFd = null;
-                }
-            }
-            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
-                    System.identityHashCode(r), r.info,
-                    new Configuration(mService.mConfiguration),
-                    r.compat, r.icicle, results, newIntents, !andResume,
-                    mService.isNextTransitionForward(), profileFile, profileFd,
-                    profileAutoStop);
-            
-            if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
-                // This may be a heavy-weight process!  Note that the package
-                // manager will ensure that only activity can run in the main
-                // process of the .apk, which is the only thing that will be
-                // considered heavy-weight.
-                if (app.processName.equals(app.info.packageName)) {
-                    if (mService.mHeavyWeightProcess != null
-                            && mService.mHeavyWeightProcess != app) {
-                        Log.w(TAG, "Starting new heavy weight process " + app
-                                + " when already running "
-                                + mService.mHeavyWeightProcess);
-                    }
-                    mService.mHeavyWeightProcess = app;
-                    Message msg = mService.mHandler.obtainMessage(
-                            ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
-                    msg.obj = r;
-                    mService.mHandler.sendMessage(msg);
-                }
-            }
-            
-        } catch (RemoteException e) {
-            if (r.launchFailed) {
-                // This is the second time we failed -- finish activity
-                // and give up.
-                Slog.e(TAG, "Second failure launching "
-                      + r.intent.getComponent().flattenToShortString()
-                      + ", giving up", e);
-                mService.appDiedLocked(app, app.pid, app.thread);
-                requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                        "2nd-crash", false);
-                return false;
-            }
-
-            // This is the first time we failed -- restart process and
-            // retry.
-            app.activities.remove(r);
-            throw e;
+        } else if (mLaunchStartTime == 0) {
+            startLaunchTraces();
+            mLaunchStartTime = mFullyDrawnStartTime = SystemClock.uptimeMillis();
         }
+    }
 
-        r.launchFailed = false;
-        if (updateLRUListLocked(r)) {
-            Slog.w(TAG, "Activity " + r
-                  + " being launched, but already in LRU list");
-        }
-
-        if (andResume) {
-            // As part of the process of launching, ActivityThread also performs
-            // a resume.
-            r.state = ActivityState.RESUMED;
-            if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
-                    + " (starting new instance)");
-            r.stopped = false;
-            mResumedActivity = r;
-            r.task.touchActiveTime();
-            if (mMainStack) {
-                mService.addRecentTaskLocked(r.task);
-            }
-            completeResumeLocked(r);
-            checkReadyForSleepLocked();
-            if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
+    void clearLaunchTime(ActivityRecord r) {
+        // Make sure that there is no activity waiting for this to launch.
+        if (mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
+            r.displayStartTime = r.fullyDrawnStartTime = 0;
         } else {
-            // This activity is not starting in the resumed state... which
-            // should look like we asked it to pause+stop (but remain visible),
-            // and it has done so and reported back the current icicle and
-            // other state.
-            if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
-                    + " (starting in stopped state)");
-            r.state = ActivityState.STOPPED;
-            r.stopped = true;
-        }
-
-        // Launch the new version setup screen if needed.  We do this -after-
-        // launching the initial activity (that is, home), so that it can have
-        // a chance to initialize itself while in the background, making the
-        // switch back to it faster and look better.
-        if (mMainStack) {
-            mService.startSetupActivityLocked();
-        }
-        
-        return true;
-    }
-
-    private final void startSpecificActivityLocked(ActivityRecord r,
-            boolean andResume, boolean checkConfig) {
-        // Is this activity's application already running?
-        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
-                r.info.applicationInfo.uid);
-
-        if (r.launchTime == 0) {
-            r.launchTime = SystemClock.uptimeMillis();
-            if (mInitialStartTime == 0) {
-                mInitialStartTime = r.launchTime;
-            }
-        } else if (mInitialStartTime == 0) {
-            mInitialStartTime = SystemClock.uptimeMillis();
-        }
-        
-        if (app != null && app.thread != null) {
-            try {
-                app.addPackage(r.info.packageName);
-                realStartActivityLocked(r, app, andResume, checkConfig);
-                return;
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Exception when starting activity "
-                        + r.intent.getComponent().flattenToShortString(), e);
-            }
-
-            // If a dead object exception was thrown -- fall through to
-            // restart the application.
-        }
-
-        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
-                "activity", r.intent.getComponent(), false, false);
-    }
-    
-    void stopIfSleepingLocked() {
-        if (mService.isSleeping()) {
-            if (!mGoingToSleep.isHeld()) {
-                mGoingToSleep.acquire();
-                if (mLaunchingActivity.isHeld()) {
-                    mLaunchingActivity.release();
-                    mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
-                }
-            }
-            mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
-            Message msg = mHandler.obtainMessage(SLEEP_TIMEOUT_MSG);
-            mHandler.sendMessageDelayed(msg, SLEEP_TIMEOUT);
-            checkReadyForSleepLocked();
+            mStackSupervisor.removeTimeoutsForActivityLocked(r);
+            mStackSupervisor.scheduleIdleTimeoutLocked(r);
         }
     }
 
     void awakeFromSleepingLocked() {
-        mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
-        mSleepTimeout = false;
-        if (mGoingToSleep.isHeld()) {
-            mGoingToSleep.release();
-        }
         // Ensure activities are no longer sleeping.
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            r.setSleeping(false);
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                activities.get(activityNdx).setSleeping(false);
+            }
         }
-        mGoingToSleepActivities.clear();
     }
 
-    void activitySleptLocked(ActivityRecord r) {
-        mGoingToSleepActivities.remove(r);
-        checkReadyForSleepLocked();
-    }
-
-    void checkReadyForSleepLocked() {
-        if (!mService.isSleeping()) {
-            // Do not care.
-            return;
+    /**
+     * @return true if something must be done before going to sleep.
+     */
+    boolean checkReadyForSleepLocked() {
+        if (mResumedActivity != null) {
+            // Still have something resumed; can't sleep until it is paused.
+            if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
+            if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
+            startPausingLocked(false, true);
+            return true;
+        }
+        if (mPausingActivity != null) {
+            // Still waiting for something to pause; can't sleep yet.
+            if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
+            return true;
         }
 
-        if (!mSleepTimeout) {
-            if (mResumedActivity != null) {
-                // Still have something resumed; can't sleep until it is paused.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
-                if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
-                startPausingLocked(false, true);
-                return;
-            }
-            if (mPausingActivity != null) {
-                // Still waiting for something to pause; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
-                return;
-            }
+        return false;
+    }
 
-            if (mStoppingActivities.size() > 0) {
-                // Still need to tell some activities to stop; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
-                        + mStoppingActivities.size() + " activities");
-                scheduleIdleLocked();
-                return;
-            }
+    void goToSleep() {
+        ensureActivitiesVisibleLocked(null, 0);
 
-            ensureActivitiesVisibleLocked(null, 0);
-
-            // Make sure any stopped but visible activities are now sleeping.
-            // This ensures that the activity's onStop() is called.
-            for (int i=mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = mHistory.get(i);
+        // Make sure any stopped but visible activities are now sleeping.
+        // This ensures that the activity's onStop() is called.
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
                 if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
                     r.setSleeping(true);
                 }
             }
-
-            if (mGoingToSleepActivities.size() > 0) {
-                // Still need to tell some activities to sleep; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
-                        + mGoingToSleepActivities.size() + " activities");
-                return;
-            }
-        }
-
-        mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
-
-        if (mGoingToSleep.isHeld()) {
-            mGoingToSleep.release();
-        }
-        if (mService.mShuttingDown) {
-            mService.notifyAll();
         }
     }
 
@@ -931,7 +674,7 @@
         if (who.noDisplay) {
             return null;
         }
-        
+
         Resources res = mService.mContext.getResources();
         int w = mThumbnailWidth;
         int h = mThumbnailHeight;
@@ -947,7 +690,7 @@
                     || mLastScreenshotBitmap.getWidth() != w
                     || mLastScreenshotBitmap.getHeight() != h) {
                 mLastScreenshotActivity = who;
-                mLastScreenshotBitmap = mService.mWindowManager.screenshotApplications(
+                mLastScreenshotBitmap = mWindowManager.screenshotApplications(
                         who.appToken, Display.DEFAULT_DISPLAY, w, h);
             }
             if (mLastScreenshotBitmap != null) {
@@ -957,17 +700,16 @@
         return null;
     }
 
-    private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
+    final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
         if (mPausingActivity != null) {
-            RuntimeException e = new RuntimeException();
             Slog.e(TAG, "Trying to pause when pause is already pending for "
-                  + mPausingActivity, e);
+                  + mPausingActivity, new RuntimeException("here").fillInStackTrace());
         }
         ActivityRecord prev = mResumedActivity;
         if (prev == null) {
-            RuntimeException e = new RuntimeException();
-            Slog.e(TAG, "Trying to pause when nothing is resumed", e);
-            resumeTopActivityLocked(null);
+            Slog.e(TAG, "Trying to pause when nothing is resumed",
+                    new RuntimeException("here").fillInStackTrace());
+            mStackSupervisor.resumeTopActivitiesLocked();
             return;
         }
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
@@ -975,46 +717,44 @@
         mResumedActivity = null;
         mPausingActivity = prev;
         mLastPausedActivity = prev;
+        mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
+                || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
         prev.state = ActivityState.PAUSING;
         prev.task.touchActiveTime();
+        clearLaunchTime(prev);
         prev.updateThumbnail(screenshotActivities(prev), null);
+        stopFullyDrawnTraceIfNeeded();
 
         mService.updateCpuStats();
-        
+
         if (prev.app != null && prev.app.thread != null) {
             if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
             try {
                 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                         prev.userId, System.identityHashCode(prev),
                         prev.shortComponentName);
+                mService.updateUsageStats(prev, false);
                 prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                         userLeaving, prev.configChangeFlags);
-                if (mMainStack) {
-                    mService.updateUsageStats(prev, false);
-                }
             } catch (Exception e) {
                 // Ignore exception, if process died other code will cleanup.
                 Slog.w(TAG, "Exception thrown during pause", e);
                 mPausingActivity = null;
                 mLastPausedActivity = null;
+                mLastNoHistoryActivity = null;
             }
         } else {
             mPausingActivity = null;
             mLastPausedActivity = null;
+            mLastNoHistoryActivity = null;
         }
 
         // If we are not going to sleep, we want to ensure the device is
         // awake until the next activity is started.
-        if (!mService.mSleeping && !mService.mShuttingDown) {
-            mLaunchingActivity.acquire();
-            if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
-                // To be safe, don't allow the wake lock to be held for too long.
-                Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
-                mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
-            }
+        if (!mService.isSleepingOrShuttingDown()) {
+            mStackSupervisor.acquireLaunchWakelock();
         }
 
-
         if (mPausingActivity != null) {
             // Have the window manager pause its key dispatching until the new
             // activity has started.  If we're pausing the activity just because
@@ -1038,46 +778,27 @@
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
-            resumeTopActivityLocked(null);
+            mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
         }
     }
 
-    final void activityResumed(IBinder token) {
-        ActivityRecord r = null;
-
-        synchronized (mService) {
-            int index = indexOfTokenLocked(token);
-            if (index >= 0) {
-                r = mHistory.get(index);
-                if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
-                r.icicle = null;
-                r.haveState = false;
-            }
-        }
-    }
-
-    final void activityPaused(IBinder token, boolean timeout) {
+    final void activityPausedLocked(IBinder token, boolean timeout) {
         if (DEBUG_PAUSE) Slog.v(
             TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
 
-        ActivityRecord r = null;
-
-        synchronized (mService) {
-            int index = indexOfTokenLocked(token);
-            if (index >= 0) {
-                r = mHistory.get(index);
-                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-                if (mPausingActivity == r) {
-                    if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
-                            + (timeout ? " (due to timeout)" : " (pause complete)"));
-                    r.state = ActivityState.PAUSED;
-                    completePauseLocked();
-                } else {
-                    EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
-                            r.userId, System.identityHashCode(r), r.shortComponentName, 
-                            mPausingActivity != null
-                                ? mPausingActivity.shortComponentName : "(none)");
-                }
+        final ActivityRecord r = isInStackLocked(token);
+        if (r != null) {
+            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+            if (mPausingActivity == r) {
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+                        + (timeout ? " (due to timeout)" : " (pause complete)"));
+                r.state = ActivityState.PAUSED;
+                completePauseLocked();
+            } else {
+                EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
+                        r.userId, System.identityHashCode(r), r.shortComponentName,
+                        mPausingActivity != null
+                            ? mPausingActivity.shortComponentName : "(none)");
             }
         }
     }
@@ -1108,32 +829,18 @@
             } else {
                 if (r.configDestroy) {
                     destroyActivityLocked(r, true, false, "stop-config");
-                    resumeTopActivityLocked(null);
+                    mStackSupervisor.resumeTopActivitiesLocked();
                 } else {
-                    // Now that this process has stopped, we may want to consider
-                    // it to be the previous app to try to keep around in case
-                    // the user wants to return to it.
-                    ProcessRecord fgApp = null;
-                    if (mResumedActivity != null) {
-                        fgApp = mResumedActivity.app;
-                    } else if (mPausingActivity != null) {
-                        fgApp = mPausingActivity.app;
-                    }
-                    if (r.app != null && fgApp != null && r.app != fgApp
-                            && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
-                            && r.app != mService.mHomeProcess) {
-                        mService.mPreviousProcess = r.app;
-                        mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
-                    }
+                    mStackSupervisor.updatePreviousProcessLocked(r);
                 }
             }
         }
     }
 
-    private final void completePauseLocked() {
+    private void completePauseLocked() {
         ActivityRecord prev = mPausingActivity;
         if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
-        
+
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
@@ -1142,7 +849,7 @@
                 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
                 if (prev.waitingVisible) {
                     prev.waitingVisible = false;
-                    mWaitingVisibleActivities.remove(prev);
+                    mStackSupervisor.mWaitingVisibleActivities.remove(prev);
                     if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
                             TAG, "Complete pause, no longer waiting: " + prev);
                 }
@@ -1155,15 +862,17 @@
                     if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
                     destroyActivityLocked(prev, true, false, "pause-config");
                 } else {
-                    mStoppingActivities.add(prev);
-                    if (mStoppingActivities.size() > 3) {
+                    mStackSupervisor.mStoppingActivities.add(prev);
+                    if (mStackSupervisor.mStoppingActivities.size() > 3 ||
+                            prev.frontOfTask && mTaskHistory.size() <= 1) {
                         // If we already have a few activities waiting to stop,
                         // then give up on things going idle and start clearing
-                        // them out.
+                        // them out. Or if r is the last of activity of the last task the stack
+                        // will be empty and must be cleared immediately.
                         if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
-                        scheduleIdleLocked();
+                        mStackSupervisor.scheduleIdleLocked();
                     } else {
-                        checkReadyForSleepLocked();
+                        mStackSupervisor.checkReadyForSleepLocked();
                     }
                 }
             } else {
@@ -1173,45 +882,46 @@
             mPausingActivity = null;
         }
 
-        if (!mService.isSleeping()) {
-            resumeTopActivityLocked(prev);
+        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
+        if (!mService.isSleepingOrShuttingDown()) {
+            mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
         } else {
-            checkReadyForSleepLocked();
-            ActivityRecord top = topRunningActivityLocked(null);
+            mStackSupervisor.checkReadyForSleepLocked();
+            ActivityRecord top = topStack.topRunningActivityLocked(null);
             if (top == null || (prev != null && top != prev)) {
                 // If there are no more activities available to run,
                 // do resume anyway to start something.  Also if the top
                 // activity on the stack is not the just paused activity,
                 // we need to go ahead and resume it to ensure we complete
                 // an in-flight app switch.
-                resumeTopActivityLocked(null);
+                mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
             }
         }
-        
-        if (prev != null) {
-            prev.resumeKeyDispatchingLocked();
-        }
 
-        if (prev.app != null && prev.cpuTimeAtResume > 0
-                && mService.mBatteryStatsService.isOnBattery()) {
-            long diff = 0;
-            synchronized (mService.mProcessStatsThread) {
-                diff = mService.mProcessStats.getCpuTimeForPid(prev.app.pid)
-                        - prev.cpuTimeAtResume;
-            }
-            if (diff > 0) {
-                BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
-                synchronized (bsi) {
-                    BatteryStatsImpl.Uid.Proc ps =
-                            bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
-                            prev.info.packageName);
-                    if (ps != null) {
-                        ps.addForegroundTimeLocked(diff);
+        if (prev != null) {
+            prev.resumeKeyDispatchingLocked();
+
+            if (prev.app != null && prev.cpuTimeAtResume > 0
+                    && mService.mBatteryStatsService.isOnBattery()) {
+                long diff;
+                synchronized (mService.mProcessCpuThread) {
+                    diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
+                            - prev.cpuTimeAtResume;
+                }
+                if (diff > 0) {
+                    BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
+                    synchronized (bsi) {
+                        BatteryStatsImpl.Uid.Proc ps =
+                                bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
+                                        prev.info.packageName);
+                        if (ps != null) {
+                            ps.addForegroundTimeLocked(diff);
+                        }
                     }
                 }
             }
+            prev.cpuTimeAtResume = 0; // reset it
         }
-        prev.cpuTimeAtResume = 0; // reset it
     }
 
     /**
@@ -1219,44 +929,29 @@
      * the resumed state (either by launching it or explicitly telling it),
      * this function updates the rest of our state to match that fact.
      */
-    private final void completeResumeLocked(ActivityRecord next) {
+    private void completeResumeLocked(ActivityRecord next) {
         next.idle = false;
         next.results = null;
         next.newIntents = null;
+        if (next.nowVisible) {
+            // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
+            mStackSupervisor.dismissKeyguard();
+        }
 
         // schedule an idle timeout in case the app doesn't do it for us.
-        Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
-        msg.obj = next;
-        mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
+        mStackSupervisor.scheduleIdleTimeoutLocked(next);
 
-        if (false) {
-            // The activity was never told to pause, so just keep
-            // things going as-is.  To maintain our own state,
-            // we need to emulate it coming back and saying it is
-            // idle.
-            msg = mHandler.obtainMessage(IDLE_NOW_MSG);
-            msg.obj = next;
-            mHandler.sendMessage(msg);
-        }
+        mStackSupervisor.reportResumedActivityLocked(next);
 
-        if (mMainStack) {
-            mService.reportResumedActivityLocked(next);
-        }
-
-        if (mMainStack) {
-            mService.setFocusedActivityLocked(next);
-        }
         next.resumeKeyDispatchingLocked();
-        ensureActivitiesVisibleLocked(null, 0);
-        mService.mWindowManager.executeAppTransition();
         mNoAnimActivities.clear();
 
         // Mark the point when the activity is resuming
         // TODO: To be more accurate, the mark should be before the onCreate,
         //       not after the onResume. But for subsequent starts, onResume is fine.
         if (next.app != null) {
-            synchronized (mService.mProcessStatsThread) {
-                next.cpuTimeAtResume = mService.mProcessStats.getCpuTimeForPid(next.app.pid);
+            synchronized (mService.mProcessCpuThread) {
+                next.cpuTimeAtResume = mService.mProcessCpuTracker.getCpuTimeForPid(next.app.pid);
             }
         } else {
             next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
@@ -1264,129 +959,185 @@
     }
 
     /**
+     * Version of ensureActivitiesVisible that can easily be called anywhere.
+     */
+    final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+        return ensureActivitiesVisibleLocked(starting, configChanges, false);
+    }
+
+    final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
+            boolean forceHomeShown) {
+        ActivityRecord r = topRunningActivityLocked(null);
+        return r != null &&
+                ensureActivitiesVisibleLocked(r, starting, null, configChanges, forceHomeShown);
+    }
+
+    /**
      * Make sure that all activities that need to be visible (that is, they
      * currently can be seen by the user) actually are.
      */
-    final void ensureActivitiesVisibleLocked(ActivityRecord top,
-            ActivityRecord starting, String onlyThisProcess, int configChanges) {
-        if (DEBUG_VISBILITY) Slog.v(
+    final boolean ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
+            String onlyThisProcess, int configChanges, boolean forceHomeShown) {
+        if (true || DEBUG_VISBILITY) Slog.v(
                 TAG, "ensureActivitiesVisible behind " + top
                 + " configChanges=0x" + Integer.toHexString(configChanges));
 
+        if (mTranslucentActivityWaiting != top) {
+            mUndrawnActivitiesBelowTopTranslucent.clear();
+            if (mTranslucentActivityWaiting != null) {
+                // Call the callback with a timeout indication.
+                notifyActivityDrawnLocked(null);
+                mTranslucentActivityWaiting = null;
+            }
+            mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
+        }
+
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
-        final int count = mHistory.size();
-        int i = count-1;
-        while (mHistory.get(i) != top) {
-            i--;
-        }
-        ActivityRecord r;
-        boolean behindFullscreen = false;
-        for (; i>=0; i--) {
-            r = mHistory.get(i);
-            if (DEBUG_VISBILITY) Slog.v(
-                    TAG, "Make visible? " + r + " finishing=" + r.finishing
-                    + " state=" + r.state);
-            if (r.finishing) {
-                continue;
-            }
-            
-            final boolean doThisProcess = onlyThisProcess == null
-                    || onlyThisProcess.equals(r.processName);
-            
-            // First: if this is not the current activity being started, make
-            // sure it matches the current configuration.
-            if (r != starting && doThisProcess) {
-                ensureActivityConfigurationLocked(r, 0);
-            }
-            
-            if (r.app == null || r.app.thread == null) {
-                if (onlyThisProcess == null
-                        || onlyThisProcess.equals(r.processName)) {
-                    // This activity needs to be visible, but isn't even
-                    // running...  get it started, but don't resume it
-                    // at this point.
-                    if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Start and freeze screen for " + r);
-                    if (r != starting) {
-                        r.startFreezingScreenLocked(r.app, configChanges);
-                    }
-                    if (!r.visible) {
-                        if (DEBUG_VISBILITY) Slog.v(
-                                TAG, "Starting and making visible: " + r);
-                        mService.mWindowManager.setAppVisibility(r.appToken, true);
-                    }
-                    if (r != starting) {
-                        startSpecificActivityLocked(r, false, false);
-                    }
+        boolean aboveTop = true;
+        boolean showHomeBehindStack = false;
+        boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
+                !(forceHomeShown && isHomeStack());
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.finishing) {
+                    continue;
                 }
-
-            } else if (r.visible) {
-                // If this activity is already visible, then there is nothing
-                // else to do here.
-                if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Skipping: already visible at " + r);
-                r.stopFreezingScreenLocked(false);
-
-            } else if (onlyThisProcess == null) {
-                // This activity is not currently visible, but is running.
-                // Tell it to become visible.
-                r.visible = true;
-                if (r.state != ActivityState.RESUMED && r != starting) {
-                    // If this activity is paused, tell it
-                    // to now show its window.
+                if (aboveTop && r != top) {
+                    continue;
+                }
+                aboveTop = false;
+                if (!behindFullscreen) {
                     if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Making visible and scheduling visibility: " + r);
-                    try {
-                        mService.mWindowManager.setAppVisibility(r.appToken, true);
-                        r.sleeping = false;
-                        r.app.pendingUiClean = true;
-                        r.app.thread.scheduleWindowVisibility(r.appToken, true);
+                            TAG, "Make visible? " + r + " finishing=" + r.finishing
+                            + " state=" + r.state);
+
+                    final boolean doThisProcess = onlyThisProcess == null
+                            || onlyThisProcess.equals(r.processName);
+
+                    // First: if this is not the current activity being started, make
+                    // sure it matches the current configuration.
+                    if (r != starting && doThisProcess) {
+                        ensureActivityConfigurationLocked(r, 0);
+                    }
+
+                    if (r.app == null || r.app.thread == null) {
+                        if (onlyThisProcess == null || onlyThisProcess.equals(r.processName)) {
+                            // This activity needs to be visible, but isn't even
+                            // running...  get it started, but don't resume it
+                            // at this point.
+                            if (DEBUG_VISBILITY) Slog.v(TAG, "Start and freeze screen for " + r);
+                            if (r != starting) {
+                                r.startFreezingScreenLocked(r.app, configChanges);
+                            }
+                            if (!r.visible) {
+                                if (true || DEBUG_VISBILITY) Slog.v(
+                                        TAG, "Starting and making visible: " + r);
+                                mWindowManager.setAppVisibility(r.appToken, true);
+                            }
+                            if (r != starting) {
+                                mStackSupervisor.startSpecificActivityLocked(r, false, false);
+                            }
+                        }
+
+                    } else if (r.visible) {
+                        // If this activity is already visible, then there is nothing
+                        // else to do here.
+                        if (DEBUG_VISBILITY) Slog.v(TAG, "Skipping: already visible at " + r);
                         r.stopFreezingScreenLocked(false);
-                    } catch (Exception e) {
-                        // Just skip on any failure; we'll make it
-                        // visible when it next restarts.
-                        Slog.w(TAG, "Exception thrown making visibile: "
-                                + r.intent.getComponent(), e);
+
+                    } else if (onlyThisProcess == null) {
+                        // This activity is not currently visible, but is running.
+                        // Tell it to become visible.
+                        r.visible = true;
+                        if (r.state != ActivityState.RESUMED && r != starting) {
+                            // If this activity is paused, tell it
+                            // to now show its window.
+                            if (true || DEBUG_VISBILITY) Slog.v(
+                                    TAG, "Making visible and scheduling visibility: " + r);
+                            try {
+                                if (mTranslucentActivityWaiting != null) {
+                                    mUndrawnActivitiesBelowTopTranslucent.add(r);
+                                }
+                                mWindowManager.setAppVisibility(r.appToken, true);
+                                r.sleeping = false;
+                                r.app.pendingUiClean = true;
+                                r.app.thread.scheduleWindowVisibility(r.appToken, true);
+                                r.stopFreezingScreenLocked(false);
+                            } catch (Exception e) {
+                                // Just skip on any failure; we'll make it
+                                // visible when it next restarts.
+                                Slog.w(TAG, "Exception thrown making visibile: "
+                                        + r.intent.getComponent(), e);
+                            }
+                        }
                     }
-                }
-            }
 
-            // Aggregate current change flags.
-            configChanges |= r.configChangeFlags;
+                    // Aggregate current change flags.
+                    configChanges |= r.configChangeFlags;
 
-            if (r.fullscreen) {
-                // At this point, nothing else needs to be shown
-                if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Stopping: fullscreen at " + r);
-                behindFullscreen = true;
-                i--;
-                break;
-            }
-        }
-
-        // Now for any activities that aren't visible to the user, make
-        // sure they no longer are keeping the screen frozen.
-        while (i >= 0) {
-            r = mHistory.get(i);
-            if (DEBUG_VISBILITY) Slog.v(
-                    TAG, "Make invisible? " + r + " finishing=" + r.finishing
-                    + " state=" + r.state
-                    + " behindFullscreen=" + behindFullscreen);
-            if (!r.finishing) {
-                if (behindFullscreen) {
+                    if (r.fullscreen) {
+                        // At this point, nothing else needs to be shown
+                        if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
+                        behindFullscreen = true;
+                    } else if (task.mOnTopOfHome) {
+                        // Work our way down from r to bottom of task and see if there are any
+                        // visible activities below r.
+                        int rIndex = task.mActivities.indexOf(r);
+                        for ( --rIndex; rIndex >= 0; --rIndex) {
+                            final ActivityRecord blocker = task.mActivities.get(rIndex);
+                            if (!blocker.finishing && blocker.visible) {
+                                if (DEBUG_VISBILITY) Slog.v(TAG, "Home visibility for " +
+                                        r + " blocked by " + blocker);
+                                break;
+                            }
+                        }
+                        if (rIndex < 0) {
+                            // Got to task bottom without finding a visible activity, show home.
+                            if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
+                            showHomeBehindStack = true;
+                            behindFullscreen = true;
+                        }
+                    }
+                } else {
+                    if (DEBUG_VISBILITY) Slog.v(
+                        TAG, "Make invisible? " + r + " finishing=" + r.finishing
+                        + " state=" + r.state
+                        + " behindFullscreen=" + behindFullscreen);
+                    // Now for any activities that aren't visible to the user, make
+                    // sure they no longer are keeping the screen frozen.
                     if (r.visible) {
-                        if (DEBUG_VISBILITY) Slog.v(
-                                TAG, "Making invisible: " + r);
+                        if (true || DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r);
                         r.visible = false;
                         try {
-                            mService.mWindowManager.setAppVisibility(r.appToken, false);
-                            if ((r.state == ActivityState.STOPPING
-                                    || r.state == ActivityState.STOPPED)
-                                    && r.app != null && r.app.thread != null) {
-                                if (DEBUG_VISBILITY) Slog.v(
-                                        TAG, "Scheduling invisibility: " + r);
-                                r.app.thread.scheduleWindowVisibility(r.appToken, false);
+                            mWindowManager.setAppVisibility(r.appToken, false);
+                            switch (r.state) {
+                                case STOPPING:
+                                case STOPPED:
+                                    if (r.app != null && r.app.thread != null) {
+                                        if (DEBUG_VISBILITY) Slog.v(
+                                                TAG, "Scheduling invisibility: " + r);
+                                        r.app.thread.scheduleWindowVisibility(r.appToken, false);
+                                    }
+                                    break;
+
+                                case INITIALIZING:
+                                case RESUMED:
+                                case PAUSING:
+                                case PAUSED:
+                                    // This case created for transitioning activities from
+                                    // translucent to opaque {@link Activity#convertToOpaque}.
+                                    if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+                                        mStackSupervisor.mStoppingActivities.add(r);
+                                    }
+                                    mStackSupervisor.scheduleIdleLocked();
+                                    break;
+
+                                default:
+                                    break;
                             }
                         } catch (Exception e) {
                             // Just skip on any failure; we'll make it
@@ -1395,30 +1146,50 @@
                                     + r.intent.getComponent(), e);
                         }
                     } else {
-                        if (DEBUG_VISBILITY) Slog.v(
-                                TAG, "Already invisible: " + r);
+                        if (DEBUG_VISBILITY) Slog.v(TAG, "Already invisible: " + r);
                     }
-                } else if (r.fullscreen) {
-                    if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Now behindFullscreen: " + r);
-                    behindFullscreen = true;
                 }
             }
-            i--;
         }
+        return showHomeBehindStack;
+    }
+
+    void convertToTranslucent(ActivityRecord r) {
+        mTranslucentActivityWaiting = r;
+        mUndrawnActivitiesBelowTopTranslucent.clear();
+        mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
     }
 
     /**
-     * Version of ensureActivitiesVisible that can easily be called anywhere.
+     * Called as activities below the top translucent activity are redrawn. When the last one is
+     * redrawn notify the top activity by calling
+     * {@link Activity#onTranslucentConversionComplete}.
+     *
+     * @param r The most recent background activity to be drawn. Or, if r is null then a timeout
+     * occurred and the activity will be notified immediately.
      */
-    final void ensureActivitiesVisibleLocked(ActivityRecord starting,
-            int configChanges) {
-        ActivityRecord r = topRunningActivityLocked(null);
-        if (r != null) {
-            ensureActivitiesVisibleLocked(r, starting, null, configChanges);
+    void notifyActivityDrawnLocked(ActivityRecord r) {
+        if ((r == null)
+                || (mUndrawnActivitiesBelowTopTranslucent.remove(r) &&
+                        mUndrawnActivitiesBelowTopTranslucent.isEmpty())) {
+            // The last undrawn activity below the top has just been drawn. If there is an
+            // opaque activity at the top, notify it that it can become translucent safely now.
+            final ActivityRecord waitingActivity = mTranslucentActivityWaiting;
+            mTranslucentActivityWaiting = null;
+            mUndrawnActivitiesBelowTopTranslucent.clear();
+            mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
+
+            if (waitingActivity != null && waitingActivity.app != null &&
+                    waitingActivity.app.thread != null) {
+                try {
+                    waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+                            waitingActivity.appToken, r != null);
+                } catch (RemoteException e) {
+                }
+            }
         }
     }
-    
+
     /**
      * Ensure that the top activity in the stack is resumed.
      *
@@ -1433,47 +1204,79 @@
     }
 
     final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
+        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+
         // Find the first activity that is not finishing.
         ActivityRecord next = topRunningActivityLocked(null);
 
         // Remember how we'll process this pause/resume situation, and ensure
         // that the state is reset however we wind up proceeding.
-        final boolean userLeaving = mUserLeaving;
-        mUserLeaving = false;
+        final boolean userLeaving = mStackSupervisor.mUserLeaving;
+        mStackSupervisor.mUserLeaving = false;
 
         if (next == null) {
             // There are no more activities!  Let's just start up the
             // Launcher...
-            if (mMainStack) {
-                ActivityOptions.abort(options);
-                return mService.startHomeActivityLocked(mCurrentUser);
-            }
+            ActivityOptions.abort(options);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
+            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+            return mStackSupervisor.resumeHomeActivity(prev);
         }
 
         next.delayedResume = false;
-        
+
         // If the top activity is the resumed one, nothing to do.
-        if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
+        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
+                    mStackSupervisor.allResumedActivitiesComplete()) {
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
-            mService.mWindowManager.executeAppTransition();
+            mWindowManager.executeAppTransition();
             mNoAnimActivities.clear();
             ActivityOptions.abort(options);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next);
+            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
 
+        final TaskRecord nextTask = next.task;
+        final TaskRecord prevTask = prev != null ? prev.task : null;
+        if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
+            if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
+            if (prevTask == nextTask) {
+                ArrayList<ActivityRecord> activities = prevTask.mActivities;
+                final int numActivities = activities.size();
+                for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+                    final ActivityRecord r = activities.get(activityNdx);
+                    // r is usually the same as next, but what if two activities were launched
+                    // before prev finished?
+                    if (!r.finishing) {
+                        r.frontOfTask = true;
+                        break;
+                    }
+                }
+            } else if (prevTask != topTask()) {
+                // This task is going away but it was supposed to return to the home task.
+                // Now the task above it has to return to the home task instead.
+                final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
+                mTaskHistory.get(taskNdx).mOnTopOfHome = true;
+            } else {
+                if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
+                return mStackSupervisor.resumeHomeActivity(prev);
+            }
+        }
+
         // If we are sleeping, and there is no resumed activity, and the top
         // activity is paused, well that is the state we want.
-        if ((mService.mSleeping || mService.mShuttingDown)
+        if (mService.isSleepingOrShuttingDown()
                 && mLastPausedActivity == next
-                && (next.state == ActivityState.PAUSED
-                    || next.state == ActivityState.STOPPED
-                    || next.state == ActivityState.STOPPING)) {
+                && mStackSupervisor.allPausedActivitiesComplete()) {
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
-            mService.mWindowManager.executeAppTransition();
+            mWindowManager.executeAppTransition();
             mNoAnimActivities.clear();
             ActivityOptions.abort(options);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Going to sleep and all paused");
+            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
 
@@ -1483,15 +1286,16 @@
         if (mService.mStartedUsers.get(next.userId) == null) {
             Slog.w(TAG, "Skipping resume of top activity " + next
                     + ": user " + next.userId + " is stopped");
+            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
 
         // The activity may be waiting for stop, but that is no longer
         // appropriate for it.
-        mStoppingActivities.remove(next);
-        mGoingToSleepActivities.remove(next);
+        mStackSupervisor.mStoppingActivities.remove(next);
+        mStackSupervisor.mGoingToSleepActivities.remove(next);
         next.sleeping = false;
-        mWaitingVisibleActivities.remove(next);
+        mStackSupervisor.mWaitingVisibleActivities.remove(next);
 
         next.updateOptionsLocked(options);
 
@@ -1499,9 +1303,10 @@
 
         // If we are currently pausing an activity, then don't do anything
         // until that is done.
-        if (mPausingActivity != null) {
-            if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG,
-                    "Skip resume: pausing=" + mPausingActivity);
+        if (!mStackSupervisor.allPausedActivitiesComplete()) {
+            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
+                    "resumeTopActivityLocked: Skip resume: some activity pausing.");
+            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
 
@@ -1533,11 +1338,18 @@
                 mLastStartedActivity = next;
             }
         }
-        
+
         // We need to start pausing the current activity so the top one
         // can be resumed...
+        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving);
         if (mResumedActivity != null) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
+            pausing = true;
+            startPausingLocked(userLeaving, false);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
+        }
+        if (pausing) {
+            if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG,
+                    "resumeTopActivityLocked: Skip resume: need to start pausing");
             // At this point we want to put the upcoming activity's process
             // at the top of the LRU list, since we know we will be needing it
             // very soon and it would be a waste to let it get killed if it
@@ -1545,31 +1357,28 @@
             if (next.app != null && next.app.thread != null) {
                 // No reason to do full oom adj update here; we'll let that
                 // happen whenever it needs to later.
-                mService.updateLruProcessLocked(next.app, false);
+                mService.updateLruProcessLocked(next.app, false, true);
             }
-            startPausingLocked(userLeaving, false);
+            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return true;
         }
 
         // If the most recent activity was noHistory but was only stopped rather
         // than stopped+finished because the device went to sleep, we need to make
         // sure to finish it as we're making a new activity topmost.
-        final ActivityRecord last = mLastPausedActivity;
-        if (mService.mSleeping && last != null && !last.finishing) {
-            if ((last.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
-                    || (last.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
-                if (DEBUG_STATES) {
-                    Slog.d(TAG, "no-history finish of " + last + " on new resume");
-                }
-                requestFinishActivityLocked(last.appToken, Activity.RESULT_CANCELED, null,
-                        "no-history", false);
-            }
+        if (mService.mSleeping && mLastNoHistoryActivity != null &&
+                !mLastNoHistoryActivity.finishing) {
+            if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity +
+                    " on new resume");
+            requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
+                    null, "no-history", false);
+            mLastNoHistoryActivity = null;
         }
 
         if (prev != null && prev != next) {
             if (!prev.waitingVisible && next != null && !next.nowVisible) {
                 prev.waitingVisible = true;
-                mWaitingVisibleActivities.add(prev);
+                mStackSupervisor.mWaitingVisibleActivities.add(prev);
                 if (DEBUG_SWITCH) Slog.v(
                         TAG, "Resuming top, waiting visible to hide: " + prev);
             } else {
@@ -1582,7 +1391,7 @@
                 // previous should actually be hidden depending on whether the
                 // new one is found to be full-screen or not.
                 if (prev.finishing) {
-                    mService.mWindowManager.setAppVisibility(prev.appToken, false);
+                    mWindowManager.setAppVisibility(prev.appToken, false);
                     if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
                             + prev + ", waitingVisible="
                             + (prev != null ? prev.waitingVisible : null)
@@ -1610,120 +1419,114 @@
         // We are starting up the next activity, so tell the window manager
         // that the previous one will be hidden soon.  This way it can know
         // to ignore it when computing the desired screen orientation.
-        boolean noAnim = false;
+        boolean anim = true;
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_TRANSITION) Slog.v(TAG,
                         "Prepare close transition: prev=" + prev);
                 if (mNoAnimActivities.contains(prev)) {
-                    mService.mWindowManager.prepareAppTransition(
-                            AppTransition.TRANSIT_NONE, false);
+                    anim = false;
+                    mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
                 } else {
-                    mService.mWindowManager.prepareAppTransition(prev.task == next.task
+                    mWindowManager.prepareAppTransition(prev.task == next.task
                             ? AppTransition.TRANSIT_ACTIVITY_CLOSE
                             : AppTransition.TRANSIT_TASK_CLOSE, false);
                 }
-                mService.mWindowManager.setAppWillBeHidden(prev.appToken);
-                mService.mWindowManager.setAppVisibility(prev.appToken, false);
+                mWindowManager.setAppWillBeHidden(prev.appToken);
+                mWindowManager.setAppVisibility(prev.appToken, false);
             } else {
-                if (DEBUG_TRANSITION) Slog.v(TAG,
-                        "Prepare open transition: prev=" + prev);
+                if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev);
                 if (mNoAnimActivities.contains(next)) {
-                    noAnim = true;
-                    mService.mWindowManager.prepareAppTransition(
-                            AppTransition.TRANSIT_NONE, false);
+                    anim = false;
+                    mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
                 } else {
-                    mService.mWindowManager.prepareAppTransition(prev.task == next.task
+                    mWindowManager.prepareAppTransition(prev.task == next.task
                             ? AppTransition.TRANSIT_ACTIVITY_OPEN
                             : AppTransition.TRANSIT_TASK_OPEN, false);
                 }
             }
             if (false) {
-                mService.mWindowManager.setAppWillBeHidden(prev.appToken);
-                mService.mWindowManager.setAppVisibility(prev.appToken, false);
+                mWindowManager.setAppWillBeHidden(prev.appToken);
+                mWindowManager.setAppVisibility(prev.appToken, false);
             }
-        } else if (mHistory.size() > 1) {
-            if (DEBUG_TRANSITION) Slog.v(TAG,
-                    "Prepare open transition: no previous");
+        } else {
+            if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: no previous");
             if (mNoAnimActivities.contains(next)) {
-                noAnim = true;
-                mService.mWindowManager.prepareAppTransition(
-                        AppTransition.TRANSIT_NONE, false);
+                anim = false;
+                mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             } else {
-                mService.mWindowManager.prepareAppTransition(
-                        AppTransition.TRANSIT_ACTIVITY_OPEN, false);
+                mWindowManager.prepareAppTransition(AppTransition.TRANSIT_ACTIVITY_OPEN, false);
             }
         }
-        if (!noAnim) {
+        if (anim) {
             next.applyOptionsLocked();
         } else {
             next.clearOptionsLocked();
         }
 
+        ActivityStack lastStack = mStackSupervisor.getLastStack();
         if (next.app != null && next.app.thread != null) {
             if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
 
             // This activity is now becoming visible.
-            mService.mWindowManager.setAppVisibility(next.appToken, true);
+            mWindowManager.setAppVisibility(next.appToken, true);
 
             // schedule launch ticks to collect information about slow apps.
             next.startLaunchTickingLocked();
 
-            ActivityRecord lastResumedActivity = mResumedActivity;
+            ActivityRecord lastResumedActivity =
+                    lastStack == null ? null :lastStack.mResumedActivity;
             ActivityState lastState = next.state;
 
             mService.updateCpuStats();
-            
+
             if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
             next.state = ActivityState.RESUMED;
             mResumedActivity = next;
             next.task.touchActiveTime();
-            if (mMainStack) {
-                mService.addRecentTaskLocked(next.task);
-            }
-            mService.updateLruProcessLocked(next.app, true);
+            mService.addRecentTaskLocked(next.task);
+            mService.updateLruProcessLocked(next.app, true, true);
             updateLRUListLocked(next);
 
             // Have the window manager re-evaluate the orientation of
             // the screen based on the new activity order.
-            boolean updated = false;
-            if (mMainStack) {
-                synchronized (mService) {
-                    Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
-                            mService.mConfiguration,
-                            next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
-                    if (config != null) {
-                        next.frozenBeforeDestroy = true;
-                    }
-                    updated = mService.updateConfigurationLocked(config, next, false, false);
+            boolean notUpdated = true;
+            if (mStackSupervisor.isFrontStack(this)) {
+                Configuration config = mWindowManager.updateOrientationFromAppTokens(
+                        mService.mConfiguration,
+                        next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
+                if (config != null) {
+                    next.frozenBeforeDestroy = true;
                 }
+                notUpdated = !mService.updateConfigurationLocked(config, next, false, false);
             }
-            if (!updated) {
+
+            if (notUpdated) {
                 // The configuration update wasn't able to keep the existing
                 // instance of the activity, and instead started a new one.
                 // We should be all done, but let's just make sure our activity
                 // is still at the top and schedule another run if something
                 // weird happened.
                 ActivityRecord nextNext = topRunningActivityLocked(null);
-                if (DEBUG_SWITCH) Slog.i(TAG,
+                if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
                         "Activity config changed during resume: " + next
                         + ", new next: " + nextNext);
                 if (nextNext != next) {
                     // Do over!
-                    mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+                    mStackSupervisor.scheduleResumeTopActivities();
                 }
-                if (mMainStack) {
-                    mService.setFocusedActivityLocked(next);
+                if (mStackSupervisor.reportResumedActivityLocked(next)) {
+                    mNoAnimActivities.clear();
+                    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+                    return true;
                 }
-                ensureActivitiesVisibleLocked(null, 0);
-                mService.mWindowManager.executeAppTransition();
-                mNoAnimActivities.clear();
-                return true;
+                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+                return false;
             }
-            
+
             try {
                 // Deliver all pending results.
-                ArrayList a = next.results;
+                ArrayList<ResultInfo> a = next.results;
                 if (a != null) {
                     final int N = a.size();
                     if (!next.finishing && N > 0) {
@@ -1741,36 +1544,38 @@
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
                         next.userId, System.identityHashCode(next),
                         next.task.taskId, next.shortComponentName);
-                
-                next.sleeping = false;
-                showAskCompatModeDialogLocked(next);
-                next.app.pendingUiClean = true;
-                next.app.thread.scheduleResumeActivity(next.appToken,
-                        mService.isNextTransitionForward());
-                
-                checkReadyForSleepLocked();
 
+                next.sleeping = false;
+                mService.showAskCompatModeDialogLocked(next);
+                next.app.pendingUiClean = true;
+                next.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
+                next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
+                        mService.isNextTransitionForward());
+
+                mStackSupervisor.checkReadyForSleepLocked();
+
+                if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Resumed " + next);
             } catch (Exception e) {
                 // Whoops, need to restart this activity!
                 if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
                         + lastState + ": " + next);
                 next.state = lastState;
-                mResumedActivity = lastResumedActivity;
+                if (lastStack != null) {
+                    lastStack.mResumedActivity = lastResumedActivity;
+                }
                 Slog.i(TAG, "Restarting because process died: " + next);
                 if (!next.hasBeenLaunched) {
                     next.hasBeenLaunched = true;
-                } else {
-                    if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
-                        mService.mWindowManager.setAppStartingWindow(
-                                next.appToken, next.packageName, next.theme,
-                                mService.compatibilityInfoForPackageLocked(
-                                        next.info.applicationInfo),
-                                next.nonLocalizedLabel,
-                                next.labelRes, next.icon, next.windowFlags,
-                                null, true);
-                    }
+                } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
+                        mStackSupervisor.isFrontStack(lastStack)) {
+                    mWindowManager.setAppStartingWindow(
+                            next.appToken, next.packageName, next.theme,
+                            mService.compatibilityInfoForPackageLocked(next.info.applicationInfo),
+                            next.nonLocalizedLabel, next.labelRes, next.icon, next.logo,
+                            next.windowFlags, null, true);
                 }
-                startSpecificActivityLocked(next, true, false);
+                mStackSupervisor.startSpecificActivityLocked(next, true, false);
+                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                 return true;
             }
 
@@ -1785,6 +1590,7 @@
                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
                 requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                         "resume-exception", true);
+                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                 return true;
             }
             next.stopped = false;
@@ -1795,53 +1601,70 @@
                 next.hasBeenLaunched = true;
             } else {
                 if (SHOW_APP_STARTING_PREVIEW) {
-                    mService.mWindowManager.setAppStartingWindow(
+                    mWindowManager.setAppStartingWindow(
                             next.appToken, next.packageName, next.theme,
                             mService.compatibilityInfoForPackageLocked(
                                     next.info.applicationInfo),
                             next.nonLocalizedLabel,
-                            next.labelRes, next.icon, next.windowFlags,
+                            next.labelRes, next.icon, next.logo, next.windowFlags,
                             null, true);
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
             }
-            startSpecificActivityLocked(next, true, true);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next);
+            mStackSupervisor.startSpecificActivityLocked(next, true, true);
         }
 
+        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
         return true;
     }
 
-    private final void startActivityLocked(ActivityRecord r, boolean newTask,
-            boolean doResume, boolean keepCurTransition, Bundle options) {
-        final int NH = mHistory.size();
+    private void insertTaskAtTop(TaskRecord task) {
+        mTaskHistory.remove(task);
+        // Now put task at top.
+        int stackNdx = mTaskHistory.size();
+        if (task.userId != mCurrentUser) {
+            // Put non-current user tasks below current user tasks.
+            while (--stackNdx >= 0) {
+                if (mTaskHistory.get(stackNdx).userId != mCurrentUser) {
+                    break;
+                }
+            }
+            ++stackNdx;
+        }
+        mTaskHistory.add(stackNdx, task);
+    }
 
-        int addPos = -1;
-        
+    final void startActivityLocked(ActivityRecord r, boolean newTask,
+            boolean doResume, boolean keepCurTransition, Bundle options) {
+        TaskRecord rTask = r.task;
+        final int taskId = rTask.taskId;
+        if (taskForIdLocked(taskId) == null || newTask) {
+            // Last activity in task had been removed or ActivityManagerService is reusing task.
+            // Insert or replace.
+            // Might not even be in.
+            insertTaskAtTop(rTask);
+            mWindowManager.moveTaskToTop(taskId);
+        }
+        TaskRecord task = null;
         if (!newTask) {
             // If starting in an existing task, find where that is...
             boolean startIt = true;
-            for (int i = NH-1; i >= 0; i--) {
-                ActivityRecord p = mHistory.get(i);
-                if (p.finishing) {
-                    continue;
-                }
-                if (p.task == r.task) {
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                task = mTaskHistory.get(taskNdx);
+                if (task == r.task) {
                     // Here it is!  Now, if this is not yet visible to the
                     // user, then just add it without starting; it will
                     // get started when the user navigates back to it.
-                    addPos = i+1;
                     if (!startIt) {
-                        if (DEBUG_ADD_REMOVE) {
-                            RuntimeException here = new RuntimeException("here");
-                            here.fillInStackTrace();
-                            Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
-                                    here);
-                        }
-                        mHistory.add(addPos, r);
+                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+                                + task, new RuntimeException("here").fillInStackTrace());
+                        task.addActivityToTop(r);
                         r.putInHistory();
-                        mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
-                                r.info.screenOrientation, r.fullscreen,
-                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
+                                r.userId);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
                         }
@@ -1849,8 +1672,7 @@
                         return;
                     }
                     break;
-                }
-                if (p.fullscreen) {
+                } else if (task.numFullscreen > 0) {
                     startIt = false;
                 }
             }
@@ -1858,28 +1680,26 @@
 
         // Place a new activity at top of stack, so it is next to interact
         // with the user.
-        if (addPos < 0) {
-            addPos = NH;
-        }
-        
+
         // If we are not placing the new activity frontmost, we do not want
         // to deliver the onUserLeaving callback to the actual frontmost
         // activity
-        if (addPos < NH) {
-            mUserLeaving = false;
-            if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
+        if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
+            mStackSupervisor.mUserLeaving = false;
+            if (DEBUG_USER_LEAVING) Slog.v(TAG,
+                    "startActivity() behind front, mUserLeaving=false");
         }
-        
+
+        task = r.task;
+
         // Slot the activity into the history stack and proceed
-        if (DEBUG_ADD_REMOVE) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
-        }
-        mHistory.add(addPos, r);
+        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
+                new RuntimeException("here").fillInStackTrace());
+        task.addActivityToTop(r);
+
         r.putInHistory();
         r.frontOfTask = newTask;
-        if (NH > 0) {
+        if (!isHomeStack() || numActivities() > 0) {
             // We want to show the starting preview window if we are
             // switching to a new task, or the next activity's process is
             // not currently running.
@@ -1894,19 +1714,18 @@
             if (DEBUG_TRANSITION) Slog.v(TAG,
                     "Prepare open transition: starting " + r);
             if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-                mService.mWindowManager.prepareAppTransition(
-                        AppTransition.TRANSIT_NONE, keepCurTransition);
+                mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition);
                 mNoAnimActivities.add(r);
             } else {
-                mService.mWindowManager.prepareAppTransition(newTask
+                mWindowManager.prepareAppTransition(newTask
                         ? AppTransition.TRANSIT_TASK_OPEN
                         : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
             r.updateOptionsLocked(options);
-            mService.mWindowManager.addAppToken(
-                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+            mWindowManager.addAppToken(task.mActivities.indexOf(r),
+                    r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -1929,23 +1748,27 @@
                 if (prev != null) {
                     // We don't want to reuse the previous starting preview if:
                     // (1) The current activity is in a different task.
-                    if (prev.task != r.task) prev = null;
+                    if (prev.task != r.task) {
+                        prev = null;
+                    }
                     // (2) The current activity is already displayed.
-                    else if (prev.nowVisible) prev = null;
+                    else if (prev.nowVisible) {
+                        prev = null;
+                    }
                 }
-                mService.mWindowManager.setAppStartingWindow(
+                mWindowManager.setAppStartingWindow(
                         r.appToken, r.packageName, r.theme,
                         mService.compatibilityInfoForPackageLocked(
                                 r.info.applicationInfo), r.nonLocalizedLabel,
-                        r.labelRes, r.icon, r.windowFlags,
+                        r.labelRes, r.icon, r.logo, r.windowFlags,
                         prev != null ? prev.appToken : null, showStartingIcon);
             }
         } else {
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
-            mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
-                    r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+            mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+                    r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
             ActivityOptions.abort(options);
         }
         if (VALIDATE_TOKENS) {
@@ -1953,233 +1776,68 @@
         }
 
         if (doResume) {
-            resumeTopActivityLocked(null);
+            mStackSupervisor.resumeTopActivitiesLocked();
         }
     }
 
     final void validateAppTokensLocked() {
         mValidateAppTokens.clear();
-        mValidateAppTokens.ensureCapacity(mHistory.size());
-        for (int i=0; i<mHistory.size(); i++) {
-            mValidateAppTokens.add(mHistory.get(i).appToken);
+        mValidateAppTokens.ensureCapacity(numActivities());
+        final int numTasks = mTaskHistory.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            if (activities.isEmpty()) {
+                continue;
+            }
+            TaskGroup group = new TaskGroup();
+            group.taskId = task.taskId;
+            mValidateAppTokens.add(group);
+            final int numActivities = activities.size();
+            for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                group.tokens.add(r.appToken);
+            }
         }
-        mService.mWindowManager.validateAppTokens(mValidateAppTokens);
+        mWindowManager.validateAppTokens(mStackId, mValidateAppTokens);
     }
 
     /**
      * Perform a reset of the given task, if needed as part of launching it.
      * Returns the new HistoryRecord at the top of the task.
      */
-    private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
-            ActivityRecord newActivity) {
-        boolean forceReset = (newActivity.info.flags
-                &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
-        if (ACTIVITY_INACTIVE_RESET_TIME > 0
-                && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
-            if ((newActivity.info.flags
-                    &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
-                forceReset = true;
-            }
-        }
-        
-        final TaskRecord task = taskTop.task;
-        
-        // We are going to move through the history list so that we can look
-        // at each activity 'target' with 'below' either the interesting
-        // activity immediately below it in the stack or null.
-        ActivityRecord target = null;
-        int targetI = 0;
-        int taskTopI = -1;
-        int replyChainEnd = -1;
-        int lastReparentPos = -1;
+    /**
+     * Helper method for #resetTaskIfNeededLocked.
+     * We are inside of the task being reset...  we'll either finish this activity, push it out
+     * for another task, or leave it as-is.
+     * @param task The task containing the Activity (taskTop) that might be reset.
+     * @param forceReset
+     * @return An ActivityOptions that needs to be processed.
+     */
+    final ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
         ActivityOptions topOptions = null;
-        boolean canMoveOptions = true;
-        for (int i=mHistory.size()-1; i>=-1; i--) {
-            ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
-            
-            if (below != null && below.finishing) {
-                continue;
-            }
-            // Don't check any lower in the stack if we're crossing a user boundary.
-            if (below != null && below.userId != taskTop.userId) {
-                break;
-            }
-            if (target == null) {
-                target = below;
-                targetI = i;
-                // If we were in the middle of a reply chain before this
-                // task, it doesn't appear like the root of the chain wants
-                // anything interesting, so drop it.
-                replyChainEnd = -1;
-                continue;
-            }
-        
-            final int flags = target.info.flags;
-            
-            final boolean finishOnTaskLaunch =
-                (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
-            final boolean allowTaskReparenting =
-                (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
-            
-            if (target.task == task) {
-                // We are inside of the task being reset...  we'll either
-                // finish this activity, push it out for another task,
-                // or leave it as-is.  We only do this
-                // for activities that are not the root of the task (since
-                // if we finish the root, we may no longer have the task!).
-                if (taskTopI < 0) {
-                    taskTopI = targetI;
-                }
-                if (below != null && below.task == task) {
-                    final boolean clearWhenTaskReset =
-                            (target.intent.getFlags()
-                                    &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
-                    if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
-                        // If this activity is sending a reply to a previous
-                        // activity, we can't do anything with it now until
-                        // we reach the start of the reply chain.
-                        // XXX note that we are assuming the result is always
-                        // to the previous activity, which is almost always
-                        // the case but we really shouldn't count on.
-                        if (replyChainEnd < 0) {
-                            replyChainEnd = targetI;
-                        }
-                    } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
-                            && target.taskAffinity != null
-                            && !target.taskAffinity.equals(task.affinity)) {
-                        // If this activity has an affinity for another
-                        // task, then we need to move it out of here.  We will
-                        // move it as far out of the way as possible, to the
-                        // bottom of the activity stack.  This also keeps it
-                        // correctly ordered with any activities we previously
-                        // moved.
-                        ActivityRecord p = mHistory.get(0);
-                        if (target.taskAffinity != null
-                                && target.taskAffinity.equals(p.task.affinity)) {
-                            // If the activity currently at the bottom has the
-                            // same task affinity as the one we are moving,
-                            // then merge it into the same task.
-                            target.setTask(p.task, p.thumbHolder, false);
-                            if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
-                                    + " out to bottom task " + p.task);
-                        } else {
-                            mService.mCurTask++;
-                            if (mService.mCurTask <= 0) {
-                                mService.mCurTask = 1;
-                            }
-                            target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
-                                    null, false);
-                            target.task.affinityIntent = target.intent;
-                            if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
-                                    + " out to new task " + target.task);
-                        }
-                        mService.mWindowManager.setAppGroupId(target.appToken, task.taskId);
-                        if (replyChainEnd < 0) {
-                            replyChainEnd = targetI;
-                        }
-                        int dstPos = 0;
-                        ThumbnailHolder curThumbHolder = target.thumbHolder;
-                        boolean gotOptions = !canMoveOptions;
-                        for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
-                            p = mHistory.get(srcPos);
-                            if (p.finishing) {
-                                continue;
-                            }
-                            if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
-                                    + " out to target's task " + target.task);
-                            p.setTask(target.task, curThumbHolder, false);
-                            curThumbHolder = p.thumbHolder;
-                            canMoveOptions = false;
-                            if (!gotOptions && topOptions == null) {
-                                topOptions = p.takeOptionsLocked();
-                                if (topOptions != null) {
-                                    gotOptions = true;
-                                }
-                            }
-                            if (DEBUG_ADD_REMOVE) {
-                                RuntimeException here = new RuntimeException("here");
-                                here.fillInStackTrace();
-                                Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
-                                        + dstPos, here);
-                            }
-                            mHistory.remove(srcPos);
-                            mHistory.add(dstPos, p);
-                            mService.mWindowManager.moveAppToken(dstPos, p.appToken);
-                            mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
-                            dstPos++;
-                            if (VALIDATE_TOKENS) {
-                                validateAppTokensLocked();
-                            }
-                            i++;
-                        }
-                        if (taskTop == p) {
-                            taskTop = below;
-                        }
-                        if (taskTopI == replyChainEnd) {
-                            taskTopI = -1;
-                        }
-                        replyChainEnd = -1;
-                    } else if (forceReset || finishOnTaskLaunch
-                            || clearWhenTaskReset) {
-                        // If the activity should just be removed -- either
-                        // because it asks for it, or the task should be
-                        // cleared -- then finish it and anything that is
-                        // part of its reply chain.
-                        if (clearWhenTaskReset) {
-                            // In this case, we want to finish this activity
-                            // and everything above it, so be sneaky and pretend
-                            // like these are all in the reply chain.
-                            replyChainEnd = targetI+1;
-                            while (replyChainEnd < mHistory.size() &&
-                                    (mHistory.get(
-                                                replyChainEnd)).task == task) {
-                                replyChainEnd++;
-                            }
-                            replyChainEnd--;
-                        } else if (replyChainEnd < 0) {
-                            replyChainEnd = targetI;
-                        }
-                        ActivityRecord p = null;
-                        boolean gotOptions = !canMoveOptions;
-                        for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
-                            p = mHistory.get(srcPos);
-                            if (p.finishing) {
-                                continue;
-                            }
-                            canMoveOptions = false;
-                            if (!gotOptions && topOptions == null) {
-                                topOptions = p.takeOptionsLocked();
-                                if (topOptions != null) {
-                                    gotOptions = true;
-                                }
-                            }
-                            if (finishActivityLocked(p, srcPos,
-                                    Activity.RESULT_CANCELED, null, "reset", false)) {
-                                replyChainEnd--;
-                                srcPos--;
-                            }
-                        }
-                        if (taskTop == p) {
-                            taskTop = below;
-                        }
-                        if (taskTopI == replyChainEnd) {
-                            taskTopI = -1;
-                        }
-                        replyChainEnd = -1;
-                    } else {
-                        // If we were in the middle of a chain, well the
-                        // activity that started it all doesn't want anything
-                        // special, so leave it all as-is.
-                        replyChainEnd = -1;
-                    }
-                } else {
-                    // Reached the bottom of the task -- any reply chain
-                    // should be left as-is.
-                    replyChainEnd = -1;
-                }
 
-            } else if (target.resultTo != null && (below == null
-                    || below.task == target.task)) {
+        int replyChainEnd = -1;
+        boolean canMoveOptions = true;
+
+        // We only do this for activities that are not the root of the task (since if we finish
+        // the root, we may no longer have the task!).
+        final ArrayList<ActivityRecord> activities = task.mActivities;
+        final int numActivities = activities.size();
+        for (int i = numActivities - 1; i > 0; --i ) {
+            ActivityRecord target = activities.get(i);
+
+            final int flags = target.info.flags;
+            final boolean finishOnTaskLaunch =
+                    (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
+            final boolean allowTaskReparenting =
+                    (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
+            final boolean clearWhenTaskReset =
+                    (target.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
+
+            if (!finishOnTaskLaunch
+                    && !clearWhenTaskReset
+                    && target.resultTo != null) {
                 // If this activity is sending a reply to a previous
                 // activity, we can't do anything with it now until
                 // we reach the start of the reply chain.
@@ -2187,14 +1845,162 @@
                 // to the previous activity, which is almost always
                 // the case but we really shouldn't count on.
                 if (replyChainEnd < 0) {
-                    replyChainEnd = targetI;
+                    replyChainEnd = i;
+                }
+            } else if (!finishOnTaskLaunch
+                    && !clearWhenTaskReset
+                    && allowTaskReparenting
+                    && target.taskAffinity != null
+                    && !target.taskAffinity.equals(task.affinity)) {
+                // If this activity has an affinity for another
+                // task, then we need to move it out of here.  We will
+                // move it as far out of the way as possible, to the
+                // bottom of the activity stack.  This also keeps it
+                // correctly ordered with any activities we previously
+                // moved.
+                final ActivityRecord bottom =
+                        !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+                        mTaskHistory.get(0).mActivities.get(0) : null;
+                if (bottom != null && target.taskAffinity != null
+                        && target.taskAffinity.equals(bottom.task.affinity)) {
+                    // If the activity currently at the bottom has the
+                    // same task affinity as the one we are moving,
+                    // then merge it into the same task.
+                    target.setTask(bottom.task, bottom.thumbHolder, false);
+                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                            + " out to bottom task " + bottom.task);
+                } else {
+                    target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
+                            null, false), null, false);
+                    target.task.affinityIntent = target.intent;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                            + " out to new task " + target.task);
                 }
 
-            } else if (taskTopI >= 0 && allowTaskReparenting
-                    && task.affinity != null
-                    && task.affinity.equals(target.taskAffinity)) {
-                // We are inside of another task...  if this activity has
-                // an affinity for our task, then either remove it if we are
+                final TaskRecord targetTask = target.task;
+                final int targetTaskId = targetTask.taskId;
+                mWindowManager.setAppGroupId(target.appToken, targetTaskId);
+
+                boolean noOptions = canMoveOptions;
+                final int start = replyChainEnd < 0 ? i : replyChainEnd;
+                for (int srcPos = start; srcPos >= i; --srcPos) {
+                    final ActivityRecord p = activities.get(srcPos);
+                    if (p.finishing) {
+                        continue;
+                    }
+
+                    ThumbnailHolder curThumbHolder = p.thumbHolder;
+                    canMoveOptions = false;
+                    if (noOptions && topOptions == null) {
+                        topOptions = p.takeOptionsLocked();
+                        if (topOptions != null) {
+                            noOptions = false;
+                        }
+                    }
+                    if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
+                            + task + " adding to task=" + targetTask,
+                            new RuntimeException("here").fillInStackTrace());
+                    if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
+                            + " out to target's task " + target.task);
+                    p.setTask(targetTask, curThumbHolder, false);
+                    targetTask.addActivityAtBottom(p);
+
+                    mWindowManager.setAppGroupId(p.appToken, targetTaskId);
+                }
+
+                mWindowManager.moveTaskToBottom(targetTaskId);
+                if (VALIDATE_TOKENS) {
+                    validateAppTokensLocked();
+                }
+
+                replyChainEnd = -1;
+            } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
+                // If the activity should just be removed -- either
+                // because it asks for it, or the task should be
+                // cleared -- then finish it and anything that is
+                // part of its reply chain.
+                int end;
+                if (clearWhenTaskReset) {
+                    // In this case, we want to finish this activity
+                    // and everything above it, so be sneaky and pretend
+                    // like these are all in the reply chain.
+                    end = numActivities - 1;
+                } else if (replyChainEnd < 0) {
+                    end = i;
+                } else {
+                    end = replyChainEnd;
+                }
+                boolean noOptions = canMoveOptions;
+                for (int srcPos = i; srcPos <= end; srcPos++) {
+                    ActivityRecord p = activities.get(srcPos);
+                    if (p.finishing) {
+                        continue;
+                    }
+                    canMoveOptions = false;
+                    if (noOptions && topOptions == null) {
+                        topOptions = p.takeOptionsLocked();
+                        if (topOptions != null) {
+                            noOptions = false;
+                        }
+                    }
+                    if (DEBUG_TASKS) Slog.w(TAG,
+                            "resetTaskIntendedTask: calling finishActivity on " + p);
+                    if (finishActivityLocked(p, Activity.RESULT_CANCELED, null, "reset", false)) {
+                        end--;
+                        srcPos--;
+                    }
+                }
+                replyChainEnd = -1;
+            } else {
+                // If we were in the middle of a chain, well the
+                // activity that started it all doesn't want anything
+                // special, so leave it all as-is.
+                replyChainEnd = -1;
+            }
+        }
+
+        return topOptions;
+    }
+
+    /**
+     * Helper method for #resetTaskIfNeededLocked. Processes all of the activities in a given
+     * TaskRecord looking for an affinity with the task of resetTaskIfNeededLocked.taskTop.
+     * @param affinityTask The task we are looking for an affinity to.
+     * @param task Task that resetTaskIfNeededLocked.taskTop belongs to.
+     * @param topTaskIsHigher True if #task has already been processed by resetTaskIfNeededLocked.
+     * @param forceReset Flag passed in to resetTaskIfNeededLocked.
+     */
+    private int resetAffinityTaskIfNeededLocked(TaskRecord affinityTask, TaskRecord task,
+            boolean topTaskIsHigher, boolean forceReset, int taskInsertionPoint) {
+        int replyChainEnd = -1;
+        final int taskId = task.taskId;
+        final String taskAffinity = task.affinity;
+
+        final ArrayList<ActivityRecord> activities = affinityTask.mActivities;
+        final int numActivities = activities.size();
+        // Do not operate on the root Activity.
+        for (int i = numActivities - 1; i > 0; --i) {
+            ActivityRecord target = activities.get(i);
+
+            final int flags = target.info.flags;
+            boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
+            boolean allowTaskReparenting = (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
+
+            if (target.resultTo != null) {
+                // If this activity is sending a reply to a previous
+                // activity, we can't do anything with it now until
+                // we reach the start of the reply chain.
+                // XXX note that we are assuming the result is always
+                // to the previous activity, which is almost always
+                // the case but we really shouldn't count on.
+                if (replyChainEnd < 0) {
+                    replyChainEnd = i;
+                }
+            } else if (topTaskIsHigher
+                    && allowTaskReparenting
+                    && taskAffinity != null
+                    && taskAffinity.equals(target.taskAffinity)) {
+                // This activity has an affinity for our task. Either remove it if we are
                 // clearing or move it over to our task.  Note that
                 // we currently punt on the case where we are resetting a
                 // task that is not at the top but who has activities above
@@ -2205,93 +2011,103 @@
                 // someone starts an activity in a new task from an activity
                 // in a task that is not currently on top.)
                 if (forceReset || finishOnTaskLaunch) {
-                    if (replyChainEnd < 0) {
-                        replyChainEnd = targetI;
-                    }
-                    ActivityRecord p = null;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index "
-                            + targetI + " to " + replyChainEnd);
-                    for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
-                        p = mHistory.get(srcPos);
+                    final int start = replyChainEnd >= 0 ? replyChainEnd : i;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index " + start + " to " + i);
+                    for (int srcPos = start; srcPos >= i; --srcPos) {
+                        final ActivityRecord p = activities.get(srcPos);
                         if (p.finishing) {
                             continue;
                         }
-                        if (finishActivityLocked(p, srcPos,
-                                Activity.RESULT_CANCELED, null, "reset", false)) {
-                            taskTopI--;
-                            lastReparentPos--;
-                            replyChainEnd--;
-                            srcPos--;
-                        }
+                        finishActivityLocked(p, Activity.RESULT_CANCELED, null, "reset", false);
                     }
-                    replyChainEnd = -1;
                 } else {
-                    if (replyChainEnd < 0) {
-                        replyChainEnd = targetI;
+                    if (taskInsertionPoint < 0) {
+                        taskInsertionPoint = task.mActivities.size();
+
                     }
-                    if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index "
-                            + targetI + " to " + replyChainEnd);
-                    for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
-                        ActivityRecord p = mHistory.get(srcPos);
-                        if (p.finishing) {
-                            continue;
-                        }
-                        if (lastReparentPos < 0) {
-                            lastReparentPos = taskTopI;
-                            taskTop = p;
-                        } else {
-                            lastReparentPos--;
-                        }
-                        if (DEBUG_ADD_REMOVE) {
-                            RuntimeException here = new RuntimeException("here");
-                            here.fillInStackTrace();
-                            Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
-                                    + lastReparentPos, here);
-                        }
-                        mHistory.remove(srcPos);
+
+                    final int start = replyChainEnd >= 0 ? replyChainEnd : i;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Reparenting from task=" + affinityTask + ":"
+                            + start + "-" + i + " to task=" + task + ":" + taskInsertionPoint);
+                    for (int srcPos = start; srcPos >= i; --srcPos) {
+                        final ActivityRecord p = activities.get(srcPos);
                         p.setTask(task, null, false);
-                        mHistory.add(lastReparentPos, p);
-                        if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
-                                + " from " + srcPos + " to " + lastReparentPos
+                        task.addActivityAtIndex(taskInsertionPoint, p);
+
+                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p
+                                + " to stack at " + task,
+                                new RuntimeException("here").fillInStackTrace());
+                        if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " from " + srcPos
                                 + " in to resetting task " + task);
-                        mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
-                        mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
-                        if (VALIDATE_TOKENS) {
-                            validateAppTokensLocked();
-                        }
+                        mWindowManager.setAppGroupId(p.appToken, taskId);
                     }
-                    replyChainEnd = -1;
-                    
+                    mWindowManager.moveTaskToTop(taskId);
+                    if (VALIDATE_TOKENS) {
+                        validateAppTokensLocked();
+                    }
+
                     // Now we've moved it in to place...  but what if this is
                     // a singleTop activity and we have put it on top of another
                     // instance of the same activity?  Then we drop the instance
                     // below so it remains singleTop.
                     if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
-                        for (int j=lastReparentPos-1; j>=0; j--) {
-                            ActivityRecord p = mHistory.get(j);
-                            if (p.finishing) {
-                                continue;
-                            }
+                        ArrayList<ActivityRecord> taskActivities = task.mActivities;
+                        int targetNdx = taskActivities.indexOf(target);
+                        if (targetNdx > 0) {
+                            ActivityRecord p = taskActivities.get(targetNdx - 1);
                             if (p.intent.getComponent().equals(target.intent.getComponent())) {
-                                if (finishActivityLocked(p, j,
-                                        Activity.RESULT_CANCELED, null, "replace", false)) {
-                                    taskTopI--;
-                                    lastReparentPos--;
-                                }
+                                finishActivityLocked(p, Activity.RESULT_CANCELED, null, "replace",
+                                        false);
                             }
                         }
                     }
                 }
 
-            } else if (below != null && below.task != target.task) {
-                // We hit the botton of a task; the reply chain can't
-                // pass through it.
                 replyChainEnd = -1;
             }
-            
-            target = below;
-            targetI = i;
         }
+        return taskInsertionPoint;
+    }
+
+    final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
+            ActivityRecord newActivity) {
+        boolean forceReset =
+                (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
+        if (ACTIVITY_INACTIVE_RESET_TIME > 0
+                && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
+            if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
+                forceReset = true;
+            }
+        }
+
+        final TaskRecord task = taskTop.task;
+
+        /** False until we evaluate the TaskRecord associated with taskTop. Switches to true
+         * for remaining tasks. Used for later tasks to reparent to task. */
+        boolean taskFound = false;
+
+        /** If ActivityOptions are moved out and need to be aborted or moved to taskTop. */
+        ActivityOptions topOptions = null;
+
+        // Preserve the location for reparenting in the new task.
+        int reparentInsertionPoint = -1;
+
+        for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
+            final TaskRecord targetTask = mTaskHistory.get(i);
+
+            if (targetTask == task) {
+                topOptions = resetTargetTaskIfNeededLocked(task, forceReset);
+                taskFound = true;
+            } else {
+                reparentInsertionPoint = resetAffinityTaskIfNeededLocked(targetTask, task,
+                        taskFound, forceReset, reparentInsertionPoint);
+            }
+        }
+
+        int taskNdx = mTaskHistory.indexOf(task);
+        do {
+            taskTop = mTaskHistory.get(taskNdx--).getTopActivity();
+        } while (taskTop == null && taskNdx >= 0);
 
         if (topOptions != null) {
             // If we got some ActivityOptions from an activity on top that
@@ -2305,1068 +2121,6 @@
 
         return taskTop;
     }
-    
-    /**
-     * Perform clear operation as requested by
-     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
-     * stack to the given task, then look for
-     * an instance of that activity in the stack and, if found, finish all
-     * activities on top of it and return the instance.
-     *
-     * @param newR Description of the new activity being started.
-     * @return Returns the old activity that should be continued to be used,
-     * or null if none was found.
-     */
-    private final ActivityRecord performClearTaskLocked(int taskId,
-            ActivityRecord newR, int launchFlags) {
-        int i = mHistory.size();
-        
-        // First find the requested task.
-        while (i > 0) {
-            i--;
-            ActivityRecord r = mHistory.get(i);
-            if (r.task.taskId == taskId) {
-                i++;
-                break;
-            }
-        }
-        
-        // Now clear it.
-        while (i > 0) {
-            i--;
-            ActivityRecord r = mHistory.get(i);
-            if (r.finishing) {
-                continue;
-            }
-            if (r.task.taskId != taskId) {
-                return null;
-            }
-            if (r.realActivity.equals(newR.realActivity)) {
-                // Here it is!  Now finish everything in front...
-                ActivityRecord ret = r;
-                while (i < (mHistory.size()-1)) {
-                    i++;
-                    r = mHistory.get(i);
-                    if (r.task.taskId != taskId) {
-                        break;
-                    }
-                    if (r.finishing) {
-                        continue;
-                    }
-                    ActivityOptions opts = r.takeOptionsLocked();
-                    if (opts != null) {
-                        ret.updateOptionsLocked(opts);
-                    }
-                    if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "clear", false)) {
-                        i--;
-                    }
-                }
-                
-                // Finally, if this is a normal launch mode (that is, not
-                // expecting onNewIntent()), then we will finish the current
-                // instance of the activity so a new fresh one can be started.
-                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
-                        && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
-                    if (!ret.finishing) {
-                        int index = indexOfTokenLocked(ret.appToken);
-                        if (index >= 0) {
-                            finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
-                                    null, "clear", false);
-                        }
-                        return null;
-                    }
-                }
-                
-                return ret;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Completely remove all activities associated with an existing
-     * task starting at a specified index.
-     */
-    private final void performClearTaskAtIndexLocked(int taskId, int i) {
-        while (i < mHistory.size()) {
-            ActivityRecord r = mHistory.get(i);
-            if (r.task.taskId != taskId) {
-                // Whoops hit the end.
-                return;
-            }
-            if (r.finishing) {
-                i++;
-                continue;
-            }
-            if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                    null, "clear", false)) {
-                i++;
-            }
-        }
-    }
-
-    /**
-     * Completely remove all activities associated with an existing task.
-     */
-    private final void performClearTaskLocked(int taskId) {
-        int i = mHistory.size();
-
-        // First find the requested task.
-        while (i > 0) {
-            i--;
-            ActivityRecord r = mHistory.get(i);
-            if (r.task.taskId == taskId) {
-                i++;
-                break;
-            }
-        }
-
-        // Now find the start and clear it.
-        while (i > 0) {
-            i--;
-            ActivityRecord r = mHistory.get(i);
-            if (r.finishing) {
-                continue;
-            }
-            if (r.task.taskId != taskId) {
-                // We hit the bottom.  Now finish it all...
-                performClearTaskAtIndexLocked(taskId, i+1);
-                return;
-            }
-        }
-    }
-
-    /**
-     * Find the activity in the history stack within the given task.  Returns
-     * the index within the history at which it's found, or < 0 if not found.
-     */
-    private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
-        int i = mHistory.size();
-        while (i > 0) {
-            i--;
-            ActivityRecord candidate = mHistory.get(i);
-            if (candidate.finishing) {
-                continue;
-            }
-            if (candidate.task.taskId != task) {
-                break;
-            }
-            if (candidate.realActivity.equals(r.realActivity)) {
-                return i;
-            }
-        }
-
-        return -1;
-    }
-
-    /**
-     * Reorder the history stack so that the activity at the given index is
-     * brought to the front.
-     */
-    private final ActivityRecord moveActivityToFrontLocked(int where) {
-        ActivityRecord newTop = mHistory.remove(where);
-        int top = mHistory.size();
-        ActivityRecord oldTop = mHistory.get(top-1);
-        if (DEBUG_ADD_REMOVE) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.i(TAG, "Removing and adding activity " + newTop + " to stack at "
-                    + top, here);
-        }
-        mHistory.add(top, newTop);
-        oldTop.frontOfTask = false;
-        newTop.frontOfTask = true;
-        return newTop;
-    }
-
-    final int startActivityLocked(IApplicationThread caller,
-            Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
-            String resultWho, int requestCode,
-            int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
-            boolean componentSpecified, ActivityRecord[] outActivity) {
-
-        int err = ActivityManager.START_SUCCESS;
-
-        ProcessRecord callerApp = null;
-
-        if (caller != null) {
-            callerApp = mService.getRecordForAppLocked(caller);
-            if (callerApp != null) {
-                callingPid = callerApp.pid;
-                callingUid = callerApp.info.uid;
-            } else {
-                Slog.w(TAG, "Unable to find app for caller " + caller
-                      + " (pid=" + callingPid + ") when starting: "
-                      + intent.toString());
-                err = ActivityManager.START_PERMISSION_DENIED;
-            }
-        }
-
-        if (err == ActivityManager.START_SUCCESS) {
-            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
-            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
-                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
-        }
-
-        ActivityRecord sourceRecord = null;
-        ActivityRecord resultRecord = null;
-        if (resultTo != null) {
-            int index = indexOfTokenLocked(resultTo);
-            if (DEBUG_RESULTS) Slog.v(
-                TAG, "Will send result to " + resultTo + " (index " + index + ")");
-            if (index >= 0) {
-                sourceRecord = mHistory.get(index);
-                if (requestCode >= 0 && !sourceRecord.finishing) {
-                    resultRecord = sourceRecord;
-                }
-            }
-        }
-
-        int launchFlags = intent.getFlags();
-
-        if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
-                && sourceRecord != null) {
-            // Transfer the result target from the source activity to the new
-            // one being started, including any failures.
-            if (requestCode >= 0) {
-                ActivityOptions.abort(options);
-                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
-            }
-            resultRecord = sourceRecord.resultTo;
-            resultWho = sourceRecord.resultWho;
-            requestCode = sourceRecord.requestCode;
-            sourceRecord.resultTo = null;
-            if (resultRecord != null) {
-                resultRecord.removeResultsLocked(
-                    sourceRecord, resultWho, requestCode);
-            }
-        }
-
-        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
-            // We couldn't find a class that can handle the given Intent.
-            // That's the end of that!
-            err = ActivityManager.START_INTENT_NOT_RESOLVED;
-        }
-
-        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
-            // We couldn't find the specific class specified in the Intent.
-            // Also the end of the line.
-            err = ActivityManager.START_CLASS_NOT_FOUND;
-        }
-
-        if (err != ActivityManager.START_SUCCESS) {
-            if (resultRecord != null) {
-                sendActivityResultLocked(-1,
-                    resultRecord, resultWho, requestCode,
-                    Activity.RESULT_CANCELED, null);
-            }
-            mDismissKeyguardOnNextActivity = false;
-            ActivityOptions.abort(options);
-            return err;
-        }
-
-        final int startAnyPerm = mService.checkPermission(
-                START_ANY_ACTIVITY, callingPid, callingUid);
-        final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
-                callingUid, aInfo.applicationInfo.uid, aInfo.exported);
-        if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {
-            if (resultRecord != null) {
-                sendActivityResultLocked(-1,
-                    resultRecord, resultWho, requestCode,
-                    Activity.RESULT_CANCELED, null);
-            }
-            mDismissKeyguardOnNextActivity = false;
-            String msg;
-            if (!aInfo.exported) {
-                msg = "Permission Denial: starting " + intent.toString()
-                        + " from " + callerApp + " (pid=" + callingPid
-                        + ", uid=" + callingUid + ")"
-                        + " not exported from uid " + aInfo.applicationInfo.uid;
-            } else {
-                msg = "Permission Denial: starting " + intent.toString()
-                        + " from " + callerApp + " (pid=" + callingPid
-                        + ", uid=" + callingUid + ")"
-                        + " requires " + aInfo.permission;
-            }
-            Slog.w(TAG, msg);
-            throw new SecurityException(msg);
-        }
-
-        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent,
-                callerApp==null?null:callerApp.info, callingUid, callingPid, resolvedType, aInfo);
-
-        if (mMainStack) {
-            if (mService.mController != null) {
-                try {
-                    // The Intent we give to the watcher has the extra data
-                    // stripped off, since it can contain private information.
-                    Intent watchIntent = intent.cloneFilter();
-                    abort |= !mService.mController.activityStarting(watchIntent,
-                            aInfo.applicationInfo.packageName);
-                } catch (RemoteException e) {
-                    mService.mController = null;
-                }
-            }
-        }
-
-        if (abort) {
-            if (resultRecord != null) {
-                sendActivityResultLocked(-1,
-                    resultRecord, resultWho, requestCode,
-                    Activity.RESULT_CANCELED, null);
-            }
-            // We pretend to the caller that it was really started, but
-            // they will just get a cancel result.
-            mDismissKeyguardOnNextActivity = false;
-            ActivityOptions.abort(options);
-            return ActivityManager.START_SUCCESS;
-        }
-
-        ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid, callingPackage,
-                intent, resolvedType, aInfo, mService.mConfiguration,
-                resultRecord, resultWho, requestCode, componentSpecified);
-        if (outActivity != null) {
-            outActivity[0] = r;
-        }
-
-        if (mMainStack) {
-            if (mResumedActivity == null
-                    || mResumedActivity.info.applicationInfo.uid != callingUid) {
-                if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
-                    PendingActivityLaunch pal = new PendingActivityLaunch();
-                    pal.r = r;
-                    pal.sourceRecord = sourceRecord;
-                    pal.startFlags = startFlags;
-                    mService.mPendingActivityLaunches.add(pal);
-                    mDismissKeyguardOnNextActivity = false;
-                    ActivityOptions.abort(options);
-                    return ActivityManager.START_SWITCHES_CANCELED;
-                }
-            }
-        
-            if (mService.mDidAppSwitch) {
-                // This is the second allowed switch since we stopped switches,
-                // so now just generally allow switches.  Use case: user presses
-                // home (switches disabled, switch to home, mDidAppSwitch now true);
-                // user taps a home icon (coming from home so allowed, we hit here
-                // and now allow anyone to switch again).
-                mService.mAppSwitchesAllowedTime = 0;
-            } else {
-                mService.mDidAppSwitch = true;
-            }
-         
-            mService.doPendingActivityLaunchesLocked(false);
-        }
-        
-        err = startActivityUncheckedLocked(r, sourceRecord,
-                startFlags, true, options);
-        if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
-            // Someone asked to have the keyguard dismissed on the next
-            // activity start, but we are not actually doing an activity
-            // switch...  just dismiss the keyguard now, because we
-            // probably want to see whatever is behind it.
-            mDismissKeyguardOnNextActivity = false;
-            mService.mWindowManager.dismissKeyguard();
-        }
-        return err;
-    }
-  
-    final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
-        if ((launchFlags &
-                (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
-                == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
-            // Caller wants to appear on home activity, so before starting
-            // their own activity we will bring home to the front.
-            moveHomeToFrontLocked();
-        }
-    }
-
-    final int startActivityUncheckedLocked(ActivityRecord r,
-            ActivityRecord sourceRecord, int startFlags, boolean doResume,
-            Bundle options) {
-        final Intent intent = r.intent;
-        final int callingUid = r.launchedFromUid;
-
-        int launchFlags = intent.getFlags();
-        
-        // 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;
-        if (DEBUG_USER_LEAVING) Slog.v(TAG,
-                "startActivity() => mUserLeaving=" + mUserLeaving);
-        
-        // If the caller has asked not to resume at this point, we make note
-        // of this in the record so that we can skip it when trying to find
-        // the top running activity.
-        if (!doResume) {
-            r.delayedResume = true;
-        }
-        
-        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
-                != 0 ? r : null;
-
-        // If the onlyIfNeeded flag is set, then we can do this if the activity
-        // being launched is the same as the one making the call...  or, as
-        // a special case, if we do not know the caller then we count the
-        // current top activity as the caller.
-        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-            ActivityRecord checkedCaller = sourceRecord;
-            if (checkedCaller == null) {
-                checkedCaller = topRunningNonDelayedActivityLocked(notTop);
-            }
-            if (!checkedCaller.realActivity.equals(r.realActivity)) {
-                // Caller is not the same as launcher, so always needed.
-                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
-            }
-        }
-
-        if (sourceRecord == null) {
-            // This activity is not being started from another...  in this
-            // case we -always- start a new task.
-            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
-                Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
-                      + intent);
-                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
-            }
-        } 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
-            // own task.
-            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
-        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
-                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
-            // The activity being started is a single instance...  it always
-            // gets launched into its own task.
-            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
-        }
-
-        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.");
-            sendActivityResultLocked(-1,
-                    r.resultTo, r.resultWho, r.requestCode,
-                Activity.RESULT_CANCELED, null);
-            r.resultTo = null;
-        }
-
-        boolean addingToTask = false;
-        boolean movedHome = false;
-        TaskRecord reuseTask = null;
-        if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
-                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
-                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-            // If bring to front is requested, and no result is requested, and
-            // we can find a task that was started with this same
-            // component, then instead of launching bring that one to the front.
-            if (r.resultTo == null) {
-                // See if there is a task to bring to the front.  If this is
-                // a SINGLE_INSTANCE activity, there can be one and only one
-                // instance of it in the history, and it is always in its own
-                // unique task, so we do a special search.
-                ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
-                        ? findTaskLocked(intent, r.info)
-                        : findActivityLocked(intent, r.info);
-                if (taskTop != null) {
-                    if (taskTop.task.intent == null) {
-                        // This task was started because of movement of
-                        // the activity based on affinity...  now that we
-                        // are actually launching it, we can assign the
-                        // base intent.
-                        taskTop.task.setIntent(intent, r.info);
-                    }
-                    // If the target task is not in the front, then we need
-                    // to bring it to the front...  except...  well, with
-                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
-                    // to have the same behavior as if a new instance was
-                    // being started, which means not bringing it to the front
-                    // if the caller is not itself in the front.
-                    ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
-                    if (curTop != null && curTop.task != taskTop.task) {
-                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-                        boolean callerAtFront = sourceRecord == null
-                                || curTop.task == sourceRecord.task;
-                        if (callerAtFront) {
-                            // We really do want to push this one into the
-                            // user's face, right now.
-                            movedHome = true;
-                            moveHomeToFrontFromLaunchLocked(launchFlags);
-                            moveTaskToFrontLocked(taskTop.task, r, options);
-                            options = null;
-                        }
-                    }
-                    // If the caller has requested that the target task be
-                    // reset, then do so.
-                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
-                        taskTop = resetTaskIfNeededLocked(taskTop, r);
-                    }
-                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)  != 0) {
-                        // We don't need to start a new activity, and
-                        // the client said not to do anything if that
-                        // is the case, so this is it!  And for paranoia, make
-                        // sure we have correctly resumed the top activity.
-                        if (doResume) {
-                            resumeTopActivityLocked(null, options);
-                        } else {
-                            ActivityOptions.abort(options);
-                        }
-                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                    }
-                    if ((launchFlags &
-                            (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
-                            == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
-                        // The caller has requested to completely replace any
-                        // existing task with its new activity.  Well that should
-                        // not be too hard...
-                        reuseTask = taskTop.task;
-                        performClearTaskLocked(taskTop.task.taskId);
-                        reuseTask.setIntent(r.intent, r.info);
-                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
-                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
-                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                        // In this situation we want to remove all activities
-                        // from the task up to the one being started.  In most
-                        // cases this means we are resetting the task to its
-                        // initial state.
-                        ActivityRecord top = performClearTaskLocked(
-                                taskTop.task.taskId, r, launchFlags);
-                        if (top != null) {
-                            if (top.frontOfTask) {
-                                // Activity aliases may mean we use different
-                                // intents for the top activity, so make sure
-                                // the task now has the identity of the new
-                                // intent.
-                                top.task.setIntent(r.intent, r.info);
-                            }
-                            logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                            top.deliverNewIntentLocked(callingUid, r.intent);
-                        } else {
-                            // A special case: we need to
-                            // start the activity because it is not currently
-                            // running, and the caller has asked to clear the
-                            // current task to have this activity at the top.
-                            addingToTask = true;
-                            // Now pretend like this activity is being started
-                            // by the top of its task, so it is put in the
-                            // right place.
-                            sourceRecord = taskTop;
-                        }
-                    } else if (r.realActivity.equals(taskTop.task.realActivity)) {
-                        // In this case the top activity on the task is the
-                        // same as the one being launched, so we take that
-                        // as a request to bring the task to the foreground.
-                        // If the top activity in the task is the root
-                        // activity, deliver this new intent to it if it
-                        // desires.
-                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
-                                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
-                                && taskTop.realActivity.equals(r.realActivity)) {
-                            logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
-                            if (taskTop.frontOfTask) {
-                                taskTop.task.setIntent(r.intent, r.info);
-                            }
-                            taskTop.deliverNewIntentLocked(callingUid, r.intent);
-                        } else if (!r.intent.filterEquals(taskTop.task.intent)) {
-                            // In this case we are launching the root activity
-                            // of the task, but with a different intent.  We
-                            // should start a new instance on top.
-                            addingToTask = true;
-                            sourceRecord = taskTop;
-                        }
-                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
-                        // In this case an activity is being launched in to an
-                        // existing task, without resetting that task.  This
-                        // is typically the situation of launching an activity
-                        // from a notification or shortcut.  We want to place
-                        // the new activity on top of the current task.
-                        addingToTask = true;
-                        sourceRecord = taskTop;
-                    } else if (!taskTop.task.rootWasReset) {
-                        // In this case we are launching in to an existing task
-                        // that has not yet been started from its front door.
-                        // The current task has been brought to the front.
-                        // Ideally, we'd probably like to place this new task
-                        // at the bottom of its stack, but that's a little hard
-                        // to do with the current organization of the code so
-                        // for now we'll just drop it.
-                        taskTop.task.setIntent(r.intent, r.info);
-                    }
-                    if (!addingToTask && reuseTask == null) {
-                        // We didn't do anything...  but it was needed (a.k.a., client
-                        // don't use that intent!)  And for paranoia, make
-                        // sure we have correctly resumed the top activity.
-                        if (doResume) {
-                            resumeTopActivityLocked(null, options);
-                        } else {
-                            ActivityOptions.abort(options);
-                        }
-                        return ActivityManager.START_TASK_TO_FRONT;
-                    }
-                }
-            }
-        }
-
-        //String uri = r.intent.toURI();
-        //Intent intent2 = new Intent(uri);
-        //Slog.i(TAG, "Given intent: " + r.intent);
-        //Slog.i(TAG, "URI is: " + uri);
-        //Slog.i(TAG, "To intent: " + intent2);
-
-        if (r.packageName != null) {
-            // If the activity being launched is the same as the one currently
-            // at the top, then we need to check if it should only be launched
-            // once.
-            ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
-            if (top != null && r.resultTo == null) {
-                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
-                    if (top.app != null && top.app.thread != null) {
-                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
-                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
-                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
-                            logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
-                            // For paranoia, make sure we have correctly
-                            // resumed the top activity.
-                            if (doResume) {
-                                resumeTopActivityLocked(null);
-                            }
-                            ActivityOptions.abort(options);
-                            if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                                // We don't need to start a new activity, and
-                                // the client said not to do anything if that
-                                // is the case, so this is it!
-                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                            }
-                            top.deliverNewIntentLocked(callingUid, r.intent);
-                            return ActivityManager.START_DELIVERED_TO_TOP;
-                        }
-                    }
-                }
-            }
-
-        } else {
-            if (r.resultTo != null) {
-                sendActivityResultLocked(-1,
-                        r.resultTo, r.resultWho, r.requestCode,
-                    Activity.RESULT_CANCELED, null);
-            }
-            ActivityOptions.abort(options);
-            return ActivityManager.START_CLASS_NOT_FOUND;
-        }
-
-        boolean newTask = false;
-        boolean keepCurTransition = false;
-
-        // Should this be considered a new task?
-        if (r.resultTo == null && !addingToTask
-                && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
-            if (reuseTask == null) {
-                // todo: should do better management of integers.
-                mService.mCurTask++;
-                if (mService.mCurTask <= 0) {
-                    mService.mCurTask = 1;
-                }
-                r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
-                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
-                        + " in new task " + r.task);
-            } else {
-                r.setTask(reuseTask, reuseTask, true);
-            }
-            newTask = true;
-            if (!movedHome) {
-                moveHomeToFrontFromLaunchLocked(launchFlags);
-            }
-            
-        } else if (sourceRecord != null) {
-            if (!addingToTask &&
-                    (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                // In this case, we are adding the activity to an existing
-                // task, but the caller has asked to clear that task if the
-                // activity is already running.
-                ActivityRecord top = performClearTaskLocked(
-                        sourceRecord.task.taskId, r, launchFlags);
-                keepCurTransition = true;
-                if (top != null) {
-                    logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(callingUid, r.intent);
-                    // For paranoia, make sure we have correctly
-                    // resumed the top activity.
-                    if (doResume) {
-                        resumeTopActivityLocked(null);
-                    }
-                    ActivityOptions.abort(options);
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            } else if (!addingToTask &&
-                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
-                // In this case, we are launching an activity in our own task
-                // that may already be running somewhere in the history, and
-                // we want to shuffle it to the front of the stack if so.
-                int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
-                if (where >= 0) {
-                    ActivityRecord top = moveActivityToFrontLocked(where);
-                    logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.updateOptionsLocked(options);
-                    top.deliverNewIntentLocked(callingUid, r.intent);
-                    if (doResume) {
-                        resumeTopActivityLocked(null);
-                    }
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            }
-            // An existing activity is starting this new activity, so we want
-            // to keep the new one in the same task as the one that is starting
-            // it.
-            r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
-                    + " in existing task " + r.task);
-
-        } else {
-            // This not being started from an existing activity, and not part
-            // of a new task...  just put it in the top task, though these days
-            // this case should never happen.
-            final int N = mHistory.size();
-            ActivityRecord prev =
-                N > 0 ? mHistory.get(N-1) : null;
-            r.setTask(prev != null
-                    ? prev.task
-                    : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
-                    + " in new guessed " + r.task);
-        }
-
-        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
-                intent, r.getUriPermissionsLocked());
-
-        if (newTask) {
-            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
-        }
-        logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
-        startActivityLocked(r, newTask, doResume, keepCurTransition, options);
-        return ActivityManager.START_SUCCESS;
-    }
-
-    ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
-            String profileFile, ParcelFileDescriptor profileFd, int userId) {
-        // Collect information about the target of the Intent.
-        ActivityInfo aInfo;
-        try {
-            ResolveInfo rInfo =
-                AppGlobals.getPackageManager().resolveIntent(
-                        intent, resolvedType,
-                        PackageManager.MATCH_DEFAULT_ONLY
-                                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
-            aInfo = rInfo != null ? rInfo.activityInfo : null;
-        } catch (RemoteException e) {
-            aInfo = null;
-        }
-
-        if (aInfo != null) {
-            // Store the found target back into the intent, because now that
-            // we have it we never want to do this again.  For example, if the
-            // user navigates back to this point in the history, we should
-            // always restart the exact same activity.
-            intent.setComponent(new ComponentName(
-                    aInfo.applicationInfo.packageName, aInfo.name));
-
-            // Don't debug things in the system process
-            if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) {
-                if (!aInfo.processName.equals("system")) {
-                    mService.setDebugApp(aInfo.processName, true, false);
-                }
-            }
-
-            if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) {
-                if (!aInfo.processName.equals("system")) {
-                    mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
-                }
-            }
-
-            if (profileFile != null) {
-                if (!aInfo.processName.equals("system")) {
-                    mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
-                            profileFile, profileFd,
-                            (startFlags&ActivityManager.START_FLAG_AUTO_STOP_PROFILER) != 0);
-                }
-            }
-        }
-        return aInfo;
-    }
-
-    final int startActivityMayWait(IApplicationThread caller, int callingUid,
-            String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags, String profileFile,
-            ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
-            Bundle options, int userId) {
-        // Refuse possible leaked file descriptors
-        if (intent != null && intent.hasFileDescriptors()) {
-            throw new IllegalArgumentException("File descriptors passed in Intent");
-        }
-        boolean componentSpecified = intent.getComponent() != null;
-
-        // Don't modify the client's object!
-        intent = new Intent(intent);
-
-        // Collect information about the target of the Intent.
-        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
-                profileFile, profileFd, userId);
-
-        synchronized (mService) {
-            int callingPid;
-            if (callingUid >= 0) {
-                callingPid = -1;
-            } else if (caller == null) {
-                callingPid = Binder.getCallingPid();
-                callingUid = Binder.getCallingUid();
-            } else {
-                callingPid = callingUid = -1;
-            }
-            
-            mConfigWillChange = config != null
-                    && mService.mConfiguration.diff(config) != 0;
-            if (DEBUG_CONFIGURATION) Slog.v(TAG,
-                    "Starting activity when config will change = " + mConfigWillChange);
-            
-            final long origId = Binder.clearCallingIdentity();
-            
-            if (mMainStack && aInfo != null &&
-                    (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
-                // This may be a heavy-weight process!  Check to see if we already
-                // have another, different heavy-weight process running.
-                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
-                    if (mService.mHeavyWeightProcess != null &&
-                            (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
-                            !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
-                        int realCallingPid = callingPid;
-                        int realCallingUid = callingUid;
-                        if (caller != null) {
-                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
-                            if (callerApp != null) {
-                                realCallingPid = callerApp.pid;
-                                realCallingUid = callerApp.info.uid;
-                            } else {
-                                Slog.w(TAG, "Unable to find app for caller " + caller
-                                      + " (pid=" + realCallingPid + ") when starting: "
-                                      + intent.toString());
-                                ActivityOptions.abort(options);
-                                return ActivityManager.START_PERMISSION_DENIED;
-                            }
-                        }
-                        
-                        IIntentSender target = mService.getIntentSenderLocked(
-                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",
-                                realCallingUid, userId, null, null, 0, new Intent[] { intent },
-                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
-                                | PendingIntent.FLAG_ONE_SHOT, null);
-                        
-                        Intent newIntent = new Intent();
-                        if (requestCode >= 0) {
-                            // Caller is requesting a result.
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
-                        }
-                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
-                                new IntentSender(target));
-                        if (mService.mHeavyWeightProcess.activities.size() > 0) {
-                            ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
-                                    hist.packageName);
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
-                                    hist.task.taskId);
-                        }
-                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
-                                aInfo.packageName);
-                        newIntent.setFlags(intent.getFlags());
-                        newIntent.setClassName("android",
-                                HeavyWeightSwitcherActivity.class.getName());
-                        intent = newIntent;
-                        resolvedType = null;
-                        caller = null;
-                        callingUid = Binder.getCallingUid();
-                        callingPid = Binder.getCallingPid();
-                        componentSpecified = true;
-                        try {
-                            ResolveInfo rInfo =
-                                AppGlobals.getPackageManager().resolveIntent(
-                                        intent, null,
-                                        PackageManager.MATCH_DEFAULT_ONLY
-                                        | ActivityManagerService.STOCK_PM_FLAGS, userId);
-                            aInfo = rInfo != null ? rInfo.activityInfo : null;
-                            aInfo = mService.getActivityInfoForUser(aInfo, userId);
-                        } catch (RemoteException e) {
-                            aInfo = null;
-                        }
-                    }
-                }
-            }
-            
-            int res = startActivityLocked(caller, intent, resolvedType,
-                    aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
-                    callingPackage, startFlags, options, componentSpecified, null);
-            
-            if (mConfigWillChange && mMainStack) {
-                // If the caller also wants to switch to a new configuration,
-                // do so now.  This allows a clean switch, as we are waiting
-                // for the current activity to pause (so we will not destroy
-                // it), and have not yet started the next activity.
-                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
-                        "updateConfiguration()");
-                mConfigWillChange = false;
-                if (DEBUG_CONFIGURATION) Slog.v(TAG,
-                        "Updating to new configuration after starting activity.");
-                mService.updateConfigurationLocked(config, null, false, false);
-            }
-            
-            Binder.restoreCallingIdentity(origId);
-            
-            if (outResult != null) {
-                outResult.result = res;
-                if (res == ActivityManager.START_SUCCESS) {
-                    mWaitingActivityLaunched.add(outResult);
-                    do {
-                        try {
-                            mService.wait();
-                        } catch (InterruptedException e) {
-                        }
-                    } while (!outResult.timeout && outResult.who == null);
-                } else if (res == ActivityManager.START_TASK_TO_FRONT) {
-                    ActivityRecord r = this.topRunningActivityLocked(null);
-                    if (r.nowVisible) {
-                        outResult.timeout = false;
-                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
-                        outResult.totalTime = 0;
-                        outResult.thisTime = 0;
-                    } else {
-                        outResult.thisTime = SystemClock.uptimeMillis();
-                        mWaitingActivityVisible.add(outResult);
-                        do {
-                            try {
-                                mService.wait();
-                            } catch (InterruptedException e) {
-                            }
-                        } while (!outResult.timeout && outResult.who == null);
-                    }
-                }
-            }
-            
-            return res;
-        }
-    }
-    
-    final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
-            Intent[] intents, String[] resolvedTypes, IBinder resultTo,
-            Bundle options, int userId) {
-        if (intents == null) {
-            throw new NullPointerException("intents is null");
-        }
-        if (resolvedTypes == null) {
-            throw new NullPointerException("resolvedTypes is null");
-        }
-        if (intents.length != resolvedTypes.length) {
-            throw new IllegalArgumentException("intents are length different than resolvedTypes");
-        }
-
-        ActivityRecord[] outActivity = new ActivityRecord[1];
-
-        int callingPid;
-        if (callingUid >= 0) {
-            callingPid = -1;
-        } else if (caller == null) {
-            callingPid = Binder.getCallingPid();
-            callingUid = Binder.getCallingUid();
-        } else {
-            callingPid = callingUid = -1;
-        }
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mService) {
-
-                for (int i=0; i<intents.length; i++) {
-                    Intent intent = intents[i];
-                    if (intent == null) {
-                        continue;
-                    }
-
-                    // Refuse possible leaked file descriptors
-                    if (intent != null && intent.hasFileDescriptors()) {
-                        throw new IllegalArgumentException("File descriptors passed in Intent");
-                    }
-
-                    boolean componentSpecified = intent.getComponent() != null;
-
-                    // Don't modify the client's object!
-                    intent = new Intent(intent);
-
-                    // Collect information about the target of the Intent.
-                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i],
-                            0, null, null, userId);
-                    // TODO: New, check if this is correct
-                    aInfo = mService.getActivityInfoForUser(aInfo, userId);
-
-                    if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags
-                            & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
-                        throw new IllegalArgumentException(
-                                "FLAG_CANT_SAVE_STATE not supported here");
-                    }
-
-                    Bundle theseOptions;
-                    if (options != null && i == intents.length-1) {
-                        theseOptions = options;
-                    } else {
-                        theseOptions = null;
-                    }
-                    int res = startActivityLocked(caller, intent, resolvedTypes[i],
-                            aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage,
-                            0, theseOptions, componentSpecified, outActivity);
-                    if (res < 0) {
-                        return res;
-                    }
-
-                    resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-
-        return ActivityManager.START_SUCCESS;
-    }
-
-    void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
-            long thisTime, long totalTime) {
-        for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
-            WaitResult w = mWaitingActivityLaunched.get(i);
-            w.timeout = timeout;
-            if (r != null) {
-                w.who = new ComponentName(r.info.packageName, r.info.name);
-            }
-            w.thisTime = thisTime;
-            w.totalTime = totalTime;
-        }
-        mService.notifyAll();
-    }
-    
-    void reportActivityVisibleLocked(ActivityRecord r) {
-        for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
-            WaitResult w = mWaitingActivityVisible.get(i);
-            w.timeout = false;
-            if (r != null) {
-                w.who = new ComponentName(r.info.packageName, r.info.name);
-            }
-            w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
-            w.thisTime = w.totalTime;
-        }
-        mService.notifyAll();
-
-        if (mDismissKeyguardOnNextActivity) {
-            mDismissKeyguardOnNextActivity = false;
-            mService.mWindowManager.dismissKeyguard();
-        }
-    }
 
     void sendActivityResultLocked(int callingUid, ActivityRecord r,
             String resultWho, int requestCode, int resultCode, Intent data) {
@@ -3394,7 +2148,7 @@
         r.addResultLocked(null, resultWho, requestCode, resultCode, data);
     }
 
-    private final void stopActivityLocked(ActivityRecord r) {
+    final void stopActivityLocked(ActivityRecord r) {
         if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
@@ -3413,7 +2167,7 @@
         }
 
         if (r.app != null && r.app.thread != null) {
-            if (mMainStack) {
+            if (mStackSupervisor.isFrontStack(this)) {
                 if (mService.mFocusedActivity == r) {
                     mService.setFocusedActivityLocked(topRunningActivityLocked(null));
                 }
@@ -3427,14 +2181,13 @@
                 if (DEBUG_VISBILITY) Slog.v(
                         TAG, "Stopping visible=" + r.visible + " for " + r);
                 if (!r.visible) {
-                    mService.mWindowManager.setAppVisibility(r.appToken, false);
+                    mWindowManager.setAppVisibility(r.appToken, false);
                 }
                 r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
-                if (mService.isSleeping()) {
+                if (mService.isSleepingOrShuttingDown()) {
                     r.setSleeping(true);
                 }
-                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG);
-                msg.obj = r;
+                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
                 mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
             } catch (Exception e) {
                 // Maybe just ignore exceptions here...  if the process
@@ -3451,217 +2204,6 @@
             }
         }
     }
-    
-    final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
-            boolean remove) {
-        int N = mStoppingActivities.size();
-        if (N <= 0) return null;
-
-        ArrayList<ActivityRecord> stops = null;
-
-        final boolean nowVisible = mResumedActivity != null
-                && mResumedActivity.nowVisible
-                && !mResumedActivity.waitingVisible;
-        for (int i=0; i<N; i++) {
-            ActivityRecord s = mStoppingActivities.get(i);
-            if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
-                    + nowVisible + " waitingVisible=" + s.waitingVisible
-                    + " finishing=" + s.finishing);
-            if (s.waitingVisible && nowVisible) {
-                mWaitingVisibleActivities.remove(s);
-                s.waitingVisible = false;
-                if (s.finishing) {
-                    // If this activity is finishing, it is sitting on top of
-                    // everyone else but we now know it is no longer needed...
-                    // so get rid of it.  Otherwise, we need to go through the
-                    // normal flow and hide it once we determine that it is
-                    // hidden by the activities in front of it.
-                    if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
-                    mService.mWindowManager.setAppVisibility(s.appToken, false);
-                }
-            }
-            if ((!s.waitingVisible || mService.isSleeping()) && remove) {
-                if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
-                if (stops == null) {
-                    stops = new ArrayList<ActivityRecord>();
-                }
-                stops.add(s);
-                mStoppingActivities.remove(i);
-                N--;
-                i--;
-            }
-        }
-
-        return stops;
-    }
-
-    final void scheduleIdleLocked() {
-        Message msg = Message.obtain();
-        msg.what = IDLE_NOW_MSG;
-        mHandler.sendMessage(msg);
-    }
-
-    final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,
-            Configuration config) {
-        if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
-
-        ActivityRecord res = null;
-
-        ArrayList<ActivityRecord> stops = null;
-        ArrayList<ActivityRecord> finishes = null;
-        ArrayList<ActivityRecord> thumbnails = null;
-        ArrayList<UserStartedState> startingUsers = null;
-        int NS = 0;
-        int NF = 0;
-        int NT = 0;
-        IApplicationThread sendThumbnail = null;
-        boolean booting = false;
-        boolean enableScreen = false;
-        boolean activityRemoved = false;
-
-        synchronized (mService) {
-            ActivityRecord r = ActivityRecord.forToken(token);
-            if (r != null) {
-                mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
-                r.finishLaunchTickingLocked();
-            }
-
-            // Get the activity record.
-            int index = indexOfActivityLocked(r);
-            if (index >= 0) {
-                res = r;
-
-                if (fromTimeout) {
-                    reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
-                }
-                
-                // This is a hack to semi-deal with a race condition
-                // in the client where it can be constructed with a
-                // newer configuration from when we asked it to launch.
-                // We'll update with whatever configuration it now says
-                // it used to launch.
-                if (config != null) {
-                    r.configuration = config;
-                }
-                
-                // No longer need to keep the device awake.
-                if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
-                    mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
-                    mLaunchingActivity.release();
-                }
-
-                // We are now idle.  If someone is waiting for a thumbnail from
-                // us, we can now deliver.
-                r.idle = true;
-                mService.scheduleAppGcsLocked();
-                if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
-                    sendThumbnail = r.app.thread;
-                    r.thumbnailNeeded = false;
-                }
-
-                // If this activity is fullscreen, set up to hide those under it.
-
-                if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
-                ensureActivitiesVisibleLocked(null, 0);
-
-                //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
-                if (mMainStack) {
-                    if (!mService.mBooted) {
-                        mService.mBooted = true;
-                        enableScreen = true;
-                    }
-                }
-                
-            } else if (fromTimeout) {
-                reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
-            }
-
-            // Atomically retrieve all of the other things to do.
-            stops = processStoppingActivitiesLocked(true);
-            NS = stops != null ? stops.size() : 0;
-            if ((NF=mFinishingActivities.size()) > 0) {
-                finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
-                mFinishingActivities.clear();
-            }
-            if ((NT=mService.mCancelledThumbnails.size()) > 0) {
-                thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
-                mService.mCancelledThumbnails.clear();
-            }
-
-            if (mMainStack) {
-                booting = mService.mBooting;
-                mService.mBooting = false;
-            }
-            if (mStartingUsers.size() > 0) {
-                startingUsers = new ArrayList<UserStartedState>(mStartingUsers);
-                mStartingUsers.clear();
-            }
-        }
-
-        int i;
-
-        // Send thumbnail if requested.
-        if (sendThumbnail != null) {
-            try {
-                sendThumbnail.requestThumbnail(token);
-            } catch (Exception e) {
-                Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
-                mService.sendPendingThumbnail(null, token, null, null, true);
-            }
-        }
-
-        // Stop any activities that are scheduled to do so but have been
-        // waiting for the next one to start.
-        for (i=0; i<NS; i++) {
-            ActivityRecord r = (ActivityRecord)stops.get(i);
-            synchronized (mService) {
-                if (r.finishing) {
-                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
-                } else {
-                    stopActivityLocked(r);
-                }
-            }
-        }
-
-        // Finish any activities that are scheduled to do so but have been
-        // waiting for the next one to start.
-        for (i=0; i<NF; i++) {
-            ActivityRecord r = (ActivityRecord)finishes.get(i);
-            synchronized (mService) {
-                activityRemoved = destroyActivityLocked(r, true, false, "finish-idle");
-            }
-        }
-
-        // Report back to any thumbnail receivers.
-        for (i=0; i<NT; i++) {
-            ActivityRecord r = (ActivityRecord)thumbnails.get(i);
-            mService.sendPendingThumbnail(r, null, null, null, true);
-        }
-
-        if (booting) {
-            mService.finishBooting();
-        } else if (startingUsers != null) {
-            for (i=0; i<startingUsers.size(); i++) {
-                mService.finishUserSwitch(startingUsers.get(i));
-            }
-        }
-
-        mService.trimApplications();
-        //dump();
-        //mWindowManager.dump();
-
-        if (enableScreen) {
-            mService.enableScreenAfterBoot();
-        }
-
-        if (activityRemoved) {
-            synchronized (mService) {
-                resumeTopActivityLocked(null);
-            }
-        }
-
-        return res;
-    }
 
     /**
      * @return Returns true if the activity is being finished, false if for
@@ -3669,63 +2211,82 @@
      */
     final boolean requestFinishActivityLocked(IBinder token, int resultCode,
             Intent resultData, String reason, boolean oomAdj) {
-        int index = indexOfTokenLocked(token);
+        ActivityRecord r = isInStackLocked(token);
         if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(
-                TAG, "Finishing activity @" + index + ": token=" + token
+                TAG, "Finishing activity token=" + token + " r="
                 + ", result=" + resultCode + ", data=" + resultData
                 + ", reason=" + reason);
-        if (index < 0) {
+        if (r == null) {
             return false;
         }
-        ActivityRecord r = mHistory.get(index);
 
-        finishActivityLocked(r, index, resultCode, resultData, reason, oomAdj);
+        finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
         return true;
     }
 
-    final void finishSubActivityLocked(IBinder token, String resultWho, int requestCode) {
-        ActivityRecord self = isInStackLocked(token);
-        if (self == null) {
-            return;
-        }
-
-        int i;
-        for (i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
-            if (r.resultTo == self && r.requestCode == requestCode) {
-                if ((r.resultWho == null && resultWho == null) ||
-                    (r.resultWho != null && r.resultWho.equals(resultWho))) {
-                    finishActivityLocked(r, i,
-                            Activity.RESULT_CANCELED, null, "request-sub", false);
+    final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = activities.get(activityNdx);
+                if (r.resultTo == self && r.requestCode == requestCode) {
+                    if ((r.resultWho == null && resultWho == null) ||
+                        (r.resultWho != null && r.resultWho.equals(resultWho))) {
+                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "request-sub",
+                                false);
+                    }
                 }
             }
         }
         mService.updateOomAdjLocked();
     }
 
-    final boolean finishActivityAffinityLocked(IBinder token) {
-        int index = indexOfTokenLocked(token);
-        if (DEBUG_RESULTS) Slog.v(
-                TAG, "Finishing activity affinity @" + index + ": token=" + token);
-        if (index < 0) {
-            return false;
+    final void finishTopRunningActivityLocked(ProcessRecord app) {
+        ActivityRecord r = topRunningActivityLocked(null);
+        if (r != null && r.app == app) {
+            // If the top running activity is from this crashing
+            // process, then terminate it to avoid getting in a loop.
+            Slog.w(TAG, "  Force finishing activity "
+                    + r.intent.getComponent().flattenToShortString());
+            int taskNdx = mTaskHistory.indexOf(r.task);
+            int activityNdx = r.task.mActivities.indexOf(r);
+            finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
+            // Also terminate any activities below it that aren't yet
+            // stopped, to avoid a situation where one will get
+            // re-start our crashing activity once it gets resumed again.
+            --activityNdx;
+            if (activityNdx < 0) {
+                do {
+                    --taskNdx;
+                    if (taskNdx < 0) {
+                        break;
+                    }
+                    activityNdx = mTaskHistory.get(taskNdx).mActivities.size() - 1;
+                } while (activityNdx < 0);
+            }
+            if (activityNdx >= 0) {
+                r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
+                if (r.state == ActivityState.RESUMED
+                        || r.state == ActivityState.PAUSING
+                        || r.state == ActivityState.PAUSED) {
+                    if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
+                        Slog.w(TAG, "  Force finishing activity "
+                                + r.intent.getComponent().flattenToShortString());
+                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
+                    }
+                }
+            }
         }
-        ActivityRecord r = mHistory.get(index);
+    }
 
-        while (index >= 0) {
-            ActivityRecord cur = mHistory.get(index);
-            if (cur.task != r.task) {
+    final boolean finishActivityAffinityLocked(ActivityRecord r) {
+        ArrayList<ActivityRecord> activities = r.task.mActivities;
+        for (int index = activities.indexOf(r); index >= 0; --index) {
+            ActivityRecord cur = activities.get(index);
+            if (!Objects.equal(cur.taskAffinity, r.taskAffinity)) {
                 break;
             }
-            if (cur.taskAffinity == null && r.taskAffinity != null) {
-                break;
-            }
-            if (cur.taskAffinity != null && !cur.taskAffinity.equals(r.taskAffinity)) {
-                break;
-            }
-            finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null,
-                    "request-affinity", true);
-            index--;
+            finishActivityLocked(cur, Activity.RESULT_CANCELED, null, "request-affinity", true);
         }
         return true;
     }
@@ -3761,17 +2322,8 @@
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
-    final boolean finishActivityLocked(ActivityRecord r, int index,
-            int resultCode, Intent resultData, String reason, boolean oomAdj) {
-        return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
-    }
-
-    /**
-     * @return Returns true if this activity has been removed from the history
-     * list, or false if it is still in the list and will be removed later.
-     */
-    final boolean finishActivityLocked(ActivityRecord r, int index, int resultCode,
-            Intent resultData, String reason, boolean immediate, boolean oomAdj) {
+    final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
+            String reason, boolean oomAdj) {
         if (r.finishing) {
             Slog.w(TAG, "Duplicate finish request for " + r);
             return false;
@@ -3781,53 +2333,49 @@
         EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                 r.userId, System.identityHashCode(r),
                 r.task.taskId, r.shortComponentName, reason);
-        if (index < (mHistory.size()-1)) {
-            ActivityRecord next = mHistory.get(index+1);
-            if (next.task == r.task) {
-                if (r.frontOfTask) {
-                    // The next activity is now the front of the task.
-                    next.frontOfTask = true;
-                }
-                if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-                    // If the caller asked that this activity (and all above it)
-                    // be cleared when the task is reset, don't lose that information,
-                    // but propagate it up to the next activity.
-                    next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-                }
+        final ArrayList<ActivityRecord> activities = r.task.mActivities;
+        final int index = activities.indexOf(r);
+        if (index < (activities.size() - 1)) {
+            ActivityRecord next = activities.get(index+1);
+            if (r.frontOfTask) {
+                // The next activity is now the front of the task.
+                next.frontOfTask = true;
+            }
+            if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+                // If the caller asked that this activity (and all above it)
+                // be cleared when the task is reset, don't lose that information,
+                // but propagate it up to the next activity.
+                next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
             }
         }
 
         r.pauseKeyDispatchingLocked();
-        if (mMainStack) {
+        if (mStackSupervisor.isFrontStack(this)) {
             if (mService.mFocusedActivity == r) {
-                mService.setFocusedActivityLocked(topRunningActivityLocked(null));
+                mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked());
             }
         }
 
         finishActivityResultsLocked(r, resultCode, resultData);
-        
-        if (mService.mPendingThumbnails.size() > 0) {
+
+        if (!mService.mPendingThumbnails.isEmpty()) {
             // There are clients waiting to receive thumbnails so, in case
             // this is an activity that someone is waiting for, add it
             // to the pending list so we can correctly update the clients.
-            mService.mCancelledThumbnails.add(r);
+            mStackSupervisor.mCancelledThumbnails.add(r);
         }
 
-        if (immediate) {
-            return finishCurrentActivityLocked(r, index,
-                    FINISH_IMMEDIATELY, oomAdj) == null;
-        } else if (mResumedActivity == r) {
-            boolean endTask = index <= 0
-                    || (mHistory.get(index-1)).task != r.task;
-            if (DEBUG_TRANSITION) Slog.v(TAG,
+        if (mResumedActivity == r) {
+            boolean endTask = index <= 0;
+            if (DEBUG_VISBILITY || DEBUG_TRANSITION) Slog.v(TAG,
                     "Prepare close transition: finishing " + r);
-            mService.mWindowManager.prepareAppTransition(endTask
+            mWindowManager.prepareAppTransition(endTask
                     ? AppTransition.TRANSIT_TASK_CLOSE
                     : AppTransition.TRANSIT_ACTIVITY_CLOSE, false);
-    
+
             // Tell window manager to prepare for this one to be removed.
-            mService.mWindowManager.setAppVisibility(r.appToken, false);
-                
+            mWindowManager.setAppVisibility(r.appToken, false);
+
             if (mPausingActivity == null) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
                 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
@@ -3838,8 +2386,7 @@
             // If the activity is PAUSING, we will complete the finish once
             // it is done pausing; else we can just directly finish it here.
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
-            return finishCurrentActivityLocked(r, index,
-                    FINISH_AFTER_PAUSE, oomAdj) == null;
+            return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
         }
@@ -3847,35 +2394,26 @@
         return false;
     }
 
-    private static final int FINISH_IMMEDIATELY = 0;
-    private static final int FINISH_AFTER_PAUSE = 1;
-    private static final int FINISH_AFTER_VISIBLE = 2;
+    static final int FINISH_IMMEDIATELY = 0;
+    static final int FINISH_AFTER_PAUSE = 1;
+    static final int FINISH_AFTER_VISIBLE = 2;
 
-    private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int mode, boolean oomAdj) {
-        final int index = indexOfActivityLocked(r);
-        if (index < 0) {
-            return null;
-        }
-
-        return finishCurrentActivityLocked(r, index, mode, oomAdj);
-    }
-
-    private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int index, int mode, boolean oomAdj) {
+    final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
         // First things first: if this activity is currently visible,
         // and the resumed activity is not yet visible, then hold off on
         // finishing until the resumed one becomes visible.
         if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
-            if (!mStoppingActivities.contains(r)) {
-                mStoppingActivities.add(r);
-                if (mStoppingActivities.size() > 3) {
+            if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+                mStackSupervisor.mStoppingActivities.add(r);
+                if (mStackSupervisor.mStoppingActivities.size() > 3
+                        || r.frontOfTask && mTaskHistory.size() <= 1) {
                     // If we already have a few activities waiting to stop,
                     // then give up on things going idle and start clearing
-                    // them out.
-                    scheduleIdleLocked();
+                    // them out. Or if r is the last of activity of the last task the stack
+                    // will be empty and must be cleared immediately.
+                    mStackSupervisor.scheduleIdleLocked();
                 } else {
-                    checkReadyForSleepLocked();
+                    mStackSupervisor.checkReadyForSleepLocked();
                 }
             }
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
@@ -3888,9 +2426,9 @@
         }
 
         // make sure the record is cleaned out of other places.
-        mStoppingActivities.remove(r);
-        mGoingToSleepActivities.remove(r);
-        mWaitingVisibleActivities.remove(r);
+        mStackSupervisor.mStoppingActivities.remove(r);
+        mStackSupervisor.mGoingToSleepActivities.remove(r);
+        mStackSupervisor.mWaitingVisibleActivities.remove(r);
         if (mResumedActivity == r) {
             mResumedActivity = null;
         }
@@ -3906,19 +2444,99 @@
             boolean activityRemoved = destroyActivityLocked(r, true,
                     oomAdj, "finish-imm");
             if (activityRemoved) {
-                resumeTopActivityLocked(null);
+                mStackSupervisor.resumeTopActivitiesLocked();
             }
             return activityRemoved ? null : r;
-        } else {
-            // Need to go through the full pause cycle to get this
-            // activity into the stopped state and then finish it.
-            if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
-            mFinishingActivities.add(r);
-            resumeTopActivityLocked(null);
         }
+
+        // Need to go through the full pause cycle to get this
+        // activity into the stopped state and then finish it.
+        if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+        mStackSupervisor.mFinishingActivities.add(r);
+        mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
         return r;
     }
 
+    final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
+            Intent resultData) {
+        final ActivityRecord srec = ActivityRecord.forToken(token);
+        final TaskRecord task = srec.task;
+        final ArrayList<ActivityRecord> activities = task.mActivities;
+        final int start = activities.indexOf(srec);
+        if (!mTaskHistory.contains(task) || (start < 0)) {
+            return false;
+        }
+        int finishTo = start - 1;
+        ActivityRecord parent = finishTo < 0 ? null : activities.get(finishTo);
+        boolean foundParentInTask = false;
+        final ComponentName dest = destIntent.getComponent();
+        if (start > 0 && dest != null) {
+            for (int i = finishTo; i >= 0; i--) {
+                ActivityRecord r = activities.get(i);
+                if (r.info.packageName.equals(dest.getPackageName()) &&
+                        r.info.name.equals(dest.getClassName())) {
+                    finishTo = i;
+                    parent = r;
+                    foundParentInTask = true;
+                    break;
+                }
+            }
+        }
+
+        IActivityController controller = mService.mController;
+        if (controller != null) {
+            ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
+            if (next != null) {
+                // ask watcher if this is allowed
+                boolean resumeOK = true;
+                try {
+                    resumeOK = controller.activityResuming(next.packageName);
+                } catch (RemoteException e) {
+                    mService.mController = null;
+                    Watchdog.getInstance().setActivityController(null);
+                }
+
+                if (!resumeOK) {
+                    return false;
+                }
+            }
+        }
+        final long origId = Binder.clearCallingIdentity();
+        for (int i = start; i > finishTo; i--) {
+            ActivityRecord r = activities.get(i);
+            requestFinishActivityLocked(r.appToken, resultCode, resultData, "navigate-up", true);
+            // Only return the supplied result for the first activity finished
+            resultCode = Activity.RESULT_CANCELED;
+            resultData = null;
+        }
+
+        if (parent != null && foundParentInTask) {
+            final int parentLaunchMode = parent.info.launchMode;
+            final int destIntentFlags = destIntent.getFlags();
+            if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+                    parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
+                    parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
+                    (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+                parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
+            } else {
+                try {
+                    ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
+                            destIntent.getComponent(), 0, srec.userId);
+                    int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
+                            null, aInfo, parent.appToken, null,
+                            0, -1, parent.launchedFromUid, parent.launchedFromPackage,
+                            0, null, true, null);
+                    foundParentInTask = res == ActivityManager.START_SUCCESS;
+                } catch (RemoteException e) {
+                    foundParentInTask = false;
+                }
+                requestFinishActivityLocked(parent.appToken, resultCode,
+                        resultData, "navigate-up", true);
+            }
+        }
+        Binder.restoreCallingIdentity(origId);
+        return foundParentInTask;
+    }
     /**
      * Perform the common clean-up of an activity record.  This is called both
      * as part of destroyActivityLocked() (when destroying the client-side
@@ -3948,9 +2566,9 @@
         // Make sure this record is no longer in the pending finishes list.
         // This could happen, for example, if we are trimming activities
         // down to the max limit while they are still waiting to finish.
-        mFinishingActivities.remove(r);
-        mWaitingVisibleActivities.remove(r);
-        
+        mStackSupervisor.mFinishingActivities.remove(r);
+        mStackSupervisor.mWaitingVisibleActivities.remove(r);
+
         // Remove any pending results.
         if (r.finishing && r.pendingResults != null) {
             for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
@@ -3963,14 +2581,14 @@
         }
 
         if (cleanServices) {
-            cleanUpActivityServicesLocked(r);            
+            cleanUpActivityServicesLocked(r);
         }
 
-        if (mService.mPendingThumbnails.size() > 0) {
+        if (!mService.mPendingThumbnails.isEmpty()) {
             // There are clients waiting to receive thumbnails so, in case
             // this is an activity that someone is waiting for, add it
             // to the pending list so we can correctly update the clients.
-            mService.mCancelledThumbnails.add(r);
+            mStackSupervisor.mCancelledThumbnails.add(r);
         }
 
         // Get rid of any pending idle timeouts.
@@ -3978,9 +2596,9 @@
     }
 
     private void removeTimeoutsForActivityLocked(ActivityRecord r) {
+        mStackSupervisor.removeTimeoutsForActivityLocked(r);
         mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
         mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
-        mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
         mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
         r.finishLaunchTickingLocked();
     }
@@ -3993,22 +2611,26 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Removing activity " + r + " from stack");
         }
-        mHistory.remove(r);
+        final TaskRecord task = r.task;
+        if (task != null && task.removeActivity(r)) {
+            if (DEBUG_STACK) Slog.i(TAG,
+                    "removeActivityFromHistoryLocked: last activity removed from " + this);
+            mStackSupervisor.removeTask(task);
+        }
         r.takeFromHistory();
         removeTimeoutsForActivityLocked(r);
-        if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
-                + " (removed from history)");
+        if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (removed from history)");
         r.state = ActivityState.DESTROYED;
         if (DEBUG_APP) Slog.v(TAG, "Clearing app during remove for activity " + r);
         r.app = null;
-        mService.mWindowManager.removeAppToken(r.appToken);
+        mWindowManager.removeAppToken(r.appToken);
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
         cleanUpActivityServicesLocked(r);
         r.removeUriPermissionsLocked();
     }
-    
+
     /**
      * Perform clean-up of service connections in an activity record.
      */
@@ -4033,36 +2655,40 @@
     final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
         boolean lastIsOpaque = false;
         boolean activityRemoved = false;
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if (r.finishing) {
-                continue;
-            }
-            if (r.fullscreen) {
-                lastIsOpaque = true;
-            }
-            if (owner != null && r.app != owner) {
-                continue;
-            }
-            if (!lastIsOpaque) {
-                continue;
-            }
-            // We can destroy this one if we have its icicle saved and
-            // it is not in the process of pausing/stopping/finishing.
-            if (r.app != null && r != mResumedActivity && r != mPausingActivity
-                    && r.haveState && !r.visible && r.stopped
-                    && r.state != ActivityState.DESTROYING
-                    && r.state != ActivityState.DESTROYED) {
-                if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
-                        + " resumed=" + mResumedActivity
-                        + " pausing=" + mPausingActivity);
-                if (destroyActivityLocked(r, true, oomAdj, reason)) {
-                    activityRemoved = true;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.finishing) {
+                    continue;
+                }
+                if (r.fullscreen) {
+                    lastIsOpaque = true;
+                }
+                if (owner != null && r.app != owner) {
+                    continue;
+                }
+                if (!lastIsOpaque) {
+                    continue;
+                }
+                // We can destroy this one if we have its icicle saved and
+                // it is not in the process of pausing/stopping/finishing.
+                if (r.app != null && r != mResumedActivity && r != mPausingActivity
+                        && r.haveState && !r.visible && r.stopped
+                        && r.state != ActivityState.DESTROYING
+                        && r.state != ActivityState.DESTROYED) {
+                    if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
+                            + " resumed=" + mResumedActivity
+                            + " pausing=" + mPausingActivity);
+                    if (destroyActivityLocked(r, true, oomAdj, reason)) {
+                        activityRemoved = true;
+                    }
                 }
             }
         }
         if (activityRemoved) {
-            resumeTopActivityLocked(null);
+            mStackSupervisor.resumeTopActivitiesLocked();
+
         }
     }
 
@@ -4089,23 +2715,21 @@
 
         if (hadApp) {
             if (removeFromApp) {
-                int idx = r.app.activities.indexOf(r);
-                if (idx >= 0) {
-                    r.app.activities.remove(idx);
-                }
+                r.app.activities.remove(r);
                 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
                     mService.mHeavyWeightProcess = null;
                     mService.mHandler.sendEmptyMessage(
                             ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
                 }
-                if (r.app.activities.size() == 0) {
-                    // No longer have activities, so update oom adj.
+                if (r.app.activities.isEmpty()) {
+                    // No longer have activities, so update LRU list and oom adj.
+                    mService.updateLruProcessLocked(r.app, false, false);
                     mService.updateOomAdjLocked();
                 }
             }
 
             boolean skipDestroy = false;
-            
+
             try {
                 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
                 r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
@@ -4123,7 +2747,7 @@
             }
 
             r.nowVisible = false;
-            
+
             // If the activity is finishing, we need to wait on removing it
             // from the list to give it a chance to do its cleanup.  During
             // that time it may make calls back with its token so we need to
@@ -4135,12 +2759,10 @@
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
                         + " (destroy requested)");
                 r.state = ActivityState.DESTROYING;
-                Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
-                msg.obj = r;
+                Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r);
                 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
             } else {
-                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
-                        + " (destroy skipped)");
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (destroy skipped)");
                 r.state = ActivityState.DESTROYED;
                 if (DEBUG_APP) Slog.v(TAG, "Clearing app during destroy for activity " + r);
                 r.app = null;
@@ -4151,8 +2773,7 @@
                 removeActivityFromHistoryLocked(r);
                 removedFromHistory = true;
             } else {
-                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
-                        + " (no app)");
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (no app)");
                 r.state = ActivityState.DESTROYED;
                 if (DEBUG_APP) Slog.v(TAG, "Clearing app during destroy for activity " + r);
                 r.app = null;
@@ -4160,46 +2781,43 @@
         }
 
         r.configChangeFlags = 0;
-        
+
         if (!mLRUActivities.remove(r) && hadApp) {
             Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
         }
-        
+
         return removedFromHistory;
     }
 
-    final void activityDestroyed(IBinder token) {
-        synchronized (mService) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                ActivityRecord r = ActivityRecord.forToken(token);
-                if (r != null) {
-                    mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
-                }
-
-                int index = indexOfActivityLocked(r);
-                if (index >= 0) {
-                    if (r.state == ActivityState.DESTROYING) {
-                        cleanUpActivityLocked(r, true, false);
-                        removeActivityFromHistoryLocked(r);
-                    }
-                }
-                resumeTopActivityLocked(null);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
+    final void activityDestroyedLocked(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            ActivityRecord r = ActivityRecord.forToken(token);
+            if (r != null) {
+                mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
             }
+
+            if (isInStackLocked(token) != null) {
+                if (r.state == ActivityState.DESTROYING) {
+                    cleanUpActivityLocked(r, true, false);
+                    removeActivityFromHistoryLocked(r);
+                }
+            }
+            mStackSupervisor.resumeTopActivitiesLocked();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
-    
-    private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app,
-            String listName) {
+
+    private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+            ProcessRecord app, String listName) {
         int i = list.size();
         if (DEBUG_CLEANUP) Slog.v(
             TAG, "Removing app " + app + " from list " + listName
             + " with " + i + " entries");
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)list.get(i);
+            ActivityRecord r = list.get(i);
             if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
             if (r.app == app) {
                 if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
@@ -4211,100 +2829,91 @@
 
     boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
         removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
-        removeHistoryRecordsForAppLocked(mStoppingActivities, app, "mStoppingActivities");
-        removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app, "mGoingToSleepActivities");
-        removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app,
+        removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
+                "mStoppingActivities");
+        removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
+                "mGoingToSleepActivities");
+        removeHistoryRecordsForAppLocked(mStackSupervisor.mWaitingVisibleActivities, app,
                 "mWaitingVisibleActivities");
-        removeHistoryRecordsForAppLocked(mFinishingActivities, app, "mFinishingActivities");
+        removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
+                "mFinishingActivities");
 
         boolean hasVisibleActivities = false;
 
         // Clean out the history list.
-        int i = mHistory.size();
+        int i = numActivities();
         if (DEBUG_CLEANUP) Slog.v(
             TAG, "Removing app " + app + " from history with " + i + " entries");
-        while (i > 0) {
-            i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
-            if (DEBUG_CLEANUP) Slog.v(
-                TAG, "Record #" + i + " " + r + ": app=" + r.app);
-            if (r.app == app) {
-                boolean remove;
-                if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
-                    // Don't currently have state for the activity, or
-                    // it is finishing -- always remove it.
-                    remove = true;
-                } else if (r.launchCount > 2 &&
-                        r.lastLaunchTime > (SystemClock.uptimeMillis()-60000)) {
-                    // We have launched this activity too many times since it was
-                    // able to run, so give up and remove it.
-                    remove = true;
-                } else {
-                    // The process may be gone, but the activity lives on!
-                    remove = false;
-                }
-                if (remove) {
-                    if (ActivityStack.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
-                        RuntimeException here = new RuntimeException("here");
-                        here.fillInStackTrace();
-                        Slog.i(TAG, "Removing activity " + r + " from stack at " + i
-                                + ": haveState=" + r.haveState
-                                + " stateNotNeeded=" + r.stateNotNeeded
-                                + " finishing=" + r.finishing
-                                + " state=" + r.state, here);
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                --i;
+                if (DEBUG_CLEANUP) Slog.v(
+                    TAG, "Record #" + i + " " + r + ": app=" + r.app);
+                if (r.app == app) {
+                    boolean remove;
+                    if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
+                        // Don't currently have state for the activity, or
+                        // it is finishing -- always remove it.
+                        remove = true;
+                    } else if (r.launchCount > 2 &&
+                            r.lastLaunchTime > (SystemClock.uptimeMillis()-60000)) {
+                        // We have launched this activity too many times since it was
+                        // able to run, so give up and remove it.
+                        remove = true;
+                    } else {
+                        // The process may be gone, but the activity lives on!
+                        remove = false;
                     }
-                    if (!r.finishing) {
-                        Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
-                        EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
-                                r.userId, System.identityHashCode(r),
-                                r.task.taskId, r.shortComponentName,
-                                "proc died without state saved");
-                    }
-                    removeActivityFromHistoryLocked(r);
+                    if (remove) {
+                        if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
+                            RuntimeException here = new RuntimeException("here");
+                            here.fillInStackTrace();
+                            Slog.i(TAG, "Removing activity " + r + " from stack at " + i
+                                    + ": haveState=" + r.haveState
+                                    + " stateNotNeeded=" + r.stateNotNeeded
+                                    + " finishing=" + r.finishing
+                                    + " state=" + r.state, here);
+                        }
+                        if (!r.finishing) {
+                            Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+                            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
+                                    r.userId, System.identityHashCode(r),
+                                    r.task.taskId, r.shortComponentName,
+                                    "proc died without state saved");
+                            if (r.state == ActivityState.RESUMED) {
+                                mService.updateUsageStats(r, false);
+                            }
+                        }
+                        removeActivityFromHistoryLocked(r);
 
-                } else {
-                    // We have the current state for this activity, so
-                    // it can be restarted later when needed.
-                    if (localLOGV) Slog.v(
-                        TAG, "Keeping entry, setting app to null");
-                    if (r.visible) {
-                        hasVisibleActivities = true;
+                    } else {
+                        // We have the current state for this activity, so
+                        // it can be restarted later when needed.
+                        if (localLOGV) Slog.v(
+                            TAG, "Keeping entry, setting app to null");
+                        if (r.visible) {
+                            hasVisibleActivities = true;
+                        }
+                        if (DEBUG_APP) Slog.v(TAG, "Clearing app during removeHistory for activity "
+                                + r);
+                        r.app = null;
+                        r.nowVisible = false;
+                        if (!r.haveState) {
+                            if (DEBUG_SAVED_STATE) Slog.i(TAG,
+                                    "App died, clearing saved state of " + r);
+                            r.icicle = null;
+                        }
                     }
-                    if (DEBUG_APP) Slog.v(TAG, "Clearing app during removeHistory for activity "
-                            + r);
-                    r.app = null;
-                    r.nowVisible = false;
-                    if (!r.haveState) {
-                        if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG,
-                                "App died, clearing saved state of " + r);
-                        r.icicle = null;
-                    }
-                }
 
-                r.stack.cleanUpActivityLocked(r, true, true);
+                    cleanUpActivityLocked(r, true, true);
+                }
             }
         }
 
         return hasVisibleActivities;
     }
-    
-    /**
-     * Move the current home activity's task (if one exists) to the front
-     * of the stack.
-     */
-    final void moveHomeToFrontLocked() {
-        TaskRecord homeTask = null;
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord hr = mHistory.get(i);
-            if (hr.isHomeActivity) {
-                homeTask = hr.task;
-                break;
-            }
-        }
-        if (homeTask != null) {
-            moveTaskToFrontLocked(homeTask, null, null);
-        }
-    }
 
     final void updateTransitLocked(int transit, Bundle options) {
         if (options != null) {
@@ -4315,16 +2924,45 @@
                 ActivityOptions.abort(options);
             }
         }
-        mService.mWindowManager.prepareAppTransition(transit, false);
+        mWindowManager.prepareAppTransition(transit, false);
+    }
+
+    void moveHomeTaskToTop() {
+        final int top = mTaskHistory.size() - 1;
+        for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.isHomeTask()) {
+                mTaskHistory.remove(taskNdx);
+                mTaskHistory.add(top, task);
+                mWindowManager.moveTaskToTop(task.taskId);
+                return;
+            }
+        }
+    }
+
+    final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
+        final TaskRecord task = taskForIdLocked(taskId);
+        if (task != null) {
+            if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
+                mStackSupervisor.mUserLeaving = true;
+            }
+            if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
+                // Caller wants the home activity moved with it.  To accomplish this,
+                // we'll just indicate that this task returns to the home task.
+                task.mOnTopOfHome = true;
+            }
+            moveTaskToFrontLocked(task, null, options);
+            return true;
+        }
+        return false;
     }
 
     final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
         if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
 
-        final int task = tr.taskId;
-        int top = mHistory.size()-1;
-
-        if (top < 0 || (mHistory.get(top)).task.taskId == task) {
+        final int numTasks = mTaskHistory.size();
+        final int index = mTaskHistory.indexOf(tr);
+        if (numTasks == 0 || index < 0)  {
             // nothing to do!
             if (reason != null &&
                     (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
@@ -4335,40 +2973,16 @@
             return;
         }
 
-        ArrayList<IBinder> moved = new ArrayList<IBinder>();
-
-        // Applying the affinities may have removed entries from the history,
-        // so get the size again.
-        top = mHistory.size()-1;
-        int pos = top;
+        mStackSupervisor.moveHomeStack(isHomeStack());
 
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
-        while (pos >= 0) {
-            ActivityRecord r = mHistory.get(pos);
-            if (localLOGV) Slog.v(
-                TAG, "At " + pos + " ckp " + r.task + ": " + r);
-            if (r.task.taskId == task) {
-                if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
-                if (DEBUG_ADD_REMOVE) {
-                    RuntimeException here = new RuntimeException("here");
-                    here.fillInStackTrace();
-                    Slog.i(TAG, "Removing and adding activity " + r + " to stack at " + top, here);
-                }
-                mHistory.remove(pos);
-                mHistory.add(top, r);
-                moved.add(0, r.appToken);
-                top--;
-            }
-            pos--;
-        }
+        insertTaskAtTop(tr);
 
-        if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to front transition: task=" + tr);
+        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
         if (reason != null &&
                 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-            mService.mWindowManager.prepareAppTransition(
-                    AppTransition.TRANSIT_NONE, false);
+            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             ActivityRecord r = topRunningActivityLocked(null);
             if (r != null) {
                 mNoAnimActivities.add(r);
@@ -4377,39 +2991,36 @@
         } else {
             updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
         }
-        
-        mService.mWindowManager.moveAppTokensToTop(moved);
+
+        mWindowManager.moveTaskToTop(tr.taskId);
+
+        mStackSupervisor.resumeTopActivitiesLocked();
+        EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
+
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
-
-        finishTaskMoveLocked(task);
-        EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
-    }
-
-    private final void finishTaskMoveLocked(int task) {
-        resumeTopActivityLocked(null);
     }
 
     /**
-     * Worker method for rearranging history stack.  Implements the function of moving all 
-     * activities for a specific task (gathering them if disjoint) into a single group at the 
+     * Worker method for rearranging history stack. Implements the function of moving all
+     * activities for a specific task (gathering them if disjoint) into a single group at the
      * bottom of the stack.
-     * 
+     *
      * If a watcher is installed, the action is preflighted and the watcher has an opportunity
      * to premeptively cancel the move.
-     * 
-     * @param task The taskId to collect and move to the bottom.
+     *
+     * @param taskId The taskId to collect and move to the bottom.
      * @return Returns true if the move completed, false if not.
      */
-    final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
-        Slog.i(TAG, "moveTaskToBack: " + task);
-        
+    final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
+        Slog.i(TAG, "moveTaskToBack: " + taskId);
+
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (mMainStack && mService.mController != null) {
-            ActivityRecord next = topRunningActivityLocked(null, task);
+        if (mStackSupervisor.isFrontStack(this) && mService.mController != null) {
+            ActivityRecord next = topRunningActivityLocked(null, taskId);
             if (next == null) {
                 next = topRunningActivityLocked(null, 0);
             }
@@ -4420,6 +3031,7 @@
                     moveOK = mService.mController.activityResuming(next.packageName);
                 } catch (RemoteException e) {
                     mService.mController = null;
+                    Watchdog.getInstance().setActivityController(null);
                 }
                 if (!moveOK) {
                     return false;
@@ -4427,181 +3039,59 @@
             }
         }
 
-        ArrayList<IBinder> moved = new ArrayList<IBinder>();
-
         if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to back transition: task=" + task);
-        
-        final int N = mHistory.size();
-        int bottom = 0;
-        int pos = 0;
+                "Prepare to back transition: task=" + taskId);
 
-        // Shift all activities with this task down to the bottom
-        // of the stack, keeping them in the same internal order.
-        while (pos < N) {
-            ActivityRecord r = mHistory.get(pos);
-            if (localLOGV) Slog.v(
-                TAG, "At " + pos + " ckp " + r.task + ": " + r);
-            if (r.task.taskId == task) {
-                if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
-                if (DEBUG_ADD_REMOVE) {
-                    RuntimeException here = new RuntimeException("here");
-                    here.fillInStackTrace();
-                    Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
-                            + bottom, here);
-                }
-                mHistory.remove(pos);
-                mHistory.add(bottom, r);
-                moved.add(r.appToken);
-                bottom++;
+        final TaskRecord tr = taskForIdLocked(taskId);
+        if (tr == null) {
+            return false;
+        }
+
+        mTaskHistory.remove(tr);
+        mTaskHistory.add(0, tr);
+
+        // There is an assumption that moving a task to the back moves it behind the home activity.
+        // We make sure here that some activity in the stack will launch home.
+        ActivityRecord lastActivity = null;
+        int numTasks = mTaskHistory.size();
+        for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.mOnTopOfHome) {
+                break;
             }
-            pos++;
+            if (taskNdx == 1) {
+                // Set the last task before tr to go to home.
+                task.mOnTopOfHome = true;
+            }
         }
 
         if (reason != null &&
-                (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-            mService.mWindowManager.prepareAppTransition(
-                    AppTransition.TRANSIT_NONE, false);
+                (reason.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             ActivityRecord r = topRunningActivityLocked(null);
             if (r != null) {
                 mNoAnimActivities.add(r);
             }
         } else {
-            mService.mWindowManager.prepareAppTransition(
-                    AppTransition.TRANSIT_TASK_TO_BACK, false);
+            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
         }
-        mService.mWindowManager.moveAppTokensToBottom(moved);
+        mWindowManager.moveTaskToBottom(taskId);
+
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
 
-        finishTaskMoveLocked(task);
+        final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+        if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
+            task.mOnTopOfHome = false;
+            return mStackSupervisor.resumeHomeActivity(null);
+        }
+
+        mStackSupervisor.resumeTopActivitiesLocked();
         return true;
     }
 
-    public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
-        TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
-        ActivityRecord resumed = mResumedActivity;
-        if (resumed != null && resumed.thumbHolder == tr) {
-            info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
-        }
-        if (info.mainThumbnail == null) {
-            info.mainThumbnail = tr.lastThumbnail;
-        }
-        return info;
-    }
-
-    public Bitmap getTaskTopThumbnailLocked(TaskRecord tr) {
-        ActivityRecord resumed = mResumedActivity;
-        if (resumed != null && resumed.task == tr) {
-            // This task is the current resumed task, we just need to take
-            // a screenshot of it and return that.
-            return resumed.stack.screenshotActivities(resumed);
-        }
-        // Return the information about the task, to figure out the top
-        // thumbnail to return.
-        TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
-        if (info.numSubThumbbails <= 0) {
-            return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail;
-        } else {
-            return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
-        }
-    }
-
-    public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
-            boolean taskRequired) {
-        TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
-        if (info.root == null) {
-            if (taskRequired) {
-                Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
-            }
-            return null;
-        }
-
-        if (subTaskIndex < 0) {
-            // Just remove the entire task.
-            performClearTaskAtIndexLocked(taskId, info.rootIndex);
-            return info.root;
-        }
-
-        if (subTaskIndex >= info.subtasks.size()) {
-            if (taskRequired) {
-                Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
-            }
-            return null;
-        }
-
-        // Remove all of this task's activities starting at the sub task.
-        TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
-        performClearTaskAtIndexLocked(taskId, subtask.index);
-        return subtask.activity;
-    }
-
-    public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
-        final TaskAccessInfo thumbs = new TaskAccessInfo();
-        // How many different sub-thumbnails?
-        final int NA = mHistory.size();
-        int j = 0;
-        ThumbnailHolder holder = null;
-        while (j < NA) {
-            ActivityRecord ar = mHistory.get(j);
-            if (!ar.finishing && ar.task.taskId == taskId) {
-                thumbs.root = ar;
-                thumbs.rootIndex = j;
-                holder = ar.thumbHolder;
-                if (holder != null) {
-                    thumbs.mainThumbnail = holder.lastThumbnail;
-                }
-                j++;
-                break;
-            }
-            j++;
-        }
-
-        if (j >= NA) {
-            return thumbs;
-        }
-
-        ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
-        thumbs.subtasks = subtasks;
-        while (j < NA) {
-            ActivityRecord ar = mHistory.get(j);
-            j++;
-            if (ar.finishing) {
-                continue;
-            }
-            if (ar.task.taskId != taskId) {
-                break;
-            }
-            if (ar.thumbHolder != holder && holder != null) {
-                thumbs.numSubThumbbails++;
-                holder = ar.thumbHolder;
-                TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
-                sub.holder = holder;
-                sub.activity = ar;
-                sub.index = j-1;
-                subtasks.add(sub);
-            }
-        }
-        if (thumbs.numSubThumbbails > 0) {
-            thumbs.retriever = new IThumbnailRetriever.Stub() {
-                public Bitmap getThumbnail(int index) {
-                    if (index < 0 || index >= thumbs.subtasks.size()) {
-                        return null;
-                    }
-                    TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index);
-                    ActivityRecord resumed = mResumedActivity;
-                    if (resumed != null && resumed.thumbHolder == sub.holder) {
-                        return resumed.stack.screenshotActivities(resumed);
-                    }
-                    return sub.holder.lastThumbnail;
-                }
-            };
-        }
-        return thumbs;
-    }
-
-    private final void logStartActivity(int tag, ActivityRecord r,
+    static final void logStartActivity(int tag, ActivityRecord r,
             TaskRecord task) {
         final Uri data = r.intent.getData();
         final String strData = data != null ? data.toSafeString() : null;
@@ -4626,10 +3116,10 @@
                     "Skipping config check (will change): " + r);
             return true;
         }
-        
+
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                 "Ensuring correct configuration: " + r);
-        
+
         // Short circuit: if the two configurations are the exact same
         // object (the common case), then there is nothing to do.
         Configuration newConfig = mService.mConfiguration;
@@ -4638,7 +3128,7 @@
                     "Configuration unchanged in " + r);
             return true;
         }
-        
+
         // We don't worry about activities that are finishing.
         if (r.finishing) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
@@ -4646,7 +3136,7 @@
             r.stopFreezingScreenLocked(false);
             return true;
         }
-        
+
         // Okay we now are going to make this activity have the new config.
         // But then we need to figure out how it needs to deal with that.
         Configuration oldConfig = r.configuration;
@@ -4672,7 +3162,7 @@
             r.forceNewConfig = false;
             return true;
         }
-        
+
         // Figure out how to handle the changes between the configurations.
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
             Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
@@ -4712,12 +3202,12 @@
                 relaunchActivityLocked(r, r.configChangeFlags, false);
                 r.configChangeFlags = 0;
             }
-            
+
             // All done...  tell the caller we weren't able to keep this
             // activity around.
             return false;
         }
-        
+
         // Default case: the activity can handle this new configuration, so
         // hand it over.  Note that we don't need to give it the new
         // configuration, since we always send configuration changes to all
@@ -4732,11 +3222,11 @@
             }
         }
         r.stopFreezingScreenLocked(false);
-        
+
         return true;
     }
 
-    private final boolean relaunchActivityLocked(ActivityRecord r,
+    private boolean relaunchActivityLocked(ActivityRecord r,
             int changes, boolean andResume) {
         List<ResultInfo> results = null;
         List<Intent> newIntents = null;
@@ -4750,9 +3240,9 @@
         EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
                 : EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
                 r.task.taskId, r.shortComponentName);
-        
+
         r.startFreezingScreenLocked(r.app, 0);
-        
+
         try {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
                     (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
@@ -4770,9 +3260,6 @@
         if (andResume) {
             r.results = null;
             r.newIntents = null;
-            if (mMainStack) {
-                mService.reportResumedActivityLocked(r);
-            }
             r.state = ActivityState.RESUMED;
         } else {
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
@@ -4781,8 +3268,318 @@
 
         return true;
     }
-    
-    public void dismissKeyguardOnNextActivityLocked() {
-        mDismissKeyguardOnNextActivity = true;
+
+    boolean willActivityBeVisibleLocked(IBinder token) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.appToken == token) {
+                        return true;
+                }
+                if (r.fullscreen && !r.finishing) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    void closeSystemDialogsLocked() {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
+                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "close-sys", true);
+                }
+            }
+        }
+    }
+
+    boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
+        boolean didSomething = false;
+        TaskRecord lastTask = null;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            int numActivities = activities.size();
+            for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+                ActivityRecord r = activities.get(activityNdx);
+                final boolean samePackage = r.packageName.equals(name)
+                        || (name == null && r.userId == userId);
+                if ((userId == UserHandle.USER_ALL || r.userId == userId)
+                        && (samePackage || r.task == lastTask)
+                        && (r.app == null || evenPersistent || !r.app.persistent)) {
+                    if (!doit) {
+                        if (r.finishing) {
+                            // If this activity is just finishing, then it is not
+                            // interesting as far as something to stop.
+                            continue;
+                        }
+                        return true;
+                    }
+                    didSomething = true;
+                    Slog.i(TAG, "  Force finishing activity " + r);
+                    if (samePackage) {
+                        if (r.app != null) {
+                            r.app.removed = true;
+                        }
+                        r.app = null;
+                    }
+                    lastTask = r.task;
+                    if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
+                            true)) {
+                        // r has been deleted from mActivities, accommodate.
+                        --numActivities;
+                        --activityNdx;
+                    }
+                }
+            }
+        }
+        return didSomething;
+    }
+
+    ActivityRecord getTasksLocked(IThumbnailReceiver receiver,
+            PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
+        ActivityRecord topRecord = null;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            ActivityRecord r = null;
+            ActivityRecord top = null;
+            int numActivities = 0;
+            int numRunning = 0;
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                r = activities.get(activityNdx);
+
+                // Initialize state for next task if needed.
+                if (top == null || (top.state == ActivityState.INITIALIZING)) {
+                    top = r;
+                    numActivities = numRunning = 0;
+                }
+
+                // Add 'r' into the current task.
+                numActivities++;
+                if (r.app != null && r.app.thread != null) {
+                    numRunning++;
+                }
+
+                if (localLOGV) Slog.v(
+                    TAG, r.intent.getComponent().flattenToShortString()
+                    + ": task=" + r.task);
+            }
+
+            RunningTaskInfo ci = new RunningTaskInfo();
+            ci.id = task.taskId;
+            ci.baseActivity = r.intent.getComponent();
+            ci.topActivity = top.intent.getComponent();
+            ci.lastActiveTime = task.lastActiveTime;
+
+            if (top.thumbHolder != null) {
+                ci.description = top.thumbHolder.lastDescription;
+            }
+            ci.numActivities = numActivities;
+            ci.numRunning = numRunning;
+            //System.out.println(
+            //    "#" + maxNum + ": " + " descr=" + ci.description);
+            if (receiver != null) {
+                if (localLOGV) Slog.v(
+                    TAG, "State=" + top.state + "Idle=" + top.idle
+                    + " app=" + top.app
+                    + " thr=" + (top.app != null ? top.app.thread : null));
+                if (top.state == ActivityState.RESUMED || top.state == ActivityState.PAUSING) {
+                    if (top.idle && top.app != null && top.app.thread != null) {
+                        topRecord = top;
+                    } else {
+                        top.thumbnailNeeded = true;
+                    }
+                }
+                pending.pendingRecords.add(top);
+            }
+            list.add(ci);
+        }
+        return topRecord;
+    }
+
+    public void unhandledBackLocked() {
+        final int top = mTaskHistory.size() - 1;
+        if (DEBUG_SWITCH) Slog.d(
+            TAG, "Performing unhandledBack(): top activity at " + top);
+        if (top >= 0) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities;
+            int activityTop = activities.size() - 1;
+            if (activityTop > 0) {
+                finishActivityLocked(activities.get(activityTop), Activity.RESULT_CANCELED, null,
+                        "unhandled-back", true);
+            }
+        }
+    }
+
+    /**
+     * Reset local parameters because an app's activity died.
+     * @param app The app of the activity that died.
+     * @return true if home should be launched next.
+     */
+    boolean handleAppDiedLocked(ProcessRecord app) {
+        if (!containsApp(app)) {
+            return false;
+        }
+
+        if (mPausingActivity != null && mPausingActivity.app == app) {
+            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
+                    "App died while pausing: " + mPausingActivity);
+            mPausingActivity = null;
+        }
+        if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
+            mLastPausedActivity = null;
+            mLastNoHistoryActivity = null;
+        }
+
+        // Determine if the top task is exiting and should return to home. Do this before it gets
+        // removed in removeHistoryRecordsForAppsLocked.
+        boolean launchHomeNext = false;
+        TaskRecord topTask = mTaskHistory.get(mTaskHistory.size() - 1);
+        ArrayList<ActivityRecord> activities = topTask.mActivities;
+        int activityNdx;
+        for (activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord r = activities.get(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            if (r.app != app) {
+                // This is the dying activity.
+                break;
+            }
+        }
+        if (activityNdx < 0) {
+            // All activities in task belong to app. Set launchHomeNext to task's value.
+            launchHomeNext = topTask.mOnTopOfHome;
+        }
+
+        removeHistoryRecordsForAppLocked(app);
+
+        return launchHomeNext;
+    }
+
+    void handleAppCrashLocked(ProcessRecord app) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.app == app) {
+                    Slog.w(TAG, "  Force finishing activity "
+                            + r.intent.getComponent().flattenToShortString());
+                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
+                }
+            }
+        }
+    }
+
+    boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+            boolean dumpClient, String dumpPackage, boolean needSep, String header) {
+        boolean printed = false;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw,
+                    mTaskHistory.get(taskNdx).mActivities, "    ", "Hist", true, !dumpAll,
+                    dumpClient, dumpPackage, needSep, header,
+                    "    Task id #" + task.taskId);
+            if (printed) {
+                header = null;
+            }
+        }
+        return printed;
+    }
+
+    ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
+        ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+
+        if ("all".equals(name)) {
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                activities.addAll(mTaskHistory.get(taskNdx).mActivities);
+            }
+        } else if ("top".equals(name)) {
+            final int top = mTaskHistory.size() - 1;
+            if (top >= 0) {
+                final ArrayList<ActivityRecord> list = mTaskHistory.get(top).mActivities;
+                int listTop = list.size() - 1;
+                if (listTop >= 0) {
+                    activities.add(list.get(listTop));
+                }
+            }
+        } else {
+            ItemMatcher matcher = new ItemMatcher();
+            matcher.build(name);
+
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                for (ActivityRecord r1 : mTaskHistory.get(taskNdx).mActivities) {
+                    if (matcher.match(r1, r1.intent.getComponent())) {
+                        activities.add(r1);
+                    }
+                }
+            }
+        }
+
+        return activities;
+    }
+
+    ActivityRecord restartPackage(String packageName) {
+        ActivityRecord starting = topRunningActivityLocked(null);
+
+        // All activities that came from the package must be
+        // restarted as if there was a config change.
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord a = activities.get(activityNdx);
+                if (a.info.packageName.equals(packageName)) {
+                    a.forceNewConfig = true;
+                    if (starting != null && a == starting && a.visible) {
+                        a.startFreezingScreenLocked(starting.app,
+                                ActivityInfo.CONFIG_SCREEN_LAYOUT);
+                    }
+                }
+            }
+        }
+
+        return starting;
+    }
+
+    boolean removeTask(TaskRecord task) {
+        final int taskNdx = mTaskHistory.indexOf(task);
+        final int topTaskNdx = mTaskHistory.size() - 1;
+        if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
+            mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
+        }
+        mTaskHistory.remove(task);
+        return mTaskHistory.isEmpty();
+    }
+
+    TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
+        TaskRecord task = new TaskRecord(taskId, info, intent);
+        addTask(task, toTop);
+        return task;
+    }
+
+    ArrayList<TaskRecord> getAllTasks() {
+        return new ArrayList<TaskRecord>(mTaskHistory);
+    }
+
+    void addTask(final TaskRecord task, final boolean toTop) {
+        task.stack = this;
+        if (toTop) {
+            insertTaskAtTop(task);
+        } else {
+            mTaskHistory.add(0, task);
+        }
+    }
+
+    public int getStackId() {
+        return mStackId;
+    }
+
+    @Override
+    public String toString() {
+        return "stackId=" + mStackId + " tasks=" + mTaskHistory;
     }
 }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
new file mode 100644
index 0000000..2b69a4e
--- /dev/null
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -0,0 +1,2640 @@
+/*
+ * 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.am;
+
+import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.server.am.ActivityManagerService.localLOGV;
+import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
+import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
+import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.am.ActivityManagerService.TAG;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.AppGlobals;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.IThumbnailReceiver;
+import android.app.PendingIntent;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityManager.WaitResult;
+import android.app.ResultInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.EventLog;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.os.TransferPipe;
+import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
+import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.wm.StackBox;
+import com.android.server.wm.WindowManagerService;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class ActivityStackSupervisor {
+    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 || true;
+    static final boolean DEBUG_IDLE = DEBUG || false;
+
+    public static final int HOME_STACK_ID = 0;
+
+    /** How long we wait until giving up on the last activity telling us it is idle. */
+    static final int IDLE_TIMEOUT = 10*1000;
+
+    /** How long we can hold the sleep wake lock before giving up. */
+    static final int SLEEP_TIMEOUT = 5*1000;
+
+    // How long we can hold the launch wake lock before giving up.
+    static final int LAUNCH_TIMEOUT = 10*1000;
+
+    static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG;
+    static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_STACK_MSG + 1;
+    static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
+    static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
+    static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
+
+    // For debugging to make sure the caller when acquiring/releasing our
+    // wake lock is the system process.
+    static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
+
+    final ActivityManagerService mService;
+    final Context mContext;
+    final Looper mLooper;
+
+    final ActivityStackSupervisorHandler mHandler;
+
+    /** Short cut */
+    WindowManagerService mWindowManager;
+
+    /** Dismiss the keyguard after the next activity is displayed? */
+    boolean mDismissKeyguardOnNextActivity = false;
+
+    /** Identifier counter for all ActivityStacks */
+    private int mLastStackId = HOME_STACK_ID;
+
+    /** Task identifier that activities are currently being started in.  Incremented each time a
+     * new task is created. */
+    private int mCurTaskId = 0;
+
+    /** The current user */
+    private int mCurrentUser;
+
+    /** The stack containing the launcher app */
+    private ActivityStack mHomeStack;
+
+    /** The non-home stack currently receiving input or launching the next activity. If home is
+     * in front then mHomeStack overrides mFocusedStack.
+     * DO NOT ACCESS DIRECTLY - It may be null, use getFocusedStack() */
+    private ActivityStack mFocusedStack;
+
+    /** All the non-launcher stacks */
+    private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
+
+    private static final int STACK_STATE_HOME_IN_FRONT = 0;
+    private static final int STACK_STATE_HOME_TO_BACK = 1;
+    private static final int STACK_STATE_HOME_IN_BACK = 2;
+    private static final int STACK_STATE_HOME_TO_FRONT = 3;
+    private int mStackState = STACK_STATE_HOME_IN_FRONT;
+
+    /** List of activities that are waiting for a new activity to become visible before completing
+     * whatever operation they are supposed to do. */
+    final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<ActivityRecord>();
+
+    /** List of processes waiting to find out about the next visible activity. */
+    final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible =
+            new ArrayList<IActivityManager.WaitResult>();
+
+    /** List of processes waiting to find out about the next launched activity. */
+    final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched =
+            new ArrayList<IActivityManager.WaitResult>();
+
+    /** List of activities that are ready to be stopped, but waiting for the next activity to
+     * settle down before doing so. */
+    final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<ActivityRecord>();
+
+    /** List of activities that are ready to be finished, but waiting for the previous activity to
+     * settle down before doing so.  It contains ActivityRecord objects. */
+    final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<ActivityRecord>();
+
+    /** List of activities that are in the process of going to sleep. */
+    final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<ActivityRecord>();
+
+    /** List of ActivityRecord objects that have been finished and must still report back to a
+     * pending thumbnail receiver. */
+    final ArrayList<ActivityRecord> mCancelledThumbnails = new ArrayList<ActivityRecord>();
+
+    /** Used on user changes */
+    final ArrayList<UserStartedState> mStartingUsers = new ArrayList<UserStartedState>();
+
+    /** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
+     * is being brought in front of us. */
+    boolean mUserLeaving = false;
+
+    /** Set when we have taken too long waiting to go to sleep. */
+    boolean mSleepTimeout = false;
+
+    /**
+     * We don't want to allow the device to go to sleep while in the process
+     * of launching an activity.  This is primarily to allow alarm intent
+     * receivers to launch an activity and get that to run before the device
+     * goes back to sleep.
+     */
+    final PowerManager.WakeLock mLaunchingActivity;
+
+    /**
+     * Set when the system is going to sleep, until we have
+     * successfully paused the current activity and released our wake lock.
+     * At that point the system is allowed to actually sleep.
+     */
+    final PowerManager.WakeLock mGoingToSleep;
+
+    public ActivityStackSupervisor(ActivityManagerService service, Context context,
+            Looper looper) {
+        mService = service;
+        mContext = context;
+        mLooper = looper;
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
+        mHandler = new ActivityStackSupervisorHandler(looper);
+        if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+            throw new IllegalStateException("Calling must be system uid");
+        }
+        mLaunchingActivity =
+                pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
+        mLaunchingActivity.setReferenceCounted(false);
+    }
+
+    void setWindowManager(WindowManagerService wm) {
+        mWindowManager = wm;
+        mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID);
+        mStacks.add(mHomeStack);
+    }
+
+    void dismissKeyguard() {
+        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+        if (mDismissKeyguardOnNextActivity) {
+            mDismissKeyguardOnNextActivity = false;
+            mWindowManager.dismissKeyguard();
+        }
+    }
+
+    ActivityStack getFocusedStack() {
+        if (mFocusedStack == null) {
+            return mHomeStack;
+        }
+        switch (mStackState) {
+            case STACK_STATE_HOME_IN_FRONT:
+            case STACK_STATE_HOME_TO_FRONT:
+                return mHomeStack;
+            case STACK_STATE_HOME_IN_BACK:
+            case STACK_STATE_HOME_TO_BACK:
+            default:
+                return mFocusedStack;
+        }
+    }
+
+    ActivityStack getLastStack() {
+        switch (mStackState) {
+            case STACK_STATE_HOME_IN_FRONT:
+            case STACK_STATE_HOME_TO_BACK:
+                return mHomeStack;
+            case STACK_STATE_HOME_TO_FRONT:
+            case STACK_STATE_HOME_IN_BACK:
+            default:
+                return mFocusedStack;
+        }
+    }
+
+    boolean isFrontStack(ActivityStack stack) {
+        return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
+    }
+
+    void moveHomeStack(boolean toFront) {
+        final boolean homeInFront = isFrontStack(mHomeStack);
+        if (homeInFront ^ toFront) {
+            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: mStackState old=" +
+                    stackStateToString(mStackState) + " new=" + stackStateToString(homeInFront ?
+                    STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT));
+            mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT;
+        }
+    }
+
+    boolean resumeHomeActivity(ActivityRecord prev) {
+        moveHomeStack(true);
+        if (prev != null) {
+            prev.task.mOnTopOfHome = false;
+        }
+        mHomeStack.moveHomeTaskToTop();
+        ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
+        if (r != null) {
+            mService.setFocusedActivityLocked(r);
+            return resumeTopActivitiesLocked(mHomeStack, prev, null);
+        }
+        return mService.startHomeActivityLocked(mCurrentUser);
+    }
+
+    final void setLaunchHomeTaskNextFlag(ActivityRecord sourceRecord, ActivityRecord r,
+            ActivityStack stack) {
+        if (stack == mHomeStack) {
+            return;
+        }
+        if ((sourceRecord == null && getLastStack() == mHomeStack) ||
+                (sourceRecord != null && sourceRecord.isHomeActivity())) {
+            if (r == null) {
+                r = stack.topRunningActivityLocked(null);
+            }
+            if (r != null && !r.isHomeActivity() && r.isRootActivity()) {
+                r.task.mOnTopOfHome = true;
+            }
+        }
+    }
+
+    void setDismissKeyguard(boolean dismiss) {
+        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(" dismiss=" + dismiss);
+        mDismissKeyguardOnNextActivity = dismiss;
+    }
+
+    TaskRecord anyTaskForIdLocked(int id) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            ActivityStack stack = mStacks.get(stackNdx);
+            TaskRecord task = stack.taskForIdLocked(id);
+            if (task != null) {
+                return task;
+            }
+        }
+        return null;
+    }
+
+    ActivityRecord isInAnyStackLocked(IBinder token) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token);
+            if (r != null) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+    int getNextTaskId() {
+        do {
+            mCurTaskId++;
+            if (mCurTaskId <= 0) {
+                mCurTaskId = 1;
+            }
+        } while (anyTaskForIdLocked(mCurTaskId) != null);
+        return mCurTaskId;
+    }
+
+    void removeTask(TaskRecord task) {
+        mWindowManager.removeTask(task.taskId);
+        final ActivityStack stack = task.stack;
+        final ActivityRecord r = stack.mResumedActivity;
+        if (r != null && r.task == task) {
+            stack.mResumedActivity = null;
+        }
+        if (stack.removeTask(task) && !stack.isHomeStack()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack);
+            mStacks.remove(stack);
+            final int stackId = stack.mStackId;
+            final int nextStackId = mWindowManager.removeStack(stackId);
+            // TODO: Perhaps we need to let the ActivityManager determine the next focus...
+            if (mFocusedStack == null || mFocusedStack.mStackId == stackId) {
+                // If this is the last app stack, set mFocusedStack to null.
+                mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);
+            }
+        }
+    }
+
+    ActivityRecord resumedAppLocked() {
+        ActivityStack stack = getFocusedStack();
+        if (stack == null) {
+            return null;
+        }
+        ActivityRecord resumedActivity = stack.mResumedActivity;
+        if (resumedActivity == null || resumedActivity.app == null) {
+            resumedActivity = stack.mPausingActivity;
+            if (resumedActivity == null || resumedActivity.app == null) {
+                resumedActivity = stack.topRunningActivityLocked(null);
+            }
+        }
+        return resumedActivity;
+    }
+
+    boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
+        boolean didSomething = false;
+        final String processName = app.processName;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (!isFrontStack(stack)) {
+                continue;
+            }
+            ActivityRecord hr = stack.topRunningActivityLocked(null);
+            if (hr != null) {
+                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
+                        && processName.equals(hr.processName)) {
+                    try {
+                        if (headless) {
+                            Slog.e(TAG, "Starting activities not supported on headless device: "
+                                    + hr);
+                        } else if (realStartActivityLocked(hr, app, true, true)) {
+                            didSomething = true;
+                        }
+                    } catch (Exception e) {
+                        Slog.w(TAG, "Exception in new application when starting activity "
+                              + hr.intent.getComponent().flattenToShortString(), e);
+                        throw e;
+                    }
+                }
+            }
+        }
+        if (!didSomething) {
+            ensureActivitiesVisibleLocked(null, 0);
+        }
+        return didSomething;
+    }
+
+    boolean allResumedActivitiesIdle() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (!isFrontStack(stack)) {
+                continue;
+            }
+            final ActivityRecord resumedActivity = stack.mResumedActivity;
+            if (resumedActivity == null || !resumedActivity.idle) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    boolean allResumedActivitiesComplete() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (isFrontStack(stack)) {
+                final ActivityRecord r = stack.mResumedActivity;
+                if (r != null && r.state != ActivityState.RESUMED) {
+                    return false;
+                }
+            }
+        }
+        // TODO: Not sure if this should check if all Paused are complete too.
+        switch (mStackState) {
+            case STACK_STATE_HOME_TO_BACK:
+                if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" +
+                        stackStateToString(STACK_STATE_HOME_TO_BACK) + " new=" +
+                        stackStateToString(STACK_STATE_HOME_IN_BACK));
+                mStackState = STACK_STATE_HOME_IN_BACK;
+                break;
+            case STACK_STATE_HOME_TO_FRONT:
+                if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" +
+                        stackStateToString(STACK_STATE_HOME_TO_FRONT) + " new=" +
+                        stackStateToString(STACK_STATE_HOME_IN_FRONT));
+                mStackState = STACK_STATE_HOME_IN_FRONT;
+                break;
+        }
+        return true;
+    }
+
+    boolean allResumedActivitiesVisible() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            final ActivityRecord r = stack.mResumedActivity;
+            if (r != null && (!r.nowVisible || r.waitingVisible)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Pause all activities in either all of the stacks or just the back stacks.
+     * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
+     * @return true if any activity was paused as a result of this call.
+     */
+    boolean pauseBackStacks(boolean userLeaving) {
+        boolean someActivityPaused = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (!isFrontStack(stack) && stack.mResumedActivity != null) {
+                if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack +
+                        " mResumedActivity=" + stack.mResumedActivity);
+                stack.startPausingLocked(userLeaving, false);
+                someActivityPaused = true;
+            }
+        }
+        return someActivityPaused;
+    }
+
+    boolean allPausedActivitiesComplete() {
+        boolean pausing = true;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            final ActivityRecord r = stack.mPausingActivity;
+            if (r != null && r.state != ActivityState.PAUSED
+                    && r.state != ActivityState.STOPPED
+                    && r.state != ActivityState.STOPPING) {
+                if (DEBUG_STATES) {
+                    Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
+                    pausing = false;
+                } else {
+                    return false;
+                }
+            }
+        }
+        return pausing;
+    }
+
+    void reportActivityVisibleLocked(ActivityRecord r) {
+        for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) {
+            WaitResult w = mWaitingActivityVisible.get(i);
+            w.timeout = false;
+            if (r != null) {
+                w.who = new ComponentName(r.info.packageName, r.info.name);
+            }
+            w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
+            w.thisTime = w.totalTime;
+        }
+        mService.notifyAll();
+        dismissKeyguard();
+    }
+
+    void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
+            long thisTime, long totalTime) {
+        for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
+            WaitResult w = mWaitingActivityLaunched.remove(i);
+            w.timeout = timeout;
+            if (r != null) {
+                w.who = new ComponentName(r.info.packageName, r.info.name);
+            }
+            w.thisTime = thisTime;
+            w.totalTime = totalTime;
+        }
+        mService.notifyAll();
+    }
+
+    ActivityRecord topRunningActivityLocked() {
+        final ActivityStack focusedStack = getFocusedStack();
+        ActivityRecord r = focusedStack.topRunningActivityLocked(null);
+        if (r != null) {
+            return r;
+        }
+
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack != focusedStack && isFrontStack(stack)) {
+                r = stack.topRunningActivityLocked(null);
+                if (r != null) {
+                    return r;
+                }
+            }
+        }
+        return null;
+    }
+
+    ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
+            PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
+        ActivityRecord r = null;
+
+        // Gather all of the running tasks for each stack into runningTaskLists.
+        final int numStacks = mStacks.size();
+        ArrayList<RunningTaskInfo>[] runningTaskLists = new ArrayList[numStacks];
+        for (int stackNdx = numStacks - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
+            runningTaskLists[stackNdx] = stackTaskList;
+            final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
+            if (isFrontStack(stack)) {
+                r = ar;
+            }
+        }
+
+        // The lists are already sorted from most recent to oldest. Just pull the most recent off
+        // each list and add it to list. Stop when all lists are empty or maxNum reached.
+        while (maxNum > 0) {
+            long mostRecentActiveTime = Long.MIN_VALUE;
+            ArrayList<RunningTaskInfo> selectedStackList = null;
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists[stackNdx];
+                if (!stackTaskList.isEmpty()) {
+                    final long lastActiveTime = stackTaskList.get(0).lastActiveTime;
+                    if (lastActiveTime > mostRecentActiveTime) {
+                        mostRecentActiveTime = lastActiveTime;
+                        selectedStackList = stackTaskList;
+                    }
+                }
+            }
+            if (selectedStackList != null) {
+                list.add(selectedStackList.remove(0));
+                --maxNum;
+            } else {
+                break;
+            }
+        }
+
+        return r;
+    }
+
+    ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
+            String profileFile, ParcelFileDescriptor profileFd, int userId) {
+        // Collect information about the target of the Intent.
+        ActivityInfo aInfo;
+        try {
+            ResolveInfo rInfo =
+                AppGlobals.getPackageManager().resolveIntent(
+                        intent, resolvedType,
+                        PackageManager.MATCH_DEFAULT_ONLY
+                                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
+            aInfo = rInfo != null ? rInfo.activityInfo : null;
+        } catch (RemoteException e) {
+            aInfo = null;
+        }
+
+        if (aInfo != null) {
+            // Store the found target back into the intent, because now that
+            // we have it we never want to do this again.  For example, if the
+            // user navigates back to this point in the history, we should
+            // always restart the exact same activity.
+            intent.setComponent(new ComponentName(
+                    aInfo.applicationInfo.packageName, aInfo.name));
+
+            // Don't debug things in the system process
+            if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) {
+                if (!aInfo.processName.equals("system")) {
+                    mService.setDebugApp(aInfo.processName, true, false);
+                }
+            }
+
+            if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) {
+                if (!aInfo.processName.equals("system")) {
+                    mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
+                }
+            }
+
+            if (profileFile != null) {
+                if (!aInfo.processName.equals("system")) {
+                    mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
+                            profileFile, profileFd,
+                            (startFlags&ActivityManager.START_FLAG_AUTO_STOP_PROFILER) != 0);
+                }
+            }
+        }
+        return aInfo;
+    }
+
+    void startHomeActivity(Intent intent, ActivityInfo aInfo) {
+        moveHomeStack(true);
+        startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
+                null, false, null);
+    }
+
+    final int startActivityMayWait(IApplicationThread caller, int callingUid,
+            String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
+            String resultWho, int requestCode, int startFlags, String profileFile,
+            ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
+            Bundle options, int userId) {
+        // Refuse possible leaked file descriptors
+        if (intent != null && intent.hasFileDescriptors()) {
+            throw new IllegalArgumentException("File descriptors passed in Intent");
+        }
+        boolean componentSpecified = intent.getComponent() != null;
+
+        // Don't modify the client's object!
+        intent = new Intent(intent);
+
+        // Collect information about the target of the Intent.
+        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
+                profileFile, profileFd, userId);
+
+        synchronized (mService) {
+            int callingPid;
+            if (callingUid >= 0) {
+                callingPid = -1;
+            } else if (caller == null) {
+                callingPid = Binder.getCallingPid();
+                callingUid = Binder.getCallingUid();
+            } else {
+                callingPid = callingUid = -1;
+            }
+
+            final ActivityStack stack = getFocusedStack();
+            stack.mConfigWillChange = config != null
+                    && mService.mConfiguration.diff(config) != 0;
+            if (DEBUG_CONFIGURATION) Slog.v(TAG,
+                    "Starting activity when config will change = " + stack.mConfigWillChange);
+
+            final long origId = Binder.clearCallingIdentity();
+
+            if (aInfo != null &&
+                    (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+                // This may be a heavy-weight process!  Check to see if we already
+                // have another, different heavy-weight process running.
+                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
+                    if (mService.mHeavyWeightProcess != null &&
+                            (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
+                            !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
+                        int realCallingUid = callingUid;
+                        if (caller != null) {
+                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
+                            if (callerApp != null) {
+                                realCallingUid = callerApp.info.uid;
+                            } else {
+                                Slog.w(TAG, "Unable to find app for caller " + caller
+                                      + " (pid=" + callingPid + ") when starting: "
+                                      + intent.toString());
+                                ActivityOptions.abort(options);
+                                return ActivityManager.START_PERMISSION_DENIED;
+                            }
+                        }
+
+                        IIntentSender target = mService.getIntentSenderLocked(
+                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",
+                                realCallingUid, userId, null, null, 0, new Intent[] { intent },
+                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
+                                | PendingIntent.FLAG_ONE_SHOT, null);
+
+                        Intent newIntent = new Intent();
+                        if (requestCode >= 0) {
+                            // Caller is requesting a result.
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
+                        }
+                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
+                                new IntentSender(target));
+                        if (mService.mHeavyWeightProcess.activities.size() > 0) {
+                            ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
+                                    hist.packageName);
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
+                                    hist.task.taskId);
+                        }
+                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
+                                aInfo.packageName);
+                        newIntent.setFlags(intent.getFlags());
+                        newIntent.setClassName("android",
+                                HeavyWeightSwitcherActivity.class.getName());
+                        intent = newIntent;
+                        resolvedType = null;
+                        caller = null;
+                        callingUid = Binder.getCallingUid();
+                        callingPid = Binder.getCallingPid();
+                        componentSpecified = true;
+                        try {
+                            ResolveInfo rInfo =
+                                AppGlobals.getPackageManager().resolveIntent(
+                                        intent, null,
+                                        PackageManager.MATCH_DEFAULT_ONLY
+                                        | ActivityManagerService.STOCK_PM_FLAGS, userId);
+                            aInfo = rInfo != null ? rInfo.activityInfo : null;
+                            aInfo = mService.getActivityInfoForUser(aInfo, userId);
+                        } catch (RemoteException e) {
+                            aInfo = null;
+                        }
+                    }
+                }
+            }
+
+            int res = startActivityLocked(caller, intent, resolvedType,
+                    aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
+                    callingPackage, startFlags, options, componentSpecified, null);
+
+            if (stack.mConfigWillChange) {
+                // If the caller also wants to switch to a new configuration,
+                // do so now.  This allows a clean switch, as we are waiting
+                // for the current activity to pause (so we will not destroy
+                // it), and have not yet started the next activity.
+                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                        "updateConfiguration()");
+                stack.mConfigWillChange = false;
+                if (DEBUG_CONFIGURATION) Slog.v(TAG,
+                        "Updating to new configuration after starting activity.");
+                mService.updateConfigurationLocked(config, null, false, false);
+            }
+
+            Binder.restoreCallingIdentity(origId);
+
+            if (outResult != null) {
+                outResult.result = res;
+                if (res == ActivityManager.START_SUCCESS) {
+                    mWaitingActivityLaunched.add(outResult);
+                    do {
+                        try {
+                            mService.wait();
+                        } catch (InterruptedException e) {
+                        }
+                    } while (!outResult.timeout && outResult.who == null);
+                } else if (res == ActivityManager.START_TASK_TO_FRONT) {
+                    ActivityRecord r = stack.topRunningActivityLocked(null);
+                    if (r.nowVisible) {
+                        outResult.timeout = false;
+                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
+                        outResult.totalTime = 0;
+                        outResult.thisTime = 0;
+                    } else {
+                        outResult.thisTime = SystemClock.uptimeMillis();
+                        mWaitingActivityVisible.add(outResult);
+                        do {
+                            try {
+                                mService.wait();
+                            } catch (InterruptedException e) {
+                            }
+                        } while (!outResult.timeout && outResult.who == null);
+                    }
+                }
+            }
+
+            return res;
+        }
+    }
+
+    final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
+            Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+            Bundle options, int userId) {
+        if (intents == null) {
+            throw new NullPointerException("intents is null");
+        }
+        if (resolvedTypes == null) {
+            throw new NullPointerException("resolvedTypes is null");
+        }
+        if (intents.length != resolvedTypes.length) {
+            throw new IllegalArgumentException("intents are length different than resolvedTypes");
+        }
+
+
+        int callingPid;
+        if (callingUid >= 0) {
+            callingPid = -1;
+        } else if (caller == null) {
+            callingPid = Binder.getCallingPid();
+            callingUid = Binder.getCallingUid();
+        } else {
+            callingPid = callingUid = -1;
+        }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mService) {
+                ActivityRecord[] outActivity = new ActivityRecord[1];
+                for (int i=0; i<intents.length; i++) {
+                    Intent intent = intents[i];
+                    if (intent == null) {
+                        continue;
+                    }
+
+                    // Refuse possible leaked file descriptors
+                    if (intent != null && intent.hasFileDescriptors()) {
+                        throw new IllegalArgumentException("File descriptors passed in Intent");
+                    }
+
+                    boolean componentSpecified = intent.getComponent() != null;
+
+                    // Don't modify the client's object!
+                    intent = new Intent(intent);
+
+                    // Collect information about the target of the Intent.
+                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i],
+                            0, null, null, userId);
+                    // TODO: New, check if this is correct
+                    aInfo = mService.getActivityInfoForUser(aInfo, userId);
+
+                    if (aInfo != null &&
+                            (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE)
+                                    != 0) {
+                        throw new IllegalArgumentException(
+                                "FLAG_CANT_SAVE_STATE not supported here");
+                    }
+
+                    Bundle theseOptions;
+                    if (options != null && i == intents.length-1) {
+                        theseOptions = options;
+                    } else {
+                        theseOptions = null;
+                    }
+                    int res = startActivityLocked(caller, intent, resolvedTypes[i],
+                            aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage,
+                            0, theseOptions, componentSpecified, outActivity);
+                    if (res < 0) {
+                        return res;
+                    }
+
+                    resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+
+        return ActivityManager.START_SUCCESS;
+    }
+
+    final boolean realStartActivityLocked(ActivityRecord r,
+            ProcessRecord app, boolean andResume, boolean checkConfig)
+            throws RemoteException {
+
+        r.startFreezingScreenLocked(app, 0);
+        if (true) Slog.d(TAG, "realStartActivity: setting app visibility true");
+        mWindowManager.setAppVisibility(r.appToken, true);
+
+        // schedule launch ticks to collect information about slow apps.
+        r.startLaunchTickingLocked();
+
+        // Have the window manager re-evaluate the orientation of
+        // the screen based on the new activity order.  Note that
+        // as a result of this, it can call back into the activity
+        // manager with a new orientation.  We don't care about that,
+        // because the activity is not currently running so we are
+        // just restarting it anyway.
+        if (checkConfig) {
+            Configuration config = mWindowManager.updateOrientationFromAppTokens(
+                    mService.mConfiguration,
+                    r.mayFreezeScreenLocked(app) ? r.appToken : null);
+            mService.updateConfigurationLocked(config, r, false, false);
+        }
+
+        r.app = app;
+        app.waitingToKill = null;
+        r.launchCount++;
+        r.lastLaunchTime = SystemClock.uptimeMillis();
+
+        if (localLOGV) Slog.v(TAG, "Launching: " + r);
+
+        int idx = app.activities.indexOf(r);
+        if (idx < 0) {
+            app.activities.add(r);
+        }
+        mService.updateLruProcessLocked(app, true, true);
+
+        final ActivityStack stack = r.task.stack;
+        try {
+            if (app.thread == null) {
+                throw new RemoteException();
+            }
+            List<ResultInfo> results = null;
+            List<Intent> newIntents = null;
+            if (andResume) {
+                results = r.results;
+                newIntents = r.newIntents;
+            }
+            if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
+                    + " icicle=" + r.icicle
+                    + " with results=" + results + " newIntents=" + newIntents
+                    + " andResume=" + andResume);
+            if (andResume) {
+                EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
+                        r.userId, System.identityHashCode(r),
+                        r.task.taskId, r.shortComponentName);
+            }
+            if (r.isHomeActivity() && r.isNotResolverActivity()) {
+                // Home process is the root process of the task.
+                mService.mHomeProcess = r.task.mActivities.get(0).app;
+            }
+            mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
+            r.sleeping = false;
+            r.forceNewConfig = false;
+            mService.showAskCompatModeDialogLocked(r);
+            r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
+            String profileFile = null;
+            ParcelFileDescriptor profileFd = null;
+            boolean profileAutoStop = false;
+            if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
+                if (mService.mProfileProc == null || mService.mProfileProc == app) {
+                    mService.mProfileProc = app;
+                    profileFile = mService.mProfileFile;
+                    profileFd = mService.mProfileFd;
+                    profileAutoStop = mService.mAutoStopProfiler;
+                }
+            }
+            app.hasShownUi = true;
+            app.pendingUiClean = true;
+            if (profileFd != null) {
+                try {
+                    profileFd = profileFd.dup();
+                } catch (IOException e) {
+                    if (profileFd != null) {
+                        try {
+                            profileFd.close();
+                        } catch (IOException o) {
+                        }
+                        profileFd = null;
+                    }
+                }
+            }
+            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
+            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
+                    System.identityHashCode(r), r.info,
+                    new Configuration(mService.mConfiguration), r.compat,
+                    app.repProcState, r.icicle, results, newIntents, !andResume,
+                    mService.isNextTransitionForward(), profileFile, profileFd,
+                    profileAutoStop);
+
+            if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+                // This may be a heavy-weight process!  Note that the package
+                // manager will ensure that only activity can run in the main
+                // process of the .apk, which is the only thing that will be
+                // considered heavy-weight.
+                if (app.processName.equals(app.info.packageName)) {
+                    if (mService.mHeavyWeightProcess != null
+                            && mService.mHeavyWeightProcess != app) {
+                        Slog.w(TAG, "Starting new heavy weight process " + app
+                                + " when already running "
+                                + mService.mHeavyWeightProcess);
+                    }
+                    mService.mHeavyWeightProcess = app;
+                    Message msg = mService.mHandler.obtainMessage(
+                            ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
+                    msg.obj = r;
+                    mService.mHandler.sendMessage(msg);
+                }
+            }
+
+        } catch (RemoteException e) {
+            if (r.launchFailed) {
+                // This is the second time we failed -- finish activity
+                // and give up.
+                Slog.e(TAG, "Second failure launching "
+                      + r.intent.getComponent().flattenToShortString()
+                      + ", giving up", e);
+                mService.appDiedLocked(app, app.pid, app.thread);
+                stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
+                        "2nd-crash", false);
+                return false;
+            }
+
+            // This is the first time we failed -- restart process and
+            // retry.
+            app.activities.remove(r);
+            throw e;
+        }
+
+        r.launchFailed = false;
+        if (stack.updateLRUListLocked(r)) {
+            Slog.w(TAG, "Activity " + r
+                  + " being launched, but already in LRU list");
+        }
+
+        if (andResume) {
+            // As part of the process of launching, ActivityThread also performs
+            // a resume.
+            stack.minimalResumeActivityLocked(r);
+        } else {
+            // This activity is not starting in the resumed state... which
+            // should look like we asked it to pause+stop (but remain visible),
+            // and it has done so and reported back the current icicle and
+            // other state.
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
+                    + " (starting in stopped state)");
+            r.state = ActivityState.STOPPED;
+            r.stopped = true;
+        }
+
+        // Launch the new version setup screen if needed.  We do this -after-
+        // launching the initial activity (that is, home), so that it can have
+        // a chance to initialize itself while in the background, making the
+        // switch back to it faster and look better.
+        if (isFrontStack(stack)) {
+            mService.startSetupActivityLocked();
+        }
+
+        return true;
+    }
+
+    void startSpecificActivityLocked(ActivityRecord r,
+            boolean andResume, boolean checkConfig) {
+        // Is this activity's application already running?
+        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
+                r.info.applicationInfo.uid, true);
+
+        r.task.stack.setLaunchTime(r);
+
+        if (app != null && app.thread != null) {
+            try {
+                app.addPackage(r.info.packageName, mService.mProcessStats);
+                realStartActivityLocked(r, app, andResume, checkConfig);
+                return;
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Exception when starting activity "
+                        + r.intent.getComponent().flattenToShortString(), e);
+            }
+
+            // If a dead object exception was thrown -- fall through to
+            // restart the application.
+        }
+
+        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
+                "activity", r.intent.getComponent(), false, false, true);
+    }
+
+    final int startActivityLocked(IApplicationThread caller,
+            Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
+            String resultWho, int requestCode,
+            int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
+            boolean componentSpecified, ActivityRecord[] outActivity) {
+        int err = ActivityManager.START_SUCCESS;
+
+        ProcessRecord callerApp = null;
+        if (caller != null) {
+            callerApp = mService.getRecordForAppLocked(caller);
+            if (callerApp != null) {
+                callingPid = callerApp.pid;
+                callingUid = callerApp.info.uid;
+            } else {
+                Slog.w(TAG, "Unable to find app for caller " + caller
+                      + " (pid=" + callingPid + ") when starting: "
+                      + intent.toString());
+                err = ActivityManager.START_PERMISSION_DENIED;
+            }
+        }
+
+        if (err == ActivityManager.START_SUCCESS) {
+            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
+            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+        }
+
+        ActivityRecord sourceRecord = null;
+        ActivityRecord resultRecord = null;
+        if (resultTo != null) {
+            sourceRecord = isInAnyStackLocked(resultTo);
+            if (DEBUG_RESULTS) Slog.v(
+                TAG, "Will send result to " + resultTo + " " + sourceRecord);
+            if (sourceRecord != null) {
+                if (requestCode >= 0 && !sourceRecord.finishing) {
+                    resultRecord = sourceRecord;
+                }
+            }
+        }
+        ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
+
+        int launchFlags = intent.getFlags();
+
+        if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
+                && sourceRecord != null) {
+            // Transfer the result target from the source activity to the new
+            // one being started, including any failures.
+            if (requestCode >= 0) {
+                ActivityOptions.abort(options);
+                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
+            }
+            resultRecord = sourceRecord.resultTo;
+            resultWho = sourceRecord.resultWho;
+            requestCode = sourceRecord.requestCode;
+            sourceRecord.resultTo = null;
+            if (resultRecord != null) {
+                resultRecord.removeResultsLocked(
+                    sourceRecord, resultWho, requestCode);
+            }
+        }
+
+        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
+            // We couldn't find a class that can handle the given Intent.
+            // That's the end of that!
+            err = ActivityManager.START_INTENT_NOT_RESOLVED;
+        }
+
+        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
+            // We couldn't find the specific class specified in the Intent.
+            // Also the end of the line.
+            err = ActivityManager.START_CLASS_NOT_FOUND;
+        }
+
+        if (err != ActivityManager.START_SUCCESS) {
+            if (resultRecord != null) {
+                resultStack.sendActivityResultLocked(-1,
+                    resultRecord, resultWho, requestCode,
+                    Activity.RESULT_CANCELED, null);
+            }
+            setDismissKeyguard(false);
+            ActivityOptions.abort(options);
+            return err;
+        }
+
+        final int startAnyPerm = mService.checkPermission(
+                START_ANY_ACTIVITY, callingPid, callingUid);
+        final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
+                callingUid, aInfo.applicationInfo.uid, aInfo.exported);
+        if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {
+            if (resultRecord != null) {
+                resultStack.sendActivityResultLocked(-1,
+                    resultRecord, resultWho, requestCode,
+                    Activity.RESULT_CANCELED, null);
+            }
+            setDismissKeyguard(false);
+            String msg;
+            if (!aInfo.exported) {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " not exported from uid " + aInfo.applicationInfo.uid;
+            } else {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " requires " + aInfo.permission;
+            }
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
+                callingPid, resolvedType, aInfo.applicationInfo);
+
+        if (mService.mController != null) {
+            try {
+                // The Intent we give to the watcher has the extra data
+                // stripped off, since it can contain private information.
+                Intent watchIntent = intent.cloneFilter();
+                abort |= !mService.mController.activityStarting(watchIntent,
+                        aInfo.applicationInfo.packageName);
+            } catch (RemoteException e) {
+                mService.mController = null;
+            }
+        }
+
+        if (abort) {
+            if (resultRecord != null) {
+                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
+                        Activity.RESULT_CANCELED, null);
+            }
+            // We pretend to the caller that it was really started, but
+            // they will just get a cancel result.
+            setDismissKeyguard(false);
+            ActivityOptions.abort(options);
+            return ActivityManager.START_SUCCESS;
+        }
+
+        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
+                intent, resolvedType, aInfo, mService.mConfiguration,
+                resultRecord, resultWho, requestCode, componentSpecified, this);
+        if (outActivity != null) {
+            outActivity[0] = r;
+        }
+
+        final ActivityStack stack = getFocusedStack();
+        if (stack.mResumedActivity == null
+                || stack.mResumedActivity.info.applicationInfo.uid != callingUid) {
+            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
+                PendingActivityLaunch pal =
+                        new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
+                mService.mPendingActivityLaunches.add(pal);
+                setDismissKeyguard(false);
+                ActivityOptions.abort(options);
+                return ActivityManager.START_SWITCHES_CANCELED;
+            }
+        }
+
+        if (mService.mDidAppSwitch) {
+            // This is the second allowed switch since we stopped switches,
+            // so now just generally allow switches.  Use case: user presses
+            // home (switches disabled, switch to home, mDidAppSwitch now true);
+            // user taps a home icon (coming from home so allowed, we hit here
+            // and now allow anyone to switch again).
+            mService.mAppSwitchesAllowedTime = 0;
+        } else {
+            mService.mDidAppSwitch = true;
+        }
+
+        mService.doPendingActivityLaunchesLocked(false);
+
+        err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
+
+        if (allPausedActivitiesComplete()) {
+            // If someone asked to have the keyguard dismissed on the next
+            // activity start, but we are not actually doing an activity
+            // switch...  just dismiss the keyguard now, because we
+            // probably want to see whatever is behind it.
+            dismissKeyguard();
+        }
+        return err;
+    }
+
+    ActivityStack adjustStackFocus(ActivityRecord r) {
+        final TaskRecord task = r.task;
+        if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) {
+            if (task != null) {
+                if (mFocusedStack != task.stack) {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                            "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task);
+                    mFocusedStack = task.stack;
+                } else {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                        "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                }
+                return mFocusedStack;
+            }
+
+            if (mFocusedStack != null) {
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
+                return mFocusedStack;
+            }
+
+            for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) {
+                ActivityStack stack = mStacks.get(stackNdx);
+                if (!stack.isHomeStack()) {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                            "adjustStackFocus: Setting focused stack=" + stack);
+                    mFocusedStack = stack;
+                    return mFocusedStack;
+                }
+            }
+
+            // Time to create the first app stack for this user.
+            int stackId = mService.createStack(-1, HOME_STACK_ID,
+                StackBox.TASK_STACK_GOES_OVER, 1.0f);
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
+                    " stackId=" + stackId);
+            mFocusedStack = getStack(stackId);
+            return mFocusedStack;
+        }
+        return mHomeStack;
+    }
+
+    void setFocusedStack(ActivityRecord r) {
+        if (r == null) {
+            return;
+        }
+        if (!r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask())) {
+            if (mStackState != STACK_STATE_HOME_IN_FRONT) {
+                if (DEBUG_STACK || DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: mStackState old=" +
+                        stackStateToString(mStackState) + " new=" +
+                        stackStateToString(STACK_STATE_HOME_TO_FRONT) +
+                        " Callers=" + Debug.getCallers(3));
+                mStackState = STACK_STATE_HOME_TO_FRONT;
+            }
+        } else {
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                    "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task +
+                    " Callers=" + Debug.getCallers(3));
+            mFocusedStack = r.task.stack;
+            if (mStackState != STACK_STATE_HOME_IN_BACK) {
+                if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" +
+                        stackStateToString(mStackState) + " new=" +
+                        stackStateToString(STACK_STATE_HOME_TO_BACK) +
+                        " Callers=" + Debug.getCallers(3));
+                mStackState = STACK_STATE_HOME_TO_BACK;
+            }
+        }
+    }
+
+    final int startActivityUncheckedLocked(ActivityRecord r,
+            ActivityRecord sourceRecord, int startFlags, boolean doResume,
+            Bundle options) {
+        final Intent intent = r.intent;
+        final int callingUid = r.launchedFromUid;
+
+        int launchFlags = intent.getFlags();
+
+        // 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;
+        if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
+
+        // If the caller has asked not to resume at this point, we make note
+        // of this in the record so that we can skip it when trying to find
+        // the top running activity.
+        if (!doResume) {
+            r.delayedResume = true;
+        }
+
+        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+
+        // If the onlyIfNeeded flag is set, then we can do this if the activity
+        // being launched is the same as the one making the call...  or, as
+        // a special case, if we do not know the caller then we count the
+        // current top activity as the caller.
+        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
+            ActivityRecord checkedCaller = sourceRecord;
+            if (checkedCaller == null) {
+                checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);
+            }
+            if (!checkedCaller.realActivity.equals(r.realActivity)) {
+                // Caller is not the same as launcher, so always needed.
+                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+            }
+        }
+
+        if (sourceRecord == null) {
+            // This activity is not being started from another...  in this
+            // case we -always- start a new task.
+            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+                Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
+                        "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
+                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+            }
+        } 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
+            // own task.
+            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
+                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
+            // The activity being started is a single instance...  it always
+            // gets launched into its own task.
+            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+        }
+
+        final ActivityStack sourceStack;
+        TaskRecord sourceTask;
+        if (sourceRecord != null) {
+            sourceTask = sourceRecord.task;
+            sourceStack = sourceTask.stack;
+        } else {
+            sourceTask = null;
+            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;
+        }
+
+        boolean addingToTask = false;
+        boolean movedHome = false;
+        TaskRecord reuseTask = null;
+        ActivityStack targetStack;
+        if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
+                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+            // If bring to front is requested, and no result is requested, and
+            // we can find a task that was started with this same
+            // component, then instead of launching bring that one to the front.
+            if (r.resultTo == null) {
+                // See if there is a task to bring to the front.  If this is
+                // a SINGLE_INSTANCE activity, there can be one and only one
+                // instance of it in the history, and it is always in its own
+                // unique task, so we do a special search.
+                ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
+                        ? findTaskLocked(r)
+                        : findActivityLocked(intent, r.info);
+                if (intentActivity != null) {
+                    if (r.task == null) {
+                        r.task = intentActivity.task;
+                    }
+                    targetStack = intentActivity.task.stack;
+                    targetStack.mLastPausedActivity = null;
+                    moveHomeStack(targetStack.isHomeStack());
+                    if (intentActivity.task.intent == null) {
+                        // This task was started because of movement of
+                        // the activity based on affinity...  now that we
+                        // are actually launching it, we can assign the
+                        // base intent.
+                        intentActivity.task.setIntent(intent, r.info);
+                    }
+                    // If the target task is not in the front, then we need
+                    // to bring it to the front...  except...  well, with
+                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
+                    // to have the same behavior as if a new instance was
+                    // being started, which means not bringing it to the front
+                    // if the caller is not itself in the front.
+                    final ActivityStack lastStack = getLastStack();
+                    ActivityRecord curTop = lastStack == null?
+                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);
+                    if (curTop != null && (curTop.task != intentActivity.task ||
+                            curTop.task != lastStack.topTask())) {
+                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
+                                sourceStack.topActivity().task == sourceRecord.task)) {
+                            // We really do want to push this one into the
+                            // user's face, right now.
+                            movedHome = true;
+                            if ((launchFlags &
+                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+                                // Caller wants to appear on home activity.
+                                intentActivity.task.mOnTopOfHome = true;
+                            }
+                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
+                            options = null;
+                        }
+                    }
+                    // If the caller has requested that the target task be
+                    // reset, then do so.
+                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
+                    }
+                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
+                        // We don't need to start a new activity, and
+                        // the client said not to do anything if that
+                        // is the case, so this is it!  And for paranoia, make
+                        // sure we have correctly resumed the top activity.
+                        if (doResume) {
+                            setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
+                            resumeTopActivitiesLocked(targetStack, null, options);
+                        } else {
+                            ActivityOptions.abort(options);
+                        }
+                        if (r.task == null)  Slog.v(TAG,
+                                "startActivityUncheckedLocked: task left null",
+                                new RuntimeException("here").fillInStackTrace());
+                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
+                    }
+                    if ((launchFlags &
+                            (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
+                            == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
+                        // The caller has requested to completely replace any
+                        // existing task with its new activity.  Well that should
+                        // not be too hard...
+                        reuseTask = intentActivity.task;
+                        reuseTask.performClearTaskLocked();
+                        reuseTask.setIntent(r.intent, r.info);
+                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
+                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
+                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+                        // In this situation we want to remove all activities
+                        // from the task up to the one being started.  In most
+                        // cases this means we are resetting the task to its
+                        // initial state.
+                        ActivityRecord top =
+                                intentActivity.task.performClearTaskLocked(r, launchFlags);
+                        if (top != null) {
+                            if (top.frontOfTask) {
+                                // Activity aliases may mean we use different
+                                // intents for the top activity, so make sure
+                                // the task now has the identity of the new
+                                // intent.
+                                top.task.setIntent(r.intent, r.info);
+                            }
+                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
+                                    r, top.task);
+                            top.deliverNewIntentLocked(callingUid, r.intent);
+                        } else {
+                            // A special case: we need to
+                            // start the activity because it is not currently
+                            // running, and the caller has asked to clear the
+                            // current task to have this activity at the top.
+                            addingToTask = true;
+                            // Now pretend like this activity is being started
+                            // by the top of its task, so it is put in the
+                            // right place.
+                            sourceRecord = intentActivity;
+                        }
+                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
+                        // In this case the top activity on the task is the
+                        // same as the one being launched, so we take that
+                        // as a request to bring the task to the foreground.
+                        // If the top activity in the task is the root
+                        // activity, deliver this new intent to it if it
+                        // desires.
+                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
+                                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
+                                && intentActivity.realActivity.equals(r.realActivity)) {
+                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
+                                    intentActivity.task);
+                            if (intentActivity.frontOfTask) {
+                                intentActivity.task.setIntent(r.intent, r.info);
+                            }
+                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);
+                        } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
+                            // In this case we are launching the root activity
+                            // of the task, but with a different intent.  We
+                            // should start a new instance on top.
+                            addingToTask = true;
+                            sourceRecord = intentActivity;
+                        }
+                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+                        // In this case an activity is being launched in to an
+                        // existing task, without resetting that task.  This
+                        // is typically the situation of launching an activity
+                        // from a notification or shortcut.  We want to place
+                        // the new activity on top of the current task.
+                        addingToTask = true;
+                        sourceRecord = intentActivity;
+                    } else if (!intentActivity.task.rootWasReset) {
+                        // In this case we are launching in to an existing task
+                        // that has not yet been started from its front door.
+                        // The current task has been brought to the front.
+                        // Ideally, we'd probably like to place this new task
+                        // at the bottom of its stack, but that's a little hard
+                        // to do with the current organization of the code so
+                        // for now we'll just drop it.
+                        intentActivity.task.setIntent(r.intent, r.info);
+                    }
+                    if (!addingToTask && reuseTask == null) {
+                        // We didn't do anything...  but it was needed (a.k.a., client
+                        // don't use that intent!)  And for paranoia, make
+                        // sure we have correctly resumed the top activity.
+                        if (doResume) {
+                            // Reset flag so it gets correctly reevaluated.
+                            intentActivity.task.mOnTopOfHome = false;
+                            setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack);
+                            targetStack.resumeTopActivityLocked(null, options);
+                        } else {
+                            ActivityOptions.abort(options);
+                        }
+                        if (r.task == null)  Slog.v(TAG,
+                            "startActivityUncheckedLocked: task left null",
+                            new RuntimeException("here").fillInStackTrace());
+                        return ActivityManager.START_TASK_TO_FRONT;
+                    }
+                }
+            }
+        }
+
+        //String uri = r.intent.toURI();
+        //Intent intent2 = new Intent(uri);
+        //Slog.i(TAG, "Given intent: " + r.intent);
+        //Slog.i(TAG, "URI is: " + uri);
+        //Slog.i(TAG, "To intent: " + intent2);
+
+        if (r.packageName != null) {
+            // If the activity being launched is the same as the one currently
+            // at the top, then we need to check if it should only be launched
+            // once.
+            ActivityStack topStack = getFocusedStack();
+            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
+            if (top != null && r.resultTo == null) {
+                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
+                    if (top.app != null && top.app.thread != null) {
+                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
+                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
+                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
+                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
+                                    top.task);
+                            // For paranoia, make sure we have correctly
+                            // resumed the top activity.
+                            topStack.mLastPausedActivity = null;
+                            if (doResume) {
+                                setLaunchHomeTaskNextFlag(sourceRecord, null, topStack);
+                                resumeTopActivitiesLocked();
+                            }
+                            ActivityOptions.abort(options);
+                            if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
+                                // We don't need to start a new activity, and
+                                // the client said not to do anything if that
+                                // is the case, so this is it!
+                                if (r.task == null)  Slog.v(TAG,
+                                    "startActivityUncheckedLocked: task left null",
+                                    new RuntimeException("here").fillInStackTrace());
+                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
+                            }
+                            top.deliverNewIntentLocked(callingUid, r.intent);
+                            if (r.task == null)  Slog.v(TAG,
+                                "startActivityUncheckedLocked: task left null",
+                                new RuntimeException("here").fillInStackTrace());
+                            return ActivityManager.START_DELIVERED_TO_TOP;
+                        }
+                    }
+                }
+            }
+
+        } else {
+            if (r.resultTo != null) {
+                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
+                        r.requestCode, Activity.RESULT_CANCELED, null);
+            }
+            ActivityOptions.abort(options);
+            if (r.task == null)  Slog.v(TAG,
+                "startActivityUncheckedLocked: task left null",
+                new RuntimeException("here").fillInStackTrace());
+            return ActivityManager.START_CLASS_NOT_FOUND;
+        }
+
+        boolean newTask = false;
+        boolean keepCurTransition = false;
+
+        // Should this be considered a new task?
+        if (r.resultTo == null && !addingToTask
+                && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+            targetStack = adjustStackFocus(r);
+            moveHomeStack(targetStack.isHomeStack());
+            if (reuseTask == null) {
+                r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
+                        null, true);
+                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
+                        r.task);
+            } else {
+                r.setTask(reuseTask, reuseTask, true);
+            }
+            newTask = true;
+            if (!movedHome) {
+                if ((launchFlags &
+                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
+                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
+                    // Caller wants to appear on home activity, so before starting
+                    // their own activity we will bring home to the front.
+                    r.task.mOnTopOfHome = true;
+                }
+            }
+        } else if (sourceRecord != null) {
+            sourceTask = sourceRecord.task;
+            targetStack = sourceTask.stack;
+            moveHomeStack(targetStack.isHomeStack());
+            if (!addingToTask &&
+                    (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+                // In this case, we are adding the activity to an existing
+                // task, but the caller has asked to clear that task if the
+                // activity is already running.
+                ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
+                keepCurTransition = true;
+                if (top != null) {
+                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
+                    top.deliverNewIntentLocked(callingUid, r.intent);
+                    // For paranoia, make sure we have correctly
+                    // resumed the top activity.
+                    targetStack.mLastPausedActivity = null;
+                    if (doResume) {
+                        setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
+                        targetStack.resumeTopActivityLocked(null);
+                    }
+                    ActivityOptions.abort(options);
+                    if (r.task == null)  Slog.v(TAG,
+                        "startActivityUncheckedLocked: task left null",
+                        new RuntimeException("here").fillInStackTrace());
+                    return ActivityManager.START_DELIVERED_TO_TOP;
+                }
+            } else if (!addingToTask &&
+                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+                // In this case, we are launching an activity in our own task
+                // that may already be running somewhere in the history, and
+                // we want to shuffle it to the front of the stack if so.
+                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
+                if (top != null) {
+                    final TaskRecord task = top.task;
+                    task.moveActivityToFrontLocked(top);
+                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
+                    top.updateOptionsLocked(options);
+                    top.deliverNewIntentLocked(callingUid, r.intent);
+                    targetStack.mLastPausedActivity = null;
+                    if (doResume) {
+                        setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
+                        targetStack.resumeTopActivityLocked(null);
+                    }
+                    return ActivityManager.START_DELIVERED_TO_TOP;
+                }
+            }
+            // An existing activity is starting this new activity, so we want
+            // to keep the new one in the same task as the one that is starting
+            // it.
+            r.setTask(sourceTask, sourceRecord.thumbHolder, false);
+            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+                    + " in existing task " + r.task);
+
+        } else {
+            // This not being started from an existing activity, and not part
+            // of a new task...  just put it in the top task, though these days
+            // this case should never happen.
+            targetStack = adjustStackFocus(r);
+            moveHomeStack(targetStack.isHomeStack());
+            ActivityRecord prev = targetStack.topActivity();
+            r.setTask(prev != null ? prev.task
+                    : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
+                    null, true);
+            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+                    + " in new guessed " + r.task);
+        }
+
+        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
+                intent, r.getUriPermissionsLocked());
+
+        if (newTask) {
+            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
+        }
+        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
+        setLaunchHomeTaskNextFlag(sourceRecord, r, targetStack);
+        targetStack.mLastPausedActivity = null;
+        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
+        mService.setFocusedActivityLocked(r);
+        return ActivityManager.START_SUCCESS;
+    }
+
+    void acquireLaunchWakelock() {
+        if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+            throw new IllegalStateException("Calling must be system uid");
+        }
+        mLaunchingActivity.acquire();
+        if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
+            // To be safe, don't allow the wake lock to be held for too long.
+            mHandler.sendEmptyMessageDelayed(LAUNCH_TIMEOUT_MSG, LAUNCH_TIMEOUT);
+        }
+    }
+
+    // Checked.
+    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
+            Configuration config) {
+        if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
+
+        ArrayList<ActivityRecord> stops = null;
+        ArrayList<ActivityRecord> finishes = null;
+        ArrayList<UserStartedState> startingUsers = null;
+        int NS = 0;
+        int NF = 0;
+        IApplicationThread sendThumbnail = null;
+        boolean booting = false;
+        boolean enableScreen = false;
+        boolean activityRemoved = false;
+
+        ActivityRecord r = ActivityRecord.forToken(token);
+        if (r != null) {
+            if (DEBUG_IDLE) Slog.d(TAG, "activityIdleInternalLocked: Callers=" +
+                    Debug.getCallers(4));
+            mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
+            r.finishLaunchTickingLocked();
+            if (fromTimeout) {
+                reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
+            }
+
+            // This is a hack to semi-deal with a race condition
+            // in the client where it can be constructed with a
+            // newer configuration from when we asked it to launch.
+            // We'll update with whatever configuration it now says
+            // it used to launch.
+            if (config != null) {
+                r.configuration = config;
+            }
+
+            // We are now idle.  If someone is waiting for a thumbnail from
+            // us, we can now deliver.
+            r.idle = true;
+
+            if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
+                sendThumbnail = r.app.thread;
+                r.thumbnailNeeded = false;
+            }
+
+            //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
+            if (!mService.mBooted && isFrontStack(r.task.stack)) {
+                mService.mBooted = true;
+                enableScreen = true;
+            }
+        }
+
+        if (allResumedActivitiesIdle()) {
+            if (r != null) {
+                mService.scheduleAppGcsLocked();
+            }
+
+            if (mLaunchingActivity.isHeld()) {
+                mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
+                if (VALIDATE_WAKE_LOCK_CALLER &&
+                        Binder.getCallingUid() != Process.myUid()) {
+                    throw new IllegalStateException("Calling must be system uid");
+                }
+                mLaunchingActivity.release();
+            }
+            ensureActivitiesVisibleLocked(null, 0);
+        }
+
+        // Atomically retrieve all of the other things to do.
+        stops = processStoppingActivitiesLocked(true);
+        NS = stops != null ? stops.size() : 0;
+        if ((NF=mFinishingActivities.size()) > 0) {
+            finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
+            mFinishingActivities.clear();
+        }
+
+        final ArrayList<ActivityRecord> thumbnails;
+        final int NT = mCancelledThumbnails.size();
+        if (NT > 0) {
+            thumbnails = new ArrayList<ActivityRecord>(mCancelledThumbnails);
+            mCancelledThumbnails.clear();
+        } else {
+            thumbnails = null;
+        }
+
+        if (isFrontStack(mHomeStack)) {
+            booting = mService.mBooting;
+            mService.mBooting = false;
+        }
+
+        if (mStartingUsers.size() > 0) {
+            startingUsers = new ArrayList<UserStartedState>(mStartingUsers);
+            mStartingUsers.clear();
+        }
+
+        // Perform the following actions from unsynchronized state.
+        final IApplicationThread thumbnailThread = sendThumbnail;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (thumbnailThread != null) {
+                    try {
+                        thumbnailThread.requestThumbnail(token);
+                    } catch (Exception e) {
+                        Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
+                        mService.sendPendingThumbnail(null, token, null, null, true);
+                    }
+                }
+
+                // Report back to any thumbnail receivers.
+                for (int i = 0; i < NT; i++) {
+                    ActivityRecord r = thumbnails.get(i);
+                    mService.sendPendingThumbnail(r, null, null, null, true);
+                }
+            }
+        });
+
+        // Stop any activities that are scheduled to do so but have been
+        // waiting for the next one to start.
+        for (int i = 0; i < NS; i++) {
+            r = stops.get(i);
+            final ActivityStack stack = r.task.stack;
+            if (r.finishing) {
+                stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
+            } else {
+                stack.stopActivityLocked(r);
+            }
+        }
+
+        // Finish any activities that are scheduled to do so but have been
+        // waiting for the next one to start.
+        for (int i = 0; i < NF; i++) {
+            r = finishes.get(i);
+            activityRemoved |= r.task.stack.destroyActivityLocked(r, true, false, "finish-idle");
+        }
+
+        if (booting) {
+            mService.finishBooting();
+        } else if (startingUsers != null) {
+            for (int i = 0; i < startingUsers.size(); i++) {
+                mService.finishUserSwitch(startingUsers.get(i));
+            }
+        }
+
+        mService.trimApplications();
+        //dump();
+        //mWindowManager.dump();
+
+        if (enableScreen) {
+            mService.enableScreenAfterBoot();
+        }
+
+        if (activityRemoved) {
+            resumeTopActivitiesLocked();
+        }
+
+        return r;
+    }
+
+    void handleAppDiedLocked(ProcessRecord app, boolean restarting) {
+        boolean launchHomeTaskNext = false;
+        final ActivityStack focusedStack = getFocusedStack();
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            // Only update launchHomeTaskNext for the focused stack.
+            launchHomeTaskNext |= (stack.handleAppDiedLocked(app) && stack == focusedStack);
+        }
+
+        if (!restarting) {
+            if (launchHomeTaskNext) {
+                resumeHomeActivity(null);
+            } else {
+                if (!resumeTopActivitiesLocked(focusedStack, null, null)) {
+                    // If there was nothing to resume, and we are not already
+                    // restarting this process, but there is a visible activity that
+                    // is hosted by the process...  then make sure all visible
+                    // activities are running, taking care of restarting this
+                    // process.
+                    ensureActivitiesVisibleLocked(null, 0);
+                }
+            }
+        }
+    }
+
+    void closeSystemDialogsLocked() {
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            stack.closeSystemDialogsLocked();
+        }
+    }
+
+    /**
+     * @return true if some activity was finished (or would have finished if doit were true).
+     */
+    boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
+        boolean didSomething = false;
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+                didSomething = true;
+            }
+        }
+        return didSomething;
+    }
+
+    void updatePreviousProcessLocked(ActivityRecord r) {
+        // Now that this process has stopped, we may want to consider
+        // it to be the previous app to try to keep around in case
+        // the user wants to return to it.
+
+        // First, found out what is currently the foreground app, so that
+        // we don't blow away the previous app if this activity is being
+        // hosted by the process that is actually still the foreground.
+        ProcessRecord fgApp = null;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (isFrontStack(stack)) {
+                if (stack.mResumedActivity != null) {
+                    fgApp = stack.mResumedActivity.app;
+                } else if (stack.mPausingActivity != null) {
+                    fgApp = stack.mPausingActivity.app;
+                }
+                break;
+            }
+        }
+
+        // Now set this one as the previous process, only if that really
+        // makes sense to.
+        if (r.app != null && fgApp != null && r.app != fgApp
+                && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
+                && r.app != mService.mHomeProcess) {
+            mService.mPreviousProcess = r.app;
+            mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
+        }
+    }
+
+    boolean resumeTopActivitiesLocked() {
+        return resumeTopActivitiesLocked(null, null, null);
+    }
+
+    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
+            Bundle targetOptions) {
+        if (targetStack == null) {
+            targetStack = getFocusedStack();
+        }
+        boolean result = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (isFrontStack(stack)) {
+                if (stack == targetStack) {
+                    result = stack.resumeTopActivityLocked(target, targetOptions);
+                } else {
+                    stack.resumeTopActivityLocked(null);
+                }
+            }
+        }
+        return result;
+    }
+
+    void finishTopRunningActivityLocked(ProcessRecord app) {
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            stack.finishTopRunningActivityLocked(app);
+        }
+    }
+
+    void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) {
+                if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" +
+                        mStacks.get(stackNdx));
+                return;
+            }
+        }
+    }
+
+    ActivityStack getStack(int stackId) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack.getStackId() == stackId) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
+    ArrayList<ActivityStack> getStacks() {
+        return new ArrayList<ActivityStack>(mStacks);
+    }
+
+    int createStack() {
+        while (true) {
+            if (++mLastStackId <= HOME_STACK_ID) {
+                mLastStackId = HOME_STACK_ID + 1;
+            }
+            if (getStack(mLastStackId) == null) {
+                break;
+            }
+        }
+        mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId));
+        return mLastStackId;
+    }
+
+    void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+        final TaskRecord task = anyTaskForIdLocked(taskId);
+        if (task == null) {
+            return;
+        }
+        final ActivityStack stack = getStack(stackId);
+        if (stack == null) {
+            Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
+            return;
+        }
+        removeTask(task);
+        stack.addTask(task, toTop);
+        mWindowManager.addTask(taskId, stackId, toTop);
+        resumeTopActivitiesLocked();
+    }
+
+    ActivityRecord findTaskLocked(ActivityRecord r) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (!r.isApplicationActivity() && !stack.isHomeStack()) {
+                continue;
+            }
+            final ActivityRecord ar = stack.findTaskLocked(r);
+            if (ar != null) {
+                return ar;
+            }
+        }
+        return null;
+    }
+
+    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info);
+            if (ar != null) {
+                return ar;
+            }
+        }
+        return null;
+    }
+
+    void goingToSleepLocked() {
+        scheduleSleepTimeout();
+        if (!mGoingToSleep.isHeld()) {
+            mGoingToSleep.acquire();
+            if (mLaunchingActivity.isHeld()) {
+                if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+                    throw new IllegalStateException("Calling must be system uid");
+                }
+                mLaunchingActivity.release();
+                mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
+            }
+        }
+        checkReadyForSleepLocked();
+    }
+
+    boolean shutdownLocked(int timeout) {
+        boolean timedout = false;
+        goingToSleepLocked();
+
+        final long endTime = System.currentTimeMillis() + timeout;
+        while (true) {
+            boolean cantShutdown = false;
+            for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                cantShutdown |= mStacks.get(stackNdx).checkReadyForSleepLocked();
+            }
+            if (cantShutdown) {
+                long timeRemaining = endTime - System.currentTimeMillis();
+                if (timeRemaining > 0) {
+                    try {
+                        mService.wait(timeRemaining);
+                    } catch (InterruptedException e) {
+                    }
+                } else {
+                    Slog.w(TAG, "Activity manager shutdown timed out");
+                    timedout = true;
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+
+        // Force checkReadyForSleep to complete.
+        mSleepTimeout = true;
+        checkReadyForSleepLocked();
+
+        return timedout;
+    }
+
+    void comeOutOfSleepIfNeededLocked() {
+        removeSleepTimeouts();
+        if (mGoingToSleep.isHeld()) {
+            mGoingToSleep.release();
+        }
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            stack.awakeFromSleepingLocked();
+            if (isFrontStack(stack)) {
+                resumeTopActivitiesLocked();
+            }
+        }
+        mGoingToSleepActivities.clear();
+    }
+
+    void activitySleptLocked(ActivityRecord r) {
+        mGoingToSleepActivities.remove(r);
+        checkReadyForSleepLocked();
+    }
+
+    void checkReadyForSleepLocked() {
+        if (!mService.isSleepingOrShuttingDown()) {
+            // Do not care.
+            return;
+        }
+
+        if (!mSleepTimeout) {
+            boolean dontSleep = false;
+            for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                dontSleep |= mStacks.get(stackNdx).checkReadyForSleepLocked();
+            }
+
+            if (mStoppingActivities.size() > 0) {
+                // Still need to tell some activities to stop; can't sleep yet.
+                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
+                        + mStoppingActivities.size() + " activities");
+                scheduleIdleLocked();
+                dontSleep = true;
+            }
+
+            if (mGoingToSleepActivities.size() > 0) {
+                // Still need to tell some activities to sleep; can't sleep yet.
+                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
+                        + mGoingToSleepActivities.size() + " activities");
+                dontSleep = true;
+            }
+
+            if (dontSleep) {
+                return;
+            }
+        }
+
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).goToSleep();
+        }
+
+        removeSleepTimeouts();
+
+        if (mGoingToSleep.isHeld()) {
+            mGoingToSleep.release();
+        }
+        if (mService.mShuttingDown) {
+            mService.notifyAll();
+        }
+    }
+
+    boolean reportResumedActivityLocked(ActivityRecord r) {
+        final ActivityStack stack = r.task.stack;
+        if (isFrontStack(stack)) {
+            mService.updateUsageStats(r, true);
+        }
+        if (allResumedActivitiesComplete()) {
+            ensureActivitiesVisibleLocked(null, 0);
+            mWindowManager.executeAppTransition();
+            return true;
+        }
+        return false;
+    }
+
+    void handleAppCrashLocked(ProcessRecord app) {
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            stack.handleAppCrashLocked(app);
+        }
+    }
+
+    void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+        // First the front stacks. In case any are not fullscreen and are in front of home.
+        boolean showHomeBehindStack = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (isFrontStack(stack)) {
+                showHomeBehindStack =
+                        stack.ensureActivitiesVisibleLocked(starting, configChanges);
+            }
+        }
+        // Now do back stacks.
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (!isFrontStack(stack)) {
+                stack.ensureActivitiesVisibleLocked(starting, configChanges, showHomeBehindStack);
+            }
+        }
+    }
+
+    void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            stack.scheduleDestroyActivities(app, false, reason);
+        }
+    }
+
+    boolean switchUserLocked(int userId, UserStartedState uss) {
+        mCurrentUser = userId;
+
+        mStartingUsers.add(uss);
+        boolean haveActivities = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            haveActivities |= mStacks.get(stackNdx).switchUserLocked(userId);
+        }
+
+        resumeTopActivitiesLocked();
+
+        return haveActivities;
+    }
+
+    final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
+        int N = mStoppingActivities.size();
+        if (N <= 0) return null;
+
+        ArrayList<ActivityRecord> stops = null;
+
+        final boolean nowVisible = allResumedActivitiesVisible();
+        for (int i=0; i<N; i++) {
+            ActivityRecord s = mStoppingActivities.get(i);
+            if (true || localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
+                    + nowVisible + " waitingVisible=" + s.waitingVisible
+                    + " finishing=" + s.finishing);
+            if (s.waitingVisible && nowVisible) {
+                mWaitingVisibleActivities.remove(s);
+                s.waitingVisible = false;
+                if (s.finishing) {
+                    // If this activity is finishing, it is sitting on top of
+                    // everyone else but we now know it is no longer needed...
+                    // so get rid of it.  Otherwise, we need to go through the
+                    // normal flow and hide it once we determine that it is
+                    // hidden by the activities in front of it.
+                    if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
+                    mWindowManager.setAppVisibility(s.appToken, false);
+                }
+            }
+            if ((!s.waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
+                if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
+                if (stops == null) {
+                    stops = new ArrayList<ActivityRecord>();
+                }
+                stops.add(s);
+                mStoppingActivities.remove(i);
+                N--;
+                i--;
+            }
+        }
+
+        return stops;
+    }
+
+    void validateTopActivitiesLocked() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            final ActivityRecord r = stack.topRunningActivityLocked(null);
+            final ActivityState state = r == null ? ActivityState.DESTROYED : r.state;
+            if (isFrontStack(stack)) {
+                if (r == null) {
+                    Slog.e(TAG, "validateTop...: null top activity, stack=" + stack);
+                } else {
+                    final ActivityRecord pausing = stack.mPausingActivity;
+                    if (pausing != null && pausing == r) {
+                        Slog.e(TAG, "validateTop...: top stack has pausing activity r=" + r +
+                            " state=" + state);
+                    }
+                    if (state != ActivityState.INITIALIZING && state != ActivityState.RESUMED) {
+                        Slog.e(TAG, "validateTop...: activity in front not resumed r=" + r +
+                                " state=" + state);
+                    }
+                }
+            } else {
+                final ActivityRecord resumed = stack.mResumedActivity;
+                if (resumed != null && resumed == r) {
+                    Slog.e(TAG, "validateTop...: back stack has resumed activity r=" + r +
+                        " state=" + state);
+                }
+                if (r != null && (state == ActivityState.INITIALIZING
+                        || state == ActivityState.RESUMED)) {
+                    Slog.e(TAG, "validateTop...: activity in back resumed r=" + r +
+                            " state=" + state);
+                }
+            }
+        }
+    }
+
+    private static String stackStateToString(int stackState) {
+        switch (stackState) {
+            case STACK_STATE_HOME_IN_FRONT: return "STACK_STATE_HOME_IN_FRONT";
+            case STACK_STATE_HOME_TO_BACK: return "STACK_STATE_HOME_TO_BACK";
+            case STACK_STATE_HOME_IN_BACK: return "STACK_STATE_HOME_IN_BACK";
+            case STACK_STATE_HOME_TO_FRONT: return "STACK_STATE_HOME_TO_FRONT";
+            default: return "Unknown stackState=" + stackState;
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity:");
+                pw.println(mDismissKeyguardOnNextActivity);
+        pw.print(prefix); pw.print("mStackState="); pw.println(stackStateToString(mStackState));
+        pw.print(prefix); pw.println("mSleepTimeout: " + mSleepTimeout);
+        pw.print(prefix); pw.println("mCurTaskId: " + mCurTaskId);
+    }
+
+    ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
+        return getFocusedStack().getDumpActivitiesLocked(name);
+    }
+
+    static boolean printThisActivity(PrintWriter pw, ActivityRecord activity, String dumpPackage,
+            boolean needSep, String prefix) {
+        if (activity != null) {
+            if (dumpPackage == null || dumpPackage.equals(activity.packageName)) {
+                if (needSep) {
+                    pw.println();
+                }
+                pw.print(prefix);
+                pw.println(activity);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+            boolean dumpClient, String dumpPackage) {
+        boolean printed = false;
+        boolean needSep = false;
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            StringBuilder stackHeader = new StringBuilder(128);
+            stackHeader.append("  Stack #");
+            stackHeader.append(mStacks.indexOf(stack));
+            stackHeader.append(":");
+            printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep,
+                    stackHeader.toString());
+            printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false, !dumpAll,
+                    false, dumpPackage, true, "    Running activities (most recent first):", null);
+
+            needSep = printed;
+            boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
+                    "    mPausingActivity: ");
+            if (pr) {
+                printed = true;
+                needSep = false;
+            }
+            pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep,
+                    "    mResumedActivity: ");
+            if (pr) {
+                printed = true;
+                needSep = false;
+            }
+            if (dumpAll) {
+                pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
+                        "    mLastPausedActivity: ");
+                if (pr) {
+                    printed = true;
+                    needSep = true;
+                }
+                printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
+                        needSep, "    mLastNoHistoryActivity: ");
+            }
+            needSep = printed;
+        }
+
+        printed |= dumpHistoryList(fd, pw, mFinishingActivities, "  ", "Fin", false, !dumpAll,
+                false, dumpPackage, true, "  Activities waiting to finish:", null);
+        printed |= dumpHistoryList(fd, pw, mStoppingActivities, "  ", "Stop", false, !dumpAll,
+                false, dumpPackage, true, "  Activities waiting to stop:", null);
+        printed |= dumpHistoryList(fd, pw, mWaitingVisibleActivities, "  ", "Wait", false, !dumpAll,
+                false, dumpPackage, true, "  Activities waiting for another to become visible:",
+                null);
+        printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, "  ", "Sleep", false, !dumpAll,
+                false, dumpPackage, true, "  Activities waiting to sleep:", null);
+        printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, "  ", "Sleep", false, !dumpAll,
+                false, dumpPackage, true, "  Activities waiting to sleep:", null);
+
+        return printed;
+    }
+
+    static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
+            String prefix, String label, boolean complete, boolean brief, boolean client,
+            String dumpPackage, boolean needNL, String header1, String header2) {
+        TaskRecord lastTask = null;
+        String innerPrefix = null;
+        String[] args = null;
+        boolean printed = false;
+        for (int i=list.size()-1; i>=0; i--) {
+            final ActivityRecord r = list.get(i);
+            if (dumpPackage != null && !dumpPackage.equals(r.packageName)) {
+                continue;
+            }
+            if (innerPrefix == null) {
+                innerPrefix = prefix + "      ";
+                args = new String[0];
+            }
+            printed = true;
+            final boolean full = !brief && (complete || !r.isInHistory());
+            if (needNL) {
+                pw.println("");
+                needNL = false;
+            }
+            if (header1 != null) {
+                pw.println(header1);
+                header1 = null;
+            }
+            if (header2 != null) {
+                pw.println(header2);
+                header2 = null;
+            }
+            if (lastTask != r.task) {
+                lastTask = r.task;
+                pw.print(prefix);
+                pw.print(full ? "* " : "  ");
+                pw.println(lastTask);
+                if (full) {
+                    lastTask.dump(pw, prefix + "  ");
+                } else if (complete) {
+                    // Complete + brief == give a summary.  Isn't that obvious?!?
+                    if (lastTask.intent != null) {
+                        pw.print(prefix); pw.print("  ");
+                                pw.println(lastTask.intent.toInsecureStringWithClip());
+                    }
+                }
+            }
+            pw.print(prefix); pw.print(full ? "  * " : "    "); pw.print(label);
+            pw.print(" #"); pw.print(i); pw.print(": ");
+            pw.println(r);
+            if (full) {
+                r.dump(pw, innerPrefix);
+            } else if (complete) {
+                // Complete + brief == give a summary.  Isn't that obvious?!?
+                pw.print(innerPrefix); pw.println(r.intent.toInsecureString());
+                if (r.app != null) {
+                    pw.print(innerPrefix); pw.println(r.app);
+                }
+            }
+            if (client && r.app != null && r.app.thread != null) {
+                // flush anything that is already in the PrintWriter since the thread is going
+                // to write to the file descriptor directly
+                pw.flush();
+                try {
+                    TransferPipe tp = new TransferPipe();
+                    try {
+                        r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+                                r.appToken, innerPrefix, args);
+                        // Short timeout, since blocking here can
+                        // deadlock with the application.
+                        tp.go(fd, 2000);
+                    } finally {
+                        tp.kill();
+                    }
+                } catch (IOException e) {
+                    pw.println(innerPrefix + "Failure while dumping the activity: " + e);
+                } catch (RemoteException e) {
+                    pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
+                }
+                needNL = true;
+            }
+        }
+        return printed;
+    }
+
+    void scheduleIdleTimeoutLocked(ActivityRecord next) {
+        if (DEBUG_IDLE) Slog.d(TAG, "scheduleIdleTimeoutLocked: Callers=" + Debug.getCallers(4));
+        Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
+        mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
+    }
+
+    final void scheduleIdleLocked() {
+        mHandler.sendEmptyMessage(IDLE_NOW_MSG);
+    }
+
+    void removeTimeoutsForActivityLocked(ActivityRecord r) {
+        if (DEBUG_IDLE) Slog.d(TAG, "removeTimeoutsForActivity: Callers=" + Debug.getCallers(4));
+        mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
+    }
+
+    final void scheduleResumeTopActivities() {
+        mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+    }
+
+    void removeSleepTimeouts() {
+        mSleepTimeout = false;
+        mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
+    }
+
+    final void scheduleSleepTimeout() {
+        removeSleepTimeouts();
+        mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT);
+    }
+
+    private final class ActivityStackSupervisorHandler extends Handler {
+
+        public ActivityStackSupervisorHandler(Looper looper) {
+            super(looper);
+        }
+
+        void activityIdleInternal(ActivityRecord r) {
+            synchronized (mService) {
+                activityIdleInternalLocked(r != null ? r.appToken : null, true, null);
+            }
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case IDLE_TIMEOUT_MSG: {
+                    if (DEBUG_IDLE) Slog.d(TAG, "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
+                    if (mService.mDidDexOpt) {
+                        mService.mDidDexOpt = false;
+                        Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
+                        nmsg.obj = msg.obj;
+                        mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
+                        return;
+                    }
+                    // We don't at this point know if the activity is fullscreen,
+                    // so we need to be conservative and assume it isn't.
+                    activityIdleInternal((ActivityRecord)msg.obj);
+                } break;
+                case IDLE_NOW_MSG: {
+                    if (DEBUG_IDLE) Slog.d(TAG, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
+                    activityIdleInternal((ActivityRecord)msg.obj);
+                } break;
+                case RESUME_TOP_ACTIVITY_MSG: {
+                    synchronized (mService) {
+                        resumeTopActivitiesLocked();
+                    }
+                } break;
+                case SLEEP_TIMEOUT_MSG: {
+                    synchronized (mService) {
+                        if (mService.isSleepingOrShuttingDown()) {
+                            Slog.w(TAG, "Sleep timeout!  Sleeping now.");
+                            mSleepTimeout = true;
+                            checkReadyForSleepLocked();
+                        }
+                    }
+                } break;
+                case LAUNCH_TIMEOUT_MSG: {
+                    if (mService.mDidDexOpt) {
+                        mService.mDidDexOpt = false;
+                        mHandler.sendEmptyMessageDelayed(LAUNCH_TIMEOUT_MSG, LAUNCH_TIMEOUT);
+                        return;
+                    }
+                    synchronized (mService) {
+                        if (mLaunchingActivity.isHeld()) {
+                            Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
+                            if (VALIDATE_WAKE_LOCK_CALLER
+                                    && Binder.getCallingUid() != Process.myUid()) {
+                                throw new IllegalStateException("Calling must be system uid");
+                            }
+                            mLaunchingActivity.release();
+                        }
+                    }
+                } break;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/java/com/android/server/am/AppBindRecord.java
index f1c54fa..06265fd 100644
--- a/services/java/com/android/server/am/AppBindRecord.java
+++ b/services/java/com/android/server/am/AppBindRecord.java
@@ -23,7 +23,7 @@
 /**
  * An association between a service and one of its client applications.
  */
-class AppBindRecord {
+final class AppBindRecord {
     final ServiceRecord service;    // The running service.
     final IntentBindRecord intent;  // The intent we are bound to.
     final ProcessRecord client;     // Who has started/bound the service.
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index ffa1e92..fffa75e 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -16,7 +16,7 @@
 
 package com.android.server.am;
 
-import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 
 import android.content.Context;
 import android.content.DialogInterface;
@@ -25,7 +25,7 @@
 import android.os.Message;
 import android.view.WindowManager;
 
-class AppErrorDialog extends BaseErrorDialog {
+final class AppErrorDialog extends BaseErrorDialog {
     private final ActivityManagerService mService;
     private final AppErrorResult mResult;
     private final ProcessRecord mProc;
@@ -72,7 +72,7 @@
         }
 
         setTitle(res.getText(com.android.internal.R.string.aerr_title));
-        getWindow().addFlags(FLAG_SYSTEM_ERROR);
+        getWindow().addFlags(PRIVATE_FLAG_SYSTEM_ERROR);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
         attrs.setTitle("Application Error: " + app.info.processName);
         attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/services/java/com/android/server/am/AppErrorResult.java b/services/java/com/android/server/am/AppErrorResult.java
index ebfcfe2..c6a5720 100644
--- a/services/java/com/android/server/am/AppErrorResult.java
+++ b/services/java/com/android/server/am/AppErrorResult.java
@@ -16,8 +16,7 @@
 
 package com.android.server.am;
 
-
-class AppErrorResult {
+final class AppErrorResult {
     public void set(int res) {
         synchronized (this) {
             mHasResult = true;
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index af61c9b..4de272d 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -16,7 +16,7 @@
 
 package com.android.server.am;
 
-import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -28,7 +28,7 @@
 import android.util.Slog;
 import android.view.WindowManager;
 
-class AppNotRespondingDialog extends BaseErrorDialog {
+final class AppNotRespondingDialog extends BaseErrorDialog {
     private static final String TAG = "AppNotRespondingDialog";
 
     // Event 'what' codes
@@ -94,7 +94,7 @@
         if (aboveSystem) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
         }
-        getWindow().addFlags(FLAG_SYSTEM_ERROR);
+        getWindow().addFlags(PRIVATE_FLAG_SYSTEM_ERROR);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
         attrs.setTitle("Application Not Responding: " + app.info.processName);
         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
@@ -128,6 +128,7 @@
                         if (app.anrDialog == AppNotRespondingDialog.this) {
                             app.anrDialog = null;
                         }
+                        mService.mServices.scheduleServiceTimeoutLocked(app);
                     }
                     break;
             }
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index d08bb10..27865a8 100644
--- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -22,7 +22,7 @@
 import android.os.Message;
 import android.view.WindowManager;
 
-class AppWaitingForDebuggerDialog extends BaseErrorDialog {
+final class AppWaitingForDebuggerDialog extends BaseErrorDialog {
     final ActivityManagerService mService;
     final ProcessRecord mProc;
     private CharSequence mAppName;
diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/java/com/android/server/am/BackupRecord.java
index 7e73106..5fa7e6a 100644
--- a/services/java/com/android/server/am/BackupRecord.java
+++ b/services/java/com/android/server/am/BackupRecord.java
@@ -21,7 +21,7 @@
 import android.content.pm.ApplicationInfo;
 
 /** @hide */
-class BackupRecord {
+final class BackupRecord {
     // backup/restore modes
     public static final int BACKUP_NORMAL = 0;
     public static final int BACKUP_FULL = 1;
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index d19c7f6..0dd950e 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -22,11 +22,13 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Process;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.os.WorkSource;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
@@ -58,7 +60,7 @@
     
     public void publish(Context context) {
         mContext = context;
-        ServiceManager.addService("batteryinfo", asBinder());
+        ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
         mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
         mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout)
@@ -76,7 +78,7 @@
         if (sService != null) {
             return sService;
         }
-        IBinder b = ServiceManager.getService("batteryinfo");
+        IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
         sService = asInterface(b);
         return sService;
     }
@@ -431,6 +433,7 @@
         }
     }
 
+    @Override
     public void noteNetworkInterfaceType(String iface, int type) {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -438,6 +441,14 @@
         }
     }
 
+    @Override
+    public void noteNetworkStatsEnabled() {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteNetworkStatsEnabledLocked();
+        }
+    }
+
     public boolean isOnBattery() {
         return mStats.isOnBattery();
     }
@@ -469,12 +480,14 @@
     }
     
     private void dumpHelp(PrintWriter pw) {
-        pw.println("Battery stats (batteryinfo) dump options:");
-        pw.println("  [--checkin] [--reset] [--write] [-h]");
+        pw.println("Battery stats (batterystats) dump options:");
+        pw.println("  [--checkin] [-c] [--unplugged] [--reset] [--write] [-h] [<package.name>]");
         pw.println("  --checkin: format output for a checkin report.");
+        pw.println("  --unplugged: only output data since last unplugged.");
         pw.println("  --reset: reset the stats, clearing all current data.");
         pw.println("  --write: force write current collected stats to disk.");
         pw.println("  -h: print this help text.");
+        pw.println("  <package.name>: optional name of package to filter output by.");
     }
 
     @Override
@@ -488,11 +501,19 @@
         }
 
         boolean isCheckin = false;
+        boolean includeHistory = false;
+        boolean isUnpluggedOnly = false;
         boolean noOutput = false;
+        int reqUid = -1;
         if (args != null) {
             for (String arg : args) {
                 if ("--checkin".equals(arg)) {
                     isCheckin = true;
+                } else if ("-c".equals(arg)) {
+                    isCheckin = true;
+                    includeHistory = true;
+                } else if ("--unplugged".equals(arg)) {
+                    isUnpluggedOnly = true;
                 } else if ("--reset".equals(arg)) {
                     synchronized (mStats) {
                         mStats.resetAllStatsLocked();
@@ -510,9 +531,20 @@
                     return;
                 } else if ("-a".equals(arg)) {
                     // fall through
-                } else {
+                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     dumpHelp(pw);
+                    return;
+                } else {
+                    // Not an option, last argument must be a package name.
+                    try {
+                        reqUid = mContext.getPackageManager().getPackageUid(arg,
+                                UserHandle.getCallingUserId());
+                    } catch (PackageManager.NameNotFoundException e) {
+                        pw.println("Unknown package: " + arg);
+                        dumpHelp(pw);
+                        return;
+                    }
                 }
             }
         }
@@ -522,11 +554,11 @@
         if (isCheckin) {
             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
             synchronized (mStats) {
-                mStats.dumpCheckinLocked(pw, args, apps);
+                mStats.dumpCheckinLocked(pw, apps, isUnpluggedOnly, includeHistory);
             }
         } else {
             synchronized (mStats) {
-                mStats.dumpLocked(pw);
+                mStats.dumpLocked(pw, isUnpluggedOnly, reqUid);
             }
         }
     }
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java
index c631b6e..986b8ea 100644
--- a/services/java/com/android/server/am/BroadcastFilter.java
+++ b/services/java/com/android/server/am/BroadcastFilter.java
@@ -22,7 +22,7 @@
 
 import java.io.PrintWriter;
 
-class BroadcastFilter extends IntentFilter {
+final class BroadcastFilter extends IntentFilter {
     // Back-pointer to the list this filter is in.
     final ReceiverList receiverList;
     final String packageName;
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index ac7eb89..b2e3ce7 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -47,15 +47,16 @@
  * We keep two broadcast queues and associated bookkeeping, one for those at
  * foreground priority, and one for normal (background-priority) broadcasts.
  */
-public class BroadcastQueue {
+public final class BroadcastQueue {
     static final String TAG = "BroadcastQueue";
     static final String TAG_MU = ActivityManagerService.TAG_MU;
     static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
     static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
     static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
 
-    static final int MAX_BROADCAST_HISTORY = 25;
-    static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
+    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 25;
+    static final int MAX_BROADCAST_SUMMARY_HISTORY
+            = ActivityManager.isLowRamDeviceStatic() ? 25 : 100;
 
     final ActivityManagerService mService;
 
@@ -70,14 +71,20 @@
     final long mTimeoutPeriod;
 
     /**
+     * If true, we can delay broadcasts while waiting services to finish in the previous
+     * receiver's process.
+     */
+    final boolean mDelayBehindServices;
+
+    /**
      * Lists of all active broadcasts that are to be executed immediately
      * (without waiting for another broadcast to finish).  Currently this only
      * contains broadcasts to registered receivers, to avoid spinning up
      * a bunch of processes to execute IntentReceiver components.  Background-
      * and foreground-priority broadcasts are queued separately.
      */
-    final ArrayList<BroadcastRecord> mParallelBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
+
     /**
      * List of all active broadcasts that are to be executed one at a time.
      * The object at the top of the list is the currently activity broadcasts;
@@ -85,20 +92,17 @@
      * broadcasts, separate background- and foreground-priority queues are
      * maintained.
      */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
 
     /**
      * Historical data of past broadcasts, for debugging.
      */
-    final BroadcastRecord[] mBroadcastHistory
-            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
 
     /**
      * Summary of historical data of past broadcasts, for debugging.
      */
-    final Intent[] mBroadcastSummaryHistory
-            = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
 
     /**
      * Set when we current have a BROADCAST_INTENT_MSG in flight.
@@ -128,10 +132,6 @@
     static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
 
     final Handler mHandler = new Handler() {
-        //public Handler() {
-        //    if (localLOGV) Slog.v(TAG, "Handler started!");
-        //}
-
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
@@ -163,10 +163,12 @@
         }
     }
 
-    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod,
+            boolean allowDelayBehindServices) {
         mService = service;
         mQueueName = name;
         mTimeoutPeriod = timeoutPeriod;
+        mDelayBehindServices = allowDelayBehindServices;
     }
 
     public boolean isPendingBroadcastProcessLocked(int pid) {
@@ -217,7 +219,8 @@
         r.receiver = app.thread.asBinder();
         r.curApp = app;
         app.curReceiver = r;
-        mService.updateLruProcessLocked(app, true);
+        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
+        mService.updateLruProcessLocked(app, true, false);
 
         // Tell the application to launch this receiver.
         r.intent.setComponent(r.curComponent);
@@ -230,7 +233,8 @@
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
-                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId);
+                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
+                    app.repProcState);
             if (DEBUG_BROADCAST)  Slog.v(TAG,
                     "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
@@ -258,7 +262,7 @@
                         + br.curComponent.flattenToShortString(), e);
                 logBroadcastReceiverDiscardLocked(br);
                 finishReceiverLocked(br, br.resultCode, br.resultData,
-                        br.resultExtras, br.resultAbort, true);
+                        br.resultExtras, br.resultAbort, false);
                 scheduleBroadcastsLocked();
                 // We need to reset the state if we failed to start the receiver.
                 br.state = BroadcastRecord.IDLE;
@@ -287,7 +291,7 @@
             // let the broadcast continue.
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
+                    r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
 
@@ -297,7 +301,7 @@
                     "[" + mQueueName + "] skip & discard pending app " + r);
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
+                    r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
         if (reschedule) {
@@ -328,14 +332,12 @@
     }
 
     public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort,
-            boolean explicit) {
-        int state = r.state;
+            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
+        final int state = r.state;
+        final ActivityInfo receiver = r.curReceiver;
         r.state = BroadcastRecord.IDLE;
         if (state == BroadcastRecord.IDLE) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
-            }
+            Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
         }
         r.receiver = null;
         r.intent.setComponent(null);
@@ -346,15 +348,47 @@
             r.curFilter.receiverList.curBroadcast = null;
         }
         r.curFilter = null;
-        r.curApp = null;
-        r.curComponent = null;
         r.curReceiver = null;
+        r.curApp = null;
         mPendingBroadcast = null;
 
         r.resultCode = resultCode;
         r.resultData = resultData;
         r.resultExtras = resultExtras;
-        r.resultAbort = resultAbort;
+        if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
+            r.resultAbort = resultAbort;
+        } else {
+            r.resultAbort = false;
+        }
+
+        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
+                && r.queue.mOrderedBroadcasts.size() > 0
+                && r.queue.mOrderedBroadcasts.get(0) == r) {
+            ActivityInfo nextReceiver;
+            if (r.nextReceiver < r.receivers.size()) {
+                Object obj = r.receivers.get(r.nextReceiver);
+                nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
+            } else {
+                nextReceiver = null;
+            }
+            // Don't do this if the next receive is in the same process as the current one.
+            if (receiver == null || nextReceiver == null
+                    || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
+                    || !receiver.processName.equals(nextReceiver.processName)) {
+                // In this case, we are ready to process the next receiver for the current broadcast,
+                // but are on a queue that would like to wait for services to finish before moving
+                // on.  If there are background services currently starting, then we will go into a
+                // special state where we hold off on continuing this broadcast until they are done.
+                if (mService.mServices.hasBackgroundServices(r.userId)) {
+                    Slog.i(ActivityManagerService.TAG, "Delay finish: "
+                            + r.curComponent.flattenToShortString());
+                    r.state = BroadcastRecord.WAITING_SERVICES;
+                    return false;
+                }
+            }
+        }
+
+        r.curComponent = null;
 
         // We will process the next receiver right now if this is finishing
         // an app receiver (which is always asynchronous) or after we have
@@ -363,6 +397,18 @@
                 || state == BroadcastRecord.CALL_DONE_RECEIVE;
     }
 
+    public void backgroundServicesFinishedLocked(int userId) {
+        if (mOrderedBroadcasts.size() > 0) {
+            BroadcastRecord br = mOrderedBroadcasts.get(0);
+            if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
+                Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+                br.curComponent = null;
+                br.state = BroadcastRecord.IDLE;
+                processNextBroadcast(false);
+            }
+        }
+    }
+
     private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
             Intent intent, int resultCode, String data, Bundle extras,
             boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
@@ -371,7 +417,7 @@
             // If we have an app thread, do the call through that so it is
             // correctly ordered with other one-way calls.
             app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                    data, extras, ordered, sticky, sendingUser);
+                    data, extras, ordered, sticky, sendingUser, app.repProcState);
         } else {
             receiver.performReceive(intent, resultCode, data, extras, ordered,
                     sticky, sendingUser);
@@ -410,7 +456,7 @@
             }
         }
         if (r.appOp != AppOpsManager.OP_NONE) {
-            int mode = mService.mAppOpsService.checkOperation(r.appOp,
+            int mode = mService.mAppOpsService.noteOperation(r.appOp,
                     filter.receiverList.uid, filter.packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
                 if (DEBUG_BROADCAST)  Slog.v(TAG,
@@ -419,6 +465,10 @@
                 skip = true;
             }
         }
+        if (!skip) {
+            skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
+                    r.callingPid, r.resolvedType, filter.receiverList.uid);
+        }
 
         if (!skip) {
             // If this is not being sent as an ordered broadcast, then we
@@ -437,7 +487,7 @@
                     // are already core system stuff so don't matter for this.
                     r.curApp = filter.receiverList.app;
                     filter.receiverList.app.curReceiver = r;
-                    mService.updateOomAdjLocked();
+                    mService.updateOomAdjLocked(r.curApp, true);
                 }
             }
             try {
@@ -717,7 +767,7 @@
                 }
             }
             if (r.appOp != AppOpsManager.OP_NONE) {
-                int mode = mService.mAppOpsService.checkOperation(r.appOp,
+                int mode = mService.mAppOpsService.noteOperation(r.appOp,
                         info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
                 if (mode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG_BROADCAST)  Slog.v(TAG,
@@ -727,6 +777,10 @@
                     skip = true;
                 }
             }
+            if (!skip) {
+                skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
+                        r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
+            }
             boolean isSingleton = false;
             try {
                 isSingleton = mService.isSingleton(info.activityInfo.processName,
@@ -792,10 +846,10 @@
 
             // Is this receiver's application already running?
             ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
-                    info.activityInfo.applicationInfo.uid);
+                    info.activityInfo.applicationInfo.uid, false);
             if (app != null && app.thread != null) {
                 try {
-                    app.addPackage(info.activityInfo.packageName);
+                    app.addPackage(info.activityInfo.packageName, mService.mProcessStats);
                     processCurBroadcastLocked(r, app);
                     return;
                 } catch (RemoteException e) {
@@ -811,7 +865,7 @@
                     // sent the broadcast.
                     logBroadcastReceiverDiscardLocked(r);
                     finishReceiverLocked(r, r.resultCode, r.resultData,
-                            r.resultExtras, r.resultAbort, true);
+                            r.resultExtras, r.resultAbort, false);
                     scheduleBroadcastsLocked();
                     // We need to reset the state if we failed to start the receiver.
                     r.state = BroadcastRecord.IDLE;
@@ -830,7 +884,7 @@
                     info.activityInfo.applicationInfo, true,
                     r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                     "broadcast", r.curComponent,
-                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
+                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                             == null) {
                 // Ah, this recipient is unavailable.  Finish it if necessary,
                 // and mark the broadcast record as ready for the next.
@@ -840,7 +894,7 @@
                         + r.intent + ": process is bad");
                 logBroadcastReceiverDiscardLocked(r);
                 finishReceiverLocked(r, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
+                        r.resultExtras, r.resultAbort, false);
                 scheduleBroadcastsLocked();
                 r.state = BroadcastRecord.IDLE;
                 return;
@@ -907,7 +961,21 @@
             }
         }
 
-        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+        BroadcastRecord br = mOrderedBroadcasts.get(0);
+        if (br.state == BroadcastRecord.WAITING_SERVICES) {
+            // In this case the broadcast had already finished, but we had decided to wait
+            // for started services to finish as well before going on.  So if we have actually
+            // waited long enough time timeout the broadcast, let's give up on the whole thing
+            // and just move on to the next.
+            Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+                    ? br.curComponent.flattenToShortString() : "(null)"));
+            br.curComponent = null;
+            br.state = BroadcastRecord.IDLE;
+            processNextBroadcast(false);
+            return;
+        }
+
+        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
                 + ", started " + (now - r.receiverTime) + "ms ago");
         r.receiverTime = now;
         r.anrCount++;
@@ -947,7 +1015,7 @@
 
         // Move on to the next receiver.
         finishReceiverLocked(r, r.resultCode, r.resultData,
-                r.resultExtras, r.resultAbort, true);
+                r.resultExtras, r.resultAbort, false);
         scheduleBroadcastsLocked();
 
         if (anrMessage != null) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 83cc0ea..b2cfd7a 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -36,7 +36,7 @@
 /**
  * An active intent broadcast.
  */
-class BroadcastRecord extends Binder {
+final class BroadcastRecord extends Binder {
     final Intent intent;    // the original intent that generated us
     final ComponentName targetComp; // original component name set on the intent
     final ProcessRecord callerApp; // process that sent this
@@ -47,6 +47,7 @@
     final boolean sticky;   // originated from existing sticky data?
     final boolean initialSticky; // initial broadcast from register to sticky?
     final int userId;       // user id this broadcast was for
+    final String resolvedType; // the resolved data type
     final String requiredPermission; // a permission the caller has required
     final int appOp;        // an app op that is associated with this broadcast
     final List receivers;   // contains BroadcastFilter and ResolveInfo
@@ -69,6 +70,7 @@
     static final int APP_RECEIVE = 1;
     static final int CALL_IN_RECEIVE = 2;
     static final int CALL_DONE_RECEIVE = 3;
+    static final int WAITING_SERVICES = 4;
 
     // The following are set when we are calling a receiver (one that
     // was found in our list of registered receivers).
@@ -152,6 +154,7 @@
                 case APP_RECEIVE:       stateStr=" (APP_RECEIVE)"; break;
                 case CALL_IN_RECEIVE:   stateStr=" (CALL_IN_RECEIVE)"; break;
                 case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+                case WAITING_SERVICES:  stateStr=" (WAITING_SERVICES)"; break;
             }
             pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
         }
@@ -171,8 +174,8 @@
 
     BroadcastRecord(BroadcastQueue _queue,
             Intent _intent, ProcessRecord _callerApp, String _callerPackage,
-            int _callingPid, int _callingUid, String _requiredPermission, int _appOp,
-            List _receivers, IIntentReceiver _resultTo, int _resultCode,
+            int _callingPid, int _callingUid, String _resolvedType, String _requiredPermission,
+            int _appOp, List _receivers, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized,
             boolean _sticky, boolean _initialSticky,
             int _userId) {
@@ -183,6 +186,7 @@
         callerPackage = _callerPackage;
         callingPid = _callingPid;
         callingUid = _callingUid;
+        resolvedType = _resolvedType;
         requiredPermission = _requiredPermission;
         appOp = _appOp;
         receivers = _receivers;
diff --git a/services/java/com/android/server/am/CompatModeDialog.java b/services/java/com/android/server/am/CompatModeDialog.java
index 0442bda..202cc7c 100644
--- a/services/java/com/android/server/am/CompatModeDialog.java
+++ b/services/java/com/android/server/am/CompatModeDialog.java
@@ -28,7 +28,7 @@
 import android.widget.CompoundButton;
 import android.widget.Switch;
 
-public class CompatModeDialog extends Dialog {
+public final class CompatModeDialog extends Dialog {
     final ActivityManagerService mService;
     final ApplicationInfo mAppInfo;
 
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index 3a6492e..59e6787 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -15,7 +15,6 @@
 
 import android.app.ActivityManager;
 import android.app.AppGlobals;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.res.CompatibilityInfo;
@@ -26,7 +25,7 @@
 import android.util.Slog;
 import android.util.Xml;
 
-public class CompatModePackages {
+public final class CompatModePackages {
     private final String TAG = ActivityManagerService.TAG;
     private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
 
@@ -166,7 +165,7 @@
     }
 
     public boolean getFrontActivityAskCompatModeLocked() {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked(null);
         if (r == null) {
             return false;
         }
@@ -178,7 +177,7 @@
     }
 
     public void setFrontActivityAskCompatModeLocked(boolean ask) {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked(null);
         if (r != null) {
             setPackageAskCompatModeLocked(r.packageName, ask);
         }
@@ -200,7 +199,7 @@
     }
 
     public int getFrontActivityScreenCompatModeLocked() {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked(null);
         if (r == null) {
             return ActivityManager.COMPAT_MODE_UNKNOWN;
         }
@@ -208,7 +207,7 @@
     }
 
     public void setFrontActivityScreenCompatModeLocked(int mode) {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked(null);
         if (r == null) {
             Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
             return;
@@ -295,25 +294,13 @@
             Message msg = mHandler.obtainMessage(MSG_WRITE);
             mHandler.sendMessageDelayed(msg, 10000);
 
-            ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null);
-
-            // All activities that came from the package must be
-            // restarted as if there was a config change.
-            for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) {
-                ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i);
-                if (a.info.packageName.equals(packageName)) {
-                    a.forceNewConfig = true;
-                    if (starting != null && a == starting && a.visible) {
-                        a.startFreezingScreenLocked(starting.app,
-                                ActivityInfo.CONFIG_SCREEN_LAYOUT);
-                    }
-                }
-            }
+            final ActivityStack stack = mService.getFocusedStack();
+            ActivityRecord starting = stack.restartPackage(packageName);
 
             // Tell all processes that loaded this package about the change.
             for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
                 ProcessRecord app = mService.mLruProcesses.get(i);
-                if (!app.pkgList.contains(packageName)) {
+                if (!app.pkgList.containsKey(packageName)) {
                     continue;
                 }
                 try {
@@ -327,10 +314,10 @@
             }
 
             if (starting != null) {
-                mService.mMainStack.ensureActivityConfigurationLocked(starting, 0);
+                stack.ensureActivityConfigurationLocked(starting, 0);
                 // And we need to make sure at this point that all other activities
                 // are made visible with the correct configuration.
-                mService.mMainStack.ensureActivitiesVisibleLocked(starting, 0);
+                stack.ensureActivitiesVisibleLocked(starting, 0);
             }
         }
     }
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 4ed3c31..576adc2 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -25,7 +25,7 @@
 /**
  * Description of a single binding to a service.
  */
-class ConnectionRecord {
+final class ConnectionRecord {
     final AppBindRecord binding;    // The application/service binding.
     final ActivityRecord activity;   // If non-null, the owning activity.
     final IServiceConnection conn;  // The client connection.
@@ -89,12 +89,15 @@
         if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
             sb.append("ACT ");
         }
-        if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
-            sb.append("!VIS ");
-        }
         if ((flags&Context.BIND_VISIBLE) != 0) {
             sb.append("VIS ");
         }
+        if ((flags&Context.BIND_SHOWING_UI) != 0) {
+            sb.append("UI ");
+        }
+        if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
+            sb.append("!VIS ");
+        }
         if (serviceDead) {
             sb.append("DEAD ");
         }
diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/java/com/android/server/am/ContentProviderConnection.java
index 7f69b24..f2c9e2f 100644
--- a/services/java/com/android/server/am/ContentProviderConnection.java
+++ b/services/java/com/android/server/am/ContentProviderConnection.java
@@ -23,7 +23,7 @@
 /**
  * Represents a link between a content provider and client.
  */
-public class ContentProviderConnection extends Binder {
+public final class ContentProviderConnection extends Binder {
     public final ContentProviderRecord provider;
     public final ProcessRecord client;
     public final long createTime;
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 8fb6a93..646b7d2 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -33,7 +33,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 
-class ContentProviderRecord {
+final class ContentProviderRecord {
     final ActivityManagerService service;
     public final ProviderInfo info;
     final int uid;
diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/java/com/android/server/am/CoreSettingsObserver.java
index 585cf2b..10ea67c 100644
--- a/services/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/java/com/android/server/am/CoreSettingsObserver.java
@@ -33,7 +33,7 @@
  * disk I/O operations. Note: This class assumes that all core settings reside
  * in {@link Settings.Secure}.
  */
-class CoreSettingsObserver extends ContentObserver {
+final class CoreSettingsObserver extends ContentObserver {
     private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName();
 
     // mapping form property name to its type
diff --git a/services/java/com/android/server/am/DeviceMonitor.java b/services/java/com/android/server/am/DeviceMonitor.java
deleted file mode 100644
index 21e7252..0000000
--- a/services/java/com/android/server/am/DeviceMonitor.java
+++ /dev/null
@@ -1,234 +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 com.android.server.am;
-
-import android.os.SELinux;
-import android.util.Slog;
-
-import java.io.*;
-import java.util.Arrays;
-
-/**
- * Monitors device resources periodically for some period of time. Useful for
- * tracking down performance problems.
- */
-class DeviceMonitor {
-
-    private static final String LOG_TAG = DeviceMonitor.class.getName();
-
-    /** Number of samples to take. */
-    private static final int SAMPLE_COUNT = 10;
-
-    /** Time to wait in ms between samples. */
-    private static final int INTERVAL = 1000;
-
-    /** Time to wait in ms between samples. */
-    private static final int MAX_FILES = 30;
-
-    private final byte[] buffer = new byte[1024];
-
-    /** Is the monitor currently running? */
-    private boolean running = false;
-
-    private DeviceMonitor() {
-        new Thread() {
-            public void run() {
-                monitor();
-            }
-        }.start();
-    }
-
-    /**
-     * Loops continuously. Pauses until someone tells us to start monitoring.
-     */
-    @SuppressWarnings("InfiniteLoopStatement")
-    private void monitor() {
-        while (true) {
-            waitForStart();
-
-            purge();
-
-            for (int i = 0; i < SAMPLE_COUNT; i++) {
-                try {
-                    dump();
-                } catch (IOException e) {
-                    Slog.w(LOG_TAG, "Dump failed.", e);
-                }
-                pause();
-            }
-
-            stop();
-        }
-    }
-
-    private static final File PROC = new File("/proc");
-    private static final File BASE = new File("/data/anr/");
-    static {
-        if (!BASE.isDirectory() && !BASE.mkdirs()) {
-            throw new AssertionError("Couldn't create " + BASE + ".");
-        }
-        if (!SELinux.restorecon(BASE)) {
-            throw new AssertionError("Couldn't restorecon " + BASE + ".");
-        }
-    }
-
-    private static final File[] PATHS = {
-        new File(PROC, "zoneinfo"),
-        new File(PROC, "interrupts"),
-        new File(PROC, "meminfo"),
-        new File(PROC, "slabinfo"),
-    };
-
-
-    /**
-     * Deletes old files.
-     */
-    private void purge() {
-        File[] files = BASE.listFiles();
-        int count = files.length - MAX_FILES;
-        if (count > 0) {
-            Arrays.sort(files);
-            for (int i = 0; i < count; i++) {
-                if (!files[i].delete()) {
-                    Slog.w(LOG_TAG, "Couldn't delete " + files[i] + ".");
-                }
-            }
-        }
-    }
-
-    /**
-     * Dumps the current device stats to a new file.
-     */
-    private void dump() throws IOException {
-        OutputStream out = new FileOutputStream(
-                new File(BASE, String.valueOf(System.currentTimeMillis())));
-        try {
-            // Copy /proc/*/stat
-            for (File processDirectory : PROC.listFiles()) {
-                if (isProcessDirectory(processDirectory)) {
-                    dump(new File(processDirectory, "stat"), out);
-                }
-            }
-
-            // Copy other files.
-            for (File file : PATHS) {
-                dump(file, out);
-            }
-        } finally {
-            closeQuietly(out);
-        }
-    }
-
-    /**
-     * Returns true if the given file represents a process directory.
-     */
-    private static boolean isProcessDirectory(File file) {
-        try {
-            Integer.parseInt(file.getName());
-            return file.isDirectory();
-        } catch (NumberFormatException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Copies from a file to an output stream.
-     */
-    private void dump(File from, OutputStream out) throws IOException {
-        writeHeader(from, out);
-        
-        FileInputStream in = null;
-        try {
-            in = new FileInputStream(from);
-            int count;
-            while ((count = in.read(buffer)) != -1) {
-                out.write(buffer, 0, count);
-            }
-        } finally {
-            closeQuietly(in);
-        }
-    }
-
-    /**
-     * Writes a header for the given file.
-     */
-    private static void writeHeader(File file, OutputStream out)
-            throws IOException {
-        String header = "*** " + file.toString() + "\n";
-        out.write(header.getBytes());
-    }
-
-    /**
-     * Closes the given resource. Logs exceptions.
-     * @param closeable
-     */
-    private static void closeQuietly(Closeable closeable) {
-        try {
-            if (closeable != null) {
-                closeable.close();
-            }
-        } catch (IOException e) {
-            Slog.w(LOG_TAG, e);
-        }
-    }
-
-    /**
-     * Pauses momentarily before we start the next dump.
-     */
-    private void pause() {
-        try {
-            Thread.sleep(INTERVAL);
-        } catch (InterruptedException e) { /* ignore */ }
-    }
-
-    /**
-     * Stops dumping.
-     */
-    private synchronized void stop() {
-        running = false;        
-    }
-
-    /**
-     * Waits until someone starts us.
-     */
-    private synchronized void waitForStart() {
-        while (!running) {
-            try {
-                wait();
-            } catch (InterruptedException e) { /* ignore */ }
-        }
-    }
-
-    /**
-     * Instructs the monitoring to start if it hasn't already.
-     */
-    private synchronized void startMonitoring() {
-        if (!running) {
-            running = true;
-            notifyAll();
-        }
-    }
-
-    private static DeviceMonitor instance = new DeviceMonitor();
-
-    /**
-     * Starts monitoring if it hasn't started already.
-     */
-    static void start() {
-        instance.startMonitoring();
-    }
-}
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index f784861..d3cc56b 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -63,7 +63,7 @@
 30024 am_broadcast_discard_filter (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
 30025 am_broadcast_discard_app (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
 # A service is being created
-30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5)
+30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(UID|1|5),(PID|1|5)
 # A service is being destroyed
 30031 am_destroy_service (User|1|5),(Service Record|1|5),(PID|1|5)
 # A process has crashed too many times, it is being cleared
@@ -86,3 +86,6 @@
 
 # User switched
 30041 am_switch_user (id|1|5)
+
+# Activity fully drawn time
+30042 am_activity_fully_drawn_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java
index 0ffb588..f4632c1 100644
--- a/services/java/com/android/server/am/FactoryErrorDialog.java
+++ b/services/java/com/android/server/am/FactoryErrorDialog.java
@@ -22,7 +22,7 @@
 import android.os.Message;
 import android.view.WindowManager;
 
-class FactoryErrorDialog extends BaseErrorDialog {
+final class FactoryErrorDialog extends BaseErrorDialog {
     public FactoryErrorDialog(Context context, CharSequence msg) {
         super(context);
         setCancelable(false);
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java
index 0a92964..21cf266 100644
--- a/services/java/com/android/server/am/IntentBindRecord.java
+++ b/services/java/com/android/server/am/IntentBindRecord.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
+import android.util.ArrayMap;
 
 import java.io.PrintWriter;
 import java.util.HashMap;
@@ -27,14 +28,14 @@
 /**
  * A particular Intent that has been bound to a Service.
  */
-class IntentBindRecord {
+final class IntentBindRecord {
     /** The running service. */
     final ServiceRecord service;
     /** The intent that is bound.*/
     final Intent.FilterComparison intent; // 
     /** All apps that have bound to this Intent. */
-    final HashMap<ProcessRecord, AppBindRecord> apps
-            = new HashMap<ProcessRecord, AppBindRecord>();
+    final ArrayMap<ProcessRecord, AppBindRecord> apps
+            = new ArrayMap<ProcessRecord, AppBindRecord>();
     /** Binder published from service. */
     IBinder binder;
     /** Set when we have initiated a request for this binder. */
@@ -62,15 +63,12 @@
                 pw.print(" received="); pw.print(received);
                 pw.print(" hasBound="); pw.print(hasBound);
                 pw.print(" doRebind="); pw.println(doRebind);
-        if (apps.size() > 0) {
-            Iterator<AppBindRecord> it = apps.values().iterator();
-            while (it.hasNext()) {
-                AppBindRecord a = it.next();
-                pw.print(prefix); pw.print("* Client AppBindRecord{");
-                        pw.print(Integer.toHexString(System.identityHashCode(a)));
-                        pw.print(' '); pw.print(a.client); pw.println('}');
-                a.dumpInIntentBind(pw, prefix + "  ");
-            }
+        for (int i=0; i<apps.size(); i++) {
+            AppBindRecord a = apps.valueAt(i);
+            pw.print(prefix); pw.print("* Client AppBindRecord{");
+                    pw.print(Integer.toHexString(System.identityHashCode(a)));
+                    pw.print(' '); pw.print(a.client); pw.println('}');
+            a.dumpInIntentBind(pw, prefix + "  ");
         }
     }
 
@@ -81,12 +79,11 @@
 
     int collectFlags() {
         int flags = 0;
-        if (apps.size() > 0) {
-            for (AppBindRecord app : apps.values()) {
-                if (app.connections.size() > 0) {
-                    for (ConnectionRecord conn : app.connections) {
-                        flags |= conn.flags;
-                    }
+        for (int i=apps.size()-1; i>=0; i--) {
+            AppBindRecord app = apps.valueAt(i);
+            if (app.connections.size() > 0) {
+                for (ConnectionRecord conn : app.connections) {
+                    flags |= conn.flags;
                 }
             }
         }
diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/java/com/android/server/am/LaunchWarningWindow.java
index cb2b7bb..30c3066 100644
--- a/services/java/com/android/server/am/LaunchWarningWindow.java
+++ b/services/java/com/android/server/am/LaunchWarningWindow.java
@@ -26,7 +26,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-public class LaunchWarningWindow extends Dialog {
+public final class LaunchWarningWindow extends Dialog {
     public LaunchWarningWindow(Context context, ActivityRecord cur, ActivityRecord next) {
         super(context, R.style.Theme_Toast);
 
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java
index a9454bd..2c7f1f1 100644
--- a/services/java/com/android/server/am/NativeCrashListener.java
+++ b/services/java/com/android/server/am/NativeCrashListener.java
@@ -40,7 +40,7 @@
  *
  * Note that this component runs in a separate thread.
  */
-class NativeCrashListener extends Thread {
+final class NativeCrashListener extends Thread {
     static final String TAG = "NativeCrashListener";
     static final boolean DEBUG = false;
     static final boolean MORE_DEBUG = DEBUG && false;
@@ -152,6 +152,13 @@
                                 Slog.d(TAG, "Exception writing ack: " + e.getMessage());
                             }
                         }
+                        try {
+                            Libcore.os.close(peerFd);
+                        } catch (ErrnoException e) {
+                            if (MORE_DEBUG) {
+                                Slog.d(TAG, "Exception closing socket: " + e.getMessage());
+                            }
+                        }
                     }
                 }
             }
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 8ab71dd..17f24a9 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -31,7 +31,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 
-class PendingIntentRecord extends IIntentSender.Stub {
+final class PendingIntentRecord extends IIntentSender.Stub {
     final ActivityManagerService owner;
     final Key key;
     final int uid;
@@ -259,7 +259,7 @@
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
-                        key.activity.stack.sendActivityResultLocked(-1, key.activity,
+                        key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
                                 key.who, key.requestCode, code, finalIntent);
                         break;
                     case ActivityManager.INTENT_SENDER_BROADCAST:
diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/java/com/android/server/am/PendingThumbnailsRecord.java
index ed478c9..e4eb4d0 100644
--- a/services/java/com/android/server/am/PendingThumbnailsRecord.java
+++ b/services/java/com/android/server/am/PendingThumbnailsRecord.java
@@ -24,16 +24,16 @@
  * This class keeps track of calls to getTasks() that are still
  * waiting for thumbnail images.
  */
-class PendingThumbnailsRecord
+final class PendingThumbnailsRecord
 {
     final IThumbnailReceiver receiver;   // who is waiting.
-    HashSet pendingRecords; // HistoryRecord objects we still wait for.
+    final HashSet<ActivityRecord> pendingRecords; // HistoryRecord objects we still wait for.
     boolean finished;       // Is pendingRecords empty?
 
     PendingThumbnailsRecord(IThumbnailReceiver _receiver)
     {
         receiver = _receiver;
-        pendingRecords = new HashSet();
+        pendingRecords = new HashSet<ActivityRecord>();
         finished = false;
     }
 }
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index 1a635a9..d3777c7 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -19,27 +19,35 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
+import android.app.ActivityManager;
 import com.android.internal.util.MemInfoReader;
 import com.android.server.wm.WindowManagerService;
 
+import android.content.res.Resources;
 import android.graphics.Point;
+import android.os.SystemProperties;
 import android.util.Slog;
 import android.view.Display;
 
 /**
  * Activity manager code dealing with processes.
  */
-class ProcessList {
+final class ProcessList {
     // The minimum time we allow between crashes, for us to consider this
     // application to be bad and stop and its services and reject broadcasts.
     static final int MIN_CRASH_INTERVAL = 60*1000;
 
     // OOM adjustments for processes in various states:
 
+    // Adjustment used in certain places where we don't know it yet.
+    // (Generally this is something that is going to be cached, but we
+    // don't know the exact value in the cached range to assign yet.)
+    static final int UNKNOWN_ADJ = 16;
+
     // This is a process only hosting activities that are not visible,
     // so it can be killed without any disruption.
-    static final int HIDDEN_APP_MAX_ADJ = 15;
-    static int HIDDEN_APP_MIN_ADJ = 9;
+    static final int CACHED_APP_MAX_ADJ = 15;
+    static final int CACHED_APP_MIN_ADJ = 9;
 
     // The B list of SERVICE_ADJ -- these are the old and decrepit
     // services that aren't as shiny and interesting as the ones in the A list.
@@ -62,14 +70,14 @@
     // have much of an impact as far as the user is concerned.
     static final int SERVICE_ADJ = 5;
 
-    // This is a process currently hosting a backup operation.  Killing it
-    // is not entirely fatal but is generally a bad idea.
-    static final int BACKUP_APP_ADJ = 4;
-
     // This is a process with a heavy-weight application.  It is in the
     // background, but we want to try to avoid killing it.  Value set in
     // system/rootdir/init.rc on startup.
-    static final int HEAVY_WEIGHT_APP_ADJ = 3;
+    static final int HEAVY_WEIGHT_APP_ADJ = 4;
+
+    // This is a process currently hosting a backup operation.  Killing it
+    // is not entirely fatal but is generally a bad idea.
+    static final int BACKUP_APP_ADJ = 3;
 
     // This is a process only hosting components that are perceptible to the
     // user, and we really want to avoid killing them, but they are not
@@ -91,49 +99,54 @@
     // The system process runs at the default adjustment.
     static final int SYSTEM_ADJ = -16;
 
+    // Special code for native processes that are not being managed by the system (so
+    // don't have an oom adj assigned by the system).
+    static final int NATIVE_ADJ = -17;
+
     // Memory pages are 4K.
     static final int PAGE_SIZE = 4*1024;
 
-    // The minimum number of hidden apps we want to be able to keep around,
+    // The minimum number of cached apps we want to be able to keep around,
     // without empty apps being able to push them out of memory.
-    static final int MIN_HIDDEN_APPS = 2;
+    static final int MIN_CACHED_APPS = 2;
 
-    // The maximum number of hidden processes we will keep around before
-    // killing them; this is just a control to not let us go too crazy with
-    // keeping around processes on devices with large amounts of RAM.
-    static final int MAX_HIDDEN_APPS = 24;
+    // The maximum number of cached processes we will keep around before killing them.
+    // NOTE: this constant is *only* a control to not let us go too crazy with
+    // keeping around processes on devices with large amounts of RAM.  For devices that
+    // are tighter on RAM, the out of memory killer is responsible for killing background
+    // processes as RAM is needed, and we should *never* be relying on this limit to
+    // kill them.  Also note that this limit only applies to cached background processes;
+    // we have no limit on the number of service, visible, foreground, or other such
+    // processes and the number of those processes does not count against the cached
+    // process limit.
+    static final int MAX_CACHED_APPS = 24;
 
     // We allow empty processes to stick around for at most 30 minutes.
     static final long MAX_EMPTY_TIME = 30*60*1000;
 
-    // The number of hidden at which we don't consider it necessary to do
-    // memory trimming.
-    static final int TRIM_HIDDEN_APPS = 3;
+    // The maximum number of empty app processes we will let sit around.
+    private static final int MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS);
 
     // The number of empty apps at which we don't consider it necessary to do
     // memory trimming.
-    static final int TRIM_EMPTY_APPS = 3;
+    static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;
 
-    // Threshold of number of hidden+empty where we consider memory critical.
+    // The number of cached at which we don't consider it necessary to do
+    // memory trimming.
+    static final int TRIM_CACHED_APPS = ((MAX_CACHED_APPS-MAX_EMPTY_APPS)*2)/3;
+
+    // Threshold of number of cached+empty where we consider memory critical.
     static final int TRIM_CRITICAL_THRESHOLD = 3;
 
-    // Threshold of number of hidden+empty where we consider memory critical.
+    // Threshold of number of cached+empty where we consider memory critical.
     static final int TRIM_LOW_THRESHOLD = 5;
 
-    // We put empty content processes after any hidden processes that have
-    // been idle for less than 15 seconds.
-    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
-
-    // We put empty content processes after any hidden processes that have
-    // been idle for less than 120 seconds.
-    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
-
     // These are the various interesting memory levels that we will give to
     // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
     // can't give it a different value for every possible kind of process.
     private final int[] mOomAdj = new int[] {
             FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
-            BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ
+            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
     };
     // These are the low-end OOM level limits.  This is appropriate for an
     // HVGA or smaller phone with less than 512MB.  Values are in KB.
@@ -152,6 +165,8 @@
 
     private final long mTotalMemMb;
 
+    private long mCachedRestoreLevel;
+
     private boolean mHaveDisplaySize;
 
     ProcessList() {
@@ -164,7 +179,7 @@
     void applyDisplaySize(WindowManagerService wm) {
         if (!mHaveDisplaySize) {
             Point p = new Point();
-            wm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, p);
+            wm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, p);
             if (p.x != 0 && p.y != 0) {
                 updateOomLevels(p.x, p.y, true);
                 mHaveDisplaySize = true;
@@ -178,10 +193,14 @@
         float scaleMem = ((float)(mTotalMemMb-300))/(700-300);
 
         // Scale buckets from screen size.
-        int minSize = 320*480;  //  153600
+        int minSize = 480*800;  //  384000
         int maxSize = 1280*800; // 1024000  230400 870400  .264
         float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
-        //Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);
+        if (false) {
+            Slog.i("XXXXXX", "scaleMem=" + scaleMem);
+            Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth
+                    + " dh=" + displayHeight);
+        }
 
         StringBuilder adjString = new StringBuilder();
         StringBuilder memString = new StringBuilder();
@@ -189,11 +208,41 @@
         float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
         if (scale < 0) scale = 0;
         else if (scale > 1) scale = 1;
+        int minfree_adj = Resources.getSystem().getInteger(
+                com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAdjust);
+        int minfree_abs = Resources.getSystem().getInteger(
+                com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAbsolute);
+        if (false) {
+            Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
+        }
+
         for (int i=0; i<mOomAdj.length; i++) {
             long low = mOomMinFreeLow[i];
             long high = mOomMinFreeHigh[i];
             mOomMinFree[i] = (long)(low + ((high-low)*scale));
+        }
 
+        if (minfree_abs >= 0) {
+            for (int i=0; i<mOomAdj.length; i++) {
+                mOomMinFree[i] = (long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
+            }
+        }
+
+        if (minfree_adj != 0) {
+            for (int i=0; i<mOomAdj.length; i++) {
+                mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
+                if (mOomMinFree[i] < 0) {
+                    mOomMinFree[i] = 0;
+                }
+            }
+        }
+
+        // The maximum size we will restore a process from cached to background, when under
+        // memory duress, is 1/3 the size we have reserved for kernel caches and other overhead
+        // before killing background processes.
+        mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;
+
+        for (int i=0; i<mOomAdj.length; i++) {
             if (i > 0) {
                 adjString.append(',');
                 memString.append(',');
@@ -202,15 +251,244 @@
             memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
         }
 
+        // Ask the kernel to try to keep enough memory free to allocate 3 full
+        // screen 32bpp buffers without entering direct reclaim.
+        int reserve = displayWidth * displayHeight * 4 * 3 / 1024;
+        int reserve_adj = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAdjust);
+        int reserve_abs = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAbsolute);
+
+        if (reserve_abs >= 0) {
+            reserve = reserve_abs;
+        }
+
+        if (reserve_adj != 0) {
+            reserve += reserve_adj;
+            if (reserve < 0) {
+                reserve = 0;
+            }
+        }
+
         //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
         if (write) {
             writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
             writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
+            SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
         }
         // GB: 2048,3072,4096,6144,7168,8192
         // HC: 8192,10240,12288,14336,16384,20480
     }
 
+    public static int computeEmptyProcessLimit(int totalProcessLimit) {
+        return (totalProcessLimit*2)/3;
+    }
+
+    private static String buildOomTag(String prefix, String space, int val, int base) {
+        if (val == base) {
+            if (space == null) return prefix;
+            return prefix + "  ";
+        }
+        return prefix + "+" + Integer.toString(val-base);
+    }
+
+    public static String makeOomAdjString(int setAdj) {
+        if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+            return buildOomTag("cch", "  ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+        } else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
+            return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+        } else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
+            return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+        } else if (setAdj >= ProcessList.HOME_APP_ADJ) {
+            return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
+        } else if (setAdj >= ProcessList.SERVICE_ADJ) {
+            return buildOomTag("svc  ", null, setAdj, ProcessList.SERVICE_ADJ);
+        } else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+            return buildOomTag("hvy  ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+        } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
+            return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+        } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+            return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+        } else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
+            return buildOomTag("vis  ", null, setAdj, ProcessList.VISIBLE_APP_ADJ);
+        } else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+            return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+        } else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
+            return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+        } else if (setAdj >= ProcessList.SYSTEM_ADJ) {
+            return buildOomTag("sys  ", null, setAdj, ProcessList.SYSTEM_ADJ);
+        } else if (setAdj >= ProcessList.NATIVE_ADJ) {
+            return buildOomTag("ntv  ", null, setAdj, ProcessList.NATIVE_ADJ);
+        } else {
+            return Integer.toString(setAdj);
+        }
+    }
+
+    public static String makeProcStateString(int curProcState) {
+        String procState;
+        switch (curProcState) {
+            case -1:
+                procState = "N ";
+                break;
+            case ActivityManager.PROCESS_STATE_PERSISTENT:
+                procState = "P ";
+                break;
+            case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+                procState = "PU";
+                break;
+            case ActivityManager.PROCESS_STATE_TOP:
+                procState = "T ";
+                break;
+            case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+                procState = "IF";
+                break;
+            case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+                procState = "IB";
+                break;
+            case ActivityManager.PROCESS_STATE_BACKUP:
+                procState = "BU";
+                break;
+            case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+                procState = "HW";
+                break;
+            case ActivityManager.PROCESS_STATE_SERVICE:
+                procState = "S ";
+                break;
+            case ActivityManager.PROCESS_STATE_RECEIVER:
+                procState = "R ";
+                break;
+            case ActivityManager.PROCESS_STATE_HOME:
+                procState = "HO";
+                break;
+            case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+                procState = "LA";
+                break;
+            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                procState = "CA";
+                break;
+            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                procState = "Ca";
+                break;
+            case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+                procState = "CE";
+                break;
+            default:
+                procState = "??";
+                break;
+        }
+        return procState;
+    }
+
+    public static void appendRamKb(StringBuilder sb, long ramKb) {
+        for (int j=0, fact=10; j<6; j++, fact*=10) {
+            if (ramKb < fact) {
+                sb.append(' ');
+            }
+        }
+        sb.append(ramKb);
+    }
+
+    // The minimum amount of time after a state change it is safe ro collect PSS.
+    public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000;
+
+    // The maximum amount of time we want to go between PSS collections.
+    public static final int PSS_MAX_INTERVAL = 30*60*1000;
+
+    // The minimum amount of time between successive PSS requests for *all* processes.
+    public static final int PSS_ALL_INTERVAL = 10*60*1000;
+
+    // The minimum amount of time between successive PSS requests for a process.
+    private static final int PSS_SHORT_INTERVAL = 2*60*1000;
+
+    // The amount of time until PSS when a process first becomes top.
+    private static final int PSS_FIRST_TOP_INTERVAL = 10*1000;
+
+    // The amount of time until PSS when a process first goes into the background.
+    private static final int PSS_FIRST_BACKGROUND_INTERVAL = 20*1000;
+
+    // The amount of time until PSS when a process first becomes cached.
+    private static final int PSS_FIRST_CACHED_INTERVAL = 30*1000;
+
+    // The amount of time until PSS when an important process stays in the same state.
+    private static final int PSS_SAME_IMPORTANT_INTERVAL = 15*60*1000;
+
+    // The amount of time until PSS when a service process stays in the same state.
+    private static final int PSS_SAME_SERVICE_INTERVAL = 20*60*1000;
+
+    // The amount of time until PSS when a cached process stays in the same state.
+    private static final int PSS_SAME_CACHED_INTERVAL = 30*60*1000;
+
+    public static final int PROC_MEM_PERSISTENT = 0;
+    public static final int PROC_MEM_TOP = 1;
+    public static final int PROC_MEM_IMPORTANT = 2;
+    public static final int PROC_MEM_SERVICE = 3;
+    public static final int PROC_MEM_CACHED = 4;
+
+    private static final int[] sProcStateToProcMem = new int[] {
+        PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT
+        PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BACKUP
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        PROC_MEM_SERVICE,               // ActivityManager.PROCESS_STATE_SERVICE
+        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_RECEIVER
+        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_HOME
+        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
+    private static final long[] sFirstAwakePssTimes = new long[] {
+        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_PERSISTENT
+        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        PSS_FIRST_TOP_INTERVAL,         // ActivityManager.PROCESS_STATE_TOP
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_BACKUP
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_SERVICE
+        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_RECEIVER
+        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_HOME
+        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
+    private static final long[] sSameAwakePssTimes = new long[] {
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_TOP
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BACKUP
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        PSS_SAME_SERVICE_INTERVAL,      // ActivityManager.PROCESS_STATE_SERVICE
+        PSS_SAME_SERVICE_INTERVAL,      // ActivityManager.PROCESS_STATE_RECEIVER
+        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_HOME
+        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
+    public static boolean procStatesDifferForMem(int procState1, int procState2) {
+        return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
+    }
+
+    public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
+            long now) {
+        final long[] table = sleeping
+                ? (first
+                        ? sFirstAwakePssTimes
+                        : sSameAwakePssTimes)
+                : (first
+                        ? sFirstAwakePssTimes
+                        : sSameAwakePssTimes);
+        return now + table[procState];
+    }
+
     long getMemLevel(int adjustment) {
         for (int i=0; i<mOomAdj.length; i++) {
             if (adjustment <= mOomAdj[i]) {
@@ -220,6 +498,14 @@
         return mOomMinFree[mOomAdj.length-1] * 1024;
     }
 
+    /**
+     * Return the maximum pss size in kb that we consider a process acceptable to
+     * restore from its cached state for running in the background when RAM is low.
+     */
+    long getCachedRestoreThresholdKb() {
+        return mCachedRestoreLevel;
+    }
+
     private void writeFile(String path, String data) {
         FileOutputStream fos = null;
         try {
diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/java/com/android/server/am/ProcessMemInfo.java
new file mode 100644
index 0000000..c94694e
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessMemInfo.java
@@ -0,0 +1,37 @@
+/*
+ * 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.am;
+
+public class ProcessMemInfo {
+    final String name;
+    final int pid;
+    final int oomAdj;
+    final int procState;
+    final String adjType;
+    final String adjReason;
+    long pss;
+
+    public ProcessMemInfo(String _name, int _pid, int _oomAdj, int _procState,
+            String _adjType, String _adjReason) {
+        name = _name;
+        pid = _pid;
+        oomAdj = _oomAdj;
+        procState = _procState;
+        adjType = _adjType;
+        adjReason = _adjReason;
+    }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 7929f96..4b62e7d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import android.util.ArraySet;
+import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
 
 import android.app.ActivityManager;
@@ -32,19 +34,18 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.PrintWriterPrinter;
 import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
 
 /**
  * Full information about a particular process that
  * is currently running.
  */
-class ProcessRecord {
+final class ProcessRecord {
     final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
     final ApplicationInfo info; // all about the first app in the process
     final boolean isolated;     // true if this is a special isolated process
@@ -52,32 +53,42 @@
     final int userId;           // user of process.
     final String processName;   // name of the process
     // List of packages running in the process
-    final HashSet<String> pkgList = new HashSet<String>();
+    final ArrayMap<String, ProcessStats.ProcessState> pkgList
+            = new ArrayMap<String, ProcessStats.ProcessState>();
     IApplicationThread thread;  // the actual proc...  may be null only if
                                 // 'persistent' is true (in which case we
                                 // are in the process of launching the app)
+    ProcessStats.ProcessState baseProcessTracker;
     int pid;                    // The process of this application; 0 if none
     boolean starting;           // True if the process is being started
     long lastActivityTime;      // For managing the LRU list
-    long lruWeight;             // Weight for ordering in LRU list
+    long lastPssTime;           // Last time we retrieved PSS data
+    long nextPssTime;           // Next time we want to request PSS data
+    long lastStateTime;         // Last time setProcState changed
+    long initialIdlePss;        // Initial memory pss of process for idle maintenance.
+    long lastPss;               // Last computed memory pss.
+    long lastCachedPss;         // Last computed pss when in cached state.
     int maxAdj;                 // Maximum OOM adjustment for this process
-    int hiddenAdj;              // If hidden, this is the adjustment to use
-    int clientHiddenAdj;        // If empty but hidden client, this is the adjustment to use
-    int emptyAdj;               // If empty, this is the adjustment to use
     int curRawAdj;              // Current OOM unlimited adjustment for this process
     int setRawAdj;              // Last set OOM unlimited adjustment for this process
-    int nonStoppingAdj;         // Adjustment not counting any stopping activities
     int curAdj;                 // Current OOM adjustment for this process
     int setAdj;                 // Last set OOM adjustment for this process
     int curSchedGroup;          // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
     int trimMemoryLevel;        // Last selected memory trimming level
     int memImportance;          // Importance constant computed from curAdj
+    int curProcState = -1;      // Currently computed process state: ActivityManager.PROCESS_STATE_*
+    int repProcState = -1;      // Last reported process state
+    int setProcState = -1;      // Last set process state in process tracker
+    int pssProcState = -1;      // The proc state we are currently requesting pss for
     boolean serviceb;           // Process currently is on the service B list
+    boolean serviceHighRam;     // We are forcing to service B list due to its RAM use
     boolean keeping;            // Actively running code so don't kill due to that?
     boolean setIsForeground;    // Running foreground UI when last set?
+    boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
     boolean hasActivities;      // Are there any activities running in this process?
     boolean hasClientActivities;  // Are there any client services with activities?
+    boolean hasStartedServices; // Are there any started services running in this process?
     boolean foregroundServices; // Running any services that are foreground?
     boolean foregroundActivities; // Running any activities that are foreground?
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
@@ -85,7 +96,8 @@
     boolean pendingUiClean;     // Want to clean up resources from showing UI?
     boolean hasAboveClient;     // Bound using BIND_ABOVE_CLIENT, so want to be lower
     boolean bad;                // True if disabled in the bad process list
-    boolean killedBackground;   // True when proc has been killed due to too many bg
+    boolean killedByAm;         // True when proc has been killed by activity manager, not for RAM
+    boolean procStateChanged;   // Keep track of whether we changed 'setAdj'.
     String waitingToKill;       // Process is waiting to be killed when in the bg; reason
     IBinder forcingToForeground;// Token that is forcing this process to be foreground
     int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
@@ -108,8 +120,7 @@
     long lastLowMemory;         // When we last told the app that memory is low
     boolean reportLowMemory;    // Set to true when waiting to report low mem
     boolean empty;              // Is this an empty background process?
-    boolean hidden;             // Is this a hidden process?
-    int lastPss;                // Last pss size reported by app.
+    boolean cached;             // Is this a cached process?
     String adjType;             // Debugging: primary thing impacting oom_adj.
     int adjTypeCode;            // Debugging: adj code to report to app.
     Object adjSource;           // Debugging: option dependent object.
@@ -119,22 +130,23 @@
     // contains HistoryRecord objects
     final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
     // all ServiceRecord running in this process
-    final HashSet<ServiceRecord> services = new HashSet<ServiceRecord>();
+    final ArraySet<ServiceRecord> services = new ArraySet<ServiceRecord>();
     // services that are currently executing code (need to remain foreground).
-    final HashSet<ServiceRecord> executingServices
-             = new HashSet<ServiceRecord>();
+    final ArraySet<ServiceRecord> executingServices
+             = new ArraySet<ServiceRecord>();
     // All ConnectionRecord this process holds
-    final HashSet<ConnectionRecord> connections
-            = new HashSet<ConnectionRecord>();  
+    final ArraySet<ConnectionRecord> connections
+            = new ArraySet<ConnectionRecord>();
     // all IIntentReceivers that are registered from this process.
-    final HashSet<ReceiverList> receivers = new HashSet<ReceiverList>();
+    final ArraySet<ReceiverList> receivers = new ArraySet<ReceiverList>();
     // class (String) -> ContentProviderRecord
-    final HashMap<String, ContentProviderRecord> pubProviders
-            = new HashMap<String, ContentProviderRecord>(); 
+    final ArrayMap<String, ContentProviderRecord> pubProviders
+            = new ArrayMap<String, ContentProviderRecord>();
     // All ContentProviderRecord process is using
     final ArrayList<ContentProviderConnection> conProviders
             = new ArrayList<ContentProviderConnection>();
-    
+
+    boolean execServicesFg;     // do we need to be executing services in the foreground?
     boolean persistent;         // always keep this application running?
     boolean crashing;           // are we in the process of crashing?
     Dialog crashDialog;         // dialog being displayed due to crash.
@@ -177,7 +189,12 @@
         pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir);
                 pw.print(" publicDir="); pw.print(info.publicSourceDir);
                 pw.print(" data="); pw.println(info.dataDir);
-        pw.print(prefix); pw.print("packageList="); pw.println(pkgList);
+        pw.print(prefix); pw.print("packageList={");
+        for (int i=0; i<pkgList.size(); i++) {
+            if (i > 0) pw.print(", ");
+            pw.print(pkgList.keyAt(i));
+        }
+        pw.println("}");
         pw.print(prefix); pw.print("compat="); pw.println(compat);
         if (instrumentationClass != null || instrumentationProfileFile != null
                 || instrumentationArguments != null) {
@@ -195,29 +212,45 @@
         }
         pw.print(prefix); pw.print("thread="); pw.println(thread);
         pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
-                pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
+                pw.println(starting);
         pw.print(prefix); pw.print("lastActivityTime=");
                 TimeUtils.formatDuration(lastActivityTime, now, pw);
-                pw.print(" lruWeight="); pw.print(lruWeight);
-                pw.print(" serviceb="); pw.print(serviceb);
-                pw.print(" keeping="); pw.print(keeping);
-                pw.print(" hidden="); pw.print(hidden);
+                pw.print(" lastPssTime=");
+                TimeUtils.formatDuration(lastPssTime, now, pw);
+                pw.print(" nextPssTime=");
+                TimeUtils.formatDuration(nextPssTime, now, pw);
+                pw.println();
+        pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
+                pw.print(" lruSeq="); pw.print(lruSeq);
+                pw.print(" lastPss="); pw.print(lastPss);
+                pw.print(" lastCachedPss="); pw.println(lastCachedPss);
+        pw.print(prefix); pw.print("keeping="); pw.print(keeping);
+                pw.print(" cached="); pw.print(cached);
                 pw.print(" empty="); pw.println(empty);
+        if (serviceb) {
+            pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
+                    pw.print(" serviceHighRam="); pw.println(serviceHighRam);
+        }
+        if (notCachedSinceIdle) {
+            pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
+                    pw.print(" initialIdlePss="); pw.println(initialIdlePss);
+        }
         pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
-                pw.print(" hidden="); pw.print(hiddenAdj);
-                pw.print(" client="); pw.print(clientHiddenAdj);
-                pw.print(" empty="); pw.print(emptyAdj);
                 pw.print(" curRaw="); pw.print(curRawAdj);
                 pw.print(" setRaw="); pw.print(setRawAdj);
-                pw.print(" nonStopping="); pw.print(nonStoppingAdj);
                 pw.print(" cur="); pw.print(curAdj);
                 pw.print(" set="); pw.println(setAdj);
         pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
                 pw.print(" setSchedGroup="); pw.print(setSchedGroup);
                 pw.print(" systemNoUi="); pw.print(systemNoUi);
                 pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
-        pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
-                pw.print(" lruSeq="); pw.println(lruSeq);
+        pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
+                pw.print(" repProcState="); pw.print(repProcState);
+                pw.print(" pssProcState="); pw.print(pssProcState);
+                pw.print(" setProcState="); pw.print(setProcState);
+                pw.print(" lastStateTime=");
+                TimeUtils.formatDuration(lastStateTime, now, pw);
+                pw.println();
         if (hasShownUi || pendingUiClean || hasAboveClient) {
             pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
                     pw.print(" pendingUiClean="); pw.print(pendingUiClean);
@@ -237,6 +270,9 @@
                     pw.print(" hasClientActivities="); pw.print(hasClientActivities);
                     pw.print(" foregroundActivities="); pw.println(foregroundActivities);
         }
+        if (hasStartedServices) {
+            pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
+        }
         if (!keeping) {
             long wtime;
             synchronized (batteryStats.getBatteryStats()) {
@@ -256,8 +292,8 @@
                 pw.print(" lastLowMemory=");
                 TimeUtils.formatDuration(lastLowMemory, now, pw);
                 pw.print(" reportLowMemory="); pw.println(reportLowMemory);
-        if (killedBackground || waitingToKill != null) {
-            pw.print(prefix); pw.print("killedBackground="); pw.print(killedBackground);
+        if (killedByAm || waitingToKill != null) {
+            pw.print(prefix); pw.print("killedByAm="); pw.print(killedByAm);
                     pw.print(" waitingToKill="); pw.println(waitingToKill);
         }
         if (debugging || crashing || crashDialog != null || notResponding
@@ -284,27 +320,28 @@
         }
         if (services.size() > 0) {
             pw.print(prefix); pw.println("Services:");
-            for (ServiceRecord sr : services) {
-                pw.print(prefix); pw.print("  - "); pw.println(sr);
+            for (int i=0; i<services.size(); i++) {
+                pw.print(prefix); pw.print("  - "); pw.println(services.valueAt(i));
             }
         }
         if (executingServices.size() > 0) {
-            pw.print(prefix); pw.println("Executing Services:");
-            for (ServiceRecord sr : executingServices) {
-                pw.print(prefix); pw.print("  - "); pw.println(sr);
+            pw.print(prefix); pw.print("Executing Services (fg=");
+            pw.print(execServicesFg); pw.println(")");
+            for (int i=0; i<executingServices.size(); i++) {
+                pw.print(prefix); pw.print("  - "); pw.println(executingServices.valueAt(i));
             }
         }
         if (connections.size() > 0) {
             pw.print(prefix); pw.println("Connections:");
-            for (ConnectionRecord cr : connections) {
-                pw.print(prefix); pw.print("  - "); pw.println(cr);
+            for (int i=0; i<connections.size(); i++) {
+                pw.print(prefix); pw.print("  - "); pw.println(connections.valueAt(i));
             }
         }
         if (pubProviders.size() > 0) {
             pw.print(prefix); pw.println("Published Providers:");
-            for (HashMap.Entry<String, ContentProviderRecord> ent : pubProviders.entrySet()) {
-                pw.print(prefix); pw.print("  - "); pw.println(ent.getKey());
-                pw.print(prefix); pw.print("    -> "); pw.println(ent.getValue());
+            for (int i=0; i<pubProviders.size(); i++) {
+                pw.print(prefix); pw.print("  - "); pw.println(pubProviders.keyAt(i));
+                pw.print(prefix); pw.print("    -> "); pw.println(pubProviders.valueAt(i));
             }
         }
         if (conProviders.size() > 0) {
@@ -318,28 +355,27 @@
         }
         if (receivers.size() > 0) {
             pw.print(prefix); pw.println("Receivers:");
-            for (ReceiverList rl : receivers) {
-                pw.print(prefix); pw.print("  - "); pw.println(rl);
+            for (int i=0; i<receivers.size(); i++) {
+                pw.print(prefix); pw.print("  - "); pw.println(receivers.valueAt(i));
             }
         }
     }
     
-    ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread,
-            ApplicationInfo _info, String _processName, int _uid) {
+    ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, ApplicationInfo _info,
+            String _processName, int _uid) {
         batteryStats = _batteryStats;
         info = _info;
         isolated = _info.uid != _uid;
         uid = _uid;
         userId = UserHandle.getUserId(_uid);
         processName = _processName;
-        pkgList.add(_info.packageName);
-        thread = _thread;
-        maxAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
-        hiddenAdj = clientHiddenAdj = emptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
+        pkgList.put(_info.packageName, null);
+        maxAdj = ProcessList.UNKNOWN_ADJ;
         curRawAdj = setRawAdj = -100;
         curAdj = setAdj = -100;
         persistent = false;
         removed = false;
+        lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
     }
 
     public void setPid(int _pid) {
@@ -347,7 +383,53 @@
         shortStringName = null;
         stringName = null;
     }
-    
+
+    public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
+        if (thread == null) {
+            final ProcessStats.ProcessState origBase = baseProcessTracker;
+            if (origBase != null) {
+                origBase.setState(ProcessStats.STATE_NOTHING,
+                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+                origBase.makeInactive();
+            }
+            baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
+                    processName);
+            baseProcessTracker.makeActive();
+            for (int i=0; i<pkgList.size(); i++) {
+                ProcessStats.ProcessState ps = pkgList.valueAt(i);
+                if (ps != null && ps != origBase) {
+                    ps.makeInactive();
+                }
+                ps = tracker.getProcessStateLocked(pkgList.keyAt(i), info.uid, processName);
+                if (ps != baseProcessTracker) {
+                    ps.makeActive();
+                }
+                pkgList.setValueAt(i, ps);
+            }
+        }
+        thread = _thread;
+    }
+
+    public void makeInactive(ProcessStatsService tracker) {
+        thread = null;
+        final ProcessStats.ProcessState origBase = baseProcessTracker;
+        if (origBase != null) {
+            if (origBase != null) {
+                origBase.setState(ProcessStats.STATE_NOTHING,
+                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+                origBase.makeInactive();
+            }
+            baseProcessTracker = null;
+            for (int i=0; i<pkgList.size(); i++) {
+                ProcessStats.ProcessState ps = pkgList.valueAt(i);
+                if (ps != null && ps != origBase) {
+                    ps.makeInactive();
+                }
+                pkgList.setValueAt(i, null);
+            }
+        }
+    }
+
     /**
      * This method returns true if any of the activities within the process record are interesting
      * to the user. See HistoryRecord.isInterestingToUserLocked()
@@ -380,16 +462,37 @@
 
     void updateHasAboveClientLocked() {
         hasAboveClient = false;
-        if (connections.size() > 0) {
-            for (ConnectionRecord cr : connections) {
-                if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
-                    hasAboveClient = true;
-                    break;
-                }
+        for (int i=connections.size()-1; i>=0; i--) {
+            ConnectionRecord cr = connections.valueAt(i);
+            if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+                hasAboveClient = true;
+                break;
             }
         }
     }
 
+    int modifyRawOomAdj(int adj) {
+        if (hasAboveClient) {
+            // If this process has bound to any services with BIND_ABOVE_CLIENT,
+            // then we need to drop its adjustment to be lower than the service's
+            // in order to honor the request.  We want to drop it by one adjustment
+            // level...  but there is special meaning applied to various levels so
+            // we will skip some of them.
+            if (adj < ProcessList.FOREGROUND_APP_ADJ) {
+                // System process will not get dropped, ever
+            } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
+                adj = ProcessList.VISIBLE_APP_ADJ;
+            } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+            } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
+                adj = ProcessList.CACHED_APP_MIN_ADJ;
+            } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
+                adj++;
+            }
+        }
+        return adj;
+    }
+
     public String toShortString() {
         if (shortStringName != null) {
             return shortStringName;
@@ -409,8 +512,14 @@
         } else {
             sb.append('u');
             sb.append(userId);
-            sb.append('a');
-            sb.append(UserHandle.getAppId(info.uid));
+            int appId = UserHandle.getAppId(info.uid);
+            if (appId >= Process.FIRST_APPLICATION_UID) {
+                sb.append('a');
+                sb.append(appId - Process.FIRST_APPLICATION_UID);
+            } else {
+                sb.append('s');
+                sb.append(appId);
+            }
             if (uid != info.uid) {
                 sb.append('i');
                 sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID);
@@ -430,24 +539,97 @@
         sb.append('}');
         return stringName = sb.toString();
     }
-    
+
+    public String makeAdjReason() {
+        if (adjSource != null || adjTarget != null) {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append(' ');
+            if (adjTarget instanceof ComponentName) {
+                sb.append(((ComponentName)adjTarget).flattenToShortString());
+            } else if (adjTarget != null) {
+                sb.append(adjTarget.toString());
+            } else {
+                sb.append("{null}");
+            }
+            sb.append("<=");
+            if (adjSource instanceof ProcessRecord) {
+                sb.append("Proc{");
+                sb.append(((ProcessRecord)adjSource).toShortString());
+                sb.append("}");
+            } else if (adjSource != null) {
+                sb.append(adjSource.toString());
+            } else {
+                sb.append("{null}");
+            }
+            return sb.toString();
+        }
+        return null;
+    }
+
     /*
      *  Return true if package has been added false if not
      */
-    public boolean addPackage(String pkg) {
-        if (!pkgList.contains(pkg)) {
-            pkgList.add(pkg);
+    public boolean addPackage(String pkg, ProcessStatsService tracker) {
+        if (!pkgList.containsKey(pkg)) {
+            if (baseProcessTracker != null) {
+                ProcessStats.ProcessState state = tracker.getProcessStateLocked(
+                        pkg, info.uid, processName);
+                pkgList.put(pkg, state);
+                if (state != baseProcessTracker) {
+                    state.makeActive();
+                }
+            } else {
+                pkgList.put(pkg, null);
+            }
             return true;
         }
         return false;
     }
-    
+
+    public int getSetAdjWithServices() {
+        if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+            if (hasStartedServices) {
+                return ProcessList.SERVICE_B_ADJ;
+            }
+        }
+        return setAdj;
+    }
+
+    public void forceProcessStateUpTo(int newState) {
+        if (repProcState > newState) {
+            curProcState = repProcState = newState;
+        }
+    }
+
     /*
      *  Delete all packages from list except the package indicated in info
      */
-    public void resetPackageList() {
-        pkgList.clear();
-        pkgList.add(info.packageName);
+    public void resetPackageList(ProcessStatsService tracker) {
+        final int N = pkgList.size();
+        if (baseProcessTracker != null) {
+            long now = SystemClock.uptimeMillis();
+            baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+                    tracker.getMemFactorLocked(), now, pkgList);
+            if (N != 1) {
+                for (int i=0; i<N; i++) {
+                    ProcessStats.ProcessState ps = pkgList.valueAt(i);
+                    if (ps != null && ps != baseProcessTracker) {
+                        ps.makeInactive();
+                    }
+
+                }
+                pkgList.clear();
+                ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+                        info.packageName, info.uid, processName);
+                pkgList.put(info.packageName, ps);
+                if (ps != baseProcessTracker) {
+                    ps.makeActive();
+                }
+            }
+        } else if (N != 1) {
+            pkgList.clear();
+            pkgList.put(info.packageName, null);
+        }
     }
     
     public String[] getPackageList() {
@@ -456,7 +638,9 @@
             return null;
         }
         String list[] = new String[size];
-        pkgList.toArray(list);
+        for (int i=0; i<pkgList.size(); i++) {
+            list[i] = pkgList.keyAt(i);
+        }
         return list;
     }
 }
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
new file mode 100644
index 0000000..7dc006c
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -0,0 +1,877 @@
+/*
+ * 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.am;
+
+import android.app.AppGlobals;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import com.android.internal.app.IProcessStats;
+import com.android.internal.app.ProcessStats;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+
+public final class ProcessStatsService extends IProcessStats.Stub {
+    static final String TAG = "ProcessStatsService";
+    static final boolean DEBUG = false;
+
+    // Most data is kept in a sparse data structure: an integer array which integer
+    // holds the type of the entry, and the identifier for a long array that data
+    // exists in and the offset into the array to find it.  The constants below
+    // define the encoding of that data in an integer.
+
+    static final int MAX_HISTORIC_STATES = 8;   // Maximum number of historic states we will keep.
+    static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
+    static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
+    static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
+    static long WRITE_PERIOD = 30*60*1000;      // Write file every 30 minutes or so.
+
+    final ActivityManagerService mAm;
+    final File mBaseDir;
+    ProcessStats mProcessStats;
+    AtomicFile mFile;
+    boolean mCommitPending;
+    boolean mShuttingDown;
+    int mLastMemOnlyState = -1;
+    boolean mMemFactorLowered;
+
+    final ReentrantLock mWriteLock = new ReentrantLock();
+    final Object mPendingWriteLock = new Object();
+    AtomicFile mPendingWriteFile;
+    Parcel mPendingWrite;
+    boolean mPendingWriteCommitted;
+    long mLastWriteTime;
+
+    public ProcessStatsService(ActivityManagerService am, File file) {
+        mAm = am;
+        mBaseDir = file;
+        mBaseDir.mkdirs();
+        mProcessStats = new ProcessStats(true);
+        updateFile();
+        SystemProperties.addChangeCallback(new Runnable() {
+            @Override public void run() {
+                synchronized (mAm) {
+                    if (mProcessStats.evaluateSystemProperties(false)) {
+                        mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
+                        writeStateLocked(true, true);
+                        mProcessStats.evaluateSystemProperties(true);
+                    }
+                }
+            }
+        });
+    }
+
+    public ProcessStats.ProcessState getProcessStateLocked(String packageName,
+            int uid, String processName) {
+        return mProcessStats.getProcessStateLocked(packageName, uid, processName);
+    }
+
+    public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
+            String processName, String className) {
+        return mProcessStats.getServiceStateLocked(packageName, uid, processName, className);
+    }
+
+    public boolean isMemFactorLowered() {
+        return mMemFactorLowered;
+    }
+
+    public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
+        mMemFactorLowered = memFactor < mLastMemOnlyState;
+        mLastMemOnlyState = memFactor;
+        if (screenOn) {
+            memFactor += ProcessStats.ADJ_SCREEN_ON;
+        }
+        if (memFactor != mProcessStats.mMemFactor) {
+            if (mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING) {
+                mProcessStats.mMemFactorDurations[mProcessStats.mMemFactor]
+                        += now - mProcessStats.mStartTime;
+            }
+            mProcessStats.mMemFactor = memFactor;
+            mProcessStats.mStartTime = now;
+            ArrayMap<String, SparseArray<ProcessStats.PackageState>> pmap
+                    = mProcessStats.mPackages.getMap();
+            for (int i=0; i<pmap.size(); i++) {
+                SparseArray<ProcessStats.PackageState> uids = pmap.valueAt(i);
+                for (int j=0; j<uids.size(); j++) {
+                    ProcessStats.PackageState pkg = uids.valueAt(j);
+                    ArrayMap<String, ProcessStats.ServiceState> services = pkg.mServices;
+                    for (int k=0; k<services.size(); k++) {
+                        ProcessStats.ServiceState service = services.valueAt(k);
+                        if (service.isInUse()) {
+                            if (service.mStartedState != ProcessStats.STATE_NOTHING) {
+                                service.setStarted(true, memFactor, now);
+                            }
+                            if (service.mBoundState != ProcessStats.STATE_NOTHING) {
+                                service.setBound(true, memFactor, now);
+                            }
+                            if (service.mExecState != ProcessStats.STATE_NOTHING) {
+                                service.setExecuting(true, memFactor, now);
+                            }
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public int getMemFactorLocked() {
+        return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
+    }
+
+    public boolean shouldWriteNowLocked(long now) {
+        if (now > (mLastWriteTime+WRITE_PERIOD)) {
+            if (SystemClock.elapsedRealtime()
+                    > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD)) {
+                mCommitPending = true;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public void shutdownLocked() {
+        Slog.w(TAG, "Writing process stats before shutdown...");
+        mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
+        writeStateSyncLocked();
+        mShuttingDown = true;
+    }
+
+    public void writeStateAsyncLocked() {
+        writeStateLocked(false);
+    }
+
+    public void writeStateSyncLocked() {
+        writeStateLocked(true);
+    }
+
+    private void writeStateLocked(boolean sync) {
+        if (mShuttingDown) {
+            return;
+        }
+        boolean commitPending = mCommitPending;
+        mCommitPending = false;
+        writeStateLocked(sync, commitPending);
+    }
+
+    public void writeStateLocked(boolean sync, final boolean commit) {
+        synchronized (mPendingWriteLock) {
+            long now = SystemClock.uptimeMillis();
+            if (mPendingWrite == null || !mPendingWriteCommitted) {
+                mPendingWrite = Parcel.obtain();
+                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                if (commit) {
+                    mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+                }
+                mProcessStats.writeToParcel(mPendingWrite, 0);
+                mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
+                mPendingWriteCommitted = commit;
+            }
+            if (commit) {
+                mProcessStats.resetSafely();
+                updateFile();
+            }
+            mLastWriteTime = SystemClock.uptimeMillis();
+            Slog.i(TAG, "Prepared write state in " + (SystemClock.uptimeMillis()-now) + "ms");
+            if (!sync) {
+                BackgroundThread.getHandler().post(new Runnable() {
+                    @Override public void run() {
+                        performWriteState();
+                    }
+                });
+                return;
+            }
+        }
+
+        performWriteState();
+    }
+
+    private void updateFile() {
+        mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
+                + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
+        mLastWriteTime = SystemClock.uptimeMillis();
+    }
+
+    void performWriteState() {
+        if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
+        Parcel data;
+        AtomicFile file;
+        synchronized (mPendingWriteLock) {
+            data = mPendingWrite;
+            file = mPendingWriteFile;
+            mPendingWriteCommitted = false;
+            if (data == null) {
+                return;
+            }
+            mPendingWrite = null;
+            mPendingWriteFile = null;
+            mWriteLock.lock();
+        }
+
+        FileOutputStream stream = null;
+        try {
+            stream = file.startWrite();
+            stream.write(data.marshall());
+            stream.flush();
+            file.finishWrite(stream);
+            if (DEBUG) Slog.d(TAG, "Write completed successfully!");
+        } catch (IOException e) {
+            Slog.w(TAG, "Error writing process statistics", e);
+            file.failWrite(stream);
+        } finally {
+            data.recycle();
+            trimHistoricStatesWriteLocked();
+            mWriteLock.unlock();
+        }
+    }
+
+    boolean readLocked(ProcessStats stats, AtomicFile file) {
+        try {
+            FileInputStream stream = file.openRead();
+            stats.read(stream);
+            stream.close();
+            if (stats.mReadError != null) {
+                Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError);
+                if (DEBUG) {
+                    ArrayMap<String, SparseArray<ProcessStats.ProcessState>> procMap
+                            = stats.mProcesses.getMap();
+                    final int NPROC = procMap.size();
+                    for (int ip=0; ip<NPROC; ip++) {
+                        Slog.w(TAG, "Process: " + procMap.keyAt(ip));
+                        SparseArray<ProcessStats.ProcessState> uids = procMap.valueAt(ip);
+                        final int NUID = uids.size();
+                        for (int iu=0; iu<NUID; iu++) {
+                            Slog.w(TAG, "  Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
+                        }
+                    }
+                    ArrayMap<String, SparseArray<ProcessStats.PackageState>> pkgMap
+                            = stats.mPackages.getMap();
+                    final int NPKG = pkgMap.size();
+                    for (int ip=0; ip<NPKG; ip++) {
+                        Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
+                        SparseArray<ProcessStats.PackageState> uids = pkgMap.valueAt(ip);
+                        final int NUID = uids.size();
+                        for (int iu=0; iu<NUID; iu++) {
+                            Slog.w(TAG, "  Uid: " + uids.keyAt(iu));
+                            ProcessStats.PackageState pkgState = uids.valueAt(iu);
+                            final int NPROCS = pkgState.mProcesses.size();
+                            for (int iproc=0; iproc<NPROCS; iproc++) {
+                                Slog.w(TAG, "    Process " + pkgState.mProcesses.keyAt(iproc)
+                                        + ": " + pkgState.mProcesses.valueAt(iproc));
+                            }
+                            final int NSRVS = pkgState.mServices.size();
+                            for (int isvc=0; isvc<NSRVS; isvc++) {
+                                Slog.w(TAG, "    Service " + pkgState.mServices.keyAt(isvc)
+                                        + ": " + pkgState.mServices.valueAt(isvc));
+                            }
+                        }
+                    }
+                }
+                return false;
+            }
+        } catch (Throwable e) {
+            stats.mReadError = "caught exception: " + e;
+            Slog.e(TAG, "Error reading process statistics", e);
+            return false;
+        }
+        return true;
+    }
+
+    private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
+            boolean inclCheckedIn) {
+        File[] files = mBaseDir.listFiles();
+        if (files == null || files.length <= minNum) {
+            return null;
+        }
+        ArrayList<String> filesArray = new ArrayList<String>(files.length);
+        String currentFile = mFile.getBaseFile().getPath();
+        if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
+        for (int i=0; i<files.length; i++) {
+            File file = files[i];
+            String fileStr = file.getPath();
+            if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
+            if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
+                if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
+                continue;
+            }
+            if (!inclCurrent && fileStr.equals(currentFile)) {
+                if (DEBUG) Slog.d(TAG, "Skipping: current stats");
+                continue;
+            }
+            filesArray.add(fileStr);
+        }
+        Collections.sort(filesArray);
+        return filesArray;
+    }
+
+    public void trimHistoricStatesWriteLocked() {
+        ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
+        if (filesArray == null) {
+            return;
+        }
+        while (filesArray.size() > MAX_HISTORIC_STATES) {
+            String file = filesArray.remove(0);
+            Slog.i(TAG, "Pruning old procstats: " + file);
+            (new File(file)).delete();
+        }
+    }
+
+    boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
+            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
+            boolean sepProcStates, int[] procStates, long now, String reqPackage) {
+        ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
+                screenStates, memStates, procStates, procStates, now, reqPackage, false);
+        if (procs.size() > 0) {
+            if (header != null) {
+                pw.println(header);
+            }
+            ProcessStats.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
+                    sepMemStates, memStates, sepProcStates, procStates, now);
+            return true;
+        }
+        return false;
+    }
+
+    static int[] parseStateList(String[] states, int mult, String arg, boolean[] outSep,
+            String[] outError) {
+        ArrayList<Integer> res = new ArrayList<Integer>();
+        int lastPos = 0;
+        for (int i=0; i<=arg.length(); i++) {
+            char c = i < arg.length() ? arg.charAt(i) : 0;
+            if (c != ',' && c != '+' && c != ' ' && c != 0) {
+                continue;
+            }
+            boolean isSep = c == ',';
+            if (lastPos == 0) {
+                // We now know the type of op.
+                outSep[0] = isSep;
+            } else if (c != 0 && outSep[0] != isSep) {
+                outError[0] = "inconsistent separators (can't mix ',' with '+')";
+                return null;
+            }
+            if (lastPos < (i-1)) {
+                String str = arg.substring(lastPos, i);
+                for (int j=0; j<states.length; j++) {
+                    if (str.equals(states[j])) {
+                        res.add(j);
+                        str = null;
+                        break;
+                    }
+                }
+                if (str != null) {
+                    outError[0] = "invalid word \"" + str + "\"";
+                    return null;
+                }
+            }
+            lastPos = i + 1;
+        }
+
+        int[] finalRes = new int[res.size()];
+        for (int i=0; i<res.size(); i++) {
+            finalRes[i] = res.get(i) * mult;
+        }
+        return finalRes;
+    }
+
+    public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+        Parcel current = Parcel.obtain();
+        mWriteLock.lock();
+        try {
+            synchronized (mAm) {
+                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                mProcessStats.writeToParcel(current, 0);
+            }
+            if (historic != null) {
+                ArrayList<String> files = getCommittedFiles(0, false, true);
+                if (files != null) {
+                    for (int i=files.size()-1; i>=0; i--) {
+                        try {
+                            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                                    new File(files.get(i)), ParcelFileDescriptor.MODE_READ_ONLY);
+                            historic.add(pfd);
+                        } catch (IOException e) {
+                            Slog.w(TAG, "Failure opening procstat file " + files.get(i), e);
+                        }
+                    }
+                }
+            }
+        } finally {
+            mWriteLock.unlock();
+        }
+        return current.marshall();
+    }
+
+    public ParcelFileDescriptor getStatsOverTime(long minTime) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+        mWriteLock.lock();
+        try {
+            Parcel current = Parcel.obtain();
+            long curTime;
+            synchronized (mAm) {
+                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                mProcessStats.writeToParcel(current, 0);
+                curTime = mProcessStats.mTimePeriodEndRealtime
+                        - mProcessStats.mTimePeriodStartRealtime;
+            }
+            if (curTime < minTime) {
+                // Need to add in older stats to reach desired time.
+                ArrayList<String> files = getCommittedFiles(0, false, true);
+                if (files != null && files.size() > 0) {
+                    current.setDataPosition(0);
+                    ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
+                    current.recycle();
+                    int i = 0;
+                    while (i < files.size() && (stats.mTimePeriodEndRealtime
+                            - stats.mTimePeriodStartRealtime) < minTime) {
+                        AtomicFile file = new AtomicFile(new File(files.get(i)));
+                        i++;
+                        ProcessStats moreStats = new ProcessStats(false);
+                        readLocked(moreStats, file);
+                        if (moreStats.mReadError == null) {
+                            stats.add(moreStats);
+                            StringBuilder sb = new StringBuilder();
+                            sb.append("Added stats: ");
+                            sb.append(moreStats.mTimePeriodStartClockStr);
+                            sb.append(", over ");
+                            TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
+                                    - moreStats.mTimePeriodStartRealtime, sb);
+                            Slog.i(TAG, sb.toString());
+                        } else {
+                            Slog.w(TAG, "Failure reading " + files.get(i) + "; "
+                                    + moreStats.mReadError);
+                            continue;
+                        }
+                    }
+                    current = Parcel.obtain();
+                    stats.writeToParcel(current, 0);
+                }
+            }
+            final byte[] outData = current.marshall();
+            current.recycle();
+            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+            Thread thr = new Thread("ProcessStats pipe output") {
+                public void run() {
+                    FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+                    try {
+                        fout.write(outData);
+                        fout.close();
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Failure writing pipe", e);
+                    }
+                }
+            };
+            thr.start();
+            return fds[0];
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed building output pipe", e);
+        } finally {
+            mWriteLock.unlock();
+        }
+        return null;
+    }
+
+    public int getCurrentMemoryState() {
+        synchronized (mAm) {
+            return mLastMemOnlyState;
+        }
+    }
+
+    static private void dumpHelp(PrintWriter pw) {
+        pw.println("Process stats (procstats) dump options:");
+        pw.println("    [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
+        pw.println("    [--details] [--full-details] [--current] [--hours] [--active]");
+        pw.println("    [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
+        pw.println("  --checkin: perform a checkin: print and delete old committed states.");
+        pw.println("  --c: print only state in checkin format.");
+        pw.println("  --csv: output data suitable for putting in a spreadsheet.");
+        pw.println("  --csv-screen: on, off.");
+        pw.println("  --csv-mem: norm, mod, low, crit.");
+        pw.println("  --csv-proc: pers, top, fore, vis, precept, backup,");
+        pw.println("    service, home, prev, cached");
+        pw.println("  --details: dump per-package details, not just summary.");
+        pw.println("  --full-details: dump all timing and active state details.");
+        pw.println("  --current: only dump current state.");
+        pw.println("  --hours: aggregate over about N last hours.");
+        pw.println("  --active: only show currently active processes/services.");
+        pw.println("  --commit: commit current stats to disk and reset to start new stats.");
+        pw.println("  --reset: reset current stats, without committing.");
+        pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");
+        pw.println("  --write: write current in-memory stats to disk.");
+        pw.println("  --read: replace current stats with last-written stats.");
+        pw.println("  -a: print everything.");
+        pw.println("  -h: print this help text.");
+        pw.println("  <package.name>: optional name of package to filter output by.");
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mAm.checkCallingPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump procstats from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " without permission " + android.Manifest.permission.DUMP);
+            return;
+        }
+
+        final long now = SystemClock.uptimeMillis();
+
+        boolean isCheckin = false;
+        boolean isCompact = false;
+        boolean isCsv = false;
+        boolean currentOnly = false;
+        boolean dumpDetails = false;
+        boolean dumpFullDetails = false;
+        boolean dumpAll = false;
+        int aggregateHours = 0;
+        boolean activeOnly = false;
+        String reqPackage = null;
+        boolean csvSepScreenStats = false;
+        int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
+        boolean csvSepMemStats = false;
+        int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
+        boolean csvSepProcStats = true;
+        int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
+        if (args != null) {
+            for (int i=0; i<args.length; i++) {
+                String arg = args[i];
+                if ("--checkin".equals(arg)) {
+                    isCheckin = true;
+                } else if ("-c".equals(arg)) {
+                    isCompact = true;
+                } else if ("--csv".equals(arg)) {
+                    isCsv = true;
+                } else if ("--csv-screen".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --csv-screen");
+                        dumpHelp(pw);
+                        return;
+                    }
+                    boolean[] sep = new boolean[1];
+                    String[] error = new String[1];
+                    csvScreenStats = parseStateList(ProcessStats.ADJ_SCREEN_NAMES_CSV, ProcessStats.ADJ_SCREEN_MOD,
+                            args[i], sep, error);
+                    if (csvScreenStats == null) {
+                        pw.println("Error in \"" + args[i] + "\": " + error[0]);
+                        dumpHelp(pw);
+                        return;
+                    }
+                    csvSepScreenStats = sep[0];
+                } else if ("--csv-mem".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --csv-mem");
+                        dumpHelp(pw);
+                        return;
+                    }
+                    boolean[] sep = new boolean[1];
+                    String[] error = new String[1];
+                    csvMemStats = parseStateList(ProcessStats.ADJ_MEM_NAMES_CSV, 1, args[i], sep, error);
+                    if (csvMemStats == null) {
+                        pw.println("Error in \"" + args[i] + "\": " + error[0]);
+                        dumpHelp(pw);
+                        return;
+                    }
+                    csvSepMemStats = sep[0];
+                } else if ("--csv-proc".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --csv-proc");
+                        dumpHelp(pw);
+                        return;
+                    }
+                    boolean[] sep = new boolean[1];
+                    String[] error = new String[1];
+                    csvProcStats = parseStateList(ProcessStats.STATE_NAMES_CSV, 1, args[i], sep, error);
+                    if (csvProcStats == null) {
+                        pw.println("Error in \"" + args[i] + "\": " + error[0]);
+                        dumpHelp(pw);
+                        return;
+                    }
+                    csvSepProcStats = sep[0];
+                } else if ("--details".equals(arg)) {
+                    dumpDetails = true;
+                } else if ("--full-details".equals(arg)) {
+                    dumpFullDetails = true;
+                } else if ("--hours".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --hours");
+                        dumpHelp(pw);
+                        return;
+                    }
+                    try {
+                        aggregateHours = Integer.parseInt(args[i]);
+                    } catch (NumberFormatException e) {
+                        pw.println("Error: --hours argument not an int -- " + args[i]);
+                        dumpHelp(pw);
+                        return;
+                    }
+                } else if ("--active".equals(arg)) {
+                    activeOnly = true;
+                    currentOnly = true;
+                } else if ("--current".equals(arg)) {
+                    currentOnly = true;
+                } else if ("--commit".equals(arg)) {
+                    synchronized (mAm) {
+                        mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+                        writeStateLocked(true, true);
+                        pw.println("Process stats committed.");
+                    }
+                    return;
+                } else if ("--reset".equals(arg)) {
+                    synchronized (mAm) {
+                        mProcessStats.resetSafely();
+                        pw.println("Process stats reset.");
+                    }
+                    return;
+                } else if ("--clear".equals(arg)) {
+                    synchronized (mAm) {
+                        mProcessStats.resetSafely();
+                        ArrayList<String> files = getCommittedFiles(0, true, true);
+                        if (files != null) {
+                            for (int fi=0; fi<files.size(); fi++) {
+                                (new File(files.get(fi))).delete();
+                            }
+                        }
+                        pw.println("All process stats cleared.");
+                    }
+                    return;
+                } else if ("--write".equals(arg)) {
+                    synchronized (mAm) {
+                        writeStateSyncLocked();
+                        pw.println("Process stats written.");
+                    }
+                    return;
+                } else if ("--read".equals(arg)) {
+                    synchronized (mAm) {
+                        readLocked(mProcessStats, mFile);
+                        pw.println("Process stats read.");
+                    }
+                    return;
+                } else if ("-h".equals(arg)) {
+                    dumpHelp(pw);
+                    return;
+                } else if ("-a".equals(arg)) {
+                    dumpDetails = true;
+                    dumpAll = true;
+                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
+                    pw.println("Unknown option: " + arg);
+                    dumpHelp(pw);
+                    return;
+                } else {
+                    // Not an option, last argument must be a package name.
+                    try {
+                        IPackageManager pm = AppGlobals.getPackageManager();
+                        if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
+                            reqPackage = arg;
+                            // Include all details, since we know we are only going to
+                            // be dumping a smaller set of data.  In fact only the details
+                            // container per-package data, so that are needed to be able
+                            // to dump anything at all when filtering by package.
+                            dumpDetails = true;
+                        }
+                    } catch (RemoteException e) {
+                    }
+                    if (reqPackage == null) {
+                        pw.println("Unknown package: " + arg);
+                        dumpHelp(pw);
+                        return;
+                    }
+                }
+            }
+        }
+
+        if (isCsv) {
+            pw.print("Processes running summed over");
+            if (!csvSepScreenStats) {
+                for (int i=0; i<csvScreenStats.length; i++) {
+                    pw.print(" ");
+                    ProcessStats.printScreenLabelCsv(pw, csvScreenStats[i]);
+                }
+            }
+            if (!csvSepMemStats) {
+                for (int i=0; i<csvMemStats.length; i++) {
+                    pw.print(" ");
+                    ProcessStats.printMemLabelCsv(pw, csvMemStats[i]);
+                }
+            }
+            if (!csvSepProcStats) {
+                for (int i=0; i<csvProcStats.length; i++) {
+                    pw.print(" ");
+                    pw.print(ProcessStats.STATE_NAMES_CSV[csvProcStats[i]]);
+                }
+            }
+            pw.println();
+            synchronized (mAm) {
+                dumpFilteredProcessesCsvLocked(pw, null,
+                        csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
+                        csvSepProcStats, csvProcStats, now, reqPackage);
+                /*
+                dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:",
+                        false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
+                        true, new int[] {ADJ_MEM_FACTOR_CRITICAL},
+                        true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
+                                STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
+                                STATE_PREVIOUS, STATE_CACHED},
+                        now, reqPackage);
+                dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:",
+                        false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
+                        false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW,
+                                ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE},
+                        true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
+                                STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
+                                STATE_PREVIOUS, STATE_CACHED},
+                        now, reqPackage);
+                */
+            }
+            return;
+        } else if (aggregateHours != 0) {
+            ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
+                    - (ProcessStats.COMMIT_PERIOD/2));
+            if (pfd == null) {
+                pw.println("Unable to build stats!");
+                return;
+            }
+            ProcessStats stats = new ProcessStats(false);
+            InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            stats.read(stream);
+            if (stats.mReadError != null) {
+                pw.print("Failure reading: "); pw.println(stats.mReadError);
+                return;
+            }
+            if (isCompact) {
+                stats.dumpCheckinLocked(pw, reqPackage);
+            } else {
+                if (dumpDetails || dumpFullDetails) {
+                    stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll, activeOnly);
+                } else {
+                    stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+                }
+            }
+            return;
+        }
+
+        boolean sepNeeded = false;
+        if (!currentOnly || isCheckin) {
+            mWriteLock.lock();
+            try {
+                ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
+                if (files != null) {
+                    for (int i=0; i<files.size(); i++) {
+                        if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
+                        try {
+                            AtomicFile file = new AtomicFile(new File(files.get(i)));
+                            ProcessStats processStats = new ProcessStats(false);
+                            readLocked(processStats, file);
+                            if (processStats.mReadError != null) {
+                                if (isCheckin || isCompact) pw.print("err,");
+                                pw.print("Failure reading "); pw.print(files.get(i));
+                                pw.print("; "); pw.println(processStats.mReadError);
+                                if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
+                                (new File(files.get(i))).delete();
+                                continue;
+                            }
+                            String fileStr = file.getBaseFile().getPath();
+                            boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
+                            if (isCheckin || isCompact) {
+                                // Don't really need to lock because we uniquely own this object.
+                                processStats.dumpCheckinLocked(pw, reqPackage);
+                            } else {
+                                if (sepNeeded) {
+                                    pw.println();
+                                } else {
+                                    sepNeeded = true;
+                                }
+                                pw.print("COMMITTED STATS FROM ");
+                                pw.print(processStats.mTimePeriodStartClockStr);
+                                if (checkedIn) pw.print(" (checked in)");
+                                pw.println(":");
+                                // Don't really need to lock because we uniquely own this object.
+                                // Always dump summary here, dumping all details is just too
+                                // much crud.
+                                if (dumpFullDetails) {
+                                    mProcessStats.dumpLocked(pw, reqPackage, now, false, false,
+                                            activeOnly);
+                                } else {
+                                    processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+                                }
+                            }
+                            if (isCheckin) {
+                                // Rename file suffix to mark that it has checked in.
+                                file.getBaseFile().renameTo(new File(
+                                        fileStr + STATE_FILE_CHECKIN_SUFFIX));
+                            }
+                        } catch (Throwable e) {
+                            pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
+                            e.printStackTrace(pw);
+                        }
+                    }
+                }
+            } finally {
+                mWriteLock.unlock();
+            }
+        }
+        if (!isCheckin) {
+            synchronized (mAm) {
+                if (isCompact) {
+                    mProcessStats.dumpCheckinLocked(pw, reqPackage);
+                } else {
+                    if (sepNeeded) {
+                        pw.println();
+                        pw.println("CURRENT STATS:");
+                    }
+                    if (dumpDetails || dumpFullDetails) {
+                        mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
+                                activeOnly);
+                        if (dumpAll) {
+                            pw.print("  mFile="); pw.println(mFile.getBaseFile());
+                        }
+                    } else {
+                        mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 9dbf5f5..7da8c48 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -22,6 +22,7 @@
 import android.os.UserHandle;
 import android.util.Slog;
 import android.util.SparseArray;
+import com.android.internal.os.TransferPipe;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -35,7 +36,7 @@
  * Keeps track of content providers by authority (name) and class. It separates the mapping by
  * user and ones that are not user-specific (system providers).
  */
-public class ProviderMap {
+public final class ProviderMap {
 
     private static final String TAG = "ProviderMap";
 
@@ -230,58 +231,87 @@
         return didSomething;
     }
 
-    private void dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll,
-            HashMap<ComponentName, ContentProviderRecord> map) {
+    private boolean dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll, String dumpPackage,
+            String header, boolean needSep, HashMap<ComponentName, ContentProviderRecord> map) {
         Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it = map.entrySet().iterator();
+        boolean written = false;
         while (it.hasNext()) {
             Map.Entry<ComponentName, ContentProviderRecord> e = it.next();
             ContentProviderRecord r = e.getValue();
+            if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+                continue;
+            }
+            if (needSep) {
+                pw.println("");
+                needSep = false;
+            }
+            if (header != null) {
+                pw.println(header);
+                header = null;
+            }
+            written = true;
             pw.print("  * ");
             pw.println(r);
             r.dump(pw, "    ", dumpAll);
         }
+        return written;
     }
 
-    private void dumpProvidersByNameLocked(PrintWriter pw,
-            HashMap<String, ContentProviderRecord> map) {
+    private boolean dumpProvidersByNameLocked(PrintWriter pw, String dumpPackage,
+            String header, boolean needSep, HashMap<String, ContentProviderRecord> map) {
         Iterator<Map.Entry<String, ContentProviderRecord>> it = map.entrySet().iterator();
+        boolean written = false;
         while (it.hasNext()) {
             Map.Entry<String, ContentProviderRecord> e = it.next();
             ContentProviderRecord r = e.getValue();
+            if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+                continue;
+            }
+            if (needSep) {
+                pw.println("");
+                needSep = false;
+            }
+            if (header != null) {
+                pw.println(header);
+                header = null;
+            }
+            written = true;
             pw.print("  ");
             pw.print(e.getKey());
             pw.print(": ");
             pw.println(r.toShortString());
         }
+        return written;
     }
 
-    void dumpProvidersLocked(PrintWriter pw, boolean dumpAll) {
+    boolean dumpProvidersLocked(PrintWriter pw, boolean dumpAll, String dumpPackage) {
+        boolean needSep = false;
+
         if (mSingletonByClass.size() > 0) {
-            pw.println("  Published single-user content providers (by class):");
-            dumpProvidersByClassLocked(pw, dumpAll, mSingletonByClass);
+            needSep |= dumpProvidersByClassLocked(pw, dumpAll, dumpPackage,
+                    "  Published single-user content providers (by class):", needSep,
+                    mSingletonByClass);
         }
 
-        pw.println("");
         for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
             HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
-            pw.println("");
-            pw.println("  Published user " + mProvidersByClassPerUser.keyAt(i)
-                    + " content providers (by class):");
-            dumpProvidersByClassLocked(pw, dumpAll, map);
+            needSep |= dumpProvidersByClassLocked(pw, dumpAll, dumpPackage,
+                    "  Published user " + mProvidersByClassPerUser.keyAt(i)
+                            + " content providers (by class):", needSep, map);
         }
 
         if (dumpAll) {
-            pw.println("");
-            pw.println("  Single-user authority to provider mappings:");
-            dumpProvidersByNameLocked(pw, mSingletonByName);
+            needSep |= dumpProvidersByNameLocked(pw, dumpPackage,
+                    "  Single-user authority to provider mappings:", needSep, mSingletonByName);
 
             for (int i = 0; i < mProvidersByNamePerUser.size(); i++) {
-                pw.println("");
-                pw.println("  User " + mProvidersByNamePerUser.keyAt(i)
-                        + " authority to provider mappings:");
-                dumpProvidersByNameLocked(pw, mProvidersByNamePerUser.valueAt(i));
+                needSep |= dumpProvidersByNameLocked(pw, dumpPackage,
+                        "  User " + mProvidersByNamePerUser.keyAt(i)
+                                + " authority to provider mappings:", needSep,
+                        mProvidersByNamePerUser.valueAt(i));
             }
         }
+        return needSep;
     }
 
     protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java
index 9b6701e..fa8c1df 100644
--- a/services/java/com/android/server/am/ReceiverList.java
+++ b/services/java/com/android/server/am/ReceiverList.java
@@ -32,7 +32,7 @@
  * A receiver object that has registered for one or more broadcasts.
  * The ArrayList holds BroadcastFilter objects.
  */
-class ReceiverList extends ArrayList<BroadcastFilter>
+final class ReceiverList extends ArrayList<BroadcastFilter>
         implements IBinder.DeathRecipient {
     final ActivityManagerService owner;
     public final IIntentReceiver receiver;
@@ -69,7 +69,7 @@
     }
     
     void dumpLocal(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("app="); pw.print(app.toShortString());
+        pw.print(prefix); pw.print("app="); pw.print(app != null ? app.toShortString() : null);
             pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid);
             pw.print(" user="); pw.println(userId);
         if (curBroadcast != null || linkedToDeath) {
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 9fdd293..c47c1ac 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -16,40 +16,39 @@
 
 package com.android.server.am;
 
-import android.app.PendingIntent;
-import android.net.Uri;
-import android.provider.Settings;
+import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.NotificationManagerService;
 
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 
 /**
  * A running application service.
  */
-class ServiceRecord extends Binder {
+final class ServiceRecord extends Binder {
     // Maximum number of delivery attempts before giving up.
     static final int MAX_DELIVERY_COUNT = 3;
 
@@ -76,24 +75,30 @@
     final boolean exported; // from ServiceInfo.exported
     final Runnable restarter; // used to schedule retries of starting the service
     final long createTime;  // when this service was created
-    final HashMap<Intent.FilterComparison, IntentBindRecord> bindings
-            = new HashMap<Intent.FilterComparison, IntentBindRecord>();
+    final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
+            = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
                             // All active bindings to the service.
-    final HashMap<IBinder, ArrayList<ConnectionRecord>> connections
-            = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
+    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
+            = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
                             // IBinder -> ConnectionRecord of all bound clients
 
     ProcessRecord app;      // where this service is running or null.
     ProcessRecord isolatedProc; // keep track of isolated process, if requested
+    ProcessStats.ServiceState tracker; // tracking service execution, may be null
+    boolean delayed;        // are we waiting to start this service in the background?
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
     Notification foregroundNoti; // Notification record of foreground state.
     long lastActivity;      // last time there was some activity on the service.
+    long startingBgTimeout;  // time at which we scheduled this for a delayed start.
     boolean startRequested; // someone explicitly called start?
+    boolean delayedStop;    // service has been stopped but is in a delayed start?
     boolean stopIfKilled;   // last onStart() said to stop if service killed?
     boolean callStart;      // last onStart() has asked to alway be called on restart.
     int executeNesting;     // number of outstanding operations keeping foreground.
+    boolean executeFg;      // should we be executing in the foreground?
     long executingStart;    // start time of last execute request.
+    boolean createdFromFg;  // was this service last created due to a foreground process call?
     int crashCount;         // number of times proc has crashed with service running
     int totalRestartCount;  // number of times we have had to restart.
     int restartCount;       // number of restarts performed in a row.
@@ -218,6 +223,9 @@
         if (isolatedProc != null) {
             pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
         }
+        if (delayed) {
+            pw.print(prefix); pw.print("delayed="); pw.println(delayed);
+        }
         if (isForeground || foregroundId != 0) {
             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
                     pw.print(" foregroundId="); pw.print(foregroundId);
@@ -225,24 +233,31 @@
         }
         pw.print(prefix); pw.print("createTime=");
                 TimeUtils.formatDuration(createTime, nowReal, pw);
-                pw.print(" lastActivity=");
+                pw.print(" startingBgTimeout=");
+                TimeUtils.formatDuration(startingBgTimeout, now, pw);
+                pw.println();
+        pw.print(prefix); pw.print("lastActivity=");
                 TimeUtils.formatDuration(lastActivity, now, pw);
-                pw.println("");
-        pw.print(prefix); pw.print("executingStart=");
-                TimeUtils.formatDuration(executingStart, now, pw);
                 pw.print(" restartTime=");
                 TimeUtils.formatDuration(restartTime, now, pw);
-                pw.println("");
-        if (startRequested || lastStartId != 0) {
+                pw.print(" createdFromFg="); pw.println(createdFromFg);
+        if (startRequested || delayedStop || lastStartId != 0) {
             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
+                    pw.print(" delayedStop="); pw.print(delayedStop);
                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
                     pw.print(" callStart="); pw.print(callStart);
                     pw.print(" lastStartId="); pw.println(lastStartId);
         }
-        if (executeNesting != 0 || crashCount != 0 || restartCount != 0
-                || restartDelay != 0 || nextRestartTime != 0) {
+        if (executeNesting != 0) {
             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
-                    pw.print(" restartCount="); pw.print(restartCount);
+                    pw.print(" executeFg="); pw.print(executeFg);
+                    pw.print(" executingStart=");
+                    TimeUtils.formatDuration(executingStart, now, pw);
+                    pw.println();
+        }
+        if (crashCount != 0 || restartCount != 0
+                || restartDelay != 0 || nextRestartTime != 0) {
+            pw.print(prefix); pw.print("restartCount="); pw.print(restartCount);
                     pw.print(" restartDelay=");
                     TimeUtils.formatDuration(restartDelay, now, pw);
                     pw.print(" nextRestartTime=");
@@ -258,10 +273,9 @@
             dumpStartList(pw, prefix, pendingStarts, 0);
         }
         if (bindings.size() > 0) {
-            Iterator<IntentBindRecord> it = bindings.values().iterator();
             pw.print(prefix); pw.println("Bindings:");
-            while (it.hasNext()) {
-                IntentBindRecord b = it.next();
+            for (int i=0; i<bindings.size(); i++) {
+                IntentBindRecord b = bindings.valueAt(i);
                 pw.print(prefix); pw.print("* IntentBindRecord{");
                         pw.print(Integer.toHexString(System.identityHashCode(b)));
                         if ((b.collectFlags()&Context.BIND_AUTO_CREATE) != 0) {
@@ -273,9 +287,8 @@
         }
         if (connections.size() > 0) {
             pw.print(prefix); pw.println("All Connections:");
-            Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
-            while (it.hasNext()) {
-                ArrayList<ConnectionRecord> c = it.next();
+            for (int conni=0; conni<connections.size(); conni++) {
+                ArrayList<ConnectionRecord> c = connections.valueAt(conni);
                 for (int i=0; i<c.size(); i++) {
                     pw.print(prefix); pw.print("  "); pw.println(c.get(i));
                 }
@@ -285,7 +298,8 @@
 
     ServiceRecord(ActivityManagerService ams,
             BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
-            Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
+            Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
+            Runnable restarter) {
         this.ams = ams;
         this.stats = servStats;
         this.name = name;
@@ -304,6 +318,31 @@
         createTime = SystemClock.elapsedRealtime();
         lastActivity = SystemClock.uptimeMillis();
         userId = UserHandle.getUserId(appInfo.uid);
+        createdFromFg = callerIsFg;
+    }
+
+    public ProcessStats.ServiceState getTracker() {
+        if (tracker != null) {
+            return tracker;
+        }
+        if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+            tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
+                    serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name);
+            tracker.applyNewOwner(this);
+        }
+        return tracker;
+    }
+
+    public void forceClearTracker() {
+        if (tracker != null) {
+            int memFactor = ams.mProcessStats.getMemFactorLocked();
+            long now = SystemClock.uptimeMillis();
+            tracker.setStarted(false, memFactor, now);
+            tracker.setBound(false, memFactor, now);
+            tracker.setExecuting(false, memFactor, now);
+            tracker.clearCurrentOwner(this);
+            tracker = null;
+        }
     }
 
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
@@ -323,6 +362,20 @@
         return a;
     }
 
+    public boolean hasAutoCreateConnections() {
+        // XXX should probably keep a count of the number of auto-create
+        // connections directly in the service.
+        for (int conni=connections.size()-1; conni>=0; conni--) {
+            ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
+            for (int i=0; i<cr.size(); i++) {
+                if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public void resetRestartCounter() {
         restartCount = 0;
         restartDelay = 0;
diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/java/com/android/server/am/StrictModeViolationDialog.java
index 35d50a1..5fee0d3 100644
--- a/services/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/java/com/android/server/am/StrictModeViolationDialog.java
@@ -16,16 +16,15 @@
 
 package com.android.server.am;
 
-import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
-import android.util.Slog;
 
-class StrictModeViolationDialog extends BaseErrorDialog {
+final class StrictModeViolationDialog extends BaseErrorDialog {
     private final static String TAG = "StrictModeViolationDialog";
 
     private final ActivityManagerService mService;
@@ -75,7 +74,7 @@
         }
 
         setTitle(res.getText(com.android.internal.R.string.aerr_title));
-        getWindow().addFlags(FLAG_SYSTEM_ERROR);
+        getWindow().addFlags(PRIVATE_FLAG_SYSTEM_ERROR);
         getWindow().setTitle("Strict Mode Violation: " + app.info.processName);
 
         // After the timeout, pretend the user clicked the quit button
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 1bae9ca..385253e 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -16,15 +16,24 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.IThumbnailRetriever;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.graphics.Bitmap;
 import android.os.UserHandle;
 import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
-class TaskRecord extends ThumbnailHolder {
+final class TaskRecord extends ThumbnailHolder {
     final int taskId;       // Unique identifier for this task.
     final String affinity;  // The affinity name for this task, or null.
     Intent intent;          // The original intent that started the task.
@@ -39,7 +48,21 @@
 
     String stringName;      // caching of toString() result.
     int userId;             // user for which this task was created
-    
+
+    int numFullscreen;      // Number of fullscreen activities.
+
+    /** List of all activities in the task arranged in history order */
+    final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
+
+    /** Current stack */
+    ActivityStack stack;
+
+    /** Takes on same set of values as ActivityRecord.mActivityType */
+    private int mTaskType;
+
+    /** Launch the home activity when leaving this task. */
+    boolean mOnTopOfHome = false;
+
     TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
         taskId = _taskId;
         affinity = info.taskAffinity;
@@ -49,11 +72,11 @@
     void touchActiveTime() {
         lastActiveTime = android.os.SystemClock.elapsedRealtime();
     }
-    
+
     long getInactiveDuration() {
         return android.os.SystemClock.elapsedRealtime() - lastActiveTime;
     }
-    
+
     void setIntent(Intent _intent, ActivityInfo info) {
         stringName = null;
 
@@ -104,12 +127,310 @@
             userId = UserHandle.getUserId(info.applicationInfo.uid);
         }
     }
-    
+
+    ActivityRecord getTopActivity() {
+        for (int i = mActivities.size() - 1; i >= 0; --i) {
+            final ActivityRecord r = mActivities.get(i);
+            if (r.finishing) {
+                continue;
+            }
+            return r;
+        }
+        return null;
+    }
+
+    ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
+        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord r = mActivities.get(activityNdx);
+            if (!r.finishing && r != notTop && stack.okToShow(r)) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Reorder the history stack so that the activity at the given index is
+     * brought to the front.
+     */
+    final void moveActivityToFrontLocked(ActivityRecord newTop) {
+        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
+            + " to stack at top", new RuntimeException("here").fillInStackTrace());
+
+        getTopActivity().frontOfTask = false;
+        mActivities.remove(newTop);
+        mActivities.add(newTop);
+        newTop.frontOfTask = true;
+    }
+
+    void addActivityAtBottom(ActivityRecord r) {
+        addActivityAtIndex(0, r);
+    }
+
+    void addActivityToTop(ActivityRecord r) {
+        addActivityAtIndex(mActivities.size(), r);
+    }
+
+    void addActivityAtIndex(int index, ActivityRecord r) {
+        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
+        if (!mActivities.remove(r) && r.fullscreen) {
+            // Was not previously in list.
+            numFullscreen++;
+        }
+        // Only set this based on the first activity
+        if (mActivities.isEmpty()) {
+            mTaskType = r.mActivityType;
+        } else {
+            // Otherwise make all added activities match this one.
+            r.mActivityType = mTaskType;
+        }
+        mActivities.add(index, r);
+    }
+
+    /** @return true if this was the last activity in the task */
+    boolean removeActivity(ActivityRecord r) {
+        if (mActivities.remove(r) && r.fullscreen) {
+            // Was previously in list.
+            numFullscreen--;
+        }
+        return mActivities.size() == 0;
+    }
+
+    /**
+     * Completely remove all activities associated with an existing
+     * task starting at a specified index.
+     */
+    final void performClearTaskAtIndexLocked(int activityNdx) {
+        int numActivities = mActivities.size();
+        for ( ; activityNdx < numActivities; ++activityNdx) {
+            final ActivityRecord r = mActivities.get(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear", false)) {
+                --activityNdx;
+                --numActivities;
+            }
+        }
+    }
+
+    /**
+     * Completely remove all activities associated with an existing task.
+     */
+    final void performClearTaskLocked() {
+        performClearTaskAtIndexLocked(0);
+    }
+
+    /**
+     * Perform clear operation as requested by
+     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
+     * stack to the given task, then look for
+     * an instance of that activity in the stack and, if found, finish all
+     * activities on top of it and return the instance.
+     *
+     * @param newR Description of the new activity being started.
+     * @return Returns the old activity that should be continued to be used,
+     * or null if none was found.
+     */
+    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
+        int numActivities = mActivities.size();
+        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord r = mActivities.get(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            if (r.realActivity.equals(newR.realActivity)) {
+                // Here it is!  Now finish everything in front...
+                final ActivityRecord ret = r;
+
+                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
+                    r = mActivities.get(activityNdx);
+                    if (r.finishing) {
+                        continue;
+                    }
+                    ActivityOptions opts = r.takeOptionsLocked();
+                    if (opts != null) {
+                        ret.updateOptionsLocked(opts);
+                    }
+                    if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
+                            false)) {
+                        --activityNdx;
+                        --numActivities;
+                    }
+                }
+
+                // Finally, if this is a normal launch mode (that is, not
+                // expecting onNewIntent()), then we will finish the current
+                // instance of the activity so a new fresh one can be started.
+                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
+                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
+                    if (!ret.finishing) {
+                        stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
+                                "clear", false);
+                        return null;
+                    }
+                }
+
+                return ret;
+            }
+        }
+
+        return null;
+    }
+
+    public ActivityManager.TaskThumbnails getTaskThumbnailsLocked() {
+        TaskAccessInfo info = getTaskAccessInfoLocked(true);
+        final ActivityRecord resumedActivity = stack.mResumedActivity;
+        if (resumedActivity != null && resumedActivity.thumbHolder == this) {
+            info.mainThumbnail = stack.screenshotActivities(resumedActivity);
+        }
+        if (info.mainThumbnail == null) {
+            info.mainThumbnail = lastThumbnail;
+        }
+        return info;
+    }
+
+    public Bitmap getTaskTopThumbnailLocked() {
+        final ActivityRecord resumedActivity = stack.mResumedActivity;
+        if (resumedActivity != null && resumedActivity.task == this) {
+            // This task is the current resumed task, we just need to take
+            // a screenshot of it and return that.
+            return stack.screenshotActivities(resumedActivity);
+        }
+        // Return the information about the task, to figure out the top
+        // thumbnail to return.
+        TaskAccessInfo info = getTaskAccessInfoLocked(true);
+        if (info.numSubThumbbails <= 0) {
+            return info.mainThumbnail != null ? info.mainThumbnail : lastThumbnail;
+        }
+        return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
+    }
+
+    public ActivityRecord removeTaskActivitiesLocked(int subTaskIndex,
+            boolean taskRequired) {
+        TaskAccessInfo info = getTaskAccessInfoLocked(false);
+        if (info.root == null) {
+            if (taskRequired) {
+                Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
+            }
+            return null;
+        }
+
+        if (subTaskIndex < 0) {
+            // Just remove the entire task.
+            performClearTaskAtIndexLocked(info.rootIndex);
+            return info.root;
+        }
+
+        if (subTaskIndex >= info.subtasks.size()) {
+            if (taskRequired) {
+                Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
+            }
+            return null;
+        }
+
+        // Remove all of this task's activities starting at the sub task.
+        TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
+        performClearTaskAtIndexLocked(subtask.index);
+        return subtask.activity;
+    }
+
+    boolean isHomeTask() {
+        return mTaskType == ActivityRecord.HOME_ACTIVITY_TYPE;
+    }
+
+    boolean isApplicationTask() {
+        return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+    }
+
+    public TaskAccessInfo getTaskAccessInfoLocked(boolean inclThumbs) {
+        final TaskAccessInfo thumbs = new TaskAccessInfo();
+        // How many different sub-thumbnails?
+        final int NA = mActivities.size();
+        int j = 0;
+        ThumbnailHolder holder = null;
+        while (j < NA) {
+            ActivityRecord ar = mActivities.get(j);
+            if (!ar.finishing) {
+                thumbs.root = ar;
+                thumbs.rootIndex = j;
+                holder = ar.thumbHolder;
+                if (holder != null) {
+                    thumbs.mainThumbnail = holder.lastThumbnail;
+                }
+                j++;
+                break;
+            }
+            j++;
+        }
+
+        if (j >= NA) {
+            return thumbs;
+        }
+
+        ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
+        thumbs.subtasks = subtasks;
+        while (j < NA) {
+            ActivityRecord ar = mActivities.get(j);
+            j++;
+            if (ar.finishing) {
+                continue;
+            }
+            if (ar.thumbHolder != holder && holder != null) {
+                thumbs.numSubThumbbails++;
+                holder = ar.thumbHolder;
+                TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
+                sub.holder = holder;
+                sub.activity = ar;
+                sub.index = j-1;
+                subtasks.add(sub);
+            }
+        }
+        if (thumbs.numSubThumbbails > 0) {
+            thumbs.retriever = new IThumbnailRetriever.Stub() {
+                @Override
+                public Bitmap getThumbnail(int index) {
+                    if (index < 0 || index >= thumbs.subtasks.size()) {
+                        return null;
+                    }
+                    TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index);
+                    ActivityRecord resumedActivity = stack.mResumedActivity;
+                    if (resumedActivity != null && resumedActivity.thumbHolder == sub.holder) {
+                        return stack.screenshotActivities(resumedActivity);
+                    }
+                    return sub.holder.lastThumbnail;
+                }
+            };
+        }
+        return thumbs;
+    }
+
+    /**
+     * Find the activity in the history stack within the given task.  Returns
+     * the index within the history at which it's found, or < 0 if not found.
+     */
+    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
+        final ComponentName realActivity = r.realActivity;
+        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord candidate = mActivities.get(activityNdx);
+            if (candidate.finishing) {
+                continue;
+            }
+            if (candidate.realActivity.equals(realActivity)) {
+                return candidate;
+            }
+        }
+        return null;
+    }
+
     void dump(PrintWriter pw, String prefix) {
-        if (numActivities != 0 || rootWasReset || userId != 0) {
+        if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
                     pw.print(" rootWasReset="); pw.print(rootWasReset);
-                    pw.print(" userId="); pw.println(userId);
+                    pw.print(" userId="); pw.print(userId);
+                    pw.print(" mTaskType="); pw.print(mTaskType);
+                    pw.print(" numFullscreen="); pw.print(numFullscreen);
+                    pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
         }
         if (affinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.println(affinity);
@@ -136,6 +457,7 @@
             pw.print(prefix); pw.print("realActivity=");
             pw.println(realActivity.flattenToShortString());
         }
+        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
         if (!askedCompatMode) {
             pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
         }
@@ -146,30 +468,35 @@
                 pw.print((getInactiveDuration()/1000)); pw.println("s)");
     }
 
+    @Override
     public String toString() {
-        if (stringName != null) {
-            return stringName;
-        }
         StringBuilder sb = new StringBuilder(128);
+        if (stringName != null) {
+            sb.append(stringName);
+            sb.append(" U=");
+            sb.append(userId);
+            sb.append(" sz=");
+            sb.append(mActivities.size());
+            sb.append('}');
+            return sb.toString();
+        }
         sb.append("TaskRecord{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(" #");
         sb.append(taskId);
         if (affinity != null) {
-            sb.append(" A ");
+            sb.append(" A=");
             sb.append(affinity);
         } else if (intent != null) {
-            sb.append(" I ");
+            sb.append(" I=");
             sb.append(intent.getComponent().flattenToShortString());
         } else if (affinityIntent != null) {
-            sb.append(" aI ");
+            sb.append(" aI=");
             sb.append(affinityIntent.getComponent().flattenToShortString());
         } else {
             sb.append(" ??");
         }
-        sb.append(" U ");
-        sb.append(userId);
-        sb.append('}');
-        return stringName = sb.toString();
+        stringName = sb.toString();
+        return toString();
     }
 }
diff --git a/services/java/com/android/server/am/TransferPipe.java b/services/java/com/android/server/am/TransferPipe.java
deleted file mode 100644
index c3f4f93..0000000
--- a/services/java/com/android/server/am/TransferPipe.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server.am;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Slog;
-
-/**
- * Helper for transferring data through a pipe from a client app.
- */
-class TransferPipe implements Runnable {
-    static final String TAG = "TransferPipe";
-    static final boolean DEBUG = false;
-
-    static final long DEFAULT_TIMEOUT = 5000;  // 5 seconds
-
-    final Thread mThread;;
-    final ParcelFileDescriptor[] mFds;
-
-    FileDescriptor mOutFd;
-    long mEndTime;
-    String mFailure;
-    boolean mComplete;
-
-    String mBufferPrefix;
-
-    interface Caller {
-        void go(IInterface iface, FileDescriptor fd, String prefix,
-                String[] args) throws RemoteException;
-    }
-
-    TransferPipe() throws IOException {
-        mThread = new Thread(this, "TransferPipe");
-        mFds = ParcelFileDescriptor.createPipe();
-    }
-
-    ParcelFileDescriptor getReadFd() {
-        return mFds[0];
-    }
-
-    ParcelFileDescriptor getWriteFd() {
-        return mFds[1];
-    }
-
-    void setBufferPrefix(String prefix) {
-        mBufferPrefix = prefix;
-    }
-
-    static void go(Caller caller, IInterface iface, FileDescriptor out,
-            String prefix, String[] args) throws IOException, RemoteException {
-        go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT);
-    }
-
-    static void go(Caller caller, IInterface iface, FileDescriptor out,
-            String prefix, String[] args, long timeout) throws IOException, RemoteException {
-        if ((iface.asBinder()) instanceof Binder) {
-            // This is a local object...  just call it directly.
-            try {
-                caller.go(iface, out, prefix, args);
-            } catch (RemoteException e) {
-            }
-            return;
-        }
-
-        TransferPipe tp = new TransferPipe();
-        try {
-            caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args);
-            tp.go(out, timeout);
-        } finally {
-            tp.kill();
-        }
-    }
-
-    static void goDump(IBinder binder, FileDescriptor out,
-            String[] args) throws IOException, RemoteException {
-        goDump(binder, out, args, DEFAULT_TIMEOUT);
-    }
-
-    static void goDump(IBinder binder, FileDescriptor out,
-            String[] args, long timeout) throws IOException, RemoteException {
-        if (binder instanceof Binder) {
-            // This is a local object...  just call it directly.
-            try {
-                binder.dump(out, args);
-            } catch (RemoteException e) {
-            }
-            return;
-        }
-
-        TransferPipe tp = new TransferPipe();
-        try {
-            binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
-            tp.go(out, timeout);
-        } finally {
-            tp.kill();
-        }
-    }
-
-    void go(FileDescriptor out) throws IOException {
-        go(out, DEFAULT_TIMEOUT);
-    }
-
-    void go(FileDescriptor out, long timeout) throws IOException {
-        try {
-            synchronized (this) {
-                mOutFd = out;
-                mEndTime = SystemClock.uptimeMillis() + timeout;
-
-                if (DEBUG) Slog.i(TAG, "read=" + getReadFd() + " write=" + getWriteFd()
-                        + " out=" + out);
-
-                // Close the write fd, so we know when the other side is done.
-                closeFd(1);
-
-                mThread.start();
-
-                while (mFailure == null && !mComplete) {
-                    long waitTime = mEndTime - SystemClock.uptimeMillis();
-                    if (waitTime <= 0) {
-                        if (DEBUG) Slog.i(TAG, "TIMEOUT!");
-                        mThread.interrupt();
-                        throw new IOException("Timeout");
-                    }
-
-                    try {
-                        wait(waitTime);
-                    } catch (InterruptedException e) {
-                    }
-                }
-
-                if (DEBUG) Slog.i(TAG, "Finished: " + mFailure);
-                if (mFailure != null) {
-                    throw new IOException(mFailure);
-                }
-            }
-        } finally {
-            kill();
-        }
-    }
-
-    void closeFd(int num) {
-        if (mFds[num] != null) {
-            if (DEBUG) Slog.i(TAG, "Closing: " + mFds[num]);
-            try {
-                mFds[num].close();
-            } catch (IOException e) {
-            }
-            mFds[num] = null;
-        }
-    }
-
-    void kill() {
-        closeFd(0);
-        closeFd(1);
-    }
-
-    @Override
-    public void run() {
-        final byte[] buffer = new byte[1024];
-        final FileInputStream fis = new FileInputStream(getReadFd().getFileDescriptor());
-        final FileOutputStream fos = new FileOutputStream(mOutFd);
-
-        if (DEBUG) Slog.i(TAG, "Ready to read pipe...");
-        byte[] bufferPrefix = null;
-        boolean needPrefix = true;
-        if (mBufferPrefix != null) {
-            bufferPrefix = mBufferPrefix.getBytes();
-        }
-
-        int size;
-        try {
-            while ((size=fis.read(buffer)) > 0) {
-                if (DEBUG) Slog.i(TAG, "Got " + size + " bytes");
-                if (bufferPrefix == null) {
-                    fos.write(buffer, 0, size);
-                } else {
-                    int start = 0;
-                    for (int i=0; i<size; i++) {
-                        if (buffer[i] != '\n') {
-                            if (i > start) {
-                                fos.write(buffer, start, i-start);
-                            }
-                            start = i;
-                            if (needPrefix) {
-                                fos.write(bufferPrefix);
-                                needPrefix = false;
-                            }
-                            do {
-                                i++;
-                            } while (i<size && buffer[i] != '\n');
-                            if (i < size) {
-                                needPrefix = true;
-                            }
-                        }
-                    }
-                    if (size > start) {
-                        fos.write(buffer, start, size-start);
-                    }
-                }
-            }
-            if (DEBUG) Slog.i(TAG, "End of pipe: size=" + size);
-            if (mThread.isInterrupted()) {
-                if (DEBUG) Slog.i(TAG, "Interrupted!");
-            }
-        } catch (IOException e) {
-            synchronized (this) {
-                mFailure = e.toString();
-                notifyAll();
-                return;
-            }
-        }
-
-        synchronized (this) {
-            mComplete = true;
-            notifyAll();
-        }
-    }
-}
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index c5b1c7b..5868c08 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -18,8 +18,15 @@
 
 import android.content.Intent;
 import android.net.Uri;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+import com.google.android.collect.Sets;
 
 import java.io.PrintWriter;
+import java.util.Comparator;
 import java.util.HashSet;
 
 /**
@@ -30,44 +37,237 @@
  * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
  *      src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
  */
-class UriPermission {
-    final int uid;
+final class UriPermission {
+    private static final String TAG = "UriPermission";
+
+    public static final int STRENGTH_NONE = 0;
+    public static final int STRENGTH_OWNED = 1;
+    public static final int STRENGTH_GLOBAL = 2;
+    public static final int STRENGTH_PERSISTABLE = 3;
+
+    final int userHandle;
+    final String sourcePkg;
+    final String targetPkg;
+
+    /** Cached UID of {@link #targetPkg}; should not be persisted */
+    final int targetUid;
+
     final Uri uri;
+
+    /**
+     * Allowed modes. All permission enforcement should use this field. Must
+     * always be a combination of {@link #ownedModeFlags},
+     * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
+     * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
+     * the owning class.
+     */
     int modeFlags = 0;
+
+    /** Allowed modes with explicit owner. */
+    int ownedModeFlags = 0;
+    /** Allowed modes without explicit owner. */
     int globalModeFlags = 0;
-    final HashSet<UriPermissionOwner> readOwners = new HashSet<UriPermissionOwner>();
-    final HashSet<UriPermissionOwner> writeOwners = new HashSet<UriPermissionOwner>();
-    
-    String stringName;
-    
-    UriPermission(int _uid, Uri _uri) {
-        uid = _uid;
-        uri = _uri;
+    /** Allowed modes that have been offered for possible persisting. */
+    int persistableModeFlags = 0;
+    /** Allowed modes that should be persisted across device boots. */
+    int persistedModeFlags = 0;
+
+    /**
+     * Timestamp when {@link #persistedModeFlags} was first defined in
+     * {@link System#currentTimeMillis()} time base.
+     */
+    long persistedCreateTime = INVALID_TIME;
+
+    private static final long INVALID_TIME = Long.MIN_VALUE;
+
+    private HashSet<UriPermissionOwner> mReadOwners;
+    private HashSet<UriPermissionOwner> mWriteOwners;
+
+    private String stringName;
+
+    UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
+        this.userHandle = UserHandle.getUserId(targetUid);
+        this.sourcePkg = sourcePkg;
+        this.targetPkg = targetPkg;
+        this.targetUid = targetUid;
+        this.uri = uri;
     }
-    
-    void clearModes(int modeFlagsToClear) {
-        if ((modeFlagsToClear&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+
+    private void updateModeFlags() {
+        modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
+    }
+
+    /**
+     * Initialize persisted modes as read from file. This doesn't issue any
+     * global or owner grants.
+     */
+    void initPersistedModes(int modeFlags, long createdTime) {
+        persistableModeFlags = modeFlags;
+        persistedModeFlags = modeFlags;
+        persistedCreateTime = createdTime;
+
+        updateModeFlags();
+    }
+
+    void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
+        if (persistable) {
+            persistableModeFlags |= modeFlags;
+        }
+
+        if (owner == null) {
+            globalModeFlags |= modeFlags;
+        } else {
+            if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+                addReadOwner(owner);
+            }
+            if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+                addWriteOwner(owner);
+            }
+        }
+
+        updateModeFlags();
+    }
+
+    /**
+     * @return if mode changes should trigger persisting.
+     */
+    boolean takePersistableModes(int modeFlags) {
+        Preconditions.checkFlagsArgument(modeFlags, persistableModeFlags);
+
+        final int before = persistedModeFlags;
+        persistedModeFlags |= (persistableModeFlags & modeFlags);
+
+        if (persistedModeFlags != 0) {
+            persistedCreateTime = System.currentTimeMillis();
+        }
+
+        updateModeFlags();
+        return persistedModeFlags != before;
+    }
+
+    boolean releasePersistableModes(int modeFlags) {
+        final int before = persistedModeFlags;
+
+        persistableModeFlags &= ~modeFlags;
+        persistedModeFlags &= ~modeFlags;
+
+        if (persistedModeFlags == 0) {
+            persistedCreateTime = INVALID_TIME;
+        }
+
+        updateModeFlags();
+        return persistedModeFlags != before;
+    }
+
+    /**
+     * @return if mode changes should trigger persisting.
+     */
+    boolean clearModes(int modeFlags, boolean persistable) {
+        final int before = persistedModeFlags;
+
+        if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+            if (persistable) {
+                persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+                persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+            }
             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-            modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-            if (readOwners.size() > 0) {
-                for (UriPermissionOwner r : readOwners) {
+            if (mReadOwners != null) {
+                ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+                for (UriPermissionOwner r : mReadOwners) {
                     r.removeReadPermission(this);
                 }
-                readOwners.clear();
+                mReadOwners = null;
             }
         }
-        if ((modeFlagsToClear&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+        if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+            if (persistable) {
+                persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+                persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+            }
             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-            modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-            if (writeOwners.size() > 0) {
-                for (UriPermissionOwner r : writeOwners) {
+            if (mWriteOwners != null) {
+                ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+                for (UriPermissionOwner r : mWriteOwners) {
                     r.removeWritePermission(this);
                 }
-                writeOwners.clear();
+                mWriteOwners = null;
             }
         }
+
+        if (persistedModeFlags == 0) {
+            persistedCreateTime = INVALID_TIME;
+        }
+
+        updateModeFlags();
+        return persistedModeFlags != before;
     }
-    
+
+    /**
+     * Return strength of this permission grant for the given flags.
+     */
+    public int getStrength(int modeFlags) {
+        if ((persistableModeFlags & modeFlags) == modeFlags) {
+            return STRENGTH_PERSISTABLE;
+        } else if ((globalModeFlags & modeFlags) == modeFlags) {
+            return STRENGTH_GLOBAL;
+        } else if ((ownedModeFlags & modeFlags) == modeFlags) {
+            return STRENGTH_OWNED;
+        } else {
+            return STRENGTH_NONE;
+        }
+    }
+
+    private void addReadOwner(UriPermissionOwner owner) {
+        if (mReadOwners == null) {
+            mReadOwners = Sets.newHashSet();
+            ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
+            updateModeFlags();
+        }
+        if (mReadOwners.add(owner)) {
+            owner.addReadPermission(this);
+        }
+    }
+
+    /**
+     * Remove given read owner, updating {@Link #modeFlags} as needed.
+     */
+    void removeReadOwner(UriPermissionOwner owner) {
+        if (!mReadOwners.remove(owner)) {
+            Log.wtf(TAG, "Unknown read owner " + owner + " in " + this);
+        }
+        if (mReadOwners.size() == 0) {
+            mReadOwners = null;
+            ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+            updateModeFlags();
+        }
+    }
+
+    private void addWriteOwner(UriPermissionOwner owner) {
+        if (mWriteOwners == null) {
+            mWriteOwners = Sets.newHashSet();
+            ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+            updateModeFlags();
+        }
+        if (mWriteOwners.add(owner)) {
+            owner.addWritePermission(this);
+        }
+    }
+
+    /**
+     * Remove given write owner, updating {@Link #modeFlags} as needed.
+     */
+    void removeWriteOwner(UriPermissionOwner owner) {
+        if (!mWriteOwners.remove(owner)) {
+            Log.wtf(TAG, "Unknown write owner " + owner + " in " + this);
+        }
+        if (mWriteOwners.size() == 0) {
+            mWriteOwners = null;
+            ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+            updateModeFlags();
+        }
+    }
+
+    @Override
     public String toString() {
         if (stringName != null) {
             return stringName;
@@ -82,22 +282,74 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("modeFlags=0x");
-                pw.print(Integer.toHexString(modeFlags));
-                pw.print(" uid="); pw.print(uid); 
-                pw.print(" globalModeFlags=0x");
-                pw.println(Integer.toHexString(globalModeFlags));
-        if (readOwners.size() != 0) {
-            pw.print(prefix); pw.println("readOwners:");
-            for (UriPermissionOwner owner : readOwners) {
-                pw.print(prefix); pw.print("  * "); pw.println(owner);
+        pw.print(prefix);
+        pw.print("userHandle=" + userHandle);
+        pw.print(" sourcePkg=" + sourcePkg);
+        pw.println(" targetPkg=" + targetPkg);
+
+        pw.print(prefix);
+        pw.print("mode=0x" + Integer.toHexString(modeFlags));
+        pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
+        pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
+        pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
+        pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
+        if (persistedCreateTime != INVALID_TIME) {
+            pw.print(" persistedCreate=" + persistedCreateTime);
+        }
+        pw.println();
+
+        if (mReadOwners != null) {
+            pw.print(prefix);
+            pw.println("readOwners:");
+            for (UriPermissionOwner owner : mReadOwners) {
+                pw.print(prefix);
+                pw.println("  * " + owner);
             }
         }
-        if (writeOwners.size() != 0) {
-            pw.print(prefix); pw.println("writeOwners:");
-            for (UriPermissionOwner owner : writeOwners) {
-                pw.print(prefix); pw.print("  * "); pw.println(owner);
+        if (mWriteOwners != null) {
+            pw.print(prefix);
+            pw.println("writeOwners:");
+            for (UriPermissionOwner owner : mReadOwners) {
+                pw.print(prefix);
+                pw.println("  * " + owner);
             }
         }
     }
+
+    public static class PersistedTimeComparator implements Comparator<UriPermission> {
+        @Override
+        public int compare(UriPermission lhs, UriPermission rhs) {
+            return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
+        }
+    }
+
+    /**
+     * Snapshot of {@link UriPermission} with frozen
+     * {@link UriPermission#persistedModeFlags} state.
+     */
+    public static class Snapshot {
+        final int userHandle;
+        final String sourcePkg;
+        final String targetPkg;
+        final Uri uri;
+        final int persistedModeFlags;
+        final long persistedCreateTime;
+
+        private Snapshot(UriPermission perm) {
+            this.userHandle = perm.userHandle;
+            this.sourcePkg = perm.sourcePkg;
+            this.targetPkg = perm.targetPkg;
+            this.uri = perm.uri;
+            this.persistedModeFlags = perm.persistedModeFlags;
+            this.persistedCreateTime = perm.persistedCreateTime;
+        }
+    }
+
+    public Snapshot snapshot() {
+        return new Snapshot(this);
+    }
+
+    public android.content.UriPermission buildPersistedPublicApiObject() {
+        return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
+    }
 }
diff --git a/services/java/com/android/server/am/UriPermissionOwner.java b/services/java/com/android/server/am/UriPermissionOwner.java
index 68a2e0f..7bbd3bc 100644
--- a/services/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/java/com/android/server/am/UriPermissionOwner.java
@@ -24,7 +24,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 
-class UriPermissionOwner {
+final class UriPermissionOwner {
     final ActivityManagerService service;
     final Object owner;
 
@@ -67,24 +67,16 @@
         if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
                 && readUriPermissions != null) {
             for (UriPermission perm : readUriPermissions) {
-                perm.readOwners.remove(this);
-                if (perm.readOwners.size() == 0 && (perm.globalModeFlags
-                        &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
-                    perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-                    service.removeUriPermissionIfNeededLocked(perm);
-                }
+                perm.removeReadOwner(this);
+                service.removeUriPermissionIfNeededLocked(perm);
             }
             readUriPermissions = null;
         }
         if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
                 && writeUriPermissions != null) {
             for (UriPermission perm : writeUriPermissions) {
-                perm.writeOwners.remove(this);
-                if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
-                        &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
-                    perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-                    service.removeUriPermissionIfNeededLocked(perm);
-                }
+                perm.removeWriteOwner(this);
+                service.removeUriPermissionIfNeededLocked(perm);
             }
             writeUriPermissions = null;
         }
@@ -97,12 +89,8 @@
             while (it.hasNext()) {
                 UriPermission perm = it.next();
                 if (uri.equals(perm.uri)) {
-                    perm.readOwners.remove(this);
-                    if (perm.readOwners.size() == 0 && (perm.globalModeFlags
-                            &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
-                        perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-                        service.removeUriPermissionIfNeededLocked(perm);
-                    }
+                    perm.removeReadOwner(this);
+                    service.removeUriPermissionIfNeededLocked(perm);
                     it.remove();
                 }
             }
@@ -116,12 +104,8 @@
             while (it.hasNext()) {
                 UriPermission perm = it.next();
                 if (uri.equals(perm.uri)) {
-                    perm.writeOwners.remove(this);
-                    if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
-                            &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
-                        perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-                        service.removeUriPermissionIfNeededLocked(perm);
-                    }
+                    perm.removeWriteOwner(this);
+                    service.removeUriPermissionIfNeededLocked(perm);
                     it.remove();
                 }
             }
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 6dae4aa..e96d8b1 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -16,8 +16,10 @@
 
 package com.android.server.am;
 
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -25,8 +27,10 @@
 import android.os.FileUtils;
 import android.os.Parcel;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.Xml;
@@ -73,7 +77,7 @@
     private static final String TAG = "UsageStats";
     
     // Current on-disk Parcel version
-    private static final int VERSION = 1007;
+    private static final int VERSION = 1008;
 
     private static final int CHECKIN_VERSION = 4;
     
@@ -93,10 +97,10 @@
     static IUsageStats sService;
     private Context mContext;
     // structure used to maintain statistics since the last checkin.
-    final private Map<String, PkgUsageStatsExtended> mStats;
+    final private ArrayMap<String, PkgUsageStatsExtended> mStats;
 
     // Maintains the last time any component was resumed, for all time.
-    final private Map<String, Map<String, Long>> mLastResumeTimes;
+    final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes;
 
     // To remove last-resume time stats when a pacakge is removed.
     private PackageMonitor mPackageMonitor;
@@ -162,8 +166,10 @@
     }
     
     private class PkgUsageStatsExtended {
-        final HashMap<String, TimeStats> mLaunchTimes
-                = new HashMap<String, TimeStats>();
+        final ArrayMap<String, TimeStats> mLaunchTimes
+                = new ArrayMap<String, TimeStats>();
+        final ArrayMap<String, TimeStats> mFullyDrawnTimes
+                = new ArrayMap<String, TimeStats>();
         int mLaunchCount;
         long mUsageTime;
         long mPausedTime;
@@ -180,14 +186,25 @@
             if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
                     + ", Usage time:" + mUsageTime);
             
-            final int numTimeStats = in.readInt();
-            if (localLOGV) Slog.v(TAG, "Reading comps: " + numTimeStats);
-            for (int i=0; i<numTimeStats; i++) {
+            final int numLaunchTimeStats = in.readInt();
+            if (localLOGV) Slog.v(TAG, "Reading launch times: " + numLaunchTimeStats);
+            mLaunchTimes.ensureCapacity(numLaunchTimeStats);
+            for (int i=0; i<numLaunchTimeStats; i++) {
                 String comp = in.readString();
                 if (localLOGV) Slog.v(TAG, "Component: " + comp);
                 TimeStats times = new TimeStats(in);
                 mLaunchTimes.put(comp, times);
             }
+
+            final int numFullyDrawnTimeStats = in.readInt();
+            if (localLOGV) Slog.v(TAG, "Reading fully drawn times: " + numFullyDrawnTimeStats);
+            mFullyDrawnTimes.ensureCapacity(numFullyDrawnTimeStats);
+            for (int i=0; i<numFullyDrawnTimeStats; i++) {
+                String comp = in.readString();
+                if (localLOGV) Slog.v(TAG, "Component: " + comp);
+                TimeStats times = new TimeStats(in);
+                mFullyDrawnTimes.put(comp, times);
+            }
         }
 
         void updateResume(String comp, boolean launched) {
@@ -219,31 +236,44 @@
             }
             times.add(millis);
         }
-        
+
+        void addFullyDrawnTime(String comp, int millis) {
+            TimeStats times = mFullyDrawnTimes.get(comp);
+            if (times == null) {
+                times = new TimeStats();
+                mFullyDrawnTimes.put(comp, times);
+            }
+            times.add(millis);
+        }
+
         void writeToParcel(Parcel out) {
             out.writeInt(mLaunchCount);
             out.writeLong(mUsageTime);
-            final int numTimeStats = mLaunchTimes.size();
-            out.writeInt(numTimeStats);
-            if (numTimeStats > 0) {
-                for (Map.Entry<String, TimeStats> ent : mLaunchTimes.entrySet()) {
-                    out.writeString(ent.getKey());
-                    TimeStats times = ent.getValue();
-                    times.writeToParcel(out);
-                }
+            final int numLaunchTimeStats = mLaunchTimes.size();
+            out.writeInt(numLaunchTimeStats);
+            for (int i=0; i<numLaunchTimeStats; i++) {
+                out.writeString(mLaunchTimes.keyAt(i));
+                mLaunchTimes.valueAt(i).writeToParcel(out);
+            }
+            final int numFullyDrawnTimeStats = mFullyDrawnTimes.size();
+            out.writeInt(numFullyDrawnTimeStats);
+            for (int i=0; i<numFullyDrawnTimeStats; i++) {
+                out.writeString(mFullyDrawnTimes.keyAt(i));
+                mFullyDrawnTimes.valueAt(i).writeToParcel(out);
             }
         }
         
         void clear() {
             mLaunchTimes.clear();
+            mFullyDrawnTimes.clear();
             mLaunchCount = 0;
             mUsageTime = 0;
         }
     }
     
     UsageStatsService(String dir) {
-        mStats = new HashMap<String, PkgUsageStatsExtended>();
-        mLastResumeTimes = new HashMap<String, Map<String, Long>>();
+        mStats = new ArrayMap<String, PkgUsageStatsExtended>();
+        mLastResumeTimes = new ArrayMap<String, ArrayMap<String, Long>>();
         mStatsLock = new Object();
         mFileLock = new Object();
         mDir = new File(dir);
@@ -386,9 +416,9 @@
                                 try {
                                     long lastResumeTime = Long.parseLong(lastResumeTimeStr);
                                     synchronized (mStatsLock) {
-                                        Map<String, Long> lrt = mLastResumeTimes.get(pkg);
+                                        ArrayMap<String, Long> lrt = mLastResumeTimes.get(pkg);
                                         if (lrt == null) {
-                                            lrt = new HashMap<String, Long>();
+                                            lrt = new ArrayMap<String, Long>();
                                             mLastResumeTimes.put(pkg, lrt);
                                         }
                                         lrt.put(comp, lastResumeTime);
@@ -591,14 +621,15 @@
     /** Filter out stats for any packages which aren't present anymore. */
     private void filterHistoryStats() {
         synchronized (mStatsLock) {
-            // Copy and clear the last resume times map, then copy back stats
-            // for all installed packages.
-            Map<String, Map<String, Long>> tmpLastResumeTimes =
-                new HashMap<String, Map<String, Long>>(mLastResumeTimes);
-            mLastResumeTimes.clear();
-            for (PackageInfo info : mContext.getPackageManager().getInstalledPackages(0)) {
-                if (tmpLastResumeTimes.containsKey(info.packageName)) {
-                    mLastResumeTimes.put(info.packageName, tmpLastResumeTimes.get(info.packageName));
+            IPackageManager pm = AppGlobals.getPackageManager();
+            for (int i=0; i<mLastResumeTimes.size(); i++) {
+                String pkg = mLastResumeTimes.keyAt(i);
+                try {
+                    if (pm.getPackageUid(pkg, 0) < 0) {
+                        mLastResumeTimes.removeAt(i);
+                        i--;
+                    }
+                } catch (RemoteException e) {
                 }
             }
         }
@@ -614,13 +645,14 @@
             out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             out.startTag(null, "usage-history");
             synchronized (mStatsLock) {
-                for (Map.Entry<String, Map<String, Long>> pkgEntry : mLastResumeTimes.entrySet()) {
+                for (int i=0; i<mLastResumeTimes.size(); i++) {
                     out.startTag(null, "pkg");
-                    out.attribute(null, "name", pkgEntry.getKey());
-                    for (Map.Entry<String, Long> compEntry : pkgEntry.getValue().entrySet()) {
+                    out.attribute(null, "name", mLastResumeTimes.keyAt(i));
+                    ArrayMap<String, Long> comp = mLastResumeTimes.valueAt(i);
+                    for (int j=0; j<comp.size(); j++) {
                         out.startTag(null, "comp");
-                        out.attribute(null, "name", compEntry.getKey());
-                        out.attribute(null, "lrt", compEntry.getValue().toString());
+                        out.attribute(null, "name", comp.keyAt(j));
+                        out.attribute(null, "lrt", comp.valueAt(j).toString());
                         out.endTag(null, "comp");
                     }
                     out.endTag(null, "pkg");
@@ -718,9 +750,9 @@
                 pus.addLaunchCount(mLastResumedComp);
             }
 
-            Map<String, Long> componentResumeTimes = mLastResumeTimes.get(pkgName);
+            ArrayMap<String, Long> componentResumeTimes = mLastResumeTimes.get(pkgName);
             if (componentResumeTimes == null) {
-                componentResumeTimes = new HashMap<String, Long>();
+                componentResumeTimes = new ArrayMap<String, Long>();
                 mLastResumeTimes.put(pkgName, componentResumeTimes);
             }
             componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
@@ -777,6 +809,25 @@
         }
     }
     
+    public void noteFullyDrawnTime(ComponentName componentName, int millis) {
+        enforceCallingPermission();
+        String pkgName;
+        if ((componentName == null) ||
+                ((pkgName = componentName.getPackageName()) == null)) {
+            return;
+        }
+
+        // Persist current data to file if needed.
+        writeStatsToFile(false, false);
+
+        synchronized (mStatsLock) {
+            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            if (pus != null) {
+                pus.addFullyDrawnTime(componentName.getClassName(), millis);
+            }
+        }
+    }
+
     public void enforceCallingPermission() {
         if (Binder.getCallingPid() == Process.myPid()) {
             return;
@@ -814,9 +865,8 @@
                 return null;
             }
             PkgUsageStats retArr[] = new PkgUsageStats[size];
-            int i = 0;
-            for (Map.Entry<String, Map<String, Long>> entry : mLastResumeTimes.entrySet()) {
-                String pkg = entry.getKey();
+            for (int i=0; i<size; i++) {
+                String pkg = mLastResumeTimes.keyAt(i);
                 long usageTime = 0;
                 int launchCount = 0;
 
@@ -825,8 +875,8 @@
                     usageTime = pus.mUsageTime;
                     launchCount = pus.mLaunchCount;
                 }
-                retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime, entry.getValue());
-                i++;
+                retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime,
+                        mLastResumeTimes.valueAt(i));
             }
             return retArr;
         }
@@ -866,6 +916,11 @@
             }
             File dFile = new File(mDir, file);
             String dateStr = file.substring(FILE_PREFIX.length());
+            if (dateStr.length() > 0 && (dateStr.charAt(0) <= '0' || dateStr.charAt(0) >= '9')) {
+                // If the remainder does not start with a number, it is not a date,
+                // so we should ignore it for purposes here.
+                continue;
+            }
             try {
                 Parcel in = getParcelForFile(dFile);
                 collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCompactOutput,
@@ -925,29 +980,33 @@
                 sb.append(',');
                 sb.append(pus.mUsageTime);
                 sb.append('\n');
-                final int NC = pus.mLaunchTimes.size();
-                if (NC > 0) {
-                    for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) {
-                        sb.append("A:");
-                        String activity = ent.getKey();
-                        if (activity.startsWith(pkgName)) {
-                            sb.append('*');
-                            sb.append(activity.substring(
-                                    pkgName.length(), activity.length()));
-                        } else {
-                            sb.append(activity);
-                        }
-                        TimeStats times = ent.getValue();
-                        sb.append(',');
-                        sb.append(times.count);
-                        for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
-                            sb.append(",");
-                            sb.append(times.times[i]);
-                        }
-                        sb.append('\n');
+                final int NLT = pus.mLaunchTimes.size();
+                for (int i=0; i<NLT; i++) {
+                    sb.append("A:");
+                    String activity = pus.mLaunchTimes.keyAt(i);
+                    sb.append(activity);
+                    TimeStats times = pus.mLaunchTimes.valueAt(i);
+                    sb.append(',');
+                    sb.append(times.count);
+                    for (int j=0; j<NUM_LAUNCH_TIME_BINS; j++) {
+                        sb.append(",");
+                        sb.append(times.times[j]);
                     }
+                    sb.append('\n');
                 }
-                
+                final int NFDT = pus.mFullyDrawnTimes.size();
+                for (int i=0; i<NFDT; i++) {
+                    sb.append("A:");
+                    String activity = pus.mFullyDrawnTimes.keyAt(i);
+                    sb.append(activity);
+                    TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
+                    for (int j=0; j<NUM_LAUNCH_TIME_BINS; j++) {
+                        sb.append(",");
+                        sb.append(times.times[j]);
+                    }
+                    sb.append('\n');
+                }
+
             } else {
                 sb.append("  ");
                 sb.append(pkgName);
@@ -957,36 +1016,68 @@
                 sb.append(pus.mUsageTime);
                 sb.append(" ms");
                 sb.append('\n');
-                final int NC = pus.mLaunchTimes.size();
-                if (NC > 0) {
-                    for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) {
-                        sb.append("    ");
-                        sb.append(ent.getKey());
-                        TimeStats times = ent.getValue();
-                        sb.append(": ");
-                        sb.append(times.count);
-                        sb.append(" starts");
-                        int lastBin = 0;
-                        for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
-                            if (times.times[i] != 0) {
-                                sb.append(", ");
-                                sb.append(lastBin);
-                                sb.append('-');
-                                sb.append(LAUNCH_TIME_BINS[i]);
-                                sb.append("ms=");
-                                sb.append(times.times[i]);
-                            }
-                            lastBin = LAUNCH_TIME_BINS[i];
-                        }
-                        if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+                final int NLT = pus.mLaunchTimes.size();
+                for (int i=0; i<NLT; i++) {
+                    sb.append("    ");
+                    sb.append(pus.mLaunchTimes.keyAt(i));
+                    TimeStats times = pus.mLaunchTimes.valueAt(i);
+                    sb.append(": ");
+                    sb.append(times.count);
+                    sb.append(" starts");
+                    int lastBin = 0;
+                    for (int j=0; j<NUM_LAUNCH_TIME_BINS-1; j++) {
+                        if (times.times[j] != 0) {
                             sb.append(", ");
-                            sb.append(">=");
                             sb.append(lastBin);
+                            sb.append('-');
+                            sb.append(LAUNCH_TIME_BINS[j]);
                             sb.append("ms=");
-                            sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+                            sb.append(times.times[j]);
                         }
-                        sb.append('\n');
+                        lastBin = LAUNCH_TIME_BINS[j];
                     }
+                    if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+                        sb.append(", ");
+                        sb.append(">=");
+                        sb.append(lastBin);
+                        sb.append("ms=");
+                        sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+                    }
+                    sb.append('\n');
+                }
+                final int NFDT = pus.mFullyDrawnTimes.size();
+                for (int i=0; i<NFDT; i++) {
+                    sb.append("    ");
+                    sb.append(pus.mFullyDrawnTimes.keyAt(i));
+                    TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
+                    sb.append(": fully drawn ");
+                    boolean needComma = false;
+                    int lastBin = 0;
+                    for (int j=0; j<NUM_LAUNCH_TIME_BINS-1; j++) {
+                        if (times.times[j] != 0) {
+                            if (needComma) {
+                                sb.append(", ");
+                            } else {
+                                needComma = true;
+                            }
+                            sb.append(lastBin);
+                            sb.append('-');
+                            sb.append(LAUNCH_TIME_BINS[j]);
+                            sb.append("ms=");
+                            sb.append(times.times[j]);
+                        }
+                        lastBin = LAUNCH_TIME_BINS[j];
+                    }
+                    if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+                        if (needComma) {
+                            sb.append(", ");
+                        }
+                        sb.append(">=");
+                        sb.append(lastBin);
+                        sb.append("ms=");
+                        sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+                    }
+                    sb.append('\n');
                 }
             }
             
diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/java/com/android/server/am/UserStartedState.java
index 0e71f81..d3e73d5 100644
--- a/services/java/com/android/server/am/UserStartedState.java
+++ b/services/java/com/android/server/am/UserStartedState.java
@@ -22,7 +22,7 @@
 import android.app.IStopUserCallback;
 import android.os.UserHandle;
 
-public class UserStartedState {
+public final class UserStartedState {
     // User is first coming up.
     public final static int STATE_BOOTING = 0;
     // User is in the normal running state.
diff --git a/services/java/com/android/server/connectivity/DataConnectionStats.java b/services/java/com/android/server/connectivity/DataConnectionStats.java
new file mode 100644
index 0000000..227ab23
--- /dev/null
+++ b/services/java/com/android/server/connectivity/DataConnectionStats.java
@@ -0,0 +1,154 @@
+/*
+ * 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.connectivity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.os.RemoteException;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.server.am.BatteryStatsService;
+
+public class DataConnectionStats extends BroadcastReceiver {
+    private static final String TAG = "DataConnectionStats";
+    private static final boolean DEBUG = false;
+
+    private final Context mContext;
+    private final IBatteryStats mBatteryStats;
+
+    private IccCardConstants.State mSimState = IccCardConstants.State.READY;
+    private SignalStrength mSignalStrength;
+    private ServiceState mServiceState;
+    private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+
+    public DataConnectionStats(Context context) {
+        mContext = context;
+        mBatteryStats = BatteryStatsService.getService();
+    }
+
+    public void startMonitoring() {
+        TelephonyManager phone =
+                (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        phone.listen(mPhoneStateListener,
+                PhoneStateListener.LISTEN_SERVICE_STATE
+              | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+              | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+              | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
+        mContext.registerReceiver(this, filter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+            updateSimState(intent);
+            notePhoneDataConnectionState();
+        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+                action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
+            notePhoneDataConnectionState();
+       }
+    }
+
+    private void notePhoneDataConnectionState() {
+        if (mServiceState == null) {
+            return;
+        }
+        boolean simReadyOrUnknown = mSimState == IccCardConstants.State.READY
+                || mSimState == IccCardConstants.State.UNKNOWN;
+        boolean visible = (simReadyOrUnknown || isCdma()) // we only check the sim state for GSM
+                && hasService()
+                && mDataState == TelephonyManager.DATA_CONNECTED;
+        int networkType = mServiceState.getDataNetworkType();
+        if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
+                networkType, visible ? "" : "not "));
+        try {
+            mBatteryStats.notePhoneDataConnectionState(networkType, visible);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error noting data connection state", e);
+        }
+    }
+
+    private final void updateSimState(Intent intent) {
+        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.ABSENT;
+        } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.READY;
+        } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+            final String lockedReason =
+                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                mSimState = IccCardConstants.State.PIN_REQUIRED;
+            } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                mSimState = IccCardConstants.State.PUK_REQUIRED;
+            } else {
+                mSimState = IccCardConstants.State.NETWORK_LOCKED;
+            }
+        } else {
+            mSimState = IccCardConstants.State.UNKNOWN;
+        }
+    }
+
+    private boolean isCdma() {
+        return mSignalStrength != null && !mSignalStrength.isGsm();
+    }
+
+    private boolean hasService() {
+        return mServiceState != null
+                && mServiceState.getState() != ServiceState.STATE_OUT_OF_SERVICE
+                && mServiceState.getState() != ServiceState.STATE_POWER_OFF;
+    }
+
+    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            mSignalStrength = signalStrength;
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            mServiceState = state;
+            notePhoneDataConnectionState();
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            mDataState = state;
+            notePhoneDataConnectionState();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            notePhoneDataConnectionState();
+        }
+    };
+}
diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/java/com/android/server/connectivity/PacManager.java
new file mode 100644
index 0000000..1cb2fe3
--- /dev/null
+++ b/services/java/com/android/server/connectivity/PacManager.java
@@ -0,0 +1,380 @@
+/**
+ * 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.connectivity;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.net.Proxy;
+import android.net.ProxyProperties;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.net.IProxyCallback;
+import com.android.net.IProxyPortListener;
+import com.android.net.IProxyService;
+import com.android.server.IoThread;
+
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * @hide
+ */
+public class PacManager {
+    public static final String PAC_PACKAGE = "com.android.pacprocessor";
+    public static final String PAC_SERVICE = "com.android.pacprocessor.PacService";
+    public static final String PAC_SERVICE_NAME = "com.android.net.IProxyService";
+
+    public static final String PROXY_PACKAGE = "com.android.proxyhandler";
+    public static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";
+
+    private static final String TAG = "PacManager";
+
+    private static final String ACTION_PAC_REFRESH = "android.net.proxy.PAC_REFRESH";
+
+    private static final String DEFAULT_DELAYS = "8 32 120 14400 43200";
+    private static final int DELAY_1 = 0;
+    private static final int DELAY_4 = 3;
+    private static final int DELAY_LONG = 4;
+
+    /** Keep these values up-to-date with ProxyService.java */
+    public static final String KEY_PROXY = "keyProxy";
+    private String mCurrentPac;
+    @GuardedBy("mProxyLock")
+    private String mPacUrl;
+
+    private AlarmManager mAlarmManager;
+    @GuardedBy("mProxyLock")
+    private IProxyService mProxyService;
+    private PendingIntent mPacRefreshIntent;
+    private ServiceConnection mConnection;
+    private ServiceConnection mProxyConnection;
+    private Context mContext;
+
+    private int mCurrentDelay;
+    private int mLastPort;
+
+    private boolean mHasSentBroadcast;
+    private boolean mHasDownloaded;
+
+    /**
+     * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac.
+     */
+    private final Object mProxyLock = new Object();
+
+    private Runnable mPacDownloader = new Runnable() {
+        @Override
+        public void run() {
+            String file;
+            synchronized (mProxyLock) {
+                if (mPacUrl == null) return;
+                try {
+                    file = get(mPacUrl);
+                } catch (IOException ioe) {
+                    file = null;
+                    Log.w(TAG, "Failed to load PAC file: " + ioe);
+                }
+            }
+            if (file != null) {
+                synchronized (mProxyLock) {
+                    if (!file.equals(mCurrentPac)) {
+                        setCurrentProxyScript(file);
+                    }
+                }
+                mHasDownloaded = true;
+                sendProxyIfNeeded();
+                longSchedule();
+            } else {
+                reschedule();
+            }
+        }
+    };
+
+    class PacRefreshIntentReceiver extends BroadcastReceiver {
+        public void onReceive(Context context, Intent intent) {
+            IoThread.getHandler().post(mPacDownloader);
+        }
+    }
+
+    public PacManager(Context context) {
+        mContext = context;
+        mLastPort = -1;
+
+        mPacRefreshIntent = PendingIntent.getBroadcast(
+                context, 0, new Intent(ACTION_PAC_REFRESH), 0);
+        context.registerReceiver(new PacRefreshIntentReceiver(),
+                new IntentFilter(ACTION_PAC_REFRESH));
+    }
+
+    private AlarmManager getAlarmManager() {
+        if (mAlarmManager == null) {
+            mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        }
+        return mAlarmManager;
+    }
+
+    /**
+     * Updates the PAC Manager with current Proxy information. This is called by
+     * the ConnectivityService directly before a broadcast takes place to allow
+     * the PacManager to indicate that the broadcast should not be sent and the
+     * PacManager will trigger a new broadcast when it is ready.
+     *
+     * @param proxy Proxy information that is about to be broadcast.
+     * @return Returns true when the broadcast should not be sent
+     */
+    public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
+        if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
+            synchronized (mProxyLock) {
+                mPacUrl = proxy.getPacFileUrl();
+            }
+            mCurrentDelay = DELAY_1;
+            mHasSentBroadcast = false;
+            mHasDownloaded = false;
+            getAlarmManager().cancel(mPacRefreshIntent);
+            bind();
+            return true;
+        } else {
+            getAlarmManager().cancel(mPacRefreshIntent);
+            synchronized (mProxyLock) {
+                mPacUrl = null;
+                mCurrentPac = null;
+                if (mProxyService != null) {
+                    try {
+                        mProxyService.stopPacSystem();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to stop PAC service", e);
+                    } finally {
+                        unbind();
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Does a post and reports back the status code.
+     *
+     * @throws IOException
+     */
+    private static String get(String urlString) throws IOException {
+        URL url = new URL(urlString);
+        URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+        return new String(Streams.readFully(urlConnection.getInputStream()));
+    }
+
+    private int getNextDelay(int currentDelay) {
+       if (++currentDelay > DELAY_4) {
+           return DELAY_4;
+       }
+       return currentDelay;
+    }
+
+    private void longSchedule() {
+        mCurrentDelay = DELAY_1;
+        setDownloadIn(DELAY_LONG);
+    }
+
+    private void reschedule() {
+        mCurrentDelay = getNextDelay(mCurrentDelay);
+        setDownloadIn(mCurrentDelay);
+    }
+
+    private String getPacChangeDelay() {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        /** Check system properties for the default value then use secure settings value, if any. */
+        String defaultDelay = SystemProperties.get(
+                "conn." + Settings.Global.PAC_CHANGE_DELAY,
+                DEFAULT_DELAYS);
+        String val = Settings.Global.getString(cr, Settings.Global.PAC_CHANGE_DELAY);
+        return (val == null) ? defaultDelay : val;
+    }
+
+    private long getDownloadDelay(int delayIndex) {
+        String[] list = getPacChangeDelay().split(" ");
+        if (delayIndex < list.length) {
+            return Long.parseLong(list[delayIndex]);
+        }
+        return 0;
+    }
+
+    private void setDownloadIn(int delayIndex) {
+        long delay = getDownloadDelay(delayIndex);
+        long timeTillTrigger = 1000 * delay + SystemClock.elapsedRealtime();
+        getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
+    }
+
+    private boolean setCurrentProxyScript(String script) {
+        if (mProxyService == null) {
+            Log.e(TAG, "setCurrentProxyScript: no proxy service");
+            return false;
+        }
+        try {
+            mProxyService.setPacFile(script);
+            mCurrentPac = script;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to set PAC file", e);
+        }
+        return true;
+    }
+
+    private void bind() {
+        if (mContext == null) {
+            Log.e(TAG, "No context for binding");
+            return;
+        }
+        Intent intent = new Intent();
+        intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
+        // Already bound no need to bind again.
+        if ((mProxyConnection != null) && (mConnection != null)) {
+            if (mLastPort != -1) {
+                sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+            } else {
+                Log.e(TAG, "Received invalid port from Local Proxy,"
+                        + " PAC will not be operational");
+            }
+            return;
+        }
+        mConnection = new ServiceConnection() {
+            @Override
+            public void onServiceDisconnected(ComponentName component) {
+                synchronized (mProxyLock) {
+                    mProxyService = null;
+                }
+            }
+
+            @Override
+            public void onServiceConnected(ComponentName component, IBinder binder) {
+                synchronized (mProxyLock) {
+                    try {
+                        Log.d(TAG, "Adding service " + PAC_SERVICE_NAME + " "
+                                + binder.getInterfaceDescriptor());
+                    } catch (RemoteException e1) {
+                        Log.e(TAG, "Remote Exception", e1);
+                    }
+                    ServiceManager.addService(PAC_SERVICE_NAME, binder);
+                    mProxyService = IProxyService.Stub.asInterface(binder);
+                    if (mProxyService == null) {
+                        Log.e(TAG, "No proxy service");
+                    } else {
+                        try {
+                            mProxyService.startPacSystem();
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e);
+                        }
+                        IoThread.getHandler().post(mPacDownloader);
+                    }
+                }
+            }
+        };
+        mContext.bindService(intent, mConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE);
+
+        intent = new Intent();
+        intent.setClassName(PROXY_PACKAGE, PROXY_SERVICE);
+        mProxyConnection = new ServiceConnection() {
+            @Override
+            public void onServiceDisconnected(ComponentName component) {
+            }
+
+            @Override
+            public void onServiceConnected(ComponentName component, IBinder binder) {
+                IProxyCallback callbackService = IProxyCallback.Stub.asInterface(binder);
+                if (callbackService != null) {
+                    try {
+                        callbackService.getProxyPort(new IProxyPortListener.Stub() {
+                            @Override
+                            public void setProxyPort(int port) throws RemoteException {
+                                if (mLastPort != -1) {
+                                    // Always need to send if port changed
+                                    mHasSentBroadcast = false;
+                                }
+                                mLastPort = port;
+                                if (port != -1) {
+                                    Log.d(TAG, "Local proxy is bound on " + port);
+                                    sendProxyIfNeeded();
+                                } else {
+                                    Log.e(TAG, "Received invalid port from Local Proxy,"
+                                            + " PAC will not be operational");
+                                }
+                            }
+                        });
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        };
+        mContext.bindService(intent, mProxyConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE);
+    }
+
+    private void unbind() {
+        if (mConnection != null) {
+            mContext.unbindService(mConnection);
+            mConnection = null;
+        }
+        if (mProxyConnection != null) {
+            mContext.unbindService(mProxyConnection);
+            mProxyConnection = null;
+        }
+        mProxyService = null;
+        mLastPort = -1;
+    }
+
+    private void sendPacBroadcast(ProxyProperties proxy) {
+        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private synchronized void sendProxyIfNeeded() {
+        if (!mHasDownloaded || (mLastPort == -1)) {
+            return;
+        }
+        if (!mHasSentBroadcast) {
+            sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+            mHasSentBroadcast = true;
+        }
+    }
+}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b83d885..231a40a 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -37,13 +37,10 @@
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.os.Binder;
-import android.os.HandlerThread;
-import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
@@ -53,6 +50,7 @@
 import com.android.internal.util.IState;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.server.IoThread;
 import com.google.android.collect.Lists;
 
 import java.io.FileDescriptor;
@@ -100,7 +98,6 @@
     private final INetworkStatsService mStatsService;
     private final IConnectivityManager mConnService;
     private Looper mLooper;
-    private HandlerThread mThread;
 
     private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
 
@@ -147,9 +144,7 @@
         mIfaces = new HashMap<String, TetherInterfaceSM>();
 
         // make our own thread so we don't anr the system
-        mThread = new HandlerThread("Tethering");
-        mThread.start();
-        mLooper = mThread.getLooper();
+        mLooper = IoThread.get().getLooper();
         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
         mTetherMasterSM.start();
 
@@ -320,6 +315,10 @@
         }
     }
 
+    public void addressUpdated(String address, String iface, int flags, int scope) {}
+
+    public void addressRemoved(String address, String iface, int flags, int scope) {}
+
     public void limitReached(String limitName, String iface) {}
 
     public void interfaceClassDataActivityChanged(String label, boolean active) {}
@@ -689,19 +688,6 @@
         return retVal;
     }
 
-    public String[] getTetheredIfacePairs() {
-        final ArrayList<String> list = Lists.newArrayList();
-        synchronized (mPublicSync) {
-            for (TetherInterfaceSM sm : mIfaces.values()) {
-                if (sm.isTethered()) {
-                    list.add(sm.mMyUpstreamIfaceName);
-                    list.add(sm.mIfaceName);
-                }
-            }
-        }
-        return list.toArray(new String[list.size()]);
-    }
-
     public String[] getTetherableIfaces() {
         ArrayList<String> list = new ArrayList<String>();
         synchronized (mPublicSync) {
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 63d3958..45797b2 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.BIND_VPN_SERVICE;
 
+import android.app.AppGlobals;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -28,8 +29,10 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
@@ -37,6 +40,7 @@
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
@@ -54,11 +58,14 @@
 import android.os.SystemClock;
 import android.os.SystemService;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.util.Log;
+import android.util.SparseBooleanArray;
 import android.widget.Toast;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.R;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
@@ -74,6 +81,7 @@
 import java.net.InetAddress;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import libcore.io.IoUtils;
@@ -98,20 +106,53 @@
     private volatile boolean mEnableNotif = true;
     private volatile boolean mEnableTeardown = true;
     private final IConnectivityManager mConnService;
+    private VpnConfig mConfig;
+
+    /* list of users using this VPN. */
+    @GuardedBy("this")
+    private SparseBooleanArray mVpnUsers = null;
+    private BroadcastReceiver mUserIntentReceiver = null;
+
+    private final int mUserId;
 
     public Vpn(Context context, VpnCallback callback, INetworkManagementService netService,
-            IConnectivityManager connService) {
+            IConnectivityManager connService, int userId) {
         // TODO: create dedicated TYPE_VPN network type
         super(ConnectivityManager.TYPE_DUMMY);
         mContext = context;
         mCallback = callback;
         mConnService = connService;
+        mUserId = userId;
 
         try {
             netService.registerObserver(mObserver);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Problem registering observer", e);
         }
+        if (userId == UserHandle.USER_OWNER) {
+            // Owner's VPN also needs to handle restricted users
+            mUserIntentReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final String action = intent.getAction();
+                    final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                            UserHandle.USER_NULL);
+                    if (userId == UserHandle.USER_NULL) return;
+
+                    if (Intent.ACTION_USER_ADDED.equals(action)) {
+                        onUserAdded(userId);
+                    } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                        onUserRemoved(userId);
+                    }
+                }
+            };
+
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(Intent.ACTION_USER_ADDED);
+            intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+            mContext.registerReceiverAsUser(
+                    mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+        }
     }
 
     /**
@@ -197,15 +238,23 @@
 
         // Reset the interface and hide the notification.
         if (mInterface != null) {
-            jniReset(mInterface);
             final long token = Binder.clearCallingIdentity();
             try {
                 mCallback.restore();
-                hideNotification();
+                final int size = mVpnUsers.size();
+                for (int i = 0; i < size; i++) {
+                    int user = mVpnUsers.keyAt(i);
+                    mCallback.clearUserForwarding(mInterface, user);
+                    hideNotification(user);
+                }
+
+                mCallback.clearMarkedForwarding(mInterface);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
+            jniReset(mInterface);
             mInterface = null;
+            mVpnUsers = null;
         }
 
         // Revoke the connection or stop LegacyVpnRunner.
@@ -225,6 +274,7 @@
 
         Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
         mPackage = newPackage;
+        mConfig = null;
         updateState(DetailedState.IDLE, "prepare");
         return true;
     }
@@ -237,12 +287,22 @@
      * @param interfaze The name of the interface.
      */
     public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
+
         PackageManager pm = mContext.getPackageManager();
-        ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
-        if (Binder.getCallingUid() != app.uid) {
+        int appUid = pm.getPackageUid(mPackage, mUserId);
+        if (Binder.getCallingUid() != appUid) {
             throw new SecurityException("Unauthorized Caller");
         }
+        // protect the socket from routing rules
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mCallback.protect(socket);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        // bind the socket to the interface
         jniProtect(socket.getFd(), interfaze);
+
     }
 
     /**
@@ -255,44 +315,40 @@
      */
     public synchronized ParcelFileDescriptor establish(VpnConfig config) {
         // Check if the caller is already prepared.
+        UserManager mgr = UserManager.get(mContext);
         PackageManager pm = mContext.getPackageManager();
         ApplicationInfo app = null;
         try {
-            app = pm.getApplicationInfo(mPackage, 0);
+            app = AppGlobals.getPackageManager().getApplicationInfo(mPackage, 0, mUserId);
+            if (Binder.getCallingUid() != app.uid) {
+                return null;
+            }
         } catch (Exception e) {
             return null;
         }
-        if (Binder.getCallingUid() != app.uid) {
-            return null;
-        }
-
         // Check if the service is properly declared.
         Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
         intent.setClassName(mPackage, config.user);
-        ResolveInfo info = pm.resolveService(intent, 0);
-        if (info == null) {
-            throw new SecurityException("Cannot find " + config.user);
-        }
-        if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
-            throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
-        }
+        long token = Binder.clearCallingIdentity();
+        try {
+            // Restricted users are not allowed to create VPNs, they are tied to Owner
+            UserInfo user = mgr.getUserInfo(mUserId);
+            if (user.isRestricted()) {
+                throw new SecurityException("Restricted users cannot establish VPNs");
+            }
 
-        // Load the label.
-        String label = app.loadLabel(pm).toString();
-
-        // Load the icon and convert it into a bitmap.
-        Drawable icon = app.loadIcon(pm);
-        Bitmap bitmap = null;
-        if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
-            int width = mContext.getResources().getDimensionPixelSize(
-                    android.R.dimen.notification_large_icon_width);
-            int height = mContext.getResources().getDimensionPixelSize(
-                    android.R.dimen.notification_large_icon_height);
-            icon.setBounds(0, 0, width, height);
-            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(bitmap);
-            icon.draw(c);
-            c.setBitmap(null);
+            ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
+                                                                        null, 0, mUserId);
+            if (info == null) {
+                throw new SecurityException("Cannot find " + config.user);
+            }
+            if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
+                throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
+            }
+        } catch (RemoteException e) {
+                throw new SecurityException("Cannot find " + config.user);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
 
         // Configure the interface. Abort if any of these steps fails.
@@ -300,14 +356,18 @@
         try {
             updateState(DetailedState.CONNECTING, "establish");
             String interfaze = jniGetName(tun.getFd());
-            if (jniSetAddresses(interfaze, config.addresses) < 1) {
+
+            // TEMP use the old jni calls until there is support for netd address setting
+            StringBuilder builder = new StringBuilder();
+            for (LinkAddress address : config.addresses) {
+                builder.append(" " + address);
+            }
+            if (jniSetAddresses(interfaze, builder.toString()) < 1) {
                 throw new IllegalArgumentException("At least one address must be specified");
             }
-            if (config.routes != null) {
-                jniSetRoutes(interfaze, config.routes);
-            }
             Connection connection = new Connection();
-            if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
+            if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
+                        new UserHandle(mUserId))) {
                 throw new IllegalStateException("Cannot bind " + config.user);
             }
             if (mConnection != null) {
@@ -318,30 +378,155 @@
             }
             mConnection = connection;
             mInterface = interfaze;
+
+            // Fill more values.
+            config.user = mPackage;
+            config.interfaze = mInterface;
+            config.startTime = SystemClock.elapsedRealtime();
+            mConfig = config;
+            // Set up forwarding and DNS rules.
+            mVpnUsers = new SparseBooleanArray();
+            token = Binder.clearCallingIdentity();
+            try {
+                mCallback.setMarkedForwarding(mInterface);
+                mCallback.setRoutes(interfaze, config.routes);
+                mCallback.override(mInterface, config.dnsServers, config.searchDomains);
+                addVpnUserLocked(mUserId);
+
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
         } catch (RuntimeException e) {
             updateState(DetailedState.FAILED, "establish");
             IoUtils.closeQuietly(tun);
+            // make sure marked forwarding is cleared if it was set
+            try {
+                mCallback.clearMarkedForwarding(mInterface);
+            } catch (Exception ingored) {
+                // ignored
+            }
             throw e;
         }
         Log.i(TAG, "Established by " + config.user + " on " + mInterface);
 
-        // Fill more values.
-        config.user = mPackage;
-        config.interfaze = mInterface;
 
-        // Override DNS servers and show the notification.
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mCallback.override(config.dnsServers, config.searchDomains);
-            showNotification(config, label, bitmap);
-        } finally {
-            Binder.restoreCallingIdentity(token);
+        // If we are owner assign all Restricted Users to this VPN
+        if (mUserId == UserHandle.USER_OWNER) {
+            token = Binder.clearCallingIdentity();
+            try {
+                for (UserInfo user : mgr.getUsers()) {
+                    if (user.isRestricted()) {
+                        try {
+                            addVpnUserLocked(user.id);
+                        } catch (Exception e) {
+                            Log.wtf(TAG, "Failed to add user " + user.id + " to owner's VPN");
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
         // TODO: ensure that contract class eventually marks as connected
         updateState(DetailedState.AUTHENTICATING, "establish");
         return tun;
     }
 
+    private boolean isRunningLocked() {
+        return mVpnUsers != null;
+    }
+
+    private void addVpnUserLocked(int user) {
+        enforceControlPermission();
+
+        if (!isRunningLocked()) {
+            throw new IllegalStateException("VPN is not active");
+        }
+        // add the user
+        mCallback.addUserForwarding(mInterface, user);
+        mVpnUsers.put(user, true);
+
+        // show the notification
+        if (!mPackage.equals(VpnConfig.LEGACY_VPN)) {
+            // Load everything for the user's notification
+            PackageManager pm = mContext.getPackageManager();
+            ApplicationInfo app = null;
+            try {
+                app = AppGlobals.getPackageManager().getApplicationInfo(mPackage, 0, mUserId);
+            } catch (RemoteException e) {
+                throw new IllegalStateException("Invalid application");
+            }
+            String label = app.loadLabel(pm).toString();
+            // Load the icon and convert it into a bitmap.
+            Drawable icon = app.loadIcon(pm);
+            Bitmap bitmap = null;
+            if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
+                int width = mContext.getResources().getDimensionPixelSize(
+                        android.R.dimen.notification_large_icon_width);
+                int height = mContext.getResources().getDimensionPixelSize(
+                        android.R.dimen.notification_large_icon_height);
+                icon.setBounds(0, 0, width, height);
+                bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+                Canvas c = new Canvas(bitmap);
+                icon.draw(c);
+                c.setBitmap(null);
+            }
+            showNotification(label, bitmap, user);
+        } else {
+            showNotification(null, null, user);
+        }
+    }
+
+    private void removeVpnUserLocked(int user) {
+            enforceControlPermission();
+
+            if (!isRunningLocked()) {
+                throw new IllegalStateException("VPN is not active");
+            }
+            mCallback.clearUserForwarding(mInterface, user);
+            mVpnUsers.delete(user);
+            hideNotification(user);
+    }
+
+    private void onUserAdded(int userId) {
+        // If the user is restricted tie them to the owner's VPN
+        synchronized(Vpn.this) {
+            UserManager mgr = UserManager.get(mContext);
+            UserInfo user = mgr.getUserInfo(userId);
+            if (user.isRestricted()) {
+                try {
+                    addVpnUserLocked(userId);
+                } catch (Exception e) {
+                    Log.wtf(TAG, "Failed to add restricted user to owner", e);
+                }
+            }
+        }
+    }
+
+    private void onUserRemoved(int userId) {
+        // clean up if restricted
+        synchronized(Vpn.this) {
+            UserManager mgr = UserManager.get(mContext);
+            UserInfo user = mgr.getUserInfo(userId);
+            if (user.isRestricted()) {
+                try {
+                    removeVpnUserLocked(userId);
+                } catch (Exception e) {
+                    Log.wtf(TAG, "Failed to remove restricted user to owner", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the configuration of the currently running VPN.
+     */
+    public VpnConfig getVpnConfig() {
+        enforceControlPermission();
+        return mConfig;
+    }
+
     @Deprecated
     public synchronized void interfaceStatusChanged(String iface, boolean up) {
         try {
@@ -367,8 +552,16 @@
                 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
                     final long token = Binder.clearCallingIdentity();
                     try {
+                        final int size = mVpnUsers.size();
+                        for (int i = 0; i < size; i++) {
+                            int user = mVpnUsers.keyAt(i);
+                            mCallback.clearUserForwarding(mInterface, user);
+                            hideNotification(user);
+                        }
+                        mVpnUsers = null;
+                        mCallback.clearMarkedForwarding(mInterface);
+
                         mCallback.restore();
-                        hideNotification();
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
@@ -391,16 +584,19 @@
         if (Binder.getCallingUid() == Process.SYSTEM_UID) {
             return;
         }
-
+        int appId = UserHandle.getAppId(Binder.getCallingUid());
+        final long token = Binder.clearCallingIdentity();
         try {
             // System dialogs are also allowed to control VPN.
             PackageManager pm = mContext.getPackageManager();
             ApplicationInfo app = pm.getApplicationInfo(VpnConfig.DIALOGS_PACKAGE, 0);
-            if (Binder.getCallingUid() == app.uid) {
+            if (appId == app.uid) {
                 return;
             }
         } catch (Exception e) {
             // ignore
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
 
         throw new SecurityException("Unauthorized Caller");
@@ -420,9 +616,9 @@
         }
     }
 
-    private void showNotification(VpnConfig config, String label, Bitmap icon) {
+    private void showNotification(String label, Bitmap icon, int user) {
         if (!mEnableNotif) return;
-        mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext, config);
+        mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
 
         NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -430,9 +626,8 @@
         if (nm != null) {
             String title = (label == null) ? mContext.getString(R.string.vpn_title) :
                     mContext.getString(R.string.vpn_title_long, label);
-            String text = (config.session == null) ? mContext.getString(R.string.vpn_text) :
-                    mContext.getString(R.string.vpn_text_long, config.session);
-            config.startTime = SystemClock.elapsedRealtime();
+            String text = (mConfig.session == null) ? mContext.getString(R.string.vpn_text) :
+                    mContext.getString(R.string.vpn_text_long, mConfig.session);
 
             Notification notification = new Notification.Builder(mContext)
                     .setSmallIcon(R.drawable.vpn_connected)
@@ -443,11 +638,11 @@
                     .setDefaults(0)
                     .setOngoing(true)
                     .build();
-            nm.notifyAsUser(null, R.drawable.vpn_connected, notification, UserHandle.ALL);
+            nm.notifyAsUser(null, R.drawable.vpn_connected, notification, new UserHandle(user));
         }
     }
 
-    private void hideNotification() {
+    private void hideNotification(int user) {
         if (!mEnableNotif) return;
         mStatusIntent = null;
 
@@ -455,7 +650,7 @@
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
         if (nm != null) {
-            nm.cancelAsUser(null, R.drawable.vpn_connected, UserHandle.ALL);
+            nm.cancelAsUser(null, R.drawable.vpn_connected, new UserHandle(user));
         }
     }
 
@@ -577,7 +772,8 @@
         config.user = profile.key;
         config.interfaze = iface;
         config.session = profile.name;
-        config.routes = profile.routes;
+
+        config.addLegacyRoutes(profile.routes);
         if (!profile.dnsServers.isEmpty()) {
             config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
         }
@@ -620,7 +816,7 @@
         if (mLegacyVpnRunner == null) return null;
 
         final LegacyVpnInfo info = new LegacyVpnInfo();
-        info.key = mLegacyVpnRunner.mConfig.user;
+        info.key = mConfig.user;
         info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
         if (mNetworkInfo.isConnected()) {
             info.intent = mStatusIntent;
@@ -630,7 +826,7 @@
 
     public VpnConfig getLegacyVpnConfig() {
         if (mLegacyVpnRunner != null) {
-            return mLegacyVpnRunner.mConfig;
+            return mConfig;
         } else {
             return null;
         }
@@ -646,7 +842,6 @@
     private class LegacyVpnRunner extends Thread {
         private static final String TAG = "LegacyVpnRunner";
 
-        private final VpnConfig mConfig;
         private final String[] mDaemons;
         private final String[][] mArguments;
         private final LocalSocket[] mSockets;
@@ -691,7 +886,7 @@
             // mConfig.interfaze will change to point to OUR
             // internal interface soon. TODO - add inner/outer to mconfig
             // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
-            // we will leave the VPN up.  We should check that it's still there/connected after 
+            // we will leave the VPN up.  We should check that it's still there/connected after
             // registering
             mOuterInterface = mConfig.interfaze;
 
@@ -867,11 +1062,11 @@
 
                 // Set the interface and the addresses in the config.
                 mConfig.interfaze = parameters[0].trim();
-                mConfig.addresses = parameters[1].trim();
 
+                mConfig.addLegacyAddresses(parameters[1]);
                 // Set the routes if they are not set in the config.
                 if (mConfig.routes == null || mConfig.routes.isEmpty()) {
-                    mConfig.routes = parameters[2].trim();
+                    mConfig.addLegacyRoutes(parameters[2]);
                 }
 
                 // Set the DNS servers if they are not set in the config.
@@ -891,10 +1086,19 @@
                 }
 
                 // Set the routes.
-                jniSetRoutes(mConfig.interfaze, mConfig.routes);
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mCallback.setMarkedForwarding(mConfig.interfaze);
+                    mCallback.setRoutes(mConfig.interfaze, mConfig.routes);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
 
                 // Here is the last step and it must be done synchronously.
                 synchronized (Vpn.this) {
+                    // Set the start time
+                    mConfig.startTime = SystemClock.elapsedRealtime();
+
                     // Check if the thread is interrupted while we are waiting.
                     checkpoint(false);
 
@@ -905,14 +1109,44 @@
 
                     // Now INetworkManagementEventObserver is watching our back.
                     mInterface = mConfig.interfaze;
-                    mCallback.override(mConfig.dnsServers, mConfig.searchDomains);
-                    showNotification(mConfig, null, null);
+                    mVpnUsers = new SparseBooleanArray();
 
+                    token = Binder.clearCallingIdentity();
+                    try {
+                        mCallback.override(mInterface, mConfig.dnsServers, mConfig.searchDomains);
+                        addVpnUserLocked(mUserId);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+
+                    // Assign all restircted users to this VPN
+                    // (Legacy VPNs are Owner only)
+                    UserManager mgr = UserManager.get(mContext);
+                    token = Binder.clearCallingIdentity();
+                    try {
+                        for (UserInfo user : mgr.getUsers()) {
+                            if (user.isRestricted()) {
+                                try {
+                                    addVpnUserLocked(user.id);
+                                } catch (Exception e) {
+                                    Log.wtf(TAG, "Failed to add user " + user.id
+                                            + " to owner's VPN");
+                                }
+                            }
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
                     Log.i(TAG, "Connected!");
                     updateState(DetailedState.CONNECTED, "execute");
                 }
             } catch (Exception e) {
                 Log.i(TAG, "Aborting", e);
+                // make sure the routing is cleared
+                try {
+                    mCallback.clearMarkedForwarding(mConfig.interfaze);
+                } catch (Exception ignored) {
+                }
                 exit();
             } finally {
                 // Kill the daemons if they fail to stop.
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index f82cf01..885ec9f 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -26,6 +26,7 @@
 import android.content.PeriodicSync;
 import android.content.SyncAdapterType;
 import android.content.SyncInfo;
+import android.content.SyncRequest;
 import android.content.SyncStatusInfo;
 import android.database.IContentObserver;
 import android.database.sqlite.SQLiteException;
@@ -36,8 +37,10 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseIntArray;
 
@@ -61,6 +64,10 @@
     private final Object mSyncManagerLock = new Object();
 
     private SyncManager getSyncManager() {
+        if (SystemProperties.getBoolean("config.disable_network", false)) {
+            return null;
+        }
+
         synchronized(mSyncManagerLock) {
             try {
                 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
@@ -134,7 +141,7 @@
             // The content service only throws security exceptions, so let's
             // log all others.
             if (!(e instanceof SecurityException)) {
-                Log.e(TAG, "Content Service Crash", e);
+                Slog.wtf(TAG, "Content Service Crash", e);
             }
             throw e;
         }
@@ -307,6 +314,7 @@
         }
     }
 
+    @Override
     public void requestSync(Account account, String authority, Bundle extras) {
         ContentResolver.validateSyncExtrasBundle(extras);
         int userId = UserHandle.getCallingUserId();
@@ -318,7 +326,8 @@
         try {
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
-                syncManager.scheduleSync(account, userId, uId, authority, extras, 0 /* no delay */,
+                syncManager.scheduleSync(account, userId, uId, authority, extras,
+                        0 /* no delay */, 0 /* no delay */,
                         false /* onlyThoseWithUnkownSyncableState */);
             }
         } finally {
@@ -327,11 +336,70 @@
     }
 
     /**
+     * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
+     * either:
+     *   periodic OR one-off sync.
+     * and
+     *   anonymous OR provider sync.
+     * Depending on the request, we enqueue to suit in the SyncManager.
+     * @param request
+     */
+    @Override
+    public void sync(SyncRequest request) {
+        Bundle extras = request.getBundle();
+        ContentResolver.validateSyncExtrasBundle(extras);
+
+        long flextime = request.getSyncFlexTime();
+        long runAtTime = request.getSyncRunTime();
+        int userId = UserHandle.getCallingUserId();
+        int uId = Binder.getCallingUid();
+
+        // This makes it so that future permission checks will be in the context of this
+        // process rather than the caller's process. We will restore this before returning.
+        long identityToken = clearCallingIdentity();
+        try {
+            SyncManager syncManager = getSyncManager();
+            if (syncManager != null) {
+                if (request.hasAuthority()) {
+                    // Sync Adapter registered with the system - old API.
+                    final  Account account = request.getAccount();
+                    final String provider = request.getProvider();
+                    if (request.isPeriodic()) {
+                        mContext.enforceCallingOrSelfPermission(
+                                Manifest.permission.WRITE_SYNC_SETTINGS,
+                                "no permission to write the sync settings");
+                        if (runAtTime < 60) {
+                            Slog.w(TAG, "Requested poll frequency of " + runAtTime
+                                    + " seconds being rounded up to 60 seconds.");
+                            runAtTime = 60;
+                        }
+                        PeriodicSync syncToAdd =
+                                new PeriodicSync(account, provider, extras, runAtTime, flextime);
+                        getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
+                    } else {
+                        long beforeRuntimeMillis = (flextime) * 1000;
+                        long runtimeMillis = runAtTime * 1000;
+                        syncManager.scheduleSync(
+                                account, userId, uId, provider, extras,
+                                beforeRuntimeMillis, runtimeMillis,
+                                false /* onlyThoseWithUnknownSyncableState */);
+                    }
+                } else {
+                    Log.w(TAG, "Unrecognised sync parameters, doing nothing.");
+                }
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    /**
      * Clear all scheduled sync operations that match the uri and cancel the active sync
      * if they match the authority and account, if they are present.
      * @param account filter the pending and active syncs to cancel using this account
      * @param authority filter the pending and active syncs to cancel using this authority
      */
+    @Override
     public void cancelSync(Account account, String authority) {
         int userId = UserHandle.getCallingUserId();
 
@@ -353,6 +421,7 @@
      * Get information about the SyncAdapters that are known to the system.
      * @return an array of SyncAdapters that have registered with the system
      */
+    @Override
     public SyncAdapterType[] getSyncAdapterTypes() {
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
@@ -366,6 +435,7 @@
         }
     }
 
+    @Override
     public boolean getSyncAutomatically(Account account, String providerName) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
@@ -384,6 +454,7 @@
         return false;
     }
 
+    @Override
     public void setSyncAutomatically(Account account, String providerName, boolean sync) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
@@ -401,6 +472,10 @@
         }
     }
 
+    /**
+     * Old API. Schedule periodic sync with default flex time.
+     */
+    @Override
     public void addPeriodicSync(Account account, String authority, Bundle extras,
             long pollFrequency) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
@@ -415,13 +490,18 @@
 
         long identityToken = clearCallingIdentity();
         try {
-            getSyncManager().getSyncStorageEngine().addPeriodicSync(
-                    account, userId, authority, extras, pollFrequency);
+            // Add default flex time to this sync.
+            PeriodicSync syncToAdd =
+                    new PeriodicSync(account, authority, extras,
+                            pollFrequency,
+                            SyncStorageEngine.calculateDefaultFlexTime(pollFrequency));
+            getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    @Override
     public void removePeriodicSync(Account account, String authority, Bundle extras) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
@@ -429,13 +509,23 @@
 
         long identityToken = clearCallingIdentity();
         try {
-            getSyncManager().getSyncStorageEngine().removePeriodicSync(account, userId, authority,
-                    extras);
+            PeriodicSync syncToRemove = new PeriodicSync(account, authority, extras,
+                    0 /* Not read for removal */, 0 /* Not read for removal */);
+            getSyncManager().getSyncStorageEngine().removePeriodicSync(syncToRemove, userId);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    /**
+     * TODO: Implement.
+     * @param request Sync to remove.
+     */
+    public void removeSync(SyncRequest request) {
+
+    }
+
+    @Override
     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
@@ -468,6 +558,7 @@
         return -1;
     }
 
+    @Override
     public void setIsSyncable(Account account, String providerName, int syncable) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
@@ -485,6 +576,7 @@
         }
     }
 
+    @Override
     public boolean getMasterSyncAutomatically() {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
@@ -502,6 +594,7 @@
         return false;
     }
 
+    @Override
     public void setMasterSyncAutomatically(boolean flag) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index ff1281e..2ae7bc7 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -34,6 +34,7 @@
 import android.content.ISyncStatusObserver;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.PeriodicSync;
 import android.content.ServiceConnection;
 import android.content.SyncActivityTooManyDeletes;
 import android.content.SyncAdapterType;
@@ -53,12 +54,10 @@
 import android.net.NetworkInfo;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -74,18 +73,21 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.accounts.AccountManagerService;
+import com.android.server.content.SyncStorageEngine.AuthorityInfo;
 import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
 
 import java.io.FileDescriptor;
-import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -114,7 +116,7 @@
     private static final long MAX_TIME_PER_SYNC;
 
     static {
-        final boolean isLargeRAM = ActivityManager.isLargeRAM();
+        final boolean isLargeRAM = !ActivityManager.isLowRamDeviceStatic();
         int defaultMaxInitSyncs = isLargeRAM ? 5 : 2;
         int defaultMaxRegularSyncs = isLargeRAM ? 2 : 1;
         MAX_SIMULTANEOUS_INITIALIZATION_SYNCS =
@@ -191,6 +193,7 @@
 
     private BroadcastReceiver mStorageIntentReceiver =
             new BroadcastReceiver() {
+                @Override
                 public void onReceive(Context context, Intent intent) {
                     String action = intent.getAction();
                     if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
@@ -211,36 +214,39 @@
             };
 
     private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
             mSyncHandler.onBootCompleted();
         }
     };
 
     private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
             if (getConnectivityManager().getBackgroundDataSetting()) {
                 scheduleSync(null /* account */, UserHandle.USER_ALL,
                         SyncOperation.REASON_BACKGROUND_DATA_SETTINGS_CHANGED,
                         null /* authority */,
-                        new Bundle(), 0 /* delay */,
+                        new Bundle(), 0 /* delay */, 0 /* delay */,
                         false /* onlyThoseWithUnknownSyncableState */);
             }
         }
     };
 
     private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
             updateRunningAccounts();
 
             // Kick off sync for everyone, since this was a radical account change
             scheduleSync(null, UserHandle.USER_ALL, SyncOperation.REASON_ACCOUNTS_UPDATED, null,
-                    null, 0 /* no delay */, false);
+                    null, 0 /* no delay */, 0/* no delay */, false);
         }
     };
 
     private final PowerManager mPowerManager;
 
-    // Use this as a random offset to seed all periodic syncs
+    // Use this as a random offset to seed all periodic syncs.
     private int mSyncRandomOffsetMillis;
 
     private final UserManager mUserManager;
@@ -297,6 +303,7 @@
 
     private BroadcastReceiver mConnectivityIntentReceiver =
             new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
             final boolean wasConnected = mDataConnectionIsConnected;
 
@@ -308,7 +315,9 @@
                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
                         Log.v(TAG, "Reconnection detected: clearing all backoffs");
                     }
-                    mSyncStorageEngine.clearAllBackoffs(mSyncQueue);
+                    synchronized(mSyncQueue) {
+                        mSyncStorageEngine.clearAllBackoffsLocked(mSyncQueue);
+                    }
                 }
                 sendCheckAlarmsMessage();
             }
@@ -322,6 +331,7 @@
 
     private BroadcastReceiver mShutdownIntentReceiver =
             new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
             Log.w(TAG, "Writing sync state before shutdown...");
             getSyncStorageEngine().writeAllState();
@@ -372,19 +382,20 @@
         SyncStorageEngine.init(context);
         mSyncStorageEngine = SyncStorageEngine.getSingleton();
         mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
+            @Override
             public void onSyncRequest(Account account, int userId, int reason, String authority,
                     Bundle extras) {
-                scheduleSync(account, userId, reason, authority, extras, 0, false);
+                scheduleSync(account, userId, reason, authority, extras,
+                    0 /* no delay */,
+                    0 /* no delay */,
+                    false);
             }
         });
 
         mSyncAdapters = new SyncAdaptersCache(mContext);
         mSyncQueue = new SyncQueue(mContext.getPackageManager(), mSyncStorageEngine, mSyncAdapters);
 
-        HandlerThread syncThread = new HandlerThread("SyncHandlerThread",
-                Process.THREAD_PRIORITY_BACKGROUND);
-        syncThread.start();
-        mSyncHandler = new SyncHandler(syncThread.getLooper());
+        mSyncHandler = new SyncHandler(BackgroundThread.get().getLooper());
 
         mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
             @Override
@@ -392,7 +403,7 @@
                 if (!removed) {
                     scheduleSync(null, UserHandle.USER_ALL,
                             SyncOperation.REASON_SERVICE_CHANGED,
-                            type.authority, null, 0 /* no delay */,
+                            type.authority, null, 0 /* no delay */, 0 /* no delay */,
                             false /* onlyThoseWithUnkownSyncableState */);
                 }
             }
@@ -457,6 +468,7 @@
 
         mSyncStorageEngine.addStatusChangeListener(
                 ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {
+            @Override
             public void onStatusChanged(int which) {
                 // force the sync loop to run if the settings change
                 sendCheckAlarmsMessage();
@@ -566,22 +578,28 @@
      * @param extras a Map of SyncAdapter-specific information to control
      *          syncs of a specific provider. Can be null. Is ignored
      *          if the url is null.
-     * @param delay how many milliseconds in the future to wait before performing this
-     * @param onlyThoseWithUnkownSyncableState
+     * @param beforeRuntimeMillis milliseconds before runtimeMillis that this sync can run.
+     * @param runtimeMillis maximum milliseconds in the future to wait before performing sync.
+     * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
-            String requestedAuthority, Bundle extras, long delay,
-            boolean onlyThoseWithUnkownSyncableState) {
+            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
+            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
         boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
 
         final boolean backgroundDataUsageAllowed = !mBootCompleted ||
                 getConnectivityManager().getBackgroundDataSetting();
 
-        if (extras == null) extras = new Bundle();
-
+        if (extras == null) {
+            extras = new Bundle();
+        }
+        if (isLoggable) {
+            Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
+                    + requestedAuthority);
+        }
         Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
         if (expedited) {
-            delay = -1; // this means schedule at the front of the queue
+            runtimeMillis = -1; // this means schedule at the front of the queue
         }
 
         AccountAndUser[] accounts;
@@ -686,11 +704,13 @@
                         account.userId, authority);
                 final long backoffTime = backoff != null ? backoff.first : 0;
                 if (isSyncable < 0) {
+                    // Initialisation sync.
                     Bundle newExtras = new Bundle();
                     newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
                     if (isLoggable) {
-                        Log.v(TAG, "scheduleSync:"
-                                + " delay " + delay
+                        Log.v(TAG, "schedule initialisation Sync:"
+                                + ", delay until " + delayUntil
+                                + ", run by " + 0
                                 + ", source " + source
                                 + ", account " + account
                                 + ", authority " + authority
@@ -698,13 +718,15 @@
                     }
                     scheduleSyncOperation(
                             new SyncOperation(account.account, account.userId, reason, source,
-                                    authority, newExtras, 0, backoffTime, delayUntil,
-                                    allowParallelSyncs));
+                                    authority, newExtras, 0 /* immediate */, 0 /* No flex time*/,
+                                    backoffTime, delayUntil, allowParallelSyncs));
                 }
                 if (!onlyThoseWithUnkownSyncableState) {
                     if (isLoggable) {
                         Log.v(TAG, "scheduleSync:"
-                                + " delay " + delay
+                                + " delay until " + delayUntil
+                                + " run by " + runtimeMillis
+                                + " flex " + beforeRuntimeMillis
                                 + ", source " + source
                                 + ", account " + account
                                 + ", authority " + authority
@@ -712,17 +734,23 @@
                     }
                     scheduleSyncOperation(
                             new SyncOperation(account.account, account.userId, reason, source,
-                                    authority, extras, delay, backoffTime, delayUntil,
-                                    allowParallelSyncs));
+                                    authority, extras, runtimeMillis, beforeRuntimeMillis,
+                                    backoffTime, delayUntil, allowParallelSyncs));
                 }
             }
         }
     }
 
+    /**
+     * Schedule sync based on local changes to a provider. Occurs within interval
+     * [LOCAL_SYNC_DELAY, 2*LOCAL_SYNC_DELAY].
+     */
     public void scheduleLocalSync(Account account, int userId, int reason, String authority) {
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
-        scheduleSync(account, userId, reason, authority, extras, LOCAL_SYNC_DELAY,
+        scheduleSync(account, userId, reason, authority, extras,
+                LOCAL_SYNC_DELAY /* earliest run time */,
+                2 * LOCAL_SYNC_DELAY /* latest sync time. */,
                 false /* onlyThoseWithUnkownSyncableState */);
     }
 
@@ -779,6 +807,7 @@
     }
 
     class SyncAlarmIntentReceiver extends BroadcastReceiver {
+        @Override
         public void onReceive(Context context, Intent intent) {
             mHandleAlarmWakeLock.acquire();
             sendSyncAlarmMessage();
@@ -947,11 +976,13 @@
                 Log.d(TAG, "retrying sync operation that failed because there was already a "
                         + "sync in progress: " + operation);
             }
-            scheduleSyncOperation(new SyncOperation(operation.account, operation.userId,
+            scheduleSyncOperation(
+                new SyncOperation(
+                    operation.account, operation.userId,
                     operation.reason,
                     operation.syncSource,
                     operation.authority, operation.extras,
-                    DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000,
+                    DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000, operation.flexTime,
                     operation.backoff, operation.delayUntil, operation.allowParallelSyncs));
         } else if (syncResult.hasSoftError()) {
             if (isLoggable) {
@@ -981,7 +1012,8 @@
         final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
-                    0 /* no delay */, true /* onlyThoseWithUnknownSyncableState */);
+                    0 /* no delay */, 0 /* No flex */,
+                    true /* onlyThoseWithUnknownSyncableState */);
         }
 
         sendCheckAlarmsMessage();
@@ -1208,7 +1240,10 @@
         synchronized (mSyncQueue) {
             sb.setLength(0);
             mSyncQueue.dump(sb);
+            // Dump Pending Operations.
+            getSyncStorageEngine().dumpPendingOperations(sb);
         }
+
         pw.println();
         pw.print(sb.toString());
 
@@ -1253,10 +1288,11 @@
                     continue;
                 }
                 int row = table.getNumRows();
-                SyncStorageEngine.AuthorityInfo settings =
-                        mSyncStorageEngine.getOrCreateAuthority(
+                Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus = 
+                        mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
                                 account.account, account.userId, syncAdapterType.type.authority);
-                SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(settings);
+                SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
+                SyncStatusInfo status = syncAuthoritySyncStatus.second;
 
                 String authority = settings.authority;
                 if (authority.length() > 50) {
@@ -1274,12 +1310,15 @@
 
 
                 for (int i = 0; i < settings.periodicSyncs.size(); i++) {
-                    final Pair<Bundle, Long> pair = settings.periodicSyncs.get(0);
-                    final String period = String.valueOf(pair.second);
-                    final String extras = pair.first.size() > 0 ? pair.first.toString() : "";
-                    final String next = formatTime(status.getPeriodicSyncTime(0)
-                            + pair.second * 1000);
-                    table.set(row + i * 2, 12, period + extras);
+                    final PeriodicSync sync = settings.periodicSyncs.get(i);
+                    final String period =
+                            String.format("[p:%d s, f: %d s]", sync.period, sync.flexTime);
+                    final String extras =
+                            sync.extras.size() > 0 ?
+                                    sync.extras.toString() : "Bundle[]";
+                    final String next = "Next sync: " + formatTime(status.getPeriodicSyncTime(i)
+                            + sync.period * 1000);
+                    table.set(row + i * 2, 12, period + " " + extras);
                     table.set(row + i * 2 + 1, 12, next);
                 }
 
@@ -1746,16 +1785,20 @@
         public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
         private final HashMap<Pair<Account, String>, PowerManager.WakeLock> mWakeLocks =
                 Maps.newHashMap();
-
-        private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
+        private List<Message> mBootQueue = new ArrayList<Message>();
 
         public void onBootCompleted() {
-            mBootCompleted = true;
-
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Boot completed, clearing boot queue.");
+            }
             doDatabaseCleanup();
-
-            if (mReadyToRunLatch != null) {
-                mReadyToRunLatch.countDown();
+            synchronized(this) {
+                // Dispatch any stashed messages.
+                for (Message message : mBootQueue) {
+                    sendMessage(message);
+                }
+                mBootQueue = null;
+                mBootCompleted = true;
             }
         }
 
@@ -1763,7 +1806,8 @@
             final Pair<Account, String> wakeLockKey = Pair.create(account, authority);
             PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
             if (wakeLock == null) {
-                final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + account;
+                final String name = SYNC_WAKE_LOCK_PREFIX + "/" + authority + "/" + account.type
+                        + "/" + account.name;
                 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
                 wakeLock.setReferenceCounted(false);
                 mWakeLocks.put(wakeLockKey, wakeLock);
@@ -1771,20 +1815,24 @@
             return wakeLock;
         }
 
-        private void waitUntilReadyToRun() {
-            CountDownLatch latch = mReadyToRunLatch;
-            if (latch != null) {
-                while (true) {
-                    try {
-                        latch.await();
-                        mReadyToRunLatch = null;
-                        return;
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                    }
+        /**
+         * Stash any messages that come to the handler before boot is complete.
+         * {@link #onBootCompleted()} will disable this and dispatch all the messages collected.
+         * @param msg Message to dispatch at a later point.
+         * @return true if a message was enqueued, false otherwise. This is to avoid losing the
+         * message if we manage to acquire the lock but by the time we do boot has completed.
+         */
+        private boolean tryEnqueueMessageUntilReadyToRun(Message msg) {
+            synchronized (this) {
+                if (!mBootCompleted) {
+                    // Need to copy the message bc looper will recycle it.
+                    mBootQueue.add(Message.obtain(msg));
+                    return true;
                 }
+                return false;
             }
         }
+
         /**
          * Used to keep track of whether a sync notification is active and who it is for.
          */
@@ -1812,14 +1860,17 @@
             super(looper);
         }
 
+        @Override
         public void handleMessage(Message msg) {
+            if (tryEnqueueMessageUntilReadyToRun(msg)) {
+                return;
+            }
+
             long earliestFuturePollTime = Long.MAX_VALUE;
             long nextPendingSyncTime = Long.MAX_VALUE;
-
             // Setting the value here instead of a method because we want the dumpsys logs
             // to have the most recent value used.
             try {
-                waitUntilReadyToRun();
                 mDataConnectionIsConnected = readDataConnectionState();
                 mSyncManagerWakeLock.acquire();
                 // Always do this first so that we be sure that any periodic syncs that
@@ -1829,7 +1880,7 @@
                 earliestFuturePollTime = scheduleReadyPeriodicSyncs();
                 switch (msg.what) {
                     case SyncHandler.MESSAGE_CANCEL: {
-                        Pair<Account, String> payload = (Pair<Account, String>)msg.obj;
+                        Pair<Account, String> payload = (Pair<Account, String>) msg.obj;
                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CANCEL: "
                                     + payload.first + ", " + payload.second);
@@ -1936,6 +1987,10 @@
          * in milliseconds since boot
          */
         private long scheduleReadyPeriodicSyncs() {
+            final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+            if (isLoggable) {
+                Log.v(TAG, "scheduleReadyPeriodicSyncs");
+            }
             final boolean backgroundDataUsageAllowed =
                     getConnectivityManager().getBackgroundDataSetting();
             long earliestFuturePollTime = Long.MAX_VALUE;
@@ -1947,83 +2002,117 @@
 
             final long nowAbsolute = System.currentTimeMillis();
             final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
-                                               ? (nowAbsolute  - mSyncRandomOffsetMillis) : 0;
+                    ? (nowAbsolute - mSyncRandomOffsetMillis) : 0;
 
-            ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
-            for (SyncStorageEngine.AuthorityInfo info : infos) {
-                // skip the sync if the account of this operation no longer exists
-                if (!containsAccountAndUser(accounts, info.account, info.userId)) {
+            ArrayList<Pair<AuthorityInfo, SyncStatusInfo>> infos = mSyncStorageEngine
+                    .getCopyOfAllAuthoritiesWithSyncStatus();
+            for (Pair<AuthorityInfo, SyncStatusInfo> info : infos) {
+                final AuthorityInfo authorityInfo = info.first;
+                final SyncStatusInfo status = info.second;
+                // skip the sync if the account of this operation no longer
+                // exists
+                if (!containsAccountAndUser(
+                        accounts, authorityInfo.account, authorityInfo.userId)) {
                     continue;
                 }
 
-                if (!mSyncStorageEngine.getMasterSyncAutomatically(info.userId)
-                        || !mSyncStorageEngine.getSyncAutomatically(info.account, info.userId,
-                                info.authority)) {
+                if (!mSyncStorageEngine.getMasterSyncAutomatically(authorityInfo.userId)
+                        || !mSyncStorageEngine.getSyncAutomatically(
+                                authorityInfo.account, authorityInfo.userId,
+                                authorityInfo.authority)) {
                     continue;
                 }
 
-                if (getIsSyncable(info.account, info.userId, info.authority)
+                if (getIsSyncable(
+                        authorityInfo.account, authorityInfo.userId, authorityInfo.authority)
                         == 0) {
                     continue;
                 }
 
-                SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(info);
-                for (int i = 0, N = info.periodicSyncs.size(); i < N; i++) {
-                    final Bundle extras = info.periodicSyncs.get(i).first;
-                    final Long periodInMillis = info.periodicSyncs.get(i).second * 1000;
-                    // Skip if the period is invalid
+                for (int i = 0, N = authorityInfo.periodicSyncs.size(); i < N; i++) {
+                    final PeriodicSync sync = authorityInfo.periodicSyncs.get(i);
+                    final Bundle extras = sync.extras;
+                    final long periodInMillis = sync.period * 1000;
+                    final long flexInMillis = sync.flexTime * 1000;
+                    // Skip if the period is invalid.
                     if (periodInMillis <= 0) {
                         continue;
                     }
-                    // find when this periodic sync was last scheduled to run
+                    // Find when this periodic sync was last scheduled to run.
                     final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
-
                     long remainingMillis
-                            = periodInMillis - (shiftedNowAbsolute % periodInMillis);
-
+                        = periodInMillis - (shiftedNowAbsolute % periodInMillis);
+                    long timeSinceLastRunMillis
+                        = (nowAbsolute - lastPollTimeAbsolute);
+                    // Schedule this periodic sync to run early if it's close enough to its next
+                    // runtime, and far enough from its last run time.
+                    // If we are early, there will still be time remaining in this period.
+                    boolean runEarly = remainingMillis <= flexInMillis
+                            && timeSinceLastRunMillis > periodInMillis - flexInMillis;
+                    if (isLoggable) {
+                        Log.v(TAG, "sync: " + i + " for " + authorityInfo.authority + "."
+                        + " period: " + (periodInMillis)
+                        + " flex: " + (flexInMillis)
+                        + " remaining: " + (remainingMillis)
+                        + " time_since_last: " + timeSinceLastRunMillis
+                        + " last poll absol: " + lastPollTimeAbsolute
+                        + " shifted now: " + shiftedNowAbsolute
+                        + " run_early: " + runEarly);
+                    }
                     /*
-                     * Sync scheduling strategy:
-                     *    Set the next periodic sync based on a random offset (in seconds).
-                     *
-                     *    Also sync right now if any of the following cases hold
-                     *    and mark it as having been scheduled
-                     *
-                     * Case 1:  This sync is ready to run now.
-                     * Case 2:  If the lastPollTimeAbsolute is in the future,
-                     *          sync now and reinitialize. This can happen for
-                     *          example if the user changed the time, synced and
-                     *          changed back.
-                     * Case 3:  If we failed to sync at the last scheduled time
+                     * Sync scheduling strategy: Set the next periodic sync
+                     * based on a random offset (in seconds). Also sync right
+                     * now if any of the following cases hold and mark it as
+                     * having been scheduled
+                     * Case 1: This sync is ready to run now.
+                     * Case 2: If the lastPollTimeAbsolute is in the
+                     * future, sync now and reinitialize. This can happen for
+                     * example if the user changed the time, synced and changed
+                     * back.
+                     * Case 3: If we failed to sync at the last scheduled
+                     * time.
+                     * Case 4: This sync is close enough to the time that we can schedule it.
                      */
-                    if (remainingMillis == periodInMillis  // Case 1
+                    if (runEarly // Case 4
+                            || remainingMillis == periodInMillis // Case 1
                             || lastPollTimeAbsolute > nowAbsolute // Case 2
-                            || (nowAbsolute - lastPollTimeAbsolute
-                                    >= periodInMillis)) { // Case 3
+                            || timeSinceLastRunMillis >= periodInMillis) { // Case 3
                         // Sync now
+                        
                         final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
-                                info.account, info.userId, info.authority);
+                                authorityInfo.account, authorityInfo.userId,
+                                authorityInfo.authority);
                         final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
                         syncAdapterInfo = mSyncAdapters.getServiceInfo(
-                                SyncAdapterType.newKey(info.authority, info.account.type),
-                                info.userId);
+                                SyncAdapterType.newKey(
+                                        authorityInfo.authority, authorityInfo.account.type),
+                                authorityInfo.userId);
                         if (syncAdapterInfo == null) {
                             continue;
                         }
+                        mSyncStorageEngine.setPeriodicSyncTime(authorityInfo.ident,
+                                authorityInfo.periodicSyncs.get(i), nowAbsolute);
                         scheduleSyncOperation(
-                                new SyncOperation(info.account, info.userId,
+                                new SyncOperation(authorityInfo.account, authorityInfo.userId,
                                         SyncOperation.REASON_PERIODIC,
                                         SyncStorageEngine.SOURCE_PERIODIC,
-                                        info.authority, extras, 0 /* delay */,
-                                        backoff != null ? backoff.first : 0,
+                                        authorityInfo.authority, extras,
+                                        0 /* runtime */, 0 /* flex */,
+                                                backoff != null ? backoff.first : 0,
                                         mSyncStorageEngine.getDelayUntilTime(
-                                                info.account, info.userId, info.authority),
+                                                authorityInfo.account, authorityInfo.userId,
+                                                authorityInfo.authority),
                                         syncAdapterInfo.type.allowParallelSyncs()));
-                        status.setPeriodicSyncTime(i, nowAbsolute);
+                        
                     }
-                    // Compute when this periodic sync should next run
-                    final long nextPollTimeAbsolute = nowAbsolute + remainingMillis;
-
-                    // remember this time if it is earlier than earliestFuturePollTime
+                    // Compute when this periodic sync should next run.
+                    long nextPollTimeAbsolute;
+                    if (runEarly) {
+                        // Add the time remaining so we don't get out of phase.
+                        nextPollTimeAbsolute = nowAbsolute + periodInMillis + remainingMillis;
+                    } else {
+                        nextPollTimeAbsolute = nowAbsolute + remainingMillis;
+                    }
                     if (nextPollTimeAbsolute < earliestFuturePollTime) {
                         earliestFuturePollTime = nextPollTimeAbsolute;
                     }
@@ -2035,10 +2124,9 @@
             }
 
             // convert absolute time to elapsed time
-            return SystemClock.elapsedRealtime()
-                    + ((earliestFuturePollTime < nowAbsolute)
-                      ? 0
-                      : (earliestFuturePollTime - nowAbsolute));
+            return SystemClock.elapsedRealtime() +
+                ((earliestFuturePollTime < nowAbsolute) ?
+                    0 : (earliestFuturePollTime - nowAbsolute));
         }
 
         private long maybeStartNextSyncLocked() {
@@ -2088,8 +2176,8 @@
                     Log.v(TAG, "build the operation array, syncQueue size is "
                         + mSyncQueue.getOperations().size());
                 }
-                final Iterator<SyncOperation> operationIterator = mSyncQueue.getOperations()
-                        .iterator();
+                final Iterator<SyncOperation> operationIterator =
+                        mSyncQueue.getOperations().iterator();
 
                 final ActivityManager activityManager
                         = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -2097,40 +2185,61 @@
                 while (operationIterator.hasNext()) {
                     final SyncOperation op = operationIterator.next();
 
-                    // drop the sync if the account of this operation no longer exists
+                    // Drop the sync if the account of this operation no longer exists.
                     if (!containsAccountAndUser(accounts, op.account, op.userId)) {
                         operationIterator.remove();
                         mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+                        if (isLoggable) {
+                            Log.v(TAG, "    Dropping sync operation: account doesn't exist.");
+                        }
                         continue;
                     }
 
-                    // drop this sync request if it isn't syncable
+                    // Drop this sync request if it isn't syncable.
                     int syncableState = getIsSyncable(
                             op.account, op.userId, op.authority);
                     if (syncableState == 0) {
                         operationIterator.remove();
                         mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+                        if (isLoggable) {
+                            Log.v(TAG, "    Dropping sync operation: isSyncable == 0.");
+                        }
                         continue;
                     }
 
-                    // if the user in not running, drop the request
+                    // If the user is not running, drop the request.
                     if (!activityManager.isUserRunning(op.userId)) {
                         final UserInfo userInfo = mUserManager.getUserInfo(op.userId);
                         if (userInfo == null) {
                             removedUsers.add(op.userId);
                         }
-                        continue;
-                    }
-
-                    // if the next run time is in the future, meaning there are no syncs ready
-                    // to run, return the time
-                    if (op.effectiveRunTime > now) {
-                        if (nextReadyToRunTime > op.effectiveRunTime) {
-                            nextReadyToRunTime = op.effectiveRunTime;
+                        if (isLoggable) {
+                            Log.v(TAG, "    Dropping sync operation: user not running.");
                         }
                         continue;
                     }
 
+                    // If the next run time is in the future, even given the flexible scheduling,
+                    // return the time.
+                    if (op.effectiveRunTime - op.flexTime > now) {
+                        if (nextReadyToRunTime > op.effectiveRunTime) {
+                            nextReadyToRunTime = op.effectiveRunTime;
+                        }
+                        if (isLoggable) {
+                            Log.v(TAG, "    Dropping sync operation: Sync too far in future.");
+                        }
+                        continue;
+                    }
+
+                    // If the op isn't allowed on metered networks and we're on one, drop it.
+                    if (getConnectivityManager().isActiveNetworkMetered()
+                            && op.isMeteredDisallowed()) {
+                        operationIterator.remove();
+                        mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+                        continue;
+                    }
+
+                    // TODO: change this behaviour for non-registered syncs.
                     final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
                     syncAdapterInfo = mSyncAdapters.getServiceInfo(
                             SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
@@ -2171,7 +2280,7 @@
             }
 
             // find the next operation to dispatch, if one is ready
-            // iterate from the top, keep issuing (while potentially cancelling existing syncs)
+            // iterate from the top, keep issuing (while potentially canceling existing syncs)
             // until the quotas are filled.
             // once the quotas are filled iterate once more to find when the next one would be
             // (also considering pre-emption reasons).
@@ -2451,11 +2560,13 @@
             }
 
             if (syncResult != null && syncResult.fullSyncRequested) {
-                scheduleSyncOperation(new SyncOperation(syncOperation.account, syncOperation.userId,
-                        syncOperation.reason,
-                        syncOperation.syncSource, syncOperation.authority, new Bundle(), 0,
-                        syncOperation.backoff, syncOperation.delayUntil,
-                        syncOperation.allowParallelSyncs));
+                scheduleSyncOperation(
+                        new SyncOperation(syncOperation.account, syncOperation.userId,
+                            syncOperation.reason,
+                            syncOperation.syncSource, syncOperation.authority, new Bundle(),
+                            0 /* delay */, 0 /* flex */,
+                            syncOperation.backoff, syncOperation.delayUntil,
+                            syncOperation.allowParallelSyncs));
             }
             // no need to schedule an alarm, as that will be done by our caller.
         }
@@ -2625,9 +2736,12 @@
             // determine if we need to set or cancel the alarm
             boolean shouldSet = false;
             boolean shouldCancel = false;
-            final boolean alarmIsActive = mAlarmScheduleTime != null;
+            final boolean alarmIsActive = (mAlarmScheduleTime != null) && (now < mAlarmScheduleTime);
             final boolean needAlarm = alarmTime != Long.MAX_VALUE;
             if (needAlarm) {
+                // Need the alarm if
+                //  - it's currently not set
+                //  - if the alarm is set in the past.
                 if (!alarmIsActive || alarmTime < mAlarmScheduleTime) {
                     shouldSet = true;
                 }
@@ -2635,7 +2749,7 @@
                 shouldCancel = alarmIsActive;
             }
 
-            // set or cancel the alarm as directed
+            // Set or cancel the alarm as directed.
             ensureAlarmService();
             if (shouldSet) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2644,7 +2758,7 @@
                             + " secs from now");
                 }
                 mAlarmScheduleTime = alarmTime;
-                mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
+                mAlarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
                         mSyncAlarmIntent);
             } else if (shouldCancel) {
                 mAlarmScheduleTime = null;
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
index eaad982..48567478 100644
--- a/services/java/com/android/server/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -18,13 +18,18 @@
 
 import android.accounts.Account;
 import android.content.pm.PackageManager;
+import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.SyncRequest;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.util.Pair;
 
 /**
  * Value type that represents a sync operation.
- * @hide
+ * TODO: This is the class to flesh out with all the scheduling data - metered/unmetered,
+ * transfer-size, etc.
+ * {@hide}
  */
 public class SyncOperation implements Comparable {
     public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
@@ -32,7 +37,9 @@
     public static final int REASON_SERVICE_CHANGED = -3;
     public static final int REASON_PERIODIC = -4;
     public static final int REASON_IS_SYNCABLE = -5;
+    /** Sync started because it has just been set to sync automatically. */
     public static final int REASON_SYNC_AUTO = -6;
+    /** Sync started because master sync automatically has been set to true. */
     public static final int REASON_MASTER_SYNC_AUTO = -7;
     public static final int REASON_USER_START = -8;
 
@@ -47,75 +54,109 @@
             "UserStart",
     };
 
+    /** Account info to identify a SyncAdapter registered with the system. */
     public final Account account;
+    /** Authority info to identify a SyncAdapter registered with the system. */
+    public final String authority;
+    /** Service to which this operation will bind to perform the sync. */
+    public final ComponentName service;
     public final int userId;
     public final int reason;
     public int syncSource;
-    public String authority;
     public final boolean allowParallelSyncs;
     public Bundle extras;
     public final String key;
-    public long earliestRunTime;
     public boolean expedited;
     public SyncStorageEngine.PendingOperation pendingOperation;
+    /** Elapsed real time in millis at which to run this sync. */
+    public long latestRunTime;
+    /** Set by the SyncManager in order to delay retries. */
     public Long backoff;
+    /** Specified by the adapter to delay subsequent sync operations. */
     public long delayUntil;
+    /**
+     * Elapsed real time in millis when this sync will be run.
+     * Depends on max(backoff, latestRunTime, and delayUntil).
+     */
     public long effectiveRunTime;
+    /** Amount of time before {@link effectiveRunTime} from which this sync can run. */
+    public long flexTime;
 
     public SyncOperation(Account account, int userId, int reason, int source, String authority,
-            Bundle extras, long delayInMs, long backoff, long delayUntil,
-            boolean allowParallelSyncs) {
+            Bundle extras, long runTimeFromNow, long flexTime, long backoff,
+            long delayUntil, boolean allowParallelSyncs) {
+        this.service = null;
         this.account = account;
+        this.authority = authority;
         this.userId = userId;
         this.reason = reason;
         this.syncSource = source;
-        this.authority = authority;
         this.allowParallelSyncs = allowParallelSyncs;
         this.extras = new Bundle(extras);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_UPLOAD);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_MANUAL);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_EXPEDITED);
-        removeFalseExtra(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
+        cleanBundle(this.extras);
         this.delayUntil = delayUntil;
         this.backoff = backoff;
         final long now = SystemClock.elapsedRealtime();
-        if (delayInMs < 0) {
+        // Checks the extras bundle. Must occur after we set the internal bundle.
+        if (runTimeFromNow < 0 || isExpedited()) {
             this.expedited = true;
-            this.earliestRunTime = now;
+            this.latestRunTime = now;
+            this.flexTime = 0;
         } else {
             this.expedited = false;
-            this.earliestRunTime = now + delayInMs;
+            this.latestRunTime = now + runTimeFromNow;
+            this.flexTime = flexTime;
         }
         updateEffectiveRunTime();
         this.key = toKey();
     }
 
-    private void removeFalseExtra(String extraName) {
-        if (!extras.getBoolean(extraName, false)) {
-            extras.remove(extraName);
+    /**
+     * Make sure the bundle attached to this SyncOperation doesn't have unnecessary
+     * flags set.
+     * @param bundle to clean.
+     */
+    private void cleanBundle(Bundle bundle) {
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_UPLOAD);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_MANUAL);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_EXPEDITED);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
+        removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISALLOW_METERED);
+
+        // Remove Config data.
+        bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD);
+        bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD);
+    }
+
+    private void removeFalseExtra(Bundle bundle, String extraName) {
+        if (!bundle.getBoolean(extraName, false)) {
+            bundle.remove(extraName);
         }
     }
 
+    /** Only used to immediately reschedule a sync. */
     SyncOperation(SyncOperation other) {
+        this.service = other.service;
         this.account = other.account;
+        this.authority = other.authority;
         this.userId = other.userId;
         this.reason = other.reason;
         this.syncSource = other.syncSource;
-        this.authority = other.authority;
         this.extras = new Bundle(other.extras);
         this.expedited = other.expedited;
-        this.earliestRunTime = SystemClock.elapsedRealtime();
+        this.latestRunTime = SystemClock.elapsedRealtime();
+        this.flexTime = 0L;
         this.backoff = other.backoff;
-        this.delayUntil = other.delayUntil;
         this.allowParallelSyncs = other.allowParallelSyncs;
         this.updateEffectiveRunTime();
         this.key = toKey();
     }
 
+    @Override
     public String toString() {
         return dump(null, true);
     }
@@ -131,8 +172,8 @@
                 .append(authority)
                 .append(", ")
                 .append(SyncStorageEngine.SOURCES[syncSource])
-                .append(", earliestRunTime ")
-                .append(earliestRunTime);
+                .append(", latestRunTime ")
+                .append(latestRunTime);
         if (expedited) {
             sb.append(", EXPEDITED");
         }
@@ -170,23 +211,38 @@
         }
     }
 
+    public boolean isMeteredDisallowed() {
+        return extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
+    }
+
     public boolean isInitialization() {
         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
     }
 
     public boolean isExpedited() {
-        return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
+        return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false) || expedited;
     }
 
     public boolean ignoreBackoff() {
         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
     }
 
+    /** Changed in V3. */
     private String toKey() {
         StringBuilder sb = new StringBuilder();
-        sb.append("authority: ").append(authority);
-        sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
-                + "}");
+        if (service == null) {
+            sb.append("authority: ").append(authority);
+            sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
+                    + "}");
+        } else {
+            sb.append("service {package=" )
+                .append(service.getPackageName())
+                .append(" user=")
+                .append(userId)
+                .append(", class=")
+                .append(service.getClassName())
+                .append("}");
+        }
         sb.append(" extras: ");
         extrasToStringBuilder(extras, sb);
         return sb.toString();
@@ -200,25 +256,39 @@
         sb.append("]");
     }
 
+    /**
+     * Update the effective run time of this Operation based on latestRunTime (specified at
+     * creation time of sync), delayUntil (specified by SyncAdapter), or backoff (specified by
+     * SyncManager on soft failures).
+     */
     public void updateEffectiveRunTime() {
-        effectiveRunTime = ignoreBackoff()
-                ? earliestRunTime
-                : Math.max(
-                    Math.max(earliestRunTime, delayUntil),
-                    backoff);
+        // Regardless of whether we're in backoff or honouring a delayUntil, we still incorporate
+        // the flex time provided by the developer.
+        effectiveRunTime = ignoreBackoff() ?
+                latestRunTime :
+                    Math.max(Math.max(latestRunTime, delayUntil), backoff);
     }
 
+    /**
+     * SyncOperations are sorted based on their earliest effective run time.
+     * This comparator is used to sort the SyncOps at a given time when
+     * deciding which to run, so earliest run time is the best criteria.
+     */
+    @Override
     public int compareTo(Object o) {
-        SyncOperation other = (SyncOperation)o;
-
+        SyncOperation other = (SyncOperation) o;
         if (expedited != other.expedited) {
             return expedited ? -1 : 1;
         }
-
-        if (effectiveRunTime == other.effectiveRunTime) {
+        long thisIntervalStart = Math.max(effectiveRunTime - flexTime, 0);
+        long otherIntervalStart = Math.max(
+            other.effectiveRunTime - other.flexTime, 0);
+        if (thisIntervalStart < otherIntervalStart) {
+            return -1;
+        } else if (otherIntervalStart < thisIntervalStart) {
+            return 1;
+        } else {
             return 0;
         }
-
-        return effectiveRunTime < other.effectiveRunTime ? -1 : 1;
     }
 }
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/java/com/android/server/content/SyncQueue.java
index 951e92c..6f3fe6e 100644
--- a/services/java/com/android/server/content/SyncQueue.java
+++ b/services/java/com/android/server/content/SyncQueue.java
@@ -73,7 +73,7 @@
             }
             SyncOperation syncOperation = new SyncOperation(
                     op.account, op.userId, op.reason, op.syncSource, op.authority, op.extras,
-                    0 /* delay */, backoff != null ? backoff.first : 0,
+                    0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0,
                     mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
                     syncAdapterInfo.type.allowParallelSyncs());
             syncOperation.expedited = op.expedited;
@@ -86,35 +86,40 @@
         return add(operation, null /* this is not coming from the database */);
     }
 
+    /**
+     * Adds a SyncOperation to the queue and creates a PendingOperation object to track that sync.
+     * If an operation is added that already exists, the existing operation is updated if the newly
+     * added operation occurs before (or the interval overlaps).
+     */
     private boolean add(SyncOperation operation,
             SyncStorageEngine.PendingOperation pop) {
-        // - if an operation with the same key exists and this one should run earlier,
-        //   update the earliestRunTime of the existing to the new time
-        // - if an operation with the same key exists and if this one should run
-        //   later, ignore it
-        // - if no operation exists then add the new one
+        // If an operation with the same key exists and this one should run sooner/overlaps,
+        // replace the run interval of the existing operation with this new one.
+        // Complications: what if the existing operation is expedited but the new operation has an
+        // earlier run time? Will not be a problem for periodic syncs (no expedited flag), and for
+        // one-off syncs we only change it if the new sync is sooner.
         final String operationKey = operation.key;
         final SyncOperation existingOperation = mOperationsMap.get(operationKey);
 
         if (existingOperation != null) {
             boolean changed = false;
-            if (existingOperation.expedited == operation.expedited) {
-                final long newRunTime =
-                        Math.min(existingOperation.earliestRunTime, operation.earliestRunTime);
-                if (existingOperation.earliestRunTime != newRunTime) {
-                    existingOperation.earliestRunTime = newRunTime;
-                    changed = true;
-                }
-            } else {
-                if (operation.expedited) {
-                    existingOperation.expedited = true;
-                    changed = true;
-                }
+            if (operation.compareTo(existingOperation) <= 0 ) {
+                existingOperation.expedited = operation.expedited;
+                long newRunTime =
+                        Math.min(existingOperation.latestRunTime, operation.latestRunTime);
+                // Take smaller runtime.
+                existingOperation.latestRunTime = newRunTime;
+                // Take newer flextime.
+                existingOperation.flexTime = operation.flexTime;
+                changed = true;
             }
             return changed;
         }
 
         operation.pendingOperation = pop;
+        // Don't update the PendingOp if one already exists. This really is just a placeholder,
+        // no actual scheduling info is placed here.
+        // TODO: Change this to support service components.
         if (operation.pendingOperation == null) {
             pop = new SyncStorageEngine.PendingOperation(
                     operation.account, operation.userId, operation.reason, operation.syncSource,
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 5b8d26f..d51c2d7 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -18,6 +18,7 @@
 
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ISyncStatusObserver;
@@ -52,6 +53,7 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -70,7 +72,7 @@
 
     private static final String TAG = "SyncManager";
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_FILE = false;
+    private static final String TAG_FILE = "SyncManagerFile";
 
     private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
     private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles";
@@ -79,8 +81,15 @@
     private static final String XML_ATTR_USER = "user";
     private static final String XML_TAG_LISTEN_FOR_TICKLES = "listenForTickles";
 
+    /** Default time for a periodic sync. */
     private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
 
+    /** Percentage of period that is flex by default, if no flex is set. */
+    private static final double DEFAULT_FLEX_PERCENT_SYNC = 0.04;
+
+    /** Lower bound on sync time from which we assign a default flex time. */
+    private static final long DEFAULT_MIN_FLEX_ALLOWED_SECS = 5;
+
     @VisibleForTesting
     static final long MILLIS_IN_4WEEKS = 1000L * 60 * 60 * 24 * 7 * 4;
 
@@ -153,12 +162,13 @@
         final int syncSource;
         final String authority;
         final Bundle extras;        // note: read-only.
+        final ComponentName serviceName;
         final boolean expedited;
 
         int authorityId;
         byte[] flatExtras;
 
-        PendingOperation(Account account, int userId, int reason,int source,
+        PendingOperation(Account account, int userId, int reason, int source,
                 String authority, Bundle extras, boolean expedited) {
             this.account = account;
             this.userId = userId;
@@ -168,6 +178,7 @@
             this.extras = extras != null ? new Bundle(extras) : extras;
             this.expedited = expedited;
             this.authorityId = -1;
+            this.serviceName = null;
         }
 
         PendingOperation(PendingOperation other) {
@@ -179,6 +190,7 @@
             this.extras = other.extras;
             this.authorityId = other.authorityId;
             this.expedited = other.expedited;
+            this.serviceName = other.serviceName;
         }
     }
 
@@ -193,6 +205,7 @@
     }
 
     public static class AuthorityInfo {
+        final ComponentName service;
         final Account account;
         final int userId;
         final String authority;
@@ -202,7 +215,7 @@
         long backoffTime;
         long backoffDelay;
         long delayUntil;
-        final ArrayList<Pair<Bundle, Long>> periodicSyncs;
+        final ArrayList<PeriodicSync> periodicSyncs;
 
         /**
          * Copy constructor for making deep-ish copies. Only the bundles stored
@@ -214,30 +227,70 @@
             account = toCopy.account;
             userId = toCopy.userId;
             authority = toCopy.authority;
+            service = toCopy.service;
             ident = toCopy.ident;
             enabled = toCopy.enabled;
             syncable = toCopy.syncable;
             backoffTime = toCopy.backoffTime;
             backoffDelay = toCopy.backoffDelay;
             delayUntil = toCopy.delayUntil;
-            periodicSyncs = new ArrayList<Pair<Bundle, Long>>();
-            for (Pair<Bundle, Long> sync : toCopy.periodicSyncs) {
+            periodicSyncs = new ArrayList<PeriodicSync>();
+            for (PeriodicSync sync : toCopy.periodicSyncs) {
                 // Still not a perfect copy, because we are just copying the mappings.
-                periodicSyncs.add(Pair.create(new Bundle(sync.first), sync.second));
+                periodicSyncs.add(new PeriodicSync(sync));
             }
         }
 
+        /**
+         * Create an authority with one periodic sync scheduled with an empty bundle and syncing
+         * every day. An empty bundle is considered equal to any other bundle see
+         * {@link PeriodicSync.syncExtrasEquals}.
+         * @param account Account that this authority syncs.
+         * @param userId which user this sync is registered for.
+         * @param userId user for which this authority is registered.
+         * @param ident id of this authority.
+         */
         AuthorityInfo(Account account, int userId, String authority, int ident) {
             this.account = account;
             this.userId = userId;
             this.authority = authority;
+            this.service = null;
             this.ident = ident;
             enabled = SYNC_ENABLED_DEFAULT;
             syncable = -1; // default to "unknown"
             backoffTime = -1; // if < 0 then we aren't in backoff mode
             backoffDelay = -1; // if < 0 then we aren't in backoff mode
-            periodicSyncs = new ArrayList<Pair<Bundle, Long>>();
-            periodicSyncs.add(Pair.create(new Bundle(), DEFAULT_POLL_FREQUENCY_SECONDS));
+            periodicSyncs = new ArrayList<PeriodicSync>();
+            // Old version adds one periodic sync a day.
+            periodicSyncs.add(new PeriodicSync(account, authority,
+                                new Bundle(),
+                                DEFAULT_POLL_FREQUENCY_SECONDS,
+                                calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
+        }
+
+        /**
+         * Create an authority with one periodic sync scheduled with an empty bundle and syncing
+         * every day using a sync service.
+         * @param cname sync service identifier.
+         * @param userId user for which this authority is registered.
+         * @param ident id of this authority.
+         */
+        AuthorityInfo(ComponentName cname, int userId, int ident) {
+            this.account = null;
+            this.userId = userId;
+            this.authority = null;
+            this.service = cname;
+            this.ident = ident;
+            // Sync service is always enabled.
+            enabled = true;
+            syncable = -1; // default to "unknown"
+            backoffTime = -1; // if < 0 then we aren't in backoff mode
+            backoffDelay = -1; // if < 0 then we aren't in backoff mode
+            periodicSyncs = new ArrayList<PeriodicSync>();
+            periodicSyncs.add(new PeriodicSync(account, authority,
+                                new Bundle(),
+                                DEFAULT_POLL_FREQUENCY_SECONDS,
+                                calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
         }
     }
 
@@ -303,6 +356,10 @@
     private final RemoteCallbackList<ISyncStatusObserver> mChangeListeners
             = new RemoteCallbackList<ISyncStatusObserver>();
 
+    /** Reverse mapping for component name -> <userid -> authority id>. */
+    private final HashMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
+            new HashMap<ComponentName, SparseArray<AuthorityInfo>>();
+
     private int mNextAuthorityId = 0;
 
     // We keep 4 weeks of stats.
@@ -364,9 +421,12 @@
         File systemDir = new File(dataDir, "system");
         File syncDir = new File(systemDir, "sync");
         syncDir.mkdirs();
+
+        maybeDeleteLegacyPendingInfoLocked(syncDir);
+
         mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
         mStatusFile = new AtomicFile(new File(syncDir, "status.bin"));
-        mPendingFile = new AtomicFile(new File(syncDir, "pending.bin"));
+        mPendingFile = new AtomicFile(new File(syncDir, "pending.xml"));
         mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"));
 
         readAccountInfoLocked();
@@ -435,6 +495,28 @@
         }
     }
 
+    /**
+     * Figure out a reasonable flex time for cases where none is provided (old api calls).
+     * @param syncTimeSeconds requested sync time from now.
+     * @return amount of seconds before syncTimeSeconds that the sync can occur.
+     *      I.e.
+     *      earliest_sync_time = syncTimeSeconds - calculateDefaultFlexTime(syncTimeSeconds)
+     * The flex time is capped at a percentage of the {@link DEFAULT_POLL_FREQUENCY_SECONDS}.
+     */
+    public static long calculateDefaultFlexTime(long syncTimeSeconds) {
+        if (syncTimeSeconds < DEFAULT_MIN_FLEX_ALLOWED_SECS) {
+            // Small enough sync request time that we don't add flex time - developer probably
+            // wants to wait for an operation to occur before syncing so we honour the
+            // request time.
+            return 0L;
+        } else if (syncTimeSeconds < DEFAULT_POLL_FREQUENCY_SECONDS) {
+            return (long) (syncTimeSeconds * DEFAULT_FLEX_PERCENT_SYNC);
+        } else {
+            // Large enough sync request time that we cap the flex time.
+            return (long) (DEFAULT_POLL_FREQUENCY_SECONDS * DEFAULT_FLEX_PERCENT_SYNC);
+        }
+    }
+
     private void reportChange(int which) {
         ArrayList<ISyncStatusObserver> reports = null;
         synchronized (mAuthorities) {
@@ -552,8 +634,8 @@
                     + ", user " + userId + " -> " + syncable);
         }
         synchronized (mAuthorities) {
-            AuthorityInfo authority = getOrCreateAuthorityLocked(account, userId, providerName, -1,
-                    false);
+            AuthorityInfo authority =
+                    getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
             if (authority.syncable == syncable) {
                 if (DEBUG) {
                     Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
@@ -598,7 +680,8 @@
                         continue;
                     }
                     for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
-                        if (providerName != null && !providerName.equals(authorityInfo.authority)) {
+                        if (providerName != null
+                                && !providerName.equals(authorityInfo.authority)) {
                             continue;
                         }
                         if (authorityInfo.backoffTime != nextSyncTime
@@ -627,28 +710,31 @@
         }
     }
 
-    public void clearAllBackoffs(SyncQueue syncQueue) {
+    /**
+     * Callers of this function need to hold a lock for syncQueue object passed in. Bear in mind
+     * this function grabs the lock for {@link #mAuthorities}
+     * @param syncQueue queue containing pending sync operations.
+     */
+    public void clearAllBackoffsLocked(SyncQueue syncQueue) {
         boolean changed = false;
         synchronized (mAuthorities) {
-            synchronized (syncQueue) {
-                for (AccountInfo accountInfo : mAccounts.values()) {
-                    for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
-                        if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
-                                || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
-                            if (DEBUG) {
-                                Log.v(TAG, "clearAllBackoffs:"
-                                        + " authority:" + authorityInfo.authority
-                                        + " account:" + accountInfo.accountAndUser.account.name
-                                        + " user:" + accountInfo.accountAndUser.userId
-                                        + " backoffTime was: " + authorityInfo.backoffTime
-                                        + " backoffDelay was: " + authorityInfo.backoffDelay);
-                            }
-                            authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
-                            authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
-                            syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
-                                    accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
-                            changed = true;
+            for (AccountInfo accountInfo : mAccounts.values()) {
+                for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+                    if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+                            || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+                        if (DEBUG) {
+                            Log.v(TAG, "clearAllBackoffs:"
+                                    + " authority:" + authorityInfo.authority
+                                    + " account:" + accountInfo.accountAndUser.account.name
+                                    + " user:" + accountInfo.accountAndUser.userId
+                                    + " backoffTime was: " + authorityInfo.backoffTime
+                                    + " backoffDelay was: " + authorityInfo.backoffDelay);
                         }
+                        authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+                        authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+                        syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
+                                accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
+                        changed = true;
                     }
                 }
             }
@@ -688,62 +774,68 @@
         }
     }
 
-    private void updateOrRemovePeriodicSync(Account account, int userId, String providerName,
-            Bundle extras,
-            long period, boolean add) {
-        if (period <= 0) {
-            period = 0;
-        }
-        if (extras == null) {
-            extras = new Bundle();
-        }
+    private void updateOrRemovePeriodicSync(PeriodicSync toUpdate, int userId, boolean add) {
         if (DEBUG) {
-            Log.v(TAG, "addOrRemovePeriodicSync: " + account + ", user " + userId
-                    + ", provider " + providerName
-                    + " -> period " + period + ", extras " + extras);
+            Log.v(TAG, "addOrRemovePeriodicSync: " + toUpdate.account + ", user " + userId
+                    + ", provider " + toUpdate.authority
+                    + " -> period " + toUpdate.period + ", extras " + toUpdate.extras);
         }
         synchronized (mAuthorities) {
+            if (toUpdate.period <= 0 && add) {
+                Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-"
+                        + add);
+            }
+            if (toUpdate.extras == null) {
+                Log.e(TAG, "null extras, should never happen in updateOrRemovePeriodicSync: add-"
+                        + add);
+            }
             try {
                 AuthorityInfo authority =
-                        getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
+                        getOrCreateAuthorityLocked(toUpdate.account, userId, toUpdate.authority,
+                                -1, false);
                 if (add) {
-                    // add this periodic sync if one with the same extras doesn't already
-                    // exist in the periodicSyncs array
+                    // add this periodic sync if an equivalent periodic doesn't already exist.
                     boolean alreadyPresent = false;
                     for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
-                        Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
-                        final Bundle existingExtras = syncInfo.first;
-                        if (PeriodicSync.syncExtrasEquals(existingExtras, extras)) {
-                            if (syncInfo.second == period) {
+                        PeriodicSync syncInfo = authority.periodicSyncs.get(i);
+                        if (PeriodicSync.syncExtrasEquals(
+                                toUpdate.extras,
+                                syncInfo.extras)) {
+                            if (toUpdate.period == syncInfo.period &&
+                                    toUpdate.flexTime == syncInfo.flexTime) {
+                                // Absolutely the same.
                                 return;
                             }
-                            authority.periodicSyncs.set(i, Pair.create(extras, period));
+                            authority.periodicSyncs.set(i, new PeriodicSync(toUpdate));
                             alreadyPresent = true;
                             break;
                         }
                     }
-                    // if we added an entry to the periodicSyncs array also add an entry to
-                    // the periodic syncs status to correspond to it
+                    // If we added an entry to the periodicSyncs array also add an entry to
+                    // the periodic syncs status to correspond to it.
                     if (!alreadyPresent) {
-                        authority.periodicSyncs.add(Pair.create(extras, period));
+                        authority.periodicSyncs.add(new PeriodicSync(toUpdate));
                         SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
-                        status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
+                        status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0L);
                     }
                 } else {
-                    // remove any periodic syncs that match the authority and extras
+                    // Remove any periodic syncs that match the authority and extras.
                     SyncStatusInfo status = mSyncStatus.get(authority.ident);
                     boolean changed = false;
-                    Iterator<Pair<Bundle, Long>> iterator = authority.periodicSyncs.iterator();
+                    Iterator<PeriodicSync> iterator = authority.periodicSyncs.iterator();
                     int i = 0;
                     while (iterator.hasNext()) {
-                        Pair<Bundle, Long> syncInfo = iterator.next();
-                        if (PeriodicSync.syncExtrasEquals(syncInfo.first, extras)) {
+                        PeriodicSync syncInfo = iterator.next();
+                        if (PeriodicSync.syncExtrasEquals(syncInfo.extras, toUpdate.extras)) {
                             iterator.remove();
                             changed = true;
-                            // if we removed an entry from the periodicSyncs array also
+                            // If we removed an entry from the periodicSyncs array also
                             // remove the corresponding entry from the status
                             if (status != null) {
                                 status.removePeriodicSyncTime(i);
+                            } else {
+                                Log.e(TAG, "Tried removing sync status on remove periodic sync but"
+                                        + "did not find it.");
                             }
                         } else {
                             i++;
@@ -762,16 +854,12 @@
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
     }
 
-    public void addPeriodicSync(Account account, int userId, String providerName, Bundle extras,
-            long pollFrequency) {
-        updateOrRemovePeriodicSync(account, userId, providerName, extras, pollFrequency,
-                true /* add */);
+    public void addPeriodicSync(PeriodicSync toAdd, int userId) {
+        updateOrRemovePeriodicSync(toAdd, userId, true /* add */);
     }
 
-    public void removePeriodicSync(Account account, int userId, String providerName,
-            Bundle extras) {
-        updateOrRemovePeriodicSync(account, userId, providerName, extras, 0 /* period, ignored */,
-                false /* remove */);
+    public void removePeriodicSync(PeriodicSync toRemove, int userId) {
+        updateOrRemovePeriodicSync(toRemove, userId, false /* remove */);
     }
 
     public List<PeriodicSync> getPeriodicSyncs(Account account, int userId, String providerName) {
@@ -780,9 +868,9 @@
             AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
                     "getPeriodicSyncs");
             if (authority != null) {
-                for (Pair<Bundle, Long> item : authority.periodicSyncs) {
-                    syncs.add(new PeriodicSync(account, providerName, item.first,
-                            item.second));
+                for (PeriodicSync item : authority.periodicSyncs) {
+                    // Copy and send out. Necessary for thread-safety although it's parceled.
+                    syncs.add(new PeriodicSync(item));
                 }
             }
         }
@@ -813,14 +901,6 @@
         }
     }
 
-    public AuthorityInfo getOrCreateAuthority(Account account, int userId, String authority) {
-        synchronized (mAuthorities) {
-            return getOrCreateAuthorityLocked(account, userId, authority,
-                    -1 /* assign a new identifier if creating a new authority */,
-                    true /* write to storage if this results in a change */);
-        }
-    }
-
     public void removeAuthority(Account account, int userId, String authority) {
         synchronized (mAuthorities) {
             removeAuthorityLocked(account, userId, authority, true /* doWrite */);
@@ -883,6 +963,14 @@
         return op;
     }
 
+    /**
+     * Remove from list of pending operations. If successful, search through list for matching
+     * authorities. If there are no more pending syncs for the same authority/account/userid,
+     * update the SyncStatusInfo for that authority(authority here is the internal representation
+     * of a 'sync operation'.
+     * @param op
+     * @return
+     */
     public boolean deleteFromPending(PendingOperation op) {
         boolean res = false;
         synchronized (mAuthorities) {
@@ -905,7 +993,7 @@
                 AuthorityInfo authority = getAuthorityLocked(op.account, op.userId, op.authority,
                         "deleteFromPending");
                 if (authority != null) {
-                    if (DEBUG) Log.v(TAG, "removing - " + authority);
+                    if (DEBUG) Log.v(TAG, "removing - " + authority.toString());
                     final int N = mPendingOperations.size();
                     boolean morePending = false;
                     for (int i=0; i<N; i++) {
@@ -1238,17 +1326,27 @@
     }
 
     /**
-     * Return an array of the current authorities. Note
-     * that the objects inside the array are the real, live objects,
-     * so be careful what you do with them.
+     * Return a copy of the specified authority with the corresponding sync status
      */
-    public ArrayList<AuthorityInfo> getAuthorities() {
+    public Pair<AuthorityInfo, SyncStatusInfo> getCopyOfAuthorityWithSyncStatus(
+            Account account, int userId, String authority) {
         synchronized (mAuthorities) {
-            final int N = mAuthorities.size();
-            ArrayList<AuthorityInfo> infos = new ArrayList<AuthorityInfo>(N);
-            for (int i=0; i<N; i++) {
-                // Make deep copy because AuthorityInfo syncs are liable to change.
-                infos.add(new AuthorityInfo(mAuthorities.valueAt(i)));
+            AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(account, userId, authority,
+                    -1 /* assign a new identifier if creating a new authority */,
+                    true /* write to storage if this results in a change */);
+            return createCopyPairOfAuthorityWithSyncStatusLocked(authorityInfo);
+        }
+    }
+
+    /**
+     * Return a copy of all authorities with their corresponding sync status
+     */
+    public ArrayList<Pair<AuthorityInfo, SyncStatusInfo>> getCopyOfAllAuthoritiesWithSyncStatus() {
+        synchronized (mAuthorities) {
+            ArrayList<Pair<AuthorityInfo, SyncStatusInfo>> infos =
+                    new ArrayList<Pair<AuthorityInfo, SyncStatusInfo>>(mAuthorities.size());
+            for (int i = 0; i < mAuthorities.size(); i++) {
+                infos.add(createCopyPairOfAuthorityWithSyncStatusLocked(mAuthorities.valueAt(i)));
             }
             return infos;
         }
@@ -1337,6 +1435,12 @@
         }
     }
 
+    private Pair<AuthorityInfo, SyncStatusInfo> createCopyPairOfAuthorityWithSyncStatusLocked(
+            AuthorityInfo authorityInfo) {
+        SyncStatusInfo syncStatusInfo = getOrCreateSyncStatusLocked(authorityInfo.ident);
+        return Pair.create(new AuthorityInfo(authorityInfo), new SyncStatusInfo(syncStatusInfo));
+    }
+
     private int getCurrentDayLocked() {
         mCal.setTimeInMillis(System.currentTimeMillis());
         final int dayOfYear = mCal.get(Calendar.DAY_OF_YEAR);
@@ -1382,6 +1486,65 @@
         return authority;
     }
 
+    /**
+     * Retrieve an authority, returning null if one does not exist.
+     *
+     * @param service The service name used for this sync.
+     * @param userId The user for whom this sync is scheduled.
+     * @param tag If non-null, this will be used in a log message if the
+     * requested authority does not exist.
+     */
+    private AuthorityInfo getAuthorityLocked(ComponentName service, int userId, String tag) {
+        AuthorityInfo authority = mServices.get(service).get(userId);
+        if (authority == null) {
+            if (tag != null) {
+                if (DEBUG) {
+                    Log.v(TAG, tag + " No authority info found for " + service + " for user "
+                            + userId);
+                }
+            }
+            return null;
+        }
+        return authority;
+    }
+
+    /**
+     * @param cname identifier for the service.
+     * @param userId for the syncs corresponding to this authority.
+     * @param ident unique identifier for authority. -1 for none.
+     * @param doWrite if true, update the accounts.xml file on the disk.
+     * @return the authority that corresponds to the provided sync service, creating it if none
+     * exists.
+     */
+    private AuthorityInfo getOrCreateAuthorityLocked(ComponentName cname, int userId, int ident,
+            boolean doWrite) {
+        SparseArray<AuthorityInfo> aInfo = mServices.get(cname);
+        if (aInfo == null) {
+            aInfo = new SparseArray<AuthorityInfo>();
+            mServices.put(cname, aInfo);
+        }
+        AuthorityInfo authority = aInfo.get(userId);
+        if (authority == null) {
+            if (ident < 0) {
+                ident = mNextAuthorityId;
+                mNextAuthorityId++;
+                doWrite = true;
+            }
+            if (DEBUG) {
+                Log.v(TAG, "created a new AuthorityInfo for " + cname.getPackageName()
+                        + ", " + cname.getClassName()
+                        + ", user: " + userId);
+            }
+            authority = new AuthorityInfo(cname, userId, ident);
+            aInfo.put(userId, authority);
+            mAuthorities.put(ident, authority);
+            if (doWrite) {
+                writeAccountInfoLocked();
+            }
+        }
+        return authority;
+    }
+
     private AuthorityInfo getOrCreateAuthorityLocked(Account accountName, int userId,
             String authorityName, int ident, boolean doWrite) {
         AccountAndUser au = new AccountAndUser(accountName, userId);
@@ -1427,9 +1590,28 @@
         }
     }
 
-    public SyncStatusInfo getOrCreateSyncStatus(AuthorityInfo authority) {
+    /**
+     * Updates (in a synchronized way) the periodic sync time of the specified
+     * authority id and target periodic sync
+     */
+    public void setPeriodicSyncTime(
+            int authorityId, PeriodicSync targetPeriodicSync, long when) {
+        boolean found = false;
+        final AuthorityInfo authorityInfo;
         synchronized (mAuthorities) {
-            return getOrCreateSyncStatusLocked(authority.ident);
+            authorityInfo = mAuthorities.get(authorityId);
+            for (int i = 0; i < authorityInfo.periodicSyncs.size(); i++) {
+                PeriodicSync periodicSync = authorityInfo.periodicSyncs.get(i);
+                if (targetPeriodicSync.equals(periodicSync)) {
+                    mSyncStatus.get(authorityId).setPeriodicSyncTime(i, when);
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!found) {
+            Log.w(TAG, "Ignoring setPeriodicSyncTime request for a sync that does not exist. " +
+                    "Authority: " + authorityInfo.authority);
         }
     }
 
@@ -1464,6 +1646,7 @@
         synchronized (mAuthorities) {
             mAuthorities.clear();
             mAccounts.clear();
+            mServices.clear();
             mPendingOperations.clear();
             mSyncStatus.clear();
             mSyncHistory.clear();
@@ -1488,7 +1671,9 @@
         FileInputStream fis = null;
         try {
             fis = mAccountInfoFile.openRead();
-            if (DEBUG_FILE) Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
+            }
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
             int eventType = parser.getEventType();
@@ -1525,7 +1710,7 @@
                 mMasterSyncAutomatically.put(0, listen == null || Boolean.parseBoolean(listen));
                 eventType = parser.next();
                 AuthorityInfo authority = null;
-                Pair<Bundle, Long> periodicSync = null;
+                PeriodicSync periodicSync = null;
                 do {
                     if (eventType == XmlPullParser.START_TAG) {
                         tagName = parser.getName();
@@ -1545,7 +1730,7 @@
                             }
                         } else if (parser.getDepth() == 4 && periodicSync != null) {
                             if ("extra".equals(tagName)) {
-                                parseExtra(parser, periodicSync);
+                                parseExtra(parser, periodicSync.extras);
                             }
                         }
                     }
@@ -1573,6 +1758,20 @@
     }
 
     /**
+     * Ensure the old pending.bin is deleted, as it has been changed to pending.xml.
+     * pending.xml was used starting in KLP.
+     * @param syncDir directory where the sync files are located.
+     */
+    private void maybeDeleteLegacyPendingInfoLocked(File syncDir) {
+        File file = new File(syncDir, "pending.bin");
+        if (!file.exists()) {
+            return;
+        } else {
+            file.delete();
+        }
+    }
+
+    /**
      * some authority names have changed. copy over their settings and delete the old ones
      * @return true if a change was made
      */
@@ -1639,8 +1838,7 @@
         AuthorityInfo authority = null;
         int id = -1;
         try {
-            id = Integer.parseInt(parser.getAttributeValue(
-                    null, "id"));
+            id = Integer.parseInt(parser.getAttributeValue(null, "id"));
         } catch (NumberFormatException e) {
             Log.e(TAG, "error parsing the id of the authority", e);
         } catch (NullPointerException e) {
@@ -1653,24 +1851,36 @@
             String accountName = parser.getAttributeValue(null, "account");
             String accountType = parser.getAttributeValue(null, "type");
             String user = parser.getAttributeValue(null, XML_ATTR_USER);
+            String packageName = parser.getAttributeValue(null, "package");
+            String className = parser.getAttributeValue(null, "class");
             int userId = user == null ? 0 : Integer.parseInt(user);
             if (accountType == null) {
                 accountType = "com.google";
                 syncable = "unknown";
             }
             authority = mAuthorities.get(id);
-            if (DEBUG_FILE) Log.v(TAG, "Adding authority: account="
-                    + accountName + " auth=" + authorityName
-                    + " user=" + userId
-                    + " enabled=" + enabled
-                    + " syncable=" + syncable);
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.v(TAG, "Adding authority: account="
+                        + accountName + " auth=" + authorityName
+                        + " user=" + userId
+                        + " enabled=" + enabled
+                        + " syncable=" + syncable);
+            }
             if (authority == null) {
-                if (DEBUG_FILE) Log.v(TAG, "Creating entry");
-                authority = getOrCreateAuthorityLocked(
-                        new Account(accountName, accountType), userId, authorityName, id, false);
+                if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                    Log.v(TAG, "Creating entry");
+                }
+                if (accountName != null && accountType != null) {
+                    authority = getOrCreateAuthorityLocked(
+                            new Account(accountName, accountType), userId, authorityName, id,
+                                false);
+                } else {
+                    authority = getOrCreateAuthorityLocked(
+                            new ComponentName(packageName, className), userId, id, false);
+                }
                 // If the version is 0 then we are upgrading from a file format that did not
                 // know about periodic syncs. In that case don't clear the list since we
-                // want the default, which is a daily periodioc sync.
+                // want the default, which is a daily periodic sync.
                 // Otherwise clear out this default list since we will populate it later with
                 // the periodic sync descriptions that are read from the configuration file.
                 if (version > 0) {
@@ -1692,14 +1902,18 @@
                         + " syncable=" + syncable);
             }
         }
-
         return authority;
     }
 
-    private Pair<Bundle, Long> parsePeriodicSync(XmlPullParser parser, AuthorityInfo authority) {
-        Bundle extras = new Bundle();
+    /**
+     * Parse a periodic sync from accounts.xml. Sets the bundle to be empty.
+     */
+    private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authority) {
+        Bundle extras = new Bundle(); // Gets filled in later.
         String periodValue = parser.getAttributeValue(null, "period");
+        String flexValue = parser.getAttributeValue(null, "flex");
         final long period;
+        long flextime;
         try {
             period = Long.parseLong(periodValue);
         } catch (NumberFormatException e) {
@@ -1709,14 +1923,24 @@
             Log.e(TAG, "the period of a periodic sync is null", e);
             return null;
         }
-        final Pair<Bundle, Long> periodicSync = Pair.create(extras, period);
+        try {
+            flextime = Long.parseLong(flexValue);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue);
+            flextime = calculateDefaultFlexTime(period);
+        } catch (NullPointerException expected) {
+            flextime = calculateDefaultFlexTime(period);
+            Log.d(TAG, "No flex time specified for this sync, using a default. period: "
+            + period + " flex: " + flextime);
+        }
+        final PeriodicSync periodicSync =
+                new PeriodicSync(authority.account, authority.authority, extras,
+                        period, flextime);
         authority.periodicSyncs.add(periodicSync);
-
         return periodicSync;
     }
 
-    private void parseExtra(XmlPullParser parser, Pair<Bundle, Long> periodicSync) {
-        final Bundle extras = periodicSync.first;
+    private void parseExtra(XmlPullParser parser, Bundle extras) {
         String name = parser.getAttributeValue(null, "name");
         String type = parser.getAttributeValue(null, "type");
         String value1 = parser.getAttributeValue(null, "value1");
@@ -1749,7 +1973,9 @@
      * Write all account information to the account file.
      */
     private void writeAccountInfoLocked() {
-        if (DEBUG_FILE) Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
+        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+            Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
+        }
         FileOutputStream fos = null;
 
         try {
@@ -1776,62 +2002,37 @@
             }
 
             final int N = mAuthorities.size();
-            for (int i=0; i<N; i++) {
+            for (int i = 0; i < N; i++) {
                 AuthorityInfo authority = mAuthorities.valueAt(i);
                 out.startTag(null, "authority");
                 out.attribute(null, "id", Integer.toString(authority.ident));
-                out.attribute(null, "account", authority.account.name);
                 out.attribute(null, XML_ATTR_USER, Integer.toString(authority.userId));
-                out.attribute(null, "type", authority.account.type);
-                out.attribute(null, "authority", authority.authority);
                 out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(authority.enabled));
+                if (authority.service == null) {
+                    out.attribute(null, "account", authority.account.name);
+                    out.attribute(null, "type", authority.account.type);
+                    out.attribute(null, "authority", authority.authority);
+                } else {
+                    out.attribute(null, "package", authority.service.getPackageName());
+                    out.attribute(null, "class", authority.service.getClassName());
+                }
                 if (authority.syncable < 0) {
                     out.attribute(null, "syncable", "unknown");
                 } else {
                     out.attribute(null, "syncable", Boolean.toString(authority.syncable != 0));
                 }
-                for (Pair<Bundle, Long> periodicSync : authority.periodicSyncs) {
+                for (PeriodicSync periodicSync : authority.periodicSyncs) {
                     out.startTag(null, "periodicSync");
-                    out.attribute(null, "period", Long.toString(periodicSync.second));
-                    final Bundle extras = periodicSync.first;
-                    for (String key : extras.keySet()) {
-                        out.startTag(null, "extra");
-                        out.attribute(null, "name", key);
-                        final Object value = extras.get(key);
-                        if (value instanceof Long) {
-                            out.attribute(null, "type", "long");
-                            out.attribute(null, "value1", value.toString());
-                        } else if (value instanceof Integer) {
-                            out.attribute(null, "type", "integer");
-                            out.attribute(null, "value1", value.toString());
-                        } else if (value instanceof Boolean) {
-                            out.attribute(null, "type", "boolean");
-                            out.attribute(null, "value1", value.toString());
-                        } else if (value instanceof Float) {
-                            out.attribute(null, "type", "float");
-                            out.attribute(null, "value1", value.toString());
-                        } else if (value instanceof Double) {
-                            out.attribute(null, "type", "double");
-                            out.attribute(null, "value1", value.toString());
-                        } else if (value instanceof String) {
-                            out.attribute(null, "type", "string");
-                            out.attribute(null, "value1", value.toString());
-                        } else if (value instanceof Account) {
-                            out.attribute(null, "type", "account");
-                            out.attribute(null, "value1", ((Account)value).name);
-                            out.attribute(null, "value2", ((Account)value).type);
-                        }
-                        out.endTag(null, "extra");
-                    }
+                    out.attribute(null, "period", Long.toString(periodicSync.period));
+                    out.attribute(null, "flex", Long.toString(periodicSync.flexTime));
+                    final Bundle extras = periodicSync.extras;
+                    extrasToXml(out, extras);
                     out.endTag(null, "periodicSync");
                 }
                 out.endTag(null, "authority");
             }
-
             out.endTag(null, "accounts");
-
             out.endDocument();
-
             mAccountInfoFile.finishWrite(fos);
         } catch (java.io.IOException e1) {
             Log.w(TAG, "Error writing accounts", e1);
@@ -1872,7 +2073,9 @@
             final boolean hasType = db.getVersion() >= 11;
 
             // Copy in all of the status information, as well as accounts.
-            if (DEBUG_FILE) Log.v(TAG, "Reading legacy sync accounts db");
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.v(TAG, "Reading legacy sync accounts db");
+            }
             SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
             qb.setTables("stats, status");
             HashMap<String,String> map = new HashMap<String,String>();
@@ -1982,7 +2185,9 @@
      * Read all sync status back in to the initial engine state.
      */
     private void readStatusLocked() {
-        if (DEBUG_FILE) Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
+        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+            Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
+        }
         try {
             byte[] data = mStatusFile.readFully();
             Parcel in = Parcel.obtain();
@@ -1994,8 +2199,10 @@
                     SyncStatusInfo status = new SyncStatusInfo(in);
                     if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
                         status.pending = false;
-                        if (DEBUG_FILE) Log.v(TAG, "Adding status for id "
-                                + status.authorityId);
+                        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                            Log.v(TAG, "Adding status for id "
+                                    + status.authorityId);
+                        }
                         mSyncStatus.put(status.authorityId, status);
                     }
                 } else {
@@ -2013,7 +2220,9 @@
      * Write all sync status to the sync status file.
      */
     private void writeStatusLocked() {
-        if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
+        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+            Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
+        }
 
         // The file is being written, so we don't need to have a scheduled
         // write until the next change.
@@ -2044,74 +2253,109 @@
 
     public static final int PENDING_OPERATION_VERSION = 3;
 
-    /**
-     * Read all pending operations back in to the initial engine state.
-     */
+    /** Read all pending operations back in to the initial engine state. */
     private void readPendingOperationsLocked() {
-        if (DEBUG_FILE) Log.v(TAG, "Reading " + mPendingFile.getBaseFile());
-        try {
-            byte[] data = mPendingFile.readFully();
-            Parcel in = Parcel.obtain();
-            in.unmarshall(data, 0, data.length);
-            in.setDataPosition(0);
-            final int SIZE = in.dataSize();
-            while (in.dataPosition() < SIZE) {
-                int version = in.readInt();
-                if (version != PENDING_OPERATION_VERSION && version != 1) {
-                    Log.w(TAG, "Unknown pending operation version "
-                            + version + "; dropping all ops");
-                    break;
-                }
-                int authorityId = in.readInt();
-                int syncSource = in.readInt();
-                byte[] flatExtras = in.createByteArray();
-                boolean expedited;
-                if (version == PENDING_OPERATION_VERSION) {
-                    expedited = in.readInt() != 0;
-                } else {
-                    expedited = false;
-                }
-                int reason = in.readInt();
-                AuthorityInfo authority = mAuthorities.get(authorityId);
-                if (authority != null) {
-                    Bundle extras;
-                    if (flatExtras != null) {
-                        extras = unflattenBundle(flatExtras);
-                    } else {
-                        // if we are unable to parse the extras for whatever reason convert this
-                        // to a regular sync by creating an empty extras
-                        extras = new Bundle();
-                    }
-                    PendingOperation op = new PendingOperation(
-                            authority.account, authority.userId, reason, syncSource,
-                            authority.authority, extras, expedited);
-                    op.authorityId = authorityId;
-                    op.flatExtras = flatExtras;
-                    if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account
-                            + " auth=" + op.authority
-                            + " src=" + op.syncSource
-                            + " reason=" + op.reason
-                            + " expedited=" + op.expedited
-                            + " extras=" + op.extras);
-                    mPendingOperations.add(op);
-                }
+        FileInputStream fis = null;
+        if (!mPendingFile.getBaseFile().exists()) {
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.v(TAG_FILE, "No pending operation file.");
+                return;
             }
+        }
+        try {
+            fis = mPendingFile.openRead();
+            XmlPullParser parser;
+            parser = Xml.newPullParser();
+            parser.setInput(fis, null);
+
+            int eventType = parser.getEventType();
+            while (eventType != XmlPullParser.START_TAG &&
+                    eventType != XmlPullParser.END_DOCUMENT) {
+                eventType = parser.next();
+            }
+            if (eventType == XmlPullParser.END_DOCUMENT) return; // Nothing to read.
+
+            String tagName = parser.getName();
+            do {
+                PendingOperation pop = null;
+                if (eventType == XmlPullParser.START_TAG) {
+                    try {
+                        tagName = parser.getName();
+                        if (parser.getDepth() == 1 && "op".equals(tagName)) {
+                            // Verify version.
+                            String versionString =
+                                    parser.getAttributeValue(null, XML_ATTR_VERSION);
+                            if (versionString == null ||
+                                    Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
+                                Log.w(TAG, "Unknown pending operation version " + versionString);
+                                throw new java.io.IOException("Unknown version.");
+                            }
+                            int authorityId = Integer.valueOf(parser.getAttributeValue(
+                                    null, XML_ATTR_AUTHORITYID));
+                            boolean expedited = Boolean.valueOf(parser.getAttributeValue(
+                                    null, XML_ATTR_EXPEDITED));
+                            int syncSource = Integer.valueOf(parser.getAttributeValue(
+                                    null, XML_ATTR_SOURCE));
+                            int reason = Integer.valueOf(parser.getAttributeValue(
+                                    null, XML_ATTR_REASON));
+                            AuthorityInfo authority = mAuthorities.get(authorityId);
+                            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                                Log.v(TAG_FILE, authorityId + " " + expedited + " " + syncSource + " "
+                                        + reason);
+                            }
+                            if (authority != null) {
+                                pop = new PendingOperation(
+                                        authority.account, authority.userId, reason,
+                                        syncSource, authority.authority, new Bundle(),
+                                        expedited);
+                                pop.flatExtras = null; // No longer used.
+                                mPendingOperations.add(pop);
+                                if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                                    Log.v(TAG_FILE, "Adding pending op: "
+                                            + pop.authority
+                                            + " src=" + pop.syncSource
+                                            + " reason=" + pop.reason
+                                            + " expedited=" + pop.expedited);
+                                }
+                            } else {
+                                // Skip non-existent authority.
+                                pop = null;
+                                if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                                    Log.v(TAG_FILE, "No authority found for " + authorityId
+                                            + ", skipping");
+                                }
+                            }
+                        } else if (parser.getDepth() == 2 &&
+                                pop != null &&
+                                "extra".equals(tagName)) {
+                            parseExtra(parser, pop.extras);
+                        }
+                    } catch (NumberFormatException e) {
+                        Log.d(TAG, "Invalid data in xml file.", e);
+                    }
+                }
+                eventType = parser.next();
+            } while(eventType != XmlPullParser.END_DOCUMENT);
         } catch (java.io.IOException e) {
-            Log.i(TAG, "No initial pending operations");
+            Log.w(TAG_FILE, "Error reading pending data.", e);
+        } catch (XmlPullParserException e) {
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.w(TAG_FILE, "Error parsing pending ops xml.", e);
+            }
+        } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (java.io.IOException e1) {}
+            }
         }
     }
 
-    private void writePendingOperationLocked(PendingOperation op, Parcel out) {
-        out.writeInt(PENDING_OPERATION_VERSION);
-        out.writeInt(op.authorityId);
-        out.writeInt(op.syncSource);
-        if (op.flatExtras == null && op.extras != null) {
-            op.flatExtras = flattenBundle(op.extras);
-        }
-        out.writeByteArray(op.flatExtras);
-        out.writeInt(op.expedited ? 1 : 0);
-        out.writeInt(op.reason);
-    }
+    private static final String XML_ATTR_AUTHORITYID = "authority_id";
+    private static final String XML_ATTR_SOURCE = "source";
+    private static final String XML_ATTR_EXPEDITED = "expedited";
+    private static final String XML_ATTR_REASON = "reason";
+    private static final String XML_ATTR_VERSION = "version";
 
     /**
      * Write all currently pending ops to the pending ops file.
@@ -2121,22 +2365,24 @@
         FileOutputStream fos = null;
         try {
             if (N == 0) {
-                if (DEBUG_FILE) Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
+                if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                    Log.v(TAG_FILE, "Truncating " + mPendingFile.getBaseFile());
+                }
                 mPendingFile.truncate();
                 return;
             }
-
-            if (DEBUG_FILE) Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
-            fos = mPendingFile.startWrite();
-
-            Parcel out = Parcel.obtain();
-            for (int i=0; i<N; i++) {
-                PendingOperation op = mPendingOperations.get(i);
-                writePendingOperationLocked(op, out);
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.v(TAG_FILE, "Writing new " + mPendingFile.getBaseFile());
             }
-            fos.write(out.marshall());
-            out.recycle();
+            fos = mPendingFile.startWrite();
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, "utf-8");
 
+            for (int i = 0; i < N; i++) {
+                PendingOperation pop = mPendingOperations.get(i);
+                writePendingOperationLocked(pop, out);
+            }
+            out.endDocument();
             mPendingFile.finishWrite(fos);
         } catch (java.io.IOException e1) {
             Log.w(TAG, "Error writing pending operations", e1);
@@ -2146,33 +2392,54 @@
         }
     }
 
+    /** Write all currently pending ops to the pending ops file. */
+     private void writePendingOperationLocked(PendingOperation pop, XmlSerializer out)
+             throws IOException {
+         // Pending operation.
+         out.startTag(null, "op");
+
+         out.attribute(null, XML_ATTR_VERSION, Integer.toString(PENDING_OPERATION_VERSION));
+         out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
+         out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
+         out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
+         out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
+         extrasToXml(out, pop.extras);
+
+         out.endTag(null, "op");
+     }
+
     /**
      * Append the given operation to the pending ops file; if unable to,
      * write all pending ops.
      */
     private void appendPendingOperationLocked(PendingOperation op) {
-        if (DEBUG_FILE) Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
+        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+            Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
+        }
         FileOutputStream fos = null;
         try {
             fos = mPendingFile.openAppend();
         } catch (java.io.IOException e) {
-            if (DEBUG_FILE) Log.v(TAG, "Failed append; writing full file");
+            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                Log.v(TAG, "Failed append; writing full file");
+            }
             writePendingOperationsLocked();
             return;
         }
 
         try {
-            Parcel out = Parcel.obtain();
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, "utf-8");
             writePendingOperationLocked(op, out);
-            fos.write(out.marshall());
-            out.recycle();
+            out.endDocument();
+            mPendingFile.finishWrite(fos);
         } catch (java.io.IOException e1) {
-            Log.w(TAG, "Error writing pending operations", e1);
+            Log.w(TAG, "Error writing appending operation", e1);
+            mPendingFile.failWrite(fos);
         } finally {
             try {
                 fos.close();
-            } catch (java.io.IOException e2) {
-            }
+            } catch (IOException e) {}
         }
     }
 
@@ -2205,6 +2472,38 @@
         return bundle;
     }
 
+    private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
+        for (String key : extras.keySet()) {
+            out.startTag(null, "extra");
+            out.attribute(null, "name", key);
+            final Object value = extras.get(key);
+            if (value instanceof Long) {
+                out.attribute(null, "type", "long");
+                out.attribute(null, "value1", value.toString());
+            } else if (value instanceof Integer) {
+                out.attribute(null, "type", "integer");
+                out.attribute(null, "value1", value.toString());
+            } else if (value instanceof Boolean) {
+                out.attribute(null, "type", "boolean");
+                out.attribute(null, "value1", value.toString());
+            } else if (value instanceof Float) {
+                out.attribute(null, "type", "float");
+                out.attribute(null, "value1", value.toString());
+            } else if (value instanceof Double) {
+                out.attribute(null, "type", "double");
+                out.attribute(null, "value1", value.toString());
+            } else if (value instanceof String) {
+                out.attribute(null, "type", "string");
+                out.attribute(null, "value1", value.toString());
+            } else if (value instanceof Account) {
+                out.attribute(null, "type", "account");
+                out.attribute(null, "value1", ((Account)value).name);
+                out.attribute(null, "value2", ((Account)value).type);
+            }
+            out.endTag(null, "extra");
+        }
+    }
+
     private void requestSync(Account account, int userId, int reason, String authority,
             Bundle extras) {
         // If this is happening in the system process, then call the syncrequest listener
@@ -2265,7 +2564,9 @@
      * Write all sync statistics to the sync status file.
      */
     private void writeStatisticsLocked() {
-        if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
+        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+            Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
+        }
 
         // The file is being written, so we don't need to have a scheduled
         // write until the next change.
@@ -2300,4 +2601,18 @@
             }
         }
     }
+
+    /**
+     * Dump state of PendingOperations.
+     */
+    public void dumpPendingOperations(StringBuilder sb) {
+        sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
+        for (PendingOperation pop : mPendingOperations) {
+            sb.append("(" + pop.account)
+                .append(", u" + pop.userId)
+                .append(", " + pop.authority)
+                .append(", " + pop.extras)
+                .append(")\n");
+        }
+    }
 }
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index 247d8a0..11c5d87 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -61,6 +61,23 @@
     public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1 << 3;
 
     /**
+     * Flag: Indicates that the display device is owned by a particular application
+     * and that no other application should be able to interact with it.
+     */
+    public static final int FLAG_PRIVATE = 1 << 4;
+
+    /**
+     * Flag: Indicates that the display device is not blanked automatically by
+     * the power manager.
+     */
+    public static final int FLAG_NEVER_BLANK = 1 << 5;
+
+    /**
+     * Flag: Indicates that the display is suitable for presentations.
+     */
+    public static final int FLAG_PRESENTATION = 1 << 6;
+
+    /**
      * Touch attachment: Display does not receive touch.
      */
     public static final int TOUCH_NONE = 0;
@@ -150,6 +167,23 @@
      */
     public String address;
 
+    /**
+     * The UID of the application that owns this display, or zero if it is owned by the system.
+     * <p>
+     * If the display is private, then only the owner can use it.
+     * </p>
+     */
+    public int ownerUid;
+
+    /**
+     * The package name of the application that owns this display, or null if it is
+     * owned by the system.
+     * <p>
+     * If the display is private, then only the owner can use it.
+     * </p>
+     */
+    public String ownerPackageName;
+
     public void setAssumedDensityForExternalDisplay(int width, int height) {
         densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
         // Technically, these values should be smaller than the apparent density
@@ -176,7 +210,9 @@
                 && touch == other.touch
                 && rotation == other.rotation
                 && type == other.type
-                && Objects.equal(address, other.address);
+                && Objects.equal(address, other.address)
+                && ownerUid == other.ownerUid
+                && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
 
     @Override
@@ -197,19 +233,32 @@
         rotation = other.rotation;
         type = other.type;
         address = other.address;
+        ownerUid = other.ownerUid;
+        ownerPackageName = other.ownerPackageName;
     }
 
     // For debugging purposes
     @Override
     public String toString() {
-        return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", "
-                + refreshRate + " fps, "
-                + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"
-                + ", touch " + touchToString(touch) + flagsToString(flags)
-                + ", rotation " + rotation
-                + ", type " + Display.typeToString(type)
-                + ", address " + address
-                + "}";
+        StringBuilder sb = new StringBuilder();
+        sb.append("DisplayDeviceInfo{\"");
+        sb.append(name).append("\": ").append(width).append(" x ").append(height);
+        sb.append(", ").append(refreshRate).append(" fps, ");
+        sb.append("density ").append(densityDpi);
+        sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
+        sb.append(", touch ").append(touchToString(touch));
+        sb.append(", rotation ").append(rotation);
+        sb.append(", type ").append(Display.typeToString(type));
+        if (address != null) {
+            sb.append(", address ").append(address);
+        }
+        if (ownerUid != 0 || ownerPackageName != null) {
+            sb.append(", owner ").append(ownerPackageName);
+            sb.append(" (uid ").append(ownerUid).append(")");
+        }
+        sb.append(flagsToString(flags));
+        sb.append("}");
+        return sb.toString();
     }
 
     private static String touchToString(int touch) {
@@ -239,6 +288,15 @@
         if ((flags & FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
             msg.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
         }
+        if ((flags & FLAG_PRIVATE) != 0) {
+            msg.append(", FLAG_PRIVATE");
+        }
+        if ((flags & FLAG_NEVER_BLANK) != 0) {
+            msg.append(", FLAG_NEVER_BLANK");
+        }
+        if ((flags & FLAG_PRESENTATION) != 0) {
+            msg.append(", FLAG_PRESENTATION");
+        }
         return msg.toString();
     }
 }
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 17b0662..249c8b0 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.IDisplayManager;
 import android.hardware.display.IDisplayManagerCallback;
@@ -33,14 +34,19 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Surface;
+
+import com.android.server.UiThread;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -148,9 +154,6 @@
     // List of all currently connected display devices.
     private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
 
-    // List of all removed display devices.
-    private final ArrayList<DisplayDevice> mRemovedDisplayDevices = new ArrayList<DisplayDevice>();
-
     // List of all logical displays indexed by logical display id.
     private final SparseArray<LogicalDisplay> mLogicalDisplays =
             new SparseArray<LogicalDisplay>();
@@ -170,6 +173,9 @@
     // The Wifi display adapter, or null if not registered.
     private WifiDisplayAdapter mWifiDisplayAdapter;
 
+    // The virtual display adapter, or null if not registered.
+    private VirtualDisplayAdapter mVirtualDisplayAdapter;
+
     // Viewports of the default display and the display that should receive touch
     // input from an external source.  Used by the input system.
     private final DisplayViewport mDefaultViewport = new DisplayViewport();
@@ -190,12 +196,12 @@
     private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
     private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
 
-    public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
+    public DisplayManagerService(Context context, Handler mainHandler) {
         mContext = context;
         mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
 
         mHandler = new DisplayManagerHandler(mainHandler.getLooper());
-        mUiHandler = uiHandler;
+        mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
 
@@ -305,6 +311,9 @@
      * to the display information synchronously so that applications will immediately
      * observe the new state.
      *
+     * NOTE: This method must be the only entry point by which the window manager
+     * influences the logical configuration of displays.
+     *
      * @param displayId The logical display id.
      * @param info The new data to be stored.
      */
@@ -313,9 +322,7 @@
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplays.get(displayId);
             if (display != null) {
-                mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
-                display.setDisplayInfoOverrideFromWindowManagerLocked(info);
-                if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
+                if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
                     sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
                     scheduleTraversalLocked(false);
                 }
@@ -324,18 +331,6 @@
     }
 
     /**
-     * Sets the overscan insets for a particular display.
-     */
-    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
-        synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplays.get(displayId);
-            if (display != null) {
-                display.setOverscan(left, top, right, bottom);
-            }
-        }
-    }
-
-    /**
      * Called by the window manager to perform traversals while holding a
      * surface flinger transaction.
      */
@@ -362,13 +357,7 @@
         synchronized (mSyncRoot) {
             if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
                 mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
-
-                final int count = mDisplayDevices.size();
-                for (int i = 0; i < count; i++) {
-                    DisplayDevice device = mDisplayDevices.get(i);
-                    device.blankLocked();
-                }
-
+                updateAllDisplayBlankingLocked();
                 scheduleTraversalLocked(false);
             }
         }
@@ -381,13 +370,7 @@
         synchronized (mSyncRoot) {
             if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
                 mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
-
-                final int count = mDisplayDevices.size();
-                for (int i = 0; i < count; i++) {
-                    DisplayDevice device = mDisplayDevices.get(i);
-                    device.unblankLocked();
-                }
-
+                updateAllDisplayBlankingLocked();
                 scheduleTraversalLocked(false);
             }
         }
@@ -402,12 +385,21 @@
      */
     @Override // Binder call
     public DisplayInfo getDisplayInfo(int displayId) {
-        synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplays.get(displayId);
-            if (display != null) {
-                return display.getDisplayInfoLocked();
+        final int callingUid = Binder.getCallingUid();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                LogicalDisplay display = mLogicalDisplays.get(displayId);
+                if (display != null) {
+                    DisplayInfo info = display.getDisplayInfoLocked();
+                    if (info.hasAccess(callingUid)) {
+                        return info;
+                    }
+                }
+                return null;
             }
-            return null;
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
@@ -416,13 +408,27 @@
      */
     @Override // Binder call
     public int[] getDisplayIds() {
-        synchronized (mSyncRoot) {
-            final int count = mLogicalDisplays.size();
-            int[] displayIds = new int[count];
-            for (int i = 0; i < count; i++) {
-                displayIds[i] = mLogicalDisplays.keyAt(i);
+        final int callingUid = Binder.getCallingUid();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                final int count = mLogicalDisplays.size();
+                int[] displayIds = new int[count];
+                int n = 0;
+                for (int i = 0; i < count; i++) {
+                    LogicalDisplay display = mLogicalDisplays.valueAt(i);
+                    DisplayInfo info = display.getDisplayInfoLocked();
+                    if (info.hasAccess(callingUid)) {
+                        displayIds[n++] = mLogicalDisplays.keyAt(i);
+                    }
+                }
+                if (n != count) {
+                    displayIds = Arrays.copyOfRange(displayIds, 0, n);
+                }
+                return displayIds;
             }
-            return displayIds;
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
@@ -491,6 +497,48 @@
         }
     }
 
+    @Override
+    public void pauseWifiDisplay() {
+        if (mContext.checkCallingPermission(
+                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                        != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
+                    + "permission to pause a wifi display session.");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestPauseLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public void resumeWifiDisplay() {
+        if (mContext.checkCallingPermission(
+                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                        != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
+                    + "permission to resume a wifi display session.");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestResumeLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @Override // Binder call
     public void disconnectWifiDisplay() {
         final long token = Binder.clearCallingIdentity();
@@ -569,6 +617,114 @@
                 == PackageManager.PERMISSION_GRANTED;
     }
 
+    @Override // Binder call
+    public int createVirtualDisplay(IBinder appToken, String packageName,
+            String name, int width, int height, int densityDpi, Surface surface, int flags) {
+        final int callingUid = Binder.getCallingUid();
+        if (!validatePackageName(callingUid, packageName)) {
+            throw new SecurityException("packageName must match the calling uid");
+        }
+        if (appToken == null) {
+            throw new IllegalArgumentException("appToken must not be null");
+        }
+        if (TextUtils.isEmpty(name)) {
+            throw new IllegalArgumentException("name must be non-null and non-empty");
+        }
+        if (width <= 0 || height <= 0 || densityDpi <= 0) {
+            throw new IllegalArgumentException("width, height, and densityDpi must be "
+                    + "greater than 0");
+        }
+        if (surface == null) {
+            throw new IllegalArgumentException("surface must not be null");
+        }
+        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+            if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
+                    != PackageManager.PERMISSION_GRANTED
+                    && mContext.checkCallingPermission(
+                            android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                            != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                        + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
+                        + "public virtual display.");
+            }
+        }
+        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
+                        + "to create a secure virtual display.");
+            }
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mVirtualDisplayAdapter == null) {
+                    Slog.w(TAG, "Rejecting request to create private virtual display "
+                            + "because the virtual display adapter is not available.");
+                    return -1;
+                }
+
+                DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+                        appToken, callingUid, packageName, name, width, height, densityDpi,
+                        surface, flags);
+                if (device == null) {
+                    return -1;
+                }
+
+                handleDisplayDeviceAddedLocked(device);
+                LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+                if (display != null) {
+                    return display.getDisplayIdLocked();
+                }
+
+                // Something weird happened and the logical display was not created.
+                Slog.w(TAG, "Rejecting request to create virtual display "
+                        + "because the logical display was not created.");
+                mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+                handleDisplayDeviceRemovedLocked(device);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return -1;
+    }
+
+    @Override // Binder call
+    public void releaseVirtualDisplay(IBinder appToken) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mVirtualDisplayAdapter == null) {
+                    return;
+                }
+
+                DisplayDevice device =
+                        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+                if (device != null) {
+                    handleDisplayDeviceRemovedLocked(device);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private boolean validatePackageName(int uid, String packageName) {
+        if (packageName != null) {
+            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+            if (packageNames != null) {
+                for (String n : packageNames) {
+                    if (n.equals(packageName)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     private void registerDefaultDisplayAdapter() {
         // Register default display adapter.
         synchronized (mSyncRoot) {
@@ -587,6 +743,7 @@
             if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
                 registerOverlayDisplayAdapterLocked();
                 registerWifiDisplayAdapterLocked();
+                registerVirtualDisplayAdapterLocked();
             }
         }
     }
@@ -607,6 +764,12 @@
         }
     }
 
+    private void registerVirtualDisplayAdapterLocked() {
+        mVirtualDisplayAdapter = new VirtualDisplayAdapter(
+                mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
+        registerDisplayAdapterLocked(mVirtualDisplayAdapter);
+    }
+
     private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
         // In safe mode, we disable non-essential display adapters to give the user
         // an opportunity to fix broken settings or other problems that might affect
@@ -624,31 +787,25 @@
 
     private void handleDisplayDeviceAdded(DisplayDevice device) {
         synchronized (mSyncRoot) {
-            if (mDisplayDevices.contains(device)) {
-                Slog.w(TAG, "Attempted to add already added display device: "
-                        + device.getDisplayDeviceInfoLocked());
-                return;
-            }
-
-            Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
-
-            mDisplayDevices.add(device);
-            addLogicalDisplayLocked(device);
-            scheduleTraversalLocked(false);
-
-            // Blank or unblank the display immediately to match the state requested
-            // by the power manager (if known).
-            switch (mAllDisplayBlankStateFromPowerManager) {
-                case DISPLAY_BLANK_STATE_BLANKED:
-                    device.blankLocked();
-                    break;
-                case DISPLAY_BLANK_STATE_UNBLANKED:
-                    device.unblankLocked();
-                    break;
-            }
+            handleDisplayDeviceAddedLocked(device);
         }
     }
 
+    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
+        if (mDisplayDevices.contains(device)) {
+            Slog.w(TAG, "Attempted to add already added display device: "
+                    + device.getDisplayDeviceInfoLocked());
+            return;
+        }
+
+        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
+
+        mDisplayDevices.add(device);
+        addLogicalDisplayLocked(device);
+        updateDisplayBlankingLocked(device);
+        scheduleTraversalLocked(false);
+    }
+
     private void handleDisplayDeviceChanged(DisplayDevice device) {
         synchronized (mSyncRoot) {
             if (!mDisplayDevices.contains(device)) {
@@ -668,17 +825,43 @@
 
     private void handleDisplayDeviceRemoved(DisplayDevice device) {
         synchronized (mSyncRoot) {
-            if (!mDisplayDevices.remove(device)) {
-                Slog.w(TAG, "Attempted to remove non-existent display device: "
-                        + device.getDisplayDeviceInfoLocked());
-                return;
+            handleDisplayDeviceRemovedLocked(device);
+        }
+    }
+    private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
+        if (!mDisplayDevices.remove(device)) {
+            Slog.w(TAG, "Attempted to remove non-existent display device: "
+                    + device.getDisplayDeviceInfoLocked());
+            return;
+        }
+
+        Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
+
+        updateLogicalDisplaysLocked();
+        scheduleTraversalLocked(false);
+    }
+
+    private void updateAllDisplayBlankingLocked() {
+        final int count = mDisplayDevices.size();
+        for (int i = 0; i < count; i++) {
+            DisplayDevice device = mDisplayDevices.get(i);
+            updateDisplayBlankingLocked(device);
+        }
+    }
+
+    private void updateDisplayBlankingLocked(DisplayDevice device) {
+        // Blank or unblank the display immediately to match the state requested
+        // by the power manager (if known).
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
+            switch (mAllDisplayBlankStateFromPowerManager) {
+                case DISPLAY_BLANK_STATE_BLANKED:
+                    device.blankLocked();
+                    break;
+                case DISPLAY_BLANK_STATE_UNBLANKED:
+                    device.unblankLocked();
+                    break;
             }
-
-            Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
-
-            mRemovedDisplayDevices.add(device);
-            updateLogicalDisplaysLocked();
-            scheduleTraversalLocked(false);
         }
     }
 
@@ -755,14 +938,6 @@
     }
 
     private void performTraversalInTransactionLocked() {
-        // Perform one last traversal for each removed display device.
-        final int removedCount = mRemovedDisplayDevices.size();
-        for (int i = 0; i < removedCount; i++) {
-            DisplayDevice device = mRemovedDisplayDevices.get(i);
-            device.performTraversalInTransactionLocked();
-        }
-        mRemovedDisplayDevices.clear();
-
         // Clear all viewports before configuring displays so that we can keep
         // track of which ones we have configured.
         clearViewportsLocked();
@@ -799,6 +974,11 @@
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplays.get(displayId);
             if (display != null && display.hasContentLocked() != hasContent) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
+                            + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
+                }
+
                 display.setHasContentLocked(hasContent);
                 scheduleTraversalLocked(inTraversal);
             }
@@ -811,13 +991,21 @@
     }
 
     private void configureDisplayInTransactionLocked(DisplayDevice device) {
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        boolean isPrivate = (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0;
+
         // Find the logical display that the display device is showing.
+        // Private displays never mirror other displays.
         LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
-        if (display != null && !display.hasContentLocked()) {
-            display = null;
-        }
-        if (display == null) {
-            display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
+        if (!isPrivate) {
+            if (display != null && !display.hasContentLocked()) {
+                // If the display does not have any content of its own, then
+                // automatically mirror the default logical display contents.
+                display = null;
+            }
+            if (display == null) {
+                display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
+            }
         }
 
         // Apply the logical display configuration to the display device.
@@ -827,11 +1015,11 @@
                     + device.getDisplayDeviceInfoLocked());
             return;
         }
-        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED);
+        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
+                && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
         display.configureDisplayInTransactionLocked(device, isBlanked);
 
         // Update the viewports if needed.
-        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if (!mDefaultViewport.valid
                 && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
             setViewportLocked(mDefaultViewport, display, device);
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 475f27b..cb8f3e2 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -155,6 +155,7 @@
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
                 } else {
                     mInfo.type = Display.TYPE_HDMI;
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_hdmi_display_name);
                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 424ec36..7e357c0 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -128,32 +128,24 @@
      *
      * @param info The logical display information, may be null.
      */
-    public void setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
+    public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
         if (info != null) {
             if (mOverrideDisplayInfo == null) {
                 mOverrideDisplayInfo = new DisplayInfo(info);
                 mInfo = null;
-            } else if (!mOverrideDisplayInfo.equals(info)) {
+                return true;
+            }
+            if (!mOverrideDisplayInfo.equals(info)) {
                 mOverrideDisplayInfo.copyFrom(info);
                 mInfo = null;
+                return true;
             }
         } else if (mOverrideDisplayInfo != null) {
             mOverrideDisplayInfo = null;
             mInfo = null;
+            return true;
         }
-    }
-
-    public void setOverscan(int left, int top, int right, int bottom) {
-        mInfo.overscanLeft = left;
-        mInfo.overscanTop = top;
-        mInfo.overscanRight = right;
-        mInfo.overscanBottom = bottom;
-        if (mOverrideDisplayInfo != null) {
-            mOverrideDisplayInfo.overscanLeft = left;
-            mOverrideDisplayInfo.overscanTop = top;
-            mOverrideDisplayInfo.overscanRight = right;
-            mOverrideDisplayInfo.overscanBottom = bottom;
-        }
+        return false;
     }
 
     /**
@@ -202,6 +194,12 @@
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SECURE) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_SECURE;
             }
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE;
+            }
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
+            }
             mBaseDisplayInfo.type = deviceInfo.type;
             mBaseDisplayInfo.address = deviceInfo.address;
             mBaseDisplayInfo.name = deviceInfo.name;
@@ -218,6 +216,8 @@
             mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
             mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
             mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
+            mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
+            mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
 
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo = null;
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index a18352c..007acf7 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -59,7 +59,7 @@
     private static final int MAX_HEIGHT = 4096;
 
     private static final Pattern SETTING_PATTERN =
-            Pattern.compile("(\\d+)x(\\d+)/(\\d+)");
+            Pattern.compile("(\\d+)x(\\d+)/(\\d+)(,[a-z]+)*");
 
     private final Handler mUiHandler;
     private final ArrayList<OverlayDisplayHandle> mOverlays =
@@ -143,6 +143,7 @@
                     int width = Integer.parseInt(matcher.group(1), 10);
                     int height = Integer.parseInt(matcher.group(2), 10);
                     int densityDpi = Integer.parseInt(matcher.group(3), 10);
+                    String flagString = matcher.group(4);
                     if (width >= MIN_WIDTH && width <= MAX_WIDTH
                             && height >= MIN_HEIGHT && height <= MAX_HEIGHT
                             && densityDpi >= DisplayMetrics.DENSITY_LOW
@@ -152,13 +153,14 @@
                                 com.android.internal.R.string.display_manager_overlay_display_name,
                                 number);
                         int gravity = chooseOverlayGravity(number);
+                        boolean secure = flagString != null && flagString.contains(",secure");
 
                         Slog.i(TAG, "Showing overlay display device #" + number
                                 + ": name=" + name + ", width=" + width + ", height=" + height
-                                + ", densityDpi=" + densityDpi);
+                                + ", densityDpi=" + densityDpi + ", secure=" + secure);
 
                         mOverlays.add(new OverlayDisplayHandle(name,
-                                width, height, densityDpi, gravity));
+                                width, height, densityDpi, gravity, secure));
                         continue;
                     }
                 } catch (NumberFormatException ex) {
@@ -190,13 +192,14 @@
         private final int mHeight;
         private final float mRefreshRate;
         private final int mDensityDpi;
+        private final boolean mSecure;
 
         private Surface mSurface;
         private SurfaceTexture mSurfaceTexture;
         private DisplayDeviceInfo mInfo;
 
         public OverlayDisplayDevice(IBinder displayToken, String name,
-                int width, int height, float refreshRate, int densityDpi,
+                int width, int height, float refreshRate, int densityDpi, boolean secure,
                 SurfaceTexture surfaceTexture) {
             super(OverlayDisplayAdapter.this, displayToken);
             mName = name;
@@ -204,14 +207,17 @@
             mHeight = height;
             mRefreshRate = refreshRate;
             mDensityDpi = densityDpi;
+            mSecure = secure;
             mSurfaceTexture = surfaceTexture;
         }
 
-        public void clearSurfaceTextureLocked() {
-            if (mSurfaceTexture != null) {
-                mSurfaceTexture = null;
+        public void destroyLocked() {
+            mSurfaceTexture = null;
+            if (mSurface != null) {
+                mSurface.release();
+                mSurface = null;
             }
-            sendTraversalRequestLocked();
+            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
         }
 
         @Override
@@ -221,12 +227,6 @@
                     mSurface = new Surface(mSurfaceTexture);
                 }
                 setSurfaceInTransactionLocked(mSurface);
-            } else {
-                setSurfaceInTransactionLocked(null);
-                if (mSurface != null) {
-                    mSurface.destroy();
-                    mSurface = null;
-                }
             }
         }
 
@@ -241,7 +241,10 @@
                 mInfo.densityDpi = mDensityDpi;
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
-                mInfo.flags = 0;
+                mInfo.flags = DisplayDeviceInfo.FLAG_PRESENTATION;
+                if (mSecure) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
+                }
                 mInfo.type = Display.TYPE_OVERLAY;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
             }
@@ -261,17 +264,19 @@
         private final int mHeight;
         private final int mDensityDpi;
         private final int mGravity;
+        private final boolean mSecure;
 
         private OverlayDisplayWindow mWindow;
         private OverlayDisplayDevice mDevice;
 
         public OverlayDisplayHandle(String name,
-                int width, int height, int densityDpi, int gravity) {
+                int width, int height, int densityDpi, int gravity, boolean secure) {
             mName = name;
             mWidth = width;
             mHeight = height;
             mDensityDpi = densityDpi;
             mGravity = gravity;
+            mSecure = secure;
 
             mUiHandler.post(mShowRunnable);
         }
@@ -285,9 +290,9 @@
         @Override
         public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
             synchronized (getSyncRoot()) {
-                IBinder displayToken = SurfaceControl.createDisplay(mName, false);
+                IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
-                        mWidth, mHeight, refreshRate, mDensityDpi, surfaceTexture);
+                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture);
 
                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
             }
@@ -298,7 +303,7 @@
         public void onWindowDestroyed() {
             synchronized (getSyncRoot()) {
                 if (mDevice != null) {
-                    mDevice.clearSurfaceTextureLocked();
+                    mDevice.destroyLocked();
                     sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
                 }
             }
@@ -310,6 +315,7 @@
             pw.println("    mHeight=" + mHeight);
             pw.println("    mDensityDpi=" + mDensityDpi);
             pw.println("    mGravity=" + mGravity);
+            pw.println("    mSecure=" + mSecure);
 
             // Try to dump the window state.
             if (mWindow != null) {
@@ -324,7 +330,7 @@
             @Override
             public void run() {
                 OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),
-                        mName, mWidth, mHeight, mDensityDpi, mGravity,
+                        mName, mWidth, mHeight, mDensityDpi, mGravity, mSecure,
                         OverlayDisplayHandle.this);
                 window.show();
 
diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/java/com/android/server/display/OverlayDisplayWindow.java
index a0edced..f1dd60a 100644
--- a/services/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/java/com/android/server/display/OverlayDisplayWindow.java
@@ -64,8 +64,9 @@
     private final int mHeight;
     private final int mDensityDpi;
     private final int mGravity;
+    private final boolean mSecure;
     private final Listener mListener;
-    private final String mTitle;
+    private String mTitle;
 
     private final DisplayManager mDisplayManager;
     private final WindowManager mWindowManager;
@@ -92,17 +93,23 @@
     private float mLiveScale = 1.0f;
 
     public OverlayDisplayWindow(Context context, String name,
-            int width, int height, int densityDpi, int gravity, Listener listener) {
+            int width, int height, int densityDpi, int gravity, boolean secure,
+            Listener listener) {
         mContext = context;
         mName = name;
         mWidth = width;
         mHeight = height;
         mDensityDpi = densityDpi;
         mGravity = gravity;
+        mSecure = secure;
         mListener = listener;
         mTitle = context.getResources().getString(
                 com.android.internal.R.string.display_manager_overlay_display_title,
                 mName, mWidth, mHeight, mDensityDpi);
+        if (secure) {
+            mTitle += context.getResources().getString(
+                    com.android.internal.R.string.display_manager_overlay_display_secure_suffix);
+        }
 
         mDisplayManager = (DisplayManager)context.getSystemService(
                 Context.DISPLAY_SERVICE);
@@ -197,6 +204,9 @@
                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        if (mSecure) {
+            mWindowParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+        }
         if (DISABLE_MOVE_AND_RESIZE) {
             mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
         }
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
index 105c253..67b3695 100644
--- a/services/java/com/android/server/display/PersistentDataStore.java
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -105,7 +105,8 @@
                 alias = mRememberedWifiDisplays.get(index).getDeviceAlias();
             }
             if (!Objects.equal(display.getDeviceAlias(), alias)) {
-                return new WifiDisplay(display.getDeviceAddress(), display.getDeviceName(), alias);
+                return new WifiDisplay(display.getDeviceAddress(), display.getDeviceName(),
+                        alias, display.isAvailable(), display.canConnect(), display.isRemembered());
             }
         }
         return display;
@@ -259,7 +260,8 @@
                 }
 
                 mRememberedWifiDisplays.add(
-                        new WifiDisplay(deviceAddress, deviceName, deviceAlias));
+                        new WifiDisplay(deviceAddress, deviceName, deviceAlias,
+                                false, false, false));
             }
         }
     }
diff --git a/services/java/com/android/server/display/VirtualDisplayAdapter.java b/services/java/com/android/server/display/VirtualDisplayAdapter.java
new file mode 100644
index 0000000..46d473c
--- /dev/null
+++ b/services/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -0,0 +1,177 @@
+/*
+ * 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.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+/**
+ * A display adapter that provides virtual displays on behalf of applications.
+ * <p>
+ * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
+ * </p>
+ */
+final class VirtualDisplayAdapter extends DisplayAdapter {
+    static final String TAG = "VirtualDisplayAdapter";
+    static final boolean DEBUG = false;
+
+    private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices =
+            new ArrayMap<IBinder, VirtualDisplayDevice>();
+
+    // Called with SyncRoot lock held.
+    public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
+            Context context, Handler handler, Listener listener) {
+        super(syncRoot, context, handler, listener, TAG);
+    }
+
+    public DisplayDevice createVirtualDisplayLocked(IBinder appToken,
+            int ownerUid, String ownerPackageName,
+            String name, int width, int height, int densityDpi, Surface surface, int flags) {
+        boolean secure = (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
+        IBinder displayToken = SurfaceControl.createDisplay(name, secure);
+        VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
+                ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags);
+
+        try {
+            appToken.linkToDeath(device, 0);
+        } catch (RemoteException ex) {
+            device.destroyLocked();
+            return null;
+        }
+
+        mVirtualDisplayDevices.put(appToken, device);
+
+        // Return the display device without actually sending the event indicating
+        // that it was added.  The caller will handle it.
+        return device;
+    }
+
+    public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
+        VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
+        if (device != null) {
+            device.destroyLocked();
+            appToken.unlinkToDeath(device, 0);
+        }
+
+        // Return the display device that was removed without actually sending the
+        // event indicating that it was removed.  The caller will handle it.
+        return device;
+    }
+
+    private void handleBinderDiedLocked(IBinder appToken) {
+        VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
+        if (device != null) {
+            Slog.i(TAG, "Virtual display device released because application token died: "
+                    + device.mOwnerPackageName);
+            device.destroyLocked();
+            sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
+        }
+    }
+
+    private final class VirtualDisplayDevice extends DisplayDevice
+            implements DeathRecipient {
+        private final IBinder mAppToken;
+        private final int mOwnerUid;
+        final String mOwnerPackageName;
+        private final String mName;
+        private final int mWidth;
+        private final int mHeight;
+        private final int mDensityDpi;
+        private final int mFlags;
+
+        private Surface mSurface;
+        private DisplayDeviceInfo mInfo;
+
+        public VirtualDisplayDevice(IBinder displayToken,
+                IBinder appToken, int ownerUid, String ownerPackageName,
+                String name, int width, int height, int densityDpi, Surface surface, int flags) {
+            super(VirtualDisplayAdapter.this, displayToken);
+            mAppToken = appToken;
+            mOwnerUid = ownerUid;
+            mOwnerPackageName = ownerPackageName;
+            mName = name;
+            mWidth = width;
+            mHeight = height;
+            mDensityDpi = densityDpi;
+            mSurface = surface;
+            mFlags = flags;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (getSyncRoot()) {
+                if (mSurface != null) {
+                    handleBinderDiedLocked(mAppToken);
+                }
+            }
+        }
+
+        public void destroyLocked() {
+            if (mSurface != null) {
+                mSurface.release();
+                mSurface = null;
+            }
+            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
+        }
+
+        @Override
+        public void performTraversalInTransactionLocked() {
+            if (mSurface != null) {
+                setSurfaceInTransactionLocked(mSurface);
+            }
+        }
+
+        @Override
+        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+            if (mInfo == null) {
+                mInfo = new DisplayDeviceInfo();
+                mInfo.name = mName;
+                mInfo.width = mWidth;
+                mInfo.height = mHeight;
+                mInfo.refreshRate = 60;
+                mInfo.densityDpi = mDensityDpi;
+                mInfo.xDpi = mDensityDpi;
+                mInfo.yDpi = mDensityDpi;
+                mInfo.flags = 0;
+                if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE |
+                            DisplayDeviceInfo.FLAG_NEVER_BLANK;
+                }
+                if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
+                }
+                if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
+                }
+                mInfo.type = Display.TYPE_VIRTUAL;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+                mInfo.ownerUid = mOwnerUid;
+                mInfo.ownerPackageName = mOwnerPackageName;
+            }
+            return mInfo;
+        }
+    }
+}
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index b655b3a..f7bbdf8 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplaySessionInfo;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.RemoteDisplay;
 import android.os.Handler;
@@ -45,6 +46,8 @@
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
 
 import libcore.util.Objects;
 
@@ -88,8 +91,10 @@
     private int mScanState;
     private int mActiveDisplayState;
     private WifiDisplay mActiveDisplay;
+    private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
     private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
     private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
+    private WifiDisplaySessionInfo mSessionInfo;
 
     private boolean mPendingStatusChangeBroadcast;
     private boolean mPendingNotificationUpdate;
@@ -116,6 +121,7 @@
         pw.println("mScanState=" + mScanState);
         pw.println("mActiveDisplayState=" + mActiveDisplayState);
         pw.println("mActiveDisplay=" + mActiveDisplay);
+        pw.println("mDisplays=" + Arrays.toString(mDisplays));
         pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
         pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
         pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
@@ -200,6 +206,36 @@
         return false;
     }
 
+    public void requestPauseLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "requestPauseLocked");
+        }
+
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestPause();
+                }
+            }
+        });
+      }
+
+    public void requestResumeLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "requestResumeLocked");
+        }
+
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestResume();
+                }
+            }
+        });
+    }
+
     public void requestDisconnectLocked() {
         if (DEBUG) {
             Slog.d(TAG, "requestDisconnectedLocked");
@@ -229,7 +265,8 @@
 
         WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
         if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
-            display = new WifiDisplay(address, display.getDeviceName(), alias);
+            display = new WifiDisplay(address, display.getDeviceName(), alias,
+                    false, false, false);
             if (mPersistentDataStore.rememberWifiDisplay(display)) {
                 mPersistentDataStore.saveIfNeeded();
                 updateRememberedDisplaysLocked();
@@ -262,7 +299,7 @@
         if (mCurrentStatus == null) {
             mCurrentStatus = new WifiDisplayStatus(
                     mFeatureState, mScanState, mActiveDisplayState,
-                    mActiveDisplay, mAvailableDisplays, mRememberedDisplays);
+                    mActiveDisplay, mDisplays, mSessionInfo);
         }
 
         if (DEBUG) {
@@ -271,10 +308,36 @@
         return mCurrentStatus;
     }
 
+    private void updateDisplaysLocked() {
+        List<WifiDisplay> displays = new ArrayList<WifiDisplay>(
+                mAvailableDisplays.length + mRememberedDisplays.length);
+        boolean[] remembered = new boolean[mAvailableDisplays.length];
+        for (WifiDisplay d : mRememberedDisplays) {
+            boolean available = false;
+            for (int i = 0; i < mAvailableDisplays.length; i++) {
+                if (d.equals(mAvailableDisplays[i])) {
+                    remembered[i] = available = true;
+                    break;
+                }
+            }
+            if (!available) {
+                displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
+                        d.getDeviceAlias(), false, false, true));
+            }
+        }
+        for (int i = 0; i < mAvailableDisplays.length; i++) {
+            WifiDisplay d = mAvailableDisplays[i];
+            displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
+                    d.getDeviceAlias(), true, d.canConnect(), remembered[i]));
+        }
+        mDisplays = displays.toArray(WifiDisplay.EMPTY_ARRAY);
+    }
+
     private void updateRememberedDisplaysLocked() {
         mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
         mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
         mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
+        updateDisplaysLocked();
     }
 
     private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
@@ -321,7 +384,7 @@
         }
 
         boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
-        int deviceFlags = 0;
+        int deviceFlags = DisplayDeviceInfo.FLAG_PRESENTATION;
         if (secure) {
             deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
             if (mSupportsProtectedBuffers) {
@@ -343,7 +406,7 @@
 
     private void removeDisplayDeviceLocked() {
         if (mDisplayDevice != null) {
-            mDisplayDevice.clearSurfaceLocked();
+            mDisplayDevice.destroyLocked();
             sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
             mDisplayDevice = null;
 
@@ -487,11 +550,18 @@
                 availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
                         availableDisplays);
 
-                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
-                        || !Arrays.equals(mAvailableDisplays, availableDisplays)) {
+                // check if any of the available displays changed canConnect status
+                boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
+                for (int i = 0; !changed && i<availableDisplays.length; i++) {
+                    changed = availableDisplays[i].canConnect()
+                            != mAvailableDisplays[i].canConnect();
+                }
+
+                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING || changed) {
                     mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
                     mAvailableDisplays = availableDisplays;
                     fixRememberedDisplayNamesFromAvailableDisplaysLocked();
+                    updateDisplaysLocked();
                     scheduleStatusChangedBroadcastLocked();
                 }
             }
@@ -542,6 +612,14 @@
         }
 
         @Override
+        public void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo) {
+            synchronized (getSyncRoot()) {
+                mSessionInfo = sessionInfo;
+                scheduleStatusChangedBroadcastLocked();
+            }
+        }
+
+        @Override
         public void onDisplayChanged(WifiDisplay display) {
             synchronized (getSyncRoot()) {
                 display = mPersistentDataStore.applyWifiDisplayAlias(display);
@@ -595,9 +673,12 @@
             mSurface = surface;
         }
 
-        public void clearSurfaceLocked() {
-            mSurface = null;
-            sendTraversalRequestLocked();
+        public void destroyLocked() {
+            if (mSurface != null) {
+                mSurface.release();
+                mSurface = null;
+            }
+            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
         }
 
         public void setNameLocked(String name) {
@@ -607,7 +688,9 @@
 
         @Override
         public void performTraversalInTransactionLocked() {
-            setSurfaceInTransactionLocked(mSurface);
+            if (mSurface != null) {
+                setSurfaceInTransactionLocked(mSurface);
+            }
         }
 
         @Override
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 8c8b360..9a4cfb7 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -25,6 +25,7 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplaySessionInfo;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.AudioManager;
 import android.media.RemoteDisplay;
@@ -76,6 +77,7 @@
     private static final int MAX_THROUGHPUT = 50;
     private static final int CONNECTION_TIMEOUT_SECONDS = 60;
     private static final int RTSP_TIMEOUT_SECONDS = 15;
+    private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
 
     private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
     private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
@@ -83,11 +85,6 @@
     private static final int CONNECT_MAX_RETRIES = 3;
     private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
 
-    // A unique token to identify the remote submix that is managed by Wifi display.
-    // It must match what the media server uses when it starts recording the submix
-    // for transmission.  We use 0 although the actual value is currently ignored.
-    private static final int REMOTE_SUBMIX_ADDRESS = 0;
-
     private final Context mContext;
     private final Handler mHandler;
     private final Listener mListener;
@@ -95,8 +92,6 @@
     private final WifiP2pManager mWifiP2pManager;
     private final Channel mWifiP2pChannel;
 
-    private final AudioManager mAudioManager;
-
     private boolean mWifiP2pEnabled;
     private boolean mWfdEnabled;
     private boolean mWfdEnabling;
@@ -146,9 +141,6 @@
     // True if RTSP has connected.
     private boolean mRemoteDisplayConnected;
 
-    // True if the remote submix is enabled.
-    private boolean mRemoteSubmixOn;
-
     // The information we have most recently told WifiDisplayAdapter about.
     private WifiDisplay mAdvertisedDisplay;
     private Surface mAdvertisedDisplaySurface;
@@ -156,6 +148,12 @@
     private int mAdvertisedDisplayHeight;
     private int mAdvertisedDisplayFlags;
 
+    // Certification
+    private boolean mWifiDisplayCertMode;
+    private int mWifiDisplayWpsConfig = WpsInfo.INVALID;
+
+    private WifiP2pDevice mThisDevice;
+
     public WifiDisplayController(Context context, Handler handler, Listener listener) {
         mContext = context;
         mHandler = handler;
@@ -164,12 +162,11 @@
         mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
         mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
 
-        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
-
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
         intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
         intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
         context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
 
         ContentObserver settingsObserver = new ContentObserver(mHandler) {
@@ -182,6 +179,10 @@
         final ContentResolver resolver = mContext.getContentResolver();
         resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver);
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, settingsObserver);
         updateSettings();
     }
 
@@ -189,6 +190,14 @@
         final ContentResolver resolver = mContext.getContentResolver();
         mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
                 Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
+        mWifiDisplayCertMode = Settings.Global.getInt(resolver,
+                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
+
+        mWifiDisplayWpsConfig = WpsInfo.INVALID;
+        if (mWifiDisplayCertMode) {
+            mWifiDisplayWpsConfig = Settings.Global.getInt(resolver,
+                  Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID);
+        }
 
         updateWfdEnableState();
     }
@@ -211,7 +220,6 @@
         pw.println("mRemoteDisplay=" + mRemoteDisplay);
         pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
         pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
-        pw.println("mRemoteSubmixOn=" + mRemoteSubmixOn);
         pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
         pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
         pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
@@ -236,6 +244,18 @@
         }
     }
 
+    public void requestPause() {
+        if (mRemoteDisplay != null) {
+            mRemoteDisplay.pause();
+        }
+    }
+
+    public void requestResume() {
+        if (mRemoteDisplay != null) {
+            mRemoteDisplay.resume();
+        }
+    }
+
     public void requestDisconnect() {
         disconnect();
     }
@@ -276,6 +296,25 @@
             }
         } else {
             // WFD should be disabled.
+            if (mWfdEnabled || mWfdEnabling) {
+                WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
+                wfdInfo.setWfdEnabled(false);
+                mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+                    @Override
+                    public void onSuccess() {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Successfully set WFD info.");
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(int reason) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+                        }
+                    }
+                });
+            }
             mWfdEnabling = false;
             mWfdEnabled = false;
             reportFeatureState();
@@ -482,7 +521,6 @@
             mHandler.removeCallbacks(mRtspTimeout);
 
             mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
-            setRemoteSubmixOn(false);
             unadvertiseDisplay();
 
             // continue to next step
@@ -496,6 +534,7 @@
             Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
             mDisconnectingDevice = mConnectedDevice;
             mConnectedDevice = null;
+            mConnectedDeviceGroupInfo = null;
 
             unadvertiseDisplay();
 
@@ -562,8 +601,12 @@
             return; // wait for asynchronous callback
         }
 
-        // Step 4. If we wanted to disconnect, then mission accomplished.
+        // Step 4. If we wanted to disconnect, or we're updating after starting an
+        // autonomous GO, then mission accomplished.
         if (mDesiredDevice == null) {
+            if (mWifiDisplayCertMode) {
+                mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
+            }
             unadvertiseDisplay();
             return; // done
         }
@@ -575,7 +618,9 @@
             mConnectingDevice = mDesiredDevice;
             WifiP2pConfig config = new WifiP2pConfig();
             WpsInfo wps = new WpsInfo();
-            if (mConnectingDevice.wpsPbcSupported()) {
+            if (mWifiDisplayWpsConfig != WpsInfo.INVALID) {
+                wps.setup = mWifiDisplayWpsConfig;
+            } else if (mConnectingDevice.wpsPbcSupported()) {
                 wps.setup = WpsInfo.PBC;
             } else if (mConnectingDevice.wpsDisplaySupported()) {
                 // We do keypad if peer does display
@@ -626,7 +671,6 @@
                 return; // done
             }
 
-            setRemoteSubmixOn(true);
             mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
 
             final WifiP2pDevice oldDevice = mConnectedDevice;
@@ -640,13 +684,18 @@
             mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
                 @Override
                 public void onDisplayConnected(Surface surface,
-                        int width, int height, int flags) {
+                        int width, int height, int flags, int session) {
                     if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
                         Slog.i(TAG, "Opened RTSP connection with Wifi display: "
                                 + mConnectedDevice.deviceName);
                         mRemoteDisplayConnected = true;
                         mHandler.removeCallbacks(mRtspTimeout);
 
+                        if (mWifiDisplayCertMode) {
+                            mListener.onDisplaySessionInfo(
+                                    getSessionInfo(mConnectedDeviceGroupInfo, session));
+                        }
+
                         final WifiDisplay display = createWifiDisplay(mConnectedDevice);
                         advertiseDisplay(display, surface, width, height, flags);
                     }
@@ -673,15 +722,29 @@
                 }
             }, mHandler);
 
-            mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000);
+            // Use extended timeout value for certification, as some tests require user inputs
+            int rtspTimeout = mWifiDisplayCertMode ?
+                    RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
+
+            mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
         }
     }
 
-    private void setRemoteSubmixOn(boolean on) {
-        if (mRemoteSubmixOn != on) {
-            mRemoteSubmixOn = on;
-            mAudioManager.setRemoteSubmixOn(on, REMOTE_SUBMIX_ADDRESS);
+    private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) {
+        if (info == null) {
+            return null;
         }
+        Inet4Address addr = getInterfaceAddress(info);
+        WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo(
+                !info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress),
+                session,
+                info.getOwner().deviceAddress + " " + info.getNetworkName(),
+                info.getPassphrase(),
+                (addr != null) ? addr.getHostAddress() : "");
+        if (DEBUG) {
+            Slog.d(TAG, sessionInfo.toString());
+        }
+        return sessionInfo;
     }
 
     private void handleStateChanged(boolean enabled) {
@@ -698,7 +761,7 @@
     private void handleConnectionChanged(NetworkInfo networkInfo) {
         mNetworkInfo = networkInfo;
         if (mWfdEnabled && networkInfo.isConnected()) {
-            if (mDesiredDevice != null) {
+            if (mDesiredDevice != null || mWifiDisplayCertMode) {
                 mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
                     @Override
                     public void onGroupInfoAvailable(WifiP2pGroup info) {
@@ -720,6 +783,25 @@
                             return;
                         }
 
+                        if (mWifiDisplayCertMode) {
+                            boolean owner = info.getOwner().deviceAddress
+                                    .equals(mThisDevice.deviceAddress);
+                            if (owner && info.getClientList().isEmpty()) {
+                                // this is the case when we started Autonomous GO,
+                                // and no client has connected, save group info
+                                // and updateConnection()
+                                mConnectingDevice = mDesiredDevice = null;
+                                mConnectedDeviceGroupInfo = info;
+                                updateConnection();
+                            } else if (mConnectingDevice == null && mDesiredDevice == null) {
+                                // this is the case when we received an incoming connection
+                                // from the sink, update both mConnectingDevice and mDesiredDevice
+                                // then proceed to updateConnection() below
+                                mConnectingDevice = mDesiredDevice = owner ?
+                                        info.getClientList().iterator().next() : info.getOwner();
+                            }
+                        }
+
                         if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
                             Slog.i(TAG, "Connected to Wifi display: "
                                     + mConnectingDevice.deviceName);
@@ -734,6 +816,7 @@
                 });
             }
         } else {
+            mConnectedDeviceGroupInfo = null;
             disconnect();
 
             // After disconnection for a group, for some reason we have a tendency
@@ -897,7 +980,8 @@
     }
 
     private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
-        return new WifiDisplay(device.deviceAddress, device.deviceName, null);
+        return new WifiDisplay(device.deviceAddress, device.deviceName, null,
+                true, device.wfdInfo.isSessionAvailable(), false);
     }
 
     private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
@@ -931,6 +1015,13 @@
                 }
 
                 handleConnectionChanged(networkInfo);
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
+                mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
+                        WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
+                if (DEBUG) {
+                    Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= "
+                            + mThisDevice);
+                }
             }
         }
     };
@@ -949,6 +1040,7 @@
         void onDisplayChanged(WifiDisplay display);
         void onDisplayConnected(WifiDisplay display,
                 Surface surface, int width, int height, int flags);
+        void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo);
         void onDisplayDisconnected();
     }
 }
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
index c9e0da5..b6e7781 100644
--- a/services/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -73,7 +73,7 @@
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
     }
 
-    public void systemReady() {
+    public void systemRunning() {
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -86,7 +86,13 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump DreamManager from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
 
         pw.println("DREAM MANAGER (dumpsys dreams)");
         pw.println();
diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/java/com/android/server/firewall/AndFilter.java
index e4276d0..13551de 100644
--- a/services/java/com/android/server/firewall/AndFilter.java
+++ b/services/java/com/android/server/firewall/AndFilter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -25,11 +25,11 @@
 
 class AndFilter extends FilterList {
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
         for (int i=0; i<children.size(); i++) {
-            if (!children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
-                    resolvedApp)) {
+            if (!children.get(i).matches(ifw, resolvedComponent, intent, callerUid, callerPid,
+                    resolvedType, receivingUid)) {
                 return false;
             }
         }
diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/java/com/android/server/firewall/CategoryFilter.java
index 4938cb8..246c096 100644
--- a/services/java/com/android/server/firewall/CategoryFilter.java
+++ b/services/java/com/android/server/firewall/CategoryFilter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -34,8 +34,8 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
         Set<String> categories = intent.getCategories();
         if (categories == null) {
             return false;
diff --git a/services/java/com/android/server/firewall/Filter.java b/services/java/com/android/server/firewall/Filter.java
index 0e783e8..0a124f7 100644
--- a/services/java/com/android/server/firewall/Filter.java
+++ b/services/java/com/android/server/firewall/Filter.java
@@ -16,24 +16,21 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 
 interface Filter {
     /**
      * Does the given intent + context info match this filter?
      *
      * @param ifw The IntentFirewall instance
+     * @param resolvedComponent The actual component that the intent was resolved to
      * @param intent The intent being started/bound/broadcast
-     * @param callerApp An ApplicationInfo of an application in the caller's process. This may not
-     *                  be the specific app that is actually sending the intent. This also may be
-     *                  null, if the caller is the system process, or an unrecognized process (e.g.
-     *                  am start)
-     * @param callerUid
-     * @param callerPid
+     * @param callerUid The uid of the caller
+     * @param callerPid The pid of the caller
      * @param resolvedType The resolved mime type of the intent
-     * @param resolvedApp The application that contains the resolved component that the intent is
+     * @param receivingUid The uid of the component receiving the intent
      */
-    boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp);
+    boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid);
 }
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index 4496aae..aaa0b58 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -20,7 +20,6 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -29,8 +28,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
+import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.Xml;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
@@ -42,15 +43,15 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 
 public class IntentFirewall {
-    private static final String TAG = "IntentFirewall";
+    static final String TAG = "IntentFirewall";
 
-    // e.g. /data/system/ifw/ifw.xml or /data/secure/system/ifw/ifw.xml
-    private static final File RULES_FILE =
-            new File(Environment.getSystemSecureDirectory(), "ifw/ifw.xml");
+    // e.g. /data/system/ifw or /data/secure/system/ifw
+    private static final File RULES_DIR = new File(Environment.getSystemSecureDirectory(), "ifw");
 
     private static final int LOG_PACKAGES_MAX_LENGTH = 150;
     private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
@@ -87,6 +88,7 @@
                 StringFilter.DATA,
                 StringFilter.HOST,
                 StringFilter.MIME_TYPE,
+                StringFilter.SCHEME,
                 StringFilter.PATH,
                 StringFilter.SSP,
 
@@ -106,12 +108,12 @@
 
     public IntentFirewall(AMSInterface ams) {
         mAms = ams;
-        File rulesFile = getRulesFile();
-        rulesFile.getParentFile().mkdirs();
+        File rulesDir = getRulesDir();
+        rulesDir.mkdirs();
 
-        readRules(rulesFile);
+        readRulesDir(rulesDir);
 
-        mObserver = new RuleObserver(rulesFile);
+        mObserver = new RuleObserver(rulesDir);
         mObserver.startWatching();
     }
 
@@ -119,16 +121,45 @@
      * This is called from ActivityManager to check if a start activity intent should be allowed.
      * It is assumed the caller is already holding the global ActivityManagerService lock.
      */
-    public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp, int callerUid,
-            int callerPid, String resolvedType, ActivityInfo resolvedActivity) {
-        List<Rule> matchingRules = mActivityResolver.queryIntent(intent, resolvedType, false, 0);
+    public boolean checkStartActivity(Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
+        return checkIntent(mActivityResolver, intent.getComponent(), TYPE_ACTIVITY, intent,
+                callerUid, callerPid, resolvedType, resolvedApp.uid);
+    }
+
+    public boolean checkService(ComponentName resolvedService, Intent intent, int callerUid,
+            int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        return checkIntent(mServiceResolver, resolvedService, TYPE_SERVICE, intent, callerUid,
+                callerPid, resolvedType, resolvedApp.uid);
+    }
+
+    public boolean checkBroadcast(Intent intent, int callerUid, int callerPid,
+            String resolvedType, int receivingUid) {
+        return checkIntent(mBroadcastResolver, intent.getComponent(), TYPE_BROADCAST, intent,
+                callerUid, callerPid, resolvedType, receivingUid);
+    }
+
+    public boolean checkIntent(FirewallIntentResolver resolver, ComponentName resolvedComponent,
+            int intentType, Intent intent, int callerUid, int callerPid, String resolvedType,
+            int receivingUid) {
         boolean log = false;
         boolean block = false;
 
-        for (int i=0; i< matchingRules.size(); i++) {
-            Rule rule = matchingRules.get(i);
-            if (rule.matches(this, intent, callerApp, callerUid, callerPid, resolvedType,
-                    resolvedActivity.applicationInfo)) {
+        // For the first pass, find all the rules that have at least one intent-filter or
+        // component-filter that matches this intent
+        List<Rule> candidateRules;
+        candidateRules = resolver.queryIntent(intent, resolvedType, false, 0);
+        if (candidateRules == null) {
+            candidateRules = new ArrayList<Rule>();
+        }
+        resolver.queryByComponent(resolvedComponent, candidateRules);
+
+        // For the second pass, try to match the potentially more specific conditions in each
+        // rule against the intent
+        for (int i=0; i<candidateRules.size(); i++) {
+            Rule rule = candidateRules.get(i);
+            if (rule.matches(this, resolvedComponent, intent, callerUid, callerPid, resolvedType,
+                    receivingUid)) {
                 block |= rule.getBlock();
                 log |= rule.getLog();
 
@@ -141,7 +172,7 @@
         }
 
         if (log) {
-            logIntent(TYPE_ACTIVITY, intent, callerUid, resolvedType);
+            logIntent(intentType, intent, callerUid, resolvedType);
         }
 
         return !block;
@@ -216,22 +247,58 @@
         return null;
     }
 
-    public static File getRulesFile() {
-        return RULES_FILE;
+    public static File getRulesDir() {
+        return RULES_DIR;
     }
 
     /**
-     * Reads rules from the given file and replaces our set of rules with the newly read rules
+     * Reads rules from all xml files (*.xml) in the given directory, and replaces our set of rules
+     * with the newly read rules.
+     *
+     * We only check for files ending in ".xml", to allow for temporary files that are atomically
+     * renamed to .xml
      *
      * All calls to this method from the file observer come through a handler and are inherently
      * serialized
      */
-    private void readRules(File rulesFile) {
+    private void readRulesDir(File rulesDir) {
         FirewallIntentResolver[] resolvers = new FirewallIntentResolver[3];
         for (int i=0; i<resolvers.length; i++) {
             resolvers[i] = new FirewallIntentResolver();
         }
 
+        File[] files = rulesDir.listFiles();
+        for (int i=0; i<files.length; i++) {
+            File file = files[i];
+
+            if (file.getName().endsWith(".xml")) {
+                readRules(file, resolvers);
+            }
+        }
+
+        Slog.i(TAG, "Read new rules (A:" + resolvers[TYPE_ACTIVITY].filterSet().size() +
+                " B:" + resolvers[TYPE_BROADCAST].filterSet().size() +
+                " S:" + resolvers[TYPE_SERVICE].filterSet().size() + ")");
+
+        synchronized (mAms.getAMSLock()) {
+            mActivityResolver = resolvers[TYPE_ACTIVITY];
+            mBroadcastResolver = resolvers[TYPE_BROADCAST];
+            mServiceResolver = resolvers[TYPE_SERVICE];
+        }
+    }
+
+    /**
+     * Reads rules from the given file and add them to the given resolvers
+     */
+    private void readRules(File rulesFile, FirewallIntentResolver[] resolvers) {
+        // some temporary lists to hold the rules while we parse the xml file, so that we can
+        // add the rules all at once, after we know there weren't any major structural problems
+        // with the xml file
+        List<List<Rule>> rulesByType = new ArrayList<List<Rule>>(3);
+        for (int i=0; i<3; i++) {
+            rulesByType.add(new ArrayList<Rule>());
+        }
+
         FileInputStream fis;
         try {
             fis = new FileInputStream(rulesFile);
@@ -247,8 +314,6 @@
 
             XmlUtils.beginDocument(parser, TAG_RULES);
 
-            int[] numRules = new int[3];
-
             int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                 int ruleType = -1;
@@ -265,41 +330,28 @@
                 if (ruleType != -1) {
                     Rule rule = new Rule();
 
-                    FirewallIntentResolver resolver = resolvers[ruleType];
+                    List<Rule> rules = rulesByType.get(ruleType);
 
                     // if we get an error while parsing a particular rule, we'll just ignore
                     // that rule and continue on with the next rule
                     try {
                         rule.readFromXml(parser);
                     } catch (XmlPullParserException ex) {
-                        Slog.e(TAG, "Error reading intent firewall rule", ex);
+                        Slog.e(TAG, "Error reading an intent firewall rule from " + rulesFile, ex);
                         continue;
                     }
 
-                    numRules[ruleType]++;
-
-                    for (int i=0; i<rule.getIntentFilterCount(); i++) {
-                        resolver.addFilter(rule.getIntentFilter(i));
-                    }
+                    rules.add(rule);
                 }
             }
-
-            Slog.i(TAG, "Read new rules (A:" + numRules[TYPE_ACTIVITY] +
-                    " B:" + numRules[TYPE_BROADCAST] + " S:" + numRules[TYPE_SERVICE] + ")");
-
-            synchronized (mAms.getAMSLock()) {
-                mActivityResolver = resolvers[TYPE_ACTIVITY];
-                mBroadcastResolver = resolvers[TYPE_BROADCAST];
-                mServiceResolver = resolvers[TYPE_SERVICE];
-            }
         } catch (XmlPullParserException ex) {
             // if there was an error outside of a specific rule, then there are probably
             // structural problems with the xml file, and we should completely ignore it
-            Slog.e(TAG, "Error reading intent firewall rules", ex);
-            clearRules();
+            Slog.e(TAG, "Error reading intent firewall rules from " + rulesFile, ex);
+            return;
         } catch (IOException ex) {
-            Slog.e(TAG, "Error reading intent firewall rules", ex);
-            clearRules();
+            Slog.e(TAG, "Error reading intent firewall rules from " + rulesFile, ex);
+            return;
         } finally {
             try {
                 fis.close();
@@ -307,21 +359,20 @@
                 Slog.e(TAG, "Error while closing " + rulesFile, ex);
             }
         }
-    }
 
-    /**
-     * Clears out all of our rules
-     *
-     * All calls to this method from the file observer come through a handler and are inherently
-     * serialized
-     */
-    private void clearRules() {
-        Slog.i(TAG, "Clearing all rules");
+        for (int ruleType=0; ruleType<rulesByType.size(); ruleType++) {
+            List<Rule> rules = rulesByType.get(ruleType);
+            FirewallIntentResolver resolver = resolvers[ruleType];
 
-        synchronized (mAms.getAMSLock())  {
-            mActivityResolver = new FirewallIntentResolver();
-            mBroadcastResolver = new FirewallIntentResolver();
-            mServiceResolver = new FirewallIntentResolver();
+            for (int ruleIndex=0; ruleIndex<rules.size(); ruleIndex++) {
+                Rule rule = rules.get(ruleIndex);
+                for (int i=0; i<rule.getIntentFilterCount(); i++) {
+                    resolver.addFilter(rule.getIntentFilter(i));
+                }
+                for (int i=0; i<rule.getComponentFilterCount(); i++) {
+                    resolver.addComponentFilter(rule.getComponentFilter(i), rule);
+                }
+            }
         }
     }
 
@@ -336,14 +387,35 @@
         return factory.newFilter(parser);
     }
 
+    /**
+     * Represents a single activity/service/broadcast rule within one of the xml files.
+     *
+     * Rules are matched against an incoming intent in two phases. The goal of the first phase
+     * is to select a subset of rules that might match a given intent.
+     *
+     * For the first phase, we use a combination of intent filters (via an IntentResolver)
+     * and component filters to select which rules to check. If a rule has multiple intent or
+     * component filters, only a single filter must match for the rule to be passed on to the
+     * second phase.
+     *
+     * In the second phase, we check the specific conditions in each rule against the values in the
+     * intent. All top level conditions (but not filters) in the rule must match for the rule as a
+     * whole to match.
+     *
+     * If the rule matches, then we block or log the intent, as specified by the rule. If multiple
+     * rules match, we combine the block/log flags from any matching rule.
+     */
     private static class Rule extends AndFilter {
         private static final String TAG_INTENT_FILTER = "intent-filter";
+        private static final String TAG_COMPONENT_FILTER = "component-filter";
+        private static final String ATTR_NAME = "name";
 
         private static final String ATTR_BLOCK = "block";
         private static final String ATTR_LOG = "log";
 
         private final ArrayList<FirewallIntentFilter> mIntentFilters =
                 new ArrayList<FirewallIntentFilter>(1);
+        private final ArrayList<ComponentName> mComponentFilters = new ArrayList<ComponentName>(0);
         private boolean block;
         private boolean log;
 
@@ -358,10 +430,25 @@
 
         @Override
         protected void readChild(XmlPullParser parser) throws IOException, XmlPullParserException {
-            if (parser.getName().equals(TAG_INTENT_FILTER)) {
+            String currentTag = parser.getName();
+
+            if (currentTag.equals(TAG_INTENT_FILTER)) {
                 FirewallIntentFilter intentFilter = new FirewallIntentFilter(this);
                 intentFilter.readFromXml(parser);
                 mIntentFilters.add(intentFilter);
+            } else if (currentTag.equals(TAG_COMPONENT_FILTER)) {
+                String componentStr = parser.getAttributeValue(null, ATTR_NAME);
+                if (componentStr == null) {
+                    throw new XmlPullParserException("Component name must be specified.",
+                            parser, null);
+                }
+
+                ComponentName componentName = ComponentName.unflattenFromString(componentStr);
+                if (componentName == null) {
+                    throw new XmlPullParserException("Invalid component name: " + componentStr);
+                }
+
+                mComponentFilters.add(componentName);
             } else {
                 super.readChild(parser);
             }
@@ -375,6 +462,13 @@
             return mIntentFilters.get(index);
         }
 
+        public int getComponentFilterCount() {
+            return mComponentFilters.size();
+        }
+
+        public ComponentName getComponentFilter(int index) {
+            return mComponentFilters.get(index);
+        }
         public boolean getBlock() {
             return block;
         }
@@ -419,56 +513,50 @@
             // there's no need to sort the results
             return;
         }
-    }
 
-    private static final int READ_RULES = 0;
-    private static final int CLEAR_RULES = 1;
+        public void queryByComponent(ComponentName componentName, List<Rule> candidateRules) {
+            Rule[] rules = mRulesByComponent.get(componentName);
+            if (rules != null) {
+                candidateRules.addAll(Arrays.asList(rules));
+            }
+        }
+
+        public void addComponentFilter(ComponentName componentName, Rule rule) {
+            Rule[] rules = mRulesByComponent.get(componentName);
+            rules = ArrayUtils.appendElement(Rule.class, rules, rule);
+            mRulesByComponent.put(componentName, rules);
+        }
+
+        private final ArrayMap<ComponentName, Rule[]> mRulesByComponent =
+                new ArrayMap<ComponentName, Rule[]>(0);
+    }
 
     final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case READ_RULES:
-                    readRules(getRulesFile());
-                    break;
-                case CLEAR_RULES:
-                    clearRules();
-                    break;
-            }
+            readRulesDir(getRulesDir());
         }
     };
 
     /**
-     * Monitors for the creation/deletion/modification of the rule file
+     * Monitors for the creation/deletion/modification of any .xml files in the rule directory
      */
     private class RuleObserver extends FileObserver {
-        // The file name we're monitoring, with no path component
-        private final String mMonitoredFile;
+        private static final int MONITORED_EVENTS = FileObserver.CREATE|FileObserver.MOVED_TO|
+                FileObserver.CLOSE_WRITE|FileObserver.DELETE|FileObserver.MOVED_FROM;
 
-        private static final int CREATED_FLAGS = FileObserver.CREATE|FileObserver.MOVED_TO|
-                FileObserver.CLOSE_WRITE;
-        private static final int DELETED_FLAGS = FileObserver.DELETE|FileObserver.MOVED_FROM;
-
-        public RuleObserver(File monitoredFile) {
-            super(monitoredFile.getParentFile().getAbsolutePath(), CREATED_FLAGS|DELETED_FLAGS);
-            mMonitoredFile = monitoredFile.getName();
+        public RuleObserver(File monitoredDir) {
+            super(monitoredDir.getAbsolutePath(), MONITORED_EVENTS);
         }
 
         @Override
         public void onEvent(int event, String path) {
-            if (path.equals(mMonitoredFile)) {
+            if (path.endsWith(".xml")) {
                 // we wait 250ms before taking any action on an event, in order to dedup multiple
                 // events. E.g. a delete event followed by a create event followed by a subsequent
-                // write+close event;
-                if ((event & CREATED_FLAGS) != 0) {
-                    mHandler.removeMessages(READ_RULES);
-                    mHandler.removeMessages(CLEAR_RULES);
-                    mHandler.sendEmptyMessageDelayed(READ_RULES, 250);
-                } else if ((event & DELETED_FLAGS) != 0) {
-                    mHandler.removeMessages(READ_RULES);
-                    mHandler.removeMessages(CLEAR_RULES);
-                    mHandler.sendEmptyMessageDelayed(CLEAR_RULES, 250);
-                }
+                // write+close event
+                mHandler.removeMessages(0);
+                mHandler.sendEmptyMessageDelayed(0, 250);
             }
         }
     }
@@ -509,4 +597,5 @@
             return false;
         }
     }
+
 }
diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/java/com/android/server/firewall/NotFilter.java
index f0fc337..09bf629 100644
--- a/services/java/com/android/server/firewall/NotFilter.java
+++ b/services/java/com/android/server/firewall/NotFilter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import com.android.internal.util.XmlUtils;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -32,10 +32,10 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-        return !mChild.matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
-                resolvedApp);
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
+        return !mChild.matches(ifw, resolvedComponent, intent, callerUid, callerPid, resolvedType,
+                receivingUid);
     }
 
     public static final FilterFactory FACTORY = new FilterFactory("not") {
diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/java/com/android/server/firewall/OrFilter.java
index 72db31e..f6a6f22 100644
--- a/services/java/com/android/server/firewall/OrFilter.java
+++ b/services/java/com/android/server/firewall/OrFilter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -25,11 +25,11 @@
 
 class OrFilter extends FilterList {
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
         for (int i=0; i<children.size(); i++) {
-            if (children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
-                    resolvedApp)) {
+            if (children.get(i).matches(ifw, resolvedComponent, intent, callerUid, callerPid,
+                    resolvedType, receivingUid)) {
                 return true;
             }
         }
diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/java/com/android/server/firewall/PortFilter.java
index fe7e085..84ace553 100644
--- a/services/java/com/android/server/firewall/PortFilter.java
+++ b/services/java/com/android/server/firewall/PortFilter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.net.Uri;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -41,8 +41,8 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
         int port = -1;
         Uri uri = intent.getData();
         if (uri != null) {
diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/java/com/android/server/firewall/SenderFilter.java
index 58bdd73..c0eee69 100644
--- a/services/java/com/android/server/firewall/SenderFilter.java
+++ b/services/java/com/android/server/firewall/SenderFilter.java
@@ -16,9 +16,14 @@
 
 package com.android.server.firewall;
 
+import android.app.AppGlobals;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -32,15 +37,21 @@
     private static final String VAL_SYSTEM_OR_SIGNATURE = "system|signature";
     private static final String VAL_USER_ID = "userId";
 
-    static boolean isSystemApp(ApplicationInfo callerApp, int callerUid, int callerPid) {
-        if (callerUid == Process.SYSTEM_UID ||
-                callerPid == Process.myPid()) {
+    static boolean isPrivilegedApp(int callerUid, int callerPid) {
+        if (callerUid == Process.SYSTEM_UID || callerUid == 0 ||
+                callerPid == Process.myPid() || callerPid == 0) {
             return true;
         }
-        if (callerApp == null) {
-            return false;
+
+        IPackageManager pm = AppGlobals.getPackageManager();
+        try {
+            return (pm.getFlagsForUid(callerUid) & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+        } catch (RemoteException ex) {
+            Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
+                    ex);
         }
-        return (callerApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+
+        return false;
     }
 
     public static final FilterFactory FACTORY = new FilterFactory("sender") {
@@ -67,45 +78,38 @@
 
     private static final Filter SIGNATURE = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-            if (callerApp == null) {
-                return false;
-            }
-            return ifw.signaturesMatch(callerUid, resolvedApp.uid);
+        public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+                int callerUid, int callerPid, String resolvedType, int receivingUid) {
+            return ifw.signaturesMatch(callerUid, receivingUid);
         }
     };
 
     private static final Filter SYSTEM = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-            if (callerApp == null) {
-                // if callerApp is null, the caller is the system process
-                return false;
-            }
-            return isSystemApp(callerApp, callerUid, callerPid);
+        public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+                int callerUid, int callerPid, String resolvedType, int receivingUid) {
+            return isPrivilegedApp(callerUid, callerPid);
         }
     };
 
     private static final Filter SYSTEM_OR_SIGNATURE = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-            return isSystemApp(callerApp, callerUid, callerPid) ||
-                    ifw.signaturesMatch(callerUid, resolvedApp.uid);
+        public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+                int callerUid, int callerPid, String resolvedType, int receivingUid) {
+            return isPrivilegedApp(callerUid, callerPid) ||
+                    ifw.signaturesMatch(callerUid, receivingUid);
         }
     };
 
     private static final Filter USER_ID = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+                int callerUid, int callerPid, String resolvedType, int receivingUid) {
             // This checks whether the caller is either the system process, or has the same user id
             // I.e. the same app, or an app that uses the same shared user id.
             // This is the same set of applications that would be able to access the component if
             // it wasn't exported.
-            return ifw.checkComponentPermission(null, callerPid, callerUid, resolvedApp.uid, false);
+            return ifw.checkComponentPermission(null, callerPid, callerUid, receivingUid, false);
         }
     };
 }
diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/java/com/android/server/firewall/SenderPermissionFilter.java
index 310da20..caa65f3 100644
--- a/services/java/com/android/server/firewall/SenderPermissionFilter.java
+++ b/services/java/com/android/server/firewall/SenderPermissionFilter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.firewall;
 
+import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -33,12 +33,12 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
         // We assume the component is exported here. If the component is not exported, then
         // ActivityManager would only resolve to this component for callers from the same uid.
         // In this case, it doesn't matter whether the component is exported or not.
-        return ifw.checkComponentPermission(mPermission, callerPid, callerUid, resolvedApp.uid,
+        return ifw.checkComponentPermission(mPermission, callerPid, callerUid, receivingUid,
                 true);
     }
 
diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/java/com/android/server/firewall/StringFilter.java
index ed5d3f3..28e99b3 100644
--- a/services/java/com/android/server/firewall/StringFilter.java
+++ b/services/java/com/android/server/firewall/StringFilter.java
@@ -18,7 +18,6 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.net.Uri;
 import android.os.PatternMatcher;
 import org.xmlpull.v1.XmlPullParser;
@@ -119,9 +118,9 @@
     protected abstract boolean matchesValue(String value);
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-        String value = mValueProvider.getValue(intent, callerApp, resolvedType, resolvedApp);
+    public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+            int callerUid, int callerPid, String resolvedType, int receivingUid) {
+        String value = mValueProvider.getValue(resolvedComponent, intent, resolvedType);
         return matchesValue(value);
     }
 
@@ -135,8 +134,8 @@
             return StringFilter.readFromXml(this, parser);
         }
 
-        public abstract String getValue(Intent intent, ApplicationInfo callerApp,
-                String resolvedType, ApplicationInfo resolvedApp);
+        public abstract String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType);
     }
 
     private static class EqualsFilter extends StringFilter {
@@ -230,11 +229,10 @@
 
     public static final ValueProvider COMPONENT = new ValueProvider("component") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
-            ComponentName cn = intent.getComponent();
-            if (cn != null) {
-                return cn.flattenToString();
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
+            if (resolvedComponent != null) {
+                return resolvedComponent.flattenToString();
             }
             return null;
         }
@@ -242,11 +240,10 @@
 
     public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
-            ComponentName cn = intent.getComponent();
-            if (cn != null) {
-                return cn.getClassName();
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
+            if (resolvedComponent != null) {
+                return resolvedComponent.getClassName();
             }
             return null;
         }
@@ -254,11 +251,10 @@
 
     public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
-            ComponentName cn = intent.getComponent();
-            if (cn != null) {
-                return cn.getPackageName();
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
+            if (resolvedComponent != null) {
+                return resolvedComponent.getPackageName();
             }
             return null;
         }
@@ -266,16 +262,16 @@
 
     public static final FilterFactory ACTION = new ValueProvider("action") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             return intent.getAction();
         }
     };
 
     public static final ValueProvider DATA = new ValueProvider("data") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.toString();
@@ -286,16 +282,16 @@
 
     public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             return resolvedType;
         }
     };
 
     public static final ValueProvider SCHEME = new ValueProvider("scheme") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getScheme();
@@ -306,8 +302,8 @@
 
     public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getSchemeSpecificPart();
@@ -318,8 +314,8 @@
 
     public static final ValueProvider HOST = new ValueProvider("host") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getHost();
@@ -330,8 +326,8 @@
 
     public static final ValueProvider PATH = new ValueProvider("path") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(ComponentName resolvedComponent, Intent intent,
+                String resolvedType) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getPath();
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 5e4907e..d749e6c 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -283,7 +283,7 @@
     }
 
     // TODO(BT) Pass in paramter for bluetooth system
-    public void systemReady() {
+    public void systemRunning() {
         if (DEBUG) {
             Slog.d(TAG, "System ready.");
         }
@@ -1292,8 +1292,9 @@
 
     // Native callback.
     private long notifyANR(InputApplicationHandle inputApplicationHandle,
-            InputWindowHandle inputWindowHandle) {
-        return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
+            InputWindowHandle inputWindowHandle, String reason) {
+        return mWindowManagerCallbacks.notifyANR(
+                inputApplicationHandle, inputWindowHandle, reason);
     }
 
     // Native callback.
@@ -1477,7 +1478,7 @@
         public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
 
         public long notifyANR(InputApplicationHandle inputApplicationHandle,
-                InputWindowHandle inputWindowHandle);
+                InputWindowHandle inputWindowHandle, String reason);
 
         public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
 
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java
new file mode 100644
index 0000000..fab84a8
--- /dev/null
+++ b/services/java/com/android/server/location/FlpHardwareProvider.java
@@ -0,0 +1,427 @@
+/*
+ * 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.location;
+
+import android.hardware.location.GeofenceHardware;
+import android.hardware.location.GeofenceHardwareImpl;
+import android.hardware.location.GeofenceHardwareRequestParcelable;
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.IFusedGeofenceHardware;
+import android.location.FusedBatchOptions;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationRequest;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * This class is an interop layer for JVM types and the JNI code that interacts
+ * with the FLP HAL implementation.
+ *
+ * {@hide}
+ */
+public class FlpHardwareProvider {
+    private GeofenceHardwareImpl mGeofenceHardwareSink = null;
+    private IFusedLocationHardwareSink mLocationSink = null;
+
+    private static FlpHardwareProvider sSingletonInstance = null;
+
+    private final static String TAG = "FlpHardwareProvider";
+    private final Context mContext;
+    private final Object mLocationSinkLock = new Object();
+
+    // FlpHal result codes, they must be equal to the ones in fused_location.h
+    private static final int FLP_RESULT_SUCCESS = 0;
+    private static final int FLP_RESULT_ERROR = -1;
+    private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2;
+    private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3;
+    private static final int FLP_RESULT_ID_EXISTS = -4;
+    private static final int FLP_RESULT_ID_UNKNOWN = -5;
+    private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6;
+
+    public static FlpHardwareProvider getInstance(Context context) {
+        if (sSingletonInstance == null) {
+            sSingletonInstance = new FlpHardwareProvider(context);
+        }
+
+        return sSingletonInstance;
+    }
+
+    private FlpHardwareProvider(Context context) {
+        mContext = context;
+
+        // register for listening for passive provider data
+        LocationManager manager = (LocationManager) mContext.getSystemService(
+                Context.LOCATION_SERVICE);
+        final long minTime = 0;
+        final float minDistance = 0;
+        final boolean oneShot = false;
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(
+                LocationManager.PASSIVE_PROVIDER,
+                minTime,
+                minDistance,
+                oneShot);
+        // Don't keep track of this request since it's done on behalf of other clients
+        // (which are kept track of separately).
+        request.setHideFromAppOps(true);
+        manager.requestLocationUpdates(
+                request,
+                new NetworkLocationListener(),
+                Looper.myLooper());
+    }
+
+    public static boolean isSupported() {
+        return nativeIsSupported();
+    }
+
+    /**
+     * Private callback functions used by FLP HAL.
+     */
+    // FlpCallbacks members
+    private void onLocationReport(Location[] locations) {
+        for (Location location : locations) {
+            location.setProvider(LocationManager.FUSED_PROVIDER);
+            // set the elapsed time-stamp just as GPS provider does
+            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        }
+
+        IFusedLocationHardwareSink sink;
+        synchronized (mLocationSinkLock) {
+            sink = mLocationSink;
+        }
+        try {
+            if (sink != null) {
+                sink.onLocationAvailable(locations);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling onLocationAvailable");
+        }
+    }
+
+    // FlpDiagnosticCallbacks members
+    private void onDataReport(String data) {
+        IFusedLocationHardwareSink sink;
+        synchronized (mLocationSinkLock) {
+            sink = mLocationSink;
+        }
+        try {
+            if (mLocationSink != null) {
+                sink.onDiagnosticDataAvailable(data);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable");
+        }
+    }
+
+    // FlpGeofenceCallbacks members
+    private void onGeofenceTransition(
+            int geofenceId,
+            Location location,
+            int transition,
+            long timestamp,
+            int sourcesUsed) {
+        getGeofenceHardwareSink().reportGeofenceTransition(
+                geofenceId,
+                updateLocationInformation(location),
+                transition,
+                timestamp,
+                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
+                sourcesUsed);
+    }
+
+    private void onGeofenceMonitorStatus(int status, int source, Location location) {
+        // allow the location to be optional in this event
+        Location updatedLocation = null;
+        if(location != null) {
+            updatedLocation = updateLocationInformation(location);
+        }
+
+        getGeofenceHardwareSink().reportGeofenceMonitorStatus(
+                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
+                status,
+                updatedLocation,
+                source);
+    }
+
+    private void onGeofenceAdd(int geofenceId, int result) {
+        getGeofenceHardwareSink().reportGeofenceAddStatus(
+                geofenceId,
+                translateToGeofenceHardwareStatus(result));
+    }
+
+    private void onGeofenceRemove(int geofenceId, int result) {
+        getGeofenceHardwareSink().reportGeofenceRemoveStatus(
+                geofenceId,
+                translateToGeofenceHardwareStatus(result));
+    }
+
+    private void onGeofencePause(int geofenceId, int result) {
+        getGeofenceHardwareSink().reportGeofencePauseStatus(
+                geofenceId,
+                translateToGeofenceHardwareStatus(result));
+    }
+
+    private void onGeofenceResume(int geofenceId, int result) {
+        getGeofenceHardwareSink().reportGeofenceResumeStatus(
+                geofenceId,
+                translateToGeofenceHardwareStatus(result));
+    }
+
+    /**
+     * Private native methods accessing FLP HAL.
+     */
+    static { nativeClassInit(); }
+
+    // Core members
+    private static native void nativeClassInit();
+    private static native boolean nativeIsSupported();
+
+    // FlpLocationInterface members
+    private native void nativeInit();
+    private native int nativeGetBatchSize();
+    private native void nativeStartBatching(int requestId, FusedBatchOptions options);
+    private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
+    private native void nativeStopBatching(int id);
+    private native void nativeRequestBatchedLocation(int lastNLocations);
+    private native void nativeInjectLocation(Location location);
+    // TODO [Fix] sort out the lifetime of the instance
+    private native void nativeCleanup();
+
+    // FlpDiagnosticsInterface members
+    private native boolean nativeIsDiagnosticSupported();
+    private native void nativeInjectDiagnosticData(String data);
+
+    // FlpDeviceContextInterface members
+    private native boolean nativeIsDeviceContextSupported();
+    private native void nativeInjectDeviceContext(int deviceEnabledContext);
+
+    // FlpGeofencingInterface members
+    private native boolean nativeIsGeofencingSupported();
+    private native void nativeAddGeofences(
+            GeofenceHardwareRequestParcelable[] geofenceRequestsArray);
+    private native void nativePauseGeofence(int geofenceId);
+    private native void  nativeResumeGeofence(int geofenceId, int monitorTransitions);
+    private native void nativeModifyGeofenceOption(
+        int geofenceId,
+        int lastTransition,
+        int monitorTransitions,
+        int notificationResponsiveness,
+        int unknownTimer,
+        int sourcesToUse);
+    private native void nativeRemoveGeofences(int[] geofenceIdsArray);
+
+    /**
+     * Interface implementations for services built on top of this functionality.
+     */
+    public static final String LOCATION = "Location";
+    public static final String GEOFENCING = "Geofencing";
+
+    public IFusedLocationHardware getLocationHardware() {
+        nativeInit();
+        return mLocationHardware;
+    }
+
+    public IFusedGeofenceHardware getGeofenceHardware() {
+        nativeInit();
+        return mGeofenceHardwareService;
+    }
+
+    private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
+        @Override
+        public void registerSink(IFusedLocationHardwareSink eventSink) {
+            synchronized (mLocationSinkLock) {
+                // only one sink is allowed at the moment
+                if (mLocationSink != null) {
+                    throw new RuntimeException(
+                            "IFusedLocationHardware does not support multiple sinks");
+                }
+
+                mLocationSink = eventSink;
+            }
+        }
+
+        @Override
+        public void unregisterSink(IFusedLocationHardwareSink eventSink) {
+            synchronized (mLocationSinkLock) {
+                // don't throw if the sink is not registered, simply make it a no-op
+                if (mLocationSink == eventSink) {
+                    mLocationSink = null;
+                }
+            }
+        }
+
+        @Override
+        public int getSupportedBatchSize() {
+            return nativeGetBatchSize();
+        }
+
+        @Override
+        public void startBatching(int requestId, FusedBatchOptions options) {
+            nativeStartBatching(requestId, options);
+        }
+
+        @Override
+        public void stopBatching(int requestId) {
+            nativeStopBatching(requestId);
+        }
+
+        @Override
+        public void updateBatchingOptions(int requestId, FusedBatchOptions options) {
+            nativeUpdateBatchingOptions(requestId, options);
+        }
+
+        @Override
+        public void requestBatchOfLocations(int batchSizeRequested) {
+            nativeRequestBatchedLocation(batchSizeRequested);
+        }
+
+        @Override
+        public boolean supportsDiagnosticDataInjection() {
+            return nativeIsDiagnosticSupported();
+        }
+
+        @Override
+        public void injectDiagnosticData(String data) {
+            nativeInjectDiagnosticData(data);
+        }
+
+        @Override
+        public boolean supportsDeviceContextInjection() {
+            return nativeIsDeviceContextSupported();
+        }
+
+        @Override
+        public void injectDeviceContext(int deviceEnabledContext) {
+            nativeInjectDeviceContext(deviceEnabledContext);
+        }
+    };
+
+    private final IFusedGeofenceHardware mGeofenceHardwareService =
+            new IFusedGeofenceHardware.Stub() {
+        @Override
+        public boolean isSupported() {
+            return nativeIsGeofencingSupported();
+        }
+
+        @Override
+        public void addGeofences(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) {
+            nativeAddGeofences(geofenceRequestsArray);
+        }
+
+        @Override
+        public void removeGeofences(int[] geofenceIds) {
+            nativeRemoveGeofences(geofenceIds);
+        }
+
+        @Override
+        public void pauseMonitoringGeofence(int geofenceId) {
+            nativePauseGeofence(geofenceId);
+        }
+
+        @Override
+        public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) {
+            nativeResumeGeofence(geofenceId, monitorTransitions);
+        }
+
+        @Override
+        public void modifyGeofenceOptions(int geofenceId,
+                int lastTransition,
+                int monitorTransitions,
+                int notificationResponsiveness,
+                int unknownTimer,
+                int sourcesToUse) {
+            nativeModifyGeofenceOption(
+                    geofenceId,
+                    lastTransition,
+                    monitorTransitions,
+                    notificationResponsiveness,
+                    unknownTimer,
+                    sourcesToUse);
+        }
+    };
+
+    /**
+     * Internal classes and functions used by the provider.
+     */
+    private final class NetworkLocationListener implements LocationListener {
+        @Override
+        public void onLocationChanged(Location location) {
+            if (
+                !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) ||
+                !location.hasAccuracy()
+                ) {
+                return;
+            }
+
+            nativeInjectLocation(location);
+        }
+
+        @Override
+        public void onStatusChanged(String provider, int status, Bundle extras) { }
+
+        @Override
+        public void onProviderEnabled(String provider) { }
+
+        @Override
+        public void onProviderDisabled(String provider) { }
+    }
+
+    private GeofenceHardwareImpl getGeofenceHardwareSink() {
+        if (mGeofenceHardwareSink == null) {
+            mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext);
+        }
+
+        return mGeofenceHardwareSink;
+    }
+
+    private static int translateToGeofenceHardwareStatus(int flpHalResult) {
+        switch(flpHalResult) {
+            case FLP_RESULT_SUCCESS:
+                return GeofenceHardware.GEOFENCE_SUCCESS;
+            case FLP_RESULT_ERROR:
+                return GeofenceHardware.GEOFENCE_FAILURE;
+            // TODO: uncomment this once the ERROR definition is marked public
+            //case FLP_RESULT_INSUFFICIENT_MEMORY:
+            //    return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY;
+            case FLP_RESULT_TOO_MANY_GEOFENCES:
+                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
+            case FLP_RESULT_ID_EXISTS:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
+            case FLP_RESULT_ID_UNKNOWN:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
+            case FLP_RESULT_INVALID_GEOFENCE_TRANSITION:
+                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
+            default:
+                Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult));
+                return GeofenceHardware.GEOFENCE_FAILURE;
+        }
+    }
+
+    private Location updateLocationInformation(Location location) {
+        location.setProvider(LocationManager.FUSED_PROVIDER);
+        // set the elapsed time-stamp just as GPS provider does
+        location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        return location;
+    }
+}
diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/java/com/android/server/location/FusedLocationHardwareSecure.java
new file mode 100644
index 0000000..389bd24
--- /dev/null
+++ b/services/java/com/android/server/location/FusedLocationHardwareSecure.java
@@ -0,0 +1,119 @@
+/*
+ * 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.location;
+
+import android.content.Context;
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.FusedBatchOptions;
+import android.os.RemoteException;
+
+/**
+ * FusedLocationHardware decorator that adds permission checking.
+ * @hide
+ */
+public class FusedLocationHardwareSecure extends IFusedLocationHardware.Stub {
+    private final IFusedLocationHardware mLocationHardware;
+    private final Context mContext;
+    private final String mPermissionId;
+
+    public FusedLocationHardwareSecure(
+            IFusedLocationHardware locationHardware,
+            Context context,
+            String permissionId) {
+        mLocationHardware = locationHardware;
+        mContext = context;
+        mPermissionId = permissionId;
+    }
+
+    private void checkPermissions() {
+        mContext.enforceCallingPermission(
+                mPermissionId,
+                String.format(
+                        "Permission '%s' not granted to access FusedLocationHardware",
+                        mPermissionId));
+    }
+
+    @Override
+    public void registerSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.registerSink(eventSink);
+    }
+
+    @Override
+    public void unregisterSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.unregisterSink(eventSink);
+    }
+
+    @Override
+    public int getSupportedBatchSize() throws RemoteException {
+        checkPermissions();
+        return mLocationHardware.getSupportedBatchSize();
+    }
+
+    @Override
+    public void startBatching(int id, FusedBatchOptions batchOptions) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.startBatching(id, batchOptions);
+    }
+
+    @Override
+    public void stopBatching(int id) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.stopBatching(id);
+    }
+
+    @Override
+    public void updateBatchingOptions(
+            int id,
+            FusedBatchOptions batchoOptions
+            ) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.updateBatchingOptions(id, batchoOptions);
+    }
+
+    @Override
+    public void requestBatchOfLocations(int batchSizeRequested) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.requestBatchOfLocations(batchSizeRequested);
+    }
+
+    @Override
+    public boolean supportsDiagnosticDataInjection() throws RemoteException {
+        checkPermissions();
+        return mLocationHardware.supportsDiagnosticDataInjection();
+    }
+
+    @Override
+    public void injectDiagnosticData(String data) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.injectDiagnosticData(data);
+    }
+
+    @Override
+    public boolean supportsDeviceContextInjection() throws RemoteException {
+        checkPermissions();
+        return mLocationHardware.supportsDeviceContextInjection();
+    }
+
+    @Override
+    public void injectDeviceContext(int deviceEnabledContext) throws RemoteException {
+        checkPermissions();
+        mLocationHardware.injectDeviceContext(deviceEnabledContext);
+    }
+}
diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/java/com/android/server/location/FusedProxy.java
new file mode 100644
index 0000000..f7fac77
--- /dev/null
+++ b/services/java/com/android/server/location/FusedProxy.java
@@ -0,0 +1,128 @@
+/*
+ * 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 law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import com.android.server.ServiceWatcher;
+
+import android.Manifest;
+import android.content.Context;
+import android.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Proxy that helps bind GCore FusedProvider implementations to the Fused Hardware instances.
+ *
+ * @hide
+ */
+public final class FusedProxy {
+    private final String TAG = "FusedProxy";
+    private final ServiceWatcher mServiceWatcher;
+    private final FusedLocationHardwareSecure mLocationHardware;
+
+    /**
+     * Constructor of the class.
+     * This is private as the class follows a factory pattern for construction.
+     *
+     * @param context           The context needed for construction.
+     * @param handler           The handler needed for construction.
+     * @param locationHardware  The instance of the Fused location hardware assigned to the proxy.
+     */
+    private FusedProxy(
+            Context context,
+            Handler handler,
+            IFusedLocationHardware locationHardware,
+            int overlaySwitchResId,
+            int defaultServicePackageNameResId,
+            int initialPackageNameResId) {
+        mLocationHardware = new FusedLocationHardwareSecure(
+                locationHardware,
+                context,
+                Manifest.permission.LOCATION_HARDWARE);
+        Runnable newServiceWork = new Runnable() {
+            @Override
+            public void run() {
+                bindProvider(mLocationHardware);
+            }
+        };
+
+        // prepare the connection to the provider
+        mServiceWatcher = new ServiceWatcher(
+                context,
+                TAG,
+                "com.android.location.service.FusedProvider",
+                overlaySwitchResId,
+                defaultServicePackageNameResId,
+                initialPackageNameResId,
+                newServiceWork,
+                handler);
+    }
+
+    /**
+     * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
+     *
+     * @param context           The context needed for construction.
+     * @param handler           The handler needed for construction.
+     * @param locationHardware  The instance of the Fused location hardware assigned to the proxy.
+     *
+     * @return An instance of the proxy if it could be bound, null otherwise.
+     */
+    public static FusedProxy createAndBind(
+            Context context,
+            Handler handler,
+            IFusedLocationHardware locationHardware,
+            int overlaySwitchResId,
+            int defaultServicePackageNameResId,
+            int initialPackageNameResId) {
+        FusedProxy fusedProxy = new FusedProxy(
+                context,
+                handler,
+                locationHardware,
+                overlaySwitchResId,
+                defaultServicePackageNameResId,
+                initialPackageNameResId);
+
+        // try to bind the Fused provider
+        if (!fusedProxy.mServiceWatcher.start()) {
+            return null;
+        }
+
+        return fusedProxy;
+    }
+
+    /**
+     * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
+     *
+     * @param locationHardware  The FusedLocationHardware instance to use for the binding operation.
+     */
+    private void bindProvider(IFusedLocationHardware locationHardware) {
+        IFusedProvider provider = IFusedProvider.Stub.asInterface(mServiceWatcher.getBinder());
+
+        if (provider == null) {
+            Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
+            return;
+        }
+
+        try {
+            provider.onFusedLocationHardwareChange(locationHardware);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.toString());
+        }
+    }
+}
diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/java/com/android/server/location/GeofenceProxy.java
index f6be27b..bbc1f47 100644
--- a/services/java/com/android/server/location/GeofenceProxy.java
+++ b/services/java/com/android/server/location/GeofenceProxy.java
@@ -22,6 +22,7 @@
 import android.hardware.location.IGeofenceHardware;
 import android.location.IGeofenceProvider;
 import android.location.IGpsGeofenceHardware;
+import android.location.IFusedGeofenceHardware;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
@@ -40,10 +41,15 @@
     private static final String TAG = "GeofenceProxy";
     private static final String SERVICE_ACTION =
             "com.android.location.service.GeofenceProvider";
-    private ServiceWatcher mServiceWatcher;
-    private Context mContext;
+    private final ServiceWatcher mServiceWatcher;
+    private final Context mContext;
+    private final IGpsGeofenceHardware mGpsGeofenceHardware;
+    private final IFusedGeofenceHardware mFusedGeofenceHardware;
+
+    private final Object mLock = new Object();
+
+    // Access to mGeofenceHardware needs to be synchronized by mLock.
     private IGeofenceHardware mGeofenceHardware;
-    private IGpsGeofenceHardware mGpsGeofenceHardware;
 
     private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
     private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
@@ -60,9 +66,11 @@
 
     public static GeofenceProxy createAndBind(Context context,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) {
+            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
+            IFusedGeofenceHardware fusedGeofenceHardware) {
         GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
-            defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence);
+            defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence,
+            fusedGeofenceHardware);
         if (proxy.bindGeofenceProvider()) {
             return proxy;
         } else {
@@ -72,11 +80,13 @@
 
     private GeofenceProxy(Context context,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) {
+            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
+            IFusedGeofenceHardware fusedGeofenceHardware) {
         mContext = context;
         mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
             defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
         mGpsGeofenceHardware = gpsGeofence;
+        mFusedGeofenceHardware = fusedGeofenceHardware;
         bindHardwareGeofence();
     }
 
@@ -84,10 +94,6 @@
         return mServiceWatcher.start();
     }
 
-    private IGeofenceProvider getGeofenceProviderService() {
-        return IGeofenceProvider.Stub.asInterface(mServiceWatcher.getBinder());
-    }
-
     private void bindHardwareGeofence() {
         mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
                 mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
@@ -96,26 +102,34 @@
     private ServiceConnection mServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
-            mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
+            synchronized (mLock) {
+                mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
+                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
+            }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            mGeofenceHardware = null;
-            mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
+            synchronized (mLock) {
+                mGeofenceHardware = null;
+                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
+            }
         }
     };
 
-    private void setGeofenceHardwareInProvider() {
+    private void setGeofenceHardwareInProviderLocked() {
         try {
-            getGeofenceProviderService().setGeofenceHardware(mGeofenceHardware);
+            IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(
+                      mServiceWatcher.getBinder());
+            if (provider != null) {
+                provider.setGeofenceHardware(mGeofenceHardware);
+            }
         } catch (RemoteException e) {
-            Log.e(TAG, "Remote Exception: setGeofenceHardwareInProvider: " + e);
+            Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
         }
     }
 
-    private void setGpsGeofence() {
+    private void setGpsGeofenceLocked() {
         try {
             mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
         } catch (RemoteException e) {
@@ -123,33 +137,48 @@
         }
     }
 
+    private void setFusedGeofenceLocked() {
+        try {
+            mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
+        } catch(RemoteException e) {
+            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
+        }
+    }
 
     // This needs to be reworked, when more services get added,
     // Might need a state machine or add a framework utility class,
     private Handler mHandler = new Handler() {
-        private boolean mGeofenceHardwareConnected = false;
-        private boolean mGeofenceProviderConnected = false;
-
 
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case GEOFENCE_PROVIDER_CONNECTED:
-                    mGeofenceProviderConnected = true;
-                    if (mGeofenceHardwareConnected) {
-                        setGeofenceHardwareInProvider();
+                    synchronized (mLock) {
+                        if (mGeofenceHardware != null) {
+                            setGeofenceHardwareInProviderLocked();
+                        }
+                        // else: the geofence provider will be notified when the connection to
+                        // GeofenceHardwareService is established.
                     }
                     break;
                 case GEOFENCE_HARDWARE_CONNECTED:
-                    setGpsGeofence();
-                    mGeofenceHardwareConnected = true;
-                    if (mGeofenceProviderConnected) {
-                        setGeofenceHardwareInProvider();
+                    synchronized (mLock) {
+                        // Theoretically this won't happen because once the GeofenceHardwareService
+                        // is connected to, we won't lose connection to it because it's a system
+                        // service. But this check does make the code more robust.
+                        if (mGeofenceHardware != null) {
+                            setGpsGeofenceLocked();
+                            setFusedGeofenceLocked();
+                            setGeofenceHardwareInProviderLocked();
+                        }
                     }
                     break;
                 case GEOFENCE_HARDWARE_DISCONNECTED:
-                    mGeofenceHardwareConnected = false;
-                    setGeofenceHardwareInProvider();
+                    synchronized (mLock) {
+                        if (mGeofenceHardware == null) {
+                            setGeofenceHardwareInProviderLocked();
+                        }
+                    }
                     break;
             }
         }
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 8c88cab..9c76c19 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -24,9 +24,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.Cursor;
+import android.hardware.location.GeofenceHardware;
 import android.hardware.location.GeofenceHardwareImpl;
-import android.hardware.location.IGeofenceHardware;
 import android.location.Criteria;
+import android.location.FusedBatchOptions;
 import android.location.IGpsGeofenceHardware;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
@@ -41,6 +42,7 @@
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -194,6 +196,17 @@
 
     private static final String PROPERTIES_FILE = "/etc/gps.conf";
 
+    private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
+    private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
+
+    // GPS Geofence errors. Should match gps.h constants.
+    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
+    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
+    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
+    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
+    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
+    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
+
     /** simpler wrapper for ProviderRequest + Worksource */
     private static class GpsRequest {
         public ProviderRequest request;
@@ -456,7 +469,8 @@
                 Context.APP_OPS_SERVICE));
 
         // Battery statistics service to be notified when GPS turns on or off
-        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
+                BatteryStats.SERVICE_NAME));
 
         mProperties = new Properties();
         try {
@@ -498,8 +512,21 @@
             public void run() {
                 LocationManager locManager =
                         (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
-                locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
-                        0, 0, new NetworkLocationListener(), mHandler.getLooper());                
+                final long minTime = 0;
+                final float minDistance = 0;
+                final boolean oneShot = false;
+                LocationRequest request = LocationRequest.createFromDeprecatedProvider(
+                        LocationManager.PASSIVE_PROVIDER,
+                        minTime,
+                        minDistance,
+                        oneShot);
+                // Don't keep track of this request since it's done on behalf of other clients
+                // (which are kept track of separately).
+                request.setHideFromAppOps(true);
+                locManager.requestLocationUpdates(
+                        request,
+                        new NetworkLocationListener(),
+                        mHandler.getLooper());
             }
         });
     }
@@ -890,7 +917,8 @@
             for (int i=0; i<newWork.size(); i++) {
                 try {
                     int uid = newWork.get(i);
-                    mAppOpsService.startOperation(AppOpsManager.OP_GPS, uid, newWork.getName(i));
+                    mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+                            AppOpsManager.OP_GPS, uid, newWork.getName(i));
                     if (uid != lastuid) {
                         lastuid = uid;
                         mBatteryStats.noteStartGps(uid);
@@ -907,7 +935,8 @@
             for (int i=0; i<goneWork.size(); i++) {
                 try {
                     int uid = goneWork.get(i);
-                    mAppOpsService.finishOperation(AppOpsManager.OP_GPS, uid, goneWork.getName(i));
+                    mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+                            AppOpsManager.OP_GPS, uid, goneWork.getName(i));
                     if (uid != lastuid) {
                         lastuid = uid;
                         mBatteryStats.noteStopGps(uid);
@@ -1401,6 +1430,62 @@
     }
 
     /**
+     * Helper method to construct a location object.
+     */
+    private Location buildLocation(
+            int flags,
+            double latitude,
+            double longitude,
+            double altitude,
+            float speed,
+            float bearing,
+            float accuracy,
+            long timestamp) {
+        Location location = new Location(LocationManager.GPS_PROVIDER);
+        if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
+            location.setLatitude(latitude);
+            location.setLongitude(longitude);
+            location.setTime(timestamp);
+            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        }
+        if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
+            location.setAltitude(altitude);
+        }
+        if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
+            location.setSpeed(speed);
+        }
+        if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
+            location.setBearing(bearing);
+        }
+        if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
+            location.setAccuracy(accuracy);
+        }
+        return location;
+    }
+
+    /**
+     * Converts the GPS HAL status to the internal Geofence Hardware status.
+     */
+    private int getGeofenceStatus(int status) {
+        switch(status) {
+            case GPS_GEOFENCE_OPERATION_SUCCESS:
+                return GeofenceHardware.GEOFENCE_SUCCESS;
+            case GPS_GEOFENCE_ERROR_GENERIC:
+                return GeofenceHardware.GEOFENCE_FAILURE;
+            case GPS_GEOFENCE_ERROR_ID_EXISTS:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
+            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
+                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
+            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
+                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
+            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
+            default:
+                return -1;
+        }
+    }
+
+    /**
      * Called from native to report GPS Geofence transition
      * All geofence callbacks are called on the same thread
      */
@@ -1410,8 +1495,22 @@
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
-        mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude,
-           altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp);
+        Location location = buildLocation(
+                flags,
+                latitude,
+                longitude,
+                altitude,
+                speed,
+                bearing,
+                accuracy,
+                timestamp);
+        mGeofenceHardwareImpl.reportGeofenceTransition(
+                geofenceId,
+                location,
+                transition,
+                transitionTimestamp,
+                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                FusedBatchOptions.SourceTechnologies.GNSS);
     }
 
     /**
@@ -1423,8 +1522,24 @@
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
-        mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude,
-            speed, bearing, accuracy, timestamp);
+        Location location = buildLocation(
+                flags,
+                latitude,
+                longitude,
+                altitude,
+                speed,
+                bearing,
+                accuracy,
+                timestamp);
+        int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+        if(status == GPS_GEOFENCE_AVAILABLE) {
+            monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
+        }
+        mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
+                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                monitorStatus,
+                location,
+                FusedBatchOptions.SourceTechnologies.GNSS);
     }
 
     /**
@@ -1434,7 +1549,7 @@
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
-        mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status);
+        mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
     }
 
     /**
@@ -1444,7 +1559,7 @@
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
-        mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status);
+        mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
     }
 
     /**
@@ -1454,7 +1569,7 @@
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
-        mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status);
+        mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
     }
 
     /**
@@ -1464,7 +1579,7 @@
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
-        mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status);
+        mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
     }
 
     //=============================================================
diff --git a/services/java/com/android/server/net/BaseNetworkObserver.java b/services/java/com/android/server/net/BaseNetworkObserver.java
deleted file mode 100644
index 8b2aa5d..0000000
--- a/services/java/com/android/server/net/BaseNetworkObserver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server.net;
-
-import android.net.INetworkManagementEventObserver;
-
-/**
- * Base {@link INetworkManagementEventObserver} that provides no-op
- * implementations which can be overridden.
- *
- * @hide
- */
-public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub {
-    @Override
-    public void interfaceStatusChanged(String iface, boolean up) {
-        // default no-op
-    }
-
-    @Override
-    public void interfaceRemoved(String iface) {
-        // default no-op
-    }
-
-    @Override
-    public void interfaceLinkStateChanged(String iface, boolean up) {
-        // default no-op
-    }
-
-    @Override
-    public void interfaceAdded(String iface) {
-        // default no-op
-    }
-
-    @Override
-    public void interfaceClassDataActivityChanged(String label, boolean active) {
-        // default no-op
-    }
-
-    @Override
-    public void limitReached(String limitName, String iface) {
-        // default no-op
-    }
-}
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/java/com/android/server/net/LockdownVpnTracker.java
index e251925..a2e9d676 100644
--- a/services/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/java/com/android/server/net/LockdownVpnTracker.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.LinkProperties;
+import android.net.LinkAddress;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
@@ -44,6 +45,8 @@
 import com.android.server.EventLogTags;
 import com.android.server.connectivity.Vpn;
 
+import java.util.List;
+
 /**
  * State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be
  * connected and kicks off VPN connection, managing any required {@code netd}
@@ -73,7 +76,7 @@
 
     private String mAcceptedEgressIface;
     private String mAcceptedIface;
-    private String mAcceptedSourceAddr;
+    private List<LinkAddress> mAcceptedSourceAddr;
 
     private int mErrorCount;
 
@@ -148,8 +151,13 @@
                 showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
 
                 mAcceptedEgressIface = egressProp.getInterfaceName();
-                mVpn.startLegacyVpn(mProfile, KeyStore.getInstance(), egressProp);
-
+                try {
+                    mVpn.startLegacyVpn(mProfile, KeyStore.getInstance(), egressProp);
+                } catch (IllegalStateException e) {
+                    mAcceptedEgressIface = null;
+                    Slog.e(TAG, "Failed to start VPN", e);
+                    showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
+                }
             } else {
                 Slog.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
                 showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
@@ -157,14 +165,15 @@
 
         } else if (vpnInfo.isConnected() && vpnConfig != null) {
             final String iface = vpnConfig.interfaze;
-            final String sourceAddr = vpnConfig.addresses;
+            final List<LinkAddress> sourceAddrs = vpnConfig.addresses;
 
             if (TextUtils.equals(iface, mAcceptedIface)
-                    && TextUtils.equals(sourceAddr, mAcceptedSourceAddr)) {
+                  && sourceAddrs.equals(mAcceptedSourceAddr)) {
                 return;
             }
 
-            Slog.d(TAG, "VPN connected using iface=" + iface + ", sourceAddr=" + sourceAddr);
+            Slog.d(TAG, "VPN connected using iface=" + iface +
+                    ", sourceAddr=" + sourceAddrs.toString());
             EventLogTags.writeLockdownVpnConnected(egressType);
             showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
 
@@ -172,11 +181,13 @@
                 clearSourceRulesLocked();
 
                 mNetService.setFirewallInterfaceRule(iface, true);
-                mNetService.setFirewallEgressSourceRule(sourceAddr, true);
+                for (LinkAddress addr : sourceAddrs) {
+                    mNetService.setFirewallEgressSourceRule(addr.toString(), true);
+                }
 
                 mErrorCount = 0;
                 mAcceptedIface = iface;
-                mAcceptedSourceAddr = sourceAddr;
+                mAcceptedSourceAddr = sourceAddrs;
             } catch (RemoteException e) {
                 throw new RuntimeException("Problem setting firewall rules", e);
             }
@@ -258,7 +269,9 @@
                 mAcceptedIface = null;
             }
             if (mAcceptedSourceAddr != null) {
-                mNetService.setFirewallEgressSourceRule(mAcceptedSourceAddr, false);
+                for (LinkAddress addr : mAcceptedSourceAddr) {
+                    mNetService.setFirewallEgressSourceRule(addr.toString(), false);
+                }
                 mAcceptedSourceAddr = null;
             }
         } catch (RemoteException e) {
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index a82f421..d568b11 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -274,7 +274,6 @@
     private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
             INetworkPolicyListener>();
 
-    private final HandlerThread mHandlerThread;
     private final Handler mHandler;
 
     private final AtomicFile mPolicyFile;
@@ -306,9 +305,9 @@
         mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
         mTime = checkNotNull(time, "missing TrustedTime");
 
-        mHandlerThread = new HandlerThread(TAG);
-        mHandlerThread.start();
-        mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mHandler = new Handler(thread.getLooper(), mHandlerCallback);
 
         mSuppressDefaultPolicy = suppressDefaultPolicy;
 
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index 2b32b41..cea084b 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -135,6 +135,9 @@
             } catch (IOException e) {
                 Log.wtf(TAG, "problem completely reading network stats", e);
                 recoverFromWtf();
+            } catch (OutOfMemoryError e) {
+                Log.wtf(TAG, "problem completely reading network stats", e);
+                recoverFromWtf();
             }
         }
         return complete;
@@ -226,6 +229,9 @@
             } catch (IOException e) {
                 Log.wtf(TAG, "problem persisting pending stats", e);
                 recoverFromWtf();
+            } catch (OutOfMemoryError e) {
+                Log.wtf(TAG, "problem persisting pending stats", e);
+                recoverFromWtf();
             }
         }
     }
@@ -241,6 +247,9 @@
         } catch (IOException e) {
             Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
             recoverFromWtf();
+        } catch (OutOfMemoryError e) {
+            Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
+            recoverFromWtf();
         }
 
         // Remove any pending stats
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 74be472..5d6adc2 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -154,7 +154,7 @@
 
     private final Context mContext;
     private final INetworkManagementService mNetworkManager;
-    private final IAlarmManager mAlarmManager;
+    private final AlarmManager mAlarmManager;
     private final TrustedTime mTime;
     private final TelephonyManager mTeleManager;
     private final NetworkStatsSettings mSettings;
@@ -240,7 +240,6 @@
     /** Data layer operation counters for splicing into other structures. */
     private NetworkStats mUidOperations = new NetworkStats(0L, 10);
 
-    private final HandlerThread mHandlerThread;
     private final Handler mHandler;
 
     private boolean mSystemReady;
@@ -262,18 +261,18 @@
             NetworkStatsSettings settings) {
         mContext = checkNotNull(context, "missing Context");
         mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
-        mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
         mTime = checkNotNull(time, "missing TrustedTime");
         mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
         mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
 
         final PowerManager powerManager = (PowerManager) context.getSystemService(
                 Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
-        mHandlerThread = new HandlerThread(TAG);
-        mHandlerThread.start();
-        mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mHandler = new Handler(thread.getLooper(), mHandlerCallback);
 
         mSystemDir = checkNotNull(systemDir);
         mBaseDir = new File(systemDir, "netstats");
@@ -415,6 +414,8 @@
             }
         } catch (IOException e) {
             Log.wtf(TAG, "problem during legacy upgrade", e);
+        } catch (OutOfMemoryError e) {
+            Log.wtf(TAG, "problem during legacy upgrade", e);
         }
     }
 
@@ -423,20 +424,16 @@
      * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
      */
     private void registerPollAlarmLocked() {
-        try {
-            if (mPollIntent != null) {
-                mAlarmManager.remove(mPollIntent);
-            }
-
-            mPollIntent = PendingIntent.getBroadcast(
-                    mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
-
-            final long currentRealtime = SystemClock.elapsedRealtime();
-            mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
-                    mSettings.getPollInterval(), mPollIntent);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
+        if (mPollIntent != null) {
+            mAlarmManager.cancel(mPollIntent);
         }
+
+        mPollIntent = PendingIntent.getBroadcast(
+                mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
+
+        final long currentRealtime = SystemClock.elapsedRealtime();
+        mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
+                mSettings.getPollInterval(), mPollIntent);
     }
 
     /**
@@ -1193,8 +1190,7 @@
      */
     private NetworkStats getNetworkStatsTethering() throws RemoteException {
         try {
-            final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
-            return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
+            return mNetworkManager.getNetworkStatsTethering();
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem reading network stats", e);
             return new NetworkStats(0L, 10);
diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/java/com/android/server/pm/GrantedPermissions.java
index c7629b9..14258a4 100644
--- a/services/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/java/com/android/server/pm/GrantedPermissions.java
@@ -44,6 +44,7 @@
     void setFlags(int pkgFlags) {
         this.pkgFlags = pkgFlags
                 & (ApplicationInfo.FLAG_SYSTEM
+                        | ApplicationInfo.FLAG_PRIVILEGED
                         | ApplicationInfo.FLAG_FORWARD_LOCK
                         | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
     }
diff --git a/services/java/com/android/server/pm/KeySetManager.java b/services/java/com/android/server/pm/KeySetManager.java
new file mode 100644
index 0000000..66dc1d1
--- /dev/null
+++ b/services/java/com/android/server/pm/KeySetManager.java
@@ -0,0 +1,586 @@
+/*
+ * 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.pm;
+
+import android.content.pm.KeySet;
+import android.content.pm.PackageParser;
+import android.os.Binder;
+import android.util.Base64;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+/*
+ * Manages system-wide KeySet state.
+ */
+public class KeySetManager {
+
+    static final String TAG = "KeySetManager";
+
+    /** Sentinel value returned when a {@code KeySet} is not found. */
+    public static final long KEYSET_NOT_FOUND = -1;
+
+    /** Sentinel value returned when public key is not found. */
+    private static final long PUBLIC_KEY_NOT_FOUND = -1;
+
+    private final Object mLockObject = new Object();
+
+    private final LongSparseArray<KeySet> mKeySets;
+
+    private final LongSparseArray<PublicKey> mPublicKeys;
+
+    private final LongSparseArray<Set<Long>> mKeySetMapping;
+
+    private final Map<String, PackageSetting> mPackages;
+
+    private static long lastIssuedKeySetId = 0;
+
+    private static long lastIssuedKeyId = 0;
+
+    public KeySetManager(Map<String, PackageSetting> packages) {
+        mKeySets = new LongSparseArray<KeySet>();
+        mPublicKeys = new LongSparseArray<PublicKey>();
+        mKeySetMapping = new LongSparseArray<Set<Long>>();
+        mPackages = packages;
+    }
+
+    /**
+     * Determine if a package is signed by the given KeySet.
+     *
+     * Returns false if the package was not signed by all the
+     * keys in the KeySet.
+     *
+     * Returns true if the package was signed by at least the
+     * keys in the given KeySet.
+     *
+     * Note that this can return true for multiple KeySets.
+     */
+    public boolean packageIsSignedBy(String packageName, KeySet ks) {
+        synchronized (mLockObject) {
+            PackageSetting pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                throw new NullPointerException("Invalid package name");
+            }
+            if (pkg.keySetData == null) {
+                throw new NullPointerException("Package has no KeySet data");
+            }
+            long id = getIdByKeySetLocked(ks);
+            return pkg.keySetData.packageIsSignedBy(id);
+        }
+    }
+
+    /**
+     * This informs the system that the given package has defined a KeySet
+     * in its manifest that a) contains the given keys and b) is named
+     * alias by that package.
+     */
+    public void addDefinedKeySetToPackage(String packageName,
+            Set<PublicKey> keys, String alias) {
+        if ((packageName == null) || (keys == null) || (alias == null)) {
+            //Log.d(TAG, "Got null argument for a defined keyset, ignoring!");
+            return;
+        }
+        synchronized (mLockObject) {
+            KeySet ks = addKeySetLocked(keys);
+            PackageSetting pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                throw new NullPointerException("Unknown package");
+            }
+            long id = getIdByKeySetLocked(ks);
+            pkg.keySetData.addDefinedKeySet(id, alias);
+        }
+    }
+
+    /**
+     * Similar to the above, this informs the system that the given package
+     * was signed by the provided KeySet.
+     */
+    public void addSigningKeySetToPackage(String packageName,
+            Set<PublicKey> signingKeys) {
+        if ((packageName == null) || (signingKeys == null)) {
+            //Log.d(TAG, "Got null argument for a signing keyset, ignoring!");
+            return;
+        }
+        synchronized (mLockObject) {
+            // add the signing KeySet
+            KeySet ks = addKeySetLocked(signingKeys);
+            long id = getIdByKeySetLocked(ks);
+            Set<Long> publicKeyIds = mKeySetMapping.get(id);
+            if (publicKeyIds == null) {
+                throw new NullPointerException("Got invalid KeySet id");
+            }
+
+            // attach it to the package
+            PackageSetting pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                throw new NullPointerException("No such package!");
+            }
+            pkg.keySetData.addSigningKeySet(id);
+
+            // for each KeySet the package defines which is a subset of
+            // the one above, add the KeySet id to the package's signing KeySets
+            for (Long keySetID : pkg.keySetData.getDefinedKeySets()) {
+                Set<Long> definedKeys = mKeySetMapping.get(keySetID);
+                if (publicKeyIds.contains(definedKeys)) {
+                    pkg.keySetData.addSigningKeySet(keySetID);
+                }
+            }
+        }
+    }
+
+    /**
+     * Fetches the stable identifier associated with the given KeySet. Returns
+     * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
+     */
+    public long getIdByKeySet(KeySet ks) {
+        synchronized (mLockObject) {
+            return getIdByKeySetLocked(ks);
+        }
+    }
+
+    private long getIdByKeySetLocked(KeySet ks) {
+        for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
+            KeySet value = mKeySets.valueAt(keySetIndex);
+            if (ks.equals(value)) {
+                return mKeySets.keyAt(keySetIndex);
+            }
+        }
+        return KEYSET_NOT_FOUND;
+    }
+
+    /**
+     * Fetches the KeySet corresponding to the given stable identifier.
+     *
+     * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
+     * identify a {@link KeySet}.
+     */
+    public KeySet getKeySetById(long id) {
+        synchronized (mLockObject) {
+            return mKeySets.get(id);
+        }
+    }
+
+    /**
+     * Fetches the KeySet that a given package refers to by the provided alias.
+     *
+     * If the package isn't known to us, throws an IllegalArgumentException.
+     * Returns null if the alias isn't known to us.
+     */
+    public KeySet getKeySetByAliasAndPackageName(String packageName, String alias) {
+        synchronized (mLockObject) {
+            PackageSetting p = mPackages.get(packageName);
+            if (p == null) {
+                throw new NullPointerException("Unknown package");
+            }
+            if (p.keySetData == null) {
+                throw new IllegalArgumentException("Package has no keySet data");
+            }
+            long keySetId = p.keySetData.getAliases().get(alias);
+            return mKeySets.get(keySetId);
+        }
+    }
+
+    /**
+     * Fetches all the known {@link KeySet KeySets} that signed the given
+     * package. Returns {@code null} if package is unknown.
+     */
+    public Set<KeySet> getSigningKeySetsByPackageName(String packageName) {
+        synchronized (mLockObject) {
+            Set<KeySet> signingKeySets = new HashSet<KeySet>();
+            PackageSetting p = mPackages.get(packageName);
+            if (p == null) {
+                throw new NullPointerException("Unknown package");
+            }
+            if (p.keySetData == null) {
+                throw new IllegalArgumentException("Package has no keySet data");
+            }
+            for (long l : p.keySetData.getSigningKeySets()) {
+                signingKeySets.add(mKeySets.get(l));
+            }
+            return signingKeySets;
+        }
+    }
+
+    /**
+     * Creates a new KeySet corresponding to the given keys.
+     *
+     * If the {@link PublicKey PublicKeys} aren't known to the system, this
+     * adds them. Otherwise, they're deduped.
+     *
+     * If the KeySet isn't known to the system, this adds that and creates the
+     * mapping to the PublicKeys. If it is known, then it's deduped.
+     *
+     * Throws if the provided set is {@code null}.
+     */
+    private KeySet addKeySetLocked(Set<PublicKey> keys) {
+        if (keys == null) {
+            throw new NullPointerException("Provided keys cannot be null");
+        }
+        // add each of the keys in the provided set
+        Set<Long> addedKeyIds = new HashSet<Long>(keys.size());
+        for (PublicKey k : keys) {
+            long id = addPublicKeyLocked(k);
+            addedKeyIds.add(id);
+        }
+
+        // check to see if the resulting keyset is new
+        long existingKeySetId = getIdFromKeyIdsLocked(addedKeyIds);
+        if (existingKeySetId != KEYSET_NOT_FOUND) {
+            return mKeySets.get(existingKeySetId);
+        }
+
+        // create the KeySet object
+        KeySet ks = new KeySet(new Binder());
+        // get the first unoccupied slot in mKeySets
+        long id = getFreeKeySetIDLocked();
+        // add the KeySet object to it
+        mKeySets.put(id, ks);
+        // add the stable key ids to the mapping
+        mKeySetMapping.put(id, addedKeyIds);
+        // go home
+        return ks;
+    }
+
+    /**
+     * Adds the given PublicKey to the system, deduping as it goes.
+     */
+    private long addPublicKeyLocked(PublicKey key) {
+        // check if the public key is new
+        long existingKeyId = getIdForPublicKeyLocked(key);
+        if (existingKeyId != PUBLIC_KEY_NOT_FOUND) {
+            return existingKeyId;
+        }
+        // if it's new find the first unoccupied slot in the public keys
+        long id = getFreePublicKeyIdLocked();
+        // add the public key to it
+        mPublicKeys.put(id, key);
+        // return the stable identifier
+        return id;
+    }
+
+    /**
+     * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
+     *
+     * Returns KEYSET_NOT_FOUND if there isn't one.
+     */
+    private long getIdFromKeyIdsLocked(Set<Long> publicKeyIds) {
+        for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
+            Set<Long> value = mKeySetMapping.valueAt(keyMapIndex);
+            if (value.equals(publicKeyIds)) {
+                return mKeySetMapping.keyAt(keyMapIndex);
+            }
+        }
+        return KEYSET_NOT_FOUND;
+    }
+
+    /**
+     * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
+     */
+    private long getIdForPublicKeyLocked(PublicKey k) {
+        String encodedPublicKey = new String(k.getEncoded());
+        for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
+            PublicKey value = mPublicKeys.valueAt(publicKeyIndex);
+            String encodedExistingKey = new String(value.getEncoded());
+            if (encodedPublicKey.equals(encodedExistingKey)) {
+                return mPublicKeys.keyAt(publicKeyIndex);
+            }
+        }
+        return PUBLIC_KEY_NOT_FOUND;
+    }
+
+    /**
+     * Gets an unused stable identifier for a KeySet.
+     */
+    private long getFreeKeySetIDLocked() {
+        lastIssuedKeySetId += 1;
+        return lastIssuedKeySetId;
+    }
+
+    /**
+     * Same as above, but for public keys.
+     */
+    private long getFreePublicKeyIdLocked() {
+        lastIssuedKeyId += 1;
+        return lastIssuedKeyId;
+    }
+
+    public void removeAppKeySetData(String packageName) {
+        synchronized (mLockObject) {
+            // Get the package's known keys and KeySets
+            Set<Long> deletableKeySets = getKnownKeySetsByPackageNameLocked(packageName);
+            Set<Long> deletableKeys = new HashSet<Long>();
+            Set<Long> knownKeys = null;
+            for (Long ks : deletableKeySets) {
+                knownKeys = mKeySetMapping.get(ks);
+                if (knownKeys != null) {
+                    deletableKeys.addAll(knownKeys);
+                }
+            }
+
+            // Now remove the keys and KeySets known to any other package
+            for (String pkgName : mPackages.keySet()) {
+                if (pkgName.equals(packageName)) {
+                    continue;
+                }
+                Set<Long> knownKeySets = getKnownKeySetsByPackageNameLocked(pkgName);
+                deletableKeySets.removeAll(knownKeySets);
+                knownKeys = new HashSet<Long>();
+                for (Long ks : knownKeySets) {
+                    knownKeys = mKeySetMapping.get(ks);
+                    if (knownKeys != null) {
+                        deletableKeys.removeAll(knownKeys);
+                    }
+                }
+            }
+
+            // The remaining keys and KeySets are not known to any other
+            // application and so can be safely deleted.
+            for (Long ks : deletableKeySets) {
+                mKeySets.delete(ks);
+                mKeySetMapping.delete(ks);
+            }
+            for (Long keyId : deletableKeys) {
+                mPublicKeys.delete(keyId);
+            }
+
+            // Now remove them from the KeySets known to each package
+            for (String pkgName : mPackages.keySet()) {
+                PackageSetting p = mPackages.get(pkgName);
+                for (Long ks : deletableKeySets) {
+                    p.keySetData.removeSigningKeySet(ks);
+                    p.keySetData.removeDefinedKeySet(ks);
+                }
+            }
+        }
+    }
+
+    private Set<Long> getKnownKeySetsByPackageNameLocked(String packageName) {
+        PackageSetting p = mPackages.get(packageName);
+        if (p == null) {
+            throw new NullPointerException("Unknown package");
+        }
+        if (p.keySetData == null) {
+            throw new IllegalArgumentException("Package has no keySet data");
+        }
+        Set<Long> knownKeySets = new HashSet<Long>();
+        for (long ks : p.keySetData.getSigningKeySets()) {
+            knownKeySets.add(ks);
+        }
+        for (long ks : p.keySetData.getDefinedKeySets()) {
+            knownKeySets.add(ks);
+        }
+        return knownKeySets;
+    }
+
+    public String encodePublicKey(PublicKey k) throws IOException {
+        return new String(Base64.encode(k.getEncoded(), 0));
+    }
+
+    public void dump(PrintWriter pw, String packageName,
+            PackageManagerService.DumpState dumpState) {
+        synchronized (mLockObject) {
+            boolean printedHeader = false;
+            for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) {
+                String keySetPackage = e.getKey();
+                if (packageName != null && !packageName.equals(keySetPackage)) {
+                    continue;
+                }
+                if (!printedHeader) {
+                    if (dumpState.onTitlePrinted())
+                        pw.println();
+                    pw.println("Key Set Manager:");
+                    printedHeader = true;
+                }
+                PackageSetting pkg = e.getValue();
+                pw.print("  ["); pw.print(keySetPackage); pw.println("]");
+                if (pkg.keySetData != null) {
+                    boolean printedLabel = false;
+                    for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
+                        if (!printedLabel) {
+                            pw.print("      KeySets Aliases: ");
+                            printedLabel = true;
+                        } else {
+                            pw.print(", ");
+                        }
+                        pw.print(entry.getKey());
+                        pw.print('=');
+                        pw.print(Long.toString(entry.getValue()));
+                    }
+                    if (printedLabel) {
+                        pw.println("");
+                    }
+                    printedLabel = false;
+                    for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
+                        if (!printedLabel) {
+                            pw.print("      Defined KeySets: ");
+                            printedLabel = true;
+                        } else {
+                            pw.print(", ");
+                        }
+                        pw.print(Long.toString(keySetId));
+                    }
+                    if (printedLabel) {
+                        pw.println("");
+                    }
+                    printedLabel = false;
+                    for (long keySetId : pkg.keySetData.getSigningKeySets()) {
+                        if (!printedLabel) {
+                            pw.print("      Signing KeySets: ");
+                            printedLabel = true;
+                        } else {
+                            pw.print(", ");
+                        }
+                        pw.print(Long.toString(keySetId));
+                    }
+                    if (printedLabel) {
+                        pw.println("");
+                    }
+                }
+            }
+        }
+    }
+
+    void writeKeySetManagerLPr(XmlSerializer serializer) throws IOException {
+        serializer.startTag(null, "keyset-settings");
+        writePublicKeysLPr(serializer);
+        writeKeySetsLPr(serializer);
+        serializer.startTag(null, "lastIssuedKeyId");
+        serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
+        serializer.endTag(null, "lastIssuedKeyId");
+        serializer.startTag(null, "lastIssuedKeySetId");
+        serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
+        serializer.endTag(null, "lastIssuedKeySetId");
+        serializer.endTag(null, "keyset-settings");
+    }
+
+    void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
+        serializer.startTag(null, "keys");
+        for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
+            long id = mPublicKeys.keyAt(pKeyIndex);
+            PublicKey key = mPublicKeys.valueAt(pKeyIndex);
+            String encodedKey = encodePublicKey(key);
+            serializer.startTag(null, "public-key");
+            serializer.attribute(null, "identifier", Long.toString(id));
+            serializer.attribute(null, "value", encodedKey);
+            serializer.endTag(null, "public-key");
+        }
+        serializer.endTag(null, "keys");
+    }
+
+    void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
+        serializer.startTag(null, "keysets");
+        for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
+            long id = mKeySetMapping.keyAt(keySetIndex);
+            Set<Long> keys = mKeySetMapping.valueAt(keySetIndex);
+            serializer.startTag(null, "keyset");
+            serializer.attribute(null, "identifier", Long.toString(id));
+            for (long keyId : keys) {
+                serializer.startTag(null, "key-id");
+                serializer.attribute(null, "identifier", Long.toString(keyId));
+                serializer.endTag(null, "key-id");
+            }
+            serializer.endTag(null, "keyset");
+        }
+        serializer.endTag(null, "keysets");
+    }
+
+    void readKeySetsLPw(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int type;
+        long currentKeySetId = 0;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            final String tagName = parser.getName();
+            if (tagName.equals("keys")) {
+                readKeysLPw(parser);
+            } else if (tagName.equals("keysets")) {
+                readKeySetListLPw(parser);
+            }
+        }
+    }
+
+    void readKeysLPw(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            final String tagName = parser.getName();
+            if (tagName.equals("public-key")) {
+                readPublicKeyLPw(parser);
+            } else if (tagName.equals("lastIssuedKeyId")) {
+                lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
+            } else if (tagName.equals("lastIssuedKeySetId")) {
+                lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
+            }
+        }
+    }
+
+    void readKeySetListLPw(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        long currentKeySetId = 0;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            final String tagName = parser.getName();
+            if (tagName.equals("keyset")) {
+                currentKeySetId = readIdentifierLPw(parser);
+                mKeySets.put(currentKeySetId, new KeySet(new Binder()));
+                mKeySetMapping.put(currentKeySetId, new HashSet<Long>());
+            } else if (tagName.equals("key-id")) {
+                long id = readIdentifierLPw(parser);
+                mKeySetMapping.get(currentKeySetId).add(id);
+            }
+        }
+    }
+
+    long readIdentifierLPw(XmlPullParser parser)
+            throws XmlPullParserException {
+        return Long.parseLong(parser.getAttributeValue(null, "identifier"));
+    }
+
+    void readPublicKeyLPw(XmlPullParser parser)
+            throws XmlPullParserException {
+        String encodedID = parser.getAttributeValue(null, "identifier");
+        long identifier = Long.parseLong(encodedID);
+        String encodedPublicKey = parser.getAttributeValue(null, "value");
+        PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
+        if (pub != null) {
+            mPublicKeys.put(identifier, pub);
+        }
+    }
+}
diff --git a/services/java/com/android/server/pm/PackageKeySetData.java b/services/java/com/android/server/pm/PackageKeySetData.java
new file mode 100644
index 0000000..cb60621
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageKeySetData.java
@@ -0,0 +1,125 @@
+/*
+ * 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.pm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class PackageKeySetData {
+
+    private long[] mSigningKeySets;
+
+    private long[] mDefinedKeySets;
+
+    private final Map<String, Long> mKeySetAliases;
+
+    PackageKeySetData() {
+        mSigningKeySets = new long[0];
+        mDefinedKeySets = new long[0];
+        mKeySetAliases =  new HashMap<String, Long>();
+    }
+
+    PackageKeySetData(PackageKeySetData original) {
+        mSigningKeySets = original.getSigningKeySets().clone();
+        mDefinedKeySets = original.getDefinedKeySets().clone();
+        mKeySetAliases = new HashMap<String, Long>();
+        mKeySetAliases.putAll(original.getAliases());
+    }
+
+    public void addSigningKeySet(long ks) {
+        // deduplicate
+        for (long knownKeySet : mSigningKeySets) {
+            if (ks == knownKeySet) {
+                return;
+            }
+        }
+        int end = mSigningKeySets.length;
+        mSigningKeySets = Arrays.copyOf(mSigningKeySets, end + 1);
+        mSigningKeySets[end] = ks;
+    }
+
+    public void removeSigningKeySet(long ks) {
+        if (packageIsSignedBy(ks)) {
+            long[] keysets = new long[mSigningKeySets.length - 1];
+            int index = 0;
+            for (long signingKeySet : mSigningKeySets) {
+                if (signingKeySet != ks) {
+                    keysets[index] = signingKeySet;
+                    index += 1;
+                }
+            }
+            mSigningKeySets = keysets;
+        }
+    }
+
+    public void addDefinedKeySet(long ks, String alias) {
+        // deduplicate
+        for (long knownKeySet : mDefinedKeySets) {
+            if (ks == knownKeySet) {
+                return;
+            }
+        }
+        int end = mDefinedKeySets.length;
+        mDefinedKeySets = Arrays.copyOf(mDefinedKeySets, end + 1);
+        mDefinedKeySets[end] = ks;
+        mKeySetAliases.put(alias, ks);
+    }
+
+    public void removeDefinedKeySet(long ks) {
+        if (mKeySetAliases.containsValue(ks)) {
+            long[] keysets = new long[mDefinedKeySets.length - 1];
+            int index = 0;
+            for (long definedKeySet : mDefinedKeySets) {
+                if (definedKeySet != ks) {
+                    keysets[index] = definedKeySet;
+                    index += 1;
+                }
+            }
+            mDefinedKeySets = keysets;
+            for (String alias : mKeySetAliases.keySet()) {
+                if (mKeySetAliases.get(alias) == ks) {
+                    mKeySetAliases.remove(alias);
+                    break;
+                }
+            }
+        }
+    }
+
+    public boolean packageIsSignedBy(long ks) {
+        for (long signingKeySet : mSigningKeySets) {
+            if (ks == signingKeySet) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public long[] getSigningKeySets() {
+        return mSigningKeySets;
+    }
+
+    public long[] getDefinedKeySets() {
+        return mDefinedKeySets;
+    }
+
+    public Map<String, Long> getAliases() {
+        return mKeySetAliases;
+    }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index a84f900..41a122b 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -35,12 +35,14 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
+import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 import com.android.server.DeviceStorageMonitorService;
 import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
 
+import com.android.server.Watchdog;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -89,6 +91,7 @@
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -112,13 +115,14 @@
 import android.os.UserHandle;
 import android.os.Environment.UserEnvironment;
 import android.os.UserManager;
-import android.provider.Settings.Secure;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.LogPrinter;
+import android.util.PrintStreamPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -157,6 +161,8 @@
 import libcore.io.Libcore;
 import libcore.io.StructStat;
 
+import com.android.internal.R;
+
 /**
  * Keep track of all those .apks everywhere.
  * 
@@ -276,6 +282,9 @@
     // This is the object monitoring the system app dir.
     final FileObserver mSystemInstallObserver;
 
+    // This is the object monitoring the privileged system app dir.
+    final FileObserver mPrivilegedInstallObserver;
+
     // This is the object monitoring the system app dir.
     final FileObserver mVendorInstallObserver;
 
@@ -289,11 +298,7 @@
     // LOCK HELD.  Can be called with mInstallLock held.
     final Installer mInstaller;
 
-    final File mFrameworkDir;
-    final File mSystemAppDir;
-    final File mVendorAppDir;
     final File mAppInstallDir;
-    final File mDalvikCacheDir;
 
     /**
      * Directory to which applications installed internally have native
@@ -420,6 +425,9 @@
     final ResolveInfo mResolveInfo = new ResolveInfo();
     ComponentName mResolveComponentName;
     PackageParser.Package mPlatformPackage;
+    ComponentName mCustomResolverComponentName;
+
+    boolean mResolverReplaced = false;
 
     // Set of pending broadcasts for aggregating enable/disable of components.
     static class PendingPackageBroadcasts {
@@ -427,7 +435,7 @@
         final SparseArray<HashMap<String, ArrayList<String>>> mUidMap;
 
         public PendingPackageBroadcasts() {
-            mUidMap = new SparseArray<HashMap<String, ArrayList<String>>>();
+            mUidMap = new SparseArray<HashMap<String, ArrayList<String>>>(2);
         }
 
         public ArrayList<String> get(int userId, String packageName) {
@@ -1054,13 +1062,18 @@
         mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings(context);
-        mSettings.addSharedUserLPw("android.uid.system",
-                Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM);
+        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
 
         String separateProcesses = SystemProperties.get("debug.separate_processes");
         if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -1090,6 +1103,7 @@
         synchronized (mPackages) {
             mHandlerThread.start();
             mHandler = new PackageHandler(mHandlerThread.getLooper());
+            Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());
 
             File dataDir = Environment.getDataDirectory();
             mAppDataDir = new File(dataDir, "data");
@@ -1109,6 +1123,15 @@
             mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                     mSdkVersion, mOnlyCore);
 
+            String customResolverActivity = Resources.getSystem().getString(
+                    R.string.config_customResolverActivity);
+            if (TextUtils.isEmpty(customResolverActivity)) {
+                customResolverActivity = null;
+            } else {
+                mCustomResolverComponentName = ComponentName.unflattenFromString(
+                        customResolverActivity);
+            }
+
             long startTime = SystemClock.uptimeMillis();
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -1122,40 +1145,27 @@
                 scanMode |= SCAN_NO_DEX;
             }
 
-            final HashSet<String> libFiles = new HashSet<String>();
-
-            mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
-            mDalvikCacheDir = new File(dataDir, "dalvik-cache");
-
-            boolean didDexOpt = false;
+            final HashSet<String> alreadyDexOpted = new HashSet<String>();
 
             /**
-             * Out of paranoia, ensure that everything in the boot class
-             * path has been dexed.
+             * Add everything in the in the boot class path to the
+             * list of process files because dexopt will have been run
+             * if necessary during zygote startup.
              */
             String bootClassPath = System.getProperty("java.boot.class.path");
             if (bootClassPath != null) {
                 String[] paths = splitString(bootClassPath, ':');
                 for (int i=0; i<paths.length; i++) {
-                    try {
-                        if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
-                            libFiles.add(paths[i]);
-                            mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
-                            didDexOpt = true;
-                        }
-                    } catch (FileNotFoundException e) {
-                        Slog.w(TAG, "Boot class path not found: " + paths[i]);
-                    } catch (IOException e) {
-                        Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "
-                                + e.getMessage());
-                    }
+                    alreadyDexOpted.add(paths[i]);
                 }
             } else {
                 Slog.w(TAG, "No BOOTCLASSPATH found!");
             }
 
+            boolean didDexOpt = false;
+
             /**
-             * Also ensure all external libraries have had dexopt run on them.
+             * Ensure all external libraries have had dexopt run on them.
              */
             if (mSharedLibraries.size() > 0) {
                 Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();
@@ -1166,7 +1176,7 @@
                     }
                     try {
                         if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
-                            libFiles.add(lib);
+                            alreadyDexOpted.add(lib);
                             mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
                             didDexOpt = true;
                         }
@@ -1179,22 +1189,29 @@
                 }
             }
 
+            File frameworkDir = new File(Environment.getRootDirectory(), "framework");
+
             // Gross hack for now: we know this file doesn't contain any
             // code, so don't dexopt it to avoid the resulting log spew.
-            libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
+            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
+
+            // Gross hack for now: we know this file is only part of
+            // the boot class path for art, so don't dexopt it to
+            // avoid the resulting log spew.
+            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
 
             /**
              * And there are a number of commands implemented in Java, which
              * we currently need to do the dexopt on so that they can be
              * run from a non-root shell.
              */
-            String[] frameworkFiles = mFrameworkDir.list();
+            String[] frameworkFiles = frameworkDir.list();
             if (frameworkFiles != null) {
                 for (int i=0; i<frameworkFiles.length; i++) {
-                    File libPath = new File(mFrameworkDir, frameworkFiles[i]);
+                    File libPath = new File(frameworkDir, frameworkFiles[i]);
                     String path = libPath.getPath();
                     // Skip the file if we alrady did it.
-                    if (libFiles.contains(path)) {
+                    if (alreadyDexOpted.contains(path)) {
                         continue;
                     }
                     // Skip the file if it is not a type we want to dexopt.
@@ -1215,19 +1232,21 @@
             }
 
             if (didDexOpt) {
+                File dalvikCacheDir = new File(dataDir, "dalvik-cache");
+
                 // 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.
-                String[] files = mDalvikCacheDir.list();
+                String[] files = dalvikCacheDir.list();
                 if (files != null) {
                     for (int i=0; i<files.length; i++) {
                         String fn = files[i];
                         if (fn.startsWith("data@app@")
                                 || fn.startsWith("data@app-private@")) {
                             Slog.i(TAG, "Pruning dalvik file: " + fn);
-                            (new File(mDalvikCacheDir, fn)).delete();
+                            (new File(dalvikCacheDir, fn)).delete();
                         }
                     }
                 }
@@ -1235,26 +1254,35 @@
 
             // Find base frameworks (resource packages without code).
             mFrameworkInstallObserver = new AppDirObserver(
-                mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
+                frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
             mFrameworkInstallObserver.startWatching();
-            scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
+            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
                     scanMode | SCAN_NO_DEX, 0);
 
-            // Collect all system packages.
-            mSystemAppDir = new File(Environment.getRootDirectory(), "app");
+            // Collected privileged system packages.
+            File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
+            mPrivilegedInstallObserver = new AppDirObserver(
+                    privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
+            mPrivilegedInstallObserver.startWatching();
+                scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
+                        | PackageParser.PARSE_IS_SYSTEM_DIR
+                        | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);
+
+            // Collect ordinary system packages.
+            File systemAppDir = new File(Environment.getRootDirectory(), "app");
             mSystemInstallObserver = new AppDirObserver(
-                mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
+                systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
             mSystemInstallObserver.startWatching();
-            scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
+            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
 
             // Collect all vendor packages.
-            mVendorAppDir = new File("/vendor/app");
+            File vendorAppDir = new File("/vendor/app");
             mVendorInstallObserver = new AppDirObserver(
-                mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
+                vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
             mVendorInstallObserver.startWatching();
-            scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
+            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
 
             if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
@@ -1321,16 +1349,19 @@
             //delete tmp files
             deleteTempPackageFiles();
 
+            // Remove any shared userIDs that have no associated packages
+            mSettings.pruneSharedUsersLPw();
+
             if (!mOnlyCore) {
                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                         SystemClock.uptimeMillis());
                 mAppInstallObserver = new AppDirObserver(
-                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
+                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);
                 mAppInstallObserver.startWatching();
                 scanDirLI(mAppInstallDir, 0, scanMode, 0);
     
                 mDrmAppInstallObserver = new AppDirObserver(
-                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
+                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false);
                 mDrmAppInstallObserver.startWatching();
                 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                         scanMode, 0);
@@ -1470,7 +1501,7 @@
             return super.onTransact(code, data, reply, flags);
         } catch (RuntimeException e) {
             if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) {
-                Slog.e(TAG, "Package Manager Crash", e);
+                Slog.wtf(TAG, "Package Manager Crash", e);
             }
             throw e;
         }
@@ -1781,8 +1812,8 @@
         }
     }
 
+    @Override
     public int[] getPackageGids(String packageName) {
-        final boolean enforcedDefault = isPermissionEnforcedDefault(READ_EXTERNAL_STORAGE);
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1790,17 +1821,7 @@
                 Log.v(TAG, "getPackageGids" + packageName + ": " + p);
             if (p != null) {
                 final PackageSetting ps = (PackageSetting)p.mExtras;
-                final SharedUserSetting suid = ps.sharedUser;
-                int[] gids = suid != null ? suid.gids : ps.gids;
-
-                // include GIDs for any unenforced permissions
-                if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE, enforcedDefault)) {
-                    final BasePermission basePerm = mSettings.mPermissions.get(
-                            READ_EXTERNAL_STORAGE);
-                    gids = appendInts(gids, basePerm.gids);
-                }
-
-                return gids;
+                return ps.getGids();
             }
         }
         // stupid thing to indicate an error.
@@ -1913,8 +1934,6 @@
                         getDataPathForPackage(packageName, 0).getPath();
                 pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
             }
-            // pkg.mSetEnabled = ps.getEnabled(userId);
-            // pkg.mSetStopped = ps.getStopped(userId);
             return generatePackageInfo(pkg, flags, userId);
         }
         return null;
@@ -2123,7 +2142,6 @@
     }
 
     public int checkPermission(String permName, String pkgName) {
-        final boolean enforcedDefault = isPermissionEnforcedDefault(permName);
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(pkgName);
             if (p != null && p.mExtras != null) {
@@ -2136,15 +2154,11 @@
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
-            if (!isPermissionEnforcedLocked(permName, enforcedDefault)) {
-                return PackageManager.PERMISSION_GRANTED;
-            }
         }
         return PackageManager.PERMISSION_DENIED;
     }
 
     public int checkUidPermission(String permName, int uid) {
-        final boolean enforcedDefault = isPermissionEnforcedDefault(permName);
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
             if (obj != null) {
@@ -2158,9 +2172,6 @@
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
-            if (!isPermissionEnforcedLocked(permName, enforcedDefault)) {
-                return PackageManager.PERMISSION_GRANTED;
-            }
         }
         return PackageManager.PERMISSION_DENIED;
     }
@@ -2565,6 +2576,20 @@
         }
     }
 
+    public int getFlagsForUid(int uid) {
+        synchronized (mPackages) {
+            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+            if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+                return sus.pkgFlags;
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return ps.pkgFlags;
+            }
+        }
+        return 0;
+    }
+
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
@@ -2574,6 +2599,37 @@
         return chooseBestActivity(intent, resolvedType, flags, query, userId);
     }
 
+    @Override
+    public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
+            IntentFilter filter, int match, ComponentName activity) {
+        final int userId = UserHandle.getCallingUserId();
+        if (DEBUG_PREFERRED) {
+            Log.v(TAG, "setLastChosenActivity intent=" + intent
+                + " resolvedType=" + resolvedType
+                + " flags=" + flags
+                + " filter=" + filter
+                + " match=" + match
+                + " activity=" + activity);
+            filter.dump(new PrintStreamPrinter(System.out), "    ");
+        }
+        intent.setComponent(null);
+        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+        // Find any earlier preferred or last chosen entries and nuke them
+        findPreferredActivity(intent, resolvedType,
+                flags, query, 0, false, true, false, userId);
+        // Add the new activity as the last chosen for this filter
+        addPreferredActivityInternal(filter, match, null, activity, false, userId);
+    }
+
+    @Override
+    public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
+        final int userId = UserHandle.getCallingUserId();
+        if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
+        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+        return findPreferredActivity(intent, resolvedType, flags, query, 0,
+                false, false, false, userId);
+    }
+
     private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
             int flags, List<ResolveInfo> query, int userId) {
         if (query != null) {
@@ -2581,12 +2637,13 @@
             if (N == 1) {
                 return query.get(0);
             } else if (N > 1) {
+                final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
                 // If there is more than one activity with the same priority,
                 // then let the user decide between them.
                 ResolveInfo r0 = query.get(0);
                 ResolveInfo r1 = query.get(1);
-                if (DEBUG_INTENT_MATCHING) {
-                    Log.d(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
+                if (DEBUG_INTENT_MATCHING || debug) {
+                    Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
                             + r1.activityInfo.name + "=" + r1.priority);
                 }
                 // If the first activity has a higher priority, or a different
@@ -2599,7 +2656,7 @@
                 // If we have saved a preference for a preferred activity for
                 // this Intent, use that.
                 ResolveInfo ri = findPreferredActivity(intent, resolvedType,
-                        flags, query, r0.priority, userId);
+                        flags, query, r0.priority, true, false, debug, userId);
                 if (ri != null) {
                     return ri;
                 }
@@ -2618,16 +2675,19 @@
         return null;
     }
 
-    ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
-            int flags, List<ResolveInfo> query, int priority, int userId) {
+    ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags,
+            List<ResolveInfo> query, int priority, boolean always,
+            boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
-                intent = intent.getSelector(); 
+                intent = intent.getSelector();
             }
             if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
             PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+            // Get the list of preferred activities that handle the intent
+            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
             List<PreferredActivity> prefs = pir != null
                     ? pir.queryIntent(intent, resolvedType,
                             (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
@@ -2638,41 +2698,50 @@
                 // from the same match quality.
                 int match = 0;
 
-                if (DEBUG_PREFERRED) {
-                    Log.v(TAG, "Figuring out best match...");
-                }
+                if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
 
                 final int N = query.size();
                 for (int j=0; j<N; j++) {
                     final ResolveInfo ri = query.get(j);
-                    if (DEBUG_PREFERRED) {
-                        Log.v(TAG, "Match for " + ri.activityInfo + ": 0x"
-                                + Integer.toHexString(match));
-                    }
+                    if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo
+                            + ": 0x" + Integer.toHexString(match));
                     if (ri.match > match) {
                         match = ri.match;
                     }
                 }
 
-                if (DEBUG_PREFERRED) {
-                    Log.v(TAG, "Best match: 0x" + Integer.toHexString(match));
-                }
+                if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x"
+                        + Integer.toHexString(match));
 
                 match &= IntentFilter.MATCH_CATEGORY_MASK;
                 final int M = prefs.size();
                 for (int i=0; i<M; i++) {
                     final PreferredActivity pa = prefs.get(i);
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Checking PreferredActivity ds="
+                                + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
+                                + "\n  component=" + pa.mPref.mComponent);
+                        pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                    }
                     if (pa.mPref.mMatch != match) {
+                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match "
+                                + Integer.toHexString(pa.mPref.mMatch));
+                        continue;
+                    }
+                    // If it's not an "always" type preferred activity and that's what we're
+                    // looking for, skip it.
+                    if (always && !pa.mPref.mAlways) {
+                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
                         continue;
                     }
                     final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
                             flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
-                    if (DEBUG_PREFERRED) {
-                        Log.v(TAG, "Got preferred activity:");
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Found preferred activity:");
                         if (ai != null) {
-                            ai.dump(new LogPrinter(Log.VERBOSE, TAG), "  ");
+                            ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
                         } else {
-                            Log.v(TAG, "  null");
+                            Slog.v(TAG, "  null");
                         }
                     }
                     if (ai == null) {
@@ -2696,23 +2765,45 @@
                             continue;
                         }
 
-                        // Okay we found a previously set preferred app.
+                        if (removeMatches) {
+                            pir.removeFilter(pa);
+                            if (DEBUG_PREFERRED) {
+                                Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
+                            }
+                            break;
+                        }
+
+                        // Okay we found a previously set preferred or last chosen app.
                         // If the result set is different from when this
                         // was created, we need to clear it and re-ask the
-                        // user their preference.
-                        if (!pa.mPref.sameSet(query, priority)) {
+                        // user their preference, if we're looking for an "always" type entry.
+                        if (always && !pa.mPref.sameSet(query, priority)) {
                             Slog.i(TAG, "Result set changed, dropping preferred activity for "
                                     + intent + " type " + resolvedType);
+                            if (DEBUG_PREFERRED) {
+                                Slog.v(TAG, "Removing preferred activity since set changed "
+                                        + pa.mPref.mComponent);
+                            }
                             pir.removeFilter(pa);
+                            // Re-add the filter as a "last chosen" entry (!always)
+                            PreferredActivity lastChosen = new PreferredActivity(
+                                    pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
+                            pir.addFilter(lastChosen);
+                            mSettings.writePackageRestrictionsLPr(userId);
                             return null;
                         }
 
-                        // Yay!
+                        // Yay! Either the set matched or we're looking for the last chosen
+                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: "
+                                + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+                        mSettings.writePackageRestrictionsLPr(userId);
                         return ri;
                     }
                 }
             }
+            mSettings.writePackageRestrictionsLPr(userId);
         }
+        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return");
         return null;
     }
 
@@ -3235,7 +3326,6 @@
     public List<ProviderInfo> queryContentProviders(String processName,
             int uid, int flags) {
         ArrayList<ProviderInfo> finalList = null;
-
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
@@ -3311,7 +3401,8 @@
         }
 
         if (DEBUG_PACKAGE_SCANNING) {
-            Log.d(TAG, "Scanning app dir " + dir);
+            Log.d(TAG, "Scanning app dir " + dir + " scanMode=" + scanMode
+                    + " flags=0x" + Integer.toHexString(flags));
         }
 
         int i;
@@ -3344,7 +3435,7 @@
         try {
             File fname = getSettingsProblemFile();
             FileOutputStream out = new FileOutputStream(fname, true);
-            PrintWriter pw = new PrintWriter(out);
+            PrintWriter pw = new FastPrintWriter(out);
             SimpleDateFormat formatter = new SimpleDateFormat();
             String dateString = formatter.format(new Date(System.currentTimeMillis()));
             pw.println(dateString + ": " + msg);
@@ -3400,10 +3491,12 @@
         pp.setOnlyCoreApps(mOnlyCore);
         final PackageParser.Package pkg = pp.parsePackage(scanFile,
                 scanPath, mMetrics, parseFlags);
+
         if (pkg == null) {
             mLastScanError = pp.getParseError();
             return null;
         }
+
         PackageSetting ps = null;
         PackageSetting updatedPkg;
         // reader
@@ -3553,6 +3646,7 @@
         } else {
             resPath = pkg.mScanPath;
         }
+
         codePath = pkg.mScanPath;
         // Set application objects path explicitly.
         setApplicationInfoPaths(pkg, codePath, resPath);
@@ -3967,6 +4061,15 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         }
 
+        if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
+            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;
+        }
+
+        if (mCustomResolverComponentName != null &&
+                mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
+            setUpCustomResolverActivity(pkg);
+        }
+
         if (pkg.packageName.equals("android")) {
             synchronized (mPackages) {
                 if (mAndroidApplication != null) {
@@ -3978,26 +4081,28 @@
                     return null;
                 }
 
-                // Set up information for our fall-back user intent resolution
-                // activity.
+                // Set up information for our fall-back user intent resolution activity.
                 mPlatformPackage = pkg;
                 pkg.mVersionCode = mSdkVersion;
                 mAndroidApplication = pkg.applicationInfo;
-                mResolveActivity.applicationInfo = mAndroidApplication;
-                mResolveActivity.name = ResolverActivity.class.getName();
-                mResolveActivity.packageName = mAndroidApplication.packageName;
-                mResolveActivity.processName = "system:ui";
-                mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-                mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
-                mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
-                mResolveActivity.exported = true;
-                mResolveActivity.enabled = true;
-                mResolveInfo.activityInfo = mResolveActivity;
-                mResolveInfo.priority = 0;
-                mResolveInfo.preferredOrder = 0;
-                mResolveInfo.match = 0;
-                mResolveComponentName = new ComponentName(
-                        mAndroidApplication.packageName, mResolveActivity.name);
+
+                if (!mResolverReplaced) {
+                    mResolveActivity.applicationInfo = mAndroidApplication;
+                    mResolveActivity.name = ResolverActivity.class.getName();
+                    mResolveActivity.packageName = mAndroidApplication.packageName;
+                    mResolveActivity.processName = "system:ui";
+                    mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                    mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+                    mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
+                    mResolveActivity.exported = true;
+                    mResolveActivity.enabled = true;
+                    mResolveInfo.activityInfo = mResolveActivity;
+                    mResolveInfo.priority = 0;
+                    mResolveInfo.preferredOrder = 0;
+                    mResolveInfo.match = 0;
+                    mResolveComponentName = new ComponentName(
+                            mAndroidApplication.packageName, mResolveActivity.name);
+                }
             }
         }
 
@@ -4042,8 +4147,7 @@
             }
 
             if (pkg.mSharedUserId != null) {
-                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId,
-                        pkg.applicationInfo.flags, true);
+                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
                 if (suid == null) {
                     Slog.w(TAG, "Creating application package " + pkg.packageName
                             + " for shared user failed");
@@ -4540,7 +4644,7 @@
         // version of the application while the new one gets installed.
         if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
             killApplication(pkg.applicationInfo.packageName,
-                        pkg.applicationInfo.uid);
+                        pkg.applicationInfo.uid, "update pkg");
         }
 
         // Also need to kill any apps that are dependent on the library.
@@ -4548,7 +4652,7 @@
             for (int i=0; i<clientLibPkgs.size(); i++) {
                 PackageParser.Package clientPkg = clientLibPkgs.get(i);
                 killApplication(clientPkg.applicationInfo.packageName,
-                        clientPkg.applicationInfo.uid);
+                        clientPkg.applicationInfo.uid, "update lib");
             }
         }
 
@@ -4589,6 +4693,24 @@
                 }
             }
 
+            // Add the package's KeySets to the global KeySetManager
+            KeySetManager ksm = mSettings.mKeySetManager;
+            try {
+                ksm.addSigningKeySetToPackage(pkg.packageName, pkg.mSigningKeys);
+                if (pkg.mKeySetMapping != null) {
+                    for (Map.Entry<String, Set<PublicKey>> entry : pkg.mKeySetMapping.entrySet()) {
+                        if (entry.getValue() != null) {
+                            ksm.addDefinedKeySetToPackage(pkg.packageName,
+                                entry.getValue(), entry.getKey());
+                        }
+                    }
+                }
+            } catch (NullPointerException e) {
+                Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e);
+            } catch (IllegalArgumentException e) {
+                Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e);
+            }
+
             int N = pkg.providers.size();
             StringBuilder r = null;
             int i;
@@ -4845,6 +4967,30 @@
         return pkg;
     }
 
+    private void setUpCustomResolverActivity(PackageParser.Package pkg) {
+        synchronized (mPackages) {
+            mResolverReplaced = true;
+            // Set up information for custom user intent resolution activity.
+            mResolveActivity.applicationInfo = pkg.applicationInfo;
+            mResolveActivity.name = mCustomResolverComponentName.getClassName();
+            mResolveActivity.packageName = pkg.applicationInfo.packageName;
+            mResolveActivity.processName = null;
+            mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+            mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
+                    ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+            mResolveActivity.theme = 0;
+            mResolveActivity.exported = true;
+            mResolveActivity.enabled = true;
+            mResolveInfo.activityInfo = mResolveActivity;
+            mResolveInfo.priority = 0;
+            mResolveInfo.preferredOrder = 0;
+            mResolveInfo.match = 0;
+            mResolveComponentName = mCustomResolverComponentName;
+            Slog.i(TAG, "Replacing default ResolverActivity with custom activity: " +
+                    mResolveComponentName);
+        }
+    }
+
     private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
             PackageSetting pkgSetting) {
         final String apkLibPath = getApkName(pkgSetting.codePathString);
@@ -4880,14 +5026,14 @@
         return NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
     }
 
-    private void killApplication(String pkgName, int appId) {
+    private void killApplication(String pkgName, int appId, String reason) {
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
         // version of the application while the new one gets installed.
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                am.killApplicationWithAppId(pkgName, appId);
+                am.killApplicationWithAppId(pkgName, appId, reason);
             } catch (RemoteException e) {
             }
         }
@@ -5348,17 +5494,20 @@
                             .getDisabledSystemPkgLPr(pkg.packageName);
                     final GrantedPermissions origGp = sysPs.sharedUser != null
                             ? sysPs.sharedUser : sysPs;
+
                     if (origGp.grantedPermissions.contains(perm)) {
+                        // If the original was granted this permission, we take
+                        // that grant decision as read and propagate it to the
+                        // update.
                         allowed = true;
                     } else {
                         // The system apk may have been updated with an older
                         // version of the one on the data partition, but which
                         // granted a new system permission that it didn't have
                         // before.  In this case we do want to allow the app to
-                        // now get the new permission, because it is allowed by
-                        // the system image.
-                        allowed = false;
-                        if (sysPs.pkg != null) {
+                        // now get the new permission if the new system-partition
+                        // apk is privileged to get it.
+                        if (sysPs.pkg != null && isPrivilegedApp(pkg)) {
                             for (int j=0;
                                     j<sysPs.pkg.requestedPermissions.size(); j++) {
                                 if (perm.equals(
@@ -5370,7 +5519,7 @@
                         }
                     }
                 } else {
-                    allowed = true;
+                    allowed = isPrivilegedApp(pkg);
                 }
             }
         }
@@ -5564,7 +5713,7 @@
             out.print(prefix); out.print(
                     Integer.toHexString(System.identityHashCode(filter.activity)));
                     out.print(' ');
-                    out.print(filter.activity.getComponentShortName());
+                    filter.activity.printComponentShortName(out);
                     out.print(" filter ");
                     out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
@@ -5763,7 +5912,7 @@
             out.print(prefix); out.print(
                     Integer.toHexString(System.identityHashCode(filter.service)));
                     out.print(' ');
-                    out.print(filter.service.getComponentShortName());
+                    filter.service.printComponentShortName(out);
                     out.print(" filter ");
                     out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
@@ -5929,10 +6078,11 @@
     }
     
     private final class AppDirObserver extends FileObserver {
-        public AppDirObserver(String path, int mask, boolean isrom) {
+        public AppDirObserver(String path, int mask, boolean isrom, boolean isPrivileged) {
             super(path, mask);
             mRootDir = path;
             mIsRom = isrom;
+            mIsPrivileged = isPrivileged;
         }
 
         public void onEvent(int event, String path) {
@@ -5993,11 +6143,15 @@
                 if ((event&ADD_EVENTS) != 0) {
                     if (p == null) {
                         if (DEBUG_INSTALL) Slog.d(TAG, "New file appeared: " + fullPath);
-                        p = scanPackageLI(fullPath,
-                                (mIsRom ? PackageParser.PARSE_IS_SYSTEM
-                                        | PackageParser.PARSE_IS_SYSTEM_DIR: 0) |
-                                PackageParser.PARSE_CHATTY |
-                                PackageParser.PARSE_MUST_BE_APK,
+                        int flags = PackageParser.PARSE_CHATTY | PackageParser.PARSE_MUST_BE_APK;
+                        if (mIsRom) {
+                            flags |= PackageParser.PARSE_IS_SYSTEM
+                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
+                            if (mIsPrivileged) {
+                                flags |= PackageParser.PARSE_IS_PRIVILEGED;
+                            }
+                        }
+                        p = scanPackageLI(fullPath, flags,
                                 SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
                                 System.currentTimeMillis(), UserHandle.ALL);
                         if (p != null) {
@@ -6040,6 +6194,7 @@
 
         private final String mRootDir;
         private final boolean mIsRom;
+        private final boolean mIsPrivileged;
     }
 
     /* Called when a downloaded package installation has been confirmed by the user */
@@ -6107,6 +6262,122 @@
         mHandler.sendMessage(msg);
     }
 
+    private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting, int userId) {
+        Bundle extras = new Bundle(1);
+        extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
+
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+                packageName, extras, null, null, new int[] {userId});
+        try {
+            IActivityManager am = ActivityManagerNative.getDefault();
+            final boolean isSystem =
+                    isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
+            if (isSystem && am.isUserRunning(userId, false)) {
+                // The just-installed/enabled app is bundled on the system, so presumed
+                // to be able to run automatically without needing an explicit launch.
+                // Send it a BOOT_COMPLETED if it would ordinarily have gotten one.
+                Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED)
+                        .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
+                        .setPackage(packageName);
+                am.broadcastIntent(null, bcIntent, null, null, 0, null, null, null,
+                        android.app.AppOpsManager.OP_NONE, false, false, userId);
+            }
+        } catch (RemoteException e) {
+            // shouldn't happen
+            Slog.w(TAG, "Unable to bootstrap installed package", e);
+        }
+    }
+
+    @Override
+    public boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked,
+            int userId) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        PackageSetting pkgSetting;
+        final int uid = Binder.getCallingUid();
+        if (UserHandle.getUserId(uid) != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "setApplicationBlockedSetting for user " + userId);
+        }
+
+        if (blocked && isPackageDeviceAdmin(packageName, userId)) {
+            Slog.w(TAG, "Not blocking package " + packageName + ": has active device admin");
+            return false;
+        }
+
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            boolean sendAdded = false;
+            boolean sendRemoved = false;
+            // writer
+            synchronized (mPackages) {
+                pkgSetting = mSettings.mPackages.get(packageName);
+                if (pkgSetting == null) {
+                    return false;
+                }
+                if (pkgSetting.getBlocked(userId) != blocked) {
+                    pkgSetting.setBlocked(blocked, userId);
+                    mSettings.writePackageRestrictionsLPr(userId);
+                    if (blocked) {
+                        sendRemoved = true;
+                    } else {
+                        sendAdded = true;
+                    }
+                }
+            }
+            if (sendAdded) {
+                sendPackageAddedForUser(packageName, pkgSetting, userId);
+                return true;
+            }
+            if (sendRemoved) {
+                killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
+                        "blocking pkg");
+                sendPackageBlockedForUser(packageName, pkgSetting, userId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+        return false;
+    }
+
+    private void sendPackageBlockedForUser(String packageName, PackageSetting pkgSetting,
+            int userId) {
+        final PackageRemovedInfo info = new PackageRemovedInfo();
+        info.removedPackage = packageName;
+        info.removedUsers = new int[] {userId};
+        info.uid = UserHandle.getUid(userId, pkgSetting.appId);
+        info.sendBroadcast(false, false, false);
+    }
+
+    /**
+     * Returns true if application is not found or there was an error. Otherwise it returns
+     * the blocked state of the package for the given user.
+     */
+    @Override
+    public boolean getApplicationBlockedSettingAsUser(String packageName, int userId) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        PackageSetting pkgSetting;
+        final int uid = Binder.getCallingUid();
+        if (UserHandle.getUserId(uid) != userId) {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "getApplicationBlocked for user " + userId);
+        }
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            // writer
+            synchronized (mPackages) {
+                pkgSetting = mSettings.mPackages.get(packageName);
+                if (pkgSetting == null) {
+                    return true;
+                }
+                return pkgSetting.getBlocked(userId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     /**
      * @hide
      */
@@ -6138,33 +6409,14 @@
                 }
                 if (!pkgSetting.getInstalled(userId)) {
                     pkgSetting.setInstalled(true, userId);
+                    pkgSetting.setBlocked(false, userId);
                     mSettings.writePackageRestrictionsLPr(userId);
-                    extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
                     sendAdded = true;
                 }
             }
 
             if (sendAdded) {
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
-                        packageName, extras, null, null, new int[] {userId});
-                try {
-                    IActivityManager am = ActivityManagerNative.getDefault();
-                    final boolean isSystem =
-                            isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
-                    if (isSystem && am.isUserRunning(userId, false)) {
-                        // The just-installed/enabled app is bundled on the system, so presumed
-                        // to be able to run automatically without needing an explicit launch.
-                        // Send it a BOOT_COMPLETED if it would ordinarily have gotten one.
-                        Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED)
-                                .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
-                                .setPackage(packageName);
-                        am.broadcastIntent(null, bcIntent, null, null, 0, null, null, null,
-                                android.app.AppOpsManager.OP_NONE, false, false, userId);
-                    }
-                } catch (RemoteException e) {
-                    // shouldn't happen
-                    Slog.w(TAG, "Unable to bootstrap installed package", e);
-                }
+                sendPackageAddedForUser(packageName, pkgSetting, userId);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -6640,31 +6892,20 @@
             if (mounted) {
                 final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
 
-                final File externalCacheDir = userEnv
-                        .getExternalStorageAppCacheDirectory(mStats.packageName);
-                final long externalCacheSize = mContainerService
-                        .calculateDirectorySize(externalCacheDir.getPath());
-                mStats.externalCacheSize = externalCacheSize;
+                mStats.externalCacheSize = calculateDirectorySize(mContainerService,
+                        userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
 
-                final File externalDataDir = userEnv
-                        .getExternalStorageAppDataDirectory(mStats.packageName);
-                long externalDataSize = mContainerService.calculateDirectorySize(externalDataDir
-                        .getPath());
+                mStats.externalDataSize = calculateDirectorySize(mContainerService,
+                        userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
 
-                if (externalCacheDir.getParentFile().equals(externalDataDir)) {
-                    externalDataSize -= externalCacheSize;
-                }
-                mStats.externalDataSize = externalDataSize;
+                // Always subtract cache size, since it's a subdirectory
+                mStats.externalDataSize -= mStats.externalCacheSize;
 
-                final File externalMediaDir = userEnv
-                        .getExternalStorageAppMediaDirectory(mStats.packageName);
-                mStats.externalMediaSize = mContainerService
-                        .calculateDirectorySize(externalMediaDir.getPath());
+                mStats.externalMediaSize = calculateDirectorySize(mContainerService,
+                        userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
 
-                final File externalObbDir = userEnv
-                        .getExternalStorageAppObbDirectory(mStats.packageName);
-                mStats.externalObbSize = mContainerService.calculateDirectorySize(externalObbDir
-                        .getPath());
+                mStats.externalObbSize = calculateDirectorySize(mContainerService,
+                        userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
             }
         }
 
@@ -6686,6 +6927,24 @@
         }
     }
 
+    private static long calculateDirectorySize(IMediaContainerService mcs, File[] paths)
+            throws RemoteException {
+        long result = 0;
+        for (File path : paths) {
+            result += mcs.calculateDirectorySize(path.getAbsolutePath());
+        }
+        return result;
+    }
+
+    private static void clearDirectory(IMediaContainerService mcs, File[] paths) {
+        for (File path : paths) {
+            try {
+                mcs.clearDirectory(path.getAbsolutePath());
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     class InstallParams extends HandlerParams {
         final IPackageInstallObserver observer;
         int flags;
@@ -8231,6 +8490,9 @@
         boolean updatedSettings = false;
         parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING |
                 PackageParser.PARSE_IS_SYSTEM;
+        if ((deletedPackage.applicationInfo.flags&ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+            parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
+        }
         String packageName = deletedPackage.packageName;
         res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
         if (packageName == null) {
@@ -8250,7 +8512,7 @@
             }
         }
 
-        killApplication(packageName, oldPkg.applicationInfo.uid);
+        killApplication(packageName, oldPkg.applicationInfo.uid, "replace sys pkg");
 
         res.removedInfo.uid = oldPkg.applicationInfo.uid;
         res.removedInfo.removedPackage = packageName;
@@ -8543,6 +8805,10 @@
         return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
+    private static boolean isPrivilegedApp(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+    }
+
     private static boolean isSystemApp(ApplicationInfo info) {
         return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
@@ -8651,6 +8917,19 @@
         });
     }
 
+    private boolean isPackageDeviceAdmin(String packageName, int userId) {
+        IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
+                ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+        try {
+            if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId)
+                    || dpm.isDeviceOwner(packageName))) {
+                return true;
+            }
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
     /**
      *  This method is an internal method that could be get invoked either
      *  to delete an installed package or to clean up a failed installation.
@@ -8669,15 +8948,9 @@
         final PackageRemovedInfo info = new PackageRemovedInfo();
         final boolean res;
 
-        IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
-                ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
-        try {
-            if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId)
-                    || dpm.isDeviceOwner(packageName))) {
-                Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
-                return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
-            }
-        } catch (RemoteException e) {
+        if (isPackageDeviceAdmin(packageName, userId)) {
+            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
+            return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
         }
 
         boolean removedForAllUsers = false;
@@ -8993,6 +9266,7 @@
                         false, //installed
                         true,  //stopped
                         true,  //notLaunched
+                        false, //blocked
                         null, null, null);
                 if (!isSystemApp(ps)) {
                     if (ps.isAnyInstalled(sUserManager.getUserIds())) {
@@ -9043,7 +9317,9 @@
             removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
             return true;
         }
+
         boolean ret = false;
+        mSettings.mKeySetManager.removeAppKeySetData(packageName);
         if (isSystemApp(ps)) {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
             // When an updated system application is deleted we delete the existing resources as well and
@@ -9053,11 +9329,12 @@
         } else {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
             // Kill application pre-emptively especially for apps on sd.
-            killApplication(packageName, ps.appId);
+            killApplication(packageName, ps.appId, "uninstall pkg");
             ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
                     allUserHandles, perUserInstalled,
                     outInfo, writeSettings);
         }
+
         return ret;
     }
 
@@ -9119,25 +9396,13 @@
                     }
 
                     final UserEnvironment userEnv = new UserEnvironment(curUser);
-                    final File externalCacheDir = userEnv
-                            .getExternalStorageAppCacheDirectory(packageName);
-                    try {
-                        conn.mContainerService.clearDirectory(externalCacheDir.toString());
-                    } catch (RemoteException e) {
-                    }
+                    clearDirectory(conn.mContainerService,
+                            userEnv.buildExternalStorageAppCacheDirs(packageName));
                     if (allData) {
-                        final File externalDataDir = userEnv
-                                .getExternalStorageAppDataDirectory(packageName);
-                        try {
-                            conn.mContainerService.clearDirectory(externalDataDir.toString());
-                        } catch (RemoteException e) {
-                        }
-                        final File externalMediaDir = userEnv
-                                .getExternalStorageAppMediaDirectory(packageName);
-                        try {
-                            conn.mContainerService.clearDirectory(externalMediaDir.toString());
-                        } catch (RemoteException e) {
-                        }
+                        clearDirectory(conn.mContainerService,
+                                userEnv.buildExternalStorageAppDataDirs(packageName));
+                        clearDirectory(conn.mContainerService,
+                                userEnv.buildExternalStorageAppMediaDirs(packageName));
                     }
                 }
             } finally {
@@ -9410,9 +9675,14 @@
         }
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
     }
-    
+
     public void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity, int userId) {
+        addPreferredActivityInternal(filter, match, set, activity, true, userId);
+    }
+
+    private void addPreferredActivityInternal(IntentFilter filter, int match,
+            ComponentName[] set, ComponentName activity, boolean always, int userId) {
         // writer
         int callingUid = Binder.getCallingUid();
         enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
@@ -9433,7 +9703,7 @@
             Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
             mSettings.editPreferredActivitiesLPw(userId).addFilter(
-                    new PreferredActivity(filter, match, set, activity));
+                    new PreferredActivity(filter, match, set, activity, always));
             mSettings.writePackageRestrictionsLPr(userId);
         }
     }
@@ -9444,10 +9714,6 @@
             throw new IllegalArgumentException(
                     "replacePreferredActivity expects filter to have only 1 action.");
         }
-        if (filter.countCategories() != 1) {
-            throw new IllegalArgumentException(
-                    "replacePreferredActivity expects filter to have only 1 category.");
-        }
         if (filter.countDataAuthorities() != 0
                 || filter.countDataPaths() != 0
                 || filter.countDataSchemes() != 0
@@ -9484,8 +9750,11 @@
                             removed = new ArrayList<PreferredActivity>();
                         }
                         removed.add(pa);
-                        Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
-                        filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        if (DEBUG_PREFERRED) {
+                            Slog.i(TAG, "Removing preferred activity "
+                                    + pa.mPref.mComponent + ":");
+                            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        }
                     }
                 }
                 if (removed != null) {
@@ -9495,7 +9764,7 @@
                     }
                 }
             }
-            addPreferredActivity(filter, match, set, activity, callingUserId);
+            addPreferredActivityInternal(filter, match, set, activity, true, callingUserId);
         }
     }
 
@@ -9540,8 +9809,11 @@
             Iterator<PreferredActivity> it = pir.filterIterator();
             while (it.hasNext()) {
                 PreferredActivity pa = it.next();
+                // Mark entry for removal only if it matches the package name
+                // and the entry is of type "always".
                 if (packageName == null ||
-                        pa.mPref.mComponent.getPackageName().equals(packageName)) {
+                        (pa.mPref.mComponent.getPackageName().equals(packageName)
+                                && pa.mPref.mAlways)) {
                     if (removed == null) {
                         removed = new ArrayList<PreferredActivity>();
                     }
@@ -9585,7 +9857,8 @@
                 while (it.hasNext()) {
                     final PreferredActivity pa = it.next();
                     if (packageName == null
-                            || pa.mPref.mComponent.getPackageName().equals(packageName)) {
+                            || (pa.mPref.mComponent.getPackageName().equals(packageName)
+                                    && pa.mPref.mAlways)) {
                         if (outFilters != null) {
                             outFilters.add(new IntentFilter(pa));
                         }
@@ -9601,6 +9874,29 @@
     }
 
     @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+
+        final int callingUserId = UserHandle.getCallingUserId();
+        List<ResolveInfo> list = queryIntentActivities(intent, null,
+                PackageManager.GET_META_DATA, callingUserId);
+        ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
+                true, false, false, callingUserId);
+
+        allHomeCandidates.clear();
+        if (list != null) {
+            for (ResolveInfo ri : list) {
+                allHomeCandidates.add(ri);
+            }
+        }
+        return (preferred == null || preferred.activityInfo == null)
+                ? null
+                : new ComponentName(preferred.activityInfo.packageName,
+                        preferred.activityInfo.name);
+    }
+
+    @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
         if (!sUserManager.exists(userId)) return;
@@ -9854,6 +10150,7 @@
                 }
             }
         }
+        sUserManager.systemReady();
     }
 
     public boolean isSafeMode() {
@@ -9900,6 +10197,8 @@
 
         public static final int DUMP_PREFERRED_XML = 1 << 10;
 
+        public static final int DUMP_KEYSETS = 1 << 11;
+
         public static final int OPTION_SHOW_FILTERS = 1 << 0;
 
         private int mTypes;
@@ -9997,6 +10296,7 @@
                 pw.println("    m[essages]: print collected runtime messages");
                 pw.println("    v[erifiers]: print package verifier info");
                 pw.println("    <package.name>: info about given package");
+                pw.println("    k[eysets]: print known keysets");
                 return;
             } else if ("-f".equals(opt)) {
                 dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
@@ -10012,6 +10312,9 @@
             // Is this a package name?
             if ("android".equals(cmd) || cmd.contains(".")) {
                 packageName = cmd;
+                // When dumping a single package, we always dump all of its
+                // filter information since the amount of data will be reasonable.
+                dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
             } else if ("l".equals(cmd) || "libraries".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_LIBS);
             } else if ("f".equals(cmd) || "features".equals(cmd)) {
@@ -10038,6 +10341,8 @@
                 dumpState.setDump(DumpState.DUMP_MESSAGES);
             } else if ("v".equals(cmd) || "verifiers".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_VERIFIERS);
+            } else if ("k".equals(cmd) || "keysets".equals(cmd)) {
+                dumpState.setDump(DumpState.DUMP_KEYSETS);
             }
         }
 
@@ -10045,7 +10350,7 @@
         synchronized (mPackages) {
             if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
                 if (dumpState.onTitlePrinted())
-                    pw.println(" ");
+                    pw.println();
                 pw.println("Verifiers:");
                 pw.print("  Required: ");
                 pw.print(mRequiredVerifierPackage);
@@ -10055,16 +10360,20 @@
             }
 
             if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
-                if (dumpState.onTitlePrinted())
-                    pw.println(" ");
-                pw.println("Libraries:");
+                boolean printedHeader = false;
                 final Iterator<String> it = mSharedLibraries.keySet().iterator();
                 while (it.hasNext()) {
                     String name = it.next();
+                    SharedLibraryEntry ent = mSharedLibraries.get(name);
+                    if (!printedHeader) {
+                        if (dumpState.onTitlePrinted())
+                            pw.println();
+                        pw.println("Libraries:");
+                        printedHeader = true;
+                    }
                     pw.print("  ");
                     pw.print(name);
                     pw.print(" -> ");
-                    SharedLibraryEntry ent = mSharedLibraries.get(name);
                     if (ent.path != null) {
                         pw.print("(jar) ");
                         pw.print(ent.path);
@@ -10078,7 +10387,7 @@
 
             if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
                 if (dumpState.onTitlePrinted())
-                    pw.println(" ");
+                    pw.println();
                 pw.println("Features:");
                 Iterator<String> it = mAvailableFeatures.keySet().iterator();
                 while (it.hasNext()) {
@@ -10114,7 +10423,7 @@
                             dumpState.getTitlePrinted()
                                 ? "\nPreferred Activities User " + user + ":"
                                 : "Preferred Activities User " + user + ":", "  ",
-                            packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+                            packageName, true)) {
                         dumpState.setTitlePrinted(true);
                     }
                 }
@@ -10154,11 +10463,11 @@
                     }
                     if (!printedSomething) {
                         if (dumpState.onTitlePrinted())
-                            pw.println(" ");
+                            pw.println();
                         pw.println("Registered ContentProviders:");
                         printedSomething = true;
                     }
-                    pw.print("  "); pw.print(p.getComponentShortName()); pw.println(":");
+                    pw.print("  "); p.printComponentShortName(pw); pw.println(":");
                     pw.print("    "); pw.println(p.toString());
                 }
                 printedSomething = false;
@@ -10169,7 +10478,7 @@
                     }
                     if (!printedSomething) {
                         if (dumpState.onTitlePrinted())
-                            pw.println(" ");
+                            pw.println();
                         pw.println("ContentProvider Authorities:");
                         printedSomething = true;
                     }
@@ -10181,7 +10490,11 @@
                     }
                 }
             }
-            
+
+            if (dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+                mSettings.mKeySetManager.dump(pw, packageName, dumpState);
+            }
+
             if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
                 mSettings.dumpPackagesLPr(pw, packageName, dumpState);
             }
@@ -10192,10 +10505,10 @@
 
             if (dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
                 if (dumpState.onTitlePrinted())
-                    pw.println(" ");
+                    pw.println();
                 mSettings.dumpReadMessagesLPr(pw, dumpState);
 
-                pw.println(" ");
+                pw.println();
                 pw.println("Package warning messages:");
                 final File fname = getSettingsProblemFile();
                 FileInputStream in = null;
@@ -10928,42 +11241,9 @@
     }
 
     @Override
+    @Deprecated
     public boolean isPermissionEnforced(String permission) {
-        final boolean enforcedDefault = isPermissionEnforcedDefault(permission);
-        synchronized (mPackages) {
-            return isPermissionEnforcedLocked(permission, enforcedDefault);
-        }
-    }
-
-    /**
-     * Check if given permission should be enforced by default. Should always be
-     * called outside of {@link #mPackages} lock.
-     */
-    private boolean isPermissionEnforcedDefault(String permission) {
-        if (READ_EXTERNAL_STORAGE.equals(permission)) {
-            return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                    android.provider.Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT, 0)
-                    != 0;
-        } else {
-            return true;
-        }
-    }
-
-    /**
-     * Check if user has requested that given permission be enforced, using
-     * given default if undefined.
-     */
-    private boolean isPermissionEnforcedLocked(String permission, boolean enforcedDefault) {
-        if (READ_EXTERNAL_STORAGE.equals(permission)) {
-            if (mSettings.mReadExternalStorageEnforced != null) {
-                return mSettings.mReadExternalStorageEnforced;
-            } else {
-                // User hasn't defined; fall back to secure default
-                return enforcedDefault;
-            }
-        } else {
-            return true;
-        }
+        return true;
     }
 
     public boolean isStorageLow() {
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java
index f7f0870..b6f9f5b 100644
--- a/services/java/com/android/server/pm/PackageSetting.java
+++ b/services/java/com/android/server/pm/PackageSetting.java
@@ -52,4 +52,8 @@
             + Integer.toHexString(System.identityHashCode(this))
             + " " + name + "/" + appId + "}";
     }
-}
\ No newline at end of file
+
+    public int[] getGids() {
+        return sharedUser != null ? sharedUser.gids : gids;
+    }
+}
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index e64ec6d..7747c8f 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -65,6 +65,8 @@
     boolean permissionsFixed;
     boolean haveGids;
 
+    PackageKeySetData keySetData = new PackageKeySetData();
+
     private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
 
     // Whether this package is currently stopped, thus can not be
@@ -120,6 +122,9 @@
         origPackage = base.origPackage;
 
         installerPackageName = base.installerPackageName;
+
+        keySetData = new PackageKeySetData(base.keySetData);
+
     }
 
     void init(File codePath, File resourcePath, String nativeLibraryPathString,
@@ -170,6 +175,7 @@
             userState.put(base.userState.keyAt(i), base.userState.valueAt(i));
         }
         installStatus = base.installStatus;
+        keySetData = base.keySetData;
     }
 
     private PackageUserState modifyUserState(int userId) {
@@ -254,14 +260,24 @@
         modifyUserState(userId).notLaunched = stop;
     }
 
+    boolean getBlocked(int userId) {
+        return readUserState(userId).blocked;
+    }
+
+    void setBlocked(boolean blocked, int userId) {
+        modifyUserState(userId).blocked = blocked;
+    }
+
     void setUserState(int userId, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, String lastDisableAppCaller, HashSet<String> enabledComponents,
+            boolean notLaunched, boolean blocked,
+            String lastDisableAppCaller, HashSet<String> enabledComponents,
             HashSet<String> disabledComponents) {
         PackageUserState state = modifyUserState(userId);
         state.enabled = enabled;
         state.installed = installed;
         state.stopped = stopped;
         state.notLaunched = notLaunched;
+        state.blocked = blocked;
         state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index c655bb1..f93ba2f 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -33,13 +33,13 @@
     private static final String TAG = "PreferredActivity";
 
     private static final boolean DEBUG_FILTERS = false;
-    static final String ATTR_USER_ID = "userId";
 
     final PreferredComponent mPref;
 
-    PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
+    PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,
+            boolean always) {
         super(filter);
-        mPref = new PreferredComponent(this, match, set, activity);
+        mPref = new PreferredComponent(this, match, set, activity, always);
     }
 
     PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -71,4 +71,10 @@
         }
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "PreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
+                + " " + mPref.mComponent.flattenToShortString() + "}";
+    }
 }
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/java/com/android/server/pm/PreferredIntentResolver.java
index 7fe6a05..bce24d7 100644
--- a/services/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/java/com/android/server/pm/PreferredIntentResolver.java
@@ -26,10 +26,12 @@
     protected PreferredActivity[] newArray(int size) {
         return new PreferredActivity[size];
     }
+
     @Override
     protected boolean isPackageForFilter(String packageName, PreferredActivity filter) {
         return packageName.equals(filter.mPref.mComponent.getPackageName());
     }
+
     @Override
     protected void dumpFilter(PrintWriter out, String prefix,
             PreferredActivity filter) {
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b0679f2..7d0b31e 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -22,6 +22,8 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.PACKAGE_INFO_GID;
 
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
@@ -43,6 +45,7 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
+import android.content.pm.KeySet;
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -57,6 +60,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -67,6 +71,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.security.PublicKey;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -106,6 +111,7 @@
     private static final String ATTR_ENABLED = "enabled";
     private static final String ATTR_ENABLED_CALLER = "enabledCaller";
     private static final String ATTR_STOPPED = "stopped";
+    private static final String ATTR_BLOCKED = "blocked";
     private static final String ATTR_INSTALLED = "inst";
 
     private final File mSettingsFilename;
@@ -113,12 +119,15 @@
     private final File mPackageListFilename;
     private final File mStoppedPackagesFilename;
     private final File mBackupStoppedPackagesFilename;
+
     final HashMap<String, PackageSetting> mPackages =
             new HashMap<String, PackageSetting>();
     // List of replaced system applications
     private final HashMap<String, PackageSetting> mDisabledSysPackages =
         new HashMap<String, PackageSetting>();
 
+    private static int mFirstAvailableUid = 0;
+
     // These are the last platform API version we were using for
     // the apps installed on internal and external storage.  It is
     // used to grant newer permissions one time during a system upgrade.
@@ -177,6 +186,9 @@
     private final Context mContext;
 
     private final File mSystemDir;
+
+    public final KeySetManager mKeySetManager = new KeySetManager(mPackages);
+
     Settings(Context context) {
         this(context, Environment.getDataDirectory());
     }
@@ -192,6 +204,8 @@
         mSettingsFilename = new File(mSystemDir, "packages.xml");
         mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
         mPackageListFilename = new File(mSystemDir, "packages.list");
+        FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+
         // Deprecated: Needed for migration
         mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
         mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
@@ -337,6 +351,19 @@
         return null;
     }
 
+    void pruneSharedUsersLPw() {
+        ArrayList<String> removeStage = new ArrayList<String>();
+        for (Map.Entry<String,SharedUserSetting> entry : mSharedUsers.entrySet()) {
+            final SharedUserSetting sus = entry.getValue();
+            if (sus == null || sus.packages.size() == 0) {
+                removeStage.add(entry.getKey());
+            }
+        }
+        for (int i = 0; i < removeStage.size(); i++) {
+            mSharedUsers.remove(removeStage.get(i));
+        }
+    }
+
     // Transfer ownership of permissions from one package to another.
     void transferPermissionsLPw(String origPkg, String newPkg) {
         // Transfer ownership of permissions to the new package.
@@ -454,6 +481,7 @@
                                     installed,
                                     true, // stopped,
                                     true, // notLaunched
+                                    false, // blocked
                                     null, null, null);
                             writePackageRestrictionsLPr(user.id);
                         }
@@ -584,7 +612,7 @@
                         "Package " + p.name + " was user "
                         + p.sharedUser + " but is now " + sharedUser
                         + "; I am not changing its files so it will probably fail!");
-                p.sharedUser.packages.remove(p);
+                p.sharedUser.removePackage(p);
             } else if (p.appId != sharedUser.userId) {
                 PackageManagerService.reportSettingsProblem(Log.ERROR,
                     "Package " + p.name + " was user id " + p.appId
@@ -593,7 +621,7 @@
                     + "; I am not changing its files so it will probably fail!");
             }
 
-            sharedUser.packages.add(p);
+            sharedUser.addPackage(p);
             p.sharedUser = sharedUser;
             p.appId = sharedUser.userId;
         }
@@ -653,7 +681,7 @@
         if (p != null) {
             mPackages.remove(name);
             if (p.sharedUser != null) {
-                p.sharedUser.packages.remove(p);
+                p.sharedUser.removePackage(p);
                 if (p.sharedUser.packages.size() == 0) {
                     mSharedUsers.remove(p.sharedUser.name);
                     removeUserIdLPw(p.sharedUser.userId);
@@ -671,8 +699,8 @@
         final PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.sharedUser != null) {
-                p.sharedUser.packages.remove(p);
-                p.sharedUser.packages.add(newp);
+                p.sharedUser.removePackage(p);
+                p.sharedUser.addPackage(newp);
             } else {
                 replaceUserIdLPw(p.appId, newp);
             }
@@ -729,6 +757,7 @@
         } else {
             mOtherUserIds.remove(uid);
         }
+        setFirstAvailableUid(uid+1);
     }
 
     private void replaceUserIdLPw(int uid, Object obj) {
@@ -851,6 +880,7 @@
                                 true,   // installed
                                 false,  // stopped
                                 false,  // notLaunched
+                                false,  // blocked
                                 null, null, null);
                     }
                     return;
@@ -904,6 +934,9 @@
                     final String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED);
                     final boolean stopped = stoppedStr == null
                             ? false : Boolean.parseBoolean(stoppedStr);
+                    final String blockedStr = parser.getAttributeValue(null, ATTR_BLOCKED);
+                    final boolean blocked = blockedStr == null
+                            ? false : Boolean.parseBoolean(blockedStr);
                     final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
                     final boolean notLaunched = stoppedStr == null
                             ? false : Boolean.parseBoolean(notLaunchedStr);
@@ -927,7 +960,7 @@
                         }
                     }
 
-                    ps.setUserState(userId, enabled, installed, stopped, notLaunched,
+                    ps.setUserState(userId, enabled, installed, stopped, notLaunched, blocked,
                             enabledCaller, enabledComponents, disabledComponents);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
@@ -1035,6 +1068,7 @@
                 PackageUserState ustate = pkg.readUserState(userId);
                 if (ustate.stopped || ustate.notLaunched || !ustate.installed
                         || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
+                        || ustate.blocked
                         || (ustate.enabledComponents != null
                                 && ustate.enabledComponents.size() > 0)
                         || (ustate.disabledComponents != null
@@ -1052,6 +1086,9 @@
                     if (ustate.notLaunched) {
                         serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
                     }
+                    if (ustate.blocked) {
+                        serializer.attribute(null, ATTR_BLOCKED, "true");
+                    }
                     if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
                         serializer.attribute(null, ATTR_ENABLED,
                                 Integer.toString(ustate.enabled));
@@ -1331,6 +1368,8 @@
                 }
             }
             
+            mKeySetManager.writeKeySetManagerLPr(serializer);
+
             serializer.endTag(null, "packages");
 
             serializer.endDocument();
@@ -1348,22 +1387,29 @@
                     -1, -1);
 
             // Write package list file now, use a JournaledFile.
-            //
-            File tempFile = new File(mPackageListFilename.toString() + ".tmp");
+            File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp");
             JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
 
-            fstr = new FileOutputStream(journal.chooseForWrite());
+            final File writeTarget = journal.chooseForWrite();
+            fstr = new FileOutputStream(writeTarget);
             str = new BufferedOutputStream(fstr);
             try {
+                FileUtils.setPermissions(fstr.getFD(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+
                 StringBuilder sb = new StringBuilder();
                 for (final PackageSetting pkg : mPackages.values()) {
-                    ApplicationInfo ai = pkg.pkg.applicationInfo;
-                    String dataPath = ai.dataDir;
-                    boolean isDebug  = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    if (pkg.pkg == null || pkg.pkg.applicationInfo == null) {
+                        Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+                        continue;
+                    }
 
-                    // Avoid any application that has a space in its path
-                    // or that is handled by the system.
-                    if (dataPath.indexOf(" ") >= 0 || ai.uid < Process.FIRST_APPLICATION_UID)
+                    final ApplicationInfo ai = pkg.pkg.applicationInfo;
+                    final String dataPath = ai.dataDir;
+                    final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    final int[] gids = pkg.getGids();
+
+                    // Avoid any application that has a space in its path.
+                    if (dataPath.indexOf(" ") >= 0)
                         continue;
 
                     // we store on each line the following information for now:
@@ -1373,12 +1419,14 @@
                     // debugFlag  - 0 or 1 if the package is debuggable.
                     // dataPath   - path to package's data path
                     // seinfo     - seinfo label for the app (assigned at install time)
+                    // gids       - supplementary gids this app launches with
                     //
                     // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                     //
                     // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
                     // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
                     //   system/core/run-as/run-as.c
+                    //   system/core/sdcard/sdcard.c
                     //
                     sb.setLength(0);
                     sb.append(ai.packageName);
@@ -1388,6 +1436,16 @@
                     sb.append(dataPath);
                     sb.append(" ");
                     sb.append(ai.seinfo);
+                    sb.append(" ");
+                    if (gids != null && gids.length > 0) {
+                        sb.append(gids[0]);
+                        for (int i = 1; i < gids.length; i++) {
+                            sb.append(",");
+                            sb.append(gids[i]);
+                        }
+                    } else {
+                        sb.append("none");
+                    }
                     sb.append("\n");
                     str.write(sb.toString().getBytes());
                 }
@@ -1396,15 +1454,11 @@
                 str.close();
                 journal.commit();
             } catch (Exception e) {
+                Log.wtf(TAG, "Failed to write packages.list", e);
                 IoUtils.closeQuietly(str);
                 journal.rollback();
             }
 
-            FileUtils.setPermissions(mPackageListFilename.toString(),
-                    FileUtils.S_IRUSR|FileUtils.S_IWUSR
-                    |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-                    -1, -1);
-
             writeAllUsersPackageRestrictionsLPr();
             return;
 
@@ -1521,9 +1575,31 @@
             serializer.endTag(null, "perms");
         }
 
+        writeSigningKeySetsLPr(serializer, pkg.keySetData);
+        writeKeySetAliasesLPr(serializer, pkg.keySetData);
+
         serializer.endTag(null, "package");
     }
 
+    void writeSigningKeySetsLPr(XmlSerializer serializer,
+            PackageKeySetData data) throws IOException {
+        for (long id : data.getSigningKeySets()) {
+            serializer.startTag(null, "signing-keyset");
+            serializer.attribute(null, "identifier", Long.toString(id));
+            serializer.endTag(null, "signing-keyset");
+        }
+    }
+
+    void writeKeySetAliasesLPr(XmlSerializer serializer,
+            PackageKeySetData data) throws IOException {
+        for (Map.Entry<String, Long> e: data.getAliases().entrySet()) {
+            serializer.startTag(null, "defined-keyset");
+            serializer.attribute(null, "alias", e.getKey());
+            serializer.attribute(null, "identifier", Long.toString(e.getValue()));
+            serializer.endTag(null, "defined-keyset");
+        }
+    }
+
     void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
             throws XmlPullParserException, java.io.IOException {
         if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) {
@@ -1698,6 +1774,8 @@
                 } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
                     final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
                     mReadExternalStorageEnforced = "1".equals(enforcement);
+                } else if (tagName.equals("keyset-settings")) {
+                    mKeySetManager.readKeySetsLPw(parser);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
                             + parser.getName());
@@ -1785,6 +1863,20 @@
     }
 
     void readDefaultPreferredAppsLPw(PackageManagerService service, int userId) {
+        // First pull data from any pre-installed apps.
+        for (PackageSetting ps : mPackages.values()) {
+            if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
+                    && ps.pkg.preferredActivityFilters != null) {
+                ArrayList<PackageParser.ActivityIntentInfo> intents
+                        = ps.pkg.preferredActivityFilters;
+                for (int i=0; i<intents.size(); i++) {
+                    PackageParser.ActivityIntentInfo aii = intents.get(i);
+                    applyDefaultPreferredActivityLPw(service, aii, new ComponentName(
+                            ps.name, aii.activity.className), userId);
+                }
+            }
+        }
+
         // Read preferred apps from .../etc/preferred-apps directory.
         File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
         if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -1844,6 +1936,166 @@
         }
     }
 
+    private void applyDefaultPreferredActivityLPw(PackageManagerService service,
+            IntentFilter tmpPa, ComponentName cn, int userId) {
+        // The initial preferences only specify the target activity
+        // component and intent-filter, not the set of matches.  So we
+        // now need to query for the matches to build the correct
+        // preferred activity entry.
+        if (PackageManagerService.DEBUG_PREFERRED) {
+            Log.d(TAG, "Processing preferred:");
+            tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
+        }
+        Intent intent = new Intent();
+        int flags = 0;
+        intent.setAction(tmpPa.getAction(0));
+        for (int i=0; i<tmpPa.countCategories(); i++) {
+            String cat = tmpPa.getCategory(i);
+            if (cat.equals(Intent.CATEGORY_DEFAULT)) {
+                flags |= PackageManager.MATCH_DEFAULT_ONLY;
+            } else {
+                intent.addCategory(cat);
+            }
+        }
+
+        boolean doNonData = true;
+
+        for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) {
+            boolean doScheme = true;
+            String scheme = tmpPa.getDataScheme(ischeme);
+            for (int issp=0; issp<tmpPa.countDataSchemeSpecificParts(); issp++) {
+                Uri.Builder builder = new Uri.Builder();
+                builder.scheme(scheme);
+                PatternMatcher ssp = tmpPa.getDataSchemeSpecificPart(issp);
+                builder.opaquePart(ssp.getPath());
+                Intent finalIntent = new Intent(intent);
+                finalIntent.setData(builder.build());
+                applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                        scheme, ssp, null, null, null, userId);
+                doScheme = false;
+            }
+            for (int iauth=0; iauth<tmpPa.countDataAuthorities(); iauth++) {
+                boolean doAuth = true;
+                IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(iauth);
+                for (int ipath=0; ipath<tmpPa.countDataPaths(); ipath++) {
+                    Uri.Builder builder = new Uri.Builder();
+                    builder.scheme(scheme);
+                    if (auth.getHost() != null) {
+                        builder.authority(auth.getHost());
+                    }
+                    PatternMatcher path = tmpPa.getDataPath(ipath);
+                    builder.path(path.getPath());
+                    Intent finalIntent = new Intent(intent);
+                    finalIntent.setData(builder.build());
+                    applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                            scheme, null, auth, path, null, userId);
+                    doAuth = doScheme = false;
+                }
+                if (doAuth) {
+                    Uri.Builder builder = new Uri.Builder();
+                    builder.scheme(scheme);
+                    if (auth.getHost() != null) {
+                        builder.authority(auth.getHost());
+                    }
+                    Intent finalIntent = new Intent(intent);
+                    finalIntent.setData(builder.build());
+                    applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                            scheme, null, auth, null, null, userId);
+                    doScheme = false;
+                }
+            }
+            if (doScheme) {
+                Uri.Builder builder = new Uri.Builder();
+                builder.scheme(scheme);
+                Intent finalIntent = new Intent(intent);
+                finalIntent.setData(builder.build());
+                applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                        scheme, null, null, null, null, userId);
+            }
+            doNonData = false;
+        }
+
+        for (int idata=0; idata<tmpPa.countDataTypes(); idata++) {
+            Intent finalIntent = new Intent(intent);
+            String mimeType = tmpPa.getDataType(idata);
+            finalIntent.setType(mimeType);
+            applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                    null, null, null, null, mimeType, userId);
+            doNonData = false;
+        }
+
+        if (doNonData) {
+            applyDefaultPreferredActivityLPw(service, intent, flags, cn,
+                    null, null, null, null, null, userId);
+        }
+    }
+
+    private void applyDefaultPreferredActivityLPw(PackageManagerService service,
+            Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
+            IntentFilter.AuthorityEntry auth, PatternMatcher path, String mimeType,
+            int userId) {
+        List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
+                intent.getType(), flags, 0);
+        if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
+                + " results: " + ri);
+        int match = 0;
+        if (ri != null && ri.size() > 1) {
+            boolean haveAct = false;
+            boolean haveNonSys = false;
+            ComponentName[] set = new ComponentName[ri.size()];
+            for (int i=0; i<ri.size(); i++) {
+                ActivityInfo ai = ri.get(i).activityInfo;
+                set[i] = new ComponentName(ai.packageName, ai.name);
+                if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    // If any of the matches are not system apps, then
+                    // there is a third party app that is now an option...
+                    // so don't set a default since we don't want to hide it.
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                            + ai.packageName + "/" + ai.name + ": non-system!");
+                    haveNonSys = true;
+                    break;
+                } else if (cn.getPackageName().equals(ai.packageName)
+                        && cn.getClassName().equals(ai.name)) {
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                            + ai.packageName + "/" + ai.name + ": default!");
+                    haveAct = true;
+                    match = ri.get(i).match;
+                } else {
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                            + ai.packageName + "/" + ai.name + ": skipped");
+                }
+            }
+            if (haveAct && !haveNonSys) {
+                IntentFilter filter = new IntentFilter();
+                if (intent.getAction() != null) {
+                    filter.addAction(intent.getAction());
+                }
+                for (String cat : intent.getCategories()) {
+                    filter.addCategory(cat);
+                }
+                if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
+                    filter.addCategory(Intent.CATEGORY_DEFAULT);
+                }
+                if (scheme != null) {
+                    filter.addDataScheme(scheme);
+                }
+                if (ssp != null) {
+                    filter.addDataSchemeSpecificPart(ssp.getPath(), ssp.getType());
+                }
+                if (auth != null) {
+                    filter.addDataAuthority(auth);
+                }
+                if (path != null) {
+                    filter.addDataPath(path);
+                }
+                PreferredActivity pa = new PreferredActivity(filter, match, set, cn, true);
+                editPreferredActivitiesLPw(userId).addFilter(pa);
+            } else if (!haveNonSys) {
+                Slog.w(TAG, "No component found for default preferred activity " + cn);
+            }
+        }
+    }
+
     private void readDefaultPreferredActivitiesLPw(PackageManagerService service,
             XmlPullParser parser, int userId)
             throws XmlPullParserException, IOException {
@@ -1859,83 +2111,8 @@
             if (tagName.equals(TAG_ITEM)) {
                 PreferredActivity tmpPa = new PreferredActivity(parser);
                 if (tmpPa.mPref.getParseError() == null) {
-                    // The initial preferences only specify the target activity
-                    // component and intent-filter, not the set of matches.  So we
-                    // now need to query for the matches to build the correct
-                    // preferred activity entry.
-                    if (PackageManagerService.DEBUG_PREFERRED) {
-                        Log.d(TAG, "Processing preferred:");
-                        tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
-                    }
-                    final ComponentName cn = tmpPa.mPref.mComponent;
-                    Intent intent = new Intent();
-                    int flags = 0;
-                    intent.setAction(tmpPa.getAction(0));
-                    for (int i=0; i<tmpPa.countCategories(); i++) {
-                        String cat = tmpPa.getCategory(i);
-                        if (cat.equals(Intent.CATEGORY_DEFAULT)) {
-                            flags |= PackageManager.MATCH_DEFAULT_ONLY;
-                        } else {
-                            intent.addCategory(cat);
-                        }
-                    }
-                    if (tmpPa.countDataSchemes() > 0) {
-                        Uri.Builder builder = new Uri.Builder();
-                        builder.scheme(tmpPa.getDataScheme(0));
-                        if (tmpPa.countDataAuthorities() > 0) {
-                            IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(0);
-                            if (auth.getHost() != null) {
-                                builder.authority(auth.getHost());
-                            }
-                        }
-                        if (tmpPa.countDataPaths() > 0) {
-                            PatternMatcher path = tmpPa.getDataPath(0);
-                            builder.path(path.getPath());
-                        }
-                        intent.setData(builder.build());
-                    } else if (tmpPa.countDataTypes() > 0) {
-                        intent.setType(tmpPa.getDataType(0));
-                    }
-                    List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
-                            intent.getType(), flags, 0);
-                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
-                            + " results: " + ri);
-                    int match = 0;
-                    if (ri != null && ri.size() > 1) {
-                        boolean haveAct = false;
-                        boolean haveNonSys = false;
-                        ComponentName[] set = new ComponentName[ri.size()];
-                        for (int i=0; i<ri.size(); i++) {
-                            ActivityInfo ai = ri.get(i).activityInfo;
-                            set[i] = new ComponentName(ai.packageName, ai.name);
-                            if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
-                                // If any of the matches are not system apps, then
-                                // there is a third party app that is now an option...
-                                // so don't set a default since we don't want to hide it.
-                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
-                                        + ai.packageName + "/" + ai.name + ": non-system!");
-                                haveNonSys = true;
-                                break;
-                            } else if (cn.getPackageName().equals(ai.packageName)
-                                    && cn.getClassName().equals(ai.name)) {
-                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
-                                        + ai.packageName + "/" + ai.name + ": default!");
-                                haveAct = true;
-                                match = ri.get(i).match;
-                            } else {
-                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
-                                        + ai.packageName + "/" + ai.name + ": skipped");
-                            }
-                        }
-                        if (haveAct && !haveNonSys) {
-                            PreferredActivity pa = new PreferredActivity(tmpPa, match, set,
-                                    tmpPa.mPref.mComponent);
-                            editPreferredActivitiesLPw(userId).addFilter(pa);
-                        } else if (!haveNonSys) {
-                            Slog.w(TAG, "No component found for default preferred activity "
-                                    + tmpPa.mPref.mComponent);
-                        }
-                    }
+                    applyDefaultPreferredActivityLPw(service, tmpPa, tmpPa.mPref.mComponent,
+                            userId);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Error in package manager settings: <preferred-activity> "
@@ -2293,12 +2470,22 @@
                 } else if (tagName.equals("perms")) {
                     readGrantedPermissionsLPw(parser, packageSetting.grantedPermissions);
                     packageSetting.permissionsFixed = true;
+                } else if (tagName.equals("signing-keyset")) {
+                    long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+                    packageSetting.keySetData.addSigningKeySet(id);
+                    Slog.d(TAG, "Adding signing keyset " + Long.toString(id) + " to " + name);
+                } else if (tagName.equals("defined-keyset")) {
+                    long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+                    String alias = parser.getAttributeValue(null, "alias");
+                    packageSetting.keySetData.addDefinedKeySet(id, alias);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unknown element under <package>: " + parser.getName());
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
+
+
         } else {
             XmlUtils.skipCurrentTag(parser);
         }
@@ -2478,11 +2665,18 @@
         file.delete();
     }
 
+    // This should be called (at least) whenever an application is removed
+    private void setFirstAvailableUid(int uid) {
+        if (uid > mFirstAvailableUid) {
+            mFirstAvailableUid = uid;
+        }
+    }
+
     // Returns -1 if we could not find an available UserId to assign
     private int newUserIdLPw(Object obj) {
         // Let's be stupidly inefficient for now...
         final int N = mUserIds.size();
-        for (int i = 0; i < N; i++) {
+        for (int i = mFirstAvailableUid; i < N; i++) {
             if (mUserIds.get(i) == null) {
                 mUserIds.set(i, obj);
                 return Process.FIRST_APPLICATION_UID + i;
@@ -2660,6 +2854,7 @@
         ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
         ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
         ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+        ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
         ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
         ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
     };
@@ -2791,6 +2986,8 @@
             pw.print(prefix); pw.print("  User "); pw.print(user.id); pw.print(": ");
             pw.print(" installed=");
             pw.print(ps.getInstalled(user.id));
+            pw.print(" blocked=");
+            pw.print(ps.getBlocked(user.id));
             pw.print(" stopped=");
             pw.print(ps.getStopped(user.id));
             pw.print(" notLaunched=");
@@ -2842,7 +3039,7 @@
 
             if (!printedSomething) {
                 if (dumpState.onTitlePrinted())
-                    pw.println(" ");
+                    pw.println();
                 pw.println("Packages:");
                 printedSomething = true;
             }
@@ -2858,7 +3055,7 @@
                 }
                 if (!printedSomething) {
                     if (dumpState.onTitlePrinted())
-                        pw.println(" ");
+                        pw.println();
                     pw.println("Renamed packages:");
                     printedSomething = true;
                 }
@@ -2878,7 +3075,7 @@
                 }
                 if (!printedSomething) {
                     if (dumpState.onTitlePrinted())
-                        pw.println(" ");
+                        pw.println();
                     pw.println("Hidden system packages:");
                     printedSomething = true;
                 }
@@ -2895,7 +3092,7 @@
             }
             if (!printedSomething) {
                 if (dumpState.onTitlePrinted())
-                    pw.println(" ");
+                    pw.println();
                 pw.println("Permissions:");
                 printedSomething = true;
             }
@@ -2929,7 +3126,7 @@
             }
             if (!printedSomething) {
                 if (dumpState.onTitlePrinted())
-                    pw.println(" ");
+                    pw.println();
                 pw.println("Shared users:");
                 printedSomething = true;
             }
diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/java/com/android/server/pm/SharedUserSetting.java
index 76826ea..ca1eeea 100644
--- a/services/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/java/com/android/server/pm/SharedUserSetting.java
@@ -26,12 +26,16 @@
 
     int userId;
 
+    // flags that are associated with this uid, regardless of any package flags
+    int uidFlags;
+
     final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
 
     final PackageSignatures signatures = new PackageSignatures();
 
     SharedUserSetting(String _name, int _pkgFlags) {
         super(_pkgFlags);
+        uidFlags =  _pkgFlags;
         name = _name;
     }
 
@@ -40,4 +44,23 @@
         return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
                 + name + "/" + userId + "}";
     }
+
+    void removePackage(PackageSetting packageSetting) {
+        if (packages.remove(packageSetting)) {
+            // recalculate the pkgFlags for this shared user if needed
+            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
+                int aggregatedFlags = uidFlags;
+                for (PackageSetting ps : packages) {
+                    aggregatedFlags |= ps.pkgFlags;
+                }
+                setFlags(aggregatedFlags);
+            }
+        }
+    }
+
+    void addPackage(PackageSetting packageSetting) {
+        if (packages.add(packageSetting)) {
+            setFlags(this.pkgFlags | packageSetting.pkgFlags);
+        }
+    }
 }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 1323c93..c33134a 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -21,11 +21,12 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.IStopUserCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.RestrictionEntry;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
@@ -42,12 +43,14 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AtomicFile;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
@@ -63,6 +66,9 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -78,6 +84,10 @@
     private static final String ATTR_ID = "id";
     private static final String ATTR_CREATION_TIME = "created";
     private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
+    private static final String ATTR_SALT = "salt";
+    private static final String ATTR_PIN_HASH = "pinHash";
+    private static final String ATTR_FAILED_ATTEMPTS = "failedAttempts";
+    private static final String ATTR_LAST_RETRY_MS = "lastAttemptMs";
     private static final String ATTR_SERIAL_NO = "serialNumber";
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
@@ -100,13 +110,21 @@
     private static final String USER_PHOTO_FILENAME = "photo.png";
 
     private static final String RESTRICTIONS_FILE_PREFIX = "res_";
+    private static final String XML_SUFFIX = ".xml";
 
     private static final int MIN_USER_ID = 10;
 
-    private static final int USER_VERSION = 2;
+    private static final int USER_VERSION = 4;
 
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
+    // Number of attempts before jumping to the next BACKOFF_TIMES slot
+    private static final int BACKOFF_INC_INTERVAL = 5;
+
+    // Amount of time to force the user to wait before entering the PIN again, after failing
+    // BACKOFF_INC_INTERVAL times.
+    private static final int[] BACKOFF_TIMES = { 0, 30*1000, 60*1000, 5*60*1000, 30*60*1000 };
+
     private final Context mContext;
     private final PackageManagerService mPm;
     private final Object mInstallLock;
@@ -121,6 +139,16 @@
     private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
     private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>();
 
+    class RestrictionsPinState {
+        long salt;
+        String pinHash;
+        int failedAttempts;
+        long lastAttemptTime;
+    }
+
+    private final SparseArray<RestrictionsPinState> mRestrictionsPinStates =
+            new SparseArray<RestrictionsPinState>();
+
     /**
      * Set of user IDs being actively removed. Removed IDs linger in this set
      * for several seconds to work around a VFS caching issue.
@@ -204,6 +232,13 @@
         }
     }
 
+    void systemReady() {
+        final Context context = ActivityThread.systemMain().getSystemContext();
+        mUserPackageMonitor.register(context,
+                null, UserHandle.ALL, false);
+        userForeground(UserHandle.USER_OWNER);
+    }
+
     @Override
     public List<UserInfo> getUsers(boolean excludeDying) {
         checkManageUsersPermission("query users");
@@ -379,8 +414,10 @@
     @Override
     public void setUserRestrictions(Bundle restrictions, int userId) {
         checkManageUsersPermission("setUserRestrictions");
+        if (restrictions == null) return;
 
         synchronized (mPackagesLock) {
+            mUserRestrictions.get(userId).clear();
             mUserRestrictions.get(userId).putAll(restrictions);
             writeUserLocked(mUsers.get(userId));
         }
@@ -452,12 +489,6 @@
         return mUserIds;
     }
 
-    private void readUserList() {
-        synchronized (mPackagesLock) {
-            readUserListLocked();
-        }
-    }
-
     private void readUserListLocked() {
         mGuestEnabled = false;
         if (!mUserListFile.exists()) {
@@ -511,7 +542,7 @@
                 }
             }
             updateUserIdsLocked();
-            upgradeIfNecessary();
+            upgradeIfNecessaryLocked();
         } catch (IOException ioe) {
             fallbackToSingleUserLocked();
         } catch (XmlPullParserException pe) {
@@ -529,7 +560,7 @@
     /**
      * Upgrade steps between versions, either for fixing bugs or changing the data format.
      */
-    private void upgradeIfNecessary() {
+    private void upgradeIfNecessaryLocked() {
         int userVersion = mUserVersion;
         if (userVersion < 1) {
             // Assign a proper name for the owner, if not initialized correctly before
@@ -551,6 +582,11 @@
             userVersion = 2;
         }
 
+
+        if (userVersion < 4) {
+            userVersion = 4;
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);
@@ -567,6 +603,7 @@
                 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
         mUsers.put(0, primary);
         mNextSerialNumber = MIN_USER_ID;
+        mUserVersion = USER_VERSION;
 
         Bundle restrictions = new Bundle();
         mUserRestrictions.append(UserHandle.USER_OWNER, restrictions);
@@ -586,7 +623,7 @@
      */
     private void writeUserLocked(UserInfo userInfo) {
         FileOutputStream fos = null;
-        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + ".xml"));
+        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + XML_SUFFIX));
         try {
             fos = userFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
@@ -604,6 +641,21 @@
             serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
             serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
                     Long.toString(userInfo.lastLoggedInTime));
+            RestrictionsPinState pinState = mRestrictionsPinStates.get(userInfo.id);
+            if (pinState != null) {
+                if (pinState.salt != 0) {
+                    serializer.attribute(null, ATTR_SALT, Long.toString(pinState.salt));
+                }
+                if (pinState.pinHash != null) {
+                    serializer.attribute(null, ATTR_PIN_HASH, pinState.pinHash);
+                }
+                if (pinState.failedAttempts != 0) {
+                    serializer.attribute(null, ATTR_FAILED_ATTEMPTS,
+                            Integer.toString(pinState.failedAttempts));
+                    serializer.attribute(null, ATTR_LAST_RETRY_MS,
+                            Long.toString(pinState.lastAttemptTime));
+                }
+            }
             if (userInfo.iconPath != null) {
                 serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
             }
@@ -690,13 +742,17 @@
         String iconPath = null;
         long creationTime = 0L;
         long lastLoggedInTime = 0L;
+        long salt = 0L;
+        String pinHash = null;
+        int failedAttempts = 0;
+        long lastAttemptTime = 0L;
         boolean partial = false;
         Bundle restrictions = new Bundle();
 
         FileInputStream fis = null;
         try {
             AtomicFile userFile =
-                    new AtomicFile(new File(mUsersDir, Integer.toString(id) + ".xml"));
+                    new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX));
             fis = userFile.openRead();
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
@@ -722,6 +778,10 @@
                 iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
                 creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
                 lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
+                salt = readLongAttribute(parser, ATTR_SALT, 0L);
+                pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH);
+                failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0);
+                lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L);
                 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
                 if ("true".equals(valueString)) {
                     partial = true;
@@ -761,6 +821,17 @@
             userInfo.lastLoggedInTime = lastLoggedInTime;
             userInfo.partial = partial;
             mUserRestrictions.append(id, restrictions);
+            if (salt != 0L) {
+                RestrictionsPinState pinState = mRestrictionsPinStates.get(id);
+                if (pinState == null) {
+                    pinState = new RestrictionsPinState();
+                    mRestrictionsPinStates.put(id, pinState);
+                }
+                pinState.salt = salt;
+                pinState.pinHash = pinHash;
+                pinState.failedAttempts = failedAttempts;
+                pinState.lastAttemptTime = lastAttemptTime;
+            }
             return userInfo;
 
         } catch (IOException ioe) {
@@ -812,6 +883,57 @@
         }
     }
 
+    private boolean isPackageInstalled(String pkg, int userId) {
+        final ApplicationInfo info = mPm.getApplicationInfo(pkg,
+                PackageManager.GET_UNINSTALLED_PACKAGES,
+                userId);
+        if (info == null || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Removes all the restrictions files (res_<packagename>) for a given user, if all is true,
+     * else removes only those packages that have been uninstalled.
+     * Does not do any permissions checking.
+     */
+    private void cleanAppRestrictions(int userId, boolean all) {
+        synchronized (mPackagesLock) {
+            File dir = Environment.getUserSystemDirectory(userId);
+            String[] files = dir.list();
+            if (files == null) return;
+            for (String fileName : files) {
+                if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) {
+                    File resFile = new File(dir, fileName);
+                    if (resFile.exists()) {
+                        if (all) {
+                            resFile.delete();
+                        } else {
+                            String pkg = restrictionsFileNameToPackage(fileName);
+                            if (!isPackageInstalled(pkg, userId)) {
+                                resFile.delete();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes the app restrictions file for a specific package and user id, if it exists.
+     */
+    private void cleanAppRestrictionsForPackage(String pkg, int userId) {
+        synchronized (mPackagesLock) {
+            File dir = Environment.getUserSystemDirectory(userId);
+            File resFile = new File(dir, packageToRestrictionsFileName(pkg));
+            if (resFile.exists()) {
+                resFile.delete();
+            }
+        }
+    }
+
     @Override
     public UserInfo createUser(String name, int flags) {
         checkManageUsersPermission("Only the system can create users");
@@ -949,8 +1071,9 @@
             }
         }, MINUTE_IN_MILLIS);
 
+        mRestrictionsPinStates.remove(userHandle);
         // Remove user file
-        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
+        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
         userFile.delete();
         // Update the user list
         writeUserListLocked();
@@ -999,6 +1122,171 @@
         }
     }
 
+    @Override
+    public boolean setRestrictionsChallenge(String newPin) {
+        checkManageUsersPermission("Only system can modify the restrictions pin");
+        int userId = UserHandle.getCallingUserId();
+        synchronized (mPackagesLock) {
+            RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
+            if (pinState == null) {
+                pinState = new RestrictionsPinState();
+            }
+            if (newPin == null) {
+                pinState.salt = 0;
+                pinState.pinHash = null;
+            } else {
+                try {
+                    pinState.salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
+                } catch (NoSuchAlgorithmException e) {
+                    pinState.salt = (long) (Math.random() * Long.MAX_VALUE);
+                }
+                pinState.pinHash = passwordToHash(newPin, pinState.salt);
+                pinState.failedAttempts = 0;
+            }
+            mRestrictionsPinStates.put(userId, pinState);
+            writeUserLocked(mUsers.get(userId));
+        }
+        return true;
+    }
+
+    @Override
+    public int checkRestrictionsChallenge(String pin) {
+        checkManageUsersPermission("Only system can verify the restrictions pin");
+        int userId = UserHandle.getCallingUserId();
+        synchronized (mPackagesLock) {
+            RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
+            // If there's no pin set, return error code
+            if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) {
+                return UserManager.PIN_VERIFICATION_FAILED_NOT_SET;
+            } else if (pin == null) {
+                // If just checking if user can be prompted, return remaining time
+                int waitTime = getRemainingTimeForPinAttempt(pinState);
+                Slog.d(LOG_TAG, "Remaining waittime peek=" + waitTime);
+                return waitTime;
+            } else {
+                int waitTime = getRemainingTimeForPinAttempt(pinState);
+                Slog.d(LOG_TAG, "Remaining waittime=" + waitTime);
+                if (waitTime > 0) {
+                    return waitTime;
+                }
+                if (passwordToHash(pin, pinState.salt).equals(pinState.pinHash)) {
+                    pinState.failedAttempts = 0;
+                    writeUserLocked(mUsers.get(userId));
+                    return UserManager.PIN_VERIFICATION_SUCCESS;
+                } else {
+                    pinState.failedAttempts++;
+                    pinState.lastAttemptTime = System.currentTimeMillis();
+                    writeUserLocked(mUsers.get(userId));
+                    return waitTime;
+                }
+            }
+        }
+    }
+
+    private int getRemainingTimeForPinAttempt(RestrictionsPinState pinState) {
+        int backoffIndex = Math.min(pinState.failedAttempts / BACKOFF_INC_INTERVAL,
+                BACKOFF_TIMES.length - 1);
+        int backoffTime = (pinState.failedAttempts % BACKOFF_INC_INTERVAL) == 0 ?
+                BACKOFF_TIMES[backoffIndex] : 0;
+        return (int) Math.max(backoffTime + pinState.lastAttemptTime - System.currentTimeMillis(),
+                0);
+    }
+
+    @Override
+    public boolean hasRestrictionsChallenge() {
+        int userId = UserHandle.getCallingUserId();
+        synchronized (mPackagesLock) {
+            return hasRestrictionsPinLocked(userId);
+        }
+    }
+
+    private boolean hasRestrictionsPinLocked(int userId) {
+        RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
+        if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void removeRestrictions() {
+        checkManageUsersPermission("Only system can remove restrictions");
+        final int userHandle = UserHandle.getCallingUserId();
+        removeRestrictionsForUser(userHandle, true);
+    }
+
+    private void removeRestrictionsForUser(final int userHandle, boolean unblockApps) {
+        synchronized (mPackagesLock) {
+            // Remove all user restrictions
+            setUserRestrictions(new Bundle(), userHandle);
+            // Remove restrictions pin
+            setRestrictionsChallenge(null);
+            // Remove any app restrictions
+            cleanAppRestrictions(userHandle, true);
+        }
+        if (unblockApps) {
+            unblockAllAppsForUser(userHandle);
+        }
+    }
+
+    private void unblockAllAppsForUser(final int userHandle) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                List<ApplicationInfo> apps =
+                        mPm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES,
+                                userHandle).getList();
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    for (ApplicationInfo appInfo : apps) {
+                        if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
+                                && (appInfo.flags & ApplicationInfo.FLAG_BLOCKED) != 0) {
+                            mPm.setApplicationBlockedSettingAsUser(appInfo.packageName, false,
+                                    userHandle);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        });
+    }
+
+    /*
+     * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
+     * Not the most secure, but it is at least a second level of protection. First level is that
+     * the file is in a location only readable by the system process.
+     * @param password the password.
+     * @param salt the randomly generated salt
+     * @return the hash of the pattern in a String.
+     */
+    private String passwordToHash(String password, long salt) {
+        if (password == null) {
+            return null;
+        }
+        String algo = null;
+        String hashed = salt + password;
+        try {
+            byte[] saltedPassword = (password + salt).getBytes();
+            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
+            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
+            hashed = toHex(sha1) + toHex(md5);
+        } catch (NoSuchAlgorithmException e) {
+            Log.w(LOG_TAG, "Failed to encode string because of missing algorithm: " + algo);
+        }
+        return hashed;
+    }
+
+    private static String toHex(byte[] ary) {
+        final String hex = "0123456789ABCDEF";
+        String ret = "";
+        for (int i = 0; i < ary.length; i++) {
+            ret += hex.charAt((ary[i] >> 4) & 0xf);
+            ret += hex.charAt(ary[i] & 0xf);
+        }
+        return ret;
+    }
+
     private int getUidForPackage(String packageName) {
         long ident = Binder.clearCallingIdentity();
         try {
@@ -1020,7 +1308,7 @@
         try {
             AtomicFile restrictionsFile =
                     new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
-                            RESTRICTIONS_FILE_PREFIX + packageName + ".xml"));
+                            packageToRestrictionsFileName(packageName)));
             fis = restrictionsFile.openRead();
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
@@ -1081,7 +1369,7 @@
         FileOutputStream fos = null;
         AtomicFile restrictionsFile = new AtomicFile(
                 new File(Environment.getUserSystemDirectory(userId),
-                        RESTRICTIONS_FILE_PREFIX + packageName + ".xml"));
+                        packageToRestrictionsFileName(packageName)));
         try {
             fos = restrictionsFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
@@ -1168,7 +1456,7 @@
     }
 
     /**
-     * Make a note of the last started time of a user.
+     * Make a note of the last started time of a user and do some cleanup.
      * @param userId the user that was just foregrounded
      */
     public void userForeground(int userId) {
@@ -1183,6 +1471,12 @@
                 user.lastLoggedInTime = now;
                 writeUserLocked(user);
             }
+            // If this is not a restricted profile and there is no restrictions pin, clean up
+            // all restrictions files that might have been left behind, else clean up just the
+            // ones with uninstalled packages
+            RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
+            final long salt = pinState == null ? 0 : pinState.salt;
+            cleanAppRestrictions(userId, (!user.isRestricted() && salt == 0));
         }
     }
 
@@ -1205,6 +1499,15 @@
         }
     }
 
+    private String packageToRestrictionsFileName(String packageName) {
+        return RESTRICTIONS_FILE_PREFIX + packageName + XML_SUFFIX;
+    }
+
+    private String restrictionsFileNameToPackage(String fileName) {
+        return fileName.substring(RESTRICTIONS_FILE_PREFIX.length(),
+                (int) (fileName.length() - XML_SUFFIX.length()));
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -1249,4 +1552,17 @@
             }
         }
     }
+
+    private PackageMonitor mUserPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageRemoved(String pkg, int uid) {
+            final int userId = this.getChangingUserId();
+            // Package could be disappearing because it is being blocked, so also check if
+            // it has been uninstalled.
+            final boolean uninstalled = isPackageDisappearing(pkg) == PACKAGE_PERMANENT_CHANGE;
+            if (uninstalled && userId >= 0 && !isPackageInstalled(pkg, userId)) {
+                cleanAppRestrictionsForPackage(pkg, userId);
+            }
+        }
+    };
 }
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index b5010f2..976a328 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -29,7 +29,6 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
-import android.hardware.SystemSensorManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -119,7 +118,7 @@
 
     // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
     private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
-    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
+    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
 
     // Trigger proximity if distance is less than 5 cm.
     private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -164,6 +163,10 @@
     // Notifier for sending asynchronous notifications.
     private final Notifier mNotifier;
 
+    // The display suspend blocker.
+    // Held while there are pending state change notifications.
+    private final SuspendBlocker mDisplaySuspendBlocker;
+
     // The display blanker.
     private final DisplayBlanker mDisplayBlanker;
 
@@ -271,7 +274,7 @@
 
     // The raw non-debounced proximity sensor state.
     private int mPendingProximity = PROXIMITY_UNKNOWN;
-    private long mPendingProximityDebounceTime;
+    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
 
     // True if the screen was turned off because of the proximity sensor.
     // When the screen turns on again, we report user activity to the power manager.
@@ -346,10 +349,11 @@
     public DisplayPowerController(Looper looper, Context context, Notifier notifier,
             LightsService lights, TwilightService twilight, SensorManager sensorManager,
             DisplayManagerService displayManager,
-            DisplayBlanker displayBlanker,
+            SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
             Callbacks callbacks, Handler callbackHandler) {
         mHandler = new DisplayControllerHandler(looper);
         mNotifier = notifier;
+        mDisplaySuspendBlocker = displaySuspendBlocker;
         mDisplayBlanker = displayBlanker;
         mCallbacks = callbacks;
         mCallbackHandler = callbackHandler;
@@ -601,7 +605,7 @@
                 if (!mScreenOffBecauseOfProximity
                         && mProximity == PROXIMITY_POSITIVE) {
                     mScreenOffBecauseOfProximity = true;
-                    sendOnProximityPositive();
+                    sendOnProximityPositiveWithWakelock();
                     setScreenOn(false);
                 }
             } else if (mWaitingForNegativeProximity
@@ -616,7 +620,7 @@
             if (mScreenOffBecauseOfProximity
                     && mProximity != PROXIMITY_POSITIVE) {
                 mScreenOffBecauseOfProximity = false;
-                sendOnProximityNegative();
+                sendOnProximityNegativeWithWakelock();
             }
         } else {
             mWaitingForNegativeProximity = false;
@@ -737,7 +741,7 @@
                     }
                 }
             }
-            sendOnStateChanged();
+            sendOnStateChangedWithWakelock();
         }
     }
 
@@ -810,49 +814,67 @@
     private void setProximitySensorEnabled(boolean enable) {
         if (enable) {
             if (!mProximitySensorEnabled) {
+                // Register the listener.
+                // Proximity sensor state already cleared initially.
                 mProximitySensorEnabled = true;
-                mPendingProximity = PROXIMITY_UNKNOWN;
                 mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
                         SensorManager.SENSOR_DELAY_NORMAL, mHandler);
             }
         } else {
             if (mProximitySensorEnabled) {
+                // Unregister the listener.
+                // Clear the proximity sensor state for next time.
                 mProximitySensorEnabled = false;
                 mProximity = PROXIMITY_UNKNOWN;
+                mPendingProximity = PROXIMITY_UNKNOWN;
                 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
                 mSensorManager.unregisterListener(mProximitySensorListener);
+                clearPendingProximityDebounceTime(); // release wake lock (must be last)
             }
         }
     }
 
     private void handleProximitySensorEvent(long time, boolean positive) {
-        if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
-            return; // no change
-        }
-        if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
-            return; // no change
-        }
+        if (mProximitySensorEnabled) {
+            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
+                return; // no change
+            }
+            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
+                return; // no change
+            }
 
-        // Only accept a proximity sensor reading if it remains
-        // stable for the entire debounce delay.
-        mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
-        if (positive) {
-            mPendingProximity = PROXIMITY_POSITIVE;
-            mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
-        } else {
-            mPendingProximity = PROXIMITY_NEGATIVE;
-            mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
+            // Only accept a proximity sensor reading if it remains
+            // stable for the entire debounce delay.  We hold a wake lock while
+            // debouncing the sensor.
+            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
+            if (positive) {
+                mPendingProximity = PROXIMITY_POSITIVE;
+                setPendingProximityDebounceTime(
+                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
+            } else {
+                mPendingProximity = PROXIMITY_NEGATIVE;
+                setPendingProximityDebounceTime(
+                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
+            }
+
+            // Debounce the new sensor reading.
+            debounceProximitySensor();
         }
-        debounceProximitySensor();
     }
 
     private void debounceProximitySensor() {
-        if (mPendingProximity != PROXIMITY_UNKNOWN) {
+        if (mProximitySensorEnabled
+                && mPendingProximity != PROXIMITY_UNKNOWN
+                && mPendingProximityDebounceTime >= 0) {
             final long now = SystemClock.uptimeMillis();
             if (mPendingProximityDebounceTime <= now) {
+                // Sensor reading accepted.  Apply the change then release the wake lock.
                 mProximity = mPendingProximity;
-                sendUpdatePowerState();
+                updatePowerState();
+                clearPendingProximityDebounceTime(); // release wake lock (must be last)
             } else {
+                // Need to wait a little longer.
+                // Debounce again later.  We continue holding a wake lock while waiting.
                 Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
                 msg.setAsynchronous(true);
                 mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
@@ -860,6 +882,20 @@
         }
     }
 
+    private void clearPendingProximityDebounceTime() {
+        if (mPendingProximityDebounceTime >= 0) {
+            mPendingProximityDebounceTime = -1;
+            mDisplaySuspendBlocker.release(); // release wake lock
+        }
+    }
+
+    private void setPendingProximityDebounceTime(long debounceTime) {
+        if (mPendingProximityDebounceTime < 0) {
+            mDisplaySuspendBlocker.acquire(); // acquire wake lock
+        }
+        mPendingProximityDebounceTime = debounceTime;
+    }
+
     private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
         if (enable) {
             if (!mLightSensorEnabled) {
@@ -1120,7 +1156,8 @@
         return x + (y - x) * alpha;
     }
 
-    private void sendOnStateChanged() {
+    private void sendOnStateChangedWithWakelock() {
+        mDisplaySuspendBlocker.acquire();
         mCallbackHandler.post(mOnStateChangedRunnable);
     }
 
@@ -1128,10 +1165,12 @@
         @Override
         public void run() {
             mCallbacks.onStateChanged();
+            mDisplaySuspendBlocker.release();
         }
     };
 
-    private void sendOnProximityPositive() {
+    private void sendOnProximityPositiveWithWakelock() {
+        mDisplaySuspendBlocker.acquire();
         mCallbackHandler.post(mOnProximityPositiveRunnable);
     }
 
@@ -1139,10 +1178,12 @@
         @Override
         public void run() {
             mCallbacks.onProximityPositive();
+            mDisplaySuspendBlocker.release();
         }
     };
 
-    private void sendOnProximityNegative() {
+    private void sendOnProximityNegativeWithWakelock() {
+        mDisplaySuspendBlocker.acquire();
         mCallbackHandler.post(mOnProximityNegativeRunnable);
     }
 
@@ -1150,6 +1191,7 @@
         @Override
         public void run() {
             mCallbacks.onProximityNegative();
+            mDisplaySuspendBlocker.release();
         }
     };
 
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 379e704..729bd16 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -35,6 +35,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -94,7 +95,7 @@
     // Texture names.  We only use one texture, which contains the screenshot.
     private final int[] mTexNames = new int[1];
     private boolean mTexNamesGenerated;
-    private float mTexMatrix[] = new float[16];
+    private final float mTexMatrix[] = new float[16];
 
     // Vertex and corresponding texture coordinates.
     // We have 4 2D vertices, so 8 elements.  The vertices form a quad.
@@ -319,10 +320,10 @@
 
     /**
      * Draws a frame where the electron beam has been stretched out into
-     * a thin white horizontal line that fades as it expands outwards.
+     * a thin white horizontal line that fades as it collapses inwards.
      *
-     * @param stretch The stretch factor.  0.0 is no stretch / no fade,
-     * 1.0 is maximum stretch / maximum fade.
+     * @param stretch The stretch factor.  0.0 is maximum stretch / no fade,
+     * 1.0 is collapsed / maximum fade.
      */
     private void drawHStretch(float stretch) {
         // compute interpolation scale factor
@@ -338,7 +339,7 @@
 
             // draw narrow fading white line
             setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
-            GLES10.glColor4f(1.0f - ag, 1.0f - ag, 1.0f - ag, 1.0f);
+            GLES10.glColor4f(1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f);
             GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
 
             // clean up
@@ -355,7 +356,7 @@
     }
 
     private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
-        final float w = dw + (dw * a);
+        final float w = 2 * dw * (1.0f - a);
         final float h = 1.0f;
         final float x = (dw - w) * 0.5f;
         final float y = (dh - h) * 0.5f;
@@ -515,7 +516,7 @@
                     mSurfaceControl = new SurfaceControl(mSurfaceSession,
                             "ElectronBeam", mDisplayWidth, mDisplayHeight,
                             PixelFormat.OPAQUE, flags);
-                } catch (SurfaceControl.OutOfResourcesException ex) {
+                } catch (OutOfResourcesException ex) {
                     Slog.e(TAG, "Unable to create surface.", ex);
                     return false;
                 }
@@ -525,7 +526,7 @@
             mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
             mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
-            
+
             mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
             mSurfaceLayout.onDisplayTransaction();
         } finally {
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index d99d523..264e2e9 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power;
 
+import android.app.AppOpsManager;
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.EventLogTags;
 
@@ -75,6 +77,7 @@
 
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
+    private final IAppOpsService mAppOps;
     private final SuspendBlocker mSuspendBlocker;
     private final ScreenOnBlocker mScreenOnBlocker;
     private final WindowManagerPolicy mPolicy;
@@ -104,10 +107,11 @@
     private boolean mScreenOnBlockerAcquired;
 
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
-            SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
+            IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
             WindowManagerPolicy policy) {
         mContext = context;
         mBatteryStats = batteryStats;
+        mAppOps = appOps;
         mSuspendBlocker = suspendBlocker;
         mScreenOnBlocker = screenOnBlocker;
         mPolicy = policy;
@@ -124,11 +128,12 @@
     /**
      * Called when a wake lock is acquired.
      */
-    public void onWakeLockAcquired(int flags, String tag, int ownerUid, int ownerPid,
-            WorkSource workSource) {
+    public void onWakeLockAcquired(int flags, String tag, String packageName,
+            int ownerUid, int ownerPid, WorkSource workSource) {
         if (DEBUG) {
             Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
-                    + "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+                    + "\", packageName=" + packageName
+                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
                     + ", workSource=" + workSource);
         }
 
@@ -138,6 +143,9 @@
                 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
             } else {
                 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
+                // XXX need to deal with disabled operations.
+                mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
+                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
             }
         } catch (RemoteException ex) {
             // Ignore
@@ -147,11 +155,12 @@
     /**
      * Called when a wake lock is released.
      */
-    public void onWakeLockReleased(int flags, String tag, int ownerUid, int ownerPid,
-            WorkSource workSource) {
+    public void onWakeLockReleased(int flags, String tag, String packageName,
+            int ownerUid, int ownerPid, WorkSource workSource) {
         if (DEBUG) {
             Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
-                    + "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+                    + "\", packageName=" + packageName
+                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
                     + ", workSource=" + workSource);
         }
 
@@ -161,6 +170,8 @@
                 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
             } else {
                 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
+                mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
+                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
             }
         } catch (RemoteException ex) {
             // Ignore
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 6f70712..2ccd21c 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.power;
 
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.BatteryService;
 import com.android.server.EventLogTags;
@@ -50,6 +51,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.SystemService;
 import android.os.UserHandle;
 import android.os.WorkSource;
@@ -61,7 +63,6 @@
 import android.view.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -171,6 +172,7 @@
     private BatteryService mBatteryService;
     private DisplayManagerService mDisplayManagerService;
     private IBatteryStats mBatteryStats;
+    private IAppOpsService mAppOps;
     private HandlerThread mHandlerThread;
     private PowerManagerHandler mHandler;
     private WindowManagerPolicy mPolicy;
@@ -284,6 +286,9 @@
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
 
+    // True if the device should suspend when the screen is off due to proximity.
+    private boolean mSuspendWhenScreenOffDueToProximityConfig;
+
     // True if dreams are supported on this device.
     private boolean mDreamsSupportedConfig;
 
@@ -364,8 +369,6 @@
     private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
 
     private native void nativeInit();
-    private static native void nativeShutdown();
-    private static native void nativeReboot(String reason) throws IOException;
 
     private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
     private static native void nativeAcquireSuspendBlocker(String name);
@@ -395,17 +398,19 @@
      */
     public void init(Context context, LightsService ls,
             ActivityManagerService am, BatteryService bs, IBatteryStats bss,
-            DisplayManagerService dm) {
+            IAppOpsService appOps, DisplayManagerService dm) {
         mContext = context;
         mLightsService = ls;
         mBatteryService = bs;
         mBatteryStats = bss;
+        mAppOps = appOps;
         mDisplayManagerService = dm;
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
         mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
 
         Watchdog.getInstance().addMonitor(this);
+        Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());
 
         // Forcibly turn the screen on at boot so that it is in a known power state.
         // We do this in init() rather than in the constructor because setting the
@@ -437,18 +442,19 @@
             // The notifier runs on the system server's main looper so as not to interfere
             // with the animations and other critical functions of the power manager.
             mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
-                    createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
+                    mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
                     mScreenOnBlocker, mPolicy);
 
             // The display power controller runs on the power manager service's
             // own handler thread to ensure timely operation.
             mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
                     mContext, mNotifier, mLightsService, twilight, sensorManager,
-                    mDisplayManagerService, mDisplayBlanker,
+                    mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
                     mDisplayPowerControllerCallbacks, mHandler);
 
             mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
-                    createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"));
+                    createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
+                    mHandler);
             mSettingsObserver = new SettingsObserver(mHandler);
             mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
 
@@ -511,6 +517,8 @@
 
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
+        mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
         mDreamsSupportedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_dreamsSupported);
         mDreamsEnabledByDefaultConfig = resources.getBoolean(
@@ -572,10 +580,14 @@
     }
 
     @Override // Binder call
-    public void acquireWakeLock(IBinder lock, int flags, String tag, WorkSource ws) {
+    public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
+            WorkSource ws) {
         if (lock == null) {
             throw new IllegalArgumentException("lock must not be null");
         }
+        if (packageName == null) {
+            throw new IllegalArgumentException("packageName must not be null");
+        }
         PowerManager.validateWakeLockParameters(flags, tag);
 
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
@@ -590,14 +602,14 @@
         final int pid = Binder.getCallingPid();
         final long ident = Binder.clearCallingIdentity();
         try {
-            acquireWakeLockInternal(lock, flags, tag, ws, uid, pid);
+            acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private void acquireWakeLockInternal(IBinder lock, int flags, String tag, WorkSource ws,
-            int uid, int pid) {
+    private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
+            WorkSource ws, int uid, int pid) {
         synchronized (mLock) {
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
@@ -612,11 +624,11 @@
                 if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
                     // Update existing wake lock.  This shouldn't happen but is harmless.
                     notifyWakeLockReleasedLocked(wakeLock);
-                    wakeLock.updateProperties(flags, tag, ws, uid, pid);
+                    wakeLock.updateProperties(flags, tag, packageName, ws, uid, pid);
                     notifyWakeLockAcquiredLocked(wakeLock);
                 }
             } else {
-                wakeLock = new WakeLock(lock, flags, tag, ws, uid, pid);
+                wakeLock = new WakeLock(lock, flags, tag, packageName, ws, uid, pid);
                 try {
                     lock.linkToDeath(wakeLock, 0);
                 } catch (RemoteException ex) {
@@ -632,6 +644,7 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
     private static boolean isScreenLock(final WakeLock wakeLock) {
         switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
             case PowerManager.FULL_WAKE_LOCK:
@@ -643,8 +656,8 @@
     }
 
     private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock) {
-        if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 &&
-                isScreenLock(wakeLock)) {
+        if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
+                && isScreenLock(wakeLock)) {
             wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
         }
     }
@@ -718,7 +731,8 @@
     }
 
     private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
-        if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0) {
+        if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0
+                && isScreenLock(wakeLock)) {
             userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
                     PowerManager.USER_ACTIVITY_EVENT_OTHER,
                     PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,
@@ -785,14 +799,16 @@
 
     private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) {
         if (mSystemReady) {
-            mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag,
+            wakeLock.mNotifiedAcquired = true;
+            mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
                     wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
         }
     }
 
     private void notifyWakeLockReleasedLocked(WakeLock wakeLock) {
-        if (mSystemReady) {
-            mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag,
+        if (mSystemReady && wakeLock.mNotifiedAcquired) {
+            wakeLock.mNotifiedAcquired = false;
+            mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
                     wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
         }
     }
@@ -807,6 +823,7 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
     private boolean isWakeLockLevelSupportedInternal(int level) {
         synchronized (mLock) {
             switch (level) {
@@ -995,6 +1012,7 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
     private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
@@ -1251,6 +1269,7 @@
      *
      * This function must have no other side-effects.
      */
+    @SuppressWarnings("deprecation")
     private void updateWakeLockSummaryLocked(int dirty) {
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
             mWakeLockSummary = 0;
@@ -1289,7 +1308,7 @@
                         break;
                     case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                         if (mWakefulness != WAKEFULNESS_ASLEEP) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+                            mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                         }
                         break;
                 }
@@ -1448,7 +1467,11 @@
 
     /**
      * Returns true if the device is being kept awake by a wake lock, user activity
-     * or the stay on while powered setting.
+     * or the stay on while powered setting.  We also keep the phone awake when
+     * the proximity sensor returns a positive result so that the device does not
+     * lock while in a phone call.  This function only controls whether the device
+     * will go to sleep or dream which is independent of whether it will be allowed
+     * to suspend.
      */
     private boolean isBeingKeptAwakeLocked() {
         return mStayOn
@@ -1739,10 +1762,8 @@
      * This function must have no other side-effects.
      */
     private void updateSuspendBlockerLocked() {
-        final boolean needWakeLockSuspendBlocker = (mWakeLockSummary != 0);
-        final boolean needDisplaySuspendBlocker = (mUserActivitySummary != 0
-                || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
-                || !mDisplayReady || !mBootCompleted);
+        final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
+        final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
 
         // First acquire suspend blockers if needed.
         if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1765,6 +1786,27 @@
         }
     }
 
+    /**
+     * Return true if we must keep a suspend blocker active on behalf of the display.
+     * We do so if the screen is on or is in transition between states.
+     */
+    private boolean needDisplaySuspendBlocker() {
+        if (!mDisplayReady) {
+            return true;
+        }
+        if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+            // If we asked for the screen to be on but it is off due to the proximity
+            // sensor then we may suspend but only if the configuration allows it.
+            // On some hardware it may not be safe to suspend because the proximity
+            // sensor may not be correctly configured as a wake-up source.
+            if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
+                    || !mSuspendWhenScreenOffDueToProximityConfig) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override // Binder call
     public boolean isScreenOn() {
         final long ident = Binder.clearCallingIdentity();
@@ -2105,7 +2147,7 @@
      *
      * @param brightness The overridden brightness.
      *
-     * @see Settings.System#SCREEN_BRIGHTNESS
+     * @see android.provider.Settings.System#SCREEN_BRIGHTNESS
      */
     @Override // Binder call
     public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
@@ -2170,18 +2212,26 @@
      * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
      */
     public static void lowLevelShutdown() {
-        nativeShutdown();
+        SystemProperties.set("sys.powerctl", "shutdown");
     }
 
     /**
-     * Low-level function to reboot the device.
+     * Low-level function to reboot the device. On success, this function
+     * doesn't return. If more than 5 seconds passes from the time,
+     * a reboot is requested, this method returns.
      *
      * @param reason code to pass to the kernel (e.g. "recovery"), or null.
-     * @throws IOException if reboot fails for some reason (eg, lack of
-     *         permission)
      */
-    public static void lowLevelReboot(String reason) throws IOException {
-        nativeReboot(reason);
+    public static void lowLevelReboot(String reason) {
+        if (reason == null) {
+            reason = "";
+        }
+        SystemProperties.set("sys.powerctl", "reboot," + reason);
+        try {
+            Thread.sleep(20000);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
     }
 
     @Override // Watchdog.Monitor implementation
@@ -2237,7 +2287,16 @@
 
             pw.println();
             pw.println("Settings and Configuration:");
+            pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
+                    + mWakeUpWhenPluggedOrUnpluggedConfig);
+            pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
+                    + mSuspendWhenScreenOffDueToProximityConfig);
             pw.println("  mDreamsSupportedConfig=" + mDreamsSupportedConfig);
+            pw.println("  mDreamsEnabledByDefaultConfig=" + mDreamsEnabledByDefaultConfig);
+            pw.println("  mDreamsActivatedOnSleepByDefaultConfig="
+                    + mDreamsActivatedOnSleepByDefaultConfig);
+            pw.println("  mDreamsActivatedOnDockByDefaultConfig="
+                    + mDreamsActivatedOnDockByDefaultConfig);
             pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
             pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
             pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
@@ -2426,15 +2485,18 @@
         public final IBinder mLock;
         public int mFlags;
         public String mTag;
+        public final String mPackageName;
         public WorkSource mWorkSource;
-        public int mOwnerUid;
-        public int mOwnerPid;
+        public final int mOwnerUid;
+        public final int mOwnerPid;
+        public boolean mNotifiedAcquired;
 
-        public WakeLock(IBinder lock, int flags, String tag, WorkSource workSource,
-                int ownerUid, int ownerPid) {
+        public WakeLock(IBinder lock, int flags, String tag, String packageName,
+                WorkSource workSource, int ownerUid, int ownerPid) {
             mLock = lock;
             mFlags = flags;
             mTag = tag;
+            mPackageName = packageName;
             mWorkSource = copyWorkSource(workSource);
             mOwnerUid = ownerUid;
             mOwnerPid = ownerPid;
@@ -2454,13 +2516,23 @@
                     && mOwnerPid == ownerPid;
         }
 
-        public void updateProperties(int flags, String tag, WorkSource workSource,
-                int ownerUid, int ownerPid) {
+        public void updateProperties(int flags, String tag, String packageName,
+                WorkSource workSource, int ownerUid, int ownerPid) {
+            if (!mPackageName.equals(packageName)) {
+                throw new IllegalStateException("Existing wake lock package name changed: "
+                        + mPackageName + " to " + packageName);
+            }
+            if (mOwnerUid != ownerUid) {
+                throw new IllegalStateException("Existing wake lock uid changed: "
+                        + mOwnerUid + " to " + ownerUid);
+            }
+            if (mOwnerPid != ownerPid) {
+                throw new IllegalStateException("Existing wake lock pid changed: "
+                        + mOwnerPid + " to " + ownerPid);
+            }
             mFlags = flags;
             mTag = tag;
             updateWorkSource(workSource);
-            mOwnerUid = ownerUid;
-            mOwnerPid = ownerPid;
         }
 
         public boolean hasSameWorkSource(WorkSource workSource) {
diff --git a/services/java/com/android/server/power/ShutdownThread.java b/services/java/com/android/server/power/ShutdownThread.java
index c084666..88a27f5 100644
--- a/services/java/com/android/server/power/ShutdownThread.java
+++ b/services/java/com/android/server/power/ShutdownThread.java
@@ -492,11 +492,8 @@
     public static void rebootOrShutdown(boolean reboot, String reason) {
         if (reboot) {
             Log.i(TAG, "Rebooting, reason: " + reason);
-            try {
-                PowerManagerService.lowLevelReboot(reason);
-            } catch (Exception e) {
-                Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
-            }
+            PowerManagerService.lowLevelReboot(reason);
+            Log.e(TAG, "Reboot failed, will attempt shutdown instead");
         } else if (SHUTDOWN_VIBRATE_MS > 0) {
             // vibrate before shutting down
             Vibrator vibrator = new SystemVibrator();
diff --git a/services/java/com/android/server/power/WirelessChargerDetector.java b/services/java/com/android/server/power/WirelessChargerDetector.java
index ac6dc3e..38f5d77 100644
--- a/services/java/com/android/server/power/WirelessChargerDetector.java
+++ b/services/java/com/android/server/power/WirelessChargerDetector.java
@@ -21,7 +21,11 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
 import android.util.Slog;
+import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 
@@ -69,12 +73,12 @@
     private static final String TAG = "WirelessChargerDetector";
     private static final boolean DEBUG = false;
 
-    // Number of nanoseconds per millisecond.
-    private static final long NANOS_PER_MS = 1000000;
-
     // The minimum amount of time to spend watching the sensor before making
     // a determination of whether movement occurred.
-    private static final long SETTLE_TIME_NANOS = 500 * NANOS_PER_MS;
+    private static final long SETTLE_TIME_MILLIS = 800;
+
+    // The sensor sampling interval.
+    private static final int SAMPLING_INTERVAL_MILLIS = 50;
 
     // The minimum number of samples that must be collected.
     private static final int MIN_SAMPLES = 3;
@@ -96,6 +100,7 @@
 
     private final SensorManager mSensorManager;
     private final SuspendBlocker mSuspendBlocker;
+    private final Handler mHandler;
 
     // The gravity sensor, or null if none.
     private Sensor mGravitySensor;
@@ -115,6 +120,9 @@
     // The suspend blocker is held while this is the case.
     private boolean mDetectionInProgress;
 
+    // The time when detection was last performed.
+    private long mDetectionStartTime;
+
     // True if the rest position should be updated if at rest.
     // Otherwise, the current rest position is simply checked and cleared if movement
     // is detected but no new rest position is stored.
@@ -126,14 +134,17 @@
     // The number of samples collected that showed evidence of not being at rest.
     private int mMovingSamples;
 
-    // The time and value of the first sample that was collected.
-    private long mFirstSampleTime;
+    // The value of the first sample that was collected.
     private float mFirstSampleX, mFirstSampleY, mFirstSampleZ;
 
+    // The value of the last sample that was collected.
+    private float mLastSampleX, mLastSampleY, mLastSampleZ;
+
     public WirelessChargerDetector(SensorManager sensorManager,
-            SuspendBlocker suspendBlocker) {
+            SuspendBlocker suspendBlocker, Handler handler) {
         mSensorManager = sensorManager;
         mSuspendBlocker = suspendBlocker;
+        mHandler = handler;
 
         mGravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
     }
@@ -147,12 +158,15 @@
             pw.println("  mAtRest=" + mAtRest);
             pw.println("  mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ);
             pw.println("  mDetectionInProgress=" + mDetectionInProgress);
+            pw.println("  mDetectionStartTime=" + (mDetectionStartTime == 0 ? "0 (never)"
+                    : TimeUtils.formatUptime(mDetectionStartTime)));
             pw.println("  mMustUpdateRestPosition=" + mMustUpdateRestPosition);
             pw.println("  mTotalSamples=" + mTotalSamples);
             pw.println("  mMovingSamples=" + mMovingSamples);
-            pw.println("  mFirstSampleTime=" + mFirstSampleTime);
             pw.println("  mFirstSampleX=" + mFirstSampleX
                     + ", mFirstSampleY=" + mFirstSampleY + ", mFirstSampleZ=" + mFirstSampleZ);
+            pw.println("  mLastSampleX=" + mLastSampleX
+                    + ", mLastSampleY=" + mLastSampleY + ", mLastSampleZ=" + mLastSampleZ);
         }
     }
 
@@ -209,25 +223,63 @@
     private void startDetectionLocked() {
         if (!mDetectionInProgress && mGravitySensor != null) {
             if (mSensorManager.registerListener(mListener, mGravitySensor,
-                    SensorManager.SENSOR_DELAY_UI)) {
+                    SAMPLING_INTERVAL_MILLIS * 1000)) {
                 mSuspendBlocker.acquire();
                 mDetectionInProgress = true;
+                mDetectionStartTime = SystemClock.uptimeMillis();
                 mTotalSamples = 0;
                 mMovingSamples = 0;
+
+                Message msg = Message.obtain(mHandler, mSensorTimeout);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageDelayed(msg, SETTLE_TIME_MILLIS);
             }
         }
     }
 
-    private void processSample(long timeNanos, float x, float y, float z) {
-        synchronized (mLock) {
-            if (!mDetectionInProgress) {
-                return;
+    private void finishDetectionLocked() {
+        if (mDetectionInProgress) {
+            mSensorManager.unregisterListener(mListener);
+            mHandler.removeCallbacks(mSensorTimeout);
+
+            if (mMustUpdateRestPosition) {
+                clearAtRestLocked();
+                if (mTotalSamples < MIN_SAMPLES) {
+                    Slog.w(TAG, "Wireless charger detector is broken.  Only received "
+                            + mTotalSamples + " samples from the gravity sensor but we "
+                            + "need at least " + MIN_SAMPLES + " and we expect to see "
+                            + "about " + SETTLE_TIME_MILLIS / SAMPLING_INTERVAL_MILLIS
+                            + " on average.");
+                } else if (mMovingSamples == 0) {
+                    mAtRest = true;
+                    mRestX = mLastSampleX;
+                    mRestY = mLastSampleY;
+                    mRestZ = mLastSampleZ;
+                }
+                mMustUpdateRestPosition = false;
             }
 
+            if (DEBUG) {
+                Slog.d(TAG, "New state: mAtRest=" + mAtRest
+                        + ", mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ
+                        + ", mTotalSamples=" + mTotalSamples
+                        + ", mMovingSamples=" + mMovingSamples);
+            }
+
+            mDetectionInProgress = false;
+            mSuspendBlocker.release();
+        }
+    }
+
+    private void processSampleLocked(float x, float y, float z) {
+        if (mDetectionInProgress) {
+            mLastSampleX = x;
+            mLastSampleY = y;
+            mLastSampleZ = z;
+
             mTotalSamples += 1;
             if (mTotalSamples == 1) {
                 // Save information about the first sample collected.
-                mFirstSampleTime = timeNanos;
                 mFirstSampleX = x;
                 mFirstSampleY = y;
                 mFirstSampleZ = z;
@@ -247,32 +299,6 @@
                 }
                 clearAtRestLocked();
             }
-
-            // Save the result when done.
-            if (timeNanos - mFirstSampleTime >= SETTLE_TIME_NANOS
-                    && mTotalSamples >= MIN_SAMPLES) {
-                mSensorManager.unregisterListener(mListener);
-                if (mMustUpdateRestPosition) {
-                    if (mMovingSamples == 0) {
-                        mAtRest = true;
-                        mRestX = x;
-                        mRestY = y;
-                        mRestZ = z;
-                    } else {
-                        clearAtRestLocked();
-                    }
-                    mMustUpdateRestPosition = false;
-                }
-                mDetectionInProgress = false;
-                mSuspendBlocker.release();
-
-                if (DEBUG) {
-                    Slog.d(TAG, "New state: mAtRest=" + mAtRest
-                            + ", mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ
-                            + ", mTotalSamples=" + mTotalSamples
-                            + ", mMovingSamples=" + mMovingSamples);
-                }
-            }
         }
     }
 
@@ -310,11 +336,22 @@
     private final SensorEventListener mListener = new SensorEventListener() {
         @Override
         public void onSensorChanged(SensorEvent event) {
-            processSample(event.timestamp, event.values[0], event.values[1], event.values[2]);
+            synchronized (mLock) {
+                processSampleLocked(event.values[0], event.values[1], event.values[2]);
+            }
         }
 
         @Override
         public void onAccuracyChanged(Sensor sensor, int accuracy) {
         }
     };
+
+    private final Runnable mSensorTimeout = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                finishDetectionLocked();
+            }
+        }
+    };
 }
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
new file mode 100644
index 0000000..b8e1b04
--- /dev/null
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -0,0 +1,631 @@
+/*
+ * 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.print;
+
+import android.Manifest;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+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.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintManager;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public final class PrintManagerService extends IPrintManager.Stub {
+
+    private static final char COMPONENT_NAME_SEPARATOR = ':';
+
+    private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
+            "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
+
+    private final Object mLock = new Object();
+
+    private final Context mContext;
+
+    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+
+    private int mCurrentUserId = UserHandle.USER_OWNER;
+
+    public PrintManagerService(Context context) {
+        mContext = context;
+        registerContentObservers();
+        registerBoradcastReceivers();
+    }
+
+    public void systemRuning() {
+        BackgroundThread.getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                final UserState userState;
+                synchronized (mLock) {
+                    userState = getCurrentUserStateLocked();
+                    userState.updateIfNeededLocked();
+                }
+                // This is the first time we switch to this user after boot, so
+                // now is the time to remove obsolete print jobs since they
+                // are from the last boot and no application would query them.
+                userState.removeObsoletePrintJobs();
+            }
+        });
+    }
+
+    @Override
+    public PrintJobInfo print(String printJobName, final IPrintClient client,
+            final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+            int appId, int userId) {
+        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return userState.print(printJobName, client, documentAdapter,
+                    attributes, resolvedAppId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
+        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return userState.getPrintJobInfos(resolvedAppId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
+        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return userState.getPrintJobInfo(printJobId, resolvedAppId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
+        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.cancelPrintJob(printJobId, resolvedAppId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
+        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.restartPrintJob(printJobId, resolvedAppId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return userState.getEnabledPrintServices();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return userState.getInstalledPrintServices();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
+            int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.createPrinterDiscoverySession(observer);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
+            int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.destroyPrinterDiscoverySession(observer);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
+            List<PrinterId> priorityList, int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.startPrinterDiscovery(observer, priorityList);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.stopPrinterDiscovery(observer);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void validatePrinters(List<PrinterId> printerIds, int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.validatePrinters(printerIds);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void startPrinterStateTracking(PrinterId printerId, int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.startPrinterStateTracking(printerId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void stopPrinterStateTracking(PrinterId printerId, int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.stopPrinterStateTracking(printerId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+            int appId, int userId) throws RemoteException {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.addPrintJobStateChangeListener(listener, resolvedAppId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+            int userId) {
+        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+        final UserState userState;
+        synchronized (mLock) {
+            userState = getOrCreateUserStateLocked(resolvedUserId);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            userState.removePrintJobStateChangeListener(listener);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump PrintManager from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mLock) {
+            pw.println("PRINT MANAGER STATE (dumpsys print)");
+            final int userStateCount = mUserStates.size();
+            for (int i = 0; i < userStateCount; i++) {
+                UserState userState = mUserStates.get(i);
+                userState.dump(fd, pw, "");
+                pw.println();
+            }
+        }
+    }
+
+    private void registerContentObservers() {
+        final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
+                Settings.Secure.ENABLED_PRINT_SERVICES);
+
+        ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                if (enabledPrintServicesUri.equals(uri)) {
+                    synchronized (mLock) {
+                        UserState userState = getCurrentUserStateLocked();
+                        userState.updateIfNeededLocked();
+                    }
+                }
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
+                false, observer, UserHandle.USER_ALL);
+    }
+
+    private void registerBoradcastReceivers() {
+        PackageMonitor monitor = new PackageMonitor() {
+            @Override
+            public boolean onPackageChanged(String packageName, int uid, String[] components) {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
+                    while (iterator.hasNext()) {
+                        ComponentName componentName = iterator.next();
+                        if (packageName.equals(componentName.getPackageName())) {
+                            userState.updateIfNeededLocked();
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
+                    while (iterator.hasNext()) {
+                        ComponentName componentName = iterator.next();
+                        if (packageName.equals(componentName.getPackageName())) {
+                            iterator.remove();
+                            persistComponentNamesToSettingLocked(
+                                    Settings.Secure.ENABLED_PRINT_SERVICES,
+                                    userState.getEnabledServices(), getChangingUserId());
+                            userState.updateIfNeededLocked();
+                            return;
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
+                    int uid, boolean doit) {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                    boolean stoppedSomePackages = false;
+                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
+                    while (iterator.hasNext()) {
+                        ComponentName componentName = iterator.next();
+                        String componentPackage = componentName.getPackageName();
+                        for (String stoppedPackage : stoppedPackages) {
+                            if (componentPackage.equals(stoppedPackage)) {
+                                if (!doit) {
+                                    return true;
+                                }
+                                stoppedSomePackages = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (stoppedSomePackages) {
+                        userState.updateIfNeededLocked();
+                    }
+                    return false;
+                }
+            }
+
+            @Override
+            public void onPackageAdded(String packageName, int uid) {
+                Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+                intent.setPackage(packageName);
+
+                List<ResolveInfo> installedServices = mContext.getPackageManager()
+                        .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
+                                getChangingUserId());
+
+                if (installedServices == null) {
+                    return;
+                }
+
+                final int installedServiceCount = installedServices.size();
+                for (int i = 0; i < installedServiceCount; i++) {
+                    ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
+                    ComponentName component = new ComponentName(serviceInfo.packageName,
+                            serviceInfo.name);
+                    String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString();
+                    showEnableInstalledPrintServiceNotification(component, label);
+                }
+            }
+
+            private void persistComponentNamesToSettingLocked(String settingName,
+                    Set<ComponentName> componentNames, int userId) {
+                StringBuilder builder = new StringBuilder();
+                for (ComponentName componentName : componentNames) {
+                    if (builder.length() > 0) {
+                        builder.append(COMPONENT_NAME_SEPARATOR);
+                    }
+                    builder.append(componentName.flattenToShortString());
+                }
+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                        settingName, builder.toString(), userId);
+            }
+        };
+
+        // package changes
+        monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
+                UserHandle.ALL, true);
+
+        // user changes
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
+    }
+
+    private UserState getCurrentUserStateLocked() {
+        return getOrCreateUserStateLocked(mCurrentUserId);
+    }
+
+    private UserState getOrCreateUserStateLocked(int userId) {
+        UserState userState = mUserStates.get(userId);
+        if (userState == null) {
+            userState = new UserState(mContext, userId, mLock);
+            mUserStates.put(userId, userState);
+        }
+        return userState;
+    }
+
+    private void switchUser(int newUserId) {
+        UserState userState;
+        synchronized (mLock) {
+            if (newUserId == mCurrentUserId) {
+                return;
+            }
+            mCurrentUserId = newUserId;
+            userState = mUserStates.get(mCurrentUserId);
+            if (userState == null) {
+                userState = getCurrentUserStateLocked();
+                userState.updateIfNeededLocked();
+            } else {
+                userState.updateIfNeededLocked();
+            }
+        }
+        // This is the first time we switch to this user after boot, so
+        // now is the time to remove obsolete print jobs since they
+        // are from the last boot and no application would query them.
+        userState.removeObsoletePrintJobs();
+    }
+
+    private void removeUser(int removedUserId) {
+        synchronized (mLock) {
+            UserState userState = mUserStates.get(removedUserId);
+            if (userState != null) {
+                userState.destroyLocked();
+                mUserStates.remove(removedUserId);
+            }
+        }
+    }
+
+    private int resolveCallingAppEnforcingPermissions(int appId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+                || callingUid == Process.SHELL_UID) {
+            return appId;
+        }
+        final int callingAppId = UserHandle.getAppId(callingUid);
+        if (appId == callingAppId) {
+            return appId;
+        }
+        if (mContext.checkCallingPermission(
+                "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Call from app " + callingAppId + " as app "
+                    + appId + " without com.android.printspooler.permission"
+                    + ".ACCESS_ALL_PRINT_JOBS");
+        }
+        return appId;
+    }
+
+    private int resolveCallingUserEnforcingPermissions(int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+                || callingUid == Process.SHELL_UID) {
+            return userId;
+        }
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (callingUserId == userId) {
+            return userId;
+        }
+        if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                != PackageManager.PERMISSION_GRANTED
+            ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+                != PackageManager.PERMISSION_GRANTED) {
+            if (userId == UserHandle.USER_CURRENT_OR_SELF) {
+                return callingUserId;
+            }
+            throw new SecurityException("Call from user " + callingUserId + " as user "
+                + userId + " without permission INTERACT_ACROSS_USERS or "
+                + "INTERACT_ACROSS_USERS_FULL not allowed.");
+        }
+        if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
+            return mCurrentUserId;
+        }
+        throw new IllegalArgumentException("Calling user can be changed to only "
+                + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
+    }
+
+    private void showEnableInstalledPrintServiceNotification(ComponentName component,
+            String label) {
+        Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
+        intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
+
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent,
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null);
+
+        Notification.Builder builder = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_print)
+                .setContentTitle(mContext.getString(R.string.print_service_installed_title, label))
+                .setContentText(mContext.getString(R.string.print_service_installed_message))
+                .setContentIntent(pendingIntent)
+                .setWhen(System.currentTimeMillis())
+                .setAutoCancel(true)
+                .setShowWhen(true);
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        String notificationTag = getClass().getName() + ":" + component.flattenToString();
+        notificationManager.notify(notificationTag, 0, builder.build());
+    }
+}
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
new file mode 100644
index 0000000..5b9dc28
--- /dev/null
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -0,0 +1,806 @@
+/*
+ * 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.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.IPrintService;
+import android.printservice.IPrintServiceClient;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a remote print service. It abstracts away the binding
+ * and unbinding from the remote implementation. Clients can call methods of
+ * this class without worrying about when and how to bind/unbind.
+ */
+final class RemotePrintService implements DeathRecipient {
+
+    private static final String LOG_TAG = "RemotePrintService";
+
+    private static final boolean DEBUG = false;
+
+    private final Context mContext;
+
+    private final ComponentName mComponentName;
+
+    private final Intent mIntent;
+
+    private final RemotePrintSpooler mSpooler;
+
+    private final PrintServiceCallbacks mCallbacks;
+
+    private final int mUserId;
+
+    private final List<Runnable> mPendingCommands = new ArrayList<Runnable>();
+
+    private final ServiceConnection mServiceConnection = new RemoteServiceConneciton();
+
+    private final RemotePrintServiceClient mPrintServiceClient;
+
+    private final Handler mHandler;
+
+    private IPrintService mPrintService;
+
+    private boolean mBinding;
+
+    private boolean mDestroyed;
+
+    private boolean mHasActivePrintJobs;
+
+    private boolean mHasPrinterDiscoverySession;
+
+    private boolean mServiceDied;
+
+    private List<PrinterId> mDiscoveryPriorityList;
+
+    private List<PrinterId> mTrackedPrinterList;
+
+    public static interface PrintServiceCallbacks {
+        public void onPrintersAdded(List<PrinterInfo> printers);
+        public void onPrintersRemoved(List<PrinterId> printerIds);
+        public void onServiceDied(RemotePrintService service);
+    }
+
+    public RemotePrintService(Context context, ComponentName componentName, int userId,
+            RemotePrintSpooler spooler, PrintServiceCallbacks callbacks) {
+        mContext = context;
+        mCallbacks = callbacks;
+        mComponentName = componentName;
+        mIntent = new Intent().setComponent(mComponentName);
+        mUserId = userId;
+        mSpooler = spooler;
+        mHandler = new MyHandler(context.getMainLooper());
+        mPrintServiceClient = new RemotePrintServiceClient(this);
+    }
+
+    public ComponentName getComponentName() {
+        return mComponentName;
+    }
+
+    public void destroy() {
+        mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY);
+    }
+
+    private void handleDestroy() {
+        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);
+                }
+            }
+        }
+
+        // Stop printer discovery.
+        if (mDiscoveryPriorityList != null) {
+            handleStopPrinterDiscovery();
+        }
+
+        // Destroy the discovery session.
+        if (mHasPrinterDiscoverySession) {
+            handleDestroyPrinterDiscoverySession();
+        }
+
+        // Unbind.
+        ensureUnbound();
+
+        // Done
+        mDestroyed = true;
+    }
+
+    @Override
+    public void binderDied() {
+        mHandler.sendEmptyMessage(MyHandler.MSG_BINDER_DIED);
+    }
+
+    private void handleBinderDied() {
+        mPrintService.asBinder().unlinkToDeath(this, 0);
+        mPrintService = null;
+        mServiceDied = true;
+        mCallbacks.onServiceDied(this);
+    }
+
+    public void onAllPrintJobsHandled() {
+        mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED);
+    }
+
+    private void handleOnAllPrintJobsHandled() {
+        throwIfDestroyed();
+        mHasActivePrintJobs = false;
+        if (!isBound()) {
+            // The service is dead and neither has active jobs nor discovery
+            // session, so ensure we are unbound since the service has no work.
+            if (mServiceDied && !mHasPrinterDiscoverySession) {
+                ensureUnbound();
+                return;
+            }
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleOnAllPrintJobsHandled();
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] onAllPrintJobsHandled()");
+            }
+            // If the service has a printer discovery session
+            // created we should not disconnect from it just yet.
+            if (!mHasPrinterDiscoverySession) {
+                ensureUnbound();
+            }
+        }
+    }
+
+    public void onRequestCancelPrintJob(PrintJobInfo printJob) {
+        mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINT_JOB,
+                printJob).sendToTarget();
+    }
+
+    private void handleRequestCancelPrintJob(final PrintJobInfo printJob) {
+        throwIfDestroyed();
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleRequestCancelPrintJob(printJob);
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCancelPrintJob()");
+            }
+            try {
+                mPrintService.requestCancelPrintJob(printJob);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error canceling a pring job.", re);
+            }
+        }
+    }
+
+    public void onPrintJobQueued(PrintJobInfo printJob) {
+        mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED,
+                printJob).sendToTarget();
+    }
+
+    private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
+        throwIfDestroyed();
+        mHasActivePrintJobs = true;
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleOnPrintJobQueued(printJob);
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] onPrintJobQueued()");
+            }
+            try {
+                mPrintService.onPrintJobQueued(printJob);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error announcing queued pring job.", re);
+            }
+        }
+    }
+
+    public void createPrinterDiscoverySession() {
+        mHandler.sendEmptyMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
+    }
+
+    private void handleCreatePrinterDiscoverySession() {
+        throwIfDestroyed();
+        mHasPrinterDiscoverySession = true;
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleCreatePrinterDiscoverySession();
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] createPrinterDiscoverySession()");
+            }
+            try {
+                mPrintService.createPrinterDiscoverySession();
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error creating printer dicovery session.", re);
+            }
+        }
+    }
+
+    public void destroyPrinterDiscoverySession() {
+        mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
+    }
+
+    private void handleDestroyPrinterDiscoverySession() {
+        throwIfDestroyed();
+        mHasPrinterDiscoverySession = false;
+        if (!isBound()) {
+            // The service is dead and neither has active jobs nor discovery
+            // session, so ensure we are unbound since the service has no work.
+            if (mServiceDied && !mHasActivePrintJobs) {
+                ensureUnbound();
+                return;
+            }
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleDestroyPrinterDiscoverySession();
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()");
+            }
+            try {
+                mPrintService.destroyPrinterDiscoverySession();
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re);
+            }
+            // If the service has no print jobs and no active discovery
+            // session anymore we should disconnect from it.
+            if (!mHasActivePrintJobs) {
+                ensureUnbound();
+            }
+        }
+    }
+
+    public void startPrinterDiscovery(List<PrinterId> priorityList) {
+        mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY,
+                priorityList).sendToTarget();
+    }
+
+    private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) {
+        throwIfDestroyed();
+        // Take a note that we are doing discovery.
+        mDiscoveryPriorityList = new ArrayList<PrinterId>();
+        if (priorityList != null) {
+            mDiscoveryPriorityList.addAll(priorityList);
+        }
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleStartPrinterDiscovery(priorityList);
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterDiscovery()");
+            }
+            try {
+                mPrintService.startPrinterDiscovery(priorityList);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error starting printer dicovery.", re);
+            }
+        }
+    }
+
+    public void stopPrinterDiscovery() {
+        mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY);
+    }
+
+    private void handleStopPrinterDiscovery() {
+        throwIfDestroyed();
+        // We are not doing discovery anymore.
+        mDiscoveryPriorityList = null;
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleStopPrinterDiscovery();
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()");
+            }
+            try {
+                mPrintService.stopPrinterDiscovery();
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error stopping printer dicovery.", re);
+            }
+        }
+    }
+
+    public void validatePrinters(List<PrinterId> printerIds) {
+        mHandler.obtainMessage(MyHandler.MSG_VALIDATE_PRINTERS,
+                printerIds).sendToTarget();
+    }
+
+    private void handleValidatePrinters(final List<PrinterId> printerIds) {
+        throwIfDestroyed();
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleValidatePrinters(printerIds);
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] validatePrinters()");
+            }
+            try {
+                mPrintService.validatePrinters(printerIds);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error requesting printers validation.", re);
+            }
+        }
+    }
+
+    public void startPrinterStateTracking(PrinterId printerId) {
+        mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING,
+                printerId).sendToTarget();
+    }
+
+    private void handleStartPrinterStateTracking(final PrinterId printerId) {
+        throwIfDestroyed();
+        // Take a note we are tracking the printer.
+        if (mTrackedPrinterList == null) {
+            mTrackedPrinterList = new ArrayList<PrinterId>();
+        }
+        mTrackedPrinterList.add(printerId);
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleStartPrinterStateTracking(printerId);
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterTracking()");
+            }
+            try {
+                mPrintService.startPrinterStateTracking(printerId);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error requesting start printer tracking.", re);
+            }
+        }
+    }
+
+    public void stopPrinterStateTracking(PrinterId printerId) {
+        mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_STATE_TRACKING,
+                printerId).sendToTarget();
+    }
+
+    private void handleStopPrinterStateTracking(final PrinterId printerId) {
+        throwIfDestroyed();
+        // We are no longer tracking the printer.
+        if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) {
+            return;
+        }
+        if (mTrackedPrinterList.isEmpty()) {
+            mTrackedPrinterList = null;
+        }
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(new Runnable() {
+                @Override
+                public void run() {
+                    handleStopPrinterStateTracking(printerId);
+                }
+            });
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()");
+            }
+            try {
+                mPrintService.stopPrinterStateTracking(printerId);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error requesting stop printer tracking.", re);
+            }
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        String tab = "  ";
+        pw.append(prefix).append("service:").println();
+        pw.append(prefix).append(tab).append("componentName=")
+                .append(mComponentName.flattenToString()).println();
+        pw.append(prefix).append(tab).append("destroyed=")
+                .append(String.valueOf(mDestroyed)).println();
+        pw.append(prefix).append(tab).append("bound=")
+                .append(String.valueOf(isBound())).println();
+        pw.append(prefix).append(tab).append("hasDicoverySession=")
+                .append(String.valueOf(mHasPrinterDiscoverySession)).println();
+        pw.append(prefix).append(tab).append("hasActivePrintJobs=")
+                .append(String.valueOf(mHasActivePrintJobs)).println();
+        pw.append(prefix).append(tab).append("isDiscoveringPrinters=")
+                .append(String.valueOf(mDiscoveryPriorityList != null)).println();
+        pw.append(prefix).append(tab).append("trackedPrinters=")
+                .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null");
+    }
+
+    private boolean isBound() {
+        return mPrintService != null;
+    }
+
+    private void ensureBound() {
+        if (isBound() || mBinding) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
+        }
+        mBinding = true;
+        mContext.bindServiceAsUser(mIntent, mServiceConnection,
+                Context.BIND_AUTO_CREATE, new UserHandle(mUserId));
+    }
+
+    private void ensureUnbound() {
+        if (!isBound() && !mBinding) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
+        }
+        mBinding = false;
+        mPendingCommands.clear();
+        mHasActivePrintJobs = false;
+        mHasPrinterDiscoverySession = false;
+        mDiscoveryPriorityList = null;
+        mTrackedPrinterList = null;
+        if (isBound()) {
+            try {
+                mPrintService.setClient(null);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+            mPrintService.asBinder().unlinkToDeath(this, 0);
+            mPrintService = null;
+            mContext.unbindService(mServiceConnection);
+        }
+    }
+
+    private void throwIfDestroyed() {
+        if (mDestroyed) {
+            throw new IllegalStateException("Cannot interact with a destroyed service");
+        }
+    }
+
+    private class RemoteServiceConneciton implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (mDestroyed || !mBinding) {
+                mContext.unbindService(mServiceConnection);
+                return;
+            }
+            mBinding = false;
+            mPrintService = IPrintService.Stub.asInterface(service);
+            try {
+                service.linkToDeath(RemotePrintService.this, 0);
+            } catch (RemoteException re) {
+                handleBinderDied();
+                return;
+            }
+            try {
+                mPrintService.setClient(mPrintServiceClient);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error setting client for: " + service, re);
+                handleBinderDied();
+                return;
+            }
+            // If the service died and there is a discovery session, recreate it.
+            if (mServiceDied && mHasPrinterDiscoverySession) {
+                handleCreatePrinterDiscoverySession();
+            }
+            // If the service died and there is discovery started, restart it.
+            if (mServiceDied && mDiscoveryPriorityList != null) {
+                handleStartPrinterDiscovery(mDiscoveryPriorityList);
+            }
+            // If the service died and printers were tracked, start tracking.
+            if (mServiceDied && mTrackedPrinterList != null) {
+                final int trackedPrinterCount = mTrackedPrinterList.size();
+                for (int i = 0; i < trackedPrinterCount; i++) {
+                    handleStartPrinterStateTracking(mTrackedPrinterList.get(i));
+                }
+            }
+            // Finally, do all the pending work.
+            while (!mPendingCommands.isEmpty()) {
+                Runnable pendingCommand = mPendingCommands.remove(0);
+                pendingCommand.run();
+            }
+            // We did a best effort to get to the last state if we crashed.
+            // If we do not have print jobs and no discovery is in progress,
+            // then no need to be bound.
+            if (!mHasPrinterDiscoverySession && !mHasActivePrintJobs) {
+                ensureUnbound();
+            }
+            mServiceDied = false;
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mBinding = true;
+        }
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
+        public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
+        public static final int MSG_START_PRINTER_DISCOVERY = 3;
+        public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
+        public static final int MSG_VALIDATE_PRINTERS = 5;
+        public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
+        public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
+        public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 8;
+        public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 9;
+        public static final int MSG_ON_PRINT_JOB_QUEUED = 10;
+        public static final int MSG_DESTROY = 11;
+        public static final int MSG_BINDER_DIED = 12;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
+                    handleCreatePrinterDiscoverySession();
+                } break;
+
+                case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
+                    handleDestroyPrinterDiscoverySession();
+                } break;
+
+                case MSG_START_PRINTER_DISCOVERY: {
+                    List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
+                    handleStartPrinterDiscovery(priorityList);
+                } break;
+
+                case MSG_STOP_PRINTER_DISCOVERY: {
+                    handleStopPrinterDiscovery();
+                } break;
+
+                case MSG_VALIDATE_PRINTERS: {
+                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+                    handleValidatePrinters(printerIds);
+                } break;
+
+                case MSG_START_PRINTER_STATE_TRACKING: {
+                    PrinterId printerId = (PrinterId) message.obj;
+                    handleStartPrinterStateTracking(printerId);
+                } break;
+
+                case MSG_STOP_PRINTER_STATE_TRACKING: {
+                    PrinterId printerId = (PrinterId) message.obj;
+                    handleStopPrinterStateTracking(printerId);
+                } break;
+
+                case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
+                    handleOnAllPrintJobsHandled();
+                } break;
+
+                case MSG_ON_REQUEST_CANCEL_PRINT_JOB: {
+                    PrintJobInfo printJob = (PrintJobInfo) message.obj;
+                    handleRequestCancelPrintJob(printJob);
+                } break;
+
+                case MSG_ON_PRINT_JOB_QUEUED: {
+                    PrintJobInfo printJob = (PrintJobInfo) message.obj;
+                    handleOnPrintJobQueued(printJob);
+                } break;
+
+                case MSG_DESTROY: {
+                    handleDestroy();
+                } break;
+
+                case MSG_BINDER_DIED: {
+                    handleBinderDied();
+                } break;
+            }
+        }
+    }
+
+    private static final class RemotePrintServiceClient extends IPrintServiceClient.Stub {
+        private final WeakReference<RemotePrintService> mWeakService;
+
+        public RemotePrintServiceClient(RemotePrintService service) {
+            mWeakService = new WeakReference<RemotePrintService>(service);
+        }
+
+        @Override
+        public List<PrintJobInfo> getPrintJobInfos() {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    return service.mSpooler.getPrintJobInfos(service.mComponentName,
+                            PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS, PrintManager.APP_ID_ANY);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    return service.mSpooler.getPrintJobInfo(printJobId,
+                            PrintManager.APP_ID_ANY);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    return service.mSpooler.setPrintJobState(printJobId, state, error);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    return service.mSpooler.setPrintJobTag(printJobId, tag);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    service.mSpooler.writePrintJobData(fd, printJobId);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @Override
+        @SuppressWarnings({"rawtypes", "unchecked"})
+        public void onPrintersAdded(ParceledListSlice printers) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                List<PrinterInfo> addedPrinters = (List<PrinterInfo>) printers.getList();
+                throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, addedPrinters);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    service.mCallbacks.onPrintersAdded(addedPrinters);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @Override
+        @SuppressWarnings({"rawtypes", "unchecked"})
+        public void onPrintersRemoved(ParceledListSlice printerIds) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                List<PrinterId> removedPrinterIds = (List<PrinterId>) printerIds.getList();
+                throwIfPrinterIdsTampered(service.mComponentName, removedPrinterIds);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    service.mCallbacks.onPrintersRemoved(removedPrinterIds);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        private void throwIfPrinterIdsForPrinterInfoTampered(ComponentName serviceName,
+                List<PrinterInfo> printerInfos) {
+            final int printerInfoCount = printerInfos.size();
+            for (int i = 0; i < printerInfoCount; i++) {
+                PrinterId printerId = printerInfos.get(i).getId();
+                throwIfPrinterIdTampered(serviceName, printerId);
+            }
+        }
+
+        private void throwIfPrinterIdsTampered(ComponentName serviceName,
+                List<PrinterId> printerIds) {
+            final int printerIdCount = printerIds.size();
+            for (int i = 0; i < printerIdCount; i++) {
+                PrinterId printerId = printerIds.get(i);
+                throwIfPrinterIdTampered(serviceName, printerId);
+            }
+        }
+
+        private void throwIfPrinterIdTampered(ComponentName serviceName, PrinterId printerId) {
+            if (printerId == null || printerId.getServiceName() == null
+                    || !printerId.getServiceName().equals(serviceName)) {
+                throw new IllegalArgumentException("Invalid printer id: " + printerId);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
new file mode 100644
index 0000000..798cea3
--- /dev/null
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -0,0 +1,612 @@
+/*
+ * 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.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintSpooler;
+import android.print.IPrintSpoolerCallbacks;
+import android.print.IPrintSpoolerClient;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.util.Slog;
+import android.util.TimedRemoteCaller;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import libcore.io.IoUtils;
+
+/**
+ * This represents the remote print spooler as a local object to the
+ * PrintManagerSerivce. 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.
+ */
+final class RemotePrintSpooler {
+
+    private static final String LOG_TAG = "RemotePrintSpooler";
+
+    private static final boolean DEBUG = false;
+
+    private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
+
+    private final Object mLock = new Object();
+
+    private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
+
+    private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
+
+    private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
+
+    private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
+
+    private final ServiceConnection mServiceConnection = new MyServiceConnection();
+
+    private final Context mContext;
+
+    private final UserHandle mUserHandle;
+
+    private final PrintSpoolerClient mClient;
+
+    private final Intent mIntent;
+
+    private final PrintSpoolerCallbacks mCallbacks;
+
+    private IPrintSpooler mRemoteInstance;
+
+    private boolean mDestroyed;
+
+    private boolean mCanUnbind;
+
+    public static interface PrintSpoolerCallbacks {
+        public void onPrintJobQueued(PrintJobInfo printJob);
+        public void onAllPrintJobsForServiceHandled(ComponentName printService);
+        public void onPrintJobStateChanged(PrintJobInfo printJob);
+    }
+
+    public RemotePrintSpooler(Context context, int userId,
+            PrintSpoolerCallbacks callbacks) {
+        mContext = context;
+        mUserHandle = new UserHandle(userId);
+        mCallbacks = callbacks;
+        mClient = new PrintSpoolerClient(this);
+        mIntent = new Intent();
+        mIntent.setComponent(new ComponentName("com.android.printspooler",
+                "com.android.printspooler.PrintSpoolerService"));
+    }
+
+    public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
+            int appId) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(),
+                    componentName, state, appId);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error getting print jobs.", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error getting print jobs.", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+        return null;
+    }
+
+    public final void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+            IPrintDocumentAdapter documentAdapter) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            getRemoteInstanceLazy().createPrintJob(printJob, client, documentAdapter);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error creating print job.", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error creating print job.", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            getRemoteInstanceLazy().writePrintJobData(fd, printJobId);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error writing print job data.", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error writing print job data.", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()");
+            }
+            // We passed the file descriptor across and now the other
+            // side is responsible to close it, so close the local copy.
+            IoUtils.closeQuietly(fd);
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(),
+                    printJobId, appId);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error getting print job info.", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error getting print job info.", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+        return null;
+    }
+
+    public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(),
+                    printJobId, state, error);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error setting print job state.", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error setting print job state.", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+        return false;
+    }
+
+    public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(),
+                    printJobId, tag);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error setting print job tag.", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error setting print job tag.", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+        return false;
+    }
+
+    public final void removeObsoletePrintJobs() {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            getRemoteInstanceLazy().removeObsoletePrintJobs();
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re);
+        } catch (TimeoutException te) {
+            Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+                        + "] removeObsoletePrintJobs()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    public final void destroy() {
+        throwIfCalledOnMainThread();
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] destroy()");
+        }
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            unbindLocked();
+            mDestroyed = true;
+            mCanUnbind = false;
+        }
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+        synchronized (mLock) {
+            pw.append(prefix).append("destroyed=")
+                    .append(String.valueOf(mDestroyed)).println();
+            pw.append(prefix).append("bound=")
+                    .append((mRemoteInstance != null) ? "true" : "false").println();
+
+            pw.flush();
+
+            try {
+                getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
+            } catch (TimeoutException te) {
+                /* ignore */
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+    }
+
+    private void onAllPrintJobsHandled() {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            unbindLocked();
+        }
+    }
+
+    private void onPrintJobStateChanged(PrintJobInfo printJob) {
+        mCallbacks.onPrintJobStateChanged(printJob);
+    }
+
+    private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
+        synchronized (mLock) {
+            if (mRemoteInstance != null) {
+                return mRemoteInstance;
+            }
+            bindLocked();
+            return mRemoteInstance;
+        }
+    }
+
+    private void bindLocked() throws TimeoutException {
+        if (mRemoteInstance != null) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
+        }
+
+        mContext.bindServiceAsUser(mIntent, mServiceConnection,
+                Context.BIND_AUTO_CREATE, mUserHandle);
+
+        final long startMillis = SystemClock.uptimeMillis();
+        while (true) {
+            if (mRemoteInstance != null) {
+                break;
+            }
+            final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
+            final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis;
+            if (remainingMillis <= 0) {
+                throw new TimeoutException("Cannot get spooler!");
+            }
+            try {
+                mLock.wait(remainingMillis);
+            } catch (InterruptedException ie) {
+                /* ignore */
+            }
+        }
+
+        mCanUnbind = true;
+        mLock.notifyAll();
+    }
+
+    private void unbindLocked() {
+        if (mRemoteInstance == null) {
+            return;
+        }
+        while (true) {
+            if (mCanUnbind) {
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()");
+                }
+                clearClientLocked();
+                mRemoteInstance = null;
+                mContext.unbindService(mServiceConnection);
+                return;
+            }
+            try {
+                mLock.wait();
+            } catch (InterruptedException ie) {
+                /* ignore */
+            }
+        }
+
+    }
+
+    private void setClientLocked() {
+        try {
+            mRemoteInstance.setClient(mClient);
+        } catch (RemoteException re) {
+            Slog.d(LOG_TAG, "Error setting print spooler client", re);
+        }
+    }
+
+    private void clearClientLocked() {
+        try {
+            mRemoteInstance.setClient(null);
+        } catch (RemoteException re) {
+            Slog.d(LOG_TAG, "Error clearing print spooler client", re);
+        }
+
+    }
+
+    private void throwIfDestroyedLocked() {
+        if (mDestroyed) {
+            throw new IllegalStateException("Cannot interact with a destroyed instance.");
+        }
+    }
+
+    private void throwIfCalledOnMainThread() {
+        if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
+            throw new RuntimeException("Cannot invoke on the main thread");
+        }
+    }
+
+    private final class MyServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                mRemoteInstance = IPrintSpooler.Stub.asInterface(service);
+                setClientLocked();
+                mLock.notifyAll();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (mLock) {
+                clearClientLocked();
+                mRemoteInstance = null;
+            }
+        }
+    }
+
+    private static final class GetPrintJobInfosCaller
+            extends TimedRemoteCaller<List<PrintJobInfo>> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public GetPrintJobInfosCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobs, int sequence) {
+                    onRemoteMethodResult(printJobs, sequence);
+                }
+            };
+        }
+
+        public List<PrintJobInfo> getPrintJobInfos(IPrintSpooler target,
+                ComponentName componentName, int state, int appId)
+                        throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.getPrintJobInfos(mCallback, componentName, state, appId, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public GetPrintJobInfoCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
+                    onRemoteMethodResult(printJob, sequence);
+                }
+            };
+        }
+
+        public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId,
+                int appId) throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public SetPrintJobStateCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void onSetPrintJobStateResult(boolean success, int sequence) {
+                    onRemoteMethodResult(success, sequence);
+                }
+            };
+        }
+
+        public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId,
+                int status, String error) throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.setPrintJobState(printJobId, status, error, mCallback, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public SetPrintJobTagCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void onSetPrintJobTagResult(boolean success, int sequence) {
+                    onRemoteMethodResult(success, sequence);
+                }
+            };
+        }
+
+        public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId,
+                String tag) throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.setPrintJobTag(printJobId, tag, mCallback, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static abstract class BasePrintSpoolerServiceCallbacks
+            extends IPrintSpoolerCallbacks.Stub {
+        @Override
+        public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobIds, int sequence) {
+            /* do nothing */
+        }
+
+        @Override
+        public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
+            /* do nothing */
+        }
+
+        @Override
+        public void onCancelPrintJobResult(boolean canceled, int sequence) {
+            /* do nothing */
+        }
+
+        @Override
+        public void onSetPrintJobStateResult(boolean success, int sequece) {
+            /* do nothing */
+        }
+
+        @Override
+        public void onSetPrintJobTagResult(boolean success, int sequence) {
+            /* do nothing */
+        }
+    }
+
+    private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
+
+        private final WeakReference<RemotePrintSpooler> mWeakSpooler;
+
+        public PrintSpoolerClient(RemotePrintSpooler spooler) {
+            mWeakSpooler = new WeakReference<RemotePrintSpooler>(spooler);
+        }
+
+        @Override
+        public void onPrintJobQueued(PrintJobInfo printJob) {
+            RemotePrintSpooler spooler = mWeakSpooler.get();
+            if (spooler != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    spooler.mCallbacks.onPrintJobQueued(printJob);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @Override
+        public void onAllPrintJobsForServiceHandled(ComponentName printService) {
+            RemotePrintSpooler spooler = mWeakSpooler.get();
+            if (spooler != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    spooler.mCallbacks.onAllPrintJobsForServiceHandled(printService);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @Override
+        public void onAllPrintJobsHandled() {
+            RemotePrintSpooler spooler = mWeakSpooler.get();
+            if (spooler != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    spooler.onAllPrintJobsHandled();
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @Override
+        public void onPrintJobStateChanged(PrintJobInfo printJob) {
+            RemotePrintSpooler spooler = mWeakSpooler.get();
+            if (spooler != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    spooler.onPrintJobStateChanged(printJob);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
new file mode 100644
index 0000000..3b0ee24
--- /dev/null
+++ b/services/java/com/android/server/print/UserState.java
@@ -0,0 +1,1584 @@
+/*
+ * 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.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintJobStateChangeListener;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.SomeArgs;
+import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
+import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Represents the print state for a user.
+ */
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
+
+    private static final String LOG_TAG = "UserState";
+
+    private static final boolean DEBUG = false;
+
+    private static final char COMPONENT_NAME_SEPARATOR = ':';
+
+    private final SimpleStringSplitter mStringColonSplitter =
+            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
+
+    private final Intent mQueryIntent =
+            new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+
+    private final ArrayMap<ComponentName, RemotePrintService> mActiveServices =
+            new ArrayMap<ComponentName, RemotePrintService>();
+
+    private final List<PrintServiceInfo> mInstalledServices =
+            new ArrayList<PrintServiceInfo>();
+
+    private final Set<ComponentName> mEnabledServices =
+            new ArraySet<ComponentName>();
+
+    private final PrintJobForAppCache mPrintJobForAppCache =
+            new PrintJobForAppCache();
+
+    private final Object mLock;
+
+    private final Context mContext;
+
+    private final int mUserId;
+
+    private final RemotePrintSpooler mSpooler;
+
+    private final Handler mHandler;
+
+    private PrinterDiscoverySessionMediator mPrinterDiscoverySession;
+
+    private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
+
+    private boolean mDestroyed;
+
+    public UserState(Context context, int userId, Object lock) {
+        mContext = context;
+        mUserId = userId;
+        mLock = lock;
+        mSpooler = new RemotePrintSpooler(context, userId, this);
+        mHandler = new UserStateHandler(context.getMainLooper());
+        synchronized (mLock) {
+            enableSystemPrintServicesOnFirstBootLocked();
+        }
+    }
+
+    @Override
+    public void onPrintJobQueued(PrintJobInfo printJob) {
+        final RemotePrintService service;
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            ComponentName printServiceName = printJob.getPrinterId().getServiceName();
+            service = mActiveServices.get(printServiceName);
+        }
+        if (service != null) {
+            service.onPrintJobQueued(printJob);
+        } else {
+            // The service for the job is no longer enabled, so just
+            // fail the job with the appropriate message.
+            mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+                    mContext.getString(R.string.reason_service_unavailable));
+        }
+    }
+
+    @Override
+    public void onAllPrintJobsForServiceHandled(ComponentName printService) {
+        final RemotePrintService service;
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            service = mActiveServices.get(printService);
+        }
+        if (service != null) {
+            service.onAllPrintJobsHandled();
+        }
+    }
+
+    public void removeObsoletePrintJobs() {
+        mSpooler.removeObsoletePrintJobs();
+    }
+
+    public PrintJobInfo print(String printJobName, final IPrintClient client,
+            final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+            int appId) {
+        // Create print job place holder.
+        final PrintJobInfo printJob = new PrintJobInfo();
+        printJob.setId(new PrintJobId());
+        printJob.setAppId(appId);
+        printJob.setLabel(printJobName);
+        printJob.setAttributes(attributes);
+        printJob.setState(PrintJobInfo.STATE_CREATED);
+        printJob.setCopies(1);
+
+        // Track this job so we can forget it when the creator dies.
+        if (!mPrintJobForAppCache.onPrintJobCreated(client.asBinder(), appId,
+                printJob)) {
+            // Not adding a print job means the client is dead - done.
+            return null;
+        }
+
+        // Spin the spooler to add the job and show the config UI.
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                mSpooler.createPrintJob(printJob, client, documentAdapter);
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+
+        return printJob;
+    }
+
+    public List<PrintJobInfo> getPrintJobInfos(int appId) {
+        List<PrintJobInfo> cachedPrintJobs = mPrintJobForAppCache.getPrintJobs(appId);
+        // Note that the print spooler is not storing print jobs that
+        // are in a terminal state as it is non-trivial to properly update
+        // the spooler state for when to forget print jobs in terminal state.
+        // Therefore, we fuse the cached print jobs for running apps (some
+        // jobs are in a terminal state) with the ones that the print
+        // spooler knows about (some jobs are being processed).
+        ArrayMap<PrintJobId, PrintJobInfo> result =
+                new ArrayMap<PrintJobId, PrintJobInfo>();
+
+        // Add the cached print jobs for running apps.
+        final int cachedPrintJobCount = cachedPrintJobs.size();
+        for (int i = 0; i < cachedPrintJobCount; i++) {
+            PrintJobInfo cachedPrintJob = cachedPrintJobs.get(i);
+            result.put(cachedPrintJob.getId(), cachedPrintJob);
+        }
+
+        // Add everything else the spooler knows about.
+        List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(null,
+                PrintJobInfo.STATE_ANY, appId);
+        if (printJobs != null) {
+            final int printJobCount = printJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = printJobs.get(i);
+                result.put(printJob.getId(), printJob);
+            }
+        }
+
+        return new ArrayList<PrintJobInfo>(result.values());
+    }
+
+    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+        PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId);
+        if (printJob != null) {
+            return printJob;
+        }
+        return mSpooler.getPrintJobInfo(printJobId, appId);
+    }
+
+    public void cancelPrintJob(PrintJobId printJobId, int appId) {
+        PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
+        if (printJobInfo == null) {
+            return;
+        }
+        if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+            ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
+            RemotePrintService printService = null;
+            synchronized (mLock) {
+                printService = mActiveServices.get(printServiceName);
+            }
+            if (printService == null) {
+                return;
+            }
+            printService.onRequestCancelPrintJob(printJobInfo);
+        } else {
+            // If the print job is failed we do not need cooperation
+            // from the print service.
+            mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
+        }
+    }
+
+    public void restartPrintJob(PrintJobId printJobId, int appId) {
+        PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
+        if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+            return;
+        }
+        mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+    }
+
+    public List<PrintServiceInfo> getEnabledPrintServices() {
+        synchronized (mLock) {
+            List<PrintServiceInfo> enabledServices = null;
+            final int installedServiceCount = mInstalledServices.size();
+            for (int i = 0; i < installedServiceCount; i++) {
+                PrintServiceInfo installedService = mInstalledServices.get(i);
+                ComponentName componentName = new ComponentName(
+                        installedService.getResolveInfo().serviceInfo.packageName,
+                        installedService.getResolveInfo().serviceInfo.name);
+                if (mActiveServices.containsKey(componentName)) {
+                    if (enabledServices == null) {
+                        enabledServices = new ArrayList<PrintServiceInfo>();
+                    }
+                    enabledServices.add(installedService);
+                }
+            }
+            return enabledServices;
+        }
+    }
+
+    public List<PrintServiceInfo> getInstalledPrintServices() {
+        synchronized (mLock) {
+            return mInstalledServices;
+        }
+    }
+
+    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            if (mPrinterDiscoverySession == null) {
+                // If we do not have a session, tell all service to create one.
+                mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
+                    @Override
+                    public void onDestroyed() {
+                        mPrinterDiscoverySession = null;
+                    }
+                };
+                // Add the observer to the brand new session.
+                mPrinterDiscoverySession.addObserverLocked(observer);
+            } else {
+                // If services have created session, just add the observer.
+                mPrinterDiscoverySession.addObserverLocked(observer);
+            }
+        }
+    }
+
+    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+        synchronized (mLock) {
+            // Already destroyed - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            // Remove this observer.
+            mPrinterDiscoverySession.removeObserverLocked(observer);
+        }
+    }
+
+    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
+            List<PrinterId> printerIds) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            // Kick of discovery.
+            mPrinterDiscoverySession.startPrinterDiscoveryLocked(observer,
+                    printerIds);
+        }
+    }
+
+    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            // Kick of discovery.
+            mPrinterDiscoverySession.stopPrinterDiscoveryLocked(observer);
+        }
+    }
+
+    public void validatePrinters(List<PrinterId> printerIds) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            // Request an updated.
+            mPrinterDiscoverySession.validatePrintersLocked(printerIds);
+        }
+    }
+
+    public void startPrinterStateTracking(PrinterId printerId) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            // Request start tracking the printer.
+            mPrinterDiscoverySession.startPrinterStateTrackingLocked(printerId);
+        }
+    }
+
+    public void stopPrinterStateTracking(PrinterId printerId) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            // Request stop tracking the printer.
+            mPrinterDiscoverySession.stopPrinterStateTrackingLocked(printerId);
+        }
+    }
+
+    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+            int appId) throws RemoteException {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintJobStateChangeListenerRecords == null) {
+                mPrintJobStateChangeListenerRecords =
+                        new ArrayList<PrintJobStateChangeListenerRecord>();
+            }
+            mPrintJobStateChangeListenerRecords.add(
+                    new PrintJobStateChangeListenerRecord(listener, appId) {
+                @Override
+                public void onBinderDied() {
+                    mPrintJobStateChangeListenerRecords.remove(this);
+                }
+            });
+        }
+    }
+
+    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintJobStateChangeListenerRecords == null) {
+                return;
+            }
+            final int recordCount = mPrintJobStateChangeListenerRecords.size();
+            for (int i = 0; i < recordCount; i++) {
+                PrintJobStateChangeListenerRecord record =
+                        mPrintJobStateChangeListenerRecords.get(i);
+                if (record.listener.asBinder().equals(listener.asBinder())) {
+                    mPrintJobStateChangeListenerRecords.remove(i);
+                    break;
+                }
+            }
+            if (mPrintJobStateChangeListenerRecords.isEmpty()) {
+                mPrintJobStateChangeListenerRecords = null;
+            }
+        }
+    }
+
+    @Override
+    public void onPrintJobStateChanged(PrintJobInfo printJob) {
+        mPrintJobForAppCache.onPrintJobStateChanged(printJob);
+        mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_JOB_STATE_CHANGED,
+                printJob.getAppId(), 0, printJob.getId()).sendToTarget();
+    }
+
+    @Override
+    public void onPrintersAdded(List<PrinterInfo> printers) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            mPrinterDiscoverySession.onPrintersAddedLocked(printers);
+        }
+    }
+
+    @Override
+    public void onPrintersRemoved(List<PrinterId> printerIds) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds);
+        }
+    }
+
+    @Override
+    public void onServiceDied(RemotePrintService service) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // Fail all print jobs.
+            failActivePrintJobsForService(service.getComponentName());
+            service.onAllPrintJobsHandled();
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            mPrinterDiscoverySession.onServiceDiedLocked(service);
+        }
+    }
+
+    public void updateIfNeededLocked() {
+        throwIfDestroyedLocked();
+        if (readConfigurationLocked()) {
+            onConfigurationChangedLocked();
+        }
+    }
+
+    public Set<ComponentName> getEnabledServices() {
+        synchronized(mLock) {
+            throwIfDestroyedLocked();
+            return mEnabledServices;
+        }
+    }
+
+    public void destroyLocked() {
+        throwIfDestroyedLocked();
+        mSpooler.destroy();
+        for (RemotePrintService service : mActiveServices.values()) {
+            service.destroy();
+        }
+        mActiveServices.clear();
+        mInstalledServices.clear();
+        mEnabledServices.clear();
+        if (mPrinterDiscoverySession != null) {
+            mPrinterDiscoverySession.destroyLocked();
+            mPrinterDiscoverySession = null;
+        }
+        mDestroyed = true;
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+        pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
+        pw.println();
+
+        String tab = "  ";
+
+        pw.append(prefix).append(tab).append("installed services:").println();
+        final int installedServiceCount = mInstalledServices.size();
+        for (int i = 0; i < installedServiceCount; i++) {
+            PrintServiceInfo installedService = mInstalledServices.get(i);
+            String installedServicePrefix = prefix + tab + tab;
+            pw.append(installedServicePrefix).append("service:").println();
+            ResolveInfo resolveInfo = installedService.getResolveInfo();
+            ComponentName componentName = new ComponentName(
+                    resolveInfo.serviceInfo.packageName,
+                    resolveInfo.serviceInfo.name);
+            pw.append(installedServicePrefix).append(tab).append("componentName=")
+                    .append(componentName.flattenToString()).println();
+            pw.append(installedServicePrefix).append(tab).append("settingsActivity=")
+                    .append(installedService.getSettingsActivityName()).println();
+            pw.append(installedServicePrefix).append(tab).append("addPrintersActivity=")
+                    .append(installedService.getAddPrintersActivityName()).println();
+        }
+
+        pw.append(prefix).append(tab).append("enabled services:").println();
+        for (ComponentName enabledService : mEnabledServices) {
+            String enabledServicePrefix = prefix + tab + tab;
+            pw.append(enabledServicePrefix).append("service:").println();
+            pw.append(enabledServicePrefix).append(tab).append("componentName=")
+                    .append(enabledService.flattenToString());
+            pw.println();
+        }
+
+        pw.append(prefix).append(tab).append("active services:").println();
+        final int activeServiceCount = mActiveServices.size();
+        for (int i = 0; i < activeServiceCount; i++) {
+            RemotePrintService activeService = mActiveServices.valueAt(i);
+            activeService.dump(pw, prefix + tab + tab);
+            pw.println();
+        }
+
+        pw.append(prefix).append(tab).append("cached print jobs:").println();
+        mPrintJobForAppCache.dump(pw, prefix + tab + tab);
+
+        pw.append(prefix).append(tab).append("discovery mediator:").println();
+        if (mPrinterDiscoverySession != null) {
+            mPrinterDiscoverySession.dump(pw, prefix + tab + tab);
+        }
+
+        pw.append(prefix).append(tab).append("print spooler:").println();
+        mSpooler.dump(fd, pw, prefix + tab + tab);
+        pw.println();
+    }
+
+    private boolean readConfigurationLocked() {
+        boolean somethingChanged = false;
+        somethingChanged |= readInstalledPrintServicesLocked();
+        somethingChanged |= readEnabledPrintServicesLocked();
+        return somethingChanged;
+    }
+
+    private boolean readInstalledPrintServicesLocked() {
+        Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
+
+        List<ResolveInfo> installedServices = mContext.getPackageManager()
+                .queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES
+                        | PackageManager.GET_META_DATA, mUserId);
+
+        final int installedCount = installedServices.size();
+        for (int i = 0, count = installedCount; i < count; i++) {
+            ResolveInfo installedService = installedServices.get(i);
+            if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals(
+                    installedService.serviceInfo.permission)) {
+                ComponentName serviceName = new ComponentName(
+                        installedService.serviceInfo.packageName,
+                        installedService.serviceInfo.name);
+                Slog.w(LOG_TAG, "Skipping print service "
+                        + serviceName.flattenToShortString()
+                        + " since it does not require permission "
+                        + android.Manifest.permission.BIND_PRINT_SERVICE);
+                continue;
+            }
+            tempPrintServices.add(PrintServiceInfo.create(installedService, mContext));
+        }
+
+        if (!tempPrintServices.equals(mInstalledServices)) {
+            mInstalledServices.clear();
+            mInstalledServices.addAll(tempPrintServices);
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean readEnabledPrintServicesLocked() {
+        Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
+        readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
+                tempEnabledServiceNameSet);
+        if (!tempEnabledServiceNameSet.equals(mEnabledServices)) {
+            mEnabledServices.clear();
+            mEnabledServices.addAll(tempEnabledServiceNameSet);
+            return true;
+        }
+        return false;
+    }
+
+    private void readPrintServicesFromSettingLocked(String setting,
+            Set<ComponentName> outServiceNames) {
+        String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                setting, mUserId);
+        if (!TextUtils.isEmpty(settingValue)) {
+            TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+            splitter.setString(settingValue);
+            while (splitter.hasNext()) {
+                String string = splitter.next();
+                if (TextUtils.isEmpty(string)) {
+                    continue;
+                }
+                ComponentName componentName = ComponentName.unflattenFromString(string);
+                if (componentName != null) {
+                    outServiceNames.add(componentName);
+                }
+            }
+        }
+    }
+
+    private void enableSystemPrintServicesOnFirstBootLocked() {
+        // Load enabled and installed services.
+        readEnabledPrintServicesLocked();
+        readInstalledPrintServicesLocked();
+
+        // Load the system services once enabled on first boot.
+        Set<ComponentName> enabledOnFirstBoot = new HashSet<ComponentName>();
+        readPrintServicesFromSettingLocked(
+                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
+                enabledOnFirstBoot);
+
+        StringBuilder builder = new StringBuilder();
+
+        final int serviceCount = mInstalledServices.size();
+        for (int i = 0; i < serviceCount; i++) {
+            ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo;
+            // Enable system print services if we never did that and are not enabled.
+            if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                ComponentName serviceName = new ComponentName(
+                        serviceInfo.packageName, serviceInfo.name);
+                if (!mEnabledServices.contains(serviceName)
+                        && !enabledOnFirstBoot.contains(serviceName)) {
+                    if (builder.length() > 0) {
+                        builder.append(":");
+                    }
+                    builder.append(serviceName.flattenToString());
+                }
+            }
+        }
+
+        // Nothing to be enabled - done.
+        if (builder.length() <= 0) {
+            return;
+        }
+
+        String servicesToEnable = builder.toString();
+
+        // Update the enabled services setting.
+        String enabledServices = Settings.Secure.getStringForUser(
+                mContext.getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
+        if (TextUtils.isEmpty(enabledServices)) {
+            enabledServices = servicesToEnable;
+        } else {
+            enabledServices = enabledServices + ":" + servicesToEnable;
+        }
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, mUserId);
+
+        // Update the enabled on first boot services setting.
+        String enabledOnFirstBootServices = Settings.Secure.getStringForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, mUserId);
+        if (TextUtils.isEmpty(enabledOnFirstBootServices)) {
+            enabledOnFirstBootServices = servicesToEnable;
+        } else {
+            enabledOnFirstBootServices = enabledOnFirstBootServices + ":" + enabledServices;
+        }
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
+                enabledOnFirstBootServices, mUserId);
+    }
+
+    private void onConfigurationChangedLocked() {
+        final int installedCount = mInstalledServices.size();
+        for (int i = 0; i < installedCount; i++) {
+            ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo();
+            ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName,
+                    resolveInfo.serviceInfo.name);
+            if (mEnabledServices.contains(serviceName)) {
+                if (!mActiveServices.containsKey(serviceName)) {
+                    RemotePrintService service = new RemotePrintService(
+                            mContext, serviceName, mUserId, mSpooler, this);
+                    addServiceLocked(service);
+                }
+            } else {
+                RemotePrintService service = mActiveServices.remove(serviceName);
+                if (service != null) {
+                    removeServiceLocked(service);
+                }
+            }
+        }
+    }
+
+    private void addServiceLocked(RemotePrintService service) {
+        mActiveServices.put(service.getComponentName(), service);
+        if (mPrinterDiscoverySession != null) {
+            mPrinterDiscoverySession.onServiceAddedLocked(service);
+        }
+    }
+
+    private void removeServiceLocked(RemotePrintService service) {
+        // Fail all print jobs.
+        failActivePrintJobsForService(service.getComponentName());
+        // If discovery is in progress, tear down the service.
+        if (mPrinterDiscoverySession != null) {
+            mPrinterDiscoverySession.onServiceRemovedLocked(service);
+        } else {
+            // Otherwise, just destroy it.
+            service.destroy();
+        }
+    }
+
+    private void failActivePrintJobsForService(final ComponentName serviceName) {
+        // Makes sure all active print jobs are failed since the service
+        // just died. Do this off the main thread since we do to allow
+        // calls into the spooler on the main thread.
+        if (Looper.getMainLooper().isCurrentThread()) {
+            BackgroundThread.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    failActivePrintJobsForServiceInternal(serviceName);
+                }
+            });
+        } else {
+            failActivePrintJobsForServiceInternal(serviceName);
+        }
+    }
+
+    private void failActivePrintJobsForServiceInternal(ComponentName serviceName) {
+        List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName,
+                PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
+        if (printJobs == null) {
+            return;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int printJobCount = printJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = printJobs.get(i);
+                mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+                        mContext.getString(R.string.reason_service_unavailable));
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void throwIfDestroyedLocked() {
+        if (mDestroyed) {
+            throw new IllegalStateException("Cannot interact with a destroyed instance.");
+        }
+    }
+
+    private void handleDispatchPrintJobStateChanged(PrintJobId printJobId, int appId) {
+        final List<PrintJobStateChangeListenerRecord> records;
+        synchronized (mLock) {
+            if (mPrintJobStateChangeListenerRecords == null) {
+                return;
+            }
+            records = new ArrayList<PrintJobStateChangeListenerRecord>(
+                    mPrintJobStateChangeListenerRecords);
+        }
+        final int recordCount = records.size();
+        for (int i = 0; i < recordCount; i++) {
+            PrintJobStateChangeListenerRecord record = records.get(i);
+            if (record.appId == PrintManager.APP_ID_ANY
+                    || record.appId == appId)
+            try {
+                record.listener.onPrintJobStateChanged(printJobId);
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error notifying for print job state change", re);
+            }
+        }
+    }
+
+    private final class UserStateHandler extends Handler {
+        public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
+
+        public UserStateHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what == MSG_DISPATCH_PRINT_JOB_STATE_CHANGED) {
+                PrintJobId printJobId = (PrintJobId) message.obj;
+                final int appId = message.arg1;
+                handleDispatchPrintJobStateChanged(printJobId, appId);
+            }
+        }
+    }
+
+    private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
+        final IPrintJobStateChangeListener listener;
+        final int appId;
+
+        public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener,
+                int appId) throws RemoteException {
+            this.listener = listener;
+            this.appId = appId;
+            listener.asBinder().linkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            listener.asBinder().unlinkToDeath(this, 0);
+            onBinderDied();
+        }
+
+        public abstract void onBinderDied();
+    }
+
+    private class PrinterDiscoverySessionMediator {
+        private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
+                new ArrayMap<PrinterId, PrinterInfo>();
+
+        private final RemoteCallbackList<IPrinterDiscoveryObserver> mDiscoveryObservers =
+                new RemoteCallbackList<IPrinterDiscoveryObserver>() {
+            @Override
+            public void onCallbackDied(IPrinterDiscoveryObserver observer) {
+                synchronized (mLock) {
+                    stopPrinterDiscoveryLocked(observer);
+                    removeObserverLocked(observer);
+                }
+            }
+        };
+
+        private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>();
+
+        private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
+
+        private final Handler mHandler;
+
+        private boolean mIsDestroyed;
+
+        public PrinterDiscoverySessionMediator(Context context) {
+            mHandler = new SessionHandler(context.getMainLooper());
+            // Kick off the session creation.
+            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
+                    mActiveServices.values());
+            mHandler.obtainMessage(SessionHandler
+                    .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
+                    .sendToTarget();
+        }
+
+        public void addObserverLocked(IPrinterDiscoveryObserver observer) {
+            // Add the observer.
+            mDiscoveryObservers.register(observer);
+
+            // Bring the added observer up to speed with the printers.
+            if (!mPrinters.isEmpty()) {
+                List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values());
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = observer;
+                args.arg2 = printers;
+                mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
+                        args).sendToTarget();
+            }
+        }
+
+        public void removeObserverLocked(IPrinterDiscoveryObserver observer) {
+            // Remove the observer.
+            mDiscoveryObservers.unregister(observer);
+            // No one else observing - then kill it.
+            if (mDiscoveryObservers.getRegisteredCallbackCount() == 0) {
+                destroyLocked();
+            }
+        }
+
+        public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer,
+                List<PrinterId> priorityList) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not starting dicovery - session destroyed");
+                return;
+            }
+
+            final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty();
+
+            // Remember we got a start request to match with an end.
+            mStartedPrinterDiscoveryTokens.add(observer.asBinder());
+
+            // If printer discovery is ongoing and the start request has a list
+            // of printer to be checked, then we just request validating them.
+            if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) {
+                validatePrinters(priorityList);
+                return;
+            }
+
+            // The service are already performing discovery - nothing to do.
+            if (mStartedPrinterDiscoveryTokens.size() > 1) {
+                return;
+            }
+
+            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
+                    mActiveServices.values());
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = services;
+            args.arg2 = priorityList;
+            mHandler.obtainMessage(SessionHandler
+                    .MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
+                    .sendToTarget();
+        }
+
+        public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not stopping dicovery - session destroyed");
+                return;
+            }
+            // This one did not make an active discovery request - nothing to do.
+            if (!mStartedPrinterDiscoveryTokens.remove(observer.asBinder())) {
+                return;
+            }
+            // There are other interested observers - do not stop discovery.
+            if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
+                return;
+            }
+            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
+                    mActiveServices.values());
+            mHandler.obtainMessage(SessionHandler
+                    .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
+                    .sendToTarget();
+        }
+
+        public void validatePrintersLocked(List<PrinterId> printerIds) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not validating pritners - session destroyed");
+                return;
+            }
+
+            List<PrinterId> remainingList = new ArrayList<PrinterId>(printerIds);
+            while (!remainingList.isEmpty()) {
+                Iterator<PrinterId> iterator = remainingList.iterator();
+                // Gather the printers per service and request a validation.
+                List<PrinterId> updateList = new ArrayList<PrinterId>();
+                ComponentName serviceName = null;
+                while (iterator.hasNext()) {
+                    PrinterId printerId = iterator.next();
+                    if (updateList.isEmpty()) {
+                        updateList.add(printerId);
+                        serviceName = printerId.getServiceName();
+                        iterator.remove();
+                    } else if (printerId.getServiceName().equals(serviceName)) {
+                        updateList.add(printerId);
+                        iterator.remove();
+                    }
+                }
+                // Schedule a notification of the service.
+                RemotePrintService service = mActiveServices.get(serviceName);
+                if (service != null) {
+                    SomeArgs args = SomeArgs.obtain();
+                    args.arg1 = service;
+                    args.arg2 = updateList;
+                    mHandler.obtainMessage(SessionHandler
+                            .MSG_VALIDATE_PRINTERS, args)
+                            .sendToTarget();
+                }
+            }
+        }
+
+        public final void startPrinterStateTrackingLocked(PrinterId printerId) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed");
+                return;
+            }
+            // If printer discovery is not started - nothing to do.
+            if (mStartedPrinterDiscoveryTokens.isEmpty()) {
+                return;
+            }
+            final boolean containedPrinterId = mStateTrackedPrinters.contains(printerId);
+            // Keep track of the number of requests to track this one.
+            mStateTrackedPrinters.add(printerId);
+            // If we were tracking this printer - nothing to do.
+            if (containedPrinterId) {
+                return;
+            }
+            // No service - nothing to do.
+            RemotePrintService service = mActiveServices.get(printerId.getServiceName());
+            if (service == null) {
+                return;
+            }
+            // Ask the service to start tracking.
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = service;
+            args.arg2 = printerId;
+            mHandler.obtainMessage(SessionHandler
+                    .MSG_START_PRINTER_STATE_TRACKING, args)
+                    .sendToTarget();
+        }
+
+        public final void stopPrinterStateTrackingLocked(PrinterId printerId) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not stopping printer state tracking - session destroyed");
+                return;
+            }
+            // If printer discovery is not started - nothing to do.
+            if (mStartedPrinterDiscoveryTokens.isEmpty()) {
+                return;
+            }
+            // If we did not track this printer - nothing to do.
+            if (!mStateTrackedPrinters.remove(printerId)) {
+                return;
+            }
+            // No service - nothing to do.
+            RemotePrintService service = mActiveServices.get(printerId.getServiceName());
+            if (service == null) {
+                return;
+            }
+            // Ask the service to start tracking.
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = service;
+            args.arg2 = printerId;
+            mHandler.obtainMessage(SessionHandler
+                    .MSG_STOP_PRINTER_STATE_TRACKING, args)
+                    .sendToTarget();
+        }
+
+        public void onDestroyed() {
+            /* do nothing */
+        }
+
+        public void destroyLocked() {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not destroying - session destroyed");
+                return;
+            }
+            // Make sure printer tracking is stopped.
+            final int printerCount = mStateTrackedPrinters.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterId printerId = mStateTrackedPrinters.get(i);
+                stopPrinterStateTracking(printerId);
+            }
+            // Make sure discovery is stopped.
+            final int observerCount = mStartedPrinterDiscoveryTokens.size();
+            for (int i = 0; i < observerCount; i++) {
+                IBinder token = mStartedPrinterDiscoveryTokens.get(i);
+                stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token));
+            }
+            // Tell the services we are done.
+            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
+                    mActiveServices.values());
+            mHandler.obtainMessage(SessionHandler
+                    .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
+                    .sendToTarget();
+        }
+
+        public void onPrintersAddedLocked(List<PrinterInfo> printers) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onPrintersAddedLocked()");
+            }
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not adding printers - session destroyed");
+                return;
+            }
+            List<PrinterInfo> addedPrinters = null;
+            final int addedPrinterCount = printers.size();
+            for (int i = 0; i < addedPrinterCount; i++) {
+                PrinterInfo printer = printers.get(i);
+                PrinterInfo oldPrinter = mPrinters.put(printer.getId(), printer);
+                if (oldPrinter == null || !oldPrinter.equals(printer)) {
+                    if (addedPrinters == null) {
+                        addedPrinters = new ArrayList<PrinterInfo>();
+                    }
+                    addedPrinters.add(printer);
+                }
+            }
+            if (addedPrinters != null) {
+                mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+                        addedPrinters).sendToTarget();
+            }
+        }
+
+        public void onPrintersRemovedLocked(List<PrinterId> printerIds) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onPrintersRemovedLocked()");
+            }
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not removing printers - session destroyed");
+                return;
+            }
+            List<PrinterId> removedPrinterIds = null;
+            final int removedPrinterCount = printerIds.size();
+            for (int i = 0; i < removedPrinterCount; i++) {
+                PrinterId removedPrinterId = printerIds.get(i);
+                if (mPrinters.remove(removedPrinterId) != null) {
+                    if (removedPrinterIds == null) {
+                        removedPrinterIds = new ArrayList<PrinterId>();
+                    }
+                    removedPrinterIds.add(removedPrinterId);
+                }
+            }
+            if (removedPrinterIds != null) {
+                mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+                        removedPrinterIds).sendToTarget();
+            }
+        }
+
+        public void onServiceRemovedLocked(RemotePrintService service) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not updating removed service - session destroyed");
+                return;
+            }
+            // Remove the reported and tracked printers for that service.
+            ComponentName serviceName = service.getComponentName();
+            removePrintersForServiceLocked(serviceName);
+            service.destroy();
+        }
+
+        public void onServiceDiedLocked(RemotePrintService service) {
+            // Remove the reported by that service.
+            removePrintersForServiceLocked(service.getComponentName());
+        }
+
+        public void onServiceAddedLocked(RemotePrintService service) {
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not updating added service - session destroyed");
+                return;
+            }
+            // Tell the service to create a session.
+            mHandler.obtainMessage(
+                    SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
+                    service).sendToTarget();
+            // Start printer discovery if necessary.
+            if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
+                mHandler.obtainMessage(
+                        SessionHandler.MSG_START_PRINTER_DISCOVERY,
+                        service).sendToTarget();
+            }
+            // Start tracking printers if necessary
+            final int trackedPrinterCount = mStateTrackedPrinters.size();
+            for (int i = 0; i < trackedPrinterCount; i++) {
+                PrinterId printerId = mStateTrackedPrinters.get(i);
+                if (printerId.getServiceName().equals(service.getComponentName())) {
+                    SomeArgs args = SomeArgs.obtain();
+                    args.arg1 = service;
+                    args.arg2 = printerId;
+                    mHandler.obtainMessage(SessionHandler
+                            .MSG_START_PRINTER_STATE_TRACKING, args)
+                            .sendToTarget();
+                }
+            }
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.append(prefix).append("destroyed=")
+                    .append(String.valueOf(mDestroyed)).println();
+
+            pw.append(prefix).append("printDiscoveryInProgress=")
+                    .append(String.valueOf(!mStartedPrinterDiscoveryTokens.isEmpty())).println();
+
+            String tab = "  ";
+
+            pw.append(prefix).append(tab).append("printer discovery observers:").println();
+            final int observerCount = mDiscoveryObservers.beginBroadcast();
+            for (int i = 0; i < observerCount; i++) {
+                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
+                pw.append(prefix).append(prefix).append(observer.toString());
+                pw.println();
+            }
+            mDiscoveryObservers.finishBroadcast();
+
+            pw.append(prefix).append(tab).append("start discovery requests:").println();
+            final int tokenCount = this.mStartedPrinterDiscoveryTokens.size();
+            for (int i = 0; i < tokenCount; i++) {
+                IBinder token = mStartedPrinterDiscoveryTokens.get(i);
+                pw.append(prefix).append(tab).append(tab).append(token.toString()).println();
+            }
+
+            pw.append(prefix).append(tab).append("tracked printer requests:").println();
+            final int trackedPrinters = mStateTrackedPrinters.size();
+            for (int i = 0; i < trackedPrinters; i++) {
+                PrinterId printer = mStateTrackedPrinters.get(i);
+                pw.append(prefix).append(tab).append(tab).append(printer.toString()).println();
+            }
+
+            pw.append(prefix).append(tab).append("printers:").println();
+            final int pritnerCount = mPrinters.size();
+            for (int i = 0; i < pritnerCount; i++) {
+                PrinterInfo printer = mPrinters.valueAt(i);
+                pw.append(prefix).append(tab).append(tab).append(
+                        printer.toString()).println();
+            }
+        }
+
+        private void removePrintersForServiceLocked(ComponentName serviceName) {
+            // No printers - nothing to do.
+            if (mPrinters.isEmpty()) {
+                return;
+            }
+            // Remove the printers for that service.
+            List<PrinterId> removedPrinterIds = null;
+            final int printerCount = mPrinters.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterId printerId = mPrinters.keyAt(i);
+                if (printerId.getServiceName().equals(serviceName)) {
+                    if (removedPrinterIds == null) {
+                        removedPrinterIds = new ArrayList<PrinterId>();
+                    }
+                    removedPrinterIds.add(printerId);
+                }
+            }
+            if (removedPrinterIds != null) {
+                final int removedPrinterCount = removedPrinterIds.size();
+                for (int i = 0; i < removedPrinterCount; i++) {
+                    mPrinters.remove(removedPrinterIds.get(i));
+                }
+                mHandler.obtainMessage(
+                        SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+                        removedPrinterIds).sendToTarget();
+            }
+        }
+
+        private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
+            final int observerCount = mDiscoveryObservers.beginBroadcast();
+            for (int i = 0; i < observerCount; i++) {
+                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
+                handlePrintersAdded(observer, addedPrinters);
+            }
+            mDiscoveryObservers.finishBroadcast();
+        }
+
+        private void handleDispatchPrintersRemoved(List<PrinterId> removedPrinterIds) {
+            final int observerCount = mDiscoveryObservers.beginBroadcast();
+            for (int i = 0; i < observerCount; i++) {
+                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
+                handlePrintersRemoved(observer, removedPrinterIds);
+            }
+            mDiscoveryObservers.finishBroadcast();
+        }
+
+        private void handleDispatchCreatePrinterDiscoverySession(
+                List<RemotePrintService> services) {
+            final int serviceCount = services.size();
+            for (int i = 0; i < serviceCount; i++) {
+                RemotePrintService service = services.get(i);
+                service.createPrinterDiscoverySession();
+            }
+        }
+
+        private void handleDispatchDestroyPrinterDiscoverySession(
+                List<RemotePrintService> services) {
+            final int serviceCount = services.size();
+            for (int i = 0; i < serviceCount; i++) {
+                RemotePrintService service = services.get(i);
+                service.destroyPrinterDiscoverySession();
+            }
+            onDestroyed();
+        }
+
+        private void handleDispatchStartPrinterDiscovery(
+                List<RemotePrintService> services, List<PrinterId> printerIds) {
+            final int serviceCount = services.size();
+            for (int i = 0; i < serviceCount; i++) {
+                RemotePrintService service = services.get(i);
+                service.startPrinterDiscovery(printerIds);
+            }
+        }
+
+        private void handleDispatchStopPrinterDiscovery(List<RemotePrintService> services) {
+            final int serviceCount = services.size();
+            for (int i = 0; i < serviceCount; i++) {
+                RemotePrintService service = services.get(i);
+                service.stopPrinterDiscovery();
+            }
+        }
+
+        private void handleValidatePrinters(RemotePrintService service,
+                List<PrinterId> printerIds) {
+            service.validatePrinters(printerIds);
+        }
+
+        private void handleStartPrinterStateTracking(RemotePrintService service,
+                PrinterId printerId) {
+            service.startPrinterStateTracking(printerId);
+        }
+
+        private void handleStopPrinterStateTracking(RemotePrintService service,
+                PrinterId printerId) {
+            service.stopPrinterStateTracking(printerId);
+        }
+
+        private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
+            List<PrinterInfo> printers) {
+            try {
+                observer.onPrintersAdded(new ParceledListSlice<PrinterInfo>(printers));
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending added printers", re);
+            }
+        }
+
+        private void handlePrintersRemoved(IPrinterDiscoveryObserver observer,
+            List<PrinterId> printerIds) {
+            try {
+                observer.onPrintersRemoved(new ParceledListSlice<PrinterId>(printerIds));
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending removed printers", re);
+            }
+        }
+
+        private final class SessionHandler extends Handler {
+            public static final int MSG_PRINTERS_ADDED = 1;
+            public static final int MSG_PRINTERS_REMOVED = 2;
+            public static final int MSG_DISPATCH_PRINTERS_ADDED = 3;
+            public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
+
+            public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
+            public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
+            public static final int MSG_START_PRINTER_DISCOVERY = 7;
+            public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
+            public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
+            public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
+            public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
+            public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
+            public static final int MSG_VALIDATE_PRINTERS = 13;
+            public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
+            public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
+            public static final int MSG_DESTROY_SERVICE = 16;
+
+            SessionHandler(Looper looper) {
+                super(looper, null, false);
+            }
+
+            @Override
+            @SuppressWarnings("unchecked")
+            public void handleMessage(Message message) {
+                switch (message.what) {
+                    case MSG_PRINTERS_ADDED: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
+                        List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2;
+                        args.recycle();
+                        handlePrintersAdded(observer, addedPrinters);
+                    } break;
+
+                    case MSG_PRINTERS_REMOVED: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
+                        List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2;
+                        args.recycle();
+                        handlePrintersRemoved(observer, removedPrinterIds);
+                    }
+
+                    case MSG_DISPATCH_PRINTERS_ADDED: {
+                        List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj;
+                        handleDispatchPrintersAdded(addedPrinters);
+                    } break;
+
+                    case MSG_DISPATCH_PRINTERS_REMOVED: {
+                        List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj;
+                        handleDispatchPrintersRemoved(removedPrinterIds);
+                    } break;
+
+                    case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.createPrinterDiscoverySession();
+                    } break;
+
+                    case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.destroyPrinterDiscoverySession();
+                    } break;
+
+                    case MSG_START_PRINTER_DISCOVERY: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.startPrinterDiscovery(null);
+                    } break;
+
+                    case MSG_STOP_PRINTER_DISCOVERY: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.stopPrinterDiscovery();
+                    } break;
+
+                    case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
+                        List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
+                        handleDispatchCreatePrinterDiscoverySession(services);
+                    } break;
+
+                    case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: {
+                        List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
+                        handleDispatchDestroyPrinterDiscoverySession(services);
+                    } break;
+
+                    case MSG_DISPATCH_START_PRINTER_DISCOVERY: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        List<RemotePrintService> services = (List<RemotePrintService>) args.arg1;
+                        List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
+                        args.recycle();
+                        handleDispatchStartPrinterDiscovery(services, printerIds);
+                    } break;
+
+                    case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: {
+                        List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
+                        handleDispatchStopPrinterDiscovery(services);
+                    } break;
+
+                    case MSG_VALIDATE_PRINTERS: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        RemotePrintService service = (RemotePrintService) args.arg1;
+                        List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
+                        args.recycle();
+                        handleValidatePrinters(service, printerIds);
+                    } break;
+
+                    case MSG_START_PRINTER_STATE_TRACKING: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        RemotePrintService service = (RemotePrintService) args.arg1;
+                        PrinterId printerId = (PrinterId) args.arg2;
+                        args.recycle();
+                        handleStartPrinterStateTracking(service, printerId);
+                    } break;
+
+                    case MSG_STOP_PRINTER_STATE_TRACKING: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        RemotePrintService service = (RemotePrintService) args.arg1;
+                        PrinterId printerId = (PrinterId) args.arg2;
+                        args.recycle();
+                        handleStopPrinterStateTracking(service, printerId);
+                    } break;
+
+                    case MSG_DESTROY_SERVICE: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.destroy();
+                    } break;
+                }
+            }
+        }
+    }
+
+    private final class PrintJobForAppCache {
+        private final SparseArray<List<PrintJobInfo>> mPrintJobsForRunningApp =
+                new SparseArray<List<PrintJobInfo>>();
+
+        public boolean onPrintJobCreated(final IBinder creator, final int appId,
+                PrintJobInfo printJob) {
+            try {
+                creator.linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        creator.unlinkToDeath(this, 0);
+                        synchronized (mLock) {
+                            mPrintJobsForRunningApp.remove(appId);
+                        }
+                    }
+                }, 0);
+            } catch (RemoteException re) {
+                /* The process is already dead - we just failed. */
+                return false;
+            }
+            synchronized (mLock) {
+                List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId);
+                if (printJobsForApp == null) {
+                    printJobsForApp = new ArrayList<PrintJobInfo>();
+                    mPrintJobsForRunningApp.put(appId, printJobsForApp);
+                }
+                printJobsForApp.add(printJob);
+            }
+            return true;
+        }
+
+        public void onPrintJobStateChanged(PrintJobInfo printJob) {
+            synchronized (mLock) {
+                List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(
+                        printJob.getAppId());
+                if (printJobsForApp == null) {
+                    return;
+                }
+                final int printJobCount = printJobsForApp.size();
+                for (int i = 0; i < printJobCount; i++) {
+                    PrintJobInfo oldPrintJob = printJobsForApp.get(i);
+                    if (oldPrintJob.getId().equals(printJob.getId())) {
+                        printJobsForApp.set(i, printJob);
+                    }
+                }
+            }
+        }
+
+        public PrintJobInfo getPrintJob(PrintJobId printJobId, int appId) {
+            synchronized (mLock) {
+                List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId);
+                if (printJobsForApp == null) {
+                    return null;
+                }
+                final int printJobCount = printJobsForApp.size();
+                for (int i = 0; i < printJobCount; i++) {
+                    PrintJobInfo printJob = printJobsForApp.get(i);
+                    if (printJob.getId().equals(printJobId)) {
+                        return printJob;
+                    }
+                }
+            }
+            return null;
+        }
+
+        public List<PrintJobInfo> getPrintJobs(int appId) {
+            synchronized (mLock) {
+                List<PrintJobInfo> printJobs = null;
+                if (appId == PrintManager.APP_ID_ANY) {
+                    final int bucketCount = mPrintJobsForRunningApp.size();
+                    for (int i = 0; i < bucketCount; i++) {
+                        List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
+                        if (printJobs == null) {
+                            printJobs = new ArrayList<PrintJobInfo>();
+                        }
+                        printJobs.addAll(bucket);
+                    }
+                } else {
+                    List<PrintJobInfo> bucket = mPrintJobsForRunningApp.get(appId);
+                    if (bucket != null) {
+                        if (printJobs == null) {
+                            printJobs = new ArrayList<PrintJobInfo>();
+                        }
+                        printJobs.addAll(bucket);
+                    }
+                }
+                if (printJobs != null) {
+                    return printJobs;
+                }
+                return Collections.emptyList();
+            }
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            synchronized (mLock) {
+                String tab = "  ";
+                final int bucketCount = mPrintJobsForRunningApp.size();
+                for (int i = 0; i < bucketCount; i++) {
+                    final int appId = mPrintJobsForRunningApp.keyAt(i);
+                    pw.append(prefix).append("appId=" + appId).append(':').println();
+                    List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
+                    final int printJobCount = bucket.size();
+                    for (int j = 0; j < printJobCount; j++) {
+                        PrintJobInfo printJob = bucket.get(j);
+                        pw.append(prefix).append(tab).append(printJob.toString()).println();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
index 9185903..0b54f92 100644
--- a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
+++ b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
@@ -21,7 +21,8 @@
 public class IntentFirewallInstallReceiver extends ConfigUpdateInstallReceiver {
 
     public IntentFirewallInstallReceiver() {
-        super(IntentFirewall.getRulesFile().getParent(), IntentFirewall.getRulesFile().getName(),
-                "metadata/", "version");
+        // TODO: should we dynamically generate a filename and store the name in metadata?
+        super(IntentFirewall.getRulesDir().getAbsolutePath(), "ifw.xml", "metadata/",
+                "gservices.version");
     }
 }
diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/java/com/android/server/usb/UsbDebuggingManager.java
index 93d3114..ce953a4 100644
--- a/services/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/java/com/android/server/usb/UsbDebuggingManager.java
@@ -22,15 +22,14 @@
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Process;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.util.Base64;
+import com.android.server.FgThread;
 
 import java.lang.Thread;
 import java.io.File;
@@ -54,7 +53,6 @@
 
     private final Context mContext;
     private final Handler mHandler;
-    private final HandlerThread mHandlerThread;
     private Thread mThread;
     private boolean mAdbEnabled = false;
     private String mFingerprints;
@@ -62,9 +60,7 @@
     private OutputStream mOutputStream = null;
 
     public UsbDebuggingManager(Context context) {
-        mHandlerThread = new HandlerThread("UsbDebuggingHandler");
-        mHandlerThread.start();
-        mHandler = new UsbDebuggingHandler(mHandlerThread.getLooper());
+        mHandler = new UsbDebuggingHandler(FgThread.get().getLooper());
         mContext = context;
     }
 
@@ -165,7 +161,7 @@
 
                     mAdbEnabled = true;
 
-                    mThread = new Thread(UsbDebuggingManager.this);
+                    mThread = new Thread(UsbDebuggingManager.this, TAG);
                     mThread.start();
 
                     break;
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 87aa8cce..5a60de0 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -32,11 +32,9 @@
 import android.hardware.usb.UsbManager;
 import android.os.FileUtils;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
-import android.os.Process;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
@@ -48,6 +46,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.FgThread;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -57,6 +56,7 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Scanner;
 
@@ -158,11 +158,7 @@
 
         readOemUsbOverrideConfig();
 
-        // create a thread for our Handler
-        HandlerThread thread = new HandlerThread("UsbDeviceManager",
-                Process.THREAD_PRIORITY_BACKGROUND);
-        thread.start();
-        mHandler = new UsbHandler(thread.getLooper());
+        mHandler = new UsbHandler(FgThread.get().getLooper());
 
         if (nativeIsStartRequested()) {
             if (DEBUG) Slog.d(TAG, "accessory attached at boot");
@@ -245,7 +241,7 @@
         for (int i = 0; i < serialLength; i++) {
             address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
         }
-        String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
+        String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
             address[0], address[1], address[2], address[3], address[4], address[5]);
         try {
             FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index a70978e..f93a45b 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -25,18 +25,20 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateMachine;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiWatchdogStateMachine;
 import android.net.DhcpInfo;
 import android.net.DhcpResults;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.BatchedScanResult;
+import android.net.wifi.BatchedScanSettings;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiStateMachine;
+import android.net.wifi.WifiWatchdogStateMachine;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Messenger;
@@ -48,16 +50,24 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.os.AsyncTask;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
 
+import java.io.FileNotFoundException;
+import java.io.BufferedReader;
 import java.io.FileDescriptor;
+import java.io.FileReader;
+import java.io.IOException;
 import java.io.PrintWriter;
+
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import com.android.internal.R;
@@ -114,6 +124,8 @@
     /* Tracks the persisted states for wi-fi & airplane mode */
     final WifiSettingsStore mSettingsStore;
 
+    final boolean mBatchedScanSupported;
+
     /**
      * Asynchronous channel to WifiStateMachine
      */
@@ -158,7 +170,26 @@
                 }
                 /* Client commands are forwarded to state machine */
                 case WifiManager.CONNECT_NETWORK:
-                case WifiManager.SAVE_NETWORK:
+                case WifiManager.SAVE_NETWORK: {
+                    WifiConfiguration config = (WifiConfiguration) msg.obj;
+                    int networkId = msg.arg1;
+                    if (config != null && config.isValid()) {
+                        if (DBG) Slog.d(TAG, "Connect with config" + config);
+                        mWifiStateMachine.sendMessage(Message.obtain(msg));
+                    } else if (config == null
+                            && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+                        if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
+                        mWifiStateMachine.sendMessage(Message.obtain(msg));
+                    } else {
+                        Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
+                        if (msg.what == WifiManager.CONNECT_NETWORK) {
+                            replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
+                        } else {
+                            replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED);
+                        }
+                    }
+                    break;
+                }
                 case WifiManager.FORGET_NETWORK:
                 case WifiManager.START_WPS:
                 case WifiManager.CANCEL_WPS:
@@ -173,6 +204,17 @@
                 }
             }
         }
+
+        private void replyFailed(Message msg, int what) {
+            Message reply = msg.obtain();
+            reply.what = what;
+            reply.arg1 = WifiManager.INVALID_ARGS;
+            try {
+                msg.replyTo.send(reply);
+            } catch (RemoteException e) {
+                // There's not much we can do if reply can't be sent!
+            }
+        }
     }
     private ClientHandler mClientHandler;
 
@@ -239,6 +281,9 @@
         mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
         mWifiController.start();
 
+        mBatchedScanSupported = mContext.getResources().getBoolean(
+                R.bool.config_wifi_batched_scan_supported);
+
         registerForScanModeChange();
         mContext.registerReceiver(
                 new BroadcastReceiver() {
@@ -296,10 +341,164 @@
 
     /**
      * see {@link android.net.wifi.WifiManager#startScan()}
+     *
+     * <p>If workSource is null, all blame is given to the calling uid.
      */
-    public void startScan() {
+    public void startScan(WorkSource workSource) {
         enforceChangePermission();
-        mWifiStateMachine.startScan(Binder.getCallingUid());
+        if (workSource != null) {
+            enforceWorkSourcePermission();
+            // WifiManager currently doesn't use names, so need to clear names out of the
+            // supplied WorkSource to allow future WorkSource combining.
+            workSource.clearNames();
+        }
+        mWifiStateMachine.startScan(Binder.getCallingUid(), workSource);
+    }
+
+    private class BatchedScanRequest extends DeathRecipient {
+        BatchedScanSettings settings;
+        int uid;
+        int pid;
+
+        BatchedScanRequest(BatchedScanSettings settings, IBinder binder) {
+            super(0, null, binder, null);
+            this.settings = settings;
+            this.uid = getCallingUid();
+            this.pid = getCallingPid();
+        }
+        public void binderDied() {
+            stopBatchedScan(settings, uid, pid);
+        }
+        public String toString() {
+            return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}";
+        }
+
+        public boolean isSameApp(int uid, int pid) {
+            return (this.uid == uid && this.pid == pid);
+        }
+    }
+
+    private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>();
+
+    public boolean isBatchedScanSupported() {
+        return mBatchedScanSupported;
+    }
+
+    public void pollBatchedScan() {
+        enforceChangePermission();
+        if (mBatchedScanSupported == false) return;
+        mWifiStateMachine.requestBatchedScanPoll();
+    }
+
+    /**
+     * see {@link android.net.wifi.WifiManager#requestBatchedScan()}
+     */
+    public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder) {
+        enforceChangePermission();
+        if (mBatchedScanSupported == false) return false;
+        requested = new BatchedScanSettings(requested);
+        if (requested.isInvalid()) return false;
+        BatchedScanRequest r = new BatchedScanRequest(requested, binder);
+        synchronized(mBatchedScanners) {
+            mBatchedScanners.add(r);
+            resolveBatchedScannersLocked();
+        }
+        return true;
+    }
+
+    public List<BatchedScanResult> getBatchedScanResults(String callingPackage) {
+        enforceAccessPermission();
+        if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>();
+        int userId = UserHandle.getCallingUserId();
+        int uid = Binder.getCallingUid();
+        long ident = Binder.clearCallingIdentity();
+        try {
+            if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
+                    != AppOpsManager.MODE_ALLOWED) {
+                return new ArrayList<BatchedScanResult>();
+            }
+            int currentUser = ActivityManager.getCurrentUser();
+            if (userId != currentUser) {
+                return new ArrayList<BatchedScanResult>();
+            } else {
+                return mWifiStateMachine.syncGetBatchedScanResultsList();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+
+    public void stopBatchedScan(BatchedScanSettings settings) {
+        enforceChangePermission();
+        if (mBatchedScanSupported == false) return;
+        stopBatchedScan(settings, getCallingUid(), getCallingPid());
+    }
+
+    private void stopBatchedScan(BatchedScanSettings settings, int uid, int pid) {
+        ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>();
+        synchronized(mBatchedScanners) {
+            for (BatchedScanRequest r : mBatchedScanners) {
+                if (r.isSameApp(uid, pid) && (settings == null || settings.equals(r.settings))) {
+                    found.add(r);
+                    if (settings != null) break;
+                }
+            }
+            for (BatchedScanRequest r : found) {
+                mBatchedScanners.remove(r);
+            }
+            if (found.size() != 0) {
+                resolveBatchedScannersLocked();
+            }
+        }
+    }
+
+    private void resolveBatchedScannersLocked() {
+        BatchedScanSettings setting = new BatchedScanSettings();
+        int responsibleUid = 0;
+
+        if (mBatchedScanners.size() == 0) {
+            mWifiStateMachine.setBatchedScanSettings(null, 0);
+            return;
+        }
+        for (BatchedScanRequest r : mBatchedScanners) {
+            BatchedScanSettings s = r.settings;
+            if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
+                    s.maxScansPerBatch < setting.maxScansPerBatch) {
+                setting.maxScansPerBatch = s.maxScansPerBatch;
+                responsibleUid = r.uid;
+            }
+            if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
+                    (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
+                    s.maxApPerScan > setting.maxApPerScan)) {
+                setting.maxApPerScan = s.maxApPerScan;
+            }
+            if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
+                    s.scanIntervalSec < setting.scanIntervalSec) {
+                setting.scanIntervalSec = s.scanIntervalSec;
+                responsibleUid = r.uid;
+            }
+            if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
+                    (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
+                    s.maxApForDistance > setting.maxApForDistance)) {
+                setting.maxApForDistance = s.maxApForDistance;
+            }
+            if (s.channelSet != null && s.channelSet.size() != 0) {
+                if (setting.channelSet == null || setting.channelSet.size() != 0) {
+                    if (setting.channelSet == null) setting.channelSet = new ArrayList<String>();
+                    for (String i : s.channelSet) {
+                        if (setting.channelSet.contains(i) == false) setting.channelSet.add(i);
+                    }
+                } // else, ignore the constraint - we already use all channels
+            } else {
+                if (setting.channelSet == null || setting.channelSet.size() != 0) {
+                    setting.channelSet = new ArrayList<String>();
+                }
+            }
+        }
+
+        setting.constrain();
+        mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid);
     }
 
     private void enforceAccessPermission() {
@@ -313,6 +512,12 @@
 
     }
 
+    private void enforceWorkSourcePermission() {
+        mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
+                                                "WifiService");
+
+    }
+
     private void enforceMulticastChangePermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
@@ -379,7 +584,12 @@
      */
     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
         enforceChangePermission();
-        mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
+        // null wifiConfig is a meaningful input for CMD_SET_AP
+        if (wifiConfig == null || wifiConfig.isValid()) {
+            mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
+        } else {
+            Slog.e(TAG, "Invalid WifiConfiguration");
+        }
     }
 
     /**
@@ -412,7 +622,11 @@
         enforceChangePermission();
         if (wifiConfig == null)
             return;
-        mWifiStateMachine.setWifiApConfiguration(wifiConfig);
+        if (wifiConfig.isValid()) {
+            mWifiStateMachine.setWifiApConfiguration(wifiConfig);
+        } else {
+            Slog.e(TAG, "Invalid WifiConfiguration");
+        }
     }
 
     /**
@@ -470,10 +684,15 @@
      */
     public int addOrUpdateNetwork(WifiConfiguration config) {
         enforceChangePermission();
-        if (mWifiStateMachineChannel != null) {
-            return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
+        if (config.isValid()) {
+            if (mWifiStateMachineChannel != null) {
+                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
+            } else {
+                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+                return -1;
+            }
         } else {
-            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+            Slog.e(TAG, "bad network configuration");
             return -1;
         }
     }
@@ -551,11 +770,11 @@
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
-        if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
-            return new ArrayList<ScanResult>();
-        }
         try {
+            if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
+                    != AppOpsManager.MODE_ALLOWED) {
+                return new ArrayList<ScanResult>();
+            }
             int currentUser = ActivityManager.getCurrentUser();
             if (userId != currentUser) {
                 return new ArrayList<ScanResult>();
@@ -749,6 +968,92 @@
     }
 
     /**
+     * enable TDLS for the local NIC to remote NIC
+     * The APPs don't know the remote MAC address to identify NIC though,
+     * so we need to do additional work to find it from remote IP address
+     */
+
+    class TdlsTaskParams {
+        public String remoteIpAddress;
+        public boolean enable;
+    }
+
+    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
+        @Override
+        protected Integer doInBackground(TdlsTaskParams... params) {
+
+            // Retrieve parameters for the call
+            TdlsTaskParams param = params[0];
+            String remoteIpAddress = param.remoteIpAddress.trim();
+            boolean enable = param.enable;
+
+            // Get MAC address of Remote IP
+            String macAddress = null;
+
+            BufferedReader reader = null;
+
+            try {
+                reader = new BufferedReader(new FileReader("/proc/net/arp"));
+
+                // Skip over the line bearing colum titles
+                String line = reader.readLine();
+
+                while ((line = reader.readLine()) != null) {
+                    String[] tokens = line.split("[ ]+");
+                    if (tokens.length < 6) {
+                        continue;
+                    }
+
+                    // ARP column format is
+                    // Address HWType HWAddress Flags Mask IFace
+                    String ip = tokens[0];
+                    String mac = tokens[3];
+
+                    if (remoteIpAddress.equals(ip)) {
+                        macAddress = mac;
+                        break;
+                    }
+                }
+
+                if (macAddress == null) {
+                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
+                            "/proc/net/arp");
+                } else {
+                    enableTdlsWithMacAddress(macAddress, enable);
+                }
+
+            } catch (FileNotFoundException e) {
+                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
+            } catch (IOException e) {
+                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
+            } finally {
+                try {
+                    if (reader != null) {
+                        reader.close();
+                    }
+                }
+                catch (IOException e) {
+                    // Do nothing
+                }
+            }
+
+            return 0;
+        }
+    }
+
+    public void enableTdls(String remoteAddress, boolean enable) {
+        TdlsTaskParams params = new TdlsTaskParams();
+        params.remoteIpAddress = remoteAddress;
+        params.enable = enable;
+        new TdlsTask().execute(params);
+    }
+
+
+    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
+        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
+    }
+
+    /**
      * Get a reference to handler. This is used by a client to establish
      * an AsyncChannel communication with WifiService
      */
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 6293dc6..3cccf1d 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -6,7 +6,6 @@
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.Display;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index fbb5013..8cc1d02 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -30,6 +30,10 @@
 import android.view.WindowManager;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+
+class AppTokenList extends ArrayList<AppWindowToken> {
+}
 
 /**
  * Version of WindowToken that is specifically for a particular application (or
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index 774b165..5aa266d 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -22,7 +22,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.util.Slog;
-import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
@@ -37,7 +37,7 @@
         final SurfaceControl surface;
 
         BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b, int layerStack)
-                throws SurfaceControl.OutOfResourcesException {
+                throws OutOfResourcesException {
             left = l;
             top = t;
             this.layer = layer;
@@ -62,6 +62,10 @@
                             "  BLACK " + surface + ": CREATE layer=" + layer);
         }
 
+        void setAlpha(float alpha) {
+            surface.setAlpha(alpha);
+        }
+
         void setMatrix(Matrix matrix) {
             mTmpMatrix.setTranslate(left, top);
             mTmpMatrix.postConcat(matrix);
@@ -93,6 +97,8 @@
     final float[] mTmpFloats = new float[9];
     final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
 
+    final boolean mForceDefaultOrientation;
+
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("Outer: "); mOuterRect.printShortString(pw);
                 pw.print(" / Inner: "); mInnerRect.printShortString(pw);
@@ -106,10 +112,12 @@
         }
     }
 
-    public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
-            int layer, final int layerStack) throws SurfaceControl.OutOfResourcesException {
+    public BlackFrame(SurfaceSession session, Rect outer, Rect inner, int layer, int layerStack,
+            boolean forceDefaultOrientation) throws OutOfResourcesException {
         boolean success = false;
 
+        mForceDefaultOrientation = forceDefaultOrientation;
+
         mOuterRect = new Rect(outer);
         mInnerRect = new Rect(inner);
         try {
@@ -162,6 +170,14 @@
         }
     }
 
+    public void setAlpha(float alpha) {
+        for (int i=0; i<mBlackSurfaces.length; i++) {
+            if (mBlackSurfaces[i] != null) {
+                mBlackSurfaces[i].setAlpha(alpha);
+            }
+        }
+    }
+
     public void setMatrix(Matrix matrix) {
         for (int i=0; i<mBlackSurfaces.length; i++) {
             if (mBlackSurfaces[i] != null) {
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/java/com/android/server/wm/DimLayer.java
index 9bd36ba..39e664f 100644
--- a/services/java/com/android/server/wm/DimLayer.java
+++ b/services/java/com/android/server/wm/DimLayer.java
@@ -3,10 +3,10 @@
 package com.android.server.wm;
 
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.DisplayInfo;
-import android.view.Surface;
 import android.view.SurfaceControl;
 
 import java.io.PrintWriter;
@@ -27,8 +27,11 @@
     /** Last value passed to mDimSurface.setLayer() */
     int mLayer = -1;
 
-    /** Last values passed to mDimSurface.setSize() */
-    int mLastDimWidth, mLastDimHeight;
+    /** Next values to pass to mDimSurface.setPosition() and mDimSurface.setSize() */
+    Rect mBounds = new Rect();
+
+    /** Last values passed to mDimSurface.setPosition() and mDimSurface.setSize() */
+    Rect mLastBounds = new Rect();
 
     /** True after mDimSurface.show() has been called, false after mDimSurface.hide(). */
     private boolean mShowing = false;
@@ -45,9 +48,10 @@
     /** Time in milliseconds to take to transition from mStartAlpha to mTargetAlpha */
     long mDuration;
 
-    DimLayer(WindowManagerService service, int displayId) {
+    DimLayer(WindowManagerService service, DisplayContent displayContent) {
+        mDisplayContent = displayContent;
+        final int displayId = displayContent.getDisplayId();
         if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
-        mDisplayContent = service.getDisplayContentLocked(displayId);
         SurfaceControl.openTransaction();
         try {
             if (WindowManagerService.DEBUG_SURFACE_TRACE) {
@@ -117,6 +121,10 @@
         }
     }
 
+    void setBounds(Rect bounds) {
+        mBounds.set(bounds);
+    }
+
     /**
      * @param duration The time to test.
      * @return True if the duration would lead to an earlier end to the current animation.
@@ -152,6 +160,7 @@
             return;
         }
 
+        /*
         // Set surface size to screen size.
         final DisplayInfo info = mDisplayContent.getDisplayInfo();
         // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
@@ -161,17 +170,17 @@
         // back off position so 1/4 of Surface is before and 1/4 is after.
         final float xPos = -1 * dw / 6;
         final float yPos = -1 * dh / 6;
+        */
 
-        if (mLastDimWidth != dw || mLastDimHeight != dh || mLayer != layer) {
+        if (!mLastBounds.equals(mBounds) || mLayer != layer) {
             try {
-                mDimSurface.setPosition(xPos, yPos);
-                mDimSurface.setSize(dw, dh);
+                mDimSurface.setPosition(mBounds.left, mBounds.top);
+                mDimSurface.setSize(mBounds.width(), mBounds.height());
                 mDimSurface.setLayer(layer);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Failure setting size or layer", e);
             }
-            mLastDimWidth = dw;
-            mLastDimHeight = dh;
+            mLastBounds.set(mBounds);
             mLayer = layer;
         }
 
@@ -255,15 +264,16 @@
     }
 
     public void printTo(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mDimSurface="); pw.println(mDimSurface);
-        pw.print(prefix); pw.print(" mLayer="); pw.print(mLayer);
+        pw.print(prefix); pw.print("mDimSurface="); pw.print(mDimSurface);
+                pw.print(" mLayer="); pw.print(mLayer);
                 pw.print(" mAlpha="); pw.println(mAlpha);
-        pw.print(prefix); pw.print("mLastDimWidth="); pw.print(mLastDimWidth);
-                pw.print(" mLastDimWidth="); pw.println(mLastDimWidth);
-        pw.print(prefix); pw.print("Last animation: mStartTime="); pw.print(mStartTime);
+        pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString());
+                pw.print(" mBounds="); pw.println(mBounds.toShortString());
+        pw.print(prefix); pw.print("Last animation: ");
                 pw.print(" mDuration="); pw.print(mDuration);
+                pw.print(" mStartTime="); pw.print(mStartTime);
                 pw.print(" curTime="); pw.println(SystemClock.uptimeMillis());
-        pw.print(" mStartAlpha="); pw.println(mStartAlpha);
-                pw.print(" mTargetAlpha="); pw.print(mTargetAlpha);
+        pw.print(prefix); pw.print(" mStartAlpha="); pw.print(mStartAlpha);
+                pw.print(" mTargetAlpha="); pw.println(mTargetAlpha);
     }
 }
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 59e4b0e..2798104 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,6 +16,15 @@
 
 package com.android.server.wm;
 
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.TAG;
+
+import android.app.ActivityManager.StackBoxInfo;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
 
@@ -61,19 +70,66 @@
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
     private final Display mDisplay;
 
+    Rect mBaseDisplayRect = new Rect();
+
     // Accessed directly by all users.
     boolean layoutNeeded;
     int pendingLayoutChanges;
     final boolean isDefaultDisplay;
 
     /**
-     * @param display May not be null.
+     * Window tokens that are in the process of exiting, but still
+     * on screen for animations.
      */
-    DisplayContent(Display display) {
+    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
+
+    /**
+     * Application tokens that are in the process of exiting, but still
+     * on screen for animations.
+     */
+    final AppTokenList mExitingAppTokens = new AppTokenList();
+
+    /** Array containing the home StackBox and possibly one more which would contain apps. Array
+     * is stored in display order with the current bottom stack at 0. */
+    private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
+
+    /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
+    private TaskStack mHomeStack = null;
+
+    /** Sorted most recent at top, oldest at [0]. */
+    ArrayList<TaskStack> mStackHistory = new ArrayList<TaskStack>();
+
+    /** Detect user tapping outside of current focused stack bounds .*/
+    StackTapPointerEventListener mTapDetector;
+
+    /** Detect user tapping outside of current focused stack bounds .*/
+    Region mTouchExcludeRegion = new Region();
+
+    /** Save allocating when retrieving tasks */
+    ArrayList<Task> mTmpTasks = new ArrayList<Task>();
+
+    /** Save allocating when calculating rects */
+    Rect mTmpRect = new Rect();
+
+    final WindowManagerService mService;
+
+    /**
+     * @param display May not be null.
+     * @param service TODO(cmautner):
+     */
+    DisplayContent(Display display, WindowManagerService service) {
         mDisplay = display;
         mDisplayId = display.getDisplayId();
         display.getDisplayInfo(mDisplayInfo);
         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
+        mService = service;
+
+        StackBox newBox = new StackBox(service, this, null);
+        mStackBoxes.add(newBox);
+        TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);
+        newStack.mStackBox = newBox;
+        newBox.mStack = newStack;
+        mHomeStack = newStack;
     }
 
     int getDisplayId() {
@@ -92,10 +148,292 @@
         return mDisplayInfo;
     }
 
-    public void updateDisplayInfo() {
+    /**
+     * Returns true if the specified UID has access to this display.
+     */
+    public boolean hasAccess(int uid) {
+        return mDisplay.hasAccess(uid);
+    }
+
+    boolean homeOnTop() {
+        return mStackBoxes.get(0).mStack != mHomeStack;
+    }
+
+    void moveStack(TaskStack stack, boolean toTop) {
+        mStackHistory.remove(stack);
+        mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
+        mService.moveStackWindowsLocked(stack);
+    }
+
+    public boolean isPrivate() {
+        return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
+    }
+
+    /**
+     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
+     * @return All the Tasks, in order, on this display.
+     */
+    ArrayList<Task> getTasks() {
+        mTmpTasks.clear();
+        final int numStacks = mStackHistory.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            mTmpTasks.addAll(mStackHistory.get(stackNdx).getTasks());
+        }
+        if (WindowManagerService.DEBUG_LAYERS) Slog.i(TAG, "getTasks: mStackHistory=" +
+                mStackHistory);
+        return mTmpTasks;
+    }
+
+    TaskStack getHomeStack() {
+        return mHomeStack;
+    }
+
+    void updateDisplayInfo() {
         mDisplay.getDisplayInfo(mDisplayInfo);
     }
 
+    void getLogicalDisplayRect(Rect out) {
+        updateDisplayInfo();
+        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
+        int width = mDisplayInfo.logicalWidth;
+        int left = (mBaseDisplayWidth - width) / 2;
+        int height = mDisplayInfo.logicalHeight;
+        int top = (mBaseDisplayHeight - height) / 2;
+        out.set(left, top, left + width, top + height);
+    }
+
+    /** @return The number of tokens in all of the Tasks on this display. */
+    int numTokens() {
+        getTasks();
+        int count = 0;
+        for (int taskNdx = mTmpTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            count += mTmpTasks.get(taskNdx).mAppTokens.size();
+        }
+        return count;
+    }
+
+    /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
+    TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {
+        TaskStack newStack = null;
+        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="
+                + relativeStackBoxId + " position=" + position + " weight=" + weight);
+        if (stackId == HOME_STACK_ID) {
+            if (mStackBoxes.size() != 1) {
+                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
+            }
+            newStack = mHomeStack;
+        } else {
+            int stackBoxNdx;
+            for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+                final StackBox box = mStackBoxes.get(stackBoxNdx);
+                if (position == StackBox.TASK_STACK_GOES_OVER
+                        || position == StackBox.TASK_STACK_GOES_UNDER) {
+                    // Position indicates a new box is added at top level only.
+                    if (box.contains(relativeStackBoxId)) {
+                        StackBox newBox = new StackBox(mService, this, null);
+                        newStack = new TaskStack(mService, stackId, this);
+                        newStack.mStackBox = newBox;
+                        newBox.mStack = newStack;
+                        final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
+                        if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +
+                                (stackBoxNdx + offset));
+                        mStackBoxes.add(stackBoxNdx + offset, newBox);
+                        break;
+                    }
+                } else {
+                    // Remaining position values indicate a box must be split.
+                    newStack = box.split(stackId, relativeStackBoxId, position, weight);
+                    if (newStack != null) {
+                        break;
+                    }
+                }
+            }
+            if (stackBoxNdx < 0) {
+                throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId
+                        + " not found.");
+            }
+        }
+        if (newStack != null) {
+            layoutNeeded = true;
+        }
+        return newStack;
+    }
+
+    /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */
+    boolean resizeStack(int stackBoxId, float weight) {
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            final StackBox box = mStackBoxes.get(stackBoxNdx);
+            if (box.resize(stackBoxId, weight)) {
+                layoutNeeded = true;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void addStackBox(StackBox box, boolean toTop) {
+        if (mStackBoxes.size() >= 2) {
+            throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!");
+        }
+        mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
+    }
+
+    void removeStackBox(StackBox box) {
+        if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box);
+        final TaskStack stack = box.mStack;
+        if (stack != null && stack.mStackId == HOME_STACK_ID) {
+            // Never delete the home stack, even if it is empty.
+            if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack.");
+            return;
+        }
+        mStackBoxes.remove(box);
+    }
+
+    StackBoxInfo getStackBoxInfo(StackBox box) {
+        StackBoxInfo info = new StackBoxInfo();
+        info.stackBoxId = box.mStackBoxId;
+        info.weight = box.mWeight;
+        info.vertical = box.mVertical;
+        info.bounds = new Rect(box.mBounds);
+        if (box.mStack != null) {
+            info.stackId = box.mStack.mStackId;
+            // ActivityManagerService will fill in the StackInfo.
+        } else {
+            info.stackId = -1;
+            info.children = new StackBoxInfo[2];
+            info.children[0] = getStackBoxInfo(box.mFirst);
+            info.children[1] = getStackBoxInfo(box.mSecond);
+        }
+        return info;
+    }
+
+    ArrayList<StackBoxInfo> getStackBoxInfos() {
+        ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
+        }
+        return list;
+    }
+
+    /**
+     * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
+     * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
+     * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false.
+     * @return true if a change was made, false otherwise.
+     */
+    boolean moveHomeStackBox(boolean toTop) {
+        if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop);
+        switch (mStackBoxes.size()) {
+            case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
+            case 1: return false; // Only the home StackBox exists.
+            case 2:
+                if (homeOnTop() ^ toTop) {
+                    mStackBoxes.add(mStackBoxes.remove(0));
+                    return true;
+                }
+                return false;
+            default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");
+        }
+    }
+
+    /**
+     * Propagate the new bounds to all child stack boxes, applying weights as we move down.
+     * @param contentRect The bounds to apply at the top level.
+     */
+    boolean setStackBoxSize(Rect contentRect) {
+        boolean change = false;
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true);
+        }
+        return change;
+    }
+
+    Rect getStackBounds(int stackId) {
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId);
+            if (bounds != null) {
+                return bounds;
+            }
+        }
+        return null;
+    }
+
+    int stackIdFromPoint(int x, int y) {
+        StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1);
+        return topBox.stackIdFromPoint(x, y);
+    }
+
+    void setTouchExcludeRegion(TaskStack focusedStack) {
+        mTouchExcludeRegion.set(mBaseDisplayRect);
+        WindowList windows = getWindowList();
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            final WindowState win = windows.get(i);
+            final TaskStack stack = win.getStack();
+            if (win.isVisibleLw() && stack != null && stack != focusedStack) {
+                mTmpRect.set(win.mVisibleFrame);
+                mTmpRect.intersect(win.mVisibleInsets);
+                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+            }
+        }
+    }
+
+    void switchUserStacks(int oldUserId, int newUserId) {
+        final WindowList windows = getWindowList();
+        for (int i = 0; i < windows.size(); i++) {
+            final WindowState win = windows.get(i);
+            if (win.isHiddenFromUserLocked()) {
+                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
+                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
+                        + win.mOwnerUid);
+                win.hideLw(false);
+            }
+        }
+
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
+        }
+    }
+
+    void resetAnimationBackgroundAnimator() {
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator();
+        }
+    }
+
+    boolean animateDimLayers() {
+        boolean result = false;
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            result |= mStackBoxes.get(stackBoxNdx).animateDimLayers();
+        }
+        return result;
+    }
+
+    void resetDimming() {
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            mStackBoxes.get(stackBoxNdx).resetDimming();
+        }
+    }
+
+    boolean isDimming() {
+        boolean result = false;
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            result |= mStackBoxes.get(stackBoxNdx).isDimming();
+        }
+        return result;
+    }
+
+    void stopDimmingIfNeeded() {
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded();
+        }
+    }
+
+    void close() {
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            mStackBoxes.get(stackBoxNdx).close();
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
         final String subPrefix = "  " + prefix;
@@ -119,7 +457,48 @@
             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-        pw.print(subPrefix); pw.print("layoutNeeded="); pw.print(layoutNeeded);
+            pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
+        for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
+            pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
+            mStackBoxes.get(boxNdx).dump(prefix + "  ", pw);
+        }
+        int ndx = numTokens();
+        if (ndx > 0) {
+            pw.println();
+            pw.println("  Application tokens in Z order:");
+            getTasks();
+            for (int taskNdx = mTmpTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                AppTokenList tokens = mTmpTasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    pw.print("  App #"); pw.print(ndx--);
+                            pw.print(' '); pw.print(wtoken); pw.println(":");
+                    wtoken.dump(pw, "    ");
+                }
+            }
+        }
+        if (mExitingTokens.size() > 0) {
+            pw.println();
+            pw.println("  Exiting tokens:");
+            for (int i=mExitingTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingTokens.get(i);
+                pw.print("  Exiting #"); pw.print(i);
+                pw.print(' '); pw.print(token);
+                pw.println(':');
+                token.dump(pw, "    ");
+            }
+        }
+        if (mExitingAppTokens.size() > 0) {
+            pw.println();
+            pw.println("  Exiting application tokens:");
+            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingAppTokens.get(i);
+                pw.print("  Exiting App #"); pw.print(i);
+                  pw.print(' '); pw.print(token);
+                  pw.println(':');
+                  token.dump(pw, "    ");
+            }
+        }
         pw.println();
     }
 }
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/java/com/android/server/wm/DisplayMagnifier.java
index 0f51028..382d7b4 100644
--- a/services/java/com/android/server/wm/DisplayMagnifier.java
+++ b/services/java/com/android/server/wm/DisplayMagnifier.java
@@ -496,7 +496,7 @@
                     mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
                     surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession, SURFACE_TITLE,
                             mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-                } catch (SurfaceControl.OutOfResourcesException oore) {
+                } catch (OutOfResourcesException oore) {
                     /* ignore */
                 }
                 mSurfaceControl = surfaceControl;
@@ -629,7 +629,7 @@
                         }
                     } catch (IllegalArgumentException iae) {
                         /* ignore */
-                    } catch (OutOfResourcesException oore) {
+                    } catch (Surface.OutOfResourcesException oore) {
                         /* ignore */
                     }
                     if (canvas == null) {
@@ -644,7 +644,7 @@
                     canvas.drawPath(path, mPaint);
 
                     mSurface.unlockCanvasAndPost(canvas);
-                    
+
                     if (mAlpha > 0) {
                         mSurfaceControl.show();
                     } else {
diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/java/com/android/server/wm/FocusedStackFrame.java
new file mode 100644
index 0000000..365b277
--- /dev/null
+++ b/services/java/com/android/server/wm/FocusedStackFrame.java
@@ -0,0 +1,142 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Surface.OutOfResourcesException;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+import com.android.server.wm.WindowStateAnimator.SurfaceTrace;
+
+class FocusedStackFrame {
+    private static final String TAG = "FocusedStackFrame";
+    private static final int THICKNESS = 10;
+    private static final float ALPHA = 0.3f;
+
+    private final SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
+    private final Rect mLastBounds = new Rect();
+    private final Rect mBounds = new Rect();
+    private final Rect mTmpDrawRect = new Rect();
+
+    public FocusedStackFrame(Display display, SurfaceSession session) {
+        SurfaceControl ctrl = null;
+        try {
+            if (DEBUG_SURFACE_TRACE) {
+                ctrl = new SurfaceTrace(session, "FocusedStackFrame",
+                    1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            } else {
+                ctrl = new SurfaceControl(session, "FocusedStackFrame",
+                    1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            }
+            ctrl.setLayerStack(display.getLayerStack());
+            ctrl.setAlpha(ALPHA);
+            mSurface.copyFrom(ctrl);
+        } catch (OutOfResourcesException e) {
+        }
+        mSurfaceControl = ctrl;
+    }
+
+    private void draw(Rect bounds, int color) {
+        if (DEBUG_STACK) Slog.i(TAG, "draw: bounds=" + bounds.toShortString() +
+                " color=" + Integer.toHexString(color));
+        mTmpDrawRect.set(bounds);
+        Canvas c = null;
+        try {
+            c = mSurface.lockCanvas(mTmpDrawRect);
+        } catch (IllegalArgumentException e) {
+        } catch (Surface.OutOfResourcesException e) {
+        }
+        if (c == null) {
+            return;
+        }
+
+        final int w = bounds.width();
+        final int h = bounds.height();
+
+        // Top
+        mTmpDrawRect.set(0, 0, w, THICKNESS);
+        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+        c.drawColor(color);
+        // Left (not including Top or Bottom stripe).
+        mTmpDrawRect.set(0, THICKNESS, THICKNESS, h - THICKNESS);
+        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+        c.drawColor(color);
+        // Right (not including Top or Bottom stripe).
+        mTmpDrawRect.set(w - THICKNESS, THICKNESS, w, h - THICKNESS);
+        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+        c.drawColor(color);
+        // Bottom
+        mTmpDrawRect.set(0, h - THICKNESS, w, h);
+        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+        c.drawColor(color);
+
+        mSurface.unlockCanvasAndPost(c);
+    }
+
+    private void positionSurface(Rect bounds) {
+        if (DEBUG_STACK) Slog.i(TAG, "positionSurface: bounds=" + bounds.toShortString());
+        mSurfaceControl.setSize(bounds.width(), bounds.height());
+        mSurfaceControl.setPosition(bounds.left, bounds.top);
+    }
+
+    // Note: caller responsible for being inside
+    // Surface.openTransaction() / closeTransaction()
+    public void setVisibility(boolean on) {
+        if (DEBUG_STACK) Slog.i(TAG, "setVisibility: on=" + on +
+                " mLastBounds=" + mLastBounds.toShortString() +
+                " mBounds=" + mBounds.toShortString());
+        if (mSurfaceControl == null) {
+            return;
+        }
+        if (on) {
+            if (!mLastBounds.equals(mBounds)) {
+                // Erase the previous rectangle.
+                positionSurface(mLastBounds);
+                draw(mLastBounds, Color.TRANSPARENT);
+                // Draw the latest rectangle.
+                positionSurface(mBounds);
+                draw(mBounds, Color.WHITE);
+                // Update the history.
+                mLastBounds.set(mBounds);
+            }
+            mSurfaceControl.show();
+        } else {
+            mSurfaceControl.hide();
+        }
+    }
+
+    public void setBounds(Rect bounds) {
+        if (DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + bounds);
+        mBounds.set(bounds);
+    }
+
+    public void setLayer(int layer) {
+        mSurfaceControl.setLayer(layer);
+    }
+}
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 0e36032..2e13fe2 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -66,6 +66,7 @@
      * 
      * Called by the InputManager.
      */
+    @Override
     public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
         if (inputWindowHandle == null) {
             return;
@@ -85,8 +86,9 @@
      * 
      * Called by the InputManager.
      */
+    @Override
     public long notifyANR(InputApplicationHandle inputApplicationHandle,
-            InputWindowHandle inputWindowHandle) {
+            InputWindowHandle inputWindowHandle, String reason) {
         AppWindowToken appWindowToken = null;
         WindowState windowState = null;
         boolean aboveSystem = false;
@@ -103,7 +105,8 @@
 
             if (windowState != null) {
                 Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
-                        + "sending to " + windowState.mAttrs.getTitle());
+                        + "sending to " + windowState.mAttrs.getTitle()
+                        + ".  Reason: " + reason);
                 // Figure out whether this window is layered above system windows.
                 // We need to do this here to help the activity manager know how to
                 // layer its ANR dialog.
@@ -112,19 +115,21 @@
                 aboveSystem = windowState.mBaseLayer > systemAlertLayer;
             } else if (appWindowToken != null) {
                 Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
-                        + "sending to application " + appWindowToken.stringName);
+                        + "sending to application " + appWindowToken.stringName
+                        + ".  Reason: " + reason);
             } else {
-                Slog.i(WindowManagerService.TAG, "Input event dispatching timed out.");
+                Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+                        + ".  Reason: " + reason);
             }
 
-            mService.saveANRStateLocked(appWindowToken, windowState);
+            mService.saveANRStateLocked(appWindowToken, windowState, reason);
         }
 
         if (appWindowToken != null && appWindowToken.appToken != null) {
             try {
                 // Notify the activity manager about the timeout and let it decide whether
                 // to abort dispatching or keep waiting.
-                boolean abort = appWindowToken.appToken.keyDispatchingTimedOut();
+                boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
                 if (! abort) {
                     // The activity manager declined to abort dispatching.
                     // Wait a bit longer and timeout again later.
@@ -137,7 +142,7 @@
                 // Notify the activity manager about the timeout and let it decide whether
                 // to abort dispatching or keep waiting.
                 long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
-                        windowState.mSession.mPid, aboveSystem);
+                        windowState.mSession.mPid, aboveSystem, reason);
                 if (timeout >= 0) {
                     // The activity manager declined to abort dispatching.
                     // Wait a bit longer and timeout again later.
@@ -161,10 +166,20 @@
     }
 
     private void addInputWindowHandleLw(final InputWindowHandle inputWindowHandle,
-            final WindowState child, final int flags, final int type,
+            final WindowState child, int flags, final int type,
             final boolean isVisible, final boolean hasFocus, final boolean hasWallpaper) {
         // Add a window to our list of input windows.
         inputWindowHandle.name = child.toString();
+        final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) == 0;
+        if (modal && child.mAppToken != null) {
+            // Limit the outer touch to the activity stack region.
+            flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            inputWindowHandle.touchableRegion.set(child.getStackBounds());
+        } else {
+            // Not modal or full screen modal
+            child.getTouchableRegion(inputWindowHandle.touchableRegion);
+        }
         inputWindowHandle.layoutParamsFlags = flags;
         inputWindowHandle.layoutParamsType = type;
         inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
@@ -193,7 +208,6 @@
             inputWindowHandle.scaleFactor = 1;
         }
 
-        child.getTouchableRegion(inputWindowHandle.touchableRegion);
 
         addInputWindowHandleLw(inputWindowHandle);
     }
@@ -249,8 +263,7 @@
         // Add all windows on the default display.
         final int numDisplays = mService.mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final WindowList windows =
-                    mService.mDisplayContents.valueAt(displayNdx).getWindowList();
+            WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                 final WindowState child = windows.get(winNdx);
                 final InputChannel inputChannel = child.mInputChannel;
@@ -302,6 +315,7 @@
     }
 
     /* Notifies that the input device configuration has changed. */
+    @Override
     public void notifyConfigurationChanged() {
         mService.sendNewConfiguration();
 
@@ -327,12 +341,14 @@
     }
 
     /* Notifies that the lid switch changed state. */
+    @Override
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
         mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
     }
-    
+
     /* Provides an opportunity for the window manager policy to intercept early key
      * processing as soon as the key has been read from the device. */
+    @Override
     public int interceptKeyBeforeQueueing(
             KeyEvent event, int policyFlags, boolean isScreenOn) {
         return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
@@ -341,20 +357,23 @@
     /* Provides an opportunity for the window manager policy to intercept early
      * motion event processing when the screen is off since these events are normally
      * dropped. */
+    @Override
     public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
         return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to process a key before
      * ordinary dispatch. */
+    @Override
     public long interceptKeyBeforeDispatching(
             InputWindowHandle focus, KeyEvent event, int policyFlags) {
         WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
         return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
     }
-    
+
     /* Provides an opportunity for the window manager policy to process a key that
      * the application did not handle. */
+    @Override
     public KeyEvent dispatchUnhandledKey(
             InputWindowHandle focus, KeyEvent event, int policyFlags) {
         WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
@@ -362,6 +381,7 @@
     }
 
     /* Callback to get pointer layer. */
+    @Override
     public int getPointerLayer() {
         return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_POINTER)
                 * WindowManagerService.TYPE_LAYER_MULTIPLIER
@@ -372,7 +392,7 @@
      * Layer assignment is assumed to be complete by the time this is called.
      */
     public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
-        if (WindowManagerService.DEBUG_INPUT) {
+        if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
             Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
         }
 
@@ -392,7 +412,7 @@
             }
         }
     }
-    
+
     public void setFocusedAppLw(AppWindowToken newApp) {
         // Focused app has changed.
         if (newApp == null) {
@@ -405,7 +425,7 @@
             mService.mInputManager.setFocusedApplication(handle);
         }
     }
-    
+
     public void pauseDispatchingLw(WindowToken window) {
         if (! window.paused) {
             if (WindowManagerService.DEBUG_INPUT) {
diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/java/com/android/server/wm/PointerEventDispatcher.java
new file mode 100644
index 0000000..6b0e4c9
--- /dev/null
+++ b/services/java/com/android/server/wm/PointerEventDispatcher.java
@@ -0,0 +1,90 @@
+/*
+ * 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.wm;
+
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+import com.android.server.UiThread;
+
+import java.util.ArrayList;
+
+public class PointerEventDispatcher extends InputEventReceiver {
+    ArrayList<PointerEventListener> mListeners = new ArrayList<PointerEventListener>();
+    PointerEventListener[] mListenersArray = new PointerEventListener[0];
+
+    public PointerEventDispatcher(InputChannel inputChannel) {
+        super(inputChannel, UiThread.getHandler().getLooper());
+    }
+
+    @Override
+    public void onInputEvent(InputEvent event) {
+        try {
+            if (event instanceof MotionEvent
+                    && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+                final MotionEvent motionEvent = (MotionEvent)event;
+                PointerEventListener[] listeners;
+                synchronized (mListeners) {
+                    if (mListenersArray == null) {
+                        mListenersArray = new PointerEventListener[mListeners.size()];
+                        mListeners.toArray(mListenersArray);
+                    }
+                    listeners = mListenersArray;
+                }
+                for (int i = 0; i < listeners.length; ++i) {
+                    listeners[i].onPointerEvent(motionEvent);
+                }
+            }
+        } finally {
+            finishInputEvent(event, false);
+        }
+    }
+
+    /**
+     * Add the specified listener to the list.
+     * @param listener The listener to add.
+     */
+    public void registerInputEventListener(PointerEventListener listener) {
+        synchronized (mListeners) {
+            if (mListeners.contains(listener)) {
+                throw new IllegalStateException("registerInputEventListener: trying to register" +
+                        listener + " twice.");
+            }
+            mListeners.add(listener);
+            mListenersArray = null;
+        }
+    }
+
+    /**
+     * Remove the specified listener from the list.
+     * @param listener The listener to remove.
+     */
+    public void unregisterInputEventListener(PointerEventListener listener) {
+        synchronized (mListeners) {
+            if (!mListeners.contains(listener)) {
+                throw new IllegalStateException("registerInputEventListener: " + listener +
+                        " not registered.");
+            }
+            mListeners.remove(listener);
+            mListenersArray = null;
+        }
+    }
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index b2fbec1..e630737 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -26,6 +26,8 @@
 import android.graphics.Rect;
 import android.util.Slog;
 import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -43,7 +45,7 @@
     static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
 
     final Context mContext;
-    final Display mDisplay;
+    final DisplayContent mDisplayContent;
     SurfaceControl mSurfaceControl;
     BlackFrame mCustomBlackFrame;
     BlackFrame mExitingBlackFrame;
@@ -53,6 +55,8 @@
     int mOriginalRotation;
     int mOriginalWidth, mOriginalHeight;
     int mCurRotation;
+    Rect mOriginalDisplayRect = new Rect();
+    Rect mCurrentDisplayRect = new Rect();
 
     // For all animations, "exit" is for the UI elements that are going
     // away (that is the snapshot of the old screen), and "enter" is for
@@ -108,6 +112,7 @@
     boolean mAnimRunning;
     boolean mFinishAnimReady;
     long mFinishAnimStartTime;
+    boolean mForceDefaultOrientation;
 
     final Matrix mFrameInitialMatrix = new Matrix();
     final Matrix mSnapshotInitialMatrix = new Matrix();
@@ -186,14 +191,35 @@
         pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
                 mExitFrameFinalMatrix.printShortString(pw);
                 pw.println();
+        pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
+        if (mForceDefaultOrientation) {
+            pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
+            pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString());
+        }
     }
 
-    public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
-            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
+    public ScreenRotationAnimation(Context context, DisplayContent displayContent,
+            SurfaceSession session, boolean inTransaction, boolean forceDefaultOrientation) {
         mContext = context;
-        mDisplay = display;
+        mDisplayContent = displayContent;
+        displayContent.getLogicalDisplayRect(mOriginalDisplayRect);
 
         // Screenshot does NOT include rotation!
+        final Display display = displayContent.getDisplay();
+        int originalRotation = display.getRotation();
+        final int originalWidth;
+        final int originalHeight;
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        if (forceDefaultOrientation) {
+            // Emulated orientation.
+            mForceDefaultOrientation = true;
+            originalWidth = displayContent.mBaseDisplayWidth;
+            originalHeight = displayContent.mBaseDisplayHeight;
+        } else {
+            // Normal situation
+            originalWidth = displayInfo.logicalWidth;
+            originalHeight = displayInfo.logicalHeight;
+        }
         if (originalRotation == Surface.ROTATION_90
                 || originalRotation == Surface.ROTATION_270) {
             mWidth = originalHeight;
@@ -219,6 +245,8 @@
                     mSurfaceControl = new SurfaceTrace(session, "ScreenshotSurface",
                             mWidth, mHeight,
                             PixelFormat.OPAQUE, SurfaceControl.HIDDEN);
+                    Slog.w(TAG, "ScreenRotationAnimation ctor: displayOffset="
+                            + mOriginalDisplayRect.toShortString());
                 } else {
                     mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface",
                             mWidth, mHeight,
@@ -230,12 +258,12 @@
                 // FIXME: we should use the proper display
                 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
                         SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
-                mSurfaceControl.setLayerStack(mDisplay.getLayerStack());
+                mSurfaceControl.setLayerStack(display.getLayerStack());
                 mSurfaceControl.setLayer(FREEZE_LAYER + 1);
                 mSurfaceControl.setAlpha(0);
                 mSurfaceControl.show();
                 sur.destroy();
-            } catch (SurfaceControl.OutOfResourcesException e) {
+            } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate freeze surface", e);
             }
 
@@ -266,7 +294,14 @@
     private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) {
         if (mSurfaceControl != null) {
             matrix.getValues(mTmpFloats);
-            mSurfaceControl.setPosition(mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
+            float x = mTmpFloats[Matrix.MTRANS_X];
+            float y = mTmpFloats[Matrix.MTRANS_Y];
+            if (mForceDefaultOrientation) {
+                mDisplayContent.getLogicalDisplayRect(mCurrentDisplayRect);
+                x -= mCurrentDisplayRect.left;
+                y -= mCurrentDisplayRect.top;
+            }
+            mSurfaceControl.setPosition(x, y);
             mSurfaceControl.setMatrix(
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
@@ -491,7 +526,7 @@
             mRotateFrameAnimation.scaleCurrentDuration(animationScale);
         }
 
-        final int layerStack = mDisplay.getLayerStack();
+        final int layerStack = mDisplayContent.getDisplay().getLayerStack();
         if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     WindowManagerService.TAG,
@@ -511,9 +546,9 @@
                         mOriginalWidth*2, mOriginalHeight*2);
                 Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
                 mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3,
-                        layerStack);
+                        layerStack, false);
                 mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
-            } catch (SurfaceControl.OutOfResourcesException e) {
+            } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
                 SurfaceControl.closeTransaction();
@@ -537,13 +572,23 @@
                 // we were last in.
                 createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
 
-                Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
-                        mOriginalWidth*2, mOriginalHeight*2);
-                Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
+                final Rect outer;
+                final Rect inner;
+                if (mForceDefaultOrientation) {
+                    // Going from a smaller Display to a larger Display, add curtains to sides
+                    // or top and bottom. Going from a larger to smaller display will result in
+                    // no BlackSurfaces being constructed.
+                    outer = mCurrentDisplayRect;
+                    inner = mOriginalDisplayRect;
+                } else {
+                    outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
+                            mOriginalWidth*2, mOriginalHeight*2);
+                    inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
+                }
                 mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2,
-                        layerStack);
+                        layerStack, mForceDefaultOrientation);
                 mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
-            } catch (SurfaceControl.OutOfResourcesException e) {
+            } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
                 SurfaceControl.closeTransaction();
@@ -564,8 +609,8 @@
                         finalWidth*2, finalHeight*2);
                 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
                 mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER,
-                        layerStack);
-            } catch (SurfaceControl.OutOfResourcesException e) {
+                        layerStack, false);
+            } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
                 SurfaceControl.closeTransaction();
@@ -850,7 +895,7 @@
                     && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
                 || (USE_CUSTOM_BLACK_FRAME
                         && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
-                || mMoreRotateEnter || mMoreRotateExit 
+                || mMoreRotateEnter || mMoreRotateExit
                 || !mFinishAnimReady;
 
         mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
@@ -888,6 +933,9 @@
             } else {
                 mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix);
                 mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix);
+                if (mForceDefaultOrientation) {
+                    mExitingBlackFrame.setAlpha(mExitTransformation.getAlpha());
+                }
             }
         }
 
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index 1d95c44..87cabc9 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -126,7 +126,7 @@
         } catch (RuntimeException e) {
             // Log all 'real' exceptions thrown to the caller
             if (!(e instanceof SecurityException)) {
-                Slog.e(WindowManagerService.TAG, "Window Session Crash", e);
+                Slog.wtf(WindowManagerService.TAG, "Window Session Crash", e);
             }
             throw e;
         }
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
new file mode 100644
index 0000000..d054e9a
--- /dev/null
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -0,0 +1,418 @@
+/*
+ * 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.wm;
+
+import android.graphics.Rect;
+import android.util.Slog;
+
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.TAG;
+
+import java.io.PrintWriter;
+
+public class StackBox {
+    /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
+    public static final int TASK_STACK_GOES_BEFORE = 0;
+    /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
+    public static final int TASK_STACK_GOES_AFTER = 1;
+    /** Used with {@link WindowManagerService#createStack}. Horizontal to left of. */
+    public static final int TASK_STACK_TO_LEFT_OF = 2;
+    /** Used with {@link WindowManagerService#createStack}. Horizontal to right of. */
+    public static final int TASK_STACK_TO_RIGHT_OF = 3;
+    /** Used with {@link WindowManagerService#createStack}. Vertical: lower t/b Rect values. */
+    public static final int TASK_STACK_GOES_ABOVE = 4;
+    /** Used with {@link WindowManagerService#createStack}. Vertical: higher t/b Rect values. */
+    public static final int TASK_STACK_GOES_BELOW = 5;
+    /** Used with {@link WindowManagerService#createStack}. Put on a higher layer on display. */
+    public static final int TASK_STACK_GOES_OVER = 6;
+    /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */
+    public static final int TASK_STACK_GOES_UNDER = 7;
+
+    static int sCurrentBoxId = 0;
+
+    /** Unique id for this box */
+    final int mStackBoxId;
+
+    /** The service */
+    final WindowManagerService mService;
+
+    /** The display this box sits in. */
+    final DisplayContent mDisplayContent;
+
+    /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this
+     * is this entire size of mDisplayContent. */
+    StackBox mParent;
+
+    /** First child, this is null exactly when mStack is non-null. */
+    StackBox mFirst;
+
+    /** Second child, this is null exactly when mStack is non-null. */
+    StackBox mSecond;
+
+    /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */
+    TaskStack mStack;
+
+    /** Content limits relative to the DisplayContent this sits in. */
+    Rect mBounds = new Rect();
+
+    /** Relative orientation of mFirst and mSecond. */
+    boolean mVertical;
+
+    /** Fraction of mBounds to devote to mFirst, remainder goes to mSecond */
+    float mWeight;
+
+    /** Dirty flag. Something inside this or some descendant of this has changed. */
+    boolean layoutNeeded;
+
+    /** True if this StackBox sits below the Status Bar. */
+    boolean mUnderStatusBar;
+
+    /** Used to keep from reallocating a temporary Rect for propagating bounds to child boxes */
+    Rect mTmpRect = new Rect();
+
+    StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) {
+        synchronized (StackBox.class) {
+            mStackBoxId = sCurrentBoxId++;
+        }
+
+        mService = service;
+        mDisplayContent = displayContent;
+        mParent = parent;
+    }
+
+    /** Propagate #layoutNeeded bottom up. */
+    void makeDirty() {
+        layoutNeeded = true;
+        if (mParent != null) {
+            mParent.makeDirty();
+        }
+    }
+
+    /**
+     * Determine if a particular StackBox is this one or a descendant of this one.
+     * @param stackBoxId The StackBox being searched for.
+     * @return true if the specified StackBox matches this or one of its descendants.
+     */
+    boolean contains(int stackBoxId) {
+        return mStackBoxId == stackBoxId ||
+                (mStack == null &&  (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId)));
+    }
+
+    /**
+     * Return the stackId of the stack that intersects the passed point.
+     * @param x coordinate of point.
+     * @param y coordinate of point.
+     * @return -1 if point is outside of mBounds, otherwise the stackId of the containing stack.
+     */
+    int stackIdFromPoint(int x, int y) {
+        if (!mBounds.contains(x, y)) {
+            return -1;
+        }
+        if (mStack != null) {
+            return mStack.mStackId;
+        }
+        int stackId = mFirst.stackIdFromPoint(x, y);
+        if (stackId >= 0) {
+            return stackId;
+        }
+        return mSecond.stackIdFromPoint(x, y);
+    }
+
+    /** Determine if this StackBox is the first child or second child.
+     * @return true if this is the first child.
+     */
+    boolean isFirstChild() {
+        return mParent != null && mParent.mFirst == this;
+    }
+
+    /** Returns the bounds of the specified TaskStack if it is contained in this StackBox.
+     * @param stackId the TaskStack to find the bounds of.
+     * @return a new Rect with the bounds of stackId if it is within this StackBox, null otherwise.
+     */
+    Rect getStackBounds(int stackId) {
+        if (mStack != null) {
+            return mStack.mStackId == stackId ? new Rect(mBounds) : null;
+        }
+        Rect bounds = mFirst.getStackBounds(stackId);
+        if (bounds != null) {
+            return bounds;
+        }
+        return mSecond.getStackBounds(stackId);
+    }
+
+    /**
+     * Create a new TaskStack relative to a specified one by splitting the StackBox containing
+     * the specified TaskStack into two children. The size and position each of the new StackBoxes
+     * is determined by the passed parameters.
+     * @param stackId The id of the new TaskStack to create.
+     * @param relativeStackBoxId The id of the StackBox to place the new TaskStack next to.
+     * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class.
+     * @param weight The percentage size of the parent StackBox to devote to the new TaskStack.
+     * @return The new TaskStack.
+     */
+    TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) {
+        if (mStackBoxId != relativeStackBoxId) {
+            // This is not the targeted StackBox.
+            if (mStack != null) {
+                return null;
+            }
+            // Propagate the split to see if the targeted StackBox is in either sub box.
+            TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight);
+            if (stack != null) {
+                return stack;
+            }
+            return mSecond.split(stackId, relativeStackBoxId, position, weight);
+        }
+
+        // Found it!
+        TaskStack stack = new TaskStack(mService, stackId, mDisplayContent);
+        TaskStack firstStack;
+        TaskStack secondStack;
+        if (position == TASK_STACK_GOES_BEFORE) {
+            // TODO: Test Configuration here for LTR/RTL.
+            position = TASK_STACK_TO_LEFT_OF;
+        } else if (position == TASK_STACK_GOES_AFTER) {
+            // TODO: Test Configuration here for LTR/RTL.
+            position = TASK_STACK_TO_RIGHT_OF;
+        }
+        switch (position) {
+            default:
+            case TASK_STACK_TO_LEFT_OF:
+            case TASK_STACK_TO_RIGHT_OF:
+                mVertical = false;
+                if (position == TASK_STACK_TO_LEFT_OF) {
+                    mWeight = weight;
+                    firstStack = stack;
+                    secondStack = mStack;
+                } else {
+                    mWeight = 1.0f - weight;
+                    firstStack = mStack;
+                    secondStack = stack;
+                }
+                break;
+            case TASK_STACK_GOES_ABOVE:
+            case TASK_STACK_GOES_BELOW:
+                mVertical = true;
+                if (position == TASK_STACK_GOES_ABOVE) {
+                    mWeight = weight;
+                    firstStack = stack;
+                    secondStack = mStack;
+                } else {
+                    mWeight = 1.0f - weight;
+                    firstStack = mStack;
+                    secondStack = stack;
+                }
+                break;
+        }
+
+        mFirst = new StackBox(mService, mDisplayContent, this);
+        firstStack.mStackBox = mFirst;
+        mFirst.mStack = firstStack;
+
+        mSecond = new StackBox(mService, mDisplayContent, this);
+        secondStack.mStackBox = mSecond;
+        mSecond.mStack = secondStack;
+
+        mStack = null;
+        return stack;
+    }
+
+    /** Return the stackId of the first mFirst StackBox with a non-null mStack */
+    int getStackId() {
+        if (mStack != null) {
+            return mStack.mStackId;
+        }
+        return mFirst.getStackId();
+    }
+
+    /** Remove this box and propagate its sibling's content up to their parent.
+     * @return The first stackId of the resulting StackBox. */
+    int remove() {
+        if (mStack != null) {
+            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing stackId=" + mStack.mStackId);
+            mDisplayContent.mStackHistory.remove(mStack);
+        }
+        mDisplayContent.layoutNeeded = true;
+
+        if (mParent == null) {
+            // This is the top-plane stack.
+            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane.");
+            mDisplayContent.removeStackBox(this);
+            return HOME_STACK_ID;
+        }
+
+        StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst;
+        StackBox grandparent = mParent.mParent;
+        sibling.mParent = grandparent;
+        if (grandparent == null) {
+            // mParent is a top-plane stack. Now sibling will be.
+            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null");
+            mDisplayContent.removeStackBox(mParent);
+            mDisplayContent.addStackBox(sibling, true);
+        } else {
+            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling");
+            if (mParent.isFirstChild()) {
+                grandparent.mFirst = sibling;
+            } else {
+                grandparent.mSecond = sibling;
+            }
+        }
+        return sibling.getStackId();
+    }
+
+    boolean resize(int stackBoxId, float weight) {
+        if (mStackBoxId != stackBoxId) {
+            return mStack == null &&
+                    (mFirst.resize(stackBoxId, weight) || mSecond.resize(stackBoxId, weight));
+        }
+        // Don't change weight on topmost stack.
+        if (mParent != null) {
+            mParent.mWeight = isFirstChild() ? weight : 1.0f - weight;
+        }
+        return true;
+    }
+
+    /** If this is a terminal StackBox (contains a TaskStack) set the bounds.
+     * @param bounds The rectangle to set the bounds to.
+     * @param underStatusBar True if the StackBox is directly below the Status Bar.
+     * @return True if the bounds changed, false otherwise. */
+    boolean setStackBoxSizes(Rect bounds, boolean underStatusBar) {
+        boolean change = false;
+        if (mUnderStatusBar != underStatusBar) {
+            change = true;
+            mUnderStatusBar = underStatusBar;
+        }
+        if (mStack != null) {
+            change |= !mBounds.equals(bounds);
+            if (change) {
+                mBounds.set(bounds);
+                mStack.setBounds(bounds, underStatusBar);
+            }
+        } else {
+            mTmpRect.set(bounds);
+            if (mVertical) {
+                final int height = bounds.height();
+                int firstHeight = (int)(height * mWeight);
+                mTmpRect.bottom = bounds.top + firstHeight;
+                change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
+                mTmpRect.top = mTmpRect.bottom;
+                mTmpRect.bottom = bounds.top + height;
+                change |= mSecond.setStackBoxSizes(mTmpRect, false);
+            } else {
+                final int width = bounds.width();
+                int firstWidth = (int)(width * mWeight);
+                mTmpRect.right = bounds.left + firstWidth;
+                change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
+                mTmpRect.left = mTmpRect.right;
+                mTmpRect.right = bounds.left + width;
+                change |= mSecond.setStackBoxSizes(mTmpRect, underStatusBar);
+            }
+        }
+        return change;
+    }
+
+    void resetAnimationBackgroundAnimator() {
+        if (mStack != null) {
+            mStack.resetAnimationBackgroundAnimator();
+            return;
+        }
+        mFirst.resetAnimationBackgroundAnimator();
+        mSecond.resetAnimationBackgroundAnimator();
+    }
+
+    boolean animateDimLayers() {
+        if (mStack != null) {
+            return mStack.animateDimLayers();
+        }
+        boolean result = mFirst.animateDimLayers();
+        result |= mSecond.animateDimLayers();
+        return result;
+    }
+
+    void resetDimming() {
+        if (mStack != null) {
+            mStack.resetDimmingTag();
+            return;
+        }
+        mFirst.resetDimming();
+        mSecond.resetDimming();
+    }
+
+    boolean isDimming() {
+        if (mStack != null) {
+            return mStack.isDimming();
+        }
+        boolean result = mFirst.isDimming();
+        result |= mSecond.isDimming();
+        return result;
+    }
+
+    void stopDimmingIfNeeded() {
+        if (mStack != null) {
+            mStack.stopDimmingIfNeeded();
+            return;
+        }
+        mFirst.stopDimmingIfNeeded();
+        mSecond.stopDimmingIfNeeded();
+    }
+
+    void switchUserStacks(int userId) {
+        if (mStack != null) {
+            mStack.switchUser(userId);
+            return;
+        }
+        mFirst.switchUserStacks(userId);
+        mSecond.switchUserStacks(userId);
+    }
+
+    void close() {
+        if (mStack != null) {
+            mStack.mDimLayer.mDimSurface.destroy();
+            mStack.mAnimationBackgroundSurface.mDimSurface.destroy();
+            return;
+        }
+        mFirst.close();
+        mSecond.close();
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mParent="); pw.println(mParent);
+        pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
+            pw.print(" mVertical="); pw.print(mVertical);
+            pw.print(" layoutNeeded="); pw.println(layoutNeeded);
+        if (mFirst != null) {
+            pw.print(prefix); pw.print("mFirst="); pw.println(System.identityHashCode(mFirst));
+            mFirst.dump(prefix + "  ", pw);
+            pw.print(prefix); pw.print("mSecond="); pw.println(System.identityHashCode(mSecond));
+            mSecond.dump(prefix + "  ", pw);
+        } else {
+            pw.print(prefix); pw.print("mStack="); pw.println(mStack);
+            mStack.dump(prefix + "  ", pw);
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (mStack != null) {
+            return "Box{" + hashCode() + " stack=" + mStack.mStackId + "}";
+        }
+        return "Box{" + hashCode() + " parent=" + System.identityHashCode(mParent)
+                + " first=" + System.identityHashCode(mFirst)
+                + " second=" + System.identityHashCode(mSecond) + "}";
+    }
+}
diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/java/com/android/server/wm/StackTapPointerEventListener.java
new file mode 100644
index 0000000..19d8ab3
--- /dev/null
+++ b/services/java/com/android/server/wm/StackTapPointerEventListener.java
@@ -0,0 +1,87 @@
+/*
+ * 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.wm;
+
+import android.graphics.Region;
+import android.view.DisplayInfo;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+import com.android.server.wm.WindowManagerService.H;
+
+public class StackTapPointerEventListener implements PointerEventListener {
+    private static final int TAP_TIMEOUT_MSEC = 300;
+    private static final float TAP_MOTION_SLOP_INCHES = 0.125f;
+
+    private final int mMotionSlop;
+    private float mDownX;
+    private float mDownY;
+    private int mPointerId;
+    final private Region mTouchExcludeRegion;
+    private final WindowManagerService mService;
+    private final DisplayContent mDisplayContent;
+
+    public StackTapPointerEventListener(WindowManagerService service,
+            DisplayContent displayContent) {
+        mService = service;
+        mDisplayContent = displayContent;
+        mTouchExcludeRegion = displayContent.mTouchExcludeRegion;
+        DisplayInfo info = displayContent.getDisplayInfo();
+        mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
+    }
+
+    @Override
+    public void onPointerEvent(MotionEvent motionEvent) {
+        final int action = motionEvent.getAction();
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                mPointerId = motionEvent.getPointerId(0);
+                mDownX = motionEvent.getX();
+                mDownY = motionEvent.getY();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mPointerId >= 0) {
+                    int index = motionEvent.findPointerIndex(mPointerId);
+                    if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
+                            || (motionEvent.getX(index) - mDownX) > mMotionSlop
+                            || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
+                        mPointerId = -1;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_POINTER_UP: {
+                int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                // Extract the index of the pointer that left the touch sensor
+                if (mPointerId == motionEvent.getPointerId(index)) {
+                    final int x = (int)motionEvent.getX(index);
+                    final int y = (int)motionEvent.getY(index);
+                    if ((motionEvent.getEventTime() - motionEvent.getDownTime())
+                            < TAP_TIMEOUT_MSEC
+                            && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop
+                            && !mTouchExcludeRegion.contains(x, y)) {
+                        mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
+                                mDisplayContent).sendToTarget();
+                    }
+                    mPointerId = -1;
+                }
+                break;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/wm/StartingData.java b/services/java/com/android/server/wm/StartingData.java
index 46bb480..7115b0f 100644
--- a/services/java/com/android/server/wm/StartingData.java
+++ b/services/java/com/android/server/wm/StartingData.java
@@ -25,17 +25,19 @@
     final CharSequence nonLocalizedLabel;
     final int labelRes;
     final int icon;
+    final int logo;
     final int windowFlags;
 
     StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo,
             CharSequence _nonLocalizedLabel,
-            int _labelRes, int _icon, int _windowFlags) {
+            int _labelRes, int _icon, int _logo, int _windowFlags) {
         pkg = _pkg;
         theme = _theme;
         compatInfo = _compatInfo;
         nonLocalizedLabel = _nonLocalizedLabel;
         labelRes = _labelRes;
         icon = _icon;
+        logo = _logo;
         windowFlags = _windowFlags;
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java
index 31628e3..fb5876b 100644
--- a/services/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/java/com/android/server/wm/StrictModeFlash.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.view.Display;
+import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -47,7 +48,7 @@
             ctrl.setPosition(0, 0);
             ctrl.show();
             mSurface.copyFrom(ctrl);
-        } catch (SurfaceControl.OutOfResourcesException e) {
+        } catch (OutOfResourcesException e) {
         }
         mSurfaceControl = ctrl;
         mDrawNeeded = true;
diff --git a/services/java/com/android/server/wm/Task.java b/services/java/com/android/server/wm/Task.java
new file mode 100644
index 0000000..d9acbb9
--- /dev/null
+++ b/services/java/com/android/server/wm/Task.java
@@ -0,0 +1,54 @@
+/*
+ * 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.wm;
+
+class Task {
+//    private final String TAG = "TaskGroup";
+    TaskStack mStack;
+    final AppTokenList mAppTokens = new AppTokenList();
+    final int taskId;
+    final int mUserId;
+
+    Task(AppWindowToken wtoken, TaskStack stack, int userId) {
+        taskId = wtoken.groupId;
+        mAppTokens.add(wtoken);
+        mStack = stack;
+        mUserId = userId;
+    }
+
+    DisplayContent getDisplayContent() {
+        return mStack.getDisplayContent();
+    }
+
+    void addAppToken(int addPos, AppWindowToken wtoken) {
+        mAppTokens.add(addPos, wtoken);
+    }
+
+    boolean removeAppToken(AppWindowToken wtoken) {
+        mAppTokens.remove(wtoken);
+        if (mAppTokens.size() == 0) {
+            mStack.removeTask(this);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "{taskId=" + taskId + " appTokens=" + mAppTokens + "}";
+    }
+}
diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/java/com/android/server/wm/TaskGroup.java
new file mode 100644
index 0000000..1f1dd58
--- /dev/null
+++ b/services/java/com/android/server/wm/TaskGroup.java
@@ -0,0 +1,31 @@
+/*
+ * 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.wm;
+
+import android.view.IApplicationToken;
+
+import java.util.ArrayList;
+
+public class TaskGroup {
+    public int taskId = -1;
+    public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();
+
+    @Override
+    public String toString() {
+        return "id=" + taskId + " tokens=" + tokens;
+    }
+}
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
new file mode 100644
index 0000000..7bb6734
--- /dev/null
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -0,0 +1,310 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
+import static com.android.server.wm.WindowManagerService.TAG;
+
+import android.graphics.Rect;
+import android.os.Debug;
+import android.util.Slog;
+import android.util.TypedValue;
+
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+public class TaskStack {
+    /** Amount of time in milliseconds to animate the dim surface from one value to another,
+     * when no window animation is driving it. */
+    private static final int DEFAULT_DIM_DURATION = 200;
+
+    /** Unique identifier */
+    final int mStackId;
+
+    /** The service */
+    private final WindowManagerService mService;
+
+    /** The display this stack sits under. */
+    private final DisplayContent mDisplayContent;
+
+    /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
+     * mTaskHistory in the ActivityStack with the same mStackId */
+    private ArrayList<Task> mTasks = new ArrayList<Task>();
+
+    /** The StackBox this sits in. */
+    StackBox mStackBox;
+
+    /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
+    final DimLayer mDimLayer;
+
+    /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
+    WindowStateAnimator mDimWinAnimator;
+
+    /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
+    final DimLayer mAnimationBackgroundSurface;
+
+    /** The particular window with an Animation with non-zero background color. */
+    WindowStateAnimator mAnimationBackgroundAnimator;
+
+    /** Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end
+     * then stop any dimming. */
+    boolean mDimmingTag;
+
+    TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {
+        mService = service;
+        mStackId = stackId;
+        mDisplayContent = displayContent;
+        final int displayId = displayContent.getDisplayId();
+        mDimLayer = new DimLayer(service, displayContent);
+        mAnimationBackgroundSurface = new DimLayer(service, displayContent);
+    }
+
+    DisplayContent getDisplayContent() {
+        return mDisplayContent;
+    }
+
+    ArrayList<Task> getTasks() {
+        return mTasks;
+    }
+
+    boolean isHomeStack() {
+        return mStackId == HOME_STACK_ID;
+    }
+
+    boolean hasSibling() {
+        return mStackBox.mParent != null;
+    }
+
+    /**
+     * Put a Task in this stack. Used for adding and moving.
+     * @param task The task to add.
+     * @param toTop Whether to add it to the top or bottom.
+     */
+    boolean addTask(Task task, boolean toTop) {
+        mStackBox.makeDirty();
+
+        int stackNdx;
+        if (!toTop) {
+            stackNdx = 0;
+        } else {
+            stackNdx = mTasks.size();
+            final int currentUserId = mService.mCurrentUserId;
+            if (task.mUserId != currentUserId) {
+                // Place the task below all current user tasks.
+                while (--stackNdx >= 0) {
+                    if (currentUserId != mTasks.get(stackNdx).mUserId) {
+                        break;
+                    }
+                }
+                ++stackNdx;
+            }
+        }
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop
+                + " pos=" + stackNdx);
+        mTasks.add(stackNdx, task);
+
+        task.mStack = this;
+        return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
+    }
+
+    boolean moveTaskToTop(Task task) {
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers="
+                + Debug.getCallers(6));
+        mTasks.remove(task);
+        return addTask(task, true);
+    }
+
+    boolean moveTaskToBottom(Task task) {
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task);
+        mTasks.remove(task);
+        return addTask(task, false);
+    }
+
+    /**
+     * Delete a Task from this stack. If it is the last Task in the stack, remove this stack from
+     * its parent StackBox and merge the parent.
+     * @param task The Task to delete.
+     */
+    void removeTask(Task task) {
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
+        mStackBox.makeDirty();
+        mTasks.remove(task);
+    }
+
+    int remove() {
+        mAnimationBackgroundSurface.destroySurface();
+        mDimLayer.destroySurface();
+        return mStackBox.remove();
+    }
+
+    void resetAnimationBackgroundAnimator() {
+        mAnimationBackgroundAnimator = null;
+        mAnimationBackgroundSurface.hide();
+    }
+
+    private long getDimBehindFadeDuration(long duration) {
+        TypedValue tv = new TypedValue();
+        mService.mContext.getResources().getValue(
+                com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
+        if (tv.type == TypedValue.TYPE_FRACTION) {
+            duration = (long)tv.getFraction(duration, duration);
+        } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
+            duration = tv.data;
+        }
+        return duration;
+    }
+
+    boolean animateDimLayers() {
+        final int dimLayer;
+        final float dimAmount;
+        if (mDimWinAnimator == null) {
+            dimLayer = mDimLayer.getLayer();
+            dimAmount = 0;
+        } else {
+            dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
+            dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
+        }
+        final float targetAlpha = mDimLayer.getTargetAlpha();
+        if (targetAlpha != dimAmount) {
+            if (mDimWinAnimator == null) {
+                mDimLayer.hide(DEFAULT_DIM_DURATION);
+            } else {
+                long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
+                        ? mDimWinAnimator.mAnimation.computeDurationHint()
+                        : DEFAULT_DIM_DURATION;
+                if (targetAlpha > dimAmount) {
+                    duration = getDimBehindFadeDuration(duration);
+                }
+                mDimLayer.show(dimLayer, dimAmount, duration);
+            }
+        } else if (mDimLayer.getLayer() != dimLayer) {
+            mDimLayer.setLayer(dimLayer);
+        }
+        if (mDimLayer.isAnimating()) {
+            if (!mService.okToDisplay()) {
+                // Jump to the end of the animation.
+                mDimLayer.show();
+            } else {
+                return mDimLayer.stepAnimation();
+            }
+        }
+        return false;
+    }
+
+    void resetDimmingTag() {
+        mDimmingTag = false;
+    }
+
+    void setDimmingTag() {
+        mDimmingTag = true;
+    }
+
+    boolean testDimmingTag() {
+        return mDimmingTag;
+    }
+
+    boolean isDimming() {
+        return mDimLayer.isDimming();
+    }
+
+    boolean isDimming(WindowStateAnimator winAnimator) {
+        return mDimWinAnimator == winAnimator && mDimLayer.isDimming();
+    }
+
+    void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
+        // Only set dim params on the highest dimmed layer.
+        final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator;
+        // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
+        if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
+                || !existingDimWinAnimator.mSurfaceShown
+                || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
+            mDimWinAnimator = newWinAnimator;
+        }
+    }
+
+    void stopDimmingIfNeeded() {
+        if (!mDimmingTag && isDimming()) {
+            mDimWinAnimator = null;
+        }
+    }
+
+    void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
+        int animLayer = winAnimator.mAnimLayer;
+        if (mAnimationBackgroundAnimator == null
+                || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
+            mAnimationBackgroundAnimator = winAnimator;
+            animLayer = mService.adjustAnimationBackground(winAnimator);
+            mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
+                    ((color >> 24) & 0xff) / 255f, 0);
+        }
+    }
+
+    void setBounds(Rect bounds, boolean underStatusBar) {
+        mDimLayer.setBounds(bounds);
+        mAnimationBackgroundSurface.setBounds(bounds);
+
+        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+            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) {
+                    final WindowState win = windows.get(winNdx);
+                    if (!resizingWindows.contains(win)) {
+                        resizingWindows.add(win);
+                    }
+                    win.mUnderStatusBar = underStatusBar;
+                }
+            }
+        }
+    }
+
+    void switchUser(int userId) {
+        int top = mTasks.size();
+        for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
+            Task task = mTasks.get(taskNdx);
+            if (task.mUserId == userId) {
+                mTasks.remove(taskNdx);
+                mTasks.add(task);
+                --top;
+            }
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
+        for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
+            pw.print(prefix); pw.println(mTasks.get(taskNdx));
+        }
+        if (mAnimationBackgroundSurface.isDimming()) {
+            pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:");
+            mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
+        }
+        if (mDimLayer.isDimming()) {
+            pw.print(prefix); pw.println("mDimLayer:");
+            mDimLayer.printTo(prefix, pw);
+            pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
+    }
+}
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java
index fedd314..e226e3d 100644
--- a/services/java/com/android/server/wm/Watermark.java
+++ b/services/java/com/android/server/wm/Watermark.java
@@ -27,10 +27,10 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Display;
+import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
-import android.view.Surface.OutOfResourcesException;
 
 /**
  * Displays a watermark on top of the window manager's windows.
@@ -119,7 +119,7 @@
             ctrl.setPosition(0, 0);
             ctrl.show();
             mSurface.copyFrom(ctrl);
-        } catch (SurfaceControl.OutOfResourcesException e) {
+        } catch (OutOfResourcesException e) {
         }
         mSurfaceControl = ctrl;
     }
@@ -144,11 +144,11 @@
             try {
                 c = mSurface.lockCanvas(dirty);
             } catch (IllegalArgumentException e) {
-            } catch (OutOfResourcesException e) {
+            } catch (Surface.OutOfResourcesException e) {
             }
             if (c != null) {
                 c.drawColor(0, PorterDuff.Mode.CLEAR);
-                
+
                 int deltaX = mDeltaX;
                 int deltaY = mDeltaY;
 
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 4252857..ca87b4f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -19,9 +19,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
-import android.util.TypedValue;
 import android.view.Display;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
@@ -38,10 +36,6 @@
 public class WindowAnimator {
     private static final String TAG = "WindowAnimator";
 
-    /** Amount of time in milliseconds to animate the dim surface from one value to another,
-     * when no window animation is driving it. */
-    static final int DEFAULT_DIM_DURATION = 200;
-
     final WindowManagerService mService;
     final Context mContext;
     final WindowManagerPolicy mPolicy;
@@ -50,8 +44,6 @@
 
     final Runnable mAnimationRunnable;
 
-    int mAdjResult;
-
     /** Time of current animation step. Reset on each iteration */
     long mCurrentTime;
 
@@ -72,7 +64,7 @@
     Object mLastWindowFreezeSource;
 
     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
-            new SparseArray<WindowAnimator.DisplayContentsAnimator>();
+            new SparseArray<WindowAnimator.DisplayContentsAnimator>(2);
 
     boolean mInitialized = false;
 
@@ -120,18 +112,10 @@
     void removeDisplayLocked(final int displayId) {
         final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
         if (displayAnimator != null) {
-            if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
-                displayAnimator.mWindowAnimationBackgroundSurface.destroySurface();
-                displayAnimator.mWindowAnimationBackgroundSurface = null;
-            }
             if (displayAnimator.mScreenRotationAnimation != null) {
                 displayAnimator.mScreenRotationAnimation.kill();
                 displayAnimator.mScreenRotationAnimation = null;
             }
-            if (displayAnimator.mDimAnimator != null) {
-                displayAnimator.mDimAnimator.destroySurface();
-                displayAnimator.mDimAnimator = null;
-            }
         }
 
         mDisplayContentsAnimators.delete(displayId);
@@ -172,28 +156,33 @@
         }
     }
 
-    private void updateAppWindowsLocked() {
-        int i;
-        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
-        final int NAT = appTokens.size();
-        for (i=0; i<NAT; i++) {
-            final AppWindowAnimator appAnimator = appTokens.get(i).mAppAnimator;
-            final boolean wasAnimating = appAnimator.animation != null
-                    && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-            if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                mAnimating = true;
-            } else if (wasAnimating) {
-                // stopped animating, do one more pass through the layout
-                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                        "appToken " + appAnimator.mAppToken + " done");
-                if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                        "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+    private void updateAppWindowsLocked(int displayId) {
+        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        final int numTasks = tasks.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int numTokens = tokens.size();
+            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+                final boolean wasAnimating = appAnimator.animation != null
+                        && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
+                if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                    mAnimating = true;
+                } else if (wasAnimating) {
+                    // stopped animating, do one more pass through the layout
+                    setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                            "appToken " + appAnimator.mAppToken + " done");
+                    if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
+                            "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+                }
             }
         }
 
-        final int NEAT = mService.mExitingAppTokens.size();
-        for (i=0; i<NEAT; i++) {
-            final AppWindowAnimator appAnimator = mService.mExitingAppTokens.get(i).mAppAnimator;
+        final AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+        final int NEAT = exitingAppTokens.size();
+        for (int i = 0; i < NEAT; i++) {
+            final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
             final boolean wasAnimating = appAnimator.animation != null
                     && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
             if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -299,10 +288,13 @@
                                     wallpaperInUnForceHiding = true;
                                 }
                             }
-                            if (mCurrentFocus == null || mCurrentFocus.mLayer < win.mLayer) {
+                            final WindowState currentFocus = mService.mCurrentFocus;
+                            if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
                                 // We are showing on to of the current
                                 // focus, so re-evaluate focus to make
                                 // sure it is correct.
+                                if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
+                                        "updateWindowsLocked: setting mFocusMayChange true");
                                 mService.mFocusMayChange = true;
                             }
                         }
@@ -359,11 +351,9 @@
     }
 
     private void updateWallpaperLocked(int displayId) {
-        final DisplayContentsAnimator displayAnimator =
-                getDisplayContentsAnimatorLocked(displayId);
+        mService.getDisplayContentLocked(displayId).resetAnimationBackgroundAnimator();
+
         final WindowList windows = mService.getWindowListLocked(displayId);
-        WindowStateAnimator windowAnimationBackground = null;
-        int windowAnimationBackgroundColor = 0;
         WindowState detachedWallpaper = null;
 
         for (int i = windows.size() - 1; i >= 0; i--) {
@@ -384,13 +374,9 @@
                             && winAnimator.mAnimation.getDetachWallpaper()) {
                         detachedWallpaper = win;
                     }
-                    final int backgroundColor = winAnimator.mAnimation.getBackgroundColor();
-                    if (backgroundColor != 0) {
-                        if (windowAnimationBackground == null || (winAnimator.mAnimLayer <
-                                windowAnimationBackground.mAnimLayer)) {
-                            windowAnimationBackground = winAnimator;
-                            windowAnimationBackgroundColor = backgroundColor;
-                        }
+                    final int color = winAnimator.mAnimation.getBackgroundColor();
+                    if (color != 0) {
+                        win.getStack().setAnimationBackground(winAnimator, color);
                     }
                 }
                 mAnimating = true;
@@ -407,13 +393,9 @@
                     detachedWallpaper = win;
                 }
 
-                final int backgroundColor = appAnimator.animation.getBackgroundColor();
-                if (backgroundColor != 0) {
-                    if (windowAnimationBackground == null || (winAnimator.mAnimLayer <
-                            windowAnimationBackground.mAnimLayer)) {
-                        windowAnimationBackground = winAnimator;
-                        windowAnimationBackgroundColor = backgroundColor;
-                    }
+                final int color = appAnimator.animation.getBackgroundColor();
+                if (color != 0) {
+                    win.getStack().setAnimationBackground(winAnimator, color);
                 }
             }
         } // end forall windows
@@ -425,68 +407,47 @@
             mWindowDetachedWallpaper = detachedWallpaper;
             mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
         }
-
-        if (windowAnimationBackgroundColor != 0) {
-            // If the window that wants black is the current wallpaper
-            // target, then the black goes *below* the wallpaper so we
-            // don't cause the wallpaper to suddenly disappear.
-            int animLayer = windowAnimationBackground.mAnimLayer;
-            WindowState win = windowAnimationBackground.mWin;
-            if (mService.mWallpaperTarget == win || mService.mLowerWallpaperTarget == win
-                    || mService.mUpperWallpaperTarget == win) {
-                final int N = windows.size();
-                for (int i = 0; i < N; i++) {
-                    WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
-                    if (winAnimator.mIsWallpaper) {
-                        animLayer = winAnimator.mAnimLayer;
-                        break;
-                    }
-                }
-            }
-
-            displayAnimator.mWindowAnimationBackgroundSurface.show(
-                    animLayer - WindowManagerService.LAYER_OFFSET_DIM,
-                    ((windowAnimationBackgroundColor >> 24) & 0xff) / 255f, 0);
-        } else {
-            displayAnimator.mWindowAnimationBackgroundSurface.hide();
-        }
     }
 
     /** See if any windows have been drawn, so they (and others associated with them) can now be
      *  shown. */
-    private void testTokenMayBeDrawnLocked() {
+    private void testTokenMayBeDrawnLocked(int displayId) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
-        final int NT = appTokens.size();
-        for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = appTokens.get(i);
-            AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            final boolean allDrawn = wtoken.allDrawn;
-            if (allDrawn != appAnimator.allDrawn) {
-                appAnimator.allDrawn = allDrawn;
-                if (allDrawn) {
-                    // The token has now changed state to having all
-                    // windows shown...  what to do, what to do?
-                    if (appAnimator.freezingScreen) {
-                        appAnimator.showAllWindowsLocked();
-                        mService.unsetAppFreezingScreenLocked(wtoken, false, true);
-                        if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
-                                "Setting mOrientationChangeComplete=true because wtoken "
-                                + wtoken + " numInteresting=" + wtoken.numInterestingWindows
-                                + " numDrawn=" + wtoken.numDrawnWindows);
-                        // This will set mOrientationChangeComplete and cause a pass through layout.
-                        setAppLayoutChanges(appAnimator,
-                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                "testTokenMayBeDrawnLocked: freezingScreen");
-                    } else {
-                        setAppLayoutChanges(appAnimator,
-                                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                                "testTokenMayBeDrawnLocked");
+        final ArrayList<Task> tasks = mService.getDisplayContentLocked(displayId).getTasks();
+        final int numTasks = tasks.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int numTokens = tokens.size();
+            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                final AppWindowToken wtoken = tokens.get(tokenNdx);
+                AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+                final boolean allDrawn = wtoken.allDrawn;
+                if (allDrawn != appAnimator.allDrawn) {
+                    appAnimator.allDrawn = allDrawn;
+                    if (allDrawn) {
+                        // The token has now changed state to having all
+                        // windows shown...  what to do, what to do?
+                        if (appAnimator.freezingScreen) {
+                            appAnimator.showAllWindowsLocked();
+                            mService.unsetAppFreezingScreenLocked(wtoken, false, true);
+                            if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
+                                    "Setting mOrientationChangeComplete=true because wtoken "
+                                    + wtoken + " numInteresting=" + wtoken.numInterestingWindows
+                                    + " numDrawn=" + wtoken.numDrawnWindows);
+                            // This will set mOrientationChangeComplete and cause a pass through layout.
+                            setAppLayoutChanges(appAnimator,
+                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                                    "testTokenMayBeDrawnLocked: freezingScreen");
+                        } else {
+                            setAppLayoutChanges(appAnimator,
+                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
+                                    "testTokenMayBeDrawnLocked");
 
-                        // We can now show all of the drawn windows!
-                        if (!mService.mOpeningApps.contains(wtoken)) {
-                            mAnimating |= appAnimator.showAllWindowsLocked();
+                            // We can now show all of the drawn windows!
+                            if (!mService.mOpeningApps.contains(wtoken)) {
+                                mAnimating |= appAnimator.showAllWindowsLocked();
+                            }
                         }
                     }
                 }
@@ -499,17 +460,6 @@
         updateWallpaperLocked(displayId);
     }
 
-    private long getDimBehindFadeDuration(long duration) {
-        TypedValue tv = new TypedValue();
-        mContext.getResources().getValue(
-            com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
-        if (tv.type == TypedValue.TYPE_FRACTION) {
-            duration = (long)tv.getFraction(duration, duration);
-        } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
-            duration = tv.data;
-        }
-        return duration;
-    }
 
     /** Locked on mService.mWindowMap. */
     private void animateLocked() {
@@ -530,11 +480,10 @@
         SurfaceControl.openTransaction();
         SurfaceControl.setAnimationTransaction();
         try {
-            updateAppWindowsLocked();
-
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
+                updateAppWindowsLocked(displayId);
                 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                 final ScreenRotationAnimation screenRotationAnimation =
@@ -560,53 +509,18 @@
                 }
             }
 
-            testTokenMayBeDrawnLocked();
-
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
-                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
+
+                testTokenMayBeDrawnLocked(displayId);
 
                 final ScreenRotationAnimation screenRotationAnimation =
-                        displayAnimator.mScreenRotationAnimation;
+                        mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
                 if (screenRotationAnimation != null) {
                     screenRotationAnimation.updateSurfacesInTransaction();
                 }
 
-                final DimLayer dimAnimator = displayAnimator.mDimAnimator;
-                final WindowStateAnimator winAnimator = displayAnimator.mDimWinAnimator;
-                final int dimLayer;
-                final float dimAmount;
-                if (winAnimator == null) {
-                    dimLayer = dimAnimator.getLayer();
-                    dimAmount = 0;
-                } else {
-                    dimLayer = winAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
-                    dimAmount = winAnimator.mWin.mAttrs.dimAmount;
-                }
-                final float targetAlpha = dimAnimator.getTargetAlpha();
-                if (targetAlpha != dimAmount) {
-                    if (winAnimator == null) {
-                        dimAnimator.hide(DEFAULT_DIM_DURATION);
-                    } else {
-                        long duration = (winAnimator.mAnimating && winAnimator.mAnimation != null)
-                                ? winAnimator.mAnimation.computeDurationHint()
-                                : DEFAULT_DIM_DURATION;
-                        if (targetAlpha > dimAmount) {
-                            duration = getDimBehindFadeDuration(duration);
-                        }
-                        dimAnimator.show(dimLayer, dimAmount, duration);
-                    }
-                } else if (dimAnimator.getLayer() != dimLayer) {
-                    dimAnimator.setLayer(dimLayer);
-                }
-                if (dimAnimator.isAnimating()) {
-                    if (!mService.okToDisplay()) {
-                        // Jump to the end of the animation.
-                        dimAnimator.show();
-                    } else {
-                        mAnimating |= dimAnimator.stepAnimation();
-                    }
-                }
+                mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();
 
                 //TODO (multidisplay): Magnification is supported only for the default display.
                 if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
@@ -614,6 +528,12 @@
                 }
             }
 
+            if (mAnimating) {
+                mService.scheduleAnimationLocked();
+            }
+
+            mService.setFocusedStackLayer();
+
             if (mService.mWatermark != null) {
                 mService.mWatermark.drawIfNeeded();
             }
@@ -647,9 +567,7 @@
             mService.requestTraversalLocked();
         }
 
-        if (mAnimating) {
-            mService.scheduleAnimationLocked();
-        } else if (wasAnimating) {
+        if (!mAnimating && wasAnimating) {
             mService.requestTraversalLocked();
         }
         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
@@ -660,26 +578,6 @@
         }
     }
 
-    WindowState mCurrentFocus;
-    void setCurrentFocus(final WindowState currentFocus) {
-        mCurrentFocus = currentFocus;
-    }
-
-    boolean isDimmingLocked(int displayId) {
-        return getDisplayContentsAnimatorLocked(displayId).mDimAnimator.isDimming();
-    }
-
-    boolean isDimmingLocked(final WindowStateAnimator winAnimator) {
-        final int displayId = winAnimator.mWin.getDisplayId();
-        DisplayContentsAnimator displayAnimator =
-                getDisplayContentsAnimatorLocked(displayId);
-        if (displayAnimator != null) {
-            return displayAnimator.mDimWinAnimator == winAnimator
-                    && displayAnimator.mDimAnimator.isDimming();
-        }
-        return false;
-    }
-
     static String bulkUpdateParamsToString(int bulkUpdateParams) {
         StringBuilder builder = new StringBuilder(128);
         if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
@@ -717,18 +615,6 @@
                 pw.print(subPrefix); pw.print("Window #"); pw.print(j);
                         pw.print(": "); pw.println(wanim);
             }
-            if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
-                if (dumpAll || displayAnimator.mWindowAnimationBackgroundSurface.isDimming()) {
-                    pw.print(subPrefix); pw.println("mWindowAnimationBackgroundSurface:");
-                    displayAnimator.mWindowAnimationBackgroundSurface.printTo(subSubPrefix, pw);
-                }
-            }
-            if (dumpAll || displayAnimator.mDimAnimator.isDimming()) {
-                pw.print(subPrefix); pw.println("mDimAnimator:");
-                displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
-                pw.print(subPrefix); pw.print("mDimWinAnimator=");
-                        pw.println(displayAnimator.mDimWinAnimator);
-            }
             if (displayAnimator.mScreenRotationAnimation != null) {
                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
                 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
@@ -771,7 +657,7 @@
 
     void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
         // Used to track which displays layout changes have been done.
-        SparseIntArray displays = new SparseIntArray();
+        SparseIntArray displays = new SparseIntArray(2);
         WindowList windows = appAnimator.mAppToken.allAppWindows;
         for (int i = windows.size() - 1; i >= 0; i--) {
             final int displayId = windows.get(i).getDisplayId();
@@ -786,26 +672,10 @@
         }
     }
 
-    void setDimWinAnimatorLocked(int displayId, WindowStateAnimator newWinAnimator) {
-        DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
-        if (newWinAnimator == null) {
-            displayAnimator.mDimWinAnimator = null;
-        } else {
-            // Only set dim params on the highest dimmed layer.
-            final WindowStateAnimator existingDimWinAnimator = displayAnimator.mDimWinAnimator;
-            // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
-            if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
-                    || !existingDimWinAnimator.mSurfaceShown
-                    || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
-                displayAnimator.mDimWinAnimator = newWinAnimator;
-            }
-        }
-    }
-
     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
         if (displayAnimator == null) {
-            displayAnimator = new DisplayContentsAnimator(displayId);
+            displayAnimator = new DisplayContentsAnimator();
             mDisplayContentsAnimators.put(displayId, displayAnimator);
         }
         return displayAnimator;
@@ -820,14 +690,6 @@
     }
 
     private class DisplayContentsAnimator {
-        DimLayer mDimAnimator = null;
-        WindowStateAnimator mDimWinAnimator = null;
-        DimLayer mWindowAnimationBackgroundSurface = null;
         ScreenRotationAnimation mScreenRotationAnimation = null;
-
-        public DisplayContentsAnimator(int displayId) {
-            mDimAnimator = new DimLayer(mService, displayId);
-            mWindowAnimationBackgroundSurface = new DimLayer(mService, displayId);
-        }
     }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index ce40e73..e625cae 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -16,44 +16,27 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.*;
+
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
 import android.app.AppOpsManager;
 import android.util.TimeUtils;
 import android.view.IWindowId;
+
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.policy.impl.PhoneWindowManager;
+import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
 import com.android.server.AttributeCache;
 import com.android.server.EventLogTags;
+import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.display.DisplayManagerService;
@@ -62,6 +45,7 @@
 import com.android.server.power.ShutdownThread;
 
 import android.Manifest;
+import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.StatusBarManager;
@@ -77,7 +61,6 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -133,6 +116,7 @@
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
+import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -143,6 +127,7 @@
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerPolicy.FakeWindow;
+import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
@@ -166,7 +151,6 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.NoSuchElementException;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -176,6 +160,7 @@
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
     static final boolean DEBUG_FOCUS = false;
+    static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
     static final boolean DEBUG_ANIM = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_RESIZE = false;
@@ -200,6 +185,8 @@
     static final boolean DEBUG_LAYOUT_REPEATS = true;
     static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
+    static final boolean DEBUG_TASK_MOVEMENT = false;
+    static final boolean DEBUG_STACK = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -234,6 +221,11 @@
     static final int LAYER_OFFSET_BLUR = 2;
 
     /**
+     * FocusedStackFrame layer is immediately above focused window.
+     */
+    static final int LAYER_OFFSET_FOCUSED_STACK = 1;
+
+    /**
      * Animation thumbnail is as far as possible below the window above
      * the thumbnail (or in other words as far as possible above the window
      * below it).
@@ -263,6 +255,9 @@
     /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
     static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
 
+    /** Amount of time (in milliseconds) to delay before declaring a starting window leaked. */
+    static final int STARTING_WINDOW_TIMEOUT_DURATION = 10000;
+
     /**
      * If true, the window manager will do its own custom freezing and general
      * management of the screen during rotation.
@@ -276,6 +271,12 @@
     // Default input dispatching timeout in nanoseconds.
     static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
+    /** Minimum value for createStack and resizeStack weight value */
+    public static final float STACK_WEIGHT_MIN = 0.2f;
+
+    /** Maximum value for createStack and resizeStack weight value */
+    public static final float STACK_WEIGHT_MAX = 0.8f;
+
     static final int UPDATE_FOCUS_NORMAL = 0;
     static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
     static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
@@ -284,6 +285,9 @@
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
+    private static final String DENSITY_OVERRIDE = "ro.config.density_override";
+    private static final String SIZE_OVERRIDE = "ro.config.size_override";
+
     private static final int MAX_SCREENSHOT_RETRIES = 3;
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -337,34 +341,7 @@
     /**
      * Mapping from a token IBinder to a WindowToken object.
      */
-    final HashMap<IBinder, WindowToken> mTokenMap =
-            new HashMap<IBinder, WindowToken>();
-
-    /**
-     * Window tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
-
-    /**
-     * List controlling the ordering of windows in different applications which must
-     * be kept in sync with ActivityManager.
-     */
-    final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
-
-    /**
-     * AppWindowTokens in the Z order they were in at the start of an animation. Between
-     * animations this list is maintained in the exact order of mAppTokens. If tokens
-     * are added to mAppTokens during an animation an attempt is made to insert them at the same
-     * logical location in this list. Note that this list is always in sync with mWindows.
-     */
-    ArrayList<AppWindowToken> mAnimatingAppTokens = new ArrayList<AppWindowToken>();
-
-    /**
-     * Application tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
+    final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();
 
     /**
      * List of window tokens that have finished starting their application,
@@ -437,8 +414,12 @@
     final SurfaceSession mFxSession;
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
+    FocusedStackFrame mFocusedStackFrame;
+
+    int mFocusedStackLayer;
 
     final float[] mTmpFloats = new float[9];
+    final Rect mTmpContentRect = new Rect();
 
     boolean mDisplayReady;
     boolean mSafeMode;
@@ -449,8 +430,8 @@
 
     String mLastANRState;
 
-    /** All DisplayDontents in the world, kept here */
-    SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>();
+    /** All DisplayContents in the world, kept here */
+    SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2);
 
     int mRotation = 0;
     int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -486,7 +467,7 @@
     // This is held as long as we have the screen frozen, to give us time to
     // perform a rotation animation when turning off shows the lock screen which
     // changes the orientation.
-    private PowerManager.WakeLock mScreenFrozenLock;
+    private final PowerManager.WakeLock mScreenFrozenLock;
 
     final AppTransition mAppTransition;
     boolean mStartingIconInTransition = false;
@@ -589,7 +570,6 @@
         Object mLastWindowFreezeSource = null;
         private Session mHoldScreen = null;
         private boolean mObscured = false;
-        boolean mDimming = false;
         private boolean mSyswin = false;
         private float mScreenBrightness = -1;
         private float mButtonBrightness = -1;
@@ -604,22 +584,6 @@
     }
     final LayoutFields mInnerFields = new LayoutFields();
 
-    static class AppWindowAnimParams {
-        AppWindowAnimator mAppAnimator;
-        ArrayList<WindowStateAnimator> mWinAnimators;
-
-        public AppWindowAnimParams(final AppWindowAnimator appAnimator) {
-            mAppAnimator = appAnimator;
-
-            final AppWindowToken atoken = appAnimator.mAppToken;
-            mWinAnimators = new ArrayList<WindowStateAnimator>();
-            final int N = atoken.allAppWindows.size();
-            for (int i = 0; i < N; i++) {
-                mWinAnimators.add(atoken.allAppWindows.get(i).mWinAnimator);
-            }
-        }
-    }
-
     boolean mAnimationScheduled;
 
     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
@@ -631,6 +595,11 @@
 
     final WindowAnimator mAnimator;
 
+    SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
+    SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
+
+    private final PointerEventDispatcher mPointerEventDispatcher;
+
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
@@ -701,7 +670,7 @@
     boolean mInTouchMode = true;
 
     private ViewServer mViewServer;
-    private ArrayList<WindowChangeListener> mWindowChangeListeners =
+    private final ArrayList<WindowChangeListener> mWindowChangeListeners =
         new ArrayList<WindowChangeListener>();
     private boolean mWindowsChanged = false;
 
@@ -722,8 +691,7 @@
 
     public static WindowManagerService main(final Context context,
             final PowerManagerService pm, final DisplayManagerService dm,
-            final InputManagerService im,
-            final Handler uiHandler, final Handler wmHandler,
+            final InputManagerService im, final Handler wmHandler,
             final boolean haveInputMethods, final boolean showBootMsgs,
             final boolean onlyCore) {
         final WindowManagerService[] holder = new WindowManagerService[1];
@@ -731,7 +699,7 @@
             @Override
             public void run() {
                 holder[0] = new WindowManagerService(context, pm, dm, im,
-                        uiHandler, haveInputMethods, showBootMsgs, onlyCore);
+                        haveInputMethods, showBootMsgs, onlyCore);
             }
         }, 0);
         return holder[0];
@@ -753,7 +721,6 @@
 
     private WindowManagerService(Context context, PowerManagerService pm,
             DisplayManagerService displayManager, InputManagerService inputManager,
-            Handler uiHandler,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
         mContext = context;
         mHaveInputMethods = haveInputMethods;
@@ -761,11 +728,15 @@
         mOnlyCore = onlyCore;
         mLimitedAlphaCompositing = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_limitedAlpha);
+        mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerService = displayManager;
         mHeadless = displayManager.isHeadless();
         mDisplaySettings = new DisplaySettings(context);
         mDisplaySettings.readSettingsLocked();
 
+        mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));
+
+        mFxSession = new SurfaceSession();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         mDisplayManager.registerDisplayListener(this, null);
         Display[] displays = mDisplayManager.getDisplays();
@@ -787,9 +758,9 @@
         mBatteryStats = BatteryStatsService.getService();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
         mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null,
-                new AppOpsManager.Callback() {
+                new AppOpsManager.OnOpChangedInternalListener() {
                     @Override
-                    public void opChanged(int op, String packageName) {
+                    public void onOpChanged(int op, String packageName) {
                         updateAppOpsState();
                     }
                 }
@@ -812,11 +783,9 @@
                 | PowerManager.ON_AFTER_RELEASE, TAG);
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        mInputManager = inputManager;
-        mFxSession = new SurfaceSession();
         mAnimator = new WindowAnimator(this);
 
-        initPolicy(uiHandler);
+        initPolicy(UiThread.getHandler());
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
@@ -824,6 +793,8 @@
         SurfaceControl.openTransaction();
         try {
             createWatermarkInTransaction();
+            mFocusedStackFrame = new FocusedStackFrame(
+                    getDefaultDisplayContentLocked().getDisplay(), mFxSession);
         } finally {
             SurfaceControl.closeTransaction();
         }
@@ -842,7 +813,7 @@
             // The window manager only throws security exceptions, so let's
             // log all others.
             if (!(e instanceof SecurityException)) {
-                Log.wtf(TAG, "Window Manager Crash", e);
+                Slog.wtf(TAG, "Window Manager Crash", e);
             }
             throw e;
         }
@@ -860,10 +831,14 @@
 
     private void placeWindowBefore(WindowState pos, WindowState window) {
         final WindowList windows = pos.getWindowList();
-        final int i = windows.indexOf(pos);
+        int i = windows.indexOf(pos);
         if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
             TAG, "Adding window " + window + " at "
             + i + " of " + windows.size() + " (before " + pos + ")");
+        if (i < 0) {
+            Slog.w(TAG, "placeWindowBefore: Unable to find " + pos + " in " + windows);
+            i = 0;
+        }
         windows.add(i, window);
         mWindowsChanged = true;
     }
@@ -920,217 +895,262 @@
         return -1;
     }
 
-    private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
+    private int addAppWindowToListLocked(final WindowState win) {
         final IWindow client = win.mClient;
         final WindowToken token = win.mToken;
         final DisplayContent displayContent = win.mDisplayContent;
 
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
-        final WindowState attached = win.mAttachedWindow;
-        int i;
         WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
-        if (attached == null) {
-            int tokenWindowsPos = 0;
-            int windowListPos = tokenWindowList.size();
-            if (token.appWindowToken != null) {
-                int index = windowListPos - 1;
-                if (index >= 0) {
-                    // If this application has existing windows, we
-                    // simply place the new window on top of them... but
-                    // keep the starting window on top.
-                    if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
-                        // Base windows go behind everything else.
-                        WindowState lowestWindow = tokenWindowList.get(0);
-                        placeWindowBefore(lowestWindow, win);
-                        tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows);
-                    } else {
-                        AppWindowToken atoken = win.mAppToken;
-                        WindowState lastWindow = tokenWindowList.get(index);
-                        if (atoken != null && lastWindow == atoken.startingWindow) {
-                            placeWindowBefore(lastWindow, win);
-                            tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows);
-                        } else {
-                            int newIdx = findIdxBasedOnAppTokens(win);
-                            //there is a window above this one associated with the same
-                            //apptoken note that the window could be a floating window
-                            //that was created later or a window at the top of the list of
-                            //windows associated with this token.
-                            if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
-                                Slog.v(TAG, "Adding window " + win + " at "
-                                        + (newIdx + 1) + " of " + N);
-                            }
-                            windows.add(newIdx + 1, win);
-                            if (newIdx < 0) {
-                                // No window from token found on win's display.
-                                tokenWindowsPos = 0;
-                            } else {
-                                tokenWindowsPos = indexOfWinInWindowList(
-                                        windows.get(newIdx), token.windows) + 1;
-                            }
-                            mWindowsChanged = true;
-                        }
-                    }
+        int tokenWindowsPos = 0;
+        int windowListPos = tokenWindowList.size();
+        if (!tokenWindowList.isEmpty()) {
+            // If this application has existing windows, we
+            // simply place the new window on top of them... but
+            // keep the starting window on top.
+            if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
+                // Base windows go behind everything else.
+                WindowState lowestWindow = tokenWindowList.get(0);
+                placeWindowBefore(lowestWindow, win);
+                tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows);
+            } else {
+                AppWindowToken atoken = win.mAppToken;
+                WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
+                if (atoken != null && lastWindow == atoken.startingWindow) {
+                    placeWindowBefore(lastWindow, win);
+                    tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows);
                 } else {
-                    // No windows from this token on this display
-                    if (localLOGV) Slog.v(
-                        TAG, "Figuring out where to add app window "
-                        + client.asBinder() + " (token=" + token + ")");
-                    // Figure out where the window should go, based on the
-                    // order of applications.
-                    final int NA = mAnimatingAppTokens.size();
-                    WindowState pos = null;
-                    for (i=NA-1; i>=0; i--) {
-                        AppWindowToken t = mAnimatingAppTokens.get(i);
-                        if (t == token) {
-                            i--;
-                            break;
-                        }
-
-                        // We haven't reached the token yet; if this token
-                        // is not going to the bottom and has windows on this display, we can
-                        // use it as an anchor for when we do reach the token.
-                        tokenWindowList = getTokenWindowsOnDisplay(t, win.mDisplayContent);
-                        if (!t.sendingToBottom && tokenWindowList.size() > 0) {
-                            pos = tokenWindowList.get(0);
-                        }
-                    }
-                    // We now know the index into the apps.  If we found
-                    // an app window above, that gives us the position; else
-                    // we need to look some more.
-                    if (pos != null) {
-                        // Move behind any windows attached to this one.
-                        WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
-                        if (atoken != null) {
-                            tokenWindowList =
-                                    getTokenWindowsOnDisplay(atoken, win.mDisplayContent);
-                            final int NC = tokenWindowList.size();
-                            if (NC > 0) {
-                                WindowState bottom = tokenWindowList.get(0);
-                                if (bottom.mSubLayer < 0) {
-                                    pos = bottom;
-                                }
-                            }
-                        }
-                        placeWindowBefore(pos, win);
+                    int newIdx = findIdxBasedOnAppTokens(win);
+                    //there is a window above this one associated with the same
+                    //apptoken note that the window could be a floating window
+                    //that was created later or a window at the top of the list of
+                    //windows associated with this token.
+                    if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+                            "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
+                            N);
+                    windows.add(newIdx + 1, win);
+                    if (newIdx < 0) {
+                        // No window from token found on win's display.
+                        tokenWindowsPos = 0;
                     } else {
-                        // Continue looking down until we find the first
-                        // token that has windows on this display.
-                        while (i >= 0) {
-                            AppWindowToken t = mAnimatingAppTokens.get(i);
-                            tokenWindowList = getTokenWindowsOnDisplay(t, win.mDisplayContent);
-                            final int NW = tokenWindowList.size();
-                            if (NW > 0) {
-                                pos = tokenWindowList.get(NW-1);
-                                break;
-                            }
-                            i--;
-                        }
-                        if (pos != null) {
-                            // Move in front of any windows attached to this
-                            // one.
-                            WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
-                            if (atoken != null) {
-                                final int NC = atoken.windows.size();
-                                if (NC > 0) {
-                                    WindowState top = atoken.windows.get(NC-1);
-                                    if (top.mSubLayer >= 0) {
-                                        pos = top;
-                                    }
-                                }
-                            }
-                            placeWindowAfter(pos, win);
-                        } else {
-                            // Just search for the start of this layer.
-                            final int myLayer = win.mBaseLayer;
-                            for (i=0; i<N; i++) {
-                                WindowState w = windows.get(i);
-                                if (w.mBaseLayer > myLayer) {
-                                    break;
-                                }
-                            }
-                            if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
-                                Slog.v(TAG, "Adding window " + win + " at "
-                                        + i + " of " + N);
-                            }
-                            windows.add(i, win);
-                            mWindowsChanged = true;
+                        tokenWindowsPos = indexOfWinInWindowList(
+                                windows.get(newIdx), token.windows) + 1;
+                    }
+                    mWindowsChanged = true;
+                }
+            }
+            return tokenWindowsPos;
+        }
+
+        // No windows from this token on this display
+        if (localLOGV) Slog.v(TAG, "Figuring out where to add app window " + client.asBinder()
+                + " (token=" + token + ")");
+        // Figure out where the window should go, based on the
+        // order of applications.
+        WindowState pos = null;
+
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        int taskNdx;
+        int tokenNdx = -1;
+        for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            for (tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                final AppWindowToken t = tokens.get(tokenNdx);
+                if (t == token) {
+                    --tokenNdx;
+                    if (tokenNdx < 0) {
+                        --taskNdx;
+                        if (taskNdx >= 0) {
+                            tokenNdx = tasks.get(taskNdx).mAppTokens.size() - 1;
                         }
                     }
+                    break;
+                }
+
+                // We haven't reached the token yet; if this token
+                // is not going to the bottom and has windows on this display, we can
+                // use it as an anchor for when we do reach the token.
+                tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
+                if (!t.sendingToBottom && tokenWindowList.size() > 0) {
+                    pos = tokenWindowList.get(0);
+                }
+            }
+            if (tokenNdx >= 0) {
+                // early exit
+                break;
+            }
+        }
+
+        // We now know the index into the apps.  If we found
+        // an app window above, that gives us the position; else
+        // we need to look some more.
+        if (pos != null) {
+            // Move behind any windows attached to this one.
+            WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
+            if (atoken != null) {
+                tokenWindowList =
+                        getTokenWindowsOnDisplay(atoken, displayContent);
+                final int NC = tokenWindowList.size();
+                if (NC > 0) {
+                    WindowState bottom = tokenWindowList.get(0);
+                    if (bottom.mSubLayer < 0) {
+                        pos = bottom;
+                    }
+                }
+            }
+            placeWindowBefore(pos, win);
+            return tokenWindowsPos;
+        }
+
+        // Continue looking down until we find the first
+        // token that has windows on this display.
+        for ( ; taskNdx >= 0; --taskNdx) {
+            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            for ( ; tokenNdx >= 0; --tokenNdx) {
+                final AppWindowToken t = tokens.get(tokenNdx);
+                tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
+                final int NW = tokenWindowList.size();
+                if (NW > 0) {
+                    pos = tokenWindowList.get(NW-1);
+                    break;
+                }
+            }
+            if (tokenNdx >= 0) {
+                // found
+                break;
+            }
+        }
+
+        if (pos != null) {
+            // Move in front of any windows attached to this
+            // one.
+            WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
+            if (atoken != null) {
+                final int NC = atoken.windows.size();
+                if (NC > 0) {
+                    WindowState top = atoken.windows.get(NC-1);
+                    if (top.mSubLayer >= 0) {
+                        pos = top;
+                    }
+                }
+            }
+            placeWindowAfter(pos, win);
+            return tokenWindowsPos;
+        }
+
+        // Just search for the start of this layer.
+        final int myLayer = win.mBaseLayer;
+        int i;
+        for (i = 0; i < N; i++) {
+            WindowState w = windows.get(i);
+            if (w.mBaseLayer > myLayer) {
+                break;
+            }
+        }
+        if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+                "Based on layer: Adding window " + win + " at " + i + " of " + N);
+        windows.add(i, win);
+        mWindowsChanged = true;
+        return tokenWindowsPos;
+    }
+
+    private void addFreeWindowToListLocked(final WindowState win) {
+        final WindowList windows = win.getWindowList();
+
+        // Figure out where window should go, based on layer.
+        final int myLayer = win.mBaseLayer;
+        int i;
+        for (i = windows.size() - 1; i >= 0; i--) {
+            if (windows.get(i).mBaseLayer <= myLayer) {
+                break;
+            }
+        }
+        i++;
+        if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+                "Free window: Adding window " + win + " at " + i + " of " + windows.size());
+        windows.add(i, win);
+        mWindowsChanged = true;
+    }
+
+    private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
+        final WindowToken token = win.mToken;
+        final DisplayContent displayContent = win.mDisplayContent;
+        final WindowState attached = win.mAttachedWindow;
+
+        WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
+
+        // Figure out this window's ordering relative to the window
+        // it is attached to.
+        final int NA = tokenWindowList.size();
+        final int sublayer = win.mSubLayer;
+        int largestSublayer = Integer.MIN_VALUE;
+        WindowState windowWithLargestSublayer = null;
+        int i;
+        for (i = 0; i < NA; i++) {
+            WindowState w = tokenWindowList.get(i);
+            final int wSublayer = w.mSubLayer;
+            if (wSublayer >= largestSublayer) {
+                largestSublayer = wSublayer;
+                windowWithLargestSublayer = w;
+            }
+            if (sublayer < 0) {
+                // For negative sublayers, we go below all windows
+                // in the same sublayer.
+                if (wSublayer >= sublayer) {
+                    if (addToToken) {
+                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
+                        token.windows.add(i, win);
+                    }
+                    placeWindowBefore(wSublayer >= 0 ? attached : w, win);
+                    break;
                 }
             } else {
-                // Figure out where window should go, based on layer.
-                final int myLayer = win.mBaseLayer;
-                for (i=N-1; i>=0; i--) {
-                    if (windows.get(i).mBaseLayer <= myLayer) {
-                        break;
+                // For positive sublayers, we go above all windows
+                // in the same sublayer.
+                if (wSublayer > sublayer) {
+                    if (addToToken) {
+                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
+                        token.windows.add(i, win);
                     }
+                    placeWindowBefore(w, win);
+                    break;
                 }
-                i++;
-                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
-                        TAG, "Adding window " + win + " at "
-                        + i + " of " + N);
-                windows.add(i, win);
-                mWindowsChanged = true;
             }
+        }
+        if (i >= NA) {
+            if (addToToken) {
+                if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
+                token.windows.add(win);
+            }
+            if (sublayer < 0) {
+                placeWindowBefore(attached, win);
+            } else {
+                placeWindowAfter(largestSublayer >= 0
+                                 ? windowWithLargestSublayer
+                                 : attached,
+                                 win);
+            }
+        }
+    }
 
+    private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
+        if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
+                " Callers=" + Debug.getCallers(4));
+        if (win.mAttachedWindow == null) {
+            final WindowToken token = win.mToken;
+            int tokenWindowsPos = 0;
+            if (token.appWindowToken != null) {
+                tokenWindowsPos = addAppWindowToListLocked(win);
+            } else {
+                addFreeWindowToListLocked(win);
+            }
             if (addToToken) {
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
                 token.windows.add(tokenWindowsPos, win);
             }
-
         } else {
-            // Figure out this window's ordering relative to the window
-            // it is attached to.
-            final int NA = tokenWindowList.size();
-            final int sublayer = win.mSubLayer;
-            int largestSublayer = Integer.MIN_VALUE;
-            WindowState windowWithLargestSublayer = null;
-            for (i=0; i<NA; i++) {
-                WindowState w = tokenWindowList.get(i);
-                final int wSublayer = w.mSubLayer;
-                if (wSublayer >= largestSublayer) {
-                    largestSublayer = wSublayer;
-                    windowWithLargestSublayer = w;
-                }
-                if (sublayer < 0) {
-                    // For negative sublayers, we go below all windows
-                    // in the same sublayer.
-                    if (wSublayer >= sublayer) {
-                        if (addToToken) {
-                            if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
-                            token.windows.add(i, win);
-                        }
-                        placeWindowBefore(wSublayer >= 0 ? attached : w, win);
-                        break;
-                    }
-                } else {
-                    // For positive sublayers, we go above all windows
-                    // in the same sublayer.
-                    if (wSublayer > sublayer) {
-                        if (addToToken) {
-                            if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
-                            token.windows.add(i, win);
-                        }
-                        placeWindowBefore(w, win);
-                        break;
-                    }
-                }
-            }
-            if (i >= NA) {
-                if (addToToken) {
-                    if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
-                    token.windows.add(win);
-                }
-                if (sublayer < 0) {
-                    placeWindowBefore(attached, win);
-                } else {
-                    placeWindowAfter(largestSublayer >= 0
-                                     ? windowWithLargestSublayer
-                                     : attached,
-                                     win);
-                }
-            }
+            addAttachedWindowToListLocked(win, addToToken);
         }
 
         if (win.mAppToken != null && addToToken) {
@@ -1172,16 +1192,15 @@
         // same display. Or even when the current IME/target are not on the same screen as the next
         // IME/target. For now only look for input windows on the main screen.
         WindowList windows = getDefaultWindowListLocked();
-        final int N = windows.size();
         WindowState w = null;
-        int i = N;
-        while (i > 0) {
-            i--;
-            w = windows.get(i);
+        int i;
+        for (i = windows.size() - 1; i >= 0; --i) {
+            WindowState win = windows.get(i);
 
             if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i
-                    + " " + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags));
-            if (canBeImeTarget(w)) {
+                    + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
+            if (canBeImeTarget(win)) {
+                w = win;
                 //Slog.i(TAG, "Putting input method here!");
 
                 // Yet more tricksyness!  If this window is a "starting"
@@ -1546,10 +1565,6 @@
         return true;
     }
 
-    void adjustInputMethodDialogsLocked() {
-        moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
-    }
-
     final boolean isWallpaperVisible(WindowState wallpaperTarget) {
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
@@ -1573,8 +1588,8 @@
 
         // TODO(multidisplay): Wallpapers on main screen only.
         final DisplayInfo displayInfo = getDefaultDisplayContentLocked().getDisplayInfo();
-        final int dw = displayInfo.appWidth;
-        final int dh = displayInfo.appHeight;
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
 
         // First find top-most window that has asked to be on top of the
         // wallpaper; all wallpapers go behind it.
@@ -1840,15 +1855,36 @@
                 // Now stick it in.
                 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
                     Slog.v(TAG, "Moving wallpaper " + wallpaper
-                            + " from " + oldIndex + " to " + foundI);
+                            + " from " + oldIndex + " to " + 0);
                 }
 
-                windows.add(foundI, wallpaper);
+                windows.add(0, wallpaper);
                 mWindowsChanged = true;
                 changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
             }
         }
 
+        /*
+        final TaskStack targetStack =
+                mWallpaperTarget == null ? null : mWallpaperTarget.getStack();
+        if ((changed & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0 &&
+                targetStack != null && !targetStack.isHomeStack()) {
+            // If the wallpaper target is not on the home stack then make sure that all windows
+            // from other non-home stacks are above the wallpaper.
+            for (i = foundI - 1; i >= 0; --i) {
+                WindowState win = windows.get(i);
+                if (!win.isVisibleLw()) {
+                    continue;
+                }
+                final TaskStack winStack = win.getStack();
+                if (winStack != null && !winStack.isHomeStack() && winStack != targetStack) {
+                    windows.remove(i);
+                    windows.add(foundI + 1, win);
+                }
+            }
+        }
+        */
+
         if (targetChanged && DEBUG_WALLPAPER_LIGHT) {
             Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
                     + " lower=" + mLowerWallpaperTarget + " upper="
@@ -1967,8 +2003,8 @@
     void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
         final DisplayContent displayContent = changingTarget.mDisplayContent;
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final int dw = displayInfo.appWidth;
-        final int dh = displayInfo.appHeight;
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
 
         WindowState target = mWallpaperTarget;
         if (target != null) {
@@ -2027,8 +2063,8 @@
         final boolean visible = isWallpaperVisible(mWallpaperTarget);
         final DisplayContent displayContent = mWallpaperTarget.mDisplayContent;
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final int dw = displayInfo.appWidth;
-        final int dh = displayInfo.appHeight;
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
 
         int curTokenIndex = mWallpaperTokens.size();
         while (curTokenIndex > 0) {
@@ -2076,6 +2112,13 @@
 
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
             if (displayContent == null) {
+                Slog.w(TAG, "Attempted to add window to a display that does not exist: "
+                        + displayId + ".  Aborting.");
+                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
+            }
+            if (!displayContent.hasAccess(session.mUid)) {
+                Slog.w(TAG, "Attempted to add window to a display for which the application "
+                        + "does not have access: " + displayId + ".  Aborting.");
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
 
@@ -2099,6 +2142,11 @@
                 }
             }
 
+            if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
+                Slog.w(TAG, "Attempted to add private presentation window to a non-private display.  Aborting.");
+                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
+            }
+
             boolean addToken = false;
             WindowToken token = mTokenMap.get(attrs.token);
             if (token == null) {
@@ -2211,6 +2259,8 @@
                 token.appWindowToken.startingWindow = win;
                 if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
                         + " startingWindow=" + win);
+                Message m = mH.obtainMessage(H.REMOVE_STARTING_TIMEOUT, token.appWindowToken);
+                mH.sendMessageDelayed(m, STARTING_WINDOW_TIMEOUT_DURATION);
             }
 
             boolean imMayMove = true;
@@ -2223,7 +2273,7 @@
             } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                 mInputMethodDialogs.add(win);
                 addWindowToListInOrderLocked(win, true);
-                adjustInputMethodDialogsLocked();
+                moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
                 imMayMove = false;
             } else {
                 addWindowToListInOrderLocked(win, true);
@@ -2311,12 +2361,16 @@
     }
 
     public void removeWindowLocked(Session session, WindowState win) {
+        if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
+            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win);
+            removeStartingWindowTimeout(win.mAppToken);
+        }
 
-        if (localLOGV || DEBUG_FOCUS) Slog.v(
+        if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
             TAG, "Remove " + win + " client="
-            + Integer.toHexString(System.identityHashCode(
-                win.mClient.asBinder()))
-            + ", surface=" + win.mWinAnimator.mSurfaceControl);
+            + Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
+            + ", surface=" + win.mWinAnimator.mSurfaceControl,
+            new RuntimeException("here").fillInStackTrace());
 
         final long origId = Binder.clearCallingIdentity();
 
@@ -2366,7 +2420,6 @@
                 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                         false /*updateInputWindows*/);
                 performLayoutAndPlaceSurfacesLocked();
-                mInputMonitor.updateInputWindowsLw(false /*force*/);
                 if (win.mAppToken != null) {
                     win.mAppToken.updateReportedVisibilityLocked();
                 }
@@ -2454,6 +2507,7 @@
         if (atoken != null) {
             if (atoken.startingWindow == win) {
                 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling startingWindow " + win);
+                removeStartingWindowTimeout(atoken);
                 atoken.startingWindow = null;
             } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
                 // If this is the last window and we had requested a starting
@@ -2463,12 +2517,7 @@
             } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
                 // If this is the last window except for a starting transition
                 // window, we need to get rid of the starting transition.
-                if (DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG, "Schedule remove starting " + token
-                            + ": no more real windows");
-                }
-                Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
-                mH.sendMessage(m);
+                scheduleRemoveStartingWindow(atoken);
             }
         }
 
@@ -2495,22 +2544,19 @@
 
     public void updateAppOpsState() {
         synchronized(mWindowMap) {
-            boolean changed = false;
-            for (int i=0; i<mDisplayContents.size(); i++) {
-                DisplayContent display = mDisplayContents.valueAt(i);
-                WindowList windows = display.getWindowList();
-                for (int j=0; j<windows.size(); j++) {
-                    final WindowState win = windows.get(j);
+            final int numDisplays = mDisplayContents.size();
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+                final int numWindows = windows.size();
+                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+                    final WindowState win = windows.get(winNdx);
                     if (win.mAppOp != AppOpsManager.OP_NONE) {
-                        changed |= win.setAppOpVisibilityLw(mAppOps.checkOpNoThrow(win.mAppOp,
-                                win.getOwningUid(),
-                                win.getOwningPackage()) == AppOpsManager.MODE_ALLOWED);
+                        final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
+                                win.getOwningPackage());
+                        win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
                     }
                 }
             }
-            if (changed) {
-                scheduleAnimationLocked();
-            }
         }
     }
 
@@ -2747,7 +2793,7 @@
             if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
                     + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
 
-            win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
+            win.mEnforceSizeCompat = (win.mAttrs.flags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
 
             if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
                 winAnimator.mAlpha = attrs.alpha;
@@ -2946,7 +2992,7 @@
             if (toBeDisplayed && win.mIsWallpaper) {
                 DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
                 updateWallpaperOffsetLocked(win,
-                        displayInfo.appWidth, displayInfo.appHeight, false);
+                        displayInfo.logicalWidth, displayInfo.logicalHeight, false);
             }
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
@@ -3157,35 +3203,70 @@
     // Application Window Tokens
     // -------------------------------------------------------------
 
-    public void validateAppTokens(List<IBinder> tokens) {
-        int v = tokens.size()-1;
-        int m = mAppTokens.size()-1;
-        while (v >= 0 && m >= 0) {
-            AppWindowToken atoken = mAppTokens.get(m);
-            if (atoken.removed) {
-                m--;
-                continue;
+    public void validateAppTokens(int stackId, List<TaskGroup> tasks) {
+        synchronized (mWindowMap) {
+            int t = tasks.size() - 1;
+            if (t < 0) {
+                Slog.w(TAG, "validateAppTokens: empty task list");
+                return;
             }
-            if (tokens.get(v) != atoken.token) {
-                Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
-                      + " @ " + v + ", internal is " + atoken.token + " @ " + m);
+
+            TaskGroup task = tasks.get(0);
+            int taskId = task.taskId;
+            Task targetTask = mTaskIdToTask.get(taskId);
+            DisplayContent displayContent = targetTask.getDisplayContent();
+            if (displayContent == null) {
+                Slog.w(TAG, "validateAppTokens: no Display for taskId=" + taskId);
+                return;
             }
-            v--;
-            m--;
-        }
-        while (v >= 0) {
-            Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
-            v--;
-        }
-        while (m >= 0) {
-            AppWindowToken atoken = mAppTokens.get(m);
-            if (!atoken.removed) {
-                Slog.w(TAG, "Invalid internal atoken: " + atoken.token + " @ " + m);
+
+            final ArrayList<Task> localTasks = mStackIdToStack.get(stackId).getTasks();
+            int taskNdx;
+            for (taskNdx = localTasks.size() - 1; taskNdx >= 0 && t >= 0; --taskNdx, --t) {
+                AppTokenList localTokens = localTasks.get(taskNdx).mAppTokens;
+                task = tasks.get(t);
+                List<IApplicationToken> tokens = task.tokens;
+
+                DisplayContent lastDisplayContent = displayContent;
+                displayContent = mTaskIdToTask.get(taskId).getDisplayContent();
+                if (displayContent != lastDisplayContent) {
+                    Slog.w(TAG, "validateAppTokens: displayContent changed in TaskGroup list!");
+                    return;
+                }
+
+                int tokenNdx;
+                int v;
+                for (tokenNdx = localTokens.size() - 1, v = task.tokens.size() - 1;
+                        tokenNdx >= 0 && v >= 0; ) {
+                    final AppWindowToken atoken = localTokens.get(tokenNdx);
+                    if (atoken.removed) {
+                        --tokenNdx;
+                        continue;
+                    }
+                    if (tokens.get(v) != atoken.token) {
+                        break;
+                    }
+                    --tokenNdx;
+                    v--;
+                }
+
+                if (tokenNdx >= 0 || v >= 0) {
+                    break;
+                }
             }
-            m--;
+
+            if (taskNdx >= 0 || t >= 0) {
+                Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks);
+                Slog.w(TAG, "validateAppTokens: Mismatch! WindowManager=" + localTasks);
+                Slog.w(TAG, "validateAppTokens: Mismatch! Callers=" + Debug.getCallers(4));
+            }
         }
     }
 
+    public void validateStackOrder(Integer[] remoteStackIds) {
+        // TODO:
+    }
+
     boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -3246,6 +3327,7 @@
 
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
+            DisplayContent displayContent = null;
             WindowToken wtoken = mTokenMap.remove(token);
             if (wtoken != null) {
                 boolean delayed = false;
@@ -3255,6 +3337,7 @@
 
                     for (int i=0; i<N; i++) {
                         WindowState win = wtoken.windows.get(i);
+                        displayContent = win.mDisplayContent;
 
                         if (win.mWinAnimator.isAnimating()) {
                             delayed = true;
@@ -3264,13 +3347,12 @@
                             win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT,
                                     false);
                             //TODO (multidisplay): Magnification is supported only for the default
-                            if (mDisplayMagnifier != null
-                                    && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
+                            if (mDisplayMagnifier != null && win.isDefaultDisplay()) {
                                 mDisplayMagnifier.onWindowTransitionLocked(win,
                                         WindowManagerPolicy.TRANSIT_EXIT);
                             }
                             changed = true;
-                            win.mDisplayContent.layoutNeeded = true;
+                            displayContent.layoutNeeded = true;
                         }
                     }
 
@@ -3283,7 +3365,7 @@
                     }
 
                     if (delayed) {
-                        mExitingTokens.add(wtoken);
+                        displayContent.mExitingTokens.add(wtoken);
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
@@ -3297,27 +3379,21 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    /**
-     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
-     *  Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1.
-     * @param addPos The location the token was inserted into in mAppTokens.
-     * @param atoken The token to insert.
-     */
-    private void addAppTokenToAnimating(final int addPos, final AppWindowToken atoken) {
-        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
-            // It was inserted into the beginning or end of mAppTokens. Honor that.
-            mAnimatingAppTokens.add(addPos, atoken);
-            return;
+    private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) {
+        final TaskStack stack = mStackIdToStack.get(stackId);
+        if (stack == null) {
+            throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
-        // Find the item immediately above the mAppTokens insertion point and put the token
-        // immediately below that one in mAnimatingAppTokens.
-        final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
-        mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
+        Task task = new Task(atoken, stack, userId);
+        stack.addTask(task, true);
+        stack.getDisplayContent().moveStack(stack, true);
+        mTaskIdToTask.put(taskId, task);
+        return task;
     }
 
     @Override
-    public void addAppToken(int addPos, IApplicationToken token,
-            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
+    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3345,14 +3421,20 @@
             }
             atoken = new AppWindowToken(this, token);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-            atoken.groupId = groupId;
+            atoken.groupId = taskId;
             atoken.appFullscreen = fullscreen;
             atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
-                    + " at " + addPos);
-            mAppTokens.add(addPos, atoken);
-            addAppTokenToAnimating(addPos, atoken);
+                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
+
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                task = createTask(taskId, stackId, userId, atoken);
+            } else {
+                task.addAppToken(addPos, atoken);
+            }
+
             mTokenMap.put(token.asBinder(), atoken);
 
             // Application tokens start out hidden.
@@ -3371,12 +3453,20 @@
         }
 
         synchronized(mWindowMap) {
-            AppWindowToken atoken = findAppWindowToken(token);
+            final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
                 return;
             }
+            Task oldTask = mTaskIdToTask.get(atoken.groupId);
+            oldTask.removeAppToken(atoken);
+
             atoken.groupId = groupId;
+            Task newTask = mTaskIdToTask.get(groupId);
+            if (newTask == null) {
+                newTask = createTask(groupId, oldTask.mStack.mStackId, oldTask.mUserId, atoken);
+            }
+            newTask.mAppTokens.add(atoken);
         }
     }
 
@@ -3417,72 +3507,76 @@
     }
 
     public int getOrientationFromAppTokensLocked() {
-        int curGroup = 0;
         int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
         boolean findingBehind = false;
-        boolean haveGroup = false;
         boolean lastFullscreen = false;
-        for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) {
-            AppWindowToken atoken = mAppTokens.get(pos);
+        // TODO: Multi window.
+        DisplayContent displayContent = getDefaultDisplayContentLocked();
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int firstToken = tokens.size() - 1;
+            for (int tokenNdx = firstToken; tokenNdx >= 0; --tokenNdx) {
+                final AppWindowToken atoken = tokens.get(tokenNdx);
 
-            if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + atoken);
+                if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + atoken);
 
-            // if we're about to tear down this window and not seek for
-            // the behind activity, don't use it for orientation
-            if (!findingBehind
-                    && (!atoken.hidden && atoken.hiddenRequested)) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
-                        + " -- going to hide");
-                continue;
-            }
-
-            if (haveGroup == true && curGroup != atoken.groupId) {
-                // If we have hit a new application group, and the bottom
-                // of the previous group didn't explicitly say to use
-                // the orientation behind it, and the last app was
-                // full screen, then we'll stick with the
-                // user's orientation.
-                if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
-                        && lastFullscreen) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
-                            + " -- end of group, return " + lastOrientation);
-                    return lastOrientation;
+                // if we're about to tear down this window and not seek for
+                // the behind activity, don't use it for orientation
+                if (!findingBehind
+                        && (!atoken.hidden && atoken.hiddenRequested)) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
+                            + " -- going to hide");
+                    continue;
                 }
-            }
 
-            // We ignore any hidden applications on the top.
-            if (atoken.hiddenRequested || atoken.willBeHidden) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
-                        + " -- hidden on top");
-                continue;
-            }
+                if (tokenNdx == firstToken) {
+                    // If we have hit a new Task, and the bottom
+                    // of the previous group didn't explicitly say to use
+                    // the orientation behind it, and the last app was
+                    // full screen, then we'll stick with the
+                    // user's orientation.
+                    if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
+                            && lastFullscreen) {
+                        if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
+                                + " -- end of group, return " + lastOrientation);
+                        return lastOrientation;
+                    }
+                }
 
-            if (!haveGroup) {
-                haveGroup = true;
-                curGroup = atoken.groupId;
-                lastOrientation = atoken.requestedOrientation;
-            }
+                // We ignore any hidden applications on the top.
+                if (atoken.hiddenRequested || atoken.willBeHidden) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
+                            + " -- hidden on top");
+                    continue;
+                }
 
-            int or = atoken.requestedOrientation;
-            // If this application is fullscreen, and didn't explicitly say
-            // to use the orientation behind it, then just take whatever
-            // orientation it has and ignores whatever is under it.
-            lastFullscreen = atoken.appFullscreen;
-            if (lastFullscreen
-                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
-                        + " -- full screen, return " + or);
-                return or;
+                if (tokenNdx == 0) {
+                    // Last token in this task.
+                    lastOrientation = atoken.requestedOrientation;
+                }
+
+                int or = atoken.requestedOrientation;
+                // If this application is fullscreen, and didn't explicitly say
+                // to use the orientation behind it, then just take whatever
+                // orientation it has and ignores whatever is under it.
+                lastFullscreen = atoken.appFullscreen;
+                if (lastFullscreen
+                        && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
+                            + " -- full screen, return " + or);
+                    return or;
+                }
+                // If this application has requested an explicit orientation,
+                // then use it.
+                if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+                        && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
+                            + " -- explicitly set, return " + or);
+                    return or;
+                }
+                findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
             }
-            // If this application has requested an explicit orientation,
-            // then use it.
-            if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
-                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
-                        + " -- explicitly set, return " + or);
-                return or;
-            }
-            findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
         }
         if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
         return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -3531,9 +3625,10 @@
             if (computeScreenConfigurationLocked(mTempConfiguration)) {
                 if (currentConfig.diff(mTempConfiguration) != 0) {
                     mWaitingForConfig = true;
-                    getDefaultDisplayContentLocked().layoutNeeded = true;
+                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                    displayContent.layoutNeeded = true;
                     int anim[] = new int[2];
-                    if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
+                    if (displayContent.isDimming()) {
                         anim[0] = anim[1] = 0;
                     } else {
                         mPolicy.selectRotationAnimationLw(anim);
@@ -3633,6 +3728,52 @@
         }
     }
 
+    /** Call while in a Surface transaction. */
+    void setFocusedStackLayer() {
+        mFocusedStackLayer = 0;
+        if (mFocusedApp != null) {
+            final WindowList windows = mFocusedApp.allAppWindows;
+            for (int i = windows.size() - 1; i >= 0; --i) {
+                final WindowState win = windows.get(i);
+                final int animLayer = win.mWinAnimator.mAnimLayer;
+                if (win.mAttachedWindow == null && win.isVisibleLw() &&
+                        animLayer > mFocusedStackLayer) {
+                    mFocusedStackLayer = animLayer + LAYER_OFFSET_FOCUSED_STACK;
+                }
+            }
+        }
+        if (DEBUG_LAYERS) Slog.v(TAG, "Setting FocusedStackFrame to layer=" +
+                mFocusedStackLayer);
+        mFocusedStackFrame.setLayer(mFocusedStackLayer);
+    }
+
+    void setFocusedStackFrame() {
+        final TaskStack stack;
+        if (mFocusedApp != null) {
+            Task task = mTaskIdToTask.get(mFocusedApp.groupId);
+            stack = task.mStack;
+            task.getDisplayContent().setTouchExcludeRegion(stack);
+        } else {
+            stack = null;
+        }
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedStackFrame");
+        SurfaceControl.openTransaction();
+        try {
+            if (stack == null) {
+                mFocusedStackFrame.setVisibility(false);
+            } else {
+                final StackBox box = stack.mStackBox;
+                final Rect bounds = box.mBounds;
+                final boolean multipleStacks = box.mParent != null;
+                mFocusedStackFrame.setBounds(bounds);
+                mFocusedStackFrame.setVisibility(multipleStacks);
+            }
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedStackFrame");
+        }
+    }
+
     @Override
     public void setFocusedApp(IBinder token, boolean moveFocusNow) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -3643,7 +3784,7 @@
         synchronized(mWindowMap) {
             boolean changed = false;
             if (token == null) {
-                if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
+                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
                 changed = mFocusedApp != null;
                 mFocusedApp = null;
                 if (changed) {
@@ -3656,9 +3797,9 @@
                     return;
                 }
                 changed = mFocusedApp != newFocus;
+                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus
+                        + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow);
                 mFocusedApp = newFocus;
-                if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp
-                        + " moveFocusNow=" + moveFocusNow);
                 if (changed) {
                     mInputMonitor.setFocusedAppLw(newFocus);
                 }
@@ -3767,7 +3908,7 @@
     @Override
     public void setAppStartingWindow(IBinder token, String pkg,
             int theme, CompatibilityInfo compatInfo,
-            CharSequence nonLocalizedLabel, int labelRes, int icon,
+            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
             int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppStartingWindow()")) {
@@ -3832,6 +3973,7 @@
                         if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
                             Slog.v(TAG, "Removing starting window: " + startingWindow);
                         }
+                        removeStartingWindowTimeout(ttoken);
                         startingWindow.getWindowList().remove(startingWindow);
                         mWindowsChanged = true;
                         if (DEBUG_ADD_REMOVE) Slog.v(TAG,
@@ -3968,7 +4110,7 @@
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData");
             mStartingIconInTransition = true;
             wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
-                    labelRes, icon, windowFlags);
+                    labelRes, icon, logo, windowFlags);
             Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
             // Note: we really want to do sendMessageAtFrontOfQueue() because we
             // want to process the message ASAP, before any other queued
@@ -3997,6 +4139,14 @@
         }
     }
 
+    public void setAppFullscreen(IBinder token, boolean toOpaque) {
+        AppWindowToken atoken = findAppWindowToken(token);
+        if (atoken != null) {
+            atoken.appFullscreen = toOpaque;
+            requestTraversal();
+        }
+    }
+
     boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
             boolean visible, int transit, boolean performLayout) {
         boolean delayed = false;
@@ -4346,11 +4496,13 @@
                         TAG, "Removing app " + wtoken + " delayed=" + delayed
                         + " animation=" + wtoken.mAppAnimator.animation
                         + " animating=" + wtoken.mAppAnimator.animating);
+                final Task task = mTaskIdToTask.get(wtoken.groupId);
+                DisplayContent displayContent = task.getDisplayContent();
                 if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
-                    mExitingAppTokens.add(wtoken);
+                    displayContent.mExitingAppTokens.add(wtoken);
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
@@ -4360,15 +4512,17 @@
                 }
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
-                mAppTokens.remove(wtoken);
-                mAnimatingAppTokens.remove(wtoken);
+
+                if (task.removeAppToken(wtoken)) {
+                    mTaskIdToTask.delete(wtoken.groupId);
+                }
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
                 }
                 unsetAppFreezingScreenLocked(wtoken, true, true);
                 if (mFocusedApp == wtoken) {
-                    if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
+                    if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Removing focused app token:" + wtoken);
                     mFocusedApp = null;
                     updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
                     mInputMonitor.setFocusedAppLw(null);
@@ -4383,14 +4537,29 @@
         }
         Binder.restoreCallingIdentity(origId);
 
-        if (startingToken != null) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Schedule remove starting "
-                    + startingToken + ": app token removed");
-            Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
-            mH.sendMessage(m);
+        // Will only remove if startingToken non null.
+        scheduleRemoveStartingWindow(startingToken);
+    }
+
+    void removeStartingWindowTimeout(AppWindowToken wtoken) {
+        if (wtoken != null) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) +
+                    ": Remove starting window timeout " + wtoken + (wtoken != null ?
+                    " startingWindow=" + wtoken.startingWindow : ""));
+            mH.removeMessages(H.REMOVE_STARTING_TIMEOUT, wtoken);
         }
     }
 
+    void scheduleRemoveStartingWindow(AppWindowToken wtoken) {
+        if (wtoken != null && wtoken.startingWindow != null) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) +
+                    ": Schedule remove starting " + wtoken + (wtoken != null ?
+                    " startingWindow=" + wtoken.startingWindow : ""));
+            removeStartingWindowTimeout(wtoken);
+            Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
+            mH.sendMessage(m);
+        }
+    }
     private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
         final int NW = token.windows.size();
         if (NW > 0) {
@@ -4413,14 +4582,19 @@
     }
 
     void dumpAppTokensLocked() {
-        for (int i=mAppTokens.size()-1; i>=0; i--) {
-            Slog.v(TAG, "  #" + i + ": " + mAppTokens.get(i).token);
-        }
-    }
-
-    void dumpAnimatingAppTokensLocked() {
-        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
-            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
+        final int numDisplays = mDisplayContents.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+            Slog.v(TAG, "  Display " + displayContent.getDisplayId());
+            final ArrayList<Task> tasks = displayContent.getTasks();
+            int i = displayContent.numTokens();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    Slog.v(TAG, "  #" + --i + ": " + wtoken.token);
+                }
+            }
         }
     }
 
@@ -4430,66 +4604,79 @@
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState w = windows.get(winNdx);
-                Slog.v(TAG, "  #" + i++ + ": " + w);
+                Slog.v(TAG, "  #" + i++ + ": " + windows.get(winNdx));
             }
         }
     }
 
-    private int findWindowOffsetLocked(WindowList windows, int tokenPos) {
+    private int findAppWindowInsertionPointLocked(AppWindowToken target) {
+        final int taskId = target.groupId;
+        Task targetTask = mTaskIdToTask.get(taskId);
+        if (targetTask == null) {
+            Slog.w(TAG, "findAppWindowInsertionPointLocked: no Task for " + target + " taskId="
+                    + taskId);
+            return 0;
+        }
+        DisplayContent displayContent = targetTask.getDisplayContent();
+        if (displayContent == null) {
+            Slog.w(TAG, "findAppWindowInsertionPointLocked: no DisplayContent for " + target);
+            return 0;
+        }
+        final WindowList windows = displayContent.getWindowList();
         final int NW = windows.size();
 
-        if (tokenPos >= mAnimatingAppTokens.size()) {
-            int i = NW;
-            while (i > 0) {
-                i--;
-                WindowState win = windows.get(i);
-                if (win.getAppToken() != null) {
-                    return i+1;
-                }
-            }
-        }
-
-        while (tokenPos > 0) {
-            // Find the first app token below the new position that has
-            // a window displayed.
-            final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
-            if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
-                    + tokenPos + " -- " + wtoken.token);
-            if (wtoken.sendingToBottom) {
-                if (DEBUG_REORDER) Slog.v(TAG,
-                        "Skipping token -- currently sending to bottom");
-                tokenPos--;
+        boolean found = false;
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = tasks.get(taskNdx);
+            if (!found && task.taskId != taskId) {
                 continue;
             }
-            int i = wtoken.windows.size();
-            while (i > 0) {
-                i--;
-                WindowState win = wtoken.windows.get(i);
-                int j = win.mChildWindows.size();
-                while (j > 0) {
-                    j--;
-                    WindowState cwin = win.mChildWindows.get(j);
-                    if (cwin.mSubLayer >= 0) {
-                        for (int pos=NW-1; pos>=0; pos--) {
-                            if (windows.get(pos) == cwin) {
-                                if (DEBUG_REORDER) Slog.v(TAG,
-                                        "Found child win @" + (pos+1));
-                                return pos+1;
+            AppTokenList tokens = task.mAppTokens;
+            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                final AppWindowToken wtoken = tokens.get(tokenNdx);
+                if (!found && wtoken == target) {
+                    found = true;
+                }
+                if (found) {
+                    // Find the first app token below the new position that has
+                    // a window displayed.
+                    if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows in " + wtoken.token);
+                    if (wtoken.sendingToBottom) {
+                        if (DEBUG_REORDER) Slog.v(TAG, "Skipping token -- currently sending to bottom");
+                        continue;
+                    }
+                    for (int i = wtoken.windows.size() - 1; i >= 0; --i) {
+                        WindowState win = wtoken.windows.get(i);
+                        for (int j = win.mChildWindows.size() - 1; j >= 0; --j) {
+                            WindowState cwin = win.mChildWindows.get(j);
+                            if (cwin.mSubLayer >= 0) {
+                                for (int pos = NW - 1; pos >= 0; pos--) {
+                                    if (windows.get(pos) == cwin) {
+                                        if (DEBUG_REORDER) Slog.v(TAG,
+                                                "Found child win @" + (pos + 1));
+                                        return pos + 1;
+                                    }
+                                }
+                            }
+                        }
+                        for (int pos = NW - 1; pos >= 0; pos--) {
+                            if (windows.get(pos) == win) {
+                                if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos + 1));
+                                return pos + 1;
                             }
                         }
                     }
                 }
-                for (int pos=NW-1; pos>=0; pos--) {
-                    if (windows.get(pos) == win) {
-                        if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos+1));
-                        return pos+1;
-                    }
-                }
             }
-            tokenPos--;
         }
-
+        // Never put an app window underneath wallpaper.
+        for (int pos = NW - 1; pos >= 0; pos--) {
+            if (windows.get(pos).mIsWallpaper) {
+                if (DEBUG_REORDER) Slog.v(TAG, "Found wallpaper @" + pos);
+                return pos + 1;
+            }
+        }
         return 0;
     }
 
@@ -4536,198 +4723,229 @@
         return index;
     }
 
-    @Override
-    public void moveAppToken(int index, IBinder token) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "moveAppToken()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
-            if (DEBUG_REORDER) dumpAppTokensLocked();
-            final AppWindowToken wtoken = findAppWindowToken(token);
-            final int oldIndex = mAppTokens.indexOf(wtoken);
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
-                    "Start moving token " + wtoken + " initially at "
-                    + oldIndex);
-            if (oldIndex > index && mAppTransition.isTransitionSet()) {
-                // animation towards back has not started, copy old list for duration of animation.
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
-            }
-            if (wtoken == null || !mAppTokens.remove(wtoken)) {
-                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
-                      + token + " (" + wtoken + ")");
-                return;
-            }
-            mAppTokens.add(index, wtoken);
-            if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
-            else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
-            if (DEBUG_REORDER) dumpAppTokensLocked();
-            if (!mAppTransition.isTransitionSet()) {
-                // Not animating, bring animating app list in line with mAppTokens.
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
-
-                // Bring window ordering, window focus and input window in line with new app token
-                final long origId = Binder.clearCallingIdentity();
-                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
-                if (DEBUG_REORDER) dumpWindowsLocked();
-                if (tmpRemoveAppWindowsLocked(wtoken)) {
-                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
-                    if (DEBUG_REORDER) dumpWindowsLocked();
-                    final int numDisplays = mDisplayContents.size();
-                    for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                        final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                        final WindowList windows = displayContent.getWindowList();
-                        final int pos = findWindowOffsetLocked(windows, index);
-                        final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
-                        if (pos != newPos) {
-                            displayContent.layoutNeeded = true;
-                        }
-                    }
-                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
-                    if (DEBUG_REORDER) dumpWindowsLocked();
-                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                            false /*updateInputWindows*/);
-                    mInputMonitor.setUpdateInputWindowsNeededLw();
-                    performLayoutAndPlaceSurfacesLocked();
-                    mInputMonitor.updateInputWindowsLw(false /*force*/);
+    private void moveHomeTasksLocked(boolean toTop) {
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        if (toTop ^ displayContent.homeOnTop()) {
+            final ArrayList<Task> tasks = displayContent.getHomeStack().getTasks();
+            final int numTasks = tasks.size();
+            for (int i = 0; i < numTasks; ++i) {
+                if (toTop) {
+                    // Keep pulling the bottom task off and moving it to the top.
+                    moveTaskToTop(tasks.get(0).taskId);
+                } else {
+                    // Keep pulling the top task off and moving it to the bottom.
+                    moveTaskToBottom(tasks.get(numTasks - 1).taskId);
                 }
-                Binder.restoreCallingIdentity(origId);
             }
         }
     }
 
-    private void removeAppTokensLocked(List<IBinder> tokens) {
-        // XXX This should be done more efficiently!
-        // (take advantage of the fact that both lists should be
-        // ordered in the same way.)
-        int N = tokens.size();
-        for (int i=0; i<N; i++) {
-            IBinder token = tokens.get(i);
-            final AppWindowToken wtoken = findAppWindowToken(token);
-            if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                    "Temporarily removing " + wtoken + " from " + mAppTokens.indexOf(wtoken));
-            if (!mAppTokens.remove(wtoken)) {
-                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
-                      + token + " (" + wtoken + ")");
-                i--;
-                N--;
-            }
-        }
-    }
+    void moveStackWindowsLocked(TaskStack stack) {
+        DisplayContent displayContent = stack.getDisplayContent();
 
-    private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
         // First remove all of the windows from the list.
-        final int N = tokens.size();
-        int i;
-        for (i=0; i<N; i++) {
-            WindowToken token = mTokenMap.get(tokens.get(i));
-            if (token != null) {
-                tmpRemoveAppWindowsLocked(token);
+        final ArrayList<Task> tasks = stack.getTasks();
+        final int numTasks = tasks.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int numTokens = tokens.size();
+            for (int tokenNdx = numTokens - 1; tokenNdx >= 0; --tokenNdx) {
+                tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
             }
         }
 
         // And now add them back at the correct place.
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            final WindowList windows = displayContent.getWindowList();
-            // Where to start adding?
-            int pos = findWindowOffsetLocked(windows, tokenPos);
-            for (i=0; i<N; i++) {
-                WindowToken token = mTokenMap.get(tokens.get(i));
-                if (token != null) {
-                    final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
+        // Where to start adding?
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            int pos = findAppWindowInsertionPointLocked(tokens.get(0));
+            final int numTokens = tokens.size();
+            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                final AppWindowToken wtoken = tokens.get(tokenNdx);
+                if (wtoken != null) {
+                    final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
                     if (newPos != pos) {
                         displayContent.layoutNeeded = true;
                     }
                     pos = newPos;
                 }
             }
-            if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                    false /*updateInputWindows*/)) {
-                assignLayersLocked(windows);
-            }
+        }
+
+        if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+                false /*updateInputWindows*/)) {
+            assignLayersLocked(displayContent.getWindowList());
         }
 
         mInputMonitor.setUpdateInputWindowsNeededLw();
-
-        // Note that the above updateFocusedWindowLocked used to sit here.
-
         performLayoutAndPlaceSurfacesLocked();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
 
         //dump();
     }
 
-    @Override
-    public void moveAppTokensToTop(List<IBinder> tokens) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "moveAppTokensToTop()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
+    public void moveTaskToTop(int taskId) {
         final long origId = Binder.clearCallingIdentity();
-        synchronized(mWindowMap) {
-            removeAppTokensLocked(tokens);
-            final int N = tokens.size();
-            for (int i=0; i<N; i++) {
-                AppWindowToken wt = findAppWindowToken(tokens.get(i));
-                if (wt != null) {
-                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
-                            "Adding next to top: " + wt);
-                    mAppTokens.add(wt);
-                    if (mAppTransition.isTransitionSet()) {
-                        wt.sendingToBottom = false;
-                    }
+        try {
+            synchronized(mWindowMap) {
+                Task task = mTaskIdToTask.get(taskId);
+                if (task == null) {
+                    // Normal behavior, addAppToken will be called next and task will be created.
+                    return;
                 }
+                final TaskStack stack = task.mStack;
+                final DisplayContent displayContent = task.getDisplayContent();
+                final boolean isHomeStackTask = stack.isHomeStack();
+                final boolean homeIsOnTop = displayContent.homeOnTop();
+                if (!isHomeStackTask && homeIsOnTop) {
+                    // First move move the home tasks all to the bottom to rearrange the windows.
+                    moveHomeTasksLocked(false);
+                    // Now move the stack itself.
+                    displayContent.moveHomeStackBox(false);
+                } else if (isHomeStackTask && !homeIsOnTop) {
+                    // Move the stack to the top.
+                    displayContent.moveHomeStackBox(true);
+                }
+                stack.moveTaskToTop(task);
+                displayContent.moveStack(stack, true);
             }
-
-            mAnimatingAppTokens.clear();
-            mAnimatingAppTokens.addAll(mAppTokens);
-            moveAppWindowsLocked(tokens, mAppTokens.size());
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        Binder.restoreCallingIdentity(origId);
     }
 
-    @Override
-    public void moveAppTokensToBottom(List<IBinder> tokens) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "moveAppTokensToBottom()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
+    public void moveTaskToBottom(int taskId) {
         final long origId = Binder.clearCallingIdentity();
-        synchronized(mWindowMap) {
-            final int N = tokens.size();
-            if (N > 0) {
-                // animating towards back, hang onto old list for duration of animation.
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
+        try {
+            synchronized(mWindowMap) {
+                Task task = mTaskIdToTask.get(taskId);
+                if (task == null) {
+                    Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
+                            + " not found in mTaskIdToTask");
+                    return;
+                }
+                final TaskStack stack = task.mStack;
+                stack.moveTaskToBottom(task);
+                moveStackWindowsLocked(stack);
             }
-            removeAppTokensLocked(tokens);
-            int pos = 0;
-            for (int i=0; i<N; i++) {
-                AppWindowToken wt = findAppWindowToken(tokens.get(i));
-                if (wt != null) {
-                    if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                            "Adding next to bottom: " + wt + " at " + pos);
-                    mAppTokens.add(pos, wt);
-                    if (mAppTransition.isTransitionSet()) {
-                        wt.sendingToBottom = true;
-                    }
-                    pos++;
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    /**
+     * Create a new TaskStack and place it next to an existing stack.
+     * @param stackId The unique identifier of the new stack.
+     * @param relativeStackBoxId The existing stack that this stack goes before or after.
+     * @param position One of:
+     *      {@link StackBox#TASK_STACK_GOES_BEFORE}
+     *      {@link StackBox#TASK_STACK_GOES_AFTER}
+     *      {@link StackBox#TASK_STACK_GOES_ABOVE}
+     *      {@link StackBox#TASK_STACK_GOES_BELOW}
+     *      {@link StackBox#TASK_STACK_GOES_UNDER}
+     *      {@link StackBox#TASK_STACK_GOES_OVER}
+     * @param weight Relative weight for determining how big to make the new TaskStack.
+     */
+    public void createStack(int stackId, int relativeStackBoxId, int position, float weight) {
+        synchronized (mWindowMap) {
+            if (position <= StackBox.TASK_STACK_GOES_BELOW &&
+                    (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX)) {
+                throw new IllegalArgumentException(
+                        "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
+                        STACK_WEIGHT_MAX + ", weight=" + weight);
+            }
+            final int numDisplays = mDisplayContents.size();
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+                TaskStack stack = displayContent.createStack(stackId, relativeStackBoxId, position,
+                        weight);
+                if (stack != null) {
+                    mStackIdToStack.put(stackId, stack);
+                    displayContent.moveStack(stack, true);
+                    performLayoutAndPlaceSurfacesLocked();
+                    return;
                 }
             }
-
-            mAnimatingAppTokens.clear();
-            mAnimatingAppTokens.addAll(mAppTokens);
-            moveAppWindowsLocked(tokens, 0);
+            Slog.e(TAG, "createStack: Unable to find relativeStackBoxId=" + relativeStackBoxId);
         }
-        Binder.restoreCallingIdentity(origId);
+    }
+
+    public int removeStack(int stackId) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack != null) {
+                mStackIdToStack.delete(stackId);
+                int nextStackId = stack.remove();
+                stack.getDisplayContent().layoutNeeded = true;
+                requestTraversalLocked();
+                return nextStackId;
+            }
+            if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId);
+        }
+        return HOME_STACK_ID;
+    }
+
+    public void removeTask(int taskId) {
+        synchronized (mWindowMap) {
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
+                return;
+            }
+            final TaskStack stack = task.mStack;
+            stack.removeTask(task);
+            stack.getDisplayContent().layoutNeeded = true;
+        }
+    }
+
+    public void addTask(int taskId, int stackId, boolean toTop) {
+        synchronized (mWindowMap) {
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                return;
+            }
+            TaskStack stack = mStackIdToStack.get(stackId);
+            stack.addTask(task, toTop);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.layoutNeeded = true;
+            performLayoutAndPlaceSurfacesLocked();
+        }
+    }
+
+    public void resizeStackBox(int stackBoxId, float weight) {
+        if (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX) {
+            throw new IllegalArgumentException(
+                    "resizeStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
+                    STACK_WEIGHT_MAX + ", weight=" + weight);
+        }
+        synchronized (mWindowMap) {
+            final int numDisplays = mDisplayContents.size();
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) {
+                    performLayoutAndPlaceSurfacesLocked();
+                    return;
+                }
+            }
+        }
+        throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId
+                + " not found.");
+    }
+
+    public ArrayList<StackBoxInfo> getStackBoxInfos() {
+        synchronized(mWindowMap) {
+            return getDefaultDisplayContentLocked().getStackBoxInfos();
+        }
+    }
+
+    public Rect getStackBounds(int stackId) {
+        final int numDisplays = mDisplayContents.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId);
+            if (bounds != null) {
+                return bounds;
+            }
+        }
+        return null;
     }
 
     // -------------------------------------------------------------
@@ -4934,6 +5152,16 @@
                 mAnimatorDurationScale };
     }
 
+    @Override
+    public void registerPointerEventListener(PointerEventListener listener) {
+        mPointerEventDispatcher.registerInputEventListener(listener);
+    }
+
+    @Override
+    public void unregisterPointerEventListener(PointerEventListener listener) {
+        mPointerEventDispatcher.unregisterInputEventListener(listener);
+    }
+
     // Called by window manager policy. Not exposed externally.
     @Override
     public int getLidState() {
@@ -4953,12 +5181,6 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
-    public InputChannel monitorInput(String inputChannelName) {
-        return mInputManager.monitorInput(inputChannelName);
-    }
-
-    // Called by window manager policy.  Not exposed externally.
-    @Override
     public void switchKeyboardLayout(int deviceId, int direction) {
         mInputManager.switchKeyboardLayout(deviceId, direction);
     }
@@ -4985,6 +5207,7 @@
 
     public void setCurrentUser(final int newUserId) {
         synchronized (mWindowMap) {
+            int oldUserId = mCurrentUserId;
             mCurrentUserId = newUserId;
             mAppTransition.setCurrentUser(newUserId);
             mPolicy.setCurrentUserLw(newUserId);
@@ -4993,16 +5216,8 @@
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                final WindowList windows = displayContent.getWindowList();
-                for (int i = 0; i < windows.size(); i++) {
-                    final WindowState win = windows.get(i);
-                    if (win.isHiddenFromUserLocked()) {
-                        Slog.w(TAG, "current user violation " + newUserId + " hiding "
-                                + win + ", attrs=" + win.mAttrs.type + ", belonging to "
-                                + win.mOwnerUid);
-                        win.hideLw(false);
-                    }
-                }
+                displayContent.switchUserStacks(oldUserId, newUserId);
+                rebuildAppWindowListLocked(displayContent);
             }
             performLayoutAndPlaceSurfacesLocked();
         }
@@ -5151,8 +5366,9 @@
             if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
             if (false) {
                 StringWriter sw = new StringWriter();
-                PrintWriter pw = new PrintWriter(sw);
+                PrintWriter pw = new FastPrintWriter(sw, false, 1024);
                 this.dump(null, pw, null);
+                pw.flush();
                 Slog.i(TAG, sw.toString());
             }
             try {
@@ -5356,6 +5572,7 @@
                 boolean including = false;
                 appWin = null;
                 final WindowList windows = displayContent.getWindowList();
+                final Rect stackBounds = new Rect();
                 for (int i = windows.size() - 1; i >= 0; i--) {
                     WindowState ws = windows.get(i);
                     if (!ws.mHasSurface) {
@@ -5378,6 +5595,7 @@
                                 continue;
                             }
                             appWin = ws;
+                            stackBounds.set(ws.getStackBounds());
                         }
                     }
 
@@ -5403,6 +5621,7 @@
                         int right = wf.right - cr.right;
                         int bottom = wf.bottom - cr.bottom;
                         frame.union(left, top, right, bottom);
+                        frame.intersect(stackBounds);
                     }
 
                     if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
@@ -5446,9 +5665,11 @@
 
                 // Constrain thumbnail to smaller of screen width or height. Assumes aspect
                 // of thumbnail is the same as the screen (in landscape) or square.
+                scale = Math.max(width / (float) fw, height / (float) fh);
+                /*
                 float targetWidthScale = width / (float) fw;
                 float targetHeightScale = height / (float) fh;
-                if (dw <= dh) {
+                if (fw <= fh) {
                     scale = targetWidthScale;
                     // If aspect of thumbnail is the same as the screen (in landscape),
                     // select the slightly larger value so we fill the entire bitmap
@@ -5463,6 +5684,7 @@
                         scale = targetWidthScale;
                     }
                 }
+                */
 
                 // The screen shot will contain the entire screen.
                 dw = (int)(dw*scale);
@@ -5497,9 +5719,11 @@
         }
 
         Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
+        frame.scale(scale);
         Matrix matrix = new Matrix();
         ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
-        matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
+        // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left
+        matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top));
         Canvas canvas = new Canvas(bm);
         canvas.drawColor(0xFF000000);
         canvas.drawBitmap(rawss, matrix, null);
@@ -5510,14 +5734,16 @@
             int[] buffer = new int[bm.getWidth() * bm.getHeight()];
             bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
             boolean allBlack = true;
+            final int firstColor = buffer[0];
             for (int i = 0; i < buffer.length; i++) {
-                if (buffer[i] != Color.BLACK) {
+                if (buffer[i] != firstColor) {
                     allBlack = false;
                     break;
                 }
             }
             if (allBlack) {
-                Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
+                Slog.i(TAG, "Screenshot " + appWin + " was monochrome(" +
+                        Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
                         (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
                         " minLayer=" + minLayer + " maxLayer=" + maxLayer);
             }
@@ -5709,9 +5935,10 @@
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
-        getDefaultDisplayContentLocked().layoutNeeded = true;
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        displayContent.layoutNeeded = true;
         final int[] anim = new int[2];
-        if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
+        if (displayContent.isDimming()) {
             anim[0] = anim[1] = 0;
         } else {
             mPolicy.selectRotationAnimationLw(anim);
@@ -5729,7 +5956,6 @@
         // the rotation animation for the new rotation.
         computeScreenConfigurationLocked(null);
 
-        final DisplayContent displayContent = getDefaultDisplayContentLocked();
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (!inTransaction) {
             if (SHOW_TRANSACTIONS) {
@@ -6441,8 +6667,9 @@
             displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
             displayInfo.appWidth = appWidth;
             displayInfo.appHeight = appHeight;
-            displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
-            displayInfo.getAppMetrics(mDisplayMetrics, null);
+            displayInfo.getLogicalMetrics(mRealDisplayMetrics,
+                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+            displayInfo.getAppMetrics(mDisplayMetrics);
             mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
                     displayContent.getDisplayId(), displayInfo);
         }
@@ -6613,7 +6840,7 @@
                     } else {
                         Slog.w(TAG, "Drag already in progress");
                     }
-                } catch (SurfaceControl.OutOfResourcesException e) {
+                } catch (OutOfResourcesException e) {
                     Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
                     if (mDragState != null) {
                         mDragState.reset();
@@ -6748,15 +6975,18 @@
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
             readForcedDisplaySizeAndDensityLocked(displayContent);
-
             mDisplayReady = true;
+        }
+
+        try {
+            mActivityManager.updateConfiguration(null);
+        } catch (RemoteException e) {
+        }
+
+        synchronized(mWindowMap) {
             mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                     PackageManager.FEATURE_TOUCHSCREEN);
-
-            mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
-                    displayContent.mInitialDisplayWidth,
-                    displayContent.mInitialDisplayHeight,
-                    displayContent.mInitialDisplayDensity);
+            configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
         }
 
         try {
@@ -6783,6 +7013,8 @@
                     displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
                     displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
                     displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
+                    displayContent.mBaseDisplayRect.set(0, 0,
+                            displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
                 }
             }
         }
@@ -6844,6 +7076,10 @@
         public static final int DO_DISPLAY_CHANGED = 29;
 
         public static final int CLIENT_FREEZE_TIMEOUT = 30;
+        public static final int TAP_OUTSIDE_STACK = 31;
+        public static final int NOTIFY_ACTIVITY_DRAWN = 32;
+
+        public static final int REMOVE_STARTING_TIMEOUT = 33;
 
         @Override
         public void handleMessage(Message msg) {
@@ -6863,8 +7099,8 @@
                             return;
                         }
                         mLastFocus = newFocus;
-                        //Slog.i(TAG, "Focus moving from " + lastFocus
-                        //        + " to " + newFocus);
+                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Focus moving from " + lastFocus +
+                                " to " + newFocus);
                         if (newFocus != null && lastFocus != null
                                 && !newFocus.isDisplayedLw()) {
                             //Slog.i(TAG, "Delaying loss of focus...");
@@ -6873,19 +7109,17 @@
                         }
                     }
 
-                    if (lastFocus != newFocus) {
-                        //System.out.println("Changing focus from " + lastFocus
-                        //                   + " to " + newFocus);
-                        if (newFocus != null) {
-                            //Slog.i(TAG, "Gaining focus: " + newFocus);
-                            newFocus.reportFocusChangedSerialized(true, mInTouchMode);
-                            notifyFocusChanged();
-                        }
+                    //System.out.println("Changing focus from " + lastFocus
+                    //                   + " to " + newFocus);
+                    if (newFocus != null) {
+                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
+                        newFocus.reportFocusChangedSerialized(true, mInTouchMode);
+                        notifyFocusChanged();
+                    }
 
-                        if (lastFocus != null) {
-                            //Slog.i(TAG, "Losing focus: " + lastFocus);
-                            lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
-                        }
+                    if (lastFocus != null) {
+                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
+                        lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
                     }
                 } break;
 
@@ -6899,7 +7133,8 @@
 
                     final int N = losers.size();
                     for (int i=0; i<N; i++) {
-                        //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
+                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing delayed focus: " +
+                                losers.get(i));
                         losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
                     }
                 } break;
@@ -6927,7 +7162,7 @@
                     try {
                         view = mPolicy.addStartingWindow(
                             wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
-                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
+                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, sd.windowFlags);
                     } catch (Exception e) {
                         Slog.w(TAG, "Exception when adding starting window", e);
                     }
@@ -6944,6 +7179,7 @@
                                             "Aborted starting " + wtoken
                                             + ": removed=" + wtoken.removed
                                             + " startingData=" + wtoken.startingData);
+                                    removeStartingWindowTimeout(wtoken);
                                     wtoken.startingWindow = null;
                                     wtoken.startingData = null;
                                     abort = true;
@@ -6968,6 +7204,11 @@
                     }
                 } break;
 
+                case REMOVE_STARTING_TIMEOUT: {
+                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
+                    Slog.e(TAG, "Starting window " + wtoken + " timed out");
+                    // Fall through.
+                }
                 case REMOVE_STARTING: {
                     final AppWindowToken wtoken = (AppWindowToken)msg.obj;
                     IBinder token = null;
@@ -7088,8 +7329,6 @@
                         if (mAppTransition.isTransitionSet()) {
                             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
                             mAppTransition.setTimeout();
-                            mAnimatingAppTokens.clear();
-                            mAnimatingAppTokens.addAll(mAppTokens);
                             performLayoutAndPlaceSurfacesLocked();
                         }
                     }
@@ -7134,13 +7373,16 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
-                        int i = mAppTokens.size();
-                        while (i > 0) {
-                            i--;
-                            AppWindowToken tok = mAppTokens.get(i);
-                            if (tok.mAppAnimator.freezingScreen) {
-                                Slog.w(TAG, "Force clearing freeze: " + tok);
-                                unsetAppFreezingScreenLocked(tok, true, true);
+                        DisplayContent displayContent = getDefaultDisplayContentLocked();
+                        final ArrayList<Task> tasks = displayContent.getTasks();
+                        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                                AppWindowToken tok = tokens.get(tokenNdx);
+                                if (tok.mAppAnimator.freezingScreen) {
+                                    Slog.w(TAG, "Force clearing freeze: " + tok);
+                                    unsetAppFreezingScreenLocked(tok, true, true);
+                                }
                             }
                         }
                     }
@@ -7262,6 +7504,26 @@
                         handleDisplayChangedLocked(msg.arg1);
                     }
                     break;
+
+                case TAP_OUTSIDE_STACK: {
+                    int stackId;
+                    synchronized (mWindowMap) {
+                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
+                    }
+                    if (stackId >= 0) {
+                        try {
+                            mActivityManager.setFocusedStack(stackId);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+                break;
+                case NOTIFY_ACTIVITY_DRAWN:
+                    try {
+                        mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
+                    } catch (RemoteException e) {
+                    }
+                    break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
@@ -7347,7 +7609,7 @@
     public void getInitialDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent != null) {
+            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 synchronized(displayContent.mDisplaySizeLock) {
                     size.x = displayContent.mInitialDisplayWidth;
                     size.y = displayContent.mInitialDisplayHeight;
@@ -7360,7 +7622,7 @@
     public void getBaseDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent != null) {
+            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 synchronized(displayContent.mDisplaySizeLock) {
                     size.x = displayContent.mBaseDisplayWidth;
                     size.y = displayContent.mBaseDisplayHeight;
@@ -7400,8 +7662,11 @@
     }
 
     private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
-        final String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
+        String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.DISPLAY_SIZE_FORCED);
+        if (sizeStr == null || sizeStr.length() == 0) {
+            sizeStr = SystemProperties.get(SIZE_OVERRIDE, null);
+        }
         if (sizeStr != null && sizeStr.length() > 0) {
             final int pos = sizeStr.indexOf(',');
             if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
@@ -7421,8 +7686,11 @@
                 }
             }
         }
-        final String densityStr = Settings.Global.getString(mContext.getContentResolver(),
+        String densityStr = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.DISPLAY_DENSITY_FORCED);
+        if (densityStr == null || densityStr.length() == 0) {
+            densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
+        }
         if (densityStr != null && densityStr.length() > 0) {
             int density;
             try {
@@ -7475,7 +7743,7 @@
     public int getInitialDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent != null) {
+            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 synchronized(displayContent.mDisplaySizeLock) {
                     return displayContent.mInitialDisplayDensity;
                 }
@@ -7488,7 +7756,7 @@
     public int getBaseDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent != null) {
+            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 synchronized(displayContent.mDisplaySizeLock) {
                     return displayContent.mBaseDisplayDensity;
                 }
@@ -7552,11 +7820,7 @@
     // displayContent must not be null
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
         // TODO: Multidisplay: for now only use with default display.
-        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
-                displayContent.mBaseDisplayWidth,
-                displayContent.mBaseDisplayHeight,
-                displayContent.mBaseDisplayDensity);
-
+        configureDisplayPolicyLocked(displayContent);
         displayContent.layoutNeeded = true;
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
@@ -7577,6 +7841,18 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
+    private void configureDisplayPolicyLocked(DisplayContent displayContent) {
+        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
+                displayContent.mBaseDisplayWidth,
+                displayContent.mBaseDisplayHeight,
+                displayContent.mBaseDisplayDensity);
+
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        mPolicy.setDisplayOverscan(displayContent.getDisplay(),
+                displayInfo.overscanLeft, displayInfo.overscanTop,
+                displayInfo.overscanRight, displayInfo.overscanBottom);
+    }
+
     @Override
     public void setOverscan(int displayId, int left, int top, int right, int bottom) {
         if (mContext.checkCallingOrSelfPermission(
@@ -7588,26 +7864,25 @@
         synchronized(mWindowMap) {
             DisplayContent displayContent = getDisplayContentLocked(displayId);
             if (displayContent != null) {
-                mDisplayManagerService.setOverscan(displayId, left, top, right, bottom);
-                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                synchronized(displayContent.mDisplaySizeLock) {
-                    displayInfo.overscanLeft = left;
-                    displayInfo.overscanTop = top;
-                    displayInfo.overscanRight = right;
-                    displayInfo.overscanBottom = bottom;
-                }
-                mPolicy.setDisplayOverscan(displayContent.getDisplay(), left, top, right, bottom);
-                displayContent.layoutNeeded = true;
-                mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
-                mDisplaySettings.writeSettingsLocked();
-                performLayoutAndPlaceSurfacesLocked();
+                setOverscanLocked(displayContent, left, top, right, bottom);
             }
         }
     }
 
-    @Override
-    public boolean hasSystemNavBar() {
-        return mPolicy.hasSystemNavBar();
+    private void setOverscanLocked(DisplayContent displayContent,
+            int left, int top, int right, int bottom) {
+        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        synchronized (displayContent.mDisplaySizeLock) {
+            displayInfo.overscanLeft = left;
+            displayInfo.overscanTop = top;
+            displayInfo.overscanRight = right;
+            displayInfo.overscanBottom = bottom;
+        }
+
+        mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
+        mDisplaySettings.writeSettingsLocked();
+
+        reconfigureDisplayLocked(displayContent);
     }
 
     // -------------------------------------------------------------
@@ -7648,10 +7923,8 @@
     }
 
     final void rebuildAppWindowListLocked() {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            rebuildAppWindowListLocked(mDisplayContents.valueAt(displayNdx));
-        }
+        // TODO: Multidisplay, when ActivityStacks and tasks exist on more than one display.
+        rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
     }
 
     private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
@@ -7674,8 +7947,7 @@
                 win.mRebuilding = true;
                 mRebuildTmp[numRemoved] = win;
                 mWindowsChanged = true;
-                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
-                        "Rebuild removing window: " + win);
+                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Rebuild removing window: " + win);
                 NW--;
                 numRemoved++;
                 continue;
@@ -7696,26 +7968,33 @@
         // in the main app list, but still have windows shown.  We put them
         // in the back because now that the animation is over we no longer
         // will care about them.
-        int NT = mExitingAppTokens.size();
+        AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+        int NT = exitingAppTokens.size();
         for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j));
+            i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
         }
 
         // And add in the still active app tokens in Z order.
-        NT = mAnimatingAppTokens.size();
-        for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j));
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        final int numTasks = tasks.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int numTokens = tokens.size();
+            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                final AppWindowToken wtoken = tokens.get(tokenNdx);
+                i = reAddAppWindowsLocked(displayContent, i, wtoken);
+            }
         }
 
         i -= lastBelow;
         if (i != numRemoved) {
-            Slog.w(TAG, "Rebuild removed " + numRemoved
-                    + " windows but added " + i);
+            Slog.w(TAG, "Rebuild removed " + numRemoved + " windows but added " + i,
+                    new RuntimeException("here").fillInStackTrace());
             for (i=0; i<numRemoved; i++) {
                 WindowState ws = mRebuildTmp[i];
                 if (ws.mRebuilding) {
                     StringWriter sw = new StringWriter();
-                    PrintWriter pw = new PrintWriter(sw);
+                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
                     ws.dump(pw, "", true);
                     pw.flush();
                     Slog.w(TAG, "This window was lost: " + ws);
@@ -7724,7 +8003,7 @@
                 }
             }
             Slog.w(TAG, "Current app token list:");
-            dumpAnimatingAppTokensLocked();
+            dumpAppTokensLocked();
             Slog.w(TAG, "Final window list:");
             dumpWindowsLocked();
         }
@@ -7736,11 +8015,8 @@
         int curLayer = 0;
         int i;
 
-        if (DEBUG_LAYERS) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.v(TAG, "Assigning layers", here);
-        }
+        if (DEBUG_LAYERS) Slog.v(TAG, "Assigning layers based on windows=" + windows,
+                new RuntimeException("here").fillInStackTrace());
 
         boolean anyLayerChanged = false;
 
@@ -7761,13 +8037,14 @@
                 layerChanged = true;
                 anyLayerChanged = true;
             }
+            final AppWindowToken wtoken = w.mAppToken;
             oldLayer = winAnimator.mAnimLayer;
             if (w.mTargetAppToken != null) {
                 winAnimator.mAnimLayer =
                         w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
-            } else if (w.mAppToken != null) {
+            } else if (wtoken != null) {
                 winAnimator.mAnimLayer =
-                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
+                        w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
             } else {
                 winAnimator.mAnimLayer = w.mLayer;
             }
@@ -7780,15 +8057,15 @@
                 layerChanged = true;
                 anyLayerChanged = true;
             }
-            if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
-                // Force an animation pass just to update the mDimAnimator layer.
+            if (layerChanged && w.getStack().isDimming(winAnimator)) {
+                // Force an animation pass just to update the mDimLayer layer.
                 scheduleAnimationLocked();
             }
             if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
                     + "mBase=" + w.mBaseLayer
                     + " mLayer=" + w.mLayer
-                    + (w.mAppToken == null ?
-                            "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+                    + (wtoken == null ?
+                            "" : " mAppLayer=" + wtoken.mAppAnimator.animLayerAdjustment)
                     + " =mAnimLayer=" + winAnimator.mAnimLayer);
             //System.out.println(
             //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
@@ -7926,6 +8203,9 @@
             mScreenRect.set(0, 0, dw, dh);
         }
 
+        mPolicy.getContentRectLw(mTmpContentRect);
+        displayContent.setStackBoxSize(mTmpContentRect);
+
         int seq = mLayoutSeq+1;
         if (seq < 0) seq = 0;
         mLayoutSeq = seq;
@@ -8331,12 +8611,8 @@
                     mAppTransition.getStartingPoint(p);
                     appAnimator.thumbnailX = p.x;
                     appAnimator.thumbnailY = p.y;
-                } catch (SurfaceControl.OutOfResourcesException e) {
-                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
-                            + " h=" + dirty.height(), e);
-                    appAnimator.clearThumbnail();
-                } catch (Surface.OutOfResourcesException e) {
-                    Slog.e(TAG, "Can't allocate Canvas surface w=" + dirty.width()
+                } catch (OutOfResourcesException e) {
+                    Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
                             + " h=" + dirty.height(), e);
                     appAnimator.clearThumbnail();
                 }
@@ -8375,11 +8651,17 @@
 
         mAppTransition.setIdle();
         // Restore window app tokens to the ActivityManager views
-        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
-            mAnimatingAppTokens.get(i).sendingToBottom = false;
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        final int numTasks = tasks.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int numTokens = tokens.size();
+            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                final AppWindowToken wtoken = tokens.get(tokenNdx);
+                wtoken.sendingToBottom = false;
+            }
         }
-        mAnimatingAppTokens.clear();
-        mAnimatingAppTokens.addAll(mAppTokens);
         rebuildAppWindowListLocked();
 
         changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
@@ -8418,7 +8700,7 @@
                     || winAnimator.mSurfaceResized
                     || configChanged) {
                 if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
-                    Slog.v(TAG, "Resize reasons: "
+                    Slog.v(TAG, "Resize reasons for w=" + w + ": "
                             + " contentInsetsChanged=" + w.mContentInsetsChanged
                             + " " + w.mContentInsets.toShortString()
                             + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
@@ -8529,30 +8811,36 @@
         if ((attrs.flags & FLAG_DIM_BEHIND) != 0
                 && w.isDisplayedLw()
                 && !w.mExiting) {
-            mInnerFields.mDimming = true;
             final WindowStateAnimator winAnimator = w.mWinAnimator;
-            if (!mAnimator.isDimmingLocked(winAnimator)) {
+            final TaskStack stack = w.getStack();
+            stack.setDimmingTag();
+            if (!stack.isDimming(winAnimator)) {
                 if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
-                startDimmingLocked(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount);
+                stack.startDimmingIfNeeded(winAnimator);
             }
         }
     }
 
-    private void updateAllDrawnLocked() {
+    private void updateAllDrawnLocked(DisplayContent displayContent) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
-        final int NT = appTokens.size();
-        for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = appTokens.get(i);
-            if (!wtoken.allDrawn) {
-                int numInteresting = wtoken.numInterestingWindows;
-                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
-                            "allDrawn: " + wtoken
-                            + " interesting=" + numInteresting
-                            + " drawn=" + wtoken.numDrawnWindows);
-                    wtoken.allDrawn = true;
+        final ArrayList<Task> tasks = displayContent.getTasks();
+        final int numTasks = tasks.size();
+        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+            final int numTokens = tokens.size();
+            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                final AppWindowToken wtoken = tokens.get(tokenNdx);
+                if (!wtoken.allDrawn) {
+                    int numInteresting = wtoken.numInterestingWindows;
+                    if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                        if (DEBUG_VISIBILITY) Slog.v(TAG,
+                                "allDrawn: " + wtoken
+                                + " interesting=" + numInteresting
+                                + " drawn=" + wtoken.numDrawnWindows);
+                        wtoken.allDrawn = true;
+                        mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+                    }
                 }
             }
         }
@@ -8576,13 +8864,17 @@
         }
 
         // Initialize state of exiting tokens.
-        for (i=mExitingTokens.size()-1; i>=0; i--) {
-            mExitingTokens.get(i).hasVisible = false;
-        }
+        final int numDisplays = mDisplayContents.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
+                displayContent.mExitingTokens.get(i).hasVisible = false;
+            }
 
-        // Initialize state of exiting applications.
-        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
-            mExitingAppTokens.get(i).hasVisible = false;
+            // Initialize state of exiting applications.
+            for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) {
+                displayContent.mExitingAppTokens.get(i).hasVisible = false;
+            }
         }
 
         mInnerFields.mHoldScreen = null;
@@ -8611,11 +8903,10 @@
             }
 
             boolean focusDisplayed = false;
-            boolean updateAllDrawn = false;
 
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+                boolean updateAllDrawn = false;
                 WindowList windows = displayContent.getWindowList();
                 DisplayInfo displayInfo = displayContent.getDisplayInfo();
                 final int displayId = displayContent.getDisplayId();
@@ -8694,8 +8985,8 @@
                 } while (displayContent.pendingLayoutChanges != 0);
 
                 mInnerFields.mObscured = false;
-                mInnerFields.mDimming = false;
                 mInnerFields.mSyswin = false;
+                displayContent.resetDimming();
 
                 // Only used if default window
                 final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
@@ -8712,7 +9003,7 @@
                         handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
                     }
 
-                    if (!mInnerFields.mDimming) {
+                    if (!w.getStack().testDimmingTag()) {
                         handleFlagDimBehind(w, innerDw, innerDh);
                     }
 
@@ -8760,7 +9051,7 @@
                                 // make this happen.
                                 displayContent.pendingLayoutChanges |=
                                         WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                                if (DEBUG_LAYOUT_REPEATS) {
                                     debugLayoutRepeats(
                                         "dream and commitFinishDrawingLocked true",
                                         displayContent.pendingLayoutChanges);
@@ -8772,7 +9063,7 @@
                                 mInnerFields.mWallpaperMayChange = true;
                                 displayContent.pendingLayoutChanges |=
                                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                                if (DEBUG_LAYOUT_REPEATS) {
                                     debugLayoutRepeats(
                                         "wallpaper and commitFinishDrawingLocked true",
                                         displayContent.pendingLayoutChanges);
@@ -8798,8 +9089,7 @@
                             }
                             if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
                                     && !w.mExiting && !w.mDestroying) {
-                                if (WindowManagerService.DEBUG_VISIBILITY ||
-                                        WindowManagerService.DEBUG_ORIENTATION) {
+                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
                                     Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
                                             + ", isAnimating=" + winAnimator.isAnimating());
                                     if (!w.isDrawnLw()) {
@@ -8816,8 +9106,7 @@
                                         atoken.numInterestingWindows++;
                                         if (w.isDrawnLw()) {
                                             atoken.numDrawnWindows++;
-                                            if (WindowManagerService.DEBUG_VISIBILITY ||
-                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
                                                     "tokenMayBeDrawn: " + atoken
                                                     + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
                                                     + " mAppFreezing=" + w.mAppFreezing);
@@ -8855,13 +9144,11 @@
                 mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
                         true /* inTraversal, must call performTraversalInTrans... below */);
 
-                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
-                    stopDimmingLocked(displayId);
-                }
-            }
+                getDisplayContentLocked(displayId).stopDimmingIfNeeded();
 
-            if (updateAllDrawn) {
-                updateAllDrawnLocked();
+                if (updateAllDrawn) {
+                    updateAllDrawnLocked(displayContent);
+                }
             }
 
             if (focusDisplayed) {
@@ -8918,8 +9205,7 @@
         mInnerFields.mWallpaperForceHidingChanged = false;
 
         if (mInnerFields.mWallpaperMayChange) {
-            if (WindowManagerService.DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
-                    "Wallpaper may change!  Adjusting");
+            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
             defaultDisplay.pendingLayoutChanges |=
                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
@@ -9032,30 +9318,37 @@
         }
 
         // Time to remove any exiting tokens?
-        for (i=mExitingTokens.size()-1; i>=0; i--) {
-            WindowToken token = mExitingTokens.get(i);
-            if (!token.hasVisible) {
-                mExitingTokens.remove(i);
-                if (token.windowType == TYPE_WALLPAPER) {
-                    mWallpaperTokens.remove(token);
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
+            for (i = exitingTokens.size() - 1; i >= 0; i--) {
+                WindowToken token = exitingTokens.get(i);
+                if (!token.hasVisible) {
+                    exitingTokens.remove(i);
+                    if (token.windowType == TYPE_WALLPAPER) {
+                        mWallpaperTokens.remove(token);
+                    }
                 }
             }
-        }
 
-        // Time to remove any exiting applications?
-        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
-            AppWindowToken token = mExitingAppTokens.get(i);
-            if (!token.hasVisible && !mClosingApps.contains(token)) {
-                // Make sure there is no animation running on this token,
-                // so any windows associated with it will be removed as
-                // soon as their animations are complete
-                token.mAppAnimator.clearAnimation();
-                token.mAppAnimator.animating = false;
-                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                        "performLayout: App token exiting now removed" + token);
-                mAppTokens.remove(token);
-                mAnimatingAppTokens.remove(token);
-                mExitingAppTokens.remove(i);
+            // Time to remove any exiting applications?
+            AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
+                AppWindowToken token = exitingAppTokens.get(i);
+                if (!token.hasVisible && !mClosingApps.contains(token)) {
+                    // Make sure there is no animation running on this token,
+                    // so any windows associated with it will be removed as
+                    // soon as their animations are complete
+                    token.mAppAnimator.clearAnimation();
+                    token.mAppAnimator.animating = false;
+                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
+                            "performLayout: App token exiting now removed" + token);
+                    final Task task = mTaskIdToTask.get(token.groupId);
+                    if (task != null && task.removeAppToken(token)) {
+                        mTaskIdToTask.delete(token.groupId);
+                    }
+                    exitingAppTokens.remove(i);
+                }
             }
         }
 
@@ -9075,7 +9368,6 @@
             defaultDisplay.layoutNeeded = true;
         }
 
-        final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
             if (displayContent.pendingLayoutChanges != 0) {
@@ -9146,6 +9438,8 @@
             }
         }
 
+        setFocusedStackFrame();
+
         // Check to see if we are now in a state where the screen should
         // be enabled, because the window obscured flags have changed.
         enableScreenIfNeededLocked();
@@ -9255,14 +9549,6 @@
         }
     }
 
-    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target) {
-        mAnimator.setDimWinAnimatorLocked(winAnimator.mWin.getDisplayId(), winAnimator);
-    }
-
-    void stopDimmingLocked(int displayId) {
-        mAnimator.setDimWinAnimatorLocked(displayId, null);
-    }
-
     private boolean needsLayout() {
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
@@ -9309,6 +9595,20 @@
         return doRequest;
     }
 
+    /** If a window that has an animation specifying a colored background and the current wallpaper
+     * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
+     * suddenly disappear. */
+    int adjustAnimationBackground(WindowStateAnimator winAnimator) {
+        WindowList windows = winAnimator.mWin.getWindowList();
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            WindowState testWin = windows.get(i);
+            if (testWin.mIsWallpaper && testWin.isVisibleNow()) {
+                return testWin.mWinAnimator.mAnimLayer;
+            }
+        }
+        return winAnimator.mAnimLayer;
+    }
+
     boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
                                            boolean secure) {
         final SurfaceControl surface = winAnimator.mSurfaceControl;
@@ -9328,6 +9628,7 @@
             // window list to make sure we haven't left any dangling surfaces
             // around.
 
+            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
@@ -9406,6 +9707,7 @@
                     winAnimator.mSurfaceShown = false;
                     winAnimator.mSurfaceControl = null;
                     winAnimator.mWin.mHasSurface = false;
+                    scheduleRemoveStartingWindow(winAnimator.mWin.mAppToken);
                 }
 
                 try {
@@ -9428,24 +9730,25 @@
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
             mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
-            if (localLOGV) Slog.v(
-                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
+            // TODO(multidisplay): Focused windows on default display only.
+            final DisplayContent displayContent = getDefaultDisplayContentLocked();
+            final boolean imWindowChanged = moveInputMethodWindowsIfNeededLocked(
+                    mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
+                            && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
+            if (imWindowChanged) {
+                displayContent.layoutNeeded = true;
+                newFocus = computeFocusedWindowLocked();
+            }
+
+            if (true || DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG, "Changing focus from " +
+                    mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
             final WindowState oldFocus = mCurrentFocus;
             mCurrentFocus = newFocus;
-            mAnimator.setCurrentFocus(newFocus);
             mLosingFocus.remove(newFocus);
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
 
-            // TODO(multidisplay): Focused windows on default display only.
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
-
-            final WindowState imWindow = mInputMethodWindow;
-            if (newFocus != imWindow && oldFocus != imWindow) {
-                if (moveInputMethodWindowsIfNeededLocked(
-                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
-                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
-                    displayContent.layoutNeeded = true;
-                }
+            if (imWindowChanged && oldFocus != mInputMethodWindow) {
+                // Focus of the input method window changed. Perform layout if needed.
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                     performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
                     focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -9498,9 +9801,6 @@
     }
 
     private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
-        int nextAppIndex = mAppTokens.size()-1;
-        WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null;
-
         final WindowList windows = displayContent.getWindowList();
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
@@ -9511,51 +9811,52 @@
                 + ", flags=" + win.mAttrs.flags
                 + ", canReceive=" + win.canReceiveKeys());
 
-            AppWindowToken thisApp = win.mAppToken;
+            AppWindowToken wtoken = win.mAppToken;
 
             // If this window's application has been removed, just skip it.
-            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
-                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
-                        ? "removed" : "sendingToBottom"));
+            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
+                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping " + wtoken + " because "
+                        + (wtoken.removed ? "removed" : "sendingToBottom"));
                 continue;
             }
 
-            // If there is a focused app, don't allow focus to go to any
-            // windows below it.  If this is an application window, step
-            // through the app tokens until we find its app.
-            if (thisApp != null && nextApp != null && thisApp != nextApp
-                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
-                int origAppIndex = nextAppIndex;
-                while (nextAppIndex > 0) {
-                    if (nextApp == mFocusedApp) {
-                        // Whoops, we are below the focused app...  no focus
-                        // for you!
-                        if (localLOGV || DEBUG_FOCUS) Slog.v(
-                            TAG, "Reached focused app: " + mFocusedApp);
-                        return null;
+            if (!win.canReceiveKeys()) {
+                continue;
+            }
+
+            // Descend through all of the app tokens and find the first that either matches
+            // win.mAppToken (return win) or mFocusedApp (return null).
+            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
+                    mFocusedApp != null) {
+                ArrayList<Task> tasks = displayContent.getTasks();
+                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                    int tokenNdx = tokens.size() - 1;
+                    for ( ; tokenNdx >= 0; --tokenNdx) {
+                        final AppWindowToken token = tokens.get(tokenNdx);
+                        if (wtoken == token) {
+                            break;
+                        }
+                        if (mFocusedApp == token) {
+                            // Whoops, we are below the focused app...  no focus for you!
+                            if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG,
+                                    "findFocusedWindow: Reached focused app=" + mFocusedApp);
+                            return null;
+                        }
                     }
-                    nextAppIndex--;
-                    nextApp = mAppTokens.get(nextAppIndex);
-                    if (nextApp == thisApp) {
+                    if (tokenNdx >= 0) {
+                        // Early exit from loop, must have found the matching token.
                         break;
                     }
                 }
-                if (thisApp != nextApp) {
-                    // Uh oh, the app token doesn't exist!  This shouldn't
-                    // happen, but if it does we can get totally hosed...
-                    // so restart at the original app.
-                    nextAppIndex = origAppIndex;
-                    nextApp = mAppTokens.get(nextAppIndex);
-                }
             }
 
-            // Dispatch to this window if it is wants key events.
-            if (win.canReceiveKeys()) {
-                if (DEBUG_FOCUS) Slog.v(
-                        TAG, "Found focus @ " + i + " = " + win);
-                return win;
-            }
+            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: Found new focus @ " + i +
+                        " = " + win);
+            return win;
         }
+
+        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: No focusable windows.");
         return null;
     }
 
@@ -9604,11 +9905,8 @@
             }
 
             // TODO(multidisplay): rotation on main screen only.
-            final Display display = displayContent.getDisplay();
-            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-            screenRotationAnimation = new ScreenRotationAnimation(mContext,
-                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
-                    displayInfo.logicalHeight, display.getRotation());
+            screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
+                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced());
             mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
         }
     }
@@ -9656,7 +9954,7 @@
             // TODO(multidisplay): rotation on main screen only.
             DisplayInfo displayInfo = displayContent.getDisplayInfo();
             // Get rotation animation again, with new top window
-            boolean isDimming = mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY);
+            boolean isDimming = displayContent.isDimming();
             if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
                 mExitAnimId = mEnterAnimId = 0;
             }
@@ -9875,16 +10173,6 @@
         return mSafeMode;
     }
 
-    @Override
-    public void showAssistant() {
-        // TODO: What permission?
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
-                != PackageManager.PERMISSION_GRANTED) {
-            return;
-        }
-        mPolicy.showAssistant();
-    }
-
     void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
         pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
         mPolicy.dump("    ", pw, args);
@@ -9926,15 +10214,6 @@
                 }
             }
         }
-        if (mAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Application tokens in Z order:");
-            for (int i=mAppTokens.size()-1; i>=0; i--) {
-                pw.print("  App #"); pw.print(i);
-                        pw.print(' '); pw.print(mAppTokens.get(i)); pw.println(":");
-                mAppTokens.get(i).dump(pw, "    ");
-            }
-        }
         if (mFinishedStarting.size() > 0) {
             pw.println();
             pw.println("  Finishing start of application tokens:");
@@ -9950,51 +10229,6 @@
                 }
             }
         }
-        if (mExitingTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting tokens:");
-            for (int i=mExitingTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingTokens.get(i);
-                pw.print("  Exiting #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
-        if (mExitingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting application tokens:");
-            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingAppTokens.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
-        if (mAppTransition.isRunning() && mAnimatingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Application tokens during animation:");
-            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mAnimatingAppTokens.get(i);
-                pw.print("  App moving to bottom #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
         if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
             pw.println();
             if (mOpeningApps.size() > 0) {
@@ -10023,7 +10257,8 @@
         if (mDisplayReady) {
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                mDisplayContents.valueAt(displayNdx).dump("  ", pw);
+                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+                displayContent.dump("  ", pw);
             }
         } else {
             pw.println("  NO DISPLAY");
@@ -10038,14 +10273,13 @@
 
     void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
-        int j = 0;
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
             for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
                 final WindowState w = windowList.get(winNdx);
                 if (windows == null || windows.contains(w)) {
-                    pw.print("  Window #"); pw.print(j++); pw.print(' ');
+                    pw.print("  Window #"); pw.print(winNdx); pw.print(' ');
                             pw.print(w); pw.println(":");
                     w.dump(pw, "    ", dumpAll || windows != null);
                 }
@@ -10259,7 +10493,8 @@
             synchronized(mWindowMap) {
                 final int numDisplays = mDisplayContents.size();
                 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
+                    final WindowList windowList =
+                            mDisplayContents.valueAt(displayNdx).getWindowList();
                     for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
                         final WindowState w = windowList.get(winNdx);
                         if (name != null) {
@@ -10300,10 +10535,12 @@
      *
      * @param appWindowToken The application that ANR'd, may be null.
      * @param windowState The window that ANR'd, may be null.
+     * @param reason The reason for the ANR, may be null.
      */
-    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
+    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState,
+            String reason) {
         StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
+        PrintWriter pw = new FastPrintWriter(sw, false, 1024);
         pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
         if (appWindowToken != null) {
             pw.println("  Application at fault: " + appWindowToken.stringName);
@@ -10311,6 +10548,9 @@
         if (windowState != null) {
             pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
         }
+        if (reason != null) {
+            pw.println("  Reason: " + reason);
+        }
         pw.println();
         dumpWindowsNoHeaderLocked(pw, true, null);
         pw.close();
@@ -10472,19 +10712,29 @@
     }
 
     private DisplayContent newDisplayContentLocked(final Display display) {
-        DisplayContent displayContent = new DisplayContent(display);
-        mDisplayContents.put(display.getDisplayId(), displayContent);
+        DisplayContent displayContent = new DisplayContent(display, this);
+        final int displayId = display.getDisplayId();
+        mDisplayContents.put(displayId, displayContent);
+
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final Rect rect = new Rect();
-        DisplayInfo info = displayContent.getDisplayInfo();
-        mDisplaySettings.getOverscanLocked(info.name, rect);
-        info.overscanLeft = rect.left;
-        info.overscanTop = rect.top;
-        info.overscanRight = rect.right;
-        info.overscanBottom = rect.bottom;
-        mDisplayManagerService.setOverscan(display.getDisplayId(), rect.left, rect.top,
-                rect.right, rect.bottom);
-        mPolicy.setDisplayOverscan(displayContent.getDisplay(), rect.left, rect.top,
-                rect.right, rect.bottom);
+        mDisplaySettings.getOverscanLocked(displayInfo.name, rect);
+        synchronized (displayContent.mDisplaySizeLock) {
+            displayInfo.overscanLeft = rect.left;
+            displayInfo.overscanTop = rect.top;
+            displayInfo.overscanRight = rect.right;
+            displayInfo.overscanBottom = rect.bottom;
+            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
+                    displayId, displayInfo);
+        }
+        configureDisplayPolicyLocked(displayContent);
+
+        // TODO: Create an input channel for each display with touch capability.
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
+            registerPointerEventListener(displayContent.mTapDetector);
+        }
+
         return displayContent;
     }
 
@@ -10492,7 +10742,7 @@
         if (display == null) {
             throw new IllegalArgumentException("getDisplayContent: display must not be null");
         }
-        newDisplayContentLocked(display);
+        getDisplayContentLocked(display.getDisplayId());
     }
 
     /**
@@ -10566,6 +10816,10 @@
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
         if (displayContent != null) {
             mDisplayContents.delete(displayId);
+            displayContent.close();
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                unregisterPointerEventListener(displayContent.mTapDetector);
+            }
             WindowList windows = displayContent.getWindowList();
             while (!windows.isEmpty()) {
                 final WindowState win = windows.get(windows.size() - 1);
@@ -10586,4 +10840,9 @@
             displayContent.updateDisplayInfo();
         }
     }
+
+    @Override
+    public Object getWindowManagerLock() {
+        return mWindowMap;
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index da15856..d56e225 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -16,8 +16,11 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
+
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -65,11 +68,6 @@
 final class WindowState implements WindowManagerPolicy.WindowState {
     static final String TAG = "WindowState";
 
-    static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY;
-    static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS;
-    static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
-    static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC;
-
     final WindowManagerService mService;
     final WindowManagerPolicy mPolicy;
     final Context mContext;
@@ -300,6 +298,10 @@
     /** When true this window can be displayed on screens owther than mOwnerUid's */
     private boolean mShowToOwnerOnly;
 
+    /** When true this window is at the top of the screen and should be layed out to extend under
+     * the status bar */
+    boolean mUnderStatusBar = true;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, final DisplayContent displayContent) {
@@ -330,7 +332,7 @@
         mContext = mService.mContext;
         DeathRecipient deathRecipient = new DeathRecipient();
         mSeq = seq;
-        mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
+        mEnforceSizeCompat = (mAttrs.flags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
         if (WindowManagerService.localLOGV) Slog.v(
             TAG, "Window " + this + " client=" + c.asBinder()
             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -459,14 +461,20 @@
     public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
         mHaveFrame = true;
 
-        final Rect container = mContainingFrame;
-        container.set(pf);
+        TaskStack stack = mAppToken != null ? getStack() : null;
+        if (stack != null && stack.hasSibling()) {
+            mContainingFrame.set(getStackBounds(stack));
+            if (mUnderStatusBar) {
+                mContainingFrame.top = pf.top;
+            }
+        } else {
+            mContainingFrame.set(pf);
+        }
 
-        final Rect display = mDisplayFrame;
-        display.set(df);
+        mDisplayFrame.set(df);
 
-        final int pw = container.right - container.left;
-        final int ph = container.bottom - container.top;
+        final int pw = mContainingFrame.width();
+        final int ph = mContainingFrame.height();
 
         int w,h;
         if ((mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0) {
@@ -513,18 +521,12 @@
             mContentChanged = true;
         }
 
-        final Rect overscan = mOverscanFrame;
-        overscan.set(of);
+        mOverscanFrame.set(of);
+        mContentFrame.set(cf);
+        mVisibleFrame.set(vf);
 
-        final Rect content = mContentFrame;
-        content.set(cf);
-
-        final Rect visible = mVisibleFrame;
-        visible.set(vf);
-
-        final Rect frame = mFrame;
-        final int fw = frame.width();
-        final int fh = frame.height();
+        final int fw = mFrame.width();
+        final int fh = mFrame.height();
 
         //System.out.println("In: w=" + w + " h=" + h + " container=" +
         //                   container + " x=" + mAttrs.x + " y=" + mAttrs.y);
@@ -538,75 +540,69 @@
             y = mAttrs.y;
         }
 
-        Gravity.apply(mAttrs.gravity, w, h, container,
+        Gravity.apply(mAttrs.gravity, w, h, mContainingFrame,
                 (int) (x + mAttrs.horizontalMargin * pw),
-                (int) (y + mAttrs.verticalMargin * ph), frame);
+                (int) (y + mAttrs.verticalMargin * ph), mFrame);
 
         //System.out.println("Out: " + mFrame);
 
         // Now make sure the window fits in the overall display.
-        Gravity.applyDisplay(mAttrs.gravity, df, frame);
+        Gravity.applyDisplay(mAttrs.gravity, df, mFrame);
 
         // Make sure the content and visible frames are inside of the
         // final window frame.
-        if (content.left < frame.left) content.left = frame.left;
-        if (content.top < frame.top) content.top = frame.top;
-        if (content.right > frame.right) content.right = frame.right;
-        if (content.bottom > frame.bottom) content.bottom = frame.bottom;
-        if (visible.left < frame.left) visible.left = frame.left;
-        if (visible.top < frame.top) visible.top = frame.top;
-        if (visible.right > frame.right) visible.right = frame.right;
-        if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
+        mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
+                Math.max(mContentFrame.top, mFrame.top),
+                Math.min(mContentFrame.right, mFrame.right),
+                Math.min(mContentFrame.bottom, mFrame.bottom));
 
-        final Rect overscanInsets = mOverscanInsets;
-        overscanInsets.left = overscan.left > frame.left ? overscan.left-frame.left : 0;
-        overscanInsets.top = overscan.top > frame.top ? overscan.top-frame.top : 0;
-        overscanInsets.right = overscan.right < frame.right ? frame.right-overscan.right : 0;
-        overscanInsets.bottom = overscan.bottom < frame.bottom ? frame.bottom-overscan.bottom : 0;
+        mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
+                Math.max(mVisibleFrame.top, mFrame.top),
+                Math.min(mVisibleFrame.right, mFrame.right),
+                Math.min(mVisibleFrame.bottom, mFrame.bottom));
 
-        final Rect contentInsets = mContentInsets;
-        contentInsets.left = content.left-frame.left;
-        contentInsets.top = content.top-frame.top;
-        contentInsets.right = frame.right-content.right;
-        contentInsets.bottom = frame.bottom-content.bottom;
+        mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
+                Math.max(mOverscanFrame.top - mFrame.top, 0),
+                Math.max(mFrame.right - mOverscanFrame.right, 0),
+                Math.max(mFrame.bottom - mOverscanFrame.bottom, 0));
 
-        final Rect visibleInsets = mVisibleInsets;
-        visibleInsets.left = visible.left-frame.left;
-        visibleInsets.top = visible.top-frame.top;
-        visibleInsets.right = frame.right-visible.right;
-        visibleInsets.bottom = frame.bottom-visible.bottom;
+        mContentInsets.set(mContentFrame.left - mFrame.left,
+                mContentFrame.top - mFrame.top,
+                mFrame.right - mContentFrame.right,
+                mFrame.bottom - mContentFrame.bottom);
 
-        mCompatFrame.set(frame);
+        mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
+                mVisibleFrame.top - mFrame.top,
+                mFrame.right - mVisibleFrame.right,
+                mFrame.bottom - mVisibleFrame.bottom);
+
+        mCompatFrame.set(mFrame);
         if (mEnforceSizeCompat) {
             // If there is a size compatibility scale being applied to the
             // window, we need to apply this to its insets so that they are
             // reported to the app in its coordinate space.
-            overscanInsets.scale(mInvGlobalScale);
-            contentInsets.scale(mInvGlobalScale);
-            visibleInsets.scale(mInvGlobalScale);
+            mOverscanInsets.scale(mInvGlobalScale);
+            mContentInsets.scale(mInvGlobalScale);
+            mVisibleInsets.scale(mInvGlobalScale);
 
             // Also the scaled frame that we report to the app needs to be
             // adjusted to be in its coordinate space.
             mCompatFrame.scale(mInvGlobalScale);
         }
 
-        if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
+        if (mIsWallpaper && (fw != mFrame.width() || fh != mFrame.height())) {
             final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            mService.updateWallpaperOffsetLocked(this, displayInfo.appWidth, displayInfo.appHeight,
-                    false);
+            mService.updateWallpaperOffsetLocked(this,
+                    displayInfo.logicalWidth, displayInfo.logicalHeight, false);
         }
 
-        if (WindowManagerService.localLOGV) {
-            //if ("com.google.android.youtube".equals(mAttrs.packageName)
-            //        && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
-                Slog.v(TAG, "Resolving (mRequestedWidth="
-                        + mRequestedWidth + ", mRequestedheight="
-                        + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
-                        + "): frame=" + mFrame.toShortString()
-                        + " ci=" + contentInsets.toShortString()
-                        + " vi=" + visibleInsets.toShortString());
-            //}
-        }
+        if (DEBUG_LAYOUT || WindowManagerService.localLOGV) Slog.v(TAG,
+                "Resolving (mRequestedWidth="
+                + mRequestedWidth + ", mRequestedheight="
+                + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
+                + "): frame=" + mFrame.toShortString()
+                + " ci=" + mContentInsets.toShortString()
+                + " vi=" + mVisibleInsets.toShortString());
     }
 
     @Override
@@ -707,6 +703,28 @@
         return mDisplayContent.getDisplayId();
     }
 
+    TaskStack getStack() {
+        AppWindowToken wtoken = mAppToken == null ? mService.mFocusedApp : mAppToken;
+        if (wtoken != null) {
+            Task task = mService.mTaskIdToTask.get(wtoken.groupId);
+            if (task != null) {
+                return task.mStack;
+            }
+        }
+        return mDisplayContent.getHomeStack();
+    }
+
+    Rect getStackBounds() {
+        return getStackBounds(getStack());
+    }
+
+    private Rect getStackBounds(TaskStack stack) {
+        if (stack != null) {
+            return stack.mStackBox.mBounds;
+        }
+        return mFrame;
+    }
+
     public long getInputDispatchingTimeoutNanos() {
         return mAppToken != null
                 ? mAppToken.inputDispatchingTimeoutNanos
@@ -901,7 +919,8 @@
                 || (atoken == null && mRootToken.hidden)
                 || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
                 || mAttachedHidden
-                || mExiting || mDestroying;
+                || (mExiting && !isAnimatingLw())
+                || mDestroying;
     }
 
     /**
@@ -968,12 +987,6 @@
         return configChanged;
     }
 
-    boolean isConfigDiff(int mask) {
-        return mConfiguration != mService.mCurConfiguration
-                && mConfiguration != null
-                && (mConfiguration.diff(mService.mCurConfiguration) & mask) != 0;
-    }
-
     void removeLocked() {
         disposeInputChannel();
 
@@ -1026,7 +1039,7 @@
                     Slog.i(TAG, "WIN DEATH: " + win);
                     if (win != null) {
                         mService.removeWindowLocked(mSession, win);
-                    } else if (WindowState.this.mHasSurface) {
+                    } else if (mHasSurface) {
                         Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
                         mService.removeWindowLocked(mSession, WindowState.this);
                     }
@@ -1129,6 +1142,8 @@
             // we allow the display to be enabled now.
             mService.enableScreenIfNeededLocked();
             if (mService.mCurrentFocus == this) {
+                if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+                        "WindowState.hideLw: setting mFocusMayChange true");
                 mService.mFocusMayChange = true;
             }
         }
@@ -1138,7 +1153,7 @@
         return true;
     }
 
-    public boolean setAppOpVisibilityLw(boolean state) {
+    public void setAppOpVisibilityLw(boolean state) {
         if (mAppOpVisibility != state) {
             mAppOpVisibility = state;
             if (state) {
@@ -1148,13 +1163,11 @@
                 // ops modifies they should only be hidden by policy due to the
                 // lock screen, and the user won't be changing this if locked.
                 // Plus it will quickly be fixed the next time we do a layout.
-                showLw(true, false);
+                showLw(true, true);
             } else {
-                hideLw(true, false);
+                hideLw(true, true);
             }
-            return true;
         }
-        return false;
     }
 
     @Override
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index c07174b..533f626 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -3,6 +3,16 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.WindowManagerService.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.WindowManagerService.localLOGV;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
 
@@ -19,7 +29,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.MagnificationSpec;
-import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowManager;
@@ -35,30 +45,12 @@
 import java.util.ArrayList;
 
 class WinAnimatorList extends ArrayList<WindowStateAnimator> {
-    public WinAnimatorList() {
-        super();
-    }
-
-    public WinAnimatorList(WinAnimatorList other) {
-        super(other);
-    }
 }
 
 /**
  * Keep track of animations and surface operations for a single WindowState.
  **/
 class WindowStateAnimator {
-    static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY;
-    static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
-    static final boolean DEBUG_LAYERS = WindowManagerService.DEBUG_LAYERS;
-    static final boolean DEBUG_STARTING_WINDOW = WindowManagerService.DEBUG_STARTING_WINDOW;
-    static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS;
-    static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
-    static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC;
-    static final boolean localLOGV = WindowManagerService.localLOGV;
-    static final boolean DEBUG_ORIENTATION = WindowManagerService.DEBUG_ORIENTATION;
-    static final boolean DEBUG_SURFACE_TRACE = WindowManagerService.DEBUG_SURFACE_TRACE;
-
     static final String TAG = "WindowStateAnimator";
 
     // Unchanging local convenience fields.
@@ -340,7 +332,7 @@
         mHasTransformation = false;
         mHasLocalTransformation = false;
         if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) {
-            if (WindowState.DEBUG_VISIBILITY) {
+            if (DEBUG_VISIBILITY) {
                 Slog.v(TAG, "Policy visibility changing after anim in " + this + ": "
                         + mWin.mPolicyVisibilityAfterAnim);
             }
@@ -348,6 +340,8 @@
             mWin.mDisplayContent.layoutNeeded = true;
             if (!mWin.mPolicyVisibility) {
                 if (mService.mCurrentFocus == mWin) {
+                    if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+                            "setAnimationLocked: setting mFocusMayChange true");
                     mService.mFocusMayChange = true;
                 }
                 // Window is no longer visible -- make sure if we were waiting
@@ -407,7 +401,7 @@
         if (mSurfaceControl != null) {
             mService.mDestroySurface.add(mWin);
             mWin.mDestroying = true;
-            if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface(
+            if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(
                 mWin, "HIDE (finishExit)", null);
             hide();
         }
@@ -489,7 +483,7 @@
         private final Rect mWindowCrop = new Rect();
         private boolean mShown = false;
         private int mLayerStack;
-        private String mName;
+        private final String mName;
 
         public SurfaceTrace(SurfaceSession s,
                        String name, int w, int h, int format, int flags)
@@ -503,22 +497,22 @@
 
         @Override
         public void setAlpha(float alpha) {
-            super.setAlpha(alpha);
-            if (alpha != mSurfaceTraceAlpha) {
-                mSurfaceTraceAlpha = alpha;
-                Slog.v(SURFACE_TAG, "setAlpha: " + this + ". Called by "
+            if (mSurfaceTraceAlpha != alpha) {
+                Slog.v(SURFACE_TAG, "setAlpha(" + alpha + "): OLD:" + this + ". Called by "
                         + Debug.getCallers(3));
+                mSurfaceTraceAlpha = alpha;
             }
+            super.setAlpha(alpha);
         }
 
         @Override
         public void setLayer(int zorder) {
-            super.setLayer(zorder);
             if (zorder != mLayer) {
-                mLayer = zorder;
-                Slog.v(SURFACE_TAG, "setLayer: " + this + ". Called by "
+                Slog.v(SURFACE_TAG, "setLayer(" + zorder + "): OLD:" + this + ". Called by "
                         + Debug.getCallers(3));
+                mLayer = zorder;
             }
+            super.setLayer(zorder);
 
             sSurfaces.remove(this);
             int i;
@@ -533,69 +527,68 @@
 
         @Override
         public void setPosition(float x, float y) {
-            super.setPosition(x, y);
             if (x != mPosition.x || y != mPosition.y) {
+                Slog.v(SURFACE_TAG, "setPosition(" + x + "," + y + "): OLD:" + this
+                        + ". Called by " + Debug.getCallers(3));
                 mPosition.set(x, y);
-                Slog.v(SURFACE_TAG, "setPosition: " + this + ". Called by "
-                        + Debug.getCallers(3));
             }
+            super.setPosition(x, y);
         }
 
         @Override
         public void setSize(int w, int h) {
-            super.setSize(w, h);
             if (w != mSize.x || h != mSize.y) {
-                mSize.set(w, h);
-                Slog.v(SURFACE_TAG, "setSize: " + this + ". Called by "
+                Slog.v(SURFACE_TAG, "setSize(" + w + "," + h + "): OLD:" + this + ". Called by "
                         + Debug.getCallers(3));
+                mSize.set(w, h);
             }
+            super.setSize(w, h);
         }
 
         @Override
         public void setWindowCrop(Rect crop) {
-            super.setWindowCrop(crop);
             if (crop != null) {
                 if (!crop.equals(mWindowCrop)) {
+                    Slog.v(SURFACE_TAG, "setWindowCrop(" + crop.toShortString() + "): OLD:" + this
+                            + ". Called by " + Debug.getCallers(3));
                     mWindowCrop.set(crop);
-                    Slog.v(SURFACE_TAG, "setWindowCrop: " + this + ". Called by "
-                            + Debug.getCallers(3));
                 }
             }
+            super.setWindowCrop(crop);
         }
 
         @Override
         public void setLayerStack(int layerStack) {
-            super.setLayerStack(layerStack);
             if (layerStack != mLayerStack) {
+                Slog.v(SURFACE_TAG, "setLayerStack(" + layerStack + "): OLD:" + this
+                        + ". Called by " + Debug.getCallers(3));
                 mLayerStack = layerStack;
-                Slog.v(SURFACE_TAG, "setLayerStack: " + this + ". Called by " + Debug.getCallers(3));
             }
+            super.setLayerStack(layerStack);
         }
 
         @Override
         public void hide() {
-            super.hide();
             if (mShown) {
+                Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by " + Debug.getCallers(3));
                 mShown = false;
-                Slog.v(SURFACE_TAG, "hide: " + this + ". Called by "
-                        + Debug.getCallers(3));
             }
+            super.hide();
         }
+
         @Override
         public void show() {
-            super.show();
             if (!mShown) {
+                Slog.v(SURFACE_TAG, "show: OLD:" + this + ". Called by " + Debug.getCallers(3));
                 mShown = true;
-                Slog.v(SURFACE_TAG, "show: " + this + ". Called by "
-                        + Debug.getCallers(3));
             }
+            super.show();
         }
 
         @Override
         public void destroy() {
             super.destroy();
-            Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by "
-                    + Debug.getCallers(3));
+            Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by " + Debug.getCallers(3));
             sSurfaces.remove(this);
         }
 
@@ -648,7 +641,7 @@
             if ((attrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 flags |= SurfaceControl.SECURE;
             }
-            if (WindowState.DEBUG_VISIBILITY) Slog.v(
+            if (DEBUG_VISIBILITY) Slog.v(
                 TAG, "Creating surface in session "
                 + mSession.mSurfaceSession + " window " + this
                 + " w=" + mWin.mCompatFrame.width()
@@ -704,7 +697,7 @@
                         + attrs.format + " flags=0x"
                         + Integer.toHexString(flags)
                         + " / " + this);
-            } catch (SurfaceControl.OutOfResourcesException e) {
+            } catch (OutOfResourcesException e) {
                 mWin.mHasSurface = false;
                 Slog.w(TAG, "OutOfResourcesException creating surface");
                 mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
@@ -1185,7 +1178,7 @@
                 mAnimator.setPendingLayoutChanges(displayId,
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
-                    mService.startDimmingLocked(this, w.mExiting ? 0 : w.mAttrs.dimAmount);
+                    w.getStack().startDimmingIfNeeded(this);
                 }
             } catch (RuntimeException e) {
                 // If something goes wrong with the surface (such
@@ -1282,6 +1275,11 @@
                             if (mIsWallpaper) {
                                 mService.dispatchWallpaperVisibility(w, true);
                             }
+                            // This draw means the difference between unique content and mirroring.
+                            // Run another pass through performLayout to set mHasContent in the
+                            // LogicalDisplay.
+                            mAnimator.setPendingLayoutChanges(w.getDisplayId(),
+                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         } else {
                             w.mOrientationChanging = false;
                         }
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java
index bd0ace8..2267123 100644
--- a/services/java/com/android/server/wm/WindowToken.java
+++ b/services/java/com/android/server/wm/WindowToken.java
@@ -19,7 +19,6 @@
 import android.os.IBinder;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 /**
  * Container of a set of related windows in the window manager.  Often this
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index b313d48..98e9b30 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -3,7 +3,8 @@
 
 LOCAL_SRC_FILES:= \
     com_android_server_AlarmManagerService.cpp \
-    com_android_server_BatteryService.cpp \
+    com_android_server_AssetAtlasService.cpp \
+    com_android_server_ConsumerIrService.cpp \
     com_android_server_input_InputApplicationHandle.cpp \
     com_android_server_input_InputManagerService.cpp \
     com_android_server_input_InputWindowHandle.cpp \
@@ -15,6 +16,7 @@
     com_android_server_UsbHostManager.cpp \
     com_android_server_VibratorService.cpp \
     com_android_server_location_GpsLocationProvider.cpp \
+    com_android_server_location_FlpHardwareProvider.cpp \
     com_android_server_connectivity_Vpn.cpp \
     onload.cpp
 
@@ -22,6 +24,7 @@
     $(JNI_H_INCLUDE) \
     frameworks/base/services \
     frameworks/base/core/jni \
+    frameworks/native/services \
     external/skia/include/core \
     libcore/include \
     libcore/include/libsuspend \
@@ -31,19 +34,25 @@
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
     libandroidfw \
+    libbinder \
     libcutils \
     liblog \
     libhardware \
     libhardware_legacy \
     libnativehelper \
-    libsystem_server \
     libutils \
     libui \
     libinput \
+    libinputservice \
+    libsensorservice \
     libskia \
     libgui \
     libusbhost \
-    libsuspend
+    libsuspend \
+    libEGL \
+    libGLESv2
+
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
 
 ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
     LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
diff --git a/services/jni/com_android_server_AssetAtlasService.cpp b/services/jni/com_android_server_AssetAtlasService.cpp
new file mode 100644
index 0000000..885d21e
--- /dev/null
+++ b/services/jni/com_android_server_AssetAtlasService.cpp
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AssetAtlasService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <android_view_GraphicBuffer.h>
+#include <cutils/log.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Defines
+// ----------------------------------------------------------------------------
+
+// Defines how long to wait for the GPU when uploading the atlas
+// This timeout is defined in nanoseconds (see EGL_KHR_fence_sync extension)
+#define FENCE_TIMEOUT 2000000000
+
+// ----------------------------------------------------------------------------
+// JNI Helpers
+// ----------------------------------------------------------------------------
+
+static struct {
+    jfieldID mFinalizer;
+    jfieldID mNativeCanvas;
+} gCanvasClassInfo;
+
+static struct {
+    jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
+#define GET_INT(object, field) \
+    env->GetIntField(object, field)
+
+#define SET_INT(object, field, value) \
+    env->SetIntField(object, field, value)
+
+// ----------------------------------------------------------------------------
+// Canvas management
+// ----------------------------------------------------------------------------
+
+static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
+    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
+    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
+            GET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas));
+    SET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas, (int) newCanvas);
+    SET_INT(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int) newCanvas);
+    SkSafeUnref(previousCanvas);
+}
+
+static SkBitmap* com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
+        jobject canvas, jint width, jint height) {
+
+    SkBitmap* bitmap = new SkBitmap;
+    bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+    bitmap->allocPixels();
+    bitmap->eraseColor(0);
+
+    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
+    swapCanvasPtr(env, canvas, nativeCanvas);
+
+    return bitmap;
+}
+
+static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject,
+        jobject canvas, SkBitmap* bitmap) {
+
+    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+    swapCanvasPtr(env, canvas, nativeCanvas);
+
+    delete bitmap;
+}
+
+#define CLEANUP_GL_AND_RETURN(result) \
+    if (fence != EGL_NO_SYNC_KHR) eglDestroySyncKHR(display, fence); \
+    if (image) eglDestroyImageKHR(display, image); \
+    if (texture) glDeleteTextures(1, &texture); \
+    if (surface != EGL_NO_SURFACE) eglDestroySurface(display, surface); \
+    if (context != EGL_NO_CONTEXT) eglDestroyContext(display, context); \
+    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); \
+    eglReleaseThread(); \
+    eglTerminate(display); \
+    return result;
+
+static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
+        jobject graphicBuffer, SkBitmap* bitmap) {
+
+    // The goal of this method is to copy the bitmap into the GraphicBuffer
+    // using the GPU to swizzle the texture content
+    sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
+
+    if (buffer != NULL) {
+        EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        if (display == EGL_NO_DISPLAY) return false;
+
+        EGLint major;
+        EGLint minor;
+        if (!eglInitialize(display, &major, &minor)) {
+            ALOGW("Could not initialize EGL");
+            return false;
+        }
+
+        // We're going to use a 1x1 pbuffer surface later on
+        // The configuration doesn't really matter for what we're trying to do
+        EGLint configAttrs[] = {
+                EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                EGL_RED_SIZE, 8,
+                EGL_GREEN_SIZE, 8,
+                EGL_BLUE_SIZE, 8,
+                EGL_ALPHA_SIZE, 0,
+                EGL_DEPTH_SIZE, 0,
+                EGL_STENCIL_SIZE, 0,
+                EGL_NONE
+        };
+        EGLConfig configs[1];
+        EGLint configCount;
+        if (!eglChooseConfig(display, configAttrs, configs, 1, &configCount)) {
+            ALOGW("Could not select EGL configuration");
+            eglReleaseThread();
+            eglTerminate(display);
+            return false;
+        }
+        if (configCount <= 0) {
+            ALOGW("Could not find EGL configuration");
+            eglReleaseThread();
+            eglTerminate(display);
+            return false;
+        }
+
+        // These objects are initialized below but the default "null"
+        // values are used to cleanup properly at any point in the
+        // initialization sequence
+        GLuint texture = 0;
+        EGLImageKHR image = EGL_NO_IMAGE_KHR;
+        EGLSurface surface = EGL_NO_SURFACE;
+        EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
+        EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+        EGLContext context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, attrs);
+        if (context == EGL_NO_CONTEXT) {
+            ALOGW("Could not create EGL context");
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        // Create the 1x1 pbuffer
+        EGLint surfaceAttrs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+        surface = eglCreatePbufferSurface(display, configs[0], surfaceAttrs);
+        if (surface == EGL_NO_SURFACE) {
+            ALOGW("Could not create EGL surface");
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        if (!eglMakeCurrent(display, surface, surface, context)) {
+            ALOGW("Could not change current EGL context");
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        // We use an EGLImage to access the content of the GraphicBuffer
+        // The EGL image is later bound to a 2D texture
+        EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+        EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+        image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
+                EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
+        if (image == EGL_NO_IMAGE_KHR) {
+            ALOGW("Could not create EGL image");
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        glGenTextures(1, &texture);
+        glBindTexture(GL_TEXTURE_2D, texture);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+        if (glGetError() != GL_NO_ERROR) {
+            ALOGW("Could not create/bind texture");
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        // Upload the content of the bitmap in the GraphicBuffer
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->width(), bitmap->height(),
+                GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
+        if (glGetError() != GL_NO_ERROR) {
+            ALOGW("Could not upload to texture");
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        // The fence is used to wait for the texture upload to finish
+        // properly. We cannot rely on glFlush() and glFinish() as
+        // some drivers completely ignore these API calls
+        fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
+        if (fence == EGL_NO_SYNC_KHR) {
+            ALOGW("Could not create sync fence %#x", eglGetError());
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
+        // pipeline flush (similar to what a glFlush() would do.)
+        EGLint waitStatus = eglClientWaitSyncKHR(display, fence,
+                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
+        if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
+            ALOGW("Failed to wait for the fence %#x", eglGetError());
+            CLEANUP_GL_AND_RETURN(false);
+        }
+
+        CLEANUP_GL_AND_RETURN(true);
+    }
+
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+const char* const kClassPathName = "com/android/server/AssetAtlasService";
+
+static JNINativeMethod gMethods[] = {
+    { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)I",
+            (void*) com_android_server_AssetAtlasService_acquireCanvas },
+    { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;I)V",
+            (void*) com_android_server_AssetAtlasService_releaseCanvas },
+    { "nUploadAtlas", "(Landroid/view/GraphicBuffer;I)Z",
+            (void*) com_android_server_AssetAtlasService_upload },
+};
+
+int register_android_server_AssetAtlasService(JNIEnv* env) {
+    jclass clazz;
+
+    FIND_CLASS(clazz, "android/graphics/Canvas");
+    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
+            "Landroid/graphics/Canvas$CanvasFinalizer;");
+    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
+
+    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
+    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
+
+    return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
deleted file mode 100644
index 433950d..0000000
--- a/services/jni/com_android_server_BatteryService.cpp
+++ /dev/null
@@ -1,471 +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.
- */
-
-#define LOG_TAG "BatteryService"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <linux/ioctl.h>
-#include <utils/Vector.h>
-#include <utils/String8.h>
-
-namespace android {
-
-#define POWER_SUPPLY_PATH "/sys/class/power_supply"
-
-struct FieldIds {
-    // members
-    jfieldID mAcOnline;
-    jfieldID mUsbOnline;
-    jfieldID mWirelessOnline;
-    jfieldID mBatteryStatus;
-    jfieldID mBatteryHealth;
-    jfieldID mBatteryPresent;
-    jfieldID mBatteryLevel;
-    jfieldID mBatteryVoltage;
-    jfieldID mBatteryTemperature;
-    jfieldID mBatteryTechnology;
-};
-static FieldIds gFieldIds;
-
-struct BatteryManagerConstants {
-    jint statusUnknown;
-    jint statusCharging;
-    jint statusDischarging;
-    jint statusNotCharging;
-    jint statusFull;
-    jint healthUnknown;
-    jint healthGood;
-    jint healthOverheat;
-    jint healthDead;
-    jint healthOverVoltage;
-    jint healthUnspecifiedFailure;
-    jint healthCold;
-};
-static BatteryManagerConstants gConstants;
-
-struct PowerSupplyPaths {
-    String8 batteryStatusPath;
-    String8 batteryHealthPath;
-    String8 batteryPresentPath;
-    String8 batteryCapacityPath;
-    String8 batteryVoltagePath;
-    String8 batteryTemperaturePath;
-    String8 batteryTechnologyPath;
-};
-static PowerSupplyPaths gPaths;
-
-static Vector<String8> gChargerNames;
-
-static int gVoltageDivisor = 1;
-
-enum PowerSupplyType {
-     ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
-     ANDROID_POWER_SUPPLY_TYPE_AC,
-     ANDROID_POWER_SUPPLY_TYPE_USB,
-     ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
-     ANDROID_POWER_SUPPLY_TYPE_BATTERY
-};
-
-static jint getBatteryStatus(const char* status)
-{
-    switch (status[0]) {
-        case 'C': return gConstants.statusCharging;         // Charging
-        case 'D': return gConstants.statusDischarging;      // Discharging
-        case 'F': return gConstants.statusFull;             // Full
-        case 'N': return gConstants.statusNotCharging;      // Not charging
-        case 'U': return gConstants.statusUnknown;          // Unknown
-            
-        default: {
-            ALOGW("Unknown battery status '%s'", status);
-            return gConstants.statusUnknown;
-        }
-    }
-}
-
-static jint getBatteryHealth(const char* status)
-{
-    switch (status[0]) {
-        case 'C': return gConstants.healthCold;         // Cold
-        case 'D': return gConstants.healthDead;         // Dead
-        case 'G': return gConstants.healthGood;         // Good
-        case 'O': {
-            if (strcmp(status, "Overheat") == 0) {
-                return gConstants.healthOverheat;
-            } else if (strcmp(status, "Over voltage") == 0) {
-                return gConstants.healthOverVoltage;
-            }
-            ALOGW("Unknown battery health[1] '%s'", status);
-            return gConstants.healthUnknown;
-        }
-        
-        case 'U': {
-            if (strcmp(status, "Unspecified failure") == 0) {
-                return gConstants.healthUnspecifiedFailure;
-            } else if (strcmp(status, "Unknown") == 0) {
-                return gConstants.healthUnknown;
-            }
-            // fall through
-        }
-            
-        default: {
-            ALOGW("Unknown battery health[2] '%s'", status);
-            return gConstants.healthUnknown;
-        }
-    }
-}
-
-static int readFromFile(const String8& path, char* buf, size_t size)
-{
-    if (path.isEmpty())
-        return -1;
-    int fd = open(path.string(), O_RDONLY, 0);
-    if (fd == -1) {
-        ALOGE("Could not open '%s'", path.string());
-        return -1;
-    }
-    
-    ssize_t count = read(fd, buf, size);
-    if (count > 0) {
-        while (count > 0 && buf[count-1] == '\n')
-            count--;
-        buf[count] = '\0';
-    } else {
-        buf[0] = '\0';
-    } 
-
-    close(fd);
-    return count;
-}
-
-static void setBooleanField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
-{
-    const int SIZE = 16;
-    char buf[SIZE];
-    
-    jboolean value = false;
-    if (readFromFile(path, buf, SIZE) > 0) {
-        if (buf[0] != '0') {
-            value = true;
-        }
-    }
-    env->SetBooleanField(obj, fieldID, value);
-}
-
-static void setIntField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
-{
-    const int SIZE = 128;
-    char buf[SIZE];
-    
-    jint value = 0;
-    if (readFromFile(path, buf, SIZE) > 0) {
-        value = atoi(buf);
-    }
-    env->SetIntField(obj, fieldID, value);
-}
-
-static void setVoltageField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
-{
-    const int SIZE = 128;
-    char buf[SIZE];
-
-    jint value = 0;
-    if (readFromFile(path, buf, SIZE) > 0) {
-        value = atoi(buf);
-        value /= gVoltageDivisor;
-    }
-    env->SetIntField(obj, fieldID, value);
-}
-
-static PowerSupplyType readPowerSupplyType(const String8& path) {
-    const int SIZE = 128;
-    char buf[SIZE];
-    int length = readFromFile(path, buf, SIZE);
-
-    if (length <= 0)
-        return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
-    if (buf[length - 1] == '\n')
-        buf[length - 1] = 0;
-    if (strcmp(buf, "Battery") == 0)
-        return ANDROID_POWER_SUPPLY_TYPE_BATTERY;
-    else if (strcmp(buf, "Mains") == 0 || strcmp(buf, "USB_DCP") == 0 ||
-             strcmp(buf, "USB_CDP") == 0 || strcmp(buf, "USB_ACA") == 0)
-        return ANDROID_POWER_SUPPLY_TYPE_AC;
-    else if (strcmp(buf, "USB") == 0)
-        return ANDROID_POWER_SUPPLY_TYPE_USB;
-    else if (strcmp(buf, "Wireless") == 0)
-        return ANDROID_POWER_SUPPLY_TYPE_WIRELESS;
-    else
-        return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
-}
-
-static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
-{
-    setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
-    
-    setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
-    setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);
-    setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);
-    
-    const int SIZE = 128;
-    char buf[SIZE];
-    
-    if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)
-        env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
-    else
-        env->SetIntField(obj, gFieldIds.mBatteryStatus,
-                         gConstants.statusUnknown);
-    
-    if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)
-        env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
-
-    if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
-        env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
-
-    unsigned int i;
-    String8 path;
-    jboolean acOnline = false;
-    jboolean usbOnline = false;
-    jboolean wirelessOnline = false;
-
-    for (i = 0; i < gChargerNames.size(); i++) {
-        path.clear();
-        path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH,
-                          gChargerNames[i].string());
-
-        if (readFromFile(path, buf, SIZE) > 0) {
-            if (buf[0] != '0') {
-                path.clear();
-                path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH,
-                                  gChargerNames[i].string());
-                switch(readPowerSupplyType(path)) {
-                case ANDROID_POWER_SUPPLY_TYPE_AC:
-                    acOnline = true;
-                    break;
-                case ANDROID_POWER_SUPPLY_TYPE_USB:
-                    usbOnline = true;
-                    break;
-                case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
-                    wirelessOnline = true;
-                    break;
-                default:
-                    ALOGW("%s: Unknown power supply type",
-                          gChargerNames[i].string());
-                }
-            }
-        }
-    }
-
-    env->SetBooleanField(obj, gFieldIds.mAcOnline, acOnline);
-    env->SetBooleanField(obj, gFieldIds.mUsbOnline, usbOnline);
-    env->SetBooleanField(obj, gFieldIds.mWirelessOnline, wirelessOnline);
-}
-
-static JNINativeMethod sMethods[] = {
-     /* name, signature, funcPtr */
-        {"native_update", "()V", (void*)android_server_BatteryService_update},
-};
-
-int register_android_server_BatteryService(JNIEnv* env)
-{
-    String8 path;
-    struct dirent* entry;
-
-    DIR* dir = opendir(POWER_SUPPLY_PATH);
-    if (dir == NULL) {
-        ALOGE("Could not open %s\n", POWER_SUPPLY_PATH);
-    } else {
-        while ((entry = readdir(dir))) {
-            const char* name = entry->d_name;
-
-            // ignore "." and ".."
-            if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
-                continue;
-            }
-
-            char buf[20];
-            // Look for "type" file in each subdirectory
-            path.clear();
-            path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH, name);
-            switch(readPowerSupplyType(path)) {
-            case ANDROID_POWER_SUPPLY_TYPE_AC:
-            case ANDROID_POWER_SUPPLY_TYPE_USB:
-            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
-                path.clear();
-                path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH, name);
-                if (access(path.string(), R_OK) == 0)
-                    gChargerNames.add(String8(name));
-                break;
-
-            case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
-                path.clear();
-                path.appendFormat("%s/%s/status", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryStatusPath = path;
-                path.clear();
-                path.appendFormat("%s/%s/health", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryHealthPath = path;
-                path.clear();
-                path.appendFormat("%s/%s/present", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryPresentPath = path;
-                path.clear();
-                path.appendFormat("%s/%s/capacity", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryCapacityPath = path;
-
-                path.clear();
-                path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0) {
-                    gPaths.batteryVoltagePath = path;
-                    // voltage_now is in microvolts, not millivolts
-                    gVoltageDivisor = 1000;
-                } else {
-                    path.clear();
-                    path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                            gPaths.batteryVoltagePath = path;
-                }
-
-                path.clear();
-                path.appendFormat("%s/%s/temp", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0) {
-                    gPaths.batteryTemperaturePath = path;
-                } else {
-                    path.clear();
-                    path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                            gPaths.batteryTemperaturePath = path;
-                }
-
-                path.clear();
-                path.appendFormat("%s/%s/technology", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryTechnologyPath = path;
-                break;
-            }
-        }
-        closedir(dir);
-    }
-
-    if (!gChargerNames.size())
-        ALOGE("No charger supplies found");
-    if (!gPaths.batteryStatusPath)
-        ALOGE("batteryStatusPath not found");
-    if (!gPaths.batteryHealthPath)
-        ALOGE("batteryHealthPath not found");
-    if (!gPaths.batteryPresentPath)
-        ALOGE("batteryPresentPath not found");
-    if (!gPaths.batteryCapacityPath)
-        ALOGE("batteryCapacityPath not found");
-    if (!gPaths.batteryVoltagePath)
-        ALOGE("batteryVoltagePath not found");
-    if (!gPaths.batteryTemperaturePath)
-        ALOGE("batteryTemperaturePath not found");
-    if (!gPaths.batteryTechnologyPath)
-        ALOGE("batteryTechnologyPath not found");
-
-    jclass clazz = env->FindClass("com/android/server/BatteryService");
-
-    if (clazz == NULL) {
-        ALOGE("Can't find com/android/server/BatteryService");
-        return -1;
-    }
-    
-    gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
-    gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
-    gFieldIds.mWirelessOnline = env->GetFieldID(clazz, "mWirelessOnline", "Z");
-    gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
-    gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
-    gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
-    gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
-    gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
-    gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
-    gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I");
-
-    LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
-    LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
-    LOG_FATAL_IF(gFieldIds.mWirelessOnline == NULL, "Unable to find BatteryService.WIRELESS_ONLINE_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH");
-    LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH");
-    
-    clazz = env->FindClass("android/os/BatteryManager");
-    
-    if (clazz == NULL) {
-        ALOGE("Can't find android/os/BatteryManager");
-        return -1;
-    }
-    
-    gConstants.statusUnknown = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I"));
-            
-    gConstants.statusCharging = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I"));
-            
-    gConstants.statusDischarging = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I"));
-    
-    gConstants.statusNotCharging = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I"));
-    
-    gConstants.statusFull = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I"));
-
-    gConstants.healthUnknown = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I"));
-
-    gConstants.healthGood = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I"));
-
-    gConstants.healthOverheat = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I"));
-
-    gConstants.healthDead = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I"));
-
-    gConstants.healthOverVoltage = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I"));
-            
-    gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz, 
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
-    
-    gConstants.healthCold = env->GetStaticIntField(clazz,
-            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I"));
-
-    return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/services/jni/com_android_server_ConsumerIrService.cpp b/services/jni/com_android_server_ConsumerIrService.cpp
new file mode 100644
index 0000000..004c0aa
--- /dev/null
+++ b/services/jni/com_android_server_ConsumerIrService.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ConsumerIrService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdlib.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/consumerir.h>
+#include <ScopedPrimitiveArray.h>
+
+namespace android {
+
+static jint halOpen(JNIEnv *env, jobject obj) {
+    hw_module_t const* module;
+    consumerir_device_t *dev;
+    int err;
+
+    err = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &module);
+    if (err != 0) {
+        ALOGE("Can't open consumer IR HW Module, error: %d", err);
+        return 0;
+    }
+
+    err = module->methods->open(module, CONSUMERIR_TRANSMITTER,
+            (hw_device_t **) &dev);
+    if (err < 0) {
+        ALOGE("Can't open consumer IR transmitter, error: %d", err);
+        return 0;
+    }
+
+    return reinterpret_cast<jint>(dev);
+}
+
+static jint halTransmit(JNIEnv *env, jobject obj, jint halObject,
+   jint carrierFrequency, jintArray pattern) {
+    int ret;
+
+    consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
+    ScopedIntArrayRO cPattern(env, pattern);
+    if (cPattern.get() == NULL) {
+        return -EINVAL;
+    }
+    jsize patternLength = cPattern.size();
+
+    ret = dev->transmit(dev, carrierFrequency, cPattern.get(), patternLength);
+
+    return reinterpret_cast<jint>(ret);
+}
+
+static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject obj,
+    jint halObject) {
+    consumerir_device_t *dev = (consumerir_device_t *) halObject;
+    consumerir_freq_range_t *ranges;
+    int len;
+
+    len = dev->get_num_carrier_freqs(dev);
+    if (len <= 0)
+        return NULL;
+
+    ranges = new consumerir_freq_range_t[len];
+
+    len = dev->get_carrier_freqs(dev, len, ranges);
+    if (len <= 0) {
+        delete[] ranges;
+        return NULL;
+    }
+
+    int i;
+    ScopedIntArrayRW freqsOut(env, env->NewIntArray(len*2));
+    jint *arr = freqsOut.get();
+    if (arr == NULL) {
+        delete[] ranges;
+        return NULL;
+    }
+    for (i = 0; i < len; i++) {
+        arr[i*2] = ranges[i].min;
+        arr[i*2+1] = ranges[i].max;
+    }
+
+    delete[] ranges;
+    return freqsOut.getJavaArray();
+}
+
+static JNINativeMethod method_table[] = {
+    { "halOpen", "()I", (void *)halOpen },
+    { "halTransmit", "(II[I)I", (void *)halTransmit },
+    { "halGetCarrierFrequencies", "(I)[I", (void *)halGetCarrierFrequencies},
+};
+
+int register_android_server_ConsumerIrService(JNIEnv *env) {
+    return jniRegisterNativeMethods(env, "com/android/server/ConsumerIrService",
+            method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/com_android_server_SystemServer.cpp b/services/jni/com_android_server_SystemServer.cpp
index ae29405..0625544 100644
--- a/services/jni/com_android_server_SystemServer.cpp
+++ b/services/jni/com_android_server_SystemServer.cpp
@@ -13,19 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include <sensorservice/SensorService.h>
+
+#include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
 
-#include "jni.h"
-#include "JNIHelp.h"
-
 namespace android {
 
-extern "C" int system_init();
-
-static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
-{
-    system_init();
+static void android_server_SystemServer_nativeInit(JNIEnv* env, jobject clazz) {
+    char propBuf[PROPERTY_VALUE_MAX];
+    property_get("system_init.startsensorservice", propBuf, "1");
+    if (strcmp(propBuf, "1") == 0) {
+        // Start the sensor service
+        SensorService::instantiate();
+    }
 }
 
 /*
@@ -33,7 +39,7 @@
  */
 static JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
-    { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
+    { "nativeInit", "()V", (void*) android_server_SystemServer_nativeInit },
 };
 
 int register_android_server_SystemServer(JNIEnv* env)
@@ -43,5 +49,3 @@
 }
 
 }; // namespace android
-
-
diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/jni/com_android_server_UsbDeviceManager.cpp
index 0014db5..3551733 100644
--- a/services/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/jni/com_android_server_UsbDeviceManager.cpp
@@ -20,6 +20,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 
 #include <stdio.h>
 #include <asm/byteorder.h>
diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/jni/com_android_server_UsbHostManager.cpp
index d0a6cdf..639790b7 100644
--- a/services/jni/com_android_server_UsbHostManager.cpp
+++ b/services/jni/com_android_server_UsbHostManager.cpp
@@ -20,6 +20,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 #include "utils/Vector.h"
 
 #include <usbhost/usbhost.h>
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 09e5be4..4ab2086 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -29,6 +29,7 @@
 #include "jni.h"
 #include <limits.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
 
 #include <utils/Log.h>
 #include <utils/Looper.h>
@@ -191,7 +192,8 @@
             uint32_t policyFlags);
     virtual void notifyConfigurationChanged(nsecs_t when);
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputWindowHandle>& inputWindowHandle);
+            const sp<InputWindowHandle>& inputWindowHandle,
+            const String8& reason);
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
@@ -553,7 +555,7 @@
 }
 
 nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-        const sp<InputWindowHandle>& inputWindowHandle) {
+        const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     ALOGD("notifyANR");
 #endif
@@ -564,15 +566,18 @@
             getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
     jobject inputWindowHandleObj =
             getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+    jstring reasonObj = env->NewStringUTF(reason.string());
 
     jlong newTimeout = env->CallLongMethod(mServiceObj,
-                gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj);
+                gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
+                reasonObj);
     if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
         newTimeout = 0; // abort dispatch
     } else {
         assert(newTimeout >= 0);
     }
 
+    env->DeleteLocalRef(reasonObj);
     env->DeleteLocalRef(inputWindowHandleObj);
     env->DeleteLocalRef(inputApplicationHandleObj);
     return newTimeout;
@@ -1379,7 +1384,7 @@
 
     GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
             "notifyANR",
-            "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;)J");
+            "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;Ljava/lang/String;)J");
 
     GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
             "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
new file mode 100644
index 0000000..6c14887
--- /dev/null
+++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -0,0 +1,1002 @@
+/*
+ * 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/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "FlpHardwareProvider"
+#define LOG_NDEBUG  0
+
+#define WAKE_LOCK_NAME  "FLP"
+#define LOCATION_CLASS_NAME "android/location/Location"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+#include "hardware/fused_location.h"
+#include "hardware_legacy/power.h"
+
+static jobject sCallbacksObj = NULL;
+static JNIEnv *sCallbackEnv = NULL;
+static hw_device_t* sHardwareDevice = NULL;
+
+static jmethodID sOnLocationReport = NULL;
+static jmethodID sOnDataReport = NULL;
+static jmethodID sOnGeofenceTransition = NULL;
+static jmethodID sOnGeofenceMonitorStatus = NULL;
+static jmethodID sOnGeofenceAdd = NULL;
+static jmethodID sOnGeofenceRemove = NULL;
+static jmethodID sOnGeofencePause = NULL;
+static jmethodID sOnGeofenceResume = NULL;
+
+static const FlpLocationInterface* sFlpInterface = NULL;
+static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
+static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
+static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
+
+namespace android {
+
+static inline void CheckExceptions(JNIEnv* env, const char* methodName) {
+  if(!env->ExceptionCheck()) {
+    return;
+  }
+
+  ALOGE("An exception was thrown by '%s'.", methodName);
+  LOGE_EX(env);
+  env->ExceptionClear();
+}
+
+static inline void ThrowOnError(
+    JNIEnv* env,
+    int resultCode,
+    const char* methodName) {
+  if(resultCode == FLP_RESULT_SUCCESS) {
+    return;
+  }
+
+  ALOGE("Error %d in '%s'", resultCode, methodName);
+  env->FatalError(methodName);
+}
+
+static bool IsValidCallbackThread() {
+  JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+  if(sCallbackEnv == NULL || sCallbackEnv != env) {
+    ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv);
+    return false;
+  }
+
+  return true;
+}
+
+static int SetThreadEvent(ThreadEvent event) {
+  JavaVM* javaVm = AndroidRuntime::getJavaVM();
+
+  switch(event) {
+    case ASSOCIATE_JVM:
+    {
+      if(sCallbackEnv != NULL) {
+        ALOGE(
+            "Attempted to associate callback in '%s'. Callback already associated.",
+            __FUNCTION__
+            );
+        return FLP_RESULT_ERROR;
+      }
+
+      JavaVMAttachArgs args = {
+          JNI_VERSION_1_6,
+          "FLP Service Callback Thread",
+          /* group */ NULL
+      };
+
+      jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
+      if (attachResult != 0) {
+        ALOGE("Callback thread attachment error: %d", attachResult);
+        return FLP_RESULT_ERROR;
+      }
+
+      ALOGV("Callback thread attached: %p", sCallbackEnv);
+      break;
+    }
+    case DISASSOCIATE_JVM:
+    {
+      if (!IsValidCallbackThread()) {
+        ALOGE(
+            "Attempted to dissasociate an unnownk callback thread : '%s'.",
+            __FUNCTION__
+            );
+        return FLP_RESULT_ERROR;
+      }
+
+      if (javaVm->DetachCurrentThread() != 0) {
+        return FLP_RESULT_ERROR;
+      }
+
+      sCallbackEnv = NULL;
+      break;
+    }
+    default:
+      ALOGE("Invalid ThreadEvent request %d", event);
+      return FLP_RESULT_ERROR;
+  }
+
+  return FLP_RESULT_SUCCESS;
+}
+
+/*
+ * Initializes the FlpHardwareProvider class from the native side by opening
+ * the HW module and obtaining the proper interfaces.
+ */
+static void ClassInit(JNIEnv* env, jclass clazz) {
+  // get references to the Java provider methods
+  sOnLocationReport = env->GetMethodID(
+      clazz,
+      "onLocationReport",
+      "([Landroid/location/Location;)V");
+  sOnDataReport = env->GetMethodID(
+      clazz,
+      "onDataReport",
+      "(Ljava/lang/String;)V"
+      );
+  sOnGeofenceTransition = env->GetMethodID(
+      clazz,
+      "onGeofenceTransition",
+      "(ILandroid/location/Location;IJI)V"
+      );
+  sOnGeofenceMonitorStatus = env->GetMethodID(
+      clazz,
+      "onGeofenceMonitorStatus",
+      "(IILandroid/location/Location;)V"
+      );
+  sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
+  sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
+  sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
+  sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
+}
+
+/*
+ * Helper function to unwrap a java object back into a FlpLocation structure.
+ */
+static void TranslateFromObject(
+    JNIEnv* env,
+    jobject locationObject,
+    FlpLocation& location) {
+  location.size = sizeof(FlpLocation);
+  location.flags = 0;
+
+  jclass locationClass = env->GetObjectClass(locationObject);
+
+  jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
+  location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
+  jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
+  location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
+  jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
+  location.timestamp = env->CallLongMethod(locationObject, getTime);
+  location.flags |= FLP_LOCATION_HAS_LAT_LONG;
+
+  jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
+  if (env->CallBooleanMethod(locationObject, hasAltitude)) {
+    jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
+    location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
+    location.flags |= FLP_LOCATION_HAS_ALTITUDE;
+  }
+
+  jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
+  if (env->CallBooleanMethod(locationObject, hasSpeed)) {
+    jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
+    location.speed = env->CallFloatMethod(locationObject, getSpeed);
+    location.flags |= FLP_LOCATION_HAS_SPEED;
+  }
+
+  jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
+  if (env->CallBooleanMethod(locationObject, hasBearing)) {
+    jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
+    location.bearing = env->CallFloatMethod(locationObject, getBearing);
+    location.flags |= FLP_LOCATION_HAS_BEARING;
+  }
+
+  jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
+  if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
+    jmethodID getAccuracy = env->GetMethodID(
+        locationClass,
+        "getAccuracy",
+        "()F"
+        );
+    location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
+    location.flags |= FLP_LOCATION_HAS_ACCURACY;
+  }
+
+  // TODO: wire sources_used if Location class exposes them
+
+  env->DeleteLocalRef(locationClass);
+}
+
+/*
+ * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
+ */
+static void TranslateFromObject(
+    JNIEnv* env,
+    jobject batchOptionsObject,
+    FlpBatchOptions& batchOptions) {
+  jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
+
+  jmethodID getMaxPower = env->GetMethodID(
+      batchOptionsClass,
+      "getMaxPowerAllocationInMW",
+      "()D"
+      );
+  batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
+      batchOptionsObject,
+      getMaxPower
+      );
+
+  jmethodID getPeriod = env->GetMethodID(
+      batchOptionsClass,
+      "getPeriodInNS",
+      "()J"
+      );
+  batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
+
+  jmethodID getSourcesToUse = env->GetMethodID(
+      batchOptionsClass,
+      "getSourcesToUse",
+      "()I"
+      );
+  batchOptions.sources_to_use = env->CallIntMethod(
+      batchOptionsObject,
+      getSourcesToUse
+      );
+
+  jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
+  batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
+
+  env->DeleteLocalRef(batchOptionsClass);
+}
+
+/*
+ * Helper function to unwrap Geofence structures from the Java Runtime calls.
+ */
+static void TranslateGeofenceFromGeofenceHardwareRequestParcelable(
+    JNIEnv* env,
+    jobject geofenceRequestObject,
+    Geofence& geofence) {
+  jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject);
+
+  jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I");
+  geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId);
+
+  jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I");
+  // this works because GeofenceHardwareRequest.java and fused_location.h have
+  // the same notion of geofence types
+  GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType);
+  if(type != TYPE_CIRCLE) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+  geofence.data->type = type;
+  GeofenceCircle& circle = geofence.data->geofence.circle;
+
+  jmethodID getLatitude = env->GetMethodID(
+      geofenceRequestClass,
+      "getLatitude",
+      "()D");
+  circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude);
+
+  jmethodID getLongitude = env->GetMethodID(
+      geofenceRequestClass,
+      "getLongitude",
+      "()D");
+  circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude);
+
+  jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D");
+  circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius);
+
+  GeofenceOptions* options = geofence.options;
+  jmethodID getMonitorTransitions = env->GetMethodID(
+      geofenceRequestClass,
+      "getMonitorTransitions",
+      "()I");
+  options->monitor_transitions = env->CallIntMethod(
+      geofenceRequestObject,
+      getMonitorTransitions);
+
+  jmethodID getUnknownTimer = env->GetMethodID(
+      geofenceRequestClass,
+      "getUnknownTimer",
+      "()I");
+  options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer);
+
+  jmethodID getNotificationResponsiveness = env->GetMethodID(
+      geofenceRequestClass,
+      "getNotificationResponsiveness",
+      "()I");
+  options->notification_responsivenes_ms = env->CallIntMethod(
+      geofenceRequestObject,
+      getNotificationResponsiveness);
+
+  jmethodID getLastTransition = env->GetMethodID(
+      geofenceRequestClass,
+      "getLastTransition",
+      "()I");
+  options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
+
+  // TODO: set data.sources_to_use when available
+
+  env->DeleteLocalRef(geofenceRequestClass);
+}
+
+/*
+ * Helper function to transform FlpLocation into a java object.
+ */
+static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
+  jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+  jmethodID locationCtor = sCallbackEnv->GetMethodID(
+      locationClass,
+      "<init>",
+      "(Ljava/lang/String;)V"
+      );
+
+  // the provider is set in the upper JVM layer
+  locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
+  jint flags = location->flags;
+
+  // set the valid information in the object
+  if (flags & FLP_LOCATION_HAS_LAT_LONG) {
+    jmethodID setLatitude = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setLatitude",
+        "(D)V"
+        );
+    sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
+
+    jmethodID setLongitude = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setLongitude",
+        "(D)V"
+        );
+    sCallbackEnv->CallVoidMethod(
+        locationObject,
+        setLongitude,
+        location->longitude
+        );
+
+    jmethodID setTime = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setTime",
+        "(J)V"
+        );
+    sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
+  }
+
+  if (flags & FLP_LOCATION_HAS_ALTITUDE) {
+    jmethodID setAltitude = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setAltitude",
+        "(D)V"
+        );
+    sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
+  }
+
+  if (flags & FLP_LOCATION_HAS_SPEED) {
+    jmethodID setSpeed = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setSpeed",
+        "(F)V"
+        );
+    sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
+  }
+
+  if (flags & FLP_LOCATION_HAS_BEARING) {
+    jmethodID setBearing = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setBearing",
+        "(F)V"
+        );
+    sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
+  }
+
+  if (flags & FLP_LOCATION_HAS_ACCURACY) {
+    jmethodID setAccuracy = sCallbackEnv->GetMethodID(
+        locationClass,
+        "setAccuracy",
+        "(F)V"
+        );
+    sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
+  }
+
+  // TODO: wire FlpLocation::sources_used when needed
+
+  sCallbackEnv->DeleteLocalRef(locationClass);
+}
+
+/*
+ * Helper function to serialize FlpLocation structures.
+ */
+static void TranslateToObjectArray(
+    int32_t locationsCount,
+    FlpLocation** locations,
+    jobjectArray& locationsArray) {
+  jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+  locationsArray = sCallbackEnv->NewObjectArray(
+      locationsCount,
+      locationClass,
+      /* initialElement */ NULL
+      );
+
+  for (int i = 0; i < locationsCount; ++i) {
+    jobject locationObject = NULL;
+    TranslateToObject(locations[i], locationObject);
+    sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
+    sCallbackEnv->DeleteLocalRef(locationObject);
+  }
+
+  sCallbackEnv->DeleteLocalRef(locationClass);
+}
+
+static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  if(locationsCount == 0 || locations == NULL) {
+    ALOGE(
+        "Invalid LocationCallback. Count: %d, Locations: %p",
+        locationsCount,
+        locations
+        );
+    return;
+  }
+
+  jobjectArray locationsArray = NULL;
+  TranslateToObjectArray(locationsCount, locations, locationsArray);
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnLocationReport,
+      locationsArray
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+  if(locationsArray != NULL) {
+    sCallbackEnv->DeleteLocalRef(locationsArray);
+  }
+}
+
+static void AcquireWakelock() {
+  acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+}
+
+static void ReleaseWakelock() {
+  release_wake_lock(WAKE_LOCK_NAME);
+}
+
+FlpCallbacks sFlpCallbacks = {
+  sizeof(FlpCallbacks),
+  LocationCallback,
+  AcquireWakelock,
+  ReleaseWakelock,
+  SetThreadEvent
+};
+
+static void ReportData(char* data, int length) {
+  jstring stringData = NULL;
+
+  if(length != 0 && data != NULL) {
+    stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
+  } else {
+    ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
+  sizeof(FlpDiagnosticCallbacks),
+  SetThreadEvent,
+  ReportData
+};
+
+static void GeofenceTransitionCallback(
+    int32_t geofenceId,
+    FlpLocation* location,
+    int32_t transition,
+    FlpUtcTime timestamp,
+    uint32_t sourcesUsed
+    ) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  if(location == NULL) {
+    ALOGE("GeofenceTransition received with invalid location: %p", location);
+    return;
+  }
+
+  jobject locationObject = NULL;
+  TranslateToObject(location, locationObject);
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnGeofenceTransition,
+      geofenceId,
+      locationObject,
+      transition,
+      timestamp,
+      sourcesUsed
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+  if(locationObject != NULL) {
+    sCallbackEnv->DeleteLocalRef(locationObject);
+  }
+}
+
+static void GeofenceMonitorStatusCallback(
+    int32_t status,
+    uint32_t source,
+    FlpLocation* lastLocation) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  jobject locationObject = NULL;
+  if(lastLocation != NULL) {
+    TranslateToObject(lastLocation, locationObject);
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnGeofenceMonitorStatus,
+      status,
+      source,
+      locationObject
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+  if(locationObject != NULL) {
+    sCallbackEnv->DeleteLocalRef(locationObject);
+  }
+}
+
+static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnGeofenceRemove,
+      geofenceId,
+      result
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnGeofencePause,
+      geofenceId,
+      result
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnGeofenceResume,
+      geofenceId,
+      result
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
+  sizeof(FlpGeofenceCallbacks),
+  GeofenceTransitionCallback,
+  GeofenceMonitorStatusCallback,
+  GeofenceAddCallback,
+  GeofenceRemoveCallback,
+  GeofencePauseCallback,
+  GeofenceResumeCallback,
+  SetThreadEvent
+};
+
+/*
+ * Initializes the Fused Location Provider in the native side. It ensures that
+ * the Flp interfaces are initialized properly.
+ */
+static void Init(JNIEnv* env, jobject obj) {
+  if(sHardwareDevice != NULL) {
+    ALOGD("Hardware Device already opened.");
+    return;
+  }
+
+  const hw_module_t* module = NULL;
+  int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
+  if(err != 0) {
+    ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+    return;
+  }
+
+  err = module->methods->open(
+        module,
+        FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
+  if(err != 0) {
+    ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+    return;
+  }
+
+  sFlpInterface = NULL;
+  flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
+  sFlpInterface = flp_device->get_flp_interface(flp_device);
+
+  if(sFlpInterface != NULL) {
+    sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
+        sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
+        );
+
+    sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
+        sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
+        );
+
+    sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
+        sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
+        );
+  }
+
+  if(sCallbacksObj == NULL) {
+    sCallbacksObj = env->NewGlobalRef(obj);
+  }
+
+  // initialize the Flp interfaces
+  if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  if(sFlpDiagnosticInterface != NULL) {
+    sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
+  }
+
+  if(sFlpGeofencingInterface != NULL) {
+    sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
+  }
+
+  // TODO: inject any device context if when needed
+}
+
+static jboolean IsSupported(JNIEnv* env, jclass clazz) {
+  return sFlpInterface != NULL;
+}
+
+static jint GetBatchSize(JNIEnv* env, jobject object) {
+  if(sFlpInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  return sFlpInterface->get_batch_size();
+}
+
+static void StartBatching(
+    JNIEnv* env,
+    jobject object,
+    jint id,
+    jobject optionsObject) {
+  if(sFlpInterface == NULL || optionsObject == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  FlpBatchOptions options;
+  TranslateFromObject(env, optionsObject, options);
+  int result = sFlpInterface->start_batching(id, &options);
+  ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void UpdateBatchingOptions(
+    JNIEnv* env,
+    jobject object,
+    jint id,
+    jobject optionsObject) {
+  if(sFlpInterface == NULL || optionsObject == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  FlpBatchOptions options;
+  TranslateFromObject(env, optionsObject, options);
+  int result = sFlpInterface->update_batching_options(id, &options);
+  ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void StopBatching(JNIEnv* env, jobject object, jint id) {
+  if(sFlpInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpInterface->stop_batching(id);
+}
+
+static void Cleanup(JNIEnv* env, jobject object) {
+  if(sFlpInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpInterface->cleanup();
+
+  if(sCallbacksObj != NULL) {
+    env->DeleteGlobalRef(sCallbacksObj);
+    sCallbacksObj = NULL;
+  }
+
+  sFlpInterface = NULL;
+  sFlpDiagnosticInterface = NULL;
+  sFlpDeviceContextInterface = NULL;
+  sFlpGeofencingInterface = NULL;
+
+  if(sHardwareDevice != NULL) {
+    sHardwareDevice->close(sHardwareDevice);
+    sHardwareDevice = NULL;
+  }
+}
+
+static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
+  if(sFlpInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpInterface->get_batched_location(lastNLocations);
+}
+
+static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
+  if(locationObject == NULL) {
+    ALOGE("Invalid location for injection: %p", locationObject);
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  if(sFlpInterface == NULL) {
+    // there is no listener, bail
+    return;
+  }
+
+  FlpLocation location;
+  TranslateFromObject(env, locationObject, location);
+  int result = sFlpInterface->inject_location(&location);
+  if (result != FLP_RESULT_SUCCESS) {
+    // do not throw but log, this operation should be fire and forget
+    ALOGE("Error %d in '%s'", result, __FUNCTION__);
+  }
+}
+
+static jboolean IsDiagnosticSupported() {
+  return sFlpDiagnosticInterface != NULL;
+}
+
+static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
+  if(stringData == NULL) {
+    ALOGE("Invalid diagnostic data for injection: %p", stringData);
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  if(sFlpDiagnosticInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  int length = env->GetStringLength(stringData);
+  const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
+  if(data == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
+  ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsDeviceContextSupported() {
+  return sFlpDeviceContextInterface != NULL;
+}
+
+static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
+  if(sFlpDeviceContextInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
+  ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsGeofencingSupported() {
+  return sFlpGeofencingInterface != NULL;
+}
+
+static void AddGeofences(
+    JNIEnv* env,
+    jobject object,
+    jobjectArray geofenceRequestsArray) {
+  if(geofenceRequestsArray == NULL) {
+    ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray);
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  if (sFlpGeofencingInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray);
+  if(geofenceRequestsCount == 0) {
+    return;
+  }
+
+  Geofence* geofences = new Geofence[geofenceRequestsCount];
+  if (geofences == NULL) {
+    ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
+  }
+
+  for (int i = 0; i < geofenceRequestsCount; ++i) {
+    geofences[i].data = new GeofenceData();
+    geofences[i].options = new GeofenceOptions();
+    jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i);
+
+    TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]);
+    env->DeleteLocalRef(geofenceObject);
+  }
+
+  sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences);
+  if (geofences != NULL) {
+    for(int i = 0; i < geofenceRequestsCount; ++i) {
+      delete geofences[i].data;
+      delete geofences[i].options;
+    }
+    delete[] geofences;
+  }
+}
+
+static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
+  if(sFlpGeofencingInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpGeofencingInterface->pause_geofence(geofenceId);
+}
+
+static void ResumeGeofence(
+    JNIEnv* env,
+    jobject object,
+    jint geofenceId,
+    jint monitorTransitions) {
+  if(sFlpGeofencingInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
+}
+
+static void ModifyGeofenceOption(
+    JNIEnv* env,
+    jobject object,
+    jint geofenceId,
+    jint lastTransition,
+    jint monitorTransitions,
+    jint notificationResponsiveness,
+    jint unknownTimer,
+    jint sourcesToUse) {
+  if(sFlpGeofencingInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  GeofenceOptions options = {
+      lastTransition,
+      monitorTransitions,
+      notificationResponsiveness,
+      unknownTimer,
+      (uint32_t)sourcesToUse
+  };
+
+  sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
+}
+
+static void RemoveGeofences(
+    JNIEnv* env,
+    jobject object,
+    jintArray geofenceIdsArray) {
+  if(sFlpGeofencingInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
+  jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
+  if(geofenceIds == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
+  env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
+}
+
+static JNINativeMethod sMethods[] = {
+  //{"name", "signature", functionPointer }
+  {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
+  {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
+  {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
+  {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
+  {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
+  {"nativeStartBatching",
+        "(ILandroid/location/FusedBatchOptions;)V",
+        reinterpret_cast<void*>(StartBatching)},
+  {"nativeUpdateBatchingOptions",
+        "(ILandroid/location/FusedBatchOptions;)V",
+        reinterpret_cast<void*>(UpdateBatchingOptions)},
+  {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
+  {"nativeRequestBatchedLocation",
+        "(I)V",
+        reinterpret_cast<void*>(GetBatchedLocation)},
+  {"nativeInjectLocation",
+        "(Landroid/location/Location;)V",
+        reinterpret_cast<void*>(InjectLocation)},
+  {"nativeIsDiagnosticSupported",
+        "()Z",
+        reinterpret_cast<void*>(IsDiagnosticSupported)},
+  {"nativeInjectDiagnosticData",
+        "(Ljava/lang/String;)V",
+        reinterpret_cast<void*>(InjectDiagnosticData)},
+  {"nativeIsDeviceContextSupported",
+        "()Z",
+        reinterpret_cast<void*>(IsDeviceContextSupported)},
+  {"nativeInjectDeviceContext",
+        "(I)V",
+        reinterpret_cast<void*>(InjectDeviceContext)},
+  {"nativeIsGeofencingSupported",
+        "()Z",
+        reinterpret_cast<void*>(IsGeofencingSupported)},
+  {"nativeAddGeofences",
+        "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V",
+        reinterpret_cast<void*>(AddGeofences)},
+  {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
+  {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
+  {"nativeModifyGeofenceOption",
+        "(IIIIII)V",
+        reinterpret_cast<void*>(ModifyGeofenceOption)},
+  {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
+};
+
+/*
+ * Registration method invoked on JNI Load.
+ */
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
+  return jniRegisterNativeMethods(
+      env,
+      "com/android/server/location/FlpHardwareProvider",
+      sMethods,
+      NELEM(sMethods)
+      );
+}
+
+} /* name-space Android */
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 98de12a..aec254b 100644
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -26,6 +26,7 @@
 #include "utils/Log.h"
 #include "utils/misc.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
 
 #include <string.h>
 #include <pthread.h>
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/jni/com_android_server_power_PowerManagerService.cpp
index 23c33af..151e134 100644
--- a/services/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/jni/com_android_server_power_PowerManagerService.cpp
@@ -26,13 +26,13 @@
 #include <limits.h>
 
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
 #include <utils/Timers.h>
 #include <utils/misc.h>
 #include <utils/String8.h>
 #include <utils/Log.h>
 #include <hardware/power.h>
 #include <hardware_legacy/power.h>
-#include <cutils/android_reboot.h>
 #include <suspend/autosuspend.h>
 
 #include "com_android_server_power_PowerManagerService.h"
@@ -189,22 +189,6 @@
     }
 }
 
-static void nativeShutdown(JNIEnv *env, jclass clazz) {
-    android_reboot(ANDROID_RB_POWEROFF, 0, 0);
-}
-
-static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {
-    if (reason == NULL) {
-        android_reboot(ANDROID_RB_RESTART, 0, 0);
-    } else {
-        const char *chars = env->GetStringUTFChars(reason, NULL);
-        android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);
-        env->ReleaseStringUTFChars(reason, chars);  // In case it fails.
-    }
-    jniThrowIOException(env, errno);
-}
-
-
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gPowerManagerServiceMethods[] = {
@@ -221,10 +205,6 @@
             (void*) nativeSetInteractive },
     { "nativeSetAutoSuspend", "(Z)V",
             (void*) nativeSetAutoSuspend },
-    { "nativeShutdown", "()V",
-            (void*) nativeShutdown },
-    { "nativeReboot", "(Ljava/lang/String;)V",
-            (void*) nativeReboot },
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 423ebd1..efc34a2 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -21,7 +21,7 @@
 
 namespace android {
 int register_android_server_AlarmManagerService(JNIEnv* env);
-int register_android_server_BatteryService(JNIEnv* env);
+int register_android_server_ConsumerIrService(JNIEnv *env);
 int register_android_server_InputApplicationHandle(JNIEnv* env);
 int register_android_server_InputWindowHandle(JNIEnv* env);
 int register_android_server_InputManager(JNIEnv* env);
@@ -33,7 +33,9 @@
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
+int register_android_server_AssetAtlasService(JNIEnv* env);
 };
 
 using namespace android;
@@ -56,13 +58,16 @@
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
-    register_android_server_BatteryService(env);
     register_android_server_UsbDeviceManager(env);
     register_android_server_UsbHostManager(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
     register_android_server_location_GpsLocationProvider(env);
+    register_android_server_location_FlpHardwareProvider(env);
     register_android_server_connectivity_Vpn(env);
+    register_android_server_AssetAtlasService(env);
+    register_android_server_ConsumerIrService(env);
+
 
     return JNI_VERSION_1_4;
 }
diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
index 17a1585..192c50c 100644
--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
@@ -66,7 +66,7 @@
 
     public void testAddRemoveListener() throws RemoteException {
         CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext());
-        serviceTester.systemReady();
+        serviceTester.systemRunning();
         waitForSystemReady(serviceTester);
         CountryListenerTester listenerTester = new CountryListenerTester();
         serviceTester.addCountryListener(listenerTester);
@@ -80,7 +80,7 @@
         CountryListenerTester listenerTesterA = new CountryListenerTester();
         CountryListenerTester listenerTesterB = new CountryListenerTester();
         Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK);
-        serviceTester.systemReady();
+        serviceTester.systemRunning();
         waitForSystemReady(serviceTester);
         serviceTester.addCountryListener(listenerTesterA);
         serviceTester.addCountryListener(listenerTesterB);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
new file mode 100644
index 0000000..56dd7c4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.net.LocalSocket;
+import android.net.LocalServerSocket;
+import android.os.Binder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import com.android.server.net.BaseNetworkObserver;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Tests for {@link NetworkManagementService}.
+ */
+@LargeTest
+public class NetworkManagementServiceTest extends AndroidTestCase {
+
+    private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest";
+    private NetworkManagementService mNMService;
+    private LocalServerSocket mServerSocket;
+    private LocalSocket mSocket;
+    private OutputStream mOutputStream;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        // TODO: make this unnecessary. runtest might already make it unnecessary.
+        System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+
+        // Set up a sheltered test environment.
+        BroadcastInterceptingContext context = new BroadcastInterceptingContext(getContext());
+        mServerSocket = new LocalServerSocket(SOCKET_NAME);
+
+        // Start the service and wait until it connects to our socket.
+        mNMService = NetworkManagementService.create(context, SOCKET_NAME);
+        mSocket = mServerSocket.accept();
+        mOutputStream = mSocket.getOutputStream();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (mSocket != null) mSocket.close();
+        if (mServerSocket != null) mServerSocket.close();
+        super.tearDown();
+    }
+
+    /**
+     * Sends a message on the netd socket and gives the events some time to make it back.
+     */
+    private void sendMessage(String message) throws IOException {
+        // Strings are null-terminated, so add "\0" at the end.
+        mOutputStream.write((message + "\0").getBytes());
+    }
+
+    private static <T> T expectSoon(T mock) {
+        return verify(mock, timeout(100));
+    }
+
+    /**
+     * Tests that network observers work properly.
+     */
+    public void testNetworkObservers() throws Exception {
+        BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
+        doReturn(new Binder()).when(observer).asBinder();  // Used by registerObserver.
+        mNMService.registerObserver(observer);
+
+        // Forget everything that happened to the mock so far, so we can explicitly verify
+        // everything that happens and does not happen to it from now on.
+        reset(observer);
+
+        // Now send NetworkManagementService messages and ensure that the observer methods are
+        // called. After every valid message we expect a callback soon after; to ensure that
+        // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
+
+        /**
+         * Interface changes.
+         */
+        sendMessage("600 Iface added rmnet12");
+        expectSoon(observer).interfaceAdded("rmnet12");
+
+        sendMessage("600 Iface removed eth1");
+        expectSoon(observer).interfaceRemoved("eth1");
+
+        sendMessage("607 Iface removed eth1");
+        // Invalid code.
+
+        sendMessage("600 Iface borked lo down");
+        // Invalid event.
+
+        sendMessage("600 Iface changed clat4 up again");
+        // Extra tokens.
+
+        sendMessage("600 Iface changed clat4 up");
+        expectSoon(observer).interfaceStatusChanged("clat4", true);
+
+        sendMessage("600 Iface linkstate rmnet0 down");
+        expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
+
+        sendMessage("600 IFACE linkstate clat4 up");
+        // Invalid group.
+
+        /**
+         * Bandwidth control events.
+         */
+        sendMessage("601 limit alert data rmnet_usb0");
+        expectSoon(observer).limitReached("data", "rmnet_usb0");
+
+        sendMessage("601 invalid alert data rmnet0");
+        // Invalid group.
+
+        sendMessage("601 limit increased data rmnet0");
+        // Invalid event.
+
+
+        /**
+         * Interface class activity.
+         */
+        sendMessage("613 IfaceClass active rmnet0");
+        expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true);
+
+        sendMessage("613 IfaceClass idle eth0");
+        expectSoon(observer).interfaceClassDataActivityChanged("eth0", false);
+
+        sendMessage("613 IfaceClass reallyactive rmnet0");
+        expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false);
+
+        sendMessage("613 InterfaceClass reallyactive rmnet0");
+        // Invalid group.
+
+
+        /**
+         * IP address changes.
+         */
+        sendMessage("614 Address updated fe80::1/64 wlan0 128 253");
+        expectSoon(observer).addressUpdated("fe80::1/64", "wlan0", 128, 253);
+
+        // There is no "added".
+        sendMessage("614 Address added fe80::1/64 wlan0 128 253");
+        expectSoon(observer).addressRemoved("fe80::1/64", "wlan0", 128, 253);
+
+        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0");
+        expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0);
+
+        sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0");
+        // Invalid code.
+
+        // Make sure nothing else was called.
+        verifyNoMoreInteractions(observer);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index cdc4d78..a1af8cb 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -40,7 +40,6 @@
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
 import static org.easymock.EasyMock.anyLong;
-import static org.easymock.EasyMock.aryEq;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.eq;
@@ -63,6 +62,7 @@
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
 import android.os.INetworkManagementService;
+import android.os.WorkSource;
 import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -73,13 +73,13 @@
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
 
+import libcore.io.IoUtils;
+
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 
 import java.io.File;
 
-import libcore.io.IoUtils;
-
 /**
  * Tests for {@link NetworkStatsService}.
  */
@@ -878,8 +878,8 @@
         mAlarmManager.remove(isA(PendingIntent.class));
         expectLastCall().anyTimes();
 
-        mAlarmManager.setInexactRepeating(
-                eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class));
+        mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
+                isA(PendingIntent.class), isA(WorkSource.class));
         expectLastCall().atLeastOnce();
 
         mNetManager.setGlobalAlert(anyLong());
@@ -918,8 +918,7 @@
         expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
 
         // also include tethering details, since they are folded into UID
-        expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).atLeastOnce();
-        expect(mNetManager.getNetworkStatsTethering(aryEq(tetherIfacePairs)))
+        expect(mNetManager.getNetworkStatsTethering())
                 .andReturn(tetherStats).atLeastOnce();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index f2772c8..37176d6 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.content;
 
 import android.accounts.Account;
+import android.content.ContentResolver;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -48,7 +49,8 @@
                 SyncOperation.REASON_PERIODIC,
                 "authority1",
                 b1,
-                100,
+                100, /* run time from now*/
+                10, /* flex */
                 1000,
                 10000,
                 false);
@@ -60,6 +62,7 @@
                 "authority1",
                 b1,
                 200,
+                20,
                 2000,
                 20000,
                 false);
@@ -71,6 +74,7 @@
                 "authority2",
                 b1,
                 100,
+                10,
                 1000,
                 10000,
                 false);
@@ -82,6 +86,7 @@
                 "authority1",
                 b1,
                 100,
+                10,
                 1000,
                 10000,
                 false);
@@ -93,6 +98,7 @@
                 "authority1",
                 b2,
                 100,
+                10,
                 1000,
                 10000,
                 false);
@@ -102,4 +108,38 @@
         assertNotSame(op1.key, op4.key);
         assertNotSame(op1.key, op5.key);
     }
+
+    @SmallTest
+    public void testCompareTo() {
+        Account dummy = new Account("account1", "type1");
+        Bundle b1 = new Bundle();
+        final long unimportant = 0L;
+        long soon = 1000;
+        long soonFlex = 50;
+        long after = 1500;
+        long afterFlex = 100;
+        SyncOperation op1 = new SyncOperation(dummy, 0, 0, SyncOperation.REASON_PERIODIC,
+                "authority1", b1, soon, soonFlex, unimportant, unimportant, true);
+
+        // Interval disjoint from and after op1.
+        SyncOperation op2 = new SyncOperation(dummy, 0, 0, SyncOperation.REASON_PERIODIC,
+                "authority1", b1, after, afterFlex, unimportant, unimportant, true);
+
+        // Interval equivalent to op1, but expedited.
+        Bundle b2 = new Bundle();
+        b2.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+        SyncOperation op3 = new SyncOperation(dummy, 0, 0, 0,
+                "authority1", b2, soon, soonFlex, unimportant, unimportant, true);
+
+        // Interval overlaps but not equivalent to op1.
+        SyncOperation op4 = new SyncOperation(dummy, 0, 0, SyncOperation.REASON_PERIODIC,
+                "authority1", b1, soon + 100, soonFlex + 100, unimportant, unimportant, true);
+
+        assertTrue(op1.compareTo(op2) == -1);
+        assertTrue("less than not transitive.", op2.compareTo(op1) == 1);
+        assertTrue(op1.compareTo(op3) == 1);
+        assertTrue("greater than not transitive. ", op3.compareTo(op1) == -1);
+        assertTrue("overlapping intervals not the same.", op1.compareTo(op4) == 0);
+        assertTrue("equality not transitive.", op4.compareTo(op1) == 0);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index 8b00f2c2..e44652f 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -22,6 +22,7 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.PeriodicSync;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
 import android.test.RenamingDelegatingContext;
@@ -39,13 +40,34 @@
 
 public class SyncStorageEngineTest extends AndroidTestCase {
 
+    protected Account account1;
+    protected String authority1 = "testprovider";
+    protected Bundle defaultBundle;
+    protected final int DEFAULT_USER = 0;
+    
+    MockContentResolver mockResolver;
+    SyncStorageEngine engine;
+    
     private File getSyncDir() {
         return new File(new File(getContext().getFilesDir(), "system"), "sync");
     }
 
+    @Override
+    public void setUp() {
+        account1 = new Account("a@example.com", "example.type");
+        // Default bundle.
+        defaultBundle = new Bundle();
+        defaultBundle.putInt("int_key", 0);
+        defaultBundle.putString("string_key", "hello");
+        // Set up storage engine.
+        mockResolver = new MockContentResolver();
+        engine = SyncStorageEngine.newTestInstance(
+                new TestContext(mockResolver, getContext()));
+    }
+
     /**
      * Test that we handle the case of a history row being old enough to purge before the
-     * correcponding sync is finished. This can happen if the clock changes while we are syncing.
+     * corresponding sync is finished. This can happen if the clock changes while we are syncing.
      *
      */
     // TODO: this test causes AidlTest to fail. Omit for now
@@ -68,7 +90,36 @@
     }
 
     /**
-     * Test that we can create, remove and retrieve periodic syncs
+     * Test persistence of pending operations.
+     */
+    @MediumTest
+    public void testPending() throws Exception {
+        SyncStorageEngine.PendingOperation pop =
+                new SyncStorageEngine.PendingOperation(account1, DEFAULT_USER,
+                        SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL,
+                        authority1, defaultBundle, false);
+        
+        engine.insertIntoPending(pop);
+        // Force engine to read from disk.
+        engine.clearAndReadState();
+
+        assert(engine.getPendingOperationCount() == 1);
+        List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations();
+        SyncStorageEngine.PendingOperation popRetrieved = pops.get(0);
+        assertEquals(pop.account, popRetrieved.account);
+        assertEquals(pop.reason, popRetrieved.reason);
+        assertEquals(pop.userId, popRetrieved.userId);
+        assertEquals(pop.syncSource, popRetrieved.syncSource);
+        assertEquals(pop.authority, popRetrieved.authority);
+        assertEquals(pop.expedited, popRetrieved.expedited);
+        assertEquals(pop.serviceName, popRetrieved.serviceName);
+        assert(android.content.PeriodicSync.syncExtrasEquals(pop.extras, popRetrieved.extras));
+
+    }
+
+    /**
+     * Test that we can create, remove and retrieve periodic syncs. Backwards compatibility -
+     * periodic syncs with no flex time are no longer used.
      */
     @MediumTest
     public void testPeriodics() throws Exception {
@@ -87,22 +138,19 @@
         PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2);
         PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2);
 
-        MockContentResolver mockResolver = new MockContentResolver();
-
-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
-                new TestContext(mockResolver, getContext()));
+        
 
         removePeriodicSyncs(engine, account1, 0, authority);
         removePeriodicSyncs(engine, account2, 0, authority);
         removePeriodicSyncs(engine, account1, 1, authority);
 
         // this should add two distinct periodic syncs for account1 and one for account2
-        engine.addPeriodicSync(sync1.account, 0, sync1.authority, sync1.extras, sync1.period);
-        engine.addPeriodicSync(sync2.account, 0, sync2.authority, sync2.extras, sync2.period);
-        engine.addPeriodicSync(sync3.account, 0, sync3.authority, sync3.extras, sync3.period);
-        engine.addPeriodicSync(sync4.account, 0, sync4.authority, sync4.extras, sync4.period);
+        engine.addPeriodicSync(sync1, 0);
+        engine.addPeriodicSync(sync2, 0);
+        engine.addPeriodicSync(sync3, 0);
+        engine.addPeriodicSync(sync4, 0);
         // add a second user
-        engine.addPeriodicSync(sync2.account, 1, sync2.authority, sync2.extras, sync2.period);
+        engine.addPeriodicSync(sync2, 1);
 
         List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
 
@@ -111,7 +159,7 @@
         assertEquals(sync1, syncs.get(0));
         assertEquals(sync3, syncs.get(1));
 
-        engine.removePeriodicSync(sync1.account, 0, sync1.authority, sync1.extras);
+        engine.removePeriodicSync(sync1, 0);
 
         syncs = engine.getPeriodicSyncs(account1, 0, authority);
         assertEquals(1, syncs.size());
@@ -126,13 +174,72 @@
         assertEquals(sync2, syncs.get(0));
     }
 
-    private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId,
-            String authority) {
-        engine.setIsSyncable(account, userId, authority,
-                engine.getIsSyncable(account, 0, authority));
+    /**
+     * Test that we can create, remove and retrieve periodic syncs with a provided flex time.
+     */
+    @MediumTest
+    public void testPeriodicsV2() throws Exception {
+        final Account account1 = new Account("a@example.com", "example.type");
+        final Account account2 = new Account("b@example.com", "example.type.2");
+        final String authority = "testprovider";
+        final Bundle extras1 = new Bundle();
+        extras1.putString("a", "1");
+        final Bundle extras2 = new Bundle();
+        extras2.putString("a", "2");
+        final int period1 = 200;
+        final int period2 = 1000;
+        final int flex1 = 10;
+        final int flex2 = 100;
+
+        PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1, flex1);
+        PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1, flex1);
+        PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2, flex2);
+        PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2, flex2);
+
+        MockContentResolver mockResolver = new MockContentResolver();
+
+        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
+                new TestContext(mockResolver, getContext()));
+
+        removePeriodicSyncs(engine, account1, 0, authority);
+        removePeriodicSyncs(engine, account2, 0, authority);
+        removePeriodicSyncs(engine, account1, 1, authority);
+
+        // This should add two distinct periodic syncs for account1 and one for account2
+        engine.addPeriodicSync(sync1, 0);
+        engine.addPeriodicSync(sync2, 0);
+        engine.addPeriodicSync(sync3, 0); // Should edit sync2 and update the period.
+        engine.addPeriodicSync(sync4, 0);
+        // add a second user
+        engine.addPeriodicSync(sync2, 1);
+
+        List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
+
+        assertEquals(2, syncs.size());
+
+        assertEquals(sync1, syncs.get(0));
+        assertEquals(sync3, syncs.get(1));
+
+        engine.removePeriodicSync(sync1, 0);
+
+        syncs = engine.getPeriodicSyncs(account1, 0, authority);
+        assertEquals(1, syncs.size());
+        assertEquals(sync3, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(account2, 0, authority);
+        assertEquals(1, syncs.size());
+        assertEquals(sync4, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(sync2.account, 1, sync2.authority);
+        assertEquals(1, syncs.size());
+        assertEquals(sync2, syncs.get(0));
+    }
+
+    private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId, String authority) {
+        engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, 0, authority));
         List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, userId, authority);
         for (PeriodicSync sync : syncs) {
-            engine.removePeriodicSync(sync.account, userId, sync.authority, sync.extras);
+            engine.removePeriodicSync(sync, userId);
         }
     }
 
@@ -154,12 +261,14 @@
         extras2.putParcelable("g", account1);
         final int period1 = 200;
         final int period2 = 1000;
+        final int flex1 = 10;
+        final int flex2 = 100;
 
-        PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1);
-        PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1);
-        PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1);
-        PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2);
-        PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1);
+        PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1, flex1);
+        PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1, flex1);
+        PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1, flex1);
+        PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2, flex2);
+        PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1, flex1);
 
         MockContentResolver mockResolver = new MockContentResolver();
 
@@ -185,11 +294,11 @@
         engine.setIsSyncable(account2, 0, authority2, 0);
         engine.setSyncAutomatically(account2, 0, authority2, true);
 
-        engine.addPeriodicSync(sync1.account, 0, sync1.authority, sync1.extras, sync1.period);
-        engine.addPeriodicSync(sync2.account, 0, sync2.authority, sync2.extras, sync2.period);
-        engine.addPeriodicSync(sync3.account, 0, sync3.authority, sync3.extras, sync3.period);
-        engine.addPeriodicSync(sync4.account, 0, sync4.authority, sync4.extras, sync4.period);
-        engine.addPeriodicSync(sync5.account, 0, sync5.authority, sync5.extras, sync5.period);
+        engine.addPeriodicSync(sync1, 0);
+        engine.addPeriodicSync(sync2, 0);
+        engine.addPeriodicSync(sync3, 0);
+        engine.addPeriodicSync(sync4, 0);
+        engine.addPeriodicSync(sync5, 0);
 
         engine.writeAllState();
         engine.clearAndReadState();
@@ -220,6 +329,131 @@
     }
 
     @MediumTest
+    /**
+     * V2 introduces flex time as well as service components.
+     * @throws Exception
+     */
+    public void testAuthorityParsingV2() throws Exception {
+        final Account account = new Account("account1", "type1");
+        final String authority1 = "auth1";
+        final String authority2 = "auth2";
+        final String authority3 = "auth3";
+
+        final long dayPoll = (60 * 60 * 24);
+        final long dayFuzz = 60;
+        final long thousandSecs = 1000;
+        final long thousandSecsFuzz = 100;
+        final Bundle extras = new Bundle();
+        PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, dayPoll, dayFuzz);
+        PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, dayPoll, dayFuzz);
+        PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, dayPoll, dayFuzz);
+        PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, thousandSecs, thousandSecsFuzz);
+        PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, thousandSecs, thousandSecsFuzz);
+        PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, thousandSecs, thousandSecsFuzz);
+        MockContentResolver mockResolver = new MockContentResolver();
+
+        final TestContext testContext = new TestContext(mockResolver, getContext());
+
+        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<accounts version=\"2\" >\n"
+                + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" >"
+                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+                + "\n</authority>"
+                + "<authority id=\"1\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth2\" >"
+                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+                + "\n</authority>"
+                // No user defaults to user 0 - all users.
+                + "<authority id=\"2\"            account=\"account1\" type=\"type1\" authority=\"auth3\" >"
+                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+                + "\n</authority>"
+                + "<authority id=\"3\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth3\" >"
+                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+                + "\n</authority>"
+                + "</accounts>").getBytes();
+
+        File syncDir = getSyncDir();
+        syncDir.mkdirs();
+        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+        FileOutputStream fos = accountInfoFile.startWrite();
+        fos.write(accountsFileData);
+        accountInfoFile.finishWrite(fos);
+
+        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
+
+        List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
+        assertEquals("Got incorrect # of syncs", 1, syncs.size());
+        assertEquals(sync1, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority2);
+        assertEquals(1, syncs.size());
+        assertEquals(sync2, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority3);
+        assertEquals(1, syncs.size());
+        assertEquals(sync3, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(account, 1, authority3);
+        assertEquals(1, syncs.size());
+        assertEquals(sync3, syncs.get(0));
+
+        // Test empty periodic data.
+        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<accounts version=\"2\">\n"
+                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
+                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
+                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
+                + "</accounts>\n").getBytes();
+
+        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+        fos = accountInfoFile.startWrite();
+        fos.write(accountsFileData);
+        accountInfoFile.finishWrite(fos);
+
+        engine.clearAndReadState();
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority1);
+        assertEquals(0, syncs.size());
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority2);
+        assertEquals(0, syncs.size());
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority3);
+        assertEquals(0, syncs.size());
+
+        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<accounts version=\"2\">\n"
+                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n"
+                + "<periodicSync period=\"1000\" />\n"
+                + "</authority>"
+                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n"
+                + "<periodicSync period=\"1000\" />\n"
+                + "</authority>"
+                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n"
+                + "<periodicSync period=\"1000\" />\n"
+                + "</authority>"
+                + "</accounts>\n").getBytes();
+
+        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+        fos = accountInfoFile.startWrite();
+        fos.write(accountsFileData);
+        accountInfoFile.finishWrite(fos);
+
+        engine.clearAndReadState();
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority1);
+        assertEquals(1, syncs.size());
+        assertEquals(sync1s, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority2);
+        assertEquals(1, syncs.size());
+        assertEquals(sync2s, syncs.get(0));
+
+        syncs = engine.getPeriodicSyncs(account, 0, authority3);
+        assertEquals(1, syncs.size());
+        assertEquals(sync3s, syncs.get(0));
+    }
+
+    @MediumTest
     public void testAuthorityParsing() throws Exception {
         final Account account = new Account("account1", "type1");
         final String authority1 = "auth1";
@@ -256,7 +490,7 @@
 
         List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
         assertEquals(1, syncs.size());
-        assertEquals(sync1, syncs.get(0));
+        assertEquals("expected sync1: " + sync1.toString() + " == sync 2" + syncs.get(0).toString(), sync1, syncs.get(0));
 
         syncs = engine.getPeriodicSyncs(account, 0, authority2);
         assertEquals(1, syncs.size());
@@ -451,6 +685,11 @@
     }
 
     @Override
+    public Resources getResources() {
+        return mRealContext.getResources();
+    }
+
+    @Override
     public File getFilesDir() {
         return mRealContext.getFilesDir();
     }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 3ae2106..ab429fd 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1805,7 +1805,7 @@
         String countryIso;
         CountryDetector detector = (CountryDetector) context.getSystemService(
                 Context.COUNTRY_DETECTOR);
-        if (detector != null) {
+        if (detector != null && detector.detectCountry() != null) {
             countryIso = detector.detectCountry().getCountryIso();
         } else {
             Locale locale = context.getResources().getConfiguration().locale;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4185aea..7d8b64f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -309,7 +309,7 @@
      */
     public List<NeighboringCellInfo> getNeighboringCellInfo() {
         try {
-            return getITelephony().getNeighboringCellInfo(mContext.getBasePackageName());
+            return getITelephony().getNeighboringCellInfo(mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -412,12 +412,12 @@
         case RILConstants.NETWORK_MODE_GSM_UMTS:
         case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
         case RILConstants.NETWORK_MODE_LTE_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_GSM;
 
         // Use CDMA Phone for the global mode including CDMA
         case RILConstants.NETWORK_MODE_GLOBAL:
         case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
-        case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_CDMA;
 
         case RILConstants.NETWORK_MODE_LTE_ONLY:
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 228a630..6978551 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -49,10 +49,6 @@
     private static final String TAG = "CallerInfo";
     private static final boolean VDBG = Rlog.isLoggable(TAG, Log.VERBOSE);
 
-    public static final String UNKNOWN_NUMBER = "-1";
-    public static final String PRIVATE_NUMBER = "-2";
-    public static final String PAYPHONE_NUMBER = "-3";
-
     /**
      * Please note that, any one of these member variables can be null,
      * and any accesses to them should be prepared to handle such a case.
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 4d8342c..4be11b8 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -94,6 +94,9 @@
     public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
     public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
     public static final int CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA = BASE + 36;
+    public static final int CMD_ENABLE_MOBILE_PROVISIONING = BASE + 37;
+    public static final int CMD_IS_PROVISIONING_APN = BASE + 38;
+    public static final int EVENT_PROVISIONING_APN_ALARM = BASE + 39;
 
     /***** Constants *****/
 
@@ -106,10 +109,12 @@
     public static final int APN_IMS_ID = 5;
     public static final int APN_FOTA_ID = 6;
     public static final int APN_CBS_ID = 7;
-    public static final int APN_NUM_TYPES = 8;
+    public static final int APN_IA_ID = 8;
+    public static final int APN_NUM_TYPES = 9;
 
     public static final int DISABLED = 0;
     public static final int ENABLED = 1;
 
     public static final String APN_TYPE_KEY = "apnType";
+    public static final String PROVISIONING_URL_KEY = "provisioningUrl";
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 16ea625..4a4a62b 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -119,5 +119,7 @@
     public static final String APN_TYPE_IMS = "ims";
     /** APN type for CBS */
     public static final String APN_TYPE_CBS = "cbs";
+    /** APN type for IA Initial Attach APN */
+    public static final String APN_TYPE_IA = "ia";
 
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 9650b99..923fef2 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -262,6 +262,7 @@
     int RIL_REQUEST_VOICE_RADIO_TECH = 108;
     int RIL_REQUEST_GET_CELL_INFO_LIST = 109;
     int RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE = 110;
+    int RIL_REQUEST_SET_INITIAL_ATTACH_APN = 111;
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 3cfd0bf..a7baf1c 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -145,6 +145,29 @@
     public static final String ACTION_ANY_DATA_CONNECTION_STATE_CHANGED
             = "android.intent.action.ANY_DATA_STATE";
 
+    /**
+     * Broadcast Action: Occurs when a data connection connects to a provisioning apn
+     * and is broadcast by the low level data connection code.
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>apn</em> - A string that is the APN associated with this
+     *      connection.</li>
+     *   <li><em>apnType</em> - A string array of APN types associated with
+     *      this connection.  The APN type <code>"*"</code> is a special
+     *      type that means this APN services all types.</li>
+     *   <li><em>linkProperties</em> - The <code>LinkProperties</code> for this APN</li>
+     *   <li><em>linkCapabilities</em> - The <code>linkCapabilities</code> for this APN</li>
+     *   <li><em>iface</em> - A string that is the name of the interface</li>
+     * </ul>
+     *
+     * <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.
+     */
+    public static final String ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN
+            = "android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN";
 
     /**
      * Broadcast Action: An attempt to establish a data connection has failed.
@@ -237,6 +260,23 @@
     public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
             = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
 
+    /**
+     * Activity Action: Start this activity to invoke the carrier setup app.
+     * To filter the intent, see {@link #CATEGORY_MCCMNC_PREFIX}.
+     *
+     * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
+     * permission.</p>
+     */
+    public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
+
+    /**
+     * A <em>prefix</em> for the MCC/MNC filtering used with {@link #ACTION_CARRIER_SETUP}.
+     * The MCC/MNC will be concatenated (zero-padded to 3 digits each) to create a final
+     * string of the form:
+     * <br />
+     * <code>android.intent.category.MCCMNC_310260</code>
+     */
+    public static final String CATEGORY_MCCMNC_PREFIX = "android.intent.category.MCCMNC_";
 
     /**
      * Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 373f24a..28d52b0 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -83,13 +83,15 @@
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(String callingPackage, Uri url, String mode)
+        public AssetFileDescriptor openAssetFile(
+                String callingPackage, Uri url, String mode, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openAssetFile(url, mode);
         }
 
         @Override
-        public ParcelFileDescriptor openFile(String callingPackage, Uri url, String mode)
+        public ParcelFileDescriptor openFile(
+                String callingPackage, Uri url, String mode, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openFile(url, mode);
         }
@@ -126,7 +128,7 @@
 
         @Override
         public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url,
-                String mimeType, Bundle opts)
+                String mimeType, Bundle opts, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
         }
@@ -135,6 +137,16 @@
         public ICancellationSignal createCancellationSignal() throws RemoteException {
             return null;
         }
+
+        @Override
+        public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+            return MockContentProvider.this.canonicalize(uri);
+        }
+
+        @Override
+        public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+            return MockContentProvider.this.uncanonicalize(uri);
+        }
     }
     private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 29d6e4d..0d9cd18 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -39,7 +39,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
-import android.view.CompatibilityInfoHolder;
+import android.view.DisplayAdjustments;
 import android.view.Display;
 
 import java.io.File;
@@ -112,6 +112,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public String getOpPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public ApplicationInfo getApplicationInfo() {
         throw new UnsupportedOperationException();
@@ -574,7 +580,22 @@
 
     /** @hide */
     @Override
-    public CompatibilityInfoHolder getCompatibilityInfo(int displayId) {
+    public DisplayAdjustments getDisplayAdjustments(int displayId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getExternalFilesDirs(String type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getObbDirs() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getExternalCacheDirs() {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index baa150a..5b8a4f4 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -177,17 +177,18 @@
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    @SuppressWarnings("deprecation")
     public void setNotificationUri(ContentResolver cr, Uri uri) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    @SuppressWarnings("deprecation")
+    public Uri getNotificationUri() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
     public void unregisterContentObserver(ContentObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    @SuppressWarnings("deprecation")
     public void unregisterDataSetObserver(DataSetObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index 2b4fce6..c0dc7c3 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -61,11 +61,13 @@
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    public ParcelFileDescriptor openFile(String callingPackage, Uri url, String mode) {
+    public ParcelFileDescriptor openFile(
+            String callingPackage, Uri url, String mode, ICancellationSignal signal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    public AssetFileDescriptor openAssetFile(String callingPackage, Uri uri, String mode) {
+    public AssetFileDescriptor openAssetFile(
+            String callingPackage, Uri uri, String mode, ICancellationSignal signal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -104,7 +106,7 @@
     }
 
     public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url, String mimeType,
-            Bundle opts) throws RemoteException, FileNotFoundException {
+            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -112,4 +114,14 @@
     public ICancellationSignal createCancellationSignal() throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
+
+    @Override
+    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 20a26ab..5f944f6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -45,6 +45,9 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.UserHandle;
 
 import java.util.List;
 
@@ -541,6 +544,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide - hidden in superclass */
+    @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public String[] getSystemSharedLibraryNames() {
         throw new UnsupportedOperationException();
@@ -585,6 +594,23 @@
      * @hide
      */
     @Override
+    public boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked,
+            UserHandle user) {
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean getApplicationBlockedSettingAsUser(String packageName, UserHandle user) {
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public int installExistingPackage(String packageName)
             throws NameNotFoundException {
         throw new UnsupportedOperationException();
diff --git a/tests/AccessoryDisplay/Android.mk b/tests/AccessoryDisplay/Android.mk
new file mode 100644
index 0000000..85cb309
--- /dev/null
+++ b/tests/AccessoryDisplay/Android.mk
@@ -0,0 +1,17 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AccessoryDisplay/README b/tests/AccessoryDisplay/README
new file mode 100644
index 0000000..5ce558c
--- /dev/null
+++ b/tests/AccessoryDisplay/README
@@ -0,0 +1,50 @@
+This directory contains sample code to test the use of virtual
+displays created over an Android Open Accessories Protocol link.
+
+--- DESCRIPTION ---
+
+There are two applications with two distinct roles: a sink
+and a source.
+
+1. Sink Application
+
+The role of the sink is to emulate an external display that happens
+to be connected using the USB accessory protocol.  Think of it as
+a monitor or video dock that the user will want to plug a phone into.
+
+The sink application uses the UsbDevice APIs to receive connections
+from the source device over USB.  The sink acts as a USB host
+in this arrangement and will provide power to the source.
+
+The sink application decodes encoded video from the source and
+displays it in a SurfaceView.  The sink also injects passes touch
+events to the source over USB HID.
+
+2. Source Application
+
+The role of the source is to present some content onto an external
+display that happens to be attached over USB.  This is the typical
+role that a phone or tablet might have when the user is trying to
+play content to an external monitor.
+
+The source application uses the UsbAccessory APIs to connect
+to the sink device over USB.  The source acts as a USB peripheral
+in this arrangement and will receive power from the sink.
+
+The source application uses the DisplayManager APIs to create
+a private virtual display which passes the framebuffer through
+an encoder and streams the output to the sink over USB.  Then
+the application opens a Presentation on the new virtual display
+and shows a silly cube animation.
+
+--- USAGE ---
+
+These applications should be installed on two separate Android
+devices which are then connected using a USB OTG cable.
+Remember that the sink device is functioning as the USB host
+so the USB OTG cable should be plugged directly into it.
+
+When connected, the applications should automatically launch
+on each device.  The source will then begin to project display
+contents to the sink.
+
diff --git a/tests/AccessoryDisplay/common/Android.mk b/tests/AccessoryDisplay/common/Android.mk
new file mode 100644
index 0000000..2d4de15
--- /dev/null
+++ b/tests/AccessoryDisplay/common/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the application.
+include $(CLEAR_VARS)
+LOCAL_MODULE := AccessoryDisplayCommon
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/BufferPool.java b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/BufferPool.java
new file mode 100644
index 0000000..a6bb5c1
--- /dev/null
+++ b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/BufferPool.java
@@ -0,0 +1,92 @@
+/*
+ * 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.accessorydisplay.common;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Maintains a bounded pool of buffers.  Attempts to acquire buffers beyond the maximum
+ * count will block until other buffers are released.
+ */
+final class BufferPool {
+    private final int mInitialBufferSize;
+    private final int mMaxBufferSize;
+    private final ByteBuffer[] mBuffers;
+    private int mAllocated;
+    private int mAvailable;
+
+    public BufferPool(int initialBufferSize, int maxBufferSize, int maxBuffers) {
+        mInitialBufferSize = initialBufferSize;
+        mMaxBufferSize = maxBufferSize;
+        mBuffers = new ByteBuffer[maxBuffers];
+    }
+
+    public ByteBuffer acquire(int needed) {
+        synchronized (this) {
+            for (;;) {
+                if (mAvailable != 0) {
+                    mAvailable -= 1;
+                    return grow(mBuffers[mAvailable], needed);
+                }
+
+                if (mAllocated < mBuffers.length) {
+                    mAllocated += 1;
+                    return ByteBuffer.allocate(chooseCapacity(mInitialBufferSize, needed));
+                }
+
+                try {
+                    wait();
+                } catch (InterruptedException ex) {
+                }
+            }
+        }
+    }
+
+    public void release(ByteBuffer buffer) {
+        synchronized (this) {
+            buffer.clear();
+            mBuffers[mAvailable++] = buffer;
+            notifyAll();
+        }
+    }
+
+    public ByteBuffer grow(ByteBuffer buffer, int needed) {
+        int capacity = buffer.capacity();
+        if (capacity < needed) {
+            final ByteBuffer oldBuffer = buffer;
+            capacity = chooseCapacity(capacity, needed);
+            buffer = ByteBuffer.allocate(capacity);
+            oldBuffer.flip();
+            buffer.put(oldBuffer);
+        }
+        return buffer;
+    }
+
+    private int chooseCapacity(int capacity, int needed) {
+        while (capacity < needed) {
+            capacity *= 2;
+        }
+        if (capacity > mMaxBufferSize) {
+            if (needed > mMaxBufferSize) {
+                throw new IllegalArgumentException("Requested size " + needed
+                        + " is larger than maximum buffer size " + mMaxBufferSize + ".");
+            }
+            capacity = mMaxBufferSize;
+        }
+        return capacity;
+    }
+}
diff --git a/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Logger.java b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Logger.java
new file mode 100644
index 0000000..e0b7e82
--- /dev/null
+++ b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Logger.java
@@ -0,0 +1,25 @@
+/*
+ * 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.accessorydisplay.common;
+
+public abstract class Logger {
+    public abstract void log(String message);
+
+    public void logError(String message) {
+        log("ERROR: " + message);
+    }
+}
diff --git a/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Protocol.java b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Protocol.java
new file mode 100644
index 0000000..46fee32
--- /dev/null
+++ b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Protocol.java
@@ -0,0 +1,65 @@
+/*
+ * 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.accessorydisplay.common;
+
+/**
+ * Defines message types.
+ */
+public class Protocol {
+    // Message header.
+    //   0: service id (16 bits)
+    //   2: what (16 bits)
+    //   4: content size (32 bits)
+    //   8: ... content follows ...
+    static final int HEADER_SIZE = 8;
+
+    // Maximum size of a message envelope including the header and contents.
+    static final int MAX_ENVELOPE_SIZE = 64 * 1024;
+
+    /**
+     * Maximum message content size.
+     */
+    public static final int MAX_CONTENT_SIZE = MAX_ENVELOPE_SIZE - HEADER_SIZE;
+
+    public static final class DisplaySinkService {
+        private DisplaySinkService() { }
+
+        public static final int ID = 1;
+
+        // Query sink capabilities.
+        // Replies with sink available or not available.
+        public static final int MSG_QUERY = 1;
+
+        // Send MPEG2-TS H.264 encoded content.
+        public static final int MSG_CONTENT = 2;
+    }
+
+    public static final class DisplaySourceService {
+        private DisplaySourceService() { }
+
+        public static final int ID = 2;
+
+        // Sink is now available for use.
+        //   0: width (32 bits)
+        //   4: height (32 bits)
+        //   8: density dpi (32 bits)
+        public static final int MSG_SINK_AVAILABLE = 1;
+
+        // Sink is no longer available for use.
+        public static final int MSG_SINK_NOT_AVAILABLE = 2;
+    }
+}
diff --git a/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Service.java b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Service.java
new file mode 100644
index 0000000..70b3806
--- /dev/null
+++ b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Service.java
@@ -0,0 +1,71 @@
+/*
+ * 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.accessorydisplay.common;
+
+import com.android.accessorydisplay.common.Transport;
+
+import android.content.Context;
+import android.os.Looper;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Base implementation of a service that communicates over a transport.
+ * <p>
+ * This object's interface is single-threaded.  It is only intended to be
+ * accessed from the {@link Looper} thread on which the transport was created.
+ * </p>
+ */
+public abstract class Service implements Transport.Callback {
+    private final Context mContext;
+    private final Transport mTransport;
+    private final int mServiceId;
+
+    public Service(Context context, Transport transport, int serviceId) {
+        mContext = context;
+        mTransport = transport;
+        mServiceId = serviceId;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public int getServiceId() {
+        return mServiceId;
+    }
+
+    public Transport getTransport() {
+        return mTransport;
+    }
+
+    public Logger getLogger() {
+        return mTransport.getLogger();
+    }
+
+    public void start() {
+        mTransport.registerService(mServiceId, this);
+    }
+
+    public void stop() {
+        mTransport.unregisterService(mServiceId);
+    }
+
+    @Override
+    public void onMessageReceived(int service, int what, ByteBuffer content) {
+    }
+}
diff --git a/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Transport.java b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Transport.java
new file mode 100644
index 0000000..84897d3
--- /dev/null
+++ b/tests/AccessoryDisplay/common/src/com/android/accessorydisplay/common/Transport.java
@@ -0,0 +1,382 @@
+/*
+ * 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.accessorydisplay.common;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.SparseArray;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * A simple message transport.
+ * <p>
+ * This object's interface is thread-safe, however incoming messages
+ * are always delivered on the {@link Looper} thread on which the transport
+ * was created.
+ * </p>
+ */
+public abstract class Transport {
+    private static final int MAX_INPUT_BUFFERS = 8;
+
+    private final Logger mLogger;
+
+    // The transport thread looper and handler.
+    private final TransportHandler mHandler;
+
+    // Lock to guard all mutable state.
+    private final Object mLock = new Object();
+
+    // The output buffer.  Set to null when the transport is closed.
+    private ByteBuffer mOutputBuffer;
+
+    // The input buffer pool.
+    private BufferPool mInputBufferPool;
+
+    // The reader thread.  Initialized when reading starts.
+    private ReaderThread mThread;
+
+    // The list of callbacks indexed by service id.
+    private final SparseArray<Callback> mServices = new SparseArray<Callback>();
+
+    public Transport(Logger logger, int maxPacketSize) {
+        mLogger = logger;
+        mHandler = new TransportHandler();
+        mOutputBuffer = ByteBuffer.allocate(maxPacketSize);
+        mInputBufferPool = new BufferPool(
+                maxPacketSize, Protocol.MAX_ENVELOPE_SIZE, MAX_INPUT_BUFFERS);
+    }
+
+    /**
+     * Gets the logger for debugging.
+     */
+    public Logger getLogger() {
+        return mLogger;
+    }
+
+    /**
+     * Gets the handler on the transport's thread.
+     */
+    public Handler getHandler() {
+        return mHandler;
+    }
+
+    /**
+     * Closes the transport.
+     */
+    public void close() {
+        synchronized (mLock) {
+            if (mOutputBuffer != null) {
+                if (mThread == null) {
+                    ioClose();
+                } else {
+                    // If the thread was started then it will be responsible for
+                    // closing the stream when it quits because it may currently
+                    // be in the process of reading from the stream so we can't simply
+                    // shut it down right now.
+                    mThread.quit();
+                }
+                mOutputBuffer = null;
+            }
+        }
+    }
+
+    /**
+     * Sends a message.
+     *
+     * @param service The service to whom the message is addressed.
+     * @param what The message type.
+     * @param content The content, or null if there is none.
+     * @return True if the message was sent successfully, false if an error occurred.
+     */
+    public boolean sendMessage(int service, int what, ByteBuffer content) {
+        checkServiceId(service);
+        checkMessageId(what);
+
+        try {
+            synchronized (mLock) {
+                if (mOutputBuffer == null) {
+                    mLogger.logError("Send message failed because transport was closed.");
+                    return false;
+                }
+
+                final byte[] outputArray = mOutputBuffer.array();
+                final int capacity = mOutputBuffer.capacity();
+                mOutputBuffer.clear();
+                mOutputBuffer.putShort((short)service);
+                mOutputBuffer.putShort((short)what);
+                if (content == null) {
+                    mOutputBuffer.putInt(0);
+                } else {
+                    final int contentLimit = content.limit();
+                    int contentPosition = content.position();
+                    int contentRemaining = contentLimit - contentPosition;
+                    if (contentRemaining > Protocol.MAX_CONTENT_SIZE) {
+                        throw new IllegalArgumentException("Message content too large: "
+                                + contentRemaining + " > " + Protocol.MAX_CONTENT_SIZE);
+                    }
+                    mOutputBuffer.putInt(contentRemaining);
+                    while (contentRemaining != 0) {
+                        final int outputAvailable = capacity - mOutputBuffer.position();
+                        if (contentRemaining <= outputAvailable) {
+                            mOutputBuffer.put(content);
+                            break;
+                        }
+                        content.limit(contentPosition + outputAvailable);
+                        mOutputBuffer.put(content);
+                        content.limit(contentLimit);
+                        ioWrite(outputArray, 0, capacity);
+                        contentPosition += outputAvailable;
+                        contentRemaining -= outputAvailable;
+                        mOutputBuffer.clear();
+                    }
+                }
+                ioWrite(outputArray, 0, mOutputBuffer.position());
+                return true;
+            }
+        } catch (IOException ex) {
+            mLogger.logError("Send message failed: " + ex);
+            return false;
+        }
+    }
+
+    /**
+     * Starts reading messages on a separate thread.
+     */
+    public void startReading() {
+        synchronized (mLock) {
+            if (mOutputBuffer == null) {
+                throw new IllegalStateException("Transport has been closed");
+            }
+
+            mThread = new ReaderThread();
+            mThread.start();
+        }
+    }
+
+    /**
+     * Registers a service and provides a callback to receive messages.
+     *
+     * @param service The service id.
+     * @param callback The callback to use.
+     */
+    public void registerService(int service, Callback callback) {
+        checkServiceId(service);
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+
+        synchronized (mLock) {
+            mServices.put(service, callback);
+        }
+    }
+
+    /**
+     * Unregisters a service.
+     *
+     * @param service The service to unregister.
+     */
+    public void unregisterService(int service) {
+        checkServiceId(service);
+
+        synchronized (mLock) {
+            mServices.remove(service);
+        }
+    }
+
+    private void dispatchMessageReceived(int service, int what, ByteBuffer content) {
+        final Callback callback;
+        synchronized (mLock) {
+            callback = mServices.get(service);
+        }
+        if (callback != null) {
+            callback.onMessageReceived(service, what, content);
+        } else {
+            mLogger.log("Discarding message " + what
+                    + " for unregistered service " + service);
+        }
+    }
+
+    private static void checkServiceId(int service) {
+        if (service < 0 || service > 0xffff) {
+            throw new IllegalArgumentException("service id out of range: " + service);
+        }
+    }
+
+    private static void checkMessageId(int what) {
+        if (what < 0 || what > 0xffff) {
+            throw new IllegalArgumentException("message id out of range: " + what);
+        }
+    }
+
+    // The IO methods must be safe to call on any thread.
+    // They may be called concurrently.
+    protected abstract void ioClose();
+    protected abstract int ioRead(byte[] buffer, int offset, int count)
+            throws IOException;
+    protected abstract void ioWrite(byte[] buffer, int offset, int count)
+            throws IOException;
+
+    /**
+     * Callback for services that handle received messages.
+     */
+    public interface Callback {
+        /**
+         * Indicates that a message was received.
+         *
+         * @param service The service to whom the message is addressed.
+         * @param what The message type.
+         * @param content The content, or null if there is none.
+         */
+        public void onMessageReceived(int service, int what, ByteBuffer content);
+    }
+
+    final class TransportHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            final ByteBuffer buffer = (ByteBuffer)msg.obj;
+            try {
+                final int limit = buffer.limit();
+                while (buffer.position() < limit) {
+                    final int service = buffer.getShort() & 0xffff;
+                    final int what = buffer.getShort() & 0xffff;
+                    final int contentSize = buffer.getInt();
+                    if (contentSize == 0) {
+                        dispatchMessageReceived(service, what, null);
+                    } else {
+                        final int end = buffer.position() + contentSize;
+                        buffer.limit(end);
+                        dispatchMessageReceived(service, what, buffer);
+                        buffer.limit(limit);
+                        buffer.position(end);
+                    }
+                }
+            } finally {
+                mInputBufferPool.release(buffer);
+            }
+        }
+    }
+
+    final class ReaderThread extends Thread {
+        // Set to true when quitting.
+        private volatile boolean mQuitting;
+
+        public ReaderThread() {
+            super("Accessory Display Transport");
+        }
+
+        @Override
+        public void run() {
+            loop();
+            ioClose();
+        }
+
+        private void loop() {
+            ByteBuffer buffer = null;
+            int length = Protocol.HEADER_SIZE;
+            int contentSize = -1;
+            outer: while (!mQuitting) {
+                // Get a buffer.
+                if (buffer == null) {
+                    buffer = mInputBufferPool.acquire(length);
+                } else {
+                    buffer = mInputBufferPool.grow(buffer, length);
+                }
+
+                // Read more data until needed number of bytes obtained.
+                int position = buffer.position();
+                int count;
+                try {
+                    count = ioRead(buffer.array(), position, buffer.capacity() - position);
+                    if (count < 0) {
+                        break; // end of stream
+                    }
+                } catch (IOException ex) {
+                    mLogger.logError("Read failed: " + ex);
+                    break; // error
+                }
+                position += count;
+                buffer.position(position);
+                if (contentSize < 0 && position >= Protocol.HEADER_SIZE) {
+                    contentSize = buffer.getInt(4);
+                    if (contentSize < 0 || contentSize > Protocol.MAX_CONTENT_SIZE) {
+                        mLogger.logError("Encountered invalid content size: " + contentSize);
+                        break; // malformed stream
+                    }
+                    length += contentSize;
+                }
+                if (position < length) {
+                    continue; // need more data
+                }
+
+                // There is at least one complete message in the buffer.
+                // Find the end of a contiguous chunk of complete messages.
+                int next = length;
+                int remaining;
+                for (;;) {
+                    length = Protocol.HEADER_SIZE;
+                    remaining = position - next;
+                    if (remaining < length) {
+                        contentSize = -1;
+                        break; // incomplete header, need more data
+                    }
+                    contentSize = buffer.getInt(next + 4);
+                    if (contentSize < 0 || contentSize > Protocol.MAX_CONTENT_SIZE) {
+                        mLogger.logError("Encountered invalid content size: " + contentSize);
+                        break outer; // malformed stream
+                    }
+                    length += contentSize;
+                    if (remaining < length) {
+                        break; // incomplete content, need more data
+                    }
+                    next += length;
+                }
+
+                // Post the buffer then don't modify it anymore.
+                // Now this is kind of sneaky.  We know that no other threads will
+                // be acquiring buffers from the buffer pool so we can keep on
+                // referring to this buffer as long as we don't modify its contents.
+                // This allows us to operate in a single-buffered mode if desired.
+                buffer.limit(next);
+                buffer.rewind();
+                mHandler.obtainMessage(0, buffer).sendToTarget();
+
+                // If there is an incomplete message at the end, then we will need
+                // to copy it to a fresh buffer before continuing.  In the single-buffered
+                // case, we may acquire the same buffer as before which is fine.
+                if (remaining == 0) {
+                    buffer = null;
+                } else {
+                    final ByteBuffer oldBuffer = buffer;
+                    buffer = mInputBufferPool.acquire(length);
+                    System.arraycopy(oldBuffer.array(), next, buffer.array(), 0, remaining);
+                    buffer.position(remaining);
+                }
+            }
+
+            if (buffer != null) {
+                mInputBufferPool.release(buffer);
+            }
+        }
+
+        public void quit() {
+            mQuitting = true;
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/sink/Android.mk b/tests/AccessoryDisplay/sink/Android.mk
new file mode 100644
index 0000000..772ce0c
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the application.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := AccessoryDisplaySink
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
+LOCAL_STATIC_JAVA_LIBRARIES := AccessoryDisplayCommon
+include $(BUILD_PACKAGE)
diff --git a/tests/AccessoryDisplay/sink/AndroidManifest.xml b/tests/AccessoryDisplay/sink/AndroidManifest.xml
new file mode 100644
index 0000000..72d498f
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.accessorydisplay.sink" >
+
+    <uses-feature android:name="android.hardware.usb.host"/>
+    <uses-sdk android:minSdkVersion="18" />
+
+    <application android:label="@string/app_name"
+            android:icon="@drawable/ic_app"
+            android:hardwareAccelerated="true">
+
+        <activity android:name=".SinkActivity"
+                android:label="@string/app_name"
+                android:theme="@android:style/Theme.Holo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+                    android:resource="@xml/usb_device_filter"/>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/tests/AccessoryDisplay/sink/res/drawable-hdpi/ic_app.png b/tests/AccessoryDisplay/sink/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/AccessoryDisplay/sink/res/drawable-mdpi/ic_app.png b/tests/AccessoryDisplay/sink/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/AccessoryDisplay/sink/res/layout/sink_activity.xml b/tests/AccessoryDisplay/sink/res/layout/sink_activity.xml
new file mode 100644
index 0000000..6afb850
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/res/layout/sink_activity.xml
@@ -0,0 +1,44 @@
+<?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:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal">
+    <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="vertical">
+        <TextView android:id="@+id/fpsTextView"
+                android:layout_width="match_parent"
+                android:layout_height="64dp"
+                android:padding="4dp" />
+
+        <TextView android:id="@+id/logTextView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+    </LinearLayout>
+
+    <FrameLayout
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="2">
+        <SurfaceView android:id="@+id/surfaceView"
+                android:layout_width="640px"
+                android:layout_height="480px" />
+    </FrameLayout>
+</LinearLayout>
diff --git a/tests/AccessoryDisplay/sink/res/values/strings.xml b/tests/AccessoryDisplay/sink/res/values/strings.xml
new file mode 100644
index 0000000..29cd001
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Accessory Display Sink</string>
+</resources>
diff --git a/tests/AccessoryDisplay/sink/res/xml/usb_device_filter.xml b/tests/AccessoryDisplay/sink/res/xml/usb_device_filter.xml
new file mode 100644
index 0000000..e8fe929
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/res/xml/usb_device_filter.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resources>
+    <!-- Match all devices -->
+    <usb-device />
+
+    <!-- Android USB accessory: accessory -->
+    <usb-device vendor-id="16601" product-id="11520" />
+    <!-- Android USB accessory: accessory + adb -->
+    <usb-device vendor-id="16601" product-id="11521" />
+</resources>
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java
new file mode 100644
index 0000000..daec845
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java
@@ -0,0 +1,240 @@
+/*
+ * 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.accessorydisplay.sink;
+
+import com.android.accessorydisplay.common.Protocol;
+import com.android.accessorydisplay.common.Service;
+import com.android.accessorydisplay.common.Transport;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.os.Handler;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import java.nio.ByteBuffer;
+
+public class DisplaySinkService extends Service implements SurfaceHolder.Callback {
+    private final ByteBuffer mBuffer = ByteBuffer.allocate(12);
+    private final Handler mTransportHandler;
+    private final int mDensityDpi;
+
+    private SurfaceView mSurfaceView;
+
+    // These fields are guarded by the following lock.
+    // This is to ensure that the surface lifecycle is respected.  Although decoding
+    // happens on the transport thread, we are not allowed to access the surface after
+    // it is destroyed by the UI thread so we need to stop the codec immediately.
+    private final Object mSurfaceAndCodecLock = new Object();
+    private Surface mSurface;
+    private int mSurfaceWidth;
+    private int mSurfaceHeight;
+    private MediaCodec mCodec;
+    private ByteBuffer[] mCodecInputBuffers;
+    private BufferInfo mCodecBufferInfo;
+
+    public DisplaySinkService(Context context, Transport transport, int densityDpi) {
+        super(context, transport, Protocol.DisplaySinkService.ID);
+        mTransportHandler = transport.getHandler();
+        mDensityDpi = densityDpi;
+    }
+
+    public void setSurfaceView(final SurfaceView surfaceView) {
+        if (mSurfaceView != surfaceView) {
+            final SurfaceView oldSurfaceView = mSurfaceView;
+            mSurfaceView = surfaceView;
+
+            if (oldSurfaceView != null) {
+                oldSurfaceView.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final SurfaceHolder holder = oldSurfaceView.getHolder();
+                        holder.removeCallback(DisplaySinkService.this);
+                        updateSurfaceFromUi(null);
+                    }
+                });
+            }
+
+            if (surfaceView != null) {
+                surfaceView.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final SurfaceHolder holder = surfaceView.getHolder();
+                        holder.addCallback(DisplaySinkService.this);
+                        updateSurfaceFromUi(holder);
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
+    public void onMessageReceived(int service, int what, ByteBuffer content) {
+        switch (what) {
+            case Protocol.DisplaySinkService.MSG_QUERY: {
+                getLogger().log("Received MSG_QUERY.");
+                sendSinkStatus();
+                break;
+            }
+
+            case Protocol.DisplaySinkService.MSG_CONTENT: {
+                decode(content);
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        // Ignore.  Wait for surface changed event that follows.
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        updateSurfaceFromUi(holder);
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        updateSurfaceFromUi(null);
+    }
+
+    private void updateSurfaceFromUi(SurfaceHolder holder) {
+        Surface surface = null;
+        int width = 0, height = 0;
+        if (holder != null && !holder.isCreating()) {
+            surface = holder.getSurface();
+            if (surface.isValid()) {
+                final Rect frame = holder.getSurfaceFrame();
+                width = frame.width();
+                height = frame.height();
+            } else {
+                surface = null;
+            }
+        }
+
+        synchronized (mSurfaceAndCodecLock) {
+            if (mSurface == surface &&  mSurfaceWidth == width && mSurfaceHeight == height) {
+                return;
+            }
+
+            mSurface = surface;
+            mSurfaceWidth = width;
+            mSurfaceHeight = height;
+
+            if (mCodec != null) {
+                mCodec.stop();
+                mCodec = null;
+                mCodecInputBuffers = null;
+                mCodecBufferInfo = null;
+            }
+
+            if (mSurface != null) {
+                MediaFormat format = MediaFormat.createVideoFormat(
+                        "video/avc", mSurfaceWidth, mSurfaceHeight);
+                mCodec = MediaCodec.createDecoderByType("video/avc");
+                mCodec.configure(format, mSurface, null, 0);
+                mCodec.start();
+                mCodecBufferInfo = new BufferInfo();
+            }
+
+            mTransportHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    sendSinkStatus();
+                }
+            });
+        }
+    }
+
+    private void decode(ByteBuffer content) {
+        if (content == null) {
+            return;
+        }
+        synchronized (mSurfaceAndCodecLock) {
+            if (mCodec == null) {
+                return;
+            }
+
+            while (content.hasRemaining()) {
+                if (!provideCodecInputLocked(content)) {
+                    getLogger().log("Dropping content because there are no available buffers.");
+                    return;
+                }
+
+                consumeCodecOutputLocked();
+            }
+        }
+    }
+
+    private boolean provideCodecInputLocked(ByteBuffer content) {
+        final int index = mCodec.dequeueInputBuffer(0);
+        if (index < 0) {
+            return false;
+        }
+        if (mCodecInputBuffers == null) {
+            mCodecInputBuffers = mCodec.getInputBuffers();
+        }
+        final ByteBuffer buffer = mCodecInputBuffers[index];
+        final int capacity = buffer.capacity();
+        buffer.clear();
+        if (content.remaining() <= capacity) {
+            buffer.put(content);
+        } else {
+            final int limit = content.limit();
+            content.limit(content.position() + capacity);
+            buffer.put(content);
+            content.limit(limit);
+        }
+        buffer.flip();
+        mCodec.queueInputBuffer(index, 0, buffer.limit(), 0, 0);
+        return true;
+    }
+
+    private void consumeCodecOutputLocked() {
+        for (;;) {
+            final int index = mCodec.dequeueOutputBuffer(mCodecBufferInfo, 0);
+            if (index >= 0) {
+                mCodec.releaseOutputBuffer(index, true /*render*/);
+            } else if (index != MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED
+                    && index != MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                break;
+            }
+        }
+    }
+
+    private void sendSinkStatus() {
+        synchronized (mSurfaceAndCodecLock) {
+            if (mCodec != null) {
+                mBuffer.clear();
+                mBuffer.putInt(mSurfaceWidth);
+                mBuffer.putInt(mSurfaceHeight);
+                mBuffer.putInt(mDensityDpi);
+                mBuffer.flip();
+                getTransport().sendMessage(Protocol.DisplaySourceService.ID,
+                        Protocol.DisplaySourceService.MSG_SINK_AVAILABLE, mBuffer);
+            } else {
+                getTransport().sendMessage(Protocol.DisplaySourceService.ID,
+                        Protocol.DisplaySourceService.MSG_SINK_NOT_AVAILABLE, null);
+            }
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
new file mode 100644
index 0000000..6fe2cfb
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
@@ -0,0 +1,508 @@
+/*
+ * 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.accessorydisplay.sink;
+
+import com.android.accessorydisplay.common.Logger;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.widget.TextView;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.Map;
+
+public class SinkActivity extends Activity {
+    private static final String TAG = "SinkActivity";
+
+    private static final String ACTION_USB_DEVICE_PERMISSION =
+            "com.android.accessorydisplay.sink.ACTION_USB_DEVICE_PERMISSION";
+
+    private static final String MANUFACTURER = "Android";
+    private static final String MODEL = "Accessory Display";
+    private static final String DESCRIPTION = "Accessory Display Sink Test Application";
+    private static final String VERSION = "1.0";
+    private static final String URI = "http://www.android.com/";
+    private static final String SERIAL = "0000000012345678";
+
+    private static final int MULTITOUCH_DEVICE_ID = 0;
+    private static final int MULTITOUCH_REPORT_ID = 1;
+    private static final int MULTITOUCH_MAX_CONTACTS = 1;
+
+    private UsbManager mUsbManager;
+    private DeviceReceiver mReceiver;
+    private TextView mLogTextView;
+    private TextView mFpsTextView;
+    private SurfaceView mSurfaceView;
+    private Logger mLogger;
+
+    private boolean mConnected;
+    private int mProtocolVersion;
+    private UsbDevice mDevice;
+    private UsbInterface mAccessoryInterface;
+    private UsbDeviceConnection mAccessoryConnection;
+    private UsbEndpoint mControlEndpoint;
+    private UsbAccessoryBulkTransport mTransport;
+
+    private boolean mAttached;
+    private DisplaySinkService mDisplaySinkService;
+
+    private final ByteBuffer mHidBuffer = ByteBuffer.allocate(4096);
+    private UsbHid.Multitouch mMultitouch;
+    private boolean mMultitouchEnabled;
+    private UsbHid.Multitouch.Contact[] mMultitouchContacts;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+
+        setContentView(R.layout.sink_activity);
+
+        mLogTextView = (TextView) findViewById(R.id.logTextView);
+        mLogTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
+        mLogger = new TextLogger();
+
+        mFpsTextView = (TextView) findViewById(R.id.fpsTextView);
+
+        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
+        mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                sendHidTouch(event);
+                return true;
+            }
+        });
+
+        mLogger.log("Waiting for accessory display source to be attached to USB...");
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        filter.addAction(ACTION_USB_DEVICE_PERMISSION);
+        mReceiver = new DeviceReceiver();
+        registerReceiver(mReceiver, filter);
+
+        Intent intent = getIntent();
+        if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+            UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (device != null) {
+                onDeviceAttached(device);
+            }
+        } else {
+            Map<String, UsbDevice> devices = mUsbManager.getDeviceList();
+            if (devices != null) {
+                for (UsbDevice device : devices.values()) {
+                    onDeviceAttached(device);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        unregisterReceiver(mReceiver);
+    }
+
+    private void onDeviceAttached(UsbDevice device) {
+        mLogger.log("USB device attached: " + device);
+        if (!mConnected) {
+            connect(device);
+        }
+    }
+
+    private void onDeviceDetached(UsbDevice device) {
+        mLogger.log("USB device detached: " + device);
+        if (mConnected && device.equals(mDevice)) {
+            disconnect();
+        }
+    }
+
+    private void connect(UsbDevice device) {
+        if (mConnected) {
+            disconnect();
+        }
+
+        // Check whether we have permission to access the device.
+        if (!mUsbManager.hasPermission(device)) {
+            mLogger.log("Prompting the user for access to the device.");
+            Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION);
+            intent.setPackage(getPackageName());
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+            mUsbManager.requestPermission(device, pendingIntent);
+            return;
+        }
+
+        // Claim the device.
+        UsbDeviceConnection conn = mUsbManager.openDevice(device);
+        if (conn == null) {
+            mLogger.logError("Could not obtain device connection.");
+            return;
+        }
+        UsbInterface iface = device.getInterface(0);
+        UsbEndpoint controlEndpoint = iface.getEndpoint(0);
+        if (!conn.claimInterface(iface, true)) {
+            mLogger.logError("Could not claim interface.");
+            return;
+        }
+        try {
+            // If already in accessory mode, then connect to the device.
+            if (isAccessory(device)) {
+                mLogger.log("Connecting to accessory...");
+
+                int protocolVersion = getProtocol(conn);
+                if (protocolVersion < 1) {
+                    mLogger.logError("Device does not support accessory protocol.");
+                    return;
+                }
+                mLogger.log("Protocol version: " + protocolVersion);
+
+                // Setup bulk endpoints.
+                UsbEndpoint bulkIn = null;
+                UsbEndpoint bulkOut = null;
+                for (int i = 0; i < iface.getEndpointCount(); i++) {
+                    UsbEndpoint ep = iface.getEndpoint(i);
+                    if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
+                        if (bulkIn == null) {
+                            mLogger.log(String.format("Bulk IN endpoint: %d", i));
+                            bulkIn = ep;
+                        }
+                    } else {
+                        if (bulkOut == null) {
+                            mLogger.log(String.format("Bulk OUT endpoint: %d", i));
+                            bulkOut = ep;
+                        }
+                    }
+                }
+                if (bulkIn == null || bulkOut == null) {
+                    mLogger.logError("Unable to find bulk endpoints");
+                    return;
+                }
+
+                mLogger.log("Connected");
+                mConnected = true;
+                mDevice = device;
+                mProtocolVersion = protocolVersion;
+                mAccessoryInterface = iface;
+                mAccessoryConnection = conn;
+                mControlEndpoint = controlEndpoint;
+                mTransport = new UsbAccessoryBulkTransport(mLogger, conn, bulkIn, bulkOut);
+                if (mProtocolVersion >= 2) {
+                    registerHid();
+                }
+                startServices();
+                mTransport.startReading();
+                return;
+            }
+
+            // Do accessory negotiation.
+            mLogger.log("Attempting to switch device to accessory mode...");
+
+            // Send get protocol.
+            int protocolVersion = getProtocol(conn);
+            if (protocolVersion < 1) {
+                mLogger.logError("Device does not support accessory protocol.");
+                return;
+            }
+            mLogger.log("Protocol version: " + protocolVersion);
+
+            // Send identifying strings.
+            sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_MANUFACTURER, MANUFACTURER);
+            sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_MODEL, MODEL);
+            sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_DESCRIPTION, DESCRIPTION);
+            sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_VERSION, VERSION);
+            sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_URI, URI);
+            sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_SERIAL, SERIAL);
+
+            // Send start.
+            // The device should re-enumerate as an accessory.
+            mLogger.log("Sending accessory start request.");
+            int len = conn.controlTransfer(UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                    UsbAccessoryConstants.ACCESSORY_START, 0, 0, null, 0, 10000);
+            if (len != 0) {
+                mLogger.logError("Device refused to switch to accessory mode.");
+            } else {
+                mLogger.log("Waiting for device to re-enumerate...");
+            }
+        } finally {
+            if (!mConnected) {
+                conn.releaseInterface(iface);
+            }
+        }
+    }
+
+    private void disconnect() {
+        mLogger.log("Disconnecting from device: " + mDevice);
+        stopServices();
+        unregisterHid();
+
+        mLogger.log("Disconnected.");
+        mConnected = false;
+        mDevice = null;
+        mAccessoryConnection = null;
+        mAccessoryInterface = null;
+        mControlEndpoint = null;
+        if (mTransport != null) {
+            mTransport.close();
+            mTransport = null;
+        }
+    }
+
+    private void registerHid() {
+        mLogger.log("Registering HID multitouch device.");
+
+        mMultitouch = new UsbHid.Multitouch(MULTITOUCH_REPORT_ID, MULTITOUCH_MAX_CONTACTS,
+                mSurfaceView.getWidth(), mSurfaceView.getHeight());
+
+        mHidBuffer.clear();
+        mMultitouch.generateDescriptor(mHidBuffer);
+        mHidBuffer.flip();
+
+        mLogger.log("HID descriptor size: " + mHidBuffer.limit());
+        mLogger.log("HID report size: " + mMultitouch.getReportSize());
+
+        final int maxPacketSize = mControlEndpoint.getMaxPacketSize();
+        mLogger.log("Control endpoint max packet size: " + maxPacketSize);
+        if (mMultitouch.getReportSize() > maxPacketSize) {
+            mLogger.logError("HID report is too big for this accessory.");
+            return;
+        }
+
+        int len = mAccessoryConnection.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                UsbAccessoryConstants.ACCESSORY_REGISTER_HID,
+                MULTITOUCH_DEVICE_ID, mHidBuffer.limit(), null, 0, 10000);
+        if (len != 0) {
+            mLogger.logError("Device rejected ACCESSORY_REGISTER_HID request.");
+            return;
+        }
+
+        while (mHidBuffer.hasRemaining()) {
+            int position = mHidBuffer.position();
+            int count = Math.min(mHidBuffer.remaining(), maxPacketSize);
+            len = mAccessoryConnection.controlTransfer(
+                    UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                    UsbAccessoryConstants.ACCESSORY_SET_HID_REPORT_DESC,
+                    MULTITOUCH_DEVICE_ID, 0,
+                    mHidBuffer.array(), position, count, 10000);
+            if (len != count) {
+                mLogger.logError("Device rejected ACCESSORY_SET_HID_REPORT_DESC request.");
+                return;
+            }
+            mHidBuffer.position(position + count);
+        }
+
+        mLogger.log("HID device registered.");
+
+        mMultitouchEnabled = true;
+        if (mMultitouchContacts == null) {
+            mMultitouchContacts = new UsbHid.Multitouch.Contact[MULTITOUCH_MAX_CONTACTS];
+            for (int i = 0; i < MULTITOUCH_MAX_CONTACTS; i++) {
+                mMultitouchContacts[i] = new UsbHid.Multitouch.Contact();
+            }
+        }
+    }
+
+    private void unregisterHid() {
+        mMultitouch = null;
+        mMultitouchContacts = null;
+        mMultitouchEnabled = false;
+    }
+
+    private void sendHidTouch(MotionEvent event) {
+        if (mMultitouchEnabled) {
+            mLogger.log("Sending touch event: " + event);
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                case MotionEvent.ACTION_MOVE: {
+                    final int pointerCount =
+                            Math.min(MULTITOUCH_MAX_CONTACTS, event.getPointerCount());
+                    final int historySize = event.getHistorySize();
+                    for (int p = 0; p < pointerCount; p++) {
+                        mMultitouchContacts[p].id = event.getPointerId(p);
+                    }
+                    for (int h = 0; h < historySize; h++) {
+                        for (int p = 0; p < pointerCount; p++) {
+                            mMultitouchContacts[p].x = (int)event.getHistoricalX(p, h);
+                            mMultitouchContacts[p].y = (int)event.getHistoricalY(p, h);
+                        }
+                        sendHidTouchReport(pointerCount);
+                    }
+                    for (int p = 0; p < pointerCount; p++) {
+                        mMultitouchContacts[p].x = (int)event.getX(p);
+                        mMultitouchContacts[p].y = (int)event.getY(p);
+                    }
+                    sendHidTouchReport(pointerCount);
+                    break;
+                }
+
+                case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_UP:
+                    sendHidTouchReport(0);
+                    break;
+            }
+        }
+    }
+
+    private void sendHidTouchReport(int contactCount) {
+        mHidBuffer.clear();
+        mMultitouch.generateReport(mHidBuffer, mMultitouchContacts, contactCount);
+        mHidBuffer.flip();
+
+        int count = mHidBuffer.limit();
+        int len = mAccessoryConnection.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                UsbAccessoryConstants.ACCESSORY_SEND_HID_EVENT,
+                MULTITOUCH_DEVICE_ID, 0,
+                mHidBuffer.array(), 0, count, 10000);
+        if (len != count) {
+            mLogger.logError("Device rejected ACCESSORY_SEND_HID_EVENT request.");
+            return;
+        }
+    }
+
+    private void startServices() {
+        mDisplaySinkService = new DisplaySinkService(this, mTransport,
+                getResources().getConfiguration().densityDpi);
+        mDisplaySinkService.start();
+
+        if (mAttached) {
+            mDisplaySinkService.setSurfaceView(mSurfaceView);
+        }
+    }
+
+    private void stopServices() {
+        if (mDisplaySinkService != null) {
+            mDisplaySinkService.stop();
+            mDisplaySinkService = null;
+        }
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        mAttached = true;
+        if (mDisplaySinkService != null) {
+            mDisplaySinkService.setSurfaceView(mSurfaceView);
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        mAttached = false;
+        if (mDisplaySinkService != null) {
+            mDisplaySinkService.setSurfaceView(null);
+        }
+    }
+
+    private int getProtocol(UsbDeviceConnection conn) {
+        byte buffer[] = new byte[2];
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
+                UsbAccessoryConstants.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
+        if (len != 2) {
+            return -1;
+        }
+        return (buffer[1] << 8) | buffer[0];
+    }
+
+    private void sendString(UsbDeviceConnection conn, int index, String string) {
+        byte[] buffer = (string + "\0").getBytes();
+        int len = conn.controlTransfer(UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                UsbAccessoryConstants.ACCESSORY_SEND_STRING, 0, index,
+                buffer, buffer.length, 10000);
+        if (len != buffer.length) {
+            mLogger.logError("Failed to send string " + index + ": \"" + string + "\"");
+        } else {
+            mLogger.log("Sent string " + index + ": \"" + string + "\"");
+        }
+    }
+
+    private static boolean isAccessory(UsbDevice device) {
+        final int vid = device.getVendorId();
+        final int pid = device.getProductId();
+        return vid == UsbAccessoryConstants.USB_ACCESSORY_VENDOR_ID
+                && (pid == UsbAccessoryConstants.USB_ACCESSORY_PRODUCT_ID
+                        || pid == UsbAccessoryConstants.USB_ACCESSORY_ADB_PRODUCT_ID);
+    }
+
+    class TextLogger extends Logger {
+        @Override
+        public void log(final String message) {
+            Log.d(TAG, message);
+
+            mLogTextView.post(new Runnable() {
+                @Override
+                public void run() {
+                    mLogTextView.append(message);
+                    mLogTextView.append("\n");
+                }
+            });
+        }
+    }
+
+    class DeviceReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (device != null) {
+                String action = intent.getAction();
+                if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+                    onDeviceAttached(device);
+                } else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
+                    onDeviceDetached(device);
+                } else if (action.equals(ACTION_USB_DEVICE_PERMISSION)) {
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        mLogger.log("Device permission granted: " + device);
+                        onDeviceAttached(device);
+                    } else {
+                        mLogger.logError("Device permission denied: " + device);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbAccessoryBulkTransport.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbAccessoryBulkTransport.java
new file mode 100644
index 0000000..a15bfad
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbAccessoryBulkTransport.java
@@ -0,0 +1,73 @@
+/*
+ * 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.accessorydisplay.sink;
+
+import com.android.accessorydisplay.common.Logger;
+import com.android.accessorydisplay.common.Transport;
+
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+
+import java.io.IOException;
+
+/**
+ * Sends or receives messages using bulk endpoints associated with a {@link UsbDevice}
+ * that represents a USB accessory.
+ */
+public class UsbAccessoryBulkTransport extends Transport {
+    private static final int TIMEOUT_MILLIS = 1000;
+
+    private UsbDeviceConnection mConnection;
+    private UsbEndpoint mBulkInEndpoint;
+    private UsbEndpoint mBulkOutEndpoint;
+
+    public UsbAccessoryBulkTransport(Logger logger, UsbDeviceConnection connection,
+            UsbEndpoint bulkInEndpoint, UsbEndpoint bulkOutEndpoint) {
+        super(logger, 16384);
+        mConnection = connection;
+        mBulkInEndpoint = bulkInEndpoint;
+        mBulkOutEndpoint = bulkOutEndpoint;
+    }
+
+    @Override
+    protected void ioClose() {
+        mConnection = null;
+        mBulkInEndpoint = null;
+        mBulkOutEndpoint = null;
+    }
+
+    @Override
+    protected int ioRead(byte[] buffer, int offset, int count) throws IOException {
+        if (mConnection == null) {
+            throw new IOException("Connection was closed.");
+        }
+        return mConnection.bulkTransfer(mBulkInEndpoint, buffer, offset, count, -1);
+    }
+
+    @Override
+    protected void ioWrite(byte[] buffer, int offset, int count) throws IOException {
+        if (mConnection == null) {
+            throw new IOException("Connection was closed.");
+        }
+        int result = mConnection.bulkTransfer(mBulkOutEndpoint,
+                buffer, offset, count, TIMEOUT_MILLIS);
+        if (result < 0) {
+            throw new IOException("Bulk transfer failed.");
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbAccessoryConstants.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbAccessoryConstants.java
new file mode 100644
index 0000000..8197d6b
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbAccessoryConstants.java
@@ -0,0 +1,135 @@
+/*
+ * 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.accessorydisplay.sink;
+
+// Constants from kernel include/linux/usb/f_accessory.h
+final class UsbAccessoryConstants {
+    /* Use Google Vendor ID when in accessory mode */
+    public static final int USB_ACCESSORY_VENDOR_ID = 0x18D1;
+
+    /* Product ID to use when in accessory mode */
+    public static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00;
+
+    /* Product ID to use when in accessory mode and adb is enabled */
+    public static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01;
+
+    /* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */
+    public static final int ACCESSORY_STRING_MANUFACTURER = 0;
+    public static final int ACCESSORY_STRING_MODEL = 1;
+    public static final int ACCESSORY_STRING_DESCRIPTION = 2;
+    public static final int ACCESSORY_STRING_VERSION = 3;
+    public static final int ACCESSORY_STRING_URI = 4;
+    public static final int ACCESSORY_STRING_SERIAL = 5;
+
+    /* Control request for retrieving device's protocol version
+     *
+     *  requestType:    USB_DIR_IN | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_GET_PROTOCOL
+     *  value:          0
+     *  index:          0
+     *  data            version number (16 bits little endian)
+     *                     1 for original accessory support
+     *                     2 adds HID and device to host audio support
+     */
+    public static final int ACCESSORY_GET_PROTOCOL = 51;
+
+    /* Control request for host to send a string to the device
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_SEND_STRING
+     *  value:          0
+     *  index:          string ID
+     *  data            zero terminated UTF8 string
+     *
+     *  The device can later retrieve these strings via the
+     *  ACCESSORY_GET_STRING_* ioctls
+     */
+    public static final int ACCESSORY_SEND_STRING = 52;
+
+    /* Control request for starting device in accessory mode.
+     * The host sends this after setting all its strings to the device.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_START
+     *  value:          0
+     *  index:          0
+     *  data            none
+     */
+    public static final int ACCESSORY_START = 53;
+
+    /* Control request for registering a HID device.
+     * Upon registering, a unique ID is sent by the accessory in the
+     * value parameter. This ID will be used for future commands for
+     * the device
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_REGISTER_HID_DEVICE
+     *  value:          Accessory assigned ID for the HID device
+     *  index:          total length of the HID report descriptor
+     *  data            none
+     */
+    public static final int ACCESSORY_REGISTER_HID = 54;
+
+    /* Control request for unregistering a HID device.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_REGISTER_HID
+     *  value:          Accessory assigned ID for the HID device
+     *  index:          0
+     *  data            none
+     */
+    public static final int ACCESSORY_UNREGISTER_HID = 55;
+
+    /* Control request for sending the HID report descriptor.
+     * If the HID descriptor is longer than the endpoint zero max packet size,
+     * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+     * commands. The data for the descriptor must be sent sequentially
+     * if multiple packets are needed.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_SET_HID_REPORT_DESC
+     *  value:          Accessory assigned ID for the HID device
+     *  index:          offset of data in descriptor
+     *                      (needed when HID descriptor is too big for one packet)
+     *  data            the HID report descriptor
+     */
+    public static final int ACCESSORY_SET_HID_REPORT_DESC = 56;
+
+    /* Control request for sending HID events.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_SEND_HID_EVENT
+     *  value:          Accessory assigned ID for the HID device
+     *  index:          0
+     *  data            the HID report for the event
+     */
+    public static final int ACCESSORY_SEND_HID_EVENT = 57;
+
+    /* Control request for setting the audio mode.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_SET_AUDIO_MODE
+     *  value:          0 - no audio
+     *                     1 - device to host, 44100 16-bit stereo PCM
+     *  index:          0
+     *  data            none
+     */
+    public static final int ACCESSORY_SET_AUDIO_MODE = 58;
+
+    private UsbAccessoryConstants() {
+    }
+}
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbHid.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbHid.java
new file mode 100644
index 0000000..b4fa1fd
--- /dev/null
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/UsbHid.java
@@ -0,0 +1,130 @@
+/*
+ * 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.accessorydisplay.sink;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Helper for creating USB HID descriptors and reports.
+ */
+final class UsbHid {
+    private UsbHid() {
+    }
+
+    /**
+     * Generates basic Windows 7 compatible HID multitouch descriptors and reports
+     * that should be supported by recent versions of the Linux hid-multitouch driver.
+     */
+    public static final class Multitouch {
+        private final int mReportId;
+        private final int mMaxContacts;
+        private final int mWidth;
+        private final int mHeight;
+
+        public Multitouch(int reportId, int maxContacts, int width, int height) {
+            mReportId = reportId;
+            mMaxContacts = maxContacts;
+            mWidth = width;
+            mHeight = height;
+        }
+
+        public void generateDescriptor(ByteBuffer buffer) {
+            buffer.put(new byte[] {
+                0x05, 0x0d,                         // USAGE_PAGE (Digitizers)
+                0x09, 0x04,                         // USAGE (Touch Screen)
+                (byte)0xa1, 0x01,                   // COLLECTION (Application)
+                (byte)0x85, (byte)mReportId,        //   REPORT_ID (Touch)
+                0x09, 0x22,                         //   USAGE (Finger)
+                (byte)0xa1, 0x00,                   //   COLLECTION (Physical)
+                0x09, 0x55,                         //     USAGE (Contact Count Maximum)
+                0x15, 0x00,                         //     LOGICAL_MINIMUM (0)
+                0x25, (byte)mMaxContacts,           //     LOGICAL_MAXIMUM (...)
+                0x75, 0x08,                         //     REPORT_SIZE (8)
+                (byte)0x95, 0x01,                   //     REPORT_COUNT (1)
+                (byte)0xb1, (byte)mMaxContacts,     //     FEATURE (Data,Var,Abs)
+                0x09, 0x54,                         //     USAGE (Contact Count)
+                (byte)0x81, 0x02,                   //     INPUT (Data,Var,Abs)
+            });
+            byte maxXLsb = (byte)(mWidth - 1);
+            byte maxXMsb = (byte)((mWidth - 1) >> 8);
+            byte maxYLsb = (byte)(mHeight - 1);
+            byte maxYMsb = (byte)((mHeight - 1) >> 8);
+            byte[] collection = new byte[] { 
+                0x05, 0x0d,                         //     USAGE_PAGE (Digitizers)
+                0x09, 0x22,                         //     USAGE (Finger)
+                (byte)0xa1, 0x02,                   //     COLLECTION (Logical)
+                0x09, 0x42,                         //       USAGE (Tip Switch)
+                0x15, 0x00,                         //       LOGICAL_MINIMUM (0)
+                0x25, 0x01,                         //       LOGICAL_MAXIMUM (1)
+                0x75, 0x01,                         //       REPORT_SIZE (1)
+                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
+                0x09, 0x32,                         //       USAGE (In Range)
+                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
+                0x09, 0x51,                         //       USAGE (Contact Identifier)
+                0x25, 0x3f,                         //       LOGICAL_MAXIMUM (63)
+                0x75, 0x06,                         //       REPORT_SIZE (6)
+                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
+                0x05, 0x01,                         //       USAGE_PAGE (Generic Desktop)
+                0x09, 0x30,                         //       USAGE (X)
+                0x26, maxXLsb, maxXMsb,             //       LOGICAL_MAXIMUM (...)
+                0x75, 0x10,                         //       REPORT_SIZE (16)
+                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
+                0x09, 0x31,                         //       USAGE (Y)
+                0x26, maxYLsb, maxYMsb,             //       LOGICAL_MAXIMUM (...)
+                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
+                (byte)0xc0,                         //     END_COLLECTION
+            };
+            for (int i = 0; i < mMaxContacts; i++) {
+                buffer.put(collection);
+            }
+            buffer.put(new byte[] {
+                (byte)0xc0,                         //   END_COLLECTION
+                (byte)0xc0,                         // END_COLLECTION
+            });
+        }
+
+        public void generateReport(ByteBuffer buffer, Contact[] contacts, int contactCount) {
+            // Report Id
+            buffer.put((byte)mReportId);
+            // Contact Count
+            buffer.put((byte)contactCount);
+
+            for (int i = 0; i < contactCount; i++) {
+                final Contact contact = contacts[i];
+                // Tip Switch, In Range, Contact Identifier
+                buffer.put((byte)((contact.id << 2) | 0x03));
+                // X
+                buffer.put((byte)contact.x).put((byte)(contact.x >> 8));
+                // Y
+                buffer.put((byte)contact.y).put((byte)(contact.y >> 8));
+            }
+            for (int i = contactCount; i < mMaxContacts; i++) {
+                buffer.put((byte)0).put((byte)0).put((byte)0).put((byte)0).put((byte)0);
+            }
+        }
+
+        public int getReportSize() {
+            return 2 + mMaxContacts * 5;
+        }
+
+        public static final class Contact {
+            public int id; // range 0..63
+            public int x;
+            public int y;
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/source/Android.mk b/tests/AccessoryDisplay/source/Android.mk
new file mode 100644
index 0000000..5d1085d
--- /dev/null
+++ b/tests/AccessoryDisplay/source/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the application.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := AccessoryDisplaySource
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
+LOCAL_STATIC_JAVA_LIBRARIES := AccessoryDisplayCommon
+include $(BUILD_PACKAGE)
diff --git a/tests/AccessoryDisplay/source/AndroidManifest.xml b/tests/AccessoryDisplay/source/AndroidManifest.xml
new file mode 100644
index 0000000..d3edcb8
--- /dev/null
+++ b/tests/AccessoryDisplay/source/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.accessorydisplay.source" >
+
+    <uses-feature android:name="android.hardware.usb.accessory"/>
+    <uses-sdk android:minSdkVersion="18" />
+
+    <application android:label="@string/app_name"
+            android:icon="@drawable/ic_app"
+            android:hardwareAccelerated="true">
+
+        <activity android:name=".SourceActivity"
+                android:label="@string/app_name"
+                android:theme="@android:style/Theme.Holo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                    android:resource="@xml/usb_accessory_filter"/>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/tests/AccessoryDisplay/source/res/drawable-hdpi/ic_app.png b/tests/AccessoryDisplay/source/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/AccessoryDisplay/source/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/AccessoryDisplay/source/res/drawable-mdpi/ic_app.png b/tests/AccessoryDisplay/source/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/AccessoryDisplay/source/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/AccessoryDisplay/source/res/layout/presentation_content.xml b/tests/AccessoryDisplay/source/res/layout/presentation_content.xml
new file mode 100644
index 0000000..bf9566a
--- /dev/null
+++ b/tests/AccessoryDisplay/source/res/layout/presentation_content.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <android.opengl.GLSurfaceView android:id="@+id/surface_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    <Button android:id="@+id/explode_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_alignParentBottom="true"
+            android:text="Explode!" />
+</RelativeLayout>
diff --git a/tests/AccessoryDisplay/source/res/layout/source_activity.xml b/tests/AccessoryDisplay/source/res/layout/source_activity.xml
new file mode 100644
index 0000000..ff2b818
--- /dev/null
+++ b/tests/AccessoryDisplay/source/res/layout/source_activity.xml
@@ -0,0 +1,24 @@
+<?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:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+    <TextView android:id="@+id/logTextView"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/tests/AccessoryDisplay/source/res/values/strings.xml b/tests/AccessoryDisplay/source/res/values/strings.xml
new file mode 100644
index 0000000..0b488df
--- /dev/null
+++ b/tests/AccessoryDisplay/source/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Accessory Display Source</string>
+</resources>
diff --git a/tests/AccessoryDisplay/source/res/xml/usb_accessory_filter.xml b/tests/AccessoryDisplay/source/res/xml/usb_accessory_filter.xml
new file mode 100644
index 0000000..5313b4e
--- /dev/null
+++ b/tests/AccessoryDisplay/source/res/xml/usb_accessory_filter.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resources>
+    <!-- Match all devices -->
+    <usb-accessory manufacturer="Android" model="Accessory Display" />
+</resources>
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java
new file mode 100644
index 0000000..256f900
--- /dev/null
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java
@@ -0,0 +1,246 @@
+/*
+ * 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.accessorydisplay.source;
+
+import com.android.accessorydisplay.common.Protocol;
+import com.android.accessorydisplay.common.Service;
+import com.android.accessorydisplay.common.Transport;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Display;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+
+public class DisplaySourceService extends Service {
+    private static final int MSG_DISPATCH_DISPLAY_ADDED = 1;
+    private static final int MSG_DISPATCH_DISPLAY_REMOVED = 2;
+
+    private static final String DISPLAY_NAME = "Accessory Display";
+    private static final int BIT_RATE = 6000000;
+    private static final int FRAME_RATE = 30;
+    private static final int I_FRAME_INTERVAL = 10;
+
+    private final Callbacks mCallbacks;
+    private final ServiceHandler mHandler;
+    private final DisplayManager mDisplayManager;
+
+    private boolean mSinkAvailable;
+    private int mSinkWidth;
+    private int mSinkHeight;
+    private int mSinkDensityDpi;
+
+    private VirtualDisplayThread mVirtualDisplayThread;
+
+    public DisplaySourceService(Context context, Transport transport, Callbacks callbacks) {
+        super(context, transport, Protocol.DisplaySourceService.ID);
+        mCallbacks = callbacks;
+        mHandler = new ServiceHandler();
+        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+    }
+
+    @Override
+    public void start() {
+        super.start();
+
+        getLogger().log("Sending MSG_QUERY.");
+        getTransport().sendMessage(Protocol.DisplaySinkService.ID,
+                Protocol.DisplaySinkService.MSG_QUERY, null);
+    }
+
+    @Override
+    public void stop() {
+        super.stop();
+
+        handleSinkNotAvailable();
+    }
+
+    @Override
+    public void onMessageReceived(int service, int what, ByteBuffer content) {
+        switch (what) {
+            case Protocol.DisplaySourceService.MSG_SINK_AVAILABLE: {
+                getLogger().log("Received MSG_SINK_AVAILABLE");
+                if (content.remaining() >= 12) {
+                    final int width = content.getInt();
+                    final int height = content.getInt();
+                    final int densityDpi = content.getInt();
+                    if (width >= 0 && width <= 4096
+                            && height >= 0 && height <= 4096
+                            && densityDpi >= 60 && densityDpi <= 640) {
+                        handleSinkAvailable(width, height, densityDpi);
+                        return;
+                    }
+                }
+                getLogger().log("Receive invalid MSG_SINK_AVAILABLE message.");
+                break;
+            }
+
+            case Protocol.DisplaySourceService.MSG_SINK_NOT_AVAILABLE: {
+                getLogger().log("Received MSG_SINK_NOT_AVAILABLE");
+                handleSinkNotAvailable();
+                break;
+            }
+        }
+    }
+
+    private void handleSinkAvailable(int width, int height, int densityDpi) {
+        if (mSinkAvailable && mSinkWidth == width && mSinkHeight == height
+                && mSinkDensityDpi == densityDpi) {
+            return;
+        }
+
+        getLogger().log("Accessory display sink available: "
+                + "width=" + width + ", height=" + height
+                + ", densityDpi=" + densityDpi);
+        mSinkAvailable = true;
+        mSinkWidth = width;
+        mSinkHeight = height;
+        mSinkDensityDpi = densityDpi;
+        createVirtualDisplay();
+    }
+
+    private void handleSinkNotAvailable() {
+        getLogger().log("Accessory display sink not available.");
+
+        mSinkAvailable = false;
+        mSinkWidth = 0;
+        mSinkHeight = 0;
+        mSinkDensityDpi = 0;
+        releaseVirtualDisplay();
+    }
+
+    private void createVirtualDisplay() {
+        releaseVirtualDisplay();
+
+        mVirtualDisplayThread = new VirtualDisplayThread(
+                mSinkWidth, mSinkHeight, mSinkDensityDpi);
+        mVirtualDisplayThread.start();
+    }
+
+    private void releaseVirtualDisplay() {
+        if (mVirtualDisplayThread != null) {
+            mVirtualDisplayThread.quit();
+            mVirtualDisplayThread = null;
+        }
+    }
+
+    public interface Callbacks {
+        public void onDisplayAdded(Display display);
+        public void onDisplayRemoved(Display display);
+    }
+
+    private final class ServiceHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_DISPATCH_DISPLAY_ADDED: {
+                    mCallbacks.onDisplayAdded((Display)msg.obj);
+                    break;
+                }
+
+                case MSG_DISPATCH_DISPLAY_REMOVED: {
+                    mCallbacks.onDisplayRemoved((Display)msg.obj);
+                    break;
+                }
+            }
+        }
+    }
+
+    private final class VirtualDisplayThread extends Thread {
+        private static final int TIMEOUT_USEC = 1000000;
+
+        private final int mWidth;
+        private final int mHeight;
+        private final int mDensityDpi;
+
+        private volatile boolean mQuitting;
+
+        public VirtualDisplayThread(int width, int height, int densityDpi) {
+            mWidth = width;
+            mHeight = height;
+            mDensityDpi = densityDpi;
+        }
+
+        @Override
+        public void run() {
+            MediaFormat format = MediaFormat.createVideoFormat("video/avc", mWidth, mHeight);
+            format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+                    MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+            format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+            format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL);
+
+            MediaCodec codec = MediaCodec.createEncoderByType("video/avc");
+            codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+            Surface surface = codec.createInputSurface();
+            codec.start();
+
+            VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(
+                    DISPLAY_NAME, mWidth, mHeight, mDensityDpi, surface, 0);
+            if (virtualDisplay != null) {
+                mHandler.obtainMessage(MSG_DISPATCH_DISPLAY_ADDED,
+                        virtualDisplay.getDisplay()).sendToTarget();
+
+                stream(codec);
+
+                mHandler.obtainMessage(MSG_DISPATCH_DISPLAY_REMOVED,
+                        virtualDisplay.getDisplay()).sendToTarget();
+                virtualDisplay.release();
+            }
+
+            codec.signalEndOfInputStream();
+            codec.stop();
+        }
+
+        public void quit() {
+            mQuitting = true;
+        }
+
+        private void stream(MediaCodec codec) {
+            BufferInfo info = new BufferInfo();
+            ByteBuffer[] buffers = null;
+            while (!mQuitting) {
+                int index = codec.dequeueOutputBuffer(info, TIMEOUT_USEC);
+                if (index >= 0) {
+                    if (buffers == null) {
+                        buffers = codec.getOutputBuffers();
+                    }
+
+                    ByteBuffer buffer = buffers[index];
+                    buffer.limit(info.offset + info.size);
+                    buffer.position(info.offset);
+
+                    getTransport().sendMessage(Protocol.DisplaySinkService.ID,
+                            Protocol.DisplaySinkService.MSG_CONTENT, buffer);
+                    codec.releaseOutputBuffer(index, false);
+                } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+                    buffers = null;
+                } else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
+                    getLogger().log("Codec dequeue buffer timed out.");
+                }
+            }
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/SourceActivity.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/SourceActivity.java
new file mode 100644
index 0000000..c59c958
--- /dev/null
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/SourceActivity.java
@@ -0,0 +1,257 @@
+/*
+ * 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.accessorydisplay.source;
+
+import com.android.accessorydisplay.common.Logger;
+import com.android.accessorydisplay.source.presentation.DemoPresentation;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.Display;
+import android.widget.TextView;
+
+public class SourceActivity extends Activity {
+    private static final String TAG = "SourceActivity";
+
+    private static final String ACTION_USB_ACCESSORY_PERMISSION =
+            "com.android.accessorydisplay.source.ACTION_USB_ACCESSORY_PERMISSION";
+
+    private static final String MANUFACTURER = "Android";
+    private static final String MODEL = "Accessory Display";
+
+    private UsbManager mUsbManager;
+    private AccessoryReceiver mReceiver;
+    private TextView mLogTextView;
+    private Logger mLogger;
+    private Presenter mPresenter;
+
+    private boolean mConnected;
+    private UsbAccessory mAccessory;
+    private UsbAccessoryStreamTransport mTransport;
+
+    private DisplaySourceService mDisplaySourceService;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+
+        setContentView(R.layout.source_activity);
+
+        mLogTextView = (TextView) findViewById(R.id.logTextView);
+        mLogTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
+        mLogger = new TextLogger();
+        mPresenter = new Presenter();
+
+        mLogger.log("Waiting for accessory display sink to be attached to USB...");
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+        filter.addAction(ACTION_USB_ACCESSORY_PERMISSION);
+        mReceiver = new AccessoryReceiver();
+        registerReceiver(mReceiver, filter);
+
+        Intent intent = getIntent();
+        if (intent.getAction().equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+            UsbAccessory accessory =
+                    (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null) {
+                onAccessoryAttached(accessory);
+            }
+        } else {
+            UsbAccessory[] accessories = mUsbManager.getAccessoryList();
+            if (accessories != null) {
+                for (UsbAccessory accessory : accessories) {
+                    onAccessoryAttached(accessory);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        unregisterReceiver(mReceiver);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        //new DemoPresentation(this, getWindowManager().getDefaultDisplay()).show();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+
+    private void onAccessoryAttached(UsbAccessory accessory) {
+        mLogger.log("USB accessory attached: " + accessory);
+        if (!mConnected) {
+            connect(accessory);
+        }
+    }
+
+    private void onAccessoryDetached(UsbAccessory accessory) {
+        mLogger.log("USB accessory detached: " + accessory);
+        if (mConnected && accessory.equals(mAccessory)) {
+            disconnect();
+        }
+    }
+
+    private void connect(UsbAccessory accessory) {
+        if (!isSink(accessory)) {
+            mLogger.log("Not connecting to USB accessory because it is not an accessory display sink: "
+                    + accessory);
+            return;
+        }
+
+        if (mConnected) {
+            disconnect();
+        }
+
+        // Check whether we have permission to access the accessory.
+        if (!mUsbManager.hasPermission(accessory)) {
+            mLogger.log("Prompting the user for access to the accessory.");
+            Intent intent = new Intent(ACTION_USB_ACCESSORY_PERMISSION);
+            intent.setPackage(getPackageName());
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+            mUsbManager.requestPermission(accessory, pendingIntent);
+            return;
+        }
+
+        // Open the accessory.
+        ParcelFileDescriptor fd = mUsbManager.openAccessory(accessory);
+        if (fd == null) {
+            mLogger.logError("Could not obtain accessory connection.");
+            return;
+        }
+
+        // All set.
+        mLogger.log("Connected.");
+        mConnected = true;
+        mAccessory = accessory;
+        mTransport = new UsbAccessoryStreamTransport(mLogger, fd);
+        startServices();
+        mTransport.startReading();
+    }
+
+    private void disconnect() {
+        mLogger.log("Disconnecting from accessory: " + mAccessory);
+        stopServices();
+
+        mLogger.log("Disconnected.");
+        mConnected = false;
+        mAccessory = null;
+        if (mTransport != null) {
+            mTransport.close();
+            mTransport = null;
+        }
+    }
+
+    private void startServices() {
+        mDisplaySourceService = new DisplaySourceService(this, mTransport, mPresenter);
+        mDisplaySourceService.start();
+    }
+
+    private void stopServices() {
+        if (mDisplaySourceService != null) {
+            mDisplaySourceService.stop();
+            mDisplaySourceService = null;
+        }
+    }
+
+    private static boolean isSink(UsbAccessory accessory) {
+        return MANUFACTURER.equals(accessory.getManufacturer())
+                && MODEL.equals(accessory.getModel());
+    }
+
+    class TextLogger extends Logger {
+        @Override
+        public void log(final String message) {
+            Log.d(TAG, message);
+
+            mLogTextView.post(new Runnable() {
+                @Override
+                public void run() {
+                    mLogTextView.append(message);
+                    mLogTextView.append("\n");
+                }
+            });
+        }
+    }
+
+    class AccessoryReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            UsbAccessory accessory = intent.<UsbAccessory>getParcelableExtra(
+                    UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null) {
+                String action = intent.getAction();
+                if (action.equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+                    onAccessoryAttached(accessory);
+                } else if (action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)) {
+                    onAccessoryDetached(accessory);
+                } else if (action.equals(ACTION_USB_ACCESSORY_PERMISSION)) {
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        mLogger.log("Accessory permission granted: " + accessory);
+                        onAccessoryAttached(accessory);
+                    } else {
+                        mLogger.logError("Accessory permission denied: " + accessory);
+                    }
+                }
+            }
+        }
+    }
+
+    class Presenter implements DisplaySourceService.Callbacks {
+        private DemoPresentation mPresentation;
+
+        @Override
+        public void onDisplayAdded(Display display) {
+            mLogger.log("Accessory display added: " + display);
+
+            mPresentation = new DemoPresentation(SourceActivity.this, display, mLogger);
+            mPresentation.show();
+        }
+
+        @Override
+        public void onDisplayRemoved(Display display) {
+            mLogger.log("Accessory display removed: " + display);
+
+            if (mPresentation != null) {
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+        }
+    }
+}
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/UsbAccessoryStreamTransport.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/UsbAccessoryStreamTransport.java
new file mode 100644
index 0000000..c28f4359
--- /dev/null
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/UsbAccessoryStreamTransport.java
@@ -0,0 +1,70 @@
+/*
+ * 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.accessorydisplay.source;
+
+import com.android.accessorydisplay.common.Logger;
+import com.android.accessorydisplay.common.Transport;
+
+import android.hardware.usb.UsbAccessory;
+import android.os.ParcelFileDescriptor;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Sends or receives messages over a file descriptor associated with a {@link UsbAccessory}.
+ */
+public class UsbAccessoryStreamTransport extends Transport {
+    private ParcelFileDescriptor mFd;
+    private FileInputStream mInputStream;
+    private FileOutputStream mOutputStream;
+
+    public UsbAccessoryStreamTransport(Logger logger, ParcelFileDescriptor fd) {
+        super(logger, 16384);
+        mFd = fd;
+        mInputStream = new FileInputStream(fd.getFileDescriptor());
+        mOutputStream = new FileOutputStream(fd.getFileDescriptor());
+    }
+
+    @Override
+    protected void ioClose() {
+        try {
+            mFd.close();
+        } catch (IOException ex) {
+        }
+        mFd = null;
+        mInputStream = null;
+        mOutputStream = null;
+    }
+
+    @Override
+    protected int ioRead(byte[] buffer, int offset, int count) throws IOException {
+        if (mInputStream == null) {
+            throw new IOException("Stream was closed.");
+        }
+        return mInputStream.read(buffer, offset, count);
+    }
+
+    @Override
+    protected void ioWrite(byte[] buffer, int offset, int count) throws IOException {
+        if (mOutputStream == null) {
+            throw new IOException("Stream was closed.");
+        }
+        mOutputStream.write(buffer, offset, count);
+    }
+}
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/Cube.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/Cube.java
new file mode 100644
index 0000000..51d8da9
--- /dev/null
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/Cube.java
@@ -0,0 +1,100 @@
+/*
+ * 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.accessorydisplay.source.presentation;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A vertex shaded cube.
+ */
+class Cube
+{
+    public Cube()
+    {
+        int one = 0x10000;
+        int vertices[] = {
+                -one, -one, -one,
+                one, -one, -one,
+                one,  one, -one,
+                -one,  one, -one,
+                -one, -one,  one,
+                one, -one,  one,
+                one,  one,  one,
+                -one,  one,  one,
+        };
+
+        int colors[] = {
+                0,    0,    0,  one,
+                one,    0,    0,  one,
+                one,  one,    0,  one,
+                0,  one,    0,  one,
+                0,    0,  one,  one,
+                one,    0,  one,  one,
+                one,  one,  one,  one,
+                0,  one,  one,  one,
+        };
+
+        byte indices[] = {
+                0, 4, 5,    0, 5, 1,
+                1, 5, 6,    1, 6, 2,
+                2, 6, 7,    2, 7, 3,
+                3, 7, 4,    3, 4, 0,
+                4, 7, 6,    4, 6, 5,
+                3, 0, 1,    3, 1, 2
+        };
+
+        // Buffers to be passed to gl*Pointer() functions
+        // must be direct, i.e., they must be placed on the
+        // native heap where the garbage collector cannot
+        // move them.
+        //
+        // Buffers with multi-byte datatypes (e.g., short, int, float)
+        // must have their byte order set to native order
+
+        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
+        vbb.order(ByteOrder.nativeOrder());
+        mVertexBuffer = vbb.asIntBuffer();
+        mVertexBuffer.put(vertices);
+        mVertexBuffer.position(0);
+
+        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
+        cbb.order(ByteOrder.nativeOrder());
+        mColorBuffer = cbb.asIntBuffer();
+        mColorBuffer.put(colors);
+        mColorBuffer.position(0);
+
+        mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
+        mIndexBuffer.put(indices);
+        mIndexBuffer.position(0);
+    }
+
+    public void draw(GL10 gl)
+    {
+        gl.glFrontFace(GL10.GL_CW);
+        gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);
+        gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer);
+        gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
+    }
+
+    private IntBuffer   mVertexBuffer;
+    private IntBuffer   mColorBuffer;
+    private ByteBuffer  mIndexBuffer;
+}
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/CubeRenderer.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/CubeRenderer.java
new file mode 100644
index 0000000..51dc82a
--- /dev/null
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/CubeRenderer.java
@@ -0,0 +1,124 @@
+/*
+ * 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.accessorydisplay.source.presentation;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLSurfaceView;
+
+/**
+ * Render a pair of tumbling cubes.
+ */
+
+public class CubeRenderer implements GLSurfaceView.Renderer {
+    private boolean mTranslucentBackground;
+    private Cube mCube;
+    private float mAngle;
+    private float mScale = 1.0f;
+    private boolean mExploding;
+
+    public CubeRenderer(boolean useTranslucentBackground) {
+        mTranslucentBackground = useTranslucentBackground;
+        mCube = new Cube();
+    }
+
+    public void explode() {
+        mExploding = true;
+    }
+
+    public void onDrawFrame(GL10 gl) {
+        /*
+         * Usually, the first thing one might want to do is to clear
+         * the screen. The most efficient way of doing this is to use
+         * glClear().
+         */
+
+        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+
+        /*
+         * Now we're ready to draw some 3D objects
+         */
+
+        gl.glMatrixMode(GL10.GL_MODELVIEW);
+        gl.glLoadIdentity();
+        gl.glTranslatef(0, 0, -3.0f);
+        gl.glRotatef(mAngle,        0, 1, 0);
+        gl.glRotatef(mAngle*0.25f,  1, 0, 0);
+
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
+
+        gl.glScalef(mScale, mScale, mScale);
+        mCube.draw(gl);
+
+        gl.glRotatef(mAngle*2.0f, 0, 1, 1);
+        gl.glTranslatef(0.5f, 0.5f, 0.5f);
+
+        mCube.draw(gl);
+
+        mAngle += 1.2f;
+
+        if (mExploding) {
+            mScale *= 1.02f;
+            if (mScale > 4.0f) {
+                mScale = 1.0f;
+                mExploding = false;
+            }
+        }
+    }
+
+    public void onSurfaceChanged(GL10 gl, int width, int height) {
+         gl.glViewport(0, 0, width, height);
+
+         /*
+          * Set our projection matrix. This doesn't have to be done
+          * each time we draw, but usually a new projection needs to
+          * be set when the viewport is resized.
+          */
+
+         float ratio = (float) width / height;
+         gl.glMatrixMode(GL10.GL_PROJECTION);
+         gl.glLoadIdentity();
+         gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+    }
+
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        /*
+         * By default, OpenGL enables features that improve quality
+         * but reduce performance. One might want to tweak that
+         * especially on software renderer.
+         */
+        gl.glDisable(GL10.GL_DITHER);
+
+        /*
+         * Some one-time OpenGL initialization can be made here
+         * probably based on features of this particular context
+         */
+         gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
+                 GL10.GL_FASTEST);
+
+         if (mTranslucentBackground) {
+             gl.glClearColor(0,0,0,0);
+         } else {
+             gl.glClearColor(1,1,1,1);
+         }
+         gl.glEnable(GL10.GL_CULL_FACE);
+         gl.glShadeModel(GL10.GL_SMOOTH);
+         gl.glEnable(GL10.GL_DEPTH_TEST);
+    }
+}
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/DemoPresentation.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/DemoPresentation.java
new file mode 100644
index 0000000..517b7fc
--- /dev/null
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/presentation/DemoPresentation.java
@@ -0,0 +1,84 @@
+/*
+ * 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.accessorydisplay.source.presentation;
+
+import com.android.accessorydisplay.common.Logger;
+import com.android.accessorydisplay.source.R;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.content.res.Resources;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+
+/**
+ * The presentation to show on the accessory display.
+ * <p>
+ * Note that this display may have different metrics from the display on which
+ * the main activity is showing so we must be careful to use the presentation's
+ * own {@link Context} whenever we load resources.
+ * </p>
+ */
+public final class DemoPresentation extends Presentation {
+    private final Logger mLogger;
+
+    private GLSurfaceView mSurfaceView;
+    private CubeRenderer mRenderer;
+    private Button mExplodeButton;
+
+    public DemoPresentation(Context context, Display display, Logger logger) {
+        super(context, display);
+        mLogger = logger;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        // Be sure to call the super class.
+        super.onCreate(savedInstanceState);
+
+        // Get the resources for the context of the presentation.
+        // Notice that we are getting the resources from the context of the presentation.
+        Resources r = getContext().getResources();
+
+        // Inflate the layout.
+        setContentView(R.layout.presentation_content);
+
+        // Set up the surface view for visual interest.
+        mRenderer = new CubeRenderer(false);
+        mSurfaceView = (GLSurfaceView)findViewById(R.id.surface_view);
+        mSurfaceView.setRenderer(mRenderer);
+
+        // Add a button.
+        mExplodeButton = (Button)findViewById(R.id.explode_button);
+        mExplodeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mRenderer.explode();
+            }
+        });
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        mLogger.log("Received touch event: " + event);
+        return super.onTouchEvent(event);
+    }
+}
\ No newline at end of file
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index c7cd975..d7a6c1d 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -182,7 +182,7 @@
         menu.add("Send!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
             @Override public boolean onMenuItemClick(MenuItem item) {
                 Intent intent = new Intent(ActivityTestMain.this, SingleUserReceiver.class);
-                sendOrderedBroadcast(intent, null, new BroadcastResultReceiver(), 
+                sendOrderedBroadcast(intent, null, new BroadcastResultReceiver(),
                         null, Activity.RESULT_OK, null, null);
                 return true;
             }
@@ -285,6 +285,12 @@
                 return true;
             }
         });
+        menu.add("HashArray").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                ArrayMapTests.run();
+                return true;
+            }
+        });
         return true;
     }
 
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java b/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java
new file mode 100644
index 0000000..4ad6dc7
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java
@@ -0,0 +1,532 @@
+/*
+ * 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.google.android.test.activity;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class ArrayMapTests {
+    static final int OP_ADD = 1;
+    static final int OP_REM = 2;
+
+    static int[] OPS = new int[] {
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+    };
+
+    static int[] KEYS = new int[] {
+            // General adding and removing.
+             -1,    1900,    600,    200,   1200,   1500,   1800,    100,   1900,
+            2100,    300,    800,    600,   1100,   1300,   2000,   1000,   1400,
+             600,    -1,    1900,    600,    300,   2100,    200,    800,    800,
+            1800,   1500,   1300,   1100,   2000,   1400,   1000,   1200,   1900,
+
+            // Shrink when removing item from end.
+             100,    200,    300,    400,    500,    600,    700,    800,    900,
+             900,    800,    700,    600,    500,    400,    300,    200,    100,
+
+            // Shrink when removing item from middle.
+             100,    200,    300,    400,    500,    600,    700,    800,    900,
+             900,    800,    700,    600,    500,    400,    200,    300,    100,
+
+            // Shrink when removing item from front.
+             100,    200,    300,    400,    500,    600,    700,    800,    900,
+             900,    800,    700,    600,    500,    400,    100,    200,    300,
+
+            // Test hash collisions.
+             105,    106,    108,    104,    102,    102,    107,      5,    205,
+               4,    202,    203,      3,      5,    101,    109,    200,    201,
+               0,     -1,    100,
+             106,    108,    104,    102,    103,    105,    107,    101,    109,
+              -1,    100,      0,
+               4,      5,      3,      5,    200,    203,    202,    201,    205,
+    };
+
+    static class ControlledHash {
+        final int mValue;
+
+        ControlledHash(int value) {
+            mValue = value;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+            return mValue == ((ControlledHash)o).mValue;
+        }
+
+        @Override
+        public final int hashCode() {
+            return mValue/100;
+        }
+
+        @Override
+        public final String toString() {
+            return Integer.toString(mValue);
+        }
+    }
+
+    private static boolean compare(Object v1, Object v2) {
+        if (v1 == null) {
+            return v2 == null;
+        }
+        if (v2 == null) {
+            return false;
+        }
+        return v1.equals(v2);
+    }
+
+    private static boolean compareMaps(HashMap map, ArrayMap array) {
+        if (map.size() != array.size()) {
+            Log.e("test", "Bad size: expected " + map.size() + ", got " + array.size());
+            return false;
+        }
+
+        Set<Map.Entry> mapSet = map.entrySet();
+        for (Map.Entry entry : mapSet) {
+            Object expValue = entry.getValue();
+            Object gotValue = array.get(entry.getKey());
+            if (!compare(expValue, gotValue)) {
+                Log.e("test", "Bad value: expected " + expValue + ", got " + gotValue
+                        + " at key " + entry.getKey());
+                return false;
+            }
+        }
+
+        for (int i=0; i<array.size(); i++) {
+            Object gotValue = array.valueAt(i);
+            Object key = array.keyAt(i);
+            Object expValue = map.get(key);
+            if (!compare(expValue, gotValue)) {
+                Log.e("test", "Bad value: expected " + expValue + ", got " + gotValue
+                        + " at key " + key);
+                return false;
+            }
+        }
+
+        if (map.entrySet().hashCode() != array.entrySet().hashCode()) {
+            Log.e("test", "Entry set hash codes differ: map=0x"
+                    + Integer.toHexString(map.entrySet().hashCode()) + " array=0x"
+                    + Integer.toHexString(array.entrySet().hashCode()));
+            return false;
+        }
+
+        if (!map.entrySet().equals(array.entrySet())) {
+            Log.e("test", "Failed calling equals on map entry set against array set");
+            return false;
+        }
+
+        if (!array.entrySet().equals(map.entrySet())) {
+            Log.e("test", "Failed calling equals on array entry set against map set");
+            return false;
+        }
+
+        if (map.keySet().hashCode() != array.keySet().hashCode()) {
+            Log.e("test", "Key set hash codes differ: map=0x"
+                    + Integer.toHexString(map.keySet().hashCode()) + " array=0x"
+                    + Integer.toHexString(array.keySet().hashCode()));
+            return false;
+        }
+
+        if (!map.keySet().equals(array.keySet())) {
+            Log.e("test", "Failed calling equals on map key set against array set");
+            return false;
+        }
+
+        if (!array.keySet().equals(map.keySet())) {
+            Log.e("test", "Failed calling equals on array key set against map set");
+            return false;
+        }
+
+        if (!map.keySet().containsAll(array.keySet())) {
+            Log.e("test", "Failed map key set contains all of array key set");
+            return false;
+        }
+
+        if (!array.keySet().containsAll(map.keySet())) {
+            Log.e("test", "Failed array key set contains all of map key set");
+            return false;
+        }
+
+        if (!array.containsAll(map.keySet())) {
+            Log.e("test", "Failed array contains all of map key set");
+            return false;
+        }
+
+        if (!map.entrySet().containsAll(array.entrySet())) {
+            Log.e("test", "Failed map entry set contains all of array entry set");
+            return false;
+        }
+
+        if (!array.entrySet().containsAll(map.entrySet())) {
+            Log.e("test", "Failed array entry set contains all of map entry set");
+            return false;
+        }
+
+        return true;
+    }
+
+    private static boolean compareSets(HashSet set, ArraySet array) {
+        if (set.size() != array.size()) {
+            Log.e("test", "Bad size: expected " + set.size() + ", got " + array.size());
+            return false;
+        }
+
+        for (Object entry : set) {
+            if (!array.contains(entry)) {
+                Log.e("test", "Bad value: expected " + entry + " not found in ArraySet");
+                return false;
+            }
+        }
+
+        for (int i=0; i<array.size(); i++) {
+            Object entry = array.valueAt(i);
+            if (!set.contains(entry)) {
+                Log.e("test", "Bad value: unexpected " + entry + " in ArraySet");
+                return false;
+            }
+        }
+
+        int index = 0;
+        for (Object entry : array) {
+            Object realEntry = array.valueAt(index);
+            if (!compare(entry, realEntry)) {
+                Log.e("test", "Bad iterator: expected value " + realEntry + ", got " + entry
+                        + " at index " + index);
+                return false;
+            }
+            index++;
+        }
+
+        return true;
+    }
+
+    private static boolean validateArrayMap(ArrayMap array) {
+        Set<Map.Entry> entrySet = array.entrySet();
+        int index=0;
+        Iterator<Map.Entry> entryIt = entrySet.iterator();
+        while (entryIt.hasNext()) {
+            Map.Entry entry = entryIt.next();
+            Object value = entry.getKey();
+            Object realValue = array.keyAt(index);
+            if (!compare(realValue, value)) {
+                Log.e("test", "Bad array map entry set: expected key " + realValue
+                        + ", got " + value + " at index " + index);
+                return false;
+            }
+            value = entry.getValue();
+            realValue = array.valueAt(index);
+            if (!compare(realValue, value)) {
+                Log.e("test", "Bad array map entry set: expected value " + realValue
+                        + ", got " + value + " at index " + index);
+                return false;
+            }
+            index++;
+        }
+
+        index = 0;
+        Set keySet = array.keySet();
+        Iterator keyIt = keySet.iterator();
+        while (keyIt.hasNext()) {
+            Object value = keyIt.next();
+            Object realValue = array.keyAt(index);
+            if (!compare(realValue, value)) {
+                Log.e("test", "Bad array map key set: expected key " + realValue
+                        + ", got " + value + " at index " + index);
+                return false;
+            }
+            index++;
+        }
+
+        index = 0;
+        Collection valueCol = array.values();
+        Iterator valueIt = valueCol.iterator();
+        while (valueIt.hasNext()) {
+            Object value = valueIt.next();
+            Object realValue = array.valueAt(index);
+            if (!compare(realValue, value)) {
+                Log.e("test", "Bad array map value col: expected value " + realValue
+                        + ", got " + value + " at index " + index);
+                return false;
+            }
+            index++;
+        }
+
+        return true;
+    }
+
+    private static void dump(Map map, ArrayMap array) {
+        Log.e("test", "HashMap of " + map.size() + " entries:");
+        Set<Map.Entry> mapSet = map.entrySet();
+        for (Map.Entry entry : mapSet) {
+            Log.e("test", "    " + entry.getKey() + " -> " + entry.getValue());
+        }
+        Log.e("test", "ArrayMap of " + array.size() + " entries:");
+        for (int i=0; i<array.size(); i++) {
+            Log.e("test", "    " + array.keyAt(i) + " -> " + array.valueAt(i));
+        }
+    }
+
+    private static void dump(Set set, ArraySet array) {
+        Log.e("test", "HashSet of " + set.size() + " entries:");
+        for (Object entry : set) {
+            Log.e("test", "    " + entry);
+        }
+        Log.e("test", "ArraySet of " + array.size() + " entries:");
+        for (int i=0; i<array.size(); i++) {
+            Log.e("test", "    " + array.valueAt(i));
+        }
+    }
+
+    private static void dump(ArrayMap map1, ArrayMap map2) {
+        Log.e("test", "ArrayMap of " + map1.size() + " entries:");
+        Set<Map.Entry> mapSet = map1.entrySet();
+        for (int i=0; i<map2.size(); i++) {
+            Log.e("test", "    " + map1.keyAt(i) + " -> " + map1.valueAt(i));
+        }
+        Log.e("test", "ArrayMap of " + map2.size() + " entries:");
+        for (int i=0; i<map2.size(); i++) {
+            Log.e("test", "    " + map2.keyAt(i) + " -> " + map2.valueAt(i));
+        }
+    }
+
+    public static void run() {
+        HashMap<ControlledHash, Integer> hashMap = new HashMap<ControlledHash, Integer>();
+        ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<ControlledHash, Integer>();
+        HashSet<ControlledHash> hashSet = new HashSet<ControlledHash>();
+        ArraySet<ControlledHash> arraySet = new ArraySet<ControlledHash>();
+
+        for (int i=0; i<OPS.length; i++) {
+            Integer oldHash;
+            Integer oldArray;
+            boolean hashChanged;
+            boolean arrayChanged;
+            ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]);
+            switch (OPS[i]) {
+                case OP_ADD:
+                    Log.i("test", "Adding key: " + KEYS[i]);
+                    oldHash = hashMap.put(key, i);
+                    oldArray = arrayMap.put(key, i);
+                    hashChanged = hashSet.add(key);
+                    arrayChanged = arraySet.add(key);
+                    break;
+                case OP_REM:
+                    Log.i("test", "Removing key: " + KEYS[i]);
+                    oldHash = hashMap.remove(key);
+                    oldArray = arrayMap.remove(key);
+                    hashChanged = hashSet.remove(key);
+                    arrayChanged = arraySet.remove(key);
+                    break;
+                default:
+                    Log.e("test", "Bad operation " + OPS[i] + " @ " + i);
+                    return;
+            }
+            if (!compare(oldHash, oldArray)) {
+                Log.e("test", "Bad result: expected " + oldHash + ", got " + oldArray);
+                dump(hashMap, arrayMap);
+                return;
+            }
+            if (hashChanged != arrayChanged) {
+                Log.e("test", "Bad change: expected " + hashChanged + ", got " + arrayChanged);
+                dump(hashSet, arraySet);
+                return;
+            }
+            if (!validateArrayMap(arrayMap)) {
+                dump(hashMap, arrayMap);
+                return;
+            }
+            if (!compareMaps(hashMap, arrayMap)) {
+                dump(hashMap, arrayMap);
+                return;
+            }
+            if (!compareSets(hashSet, arraySet)) {
+                dump(hashSet, arraySet);
+                return;
+            }
+        }
+
+        arrayMap.put(new ControlledHash(50000), 100);
+        ControlledHash lookup = new ControlledHash(50000);
+        Iterator<ControlledHash> it = arrayMap.keySet().iterator();
+        while (it.hasNext()) {
+            if (it.next().equals(lookup)) {
+                it.remove();
+            }
+        }
+        if (arrayMap.containsKey(lookup)) {
+            Log.e("test", "Bad map iterator: didn't remove test key");
+            dump(hashMap, arrayMap);
+        }
+
+        arraySet.add(new ControlledHash(50000));
+        it = arraySet.iterator();
+        while (it.hasNext()) {
+            if (it.next().equals(lookup)) {
+                it.remove();
+            }
+        }
+        if (arraySet.contains(lookup)) {
+            Log.e("test", "Bad set iterator: didn't remove test key");
+            dump(hashSet, arraySet);
+        }
+
+        if (!equalsMapTest()) {
+            return;
+        }
+
+        if (!equalsSetTest()) {
+            return;
+        }
+
+        // map copy constructor test
+        ArrayMap newMap = new ArrayMap<Integer, String>();
+        for (int i = 0; i < 10; ++i) {
+            newMap.put(i, String.valueOf(i));
+        }
+        ArrayMap mapCopy = new ArrayMap(newMap);
+        if (!compare(mapCopy, newMap)) {
+            Log.e("test", "ArrayMap copy constructor failure: expected " +
+                    newMap + ", got " + mapCopy);
+            dump(newMap, mapCopy);
+            return;
+        }
+
+        // set copy constructor test
+        ArraySet newSet = new ArraySet<Integer>();
+        for (int i = 0; i < 10; ++i) {
+            newSet.add(i);
+        }
+        ArraySet setCopy = new ArraySet(newSet);
+        if (!compare(setCopy, newSet)) {
+            Log.e("test", "ArraySet copy constructor failure: expected " +
+                    newSet + ", got " + setCopy);
+            dump(newSet, setCopy);
+            return;
+        }
+
+        Log.e("test", "Test successful; printing final map.");
+        dump(hashMap, arrayMap);
+
+        Log.e("test", "Test successful; printing final set.");
+        dump(hashSet, arraySet);
+    }
+
+    private static boolean equalsMapTest() {
+        ArrayMap<Integer, String> map1 = new ArrayMap<Integer, String>();
+        ArrayMap<Integer, String> map2 = new ArrayMap<Integer, String>();
+        HashMap<Integer, String> map3 = new HashMap<Integer, String>();
+        if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
+            Log.e("test", "ArrayMap equals failure for empty maps " + map1 + ", " +
+                    map2 + ", " + map3);
+            return false;
+        }
+
+        for (int i = 0; i < 10; ++i) {
+            String value = String.valueOf(i);
+            map1.put(i, value);
+            map2.put(i, value);
+            map3.put(i, value);
+        }
+        if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
+            Log.e("test", "ArrayMap equals failure for populated maps " + map1 + ", " +
+                    map2 + ", " + map3);
+            return false;
+        }
+
+        map1.remove(0);
+        if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) {
+            Log.e("test", "ArrayMap equals failure for map size " + map1 + ", " +
+                    map2 + ", " + map3);
+            return false;
+        }
+
+        map1.put(0, "-1");
+        if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) {
+            Log.e("test", "ArrayMap equals failure for map contents " + map1 + ", " +
+                    map2 + ", " + map3);
+            return false;
+        }
+
+        return true;
+    }
+
+    private static boolean equalsSetTest() {
+        ArraySet<Integer> set1 = new ArraySet<Integer>();
+        ArraySet<Integer> set2 = new ArraySet<Integer>();
+        HashSet<Integer> set3 = new HashSet<Integer>();
+        if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) {
+            Log.e("test", "ArraySet equals failure for empty sets " + set1 + ", " +
+                    set2 + ", " + set3);
+            return false;
+        }
+
+        for (int i = 0; i < 10; ++i) {
+            set1.add(i);
+            set2.add(i);
+            set3.add(i);
+        }
+        if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) {
+            Log.e("test", "ArraySet equals failure for populated sets " + set1 + ", " +
+                    set2 + ", " + set3);
+            return false;
+        }
+
+        set1.remove(0);
+        if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) {
+            Log.e("test", "ArraSet equals failure for set size " + set1 + ", " +
+                    set2 + ", " + set3);
+            return false;
+        }
+
+        set1.add(-1);
+        if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) {
+            Log.e("test", "ArraySet equals failure for set contents " + set1 + ", " +
+                    set2 + ", " + set3);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/media/libdrm/Android.mk b/tests/Camera2Tests/Android.mk
similarity index 100%
rename from media/libdrm/Android.mk
rename to tests/Camera2Tests/Android.mk
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
index 9939c08..6ad01a0 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
@@ -224,7 +224,7 @@
                     put("rotate45", new DisplayModifier() {
                         @Override
                         public void modifyDrawing(Paint paint, Canvas canvas) {
-                            canvas.rotate(5);
+                            canvas.rotate(45);
                         }
                     });
                     put("rotate90", new DisplayModifier() {
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
index 400dff0..405ff65 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
@@ -82,6 +82,7 @@
                         mCompareImageView.setImageBitmap(mCompareBitmap);
                         break;
                 }
+                mCompareImageView.getDrawable().setFilterBitmap(false);
                 mCompareImageView.invalidate();
             }
 
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
index 668f61d..3681784 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
@@ -49,8 +49,8 @@
     float4 diff = idealPixel - givenPixel;
     float totalDiff = diff.x + diff.y + diff.z + diff.w;
     if (totalDiff < 0) {
-        v_out[0] = rsPackColorTo8888(0, 0, clamp(-totalDiff/2, 0, 1));
+        v_out[0] = rsPackColorTo8888(0, 0, clamp(-totalDiff/2.f, 0.f, 1.f));
     } else {
-        v_out[0] = rsPackColorTo8888(clamp(totalDiff/2, 0, 1), 0, 0);
+        v_out[0] = rsPackColorTo8888(clamp(totalDiff/2.f, 0.f, 1.f), 0, 0);
     }
 }
diff --git a/tests/DumpRenderTree/Android.mk b/tests/DumpRenderTree/Android.mk
deleted file mode 100644
index 505a436..0000000
--- a/tests/DumpRenderTree/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_PACKAGE_NAME := DumpRenderTree
-
-include $(BUILD_PACKAGE)
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
deleted file mode 100644
index bcb821b..0000000
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ /dev/null
@@ -1,46 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.dumprendertree">
-    <application android:name="HTMLHostApp">
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="Menu" android:label="Dump Render Tree"
-          android:screenOrientation="portrait"
-          android:theme="@android:style/Theme.Light">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.TEST" />
-            </intent-filter>
-        </activity>
-        <activity android:name="TestShellActivity"
-          android:launchMode="singleTop"
-          android:hardwareAccelerated="true"
-          android:screenOrientation="portrait"
-          android:theme="@android:style/Theme.Light"/>
-        <activity android:name="ReliabilityTestActivity" android:screenOrientation="portrait"
-          android:theme="@android:style/Theme.Light"/>
-    </application>
-
-    <instrumentation android:name=".LayoutTestsAutoRunner"
-        android:targetPackage="com.android.dumprendertree"
-        android:label="Layout test automation runner"
-    />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.WRITE_SDCARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-sdk android:minSdkVersion="5"
-              android:targetSdkVersion="5" />
-</manifest>
diff --git a/tests/DumpRenderTree/assets/results/layout_tests_crashed.txt b/tests/DumpRenderTree/assets/results/layout_tests_crashed.txt
deleted file mode 100644
index 89439d3..0000000
--- a/tests/DumpRenderTree/assets/results/layout_tests_crashed.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/basic-auth.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/failed-auth.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cross-origin-authorization.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cross-origin-no-authorization.html
diff --git a/tests/DumpRenderTree/assets/results/layout_tests_failed.txt b/tests/DumpRenderTree/assets/results/layout_tests_failed.txt
deleted file mode 100644
index 5b64b9a..0000000
--- a/tests/DumpRenderTree/assets/results/layout_tests_failed.txt
+++ /dev/null
@@ -1,1010 +0,0 @@
-/sdcard/android/layout_tests/accessibility/onclick-handlers.html
-/sdcard/android/layout_tests/accessibility/textarea-insertion-point-line-number.html
-/sdcard/android/layout_tests/accessibility/aria-readonly.html
-/sdcard/android/layout_tests/accessibility/radio-button-checkbox-size.html
-/sdcard/android/layout_tests/accessibility/th-as-title-ui.html
-/sdcard/android/layout_tests/accessibility/visible-elements.html
-/sdcard/android/layout_tests/accessibility/iframe-bastardization.html
-/sdcard/android/layout_tests/accessibility/button-press-action.html
-/sdcard/android/layout_tests/accessibility/img-aria-button-alt-tag.html
-/sdcard/android/layout_tests/accessibility/input-image-alt.html
-/sdcard/android/layout_tests/accessibility/radio-button-title-label.html
-/sdcard/android/layout_tests/accessibility/aria-hidden.html
-/sdcard/android/layout_tests/accessibility/secure-textfield-title-ui.html
-/sdcard/android/layout_tests/accessibility/canvas.html
-/sdcard/android/layout_tests/accessibility/textarea-selected-text-range.html
-/sdcard/android/layout_tests/accessibility/language-attribute.html
-/sdcard/android/layout_tests/accessibility/table-nofirstbody.html
-/sdcard/android/layout_tests/accessibility/editable-webarea-context-menu-point.html
-/sdcard/android/layout_tests/accessibility/table-modification-crash.html
-/sdcard/android/layout_tests/accessibility/aria-link-supports-press.html
-/sdcard/android/layout_tests/accessibility/table-notbody.html
-/sdcard/android/layout_tests/accessibility/ignore-spacer-elements.html
-/sdcard/android/layout_tests/accessibility/transformed-element.html
-/sdcard/android/layout_tests/accessibility/aria-disabled.html
-/sdcard/android/layout_tests/accessibility/placeholder.html
-/sdcard/android/layout_tests/accessibility/non-data-table-cell-title-ui-element.html
-/sdcard/android/layout_tests/accessibility/aria-label.html
-/sdcard/android/layout_tests/accessibility/textarea-line-for-index.html
-/sdcard/android/layout_tests/accessibility/nochildren-elements.html
-/sdcard/android/layout_tests/animations/keyframes-to-missing.html
-/sdcard/android/layout_tests/animations/animation-hit-test.html
-/sdcard/android/layout_tests/animations/animation-hit-test-transform.html
-/sdcard/android/layout_tests/animations/animation-controller-drt-api.html
-/sdcard/android/layout_tests/animations/keyframes-from-missing.html
-/sdcard/android/layout_tests/animations/change-keyframes-name.html
-/sdcard/android/layout_tests/animations/change-keyframes.html
-/sdcard/android/layout_tests/editing/style/remove-underline-from-stylesheet.html
-/sdcard/android/layout_tests/editing/style/remove-underline-in-bold.html
-/sdcard/android/layout_tests/editing/style/apply-through-end-of-document.html
-/sdcard/android/layout_tests/editing/inserting/typing-tab-designmode.html
-/sdcard/android/layout_tests/editing/inserting/space-after-removeformat.html
-/sdcard/android/layout_tests/editing/inserting/insert-thai-characters-001.html
-/sdcard/android/layout_tests/editing/inserting/5994480-2.html
-/sdcard/android/layout_tests/editing/execCommand/queryCommandState-01.html
-/sdcard/android/layout_tests/editing/execCommand/4128080-2.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-6.html
-/sdcard/android/layout_tests/editing/execCommand/enabling-and-selection.html
-/sdcard/android/layout_tests/editing/execCommand/insert-line-break-no-scroll.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-3.html
-/sdcard/android/layout_tests/editing/execCommand/enabling-and-selection-2.html
-/sdcard/android/layout_tests/editing/execCommand/delete-no-scroll.html
-/sdcard/android/layout_tests/editing/execCommand/forward-delete-no-scroll.html
-/sdcard/android/layout_tests/editing/execCommand/switch-list-type.html
-/sdcard/android/layout_tests/editing/execCommand/19089.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-nested-lists-2.html
-/sdcard/android/layout_tests/editing/execCommand/unlink.html
-/sdcard/android/layout_tests/editing/execCommand/remove-list-1.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-5.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-2.html
-/sdcard/android/layout_tests/editing/execCommand/copy-without-selection.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-nested-lists-4.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-nested-lists-1.html
-/sdcard/android/layout_tests/editing/execCommand/findString-diacriticals.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-7.html
-/sdcard/android/layout_tests/editing/execCommand/createLink.html
-/sdcard/android/layout_tests/editing/execCommand/remove-list-items.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-4.html
-/sdcard/android/layout_tests/editing/execCommand/5939887.html
-/sdcard/android/layout_tests/editing/execCommand/insertHTML.html
-/sdcard/android/layout_tests/editing/execCommand/convert-style-elements-to-spans.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-lists-1.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-nested-lists-3.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-into-anchor-text.html
-/sdcard/android/layout_tests/editing/pasteboard/19644-1.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-crash.html
-/sdcard/android/layout_tests/editing/pasteboard/5665299.html
-/sdcard/android/layout_tests/editing/pasteboard/file-input-files-access.html
-/sdcard/android/layout_tests/editing/pasteboard/get-data-text-plain-drop.html
-/sdcard/android/layout_tests/editing/pasteboard/get-data-text-plain-paste.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-before-blockquote.html
-/sdcard/android/layout_tests/editing/pasteboard/5761530-1.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-in-password-field.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-plaintext-user-select-none.html
-/sdcard/android/layout_tests/editing/pasteboard/drag-image-in-about-blank-frame.html
-/sdcard/android/layout_tests/editing/pasteboard/4744008.html
-/sdcard/android/layout_tests/editing/pasteboard/4922709.html
-/sdcard/android/layout_tests/editing/pasteboard/19644-2.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-013.html
-/sdcard/android/layout_tests/editing/pasteboard/5780697-2.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-double-nested-blockquote-before-blockquote.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-paste-float.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-table-002.html
-/sdcard/android/layout_tests/editing/selection/click-outside-editable-div.html
-/sdcard/android/layout_tests/editing/selection/drag-text-delay.html
-/sdcard/android/layout_tests/editing/selection/anchor-focus3.html
-/sdcard/android/layout_tests/editing/selection/home-end.html
-/sdcard/android/layout_tests/editing/selection/user-drag-element-and-user-select-none.html
-/sdcard/android/layout_tests/editing/selection/drag-start-event-client-x-y.html
-/sdcard/android/layout_tests/editing/selection/extend-selection-bidi.html
-/sdcard/android/layout_tests/editing/selection/find-in-text-control.html
-/sdcard/android/layout_tests/editing/selection/5209984.html
-/sdcard/android/layout_tests/editing/selection/toString-1.html
-/sdcard/android/layout_tests/editing/selection/hit-test-anonymous.html
-/sdcard/android/layout_tests/editing/selection/move-begin-end.html
-/sdcard/android/layout_tests/editing/selection/doubleclick-whitespace-img-crash.html
-/sdcard/android/layout_tests/editing/selection/click-after-nested-block.html
-/sdcard/android/layout_tests/editing/selection/move-by-line-003.html
-/sdcard/android/layout_tests/editing/selection/skip-non-editable-1.html
-/sdcard/android/layout_tests/editing/selection/anchor-focus1.html
-/sdcard/android/layout_tests/editing/selection/getRangeAt.html
-/sdcard/android/layout_tests/editing/selection/select-all-textarea.html
-/sdcard/android/layout_tests/editing/selection/doubleclick-whitespace.html
-/sdcard/android/layout_tests/editing/selection/move-paragraph-document-edges.html
-/sdcard/android/layout_tests/editing/selection/after-line-break.html
-/sdcard/android/layout_tests/editing/selection/legal-positions.html
-/sdcard/android/layout_tests/editing/selection/extend-selection-after-double-click.html
-/sdcard/android/layout_tests/editing/selection/select-line.html
-/sdcard/android/layout_tests/editing/selection/doubleclick-whitespace-crash.html
-/sdcard/android/layout_tests/editing/selection/toString.html
-/sdcard/android/layout_tests/editing/selection/inactive-selection.html
-/sdcard/android/layout_tests/editing/selection/click-in-margins-inside-editable-div.html
-/sdcard/android/layout_tests/editing/selection/removeAllRanges.html
-/sdcard/android/layout_tests/editing/selection/skip-non-editable-2.html
-/sdcard/android/layout_tests/editing/selection/anchor-focus2.html
-/sdcard/android/layout_tests/editing/selection/click-in-padding-with-multiple-line-boxes.html
-/sdcard/android/layout_tests/editing/selection/click-before-and-after-table.html
-/sdcard/android/layout_tests/editing/undo/undo-iframe-location-change.html
-/sdcard/android/layout_tests/editing/deleting/pruning-after-merge-1.html
-/sdcard/android/layout_tests/editing/deleting/5546763.html
-/sdcard/android/layout_tests/editing/deleting/5729680.html
-/sdcard/android/layout_tests/editing/deleting/4916235-1.html
-/sdcard/android/layout_tests/editing/deleting/delete-ligature-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-ligature-003.html
-/sdcard/android/layout_tests/editing/deleting/skip-virama-001.html
-/sdcard/android/layout_tests/editing/deleting/smart-editing-disabled.html
-/sdcard/android/layout_tests/editing/deleting/delete-ligature-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-all-text-in-text-field-assertion.html
-/sdcard/android/layout_tests/editing/text-iterator/basic-iteration.html
-/sdcard/android/layout_tests/editing/text-iterator/thai-cursor-movement.html
-/sdcard/android/layout_tests/fast/replaced/table-percent-height-text-controls.html
-/sdcard/android/layout_tests/fast/replaced/image-map-2.html
-/sdcard/android/layout_tests/fast/replaced/image-map-bug16782.html
-/sdcard/android/layout_tests/fast/replaced/table-percent-height.html
-/sdcard/android/layout_tests/fast/replaced/image-map.html
-/sdcard/android/layout_tests/fast/dynamic/paused-event-dispatch.html
-/sdcard/android/layout_tests/fast/text/international/thai-offsetForPosition-inside-character.html
-/sdcard/android/layout_tests/fast/text/plain-text-line-breaks.html
-/sdcard/android/layout_tests/fast/text/offsetForPosition-cluster-at-zero.html
-/sdcard/android/layout_tests/fast/text/zero-width-characters.html
-/sdcard/android/layout_tests/fast/text/reset-drag-on-mouse-down.html
-/sdcard/android/layout_tests/fast/encoding/invalid-xml.html
-/sdcard/android/layout_tests/fast/encoding/char-decoding-mac.html
-/sdcard/android/layout_tests/fast/encoding/mailto-always-utf-8.html
-/sdcard/android/layout_tests/fast/encoding/percent-escaping.html
-/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-nobom.xml
-/sdcard/android/layout_tests/fast/encoding/hanarei-blog32-fc2-com.html
-/sdcard/android/layout_tests/fast/encoding/frame-default-enc.html
-/sdcard/android/layout_tests/fast/encoding/char-decoding.html
-/sdcard/android/layout_tests/fast/encoding/url-host-name-non-ascii.html
-/sdcard/android/layout_tests/fast/encoding/idn-security.html
-/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-nobom.xml
-/sdcard/android/layout_tests/fast/encoding/char-encoding-mac.html
-/sdcard/android/layout_tests/fast/encoding/charset-koi8-u.html
-/sdcard/android/layout_tests/fast/workers/worker-location.html
-/sdcard/android/layout_tests/fast/selectors/lang-inheritance.html
-/sdcard/android/layout_tests/fast/selectors/lang-vs-xml-lang.html
-/sdcard/android/layout_tests/fast/selectors/lang-inheritance2.html
-/sdcard/android/layout_tests/fast/overflow/scroll-vertical-not-horizontal.html
-/sdcard/android/layout_tests/fast/events/onunload.html
-/sdcard/android/layout_tests/fast/events/mouseup-outside-document.html
-/sdcard/android/layout_tests/fast/events/offsetX-offsetY.html
-/sdcard/android/layout_tests/fast/events/mouseover-mouseout.html
-/sdcard/android/layout_tests/fast/events/option-tab.html
-/sdcard/android/layout_tests/fast/events/popup-blocking-click-in-iframe.html
-/sdcard/android/layout_tests/fast/events/tabindex-focus-blur-all.html
-/sdcard/android/layout_tests/fast/events/onchange-passwordfield.html
-/sdcard/android/layout_tests/fast/events/drag-in-frames.html
-/sdcard/android/layout_tests/fast/events/frame-tab-focus.html
-/sdcard/android/layout_tests/fast/events/autoscroll-in-textfield.html
-/sdcard/android/layout_tests/fast/events/arrow-navigation.html
-/sdcard/android/layout_tests/fast/events/fire-scroll-event.html
-/sdcard/android/layout_tests/fast/events/attempt-scroll-with-no-scrollbars.html
-/sdcard/android/layout_tests/fast/events/mouseclick-target-and-positioning.html
-/sdcard/android/layout_tests/fast/events/anchor-empty-focus.html
-/sdcard/android/layout_tests/fast/events/input-image-scrolled-x-y.html
-/sdcard/android/layout_tests/fast/events/dblclick-addEventListener.html
-/sdcard/android/layout_tests/fast/events/frame-programmatic-focus.html
-/sdcard/android/layout_tests/fast/events/related-target.html
-/sdcard/android/layout_tests/fast/events/context-onmousedown-event.html
-/sdcard/android/layout_tests/fast/events/mouse-drag-from-frame-to-other-frame.html
-/sdcard/android/layout_tests/fast/events/prevent-drag-to-navigate.html
-/sdcard/android/layout_tests/fast/events/stop-load-in-unload-handler-using-window-stop.html
-/sdcard/android/layout_tests/fast/events/content-changed-during-drop.html
-/sdcard/android/layout_tests/fast/events/autoscroll-with-non-scrollable-parent.html
-/sdcard/android/layout_tests/fast/events/window-events-capture.html
-/sdcard/android/layout_tests/fast/events/onchange-click-hang.html
-/sdcard/android/layout_tests/fast/events/onload-webkit-before-webcore.html
-/sdcard/android/layout_tests/fast/events/window-events-bubble2.html
-/sdcard/android/layout_tests/fast/events/js-keyboard-event-creation.html
-/sdcard/android/layout_tests/fast/events/event-view-toString.html
-/sdcard/android/layout_tests/fast/events/onchange-select-popup.html
-/sdcard/android/layout_tests/fast/events/access-key-self-destruct.html
-/sdcard/android/layout_tests/fast/events/scrollbar-double-click.html
-/sdcard/android/layout_tests/fast/events/onunload-clears-onbeforeunload.html
-/sdcard/android/layout_tests/fast/events/stop-load-in-unload-handler-using-document-write.html
-/sdcard/android/layout_tests/fast/events/tabindex-focus-chain.html
-/sdcard/android/layout_tests/fast/events/capture-on-target.html
-/sdcard/android/layout_tests/fast/events/window-events-bubble.html
-/sdcard/android/layout_tests/fast/events/event-function-toString.html
-/sdcard/android/layout_tests/fast/events/right-click-focus.html
-/sdcard/android/layout_tests/fast/events/mouseup-from-button2.html
-/sdcard/android/layout_tests/fast/events/frame-click-focus.html
-/sdcard/android/layout_tests/fast/events/crash-on-mutate-during-drop.html
-/sdcard/android/layout_tests/fast/events/mouseout-on-window.html
-/sdcard/android/layout_tests/fast/events/keypress-insert-tab.html
-/sdcard/android/layout_tests/fast/events/mouseout-dead-subframe.html
-/sdcard/android/layout_tests/fast/events/onunload-not-on-body.html
-/sdcard/android/layout_tests/fast/events/mousemove-after-drag-over-scrollbar.html
-/sdcard/android/layout_tests/fast/events/contextmenu-scrolled-page-with-frame.html
-/sdcard/android/layout_tests/fast/events/drag-to-navigate.html
-/sdcard/android/layout_tests/fast/events/key-events-in-input-button.html
-/sdcard/android/layout_tests/fast/events/arrow-keys-on-body.html
-/sdcard/android/layout_tests/fast/events/ondragenter.html
-/sdcard/android/layout_tests/fast/events/pointer-events.html
-/sdcard/android/layout_tests/fast/events/scroll-to-anchor-in-overflow-hidden.html
-/sdcard/android/layout_tests/fast/events/autoscroll-nonscrollable-iframe-in-scrollable-div.html
-/sdcard/android/layout_tests/fast/events/keypress-focus-change.html
-/sdcard/android/layout_tests/fast/events/key-events-in-input-text.html
-/sdcard/android/layout_tests/fast/events/pointer-events-2.html
-/sdcard/android/layout_tests/fast/events/drag-outside-window.html
-/sdcard/android/layout_tests/fast/events/click-count.html
-/sdcard/android/layout_tests/fast/events/onchange-searchfield.html
-/sdcard/android/layout_tests/fast/events/special-key-events-in-input-text.html
-/sdcard/android/layout_tests/fast/events/mouse-drag-from-frame.html
-/sdcard/android/layout_tests/fast/events/keydown-keypress-preventDefault.html
-/sdcard/android/layout_tests/fast/events/onsearch-enter.html
-/sdcard/android/layout_tests/fast/events/mouse-click-events.html
-/sdcard/android/layout_tests/fast/events/mouseover-mouseout2.html
-/sdcard/android/layout_tests/fast/events/open-window-from-another-frame.html
-/sdcard/android/layout_tests/fast/events/resize-subframe.html
-/sdcard/android/layout_tests/fast/events/onchange-textfield.html
-/sdcard/android/layout_tests/fast/events/onclick-list-marker.html
-/sdcard/android/layout_tests/fast/events/anchor-image-scrolled-x-y.html
-/sdcard/android/layout_tests/fast/images/image-map-zoom.html
-/sdcard/android/layout_tests/fast/js/kde/Number.html
-/sdcard/android/layout_tests/fast/js/instanceof-operator.html
-/sdcard/android/layout_tests/fast/js/navigator-mimeTypes-length.html
-/sdcard/android/layout_tests/fast/js/global-constructors.html
-/sdcard/android/layout_tests/fast/js/convert-nan-to-bool.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/hasFocus.html
-/sdcard/android/layout_tests/fast/dom/Document/early-document-access.html
-/sdcard/android/layout_tests/fast/dom/DOMException/XPathException.html
-/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/nested-execution.html
-/sdcard/android/layout_tests/fast/dom/HTMLDataGridElement/DataGridColumns-dom.html
-/sdcard/android/layout_tests/fast/dom/HTMLDataGridElement/DataGridColumns-basic.html
-/sdcard/android/layout_tests/fast/dom/HTMLDataGridElement/DataGridColumns-dom-attributes.html
-/sdcard/android/layout_tests/fast/dom/HTMLDataGridElement/DataGridDataSource-basic.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/010.xml
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/011.xml
-/sdcard/android/layout_tests/fast/dom/Window/window-xy-properties.html
-/sdcard/android/layout_tests/fast/dom/Window/window-screen-properties.html
-/sdcard/android/layout_tests/fast/dom/Window/new-window-opener.html
-/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-window.html
-/sdcard/android/layout_tests/fast/dom/Window/window-resize.html
-/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-window.html
-/sdcard/android/layout_tests/fast/dom/Window/Plug-ins.html
-/sdcard/android/layout_tests/fast/dom/Window/get-set-properties.html
-/sdcard/android/layout_tests/fast/dom/Window/window-scroll-arguments.html
-/sdcard/android/layout_tests/fast/dom/Window/window-lookup-precedence.html
-/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-arguments.html
-/sdcard/android/layout_tests/fast/dom/Window/custom-constructors.html
-/sdcard/android/layout_tests/fast/dom/Window/webkitConvertPoint.html
-/sdcard/android/layout_tests/fast/dom/Window/window-properties.html
-/sdcard/android/layout_tests/fast/dom/Window/window-onFocus.html
-/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-iframe.html
-/sdcard/android/layout_tests/fast/dom/Window/window-early-properties.html
-/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime-2.html
-/sdcard/android/layout_tests/fast/dom/dom-constructors.html
-/sdcard/android/layout_tests/fast/dom/assign-to-window-status.html
-/sdcard/android/layout_tests/fast/dom/navigator-detached-no-crash.html
-/sdcard/android/layout_tests/fast/dom/object-embed-plugin-scripting.html
-/sdcard/android/layout_tests/fast/dom/node-filter-gc.html
-/sdcard/android/layout_tests/fast/dom/noscript-canvas-in-created-html-document.html
-/sdcard/android/layout_tests/fast/dom/getClientRects.html
-/sdcard/android/layout_tests/fast/dom/null-document-location-href-put-crash.html
-/sdcard/android/layout_tests/fast/dom/prototype-inheritance-2.html
-/sdcard/android/layout_tests/fast/dom/location-new-window-no-crash.html
-/sdcard/android/layout_tests/fast/dom/gc-9.html
-/sdcard/android/layout_tests/fast/dom/wrapper-classes.html
-/sdcard/android/layout_tests/fast/dom/document-width-height-force-layout.html
-/sdcard/android/layout_tests/fast/dom/client-width-height.html
-/sdcard/android/layout_tests/fast/dom/constructed-objects-prototypes.html
-/sdcard/android/layout_tests/fast/dom/global-constructors.html
-/sdcard/android/layout_tests/fast/dom/client-width-height-quirks.html
-/sdcard/android/layout_tests/fast/dom/javascript-url-crash-function.html
-/sdcard/android/layout_tests/fast/dom/getBoundingClientRect.html
-/sdcard/android/layout_tests/fast/dom/location-hash.html
-/sdcard/android/layout_tests/fast/dom/documenturi-can-hold-arbitrary-string.html
-/sdcard/android/layout_tests/fast/dom/documenturi-not-affected-by-base-tag.html
-/sdcard/android/layout_tests/fast/dom/open-and-close-by-DOM.html
-/sdcard/android/layout_tests/fast/dom/set-frame-src-while-running-script-in-frame.html
-/sdcard/android/layout_tests/fast/dom/prototype-inheritance.html
-/sdcard/android/layout_tests/fast/dom/getBoundingClientRect-getClientRects-relative-to-viewport.html
-/sdcard/android/layout_tests/fast/dom/frame-loading-via-document-write.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/paths.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/expressions.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/predicates.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/abbreviations.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/axes.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/functions.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/nodetests.html
-/sdcard/android/layout_tests/fast/xpath/py-dom-xpath/data.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Borrowed/od_20000608.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Borrowed/namespace-nodes.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Borrowed/rs_20010831.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Borrowed/sr_20021217.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Borrowed/kd_20010423.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Borrowed/cz_20030217.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_boolean_expr.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_core_functions.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_location_path.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_node_test.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_literal_expr.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_predicate_list.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_parser.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_nodeset_expr.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_numeric_expr.html
-/sdcard/android/layout_tests/fast/xpath/4XPath/Core/test_step.html
-/sdcard/android/layout_tests/fast/xpath/detached-subtree-invalidate-iterator.html
-/sdcard/android/layout_tests/fast/xpath/ancestor-axis.html
-/sdcard/android/layout_tests/fast/xpath/string-value.html
-/sdcard/android/layout_tests/fast/xpath/id-simple.html
-/sdcard/android/layout_tests/fast/xpath/id-path.html
-/sdcard/android/layout_tests/fast/xpath/invalid-functions.html
-/sdcard/android/layout_tests/fast/xpath/xpath-namespaces.html
-/sdcard/android/layout_tests/fast/xpath/node-name-case-sensitivity.html
-/sdcard/android/layout_tests/fast/xpath/xpath-empty-string.html
-/sdcard/android/layout_tests/fast/xpath/attribute-node-predicate.html
-/sdcard/android/layout_tests/fast/xpath/nodeset-duplicates.html
-/sdcard/android/layout_tests/fast/xpath/name-null-namespace.html
-/sdcard/android/layout_tests/fast/xpath/implicit-node-args.html
-/sdcard/android/layout_tests/fast/xpath/text-nodes.html
-/sdcard/android/layout_tests/fast/xpath/complex-id.html
-/sdcard/android/layout_tests/fast/xpath/xpath-functional-test.html
-/sdcard/android/layout_tests/fast/xpath/attr-namespace.html
-/sdcard/android/layout_tests/fast/xpath/position.html
-/sdcard/android/layout_tests/fast/xpath/evaluate-twice.html
-/sdcard/android/layout_tests/fast/xpath/substring-after.html
-/sdcard/android/layout_tests/fast/xpath/empty-string-substring.html
-/sdcard/android/layout_tests/fast/xpath/document-order.html
-/sdcard/android/layout_tests/fast/xpath/reverse-axes.html
-/sdcard/android/layout_tests/fast/xpath/nan-to-boolean.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain.html
-/sdcard/android/layout_tests/fast/forms/mailto/advanced-get.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain-latin-1.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-multipart-form-data.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-always-utf-8.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-append-query.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-x-www-form-urlencoded.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-overwrite-query.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-x-www-form-urlencoded.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-text-plain.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-text-plain.html
-/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain-with-accept-charset.html
-/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain.html
-/sdcard/android/layout_tests/fast/forms/mailto/advanced-put.html
-/sdcard/android/layout_tests/fast/forms/listbox-typeahead-scroll.html
-/sdcard/android/layout_tests/fast/forms/select-empty-list.html
-/sdcard/android/layout_tests/fast/forms/focus2.html
-/sdcard/android/layout_tests/fast/forms/legend-access-key.html
-/sdcard/android/layout_tests/fast/forms/focus-selection-textarea.html
-/sdcard/android/layout_tests/fast/forms/select-popup-pagekeys.html
-/sdcard/android/layout_tests/fast/forms/select-double-onchange.html
-/sdcard/android/layout_tests/fast/forms/button-enter-click.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-003.html
-/sdcard/android/layout_tests/fast/forms/search-click-in-placeholder.html
-/sdcard/android/layout_tests/fast/forms/onselect-textfield.html
-/sdcard/android/layout_tests/fast/forms/textfield-onchange-deletion.html
-/sdcard/android/layout_tests/fast/forms/listbox-onchange.html
-/sdcard/android/layout_tests/fast/forms/button-spacebar-click.html
-/sdcard/android/layout_tests/fast/forms/search-cancel-button-mouseup.html
-/sdcard/android/layout_tests/fast/forms/get-file-upload.html
-/sdcard/android/layout_tests/fast/forms/select-enter-key.html
-/sdcard/android/layout_tests/fast/forms/drag-out-of-textarea.html
-/sdcard/android/layout_tests/fast/forms/option-mouseevents.html
-/sdcard/android/layout_tests/fast/forms/input-radio-checked-tab.html
-/sdcard/android/layout_tests/fast/forms/plaintext-mode-1.html
-/sdcard/android/layout_tests/fast/forms/input-select-on-click.html
-/sdcard/android/layout_tests/fast/forms/textarea-scrolled-endline-caret.html
-/sdcard/android/layout_tests/fast/forms/textarea-scrollbar-height.html
-/sdcard/android/layout_tests/fast/forms/textarea-type-spaces.html
-/sdcard/android/layout_tests/fast/forms/slider-mouse-events.html
-/sdcard/android/layout_tests/fast/forms/slider-onchange-event.html
-/sdcard/android/layout_tests/fast/forms/textarea-input-event.html
-/sdcard/android/layout_tests/fast/forms/search-delete-while-cancel-button-clicked.html
-/sdcard/android/layout_tests/fast/forms/select-accesskey.html
-/sdcard/android/layout_tests/fast/forms/password-doubleclick-selection.html
-/sdcard/android/layout_tests/fast/forms/textfield-inside-anchor.html
-/sdcard/android/layout_tests/fast/forms/slider-delete-while-dragging-thumb.html
-/sdcard/android/layout_tests/fast/forms/textfield-to-password-on-focus.html
-/sdcard/android/layout_tests/fast/forms/textarea-arrow-navigation.html
-/sdcard/android/layout_tests/fast/forms/search-abs-pos-cancel-button.html
-/sdcard/android/layout_tests/fast/forms/enter-clicks-buttons.html
-/sdcard/android/layout_tests/fast/forms/radio_checked_name.html
-/sdcard/android/layout_tests/fast/forms/search-hidden-cancel-button.html
-/sdcard/android/layout_tests/fast/forms/select-script-onchange.html
-/sdcard/android/layout_tests/fast/forms/textarea-paste-newline.html
-/sdcard/android/layout_tests/fast/forms/drag-into-textarea.html
-/sdcard/android/layout_tests/fast/forms/form-and-frame-interaction-retains-values.html
-/sdcard/android/layout_tests/fast/forms/slider-transformed.html
-/sdcard/android/layout_tests/fast/forms/focus-control-to-page.html
-/sdcard/android/layout_tests/fast/forms/select-type-ahead-non-latin.html
-/sdcard/android/layout_tests/fast/forms/focus-selection-input.html
-/sdcard/android/layout_tests/fast/forms/slider-zoomed.html
-/sdcard/android/layout_tests/fast/forms/search-event-delay.html
-/sdcard/android/layout_tests/fast/forms/empty-textarea-toggle-disabled.html
-/sdcard/android/layout_tests/fast/forms/25153.html
-/sdcard/android/layout_tests/fast/forms/select-cache-desynchronization.html
-/sdcard/android/layout_tests/fast/forms/check-box-enter-key.html
-/sdcard/android/layout_tests/fast/forms/button-state-restore.html
-/sdcard/android/layout_tests/fast/forms/access-key.html
-/sdcard/android/layout_tests/fast/forms/textarea-selection-preservation.html
-/sdcard/android/layout_tests/fast/forms/textarea-metrics.html
-/sdcard/android/layout_tests/fast/forms/onchange-enter-submit.html
-/sdcard/android/layout_tests/fast/forms/onselect-textarea.html
-/sdcard/android/layout_tests/fast/forms/listbox-selection.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/computed-style.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/computed-style-without-renderer.html
-/sdcard/android/layout_tests/fast/css/text-align.html
-/sdcard/android/layout_tests/fast/css/hover-affects-child.html
-/sdcard/android/layout_tests/fast/css/resize-single-axis.html
-/sdcard/android/layout_tests/fast/css/percent-character-as-value.html
-/sdcard/android/layout_tests/fast/css/uri-token-parsing.html
-/sdcard/android/layout_tests/fast/css/zoom-body-scroll.html
-/sdcard/android/layout_tests/fast/css/invalid-percentage-property.html
-/sdcard/android/layout_tests/fast/parser/external-entities-in-xslt.xml
-/sdcard/android/layout_tests/fast/parser/xml-declaration-missing-ending-mark.html
-/sdcard/android/layout_tests/fast/parser/tabindex-parsing.html
-/sdcard/android/layout_tests/fast/history/saves-state-after-fragment-nav.html
-/sdcard/android/layout_tests/fast/history/back-forward-is-asynchronous.html
-/sdcard/android/layout_tests/fast/history/window-open.html
-/sdcard/android/layout_tests/fast/history/history_reload.html
-/sdcard/android/layout_tests/fast/history/go-back-to-changed-name.html
-/sdcard/android/layout_tests/fast/loader/cancel-load-during-port-block-timer.html
-/sdcard/android/layout_tests/fast/loader/local-iFrame-source-from-local.html
-/sdcard/android/layout_tests/fast/loader/null-request-after-willSendRequest.html
-/sdcard/android/layout_tests/fast/loader/stop-provisional-loads.html
-/sdcard/android/layout_tests/fast/loader/location-port.html
-/sdcard/android/layout_tests/fast/loader/user-style-sheet-resource-load-callbacks.html
-/sdcard/android/layout_tests/fast/loader/policy-delegate-action-hit-test-zoomed.html
-/sdcard/android/layout_tests/fast/loader/subframe-navigate-during-main-frame-load.html
-/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash-2.html
-/sdcard/android/layout_tests/fast/loader/javascript-url-hierarchical-execution.html
-/sdcard/android/layout_tests/fast/loader/plain-text-document.html
-/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash.html
-/sdcard/android/layout_tests/fast/loader/subframe-self-close.html
-/sdcard/android/layout_tests/fast/loader/local-image-from-local.html
-/sdcard/android/layout_tests/fast/loader/local-CSS-from-local.html
-/sdcard/android/layout_tests/fast/loader/reload-policy-delegate.html
-/sdcard/android/layout_tests/fast/loader/local-JavaScript-from-local.html
-/sdcard/android/layout_tests/fast/loader/main-document-url-for-non-http-loads.html
-/sdcard/android/layout_tests/fast/loader/data-url-encoding-svg.html
-/sdcard/android/layout_tests/fast/loader/data-url-encoding-html.html
-/sdcard/android/layout_tests/fast/loader/opaque-base-url.html
-/sdcard/android/layout_tests/fast/xsl/sort-locale.xml
-/sdcard/android/layout_tests/fast/xsl/transformToFragment-XML-declaration.html
-/sdcard/android/layout_tests/fast/xsl/extra-lf-at-end.html
-/sdcard/android/layout_tests/fast/xsl/xslt-doc-noenc.xml
-/sdcard/android/layout_tests/fast/xsl/import-after-comment.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-processor.html
-/sdcard/android/layout_tests/fast/xsl/sort-unicode.xml
-/sdcard/android/layout_tests/fast/xsl/default-html.html
-/sdcard/android/layout_tests/fast/xsl/nbsp-in-stylesheet.html
-/sdcard/android/layout_tests/fast/xsl/xslt-string-parameters.html
-/sdcard/android/layout_tests/fast/xsl/xslt-entity-enc.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-text.html
-/sdcard/android/layout_tests/fast/xsl/xslt-nested-stylesheets.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-url.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-doc-enc.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-recursion.xml
-/sdcard/android/layout_tests/fast/xsl/exslt-node-set.xml
-/sdcard/android/layout_tests/fast/xsl/subframe-location.html
-/sdcard/android/layout_tests/fast/xsl/xslt-second-level-import.xml
-/sdcard/android/layout_tests/fast/xsl/dtd-in-source-document.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-fragment-in-empty-doc.html
-/sdcard/android/layout_tests/fast/xsl/mozilla-tests.xml
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-bad-mimetype.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-gc.html
-/sdcard/android/layout_tests/fast/canvas/canvas-alphaImageData-behavior.html
-/sdcard/android/layout_tests/fast/canvas/canvas-gradient-addStop-error.html
-/sdcard/android/layout_tests/fast/canvas/canvas-pattern-behaviour.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transform-non-invertible.html
-/sdcard/android/layout_tests/fast/canvas/pointInPath.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transform-infinity.html
-/sdcard/android/layout_tests/fast/canvas/translate-text.html
-/sdcard/android/layout_tests/fast/canvas/toDataURL-supportedTypes.html
-/sdcard/android/layout_tests/fast/canvas/canvas-getImageData.html
-/sdcard/android/layout_tests/fast/canvas/canvas-empty-image-pattern.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transform-skewed.html
-/sdcard/android/layout_tests/fast/canvas/canvas-ImageData-behaviour.html
-/sdcard/android/layout_tests/fast/canvas/canvas-putImageData.html
-/sdcard/android/layout_tests/fast/canvas/canvas-pattern-modify.html
-/sdcard/android/layout_tests/fast/canvas/canvas-longlived-context.html
-/sdcard/android/layout_tests/fast/canvas/canvas-save-restore-with-path.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transform-nan.html
-/sdcard/android/layout_tests/fast/canvas/canvas-pattern-transform.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transform-identity.html
-/sdcard/android/layout_tests/fast/canvas/set-colors.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transform-multiply.html
-/sdcard/android/layout_tests/fast/frames/viewsource-empty-attribute-value.html
-/sdcard/android/layout_tests/fast/frames/location-put-after-removal.html
-/sdcard/android/layout_tests/fast/frames/frame-deep-nested-resize.html
-/sdcard/android/layout_tests/fast/frames/iframe-window-focus.html
-/sdcard/android/layout_tests/fast/frames/frame-dead-region.html
-/sdcard/android/layout_tests/fast/frames/frameElement-widthheight.html
-/sdcard/android/layout_tests/fast/frames/removal-before-attach-crash.html
-/sdcard/android/layout_tests/fast/frames/frame-unload-crash.html
-/sdcard/android/layout_tests/fast/frames/frame-js-url-clientWidth.html
-/sdcard/android/layout_tests/fast/frames/iframe-js-url-clientWidth.html
-/sdcard/android/layout_tests/fast/frames/frame-length-fractional.html
-/sdcard/android/layout_tests/fast/frames/iframe-name-and-id.html
-/sdcard/android/layout_tests/fast/loading/subframe-removes-itself.html
-/sdcard/android/layout_tests/http/tests/media/video-seekable-stall.html
-/sdcard/android/layout_tests/http/tests/media/remove-while-loading.html
-/sdcard/android/layout_tests/http/tests/media/video-play-stall.html
-/sdcard/android/layout_tests/http/tests/media/video-play-stall-seek.html
-/sdcard/android/layout_tests/http/tests/plugins/npapi-response-headers.html
-/sdcard/android/layout_tests/http/tests/plugins/get-url.html
-/sdcard/android/layout_tests/http/tests/plugins/interrupted-get-url.html
-/sdcard/android/layout_tests/http/tests/plugins/post-url-file.html
-/sdcard/android/layout_tests/http/tests/plugins/cross-frame-object-access.html
-/sdcard/android/layout_tests/http/tests/plugins/local-geturl-from-remote.html
-/sdcard/android/layout_tests/http/tests/plugins/geturlnotify-from-npp-destroystream.html
-/sdcard/android/layout_tests/http/tests/mime/standard-mode-does-not-load-stylesheet-with-text-plain-and-css-extension.html
-/sdcard/android/layout_tests/http/tests/mime/standard-mode-does-not-load-stylesheet-with-text-plain.html
-/sdcard/android/layout_tests/http/tests/local/drag-over-remote-content.html
-/sdcard/android/layout_tests/http/tests/misc/image-blocked-src-change.html
-/sdcard/android/layout_tests/http/tests/misc/acid3.html
-/sdcard/android/layout_tests/http/tests/misc/dns-prefetch-control.html
-/sdcard/android/layout_tests/http/tests/misc/will-send-request-returns-null-on-redirect.html
-/sdcard/android/layout_tests/http/tests/misc/isindex-formdata.html
-/sdcard/android/layout_tests/http/tests/misc/image-blocked-src-no-change.html
-/sdcard/android/layout_tests/http/tests/misc/policy-delegate-called-twice.html
-/sdcard/android/layout_tests/http/tests/misc/window-dot-stop.html
-/sdcard/android/layout_tests/http/tests/misc/css-reject-any-type-in-strict-mode.html
-/sdcard/android/layout_tests/http/tests/misc/favicon-loads-with-images-disabled.html
-/sdcard/android/layout_tests/http/tests/misc/SVGFont-delayed-load.html
-/sdcard/android/layout_tests/http/tests/misc/location-test-xsl-style-sheet.xml
-/sdcard/android/layout_tests/http/tests/misc/redirect-to-external-url.html
-/sdcard/android/layout_tests/http/tests/misc/submit-get-in-utf7.html
-/sdcard/android/layout_tests/http/tests/cookies/simple-cookies-max-age.html
-/sdcard/android/layout_tests/http/tests/cookies/simple-cookies-expired.html
-/sdcard/android/layout_tests/http/tests/cookies/multiple-cookies.html
-/sdcard/android/layout_tests/http/tests/wml/access-target-path-deny.html
-/sdcard/android/layout_tests/http/tests/wml/post-data-to-server.html
-/sdcard/android/layout_tests/http/tests/wml/go-task-get-method-accept-charset.html
-/sdcard/android/layout_tests/http/tests/wml/access-target.html
-/sdcard/android/layout_tests/http/tests/wml/access-target-domain-deny.html
-/sdcard/android/layout_tests/http/tests/wml/go-task-post-method-accept-charset.html
-/sdcard/android/layout_tests/http/tests/wml/go-task-get-method.html
-/sdcard/android/layout_tests/http/tests/wml/go-task-post-method.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-reload.html
-/sdcard/android/layout_tests/http/tests/navigation/redirect-cycle.html
-/sdcard/android/layout_tests/http/tests/navigation/reload-subframe-frame.html
-/sdcard/android/layout_tests/http/tests/navigation/window-open-adds-history-item.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/timerredirect-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/lockedhistory-iframe.html
-/sdcard/android/layout_tests/http/tests/navigation/document-location-click-timeout.html
-/sdcard/android/layout_tests/http/tests/navigation/post-goback2.html
-/sdcard/android/layout_tests/http/tests/navigation/onload-navigation-iframe-timeout.html
-/sdcard/android/layout_tests/http/tests/navigation/location-assign-adds-history-item.html
-/sdcard/android/layout_tests/http/tests/navigation/anchor-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/redirect-load-no-form-restoration.html
-/sdcard/android/layout_tests/http/tests/navigation/metaredirect-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/javascriptlink-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/metaredirect-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/post-goback-same-url.html
-/sdcard/android/layout_tests/http/tests/navigation/restore-form-state-https.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/redirect302-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/document-location-mouseover.html
-/sdcard/android/layout_tests/http/tests/navigation/redirect302-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/anchor-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/target-frame-from-window.html
-/sdcard/android/layout_tests/http/tests/navigation/slowmetaredirect-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/reload-subframe-iframe.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-loadsame.html
-/sdcard/android/layout_tests/http/tests/navigation/relativeanchor-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/redirect302-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/relativeanchor-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/metaredirect-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/redirect302-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/multiple-back-forward-entries.html
-/sdcard/android/layout_tests/http/tests/navigation/javascriptlink-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/postredirect-goback2.html
-/sdcard/android/layout_tests/http/tests/navigation/timerredirect-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/location-href-set-adds-history-item.html
-/sdcard/android/layout_tests/http/tests/navigation/anchor-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/document-location-click.html
-/sdcard/android/layout_tests/http/tests/navigation/onload-navigation-iframe.html
-/sdcard/android/layout_tests/http/tests/navigation/relativeanchor-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/metaredirect-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/location-replace-adds-history-item.html
-/sdcard/android/layout_tests/http/tests/navigation/success200-frames-loadsame.html
-/sdcard/android/layout_tests/http/tests/navigation/back-to-slow-frame.html
-/sdcard/android/layout_tests/http/tests/navigation/new-window-redirect-history.html
-/sdcard/android/layout_tests/http/tests/navigation/javascriptlink-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/timerredirect-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/location-set-adds-history-item.html
-/sdcard/android/layout_tests/http/tests/navigation/onload-navigation-iframe-2.html
-/sdcard/android/layout_tests/http/tests/navigation/reload-subframe-object.html
-/sdcard/android/layout_tests/http/tests/navigation/timerredirect-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/slowtimerredirect-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/window-open-adds-history-item2.html
-/sdcard/android/layout_tests/http/tests/navigation/document-location-onload.html
-/sdcard/android/layout_tests/http/tests/history/redirect-meta-refresh-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-assign-before-load.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-href-0-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-href-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-form-submit-0-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-form-submit-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-0-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-href-before-load.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-replace-0-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-replace-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-document-location-0-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-document-location-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-form-submit-before-load.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-assign-0-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-assign-2-seconds.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-before-load.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-location-replace-before-load.html
-/sdcard/android/layout_tests/http/tests/history/redirect-js-document-location-before-load.html
-/sdcard/android/layout_tests/http/tests/history/redirect-meta-refresh-0-seconds.html
-/sdcard/android/layout_tests/http/tests/cache/subresource-expiration.html
-/sdcard/android/layout_tests/http/tests/appcache/local-content.html
-/sdcard/android/layout_tests/http/tests/appcache/max-size.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/xss-DENIED-set-opener.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/xss-DENIED-navigate-opener-javascript-url.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/xss-DENIED-navigate-opener-document-write.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-javascript-url-window-open.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-sub-frame-2-level.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-data-url-in-foreign-domain-subframe.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-data-url-in-foreign-domain-window-open.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-in-foreign-domain-subframe-location-change.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-data-url-sub-frame.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-in-foreign-domain-subframe.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-in-foreign-domain-window-open.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-data-url-sub-frame-2-level.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-sub-frame-uppercase.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-window-open.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-data-url-sub-frame-to-data-url-sub-frame.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-from-data-url-to-data-url.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-from-data-url.html
-/sdcard/android/layout_tests/http/tests/security/dataURL/xss-DENIED-to-data-url-sub-frame.html
-/sdcard/android/layout_tests/http/tests/security/clipboard/clipboard-file-access.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/image-prototype.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/body-properties.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/number-prototype.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/body-prototype.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/global-variables.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/location-prototype.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/image-properties.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/document-open.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/document-prototype.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/window-properties.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/location-properties.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/all-window-prototypes.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/click-event.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/all-window-properties.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/document-properties.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/string-prototype.html
-/sdcard/android/layout_tests/http/tests/security/isolatedWorld/object-prototype.html
-/sdcard/android/layout_tests/http/tests/security/listener/xss-window-onclick-addEventListener.html
-/sdcard/android/layout_tests/http/tests/security/listener/xss-window-onclick-shortcut.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-parent-same-origin-allow.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-parent-same-origin-deny.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-in-body.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-allow.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny.html
-/sdcard/android/layout_tests/http/tests/security/XFrameOptions/x-frame-options-deny.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/xss-ALLOWED-targeted-subframe-navigation-change.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/xss-DENIED-targeted-link-navigation.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNode.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNodeNS.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttribute.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNS.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNode.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNodeNS.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame-2-level.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-to-javscript-url.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-from-javscript-url.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-getAttribute-value.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-htmldom.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-sub-frame-2-level.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-window-open.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-DENIED-from-javascript-url-in-foreign-domain-window-open.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-location-htmldom.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-getAttribute-value.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame-to-javascript-url-sub-frame.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-DENIED-to-javascript-url-in-foreign-domain-subframe.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-window-open.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-htmldom.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-DENIED-to-javascript-url-in-foreign-domain-window-open.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-sub-frame.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttribute.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNS.html
-/sdcard/android/layout_tests/http/tests/security/javascriptURL/xss-DENIED-from-javascript-url-in-foreign-domain-subframe.html
-/sdcard/android/layout_tests/http/tests/security/originHeader/origin-header-for-empty.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/faux-script1.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-convoluted.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/dom-write-location.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-HTML-entities-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/object-embed-tag-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/anchor-url-dom-write-location.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/link-onclick-ampersand.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source-double-quote.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source-no-quote.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href-safe3.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/http-equiv-utf-7-encoded.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/link-onclick-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href-scheme-relative.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-open-redirect.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/object-embed-tag-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/faux-script3.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/link-onclick-entities.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-post.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/embed-tag-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/property-escape.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-post-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-HTML-entities.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-addslashes-single-quote.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/dom-write-innerHTML.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source-entities.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/dom-write-location-inline-event.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/malformed-HTML.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-ampersand.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/link-onclick.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/anchor-url-dom-write-location-inline-event.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href-safe2.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/anchor-url-dom-write-location-inline-event-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/dom-write-URL.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-redirect.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/object-tag.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-addslashes-backslash.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/dom-write-location-javascript-URL.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/embed-tag.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/faux-script2.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/anchor-url-dom-write-location-javascript-URL.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source-relative-scheme.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/img-onerror-tricky.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-HTML-entities-named.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link-HTML-entities-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-addslashes-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/link-opens-new-window.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-utf-7-encoded.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-utf-7.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-addslashes-double-quote.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-safe.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/link-onclick-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/javascript-link.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source-null-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/iframe-javascript-url.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-src-redirect-safe.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-with-source-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/get-from-iframe.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/inline-event-HTML-entities.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/post-from-iframe.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-post-control-char.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/object-embed-tag.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/script-tag-entities.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/base-href-safe.html
-/sdcard/android/layout_tests/http/tests/security/xssAuditor/embed-tag-null-char.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-location-get-override.html
-/sdcard/android/layout_tests/http/tests/security/protocol-compare-case-insensitive.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-xsl-external-entity.xml
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-history-get-override.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-get-override.html
-/sdcard/android/layout_tests/http/tests/security/cross-origin-xsl-BLOCKED.html
-/sdcard/android/layout_tests/http/tests/security/local-iFrame-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/credentials-in-referer.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-xsl-external-entity-redirect.xml
-/sdcard/android/layout_tests/http/tests/security/local-video-poster-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/local-CSS-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/local-user-CSS-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-object-prototype.html
-/sdcard/android/layout_tests/http/tests/security/dataTransfer-set-data-file-url.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-enumeration.html
-/sdcard/android/layout_tests/http/tests/security/host-compare-case-insensitive.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-xsl-document.xml
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-protocol.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-private-browsing.html
-/sdcard/android/layout_tests/http/tests/security/feed-urls-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-put.html
-/sdcard/android/layout_tests/http/tests/security/canvas-remote-read-svg-image.html
-/sdcard/android/layout_tests/http/tests/security/window-properties-clear-domain.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-callback-explicit-domain-DENY.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-get.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-port.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-document-direct.html
-/sdcard/android/layout_tests/http/tests/security/window-properties-pass.html
-/sdcard/android/layout_tests/http/tests/security/local-video-src-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-history-put.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-child-explicit-domain.html
-/sdcard/android/layout_tests/http/tests/security/local-video-source-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/drag-over-remote-content-iframe.html
-/sdcard/android/layout_tests/http/tests/security/local-JavaScript-from-remote.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-parent-explicit-domain.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-location-put.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-history-get.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-get-custom-property-cached.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-location-get.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-delete.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-xsl-document-redirect.xml
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-protocol-explicit-domain.html
-/sdcard/android/layout_tests/http/tests/security/window-properties-clear-port.html
-/sdcard/android/layout_tests/http/tests/security/frame-loading-via-document-write.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-port-explicit-domain.html
-/sdcard/android/layout_tests/http/tests/security/local-image-from-remote.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/workers/methods-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/workers/methods.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/008.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/methods-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/methods.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-005.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/upload-onload-event.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/small-chunks-response-text.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-non-simple-allow-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-009.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/frame-unload-abort-crash.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-non-simple-deny-cached.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-006.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/upload-onprogress-event.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cache-override.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xhr-onunload.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/methods-lower-case.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-007.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/svg-created-by-xhr-disallowed-in-dashboard.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-004.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-missing-file-exception.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cookies.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-010.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin-tripmine.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-same-origin-get-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/response-encoding.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/frame-load-cancelled-abort.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/upload-progress-events.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xml-encoding.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/default-content-type-dashboard.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/abort-should-cancel-load.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-whitelist-request-headers.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/uri-resolution-opera-open-008.html
-/sdcard/android/layout_tests/http/tests/loading/preload-img-test.html
-/sdcard/android/layout_tests/http/tests/loading/gmail-assert-on-load.html
-/sdcard/android/layout_tests/http/tests/loading/text-content-type-with-binary-extension.html
-/sdcard/android/layout_tests/http/tests/loading/basic.html
-/sdcard/android/layout_tests/http/tests/loading/slow-parsing-subframe.html
-/sdcard/android/layout_tests/http/tests/loading/deleted-host-in-resource-load-delegate-callback.html
-/sdcard/android/layout_tests/http/tests/loading/bad-scheme-subframe.html
-/sdcard/android/layout_tests/http/tests/loading/location-hash-reload-cycle.html
-/sdcard/android/layout_tests/http/tests/loading/bad-server-subframe.html
-/sdcard/android/layout_tests/http/tests/loading/empty-subframe.html
-/sdcard/android/layout_tests/http/tests/loading/redirect-methods.html
-/sdcard/android/layout_tests/media/video-error-does-not-exist.html
-/sdcard/android/layout_tests/media/audio-constructor.html
-/sdcard/android/layout_tests/media/video-play-empty-events.html
-/sdcard/android/layout_tests/media/video-append-source.html
-/sdcard/android/layout_tests/media/media-load-event.html
-/sdcard/android/layout_tests/media/unsupported-rtsp.html
-/sdcard/android/layout_tests/media/video-dom-autoplay.html
-/sdcard/android/layout_tests/media/video-currentTime-set2.html
-/sdcard/android/layout_tests/media/video-muted.html
-/sdcard/android/layout_tests/media/progress-event.html
-/sdcard/android/layout_tests/media/video-source-type.html
-/sdcard/android/layout_tests/media/audio-delete-while-step-button-clicked.html
-/sdcard/android/layout_tests/media/video-played-reset.html
-/sdcard/android/layout_tests/media/video-seek-past-end-playing.html
-/sdcard/android/layout_tests/media/video-dom-src.html
-/sdcard/android/layout_tests/media/remove-from-document.html
-/sdcard/android/layout_tests/media/video-loop.html
-/sdcard/android/layout_tests/media/video-src-change.html
-/sdcard/android/layout_tests/media/video-seekable.html
-/sdcard/android/layout_tests/media/video-played.html
-/sdcard/android/layout_tests/media/video-played-collapse.html
-/sdcard/android/layout_tests/media/video-click-dblckick-standalone.html
-/sdcard/android/layout_tests/media/video-can-play-type.html
-/sdcard/android/layout_tests/media/video-seeking.html
-/sdcard/android/layout_tests/media/video-controls-transformed.html
-/sdcard/android/layout_tests/media/video-controls-zoomed.html
-/sdcard/android/layout_tests/media/video-src-invalid-remove.html
-/sdcard/android/layout_tests/media/video-volume.html
-/sdcard/android/layout_tests/media/video-size.html
-/sdcard/android/layout_tests/media/controls-right-click-on-timebar.html
-/sdcard/android/layout_tests/media/video-currentTime.html
-/sdcard/android/layout_tests/media/audio-constructor-autobuffer.html
-/sdcard/android/layout_tests/media/broken-video.html
-/sdcard/android/layout_tests/media/video-buffered.html
-/sdcard/android/layout_tests/media/video-load-readyState.html
-/sdcard/android/layout_tests/media/video-load-networkState.html
-/sdcard/android/layout_tests/media/unsupported-tracks.html
-/sdcard/android/layout_tests/media/video-source-add-src.html
-/sdcard/android/layout_tests/media/video-seek-past-end-paused.html
-/sdcard/android/layout_tests/media/media-startTime.html
-/sdcard/android/layout_tests/media/video-source-error.html
-/sdcard/android/layout_tests/media/video-autoplay.html
-/sdcard/android/layout_tests/media/video-controls.html
-/sdcard/android/layout_tests/media/video-canvas-source.html
-/sdcard/android/layout_tests/media/video-timeupdate-during-playback.html
-/sdcard/android/layout_tests/media/video-currentTime-set.html
-/sdcard/android/layout_tests/media/controls-css-overload.html
-/sdcard/android/layout_tests/media/video-source-type-params.html
-/sdcard/android/layout_tests/media/event-attributes.html
-/sdcard/android/layout_tests/media/audio-data-url.html
-/sdcard/android/layout_tests/media/video-src-plus-source.html
-/sdcard/android/layout_tests/media/video-no-autoplay.html
-/sdcard/android/layout_tests/media/video-pause-empty-events.html
-/sdcard/android/layout_tests/media/video-document-types.html
-/sdcard/android/layout_tests/media/video-src-remove.html
-/sdcard/android/layout_tests/media/audio-delete-while-slider-thumb-clicked.html
-/sdcard/android/layout_tests/media/video-error-abort.html
-/sdcard/android/layout_tests/media/video-size-intrinsic-scale.html
-/sdcard/android/layout_tests/media/progress-event-total.html
-/sdcard/android/layout_tests/media/audio-constructor-src.html
-/sdcard/android/layout_tests/media/audio-mpeg-supported.html
-/sdcard/android/layout_tests/plugins/throw-on-dealloc.html
-/sdcard/android/layout_tests/plugins/invoke.html
-/sdcard/android/layout_tests/plugins/plugin-remove-subframe.html
-/sdcard/android/layout_tests/plugins/netscape-identifier-conversion.html
-/sdcard/android/layout_tests/plugins/netscape-invoke-browserfuncs.html
-/sdcard/android/layout_tests/plugins/call-as-function-test.html
-/sdcard/android/layout_tests/plugins/npruntime.html
-/sdcard/android/layout_tests/plugins/netscape-construct.html
-/sdcard/android/layout_tests/plugins/root-object-premature-delete-crash.html
-/sdcard/android/layout_tests/plugins/netscape-get-property-return-value.html
-/sdcard/android/layout_tests/plugins/mouse-events.html
-/sdcard/android/layout_tests/plugins/return-error-from-new-stream-doesnt-invoke-destroy-stream.html
-/sdcard/android/layout_tests/plugins/destroy-stream-twice.html
-/sdcard/android/layout_tests/plugins/jsobjc-simple.html
-/sdcard/android/layout_tests/plugins/embed-attributes-setting.html
-/sdcard/android/layout_tests/plugins/inner-html-display-none.html
-/sdcard/android/layout_tests/plugins/netscape-invoke-default.html
-/sdcard/android/layout_tests/plugins/undefined-property-crash.html
-/sdcard/android/layout_tests/plugins/netscape-plugin-map-data-to-src.html
-/sdcard/android/layout_tests/plugins/netscape-plugin-setwindow-size-2.html
-/sdcard/android/layout_tests/plugins/jsobjc-dom-wrappers.html
-/sdcard/android/layout_tests/plugins/plugin-javascript-access.html
-/sdcard/android/layout_tests/plugins/getintidentifier-special-values.html
-/sdcard/android/layout_tests/plugins/get-empty-url.html
-/sdcard/android/layout_tests/plugins/geturl-replace-query.html
-/sdcard/android/layout_tests/plugins/netscape-destroy-plugin-script-objects.html
-/sdcard/android/layout_tests/plugins/open-and-close-window-with-plugin.html
-/sdcard/android/layout_tests/plugins/netscape-enumerate.html
-/sdcard/android/layout_tests/plugins/get-url-that-the-resource-load-delegate-will-disallow.html
-/sdcard/android/layout_tests/plugins/netscape-plugin-setwindow-size.html
-/sdcard/android/layout_tests/plugins/embed-inside-object.html
-/sdcard/android/layout_tests/plugins/netscape-throw-exception.html
-/sdcard/android/layout_tests/plugins/get-url-with-blank-target.html
-/sdcard/android/layout_tests/plugins/bindings-test.html
-/sdcard/android/layout_tests/scrollbars/scrollbar-miss-mousemove-disabled.html
-/sdcard/android/layout_tests/security/set-form-autocomplete-attribute.html
-/sdcard/android/layout_tests/storage/execute-sql-args.html
-/sdcard/android/layout_tests/transitions/transition-shorthand-delay.html
-/sdcard/android/layout_tests/transitions/transition-drt-api-delay.html
-/sdcard/android/layout_tests/transitions/transition-hit-test.html
-/sdcard/android/layout_tests/transitions/opacity-transition-zindex.html
-/sdcard/android/layout_tests/transitions/interrupted-all-transition.html
-/sdcard/android/layout_tests/transitions/hang-with-bad-transition-list.html
-/sdcard/android/layout_tests/transitions/zero-duration-with-non-zero-delay-end.html
-/sdcard/android/layout_tests/transitions/remove-transition-style.html
-/sdcard/android/layout_tests/transitions/transition-hit-test-transform.html
-/sdcard/android/layout_tests/transitions/repeated-firing-background-color.html
-/sdcard/android/layout_tests/webarchive/loading/test-loading-archive.html
-/sdcard/android/layout_tests/wml/onenterforward-event.html
-/sdcard/android/layout_tests/wml/go-task-get-method-external-deck-with-href.html
-/sdcard/android/layout_tests/wml/option-element-onpick.html
-/sdcard/android/layout_tests/wml/enter-first-card-with-events.html
-/sdcard/android/layout_tests/wml/go-task-get-method-external-deck.html
-/sdcard/android/layout_tests/wml/go-task-get-method-same-deck.html
-/sdcard/android/layout_tests/wml/onenterforward-inline-event.html
-/sdcard/android/layout_tests/wml/ontimer-event.html
-/sdcard/android/layout_tests/wml/variable-reference-invalid-character.html
-/sdcard/android/layout_tests/wml/enter-card-with-events.html
-/sdcard/android/layout_tests/wml/ontimer-inline-event.html
-/sdcard/android/layout_tests/wml/select-element-variables.html
-/sdcard/android/layout_tests/wml/variable-reference-valid.html
-/sdcard/android/layout_tests/wml/access-target-deny.html
-/sdcard/android/layout_tests/wml/input-format.html
-/sdcard/android/layout_tests/wml/access-target.html
-/sdcard/android/layout_tests/wml/newcontext-same-deck.html
diff --git a/tests/DumpRenderTree/assets/results/layout_tests_nontext.txt b/tests/DumpRenderTree/assets/results/layout_tests_nontext.txt
deleted file mode 100644
index 665ef07..0000000
--- a/tests/DumpRenderTree/assets/results/layout_tests_nontext.txt
+++ /dev/null
@@ -1,4280 +0,0 @@
-/sdcard/android/layout_tests/accessibility/image-map1.html
-/sdcard/android/layout_tests/accessibility/aria-labelledby-on-input.html
-/sdcard/android/layout_tests/accessibility/aria-labelledby-stay-within.html
-/sdcard/android/layout_tests/accessibility/table-with-rules.html
-/sdcard/android/layout_tests/accessibility/aria-describedby-on-input.html
-/sdcard/android/layout_tests/accessibility/table-detection.html
-/sdcard/android/layout_tests/accessibility/table-with-aria-role.html
-/sdcard/android/layout_tests/accessibility/image-map2.html
-/sdcard/android/layout_tests/accessibility/table-cell-spans.html
-/sdcard/android/layout_tests/accessibility/table-cells.html
-/sdcard/android/layout_tests/accessibility/lists.html
-/sdcard/android/layout_tests/accessibility/plugin.html
-/sdcard/android/layout_tests/accessibility/table-sections.html
-/sdcard/android/layout_tests/accessibility/table-one-cell.html
-/sdcard/android/layout_tests/accessibility/internal-link-anchors2.html
-/sdcard/android/layout_tests/accessibility/radio-button-group-members.html
-/sdcard/android/layout_tests/accessibility/table-attributes.html
-/sdcard/android/layout_tests/accessibility/input-slider.html
-/sdcard/android/layout_tests/accessibility/aria-tables.html
-/sdcard/android/layout_tests/accessibility/legend.html
-/sdcard/android/layout_tests/accessibility/aria-roles.html
-/sdcard/android/layout_tests/animations/animation-drt-api-multiple-keyframes.html
-/sdcard/android/layout_tests/animations/animation-drt-api.html
-/sdcard/android/layout_tests/compositing/repaint/content-into-overflow.html
-/sdcard/android/layout_tests/compositing/repaint/overflow-into-content.html
-/sdcard/android/layout_tests/compositing/repaint/become-overlay-composited-layer.html
-/sdcard/android/layout_tests/compositing/repaint/layer-repaint-rects.html
-/sdcard/android/layout_tests/compositing/overflow/ancestor-overflow.html
-/sdcard/android/layout_tests/compositing/overflow/overflow-scroll.html
-/sdcard/android/layout_tests/compositing/overflow/overflow-positioning.html
-/sdcard/android/layout_tests/compositing/overflow/parent-overflow.html
-/sdcard/android/layout_tests/compositing/color-matching/image-color-matching.html
-/sdcard/android/layout_tests/compositing/geometry/root-layer-update.html
-/sdcard/android/layout_tests/compositing/geometry/outline-change.html
-/sdcard/android/layout_tests/compositing/reflections/reflection-on-composited.html
-/sdcard/android/layout_tests/compositing/self-painting-layers.html
-/sdcard/android/layout_tests/compositing/direct-image-compositing.html
-/sdcard/android/layout_tests/compositing/layers-inside-overflow-scroll.html
-/sdcard/android/layout_tests/compositing/generated-content.html
-/sdcard/android/layout_tests/compositing/sibling-positioning.html
-/sdcard/android/layout_tests/css1/color_and_background/background_color.html
-/sdcard/android/layout_tests/css1/color_and_background/color.html
-/sdcard/android/layout_tests/css1/color_and_background/background.html
-/sdcard/android/layout_tests/css1/color_and_background/background_repeat.html
-/sdcard/android/layout_tests/css1/color_and_background/background_image.html
-/sdcard/android/layout_tests/css1/color_and_background/background_position.html
-/sdcard/android/layout_tests/css1/color_and_background/background_attachment.html
-/sdcard/android/layout_tests/css1/pseudo/firstline.html
-/sdcard/android/layout_tests/css1/pseudo/pseudo_elements_in_selectors.html
-/sdcard/android/layout_tests/css1/pseudo/multiple_pseudo_elements.html
-/sdcard/android/layout_tests/css1/pseudo/firstletter.html
-/sdcard/android/layout_tests/css1/pseudo/anchor.html
-/sdcard/android/layout_tests/css1/text_properties/text_align.html
-/sdcard/android/layout_tests/css1/text_properties/line_height.html
-/sdcard/android/layout_tests/css1/text_properties/text_transform.html
-/sdcard/android/layout_tests/css1/text_properties/word_spacing.html
-/sdcard/android/layout_tests/css1/text_properties/letter_spacing.html
-/sdcard/android/layout_tests/css1/text_properties/vertical_align.html
-/sdcard/android/layout_tests/css1/text_properties/text_indent.html
-/sdcard/android/layout_tests/css1/text_properties/text_decoration.html
-/sdcard/android/layout_tests/css1/basic/containment.html
-/sdcard/android/layout_tests/css1/basic/id_as_selector.html
-/sdcard/android/layout_tests/css1/basic/comments.html
-/sdcard/android/layout_tests/css1/basic/class_as_selector.html
-/sdcard/android/layout_tests/css1/basic/contextual_selectors.html
-/sdcard/android/layout_tests/css1/basic/inheritance.html
-/sdcard/android/layout_tests/css1/basic/grouping.html
-/sdcard/android/layout_tests/css1/font_properties/font_weight.html
-/sdcard/android/layout_tests/css1/font_properties/font_size.html
-/sdcard/android/layout_tests/css1/font_properties/font.html
-/sdcard/android/layout_tests/css1/font_properties/font_style.html
-/sdcard/android/layout_tests/css1/font_properties/font_family.html
-/sdcard/android/layout_tests/css1/font_properties/font_variant.html
-/sdcard/android/layout_tests/css1/units/percentage_units.html
-/sdcard/android/layout_tests/css1/units/color_units.html
-/sdcard/android/layout_tests/css1/units/length_units.html
-/sdcard/android/layout_tests/css1/units/urls.html
-/sdcard/android/layout_tests/css1/cascade/important.html
-/sdcard/android/layout_tests/css1/cascade/cascade_order.html
-/sdcard/android/layout_tests/css1/box_properties/border_width.html
-/sdcard/android/layout_tests/css1/box_properties/margin.html
-/sdcard/android/layout_tests/css1/box_properties/width.html
-/sdcard/android/layout_tests/css1/box_properties/padding_left.html
-/sdcard/android/layout_tests/css1/box_properties/margin_left_inline.html
-/sdcard/android/layout_tests/css1/box_properties/clear.html
-/sdcard/android/layout_tests/css1/box_properties/border_left_width.html
-/sdcard/android/layout_tests/css1/box_properties/margin_left.html
-/sdcard/android/layout_tests/css1/box_properties/padding_top.html
-/sdcard/android/layout_tests/css1/box_properties/padding_bottom.html
-/sdcard/android/layout_tests/css1/box_properties/border_style_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_top_width_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_top_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_style.html
-/sdcard/android/layout_tests/css1/box_properties/border_top.html
-/sdcard/android/layout_tests/css1/box_properties/margin_bottom_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_bottom_width.html
-/sdcard/android/layout_tests/css1/box_properties/margin_bottom.html
-/sdcard/android/layout_tests/css1/box_properties/float_elements_in_series.html
-/sdcard/android/layout_tests/css1/box_properties/float_on_text_elements.html
-/sdcard/android/layout_tests/css1/box_properties/padding.html
-/sdcard/android/layout_tests/css1/box_properties/border_right_width_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_right_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_right_width.html
-/sdcard/android/layout_tests/css1/box_properties/margin_right.html
-/sdcard/android/layout_tests/css1/box_properties/border_width_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_inline.html
-/sdcard/android/layout_tests/css1/box_properties/clear_float.html
-/sdcard/android/layout_tests/css1/box_properties/border.html
-/sdcard/android/layout_tests/css1/box_properties/padding_left_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_left_width_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_left_inline.html
-/sdcard/android/layout_tests/css1/box_properties/padding_top_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_left.html
-/sdcard/android/layout_tests/css1/box_properties/padding_bottom_inline.html
-/sdcard/android/layout_tests/css1/box_properties/margin_top_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_top_width.html
-/sdcard/android/layout_tests/css1/box_properties/border_bottom_width_inline.html
-/sdcard/android/layout_tests/css1/box_properties/acid_test.html
-/sdcard/android/layout_tests/css1/box_properties/border_bottom_inline.html
-/sdcard/android/layout_tests/css1/box_properties/margin_top.html
-/sdcard/android/layout_tests/css1/box_properties/border_bottom.html
-/sdcard/android/layout_tests/css1/box_properties/padding_right_inline.html
-/sdcard/android/layout_tests/css1/box_properties/float_margin.html
-/sdcard/android/layout_tests/css1/box_properties/padding_right.html
-/sdcard/android/layout_tests/css1/box_properties/padding_inline.html
-/sdcard/android/layout_tests/css1/box_properties/float.html
-/sdcard/android/layout_tests/css1/box_properties/height.html
-/sdcard/android/layout_tests/css1/box_properties/margin_right_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_color_inline.html
-/sdcard/android/layout_tests/css1/box_properties/border_right.html
-/sdcard/android/layout_tests/css1/box_properties/border_color.html
-/sdcard/android/layout_tests/css1/box_properties/margin_inline.html
-/sdcard/android/layout_tests/css1/conformance/forward_compatible_parsing.html
-/sdcard/android/layout_tests/css1/formatting_model/floating_elements.html
-/sdcard/android/layout_tests/css1/formatting_model/horizontal_formatting.html
-/sdcard/android/layout_tests/css1/formatting_model/vertical_formatting.html
-/sdcard/android/layout_tests/css1/formatting_model/height_of_lines.html
-/sdcard/android/layout_tests/css1/formatting_model/inline_elements.html
-/sdcard/android/layout_tests/css1/formatting_model/canvas.html
-/sdcard/android/layout_tests/css1/formatting_model/replaced_elements.html
-/sdcard/android/layout_tests/css1/classification/list_style_type.html
-/sdcard/android/layout_tests/css1/classification/list_style_image.html
-/sdcard/android/layout_tests/css1/classification/list_style_position.html
-/sdcard/android/layout_tests/css1/classification/display.html
-/sdcard/android/layout_tests/css1/classification/list_style.html
-/sdcard/android/layout_tests/css1/classification/white_space.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-03-c.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-padn-l-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1205-c563-list-type-00-b.html
-/sdcard/android/layout_tests/css2.1/t090402-c42-ibx-pad-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t120401-scope-00-b.html
-/sdcard/android/layout_tests/css2.1/t010403-shand-border-00-c.html
-/sdcard/android/layout_tests/css2.1/t0805-c5518-ibrdr-t-00-a.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-03-b.html
-/sdcard/android/layout_tests/css2.1/t1008-c44-ln-box-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-14-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-34-d.html
-/sdcard/android/layout_tests/css2.1/t1204-implied-00-b.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-03-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-54-d.html
-/sdcard/android/layout_tests/css2.1/t100801-c548-ln-ht-00-c-a.html
-/sdcard/android/layout_tests/css2.1/t0905-c5526-fltclr-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/bogus-color-span.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-74-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-03-b-a.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgreps-04-c-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-94-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-03-b-a.html
-/sdcard/android/layout_tests/css2.1/t040307-syntax-01-b.html
-/sdcard/android/layout_tests/css2.1/t100801-c548-ln-ht-04-d-ag.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-06-b.html
-/sdcard/android/layout_tests/css2.1/t040306-c63-color-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-02-b.html
-/sdcard/android/layout_tests/css2.1/t080301-c411-vt-mrgn-00-b.html
-/sdcard/android/layout_tests/css2.1/t010403-shand-font-03-b.html
-/sdcard/android/layout_tests/css2.1/t051103-c21-focus-ln-00-e-i.html
-/sdcard/android/layout_tests/css2.1/t120403-display-none-00-c.html
-/sdcard/android/layout_tests/css2.1/t0805-c5512-brdr-rw-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-12-c.html
-/sdcard/android/layout_tests/css2.1/t0805-c5515-ibrdr-00-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5520-brdr-b-00-a.html
-/sdcard/android/layout_tests/css2.1/t1505-c524-font-var-00-b.html
-/sdcard/android/layout_tests/css2.1/t0509-c15-ids-00-a.html
-/sdcard/android/layout_tests/css2.1/t060403-c21-pseu-cls-00-e-i.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-03-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-12-b.html
-/sdcard/android/layout_tests/css2.1/t0402-c71-fwd-parsing-04-f.html
-/sdcard/android/layout_tests/css2.1/t040303-c62-percent-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-23-d.html
-/sdcard/android/layout_tests/css2.1/t140201-c535-bg-fixd-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-43-d.html
-/sdcard/android/layout_tests/css2.1/t1204-increment-02-c-o.html
-/sdcard/android/layout_tests/css2.1/t0602-c13-inh-underlin-00-e.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-63-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-83-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-16-f.html
-/sdcard/android/layout_tests/css2.1/t040302-c61-phys-len-00-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5516-ibrdr-c-00-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5521-brdr-l-01-e.html
-/sdcard/android/layout_tests/css2.1/t100801-c544-valgn-03-d-agi.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-06-b.html
-/sdcard/android/layout_tests/css2.1/t0402-syntax-03-f.html
-/sdcard/android/layout_tests/css2.1/t050803-c14-classes-00-e.html
-/sdcard/android/layout_tests/css2.1/t140201-c537-bgfxps-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t1002-c5523-width-02-b-g.html
-/sdcard/android/layout_tests/css2.1/t1004-c5524-width-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-11-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-06-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0805-c5522-brdr-02-e.html
-/sdcard/android/layout_tests/css2.1/t0511-c21-pseud-anch-00-e-i.html
-/sdcard/android/layout_tests/css2.1/t0804-c5508-ipadn-b-01-f-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-04-b-ag.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-01-c.html
-/sdcard/android/layout_tests/css2.1/t040102-keywords-00-b.html
-/sdcard/android/layout_tests/css2.1/t0505-c16-descendant-02-e.html
-/sdcard/android/layout_tests/css2.1/t1507-c526-font-sz-03-f-a.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-09-b.html
-/sdcard/android/layout_tests/css2.1/t1204-root-e.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-fit-01-d-g.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-01-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-12-d.html
-/sdcard/android/layout_tests/css2.1/t090501-c5525-flt-r-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-32-d.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-01-b.html
-/sdcard/android/layout_tests/css2.1/t1004-c43-rpl-bbx-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgre-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-ipadn-l-02-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-52-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5512-brdr-rw-02-b.html
-/sdcard/android/layout_tests/css2.1/t040109-c17-comments-00-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-ipadn-r-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-72-d.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgreps-01-c-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-92-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-01-d-g.html
-/sdcard/android/layout_tests/css2.1/t100801-c548-ln-ht-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-03-b-g.html
-/sdcard/android/layout_tests/css2.1/t1204-multiple-01-c.html
-/sdcard/android/layout_tests/css2.1/t0803-c5505-mrgn-03-c-ag.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-04-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-00-b.html
-/sdcard/android/layout_tests/css2.1/t1602-c43-center-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t140201-c532-bgcolor-00-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-mrgn-l-03-c.html
-/sdcard/android/layout_tests/css2.1/t010403-shand-font-01-b.html
-/sdcard/android/layout_tests/css2.1/t1005-c5524-width-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t1601-c547-indent-01-d.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-10-c.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-01-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5505-mrgn-02-c.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-04-c.html
-/sdcard/android/layout_tests/css2.1/t051103-dom-hover-01-c-io.html
-/sdcard/android/layout_tests/css2.1/t1604-c542-letter-sp-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-08-c.html
-/sdcard/android/layout_tests/css2.1/t120401-scope-02-c.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-01-d.html
-/sdcard/android/layout_tests/css2.1/t0402-c71-fwd-parsing-02-f.html
-/sdcard/android/layout_tests/css2.1/t1204-reset-00-c-o.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-21-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-41-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltwidth-01-c-g.html
-/sdcard/android/layout_tests/css2.1/t1507-c526-font-sz-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-61-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-08-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-81-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-19-d.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-04-b.html
-/sdcard/android/layout_tests/css2.1/t1604-c541-word-sp-01-b-a.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-39-d.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-08-b.html
-/sdcard/android/layout_tests/css2.1/t0402-syntax-01-f.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-59-d.html
-/sdcard/android/layout_tests/css2.1/t1205-c565-list-pos-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-79-d.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-10-c.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-99-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t040306-syntax-01-f.html
-/sdcard/android/layout_tests/css2.1/t1507-c526-font-sz-01-b-a.html
-/sdcard/android/layout_tests/css2.1/t040105-atrule-04-b.html
-/sdcard/android/layout_tests/css2.1/t0505-c16-descendant-00-e.html
-/sdcard/android/layout_tests/css2.1/t0805-c5513-brdr-bw-02-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5519-brdr-r-01-e.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-07-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5510-padn-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0805-c5517-ibrdr-s-00-a.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-10-d.html
-/sdcard/android/layout_tests/css2.1/t040105-import-00-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-ipadn-l-03-b-a.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-30-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5514-brdr-lw-02-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-50-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-ipadn-r-03-b-a.html
-/sdcard/android/layout_tests/css2.1/t1008-c44-ln-box-02-d-ag.html
-/sdcard/android/layout_tests/css2.1/t0805-c5512-brdr-rw-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-70-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-08-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-90-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-28-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-48-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5513-brdr-bw-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-68-d.html
-/sdcard/android/layout_tests/css2.1/t1402-c45-bg-canvas-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-88-d.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-02-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5521-ibrdr-l-00-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5522-brdr-00-b.html
-/sdcard/android/layout_tests/css2.1/t1606-c562-white-sp-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-02-c.html
-/sdcard/android/layout_tests/css2.1/t100801-c544-valgn-00-a-ag.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-06-c.html
-/sdcard/android/layout_tests/css2.1/t0402-c71-fwd-parsing-00-f.html
-/sdcard/android/layout_tests/css2.1/t1204-reset-02-c-o.html
-/sdcard/android/layout_tests/css2.1/t0602-c13-inheritance-00-e.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-ln-02-d.html
-/sdcard/android/layout_tests/css2.1/t1205-c566-list-stl-01-c-g.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-06-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-17-d.html
-/sdcard/android/layout_tests/css2.1/t100304-c43-rpl-bbx-00-d-g.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-mrgn-l-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t1205-c566-list-stl-00-e-ag.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltwidth-03-c-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-37-d.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-06-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-57-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5510-padn-02-f.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-77-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-97-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t090204-display-change-01-b-ao.html
-/sdcard/android/layout_tests/css2.1/t040302-c61-ex-len-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t040105-atrule-02-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5513-brdr-bw-00-b.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-09-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-05-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-mrgn-r-02-c.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-06-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-padn-r-01-c-a.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-00-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-17-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-mrgn-l-01-c-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5514-brdr-lw-00-b.html
-/sdcard/android/layout_tests/css2.1/t140201-c536-bgpos-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t100303-c412-blockw-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t120401-scope-04-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5506-ipadn-t-01-b-a.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-06-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-15-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-26-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5521-brdr-l-00-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5511-brdr-tw-02-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-46-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-ipadn-r-02-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-66-d.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgreps-03-c-ag.html
-/sdcard/android/layout_tests/css2.1/t100801-c544-valgn-02-d-agi.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-ipadn-l-04-f-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-86-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5512-ibrdr-rw-00-a.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-00-b.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltblck-01-d.html
-/sdcard/android/layout_tests/css2.1/t0402-syntax-06-f.html
-/sdcard/android/layout_tests/css2.1/t100801-c548-ln-ht-03-d-ag.html
-/sdcard/android/layout_tests/css2.1/t0805-c5515-brdr-w-00-a.html
-/sdcard/android/layout_tests/css2.1/t051202-c24-first-lttr-00-b.html
-/sdcard/android/layout_tests/css2.1/t0511-c21-pseud-link-02-e.html
-/sdcard/android/layout_tests/css2.1/t0804-c5510-padn-01-e-a.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltinln-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-14-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5518-brdr-t-01-e.html
-/sdcard/android/layout_tests/css2.1/t040105-atkeyw-01-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5511-brdr-tw-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-04-c.html
-/sdcard/android/layout_tests/css2.1/t1205-c563-list-type-01-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-18-f.html
-/sdcard/android/layout_tests/css2.1/t0509-id-sel-syntax-01-f.html
-/sdcard/android/layout_tests/css2.1/t100801-c544-valgn-01-d-ag.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-ln-00-d.html
-/sdcard/android/layout_tests/css2.1/t1601-c547-indent-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-04-b.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-flthw-00-c-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-15-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5522-brdr-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-35-d.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-00-b.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-04-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-55-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-75-d.html
-/sdcard/android/layout_tests/css2.1/t1205-c564-list-img-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-95-d.html
-/sdcard/android/layout_tests/css2.1/t120403-visibility-00-c.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-02-b-a.html
-/sdcard/android/layout_tests/css2.1/t051103-c21-activ-ln-00-e-i.html
-/sdcard/android/layout_tests/css2.1/t0801-c412-hz-box-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-02-d-g.html
-/sdcard/android/layout_tests/css2.1/t1605-c545-txttrans-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t040105-atrule-00-b.html
-/sdcard/android/layout_tests/css2.1/t100801-c548-leadin-00-d-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-05-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0804-c5508-ipadn-b-03-b-a.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-07-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-03-b.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-13-c.html
-/sdcard/android/layout_tests/css2.1/t1204-order-01-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5510-ipadn-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-04-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-13-b.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgre-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1504-c523-font-style-00-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-ipadn-l-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-mrgn-r-01-c-a.html
-/sdcard/android/layout_tests/css2.1/t1204-increment-01-c-o.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-24-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5511-brdr-tw-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-44-d.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgreps-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-64-d.html
-/sdcard/android/layout_tests/css2.1/t1204-implied-02-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-84-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5521-brdr-l-02-e.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-07-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-padn-r-02-f.html
-/sdcard/android/layout_tests/css2.1/t0402-syntax-04-f.html
-/sdcard/android/layout_tests/css2.1/t1002-c5523-width-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t0805-c5519-brdr-r-00-a.html
-/sdcard/android/layout_tests/css2.1/t0511-c21-pseud-link-00-e.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-12-b.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-02-c.html
-/sdcard/android/layout_tests/css2.1/t040102-keywords-01-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5503-imrgn-b-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5513-ibrdr-bw-00-a.html
-/sdcard/android/layout_tests/css2.1/css1_forward_compatible_parsing.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-padn-l-03-f-g.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-02-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-13-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c5526-flthw-00-c-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-33-d.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-02-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-53-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5512-brdr-rw-03-b.html
-/sdcard/android/layout_tests/css2.1/t040109-c17-comments-01-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-73-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-93-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5511-ibrdr-tw-00-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-02-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-05-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-01-b.html
-/sdcard/android/layout_tests/css2.1/t1005-c5524-width-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-wrap-01-d-g.html
-/sdcard/android/layout_tests/css2.1/t010403-shand-font-02-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5515-brdr-w-02-b.html
-/sdcard/android/layout_tests/css2.1/t060401-c32-cascading-00-b.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltcont-00-d-g.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-11-c.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-16-c.html
-/sdcard/android/layout_tests/css2.1/t0509-id-sel-syntax-02-b.html
-/sdcard/android/layout_tests/css2.1/t090501-c5525-flt-l-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-09-c.html
-/sdcard/android/layout_tests/css2.1/t050201-c12-grouping-00-b.html
-/sdcard/android/layout_tests/css2.1/t120401-scope-03-c.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-02-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-wrap-00-e.html
-/sdcard/android/layout_tests/css2.1/t0402-c71-fwd-parsing-03-f.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-11-b.html
-/sdcard/android/layout_tests/css2.1/t1506-c525-font-wt-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-22-d.html
-/sdcard/android/layout_tests/css2.1/t1008-c44-ln-box-01-d-ag.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltwidth-00-c-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-42-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-62-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltmult-00-d-g.html
-/sdcard/android/layout_tests/css2.1/t1401-c531-color-00-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5514-ibrdr-lw-00-a.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-09-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-82-d.html
-/sdcard/android/layout_tests/css2.1/t1604-c541-word-sp-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5515-brdr-w-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-ipadn-r-04-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-09-b.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgreps-05-c-ag.html
-/sdcard/android/layout_tests/css2.1/t0402-syntax-02-f.html
-/sdcard/android/layout_tests/css2.1/t0803-c5503-mrgn-b-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5517-brdr-s-00-c.html
-/sdcard/android/layout_tests/css2.1/t0805-c5514-brdr-lw-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t100801-c42-ibx-ht-00-d-a.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-00-c.html
-/sdcard/android/layout_tests/css2.1/t0805-c5513-brdr-bw-03-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5506-padn-t-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t0505-c16-descendant-01-e.html
-/sdcard/android/layout_tests/css2.1/t0805-c5519-brdr-r-02-e.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-08-b.html
-/sdcard/android/layout_tests/css2.1/t051103-c21-hover-ln-00-e-i.html
-/sdcard/android/layout_tests/css2.1/t120403-content-none-00-c.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-00-b.html
-/sdcard/android/layout_tests/css2.1/t040105-import-01-b.html
-/sdcard/android/layout_tests/css2.1/t040103-case-01-c.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-11-d.html
-/sdcard/android/layout_tests/css2.1/t09-c5526c-display-00-e.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltblck-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-31-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5514-brdr-lw-03-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-51-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-71-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-09-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-91-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltwrap-00-b.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-fit-00-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-29-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5505-mrgn-01-e-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-mrgn-r-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t1004-c43-rpl-ibx-00-d-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-49-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-69-d.html
-/sdcard/android/layout_tests/css2.1/t1204-multiple-00-c.html
-/sdcard/android/layout_tests/css2.1/t140201-c533-bgimage-01-b-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-89-d.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-03-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-mrgn-l-02-c.html
-/sdcard/android/layout_tests/css2.1/t0805-c5518-brdr-t-00-a.html
-/sdcard/android/layout_tests/css2.1/t010403-shand-font-00-b.html
-/sdcard/android/layout_tests/css2.1/t0510-c25-pseudo-elmnt-00-c.html
-/sdcard/android/layout_tests/css2.1/t0803-c5505-imrgn-00-a-ag.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-imrgn-r-05-b-ag.html
-/sdcard/android/layout_tests/css2.1/t060402-c31-important-00-b.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-00-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c414-flt-03-c.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-07-c.html
-/sdcard/android/layout_tests/css2.1/t1204-order-00-c.html
-/sdcard/android/layout_tests/css2.1/t120401-scope-01-c.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-00-d.html
-/sdcard/android/layout_tests/css2.1/t0402-c71-fwd-parsing-01-f.html
-/sdcard/android/layout_tests/css2.1/t1604-c542-letter-sp-01-b-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5520-brdr-b-01-e.html
-/sdcard/android/layout_tests/css2.1/t140201-c536-bgpos-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-20-d.html
-/sdcard/android/layout_tests/css2.1/t0509-c15-ids-01-e.html
-/sdcard/android/layout_tests/css2.1/t1204-reset-01-c-o.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-40-d.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-ln-03-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-60-d.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltwidth-02-c-g.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltclr-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-07-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-80-d.html
-/sdcard/android/layout_tests/css2.1/t1204-implied-01-c.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-18-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-ipadn-r-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-03-b.html
-/sdcard/android/layout_tests/css2.1/t140201-c534-bgreps-02-c-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-38-d.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-07-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-58-d.html
-/sdcard/android/layout_tests/css2.1/t0803-c5505-mrgn-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t100801-c544-valgn-04-d-agi.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-78-d.html
-/sdcard/android/layout_tests/css2.1/t100801-c548-ln-ht-02-b-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-98-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5508-ipadn-b-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-padn-l-01-b-a.html
-/sdcard/android/layout_tests/css2.1/t040105-atrule-03-b.html
-/sdcard/android/layout_tests/css2.1/t1507-c526-font-sz-02-b-a.html
-/sdcard/android/layout_tests/css2.1/t0805-c5522-ibrdr-00-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5502-mrgn-r-03-c.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-06-b.html
-/sdcard/android/layout_tests/css2.1/t0905-c5525-fltmrgn-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t051103-dom-hover-02-c-io.html
-/sdcard/android/layout_tests/css2.1/t0804-c5506-ipadn-t-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t040304-c64-uri-00-a-g.html
-/sdcard/android/layout_tests/css2.1/t0803-c5501-mrgn-t-00-b-a.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-07-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-27-d.html
-/sdcard/android/layout_tests/css2.1/t0805-c5511-brdr-tw-03-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-47-d.html
-/sdcard/android/layout_tests/css2.1/t060403-c21-pseu-id-00-e-i.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-67-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-87-d.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-01-b.html
-/sdcard/android/layout_tests/css2.1/t0603-c11-import-00-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-04-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1503-c522-font-family-00-b.html
-/sdcard/android/layout_tests/css2.1/t090501-c414-flt-ln-01-d-g.html
-/sdcard/android/layout_tests/css2.1/t0511-c21-pseud-link-03-e.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-15-b.html
-/sdcard/android/layout_tests/css2.1/t040105-atkeyw-02-b.html
-/sdcard/android/layout_tests/css2.1/t0805-c5519-ibrdr-r-00-a.html
-/sdcard/android/layout_tests/css2.1/t040103-ident-05-c.html
-/sdcard/android/layout_tests/css2.1/t0602-inherit-bdr-pad-b-00.html
-/sdcard/android/layout_tests/css2.1/t040302-c61-rel-len-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-padn-r-00-c-ag.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-ipadn-l-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t0805-c5520-ibrdr-b-00-a.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-05-b.html
-/sdcard/android/layout_tests/css2.1/t1008-c44-ln-box-03-d-ag.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-16-d.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-01-b.html
-/sdcard/android/layout_tests/css2.1/t100304-c43-rpl-bbx-01-d-g.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-36-d.html
-/sdcard/android/layout_tests/css2.1/t1001-abs-pos-cb-05-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-56-d.html
-/sdcard/android/layout_tests/css2.1/t0804-c5509-padn-l-02-f.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-76-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-96-d.html
-/sdcard/android/layout_tests/css2.1/t051202-c26-psudo-nest-00-c.html
-/sdcard/android/layout_tests/css2.1/t040105-atrule-01-b.html
-/sdcard/android/layout_tests/css2.1/t0804-c5508-ipadn-b-02-b-a.html
-/sdcard/android/layout_tests/css2.1/t0803-c5501-imrgn-t-00-b-ag.html
-/sdcard/android/layout_tests/css2.1/t140201-c532-bgcolor-01-b.html
-/sdcard/android/layout_tests/css2.1/t1508-c527-font-08-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-04-b.html
-/sdcard/android/layout_tests/css2.1/t040103-case-00-b.html
-/sdcard/android/layout_tests/css2.1/t1504-c543-txt-decor-00-d-g.html
-/sdcard/android/layout_tests/css2.1/t0805-c5516-brdr-c-00-a.html
-/sdcard/android/layout_tests/css2.1/t0804-c5506-ipadn-t-02-b-a.html
-/sdcard/android/layout_tests/css2.1/t1204-increment-00-c-o.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-05-d.html
-/sdcard/android/layout_tests/css2.1/t1202-counter-14-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-25-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-45-d.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-65-d.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-02-d.html
-/sdcard/android/layout_tests/css2.1/t1602-c546-txt-align-00-b.html
-/sdcard/android/layout_tests/css2.1/t170602-bdr-conflct-w-85-d.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-05-c.html
-/sdcard/android/layout_tests/css2.1/t040103-escapes-08-b.html
-/sdcard/android/layout_tests/css2.1/t0803-c5504-imrgn-l-01-b-ag.html
-/sdcard/android/layout_tests/css2.1/t1002-c5523-width-00-b-g.html
-/sdcard/android/layout_tests/css2.1/t0804-c5507-padn-r-03-f.html
-/sdcard/android/layout_tests/css2.1/t0402-syntax-05-f.html
-/sdcard/android/layout_tests/css2.1/t1205-c561-list-displ-00-b.html
-/sdcard/android/layout_tests/css2.1/t0511-c21-pseud-link-01-e.html
-/sdcard/android/layout_tests/css2.1/t051201-c23-first-line-00-b.html
-/sdcard/android/layout_tests/css2.1/t1202-counters-13-b.html
-/sdcard/android/layout_tests/css2.1/t140201-c533-bgimage-00-a.html
-/sdcard/android/layout_tests/css2.1/t040105-atkeyw-00-b.html
-/sdcard/android/layout_tests/css3/css3-modsel-33.html
-/sdcard/android/layout_tests/css3/css3-modsel-35.html
-/sdcard/android/layout_tests/css3/css3-modsel-36.html
-/sdcard/android/layout_tests/css3/css3-modsel-37.html
-/sdcard/android/layout_tests/editing/input/emacs-ctrl-o.html
-/sdcard/android/layout_tests/editing/style/style-3681552-fix-001.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-013.html
-/sdcard/android/layout_tests/editing/style/style-3690704-fix.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-005.html
-/sdcard/android/layout_tests/editing/style/style-boundary-002.html
-/sdcard/android/layout_tests/editing/style/remove-underline-after-paragraph.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-009.html
-/sdcard/android/layout_tests/editing/style/5228141.html
-/sdcard/android/layout_tests/editing/style/block-style-004.html
-/sdcard/android/layout_tests/editing/style/apple-style-editable-mix.html
-/sdcard/android/layout_tests/editing/style/unbold-in-bold.html
-/sdcard/android/layout_tests/editing/style/typing-style-001.html
-/sdcard/android/layout_tests/editing/style/relative-font-size-change-004.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-010.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-002.html
-/sdcard/android/layout_tests/editing/style/style-3681552-fix-002.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-006.html
-/sdcard/android/layout_tests/editing/style/style-boundary-003.html
-/sdcard/android/layout_tests/editing/style/block-style-001.html
-/sdcard/android/layout_tests/editing/style/smoosh-styles-001.html
-/sdcard/android/layout_tests/editing/style/font-family-with-space.html
-/sdcard/android/layout_tests/editing/style/5084241.html
-/sdcard/android/layout_tests/editing/style/5065910.html
-/sdcard/android/layout_tests/editing/style/block-style-005.html
-/sdcard/android/layout_tests/editing/style/remove-underline-across-paragraph-in-bold.html
-/sdcard/android/layout_tests/editing/style/5279521.html
-/sdcard/android/layout_tests/editing/style/non-inheritable-styles.html
-/sdcard/android/layout_tests/editing/style/5046875-1.html
-/sdcard/android/layout_tests/editing/style/style-3998892-fix.html
-/sdcard/android/layout_tests/editing/style/typing-style-002.html
-/sdcard/android/layout_tests/editing/style/relative-font-size-change-001.html
-/sdcard/android/layout_tests/editing/style/4916887.html
-/sdcard/android/layout_tests/editing/style/remove-underline-across-paragraph.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-011.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-003.html
-/sdcard/android/layout_tests/editing/style/remove-underline.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-007.html
-/sdcard/android/layout_tests/editing/style/style-boundary-004.html
-/sdcard/android/layout_tests/editing/style/5017613-1.html
-/sdcard/android/layout_tests/editing/style/block-style-002.html
-/sdcard/android/layout_tests/editing/style/block-style-006.html
-/sdcard/android/layout_tests/editing/style/fontsize-1.html
-/sdcard/android/layout_tests/editing/style/5046875-2.html
-/sdcard/android/layout_tests/editing/style/typing-style-003.html
-/sdcard/android/layout_tests/editing/style/relative-font-size-change-002.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-012.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-004.html
-/sdcard/android/layout_tests/editing/style/designmode.html
-/sdcard/android/layout_tests/editing/style/block-styles-007.html
-/sdcard/android/layout_tests/editing/style/style-boundary-001.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-008.html
-/sdcard/android/layout_tests/editing/style/style-boundary-005.html
-/sdcard/android/layout_tests/editing/style/5017613-2.html
-/sdcard/android/layout_tests/editing/style/underline.html
-/sdcard/android/layout_tests/editing/style/block-style-003.html
-/sdcard/android/layout_tests/editing/style/smoosh-styles-003.html
-/sdcard/android/layout_tests/editing/style/remove-underline-after-paragraph-in-bold.html
-/sdcard/android/layout_tests/editing/style/highlight.html
-/sdcard/android/layout_tests/editing/style/relative-font-size-change-003.html
-/sdcard/android/layout_tests/editing/style/table-selection.html
-/sdcard/android/layout_tests/editing/style/create-block-for-style-001.html
-/sdcard/android/layout_tests/editing/unsupported-content/table-delete-001.html
-/sdcard/android/layout_tests/editing/unsupported-content/table-type-after.html
-/sdcard/android/layout_tests/editing/unsupported-content/table-delete-002.html
-/sdcard/android/layout_tests/editing/unsupported-content/table-type-before.html
-/sdcard/android/layout_tests/editing/unsupported-content/table-delete-003.html
-/sdcard/android/layout_tests/editing/unsupported-content/list-delete-001.html
-/sdcard/android/layout_tests/editing/unsupported-content/list-type-after.html
-/sdcard/android/layout_tests/editing/unsupported-content/list-type-before.html
-/sdcard/android/layout_tests/editing/unsupported-content/list-delete-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-011.html
-/sdcard/android/layout_tests/editing/inserting/4960120-1.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-023.html
-/sdcard/android/layout_tests/editing/inserting/insert-paragraph-04.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-007.html
-/sdcard/android/layout_tests/editing/inserting/5058163-2.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-019.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-at-tabspan-003.html
-/sdcard/android/layout_tests/editing/inserting/5607069-2.html
-/sdcard/android/layout_tests/editing/inserting/6633727.html
-/sdcard/android/layout_tests/editing/inserting/6703873.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-003.html
-/sdcard/android/layout_tests/editing/inserting/4875189-1.html
-/sdcard/android/layout_tests/editing/inserting/typing-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-3907422-fix.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-020.html
-/sdcard/android/layout_tests/editing/inserting/before-after-input-element.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-004.html
-/sdcard/android/layout_tests/editing/inserting/insert-paragraph-01.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-016.html
-/sdcard/android/layout_tests/editing/inserting/5510537.html
-/sdcard/android/layout_tests/editing/inserting/4959067.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-008.html
-/sdcard/android/layout_tests/editing/inserting/insert-text-at-tabspan-001.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-001.html
-/sdcard/android/layout_tests/editing/inserting/paragraph-separator-02.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-013.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-025.html
-/sdcard/android/layout_tests/editing/inserting/insert-3654864-fix.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-009.html
-/sdcard/android/layout_tests/editing/inserting/return-key-with-selection-002.html
-/sdcard/android/layout_tests/editing/inserting/editable-html-element.html
-/sdcard/android/layout_tests/editing/inserting/5418891.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-005.html
-/sdcard/android/layout_tests/editing/inserting/insert-tab-002.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-005.html
-/sdcard/android/layout_tests/editing/inserting/line-break.html
-/sdcard/android/layout_tests/editing/inserting/5549929-3.html
-/sdcard/android/layout_tests/editing/inserting/typing-tab-designmode-forms.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-010.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-022.html
-/sdcard/android/layout_tests/editing/inserting/insert-paragraph-03.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-006.html
-/sdcard/android/layout_tests/editing/inserting/5058163-1.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-018.html
-/sdcard/android/layout_tests/editing/inserting/paragraph-separator-in-table-2.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-at-tabspan-002.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-002.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-002.html
-/sdcard/android/layout_tests/editing/inserting/typing-002.html
-/sdcard/android/layout_tests/editing/inserting/insert-3800346-fix.html
-/sdcard/android/layout_tests/editing/inserting/typing-around-image-001.html
-/sdcard/android/layout_tests/editing/inserting/insert-text-at-tabspan-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-text-with-newlines.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-015.html
-/sdcard/android/layout_tests/editing/inserting/insert-at-end-02.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-027.html
-/sdcard/android/layout_tests/editing/inserting/insert-3659587-fix.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-007.html
-/sdcard/android/layout_tests/editing/inserting/insert-tab-004.html
-/sdcard/android/layout_tests/editing/inserting/editable-inline-element.html
-/sdcard/android/layout_tests/editing/inserting/paragraph-separator-01.html
-/sdcard/android/layout_tests/editing/inserting/insert-3851164-fix.html
-/sdcard/android/layout_tests/editing/inserting/5156401-2.html
-/sdcard/android/layout_tests/editing/inserting/4960120-2.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-012.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-024.html
-/sdcard/android/layout_tests/editing/inserting/multiple-lines-selected.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-008.html
-/sdcard/android/layout_tests/editing/inserting/insert-paragraph-05.html
-/sdcard/android/layout_tests/editing/inserting/insert-3778059-fix.html
-/sdcard/android/layout_tests/editing/inserting/return-key-with-selection-001.html
-/sdcard/android/layout_tests/editing/inserting/5607069-3.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-004.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-004.html
-/sdcard/android/layout_tests/editing/inserting/insert-tab-001.html
-/sdcard/android/layout_tests/editing/inserting/4875189-2.html
-/sdcard/android/layout_tests/editing/inserting/5549929-2.html
-/sdcard/android/layout_tests/editing/inserting/editing-empty-divs.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-021.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-005.html
-/sdcard/android/layout_tests/editing/inserting/insert-paragraph-02.html
-/sdcard/android/layout_tests/editing/inserting/insert-3786362-fix.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-017.html
-/sdcard/android/layout_tests/editing/inserting/paragraph-separator-in-table-1.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-at-tabspan-001.html
-/sdcard/android/layout_tests/editing/inserting/insert-space-in-empty-doc.html
-/sdcard/android/layout_tests/editing/inserting/insert-after-delete-001.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-001.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-001.html
-/sdcard/android/layout_tests/editing/inserting/typing-001.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-009.html
-/sdcard/android/layout_tests/editing/inserting/4278698.html
-/sdcard/android/layout_tests/editing/inserting/insert-text-at-tabspan-002.html
-/sdcard/android/layout_tests/editing/inserting/5002441.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-002.html
-/sdcard/android/layout_tests/editing/inserting/paragraph-separator-03.html
-/sdcard/android/layout_tests/editing/inserting/12882.html
-/sdcard/android/layout_tests/editing/inserting/insert-3775316-fix.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-014.html
-/sdcard/android/layout_tests/editing/inserting/edited-whitespace-1.html
-/sdcard/android/layout_tests/editing/inserting/insert-at-end-01.html
-/sdcard/android/layout_tests/editing/inserting/insert-div-026.html
-/sdcard/android/layout_tests/editing/inserting/break-blockquote-after-delete.html
-/sdcard/android/layout_tests/editing/inserting/redo.html
-/sdcard/android/layout_tests/editing/inserting/4840662.html
-/sdcard/android/layout_tests/editing/inserting/typing-around-br-001.html
-/sdcard/android/layout_tests/editing/inserting/return-key-with-selection-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-006.html
-/sdcard/android/layout_tests/editing/inserting/insert-tab-003.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-006.html
-/sdcard/android/layout_tests/editing/execCommand/5142012-1.html
-/sdcard/android/layout_tests/editing/execCommand/hilitecolor.html
-/sdcard/android/layout_tests/editing/execCommand/format-block-with-braces.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-blockquote-test3.html
-/sdcard/android/layout_tests/editing/execCommand/4920742-1.html
-/sdcard/android/layout_tests/editing/execCommand/4924441.html
-/sdcard/android/layout_tests/editing/execCommand/create-list-with-hr.html
-/sdcard/android/layout_tests/editing/execCommand/format-block-with-trailing-br.html
-/sdcard/android/layout_tests/editing/execCommand/remove-formatting-2.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-selection.html
-/sdcard/android/layout_tests/editing/execCommand/strikethroughSelection.html
-/sdcard/android/layout_tests/editing/execCommand/5482023.html
-/sdcard/android/layout_tests/editing/execCommand/4786404-1.html
-/sdcard/android/layout_tests/editing/execCommand/remove-formatting.html
-/sdcard/android/layout_tests/editing/execCommand/findString.html
-/sdcard/android/layout_tests/editing/execCommand/italicizeByCharacter.html
-/sdcard/android/layout_tests/editing/execCommand/create-list-from-range-selection.html
-/sdcard/android/layout_tests/editing/execCommand/5190926.html
-/sdcard/android/layout_tests/editing/execCommand/insertHorizontalRule.html
-/sdcard/android/layout_tests/editing/execCommand/paste-1.html
-/sdcard/android/layout_tests/editing/execCommand/nsresponder-outdent.html
-/sdcard/android/layout_tests/editing/execCommand/toggle-compound-styles.html
-/sdcard/android/layout_tests/editing/execCommand/5080333-2.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-blockquote-test2.html
-/sdcard/android/layout_tests/editing/execCommand/5049671.html
-/sdcard/android/layout_tests/editing/execCommand/4920488.html
-/sdcard/android/layout_tests/editing/execCommand/nsresponder-indent.html
-/sdcard/android/layout_tests/editing/execCommand/indent-list-item.html
-/sdcard/android/layout_tests/editing/execCommand/4916402.html
-/sdcard/android/layout_tests/editing/execCommand/5138441.html
-/sdcard/android/layout_tests/editing/execCommand/insert-list-empty-div.html
-/sdcard/android/layout_tests/editing/execCommand/5481523.html
-/sdcard/android/layout_tests/editing/execCommand/print.html
-/sdcard/android/layout_tests/editing/execCommand/4641880-2.html
-/sdcard/android/layout_tests/editing/execCommand/4580583-2.html
-/sdcard/android/layout_tests/editing/execCommand/remove-list-item-1.html
-/sdcard/android/layout_tests/editing/execCommand/5569741.html
-/sdcard/android/layout_tests/editing/execCommand/findString-2.html
-/sdcard/android/layout_tests/editing/execCommand/modifyForeColorByCharacter.html
-/sdcard/android/layout_tests/editing/execCommand/5142012-2.html
-/sdcard/android/layout_tests/editing/execCommand/find-after-replace.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-blockquote-test4.html
-/sdcard/android/layout_tests/editing/execCommand/format-block.html
-/sdcard/android/layout_tests/editing/execCommand/5080333-1.html
-/sdcard/android/layout_tests/editing/execCommand/remove-list-from-range-selection.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-blockquote-test1.html
-/sdcard/android/layout_tests/editing/execCommand/5136770.html
-/sdcard/android/layout_tests/editing/execCommand/4916541.html
-/sdcard/android/layout_tests/editing/execCommand/4786404-2.html
-/sdcard/android/layout_tests/editing/execCommand/insertImage.html
-/sdcard/android/layout_tests/editing/execCommand/insert-list-and-stitch.html
-/sdcard/android/layout_tests/editing/execCommand/5573879.html
-/sdcard/android/layout_tests/editing/execCommand/4641880-1.html
-/sdcard/android/layout_tests/editing/execCommand/4580583-1.html
-/sdcard/android/layout_tests/editing/execCommand/4747450.html
-/sdcard/android/layout_tests/editing/execCommand/format-block-from-range-selection.html
-/sdcard/android/layout_tests/editing/execCommand/indent-empty-root.html
-/sdcard/android/layout_tests/editing/execCommand/indent-selection.html
-/sdcard/android/layout_tests/editing/execCommand/selectAll.html
-/sdcard/android/layout_tests/editing/execCommand/paste-2.html
-/sdcard/android/layout_tests/editing/pasteboard/subframe-dragndrop-1.html
-/sdcard/android/layout_tests/editing/pasteboard/innerText-inline-table.html
-/sdcard/android/layout_tests/editing/pasteboard/5156401-1.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-list-001.html
-/sdcard/android/layout_tests/editing/pasteboard/4242293-1.html
-/sdcard/android/layout_tests/editing/pasteboard/5032095.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-004.html
-/sdcard/android/layout_tests/editing/pasteboard/5247341.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-4035648-fix.html
-/sdcard/android/layout_tests/editing/pasteboard/4700297.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-003.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-into-blockquote.html
-/sdcard/android/layout_tests/editing/pasteboard/drop-link.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-into-blockquote-3.html
-/sdcard/android/layout_tests/editing/pasteboard/4944770-1.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-015.html
-/sdcard/android/layout_tests/editing/pasteboard/5075944.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-match-style-001.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-4039777-fix.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-3.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-007.html
-/sdcard/android/layout_tests/editing/pasteboard/5483567.html
-/sdcard/android/layout_tests/editing/pasteboard/7955.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-blockquote.html
-/sdcard/android/layout_tests/editing/pasteboard/testcase-9507.html
-/sdcard/android/layout_tests/editing/pasteboard/input-field-1.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-001.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-at-tabspan-001.html
-/sdcard/android/layout_tests/editing/pasteboard/interchange-newline-2.html
-/sdcard/android/layout_tests/editing/pasteboard/block-wrappers-necessary.html
-/sdcard/android/layout_tests/editing/pasteboard/4861080.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-009.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-after-delete.html
-/sdcard/android/layout_tests/editing/pasteboard/5478250.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-012.html
-/sdcard/android/layout_tests/editing/pasteboard/prevent-block-nesting-01.html
-/sdcard/android/layout_tests/editing/pasteboard/8145-2.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-borders.html
-/sdcard/android/layout_tests/editing/pasteboard/5027857.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-004.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-start-list.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-008.html
-/sdcard/android/layout_tests/editing/pasteboard/4806874.html
-/sdcard/android/layout_tests/editing/pasteboard/emacs-ctrl-a-k-y.html
-/sdcard/android/layout_tests/editing/pasteboard/bad-placeholder.html
-/sdcard/android/layout_tests/editing/pasteboard/displaced-placeholder.html
-/sdcard/android/layout_tests/editing/pasteboard/5387578.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-1.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-010.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-006.html
-/sdcard/android/layout_tests/editing/pasteboard/5601583-1.html
-/sdcard/android/layout_tests/editing/pasteboard/4947130.html
-/sdcard/android/layout_tests/editing/pasteboard/pasting-tabs.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-after-delete-2.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-001.html
-/sdcard/android/layout_tests/editing/pasteboard/4076267-2.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-table-001.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-005.html
-/sdcard/android/layout_tests/editing/pasteboard/5089327.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-017.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-5.html
-/sdcard/android/layout_tests/editing/pasteboard/drop-text-without-selection.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-at-tabspan-003.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-003.html
-/sdcard/android/layout_tests/editing/pasteboard/drag-drop-modifies-page.html
-/sdcard/android/layout_tests/editing/pasteboard/emacs-ctrl-k-y-001.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-after-blockquote.html
-/sdcard/android/layout_tests/editing/pasteboard/5071074.html
-/sdcard/android/layout_tests/editing/pasteboard/interchange-newline-4.html
-/sdcard/android/layout_tests/editing/pasteboard/styled-element-markup.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-4038267-fix.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-002.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-into-blockquote-2.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-pre-002.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-014.html
-/sdcard/android/layout_tests/editing/pasteboard/drag-drop-dead-frame.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-2.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-006.html
-/sdcard/android/layout_tests/editing/pasteboard/5368833.html
-/sdcard/android/layout_tests/editing/pasteboard/select-element-1.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-3.html
-/sdcard/android/layout_tests/editing/pasteboard/4641033.html
-/sdcard/android/layout_tests/editing/pasteboard/drag-image-to-contenteditable-in-iframe.html
-/sdcard/android/layout_tests/editing/pasteboard/interchange-newline-1.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-paste-bidi.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-008.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-011.html
-/sdcard/android/layout_tests/editing/pasteboard/8145-1.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-003.html
-/sdcard/android/layout_tests/editing/pasteboard/5075944-3.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-table-003.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-TIFF.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-007.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-019.html
-/sdcard/android/layout_tests/editing/pasteboard/undoable-fragment-removes.html
-/sdcard/android/layout_tests/editing/pasteboard/nested-blocks-with-text-field.html
-/sdcard/android/layout_tests/editing/pasteboard/4989774.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-unrendered-select.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-005.html
-/sdcard/android/layout_tests/editing/pasteboard/emacs-cntl-y-001.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-after-delete-1.html
-/sdcard/android/layout_tests/editing/pasteboard/unrendered-br.html
-/sdcard/android/layout_tests/editing/pasteboard/4631972.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-004.html
-/sdcard/android/layout_tests/editing/pasteboard/quirks-mode-br-1.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-into-blockquote-4.html
-/sdcard/android/layout_tests/editing/pasteboard/4944770-2.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-table-cells.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-016.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-match-style-002.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-4.html
-/sdcard/android/layout_tests/editing/pasteboard/drag-selected-image-to-contenteditable.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-008.html
-/sdcard/android/layout_tests/editing/pasteboard/3976872.html
-/sdcard/android/layout_tests/editing/pasteboard/pasting-object.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-list.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-standalone-image.html
-/sdcard/android/layout_tests/editing/pasteboard/displaced-generic-placeholder.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-002.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-at-tabspan-002.html
-/sdcard/android/layout_tests/editing/pasteboard/interchange-newline-3.html
-/sdcard/android/layout_tests/editing/pasteboard/5071074-2.html
-/sdcard/android/layout_tests/editing/pasteboard/display-block-on-spans.html
-/sdcard/android/layout_tests/editing/pasteboard/4242293.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-001.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-pre-001.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-start-blockquote.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-1.html
-/sdcard/android/layout_tests/editing/pasteboard/8145-3.html
-/sdcard/android/layout_tests/editing/pasteboard/5006779.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-005.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-009.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-blockquote-2.html
-/sdcard/android/layout_tests/editing/pasteboard/merge-end-table.html
-/sdcard/android/layout_tests/editing/pasteboard/5065605.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-line-endings-007.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-010.html
-/sdcard/android/layout_tests/editing/pasteboard/5028447.html
-/sdcard/android/layout_tests/editing/pasteboard/nested-blocks-with-text-area.html
-/sdcard/android/layout_tests/editing/pasteboard/4076267-3.html
-/sdcard/android/layout_tests/editing/pasteboard/4076267.html
-/sdcard/android/layout_tests/editing/pasteboard/smart-paste-002.html
-/sdcard/android/layout_tests/editing/pasteboard/5075944-2.html
-/sdcard/android/layout_tests/editing/pasteboard/5134759.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-006.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-text-018.html
-/sdcard/android/layout_tests/editing/pasteboard/paste-RTFD.html
-/sdcard/android/layout_tests/editing/pasteboard/cut-text-001.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-9.html
-/sdcard/android/layout_tests/editing/selection/fake-drag.html
-/sdcard/android/layout_tests/editing/selection/wrapped-line-caret-2.html
-/sdcard/android/layout_tests/editing/selection/unrendered-002.html
-/sdcard/android/layout_tests/editing/selection/3690703-2.html
-/sdcard/android/layout_tests/editing/selection/extend-by-character-005.html
-/sdcard/android/layout_tests/editing/selection/caret-rtl-2.html
-/sdcard/android/layout_tests/editing/selection/paragraph-granularity.html
-/sdcard/android/layout_tests/editing/selection/clear-selection.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-6.html
-/sdcard/android/layout_tests/editing/selection/drag-in-iframe.html
-/sdcard/android/layout_tests/editing/selection/unrendered-space.html
-/sdcard/android/layout_tests/editing/selection/extend-by-character-002.html
-/sdcard/android/layout_tests/editing/selection/4932260-2.html
-/sdcard/android/layout_tests/editing/selection/select-element-paragraph-boundary.html
-/sdcard/android/layout_tests/editing/selection/extend-by-sentence-001.html
-/sdcard/android/layout_tests/editing/selection/3690719.html
-/sdcard/android/layout_tests/editing/selection/editable-non-editable-crash.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-3.html
-/sdcard/android/layout_tests/editing/selection/replaced-boundaries-3.html
-/sdcard/android/layout_tests/editing/selection/move-by-sentence-linebreak.html
-/sdcard/android/layout_tests/editing/selection/move-by-character-005.html
-/sdcard/android/layout_tests/editing/selection/end-of-document.html
-/sdcard/android/layout_tests/editing/selection/selectNode.html
-/sdcard/android/layout_tests/editing/selection/editable-links.html
-/sdcard/android/layout_tests/editing/selection/extend-by-word-002.html
-/sdcard/android/layout_tests/editing/selection/move-by-character-002.html
-/sdcard/android/layout_tests/editing/selection/14971.html
-/sdcard/android/layout_tests/editing/selection/5131716-2.html
-/sdcard/android/layout_tests/editing/selection/5081257-1.html
-/sdcard/android/layout_tests/editing/selection/move-3875641-fix.html
-/sdcard/android/layout_tests/editing/selection/5099303.html
-/sdcard/android/layout_tests/editing/selection/move-by-line-002.html
-/sdcard/android/layout_tests/editing/selection/select-missing-image.html
-/sdcard/android/layout_tests/editing/selection/selection-3748164-fix.html
-/sdcard/android/layout_tests/editing/selection/4983858.html
-/sdcard/android/layout_tests/editing/selection/move-by-sentence-001.html
-/sdcard/android/layout_tests/editing/selection/table-caret-1.html
-/sdcard/android/layout_tests/editing/selection/move-by-word-001.html
-/sdcard/android/layout_tests/editing/selection/select-all-004.html
-/sdcard/android/layout_tests/editing/selection/5076323-2.html
-/sdcard/android/layout_tests/editing/selection/move-3875618-fix.html
-/sdcard/android/layout_tests/editing/selection/inline-table.html
-/sdcard/android/layout_tests/editing/selection/4895428-3.html
-/sdcard/android/layout_tests/editing/selection/caret-before-select.html
-/sdcard/android/layout_tests/editing/selection/select-all-001.html
-/sdcard/android/layout_tests/editing/selection/unrendered-003.html
-/sdcard/android/layout_tests/editing/selection/extend-by-character-006.html
-/sdcard/android/layout_tests/editing/selection/7152-1.html
-/sdcard/android/layout_tests/editing/selection/iframe.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-7.html
-/sdcard/android/layout_tests/editing/selection/select-all-iframe.html
-/sdcard/android/layout_tests/editing/selection/extend-by-character-003.html
-/sdcard/android/layout_tests/editing/selection/4932260-3.html
-/sdcard/android/layout_tests/editing/selection/4960116.html
-/sdcard/android/layout_tests/editing/selection/drag-to-contenteditable-iframe.html
-/sdcard/android/layout_tests/editing/selection/selectNodeContents.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-4.html
-/sdcard/android/layout_tests/editing/selection/focus-body.html
-/sdcard/android/layout_tests/editing/selection/designmode-no-caret.html
-/sdcard/android/layout_tests/editing/selection/5234383-1.html
-/sdcard/android/layout_tests/editing/selection/5232159.html
-/sdcard/android/layout_tests/editing/selection/4960137.html
-/sdcard/android/layout_tests/editing/selection/previous-line-position.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-1.html
-/sdcard/android/layout_tests/editing/selection/replaced-boundaries-1.html
-/sdcard/android/layout_tests/editing/selection/move-by-character-003.html
-/sdcard/android/layout_tests/editing/selection/4776665.html
-/sdcard/android/layout_tests/editing/selection/move-by-character-6.html
-/sdcard/android/layout_tests/editing/selection/image-before-linebreak.html
-/sdcard/android/layout_tests/editing/selection/move-between-blocks-no-001.html
-/sdcard/android/layout_tests/editing/selection/5131716-3.html
-/sdcard/android/layout_tests/editing/selection/5081257-2.html
-/sdcard/android/layout_tests/editing/selection/5354455-1.html
-/sdcard/android/layout_tests/editing/selection/expanding-selections2.html
-/sdcard/android/layout_tests/editing/selection/display-table-text.html
-/sdcard/android/layout_tests/editing/selection/13804.html
-/sdcard/android/layout_tests/editing/selection/table-caret-2.html
-/sdcard/android/layout_tests/editing/selection/expanding-selections.html
-/sdcard/android/layout_tests/editing/selection/node-removal-1.html
-/sdcard/android/layout_tests/editing/selection/5240265.html
-/sdcard/android/layout_tests/editing/selection/select-all-005.html
-/sdcard/android/layout_tests/editing/selection/5076323-3.html
-/sdcard/android/layout_tests/editing/selection/line-wrap-1.html
-/sdcard/android/layout_tests/editing/selection/replace-selection-1.html
-/sdcard/android/layout_tests/editing/selection/caret-rtl.html
-/sdcard/android/layout_tests/editing/selection/5109817.html
-/sdcard/android/layout_tests/editing/selection/5136696.html
-/sdcard/android/layout_tests/editing/selection/4397952.html
-/sdcard/android/layout_tests/editing/selection/caret-and-focus-ring.html
-/sdcard/android/layout_tests/editing/selection/4895428-4.html
-/sdcard/android/layout_tests/editing/selection/4947387.html
-/sdcard/android/layout_tests/editing/selection/select-from-textfield-outwards.html
-/sdcard/android/layout_tests/editing/selection/leave-requested-block.html
-/sdcard/android/layout_tests/editing/selection/select-all-002.html
-/sdcard/android/layout_tests/editing/selection/unrendered-004.html
-/sdcard/android/layout_tests/editing/selection/7152-2.html
-/sdcard/android/layout_tests/editing/selection/5195166-1.html
-/sdcard/android/layout_tests/editing/selection/editable-html-element.html
-/sdcard/android/layout_tests/editing/selection/4866671.html
-/sdcard/android/layout_tests/editing/selection/4895428-1.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-8.html
-/sdcard/android/layout_tests/editing/selection/wrapped-line-caret-1.html
-/sdcard/android/layout_tests/editing/selection/selection-actions.html
-/sdcard/android/layout_tests/editing/selection/4402375.html
-/sdcard/android/layout_tests/editing/selection/unrendered-001.html
-/sdcard/android/layout_tests/editing/selection/extend-by-character-004.html
-/sdcard/android/layout_tests/editing/selection/contenteditable-click-inside.html
-/sdcard/android/layout_tests/editing/selection/addRange.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-5.html
-/sdcard/android/layout_tests/editing/selection/5007143.html
-/sdcard/android/layout_tests/editing/selection/fake-doubleclick.html
-/sdcard/android/layout_tests/editing/selection/extend-by-character-001.html
-/sdcard/android/layout_tests/editing/selection/4932260-1.html
-/sdcard/android/layout_tests/editing/selection/5234383-2.html
-/sdcard/android/layout_tests/editing/selection/5057506.html
-/sdcard/android/layout_tests/editing/selection/focus_editable_html.html
-/sdcard/android/layout_tests/editing/selection/4818145.html
-/sdcard/android/layout_tests/editing/selection/move-backwords-by-word-001.html
-/sdcard/android/layout_tests/editing/selection/mixed-editability-2.html
-/sdcard/android/layout_tests/editing/selection/replaced-boundaries-2.html
-/sdcard/android/layout_tests/editing/selection/move-by-character-004.html
-/sdcard/android/layout_tests/editing/selection/4889598.html
-/sdcard/android/layout_tests/editing/selection/5131716-4.html
-/sdcard/android/layout_tests/editing/selection/3690703.html
-/sdcard/android/layout_tests/editing/selection/5333725.html
-/sdcard/android/layout_tests/editing/selection/5354455-2.html
-/sdcard/android/layout_tests/editing/selection/selection-background.html
-/sdcard/android/layout_tests/editing/selection/extend-by-word-001.html
-/sdcard/android/layout_tests/editing/selection/move-by-character-001.html
-/sdcard/android/layout_tests/editing/selection/doubleclick-crash.html
-/sdcard/android/layout_tests/editing/selection/table-caret-3.html
-/sdcard/android/layout_tests/editing/selection/5131716-1.html
-/sdcard/android/layout_tests/editing/selection/node-removal-2.html
-/sdcard/android/layout_tests/editing/selection/drag-select-1.html
-/sdcard/android/layout_tests/editing/selection/select-all-006.html
-/sdcard/android/layout_tests/editing/selection/after-line-wrap.html
-/sdcard/android/layout_tests/editing/selection/line-wrap-2.html
-/sdcard/android/layout_tests/editing/selection/move-by-line-001.html
-/sdcard/android/layout_tests/editing/selection/move-between-blocks-yes-001.html
-/sdcard/android/layout_tests/editing/selection/6476.html
-/sdcard/android/layout_tests/editing/selection/contains-boundaries.html
-/sdcard/android/layout_tests/editing/selection/click-start-of-line.html
-/sdcard/android/layout_tests/editing/selection/triple-click-in-pre.html
-/sdcard/android/layout_tests/editing/selection/move-past-trailing-space.html
-/sdcard/android/layout_tests/editing/selection/inline-closest-leaf-child.html
-/sdcard/android/layout_tests/editing/selection/5007143-2.html
-/sdcard/android/layout_tests/editing/selection/select-all-003.html
-/sdcard/android/layout_tests/editing/selection/5076323-1.html
-/sdcard/android/layout_tests/editing/selection/5057506-2.html
-/sdcard/android/layout_tests/editing/selection/4975120.html
-/sdcard/android/layout_tests/editing/selection/unrendered-005.html
-/sdcard/android/layout_tests/editing/selection/5195166-2.html
-/sdcard/android/layout_tests/editing/selection/select-box.html
-/sdcard/android/layout_tests/editing/selection/4895428-2.html
-/sdcard/android/layout_tests/editing/selection/word-granularity.html
-/sdcard/android/layout_tests/editing/undo/undo-misspellings.html
-/sdcard/android/layout_tests/editing/undo/undo-combined-delete.html
-/sdcard/android/layout_tests/editing/undo/undo-delete-boundary.html
-/sdcard/android/layout_tests/editing/undo/undo-forward-delete-boundary.html
-/sdcard/android/layout_tests/editing/undo/4063751.html
-/sdcard/android/layout_tests/editing/undo/redo-typing-001.html
-/sdcard/android/layout_tests/editing/undo/5378473.html
-/sdcard/android/layout_tests/editing/undo/undo-combined-delete-boundary.html
-/sdcard/android/layout_tests/editing/undo/undo-delete.html
-/sdcard/android/layout_tests/editing/undo/undo-forward-delete.html
-/sdcard/android/layout_tests/editing/undo/undo-typing-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-3608462-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-image-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-3928305-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-012.html
-/sdcard/android/layout_tests/editing/deleting/5115601.html
-/sdcard/android/layout_tests/editing/deleting/deletionUI-single-instance.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-contents-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-024.html
-/sdcard/android/layout_tests/editing/deleting/delete-after-span-ws-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-011.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-008.html
-/sdcard/android/layout_tests/editing/deleting/delete-listitem-001.html
-/sdcard/android/layout_tests/editing/deleting/5300379.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-007.html
-/sdcard/android/layout_tests/editing/deleting/5433862-2.html
-/sdcard/android/layout_tests/editing/deleting/5026848-1.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-012.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-008.html
-/sdcard/android/layout_tests/editing/deleting/5206311-2.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-start-or-end.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-021.html
-/sdcard/android/layout_tests/editing/deleting/delete-ws-fixup-004.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-005.html
-/sdcard/android/layout_tests/editing/deleting/delete-select-all-003.html
-/sdcard/android/layout_tests/editing/deleting/smart-delete-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-017.html
-/sdcard/android/layout_tests/editing/deleting/table-cells.html
-/sdcard/android/layout_tests/editing/deleting/5156801-2.html
-/sdcard/android/layout_tests/editing/deleting/delete-leading-ws-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-004.html
-/sdcard/android/layout_tests/editing/deleting/delete-3857753-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-3959464-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-016.html
-/sdcard/android/layout_tests/editing/deleting/delete-trailing-ws-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-005.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-008.html
-/sdcard/android/layout_tests/editing/deleting/delete-tab-004.html
-/sdcard/android/layout_tests/editing/deleting/merge-whitespace-pre.html
-/sdcard/android/layout_tests/editing/deleting/delete-ws-fixup-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-end-ws-002.html
-/sdcard/android/layout_tests/editing/deleting/merge-unrendered-space.html
-/sdcard/android/layout_tests/editing/deleting/delete-by-word-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-image-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-selection-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-014.html
-/sdcard/android/layout_tests/editing/deleting/merge-different-styles.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-contents-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-after-span-ws-003.html
-/sdcard/android/layout_tests/editing/deleting/merge-into-empty-block-1.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-013.html
-/sdcard/android/layout_tests/editing/deleting/delete-3865854-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-009.html
-/sdcard/android/layout_tests/editing/deleting/5026848-3.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-005.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-tab-001.html
-/sdcard/android/layout_tests/editing/deleting/whitespace-pre-1.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-table.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-011.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-023.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-010.html
-/sdcard/android/layout_tests/editing/deleting/5032066.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-007.html
-/sdcard/android/layout_tests/editing/deleting/smart-delete-004.html
-/sdcard/android/layout_tests/editing/deleting/5144139-2.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-019.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-006.html
-/sdcard/android/layout_tests/editing/deleting/5126166.html
-/sdcard/android/layout_tests/editing/deleting/delete-to-end-of-paragraph.html
-/sdcard/android/layout_tests/editing/deleting/5408255.html
-/sdcard/android/layout_tests/editing/deleting/5099303.html
-/sdcard/android/layout_tests/editing/deleting/4845371.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-002.html
-/sdcard/android/layout_tests/editing/deleting/4922367.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-011.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-007.html
-/sdcard/android/layout_tests/editing/deleting/move-nodes-001.html
-/sdcard/android/layout_tests/editing/deleting/merge-no-br.html
-/sdcard/android/layout_tests/editing/deleting/delete-3800834-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-4038408-fix.html
-/sdcard/android/layout_tests/editing/deleting/5206311-1.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-020.html
-/sdcard/android/layout_tests/editing/deleting/delete-ws-fixup-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-004.html
-/sdcard/android/layout_tests/editing/deleting/delete-select-all-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-contiguous-ws-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-to-select-table.html
-/sdcard/android/layout_tests/editing/deleting/smart-delete-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-016.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-015.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-011.html
-/sdcard/android/layout_tests/editing/deleting/5390681.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-004.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-007.html
-/sdcard/android/layout_tests/editing/deleting/forward-delete.html
-/sdcard/android/layout_tests/editing/deleting/delete-tab-003.html
-/sdcard/android/layout_tests/editing/deleting/collapse-whitespace-3587601-fix.html
-/sdcard/android/layout_tests/editing/deleting/pruning-after-merge-2.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-end-ws-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-by-word-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-image-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-013.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-contents-002.html
-/sdcard/android/layout_tests/editing/deleting/paragraph-in-preserveNewline.html
-/sdcard/android/layout_tests/editing/deleting/delete-after-span-ws-002.html
-/sdcard/android/layout_tests/editing/deleting/5272440.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-012.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-009.html
-/sdcard/android/layout_tests/editing/deleting/delete-listitem-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-character-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-008.html
-/sdcard/android/layout_tests/editing/deleting/5483370.html
-/sdcard/android/layout_tests/editing/deleting/5026848-2.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-004.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-013.html
-/sdcard/android/layout_tests/editing/deleting/5091898.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-009.html
-/sdcard/android/layout_tests/editing/deleting/transpose-empty.html
-/sdcard/android/layout_tests/editing/deleting/merge-endOfParagraph.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-010.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-022.html
-/sdcard/android/layout_tests/editing/deleting/delete-3775172-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-mixed-editable-content-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-006.html
-/sdcard/android/layout_tests/editing/deleting/smart-delete-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-018.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-005.html
-/sdcard/android/layout_tests/editing/deleting/delete-first-list-item.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-017.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-trailing-ws-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-010.html
-/sdcard/android/layout_tests/editing/deleting/delete-and-undo.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-006.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-009.html
-/sdcard/android/layout_tests/editing/deleting/delete-hr.html
-/sdcard/android/layout_tests/editing/deleting/delete-4083333-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-3608445-fix.html
-/sdcard/android/layout_tests/editing/deleting/delete-ws-fixup-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-image-004.html
-/sdcard/android/layout_tests/editing/deleting/delete-select-all-001.html
-/sdcard/android/layout_tests/editing/deleting/delete-block-merge-contents-015.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-002.html
-/sdcard/android/layout_tests/editing/deleting/delete-line-014.html
-/sdcard/android/layout_tests/editing/deleting/merge-into-empty-block-2.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-010.html
-/sdcard/android/layout_tests/editing/deleting/5390681-2.html
-/sdcard/android/layout_tests/editing/deleting/5369009.html
-/sdcard/android/layout_tests/editing/deleting/delete-br-003.html
-/sdcard/android/layout_tests/editing/deleting/delete-at-paragraph-boundaries-006.html
-/sdcard/android/layout_tests/editing/deleting/delete-tab-002.html
-/sdcard/android/layout_tests/editing/deleting/list-item-1.html
-/sdcard/android/layout_tests/editing/deleting/5168598.html
-/sdcard/android/layout_tests/editing/deleting/delete-3608430-fix.html
-/sdcard/android/layout_tests/editing/deleting/type-delete-after-quote.html
-/sdcard/android/layout_tests/editing/spelling/spelling.html
-/sdcard/android/layout_tests/editing/spelling/spellcheck-attribute.html
-/sdcard/android/layout_tests/editing/spelling/inline_spelling_markers.html
-/sdcard/android/layout_tests/editing/spelling/spelling-linebreak.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-05.html
-/sdcard/android/layout_tests/fast/media/mq-grid-02.html
-/sdcard/android/layout_tests/fast/media/mq-compound-query-02.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-09.html
-/sdcard/android/layout_tests/fast/media/mq-width-absolute-03.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-02.html
-/sdcard/android/layout_tests/fast/media/mq-simple-query-04.html
-/sdcard/android/layout_tests/fast/media/mq-min-pixel-ratio.html
-/sdcard/android/layout_tests/fast/media/implicit-media-all.html
-/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-01.html
-/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-03.html
-/sdcard/android/layout_tests/fast/media/viewport-media-query.html
-/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-05.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-01.html
-/sdcard/android/layout_tests/fast/media/mq-transition.html
-/sdcard/android/layout_tests/fast/media/mq-orientation.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-05.html
-/sdcard/android/layout_tests/fast/media/mq-transform-04.html
-/sdcard/android/layout_tests/fast/media/mq-js-media-except-02.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-02.html
-/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-03.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-06.html
-/sdcard/android/layout_tests/fast/media/mq-valueless.html
-/sdcard/android/layout_tests/fast/media/mq-compound-query-03.html
-/sdcard/android/layout_tests/fast/media/mq-simple-query-01.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-03.html
-/sdcard/android/layout_tests/fast/media/mq-width-absolute-04.html
-/sdcard/android/layout_tests/fast/media/mq-simple-query-05.html
-/sdcard/android/layout_tests/fast/media/mq-animation.html
-/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-02.html
-/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-04.html
-/sdcard/android/layout_tests/fast/media/media-type-syntax-01.html
-/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-06.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-02.html
-/sdcard/android/layout_tests/fast/media/mq-transform-01.html
-/sdcard/android/layout_tests/fast/media/monochrome.html
-/sdcard/android/layout_tests/fast/media/mq-pixel-ratio.html
-/sdcard/android/layout_tests/fast/media/mq-js-media-except-03.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-03.html
-/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-04.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-07.html
-/sdcard/android/layout_tests/fast/media/mq-compound-query-04.html
-/sdcard/android/layout_tests/fast/media/mq-width-absolute-01.html
-/sdcard/android/layout_tests/fast/media/mq-simple-query-02.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-04.html
-/sdcard/android/layout_tests/fast/media/mq-max-pixel-ratio.html
-/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-01.html
-/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-03.html
-/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-05.html
-/sdcard/android/layout_tests/fast/media/media-type-syntax-02.html
-/sdcard/android/layout_tests/fast/media/mq-transform-02.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-03.html
-/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-01.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-04.html
-/sdcard/android/layout_tests/fast/media/mq-grid-01.html
-/sdcard/android/layout_tests/fast/media/mq-compound-query-01.html
-/sdcard/android/layout_tests/fast/media/mq-min-constraint.html
-/sdcard/android/layout_tests/fast/media/mq-relative-constraints-08.html
-/sdcard/android/layout_tests/fast/media/mq-compound-query-05.html
-/sdcard/android/layout_tests/fast/media/mq-width-absolute-02.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-01.html
-/sdcard/android/layout_tests/fast/media/mq-simple-query-03.html
-/sdcard/android/layout_tests/fast/media/mq-js-media-forward-syntax.html
-/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-02.html
-/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-04.html
-/sdcard/android/layout_tests/fast/media/mq-aspect-ratio.html
-/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-04.html
-/sdcard/android/layout_tests/fast/media/mq-transform-03.html
-/sdcard/android/layout_tests/fast/media/mq-js-media-except-01.html
-/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-02.html
-/sdcard/android/layout_tests/fast/replaced/embed-display-none.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-radio.html
-/sdcard/android/layout_tests/fast/replaced/selection-rect.html
-/sdcard/android/layout_tests/fast/replaced/applet-display-none.html
-/sdcard/android/layout_tests/fast/replaced/inline-box-wrapper-handover.html
-/sdcard/android/layout_tests/fast/replaced/maxheight-pxs.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-searchfield.html
-/sdcard/android/layout_tests/fast/replaced/selection-rect-transform.html
-/sdcard/android/layout_tests/fast/replaced/minwidth-pxs.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-textarea.html
-/sdcard/android/layout_tests/fast/replaced/maxwidth-pxs.html
-/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-height.html
-/sdcard/android/layout_tests/fast/replaced/004.html
-/sdcard/android/layout_tests/fast/replaced/applet-disabled-positioned.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-checkbox.html
-/sdcard/android/layout_tests/fast/replaced/008.html
-/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block-widget.html
-/sdcard/android/layout_tests/fast/replaced/maxheight-percent.html
-/sdcard/android/layout_tests/fast/replaced/minwidth-percent.html
-/sdcard/android/layout_tests/fast/replaced/maxwidth-percent.html
-/sdcard/android/layout_tests/fast/replaced/applet-rendering-java-disabled.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-button.html
-/sdcard/android/layout_tests/fast/replaced/image-resize-width.html
-/sdcard/android/layout_tests/fast/replaced/absolute-image-sizing.html
-/sdcard/android/layout_tests/fast/replaced/001.html
-/sdcard/android/layout_tests/fast/replaced/005.html
-/sdcard/android/layout_tests/fast/replaced/object-display-none.html
-/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-width.html
-/sdcard/android/layout_tests/fast/replaced/object-align-hspace-vspace.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-menulist.html
-/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block-in-table.html
-/sdcard/android/layout_tests/fast/replaced/image-sizing.html
-/sdcard/android/layout_tests/fast/replaced/minheight-pxs.html
-/sdcard/android/layout_tests/fast/replaced/pdf-as-image.html
-/sdcard/android/layout_tests/fast/replaced/replaced-breaking-mixture.html
-/sdcard/android/layout_tests/fast/replaced/max-width-percent.html
-/sdcard/android/layout_tests/fast/replaced/002.html
-/sdcard/android/layout_tests/fast/replaced/006.html
-/sdcard/android/layout_tests/fast/replaced/minheight-percent.html
-/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-width-and-left-and-right.html
-/sdcard/android/layout_tests/fast/replaced/selection-rect-in-table-cell.html
-/sdcard/android/layout_tests/fast/replaced/border-radius-clip.html
-/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block.html
-/sdcard/android/layout_tests/fast/replaced/three-selects-break.html
-/sdcard/android/layout_tests/fast/replaced/image-tag.html
-/sdcard/android/layout_tests/fast/replaced/image-onload.html
-/sdcard/android/layout_tests/fast/replaced/replaced-breaking.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-image.html
-/sdcard/android/layout_tests/fast/replaced/image-solid-color-with-alpha.html
-/sdcard/android/layout_tests/fast/replaced/003.html
-/sdcard/android/layout_tests/fast/replaced/replaced-child-of-absolute-with-auto-height.html
-/sdcard/android/layout_tests/fast/replaced/007.html
-/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-height-and-top-and-bottom.html
-/sdcard/android/layout_tests/fast/replaced/width100percent-textfield.html
-/sdcard/android/layout_tests/fast/dynamic/positioned-movement-with-positioned-children.html
-/sdcard/android/layout_tests/fast/dynamic/subtree-table-cell-height.html
-/sdcard/android/layout_tests/fast/dynamic/move-node-with-selection.html
-/sdcard/android/layout_tests/fast/dynamic/create-renderer-for-whitespace-only-text.html
-/sdcard/android/layout_tests/fast/dynamic/outerHTML-doc.html
-/sdcard/android/layout_tests/fast/dynamic/window-scrollbars-test.html
-/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned-2.html
-/sdcard/android/layout_tests/fast/dynamic/anchor-lock.html
-/sdcard/android/layout_tests/fast/dynamic/012.html
-/sdcard/android/layout_tests/fast/dynamic/004.html
-/sdcard/android/layout_tests/fast/dynamic/008.html
-/sdcard/android/layout_tests/fast/dynamic/float-no-longer-overhanging.html
-/sdcard/android/layout_tests/fast/dynamic/float-withdrawal-2.html
-/sdcard/android/layout_tests/fast/dynamic/float-in-trailing-whitespace-after-last-line-break.html
-/sdcard/android/layout_tests/fast/dynamic/selection-highlight-adjust.html
-/sdcard/android/layout_tests/fast/dynamic/subtree-no-common-root-static-y.html
-/sdcard/android/layout_tests/fast/dynamic/genContentDestroyChildren.html
-/sdcard/android/layout_tests/fast/dynamic/001.html
-/sdcard/android/layout_tests/fast/dynamic/link-href-change.html
-/sdcard/android/layout_tests/fast/dynamic/013.html
-/sdcard/android/layout_tests/fast/dynamic/005.html
-/sdcard/android/layout_tests/fast/dynamic/009.html
-/sdcard/android/layout_tests/fast/dynamic/float-withdrawal.html
-/sdcard/android/layout_tests/fast/dynamic/anonymous-block-layer-lost.html
-/sdcard/android/layout_tests/fast/dynamic/layer-hit-test-crash.html
-/sdcard/android/layout_tests/fast/dynamic/view-overflow.html
-/sdcard/android/layout_tests/fast/dynamic/window-resize-scrollbars-test.html
-/sdcard/android/layout_tests/fast/dynamic/010.html
-/sdcard/android/layout_tests/fast/dynamic/002.html
-/sdcard/android/layout_tests/fast/dynamic/014.html
-/sdcard/android/layout_tests/fast/dynamic/006.html
-/sdcard/android/layout_tests/fast/dynamic/flash-replacement-test.html
-/sdcard/android/layout_tests/fast/dynamic/insertAdjacentElement.html
-/sdcard/android/layout_tests/fast/dynamic/insert-before-table-part-in-continuation.html
-/sdcard/android/layout_tests/fast/dynamic/staticY.html
-/sdcard/android/layout_tests/fast/dynamic/anonymous-block-orphaned-lines.html
-/sdcard/android/layout_tests/fast/dynamic/noninlinebadness.html
-/sdcard/android/layout_tests/fast/dynamic/subtree-parent-static-y.html
-/sdcard/android/layout_tests/fast/dynamic/outerHTML-img.html
-/sdcard/android/layout_tests/fast/dynamic/staticY-marking-parents-regression.html
-/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned.html
-/sdcard/android/layout_tests/fast/dynamic/subtree-boundary-percent-height.html
-/sdcard/android/layout_tests/fast/dynamic/011.html
-/sdcard/android/layout_tests/fast/dynamic/containing-block-change.html
-/sdcard/android/layout_tests/fast/dynamic/015.html
-/sdcard/android/layout_tests/fast/dynamic/007.html
-/sdcard/android/layout_tests/fast/text/firstline/001.html
-/sdcard/android/layout_tests/fast/text/firstline/002.html
-/sdcard/android/layout_tests/fast/text/firstline/003.html
-/sdcard/android/layout_tests/fast/text/international/hindi-spacing.html
-/sdcard/android/layout_tests/fast/text/international/bidi-L2-run-reordering.html
-/sdcard/android/layout_tests/fast/text/international/bidi-override.html
-/sdcard/android/layout_tests/fast/text/international/hindi-whitespace.html
-/sdcard/android/layout_tests/fast/text/international/bidi-european-terminators.html
-/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-formatting-characters.html
-/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-L.html
-/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-CSS.html
-/sdcard/android/layout_tests/fast/text/international/bidi-control-chars-treated-as-ZWS.html
-/sdcard/android/layout_tests/fast/text/international/bidi-neutral-directionality-paragraph-start.html
-/sdcard/android/layout_tests/fast/text/international/bidi-linebreak-001.html
-/sdcard/android/layout_tests/fast/text/international/bidi-linebreak-003.html
-/sdcard/android/layout_tests/fast/text/international/002.html
-/sdcard/android/layout_tests/fast/text/international/bidi-explicit-embedding.html
-/sdcard/android/layout_tests/fast/text/international/rtl-white-space-pre-wrap.html
-/sdcard/android/layout_tests/fast/text/international/bidi-CS-after-AN.html
-/sdcard/android/layout_tests/fast/text/international/complex-character-based-fallback.html
-/sdcard/android/layout_tests/fast/text/international/wrap-CJK-001.html
-/sdcard/android/layout_tests/fast/text/international/bidi-listbox-atsui.html
-/sdcard/android/layout_tests/fast/text/international/thai-line-breaks.html
-/sdcard/android/layout_tests/fast/text/international/bidi-neutral-run.html
-/sdcard/android/layout_tests/fast/text/international/bidi-innertext.html
-/sdcard/android/layout_tests/fast/text/international/bidi-listbox.html
-/sdcard/android/layout_tests/fast/text/international/khmer-selection.html
-/sdcard/android/layout_tests/fast/text/international/thai-baht-space.html
-/sdcard/android/layout_tests/fast/text/international/rtl-caret.html
-/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-empty-run.html
-/sdcard/android/layout_tests/fast/text/international/001.html
-/sdcard/android/layout_tests/fast/text/international/bidi-linebreak-002.html
-/sdcard/android/layout_tests/fast/text/international/danda-space.html
-/sdcard/android/layout_tests/fast/text/international/003.html
-/sdcard/android/layout_tests/fast/text/international/bidi-ignored-for-first-child-inline.html
-/sdcard/android/layout_tests/fast/text/international/bidi-layout-across-linebreak.html
-/sdcard/android/layout_tests/fast/text/international/bidi-menulist.html
-/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-HTML.html
-/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-overflow-selection.html
-/sdcard/android/layout_tests/fast/text/whitespace/pre-newline-box-test.html
-/sdcard/android/layout_tests/fast/text/whitespace/span-in-word-space-causes-overflow.html
-/sdcard/android/layout_tests/fast/text/whitespace/nowrap-clear-float.html
-/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-line-test.html
-/sdcard/android/layout_tests/fast/text/whitespace/010.html
-/sdcard/android/layout_tests/fast/text/whitespace/020.html
-/sdcard/android/layout_tests/fast/text/whitespace/002.html
-/sdcard/android/layout_tests/fast/text/whitespace/030.html
-/sdcard/android/layout_tests/fast/text/whitespace/012.html
-/sdcard/android/layout_tests/fast/text/whitespace/022.html
-/sdcard/android/layout_tests/fast/text/whitespace/004.html
-/sdcard/android/layout_tests/fast/text/whitespace/014.html
-/sdcard/android/layout_tests/fast/text/whitespace/024.html
-/sdcard/android/layout_tests/fast/text/whitespace/006.html
-/sdcard/android/layout_tests/fast/text/whitespace/016.html
-/sdcard/android/layout_tests/fast/text/whitespace/008.html
-/sdcard/android/layout_tests/fast/text/whitespace/026.html
-/sdcard/android/layout_tests/fast/text/whitespace/018.html
-/sdcard/android/layout_tests/fast/text/whitespace/028.html
-/sdcard/android/layout_tests/fast/text/whitespace/normal-after-nowrap-breaking.html
-/sdcard/android/layout_tests/fast/text/whitespace/pre-break-word.html
-/sdcard/android/layout_tests/fast/text/whitespace/nbsp-mode-and-linewraps.html
-/sdcard/android/layout_tests/fast/text/whitespace/001.html
-/sdcard/android/layout_tests/fast/text/whitespace/011.html
-/sdcard/android/layout_tests/fast/text/whitespace/tab-character-basics.html
-/sdcard/android/layout_tests/fast/text/whitespace/003.html
-/sdcard/android/layout_tests/fast/text/whitespace/021.html
-/sdcard/android/layout_tests/fast/text/whitespace/013.html
-/sdcard/android/layout_tests/fast/text/whitespace/023.html
-/sdcard/android/layout_tests/fast/text/whitespace/005.html
-/sdcard/android/layout_tests/fast/text/whitespace/015.html
-/sdcard/android/layout_tests/fast/text/whitespace/025.html
-/sdcard/android/layout_tests/fast/text/whitespace/007.html
-/sdcard/android/layout_tests/fast/text/whitespace/017.html
-/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html
-/sdcard/android/layout_tests/fast/text/whitespace/027.html
-/sdcard/android/layout_tests/fast/text/whitespace/009.html
-/sdcard/android/layout_tests/fast/text/whitespace/019.html
-/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-last-char.html
-/sdcard/android/layout_tests/fast/text/whitespace/029.html
-/sdcard/android/layout_tests/fast/text/basic/001.html
-/sdcard/android/layout_tests/fast/text/basic/002.html
-/sdcard/android/layout_tests/fast/text/basic/011.html
-/sdcard/android/layout_tests/fast/text/basic/generic-family-changes.html
-/sdcard/android/layout_tests/fast/text/basic/003.html
-/sdcard/android/layout_tests/fast/text/basic/012.html
-/sdcard/android/layout_tests/fast/text/basic/004.html
-/sdcard/android/layout_tests/fast/text/basic/013.html
-/sdcard/android/layout_tests/fast/text/basic/005.html
-/sdcard/android/layout_tests/fast/text/basic/014.html
-/sdcard/android/layout_tests/fast/text/basic/006.html
-/sdcard/android/layout_tests/fast/text/basic/015.html
-/sdcard/android/layout_tests/fast/text/basic/007.html
-/sdcard/android/layout_tests/fast/text/basic/008.html
-/sdcard/android/layout_tests/fast/text/basic/009.html
-/sdcard/android/layout_tests/fast/text/basic/generic-family-reset.html
-/sdcard/android/layout_tests/fast/text/in-rendered-text-rtl.html
-/sdcard/android/layout_tests/fast/text/selection-painted-separately.html
-/sdcard/android/layout_tests/fast/text/bidi-embedding-pop-and-push-same.html
-/sdcard/android/layout_tests/fast/text/wbr-in-pre-crash.html
-/sdcard/android/layout_tests/fast/text/atsui-spacing-features.html
-/sdcard/android/layout_tests/fast/text/textIteratorNilRenderer.html
-/sdcard/android/layout_tests/fast/text/drawBidiText.html
-/sdcard/android/layout_tests/fast/text/selection-hard-linebreak.html
-/sdcard/android/layout_tests/fast/text/word-break.html
-/sdcard/android/layout_tests/fast/text/break-word.html
-/sdcard/android/layout_tests/fast/text/font-initial.html
-/sdcard/android/layout_tests/fast/text/complex-text-opacity.html
-/sdcard/android/layout_tests/fast/text/stroking.html
-/sdcard/android/layout_tests/fast/text/midword-break-hang.html
-/sdcard/android/layout_tests/fast/text/atsui-partial-selection.html
-/sdcard/android/layout_tests/fast/text/embed-at-end-of-pre-wrap-line.html
-/sdcard/android/layout_tests/fast/text/atsui-multiple-renderers.html
-/sdcard/android/layout_tests/fast/text/shadow-translucent-fill.html
-/sdcard/android/layout_tests/fast/text/apply-start-width-after-skipped-text.html
-/sdcard/android/layout_tests/fast/text/capitalize-preserve-nbsp.html
-/sdcard/android/layout_tests/fast/text/updateNewFont.html
-/sdcard/android/layout_tests/fast/text/atsui-rtl-override-selection.html
-/sdcard/android/layout_tests/fast/text/align-center-rtl-spill.html
-/sdcard/android/layout_tests/fast/text/wbr.html
-/sdcard/android/layout_tests/fast/text/cg-vs-atsui.html
-/sdcard/android/layout_tests/fast/text/monospace-width-cache.html
-/sdcard/android/layout_tests/fast/text/soft-hyphen-2.html
-/sdcard/android/layout_tests/fast/text/atsui-pointtooffset-calls-cg.html
-/sdcard/android/layout_tests/fast/text/justified-selection.html
-/sdcard/android/layout_tests/fast/text/atsui-kerning-and-ligatures.html
-/sdcard/android/layout_tests/fast/text/wbr-pre.html
-/sdcard/android/layout_tests/fast/text/capitalize-boundaries.html
-/sdcard/android/layout_tests/fast/text/trailing-white-space.html
-/sdcard/android/layout_tests/fast/text/capitalize-empty-generated-string.html
-/sdcard/android/layout_tests/fast/text/stripNullFromText.html
-/sdcard/android/layout_tests/fast/text/letter-spacing-negative-opacity.html
-/sdcard/android/layout_tests/fast/text/atsui-small-caps-punctuation-size.html
-/sdcard/android/layout_tests/fast/text/word-break-soft-hyphen.html
-/sdcard/android/layout_tests/fast/text/fixed-pitch-control-characters.html
-/sdcard/android/layout_tests/fast/text/cg-fallback-bolding.html
-/sdcard/android/layout_tests/fast/text/line-breaks-after-white-space.html
-/sdcard/android/layout_tests/fast/text/text-letter-spacing.html
-/sdcard/android/layout_tests/fast/text/soft-hyphen-3.html
-/sdcard/android/layout_tests/fast/text/should-use-atsui.html
-/sdcard/android/layout_tests/fast/text/wide-zero-width-space.html
-/sdcard/android/layout_tests/fast/text/justified-selection-at-edge.html
-/sdcard/android/layout_tests/fast/text/trailing-white-space-2.html
-/sdcard/android/layout_tests/fast/text/word-break-run-rounding.html
-/sdcard/android/layout_tests/fast/text/softHyphen.html
-/sdcard/android/layout_tests/fast/text/delete-hard-break-character.html
-/sdcard/android/layout_tests/fast/text/line-breaks.html
-/sdcard/android/layout_tests/fast/text/wbr-styled.html
-/sdcard/android/layout_tests/fast/text/large-text-composed-char.html
-/sdcard/android/layout_tests/fast/text/shadow-no-blur.html
-/sdcard/android/layout_tests/fast/text/reset-emptyRun.html
-/sdcard/android/layout_tests/fast/text/word-space.html
-/sdcard/android/layout_tests/fast/text/midword-break-after-breakable-char.html
-/sdcard/android/layout_tests/fast/text/stroking-decorations.html
-/sdcard/android/layout_tests/fast/encoding/utf-16-little-endian.html
-/sdcard/android/layout_tests/fast/encoding/denormalised-voiced-japanese-chars.html
-/sdcard/android/layout_tests/fast/encoding/utf-16-no-bom.xml
-/sdcard/android/layout_tests/fast/encoding/utf-16-big-endian.html
-/sdcard/android/layout_tests/fast/encoding/xmacroman-encoding-test.html
-/sdcard/android/layout_tests/fast/encoding/invalid-UTF-8.html
-/sdcard/android/layout_tests/fast/multicol/float-avoidance.html
-/sdcard/android/layout_tests/fast/multicol/negativeColumnWidth.html
-/sdcard/android/layout_tests/fast/multicol/column-rules.html
-/sdcard/android/layout_tests/fast/multicol/column-rules-stacking.html
-/sdcard/android/layout_tests/fast/multicol/zeroColumnCount.html
-/sdcard/android/layout_tests/fast/multicol/columns-shorthand-parsing.html
-/sdcard/android/layout_tests/fast/multicol/float-multicol.html
-/sdcard/android/layout_tests/fast/doctypes/001.html
-/sdcard/android/layout_tests/fast/doctypes/002.html
-/sdcard/android/layout_tests/fast/doctypes/003.html
-/sdcard/android/layout_tests/fast/doctypes/004.html
-/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-to-inline.html
-/sdcard/android/layout_tests/fast/css-generated-content/spellingToolTip-assert.html
-/sdcard/android/layout_tests/fast/css-generated-content/no-openclose-quote.html
-/sdcard/android/layout_tests/fast/css-generated-content/before-with-first-letter.html
-/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-with-before.html
-/sdcard/android/layout_tests/fast/css-generated-content/010.html
-/sdcard/android/layout_tests/fast/css-generated-content/table-with-before.html
-/sdcard/android/layout_tests/fast/css-generated-content/002.html
-/sdcard/android/layout_tests/fast/css-generated-content/012.html
-/sdcard/android/layout_tests/fast/css-generated-content/004.html
-/sdcard/android/layout_tests/fast/css-generated-content/014.html
-/sdcard/android/layout_tests/fast/css-generated-content/016.html
-/sdcard/android/layout_tests/fast/css-generated-content/008.html
-/sdcard/android/layout_tests/fast/css-generated-content/after-order.html
-/sdcard/android/layout_tests/fast/css-generated-content/table-cell-before-content.html
-/sdcard/android/layout_tests/fast/css-generated-content/visibleContentHiddenParent.html
-/sdcard/android/layout_tests/fast/css-generated-content/inline-display-types.html
-/sdcard/android/layout_tests/fast/css-generated-content/positioned-background-hit-test-crash.html
-/sdcard/android/layout_tests/fast/css-generated-content/001.html
-/sdcard/android/layout_tests/fast/css-generated-content/011.html
-/sdcard/android/layout_tests/fast/css-generated-content/003.html
-/sdcard/android/layout_tests/fast/css-generated-content/beforeAfter-interdocument.html
-/sdcard/android/layout_tests/fast/css-generated-content/013.html
-/sdcard/android/layout_tests/fast/css-generated-content/005.html
-/sdcard/android/layout_tests/fast/css-generated-content/hover-style-change.html
-/sdcard/android/layout_tests/fast/css-generated-content/table-row-with-before.html
-/sdcard/android/layout_tests/fast/css-generated-content/absolute-position-inside-inline.html
-/sdcard/android/layout_tests/fast/css-generated-content/015.html
-/sdcard/android/layout_tests/fast/css-generated-content/hit-test-generated-content.html
-/sdcard/android/layout_tests/fast/css-generated-content/007.html
-/sdcard/android/layout_tests/fast/css-generated-content/009.html
-/sdcard/android/layout_tests/fast/css-generated-content/wbr-with-before-content.html
-/sdcard/android/layout_tests/fast/lists/decimal-leading-zero.html
-/sdcard/android/layout_tests/fast/lists/ol-display-types.html
-/sdcard/android/layout_tests/fast/lists/li-style-alpha-huge-value-crash.html
-/sdcard/android/layout_tests/fast/lists/ol-start-dynamic.html
-/sdcard/android/layout_tests/fast/lists/numeric-markers-outside-list.html
-/sdcard/android/layout_tests/fast/lists/marker-image-error.html
-/sdcard/android/layout_tests/fast/lists/marker-before-empty-inline.html
-/sdcard/android/layout_tests/fast/lists/list-marker-with-line-height.html
-/sdcard/android/layout_tests/fast/lists/scrolled-marker-paint.html
-/sdcard/android/layout_tests/fast/lists/li-values.html
-/sdcard/android/layout_tests/fast/lists/002.html
-/sdcard/android/layout_tests/fast/lists/dynamic-marker-crash.html
-/sdcard/android/layout_tests/fast/lists/list-item-line-height.html
-/sdcard/android/layout_tests/fast/lists/004.html
-/sdcard/android/layout_tests/fast/lists/drag-into-marker.html
-/sdcard/android/layout_tests/fast/lists/list-style-none-crash.html
-/sdcard/android/layout_tests/fast/lists/alpha-list-wrap.html
-/sdcard/android/layout_tests/fast/lists/006.html
-/sdcard/android/layout_tests/fast/lists/ol-start-parsing.html
-/sdcard/android/layout_tests/fast/lists/008.html
-/sdcard/android/layout_tests/fast/lists/inlineBoxWrapperNullCheck.html
-/sdcard/android/layout_tests/fast/lists/w3-list-styles.html
-/sdcard/android/layout_tests/fast/lists/item-not-in-list-line-wrapping.html
-/sdcard/android/layout_tests/fast/lists/olstart.html
-/sdcard/android/layout_tests/fast/lists/big-list-marker.html
-/sdcard/android/layout_tests/fast/lists/markers-in-selection.html
-/sdcard/android/layout_tests/fast/lists/list-style-type-dynamic-change.html
-/sdcard/android/layout_tests/fast/lists/001.html
-/sdcard/android/layout_tests/fast/lists/ordered-list-with-no-ol-tag.html
-/sdcard/android/layout_tests/fast/lists/003.html
-/sdcard/android/layout_tests/fast/lists/005.html
-/sdcard/android/layout_tests/fast/lists/li-br.html
-/sdcard/android/layout_tests/fast/lists/007.html
-/sdcard/android/layout_tests/fast/lists/009.html
-/sdcard/android/layout_tests/fast/transforms/transform-overflow.html
-/sdcard/android/layout_tests/fast/transforms/transforms-with-opacity.html
-/sdcard/android/layout_tests/fast/transforms/transformed-caret.html
-/sdcard/android/layout_tests/fast/transforms/bounding-rect-zoom.html
-/sdcard/android/layout_tests/fast/transforms/matrix-01.html
-/sdcard/android/layout_tests/fast/transforms/matrix-02.html
-/sdcard/android/layout_tests/fast/transforms/overflow-with-transform.html
-/sdcard/android/layout_tests/fast/transforms/transformed-document-element.html
-/sdcard/android/layout_tests/fast/transforms/transforms-with-zoom.html
-/sdcard/android/layout_tests/fast/transforms/transformed-focused-text-input.html
-/sdcard/android/layout_tests/fast/transforms/identity-matrix.html
-/sdcard/android/layout_tests/fast/transforms/transform-on-inline.html
-/sdcard/android/layout_tests/fast/transforms/transform-positioned-ancestor.html
-/sdcard/android/layout_tests/fast/transforms/skew-with-unitless-zero.html
-/sdcard/android/layout_tests/fast/transforms/transform-table-row.html
-/sdcard/android/layout_tests/fast/transforms/shadows.html
-/sdcard/android/layout_tests/fast/transforms/diamond.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusSolid01.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDouble01.html
-/sdcard/android/layout_tests/fast/borders/block-mask-overlay-image.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDouble03.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusSolid03.html
-/sdcard/android/layout_tests/fast/borders/border-color-inherit.html
-/sdcard/android/layout_tests/fast/borders/svg-as-border-image-2.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusInvalidColor.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDotted02.html
-/sdcard/android/layout_tests/fast/borders/border-image-scale-transform.html
-/sdcard/android/layout_tests/fast/borders/border-fit.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusArcs01.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDashed01.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDashed03.html
-/sdcard/android/layout_tests/fast/borders/fieldsetBorderRadius.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusAllStylesAllCorners.html
-/sdcard/android/layout_tests/fast/borders/border-radius-split-inline.html
-/sdcard/android/layout_tests/fast/borders/border-radius-constraints.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusGroove01.html
-/sdcard/android/layout_tests/fast/borders/border-image-omit-right-slice.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDouble02.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusSolid02.html
-/sdcard/android/layout_tests/fast/borders/outline-offset-min-assert.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusSolid04.html
-/sdcard/android/layout_tests/fast/borders/border-radius-huge-assert.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusInset01.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDotted01.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusOutset01.html
-/sdcard/android/layout_tests/fast/borders/svg-as-border-image.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDotted03.html
-/sdcard/android/layout_tests/fast/borders/border-image-border-radius.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusDashed02.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusRidge01.html
-/sdcard/android/layout_tests/fast/borders/border-image-rotate-transform.html
-/sdcard/android/layout_tests/fast/borders/inline-mask-overlay-image.html
-/sdcard/android/layout_tests/fast/borders/borderRadiusGroove02.html
-/sdcard/android/layout_tests/fast/borders/border-image-01.html
-/sdcard/android/layout_tests/fast/innerHTML/001.html
-/sdcard/android/layout_tests/fast/innerHTML/002.html
-/sdcard/android/layout_tests/fast/innerHTML/003.html
-/sdcard/android/layout_tests/fast/innerHTML/006.html
-/sdcard/android/layout_tests/fast/selectors/175a.html
-/sdcard/android/layout_tests/fast/selectors/155c.html
-/sdcard/android/layout_tests/fast/selectors/059.html
-/sdcard/android/layout_tests/fast/selectors/066b.html
-/sdcard/android/layout_tests/fast/selectors/168.html
-/sdcard/android/layout_tests/fast/selectors/177a.html
-/sdcard/android/layout_tests/fast/selectors/087b.html
-/sdcard/android/layout_tests/fast/selectors/020.html
-/sdcard/android/layout_tests/fast/selectors/012.html
-/sdcard/android/layout_tests/fast/selectors/040.html
-/sdcard/android/layout_tests/fast/selectors/004.html
-/sdcard/android/layout_tests/fast/selectors/032.html
-/sdcard/android/layout_tests/fast/selectors/060.html
-/sdcard/android/layout_tests/fast/selectors/016.html
-/sdcard/android/layout_tests/fast/selectors/044.html
-/sdcard/android/layout_tests/fast/selectors/008.html
-/sdcard/android/layout_tests/fast/selectors/072.html
-/sdcard/android/layout_tests/fast/selectors/064.html
-/sdcard/android/layout_tests/fast/selectors/056.html
-/sdcard/android/layout_tests/fast/selectors/018b.html
-/sdcard/android/layout_tests/fast/selectors/090b.html
-/sdcard/android/layout_tests/fast/selectors/045c.html
-/sdcard/android/layout_tests/fast/selectors/170d.html
-/sdcard/android/layout_tests/fast/selectors/157.html
-/sdcard/android/layout_tests/fast/selectors/039b.html
-/sdcard/android/layout_tests/fast/selectors/156b.html
-/sdcard/android/layout_tests/fast/selectors/175b.html
-/sdcard/android/layout_tests/fast/selectors/155d.html
-/sdcard/android/layout_tests/fast/selectors/167a.html
-/sdcard/android/layout_tests/fast/selectors/169.html
-/sdcard/android/layout_tests/fast/selectors/077b.html
-/sdcard/android/layout_tests/fast/selectors/177b.html
-/sdcard/android/layout_tests/fast/selectors/169a.html
-/sdcard/android/layout_tests/fast/selectors/001.html
-/sdcard/android/layout_tests/fast/selectors/021.html
-/sdcard/android/layout_tests/fast/selectors/unqualified-hover-quirks.html
-/sdcard/android/layout_tests/fast/selectors/013.html
-/sdcard/android/layout_tests/fast/selectors/041.html
-/sdcard/android/layout_tests/fast/selectors/021b.html
-/sdcard/android/layout_tests/fast/selectors/005.html
-/sdcard/android/layout_tests/fast/selectors/061.html
-/sdcard/android/layout_tests/fast/selectors/170.html
-/sdcard/android/layout_tests/fast/selectors/017.html
-/sdcard/android/layout_tests/fast/selectors/170a.html
-/sdcard/android/layout_tests/fast/selectors/009.html
-/sdcard/android/layout_tests/fast/selectors/045.html
-/sdcard/android/layout_tests/fast/selectors/154.html
-/sdcard/android/layout_tests/fast/selectors/044b.html
-/sdcard/android/layout_tests/fast/selectors/065.html
-/sdcard/android/layout_tests/fast/selectors/155a.html
-/sdcard/android/layout_tests/fast/selectors/166.html
-/sdcard/android/layout_tests/fast/selectors/158.html
-/sdcard/android/layout_tests/fast/selectors/077.html
-/sdcard/android/layout_tests/fast/selectors/175c.html
-/sdcard/android/layout_tests/fast/selectors/089.html
-/sdcard/android/layout_tests/fast/selectors/088b.html
-/sdcard/android/layout_tests/fast/selectors/nondeterministic-combinators.html
-/sdcard/android/layout_tests/fast/selectors/unqualified-hover-strict.html
-/sdcard/android/layout_tests/fast/selectors/010.html
-/sdcard/android/layout_tests/fast/selectors/002.html
-/sdcard/android/layout_tests/fast/selectors/014.html
-/sdcard/android/layout_tests/fast/selectors/042.html
-/sdcard/android/layout_tests/fast/selectors/006.html
-/sdcard/android/layout_tests/fast/selectors/034.html
-/sdcard/android/layout_tests/fast/selectors/062.html
-/sdcard/android/layout_tests/fast/selectors/007a.html
-/sdcard/android/layout_tests/fast/selectors/054.html
-/sdcard/android/layout_tests/fast/selectors/018.html
-/sdcard/android/layout_tests/fast/selectors/046.html
-/sdcard/android/layout_tests/fast/selectors/170b.html
-/sdcard/android/layout_tests/fast/selectors/072b.html
-/sdcard/android/layout_tests/fast/selectors/044c.html
-/sdcard/android/layout_tests/fast/selectors/038.html
-/sdcard/android/layout_tests/fast/selectors/155.html
-/sdcard/android/layout_tests/fast/selectors/066.html
-/sdcard/android/layout_tests/fast/selectors/058.html
-/sdcard/android/layout_tests/fast/selectors/155b.html
-/sdcard/android/layout_tests/fast/selectors/166a.html
-/sdcard/android/layout_tests/fast/selectors/167.html
-/sdcard/android/layout_tests/fast/selectors/159.html
-/sdcard/android/layout_tests/fast/selectors/168a.html
-/sdcard/android/layout_tests/fast/selectors/078b.html
-/sdcard/android/layout_tests/fast/selectors/011.html
-/sdcard/android/layout_tests/fast/selectors/003.html
-/sdcard/android/layout_tests/fast/selectors/015.html
-/sdcard/android/layout_tests/fast/selectors/043.html
-/sdcard/android/layout_tests/fast/selectors/160.html
-/sdcard/android/layout_tests/fast/selectors/063.html
-/sdcard/android/layout_tests/fast/selectors/043b.html
-/sdcard/android/layout_tests/fast/selectors/007b.html
-/sdcard/android/layout_tests/fast/selectors/027.html
-/sdcard/android/layout_tests/fast/selectors/019.html
-/sdcard/android/layout_tests/fast/selectors/083.html
-/sdcard/android/layout_tests/fast/selectors/045b.html
-/sdcard/android/layout_tests/fast/selectors/170c.html
-/sdcard/android/layout_tests/fast/selectors/044d.html
-/sdcard/android/layout_tests/fast/selectors/039.html
-/sdcard/android/layout_tests/fast/overflow/overflow-focus-ring.html
-/sdcard/android/layout_tests/fast/overflow/overflow-x-y.html
-/sdcard/android/layout_tests/fast/overflow/overflow-text-hit-testing.html
-/sdcard/android/layout_tests/fast/overflow/unreachable-overflow-rtl-bug.html
-/sdcard/android/layout_tests/fast/overflow/overflow-auto-position-absolute.html
-/sdcard/android/layout_tests/fast/overflow/scrollRevealButton.html
-/sdcard/android/layout_tests/fast/overflow/overflow-rtl-inline-scrollbar.html
-/sdcard/android/layout_tests/fast/overflow/002.html
-/sdcard/android/layout_tests/fast/overflow/overflow-rtl.html
-/sdcard/android/layout_tests/fast/overflow/004.html
-/sdcard/android/layout_tests/fast/overflow/overflow-stacking.html
-/sdcard/android/layout_tests/fast/overflow/006.html
-/sdcard/android/layout_tests/fast/overflow/border-radius-clipping.html
-/sdcard/android/layout_tests/fast/overflow/scrollbar-position-update.html
-/sdcard/android/layout_tests/fast/overflow/008.html
-/sdcard/android/layout_tests/fast/overflow/overflow-float-stacking.html
-/sdcard/android/layout_tests/fast/overflow/scroll-nested-positioned-layer-in-overflow.html
-/sdcard/android/layout_tests/fast/overflow/image-selection-highlight.html
-/sdcard/android/layout_tests/fast/overflow/childFocusRingClip.html
-/sdcard/android/layout_tests/fast/overflow/position-relative.html
-/sdcard/android/layout_tests/fast/overflow/dynamic-hidden.html
-/sdcard/android/layout_tests/fast/overflow/overflow_hidden.html
-/sdcard/android/layout_tests/fast/overflow/clip-rects-fixed-ancestor.html
-/sdcard/android/layout_tests/fast/overflow/infiniteRecursionGuard.html
-/sdcard/android/layout_tests/fast/overflow/float-in-relpositioned.html
-/sdcard/android/layout_tests/fast/overflow/table-overflow-float.html
-/sdcard/android/layout_tests/fast/overflow/003.xml
-/sdcard/android/layout_tests/fast/overflow/overflow-auto-table.html
-/sdcard/android/layout_tests/fast/overflow/unreachable-content-test.html
-/sdcard/android/layout_tests/fast/overflow/infiniteRecursion.html
-/sdcard/android/layout_tests/fast/overflow/001.html
-/sdcard/android/layout_tests/fast/overflow/hit-test-overflow-controls.html
-/sdcard/android/layout_tests/fast/overflow/005.html
-/sdcard/android/layout_tests/fast/overflow/007.html
-/sdcard/android/layout_tests/fast/overflow/overflow-with-local-background-attachment.html
-/sdcard/android/layout_tests/fast/overflow/hidden-scrollbar-resize.html
-/sdcard/android/layout_tests/fast/events/context-no-deselect.html
-/sdcard/android/layout_tests/fast/events/autoscroll.html
-/sdcard/android/layout_tests/fast/events/5056619.html
-/sdcard/android/layout_tests/fast/events/updateLayoutForHitTest.html
-/sdcard/android/layout_tests/fast/events/label-focus.html
-/sdcard/android/layout_tests/fast/events/keydown-1.html
-/sdcard/android/layout_tests/fast/events/onloadFrameCrash.html
-/sdcard/android/layout_tests/fast/events/event-listener-on-link.html
-/sdcard/android/layout_tests/fast/events/onload-re-entry.html
-/sdcard/android/layout_tests/fast/events/standalone-image-drag-to-editable.html
-/sdcard/android/layout_tests/fast/events/focusingUnloadedFrame.html
-/sdcard/android/layout_tests/fast/events/event-sender-mouse-moved.html
-/sdcard/android/layout_tests/fast/events/reveal-link-when-focused.html
-/sdcard/android/layout_tests/fast/events/mouseout-dead-node.html
-/sdcard/android/layout_tests/fast/html/keygen.html
-/sdcard/android/layout_tests/fast/html/marquee-scroll.html
-/sdcard/android/layout_tests/fast/html/link-rel-stylesheet.html
-/sdcard/android/layout_tests/fast/html/listing.html
-/sdcard/android/layout_tests/fast/images/svg-as-background.html
-/sdcard/android/layout_tests/fast/images/pdf-as-image-landscape.html
-/sdcard/android/layout_tests/fast/images/pdf-as-tiled-background.html
-/sdcard/android/layout_tests/fast/images/pdf-as-image.html
-/sdcard/android/layout_tests/fast/images/image-map-anchor-children.html
-/sdcard/android/layout_tests/fast/images/animated-gif-with-offsets.html
-/sdcard/android/layout_tests/fast/images/favicon-as-image.html
-/sdcard/android/layout_tests/fast/images/svg-width-100p-as-background.html
-/sdcard/android/layout_tests/fast/images/svg-as-tiled-background.html
-/sdcard/android/layout_tests/fast/images/svg-as-image.html
-/sdcard/android/layout_tests/fast/images/object-image.html
-/sdcard/android/layout_tests/fast/images/pdf-as-background.html
-/sdcard/android/layout_tests/fast/images/imagemap-case.html
-/sdcard/android/layout_tests/fast/images/svg-as-relative-image.html
-/sdcard/android/layout_tests/fast/images/embed-image.html
-/sdcard/android/layout_tests/fast/images/animated-svg-as-image.html
-/sdcard/android/layout_tests/fast/images/image-in-map.html
-/sdcard/android/layout_tests/fast/images/icon-decoding.html
-/sdcard/android/layout_tests/fast/inline-block/14498-positionForCoordinates.html
-/sdcard/android/layout_tests/fast/inline-block/001.html
-/sdcard/android/layout_tests/fast/inline-block/002.html
-/sdcard/android/layout_tests/fast/inline-block/003.html
-/sdcard/android/layout_tests/fast/inline-block/004.html
-/sdcard/android/layout_tests/fast/inline-block/005.html
-/sdcard/android/layout_tests/fast/inline-block/contenteditable-baseline.html
-/sdcard/android/layout_tests/fast/inline-block/006.html
-/sdcard/android/layout_tests/fast/inline-block/inline-block-vertical-align.html
-/sdcard/android/layout_tests/fast/inline-block/tricky-baseline.html
-/sdcard/android/layout_tests/fast/inline-block/overflow-clip.html
-/sdcard/android/layout_tests/fast/inspector/matchedrules.html
-/sdcard/android/layout_tests/fast/inspector/style.html
-/sdcard/android/layout_tests/fast/flexbox/010.html
-/sdcard/android/layout_tests/fast/flexbox/020.html
-/sdcard/android/layout_tests/fast/flexbox/002.html
-/sdcard/android/layout_tests/fast/flexbox/012.html
-/sdcard/android/layout_tests/fast/flexbox/022.html
-/sdcard/android/layout_tests/fast/flexbox/004.html
-/sdcard/android/layout_tests/fast/flexbox/014.html
-/sdcard/android/layout_tests/fast/flexbox/024.html
-/sdcard/android/layout_tests/fast/flexbox/006.html
-/sdcard/android/layout_tests/fast/flexbox/016.html
-/sdcard/android/layout_tests/fast/flexbox/026.html
-/sdcard/android/layout_tests/fast/flexbox/008.html
-/sdcard/android/layout_tests/fast/flexbox/018.html
-/sdcard/android/layout_tests/fast/flexbox/001.html
-/sdcard/android/layout_tests/fast/flexbox/011.html
-/sdcard/android/layout_tests/fast/flexbox/003.html
-/sdcard/android/layout_tests/fast/flexbox/021.html
-/sdcard/android/layout_tests/fast/flexbox/013.html
-/sdcard/android/layout_tests/fast/flexbox/005.html
-/sdcard/android/layout_tests/fast/flexbox/023.html
-/sdcard/android/layout_tests/fast/flexbox/015.html
-/sdcard/android/layout_tests/fast/flexbox/007.html
-/sdcard/android/layout_tests/fast/flexbox/025.html
-/sdcard/android/layout_tests/fast/flexbox/017.html
-/sdcard/android/layout_tests/fast/flexbox/009.html
-/sdcard/android/layout_tests/fast/flexbox/019.html
-/sdcard/android/layout_tests/fast/flexbox/flex-hang.html
-/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-1.html
-/sdcard/android/layout_tests/fast/tokenizer/002.html
-/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-2.html
-/sdcard/android/layout_tests/fast/tokenizer/script-after-frameset.html
-/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-2.html
-/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write.html
-/sdcard/android/layout_tests/fast/tokenizer/script_extra_close.html
-/sdcard/android/layout_tests/fast/tokenizer/001.html
-/sdcard/android/layout_tests/fast/tokenizer/003.html
-/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-1.html
-/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write_2.html
-/sdcard/android/layout_tests/fast/box-shadow/transform-fringing.html
-/sdcard/android/layout_tests/fast/box-shadow/spread.html
-/sdcard/android/layout_tests/fast/box-shadow/border-radius-big.html
-/sdcard/android/layout_tests/fast/box-shadow/inset.html
-/sdcard/android/layout_tests/fast/box-shadow/basic-shadows.html
-/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-3.html
-/sdcard/android/layout_tests/fast/js/missing-style-end-tag-js.html
-/sdcard/android/layout_tests/fast/inline/continuation-outlines-with-layers.html
-/sdcard/android/layout_tests/fast/inline/inline-padding-disables-text-quirk.html
-/sdcard/android/layout_tests/fast/inline/emptyInlinesWithinLists.html
-/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlines.html
-/sdcard/android/layout_tests/fast/inline/long-wrapped-line.html
-/sdcard/android/layout_tests/fast/inline/inline-continuation-borders.html
-/sdcard/android/layout_tests/fast/inline/vertical-align-text-bottom.html
-/sdcard/android/layout_tests/fast/inline/25277-2.html
-/sdcard/android/layout_tests/fast/inline/25277.html
-/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlinesWithWS.html
-/sdcard/android/layout_tests/fast/inline/positionedLifetime.html
-/sdcard/android/layout_tests/fast/inline/dirtyLinesForInline.html
-/sdcard/android/layout_tests/fast/inline/001.html
-/sdcard/android/layout_tests/fast/inline/002.html
-/sdcard/android/layout_tests/fast/inline/inline-text-quirk-bpm.html
-/sdcard/android/layout_tests/fast/inline/inline-borders-with-bidi-override.html
-/sdcard/android/layout_tests/fast/inline/styledEmptyInlinesWithBRs.html
-/sdcard/android/layout_tests/fast/inline/continuation-outlines.html
-/sdcard/android/layout_tests/fast/inline/br-text-decoration.html
-/sdcard/android/layout_tests/fast/inline/outline-continuations.html
-/sdcard/android/layout_tests/fast/inline/percentage-margins.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/010.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/001.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/002.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/003.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/004.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/005.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/006.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/007.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/008.html
-/sdcard/android/layout_tests/fast/body-propagation/background-image/009.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/001.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/002.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/003.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/004.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/005.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/006.html
-/sdcard/android/layout_tests/fast/body-propagation/overflow/007.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/001.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/002.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/003.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/004.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/005.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/006.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/007.html
-/sdcard/android/layout_tests/fast/body-propagation/background-color/008.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/colSpan.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/createCaption.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/frameless-location-bugzilla10837.html
-/sdcard/android/layout_tests/fast/dom/Element/null-offset-parent.html
-/sdcard/android/layout_tests/fast/dom/Element/class-attribute-whitespace.html
-/sdcard/android/layout_tests/fast/dom/HTMLLinkElement/pending-stylesheet-count.html
-/sdcard/android/layout_tests/fast/dom/HTMLStyleElement/insert-parser-generated.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableColElement/resize-table-using-col-width.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-image-alt-text.html
-/sdcard/android/layout_tests/fast/dom/Window/open-existing-pop-up-blocking.html
-/sdcard/android/layout_tests/fast/dom/Window/btoa-pnglet.html
-/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/vspace-hspace-as-number.html
-/sdcard/android/layout_tests/fast/dom/HTMLElement/bdo.html
-/sdcard/android/layout_tests/fast/dom/Range/surroundContents-1.html
-/sdcard/android/layout_tests/fast/dom/Range/create-contextual-fragment.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead1.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead2.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead3.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead4.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead5.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-link-style-href-check.html
-/sdcard/android/layout_tests/fast/dom/HTMLTextAreaElement/reset-textarea.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-alt-text.html
-/sdcard/android/layout_tests/fast/dom/dom-parse-serialize.html
-/sdcard/android/layout_tests/fast/dom/focus-contenteditable.html
-/sdcard/android/layout_tests/fast/dom/jsDevicePixelRatio.html
-/sdcard/android/layout_tests/fast/dom/isindex-001.html
-/sdcard/android/layout_tests/fast/dom/css-cached-import-rule.html
-/sdcard/android/layout_tests/fast/dom/dom-parse-serialize-display.html
-/sdcard/android/layout_tests/fast/dom/css-rule-functions.html
-/sdcard/android/layout_tests/fast/dom/createDocumentType.html
-/sdcard/android/layout_tests/fast/dom/clientWidthAfterDocumentIsRemoved.html
-/sdcard/android/layout_tests/fast/dom/css-inline-style-important.html
-/sdcard/android/layout_tests/fast/dom/replaceChild.html
-/sdcard/android/layout_tests/fast/dom/anchor-text.html
-/sdcard/android/layout_tests/fast/dom/importNodeHTML.html
-/sdcard/android/layout_tests/fast/dom/gc-10.html
-/sdcard/android/layout_tests/fast/dom/inner-text.html
-/sdcard/android/layout_tests/fast/dom/isindex-002.html
-/sdcard/android/layout_tests/fast/dom/outerText.html
-/sdcard/android/layout_tests/fast/dom/row-inner-text.html
-/sdcard/android/layout_tests/fast/dom/blur-contenteditable.html
-/sdcard/android/layout_tests/fast/dom/setPrimitiveValue.html
-/sdcard/android/layout_tests/fast/dom/delete-contents.html
-/sdcard/android/layout_tests/fast/dom/children-nodes.html
-/sdcard/android/layout_tests/fast/dom/css-mediarule-deleteRule-update.html
-/sdcard/android/layout_tests/fast/dom/attr_dead_doc.html
-/sdcard/android/layout_tests/fast/dom/clone-contents-0-end-offset.html
-/sdcard/android/layout_tests/fast/dom/comment-not-documentElement.html
-/sdcard/android/layout_tests/fast/dom/clone-node-dynamic-style.html
-/sdcard/android/layout_tests/fast/dom/css-mediarule-insertRule-update.html
-/sdcard/android/layout_tests/fast/dom/css-insert-import-rule.html
-/sdcard/android/layout_tests/fast/dom/stripNullFromTextNodes.html
-/sdcard/android/layout_tests/fast/gradients/crash-on-zero-radius.html
-/sdcard/android/layout_tests/fast/gradients/generated-gradients.html
-/sdcard/android/layout_tests/fast/gradients/background-clipped.html
-/sdcard/android/layout_tests/fast/gradients/list-item-gradient.html
-/sdcard/android/layout_tests/fast/gradients/border-image-gradient-sides-and-corners.html
-/sdcard/android/layout_tests/fast/gradients/simple-gradients.html
-/sdcard/android/layout_tests/fast/gradients/border-image-gradient.html
-/sdcard/android/layout_tests/fast/invalid/table-inside-stray-table-content.html
-/sdcard/android/layout_tests/fast/invalid/010.html
-/sdcard/android/layout_tests/fast/invalid/002.html
-/sdcard/android/layout_tests/fast/invalid/012.html
-/sdcard/android/layout_tests/fast/invalid/004.html
-/sdcard/android/layout_tests/fast/invalid/014.html
-/sdcard/android/layout_tests/fast/invalid/006.html
-/sdcard/android/layout_tests/fast/invalid/016.html
-/sdcard/android/layout_tests/fast/invalid/008.html
-/sdcard/android/layout_tests/fast/invalid/018.html
-/sdcard/android/layout_tests/fast/invalid/junk-data.xml
-/sdcard/android/layout_tests/fast/invalid/missing-dl-end-tag.html
-/sdcard/android/layout_tests/fast/invalid/td-inside-object.html
-/sdcard/android/layout_tests/fast/invalid/table-residual-style-crash.html
-/sdcard/android/layout_tests/fast/invalid/missing-font-end-tag.html
-/sdcard/android/layout_tests/fast/invalid/missing-dt-end-tag.html
-/sdcard/android/layout_tests/fast/invalid/020.xml
-/sdcard/android/layout_tests/fast/invalid/001.html
-/sdcard/android/layout_tests/fast/invalid/nestedh3s.html
-/sdcard/android/layout_tests/fast/invalid/011.html
-/sdcard/android/layout_tests/fast/invalid/003.html
-/sdcard/android/layout_tests/fast/invalid/021.html
-/sdcard/android/layout_tests/fast/invalid/013.html
-/sdcard/android/layout_tests/fast/invalid/005.html
-/sdcard/android/layout_tests/fast/invalid/015.html
-/sdcard/android/layout_tests/fast/invalid/007.html
-/sdcard/android/layout_tests/fast/invalid/residual-style.html
-/sdcard/android/layout_tests/fast/invalid/017.html
-/sdcard/android/layout_tests/fast/invalid/009.html
-/sdcard/android/layout_tests/fast/invalid/missing-address-end-tag.html
-/sdcard/android/layout_tests/fast/invalid/019.html
-/sdcard/android/layout_tests/fast/forms/input-width.html
-/sdcard/android/layout_tests/fast/forms/select-item-background-clip.html
-/sdcard/android/layout_tests/fast/forms/radio-nested-labels.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-preventDefault.html
-/sdcard/android/layout_tests/fast/forms/input-double-click-selection-gap-bug.html
-/sdcard/android/layout_tests/fast/forms/preserveFormDuringResidualStyle.html
-/sdcard/android/layout_tests/fast/forms/input-text-option-delete.html
-/sdcard/android/layout_tests/fast/forms/textfield-overflow.html
-/sdcard/android/layout_tests/fast/forms/search-zoomed.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label02.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-visibility.html
-/sdcard/android/layout_tests/fast/forms/search-vertical-alignment.html
-/sdcard/android/layout_tests/fast/forms/file-input-direction.html
-/sdcard/android/layout_tests/fast/forms/select-change-listbox-size.html
-/sdcard/android/layout_tests/fast/forms/002.html
-/sdcard/android/layout_tests/fast/forms/textarea-align.html
-/sdcard/android/layout_tests/fast/forms/control-restrict-line-height.html
-/sdcard/android/layout_tests/fast/forms/basic-textareas.html
-/sdcard/android/layout_tests/fast/forms/button-generated-content.html
-/sdcard/android/layout_tests/fast/forms/input-text-paste-maxlength.html
-/sdcard/android/layout_tests/fast/forms/select-display-none-style-resolve.html
-/sdcard/android/layout_tests/fast/forms/input-readonly-autoscroll.html
-/sdcard/android/layout_tests/fast/forms/thumbslider-no-parent-slider.html
-/sdcard/android/layout_tests/fast/forms/listbox-clip.html
-/sdcard/android/layout_tests/fast/forms/textarea-setinnerhtml.html
-/sdcard/android/layout_tests/fast/forms/input-align.html
-/sdcard/android/layout_tests/fast/forms/button-cannot-be-nested.html
-/sdcard/android/layout_tests/fast/forms/input-type-change.html
-/sdcard/android/layout_tests/fast/forms/menulist-option-wrap.html
-/sdcard/android/layout_tests/fast/forms/select-empty-option-height.html
-/sdcard/android/layout_tests/fast/forms/float-before-fieldset.html
-/sdcard/android/layout_tests/fast/forms/radio_checked.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-focus.html
-/sdcard/android/layout_tests/fast/forms/input-value.html
-/sdcard/android/layout_tests/fast/forms/select-selected.html
-/sdcard/android/layout_tests/fast/forms/control-clip-overflow.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-default-bkcolor.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label03.html
-/sdcard/android/layout_tests/fast/forms/button-default-title.html
-/sdcard/android/layout_tests/fast/forms/hidden-listbox.html
-/sdcard/android/layout_tests/fast/forms/input-baseline.html
-/sdcard/android/layout_tests/fast/forms/targeted-frame-submission.html
-/sdcard/android/layout_tests/fast/forms/003.html
-/sdcard/android/layout_tests/fast/forms/text-control-intrinsic-widths.html
-/sdcard/android/layout_tests/fast/forms/select-change-listbox-to-popup.html
-/sdcard/android/layout_tests/fast/forms/radio_checked_dynamic.html
-/sdcard/android/layout_tests/fast/forms/text-style-color.html
-/sdcard/android/layout_tests/fast/forms/button-sizes.html
-/sdcard/android/layout_tests/fast/forms/listbox-scrollbar-incremental-load.html
-/sdcard/android/layout_tests/fast/forms/password-placeholder.html
-/sdcard/android/layout_tests/fast/forms/button-style-color.html
-/sdcard/android/layout_tests/fast/forms/caret-rtl.html
-/sdcard/android/layout_tests/fast/forms/listbox-deselect-scroll.html
-/sdcard/android/layout_tests/fast/forms/select-initial-position.html
-/sdcard/android/layout_tests/fast/forms/placeholder-set-attribute.html
-/sdcard/android/layout_tests/fast/forms/radio-attr-order.html
-/sdcard/android/layout_tests/fast/forms/input-disabled-color.html
-/sdcard/android/layout_tests/fast/forms/fieldset-align.html
-/sdcard/android/layout_tests/fast/forms/select-baseline.html
-/sdcard/android/layout_tests/fast/forms/stuff-on-my-optgroup.html
-/sdcard/android/layout_tests/fast/forms/input-align-image.html
-/sdcard/android/layout_tests/fast/forms/option-index.html
-/sdcard/android/layout_tests/fast/forms/menulist-clip.html
-/sdcard/android/layout_tests/fast/forms/search-display-none-cancel-button.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label04.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-disabled.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-height.html
-/sdcard/android/layout_tests/fast/forms/004.html
-/sdcard/android/layout_tests/fast/forms/search-placeholder-value-changed.html
-/sdcard/android/layout_tests/fast/forms/input-field-text-truncated.html
-/sdcard/android/layout_tests/fast/forms/input-type-text-min-width.html
-/sdcard/android/layout_tests/fast/forms/slider-thumb-shared-style.html
-/sdcard/android/layout_tests/fast/forms/option-script.html
-/sdcard/android/layout_tests/fast/forms/input-paste-undo.html
-/sdcard/android/layout_tests/fast/forms/button-white-space.html
-/sdcard/android/layout_tests/fast/forms/slider-padding.html
-/sdcard/android/layout_tests/fast/forms/button-submit.html
-/sdcard/android/layout_tests/fast/forms/input-text-double-click.html
-/sdcard/android/layout_tests/fast/forms/form-hides-table.html
-/sdcard/android/layout_tests/fast/forms/listbox-width-change.html
-/sdcard/android/layout_tests/fast/forms/button-positioned.html
-/sdcard/android/layout_tests/fast/forms/control-clip.html
-/sdcard/android/layout_tests/fast/forms/listbox-hit-test-zoomed.html
-/sdcard/android/layout_tests/fast/forms/thumbslider-crash.html
-/sdcard/android/layout_tests/fast/forms/input-first-letter.html
-/sdcard/android/layout_tests/fast/forms/search-rtl.html
-/sdcard/android/layout_tests/fast/forms/isindex-placeholder.html
-/sdcard/android/layout_tests/fast/forms/plaintext-mode-2.html
-/sdcard/android/layout_tests/fast/forms/select-change-popup-to-listbox.html
-/sdcard/android/layout_tests/fast/forms/blankbuttons.html
-/sdcard/android/layout_tests/fast/forms/input-text-maxlength.html
-/sdcard/android/layout_tests/fast/forms/password-placeholder-text-security.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label05.html
-/sdcard/android/layout_tests/fast/forms/visual-hebrew-text-field.html
-/sdcard/android/layout_tests/fast/forms/005.html
-/sdcard/android/layout_tests/fast/forms/search-styled.html
-/sdcard/android/layout_tests/fast/forms/file-input-disabled.html
-/sdcard/android/layout_tests/fast/forms/select-disabled-appearance.html
-/sdcard/android/layout_tests/fast/forms/input-type-change2.html
-/sdcard/android/layout_tests/fast/forms/select-block-background.html
-/sdcard/android/layout_tests/fast/forms/select-dirty-parent-pref-widths.html
-/sdcard/android/layout_tests/fast/forms/range-thumb-height-percentage.html
-/sdcard/android/layout_tests/fast/forms/select-visual-hebrew.html
-/sdcard/android/layout_tests/fast/forms/textAreaLineHeight.html
-/sdcard/android/layout_tests/fast/forms/option-text-clip.html
-/sdcard/android/layout_tests/fast/forms/formmove.html
-/sdcard/android/layout_tests/fast/forms/textfield-outline.html
-/sdcard/android/layout_tests/fast/forms/button-text-transform.html
-/sdcard/android/layout_tests/fast/forms/textarea-scroll-height.html
-/sdcard/android/layout_tests/fast/forms/button-table-styles.html
-/sdcard/android/layout_tests/fast/forms/box-shadow-override.html
-/sdcard/android/layout_tests/fast/forms/checkbox-radio-onchange.html
-/sdcard/android/layout_tests/fast/forms/searchfield-heights.html
-/sdcard/android/layout_tests/fast/forms/input-spaces.html
-/sdcard/android/layout_tests/fast/forms/textarea-scrollbar.html
-/sdcard/android/layout_tests/fast/forms/minWidthPercent.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label06.html
-/sdcard/android/layout_tests/fast/forms/placeholder-pseudo-style.html
-/sdcard/android/layout_tests/fast/forms/menulist-width-change.html
-/sdcard/android/layout_tests/fast/forms/input-text-drag-down.html
-/sdcard/android/layout_tests/fast/forms/option-strip-whitespace.html
-/sdcard/android/layout_tests/fast/forms/006.html
-/sdcard/android/layout_tests/fast/forms/input-no-renderer.html
-/sdcard/android/layout_tests/fast/forms/input-text-click-outside.html
-/sdcard/android/layout_tests/fast/forms/input-text-scroll-left-on-blur.html
-/sdcard/android/layout_tests/fast/forms/form-element-geometry.html
-/sdcard/android/layout_tests/fast/forms/input-table.html
-/sdcard/android/layout_tests/fast/forms/textarea-scrolled-type.html
-/sdcard/android/layout_tests/fast/forms/select-align.html
-/sdcard/android/layout_tests/fast/forms/select-writing-direction-natural.html
-/sdcard/android/layout_tests/fast/forms/search-cancel-button-style-sharing.html
-/sdcard/android/layout_tests/fast/forms/tabbing-input-iframe.html
-/sdcard/android/layout_tests/fast/forms/hidden-input-file.html
-/sdcard/android/layout_tests/fast/forms/menulist-deselect-update.html
-/sdcard/android/layout_tests/fast/forms/slider-thumb-stylability.html
-/sdcard/android/layout_tests/fast/forms/input-readonly-dimmed.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-width.html
-/sdcard/android/layout_tests/fast/forms/select-list-box-with-height.html
-/sdcard/android/layout_tests/fast/forms/textarea-rows-cols.html
-/sdcard/android/layout_tests/fast/forms/button-align.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-readonly.html
-/sdcard/android/layout_tests/fast/forms/form-added-to-table.html
-/sdcard/android/layout_tests/fast/forms/menulist-no-overflow.html
-/sdcard/android/layout_tests/fast/forms/formmove2.html
-/sdcard/android/layout_tests/fast/forms/input-text-word-wrap.html
-/sdcard/android/layout_tests/fast/forms/listbox-selection-2.html
-/sdcard/android/layout_tests/fast/forms/input-readonly-empty.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label07.html
-/sdcard/android/layout_tests/fast/forms/007.html
-/sdcard/android/layout_tests/fast/forms/indeterminate.html
-/sdcard/android/layout_tests/fast/forms/negativeLineHeight.html
-/sdcard/android/layout_tests/fast/forms/select-style.html
-/sdcard/android/layout_tests/fast/forms/select-size.html
-/sdcard/android/layout_tests/fast/forms/menulist-separator-painting.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label01.html
-/sdcard/android/layout_tests/fast/forms/fieldset-with-float.html
-/sdcard/android/layout_tests/fast/forms/floating-textfield-relayout.html
-/sdcard/android/layout_tests/fast/forms/button-inner-block-reuse.html
-/sdcard/android/layout_tests/fast/forms/001.html
-/sdcard/android/layout_tests/fast/forms/input-text-click-inside.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-selection.html
-/sdcard/android/layout_tests/fast/forms/menulist-narrow-width.html
-/sdcard/android/layout_tests/fast/forms/linebox-overflow-in-textarea-padding.html
-/sdcard/android/layout_tests/fast/forms/menulist-restrict-line-height.html
-/sdcard/android/layout_tests/fast/forms/textarea-width.html
-/sdcard/android/layout_tests/fast/forms/disabled-select-change-index.html
-/sdcard/android/layout_tests/fast/forms/formmove3.html
-/sdcard/android/layout_tests/fast/forms/placeholder-set-value.html
-/sdcard/android/layout_tests/fast/forms/input-text-self-emptying-click.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-bkcolor.html
-/sdcard/android/layout_tests/fast/forms/search-transformed.html
-/sdcard/android/layout_tests/fast/forms/image-border.html
-/sdcard/android/layout_tests/fast/forms/encoding-test.html
-/sdcard/android/layout_tests/fast/forms/form-in-malformed-markup.html
-/sdcard/android/layout_tests/fast/forms/menulist-style-color.html
-/sdcard/android/layout_tests/fast/compact/001.html
-/sdcard/android/layout_tests/fast/compact/002.html
-/sdcard/android/layout_tests/fast/compact/003.html
-/sdcard/android/layout_tests/fast/clip/nestedTransparencyClip.html
-/sdcard/android/layout_tests/fast/clip/overflow-border-radius-clip.html
-/sdcard/android/layout_tests/fast/clip/outline-overflowClip.html
-/sdcard/android/layout_tests/fast/clip/001.html
-/sdcard/android/layout_tests/fast/clip/010.html
-/sdcard/android/layout_tests/fast/clip/002.html
-/sdcard/android/layout_tests/fast/clip/011.html
-/sdcard/android/layout_tests/fast/clip/003.html
-/sdcard/android/layout_tests/fast/clip/012.html
-/sdcard/android/layout_tests/fast/clip/004.html
-/sdcard/android/layout_tests/fast/clip/013.html
-/sdcard/android/layout_tests/fast/clip/005.html
-/sdcard/android/layout_tests/fast/clip/014.html
-/sdcard/android/layout_tests/fast/clip/006.html
-/sdcard/android/layout_tests/fast/clip/015.html
-/sdcard/android/layout_tests/fast/clip/016.html
-/sdcard/android/layout_tests/fast/clip/007.html
-/sdcard/android/layout_tests/fast/clip/008.html
-/sdcard/android/layout_tests/fast/clip/017.html
-/sdcard/android/layout_tests/fast/clip/009.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/001.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/002.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/003.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/004.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/equal-precedence-resolution.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/rtl-border-collapsing.html
-/sdcard/android/layout_tests/fast/table/border-collapsing/border-collapsing-head-foot.html
-/sdcard/android/layout_tests/fast/table/fixed-nested.html
-/sdcard/android/layout_tests/fast/table/frame-and-rules.html
-/sdcard/android/layout_tests/fast/table/empty-table-percent-height.html
-/sdcard/android/layout_tests/fast/table/100-percent-cell-width.html
-/sdcard/android/layout_tests/fast/table/stale-grid-crash.html
-/sdcard/android/layout_tests/fast/table/div-as-col-span.html
-/sdcard/android/layout_tests/fast/table/nobr.html
-/sdcard/android/layout_tests/fast/table/012.html
-/sdcard/android/layout_tests/fast/table/040.html
-/sdcard/android/layout_tests/fast/table/growCellForImageQuirk.html
-/sdcard/android/layout_tests/fast/table/024.html
-/sdcard/android/layout_tests/fast/table/cell-pref-width-invalidation.html
-/sdcard/android/layout_tests/fast/table/fixed-granular-cols.html
-/sdcard/android/layout_tests/fast/table/008.html
-/sdcard/android/layout_tests/fast/table/036.html
-/sdcard/android/layout_tests/fast/table/nested-percent-height-table.html
-/sdcard/android/layout_tests/fast/table/rules-attr-dynchange1.html
-/sdcard/android/layout_tests/fast/table/wide-column.html
-/sdcard/android/layout_tests/fast/table/fixed-with-auto-with-colspan.html
-/sdcard/android/layout_tests/fast/table/percent-heights.html
-/sdcard/android/layout_tests/fast/table/021.html
-/sdcard/android/layout_tests/fast/table/colspanMinWidth.html
-/sdcard/android/layout_tests/fast/table/005.html
-/sdcard/android/layout_tests/fast/table/033.html
-/sdcard/android/layout_tests/fast/table/floatingTablePaintBackground.html
-/sdcard/android/layout_tests/fast/table/017.html
-/sdcard/android/layout_tests/fast/table/029.html
-/sdcard/android/layout_tests/fast/table/cell-absolute-child.html
-/sdcard/android/layout_tests/fast/table/click-near-anonymous-table.html
-/sdcard/android/layout_tests/fast/table/auto-with-percent-height.html
-/sdcard/android/layout_tests/fast/table/insert-before-anonymous-ancestors.html
-/sdcard/android/layout_tests/fast/table/append-cells2.html
-/sdcard/android/layout_tests/fast/table/unused-percent-heights.html
-/sdcard/android/layout_tests/fast/table/max-width-integer-overflow.html
-/sdcard/android/layout_tests/fast/table/vertical-align-baseline-readjust.html
-/sdcard/android/layout_tests/fast/table/empty-row-crash.html
-/sdcard/android/layout_tests/fast/table/002.html
-/sdcard/android/layout_tests/fast/table/030.html
-/sdcard/android/layout_tests/fast/table/cell-width-auto.html
-/sdcard/android/layout_tests/fast/table/014.html
-/sdcard/android/layout_tests/fast/table/037.xml
-/sdcard/android/layout_tests/fast/table/large-width.html
-/sdcard/android/layout_tests/fast/table/026.html
-/sdcard/android/layout_tests/fast/table/unbreakable-images-quirk.html
-/sdcard/android/layout_tests/fast/table/038.html
-/sdcard/android/layout_tests/fast/table/dynamic-cellpadding.html
-/sdcard/android/layout_tests/fast/table/generated-caption.html
-/sdcard/android/layout_tests/fast/table/empty-cells.html
-/sdcard/android/layout_tests/fast/table/add-before-anonymous-child.html
-/sdcard/android/layout_tests/fast/table/011.html
-/sdcard/android/layout_tests/fast/table/table-display-types-strict.html
-/sdcard/android/layout_tests/fast/table/023.html
-/sdcard/android/layout_tests/fast/table/007.html
-/sdcard/android/layout_tests/fast/table/cellindex.html
-/sdcard/android/layout_tests/fast/table/035.html
-/sdcard/android/layout_tests/fast/table/colgroup-spanning-groups-rules.html
-/sdcard/android/layout_tests/fast/table/insert-row-before-form.html
-/sdcard/android/layout_tests/fast/table/rowspan-paint-order.html
-/sdcard/android/layout_tests/fast/table/rtl-cell-display-none-assert.html
-/sdcard/android/layout_tests/fast/table/insert-cell-before-form.html
-/sdcard/android/layout_tests/fast/table/replaced-percent-height.html
-/sdcard/android/layout_tests/fast/table/text-field-baseline.html
-/sdcard/android/layout_tests/fast/table/table-display-types.html
-/sdcard/android/layout_tests/fast/table/table-hspace-align-center.html
-/sdcard/android/layout_tests/fast/table/caption-relayout.html
-/sdcard/android/layout_tests/fast/table/020.html
-/sdcard/android/layout_tests/fast/table/fixed-table-non-cell-in-row.html
-/sdcard/android/layout_tests/fast/table/004.html
-/sdcard/android/layout_tests/fast/table/032.html
-/sdcard/android/layout_tests/fast/table/row-height-recalc.html
-/sdcard/android/layout_tests/fast/table/016.html
-/sdcard/android/layout_tests/fast/table/absolute-table-at-bottom.html
-/sdcard/android/layout_tests/fast/table/028.html
-/sdcard/android/layout_tests/fast/table/spanOverlapRepaint.html
-/sdcard/android/layout_tests/fast/table/invisible-cell-background.html
-/sdcard/android/layout_tests/fast/table/vertical-align-baseline.html
-/sdcard/android/layout_tests/fast/table/cell-coalescing.html
-/sdcard/android/layout_tests/fast/table/wide-colspan.html
-/sdcard/android/layout_tests/fast/table/rowindex.html
-/sdcard/android/layout_tests/fast/table/001.html
-/sdcard/android/layout_tests/fast/table/remove-td-display-none.html
-/sdcard/android/layout_tests/fast/table/013.html
-/sdcard/android/layout_tests/fast/table/041.html
-/sdcard/android/layout_tests/fast/table/colgroup-preceded-by-caption.html
-/sdcard/android/layout_tests/fast/table/025.html
-/sdcard/android/layout_tests/fast/table/giantCellspacing.html
-/sdcard/android/layout_tests/fast/table/009.html
-/sdcard/android/layout_tests/fast/table/edge-offsets.html
-/sdcard/android/layout_tests/fast/table/giantRowspan.html
-/sdcard/android/layout_tests/fast/table/inline-form-assert.html
-/sdcard/android/layout_tests/fast/table/overflowHidden.html
-/sdcard/android/layout_tests/fast/table/rules-attr-dynchange2.html
-/sdcard/android/layout_tests/fast/table/height-percent-test.html
-/sdcard/android/layout_tests/fast/table/multiple-percent-height-rows.html
-/sdcard/android/layout_tests/fast/table/giantRowspan2.html
-/sdcard/android/layout_tests/fast/table/010.html
-/sdcard/android/layout_tests/fast/table/tableInsideCaption.html
-/sdcard/android/layout_tests/fast/table/022.html
-/sdcard/android/layout_tests/fast/table/006.html
-/sdcard/android/layout_tests/fast/table/034.html
-/sdcard/android/layout_tests/fast/table/append-cells.html
-/sdcard/android/layout_tests/fast/table/018.html
-/sdcard/android/layout_tests/fast/table/percent-widths-stretch.html
-/sdcard/android/layout_tests/fast/table/prepend-in-anonymous-table.html
-/sdcard/android/layout_tests/fast/table/floating-th.html
-/sdcard/android/layout_tests/fast/table/empty-section-crash.html
-/sdcard/android/layout_tests/fast/table/form-with-table-style.html
-/sdcard/android/layout_tests/fast/table/003.html
-/sdcard/android/layout_tests/fast/table/031.html
-/sdcard/android/layout_tests/fast/table/015.html
-/sdcard/android/layout_tests/fast/table/027.html
-/sdcard/android/layout_tests/fast/table/039.html
-/sdcard/android/layout_tests/fast/css/counters/invalidate-cached-counter-node.html
-/sdcard/android/layout_tests/fast/css/counters/counter-text-security.html
-/sdcard/android/layout_tests/fast/css/counters/counter-text-transform.html
-/sdcard/android/layout_tests/fast/css/variables/multiple-term-test.html
-/sdcard/android/layout_tests/fast/css/variables/colors-test.html
-/sdcard/android/layout_tests/fast/css/variables/font-test.html
-/sdcard/android/layout_tests/fast/css/variables/multiple-blocks-test.html
-/sdcard/android/layout_tests/fast/css/variables/misplaced-variables-test.html
-/sdcard/android/layout_tests/fast/css/variables/invalid-variable-test.html
-/sdcard/android/layout_tests/fast/css/variables/misplaced-import-test.html
-/sdcard/android/layout_tests/fast/css/variables/import-test.html
-/sdcard/android/layout_tests/fast/css/variables/inline-style-test.html
-/sdcard/android/layout_tests/fast/css/variables/declaration-block-test.html
-/sdcard/android/layout_tests/fast/css/variables/margin-test.html
-/sdcard/android/layout_tests/fast/css/variables/set-variable-test.html
-/sdcard/android/layout_tests/fast/css/variables/override-test.html
-/sdcard/android/layout_tests/fast/css/variables/remove-variable-test.html
-/sdcard/android/layout_tests/fast/css/variables/variable-iteration-test.html
-/sdcard/android/layout_tests/fast/css/variables/image-test.html
-/sdcard/android/layout_tests/fast/css/variables/block-cycle-test.html
-/sdcard/android/layout_tests/fast/css/variables/shorthand-test.html
-/sdcard/android/layout_tests/fast/css/variables/print-test.html
-/sdcard/android/layout_tests/fast/css/namespaces/001.xml
-/sdcard/android/layout_tests/fast/css/namespaces/002.xml
-/sdcard/android/layout_tests/fast/css/namespaces/003.xml
-/sdcard/android/layout_tests/fast/css/namespaces/004.xml
-/sdcard/android/layout_tests/fast/css/namespaces/005.xml
-/sdcard/android/layout_tests/fast/css/namespaces/006.xml
-/sdcard/android/layout_tests/fast/css/namespaces/007.xml
-/sdcard/android/layout_tests/fast/css/font-face-in-media-rule.html
-/sdcard/android/layout_tests/fast/css/font-face-default-font.html
-/sdcard/android/layout_tests/fast/css/first-letter-float-after-float.html
-/sdcard/android/layout_tests/fast/css/invalidation-errors-2.html
-/sdcard/android/layout_tests/fast/css/line-height-negative.html
-/sdcard/android/layout_tests/fast/css/only-child-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/008.html
-/sdcard/android/layout_tests/fast/css/first-of-type-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers2.html
-/sdcard/android/layout_tests/fast/css/target-fragment-match.html
-/sdcard/android/layout_tests/fast/css/attribute-selector-dynamic.xml
-/sdcard/android/layout_tests/fast/css/zoom-font-size.html
-/sdcard/android/layout_tests/fast/css/live-cssrules.html
-/sdcard/android/layout_tests/fast/css/005.html
-/sdcard/android/layout_tests/fast/css/first-letter-hover.html
-/sdcard/android/layout_tests/fast/css/clip-zooming.html
-/sdcard/android/layout_tests/fast/css/color-quirk.html
-/sdcard/android/layout_tests/fast/css/resize-corner-tracking-transformed.html
-/sdcard/android/layout_tests/fast/css/selector-set-attribute.html
-/sdcard/android/layout_tests/fast/css/attribute-selector-empty-value.html
-/sdcard/android/layout_tests/fast/css/line-height-overflow.html
-/sdcard/android/layout_tests/fast/css/002.html
-/sdcard/android/layout_tests/fast/css/empty-generated-content.html
-/sdcard/android/layout_tests/fast/css/border-radius-outline-offset.html
-/sdcard/android/layout_tests/fast/css/background-image-with-baseurl.html
-/sdcard/android/layout_tests/fast/css/hsla-color.html
-/sdcard/android/layout_tests/fast/css/first-letter-skip-out-of-flow.html
-/sdcard/android/layout_tests/fast/css/font-face-multiple-remote-sources.html
-/sdcard/android/layout_tests/fast/css/pseudo-cache-stale.html
-/sdcard/android/layout_tests/fast/css/hover-subselector.html
-/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-strict.html
-/sdcard/android/layout_tests/fast/css/shadow-multiple.html
-/sdcard/android/layout_tests/fast/css/import_with_baseurl.html
-/sdcard/android/layout_tests/fast/css/list-outline.html
-/sdcard/android/layout_tests/fast/css/apple-prefix.html
-/sdcard/android/layout_tests/fast/css/line-height.html
-/sdcard/android/layout_tests/fast/css/first-letter-visibility.html
-/sdcard/android/layout_tests/fast/css/acid2.html
-/sdcard/android/layout_tests/fast/css/font_property_normal.html
-/sdcard/android/layout_tests/fast/css/css-imports.html
-/sdcard/android/layout_tests/fast/css/last-of-type-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/last-child-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/visibility-hit-test.html
-/sdcard/android/layout_tests/fast/css/absolute-poition-in-rtl-parent.html
-/sdcard/android/layout_tests/fast/css/content-dynamic.html
-/sdcard/android/layout_tests/fast/css/acid2-pixel.html
-/sdcard/android/layout_tests/fast/css/transition-color-unspecified.html
-/sdcard/android/layout_tests/fast/css/table-text-align-strict.html
-/sdcard/android/layout_tests/fast/css/transform-default-parameter.html
-/sdcard/android/layout_tests/fast/css/text-overflow-ellipsis-bidi.html
-/sdcard/android/layout_tests/fast/css/contentImage.html
-/sdcard/android/layout_tests/fast/css/value-list-out-of-bounds-crash.html
-/sdcard/android/layout_tests/fast/css/color-strict.html
-/sdcard/android/layout_tests/fast/css/ignore-text-zoom.html
-/sdcard/android/layout_tests/fast/css/max-height-none.html
-/sdcard/android/layout_tests/fast/css/invalidation-errors-3.html
-/sdcard/android/layout_tests/fast/css/empty-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/begin-end-contain-selector-empty-value.html
-/sdcard/android/layout_tests/fast/css/find-next-layer.html
-/sdcard/android/layout_tests/fast/css/text-overflow-ellipsis.html
-/sdcard/android/layout_tests/fast/css/contentDiv.html
-/sdcard/android/layout_tests/fast/css/invalid-pseudo-classes.html
-/sdcard/android/layout_tests/fast/css/disabled-author-styles.html
-/sdcard/android/layout_tests/fast/css/text-security.html
-/sdcard/android/layout_tests/fast/css/font-weight-1.html
-/sdcard/android/layout_tests/fast/css/nested-floating-relative-position-percentages.html
-/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-quirk.html
-/sdcard/android/layout_tests/fast/css/font-shorthand-weight-only.html
-/sdcard/android/layout_tests/fast/css/006.html
-/sdcard/android/layout_tests/fast/css/fieldset-display-row.html
-/sdcard/android/layout_tests/fast/css/border-height.html
-/sdcard/android/layout_tests/fast/css/css2-system-fonts.html
-/sdcard/android/layout_tests/fast/css/imageTileOpacity.html
-/sdcard/android/layout_tests/fast/css/font-face-remote.html
-/sdcard/android/layout_tests/fast/css/003.html
-/sdcard/android/layout_tests/fast/css/error-in-last-decl.html
-/sdcard/android/layout_tests/fast/css/zoom-property-parsing.html
-/sdcard/android/layout_tests/fast/css/style-outside-head.html
-/sdcard/android/layout_tests/fast/css/positioned-overflow-scroll.html
-/sdcard/android/layout_tests/fast/css/first-letter-capitalized.html
-/sdcard/android/layout_tests/fast/css/font-face-locally-installed.html
-/sdcard/android/layout_tests/fast/css/word-space-extra.html
-/sdcard/android/layout_tests/fast/css/first-letter-float.html
-/sdcard/android/layout_tests/fast/css/simple-selector-chain-parsing.html
-/sdcard/android/layout_tests/fast/css/xml-stylesheet-pi-not-in-prolog.xml
-/sdcard/android/layout_tests/fast/css/continuationCrash.html
-/sdcard/android/layout_tests/fast/css/vertical-align-lengths.html
-/sdcard/android/layout_tests/fast/css/first-child-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/percent-top-value-with-relative-position.html
-/sdcard/android/layout_tests/fast/css/beforeSelectorOnCodeElement.html
-/sdcard/android/layout_tests/fast/css/getFloatValueForUnit.html
-/sdcard/android/layout_tests/fast/css/first-letter-detach.html
-/sdcard/android/layout_tests/fast/css/line-height-font-order.html
-/sdcard/android/layout_tests/fast/css/text-overflow-ellipsis-strict.html
-/sdcard/android/layout_tests/fast/css/font-face-unicode-range.html
-/sdcard/android/layout_tests/fast/css/layerZOrderCrash.html
-/sdcard/android/layout_tests/fast/css/compare-content-style.html
-/sdcard/android/layout_tests/fast/css/import-rule-regression-11590.html
-/sdcard/android/layout_tests/fast/css/last-child-style-sharing.html
-/sdcard/android/layout_tests/fast/css/css3-modsel-22.html
-/sdcard/android/layout_tests/fast/css/ex-after-font-variant.html
-/sdcard/android/layout_tests/fast/css/quirk-orphaned-units.html
-/sdcard/android/layout_tests/fast/css/outline-auto-location.html
-/sdcard/android/layout_tests/fast/css/margin-top-bottom-dynamic.html
-/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values.html
-/sdcard/android/layout_tests/fast/css/empty-body-test.html
-/sdcard/android/layout_tests/fast/css/007.html
-/sdcard/android/layout_tests/fast/css/link-outside-head.html
-/sdcard/android/layout_tests/fast/css/font-size-negative.html
-/sdcard/android/layout_tests/fast/css/rem-units-on-root.html
-/sdcard/android/layout_tests/fast/css/position-negative-top-margin.html
-/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers.html
-/sdcard/android/layout_tests/fast/css/only-of-type-pseudo-class.html
-/sdcard/android/layout_tests/fast/css/004.html
-/sdcard/android/layout_tests/fast/css/rtl-ordering.html
-/sdcard/android/layout_tests/fast/css/affected-by-hover-after-style-change.html
-/sdcard/android/layout_tests/fast/css/resize-corner-tracking.html
-/sdcard/android/layout_tests/fast/css/invalidation-errors.html
-/sdcard/android/layout_tests/fast/css/background-shorthand-invalid-url.html
-/sdcard/android/layout_tests/fast/css/MarqueeLayoutTest.html
-/sdcard/android/layout_tests/fast/css/textCapitalizeEdgeCases.html
-/sdcard/android/layout_tests/fast/css/001.html
-/sdcard/android/layout_tests/fast/css/hsl-color.html
-/sdcard/android/layout_tests/fast/css/font-face-implicit-local-font.html
-/sdcard/android/layout_tests/fast/css/first-letter-recalculation.html
-/sdcard/android/layout_tests/fast/css/rem-dynamic-scaling.html
-/sdcard/android/layout_tests/fast/css/inline-properties-important.html
-/sdcard/android/layout_tests/fast/css/dynamic-sibling-selector.html
-/sdcard/android/layout_tests/fast/css/table-text-align-quirk.html
-/sdcard/android/layout_tests/fast/css/nth-child-dynamic.html
-/sdcard/android/layout_tests/fast/css/outline-auto-empty-rects.html
-/sdcard/android/layout_tests/fast/css/font-face-multiple-faces.html
-/sdcard/android/layout_tests/fast/css/rgb-float.html
-/sdcard/android/layout_tests/fast/css/pendingStylesheetFontSize.html
-/sdcard/android/layout_tests/fast/css/contentDivWithChildren.html
-/sdcard/android/layout_tests/fast/css/universal-hover-quirk.html
-/sdcard/android/layout_tests/fast/css/css3-nth-child.html
-/sdcard/android/layout_tests/fast/css/style-parsed-outside-head.html
-/sdcard/android/layout_tests/fast/css/percentage-non-integer.html
-/sdcard/android/layout_tests/fast/css/nested-layers-with-hover.html
-/sdcard/android/layout_tests/fast/css/negative-nth-child.html
-/sdcard/android/layout_tests/fast/box-sizing/panels-one.html
-/sdcard/android/layout_tests/fast/box-sizing/percentage-height.html
-/sdcard/android/layout_tests/fast/box-sizing/box-sizing.html
-/sdcard/android/layout_tests/fast/box-sizing/panels-two.html
-/sdcard/android/layout_tests/fast/block/basic/minheight.html
-/sdcard/android/layout_tests/fast/block/basic/min-pref-width-nowrap-floats.html
-/sdcard/android/layout_tests/fast/block/basic/fieldset-stretch-to-legend.html
-/sdcard/android/layout_tests/fast/block/basic/white-space-pre-wraps.html
-/sdcard/android/layout_tests/fast/block/basic/adding-near-anonymous-block.html
-/sdcard/android/layout_tests/fast/block/basic/quirk-percent-height-grandchild.html
-/sdcard/android/layout_tests/fast/block/basic/001.html
-/sdcard/android/layout_tests/fast/block/basic/010.html
-/sdcard/android/layout_tests/fast/block/basic/quirk-height.html
-/sdcard/android/layout_tests/fast/block/basic/020.html
-/sdcard/android/layout_tests/fast/block/basic/002.html
-/sdcard/android/layout_tests/fast/block/basic/011.html
-/sdcard/android/layout_tests/fast/block/basic/text-indent-rtl.html
-/sdcard/android/layout_tests/fast/block/basic/021.html
-/sdcard/android/layout_tests/fast/block/basic/003.html
-/sdcard/android/layout_tests/fast/block/basic/012.html
-/sdcard/android/layout_tests/fast/block/basic/013.html
-/sdcard/android/layout_tests/fast/block/basic/004.html
-/sdcard/android/layout_tests/fast/block/basic/014.html
-/sdcard/android/layout_tests/fast/block/basic/005.html
-/sdcard/android/layout_tests/fast/block/basic/015.html
-/sdcard/android/layout_tests/fast/block/basic/006.html
-/sdcard/android/layout_tests/fast/block/basic/016.html
-/sdcard/android/layout_tests/fast/block/basic/007.html
-/sdcard/android/layout_tests/fast/block/basic/008.html
-/sdcard/android/layout_tests/fast/block/basic/009.html
-/sdcard/android/layout_tests/fast/block/basic/018.html
-/sdcard/android/layout_tests/fast/block/basic/019.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/001.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/002.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/003.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/004.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/005.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/006.html
-/sdcard/android/layout_tests/fast/block/positioning/auto/007.html
-/sdcard/android/layout_tests/fast/block/positioning/059.html
-/sdcard/android/layout_tests/fast/block/positioning/negative-rel-position.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-rtl.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-ltr.html
-/sdcard/android/layout_tests/fast/block/positioning/fixed-positioning-scrollbar-bug.html
-/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced-float.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-positioned-overconstrained.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-2.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-2.html
-/sdcard/android/layout_tests/fast/block/positioning/020.html
-/sdcard/android/layout_tests/fast/block/positioning/012.html
-/sdcard/android/layout_tests/fast/block/positioning/004.html
-/sdcard/android/layout_tests/fast/block/positioning/040.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-strict.html
-/sdcard/android/layout_tests/fast/block/positioning/032.html
-/sdcard/android/layout_tests/fast/block/positioning/060.html
-/sdcard/android/layout_tests/fast/block/positioning/024.html
-/sdcard/android/layout_tests/fast/block/positioning/052.html
-/sdcard/android/layout_tests/fast/block/positioning/016.html
-/sdcard/android/layout_tests/fast/block/positioning/044.html
-/sdcard/android/layout_tests/fast/block/positioning/008.html
-/sdcard/android/layout_tests/fast/block/positioning/036.html
-/sdcard/android/layout_tests/fast/block/positioning/028.html
-/sdcard/android/layout_tests/fast/block/positioning/056.html
-/sdcard/android/layout_tests/fast/block/positioning/048.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-quirk.html
-/sdcard/android/layout_tests/fast/block/positioning/replaced-inside-fixed-top-bottom.html
-/sdcard/android/layout_tests/fast/block/positioning/pref-width-change.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-3.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-3.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl.html
-/sdcard/android/layout_tests/fast/block/positioning/001.html
-/sdcard/android/layout_tests/fast/block/positioning/021.html
-/sdcard/android/layout_tests/fast/block/positioning/013.html
-/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-block.html
-/sdcard/android/layout_tests/fast/block/positioning/005.html
-/sdcard/android/layout_tests/fast/block/positioning/041.html
-/sdcard/android/layout_tests/fast/block/positioning/033.html
-/sdcard/android/layout_tests/fast/block/positioning/025.html
-/sdcard/android/layout_tests/fast/block/positioning/061.html
-/sdcard/android/layout_tests/fast/block/positioning/017.html
-/sdcard/android/layout_tests/fast/block/positioning/053.html
-/sdcard/android/layout_tests/fast/block/positioning/009.html
-/sdcard/android/layout_tests/fast/block/positioning/045.html
-/sdcard/android/layout_tests/fast/block/positioning/037.html
-/sdcard/android/layout_tests/fast/block/positioning/029.html
-/sdcard/android/layout_tests/fast/block/positioning/057.html
-/sdcard/android/layout_tests/fast/block/positioning/049.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-quirks.html
-/sdcard/android/layout_tests/fast/block/positioning/leftmargin-topmargin.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-length-of-neg-666666.html
-/sdcard/android/layout_tests/fast/block/positioning/complex-percentage-height.html
-/sdcard/android/layout_tests/fast/block/positioning/auto-height-with-top-and-bottom.html
-/sdcard/android/layout_tests/fast/block/positioning/010.html
-/sdcard/android/layout_tests/fast/block/positioning/002.html
-/sdcard/android/layout_tests/fast/block/positioning/030.html
-/sdcard/android/layout_tests/fast/block/positioning/relayout-on-position-change.html
-/sdcard/android/layout_tests/fast/block/positioning/022.html
-/sdcard/android/layout_tests/fast/block/positioning/padding-percent.html
-/sdcard/android/layout_tests/fast/block/positioning/014.html
-/sdcard/android/layout_tests/fast/block/positioning/050.html
-/sdcard/android/layout_tests/fast/block/positioning/042.html
-/sdcard/android/layout_tests/fast/block/positioning/006.html
-/sdcard/android/layout_tests/fast/block/positioning/034.html
-/sdcard/android/layout_tests/fast/block/positioning/offsetLeft-offsetTop-borders.html
-/sdcard/android/layout_tests/fast/block/positioning/062.html
-/sdcard/android/layout_tests/fast/block/positioning/026.html
-/sdcard/android/layout_tests/fast/block/positioning/054.html
-/sdcard/android/layout_tests/fast/block/positioning/018.html
-/sdcard/android/layout_tests/fast/block/positioning/046.html
-/sdcard/android/layout_tests/fast/block/positioning/abs-inside-inline-rel.html
-/sdcard/android/layout_tests/fast/block/positioning/038.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-strict.html
-/sdcard/android/layout_tests/fast/block/positioning/058.html
-/sdcard/android/layout_tests/fast/block/positioning/negative-right-pos.html
-/sdcard/android/layout_tests/fast/block/positioning/relative-overconstrained.html
-/sdcard/android/layout_tests/fast/block/positioning/child-of-absolute-with-auto-height.html
-/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced.html
-/sdcard/android/layout_tests/fast/block/positioning/height-change.html
-/sdcard/android/layout_tests/fast/block/positioning/window-height-change.html
-/sdcard/android/layout_tests/fast/block/positioning/011.html
-/sdcard/android/layout_tests/fast/block/positioning/003.html
-/sdcard/android/layout_tests/fast/block/positioning/move-with-auto-width.html
-/sdcard/android/layout_tests/fast/block/positioning/031.html
-/sdcard/android/layout_tests/fast/block/positioning/023.html
-/sdcard/android/layout_tests/fast/block/positioning/051.html
-/sdcard/android/layout_tests/fast/block/positioning/015.html
-/sdcard/android/layout_tests/fast/block/positioning/043.html
-/sdcard/android/layout_tests/fast/block/positioning/007.html
-/sdcard/android/layout_tests/fast/block/positioning/035.html
-/sdcard/android/layout_tests/fast/block/positioning/027.html
-/sdcard/android/layout_tests/fast/block/positioning/055.html
-/sdcard/android/layout_tests/fast/block/positioning/019.html
-/sdcard/android/layout_tests/fast/block/positioning/047.html
-/sdcard/android/layout_tests/fast/block/positioning/039.html
-/sdcard/android/layout_tests/fast/block/positioning/inline-block-relposition.html
-/sdcard/android/layout_tests/fast/block/float/vertical-move-relayout.html
-/sdcard/android/layout_tests/fast/block/float/overlapping-floats-with-overflow-hidden.html
-/sdcard/android/layout_tests/fast/block/float/tableshifting.html
-/sdcard/android/layout_tests/fast/block/float/table-relayout.html
-/sdcard/android/layout_tests/fast/block/float/nested-clearance.html
-/sdcard/android/layout_tests/fast/block/float/br-with-clear-2.html
-/sdcard/android/layout_tests/fast/block/float/020.html
-/sdcard/android/layout_tests/fast/block/float/012.html
-/sdcard/android/layout_tests/fast/block/float/004.html
-/sdcard/android/layout_tests/fast/block/float/032.html
-/sdcard/android/layout_tests/fast/block/float/024.html
-/sdcard/android/layout_tests/fast/block/float/016.html
-/sdcard/android/layout_tests/fast/block/float/008.html
-/sdcard/android/layout_tests/fast/block/float/028.html
-/sdcard/android/layout_tests/fast/block/float/shrink-to-fit-width.html
-/sdcard/android/layout_tests/fast/block/float/clamped-right-float.html
-/sdcard/android/layout_tests/fast/block/float/independent-align-positioning.html
-/sdcard/android/layout_tests/fast/block/float/float-on-zero-height-line.html
-/sdcard/android/layout_tests/fast/block/float/nowrap-clear-min-width.html
-/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease-offsets.html
-/sdcard/android/layout_tests/fast/block/float/001.html
-/sdcard/android/layout_tests/fast/block/float/021.html
-/sdcard/android/layout_tests/fast/block/float/013.html
-/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction2.html
-/sdcard/android/layout_tests/fast/block/float/005.html
-/sdcard/android/layout_tests/fast/block/float/033.html
-/sdcard/android/layout_tests/fast/block/float/025.html
-/sdcard/android/layout_tests/fast/block/float/017.html
-/sdcard/android/layout_tests/fast/block/float/009.html
-/sdcard/android/layout_tests/fast/block/float/float-in-float-hit-testing.html
-/sdcard/android/layout_tests/fast/block/float/029.html
-/sdcard/android/layout_tests/fast/block/float/4145535Crash.html
-/sdcard/android/layout_tests/fast/block/float/editable-text-overlapping-float.html
-/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks.html
-/sdcard/android/layout_tests/fast/block/float/intruding-painted-twice.html
-/sdcard/android/layout_tests/fast/block/float/010.html
-/sdcard/android/layout_tests/fast/block/float/002.html
-/sdcard/android/layout_tests/fast/block/float/dynamic-unfloat-pref-width.html
-/sdcard/android/layout_tests/fast/block/float/marquee-shrink-to-avoid-floats.html
-/sdcard/android/layout_tests/fast/block/float/030.html
-/sdcard/android/layout_tests/fast/block/float/022.html
-/sdcard/android/layout_tests/fast/block/float/014.html
-/sdcard/android/layout_tests/fast/block/float/006.html
-/sdcard/android/layout_tests/fast/block/float/relative-painted-twice.html
-/sdcard/android/layout_tests/fast/block/float/034.html
-/sdcard/android/layout_tests/fast/block/float/026.html
-/sdcard/android/layout_tests/fast/block/float/018.html
-/sdcard/android/layout_tests/fast/block/float/width-update-after-clear.html
-/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction.html
-/sdcard/android/layout_tests/fast/block/float/float-in-float-painting.html
-/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease.html
-/sdcard/android/layout_tests/fast/block/float/float-avoidance.html
-/sdcard/android/layout_tests/fast/block/float/narrow-after-wide.html
-/sdcard/android/layout_tests/fast/block/float/multiple-float-positioning.html
-/sdcard/android/layout_tests/fast/block/float/br-with-clear.html
-/sdcard/android/layout_tests/fast/block/float/011.html
-/sdcard/android/layout_tests/fast/block/float/negative-margin-clear.html
-/sdcard/android/layout_tests/fast/block/float/003.html
-/sdcard/android/layout_tests/fast/block/float/031.html
-/sdcard/android/layout_tests/fast/block/float/023.html
-/sdcard/android/layout_tests/fast/block/float/015.html
-/sdcard/android/layout_tests/fast/block/float/007.html
-/sdcard/android/layout_tests/fast/block/float/035.html
-/sdcard/android/layout_tests/fast/block/float/027.html
-/sdcard/android/layout_tests/fast/block/float/019.html
-/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks2.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/059.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/empty-clear-blocks.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/010.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/negative-margins.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/002.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/020.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/101.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/030.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/012.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/040.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/022.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/004.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/103.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/032.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/006.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/042.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/016.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/034.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/062.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/044.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/026.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/018.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/028.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/056.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/038.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/058.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/100.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/001.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/011.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/102.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/021.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/003.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/031.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/005.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/041.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/104.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/033.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/015.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/025.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/043.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/035.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/017.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/027.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/045.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/063.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/037.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/019.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/055.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/029.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/039.html
-/sdcard/android/layout_tests/fast/block/margin-collapse/057.html
-/sdcard/android/layout_tests/fast/runin/generated.html
-/sdcard/android/layout_tests/fast/runin/001.html
-/sdcard/android/layout_tests/fast/runin/002.html
-/sdcard/android/layout_tests/fast/parser/comments.html
-/sdcard/android/layout_tests/fast/parser/title-error-test.html
-/sdcard/android/layout_tests/fast/parser/entity-comment-in-textarea.html
-/sdcard/android/layout_tests/fast/parser/parseCommentsInTitles.html
-/sdcard/android/layout_tests/fast/parser/open-comment-in-style.html
-/sdcard/android/layout_tests/fast/parser/document-write-option.html
-/sdcard/android/layout_tests/fast/parser/comment-in-textarea.html
-/sdcard/android/layout_tests/fast/parser/fonts.html
-/sdcard/android/layout_tests/fast/parser/comment-in-style.html
-/sdcard/android/layout_tests/fast/parser/comment-in-script.html
-/sdcard/android/layout_tests/fast/parser/broken-comments-vs-parsing-mode.html
-/sdcard/android/layout_tests/fast/parser/entity-comment-in-style.html
-/sdcard/android/layout_tests/fast/parser/xhtml-alternate-entities.xml
-/sdcard/android/layout_tests/fast/parser/nofoo-tags-inside-paragraph.html
-/sdcard/android/layout_tests/fast/parser/bad-xml-slash.html
-/sdcard/android/layout_tests/fast/parser/001.html
-/sdcard/android/layout_tests/fast/parser/open-comment-in-textarea.html
-/sdcard/android/layout_tests/fast/parser/tabs-in-scripts.html
-/sdcard/android/layout_tests/fast/parser/remove-block-in-residual-style.html
-/sdcard/android/layout_tests/fast/parser/style-script-head-test.html
-/sdcard/android/layout_tests/fast/layers/zindex-ridonkulous.html
-/sdcard/android/layout_tests/fast/layers/self-painting-outline.html
-/sdcard/android/layout_tests/fast/layers/positioned-inside-root-with-margins.html
-/sdcard/android/layout_tests/fast/layers/video-layer.html
-/sdcard/android/layout_tests/fast/layers/inline-dirty-z-order-lists.html
-/sdcard/android/layout_tests/fast/layers/layer-visibility-sublayer.html
-/sdcard/android/layout_tests/fast/layers/opacity-outline.html
-/sdcard/android/layout_tests/fast/layers/add-layer-with-nested-stacking.html
-/sdcard/android/layout_tests/fast/layers/layer-content-visibility-change.html
-/sdcard/android/layout_tests/fast/layers/normal-flow-hit-test.html
-/sdcard/android/layout_tests/fast/layers/remove-layer-with-nested-stacking.html
-/sdcard/android/layout_tests/fast/layers/layer-visibility.html
-/sdcard/android/layout_tests/fast/layers/zindex-inherit.html
-/sdcard/android/layout_tests/fast/layers/overflow-scroll-auto-switch.html
-/sdcard/android/layout_tests/fast/layers/opacity-transforms.html
-/sdcard/android/layout_tests/fast/layers/scroll-rect-to-visible.html
-/sdcard/android/layout_tests/fast/layers/opacity-stacking.html
-/sdcard/android/layout_tests/fast/layers/remove-only-this-layer-update.html
-/sdcard/android/layout_tests/fast/history/clicked-link-is-visited.html
-/sdcard/android/layout_tests/fast/backgrounds/repeat/mask-negative-offset-repeat.html
-/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat.html
-/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
-/sdcard/android/layout_tests/fast/backgrounds/repeat/noRepeatCorrectClip.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize20.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize02.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize11.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize21.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize03.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize12.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize22.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize04.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize13.html
-/sdcard/android/layout_tests/fast/backgrounds/size/zero.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize05.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize14.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize06.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize15.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize07.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize16.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize08.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize17.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize09.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize18.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize19.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize10.html
-/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize01.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-2.html
-/sdcard/android/layout_tests/fast/backgrounds/background-origin-root-element.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-3.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-4.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-5.html
-/sdcard/android/layout_tests/fast/backgrounds/background-position-1.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-6.html
-/sdcard/android/layout_tests/fast/backgrounds/opacity-on-document-element.html
-/sdcard/android/layout_tests/fast/backgrounds/background-clip-text.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-mask.html
-/sdcard/android/layout_tests/fast/backgrounds/solid-color-context-restore.html
-/sdcard/android/layout_tests/fast/backgrounds/mask-composite.html
-/sdcard/android/layout_tests/fast/backgrounds/animated-svg-as-background.html
-/sdcard/android/layout_tests/fast/backgrounds/body-generated-image-propagated-to-root.html
-/sdcard/android/layout_tests/fast/backgrounds/001.html
-/sdcard/android/layout_tests/fast/backgrounds/animated-gif-as-background.html
-/sdcard/android/layout_tests/fast/backgrounds/background-position-rounding.html
-/sdcard/android/layout_tests/fast/backgrounds/bgCompositeCopy.html
-/sdcard/android/layout_tests/fast/backgrounds/background-inherit-color-bug.html
-/sdcard/android/layout_tests/fast/backgrounds/animated-svg-as-mask.html
-/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-1.html
-/sdcard/android/layout_tests/fast/repaint/reflection-redraw.html
-/sdcard/android/layout_tests/fast/repaint/layer-full-repaint.html
-/sdcard/android/layout_tests/fast/repaint/subtree-root-clip.html
-/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-3.html
-/sdcard/android/layout_tests/fast/repaint/layer-outline-horizontal.html
-/sdcard/android/layout_tests/fast/repaint/transform-layout-repaint.html
-/sdcard/android/layout_tests/fast/repaint/float-new-in-block.html
-/sdcard/android/layout_tests/fast/repaint/list-marker-2.html
-/sdcard/android/layout_tests/fast/repaint/layer-hide-when-needs-layout.html
-/sdcard/android/layout_tests/fast/repaint/layer-outline.html
-/sdcard/android/layout_tests/fast/repaint/table-section-overflow.html
-/sdcard/android/layout_tests/fast/repaint/body-background-image.html
-/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-vertical.html
-/sdcard/android/layout_tests/fast/repaint/inline-outline-repaint.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-4.html
-/sdcard/android/layout_tests/fast/repaint/change-transform.html
-/sdcard/android/layout_tests/fast/repaint/fixed.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-8.html
-/sdcard/android/layout_tests/fast/repaint/erase-overflow.html
-/sdcard/android/layout_tests/fast/repaint/outline-child-repaint.html
-/sdcard/android/layout_tests/fast/repaint/float-overflow.html
-/sdcard/android/layout_tests/fast/repaint/containing-block-position-change.html
-/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow.html
-/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow-horizontal.html
-/sdcard/android/layout_tests/fast/repaint/table-cell-move.html
-/sdcard/android/layout_tests/fast/repaint/transform-absolute-child.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-10.html
-/sdcard/android/layout_tests/fast/repaint/opacity-change-on-overflow-float.html
-/sdcard/android/layout_tests/fast/repaint/float-move-during-layout.html
-/sdcard/android/layout_tests/fast/repaint/overflow-clip-subtree-layout.html
-/sdcard/android/layout_tests/fast/repaint/invisible-objects.html
-/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-horizontal.html
-/sdcard/android/layout_tests/fast/repaint/focus-layers.html
-/sdcard/android/layout_tests/fast/repaint/inline-color-change.html
-/sdcard/android/layout_tests/fast/repaint/table-col-background.html
-/sdcard/android/layout_tests/fast/repaint/selection-after-remove.html
-/sdcard/android/layout_tests/fast/repaint/dynamic-table-vertical-alignment-change.html
-/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow.html
-/sdcard/android/layout_tests/fast/repaint/table-two-pass-layout-overpaint.html
-/sdcard/android/layout_tests/fast/repaint/overflow-into-content.html
-/sdcard/android/layout_tests/fast/repaint/shadow-multiple-vertical.html
-/sdcard/android/layout_tests/fast/repaint/border-repaint-glitch.html
-/sdcard/android/layout_tests/fast/repaint/continuation-after-outline.html
-/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position.html
-/sdcard/android/layout_tests/fast/repaint/table-section-repaint.html
-/sdcard/android/layout_tests/fast/repaint/clipped-relative.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-1.html
-/sdcard/android/layout_tests/fast/repaint/backgroundSizeRepaint.html
-/sdcard/android/layout_tests/fast/repaint/box-shadow-dynamic.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-5.html
-/sdcard/android/layout_tests/fast/repaint/text-shadow-horizontal.html
-/sdcard/android/layout_tests/fast/repaint/caret-outside-block.html
-/sdcard/android/layout_tests/fast/repaint/renderer-destruction-by-invalidateSelection-crash.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-9.html
-/sdcard/android/layout_tests/fast/repaint/float-in-new-block-with-layout-delta.html
-/sdcard/android/layout_tests/fast/repaint/transform-repaint-descendants.html
-/sdcard/android/layout_tests/fast/repaint/layout-state-relative.html
-/sdcard/android/layout_tests/fast/repaint/shadow-multiple-horizontal.html
-/sdcard/android/layout_tests/fast/repaint/border-fit-lines.html
-/sdcard/android/layout_tests/fast/repaint/repaint-resized-overflow.html
-/sdcard/android/layout_tests/fast/repaint/bugzilla-3509.html
-/sdcard/android/layout_tests/fast/repaint/inline-block-overflow.html
-/sdcard/android/layout_tests/fast/repaint/search-field-cancel.html
-/sdcard/android/layout_tests/fast/repaint/background-generated.html
-/sdcard/android/layout_tests/fast/repaint/bugzilla-6278.html
-/sdcard/android/layout_tests/fast/repaint/button-spurious-layout-hint.html
-/sdcard/android/layout_tests/fast/repaint/box-shadow-v.html
-/sdcard/android/layout_tests/fast/repaint/float-overflow-right.html
-/sdcard/android/layout_tests/fast/repaint/delete-into-nested-block.html
-/sdcard/android/layout_tests/fast/repaint/table-cell-collapsed-border.html
-/sdcard/android/layout_tests/fast/repaint/selection-after-delete.html
-/sdcard/android/layout_tests/fast/repaint/layout-state-only-positioned.html
-/sdcard/android/layout_tests/fast/repaint/lines-with-layout-delta.html
-/sdcard/android/layout_tests/fast/repaint/table-extra-bottom-grow.html
-/sdcard/android/layout_tests/fast/repaint/transform-relative-position.html
-/sdcard/android/layout_tests/fast/repaint/selection-gap-overflow-scroll.html
-/sdcard/android/layout_tests/fast/repaint/subtree-root-skipped.html
-/sdcard/android/layout_tests/fast/repaint/line-overflow.html
-/sdcard/android/layout_tests/fast/repaint/background-misaligned.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-2.html
-/sdcard/android/layout_tests/fast/repaint/text-append-dirty-lines.html
-/sdcard/android/layout_tests/fast/repaint/table-row.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-6.html
-/sdcard/android/layout_tests/fast/repaint/table-outer-border.html
-/sdcard/android/layout_tests/fast/repaint/transform-replaced-shadows.html
-/sdcard/android/layout_tests/fast/repaint/overflow-scroll-delete.html
-/sdcard/android/layout_tests/fast/repaint/layer-visibility.html
-/sdcard/android/layout_tests/fast/repaint/border-radius-repaint.html
-/sdcard/android/layout_tests/fast/repaint/table-collapsed-border.html
-/sdcard/android/layout_tests/fast/repaint/transform-translate.html
-/sdcard/android/layout_tests/fast/repaint/bugzilla-7235.html
-/sdcard/android/layout_tests/fast/repaint/reflection-repaint-test.html
-/sdcard/android/layout_tests/fast/repaint/4776765.html
-/sdcard/android/layout_tests/fast/repaint/selection-clear.html
-/sdcard/android/layout_tests/fast/repaint/bugzilla-6473.html
-/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position-clip.html
-/sdcard/android/layout_tests/fast/repaint/focus-ring.html
-/sdcard/android/layout_tests/fast/repaint/table-cell-vertical-overflow.html
-/sdcard/android/layout_tests/fast/repaint/create-layer-repaint.html
-/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-2.html
-/sdcard/android/layout_tests/fast/repaint/bugzilla-6388.html
-/sdcard/android/layout_tests/fast/repaint/overflow-outline-repaint.html
-/sdcard/android/layout_tests/fast/repaint/content-into-overflow.html
-/sdcard/android/layout_tests/fast/repaint/static-to-positioned.html
-/sdcard/android/layout_tests/fast/repaint/bugzilla-5699.html
-/sdcard/android/layout_tests/fast/repaint/transform-absolute-in-positioned-container.html
-/sdcard/android/layout_tests/fast/repaint/outline-repaint-glitch.html
-/sdcard/android/layout_tests/fast/repaint/overflow-delete-line.html
-/sdcard/android/layout_tests/fast/repaint/transform-disable-layoutstate.html
-/sdcard/android/layout_tests/fast/repaint/list-marker.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-3.html
-/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-7.html
-/sdcard/android/layout_tests/fast/repaint/outline-inset.html
-/sdcard/android/layout_tests/fast/repaint/box-shadow-h.html
-/sdcard/android/layout_tests/fast/repaint/4774354.html
-/sdcard/android/layout_tests/fast/repaint/clip-with-layout-delta.html
-/sdcard/android/layout_tests/fast/repaint/control-clip.html
-/sdcard/android/layout_tests/fast/repaint/selected-replaced.html
-/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow-2.html
-/sdcard/android/layout_tests/fast/repaint/make-children-non-inline.html
-/sdcard/android/layout_tests/fast/repaint/text-shadow.html
-/sdcard/android/layout_tests/fast/repaint/outline-shrinking.html
-/sdcard/android/layout_tests/fast/repaint/layer-child-outline.html
-/sdcard/android/layout_tests/fast/loader/start-load-in-unload.html
-/sdcard/android/layout_tests/fast/loader/text-document-wrapping.html
-/sdcard/android/layout_tests/fast/xsl/document-function.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-extra-content-at-end.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-enc.xml
-/sdcard/android/layout_tests/fast/xsl/xslt_unicode.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-import-depth.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-enc16.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-enc16to16.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-missing-namespace-in-xslt.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-enc-cyr.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-relative-path.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-mismatched-tags-in-xslt.xml
-/sdcard/android/layout_tests/fast/xsl/xslt-entity.xml
-/sdcard/android/layout_tests/fast/canvas/fillrect-gradient-zero-stops.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transforms-during-path.html
-/sdcard/android/layout_tests/fast/canvas/drawImage.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-7.html
-/sdcard/android/layout_tests/fast/canvas/image-pattern-rotate.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-4.html
-/sdcard/android/layout_tests/fast/canvas/drawImage-with-globalAlpha.html
-/sdcard/android/layout_tests/fast/canvas/canvas-text-baseline.html
-/sdcard/android/layout_tests/fast/canvas/canvas-as-image-incremental-repaint.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-1.html
-/sdcard/android/layout_tests/fast/canvas/canvas-size-change-after-layout.html
-/sdcard/android/layout_tests/fast/canvas/canvas-resize-reset.html
-/sdcard/android/layout_tests/fast/canvas/canvas-bg.html
-/sdcard/android/layout_tests/fast/canvas/zero-size-fill-rect.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-6.html
-/sdcard/android/layout_tests/fast/canvas/patternfill-repeat.html
-/sdcard/android/layout_tests/fast/canvas/image-object-in-canvas.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-3.html
-/sdcard/android/layout_tests/fast/canvas/canvas-composite.html
-/sdcard/android/layout_tests/fast/canvas/quadraticCurveTo.xml
-/sdcard/android/layout_tests/fast/canvas/gradient-add-second-start-end-stop.html
-/sdcard/android/layout_tests/fast/canvas/fill-stroke-clip-reset-path.html
-/sdcard/android/layout_tests/fast/canvas/canvas-text-alignment.html
-/sdcard/android/layout_tests/fast/canvas/canvas-incremental-repaint.html
-/sdcard/android/layout_tests/fast/canvas/canvas-bg-zoom.html
-/sdcard/android/layout_tests/fast/canvas/canvasDrawingIntoSelf.html
-/sdcard/android/layout_tests/fast/canvas/canvas-as-image.html
-/sdcard/android/layout_tests/fast/canvas/canvas-before-css.html
-/sdcard/android/layout_tests/fast/canvas/canvas-incremental-repaint-2.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-5.html
-/sdcard/android/layout_tests/fast/canvas/fillrect_gradient.html
-/sdcard/android/layout_tests/fast/canvas/shadow-offset-2.html
-/sdcard/android/layout_tests/fast/frames/contentWindow_Frame.html
-/sdcard/android/layout_tests/fast/frames/onlyCommentInIFrame.html
-/sdcard/android/layout_tests/fast/frames/content-opacity-2.html
-/sdcard/android/layout_tests/fast/frames/frame-src-attribute.html
-/sdcard/android/layout_tests/fast/frames/frameElement-frame.html
-/sdcard/android/layout_tests/fast/frames/empty-cols-attribute.html
-/sdcard/android/layout_tests/fast/frames/iframe-scrolling-attribute.html
-/sdcard/android/layout_tests/fast/frames/inline-object-inside-frameset.html
-/sdcard/android/layout_tests/fast/frames/valid.html
-/sdcard/android/layout_tests/fast/frames/no-frame-borders.html
-/sdcard/android/layout_tests/fast/frames/empty-frame-src.html
-/sdcard/android/layout_tests/fast/frames/calculate-round.html
-/sdcard/android/layout_tests/fast/frames/frame-navigation.html
-/sdcard/android/layout_tests/fast/frames/001.html
-/sdcard/android/layout_tests/fast/frames/viewsource-on-image-file.html
-/sdcard/android/layout_tests/fast/frames/invalid.html
-/sdcard/android/layout_tests/fast/frames/frameset-style-recalc.html
-/sdcard/android/layout_tests/fast/frames/viewsource-attribute.html
-/sdcard/android/layout_tests/fast/frames/002.html
-/sdcard/android/layout_tests/fast/frames/calculate-relative.html
-/sdcard/android/layout_tests/fast/frames/calculate-order.html
-/sdcard/android/layout_tests/fast/frames/calculate-percentage.html
-/sdcard/android/layout_tests/fast/frames/content-opacity-1.html
-/sdcard/android/layout_tests/fast/frames/iframe-text-contents.html
-/sdcard/android/layout_tests/fast/frames/frame-scrolling-attribute.html
-/sdcard/android/layout_tests/fast/frames/contentWindow_iFrame.html
-/sdcard/android/layout_tests/fast/frames/calculate-fixed.html
-/sdcard/android/layout_tests/fast/frames/frame-element-name.html
-/sdcard/android/layout_tests/fast/frames/frame-set-whitespace-attributes.html
-/sdcard/android/layout_tests/fast/frames/iframe-with-frameborder.html
-/sdcard/android/layout_tests/fast/frames/frameElement-iframe.html
-/sdcard/android/layout_tests/fast/reflections/inline-crash.html
-/sdcard/android/layout_tests/fast/reflections/reflection-masks-opacity.html
-/sdcard/android/layout_tests/fast/reflections/reflection-nesting.html
-/sdcard/android/layout_tests/fast/reflections/reflection-overflow-hidden.html
-/sdcard/android/layout_tests/fast/reflections/table-cell.html
-/sdcard/android/layout_tests/fast/reflections/reflection-masks.html
-/sdcard/android/layout_tests/fast/reflections/reflection-direction.html
-/sdcard/android/layout_tests/fonts/cursive.html
-/sdcard/android/layout_tests/fonts/default.html
-/sdcard/android/layout_tests/fonts/monospace.html
-/sdcard/android/layout_tests/fonts/fantasy.html
-/sdcard/android/layout_tests/fonts/serif.html
-/sdcard/android/layout_tests/fonts/sans-serif.html
-/sdcard/android/layout_tests/http/tests/webarchive/test-css-url-encoding-shift-jis.html
-/sdcard/android/layout_tests/http/tests/webarchive/test-css-url-encoding.html
-/sdcard/android/layout_tests/http/tests/webarchive/test-css-url-encoding-utf-8.html
-/sdcard/android/layout_tests/http/tests/webarchive/test-preload-resources.html
-/sdcard/android/layout_tests/http/tests/multipart/invalid-image-data.html
-/sdcard/android/layout_tests/http/tests/multipart/invalid-image-data-standalone.html
-/sdcard/android/layout_tests/http/tests/local/file-url-sent-as-referer.html
-/sdcard/android/layout_tests/http/tests/misc/location-replace-crossdomain.html
-/sdcard/android/layout_tests/http/tests/misc/acid2.html
-/sdcard/android/layout_tests/http/tests/misc/acid2-pixel.html
-/sdcard/android/layout_tests/http/tests/misc/favicon-as-image.html
-/sdcard/android/layout_tests/http/tests/misc/generated-content-inside-table.html
-/sdcard/android/layout_tests/http/tests/misc/willCacheResponse-delegate-callback.html
-/sdcard/android/layout_tests/http/tests/misc/iframe404.html
-/sdcard/android/layout_tests/http/tests/misc/frame-access-during-load.html
-/sdcard/android/layout_tests/http/tests/navigation/postredirect-goback1.html
-/sdcard/android/layout_tests/http/tests/navigation/error404-subframeload.html
-/sdcard/android/layout_tests/http/tests/navigation/error404-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/anchor-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/postredirect-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/post-goback1.html
-/sdcard/android/layout_tests/http/tests/navigation/post-basic.html
-/sdcard/android/layout_tests/http/tests/navigation/post-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/error404-goback.html
-/sdcard/android/layout_tests/http/tests/navigation/javascriptlink-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/postredirect-frames.html
-/sdcard/android/layout_tests/http/tests/navigation/error404-frames.html
-/sdcard/android/layout_tests/http/tests/loading/simple-subframe.html
-/sdcard/android/layout_tests/media/video-display-toggle.html
-/sdcard/android/layout_tests/media/video-transformed.html
-/sdcard/android/layout_tests/media/video-empty-source.html
-/sdcard/android/layout_tests/media/controls-strict.html
-/sdcard/android/layout_tests/media/audio-controls-rendering.html
-/sdcard/android/layout_tests/media/video-controls-visible-audio-only.html
-/sdcard/android/layout_tests/media/audio-no-installed-engines.html
-/sdcard/android/layout_tests/media/video-zoom.html
-/sdcard/android/layout_tests/media/video-zoom-controls.html
-/sdcard/android/layout_tests/media/video-controls-rendering.html
-/sdcard/android/layout_tests/media/controls-styling.html
-/sdcard/android/layout_tests/media/video-aspect-ratio.html
-/sdcard/android/layout_tests/media/controls-after-reload.html
-/sdcard/android/layout_tests/media/video-layer-crash.html
-/sdcard/android/layout_tests/plugins/netscape-dom-access.html
-/sdcard/android/layout_tests/plugins/embed-attributes-style.html
-/sdcard/android/layout_tests/printing/media-queries-print.html
-/sdcard/android/layout_tests/scrollbars/scrollbar-orientation.html
-/sdcard/android/layout_tests/scrollbars/scrollbar-buttons.html
-/sdcard/android/layout_tests/scrollbars/basic-scrollbar.html
-/sdcard/android/layout_tests/scrollbars/overflow-scrollbar-combinations.html
-/sdcard/android/layout_tests/scrollbars/disabled-scrollbar.html
-/sdcard/android/layout_tests/scrollbars/listbox-scrollbar-combinations.html
-/sdcard/android/layout_tests/security/block-test-no-port.html
-/sdcard/android/layout_tests/security/block-test.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/dom/insertTbodyRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/dom/appendCellsRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/dom/appendColGroup1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/dom/appendCol1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/dom/insertTbodyExpand1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/dom/appendCells1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug56024.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-14.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug11945.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-18.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug72393.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug23847.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug7121-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug27993-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug7243.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-3.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1647.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-7.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug101759.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug2479-5.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug14007-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-11.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1010.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-15.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug14159-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug25707.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug47163.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug91057.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug131020-3.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug19526.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug14489.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug73629.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1725.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-4.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug106336.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-8.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug22122.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug10216.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug14007-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug106966.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug32205-4.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug42043.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug178855.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-12.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug92868_1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug21518.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug45621.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-16.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug65372.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug59252.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug29058-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug17826.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug67915-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug46268-4.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1128.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1164.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/97619.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-5.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug10140.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-9.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug32205-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug61042-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug104898.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug8499.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug9879-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug128876.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-13.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug58402-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug24880-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug85016.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-17.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug80762-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug18770.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug33784.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3105.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1055-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug89315.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug92647-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug1262.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug7113.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3517.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug220653.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug4294.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-6.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug6933.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug51000.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug11331.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug61042-2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/bugs/bug3166-10.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/other/empty_cells.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/other/test4.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/col_span2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/columns.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/captions1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/cols1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/backgrounds.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/captions2.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/captions3.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/conflicts.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/core/standards1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/collapsing_borders/bug41262-5.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/collapsing_borders/bug41262-6.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/collapsing_borders/bug41262-1.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_below.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_position-table-cell.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_dirty_reflow_row.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_hidden_tr.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_position-table-column.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/tables_caption_align_right.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table-column-group.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_position-table-row-group.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption_hidden.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_row_sibling.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_lhs.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_tbody.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_rules_rows.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_rules_all.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_above.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_table.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_void.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_hsides.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_td_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption_right.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_hidden_tbody.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_layers-show.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_caption_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table-cell.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_below.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_table_caption.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_hidden_table.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_rules_cols.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_cell.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_position-table-row.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_td_align_right.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table-row.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_tbody_sibling.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_rules_cols.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_border.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_colgroup_width_px.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_td_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table-quirks.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_box.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_rules_rows.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_hsides.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption_left.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_caption_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption_hidden_table.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table-row-group.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption_bottom.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_rhs.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_frame_vsides.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_cell_sibling.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_layers-hide.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_td_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/tables_cellspacing_pct.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_position-table-column-group.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_lhs.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_fixed-bg.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_td_dynamic_deactivate.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_row.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_rhs.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_above.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/x_table_frame_vsides.xml
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_dirty_reflow.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_dirty_reflow_tbody.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/backgr_border-table-column.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_caption_top.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/table_overflow_dirty_reflow_table.html
-/sdcard/android/layout_tests/tables/mozilla_expected_failures/marvin/tables_caption_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteCellsRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteRowsShrink1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCellsRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCellsRebuild2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteCol1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteCol2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertColGroups1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteCol3.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertColGroups2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteCellsShrink1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteTbodyExpand1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteCellsShrink2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/tableDom.html
-/sdcard/android/layout_tests/tables/mozilla/dom/appendCol2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/appendTbodyExpand1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteTbodyRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteColGroup1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteColGroup2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertRowsExpand1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/appendRowsExpand1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/deleteRowsRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCols1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCols2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertRowsRebuild1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCellsExpand1.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCols3.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCellsExpand2.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCols4.html
-/sdcard/android/layout_tests/tables/mozilla/dom/insertCols5.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30418.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug14159-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46623-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug24661.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30692.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug53690-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug88035-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug51727.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug81934.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug68912.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug60992.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug92647-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug120107.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1271.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug28928.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug103533.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4093.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2267.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug92868.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4429.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5538.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug106816.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10009.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug149275-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug32205-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug13118.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1802s.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10296-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug647.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug48028-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug72359.xml
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug25367.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1430.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1224.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug67915-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug45486.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug113424.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug108340.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3454.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2479-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug139524-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4849-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug11321.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2886.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug219693-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug42443.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug54450.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug269566.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12709.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug80762-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug21918.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1302.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug25663.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug55527.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug7112-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1055-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug69382-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug17587.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug102145-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2516.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4803.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug19599.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1188.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3718.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug110566.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug106158-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5188.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug215629.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug154780.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug137388-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10039.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5798.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug22246-3a.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug25074.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug27038-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/45621.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug25086.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug43854-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug34538.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug131020.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug7121-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4501.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug53891.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8032-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46268-5.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug63785.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug113235-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug69187.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9024.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug120364.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug109043.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug220536.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1818-5.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2973.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug222467.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug6674.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug99948.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug277062.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug127267.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30332-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10036.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug16012.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2997.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug17130-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug650.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug14323.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10565.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug52505.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug29314.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug13169.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30559.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug29326.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug55545.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46268-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug18359.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3037-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug82946-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug55694.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug6304.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3263.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1818-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug101674.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug123862.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug221784-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug275625.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug106795.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug22513.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug57300.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug51037.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug119786.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12908-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug15247.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46623-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug34176.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug53690-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug24880.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug41890.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug88035-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug50695-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1163-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8411.xml
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1802.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3260.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug97138.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9123-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3309-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3191.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1296.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug222336.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2773.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8381.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug194024.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2947.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5838.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug60013.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug138725.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug11026.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug175455-4.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug58402-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug43039.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug48028-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug24627.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug35662.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug21299.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug26178.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug18664.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug23299.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug88524.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug48827.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1318.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4427.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug6184.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug11384s.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5835.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4576.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2479-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug139524-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug133948.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9879-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug11944.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug13196.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug20579.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug29058-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug96334.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug7112-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug60749.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug59354.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug69382-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug27993-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug57378.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug102145-4.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug98196.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9072.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2585.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug145572.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug137388-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5799.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug157890.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug196870.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug22246-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug73321.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug18440.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug965.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug131020-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug43854-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug96343.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46368-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug102145-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8032-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1067-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2065.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug97383.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug113235-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3681-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9271-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1809.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2962.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1818-6.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2469.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8950.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug133756-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2886-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug159108.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4849.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug25004.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12910.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug43204.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug20804.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug23072.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug19061-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10269-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug13526.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug52506.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug27038-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46480-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug42187.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2050.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3103.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug39209.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46268.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46268-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug38916.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug82946-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3037-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4523.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug67864.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8361.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1818-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2981-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2684.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4385.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug126742.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12910-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug8858.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug709.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug16252.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug33137.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug45350.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12908-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug92143.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug14159-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug50695-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug29429.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1261.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4520.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46944.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/adforce_imgis_com.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug18955.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug227123.xml
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3309-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9123-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug7342.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug83786.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4382.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug24200.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug641-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug625.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug32205-5.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug56201.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug32841.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug44505.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug45055-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug15544.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug40828.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1800.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug6404.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2509.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2479-4.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4739.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug139524-4.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug13105.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug149275-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug32205-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12008.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10296-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug727.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug278385.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug13484.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug15933.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug60807.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug93363.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug14929.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug86708.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug57828.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug11384q.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2954.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2479-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug139524-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug219693-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug137388-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30273.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug22246-3.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug22246-2a.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12384.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug44523.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug60804.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug86220.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug32447.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug17138.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug56405.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug26553.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1220.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug29058-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug33855.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug29157.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2123.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug19356.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug28933.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46368-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug18558.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug102145-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1067-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1474.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3681-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4284.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug4527.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug9271-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2296.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug106158-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2757.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug128229.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug133756-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug5797.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug278266.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug23235.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug19061-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10269-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug963.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug27038-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug12268.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug45055.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug7471.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug75250.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46480-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30985.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46924.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug56563.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug23994.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug113235-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug99923.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug55789.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2981-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1818-4.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug7714.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug222846.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug68998.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug30332-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug17130-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug51140.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug23151.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug10633.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug24503.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug28341.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug47432.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug101201.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug17168.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug46268-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug78162.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug17548.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug100334.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug57828-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1818-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug2763.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug1828.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug221784-1.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug3977.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug131020_iframe.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug641-2.html
-/sdcard/android/layout_tests/tables/mozilla/bugs/bug22019.html
-/sdcard/android/layout_tests/tables/mozilla/other/move_row.html
-/sdcard/android/layout_tests/tables/mozilla/other/nestedTables.html
-/sdcard/android/layout_tests/tables/mozilla/other/wa_table_tr_align.html
-/sdcard/android/layout_tests/tables/mozilla/other/ms.html
-/sdcard/android/layout_tests/tables/mozilla/other/cell_widths.html
-/sdcard/android/layout_tests/tables/mozilla/other/test3.html
-/sdcard/android/layout_tests/tables/mozilla/other/cellspacing.html
-/sdcard/android/layout_tests/tables/mozilla/other/nested2.html
-/sdcard/android/layout_tests/tables/mozilla/other/test6.html
-/sdcard/android/layout_tests/tables/mozilla/other/padding.html
-/sdcard/android/layout_tests/tables/mozilla/other/body_col.html
-/sdcard/android/layout_tests/tables/mozilla/other/wa_table_thtd_rowspan.html
-/sdcard/android/layout_tests/tables/mozilla/other/slashlogo.html
-/sdcard/android/layout_tests/tables/mozilla/images/adforce_imgis_com.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_auto.html
-/sdcard/android/layout_tests/tables/mozilla/core/captions.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_fixPer.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_autoFix.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_autoPer.html
-/sdcard/android/layout_tests/tables/mozilla/core/row_span.html
-/sdcard/android/layout_tests/tables/mozilla/core/cell_heights.html
-/sdcard/android/layout_tests/tables/mozilla/core/misc.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_autoFixPer.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_fix.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_per.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_auto.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_span.html
-/sdcard/android/layout_tests/tables/mozilla/core/margins.html
-/sdcard/android/layout_tests/tables/mozilla/core/borders.html
-/sdcard/android/layout_tests/tables/mozilla/core/table_frame.html
-/sdcard/android/layout_tests/tables/mozilla/core/table_rules.html
-/sdcard/android/layout_tests/tables/mozilla/core/table_heights.html
-/sdcard/android/layout_tests/tables/mozilla/core/nested1.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_autoFix.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_auto_fixPer.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_autoPer.html
-/sdcard/android/layout_tests/tables/mozilla/core/bloomberg.html
-/sdcard/android/layout_tests/tables/mozilla/core/one_row.html
-/sdcard/android/layout_tests/tables/mozilla/core/table_widths.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_autoFixPer.html
-/sdcard/android/layout_tests/tables/mozilla/core/box_sizing.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_fix.html
-/sdcard/android/layout_tests/tables/mozilla/core/col_widths_fix_per.html
-/sdcard/android/layout_tests/tables/mozilla/collapsing_borders/bug41262-3.html
-/sdcard/android/layout_tests/tables/mozilla/collapsing_borders/bug41262-4.html
-/sdcard/android/layout_tests/tables/mozilla/collapsing_borders/bug127040.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_green.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_olive.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_teal_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_width_pct.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_olive_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_border_0.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_simple-table-row-group.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_maroon_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_width_rel.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_lime.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/td_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_navy.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_simple-table-column.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_nowrap.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_style.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_bgcolor_rgb.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_green_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_caption_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_align_char.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_span.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_bgcolor_rgb.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/th_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_silver_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_rules_groups.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_gray.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_bgcolor_rgb.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_cellspacing.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_width_px.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_navy_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/td_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_yellow.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_width.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_green.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_simple-table-cell.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_silver.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_border_px.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_colspan.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_cellspacing_pct.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_nowrap.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_char.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_blue.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_navy.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_lime_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_aqua_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_rowspan.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_bgcolor_name.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_rowspan.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_navy_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_red.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_gray.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_align_justify.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_fuchsia.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_white_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_maroon_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_rules_none.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_caption_align_bot.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_cellpadding_pct.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_yellow_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_colspan.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_align_justify.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/th_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_colspan.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_nowrap.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_lime_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_aqua_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_border_none.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_border_1.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_row_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/td_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_maroon.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_frame_border.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_caption_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_blue.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_width_px.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_silver_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_width_rel.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_index.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_row_th_nowrap.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_black_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_width.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_cellpadding_pct.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_gray_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_olive_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_id.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_align_char.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/body_col.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_simple-table-row.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_fuchsia.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_cellpadding.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_caption_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_frame_void.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_rowspan.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_char.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_purple.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_rules_groups.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_simple-table.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_gray_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_class.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_width_pct.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/body_tfoot.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_span.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_width_pct.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_yellow_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_height.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_white.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_frame_box.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_yellow.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_width_px.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_char.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_row_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_border_2.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_aqua.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_fuchsia_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/td_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/th_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/col_span.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_row_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_purple_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_red_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_width_pct.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_green_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_border.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_white_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_valign_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_fuchsia_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_default.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_caption_align_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_silver.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_red.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_black.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_overflow_td_dynamic_deactivate.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_cellpadding.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_align_right.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_rowspan.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_cellspacing.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_rules_none.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_white.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_align_justify.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_rules_all.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_blue_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_black_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_align_left.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_align_right.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_caption_align_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_id.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_col_span.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_bgcolor_name.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_height.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_teal.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_height.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_olive.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_height.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/body_thead.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_maroon.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_simple-table-column-group.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/table_overflow_hidden_td.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_black.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_layers-opacity.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_bgcolor_name.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_red_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_blue_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_valign_top.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_lime.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/th_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_width_percent.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_width.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_teal_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_valign_middle.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_width_px.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_valign_baseline.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_align_char.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/backgr_position-table.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_align_char.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_th_width.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tfoot_align_center.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tbody_align_justify.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_bgcolor_rgb.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_purple_rgb.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/colgroup_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_td_colspan.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_caption_align_top.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_table_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_valign_middle.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_colgroup_align_center.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/thead_valign_baseline.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_thead_style.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tbody_class.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_border_3.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_align_left.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tr_valign_bottom.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/body_tbody.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_td_bgcolor_name.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_bgcolor_teal.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_tfoot_align_justify.xml
-/sdcard/android/layout_tests/tables/mozilla/marvin/tables_bgcolor_purple.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/tr_valign_bottom.html
-/sdcard/android/layout_tests/tables/mozilla/marvin/x_th_id.xml
-/sdcard/android/layout_tests/transforms/2d/transform-borderbox.html
-/sdcard/android/layout_tests/transforms/2d/zoom-menulist.html
-/sdcard/android/layout_tests/transforms/2d/transform-origin-borderbox.html
-/sdcard/android/layout_tests/transforms/2d/compound-transforms-vs-containers.html
-/sdcard/android/layout_tests/transforms/3d/hit-testing/backface-hit-test.html
-/sdcard/android/layout_tests/transforms/3d/hit-testing/backface-no-transform-hit-test.html
-/sdcard/android/layout_tests/transforms/3d/hit-testing/rotated-hit-test.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-origins.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-deep.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-coplanar.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-preserve-3d.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-2.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-3.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping.html
-/sdcard/android/layout_tests/transforms/3d/point-mapping/3d-point-mapping-overlapping.html
-/sdcard/android/layout_tests/transforms/3d/general/perspective-units.html
-/sdcard/android/layout_tests/transforms/3d/general/perspective-non-layer.html
-/sdcard/android/layout_tests/transforms/no_transform_hit_testing.html
-/sdcard/android/layout_tests/transitions/transition-drt-api.html
-/sdcard/android/layout_tests/webarchive/loading/cache-expired-subresource.html
-/sdcard/android/layout_tests/webarchive/test-css-import.html
-/sdcard/android/layout_tests/webarchive/test-img-src.html
-/sdcard/android/layout_tests/webarchive/test-link-rel-icon.html
-/sdcard/android/layout_tests/webarchive/adopt-attribute-styled-body-webarchive.html
-/sdcard/android/layout_tests/webarchive/archive-empty-frame-dom.html
-/sdcard/android/layout_tests/webarchive/test-frameset.html
-/sdcard/android/layout_tests/webarchive/test-body-background.html
-/sdcard/android/layout_tests/webarchive/test-input-src.html
-/sdcard/android/layout_tests/webarchive/archive-empty-frame-source.html
-/sdcard/android/layout_tests/webarchive/doctype.html
-/sdcard/android/layout_tests/webarchive/test-css-url-resources-inline-styles.html
-/sdcard/android/layout_tests/webarchive/test-table-background.html
-/sdcard/android/layout_tests/webarchive/adopt-inline-styled-node-webarchive.html
-/sdcard/android/layout_tests/webarchive/test-object-data.html
-/sdcard/android/layout_tests/webarchive/test-css-url-resources-in-stylesheets.html
-/sdcard/android/layout_tests/webarchive/archive-with-unencoded-url.html
-/sdcard/android/layout_tests/webarchive/test-link-href.html
-/sdcard/android/layout_tests/webarchive/test-duplicate-resources.html
-/sdcard/android/layout_tests/webarchive/test-xml-stylesheet.xml
-/sdcard/android/layout_tests/webarchive/test-td-background.html
-/sdcard/android/layout_tests/webarchive/test-script-src.html
-/sdcard/android/layout_tests/webarchive/adopt-attribute-styled-node-webarchive.html
diff --git a/tests/DumpRenderTree/assets/results/layout_tests_passed.txt b/tests/DumpRenderTree/assets/results/layout_tests_passed.txt
deleted file mode 100644
index 942b647..0000000
--- a/tests/DumpRenderTree/assets/results/layout_tests_passed.txt
+++ /dev/null
@@ -1,2960 +0,0 @@
-/sdcard/android/layout_tests/accessibility/non-native-image-crash.html
-/sdcard/android/layout_tests/animations/animation-css-rule-types.html
-/sdcard/android/layout_tests/animations/animation-events-create.html
-/sdcard/android/layout_tests/animations/play-state.html
-/sdcard/android/layout_tests/animations/animation-start-event-destroy-renderer.html
-/sdcard/android/layout_tests/animations/combo-transform-translate+scale.html
-/sdcard/android/layout_tests/animations/transform-origin-vs-functions.html
-/sdcard/android/layout_tests/animations/simultaneous-start-transform.html
-/sdcard/android/layout_tests/animations/lineheight-animation.html
-/sdcard/android/layout_tests/animations/import.html
-/sdcard/android/layout_tests/animations/simultaneous-start-left.html
-/sdcard/android/layout_tests/animations/fill-unset-properties.html
-/sdcard/android/layout_tests/animations/multiple-keyframes.html
-/sdcard/android/layout_tests/animations/change-one-anim.html
-/sdcard/android/layout_tests/animations/keyframes-comma-separated.html
-/sdcard/android/layout_tests/animations/matrix-anim.html
-/sdcard/android/layout_tests/animations/keyframes-rule.html
-/sdcard/android/layout_tests/animations/generic-from-to.html
-/sdcard/android/layout_tests/animations/big-rotation.html
-/sdcard/android/layout_tests/animations/keyframe-timing-functions.html
-/sdcard/android/layout_tests/animations/transition-and-animation-1.html
-/sdcard/android/layout_tests/animations/computed-style.html
-/sdcard/android/layout_tests/animations/animation-iteration-event-destroy-renderer.html
-/sdcard/android/layout_tests/animations/keyframes.html
-/sdcard/android/layout_tests/animations/multiple-animations.html
-/sdcard/android/layout_tests/animations/animation-end-event-destroy-renderer.html
-/sdcard/android/layout_tests/animations/transition-and-animation-2.html
-/sdcard/android/layout_tests/animations/import-crash.html
-/sdcard/android/layout_tests/animations/empty-keyframes.html
-/sdcard/android/layout_tests/animations/width-using-ems.html
-/sdcard/android/layout_tests/animations/combo-transform-rotate+scale.html
-/sdcard/android/layout_tests/animations/keyframes-out-of-order.html
-/sdcard/android/layout_tests/css1/units/zero-duration-without-units.html
-/sdcard/android/layout_tests/css2.1/atrule_longest_match.html
-/sdcard/android/layout_tests/css3/khtml-background-size-0x0-bmp.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrlastchild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementnormalize.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_noderemovechildnode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetattributenodenull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapreturnfirstitem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrparentnodenull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapreturnattrnode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementsetattributenodenull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementnormalize2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_noderemovechild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforeinvalidnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodechildnodesappendchild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrfirstchild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue05.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatagetlength.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrinsertdataoffsetnegative.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementinvalidcharacterexception.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textsplittexttwo.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrsetvalue1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeclonegetparentnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentcreatetextnode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentinvalidcharacterexceptioncreateelement.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelistreturnlastitem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrchildnodes1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrdeletedataoffsetnegative.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodetextnodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementretrieveallattributes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentinvalidcharacterexceptioncreateelement1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_domimplementationfeaturenoversion.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrprevioussiblingnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetelementsbytagnamespecialvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchildnodeancestor.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrappendchild1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetelementsbytagnamenomatch.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchildgetnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatadeletedataend.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatareplacedataexceedslengthofarg.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_notationssetnameditem1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechildinvalidnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforenodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore7.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetprevioussiblingnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodehaschildnodesfalse.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapreturnlastitem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetfirstchildnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_notationsremovenameditem1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforedocfragment.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataappenddata.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeattributenodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrspecifiedvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrgetvalue1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechildnewchilddiffdocument.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_domimplementationfeaturenull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrreplacedataoffsetnegative.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforenewchildexists.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue06.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelistindexnotzero.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textwithnomarkup.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_entitiessetnameditem1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrsetvalue2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentgetelementsbytagnametotallength.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentinvalidcharacterexceptioncreateattribute1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelistindexgetlengthofemptylist.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementchangeattributevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeattributenodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetnextsiblingnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapinuseattributeerr.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrchildnodes2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrcreatetextnode2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodechildnodesempty.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataappenddatagetdata.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatareplacedataend.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetlastchildnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrcreatetextnode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeclonefalsenocopytext.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrappendchild2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrreplacedataoffsetgreater.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodetextnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeparentnode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapnotfounderr.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementretrieveattrvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechildoldchildnonexistent.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbefore.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodehaschildnodes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodecommentnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/documentinvalidcharacterexceptioncreateentref1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrgetvalue2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementretrievetagname.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrspecifiedvaluechanged.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforenewchilddiffdocument.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrreplacedatacountnegative.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatadeletedatabegining.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentcreateelement.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrinsertdataoffsetgreater.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textparseintolistofelements.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue07.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetownerdocumentnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatareplacedatamiddle.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchildinvalidnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementremoveattributenode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrsubstringoffsetgreater.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatadeletedatamiddle.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatasubstringexceedsvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentgetrootnode.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatainsertdataend.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeclonenodetrue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapchildnoderange.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapnumberofnodes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue01.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentgetimplementation.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchildchildexists.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrappendchild3.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentgetelementsbytagnamelength.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeelementnodeattributes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrsubstringnegativeoffset.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_noderemovechildgetnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrsubstringcountnegative.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementnotfounderr.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentfragmentnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrdeletedataoffsetgreater.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatasubstringvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetownerdocument.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementassociatedattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementinvalidcharacterexception1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textindexsizeerroffsetoutofbounds.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatadeletedatagetlengthanddata.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechildnodeancestor.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue08.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textsplittextthree.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentcreateelementcasesensitive.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore3.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentnodeattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdataindexsizeerrdeletedatacountnegative.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeelementnodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechildnewchildexists.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_domimplementationfeaturexml.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementreplaceexistingattributegevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeelementnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementcreatenewattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodecommentnodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrnextsiblingnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrremovechild1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapwrongdocumenterr.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapreturnnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue02.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrappendchild4.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementinuseattributeerr.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetlastchild.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetattributenode.html
-/sdcard/android/layout_tests/dom/html/level1/core/documentgetdoctypenodtd.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapsetnameditemreturnvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatareplacedataexceedslengthofdata.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodetextnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeattributenodeattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentgetdoctype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapsetnameditemthatexists.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentcreatedocumentfragment.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_commentgetcomment.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attreffectivevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textsplittextfour.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforenodeancestor.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore4.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textindexsizeerrnegativeoffset.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodecommentnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodetextnodeattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentnodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatadeletedataexceedslength.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_textsplittextone.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentfragmentnodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatagetdata.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatainsertdatabeginning.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetnextsibling.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelistreturnfirstitem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrremovechild2.html
-/sdcard/android/layout_tests/dom/html/level1/core/documentinvalidcharacterexceptioncreatepi.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue03.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrappendchild5.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrhaschildnodes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrreplacechild1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrnormalize.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodedocumentfragmentnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementreplaceexistingattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchildnewchilddiffdocument.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelisttraverselist.html
-/sdcard/android/layout_tests/dom/html/level1/core/documentinvalidcharacterexceptioncreateentref.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatasetnodevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_entitiesremovenameditem1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore5.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetelementsbytagname.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrcreatedocumentfragment.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrclonenode1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapremovenameditem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementaddnewattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelistindexequalzero.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodechildnodes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetelementempty.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatainsertdatamiddle.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentcreatecomment.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetprevioussibling.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforerefchildnonexistent.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementremoveattributeaftercreate.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_noderemovechildoldchildnonexistent.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementwrongdocumenterr.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_characterdatareplacedatabegining.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeattributenodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodecommentnodeattributes.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodevalue04.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentinvalidcharacterexceptioncreateattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementremoveattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrappendchild6.html
-/sdcard/android/layout_tests/dom/html/level1/core/documentinvalidcharacterexceptioncreatepi1.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeelementnodetype.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrname.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapgetnameditem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgettagname.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapsetnameditem.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeinsertbeforerefchildnull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrreplacechild2.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeparentnodenull.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodecloneattributescopied.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeclonenodefalse.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodereplacechildnodename.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementgetelementsbytagnameaccessnodelist.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeclonetruecopytext.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_attrinsertbefore6.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodelistindexgetlength.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_elementreplaceattributewithself.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentcreateattribute.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodeappendchilddocfragment.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_namednodemapsetnameditemwithnewvalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_documentgetelementsbytagnamevalue.html
-/sdcard/android/layout_tests/dom/html/level1/core/hc_nodegetfirstchild.html
-/sdcard/android/layout_tests/dom/html/level2/events/EventTargetCast01.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent12.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent04.html
-/sdcard/android/layout_tests/dom/html/level2/events/createEvent02.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent08.html
-/sdcard/android/layout_tests/dom/html/level2/events/initEvent04.html
-/sdcard/android/layout_tests/dom/html/level2/events/DocumentEventCast01.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent01.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent13.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent05.html
-/sdcard/android/layout_tests/dom/html/level2/events/initEvent01.html
-/sdcard/android/layout_tests/dom/html/level2/events/createEvent03.html
-/sdcard/android/layout_tests/dom/html/level2/events/initEvent05.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent09.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent10.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent02.html
-/sdcard/android/layout_tests/dom/html/level2/events/initEvent02.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent06.html
-/sdcard/android/layout_tests/dom/html/level2/events/createEvent04.html
-/sdcard/android/layout_tests/dom/html/level2/events/initEvent06.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent11.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent03.html
-/sdcard/android/layout_tests/dom/html/level2/events/createEvent01.html
-/sdcard/android/layout_tests/dom/html/level2/events/dispatchEvent07.html
-/sdcard/android/layout_tests/dom/html/level2/events/initEvent03.html
-/sdcard/android/layout_tests/dom/html/level2/events/createEvent05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement87.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/hasFeature04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement26.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement141.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement37.html
-/sdcard/android/layout_tests/dom/html/level2/html/table12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIsIndexElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameSetElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLModElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement27.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement90.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/table45.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement124.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement40.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLParamElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement30.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptGroupElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement73.html
-/sdcard/android/layout_tests/dom/html/level2/html/table28.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/anchor02.html
-/sdcard/android/layout_tests/dom/html/level2/html/object09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement27.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement107.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement23.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMetaElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument25.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement56.html
-/sdcard/android/layout_tests/dom/html/level2/html/table31.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/object12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement30.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement89.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement110.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLabelElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/hasFeature06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement28.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement143.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBaseElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement39.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIsIndexElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLModElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement29.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement92.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/table47.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement126.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement42.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLParamElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement75.html
-/sdcard/android/layout_tests/dom/html/level2/html/table50.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/anchor04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement29.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement109.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement25.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument27.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement58.html
-/sdcard/android/layout_tests/dom/html/level2/html/table33.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadingElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/area01.html
-/sdcard/android/layout_tests/dom/html/level2/html/object14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement32.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement112.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLabelElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDivElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLUListElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement145.html
-/sdcard/android/layout_tests/dom/html/level2/html/button01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement61.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLegendElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCaptionElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement94.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFieldSetElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/table49.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLIElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement128.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMapElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement44.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement77.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/table52.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/anchor06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement131.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLParagraphElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement27.html
-/sdcard/android/layout_tests/dom/html/level2/html/table02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement80.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/table35.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadingElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/area03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement34.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement114.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement30.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLStyleElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/button03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement63.html
-/sdcard/android/layout_tests/dom/html/level2/html/table18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLegendElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement96.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement46.html
-/sdcard/android/layout_tests/dom/html/level2/html/table21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/object02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLQuoteElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement79.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement100.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement133.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement29.html
-/sdcard/android/layout_tests/dom/html/level2/html/table04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement82.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/table37.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadingElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement36.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement116.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement32.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/basefont01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLStyleElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement22.html
-/sdcard/android/layout_tests/dom/html/level2/html/button05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement65.html
-/sdcard/android/layout_tests/dom/html/level2/html/table40.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement98.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement48.html
-/sdcard/android/layout_tests/dom/html/level2/html/table23.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/object04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLPreElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement22.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOListElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement102.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement135.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement51.html
-/sdcard/android/layout_tests/dom/html/level2/html/table06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement84.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/table39.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/hasFeature01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement23.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement38.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement118.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement34.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBaseFontElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement24.html
-/sdcard/android/layout_tests/dom/html/level2/html/button07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement67.html
-/sdcard/android/layout_tests/dom/html/level2/html/table42.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement121.html
-/sdcard/android/layout_tests/dom/html/level2/html/dlist01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement70.html
-/sdcard/android/layout_tests/dom/html/level2/html/table25.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMenuElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFontElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement24.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement104.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMetaElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument22.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement137.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHRElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement53.html
-/sdcard/android/layout_tests/dom/html/level2/html/table08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement86.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/hasFeature03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement25.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement140.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement36.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBaseFontElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameSetElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement26.html
-/sdcard/android/layout_tests/dom/html/level2/html/button09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement69.html
-/sdcard/android/layout_tests/dom/html/level2/html/table44.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement123.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLParamElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement72.html
-/sdcard/android/layout_tests/dom/html/level2/html/table27.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/anchor01.html
-/sdcard/android/layout_tests/dom/html/level2/html/object08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement26.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement106.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement22.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMetaElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/body01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument24.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement139.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHRElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement55.html
-/sdcard/android/layout_tests/dom/html/level2/html/table30.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/object11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement88.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHtmlElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLabelElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTitleElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/hasFeature05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement27.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement142.html
-/sdcard/android/layout_tests/dom/html/level2/html/doc01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBaseElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/AppletsCollection.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement38.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIsIndexElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLModElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement28.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement91.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/table46.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement30.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement125.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement41.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLParamElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement31.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptGroupElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement74.html
-/sdcard/android/layout_tests/dom/html/level2/html/table29.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/anchor03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement28.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement108.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement24.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument26.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement57.html
-/sdcard/android/layout_tests/dom/html/level2/html/table32.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/object13.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement31.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement111.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLabelElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement29.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement144.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement60.html
-/sdcard/android/layout_tests/dom/html/level2/html/table15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLegendElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLModElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement93.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFieldSetElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/table48.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLIElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement127.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement43.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement76.html
-/sdcard/android/layout_tests/dom/html/level2/html/table51.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/anchor05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement130.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement26.html
-/sdcard/android/layout_tests/dom/html/level2/html/table01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement59.html
-/sdcard/android/layout_tests/dom/html/level2/html/table34.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadingElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/area02.html
-/sdcard/android/layout_tests/dom/html/level2/html/object15.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement33.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement113.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLUListElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBRElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/button02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLButtonElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement62.html
-/sdcard/android/layout_tests/dom/html/level2/html/table17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLegendElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement95.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionsCollection06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement129.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMapElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement45.html
-/sdcard/android/layout_tests/dom/html/level2/html/table20.html
-/sdcard/android/layout_tests/dom/html/level2/html/object01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement78.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/table53.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement22.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement17.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement132.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement28.html
-/sdcard/android/layout_tests/dom/html/level2/html/table03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement81.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/table36.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadingElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/area04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement20.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement35.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement115.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDlistElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement31.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLStyleElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement21.html
-/sdcard/android/layout_tests/dom/html/level2/html/button04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement64.html
-/sdcard/android/layout_tests/dom/html/level2/html/table19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement97.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement47.html
-/sdcard/android/layout_tests/dom/html/level2/html/table22.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/object03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOListElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLQuoteElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement101.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement19.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement134.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLScriptElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement50.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement83.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/table38.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHeadingElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement22.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement37.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement117.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement33.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDirectoryElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement23.html
-/sdcard/android/layout_tests/dom/html/level2/html/button06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement66.html
-/sdcard/android/layout_tests/dom/html/level2/html/table41.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement40.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement99.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement120.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement16.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAppletElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement49.html
-/sdcard/android/layout_tests/dom/html/level2/html/table24.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFontElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/object05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLCollection11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLImageElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement23.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOListElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement103.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement136.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHRElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement52.html
-/sdcard/android/layout_tests/dom/html/level2/html/table07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLSelectElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableColElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement85.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement09.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAnchorElement14.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/hasFeature02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement24.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement39.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement119.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement35.html
-/sdcard/android/layout_tests/dom/html/level2/html/table10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBaseFontElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement25.html
-/sdcard/android/layout_tests/dom/html/level2/html/button08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement68.html
-/sdcard/android/layout_tests/dom/html/level2/html/table43.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLInputElement12.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTextAreaElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableRowElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFrameElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement122.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement18.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFormElement04.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLAreaElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLObjectElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement71.html
-/sdcard/android/layout_tests/dom/html/level2/html/table26.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLIFrameElement06.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLFontElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/object07.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableCellElement10.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableElement25.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement105.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLLinkElement08.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLOptionElement05.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement21.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLMetaElement02.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLBodyElement01.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLDocument23.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement138.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLHRElement03.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLTableSectionElement11.html
-/sdcard/android/layout_tests/dom/html/level2/html/HTMLElement54.html
-/sdcard/android/layout_tests/dom/html/level2/html/table09.html
-/sdcard/android/layout_tests/dom/html/level2/html/object10.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_notationsremovenameditemns1.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_entitiessetnameditemns1.html
-/sdcard/android/layout_tests/dom/html/level2/core/setAttributeNS10.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_nodedocumentfragmentnormalize2.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_namednodemapinvalidtype1.html
-/sdcard/android/layout_tests/dom/html/level2/core/createAttributeNS06.html
-/sdcard/android/layout_tests/dom/html/level2/core/createDocumentType04.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_notationssetnameditemns1.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_entitiesremovenameditemns1.html
-/sdcard/android/layout_tests/dom/html/level2/core/hc_nodedocumentfragmentnormalize1.html
-/sdcard/android/layout_tests/dom/html/level2/core/createDocument08.html
-/sdcard/android/layout_tests/editing/style/temporary-span-crash.html
-/sdcard/android/layout_tests/editing/style/4230923.html
-/sdcard/android/layout_tests/editing/style/textdecoration-outside-of-unsplittable-element.html
-/sdcard/android/layout_tests/editing/style/textdecoration-outside-of-rooteditable.html
-/sdcard/android/layout_tests/editing/style/highlight-insert-paragraph.html
-/sdcard/android/layout_tests/editing/inserting/6609479-1.html
-/sdcard/android/layout_tests/editing/inserting/6609479.html
-/sdcard/android/layout_tests/editing/inserting/5549929-1.html
-/sdcard/android/layout_tests/editing/inserting/font-size-clears-from-typing-style.html
-/sdcard/android/layout_tests/editing/inserting/6104369.html
-/sdcard/android/layout_tests/editing/inserting/return-with-object-element.html
-/sdcard/android/layout_tests/editing/inserting/5803706-2.html
-/sdcard/android/layout_tests/editing/inserting/5685601-2.html
-/sdcard/android/layout_tests/editing/inserting/5607069-1.html
-/sdcard/android/layout_tests/editing/inserting/insert-br-quoted-007.html
-/sdcard/android/layout_tests/editing/inserting/5803706-1.html
-/sdcard/android/layout_tests/editing/inserting/5685601-1.html
-/sdcard/android/layout_tests/editing/inserting/5994480.html
-/sdcard/android/layout_tests/editing/inserting/6104369-2.html
-/sdcard/android/layout_tests/editing/inserting/insert-before-link-1.html
-/sdcard/android/layout_tests/editing/inserting/5378847.html
-/sdcard/android/layout_tests/editing/inserting/5685601-3.html
-/sdcard/android/layout_tests/editing/inserting/6703873-2.html
-/sdcard/android/layout_tests/editing/execCommand/toggle-style-2.html
-/sdcard/android/layout_tests/editing/execCommand/19403.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-div.html
-/sdcard/android/layout_tests/editing/execCommand/25256.html
-/sdcard/android/layout_tests/editing/execCommand/default-parameters.html
-/sdcard/android/layout_tests/editing/execCommand/5120591.html
-/sdcard/android/layout_tests/editing/execCommand/19455.html
-/sdcard/android/layout_tests/editing/execCommand/19087.html
-/sdcard/android/layout_tests/editing/execCommand/5543472-3.html
-/sdcard/android/layout_tests/editing/execCommand/5207369.html
-/sdcard/android/layout_tests/editing/execCommand/empty-span-removal.html
-/sdcard/android/layout_tests/editing/execCommand/4916583.html
-/sdcard/android/layout_tests/editing/execCommand/5658933-2.html
-/sdcard/android/layout_tests/editing/execCommand/5469868.html
-/sdcard/android/layout_tests/editing/execCommand/insert-list-with-id.html
-/sdcard/android/layout_tests/editing/execCommand/indent-div-inside-list.html
-/sdcard/android/layout_tests/editing/execCommand/5575101-1.html
-/sdcard/android/layout_tests/editing/execCommand/5432254-1.html
-/sdcard/android/layout_tests/editing/execCommand/indent-nested-blockquotes.html
-/sdcard/android/layout_tests/editing/execCommand/5062376.html
-/sdcard/android/layout_tests/editing/execCommand/indent-second-paragraph-in-blockquote.html
-/sdcard/android/layout_tests/editing/execCommand/findString-3.html
-/sdcard/android/layout_tests/editing/execCommand/toggle-text-decorations.html
-/sdcard/android/layout_tests/editing/execCommand/5142012-3.html
-/sdcard/android/layout_tests/editing/execCommand/indent-empty-table-cell.html
-/sdcard/android/layout_tests/editing/execCommand/5700414-1.html
-/sdcard/android/layout_tests/editing/execCommand/16049.html
-/sdcard/android/layout_tests/editing/execCommand/19653-1.html
-/sdcard/android/layout_tests/editing/execCommand/arguments-combinations.html
-/sdcard/android/layout_tests/editing/execCommand/5685604-1.html
-/sdcard/android/layout_tests/editing/execCommand/4128080-1.html
-/sdcard/android/layout_tests/editing/execCommand/5575101-3.html
-/sdcard/android/layout_tests/editing/execCommand/5119244.html
-/sdcard/android/layout_tests/editing/execCommand/5543472-2.html
-/sdcard/android/layout_tests/editing/execCommand/inline-style-after-indentoutdent.html
-/sdcard/android/layout_tests/editing/execCommand/5770834-1.html
-/sdcard/android/layout_tests/editing/execCommand/5483526.html
-/sdcard/android/layout_tests/editing/execCommand/5658933-1.html
-/sdcard/android/layout_tests/editing/execCommand/5164796.html
-/sdcard/android/layout_tests/editing/execCommand/6355786.html
-/sdcard/android/layout_tests/editing/execCommand/5604313.html
-/sdcard/android/layout_tests/editing/execCommand/19653-3.html
-/sdcard/android/layout_tests/editing/execCommand/outdent-regular-blockquote.html
-/sdcard/android/layout_tests/editing/execCommand/6444148.html
-/sdcard/android/layout_tests/editing/execCommand/5763082.html
-/sdcard/android/layout_tests/editing/execCommand/4976800.html
-/sdcard/android/layout_tests/editing/execCommand/4928635.html
-/sdcard/android/layout_tests/editing/execCommand/list-wrapping-image-crash.html
-/sdcard/android/layout_tests/editing/execCommand/4920742-2.html
-/sdcard/android/layout_tests/editing/execCommand/4917055.html
-/sdcard/android/layout_tests/editing/execCommand/5658933-3.html
-/sdcard/android/layout_tests/editing/execCommand/5575101-2.html
-/sdcard/android/layout_tests/editing/execCommand/5432254-2.html
-/sdcard/android/layout_tests/editing/execCommand/5144139-1.html
-/sdcard/android/layout_tests/editing/execCommand/5543472-1.html
-/sdcard/android/layout_tests/editing/execCommand/25320.html
-/sdcard/android/layout_tests/editing/execCommand/5210032.html
-/sdcard/android/layout_tests/editing/execCommand/12244.html
-/sdcard/android/layout_tests/editing/execCommand/15381.html
-/sdcard/android/layout_tests/editing/execCommand/5700414-2.html
-/sdcard/android/layout_tests/editing/execCommand/19653-2.html
-/sdcard/android/layout_tests/editing/execCommand/boldSelection.html
-/sdcard/android/layout_tests/editing/execCommand/4916235.html
-/sdcard/android/layout_tests/editing/execCommand/5458246.html
-/sdcard/android/layout_tests/editing/execCommand/toggle-styles.html
-/sdcard/android/layout_tests/editing/pasteboard/5761530-2.html
-/sdcard/android/layout_tests/editing/pasteboard/6018653.html
-/sdcard/android/layout_tests/editing/pasteboard/4930986-1.html
-/sdcard/android/layout_tests/editing/pasteboard/5780697-1.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-crash-with-extraneous-attribute.html
-/sdcard/android/layout_tests/editing/pasteboard/4930986-3.html
-/sdcard/android/layout_tests/editing/pasteboard/5245519.html
-/sdcard/android/layout_tests/editing/pasteboard/copy-display-none.html
-/sdcard/android/layout_tests/editing/pasteboard/5521237.html
-/sdcard/android/layout_tests/editing/pasteboard/newlines-around-floating-or-positioned.html
-/sdcard/android/layout_tests/editing/pasteboard/5078739.html
-/sdcard/android/layout_tests/editing/pasteboard/createMarkup-assert.xml
-/sdcard/android/layout_tests/editing/pasteboard/4930986-2.html
-/sdcard/android/layout_tests/editing/pasteboard/4840662.html
-/sdcard/android/layout_tests/editing/pasteboard/5480736.html
-/sdcard/android/layout_tests/editing/selection/5825350-1.html
-/sdcard/android/layout_tests/editing/selection/selection-invalid-offset.html
-/sdcard/android/layout_tests/editing/selection/move-by-line-005.html
-/sdcard/android/layout_tests/editing/selection/rangeCount.html
-/sdcard/android/layout_tests/editing/selection/containsNode.html
-/sdcard/android/layout_tests/editing/selection/selectAllChildren.html
-/sdcard/android/layout_tests/editing/selection/cleared-by-relayout.html
-/sdcard/android/layout_tests/editing/selection/extend-selection.html
-/sdcard/android/layout_tests/editing/selection/5825350-2.html
-/sdcard/android/layout_tests/editing/selection/5794920-1.html
-/sdcard/android/layout_tests/editing/selection/deleteFromDocument.html
-/sdcard/android/layout_tests/editing/selection/5497643.html
-/sdcard/android/layout_tests/editing/selection/setBaseAndExtent-revert-selection.html
-/sdcard/android/layout_tests/editing/selection/crash-on-drag-with-mutation-events.html
-/sdcard/android/layout_tests/editing/selection/5714333.html
-/sdcard/android/layout_tests/editing/selection/select-all-user-select-none.html
-/sdcard/android/layout_tests/editing/selection/thai-word-at-document-end.html
-/sdcard/android/layout_tests/editing/selection/extend.html
-/sdcard/android/layout_tests/editing/selection/5241148.html
-/sdcard/android/layout_tests/editing/selection/5213963.html
-/sdcard/android/layout_tests/editing/selection/move-by-line-004.html
-/sdcard/android/layout_tests/editing/selection/extend-by-line-anonymous-content-crash.html
-/sdcard/android/layout_tests/editing/selection/5779984-1.html
-/sdcard/android/layout_tests/editing/undo/4059423-1.html
-/sdcard/android/layout_tests/editing/undo/4059423-2.html
-/sdcard/android/layout_tests/editing/undo/5658727.html
-/sdcard/android/layout_tests/editing/undo/5738768.html
-/sdcard/android/layout_tests/editing/deleting/25322-2.html
-/sdcard/android/layout_tests/editing/deleting/2610675-2.html
-/sdcard/android/layout_tests/editing/deleting/5847330-2.html
-/sdcard/android/layout_tests/editing/deleting/5156801.html
-/sdcard/android/layout_tests/editing/deleting/4866671.html
-/sdcard/android/layout_tests/editing/deleting/type-delete-after-quote-2.html
-/sdcard/android/layout_tests/editing/deleting/25322-1.html
-/sdcard/android/layout_tests/editing/deleting/merge-at-end-of-document.html
-/sdcard/android/layout_tests/editing/deleting/6026335.html
-/sdcard/android/layout_tests/editing/deleting/2610675-1.html
-/sdcard/android/layout_tests/editing/deleting/5847330-1.html
-/sdcard/android/layout_tests/editing/deleting/5433862-1.html
-/sdcard/android/layout_tests/editing/deleting/5495723.html
-/sdcard/android/layout_tests/editing/deleting/5290534.html
-/sdcard/android/layout_tests/editing/deleting/removeNodeCommand-assert.html
-/sdcard/android/layout_tests/editing/deleting/25322-3.html
-/sdcard/android/layout_tests/editing/deleting/2610675-3.html
-/sdcard/android/layout_tests/editing/deleting/5890684.html
-/sdcard/android/layout_tests/editing/deleting/in-visibly-empty-root.html
-/sdcard/android/layout_tests/editing/deleting/4875189.html
-/sdcard/android/layout_tests/fast/media/matchmedium-query-api.html
-/sdcard/android/layout_tests/fast/replaced/object-param-no-name.html
-/sdcard/android/layout_tests/fast/ruby/parse-rp.html
-/sdcard/android/layout_tests/fast/dynamic/subtree-common-root.html
-/sdcard/android/layout_tests/fast/dynamic/hovered-detach.html
-/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML.html
-/sdcard/android/layout_tests/fast/dynamic/style-access-late-stylesheet-load.html
-/sdcard/android/layout_tests/fast/dynamic/insertAdjacentText.html
-/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML-allowed-parents.html
-/sdcard/android/layout_tests/fast/dynamic/checkbox-selection-crash.html
-/sdcard/android/layout_tests/fast/dynamic/outerHTML-no-element.html
-/sdcard/android/layout_tests/fast/dynamic/5872671.html
-/sdcard/android/layout_tests/fast/dynamic/ancestor-to-absolute.html
-/sdcard/android/layout_tests/fast/dynamic/float-remove-above-line.html
-/sdcard/android/layout_tests/fast/dynamic/recursive-layout.html
-/sdcard/android/layout_tests/fast/dynamic/inline-to-block-crash.html
-/sdcard/android/layout_tests/fast/text/whitespace/nowrap-line-break-after-white-space.html
-/sdcard/android/layout_tests/fast/text/find-backwards.html
-/sdcard/android/layout_tests/fast/text/large-text-composed-char-dos.html
-/sdcard/android/layout_tests/fast/text/find-quotes.html
-/sdcard/android/layout_tests/fast/text/find-case-folding.html
-/sdcard/android/layout_tests/fast/text/text-shadow-extreme-value.html
-/sdcard/android/layout_tests/fast/text/find-hidden-text.html
-/sdcard/android/layout_tests/fast/text/line-breaks-after-ideographic-comma-or-full-stop.html
-/sdcard/android/layout_tests/fast/text/find-spaces.html
-/sdcard/android/layout_tests/fast/text/text-large-negative-letter-spacing-with-opacity.html
-/sdcard/android/layout_tests/fast/encoding/gbk/chinese.html
-/sdcard/android/layout_tests/fast/encoding/gbk/x-euc-cn.html
-/sdcard/android/layout_tests/fast/encoding/gbk/gb_2312-80.html
-/sdcard/android/layout_tests/fast/encoding/gbk/cn-gb.html
-/sdcard/android/layout_tests/fast/encoding/gbk/csgb2312.html
-/sdcard/android/layout_tests/fast/encoding/gbk/iso-ir-58.html
-/sdcard/android/layout_tests/fast/encoding/gbk/csgb231280.html
-/sdcard/android/layout_tests/fast/encoding/gbk/gb2312.html
-/sdcard/android/layout_tests/fast/encoding/gbk/gbk.html
-/sdcard/android/layout_tests/fast/encoding/gbk/x-gbk.html
-/sdcard/android/layout_tests/fast/encoding/gbk/EUC-CN.html
-/sdcard/android/layout_tests/fast/encoding/gbk/close-gbk-converter.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/hebrew.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/csISO88598I.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-e.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-i.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/logical.html
-/sdcard/android/layout_tests/fast/encoding/hebrew/iso-ir-138.html
-/sdcard/android/layout_tests/fast/encoding/pseudo-xml-4.html
-/sdcard/android/layout_tests/fast/encoding/no-charset-on-dynamic-script-load.html
-/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-bom.html
-/sdcard/android/layout_tests/fast/encoding/bandai-co-jp-releases.html
-/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-bom.html
-/sdcard/android/layout_tests/fast/encoding/css-charset-evil.html
-/sdcard/android/layout_tests/fast/encoding/css-charset.html
-/sdcard/android/layout_tests/fast/encoding/xml-charset-utf16.html
-/sdcard/android/layout_tests/fast/encoding/pseudo-xml-3.html
-/sdcard/android/layout_tests/fast/encoding/tag-in-title.html
-/sdcard/android/layout_tests/fast/encoding/noscript-in-head.html
-/sdcard/android/layout_tests/fast/encoding/css-cached-bom.html
-/sdcard/android/layout_tests/fast/encoding/preload-encoding.html
-/sdcard/android/layout_tests/fast/encoding/charset-invalid.html
-/sdcard/android/layout_tests/fast/encoding/pseudo-tags-in-attributes.html
-/sdcard/android/layout_tests/fast/encoding/decoder-allow-null-chars.html
-/sdcard/android/layout_tests/fast/encoding/css-charset-dom.html
-/sdcard/android/layout_tests/fast/encoding/charset-utf16.html
-/sdcard/android/layout_tests/fast/encoding/char-encoding.html
-/sdcard/android/layout_tests/fast/encoding/css-link-charset.html
-/sdcard/android/layout_tests/fast/encoding/latin1-winlatin.html
-/sdcard/android/layout_tests/fast/encoding/high-bit-latin1.html
-/sdcard/android/layout_tests/fast/encoding/bom-in-content.html
-/sdcard/android/layout_tests/fast/encoding/bom-in-content-utf16.html
-/sdcard/android/layout_tests/fast/encoding/namespace-tolerance.html
-/sdcard/android/layout_tests/fast/encoding/misplaced-xml-declaration.html
-/sdcard/android/layout_tests/fast/encoding/euckr-name.html
-/sdcard/android/layout_tests/fast/encoding/charset-xuser-defined.html
-/sdcard/android/layout_tests/fast/encoding/pseudo-xml-2.html
-/sdcard/android/layout_tests/fast/encoding/floraexpress-ru.html
-/sdcard/android/layout_tests/fast/encoding/charset-cp1251.html
-/sdcard/android/layout_tests/fast/encoding/charset-unicode.html
-/sdcard/android/layout_tests/fast/encoding/meta-charset.html
-/sdcard/android/layout_tests/fast/encoding/xml-utf-8-default.xml
-/sdcard/android/layout_tests/fast/encoding/pseudo-xml.html
-/sdcard/android/layout_tests/fast/encoding/yahoo-mail.html
-/sdcard/android/layout_tests/fast/encoding/ahram-org-eg.html
-/sdcard/android/layout_tests/fast/encoding/script-in-head.html
-/sdcard/android/layout_tests/fast/encoding/mispositioned-meta.html
-/sdcard/android/layout_tests/fast/multicol/gap-non-negative.html
-/sdcard/android/layout_tests/fast/multicol/content-height-zero-crash.html
-/sdcard/android/layout_tests/fast/doctypes/doctype-at-end.html
-/sdcard/android/layout_tests/fast/doctypes/005-case-preserving.html
-/sdcard/android/layout_tests/fast/doctypes/doctype-in-element.html
-/sdcard/android/layout_tests/fast/doctypes/doctype-after-comment.html
-/sdcard/android/layout_tests/fast/doctypes/doctype-parsing.html
-/sdcard/android/layout_tests/fast/doctypes/html-doctype.html
-/sdcard/android/layout_tests/fast/cookies/local-file-can-set-cookies.html
-/sdcard/android/layout_tests/fast/css-generated-content/empty-content-with-float-crash.html
-/sdcard/android/layout_tests/fast/css-generated-content/reset-content-to-initial.html
-/sdcard/android/layout_tests/fast/workers/worker-close.html
-/sdcard/android/layout_tests/fast/workers/worker-context-gc.html
-/sdcard/android/layout_tests/fast/workers/worker-constructor.html
-/sdcard/android/layout_tests/fast/workers/worker-timeout.html
-/sdcard/android/layout_tests/fast/workers/worker-messageport.html
-/sdcard/android/layout_tests/fast/workers/worker-gc.html
-/sdcard/android/layout_tests/fast/workers/worker-replace-self.html
-/sdcard/android/layout_tests/fast/workers/worker-event-listener.html
-/sdcard/android/layout_tests/fast/workers/worker-cloneport.html
-/sdcard/android/layout_tests/fast/workers/worker-call.html
-/sdcard/android/layout_tests/fast/workers/worker-messageport-gc.html
-/sdcard/android/layout_tests/fast/workers/stress-js-execution.html
-/sdcard/android/layout_tests/fast/workers/worker-terminate.html
-/sdcard/android/layout_tests/fast/workers/use-machine-stack.html
-/sdcard/android/layout_tests/fast/workers/worker-navigator.html
-/sdcard/android/layout_tests/fast/workers/worker-script-error.html
-/sdcard/android/layout_tests/fast/workers/worker-replace-global-constructor.html
-/sdcard/android/layout_tests/fast/transforms/container-transform-crash.html
-/sdcard/android/layout_tests/fast/leaks/001.html
-/sdcard/android/layout_tests/fast/leaks/002.html
-/sdcard/android/layout_tests/fast/borders/border-radius-parsing.html
-/sdcard/android/layout_tests/fast/innerHTML/innerHTML-custom-tag.html
-/sdcard/android/layout_tests/fast/innerHTML/additional-inline-style.html
-/sdcard/android/layout_tests/fast/innerHTML/005.html
-/sdcard/android/layout_tests/fast/innerHTML/javascript-url.html
-/sdcard/android/layout_tests/fast/innerHTML/innerHTML-case.html
-/sdcard/android/layout_tests/fast/overflow/onscroll-layer-self-destruct.html
-/sdcard/android/layout_tests/fast/overflow/generated-content-crash.html
-/sdcard/android/layout_tests/fast/overflow/overflow-y-scroll.html
-/sdcard/android/layout_tests/fast/events/dispatch-to-handle-event.html
-/sdcard/android/layout_tests/fast/events/scroll-during-zoom-change.html
-/sdcard/android/layout_tests/fast/events/scroll-event-does-not-bubble.html
-/sdcard/android/layout_tests/fast/events/onload-after-document-close-with-subresource.html
-/sdcard/android/layout_tests/fast/events/message-channel-gc-4.html
-/sdcard/android/layout_tests/fast/events/message-channel-listener-circular-ownership.html
-/sdcard/android/layout_tests/fast/events/message-port-constructor-for-deleted-document.html
-/sdcard/android/layout_tests/fast/events/dispatchEvent-crash.html
-/sdcard/android/layout_tests/fast/events/programmatic-check-no-change-event.html
-/sdcard/android/layout_tests/fast/events/message-port-inactive-document.html
-/sdcard/android/layout_tests/fast/events/onunload-body-property.html
-/sdcard/android/layout_tests/fast/events/event-trace.html
-/sdcard/android/layout_tests/fast/events/init-event-after-dispatch.html
-/sdcard/android/layout_tests/fast/events/delayed-style-mutation-event-crash.html
-/sdcard/android/layout_tests/fast/events/keydown-keypress-focus-change.html
-/sdcard/android/layout_tests/fast/events/no-blur-on-page-leave.html
-/sdcard/android/layout_tests/fast/events/onload-name-collision.html
-/sdcard/android/layout_tests/fast/events/div-focus.html
-/sdcard/android/layout_tests/fast/events/overflow-events.html
-/sdcard/android/layout_tests/fast/events/create-document-crash-on-attach-event.html
-/sdcard/android/layout_tests/fast/events/no-blur-on-enter-button.html
-/sdcard/android/layout_tests/fast/events/keypress-removed-node.html
-/sdcard/android/layout_tests/fast/events/shadow-boundary-crossing.html
-/sdcard/android/layout_tests/fast/events/submit-reset-nested-bubble.html
-/sdcard/android/layout_tests/fast/events/message-port-deleted-frame.html
-/sdcard/android/layout_tests/fast/events/nested-event-remove-node-crash.html
-/sdcard/android/layout_tests/fast/events/onsubmit-bubbling.html
-/sdcard/android/layout_tests/fast/events/onload-fires-twice.html
-/sdcard/android/layout_tests/fast/events/message-port-no-wrapper.html
-/sdcard/android/layout_tests/fast/events/mousedown_in_scrollbar.html
-/sdcard/android/layout_tests/fast/events/onload-single-line-comment.html
-/sdcard/android/layout_tests/fast/events/message-channel-gc-2.html
-/sdcard/android/layout_tests/fast/events/window-load-capture.html
-/sdcard/android/layout_tests/fast/events/message-port-deleted-document.html
-/sdcard/android/layout_tests/fast/events/event-instanceof.html
-/sdcard/android/layout_tests/fast/events/message-channel-gc.html
-/sdcard/android/layout_tests/fast/events/event-creation.html
-/sdcard/android/layout_tests/fast/events/event-listener-sharing.html
-/sdcard/android/layout_tests/fast/events/caller-access-from-event-listener.html
-/sdcard/android/layout_tests/fast/events/stopPropagation-submit.html
-/sdcard/android/layout_tests/fast/events/remove-event-listener.html
-/sdcard/android/layout_tests/fast/events/mouseup-outside-button.html
-/sdcard/android/layout_tests/fast/events/iframe-object-onload.html
-/sdcard/android/layout_tests/fast/events/no-window-load.html
-/sdcard/android/layout_tests/fast/events/event-listener-html-non-html-confusion.html
-/sdcard/android/layout_tests/fast/events/onerror-bubbling.html
-/sdcard/android/layout_tests/fast/events/keydown-remove-frame.html
-/sdcard/android/layout_tests/fast/events/message-channel-gc-3.html
-/sdcard/android/layout_tests/fast/events/event-targets.html
-/sdcard/android/layout_tests/fast/events/space-scroll-event.html
-/sdcard/android/layout_tests/fast/events/onload-after-document-close-no-subresource.html
-/sdcard/android/layout_tests/fast/events/nested-window-event.html
-/sdcard/android/layout_tests/fast/events/selectstart-during-autoscroll.html
-/sdcard/android/layout_tests/fast/events/stopPropagation-checkbox.html
-/sdcard/android/layout_tests/fast/events/message-port-clone.html
-/sdcard/android/layout_tests/fast/events/tab-crash-with-image-map.html
-/sdcard/android/layout_tests/fast/events/simulated-key-state.html
-/sdcard/android/layout_tests/fast/events/init-event-null-view.html
-/sdcard/android/layout_tests/fast/events/init-events.html
-/sdcard/android/layout_tests/fast/events/onunload-window-property.html
-/sdcard/android/layout_tests/fast/events/message-port.html
-/sdcard/android/layout_tests/fast/html/tab-order.html
-/sdcard/android/layout_tests/fast/html/xhtml-serialize.html
-/sdcard/android/layout_tests/fast/html/empty-fragment-id-goto-top.html
-/sdcard/android/layout_tests/fast/html/script-allowed-types-languages.html
-/sdcard/android/layout_tests/fast/html/text-field-input-types.html
-/sdcard/android/layout_tests/fast/html/draggable.html
-/sdcard/android/layout_tests/fast/html/body-offset-properties.html
-/sdcard/android/layout_tests/fast/images/image-empty-data.html
-/sdcard/android/layout_tests/fast/images/text-content-crash.html
-/sdcard/android/layout_tests/fast/images/border.html
-/sdcard/android/layout_tests/fast/images/animated-background-image-crash.html
-/sdcard/android/layout_tests/fast/images/load-img-with-empty-src.html
-/sdcard/android/layout_tests/fast/images/text-content-crash-2.html
-/sdcard/android/layout_tests/fast/inspector/cssURLQuotes.html
-/sdcard/android/layout_tests/fast/flexbox/repaint-scrollbar.html
-/sdcard/android/layout_tests/fast/flexbox/inline-children-crash.html
-/sdcard/android/layout_tests/fast/tokenizer/nested-cached-scripts.html
-/sdcard/android/layout_tests/fast/tokenizer/image-empty-crash.html
-/sdcard/android/layout_tests/fast/tokenizer/lessthan-terminates-tags-and-attrs.html
-/sdcard/android/layout_tests/fast/tokenizer/ignore-tags-in-iframe.html
-/sdcard/android/layout_tests/fast/tokenizer/write-partial-entity.html
-/sdcard/android/layout_tests/fast/tokenizer/external-script-document-open.html
-/sdcard/android/layout_tests/fast/tokenizer/004.html
-/sdcard/android/layout_tests/fast/tokenizer/write-inline-script-open.html
-/sdcard/android/layout_tests/fast/tokenizer/write-external-script-open.html
-/sdcard/android/layout_tests/fast/tokenizer/doctype-search-reset.html
-/sdcard/android/layout_tests/fast/tokenizer/nested-multiple-scripts.html
-/sdcard/android/layout_tests/fast/tokenizer/nested-cached-scripts-and-stylesheet.html
-/sdcard/android/layout_tests/fast/tokenizer/ampersand-in-special-tag.html
-/sdcard/android/layout_tests/fast/tokenizer/write-unclosed-script.html
-/sdcard/android/layout_tests/fast/tokenizer/badscript.html
-/sdcard/android/layout_tests/fast/regex/quantified-assertions.html
-/sdcard/android/layout_tests/fast/regex/non-pattern-characters.html
-/sdcard/android/layout_tests/fast/regex/malformed-escapes.html
-/sdcard/android/layout_tests/fast/regex/early-acid3-86.html
-/sdcard/android/layout_tests/fast/regex/alternative-length-miscalculation.html
-/sdcard/android/layout_tests/fast/regex/test4.html
-/sdcard/android/layout_tests/fast/regex/non-capturing-backtracking.html
-/sdcard/android/layout_tests/fast/box-shadow/box-shadow-overflow-scroll.html
-/sdcard/android/layout_tests/fast/js/kde/Boolean.html
-/sdcard/android/layout_tests/fast/js/kde/garbage-n.html
-/sdcard/android/layout_tests/fast/js/kde/function.html
-/sdcard/android/layout_tests/fast/js/kde/function_length.html
-/sdcard/android/layout_tests/fast/js/kde/const.html
-/sdcard/android/layout_tests/fast/js/kde/constructor_length.html
-/sdcard/android/layout_tests/fast/js/kde/statements.html
-/sdcard/android/layout_tests/fast/js/kde/math.html
-/sdcard/android/layout_tests/fast/js/kde/assignments.html
-/sdcard/android/layout_tests/fast/js/kde/crash-1.html
-/sdcard/android/layout_tests/fast/js/kde/delete.html
-/sdcard/android/layout_tests/fast/js/kde/var_decl_init.html
-/sdcard/android/layout_tests/fast/js/kde/literals.html
-/sdcard/android/layout_tests/fast/js/kde/eval.html
-/sdcard/android/layout_tests/fast/js/kde/j-comment-3.html
-/sdcard/android/layout_tests/fast/js/kde/StringObject.html
-/sdcard/android/layout_tests/fast/js/kde/crash-2.html
-/sdcard/android/layout_tests/fast/js/kde/exception_propagation.html
-/sdcard/android/layout_tests/fast/js/kde/conditional.html
-/sdcard/android/layout_tests/fast/js/kde/scope.html
-/sdcard/android/layout_tests/fast/js/kde/parse.html
-/sdcard/android/layout_tests/fast/js/kde/function_arguments.html
-/sdcard/android/layout_tests/fast/js/kde/arguments-scope.html
-/sdcard/android/layout_tests/fast/js/kde/lval-exceptions.html
-/sdcard/android/layout_tests/fast/js/kde/operators.html
-/sdcard/android/layout_tests/fast/js/kde/Array.html
-/sdcard/android/layout_tests/fast/js/kde/md5-1.html
-/sdcard/android/layout_tests/fast/js/kde/object_prototype_tostring.html
-/sdcard/android/layout_tests/fast/js/kde/Date-setYear.html
-/sdcard/android/layout_tests/fast/js/kde/GlobalObject.html
-/sdcard/android/layout_tests/fast/js/kde/prototype_proto.html
-/sdcard/android/layout_tests/fast/js/kde/evil-n.html
-/sdcard/android/layout_tests/fast/js/kde/RegExp.html
-/sdcard/android/layout_tests/fast/js/kde/cast.html
-/sdcard/android/layout_tests/fast/js/kde/j-comment-4.html
-/sdcard/android/layout_tests/fast/js/kde/iteration.html
-/sdcard/android/layout_tests/fast/js/kde/comment-1.html
-/sdcard/android/layout_tests/fast/js/kde/string-2-n.html
-/sdcard/android/layout_tests/fast/js/kde/Prototype.html
-/sdcard/android/layout_tests/fast/js/kde/completion.html
-/sdcard/android/layout_tests/fast/js/kde/encode_decode_uri.html
-/sdcard/android/layout_tests/fast/js/kde/exceptions.html
-/sdcard/android/layout_tests/fast/js/kde/md5-2.html
-/sdcard/android/layout_tests/fast/js/kde/Error.html
-/sdcard/android/layout_tests/fast/js/kde/function_constructor.html
-/sdcard/android/layout_tests/fast/js/kde/object_prototype.html
-/sdcard/android/layout_tests/fast/js/kde/empty.html
-/sdcard/android/layout_tests/fast/js/kde/inbuilt_function_proto.html
-/sdcard/android/layout_tests/fast/js/kde/string-1-n.html
-/sdcard/android/layout_tests/fast/js/kde/func-decl.html
-/sdcard/android/layout_tests/fast/js/kde/comment-2.html
-/sdcard/android/layout_tests/fast/js/kde/inbuilt_function_tostring.html
-/sdcard/android/layout_tests/fast/js/kde/Object.html
-/sdcard/android/layout_tests/fast/js/kde/prototype_length.html
-/sdcard/android/layout_tests/fast/js/pic/cached-single-entry-transition.html
-/sdcard/android/layout_tests/fast/js/pic/cached-prototype-setter.html
-/sdcard/android/layout_tests/fast/js/pic/get-empty-string.html
-/sdcard/android/layout_tests/fast/js/pic/get-set-proxy-object.html
-/sdcard/android/layout_tests/fast/js/pic/rehash-poisons-structure.html
-/sdcard/android/layout_tests/fast/js/pic/cached-array-length-access.html
-/sdcard/android/layout_tests/fast/js/pic/cached-prototype-then-immediate.html
-/sdcard/android/layout_tests/fast/js/pic/cached-getter-setter.html
-/sdcard/android/layout_tests/fast/js/pic/cached-getter-dictionary-and-proto.html
-/sdcard/android/layout_tests/fast/js/pic/delete-global-object.html
-/sdcard/android/layout_tests/fast/js/pic/cached-deleted-properties.html
-/sdcard/android/layout_tests/fast/js/pic/dictionary-prototype.html
-/sdcard/android/layout_tests/fast/js/bitwise-and-on-undefined.html
-/sdcard/android/layout_tests/fast/js/exception-sequencing-binops.html
-/sdcard/android/layout_tests/fast/js/exception-thrown-from-eval-inside-closure.html
-/sdcard/android/layout_tests/fast/js/recursion-limit-equal.html
-/sdcard/android/layout_tests/fast/js/string_replace.html
-/sdcard/android/layout_tests/fast/js/ignored-result-ref-crash.html
-/sdcard/android/layout_tests/fast/js/function-toString-object-literals.html
-/sdcard/android/layout_tests/fast/js/numeric-conversion.html
-/sdcard/android/layout_tests/fast/js/select-options-remove.html
-/sdcard/android/layout_tests/fast/js/array-tostring-ignore-separator.html
-/sdcard/android/layout_tests/fast/js/exception-sequencing-binops2.html
-/sdcard/android/layout_tests/fast/js/function-declaration.html
-/sdcard/android/layout_tests/fast/js/number-toExponential.html
-/sdcard/android/layout_tests/fast/js/direct-entry-to-function-code.html
-/sdcard/android/layout_tests/fast/js/number-parsing-crash.html
-/sdcard/android/layout_tests/fast/js/vardecl-preserve-vardecl.html
-/sdcard/android/layout_tests/fast/js/unexpected-constant-crash.html
-/sdcard/android/layout_tests/fast/js/var-shadows-arg-gc-crash.html
-/sdcard/android/layout_tests/fast/js/arguments-bad-index.html
-/sdcard/android/layout_tests/fast/js/resize-array-assign.html
-/sdcard/android/layout_tests/fast/js/number-toString.html
-/sdcard/android/layout_tests/fast/js/this-non-object-proto.html
-/sdcard/android/layout_tests/fast/js/exception-thrown-from-new.html
-/sdcard/android/layout_tests/fast/js/cyclic-proto.html
-/sdcard/android/layout_tests/fast/js/vardecl-preserve-arguments.html
-/sdcard/android/layout_tests/fast/js/regexp-compile-crash.html
-/sdcard/android/layout_tests/fast/js/var-declarations-shadowing.html
-/sdcard/android/layout_tests/fast/js/ignored-result-null-comparison-crash.html
-/sdcard/android/layout_tests/fast/js/array-sort-reentrance.html
-/sdcard/android/layout_tests/fast/js/toString-for-var-decl.html
-/sdcard/android/layout_tests/fast/js/string-slice-abnormal-values.html
-/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-1.html
-/sdcard/android/layout_tests/fast/js/do-while-without-semicolon.html
-/sdcard/android/layout_tests/fast/js/object-prototype-toLocaleString.html
-/sdcard/android/layout_tests/fast/js/function-redefinition.html
-/sdcard/android/layout_tests/fast/js/function-name.html
-/sdcard/android/layout_tests/fast/js/logical-or-jless.html
-/sdcard/android/layout_tests/fast/js/regexp-non-character.html
-/sdcard/android/layout_tests/fast/js/JSON-parse.html
-/sdcard/android/layout_tests/fast/js/assign.html
-/sdcard/android/layout_tests/fast/js/for-in-avoid-duplicates.html
-/sdcard/android/layout_tests/fast/js/math-transforms.html
-/sdcard/android/layout_tests/fast/js/sort-stability.html
-/sdcard/android/layout_tests/fast/js/try-catch-crash.html
-/sdcard/android/layout_tests/fast/js/duplicate-param-gc-crash.html
-/sdcard/android/layout_tests/fast/js/regexp-stack-overflow.html
-/sdcard/android/layout_tests/fast/js/function-argument-evaluation-before-exception.html
-/sdcard/android/layout_tests/fast/js/number-toprecision.html
-/sdcard/android/layout_tests/fast/js/string-property-iteration.html
-/sdcard/android/layout_tests/fast/js/do-while-semicolon.html
-/sdcard/android/layout_tests/fast/js/regexp-divequal.html
-/sdcard/android/layout_tests/fast/js/named-function-expression.html
-/sdcard/android/layout_tests/fast/js/array-iterate-backwards.html
-/sdcard/android/layout_tests/fast/js/constructor-attributes.html
-/sdcard/android/layout_tests/fast/js/array-some.html
-/sdcard/android/layout_tests/fast/js/missing-title-end-tag-js.html
-/sdcard/android/layout_tests/fast/js/object-extra-comma.html
-/sdcard/android/layout_tests/fast/js/number-tofixed.html
-/sdcard/android/layout_tests/fast/js/function-declarations-in-switch-statement.html
-/sdcard/android/layout_tests/fast/js/regexp-extended-characters-crash.html
-/sdcard/android/layout_tests/fast/js/typeof-codegen-crash.html
-/sdcard/android/layout_tests/fast/js/array-indexof.html
-/sdcard/android/layout_tests/fast/js/mod-crash.html
-/sdcard/android/layout_tests/fast/js/eval-keyword-vs-function.html
-/sdcard/android/layout_tests/fast/js/debugger.html
-/sdcard/android/layout_tests/fast/js/rehash-assign.html
-/sdcard/android/layout_tests/fast/js/object-prototype-constructor.html
-/sdcard/android/layout_tests/fast/js/function-call-aliased.html
-/sdcard/android/layout_tests/fast/js/string-replace-exception-crash.html
-/sdcard/android/layout_tests/fast/js/date-big-setmonth.html
-/sdcard/android/layout_tests/fast/js/array-enumerators-functions.html
-/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-2.html
-/sdcard/android/layout_tests/fast/js/select-options-add.html
-/sdcard/android/layout_tests/fast/js/toString-dontEnum.html
-/sdcard/android/layout_tests/fast/js/toString-elision-trailing-comma.html
-/sdcard/android/layout_tests/fast/js/regexp-negative-special-characters.html
-/sdcard/android/layout_tests/fast/js/getter-setter-gc.html
-/sdcard/android/layout_tests/fast/js/string-substr.html
-/sdcard/android/layout_tests/fast/js/for-in-var-scope.html
-/sdcard/android/layout_tests/fast/js/exec-state-marking.html
-/sdcard/android/layout_tests/fast/js/primitive-method-this.html
-/sdcard/android/layout_tests/fast/js/string-sort.html
-/sdcard/android/layout_tests/fast/js/for-in-cached.html
-/sdcard/android/layout_tests/fast/js/delete-getters-setters.html
-/sdcard/android/layout_tests/fast/js/const-without-initializer.html
-/sdcard/android/layout_tests/fast/js/function-apply-aliased.html
-/sdcard/android/layout_tests/fast/js/sparse-array.html
-/sdcard/android/layout_tests/fast/js/same-origin-subframe-about-blank.html
-/sdcard/android/layout_tests/fast/js/nested-function-scope.html
-/sdcard/android/layout_tests/fast/js/function-constructor-single-line-comment.html
-/sdcard/android/layout_tests/fast/js/JSON-stringify.html
-/sdcard/android/layout_tests/fast/js/uncaught-exception-line-number.html
-/sdcard/android/layout_tests/fast/js/const.html
-/sdcard/android/layout_tests/fast/js/reparsing-semicolon-insertion.html
-/sdcard/android/layout_tests/fast/js/regexp-non-capturing-groups.html
-/sdcard/android/layout_tests/fast/js/has-own-property.html
-/sdcard/android/layout_tests/fast/js/window-location-href-file-urls.html
-/sdcard/android/layout_tests/fast/js/regexp-extended-characters-more.html
-/sdcard/android/layout_tests/fast/js/prefix-syntax.html
-/sdcard/android/layout_tests/fast/js/exceptions-thrown-in-callbacks.html
-/sdcard/android/layout_tests/fast/js/exception-with-handler-inside-eval-with-dynamic-scope.html
-/sdcard/android/layout_tests/fast/js/for-in-exeception.html
-/sdcard/android/layout_tests/fast/js/array-lastIndexOf.html
-/sdcard/android/layout_tests/fast/js/modify-non-references.html
-/sdcard/android/layout_tests/fast/js/exception-for-nonobject.html
-/sdcard/android/layout_tests/fast/js/regexp-find-first-asserted.html
-/sdcard/android/layout_tests/fast/js/sort-randomly.html
-/sdcard/android/layout_tests/fast/js/array-indexing.html
-/sdcard/android/layout_tests/fast/js/registerCachingAcrossBranchTargets.html
-/sdcard/android/layout_tests/fast/js/regexp-caching.html
-/sdcard/android/layout_tests/fast/js/typeof-syntax.html
-/sdcard/android/layout_tests/fast/js/regexp-character-match-out-of-order.html
-/sdcard/android/layout_tests/fast/js/date-toisostring.html
-/sdcard/android/layout_tests/fast/js/function-call-register-allocation.html
-/sdcard/android/layout_tests/fast/js/arguments.html
-/sdcard/android/layout_tests/fast/js/constant-folding.html
-/sdcard/android/layout_tests/fast/js/activation-object-function-lifetime.html
-/sdcard/android/layout_tests/fast/js/array-filter.html
-/sdcard/android/layout_tests/fast/js/implicit-global-to-global-reentry.html
-/sdcard/android/layout_tests/fast/js/array-reduceRight.html
-/sdcard/android/layout_tests/fast/js/array-foreach.html
-/sdcard/android/layout_tests/fast/js/regexp-many-brackets.html
-/sdcard/android/layout_tests/fast/js/activation-proto.html
-/sdcard/android/layout_tests/fast/js/toString-overrides.html
-/sdcard/android/layout_tests/fast/js/regexp-unicode-overflow.html
-/sdcard/android/layout_tests/fast/js/postfix-syntax.html
-/sdcard/android/layout_tests/fast/js/global-recursion-on-full-stack.html
-/sdcard/android/layout_tests/fast/js/closure-inside-extra-arg-call.html
-/sdcard/android/layout_tests/fast/js/number-cell-reuse.html
-/sdcard/android/layout_tests/fast/js/removing-Cf-characters.html
-/sdcard/android/layout_tests/fast/js/pretty-print.html
-/sdcard/android/layout_tests/fast/js/isPrototypeOf.html
-/sdcard/android/layout_tests/fast/js/prototypes.html
-/sdcard/android/layout_tests/fast/js/math.html
-/sdcard/android/layout_tests/fast/js/string-from-char-code.html
-/sdcard/android/layout_tests/fast/js/sort-no-jit-code-crash.html
-/sdcard/android/layout_tests/fast/js/eval-overriding.html
-/sdcard/android/layout_tests/fast/js/regexp-char-insensitive.html
-/sdcard/android/layout_tests/fast/js/array-float-delete.html
-/sdcard/android/layout_tests/fast/js/array-index-immediate-types.html
-/sdcard/android/layout_tests/fast/js/integer-extremes.html
-/sdcard/android/layout_tests/fast/js/console-non-string-values.html
-/sdcard/android/layout_tests/fast/js/regexp-non-bmp.html
-/sdcard/android/layout_tests/fast/js/regexp-range-bound-ffff.html
-/sdcard/android/layout_tests/fast/js/delete-then-put.html
-/sdcard/android/layout_tests/fast/js/nested-object-gc.html
-/sdcard/android/layout_tests/fast/js/string-replace-2.html
-/sdcard/android/layout_tests/fast/js/cached-eval-gc.html
-/sdcard/android/layout_tests/fast/js/property-getters-and-setters.html
-/sdcard/android/layout_tests/fast/js/array-reset-large-index.html
-/sdcard/android/layout_tests/fast/js/date-proto-generic-invocation.html
-/sdcard/android/layout_tests/fast/js/lastModified.html
-/sdcard/android/layout_tests/fast/js/encode-URI-test.html
-/sdcard/android/layout_tests/fast/js/codegen-loops-logical-nodes.html
-/sdcard/android/layout_tests/fast/js/string-capitalization.html
-/sdcard/android/layout_tests/fast/js/caller-property.html
-/sdcard/android/layout_tests/fast/js/regexp-overflow-too-big.html
-/sdcard/android/layout_tests/fast/js/repeat-cached-vm-reentry.html
-/sdcard/android/layout_tests/fast/js/date-DST-time-cusps.html
-/sdcard/android/layout_tests/fast/js/regexp-unicode-handling.html
-/sdcard/android/layout_tests/fast/js/unmatching-argument-count.html
-/sdcard/android/layout_tests/fast/js/text-field-resize.html
-/sdcard/android/layout_tests/fast/js/delete-multiple-global-blocks.html
-/sdcard/android/layout_tests/fast/js/eval-throw-return.html
-/sdcard/android/layout_tests/fast/js/duplicate-param-crash.html
-/sdcard/android/layout_tests/fast/js/switch-behaviour.html
-/sdcard/android/layout_tests/fast/js/delete-syntax.html
-/sdcard/android/layout_tests/fast/js/date-DST-pre-1970.html
-/sdcard/android/layout_tests/fast/js/array-splice.html
-/sdcard/android/layout_tests/fast/js/statement-list-register-crash.html
-/sdcard/android/layout_tests/fast/js/date-set-to-nan.html
-/sdcard/android/layout_tests/fast/js/code-serialize-paren.html
-/sdcard/android/layout_tests/fast/js/parse-backslash-before-newline.html
-/sdcard/android/layout_tests/fast/js/delete-function-parameter.html
-/sdcard/android/layout_tests/fast/js/exception-expression-offset.html
-/sdcard/android/layout_tests/fast/js/JSON-stringify-replacer.html
-/sdcard/android/layout_tests/fast/js/invalid-syntax-for-function.html
-/sdcard/android/layout_tests/fast/js/toString-and-valueOf-override.html
-/sdcard/android/layout_tests/fast/js/cyclic-prototypes.html
-/sdcard/android/layout_tests/fast/js/equality.html
-/sdcard/android/layout_tests/fast/js/order-of-operations.html
-/sdcard/android/layout_tests/fast/js/regexp-no-extensions.html
-/sdcard/android/layout_tests/fast/js/stack-unwinding.html
-/sdcard/android/layout_tests/fast/js/toString-try-else.html
-/sdcard/android/layout_tests/fast/js/reserved-words.html
-/sdcard/android/layout_tests/fast/js/function-dot-arguments-and-caller.html
-/sdcard/android/layout_tests/fast/js/do-while-expression-value.html
-/sdcard/android/layout_tests/fast/js/bom-in-file-retains-correct-offset.html
-/sdcard/android/layout_tests/fast/js/string-split-ignore-case.html
-/sdcard/android/layout_tests/fast/js/date-constructor.html
-/sdcard/android/layout_tests/fast/js/global-function-resolve.html
-/sdcard/android/layout_tests/fast/js/date-big-setdate.html
-/sdcard/android/layout_tests/fast/js/array-every.html
-/sdcard/android/layout_tests/fast/js/array-functions-non-arrays.html
-/sdcard/android/layout_tests/fast/js/function-toString-parentheses.html
-/sdcard/android/layout_tests/fast/js/while-expression-value.html
-/sdcard/android/layout_tests/fast/js/string-replace-3.html
-/sdcard/android/layout_tests/fast/js/avl-crash.html
-/sdcard/android/layout_tests/fast/js/vardecl-blocks-init.html
-/sdcard/android/layout_tests/fast/js/null-char-in-string.html
-/sdcard/android/layout_tests/fast/js/codegen-temporaries-multiple-global-blocks.html
-/sdcard/android/layout_tests/fast/js/char-at.html
-/sdcard/android/layout_tests/fast/js/function-constructor-newline-after-brace.html
-/sdcard/android/layout_tests/fast/js/propertyIsEnumerable.html
-/sdcard/android/layout_tests/fast/js/exception-thrown-from-equal.html
-/sdcard/android/layout_tests/fast/js/constructor.html
-/sdcard/android/layout_tests/fast/js/regexp-backreferences.html
-/sdcard/android/layout_tests/fast/js/regexp-overflow.html
-/sdcard/android/layout_tests/fast/js/var-declarations.html
-/sdcard/android/layout_tests/fast/js/continue-break-multiple-labels.html
-/sdcard/android/layout_tests/fast/js/toString-exception.html
-/sdcard/android/layout_tests/fast/js/regexp-test-null-string.html
-/sdcard/android/layout_tests/fast/js/date-parse-comments-test.html
-/sdcard/android/layout_tests/fast/js/select-options-remove-gc.html
-/sdcard/android/layout_tests/fast/js/implicit-call-with-global-reentry.html
-/sdcard/android/layout_tests/fast/js/array-tostring-and-join.html
-/sdcard/android/layout_tests/fast/js/function-names.html
-/sdcard/android/layout_tests/fast/js/primitive-property-access-edge-cases.html
-/sdcard/android/layout_tests/fast/js/date-preserve-milliseconds.html
-/sdcard/android/layout_tests/fast/js/sort-large-array.html
-/sdcard/android/layout_tests/fast/js/for-in-to-text.html
-/sdcard/android/layout_tests/fast/js/global-var-limit.html
-/sdcard/android/layout_tests/fast/js/static-scope-object.html
-/sdcard/android/layout_tests/fast/js/var-shadows-arg-crash.html
-/sdcard/android/layout_tests/fast/js/function-apply.html
-/sdcard/android/layout_tests/fast/js/array-reduce.html
-/sdcard/android/layout_tests/fast/js/function-prototype.html
-/sdcard/android/layout_tests/fast/js/tostring-exception-in-property-access.html
-/sdcard/android/layout_tests/fast/js/function-declaration-statement.html
-/sdcard/android/layout_tests/fast/js/large-expressions.html
-/sdcard/android/layout_tests/fast/js/date-negative-setmonth.html
-/sdcard/android/layout_tests/fast/js/reentrant-call-unwind.html
-/sdcard/android/layout_tests/fast/js/dictionary-no-cache.html
-/sdcard/android/layout_tests/fast/js/regexp-lastindex.html
-/sdcard/android/layout_tests/fast/js/finally-codegen-failure.html
-/sdcard/android/layout_tests/fast/js/instance-of-immediates.html
-/sdcard/android/layout_tests/fast/js/read-modify-eval.html
-/sdcard/android/layout_tests/fast/js/exception-thrown-from-function-with-lazy-activation.html
-/sdcard/android/layout_tests/fast/js/cyclic-ref-toString.html
-/sdcard/android/layout_tests/fast/js/function-toString-semicolon-insertion.html
-/sdcard/android/layout_tests/fast/js/exception-sequencing.html
-/sdcard/android/layout_tests/fast/js/date-big-constructor.html
-/sdcard/android/layout_tests/fast/js/gmail-re-re.html
-/sdcard/android/layout_tests/fast/js/deep-recursion-test.html
-/sdcard/android/layout_tests/fast/js/lexical-lookup-in-function-constructor.html
-/sdcard/android/layout_tests/fast/js/regexp-range-out-of-order.html
-/sdcard/android/layout_tests/fast/js/throw-from-array-sort.html
-/sdcard/android/layout_tests/fast/js/slash-lineterminator-parse.html
-/sdcard/android/layout_tests/fast/js/dot-node-base-exception.html
-/sdcard/android/layout_tests/fast/js/toString-stack-overflow.html
-/sdcard/android/layout_tests/fast/js/codegen-peephole-locals.html
-/sdcard/android/layout_tests/fast/js/constant-count.html
-/sdcard/android/layout_tests/fast/js/regexp-compile.html
-/sdcard/android/layout_tests/fast/js/declaration-in-block.html
-/sdcard/android/layout_tests/fast/js/eval-var-decl.html
-/sdcard/android/layout_tests/fast/js/eval-cross-window.html
-/sdcard/android/layout_tests/fast/js/function-decompilation-operators.html
-/sdcard/android/layout_tests/fast/js/sort-non-numbers.html
-/sdcard/android/layout_tests/fast/js/excessive-comma-usage.html
-/sdcard/android/layout_tests/fast/js/method-check.html
-/sdcard/android/layout_tests/fast/js/function-declarations.html
-/sdcard/android/layout_tests/fast/js/regexp-extended-characters-match.html
-/sdcard/android/layout_tests/fast/js/non-object-proto.html
-/sdcard/android/layout_tests/fast/js/toString-number-dot-expr.html
-/sdcard/android/layout_tests/fast/js/date-parse-test.html
-/sdcard/android/layout_tests/fast/js/exception-try-finally-scope-error.html
-/sdcard/android/layout_tests/fast/js/function-dot-arguments.html
-/sdcard/android/layout_tests/fast/js/toString-prefix-postfix-preserve-parens.html
-/sdcard/android/layout_tests/fast/js/regexp-ranges-and-escaped-hyphens.html
-/sdcard/android/layout_tests/fast/js/construct-global-object.html
-/sdcard/android/layout_tests/fast/js/array-holes.html
-/sdcard/android/layout_tests/fast/js/exception-linenums.html
-/sdcard/android/layout_tests/fast/js/codegen-temporaries.html
-/sdcard/android/layout_tests/fast/js/array-join-bug-11524.html
-/sdcard/android/layout_tests/fast/js/with-scope-gc.html
-/sdcard/android/layout_tests/fast/js/string-index-overflow.html
-/sdcard/android/layout_tests/fast/js/eval-cache-crash.html
-/sdcard/android/layout_tests/fast/js/array-map.html
-/sdcard/android/layout_tests/fast/js/exception-codegen-crash.html
-/sdcard/android/layout_tests/fast/js/comparefn-sort-stability.html
-/sdcard/android/layout_tests/fast/js/typeof-constant-string.html
-/sdcard/android/layout_tests/fast/js/navigator-plugins-crash.html
-/sdcard/android/layout_tests/fast/js/vardecl-preserve-parameters.html
-/sdcard/android/layout_tests/fast/inline/clean-after-removing-temp-boxes.html
-/sdcard/android/layout_tests/fast/inline/continuation-positioned-reparenting.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-65-excerpt.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-66-excerpt.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/cellpadding-attribute.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/insert-row.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/tBodies.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableElement/rows.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/activeElement.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/hasFocus-frameless-crash.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-call.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-plugins.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-get.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-unknown-child-element.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-or-id.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-set.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-multiple-calls.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-special-properties.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/url-getset.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-call.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-open-return-value.html
-/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-multiple-calls.html
-/sdcard/android/layout_tests/fast/dom/HTMLLabelElement/form/test1.html
-/sdcard/android/layout_tests/fast/dom/Document/replace-child.html
-/sdcard/android/layout_tests/fast/dom/Document/title-property-creates-title-element.html
-/sdcard/android/layout_tests/fast/dom/Document/createElementNS-namespace-err.html
-/sdcard/android/layout_tests/fast/dom/Document/title-property-set-multiple-times.html
-/sdcard/android/layout_tests/fast/dom/Document/document-reopen.html
-/sdcard/android/layout_tests/fast/dom/Document/document-charset.html
-/sdcard/android/layout_tests/fast/dom/Document/replaceChild-null-oldChild.html
-/sdcard/android/layout_tests/fast/dom/Document/createAttributeNS-namespace-err.html
-/sdcard/android/layout_tests/fast/dom/Document/open-with-pending-load.html
-/sdcard/android/layout_tests/fast/dom/Document/document-write-doctype.html
-/sdcard/android/layout_tests/fast/dom/Document/doc-open-while-parsing.html
-/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/named-options.html
-/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/length-not-overridden.html
-/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-set-string-length.html
-/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/listbox-select-reset.html
-/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-detached.html
-/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/remove-element-from-within-focus-handler-crash.html
-/sdcard/android/layout_tests/fast/dom/Selection/getRangeAt.html
-/sdcard/android/layout_tests/fast/dom/HTMLMetaElement/meta-attributes.html
-/sdcard/android/layout_tests/fast/dom/Element/fixed-position-offset-parent.html
-/sdcard/android/layout_tests/fast/dom/Element/getAttribute-check-case-sensitivity.html
-/sdcard/android/layout_tests/fast/dom/Element/attr-param-typechecking.html
-/sdcard/android/layout_tests/fast/dom/Element/attribute-uppercase.html
-/sdcard/android/layout_tests/fast/dom/Element/element-traversal.html
-/sdcard/android/layout_tests/fast/dom/Element/onclick-case.html
-/sdcard/android/layout_tests/fast/dom/Element/offsetLeft-offsetTop-body-quirk.html
-/sdcard/android/layout_tests/fast/dom/Element/contains-method.html
-/sdcard/android/layout_tests/fast/dom/Element/scrollWidth.html
-/sdcard/android/layout_tests/fast/dom/Element/setAttribute-with-colon.html
-/sdcard/android/layout_tests/fast/dom/Element/setAttribute-case-insensitivity.html
-/sdcard/android/layout_tests/fast/dom/Element/dimension-properties-unrendered.html
-/sdcard/android/layout_tests/fast/dom/Element/offsetLeft-offsetTop-html.html
-/sdcard/android/layout_tests/fast/dom/Element/offsetTop-table-cell.html
-/sdcard/android/layout_tests/fast/dom/DOMException/EventException.html
-/sdcard/android/layout_tests/fast/dom/DOMException/prototype-object.html
-/sdcard/android/layout_tests/fast/dom/DOMException/RangeException.html
-/sdcard/android/layout_tests/fast/dom/HTMLButtonElement/value/getset.html
-/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-for-attribute-unexpected-execution.html
-/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-reexecution.html
-/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-set-src.html
-/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-load-events.html
-/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-decoding-error-after-setting-src.html
-/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/collection-setter-getter.html
-/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/set-option-index-text.html
-/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-text.html
-/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-prototype.html
-/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-1.html
-/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-2.html
-/sdcard/android/layout_tests/fast/dom/NodeList/childNodes-reset-cache.html
-/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-3.html
-/sdcard/android/layout_tests/fast/dom/NodeList/invalidate-node-lists-when-parsing.html
-/sdcard/android/layout_tests/fast/dom/NodeList/item-by-id-with-no-document.html
-/sdcard/android/layout_tests/fast/dom/NodeList/nodelist-item-with-name.html
-/sdcard/android/layout_tests/fast/dom/DOMImplementation/createDocument-namespace-err.html
-/sdcard/android/layout_tests/fast/dom/DOMImplementation/createDocumentType-err.html
-/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/transition-property-names.html
-/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/css-properties-case-sensitive.html
-/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/empty-string-property.html
-/sdcard/android/layout_tests/fast/dom/Node/normalize.html
-/sdcard/android/layout_tests/fast/dom/Node/initial-values.html
-/sdcard/android/layout_tests/fast/dom/Node/DOMNodeRemovedEvent.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/viewless-document.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-almost-strict.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/elementRoot.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-strict.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/not-supported-namespace-in-selector.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseTag.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/undefined-null-stringify.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/detached-element.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/bug-17313.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-almost-strict.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-strict.html
-/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList-almost-strict.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableSectionElement/rows.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/checked-pseudo-selector.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-text-reset.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-as-number.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/duplicate-element-names.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-hidden-value.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-checked-reset.html
-/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-attribute.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/001.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/002.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/003.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/004.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/002.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/012.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/004.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/014.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/006.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/008.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/dumpNodeList.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/001.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/003.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/013.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/005.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/015.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/007.html
-/sdcard/android/layout_tests/fast/dom/getElementsByClassName/009.html
-/sdcard/android/layout_tests/fast/dom/TreeWalker/TreeWalker-currentNode.html
-/sdcard/android/layout_tests/fast/dom/HTMLDivElement/align/getset.html
-/sdcard/android/layout_tests/fast/dom/Text/replaceWholeText.html
-/sdcard/android/layout_tests/fast/dom/HTMLFormElement/adopt-assertion.html
-/sdcard/android/layout_tests/fast/dom/HTMLFormElement/document-deactivation-callback-crash.html
-/sdcard/android/layout_tests/fast/dom/HTMLFormElement/htmlformelement-indexed-getter.html
-/sdcard/android/layout_tests/fast/dom/HTMLFormElement/elements-not-in-document.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/window-override-window-using-defineGetter.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/window-override-location-using-defineGetter.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-valueOf-using-with.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-valueOf-on-proto-using-defineGetter.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/window-shadow-location-using-string.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-valueOf-on-proto-using-with.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-toString.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-valueOf-on-proto.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/window-shadow-window-using-js-object-with-location-field.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/window-shadow-location-using-js-object-with-toString.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-toString-using-defineGetter.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-valueOf.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-toString-using-with.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-toString-on-proto-using-defineGetter.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-toString-on-proto-using-with.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-toString-on-proto.html
-/sdcard/android/layout_tests/fast/dom/Window/Location/location-override-valueOf-using-defineGetter.html
-/sdcard/android/layout_tests/fast/dom/Window/window-closed-crash.html
-/sdcard/android/layout_tests/fast/dom/Window/window-function-name-getter-precedence.html
-/sdcard/android/layout_tests/fast/dom/Window/window-open-self.html
-/sdcard/android/layout_tests/fast/dom/Window/console-functions.html
-/sdcard/android/layout_tests/fast/dom/Window/window-postmessage-args.html
-/sdcard/android/layout_tests/fast/dom/Window/attr-constructor.html
-/sdcard/android/layout_tests/fast/dom/Window/window-remove-event-listener.html
-/sdcard/android/layout_tests/fast/dom/Window/window-frames-self-referential.html
-/sdcard/android/layout_tests/fast/dom/Window/redirect-with-timer.html
-/sdcard/android/layout_tests/fast/dom/Window/setting-properties-on-closed-window.html
-/sdcard/android/layout_tests/fast/dom/Window/window-open-parent.html
-/sdcard/android/layout_tests/fast/dom/Window/window-access-after-navigation.html
-/sdcard/android/layout_tests/fast/dom/Window/window-appendages-cleared.html
-/sdcard/android/layout_tests/fast/dom/Window/window-special-properties.html
-/sdcard/android/layout_tests/fast/dom/Window/window-custom-prototype.html
-/sdcard/android/layout_tests/fast/dom/Window/window-collection-length-no-crash.html
-/sdcard/android/layout_tests/fast/dom/Window/setTimeout-no-arguments.html
-/sdcard/android/layout_tests/fast/dom/Window/getMatchedCSSRules-null-crash.html
-/sdcard/android/layout_tests/fast/dom/Window/window-open-self-from-other-frame.html
-/sdcard/android/layout_tests/fast/dom/Window/window-custom-prototype-crash.html
-/sdcard/android/layout_tests/fast/dom/Window/setTimeout-string-argument.html
-/sdcard/android/layout_tests/fast/dom/Window/window-object-cross-frame-calls.html
-/sdcard/android/layout_tests/fast/dom/Window/window-location-replace-functions.html
-/sdcard/android/layout_tests/fast/dom/Window/dispatchEvent.html
-/sdcard/android/layout_tests/fast/dom/Window/window-function-frame-getter-precedence.html
-/sdcard/android/layout_tests/fast/dom/Window/atob-btoa.html
-/sdcard/android/layout_tests/fast/dom/Window/clear-timeout.html
-/sdcard/android/layout_tests/fast/dom/Window/window-early-properties-xhr.html
-/sdcard/android/layout_tests/fast/dom/Window/window-property-clearing.html
-/sdcard/android/layout_tests/fast/dom/Window/element-constructors-on-window.html
-/sdcard/android/layout_tests/fast/dom/Window/orphaned-frame-access.html
-/sdcard/android/layout_tests/fast/dom/Window/window-open-pending-url.html
-/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-sub-frame.html
-/sdcard/android/layout_tests/fast/dom/Window/console-trace.html
-/sdcard/android/layout_tests/fast/dom/Window/alert-undefined.html
-/sdcard/android/layout_tests/fast/dom/Window/window-open-top.html
-/sdcard/android/layout_tests/fast/dom/Window/global-opener-function.html
-/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing.html
-/sdcard/android/layout_tests/fast/dom/Window/remove-timeout-crash.html
-/sdcard/android/layout_tests/fast/dom/Window/customized-property-survives-gc.html
-/sdcard/android/layout_tests/fast/dom/Window/timeout-callback-scope.html
-/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing-name.html
-/sdcard/android/layout_tests/fast/dom/Window/window-open-parent-no-parent.html
-/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-iframe.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/cells.html
-/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/insertCell.html
-/sdcard/android/layout_tests/fast/dom/HTMLFontElement/size-attribute.html
-/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/form/test1.html
-/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/object-as-frame.html
-/sdcard/android/layout_tests/fast/dom/HTMLElement/innerHTML-selection-crash.html
-/sdcard/android/layout_tests/fast/dom/HTMLElement/set-inner-outer-optimization.html
-/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-1.html
-/sdcard/android/layout_tests/fast/dom/Range/range-compareNode.html
-/sdcard/android/layout_tests/fast/dom/Range/range-comparePoint.html
-/sdcard/android/layout_tests/fast/dom/Range/acid3-surround-contents.html
-/sdcard/android/layout_tests/fast/dom/Range/mutation.html
-/sdcard/android/layout_tests/fast/dom/Range/deleted-range-endpoints.html
-/sdcard/android/layout_tests/fast/dom/Range/13000.html
-/sdcard/android/layout_tests/fast/dom/Range/range-processing-instructions.html
-/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-separate-endContainer.html
-/sdcard/android/layout_tests/fast/dom/Range/range-intersectsNode.html
-/sdcard/android/layout_tests/fast/dom/Range/range-isPointInRange.html
-/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-2.html
-/sdcard/android/layout_tests/fast/dom/Range/range-clone-empty.html
-/sdcard/android/layout_tests/fast/dom/Range/range-modifycontents.html
-/sdcard/android/layout_tests/fast/dom/Range/bug-19527.html
-/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-splittext.html
-/sdcard/android/layout_tests/fast/dom/Range/surroundContents-check-boundary-points.html
-/sdcard/android/layout_tests/fast/dom/Range/range-exceptions.html
-/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-check.html
-/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/set-version.html
-/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/duplicate-html-element-crash.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-lowsrc-getset.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-src-absolute-url.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-loading-gc.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-longdesc-absolute-url.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/constructor-mutation-event-dispatch.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-load-cross-document.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-without-renderer-width.html
-/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-natural-width-height.html
-/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime.html
-/sdcard/android/layout_tests/fast/dom/EntityReference/readonly-exceptions.html
-/sdcard/android/layout_tests/fast/dom/script-element-remove-self.html
-/sdcard/android/layout_tests/fast/dom/remove-named-attribute-crash.html
-/sdcard/android/layout_tests/fast/dom/style-sheet-candidate-remove-unrendered-document.html
-/sdcard/android/layout_tests/fast/dom/node-item.html
-/sdcard/android/layout_tests/fast/dom/clone-node-style.html
-/sdcard/android/layout_tests/fast/dom/script-element-without-frame-crash.html
-/sdcard/android/layout_tests/fast/dom/script-element-gc.html
-/sdcard/android/layout_tests/fast/dom/empty-hash-and-search.html
-/sdcard/android/layout_tests/fast/dom/duplicate-ids.html
-/sdcard/android/layout_tests/fast/dom/prototypes.html
-/sdcard/android/layout_tests/fast/dom/clone-node-form-elements.html
-/sdcard/android/layout_tests/fast/dom/import-attribute-node.html
-/sdcard/android/layout_tests/fast/dom/getter-on-window-object2.html
-/sdcard/android/layout_tests/fast/dom/objc-big-method-name.html
-/sdcard/android/layout_tests/fast/dom/importNode-prefix.html
-/sdcard/android/layout_tests/fast/dom/css-dom-read.html
-/sdcard/android/layout_tests/fast/dom/image-object.html
-/sdcard/android/layout_tests/fast/dom/gc-5.html
-/sdcard/android/layout_tests/fast/dom/cssTarget-crash.html
-/sdcard/android/layout_tests/fast/dom/DOMParser-assign-variable.html
-/sdcard/android/layout_tests/fast/dom/offset-parent-positioned-and-inline.html
-/sdcard/android/layout_tests/fast/dom/timer-clear-interval-in-handler.html
-/sdcard/android/layout_tests/fast/dom/implementation-createHTMLDocument.html
-/sdcard/android/layout_tests/fast/dom/iframe-document.html
-/sdcard/android/layout_tests/fast/dom/document-all-input.html
-/sdcard/android/layout_tests/fast/dom/getelementsbytagnamens-mixed-namespaces.html
-/sdcard/android/layout_tests/fast/dom/object-plugin-hides-properties.html
-/sdcard/android/layout_tests/fast/dom/gc-2.html
-/sdcard/android/layout_tests/fast/dom/computed-style-set-property.html
-/sdcard/android/layout_tests/fast/dom/inner-text-001.html
-/sdcard/android/layout_tests/fast/dom/css-selectorText.html
-/sdcard/android/layout_tests/fast/dom/replace-first-child.html
-/sdcard/android/layout_tests/fast/dom/select-selectedIndex-multiple.html
-/sdcard/android/layout_tests/fast/dom/importNode-null.html
-/sdcard/android/layout_tests/fast/dom/space-to-text.html
-/sdcard/android/layout_tests/fast/dom/css-set-property-exception.html
-/sdcard/android/layout_tests/fast/dom/java-applet-calls.html
-/sdcard/android/layout_tests/fast/dom/plugin-attributes-enumeration.html
-/sdcard/android/layout_tests/fast/dom/html-attribute-types.html
-/sdcard/android/layout_tests/fast/dom/resource-locations-in-created-html-document.html
-/sdcard/android/layout_tests/fast/dom/comment-document-fragment.html
-/sdcard/android/layout_tests/fast/dom/createAttribute-exception.html
-/sdcard/android/layout_tests/fast/dom/noscript-style.html
-/sdcard/android/layout_tests/fast/dom/serialize-cdata.html
-/sdcard/android/layout_tests/fast/dom/createDocument.html
-/sdcard/android/layout_tests/fast/dom/getelementbyname-invalidation.html
-/sdcard/android/layout_tests/fast/dom/setAttributeNS-empty-namespace.html
-/sdcard/android/layout_tests/fast/dom/capturing-event-listeners.html
-/sdcard/android/layout_tests/fast/dom/title-text-property.html
-/sdcard/android/layout_tests/fast/dom/null-page-show-modal-dialog-crash.html
-/sdcard/android/layout_tests/fast/dom/incompatible-operations.html
-/sdcard/android/layout_tests/fast/dom/inner-text-rtl.html
-/sdcard/android/layout_tests/fast/dom/createDocument-empty.html
-/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-baseuri-null.html
-/sdcard/android/layout_tests/fast/dom/option-properties.html
-/sdcard/android/layout_tests/fast/dom/background-shorthand-csstext.html
-/sdcard/android/layout_tests/fast/dom/Range-insertNode-crash.html
-/sdcard/android/layout_tests/fast/dom/NamedNodeMap-setNamedItem-crash.html
-/sdcard/android/layout_tests/fast/dom/early-frame-url.html
-/sdcard/android/layout_tests/fast/dom/everything-to-string.html
-/sdcard/android/layout_tests/fast/dom/attribute-empty-value-no-children.html
-/sdcard/android/layout_tests/fast/dom/length-attribute-mapping.html
-/sdcard/android/layout_tests/fast/dom/documenturi-loses-to-base-tag.html
-/sdcard/android/layout_tests/fast/dom/createDocumentType2.html
-/sdcard/android/layout_tests/fast/dom/gc-6.html
-/sdcard/android/layout_tests/fast/dom/attribute-case-sensitivity.html
-/sdcard/android/layout_tests/fast/dom/compatMode-Compat.html
-/sdcard/android/layout_tests/fast/dom/namespaces-1.html
-/sdcard/android/layout_tests/fast/dom/getter-on-window-object.html
-/sdcard/android/layout_tests/fast/dom/constructors-overriding.html
-/sdcard/android/layout_tests/fast/dom/defaultView.html
-/sdcard/android/layout_tests/fast/dom/collection-null-like-arguments.html
-/sdcard/android/layout_tests/fast/dom/gc-3.html
-/sdcard/android/layout_tests/fast/dom/event-attribute-availability.html
-/sdcard/android/layout_tests/fast/dom/select-selectedIndex.html
-/sdcard/android/layout_tests/fast/dom/compatMode-Strict.html
-/sdcard/android/layout_tests/fast/dom/attribute-downcast-right.html
-/sdcard/android/layout_tests/fast/dom/document-all-select.html
-/sdcard/android/layout_tests/fast/dom/wrapper-context.html
-/sdcard/android/layout_tests/fast/dom/anchor-backslash.html
-/sdcard/android/layout_tests/fast/dom/css-mediarule-functions.html
-/sdcard/android/layout_tests/fast/dom/gc-acid3.html
-/sdcard/android/layout_tests/fast/dom/duplicate-ids-document-order.html
-/sdcard/android/layout_tests/fast/dom/exception-no-frame-inline-script-crash.html
-/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype2.html
-/sdcard/android/layout_tests/fast/dom/dir-no-body.html
-/sdcard/android/layout_tests/fast/dom/null-document-window-open-crash.html
-/sdcard/android/layout_tests/fast/dom/css-RGBValue.html
-/sdcard/android/layout_tests/fast/dom/documentElement-null.html
-/sdcard/android/layout_tests/fast/dom/innerHTML-nbsp.html
-/sdcard/android/layout_tests/fast/dom/createElementNS-empty-namespace.html
-/sdcard/android/layout_tests/fast/dom/class-all-whitespace.html
-/sdcard/android/layout_tests/fast/dom/wrapper-identity.html
-/sdcard/android/layout_tests/fast/dom/null-document-location-assign-crash.html
-/sdcard/android/layout_tests/fast/dom/createElement.html
-/sdcard/android/layout_tests/fast/dom/createElement-with-column.xml
-/sdcard/android/layout_tests/fast/dom/simultaneouslyRegsiteredTimerFireOrder.html
-/sdcard/android/layout_tests/fast/dom/clone-node-form-elements-with-attr.html
-/sdcard/android/layout_tests/fast/dom/setAttributeNS.html
-/sdcard/android/layout_tests/fast/dom/anchor-toString.html
-/sdcard/android/layout_tests/fast/dom/dom-add-optionelement.html
-/sdcard/android/layout_tests/fast/dom/location-assign.html
-/sdcard/android/layout_tests/fast/dom/documenturi-affects-relative-paths.html
-/sdcard/android/layout_tests/fast/dom/javascript-backslash.html
-/sdcard/android/layout_tests/fast/dom/setAttribute-using-initial-input-value.html
-/sdcard/android/layout_tests/fast/dom/css-shortHands.html
-/sdcard/android/layout_tests/fast/dom/generic-form-element-assert.html
-/sdcard/android/layout_tests/fast/dom/dom-instanceof.html
-/sdcard/android/layout_tests/fast/dom/array-special-accessors-should-ignore-items.html
-/sdcard/android/layout_tests/fast/dom/element-attribute-js-null.html
-/sdcard/android/layout_tests/fast/dom/css-dom-read-2.html
-/sdcard/android/layout_tests/fast/dom/navigator-cookieEnabled-no-crash.html
-/sdcard/android/layout_tests/fast/dom/import-document-fragment.html
-/sdcard/android/layout_tests/fast/dom/setter-type-enforcement.html
-/sdcard/android/layout_tests/fast/dom/XMLSerializer.html
-/sdcard/android/layout_tests/fast/dom/navigator-vendorSub.html
-/sdcard/android/layout_tests/fast/dom/outerText-no-element.html
-/sdcard/android/layout_tests/fast/dom/replace-child-siblings.html
-/sdcard/android/layout_tests/fast/dom/xmlhttprequest-constructor-in-detached-document.html
-/sdcard/android/layout_tests/fast/dom/constants.html
-/sdcard/android/layout_tests/fast/dom/inner-text-with-no-renderer.html
-/sdcard/android/layout_tests/fast/dom/gc-7.html
-/sdcard/android/layout_tests/fast/dom/onerror-img.html
-/sdcard/android/layout_tests/fast/dom/document-attribute-js-null.html
-/sdcard/android/layout_tests/fast/dom/css-element-attribute-js-null.html
-/sdcard/android/layout_tests/fast/dom/gc-11.html
-/sdcard/android/layout_tests/fast/dom/mutation-event-remove-inserted-node.html
-/sdcard/android/layout_tests/fast/dom/constructors-cached.html
-/sdcard/android/layout_tests/fast/dom/null-chardata-crash.html
-/sdcard/android/layout_tests/fast/dom/compatMode-AlmostStrict.html
-/sdcard/android/layout_tests/fast/dom/createElement-with-column.html
-/sdcard/android/layout_tests/fast/dom/exception-no-frame-timeout-crash.html
-/sdcard/android/layout_tests/fast/dom/title-text-property-2.html
-/sdcard/android/layout_tests/fast/dom/no-elements.html
-/sdcard/android/layout_tests/fast/dom/non-numeric-values-numeric-parameters.html
-/sdcard/android/layout_tests/fast/dom/gc-4.html
-/sdcard/android/layout_tests/fast/dom/inner-width-height.html
-/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype.html
-/sdcard/android/layout_tests/fast/dom/createElementNS.html
-/sdcard/android/layout_tests/fast/dom/undetectable-document-all.html
-/sdcard/android/layout_tests/fast/dom/prototype-chain.html
-/sdcard/android/layout_tests/fast/dom/gc-1.html
-/sdcard/android/layout_tests/fast/dom/script-add.html
-/sdcard/android/layout_tests/fast/dom/select-selectedIndex-bug-12942.html
-/sdcard/android/layout_tests/fast/dom/text-control-crash-on-select.html
-/sdcard/android/layout_tests/fast/dom/frame-contentWindow-crash.html
-/sdcard/android/layout_tests/fast/dom/document_write_params.html
-/sdcard/android/layout_tests/fast/dom/namednodemap-namelookup.html
-/sdcard/android/layout_tests/fast/dom/null-document-location-replace-crash.html
-/sdcard/android/layout_tests/fast/dom/htmlcollection-detectability.html
-/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-relative-urls-do-not-resolve.html
-/sdcard/android/layout_tests/fast/dom/collection-namedItem-via-item.html
-/sdcard/android/layout_tests/fast/dom/set-inner-text-newlines.html
-/sdcard/android/layout_tests/fast/dom/document-dir-property.html
-/sdcard/android/layout_tests/fast/dom/undetectable-style-filter.html
-/sdcard/android/layout_tests/fast/dom/domListEnumeration.html
-/sdcard/android/layout_tests/fast/dom/destroy-selected-radio-button-crash.html
-/sdcard/android/layout_tests/fast/dom/tabindex-clamp.html
-/sdcard/android/layout_tests/fast/dom/iframe-contentWindow-crash.html
-/sdcard/android/layout_tests/fast/dom/comment-dom-node.html
-/sdcard/android/layout_tests/fast/dom/constructors-cached-navigate.html
-/sdcard/android/layout_tests/fast/dom/features.html
-/sdcard/android/layout_tests/fast/dom/canvasContext2d-element-attribute-js-null.html
-/sdcard/android/layout_tests/fast/dom/remove-style-element.html
-/sdcard/android/layout_tests/fast/dom/attribute-namespaces-get-set.html
-/sdcard/android/layout_tests/fast/dom/innerHTML-escaping-attribute.html
-/sdcard/android/layout_tests/fast/dom/null-document-location-put-crash.html
-/sdcard/android/layout_tests/fast/dom/ImageDocument-image-deletion.html
-/sdcard/android/layout_tests/fast/dom/document-scripts.html
-/sdcard/android/layout_tests/fast/dom/cloneNode.html
-/sdcard/android/layout_tests/fast/dom/onload-open.html
-/sdcard/android/layout_tests/fast/gradients/crash-on-remove.html
-/sdcard/android/layout_tests/fast/invalid/test-case-tr-th-td-should-not-close-dl-list.html
-/sdcard/android/layout_tests/fast/invalid/nestedh3s-rapidweaver.html
-/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_selected.html
-/sdcard/android/layout_tests/fast/forms/option-value-and-label.html
-/sdcard/android/layout_tests/fast/forms/menulist-selection-reset.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-customError-001.html
-/sdcard/android/layout_tests/fast/forms/textfield-focus-out.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-000.html
-/sdcard/android/layout_tests/fast/forms/form-data-encoding-normalization-overrun.html
-/sdcard/android/layout_tests/fast/forms/textarea-trailing-newline.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-002.html
-/sdcard/android/layout_tests/fast/forms/selection-functions.html
-/sdcard/android/layout_tests/fast/forms/select-no-name.html
-/sdcard/android/layout_tests/fast/forms/multiple-selected-options-innerHTML.html
-/sdcard/android/layout_tests/fast/forms/input-named-action-overrides-action-attribute.html
-/sdcard/android/layout_tests/fast/forms/empty-get.html
-/sdcard/android/layout_tests/fast/forms/display-none-in-onchange-keyboard.html
-/sdcard/android/layout_tests/fast/forms/4628409.html
-/sdcard/android/layout_tests/fast/forms/numeric-input-name.html
-/sdcard/android/layout_tests/fast/forms/activate-and-disabled-elements.html
-/sdcard/android/layout_tests/fast/forms/tabs-with-modifiers.html
-/sdcard/android/layout_tests/fast/forms/form-get-multipart2.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-002.html
-/sdcard/android/layout_tests/fast/forms/menulist-no-renderer-onmousedown.html
-/sdcard/android/layout_tests/fast/forms/select-replace-option.html
-/sdcard/android/layout_tests/fast/forms/textarea-setvalue-submit.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-007.html
-/sdcard/android/layout_tests/fast/forms/double-focus.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-004.html
-/sdcard/android/layout_tests/fast/forms/form-data-encoding-2.html
-/sdcard/android/layout_tests/fast/forms/inline-ignored-on-legend.html
-/sdcard/android/layout_tests/fast/forms/focus.html
-/sdcard/android/layout_tests/fast/forms/input-text-enter.html
-/sdcard/android/layout_tests/fast/forms/input-implicit-length-limit.html
-/sdcard/android/layout_tests/fast/forms/element-order.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-customError-002.html
-/sdcard/android/layout_tests/fast/forms/form-post-urlencoded.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-001.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-003.html
-/sdcard/android/layout_tests/fast/forms/8250.html
-/sdcard/android/layout_tests/fast/forms/var-name-conflict-in-form-event-handler.html
-/sdcard/android/layout_tests/fast/forms/listbox-select-all.html
-/sdcard/android/layout_tests/fast/forms/range-reset.html
-/sdcard/android/layout_tests/fast/forms/select-remove-option.html
-/sdcard/android/layout_tests/fast/forms/onselect-selectall.html
-/sdcard/android/layout_tests/fast/forms/input-select-webkit-user-select-none.html
-/sdcard/android/layout_tests/fast/forms/paste-multiline-text-input.html
-/sdcard/android/layout_tests/fast/forms/textarea-no-scroll-on-blur.html
-/sdcard/android/layout_tests/fast/forms/select-reset-multiple-selections-4-single-selection.html
-/sdcard/android/layout_tests/fast/forms/tab-in-input.html
-/sdcard/android/layout_tests/fast/forms/button-click-DOM.html
-/sdcard/android/layout_tests/fast/forms/submit-nil-value-field-assert.html
-/sdcard/android/layout_tests/fast/forms/domstring-replace-crash.html
-/sdcard/android/layout_tests/fast/forms/select-max-length.html
-/sdcard/android/layout_tests/fast/forms/form-get-multipart3.html
-/sdcard/android/layout_tests/fast/forms/select-out-of-bounds-index.html
-/sdcard/android/layout_tests/fast/forms/selected-index-assert.html
-/sdcard/android/layout_tests/fast/forms/legend-display-none.html
-/sdcard/android/layout_tests/fast/forms/form-collection-lookup.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-004.html
-/sdcard/android/layout_tests/fast/forms/select-list-box-mouse-focus.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-008.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-005.html
-/sdcard/android/layout_tests/fast/forms/required-attribute-001.html
-/sdcard/android/layout_tests/fast/forms/select-index-setter.html
-/sdcard/android/layout_tests/fast/forms/option-change-single-selected.html
-/sdcard/android/layout_tests/fast/forms/listbox-scroll-after-options-removed.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-customError-003.html
-/sdcard/android/layout_tests/fast/forms/input-selection-hidden.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-002.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-004.html
-/sdcard/android/layout_tests/fast/forms/select-set-inner.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-elementFromPoint.html
-/sdcard/android/layout_tests/fast/forms/missing-action.html
-/sdcard/android/layout_tests/fast/forms/listbox-typeahead-empty.html
-/sdcard/android/layout_tests/fast/forms/submit-to-url-fragment.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-005.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-009.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-006.html
-/sdcard/android/layout_tests/fast/forms/old-names.html
-/sdcard/android/layout_tests/fast/forms/required-attribute-002.html
-/sdcard/android/layout_tests/fast/forms/add-and-remove-option.html
-/sdcard/android/layout_tests/fast/forms/focus-style-pending.html
-/sdcard/android/layout_tests/fast/forms/textarea-initial-caret-position.html
-/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-mouse.html
-/sdcard/android/layout_tests/fast/forms/mutation-event-recalc.html
-/sdcard/android/layout_tests/fast/forms/slow-click.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-customError-004.html
-/sdcard/android/layout_tests/fast/forms/autofocus-attribute.html
-/sdcard/android/layout_tests/fast/forms/element-by-name.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-003.html
-/sdcard/android/layout_tests/fast/forms/radio-button-no-change-event.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-005.html
-/sdcard/android/layout_tests/fast/forms/input-maxlength.html
-/sdcard/android/layout_tests/fast/forms/select-reset.html
-/sdcard/android/layout_tests/fast/forms/input-hit-test-border.html
-/sdcard/android/layout_tests/fast/forms/pattern-attribute-001.html
-/sdcard/android/layout_tests/fast/forms/range-default-value.html
-/sdcard/android/layout_tests/fast/forms/shadow-tree-exposure.html
-/sdcard/android/layout_tests/fast/forms/paste-into-textarea.html
-/sdcard/android/layout_tests/fast/forms/radio-no-theme-padding.html
-/sdcard/android/layout_tests/fast/forms/textfield-drag-into-disabled.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-006.html
-/sdcard/android/layout_tests/fast/forms/saved-state-adoptNode-crash.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-007.html
-/sdcard/android/layout_tests/fast/forms/radio-check-click-and-drag.html
-/sdcard/android/layout_tests/fast/forms/11423.html
-/sdcard/android/layout_tests/fast/forms/cursor-position.html
-/sdcard/android/layout_tests/fast/forms/input-changing-value.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-004.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-001.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-006.html
-/sdcard/android/layout_tests/fast/forms/button-in-forms-collection.html
-/sdcard/android/layout_tests/fast/forms/input-delete.html
-/sdcard/android/layout_tests/fast/forms/placeholder-non-textfield.html
-/sdcard/android/layout_tests/fast/forms/option-constructor-selected.html
-/sdcard/android/layout_tests/fast/forms/input-multiple.html
-/sdcard/android/layout_tests/fast/forms/input-zero-height-focus.html
-/sdcard/android/layout_tests/fast/forms/pattern-attribute-002.html
-/sdcard/android/layout_tests/fast/forms/textarea-linewrap-dynamic.html
-/sdcard/android/layout_tests/fast/forms/placeholder-dom-property.html
-/sdcard/android/layout_tests/fast/forms/select-width-font-change.html
-/sdcard/android/layout_tests/fast/forms/text-field-setvalue-crash.html
-/sdcard/android/layout_tests/fast/forms/form-get-multipart.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-007.html
-/sdcard/android/layout_tests/fast/forms/select-type-ahead-list-box-no-selection.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-008.html
-/sdcard/android/layout_tests/fast/forms/textarea-crlf.html
-/sdcard/android/layout_tests/fast/forms/remove-radio-button-assert.html
-/sdcard/android/layout_tests/fast/forms/text-set-value-crash.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-001.html
-/sdcard/android/layout_tests/fast/forms/select-namedItem.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-005.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-002.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-007.html
-/sdcard/android/layout_tests/fast/forms/add-remove-option-modification-event.html
-/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-keyboard.html
-/sdcard/android/layout_tests/fast/forms/option-in-optgroup-removal.html
-/sdcard/android/layout_tests/fast/forms/form-data-encoding.html
-/sdcard/android/layout_tests/fast/forms/pattern-attribute-003.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-patternMismatch-001.html
-/sdcard/android/layout_tests/fast/forms/textarea-default-value-leading-newline.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-008.html
-/sdcard/android/layout_tests/fast/forms/add-remove-form-elements-stress-test.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-009.html
-/sdcard/android/layout_tests/fast/forms/textarea-setvalue-without-renderer.html
-/sdcard/android/layout_tests/fast/forms/hidden-input-not-enabled.html
-/sdcard/android/layout_tests/fast/forms/input-appearance-maxlength.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-001.html
-/sdcard/android/layout_tests/fast/forms/submit-with-base.html
-/sdcard/android/layout_tests/fast/forms/input-setvalue-selection.html
-/sdcard/android/layout_tests/fast/forms/autofocus-opera-002.html
-/sdcard/android/layout_tests/fast/forms/textarea-appearance-wrap.html
-/sdcard/android/layout_tests/fast/forms/add-selected-option.html
-/sdcard/android/layout_tests/fast/forms/willvalidate-006.html
-/sdcard/android/layout_tests/fast/forms/ValidityState-valueMissing-003.html
-/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap-empty.html
-/sdcard/android/layout_tests/fast/forms/document-write.html
-/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-hang.html
-/sdcard/android/layout_tests/fast/table/section-in-table-before-misnested-text-crash-css.html
-/sdcard/android/layout_tests/fast/table/large-rowspan-crash.html
-/sdcard/android/layout_tests/fast/table/colgroup-relative.html
-/sdcard/android/layout_tests/fast/table/border-changes.html
-/sdcard/android/layout_tests/fast/table/table-row-compositing-repaint-crash.html
-/sdcard/android/layout_tests/fast/table/cell-in-row-before-misnested-text-crash-css.html
-/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-2.html
-/sdcard/android/layout_tests/fast/table/rowindex-comment-nodes.html
-/sdcard/android/layout_tests/fast/table/td-display-nowrap.html
-/sdcard/android/layout_tests/fast/table/row-in-tbody-before-misnested-text-crash-css.html
-/sdcard/android/layout_tests/fast/table/empty-auto-column-zero-divide.html
-/sdcard/android/layout_tests/fast/table/form-in-tbody-before-misnested-text-crash-css.html
-/sdcard/android/layout_tests/fast/table/form-in-table-before-misnested-text-crash-css.html
-/sdcard/android/layout_tests/fast/table/destroy-cell-with-selection-crash.html
-/sdcard/android/layout_tests/fast/table/form-in-row-before-misnested-text-crash-css.html
-/sdcard/android/layout_tests/fast/css/counters/counter-function-input-2.html
-/sdcard/android/layout_tests/fast/css/counters/counter-function-input.html
-/sdcard/android/layout_tests/fast/css/counters/counter-number-input.html
-/sdcard/android/layout_tests/fast/css/variables/color-hex-test.html
-/sdcard/android/layout_tests/fast/css/variables/invalid-identifier.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/computed-style-negative-top.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-borderRadius.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-background-size.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-border-image.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-border-spacing.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/computed-style-font-family.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-zIndex-auto.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-transform.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/computed-style-display-none.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-background-position.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-text-overflow.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-border-box.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-relayout.html
-/sdcard/android/layout_tests/fast/css/getComputedStyle/getComputedStyle-text-decoration.html
-/sdcard/android/layout_tests/fast/css/media-rule-dyn.html
-/sdcard/android/layout_tests/fast/css/transform-function-lowercase-assert.html
-/sdcard/android/layout_tests/fast/css/word-break-user-modify-allowed-values.html
-/sdcard/android/layout_tests/fast/css/import-style-update.html
-/sdcard/android/layout_tests/fast/css/outline-invert-assertion.html
-/sdcard/android/layout_tests/fast/css/insertRule-font-face.html
-/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-004.html
-/sdcard/android/layout_tests/fast/css/zoom-in-length-round-trip.html
-/sdcard/android/layout_tests/fast/css/transform-inline-style-remove.html
-/sdcard/android/layout_tests/fast/css/padding-no-renderer.html
-/sdcard/android/layout_tests/fast/css/transition_shorthand_parsing.html
-/sdcard/android/layout_tests/fast/css/css-selector-text.html
-/sdcard/android/layout_tests/fast/css/dashboard-regions-attr-crash.html
-/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-001.html
-/sdcard/android/layout_tests/fast/css/pseudo-required-optional-006.html
-/sdcard/android/layout_tests/fast/css/font-property-priority.html
-/sdcard/android/layout_tests/fast/css/number-parsing-crash.html
-/sdcard/android/layout_tests/fast/css/device-aspect-ratio.html
-/sdcard/android/layout_tests/fast/css/pseudostyle-anonymous-text.html
-/sdcard/android/layout_tests/fast/css/css-properties-case-insensitive.html
-/sdcard/android/layout_tests/fast/css/sheet-collection-link.html
-/sdcard/android/layout_tests/fast/css/pseudo-required-optional-003.html
-/sdcard/android/layout_tests/fast/css/resize-value-compared.html
-/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values-parsing.html
-/sdcard/android/layout_tests/fast/css/hexColor-isDigit-assert.html
-/sdcard/android/layout_tests/fast/css/transform-inline-style.html
-/sdcard/android/layout_tests/fast/css/child-selector-implicit-tbody.html
-/sdcard/android/layout_tests/fast/css/outline-hidden-illegal-value.html
-/sdcard/android/layout_tests/fast/css/emptyStyleTag.html
-/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-1.html
-/sdcard/android/layout_tests/fast/css/display-none-inline-style-change-crash.html
-/sdcard/android/layout_tests/fast/css/getPropertyValue-clip.html
-/sdcard/android/layout_tests/fast/css/border-image-crash.html
-/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-005.html
-/sdcard/android/layout_tests/fast/css/insertRule-media.html
-/sdcard/android/layout_tests/fast/css/html-attr-case-sensitivity.html
-/sdcard/android/layout_tests/fast/css/font-face-multiple-families.html
-/sdcard/android/layout_tests/fast/css/getPropertyValue-border.html
-/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-002.html
-/sdcard/android/layout_tests/fast/css/invalid-rule-value.html
-/sdcard/android/layout_tests/fast/css/max-device-aspect-ratio.html
-/sdcard/android/layout_tests/fast/css/background-currentcolor.html
-/sdcard/android/layout_tests/fast/css/pseudo-required-optional-004.html
-/sdcard/android/layout_tests/fast/css/orphaned_units_crash.html
-/sdcard/android/layout_tests/fast/css/invalid-cursor-property-crash.html
-/sdcard/android/layout_tests/fast/css/sheet-title.html
-/sdcard/android/layout_tests/fast/css/large-list-of-rules-crash.html
-/sdcard/android/layout_tests/fast/css/pseudo-required-optional-001.html
-/sdcard/android/layout_tests/fast/css/background-position-serialize.html
-/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-2.html
-/sdcard/android/layout_tests/fast/css/webkit-marquee-speed-unit-in-quirksmode.html
-/sdcard/android/layout_tests/fast/css/CSSPrimitiveValue-exceptions.html
-/sdcard/android/layout_tests/fast/css/empty-script.html
-/sdcard/android/layout_tests/fast/css/mask-missing-image-crash.html
-/sdcard/android/layout_tests/fast/css/parse-timing-function-crash.html
-/sdcard/android/layout_tests/fast/css/background-position-inherit.html
-/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-003.html
-/sdcard/android/layout_tests/fast/css/font-family-builtins.html
-/sdcard/android/layout_tests/fast/css/remove-shorthand.html
-/sdcard/android/layout_tests/fast/css/overflow-property.html
-/sdcard/android/layout_tests/fast/css/pseudo-required-optional-005.html
-/sdcard/android/layout_tests/fast/css/min-device-aspect-ratio.html
-/sdcard/android/layout_tests/fast/css/nested-rule-parent-sheet.html
-/sdcard/android/layout_tests/fast/css/case-transform.html
-/sdcard/android/layout_tests/fast/css/number-parsing-crash-2.html
-/sdcard/android/layout_tests/fast/css/matrix-as-function-crash.html
-/sdcard/android/layout_tests/fast/css/pseudo-required-optional-002.html
-/sdcard/android/layout_tests/fast/css/attr-parsing.html
-/sdcard/android/layout_tests/fast/css/font-family-initial.html
-/sdcard/android/layout_tests/fast/css/small-caps-crash.html
-/sdcard/android/layout_tests/fast/css/max-height-and-max-width.html
-/sdcard/android/layout_tests/fast/css/legacy-opacity-styles.html
-/sdcard/android/layout_tests/fast/css/transition-timing-function.html
-/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-4.html
-/sdcard/android/layout_tests/fast/block/float/selection-gap-clip-out-tiger-crash.html
-/sdcard/android/layout_tests/fast/block/float/crash-on-absolute-positioning.html
-/sdcard/android/layout_tests/fast/block/float/crash-replaced-display-block.html
-/sdcard/android/layout_tests/fast/parser/implicit-head-in-fragment-crash.html
-/sdcard/android/layout_tests/fast/parser/smart-quotes-in-tag.html
-/sdcard/android/layout_tests/fast/parser/entity-comment-in-iframe.html
-/sdcard/android/layout_tests/fast/parser/remove-node-stack.html
-/sdcard/android/layout_tests/fast/parser/remove-current-node-parent.html
-/sdcard/android/layout_tests/fast/parser/entity-end-iframe-tag.html
-/sdcard/android/layout_tests/fast/parser/nsup-entity.html
-/sdcard/android/layout_tests/fast/parser/block-nesting-cap.html
-/sdcard/android/layout_tests/fast/parser/residual-style-close-across-n-blocks.html
-/sdcard/android/layout_tests/fast/parser/tag-with-exclamation-point.html
-/sdcard/android/layout_tests/fast/parser/p-in-scope-strict.html
-/sdcard/android/layout_tests/fast/parser/entity-end-style-tag.html
-/sdcard/android/layout_tests/fast/parser/entity-end-xmp-tag.html
-/sdcard/android/layout_tests/fast/parser/external-entities.xml
-/sdcard/android/layout_tests/fast/parser/head-comment.html
-/sdcard/android/layout_tests/fast/parser/test-unicode-characters-in-attribute-name.html
-/sdcard/android/layout_tests/fast/parser/entity-end-textarea-tag.html
-/sdcard/android/layout_tests/fast/parser/script-tag-with-trailing-slash.html
-/sdcard/android/layout_tests/fast/parser/empty-text-resource.html
-/sdcard/android/layout_tests/fast/parser/comment-in-title.html
-/sdcard/android/layout_tests/fast/parser/residual-style-close-across-removed-block.html
-/sdcard/android/layout_tests/fast/parser/entity-comment-in-title.html
-/sdcard/android/layout_tests/fast/parser/entity-end-title-tag.html
-/sdcard/android/layout_tests/fast/parser/head-content-after-head-removal.html
-/sdcard/android/layout_tests/fast/parser/pre-first-line-break.html
-/sdcard/android/layout_tests/fast/parser/number-sign-in-map-name.html
-/sdcard/android/layout_tests/fast/parser/input-textarea-inside-select-element.html
-/sdcard/android/layout_tests/fast/parser/entity-end-script-tag.html
-/sdcard/android/layout_tests/fast/parser/area-in-div.html
-/sdcard/android/layout_tests/fast/parser/entity-surrogate-pairs.html
-/sdcard/android/layout_tests/fast/parser/eightdigithexentity.html
-/sdcard/android/layout_tests/fast/parser/parse-wbr.html
-/sdcard/android/layout_tests/fast/parser/open-comment-in-script-tricky.html
-/sdcard/android/layout_tests/fast/parser/head-element-for-yahoo-player.html
-/sdcard/android/layout_tests/fast/parser/hex-entities-length.html
-/sdcard/android/layout_tests/fast/parser/html-whitespace.html
-/sdcard/android/layout_tests/fast/parser/script-after-frameset-assert.html
-/sdcard/android/layout_tests/fast/parser/comment-in-iframe.html
-/sdcard/android/layout_tests/fast/parser/duplicate-html-body-element-IDs.html
-/sdcard/android/layout_tests/fast/parser/assertion-empty-attribute.html
-/sdcard/android/layout_tests/fast/parser/comment-in-script-tricky.html
-/sdcard/android/layout_tests/fast/parser/rewrite-form.html
-/sdcard/android/layout_tests/fast/parser/entity-comment-in-script-tricky.html
-/sdcard/android/layout_tests/fast/parser/head-parsing-19517.html
-/sdcard/android/layout_tests/fast/parser/entities-in-html.html
-/sdcard/android/layout_tests/fast/parser/remove-parser-current-node.html
-/sdcard/android/layout_tests/fast/parser/rewrite-map.html
-/sdcard/android/layout_tests/fast/parser/strict-img-in-map.html
-/sdcard/android/layout_tests/fast/parser/p-in-scope.html
-/sdcard/android/layout_tests/fast/layers/removed-by-scroll-handler.html
-/sdcard/android/layout_tests/fast/layers/generated-layer-scrollbar-crash.html
-/sdcard/android/layout_tests/fast/layers/zindex-hit-test.html
-/sdcard/android/layout_tests/fast/layers/resize-layer-deletion-crash.html
-/sdcard/android/layout_tests/fast/history/subframe-is-visited.html
-/sdcard/android/layout_tests/fast/loader/early-load-cancel.html
-/sdcard/android/layout_tests/fast/loader/iframe-recursive-synchronous-load.html
-/sdcard/android/layout_tests/fast/loader/local-css-allowed-in-strict-mode.html
-/sdcard/android/layout_tests/fast/loader/url-strip-cr-lf-tab.html
-/sdcard/android/layout_tests/fast/loader/hashchange-event.html
-/sdcard/android/layout_tests/fast/loader/unloadable-script.html
-/sdcard/android/layout_tests/fast/loader/url-parse-1.html
-/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe-2.html
-/sdcard/android/layout_tests/fast/loader/simultaneous-reloads-assert.html
-/sdcard/android/layout_tests/fast/loader/invalid-charset-on-script-crashes-loader.html
-/sdcard/android/layout_tests/fast/loader/javascript-url-encoding.html
-/sdcard/android/layout_tests/fast/loader/empty-embed-src-attribute.html
-/sdcard/android/layout_tests/fast/loader/charset-parse.html
-/sdcard/android/layout_tests/fast/loader/meta-refresh-vs-open.html
-/sdcard/android/layout_tests/fast/loader/submit-form-while-parsing-2.html
-/sdcard/android/layout_tests/fast/loader/url-data-replace-backslash.html
-/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe.html
-/sdcard/android/layout_tests/fast/loader/empty-ref-versus-no-ref.html
-/sdcard/android/layout_tests/fast/loader/javascript-url-encoding-2.html
-/sdcard/android/layout_tests/fast/loader/window-clearing.html
-/sdcard/android/layout_tests/fast/loader/frame-creation-removal.html
-/sdcard/android/layout_tests/fast/loader/external-script-URL-location.html
-/sdcard/android/layout_tests/fast/loader/link-no-URL.html
-/sdcard/android/layout_tests/fast/loader/loadInProgress.html
-/sdcard/android/layout_tests/fast/loader/inherit-charset-to-empty-frame.html
-/sdcard/android/layout_tests/fast/loader/font-face-empty.html
-/sdcard/android/layout_tests/fast/loader/goto-anchor-infinite-layout.html
-/sdcard/android/layout_tests/fast/loader/file-URL-with-port-number.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-default-attributes.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-missing-file-exception.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-invalid-values.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-html-response-encoding.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/null-document-xmlhttprequest-open.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-nonexistent-file.html
-/sdcard/android/layout_tests/fast/xmlhttprequest/xmlhttprequest-open-after-iframe-onload-remove-self.html
-/sdcard/android/layout_tests/fast/canvas/pattern-with-transform.html
-/sdcard/android/layout_tests/fast/canvas/gradient-addColorStop-with-invalid-color.html
-/sdcard/android/layout_tests/fast/canvas/canvas-gradient-without-path.html
-/sdcard/android/layout_tests/fast/canvas/radialGradient-infinite-values.html
-/sdcard/android/layout_tests/fast/canvas/drawImage-with-negative-source-destination.html
-/sdcard/android/layout_tests/fast/canvas/drawImage-with-invalid-args.html
-/sdcard/android/layout_tests/fast/canvas/canvas-stroke-empty-fill.html
-/sdcard/android/layout_tests/fast/canvas/canvas-lineWidth.html
-/sdcard/android/layout_tests/fast/canvas/access-zero-sized-canvas.html
-/sdcard/android/layout_tests/fast/canvas/script-inside-canvas-fallback.html
-/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-2.html
-/sdcard/android/layout_tests/fast/canvas/create-pattern-does-not-crash.html
-/sdcard/android/layout_tests/fast/canvas/gradient-with-clip.html
-/sdcard/android/layout_tests/fast/canvas/canvas-hides-fallback.html
-/sdcard/android/layout_tests/fast/canvas/arc-crash.html
-/sdcard/android/layout_tests/fast/canvas/canvas-modify-emptyPath.html
-/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-4.html
-/sdcard/android/layout_tests/fast/canvas/canvas-invalid-fillstyle.html
-/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-1.html
-/sdcard/android/layout_tests/fast/canvas/toDataURL-noData.html
-/sdcard/android/layout_tests/fast/canvas/canvas-with-incorrect-args.html
-/sdcard/android/layout_tests/fast/canvas/canvas-path-with-inf-nan-dimensions.html
-/sdcard/android/layout_tests/fast/canvas/canvas-radial-gradient-spreadMethod.html
-/sdcard/android/layout_tests/fast/canvas/canvas-set-properties-with-non-invertible-ctm.html
-/sdcard/android/layout_tests/fast/canvas/canvas-invalid-strokestyle.html
-/sdcard/android/layout_tests/fast/canvas/canvas-strokeRect.html
-/sdcard/android/layout_tests/fast/canvas/canvas-composite-alpha.html
-/sdcard/android/layout_tests/fast/canvas/canvas-transparency-and-composite.html
-/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-3.html
-/sdcard/android/layout_tests/fast/canvas/linearGradient-infinite-values.html
-/sdcard/android/layout_tests/fast/canvas/canvas-setTransform.html
-/sdcard/android/layout_tests/fast/frames/frame-set-same-location.html
-/sdcard/android/layout_tests/fast/frames/viewsource-unfinished-tags.html
-/sdcard/android/layout_tests/fast/frames/set-unloaded-frame-location.html
-/sdcard/android/layout_tests/fast/frames/negative-remaining-length-crash.html
-/sdcard/android/layout_tests/fast/frames/frame-name-reset.html
-/sdcard/android/layout_tests/fast/frames/frame-set-same-src.html
-/sdcard/android/layout_tests/fast/frames/crash-removed-iframe.html
-/sdcard/android/layout_tests/fast/frames/empty-frame-document.html
-/sdcard/android/layout_tests/fast/frames/viewsource-plain-text-tags.html
-/sdcard/android/layout_tests/fast/frames/repaint-display-none-crash.html
-/sdcard/android/layout_tests/fast/frames/remove-frame-with-scrollbars-crash.html
-/sdcard/android/layout_tests/fast/frames/cross-site-this.html
-/sdcard/android/layout_tests/fast/frames/onload-remove-iframe-crash.html
-/sdcard/android/layout_tests/fast/frames/iframe-set-inner-html.html
-/sdcard/android/layout_tests/fast/frames/iframe-remove-after-id-change.html
-/sdcard/android/layout_tests/fast/frames/iframe-target.html
-/sdcard/android/layout_tests/fast/frames/viewsource-link-on-href-value.html
-/sdcard/android/layout_tests/fast/frames/hover-timer-crash.html
-/sdcard/android/layout_tests/fast/frames/iframe-no-src-set-location.html
-/sdcard/android/layout_tests/fast/frames/iframe-set-same-src.html
-/sdcard/android/layout_tests/fast/frames/iframe-double-attach.html
-/sdcard/android/layout_tests/fast/frames/iframe-set-same-location.html
-/sdcard/android/layout_tests/fast/frames/location-change.html
-/sdcard/android/layout_tests/fast/frames/frame-base-url.html
-/sdcard/android/layout_tests/fast/frames/iframe-display-none.html
-/sdcard/android/layout_tests/fast/frames/javascript-url-as-framesrc-crash.html
-/sdcard/android/layout_tests/fast/frames/frame-limit.html
-/sdcard/android/layout_tests/fast/frames/frame-display-none-focus.html
-/sdcard/android/layout_tests/fast/reflections/teardown-crash.html
-/sdcard/android/layout_tests/fast/reflections/reflection-computed-style.html
-/sdcard/android/layout_tests/fast/reflections/reflection-overflow-scroll.html
-/sdcard/android/layout_tests/http/tests/multipart/win-boundary-crash.html
-/sdcard/android/layout_tests/http/tests/multipart/stop-crash.html
-/sdcard/android/layout_tests/http/tests/mime/standard-mode-loads-stylesheet-with-text-css-and-invalid-type.html
-/sdcard/android/layout_tests/http/tests/mime/standard-mode-loads-stylesheet-with-empty-content-type.html
-/sdcard/android/layout_tests/http/tests/mime/standard-mode-loads-stylesheet-with-charset-and-css-extension.html
-/sdcard/android/layout_tests/http/tests/mime/standard-mode-loads-stylesheet-with-charset.html
-/sdcard/android/layout_tests/http/tests/local/style-access-before-stylesheet-loaded.html
-/sdcard/android/layout_tests/http/tests/local/stylesheet-and-script-load-order-http.html
-/sdcard/android/layout_tests/http/tests/local/link-stylesheet-preferred.html
-/sdcard/android/layout_tests/http/tests/local/stylesheet-and-script-load-order.html
-/sdcard/android/layout_tests/http/tests/misc/uncacheable-script-repeated.html
-/sdcard/android/layout_tests/http/tests/misc/embedCrasher.html
-/sdcard/android/layout_tests/http/tests/misc/multiple-submit.html
-/sdcard/android/layout_tests/http/tests/misc/empty-file-formdata.html
-/sdcard/android/layout_tests/http/tests/misc/submit-post-in-utf7.html
-/sdcard/android/layout_tests/http/tests/misc/text-refresh.html
-/sdcard/android/layout_tests/http/tests/misc/window-open-then-write.html
-/sdcard/android/layout_tests/http/tests/misc/submit-post-in-utf16be.html
-/sdcard/android/layout_tests/http/tests/misc/frame-default-enc-same-domain.html
-/sdcard/android/layout_tests/http/tests/misc/submit-post-in-utf32le.html
-/sdcard/android/layout_tests/http/tests/misc/iframe-domain-test.html
-/sdcard/android/layout_tests/http/tests/misc/frame-default-enc-different-domain.html
-/sdcard/android/layout_tests/http/tests/misc/css-accept-any-type.html
-/sdcard/android/layout_tests/http/tests/misc/url-in-utf7.html
-/sdcard/android/layout_tests/http/tests/misc/submit-get-in-utf32be.html
-/sdcard/android/layout_tests/http/tests/misc/meta-refresh-stray-single-quote.html
-/sdcard/android/layout_tests/http/tests/misc/canvas-pattern-from-incremental-image.html
-/sdcard/android/layout_tests/http/tests/misc/submit-get-in-utf16le.html
-/sdcard/android/layout_tests/http/tests/misc/url-in-utf32be.html
-/sdcard/android/layout_tests/http/tests/misc/timer-vs-loading.html
-/sdcard/android/layout_tests/http/tests/misc/font-face-in-multiple-segmented-faces.html
-/sdcard/android/layout_tests/http/tests/misc/url-in-utf16le.html
-/sdcard/android/layout_tests/http/tests/misc/refresh-meta-with-newline.html
-/sdcard/android/layout_tests/http/tests/misc/post-submit-button.html
-/sdcard/android/layout_tests/http/tests/misc/redirect-to-about-blank.html
-/sdcard/android/layout_tests/http/tests/misc/javascript-url-stop-loaders.html
-/sdcard/android/layout_tests/http/tests/misc/iframe-invalid-source-crash.html
-/sdcard/android/layout_tests/http/tests/misc/slow-preload-cancel.html
-/sdcard/android/layout_tests/http/tests/misc/object-image-error-with-onload.html
-/sdcard/android/layout_tests/http/tests/misc/image-error.html
-/sdcard/android/layout_tests/http/tests/misc/referrer.html
-/sdcard/android/layout_tests/http/tests/misc/cached-scripts.html
-/sdcard/android/layout_tests/http/tests/misc/empty-cookie.html
-/sdcard/android/layout_tests/http/tests/misc/submit-post-in-utf32be.html
-/sdcard/android/layout_tests/http/tests/misc/missing-style-sheet.html
-/sdcard/android/layout_tests/http/tests/misc/submit-post-in-utf16le.html
-/sdcard/android/layout_tests/http/tests/misc/submit-get-in-utf16be.html
-/sdcard/android/layout_tests/http/tests/misc/DOMContentLoaded-event.html
-/sdcard/android/layout_tests/http/tests/misc/onload-remove-iframe-crash-2.html
-/sdcard/android/layout_tests/http/tests/misc/submit-get-in-utf32le.html
-/sdcard/android/layout_tests/http/tests/misc/object-image-error.html
-/sdcard/android/layout_tests/http/tests/misc/createElementNamespace3.html
-/sdcard/android/layout_tests/http/tests/misc/url-in-utf16be.html
-/sdcard/android/layout_tests/http/tests/misc/url-in-utf32le.html
-/sdcard/android/layout_tests/http/tests/misc/crash-multiple-family-fontface.html
-/sdcard/android/layout_tests/http/tests/misc/BOM-override-script.html
-/sdcard/android/layout_tests/http/tests/misc/createElementNamespace1.xml
-/sdcard/android/layout_tests/http/tests/workers/text-encoding.html
-/sdcard/android/layout_tests/http/tests/workers/worker-redirect.html
-/sdcard/android/layout_tests/http/tests/workers/worker-importScripts.html
-/sdcard/android/layout_tests/http/tests/cookies/double-quoted-value-with-semi-colon.html
-/sdcard/android/layout_tests/http/tests/uri/resolve-encoding-relative.html
-/sdcard/android/layout_tests/http/tests/uri/escaped-entity.html
-/sdcard/android/layout_tests/http/tests/uri/utf8-path.html
-/sdcard/android/layout_tests/http/tests/navigation/changing-frame-hierarchy-in-onload.html
-/sdcard/android/layout_tests/http/tests/navigation/fallback-anchor-reload.html
-/sdcard/android/layout_tests/http/tests/navigation/back-send-referrer.html
-/sdcard/android/layout_tests/http/tests/incremental/slow-utf8-css.html
-/sdcard/android/layout_tests/http/tests/incremental/frame-focus-before-load.html
-/sdcard/android/layout_tests/http/tests/appcache/crash-when-navigating-away-then-back.html
-/sdcard/android/layout_tests/http/tests/appcache/offline-access.html
-/sdcard/android/layout_tests/http/tests/appcache/update-cache.html
-/sdcard/android/layout_tests/http/tests/appcache/manifest-with-empty-file.html
-/sdcard/android/layout_tests/http/tests/appcache/simple.html
-/sdcard/android/layout_tests/http/tests/appcache/wrong-signature-2.html
-/sdcard/android/layout_tests/http/tests/appcache/top-frame-3.html
-/sdcard/android/layout_tests/http/tests/appcache/online-whitelist.html
-/sdcard/android/layout_tests/http/tests/appcache/fallback.html
-/sdcard/android/layout_tests/http/tests/appcache/different-origin-manifest.html
-/sdcard/android/layout_tests/http/tests/appcache/empty-manifest.html
-/sdcard/android/layout_tests/http/tests/appcache/manifest-redirect.html
-/sdcard/android/layout_tests/http/tests/appcache/navigating-away-while-cache-attempt-in-progress.html
-/sdcard/android/layout_tests/http/tests/appcache/top-frame-4.html
-/sdcard/android/layout_tests/http/tests/appcache/wrong-signature.html
-/sdcard/android/layout_tests/http/tests/appcache/fail-on-update.html
-/sdcard/android/layout_tests/http/tests/appcache/foreign-iframe-main.html
-/sdcard/android/layout_tests/http/tests/appcache/xhr-foreign-resource.html
-/sdcard/android/layout_tests/http/tests/appcache/manifest-containing-itself.html
-/sdcard/android/layout_tests/http/tests/appcache/resource-redirect.html
-/sdcard/android/layout_tests/http/tests/appcache/idempotent-update.html
-/sdcard/android/layout_tests/http/tests/appcache/top-frame-1.html
-/sdcard/android/layout_tests/http/tests/appcache/main-resource-hash.html
-/sdcard/android/layout_tests/http/tests/appcache/manifest-parsing.html
-/sdcard/android/layout_tests/http/tests/appcache/404-manifest.html
-/sdcard/android/layout_tests/http/tests/appcache/wrong-content-type.html
-/sdcard/android/layout_tests/http/tests/appcache/resource-redirect-2.html
-/sdcard/android/layout_tests/http/tests/appcache/top-frame-2.html
-/sdcard/android/layout_tests/http/tests/appcache/404-resource.html
-/sdcard/android/layout_tests/http/tests/appcache/remove-cache.html
-/sdcard/android/layout_tests/http/tests/appcache/manifest-redirect-2.html
-/sdcard/android/layout_tests/http/tests/appcache/reload.html
-/sdcard/android/layout_tests/http/tests/appcache/cyrillic-uri.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-alias.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-write.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-grandchildren-alias.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-with-base-tag.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/window-open-self-about-blank.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-grandchildren.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-grandchildren-writeln-lexical.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-window-open.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-grandchildren-write-lexical.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-grandchildren-lexical.html
-/sdcard/android/layout_tests/http/tests/security/aboutBlank/security-context-writeln.html
-/sdcard/android/layout_tests/http/tests/security/cookies/document-open.html
-/sdcard/android/layout_tests/http/tests/security/cookies/create-document.html
-/sdcard/android/layout_tests/http/tests/security/cookies/assign-document-url.html
-/sdcard/android/layout_tests/http/tests/security/cookies/basic.html
-/sdcard/android/layout_tests/http/tests/security/cookies/base-tag.html
-/sdcard/android/layout_tests/http/tests/security/cookies/base-about-blank.html
-/sdcard/android/layout_tests/http/tests/security/cookies/xmlhttprequest.html
-/sdcard/android/layout_tests/http/tests/security/listener/xss-JSTargetNode-onclick-shortcut.html
-/sdcard/android/layout_tests/http/tests/security/listener/xss-XMLHttpRequest-shortcut.html
-/sdcard/android/layout_tests/http/tests/security/listener/xss-JSTargetNode-onclick-addEventListener.html
-/sdcard/android/layout_tests/http/tests/security/listener/xss-XMLHttpRequest-addEventListener.html
-/sdcard/android/layout_tests/http/tests/security/MessagePort/event-listener-context.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/delivery-order.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/data-url-sends-null-origin.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/origin-unaffected-by-base-tag.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/origin-unaffected-by-document-domain.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/javascript-page-still-sends-origin.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/invalid-origin-throws-exception.html
-/sdcard/android/layout_tests/http/tests/security/postMessage/target-origin.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/context-for-window-open.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/context-for-location.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/not-opener.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/opener.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/context-for-location-assign.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/context-for-location-href.html
-/sdcard/android/layout_tests/http/tests/security/frameNavigation/xss-ALLOWED-parent-navigation-change.html
-/sdcard/android/layout_tests/http/tests/security/originHeader/origin-header-for-get.html
-/sdcard/android/layout_tests/http/tests/security/originHeader/origin-header-for-https.html
-/sdcard/android/layout_tests/http/tests/security/originHeader/origin-header-for-post.html
-/sdcard/android/layout_tests/http/tests/security/originHeader/origin-header-for-data.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-hash.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-history-prototype.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-synchronous-form.html
-/sdcard/android/layout_tests/http/tests/security/canvas-remote-read-redirect-to-remote-image.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-nonstandardProperty.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-pathname.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-frames.html
-/sdcard/android/layout_tests/http/tests/security/object-literals.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-location-prototype.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-search.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-selection.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-name-getter.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-call.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-reload.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-invalid-domain-change.html
-/sdcard/android/layout_tests/http/tests/security/canvas-remote-read-remote-image.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-protocol.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-first-time.html
-/sdcard/android/layout_tests/http/tests/security/xss-eval.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-DOMImplementation.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-hostname.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-custom.html
-/sdcard/android/layout_tests/http/tests/security/xss-DENIED-assign-location-host.html
-/sdcard/android/layout_tests/http/tests/security/cross-frame-access-callback-explicit-domain-ALLOW.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/workers/xmlhttprequest-file-not-found.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/workers/abort-exception-assert.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/workers/close.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/010.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/002.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/012.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/004.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/014.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/018.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/002-simple.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/001.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/011.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/003.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/013.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/005.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/015.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/web-apps/007.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cross-site-denied-response.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/encode-request-url.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-non-simple-allow.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-preflight-cache.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/inject-header.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-LSProgressEvent-ProgressEvent-should-match.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-same-origin-post-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-denied.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-InvalidStateException-getAllRequestHeaders.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/binary-x-user-defined.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/onloadstart-event.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-no-content-length-onProgress.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/readystatechange.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-contenttype-empty.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-post-fail-non-simple-content-type.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-forbidden-methods-exception.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-preflight-cache-invalidation-by-method.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/serialize-document.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/onerror-event.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/close-window.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin-post-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/detaching-frame-2.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/encode-request-url-2.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/set-dangerous-headers.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/event-target.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-addEventListener-onProgress.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/send-on-abort.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/document-domain-set.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-preflight-cache-timeout.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-responseXML-exception.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cross-site-denied-response-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/upload-onloadstart-event.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/supported-xml-content-types.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/simple-cross-origin-denied-events.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/request-encoding.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/zero-length-response.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/connection-error-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-access-control-origin-header-data-url.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-preflight-cache-invalidation-by-header.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-star.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-crlf-getAllResponseHeader.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/event-listener-gc.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/interactive-state.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/state-after-network-error.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/abort-crash.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/get-dangerous-headers.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-image-not-loaded.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/exceptions.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-test-send-flag.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-cross-origin-post-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/referer.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-invalidHeader-getRequestHeader.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/infoOnProgressEvent.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-allow-access-control-origin-header.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/docLoaderFrame.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/post-content-type.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-whitelist-response-headers.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/onabort-event.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-same-origin-get-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/detaching-frame.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-get-fail-non-simple.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/zero-length-response-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/access-control-basic-denied-preflight-cache.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/authorization-header.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-post-crash.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-cross-origin-get-async.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin-sync-double.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-abort-readyState-shouldDispatchEvent.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-responseText-exception.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin-2.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-abort-readyState-shouldNotDispatchEvent.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/status-after-abort.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/XMLHttpRequestException.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-onProgress-open-should-zero-length.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/broken-xml-encoding.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/extra-parameters.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-multiple-open.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/xmlhttprequest-InvalidStateException-getRequestHeader.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/origin-header-same-origin-post-sync.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/cross-site-denied-response-sync-2.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/request-from-popup.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/redirect-cross-origin-post.html
-/sdcard/android/layout_tests/http/tests/xmlhttprequest/simple-cross-origin-progress-events.html
-/sdcard/android/layout_tests/http/tests/messaging/cross-domain-message-event-dispatch.html
-/sdcard/android/layout_tests/http/tests/messaging/cross-domain-message-send.html
-/sdcard/android/layout_tests/media/constructors.html
-/sdcard/android/layout_tests/media/video-poster.html
-/sdcard/android/layout_tests/media/video-source-media.html
-/sdcard/android/layout_tests/media/video-controls-with-mutation-event-handler.html
-/sdcard/android/layout_tests/media/video-src-set.html
-/sdcard/android/layout_tests/media/video-display-none-crash.html
-/sdcard/android/layout_tests/media/video-width-height.html
-/sdcard/android/layout_tests/media/video-source.html
-/sdcard/android/layout_tests/media/fallback.html
-/sdcard/android/layout_tests/media/remove-from-document-no-load.html
-/sdcard/android/layout_tests/media/before-load-member-access.html
-/sdcard/android/layout_tests/media/video-play-pause-events.html
-/sdcard/android/layout_tests/media/media-constants.html
-/sdcard/android/layout_tests/media/video-src-source.html
-/sdcard/android/layout_tests/media/video-play-pause-exception.html
-/sdcard/android/layout_tests/media/video-dom-autobuffer.html
-/sdcard/android/layout_tests/media/video-seek-no-src-exception.html
-/sdcard/android/layout_tests/media/video-src.html
-/sdcard/android/layout_tests/plugins/createScriptableObject-before-start.html
-/sdcard/android/layout_tests/plugins/return-error-from-new-stream-callback-in-full-frame-plugin.html
-/sdcard/android/layout_tests/scrollbars/scrollbar-crash-on-refresh.html
-/sdcard/android/layout_tests/scrollbars/scrollbar-miss-mousemove.html
-/sdcard/android/layout_tests/security/autocomplete-cleared-on-back.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/complex-keys.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/clear.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/enumerate-storage.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/remove-item.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/string-conversion.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/simple-events.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/delete-removal.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/window-open.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/index-get-and-set.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/onstorage-attribute-setattribute.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/onstorage-attribute-setwindow.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/simple-usage.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/onstorage-attribute-markup.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/enumerate-with-length-and-key.html
-/sdcard/android/layout_tests/storage/domstorage/localstorage/complex-values.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/index-get-and-set.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/onstorage-attribute-setattribute.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/onstorage-attribute-setwindow.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/clear.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/enumerate-storage.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/string-conversion.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/simple-usage.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/simple-events.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/onstorage-attribute-markup.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/enumerate-with-length-and-key.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/delete-removal.html
-/sdcard/android/layout_tests/storage/domstorage/sessionstorage/window-open.html
-/sdcard/android/layout_tests/storage/domstorage/window-attributes-exist.html
-/sdcard/android/layout_tests/storage/hash-change-with-xhr.html
-/sdcard/android/layout_tests/storage/open-database-empty-version.html
-/sdcard/android/layout_tests/storage/quota-tracking.html
-/sdcard/android/layout_tests/storage/close-during-stress-test.html
-/sdcard/android/layout_tests/storage/database-lock-after-reload.html
-/sdcard/android/layout_tests/storage/multiple-databases-garbage-collection.html
-/sdcard/android/layout_tests/storage/empty-statement.html
-/sdcard/android/layout_tests/storage/multiple-transactions.html
-/sdcard/android/layout_tests/storage/success-callback.html
-/sdcard/android/layout_tests/storage/transaction-error-callback.html
-/sdcard/android/layout_tests/storage/sql-data-types.html
-/sdcard/android/layout_tests/storage/transaction-callback-exception-crash.html
-/sdcard/android/layout_tests/transforms/2d/transform-2d.html
-/sdcard/android/layout_tests/transforms/2d/compound-2d-transforms.html
-/sdcard/android/layout_tests/transforms/2d/computed-style-origin.html
-/sdcard/android/layout_tests/transforms/2d/transform-accuracy.html
-/sdcard/android/layout_tests/transforms/2d/transform-value-types.html
-/sdcard/android/layout_tests/transforms/3d/hit-testing/hit-preserves-3d.html
-/sdcard/android/layout_tests/transitions/cancel-transition.html
-/sdcard/android/layout_tests/transitions/transition-end-event-all-properties.html
-/sdcard/android/layout_tests/transitions/transition-end-event-window.html
-/sdcard/android/layout_tests/transitions/transition-end-event-multiple-03.html
-/sdcard/android/layout_tests/transitions/text-indent-transition.html
-/sdcard/android/layout_tests/transitions/transition-end-event-set-none.html
-/sdcard/android/layout_tests/transitions/zero-duration-without-units.html
-/sdcard/android/layout_tests/transitions/min-max-width-height-transitions.html
-/sdcard/android/layout_tests/transitions/shorthand-transitions.html
-/sdcard/android/layout_tests/transitions/mask-transitions.html
-/sdcard/android/layout_tests/transitions/zero-duration-with-non-zero-delay-start.html
-/sdcard/android/layout_tests/transitions/zero-duration-in-list.html
-/sdcard/android/layout_tests/transitions/shorthand-border-transitions.html
-/sdcard/android/layout_tests/transitions/inherit-other-props.html
-/sdcard/android/layout_tests/transitions/transition-end-event-multiple-04.html
-/sdcard/android/layout_tests/transitions/background-transitions.html
-/sdcard/android/layout_tests/transitions/transition-duration-cleared-in-transitionend-crash.html
-/sdcard/android/layout_tests/transitions/interrupt-zero-duration.html
-/sdcard/android/layout_tests/transitions/retargetted-transition.html
-/sdcard/android/layout_tests/transitions/transition-end-event-left.html
-/sdcard/android/layout_tests/transitions/override-transition-crash.html
-/sdcard/android/layout_tests/transitions/transition-end-event-multiple-01.html
-/sdcard/android/layout_tests/transitions/matched-transform-functions.html
-/sdcard/android/layout_tests/transitions/transform-op-list-match.html
-/sdcard/android/layout_tests/transitions/transition-end-event-container.html
-/sdcard/android/layout_tests/transitions/interrupt-transform-transition.html
-/sdcard/android/layout_tests/transitions/transition-end-event-nested.html
-/sdcard/android/layout_tests/transitions/change-values-during-transition.html
-/sdcard/android/layout_tests/transitions/transition-end-event-attributes.html
-/sdcard/android/layout_tests/transitions/inherit.html
-/sdcard/android/layout_tests/transitions/transition-end-event-create.html
-/sdcard/android/layout_tests/transitions/shadow.html
-/sdcard/android/layout_tests/transitions/transition-end-event-multiple-02.html
-/sdcard/android/layout_tests/transitions/transition-end-event-transform.html
-/sdcard/android/layout_tests/transitions/start-transform-transition.html
-/sdcard/android/layout_tests/transitions/transition-timing-function.html
-/sdcard/android/layout_tests/transitions/transform-op-list-no-match.html
-/sdcard/android/layout_tests/transitions/bad-transition-shorthand-crash.html
-/sdcard/android/layout_tests/transitions/transition-end-event-destroy-renderer.html
-/sdcard/android/layout_tests/transitions/extra-transition.html
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/010.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/001.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/002.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/003.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/004.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/005.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/006.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/007.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/008.xml
-/sdcard/android/layout_tests/traversal/hixie-node-iterator/009.xml
-/sdcard/android/layout_tests/traversal/node-iterator-003.html
-/sdcard/android/layout_tests/traversal/node-iterator-005.html
-/sdcard/android/layout_tests/traversal/node-iterator-007.html
-/sdcard/android/layout_tests/traversal/tree-walker-001.html
-/sdcard/android/layout_tests/traversal/node-iterator-009.html
-/sdcard/android/layout_tests/traversal/tree-walker-003.html
-/sdcard/android/layout_tests/traversal/tree-walker-005.html
-/sdcard/android/layout_tests/traversal/exception-forwarding.html
-/sdcard/android/layout_tests/traversal/stay-within-root.html
-/sdcard/android/layout_tests/traversal/node-iterator-002.html
-/sdcard/android/layout_tests/traversal/node-iterator-004.html
-/sdcard/android/layout_tests/traversal/node-iterator-006.html
-/sdcard/android/layout_tests/traversal/node-iterator-006a.html
-/sdcard/android/layout_tests/traversal/tree-walker-002.html
-/sdcard/android/layout_tests/traversal/node-iterator-008.html
-/sdcard/android/layout_tests/traversal/tree-walker-004.html
-/sdcard/android/layout_tests/traversal/tree-walker-006.html
-/sdcard/android/layout_tests/traversal/size-zero-run.html
-/sdcard/android/layout_tests/traversal/acid3-test-2.html
-/sdcard/android/layout_tests/traversal/tree-walker-filter-1.html
-/sdcard/android/layout_tests/traversal/node-iterator-001.html
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
deleted file mode 100755
index 21c02ec..0000000
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ /dev/null
@@ -1,320 +0,0 @@
-#!/usr/bin/python
-
-"""Run layout tests using Android emulator and instrumentation.
-
-  First, you need to get an SD card or sdcard image that has layout tests on it.
-  Layout tests are in following directory:
-    /sdcard/webkit/layout_tests
-  For example, /sdcard/webkit/layout_tests/fast
-
-  Usage:
-    Run all tests under fast/ directory:
-      run_layout_tests.py, or
-      run_layout_tests.py fast
-
-    Run all tests under a sub directory:
-      run_layout_tests.py fast/dom
-
-    Run a single test:
-      run_layout_tests.py fast/dom/
-
-  After a merge, if there are changes of layout tests in SD card, you need to
-  use --refresh-test-list option *once* to re-generate test list on the card.
-
-  Some other options are:
-    --rebaseline generates expected layout tests results under /sdcard/webkit/expected_result/
-    --time-out-ms (default is 8000 millis) for each test
-    --adb-options="-e" passes option string to adb
-    --results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
-    --js-engine the JavaScript engine currently in use, determines which set of Android-specific expected results we should use, should be 'jsc' or 'v8'
-"""
-
-import logging
-import optparse
-import os
-import subprocess
-import sys
-import time
-
-def CountLineNumber(filename):
-  """Compute the number of lines in a given file.
-
-  Args:
-    filename: a file name related to the current directory.
-  """
-
-  fp = open(os.path.abspath(filename), "r");
-  lines = 0
-  for line in fp.readlines():
-    lines = lines + 1
-  fp.close()
-  return lines
-
-def DumpRenderTreeFinished(adb_cmd):
-  """ Check if DumpRenderTree finished running tests
-
-  Args:
-    output: adb_cmd string
-  """
-
-  # pull /sdcard/webkit/running_test.txt, if the content is "#DONE", it's done
-  shell_cmd_str = adb_cmd + " shell cat /sdcard/webkit/running_test.txt"
-  adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
-  return adb_output.strip() == "#DONE"
-
-def DiffResults(marker, new_results, old_results, diff_results, strip_reason,
-                new_count_first=True):
-   """ Given two result files, generate diff and
-       write to diff_results file. All arguments are absolute paths
-       to files.
-   """
-   old_file = open(old_results, "r")
-   new_file = open(new_results, "r")
-   diff_file = open(diff_results, "a")
-
-   # Read lines from each file
-   ndict = new_file.readlines()
-   cdict = old_file.readlines()
-
-   # Write marker to diff file
-   diff_file.writelines(marker + "\n")
-   diff_file.writelines("###############\n")
-
-   # Strip reason from result lines
-   if strip_reason is True:
-     for i in range(0, len(ndict)):
-       ndict[i] = ndict[i].split(' ')[0] + "\n"
-     for i in range(0, len(cdict)):
-       cdict[i] = cdict[i].split(' ')[0] + "\n"
-
-   params = {
-       "new": [0, ndict, cdict, "+"],
-       "miss": [0, cdict, ndict, "-"]
-       }
-   if new_count_first:
-     order = ["new", "miss"]
-   else:
-     order = ["miss", "new"]
-
-   for key in order:
-     for line in params[key][1]:
-       if line not in params[key][2]:
-         if line[-1] != "\n":
-           line += "\n";
-         diff_file.writelines(params[key][3] + line)
-         params[key][0] += 1
-
-   logging.info(marker + "  >>> " + str(params["new"][0]) + " new, " +
-                str(params["miss"][0]) + " misses")
-
-   diff_file.writelines("\n\n")
-
-   old_file.close()
-   new_file.close()
-   diff_file.close()
-   return
-
-def CompareResults(ref_dir, results_dir):
-  """Compare results in two directories
-
-  Args:
-    ref_dir: the reference directory having layout results as references
-    results_dir: the results directory
-  """
-  logging.info("Comparing results to " + ref_dir)
-
-  diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
-  if os.path.exists(diff_result):
-    os.remove(diff_result)
-
-  files=["crashed", "failed", "passed", "nontext"]
-  for f in files:
-    result_file_name = "layout_tests_" + f + ".txt"
-    DiffResults(f, os.path.join(results_dir, result_file_name),
-                os.path.join(ref_dir, result_file_name), diff_result,
-                False, f != "passed")
-  logging.info("Detailed diffs are in " + diff_result)
-
-def main(options, args):
-  """Run the tests. Will call sys.exit when complete.
-
-  Args:
-    options: a dictionary of command line options
-    args: a list of sub directories or files to test
-  """
-
-  # Set up logging format.
-  log_level = logging.INFO
-  if options.verbose:
-    log_level = logging.DEBUG
-  logging.basicConfig(level=log_level,
-                      format='%(message)s')
-
-  # Include all tests if none are specified.
-  if not args:
-    path = '/';
-  else:
-    path = ' '.join(args);
-
-  adb_cmd = "adb ";
-  if options.adb_options:
-    adb_cmd += options.adb_options
-
-  # Re-generate the test list if --refresh-test-list is on
-  if options.refresh_test_list:
-    logging.info("Generating test list.");
-    generate_test_list_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#generateTestList -e path \"" + path + "\" -w com.android.dumprendertree/.LayoutTestsAutoRunner"
-    adb_output = subprocess.Popen(generate_test_list_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
-
-    if adb_output.find('Process crashed') != -1:
-       logging.info("Aborting because cannot generate test list.\n" + adb_output)
-       sys.exit(1)
-
-
-  logging.info("Running tests")
-
-  # Count crashed tests.
-  crashed_tests = []
-
-  timeout_ms = '15000'
-  if options.time_out_ms:
-    timeout_ms = options.time_out_ms
-
-  # Run test until it's done
-
-  run_layout_test_cmd_prefix = adb_cmd + " shell am instrument"
-
-  run_layout_test_cmd_postfix = " -e path \"" + path + "\" -e timeout " + timeout_ms
-  if options.rebaseline:
-    run_layout_test_cmd_postfix += " -e rebaseline true"
-
-  # If the JS engine is not specified on the command line, try reading the
-  # JS_ENGINE environment  variable, which is used by the build system in
-  # external/webkit/Android.mk.
-  js_engine = options.js_engine
-  if not js_engine and os.environ.has_key('JS_ENGINE'):
-    js_engine = os.environ['JS_ENGINE']
-  if js_engine:
-    run_layout_test_cmd_postfix += " -e jsengine " + js_engine
-
-  run_layout_test_cmd_postfix += " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
-
-  # Call LayoutTestsAutoTest::startLayoutTests.
-  run_layout_test_cmd = run_layout_test_cmd_prefix + " -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests" + run_layout_test_cmd_postfix
-
-  adb_output = subprocess.Popen(run_layout_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
-  while not DumpRenderTreeFinished(adb_cmd):
-    # Get the running_test.txt
-    logging.error("DumpRenderTree crashed, output:\n" + adb_output)
-
-    shell_cmd_str = adb_cmd + " shell cat /sdcard/webkit/running_test.txt"
-    crashed_test = ""
-    while not crashed_test:
-      (crashed_test, err) = subprocess.Popen(
-          shell_cmd_str, shell=True, stdout=subprocess.PIPE,
-          stderr=subprocess.PIPE).communicate()
-      crashed_test = crashed_test.strip()
-      if not crashed_test:
-        logging.error('Cannot get crashed test name, device offline?')
-        logging.error('stderr: ' + err)
-        logging.error('retrying in 10s...')
-        time.sleep(10)
-
-    logging.info(crashed_test + " CRASHED");
-    crashed_tests.append(crashed_test);
-
-    logging.info("Resuming layout test runner...");
-    # Call LayoutTestsAutoTest::resumeLayoutTests
-    run_layout_test_cmd = run_layout_test_cmd_prefix + " -e class com.android.dumprendertree.LayoutTestsAutoTest#resumeLayoutTests" + run_layout_test_cmd_postfix
-
-    adb_output = subprocess.Popen(run_layout_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
-
-  if adb_output.find('INSTRUMENTATION_FAILED') != -1:
-    logging.error("Error happened : " + adb_output)
-    sys.exit(1)
-
-  logging.debug(adb_output);
-  logging.info("Done\n");
-
-  # Pull results from /sdcard
-  results_dir = options.results_directory
-  if not os.path.exists(results_dir):
-    os.makedirs(results_dir)
-  if not os.path.isdir(results_dir):
-    logging.error("Cannot create results dir: " + results_dir);
-    sys.exit(1);
-
-  result_files = ["/sdcard/layout_tests_passed.txt",
-                  "/sdcard/layout_tests_failed.txt",
-                  "/sdcard/layout_tests_ignored.txt",
-                  "/sdcard/layout_tests_nontext.txt"]
-  for file in result_files:
-    shell_cmd_str = adb_cmd + " pull " + file + " " + results_dir
-    adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
-    logging.debug(adb_output)
-
-  # Create the crash list.
-  fp = open(results_dir + "/layout_tests_crashed.txt", "w");
-  for crashed_test in crashed_tests:
-    fp.writelines(crashed_test + '\n')
-  fp.close()
-
-  # Count the number of tests in each category.
-  passed_tests = CountLineNumber(results_dir + "/layout_tests_passed.txt")
-  logging.info(str(passed_tests) + " passed")
-  failed_tests = CountLineNumber(results_dir + "/layout_tests_failed.txt")
-  logging.info(str(failed_tests) + " failed")
-  ignored_tests = CountLineNumber(results_dir + "/layout_tests_ignored.txt")
-  logging.info(str(ignored_tests) + " ignored results")
-  crashed_tests = CountLineNumber(results_dir + "/layout_tests_crashed.txt")
-  logging.info(str(crashed_tests) + " crashed")
-  nontext_tests = CountLineNumber(results_dir + "/layout_tests_nontext.txt")
-  logging.info(str(nontext_tests) + " no dumpAsText")
-  logging.info(str(passed_tests + failed_tests + ignored_tests + crashed_tests + nontext_tests) + " TOTAL")
-
-  logging.info("Results are stored under: " + results_dir + "\n")
-
-  # Comparing results to references to find new fixes and regressions.
-  results_dir = os.path.abspath(options.results_directory)
-  ref_dir = options.ref_directory
-
-  # if ref_dir is null, cannonify ref_dir to the script dir.
-  if not ref_dir:
-    script_self = sys.argv[0]
-    script_dir = os.path.dirname(script_self)
-    ref_dir = os.path.join(script_dir, "results")
-
-  ref_dir = os.path.abspath(ref_dir)
-
-  CompareResults(ref_dir, results_dir)
-
-if '__main__' == __name__:
-  option_parser = optparse.OptionParser()
-  option_parser.add_option("", "--rebaseline", action="store_true",
-                           default=False,
-                           help="generate expected results for those tests not having one")
-  option_parser.add_option("", "--time-out-ms",
-                           default=None,
-                           help="set the timeout for each test")
-  option_parser.add_option("", "--verbose", action="store_true",
-                           default=False,
-                           help="include debug-level logging")
-  option_parser.add_option("", "--refresh-test-list", action="store_true",
-                           default=False,
-                           help="re-generate test list, it may take some time.")
-  option_parser.add_option("", "--adb-options",
-                           default=None,
-                           help="pass options to adb, such as -d -e, etc");
-  option_parser.add_option("", "--results-directory",
-                           default="layout-test-results",
-                           help="directory which results are stored.")
-  option_parser.add_option("", "--ref-directory",
-                           default=None,
-                           dest="ref_directory",
-                           help="directory where reference results are stored.")
-  option_parser.add_option("", "--js-engine",
-                           default=None,
-                           help="The JavaScript engine currently in use, which determines which set of Android-specific expected results we should use. Should be 'jsc' or 'v8'.");
-
-  options, args = option_parser.parse_args();
-  main(options, args)
diff --git a/tests/DumpRenderTree/assets/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py
deleted file mode 100755
index f995086..0000000
--- a/tests/DumpRenderTree/assets/run_page_cycler.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/python
-
-"""Run page cycler tests using Android instrumentation.
-
-  First, you need to get an SD card or sdcard image that has page cycler tests.
-
-  Usage:
-    Run a single page cycler test:
-      run_page_cycler.py "file:///sdcard/webkit/page_cycler/moz/start.html\?auto=1\&iterations=10"
-"""
-
-import logging
-import optparse
-import os
-import subprocess
-import sys
-import time
-
-
-
-def main(options, args):
-  """Run the tests. Will call sys.exit when complete.
-
-  """
-
-  # Set up logging format.
-  log_level = logging.INFO
-  if options.verbose:
-    log_level = logging.DEBUG
-  logging.basicConfig(level=log_level,
-                      format='%(message)s')
-
-  # Include all tests if none are specified.
-  if not args:
-    print "need a URL, e.g. file:///sdcard/webkit/page_cycler/moz/start.html\?auto=1\&iterations=10"
-    print "  or remote:android-browser-test:80/page_cycler/"
-    sys.exit(1)
-  else:
-    path = ' '.join(args);
-
-  if path[:7] == "remote:":
-    remote_path = path[7:]
-  else:
-    remote_path = None
-
-  adb_cmd = "adb ";
-  if options.adb_options:
-    adb_cmd += options.adb_options
-
-  logging.info("Running the test ...")
-
-  # Count crashed tests.
-  crashed_tests = []
-
-  timeout_ms = '0'
-  if options.time_out_ms:
-    timeout_ms = options.time_out_ms
-
-  # Run test until it's done
-
-  run_load_test_cmd_prefix = adb_cmd + " shell am instrument"
-  run_load_test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
-
-  # Call LoadTestsAutoTest::runTest.
-  run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e timeout " + timeout_ms
-
-  if remote_path:
-    if options.suite:
-      run_load_test_cmd += " -e suite %s -e forward %s " % (options.suite,
-                                                            remote_path)
-    else:
-      print "for network mode, need to specify --suite as well."
-      sys.exit(1)
-    if options.iteration:
-      run_load_test_cmd += " -e iteration %s" % options.iteration
-  else:
-    run_load_test_cmd += " -e path \"%s\" " % path
-
-
-  if options.drawtime:
-    run_load_test_cmd += " -e drawtime true "
-
-  if options.save_image:
-    run_load_test_cmd += " -e saveimage \"%s\"" % options.save_image
-
-  run_load_test_cmd += run_load_test_cmd_postfix
-
-  (adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
-  fail_flag = False
-  for line in adb_output.splitlines():
-    line = line.strip()
-    if line.find('INSTRUMENTATION_CODE') == 0:
-      if not line[22:] == '-1':
-        fail_flag = True
-        break
-    if (line.find('INSTRUMENTATION_FAILED') != -1 or
-        line.find('Process crashed.') != -1):
-      fail_flag = True
-      break
-  if fail_flag:
-    logging.error("Error happened : " + adb_output)
-    sys.exit(1)
-
-  logging.info(adb_output);
-  logging.info(adb_error);
-  logging.info("Done\n");
-
-  # Pull results from /sdcard/load_test_result.txt
-  results_dir = options.results_directory
-  if not os.path.exists(results_dir):
-    os.makedirs(results_dir)
-  if not os.path.isdir(results_dir):
-    logging.error("Cannot create results dir: " + results_dir)
-    sys.exit(1)
-
-  result_file = "/sdcard/load_test_result.txt"
-  shell_cmd_str = adb_cmd + " pull " + result_file + " " + results_dir
-  (adb_output, err) = subprocess.Popen(
-      shell_cmd_str, shell=True,
-      stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
-  if not os.path.isfile(os.path.join(results_dir, "load_test_result.txt")):
-    logging.error("Failed to pull result file.")
-    logging.error("adb stdout:")
-    logging.error(adb_output)
-    logging.error("adb stderr:")
-    logging.error(err)
-  logging.info("Results are stored under: " + results_dir + "/load_test_result.txt\n")
-
-if '__main__' == __name__:
-  option_parser = optparse.OptionParser()
-  option_parser.add_option("-t", "--time-out-ms",
-                           default=None,
-                           help="set the timeout for each test")
-  option_parser.add_option("-v", "--verbose", action="store_true",
-                           default=False,
-                           help="include debug-level logging")
-  option_parser.add_option("-a", "--adb-options",
-                           default=None,
-                           help="pass options to adb, such as -d -e, etc");
-  option_parser.add_option("-r", "--results-directory",
-                           default="layout-test-results",
-                           help="directory which results are stored.")
-
-  option_parser.add_option("-d", "--drawtime", action="store_true",
-                           default=False,
-                           help="log draw time for each page rendered.")
-
-  option_parser.add_option("-s", "--save-image",
-                           default=None,
-                           help="stores rendered page to a location on device.")
-
-  option_parser.add_option("-u", "--suite",
-                           default=None,
-                           help="(for network mode) specify the suite to"
-                           " run by name")
-
-  option_parser.add_option("-i", "--iteration",
-                           default="5",
-                           help="(for network mode) specify how many iterations"
-                           " to run")
-
-  options, args = option_parser.parse_args();
-  main(options, args)
diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py
deleted file mode 100755
index 59ac4a3..0000000
--- a/tests/DumpRenderTree/assets/run_reliability_tests.py
+++ /dev/null
@@ -1,276 +0,0 @@
-#!/usr/bin/python2.4
-
-"""Run reliability tests using Android instrumentation.
-
-  A test file consists of list web sites to test is needed as a parameter
-
-  Usage:
-    run_reliability_tests.py path/to/url/list
-"""
-
-import logging
-import optparse
-import os
-import subprocess
-import sys
-import time
-from Numeric import *
-
-TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt"
-TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt"
-TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt"
-TEST_LOAD_TIME_FILE = "/sdcard/android/reliability_load_time.txt"
-HTTP_URL_FILE = "urllist_http"
-HTTPS_URL_FILE = "urllist_https"
-NUM_URLS = 25
-
-
-def DumpRenderTreeFinished(adb_cmd):
-  """Check if DumpRenderTree finished running.
-
-  Args:
-    adb_cmd: adb command string
-
-  Returns:
-    True if DumpRenderTree has finished, False otherwise
-  """
-
-  # pull test status file and look for "#DONE"
-  shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
-  adb_output = subprocess.Popen(shell_cmd_str,
-                                shell=True, stdout=subprocess.PIPE,
-                                stderr=subprocess.PIPE).communicate()[0]
-  return adb_output.strip() == "#DONE"
-
-
-def RemoveDeviceFile(adb_cmd, file_name):
-  shell_cmd_str = adb_cmd + " shell rm " + file_name
-  subprocess.Popen(shell_cmd_str,
-                   shell=True, stdout=subprocess.PIPE,
-                   stderr=subprocess.PIPE).communicate()
-
-
-def Bugreport(url, bugreport_dir, adb_cmd):
-  """Pull a bugreport from the device."""
-  bugreport_filename = "%s/reliability_bugreport_%d.txt" % (bugreport_dir,
-                                                            int(time.time()))
-
-  # prepend the report with url
-  handle = open(bugreport_filename, "w")
-  handle.writelines("Bugreport for crash in url - %s\n\n" % url)
-  handle.close()
-
-  cmd = "%s bugreport >> %s" % (adb_cmd, bugreport_filename)
-  os.system(cmd)
-
-
-def ProcessPageLoadTime(raw_log):
-  """Processes the raw page load time logged by test app."""
-  log_handle = open(raw_log, "r")
-  load_times = {}
-
-  for line in log_handle:
-    line = line.strip()
-    pair = line.split("|")
-    if len(pair) != 2:
-      logging.info("Line has more than one '|': " + line)
-      continue
-    if pair[0] not in load_times:
-      load_times[pair[0]] = []
-    try:
-      pair[1] = int(pair[1])
-    except ValueError:
-      logging.info("Lins has non-numeric load time: " + line)
-      continue
-    load_times[pair[0]].append(pair[1])
-
-  log_handle.close()
-
-  # rewrite the average time to file
-  log_handle = open(raw_log, "w")
-  for url, times in load_times.iteritems():
-    # calculate std
-    arr = array(times)
-    avg = average(arr)
-    d = arr - avg
-    std = sqrt(sum(d * d) / len(arr))
-    output = ("%-70s%-10d%-10d%-12.2f%-12.2f%s\n" %
-              (url, min(arr), max(arr), avg, std,
-               array2string(arr)))
-    log_handle.write(output)
-  log_handle.close()
-
-
-def main(options, args):
-  """Send the url list to device and start testing, restart if crashed."""
-
-  # Set up logging format.
-  log_level = logging.INFO
-  if options.verbose:
-    log_level = logging.DEBUG
-  logging.basicConfig(level=log_level,
-                      format="%(message)s")
-
-  # Include all tests if none are specified.
-  if not args:
-    print "Missing URL list file"
-    sys.exit(1)
-  else:
-    path = args[0]
-
-  if not options.crash_file:
-    print "Missing crash file name, use --crash-file to specify"
-    sys.exit(1)
-  else:
-    crashed_file = options.crash_file
-
-  if not options.timeout_file:
-    print "Missing timeout file, use --timeout-file to specify"
-    sys.exit(1)
-  else:
-    timedout_file = options.timeout_file
-
-  if not options.delay:
-    manual_delay = 0
-  else:
-    manual_delay = options.delay
-
-  if not options.bugreport:
-    bugreport_dir = "."
-  else:
-    bugreport_dir = options.bugreport
-  if not os.path.exists(bugreport_dir):
-    os.makedirs(bugreport_dir)
-  if not os.path.isdir(bugreport_dir):
-    logging.error("Cannot create results dir: " + bugreport_dir)
-    sys.exit(1)
-
-  adb_cmd = "adb "
-  if options.adb_options:
-    adb_cmd += options.adb_options + " "
-
-  # push url list to device
-  test_cmd = adb_cmd + " push \"" + path + "\" \"" + TEST_LIST_FILE + "\""
-  proc = subprocess.Popen(test_cmd, shell=True,
-                          stdout=subprocess.PIPE,
-                          stderr=subprocess.PIPE)
-  (adb_output, adb_error) = proc.communicate()
-  if proc.returncode != 0:
-    logging.error("failed to push url list to device.")
-    logging.error(adb_output)
-    logging.error(adb_error)
-    sys.exit(1)
-
-  # clean up previous results
-  RemoveDeviceFile(adb_cmd, TEST_STATUS_FILE)
-  RemoveDeviceFile(adb_cmd, TEST_TIMEOUT_FILE)
-  RemoveDeviceFile(adb_cmd, TEST_LOAD_TIME_FILE)
-
-  logging.info("Running the test ...")
-
-  # Count crashed tests.
-  crashed_tests = []
-
-  if options.time_out_ms:
-    timeout_ms = options.time_out_ms
-
-  # Run test until it's done
-  test_cmd_prefix = adb_cmd + " shell am instrument"
-  test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
-
-  # Call ReliabilityTestsAutoTest#startReliabilityTests
-  test_cmd = (test_cmd_prefix + " -e class "
-              "com.android.dumprendertree.ReliabilityTest#"
-              "runReliabilityTest -e timeout %s -e delay %s" %
-              (str(timeout_ms), str(manual_delay)))
-
-  if options.logtime:
-    test_cmd += " -e logtime true"
-
-  test_cmd += test_cmd_postfix
-
-  adb_output = subprocess.Popen(test_cmd, shell=True,
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.PIPE).communicate()[0]
-  while not DumpRenderTreeFinished(adb_cmd):
-    logging.error("DumpRenderTree exited before all URLs are visited.")
-    shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
-    crashed_test = ""
-    while not crashed_test:
-      (crashed_test, err) = subprocess.Popen(
-          shell_cmd_str, shell=True, stdout=subprocess.PIPE,
-          stderr=subprocess.PIPE).communicate()
-      crashed_test = crashed_test.strip()
-      if not crashed_test:
-        logging.error('Cannot get crashed test name, device offline?')
-        logging.error('stderr: ' + err)
-        logging.error('retrying in 10s...')
-        time.sleep(10)
-
-    logging.info(crashed_test + " CRASHED")
-    crashed_tests.append(crashed_test)
-    Bugreport(crashed_test, bugreport_dir, adb_cmd)
-    logging.info("Resuming reliability test runner...")
-
-    adb_output = subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE,
-                                  stderr=subprocess.PIPE).communicate()[0]
-
-  if (adb_output.find("INSTRUMENTATION_FAILED") != -1 or
-      adb_output.find("Process crashed.") != -1):
-    logging.error("Error happened : " + adb_output)
-    sys.exit(1)
-
-  logging.info(adb_output)
-  logging.info("Done\n")
-
-  if crashed_tests:
-    file_handle = open(crashed_file, "w")
-    file_handle.writelines("\n".join(crashed_tests))
-    logging.info("Crashed URL list stored in: " + crashed_file)
-    file_handle.close()
-  else:
-    logging.info("No crash found.")
-
-  # get timeout file from sdcard
-  test_cmd = (adb_cmd + "pull \"" + TEST_TIMEOUT_FILE + "\" \""
-              + timedout_file +  "\"")
-  subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE,
-                   stderr=subprocess.PIPE).communicate()
-
-  if options.logtime:
-    # get logged page load times from sdcard
-    test_cmd = (adb_cmd + "pull \"" + TEST_LOAD_TIME_FILE + "\" \""
-                + options.logtime +  "\"")
-    subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE,
-                     stderr=subprocess.PIPE).communicate()
-    ProcessPageLoadTime(options.logtime)
-
-
-if "__main__" == __name__:
-  option_parser = optparse.OptionParser()
-  option_parser.add_option("-t", "--time-out-ms",
-                           default=60000,
-                           help="set the timeout for each test")
-  option_parser.add_option("-v", "--verbose", action="store_true",
-                           default=False,
-                           help="include debug-level logging")
-  option_parser.add_option("-a", "--adb-options",
-                           default=None,
-                           help="pass options to adb, such as -d -e, etc")
-  option_parser.add_option("-c", "--crash-file",
-                           default="reliability_crashed_sites.txt",
-                           help="the list of sites that cause browser to crash")
-  option_parser.add_option("-f", "--timeout-file",
-                           default="reliability_timedout_sites.txt",
-                           help="the list of sites that timedout during test")
-  option_parser.add_option("-d", "--delay",
-                           default=0,
-                           help="add a manual delay between pages (in ms)")
-  option_parser.add_option("-b", "--bugreport",
-                           default=".",
-                           help="the directory to store bugreport for crashes")
-  option_parser.add_option("-l", "--logtime",
-                           default=None,
-                           help="Logs page load time for each url to the file")
-  opts, arguments = option_parser.parse_args()
-  main(opts, arguments)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
deleted file mode 100644
index 9d621d6..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.webkit.WebStorage;
-
-import java.util.HashMap;
-
-public class CallbackProxy extends Handler implements EventSender, LayoutTestController {
-
-    private EventSender mEventSender;
-    private LayoutTestController mLayoutTestController;
-
-    private static final int EVENT_DOM_LOG = 1;
-    private static final int EVENT_FIRE_KBD = 2;
-    private static final int EVENT_KEY_DOWN_1 = 3;
-    private static final int EVENT_KEY_DOWN_2 = 4;
-    private static final int EVENT_LEAP = 5;
-    private static final int EVENT_MOUSE_CLICK = 6;
-    private static final int EVENT_MOUSE_DOWN = 7;
-    private static final int EVENT_MOUSE_MOVE = 8;
-    private static final int EVENT_MOUSE_UP = 9;
-    private static final int EVENT_TOUCH_START = 10;
-    private static final int EVENT_TOUCH_MOVE = 11;
-    private static final int EVENT_TOUCH_END = 12;
-    private static final int EVENT_TOUCH_CANCEL = 13;
-    private static final int EVENT_ADD_TOUCH_POINT = 14;
-    private static final int EVENT_UPDATE_TOUCH_POINT = 15;
-    private static final int EVENT_RELEASE_TOUCH_POINT = 16;
-    private static final int EVENT_CLEAR_TOUCH_POINTS = 17;
-    private static final int EVENT_CANCEL_TOUCH_POINT = 18;
-    private static final int EVENT_SET_TOUCH_MODIFIER = 19;
-    private static final int LAYOUT_CLEAR_LIST = 20;
-    private static final int LAYOUT_DISPLAY = 21;
-    private static final int LAYOUT_DUMP_TEXT = 22;
-    private static final int LAYOUT_DUMP_HISTORY = 23;
-    private static final int LAYOUT_DUMP_CHILD_SCROLL = 24;
-    private static final int LAYOUT_DUMP_EDIT_CB = 25;
-    private static final int LAYOUT_DUMP_SEL_RECT = 26;
-    private static final int LAYOUT_DUMP_TITLE_CHANGES = 27;
-    private static final int LAYOUT_KEEP_WEB_HISTORY = 28;
-    private static final int LAYOUT_NOTIFY_DONE = 29;
-    private static final int LAYOUT_QUEUE_BACK_NAV = 30;
-    private static final int LAYOUT_QUEUE_FWD_NAV = 31;
-    private static final int LAYOUT_QUEUE_LOAD = 32;
-    private static final int LAYOUT_QUEUE_RELOAD = 33;
-    private static final int LAYOUT_QUEUE_SCRIPT = 34;
-    private static final int LAYOUT_REPAINT_HORZ = 35;
-    private static final int LAYOUT_SET_ACCEPT_EDIT = 36;
-    private static final int LAYOUT_MAIN_FIRST_RESP = 37;
-    private static final int LAYOUT_SET_WINDOW_KEY = 38;
-    private static final int LAYOUT_TEST_REPAINT = 39;
-    private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
-    private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
-    private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
-    private static final int OVERRIDE_PREFERENCE = 43;
-    private static final int LAYOUT_DUMP_CHILD_FRAMES_TEXT = 44;
-    private static final int SET_XSS_AUDITOR_ENABLED = 45;
-    
-    CallbackProxy(EventSender eventSender, 
-            LayoutTestController layoutTestController) {
-        mEventSender = eventSender;
-        mLayoutTestController = layoutTestController;
-    }
-    
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-        case EVENT_DOM_LOG:
-            mEventSender.enableDOMUIEventLogging(msg.arg1);
-            break;
-        case EVENT_FIRE_KBD:
-            mEventSender.fireKeyboardEventsToElement(msg.arg1);
-            break;
-        case EVENT_KEY_DOWN_1:
-            HashMap map = (HashMap) msg.obj;
-            mEventSender.keyDown((String) map.get("character"), 
-                    (String[]) map.get("withModifiers"));
-            break;
-
-        case EVENT_KEY_DOWN_2:
-            mEventSender.keyDown((String)msg.obj);
-            break;
-
-        case EVENT_LEAP:
-            mEventSender.leapForward(msg.arg1);
-            break;
-
-        case EVENT_MOUSE_CLICK:
-            mEventSender.mouseClick();
-            break;
-
-        case EVENT_MOUSE_DOWN:
-            mEventSender.mouseDown();
-            break;
-
-        case EVENT_MOUSE_MOVE:
-            mEventSender.mouseMoveTo(msg.arg1, msg.arg2);
-            break;
-
-        case EVENT_MOUSE_UP:
-            mEventSender.mouseUp();
-            break;
-
-        case EVENT_TOUCH_START:
-            mEventSender.touchStart();
-            break;
-
-        case EVENT_TOUCH_MOVE:
-            mEventSender.touchMove();
-            break;
-
-        case EVENT_TOUCH_END:
-            mEventSender.touchEnd();
-            break;
-
-        case EVENT_TOUCH_CANCEL:
-            mEventSender.touchCancel();
-            break;
-
-        case EVENT_ADD_TOUCH_POINT:
-            mEventSender.addTouchPoint(msg.arg1, msg.arg2);
-            break;
-
-        case EVENT_UPDATE_TOUCH_POINT:
-            Bundle args = (Bundle) msg.obj;
-            int x = args.getInt("x");
-            int y = args.getInt("y");
-            int id = args.getInt("id");
-            mEventSender.updateTouchPoint(id, x, y);
-            break;
-
-        case EVENT_SET_TOUCH_MODIFIER:
-            Bundle modifierArgs = (Bundle) msg.obj;
-            String modifier = modifierArgs.getString("modifier");
-            boolean enabled = modifierArgs.getBoolean("enabled");
-            mEventSender.setTouchModifier(modifier, enabled);
-            break;
-
-        case EVENT_RELEASE_TOUCH_POINT:
-            mEventSender.releaseTouchPoint(msg.arg1);
-            break;
-
-        case EVENT_CLEAR_TOUCH_POINTS:
-            mEventSender.clearTouchPoints();
-            break;
-
-        case EVENT_CANCEL_TOUCH_POINT:
-            mEventSender.cancelTouchPoint(msg.arg1);
-            break;
-
-        case LAYOUT_CLEAR_LIST:
-            mLayoutTestController.clearBackForwardList();
-            break;
-
-        case LAYOUT_DISPLAY:
-            mLayoutTestController.display();
-            break;
-
-        case LAYOUT_DUMP_TEXT:
-            mLayoutTestController.dumpAsText(msg.arg1 == 1);
-            break;
-
-        case LAYOUT_DUMP_CHILD_FRAMES_TEXT:
-            mLayoutTestController.dumpChildFramesAsText();
-            break;
-
-        case LAYOUT_DUMP_HISTORY:
-            mLayoutTestController.dumpBackForwardList();
-            break;
-
-        case LAYOUT_DUMP_CHILD_SCROLL:
-            mLayoutTestController.dumpChildFrameScrollPositions();
-            break;
-
-        case LAYOUT_DUMP_EDIT_CB:
-            mLayoutTestController.dumpEditingCallbacks();
-            break;
-
-        case LAYOUT_DUMP_SEL_RECT:
-            mLayoutTestController.dumpSelectionRect();
-            break;
-
-        case LAYOUT_DUMP_TITLE_CHANGES:
-            mLayoutTestController.dumpTitleChanges();
-            break;
-
-        case LAYOUT_KEEP_WEB_HISTORY:
-            mLayoutTestController.keepWebHistory();
-            break;
-
-        case LAYOUT_NOTIFY_DONE:
-            mLayoutTestController.notifyDone();
-            break;
-
-        case LAYOUT_QUEUE_BACK_NAV:
-            mLayoutTestController.queueBackNavigation(msg.arg1);
-            break;
-
-        case LAYOUT_QUEUE_FWD_NAV:
-            mLayoutTestController.queueForwardNavigation(msg.arg1);
-            break;
-
-        case LAYOUT_QUEUE_LOAD:
-            HashMap<String, String> loadMap = 
-                (HashMap<String, String>) msg.obj;
-            mLayoutTestController.queueLoad(loadMap.get("Url"), 
-                    loadMap.get("frameTarget"));
-            break;
-
-        case LAYOUT_QUEUE_RELOAD:
-            mLayoutTestController.queueReload();
-            break;
-
-        case LAYOUT_QUEUE_SCRIPT:
-            mLayoutTestController.queueScript((String)msg.obj);
-            break;
-
-        case LAYOUT_REPAINT_HORZ:
-            mLayoutTestController.repaintSweepHorizontally();
-            break;
-
-        case LAYOUT_SET_ACCEPT_EDIT:
-            mLayoutTestController.setAcceptsEditing(
-                    msg.arg1 == 1 ? true : false);
-            break;
-        case LAYOUT_MAIN_FIRST_RESP:
-            mLayoutTestController.setMainFrameIsFirstResponder(
-                    msg.arg1 == 1 ? true : false);
-            break;
-
-        case LAYOUT_SET_WINDOW_KEY:
-            mLayoutTestController.setWindowIsKey(
-                    msg.arg1 == 1 ? true : false);
-            break;
-
-        case LAYOUT_TEST_REPAINT:
-            mLayoutTestController.testRepaint();
-            break;
-
-        case LAYOUT_WAIT_UNTIL_DONE:
-            mLayoutTestController.waitUntilDone();
-            break;
-
-        case LAYOUT_DUMP_DATABASE_CALLBACKS:
-            mLayoutTestController.dumpDatabaseCallbacks();
-            break;
-
-        case LAYOUT_SET_CAN_OPEN_WINDOWS:
-            mLayoutTestController.setCanOpenWindows();
-            break;
-
-        case OVERRIDE_PREFERENCE:
-            String key = msg.getData().getString("key");
-            boolean value = msg.getData().getBoolean("value");
-            mLayoutTestController.overridePreference(key, value);
-            break;
-
-        case SET_XSS_AUDITOR_ENABLED:
-            mLayoutTestController.setXSSAuditorEnabled(msg.arg1 == 1);
-            break;
-        }
-    }
-
-    // EventSender Methods
-    
-    public void enableDOMUIEventLogging(int DOMNode) {
-        obtainMessage(EVENT_DOM_LOG, DOMNode, 0).sendToTarget();
-    }
-
-    public void fireKeyboardEventsToElement(int DOMNode) {
-        obtainMessage(EVENT_FIRE_KBD, DOMNode, 0).sendToTarget();
-    }
-
-    public void keyDown(String character, String[] withModifiers) {
-        // TODO Auto-generated method stub
-        HashMap map = new HashMap();
-        map.put("character", character);
-        map.put("withModifiers", withModifiers);
-        obtainMessage(EVENT_KEY_DOWN_1, map).sendToTarget();
-    }
-
-    public void keyDown(String character) {
-        obtainMessage(EVENT_KEY_DOWN_2, character).sendToTarget();
-    }
-
-    public void leapForward(int milliseconds) {
-        obtainMessage(EVENT_LEAP, milliseconds, 0).sendToTarget(); 
-    }
-
-    public void mouseClick() {
-        obtainMessage(EVENT_MOUSE_CLICK).sendToTarget();
-    }
-
-    public void mouseDown() {
-        obtainMessage(EVENT_MOUSE_DOWN).sendToTarget();
-    }
-
-    public void mouseMoveTo(int X, int Y) {
-        obtainMessage(EVENT_MOUSE_MOVE, X, Y).sendToTarget();
-    }
-
-    public void mouseUp() {
-        obtainMessage(EVENT_MOUSE_UP).sendToTarget();
-    }
-
-    public void touchStart() {
-        obtainMessage(EVENT_TOUCH_START).sendToTarget();
-    }
-
-    public void addTouchPoint(int x, int y) {
-        obtainMessage(EVENT_ADD_TOUCH_POINT, x, y).sendToTarget();
-    }
-
-    public void updateTouchPoint(int id, int x, int y) {
-        Bundle map = new Bundle();
-        map.putInt("x", x);
-        map.putInt("y", y);
-        map.putInt("id", id);
-        obtainMessage(EVENT_UPDATE_TOUCH_POINT, map).sendToTarget();
-    }
-
-    public void setTouchModifier(String modifier, boolean enabled) {
-        Bundle map = new Bundle();
-        map.putString("modifier", modifier);
-        map.putBoolean("enabled", enabled);
-        obtainMessage(EVENT_SET_TOUCH_MODIFIER, map).sendToTarget();
-    }
-
-    public void touchMove() {
-        obtainMessage(EVENT_TOUCH_MOVE).sendToTarget();
-    }
-
-    public void releaseTouchPoint(int id) {
-        obtainMessage(EVENT_RELEASE_TOUCH_POINT, id, 0).sendToTarget();
-    }
-
-    public void touchEnd() {
-        obtainMessage(EVENT_TOUCH_END).sendToTarget();
-    }
-
-    public void touchCancel() {
-        obtainMessage(EVENT_TOUCH_CANCEL).sendToTarget();
-    }
-
-
-    public void clearTouchPoints() {
-        obtainMessage(EVENT_CLEAR_TOUCH_POINTS).sendToTarget();
-    }
-
-    public void cancelTouchPoint(int id) {
-        obtainMessage(EVENT_CANCEL_TOUCH_POINT, id, 0).sendToTarget();
-    }
-    
-    // LayoutTestController Methods
-
-    public void clearBackForwardList() {
-        obtainMessage(LAYOUT_CLEAR_LIST).sendToTarget();
-    }
-
-    public void display() {
-        obtainMessage(LAYOUT_DISPLAY).sendToTarget();
-    }
-
-    public void dumpAsText() {
-        obtainMessage(LAYOUT_DUMP_TEXT, 0).sendToTarget();
-    }
-
-    public void dumpAsText(boolean enablePixelTests) {
-        obtainMessage(LAYOUT_DUMP_TEXT, enablePixelTests ? 1 : 0).sendToTarget();
-    }
-
-    public void dumpChildFramesAsText() {
-        obtainMessage(LAYOUT_DUMP_CHILD_FRAMES_TEXT).sendToTarget();
-    }
-
-    public void dumpBackForwardList() {
-        obtainMessage(LAYOUT_DUMP_HISTORY).sendToTarget();
-    }
-
-    public void dumpChildFrameScrollPositions() {
-        obtainMessage(LAYOUT_DUMP_CHILD_SCROLL).sendToTarget();
-    }
-
-    public void dumpEditingCallbacks() {
-        obtainMessage(LAYOUT_DUMP_EDIT_CB).sendToTarget(); 
-    }
-
-    public void dumpSelectionRect() {
-        obtainMessage(LAYOUT_DUMP_SEL_RECT).sendToTarget(); 
-    }
-
-    public void dumpTitleChanges() {
-        obtainMessage(LAYOUT_DUMP_TITLE_CHANGES).sendToTarget();
-    }
-
-    public void keepWebHistory() {
-        obtainMessage(LAYOUT_KEEP_WEB_HISTORY).sendToTarget();
-    }
-
-    public void notifyDone() {
-        obtainMessage(LAYOUT_NOTIFY_DONE).sendToTarget();
-    }
-
-    public void queueBackNavigation(int howfar) {
-        obtainMessage(LAYOUT_QUEUE_BACK_NAV, howfar, 0).sendToTarget();
-    }
-
-    public void queueForwardNavigation(int howfar) {
-        obtainMessage(LAYOUT_QUEUE_FWD_NAV, howfar, 0).sendToTarget();
-    }
-
-    public void queueLoad(String Url, String frameTarget) {
-        HashMap <String, String>map = new HashMap<String, String>();
-        map.put("Url", Url);
-        map.put("frameTarget", frameTarget);
-        obtainMessage(LAYOUT_QUEUE_LOAD, map).sendToTarget();
-    }
-
-    public void queueReload() {
-        obtainMessage(LAYOUT_QUEUE_RELOAD).sendToTarget();
-    }
-
-    public void queueScript(String scriptToRunInCurrentContext) {
-        obtainMessage(LAYOUT_QUEUE_SCRIPT, 
-                scriptToRunInCurrentContext).sendToTarget();
-    }
-
-    public void repaintSweepHorizontally() {
-        obtainMessage(LAYOUT_REPAINT_HORZ).sendToTarget();
-    }
-
-    public void setAcceptsEditing(boolean b) {
-        obtainMessage(LAYOUT_SET_ACCEPT_EDIT, b ? 1 : 0, 0).sendToTarget();
-    }
-
-    public void setMainFrameIsFirstResponder(boolean b) {
-        obtainMessage(LAYOUT_MAIN_FIRST_RESP, b ? 1 : 0, 0).sendToTarget();
-    }
-
-    public void setWindowIsKey(boolean b) {
-        obtainMessage(LAYOUT_SET_WINDOW_KEY, b ? 1 : 0, 0).sendToTarget();
-    }
-
-    public void testRepaint() {
-        obtainMessage(LAYOUT_TEST_REPAINT).sendToTarget(); 
-    }
-
-    public void waitUntilDone() {
-        obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
-    }
-
-    public void dumpDatabaseCallbacks() {
-        obtainMessage(LAYOUT_DUMP_DATABASE_CALLBACKS).sendToTarget();
-    }
-
-    public void clearAllDatabases() {
-        WebStorage.getInstance().deleteAllData();
-    }
-
-    public void setDatabaseQuota(long quota) {
-        WebStorage.getInstance().setQuotaForOrigin("file://", quota);
-    }
-
-    public void setAppCacheMaximumSize(long size) {
-        android.webkit.WebStorageClassic.getInstance().setAppCacheMaximumSize(size);
-    }
-
-    public void setCanOpenWindows() {
-        obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
-    }
-
-    public void setMockGeolocationPosition(double latitude,
-                                           double longitude,
-                                           double accuracy) {
-        // Configuration is in WebKit, so stay on WebCore thread, but go via the TestShellActivity
-        // as we need access to the Webview.
-        mLayoutTestController.setMockGeolocationPosition(latitude,
-                                                         longitude,
-                                                         accuracy);
-    }
-
-    public void setMockGeolocationError(int code, String message) {
-        // Configuration is in WebKit, so stay on WebCore thread, but go via the TestShellActivity
-        // as we need access to the Webview.
-        mLayoutTestController.setMockGeolocationError(code, message);
-    }
-
-    public void setGeolocationPermission(boolean allow) {
-        // Configuration is in WebKit, so stay on WebCore thread, but go via the TestShellActivity
-        // as we need access to the Webview.
-        mLayoutTestController.setGeolocationPermission(allow);
-    }
-
-    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
-            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
-        // Configuration is in WebKit, so stay on WebCore thread, but go via the TestShellActivity
-        // as we need access to the Webview.
-        mLayoutTestController.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta,
-                canProvideGamma, gamma);
-    }
-
-    public void overridePreference(String key, boolean value) {
-        Message message = obtainMessage(OVERRIDE_PREFERENCE);
-        message.getData().putString("key", key);
-        message.getData().putBoolean("value", value);
-        message.sendToTarget();
-    }
-
-    public void setXSSAuditorEnabled(boolean flag) {
-        obtainMessage(SET_XSS_AUDITOR_ENABLED, flag ? 1 : 0, 0).sendToTarget();
-    }
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java
deleted file mode 100644
index 23cc8f5..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-public interface EventSender {
-    	public void mouseDown();
-    	public void mouseUp();
-        public void mouseClick();
-        public void mouseMoveTo(int X, int Y);
-        public void leapForward(int milliseconds);
-        public void keyDown (String character, String[] withModifiers);
-        public void keyDown (String character);
-        public void enableDOMUIEventLogging(int DOMNode);
-        public void fireKeyboardEventsToElement(int DOMNode);
-        public void touchStart();
-        public void touchMove();
-        public void touchEnd();
-        public void touchCancel();
-        public void addTouchPoint(int x, int y);
-        public void updateTouchPoint(int id, int x, int y);
-        public void setTouchModifier(String modifier, boolean enabled);
-        public void releaseTouchPoint(int id);
-        public void clearTouchPoints();
-        public void cancelTouchPoint(int id);
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
deleted file mode 100644
index d373d8d..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import java.util.Vector;
-import android.util.*;
-
-public class FileFilter {
-
-    private static final String LOGTAG = "FileFilter";
-
-    // Returns whether we should ignore this test and skip running it.
-    // Currently we use this only for tests that crash or hang DumpRenderTree.
-    // TODO: Fix these and eliminate this method.
-    public static boolean ignoreTest(String file) {
-        for (int i = 0; i < ignoreTestList.length; i++) {
-            if (file.endsWith(ignoreTestList[i])) {
-                Log.v(LOGTAG, "File path in list of ignored tests: " + file);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // Returns whether a directory does not contain layout tests and so can be
-    // ignored.
-    public static boolean isNonTestDir(String file) {
-        for (int i = 0; i < nonTestDirs.length; i++) {
-            if (file.endsWith(nonTestDirs[i])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // Returns whether we should ignore the result of this test.
-    public static boolean ignoreResult(String file) {
-        for (int i = 0; i < ignoreResultList.size(); i++) {
-            if (file.endsWith(ignoreResultList.get(i))) {
-                Log.v(LOGTAG, "File path in list of ignored results: " + file);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    final static Vector<String> ignoreResultList = new Vector<String>();
-
-    static {
-        fillIgnoreResultList();
-    }
-
-    static final String[] nonTestDirs = {
-        ".", // ignore hidden directories and files
-        "resources", // ignore resource directories
-        ".svn", // don't run anything under .svn folder
-        "platform"  // No-Android specific tests
-    };
-
-    static final String[] ignoreTestList = {
-        "canvas/philip/tests/2d.drawImage.broken.html", // blocks test, http://b/2982500
-        "editing/selection/move-left-right.html", // Causes DumpRenderTree to hang
-        "fast/js/excessive-comma-usage.html", // Tests huge initializer list, causes OOM.
-        "fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM
-        "fast/js/regexp-overflow.html", // Result is too large, causing OOM when reading by DRT, http://b/2697589
-        "fast/regex/test1.html", // Causes DumpRenderTree to hang with V8
-        "fast/regex/slow.html", // Causes DumpRenderTree to hang with V8
-    };
-
-    static void fillIgnoreResultList() {
-        // This first block of tests are for features for which Android
-        // should pass all tests. They are skipped only temporarily.
-        // TODO: Fix these failing tests and remove them from this list.
-        ignoreResultList.add("fast/dom/HTMLKeygenElement/keygen.html"); // Missing layoutTestController.shadowRoot()
-        ignoreResultList.add("fast/dom/Geolocation/window-close-crash.html"); // Missing layoutTestContoller.setCloseRemainingWindowsWhenComplete()
-        ignoreResultList.add("fast/dom/Geolocation/page-reload-cancel-permission-requests.html"); // Missing layoutTestController.numberOfPendingGeolocationPermissionRequests()
-        ignoreResultList.add("fast/dom/HTMLLinkElement/link-and-subresource-test.html"); // Missing layoutTestController.dumpResourceResponseMIMETypes()
-        ignoreResultList.add("fast/dom/HTMLLinkElement/prefetch.html"); // Missing layoutTestController.dumpResourceResponseMIMETypes()
-        ignoreResultList.add("fast/dom/HTMLLinkElement/subresource.html"); // Missing layoutTestController.dumpResourceResponseMIMETypes()
-        ignoreResultList.add("fast/encoding/char-decoding.html"); // fails in Java HTTP stack, see http://b/issue?id=3047156
-        ignoreResultList.add("fast/encoding/hanarei-blog32-fc2-com.html"); // fails in Java HTTP stack, see http://b/issue?id=3046986
-        ignoreResultList.add("fast/encoding/mailto-always-utf-8.html"); // Requires waitForPolicyDelegate(), see http://b/issue?id=3043468
-        ignoreResultList.add("fast/encoding/percent-escaping.html"); // fails in Java HTTP stack, see http://b/issue?id=3046984
-        ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky
-        ignoreResultList.add("http/tests/appcache/fallback.html"); // http://b/issue?id=2713004
-        ignoreResultList.add("http/tests/appcache/foreign-fallback.html"); // Flaky, may be due to DRT, see http://b/3285647
-        ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
-        ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
-        ignoreResultList.add("http/tests/appcache/origin-quota.html"); // needs clearAllApplicationCaches(), see http://b/issue?id=2944196
-        ignoreResultList.add("storage/database-lock-after-reload.html"); // Succeeds but DumpRenderTree does not read result correctly
-        ignoreResultList.add("storage/hash-change-with-xhr.html"); // Succeeds but DumpRenderTree does not read result correctly
-        ignoreResultList.add("storage/open-database-creation-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
-        ignoreResultList.add("storage/statement-error-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
-        ignoreResultList.add("storage/statement-success-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
-        ignoreResultList.add("storage/storageinfo-query-usage.html"); // Need window.webkitStorageInfo
-        ignoreResultList.add("storage/transaction-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
-        ignoreResultList.add("storage/transaction-error-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
-        ignoreResultList.add("storage/transaction-success-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
-        ignoreResultList.add("storage/domstorage/localstorage/storagetracker/storage-tracker-1-prepare.html"); // Missing layoutTestController.originsWithLocalStorage()
-        ignoreResultList.add("storage/domstorage/localstorage/storagetracker/storage-tracker-2-create.html"); // Missing layoutTestController.originsWithLocalStorage()
-        ignoreResultList.add("storage/domstorage/localstorage/storagetracker/storage-tracker-3-delete-all.html"); // Missing layoutTestController.originsWithLocalStorage()
-        ignoreResultList.add("storage/domstorage/localstorage/storagetracker/storage-tracker-4-create.html"); // Missing layoutTestController.originsWithLocalStorage()
-        ignoreResultList.add("storage/domstorage/localstorage/storagetracker/storage-tracker-5-delete-one.html"); // Missing layoutTestController.originsWithLocalStorage()
-
-
-        // Expected failures due to unsupported features or tests unsuitable for Android.
-        ignoreResultList.add("fast/encoding/char-decoding-mac.html"); // Mac-specific encodings (also marked Won't Fix in Chromium, bug 7388)
-        ignoreResultList.add("fast/encoding/char-encoding-mac.html"); // Mac-specific encodings (also marked Won't Fix in Chromium, bug 7388)
-        ignoreResultList.add("fast/encoding/idn-security.html"); // Mac-specific IDN checks (also marked Won't Fix in Chromium, bug 21814)
-        ignoreResultList.add("fast/events/touch/basic-multi-touch-events.html"); // Requires multi-touch gestures not supported by Android system
-        ignoreResultList.add("fast/events/touch/touch-coords-in-zoom-and-scroll.html"); // Requires eventSender.zoomPageIn(),zoomPageOut()
-        ignoreResultList.add("fast/events/touch/touch-target.html"); // Requires multi-touch gestures not supported by Android system
-        ignoreResultList.add("fast/workers"); // workers not supported
-        ignoreResultList.add("http/tests/cookies/third-party-cookie-relaxing.html"); // We don't support conditional acceptance of third-party cookies
-        ignoreResultList.add("http/tests/eventsource/workers"); // workers not supported
-        ignoreResultList.add("http/tests/workers"); // workers not supported
-        ignoreResultList.add("http/tests/xmlhttprequest/workers"); // workers not supported
-        ignoreResultList.add("storage/domstorage/localstorage/private-browsing-affects-storage.html"); // private browsing not supported
-        ignoreResultList.add("storage/domstorage/sessionstorage/private-browsing-affects-storage.html"); // private browsing not supported
-        ignoreResultList.add("storage/indexeddb"); // indexeddb not supported
-        ignoreResultList.add("storage/private-browsing-noread-nowrite.html"); // private browsing not supported
-        ignoreResultList.add("storage/private-browsing-readonly.html"); // private browsing not supported
-        ignoreResultList.add("websocket/tests/workers"); // workers not supported
-        ignoreResultList.add("dom/xhtml/level2/html/htmldocument04.xhtml"); // /mnt/sdcard on SR uses lowercase filesystem, this test checks filename and is case senstive.
-        ignoreResultList.add("dom/html/level2/html/htmldocument04.html"); // ditto
-
-        // Expected failures due to missing expected results
-        ignoreResultList.add("dom/xhtml/level3/core/canonicalform08.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/canonicalform09.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/documentgetinputencoding03.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/entitygetinputencoding02.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/entitygetxmlversion02.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri05.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri07.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri09.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri10.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri11.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri15.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri17.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodegetbaseuri18.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodelookupnamespaceuri01.xhtml");
-        ignoreResultList.add("dom/xhtml/level3/core/nodelookupprefix19.xhtml");
-
-        // TODO: These need to be triaged
-        ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
-        ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
-        ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
-        ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); // pixel depth
-        ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/dom/attribute-namespaces-get-set.html"); // http://b/733229
-        ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); // dynamic plugins not supported
-        ignoreResultList.add("fast/dom/tabindex-clamp.html"); // there is extra spacing in the file due to multiple input boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
-        ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/arrow-navigation.html"); // http://b/735233
-        ignoreResultList.add("fast/events/capture-on-target.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/dblclick-addEventListener.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/drag-in-frames.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/drag-outside-window.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/event-view-toString.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/frame-click-focus.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/frame-tab-focus.html"); // http://b/734308
-        ignoreResultList.add("fast/events/iframe-object-onload.html"); // there is extra spacing in the file due to multiple frame boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
-        ignoreResultList.add("fast/events/input-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/mouseover-mouseout.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/mouseover-mouseout2.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/mouseup-outside-button.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/mouseup-outside-document.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/onclick-list-marker.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/ondragenter.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/onload-webkit-before-webcore.html"); // missing space in textrun, ok as text is wrapped. ignore. #714933
-        ignoreResultList.add("fast/events/option-tab.html"); // http://b/734308
-        ignoreResultList.add("fast/events/window-events-bubble.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/window-events-bubble2.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/window-events-capture.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/drag-into-textarea.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/focus-control-to-page.html"); // http://b/716638
-        ignoreResultList.add("fast/forms/focus2.html"); // http://b/735111
-        ignoreResultList.add("fast/forms/form-data-encoding-2.html"); // charset convert. #516936 ignore, won't fix
-        ignoreResultList.add("fast/forms/form-data-encoding.html"); // charset convert. #516936 ignore, won't fix
-        ignoreResultList.add("fast/forms/input-appearance-maxlength.html"); // execCommand "insertText" not supported
-        ignoreResultList.add("fast/forms/input-select-on-click.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/listbox-onchange.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/listbox-selection.html"); // http://b/735116
-        ignoreResultList.add("fast/forms/onselect-textarea.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
-        ignoreResultList.add("fast/forms/onselect-textfield.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
-        ignoreResultList.add("fast/forms/plaintext-mode-1.html"); // not implemented queryCommandEnabled:BackColor, Undo & Redo
-        ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/search-event-delay.html"); // http://b/735120
-        ignoreResultList.add("fast/forms/select-empty-list.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/select-type-ahead-non-latin.html"); // http://b/735244
-        ignoreResultList.add("fast/forms/selected-index-assert.html"); // not capturing the console messages
-        ignoreResultList.add("fast/forms/selection-functions.html"); // there is extra spacing as the text areas and input boxes fit next to each other on Apple, but are wrapped on our screen.
-        ignoreResultList.add("fast/forms/textarea-appearance-wrap.html"); // Our text areas are a little thinner than Apples. Also RTL test failes
-        ignoreResultList.add("fast/forms/textarea-initial-caret-position.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
-        ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
-        ignoreResultList.add("fast/forms/textarea-paste-newline.html"); // Copy&Paste commands not supported
-        ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/frames/iframe-window-focus.html"); // http://b/735140
-        ignoreResultList.add("fast/frames/frameElement-widthheight.html"); // screen width&height are different
-        ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html"); // screen width&height are different
-        ignoreResultList.add("fast/html/tab-order.html"); // http://b/719289
-        ignoreResultList.add("fast/js/navigator-mimeTypes-length.html"); // dynamic plugins not supported
-        ignoreResultList.add("fast/js/string-capitalization.html"); // http://b/516936
-        ignoreResultList.add("fast/loader/local-JavaScript-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
-        ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
-        ignoreResultList.add("fast/loader/opaque-base-url.html"); // extra spacing because iFrames rendered next to each other on Apple
-        ignoreResultList.add("fast/overflow/scroll-vertical-not-horizontal.html"); // http://b/735196
-        ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html"); // not capturing the console messages
-        ignoreResultList.add("fast/replaced/image-map.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/text/plain-text-line-breaks.html"); // extra spacing because iFrames rendered next to each other on Apple
-        ignoreResultList.add("profiler"); // profiler is not supported
-    }
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
deleted file mode 100644
index 4a47a0e..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.io.File;
-
-import android.app.AlertDialog;
-import android.app.ListActivity;
-import android.content.DialogInterface;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.SimpleAdapter;
-import android.os.Bundle;
-import android.os.Environment;
-
-
-public abstract class FileList extends ListActivity
-{
-	public boolean onKeyDown(int keyCode, KeyEvent event) {
-		switch (keyCode)
-		{
-			case KeyEvent.KEYCODE_DPAD_LEFT:
-				if (mPath.length() > mBaseLength) {
-					File f = new File(mPath);
-					mFocusFile = f.getName();
-					mFocusIndex = 0;
-					f = f.getParentFile();
-					mPath = f.getPath();
-					updateList();
-					return true;
-				}
-				break;
-
-			case KeyEvent.KEYCODE_DPAD_RIGHT:
-				{
-					Map map = (Map) getListView().getItemAtPosition(getListView().getSelectedItemPosition());
-					String path = (String)map.get("path");
-					if ((new File(path)).isDirectory()) {
-						mPath = path;
-				        mFocusFile = null;
-						updateList();
-					} else {
-						processFile(path, false);
-					}
-                    return true;
-				}
-
-			default:
-				break;
-		}
-		return super.onKeyDown(keyCode, event);
-	}
-
-	public void onCreate(Bundle icicle)
-    {
-        super.onCreate(icicle);
-        setupPath();
-        updateList();
-    }
-
-    protected List getData()
-    {
-        List myData = new ArrayList<HashMap>();
-
-        File f = new File(mPath);
-        if (!f.exists()) {
-        	addItem(myData, "!LayoutTests path missing!", "");
-        	return myData;
-        }
-        String[] files = f.list();
-        Arrays.sort(files);
-
-        for (int i = 0; i < files.length; i++) {
-        	StringBuilder sb = new StringBuilder(mPath);
-        	sb.append(File.separatorChar);
-        	sb.append(files[i]);
-        	String path = sb.toString();
-        	File c = new File(path);
-        	if (fileFilter(c)) {
-	        	if (c.isDirectory()) {
-	        		addItem(myData, "<"+files[i]+">", path);
-	        		if (mFocusFile != null && mFocusFile.equals(files[i]))
-	        			mFocusIndex = myData.size()-1;
-	        	}
-	        	else
-	        	    addItem(myData, files[i], path);
-        	}
-        }
-
-        return myData;
-    }
-
-    protected void addItem(List<Map> data, String name, String path)
-    {
-        HashMap temp = new HashMap();
-        temp.put("title", name);
-        temp.put("path", path);
-        data.add(temp);
-    }
-
-    protected void onListItemClick(ListView l, View v, int position, long id)
-    {
-        Map map = (Map) l.getItemAtPosition(position);
-        final String path = (String)map.get("path");
-
-        if ((new File(path)).isDirectory()) {
-            final CharSequence[] items = {"Open", "Run"};
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Select an Action");
-            builder.setSingleChoiceItems(items, -1,
-                    new DialogInterface.OnClickListener(){
-                public void onClick(DialogInterface dialog, int which) {
-                    switch (which) {
-                        case OPEN_DIRECTORY:
-                            dialog.dismiss();
-                            mPath = path;
-                            mFocusFile = null;
-                            updateList();
-                            break;
-                        case RUN_TESTS:
-                            dialog.dismiss();
-                            processDirectory(path, false);
-                            break;
-                    }
-                }
-            });
-            builder.create().show();
-        } else {
-            processFile(path, false);
-        }
-    }
-
-    /*
-     * This function is called when the user has selected a directory in the
-     * list and wants to perform an action on it instead of navigating into
-     * the directory.
-     */
-    abstract void processDirectory(String path, boolean selection);
-    /*
-     * This function is called when the user has selected a file in the
-     * file list. The selected file could be a file or a directory.
-     * The flag indicates if this was from a selection or not.
-     */
-    abstract void processFile(String filename, boolean selection);
-
-    /*
-     * This function is called when the file list is being built. Return
-     * true if the file is to be added to the file list.
-     */
-    abstract boolean fileFilter(File f);
-
-    protected void updateList() {
-        setListAdapter(new SimpleAdapter(this,
-                getData(),
-                android.R.layout.simple_list_item_1,
-                new String[] {"title"},
-                new int[] {android.R.id.text1}));
-        String title = mPath; //.substring(mBaseLength-11); // show the word LayoutTests
-        setTitle(title);
-        getListView().setSelection(mFocusIndex);
-    }
-
-    protected void setupPath() {
-        mPath = Environment.getExternalStorageDirectory() + "/webkit/layout_tests";
-        mBaseLength = mPath.length();
-    }
-
-    protected String mPath;
-    protected int mBaseLength;
-    protected String mFocusFile;
-    protected int mFocusIndex;
-
-    private final static int OPEN_DIRECTORY = 0;
-    private final static int RUN_TESTS = 1;
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
deleted file mode 100644
index b7d2c26..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import com.android.dumprendertree.forwarder.ForwardService;
-
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.regex.Pattern;
-
-public class FsUtils {
-
-    private static final String LOGTAG = "FsUtils";
-    static final String EXTERNAL_DIR = Environment.getExternalStorageDirectory().toString();
-    static final String HTTP_TESTS_PREFIX =
-        EXTERNAL_DIR + "/webkit/layout_tests/http/tests/";
-    static final String HTTPS_TESTS_PREFIX =
-        EXTERNAL_DIR + "/webkit/layout_tests/http/tests/ssl/";
-    static final String HTTP_LOCAL_TESTS_PREFIX =
-        EXTERNAL_DIR + "/webkit/layout_tests/http/tests/local/";
-    static final String HTTP_MEDIA_TESTS_PREFIX =
-        EXTERNAL_DIR + "/webkit/layout_tests/http/tests/media/";
-    static final String HTTP_WML_TESTS_PREFIX =
-        EXTERNAL_DIR + "/webkit/layout_tests/http/tests/wml/";
-
-    private FsUtils() {
-        //no creation of instances
-    }
-
-    /**
-     * @return the number of tests in the list.
-     */
-    public static int writeLayoutTestListRecursively(BufferedOutputStream bos,
-            String dir, boolean ignoreResultsInDir) throws IOException {
-
-        int testCount = 0;
-        Log.v(LOGTAG, "Searching tests under " + dir);
-
-        File d = new File(dir);
-        if (!d.isDirectory()) {
-            throw new AssertionError("A directory expected, but got " + dir);
-        }
-        ignoreResultsInDir |= FileFilter.ignoreResult(dir);
-
-        String[] files = d.list();
-        for (int i = 0; i < files.length; i++) {
-            String s = dir + "/" + files[i];
-
-            File f = new File(s);
-            if (f.isDirectory()) {
-                // If this is not a test directory, we don't recurse into it.
-                if (!FileFilter.isNonTestDir(s)) {
-                    Log.v(LOGTAG, "Recursing on " + s);
-                    testCount += writeLayoutTestListRecursively(bos, s, ignoreResultsInDir);
-                }
-                continue;
-            }
-
-            // If this test should be ignored, we skip it completely.
-            if (FileFilter.ignoreTest(s)) {
-                Log.v(LOGTAG, "Ignoring: " + s);
-                continue;
-            }
-
-            if ((s.toLowerCase().endsWith(".html")
-                    || s.toLowerCase().endsWith(".xml")
-                    || s.toLowerCase().endsWith(".xhtml"))
-                    && !s.endsWith("TEMPLATE.html")) {
-                Log.v(LOGTAG, "Recording " + s);
-                bos.write(s.getBytes());
-                // If the result of this test should be ignored, we still run the test.
-                if (ignoreResultsInDir || FileFilter.ignoreResult(s)) {
-                    bos.write((" IGNORE_RESULT").getBytes());
-                }
-                bos.write('\n');
-                testCount++;
-            }
-        }
-        return testCount;
-    }
-
-    public static void updateTestStatus(String statusFile, String s) {
-        try {
-            BufferedOutputStream bos = new BufferedOutputStream(
-                    new FileOutputStream(statusFile));
-            bos.write(s.getBytes());
-            bos.close();
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Cannot update file " + statusFile);
-        }
-    }
-
-    public static String readTestStatus(String statusFile) {
-        // read out the test name it stopped last time.
-        String status = null;
-        File testStatusFile = new File(statusFile);
-        if(testStatusFile.exists()) {
-            try {
-                BufferedReader inReader = new BufferedReader(
-                        new FileReader(testStatusFile));
-                status = inReader.readLine();
-                inReader.close();
-            } catch (IOException e) {
-                Log.e(LOGTAG, "Error reading test status.", e);
-            }
-        }
-        return status;
-    }
-
-    public static String getTestUrl(String path) {
-        String url = null;
-        if (!path.startsWith(HTTP_TESTS_PREFIX)) {
-            url = "file://" + path;
-        } else {
-            ForwardService.getForwardService().startForwardService();
-            if (path.startsWith(HTTPS_TESTS_PREFIX)) {
-                // still cut the URL after "http/tests/"
-                url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
-            } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
-                    && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
-                    && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
-                url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
-            } else {
-                url = "file://" + path;
-            }
-        }
-        return url;
-    }
-
-    public static boolean diffIgnoreSpaces(String file1, String file2)  throws IOException {
-        BufferedReader br1 = new BufferedReader(new FileReader(file1));
-        BufferedReader br2 = new BufferedReader(new FileReader(file2));
-        boolean same = true;
-        Pattern trailingSpace = Pattern.compile("\\s+$");
-
-        while(true) {
-            String line1 = br1.readLine();
-            String line2 = br2.readLine();
-
-            if (line1 == null && line2 == null)
-                break;
-            if (line1 != null) {
-                line1 = trailingSpace.matcher(line1).replaceAll("");
-            } else {
-                line1 = "";
-            }
-            if (line2 != null) {
-                line2 = trailingSpace.matcher(line2).replaceAll("");
-            } else {
-                line2 = "";
-            }
-            if(!line1.equals(line2)) {
-                same = false;
-                break;
-            }
-        }
-
-        br1.close();
-        br2.close();
-
-        return same;
-    }
-
-    public static boolean isTestPageUrl(String url) {
-        int qmPostion = url.indexOf('?');
-        int slashPostion = url.lastIndexOf('/');
-        if (slashPostion < qmPostion) {
-            String fileName = url.substring(slashPostion + 1, qmPostion);
-            if ("index.html".equals(fileName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static String getLastSegmentInPath(String path) {
-        int endPos = path.lastIndexOf('/');
-        path = path.substring(0, endPos);
-        endPos = path.lastIndexOf('/');
-        return path.substring(endPos + 1);
-    }
-
-    public static void writeDrawTime(String fileName, String url, long[] times) {
-        StringBuffer lineBuffer = new StringBuffer();
-        // grab the last segment of path in url
-        lineBuffer.append(getLastSegmentInPath(url));
-        for (long time : times) {
-            lineBuffer.append('\t');
-            lineBuffer.append(time);
-        }
-        lineBuffer.append('\n');
-        String line = lineBuffer.toString();
-        Log.v(LOGTAG, "logging draw times: " + line);
-        try {
-            FileWriter fw = new FileWriter(fileName, true);
-            fw.write(line);
-            fw.close();
-        } catch (IOException ioe) {
-            Log.e(LOGTAG, "Failed to log draw times", ioe);
-        }
-    }
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java
deleted file mode 100644
index f610f5a..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import android.app.Application;
-
-public class HTMLHostApp extends Application { 
-
-	public HTMLHostApp() {
-    }
-
-    public void onCreate() {
-    }
-
-    public void onTerminate() {
-    }
-	
-}
-
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
deleted file mode 100644
index c936a6c..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-public interface LayoutTestController {
-
-    public void dumpAsText(boolean enablePixelTests);
-    public void dumpChildFramesAsText();
-    public void waitUntilDone();
-    public void notifyDone();
-
-    // Force a redraw of the page
-    public void display();
-    // Used with pixel dumps of content
-    public void testRepaint();
-
-    // If the page title changes, add the information to the output.
-    public void dumpTitleChanges();
-    public void dumpBackForwardList();
-    public void dumpChildFrameScrollPositions();
-    public void dumpEditingCallbacks();
-
-    // Show/Hide window for window.onBlur() testing
-    public void setWindowIsKey(boolean b);
-    // Mac function, used to disable events going to the window
-    public void setMainFrameIsFirstResponder(boolean b);
-
-    public void dumpSelectionRect();
-
-    // invalidate and draw one line at a time of the web view.
-    public void repaintSweepHorizontally();
-    
-    // History testing functions
-    public void keepWebHistory();
-    public void clearBackForwardList();
-    // navigate after page load has finished
-    public void queueBackNavigation(int howfar);
-    public void queueForwardNavigation(int howfar);
-    
-    // Reload when the page load has finished
-    public void queueReload();
-    // Execute the provided script in current context when page load has finished.
-    public void queueScript(String scriptToRunInCurrentContext);
-    // Load the provided URL into the provided frame
-    public void queueLoad(String Url, String frameTarget);
-
-    public void setAcceptsEditing(boolean b);
-
-    // For storage tests
-    public void dumpDatabaseCallbacks();
-    public void setCanOpenWindows();
-
-    // For Geolocation tests
-    public void setGeolocationPermission(boolean allow);
-
-    public void overridePreference(String key, boolean value);
-
-    // For XSSAuditor tests
-    public void setXSSAuditorEnabled(boolean flag);
-
-    // For Geolocation tests
-    public void setMockGeolocationPosition(double latitude, double longitude, double accuracy);
-    public void setMockGeolocationError(int code, String message);
-
-    // For DeviceOrientation tests
-    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
-            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma);
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
deleted file mode 100644
index fb2a1f4..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
+++ /dev/null
@@ -1,80 +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 com.android.dumprendertree;
-
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-
-import junit.framework.TestSuite;
-
-
-/**
- * Instrumentation Test Runner for all DumpRenderTree tests.
- *
- * Running all tests:
- *
- * adb shell am instrument \
- *   -w com.android.dumprendertree.LayoutTestsAutoRunner
- */
-
-public class LayoutTestsAutoRunner extends InstrumentationTestRunner {
-    @Override
-    public TestSuite getAllTests() {
-        TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(LayoutTestsAutoTest.class);
-        suite.addTestSuite(LoadTestsAutoTest.class);
-        return suite;
-    }
-
-    @Override
-    public ClassLoader getLoader() {
-        return LayoutTestsAutoRunner.class.getClassLoader();
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        this.mTestPath = (String) icicle.get("path");
-        String timeout_str = (String) icicle.get("timeout");
-        if (timeout_str != null) {
-            try {
-                this.mTimeoutInMillis = Integer.parseInt(timeout_str);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-
-        String r = icicle.getString("rebaseline");
-        this.mRebaseline = (r != null && r.toLowerCase().equals("true"));
-
-        mJsEngine = icicle.getString("jsengine");
-
-        mPageCyclerSuite = icicle.getString("suite");
-        mPageCyclerForwardHost = icicle.getString("forward");
-        mPageCyclerIteration = icicle.getString("iteration", "5");
-
-        super.onCreate(icicle);
-    }
-
-    String mPageCyclerSuite;
-    String mPageCyclerForwardHost;
-    String mPageCyclerIteration;
-    String mTestPath;
-    int mTimeoutInMillis = 0;
-    boolean mRebaseline;
-    String mJsEngine;
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
deleted file mode 100644
index 3fe4e70..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ /dev/null
@@ -1,494 +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 com.android.dumprendertree;
-
-import com.android.dumprendertree.TestShellActivity.DumpDataType;
-import com.android.dumprendertree.forwarder.AdbUtils;
-import com.android.dumprendertree.forwarder.ForwardService;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Vector;
-
-// TestRecorder creates four files ...
-// - passing tests
-// - failing tests
-// - tests for which results are ignored
-// - tests with no text results available
-// TestRecorder does not have the ability to clear the results.
-class MyTestRecorder {
-    private BufferedOutputStream mBufferedOutputPassedStream;
-    private BufferedOutputStream mBufferedOutputFailedStream;
-    private BufferedOutputStream mBufferedOutputIgnoreResultStream;
-    private BufferedOutputStream mBufferedOutputNoResultStream;
-
-    public void passed(String layout_file) {
-        try {
-            mBufferedOutputPassedStream.write(layout_file.getBytes());
-            mBufferedOutputPassedStream.write('\n');
-            mBufferedOutputPassedStream.flush();
-        } catch(Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    public void failed(String layout_file) {
-        try {
-            mBufferedOutputFailedStream.write(layout_file.getBytes());
-            mBufferedOutputFailedStream.write('\n');
-            mBufferedOutputFailedStream.flush();
-        } catch(Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    public void ignoreResult(String layout_file) {
-        try {
-            mBufferedOutputIgnoreResultStream.write(layout_file.getBytes());
-            mBufferedOutputIgnoreResultStream.write('\n');
-            mBufferedOutputIgnoreResultStream.flush();
-        } catch(Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    public void noResult(String layout_file) {
-        try {
-            mBufferedOutputNoResultStream.write(layout_file.getBytes());
-            mBufferedOutputNoResultStream.write('\n');
-            mBufferedOutputNoResultStream.flush();
-        } catch(Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    public MyTestRecorder(boolean resume) {
-        try {
-            File externalDir = Environment.getExternalStorageDirectory();
-            File resultsPassedFile = new File(externalDir, "layout_tests_passed.txt");
-            File resultsFailedFile = new File(externalDir, "layout_tests_failed.txt");
-            File resultsIgnoreResultFile = new File(externalDir, "layout_tests_ignored.txt");
-            File noExpectedResultFile = new File(externalDir, "layout_tests_nontext.txt");
-
-            mBufferedOutputPassedStream =
-                new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
-            mBufferedOutputFailedStream =
-                new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
-            mBufferedOutputIgnoreResultStream =
-                new BufferedOutputStream(new FileOutputStream(resultsIgnoreResultFile, resume));
-            mBufferedOutputNoResultStream =
-                new BufferedOutputStream(new FileOutputStream(noExpectedResultFile, resume));
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    public void close() {
-        try {
-            mBufferedOutputPassedStream.close();
-            mBufferedOutputFailedStream.close();
-            mBufferedOutputIgnoreResultStream.close();
-            mBufferedOutputNoResultStream.close();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}
-
-
-public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
-
-    private static final String LOGTAG = "LayoutTests";
-    static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-
-    static final String EXTERNAL_DIR = Environment.getExternalStorageDirectory().toString();
-    static final String LAYOUT_TESTS_ROOT = EXTERNAL_DIR + "/webkit/layout_tests/";
-    static final String LAYOUT_TESTS_RESULT_DIR = EXTERNAL_DIR + "/webkit/layout_tests_results/";
-    static final String ANDROID_EXPECTED_RESULT_DIR = EXTERNAL_DIR + "/webkit/expected_results/";
-    static final String LAYOUT_TESTS_LIST_FILE = EXTERNAL_DIR + "/webkit/layout_tests_list.txt";
-    static final String TEST_STATUS_FILE = EXTERNAL_DIR + "/webkit/running_test.txt";
-    static final String LAYOUT_TESTS_RESULTS_REFERENCE_FILES[] = {
-          "results/layout_tests_passed.txt",
-          "results/layout_tests_failed.txt",
-          "results/layout_tests_nontext.txt",
-          "results/layout_tests_crashed.txt",
-          "run_layout_tests.py"
-    };
-
-    static final String LAYOUT_RESULTS_FAILED_RESULT_FILE = "results/layout_tests_failed.txt";
-    static final String LAYOUT_RESULTS_NONTEXT_RESULT_FILE = "results/layout_tests_nontext.txt";
-    static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
-    static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
-
-    private MyTestRecorder mResultRecorder;
-    private Vector<String> mTestList;
-    // Whether we should ignore the result for the corresponding test. Ordered same as mTestList.
-    private Vector<Boolean> mTestListIgnoreResult;
-    private boolean mRebaselineResults;
-    // The JavaScript engine currently in use. This determines which set of Android-specific
-    // expected test results we use.
-    private String mJsEngine;
-    private String mTestPathPrefix;
-    private boolean mFinished;
-    private int mTestCount;
-    private int mResumeIndex;
-
-    public LayoutTestsAutoTest() {
-      super(TestShellActivity.class);
-    }
-
-    private void getTestList() {
-        // Read test list.
-        try {
-            BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE));
-            String line = inReader.readLine();
-            while (line != null) {
-                if (line.startsWith(mTestPathPrefix)) {
-                    String[] components = line.split(" ");
-                    mTestList.add(components[0]);
-                    mTestListIgnoreResult.add(components.length > 1 && components[1].equals("IGNORE_RESULT"));
-                }
-                line = inReader.readLine();
-            }
-            inReader.close();
-            Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s).");
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
-        }
-        mTestCount = mTestList.size();
-    }
-
-    private void resumeTestList() {
-        // read out the test name it stoped last time.
-        try {
-            String line = FsUtils.readTestStatus(TEST_STATUS_FILE);
-            for (int i = 0; i < mTestList.size(); i++) {
-                if (mTestList.elementAt(i).equals(line)) {
-                    mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
-                    mTestListIgnoreResult = new Vector<Boolean>(mTestListIgnoreResult.subList(i+1, mTestListIgnoreResult.size()));
-                    mResumeIndex = i + 1;
-                    break;
-                }
-            }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
-        }
-    }
-
-    private void clearTestStatus() {
-        // Delete TEST_STATUS_FILE
-        try {
-            File f = new File(TEST_STATUS_FILE);
-            if (f.delete())
-                Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
-            else
-                Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
-        }
-    }
-
-    private String getResultFile(String test) {
-        String shortName = test.substring(0, test.lastIndexOf('.'));
-        // Write actual results to result directory.
-        return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
-    }
-
-    // Gets the file which contains WebKit's expected results for this test.
-    private String getExpectedResultFile(String test) {
-        // The generic result is at <path>/<name>-expected.txt
-        // First try the Android-specific result at
-        // platform/android-<js-engine>/<path>/<name>-expected.txt
-        // then
-        // platform/android/<path>/<name>-expected.txt
-        int pos = test.lastIndexOf('.');
-        if (pos == -1)
-            return null;
-        String genericExpectedResult = test.substring(0, pos) + "-expected.txt";
-        String androidExpectedResultsDir = "platform/android-" + mJsEngine + "/";
-        String androidExpectedResult = genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT,
-                LAYOUT_TESTS_ROOT + androidExpectedResultsDir);
-        File f = new File(androidExpectedResult);
-        if (f.exists())
-            return androidExpectedResult;
-        androidExpectedResultsDir = "platform/android/";
-        androidExpectedResult = genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT,
-                LAYOUT_TESTS_ROOT + androidExpectedResultsDir);
-        f = new File(androidExpectedResult);
-        return f.exists() ? androidExpectedResult : genericExpectedResult;
-    }
-
-    // Gets the file which contains the actual results of running the test on
-    // Android, generated by a previous run which set a new baseline.
-    private String getAndroidExpectedResultFile(String expectedResultFile) {
-        return expectedResultFile.replaceFirst(LAYOUT_TESTS_ROOT, ANDROID_EXPECTED_RESULT_DIR);
-    }
-
-    // Wrap up
-    private void failedCase(String file) {
-        Log.w("Layout test: ", file + " failed");
-        mResultRecorder.failed(file);
-    }
-
-    private void passedCase(String file) {
-        Log.v("Layout test:", file + " passed");
-        mResultRecorder.passed(file);
-    }
-
-    private void ignoreResultCase(String file) {
-        Log.v("Layout test:", file + " ignore result");
-        mResultRecorder.ignoreResult(file);
-    }
-
-    private void noResultCase(String file) {
-        Log.v("Layout test:", file + " no expected result");
-        mResultRecorder.noResult(file);
-    }
-
-    private void processResult(String testFile, String actualResultFile, String expectedResultFile, boolean ignoreResult) {
-        Log.v(LOGTAG, "  Processing result: " + testFile);
-
-        if (ignoreResult) {
-            ignoreResultCase(testFile);
-            return;
-        }
-
-        File actual = new File(actualResultFile);
-        File expected = new File(expectedResultFile);
-        if (actual.exists() && expected.exists()) {
-            try {
-                if (FsUtils.diffIgnoreSpaces(actualResultFile, expectedResultFile)) {
-                    passedCase(testFile);
-                } else {
-                    failedCase(testFile);
-                }
-            } catch (FileNotFoundException ex) {
-                Log.e(LOGTAG, "File not found : " + ex.getMessage());
-            } catch (IOException ex) {
-                Log.e(LOGTAG, "IO Error : " + ex.getMessage());
-            }
-            return;
-        }
-
-        if (!expected.exists()) {
-            noResultCase(testFile);
-        }
-    }
-
-    private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult, int testNumber) {
-        activity.setCallback(new TestShellCallback() {
-            public void finished() {
-                synchronized (LayoutTestsAutoTest.this) {
-                    mFinished = true;
-                    LayoutTestsAutoTest.this.notifyAll();
-                }
-            }
-
-            public void timedOut(String url) {
-                Log.v(LOGTAG, "layout timeout: " + url);
-            }
-
-            @Override
-            public void dumpResult(String webViewDump) {
-            }
-        });
-
-        String resultFile = getResultFile(test);
-        if (resultFile == null) {
-            // Simply ignore this test.
-            return;
-        }
-        if (mRebaselineResults) {
-            String expectedResultFile = getExpectedResultFile(test);
-            File f = new File(expectedResultFile);
-            if (f.exists()) {
-                return;  // don't run test and don't overwrite default tests.
-            }
-
-            resultFile = getAndroidExpectedResultFile(expectedResultFile);
-        }
-
-        mFinished = false;
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setClass(activity, TestShellActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test));
-        intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
-        intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
-        intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, mTestCount);
-        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, testNumber);
-        intent.putExtra(TestShellActivity.STOP_ON_REF_ERROR, true);
-        activity.startActivity(intent);
-
-        // Wait until done.
-        synchronized (this) {
-            while(!mFinished){
-                try {
-                    this.wait();
-                } catch (InterruptedException e) { }
-            }
-        }
-
-        if (!mRebaselineResults) {
-            String expectedResultFile = getExpectedResultFile(test);
-            File f = new File(expectedResultFile);
-            if (!f.exists()) {
-                expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
-            }
-
-            processResult(test, resultFile, expectedResultFile, ignoreResult);
-        }
-    }
-
-    // Invokes running of layout tests
-    // and waits till it has finished running.
-    public void executeLayoutTests(boolean resume) {
-        LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
-        // A convenient method to be called by another activity.
-
-        if (runner.mTestPath == null) {
-            Log.e(LOGTAG, "No test specified");
-            return;
-        }
-
-        this.mTestList = new Vector<String>();
-        this.mTestListIgnoreResult = new Vector<Boolean>();
-
-        // Read settings
-        mTestPathPrefix = (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getAbsolutePath();
-        mRebaselineResults = runner.mRebaseline;
-        // V8 is the default JavaScript engine.
-        mJsEngine = runner.mJsEngine == null ? "v8" : runner.mJsEngine;
-
-        int timeout = runner.mTimeoutInMillis;
-        if (timeout <= 0) {
-            timeout = DEFAULT_TIMEOUT_IN_MILLIS;
-        }
-
-        this.mResultRecorder = new MyTestRecorder(resume);
-
-        if (!resume)
-            clearTestStatus();
-
-        getTestList();
-        if (resume)
-            resumeTestList();
-
-        TestShellActivity activity = getActivity();
-        activity.setDefaultDumpDataType(DumpDataType.EXT_REPR);
-
-        // Run tests.
-        for (int i = 0; i < mTestList.size(); i++) {
-            String s = mTestList.elementAt(i);
-            boolean ignoreResult = mTestListIgnoreResult.elementAt(i);
-            FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
-            // Run tests
-            // i is 0 based, but test count is 1 based so add 1 to i here.
-            runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult,
-                    i + 1 + mResumeIndex);
-        }
-
-        FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-        ForwardService.getForwardService().stopForwardService();
-        activity.finish();
-    }
-
-    private String getTestPath() {
-        LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
-
-        String test_path = LAYOUT_TESTS_ROOT;
-        if (runner.mTestPath != null) {
-            test_path += runner.mTestPath;
-        }
-        test_path = new File(test_path).getAbsolutePath();
-        Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-
-        return test_path;
-    }
-
-    public void generateTestList() {
-        try {
-            File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
-            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
-            FsUtils.writeLayoutTestListRecursively(bos, getTestPath(), false); // Don't ignore results
-            bos.flush();
-            bos.close();
-       } catch (Exception e) {
-           Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
-       }
-    }
-
-    // Running all the layout tests at once sometimes
-    // causes the dumprendertree to run out of memory.
-    // So, additional tests are added to run the tests
-    // in chunks.
-    public void startLayoutTests() {
-        try {
-            File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
-            if (!tests_list.exists())
-              generateTestList();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-
-        executeLayoutTests(false);
-    }
-
-    public void resumeLayoutTests() {
-        executeLayoutTests(true);
-    }
-
-    public void copyResultsAndRunnerAssetsToCache() {
-        try {
-            Context targetContext = getInstrumentation().getTargetContext();
-            File cacheDir = targetContext.getCacheDir();
-
-            for( int i=0; i< LAYOUT_TESTS_RESULTS_REFERENCE_FILES.length; i++) {
-                InputStream in = targetContext.getAssets().open(
-                        LAYOUT_TESTS_RESULTS_REFERENCE_FILES[i]);
-                OutputStream out = new FileOutputStream(new File(cacheDir,
-                        LAYOUT_TESTS_RESULTS_REFERENCE_FILES[i]));
-
-                byte[] buf = new byte[2048];
-                int len;
-
-                while ((len = in.read(buf)) >= 0 ) {
-                    out.write(buf, 0, len);
-                }
-                out.close();
-                in.close();
-            }
-        }catch (IOException e) {
-          e.printStackTrace();
-        }
-
-    }
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
deleted file mode 100644
index 4b86a0b..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ /dev/null
@@ -1,298 +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 com.android.dumprendertree;
-
-import com.android.dumprendertree.forwarder.AdbUtils;
-import com.android.dumprendertree.forwarder.ForwardServer;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.Environment;
-import android.os.Process;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
-
-    private final static String LOGTAG = "LoadTest";
-    private final static String LOAD_TEST_RESULT =
-        Environment.getExternalStorageDirectory() + "/load_test_result.txt";
-    private final static int MAX_GC_WAIT_SEC = 10;
-    private final static int LOCAL_PORT = 17171;
-    private boolean mFinished;
-    static final String LOAD_TEST_RUNNER_FILES[] = {
-        "run_page_cycler.py"
-    };
-    private ForwardServer mForwardServer;
-
-    public LoadTestsAutoTest() {
-        super(TestShellActivity.class);
-    }
-
-    // This function writes the result of the layout test to
-    // Am status so that it can be picked up from a script.
-    public void passOrFailCallback(String file, boolean result) {
-        Instrumentation inst = getInstrumentation();
-        Bundle bundle = new Bundle();
-        bundle.putBoolean(file, result);
-        inst.sendStatus(0, bundle);
-    }
-
-    private String setUpForwarding(String forwardInfo, String suite, String iteration) throws IOException {
-        // read forwarding information first
-        Pattern forwardPattern = Pattern.compile("(.*):(\\d+)/(.*)/");
-        Matcher matcher = forwardPattern.matcher(forwardInfo);
-        if (!matcher.matches()) {
-            throw new RuntimeException("Invalid forward information");
-        }
-        String host = matcher.group(1);
-        int port = Integer.parseInt(matcher.group(2));
-        mForwardServer = new ForwardServer(LOCAL_PORT, AdbUtils.resolve(host), port);
-        mForwardServer.start();
-        return String.format("http://127.0.0.1:%d/%s/%s/start.html?auto=1&iterations=%s",
-                LOCAL_PORT, matcher.group(3), suite, iteration);
-    }
-
-    // Invokes running of layout tests
-    // and waits till it has finished running.
-    public void runPageCyclerTest() throws IOException {
-        LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
-
-        if (runner.mPageCyclerSuite != null) {
-            // start forwarder to use page cycler suites hosted on external web server
-            if (runner.mPageCyclerForwardHost == null) {
-                throw new RuntimeException("no forwarder information provided");
-            }
-            runner.mTestPath = setUpForwarding(runner.mPageCyclerForwardHost,
-                    runner.mPageCyclerSuite, runner.mPageCyclerIteration);
-            Log.d(LOGTAG, "using path: " + runner.mTestPath);
-        }
-
-        if (runner.mTestPath == null) {
-            throw new RuntimeException("No test specified");
-        }
-
-        final TestShellActivity activity = (TestShellActivity) getActivity();
-
-        Log.v(LOGTAG, "About to run tests, calling gc first...");
-        freeMem();
-
-        // Run tests
-        runTestAndWaitUntilDone(activity, runner.mTestPath, runner.mTimeoutInMillis);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-
-            @Override
-            public void run() {
-                activity.clearCache();
-            }
-        });
-        if (mForwardServer != null) {
-            mForwardServer.stop();
-            mForwardServer = null;
-        }
-        try {
-            Thread.sleep(5000);
-        } catch (InterruptedException e) {
-        }
-        dumpMemoryInfo();
-
-        // Kill activity
-        activity.finish();
-    }
-
-    private void freeMem() {
-        Log.v(LOGTAG, "freeMem: calling gc...");
-        final CountDownLatch latch = new CountDownLatch(1);
-        @SuppressWarnings("unused")
-        Object dummy = new Object() {
-            // this object instance is used to track gc
-            @Override
-            protected void finalize() throws Throwable {
-                latch.countDown();
-                super.finalize();
-            }
-        };
-        dummy = null;
-        System.gc();
-        try {
-            if (!latch.await(MAX_GC_WAIT_SEC, TimeUnit.SECONDS)) {
-                Log.w(LOGTAG, "gc did not happen in 10s");
-            }
-        } catch (InterruptedException e) {
-            //ignore
-        }
-    }
-
-    private void printRow(PrintStream ps, String format, Object...objs) {
-        ps.println(String.format(format, objs));
-    }
-
-    private void dumpMemoryInfo() {
-        try {
-            freeMem();
-            Log.v(LOGTAG, "Dumping memory information.");
-
-            FileOutputStream out = new FileOutputStream(LOAD_TEST_RESULT, true);
-            PrintStream ps = new PrintStream(out);
-
-            ps.print("\n\n\n");
-            ps.println("** MEMINFO in pid " + Process.myPid()
-                    + " [com.android.dumprendertree] **");
-            String formatString = "%17s %8s %8s %8s %8s";
-
-            long nativeMax = Debug.getNativeHeapSize() / 1024;
-            long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
-            long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
-            Runtime runtime = Runtime.getRuntime();
-            long dalvikMax = runtime.totalMemory() / 1024;
-            long dalvikFree = runtime.freeMemory() / 1024;
-            long dalvikAllocated = dalvikMax - dalvikFree;
-
-
-            Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
-            Debug.getMemoryInfo(memInfo);
-
-            final int nativeShared = memInfo.nativeSharedDirty;
-            final int dalvikShared = memInfo.dalvikSharedDirty;
-            final int otherShared = memInfo.otherSharedDirty;
-
-            final int nativePrivate = memInfo.nativePrivateDirty;
-            final int dalvikPrivate = memInfo.dalvikPrivateDirty;
-            final int otherPrivate = memInfo.otherPrivateDirty;
-
-            printRow(ps, formatString, "", "native", "dalvik", "other", "total");
-            printRow(ps, formatString, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
-            printRow(ps, formatString, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
-                    nativeAllocated + dalvikAllocated);
-            printRow(ps, formatString, "free:", nativeFree, dalvikFree, "N/A",
-                    nativeFree + dalvikFree);
-
-            printRow(ps, formatString, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
-                    memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
-
-            printRow(ps, formatString, "(shared dirty):", nativeShared, dalvikShared, otherShared,
-                    nativeShared + dalvikShared + otherShared);
-            printRow(ps, formatString, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
-                    nativePrivate + dalvikPrivate + otherPrivate);
-            ps.print("\n\n\n");
-            ps.flush();
-            ps.close();
-            out.flush();
-            out.close();
-        } catch (IOException e) {
-            Log.e(LOGTAG, e.getMessage());
-        }
-    }
-
-    // A convenient method to be called by another activity.
-    private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) {
-        activity.setCallback(new TestShellCallback() {
-            @Override
-            public void finished() {
-                synchronized (LoadTestsAutoTest.this) {
-                    mFinished = true;
-                    LoadTestsAutoTest.this.notifyAll();
-                }
-            }
-
-            @Override
-            public void timedOut(String url) {
-            }
-
-            @Override
-            public void dumpResult(String webViewDump) {
-                String lines[] = webViewDump.split("\\r?\\n");
-                for (String line : lines) {
-                    line = line.trim();
-                    // parse for a line like this:
-                    // totals:   9620.00 11947.00    10099.75    380.38
-                    // and return the 3rd number, which is mean
-                    if (line.startsWith("totals:")) {
-                        line = line.substring(7).trim(); // strip "totals:"
-                        String[] numbers = line.split("\\s+");
-                        if (numbers.length == 4) {
-                            Bundle b = new Bundle();
-                            b.putString("mean", numbers[2]);
-                            getInstrumentation().sendStatus(Activity.RESULT_FIRST_USER, b);
-                        }
-                    }
-                }
-            }
-        });
-
-        mFinished = false;
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setClass(activity, TestShellActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, url);
-        intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
-        intent.putExtra(TestShellActivity.RESULT_FILE, LOAD_TEST_RESULT);
-        activity.startActivity(intent);
-
-        // Wait until done.
-        synchronized (this) {
-            while(!mFinished) {
-                try {
-                    this.wait();
-                } catch (InterruptedException e) { }
-            }
-        }
-    }
-
-    public void copyRunnerAssetsToCache() {
-        try {
-            Context targetContext = getInstrumentation().getTargetContext();
-            File cacheDir = targetContext.getCacheDir();
-
-            for( int i=0; i< LOAD_TEST_RUNNER_FILES.length; i++) {
-                InputStream in = targetContext.getAssets().open(
-                        LOAD_TEST_RUNNER_FILES[i]);
-                OutputStream out = new FileOutputStream(
-                        new File(cacheDir, LOAD_TEST_RUNNER_FILES[i]));
-
-                byte[] buf = new byte[2048];
-                int len;
-
-                while ((len = in.read(buf)) >= 0 ) {
-                    out.write(buf, 0, len);
-                }
-                out.close();
-                in.close();
-            }
-        }catch (IOException e) {
-          e.printStackTrace();
-        }
-
-    }
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
deleted file mode 100644
index 0b00d65..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-
-public class Menu extends FileList {
-
-    private static final int MENU_START = 0x01;
-    private static String LOGTAG = "MenuActivity";
-    static final String LAYOUT_TESTS_LIST_FILE =
-        Environment.getExternalStorageDirectory() + "/android/layout_tests_list.txt";
-
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-    }
-
-    boolean fileFilter(File f) {
-    	if (f.getName().startsWith("."))
-    		return false;
-    	if (f.getName().equalsIgnoreCase("resources"))
-    		return false;
-    	if (f.isDirectory())
-    		return true;
-    	if (f.getPath().toLowerCase().endsWith("ml"))
-    		return true;
-    	return false;
-    }
-
-    void processFile(String filename, boolean selection) {
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setClass(this, TestShellActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, "file://" + filename);
-        intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, 1);
-        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 1);
-        startActivity(intent);
-    }
-
-    @Override
-    void processDirectory(String path, boolean selection) {
-        int testCount = generateTestList(path);
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setClass(this, TestShellActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.UI_AUTO_TEST, LAYOUT_TESTS_LIST_FILE);
-        intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, testCount);
-        // TestShellActivity will process this intent once and increment the test index
-        // before running the first test, so pass 0 here to allow for that.
-        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 0);
-        startActivity(intent);
-    }
-
-    private int generateTestList(String path) {
-        int testCount = 0;
-        try {
-            File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
-            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
-            testCount = FsUtils.writeLayoutTestListRecursively(
-                    bos, path, false); // Don't ignore results
-            bos.flush();
-            bos.close();
-       } catch (Exception e) {
-           Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
-       }
-       return testCount;
-    }
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
deleted file mode 100644
index 22b587f..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import android.app.Activity;
-import android.app.ActivityThread;
-import android.graphics.Bitmap;
-import android.net.http.SslError;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.view.ViewGroup;
-import android.webkit.HttpAuthHandler;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.webkit.WebSettings.LayoutAlgorithm;
-import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
-
-public class ReliabilityTestActivity extends Activity {
-
-    public static final String TEST_URL_ACTION = "com.andrdoid.dumprendertree.TestUrlAction";
-    public static final String PARAM_URL = "URL";
-    public static final String PARAM_TIMEOUT = "Timeout";
-    public static final int RESULT_TIMEOUT = 0xDEAD;
-    public static final int MSG_TIMEOUT = 0xC001;
-    public static final int MSG_NAVIGATE = 0xC002;
-    public static final String MSG_NAV_URL = "url";
-    public static final String MSG_NAV_LOGTIME = "logtime";
-
-    private static final String LOGTAG = "ReliabilityTestActivity";
-
-    private WebView webView;
-    private SimpleWebViewClient webViewClient;
-    private SimpleChromeClient chromeClient;
-    private Handler handler;
-    private boolean timeoutFlag;
-    private boolean logTime;
-    private boolean pageDone;
-    private Object pageDoneLock;
-    private int pageStartCount;
-    private int manualDelay;
-    private long startTime;
-    private long pageLoadTime;
-    private PageDoneRunner pageDoneRunner = new PageDoneRunner();
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        Log.v(LOGTAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
-
-        LinearLayout contentView = new LinearLayout(this);
-        contentView.setOrientation(LinearLayout.VERTICAL);
-        setContentView(contentView);
-        setTitle("Idle");
-
-        webView = new WebView(this);
-        webView.getSettings().setJavaScriptEnabled(true);
-        webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
-        webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
-
-        webViewClient = new SimpleWebViewClient();
-        chromeClient = new SimpleChromeClient();
-        webView.setWebViewClient(webViewClient);
-        webView.setWebChromeClient(chromeClient);
-
-        contentView.addView(webView, new LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT, 0.0f));
-
-        handler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case MSG_TIMEOUT:
-                        handleTimeout();
-                        return;
-                    case MSG_NAVIGATE:
-                        manualDelay = msg.arg2;
-                        navigate(msg.getData().getString(MSG_NAV_URL), msg.arg1);
-                        logTime = msg.getData().getBoolean(MSG_NAV_LOGTIME);
-                        return;
-                }
-            }
-        };
-
-        pageDoneLock = new Object();
-    }
-
-    public void reset() {
-        synchronized (pageDoneLock) {
-            pageDone = false;
-        }
-        timeoutFlag = false;
-        pageStartCount = 0;
-        chromeClient.resetJsTimeout();
-    }
-
-    private void navigate(String url, int timeout) {
-        if(url == null) {
-            Log.v(LOGTAG, "URL is null, cancelling...");
-            finish();
-        }
-        webView.stopLoading();
-        if(logTime) {
-            webView.clearCache(true);
-        }
-        startTime = System.currentTimeMillis();
-        Log.v(LOGTAG, "Navigating to URL: " + url);
-        webView.loadUrl(url);
-
-        if(timeout != 0) {
-            //set a timer with specified timeout (in ms)
-            handler.sendMessageDelayed(handler.obtainMessage(MSG_TIMEOUT),
-                    timeout);
-        }
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
-        webView.clearCache(true);
-        webView.destroy();
-    }
-
-    private boolean isPageDone() {
-        synchronized (pageDoneLock) {
-            return pageDone;
-        }
-    }
-
-    private void setPageDone(boolean pageDone) {
-        synchronized (pageDoneLock) {
-            this.pageDone = pageDone;
-            pageDoneLock.notifyAll();
-        }
-    }
-
-    private void handleTimeout() {
-        int progress = webView.getProgress();
-        webView.stopLoading();
-        Log.v(LOGTAG, "Page timeout triggered, progress = " + progress);
-        timeoutFlag = true;
-        handler.postDelayed(pageDoneRunner, manualDelay);
-    }
-
-    public boolean waitUntilDone() {
-        validateNotAppThread();
-        synchronized (pageDoneLock) {
-            while(!isPageDone()) {
-                try {
-                    pageDoneLock.wait();
-                } catch (InterruptedException ie) {
-                    //no-op
-                }
-            }
-        }
-        return timeoutFlag;
-    }
-
-    public Handler getHandler() {
-        return handler;
-    }
-
-    private final void validateNotAppThread() {
-        if (Looper.myLooper() == Looper.getMainLooper()) {
-            throw new RuntimeException(
-                "This method can not be called from the main application thread");
-        }
-    }
-
-    public long getPageLoadTime() {
-        return pageLoadTime;
-    }
-
-    class SimpleWebViewClient extends WebViewClient {
-
-        @Override
-        public void onReceivedError(WebView view, int errorCode, String description,
-                String failingUrl) {
-            Log.v(LOGTAG, "Received WebCore error: code=" + errorCode
-                    + ", description=" + description
-                    + ", url=" + failingUrl);
-        }
-
-        @Override
-        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-            //ignore certificate error
-            Log.v(LOGTAG, "Received SSL error: " + error.toString());
-            handler.proceed();
-        }
-
-        @Override
-        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,
-                String realm) {
-            // cancel http auth request
-            handler.cancel();
-        }
-
-        @Override
-        public void onPageStarted(WebView view, String url, Bitmap favicon) {
-            pageStartCount++;
-            Log.v(LOGTAG, "onPageStarted: " + url);
-        }
-
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            Log.v(LOGTAG, "onPageFinished: " + url);
-            // let handleTimeout take care of finishing the page
-            if(!timeoutFlag)
-                handler.postDelayed(new WebViewStatusChecker(), 500);
-        }
-    }
-
-    class SimpleChromeClient extends WebChromeClient {
-
-        private int timeoutCounter = 0;
-
-        @Override
-        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
-                JsPromptResult result) {
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsTimeout() {
-            timeoutCounter++;
-            Log.v(LOGTAG, "JavaScript timeout, count=" + timeoutCounter);
-            return timeoutCounter > 2;
-        }
-
-        public void resetJsTimeout() {
-            timeoutCounter = 0;
-        }
-
-        @Override
-        public void onReceivedTitle(WebView view, String title) {
-            ReliabilityTestActivity.this.setTitle(title);
-        }
-    }
-
-    class WebViewStatusChecker implements Runnable {
-
-        private int initialStartCount;
-
-        public WebViewStatusChecker() {
-            initialStartCount = pageStartCount;
-        }
-
-        public void run() {
-            if (initialStartCount == pageStartCount && !isPageDone()) {
-                handler.removeMessages(MSG_TIMEOUT);
-                webView.stopLoading();
-                handler.postDelayed(pageDoneRunner, manualDelay);
-            }
-        }
-    }
-
-    class PageDoneRunner implements Runnable {
-
-        public void run() {
-            Log.v(LOGTAG, "Finishing URL: " + webView.getUrl());
-            pageLoadTime = System.currentTimeMillis() - startTime;
-            setPageDone(true);
-        }
-    }
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
deleted file mode 100644
index 42d6457..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import com.android.dumprendertree.forwarder.ForwardService;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.http.SslError;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.webkit.ConsoleMessage;
-import android.webkit.CookieManager;
-import android.webkit.GeolocationPermissions;
-import android.webkit.HttpAuthHandler;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebSettingsClassic;
-import android.webkit.WebStorage;
-import android.webkit.WebView;
-import android.webkit.WebViewClassic;
-import android.webkit.WebViewClient;
-import android.widget.LinearLayout;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Vector;
-
-public class TestShellActivity extends Activity implements LayoutTestController {
-
-    static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP}
-
-    // String constants for use with layoutTestController.overridePreferences
-    private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED =
-            "WebKitOfflineWebApplicationCacheEnabled";
-    private final String WEBKIT_USES_PAGE_CACHE_PREFERENCE_KEY = "WebKitUsesPageCachePreferenceKey";
-
-    public class AsyncHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == MSG_TIMEOUT) {
-                mTimedOut = true;
-                mWebView.stopLoading();
-                if (mCallback != null)
-                    mCallback.timedOut(mWebView.getUrl());
-                if (!mRequestedWebKitData) {
-                    requestWebKitData();
-                } else {
-                    // if timed out and webkit data has been dumped before
-                    // finish directly
-                    finished();
-                }
-                return;
-            } else if (msg.what == MSG_WEBKIT_DATA) {
-                Log.v(LOGTAG, "Received WebView dump data");
-                mHandler.removeMessages(MSG_DUMP_TIMEOUT);
-                TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
-                return;
-            } else if (msg.what == MSG_DUMP_TIMEOUT) {
-                throw new RuntimeException("WebView dump timeout, is it pegged?");
-            }
-            super.handleMessage(msg);
-        }
-    }
-
-    public void requestWebKitData() {
-        setDumpTimeout(DUMP_TIMEOUT_MS);
-        Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
-
-        if (mRequestedWebKitData)
-            throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
-
-        mRequestedWebKitData = true;
-        Log.v(LOGTAG, "message sent to WebView to dump text.");
-        switch (mDumpDataType) {
-            case DUMP_AS_TEXT:
-                callback.arg1 = mDumpTopFrameAsText ? 1 : 0;
-                callback.arg2 = mDumpChildFramesAsText ? 1 : 0;
-                mWebViewClassic.documentAsText(callback);
-                break;
-            case EXT_REPR:
-                mWebViewClassic.externalRepresentation(callback);
-                break;
-            default:
-                finished();
-                break;
-        }
-    }
-
-    private void setDumpTimeout(long timeout) {
-        Log.v(LOGTAG, "setting dump timeout at " + timeout);
-        Message msg = mHandler.obtainMessage(MSG_DUMP_TIMEOUT);
-        mHandler.sendMessageDelayed(msg, timeout);
-    }
-
-    public void clearCache() {
-      mWebView.freeMemory();
-    }
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        requestWindowFeature(Window.FEATURE_PROGRESS);
-
-        LinearLayout contentView = new LinearLayout(this);
-        contentView.setOrientation(LinearLayout.VERTICAL);
-        setContentView(contentView);
-
-        CookieManager.setAcceptFileSchemeCookies(true);
-        mWebView = new WebView(this);
-        mWebViewClassic = WebViewClassic.fromWebView(mWebView);
-        mEventSender = new WebViewEventSender(mWebView);
-        mCallbackProxy = new CallbackProxy(mEventSender, this);
-
-        mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
-        mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
-        setupWebViewForLayoutTests(mWebView, mCallbackProxy);
-
-        contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0f));
-
-        mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-
-        // Expose window.gc function to JavaScript. JSC build exposes
-        // this function by default, but V8 requires the flag to turn it on.
-        // WebView::setJsFlags is noop in JSC build.
-        mWebViewClassic.setJsFlags("--expose_gc");
-
-        mHandler = new AsyncHandler();
-
-        Intent intent = getIntent();
-        if (intent != null) {
-            executeIntent(intent);
-        }
-
-        // This is asynchronous, but it gets processed by WebCore before it starts loading pages.
-        mWebViewClassic.setUseMockDeviceOrientation();
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        executeIntent(intent);
-    }
-
-    private void executeIntent(Intent intent) {
-        resetTestStatus();
-        if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
-            return;
-        }
-
-        mTotalTestCount = intent.getIntExtra(TOTAL_TEST_COUNT, mTotalTestCount);
-        mCurrentTestNumber = intent.getIntExtra(CURRENT_TEST_NUMBER, mCurrentTestNumber);
-
-        mTestUrl = intent.getStringExtra(TEST_URL);
-        if (mTestUrl == null) {
-            mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST);
-            if(mUiAutoTestPath != null) {
-                beginUiAutoTest();
-            }
-            return;
-        }
-
-        mResultFile = intent.getStringExtra(RESULT_FILE);
-        mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
-        mStopOnRefError = intent.getBooleanExtra(STOP_ON_REF_ERROR, false);
-        setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount);
-        float ratio = (float)mCurrentTestNumber / mTotalTestCount;
-        int progress = (int)(ratio * Window.PROGRESS_END);
-        getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress);
-
-        Log.v(LOGTAG, "  Loading " + mTestUrl);
-
-        if (mTestUrl.contains("/dumpAsText/")) {
-            dumpAsText(false);
-        }
-
-        mWebView.loadUrl(mTestUrl);
-
-        if (mTimeoutInMillis > 0) {
-            // Create a timeout timer
-            Message m = mHandler.obtainMessage(MSG_TIMEOUT);
-            mHandler.sendMessageDelayed(m, mTimeoutInMillis);
-        }
-    }
-
-    private void beginUiAutoTest() {
-        try {
-            mTestListReader = new BufferedReader(
-                    new FileReader(mUiAutoTestPath));
-        } catch (IOException ioe) {
-            Log.e(LOGTAG, "Failed to open test list for read.", ioe);
-            finishUiAutoTest();
-            return;
-        }
-        moveToNextTest();
-    }
-
-    private void finishUiAutoTest() {
-        try {
-            if(mTestListReader != null)
-                mTestListReader.close();
-        } catch (IOException ioe) {
-            Log.w(LOGTAG, "Failed to close test list file.", ioe);
-        }
-        ForwardService.getForwardService().stopForwardService();
-        finished();
-    }
-
-    private void moveToNextTest() {
-        String url = null;
-        try {
-            url = mTestListReader.readLine();
-        } catch (IOException ioe) {
-            Log.e(LOGTAG, "Failed to read next test.", ioe);
-            finishUiAutoTest();
-            return;
-        }
-        if (url == null) {
-            mUiAutoTestPath = null;
-            finishUiAutoTest();
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setMessage("All tests finished. Exit?")
-                   .setCancelable(false)
-                   .setPositiveButton("Yes", new OnClickListener(){
-                       @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                           TestShellActivity.this.finish();
-                       }
-                   })
-                   .setNegativeButton("No", new OnClickListener(){
-                       @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                           dialog.cancel();
-                       }
-                   });
-            builder.create().show();
-            return;
-        }
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
-        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, ++mCurrentTestNumber);
-        intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
-        executeIntent(intent);
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        mWebView.stopLoading();
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mWebView.destroy();
-        mWebView = null;
-        mWebViewClassic = null;
-    }
-
-    @Override
-    public void onLowMemory() {
-        super.onLowMemory();
-        Log.e(LOGTAG, "Low memory, clearing caches");
-        mWebView.freeMemory();
-    }
-
-    // Dump the page
-    public void dump(boolean timeout, String webkitData) {
-        mDumpWebKitData = true;
-        if (mResultFile == null || mResultFile.length() == 0) {
-            finished();
-            return;
-        }
-
-        if (mCallback != null) {
-            mCallback.dumpResult(webkitData);
-        }
-
-        try {
-            File parentDir = new File(mResultFile).getParentFile();
-            if (!parentDir.exists()) {
-                parentDir.mkdirs();
-            }
-
-            FileOutputStream os = new FileOutputStream(mResultFile);
-            if (timeout) {
-                Log.w("Layout test: Timeout", mResultFile);
-                os.write(TIMEOUT_STR.getBytes());
-                os.write('\n');
-            }
-            if (mDumpTitleChanges)
-                os.write(mTitleChanges.toString().getBytes());
-            if (mDialogStrings != null)
-                os.write(mDialogStrings.toString().getBytes());
-            mDialogStrings = null;
-            if (mDatabaseCallbackStrings != null)
-                os.write(mDatabaseCallbackStrings.toString().getBytes());
-            mDatabaseCallbackStrings = null;
-            if (mConsoleMessages != null)
-                os.write(mConsoleMessages.toString().getBytes());
-            mConsoleMessages = null;
-            if (webkitData != null)
-                os.write(webkitData.getBytes());
-            os.flush();
-            os.close();
-        } catch (IOException ex) {
-            Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage());
-        }
-
-        finished();
-    }
-
-    public void setCallback(TestShellCallback callback) {
-        mCallback = callback;
-    }
-
-    public boolean finished() {
-        if (canMoveToNextTest()) {
-            mHandler.removeMessages(MSG_TIMEOUT);
-            if (mUiAutoTestPath != null) {
-                //don't really finish here
-                moveToNextTest();
-            } else {
-                if (mCallback != null) {
-                    mCallback.finished();
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) {
-        mDefaultDumpDataType = defaultDumpDataType;
-    }
-
-    // .......................................
-    // LayoutTestController Functions
-    @Override
-    public void dumpAsText(boolean enablePixelTests) {
-        // Added after webkit update to r63859. See trac.webkit.org/changeset/63730.
-        if (enablePixelTests) {
-            Log.v(LOGTAG, "dumpAsText(enablePixelTests == true) not implemented on Android!");
-        }
-
-        mDumpDataType = DumpDataType.DUMP_AS_TEXT;
-        mDumpTopFrameAsText = true;
-        if (mWebView != null) {
-            String url = mWebView.getUrl();
-            Log.v(LOGTAG, "dumpAsText called: "+url);
-        }
-    }
-
-    @Override
-    public void dumpChildFramesAsText() {
-        mDumpDataType = DumpDataType.DUMP_AS_TEXT;
-        mDumpChildFramesAsText = true;
-        if (mWebView != null) {
-            String url = mWebView.getUrl();
-            Log.v(LOGTAG, "dumpChildFramesAsText called: "+url);
-        }
-    }
-
-    @Override
-    public void waitUntilDone() {
-        mWaitUntilDone = true;
-        String url = mWebView.getUrl();
-        Log.v(LOGTAG, "waitUntilDone called: " + url);
-    }
-
-    @Override
-    public void notifyDone() {
-        String url = mWebView.getUrl();
-        Log.v(LOGTAG, "notifyDone called: " + url);
-        if (mWaitUntilDone) {
-            mWaitUntilDone = false;
-            if (!mRequestedWebKitData && !mTimedOut && !finished()) {
-                requestWebKitData();
-            }
-        }
-    }
-
-    @Override
-    public void display() {
-        mWebView.invalidate();
-    }
-
-    @Override
-    public void clearBackForwardList() {
-        mWebView.clearHistory();
-
-    }
-
-    @Override
-    public void dumpBackForwardList() {
-        //printf("\n============== Back Forward List ==============\n");
-        // mWebHistory
-        //printf("===============================================\n");
-
-    }
-
-    @Override
-    public void dumpChildFrameScrollPositions() {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void dumpEditingCallbacks() {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void dumpSelectionRect() {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void dumpTitleChanges() {
-        if (!mDumpTitleChanges) {
-            mTitleChanges = new StringBuffer();
-        }
-        mDumpTitleChanges = true;
-    }
-
-    @Override
-    public void keepWebHistory() {
-        if (!mKeepWebHistory) {
-            mWebHistory = new Vector();
-        }
-        mKeepWebHistory = true;
-    }
-
-    @Override
-    public void queueBackNavigation(int howfar) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void queueForwardNavigation(int howfar) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void queueLoad(String Url, String frameTarget) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void queueReload() {
-        mWebView.reload();
-    }
-
-    @Override
-    public void queueScript(String scriptToRunInCurrentContext) {
-        mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
-    }
-
-    @Override
-    public void repaintSweepHorizontally() {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void setAcceptsEditing(boolean b) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void setMainFrameIsFirstResponder(boolean b) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void setWindowIsKey(boolean b) {
-        // This is meant to show/hide the window. The best I can find
-        // is setEnabled()
-        mWebView.setEnabled(b);
-    }
-
-    @Override
-    public void testRepaint() {
-        mWebView.invalidate();
-    }
-
-    @Override
-    public void dumpDatabaseCallbacks() {
-        Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
-        mDumpDatabaseCallbacks = true;
-    }
-
-    @Override
-    public void setCanOpenWindows() {
-        Log.v(LOGTAG, "setCanOpenWindows called.");
-        mCanOpenWindows = true;
-    }
-
-    @Override
-    public void setMockGeolocationPosition(double latitude, double longitude, double accuracy) {
-        WebViewClassic.fromWebView(mWebView).setMockGeolocationPosition(latitude, longitude,
-                accuracy);
-    }
-
-    @Override
-    public void setMockGeolocationError(int code, String message) {
-        WebViewClassic.fromWebView(mWebView).setMockGeolocationError(code, message);
-    }
-
-    @Override
-    public void setGeolocationPermission(boolean allow) {
-        Log.v(LOGTAG, "setGeolocationPermission() allow=" + allow);
-        WebViewClassic.fromWebView(mWebView).setMockGeolocationPermission(allow);
-    }
-
-    @Override
-    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
-            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
-        WebViewClassic.fromWebView(mWebView).setMockDeviceOrientation(canProvideAlpha, alpha,
-                canProvideBeta, beta, canProvideGamma, gamma);
-    }
-
-    @Override
-    public void overridePreference(String key, boolean value) {
-        // TODO: We should look up the correct WebView for the frame which
-        // called the layoutTestController method. Currently, we just use the
-        // WebView for the main frame. EventSender suffers from the same
-        // problem.
-        if (WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED.equals(key)) {
-            mWebViewClassic.getSettings().setAppCacheEnabled(value);
-        } else if (WEBKIT_USES_PAGE_CACHE_PREFERENCE_KEY.equals(key)) {
-            // Cache the maximum possible number of pages.
-            mWebViewClassic.getSettings().setPageCacheCapacity(Integer.MAX_VALUE);
-        } else {
-            Log.w(LOGTAG, "LayoutTestController.overridePreference(): " +
-                  "Unsupported preference '" + key + "'");
-        }
-    }
-
-    @Override
-    public void setXSSAuditorEnabled (boolean flag) {
-        mWebViewClassic.getSettings().setXSSAuditorEnabled(flag);
-    }
-
-    private final WebViewClient mViewClient = new WebViewClient(){
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            Log.v(LOGTAG, "onPageFinished, url=" + url);
-            mPageFinished = true;
-
-            // Calling finished() will check if we've met all the conditions for completing
-            // this test and move to the next one if we are ready. Otherwise we ask WebCore to
-            // dump the page.
-            if (finished()) {
-                return;
-            }
-
-            if (!mWaitUntilDone && !mRequestedWebKitData && !mTimedOut) {
-                requestWebKitData();
-            } else {
-                if (mWaitUntilDone) {
-                    Log.v(LOGTAG, "page finished loading but waiting for notifyDone to be called: " + url);
-                }
-
-                if (mRequestedWebKitData) {
-                    Log.v(LOGTAG, "page finished loading but webkit data has already been requested: " + url);
-                }
-
-                if (mTimedOut) {
-                    Log.v(LOGTAG, "page finished loading but already timed out: " + url);
-                }
-            }
-
-            super.onPageFinished(view, url);
-        }
-
-        @Override
-        public void onPageStarted(WebView view, String url, Bitmap favicon) {
-            Log.v(LOGTAG, "onPageStarted, url=" + url);
-            mPageFinished = false;
-            super.onPageStarted(view, url, favicon);
-        }
-
-        @Override
-        public void onReceivedError(WebView view, int errorCode, String description,
-                String failingUrl) {
-            Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
-                    + ", desc=" + description + ", url=" + failingUrl);
-            super.onReceivedError(view, errorCode, description, failingUrl);
-        }
-
-        @Override
-        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
-                String host, String realm) {
-            if (handler.useHttpAuthUsernamePassword() && view != null) {
-                String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
-                if (credentials != null && credentials.length == 2) {
-                    handler.proceed(credentials[0], credentials[1]);
-                    return;
-                }
-            }
-            handler.cancel();
-        }
-
-        @Override
-        public void onReceivedSslError(WebView view, SslErrorHandler handler,
-                SslError error) {
-            handler.proceed();
-        }
-    };
-
-
-    private final WebChromeClient mChromeClient = new WebChromeClient() {
-        @Override
-        public void onReceivedTitle(WebView view, String title) {
-            setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount + ": "+ title);
-            if (mDumpTitleChanges) {
-                mTitleChanges.append("TITLE CHANGED: ");
-                mTitleChanges.append(title);
-                mTitleChanges.append("\n");
-            }
-        }
-
-        @Override
-        public boolean onJsAlert(WebView view, String url, String message,
-                JsResult result) {
-            if (mDialogStrings == null) {
-                mDialogStrings = new StringBuffer();
-            }
-            mDialogStrings.append("ALERT: ");
-            mDialogStrings.append(message);
-            mDialogStrings.append('\n');
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsConfirm(WebView view, String url, String message,
-                JsResult result) {
-            if (mDialogStrings == null) {
-                mDialogStrings = new StringBuffer();
-            }
-            mDialogStrings.append("CONFIRM: ");
-            mDialogStrings.append(message);
-            mDialogStrings.append('\n');
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsPrompt(WebView view, String url, String message,
-                String defaultValue, JsPromptResult result) {
-            if (mDialogStrings == null) {
-                mDialogStrings = new StringBuffer();
-            }
-            mDialogStrings.append("PROMPT: ");
-            mDialogStrings.append(message);
-            mDialogStrings.append(", default text: ");
-            mDialogStrings.append(defaultValue);
-            mDialogStrings.append('\n');
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsTimeout() {
-            Log.v(LOGTAG, "JavaScript timeout");
-            return false;
-        }
-
-        @Override
-        public void onExceededDatabaseQuota(String url_str,
-                String databaseIdentifier, long currentQuota,
-                long estimatedSize, long totalUsedQuota,
-                WebStorage.QuotaUpdater callback) {
-            if (mDumpDatabaseCallbacks) {
-                if (mDatabaseCallbackStrings == null) {
-                    mDatabaseCallbackStrings = new StringBuffer();
-                }
-
-                String protocol = "";
-                String host = "";
-                int port = 0;
-
-                try {
-                    URL url = new URL(url_str);
-                    protocol = url.getProtocol();
-                    host = url.getHost();
-                    if (url.getPort() > -1) {
-                        port = url.getPort();
-                    }
-                } catch (MalformedURLException e) {}
-
-                String databaseCallbackString =
-                        "UI DELEGATE DATABASE CALLBACK: " +
-                        "exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
-                        ", " + host + ", " + port + "} database:" +
-                        databaseIdentifier + "\n";
-                Log.v(LOGTAG, "LOG: "+databaseCallbackString);
-                mDatabaseCallbackStrings.append(databaseCallbackString);
-            }
-            // Give 5MB more quota.
-            callback.updateQuota(currentQuota + 1024 * 1024 * 5);
-        }
-
-        @Override
-        public void onGeolocationPermissionsShowPrompt(String origin,
-                GeolocationPermissions.Callback callback) {
-            throw new RuntimeException(
-                    "The WebCore mock used by DRT should bypass the usual permissions flow.");
-        }
-
-        @Override
-        public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
-            String msg = "CONSOLE MESSAGE: line " + consoleMessage.lineNumber() + ": "
-                    + consoleMessage.message() + "\n";
-            if (mConsoleMessages == null) {
-                mConsoleMessages = new StringBuffer();
-            }
-            mConsoleMessages.append(msg);
-            Log.v(LOGTAG, "LOG: " + msg);
-            // the rationale here is that if there's an error of either type, and the test was
-            // waiting for "notifyDone" signal to finish, then there's no point in waiting
-            // anymore because the JS execution is already terminated at this point and a
-            // "notifyDone" will never come out so it's just wasting time till timeout kicks in
-            if ((msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:"))
-                    && mWaitUntilDone && mStopOnRefError) {
-                Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError.");
-                mHandler.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        notifyDone();
-                    }
-                }, 500);
-            }
-            return true;
-        }
-
-        @Override
-        public boolean onCreateWindow(WebView view, boolean dialog,
-                boolean userGesture, Message resultMsg) {
-            if (!mCanOpenWindows) {
-                // We can't open windows, so just send null back.
-                WebView.WebViewTransport transport =
-                        (WebView.WebViewTransport) resultMsg.obj;
-                transport.setWebView(null);
-                resultMsg.sendToTarget();
-                return true;
-            }
-
-            // We never display the new window, just create the view and
-            // allow it's content to execute and be recorded by the test
-            // runner.
-
-            HashMap<String, Object> jsIfaces = new HashMap<String, Object>();
-            jsIfaces.put("layoutTestController", mCallbackProxy);
-            jsIfaces.put("eventSender", mCallbackProxy);
-            WebView newWindowView = new NewWindowWebView(TestShellActivity.this, jsIfaces);
-            setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
-            WebView.WebViewTransport transport =
-                    (WebView.WebViewTransport) resultMsg.obj;
-            transport.setWebView(newWindowView);
-            resultMsg.sendToTarget();
-            return true;
-        }
-
-        @Override
-        public void onCloseWindow(WebView view) {
-            view.destroy();
-        }
-    };
-
-    private static class NewWindowWebView extends WebView {
-        public NewWindowWebView(Context context, Map<String, Object> jsIfaces) {
-            super(context, null, 0, jsIfaces, false);
-        }
-    }
-
-    private void resetTestStatus() {
-        mWaitUntilDone = false;
-        mDumpDataType = mDefaultDumpDataType;
-        mDumpTopFrameAsText = false;
-        mDumpChildFramesAsText = false;
-        mTimedOut = false;
-        mDumpTitleChanges = false;
-        mRequestedWebKitData = false;
-        mDumpDatabaseCallbacks = false;
-        mCanOpenWindows = false;
-        mEventSender.resetMouse();
-        mEventSender.clearTouchPoints();
-        mEventSender.clearTouchMetaState();
-        mPageFinished = false;
-        mDumpWebKitData = false;
-        setDefaultWebSettings(mWebView);
-        CookieManager.getInstance().removeAllCookie();
-        mWebViewClassic.setUseMockGeolocation();
-    }
-
-    private boolean canMoveToNextTest() {
-        return (mDumpWebKitData && mPageFinished && !mWaitUntilDone) || mTimedOut;
-    }
-
-    private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
-        if (webview == null) {
-            return;
-        }
-
-        setDefaultWebSettings(webview);
-
-        webview.setWebChromeClient(mChromeClient);
-        webview.setWebViewClient(mViewClient);
-        // Setting a touch interval of -1 effectively disables the optimisation in WebView
-        // that stops repeated touch events flooding WebCore. The Event Sender only sends a
-        // single event rather than a stream of events (like what would generally happen in
-        // a real use of touch events in a WebView)  and so if the WebView drops the event,
-        // the test will fail as the test expects one callback for every touch it synthesizes.
-        WebViewClassic.fromWebView(webview).setTouchInterval(-1);
-    }
-
-    public void setDefaultWebSettings(WebView webview) {
-        WebSettingsClassic settings = WebViewClassic.fromWebView(webview).getSettings();
-        settings.setAppCacheEnabled(true);
-        settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
-        settings.setAppCacheMaxSize(Long.MAX_VALUE);
-        settings.setJavaScriptEnabled(true);
-        settings.setJavaScriptCanOpenWindowsAutomatically(true);
-        settings.setSupportMultipleWindows(true);
-        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-        settings.setDatabaseEnabled(true);
-        settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
-        settings.setDomStorageEnabled(true);
-        settings.setWorkersEnabled(false);
-        settings.setXSSAuditorEnabled(false);
-        settings.setPageCacheCapacity(0);
-        settings.setProperty("use_minimal_memory", "false");
-        settings.setAllowUniversalAccessFromFileURLs(true);
-        settings.setAllowFileAccessFromFileURLs(true);
-    }
-
-    private WebViewClassic mWebViewClassic;
-    private WebView mWebView;
-    private WebViewEventSender mEventSender;
-    private AsyncHandler mHandler;
-    private TestShellCallback mCallback;
-
-    private CallbackProxy mCallbackProxy;
-
-    private String mTestUrl;
-    private String mResultFile;
-    private int mTimeoutInMillis;
-    private String mUiAutoTestPath;
-    private BufferedReader mTestListReader;
-    private int mTotalTestCount;
-    private int mCurrentTestNumber;
-    private boolean mStopOnRefError;
-
-    // States
-    private boolean mTimedOut;
-    private boolean mRequestedWebKitData;
-    private boolean mFinishedRunning;
-
-    // Layout test controller variables.
-    private DumpDataType mDumpDataType;
-    private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR;
-    private boolean mDumpTopFrameAsText;
-    private boolean mDumpChildFramesAsText;
-    private boolean mWaitUntilDone;
-    private boolean mDumpTitleChanges;
-    private StringBuffer mTitleChanges;
-    private StringBuffer mDialogStrings;
-    private boolean mKeepWebHistory;
-    private Vector mWebHistory;
-    private boolean mDumpDatabaseCallbacks;
-    private StringBuffer mDatabaseCallbackStrings;
-    private StringBuffer mConsoleMessages;
-    private boolean mCanOpenWindows;
-
-    private boolean mPageFinished = false;
-    private boolean mDumpWebKitData = false;
-
-    static final String TIMEOUT_STR = "**Test timeout";
-    static final long DUMP_TIMEOUT_MS = 100000; // 100s timeout for dumping webview content
-
-    static final int MSG_TIMEOUT = 0;
-    static final int MSG_WEBKIT_DATA = 1;
-    static final int MSG_DUMP_TIMEOUT = 2;
-
-    static final String LOGTAG="TestShell";
-
-    static final String TEST_URL = "TestUrl";
-    static final String RESULT_FILE = "ResultFile";
-    static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
-    static final String UI_AUTO_TEST = "UiAutoTest";
-    static final String GET_DRAW_TIME = "GetDrawTime";
-    static final String SAVE_IMAGE = "SaveImage";
-    static final String TOTAL_TEST_COUNT = "TestCount";
-    static final String CURRENT_TEST_NUMBER = "TestNumber";
-    static final String STOP_ON_REF_ERROR = "StopOnReferenceError";
-
-    static final int DRAW_RUNS = 5;
-    static final String DRAW_TIME_LOG = Environment.getExternalStorageDirectory() +
-        "/android/page_draw_time.txt";
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
deleted file mode 100644
index 5220d579..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-public interface TestShellCallback {
-    public void finished();
-    public void dumpResult(String webViewDump);
-    public void timedOut(String url);
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
deleted file mode 100644
index 17345ae..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import android.os.SystemClock;
-import android.util.*;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.webkit.WebView;
-
-import java.util.Arrays;
-import java.util.Vector;
-
-public class WebViewEventSender implements EventSender {
-
-    private static final String LOGTAG = "WebViewEventSender";
-	
-    WebViewEventSender(WebView webView) {
-        mWebView = webView;
-        mWebView.getSettings().setBuiltInZoomControls(true);
-        mTouchPoints = new Vector<TouchPoint>();
-    }
-	
-	public void resetMouse() {
-		mouseX = mouseY = 0;
-	}
-
-	public void enableDOMUIEventLogging(int DOMNode) {
-		// TODO Auto-generated method stub
-
-	}
-
-	public void fireKeyboardEventsToElement(int DOMNode) {
-		// TODO Auto-generated method stub
-
-	}
-
-	public void keyDown(String character, String[] withModifiers) {
-        Log.e("EventSender", "KeyDown: " + character + "("
-                + character.getBytes()[0] + ") Modifiers: "
-                + Arrays.toString(withModifiers));
-        KeyEvent modifier = null;
-        if (withModifiers != null && withModifiers.length > 0) {
-            for (int i = 0; i < withModifiers.length; i++) {
-                int keyCode = modifierMapper(withModifiers[i]);
-                modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
-                mWebView.onKeyDown(modifier.getKeyCode(), modifier);
-            }
-        }
-        int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]);
-        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
-        mWebView.onKeyDown(event.getKeyCode(), event);
-
-    }
-	
-	public void keyDown(String character) {
-        keyDown(character, null);
-	}
-
-	public void leapForward(int milliseconds) {
-		// TODO Auto-generated method stub
-
-	}
-
-	public void mouseClick() {
-		mouseDown();
-		mouseUp();
-	}
-
-    public void mouseDown() {
-        long ts = SystemClock.uptimeMillis();
-        MotionEvent event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_DOWN, mouseX, mouseY, 0);
-        mWebView.onTouchEvent(event);
-    }
-
-    public void mouseMoveTo(int X, int Y) {
-        mouseX= X;
-        mouseY= Y;
-    }
-
-     public void mouseUp() {
-        long ts = SystemClock.uptimeMillis();
-        MotionEvent event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_UP, mouseX, mouseY, 0);
-        mWebView.onTouchEvent(event);
-    }
-
-	// Assumes lowercase chars, case needs to be
-	// handled by calling function.
-	static int keyMapper(char c) {
-		// handle numbers
-		if (c >= '0' && c<= '9') {
-			int offset = c - '0';
-			return KeyEvent.KEYCODE_0 + offset;
-		}
-
-		// handle characters
-		if (c >= 'a' && c <= 'z') {
-			int offset = c - 'a';
-			return KeyEvent.KEYCODE_A + offset;
-		}
-
-		// handle all others
-		switch (c) {
-		case '*':
-			return KeyEvent.KEYCODE_STAR;
-		case '#':
-			return KeyEvent.KEYCODE_POUND;
-		case ',':
-			return KeyEvent.KEYCODE_COMMA;
-		case '.':
-			return KeyEvent.KEYCODE_PERIOD;
-		case '\t':
-			return KeyEvent.KEYCODE_TAB;
-		case ' ':
-			return KeyEvent.KEYCODE_SPACE;
-		case '\n':
-			return KeyEvent.KEYCODE_ENTER;
-		case '\b':
-        case 0x7F:
-			return KeyEvent.KEYCODE_DEL;
-		case '~':
-			return KeyEvent.KEYCODE_GRAVE;
-		case '-':
-			return KeyEvent.KEYCODE_MINUS;
-		case '=':
-			return KeyEvent.KEYCODE_EQUALS;
-		case '(':
-			return KeyEvent.KEYCODE_LEFT_BRACKET;
-		case ')':
-			return KeyEvent.KEYCODE_RIGHT_BRACKET;
-		case '\\':
-			return KeyEvent.KEYCODE_BACKSLASH;
-		case ';':
-			return KeyEvent.KEYCODE_SEMICOLON;
-		case '\'':
-			return KeyEvent.KEYCODE_APOSTROPHE;
-		case '/':
-			return KeyEvent.KEYCODE_SLASH;
-		default:
-			break;
-		}
-
-		return c;
-	}
-	
-	static int modifierMapper(String modifier) {
-		if (modifier.equals("ctrlKey")) {
-			return KeyEvent.KEYCODE_ALT_LEFT;
-		} else if (modifier.equals("shiftKey")) {
-			return KeyEvent.KEYCODE_SHIFT_LEFT;
-		} else if (modifier.equals("altKey")) {
-			return KeyEvent.KEYCODE_SYM;
-		} else if (modifier.equals("metaKey")) {
-			return KeyEvent.KEYCODE_UNKNOWN;
-		}
-		return KeyEvent.KEYCODE_UNKNOWN;
-	}
-
-    public void touchStart() {
-        final int numPoints = mTouchPoints.size();
-        if (numPoints == 0) {
-            return;
-        }
-
-        int[] pointerIds = new int[numPoints];
-        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
-        long downTime = SystemClock.uptimeMillis();
-
-        for (int i = 0; i < numPoints; ++i) {
-            pointerIds[i] = mTouchPoints.get(i).getId();
-            pointerCoords[i] = new MotionEvent.PointerCoords();
-            pointerCoords[i].x = mTouchPoints.get(i).getX();
-            pointerCoords[i].y = mTouchPoints.get(i).getY();
-            mTouchPoints.get(i).setDownTime(downTime);
-        }
-
-        MotionEvent event = MotionEvent.obtain(downTime, downTime,
-            MotionEvent.ACTION_DOWN, numPoints, pointerIds, pointerCoords,
-            mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
-
-        mWebView.onTouchEvent(event);
-    }
-
-    public void touchMove() {
-        final int numPoints = mTouchPoints.size();
-        if (numPoints == 0) {
-            return;
-        }
-
-        int[] pointerIds = new int[numPoints];
-        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
-        int numMovedPoints = 0;
-        for (int i = 0; i < numPoints; ++i) {
-            TouchPoint tp = mTouchPoints.get(i);
-            if (tp.hasMoved()) {
-                pointerIds[numMovedPoints] = mTouchPoints.get(i).getId();
-                pointerCoords[i] = new MotionEvent.PointerCoords();
-                pointerCoords[numMovedPoints].x = mTouchPoints.get(i).getX();
-                pointerCoords[numMovedPoints].y = mTouchPoints.get(i).getY();
-                ++numMovedPoints;
-                tp.setMoved(false);
-            }
-        }
-
-        if (numMovedPoints == 0) {
-            return;
-        }
-
-        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).downTime(),
-                SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE,
-                numMovedPoints, pointerIds, pointerCoords,
-                mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
-        mWebView.onTouchEvent(event);
-    }
-
-    public void touchEnd() {
-        final int numPoints = mTouchPoints.size();
-        if (numPoints == 0) {
-            return;
-        }
-
-        int[] pointerIds = new int[numPoints];
-        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
-
-        for (int i = 0; i < numPoints; ++i) {
-            pointerIds[i] = mTouchPoints.get(i).getId();
-            pointerCoords[i] = new MotionEvent.PointerCoords();
-            pointerCoords[i].x = mTouchPoints.get(i).getX();
-            pointerCoords[i].y = mTouchPoints.get(i).getY();
-        }
-
-        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).downTime(),
-                SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
-                numPoints, pointerIds, pointerCoords,
-                mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
-        mWebView.onTouchEvent(event);
-
-        for (int i = numPoints - 1; i >= 0; --i) {  // remove released points.
-            TouchPoint tp = mTouchPoints.get(i);
-            if (tp.isReleased()) {
-              mTouchPoints.remove(i);
-            }
-        }
-    }
-
-    public void touchCancel() {
-        final int numPoints = mTouchPoints.size();
-        if (numPoints == 0) {
-            return;
-        }
-
-        int[] pointerIds = new int[numPoints];
-        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
-        long cancelTime = SystemClock.uptimeMillis();
-        int numCanceledPoints = 0;
-
-        for (int i = 0; i < numPoints; ++i) {
-            TouchPoint tp = mTouchPoints.get(i);
-            if (tp.cancelled()) {
-                pointerIds[numCanceledPoints] = mTouchPoints.get(i).getId();
-                pointerCoords[numCanceledPoints] = new MotionEvent.PointerCoords();
-                pointerCoords[numCanceledPoints].x = mTouchPoints.get(i).getX();
-                pointerCoords[numCanceledPoints].y = mTouchPoints.get(i).getY();
-                ++numCanceledPoints;
-            }
-        }
-
-        if (numCanceledPoints == 0) {
-            return;
-        }
-
-        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).downTime(),
-            SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL,
-            numCanceledPoints, pointerIds, pointerCoords,
-            mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
-
-        mWebView.onTouchEvent(event);
-    }
-
-    public void cancelTouchPoint(int id) {
-        TouchPoint tp = mTouchPoints.get(id);
-        if (tp == null) {
-            return;
-        }
-
-        tp.cancel();
-    }
-
-    public void addTouchPoint(int x, int y) {
-        final int numPoints = mTouchPoints.size();
-        int id;
-        if (numPoints == 0) {
-          id = 0;
-        } else {
-          id = mTouchPoints.get(numPoints - 1).getId() + 1;
-        }
-
-        mTouchPoints.add(new TouchPoint(id, contentsToWindowX(x), contentsToWindowY(y)));
-    }
-
-    public void updateTouchPoint(int i, int x, int y) {
-        TouchPoint tp = mTouchPoints.get(i);
-        if (tp == null) {
-            return;
-        }
-
-        tp.update(contentsToWindowX(x), contentsToWindowY(y));
-        tp.setMoved(true);
-    }
-
-    public void setTouchModifier(String modifier, boolean enabled) {
-        int mask = 0;
-        if ("alt".equals(modifier.toLowerCase())) {
-            mask = KeyEvent.META_ALT_ON;
-        } else if ("shift".equals(modifier.toLowerCase())) {
-            mask = KeyEvent.META_SHIFT_ON;
-        } else if ("ctrl".equals(modifier.toLowerCase())) {
-            mask = KeyEvent.META_SYM_ON;
-        }
-
-        if (enabled) {
-            mTouchMetaState |= mask;
-        } else {
-            mTouchMetaState &= ~mask;
-        }
-    }
-
-    public void releaseTouchPoint(int id) {
-        TouchPoint tp = mTouchPoints.get(id);
-        if (tp == null) {
-            return;
-        }
-
-        tp.release();
-    }
-
-    public void clearTouchPoints() {
-        mTouchPoints.clear();
-    }
-
-    public void clearTouchMetaState() {
-        mTouchMetaState = 0;
-    }
-
-    private int contentsToWindowX(int x) {
-        return Math.round(x * mWebView.getScale()) - mWebView.getScrollX();
-    }
-
-    private int contentsToWindowY(int y) {
-        return Math.round(y * mWebView.getScale()) - mWebView.getScrollY();
-    }
-
-    private WebView mWebView = null;
-    private int mouseX;
-    private int mouseY;
-
-    private class TouchPoint {
-        private int mId;
-        private int mX;
-        private int mY;
-        private long mDownTime;
-        private boolean mReleased;
-        private boolean mMoved;
-        private boolean mCancelled;
-
-        public TouchPoint(int id, int x, int y) {
-            mId = id;
-            mX = x;
-            mY = y;
-            mReleased = false;
-            mMoved = false;
-            mCancelled = false;
-        }
-
-        public void setDownTime(long downTime) { mDownTime = downTime; }
-        public long downTime() { return mDownTime; }
-        public void cancel() { mCancelled = true; }
-
-        public boolean cancelled() { return mCancelled; }
-
-        public void release() { mReleased = true; }
-        public boolean isReleased() { return mReleased; }
-
-        public void setMoved(boolean moved) { mMoved = moved; }
-        public boolean hasMoved() { return mMoved; }
-
-        public int getId() { return mId; }
-        public int getX() { return mX; }
-        public int getY() { return mY; }
-
-        public void update(int x, int y) {
-            mX = x;
-            mY = y;
-        }
-    }
-
-    private Vector<TouchPoint> mTouchPoints;
-    private int mTouchMetaState;
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
deleted file mode 100644
index c2ecf3a..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree.forwarder;
-
-import android.util.Log;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-
-public class AdbUtils {
-
-    private static final String ADB_OK = "OKAY";
-    private static final int ADB_PORT = 5037;
-    private static final String ADB_HOST = "127.0.0.1";
-    private static final int ADB_RESPONSE_SIZE = 4;
-
-    private static final String LOGTAG = "AdbUtils";
-
-    /**
-     *
-     * Convert integer format IP into xxx.xxx.xxx.xxx format
-     *
-     * @param host IP address in integer format
-     * @return human readable format
-     */
-    public static String convert(int host) {
-        return ((host >> 24) & 0xFF) + "."
-        + ((host >> 16) & 0xFF) + "."
-        + ((host >> 8) & 0xFF) + "."
-        + (host & 0xFF);
-    }
-
-    /**
-     *
-     * Resolve DNS name into IP address
-     *
-     * @param host DNS name
-     * @return IP address in integer format
-     * @throws IOException
-     */
-    public static int resolve(String host)  throws IOException {
-        Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
-        DataInputStream dis = new DataInputStream(localSocket.getInputStream());
-        OutputStream os = localSocket.getOutputStream();
-        int count_read = 0;
-
-        if (localSocket == null || dis == null || os == null)
-            return -1;
-        String cmd = "dns:" + host;
-
-        if(!sendAdbCmd(dis, os, cmd))
-            return -1;
-
-        count_read = dis.readInt();
-        localSocket.close();
-        return count_read;
-    }
-
-    /**
-     *
-     * Send an ADB command using existing socket connection
-     *
-     * the streams provided must be from a socket connected to adbd already
-     *
-     * @param is input stream of the socket connection
-     * @param os output stream of the socket
-     * @param cmd the adb command to send
-     * @return if adb gave a success response
-     * @throws IOException
-     */
-    public static boolean sendAdbCmd(InputStream is, OutputStream os,
-            String cmd) throws IOException {
-        byte[] buf = new byte[ADB_RESPONSE_SIZE];
-
-        cmd = String.format("%04X", cmd.length()) + cmd;
-        os.write(cmd.getBytes());
-        int read = is.read(buf);
-        if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
-            Log.w(LOGTAG, "adb cmd faild.");
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     *
-     * Get a tcp socket connection to specified IP address and port proxied by adb
-     *
-     * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
-     * read from as if it is directly connected to the target
-     *
-     * @param remoteAddress IP address of the host to connect to
-     * @param remotePort port of the host to connect to
-     * @return a valid Socket instance if successful, null otherwise
-     */
-    public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
-        try {
-            Socket socket = new Socket(ADB_HOST, ADB_PORT);
-            String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
-            if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
-                socket.close();
-                return null;
-            }
-            return socket;
-        } catch (IOException ioe) {
-            Log.w(LOGTAG, "error creating adb socket", ioe);
-            return null;
-        }
-    }
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
deleted file mode 100644
index 14f8fbe..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree.forwarder;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- *
- * A port forwarding server. Listens at specified local port and forward the tcp communications to
- * external host/port via adb networking proxy.
- *
- */
-public class ForwardServer {
-
-    private static final String LOGTAG = "ForwardServer";
-
-    private int remotePort;
-    private int remoteAddress;
-    private int localPort;
-    private ServerSocket serverSocket;
-    private boolean started;
-
-    private Set<Forwarder> forwarders;
-
-    public ForwardServer(int localPort, int remoteAddress, int remotePort) {
-        this.localPort = localPort;
-        this.remoteAddress = remoteAddress;
-        this.remotePort = remotePort;
-        started = false;
-        forwarders = new HashSet<Forwarder>();
-    }
-
-    public synchronized void start() throws IOException {
-        if(!started) {
-            serverSocket = new ServerSocket(localPort);
-            Thread serverThread = new Thread(new ServerRunner(serverSocket));
-            serverThread.setName(LOGTAG);
-            serverThread.start();
-            started = true;
-        }
-    }
-
-    public synchronized void stop() {
-        if(started) {
-            synchronized (forwarders) {
-                for(Forwarder forwarder : forwarders)
-                    forwarder.stop();
-                forwarders.clear();
-            }
-            try {
-                serverSocket.close();
-            } catch (IOException ioe) {
-                Log.v(LOGTAG, "exception while closing", ioe);
-            } finally {
-                started = false;
-            }
-        }
-    }
-
-    public synchronized boolean isRunning() {
-        return started;
-    }
-
-    private class ServerRunner implements Runnable {
-
-        private ServerSocket socket;
-
-        public ServerRunner(ServerSocket socket) {
-            this.socket = socket;
-        }
-
-        public void run() {
-            try {
-                while (true) {
-                    Socket localSocket = socket.accept();
-                    Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
-                    if(remoteSocket == null) {
-                        try {
-                            localSocket.close();
-                        } catch (IOException ioe) {
-                            Log.w(LOGTAG, "error while closing socket", ioe);
-                        } finally {
-                            Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
-                        }
-                    } else {
-                        Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
-                                ForwardServer.this);
-                        forwarder.start();
-                    }
-                }
-            } catch (IOException ioe) {
-                return;
-            }
-        }
-    }
-
-    public void register(Forwarder forwarder) {
-        synchronized (forwarders) {
-            if(!forwarders.contains(forwarder)) {
-                forwarders.add(forwarder);
-            }
-        }
-    }
-
-    public void unregister(Forwarder recyclable) {
-        synchronized (forwarders) {
-            if(forwarders.contains(recyclable)) {
-                recyclable.stop();
-                forwarders.remove(recyclable);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
deleted file mode 100644
index 25dd04fd..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree.forwarder;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-
-import android.os.Environment;
-import android.util.Log;
-
-public class ForwardService {
-
-    private ForwardServer fs8000, fs8080, fs8443;
-
-    private static ForwardService inst;
-
-    private static final String LOGTAG = "ForwardService";
-
-    private static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com";
-
-    private static final String FORWARD_HOST_CONF =
-        Environment.getExternalStorageDirectory() + "/drt_forward_host.txt";
-
-    private ForwardService() {
-        int addr = getForwardHostAddr();
-        if (addr != -1) {
-            fs8000 = new ForwardServer(8000, addr, 8000);
-            fs8080 = new ForwardServer(8080, addr, 8080);
-            fs8443 = new ForwardServer(8443, addr, 8443);
-        }
-    }
-
-    public static ForwardService getForwardService() {
-        if (inst == null) {
-            inst = new ForwardService();
-        }
-        return inst;
-    }
-
-    public void startForwardService() {
-        try {
-            if (fs8000 != null)
-                fs8000.start();
-            if (fs8080 != null)
-                fs8080.start();
-            if (fs8443 != null)
-                fs8443.start();
-        } catch (IOException ioe) {
-            Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
-            return;
-        }
-    }
-
-    public void stopForwardService() {
-        if (fs8000 != null) {
-            fs8000.stop();
-            fs8000 = null;
-        }
-        if (fs8080 != null) {
-            fs8080.stop();
-            fs8080 = null;
-        }
-        if (fs8443 != null) {
-            fs8443.stop();
-            fs8443 = null;
-        }
-        Log.v(LOGTAG, "forwarders stopped.");
-    }
-
-    private static int getForwardHostAddr() {
-        int addr = -1;
-        String host = null;
-        File forwardHostConf = new File(FORWARD_HOST_CONF);
-        if (forwardHostConf.isFile()) {
-            BufferedReader hostReader = null;
-            try {
-                hostReader = new BufferedReader(new FileReader(forwardHostConf));
-                host = hostReader.readLine();
-                Log.v(LOGTAG, "read forward host from file: " + host);
-            } catch (IOException ioe) {
-                Log.v(LOGTAG, "cannot read forward host from file", ioe);
-            } finally {
-                if (hostReader != null) {
-                    try {
-                        hostReader.close();
-                    } catch (IOException ioe) {
-                        // burn!!!
-                    }
-                }
-            }
-        }
-        if (host == null || host.length() == 0)
-            host = DEFAULT_TEST_HOST;
-        try {
-            addr = AdbUtils.resolve(host);
-        } catch (IOException ioe) {
-            Log.e(LOGTAG, "failed to resolve server address", ioe);
-        }
-        return addr;
-    }
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
deleted file mode 100644
index a971e7b..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree.forwarder;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-
-/**
- *
- * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
- * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
- * connection already proxied by adb networking (see also {@link AdbUtils}).
- *
- */
-public class Forwarder {
-
-    private ForwardServer server;
-    private Socket from, to;
-
-    private static final String LOGTAG = "Forwarder";
-    private static final int BUFFER_SIZE = 16384;
-
-    public Forwarder (Socket from, Socket to, ForwardServer server) {
-        this.server = server;
-        this.from = from;
-        this.to = to;
-        server.register(this);
-    }
-
-    public void start() {
-        Thread outgoing = new Thread(new SocketPipe(from, to));
-        Thread incoming = new Thread(new SocketPipe(to, from));
-        outgoing.setName(LOGTAG);
-        incoming.setName(LOGTAG);
-        outgoing.start();
-        incoming.start();
-    }
-
-    public void stop() {
-        shutdown(from);
-        shutdown(to);
-    }
-
-    private void shutdown(Socket socket) {
-        try {
-            socket.shutdownInput();
-        } catch (IOException e) {
-            Log.v(LOGTAG, "Socket#shutdownInput", e);
-        }
-        try {
-            socket.shutdownOutput();
-        } catch (IOException e) {
-            Log.v(LOGTAG, "Socket#shutdownOutput", e);
-        }
-        try {
-            socket.close();
-        } catch (IOException e) {
-            Log.v(LOGTAG, "Socket#close", e);
-        }
-    }
-
-    private class SocketPipe implements Runnable {
-
-        private Socket in, out;
-
-        public SocketPipe(Socket in, Socket out) {
-            this.in = in;
-            this.out = out;
-        }
-
-        public void run() {
-            try {
-                int length;
-                InputStream is = in.getInputStream();
-                OutputStream os = out.getOutputStream();
-                byte[] buffer = new byte[BUFFER_SIZE];
-                while ((length = is.read(buffer)) > 0) {
-                    os.write(buffer, 0, length);
-                }
-            } catch (IOException ioe) {
-            } finally {
-                server.unregister(Forwarder.this);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "SocketPipe{" + in + "=>" + out  + "}";
-        }
-    }
-}
diff --git a/tests/DumpRenderTree2/Android.mk b/tests/DumpRenderTree2/Android.mk
deleted file mode 100644
index 81fc633..0000000
--- a/tests/DumpRenderTree2/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 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
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT 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_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := diff_match_patch
-
-LOCAL_PACKAGE_NAME := DumpRenderTree2
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/AndroidManifest.xml b/tests/DumpRenderTree2/AndroidManifest.xml
deleted file mode 100644
index ea6571e..0000000
--- a/tests/DumpRenderTree2/AndroidManifest.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 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
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT 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.dumprendertree2">
-    <application>
-        <uses-library android:name="android.test.runner" />
-
-        <activity android:name=".ui.DirListActivity"
-                  android:label="Dump Render Tree 2"
-                  android:configChanges="orientation">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.TEST" />
-            </intent-filter>
-        </activity>
-
-        <!-- android:launchMode="singleTask" is there so we only have a one instance
-             of this activity. However, it doesn't seem to work exactly like described in the
-             documentation, because the behaviour of the application suggest
-             there is only a single task for all 3 activities. We don't understand
-             how exactly it all works, but at the moment it works just fine.
-             It can lead to some weird behaviour in the future. -->
-        <activity android:name=".TestsListActivity"
-                  android:label="Tests' list activity"
-                  android:launchMode="singleTask"
-                  android:configChanges="orientation">
-        </activity>
-
-        <activity android:name=".LayoutTestsExecutor"
-                  android:theme="@style/WhiteBackground"
-                  android:label="Layout tests' executor"
-                  android:process=":executor">
-        </activity>
-
-        <service android:name="ManagerService">
-        </service>
-    </application>
-
-    <instrumentation android:name="com.android.dumprendertree2.scriptsupport.ScriptTestRunner"
-                     android:targetPackage="com.android.dumprendertree2"
-                     android:label="Layout tests script runner" />
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.WRITE_SDCARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-</manifest>
diff --git a/tests/DumpRenderTree2/assets/run_apache2.py b/tests/DumpRenderTree2/assets/run_apache2.py
deleted file mode 100755
index 3806599..0000000
--- a/tests/DumpRenderTree2/assets/run_apache2.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (C) 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
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""Start, stop, or restart apache2 server.
-
-  Apache2 must be installed with mod_php!
-
-  Usage:
-    run_apache2.py start|stop|restart
-"""
-
-import sys
-import os
-import subprocess
-import logging
-import optparse
-import time
-
-def main(run_cmd, options):
-  # Setup logging class
-  logging.basicConfig(level=logging.INFO, format='%(message)s')
-
-  if not run_cmd in ("start", "stop", "restart"):
-    logging.info("illegal argument: " + run_cmd)
-    logging.info("Usage: python run_apache2.py start|stop|restart")
-    return False
-
-  # Create /tmp/WebKit if it doesn't exist. This is needed for various files used by apache2
-  tmp_WebKit = os.path.join("/tmp", "WebKit")
-  if not os.path.exists(tmp_WebKit):
-    os.mkdir(tmp_WebKit)
-
-  # Get the path to android tree root based on the script location.
-  # Basically we go 5 levels up
-  parent = os.pardir
-  script_location = os.path.abspath(os.path.dirname(sys.argv[0]))
-  android_tree_root = os.path.join(script_location, parent, parent, parent, parent, parent)
-  android_tree_root = os.path.normpath(android_tree_root)
-
-  # If any of these is relative, then it's relative to ServerRoot (in our case android_tree_root)
-  webkit_path = os.path.join("external", "webkit")
-  if (options.tests_root_directory != None):
-    # if options.tests_root_directory is absolute, os.getcwd() is discarded!
-    layout_tests_path = os.path.normpath(os.path.join(os.getcwd(), options.tests_root_directory))
-  else:
-    layout_tests_path = os.path.join(webkit_path, "LayoutTests")
-  http_conf_path = os.path.join(layout_tests_path, "http", "conf")
-
-  # Prepare the command to set ${APACHE_RUN_USER} and ${APACHE_RUN_GROUP}
-  envvars_path = os.path.join("/etc", "apache2", "envvars")
-  export_envvars_cmd = "source " + envvars_path
-
-  error_log_path = os.path.join(tmp_WebKit, "apache2-error.log")
-  custom_log_path = os.path.join(tmp_WebKit, "apache2-access.log")
-
-  # Prepare the command to (re)start/stop the server with specified settings
-  apache2_restart_template = "apache2 -k %s"
-  directives  = " -c \"ServerRoot " + android_tree_root + "\""
-
-  # The default config in apache2-debian-httpd.conf listens on ports 8080 and
-  # 8443. We also need to listen on port 8000 for HTTP tests.
-  directives += " -c \"Listen 8000\""
-
-  # We use http/tests as the document root as the HTTP tests use hardcoded
-  # resources at the server root. We then use aliases to make available the
-  # complete set of tests and the required scripts.
-  directives += " -c \"DocumentRoot " + os.path.join(layout_tests_path, "http", "tests/") + "\""
-  directives += " -c \"Alias /LayoutTests " + layout_tests_path + "\""
-  directives += " -c \"Alias /Tools/DumpRenderTree/android " + \
-    os.path.join(webkit_path, "Tools", "DumpRenderTree", "android") + "\""
-  directives += " -c \"Alias /ThirdPartyProject.prop " + \
-    os.path.join(webkit_path, "ThirdPartyProject.prop") + "\""
-
-  # This directive is commented out in apache2-debian-httpd.conf for some reason
-  # However, it is useful to browse through tests in the browser, so it's added here.
-  # One thing to note is that because of problems with mod_dir and port numbers, mod_dir
-  # is turned off. That means that there _must_ be a trailing slash at the end of URL
-  # for auto indexes to work correctly.
-  directives += " -c \"LoadModule autoindex_module /usr/lib/apache2/modules/mod_autoindex.so\""
-
-  directives += " -c \"ErrorLog " + error_log_path +"\""
-  directives += " -c \"CustomLog " + custom_log_path + " combined\""
-  directives += " -c \"SSLCertificateFile " + os.path.join(http_conf_path, "webkit-httpd.pem") + \
-    "\""
-  directives += " -c \"User ${APACHE_RUN_USER}\""
-  directives += " -c \"Group ${APACHE_RUN_GROUP}\""
-  directives += " -C \"TypesConfig " + \
-    os.path.join(android_tree_root, http_conf_path, "mime.types") + "\""
-  conf_file_cmd = " -f " + \
-    os.path.join(android_tree_root, http_conf_path, "apache2-debian-httpd.conf")
-
-  # Try to execute the commands
-  logging.info("Will " + run_cmd + " apache2 server.")
-
-  # It is worth noting here that if the configuration file with which we restart the server points
-  # to a different PidFile it will not work and will result in a second apache2 instance.
-  if (run_cmd == 'restart'):
-    logging.info("First will stop...")
-    if execute_cmd(envvars_path, error_log_path,
-                   export_envvars_cmd + " && " + (apache2_restart_template % ('stop')) + directives + conf_file_cmd) == False:
-      logging.info("Failed to stop Apache2")
-      return False
-    logging.info("Stopped. Will start now...")
-    # We need to sleep breifly to avoid errors with apache being stopped and started too quickly
-    time.sleep(0.5)
-
-  if execute_cmd(envvars_path, error_log_path,
-                 export_envvars_cmd + " && " +
-                 (apache2_restart_template % (run_cmd)) + directives +
-                 conf_file_cmd) == False:
-    logging.info("Failed to start Apache2")
-    return False
-
-  logging.info("Successfully started")
-  return True
-
-def execute_cmd(envvars_path, error_log_path, cmd):
-  p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-  (out, err) = p.communicate()
-
-  # Output the stdout from the command to console
-  logging.info(out)
-
-  # Report any errors
-  if p.returncode != 0:
-    logging.info("!! ERRORS:")
-
-    if err.find(envvars_path) != -1:
-      logging.info(err)
-    elif err.find('command not found') != -1:
-      logging.info("apache2 is probably not installed")
-    else:
-      logging.info(err)
-      logging.info("Try looking in " + error_log_path + " for details")
-    return False
-
-  return True
-
-if __name__ == "__main__":
-  option_parser = optparse.OptionParser(usage="Usage: %prog [options] start|stop|restart")
-  option_parser.add_option("", "--tests-root-directory",
-                           help="The directory from which to take the tests, default is external/webkit/LayoutTests in this checkout of the Android tree")
-  options, args = option_parser.parse_args();
-
-  if len(args) < 1:
-    run_cmd = ""
-  else:
-    run_cmd = args[0]
-
-  main(run_cmd, options)
diff --git a/tests/DumpRenderTree2/assets/run_layout_tests.py b/tests/DumpRenderTree2/assets/run_layout_tests.py
deleted file mode 100755
index 161416a..0000000
--- a/tests/DumpRenderTree2/assets/run_layout_tests.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/python
-
-"""Run layout tests on the device.
-
-  It runs the specified tests on the device, downloads the summaries to the temporary directory
-  and optionally shows the detailed results the host's default browser.
-
-  Usage:
-    run_layout_tests.py --show-results-in-browser test-relative-path
-"""
-
-import logging
-import optparse
-import os
-import re
-import sys
-import subprocess
-import tempfile
-import webbrowser
-
-import run_apache2
-
-#TODO: These should not be hardcoded
-RESULTS_ABSOLUTE_PATH = "/sdcard/layout-test-results/"
-DETAILS_HTML = "details.html"
-SUMMARY_TXT = "summary.txt"
-
-def main(path, options):
-  tmpdir = tempfile.gettempdir()
-
-  # Restart the server
-  if run_apache2.main("restart", options) == False:
-    return
-
-  # Run the tests in path
-  adb_cmd = "adb"
-  if options.serial:
-    adb_cmd += " -s " + options.serial
-  cmd = adb_cmd + " shell am instrument "
-  cmd += "-e class com.android.dumprendertree2.scriptsupport.Starter#startLayoutTests "
-  cmd += "-e path \"" + path + "\" "
-  cmd += "-w com.android.dumprendertree2/com.android.dumprendertree2.scriptsupport.ScriptTestRunner"
-
-  logging.info("Running the tests...")
-  logging.debug("Command = %s" % cmd)
-  (stdoutdata, stderrdata) = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
-  if stderrdata != "":
-    logging.info("Failed to start tests:\n%s", stderrdata)
-    return
-  if re.search("^INSTRUMENTATION_STATUS_CODE: -1", stdoutdata, re.MULTILINE) != None:
-    logging.info("Failed to run the tests. Is DumpRenderTree2 installed on the device?")
-    return
-  if re.search("^OK \([0-9]+ tests?\)", stdoutdata, re.MULTILINE) == None:
-    logging.info("DumpRenderTree2 failed to run correctly:\n%s", stdoutdata)
-    return
-
-  logging.info("Downloading the summaries...")
-
-  # Download the txt summary to tmp folder
-  summary_txt_tmp_path = os.path.join(tmpdir, SUMMARY_TXT)
-  cmd = "rm -f " + summary_txt_tmp_path + ";"
-  cmd += adb_cmd + " pull " + RESULTS_ABSOLUTE_PATH + SUMMARY_TXT + " " + summary_txt_tmp_path
-  subprocess.Popen(cmd, shell=True).wait()
-
-  # Download the html summary to tmp folder
-  details_html_tmp_path = os.path.join(tmpdir, DETAILS_HTML)
-  cmd = "rm -f " + details_html_tmp_path + ";"
-  cmd += adb_cmd + " pull " + RESULTS_ABSOLUTE_PATH + DETAILS_HTML + " " + details_html_tmp_path
-  subprocess.Popen(cmd, shell=True).wait()
-
-  # Print summary to console
-  logging.info("All done.\n")
-  cmd = "cat " + summary_txt_tmp_path
-  os.system(cmd)
-  logging.info("")
-
-  # Open the browser with summary
-  if options.show_results_in_browser != "false":
-    webbrowser.open(details_html_tmp_path)
-
-if __name__ == "__main__":
-  option_parser = optparse.OptionParser(usage="Usage: %prog [options] test-relative-path")
-  option_parser.add_option("", "--show-results-in-browser", default="true",
-                           help="Show the results the host's default web browser, default=true")
-  option_parser.add_option("", "--tests-root-directory",
-                           help="The directory from which to take the tests, default is external/webkit/LayoutTests in this checkout of the Android tree")
-  option_parser.add_option("-s", "--serial", default=None, help="Specify the serial number of device to run test on")
-  options, args = option_parser.parse_args();
-
-  logging.basicConfig(level=logging.INFO, format='%(message)s')
-
-  if len(args) > 1:
-    logging.fatal("Usage: run_layout_tests.py [options] test-relative-path")
-  else:
-    if len(args) < 1:
-      path = "";
-    else:
-      path = args[0]
-    main(path, options);
diff --git a/tests/DumpRenderTree2/res/drawable/folder.png b/tests/DumpRenderTree2/res/drawable/folder.png
deleted file mode 100644
index 5b3fcec..0000000
--- a/tests/DumpRenderTree2/res/drawable/folder.png
+++ /dev/null
Binary files differ
diff --git a/tests/DumpRenderTree2/res/drawable/runtest.png b/tests/DumpRenderTree2/res/drawable/runtest.png
deleted file mode 100644
index 910c654..0000000
--- a/tests/DumpRenderTree2/res/drawable/runtest.png
+++ /dev/null
Binary files differ
diff --git a/tests/DumpRenderTree2/res/layout/dirlist_row.xml b/tests/DumpRenderTree2/res/layout/dirlist_row.xml
deleted file mode 100644
index e5578a6..0000000
--- a/tests/DumpRenderTree2/res/layout/dirlist_row.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 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
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:gravity="center_vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content">
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="80px"
-        android:adjustViewBounds="true"
-        android:paddingLeft="15px"
-        android:paddingRight="15px"
-        android:paddingTop="15px"
-        android:paddingBottom="15px"
-        android:layout_height="wrap_content"
-    />
-
-    <TextView
-        android:id="@+id/label"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="60px"
-        android:gravity="center_vertical"
-        android:textSize="14sp"
-    />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/res/menu/gui_menu.xml b/tests/DumpRenderTree2/res/menu/gui_menu.xml
deleted file mode 100644
index a5b2b65..0000000
--- a/tests/DumpRenderTree2/res/menu/gui_menu.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 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
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/run_all"
-          android:title="@string/run_all_tests" />
-</menu>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/res/values/strings.xml b/tests/DumpRenderTree2/res/values/strings.xml
deleted file mode 100644
index 0496404..0000000
--- a/tests/DumpRenderTree2/res/values/strings.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 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
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT 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="dialog_run_abort_dir_title_prefix">Directory:</string>
-    <string name="dialog_run_abort_dir_msg">This will run all the tests in this directory and all
-            the subdirectories. It may take a few hours!</string>
-    <string name="dialog_run_abort_dir_ok_button">Run tests!</string>
-    <string name="dialog_run_abort_dir_abort_button">Abort</string>
-
-    <string name="dialog_progress_title">Loading items.</string>
-    <string name="dialog_progress_msg">Please wait...</string>
-
-    <string name="runner_preloading_title">Preloading tests...</string>
-
-    <string name="run_all_tests">Run all tests in the current directory</string>
-</resources>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/res/values/style.xml b/tests/DumpRenderTree2/res/values/style.xml
deleted file mode 100644
index 35f3419..0000000
--- a/tests/DumpRenderTree2/res/values/style.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 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
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT 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>
-    <style name="WhiteBackground">
-        <item name="android:background">@android:color/white</item>
-    </style>
-</resources>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java
deleted file mode 100644
index 614b03c..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.os.Bundle;
-import android.os.Message;
-import android.util.Log;
-import android.webkit.WebView;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-
-/**
- * A class that represent a result of the test. It is responsible for returning the result's
- * raw data and generating its own diff in HTML format.
- */
-public abstract class AbstractResult implements Comparable<AbstractResult>, Serializable {
-
-    private static final String LOG_TAG = "AbstractResult";
-
-    public enum TestType {
-        TEXT {
-            @Override
-            public AbstractResult createResult(Bundle bundle) {
-                return new TextResult(bundle);
-            }
-        },
-        RENDER_TREE {
-            @Override
-            public AbstractResult createResult(Bundle bundle) {
-                /** TODO: RenderTree tests are not yet supported */
-                return null;
-            }
-        };
-
-        public abstract AbstractResult createResult(Bundle bundle);
-    }
-
-    /**
-     * A code representing the result of comparing actual and expected results.
-     */
-    public enum ResultCode implements Serializable {
-        RESULTS_MATCH("Results match"),
-        RESULTS_DIFFER("Results differ"),
-        NO_EXPECTED_RESULT("No expected result"),
-        NO_ACTUAL_RESULT("No actual result");
-
-        private String mTitle;
-
-        private ResultCode(String title) {
-            mTitle = title;
-        }
-
-        @Override
-        public String toString() {
-            return mTitle;
-        }
-    }
-
-    String mAdditionalTextOutputString;
-
-    public int compareTo(AbstractResult another) {
-        return getRelativePath().compareTo(another.getRelativePath());
-    }
-
-    public void setAdditionalTextOutputString(String additionalTextOutputString) {
-        mAdditionalTextOutputString = additionalTextOutputString;
-    }
-
-    public String getAdditionalTextOutputString() {
-        return mAdditionalTextOutputString;
-    }
-
-    public byte[] getBytes() {
-        ByteArrayOutputStream baos = null;
-        ObjectOutputStream oos = null;
-        try {
-            try {
-                baos = new ByteArrayOutputStream();
-                oos = new ObjectOutputStream(baos);
-                oos.writeObject(this);
-            } finally {
-                if (baos != null) {
-                    baos.close();
-                }
-                if (oos != null) {
-                    oos.close();
-                }
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Unable to serialize result: " + getRelativePath(), e);
-        }
-
-        return baos == null ? null : baos.toByteArray();
-    }
-
-    public static AbstractResult create(byte[] bytes) {
-        ByteArrayInputStream bais = null;
-        ObjectInputStream ois = null;
-        AbstractResult result = null;
-        try {
-            try {
-                bais = new ByteArrayInputStream(bytes);
-                ois = new ObjectInputStream(bais);
-                result = (AbstractResult)ois.readObject();
-            } finally {
-                if (bais != null) {
-                    bais.close();
-                }
-                if (ois != null) {
-                    ois.close();
-                }
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Unable to deserialize result!", e);
-        } catch (ClassNotFoundException e) {
-            Log.e(LOG_TAG, "Unable to deserialize result!", e);
-        }
-        return result;
-    }
-
-    public void clearResults() {
-        mAdditionalTextOutputString = null;
-    }
-
-    /**
-     * Makes the result object obtain the results of the test from the webview
-     * and store them in the format that suits itself bests. This method is asynchronous.
-     * The message passed as a parameter is a message that should be sent to its target
-     * when the result finishes obtaining the result.
-     *
-     * @param webview
-     * @param resultObtainedMsg
-     */
-    public abstract void obtainActualResults(WebView webview, Message resultObtainedMsg);
-
-    public abstract void setExpectedImageResult(byte[] expectedResult);
-
-    public abstract void setExpectedImageResultPath(String relativePath);
-
-    public abstract String getExpectedImageResultPath();
-
-    public abstract void setExpectedTextResult(String expectedResult);
-
-    public abstract void setExpectedTextResultPath(String relativePath);
-
-    public abstract String getExpectedTextResultPath();
-
-    /**
-     * Returns result's image data that can be written to the disk. It can be null
-     * if there is an error of some sort or for example the test times out.
-     *
-     * <p> Some tests will not provide data (like text tests)
-     *
-     * @return
-     *      results image data
-     */
-    public abstract byte[] getActualImageResult();
-
-    /**
-     * Returns result's text data. It can be null
-     * if there is an error of some sort or for example the test times out.
-     *
-     * @return
-     *      results text data
-     */
-    public abstract String getActualTextResult();
-
-    /**
-     * Returns the status code representing the result of comparing actual and expected results.
-     *
-     * @return
-     *      the status code from comparing actual and expected results
-     */
-    public abstract ResultCode getResultCode();
-
-    /**
-     * Returns whether this test crashed.
-     *
-     * @return
-     *      whether this test crashed
-     */
-    public abstract boolean didCrash();
-
-    /**
-     * Returns whether this test timed out.
-     *
-     * @return
-     *      whether this test timed out
-     */
-    public abstract boolean didTimeOut();
-
-    /**
-     * Sets that this test timed out.
-     */
-    public abstract void setDidTimeOut();
-
-    /**
-     * Returns whether the test passed.
-     *
-     * @return
-     *      whether the test passed
-     */
-    public boolean didPass() {
-        // Tests that crash can't have timed out or have an actual result.
-        assert !(didCrash() && didTimeOut());
-        assert !(didCrash() && getResultCode() != ResultCode.NO_ACTUAL_RESULT);
-        return !didCrash() && !didTimeOut() && getResultCode() == ResultCode.RESULTS_MATCH;
-    }
-
-    /**
-     * Return the type of the result data.
-     *
-     * @return
-     *      the type of the result data.
-     */
-    public abstract TestType getType();
-
-    public abstract String getRelativePath();
-
-    /**
-     * Returns a piece of HTML code that presents a visual diff between a result and
-     * the expected result.
-     *
-     * @return
-     *      a piece of HTML code with a visual diff between the result and the expected result
-     */
-    public abstract String getDiffAsHtml();
-
-    public abstract Bundle getBundle();
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AdditionalTextOutput.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AdditionalTextOutput.java
deleted file mode 100644
index bb9a916..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AdditionalTextOutput.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.util.Log;
-import android.webkit.ConsoleMessage;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * A class that stores consoles messages, database callbacks, alert messages, etc.
- */
-public class AdditionalTextOutput {
-    private static final String LOG_TAG = "AdditionalTextOutput";
-
-    /**
-     * Ordering of enums is important as it determines ordering of the toString method!
-     * StringBuilders will be printed in the order the corresponding types appear here.
-     */
-    private enum OutputType {
-        JS_DIALOG,
-        EXCEEDED_DB_QUOTA_MESSAGE,
-        CONSOLE_MESSAGE;
-    }
-
-    StringBuilder[] mOutputs = new StringBuilder[OutputType.values().length];
-
-    private StringBuilder getStringBuilderForType(OutputType outputType) {
-        int index = outputType.ordinal();
-        if (mOutputs[index] == null) {
-            mOutputs[index] = new StringBuilder();
-        }
-        return mOutputs[index];
-    }
-
-    public void appendExceededDbQuotaMessage(String urlString, String databaseIdentifier) {
-        StringBuilder output = getStringBuilderForType(OutputType.EXCEEDED_DB_QUOTA_MESSAGE);
-
-        String protocol = "";
-        String host = "";
-        int port = 0;
-
-        try {
-            URL url = new URL(urlString);
-            protocol = url.getProtocol();
-            host = url.getHost();
-            if (url.getPort() > -1) {
-                port = url.getPort();
-            }
-        } catch (MalformedURLException e) {
-            Log.e(LOG_TAG, "urlString=" + urlString + " databaseIdentifier=" + databaseIdentifier,
-                    e);
-        }
-
-        output.append("UI DELEGATE DATABASE CALLBACK: ");
-        output.append("exceededDatabaseQuotaForSecurityOrigin:{");
-        output.append(protocol + ", " + host + ", " + port + "} ");
-        output.append("database:" + databaseIdentifier + "\n");
-    }
-
-    public void appendConsoleMessage(ConsoleMessage consoleMessage) {
-        StringBuilder output = getStringBuilderForType(OutputType.CONSOLE_MESSAGE);
-
-        output.append("CONSOLE MESSAGE: line " + consoleMessage.lineNumber());
-        output.append(": " + consoleMessage.message() + "\n");
-    }
-
-    public void appendJsAlert(String message) {
-        StringBuilder output = getStringBuilderForType(OutputType.JS_DIALOG);
-
-        output.append("ALERT: ");
-        output.append(message);
-        output.append('\n');
-    }
-
-    public void appendJsConfirm(String message) {
-        StringBuilder output = getStringBuilderForType(OutputType.JS_DIALOG);
-
-        output.append("CONFIRM: ");
-        output.append(message);
-        output.append('\n');
-    }
-
-    public void appendJsPrompt(String message, String defaultValue) {
-        StringBuilder output = getStringBuilderForType(OutputType.JS_DIALOG);
-
-        output.append("PROMPT: ");
-        output.append(message);
-        output.append(", default text: ");
-        output.append(defaultValue);
-        output.append('\n');
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder result = new StringBuilder();
-        for (int i = 0; i < mOutputs.length; i++) {
-            if (mOutputs[i] != null) {
-                result.append(mOutputs[i].toString());
-            }
-        }
-        return result.toString();
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/CrashedDummyResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/CrashedDummyResult.java
deleted file mode 100644
index 4831168..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/CrashedDummyResult.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.os.Bundle;
-import android.os.Message;
-import android.webkit.WebView;
-
-/**
- * A dummy class representing test that crashed.
- *
- * TODO: All the methods regarding expected results need implementing.
- */
-public class CrashedDummyResult extends AbstractResult {
-    String mRelativePath;
-
-    public CrashedDummyResult(String relativePath) {
-        mRelativePath = relativePath;
-    }
-
-    @Override
-    public byte[] getActualImageResult() {
-        return null;
-    }
-
-    @Override
-    public String getActualTextResult() {
-        return null;
-    }
-
-    @Override
-    public Bundle getBundle() {
-        /** TODO:  */
-        return null;
-    }
-
-    @Override
-    public String getDiffAsHtml() {
-        /** TODO: Probably show at least expected results */
-        return "Ooops, I crashed...";
-    }
-
-    @Override
-    public String getRelativePath() {
-        return mRelativePath;
-    }
-
-    @Override
-    public ResultCode getResultCode() {
-        return ResultCode.NO_ACTUAL_RESULT;
-    }
-
-    @Override
-    public boolean didCrash() {
-        return true;
-    }
-
-    @Override
-    public boolean didTimeOut() {
-        return false;
-    }
-
-    @Override
-    public void setDidTimeOut() {
-        /** This method is not applicable for this type of result */
-        assert false;
-    }
-
-    @Override
-    public TestType getType() {
-        return null;
-    }
-
-    @Override
-    public void obtainActualResults(WebView webview, Message resultObtainedMsg) {
-        /** This method is not applicable for this type of result */
-        assert false;
-    }
-
-    @Override
-    public void setExpectedImageResult(byte[] expectedResult) {
-        /** TODO */
-    }
-
-    @Override
-    public void setExpectedTextResult(String expectedResult) {
-        /** TODO */
-    }
-
-    @Override
-    public String getExpectedImageResultPath() {
-        /** TODO */
-        return null;
-    }
-
-    @Override
-    public String getExpectedTextResultPath() {
-        /** TODO */
-        return null;
-    }
-
-    @Override
-    public void setExpectedImageResultPath(String relativePath) {
-        /** TODO */
-    }
-
-    @Override
-    public void setExpectedTextResultPath(String relativePath) {
-        /** TODO */
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSender.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSender.java
deleted file mode 100644
index 5b7cbc4..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSender.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.webkit.WebView;
-
-/**
- * A class that acts as a JS interface for webview to mock various touch events,
- * mouse actions and key presses.
- *
- * The methods here just call corresponding methods on EventSenderImpl
- * that contains the logic of how to execute the methods.
- */
-public class EventSender {
-    EventSenderImpl mEventSenderImpl = new EventSenderImpl();
-
-    public void reset(WebView webView) {
-        mEventSenderImpl.reset(webView);
-    }
-
-    public void enableDOMUIEventLogging(int domNode) {
-        mEventSenderImpl.enableDOMUIEventLogging(domNode);
-    }
-
-    public void fireKeyboardEventsToElement(int domNode) {
-        mEventSenderImpl.fireKeyboardEventsToElement(domNode);
-    }
-
-    public void keyDown(String character, String[] withModifiers) {
-        mEventSenderImpl.keyDown(character, withModifiers);
-    }
-
-    public void keyDown(String character) {
-        keyDown(character, null);
-    }
-
-    public void leapForward(int milliseconds) {
-        mEventSenderImpl.leapForward(milliseconds);
-    }
-
-    public void mouseClick() {
-        mEventSenderImpl.mouseClick();
-    }
-
-    public void mouseDown() {
-        mEventSenderImpl.mouseDown();
-    }
-
-    public void mouseMoveTo(int x, int y) {
-        mEventSenderImpl.mouseMoveTo(x, y);
-    }
-
-    public void mouseUp() {
-        mEventSenderImpl.mouseUp();
-    }
-
-    public void touchStart() {
-        mEventSenderImpl.touchStart();
-    }
-
-    public void addTouchPoint(int x, int y) {
-        mEventSenderImpl.addTouchPoint(x, y);
-    }
-
-    public void updateTouchPoint(int id, int x, int y) {
-        mEventSenderImpl.updateTouchPoint(id, x, y);
-    }
-
-    public void setTouchModifier(String modifier, boolean enabled) {
-        mEventSenderImpl.setTouchModifier(modifier, enabled);
-    }
-
-    public void touchMove() {
-        mEventSenderImpl.touchMove();
-    }
-
-    public void releaseTouchPoint(int id) {
-        mEventSenderImpl.releaseTouchPoint(id);
-    }
-
-    public void touchEnd() {
-        mEventSenderImpl.touchEnd();
-    }
-
-    public void touchCancel() {
-        mEventSenderImpl.touchCancel();
-    }
-
-    public void clearTouchPoints() {
-        mEventSenderImpl.clearTouchPoints();
-    }
-
-    public void cancelTouchPoint(int id) {
-        mEventSenderImpl.cancelTouchPoint(id);
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java
deleted file mode 100644
index af22039..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.webkit.WebView;
-
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * An implementation of EventSender
- */
-public class EventSenderImpl {
-    private static final String LOG_TAG = "EventSenderImpl";
-
-    private static final int MSG_ENABLE_DOM_UI_EVENT_LOGGING = 0;
-    private static final int MSG_FIRE_KEYBOARD_EVENTS_TO_ELEMENT = 1;
-    private static final int MSG_LEAP_FORWARD = 2;
-
-    private static final int MSG_KEY_DOWN = 3;
-
-    private static final int MSG_MOUSE_DOWN = 4;
-    private static final int MSG_MOUSE_UP = 5;
-    private static final int MSG_MOUSE_CLICK = 6;
-    private static final int MSG_MOUSE_MOVE_TO = 7;
-
-    private static final int MSG_ADD_TOUCH_POINT = 8;
-    private static final int MSG_TOUCH_START = 9;
-    private static final int MSG_UPDATE_TOUCH_POINT = 10;
-    private static final int MSG_TOUCH_MOVE = 11;
-    private static final int MSG_CLEAR_TOUCH_POINTS = 12;
-    private static final int MSG_TOUCH_CANCEL = 13;
-    private static final int MSG_RELEASE_TOUCH_POINT = 14;
-    private static final int MSG_TOUCH_END = 15;
-    private static final int MSG_SET_TOUCH_MODIFIER = 16;
-    private static final int MSG_CANCEL_TOUCH_POINT = 17;
-
-    private static class Point {
-        private int mX;
-        private int mY;
-
-        public Point(int x, int y) {
-            mX = x;
-            mY = y;
-        }
-        public int x() {
-            return mX;
-        }
-        public int y() {
-            return mY;
-        }
-    }
-
-    private Point createViewPointFromContentCoordinates(int x, int y) {
-        return new Point(Math.round(x * mWebView.getScale()) - mWebView.getScrollX(),
-                         Math.round(y * mWebView.getScale()) - mWebView.getScrollY());
-    }
-
-    public static class TouchPoint {
-        private int mId;
-        private Point mPoint;
-        private long mDownTime;
-        private boolean mReleased = false;
-        private boolean mMoved = false;
-        private boolean mCancelled = false;
-
-        public TouchPoint(int id, Point point) {
-            mId = id;
-            mPoint = point;
-        }
-
-        public int getId() {
-          return mId;
-        }
-
-        public int getX() {
-            return mPoint.x();
-        }
-
-        public int getY() {
-            return mPoint.y();
-        }
-
-        public boolean hasMoved() {
-            return mMoved;
-        }
-
-        public void move(Point point) {
-            mPoint = point;
-            mMoved = true;
-        }
-
-        public void resetHasMoved() {
-            mMoved = false;
-        }
-
-        public long getDownTime() {
-            return mDownTime;
-        }
-
-        public void setDownTime(long downTime) {
-            mDownTime = downTime;
-        }
-
-        public boolean isReleased() {
-            return mReleased;
-        }
-
-        public void release() {
-            mReleased = true;
-        }
-
-        public boolean isCancelled() {
-            return mCancelled;
-        }
-
-        public void cancel() {
-            mCancelled = true;
-        }
-    }
-
-    private List<TouchPoint> mTouchPoints;
-    private int mTouchMetaState;
-    private Point mMousePoint;
-
-    private WebView mWebView;
-
-    private Handler mEventSenderHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            Bundle bundle;
-            MotionEvent event;
-            long ts;
-
-            switch (msg.what) {
-                case MSG_ENABLE_DOM_UI_EVENT_LOGGING:
-                    /** TODO: implement */
-                    break;
-
-                case MSG_FIRE_KEYBOARD_EVENTS_TO_ELEMENT:
-                    /** TODO: implement */
-                    break;
-
-                case MSG_LEAP_FORWARD:
-                    /** TODO: implement */
-                    break;
-
-                case MSG_KEY_DOWN:
-                    bundle = (Bundle)msg.obj;
-                    String character = bundle.getString("character");
-                    String[] withModifiers = bundle.getStringArray("withModifiers");
-
-                    if (withModifiers != null && withModifiers.length > 0) {
-                        for (int i = 0; i < withModifiers.length; i++) {
-                            executeKeyEvent(KeyEvent.ACTION_DOWN,
-                                    modifierToKeyCode(withModifiers[i]));
-                        }
-                    }
-                    executeKeyEvent(KeyEvent.ACTION_DOWN,
-                            charToKeyCode(character.toLowerCase().toCharArray()[0]));
-                    break;
-
-                /** MOUSE */
-
-                case MSG_MOUSE_DOWN:
-                    if (mMousePoint != null) {
-                        ts = SystemClock.uptimeMillis();
-                        event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_DOWN, mMousePoint.x(), mMousePoint.y(), 0);
-                        mWebView.onTouchEvent(event);
-                    }
-                    break;
-
-                case MSG_MOUSE_UP:
-                    if (mMousePoint != null) {
-                        ts = SystemClock.uptimeMillis();
-                        event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_UP, mMousePoint.x(), mMousePoint.y(), 0);
-                        mWebView.onTouchEvent(event);
-                    }
-                    break;
-
-                case MSG_MOUSE_CLICK:
-                    mouseDown();
-                    mouseUp();
-                    break;
-
-                case MSG_MOUSE_MOVE_TO:
-                    mMousePoint = createViewPointFromContentCoordinates(msg.arg1, msg.arg2);
-                    break;
-
-                /** TOUCH */
-
-                case MSG_ADD_TOUCH_POINT:
-                    int numPoints = getTouchPoints().size();
-                    int id;
-                    if (numPoints == 0) {
-                        id = 0;
-                    } else {
-                        id = getTouchPoints().get(numPoints - 1).getId() + 1;
-                    }
-                    getTouchPoints().add(
-                            new TouchPoint(id, createViewPointFromContentCoordinates(msg.arg1, msg.arg2)));
-                    break;
-
-                case MSG_TOUCH_START:
-                    if (getTouchPoints().isEmpty()) {
-                        return;
-                    }
-                    for (int i = 0; i < getTouchPoints().size(); ++i) {
-                        getTouchPoints().get(i).setDownTime(SystemClock.uptimeMillis());
-                    }
-                    executeTouchEvent(MotionEvent.ACTION_DOWN);
-                    break;
-
-                case MSG_UPDATE_TOUCH_POINT:
-                    bundle = (Bundle)msg.obj;
-
-                    int index = bundle.getInt("id");
-                    if (index >= getTouchPoints().size()) {
-                        Log.w(LOG_TAG + "::MSG_UPDATE_TOUCH_POINT", "TouchPoint out of bounds: "
-                                + index);
-                        break;
-                    }
-
-                    getTouchPoints().get(index).move(
-                            createViewPointFromContentCoordinates(bundle.getInt("x"), bundle.getInt("y")));
-                    break;
-
-                case MSG_TOUCH_MOVE:
-                    /**
-                     * FIXME: At the moment we don't support multi-touch. Hence, we only examine
-                     * the first touch point. In future this method will need rewriting.
-                     */
-                    if (getTouchPoints().isEmpty()) {
-                        return;
-                    }
-                    executeTouchEvent(MotionEvent.ACTION_MOVE);
-                    for (int i = 0; i < getTouchPoints().size(); ++i) {
-                        getTouchPoints().get(i).resetHasMoved();
-                    }
-                    break;
-
-                case MSG_CANCEL_TOUCH_POINT:
-                    if (msg.arg1 >= getTouchPoints().size()) {
-                        Log.w(LOG_TAG + "::MSG_RELEASE_TOUCH_POINT", "TouchPoint out of bounds: "
-                                + msg.arg1);
-                        break;
-                    }
-
-                    getTouchPoints().get(msg.arg1).cancel();
-                    break;
-
-                case MSG_TOUCH_CANCEL:
-                    /**
-                     * FIXME: At the moment we don't support multi-touch. Hence, we only examine
-                     * the first touch point. In future this method will need rewriting.
-                     */
-                    if (getTouchPoints().isEmpty()) {
-                        return;
-                    }
-                    executeTouchEvent(MotionEvent.ACTION_CANCEL);
-                    break;
-
-                case MSG_RELEASE_TOUCH_POINT:
-                    if (msg.arg1 >= getTouchPoints().size()) {
-                        Log.w(LOG_TAG + "::MSG_RELEASE_TOUCH_POINT", "TouchPoint out of bounds: "
-                                + msg.arg1);
-                        break;
-                    }
-
-                    getTouchPoints().get(msg.arg1).release();
-                    break;
-
-                case MSG_TOUCH_END:
-                    /**
-                     * FIXME: At the moment we don't support multi-touch. Hence, we only examine
-                     * the first touch point. In future this method will need rewriting.
-                     */
-                    if (getTouchPoints().isEmpty()) {
-                        return;
-                    }
-                    executeTouchEvent(MotionEvent.ACTION_UP);
-                    // remove released points.
-                    for (int i = getTouchPoints().size() - 1; i >= 0; --i) {
-                        if (getTouchPoints().get(i).isReleased()) {
-                            getTouchPoints().remove(i);
-                        }
-                    }
-                    break;
-
-                case MSG_SET_TOUCH_MODIFIER:
-                    bundle = (Bundle)msg.obj;
-                    String modifier = bundle.getString("modifier");
-                    boolean enabled = bundle.getBoolean("enabled");
-
-                    int mask = 0;
-                    if ("alt".equals(modifier.toLowerCase())) {
-                        mask = KeyEvent.META_ALT_ON;
-                    } else if ("shift".equals(modifier.toLowerCase())) {
-                        mask = KeyEvent.META_SHIFT_ON;
-                    } else if ("ctrl".equals(modifier.toLowerCase())) {
-                        mask = KeyEvent.META_SYM_ON;
-                    }
-
-                    if (enabled) {
-                        mTouchMetaState |= mask;
-                    } else {
-                        mTouchMetaState &= ~mask;
-                    }
-
-                    break;
-
-                case MSG_CLEAR_TOUCH_POINTS:
-                    getTouchPoints().clear();
-                    break;
-
-                default:
-                    break;
-            }
-        }
-    };
-
-    public void reset(WebView webView) {
-        mWebView = webView;
-        mTouchPoints = null;
-        mTouchMetaState = 0;
-        mMousePoint = null;
-    }
-
-    public void enableDOMUIEventLogging(int domNode) {
-        Message msg = mEventSenderHandler.obtainMessage(MSG_ENABLE_DOM_UI_EVENT_LOGGING);
-        msg.arg1 = domNode;
-        msg.sendToTarget();
-    }
-
-    public void fireKeyboardEventsToElement(int domNode) {
-        Message msg = mEventSenderHandler.obtainMessage(MSG_FIRE_KEYBOARD_EVENTS_TO_ELEMENT);
-        msg.arg1 = domNode;
-        msg.sendToTarget();
-    }
-
-    public void leapForward(int milliseconds) {
-        Message msg = mEventSenderHandler.obtainMessage(MSG_LEAP_FORWARD);
-        msg.arg1 = milliseconds;
-        msg.sendToTarget();
-    }
-
-    public void keyDown(String character, String[] withModifiers) {
-        Bundle bundle = new Bundle();
-        bundle.putString("character", character);
-        bundle.putStringArray("withModifiers", withModifiers);
-        mEventSenderHandler.obtainMessage(MSG_KEY_DOWN, bundle).sendToTarget();
-    }
-
-    /** MOUSE */
-
-    public void mouseDown() {
-        mEventSenderHandler.sendEmptyMessage(MSG_MOUSE_DOWN);
-    }
-
-    public void mouseUp() {
-        mEventSenderHandler.sendEmptyMessage(MSG_MOUSE_UP);
-    }
-
-    public void mouseClick() {
-        mEventSenderHandler.sendEmptyMessage(MSG_MOUSE_CLICK);
-    }
-
-    public void mouseMoveTo(int x, int y) {
-        mEventSenderHandler.obtainMessage(MSG_MOUSE_MOVE_TO, x, y).sendToTarget();
-    }
-
-    /** TOUCH */
-
-    public void addTouchPoint(int x, int y) {
-        mEventSenderHandler.obtainMessage(MSG_ADD_TOUCH_POINT, x, y).sendToTarget();
-    }
-
-    public void touchStart() {
-        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_START);
-    }
-
-    public void updateTouchPoint(int id, int x, int y) {
-        Bundle bundle = new Bundle();
-        bundle.putInt("id", id);
-        bundle.putInt("x", x);
-        bundle.putInt("y", y);
-        mEventSenderHandler.obtainMessage(MSG_UPDATE_TOUCH_POINT, bundle).sendToTarget();
-    }
-
-    public void touchMove() {
-        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_MOVE);
-    }
-
-    public void cancelTouchPoint(int id) {
-        Message msg = mEventSenderHandler.obtainMessage(MSG_CANCEL_TOUCH_POINT);
-        msg.arg1 = id;
-        msg.sendToTarget();
-    }
-
-    public void touchCancel() {
-        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_CANCEL);
-    }
-
-    public void releaseTouchPoint(int id) {
-        Message msg = mEventSenderHandler.obtainMessage(MSG_RELEASE_TOUCH_POINT);
-        msg.arg1 = id;
-        msg.sendToTarget();
-    }
-
-    public void touchEnd() {
-        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_END);
-    }
-
-    public void setTouchModifier(String modifier, boolean enabled) {
-        Bundle bundle = new Bundle();
-        bundle.putString("modifier", modifier);
-        bundle.putBoolean("enabled", enabled);
-        mEventSenderHandler.obtainMessage(MSG_SET_TOUCH_MODIFIER, bundle).sendToTarget();
-    }
-
-    public void clearTouchPoints() {
-        mEventSenderHandler.sendEmptyMessage(MSG_CLEAR_TOUCH_POINTS);
-    }
-
-    private List<TouchPoint> getTouchPoints() {
-        if (mTouchPoints == null) {
-            mTouchPoints = new LinkedList<TouchPoint>();
-        }
-
-        return mTouchPoints;
-    }
-
-    private void executeTouchEvent(int action) {
-        int numPoints = getTouchPoints().size();
-        int[] pointerIds = new int[numPoints];
-        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
-
-        for (int i = 0; i < numPoints; ++i) {
-            boolean isNeeded = false;
-            switch(action) {
-            case MotionEvent.ACTION_DOWN:
-            case MotionEvent.ACTION_UP:
-                isNeeded = true;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                isNeeded = getTouchPoints().get(i).hasMoved();
-                break;
-            case MotionEvent.ACTION_CANCEL:
-                isNeeded = getTouchPoints().get(i).isCancelled();
-                break;
-            default:
-                Log.w(LOG_TAG + "::executeTouchEvent(),", "action not supported:" + action);
-                break;
-            }
-
-            numPoints = 0;
-            if (isNeeded) {
-                pointerIds[numPoints] = getTouchPoints().get(i).getId();
-                pointerCoords[numPoints] = new MotionEvent.PointerCoords();
-                pointerCoords[numPoints].x = getTouchPoints().get(i).getX();
-                pointerCoords[numPoints].y = getTouchPoints().get(i).getY();
-                ++numPoints;
-            }
-        }
-
-        if (numPoints == 0) {
-            return;
-        }
-
-        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).getDownTime(),
-                SystemClock.uptimeMillis(), action,
-                numPoints, pointerIds, pointerCoords,
-                mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
-
-        mWebView.onTouchEvent(event);
-    }
-
-    private void executeKeyEvent(int action, int keyCode) {
-        KeyEvent event = new KeyEvent(action, keyCode);
-        mWebView.onKeyDown(event.getKeyCode(), event);
-    }
-
-    /**
-     * Assumes lowercase chars, case needs to be handled by calling function.
-     */
-    private static int charToKeyCode(char c) {
-        // handle numbers
-        if (c >= '0' && c <= '9') {
-            int offset = c - '0';
-            return KeyEvent.KEYCODE_0 + offset;
-        }
-
-        // handle characters
-        if (c >= 'a' && c <= 'z') {
-            int offset = c - 'a';
-            return KeyEvent.KEYCODE_A + offset;
-        }
-
-        // handle all others
-        switch (c) {
-            case '*':
-                return KeyEvent.KEYCODE_STAR;
-
-            case '#':
-                return KeyEvent.KEYCODE_POUND;
-
-            case ',':
-                return KeyEvent.KEYCODE_COMMA;
-
-            case '.':
-                return KeyEvent.KEYCODE_PERIOD;
-
-            case '\t':
-                return KeyEvent.KEYCODE_TAB;
-
-            case ' ':
-                return KeyEvent.KEYCODE_SPACE;
-
-            case '\n':
-                return KeyEvent.KEYCODE_ENTER;
-
-            case '\b':
-            case 0x7F:
-                return KeyEvent.KEYCODE_DEL;
-
-            case '~':
-                return KeyEvent.KEYCODE_GRAVE;
-
-            case '-':
-                return KeyEvent.KEYCODE_MINUS;
-
-            case '=':
-                return KeyEvent.KEYCODE_EQUALS;
-
-            case '(':
-                return KeyEvent.KEYCODE_LEFT_BRACKET;
-
-            case ')':
-                return KeyEvent.KEYCODE_RIGHT_BRACKET;
-
-            case '\\':
-                return KeyEvent.KEYCODE_BACKSLASH;
-
-            case ';':
-                return KeyEvent.KEYCODE_SEMICOLON;
-
-            case '\'':
-                return KeyEvent.KEYCODE_APOSTROPHE;
-
-            case '/':
-                return KeyEvent.KEYCODE_SLASH;
-
-            default:
-                return c;
-        }
-    }
-
-    private static int modifierToKeyCode(String modifier) {
-        if (modifier.equals("ctrlKey")) {
-            return KeyEvent.KEYCODE_ALT_LEFT;
-        } else if (modifier.equals("shiftKey")) {
-            return KeyEvent.KEYCODE_SHIFT_LEFT;
-        } else if (modifier.equals("altKey")) {
-            return KeyEvent.KEYCODE_SYM;
-        }
-
-        return KeyEvent.KEYCODE_UNKNOWN;
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
deleted file mode 100644
index 5360e3d..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.util.Log;
-
-import com.android.dumprendertree2.forwarder.ForwarderManager;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A utility to filter out some files/directories from the views and tests that run.
- */
-public class FileFilter {
-    private static final String LOG_TAG = "FileFilter";
-
-    private static final String TEST_EXPECTATIONS_TXT_PATH =
-            "platform/android/test_expectations.txt";
-
-    private static final String HTTP_TESTS_PATH = "http/tests/";
-    private static final String SSL_PATH = "ssl/";
-
-    private static final String TOKEN_CRASH = "CRASH";
-    private static final String TOKEN_FAIL = "FAIL";
-    private static final String TOKEN_SLOW = "SLOW";
-
-    private final Set<String> mCrashList = new HashSet<String>();
-    private final Set<String> mFailList = new HashSet<String>();
-    private final Set<String> mSlowList = new HashSet<String>();
-
-    public FileFilter() {
-        loadTestExpectations();
-    }
-
-    private static final String trimTrailingSlashIfPresent(String path) {
-        File file = new File(path);
-        return file.getPath();
-    }
-
-    public void loadTestExpectations() {
-        URL url = null;
-        try {
-            url = new URL(ForwarderManager.getHostSchemePort(false) +
-                    "LayoutTests/" + TEST_EXPECTATIONS_TXT_PATH);
-        } catch (MalformedURLException e) {
-            assert false;
-        }
-
-        try {
-            InputStream inputStream = null;
-            BufferedReader bufferedReader = null;
-            try {
-                byte[] httpAnswer = FsUtils.readDataFromUrl(url);
-                if (httpAnswer == null) {
-                    Log.w(LOG_TAG, "loadTestExpectations(): File not found: " +
-                            TEST_EXPECTATIONS_TXT_PATH);
-                    return;
-                }
-                bufferedReader = new BufferedReader(new StringReader(
-                        new String(httpAnswer)));
-                String line;
-                String entry;
-                String[] parts;
-                String path;
-                Set<String> tokens;
-                while (true) {
-                    line = bufferedReader.readLine();
-                    if (line == null) {
-                        break;
-                    }
-
-                    /** Remove the comment and trim */
-                    entry = line.split("//", 2)[0].trim();
-
-                    /** Omit empty lines, advance to next line */
-                    if (entry.isEmpty()) {
-                        continue;
-                    }
-
-                    /** Split on whitespace into path part and the rest */
-                    parts = entry.split("\\s", 2);
-
-                    /** At this point parts.length >= 1 */
-                    if (parts.length == 1) {
-                        Log.w(LOG_TAG + "::reloadConfiguration",
-                                "There are no options specified for the test!");
-                        continue;
-                    }
-
-                    path = trimTrailingSlashIfPresent(parts[0]);
-
-                    /** Split on whitespace */
-                    tokens = new HashSet<String>(Arrays.asList(
-                            parts[1].split("\\s", 0)));
-
-                    /** Chose the right collections to add to */
-                    if (tokens.contains(TOKEN_CRASH)) {
-                        mCrashList.add(path);
-
-                        /** If test is on skip list we ignore any further options */
-                        continue;
-                    }
-
-                    if (tokens.contains(TOKEN_FAIL)) {
-                        mFailList.add(path);
-                    }
-                    if (tokens.contains(TOKEN_SLOW)) {
-                        mSlowList.add(path);
-                    }
-                }
-            } finally {
-                if (inputStream != null) {
-                    inputStream.close();
-                }
-                if (bufferedReader != null) {
-                    bufferedReader.close();
-                }
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "url=" + url, e);
-        }
-    }
-
-    /**
-     * Checks if test is expected to crash.
-     *
-     * <p>
-     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
-     *
-     * @param testPath
-     *            - a relative path within LayoutTests folder
-     * @return if the test is supposed to be skipped
-     */
-    public boolean isCrash(String testPath) {
-        for (String prefix : getPrefixes(testPath)) {
-            if (mCrashList.contains(prefix)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks if test result is supposed to be "failed".
-     *
-     * <p>
-     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
-     *
-     * @param testPath
-     *            - a relative path within LayoutTests folder
-     * @return if the test result is supposed to be "failed"
-     */
-    public boolean isFail(String testPath) {
-        for (String prefix : getPrefixes(testPath)) {
-            if (mFailList.contains(prefix)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks if test is slow and should have timeout increased.
-     *
-     * <p>
-     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
-     *
-     * @param testPath
-     *            - a relative path within LayoutTests folder
-     * @return if the test is slow and should have timeout increased.
-     */
-    public boolean isSlow(String testPath) {
-        for (String prefix : getPrefixes(testPath)) {
-            if (mSlowList.contains(prefix)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the list of all path prefixes of the given path.
-     *
-     * <p>
-     * e.g. this/is/a/path returns the list: this this/is this/is/a this/is/a/path
-     *
-     * @param path
-     * @return the list of all path prefixes of the given path.
-     */
-    private static List<String> getPrefixes(String path) {
-        File file = new File(path);
-        List<String> prefixes = new ArrayList<String>(8);
-
-        do {
-            prefixes.add(file.getPath());
-            file = file.getParentFile();
-        } while (file != null);
-
-        return prefixes;
-    }
-
-    /**
-     * Checks if the directory may contain tests or contains just helper files.
-     *
-     * @param dirName
-     * @return
-     *      if the directory may contain tests
-     */
-    public static boolean isTestDir(String dirName) {
-        return (!dirName.equals("script-tests")
-                && !dirName.equals("resources") && !dirName.startsWith("."));
-    }
-
-    /**
-     * Checks if the file is a test.
-     * Currently we run .html, .xhtml and .php tests.
-     *
-     * @warning You MUST also call isTestDir() on the parent directory before
-     * assuming that a file is a test.
-     *
-     * @param testName
-     * @return if the file is a test
-     */
-    public static boolean isTestFile(String testName) {
-        return testName.endsWith(".html")
-            || testName.endsWith(".xhtml")
-            || testName.endsWith(".php");
-    }
-
-    /**
-     * Return a URL of the test on the server.
-     *
-     * @param relativePath
-     * @param allowHttps Whether to allow the use of HTTPS, even if the file is in the SSL
-     *     directory.
-     * @return a URL of the test on the server
-     */
-    public static URL getUrl(String relativePath, boolean allowHttps) {
-        String urlBase = ForwarderManager.getHostSchemePort(false);
-
-        /**
-         * URL is formed differently for HTTP vs non-HTTP tests, because HTTP tests
-         * expect different document root. See run_apache2.py and .conf file for details
-         */
-        if (relativePath.startsWith(HTTP_TESTS_PATH)) {
-            relativePath = relativePath.substring(HTTP_TESTS_PATH.length());
-            if (relativePath.startsWith(SSL_PATH) && allowHttps) {
-                urlBase = ForwarderManager.getHostSchemePort(true);
-            }
-        } else {
-            relativePath = "LayoutTests/" + relativePath;
-        }
-
-        try {
-            return new URL(urlBase + relativePath);
-        } catch (MalformedURLException e) {
-            Log.e(LOG_TAG, "Malformed URL!", e);
-        }
-
-        return null;
-    }
-
-    /**
-     * If the path contains extension (e.g .foo at the end of the file) then it changes
-     * this (.foo) into newEnding (so it has to contain the dot if we want to preserve it).
-     *
-     * <p>If the path doesn't contain an extension, it adds the ending to the path.
-     *
-     * @param relativePath
-     * @param newEnding
-     * @return
-     *      a new path, containing the newExtension
-     */
-    public static String setPathEnding(String relativePath, String newEnding) {
-        int dotPos = relativePath.lastIndexOf('.');
-        if (dotPos == -1) {
-            return relativePath + newEnding;
-        }
-
-        return relativePath.substring(0, dotPos) + newEnding;
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java
deleted file mode 100644
index 54cbfda..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.util.Log;
-
-import com.android.dumprendertree2.forwarder.ForwarderManager;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.util.EntityUtils;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.MalformedURLException;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- *
- */
-public class FsUtils {
-    public static final String LOG_TAG = "FsUtils";
-
-    private static final String SCRIPT_URL = ForwarderManager.getHostSchemePort(false) +
-            "Tools/DumpRenderTree/android/get_layout_tests_dir_contents.php";
-
-    private static final int HTTP_TIMEOUT_MS = 5000;
-
-    private static HttpClient sHttpClient;
-
-    private static HttpClient getHttpClient() {
-        if (sHttpClient == null) {
-            HttpParams params = new BasicHttpParams();
-
-            SchemeRegistry schemeRegistry = new SchemeRegistry();
-            schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(),
-                    ForwarderManager.HTTP_PORT));
-            schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(),
-                    ForwarderManager.HTTPS_PORT));
-
-            ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(params,
-                    schemeRegistry);
-            sHttpClient = new DefaultHttpClient(connectionManager, params);
-            HttpConnectionParams.setSoTimeout(sHttpClient.getParams(), HTTP_TIMEOUT_MS);
-            HttpConnectionParams.setConnectionTimeout(sHttpClient.getParams(), HTTP_TIMEOUT_MS);
-        }
-        return sHttpClient;
-    }
-
-    public static void writeDataToStorage(File file, byte[] bytes, boolean append) {
-        Log.d(LOG_TAG, "writeDataToStorage(): " + file.getAbsolutePath());
-        try {
-            OutputStream outputStream = null;
-            try {
-                file.getParentFile().mkdirs();
-                file.createNewFile();
-                Log.d(LOG_TAG, "writeDataToStorage(): File created: " + file.getAbsolutePath());
-                outputStream = new FileOutputStream(file, append);
-                outputStream.write(bytes);
-            } finally {
-                if (outputStream != null) {
-                    outputStream.close();
-                }
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "file.getAbsolutePath=" + file.getAbsolutePath() + " append=" + append,
-                    e);
-        }
-    }
-
-    public static byte[] readDataFromStorage(File file) {
-        if (!file.exists()) {
-            Log.d(LOG_TAG, "readDataFromStorage(): File does not exist: "
-                    + file.getAbsolutePath());
-            return null;
-        }
-
-        byte[] bytes = null;
-        try {
-            FileInputStream fis = null;
-            try {
-                fis = new FileInputStream(file);
-                bytes = new byte[(int)file.length()];
-                fis.read(bytes);
-            } finally {
-                if (fis != null) {
-                    fis.close();
-                }
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "file.getAbsolutePath=" + file.getAbsolutePath(), e);
-        }
-
-        return bytes;
-    }
-
-    static class UrlDataGetter extends Thread {
-        private URL mUrl;
-        private byte[] mBytes;
-        private boolean mGetComplete;
-        public UrlDataGetter(URL url) {
-            mUrl = url;
-        }
-        public byte[] get() {
-            start();
-            synchronized(this) {
-                while (!mGetComplete) {
-                    try{
-                        wait();
-                    } catch(InterruptedException e) {
-                    }
-                }
-            }
-            return mBytes;
-        }
-        public synchronized void run() {
-            mGetComplete = false;
-            HttpGet httpRequest = new HttpGet(mUrl.toString());
-            ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() {
-                @Override
-                public byte[] handleResponse(HttpResponse response) throws IOException {
-                    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
-                        return null;
-                    }
-                    HttpEntity entity = response.getEntity();
-                    return (entity == null ? null : EntityUtils.toByteArray(entity));
-                }
-            };
-
-            mBytes = null;
-            try {
-                /**
-                 * TODO: Not exactly sure why some requests hang indefinitely, but adding this
-                 * timeout (in static getter for http client) in loop helps.
-                 */
-                boolean timedOut;
-                do {
-                    timedOut = false;
-                    try {
-                        mBytes = getHttpClient().execute(httpRequest, handler);
-                    } catch (SocketTimeoutException e) {
-                        timedOut = true;
-                        Log.w(LOG_TAG, "Expected SocketTimeoutException: " + mUrl, e);
-                    }
-                } while (timedOut);
-            } catch (IOException e) {
-                Log.e(LOG_TAG, "url=" + mUrl, e);
-            }
-
-            mGetComplete = true;
-            notify();
-        }
-    }
-
-    public static byte[] readDataFromUrl(URL url) {
-        if (url == null) {
-            Log.w(LOG_TAG, "readDataFromUrl(): url is null!");
-            return null;
-        }
-
-        UrlDataGetter getter = new UrlDataGetter(url);
-        return getter.get();
-    }
-
-    public static List<String> getLayoutTestsDirContents(String dirRelativePath, boolean recurse,
-            boolean mode) {
-        String modeString = (mode ? "folders" : "files");
-
-        URL url = null;
-        try {
-            url = new URL(SCRIPT_URL +
-                    "?path=" + dirRelativePath +
-                    "&recurse=" + recurse +
-                    "&mode=" + modeString);
-        } catch (MalformedURLException e) {
-            Log.e(LOG_TAG, "path=" + dirRelativePath + " recurse=" + recurse + " mode=" +
-                    modeString, e);
-            return new LinkedList<String>();
-        }
-
-        HttpGet httpRequest = new HttpGet(url.toString());
-        ResponseHandler<LinkedList<String>> handler = new ResponseHandler<LinkedList<String>>() {
-            @Override
-            public LinkedList<String> handleResponse(HttpResponse response)
-                    throws IOException {
-                LinkedList<String> lines = new LinkedList<String>();
-
-                if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
-                    return lines;
-                }
-                HttpEntity entity = response.getEntity();
-                if (entity == null) {
-                    return lines;
-                }
-
-                BufferedReader reader =
-                        new BufferedReader(new InputStreamReader(entity.getContent()));
-                String line;
-                try {
-                    while ((line = reader.readLine()) != null) {
-                        lines.add(line);
-                    }
-                } finally {
-                    if (reader != null) {
-                        reader.close();
-                    }
-                }
-
-                return lines;
-            }
-        };
-
-        try {
-            return getHttpClient().execute(httpRequest, handler);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "getLayoutTestsDirContents(): HTTP GET failed for URL " + url);
-            return null;
-        }
-    }
-
-    public static void closeInputStream(InputStream inputStream) {
-        try {
-            if (inputStream != null) {
-                inputStream.close();
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Couldn't close stream!", e);
-        }
-    }
-
-    public static void closeOutputStream(OutputStream outputStream) {
-        try {
-            if (outputStream != null) {
-                outputStream.close();
-            }
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Couldn't close stream!", e);
-        }
-    }
-
-    public static List<String> loadTestListFromStorage(String path) {
-        List<String> list = new ArrayList<String>();
-        if (path != null && !path.isEmpty()) {
-            try {
-                File file = new File(path);
-                Log.d(LOG_TAG, "test list loaded from " + path);
-                BufferedReader reader = new BufferedReader(new FileReader(file));
-                String line = null;
-                while ((line = reader.readLine()) != null) {
-                    list.add(line);
-                }
-                reader.close();
-            } catch (IOException ioe) {
-                Log.e(LOG_TAG, "failed to load test list", ioe);
-            }
-        }
-        return list;
-    }
-
-    public static void saveTestListToStorage(File file, int start, List<String> testList) {
-        try {
-            BufferedWriter writer = new BufferedWriter(
-                    new FileWriter(file));
-            for (String line : testList.subList(start, testList.size())) {
-                writer.write(line + '\n');
-            }
-            writer.flush();
-            writer.close();
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "failed to write test list", e);
-        }
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java
deleted file mode 100644
index c9c35ce..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.net.Uri;
-import android.util.Log;
-import android.webkit.MockGeolocation;
-import android.webkit.WebStorage;
-
-import java.io.File;
-
-/**
- * A class that is registered as JS interface for webview in LayoutTestExecutor
- */
-public class LayoutTestController {
-    private static final String LOG_TAG = "LayoutTestController";
-
-    LayoutTestsExecutor mLayoutTestsExecutor;
-
-    public LayoutTestController(LayoutTestsExecutor layoutTestsExecutor) {
-        mLayoutTestsExecutor = layoutTestsExecutor;
-    }
-
-    public void clearAllDatabases() {
-        Log.i(LOG_TAG, "clearAllDatabases() called");
-        WebStorage.getInstance().deleteAllData();
-    }
-
-    public void dumpAsText() {
-        dumpAsText(false);
-    }
-
-    public void dumpAsText(boolean enablePixelTest) {
-        mLayoutTestsExecutor.dumpAsText(enablePixelTest);
-    }
-
-    public void dumpChildFramesAsText() {
-        mLayoutTestsExecutor.dumpChildFramesAsText();
-    }
-
-    public void dumpDatabaseCallbacks() {
-        mLayoutTestsExecutor.dumpDatabaseCallbacks();
-    }
-
-    public void notifyDone() {
-        mLayoutTestsExecutor.notifyDone();
-    }
-
-    public void overridePreference(String key, boolean value) {
-        mLayoutTestsExecutor.overridePreference(key, value);
-    }
-
-    public void setAppCacheMaximumSize(long size) {
-        Log.i(LOG_TAG, "setAppCacheMaximumSize() called with: " + size);
-        android.webkit.WebStorageClassic.getInstance().setAppCacheMaximumSize(size);
-    }
-
-    public void setCanOpenWindows() {
-        mLayoutTestsExecutor.setCanOpenWindows();
-    }
-
-    public void setDatabaseQuota(long quota) {
-        /** TODO: Reset this before every test! */
-        Log.i(LOG_TAG, "setDatabaseQuota() called with: " + quota);
-        WebStorage.getInstance().setQuotaForOrigin(Uri.fromFile(new File("")).toString(),
-                quota);
-    }
-
-    public void setMockGeolocationPosition(double latitude, double longitude, double accuracy) {
-        Log.i(LOG_TAG, "setMockGeolocationPosition(): " + "latitude=" + latitude +
-                " longitude=" + longitude + " accuracy=" + accuracy);
-        mLayoutTestsExecutor.setMockGeolocationPosition(latitude, longitude, accuracy);
-    }
-
-    public void setMockGeolocationError(int code, String message) {
-        Log.i(LOG_TAG, "setMockGeolocationError(): " + "code=" + code + " message=" + message);
-        mLayoutTestsExecutor.setMockGeolocationError(code, message);
-    }
-
-    public void setGeolocationPermission(boolean allow) {
-        mLayoutTestsExecutor.setGeolocationPermission(allow);
-    }
-
-    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
-            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
-        // Configuration is in WebKit, so stay on WebCore thread, but go via LayoutTestsExecutor
-        // as we need access to the Webview.
-        Log.i(LOG_TAG, "setMockDeviceOrientation(" + canProvideAlpha +
-                ", " + alpha + ", " + canProvideBeta + ", " + beta + ", " + canProvideGamma +
-                ", " + gamma + ")");
-        mLayoutTestsExecutor.setMockDeviceOrientation(
-                canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
-    }
-
-    public void setXSSAuditorEnabled(boolean flag) {
-        mLayoutTestsExecutor.setXSSAuditorEnabled(flag);
-    }
-
-    public void waitUntilDone() {
-        mLayoutTestsExecutor.waitUntilDone();
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
deleted file mode 100644
index 25ac700..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.http.SslError;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.Window;
-import android.webkit.ConsoleMessage;
-import android.webkit.GeolocationPermissions;
-import android.webkit.HttpAuthHandler;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebSettingsClassic;
-import android.webkit.WebStorage;
-import android.webkit.WebStorage.QuotaUpdater;
-import android.webkit.WebView;
-import android.webkit.WebViewClassic;
-import android.webkit.WebViewClient;
-
-import java.lang.Thread.UncaughtExceptionHandler;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This activity executes the test. It contains WebView and logic of LayoutTestController
- * functions. It runs in a separate process and sends the results of running the test
- * to ManagerService. The reason why is to handle crashing (test that crashes brings down
- * whole process with it).
- */
-public class LayoutTestsExecutor extends Activity {
-
-    private enum CurrentState {
-        IDLE,
-        RENDERING_PAGE,
-        WAITING_FOR_ASYNCHRONOUS_TEST,
-        OBTAINING_RESULT;
-
-        public boolean isRunningState() {
-            return this == CurrentState.RENDERING_PAGE ||
-                    this == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST;
-        }
-    }
-
-    private static final String LOG_TAG = "LayoutTestsExecutor";
-
-    public static final String EXTRA_TESTS_FILE = "TestsList";
-    public static final String EXTRA_TEST_INDEX = "TestIndex";
-
-    private static final int MSG_ACTUAL_RESULT_OBTAINED = 0;
-    private static final int MSG_TEST_TIMED_OUT = 1;
-
-    private static final int DEFAULT_TIME_OUT_MS = 15 * 1000;
-
-    /** A list of tests that remain to run since last crash */
-    private List<String> mTestsList;
-
-    /**
-     * This is a number of currently running test. It is 0-based and doesn't reset after
-     * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts
-     * it.
-     */
-    private int mCurrentTestIndex;
-
-    /** The total number of tests to run, doesn't reset after crash */
-    private int mTotalTestCount;
-
-    private WebView mCurrentWebView;
-    private String mCurrentTestRelativePath;
-    private String mCurrentTestUri;
-    private CurrentState mCurrentState = CurrentState.IDLE;
-
-    private boolean mCurrentTestTimedOut;
-    private AbstractResult mCurrentResult;
-    private AdditionalTextOutput mCurrentAdditionalTextOutput;
-
-    private LayoutTestController mLayoutTestController = new LayoutTestController(this);
-    private boolean mCanOpenWindows;
-    private boolean mDumpDatabaseCallbacks;
-
-    private EventSender mEventSender = new EventSender();
-
-    private WakeLock mScreenDimLock;
-
-    /** COMMUNICATION WITH ManagerService */
-
-    private Messenger mManagerServiceMessenger;
-
-    private ServiceConnection mServiceConnection = new ServiceConnection() {
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mManagerServiceMessenger = new Messenger(service);
-            startTests();
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            /** TODO */
-        }
-    };
-
-    private final Handler mResultHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_ACTUAL_RESULT_OBTAINED:
-                    onActualResultsObtained();
-                    break;
-
-                case MSG_TEST_TIMED_OUT:
-                    onTestTimedOut();
-                    break;
-
-                default:
-                    break;
-            }
-        }
-    };
-
-    /** WEBVIEW CONFIGURATION */
-
-    private WebViewClient mWebViewClient = new WebViewClient() {
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            /** Some tests fire up many page loads, we don't want to detect them */
-            if (!url.equals(mCurrentTestUri)) {
-                return;
-            }
-
-            if (mCurrentState == CurrentState.RENDERING_PAGE) {
-                onTestFinished();
-            }
-        }
-
-         @Override
-         public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
-                 String host, String realm) {
-             if (handler.useHttpAuthUsernamePassword() && view != null) {
-                 String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
-                 if (credentials != null && credentials.length == 2) {
-                     handler.proceed(credentials[0], credentials[1]);
-                     return;
-                 }
-             }
-             handler.cancel();
-         }
-
-         @Override
-         public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-             // We ignore SSL errors. In particular, the certificate used by the LayoutTests server
-             // produces an error as it lacks a CN field.
-             handler.proceed();
-         }
-    };
-
-    private WebChromeClient mWebChromeClient = new WebChromeClient() {
-        @Override
-        public void onExceededDatabaseQuota(String url, String databaseIdentifier,
-                long currentQuota, long estimatedSize, long totalUsedQuota,
-                QuotaUpdater quotaUpdater) {
-            /** TODO: This should be recorded as part of the text result */
-            /** TODO: The quota should also probably be reset somehow for every test? */
-            if (mDumpDatabaseCallbacks) {
-                getCurrentAdditionalTextOutput().appendExceededDbQuotaMessage(url,
-                        databaseIdentifier);
-            }
-            quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024);
-        }
-
-        @Override
-        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
-            getCurrentAdditionalTextOutput().appendJsAlert(message);
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
-            getCurrentAdditionalTextOutput().appendJsConfirm(message);
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
-                JsPromptResult result) {
-            getCurrentAdditionalTextOutput().appendJsPrompt(message, defaultValue);
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
-            getCurrentAdditionalTextOutput().appendConsoleMessage(consoleMessage);
-            return true;
-        }
-
-        @Override
-        public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
-                Message resultMsg) {
-            WebView.WebViewTransport transport = (WebView.WebViewTransport)resultMsg.obj;
-            /** By default windows cannot be opened, so just send null back. */
-            WebView newWindowWebView = null;
-
-            if (mCanOpenWindows) {
-                /**
-                 * We never display the new window, just create the view and allow it's content to
-                 * execute and be recorded by the executor.
-                 */
-                newWindowWebView = createWebViewWithJavascriptInterfaces();
-                setupWebView(newWindowWebView);
-            }
-
-            transport.setWebView(newWindowWebView);
-            resultMsg.sendToTarget();
-            return true;
-        }
-
-        @Override
-        public void onGeolocationPermissionsShowPrompt(String origin,
-                GeolocationPermissions.Callback callback) {
-            throw new RuntimeException(
-                    "The WebCore mock used by DRT should bypass the usual permissions flow.");
-        }
-    };
-
-    /** IMPLEMENTATION */
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        /**
-         * It detects the crash by catching all the uncaught exceptions. However, we
-         * still have to kill the process, because after catching the exception the
-         * activity remains in a strange state, where intents don't revive it.
-         * However, we send the message to the service to speed up the rebooting
-         * (we don't have to wait for time-out to kick in).
-         */
-        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
-            @Override
-            public void uncaughtException(Thread thread, Throwable e) {
-                Log.w(LOG_TAG,
-                        "onTestCrashed(): " + mCurrentTestRelativePath + " thread=" + thread, e);
-
-                try {
-                    Message serviceMsg =
-                            Message.obtain(null, ManagerService.MSG_CURRENT_TEST_CRASHED);
-
-                    mManagerServiceMessenger.send(serviceMsg);
-                } catch (RemoteException e2) {
-                    Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e2);
-                }
-
-                Process.killProcess(Process.myPid());
-            }
-        });
-
-        requestWindowFeature(Window.FEATURE_PROGRESS);
-
-        Intent intent = getIntent();
-        mTestsList = FsUtils.loadTestListFromStorage(intent.getStringExtra(EXTRA_TESTS_FILE));
-        mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1);
-        mTotalTestCount = mCurrentTestIndex + mTestsList.size();
-
-        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
-        mScreenDimLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK
-                | PowerManager.ON_AFTER_RELEASE, "WakeLock in LayoutTester");
-        mScreenDimLock.acquire();
-
-        bindService(new Intent(this, ManagerService.class), mServiceConnection,
-                Context.BIND_AUTO_CREATE);
-    }
-
-    private void reset() {
-        WebView previousWebView = mCurrentWebView;
-
-        resetLayoutTestController();
-
-        mCurrentTestTimedOut = false;
-        mCurrentResult = null;
-        mCurrentAdditionalTextOutput = null;
-
-        mCurrentWebView = createWebViewWithJavascriptInterfaces();
-        // When we create the first WebView, we need to pause to wait for the WebView thread to spin
-        // and up and for it to register its message handlers.
-        if (previousWebView == null) {
-            try {
-                Thread.currentThread().sleep(1000);
-            } catch (Exception e) {}
-        }
-        setupWebView(mCurrentWebView);
-
-        mEventSender.reset(mCurrentWebView);
-
-        setContentView(mCurrentWebView);
-        if (previousWebView != null) {
-            Log.d(LOG_TAG + "::reset", "previousWebView != null");
-            previousWebView.destroy();
-        }
-    }
-
-    private static class WebViewWithJavascriptInterfaces extends WebView {
-        public WebViewWithJavascriptInterfaces(
-                Context context, Map<String, Object> javascriptInterfaces) {
-            super(context,
-                  null, // attribute set
-                  0, // default style resource ID
-                  javascriptInterfaces,
-                  false); // is private browsing
-        }
-    }
-    private WebView createWebViewWithJavascriptInterfaces() {
-        Map<String, Object> javascriptInterfaces = new HashMap<String, Object>();
-        javascriptInterfaces.put("layoutTestController", mLayoutTestController);
-        javascriptInterfaces.put("eventSender", mEventSender);
-        return new WebViewWithJavascriptInterfaces(this, javascriptInterfaces);
-    }
-
-    private void setupWebView(WebView webView) {
-        webView.setWebViewClient(mWebViewClient);
-        webView.setWebChromeClient(mWebChromeClient);
-
-        /**
-         * Setting a touch interval of -1 effectively disables the optimisation in WebView
-         * that stops repeated touch events flooding WebCore. The Event Sender only sends a
-         * single event rather than a stream of events (like what would generally happen in
-         * a real use of touch events in a WebView)  and so if the WebView drops the event,
-         * the test will fail as the test expects one callback for every touch it synthesizes.
-         */
-        WebViewClassic webViewClassic = WebViewClassic.fromWebView(webView);
-        webViewClassic.setTouchInterval(-1);
-
-        webViewClassic.clearCache(true);
-
-        WebSettingsClassic webViewSettings = webViewClassic.getSettings();
-        webViewSettings.setAppCacheEnabled(true);
-        webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
-        // Use of larger values causes unexplained AppCache database corruption.
-        // TODO: Investigate what's really going on here.
-        webViewSettings.setAppCacheMaxSize(100 * 1024 * 1024);
-        webViewSettings.setJavaScriptEnabled(true);
-        webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true);
-        webViewSettings.setSupportMultipleWindows(true);
-        webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-        webViewSettings.setDatabaseEnabled(true);
-        webViewSettings.setDatabasePath(getDir("databases", 0).getAbsolutePath());
-        webViewSettings.setDomStorageEnabled(true);
-        webViewSettings.setWorkersEnabled(false);
-        webViewSettings.setXSSAuditorEnabled(false);
-        webViewSettings.setPageCacheCapacity(0);
-
-        // This is asynchronous, but it gets processed by WebCore before it starts loading pages.
-        WebViewClassic.fromWebView(mCurrentWebView).setUseMockGeolocation();
-        WebViewClassic.fromWebView(mCurrentWebView).setUseMockDeviceOrientation();
-
-        // Must do this after setting the AppCache path.
-        WebStorage.getInstance().deleteAllData();
-    }
-
-    private void startTests() {
-        // This is called when the tests are started and after each crash.
-        // We only send the reset message in the former case.
-        if (mCurrentTestIndex <= 0) {
-            sendResetMessage();
-        }
-        if (mCurrentTestIndex == 0) {
-            sendFirstTestMessage();
-        }
-
-        runNextTest();
-    }
-
-    private void sendResetMessage() {
-        try {
-            Message serviceMsg = Message.obtain(null, ManagerService.MSG_RESET);
-            mManagerServiceMessenger.send(serviceMsg);
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, "Error sending message to manager service:", e);
-        }
-    }
-
-    private void sendFirstTestMessage() {
-        try {
-            Message serviceMsg = Message.obtain(null, ManagerService.MSG_FIRST_TEST);
-
-            Bundle bundle = new Bundle();
-            bundle.putString("firstTest", mTestsList.get(0));
-            bundle.putInt("index", mCurrentTestIndex);
-
-            serviceMsg.setData(bundle);
-            mManagerServiceMessenger.send(serviceMsg);
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, "Error sending message to manager service:", e);
-        }
-    }
-
-    private void runNextTest() {
-        assert mCurrentState == CurrentState.IDLE : "mCurrentState = " + mCurrentState.name();
-
-        if (mTestsList.isEmpty()) {
-            onAllTestsFinished();
-            return;
-        }
-
-        mCurrentTestRelativePath = mTestsList.remove(0);
-
-        Log.i(LOG_TAG, "runNextTest(): Start: " + mCurrentTestRelativePath +
-                " (" + mCurrentTestIndex + ")");
-
-        mCurrentTestUri = FileFilter.getUrl(mCurrentTestRelativePath, true).toString();
-
-        reset();
-
-        /** Start time-out countdown and the test */
-        mCurrentState = CurrentState.RENDERING_PAGE;
-        mResultHandler.sendEmptyMessageDelayed(MSG_TEST_TIMED_OUT, DEFAULT_TIME_OUT_MS);
-        mCurrentWebView.loadUrl(mCurrentTestUri);
-    }
-
-    private void onTestTimedOut() {
-        assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
-
-        Log.w(LOG_TAG, "onTestTimedOut(): " + mCurrentTestRelativePath);
-        mCurrentTestTimedOut = true;
-
-        /**
-         * While it is theoretically possible that the test times out because
-         * of webview becoming unresponsive, it is very unlikely. Therefore it's
-         * assumed that obtaining results (that calls various webview methods)
-         * will not itself hang.
-         */
-        obtainActualResultsFromWebView();
-    }
-
-    private void onTestFinished() {
-        assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
-
-        Log.i(LOG_TAG, "onTestFinished(): " + mCurrentTestRelativePath);
-        mResultHandler.removeMessages(MSG_TEST_TIMED_OUT);
-        obtainActualResultsFromWebView();
-    }
-
-    private void obtainActualResultsFromWebView() {
-        /**
-         * If the result has not been set by the time the test finishes we create
-         * a default type of result.
-         */
-        if (mCurrentResult == null) {
-            /** TODO: Default type should be RenderTreeResult. We don't support it now. */
-            mCurrentResult = new TextResult(mCurrentTestRelativePath);
-        }
-
-        mCurrentState = CurrentState.OBTAINING_RESULT;
-
-        if (mCurrentTestTimedOut) {
-            mCurrentResult.setDidTimeOut();
-        }
-        mCurrentResult.obtainActualResults(mCurrentWebView,
-                mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED));
-    }
-
-    private void onActualResultsObtained() {
-        assert mCurrentState == CurrentState.OBTAINING_RESULT
-                : "mCurrentState = " + mCurrentState.name();
-
-        Log.i(LOG_TAG, "onActualResultsObtained(): " + mCurrentTestRelativePath);
-        mCurrentState = CurrentState.IDLE;
-
-        reportResultToService();
-        mCurrentTestIndex++;
-        updateProgressBar();
-        runNextTest();
-    }
-
-    private void reportResultToService() {
-        if (mCurrentAdditionalTextOutput != null) {
-            mCurrentResult.setAdditionalTextOutputString(mCurrentAdditionalTextOutput.toString());
-        }
-
-        try {
-            Message serviceMsg =
-                    Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS);
-
-            Bundle bundle = mCurrentResult.getBundle();
-            bundle.putInt("testIndex", mCurrentTestIndex);
-            if (!mTestsList.isEmpty()) {
-                bundle.putString("nextTest", mTestsList.get(0));
-            }
-
-            serviceMsg.setData(bundle);
-            mManagerServiceMessenger.send(serviceMsg);
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e);
-        }
-    }
-
-    private void updateProgressBar() {
-        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount);
-        setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " +
-                "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")");
-    }
-
-    private void onAllTestsFinished() {
-        mScreenDimLock.release();
-
-        try {
-            Message serviceMsg =
-                    Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED);
-            mManagerServiceMessenger.send(serviceMsg);
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e);
-        }
-
-        unbindService(mServiceConnection);
-    }
-
-    private AdditionalTextOutput getCurrentAdditionalTextOutput() {
-        if (mCurrentAdditionalTextOutput == null) {
-            mCurrentAdditionalTextOutput = new AdditionalTextOutput();
-        }
-        return mCurrentAdditionalTextOutput;
-    }
-
-    /** LAYOUT TEST CONTROLLER */
-
-    private static final int MSG_WAIT_UNTIL_DONE = 0;
-    private static final int MSG_NOTIFY_DONE = 1;
-    private static final int MSG_DUMP_AS_TEXT = 2;
-    private static final int MSG_DUMP_CHILD_FRAMES_AS_TEXT = 3;
-    private static final int MSG_SET_CAN_OPEN_WINDOWS = 4;
-    private static final int MSG_DUMP_DATABASE_CALLBACKS = 5;
-    private static final int MSG_OVERRIDE_PREFERENCE = 6;
-    private static final int MSG_SET_XSS_AUDITOR_ENABLED = 7;
-
-    /** String constants for use with layoutTestController.overridePreference() */
-    private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED =
-            "WebKitOfflineWebApplicationCacheEnabled";
-    private final String WEBKIT_USES_PAGE_CACHE_PREFERENCE_KEY = "WebKitUsesPageCachePreferenceKey";
-
-    Handler mLayoutTestControllerHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
-
-            switch (msg.what) {
-                case MSG_DUMP_AS_TEXT:
-                    if (mCurrentResult == null) {
-                        mCurrentResult = new TextResult(mCurrentTestRelativePath);
-                    }
-                    assert mCurrentResult instanceof TextResult
-                            : "mCurrentResult instanceof" + mCurrentResult.getClass().getName();
-                    break;
-
-                case MSG_DUMP_CHILD_FRAMES_AS_TEXT:
-                    /** If dumpAsText was not called we assume that the result should be text */
-                    if (mCurrentResult == null) {
-                        mCurrentResult = new TextResult(mCurrentTestRelativePath);
-                    }
-
-                    assert mCurrentResult instanceof TextResult
-                            : "mCurrentResult instanceof" + mCurrentResult.getClass().getName();
-
-                    ((TextResult)mCurrentResult).setDumpChildFramesAsText(true);
-                    break;
-
-                case MSG_DUMP_DATABASE_CALLBACKS:
-                    mDumpDatabaseCallbacks = true;
-                    break;
-
-                case MSG_NOTIFY_DONE:
-                    if (mCurrentState == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST) {
-                        onTestFinished();
-                    }
-                    break;
-
-                case MSG_OVERRIDE_PREFERENCE:
-                    /**
-                     * TODO: We should look up the correct WebView for the frame which
-                     * called the layoutTestController method. Currently, we just use the
-                     * WebView for the main frame. EventSender suffers from the same
-                     * problem.
-                     */
-                    String key = msg.getData().getString("key");
-                    boolean value = msg.getData().getBoolean("value");
-                    if (WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED.equals(key)) {
-                        WebViewClassic.fromWebView(mCurrentWebView).getSettings().
-                                setAppCacheEnabled(value);
-                    } else if (WEBKIT_USES_PAGE_CACHE_PREFERENCE_KEY.equals(key)) {
-                        // Cache the maximum possible number of pages.
-                        WebViewClassic.fromWebView(mCurrentWebView).getSettings().
-                                setPageCacheCapacity(Integer.MAX_VALUE);
-                    } else {
-                        Log.w(LOG_TAG, "LayoutTestController.overridePreference(): " +
-                              "Unsupported preference '" + key + "'");
-                    }
-                    break;
-
-                case MSG_SET_CAN_OPEN_WINDOWS:
-                    mCanOpenWindows = true;
-                    break;
-
-                case MSG_SET_XSS_AUDITOR_ENABLED:
-                    WebViewClassic.fromWebView(mCurrentWebView).getSettings().
-                            setXSSAuditorEnabled(msg.arg1 == 1);
-                    break;
-
-                case MSG_WAIT_UNTIL_DONE:
-                    mCurrentState = CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST;
-                    break;
-
-                default:
-                    assert false : "msg.what=" + msg.what;
-                    break;
-            }
-        }
-    };
-
-    private void resetLayoutTestController() {
-        mCanOpenWindows = false;
-        mDumpDatabaseCallbacks = false;
-    }
-
-    public void dumpAsText(boolean enablePixelTest) {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpAsText(" + enablePixelTest + ") called");
-        /** TODO: Implement */
-        if (enablePixelTest) {
-            Log.w(LOG_TAG, "enablePixelTest not implemented, switching to false");
-        }
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_AS_TEXT);
-    }
-
-    public void dumpChildFramesAsText() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpChildFramesAsText() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_CHILD_FRAMES_AS_TEXT);
-    }
-
-    public void dumpDatabaseCallbacks() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpDatabaseCallbacks() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_DATABASE_CALLBACKS);
-    }
-
-    public void notifyDone() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": notifyDone() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_NOTIFY_DONE);
-    }
-
-    public void overridePreference(String key, boolean value) {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": overridePreference(" + key + ", " + value +
-        ") called");
-        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_OVERRIDE_PREFERENCE);
-        msg.getData().putString("key", key);
-        msg.getData().putBoolean("value", value);
-        msg.sendToTarget();
-    }
-
-    public void setCanOpenWindows() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setCanOpenWindows() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_SET_CAN_OPEN_WINDOWS);
-    }
-
-    public void setMockGeolocationPosition(double latitude, double longitude, double accuracy) {
-        WebViewClassic.fromWebView(mCurrentWebView).setMockGeolocationPosition(latitude, longitude,
-                accuracy);
-    }
-
-    public void setMockGeolocationError(int code, String message) {
-        WebViewClassic.fromWebView(mCurrentWebView).setMockGeolocationError(code, message);
-    }
-
-    public void setGeolocationPermission(boolean allow) {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setGeolocationPermission(" + allow +
-                ") called");
-        WebViewClassic.fromWebView(mCurrentWebView).setMockGeolocationPermission(allow);
-    }
-
-    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
-            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setMockDeviceOrientation(" + canProvideAlpha +
-                ", " + alpha + ", " + canProvideBeta + ", " + beta + ", " + canProvideGamma +
-                ", " + gamma + ")");
-        WebViewClassic.fromWebView(mCurrentWebView).setMockDeviceOrientation(canProvideAlpha,
-                alpha, canProvideBeta, beta, canProvideGamma, gamma);
-    }
-
-    public void setXSSAuditorEnabled(boolean flag) {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setXSSAuditorEnabled(" + flag + ") called");
-        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_XSS_AUDITOR_ENABLED);
-        msg.arg1 = flag ? 1 : 0;
-        msg.sendToTarget();
-    }
-
-    public void waitUntilDone() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE);
-    }
-
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
deleted file mode 100644
index 4783cc7..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.util.Log;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A service that handles managing the results of tests, informing of crashes, generating
- * summaries, etc.
- */
-public class ManagerService extends Service {
-
-    private static final String LOG_TAG = "ManagerService";
-
-    private static final int MSG_CRASH_TIMEOUT_EXPIRED = 0;
-    private static final int MSG_SUMMARIZER_DONE = 1;
-
-    private static final int CRASH_TIMEOUT_MS = 20 * 1000;
-
-    /** TODO: make it a setting */
-    static final String RESULTS_ROOT_DIR_PATH =
-            Environment.getExternalStorageDirectory() + File.separator + "layout-test-results";
-
-    /** TODO: Make it a setting */
-    private static final List<String> EXPECTED_RESULT_LOCATION_RELATIVE_DIR_PREFIXES =
-            new ArrayList<String>(3);
-    {
-        EXPECTED_RESULT_LOCATION_RELATIVE_DIR_PREFIXES.add("platform" + File.separator +
-                "android-v8" + File.separator);
-        EXPECTED_RESULT_LOCATION_RELATIVE_DIR_PREFIXES.add("platform" + File.separator +
-                "android" + File.separator);
-        EXPECTED_RESULT_LOCATION_RELATIVE_DIR_PREFIXES.add("");
-    }
-
-    /** TODO: Make these settings */
-    private static final String TEXT_RESULT_EXTENSION = "txt";
-    private static final String IMAGE_RESULT_EXTENSION = "png";
-
-    static final int MSG_PROCESS_ACTUAL_RESULTS = 0;
-    static final int MSG_ALL_TESTS_FINISHED = 1;
-    static final int MSG_FIRST_TEST = 2;
-    static final int MSG_CURRENT_TEST_CRASHED = 3;
-    static final int MSG_RESET = 4;
-
-    /**
-     * This handler is purely for IPC. It is used to create mMessenger
-     * that generates a binder returned in onBind method.
-     */
-    private Handler mIncomingHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_RESET:
-                    mSummarizer.reset();
-                    break;
-
-                case MSG_FIRST_TEST:
-                    Bundle bundle = msg.getData();
-                    ensureNextTestSetup(bundle.getString("firstTest"), bundle.getInt("index"));
-                    break;
-
-                case MSG_PROCESS_ACTUAL_RESULTS:
-                    Log.d(LOG_TAG,"mIncomingHandler: " + msg.getData().getString("relativePath"));
-                    onActualResultsObtained(msg.getData());
-                    break;
-
-                case MSG_CURRENT_TEST_CRASHED:
-                    mInternalMessagesHandler.removeMessages(MSG_CRASH_TIMEOUT_EXPIRED);
-                    onTestCrashed();
-                    break;
-
-                case MSG_ALL_TESTS_FINISHED:
-                    /** We run it in a separate thread to avoid ANR */
-                    new Thread() {
-                        @Override
-                        public void run() {
-                            mSummarizer.setTestsRelativePath(mAllTestsRelativePath);
-                            Message msg = Message.obtain(mInternalMessagesHandler,
-                                    MSG_SUMMARIZER_DONE);
-                            mSummarizer.summarize(msg);
-                        }
-                    }.start();
-            }
-        }
-    };
-
-    private Messenger mMessenger = new Messenger(mIncomingHandler);
-
-    private Handler mInternalMessagesHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_CRASH_TIMEOUT_EXPIRED:
-                    onTestCrashed();
-                    break;
-
-                case MSG_SUMMARIZER_DONE:
-                    Intent intent = new Intent(ManagerService.this, TestsListActivity.class);
-                    intent.setAction(Intent.ACTION_SHUTDOWN);
-                    /** This flag is needed because we send the intent from the service */
-                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    startActivity(intent);
-                    break;
-            }
-        }
-    };
-
-    private Summarizer mSummarizer;
-
-    private String mCurrentlyRunningTest;
-    private int mCurrentlyRunningTestIndex;
-
-    /**
-     * These are implementation details of getExpectedResultPath() used to reduce the number
-     * of requests required to the host server.
-     */
-    private String mLastExpectedResultPathRequested;
-    private String mLastExpectedResultPathFetched;
-
-    private String mAllTestsRelativePath;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        mSummarizer = new Summarizer(RESULTS_ROOT_DIR_PATH, getApplicationContext());
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        mAllTestsRelativePath = intent.getStringExtra("path");
-        assert mAllTestsRelativePath != null;
-        return START_STICKY;
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mMessenger.getBinder();
-    }
-
-    private void onActualResultsObtained(Bundle bundle) {
-        mInternalMessagesHandler.removeMessages(MSG_CRASH_TIMEOUT_EXPIRED);
-        ensureNextTestSetup(bundle.getString("nextTest"), bundle.getInt("testIndex") + 1);
-
-        AbstractResult results =
-                AbstractResult.TestType.valueOf(bundle.getString("type")).createResult(bundle);
-
-        Log.i(LOG_TAG, "onActualResultObtained: " + results.getRelativePath());
-        handleResults(results);
-    }
-
-    private void ensureNextTestSetup(String nextTest, int index) {
-        if (nextTest == null) {
-            Log.w(LOG_TAG, "ensureNextTestSetup(): nextTest=null");
-            return;
-        }
-
-        mCurrentlyRunningTest = nextTest;
-        mCurrentlyRunningTestIndex = index;
-        mInternalMessagesHandler.sendEmptyMessageDelayed(MSG_CRASH_TIMEOUT_EXPIRED, CRASH_TIMEOUT_MS);
-    }
-
-    /**
-     * This sends an intent to TestsListActivity to restart LayoutTestsExecutor.
-     * The more detailed description of the flow is in the comment of onNewIntent
-     * method in TestsListActivity.
-     */
-    private void onTestCrashed() {
-        handleResults(new CrashedDummyResult(mCurrentlyRunningTest));
-
-        Log.w(LOG_TAG, "onTestCrashed(): " + mCurrentlyRunningTest +
-                " (" + mCurrentlyRunningTestIndex + ")");
-
-        Intent intent = new Intent(this, TestsListActivity.class);
-        intent.setAction(Intent.ACTION_REBOOT);
-        /** This flag is needed because we send the intent from the service */
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.putExtra("crashedTestIndex", mCurrentlyRunningTestIndex);
-        startActivity(intent);
-    }
-
-    private void handleResults(AbstractResult results) {
-        String relativePath = results.getRelativePath();
-        results.setExpectedTextResult(getExpectedTextResult(relativePath));
-        results.setExpectedTextResultPath(getExpectedTextResultPath(relativePath));
-        results.setExpectedImageResult(getExpectedImageResult(relativePath));
-        results.setExpectedImageResultPath(getExpectedImageResultPath(relativePath));
-
-        dumpActualTextResult(results);
-        dumpActualImageResult(results);
-
-        mSummarizer.appendTest(results);
-    }
-
-    private void dumpActualTextResult(AbstractResult result) {
-        String testPath = result.getRelativePath();
-        String actualTextResult = result.getActualTextResult();
-        if (actualTextResult == null) {
-            return;
-        }
-
-        String resultPath = FileFilter.setPathEnding(testPath, "-actual." + TEXT_RESULT_EXTENSION);
-        FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath),
-                actualTextResult.getBytes(), false);
-    }
-
-    private void dumpActualImageResult(AbstractResult result) {
-        String testPath = result.getRelativePath();
-        byte[] actualImageResult = result.getActualImageResult();
-        if (actualImageResult == null) {
-            return;
-        }
-
-        String resultPath = FileFilter.setPathEnding(testPath,
-                "-actual." + IMAGE_RESULT_EXTENSION);
-        FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath),
-                actualImageResult, false);
-    }
-
-    public String getExpectedTextResult(String relativePath) {
-        byte[] result = getExpectedResult(relativePath, TEXT_RESULT_EXTENSION);
-        if (result != null) {
-            return new String(result);
-        }
-        return null;
-    }
-
-    public byte[] getExpectedImageResult(String relativePath) {
-        return getExpectedResult(relativePath, IMAGE_RESULT_EXTENSION);
-    }
-
-    private byte[] getExpectedResult(String relativePath, String extension) {
-        String originalRelativePath =
-                FileFilter.setPathEnding(relativePath, "-expected." + extension);
-        mLastExpectedResultPathRequested = originalRelativePath;
-
-        byte[] bytes = null;
-        List<String> locations = EXPECTED_RESULT_LOCATION_RELATIVE_DIR_PREFIXES;
-
-        int size = EXPECTED_RESULT_LOCATION_RELATIVE_DIR_PREFIXES.size();
-        for (int i = 0; bytes == null && i < size; i++) {
-            relativePath = locations.get(i) + originalRelativePath;
-            bytes = FsUtils.readDataFromUrl(FileFilter.getUrl(relativePath, false));
-        }
-
-        mLastExpectedResultPathFetched = bytes == null ? null : relativePath;
-        return bytes;
-    }
-
-    private String getExpectedTextResultPath(String relativePath) {
-        return getExpectedResultPath(relativePath, TEXT_RESULT_EXTENSION);
-    }
-
-    private String getExpectedImageResultPath(String relativePath) {
-        return getExpectedResultPath(relativePath, IMAGE_RESULT_EXTENSION);
-    }
-
-    private String getExpectedResultPath(String relativePath, String extension) {
-        String originalRelativePath =
-            FileFilter.setPathEnding(relativePath, "-expected." + extension);
-        if (!originalRelativePath.equals(mLastExpectedResultPathRequested)) {
-            getExpectedResult(relativePath, extension);
-        }
-
-        return mLastExpectedResultPathFetched;
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
deleted file mode 100644
index bae8e6b..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.content.Context;
-import android.content.res.AssetManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.os.Build;
-import android.os.Message;
-import android.util.DisplayMetrics;
-import android.util.Log;
-
-import com.android.dumprendertree2.forwarder.ForwarderManager;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A class that collects information about tests that ran and can create HTML
- * files with summaries and easy navigation.
- */
-public class Summarizer {
-
-    private static final String LOG_TAG = "Summarizer";
-
-    private static final String CSS =
-            "<style type=\"text/css\">" +
-            "* {" +
-            "       font-family: Verdana;" +
-            "       border: 0;" +
-            "       margin: 0;" +
-            "       padding: 0;}" +
-            "body {" +
-            "       margin: 10px;}" +
-            "h1 {" +
-            "       font-size: 24px;" +
-            "       margin: 4px 0 4px 0;}" +
-            "h2 {" +
-            "       font-size:18px;" +
-            "       text-transform: uppercase;" +
-            "       margin: 20px 0 3px 0;}" +
-            "h3, h3 a {" +
-            "       font-size: 14px;" +
-            "       color: black;" +
-            "       text-decoration: none;" +
-            "       margin-top: 4px;" +
-            "       margin-bottom: 2px;}" +
-            "h3 a span.path {" +
-            "       text-decoration: underline;}" +
-            "h3 span.tri {" +
-            "       text-decoration: none;" +
-            "       float: left;" +
-            "       width: 20px;}" +
-            "h3 span.sqr {" +
-            "       text-decoration: none;" +
-            "       float: left;" +
-            "       width: 20px;}" +
-            "h3 span.sqr_pass {" +
-            "       color: #8ee100;}" +
-            "h3 span.sqr_fail {" +
-            "       color: #c30000;}" +
-            "span.source {" +
-            "       display: block;" +
-            "       font-size: 10px;" +
-            "       color: #888;" +
-            "       margin-left: 20px;" +
-            "       margin-bottom: 1px;}" +
-            "span.source a {" +
-            "       font-size: 10px;" +
-            "       color: #888;}" +
-            "h3 img {" +
-            "       width: 8px;" +
-            "       margin-right: 4px;}" +
-            "div.diff {" +
-            "       margin-bottom: 25px;}" +
-            "div.diff a {" +
-            "       font-size: 12px;" +
-            "       color: #888;}" +
-            "table.visual_diff {" +
-            "       border-bottom: 0px solid;" +
-            "       border-collapse: collapse;" +
-            "       width: 100%;" +
-            "       margin-bottom: 2px;}" +
-            "table.visual_diff tr.headers td {" +
-            "       border-bottom: 1px solid;" +
-            "       border-top: 0;" +
-            "       padding-bottom: 3px;}" +
-            "table.visual_diff tr.results td {" +
-            "       border-top: 1px dashed;" +
-            "       border-right: 1px solid;" +
-            "       font-size: 15px;" +
-            "       vertical-align: top;}" +
-            "table.visual_diff tr.results td.line_count {" +
-            "       background-color:#aaa;" +
-            "       min-width:20px;" +
-            "       text-align: right;" +
-            "       border-right: 1px solid;" +
-            "       border-left: 1px solid;" +
-            "       padding: 2px 1px 2px 0px;}" +
-            "table.visual_diff tr.results td.line {" +
-            "       padding: 2px 0px 2px 4px;" +
-            "       border-right: 1px solid;" +
-            "       width: 49.8%;}" +
-            "table.visual_diff tr.footers td {" +
-            "       border-top: 1px solid;" +
-            "       border-bottom: 0;}" +
-            "table.visual_diff tr td.space {" +
-            "       border: 0;" +
-            "       width: 0.4%}" +
-            "div.space {" +
-            "       margin-top:4px;}" +
-            "span.eql {" +
-            "       background-color: #f3f3f3;}" +
-            "span.del {" +
-            "       background-color: #ff8888; }" +
-            "span.ins {" +
-            "       background-color: #88ff88; }" +
-            "table.summary {" +
-            "       border: 1px solid black;" +
-            "       margin-top: 20px;}" +
-            "table.summary td {" +
-            "       padding: 3px;}" +
-            "span.listItem {" +
-            "       font-size: 11px;" +
-            "       font-weight: normal;" +
-            "       text-transform: uppercase;" +
-            "       padding: 3px;" +
-            "       -webkit-border-radius: 4px;}" +
-            "span." + AbstractResult.ResultCode.RESULTS_DIFFER.name() + "{" +
-            "       background-color: #ccc;" +
-            "       color: black;}" +
-            "span." + AbstractResult.ResultCode.NO_EXPECTED_RESULT.name() + "{" +
-            "       background-color: #a700e4;" +
-            "       color: #fff;}" +
-            "span.timed_out {" +
-            "       background-color: #f3cb00;" +
-            "       color: black;}" +
-            "span.crashed {" +
-            "       background-color: #c30000;" +
-            "       color: #fff;}" +
-            "span.noLtc {" +
-            "       background-color: #944000;" +
-            "       color: #fff;}" +
-            "span.noEventSender {" +
-            "       background-color: #815600;" +
-            "       color: #fff;}" +
-            "</style>";
-
-    private static final String SCRIPT =
-            "<script type=\"text/javascript\">" +
-            "    function toggleDisplay(id) {" +
-            "        element = document.getElementById(id);" +
-            "        triangle = document.getElementById('tri.' + id);" +
-            "        if (element.style.display == 'none') {" +
-            "            element.style.display = 'inline';" +
-            "            triangle.innerHTML = '&#x25bc; ';" +
-            "        } else {" +
-            "            element.style.display = 'none';" +
-            "            triangle.innerHTML = '&#x25b6; ';" +
-            "        }" +
-            "    }" +
-            "</script>";
-
-    /** TODO: Make it a setting */
-    private static final String HTML_DETAILS_RELATIVE_PATH = "details.html";
-    private static final String TXT_SUMMARY_RELATIVE_PATH = "summary.txt";
-
-    private static final int RESULTS_PER_DUMP = 500;
-    private static final int RESULTS_PER_DB_ACCESS = 50;
-
-    private int mCrashedTestsCount = 0;
-    private List<AbstractResult> mUnexpectedFailures = new ArrayList<AbstractResult>();
-    private List<AbstractResult> mExpectedFailures = new ArrayList<AbstractResult>();
-    private List<AbstractResult> mExpectedPasses = new ArrayList<AbstractResult>();
-    private List<AbstractResult> mUnexpectedPasses = new ArrayList<AbstractResult>();
-
-    private Cursor mUnexpectedFailuresCursor;
-    private Cursor mExpectedFailuresCursor;
-    private Cursor mUnexpectedPassesCursor;
-    private Cursor mExpectedPassesCursor;
-
-    private FileFilter mFileFilter;
-    private String mResultsRootDirPath;
-    private String mTestsRelativePath;
-    private Date mDate;
-
-    private int mResultsSinceLastHtmlDump = 0;
-    private int mResultsSinceLastDbAccess = 0;
-
-    private SummarizerDBHelper mDbHelper;
-
-    public Summarizer(String resultsRootDirPath, Context context) {
-        mFileFilter = new FileFilter();
-        mResultsRootDirPath = resultsRootDirPath;
-
-        /**
-         * We don't run the database I/O in a separate thread to avoid consumer/producer problem
-         * and to simplify code.
-         */
-        mDbHelper = new SummarizerDBHelper(context);
-        mDbHelper.open();
-    }
-
-    public static URI getDetailsUri() {
-        return new File(ManagerService.RESULTS_ROOT_DIR_PATH + File.separator +
-                HTML_DETAILS_RELATIVE_PATH).toURI();
-    }
-
-    public void appendTest(AbstractResult result) {
-        String relativePath = result.getRelativePath();
-
-        if (result.didCrash()) {
-            mCrashedTestsCount++;
-        }
-
-        if (result.didPass()) {
-            result.clearResults();
-            if (mFileFilter.isFail(relativePath)) {
-                mUnexpectedPasses.add(result);
-            } else {
-                mExpectedPasses.add(result);
-            }
-        } else {
-            if (mFileFilter.isFail(relativePath)) {
-                mExpectedFailures.add(result);
-            } else {
-                mUnexpectedFailures.add(result);
-            }
-        }
-
-        if (++mResultsSinceLastDbAccess == RESULTS_PER_DB_ACCESS) {
-            persistLists();
-            clearLists();
-        }
-    }
-
-    private void clearLists() {
-        mUnexpectedFailures.clear();
-        mExpectedFailures.clear();
-        mUnexpectedPasses.clear();
-        mExpectedPasses.clear();
-    }
-
-    private void persistLists() {
-        persistListToTable(mUnexpectedFailures, SummarizerDBHelper.UNEXPECTED_FAILURES_TABLE);
-        persistListToTable(mExpectedFailures, SummarizerDBHelper.EXPECTED_FAILURES_TABLE);
-        persistListToTable(mUnexpectedPasses, SummarizerDBHelper.UNEXPECTED_PASSES_TABLE);
-        persistListToTable(mExpectedPasses, SummarizerDBHelper.EXPECTED_PASSES_TABLE);
-        mResultsSinceLastDbAccess = 0;
-    }
-
-    private void persistListToTable(List<AbstractResult> results, String table) {
-        for (AbstractResult abstractResult : results) {
-            mDbHelper.insertAbstractResult(abstractResult, table);
-        }
-    }
-
-    public void setTestsRelativePath(String testsRelativePath) {
-        mTestsRelativePath = testsRelativePath;
-    }
-
-    public void summarize(Message onFinishMessage) {
-        persistLists();
-        clearLists();
-
-        mUnexpectedFailuresCursor =
-            mDbHelper.getAbstractResults(SummarizerDBHelper.UNEXPECTED_FAILURES_TABLE);
-        mUnexpectedPassesCursor =
-            mDbHelper.getAbstractResults(SummarizerDBHelper.UNEXPECTED_PASSES_TABLE);
-        mExpectedFailuresCursor =
-            mDbHelper.getAbstractResults(SummarizerDBHelper.EXPECTED_FAILURES_TABLE);
-        mExpectedPassesCursor =
-            mDbHelper.getAbstractResults(SummarizerDBHelper.EXPECTED_PASSES_TABLE);
-
-        String webKitRevision = getWebKitRevision();
-        createHtmlDetails(webKitRevision);
-        createTxtSummary(webKitRevision);
-
-        clearLists();
-        mUnexpectedFailuresCursor.close();
-        mUnexpectedPassesCursor.close();
-        mExpectedFailuresCursor.close();
-        mExpectedPassesCursor.close();
-
-        onFinishMessage.sendToTarget();
-    }
-
-    public void reset() {
-        mCrashedTestsCount = 0;
-        clearLists();
-        mDbHelper.reset();
-        mDate = new Date();
-    }
-
-    private void dumpHtmlToFile(StringBuilder html, boolean append) {
-        FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DETAILS_RELATIVE_PATH),
-                html.toString().getBytes(), append);
-        html.setLength(0);
-        mResultsSinceLastHtmlDump = 0;
-    }
-
-    private void createTxtSummary(String webKitRevision) {
-        StringBuilder txt = new StringBuilder();
-
-        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
-        txt.append("Path: " + mTestsRelativePath + "\n");
-        txt.append("Date: " + dateFormat.format(mDate) + "\n");
-        txt.append("Build fingerprint: " + Build.FINGERPRINT + "\n");
-        txt.append("WebKit version: " + getWebKitVersionFromUserAgentString() + "\n");
-        txt.append("WebKit revision: " + webKitRevision + "\n");
-
-        txt.append("TOTAL:                     " + getTotalTestCount() + "\n");
-        txt.append("CRASHED (among all tests): " + mCrashedTestsCount + "\n");
-        txt.append("UNEXPECTED FAILURES:       " + mUnexpectedFailuresCursor.getCount() + "\n");
-        txt.append("UNEXPECTED PASSES:         " + mUnexpectedPassesCursor.getCount() + "\n");
-        txt.append("EXPECTED FAILURES:         " + mExpectedFailuresCursor.getCount() + "\n");
-        txt.append("EXPECTED PASSES:           " + mExpectedPassesCursor.getCount() + "\n");
-
-        FsUtils.writeDataToStorage(new File(mResultsRootDirPath, TXT_SUMMARY_RELATIVE_PATH),
-                txt.toString().getBytes(), false);
-    }
-
-    private void createHtmlDetails(String webKitRevision) {
-        StringBuilder html = new StringBuilder();
-
-        html.append("<html><head>");
-        html.append(CSS);
-        html.append(SCRIPT);
-        html.append("</head><body>");
-
-        createTopSummaryTable(webKitRevision, html);
-        dumpHtmlToFile(html, false);
-
-        createResultsList(html, "Unexpected failures", mUnexpectedFailuresCursor);
-        createResultsList(html, "Unexpected passes", mUnexpectedPassesCursor);
-        createResultsList(html, "Expected failures", mExpectedFailuresCursor);
-        createResultsList(html, "Expected passes", mExpectedPassesCursor);
-
-        html.append("</body></html>");
-        dumpHtmlToFile(html, true);
-    }
-
-    private int getTotalTestCount() {
-        return mUnexpectedFailuresCursor.getCount() +
-                mUnexpectedPassesCursor.getCount() +
-                mExpectedPassesCursor.getCount() +
-                mExpectedFailuresCursor.getCount();
-    }
-
-    private String getWebKitVersionFromUserAgentString() {
-        Resources resources = new Resources(new AssetManager(), new DisplayMetrics(),
-                new Configuration());
-        String userAgent =
-                resources.getString(com.android.internal.R.string.web_user_agent);
-
-        Matcher matcher = Pattern.compile("AppleWebKit/([0-9]+?\\.[0-9])").matcher(userAgent);
-        if (matcher.find()) {
-            return matcher.group(1);
-        }
-        return "unknown";
-    }
-
-    private String getWebKitRevision() {
-        URL url = null;
-        try {
-            url = new URL(ForwarderManager.getHostSchemePort(false) + "ThirdPartyProject.prop");
-        } catch (MalformedURLException e) {
-            assert false;
-        }
-
-        String thirdPartyProjectContents = new String(FsUtils.readDataFromUrl(url));
-        Matcher matcher = Pattern.compile("^version=([0-9]+)", Pattern.MULTILINE).matcher(
-                thirdPartyProjectContents);
-        if (matcher.find()) {
-            return matcher.group(1);
-        }
-        return "unknown";
-    }
-
-    private void createTopSummaryTable(String webKitRevision, StringBuilder html) {
-        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
-        html.append("<h1>" + "Layout tests' results for: " +
-                (mTestsRelativePath.equals("") ? "all tests" : mTestsRelativePath) + "</h1>");
-        html.append("<h3>" + "Date: " + dateFormat.format(new Date()) + "</h3>");
-        html.append("<h3>" + "Build fingerprint: " + Build.FINGERPRINT + "</h3>");
-        html.append("<h3>" + "WebKit version: " + getWebKitVersionFromUserAgentString() + "</h3>");
-
-        html.append("<h3>" + "WebKit revision: ");
-        html.append("<a href=\"http://trac.webkit.org/browser/trunk?rev=" + webKitRevision +
-                "\" target=\"_blank\"><span class=\"path\">" + webKitRevision + "</span></a>");
-        html.append("</h3>");
-
-        html.append("<table class=\"summary\">");
-        createSummaryTableRow(html, "TOTAL", getTotalTestCount());
-        createSummaryTableRow(html, "CRASHED (among all tests)", mCrashedTestsCount);
-        createSummaryTableRow(html, "UNEXPECTED FAILURES", mUnexpectedFailuresCursor.getCount());
-        createSummaryTableRow(html, "UNEXPECTED PASSES", mUnexpectedPassesCursor.getCount());
-        createSummaryTableRow(html, "EXPECTED FAILURES", mExpectedFailuresCursor.getCount());
-        createSummaryTableRow(html, "EXPECTED PASSES", mExpectedPassesCursor.getCount());
-        html.append("</table>");
-    }
-
-    private void createSummaryTableRow(StringBuilder html, String caption, int size) {
-        html.append("<tr>");
-        html.append("    <td>" + caption + "</td>");
-        html.append("    <td>" + size + "</td>");
-        html.append("</tr>");
-    }
-
-    private void createResultsList(
-            StringBuilder html, String title, Cursor cursor) {
-        String relativePath;
-        String id = "";
-        AbstractResult.ResultCode resultCode;
-
-        html.append("<h2>" + title + " [" + cursor.getCount() + "]</h2>");
-
-        if (!cursor.moveToFirst()) {
-            return;
-        }
-
-        AbstractResult result;
-        do {
-            result = SummarizerDBHelper.getAbstractResult(cursor);
-
-            relativePath = result.getRelativePath();
-            resultCode = result.getResultCode();
-
-            html.append("<h3>");
-
-            /**
-             * Technically, two different paths could end up being the same, because
-             * ':' is a valid  character in a path. However, it is probably not going
-             * to cause any problems in this case
-             */
-            id = relativePath.replace(File.separator, ":");
-
-            /** Write the test name */
-            if (resultCode == AbstractResult.ResultCode.RESULTS_DIFFER) {
-                html.append("<a href=\"#\" onClick=\"toggleDisplay('" + id + "');");
-                html.append("return false;\">");
-                html.append("<span class=\"tri\" id=\"tri." + id + "\">&#x25b6; </span>");
-                html.append("<span class=\"path\">" + relativePath + "</span>");
-                html.append("</a>");
-            } else {
-                html.append("<a href=\"" + getViewSourceUrl(result.getRelativePath()).toString() + "\"");
-                html.append(" target=\"_blank\">");
-                html.append("<span class=\"sqr sqr_" + (result.didPass() ? "pass" : "fail"));
-                html.append("\">&#x25a0; </span>");
-                html.append("<span class=\"path\">" + result.getRelativePath() + "</span>");
-                html.append("</a>");
-            }
-
-            if (!result.didPass()) {
-                appendTags(html, result);
-            }
-
-            html.append("</h3>");
-            appendExpectedResultsSources(result, html);
-
-            if (resultCode == AbstractResult.ResultCode.RESULTS_DIFFER) {
-                html.append("<div class=\"diff\" style=\"display: none;\" id=\"" + id + "\">");
-                html.append(result.getDiffAsHtml());
-                html.append("<a href=\"#\" onClick=\"toggleDisplay('" + id + "');");
-                html.append("return false;\">Hide</a>");
-                html.append(" | ");
-                html.append("<a href=\"" + getViewSourceUrl(relativePath).toString() + "\"");
-                html.append(" target=\"_blank\">Show source</a>");
-                html.append("</div>");
-            }
-
-            html.append("<div class=\"space\"></div>");
-
-            if (++mResultsSinceLastHtmlDump == RESULTS_PER_DUMP) {
-                dumpHtmlToFile(html, true);
-            }
-
-            cursor.moveToNext();
-        } while (!cursor.isAfterLast());
-    }
-
-    private void appendTags(StringBuilder html, AbstractResult result) {
-        /** Tag tests which crash, time out or where results don't match */
-        if (result.didCrash()) {
-            html.append(" <span class=\"listItem crashed\">Crashed</span>");
-        } else {
-            if (result.didTimeOut()) {
-                html.append(" <span class=\"listItem timed_out\">Timed out</span>");
-            }
-            AbstractResult.ResultCode resultCode = result.getResultCode();
-            if (resultCode != AbstractResult.ResultCode.RESULTS_MATCH) {
-                html.append(" <span class=\"listItem " + resultCode.name() + "\">");
-                html.append(resultCode.toString());
-                html.append("</span>");
-            }
-        }
-
-        /** Detect missing LTC function */
-        String additionalTextOutputString = result.getAdditionalTextOutputString();
-        if (additionalTextOutputString != null &&
-                additionalTextOutputString.contains("com.android.dumprendertree") &&
-                additionalTextOutputString.contains("has no method")) {
-            if (additionalTextOutputString.contains("LayoutTestController")) {
-                html.append(" <span class=\"listItem noLtc\">LTC function missing</span>");
-            }
-            if (additionalTextOutputString.contains("EventSender")) {
-                html.append(" <span class=\"listItem noEventSender\">");
-                html.append("ES function missing</span>");
-            }
-        }
-    }
-
-    private static final void appendExpectedResultsSources(AbstractResult result,
-            StringBuilder html) {
-        String textSource = result.getExpectedTextResultPath();
-        String imageSource = result.getExpectedImageResultPath();
-
-        if (result.didCrash()) {
-            html.append("<span class=\"source\">Did not look for expected results</span>");
-            return;
-        }
-
-        if (textSource == null) {
-            // Show if a text result is missing. We may want to revisit this decision when we add
-            // support for image results.
-            html.append("<span class=\"source\">Expected textual result missing</span>");
-        } else {
-            html.append("<span class=\"source\">Expected textual result from: ");
-            html.append("<a href=\"" + ForwarderManager.getHostSchemePort(false) + "LayoutTests/" +
-                    textSource + "\"");
-            html.append(" target=\"_blank\">");
-            html.append(textSource + "</a></span>");
-        }
-        if (imageSource != null) {
-            html.append("<span class=\"source\">Expected image result from: ");
-            html.append("<a href=\"" + ForwarderManager.getHostSchemePort(false) + "LayoutTests/" +
-                    imageSource + "\"");
-            html.append(" target=\"_blank\">");
-            html.append(imageSource + "</a></span>");
-        }
-    }
-
-    private static final URL getViewSourceUrl(String relativePath) {
-        URL url = null;
-        try {
-            url = new URL("http", "localhost", ForwarderManager.HTTP_PORT,
-                    "/Tools/DumpRenderTree/android/view_source.php?src=" +
-                    relativePath);
-        } catch (MalformedURLException e) {
-            assert false : "relativePath=" + relativePath;
-        }
-        return url;
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/SummarizerDBHelper.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/SummarizerDBHelper.java
deleted file mode 100644
index 23e13ec..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/SummarizerDBHelper.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A basic class that wraps database accesses inside itself and provides functionality to
- * store and retrieve AbstractResults.
- */
-public class SummarizerDBHelper {
-    private static final String KEY_ID = "id";
-    private static final String KEY_PATH = "path";
-    private static final String KEY_BYTES = "bytes";
-
-    private static final String DATABASE_NAME = "SummarizerDB";
-    private static final int DATABASE_VERSION = 1;
-
-    static final String EXPECTED_FAILURES_TABLE = "expectedFailures";
-    static final String UNEXPECTED_FAILURES_TABLE = "unexpectedFailures";
-    static final String EXPECTED_PASSES_TABLE = "expextedPasses";
-    static final String UNEXPECTED_PASSES_TABLE = "unexpextedPasses";
-    private static final Set<String> TABLES_NAMES = new HashSet<String>();
-    {
-        TABLES_NAMES.add(EXPECTED_FAILURES_TABLE);
-        TABLES_NAMES.add(EXPECTED_PASSES_TABLE);
-        TABLES_NAMES.add(UNEXPECTED_FAILURES_TABLE);
-        TABLES_NAMES.add(UNEXPECTED_PASSES_TABLE);
-    }
-
-    private static final void createTables(SQLiteDatabase db) {
-        String cmd;
-        for (String tableName : TABLES_NAMES) {
-            cmd = "create table " + tableName + " ("
-                    + KEY_ID + " integer primary key autoincrement, "
-                    + KEY_PATH + " text not null, "
-                    + KEY_BYTES + " blob not null);";
-            db.execSQL(cmd);
-        }
-    }
-
-    private static final void dropTables(SQLiteDatabase db) {
-        for (String tableName : TABLES_NAMES) {
-            db.execSQL("DROP TABLE IF EXISTS " + tableName);
-        }
-    }
-
-    private static class DatabaseHelper extends SQLiteOpenHelper {
-        DatabaseHelper(Context context) {
-            super(context, DATABASE_NAME, null, DATABASE_VERSION);
-        }
-
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            dropTables(db);
-            createTables(db);
-        }
-
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            /** NOOP for now, because we will never upgrade the db */
-        }
-
-        public void reset(SQLiteDatabase db) {
-            dropTables(db);
-            createTables(db);
-        }
-    }
-
-    private DatabaseHelper mDbHelper;
-    private SQLiteDatabase mDb;
-
-    private final Context mContext;
-
-    public SummarizerDBHelper(Context ctx) {
-        mContext = ctx;
-        mDbHelper = new DatabaseHelper(mContext);
-    }
-
-    public void reset() {
-        mDbHelper.reset(this.mDb);
-    }
-
-    public void open() throws SQLException {
-        mDb = mDbHelper.getWritableDatabase();
-    }
-
-    public void close() {
-        mDbHelper.close();
-    }
-
-    public void insertAbstractResult(AbstractResult result, String table) {
-        ContentValues cv = new ContentValues();
-        cv.put(KEY_PATH, result.getRelativePath());
-        cv.put(KEY_BYTES, result.getBytes());
-        mDb.insert(table, null, cv);
-    }
-
-    public Cursor getAbstractResults(String table) throws SQLException {
-        return mDb.query(false, table, new String[] {KEY_BYTES}, null, null, null, null,
-                KEY_PATH + " ASC", null);
-    }
-
-    public static AbstractResult getAbstractResult(Cursor cursor) {
-        return AbstractResult.create(cursor.getBlob(cursor.getColumnIndex(KEY_BYTES)));
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
deleted file mode 100644
index e374c1b..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import com.android.dumprendertree2.scriptsupport.OnEverythingFinishedCallback;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.Gravity;
-import android.view.Window;
-import android.webkit.WebView;
-import android.widget.Toast;
-
-import java.io.File;
-import java.util.ArrayList;
-
-/**
- * An Activity that generates a list of tests and sends the intent to
- * LayoutTestsExecuter to run them. It also restarts the LayoutTestsExecuter
- * after it crashes.
- */
-public class TestsListActivity extends Activity {
-
-    private static final int MSG_TEST_LIST_PRELOADER_DONE = 0;
-
-    /** Constants for adding extras to an intent */
-    public static final String EXTRA_TEST_PATH = "TestPath";
-
-    private static ProgressDialog sProgressDialog;
-
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_TEST_LIST_PRELOADER_DONE:
-                    sProgressDialog.dismiss();
-                    mTestsList = (ArrayList<String>)msg.obj;
-                    mTotalTestCount = mTestsList.size();
-                    restartExecutor(0);
-                    break;
-            }
-        }
-    };
-
-    private ArrayList<String> mTestsList;
-    private int mTotalTestCount;
-
-    private OnEverythingFinishedCallback mOnEverythingFinishedCallback;
-    private boolean mEverythingFinished;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        /** Prepare the progress dialog */
-        sProgressDialog = new ProgressDialog(TestsListActivity.this);
-        sProgressDialog.setCancelable(false);
-        sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
-        sProgressDialog.setTitle(R.string.dialog_progress_title);
-        sProgressDialog.setMessage(getText(R.string.dialog_progress_msg));
-
-        requestWindowFeature(Window.FEATURE_PROGRESS);
-
-        Intent intent = getIntent();
-        if (!intent.getAction().equals(Intent.ACTION_RUN)) {
-            return;
-        }
-        String path = intent.getStringExtra(EXTRA_TEST_PATH);
-
-        sProgressDialog.show();
-        Message doneMsg = Message.obtain(mHandler, MSG_TEST_LIST_PRELOADER_DONE);
-
-        Intent serviceIntent = new Intent(this, ManagerService.class);
-        serviceIntent.putExtra("path", path);
-        startService(serviceIntent);
-
-        new TestsListPreloaderThread(path, doneMsg).start();
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        if (intent.getAction().equals(Intent.ACTION_REBOOT)) {
-            onCrashIntent(intent);
-        } else if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
-            onEverythingFinishedIntent(intent);
-        }
-    }
-
-    /**
-     * This method handles an intent that comes from ManageService when crash is detected.
-     * The intent contains an index in mTestsList of the test that crashed. TestsListActivity
-     * restarts the LayoutTestsExecutor from the following test in mTestsList, by sending
-     * an intent to it. This new intent contains a list of remaining tests to run,
-     * total count of all tests, and the index of the first test to run after restarting.
-     * LayoutTestExecutor runs then as usual, sending reports to ManagerService. If it
-     * detects the crash it sends a new intent and the flow repeats.
-     */
-    private void onCrashIntent(Intent intent) {
-        int nextTestToRun = intent.getIntExtra("crashedTestIndex", -1) + 1;
-        if (nextTestToRun > 0 && nextTestToRun <= mTotalTestCount) {
-            restartExecutor(nextTestToRun);
-        }
-    }
-
-    public void registerOnEverythingFinishedCallback(OnEverythingFinishedCallback callback) {
-        mOnEverythingFinishedCallback = callback;
-        if (mEverythingFinished) {
-            mOnEverythingFinishedCallback.onFinished();
-        }
-    }
-
-    private void onEverythingFinishedIntent(Intent intent) {
-        Toast toast = Toast.makeText(this,
-                "All tests finished.\nPress back key to return to the tests' list.",
-                Toast.LENGTH_LONG);
-        toast.setGravity(Gravity.CENTER, -40, 0);
-        toast.show();
-
-        /** Show the details to the user */
-        WebView webView = new WebView(this);
-        webView.getSettings().setJavaScriptEnabled(true);
-        webView.getSettings().setBuiltInZoomControls(true);
-        webView.getSettings().setEnableSmoothTransition(true);
-        /** This enables double-tap to zoom */
-        webView.getSettings().setUseWideViewPort(true);
-
-        setContentView(webView);
-        webView.loadUrl(Summarizer.getDetailsUri().toString());
-
-        mEverythingFinished = true;
-        if (mOnEverythingFinishedCallback != null) {
-            mOnEverythingFinishedCallback.onFinished();
-        }
-    }
-
-    /**
-     * This, together with android:configChanges="orientation" in manifest file, prevents
-     * the activity from restarting on orientation change.
-     */
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        outState.putStringArrayList("testsList", mTestsList);
-        outState.putInt("totalCount", mTotalTestCount);
-
-        super.onSaveInstanceState(outState);
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-
-        mTestsList = savedInstanceState.getStringArrayList("testsList");
-        mTotalTestCount = savedInstanceState.getInt("totalCount");
-    }
-
-    /**
-     * (Re)starts the executer activity from the given test number (inclusive, 0-based).
-     * This number is an index in mTestsList, not the sublist passed in the intent.
-     *
-     * @param startFrom
-     *      test index in mTestsList to start the tests from (inclusive, 0-based)
-     */
-    private void restartExecutor(int startFrom) {
-        Intent intent = new Intent();
-        intent.setClass(this, LayoutTestsExecutor.class);
-        intent.setAction(Intent.ACTION_RUN);
-
-        if (startFrom < mTotalTestCount) {
-            File testListFile = new File(getExternalFilesDir(null), "test_list.txt");
-            FsUtils.saveTestListToStorage(testListFile, startFrom, mTestsList);
-            intent.putExtra(LayoutTestsExecutor.EXTRA_TESTS_FILE, testListFile.getAbsolutePath());
-            intent.putExtra(LayoutTestsExecutor.EXTRA_TEST_INDEX, startFrom);
-        } else {
-            intent.putExtra(LayoutTestsExecutor.EXTRA_TESTS_FILE, "");
-        }
-
-        startActivity(intent);
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
deleted file mode 100644
index ab98830..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.os.Environment;
-import android.os.Message;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * A Thread that is responsible for generating a lists of tests to run.
- */
-public class TestsListPreloaderThread extends Thread {
-
-    private static final String LOG_TAG = "TestsListPreloaderThread";
-
-    /** A list containing relative paths of tests to run */
-    private ArrayList<String> mTestsList = new ArrayList<String>();
-
-    private FileFilter mFileFilter;
-
-    /**
-     * A relative path to the directory with the tests we want to run or particular test.
-     * Used up to and including preloadTests().
-     */
-    private String mRelativePath;
-
-    private Message mDoneMsg;
-
-    /**
-     * The given path must be relative to the root dir.
-     *
-     * @param path
-     * @param doneMsg
-     */
-    public TestsListPreloaderThread(String path, Message doneMsg) {
-        mRelativePath = path;
-        mDoneMsg = doneMsg;
-    }
-
-    @Override
-    public void run() {
-        mFileFilter = new FileFilter();
-        if (FileFilter.isTestFile(mRelativePath)) {
-            mTestsList.add(mRelativePath);
-        } else {
-            loadTestsFromUrl(mRelativePath);
-        }
-
-        mDoneMsg.obj = mTestsList;
-        mDoneMsg.sendToTarget();
-    }
-
-    /**
-     * Loads all the tests from the given directories and all the subdirectories
-     * into mTestsList.
-     *
-     * @param dirRelativePath
-     */
-    private void loadTestsFromUrl(String rootRelativePath) {
-        LinkedList<String> directoriesList = new LinkedList<String>();
-        directoriesList.add(rootRelativePath);
-
-        String relativePath;
-        String itemName;
-        while (!directoriesList.isEmpty()) {
-            relativePath = directoriesList.removeFirst();
-
-            List<String> dirRelativePaths = FsUtils.getLayoutTestsDirContents(relativePath, false, true);
-            if (dirRelativePaths != null) {
-                for (String dirRelativePath : dirRelativePaths) {
-                    itemName = new File(dirRelativePath).getName();
-                    if (FileFilter.isTestDir(itemName)) {
-                        directoriesList.add(dirRelativePath);
-                    }
-                }
-            }
-
-            List<String> testRelativePaths = FsUtils.getLayoutTestsDirContents(relativePath, false, false);
-            if (testRelativePaths != null) {
-                for (String testRelativePath : testRelativePaths) {
-                    itemName = new File(testRelativePath).getName();
-                    if (FileFilter.isTestFile(itemName)) {
-                        /** We choose to skip all the tests that are expected to crash. */
-                        if (!mFileFilter.isCrash(testRelativePath)) {
-                            mTestsList.add(testRelativePath);
-                        } else {
-                            /**
-                             * TODO: Summarizer is now in service - figure out how to send the info.
-                             * Previously: mSummarizer.addSkippedTest(relativePath);
-                             */
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java
deleted file mode 100644
index fd1c0ad..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.webkit.WebView;
-import android.webkit.WebViewClassic;
-
-import name.fraser.neil.plaintext.diff_match_patch;
-
-import java.util.LinkedList;
-
-/**
- * A result object for which the expected output is text. It does not have an image
- * expected result.
- *
- * <p>Created if layoutTestController.dumpAsText() was called.
- */
-public class TextResult extends AbstractResult {
-
-    private static final int MSG_DOCUMENT_AS_TEXT = 0;
-
-    private String mExpectedResult;
-    private String mExpectedResultPath;
-    private String mActualResult;
-    private String mRelativePath;
-    private boolean mDidTimeOut;
-    private ResultCode mResultCode;
-    transient private Message mResultObtainedMsg;
-
-    private boolean mDumpChildFramesAsText;
-
-    transient private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == MSG_DOCUMENT_AS_TEXT) {
-                mActualResult = (String)msg.obj;
-                mResultObtainedMsg.sendToTarget();
-            }
-        }
-    };
-
-    public TextResult(String relativePath) {
-        mRelativePath = relativePath;
-    }
-
-    public void setDumpChildFramesAsText(boolean dumpChildFramesAsText) {
-        mDumpChildFramesAsText = dumpChildFramesAsText;
-    }
-
-    /**
-     * Used to recreate the Result when received by the service.
-     *
-     * @param bundle
-     *      bundle with data used to recreate the result
-     */
-    public TextResult(Bundle bundle) {
-        mExpectedResult = bundle.getString("expectedTextualResult");
-        mExpectedResultPath = bundle.getString("expectedTextualResultPath");
-        mActualResult = bundle.getString("actualTextualResult");
-        setAdditionalTextOutputString(bundle.getString("additionalTextOutputString"));
-        mRelativePath = bundle.getString("relativePath");
-        mDidTimeOut = bundle.getBoolean("didTimeOut");
-    }
-
-    @Override
-    public void clearResults() {
-        super.clearResults();
-        mExpectedResult = null;
-        mActualResult = null;
-    }
-
-    @Override
-    public ResultCode getResultCode() {
-        if (mResultCode == null) {
-            mResultCode = resultsMatch() ? AbstractResult.ResultCode.RESULTS_MATCH
-                    : AbstractResult.ResultCode.RESULTS_DIFFER;
-        }
-        return mResultCode;
-    }
-
-    private boolean resultsMatch() {
-        assert mExpectedResult != null;
-        assert mActualResult != null;
-        // Trim leading and trailing empty lines, as other WebKit platforms do.
-        String leadingEmptyLines = "^\\n+";
-        String trailingEmptyLines = "\\n+$";
-        String trimmedExpectedResult = mExpectedResult.replaceFirst(leadingEmptyLines, "")
-                .replaceFirst(trailingEmptyLines, "");
-        String trimmedActualResult = mActualResult.replaceFirst(leadingEmptyLines, "")
-                .replaceFirst(trailingEmptyLines, "");
-        return trimmedExpectedResult.equals(trimmedActualResult);
-    }
-
-    @Override
-    public boolean didCrash() {
-        return false;
-    }
-
-    @Override
-    public boolean didTimeOut() {
-        return mDidTimeOut;
-    }
-
-    @Override
-    public void setDidTimeOut() {
-        mDidTimeOut = true;
-    }
-
-    @Override
-    public byte[] getActualImageResult() {
-        return null;
-    }
-
-    @Override
-    public String getActualTextResult() {
-        String additionalTextResultString = getAdditionalTextOutputString();
-        if (additionalTextResultString != null) {
-            return additionalTextResultString + mActualResult;
-        }
-
-        return mActualResult;
-    }
-
-    @Override
-    public void setExpectedImageResult(byte[] expectedResult) {
-        /** This method is not applicable to this type of result */
-    }
-
-    @Override
-    public void setExpectedImageResultPath(String relativePath) {
-        /** This method is not applicable to this type of result */
-    }
-
-    @Override
-    public String getExpectedImageResultPath() {
-        /** This method is not applicable to this type of result */
-        return null;
-    }
-
-    @Override
-    public void setExpectedTextResultPath(String relativePath) {
-        mExpectedResultPath = relativePath;
-    }
-
-    @Override
-    public String getExpectedTextResultPath() {
-        return mExpectedResultPath;
-    }
-
-    @Override
-    public void setExpectedTextResult(String expectedResult) {
-        // For text results, we use an empty string for the expected result when none is
-        // present, as other WebKit platforms do.
-        mExpectedResult = expectedResult == null ? "" : expectedResult;
-    }
-
-    @Override
-    public String getDiffAsHtml() {
-        assert mExpectedResult != null;
-        assert mActualResult != null;
-
-        StringBuilder html = new StringBuilder();
-        html.append("<table class=\"visual_diff\">");
-        html.append("    <tr class=\"headers\">");
-        html.append("        <td colspan=\"2\">Expected result:</td>");
-        html.append("        <td class=\"space\"></td>");
-        html.append("        <td colspan=\"2\">Actual result:</td>");
-        html.append("    </tr>");
-
-        appendDiffHtml(html);
-
-        html.append("    <tr class=\"footers\">");
-        html.append("        <td colspan=\"2\"></td>");
-        html.append("        <td class=\"space\"></td>");
-        html.append("        <td colspan=\"2\"></td>");
-        html.append("    </tr>");
-        html.append("</table>");
-
-        return html.toString();
-    }
-
-    private void appendDiffHtml(StringBuilder html) {
-        LinkedList<diff_match_patch.Diff> diffs =
-                new diff_match_patch().diff_main(mExpectedResult, mActualResult);
-
-        diffs = VisualDiffUtils.splitDiffsOnNewline(diffs);
-
-        LinkedList<String> expectedLines = new LinkedList<String>();
-        LinkedList<Integer> expectedLineNums = new LinkedList<Integer>();
-        LinkedList<String> actualLines = new LinkedList<String>();
-        LinkedList<Integer> actualLineNums = new LinkedList<Integer>();
-
-        VisualDiffUtils.generateExpectedResultLines(diffs, expectedLineNums, expectedLines);
-        VisualDiffUtils.generateActualResultLines(diffs, actualLineNums, actualLines);
-        // TODO: We should use a map for each line number and lines pair.
-        assert expectedLines.size() == expectedLineNums.size();
-        assert actualLines.size() == actualLineNums.size();
-        assert expectedLines.size() == actualLines.size();
-
-        html.append(VisualDiffUtils.getHtml(expectedLineNums, expectedLines,
-                actualLineNums, actualLines));
-    }
-
-    @Override
-    public TestType getType() {
-        return TestType.TEXT;
-    }
-
-    @Override
-    public void obtainActualResults(WebView webview, Message resultObtainedMsg) {
-        mResultObtainedMsg = resultObtainedMsg;
-        Message msg = mHandler.obtainMessage(MSG_DOCUMENT_AS_TEXT);
-
-        /**
-         * arg1 - should dump top frame as text
-         * arg2 - should dump child frames as text
-         */
-        msg.arg1 = 1;
-        msg.arg2 = mDumpChildFramesAsText ? 1 : 0;
-        WebViewClassic.fromWebView(webview).documentAsText(msg);
-    }
-
-    @Override
-    public Bundle getBundle() {
-        Bundle bundle = new Bundle();
-        bundle.putString("expectedTextualResult", mExpectedResult);
-        bundle.putString("expectedTextualResultPath", mExpectedResultPath);
-        bundle.putString("actualTextualResult", getActualTextResult());
-        bundle.putString("additionalTextOutputString", getAdditionalTextOutputString());
-        bundle.putString("relativePath", mRelativePath);
-        bundle.putBoolean("didTimeOut", mDidTimeOut);
-        bundle.putString("type", getType().name());
-        return bundle;
-    }
-
-    @Override
-    public String getRelativePath() {
-        return mRelativePath;
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/VisualDiffUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/VisualDiffUtils.java
deleted file mode 100644
index d7f7313..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/VisualDiffUtils.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import name.fraser.neil.plaintext.diff_match_patch;
-
-import java.util.LinkedList;
-
-/**
- * Helper methods fo TextResult.getDiffAsHtml()
- */
-public class VisualDiffUtils {
-
-    private static final int DONT_PRINT_LINE_NUMBER = -1;
-
-    /**
-     * Preprocesses the list of diffs so that new line characters appear only at the end of
-     * diff.text
-     *
-     * @param diffs
-     * @return
-     *      LinkedList of diffs where new line character appears only on the end of
-     *      diff.text
-     */
-    public static LinkedList<diff_match_patch.Diff> splitDiffsOnNewline(
-            LinkedList<diff_match_patch.Diff> diffs) {
-        LinkedList<diff_match_patch.Diff> newDiffs = new LinkedList<diff_match_patch.Diff>();
-
-        String[] parts;
-        int lengthMinusOne;
-        for (diff_match_patch.Diff diff : diffs) {
-            parts = diff.text.split("\n", -1);
-            if (parts.length == 1) {
-                newDiffs.add(diff);
-                continue;
-            }
-
-            lengthMinusOne = parts.length - 1;
-            for (int i = 0; i < lengthMinusOne; i++) {
-                newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[i] + "\n"));
-            }
-            if (!parts[lengthMinusOne].isEmpty()) {
-                newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[lengthMinusOne]));
-            }
-        }
-
-        return newDiffs;
-    }
-
-    public static void generateExpectedResultLines(LinkedList<diff_match_patch.Diff> diffs,
-            LinkedList<Integer> lineNums, LinkedList<String> lines) {
-        String delSpan = "<span class=\"del\">";
-        String eqlSpan = "<span class=\"eql\">";
-
-        String line = "";
-        int i = 1;
-        diff_match_patch.Diff diff;
-        int size = diffs.size();
-        boolean isLastDiff;
-        for (int j = 0; j < size; j++) {
-            diff = diffs.get(j);
-            isLastDiff = j == size - 1;
-            switch (diff.operation) {
-                case DELETE:
-                    line = processDiff(diff, lineNums, lines, line, i, delSpan, isLastDiff);
-                    if (line.equals("")) {
-                        i++;
-                    }
-                    break;
-
-                case INSERT:
-                    // If the line is currently empty and this insertion is the entire line, the
-                    // expected line is absent, so it has no line number.
-                    if (diff.text.endsWith("\n") || isLastDiff) {
-                        lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++);
-                        lines.add(line);
-                        line = "";
-                    }
-                    break;
-
-                case EQUAL:
-                    line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff);
-                    if (line.equals("")) {
-                        i++;
-                    }
-                    break;
-            }
-        }
-    }
-
-    public static void generateActualResultLines(LinkedList<diff_match_patch.Diff> diffs,
-            LinkedList<Integer> lineNums, LinkedList<String> lines) {
-        String insSpan = "<span class=\"ins\">";
-        String eqlSpan = "<span class=\"eql\">";
-
-        String line = "";
-        int i = 1;
-        diff_match_patch.Diff diff;
-        int size = diffs.size();
-        boolean isLastDiff;
-        for (int j = 0; j < size; j++) {
-            diff = diffs.get(j);
-            isLastDiff = j == size - 1;
-            switch (diff.operation) {
-                case INSERT:
-                    line = processDiff(diff, lineNums, lines, line, i, insSpan, isLastDiff);
-                    if (line.equals("")) {
-                        i++;
-                    }
-                    break;
-
-                case DELETE:
-                    // If the line is currently empty and deletion is the entire line, the
-                    // actual line is absent, so it has no line number.
-                    if (diff.text.endsWith("\n") || isLastDiff) {
-                        lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++);
-                        lines.add(line);
-                        line = "";
-                    }
-                    break;
-
-                case EQUAL:
-                    line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff);
-                    if (line.equals("")) {
-                        i++;
-                    }
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Generate or append a line for a given diff and add it to given collections if necessary.
-     * It puts diffs in HTML spans.
-     *
-     * @param diff
-     * @param lineNums
-     * @param lines
-     * @param line
-     * @param i
-     * @param begSpan
-     * @param forceOutputLine Force the current line to be output
-     * @return
-     */
-    public static String processDiff(diff_match_patch.Diff diff, LinkedList<Integer> lineNums,
-            LinkedList<String> lines, String line, int i, String begSpan, boolean forceOutputLine) {
-        String endSpan = "</span>";
-        String br = "&nbsp;";
-
-        if (diff.text.endsWith("\n") || forceOutputLine) {
-            lineNums.add(i);
-            /** TODO: Think of better way to replace stuff */
-            line += begSpan + diff.text.replace("  ", "&nbsp;&nbsp;")
-                    + endSpan + br;
-            lines.add(line);
-            line = "";
-        } else {
-            line += begSpan + diff.text.replace("  ", "&nbsp;&nbsp;") + endSpan;
-        }
-
-        return line;
-    }
-
-    public static String getHtml(LinkedList<Integer> lineNums1, LinkedList<String> lines1,
-            LinkedList<Integer> lineNums2, LinkedList<String> lines2) {
-        StringBuilder html = new StringBuilder();
-        int lineNum;
-        int size = lines1.size();
-        for (int i = 0; i < size; i++) {
-            html.append("<tr class=\"results\">");
-
-            html.append("    <td class=\"line_count\">");
-            lineNum = lineNums1.removeFirst();
-            if (lineNum > 0) {
-                html.append(lineNum);
-            }
-            html.append("    </td>");
-
-            html.append("    <td class=\"line\">");
-            html.append(lines1.removeFirst());
-            html.append("    </td>");
-
-            html.append("    <td class=\"space\"></td>");
-
-            html.append("    <td class=\"line_count\">");
-            lineNum = lineNums2.removeFirst();
-            if (lineNum > 0) {
-                html.append(lineNum);
-            }
-            html.append("    </td>");
-
-            html.append("    <td class=\"line\">");
-            html.append(lines2.removeFirst());
-            html.append("    </td>");
-
-            html.append("</tr>");
-        }
-        return html.toString();
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java
deleted file mode 100644
index 224509d..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.forwarder;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-
-/**
- * The utility class that can setup a socket allowing the device to communicate with remote
- * machines through the machine that the device is connected to via adb.
- */
-public class AdbUtils {
-    private static final String LOG_TAG = "AdbUtils";
-
-    private static final String ADB_OK = "OKAY";
-    private static final int ADB_PORT = 5037;
-    private static final String ADB_HOST = "127.0.0.1";
-    private static final int ADB_RESPONSE_SIZE = 4;
-
-    /**
-     * Creates a new socket that can be configured to serve as a transparent proxy to a
-     * remote machine. This can be achieved by calling configureSocket()
-     *
-     * @return a socket that can be configured to link to remote machine
-     * @throws IOException
-     */
-    public static Socket createSocket() throws IOException{
-        return new Socket(ADB_HOST, ADB_PORT);
-    }
-
-    /**
-     * Configures the connection to serve as a transparent proxy to a remote machine.
-     * The given streams must belong to a socket created by createSocket().
-     *
-     * @param inputStream inputStream of the socket we want to configure
-     * @param outputStream outputStream of the socket we want to configure
-     * @param remoteAddress address of the remote machine (as you would type in a browser
-     *      in a machine that the device is connected to via adb)
-     * @param remotePort port on which to connect
-     * @return if the configuration suceeded
-     * @throws IOException
-     */
-    public static boolean configureConnection(InputStream inputStream, OutputStream outputStream,
-            String remoteAddress, int remotePort) throws IOException {
-        String cmd = "tcp:" + remotePort + ":" + remoteAddress;
-        cmd = String.format("%04X", cmd.length()) + cmd;
-
-        byte[] buf = new byte[ADB_RESPONSE_SIZE];
-        outputStream.write(cmd.getBytes());
-        int read = inputStream.read(buf);
-        if (read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
-            Log.w(LOG_TAG, "adb cmd failed.");
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java
deleted file mode 100644
index f19cd41..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.forwarder;
-
-import android.util.Log;
-
-import com.android.dumprendertree2.FsUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-
-/**
- * Worker class for {@link Forwarder}. A ConnectionHandler will be created once the Forwarder
- * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
- * connection already proxied by adb networking (see also {@link AdbUtils}).
- */
-public class ConnectionHandler {
-
-    private static final String LOG_TAG = "ConnectionHandler";
-
-    public static interface OnFinishedCallback {
-        public void onFinished();
-    }
-
-    private class SocketPipeThread extends Thread {
-
-        private InputStream mInputStream;
-        private OutputStream mOutputStream;
-
-        public SocketPipeThread(InputStream inputStream, OutputStream outputStream) {
-            mInputStream = inputStream;
-            mOutputStream = outputStream;
-            setName("SocketPipeThread: " + getName());
-        }
-
-        @Override
-        public void run() {
-            byte[] buffer = new byte[4096];
-            int length;
-            while (true) {
-                try {
-                    if ((length = mInputStream.read(buffer)) < 0) {
-                        break;
-                    }
-                    mOutputStream.write(buffer, 0, length);
-                } catch (IOException e) {
-                    /** This exception means one of the streams is closed */
-                    Log.v(LOG_TAG, this.toString(), e);
-                    break;
-                }
-            }
-
-            synchronized (mThreadsRunning) {
-                mThreadsRunning--;
-                if (mThreadsRunning == 0) {
-                    ConnectionHandler.this.stop();
-                    mOnFinishedCallback.onFinished();
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return getName();
-        }
-    }
-
-    private Integer mThreadsRunning;
-
-    private Socket mFromSocket, mToSocket;
-    private SocketPipeThread mFromToPipe, mToFromPipe;
-    private InputStream mFromSocketInputStream, mToSocketInputStream;
-    private OutputStream mFromSocketOutputStream, mToSocketOutputStream;
-
-    private int mPort;
-    private String mRemoteMachineIpAddress;
-
-    private OnFinishedCallback mOnFinishedCallback;
-
-    public ConnectionHandler(String remoteMachineIp, int port, Socket fromSocket, Socket toSocket)
-            throws IOException {
-        mRemoteMachineIpAddress = remoteMachineIp;
-        mPort = port;
-
-        mFromSocket = fromSocket;
-        mToSocket = toSocket;
-
-        try {
-            mFromSocketInputStream = mFromSocket.getInputStream();
-            mToSocketInputStream = mToSocket.getInputStream();
-            mFromSocketOutputStream = mFromSocket.getOutputStream();
-            mToSocketOutputStream = mToSocket.getOutputStream();
-            AdbUtils.configureConnection(mToSocketInputStream, mToSocketOutputStream,
-                    mRemoteMachineIpAddress, mPort);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Unable to start ConnectionHandler", e);
-            closeStreams();
-            throw e;
-        }
-
-        mFromToPipe = new SocketPipeThread(mFromSocketInputStream, mToSocketOutputStream);
-        mToFromPipe = new SocketPipeThread(mToSocketInputStream, mFromSocketOutputStream);
-    }
-
-    public void registerOnConnectionHandlerFinishedCallback(OnFinishedCallback callback) {
-        mOnFinishedCallback = callback;
-    }
-
-    private void closeStreams() {
-        FsUtils.closeInputStream(mFromSocketInputStream);
-        FsUtils.closeInputStream(mToSocketInputStream);
-        FsUtils.closeOutputStream(mFromSocketOutputStream);
-        FsUtils.closeOutputStream(mToSocketOutputStream);
-    }
-
-    public void start() {
-        /** We have 2 threads running, one for each pipe, that we start here. */
-        mThreadsRunning = 2;
-        mFromToPipe.start();
-        mToFromPipe.start();
-    }
-
-    public void stop() {
-        shutdown(mFromSocket);
-        shutdown(mToSocket);
-    }
-
-    private void shutdown(Socket socket) {
-        synchronized (mFromToPipe) {
-            synchronized (mToFromPipe) {
-                /** This will stop the while loop in the run method */
-                try {
-                    if (!socket.isInputShutdown()) {
-                        socket.shutdownInput();
-                    }
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
-                }
-                try {
-                    if (!socket.isOutputShutdown()) {
-                        socket.shutdownOutput();
-                    }
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
-                }
-                try {
-                    if (!socket.isClosed()) {
-                        socket.close();
-                    }
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
-                }
-            }
-        }
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java
deleted file mode 100644
index ce22fa0..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.forwarder;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A port forwarding server. Listens on localhost on specified port and forwards the tcp
- * communications to external socket via adb networking proxy.
- */
-public class Forwarder extends Thread {
-    private static final String LOG_TAG = "Forwarder";
-
-    private int mPort;
-    private String mRemoteMachineIpAddress;
-
-    private ServerSocket mServerSocket;
-
-    private Set<ConnectionHandler> mConnectionHandlers = new HashSet<ConnectionHandler>();
-
-    public Forwarder(int port, String remoteMachineIpAddress) {
-        mPort = port;
-        mRemoteMachineIpAddress = remoteMachineIpAddress;
-    }
-
-    @Override
-    public void start() {
-        Log.i(LOG_TAG, "start(): Starting fowarder on port: " + mPort);
-
-        try {
-            mServerSocket = new ServerSocket(mPort);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "mPort=" + mPort, e);
-            return;
-        }
-
-        super.start();
-    }
-
-    @Override
-    public void run() {
-        while (true) {
-            Socket localSocket;
-            try {
-                localSocket = mServerSocket.accept();
-            } catch (IOException e) {
-                /** This most likely means that mServerSocket is already closed */
-                Log.w(LOG_TAG, "mPort=" + mPort, e);
-                break;
-            }
-
-            Socket remoteSocket = null;
-            final ConnectionHandler connectionHandler;
-            try {
-                remoteSocket = AdbUtils.createSocket();
-                connectionHandler = new ConnectionHandler(
-                        mRemoteMachineIpAddress, mPort, localSocket, remoteSocket);
-            } catch (IOException exception) {
-                try {
-                    localSocket.close();
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "mPort=" + mPort, e);
-                }
-                if (remoteSocket != null) {
-                    try {
-                        remoteSocket.close();
-                    } catch (IOException e) {
-                        Log.e(LOG_TAG, "mPort=" + mPort, e);
-                    }
-                }
-                continue;
-            }
-
-            /**
-             * We have to close the sockets after the ConnectionHandler finishes, so we
-             * don't get "Too may open files" exception. We also remove the ConnectionHandler
-             * from the collection to avoid memory issues.
-             * */
-            ConnectionHandler.OnFinishedCallback callback =
-                    new ConnectionHandler.OnFinishedCallback() {
-                @Override
-                public void onFinished() {
-                    synchronized (this) {
-                        if (!mConnectionHandlers.remove(connectionHandler)) {
-                            assert false : "removeConnectionHandler(): not in the collection";
-                        }
-                    }
-                }
-            };
-            connectionHandler.registerOnConnectionHandlerFinishedCallback(callback);
-
-            synchronized (this) {
-                mConnectionHandlers.add(connectionHandler);
-            }
-            connectionHandler.start();
-        }
-
-        synchronized (this) {
-            for (ConnectionHandler connectionHandler : mConnectionHandlers) {
-                connectionHandler.stop();
-            }
-        }
-    }
-
-    public void finish() {
-        try {
-            mServerSocket.close();
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "mPort=" + mPort, e);
-        }
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java
deleted file mode 100644
index cff436ff..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.forwarder;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import android.util.Log;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A simple class to start and stop Forwarders running on some ports.
- *
- * It uses a singleton pattern and is thread safe.
- */
-public class ForwarderManager {
-    private static final String LOG_TAG = "ForwarderManager";
-
-    /**
-     * The IP address of the server serving the tests.
-     */
-    private static final String HOST_IP = "127.0.0.1";
-
-    /**
-     * We use these ports because other webkit platforms do. They are set up in
-     * external/webkit/LayoutTests/http/conf/apache2-debian-httpd.conf
-     */
-    public static final int HTTP_PORT = 8000;
-    public static final int HTTPS_PORT = 8443;
-
-    private static ForwarderManager forwarderManager;
-
-    private Set<Forwarder> mForwarders;
-    private boolean mIsStarted;
-
-    private ForwarderManager() {
-        mForwarders = new HashSet<Forwarder>(2);
-        mForwarders.add(new Forwarder(HTTP_PORT, HOST_IP));
-        mForwarders.add(new Forwarder(HTTPS_PORT, HOST_IP));
-    }
-
-    /**
-     * Returns the main part of the URL with the trailing slash
-     *
-     * @param isHttps
-     * @return
-     */
-    public static final String getHostSchemePort(boolean isHttps) {
-        int port;
-        String protocol;
-        if (isHttps) {
-            protocol = "https";
-            port = HTTPS_PORT;
-        } else {
-            protocol = "http";
-            port = HTTP_PORT;
-        }
-
-        URL url = null;
-        try {
-            url = new URL(protocol, HOST_IP, port, "/");
-        } catch (MalformedURLException e) {
-            assert false : "isHttps=" + isHttps;
-        }
-
-        return url.toString();
-    }
-
-    public static synchronized ForwarderManager getForwarderManager() {
-        if (forwarderManager == null) {
-            forwarderManager = new ForwarderManager();
-        }
-        return forwarderManager;
-    }
-
-    @Override
-    public Object clone() throws CloneNotSupportedException {
-        throw new CloneNotSupportedException();
-    }
-
-    public synchronized void start() {
-        if (mIsStarted) {
-            Log.w(LOG_TAG, "start(): ForwarderManager already running! NOOP.");
-            return;
-        }
-
-        for (Forwarder forwarder : mForwarders) {
-            forwarder.start();
-        }
-
-        mIsStarted = true;
-        Log.i(LOG_TAG, "ForwarderManager started.");
-    }
-
-    public synchronized void stop() {
-        if (!mIsStarted) {
-            Log.w(LOG_TAG, "stop(): ForwarderManager already stopped! NOOP.");
-            return;
-        }
-
-        for (Forwarder forwarder : mForwarders) {
-            forwarder.finish();
-        }
-
-        mIsStarted = false;
-        Log.i(LOG_TAG, "ForwarderManager stopped.");
-    }
-}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java
deleted file mode 100644
index e1d4364..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.scriptsupport;
-
-/**
- * Callback used to inform scriptsupport.Starter that everything is finished and
- * we can exit
- */
-public interface OnEverythingFinishedCallback {
-    public void onFinished();
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java
deleted file mode 100644
index 78f58d5..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.scriptsupport;
-
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
-
-/**
- * Extends InstrumentationTestRunner to allow the script to pass arguments to the application
- */
-public class ScriptTestRunner extends InstrumentationTestRunner {
-    String mTestsRelativePath;
-
-    @Override
-    public void onCreate(Bundle arguments) {
-        mTestsRelativePath = arguments.getString("path");
-        super.onCreate(arguments);
-    }
-
-    public String getTestsRelativePath() {
-        return mTestsRelativePath;
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java
deleted file mode 100644
index 6f41a0f..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.scriptsupport;
-
-import android.content.Intent;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import com.android.dumprendertree2.TestsListActivity;
-import com.android.dumprendertree2.forwarder.ForwarderManager;
-
-/**
- * A class which provides methods that can be invoked by a script running on the host machine to
- * run the tests.
- *
- * It starts a TestsListActivity and does not return until all the tests finish executing.
- */
-public class Starter extends ActivityInstrumentationTestCase2<TestsListActivity> {
-    private static final String LOG_TAG = "Starter";
-    private boolean mEverythingFinished;
-
-    public Starter() {
-        super(TestsListActivity.class);
-    }
-
-    /**
-     * This method is called from adb to start executing the tests. It doesn't return
-     * until everything is finished so that the script can wait for the end if it needs
-     * to.
-     */
-    public void startLayoutTests() {
-        ScriptTestRunner runner = (ScriptTestRunner)getInstrumentation();
-        String relativePath = runner.getTestsRelativePath();
-
-        ForwarderManager.getForwarderManager().start();
-
-        Intent intent = new Intent();
-        intent.setClassName("com.android.dumprendertree2", "TestsListActivity");
-        intent.setAction(Intent.ACTION_RUN);
-        intent.putExtra(TestsListActivity.EXTRA_TEST_PATH, relativePath);
-        setActivityIntent(intent);
-        getActivity().registerOnEverythingFinishedCallback(new OnEverythingFinishedCallback() {
-            /** This method is safe to call on any thread */
-            @Override
-            public void onFinished() {
-                synchronized (Starter.this) {
-                    mEverythingFinished = true;
-                    Starter.this.notifyAll();
-                }
-            }
-        });
-
-        synchronized (this) {
-            while (!mEverythingFinished) {
-                try {
-                    this.wait();
-                } catch (InterruptedException e) {
-                    Log.e(LOG_TAG, "startLayoutTests()", e);
-                }
-            }
-        }
-
-        ForwarderManager.getForwarderManager().stop();
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
deleted file mode 100644
index 5de69a7..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Copyright (C) 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
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2.ui;
-
-import com.android.dumprendertree2.FileFilter;
-import com.android.dumprendertree2.FsUtils;
-import com.android.dumprendertree2.TestsListActivity;
-import com.android.dumprendertree2.R;
-import com.android.dumprendertree2.forwarder.ForwarderManager;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An Activity that allows navigating through tests folders and choosing folders or tests to run.
- */
-public class DirListActivity extends ListActivity {
-
-    private static final String LOG_TAG = "DirListActivity";
-
-    /** TODO: This is just a guess - think of a better way to achieve it */
-    private static final int MEAN_TITLE_CHAR_SIZE = 13;
-
-    private static final int PROGRESS_DIALOG_DELAY_MS = 200;
-
-    /** Code for the dialog, used in showDialog and onCreateDialog */
-    private static final int DIALOG_RUN_ABORT_DIR = 0;
-
-    /** Messages codes */
-    private static final int MSG_LOADED_ITEMS = 0;
-    private static final int MSG_SHOW_PROGRESS_DIALOG = 1;
-
-    private static final CharSequence NO_RESPONSE_MESSAGE =
-            "No response from host when getting directory contents. Is the host server running?";
-
-    /** Initialized lazily before first sProgressDialog.show() */
-    private static ProgressDialog sProgressDialog;
-
-    private ListView mListView;
-
-    /** This is a relative path! */
-    private String mCurrentDirPath;
-
-    /**
-     * A thread responsible for loading the contents of the directory from sd card
-     * and sending them via Message to main thread that then loads them into
-     * ListView
-     */
-    private class LoadListItemsThread extends Thread {
-        private Handler mHandler;
-        private String mRelativePath;
-
-        public LoadListItemsThread(String relativePath, Handler handler) {
-            mRelativePath = relativePath;
-            mHandler = handler;
-        }
-
-        @Override
-        public void run() {
-            Message msg = mHandler.obtainMessage(MSG_LOADED_ITEMS);
-            msg.obj = getDirList(mRelativePath);
-            mHandler.sendMessage(msg);
-        }
-    }
-
-    /**
-     * Very simple object to use inside ListView as an item.
-     */
-    private static class ListItem implements Comparable<ListItem> {
-        private String mRelativePath;
-        private String mName;
-        private boolean mIsDirectory;
-
-        public ListItem(String relativePath, boolean isDirectory) {
-            mRelativePath = relativePath;
-            mName = new File(relativePath).getName();
-            mIsDirectory = isDirectory;
-        }
-
-        public boolean isDirectory() {
-            return mIsDirectory;
-        }
-
-        public String getRelativePath() {
-            return mRelativePath;
-        }
-
-        public String getName() {
-            return mName;
-        }
-
-        @Override
-        public int compareTo(ListItem another) {
-            return mRelativePath.compareTo(another.getRelativePath());
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (!(o instanceof ListItem)) {
-                return false;
-            }
-
-            return mRelativePath.equals(((ListItem)o).getRelativePath());
-        }
-
-        @Override
-        public int hashCode() {
-            return mRelativePath.hashCode();
-        }
-
-    }
-
-    /**
-     * A custom adapter that sets the proper icon and label in the list view.
-     */
-    private static class DirListAdapter extends ArrayAdapter<ListItem> {
-        private Activity mContext;
-        private ListItem[] mItems;
-
-        public DirListAdapter(Activity context, ListItem[] items) {
-            super(context, R.layout.dirlist_row, items);
-
-            mContext = context;
-            mItems = items;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            LayoutInflater inflater = mContext.getLayoutInflater();
-            View row = inflater.inflate(R.layout.dirlist_row, null);
-
-            TextView label = (TextView)row.findViewById(R.id.label);
-            label.setText(mItems[position].getName());
-
-            ImageView icon = (ImageView)row.findViewById(R.id.icon);
-            if (mItems[position].isDirectory()) {
-                icon.setImageResource(R.drawable.folder);
-            } else {
-                icon.setImageResource(R.drawable.runtest);
-            }
-
-            return row;
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        ForwarderManager.getForwarderManager().start();
-
-        mListView = getListView();
-
-        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                ListItem item = (ListItem)parent.getItemAtPosition(position);
-
-                if (item.isDirectory()) {
-                    showDir(item.getRelativePath());
-                } else {
-                    /** Run the test */
-                    runAllTestsUnder(item.getRelativePath());
-                }
-            }
-        });
-
-        mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
-            @Override
-            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
-                ListItem item = (ListItem)parent.getItemAtPosition(position);
-
-                if (item.isDirectory()) {
-                    Bundle arguments = new Bundle(1);
-                    arguments.putString("name", item.getName());
-                    arguments.putString("relativePath", item.getRelativePath());
-                    showDialog(DIALOG_RUN_ABORT_DIR, arguments);
-                } else {
-                    /** TODO: Maybe show some info about a test? */
-                }
-
-                return true;
-            }
-        });
-
-        /** All the paths are relative to test root dir where possible */
-        showDir("");
-    }
-
-    private void runAllTestsUnder(String relativePath) {
-        Intent intent = new Intent();
-        intent.setClass(DirListActivity.this, TestsListActivity.class);
-        intent.setAction(Intent.ACTION_RUN);
-        intent.putExtra(TestsListActivity.EXTRA_TEST_PATH, relativePath);
-        startActivity(intent);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.gui_menu, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.run_all:
-                runAllTestsUnder(mCurrentDirPath);
-                return true;
-            default:
-                return super.onOptionsItemSelected(item);
-        }
-    }
-
-    @Override
-    /**
-     * Moves to the parent directory if one exists. Does not allow to move above
-     * the test 'root' directory.
-     */
-    public void onBackPressed() {
-        File currentDirParent = new File(mCurrentDirPath).getParentFile();
-        if (currentDirParent != null) {
-            showDir(currentDirParent.getPath());
-        } else {
-            showDir("");
-        }
-    }
-
-    /**
-     * Prevents the activity from recreating on change of orientation. The title needs to
-     * be recalculated.
-     */
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-
-        setTitle(shortenTitle(mCurrentDirPath));
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id, final Bundle args) {
-        Dialog dialog = null;
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-
-        switch (id) {
-            case DIALOG_RUN_ABORT_DIR:
-                builder.setTitle(getText(R.string.dialog_run_abort_dir_title_prefix) + " " +
-                        args.getString("name"));
-                builder.setMessage(R.string.dialog_run_abort_dir_msg);
-                builder.setCancelable(true);
-
-                builder.setPositiveButton(R.string.dialog_run_abort_dir_ok_button,
-                        new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        removeDialog(DIALOG_RUN_ABORT_DIR);
-                        runAllTestsUnder(args.getString("relativePath"));
-                    }
-                });
-
-                builder.setNegativeButton(R.string.dialog_run_abort_dir_abort_button,
-                        new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        removeDialog(DIALOG_RUN_ABORT_DIR);
-                    }
-                });
-
-                dialog = builder.create();
-                dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-                    @Override
-                    public void onCancel(DialogInterface dialog) {
-                        removeDialog(DIALOG_RUN_ABORT_DIR);
-                    }
-                });
-                break;
-        }
-
-        return dialog;
-    }
-
-    /**
-     * Loads the contents of dir into the list view.
-     *
-     * @param dirPath
-     *      directory to load into list view
-     */
-    private void showDir(String dirPath) {
-        mCurrentDirPath = dirPath;
-
-        /** Show progress dialog with a delay */
-        final Handler delayedDialogHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_SHOW_PROGRESS_DIALOG) {
-                    if (sProgressDialog == null) {
-                        sProgressDialog = new ProgressDialog(DirListActivity.this);
-                        sProgressDialog.setCancelable(false);
-                        sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
-                        sProgressDialog.setTitle(R.string.dialog_progress_title);
-                        sProgressDialog.setMessage(getText(R.string.dialog_progress_msg));
-                    }
-                    sProgressDialog.show();
-                }
-            }
-        };
-        Message msgShowDialog = delayedDialogHandler.obtainMessage(MSG_SHOW_PROGRESS_DIALOG);
-        delayedDialogHandler.sendMessageDelayed(msgShowDialog, PROGRESS_DIALOG_DELAY_MS);
-
-        /** Delegate loading contents from SD card to a new thread */
-        new LoadListItemsThread(mCurrentDirPath, new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_LOADED_ITEMS) {
-                    setTitle(shortenTitle(mCurrentDirPath));
-                    delayedDialogHandler.removeMessages(MSG_SHOW_PROGRESS_DIALOG);
-                    if (sProgressDialog != null) {
-                        sProgressDialog.dismiss();
-                    }
-                    if (msg.obj == null) {
-                        Toast.makeText(DirListActivity.this, NO_RESPONSE_MESSAGE,
-                                Toast.LENGTH_LONG).show();
-                    } else {
-                        setListAdapter(new DirListAdapter(DirListActivity.this,
-                                (ListItem[])msg.obj));
-                    }
-                }
-            }
-        }).start();
-    }
-
-    /**
-     * TODO: find a neat way to determine number of characters that fit in the title
-     * bar.
-     * */
-    private String shortenTitle(String title) {
-        if (title.equals("")) {
-            return "Tests' root dir:";
-        }
-        int charCount = mListView.getWidth() / MEAN_TITLE_CHAR_SIZE;
-
-        if (title.length() > charCount) {
-            return "..." + title.substring(title.length() - charCount);
-        } else {
-            return title;
-        }
-    }
-
-    /**
-     * Return the array with contents of the given directory.
-     * First it contains the subfolders, then the files. Both sorted
-     * alphabetically.
-     *
-     * The dirPath is relative.
-     */
-    private ListItem[] getDirList(String dirPath) {
-        List<ListItem> subDirs = new ArrayList<ListItem>();
-        List<ListItem> subFiles = new ArrayList<ListItem>();
-
-        List<String> dirRelativePaths = FsUtils.getLayoutTestsDirContents(dirPath, false, true);
-        if (dirRelativePaths == null) {
-            return null;
-        }
-        for (String dirRelativePath : dirRelativePaths) {
-            if (FileFilter.isTestDir(new File(dirRelativePath).getName())) {
-                subDirs.add(new ListItem(dirRelativePath, true));
-            }
-        }
-
-        List<String> testRelativePaths = FsUtils.getLayoutTestsDirContents(dirPath, false, false);
-        if (testRelativePaths == null) {
-            return null;
-        }
-        for (String testRelativePath : testRelativePaths) {
-            if (FileFilter.isTestFile(new File(testRelativePath).getName())) {
-                subFiles.add(new ListItem(testRelativePath, false));
-            }
-        }
-
-        /** Concatenate the two lists */
-        subDirs.addAll(subFiles);
-
-        return subDirs.toArray(new ListItem[subDirs.size()]);
-    }
-}
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java
index 5f4f006..309ce34 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java
@@ -21,7 +21,11 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.lang.String;
+import java.util.HashMap;
+import java.util.Random;
 
+import android.util.ArrayMap;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -142,6 +146,18 @@
             new LoadRecycleLargeBitmapOp(),
             new LoadSmallScaledBitmapOp(),
             new LoadLargeScaledBitmapOp(),
+            new GrowTinyHashMapOp(),
+            new GrowTinyArrayMapOp(),
+            new GrowSmallHashMapOp(),
+            new GrowSmallArrayMapOp(),
+            new GrowLargeHashMapOp(),
+            new GrowLargeArrayMapOp(),
+            new LookupTinyHashMapOp(),
+            new LookupTinyArrayMapOp(),
+            new LookupSmallHashMapOp(),
+            new LookupSmallArrayMapOp(),
+            new LookupLargeHashMapOp(),
+            new LookupLargeArrayMapOp(),
     };
 
     static final int CMD_START_TEST = 1;
@@ -1111,4 +1127,196 @@
             mFile.delete();
         }
     }
+
+    static abstract class GenericMapOp extends Op {
+        final int mSize;
+        String[] mKeys;
+        String[] mValues;
+
+        GenericMapOp(String name, String longName, int size) {
+            super(name, longName);
+            mSize = size;
+        }
+
+        void onInit(Context context, boolean foreground) {
+            mKeys = new String[mSize];
+            mValues = new String[mSize];
+            Random random = new Random(0);
+            for (int i=0; i<mSize; i++) {
+                int chars = random.nextInt(10);
+                StringBuilder builder = new StringBuilder(chars);
+                for (int j=0; j<chars; j++) {
+                    builder.append('a' + random.nextInt(100));
+                }
+                mKeys[i] = builder.toString();
+                mValues[i] = Integer.toString(i);
+            }
+        }
+
+        int getOpsPerRun() {
+            return mSize;
+        }
+    }
+
+    static class GrowTinyHashMapOp extends GenericMapOp {
+        GrowTinyHashMapOp() {
+            super("GrowTinyHashMap", "Add 5 items to a HashMap", 5);
+        }
+
+        boolean onRun() {
+            HashMap<String, String> map = new HashMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                map.put(mKeys[i], mValues[i]);
+            }
+            return true;
+        }
+    }
+
+    static class GrowTinyArrayMapOp extends GenericMapOp {
+        GrowTinyArrayMapOp() {
+            super("GrowTinyArrayMap", "Add 5 items to a ArrayMap", 5);
+        }
+
+        boolean onRun() {
+            ArrayMap<String, String> map = new ArrayMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                map.put(mKeys[i], mValues[i]);
+            }
+            return true;
+        }
+    }
+
+    static class GrowSmallHashMapOp extends GenericMapOp {
+        GrowSmallHashMapOp() {
+            super("GrowSmallHashMap", "Add 100 items to a HashMap", 100);
+        }
+
+        boolean onRun() {
+            HashMap<String, String> map = new HashMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                map.put(mKeys[i], mValues[i]);
+            }
+            return true;
+        }
+    }
+
+    static class GrowSmallArrayMapOp extends GenericMapOp {
+        GrowSmallArrayMapOp() {
+            super("GrowSmallArrayMap", "Add 100 items to a ArrayMap", 100);
+        }
+
+        boolean onRun() {
+            ArrayMap<String, String> map = new ArrayMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                map.put(mKeys[i], mValues[i]);
+            }
+            return true;
+        }
+    }
+
+    static class GrowLargeHashMapOp extends GenericMapOp {
+        GrowLargeHashMapOp() {
+            super("GrowLargeHashMap", "Add 10000 items to a HashMap", 10000);
+        }
+
+        boolean onRun() {
+            HashMap<String, String> map = new HashMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                map.put(mKeys[i], mValues[i]);
+            }
+            return true;
+        }
+    }
+
+    static class GrowLargeArrayMapOp extends GenericMapOp {
+        GrowLargeArrayMapOp() {
+            super("GrowLargeArrayMap", "Add 10000 items to a ArrayMap", 10000);
+        }
+
+        boolean onRun() {
+            ArrayMap<String, String> map = new ArrayMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                map.put(mKeys[i], mValues[i]);
+            }
+            return true;
+        }
+    }
+
+    static class LookupTinyHashMapOp extends LookupSmallHashMapOp {
+        LookupTinyHashMapOp() {
+            super("LookupTinyHashMap", "Lookup items in 5 entry HashMap", 5);
+        }
+    }
+
+    static class LookupTinyArrayMapOp extends LookupSmallArrayMapOp {
+        LookupTinyArrayMapOp() {
+            super("LookupTinyArrayMap", "Lookup items in 5 entry ArrayMap", 5);
+        }
+    }
+
+    static class LookupSmallHashMapOp extends GenericMapOp {
+        HashMap<String, String> mHashMap;
+
+        LookupSmallHashMapOp() {
+            super("LookupSmallHashMap", "Lookup items in 100 entry HashMap", 100);
+        }
+
+        LookupSmallHashMapOp(String name, String longname, int size) {
+            super(name, longname, size);
+        }
+
+        void onInit(Context context, boolean foreground) {
+            super.onInit(context, foreground);
+            mHashMap = new HashMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                mHashMap.put(mKeys[i], mValues[i]);
+            }
+        }
+
+        boolean onRun() {
+            for (int i=0; i<mSize; i++) {
+                mHashMap.get(mKeys[i]);
+            }
+            return true;
+        }
+    }
+
+    static class LookupSmallArrayMapOp extends GenericMapOp {
+        ArrayMap<String, String> mArrayMap;
+
+        LookupSmallArrayMapOp() {
+            super("LookupSmallArrayMap", "Lookup items in 100 entry ArrayMap", 100);
+        }
+
+        LookupSmallArrayMapOp(String name, String longname, int size) {
+            super(name, longname, size);
+        }
+
+        void onInit(Context context, boolean foreground) {
+            super.onInit(context, foreground);
+            mArrayMap = new ArrayMap<String, String>();
+            for (int i=0; i<mSize; i++) {
+                mArrayMap.put(mKeys[i], mValues[i]);
+            }
+        }
+
+        boolean onRun() {
+            for (int i=0; i<mSize; i++) {
+                mArrayMap.get(mKeys[i]);
+            }
+            return true;
+        }
+    }
+
+    static class LookupLargeHashMapOp extends LookupSmallHashMapOp {
+        LookupLargeHashMapOp() {
+            super("LookupLargeHashMap", "Lookup items in 10000 entry HashMap", 10000);
+        }
+    }
+
+    static class LookupLargeArrayMapOp extends LookupSmallArrayMapOp {
+        LookupLargeArrayMapOp() {
+            super("LookupLargeArrayMap", "Lookup items in 10000 entry ArrayMap", 10000);
+        }
+    }
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 46a539e..1bb0db0 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -41,6 +41,26 @@
         </activity>
 
         <activity
+                android:name="PathOpsActivity"
+                android:label="Path/Ops"
+                android:theme="@android:style/Theme.Holo.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity
+                android:name="AssetsAtlasActivity"
+                android:label="Atlas/Framework"
+                android:theme="@android:style/Theme.Holo.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="ScaledTextActivity"
                 android:label="Text/Scaled"
                 android:theme="@android:style/Theme.Holo.Light">
@@ -725,7 +745,7 @@
                 android:name="PathsCacheActivity"
                 android:label="Path/Cache">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.MAIN" />`
                 <category android:name="com.android.test.hwui.TEST" />
             </intent-filter>
         </activity>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java
new file mode 100644
index 0000000..df7e3bb
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import com.android.internal.R;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class AssetsAtlasActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(new BitmapsView(this));
+    }
+
+    static class BitmapsView extends View {
+        private final Bitmap mBitmap;
+
+        BitmapsView(Context c) {
+            super(c);
+
+            Drawable d = c.getResources().getDrawable(R.drawable.text_select_handle_left);
+            mBitmap = ((BitmapDrawable) d).getBitmap();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            final Matrix matrix = new Matrix();
+            matrix.setScale(0.5f, 0.5f);
+
+            final Rect src = new Rect(0, 0, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);
+            final Rect dst = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+
+            canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+            canvas.translate(0.0f, mBitmap.getHeight());
+            canvas.drawBitmap(mBitmap, matrix, null);
+            canvas.translate(0.0f, mBitmap.getHeight());
+            canvas.drawBitmap(mBitmap, src, dst, null);
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
index 066e35c..fe4d602 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
@@ -48,7 +48,7 @@
     }
 
     public static class RegionView extends FrameLayout {
-        private final Region mRegion = new Region();
+        private Region mRegion = new Region();
         private float mClipPosition = 0.0f;
 
         public RegionView(Context c) {
@@ -69,9 +69,7 @@
 
             canvas.save();
 
-            mRegion.setEmpty();
-            mRegion.op(0, 0, getWidth(), getHeight(),
-                    Region.Op.REPLACE);
+            mRegion.set(0, 0, getWidth(), getHeight());
             mRegion.op(getWidth() / 4, getHeight() / 4, 3 * getWidth() / 4, 3 * getHeight() / 4,
                     Region.Op.DIFFERENCE);
 
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
index 13b6129..db6421e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
@@ -20,19 +20,15 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Bundle;
-import android.os.Environment;
 import android.util.DisplayMetrics;
 import android.view.ContextMenu;
 import android.view.View;
-import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
 
-import java.io.File;
-
 @SuppressWarnings({"UnusedDeclaration"})
 public class ListActivity extends Activity {
     private static final String[] DATA_LIST = {
@@ -86,7 +82,7 @@
 
         ListAdapter adapter = new SimpleListAdapter(this);
 
-        ListView list = (ListView) findViewById(R.id.list);
+        final ListView list = (ListView) findViewById(R.id.list);
         list.setAdapter(adapter);
         
         registerForContextMenu(list);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
new file mode 100644
index 0000000..b9927ac
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class PathOpsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final PathsView view = new PathsView(this);
+        setContentView(view);
+    }
+
+    public static class PathsView extends View {
+        private final Paint mPaint;
+        private Path[] mPaths;
+        private float mSize;
+
+
+        public PathsView(Context c) {
+            super(c);
+
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+            mPaint.setStyle(Paint.Style.FILL);
+            mPaint.setColor(Color.RED);
+        }
+
+        @Override
+        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+            super.onSizeChanged(w, h, oldw, oldh);
+
+            Path.Op[] ops = Path.Op.values();
+            mPaths = new Path[ops.length];
+
+            mSize = w / (ops.length * 2.0f);
+
+            Path p1 = new Path();
+            p1.addRect(0.0f, 0.0f, mSize, mSize, Path.Direction.CW);
+
+            Path p2 = new Path();
+            p2.addCircle(mSize, mSize, mSize / 2.0f, Path.Direction.CW);
+
+            for (int i = 0; i < ops.length; i++) {
+                mPaths[i] = new Path();
+                if (!mPaths[i].op(p1, p2, ops[i])) {
+                    Log.d("PathOps", ops[i].name() + " failed!");
+                }
+            }
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.translate(mSize * 0.2f, getHeight() / 2.0f);
+            for (Path path : mPaths) {
+                canvas.drawPath(path, mPaint);
+                canvas.translate(mSize * 1.8f, 0.0f);
+            }
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
index 9f97311..c1e7f4a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
@@ -88,8 +88,6 @@
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
-            
-            Log.d("OpenGLRenderer", "Start frame");
 
             canvas.drawARGB(255, 255, 255, 255);
 
@@ -104,6 +102,13 @@
             canvas.drawPath(mPath, mMediumPaint);
             canvas.drawPath(mPath, mMediumPaint);
 
+            mPath.reset();
+            buildPath(mPath);
+
+            canvas.translate(30.0f, 30.0f);
+            canvas.drawPath(mPath, mMediumPaint);
+            canvas.drawPath(mPath, mMediumPaint);
+
             canvas.restore();
 
             for (int i = 0; i < mRandom.nextInt(20); i++) {
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
index ba09421..98cec55 100644
--- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
@@ -20,7 +20,7 @@
 import java.util.ArrayList;
 import java.util.concurrent.Semaphore;
 
-import android.renderscript.RSTextureView;
+import android.renderscript.RSSurfaceView;
 import android.renderscript.RenderScript;
 import android.renderscript.RenderScriptGL;
 
@@ -39,7 +39,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
-public class FountainView extends RSTextureView {
+public class FountainView extends RSSurfaceView {
 
     public FountainView(Context context) {
         super(context);
@@ -49,13 +49,12 @@
     private RenderScriptGL mRS;
     private FountainRS mRender;
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        android.util.Log.e("rs", "onAttachedToWindow");
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
         if (mRS == null) {
             RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
             mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
             mRender = new FountainRS();
             mRender.init(mRS, getResources());
         }
@@ -63,8 +62,6 @@
 
     @Override
     protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        android.util.Log.e("rs", "onDetachedFromWindow");
         if (mRS != null) {
             mRS = null;
             destroyRenderScriptGL();
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
index 6e40da3..8636717 100644
--- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
@@ -17,12 +17,13 @@
 package com.example.android.rs.fountainfbo;
 
 
-import android.renderscript.RSTextureView;
+import android.renderscript.RSSurfaceView;
 import android.renderscript.RenderScriptGL;
 import android.content.Context;
+import android.view.SurfaceHolder;
 import android.view.MotionEvent;
 
-public class FountainFboView extends RSTextureView {
+public class FountainFboView extends RSSurfaceView {
 
     public FountainFboView(Context context) {
         super(context);
@@ -31,13 +32,12 @@
     private RenderScriptGL mRS;
     private FountainFboRS mRender;
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        android.util.Log.e("rs", "onAttachedToWindow");
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
         if (mRS == null) {
             RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
             mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
             mRender = new FountainFboRS();
             mRender.init(mRS, getResources());
         }
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
deleted file mode 100644
index 5763ad3..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
-
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-import android.webkit.WebSettings;
-import android.widget.Spinner;
-
-public class PerformanceTest extends
-        ActivityInstrumentationTestCase2<ProfileActivity> {
-
-    public static class AnimStat {
-        double aggVal = 0;
-        double aggSqrVal = 0;
-        double count = 0;
-    }
-
-    private class StatAggregator extends PlaybackGraphs {
-        private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
-        private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>();
-        private int mCount = 0;
-
-
-        public void aggregate() {
-            boolean inAnimTests = mAnimTests != null;
-            Resources resources = mWeb.getResources();
-            String animFramerateString = resources.getString(R.string.animation_framerate);
-            for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
-                String name = e.getKey();
-                if (inAnimTests) {
-                    if (name.equals(animFramerateString)) {
-                        // in animation testing phase, record animation framerate and aggregate
-                        // stats, differentiating on values of mAnimTestNr and mDoubleBuffering
-                        String fullName = ANIM_TEST_NAMES[mAnimTestNr] + " " + name;
-                        fullName += mDoubleBuffering ? " tiled" : " webkit";
-
-                        if (!mAnimDataMap.containsKey(fullName)) {
-                            mAnimDataMap.put(fullName, new AnimStat());
-                        }
-                        AnimStat statVals = mAnimDataMap.get(fullName);
-                        statVals.aggVal += e.getValue();
-                        statVals.aggSqrVal += e.getValue() * e.getValue();
-                        statVals.count += 1;
-                    }
-                } else {
-                    double aggVal = mDataMap.containsKey(name)
-                            ? mDataMap.get(name) : 0;
-                    mDataMap.put(name, aggVal + e.getValue());
-                }
-            }
-
-            if (inAnimTests) {
-                return;
-            }
-
-            mCount++;
-            for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
-                for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                    String metricLabel = resources.getString(
-                            Metrics[metricIndex].getLabelId());
-                    String statLabel = resources.getString(
-                            Stats[statIndex].getLabelId());
-
-                    String label = metricLabel + " " + statLabel;
-                    double aggVal = mDataMap.containsKey(label) ? mDataMap
-                            .get(label) : 0;
-
-                    aggVal += mStats[metricIndex][statIndex];
-                    mDataMap.put(label, aggVal);
-                }
-            }
-
-        }
-
-        // build the final bundle of results
-        public Bundle getBundle() {
-            Bundle b = new Bundle();
-            int count = (0 == mCount) ? Integer.MAX_VALUE : mCount;
-            for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
-                b.putDouble(e.getKey(), e.getValue() / count);
-            }
-
-            for (Map.Entry<String, AnimStat> e : mAnimDataMap.entrySet()) {
-                String statName = e.getKey();
-                AnimStat statVals = e.getValue();
-
-                double avg = statVals.aggVal/statVals.count;
-                double stdDev = Math.sqrt((statVals.aggSqrVal / statVals.count) - avg * avg);
-
-                b.putDouble(statName, avg);
-                b.putDouble(statName + " STD DEV", stdDev);
-            }
-
-            return b;
-        }
-    }
-
-    ProfileActivity mActivity;
-    ProfiledWebView mWeb;
-    Spinner mMovementSpinner;
-    StatAggregator mStats;
-
-    private static final String LOGTAG = "PerformanceTest";
-    private static final String TEST_LOCATION = "webkit/page_cycler";
-    private static final String URL_PREFIX = "file://";
-    private static final String URL_POSTFIX = "/index.html?skip=true";
-    private static final int MAX_ITERATIONS = 4;
-    private static final String SCROLL_TEST_DIRS[] = {
-        "alexa25_2011"
-    };
-    private static final String ANIM_TEST_DIRS[] = {
-        "dhtml"
-    };
-
-    public PerformanceTest() {
-        super(ProfileActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mWeb = (ProfiledWebView) mActivity.findViewById(R.id.web);
-        mMovementSpinner = (Spinner) mActivity.findViewById(R.id.movement);
-        mStats = new StatAggregator();
-
-        // use mStats as a condition variable between the UI thread and
-        // this(the testing) thread
-        mActivity.setCallback(new ProfileCallback() {
-            @Override
-            public void profileCallback(RunData data) {
-                mStats.setData(data);
-                synchronized (mStats) {
-                    mStats.notify();
-                }
-            }
-        });
-
-    }
-
-    private boolean loadUrl(final String url) {
-        try {
-            Log.d(LOGTAG, "test starting for url " + url);
-            mActivity.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mWeb.loadUrl(url);
-                }
-            });
-            synchronized (mStats) {
-                mStats.wait();
-            }
-
-            mStats.aggregate();
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-            return false;
-        }
-        return true;
-    }
-
-    private boolean validTest(String nextTest) {
-        // if testing animations, test must be in mAnimTests
-        if (mAnimTests == null)
-            return true;
-
-        for (String test : mAnimTests) {
-            if (test.equals(nextTest)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean runIteration(String[] testDirs) {
-        File sdFile = Environment.getExternalStorageDirectory();
-        for (String testDirName : testDirs) {
-            File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
-            Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
-                    + "', exists=" + testDir.exists());
-
-            for (File siteDir : testDir.listFiles()) {
-                if (!siteDir.isDirectory() || !validTest(siteDir.getName())) {
-                    continue;
-                }
-
-                if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
-                        + URL_POSTFIX)) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    private boolean  runTestDirs(String[] testDirs) {
-        for (int i = 0; i < MAX_ITERATIONS; i++)
-            if (!runIteration(testDirs)) {
-                return false;
-            }
-        return true;
-    }
-
-    private void pushDoubleBuffering() {
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                mWeb.setDoubleBuffering(mDoubleBuffering);
-            }
-        });
-    }
-
-    private void setScrollingTestingMode(final boolean scrolled) {
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                mMovementSpinner.setSelection(scrolled ? 0 : 2);
-            }
-        });
-    }
-
-
-    private String[] mAnimTests = null;
-    private int mAnimTestNr = -1;
-    private boolean mDoubleBuffering = true;
-    private static final String[] ANIM_TEST_NAMES = {
-        "slow", "fast"
-    };
-    private static final String[][] ANIM_TESTS = {
-        {"scrolling", "replaceimages", "layers5", "layers1"},
-        {"slidingballs", "meter", "slidein", "fadespacing", "colorfade",
-                "mozilla", "movingtext", "diagball", "zoom", "imageslide"},
-    };
-
-    private boolean checkMedia() {
-        String state = Environment.getExternalStorageState();
-
-        if (!Environment.MEDIA_MOUNTED.equals(state)
-                && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
-            Log.d(LOGTAG, "ARG Can't access sd card!");
-            // Can't read the SD card, fail and die!
-            getInstrumentation().sendStatus(1, null);
-            return false;
-        }
-        return true;
-    }
-
-    public void testMetrics() {
-        setScrollingTestingMode(true);
-        if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) {
-            getInstrumentation().sendStatus(0, mStats.getBundle());
-        } else {
-            getInstrumentation().sendStatus(1, null);
-        }
-    }
-
-    public void testMetricsMinimalMemory() {
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWeb.setUseMinimalMemory(true);
-            }
-        });
-
-        setScrollingTestingMode(true);
-        if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) {
-            getInstrumentation().sendStatus(0, mStats.getBundle());
-        } else {
-            getInstrumentation().sendStatus(1, null);
-        }
-    }
-
-    private boolean runAnimationTests() {
-        for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) {
-            mDoubleBuffering = doubleBuffer == 1;
-            pushDoubleBuffering();
-            for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) {
-                mAnimTests = ANIM_TESTS[mAnimTestNr];
-                if (!runTestDirs(ANIM_TEST_DIRS)) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    public void testAnimations() {
-        // instead of autoscrolling, load each page until either an timer fires,
-        // or the animation signals complete via javascript
-        setScrollingTestingMode(false);
-
-        if (checkMedia() && runAnimationTests()) {
-            getInstrumentation().sendStatus(0, mStats.getBundle());
-        } else {
-            getInstrumentation().sendStatus(1, null);
-        }
-    }
-}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
deleted file mode 100644
index 1eb1c00..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import android.app.Activity;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-
-/**
- * Interface for playing back WebView tile rendering status. Draws viewport and
- * states of tiles and statistics for off-line analysis.
- */
-public class PlaybackActivity extends Activity {
-    private static final float SCROLL_SCALER = 0.125f;
-
-    PlaybackView mPlaybackView;
-    SeekBar mSeekBar;
-    Button mForward;
-    Button mBackward;
-    TextView mFrameDisplay;
-
-    private int mFrame = -1;
-    private int mFrameMax;
-
-    private class TouchFrameChangeListener extends SimpleOnGestureListener {
-        float mDist = 0;
-
-        @Override
-        public boolean onScroll(MotionEvent e1, MotionEvent e2,
-                float distanceX, float distanceY) {
-            // aggregate scrolls so that small ones can add up
-            mDist += distanceY * SCROLL_SCALER;
-            int intComponent = (int) Math.floor(Math.abs(mDist));
-            if (intComponent >= 1) {
-                int scrollDist = (mDist > 0) ? intComponent : -intComponent;
-                setFrame(null, mFrame + scrollDist);
-                mDist -= scrollDist;
-            }
-            return super.onScroll(e1, e2, distanceX, distanceY);
-        }
-    };
-
-    private class SeekFrameChangeListener implements OnSeekBarChangeListener {
-        @Override
-        public void onStopTrackingTouch(SeekBar seekBar) {
-        }
-
-        @Override
-        public void onStartTrackingTouch(SeekBar seekBar) {
-        }
-
-        @Override
-        public void onProgressChanged(SeekBar seekBar, int progress,
-                boolean fromUser) {
-            setFrame(seekBar, progress);
-        }
-    };
-
-    private class LoadFileTask extends AsyncTask<String, Void, RunData> {
-        @Override
-        protected RunData doInBackground(String... params) {
-            RunData data = null;
-            try {
-                FileInputStream fis = openFileInput(params[0]);
-                ObjectInputStream in = new ObjectInputStream(fis);
-                data = (RunData) in.readObject();
-                in.close();
-            } catch (IOException ex) {
-                ex.printStackTrace();
-            } catch (ClassNotFoundException ex) {
-                ex.printStackTrace();
-            }
-            return data;
-        }
-
-        @Override
-        protected void onPostExecute(RunData data) {
-            if (data == null) {
-                Toast.makeText(getApplicationContext(),
-                        getResources().getString(R.string.error_no_data),
-                        Toast.LENGTH_LONG).show();
-                return;
-            }
-            mPlaybackView.setData(data);
-
-            mFrameMax = data.frames.length - 1;
-            mSeekBar.setMax(mFrameMax);
-
-            setFrame(null, 0);
-        }
-    }
-
-    private void setFrame(View changer, int f) {
-        if (f < 0) {
-            f = 0;
-        } else if (f > mFrameMax) {
-            f = mFrameMax;
-        }
-
-        if (mFrame == f) {
-            return;
-        }
-
-        mFrame = f;
-        mForward.setEnabled(mFrame != mFrameMax);
-        mBackward.setEnabled(mFrame != 0);
-        if (changer != mSeekBar) {
-            mSeekBar.setProgress(mFrame);
-        }
-        mFrameDisplay.setText(Integer.toString(mFrame));
-        mPlaybackView.setFrame(mFrame);
-    };
-
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.playback);
-
-        mPlaybackView = (PlaybackView) findViewById(R.id.playback);
-        mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
-        mForward = (Button) findViewById(R.id.forward);
-        mBackward = (Button) findViewById(R.id.backward);
-        mFrameDisplay = (TextView) findViewById(R.id.frame_display);
-
-        mForward.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setFrame(v, mFrame + 1);
-            }
-        });
-
-        mBackward.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setFrame(v, mFrame - 1);
-            }
-        });
-
-        mSeekBar.setOnSeekBarChangeListener(new SeekFrameChangeListener());
-
-        mPlaybackView.setOnGestureListener(new TouchFrameChangeListener());
-
-        new LoadFileTask().execute(ProfileActivity.TEMP_FILENAME);
-    }
-}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
deleted file mode 100644
index 065e86f..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.ShapeDrawable;
-
-import com.test.tilebenchmark.RunData.TileData;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-
-public class PlaybackGraphs {
-    private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
-    private static final float CANVAS_SCALE = 0.2f;
-    private static final double IDEAL_FRAMES = 60;
-    private static final int LABELOFFSET = 100;
-    private static Paint whiteLabels;
-
-    private static double viewportCoverage(TileData view, TileData tile) {
-        if (tile.left < (view.right * view.scale)
-                && tile.right >= (view.left * view.scale)
-                && tile.top < (view.bottom * view.scale)
-                && tile.bottom >= (view.top * view.scale)) {
-            return 1.0f;
-        }
-        return 0.0f;
-    }
-
-    protected interface MetricGen {
-        public double getValue(TileData[] frame);
-
-        public double getMax();
-
-        public int getLabelId();
-    };
-
-    protected static MetricGen[] Metrics = new MetricGen[] {
-            new MetricGen() {
-                // framerate graph
-                @Override
-                public double getValue(TileData[] frame) {
-                    int renderTimeUS = frame[0].level;
-                    return 1.0e6f / renderTimeUS;
-                }
-
-                @Override
-                public double getMax() {
-                    return IDEAL_FRAMES;
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.frames_per_second;
-                }
-            }, new MetricGen() {
-                // coverage graph
-                @Override
-                public double getValue(TileData[] frame) {
-                    double total = 0, totalCount = 0;
-                    for (int tileID = 1; tileID < frame.length; tileID++) {
-                        TileData data = frame[tileID];
-                        double coverage = viewportCoverage(frame[0], data);
-                        total += coverage * (data.isReady ? 100 : 0);
-                        totalCount += coverage;
-                    }
-                    if (totalCount == 0) {
-                        return -1;
-                    }
-                    return total / totalCount;
-                }
-
-                @Override
-                public double getMax() {
-                    return 100;
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.viewport_coverage;
-                }
-            }
-    };
-
-    protected interface StatGen {
-        public double getValue(double sortedValues[]);
-
-        public int getLabelId();
-    }
-
-    public static double getPercentile(double sortedValues[], double ratioAbove) {
-        if (sortedValues.length == 0)
-            return -1;
-
-        double index = ratioAbove * (sortedValues.length - 1);
-        int intIndex = (int) Math.floor(index);
-        if (index == intIndex) {
-            return sortedValues[intIndex];
-        }
-        double alpha = index - intIndex;
-        return sortedValues[intIndex] * (1 - alpha)
-                + sortedValues[intIndex + 1] * (alpha);
-    }
-
-    public static double getMean(double sortedValues[]) {
-        if (sortedValues.length == 0)
-            return -1;
-
-        double agg = 0;
-        for (double val : sortedValues) {
-            agg += val;
-        }
-        return agg / sortedValues.length;
-    }
-
-    public static double getStdDev(double sortedValues[]) {
-        if (sortedValues.length == 0)
-            return -1;
-
-        double agg = 0;
-        double sqrAgg = 0;
-        for (double val : sortedValues) {
-            agg += val;
-            sqrAgg += val*val;
-        }
-        double mean = agg / sortedValues.length;
-        return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean));
-    }
-
-    protected static StatGen[] Stats = new StatGen[] {
-            new StatGen() {
-                @Override
-                public double getValue(double[] sortedValues) {
-                    return getPercentile(sortedValues, 0.25);
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.percentile_25;
-                }
-            }, new StatGen() {
-                @Override
-                public double getValue(double[] sortedValues) {
-                    return getPercentile(sortedValues, 0.5);
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.percentile_50;
-                }
-            }, new StatGen() {
-                @Override
-                public double getValue(double[] sortedValues) {
-                    return getPercentile(sortedValues, 0.75);
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.percentile_75;
-                }
-            }, new StatGen() {
-                @Override
-                public double getValue(double[] sortedValues) {
-                    return getStdDev(sortedValues);
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.std_dev;
-                }
-            }, new StatGen() {
-                @Override
-                public double getValue(double[] sortedValues) {
-                    return getMean(sortedValues);
-                }
-
-                @Override
-                public int getLabelId() {
-                    return R.string.mean;
-                }
-            },
-    };
-
-    public PlaybackGraphs() {
-        whiteLabels = new Paint();
-        whiteLabels.setColor(Color.WHITE);
-        whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3);
-    }
-
-    private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
-    protected final double[][] mStats = new double[Metrics.length][Stats.length];
-    protected HashMap<String, Double> mSingleStats;
-
-    private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) {
-        // create graph out of rectangles, one per frame
-        int lastBar = 0;
-        for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
-            TileData frame[] = data.frames[frameIndex];
-            int newBar = (int)((frame[0].top + frame[0].bottom) * frame[0].scale / 2.0f);
-
-            MetricGen s = Metrics[metricIndex];
-            double absoluteValue = s.getValue(frame);
-            double relativeValue = absoluteValue / s.getMax();
-            relativeValue = Math.min(1,relativeValue);
-            relativeValue = Math.max(0,relativeValue);
-            int rightPos = (int) (-BAR_WIDTH * metricIndex);
-            int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
-
-            ShapeDrawable graphBar = new ShapeDrawable();
-            graphBar.getPaint().setColor(Color.BLUE);
-            graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
-
-            mShapes.add(graphBar);
-            metricValues[frameIndex] = absoluteValue;
-            lastBar = newBar;
-        }
-    }
-
-    public void setData(RunData data) {
-        mShapes.clear();
-        double metricValues[] = new double[data.frames.length];
-
-        mSingleStats = data.singleStats;
-
-        if (data.frames.length == 0) {
-            return;
-        }
-
-        for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
-            // calculate metric based on list of frames
-            gatherFrameMetric(metricIndex, metricValues, data);
-
-            // store aggregate statistics per metric (median, and similar)
-            Arrays.sort(metricValues);
-            for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                mStats[metricIndex][statIndex] =
-                        Stats[statIndex].getValue(metricValues);
-            }
-        }
-    }
-
-    public void drawVerticalShiftedShapes(Canvas canvas,
-            ArrayList<ShapeDrawable> shapes) {
-        // Shapes drawn here are drawn relative to the viewRect
-        Rect viewRect = shapes.get(shapes.size() - 1).getBounds();
-        canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top);
-
-        for (ShapeDrawable shape : mShapes) {
-            shape.draw(canvas);
-        }
-        for (ShapeDrawable shape : shapes) {
-            shape.draw(canvas);
-        }
-    }
-
-    public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
-            ArrayList<String> strings, Resources resources) {
-        canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
-
-        canvas.translate(BAR_WIDTH * Metrics.length, 0);
-
-        canvas.save();
-        drawVerticalShiftedShapes(canvas, shapes);
-        canvas.restore();
-
-        for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
-            String label = resources.getString(
-                    Metrics[metricIndex].getLabelId());
-            int xPos = (metricIndex + 1) * -BAR_WIDTH;
-            int yPos = LABELOFFSET;
-            canvas.drawText(label, xPos, yPos, whiteLabels);
-            for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                String statLabel = resources.getString(
-                        Stats[statIndex].getLabelId()).substring(0,3);
-                label = statLabel + " " + resources.getString(
-                        R.string.format_stat, mStats[metricIndex][statIndex]);
-                yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
-                        / 2;
-                canvas.drawText(label, xPos, yPos, whiteLabels);
-            }
-        }
-        for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
-            int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
-            canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
-        }
-    }
-}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
deleted file mode 100644
index 5459c1f..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.ShapeDrawable;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.test.tilebenchmark.RunData.TileData;
-
-import java.util.ArrayList;
-
-public class PlaybackView extends View {
-    public static final int TILE_SCALE = 256;
-    private static final int INVAL_FLAG = -2;
-    private static final int INVAL_CYCLE = 250;
-
-    private Paint levelPaint = null, coordPaint = null, goldPaint = null;
-    private PlaybackGraphs mGraphs;
-
-    private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>();
-    private RunData mProfData = null;
-    private GestureDetector mGestureDetector = null;
-    private ArrayList<String> mRenderStrings = new ArrayList<String>();
-
-    private class TileDrawable extends ShapeDrawable {
-        TileData tile;
-        String label;
-
-        public TileDrawable(TileData t, int colorId) {
-            this.tile = t;
-            getPaint().setColor(getResources().getColor(colorId));
-            if (colorId == R.color.ready_tile
-                    || colorId == R.color.unready_tile) {
-
-                label = (int) (t.left / TILE_SCALE) + ", "
-                        + (int) (t.top / TILE_SCALE);
-                // ignore scale value for tiles
-                setBounds(t.left, t.top,
-                        t.right, t.bottom);
-            } else {
-                setBounds((int) (t.left * t.scale),
-                        (int) (t.top * t.scale),
-                        (int) (t.right * t.scale),
-                        (int) (t.bottom * t.scale));
-            }
-        }
-
-        @SuppressWarnings("unused")
-        public void setColor(int color) {
-            getPaint().setColor(color);
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            super.draw(canvas);
-            if (label != null) {
-                canvas.drawText(Integer.toString(tile.level), getBounds().left,
-                        getBounds().bottom, levelPaint);
-                canvas.drawText(label, getBounds().left,
-                        ((getBounds().bottom + getBounds().top) / 2),
-                        coordPaint);
-            }
-        }
-    }
-
-    public PlaybackView(Context context) {
-        super(context);
-        init();
-    }
-
-    public PlaybackView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
-    }
-
-    public PlaybackView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init();
-    }
-
-    public void setOnGestureListener(OnGestureListener gl) {
-        mGestureDetector = new GestureDetector(getContext(), gl);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        mGestureDetector.onTouchEvent(event);
-        return true;
-    }
-
-    private void init() {
-        levelPaint = new Paint();
-        levelPaint.setColor(Color.WHITE);
-        levelPaint.setTextSize(TILE_SCALE / 2);
-        coordPaint = new Paint();
-        coordPaint.setColor(Color.BLACK);
-        coordPaint.setTextSize(TILE_SCALE / 3);
-        goldPaint = new Paint();
-        goldPaint.setColor(0xffa0e010);
-        mGraphs = new PlaybackGraphs();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        if (mTempShapes == null || mTempShapes.isEmpty()) {
-            return;
-        }
-
-        mGraphs.draw(canvas, mTempShapes, mRenderStrings, getResources());
-        invalidate(); // may have animations, force redraw
-    }
-
-    private String statString(int labelId, int value) {
-        return getResources().getString(R.string.format_stat_name,
-                getResources().getString(labelId), value);
-    }
-    private String tileString(int formatStringId, TileData t) {
-        return getResources().getString(formatStringId,
-                t.left, t.top, t.right, t.bottom);
-    }
-
-    public int setFrame(int frame) {
-        if (mProfData == null || mProfData.frames.length == 0) {
-            return 0;
-        }
-
-        int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0;
-        mTempShapes.clear();
-        mRenderStrings.clear();
-
-        // create tile shapes (as they're drawn on bottom)
-        for (TileData t : mProfData.frames[frame]) {
-            if (t == mProfData.frames[frame][0]){
-                // viewport 'tile', add coords to render strings
-                mRenderStrings.add(tileString(R.string.format_view_pos, t));
-            } else  if (t.level != INVAL_FLAG) {
-                int colorId;
-                if (t.isReady) {
-                    readyTiles++;
-                    colorId = R.color.ready_tile;
-                } else {
-                    unreadyTiles++;
-                    colorId = R.color.unready_tile;
-                }
-                if (t.left < 0 || t.top < 0) {
-                    unplacedTiles++;
-                }
-                mTempShapes.add(new TileDrawable(t, colorId));
-            } else {
-                // inval 'tile', count and add coords to render strings
-                numInvals++;
-                mRenderStrings.add(tileString(R.string.format_inval_pos, t));
-            }
-        }
-
-        // create invalidate shapes (drawn above tiles)
-        int invalId = 0;
-        for (TileData t : mProfData.frames[frame]) {
-            if (t.level == INVAL_FLAG && t != mProfData.frames[frame][0]) {
-                TileDrawable invalShape = new TileDrawable(t,
-                        R.color.inval_region_start);
-                ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape,
-                        "color",
-                        getResources().getColor(R.color.inval_region_start),
-                        getResources().getColor(R.color.inval_region_stop));
-                tileAnimator.setDuration(numInvals * INVAL_CYCLE);
-                tileAnimator.setEvaluator(new ArgbEvaluator());
-                tileAnimator.setRepeatCount(ValueAnimator.INFINITE);
-                tileAnimator.setRepeatMode(ValueAnimator.RESTART);
-                float delay = (float) (invalId) * INVAL_CYCLE;
-                tileAnimator.setStartDelay((int) delay);
-                invalId++;
-                tileAnimator.start();
-
-                mTempShapes.add(invalShape);
-            }
-        }
-
-        mRenderStrings.add(statString(R.string.ready_tiles, readyTiles));
-        mRenderStrings.add(statString(R.string.unready_tiles, unreadyTiles));
-        mRenderStrings.add(statString(R.string.unplaced_tiles, unplacedTiles));
-        mRenderStrings.add(statString(R.string.number_invalidates, numInvals));
-
-        // draw view rect (using first TileData object, on top)
-        TileDrawable viewShape = new TileDrawable(mProfData.frames[frame][0],
-                R.color.view);
-        mTempShapes.add(viewShape);
-        this.invalidate();
-        return frame;
-    }
-
-    public void setData(RunData tileProfilingData) {
-        mProfData = tileProfilingData;
-
-        mGraphs.setData(mProfData);
-    }
-}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
deleted file mode 100644
index 2e77157..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-import android.widget.ToggleButton;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-
-/**
- * Interface for profiling the webview's scrolling, with simple controls on how
- * to scroll, and what content to load.
- */
-public class ProfileActivity extends Activity {
-
-    private static final int TIMED_RECORD_MILLIS = 2000;
-
-    public interface ProfileCallback {
-        public void profileCallback(RunData data);
-    }
-
-    public static final String TEMP_FILENAME = "profile.tiles";
-
-    Button mInspectButton;
-    ToggleButton mCaptureButton;
-    Spinner mVelocitySpinner;
-    Spinner mMovementSpinner;
-    EditText mUrl;
-    ProfiledWebView mWeb;
-    ProfileCallback mCallback;
-
-    LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient();
-    AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient();
-    TimedLoggingWebViewClient mTimedLoggingWebViewClient = new TimedLoggingWebViewClient();
-
-    private enum TestingState {
-        NOT_TESTING,
-        PRE_TESTING,
-        START_TESTING,
-        STOP_TESTING,
-        SAVED_TESTING
-    };
-
-    private class VelocitySelectedListener implements OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view,
-                int position, long id) {
-            String speedStr = parent.getItemAtPosition(position).toString();
-            int speedInt = Integer.parseInt(speedStr);
-            mWeb.setAutoScrollSpeed(speedInt);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-        }
-    }
-
-    private class MovementSelectedListener implements OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view,
-                int position, long id) {
-            String movementStr = parent.getItemAtPosition(position).toString();
-            if (movementStr == getResources().getString(R.string.movement_auto_scroll)) {
-                mWeb.setWebViewClient(mAutoLoggingWebViewClient);
-                mCaptureButton.setEnabled(false);
-                mVelocitySpinner.setEnabled(true);
-            } else if (movementStr == getResources().getString(R.string.movement_manual)) {
-                mWeb.setWebViewClient(mLoggingWebViewClient);
-                mCaptureButton.setEnabled(true);
-                mVelocitySpinner.setEnabled(false);
-            } else if (movementStr == getResources().getString(R.string.movement_timed)) {
-                mWeb.setWebViewClient(mTimedLoggingWebViewClient);
-                mCaptureButton.setEnabled(false);
-                mVelocitySpinner.setEnabled(false);
-            }
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-        }
-    }
-
-    private class LoggingWebViewClient extends WebViewClient {
-        @Override
-        public boolean shouldOverrideUrlLoading(WebView view, String url) {
-            return false;
-        }
-
-        @Override
-        public void onPageStarted(WebView view, String url, Bitmap favicon) {
-            super.onPageStarted(view, url, favicon);
-            mUrl.setText(url);
-        }
-
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            super.onPageFinished(view, url);
-            view.requestFocus();
-            ((ProfiledWebView)view).onPageFinished();
-        }
-    }
-
-    private class AutoLoggingWebViewClient extends LoggingWebViewClient {
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            super.onPageFinished(view, url);
-            startViewProfiling(true);
-        }
-
-        @Override
-        public void onPageStarted(WebView view, String url, Bitmap favicon) {
-            super.onPageStarted(view, url, favicon);
-            setTestingState(TestingState.PRE_TESTING);
-        }
-    }
-
-    private class TimedLoggingWebViewClient extends LoggingWebViewClient {
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            super.onPageFinished(view, url);
-            startViewProfiling(false);
-
-            // after a fixed time after page finished, stop testing
-            new CountDownTimer(TIMED_RECORD_MILLIS, TIMED_RECORD_MILLIS) {
-                @Override
-                public void onTick(long millisUntilFinished) {
-                }
-
-                @Override
-                public void onFinish() {
-                    mWeb.stopScrollTest();
-                }
-            }.start();
-        }
-
-        @Override
-        public void onPageStarted(WebView view, String url, Bitmap favicon) {
-            super.onPageStarted(view, url, favicon);
-            setTestingState(TestingState.PRE_TESTING);
-        }
-    }
-
-    private class StoreFileTask extends
-            AsyncTask<Pair<String, RunData>, Void, Void> {
-
-        @Override
-        protected Void doInBackground(Pair<String, RunData>... params) {
-            try {
-                FileOutputStream fos = openFileOutput(params[0].first,
-                        Context.MODE_PRIVATE);
-                ObjectOutputStream out = new ObjectOutputStream(fos);
-                out.writeObject(params[0].second);
-                out.close();
-            } catch (IOException ex) {
-                ex.printStackTrace();
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Void v) {
-            setTestingState(TestingState.SAVED_TESTING);
-        }
-    }
-
-    public void setTestingState(TestingState state) {
-        switch (state) {
-            case NOT_TESTING:
-                mUrl.setBackgroundResource(R.color.background_not_testing);
-                mInspectButton.setEnabled(true);
-                mMovementSpinner.setEnabled(true);
-                break;
-            case PRE_TESTING:
-                mInspectButton.setEnabled(false);
-                mMovementSpinner.setEnabled(false);
-                break;
-            case START_TESTING:
-                mCaptureButton.setChecked(true);
-                mUrl.setBackgroundResource(R.color.background_start_testing);
-                mInspectButton.setEnabled(false);
-                mMovementSpinner.setEnabled(false);
-                break;
-            case STOP_TESTING:
-                mCaptureButton.setChecked(false);
-                mUrl.setBackgroundResource(R.color.background_stop_testing);
-                break;
-            case SAVED_TESTING:
-                mInspectButton.setEnabled(true);
-                mMovementSpinner.setEnabled(true);
-                break;
-        }
-    }
-
-    /** auto - automatically scroll. */
-    private void startViewProfiling(boolean auto) {
-        // toggle capture button to indicate capture state to user
-        mWeb.startScrollTest(mCallback, auto);
-        setTestingState(TestingState.START_TESTING);
-    }
-
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-        mInspectButton = (Button) findViewById(R.id.inspect);
-        mCaptureButton = (ToggleButton) findViewById(R.id.capture);
-        mVelocitySpinner = (Spinner) findViewById(R.id.velocity);
-        mMovementSpinner = (Spinner) findViewById(R.id.movement);
-        mUrl = (EditText) findViewById(R.id.url);
-        mWeb = (ProfiledWebView) findViewById(R.id.web);
-        setCallback(new ProfileCallback() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public void profileCallback(RunData data) {
-                new StoreFileTask().execute(new Pair<String, RunData>(
-                        TEMP_FILENAME, data));
-                Log.d("ProfileActivity", "stored " + data.frames.length + " frames in file");
-                setTestingState(TestingState.STOP_TESTING);
-            }
-        });
-
-        // Inspect button (opens PlaybackActivity)
-        mInspectButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startActivity(new Intent(ProfileActivity.this,
-                        PlaybackActivity.class));
-            }
-        });
-
-        // Velocity spinner
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
-                this, R.array.velocity_array,
-                android.R.layout.simple_spinner_item);
-        adapter.setDropDownViewResource(
-                android.R.layout.simple_spinner_dropdown_item);
-        mVelocitySpinner.setAdapter(adapter);
-        mVelocitySpinner.setOnItemSelectedListener(
-                new VelocitySelectedListener());
-        mVelocitySpinner.setSelection(3);
-
-        // Movement spinner
-        String content[] = {
-                getResources().getString(R.string.movement_auto_scroll),
-                getResources().getString(R.string.movement_manual),
-                getResources().getString(R.string.movement_timed)
-        };
-        adapter = new ArrayAdapter<CharSequence>(this,
-                android.R.layout.simple_spinner_item, content);
-        adapter.setDropDownViewResource(
-                android.R.layout.simple_spinner_dropdown_item);
-        mMovementSpinner.setAdapter(adapter);
-        mMovementSpinner.setOnItemSelectedListener(
-                new MovementSelectedListener());
-        mMovementSpinner.setSelection(0);
-
-        // Capture toggle button
-        mCaptureButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mCaptureButton.isChecked()) {
-                    startViewProfiling(false);
-                } else {
-                    mWeb.stopScrollTest();
-                }
-            }
-        });
-
-        // Custom profiling WebView
-        mWeb.init(this);
-        mWeb.setWebViewClient(new LoggingWebViewClient());
-
-        // URL text entry
-        mUrl.setOnEditorActionListener(new OnEditorActionListener() {
-            public boolean onEditorAction(TextView v, int actionId,
-                    KeyEvent event) {
-                String url = mUrl.getText().toString();
-                mWeb.loadUrl(url);
-                mWeb.requestFocus();
-                return true;
-            }
-        });
-
-        setTestingState(TestingState.NOT_TESTING);
-    }
-
-    public void setCallback(ProfileCallback callback) {
-        mCallback = callback;
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWeb.canGoBack()) {
-            mWeb.goBack();
-            return true;
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
deleted file mode 100644
index d3b572c..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import android.content.Context;
-import android.os.CountDownTimer;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.webkit.WebSettingsClassic;
-import android.webkit.WebView;
-import android.webkit.WebViewClassic;
-
-import java.util.ArrayList;
-
-import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
-import com.test.tilebenchmark.RunData.TileData;
-
-public class ProfiledWebView extends WebView implements WebViewClassic.PageSwapDelegate {
-    private static final String LOGTAG = "ProfiledWebView";
-
-    private int mSpeed;
-
-    private boolean mIsTesting = false;
-    private boolean mIsScrolling = false;
-    private ProfileCallback mCallback;
-    private long mContentInvalMillis;
-    private static final int LOAD_STALL_MILLIS = 2000; // nr of millis after load,
-                                                       // before test is forced
-
-    // ignore anim end events until this many millis after load
-    private static final long ANIM_SAFETY_THRESHOLD = 200;
-    private long mLoadTime;
-    private long mAnimationTime;
-
-    public ProfiledWebView(Context context) {
-        super(context);
-    }
-
-    public ProfiledWebView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public ProfiledWebView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public ProfiledWebView(Context context, AttributeSet attrs, int defStyle,
-            boolean privateBrowsing) {
-        super(context, attrs, defStyle, privateBrowsing);
-    }
-
-    private class JavaScriptInterface {
-        Context mContext;
-
-        /** Instantiate the interface and set the context */
-        JavaScriptInterface(Context c) {
-            mContext = c;
-        }
-
-        public void animationComplete() {
-            mAnimationTime = System.currentTimeMillis();
-        }
-    }
-
-    public void init(Context c) {
-        WebSettingsClassic settings = getWebViewClassic().getSettings();
-        settings.setJavaScriptEnabled(true);
-        settings.setSupportZoom(true);
-        settings.setEnableSmoothTransition(true);
-        settings.setBuiltInZoomControls(true);
-        settings.setLoadWithOverviewMode(true);
-        settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
-        addJavascriptInterface(new JavaScriptInterface(c), "Android");
-        mAnimationTime = 0;
-        mLoadTime = 0;
-    }
-
-    public void setUseMinimalMemory(boolean minimal) {
-        WebSettingsClassic settings = getWebViewClassic().getSettings();
-        settings.setProperty("use_minimal_memory", minimal ? "true" : "false");
-    }
-
-    public void onPageFinished() {
-        mLoadTime = System.currentTimeMillis();
-    }
-
-    @Override
-    protected void onDraw(android.graphics.Canvas canvas) {
-        if (mIsTesting && mIsScrolling) {
-            if (canScrollVertically(1)) {
-                scrollBy(0, mSpeed);
-            } else {
-                stopScrollTest();
-                mIsScrolling = false;
-            }
-        }
-        super.onDraw(canvas);
-    }
-
-    /*
-     * Called once the page is loaded to start scrolling for evaluating tiles.
-     * If autoScrolling isn't set, stop must be called manually. Before
-     * scrolling, invalidate all content and redraw it, measuring time taken.
-     */
-    public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
-        mCallback = callback;
-        mIsTesting = false;
-        mIsScrolling = false;
-        WebSettingsClassic settings = getWebViewClassic().getSettings();
-        settings.setProperty("tree_updates", "0");
-
-
-        if (autoScrolling) {
-            // after a while, force it to start even if the pages haven't swapped
-            new CountDownTimer(LOAD_STALL_MILLIS, LOAD_STALL_MILLIS) {
-                @Override
-                public void onTick(long millisUntilFinished) {
-                }
-
-                @Override
-                public void onFinish() {
-                    // invalidate all content, and kick off redraw
-                    Log.d("ProfiledWebView",
-                            "kicking off test with callback registration, and tile discard...");
-                    getWebViewClassic().discardAllTextures();
-                    invalidate();
-                    mIsScrolling = true;
-                    mContentInvalMillis = System.currentTimeMillis();
-                }
-            }.start();
-        } else {
-            mIsTesting = true;
-            getWebViewClassic().tileProfilingStart();
-        }
-    }
-
-    /*
-     * Called after the manual contentInvalidateAll, after the tiles have all
-     * been redrawn.
-     * From PageSwapDelegate.
-     */
-    @Override
-    public void onPageSwapOccurred(boolean startAnim) {
-        if (!mIsTesting && mIsScrolling) {
-            // kick off testing
-            mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
-            Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis");
-            mIsTesting = true;
-            invalidate(); // ensure a redraw so that auto-scrolling can occur
-            getWebViewClassic().tileProfilingStart();
-        }
-    }
-
-    private double animFramerate() {
-        WebSettingsClassic settings = getWebViewClassic().getSettings();
-        String updatesString = settings.getProperty("tree_updates");
-        int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString);
-
-        long animationTime;
-        if (mAnimationTime == 0 || mAnimationTime - mLoadTime < ANIM_SAFETY_THRESHOLD) {
-            animationTime = System.currentTimeMillis() - mLoadTime;
-        } else {
-            animationTime = mAnimationTime - mLoadTime;
-        }
-
-        return updates * 1000.0 / animationTime;
-    }
-
-    public void setDoubleBuffering(boolean useDoubleBuffering) {
-        WebSettingsClassic settings = getWebViewClassic().getSettings();
-        settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false");
-    }
-
-    /*
-     * Called once the page has stopped scrolling
-     */
-    public void stopScrollTest() {
-        getWebViewClassic().tileProfilingStop();
-        mIsTesting = false;
-
-        if (mCallback == null) {
-            getWebViewClassic().tileProfilingClear();
-            return;
-        }
-
-        RunData data = new RunData(getWebViewClassic().tileProfilingNumFrames());
-        // record the time spent (before scrolling) rendering the page
-        data.singleStats.put(getResources().getString(R.string.render_millis),
-                (double)mContentInvalMillis);
-
-        // record framerate
-        double framerate = animFramerate();
-        Log.d(LOGTAG, "anim framerate was "+framerate);
-        data.singleStats.put(getResources().getString(R.string.animation_framerate),
-                framerate);
-
-        for (int frame = 0; frame < data.frames.length; frame++) {
-            data.frames[frame] = new TileData[
-                    getWebViewClassic().tileProfilingNumTilesInFrame(frame)];
-            for (int tile = 0; tile < data.frames[frame].length; tile++) {
-                int left = getWebViewClassic().tileProfilingGetInt(frame, tile, "left");
-                int top = getWebViewClassic().tileProfilingGetInt(frame, tile, "top");
-                int right = getWebViewClassic().tileProfilingGetInt(frame, tile, "right");
-                int bottom = getWebViewClassic().tileProfilingGetInt(frame, tile, "bottom");
-
-                boolean isReady = getWebViewClassic().tileProfilingGetInt(
-                        frame, tile, "isReady") == 1;
-                int level = getWebViewClassic().tileProfilingGetInt(frame, tile, "level");
-
-                float scale = getWebViewClassic().tileProfilingGetFloat(frame, tile, "scale");
-
-                data.frames[frame][tile] = data.new TileData(left, top, right, bottom,
-                        isReady, level, scale);
-            }
-        }
-        getWebViewClassic().tileProfilingClear();
-
-        mCallback.profileCallback(data);
-    }
-
-    @Override
-    public void loadUrl(String url) {
-        mAnimationTime = 0;
-        mLoadTime = 0;
-        if (!url.startsWith("http://") && !url.startsWith("file://")) {
-            url = "http://" + url;
-        }
-        super.loadUrl(url);
-    }
-
-    public void setAutoScrollSpeed(int speedInt) {
-        mSpeed = speedInt;
-    }
-
-    public WebViewClassic getWebViewClassic() {
-        return WebViewClassic.fromWebView(this);
-    }
-}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
deleted file mode 100644
index 5e48afd..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-package com.test.tilebenchmark;
-
-import java.io.Serializable;
-import java.util.HashMap;
-
-public class RunData implements Serializable {
-    public TileData[][] frames;
-    public HashMap<String, Double> singleStats = new HashMap<String, Double>();
-
-    public RunData(int frames) {
-        this.frames = new TileData[frames][];
-    }
-
-    public class TileData implements Serializable {
-        public int left, top, right, bottom;
-        public boolean isReady;
-        public int level;
-        public float scale;
-
-        public TileData(int left, int top, int right, int bottom,
-                boolean isReady, int level, float scale) {
-            this.left = left;
-            this.right = right;
-            this.top = top;
-            this.bottom = bottom;
-            this.isReady = isReady;
-            this.level = level;
-            this.scale = scale;
-        }
-
-        public String toString() {
-            return "Tile (" + left + "," + top + ")->("
-                    + right + "," + bottom + ")"
-                    + (isReady ? "ready" : "NOTready") + " at scale " + scale;
-        }
-    }
-
-}
diff --git a/tests/TransitionTests/Android.mk b/tests/TransitionTests/Android.mk
new file mode 100644
index 0000000..22fa638
--- /dev/null
+++ b/tests/TransitionTests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TransitionTests
+
+LOCAL_STATIC_JAVA_LIBRARIES += android-common
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/TransitionTests/AndroidManifest.xml b/tests/TransitionTests/AndroidManifest.xml
new file mode 100644
index 0000000..35e7b69
--- /dev/null
+++ b/tests/TransitionTests/AndroidManifest.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.transitiontests"
+          android:versionCode="1"
+          android:versionName="1.0">
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application
+            android:icon="@drawable/icon"
+            android:label="@string/app_name"
+            android:hardwareAccelerated="true"
+            android:theme="@style/AppTheme">
+        <activity android:label="@string/states_test1"
+                  android:name="ScenesTestv21">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="@string/states_test_auto_targets"
+                  android:name="ScenesTestAutoTargets">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="@string/states_test_auto_transition"
+                  android:name="ScenesTestAutoTransition">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="@string/states_test_auto_transition2"
+                  android:name="ScenesTestAutoTransition2">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="@string/contacts_expansion"
+                  android:name="ContactsExpansion">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Demo0"
+                  android:name="Demo0">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Demo1"
+                  android:name="Demo1">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Demo2"
+                  android:name="Demo2">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Demo3"
+                  android:name="Demo3">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Demo4"
+                  android:name="Demo4">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Demo5"
+                  android:name="Demo5">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="LoginActivity"
+                  android:name="LoginActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="LoginActivityFromResources"
+                  android:name="LoginActivityFromResources">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="OverlayTest"
+                  android:name="OverlayTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="ResourceLoadingTest"
+                  android:name="ResourceLoadingTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="FadingTest"
+                  android:name="FadingTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="UniqueIds"
+                  android:name="UniqueIds">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="HitRectBug"
+                  android:name="HitRectBug">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="SequenceTest"
+                  android:name="SequenceTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="SequenceTestSimple"
+                  android:name="SequenceTestSimple">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="ChangingText"
+                  android:name="ChangingText">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="ClippingText"
+                  android:name="ClippingText">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="ListViewAddRemove"
+                  android:name="ListViewAddRemove">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="ListViewAddRemoveNoTransition"
+                  android:name="ListViewAddRemoveNoTransition">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="CrossFadeDemo"
+                  android:name="CrossFadeDemo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="Reparenting"
+                  android:name="Reparenting">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="SurfaceAndTextureViews"
+                  android:name="SurfaceAndTextureViews">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="InstanceTargets"
+                  android:name="InstanceTargets">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="InterruptionTest"
+                  android:name="InterruptionTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="DelayedTransition"
+                  android:name="DelayedTransition">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="FadingHierachy"
+                  android:name=".FadingHierarchy">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="HierarchicalMove"
+                  android:name=".HierarchicalMove">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="CrossfadeImage"
+                  android:name=".CrossfadeImage">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="CrossfadeMultiple"
+                  android:name=".CrossfadeMultiple">
+            <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/TransitionTests/res/drawable-hdpi/icon.png b/tests/TransitionTests/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-ldpi/icon.png b/tests/TransitionTests/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-mdpi/icon.png b/tests/TransitionTests/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.png b/tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.png
new file mode 100644
index 0000000..5cae8f2
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpg
new file mode 100644
index 0000000..8cce1c1
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpg
new file mode 100644
index 0000000..26c0a85
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpg
new file mode 100644
index 0000000..f18ae5b
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_400.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_400.jpg
new file mode 100644
index 0000000..3923fd1
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_400.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/layout/activity_login.xml b/tests/TransitionTests/res/layout/activity_login.xml
new file mode 100644
index 0000000..2aaafc0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/activity_login.xml
@@ -0,0 +1,86 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/password"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignRight="@+id/username"
+        android:layout_below="@+id/username"
+        android:layout_marginTop="30dp"
+        android:textColor="#7f7f7f"
+        android:text="@string/password"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <EditText
+        android:id="@+id/usernameEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@+id/username"
+        android:layout_marginLeft="14dp"
+        android:layout_toRightOf="@+id/username"
+        android:ems="10" />
+
+    <TextView
+        android:id="@+id/username"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:layout_marginLeft="20dp"
+        android:layout_marginTop="51dp"
+        android:text="@string/username"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <EditText
+        android:id="@+id/passwordEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/password"
+        android:layout_alignBottom="@+id/password"
+        android:layout_alignLeft="@+id/usernameEdit"
+        android:layout_alignParentRight="true"
+        android:editable="false"
+        android:ems="10" >
+
+        <requestFocus />
+    </EditText>
+
+    <Button
+        android:id="@+id/cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="14dp"
+        android:layout_toLeftOf="@+id/passwordEdit"
+        android:onClick="sendMessage"
+        android:text="@string/cancel" />
+
+    <Button
+        android:id="@+id/submit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/cancel"
+        android:layout_alignBottom="@+id/cancel"
+        android:layout_alignLeft="@+id/passwordEdit"
+        android:layout_marginLeft="41dp"
+        android:onClick="sendMessage"
+        android:text="@string/submit" />
+
+    <TextView
+        android:id="@+id/newuser"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/passwordEdit"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="16dp"
+        android:textColor="#0000ff"
+        android:text="@string/new_user"
+        android:clickable="true"
+        android:onClick="sendMessage"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textStyle="italic" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/button_template.xml b/tests/TransitionTests/res/layout/button_template.xml
new file mode 100644
index 0000000..9b867f2
--- /dev/null
+++ b/tests/TransitionTests/res/layout/button_template.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+              android:onClick="sendMessage"
+              android:id="@+id/button"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+
+</Button>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/changing_text_1.xml b/tests/TransitionTests/res/layout/changing_text_1.xml
new file mode 100644
index 0000000..88086a3
--- /dev/null
+++ b/tests/TransitionTests/res/layout/changing_text_1.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/shortText1"
+            android:background="#8f8f8f"
+            android:id="@+id/textview1"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/buttona"
+            android:text="@string/button"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/longText1"
+            android:background="#8f8f8f"
+            android:id="@+id/textview2"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/buttonb"
+            android:text="@string/button"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/changing_text_2.xml b/tests/TransitionTests/res/layout/changing_text_2.xml
new file mode 100644
index 0000000..91fdfef
--- /dev/null
+++ b/tests/TransitionTests/res/layout/changing_text_2.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/longText2"
+            android:background="#8f8f8f"
+            android:id="@+id/textview1"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/buttona"
+            android:text="@string/button"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/shortText2"
+            android:background="#8f8f8f"
+            android:id="@+id/textview2"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/buttonb"
+            android:text="@string/button"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/clipping_text_1.xml b/tests/TransitionTests/res/layout/clipping_text_1.xml
new file mode 100644
index 0000000..5fe45ab
--- /dev/null
+++ b/tests/TransitionTests/res/layout/clipping_text_1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/shortText1"
+            android:background="#8f8f8f"
+            android:id="@+id/textview1"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/clipping_text_2.xml b/tests/TransitionTests/res/layout/clipping_text_2.xml
new file mode 100644
index 0000000..3a0e3f4
--- /dev/null
+++ b/tests/TransitionTests/res/layout/clipping_text_2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="500dip"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/longText2"
+            android:background="#8f8f8f"
+            android:id="@+id/textview1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/contact_collapsed.xml b/tests/TransitionTests/res/layout/contact_collapsed.xml
new file mode 100644
index 0000000..bfa97df
--- /dev/null
+++ b/tests/TransitionTests/res/layout/contact_collapsed.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:background="#fff"
+              android:layout_width="fill_parent"
+              android:id="@+id/topContainer"
+              android:layout_height="wrap_content">
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/contact_arrow"
+            android:src="@drawable/arrow_thumbnail"/>
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/contact_picture"/>
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="0dip"
+                  android:id="@+id/itemContainer"
+                  android:background="#ccc"
+                  android:layout_weight="1"
+                  android:layout_height="wrap_content">
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/contact_name"/>
+        <LinearLayout android:orientation="vertical"
+                      android:visibility="gone"
+                      android:id="@+id/expanded_info"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content">
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/contact_street"/>
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/contact_city"/>
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/contact_phone"/>
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:id="@+id/contact_email"/>
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/contact_expanded.xml b/tests/TransitionTests/res/layout/contact_expanded.xml
new file mode 100644
index 0000000..4007d4a
--- /dev/null
+++ b/tests/TransitionTests/res/layout/contact_expanded.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:background="#fff"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent">
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/contact_arrow"
+            android:src="@drawable/arrow_thumbnail"/>
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="fill_parent"
+                  android:layout_height="fill_parent">
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/contact_name"/>
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/contact_street"/>
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/contact_city"/>
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/contact_phone"/>
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/contact_email"/>
+    </LinearLayout>
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/contact_picture"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/contacts_list.xml b/tests/TransitionTests/res/layout/contacts_list.xml
new file mode 100644
index 0000000..d38704c
--- /dev/null
+++ b/tests/TransitionTests/res/layout/contacts_list.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/contactsContainer"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent">
+
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/crossfade.xml b/tests/TransitionTests/res/layout/crossfade.xml
new file mode 100644
index 0000000..d766ce1
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:id="@+id/container">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:onClick="sendMessage"
+            android:id="@+id/button"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/shortText1"
+            android:id="@+id/textview"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/longText1"
+            android:id="@+id/textview1"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/someText"
+            android:id="@+id/textview2"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/crossfade_1.xml b/tests/TransitionTests/res/layout/crossfade_1.xml
new file mode 100644
index 0000000..4cc5bc9
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade_1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:id="@+id/container">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:onClick="sendMessage"
+            android:id="@+id/button"/>
+
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/shortText2"
+            android:id="@+id/textview"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/longText2"
+            android:id="@+id/textview1"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/someText"
+            android:id="@+id/textview2"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/crossfade_image.xml b/tests/TransitionTests/res/layout/crossfade_image.xml
new file mode 100644
index 0000000..c46327a
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade_image.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/self_portrait_square_100"
+            android:onClick="sendMessage"
+            android:id="@+id/contact_picture"/>
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/self_portrait_square_100"
+            android:onClick="sendMessage"
+            android:id="@+id/contact_picture1"/>
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/self_portrait_square_100"
+            android:onClick="sendMessage"
+            android:id="@+id/contact_picture2"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/crossfade_multiple.xml b/tests/TransitionTests/res/layout/crossfade_multiple.xml
new file mode 100644
index 0000000..3e6d551
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade_multiple.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <RadioGroup android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+        <RadioButton android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="changeTransitionType"
+                     android:id="@+id/reveal"
+                     android:text="@string/reveal"/>
+        <RadioButton android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="changeTransitionType"
+                     android:id="@+id/crossfade"
+                     android:text="@string/crossfade"/>
+        <RadioButton android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="changeTransitionType"
+                     android:id="@+id/inout"
+                     android:text="@string/inout"/>
+        <RadioButton android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="changeTransitionType"
+                     android:id="@+id/textfade1"
+                     android:text="@string/textfade1"/>
+        <RadioButton android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="changeTransitionType"
+                     android:id="@+id/textfade2"
+                     android:text="@string/textfade2"/>
+        <RadioButton android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="changeTransitionType"
+                     android:id="@+id/textfade3"
+                     android:text="@string/textfade3"/>
+    </RadioGroup>
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="sendMessage"
+                android:text="@string/state1"
+                android:id="@+id/button1"/>
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="sendMessage"
+                android:text="@string/state2"
+                android:id="@+id/button2"/>
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="sendMessage"
+                android:text="@string/state3"
+                android:id="@+id/button3"/>
+    </LinearLayout>
+
+    <LinearLayout android:orientation="vertical"
+                  android:id="@+id/container"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+        <Button
+                android:layout_width="100dip"
+                android:layout_height="100dip"
+                android:textSize="40dip"
+                android:text="@string/a"
+                android:id="@+id/button"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="40dip"
+                android:text="@string/state1"
+                android:id="@+id/textview"/>
+        <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/self_portrait_square_100"
+                android:onClick="sendMessage"
+                android:id="@+id/imageview"/>
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_hierarchy.xml b/tests/TransitionTests/res/layout/fading_hierarchy.xml
new file mode 100644
index 0000000..a24a6b6
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_hierarchy.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/button"/>
+        <LinearLayout
+                android:orientation="vertical"
+                android:id="@+id/removingContainer"
+                android:layout_width="wrap_content"
+                android:layout_height="200dip">
+            <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/removingButton"
+                    android:id="@+id/removingButton"/>
+        </LinearLayout>
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/button"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test.xml b/tests/TransitionTests/res/layout/fading_test.xml
new file mode 100644
index 0000000..3728b5e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/removingButton"
+            android:id="@+id/removingButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/invisibleButton"
+            android:id="@+id/invisibleButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/goneButton"
+            android:id="@+id/goneButton"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button"
+            android:text="@string/button"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test_scene_2.xml b/tests/TransitionTests/res/layout/fading_test_scene_2.xml
new file mode 100644
index 0000000..baf5b4d
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test_scene_2.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/invisibleButton"
+            android:visibility="invisible"
+            android:id="@+id/invisibleButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/goneButton"
+            android:visibility="gone"
+            android:id="@+id/goneButton"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button"
+            android:text="@string/button"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test_simple.xml b/tests/TransitionTests/res/layout/fading_test_simple.xml
new file mode 100644
index 0000000..d201eca
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test_simple.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/removingButton"
+            android:id="@+id/removingButton"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test_simple2.xml b/tests/TransitionTests/res/layout/fading_test_simple2.xml
new file mode 100644
index 0000000..80f3f94
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test_simple2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="50dip"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/removingButton"
+            android:visibility="invisible"
+            android:id="@+id/removingButton"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/hierarchical_move.xml b/tests/TransitionTests/res/layout/hierarchical_move.xml
new file mode 100644
index 0000000..1e70ba9
--- /dev/null
+++ b/tests/TransitionTests/res/layout/hierarchical_move.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit"
+            android:onClick="sendMessage"
+            android:id="@+id/sceneSwitchButton"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button0"
+            android:id="@+id/button0"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button1"
+            android:id="@+id/button1"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button2"
+            android:id="@+id/button2"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button3"
+            android:id="@+id/button3"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button4"
+            android:id="@+id/button4"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button5"
+            android:id="@+id/button5"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/incorrect_password.xml b/tests/TransitionTests/res/layout/incorrect_password.xml
new file mode 100644
index 0000000..af59618
--- /dev/null
+++ b/tests/TransitionTests/res/layout/incorrect_password.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <Button
+        android:id="@+id/okay"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:layout_marginBottom="164dp"
+        android:onClick="sendMessage"
+        android:text="@string/okay" />
+
+    <TextView
+        android:id="@+id/incorrectpassword"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_above="@+id/okay"
+        android:layout_centerHorizontal="true"
+        android:layout_marginBottom="93dp"
+        android:text="@string/incorrect_password"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <TextView
+        android:id="@+id/tryagain"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@+id/incorrectpassword"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="35dp"
+        android:text="@string/try_again"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/instance_targets.xml b/tests/TransitionTests/res/layout/instance_targets.xml
new file mode 100644
index 0000000..5677d52
--- /dev/null
+++ b/tests/TransitionTests/res/layout/instance_targets.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:id="@+id/container">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:onClick="sendMessage"
+            android:id="@+id/button0"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/button0"
+            android:onClick="sendMessage"
+            android:id="@+id/button1"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/button1"
+            android:onClick="sendMessage"
+            android:id="@+id/button2"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/button2"
+            android:onClick="sendMessage"
+            android:id="@+id/button3"/>
+
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/interruption.xml b/tests/TransitionTests/res/layout/interruption.xml
new file mode 100644
index 0000000..9fdb27a
--- /dev/null
+++ b/tests/TransitionTests/res/layout/interruption.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <RadioGroup android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+        <RadioButton android:id="@+id/scene1RB"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:text="@string/state1"
+                     android:onClick="onRadioButtonClicked"/>
+        <RadioButton android:id="@+id/scene2RB"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:text="@string/state2"
+                     android:onClick="onRadioButtonClicked"/>
+        <RadioButton android:id="@+id/scene3RB"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:text="@string/state3"
+                     android:onClick="onRadioButtonClicked"/>
+        <RadioButton android:id="@+id/scene4RB"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:text="@string/state4"
+                     android:onClick="onRadioButtonClicked"/>
+    </RadioGroup>
+
+    <LinearLayout
+            android:orientation="vertical"
+            android:id="@+id/sceneRoot"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+        <include layout="@layout/interruption_inner_1"/>
+
+    </LinearLayout>
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/interruption_inner_1.xml b/tests/TransitionTests/res/layout/interruption_inner_1.xml
new file mode 100644
index 0000000..f82dfb0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/interruption_inner_1.xml
@@ -0,0 +1,20 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/buttonContainer">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:text="@string/state1"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button1"
+            android:layout_alignLeft="@+id/button"
+            android:layout_below="@+id/button"
+            android:text="@string/state1"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/interruption_inner_2.xml b/tests/TransitionTests/res/layout/interruption_inner_2.xml
new file mode 100644
index 0000000..e6821d6
--- /dev/null
+++ b/tests/TransitionTests/res/layout/interruption_inner_2.xml
@@ -0,0 +1,20 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/buttonContainer">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:id="@+id/button"
+            android:layout_alignParentRight="true"
+            android:text="@string/state2"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button1"
+            android:layout_alignLeft="@+id/button"
+            android:layout_below="@+id/button"
+            android:text="@string/state2"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/interruption_inner_3.xml b/tests/TransitionTests/res/layout/interruption_inner_3.xml
new file mode 100644
index 0000000..4e40150
--- /dev/null
+++ b/tests/TransitionTests/res/layout/interruption_inner_3.xml
@@ -0,0 +1,20 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/buttonContainer">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:text="@string/state3"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button1"
+            android:layout_alignLeft="@+id/button"
+            android:layout_above="@+id/button"
+            android:text="@string/state3"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/interruption_inner_4.xml b/tests/TransitionTests/res/layout/interruption_inner_4.xml
new file mode 100644
index 0000000..8c3661e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/interruption_inner_4.xml
@@ -0,0 +1,20 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/buttonContainer">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:text="@string/state4"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button1"
+            android:layout_alignLeft="@+id/button"
+            android:layout_above="@+id/button"
+            android:text="@string/state4"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/list_view_add_remove.xml b/tests/TransitionTests/res/layout/list_view_add_remove.xml
new file mode 100644
index 0000000..230511f
--- /dev/null
+++ b/tests/TransitionTests/res/layout/list_view_add_remove.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <ListView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/listview"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/login_password.xml b/tests/TransitionTests/res/layout/login_password.xml
new file mode 100644
index 0000000..1e75694
--- /dev/null
+++ b/tests/TransitionTests/res/layout/login_password.xml
@@ -0,0 +1,86 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".LoginActivity" >
+
+    <TextView
+        android:id="@+id/password"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignRight="@+id/username"
+        android:layout_below="@+id/username"
+        android:layout_marginTop="30dp"
+        android:text="@string/password"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <EditText
+        android:id="@+id/usernameEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@+id/username"
+        android:layout_marginLeft="14dp"
+        android:layout_toRightOf="@+id/username"
+        android:ems="10" />
+
+    <TextView
+        android:id="@+id/username"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:layout_marginLeft="20dp"
+        android:layout_marginTop="51dp"
+        android:text="@string/username"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <EditText
+        android:id="@+id/passwordEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/password"
+        android:layout_alignBottom="@+id/password"
+        android:layout_alignLeft="@+id/usernameEdit"
+        android:layout_alignParentRight="true"
+        android:ems="10" >
+
+        <requestFocus />
+    </EditText>
+
+    <Button
+        android:id="@+id/cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="14dp"
+        android:layout_toLeftOf="@+id/passwordEdit"
+        android:onClick="sendMessage"
+        android:text="@string/cancel" />
+
+    <Button
+        android:id="@+id/submit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/cancel"
+        android:layout_alignBottom="@+id/cancel"
+        android:layout_alignLeft="@+id/passwordEdit"
+        android:layout_marginLeft="41dp"
+        android:onClick="sendMessage"
+        android:text="@string/submit" />
+
+    <TextView
+        android:id="@+id/newuser"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/passwordEdit"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="16dp"
+        android:textColor="#0000ff"
+        android:text="@string/new_user"
+        android:clickable="true"
+        android:onClick="sendMessage"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textStyle="italic" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/main.xml b/tests/TransitionTests/res/layout/main.xml
new file mode 100644
index 0000000..b42318e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/main.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:id="@+id/container">
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/button"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/new_user.xml b/tests/TransitionTests/res/layout/new_user.xml
new file mode 100644
index 0000000..f8dfab06
--- /dev/null
+++ b/tests/TransitionTests/res/layout/new_user.xml
@@ -0,0 +1,92 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/container"
+    tools:context=".LoginActivity" >
+
+    <TextView
+        android:id="@+id/password"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignRight="@+id/username"
+        android:layout_below="@+id/username"
+        android:layout_marginTop="30dp"
+        android:text="@string/password"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <EditText
+        android:id="@+id/usernameEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@+id/username"
+        android:layout_marginLeft="14dp"
+        android:layout_toRightOf="@+id/username"
+        android:ems="10" />
+
+    <TextView
+        android:id="@+id/username"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:layout_marginLeft="20dp"
+        android:layout_marginTop="51dp"
+        android:text="@string/username"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <EditText
+        android:id="@+id/passwordEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/password"
+        android:layout_alignBottom="@+id/password"
+        android:layout_alignLeft="@+id/usernameEdit"
+        android:layout_alignParentRight="true"
+        android:ems="10" >
+
+        <requestFocus />
+    </EditText>
+
+    <Button
+        android:id="@+id/cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="14dp"
+        android:layout_toLeftOf="@+id/passwordEdit"
+        android:onClick="sendMessage"
+        android:text="@string/cancel" />
+
+    <Button
+        android:id="@+id/submit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/cancel"
+        android:layout_alignBottom="@+id/cancel"
+        android:layout_alignLeft="@+id/passwordEdit"
+        android:layout_marginLeft="41dp"
+        android:onClick="sendMessage"
+        android:text="@string/submit" />
+
+    <EditText
+        android:id="@+id/retypeEdit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/retype"
+        android:layout_alignBottom="@+id/retype"
+        android:layout_alignLeft="@+id/passwordEdit"
+        android:layout_alignParentRight="true"
+        android:ems="10" />
+
+    <TextView
+        android:id="@+id/retype"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/passwordEdit"
+        android:layout_marginTop="26dp"
+        android:layout_toLeftOf="@+id/usernameEdit"
+        android:text="@string/retype"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/overlay_test.xml b/tests/TransitionTests/res/layout/overlay_test.xml
new file mode 100644
index 0000000..edd0393
--- /dev/null
+++ b/tests/TransitionTests/res/layout/overlay_test.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent">
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button"
+            android:text="@string/start"
+            android:onClick="onClick"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/fadingButton"
+            android:id="@+id/fadingButton"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/reparenting.xml b/tests/TransitionTests/res/layout/reparenting.xml
new file mode 100644
index 0000000..b3bfbb9
--- /dev/null
+++ b/tests/TransitionTests/res/layout/reparenting.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:id="@+id/container">
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/container1"/>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/container2"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/resources_test_layout.xml b/tests/TransitionTests/res/layout/resources_test_layout.xml
new file mode 100644
index 0000000..48affa0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/resources_test_layout.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView
+    src="@drawable/icon"/>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/results_screen.xml b/tests/TransitionTests/res/layout/results_screen.xml
new file mode 100644
index 0000000..8550a5e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/results_screen.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:background="#7f7f7f"
+              android:id="@+id/container">
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="top|right"
+                  android:id="@+id/searchContainer">
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/searchText"
+                android:id="@+id/searchText"/>
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/searchButton"
+                android:onClick="sendMessage"
+                android:id="@+id/searchButton"/>
+    </LinearLayout>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/resultsTitle"
+            android:id="@+id/resultsText"/>
+    <LinearLayout android:layout_width="match_parent"
+            android:layout_height="0dip"
+            android:layout_weight="1"
+            android:orientation="vertical"
+            android:id="@+id/resultsList">
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder"/>
+
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/search_screen.xml b/tests/TransitionTests/res/layout/search_screen.xml
new file mode 100644
index 0000000..947702b
--- /dev/null
+++ b/tests/TransitionTests/res/layout/search_screen.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:background="#000000"
+              android:id="@+id/container">
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center"
+                  android:id="@+id/searchContainer">
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/searchText"
+                android:id="@+id/searchText"/>
+        <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/searchButton"
+                android:onClick="sendMessage"
+                android:id="@+id/searchButton"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/success.xml b/tests/TransitionTests/res/layout/success.xml
new file mode 100644
index 0000000..9c265ef
--- /dev/null
+++ b/tests/TransitionTests/res/layout/success.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <TextView
+            android:id="@+id/loginsuccessful"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="93dp"
+            android:text="@string/login_successful"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <TextView
+            android:id="@+id/firstactivityscreen"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignTop="@+id/loginsuccessful"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="35dp"
+            android:text="@string/first_activity_screen"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <Button
+            android:id="@+id/reset"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="164dp"
+            android:onClick="sendMessage"
+            android:text="@string/reset" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/surface_texture_views.xml b/tests/TransitionTests/res/layout/surface_texture_views.xml
new file mode 100644
index 0000000..9260bc0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/surface_texture_views.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+            android:text="@string/toggle"
+            android:id="@+id/toggleButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/two_buttons.xml b/tests/TransitionTests/res/layout/two_buttons.xml
new file mode 100644
index 0000000..23d59f8
--- /dev/null
+++ b/tests/TransitionTests/res/layout/two_buttons.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:id="@+id/container">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button1"/>
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/button2"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/unique_id_test.xml b/tests/TransitionTests/res/layout/unique_id_test.xml
new file mode 100644
index 0000000..9b7eb10
--- /dev/null
+++ b/tests/TransitionTests/res/layout/unique_id_test.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:id="@+id/container"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/username_taken.xml b/tests/TransitionTests/res/layout/username_taken.xml
new file mode 100644
index 0000000..9484e69
--- /dev/null
+++ b/tests/TransitionTests/res/layout/username_taken.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <Button
+            android:id="@+id/okay"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="164dp"
+            android:onClick="sendMessage"
+            android:text="@string/okay" />
+
+    <TextView
+            android:id="@+id/usernametaken"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_above="@+id/okay"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="93dp"
+            android:text="@string/username_taken"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <TextView
+            android:id="@+id/textView2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignTop="@+id/usernametaken"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="35dp"
+            android:text="@string/try_again"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/colorizer_transition.xml b/tests/TransitionTests/res/transition/colorizer_transition.xml
new file mode 100644
index 0000000..12f4be7
--- /dev/null
+++ b/tests/TransitionTests/res/transition/colorizer_transition.xml
@@ -0,0 +1,6 @@
+<recolor xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetId="@id/password"/>
+        <target android:targetId="@id/passwordEdit"/>
+    </targets>
+</recolor>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/fader.xml b/tests/TransitionTests/res/transition/fader.xml
new file mode 100644
index 0000000..c71fd94
--- /dev/null
+++ b/tests/TransitionTests/res/transition/fader.xml
@@ -0,0 +1 @@
+<fade/>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/login_slider_transition.xml b/tests/TransitionTests/res/transition/login_slider_transition.xml
new file mode 100644
index 0000000..2317857
--- /dev/null
+++ b/tests/TransitionTests/res/transition/login_slider_transition.xml
@@ -0,0 +1,22 @@
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <slide>
+        <targets>
+            <target android:targetId="@id/retype"/>
+            <target android:targetId="@id/retypeEdit"/>
+        </targets>
+    </slide>
+    <recolor>
+        <targets>
+            <target android:targetId="@id/password"/>
+            <target android:targetId="@id/passwordEdit"/>
+        </targets>
+    </recolor>
+    <fade/>
+</transitionSet>
+
+<!--
+                TransitionSet slider = new TransitionSet();
+        slider.addTransition(new Slide(R.id.retype, R.id.retypeEdit));
+        slider.addTransition(new Recolor(R.id.password, R.id.passwordEdit));
+        slider.addTransition(new Fade());
+-->
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/login_transition_mgr.xml b/tests/TransitionTests/res/transition/login_transition_mgr.xml
new file mode 100644
index 0000000..5d07be0
--- /dev/null
+++ b/tests/TransitionTests/res/transition/login_transition_mgr.xml
@@ -0,0 +1,14 @@
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition android:fromScene="@layout/activity_login" android:toScene="@layout/new_user"
+                android:transition="@transition/login_slider_transition"/>
+    <transition android:fromScene="@layout/login_password" android:toScene="@layout/new_user"
+                android:transition="@transition/login_slider_transition"/>
+    <transition android:fromScene="@layout/new_user" android:toScene="@layout/activity_login"
+                android:transition="@transition/login_slider_transition"/>
+    <transition android:fromScene="@layout/new_user" android:toScene="@layout/login_password"
+                android:transition="@transition/login_slider_transition"/>
+    <transition android:fromScene="@layout/activity_login" android:toScene="@layout/login_password"
+                android:transition="@transition/colorizer_transition"/>
+    <transition android:fromScene="@layout/login_password" android:toScene="@layout/activity_login"
+                android:transition="@transition/colorizer_transition"/>
+</transitionManager>
diff --git a/tests/TransitionTests/res/transition/mover.xml b/tests/TransitionTests/res/transition/mover.xml
new file mode 100644
index 0000000..b23d2a5
--- /dev/null
+++ b/tests/TransitionTests/res/transition/mover.xml
@@ -0,0 +1 @@
+<changeBounds/>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/mover_fader.xml b/tests/TransitionTests/res/transition/mover_fader.xml
new file mode 100644
index 0000000..ef11676
--- /dev/null
+++ b/tests/TransitionTests/res/transition/mover_fader.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <fade/>
+    <changeBounds/>
+</transitionSet>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/my_scene.xml b/tests/TransitionTests/res/transition/my_scene.xml
new file mode 100644
index 0000000..b8278c9
--- /dev/null
+++ b/tests/TransitionTests/res/transition/my_scene.xml
@@ -0,0 +1,3 @@
+<scene >
+
+</scene>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/my_transition.xml b/tests/TransitionTests/res/transition/my_transition.xml
new file mode 100644
index 0000000..022313c
--- /dev/null
+++ b/tests/TransitionTests/res/transition/my_transition.xml
@@ -0,0 +1,20 @@
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <fade></fade>
+    <transitionSet>
+        <changeBounds android:duration="500">
+            <targets>
+                <target android:targetId="@id/container"/>
+                <target android:targetId="@id/resultsList"/>
+            </targets>
+        </changeBounds>
+        <transitionSet>
+            <targets>
+                <target android:targetId="@id/container"/>
+                <target android:targetId="@id/resultsList"/>
+            </targets>
+            <fade android:startOffset="25"/>
+        </transitionSet>
+        <recolor/>
+    </transitionSet>
+    <changeBounds/>
+</transitionSet>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/my_transition_mgr.xml b/tests/TransitionTests/res/transition/my_transition_mgr.xml
new file mode 100644
index 0000000..5d8f799
--- /dev/null
+++ b/tests/TransitionTests/res/transition/my_transition_mgr.xml
@@ -0,0 +1,6 @@
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition android:fromScene="@layout/search_screen" android:toScene="@layout/results_screen"
+                android:transition="@transition/mover_fader"/>
+    <transition android:fromScene="@layout/results_screen" android:toScene="@layout/search_screen"
+                android:transition="@transition/mover_fader"/>
+</transitionManager>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/username_taken_scene.xml b/tests/TransitionTests/res/transition/username_taken_scene.xml
new file mode 100644
index 0000000..b2f050e
--- /dev/null
+++ b/tests/TransitionTests/res/transition/username_taken_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+       android:layout="@layout/username_taken"/>
\ No newline at end of file
diff --git a/tests/TransitionTests/res/values-v11/styles.xml b/tests/TransitionTests/res/values-v11/styles.xml
new file mode 100644
index 0000000..541752f
--- /dev/null
+++ b/tests/TransitionTests/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<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/TransitionTests/res/values-v14/styles.xml b/tests/TransitionTests/res/values-v14/styles.xml
new file mode 100644
index 0000000..f20e015
--- /dev/null
+++ b/tests/TransitionTests/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<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/tests/TransitionTests/res/values/strings.xml b/tests/TransitionTests/res/values/strings.xml
new file mode 100644
index 0000000..e3cff48
--- /dev/null
+++ b/tests/TransitionTests/res/values/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">StatesTest</string>
+    <string name="states_test1">StatesTestv21</string>
+    <string name="states_test_auto_targets">StatesTestAutoTargets</string>
+    <string name="states_test_auto_transition">StatesTestAutoTransition</string>
+    <string name="states_test_auto_transition2">StatesTestAutoTransition2</string>
+    <string name="contacts_expansion">ContactsExpansion</string>
+    <string name="states_test3">StatesTest3</string>
+    <string name="states_test4">StatesTest4</string>
+    <string name="states_test5">StatesTest5</string>
+    <string name="states_test6">StatesTest6</string>
+    <string name="button">Button</string>
+    <string name="searchButton">Search</string>
+    <string name="searchText">This is some text</string>
+    <string name="resultsTitle">Search Results</string>
+    <string name="placeholder">Blah Blah Blah</string>
+    <string name="username">Username:</string>
+    <string name="password">Password:</string>
+    <string name="retype">Retype:</string>
+    <string name="new_user">New User?</string>
+    <string name="incorrect_password">Incorrect password:</string>
+    <string name="try_again">Please try again.</string>
+    <string name="login_successful">Success!</string>
+    <string name="first_activity_screen">First activity screen</string>
+    <string name="username_taken">Username taken:</string>
+    <string name="cancel">Cancel</string>
+    <string name="submit">Submit</string>
+    <string name="okay">Okay</string>
+    <string name="reset">Reset</string>
+    <string name="fadingButton">Fading Button</string>
+    <string name="removingButton">Removing Button</string>
+    <string name="invisibleButton">invisible Button</string>
+    <string name="goneButton">Gone Button</string>
+    <string name="start">Start</string>
+    <string name="toggle">Toggle State</string>
+    <string name="someText">This is some text</string>
+    <string name="shortText1">This is some short text</string>
+    <string name="shortText2">Not much text here</string>
+    <string name="longText1">This is the beginning of the Spring of my discontent. In the event of a real emergency, you would be notified by email. Fear not, for death comes swiftly.</string>
+    <string name="longText2">When do we get to eat? I like all things, especially following strong leaders, and mangy cats. Break glass in emergency. The purpose of a framework is to provide the facilities and functionality of a powerful toolkit with the simplicity of a refrigerator.</string>
+    <string name="state1">State 1</string>
+    <string name="state2">State 2</string>
+    <string name="state3">State 3</string>
+    <string name="state4">State 4</string>
+    <string name="button0">Button 0</string>
+    <string name="button1">Button 1</string>
+    <string name="button2">Button 2</string>
+    <string name="button3">Button 3</string>
+    <string name="button4">Button 4</string>
+    <string name="button5">Button 5</string>
+    <string name="a">A</string>
+    <string name="b">B</string>
+    <string name="c">C</string>
+    <string name="reveal">Reveal</string>
+    <string name="crossfade">Crossfade</string>
+    <string name="inout">In/Out</string>
+    <string name="textfade1">CT</string>
+    <string name="textfade2">CTO</string>
+    <string name="textfade3">CTI</string>
+</resources>
diff --git a/tests/TransitionTests/res/values/styles.xml b/tests/TransitionTests/res/values/styles.xml
new file mode 100644
index 0000000..4a10ca4
--- /dev/null
+++ b/tests/TransitionTests/res/values/styles.xml
@@ -0,0 +1,20 @@
+<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/TransitionTests/src/com/android/transitiontests/ChangingText.java b/tests/TransitionTests/src/com/android/transitiontests/ChangingText.java
new file mode 100644
index 0000000..01d46b2
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ChangingText.java
@@ -0,0 +1,61 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.ChangeBounds;
+import android.transition.ChangeText;
+import android.transition.TransitionManager;
+
+public class ChangingText extends Activity {
+
+    Scene mScene1, mScene2;
+    ViewGroup mSceneRoot;
+    TransitionSet mChanger;
+    Scene mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.changing_text_1);
+
+        View container = findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.changing_text_1, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.changing_text_2, this);
+
+        mChanger = new TransitionSet().setOrdering(TransitionSet.ORDERING_TOGETHER);
+        mChanger.addTransition(new ChangeBounds()).addTransition(new ChangeText());
+
+        mCurrentScene = mScene1;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mScene1) {
+            TransitionManager.go(mScene2, mChanger);
+            mCurrentScene = mScene2;
+        } else {
+            TransitionManager.go(mScene1, mChanger);
+            mCurrentScene = mScene1;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ClippingText.java b/tests/TransitionTests/src/com/android/transitiontests/ClippingText.java
new file mode 100644
index 0000000..54c44e2
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ClippingText.java
@@ -0,0 +1,68 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.widget.Button;
+import android.transition.Fade;
+import android.transition.ChangeText;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+public class ClippingText extends Activity {
+
+    Button mRemovingButton, mInvisibleButton, mGoneButton;
+    Scene mScene1, mScene2;
+    ViewGroup mSceneRoot;
+    //    static Fade sFade = new Fade(R.id.removingButton, R.id.invisibleButton, R.id.goneButton);
+    Fade fader;
+    TransitionSet mChanger;
+    Scene mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.clipping_text_1);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.clipping_text_1, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.clipping_text_2, this);
+
+        mChanger = new TransitionSet().setOrdering(TransitionSet.ORDERING_TOGETHER);
+        ChangeBounds changeBounds = new ChangeBounds();
+        changeBounds.setResizeClip(true);
+        mChanger.addTransition(changeBounds).addTransition(new ChangeText());
+
+        mCurrentScene = mScene1;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mScene1) {
+            TransitionManager.go(mScene2, mChanger);
+            mCurrentScene = mScene2;
+        } else {
+            TransitionManager.go(mScene1, mChanger);
+            mCurrentScene = mScene1;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
new file mode 100644
index 0000000..f687da3
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
@@ -0,0 +1,124 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.transition.Crossfade;
+import android.transition.Rotate;
+import android.transition.TransitionManager;
+
+public class ContactsExpansion extends Activity {
+
+    String contactsData[] = {
+            "Alan Green", "56 Bob Street", "Boston, MA 02134", "617-555-5555", "blatt@blatt.com",
+            "Bob Foonman", "92 The Avenue", "Chico, CA 78456", "510-555-5556", "bob@jerk.com",
+            "Tracey Sue", "95 Houses Street", "San Jose, CA 96504", "415-555-5557", "ts@thing.com",
+    };
+
+    View currentItem = null;
+
+    TransitionSet mMyAutoTransition = new TransitionSet().
+            setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.contacts_list);
+        ViewGroup contactsContainer = (ViewGroup) findViewById(R.id.contactsContainer);
+
+        int contactsIndex = 0;
+        addContact(contactsContainer, contactsIndex, R.drawable.self_portrait_square_100);
+        contactsIndex += 5;
+        addContact(contactsContainer, contactsIndex, R.drawable.self_portrait_square_100);
+        contactsIndex += 5;
+        addContact(contactsContainer, contactsIndex, R.drawable.self_portrait_square_100);
+
+    }
+
+    private void addContact(ViewGroup container, int dataIndex, int thumbnailID) {
+        LayoutInflater inflater = (LayoutInflater)
+                getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View contactItem = inflater.inflate(R.layout.contact_collapsed, container, false);
+        ImageView thumbnailView = (ImageView) contactItem.findViewById(R.id.contact_picture);
+        thumbnailView.setImageResource(thumbnailID);
+        ((TextView)contactItem.findViewById(R.id.contact_name)).setText(contactsData[dataIndex++]);
+        ((TextView)contactItem.findViewById(R.id.contact_street)).
+                setText(contactsData[dataIndex++]);
+        ((TextView)contactItem.findViewById(R.id.contact_city)).setText(contactsData[dataIndex++]);
+        ((TextView)contactItem.findViewById(R.id.contact_phone)).setText(contactsData[dataIndex++]);
+        ((TextView)contactItem.findViewById(R.id.contact_email)).setText(contactsData[dataIndex++]);
+        container.addView(contactItem);
+
+        final TransitionSet myTransition = new TransitionSet();
+        myTransition.addTransition(new Fade(Fade.IN)).
+                addTransition(new Rotate().addTarget(R.id.contact_arrow)).
+                addTransition(new ChangeBounds()).
+                addTransition(new Fade(Fade.OUT)).
+                addTransition(new Crossfade().addTarget(R.id.contact_picture));
+        final ToggleScene toggleScene = new ToggleScene(container, myTransition);
+        contactItem.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                currentItem = v;
+                toggleScene.changeToScene();
+            }
+        });
+    }
+
+    class ToggleScene {
+        boolean expanded = false;
+        Scene mScene;
+        Transition mTransition;
+
+        ToggleScene(ViewGroup rootView, Transition transition) {
+            mScene = new Scene(rootView);
+            mTransition = transition;
+            mScene.setEnterAction(new Runnable() {
+                @Override
+                public void run() {
+                    if (currentItem != null) {
+                        System.out.println("onsceneChanged: currentItem = " + currentItem);
+                        View expandedContainer = currentItem.findViewById(R.id.expanded_info);
+                        expandedContainer.setVisibility(expanded ? View.GONE : View.VISIBLE);
+                        ImageView thumbnailView =
+                                (ImageView) currentItem.findViewById(R.id.contact_picture);
+                        thumbnailView.setImageResource(expanded ? R.drawable.self_portrait_square_100 :
+                                R.drawable.self_portrait_square_200);
+                        ImageView arrow = (ImageView) currentItem.findViewById(R.id.contact_arrow);
+                        arrow.setRotation(expanded ? 0 : 90);
+                        expanded = !expanded;
+                    }
+                }
+            });
+        }
+
+        void changeToScene() {
+            TransitionManager.go(mScene, mTransition);
+        }
+    };
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
new file mode 100644
index 0000000..5bb0e77
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
@@ -0,0 +1,69 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Crossfade;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class CrossFadeDemo extends Activity {
+
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+    Scene mScene1, mScene2;
+    TransitionManager mTransitionManager;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.crossfade);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.crossfade, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.crossfade_1, this);
+
+        Crossfade crossfade = new Crossfade();
+        crossfade.setFadeBehavior(Crossfade.FADE_BEHAVIOR_CROSSFADE);
+        crossfade.setResizeBehavior(Crossfade.RESIZE_BEHAVIOR_NONE);
+        crossfade.addTarget(R.id.textview).addTarget(R.id.textview1).
+                addTarget(R.id.textview2);
+        mTransitionManager = new TransitionManager();
+        TransitionSet moveCrossFade = new TransitionSet();
+        moveCrossFade.addTransition(crossfade).addTransition(new ChangeBounds());
+        mTransitionManager.setTransition(mScene1, moveCrossFade);
+        mTransitionManager.setTransition(mScene2, moveCrossFade);
+        mCurrentScene = 1;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == 1) {
+            mTransitionManager.transitionTo(mScene2);
+            mCurrentScene = 2;
+        } else {
+            mTransitionManager.transitionTo(mScene1);
+            mCurrentScene = 1;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
new file mode 100644
index 0000000..1f278b9
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
@@ -0,0 +1,68 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Crossfade;
+import android.transition.ChangeBounds;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+import android.widget.ImageView;
+
+public class CrossfadeImage extends Activity {
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+    Scene mScene1, mScene2;
+    TransitionManager mTransitionManager;
+    boolean mExpanded = false;
+    Transition mTransition;
+    ImageView mImageView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.crossfade_image);
+
+        ViewGroup container = (ViewGroup) findViewById(R.id.container);
+        mSceneRoot = container;
+
+        mImageView = (ImageView) findViewById(R.id.contact_picture);
+        mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+
+        Crossfade mCrossfade = new Crossfade();
+        mCrossfade.addTarget(R.id.contact_picture);
+
+        TransitionSet group = new TransitionSet();
+        group.setDuration(1500);
+        group.addTransition(mCrossfade).addTransition(new ChangeBounds());
+        mTransition = group;
+    }
+
+    public void sendMessage(View view) {
+        TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+        if (mExpanded) {
+            mImageView.setImageResource(R.drawable.self_portrait_square_100);
+        } else {
+            mImageView.setImageResource(R.drawable.self_portrait_square_200);
+        }
+        mExpanded = !mExpanded;
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
new file mode 100644
index 0000000..469ee8b
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
@@ -0,0 +1,146 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Crossfade;
+import android.transition.ChangeText;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import static android.widget.LinearLayout.LayoutParams;
+
+public class CrossfadeMultiple extends Activity {
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+    TransitionManager mTransitionManager;
+    Transition mTransition;
+    ImageView mImageView;
+    TextView mTextView;
+    Button mButton;
+    Crossfade mCrossfade;
+    TransitionSet mCrossfadeGroup;
+    TransitionSet mTextChangeGroup1, mTextChangeGroup2, mTextChangeGroup3;
+    TransitionSet mInOutGroup;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.crossfade_multiple);
+
+        ViewGroup container = (ViewGroup) findViewById(R.id.container);
+        mSceneRoot = container;
+
+        mButton = (Button) findViewById(R.id.button);
+        mImageView = (ImageView) findViewById(R.id.imageview);
+        mTextView = (TextView) findViewById(R.id.textview);
+
+        mCrossfade = new Crossfade();
+        mCrossfade.addTarget(R.id.button).addTarget(R.id.textview).addTarget(R.id.imageview);
+
+        mCrossfadeGroup = new TransitionSet();
+        mCrossfadeGroup.setDuration(300);
+        mCrossfadeGroup.addTransition(mCrossfade).addTransition(new ChangeBounds());
+        mTransition = mCrossfadeGroup;
+
+        mInOutGroup = new TransitionSet();
+        Crossfade inOut = new Crossfade();
+        inOut.setDuration(300);
+        inOut.setFadeBehavior(Crossfade.FADE_BEHAVIOR_OUT_IN);
+        ChangeBounds changeBounds = new ChangeBounds();
+        changeBounds.setStartDelay(150);
+        changeBounds.setDuration(0);
+        mInOutGroup.addTransition(inOut).addTransition(changeBounds);
+
+        mTextChangeGroup1 = new TransitionSet();
+        ChangeText changeTextInOut = new ChangeText();
+        changeTextInOut.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN);
+        mTextChangeGroup1.addTransition(changeTextInOut).addTransition(new ChangeBounds());
+
+        mTextChangeGroup2 = new TransitionSet();
+        mTextChangeGroup2.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        ChangeText changeTextOut = new ChangeText();
+        changeTextOut.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT);
+        mTextChangeGroup2.addTransition(changeTextOut).addTransition(new ChangeBounds());
+
+        mTextChangeGroup3 = new TransitionSet();
+        mTextChangeGroup3.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        ChangeText changeTextIn = new ChangeText();
+        changeTextIn.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_IN);
+        mTextChangeGroup3.addTransition(changeTextIn).addTransition(new ChangeBounds());
+    }
+
+    public void sendMessage(View view) {
+        TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+        int id = view.getId();
+        LayoutParams params = null;
+        switch (id) {
+            case R.id.button1:
+                params = new LayoutParams(200, 200);
+                mButton.setText("A");
+                mTextView.setText("1111111");
+                mImageView.setImageResource(R.drawable.self_portrait_square_100);
+                break;
+            case R.id.button2:
+                params = new LayoutParams(400, 200);
+                mButton.setText("B");
+                mTextView.setText("2222222");
+                mImageView.setImageResource(R.drawable.self_portrait_square_200);
+                break;
+            case R.id.button3:
+                params = new LayoutParams(200, 400);
+                mButton.setText("C");
+                mTextView.setText("3333333");
+                mImageView.setImageResource(R.drawable.self_portrait_square_400);
+                break;
+        }
+        mButton.setLayoutParams(params);
+    }
+
+    public void changeTransitionType(View view) {
+        int id = view.getId();
+        switch (id) {
+            case R.id.reveal:
+                mCrossfade.setFadeBehavior(Crossfade.FADE_BEHAVIOR_REVEAL);
+                mTransition = mCrossfadeGroup;
+                break;
+            case R.id.crossfade:
+                mCrossfade.setFadeBehavior(Crossfade.FADE_BEHAVIOR_CROSSFADE);
+                mTransition = mCrossfadeGroup;
+                break;
+            case R.id.inout:
+                mTransition = mInOutGroup;
+                break;
+            case R.id.textfade1:
+                mTransition = mTextChangeGroup1;
+                break;
+            case R.id.textfade2:
+                mTransition = mTextChangeGroup2;
+                break;
+            case R.id.textfade3:
+                mTransition = mTextChangeGroup3;
+                break;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/DelayedTransition.java b/tests/TransitionTests/src/com/android/transitiontests/DelayedTransition.java
new file mode 100644
index 0000000..fe5f05a
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/DelayedTransition.java
@@ -0,0 +1,66 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.TransitionManager;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import static android.widget.LinearLayout.LayoutParams;
+
+public class DelayedTransition extends Activity {
+
+    private static final int SEARCH_SCREEN = 0;
+    private static final int RESULTS_SCREEN = 1;
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.two_buttons);
+
+        final Button button1 = (Button) findViewById(R.id.button1);
+        final Button button2 = (Button) findViewById(R.id.button2);
+        final LinearLayout container = (LinearLayout) findViewById(R.id.container);
+        button1.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                int buttonWidth = button1.getWidth();
+                int containerWidth = container.getWidth();
+                if (buttonWidth < containerWidth) {
+                    TransitionManager.beginDelayedTransition(container, null);
+                    button1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                            LayoutParams.WRAP_CONTENT));
+                    TransitionManager.beginDelayedTransition(container, null);
+                    button2.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                            LayoutParams.MATCH_PARENT));
+                } else {
+                    TransitionManager.beginDelayedTransition(container, null);
+                    button1.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                            LayoutParams.WRAP_CONTENT));
+                    TransitionManager.beginDelayedTransition(container, null);
+                    button2.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                            LayoutParams.WRAP_CONTENT));
+                }
+            }
+        });
+    }
+
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo0.java b/tests/TransitionTests/src/com/android/transitiontests/Demo0.java
new file mode 100644
index 0000000..d52ab1d
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo0.java
@@ -0,0 +1,59 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+
+public class Demo0 extends Activity {
+
+    private static final int SEARCH_SCREEN = 0;
+    private static final int RESULTS_SCREEN = 1;
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mCurrentScene = SEARCH_SCREEN;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == RESULTS_SCREEN) {
+            mSceneRoot.removeAllViews();
+            LayoutInflater inflater = (LayoutInflater)
+                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            inflater.inflate(R.layout.search_screen, mSceneRoot);
+            mCurrentScene = SEARCH_SCREEN;
+        } else {
+            mSceneRoot.removeAllViews();
+            LayoutInflater inflater = (LayoutInflater)
+                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            inflater.inflate(R.layout.results_screen, mSceneRoot);
+            mCurrentScene = RESULTS_SCREEN;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
new file mode 100644
index 0000000..5b5eb15
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
@@ -0,0 +1,88 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.ChangeBounds;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class Demo1 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    boolean mFirstTime = true;
+    Scene mSearchScreen, mResultsScreen;
+    TransitionManager mTransitionManager = null;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+//        mResultsScreen = new MyScene(mSceneRoot, R.layout.results_screen);
+//        mSearchScreen = new MyScene(mSceneRoot, R.layout.search_screen);
+        mResultsScreen = new Scene(mSceneRoot);
+        mResultsScreen.setEnterAction(new Runnable() {
+            @Override
+            public void run() {
+                LayoutInflater inflater = (LayoutInflater)
+                        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                inflater.inflate(R.layout.results_screen, mSceneRoot);
+            }
+        });
+        mSearchScreen = new Scene(mSceneRoot);
+        mSearchScreen.setEnterAction(new Runnable() {
+            @Override
+            public void run() {
+                LayoutInflater inflater = (LayoutInflater)
+                        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                inflater.inflate(R.layout.search_screen, mSceneRoot);
+            }
+        });
+
+    }
+
+    public void sendMessage(View view) {
+        if (mFirstTime) {
+            mFirstTime = false;
+            TransitionSet transition = new TransitionSet();
+            transition.addTransition(new Fade().addTarget(R.id.resultsText).
+                    addTarget(R.id.resultsList)).
+                    addTransition(new ChangeBounds().addTarget(R.id.searchContainer));
+            mTransitionManager = new TransitionManager();
+            mTransitionManager.setTransition(mSearchScreen, transition);
+            mTransitionManager.setTransition(mResultsScreen, transition);
+        }
+        if (mCurrentScene == mResultsScreen) {
+            mTransitionManager.transitionTo(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            mTransitionManager.transitionTo(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
new file mode 100644
index 0000000..0f3257b
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
@@ -0,0 +1,76 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.ChangeBounds;
+import android.transition.Recolor;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+public class Demo2 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    boolean mFirstTime = true;
+    Scene mSearchScreen, mResultsScreen;
+    TransitionManager mTransitionManager = null;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+    }
+
+    public void sendMessage(View view) {
+        if (mFirstTime) {
+            mFirstTime = false;
+            // Non-resource approach of creating scenes
+//        mSearchScreen = new Scene(this, mSceneRoot, R.layout.search_screen);
+//        mResultsScreen = new Scene(this, mSceneRoot, R.layout.results_screen);
+            try {
+                mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+                mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+            } catch (Exception e) {
+                System.out.println("Problem loading scene resource: " + e);
+            }
+
+            TransitionSet transition = new TransitionSet();
+            transition.addTransition(new Fade().addTarget(R.id.resultsText).
+                    addTarget(R.id.resultsList)).
+                    addTransition(new ChangeBounds().addTarget(R.id.searchContainer)).
+                    addTransition(new Recolor().addTarget(R.id.container));
+            mTransitionManager = new TransitionManager();
+            mTransitionManager.setTransition(mSearchScreen, transition);
+            mTransitionManager.setTransition(mResultsScreen, transition);
+        }
+        if (mCurrentScene == mResultsScreen) {
+            mTransitionManager.transitionTo(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            mTransitionManager.transitionTo(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo3.java b/tests/TransitionTests/src/com/android/transitiontests/Demo3.java
new file mode 100644
index 0000000..0ffa1f5
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo3.java
@@ -0,0 +1,64 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.Recolor;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class Demo3 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    Scene mSearchScreen, mResultsScreen;
+    TransitionManager mTransitionManager = null;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+
+        TransitionSet transition = new TransitionSet();
+        transition.addTransition(new Fade()).addTransition(new ChangeBounds()).addTransition(new Recolor());
+
+        mTransitionManager = new TransitionManager();
+        mTransitionManager.setTransition(mSearchScreen, transition);
+        mTransitionManager.setTransition(mResultsScreen, transition);
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            mTransitionManager.transitionTo(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            mTransitionManager.transitionTo(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
new file mode 100644
index 0000000..3aadbb0
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
@@ -0,0 +1,75 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.Recolor;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class Demo4 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    Scene mSearchScreen, mResultsScreen;
+    TransitionManager mTransitionManager = null;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+
+        TransitionSet transitionToResults = new TransitionSet();
+        Fade fade = new Fade();
+        fade.addTarget(R.id.resultsText).addTarget(R.id.resultsList);
+        fade.setStartDelay(300);
+        fade.setDuration(1000);
+        transitionToResults.addTransition(fade).
+                addTransition(new ChangeBounds().addTarget(R.id.searchContainer)).
+                addTransition(new Recolor().addTarget(R.id.container));
+
+        TransitionSet transitionToSearch = new TransitionSet();
+        transitionToSearch.addTransition(fade).
+                addTransition(new ChangeBounds().addTarget(R.id.searchContainer)).
+                addTransition(new Recolor().addTarget(R.id.container));
+
+        mTransitionManager = new TransitionManager();
+        mTransitionManager.setTransition(mSearchScreen, transitionToSearch);
+        mTransitionManager.setTransition(mResultsScreen, transitionToResults);
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            mTransitionManager.transitionTo(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            mTransitionManager.transitionTo(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo5.java b/tests/TransitionTests/src/com/android/transitiontests/Demo5.java
new file mode 100644
index 0000000..c36abda
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo5.java
@@ -0,0 +1,53 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+
+
+public class Demo5 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    Scene mSearchScreen, mResultsScreen;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            TransitionManager.go(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            TransitionManager.go(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/FadingHierarchy.java b/tests/TransitionTests/src/com/android/transitiontests/FadingHierarchy.java
new file mode 100644
index 0000000..d497abe
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/FadingHierarchy.java
@@ -0,0 +1,53 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.TransitionManager;
+import android.widget.Button;
+
+public class FadingHierarchy extends Activity {
+
+    ViewGroup mRemovingContainer, mContainer;
+    Button mRemovingButton;
+    boolean mVisible = true;
+    ViewGroup mInnerContainerParent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.fading_hierarchy);
+
+        mContainer = (ViewGroup) findViewById(R.id.container);
+        mRemovingContainer = (ViewGroup) findViewById(R.id.removingContainer);
+        mInnerContainerParent = (ViewGroup) mRemovingContainer.getParent();
+
+        mRemovingButton = (Button) findViewById(R.id.removingButton);
+    }
+
+    public void sendMessage(View view) {
+        TransitionManager.beginDelayedTransition(mContainer, null);
+        if (mVisible) {
+            mInnerContainerParent.removeView(mRemovingContainer);
+        } else {
+            mInnerContainerParent.addView(mRemovingContainer);
+        }
+        mVisible = !mVisible;
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
new file mode 100644
index 0000000..29fb868
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.widget.Button;
+import android.transition.Fade;
+import android.transition.TransitionManager;
+
+
+public class FadingTest extends Activity {
+
+    Button mRemovingButton, mInvisibleButton, mGoneButton;
+    Scene mScene1, mScene2;
+    ViewGroup mSceneRoot;
+    static Fade sFade = new Fade();
+    Scene mCurrentScene;
+
+    static {
+        sFade.addTarget(R.id.removingButton).addTarget(R.id.invisibleButton).
+                addTarget(R.id.goneButton);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.fading_test);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+
+        mRemovingButton = (Button) findViewById(R.id.removingButton);
+        mInvisibleButton = (Button) findViewById(R.id.invisibleButton);
+        mGoneButton = (Button) findViewById(R.id.goneButton);
+
+        mGoneButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mGoneButton.setAlpha(mGoneButton.getAlpha() < 1 ? 1 : .6f);
+            }
+        });
+
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test_scene_2, this);
+
+        mCurrentScene = mScene1;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mScene1) {
+            TransitionManager.go(mScene2);
+            mCurrentScene = mScene2;
+        } else {
+            TransitionManager.go(mScene1);
+            mCurrentScene = mScene1;
+        }
+    }
+
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/HierarchicalMove.java b/tests/TransitionTests/src/com/android/transitiontests/HierarchicalMove.java
new file mode 100644
index 0000000..1146e20
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/HierarchicalMove.java
@@ -0,0 +1,108 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+import android.widget.Button;
+
+import static android.widget.LinearLayout.LayoutParams;
+
+public class HierarchicalMove extends Activity {
+
+    Button[] buttons = new Button[6];
+    ViewGroup mSceneRoot;
+    boolean wide = false;
+    Transition mTransition;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.hierarchical_move);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        buttons[0] = (Button) findViewById(R.id.button0);
+        buttons[1] = (Button) findViewById(R.id.button1);
+        buttons[2] = (Button) findViewById(R.id.button2);
+        buttons[3] = (Button) findViewById(R.id.button3);
+        buttons[4] = (Button) findViewById(R.id.button4);
+        buttons[5] = (Button) findViewById(R.id.button5);
+
+        // Move button0, then buttons 1/2 together, then buttons 3/4/5 sequentially:
+        // group (seq)
+        //    Move 0
+        //    group (seq)
+        //       group (together)
+        //          Move 1
+        //          Move 2
+        //       group (sequentially)
+        //          Move 3
+        //          Move 4/5
+        TransitionSet rootTransition = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+
+        // button0
+        Transition move0 = new ChangeBounds();
+        move0.addTarget(buttons[0]);
+
+        // buttons 1/2/3/4/5
+        TransitionSet group12345 = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+
+        // buttons 1/2
+        TransitionSet group12 = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_TOGETHER);
+        ChangeBounds changeBounds1 = new ChangeBounds();
+        changeBounds1.addTarget(buttons[1]);
+        ChangeBounds changeBounds2 = new ChangeBounds();
+        changeBounds2.addTarget(buttons[2]);
+        group12.addTransition(changeBounds1).addTransition(changeBounds2);
+
+        TransitionSet group345 = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        ChangeBounds changeBounds3 = new ChangeBounds();
+        changeBounds3.addTarget(buttons[3]);
+        ChangeBounds changeBounds45 = new ChangeBounds();
+        changeBounds45.addTarget(buttons[4]).addTarget(buttons[5]);
+        group345.addTransition(changeBounds3).addTransition(changeBounds45);
+
+        group12345.addTransition(move0).addTransition(group12).addTransition(group345);
+
+        rootTransition.addTransition(group12345);
+        rootTransition.setDuration(1000);
+        mTransition = rootTransition;
+
+    }
+
+    public void sendMessage(View view) {
+        TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+        int widthSpec = wide ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT;
+        LayoutParams params = new LayoutParams(widthSpec, LayoutParams.WRAP_CONTENT);
+        for (int i = 0; i < buttons.length; ++i) {
+            buttons[i].setLayoutParams(params);
+        }
+        wide = !wide;
+    }
+
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java b/tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java
new file mode 100644
index 0000000..9f19405
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java
@@ -0,0 +1,91 @@
+/*
+ * 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.transitiontests;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+
+public class HitRectBug extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(new TestDrawingView(this));
+    }
+
+    public static class TestDrawingView extends RelativeLayout
+    {
+        private Rect mRect = new Rect();
+        private Paint mPaint;
+        private ImageView mImageView;
+
+        public TestDrawingView(Context context)
+        {
+            super(context);
+            setWillNotDraw(false);
+
+            mPaint = new Paint();
+            mPaint.setColor(Color.RED);
+            mPaint.setStyle(Paint.Style.STROKE);
+
+            mImageView = new ImageView(context);
+            mImageView.setLeft(100);
+            mImageView.setRight(200);
+            mImageView.setImageResource(R.drawable.self_portrait_square);
+            mImageView.setScaleX(3);
+            mImageView.setScaleY(3);
+//            mImageView.setRotation(145);
+
+            ObjectAnimator anim = ObjectAnimator.ofFloat(mImageView, View.ROTATION, 0, 360);
+            anim.setRepeatCount(ValueAnimator.INFINITE);
+            anim.setDuration(5000);
+            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    invalidate();
+                }
+            });
+            anim.start();
+            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(128, 128);
+            params.addRule(RelativeLayout.CENTER_IN_PARENT);
+            addView(mImageView, params);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas)
+        {
+            super.onDraw(canvas);
+        }
+
+        @Override
+        protected void dispatchDraw(Canvas canvas) {
+            super.dispatchDraw(canvas);
+            mImageView.getHitRect(mRect);
+            canvas.drawRect(mRect, mPaint);
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java b/tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java
new file mode 100644
index 0000000..a06ba8f
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java
@@ -0,0 +1,60 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.ChangeBounds;
+import android.transition.TransitionManager;
+import android.widget.Button;
+
+import static android.widget.RelativeLayout.ALIGN_PARENT_LEFT;
+import static android.widget.RelativeLayout.ALIGN_PARENT_RIGHT;
+import static android.widget.RelativeLayout.LayoutParams;
+
+public class InstanceTargets extends Activity {
+
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.instance_targets);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container;
+    }
+
+    public void sendMessage(final View view) {
+        TransitionManager.beginDelayedTransition(mSceneRoot, new ChangeBounds().addTarget(view));
+        for (int i = 0; i < mSceneRoot.getChildCount(); ++i) {
+            Button button = (Button) mSceneRoot.getChildAt(i);
+            LayoutParams params = (LayoutParams) button.getLayoutParams();
+            int rules[] = params.getRules();
+            if (rules[ALIGN_PARENT_RIGHT] != 0) {
+                params.removeRule(ALIGN_PARENT_RIGHT);
+                params.addRule(ALIGN_PARENT_LEFT);
+            } else {
+                params.removeRule(ALIGN_PARENT_LEFT);
+                params.addRule(ALIGN_PARENT_RIGHT);
+            }
+            button.setLayoutParams(params);
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
new file mode 100644
index 0000000..c26e93f
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+import android.widget.RadioButton;
+
+public class InterruptionTest extends Activity {
+
+    RadioButton mScene1RB, mScene2RB, mScene3RB, mScene4RB;
+    private Scene mScene1;
+    private Scene mScene2;
+    private Scene mScene3;
+    private Scene mScene4;
+    TransitionSet mSequencedMove = new TransitionSet().
+            setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.interruption);
+
+        ViewGroup sceneRoot = (ViewGroup) findViewById(R.id.sceneRoot);
+
+        mScene1 = Scene.getSceneForLayout(sceneRoot, R.layout.interruption_inner_1, this);
+        mScene2 = Scene.getSceneForLayout(sceneRoot, R.layout.interruption_inner_2, this);
+        mScene3 = Scene.getSceneForLayout(sceneRoot, R.layout.interruption_inner_3, this);
+        mScene4 = Scene.getSceneForLayout(sceneRoot, R.layout.interruption_inner_4, this);
+
+        mScene1RB = (RadioButton) findViewById(R.id.scene1RB);
+        mScene2RB = (RadioButton) findViewById(R.id.scene2RB);
+        mScene3RB = (RadioButton) findViewById(R.id.scene3RB);
+        mScene4RB = (RadioButton) findViewById(R.id.scene4RB);
+
+        ChangeBounds changeBounds1 = new ChangeBounds();
+        changeBounds1.addTarget(R.id.button);
+        ChangeBounds changeBounds2 = new ChangeBounds();
+        changeBounds2.addTarget(R.id.button1);
+
+        mSequencedMove.addTransition(changeBounds1).addTransition(changeBounds2);
+        mSequencedMove.setDuration(1000);
+    }
+
+    public void onRadioButtonClicked(View clickedButton) {
+        if (clickedButton == mScene1RB) {
+            TransitionManager.go(mScene1, mSequencedMove);
+        } else if (clickedButton == mScene2RB) {
+            TransitionManager.go(mScene2, mSequencedMove);
+        } else if (clickedButton == mScene3RB) {
+            TransitionManager.go(mScene3, mSequencedMove);
+        } else {
+            TransitionManager.go(mScene4, mSequencedMove);
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
new file mode 100644
index 0000000..6629770
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
@@ -0,0 +1,167 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.transition.Fade;
+import android.transition.Scene;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.transition.AutoTransition;
+import android.transition.ChangeBounds;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ListViewAddRemove extends Activity {
+
+    final ArrayList<String> numList = new ArrayList<String>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.list_view_add_remove);
+
+        final LinearLayout container = (LinearLayout) findViewById(R.id.container);
+
+        final ListView listview = (ListView) findViewById(R.id.listview);
+        for (int i = 0; i < 200; ++i) {
+            numList.add(Integer.toString(i));
+        }
+        final StableArrayAdapter adapter = new StableArrayAdapter(this,
+                android.R.layout.simple_list_item_1, numList);
+        listview.setAdapter(adapter);
+
+        final ViewTreeObserver observer = container.getViewTreeObserver();
+        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+            public void onGlobalLayout() {
+                System.out.println("-------------------------------------");
+                System.out.println("onLayoutListener: listview view tops: ");
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    TextView view = (TextView) listview.getChildAt(i);
+                    System.out.println("    " + view.getText() + ": " + view.getTop());
+                }
+            }
+        });
+
+        final Scene mySceneChanger = new Scene(listview);
+
+        mySceneChanger.setEnterAction(new Runnable() {
+            @Override
+            public void run() {
+                numList.remove(mItemToDelete);
+                adapter.notifyDataSetChanged();
+            }
+        });
+        final Transition myTransition = new AutoTransition();
+        final TransitionSet noFadeIn = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        Fade fadeIn = new Fade(Fade.IN);
+        fadeIn.setDuration(50);
+        noFadeIn.addTransition(new Fade(Fade.OUT)).addTransition(new ChangeBounds()).addTransition(fadeIn);
+
+        myTransition.addListener(new Transition.TransitionListenerAdapter() {
+            @Override
+            public void onTransitionStart(Transition transition) {
+                System.out.println("---------ListView Tops: Before--------");
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    TextView view = (TextView) listview.getChildAt(i);
+                    int position = listview.getPositionForView(view);
+                }
+            }
+
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                System.out.println("---------ListView Tops: After--------");
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    TextView view = (TextView) listview.getChildAt(i);
+                    int position = listview.getPositionForView(view);
+                    if (view.hasTransientState()) {
+//                        view.setHasTransientState(false);
+                    }
+                }
+                myTransition.removeListener(this);
+            }
+        });
+
+        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+            @Override
+            public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
+                System.out.println("---------ListView Tops: OnClick--------");
+                String item = (String) parent.getItemAtPosition(position);
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    TextView v = (TextView) listview.getChildAt(i);
+                    if (!item.equals(v.getText())) {
+//                        v.setHasTransientState(true);
+                    }
+                }
+//                listview.setHasTransientState(true);
+                mItemToDelete = item;
+//                numList.remove(item);
+                TransitionManager.go(mySceneChanger, noFadeIn);
+//                view.postDelayed(new Runnable() {
+//                    @Override
+//                    public void run() {
+//                        for (int i = 0; i < listview.getChildCount(); ++i) {
+//                            TextView v = (TextView) listview.getChildAt(i);
+//                            v.setHasTransientState(false);
+//                        }
+//                    }
+//                }, 200);
+            }
+
+        });
+    }
+
+    String mItemToDelete = null;
+
+    private class StableArrayAdapter extends ArrayAdapter<String> {
+
+        HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
+
+        public StableArrayAdapter(Context context, int textViewResourceId,
+                List<String> objects) {
+            super(context, textViewResourceId, objects);
+            for (int i = 0; i < objects.size(); ++i) {
+                mIdMap.put(objects.get(i), i);
+            }
+        }
+
+        @Override
+        public long getItemId(int position) {
+            String item = getItem(position);
+            return mIdMap.get(item);
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java
new file mode 100644
index 0000000..4eeba4d
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java
@@ -0,0 +1,103 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ListViewAddRemoveNoTransition extends Activity {
+
+    final ArrayList<String> numList = new ArrayList<String>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.list_view_add_remove);
+
+        final LinearLayout container = (LinearLayout) findViewById(R.id.container);
+
+        final ListView listview = (ListView) findViewById(R.id.listview);
+        for (int i = 0; i < 200; ++i) {
+            numList.add(Integer.toString(i));
+        }
+        final StableArrayAdapter adapter = new StableArrayAdapter(this,
+                android.R.layout.simple_list_item_1, numList);
+        listview.setAdapter(adapter);
+
+        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+            @Override
+            public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
+                String item = (String) parent.getItemAtPosition(position);
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    TextView v = (TextView) listview.getChildAt(i);
+                    if (!item.equals(v.getText())) {
+                        v.setHasTransientState(true);
+                    }
+                }
+                numList.remove(item);
+                adapter.notifyDataSetChanged();
+                view.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        for (int i = 0; i < listview.getChildCount(); ++i) {
+                            TextView v = (TextView) listview.getChildAt(i);
+                            v.setHasTransientState(false);
+                        }
+                    }
+                }, 200);
+            }
+
+        });
+    }
+
+    private class StableArrayAdapter extends ArrayAdapter<String> {
+
+        HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
+
+        public StableArrayAdapter(Context context, int textViewResourceId,
+                List<String> objects) {
+            super(context, textViewResourceId, objects);
+            for (int i = 0; i < objects.size(); ++i) {
+                mIdMap.put(objects.get(i), i);
+            }
+        }
+
+        @Override
+        public long getItemId(int position) {
+            String item = getItem(position);
+            return mIdMap.get(item);
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
new file mode 100644
index 0000000..92bbb85
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
@@ -0,0 +1,105 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.widget.TextView;
+import android.transition.Fade;
+import android.transition.Recolor;
+import android.transition.Slide;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class LoginActivity extends Activity {
+    ViewGroup mSceneRoot;
+    Scene mCurrentScene;
+    TransitionManager mTransitionManager;
+    Scene mLoginScene, mPasswordScene, mIncorrectPasswordScene, mSuccessScene, mUsernameTakenScene,
+            mNewUserScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_login);
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mLoginScene = Scene.getSceneForLayout(mSceneRoot, R.layout.activity_login, this);
+        mPasswordScene = Scene.getSceneForLayout(mSceneRoot, R.layout.login_password, this);
+        mIncorrectPasswordScene = Scene.getSceneForLayout(mSceneRoot, R.layout.incorrect_password, this);
+        mUsernameTakenScene = Scene.getSceneForLayout(mSceneRoot, R.layout.username_taken, this);
+        mSuccessScene = Scene.getSceneForLayout(mSceneRoot, R.layout.success, this);
+        mNewUserScene = Scene.getSceneForLayout(mSceneRoot, R.layout.new_user, this);
+
+        mTransitionManager = new TransitionManager();
+
+        // Custom transitions in/out of NewUser screen - slide in the 2nd password UI
+        TransitionSet slider = new TransitionSet();
+        slider.addTransition(new Slide().addTarget(R.id.retype).addTarget(R.id.retypeEdit));
+        slider.addTransition(new Recolor().addTarget(R.id.password).
+                addTarget(R.id.passwordEdit));
+        slider.addTransition(new Fade());
+        mTransitionManager.setTransition(mLoginScene, mNewUserScene, slider);
+        mTransitionManager.setTransition(mPasswordScene, mNewUserScene, slider);
+        mTransitionManager.setTransition(mNewUserScene, mLoginScene, slider);
+        mTransitionManager.setTransition(mNewUserScene, mPasswordScene, slider);
+
+        // Custom transitions with recoloring password field
+        Transition colorizer = new Recolor().addTarget(R.id.password).
+                addTarget(R.id.passwordEdit);
+        mTransitionManager.setTransition(mLoginScene, mPasswordScene, colorizer);
+        mTransitionManager.setTransition(mPasswordScene, mLoginScene, colorizer);
+
+        mCurrentScene = mLoginScene;
+    }
+
+    public void applyScene(Scene scene) {
+        mTransitionManager.transitionTo(scene);
+        mCurrentScene = scene;
+    }
+
+    public void sendMessage(View view) {
+        TextView textView = (TextView) view;
+        CharSequence text = textView.getText();
+        if (text.equals("Cancel")) {
+            applyScene(mLoginScene);
+        } else if (text.equals("Submit")) {
+            if (mCurrentScene == mLoginScene) {
+                applyScene(mPasswordScene);
+            } else if (mCurrentScene == mPasswordScene) {
+                applyScene(Math.random() < .5 ? mSuccessScene : mIncorrectPasswordScene);
+            } else if (mCurrentScene == mNewUserScene) {
+                applyScene(Math.random() < .5 ? mSuccessScene : mUsernameTakenScene);
+            }
+        } else if (text.equals("New User?")) {
+            applyScene(mNewUserScene);
+        } else if (text.equals("Okay")) {
+            if (mCurrentScene == mIncorrectPasswordScene) {
+                applyScene(mPasswordScene);
+            } else { // username taken scene
+                applyScene(mNewUserScene);
+            }
+        } else if (text.equals("Reset")) {
+            applyScene(mLoginScene);
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java b/tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java
new file mode 100644
index 0000000..600c791
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java
@@ -0,0 +1,91 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionInflater;
+import android.widget.TextView;
+import android.transition.TransitionManager;
+
+
+public class LoginActivityFromResources extends Activity {
+    ViewGroup mSceneRoot;
+    Scene mCurrentScene;
+    TransitionManager mTransitionManager = null;
+    Scene mLoginScene, mPasswordScene, mIncorrectPasswordScene, mSuccessScene, mUsernameTakenScene,
+            mNewUserScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_login);
+        View container = findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+    }
+
+    public void applyScene(Scene scene) {
+        mTransitionManager.transitionTo(scene);
+        mCurrentScene = scene;
+    }
+
+    public void sendMessage(View view) {
+        if (mTransitionManager == null) {
+            TransitionInflater inflater = TransitionInflater.from(this);
+
+            mLoginScene = Scene.getSceneForLayout(mSceneRoot, R.layout.activity_login, this);
+            mPasswordScene = Scene.getSceneForLayout(mSceneRoot, R.layout.login_password, this);
+            mIncorrectPasswordScene = Scene.getSceneForLayout(mSceneRoot, R.layout
+                    .incorrect_password, this);
+            mUsernameTakenScene = Scene.getSceneForLayout(mSceneRoot, R.layout.username_taken, this);
+            mSuccessScene = Scene.getSceneForLayout(mSceneRoot, R.layout.success, this);
+            mNewUserScene = Scene.getSceneForLayout(mSceneRoot, R.layout.new_user, this);
+
+            mTransitionManager =
+                    inflater.inflateTransitionManager(R.transition.login_transition_mgr,
+                            mSceneRoot);
+
+            mCurrentScene = mLoginScene;
+        }
+        TextView textView = (TextView) view;
+        CharSequence text = textView.getText();
+        if (text.equals("Cancel")) {
+            applyScene(mLoginScene);
+        } else if (text.equals("Submit")) {
+            if (mCurrentScene == mLoginScene) {
+                applyScene(mPasswordScene);
+            } else if (mCurrentScene == mPasswordScene) {
+                applyScene(Math.random() < .5 ? mSuccessScene : mIncorrectPasswordScene);
+            } else if (mCurrentScene == mNewUserScene) {
+                applyScene(Math.random() < .5 ? mSuccessScene : mUsernameTakenScene);
+            }
+        } else if (text.equals("New User?")) {
+            applyScene(mNewUserScene);
+        } else if (text.equals("Okay")) {
+            if (mCurrentScene == mIncorrectPasswordScene) {
+                applyScene(mPasswordScene);
+            } else { // username taken scene
+                applyScene(mNewUserScene);
+            }
+        } else if (text.equals("Reset")) {
+            applyScene(mLoginScene);
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java b/tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java
new file mode 100644
index 0000000..ef8cd37
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+
+public class OverlayTest extends Activity {
+
+    ViewGroup mContainer;
+    ViewGroup mRoot;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.overlay_test);
+
+        mContainer = (ViewGroup) findViewById(R.id.container);
+        mRoot = (ViewGroup) mContainer.getParent();
+    }
+
+    public void onClick(View view) {
+        final Button fadingButton = (Button) findViewById(R.id.fadingButton);
+        if (fadingButton != null) {
+            mContainer.removeView(fadingButton);
+            mRoot.getOverlay().add(fadingButton);
+            fadingButton.animate().alpha(0).setDuration(1000).withEndAction(new Runnable() {
+                @Override
+                public void run() {
+                    fadingButton.setAlpha(1);
+                    mRoot.getOverlay().remove(fadingButton);
+                    mContainer.addView(fadingButton);
+                }
+            });
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Reparenting.java b/tests/TransitionTests/src/com/android/transitiontests/Reparenting.java
new file mode 100644
index 0000000..1ee8621
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Reparenting.java
@@ -0,0 +1,75 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.widget.Button;
+
+public class Reparenting extends Activity {
+
+    ViewGroup mSceneRoot;
+    ViewGroup mContainer1, mContainer2;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.reparenting);
+
+        ViewGroup container = (ViewGroup) findViewById(R.id.container);
+        mContainer1 = (ViewGroup) findViewById(R.id.container1);
+        mContainer2 = (ViewGroup) findViewById(R.id.container2);
+        System.out.println("container 1 and 2 " + mContainer1 + ", " + mContainer2);
+
+        setupButtons(0, mContainer1);
+        setupButtons(3, mContainer2);
+
+        mSceneRoot = container;
+    }
+
+    private void setupButtons(int startIndex, ViewGroup parent) {
+        for (int i = startIndex; i < (startIndex + 3); ++i) {
+            Button button = new Button(this);
+            button.setText(Integer.toString(i));
+            button.setOnClickListener(mButtonListener);
+            parent.addView(button);
+        }
+    }
+
+    private View.OnClickListener mButtonListener = new View.OnClickListener() {
+        @Override
+        public void onClick(final View v) {
+            Scene newScene = new Scene(mSceneRoot);
+            newScene.setEnterAction(new Runnable() {
+                @Override
+                public void run() {
+                    ViewGroup oldParent = (ViewGroup) v.getParent();
+                    ViewGroup newParent = oldParent == mContainer1 ? mContainer2 : mContainer1;
+                    oldParent.removeView(v);
+                    newParent.addView(v);
+                }
+            });
+            ChangeBounds reparent = new ChangeBounds();
+            reparent.setReparent(true);
+            TransitionManager.go(newScene, reparent);
+        }
+    };
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java b/tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java
new file mode 100644
index 0000000..1aee258
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionInflater;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+
+
+public class ResourceLoadingTest extends Activity {
+
+    private static final int SEARCH_SCREEN = 0;
+    private static final int RESULTS_SCREEN = 1;
+    ViewGroup mSceneRoot;
+    static int mCurrentScene;
+    TransitionManager mTransitionManager = null;
+    TransitionInflater mInflater;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mCurrentScene = SEARCH_SCREEN;
+
+        mInflater = TransitionInflater.from(this);
+    }
+
+    public void sendMessage(View view) {
+        if (mTransitionManager == null) {
+            try {
+                TransitionInflater inflater = TransitionInflater.from(this);
+                mTransitionManager =
+                        inflater.inflateTransitionManager(R.transition.my_transition_mgr,
+                                mSceneRoot);
+                Scene loadedScene = new Scene(mSceneRoot);
+                System.out.println("loadedScene = " + loadedScene);
+                Transition loadedTransition = inflater.inflateTransition(R.transition.my_transition);
+                System.out.println("loadedTransition = " + loadedTransition);
+            } catch (Exception e) {
+                System.out.println("Problem loading scene resource: " + e);
+            }
+        }
+        if (mCurrentScene == RESULTS_SCREEN) {
+            Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+            mTransitionManager.transitionTo(scene);
+            mCurrentScene = SEARCH_SCREEN;
+        } else {
+            Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+            mTransitionManager.transitionTo(scene);
+            mCurrentScene = RESULTS_SCREEN;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java
new file mode 100644
index 0000000..7504058
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java
@@ -0,0 +1,65 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.Recolor;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class ScenesTestAutoTargets extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    TransitionManager mTransitionManager = null;
+    Scene mResultsScreen, mSearchScreen;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+
+        TransitionSet transition = new TransitionSet();
+        transition.addTransition(new Fade()).addTransition(new ChangeBounds()).addTransition(new Recolor());
+
+        mTransitionManager = new TransitionManager();
+        mTransitionManager.setTransition(mSearchScreen, transition);
+        mTransitionManager.setTransition(mResultsScreen, transition);
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            mTransitionManager.transitionTo(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            mTransitionManager.transitionTo(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java
new file mode 100644
index 0000000..23b28ec
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java
@@ -0,0 +1,56 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.AutoTransition;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+
+
+public class ScenesTestAutoTransition extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    Transition mTransition = new AutoTransition();
+    Scene mResultsScreen, mSearchScreen;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            TransitionManager.go(mSearchScreen, mTransition);
+            mCurrentScene = mSearchScreen;
+        } else {
+            TransitionManager.go(mResultsScreen, mTransition);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java
new file mode 100644
index 0000000..5a9fa9d
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java
@@ -0,0 +1,54 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+
+
+public class ScenesTestAutoTransition2 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+
+    Scene mResultsScreen, mSearchScreen;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            TransitionManager.go(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            TransitionManager.go(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
new file mode 100644
index 0000000..ecf5ef3
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
@@ -0,0 +1,75 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Fade;
+import android.transition.Recolor;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+
+
+public class ScenesTestv21 extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    TransitionManager mTransitionManager = null;
+    Scene mResultsScreen, mSearchScreen;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search_screen);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mSearchScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.search_screen, this);
+        mResultsScreen = Scene.getSceneForLayout(mSceneRoot, R.layout.results_screen, this);
+
+        TransitionSet transitionToResults = new TransitionSet();
+        Fade fade = new Fade();
+        fade.addTarget(R.id.resultsText).addTarget(R.id.resultsList);
+        fade.setStartDelay(300);
+        transitionToResults.addTransition(fade);
+        transitionToResults.addTransition(new ChangeBounds().addTarget(R.id.searchContainer));
+        transitionToResults.addTransition(new Recolor().addTarget(R.id.container));
+
+        TransitionSet transitionToSearch = new TransitionSet();
+        transitionToSearch.addTransition(new Fade().addTarget(R.id.resultsText).
+                addTarget(R.id.resultsList));
+        transitionToSearch.addTransition(new ChangeBounds().addTarget(R.id.searchContainer));
+        transitionToSearch.addTransition(new Recolor().addTarget(R.id.container));
+        mTransitionManager = new TransitionManager();
+        mTransitionManager.setTransition(mSearchScreen, transitionToSearch);
+        mTransitionManager.setTransition(mResultsScreen, transitionToResults);
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mResultsScreen) {
+            mTransitionManager.transitionTo(mSearchScreen);
+            mCurrentScene = mSearchScreen;
+        } else {
+            mTransitionManager.transitionTo(mResultsScreen);
+            mCurrentScene = mResultsScreen;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
new file mode 100644
index 0000000..c550e92
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+import android.widget.Button;
+import android.transition.Fade;
+import android.transition.ChangeBounds;
+import android.transition.TransitionManager;
+
+
+public class SequenceTest extends Activity {
+
+    Button mRemovingButton, mInvisibleButton, mGoneButton;
+    Scene mScene1, mScene2;
+    ViewGroup mSceneRoot;
+    TransitionSet sequencedFade, reverseSequencedFade;
+    Scene mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.fading_test);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mRemovingButton = (Button) findViewById(R.id.removingButton);
+        mInvisibleButton = (Button) findViewById(R.id.invisibleButton);
+        mGoneButton = (Button) findViewById(R.id.goneButton);
+
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test_scene_2, this);
+
+        Transition fade1 = new Fade().addTarget(R.id.removingButton);
+        Transition fade2 = new Fade().addTarget(R.id.invisibleButton);
+        Transition fade3 = new Fade().addTarget(R.id.goneButton);
+        TransitionSet fader = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        fader.addTransition(fade1).addTransition(fade2).addTransition(fade3).
+                addTransition(new ChangeBounds());
+        sequencedFade = fader;
+
+        reverseSequencedFade = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        reverseSequencedFade.addTransition(new ChangeBounds()).addTransition(fade3).addTransition(fade2).
+                addTransition(fade1);
+
+        mCurrentScene = mScene1;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mScene1) {
+            TransitionManager.go(mScene2, sequencedFade);
+            mCurrentScene = mScene2;
+        } else {
+            TransitionManager.go(mScene1, reverseSequencedFade);
+            mCurrentScene = mScene1;
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
new file mode 100644
index 0000000..92b169e
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
@@ -0,0 +1,75 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.widget.Button;
+import android.transition.Fade;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+
+
+public class SequenceTestSimple extends Activity {
+
+    Button mRemovingButton, mInvisibleButton, mGoneButton;
+    Scene mScene1, mScene2;
+    ViewGroup mSceneRoot;
+    Transition sequencedFade;
+    TransitionSet sequencedFadeReverse;
+    Scene mCurrentScene;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.fading_test_simple);
+
+        View container = (View) findViewById(R.id.container);
+        mSceneRoot = (ViewGroup) container.getParent();
+
+        mRemovingButton = (Button) findViewById(R.id.removingButton);
+
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test_simple, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test_simple2, this);
+
+        TransitionSet fader = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        fader.addTransition(new Fade().addTarget(R.id.removingButton));
+        fader.addTransition(new ChangeBounds().addTarget(R.id.sceneSwitchButton));
+        sequencedFade = fader;
+
+        sequencedFadeReverse = new TransitionSet().
+                setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+        sequencedFadeReverse.addTransition(new ChangeBounds().addTarget(R.id.sceneSwitchButton));
+        sequencedFadeReverse.addTransition(new Fade().addTarget(R.id.removingButton));
+
+        mCurrentScene = mScene1;
+    }
+
+    public void sendMessage(View view) {
+        if (mCurrentScene == mScene1) {
+            TransitionManager.go(mScene2, sequencedFade);
+            mCurrentScene = mScene2;
+        } else {
+            TransitionManager.go(mScene1, sequencedFadeReverse);
+            mCurrentScene = mScene1;
+        }
+    }}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
new file mode 100644
index 0000000..9b246ad
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
@@ -0,0 +1,195 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Crossfade;
+import android.transition.ChangeBounds;
+import android.transition.Scene;
+import android.transition.TransitionSet;
+import android.transition.TransitionManager;
+import android.widget.Button;
+
+import static android.widget.LinearLayout.LayoutParams;
+
+public class SurfaceAndTextureViews extends Activity {
+
+    SimpleView mView;
+    SimpleSurfaceView mSurfaceView;
+    SimpleTextureView mTextureView;
+    private static final int SMALL_SIZE = 200;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.surface_texture_views);
+
+        final ViewGroup container = (ViewGroup) findViewById(R.id.container);
+        Button toggleButton = (Button) findViewById(R.id.toggleButton);
+
+        mView = new SimpleView(this);
+        mView.setId(0);
+        mView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+        container.addView(mView);
+
+        mSurfaceView = new SimpleSurfaceView(this);
+        mSurfaceView.setId(1);
+        mSurfaceView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+        container.addView(mSurfaceView);
+
+        mTextureView = new SimpleTextureView(this);
+        mTextureView.setId(2);
+        mTextureView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+        container.addView(mTextureView);
+
+        final TransitionSet transition = new TransitionSet();
+        transition.addTransition(new ChangeBounds()).addTransition(new Crossfade().addTarget(0).
+                addTarget(1).addTarget(2));
+
+        toggleButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Scene newScene = new Scene(container);
+                newScene.setEnterAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mView.getWidth() <= SMALL_SIZE) {
+                            mView.setLayoutParams(new LayoutParams(SMALL_SIZE * 2, SMALL_SIZE));
+                            mSurfaceView.setLayoutParams(new LayoutParams(SMALL_SIZE * 2, SMALL_SIZE));
+                            mTextureView.setLayoutParams(new LayoutParams(SMALL_SIZE * 2, SMALL_SIZE));
+                            mView.mColor = SimpleView.LARGE_COLOR;
+                            mSurfaceView.mColor = SimpleSurfaceView.LARGE_COLOR;
+                            mTextureView.mColor = SimpleTextureView.LARGE_COLOR;
+                        } else {
+                            mView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+                            mSurfaceView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+                            mTextureView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+                            mView.mColor = SimpleView.SMALL_COLOR;
+                            mSurfaceView.mColor = SimpleSurfaceView.SMALL_COLOR;
+                            mTextureView.mColor = SimpleTextureView.SMALL_COLOR;
+                        }
+                    }
+                });
+                TransitionManager.go(newScene, transition);
+            }
+        });
+
+    }
+
+    static private class SimpleView extends View {
+        static final int SMALL_COLOR = Color.BLUE;
+        static final int LARGE_COLOR = Color.YELLOW;
+        int mColor = SMALL_COLOR;
+
+        private SimpleView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            canvas.drawColor(mColor);
+        }
+    }
+
+    static private class SimpleSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+
+        static final int SMALL_COLOR = Color.GREEN;
+        static final int LARGE_COLOR = Color.GRAY;
+        int mColor = SMALL_COLOR;
+        SurfaceHolder mHolder = null;
+
+        private SimpleSurfaceView(Context context) {
+            super(context);
+            SurfaceHolder holder = getHolder();
+            holder.addCallback(this);
+        }
+
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            System.out.println("surfaceCreated");
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            System.out.println("surfaceChanged: w h = " + width + ", " + height);
+            Canvas canvas = holder.lockCanvas();
+            canvas.drawColor(mColor);
+            holder.unlockCanvasAndPost(canvas);
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            System.out.println("surfaceDestroyed");
+        }
+    }
+
+    static private class SimpleTextureView extends TextureView implements TextureView.SurfaceTextureListener {
+
+        static final int SMALL_COLOR = Color.RED;
+        static final int LARGE_COLOR = Color.CYAN;
+        int mColor = SMALL_COLOR;
+
+        private SimpleTextureView(Context context) {
+            super(context);
+            setSurfaceTextureListener(this);
+        }
+
+        private SimpleTextureView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            setSurfaceTextureListener(this);
+        }
+
+        private SimpleTextureView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+            setSurfaceTextureListener(this);
+        }
+
+        @Override
+        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+            System.out.println("SurfaceTexture available");
+        }
+
+        @Override
+        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+            System.out.println("SurfaceTexture size changed to " + width + ", " + height);
+            Canvas canvas = lockCanvas();
+            canvas.drawColor(mColor);
+            unlockCanvasAndPost(canvas);
+        }
+
+        @Override
+        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+            return false;
+        }
+
+        @Override
+        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+            System.out.println("SurfaceTexture updated");
+        }
+    }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java b/tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java
new file mode 100644
index 0000000..c824956
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java
@@ -0,0 +1,85 @@
+/*
+ * 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.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.transition.TransitionManager;
+
+
+import java.util.HashMap;
+
+public class UniqueIds extends Activity {
+    ViewGroup mSceneRoot;
+    static Scene mCurrentScene;
+    TransitionManager mTransitionManager = null;
+    HashMap<Button, ToggleScene> mSceneMap = new HashMap<Button, ToggleScene>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.unique_id_test);
+
+        LinearLayout container = (LinearLayout) findViewById(R.id.container);
+        LayoutInflater inflater = getLayoutInflater();
+        Button button = (Button) inflater.inflate(R.layout.button_template, null);
+        container.addView(button);
+        ToggleScene scene = new ToggleScene(container, button);
+        mSceneMap.put(button, scene);
+        button = (Button) inflater.inflate(R.layout.button_template, null);
+        container.addView(button);
+        scene = new ToggleScene(container, button);
+        mSceneMap.put(button, scene);
+    }
+
+    public void sendMessage(View view) {
+        mSceneMap.get(view).changeToScene();
+    }
+
+    class ToggleScene {
+        Scene mScene;
+        Transition mTransition;
+        Button mButton;
+
+        ToggleScene(ViewGroup rootView, Button button) {
+            mScene = new Scene(rootView);
+            mButton = button;
+            mScene.setEnterAction(new Runnable() {
+                @Override
+                public void run() {
+                    if (mButton.getLeft() == 0) {
+                        mButton.offsetLeftAndRight(500);
+                    } else {
+                        int width = mButton.getWidth();
+                        mButton.setLeft(0);
+                        mButton.setRight(width);
+                    }
+                }
+            });
+        }
+
+        void changeToScene() {
+            TransitionManager.go(mScene);
+        }
+    }
+}
diff --git a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
index b736e9f..9c2cf41 100644
--- a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
+++ b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
@@ -70,6 +70,8 @@
         // Test 1 :Tests that calls to onLoadLanguage( ) are delegated through to the
         // service without any caching or intermediate steps.
         mTts.setLanguage(new Locale("eng", "USA", "variant"));
+        LittleMock.verify(delegate, LittleMock.times(1)).onIsLanguageAvailable(
+                "eng", "USA", "variant");
         LittleMock.verify(delegate, LittleMock.times(1)).onLoadLanguage(
                 "eng", "USA", "variant");
     }
@@ -82,6 +84,8 @@
         // Test 2 : Tests that when the language is successfully set
         // like above (returns LANG_COUNTRY_AVAILABLE). That the
         // request language changes from that point on.
+        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable(
+                "eng", "USA", "variant");
         LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage(
                 "eng", "USA", "variant");
         mTts.setLanguage(new Locale("eng", "USA", "variant"));
@@ -103,6 +107,8 @@
         // TEST 3 : Tests that the language that is set does not change when the
         // engine reports it could not load the specified language.
         LittleMock.doReturn(TextToSpeech.LANG_NOT_SUPPORTED).when(
+                delegate).onIsLanguageAvailable("fra", "FRA", "");
+        LittleMock.doReturn(TextToSpeech.LANG_NOT_SUPPORTED).when(
                 delegate).onLoadLanguage("fra", "FRA", "");
         mTts.setLanguage(Locale.FRANCE);
         blockingCallSpeak("le fou barre", delegate);
@@ -116,38 +122,6 @@
         assertEquals("", req2.getValue().getVariant());
     }
 
-
-    public void testGetLanguage_invalidReturnValues() {
-        IDelegate delegate = LittleMock.mock(IDelegate.class);
-        MockableTextToSpeechService.setMocker(delegate);
-
-        // Test1: Simple end to end test. Ensure that bad return values
-        // are dealt with appropriately.
-        LittleMock.doReturn(null).when(delegate).onGetLanguage();
-        Locale returnVal = mTts.getLanguage();
-        assertNull(returnVal);
-
-
-        // Bad value 2. An array of length < 3.
-        LittleMock.doReturn(new String[] {"eng", "usa"}).when(delegate).onGetLanguage();
-        returnVal = mTts.getLanguage();
-        assertNull(returnVal);
-    }
-
-    public void testGetLanguage_validReturnValues() {
-        IDelegate delegate = LittleMock.mock(IDelegate.class);
-        MockableTextToSpeechService.setMocker(delegate);
-
-        // A correct value.
-        LittleMock.doReturn(new String[] {"eng", "usa", ""}).when(delegate).onGetLanguage();
-        Locale returnVal = mTts.getLanguage();
-
-        // Note: This is not the same as Locale.US . Well tough luck for
-        // being the only component of the entire framework that standardized
-        // three letter country and language codes.
-        assertEquals(new Locale("eng", "USA", ""), returnVal);
-    }
-
     public void testIsLanguageAvailable() {
         IDelegate delegate = LittleMock.mock(IDelegate.class);
         MockableTextToSpeechService.setMocker(delegate);
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 746ac06..e4c4214 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
         }
         
         try {
-            mWm.addAppToken(0, null, 0, 0, false, false);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -164,7 +164,7 @@
         }
         
         try {
-            mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, null, false);
+            mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
             fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -222,37 +222,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
-        try {
-            mWm.moveAppToken(0, null);
-            fail("IWindowManager.moveAppToken did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-        
-        try {
-            mWm.moveAppTokensToTop(null);
-            fail("IWindowManager.moveAppTokensToTop did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-        
-        try {
-            mWm.moveAppTokensToBottom(null);
-            fail("IWindowManager.moveAppTokensToBottom did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-	}    
+    }
 
     @SmallTest
     public void testDISABLE_KEYGUARD() {
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 9b1658a..452c60a 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -7,10 +7,8 @@
 # This tool is prebuilt if we're doing an app-only build.
 ifeq ($(TARGET_BUILD_APPS),)
 
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
+aapt_src_files := \
 	AaptAssets.cpp \
 	Command.cpp \
 	CrunchCache.cpp \
@@ -24,23 +22,29 @@
 	ResourceTable.cpp \
 	Images.cpp \
 	Resource.cpp \
+    pseudolocalize.cpp \
     SourcePos.cpp \
+	WorkQueue.cpp \
     ZipEntry.cpp \
-    ZipFile.cpp
+    ZipFile.cpp \
+	qsort_r_compat.c
 
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(aapt_src_files)
 
 LOCAL_CFLAGS += -Wno-format-y2k
 ifeq (darwin,$(HOST_OS))
 LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
 endif
 
+LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
 
 LOCAL_C_INCLUDES += external/libpng
 LOCAL_C_INCLUDES += external/zlib
-LOCAL_C_INCLUDES += build/libs/host/include
 
 LOCAL_STATIC_LIBRARIES := \
-	libhost \
 	libandroidfw \
 	libutils \
 	libcutils \
@@ -64,4 +68,36 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
+# aapt for running on the device
+# =========================================================
+ifneq ($(SDK_ONLY),true)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(aapt_src_files)
+
+LOCAL_MODULE := aapt
+
+LOCAL_C_INCLUDES += bionic
+LOCAL_C_INCLUDES += bionic/libstdc++/include
+LOCAL_C_INCLUDES += external/stlport/stlport
+LOCAL_C_INCLUDES += external/libpng
+LOCAL_C_INCLUDES += external/zlib
+
+LOCAL_CFLAGS += -Wno-non-virtual-dtor
+
+LOCAL_SHARED_LIBRARIES := \
+        libandroidfw \
+        libutils \
+        libcutils \
+        libpng \
+        liblog \
+        libz
+
+LOCAL_STATIC_LIBRARIES := \
+        libstlport_static \
+        libexpat_static
+
+include $(BUILD_EXECUTABLE)
+endif
+
 endif # TARGET_BUILD_APPS
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index cadac02..632efe0 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -346,6 +346,8 @@
     LABEL_ATTR = 0x01010001,
     ICON_ATTR = 0x01010002,
     NAME_ATTR = 0x01010003,
+    PERMISSION_ATTR = 0x01010006,
+    RESOURCE_ATTR = 0x01010025,
     DEBUGGABLE_ATTR = 0x0101000f,
     VERSION_CODE_ATTR = 0x0101021b,
     VERSION_NAME_ATTR = 0x0101021c,
@@ -372,6 +374,7 @@
     COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
     LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
     PUBLIC_KEY_ATTR = 0x010103a6,
+    CATEGORY_ATTR = 0x010103e8,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -424,6 +427,61 @@
     printf("\n");
 }
 
+Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
+        String8 *outError = NULL)
+{
+    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
+    if (aidAsset == NULL) {
+        if (outError != NULL) *outError = "xml resource does not exist";
+        return Vector<String8>();
+    }
+
+    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
+
+    bool withinApduService = false;
+    Vector<String8> categories;
+
+    String8 error;
+    ResXMLTree tree;
+    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
+
+    size_t len;
+    int depth = 0;
+    ResXMLTree::event_code_t code;
+    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+        if (code == ResXMLTree::END_TAG) {
+            depth--;
+            String8 tag(tree.getElementName(&len));
+
+            if (depth == 0 && tag == serviceTagName) {
+                withinApduService = false;
+            }
+
+        } else if (code == ResXMLTree::START_TAG) {
+            depth++;
+            String8 tag(tree.getElementName(&len));
+
+            if (depth == 1) {
+                if (tag == serviceTagName) {
+                    withinApduService = true;
+                }
+            } else if (depth == 2 && withinApduService) {
+                if (tag == "aid-group") {
+                    String8 category = getAttribute(tree, CATEGORY_ATTR, &error);
+                    if (error != "") {
+                        if (outError != NULL) *outError = error;
+                        return Vector<String8>();
+                    }
+
+                    categories.add(category);
+                }
+            }
+        }
+    }
+    aidAsset->close();
+    return categories;
+}
+
 /*
  * Handle the "dump" command, to extract select data from an archive.
  */
@@ -621,6 +679,7 @@
             bool isLauncherActivity = false;
             bool isSearchable = false;
             bool withinApplication = false;
+            bool withinSupportsInput = false;
             bool withinReceiver = false;
             bool withinService = false;
             bool withinIntentFilter = false;
@@ -630,12 +689,31 @@
             bool hasOtherServices = false;
             bool hasWallpaperService = false;
             bool hasImeService = false;
+            bool hasAccessibilityService = false;
+            bool hasPrintService = false;
             bool hasWidgetReceivers = false;
+            bool hasDeviceAdminReceiver = false;
             bool hasIntentFilter = false;
+            bool hasPaymentService = false;
             bool actMainActivity = false;
             bool actWidgetReceivers = false;
+            bool actDeviceAdminEnabled = false;
             bool actImeService = false;
             bool actWallpaperService = false;
+            bool actAccessibilityService = false;
+            bool actPrintService = false;
+            bool actHostApduService = false;
+            bool actOffHostApduService = false;
+            bool hasMetaHostPaymentCategory = false;
+            bool hasMetaOffHostPaymentCategory = false;
+
+            // These permissions are required by services implementing services
+            // the system binds to (IME, Accessibility, PrintServices, etc.)
+            bool hasBindDeviceAdminPermission = false;
+            bool hasBindInputMethodPermission = false;
+            bool hasBindAccessibilityServicePermission = false;
+            bool hasBindPrintServicePermission = false;
+            bool hasBindNfcServicePermission = false;
 
             // These two implement the implicit permissions that are granted
             // to pre-1.6 applications.
@@ -711,11 +789,26 @@
             String8 activityIcon;
             String8 receiverName;
             String8 serviceName;
+            Vector<String8> supportedInput;
             while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                 if (code == ResXMLTree::END_TAG) {
                     depth--;
                     if (depth < 2) {
+                        if (withinSupportsInput && !supportedInput.isEmpty()) {
+                            printf("supports-input: '");
+                            const size_t N = supportedInput.size();
+                            for (size_t i=0; i<N; i++) {
+                                printf("%s", supportedInput[i].string());
+                                if (i != N - 1) {
+                                    printf("' '");
+                                } else {
+                                    printf("'\n");
+                                }
+                            }
+                            supportedInput.clear();
+                        }
                         withinApplication = false;
+                        withinSupportsInput = false;
                     } else if (depth < 3) {
                         if (withinActivity && isMainActivity && isLauncherActivity) {
                             const char *aName = getComponentName(pkg, activityName);
@@ -731,6 +824,13 @@
                             hasOtherActivities |= withinActivity;
                             hasOtherReceivers |= withinReceiver;
                             hasOtherServices |= withinService;
+                        } else {
+                            if (withinService) {
+                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
+                                        hasBindNfcServicePermission);
+                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
+                                        hasBindNfcServicePermission);
+                            }
                         }
                         withinActivity = false;
                         withinService = false;
@@ -744,11 +844,18 @@
                                 hasOtherActivities |= !actMainActivity;
                             } else if (withinReceiver) {
                                 hasWidgetReceivers |= actWidgetReceivers;
-                                hasOtherReceivers |= !actWidgetReceivers;
+                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
+                                        hasBindDeviceAdminPermission);
+                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
                             } else if (withinService) {
                                 hasImeService |= actImeService;
                                 hasWallpaperService |= actWallpaperService;
-                                hasOtherServices |= (!actImeService && !actWallpaperService);
+                                hasAccessibilityService |= (actAccessibilityService &&
+                                        hasBindAccessibilityServicePermission);
+                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
+                                hasOtherServices |= (!actImeService && !actWallpaperService &&
+                                        !actAccessibilityService && !actPrintService &&
+                                        !actHostApduService && !actOffHostApduService);
                             }
                         }
                         withinIntentFilter = false;
@@ -910,6 +1017,8 @@
                             printf(" reqFiveWayNav='%d'", reqFiveWayNav);
                         }
                         printf("\n");
+                    } else if (tag == "supports-input") {
+                        withinSupportsInput = true;
                     } else if (tag == "supports-screens") {
                         smallScreen = getIntegerAttribute(tree,
                                 SMALL_SCREEN_ATTR, NULL, 1);
@@ -1086,73 +1195,175 @@
                             }
                         }
                     }
-                } else if (depth == 3 && withinApplication) {
+                } else if (depth == 3) {
                     withinActivity = false;
                     withinReceiver = false;
                     withinService = false;
                     hasIntentFilter = false;
-                    if(tag == "activity") {
-                        withinActivity = true;
-                        activityName = getAttribute(tree, NAME_ATTR, &error);
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
-                            goto bail;
-                        }
+                    hasMetaHostPaymentCategory = false;
+                    hasMetaOffHostPaymentCategory = false;
+                    hasBindDeviceAdminPermission = false;
+                    hasBindInputMethodPermission = false;
+                    hasBindAccessibilityServicePermission = false;
+                    hasBindPrintServicePermission = false;
+                    hasBindNfcServicePermission = false;
+                    if (withinApplication) {
+                        if(tag == "activity") {
+                            withinActivity = true;
+                            activityName = getAttribute(tree, NAME_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
 
-                        activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string());
-                            goto bail;
-                        }
+                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
 
-                        activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
-                            goto bail;
-                        }
+                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
 
-                        int32_t orien = getResolvedIntegerAttribute(&res, tree,
-                                SCREEN_ORIENTATION_ATTR, &error);
-                        if (error == "") {
-                            if (orien == 0 || orien == 6 || orien == 8) {
-                                // Requests landscape, sensorLandscape, or reverseLandscape.
-                                reqScreenLandscapeFeature = true;
-                            } else if (orien == 1 || orien == 7 || orien == 9) {
-                                // Requests portrait, sensorPortrait, or reversePortrait.
-                                reqScreenPortraitFeature = true;
+                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
+                                    SCREEN_ORIENTATION_ATTR, &error);
+                            if (error == "") {
+                                if (orien == 0 || orien == 6 || orien == 8) {
+                                    // Requests landscape, sensorLandscape, or reverseLandscape.
+                                    reqScreenLandscapeFeature = true;
+                                } else if (orien == 1 || orien == 7 || orien == 9) {
+                                    // Requests portrait, sensorPortrait, or reversePortrait.
+                                    reqScreenPortraitFeature = true;
+                                }
+                            }
+                        } else if (tag == "uses-library") {
+                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr,
+                                        "ERROR getting 'android:name' attribute for uses-library"
+                                        " %s\n", error.string());
+                                goto bail;
+                            }
+                            int req = getIntegerAttribute(tree,
+                                    REQUIRED_ATTR, NULL, 1);
+                            printf("uses-library%s:'%s'\n",
+                                    req ? "" : "-not-required", libraryName.string());
+                        } else if (tag == "receiver") {
+                            withinReceiver = true;
+                            receiverName = getAttribute(tree, NAME_ATTR, &error);
+
+                            if (error != "") {
+                                fprintf(stderr,
+                                        "ERROR getting 'android:name' attribute for receiver:"
+                                        " %s\n", error.string());
+                                goto bail;
+                            }
+
+                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
+                            if (error == "") {
+                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
+                                    hasBindDeviceAdminPermission = true;
+                                }
+                            } else {
+                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
+                                        " receiver '%s': %s\n", receiverName.string(), error.string());
+                            }
+                        } else if (tag == "service") {
+                            withinService = true;
+                            serviceName = getAttribute(tree, NAME_ATTR, &error);
+
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:name' attribute for"
+                                        " service: %s\n", error.string());
+                                goto bail;
+                            }
+
+                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
+                            if (error == "") {
+                                if (permission == "android.permission.BIND_INPUT_METHOD") {
+                                    hasBindInputMethodPermission = true;
+                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
+                                    hasBindAccessibilityServicePermission = true;
+                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
+                                    hasBindPrintServicePermission = true;
+                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
+                                    hasBindNfcServicePermission = true;
+                                }
+                            } else {
+                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
+                                        " service '%s': %s\n", serviceName.string(), error.string());
                             }
                         }
-                    } else if (tag == "uses-library") {
-                        String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string());
-                            goto bail;
-                        }
-                        int req = getIntegerAttribute(tree,
-                                REQUIRED_ATTR, NULL, 1);
-                        printf("uses-library%s:'%s'\n",
-                                req ? "" : "-not-required", libraryName.string());
-                    } else if (tag == "receiver") {
-                        withinReceiver = true;
-                        receiverName = getAttribute(tree, NAME_ATTR, &error);
-
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
-                            goto bail;
-                        }
-                    } else if (tag == "service") {
-                        withinService = true;
-                        serviceName = getAttribute(tree, NAME_ATTR, &error);
-
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:name' attribute for service: %s\n", error.string());
+                    } else if (withinSupportsInput && tag == "input-type") {
+                        String8 name = getAttribute(tree, NAME_ATTR, &error);
+                        if (name != "" && error == "") {
+                            supportedInput.add(name);
+                        } else {
+                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+                                    error.string());
                             goto bail;
                         }
                     }
-                } else if ((depth == 4) && (tag == "intent-filter")) {
-                    hasIntentFilter = true;
-                    withinIntentFilter = true;
-                    actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false;
+                } else if (depth == 4) {
+                    if (tag == "intent-filter") {
+                        hasIntentFilter = true;
+                        withinIntentFilter = true;
+                        actMainActivity = false;
+                        actWidgetReceivers = false;
+                        actImeService = false;
+                        actWallpaperService = false;
+                        actAccessibilityService = false;
+                        actPrintService = false;
+                        actDeviceAdminEnabled = false;
+                        actHostApduService = false;
+                        actOffHostApduService = false;
+                    } else if (withinService && tag == "meta-data") {
+                        String8 name = getAttribute(tree, NAME_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
+                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+                            goto bail;
+                        }
+
+                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
+                                name == "android.nfc.cardemulation.off_host_apdu_service") {
+                            bool offHost = true;
+                            if (name == "android.nfc.cardemulation.host_apdu_service") {
+                                offHost = false;
+                            }
+
+                            String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
+                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+                                goto bail;
+                            }
+
+                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
+                                    offHost, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
+                                        serviceName.string());
+                                goto bail;
+                            }
+
+                            const size_t catLen = categories.size();
+                            for (size_t i = 0; i < catLen; i++) {
+                                bool paymentCategory = (categories[i] == "payment");
+                                if (offHost) {
+                                    hasMetaOffHostPaymentCategory |= paymentCategory;
+                                } else {
+                                    hasMetaHostPaymentCategory |= paymentCategory;
+                                }
+                            }
+                        }
+                    }
                 } else if ((depth == 5) && withinIntentFilter){
                     String8 action;
                     if (tag == "action") {
@@ -1169,12 +1380,22 @@
                         } else if (withinReceiver) {
                             if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
                                 actWidgetReceivers = true;
+                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
+                                actDeviceAdminEnabled = true;
                             }
                         } else if (withinService) {
                             if (action == "android.view.InputMethod") {
                                 actImeService = true;
                             } else if (action == "android.service.wallpaper.WallpaperService") {
                                 actWallpaperService = true;
+                            } else if (action == "android.accessibilityservice.AccessibilityService") {
+                                actAccessibilityService = true;
+                            } else if (action == "android.printservice.PrintService") {
+                                actPrintService = true;
+                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
+                                actHostApduService = true;
+                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
+                                actOffHostApduService = true;
                             }
                         }
                         if (action == "android.intent.action.SEARCH") {
@@ -1374,12 +1595,24 @@
             if (hasWidgetReceivers) {
                 printf("app-widget\n");
             }
+            if (hasDeviceAdminReceiver) {
+                printf("device-admin\n");
+            }
             if (hasImeService) {
                 printf("ime\n");
             }
             if (hasWallpaperService) {
                 printf("wallpaper\n");
             }
+            if (hasAccessibilityService) {
+                printf("accessibility\n");
+            }
+            if (hasPrintService) {
+                printf("print\n");
+            }
+            if (hasPaymentService) {
+                printf("payment\n");
+            }
             if (hasOtherActivities) {
                 printf("other-activities\n");
             }
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 3930117..872d95c 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -8,10 +8,13 @@
 #include "ResourceTable.h"
 #include "ResourceFilter.h"
 
+#include <androidfw/misc.h>
+
 #include <utils/Log.h>
 #include <utils/threads.h>
 #include <utils/List.h>
 #include <utils/Errors.h>
+#include <utils/misc.h>
 
 #include <sys/types.h>
 #include <dirent.h>
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 6168bbd..08ad7a0 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -14,7 +14,7 @@
 #include "FileFinder.h"
 #include "CacheUpdater.h"
 
-#include <utils/WorkQueue.h>
+#include "WorkQueue.h"
 
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
@@ -172,6 +172,7 @@
 bool isValidResourceType(const String8& type)
 {
     return type == "anim" || type == "animator" || type == "interpolator"
+        || type == "transition"
         || type == "drawable" || type == "layout"
         || type == "values" || type == "xml" || type == "raw"
         || type == "color" || type == "menu" || type == "mipmap";
@@ -932,6 +933,7 @@
     sp<ResourceTypeSet> anims;
     sp<ResourceTypeSet> animators;
     sp<ResourceTypeSet> interpolators;
+    sp<ResourceTypeSet> transitions;
     sp<ResourceTypeSet> xmls;
     sp<ResourceTypeSet> raws;
     sp<ResourceTypeSet> colors;
@@ -943,6 +945,7 @@
     ASSIGN_IT(anim);
     ASSIGN_IT(animator);
     ASSIGN_IT(interpolator);
+    ASSIGN_IT(transition);
     ASSIGN_IT(xml);
     ASSIGN_IT(raw);
     ASSIGN_IT(color);
@@ -965,6 +968,7 @@
             !applyFileOverlay(bundle, assets, &anims, "anim") ||
             !applyFileOverlay(bundle, assets, &animators, "animator") ||
             !applyFileOverlay(bundle, assets, &interpolators, "interpolator") ||
+            !applyFileOverlay(bundle, assets, &transitions, "transition") ||
             !applyFileOverlay(bundle, assets, &xmls, "xml") ||
             !applyFileOverlay(bundle, assets, &raws, "raw") ||
             !applyFileOverlay(bundle, assets, &colors, "color") ||
@@ -1024,6 +1028,13 @@
         }
     }
 
+    if (transitions != NULL) {
+        err = makeFileResources(bundle, assets, &table, transitions, "transition");
+        if (err != NO_ERROR) {
+            hasErrors = true;
+        }
+    }
+
     if (interpolators != NULL) {
         err = makeFileResources(bundle, assets, &table, interpolators, "interpolator");
         if (err != NO_ERROR) {
@@ -1168,6 +1179,21 @@
         err = NO_ERROR;
     }
 
+    if (transitions != NULL) {
+        ResourceDirIterator it(transitions, String8("transition"));
+        while ((err=it.next()) == NO_ERROR) {
+            err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+            if (err != NO_ERROR) {
+                hasErrors = true;
+            }
+        }
+
+        if (err < NO_ERROR) {
+            hasErrors = true;
+        }
+        err = NO_ERROR;
+    }
+
     if (xmls != NULL) {
         ResourceDirIterator it(xmls, String8("xml"));
         while ((err=it.next()) == NO_ERROR) {
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 839eda5..158b391 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -9,7 +9,7 @@
 
 #include <utils/ByteOrder.h>
 #include <utils/SortedVector.h>
-#include <cutils/qsort_r_compat.h>
+#include "qsort_r_compat.h"
 
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 16050b2..1b3abfd 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -12,7 +12,6 @@
 
 #include <androidfw/ResourceTypes.h>
 #include <utils/String16.h>
-#include <utils/TextOutput.h>
 #include <utils/TypeHelpers.h>
 
 #include <sys/types.h>
diff --git a/tools/aapt/WorkQueue.cpp b/tools/aapt/WorkQueue.cpp
new file mode 100644
index 0000000..24a962f
--- /dev/null
+++ b/tools/aapt/WorkQueue.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "WorkQueue"
+
+#include <utils/Log.h>
+#include "WorkQueue.h"
+
+namespace android {
+
+// --- WorkQueue ---
+
+WorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) :
+        mMaxThreads(maxThreads), mCanCallJava(canCallJava),
+        mCanceled(false), mFinished(false), mIdleThreads(0) {
+}
+
+WorkQueue::~WorkQueue() {
+    if (!cancel()) {
+        finish();
+    }
+}
+
+status_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) {
+    AutoMutex _l(mLock);
+
+    if (mFinished || mCanceled) {
+        return INVALID_OPERATION;
+    }
+
+    if (mWorkThreads.size() < mMaxThreads
+            && mIdleThreads < mWorkUnits.size() + 1) {
+        sp<WorkThread> workThread = new WorkThread(this, mCanCallJava);
+        status_t status = workThread->run("WorkQueue::WorkThread");
+        if (status) {
+            return status;
+        }
+        mWorkThreads.add(workThread);
+        mIdleThreads += 1;
+    } else if (backlog) {
+        while (mWorkUnits.size() >= mMaxThreads * backlog) {
+            mWorkDequeuedCondition.wait(mLock);
+            if (mFinished || mCanceled) {
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
+    mWorkUnits.add(workUnit);
+    mWorkChangedCondition.broadcast();
+    return OK;
+}
+
+status_t WorkQueue::cancel() {
+    AutoMutex _l(mLock);
+
+    return cancelLocked();
+}
+
+status_t WorkQueue::cancelLocked() {
+    if (mFinished) {
+        return INVALID_OPERATION;
+    }
+
+    if (!mCanceled) {
+        mCanceled = true;
+
+        size_t count = mWorkUnits.size();
+        for (size_t i = 0; i < count; i++) {
+            delete mWorkUnits.itemAt(i);
+        }
+        mWorkUnits.clear();
+        mWorkChangedCondition.broadcast();
+        mWorkDequeuedCondition.broadcast();
+    }
+    return OK;
+}
+
+status_t WorkQueue::finish() {
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        if (mFinished) {
+            return INVALID_OPERATION;
+        }
+
+        mFinished = true;
+        mWorkChangedCondition.broadcast();
+    } // release lock
+
+    // It is not possible for the list of work threads to change once the mFinished
+    // flag has been set, so we can access mWorkThreads outside of the lock here.
+    size_t count = mWorkThreads.size();
+    for (size_t i = 0; i < count; i++) {
+        mWorkThreads.itemAt(i)->join();
+    }
+    mWorkThreads.clear();
+    return OK;
+}
+
+bool WorkQueue::threadLoop() {
+    WorkUnit* workUnit;
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (;;) {
+            if (mCanceled) {
+                return false;
+            }
+
+            if (!mWorkUnits.isEmpty()) {
+                workUnit = mWorkUnits.itemAt(0);
+                mWorkUnits.removeAt(0);
+                mIdleThreads -= 1;
+                mWorkDequeuedCondition.broadcast();
+                break;
+            }
+
+            if (mFinished) {
+                return false;
+            }
+
+            mWorkChangedCondition.wait(mLock);
+        }
+    } // release lock
+
+    bool shouldContinue = workUnit->run();
+    delete workUnit;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        mIdleThreads += 1;
+
+        if (!shouldContinue) {
+            cancelLocked();
+            return false;
+        }
+    } // release lock
+
+    return true;
+}
+
+// --- WorkQueue::WorkThread ---
+
+WorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) :
+        Thread(canCallJava), mWorkQueue(workQueue) {
+}
+
+WorkQueue::WorkThread::~WorkThread() {
+}
+
+bool WorkQueue::WorkThread::threadLoop() {
+    return mWorkQueue->threadLoop();
+}
+
+};  // namespace android
diff --git a/tools/aapt/WorkQueue.h b/tools/aapt/WorkQueue.h
new file mode 100644
index 0000000..d38f05d
--- /dev/null
+++ b/tools/aapt/WorkQueue.h
@@ -0,0 +1,119 @@
+/*]
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_WORK_QUEUE_H
+#define AAPT_WORK_QUEUE_H
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+/*
+ * A threaded work queue.
+ *
+ * This class is designed to make it easy to run a bunch of isolated work
+ * units in parallel, using up to the specified number of threads.
+ * To use it, write a loop to post work units to the work queue, then synchronize
+ * on the queue at the end.
+ */
+class WorkQueue {
+public:
+    class WorkUnit {
+    public:
+        WorkUnit() { }
+        virtual ~WorkUnit() { }
+
+        /*
+         * Runs the work unit.
+         * If the result is 'true' then the work queue continues scheduling work as usual.
+         * If the result is 'false' then the work queue is canceled.
+         */
+        virtual bool run() = 0;
+    };
+
+    /* Creates a work queue with the specified maximum number of work threads. */
+    WorkQueue(size_t maxThreads, bool canCallJava = true);
+
+    /* Destroys the work queue.
+     * Cancels pending work and waits for all remaining threads to complete.
+     */
+    ~WorkQueue();
+
+    /* Posts a work unit to run later.
+     * If the work queue has been canceled or is already finished, returns INVALID_OPERATION
+     * and does not take ownership of the work unit (caller must destroy it itself).
+     * Otherwise, returns OK and takes ownership of the work unit (the work queue will
+     * destroy it automatically).
+     *
+     * For flow control, this method blocks when the size of the pending work queue is more
+     * 'backlog' times the number of threads.  This condition reduces the rate of entry into
+     * the pending work queue and prevents it from growing much more rapidly than the
+     * work threads can actually handle.
+     *
+     * If 'backlog' is 0, then no throttle is applied.
+     */
+    status_t schedule(WorkUnit* workUnit, size_t backlog = 2);
+
+    /* Cancels all pending work.
+     * If the work queue is already finished, returns INVALID_OPERATION.
+     * If the work queue is already canceled, returns OK and does nothing else.
+     * Otherwise, returns OK, discards all pending work units and prevents additional
+     * work units from being scheduled.
+     *
+     * Call finish() after cancel() to wait for all remaining work to complete.
+     */
+    status_t cancel();
+
+    /* Waits for all work to complete.
+     * If the work queue is already finished, returns INVALID_OPERATION.
+     * Otherwise, waits for all work to complete and returns OK.
+     */
+    status_t finish();
+
+private:
+    class WorkThread : public Thread {
+    public:
+        WorkThread(WorkQueue* workQueue, bool canCallJava);
+        virtual ~WorkThread();
+
+    private:
+        virtual bool threadLoop();
+
+        WorkQueue* const mWorkQueue;
+    };
+
+    status_t cancelLocked();
+    bool threadLoop(); // called from each work thread
+
+    const size_t mMaxThreads;
+    const bool mCanCallJava;
+
+    Mutex mLock;
+    Condition mWorkChangedCondition;
+    Condition mWorkDequeuedCondition;
+
+    bool mCanceled;
+    bool mFinished;
+    size_t mIdleThreads;
+    Vector<sp<WorkThread> > mWorkThreads;
+    Vector<WorkUnit*> mWorkUnits;
+};
+
+}; // namespace android
+
+#endif // AAPT_WORK_QUEUE_H
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index dcbe7db..a663ad5 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -6,8 +6,8 @@
 
 #include "XMLNode.h"
 #include "ResourceTable.h"
+#include "pseudolocalize.h"
 
-#include <host/pseudolocalize.h>
 #include <utils/ByteOrder.h>
 #include <errno.h>
 #include <string.h>
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 3994c31..8057068 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -20,8 +20,8 @@
 
 #define LOG_TAG "zip"
 
+#include <androidfw/ZipUtils.h>
 #include <utils/Log.h>
-#include <utils/ZipUtils.h>
 
 #include "ZipFile.h"
 
diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp
new file mode 100644
index 0000000..9e50c5a
--- /dev/null
+++ b/tools/aapt/pseudolocalize.cpp
@@ -0,0 +1,119 @@
+#include "pseudolocalize.h"
+
+using namespace std;
+
+static const char*
+pseudolocalize_char(char c)
+{
+    switch (c) {
+        case 'a':   return "\xc4\x83";
+        case 'b':   return "\xcf\x84";
+        case 'c':   return "\xc4\x8b";
+        case 'd':   return "\xc4\x8f";
+        case 'e':   return "\xc4\x99";
+        case 'f':   return "\xc6\x92";
+        case 'g':   return "\xc4\x9d";
+        case 'h':   return "\xd1\x9b";
+        case 'i':   return "\xcf\x8a";
+        case 'j':   return "\xc4\xb5";
+        case 'k':   return "\xc4\xb8";
+        case 'l':   return "\xc4\xba";
+        case 'm':   return "\xe1\xb8\xbf";
+        case 'n':   return "\xd0\xb8";
+        case 'o':   return "\xcf\x8c";
+        case 'p':   return "\xcf\x81";
+        case 'q':   return "\x51";
+        case 'r':   return "\xd2\x91";
+        case 's':   return "\xc5\xa1";
+        case 't':   return "\xd1\x82";
+        case 'u':   return "\xce\xb0";
+        case 'v':   return "\x56";
+        case 'w':   return "\xe1\xba\x85";
+        case 'x':   return "\xd1\x85";
+        case 'y':   return "\xe1\xbb\xb3";
+        case 'z':   return "\xc5\xba";
+        case 'A':   return "\xc3\x85";
+        case 'B':   return "\xce\xb2";
+        case 'C':   return "\xc4\x88";
+        case 'D':   return "\xc4\x90";
+        case 'E':   return "\xd0\x84";
+        case 'F':   return "\xce\x93";
+        case 'G':   return "\xc4\x9e";
+        case 'H':   return "\xc4\xa6";
+        case 'I':   return "\xd0\x87";
+        case 'J':   return "\xc4\xb5";
+        case 'K':   return "\xc4\xb6";
+        case 'L':   return "\xc5\x81";
+        case 'M':   return "\xe1\xb8\xbe";
+        case 'N':   return "\xc5\x83";
+        case 'O':   return "\xce\x98";
+        case 'P':   return "\xcf\x81";
+        case 'Q':   return "\x71";
+        case 'R':   return "\xd0\xaf";
+        case 'S':   return "\xc8\x98";
+        case 'T':   return "\xc5\xa6";
+        case 'U':   return "\xc5\xa8";
+        case 'V':   return "\xce\xbd";
+        case 'W':   return "\xe1\xba\x84";
+        case 'X':   return "\xc3\x97";
+        case 'Y':   return "\xc2\xa5";
+        case 'Z':   return "\xc5\xbd";
+        default:    return NULL;
+    }
+}
+
+/**
+ * Converts characters so they look like they've been localized.
+ *
+ * Note: This leaves escape sequences untouched so they can later be
+ * processed by ResTable::collectString in the normal way.
+ */
+string
+pseudolocalize_string(const string& source)
+{
+    const char* s = source.c_str();
+    string result;
+    const size_t I = source.length();
+    for (size_t i=0; i<I; i++) {
+        char c = s[i];
+        if (c == '\\') {
+            if (i<I-1) {
+                result += '\\';
+                i++;
+                c = s[i];
+                switch (c) {
+                    case 'u':
+                        // this one takes up 5 chars
+                        result += string(s+i, 5);
+                        i += 4;
+                        break;
+                    case 't':
+                    case 'n':
+                    case '#':
+                    case '@':
+                    case '?':
+                    case '"':
+                    case '\'':
+                    case '\\':
+                    default:
+                        result += c;
+                        break;
+                }
+            } else {
+                result += c;
+            }
+        } else {
+            const char* p = pseudolocalize_char(c);
+            if (p != NULL) {
+                result += p;
+            } else {
+                result += c;
+            }
+        }
+    }
+
+    //printf("result=\'%s\'\n", result.c_str());
+    return result;
+}
+
+
diff --git a/tools/aapt/pseudolocalize.h b/tools/aapt/pseudolocalize.h
new file mode 100644
index 0000000..94cb034
--- /dev/null
+++ b/tools/aapt/pseudolocalize.h
@@ -0,0 +1,9 @@
+#ifndef HOST_PSEUDOLOCALIZE_H
+#define HOST_PSEUDOLOCALIZE_H
+
+#include <string>
+
+std::string pseudolocalize_string(const std::string& source);
+
+#endif // HOST_PSEUDOLOCALIZE_H
+
diff --git a/tools/aapt/qsort_r_compat.c b/tools/aapt/qsort_r_compat.c
new file mode 100644
index 0000000..2a8dbe8
--- /dev/null
+++ b/tools/aapt/qsort_r_compat.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "qsort_r_compat.h"
+
+/*
+ * Note: This code is only used on the host, and is primarily here for
+ * Mac OS compatibility. Apparently, glibc and Apple's libc disagree on
+ * the parameter order for qsort_r.
+ */
+
+#if HAVE_BSD_QSORT_R
+
+/*
+ * BSD qsort_r parameter order is as we have defined here.
+ */
+
+void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
+        int (*compar)(void*, const void* , const void*)) {
+    qsort_r(base, nel, width, thunk, compar);
+}
+
+#elif HAVE_GNU_QSORT_R
+
+/*
+ * GNU qsort_r parameter order places the thunk parameter last.
+ */
+
+struct compar_data {
+    void* thunk;
+    int (*compar)(void*, const void* , const void*);
+};
+
+static int compar_wrapper(const void* a, const void* b, void* data) {
+    struct compar_data* compar_data = (struct compar_data*)data;
+    return compar_data->compar(compar_data->thunk, a, b);
+}
+
+void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
+        int (*compar)(void*, const void* , const void*)) {
+    struct compar_data compar_data;
+    compar_data.thunk = thunk;
+    compar_data.compar = compar;
+    qsort_r(base, nel, width, compar_wrapper, &compar_data);
+}
+
+#else
+
+/*
+ * Emulate qsort_r using thread local storage to access the thunk data.
+ */
+
+#include <cutils/threads.h>
+
+static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER;
+
+struct compar_data {
+    void* thunk;
+    int (*compar)(void*, const void* , const void*);
+};
+
+static int compar_wrapper(const void* a, const void* b) {
+    struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key);
+    return compar_data->compar(compar_data->thunk, a, b);
+}
+
+void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
+        int (*compar)(void*, const void* , const void*)) {
+    struct compar_data compar_data;
+    compar_data.thunk = thunk;
+    compar_data.compar = compar;
+    thread_store_set(&compar_data_key, &compar_data, NULL);
+    qsort(base, nel, width, compar_wrapper);
+}
+
+#endif
diff --git a/tools/aapt/qsort_r_compat.h b/tools/aapt/qsort_r_compat.h
new file mode 100644
index 0000000..e14f999
--- /dev/null
+++ b/tools/aapt/qsort_r_compat.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Provides a portable version of qsort_r, called qsort_r_compat, which is a
+ * reentrant variant of qsort that passes a user data pointer to its comparator.
+ * This implementation follows the BSD parameter convention.
+ */
+
+#ifndef ___QSORT_R_COMPAT_H
+#define ___QSORT_R_COMPAT_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
+        int (*compar)(void*, const void* , const void* ));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ___QSORT_R_COMPAT_H
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 071a8d7..b8a4803 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -673,6 +673,16 @@
 
     fprintf(to, "\n");
 
+    // Output "<imported_file>: " so make won't fail if the imported file has
+    // been deleted, moved or renamed in incremental build.
+    import = g_imports;
+    while (import) {
+        if (import->filename) {
+            fprintf(to, "%s :\n", import->filename);
+        }
+        import = import->next;
+    }
+
     fclose(to);
 }
 
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index b27ce0e..4e73568 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -25,8 +25,8 @@
 # We need to process the framework classes.jar file, but we can't
 # depend directly on it (private vars won't be inherited correctly).
 # So, we depend on framework's BUILT file.
-built_framework_dep := $(call java-lib-deps,framework)
-built_framework_classes := $(call java-lib-files,framework)
+built_framework_dep := $(call java-lib-deps,framework-base)
+built_framework_classes := $(call java-lib-files,framework-base)
 
 built_core_dep := $(call java-lib-deps,core)
 built_core_classes := $(call java-lib-files,core)
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 3c124d9..2e4274d 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -7,5 +7,6 @@
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
+	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 687a91f..e3d48fc 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -22,6 +22,7 @@
 
 LOCAL_JAVA_LIBRARIES := \
 	kxml2-2.3.0 \
+	icu4j \
 	layoutlib_api-prebuilt \
 	tools-common-prebuilt
 
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..782ebfe
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..677b471
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..a1b8062
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..fcdbefe
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..633d864
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..4665e2a
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
new file mode 100644
index 0000000..62d0a0d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -0,0 +1,215 @@
+/*
+ * 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 android.graphics;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.ibm.icu.lang.UScript;
+import com.ibm.icu.lang.UScriptRun;
+
+import android.graphics.Paint_Delegate.FontInfo;
+
+/**
+ * Render the text by breaking it into various scripts and using the right font for each script.
+ * Can be used to measure the text without actually drawing it.
+ */
+@SuppressWarnings("deprecation")
+public class BidiRenderer {
+
+    /* package */ static class ScriptRun {
+        int start;
+        int limit;
+        boolean isRtl;
+        int scriptCode;
+        FontInfo font;
+
+        public ScriptRun(int start, int limit, boolean isRtl) {
+            this.start = start;
+            this.limit = limit;
+            this.isRtl = isRtl;
+            this.scriptCode = UScript.INVALID_CODE;
+        }
+    }
+
+    /* package */ Graphics2D graphics;
+    /* package */ Paint_Delegate paint;
+    /* package */ char[] text;
+
+    /**
+     * @param graphics May be null.
+     * @param paint The Paint to use to get the fonts. Should not be null.
+     * @param text Unidirectional text. Should not be null.
+     */
+    /* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
+        assert (paint != null);
+        this.graphics = graphics;
+        this.paint = paint;
+        this.text = text;
+    }
+
+    /**
+     * Render unidirectional text.
+     *
+     * This method can also be used to measure the width of the text without actually drawing it.
+     *
+     * @param start index of the first character
+     * @param limit index of the first character that should not be rendered.
+     * @param isRtl is the text right-to-left
+     * @param advances If not null, then advances for each character to be rendered are returned
+     *            here.
+     * @param advancesIndex index into advances from where the advances need to be filled.
+     * @param draw If true and {@link graphics} is not null, draw the rendered text on the graphics
+     *            at the given co-ordinates
+     * @param x The x-coordinate of the left edge of where the text should be drawn on the given
+     *            graphics.
+     * @param y The y-coordinate at which to draw the text on the given graphics.
+     * @return The x-coordinate of the right edge of the drawn text. In other words,
+     *            x + the width of the text.
+     */
+    /* package */ float renderText(int start, int limit, boolean isRtl, float advances[],
+            int advancesIndex, boolean draw, float x, float y) {
+        // We break the text into scripts and then select font based on it and then render each of
+        // the script runs.
+        for (ScriptRun run : getScriptRuns(text, start, limit, isRtl, paint.getFonts())) {
+            int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
+            flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
+            x = renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw,
+                    x, y);
+            advancesIndex += run.limit - run.start;
+        }
+        return x;
+    }
+
+    /**
+     * Render a script run. Use the preferred font to render as much as possible. This also
+     * implements a fallback mechanism to render characters that cannot be drawn using the
+     * preferred font.
+     *
+     * @return x + width of the text drawn.
+     */
+    private float renderScript(int start, int limit, FontInfo preferredFont, int flag,
+            float advances[], int advancesIndex, boolean draw, float x, float y) {
+        List<FontInfo> fonts = paint.getFonts();
+        if (fonts == null || preferredFont == null) {
+            return x;
+        }
+
+        while (start < limit) {
+            boolean foundFont = false;
+            int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(text, start, limit);
+            if (canDisplayUpTo == -1) {
+                return render(start, limit, preferredFont, flag, advances, advancesIndex, draw,
+                        x, y);
+            } else if (canDisplayUpTo > start) { // can draw something
+                x = render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex,
+                        draw, x, y);
+                advancesIndex += canDisplayUpTo - start;
+                start = canDisplayUpTo;
+            }
+
+            int charCount = Character.isHighSurrogate(text[start]) ? 2 : 1;
+            for (FontInfo font : fonts) {
+                canDisplayUpTo = font.mFont.canDisplayUpTo(text, start, start + charCount);
+                if (canDisplayUpTo == -1) {
+                    x = render(start, start+charCount, font, flag, advances, advancesIndex, draw,
+                            x, y);
+                    start += charCount;
+                    advancesIndex += charCount;
+                    foundFont = true;
+                    break;
+                }
+            }
+            if (!foundFont) {
+                // No font can display this char. Use the preferred font. The char will most
+                // probably appear as a box or a blank space. We could, probably, use some
+                // heuristics and break the character into the base character and diacritics and
+                // then draw it, but it's probably not worth the effort.
+                x = render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
+                        draw, x, y);
+                start += charCount;
+                advancesIndex += charCount;
+            }
+        }
+        return x;
+    }
+
+    /**
+     * Render the text with the given font.
+     */
+    private float render(int start, int limit, FontInfo font, int flag, float advances[],
+            int advancesIndex, boolean draw, float x, float y) {
+
+        float totalAdvance = 0;
+        // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with
+        // the anti-aliasing set.
+        FontRenderContext f = font.mMetrics.getFontRenderContext();
+        FontRenderContext frc = new FontRenderContext(f.getTransform(), paint.isAntiAliased(),
+                f.usesFractionalMetrics());
+        GlyphVector gv = font.mFont.layoutGlyphVector(frc, text, start, limit, flag);
+        int ng = gv.getNumGlyphs();
+        int[] ci = gv.getGlyphCharIndices(0, ng, null);
+        for (int i = 0; i < ng; i++) {
+            float adv = gv.getGlyphMetrics(i).getAdvanceX();
+            if (advances != null) {
+                int adv_idx = advancesIndex + ci[i];
+                advances[adv_idx] += adv;
+            }
+            totalAdvance += adv;
+        }
+        if (draw && graphics != null) {
+            graphics.drawGlyphVector(gv, x, y);
+        }
+        return x + totalAdvance;
+    }
+
+    // --- Static helper methods ---
+
+    /* package */  static List<ScriptRun> getScriptRuns(char[] text, int start, int limit,
+            boolean isRtl, List<FontInfo> fonts) {
+        LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>();
+
+        int count = limit - start;
+        UScriptRun uScriptRun = new UScriptRun(text, start, count);
+        while (uScriptRun.next()) {
+            int scriptStart = uScriptRun.getScriptStart();
+            int scriptLimit = uScriptRun.getScriptLimit();
+            ScriptRun run = new ScriptRun(scriptStart, scriptLimit, isRtl);
+            run.scriptCode = uScriptRun.getScriptCode();
+            setScriptFont(text, run, fonts);
+            scriptRuns.add(run);
+        }
+
+        return scriptRuns;
+    }
+
+    // TODO: Replace this method with one which returns the font based on the scriptCode.
+    private static void setScriptFont(char[] text, ScriptRun run,
+            List<FontInfo> fonts) {
+        for (FontInfo fontInfo : fonts) {
+            if (fontInfo.mFont.canDisplayUpTo(text, run.start, run.limit) == -1) {
+                run.font = fontInfo;
+                return;
+            }
+        }
+        run.font = fonts.get(0);
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 5256b58..04ce9d0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -24,10 +24,13 @@
 
 import android.content.res.BridgeResources.NinePatchInputStream;
 import android.graphics.BitmapFactory.Options;
+import android.graphics.Bitmap_Delegate.BitmapCreateFlags;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.EnumSet;
+import java.util.Set;
 
 /**
  * Delegate implementing the native methods of android.graphics.BitmapFactory
@@ -98,8 +101,12 @@
         //TODO support rescaling
 
         Density density = Density.MEDIUM;
+        Set<BitmapCreateFlags> bitmapCreateFlags = EnumSet.of(BitmapCreateFlags.MUTABLE);
         if (opts != null) {
             density = Density.getEnum(opts.inDensity);
+            if (opts.inPremultiplied) {
+                bitmapCreateFlags.add(BitmapCreateFlags.PREMULTIPLIED);
+            }
         }
 
         try {
@@ -112,7 +119,7 @@
                         npis, true /*is9Patch*/, false /*convert*/);
 
                 // get the bitmap and chunk objects.
-                bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
+                bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), bitmapCreateFlags,
                         density);
                 NinePatchChunk chunk = ninePatch.getChunk();
 
@@ -127,7 +134,7 @@
                 padding.bottom = paddingarray[3];
             } else {
                 // load the bitmap directly.
-                bm = Bitmap_Delegate.createBitmap(is, true, density);
+                bm = Bitmap_Delegate.createBitmap(is, bitmapCreateFlags, density);
             }
         } catch (IOException e) {
             Bridge.getLog().error(null,"Failed to load image" , e, null);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 96616aa..ec284ac 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -33,6 +33,8 @@
 import java.io.OutputStream;
 import java.nio.Buffer;
 import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Set;
 
 import javax.imageio.ImageIO;
 
@@ -51,6 +53,10 @@
  */
 public final class Bitmap_Delegate {
 
+    public enum BitmapCreateFlags {
+        PREMULTIPLIED, MUTABLE
+    }
+
     // ---- delegate manager ----
     private static final DelegateManager<Bitmap_Delegate> sManager =
             new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
@@ -93,10 +99,25 @@
      */
     public static Bitmap createBitmap(File input, boolean isMutable, Density density)
             throws IOException {
+        return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given file content.
+     *
+     * @param input the file from which to read the bitmap content
+     * @param density the density associated with the bitmap
+     *
+     * @see Bitmap#isPremultiplied()
+     * @see Bitmap#isMutable()
+     * @see Bitmap#getDensity()
+     */
+    public static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags,
+            Density density) throws IOException {
         // create a delegate with the content of the file.
         Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
 
-        return createBitmap(delegate, isMutable, density.getDpiValue());
+        return createBitmap(delegate, createFlags, density.getDpiValue());
     }
 
     /**
@@ -111,10 +132,26 @@
      */
     public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
             throws IOException {
+        return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given stream content.
+     *
+     * @param input the stream from which to read the bitmap content
+     * @param createFlags
+     * @param density the density associated with the bitmap
+     *
+     * @see Bitmap#isPremultiplied()
+     * @see Bitmap#isMutable()
+     * @see Bitmap#getDensity()
+     */
+    public static Bitmap createBitmap(InputStream input, Set<BitmapCreateFlags> createFlags,
+            Density density) throws IOException {
         // create a delegate with the content of the stream.
         Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
 
-        return createBitmap(delegate, isMutable, density.getDpiValue());
+        return createBitmap(delegate, createFlags, density.getDpiValue());
     }
 
     /**
@@ -129,10 +166,26 @@
      */
     public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
             Density density) throws IOException {
+        return createBitmap(image, getPremultipliedBitmapCreateFlags(isMutable), density);
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
+     *
+     * @param image the bitmap content
+     * @param createFlags
+     * @param density the density associated with the bitmap
+     *
+     * @see Bitmap#isPremultiplied()
+     * @see Bitmap#isMutable()
+     * @see Bitmap#getDensity()
+     */
+    public static Bitmap createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags,
+            Density density) throws IOException {
         // create a delegate with the given image.
         Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
 
-        return createBitmap(delegate, isMutable, density.getDpiValue());
+        return createBitmap(delegate, createFlags, density.getDpiValue());
     }
 
     /**
@@ -203,7 +256,7 @@
 
     @LayoutlibDelegate
     /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
-            int height, int nativeConfig, boolean mutable) {
+            int height, int nativeConfig, boolean isMutable) {
         int imageType = getBufferedImageType(nativeConfig);
 
         // create the image
@@ -216,7 +269,8 @@
         // create a delegate with the content of the stream.
         Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
 
-        return createBitmap(delegate, mutable, Bitmap.getDefaultDensity());
+        return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
+                            Bitmap.getDefaultDensity());
     }
 
     @LayoutlibDelegate
@@ -244,7 +298,8 @@
         // create a delegate with the content of the stream.
         Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
 
-        return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
+        return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
+                Bitmap.getDefaultDensity());
     }
 
     @LayoutlibDelegate
@@ -464,7 +519,7 @@
         Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
 
         // the density doesn't matter, it's set by the Java method.
-        return createBitmap(delegate, false /*isMutable*/,
+        return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.MUTABLE),
                 Density.DEFAULT_DENSITY /*density*/);
     }
 
@@ -546,13 +601,27 @@
         mConfig = config;
     }
 
-    private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
+    private static Bitmap createBitmap(Bitmap_Delegate delegate,
+            Set<BitmapCreateFlags> createFlags, int density) {
         // get its native_int
         int nativeInt = sManager.addNewDelegate(delegate);
 
+        int width = delegate.mImage.getWidth();
+        int height = delegate.mImage.getHeight();
+        boolean isMutable = createFlags.contains(BitmapCreateFlags.MUTABLE);
+        boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED);
+
         // and create/return a new Bitmap with it
-        return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/,
-                density);
+        return new Bitmap(nativeInt, null /* buffer */, width, height, density, isMutable,
+                          isPremultiplied, null /*ninePatchChunk*/, null /* layoutBounds */);
+    }
+
+    private static Set<BitmapCreateFlags> getPremultipliedBitmapCreateFlags(boolean isMutable) {
+        Set<BitmapCreateFlags> createFlags = EnumSet.of(BitmapCreateFlags.PREMULTIPLIED);
+        if (isMutable) {
+            createFlags.add(BitmapCreateFlags.MUTABLE);
+        }
+        return createFlags;
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 4171bb5..62b47bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -23,7 +23,6 @@
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.graphics.Bitmap.Config;
-import android.graphics.Paint_Delegate.FontInfo;
 import android.text.TextUtils;
 
 import java.awt.Color;
@@ -35,7 +34,6 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
 import java.awt.image.BufferedImage;
-import java.util.List;
 
 
 /**
@@ -978,7 +976,8 @@
     @LayoutlibDelegate
     /*package*/ static void native_drawText(int nativeCanvas,
             final char[] text, final int index, final int count,
-            final float startX, final float startY, int flags, int paint) {
+            final float startX, final float startY, final int flags, int paint) {
+
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
             @Override
@@ -988,10 +987,10 @@
                 // Paint.TextAlign indicates how the text is positioned relative to X.
                 // LEFT is the default and there's nothing to do.
                 float x = startX;
-                float y = startY;
+                int limit = index + count;
+                boolean isRtl = flags == Canvas.DIRECTION_RTL;
                 if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
-                    // TODO: check the value of bidiFlags.
-                    float m = paintDelegate.measureText(text, index, count, 0);
+                    float m = paintDelegate.measureText(text, index, count, isRtl);
                     if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
                         x -= m / 2;
                     } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
@@ -999,87 +998,15 @@
                     }
                 }
 
-                List<FontInfo> fonts = paintDelegate.getFonts();
-
-                if (fonts.size() > 0) {
-                    FontInfo mainFont = fonts.get(0);
-                    int i = index;
-                    int lastIndex = index + count;
-                    while (i < lastIndex) {
-                        // always start with the main font.
-                        int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
-                        if (upTo == -1) {
-                            // draw all the rest and exit.
-                            graphics.setFont(mainFont.mFont);
-                            graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y);
-                            return;
-                        } else if (upTo > 0) {
-                            // draw what's possible
-                            graphics.setFont(mainFont.mFont);
-                            graphics.drawChars(text, i, upTo - i, (int)x, (int)y);
-
-                            // compute the width that was drawn to increase x
-                            x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-
-                            // move index to the first non displayed char.
-                            i = upTo;
-
-                            // don't call continue at this point. Since it is certain the main font
-                            // cannot display the font a index upTo (now ==i), we move on to the
-                            // fallback fonts directly.
-                        }
-
-                        // no char supported, attempt to read the next char(s) with the
-                        // fallback font. In this case we only test the first character
-                        // and then go back to test with the main font.
-                        // Special test for 2-char characters.
-                        boolean foundFont = false;
-                        for (int f = 1 ; f < fonts.size() ; f++) {
-                            FontInfo fontInfo = fonts.get(f);
-
-                            // need to check that the font can display the character. We test
-                            // differently if the char is a high surrogate.
-                            int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                            upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
-                            if (upTo == -1) {
-                                // draw that char
-                                graphics.setFont(fontInfo.mFont);
-                                graphics.drawChars(text, i, charCount, (int)x, (int)y);
-
-                                // update x
-                                x += fontInfo.mMetrics.charsWidth(text, i, charCount);
-
-                                // update the index in the text, and move on
-                                i += charCount;
-                                foundFont = true;
-                                break;
-
-                            }
-                        }
-
-                        // in case no font can display the char, display it with the main font.
-                        // (it'll put a square probably)
-                        if (foundFont == false) {
-                            int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-
-                            graphics.setFont(mainFont.mFont);
-                            graphics.drawChars(text, i, charCount, (int)x, (int)y);
-
-                            // measure it to advance x
-                            x += mainFont.mMetrics.charsWidth(text, i, charCount);
-
-                            // and move to the next chars.
-                            i += charCount;
-                        }
-                    }
-                }
+                new BidiRenderer(graphics, paintDelegate, text).renderText(
+                        index, limit, isRtl, null, 0, true, x, startY);
             }
         });
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_drawText(int nativeCanvas, String text,
-            int start, int end, float x, float y, int flags, int paint) {
+            int start, int end, float x, float y, final int flags, int paint) {
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
@@ -1148,14 +1075,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPicture(int nativeCanvas,
-                                                  int nativePicture) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPicture is not supported.", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
     /*package*/ static void finalizer(int nativeCanvas) {
         // get the delegate from the native int so that it can be disposed.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index c9c9800..41953ed 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -32,7 +32,6 @@
 import java.awt.Toolkit;
 import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -576,7 +575,7 @@
             return 0;
         }
 
-        return delegate.measureText(text, index, count, bidiFlags);
+        return delegate.measureText(text, index, count, isRtl(bidiFlags));
     }
 
     @LayoutlibDelegate
@@ -615,7 +614,7 @@
             }
 
             // measure from start to end
-            float res = delegate.measureText(text, start, end - start + 1, bidiFlags);
+            float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
 
             if (measuredWidth != null) {
                 measuredWidth[measureIndex] = res;
@@ -980,51 +979,27 @@
     /*package*/ static float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
             int flags, float[] advances, int advancesIndex) {
+
+        if (advances != null)
+            for (int i = advancesIndex; i< advancesIndex+count; i++)
+                advances[i]=0;
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
+        if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
             return 0.f;
         }
+        boolean isRtl = isRtl(flags);
 
-        if (delegate.mFonts.size() > 0) {
-            // FIXME: handle multi-char characters (see measureText)
-            float totalAdvance = 0;
-            for (int i = 0; i < count; i++) {
-                char c = text[i + index];
-                boolean found = false;
-                for (FontInfo info : delegate.mFonts) {
-                    if (info.mFont.canDisplay(c)) {
-                        float adv = info.mMetrics.charWidth(c);
-                        totalAdvance += adv;
-                        if (advances != null) {
-                            advances[i] = adv;
-                        }
-
-                        found = true;
-                        break;
-                    }
-                }
-
-                if (found == false) {
-                    // no advance for this char.
-                    if (advances != null) {
-                        advances[i] = 0.f;
-                    }
-                }
-            }
-
-            return totalAdvance;
-        }
-
-        return 0;
-
+        int limit = index + count;
+        return new BidiRenderer(null, delegate, text).renderText(
+                index, limit, isRtl, advances, advancesIndex, false, 0, 0);
     }
 
     @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
             int flags, float[] advances, int advancesIndex) {
-        // FIXME: support contextStart, contextEnd and direction flag
+        // FIXME: support contextStart and contextEnd
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
@@ -1080,19 +1055,12 @@
 
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
+        if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
             return;
         }
-
-        // FIXME should test if the main font can display all those characters.
-        // See MeasureText
-        if (delegate.mFonts.size() > 0) {
-            FontInfo mainInfo = delegate.mFonts.get(0);
-
-            Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
-                    delegate.mFontContext);
-            bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
-        }
+        int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags));
+        int h= delegate.getFonts().get(0).mMetrics.getHeight();
+        bounds.set(0, 0, w, h);
     }
 
     @LayoutlibDelegate
@@ -1176,6 +1144,7 @@
                     info.mFont = info.mFont.deriveFont(new AffineTransform(
                             mTextScaleX, mTextSkewX, 0, 1, 0, 0));
                 }
+                // The metrics here don't have anti-aliasing set.
                 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
 
                 infoList.add(info);
@@ -1185,64 +1154,9 @@
         }
     }
 
-    /*package*/ float measureText(char[] text, int index, int count, int bidiFlags) {
-        // TODO: find out what bidiFlags actually does.
-
-        // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
-        // Any change to this method should be reflected there as well
-
-        if (mFonts.size() > 0) {
-            FontInfo mainFont = mFonts.get(0);
-            int i = index;
-            int lastIndex = index + count;
-            float total = 0f;
-            while (i < lastIndex) {
-                // always start with the main font.
-                int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
-                if (upTo == -1) {
-                    // shortcut to exit
-                    return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
-                } else if (upTo > 0) {
-                    total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-                    i = upTo;
-                    // don't call continue at this point. Since it is certain the main font
-                    // cannot display the font a index upTo (now ==i), we move on to the
-                    // fallback fonts directly.
-                }
-
-                // no char supported, attempt to read the next char(s) with the
-                // fallback font. In this case we only test the first character
-                // and then go back to test with the main font.
-                // Special test for 2-char characters.
-                boolean foundFont = false;
-                for (int f = 1 ; f < mFonts.size() ; f++) {
-                    FontInfo fontInfo = mFonts.get(f);
-
-                    // need to check that the font can display the character. We test
-                    // differently if the char is a high surrogate.
-                    int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                    upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
-                    if (upTo == -1) {
-                        total += fontInfo.mMetrics.charsWidth(text, i, charCount);
-                        i += charCount;
-                        foundFont = true;
-                        break;
-
-                    }
-                }
-
-                // in case no font can display the char, measure it with the main font.
-                if (foundFont == false) {
-                    int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                    total += mainFont.mMetrics.charsWidth(text, i, size);
-                    i += size;
-                }
-            }
-
-            return total;
-        }
-
-        return 0;
+    /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) {
+        return new BidiRenderer(null, this, text).renderText(
+                index, index + count, isRtl, null, 0, false, 0, 0);
     }
 
     private float getFontMetrics(FontMetrics metrics) {
@@ -1281,4 +1195,14 @@
         }
     }
 
+    private static boolean isRtl(int flag) {
+        switch(flag) {
+        case Paint.BIDI_RTL:
+        case Paint.BIDI_FORCE_RTL:
+        case Paint.BIDI_DEFAULT_RTL:
+            return true;
+        default:
+            return false;
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
index 52b8f34..973fa0e 100644
--- a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
@@ -16,7 +16,10 @@
 
 package android.text;
 
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.ibm.icu.text.Bidi;
 
 
 /**
@@ -29,9 +32,29 @@
 public class AndroidBidi_Delegate {
 
     @LayoutlibDelegate
-    /*package*/ static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) {
-        // return the equivalent of Layout.DIR_LEFT_TO_RIGHT
-        // TODO: actually figure the direction.
-        return 0;
+    /*package*/ static int runBidi(int dir, char[] chars, byte[] charInfo, int count,
+            boolean haveInfo) {
+
+        switch (dir) {
+        case 0: // Layout.DIR_REQUEST_LTR
+        case 1: // Layout.DIR_REQUEST_RTL
+            break;  // No change.
+        case -1:
+            dir = Bidi.LEVEL_DEFAULT_LTR;
+            break;
+        case -2:
+            dir = Bidi.LEVEL_DEFAULT_RTL;
+            break;
+        default:
+            // Invalid code. Log error, assume LEVEL_DEFAULT_LTR and continue.
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Invalid direction flag", null);
+            dir = Bidi.LEVEL_DEFAULT_LTR;
+        }
+        Bidi bidi = new Bidi(chars, 0, null, 0, count, dir);
+        if (charInfo != null) {
+            for (int i = 0; i < count; ++i)
+            charInfo[i] = bidi.getLevelAt(i);
+        }
+        return bidi.getParaLevel();
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 434b131..fd7a645 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -49,15 +49,13 @@
     private final Configuration mConfig;
     private final DisplayMetrics mMetrics;
     private final int mRotation;
-    private final boolean mHasSystemNavBar;
     private final boolean mHasNavigationBar;
 
     public IWindowManagerImpl(Configuration config, DisplayMetrics metrics, int rotation,
-            boolean hasSystemNavBar, boolean hasNavigationBar) {
+            boolean hasNavigationBar) {
         mConfig = config;
         mMetrics = metrics;
         mRotation = rotation;
-        mHasSystemNavBar = hasSystemNavBar;
         mHasNavigationBar = hasNavigationBar;
     }
 
@@ -79,16 +77,11 @@
         return mHasNavigationBar;
     }
 
-    @Override
-    public boolean hasSystemNavBar() throws RemoteException {
-        return mHasSystemNavBar;
-    }
-
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
-                            boolean arg5)
+    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
+            boolean arg5, boolean arg6, int arg7)
             throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -211,24 +204,6 @@
     }
 
     @Override
-    public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
@@ -322,7 +297,7 @@
 
     @Override
     public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
-            CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
+            CharSequence arg4, int arg5, int arg6, int arg7, int arg8, IBinder arg9, boolean arg10)
             throws RemoteException {
         // TODO Auto-generated method stub
     }
@@ -483,11 +458,6 @@
     }
 
     @Override
-    public void showAssistant() {
-
-    }
-
-    @Override
     public IBinder getFocusedWindowToken() {
         // TODO Auto-generated method stub
         return null;
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 3b66188..202f204 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -99,14 +99,6 @@
     public static void disablePlatformNotifications() {
     }
 
-    public WebBackForwardList saveState(Bundle outState) {
-        return null;
-    }
-
-    public WebBackForwardList restoreState(Bundle inState) {
-        return null;
-    }
-
     public void loadUrl(String url) {
     }
 
@@ -213,10 +205,6 @@
     public void clearSslPreferences() {
     }
 
-    public WebBackForwardList copyBackForwardList() {
-        return null;
-    }
-
     public static String findAddress(String addr) {
         return null;
     }
@@ -236,10 +224,6 @@
     public void addJavascriptInterface(Object obj, String interfaceName) {
     }
 
-    public WebSettings getSettings() {
-        return null;
-    }
-
     public View getZoomControls() {
         return null;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 42257c5..ab4be71 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -35,6 +35,7 @@
 import com.android.tools.layoutlib.create.MethodAdapter;
 import com.android.tools.layoutlib.create.OverrideMethod;
 import com.android.util.Pair;
+import com.ibm.icu.util.ULocale;
 
 import android.content.res.BridgeAssetManager;
 import android.graphics.Bitmap;
@@ -64,6 +65,8 @@
  */
 public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
 
+    private static final String ICU_LOCALE_DIRECTION_RTL = "right-to-left";
+
     public static class StaticMethodNotImplementedException extends RuntimeException {
         private static final long serialVersionUID = 1L;
 
@@ -211,7 +214,8 @@
                 Capability.ANIMATED_VIEW_MANIPULATION,
                 Capability.ADAPTER_BINDING,
                 Capability.EXTENDED_VIEWINFO,
-                Capability.FIXED_SCALABLE_NINE_PATCH);
+                Capability.FIXED_SCALABLE_NINE_PATCH,
+                Capability.RTL);
 
 
         BridgeAssetManager.initSystem();
@@ -411,6 +415,20 @@
         throw new IllegalArgumentException("viewObject is not a View");
     }
 
+    @Override
+    public boolean isRtl(String locale) {
+        return isLocaleRtl(locale);
+    }
+
+    public static boolean isLocaleRtl(String locale) {
+        if (locale == null) {
+            locale = "";
+        }
+        ULocale uLocale = new ULocale(locale);
+        return uLocale.getCharacterOrientation().equals(ICU_LOCALE_DIRECTION_RTL) ?
+                true : false;
+    }
+
     /**
      * Returns the lock for the bridge
      */
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 4aea38f..01740b1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -81,14 +81,16 @@
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(String callingPackage, Uri arg0, String arg1)
+    public AssetFileDescriptor openAssetFile(
+            String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
     }
 
     @Override
-    public ParcelFileDescriptor openFile(String callingPackage, Uri arg0, String arg1)
+    public ParcelFileDescriptor openFile(
+            String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
@@ -122,7 +124,7 @@
 
     @Override
     public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri arg0, String arg1,
-            Bundle arg2) throws RemoteException, FileNotFoundException {
+            Bundle arg2, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
     }
@@ -132,4 +134,14 @@
         // TODO Auto-generated method stub
         return null;
     }
+
+    @Override
+    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 21bef1c..b9294ab 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -67,8 +67,8 @@
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.view.BridgeInflater;
-import android.view.CompatibilityInfoHolder;
 import android.view.Display;
+import android.view.DisplayAdjustments;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -132,7 +132,8 @@
             RenderResources renderResources,
             IProjectCallback projectCallback,
             Configuration config,
-            int targetSdkVersion) {
+            int targetSdkVersion,
+            boolean hasRtlSupport) {
         mProjectKey = projectKey;
         mMetrics = metrics;
         mProjectCallback = projectCallback;
@@ -142,6 +143,9 @@
 
         mApplicationInfo = new ApplicationInfo();
         mApplicationInfo.targetSdkVersion = targetSdkVersion;
+        if (hasRtlSupport) {
+            mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL;
+        }
 
         mWindowManager = new WindowManagerImpl(mMetrics);
     }
@@ -1086,6 +1090,12 @@
     }
 
     @Override
+    public String getOpPackageName() {
+        // pass
+        return null;
+    }
+
+    @Override
     public ApplicationInfo getApplicationInfo() {
         return mApplicationInfo;
     }
@@ -1394,7 +1404,7 @@
     }
 
     @Override
-    public CompatibilityInfoHolder getCompatibilityInfo(int displayId) {
+    public DisplayAdjustments getDisplayAdjustments(int displayId) {
         // pass
         return null;
     }
@@ -1406,4 +1416,22 @@
     public int getUserId() {
         return 0; // not used
     }
+
+    @Override
+    public File[] getExternalFilesDirs(String type) {
+        // pass
+        return new File[0];
+    }
+
+    @Override
+    public File[] getObbDirs() {
+        // pass
+        return new File[0];
+    }
+
+    @Override
+    public File[] getExternalCacheDirs() {
+        // pass
+        return new File[0];
+    }
 }
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 d6abbaa..3cf5ed5 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
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo arg0,
+    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String arg0,
             boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
@@ -203,6 +203,12 @@
     }
 
     @Override
+        public boolean shouldOfferSwitchingToNextInputMethod(IBinder arg0) throws RemoteException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
     public void updateStatusIcon(IBinder arg0, String arg1, int arg2) 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 1ccbc40..6fd5acc 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
@@ -39,7 +39,7 @@
     }
 
     @Override
-    public void acquireWakeLock(IBinder arg0, int arg1, String arg2, WorkSource arg3)
+    public void acquireWakeLock(IBinder arg0, int arg1, String arg2, String arg2_5, WorkSource arg3)
             throws RemoteException {
         // pass for now.
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index ea9d8d9..17b0eb6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -25,6 +25,7 @@
 import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.resources.Density;
+import com.android.resources.LayoutDirection;
 import com.android.resources.ResourceType;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -86,38 +87,53 @@
         }
     }
 
-    private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
-            boolean tryOtherDensities) {
+    private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction, 
+            String[] pathOut, boolean tryOtherDensities) {
         // current density
         Density density = densityInOut[0];
 
         // bitmap url relative to this class
-        pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
+        if (direction != null) {
+            pathOut[0] = "/bars/" + direction.getResourceValue() + "-" + density.getResourceValue()
+                    + "/" + iconName;
+        } else {
+            pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
+        }
 
         InputStream stream = getClass().getResourceAsStream(pathOut[0]);
         if (stream == null && tryOtherDensities) {
             for (Density d : Density.values()) {
                 if (d != density) {
                     densityInOut[0] = d;
-                    stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
+                    stream = getIcon(iconName, densityInOut, direction, pathOut,
+                            false /*tryOtherDensities*/);
                     if (stream != null) {
                         return stream;
                     }
                 }
             }
+            // couldn't find resource with direction qualifier. try without.
+            if (direction != null) {
+                return getIcon(iconName, densityInOut, null, pathOut, true);
+            }
         }
 
         return stream;
     }
 
     protected void loadIcon(int index, String iconName, Density density) {
+        loadIcon(index, iconName, density, false);
+    }
+
+    protected void loadIcon(int index, String iconName, Density density, boolean isRtl) {
         View child = getChildAt(index);
         if (child instanceof ImageView) {
             ImageView imageView = (ImageView) child;
 
             String[] pathOut = new String[1];
             Density[] densityInOut = new Density[] { density };
-            InputStream stream = getIcon(iconName, densityInOut, pathOut,
+            LayoutDirection dir = isRtl ? LayoutDirection.RTL : LayoutDirection.LTR;
+            InputStream stream = getIcon(iconName, densityInOut, dir, pathOut,
                     true /*tryOtherDensities*/);
             density = densityInOut[0];
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index cc90d6b..84e676e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -17,6 +17,7 @@
 package com.android.layoutlib.bridge.bars;
 
 import com.android.resources.Density;
+import com.android.layoutlib.bridge.Bridge;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -26,7 +27,8 @@
 
 public class NavigationBar extends CustomBar {
 
-    public NavigationBar(Context context, Density density, int orientation) throws XmlPullParserException {
+    public NavigationBar(Context context, Density density, int orientation, boolean isRtl,
+            boolean rtlEnabled) throws XmlPullParserException {
         super(context, density, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml");
 
         setBackgroundColor(0xFF000000);
@@ -37,14 +39,15 @@
         // 0 is a spacer.
         int back = 1;
         int recent = 3;
-        if (orientation == LinearLayout.VERTICAL) {
+        if (orientation == LinearLayout.VERTICAL || (isRtl && !rtlEnabled)) {
+            // If RTL is enabled, then layoutlib mirrors the layout for us.
             back = 3;
             recent = 1;
         }
 
-        loadIcon(back,   "ic_sysbar_back.png", density);
-        loadIcon(2,      "ic_sysbar_home.png", density);
-        loadIcon(recent, "ic_sysbar_recent.png", density);
+        loadIcon(back,   "ic_sysbar_back.png",   density, isRtl);
+        loadIcon(2,      "ic_sysbar_home.png",   density, isRtl);
+        loadIcon(recent, "ic_sysbar_recent.png", density, isRtl);
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 5c08412..baa956d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -30,7 +30,10 @@
 
 public class StatusBar extends CustomBar {
 
-    public StatusBar(Context context, Density density) throws XmlPullParserException {
+    public StatusBar(Context context, Density density, int direction, boolean RtlEnabled)
+            throws XmlPullParserException {
+        // FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
+
         super(context, density, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml");
 
         // FIXME: use FILL_H?
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
index 081ce67..108b651 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
@@ -52,6 +52,8 @@
     private static final String NODE_NAME = "name";
     private static final String NODE_FILE = "file";
 
+    private static final String ATTRIBUTE_VARIANT = "variant";
+    private static final String ATTRIBUTE_VALUE_ELEGANT = "elegant";
     private static final String FONT_SUFFIX_NONE = ".ttf";
     private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf";
     private static final String FONT_SUFFIX_BOLD = "-Bold.ttf";
@@ -189,6 +191,7 @@
         private FontInfo mFontInfo = null;
         private final StringBuilder mBuilder = new StringBuilder();
         private List<FontInfo> mFontList = new ArrayList<FontInfo>();
+        private boolean isCompactFont = true;
 
         private FontHandler(String osFontsLocation) {
             super();
@@ -209,8 +212,21 @@
                 mFontList = new ArrayList<FontInfo>();
             } else if (NODE_FAMILY.equals(localName)) {
                 if (mFontList != null) {
+                    mFontInfo = null;
+                }
+            } else if (NODE_NAME.equals(localName)) {
+                if (mFontList != null && mFontInfo == null) {
                     mFontInfo = new FontInfo();
                 }
+            } else if (NODE_FILE.equals(localName)) {
+                if (mFontList != null && mFontInfo == null) {
+                    mFontInfo = new FontInfo();
+                }
+                if (ATTRIBUTE_VALUE_ELEGANT.equals(attributes.getValue(ATTRIBUTE_VARIANT))) {
+                    isCompactFont = false;
+                } else {
+                    isCompactFont = true;
+                }
             }
 
             mBuilder.setLength(0);
@@ -223,7 +239,9 @@
          */
         @Override
         public void characters(char[] ch, int start, int length) throws SAXException {
-            mBuilder.append(ch, start, length);
+            if (isCompactFont) {
+              mBuilder.append(ch, start, length);
+            }
         }
 
         /* (non-Javadoc)
@@ -259,7 +277,7 @@
                 }
             } else if (NODE_FILE.equals(localName)) {
                 // handle a new file for an existing Font Info
-                if (mFontInfo != null) {
+                if (isCompactFont && mFontInfo != null) {
                     String fileName = trimXmlWhitespaces(mBuilder.toString());
                     Font font = getFont(fileName);
                     if (font != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index b909bec..87047b3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -121,7 +121,8 @@
 
         // build the context
         mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
-                mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion());
+                mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
+                mParams.isRtlSupported());
 
         setUp();
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c14af4a..57771e3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -192,11 +192,10 @@
         findNavigationBar(resources, metrics);
 
         // FIXME: find those out, and possibly add them to the render params
-        boolean hasSystemNavBar = true;
         boolean hasNavigationBar = true;
         IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
                 metrics, Surface.ROTATION_0,
-                hasSystemNavBar, hasNavigationBar);
+                hasNavigationBar);
         WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
 
         // build the inflater and parser.
@@ -225,13 +224,15 @@
             SessionParams params = getParams();
             HardwareConfig hardwareConfig = params.getHardwareConfig();
             BridgeContext context = getContext();
-
+            boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
+            int direction = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
 
             // the view group that receives the window background.
             ViewGroup backgroundView = null;
 
             if (mWindowIsFloating || params.isForceNoDecor()) {
                 backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
+                mViewRoot.setLayoutDirection(direction);
             } else {
                 if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
                     /*
@@ -253,12 +254,14 @@
                        the bottom
                      */
                     LinearLayout topLayout = new LinearLayout(context);
+                    topLayout.setLayoutDirection(direction);
                     mViewRoot = topLayout;
                     topLayout.setOrientation(LinearLayout.HORIZONTAL);
 
                     try {
                         NavigationBar navigationBar = new NavigationBar(context,
-                                hardwareConfig.getDensity(), LinearLayout.VERTICAL);
+                                hardwareConfig.getDensity(), LinearLayout.VERTICAL, isRtl,
+                                params.isRtlSupported());
                         navigationBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
                                         mNavigationBarSize,
@@ -290,6 +293,7 @@
 
                 LinearLayout topLayout = new LinearLayout(context);
                 topLayout.setOrientation(LinearLayout.VERTICAL);
+                topLayout.setLayoutDirection(direction);
                 // if we don't already have a view root this is it
                 if (mViewRoot == null) {
                     mViewRoot = topLayout;
@@ -301,13 +305,22 @@
 
                     // this is the case of soft buttons + vertical bar.
                     // this top layout is the first layout in the horizontal layout. see above)
-                    mViewRoot.addView(topLayout, 0);
+                    if (isRtl && params.isRtlSupported()) {
+                        // If RTL is enabled, layoutlib will mirror the layouts. So, add the
+                        // topLayout to the right of Navigation Bar and layoutlib will draw it
+                        // to the left.
+                        mViewRoot.addView(topLayout);
+                    } else {
+                        // Add the top layout to the left of the Navigation Bar.
+                        mViewRoot.addView(topLayout, 0);
+                    }
                 }
 
                 if (mStatusBarSize > 0) {
                     // system bar
                     try {
-                        StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity());
+                        StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity(),
+                                direction, params.isRtlSupported());
                         systemBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
                                         LayoutParams.MATCH_PARENT, mStatusBarSize));
@@ -366,7 +379,8 @@
                     // system bar
                     try {
                         NavigationBar navigationBar = new NavigationBar(context,
-                                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL);
+                                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL, isRtl,
+                                params.isRtlSupported());
                         navigationBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
                                         LayoutParams.MATCH_PARENT, mNavigationBarSize));
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
new file mode 100644
index 0000000..6c998af
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -0,0 +1,148 @@
+/*
+ * 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.layoutlib.bridge.impl.binding;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.ide.common.rendering.api.IProjectCallback.ViewAttribute;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.util.Pair;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * A Helper class to do fake data binding in {@link AdapterView} objects.
+ */
+@SuppressWarnings("deprecation")
+public class AdapterHelper {
+
+    static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
+            IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
+        // we don't care about recycling here because we never scroll.
+        DataBindingItem dataBindingItem = item.getDataBindingItem();
+
+        BridgeContext context = RenderAction.getCurrentContext();
+
+        Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
+                parent, false /*attachToRoot*/, skipCallbackParser);
+
+        View view = pair.getFirst();
+        skipCallbackParser |= pair.getSecond();
+
+        if (view != null) {
+            fillView(context, view, item, parentItem, callback, adapterRef);
+        } else {
+            // create a text view to display an error.
+            TextView tv = new TextView(context);
+            tv.setText("Unable to find layout: " + dataBindingItem.getViewReference().getName());
+            view = tv;
+        }
+
+        return Pair.of(view, skipCallbackParser);
+    }
+
+    private static void fillView(BridgeContext context, View view, AdapterItem item,
+            AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) {
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+            final int count = group.getChildCount();
+            for (int i = 0 ; i < count ; i++) {
+                fillView(context, group.getChildAt(i), item, parentItem, callback, adapterRef);
+            }
+        } else {
+            int id = view.getId();
+            if (id != 0) {
+                ResourceReference resolvedRef = context.resolveId(id);
+                if (resolvedRef != null) {
+                    int fullPosition = item.getFullPosition();
+                    int positionPerType = item.getPositionPerType();
+                    int fullParentPosition = parentItem != null ? parentItem.getFullPosition() : 0;
+                    int parentPositionPerType = parentItem != null ?
+                            parentItem.getPositionPerType() : 0;
+
+                    if (view instanceof TextView) {
+                        TextView tv = (TextView) view;
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
+                                item.getDataBindingItem().getViewReference(),
+                                fullPosition, positionPerType,
+                                fullParentPosition, parentPositionPerType,
+                                resolvedRef, ViewAttribute.TEXT, tv.getText().toString());
+                        if (value != null) {
+                            if (value.getClass() != ViewAttribute.TEXT.getAttributeClass()) {
+                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
+                                        "Wrong Adapter Item value class for TEXT. Expected String, got %s",
+                                        value.getClass().getName()), null);
+                            } else {
+                                tv.setText((String) value);
+                            }
+                        }
+                    }
+
+                    if (view instanceof Checkable) {
+                        Checkable cb = (Checkable) view;
+
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
+                                item.getDataBindingItem().getViewReference(),
+                                fullPosition, positionPerType,
+                                fullParentPosition, parentPositionPerType,
+                                resolvedRef, ViewAttribute.IS_CHECKED, cb.isChecked());
+                        if (value != null) {
+                            if (value.getClass() != ViewAttribute.IS_CHECKED.getAttributeClass()) {
+                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
+                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
+                                        value.getClass().getName()), null);
+                            } else {
+                                cb.setChecked((Boolean) value);
+                            }
+                        }
+                    }
+
+                    if (view instanceof ImageView) {
+                        ImageView iv = (ImageView) view;
+
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
+                                item.getDataBindingItem().getViewReference(),
+                                fullPosition, positionPerType,
+                                fullParentPosition, parentPositionPerType,
+                                resolvedRef, ViewAttribute.SRC, iv.getDrawable());
+                        if (value != null) {
+                            if (value.getClass() != ViewAttribute.SRC.getAttributeClass()) {
+                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
+                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
+                                        value.getClass().getName()), null);
+                            } else {
+                                // FIXME
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
new file mode 100644
index 0000000..8e28dba
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
@@ -0,0 +1,74 @@
+/*
+ * 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.layoutlib.bridge.impl.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+
+/**
+ * This is the items provided by the adapter. They are dynamically generated.
+ */
+final class AdapterItem {
+    private final DataBindingItem mItem;
+    private final int mType;
+    private final int mFullPosition;
+    private final int mPositionPerType;
+    private List<AdapterItem> mChildren;
+
+    protected AdapterItem(DataBindingItem item, int type, int fullPosition,
+            int positionPerType) {
+        mItem = item;
+        mType = type;
+        mFullPosition = fullPosition;
+        mPositionPerType = positionPerType;
+    }
+
+    void addChild(AdapterItem child) {
+        if (mChildren == null) {
+            mChildren = new ArrayList<AdapterItem>();
+        }
+
+        mChildren.add(child);
+    }
+
+    List<AdapterItem> getChildren() {
+        if (mChildren != null) {
+            return mChildren;
+        }
+
+        return Collections.emptyList();
+    }
+
+    int getType() {
+        return mType;
+    }
+
+    int getFullPosition() {
+        return mFullPosition;
+    }
+
+    int getPositionPerType() {
+        return mPositionPerType;
+    }
+
+    DataBindingItem getDataBindingItem() {
+        return mItem;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
deleted file mode 100644
index e0414fe..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.layoutlib.bridge.impl.binding;
-
-import com.android.ide.common.rendering.api.AdapterBinding;
-import com.android.ide.common.rendering.api.DataBindingItem;
-import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.ResourceReference;
-import com.android.ide.common.rendering.api.IProjectCallback.ViewAttribute;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.impl.RenderAction;
-import com.android.util.Pair;
-
-import android.database.DataSetObserver;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.Checkable;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Base adapter to do fake data binding in {@link AdapterView} objects.
- */
-public class BaseAdapter {
-
-    /**
-     * This is the items provided by the adapter. They are dynamically generated.
-     */
-    protected final static class AdapterItem {
-        private final DataBindingItem mItem;
-        private final int mType;
-        private final int mFullPosition;
-        private final int mPositionPerType;
-        private List<AdapterItem> mChildren;
-
-        protected AdapterItem(DataBindingItem item, int type, int fullPosition,
-                int positionPerType) {
-            mItem = item;
-            mType = type;
-            mFullPosition = fullPosition;
-            mPositionPerType = positionPerType;
-        }
-
-        void addChild(AdapterItem child) {
-            if (mChildren == null) {
-                mChildren = new ArrayList<AdapterItem>();
-            }
-
-            mChildren.add(child);
-        }
-
-        List<AdapterItem> getChildren() {
-            if (mChildren != null) {
-                return mChildren;
-            }
-
-            return Collections.emptyList();
-        }
-
-        int getType() {
-            return mType;
-        }
-
-        int getFullPosition() {
-            return mFullPosition;
-        }
-
-        int getPositionPerType() {
-            return mPositionPerType;
-        }
-
-        DataBindingItem getDataBindingItem() {
-            return mItem;
-        }
-    }
-
-    private final AdapterBinding mBinding;
-    private final IProjectCallback mCallback;
-    private final ResourceReference mAdapterRef;
-    private boolean mSkipCallbackParser = false;
-
-    protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
-
-    protected BaseAdapter(ResourceReference adapterRef, AdapterBinding binding,
-            IProjectCallback callback) {
-        mAdapterRef = adapterRef;
-        mBinding = binding;
-        mCallback = callback;
-    }
-
-    // ------- Some Adapter method used by all children classes.
-
-    public boolean areAllItemsEnabled() {
-        return true;
-    }
-
-    public boolean hasStableIds() {
-        return true;
-    }
-
-    public boolean isEmpty() {
-        return mItems.size() == 0;
-    }
-
-    public void registerDataSetObserver(DataSetObserver observer) {
-        // pass
-    }
-
-    public void unregisterDataSetObserver(DataSetObserver observer) {
-        // pass
-    }
-
-    // -------
-
-
-    protected AdapterBinding getBinding() {
-        return mBinding;
-    }
-
-    protected View getView(AdapterItem item, AdapterItem parentItem, View convertView,
-            ViewGroup parent) {
-        // we don't care about recycling here because we never scroll.
-        DataBindingItem dataBindingItem = item.getDataBindingItem();
-
-        BridgeContext context = RenderAction.getCurrentContext();
-
-        Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
-                parent, false /*attachToRoot*/, mSkipCallbackParser);
-
-        View view = pair.getFirst();
-        mSkipCallbackParser |= pair.getSecond();
-
-        if (view != null) {
-            fillView(context, view, item, parentItem);
-        } else {
-            // create a text view to display an error.
-            TextView tv = new TextView(context);
-            tv.setText("Unable to find layout: " + dataBindingItem.getViewReference().getName());
-            view = tv;
-        }
-
-        return view;
-    }
-
-    private void fillView(BridgeContext context, View view, AdapterItem item,
-            AdapterItem parentItem) {
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-            final int count = group.getChildCount();
-            for (int i = 0 ; i < count ; i++) {
-                fillView(context, group.getChildAt(i), item, parentItem);
-            }
-        } else {
-            int id = view.getId();
-            if (id != 0) {
-                ResourceReference resolvedRef = context.resolveId(id);
-                if (resolvedRef != null) {
-                    int fullPosition = item.getFullPosition();
-                    int positionPerType = item.getPositionPerType();
-                    int fullParentPosition = parentItem != null ? parentItem.getFullPosition() : 0;
-                    int parentPositionPerType = parentItem != null ?
-                            parentItem.getPositionPerType() : 0;
-
-                    if (view instanceof TextView) {
-                        TextView tv = (TextView) view;
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
-                                item.getDataBindingItem().getViewReference(),
-                                fullPosition, positionPerType,
-                                fullParentPosition, parentPositionPerType,
-                                resolvedRef, ViewAttribute.TEXT, tv.getText().toString());
-                        if (value != null) {
-                            if (value.getClass() != ViewAttribute.TEXT.getAttributeClass()) {
-                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected String, got %s",
-                                        value.getClass().getName()), null);
-                            } else {
-                                tv.setText((String) value);
-                            }
-                        }
-                    }
-
-                    if (view instanceof Checkable) {
-                        Checkable cb = (Checkable) view;
-
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
-                                item.getDataBindingItem().getViewReference(),
-                                fullPosition, positionPerType,
-                                fullParentPosition, parentPositionPerType,
-                                resolvedRef, ViewAttribute.IS_CHECKED, cb.isChecked());
-                        if (value != null) {
-                            if (value.getClass() != ViewAttribute.IS_CHECKED.getAttributeClass()) {
-                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
-                                        value.getClass().getName()), null);
-                            } else {
-                                cb.setChecked((Boolean) value);
-                            }
-                        }
-                    }
-
-                    if (view instanceof ImageView) {
-                        ImageView iv = (ImageView) view;
-
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
-                                item.getDataBindingItem().getViewReference(),
-                                fullPosition, positionPerType,
-                                fullParentPosition, parentPositionPerType,
-                                resolvedRef, ViewAttribute.SRC, iv.getDrawable());
-                        if (value != null) {
-                            if (value.getClass() != ViewAttribute.SRC.getAttributeClass()) {
-                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
-                                        value.getClass().getName()), null);
-                            } else {
-                                // FIXME
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index 22570b9..9a13f5a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -20,10 +20,12 @@
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
 
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
+import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 import android.widget.SpinnerAdapter;
 
@@ -35,17 +37,23 @@
  * and {@link SpinnerAdapter}.
  *
  */
-public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+@SuppressWarnings("deprecation")
+public class FakeAdapter extends BaseAdapter {
 
     // don't use a set because the order is important.
     private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>();
+    private final IProjectCallback mCallback;
+    private final ResourceReference mAdapterRef;
+    private final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
+    private boolean mSkipCallbackParser = false;
 
     public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
             IProjectCallback callback) {
-        super(adapterRef, binding, callback);
+        mAdapterRef = adapterRef;
+        mCallback = callback;
 
-        final int repeatCount = getBinding().getRepeatCount();
-        final int itemCount = getBinding().getItemCount();
+        final int repeatCount = binding.getRepeatCount();
+        final int itemCount = binding.getItemCount();
 
         // Need an array to count for each type.
         // This is likely too big, but is the max it can be.
@@ -54,7 +62,7 @@
         // We put several repeating sets.
         for (int r = 0 ; r < repeatCount ; r++) {
             // loop on the type of list items, and add however many for each type.
-            for (DataBindingItem dataBindingItem : getBinding()) {
+            for (DataBindingItem dataBindingItem : binding) {
                 ResourceReference viewRef = dataBindingItem.getViewReference();
                 int typeIndex = mTypes.indexOf(viewRef);
                 if (typeIndex == -1) {
@@ -103,7 +111,11 @@
     public View getView(int position, View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(position);
-        return getView(item, null /*parentGroup*/, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentGroup*/, parent,
+                mCallback, mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
+
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 199e040..e539579 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -20,7 +20,9 @@
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
 
+import android.database.DataSetObserver;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ExpandableListAdapter;
@@ -29,8 +31,14 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter,
-        HeterogeneousExpandableList {
+@SuppressWarnings("deprecation")
+public class FakeExpandableAdapter implements ExpandableListAdapter, HeterogeneousExpandableList {
+
+    private final IProjectCallback mCallback;
+    private final ResourceReference mAdapterRef;
+    private boolean mSkipCallbackParser = false;
+
+    protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
 
     // don't use a set because the order is important.
     private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>();
@@ -38,7 +46,8 @@
 
     public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
             IProjectCallback callback) {
-        super(adapterRef, binding, callback);
+        mAdapterRef = adapterRef;
+        mCallback = callback;
 
         createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
     }
@@ -125,7 +134,10 @@
             ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(groupPosition);
-        return getView(item, null /*parentItem*/, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentItem*/, parent,
+                mCallback, mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
     }
 
     @Override
@@ -134,7 +146,10 @@
         // we don't care about recycling here because we never scroll.
         AdapterItem parentItem = mItems.get(groupPosition);
         AdapterItem item = getChildItem(groupPosition, childPosition);
-        return getView(item, parentItem, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, parentItem, parent, mCallback,
+                mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
     }
 
     @Override
@@ -172,6 +187,31 @@
         // pass
     }
 
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        // pass
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        // pass
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return mItems.isEmpty();
+    }
+
     // ---- HeterogeneousExpandableList
 
     @Override
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index ad8de69..9ff56d6 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -18,8 +18,8 @@
 #LOCAL_C_INCLUDES +=
 
 LOCAL_STATIC_LIBRARIES := \
-	libutils \
 	libandroidfw \
+	libutils \
 	libcutils \
 	liblog
 
diff --git a/tools/preload/Policy.java b/tools/preload/Policy.java
index ca0291b..af46820 100644
--- a/tools/preload/Policy.java
+++ b/tools/preload/Policy.java
@@ -81,8 +81,9 @@
         return SERVICES.contains(processName);
     }
 
-    /**Reports if the given class should be preloaded. */
+    /** Reports if the given class should be preloaded. */
     public static boolean isPreloadable(LoadedClass clazz) {
-        return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name);
+        return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name)
+                && !clazz.name.endsWith("$NoPreloadHolder");
     }
 }
diff --git a/tools/validatekeymaps/Android.mk b/tools/validatekeymaps/Android.mk
index 90fbc08..9af721d 100644
--- a/tools/validatekeymaps/Android.mk
+++ b/tools/validatekeymaps/Android.mk
@@ -15,10 +15,8 @@
 
 LOCAL_CFLAGS := -Wall -Werror
 
-#LOCAL_C_INCLUDES +=
-
 LOCAL_STATIC_LIBRARIES := \
-	libandroidfw \
+	libinput \
 	libutils \
 	libcutils \
 	liblog
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 91e4fda..5b45c55 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/VirtualKeyMap.h>
 #include <utils/PropertyMap.h>
 #include <utils/String8.h>
 
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.aidl b/wifi/java/android/net/wifi/BatchedScanResult.aidl
new file mode 100644
index 0000000..a70bc0a
--- /dev/null
+++ b/wifi/java/android/net/wifi/BatchedScanResult.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.net.wifi;
+
+parcelable BatchedScanResult;
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.java b/wifi/java/android/net/wifi/BatchedScanResult.java
new file mode 100644
index 0000000..eb4e0276
--- /dev/null
+++ b/wifi/java/android/net/wifi/BatchedScanResult.java
@@ -0,0 +1,94 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Describes the Results of a batched set of wifi scans where the firmware performs many
+ * scans and stores the timestamped results without waking the main processor each time.
+ * @hide pending review
+ */
+public class BatchedScanResult implements Parcelable {
+    private static final String TAG = "BatchedScanResult";
+
+    /** Inidcates this scan was interrupted and may only have partial results. */
+    public boolean truncated;
+
+    /** The result of this particular scan. */
+    public final List<ScanResult> scanResults = new ArrayList<ScanResult>();
+
+
+    public BatchedScanResult() {
+    }
+
+    public BatchedScanResult(BatchedScanResult source) {
+        truncated = source.truncated;
+        for (ScanResult s : source.scanResults) scanResults.add(new ScanResult(s));
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("BatchedScanResult: ").
+                append("truncated: ").append(String.valueOf(truncated)).
+                append("scanResults: [");
+        for (ScanResult s : scanResults) {
+            sb.append(" <").append(s.toString()).append("> ");
+        }
+        sb.append(" ]");
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(truncated ? 1 : 0);
+        dest.writeInt(scanResults.size());
+        for (ScanResult s : scanResults) {
+            s.writeToParcel(dest, flags);
+        }
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<BatchedScanResult> CREATOR =
+        new Creator<BatchedScanResult>() {
+            public BatchedScanResult createFromParcel(Parcel in) {
+                BatchedScanResult result = new BatchedScanResult();
+                result.truncated = (in.readInt() == 1);
+                int count = in.readInt();
+                while (count-- > 0) {
+                    result.scanResults.add(ScanResult.CREATOR.createFromParcel(in));
+                }
+                return result;
+            }
+
+            public BatchedScanResult[] newArray(int size) {
+                return new BatchedScanResult[size];
+            }
+        };
+}
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.aidl b/wifi/java/android/net/wifi/BatchedScanSettings.aidl
new file mode 100644
index 0000000..8cfc508
--- /dev/null
+++ b/wifi/java/android/net/wifi/BatchedScanSettings.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.net.wifi;
+
+parcelable BatchedScanSettings;
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.java b/wifi/java/android/net/wifi/BatchedScanSettings.java
new file mode 100644
index 0000000..f7ebc17
--- /dev/null
+++ b/wifi/java/android/net/wifi/BatchedScanSettings.java
@@ -0,0 +1,263 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Describes the settings for batched wifi scans where the firmware performs many
+ * scans and stores the timestamped results without waking the main processor each time.
+ * This can give information over time with minimal battery impact.
+ * @hide pending review
+ */
+public class BatchedScanSettings implements Parcelable {
+    private static final String TAG = "BatchedScanSettings";
+
+    /** Used to indicate no preference for an int value */
+    public final static int UNSPECIFIED = Integer.MAX_VALUE;
+
+    // TODO - make MIN/mAX dynamic and gservices adjustable.
+    public final static int MIN_SCANS_PER_BATCH = 2;
+    public final static int MAX_SCANS_PER_BATCH = 255;
+    public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH;
+
+    public final static int MIN_AP_PER_SCAN = 2;
+    public final static int MAX_AP_PER_SCAN = 255;
+    public final static int DEFAULT_AP_PER_SCAN = 16;
+
+    public final static int MIN_INTERVAL_SEC = 0;
+    public final static int MAX_INTERVAL_SEC = 3600;
+    public final static int DEFAULT_INTERVAL_SEC = 30;
+
+    public final static int MIN_AP_FOR_DISTANCE = 0;
+    public final static int MAX_AP_FOR_DISTANCE = MAX_AP_PER_SCAN;
+    public final static int DEFAULT_AP_FOR_DISTANCE = 0;
+
+    public final static int MAX_WIFI_CHANNEL = 196;
+
+    /** The expected number of scans per batch.  Note that the firmware may drop scans
+     *  leading to fewer scans during the normal batch scan duration.  This value need not
+     *  be specified (may be set to {@link UNSPECIFIED}) by the application and we will try
+     *  to scan as many times as the firmware can support.  If another app requests fewer
+     *  scans per batch we will attempt to honor that.
+     */
+    public int maxScansPerBatch;
+
+    /** The maximum desired AP listed per scan.  Fewer AP may be returned if that's all
+     *  that the driver detected.  If another application requests more AP per scan that
+     *  will take precedence.  The if more channels are detected than we request, the APs
+     *  with the lowest signal strength will be dropped.
+     */
+    public int maxApPerScan;
+
+    /** The channels used in the scan.  If all channels should be used, {@code null} may be
+     *  specified.  If another application requests more channels or all channels, that
+     *  will take precedence.
+     */
+    public Collection<String> channelSet;
+
+    /** The time between the start of two sequential scans, in seconds.  If another
+     *  application requests more frequent scans, that will take precedence.  If this
+     * value is less than the duration of a scan, the next scan should start immediately.
+     */
+    public int scanIntervalSec;
+
+    /** The number of the best (strongest signal) APs for which the firmware will
+     *  attempt to get distance information (RTT).  Not all firmware supports this
+     *  feature, so it may be ignored.  If another application requests a greater
+     *  number, that will take precedence.
+     */
+    public int maxApForDistance;
+
+    public BatchedScanSettings() {
+        clear();
+    }
+
+    public void clear() {
+        maxScansPerBatch = UNSPECIFIED;
+        maxApPerScan = UNSPECIFIED;
+        channelSet = null;
+        scanIntervalSec = UNSPECIFIED;
+        maxApForDistance = UNSPECIFIED;
+    }
+
+    public BatchedScanSettings(BatchedScanSettings source) {
+        maxScansPerBatch = source.maxScansPerBatch;
+        maxApPerScan = source.maxApPerScan;
+        if (source.channelSet != null) {
+            channelSet = new ArrayList(source.channelSet);
+        }
+        scanIntervalSec = source.scanIntervalSec;
+        maxApForDistance = source.maxApForDistance;
+    }
+
+    private boolean channelSetIsValid() {
+        if (channelSet == null || channelSet.isEmpty()) return true;
+        for (String channel : channelSet) {
+            try {
+                int i = Integer.parseInt(channel);
+                if (i > 0 && i <= MAX_WIFI_CHANNEL) continue;
+            } catch (NumberFormatException e) {}
+            if (channel.equals("A") || channel.equals("B")) continue;
+            return false;
+        }
+        return true;
+    }
+    /** @hide */
+    public boolean isInvalid() {
+        if (maxScansPerBatch != UNSPECIFIED && (maxScansPerBatch < MIN_SCANS_PER_BATCH ||
+                maxScansPerBatch > MAX_SCANS_PER_BATCH)) return true;
+        if (maxApPerScan != UNSPECIFIED && (maxApPerScan < MIN_AP_PER_SCAN ||
+                maxApPerScan > MAX_AP_PER_SCAN)) return true;
+        if (channelSetIsValid() == false) return true;
+        if (scanIntervalSec != UNSPECIFIED && (scanIntervalSec < MIN_INTERVAL_SEC ||
+                scanIntervalSec > MAX_INTERVAL_SEC)) return true;
+        if (maxApForDistance != UNSPECIFIED && (maxApForDistance < MIN_AP_FOR_DISTANCE ||
+                maxApForDistance > MAX_AP_FOR_DISTANCE)) return true;
+        return false;
+    }
+
+    /** @hide */
+    public void constrain() {
+        if (scanIntervalSec == UNSPECIFIED) {
+            scanIntervalSec = DEFAULT_INTERVAL_SEC;
+        } else if (scanIntervalSec < MIN_INTERVAL_SEC) {
+            scanIntervalSec = MIN_INTERVAL_SEC;
+        } else if (scanIntervalSec > MAX_INTERVAL_SEC) {
+            scanIntervalSec = MAX_INTERVAL_SEC;
+        }
+
+        if (maxScansPerBatch == UNSPECIFIED) {
+            maxScansPerBatch = DEFAULT_SCANS_PER_BATCH;
+        } else if (maxScansPerBatch < MIN_SCANS_PER_BATCH) {
+            maxScansPerBatch = MIN_SCANS_PER_BATCH;
+        } else if (maxScansPerBatch > MAX_SCANS_PER_BATCH) {
+            maxScansPerBatch = MAX_SCANS_PER_BATCH;
+        }
+
+        if (maxApPerScan == UNSPECIFIED) {
+            maxApPerScan = DEFAULT_AP_PER_SCAN;
+        } else if (maxApPerScan < MIN_AP_PER_SCAN) {
+            maxApPerScan = MIN_AP_PER_SCAN;
+        } else if (maxApPerScan > MAX_AP_PER_SCAN) {
+            maxApPerScan = MAX_AP_PER_SCAN;
+        }
+
+        if (maxApForDistance == UNSPECIFIED) {
+            maxApForDistance = DEFAULT_AP_FOR_DISTANCE;
+        } else if (maxApForDistance < MIN_AP_FOR_DISTANCE) {
+            maxApForDistance = MIN_AP_FOR_DISTANCE;
+        } else if (maxApForDistance > MAX_AP_FOR_DISTANCE) {
+            maxApForDistance = MAX_AP_FOR_DISTANCE;
+        }
+    }
+
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof BatchedScanSettings == false) return false;
+        BatchedScanSettings o = (BatchedScanSettings)obj;
+        if (maxScansPerBatch != o.maxScansPerBatch ||
+              maxApPerScan != o.maxApPerScan ||
+              scanIntervalSec != o.scanIntervalSec ||
+              maxApForDistance != o.maxApForDistance) return false;
+        if (channelSet == null) {
+            return (o.channelSet == null);
+        }
+        return channelSet.equals(o.channelSet);
+    }
+
+    @Override
+    public int hashCode() {
+        return maxScansPerBatch +
+                (maxApPerScan * 3) +
+                (scanIntervalSec * 5) +
+                (maxApForDistance * 7) +
+                (channelSet.hashCode() * 11);
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        String none = "<none>";
+
+        sb.append("BatchScanSettings [maxScansPerBatch: ").
+                append(maxScansPerBatch == UNSPECIFIED ? none : maxScansPerBatch).
+                append(", maxApPerScan: ").append(maxApPerScan == UNSPECIFIED? none : maxApPerScan).
+                append(", scanIntervalSec: ").
+                append(scanIntervalSec == UNSPECIFIED ? none : scanIntervalSec).
+                append(", maxApForDistance: ").
+                append(maxApForDistance == UNSPECIFIED ? none : maxApForDistance).
+                append(", channelSet: ");
+        if (channelSet == null) {
+            sb.append("ALL");
+        } else {
+            sb.append("<");
+            for (String channel : channelSet) {
+                sb.append(" " + channel);
+            }
+            sb.append(">");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(maxScansPerBatch);
+        dest.writeInt(maxApPerScan);
+        dest.writeInt(scanIntervalSec);
+        dest.writeInt(maxApForDistance);
+        dest.writeInt(channelSet == null ? 0 : channelSet.size());
+        if (channelSet != null) {
+            for (String channel : channelSet) dest.writeString(channel);
+        }
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<BatchedScanSettings> CREATOR =
+        new Creator<BatchedScanSettings>() {
+            public BatchedScanSettings createFromParcel(Parcel in) {
+                BatchedScanSettings settings = new BatchedScanSettings();
+                settings.maxScansPerBatch = in.readInt();
+                settings.maxApPerScan = in.readInt();
+                settings.scanIntervalSec = in.readInt();
+                settings.maxApForDistance = in.readInt();
+                int channelCount = in.readInt();
+                if (channelCount > 0) {
+                    settings.channelSet = new ArrayList(channelCount);
+                    while (channelCount-- > 0) {
+                        settings.channelSet.add(in.readString());
+                    }
+                }
+                return settings;
+            }
+
+            public BatchedScanSettings[] newArray(int size) {
+                return new BatchedScanSettings[size];
+            }
+        };
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 547ae95..5a1928c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -16,8 +16,10 @@
 
 package android.net.wifi;
 
-import android.net.wifi.WifiInfo;
+import android.net.wifi.BatchedScanResult;
+import android.net.wifi.BatchedScanSettings;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
 import android.net.wifi.ScanResult;
 import android.net.DhcpInfo;
 
@@ -43,7 +45,7 @@
 
     boolean pingSupplicant();
 
-    void startScan();
+    void startScan(in WorkSource ws);
 
     List<ScanResult> getScanResults(String callingPackage);
 
@@ -110,5 +112,19 @@
     String getConfigFile();
 
     void captivePortalCheckComplete();
+
+    void enableTdls(String remoteIPAddress, boolean enable);
+
+    void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
+
+    boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder);
+
+    void stopBatchedScan(in BatchedScanSettings requested);
+
+    List<BatchedScanResult> getBatchedScanResults(String callingPackage);
+
+    boolean isBatchedScanSupported();
+
+    void pollBatchedScan();
 }
 
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9977419..12729d2 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -54,7 +54,26 @@
      * Time Synchronization Function (tsf) timestamp in microseconds when
      * this result was last seen.
      */
-     public long timestamp;
+    public long timestamp;
+
+    /**
+     * The approximate distance to the AP in centimeter, if available.  Else
+     * {@link UNSPECIFIED}.
+     * {@hide}
+     */
+    public int distanceCm;
+
+    /**
+     * The standard deviation of the distance to the AP, if available.
+     * Else {@link UNSPECIFIED}.
+     * {@hide}
+     */
+    public int distanceSdCm;
+
+    /**
+     * {@hide}
+     */
+    public final static int UNSPECIFIED = -1;
 
     /** {@hide} */
     public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
@@ -66,8 +85,23 @@
         this.level = level;
         this.frequency = frequency;
         this.timestamp = tsf;
+        this.distanceCm = UNSPECIFIED;
+        this.distanceSdCm = UNSPECIFIED;
     }
 
+    /** {@hide} */
+    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
+            long tsf, int distCm, int distSdCm) {
+        this.wifiSsid = wifiSsid;
+        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
+        this.BSSID = BSSID;
+        this.capabilities = caps;
+        this.level = level;
+        this.frequency = frequency;
+        this.timestamp = tsf;
+        this.distanceCm = distCm;
+        this.distanceSdCm = distSdCm;
+    }
 
     /** copy constructor {@hide} */
     public ScanResult(ScanResult source) {
@@ -79,6 +113,8 @@
             level = source.level;
             frequency = source.frequency;
             timestamp = source.timestamp;
+            distanceCm = source.distanceCm;
+            distanceSdCm = source.distanceSdCm;
         }
     }
 
@@ -100,6 +136,11 @@
             append(", timestamp: ").
             append(timestamp);
 
+        sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
+                append("(cm)");
+        sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
+                append("(cm)");
+
         return sb.toString();
     }
 
@@ -121,6 +162,8 @@
         dest.writeInt(level);
         dest.writeInt(frequency);
         dest.writeLong(timestamp);
+        dest.writeInt(distanceCm);
+        dest.writeInt(distanceSdCm);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -137,7 +180,9 @@
                     in.readString(),
                     in.readInt(),
                     in.readInt(),
-                    in.readLong()
+                    in.readLong(),
+                    in.readInt(),
+                    in.readInt()
                 );
             }
 
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 9418de1..f79a4a6 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -31,22 +31,28 @@
 import android.net.wifi.NetworkUpdateResult;
 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
 import android.os.Environment;
+import android.os.FileObserver;
 import android.os.Message;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.UserHandle;
 import android.security.KeyStore;
 import android.text.TextUtils;
+import android.util.LocalLog;
 import android.util.Log;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.EOFException;
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.InetAddress;
@@ -108,7 +114,10 @@
 
     private Context mContext;
     private static final String TAG = "WifiConfigStore";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf";
 
     /* configured networks with network id as the key */
     private HashMap<Integer, WifiConfiguration> mConfiguredNetworks =
@@ -141,17 +150,46 @@
     private static final String PROXY_SETTINGS_KEY = "proxySettings";
     private static final String PROXY_HOST_KEY = "proxyHost";
     private static final String PROXY_PORT_KEY = "proxyPort";
+    private static final String PROXY_PAC_FILE = "proxyPac";
     private static final String EXCLUSION_LIST_KEY = "exclusionList";
     private static final String EOS = "eos";
 
+    private final LocalLog mLocalLog;
+    private final WpaConfigFileObserver mFileObserver;
+
     private WifiNative mWifiNative;
     private final KeyStore mKeyStore = KeyStore.getInstance();
 
     WifiConfigStore(Context c, WifiNative wn) {
         mContext = c;
         mWifiNative = wn;
+
+        if (VDBG) {
+            mLocalLog = mWifiNative.getLocalLog();
+            mFileObserver = new WpaConfigFileObserver();
+            mFileObserver.startWatching();
+        } else {
+            mLocalLog = null;
+            mFileObserver = null;
+        }
     }
 
+    class WpaConfigFileObserver extends FileObserver {
+
+        public WpaConfigFileObserver() {
+            super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE);
+        }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if (event == CLOSE_WRITE) {
+                File file = new File(SUPPLICANT_CONFIG_FILE);
+                if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length());
+            }
+        }
+    }
+
+
     /**
      * Fetch the list of configured networks
      * and enable all stored networks in supplicant.
@@ -211,6 +249,7 @@
      * @return false if the network id is invalid
      */
     boolean selectNetwork(int netId) {
+        if (VDBG) localLog("selectNetwork", netId);
         if (netId == INVALID_NETWORK_ID) return false;
 
         // Reset the priority of each network at start or if it goes too high.
@@ -247,6 +286,7 @@
      * @return network update result
      */
     NetworkUpdateResult saveNetwork(WifiConfiguration config) {
+        if (VDBG) localLog("saveNetwork", config.networkId);
         // A new network cannot have null SSID
         if (config == null || (config.networkId == INVALID_NETWORK_ID &&
                 config.SSID == null)) {
@@ -295,6 +335,7 @@
      * @return {@code true} if it succeeds, {@code false} otherwise
      */
     boolean forgetNetwork(int netId) {
+        if (VDBG) localLog("forgetNetwork", netId);
         if (mWifiNative.removeNetwork(netId)) {
             mWifiNative.saveConfig();
             removeConfigAndSendBroadcastIfNeeded(netId);
@@ -315,11 +356,12 @@
      * @return network Id
      */
     int addOrUpdateNetwork(WifiConfiguration config) {
+        if (VDBG) localLog("addOrUpdateNetwork", config.networkId);
         NetworkUpdateResult result = addOrUpdateNetworkNative(config);
         if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
             sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()),
                     result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED :
-                        WifiManager.CHANGE_REASON_CONFIG_CHANGE);
+                            WifiManager.CHANGE_REASON_CONFIG_CHANGE);
         }
         return result.getNetworkId();
     }
@@ -334,6 +376,7 @@
      * @return {@code true} if it succeeds, {@code false} otherwise
      */
     boolean removeNetwork(int netId) {
+        if (VDBG) localLog("removeNetwork", netId);
         boolean ret = mWifiNative.removeNetwork(netId);
         if (ret) {
             removeConfigAndSendBroadcastIfNeeded(netId);
@@ -368,8 +411,10 @@
     boolean enableNetwork(int netId, boolean disableOthers) {
         boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
         if (disableOthers) {
+            if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId);
             sendConfiguredNetworksChangedBroadcast();
         } else {
+            if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId);
             WifiConfiguration enabledNetwork = null;
             synchronized(mConfiguredNetworks) {
                 enabledNetwork = mConfiguredNetworks.get(netId);
@@ -396,6 +441,7 @@
     }
 
     void disableAllNetworks() {
+        if (VDBG) localLog("disableAllNetworks");
         boolean networkDisabled = false;
         for(WifiConfiguration config : mConfiguredNetworks.values()) {
             if(config != null && config.status != Status.DISABLED) {
@@ -428,6 +474,7 @@
      * @return {@code true} if it succeeds, {@code false} otherwise
      */
     boolean disableNetwork(int netId, int reason) {
+        if (VDBG) localLog("disableNetwork", netId);
         boolean ret = mWifiNative.disableNetwork(netId);
         WifiConfiguration network = null;
         WifiConfiguration config = mConfiguredNetworks.get(netId);
@@ -618,6 +665,7 @@
             try {
                 config.networkId = Integer.parseInt(result[0]);
             } catch(NumberFormatException e) {
+                loge("Failed to read network-id '" + result[0] + "'");
                 continue;
             }
             if (result.length > 3) {
@@ -636,12 +684,46 @@
             }
             config.ipAssignment = IpAssignment.DHCP;
             config.proxySettings = ProxySettings.NONE;
-            mConfiguredNetworks.put(config.networkId, config);
-            mNetworkIds.put(configKey(config), config.networkId);
+
+            if (mNetworkIds.containsKey(configKey(config))) {
+                // That SSID is already known, just ignore this duplicate entry
+                if (VDBG) localLog("discarded duplicate network", config.networkId);
+            } else {
+                mConfiguredNetworks.put(config.networkId, config);
+                mNetworkIds.put(configKey(config), config.networkId);
+                if (VDBG) localLog("loaded configured network", config.networkId);
+            }
         }
 
         readIpAndProxyConfigurations();
         sendConfiguredNetworksChangedBroadcast();
+
+        if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks");
+
+        if (mNetworkIds.size() == 0) {
+            // no networks? Lets log if the wpa_supplicant.conf file contents
+            BufferedReader reader = null;
+            try {
+                reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE));
+                if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---");
+                for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+                    if (VDBG) localLog(line);
+                }
+                if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---");
+            } catch (FileNotFoundException e) {
+                if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e);
+            } catch (IOException e) {
+                if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e);
+            } finally {
+                try {
+                    if (reader != null) {
+                        reader.close();
+                    }
+                } catch (IOException e) {
+                    // Just ignore the fact that we couldn't close
+                }
+            }
+        }
     }
 
     /* Mark all networks except specified netId as disabled */
@@ -771,6 +853,14 @@
                                 out.writeUTF(exclusionList);
                                 writeToFile = true;
                                 break;
+                            case PAC:
+                                ProxyProperties proxyPacProperties = linkProperties.getHttpProxy();
+                                out.writeUTF(PROXY_SETTINGS_KEY);
+                                out.writeUTF(config.proxySettings.toString());
+                                out.writeUTF(PROXY_PAC_FILE);
+                                out.writeUTF(proxyPacProperties.getPacFileUrl());
+                                writeToFile = true;
+                                break;
                             case NONE:
                                 out.writeUTF(PROXY_SETTINGS_KEY);
                                 out.writeUTF(config.proxySettings.toString());
@@ -838,6 +928,7 @@
                 ProxySettings proxySettings = ProxySettings.NONE;
                 LinkProperties linkProperties = new LinkProperties();
                 String proxyHost = null;
+                String pacFileUrl = null;
                 int proxyPort = -1;
                 String exclusionList = null;
                 String key;
@@ -879,6 +970,8 @@
                             proxyHost = in.readUTF();
                         } else if (key.equals(PROXY_PORT_KEY)) {
                             proxyPort = in.readInt();
+                        } else if (key.equals(PROXY_PAC_FILE)) {
+                            pacFileUrl = in.readUTF();
                         } else if (key.equals(EXCLUSION_LIST_KEY)) {
                             exclusionList = in.readUTF();
                         } else if (key.equals(EOS)) {
@@ -920,6 +1013,12 @@
                                     new ProxyProperties(proxyHost, proxyPort, exclusionList);
                                 linkProperties.setHttpProxy(proxyProperties);
                                 break;
+                            case PAC:
+                                config.proxySettings = proxySettings;
+                                ProxyProperties proxyPacProperties = 
+                                        new ProxyProperties(pacFileUrl);
+                                linkProperties.setHttpProxy(proxyPacProperties);
+                                break;
                             case NONE:
                                 config.proxySettings = proxySettings;
                                 break;
@@ -954,6 +1053,9 @@
          * network configuration. Otherwise, the networkId should
          * refer to an existing configuration.
          */
+
+        if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid());
+
         int netId = config.networkId;
         boolean newNetwork = false;
         // networkId of INVALID_NETWORK_ID means we want to create a new network
@@ -1247,6 +1349,7 @@
 
         switch (newConfig.proxySettings) {
             case STATIC:
+            case PAC:
                 ProxyProperties newHttpProxy = newConfig.linkProperties.getHttpProxy();
                 ProxyProperties currentHttpProxy = currentConfig.linkProperties.getHttpProxy();
 
@@ -1558,6 +1661,12 @@
             pw.println(conf);
         }
         pw.println();
+
+        if (mLocalLog != null) {
+            pw.println("WifiConfigStore - Log Begin ----");
+            mLocalLog.dump(fd, pw, args);
+            pw.println("WifiConfigStore - Log End ----");
+        }
     }
 
     public String getConfigFile() {
@@ -1571,4 +1680,28 @@
     private void log(String s) {
         Log.d(TAG, s);
     }
+
+    private void localLog(String s) {
+        if (mLocalLog != null) {
+            mLocalLog.log(s);
+        }
+    }
+
+    private void localLog(String s, int netId) {
+        if (mLocalLog == null) {
+            return;
+        }
+
+        WifiConfiguration config;
+        synchronized(mConfiguredNetworks) {
+            config = mConfiguredNetworks.get(netId);
+        }
+
+        if (config != null) {
+            mLocalLog.log(s + " " + config.getPrintableSsid());
+        } else {
+            mLocalLog.log(s + " " + netId);
+        }
+    }
+
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index bd8f0eb..87afa88 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -312,7 +312,10 @@
         STATIC,
         /* no proxy details are assigned, this is used to indicate
          * that any existing proxy settings should be retained */
-        UNASSIGNED
+        UNASSIGNED,
+        /* Use a Pac based proxy.
+         */
+        PAC
     }
     /**
      * @hide
@@ -345,6 +348,29 @@
         linkProperties = new LinkProperties();
     }
 
+    /**
+     * indicates whether the configuration is valid
+     * @return true if valid, false otherwise
+     * @hide
+     */
+    public boolean isValid() {
+        if (allowedKeyManagement.cardinality() > 1) {
+            if (allowedKeyManagement.cardinality() != 2) {
+                return false;
+            }
+            if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) {
+                return false;
+            }
+            if ((allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false)
+                    && (allowedKeyManagement.get(KeyMgmt.WPA_PSK) == false)) {
+                return false;
+            }
+        }
+
+        // TODO: Add more checks
+        return true;
+    }
+
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
@@ -529,8 +555,8 @@
 
     /** @hide */
     public int getAuthType() {
-        if (allowedKeyManagement.cardinality() > 1) {
-            throw new IllegalStateException("More than one auth type set");
+        if (isValid() == false) {
+            throw new IllegalStateException("Invalid configuration");
         }
         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
             return KeyMgmt.WPA_PSK;
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 4bee937..e357804a 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -721,7 +721,13 @@
         String value = mFields.get(key);
         // Uninitialized or known to be empty after reading from supplicant
         if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
-        return removeDoubleQuotes(value).substring(prefix.length());
+
+        value = removeDoubleQuotes(value);
+        if (value.startsWith(prefix)) {
+            return value.substring(prefix.length());
+        } else {
+            return value;
+        }
     }
 
     /** Set a value with an optional prefix at key
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a3c172a..b7594ee1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -32,8 +32,10 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import java.net.InetAddress;
 import java.util.concurrent.CountDownLatch;
 
+import com.android.internal.R;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
@@ -364,6 +366,14 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
     /**
+     * A batch of access point scans has been completed and the results areavailable.
+     * Call {@link #getBatchedScanResults()} to obtain the results.
+     * @hide pending review
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
+            "android.net.wifi.BATCHED_RESULTS";
+    /**
      * The RSSI (signal strength) has changed.
      * @see #EXTRA_NEW_RSSI
      */
@@ -758,13 +768,107 @@
      */
     public boolean startScan() {
         try {
-            mService.startScan();
+            final WorkSource workSource = null;
+            mService.startScan(workSource);
             return true;
         } catch (RemoteException e) {
             return false;
         }
     }
 
+    /** @hide */
+    public boolean startScan(WorkSource workSource) {
+        try {
+            mService.startScan(workSource);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Request a batched scan for access points.  To end your requested batched scan,
+     * call stopBatchedScan with the same Settings.
+     *
+     * If there are mulitple requests for batched scans, the more demanding settings will
+     * take precidence.
+     *
+     * @param requested {@link BatchedScanSettings} the scan settings requested.
+     * @return false on known error
+     * @hide
+     */
+    public boolean requestBatchedScan(BatchedScanSettings requested) {
+        try {
+            return mService.requestBatchedScan(requested, new Binder());
+        } catch (RemoteException e) { return false; }
+    }
+
+    /**
+     * Check if the Batched Scan feature is supported.
+     *
+     * @return false if not supported.
+     * @hide
+     */
+    public boolean isBatchedScanSupported() {
+        try {
+            return mService.isBatchedScanSupported();
+        } catch (RemoteException e) { return false; }
+    }
+
+    /**
+     * End a requested batch scan for this applicaiton.  Note that batched scan may
+     * still occur if other apps are using them.
+     *
+     * @param requested {@link BatchedScanSettings} the scan settings you previously requested
+     *        and now wish to stop.  A value of null here will stop all scans requested by the
+     *        calling App.
+     * @hide
+     */
+    public void stopBatchedScan(BatchedScanSettings requested) {
+        try {
+            mService.stopBatchedScan(requested);
+        } catch (RemoteException e) {}
+    }
+
+    /**
+     * Retrieve the latest batched scan result.  This should be called immediately after
+     * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
+     * @hide
+     */
+    public List<BatchedScanResult> getBatchedScanResults() {
+        try {
+            return mService.getBatchedScanResults(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Force a re-reading of batched scan results.  This will attempt
+     * to read more information from the chip, but will do so at the expense
+     * of previous data.  Rate limited to the current scan frequency.
+     *
+     * pollBatchedScan will always wait 1 period from the start of the batch
+     * before trying to read from the chip, so if your #scans/batch == 1 this will
+     * have no effect.
+     *
+     * If you had already waited 1 period before calling, this should have
+     * immediate (though async) effect.
+     *
+     * If you call before that 1 period is up this will set up a timer and fetch
+     * results when the 1 period is up.
+     *
+     * Servicing a pollBatchedScan request (immediate or after timed delay) starts a
+     * new batch, so if you were doing 10 scans/batch and called in the 4th scan, you
+     * would get data in the 4th and then again 10 scans later.
+     * @hide
+     */
+    public void pollBatchedScan() {
+        try {
+            mService.pollBatchedScan();
+        } catch (RemoteException e) { }
+    }
+
     /**
      * Return dynamic information about the current Wi-Fi connection, if any is active.
      * @return the Wi-Fi information, contained in {@link WifiInfo}.
@@ -783,7 +887,7 @@
      */
     public List<ScanResult> getScanResults() {
         try {
-            return mService.getScanResults(mContext.getBasePackageName());
+            return mService.getScanResults(mContext.getOpPackageName());
         } catch (RemoteException e) {
             return null;
         }
@@ -1132,6 +1236,49 @@
         }
     }
 
+
+    /**
+     * Enable/Disable TDLS on a specific local route.
+     *
+     * <p>
+     * TDLS enables two wireless endpoints to talk to each other directly
+     * without going through the access point that is managing the local
+     * network. It saves bandwidth and improves quality of the link.
+     * </p>
+     * <p>
+     * This API enables/disables the option of using TDLS. If enabled, the
+     * underlying hardware is free to use TDLS or a hop through the access
+     * point. If disabled, existing TDLS session is torn down and
+     * hardware is restricted to use access point for transferring wireless
+     * packets. Default value for all routes is 'disabled', meaning restricted
+     * to use access point for transferring packets.
+     * </p>
+     *
+     * @param remoteIPAddress IP address of the endpoint to setup TDLS with
+     * @param enable true = setup and false = tear down TDLS
+     */
+    public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
+        try {
+            mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
+        } catch (RemoteException e) {
+            // Just ignore the exception
+        }
+    }
+
+    /**
+     * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
+     * this version allows you to specify remote endpoint with a MAC address.
+     * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
+     * @param enable true = setup and false = tear down TDLS
+     */
+    public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
+        try {
+            mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
+        } catch (RemoteException e) {
+            // Just ignore the exception
+        }
+    }
+
     /* TODO: deprecate synchronous API and open up the following API */
 
     private static final int BASE = Protocol.BASE_WIFI_MANAGER;
@@ -1223,6 +1370,13 @@
     /** WPS timed out {@hide} */
     public static final int WPS_TIMED_OUT               = 7;
 
+    /**
+     * Passed with {@link ActionListener#onFailure}.
+     * Indicates that the operation failed due to invalid inputs
+     * @hide
+     */
+    public static final int INVALID_ARGS                = 8;
+
     /** Interface for callback invocation on an application action {@hide} */
     public interface ActionListener {
         /** The operation succeeded */
@@ -1713,13 +1867,16 @@
                 boolean changed = true;
                 if (ws == null) {
                     mWorkSource = null;
-                } else if (mWorkSource == null) {
-                    changed = mWorkSource != null;
-                    mWorkSource = new WorkSource(ws);
                 } else {
-                    changed = mWorkSource.diff(ws);
-                    if (changed) {
-                        mWorkSource.set(ws);
+                    ws.clearNames();
+                    if (mWorkSource == null) {
+                        changed = mWorkSource != null;
+                        mWorkSource = new WorkSource(ws);
+                    } else {
+                        changed = mWorkSource.diff(ws);
+                        if (changed) {
+                            mWorkSource.set(ws);
+                        }
                     }
                 }
                 if (changed && mHeld) {
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index fe3c709..6817777 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -32,7 +32,10 @@
 import com.android.internal.util.Protocol;
 import com.android.internal.util.StateMachine;
 
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
@@ -44,6 +47,7 @@
  */
 public class WifiMonitor {
 
+    private static final boolean DBG = false;
     private static final String TAG = "WifiMonitor";
 
     /** Events we receive from the supplicant daemon */
@@ -279,9 +283,6 @@
     /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
     private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
 
-    private final StateMachine mStateMachine;
-    private final WifiNative mWifiNative;
-
     /* Supplicant events reported to a state machine */
     private static final int BASE = Protocol.BASE_WIFI_MONITOR;
 
@@ -347,164 +348,332 @@
     private static final String WPA_RECV_ERROR_STR = "recv error";
 
     /**
-     * Tracks consecutive receive errors
-     */
-    private int mRecvErrors = 0;
-
-    /**
      * Max errors before we close supplicant connection
      */
     private static final int MAX_RECV_ERRORS    = 10;
 
+    private final String mInterfaceName;
+    private final WifiNative mWifiNative;
+    private final StateMachine mWifiStateMachine;
+    private boolean mMonitoring;
+
     public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) {
-        mStateMachine = wifiStateMachine;
+        if (DBG) Log.d(TAG, "Creating WifiMonitor");
         mWifiNative = wifiNative;
+        mInterfaceName = wifiNative.mInterfaceName;
+        mWifiStateMachine = wifiStateMachine;
+        mMonitoring = false;
+
+        WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this);
     }
 
     public void startMonitoring() {
-        new MonitorThread().start();
+        WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName);
     }
 
-    class MonitorThread extends Thread {
-        public MonitorThread() {
-            super("WifiMonitor");
+    public void stopMonitoring() {
+        WifiMonitorSingleton.getMonitor().stopMonitoring(mInterfaceName);
+    }
+
+    public void stopSupplicant() {
+        WifiMonitorSingleton.getMonitor().stopSupplicant();
+    }
+
+    public void killSupplicant(boolean p2pSupported) {
+        WifiMonitorSingleton.getMonitor().killSupplicant(p2pSupported);
+    }
+
+    private static class WifiMonitorSingleton {
+        private static Object sSingletonLock = new Object();
+        private static WifiMonitorSingleton sWifiMonitorSingleton = null;
+        private HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>();
+        private boolean mConnected = false;
+        private WifiNative mWifiNative;
+
+        private WifiMonitorSingleton() {
         }
 
-        public void run() {
+        static WifiMonitorSingleton getMonitor() {
+            if (DBG) Log.d(TAG, "WifiMonitorSingleton gotten");
+            synchronized (sSingletonLock) {
+                if (sWifiMonitorSingleton == null) {
+                    if (DBG) Log.d(TAG, "WifiMonitorSingleton created");
+                    sWifiMonitorSingleton = new WifiMonitorSingleton();
+                }
+            }
+            return sWifiMonitorSingleton;
+        }
 
-            if (connectToSupplicant()) {
-                // Send a message indicating that it is now possible to send commands
-                // to the supplicant
-                mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
-            } else {
-                mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+        public synchronized void startMonitoring(String iface) {
+            WifiMonitor m = mIfaceMap.get(iface);
+            if (m == null) {
+                Log.e(TAG, "startMonitor called with unknown iface=" + iface);
                 return;
             }
 
+            Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected);
+
+            if (mConnected) {
+                m.mMonitoring = true;
+                m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
+            } else {
+                if (DBG) Log.d(TAG, "connecting to supplicant");
+                int connectTries = 0;
+                while (true) {
+                    if (mWifiNative.connectToSupplicant()) {
+                        m.mMonitoring = true;
+                        m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
+                        new MonitorThread(mWifiNative, this).start();
+                        mConnected = true;
+                        break;
+                    }
+                    if (connectTries++ < 5) {
+                        try {
+                            Thread.sleep(1000);
+                        } catch (InterruptedException ignore) {
+                        }
+                    } else {
+                        mIfaceMap.remove(iface);
+                        m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+                        Log.e(TAG, "startMonitoring(" + iface + ") failed!");
+                        break;
+                    }
+                }
+            }
+        }
+
+        public synchronized void stopMonitoring(String iface) {
+            WifiMonitor m = mIfaceMap.get(iface);
+            if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mWifiStateMachine);
+            m.mMonitoring = false;
+            m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+        }
+
+        public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) {
+            if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mWifiStateMachine + ")");
+            mIfaceMap.put(iface, m);
+            if (mWifiNative == null) {
+                mWifiNative = m.mWifiNative;
+            }
+        }
+
+        public synchronized void unregisterInterfaceMonitor(String iface) {
+            // REVIEW: When should we call this? If this isn't called, then WifiMonitor
+            // objects will remain in the mIfaceMap; and won't ever get deleted
+
+            WifiMonitor m = mIfaceMap.remove(iface);
+            if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mWifiStateMachine + ")");
+        }
+
+        public synchronized void stopSupplicant() {
+            mWifiNative.stopSupplicant();
+        }
+
+        public synchronized void killSupplicant(boolean p2pSupported) {
+            mWifiNative.killSupplicant(p2pSupported);
+            mConnected = false;
+            Iterator<Map.Entry<String, WifiMonitor>> it = mIfaceMap.entrySet().iterator();
+            while (it.hasNext()) {
+                Map.Entry<String, WifiMonitor> e = it.next();
+                WifiMonitor m = e.getValue();
+                m.mMonitoring = false;
+            }
+        }
+
+        private synchronized WifiMonitor getMonitor(String iface) {
+            return mIfaceMap.get(iface);
+        }
+    }
+
+    private static class MonitorThread extends Thread {
+        private final WifiNative mWifiNative;
+        private final WifiMonitorSingleton mWifiMonitorSingleton;
+        private int mRecvErrors = 0;
+        private StateMachine mStateMachine = null;
+
+        public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
+            super("WifiMonitor");
+            mWifiNative = wifiNative;
+            mWifiMonitorSingleton = wifiMonitorSingleton;
+        }
+
+        public void run() {
             //noinspection InfiniteLoopStatement
             for (;;) {
                 String eventStr = mWifiNative.waitForEvent();
 
                 // Skip logging the common but mostly uninteresting scan-results event
-                if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
+                if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
                     Log.d(TAG, "Event [" + eventStr + "]");
                 }
-                if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
-                    if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
-                            0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
-                        mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
-                    } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
-                        mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
-                    } else if (eventStr.startsWith(WPS_FAIL_STR)) {
-                        handleWpsFailEvent(eventStr);
-                    } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
-                        mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
-                    } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
-                        mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
-                    } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
-                        handleP2pEvents(eventStr);
-                    } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
-                        handleHostApEvents(eventStr);
-                    }
-                    continue;
-                }
 
-                String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
-                int nameEnd = eventName.indexOf(' ');
-                if (nameEnd != -1)
-                    eventName = eventName.substring(0, nameEnd);
-                if (eventName.length() == 0) {
-                    if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name");
-                    continue;
-                }
-                /*
-                 * Map event name into event enum
-                 */
-                int event;
-                if (eventName.equals(CONNECTED_STR))
-                    event = CONNECTED;
-                else if (eventName.equals(DISCONNECTED_STR))
-                    event = DISCONNECTED;
-                else if (eventName.equals(STATE_CHANGE_STR))
-                    event = STATE_CHANGE;
-                else if (eventName.equals(SCAN_RESULTS_STR))
-                    event = SCAN_RESULTS;
-                else if (eventName.equals(LINK_SPEED_STR))
-                    event = LINK_SPEED;
-                else if (eventName.equals(TERMINATING_STR))
-                    event = TERMINATING;
-                else if (eventName.equals(DRIVER_STATE_STR))
-                    event = DRIVER_STATE;
-                else if (eventName.equals(EAP_FAILURE_STR))
-                    event = EAP_FAILURE;
-                else if (eventName.equals(ASSOC_REJECT_STR))
-                    event = ASSOC_REJECT;
-                else
-                    event = UNKNOWN;
+                String iface = "p2p0";
+                WifiMonitor m = null;
+                mStateMachine = null;
 
-                String eventData = eventStr;
-                if (event == DRIVER_STATE || event == LINK_SPEED)
-                    eventData = eventData.split(" ")[1];
-                else if (event == STATE_CHANGE || event == EAP_FAILURE) {
-                    int ind = eventStr.indexOf(" ");
-                    if (ind != -1) {
-                        eventData = eventStr.substring(ind + 1);
+                if (eventStr.startsWith("IFNAME=")) {
+                    int space = eventStr.indexOf(' ');
+                    if (space != -1) {
+                        iface = eventStr.substring(7,space);
+                        m = mWifiMonitorSingleton.getMonitor(iface);
+                        if (m == null && iface.startsWith("p2p-")) {
+                            // p2p interfaces are created dynamically, but we have
+                            // only one P2p state machine monitoring all of them; look
+                            // for it explicitly, and send messages there ..
+                            m = mWifiMonitorSingleton.getMonitor("p2p0");
+                        }
+                        eventStr = eventStr.substring(space + 1);
                     }
                 } else {
-                    int ind = eventStr.indexOf(" - ");
-                    if (ind != -1) {
-                        eventData = eventStr.substring(ind + 3);
+                    // events without prefix belong to p2p0 monitor
+                    m = mWifiMonitorSingleton.getMonitor("p2p0");
+                }
+
+                if (m != null) {
+                    if (m.mMonitoring) {
+                        mStateMachine = m.mWifiStateMachine;
+                    } else {
+                        if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
+                                            ") is stopped");
+                        continue;
                     }
                 }
 
-                if (event == STATE_CHANGE) {
-                    handleSupplicantStateChange(eventData);
-                } else if (event == DRIVER_STATE) {
-                    handleDriverEvent(eventData);
-                } else if (event == TERMINATING) {
-                    /**
-                     * Close the supplicant connection if we see
-                     * too many recv errors
-                     */
-                    if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
-                        if (++mRecvErrors > MAX_RECV_ERRORS) {
-                            if (false) {
-                                Log.d(TAG, "too many recv errors, closing connection");
-                            }
-                        } else {
-                            continue;
+                if (mStateMachine != null) {
+                    if (dispatchEvent(eventStr)) {
+                        break;
+                    }
+                } else {
+                    if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
+                    boolean done = false;
+                    Iterator<Map.Entry<String, WifiMonitor>> it =
+                            mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
+                    while (it.hasNext()) {
+                        Map.Entry<String, WifiMonitor> e = it.next();
+                        m = e.getValue();
+                        mStateMachine = m.mWifiStateMachine;
+                        if (dispatchEvent(eventStr)) {
+                            done = true;
                         }
                     }
 
-                    // notify and exit
-                    mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
-                    break;
-                } else if (event == EAP_FAILURE) {
-                    if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
-                        mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+                    if (done) {
+                        // After this thread terminates, we'll no longer
+                        // be connected to the supplicant
+                        if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
+                        mWifiMonitorSingleton.mConnected = false;
+                        break;
                     }
-                } else if (event == ASSOC_REJECT) {
-                        mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
-                } else {
-                    handleEvent(event, eventData);
                 }
-                mRecvErrors = 0;
             }
         }
 
-        private boolean connectToSupplicant() {
-            int connectTries = 0;
+        /* @return true if the event was supplicant disconnection */
+        private boolean dispatchEvent(String eventStr) {
 
-            while (true) {
-                if (mWifiNative.connectToSupplicant()) {
-                    return true;
+            if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
+                if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
+                        0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
+                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+                } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
+                    mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
+                } else if (eventStr.startsWith(WPS_FAIL_STR)) {
+                    handleWpsFailEvent(eventStr);
+                } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
+                    mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
+                } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
+                    mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
+                } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
+                    handleP2pEvents(eventStr);
+                } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
+                    handleHostApEvents(eventStr);
                 }
-                if (connectTries++ < 5) {
-                    nap(1);
-                } else {
-                    break;
+                else {
+                    if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
+                }
+                return false;
+            }
+
+            String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
+            int nameEnd = eventName.indexOf(' ');
+            if (nameEnd != -1)
+                eventName = eventName.substring(0, nameEnd);
+            if (eventName.length() == 0) {
+                if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");
+                return false;
+            }
+            /*
+             * Map event name into event enum
+             */
+            int event;
+            if (eventName.equals(CONNECTED_STR))
+                event = CONNECTED;
+            else if (eventName.equals(DISCONNECTED_STR))
+                event = DISCONNECTED;
+            else if (eventName.equals(STATE_CHANGE_STR))
+                event = STATE_CHANGE;
+            else if (eventName.equals(SCAN_RESULTS_STR))
+                event = SCAN_RESULTS;
+            else if (eventName.equals(LINK_SPEED_STR))
+                event = LINK_SPEED;
+            else if (eventName.equals(TERMINATING_STR))
+                event = TERMINATING;
+            else if (eventName.equals(DRIVER_STATE_STR))
+                event = DRIVER_STATE;
+            else if (eventName.equals(EAP_FAILURE_STR))
+                event = EAP_FAILURE;
+            else if (eventName.equals(ASSOC_REJECT_STR))
+                event = ASSOC_REJECT;
+            else
+                event = UNKNOWN;
+
+            String eventData = eventStr;
+            if (event == DRIVER_STATE || event == LINK_SPEED)
+                eventData = eventData.split(" ")[1];
+            else if (event == STATE_CHANGE || event == EAP_FAILURE) {
+                int ind = eventStr.indexOf(" ");
+                if (ind != -1) {
+                    eventData = eventStr.substring(ind + 1);
+                }
+            } else {
+                int ind = eventStr.indexOf(" - ");
+                if (ind != -1) {
+                    eventData = eventStr.substring(ind + 3);
                 }
             }
+
+            if (event == STATE_CHANGE) {
+                handleSupplicantStateChange(eventData);
+            } else if (event == DRIVER_STATE) {
+                handleDriverEvent(eventData);
+            } else if (event == TERMINATING) {
+                /**
+                 * Close the supplicant connection if we see
+                 * too many recv errors
+                 */
+                if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
+                    if (++mRecvErrors > MAX_RECV_ERRORS) {
+                        if (DBG) {
+                            Log.d(TAG, "too many recv errors, closing connection");
+                        }
+                    } else {
+                        return false;
+                    }
+                }
+
+                // notify and exit
+                mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+                return true;
+            } else if (event == EAP_FAILURE) {
+                if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
+                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+                }
+            } else if (event == ASSOC_REJECT) {
+                mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
+            } else {
+                handleEvent(event, eventData);
+            }
+            mRecvErrors = 0;
             return false;
         }
 
@@ -723,71 +892,60 @@
             }
             notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState);
         }
-    }
 
-    private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
-        String BSSID = null;
-        int networkId = -1;
-        if (newState == NetworkInfo.DetailedState.CONNECTED) {
-            Matcher match = mConnectedEventPattern.matcher(data);
-            if (!match.find()) {
-                if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
-            } else {
-                BSSID = match.group(1);
-                try {
-                    networkId = Integer.parseInt(match.group(2));
-                } catch (NumberFormatException e) {
-                    networkId = -1;
+        private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
+            String BSSID = null;
+            int networkId = -1;
+            if (newState == NetworkInfo.DetailedState.CONNECTED) {
+                Matcher match = mConnectedEventPattern.matcher(data);
+                if (!match.find()) {
+                    if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
+                } else {
+                    BSSID = match.group(1);
+                    try {
+                        networkId = Integer.parseInt(match.group(2));
+                    } catch (NumberFormatException e) {
+                        networkId = -1;
+                    }
                 }
+                notifyNetworkStateChange(newState, BSSID, networkId);
             }
         }
-        notifyNetworkStateChange(newState, BSSID, networkId);
-    }
 
-    /**
-     * Send the state machine a notification that the state of Wifi connectivity
-     * has changed.
-     * @param networkId the configured network on which the state change occurred
-     * @param newState the new network state
-     * @param BSSID when the new state is {@link DetailedState#CONNECTED
-     * NetworkInfo.DetailedState.CONNECTED},
-     * this is the MAC address of the access point. Otherwise, it
-     * is {@code null}.
-     */
-    void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
-        if (newState == NetworkInfo.DetailedState.CONNECTED) {
-            Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
-                    netId, 0, BSSID);
-            mStateMachine.sendMessage(m);
-        } else {
-            Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
-                    netId, 0, BSSID);
-            mStateMachine.sendMessage(m);
+        /**
+         * Send the state machine a notification that the state of Wifi connectivity
+         * has changed.
+         * @param networkId the configured network on which the state change occurred
+         * @param newState the new network state
+         * @param BSSID when the new state is {@link DetailedState#CONNECTED
+         * NetworkInfo.DetailedState.CONNECTED},
+         * this is the MAC address of the access point. Otherwise, it
+         * is {@code null}.
+         */
+        void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
+            if (newState == NetworkInfo.DetailedState.CONNECTED) {
+                Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
+                        netId, 0, BSSID);
+                mStateMachine.sendMessage(m);
+            } else {
+                Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
+                        netId, 0, BSSID);
+                mStateMachine.sendMessage(m);
+            }
         }
-    }
 
-    /**
-     * Send the state machine a notification that the state of the supplicant
-     * has changed.
-     * @param networkId the configured network on which the state change occurred
-     * @param wifiSsid network name
-     * @param BSSID network address
-     * @param newState the new {@code SupplicantState}
-     */
-    void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
-            SupplicantState newState) {
-        mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
-                new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
-    }
-
-    /**
-     * Sleep for a period of time.
-     * @param secs the number of seconds to sleep
-     */
-    private static void nap(int secs) {
-        try {
-            Thread.sleep(secs * 1000);
-        } catch (InterruptedException ignore) {
+        /**
+         * Send the state machine a notification that the state of the supplicant
+         * has changed.
+         * @param networkId the configured network on which the state change occurred
+         * @param wifiSsid network name
+         * @param BSSID network address
+         * @param newState the new {@code SupplicantState}
+         */
+        void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
+                SupplicantState newState) {
+            mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
+                    new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index f637e89..520668e 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -20,10 +20,12 @@
 import android.net.wifi.p2p.WifiP2pGroup;
 import android.text.TextUtils;
 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
+import android.util.LocalLog;
 import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Native calls for bring up/shut down of the supplicant daemon and for
@@ -37,6 +39,7 @@
 public class WifiNative {
 
     private static final boolean DBG = false;
+    private static final boolean VDBG = false;
     private final String mTAG;
     private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
 
@@ -47,7 +50,13 @@
     static final int SCAN_WITHOUT_CONNECTION_SETUP          = 1;
     static final int SCAN_WITH_CONNECTION_SETUP             = 2;
 
-    String mInterface = "";
+    // Hold this lock before calling supplicant - it is required to
+    // mutually exclude access from Wifi and P2p state machines
+    static final Object mLock = new Object();
+
+    public final String mInterfaceName;
+    public final String mInterfacePrefix;
+
     private boolean mSuspendOptEnabled = false;
 
     public native static boolean loadDriver();
@@ -62,52 +71,108 @@
        or when the supplicant is hung */
     public native static boolean killSupplicant(boolean p2pSupported);
 
-    private native boolean connectToSupplicant(String iface);
+    private native boolean connectToSupplicantNative();
 
-    private native void closeSupplicantConnection(String iface);
+    private native void closeSupplicantConnectionNative();
 
     /**
      * Wait for the supplicant to send an event, returning the event string.
      * @return the event string sent by the supplicant.
      */
-    private native String waitForEvent(String iface);
+    private native String waitForEventNative();
 
-    private native boolean doBooleanCommand(String iface, String command);
+    private native boolean doBooleanCommandNative(String command);
 
-    private native int doIntCommand(String iface, String command);
+    private native int doIntCommandNative(String command);
 
-    private native String doStringCommand(String iface, String command);
+    private native String doStringCommandNative(String command);
 
-    public WifiNative(String iface) {
-        mInterface = iface;
-        mTAG = "WifiNative-" + iface;
+    public WifiNative(String interfaceName) {
+        mInterfaceName = interfaceName;
+        mTAG = "WifiNative-" + interfaceName;
+        if (!interfaceName.equals("p2p0")) {
+            mInterfacePrefix = "IFNAME=" + interfaceName + " ";
+        } else {
+            // commands for p2p0 interface don't need prefix
+            mInterfacePrefix = "";
+        }
+    }
+
+    private static final LocalLog mLocalLog = new LocalLog(1024);
+
+    // hold mLock before accessing mCmdIdLock
+    private int mCmdId;
+
+    public LocalLog getLocalLog() {
+        return mLocalLog;
+    }
+
+    private int getNewCmdIdLocked() {
+        return mCmdId++;
+    }
+
+    private void localLog(String s) {
+        if (mLocalLog != null)
+            mLocalLog.log(mInterfaceName + ": " + s);
     }
 
     public boolean connectToSupplicant() {
-        return connectToSupplicant(mInterface);
+        // No synchronization necessary .. it is implemented in WifiMonitor
+        if (VDBG) localLog(mInterfacePrefix + "connectToSupplicant");
+        return connectToSupplicantNative();
     }
 
     public void closeSupplicantConnection() {
-        closeSupplicantConnection(mInterface);
+        if (VDBG) localLog(mInterfacePrefix + "closeSupplicantConnection");
+        closeSupplicantConnectionNative();
     }
 
     public String waitForEvent() {
-        return waitForEvent(mInterface);
+        // No synchronization necessary .. it is implemented in WifiMonitor
+        return waitForEventNative();
     }
 
     private boolean doBooleanCommand(String command) {
         if (DBG) Log.d(mTAG, "doBoolean: " + command);
-        return doBooleanCommand(mInterface, command);
+        synchronized (mLock) {
+            int cmdId = getNewCmdIdLocked();
+            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            boolean result = doBooleanCommandNative(mInterfacePrefix + command);
+            if (VDBG) localLog(cmdId + "<-" + result);
+            if (DBG) Log.d(mTAG, "   returned " + result);
+            return result;
+        }
     }
 
     private int doIntCommand(String command) {
         if (DBG) Log.d(mTAG, "doInt: " + command);
-        return doIntCommand(mInterface, command);
+        synchronized (mLock) {
+            int cmdId = getNewCmdIdLocked();
+            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            int result = doIntCommandNative(mInterfacePrefix + command);
+            if (VDBG) localLog(cmdId + "<-" + result);
+            if (DBG) Log.d(mTAG, "   returned " + result);
+            return result;
+        }
     }
 
     private String doStringCommand(String command) {
         if (DBG) Log.d(mTAG, "doString: " + command);
-        return doStringCommand(mInterface, command);
+        synchronized (mLock) {
+            int cmdId = getNewCmdIdLocked();
+            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            String result = doStringCommandNative(mInterfacePrefix + command);
+            if (VDBG) localLog(cmdId + "<-" + result);
+            if (DBG) Log.d(mTAG, "   returned " + result);
+            return result;
+        }
+    }
+
+    private String doStringCommandWithoutLogging(String command) {
+        if (DBG) Log.d(mTAG, "doString: " + command);
+        synchronized (mLock) {
+            return doStringCommandNative(mInterfacePrefix + command);
+        }
     }
 
     public boolean ping() {
@@ -150,7 +215,9 @@
 
     public String getNetworkVariable(int netId, String name) {
         if (TextUtils.isEmpty(name)) return null;
-        return doStringCommand("GET_NETWORK " + netId + " " + name);
+
+        // GET_NETWORK will likely flood the logs ...
+        return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name);
     }
 
     public boolean removeNetwork(int netId) {
@@ -213,7 +280,47 @@
      * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details
      */
     public String scanResults(int sid) {
-        return doStringCommand("BSS RANGE=" + sid + "- MASK=0x21987");
+        return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x21987");
+    }
+
+    /**
+     * Format of command
+     * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s
+     * where x is an ascii representation of an integer number of seconds between scans
+     *       r is an ascii representation of an integer number of scans per batch
+     *       y is an ascii representation of an integer number of the max AP to remember per scan
+     *       z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values
+     *           indicating entire ranges of channels
+     *       s is an ascii representation of an integer number of highest-strength AP
+     *           for which we'd like approximate distance reported
+     *
+     * The return value is an ascii integer representing a guess of the number of scans
+     * the firmware can remember before it runs out of buffer space or -1 on error
+     */
+    public String setBatchedScanSettings(BatchedScanSettings settings) {
+        if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
+        String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
+        cmd += " MSCAN=" + settings.maxScansPerBatch;
+        if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
+            cmd += " BESTN=" + settings.maxApPerScan;
+        }
+        if (settings.channelSet != null && !settings.channelSet.isEmpty()) {
+            cmd += " CHANNEL=<";
+            int i = 0;
+            for (String channel : settings.channelSet) {
+                cmd += (i > 0 ? "," : "") + channel;
+                ++i;
+            }
+            cmd += ">";
+        }
+        if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) {
+            cmd += " RTT=" + settings.maxApForDistance;
+        }
+        return doStringCommand(cmd);
+    }
+
+    public String getBatchedScanResults() {
+        return doStringCommand("DRIVER WLS_BATCHING GET");
     }
 
     public boolean startDriver() {
@@ -355,7 +462,7 @@
     }
 
     public boolean setCountryCode(String countryCode) {
-        return doBooleanCommand("DRIVER COUNTRY " + countryCode);
+        return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
     }
 
     public void enableBackgroundScan(boolean enable) {
@@ -370,6 +477,15 @@
         doBooleanCommand("SCAN_INTERVAL " + scanInterval);
     }
 
+    public void startTdls(String macAddr, boolean enable) {
+        if (enable) {
+            doBooleanCommand("TDLS_DISCOVER " + macAddr);
+            doBooleanCommand("TDLS_SETUP " + macAddr);
+        } else {
+            doBooleanCommand("TDLS_TEARDOWN " + macAddr);
+        }
+    }
+
     /** Example output:
      * RSSI=-65
      * LINKSPEED=48
@@ -377,7 +493,7 @@
      * FREQUENCY=0
      */
     public String signalPoll() {
-        return doStringCommand("SIGNAL_POLL");
+        return doStringCommandWithoutLogging("SIGNAL_POLL");
     }
 
     /** Example outout:
@@ -388,6 +504,10 @@
         return doStringCommand("PKTCNT_POLL");
     }
 
+    public void bssFlush() {
+        doBooleanCommand("BSS_FLUSH 0");
+    }
+
     public boolean startWpsPbc(String bssid) {
         if (TextUtils.isEmpty(bssid)) {
             return doBooleanCommand("WPS_PBC");
@@ -397,10 +517,12 @@
     }
 
     public boolean startWpsPbc(String iface, String bssid) {
-        if (TextUtils.isEmpty(bssid)) {
-            return doBooleanCommand("WPS_PBC interface=" + iface);
-        } else {
-            return doBooleanCommand("WPS_PBC interface=" + iface + " " + bssid);
+        synchronized (mLock) {
+            if (TextUtils.isEmpty(bssid)) {
+                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
+            } else {
+                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
+            }
         }
     }
 
@@ -411,7 +533,9 @@
 
     public boolean startWpsPinKeypad(String iface, String pin) {
         if (TextUtils.isEmpty(pin)) return false;
-        return doBooleanCommand("WPS_PIN interface=" + iface + " any " + pin);
+        synchronized (mLock) {
+            return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
+        }
     }
 
 
@@ -424,10 +548,12 @@
     }
 
     public String startWpsPinDisplay(String iface, String bssid) {
-        if (TextUtils.isEmpty(bssid)) {
-            return doStringCommand("WPS_PIN interface=" + iface + " any");
-        } else {
-            return doStringCommand("WPS_PIN interface=" + iface + " " + bssid);
+        synchronized (mLock) {
+            if (TextUtils.isEmpty(bssid)) {
+                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
+            } else {
+                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
+            }
         }
     }
 
@@ -479,7 +605,9 @@
     }
 
     public boolean setP2pGroupIdle(String iface, int time) {
-        return doBooleanCommand("SET interface=" + iface + " p2p_group_idle " + time);
+        synchronized (mLock) {
+            return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
+        }
     }
 
     public void setPowerSave(boolean enabled) {
@@ -491,10 +619,12 @@
     }
 
     public boolean setP2pPowerSave(String iface, boolean enabled) {
-        if (enabled) {
-            return doBooleanCommand("P2P_SET interface=" + iface + " ps 1");
-        } else {
-            return doBooleanCommand("P2P_SET interface=" + iface + " ps 0");
+        synchronized (mLock) {
+            if (enabled) {
+                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
+            } else {
+                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
+            }
         }
     }
 
@@ -540,6 +670,37 @@
         return doBooleanCommand("P2P_LISTEN " + timeout);
     }
 
+    public boolean p2pExtListen(boolean enable, int period, int interval) {
+        if (enable && interval < period) {
+            return false;
+        }
+        return doBooleanCommand("P2P_EXT_LISTEN"
+                    + (enable ? (" " + period + " " + interval) : ""));
+    }
+
+    public boolean p2pSetChannel(int lc, int oc) {
+        if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
+
+        if (lc >=1 && lc <= 11) {
+            if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
+                return false;
+            }
+        } else if (lc != 0) {
+            return false;
+        }
+
+        if (oc >= 1 && oc <= 165 ) {
+            int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
+            return doBooleanCommand("P2P_SET disallow_freq 1000-"
+                    + (freq - 5) + "," + (freq + 5) + "-6000");
+        } else if (oc == 0) {
+            /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
+            return doBooleanCommand("P2P_SET disallow_freq \"\"");
+        }
+
+        return false;
+    }
+
     public boolean p2pFlush() {
         return doBooleanCommand("P2P_FLUSH");
     }
@@ -632,7 +793,9 @@
 
     public boolean p2pGroupRemove(String iface) {
         if (TextUtils.isEmpty(iface)) return false;
-        return doBooleanCommand("P2P_GROUP_REMOVE " + iface);
+        synchronized (mLock) {
+            return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
+        }
     }
 
     public boolean p2pReject(String deviceAddress) {
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index 55e9b2d..a35a34b 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -27,6 +27,7 @@
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
+import java.util.Locale;
 
 /**
  * Stores SSID octets and handles conversion.
@@ -199,7 +200,7 @@
         String out = "0x";
         byte[] ssidbytes = getOctets();
         for (int i = 0; i < octets.size(); i++) {
-            out += String.format("%02x", ssidbytes[i]);
+            out += String.format(Locale.US, "%02x", ssidbytes[i]);
         }
         return out;
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index ebc94e0..798bc2e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -51,9 +51,11 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
+import android.net.RouteInfo;
 import android.net.wifi.WpsResult.Status;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.net.wifi.p2p.WifiP2pService;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -63,10 +65,12 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.util.Log;
 import android.util.LruCache;
 import android.text.TextUtils;
 
@@ -77,12 +81,14 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
+import com.android.server.net.BaseNetworkObserver;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.InetAddress;
+import java.net.Inet6Address;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.Iterator;
@@ -121,6 +127,13 @@
     private static final int SCAN_RESULT_CACHE_SIZE = 80;
     private final LruCache<String, ScanResult> mScanResultCache;
 
+    /* Batch scan results */
+    private final List<BatchedScanResult> mBatchedScanResults =
+            new ArrayList<BatchedScanResult>();
+    private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE;
+    private int mExpectedBatchedScans = 0;
+    private long mBatchedScanMinPollTime = 0;
+
     /* Chipset supports background scan */
     private final boolean mBackgroundScanSupported;
 
@@ -189,8 +202,19 @@
     /* Tracks sequence number on a driver time out */
     private int mDriverStartToken = 0;
 
+    /**
+     * The link properties of the wifi interface.
+     * Do not modify this directly; use updateLinkProperties instead.
+     */
     private LinkProperties mLinkProperties;
 
+    /**
+     * Subset of link properties coming from netlink.
+     * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
+     * and domains obtained from router advertisements (RFC 6106).
+     */
+    private final LinkProperties mNetlinkLinkProperties;
+
     /* Tracks sequence number on a periodic scan message */
     private int mPeriodicScanToken = 0;
 
@@ -205,10 +229,45 @@
     private NetworkInfo mNetworkInfo;
     private SupplicantStateTracker mSupplicantStateTracker;
     private DhcpStateMachine mDhcpStateMachine;
+    private boolean mDhcpActive = false;
+
+    private class InterfaceObserver extends BaseNetworkObserver {
+        private WifiStateMachine mWifiStateMachine;
+
+        InterfaceObserver(WifiStateMachine wifiStateMachine) {
+            super();
+            mWifiStateMachine = wifiStateMachine;
+        }
+
+        @Override
+        public void addressUpdated(String address, String iface, int flags, int scope) {
+            if (mWifiStateMachine.mInterfaceName.equals(iface)) {
+                if (DBG) {
+                    log("addressUpdated: " + address + " on " + iface +
+                        " flags " + flags + " scope " + scope);
+                }
+                mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, new LinkAddress(address));
+            }
+        }
+
+        @Override
+        public void addressRemoved(String address, String iface, int flags, int scope) {
+            if (mWifiStateMachine.mInterfaceName.equals(iface)) {
+                if (DBG) {
+                    log("addressRemoved: " + address + " on " + iface +
+                        " flags " + flags + " scope " + scope);
+                }
+                mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, new LinkAddress(address));
+            }
+        }
+    }
+
+    private InterfaceObserver mInterfaceObserver;
 
     private AlarmManager mAlarmManager;
     private PendingIntent mScanIntent;
     private PendingIntent mDriverStopIntent;
+    private PendingIntent mBatchedScanIntervalIntent;
 
     /* Tracks current frequency mode */
     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
@@ -337,6 +396,8 @@
     static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
     /* Enable background scan for configured networks */
     static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
+    /* Enable TDLS on a specific MAC address */
+    static final int CMD_ENABLE_TDLS                      = BASE + 92;
 
     /* Commands from/to the SupplicantStateTracker */
     /* Reset the supplicant state tracker */
@@ -352,8 +413,26 @@
 
     public static final int CMD_BOOT_COMPLETED            = BASE + 134;
 
+    /* change the batch scan settings.
+     * arg1 = responsible UID
+     * obj = the new settings
+     */
+    public static final int CMD_SET_BATCHED_SCAN          = BASE + 135;
+    public static final int CMD_START_NEXT_BATCHED_SCAN   = BASE + 136;
+    public static final int CMD_POLL_BATCHED_SCAN         = BASE + 137;
+
+    /* Link configuration (IP address, DNS, ...) changes */
+    /* An new IP address was added to our interface, or an existing IP address was updated */
+    static final int CMD_IP_ADDRESS_UPDATED               = BASE + 140;
+    /* An IP address was removed from our interface */
+    static final int CMD_IP_ADDRESS_REMOVED               = BASE + 141;
+
+    /* Wifi state machine modes of operation */
+    /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
     public static final int CONNECT_MODE                   = 1;
+    /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
     public static final int SCAN_ONLY_MODE                 = 2;
+    /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE   = 3;
 
     private static final int SUCCESS = 1;
@@ -516,6 +595,8 @@
     private static final String ACTION_DELAYED_DRIVER_STOP =
         "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
 
+    private static final String ACTION_REFRESH_BATCHED_SCAN =
+            "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN";
     /**
      * Keep track of whether WIFI is running.
      */
@@ -538,14 +619,17 @@
 
     private final IBatteryStats mBatteryStats;
 
+    private BatchedScanSettings mBatchedScanSettings = null;
+
+
     public WifiStateMachine(Context context, String wlanInterface) {
         super("WifiStateMachine");
-
         mContext = context;
         mInterfaceName = wlanInterface;
 
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
-        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
+                BatteryStats.SERVICE_NAME));
 
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
         mNwService = INetworkManagementService.Stub.asInterface(b);
@@ -560,19 +644,29 @@
         mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
                 getHandler());
         mLinkProperties = new LinkProperties();
+        mNetlinkLinkProperties = new LinkProperties();
 
         mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
 
         mNetworkInfo.setIsAvailable(false);
-        mLinkProperties.clear();
         mLastBssid = null;
         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
         mLastSignalLevel = -1;
 
+        mInterfaceObserver = new InterfaceObserver(this);
+        try {
+            mNwService.registerObserver(mInterfaceObserver);
+        } catch (RemoteException e) {
+            loge("Couldn't register interface observer: " + e.toString());
+        }
+
         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
         Intent scanIntent = new Intent(ACTION_START_SCAN, null);
         mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
 
+        Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
+        mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0);
+
         mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
                 R.integer.config_wifi_framework_scan_interval);
 
@@ -604,27 +698,31 @@
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        startScan(UNKNOWN_SCAN_SOURCE);
+                        final WorkSource workSource = null;
+                        startScan(UNKNOWN_SCAN_SOURCE, workSource);
                     }
                 },
                 new IntentFilter(ACTION_START_SCAN));
 
-        IntentFilter screenFilter = new IntentFilter();
-        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
-        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
-        BroadcastReceiver screenReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_SCREEN_ON);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        String action = intent.getAction();
 
-                if (action.equals(Intent.ACTION_SCREEN_ON)) {
-                    handleScreenStateChanged(true);
-                } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
-                    handleScreenStateChanged(false);
-                }
-            }
-        };
-        mContext.registerReceiver(screenReceiver, screenFilter);
+                        if (action.equals(Intent.ACTION_SCREEN_ON)) {
+                            handleScreenStateChanged(true);
+                        } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+                            handleScreenStateChanged(false);
+                        } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
+                            startNextBatchedScanAsync();
+                        }
+                    }
+                }, filter);
 
         mContext.registerReceiver(
                 new BroadcastReceiver() {
@@ -691,7 +789,7 @@
 
         setInitialState(mInitialState);
 
-        setLogRecSize(300);
+        setLogRecSize(2000);
         setLogOnlyTransitions(false);
         if (DBG) setDbg(true);
 
@@ -722,15 +820,321 @@
     }
 
     /**
-     * TODO: doc
+     * Initiate a wifi scan.  If workSource is not null, blame is given to it,
+     * otherwise blame is given to callingUid.
+     *
+     * @param callingUid The uid initiating the wifi scan.  Blame will be given
+     *                   here unless workSource is specified.
+     * @param workSource If not null, blame is given to workSource.
      */
-    public void startScan(int callingUid) {
-        sendMessage(CMD_START_SCAN, callingUid);
+    public void startScan(int callingUid, WorkSource workSource) {
+        sendMessage(CMD_START_SCAN, callingUid, 0, workSource);
     }
 
-    private void noteScanStart(int callingUid) {
-        if (mScanWorkSource == null && callingUid != UNKNOWN_SCAN_SOURCE) {
-            mScanWorkSource = new WorkSource(callingUid);
+    /**
+     * start or stop batched scanning using the given settings
+     */
+    public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid) {
+        sendMessage(CMD_SET_BATCHED_SCAN, callingUid, 0, settings);
+    }
+
+    public List<BatchedScanResult> syncGetBatchedScanResultsList() {
+        synchronized (mBatchedScanResults) {
+            List<BatchedScanResult> batchedScanList =
+                    new ArrayList<BatchedScanResult>(mBatchedScanResults.size());
+            for(BatchedScanResult result: mBatchedScanResults) {
+                batchedScanList.add(new BatchedScanResult(result));
+            }
+            return batchedScanList;
+        }
+    }
+
+    public void requestBatchedScanPoll() {
+        sendMessage(CMD_POLL_BATCHED_SCAN);
+    }
+
+    private void startBatchedScan() {
+        if (mDhcpActive) {
+            if (DBG) log("not starting Batched Scans due to DHCP");
+            return;
+        }
+
+        // first grab any existing data
+        retrieveBatchedScanData();
+
+        mAlarmManager.cancel(mBatchedScanIntervalIntent);
+
+        String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
+
+        try {
+            mExpectedBatchedScans = Integer.parseInt(scansExpected);
+            setNextBatchedAlarm(mExpectedBatchedScans);
+        } catch (NumberFormatException e) {
+            stopBatchedScan();
+            loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
+        }
+    }
+
+    // called from BroadcastListener
+    private void startNextBatchedScanAsync() {
+        sendMessage(CMD_START_NEXT_BATCHED_SCAN);
+    }
+
+    private void startNextBatchedScan() {
+        // first grab any existing data
+        retrieveBatchedScanData();
+
+        setNextBatchedAlarm(mExpectedBatchedScans);
+    }
+
+    private void handleBatchedScanPollRequest() {
+        if (DBG) {
+            log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" +
+                    mBatchedScanMinPollTime + " , mBatchedScanSettings=" +
+                    mBatchedScanSettings);
+        }
+        // if there is no appropriate PollTime that's because we either aren't
+        // batching or we've already set a time for a poll request
+        if (mBatchedScanMinPollTime == 0) return;
+        if (mBatchedScanSettings == null) return;
+
+        long now = System.currentTimeMillis();
+
+        if (now > mBatchedScanMinPollTime) {
+            // do the poll and reset our timers
+            startNextBatchedScan();
+        } else {
+            mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime,
+                    mBatchedScanIntervalIntent);
+            mBatchedScanMinPollTime = 0;
+        }
+    }
+
+    // return true if new/different
+    private boolean recordBatchedScanSettings(BatchedScanSettings settings) {
+        if (DBG) log("set batched scan to " + settings);
+        if (settings != null) {
+            // TODO - noteBatchedScanStart(message.arg1);
+            if (settings.equals(mBatchedScanSettings)) return false;
+        } else {
+            if (mBatchedScanSettings == null) return false;
+            // TODO - noteBatchedScanStop(message.arg1);
+        }
+        mBatchedScanSettings = settings;
+        return true;
+    }
+
+    private void stopBatchedScan() {
+        mAlarmManager.cancel(mBatchedScanIntervalIntent);
+        if (mBatchedScanSettings != null) {
+            retrieveBatchedScanData();
+            mWifiNative.setBatchedScanSettings(null);
+        }
+    }
+
+    private void setNextBatchedAlarm(int scansExpected) {
+
+        if (mBatchedScanSettings == null || scansExpected < 1) return;
+
+        mBatchedScanMinPollTime = System.currentTimeMillis() +
+                mBatchedScanSettings.scanIntervalSec * 1000;
+
+        if (mBatchedScanSettings.maxScansPerBatch < scansExpected) {
+            scansExpected = mBatchedScanSettings.maxScansPerBatch;
+        }
+
+        int secToFull = mBatchedScanSettings.scanIntervalSec;
+        secToFull *= scansExpected;
+
+        int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0);
+        if (debugPeriod > 0) secToFull = debugPeriod;
+
+        // set the alarm to do the next poll.  We set it a little short as we'd rather
+        // wake up wearly than miss a scan due to buffer overflow
+        mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+                + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000),
+                mBatchedScanIntervalIntent);
+    }
+
+    /**
+     * Start reading new scan data
+     * Data comes in as:
+     * "scancount=5\n"
+     * "nextcount=5\n"
+     *   "apcount=3\n"
+     *   "trunc\n" (optional)
+     *     "bssid=...\n"
+     *     "ssid=...\n"
+     *     "freq=...\n" (in Mhz)
+     *     "level=...\n"
+     *     "dist=...\n" (in cm)
+     *     "distsd=...\n" (standard deviation, in cm)
+     *     "===="
+     *     "bssid=...\n"
+     *     etc
+     *     "===="
+     *     "bssid=...\n"
+     *     etc
+     *     "%%%%"
+     *   "apcount=2\n"
+     *     "bssid=...\n"
+     *     etc
+     *     "%%%%
+     *   etc
+     *   "----"
+     */
+    private final static boolean DEBUG_PARSE = false;
+    private void retrieveBatchedScanData() {
+        String rawData = mWifiNative.getBatchedScanResults();
+        if (DEBUG_PARSE) log("rawData = " + rawData);
+        mBatchedScanMinPollTime = 0;
+        if (rawData == null || rawData.equalsIgnoreCase("OK")) {
+            loge("Unexpected BatchedScanResults :" + rawData);
+            return;
+        }
+
+        int scanCount = 0;
+        final String END_OF_BATCHES = "----";
+        final String SCANCOUNT = "scancount=";
+        final String TRUNCATED = "trunc";
+        final String AGE = "age=";
+        final String DIST = "dist=";
+        final String DISTSD = "distSd=";
+
+        String splitData[] = rawData.split("\n");
+        int n = 0;
+        if (splitData[n].startsWith(SCANCOUNT)) {
+            try {
+                scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length()));
+            } catch (NumberFormatException e) {
+                loge("scancount parseInt Exception from " + splitData[n]);
+            }
+        } else log("scancount not found");
+        if (scanCount == 0) {
+            loge("scanCount==0 - aborting");
+            return;
+        }
+
+        final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+        synchronized (mBatchedScanResults) {
+            mBatchedScanResults.clear();
+            BatchedScanResult batchedScanResult = new BatchedScanResult();
+
+            String bssid = null;
+            WifiSsid wifiSsid = null;
+            int level = 0;
+            int freq = 0;
+            int dist, distSd;
+            long tsf = 0;
+            dist = distSd = ScanResult.UNSPECIFIED;
+            long now = SystemClock.elapsedRealtime();
+
+            while (true) {
+                while (n < splitData.length) {
+                    if (DEBUG_PARSE) logd("parsing " + splitData[n]);
+                    if (splitData[n].equals(END_OF_BATCHES)) {
+                        if (n+1 != splitData.length) {
+                            loge("didn't consume " + (splitData.length-n));
+                        }
+                        if (mBatchedScanResults.size() > 0) {
+                            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+                        }
+                        logd("retrieveBatchedScanResults X");
+                        return;
+                    }
+                    if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) {
+                        if (bssid != null) {
+                            batchedScanResult.scanResults.add(new ScanResult(
+                                    wifiSsid, bssid, "", level, freq, tsf, dist, distSd));
+                            wifiSsid = null;
+                            bssid = null;
+                            level = 0;
+                            freq = 0;
+                            tsf = 0;
+                            dist = distSd = ScanResult.UNSPECIFIED;
+                        }
+                        if (splitData[n].equals(END_STR)) {
+                            if (batchedScanResult.scanResults.size() != 0) {
+                                mBatchedScanResults.add(batchedScanResult);
+                                batchedScanResult = new BatchedScanResult();
+                            } else {
+                                logd("Found empty batch");
+                            }
+                        }
+                    } else if (splitData[n].equals(TRUNCATED)) {
+                        batchedScanResult.truncated = true;
+                    } else if (splitData[n].startsWith(BSSID_STR)) {
+                        bssid = splitData[n].substring(BSSID_STR.length());
+                    } else if (splitData[n].startsWith(FREQ_STR)) {
+                        try {
+                            freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length()));
+                        } catch (NumberFormatException e) {
+                            loge("Invalid freqency: " + splitData[n]);
+                            freq = 0;
+                        }
+                    } else if (splitData[n].startsWith(AGE)) {
+                        try {
+                            tsf = now - Long.parseLong(splitData[n].substring(AGE.length()));
+                            tsf *= 1000; // convert mS -> uS
+                        } catch (NumberFormatException e) {
+                            loge("Invalid timestamp: " + splitData[n]);
+                            tsf = 0;
+                        }
+                    } else if (splitData[n].startsWith(SSID_STR)) {
+                        wifiSsid = WifiSsid.createFromAsciiEncoded(
+                                splitData[n].substring(SSID_STR.length()));
+                    } else if (splitData[n].startsWith(LEVEL_STR)) {
+                        try {
+                            level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length()));
+                            if (level > 0) level -= 256;
+                        } catch (NumberFormatException e) {
+                            loge("Invalid level: " + splitData[n]);
+                            level = 0;
+                        }
+                    } else if (splitData[n].startsWith(DIST)) {
+                        try {
+                            dist = Integer.parseInt(splitData[n].substring(DIST.length()));
+                        } catch (NumberFormatException e) {
+                            loge("Invalid distance: " + splitData[n]);
+                            dist = ScanResult.UNSPECIFIED;
+                        }
+                    } else if (splitData[n].startsWith(DISTSD)) {
+                        try {
+                            distSd = Integer.parseInt(splitData[n].substring(DISTSD.length()));
+                        } catch (NumberFormatException e) {
+                            loge("Invalid distanceSd: " + splitData[n]);
+                            distSd = ScanResult.UNSPECIFIED;
+                        }
+                    } else {
+                        loge("Unable to parse batched scan result line: " + splitData[n]);
+                    }
+                    n++;
+                }
+                rawData = mWifiNative.getBatchedScanResults();
+                if (DEBUG_PARSE) log("reading more data:\n" + rawData);
+                if (rawData == null) {
+                    loge("Unexpected null BatchedScanResults");
+                    return;
+                }
+                splitData = rawData.split("\n");
+                if (splitData.length == 0 || splitData[0].equals("ok")) {
+                    loge("batch scan results just ended!");
+                    if (mBatchedScanResults.size() > 0) {
+                        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+                    }
+                    return;
+                }
+                n = 0;
+            }
+        }
+    }
+
+    // If workSource is not null, blame is given to it, otherwise blame is given to callingUid.
+    private void noteScanStart(int callingUid, WorkSource workSource) {
+        if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) {
+            mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid);
             try {
                 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource);
             } catch (RemoteException e) {
@@ -877,6 +1281,7 @@
      * TODO: doc
      */
     public void setOperationalMode(int mode) {
+        if (DBG) log("setting operational mode to " + String.valueOf(mode));
         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
     }
 
@@ -1051,11 +1456,9 @@
     public void setCountryCode(String countryCode, boolean persist) {
         if (persist) {
             mPersistedCountryCode = countryCode;
-            Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.WIFI_COUNTRY_CODE,
-                    countryCode);
         }
         sendMessage(CMD_SET_COUNTRY_CODE, countryCode);
+        mWifiP2pChannel.sendMessage(WifiP2pService.SET_COUNTRY_CODE, countryCode);
     }
 
     /**
@@ -1073,6 +1476,14 @@
     }
 
     /**
+     * Enable TDLS for a specific MAC address
+     */
+    public void enableTdls(String remoteMacAddress, boolean enable) {
+        int enabler = enable ? 1 : 0;
+        sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
+    }
+
+    /**
      * Returns the operational frequency band
      */
     public int getFrequencyBand() {
@@ -1277,8 +1688,8 @@
      * Set the country code from the system setting value, if any.
      */
     private void setCountryCode() {
-        String countryCode = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.WIFI_COUNTRY_CODE);
+        String countryCode = mContext.getResources().getString(
+                                    R.string.config_wifi_default_country_code);
         if (countryCode != null && !countryCode.isEmpty()) {
             setCountryCode(countryCode, false);
         } else {
@@ -1584,19 +1995,82 @@
         }
     }
 
-    private void configureLinkProperties() {
-        if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
-            mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId);
-        } else {
-            synchronized (mDhcpResultsLock) {
-                if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) {
-                    mLinkProperties = mDhcpResults.linkProperties;
+    /**
+     * Updates mLinkProperties by merging information from various sources.
+     *
+     * This is needed because the information in mLinkProperties comes from multiple sources (DHCP,
+     * netlink, static configuration, ...). When one of these sources of information has updated
+     * link properties, we can't just assign them to mLinkProperties or we'd lose track of the
+     * information that came from other sources. Instead, when one of those sources has new
+     * information, we update the object that tracks the information from that source and then
+     * call this method to apply the change to mLinkProperties.
+     *
+     * The information in mLinkProperties is currently obtained as follows:
+     * - Interface name: set in the constructor.
+     * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver.
+     * - IPv4 routes, DNS servers, and domains: DHCP.
+     * - HTTP proxy: the wifi config store.
+     */
+    private void updateLinkProperties() {
+        LinkProperties newLp = new LinkProperties();
+
+        // Interface name and proxy are locally configured.
+        newLp.setInterfaceName(mInterfaceName);
+        newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
+
+        // IPv4 and IPv6 addresses come from netlink.
+        newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses());
+
+        // For now, routing and DNS only come from DHCP or static configuration. In the future,
+        // we'll need to merge IPv6 DNS servers and domains coming from netlink.
+        synchronized (mDhcpResultsLock) {
+            // Even when we're using static configuration, we don't need to look at the config
+            // store, because static IP configuration also populates mDhcpResults.
+            if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) {
+                LinkProperties lp = mDhcpResults.linkProperties;
+                for (RouteInfo route: lp.getRoutes()) {
+                    newLp.addRoute(route);
                 }
+                for (InetAddress dns: lp.getDnses()) {
+                    newLp.addDns(dns);
+                }
+                newLp.setDomains(lp.getDomains());
             }
-            mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
         }
-        mLinkProperties.setInterfaceName(mInterfaceName);
-        if (DBG) log("netId=" + mLastNetworkId  + " Link configured: " + mLinkProperties);
+
+        // If anything has changed, and we're already connected, send out a notification.
+        // If we're still connecting, apps will be notified when we connect.
+        if (!newLp.equals(mLinkProperties)) {
+            if (DBG) {
+                log("Link configuration changed for netId: " + mLastNetworkId
+                        + " old: " + mLinkProperties + "new: " + newLp);
+            }
+            mLinkProperties = newLp;
+            if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+                sendLinkConfigurationChangedBroadcast();
+            }
+        }
+    }
+
+    /**
+     * Clears all our link properties.
+     */
+    private void clearLinkProperties() {
+        // If the network used DHCP, clear the LinkProperties we stored in the config store.
+        if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+            mWifiConfigStore.clearLinkProperties(mLastNetworkId);
+        }
+
+        // Clear the link properties obtained from DHCP and netlink.
+        synchronized(mDhcpResultsLock) {
+            if (mDhcpResults != null && mDhcpResults.linkProperties != null) {
+                mDhcpResults.linkProperties.clear();
+            }
+        }
+        mNetlinkLinkProperties.clear();
+
+        // Now clear the merged link properties.
+        mLinkProperties.clear();
     }
 
     private int getMaxDhcpRetries() {
@@ -1719,16 +2193,11 @@
         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
 
         /* Clear network properties */
-        mLinkProperties.clear();
+        clearLinkProperties();
 
         /* send event to CM & network change broadcast */
         sendNetworkStateChangeBroadcast(mLastBssid);
 
-        /* Clear IP settings if the network used DHCP */
-        if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
-            mWifiConfigStore.clearLinkProperties(mLastNetworkId);
-        }
-
         mLastBssid= null;
         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
     }
@@ -1737,13 +2206,13 @@
         /* Socket connection can be lost when we do a graceful shutdown
         * or when the driver is hung. Ensure supplicant is stopped here.
         */
-        mWifiNative.killSupplicant(mP2pSupported);
-        mWifiNative.closeSupplicantConnection();
+        mWifiMonitor.killSupplicant(mP2pSupported);
         sendSupplicantConnectionChangedBroadcast(false);
         setWifiState(WIFI_STATE_DISABLED);
     }
 
     void handlePreDhcpSetup() {
+        mDhcpActive = true;
         if (!mBluetoothConnectionActive) {
             /*
              * There are problems setting the Wi-Fi driver's power
@@ -1773,6 +2242,8 @@
         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
         mWifiNative.setPowerSave(false);
 
+        stopBatchedScan();
+
         /* P2p discovery breaks dhcp, shut it down in order to get through this */
         Message msg = new Message();
         msg.what = WifiP2pService.BLOCK_DISCOVERY;
@@ -1811,6 +2282,12 @@
         // Set the coexistence mode back to its default value
         mWifiNative.setBluetoothCoexistenceMode(
                 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+
+        mDhcpActive = false;
+
+        if (mBatchedScanSettings != null) {
+            startBatchedScan();
+        }
     }
 
     private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
@@ -1828,20 +2305,7 @@
         }
         mWifiInfo.setInetAddress(addr);
         mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
-        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
-            //DHCP renewal in connected state
-            linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
-            if (!linkProperties.equals(mLinkProperties)) {
-                if (DBG) {
-                    log("Link configuration changed for netId: " + mLastNetworkId
-                            + " old: " + mLinkProperties + "new: " + linkProperties);
-                }
-                mLinkProperties = linkProperties;
-                sendLinkConfigurationChangedBroadcast();
-            }
-        } else {
-            configureLinkProperties();
-        }
+        updateLinkProperties();
     }
 
     private void handleFailedIpConfiguration() {
@@ -1950,16 +2414,18 @@
                 case CMD_BOOT_COMPLETED:
                     String countryCode = mPersistedCountryCode;
                     if (TextUtils.isEmpty(countryCode) == false) {
-                        Settings.Global.putString(mContext.getContentResolver(),
-                                Settings.Global.WIFI_COUNTRY_CODE,
-                                countryCode);
-                        // it may be that the state transition that should send this info
-                        // to the driver happened between mPersistedCountryCode getting set
-                        // and now, so simply persisting it here would mean we have sent
-                        // nothing to the driver.  Send the cmd so it might be set now.
                         sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode);
                     }
                     break;
+                case CMD_SET_BATCHED_SCAN:
+                    recordBatchedScanSettings((BatchedScanSettings)message.obj);
+                    break;
+                case CMD_POLL_BATCHED_SCAN:
+                    handleBatchedScanPollRequest();
+                    break;
+                case CMD_START_NEXT_BATCHED_SCAN:
+                    startNextBatchedScan();
+                    break;
                     /* Discard */
                 case CMD_START_SCAN:
                 case CMD_START_SUPPLICANT:
@@ -2058,6 +2524,17 @@
                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
                     replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE);
                     break;
+                case CMD_IP_ADDRESS_UPDATED:
+                    // addLinkAddress is a no-op if called more than once with the same address.
+                    if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) {
+                        updateLinkProperties();
+                    }
+                    break;
+                case CMD_IP_ADDRESS_REMOVED:
+                    if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) {
+                        updateLinkProperties();
+                    }
+                    break;
                 default:
                     loge("Error! unhandled message" + message);
                     break;
@@ -2120,7 +2597,7 @@
                         * Avoids issues with drivers that do not handle interface down
                         * on a running supplicant properly.
                         */
-                        mWifiNative.killSupplicant(mP2pSupported);
+                        mWifiMonitor.killSupplicant(mP2pSupported);
                         if(mWifiNative.startSupplicant(mP2pSupported)) {
                             setWifiState(WIFI_STATE_ENABLING);
                             if (DBG) log("Supplicant start successful");
@@ -2203,7 +2680,7 @@
                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
                         loge("Failed to setup control channel, restart supplicant");
-                        mWifiNative.killSupplicant(mP2pSupported);
+                        mWifiMonitor.killSupplicant(mP2pSupported);
                         transitionTo(mInitialState);
                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
                     } else {
@@ -2310,9 +2787,7 @@
             }
 
             if (DBG) log("stopping supplicant");
-            if (!mWifiNative.stopSupplicant()) {
-                loge("Failed to stop supplicant");
-            }
+            mWifiMonitor.stopSupplicant();
 
             /* Send ourselves a delayed message to indicate failure after a wait time */
             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
@@ -2453,13 +2928,24 @@
                 mWifiNative.stopFilteringMulticastV4Packets();
             }
 
+            mDhcpActive = false;
+
+            if (mBatchedScanSettings != null) {
+                startBatchedScan();
+            }
+
             if (mOperationalMode != CONNECT_MODE) {
                 mWifiNative.disconnect();
+                mWifiConfigStore.disableAllNetworks();
+                setWifiState(WIFI_STATE_DISABLED);
                 transitionTo(mScanModeState);
             } else {
                 /* Driver stop may have disabled networks, enable right after start */
                 mWifiConfigStore.enableAllNetworks();
+
+                if (DBG) log("Attempting to reconnect to wifi network ..");
                 mWifiNative.reconnect();
+
                 // Status pulls in the current supplicant state and network connection state
                 // events over the monitor connection. This helps framework sync up with
                 // current supplicant state
@@ -2479,7 +2965,15 @@
             }
             mWifiNative.setPowerSave(true);
 
-            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
+            if (mP2pSupported) {
+                if (mOperationalMode == CONNECT_MODE) {
+                    mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
+                } else {
+                    // P2P statemachine starts in disabled state, and is not enabled until
+                    // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
+                    // keep it disabled.
+                }
+            }
 
             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -2491,13 +2985,17 @@
         public boolean processMessage(Message message) {
             switch(message.what) {
                 case CMD_START_SCAN:
-                    noteScanStart(message.arg1);
+                    noteScanStart(message.arg1, (WorkSource) message.obj);
                     startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     break;
+                case CMD_SET_BATCHED_SCAN:
+                    recordBatchedScanSettings((BatchedScanSettings)message.obj);
+                    startBatchedScan();
+                    break;
                 case CMD_SET_COUNTRY_CODE:
                     String country = (String) message.obj;
                     if (DBG) log("set country code " + country);
-                    if (!mWifiNative.setCountryCode(country.toUpperCase(Locale.ROOT))) {
+                    if (!mWifiNative.setCountryCode(country)) {
                         loge("Failed to set country code " + country);
                     }
                     break;
@@ -2506,6 +3004,8 @@
                     if (DBG) log("set frequency band " + band);
                     if (mWifiNative.setBand(band)) {
                         mFrequencyBand.set(band);
+                        // flush old data - like scan results
+                        mWifiNative.bssFlush();
                         //Fetch the latest scan results when frequency band is set
                         startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     } else {
@@ -2602,6 +3102,13 @@
                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
                     }
                     break;
+                case CMD_ENABLE_TDLS:
+                    if (message.obj != null) {
+                        String remoteAddress = (String) message.obj;
+                        boolean enable = (message.arg1 == 1);
+                        mWifiNative.startTdls(remoteAddress, enable);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -2613,6 +3120,10 @@
             updateBatteryWorkSource(null);
             mScanResults = new ArrayList<ScanResult>();
 
+            if (mBatchedScanSettings != null) {
+                stopBatchedScan();
+            }
+
             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
@@ -2733,31 +3244,26 @@
         private int mLastOperationMode;
         @Override
         public void enter() {
-            mWifiConfigStore.disableAllNetworks();
             mLastOperationMode = mOperationalMode;
-            if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
-                mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
-                setWifiState(WIFI_STATE_DISABLED);
-            }
-        }
-        @Override
-        public void exit() {
-            if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
-                setWifiState(WIFI_STATE_ENABLED);
-                // Load and re-enable networks when going back to enabled state
-                // This is essential for networks to show up after restore
-                mWifiConfigStore.loadAndEnableAllNetworks();
-                mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
-            } else {
-                mWifiConfigStore.enableAllNetworks();
-            }
-            mWifiNative.reconnect();
         }
         @Override
         public boolean processMessage(Message message) {
             switch(message.what) {
                 case CMD_SET_OPERATIONAL_MODE:
                     if (message.arg1 == CONNECT_MODE) {
+
+                        if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
+                            setWifiState(WIFI_STATE_ENABLED);
+                            // Load and re-enable networks when going back to enabled state
+                            // This is essential for networks to show up after restore
+                            mWifiConfigStore.loadAndEnableAllNetworks();
+                            mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
+                        } else {
+                            mWifiConfigStore.enableAllNetworks();
+                        }
+
+                        mWifiNative.reconnect();
+
                         mOperationalMode = CONNECT_MODE;
                         transitionTo(mDisconnectedState);
                     } else {
@@ -2768,7 +3274,7 @@
                 // Handle scan. All the connection related commands are
                 // handled only in ConnectModeState
                 case CMD_START_SCAN:
-                    noteScanStart(message.arg1);
+                    noteScanStart(message.arg1, (WorkSource) message.obj);
                     startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
                     break;
                 default:
@@ -2998,6 +3504,14 @@
         }
 
         @Override
+        public void exit() {
+            // if we're leaving before this is done, cleanup
+            if (mDhcpActive) {
+                handlePostDhcpSetup();
+            }
+        }
+
+        @Override
         public boolean processMessage(Message message) {
             switch (message.what) {
               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
@@ -3034,7 +3548,7 @@
                     break;
                 case CMD_START_SCAN:
                     /* Do not attempt to connect when we are already connected */
-                    noteScanStart(message.arg1);
+                    noteScanStart(message.arg1, (WorkSource) message.obj);
                     startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
                     break;
                     /* Ignore connection to same network */
@@ -3054,8 +3568,7 @@
                         }
                         if (result.hasProxyChanged()) {
                             log("Reconfiguring proxy on connection");
-                            configureLinkProperties();
-                            sendLinkConfigurationChangedBroadcast();
+                            updateLinkProperties();
                         }
                     }
 
@@ -3109,13 +3622,14 @@
         @Override
         public void enter() {
             if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+                // TODO: If we're switching between static IP configuration and DHCP, remove the
+                // static configuration first.
                 startDhcp();
             } else {
                 // stop any running dhcp before assigning static IP
                 stopDhcp();
                 DhcpResults dhcpResults = new DhcpResults(
                         mWifiConfigStore.getLinkProperties(mLastNetworkId));
-                dhcpResults.linkProperties.setInterfaceName(mInterfaceName);
                 InterfaceConfiguration ifcg = new InterfaceConfiguration();
                 Iterator<LinkAddress> addrs =
                         dhcpResults.linkProperties.getLinkAddresses().iterator();
@@ -3172,6 +3686,7 @@
     class VerifyingLinkState extends State {
         @Override
         public void enter() {
+            log(getName() + " enter");
             setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
             sendNetworkStateChangeBroadcast(mLastBssid);
@@ -3181,11 +3696,14 @@
             switch (message.what) {
                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
                     //stay here
+                    log(getName() + " POOR_LINK_DETECTED: no transition");
                     break;
                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
+                    log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check");
                     transitionTo(mCaptivePortalCheckState);
                     break;
                 default:
+                    if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED");
                     return NOT_HANDLED;
             }
             return HANDLED;
@@ -3195,6 +3713,7 @@
     class CaptivePortalCheckState extends State {
         @Override
         public void enter() {
+            log(getName() + " enter");
             setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK);
             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK);
             sendNetworkStateChangeBroadcast(mLastBssid);
@@ -3203,6 +3722,7 @@
         public boolean processMessage(Message message) {
             switch (message.what) {
                 case CMD_CAPTIVE_CHECK_COMPLETE:
+                    log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE");
                     try {
                         mNwService.enableIpv6(mInterfaceName);
                     } catch (RemoteException re) {
@@ -3352,7 +3872,7 @@
                     if (mP2pConnected.get()) break;
                     if (message.arg1 == mPeriodicScanToken &&
                             mWifiConfigStore.getConfiguredNetworks().size() == 0) {
-                        sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE);
+                        sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE, 0, (WorkSource) null);
                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
                     }
@@ -3369,6 +3889,13 @@
                 case CMD_SET_OPERATIONAL_MODE:
                     if (message.arg1 != CONNECT_MODE) {
                         mOperationalMode = message.arg1;
+
+                        mWifiConfigStore.disableAllNetworks();
+                        if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
+                            mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
+                            setWifiState(WIFI_STATE_DISABLED);
+                        }
+
                         transitionTo(mScanModeState);
                     }
                     break;
@@ -3691,6 +4218,7 @@
                     if (!isWifiTethered(stateChange.active)) {
                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
                         setHostApRunning(null, false);
+                        setHostApRunning(null, true);
                     }
                     return HANDLED;
                 case CMD_STOP_AP:
@@ -3781,7 +4309,7 @@
     /**
      * arg2 on the source message has a unique id that needs to be retained in replies
      * to match the request
-     *
+
      * see WifiManager for details
      */
     private Message obtainMessageWithArg2(Message srcMsg) {
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index cf75381..615c893 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -20,11 +20,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.BaseNetworkStateTracker;
 import android.net.LinkCapabilities;
+import android.net.LinkQualityInfo;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkStateTracker;
+import android.net.SamplingDataTracker;
+import android.net.WifiLinkQualityInfo;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
@@ -37,7 +40,7 @@
  *
  * @hide
  */
-public class WifiStateTracker implements NetworkStateTracker {
+public class WifiStateTracker extends BaseNetworkStateTracker {
 
     private static final String NETWORKTYPE = "WIFI";
     private static final String TAG = "WifiStateTracker";
@@ -48,17 +51,17 @@
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
 
-    private LinkProperties mLinkProperties;
-    private LinkCapabilities mLinkCapabilities;
-    private NetworkInfo mNetworkInfo;
     private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN;
 
+    private WifiInfo mWifiInfo;
+
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
-    private Context mContext;
     private BroadcastReceiver mWifiStateReceiver;
     private WifiManager mWifiManager;
 
+    private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
+
     public WifiStateTracker(int netType, String networkName) {
         mNetworkInfo = new NetworkInfo(netType, 0, networkName, "");
         mLinkProperties = new LinkProperties();
@@ -120,6 +123,11 @@
         mWifiManager.captivePortalCheckComplete();
     }
 
+    @Override
+    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+        // not implemented
+    }
+
     /**
      * Turn the wireless radio off for a network.
      * @param turnOn {@code true} to turn the radio on, {@code false}
@@ -169,6 +177,7 @@
     /**
      * Fetch NetworkInfo for the network
      */
+    @Override
     public NetworkInfo getNetworkInfo() {
         return new NetworkInfo(mNetworkInfo);
     }
@@ -176,6 +185,7 @@
     /**
      * Fetch LinkProperties for the network
      */
+    @Override
     public LinkProperties getLinkProperties() {
         return new LinkProperties(mLinkProperties);
     }
@@ -186,11 +196,48 @@
      *
      * @return a copy of this connections capabilities, may be empty but never null.
      */
+    @Override
     public LinkCapabilities getLinkCapabilities() {
         return new LinkCapabilities(mLinkCapabilities);
     }
 
     /**
+     * Return link info
+     * @return an object of type WifiLinkQualityInfo
+     */
+    @Override
+    public LinkQualityInfo getLinkQualityInfo() {
+        if (mNetworkInfo == null) {
+            // no data available yet; just return
+            return null;
+        }
+
+        WifiLinkQualityInfo li = new WifiLinkQualityInfo();
+        li.setNetworkType(mNetworkInfo.getType());
+
+        synchronized(mSamplingDataTracker.mSamplingDataLock) {
+            mSamplingDataTracker.setCommonLinkQualityInfoFields(li);
+            li.setTxGood(mSamplingDataTracker.getSampledTxPacketCount());
+            li.setTxBad(mSamplingDataTracker.getSampledTxPacketErrorCount());
+        }
+
+        // li.setTheoreticalRxBandwidth(??);
+        // li.setTheoreticalTxBandwidth(??);
+
+        if (mWifiInfo != null) {
+            li.setBssid(mWifiInfo.getBSSID());
+
+            int rssi = mWifiInfo.getRssi();
+            li.setRssi(rssi);
+
+            li.setNormalizedSignalStrength(mWifiManager.calculateSignalLevel(rssi,
+                    LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE));
+        }
+
+        return li;
+    }
+
+    /**
      * Check if default route is set
      */
     public boolean isDefaultRouteSet() {
@@ -219,6 +266,7 @@
             if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
                         WifiManager.EXTRA_NETWORK_INFO);
+
                 mLinkProperties = intent.getParcelableExtra(
                         WifiManager.EXTRA_LINK_PROPERTIES);
                 if (mLinkProperties == null) {
@@ -229,7 +277,9 @@
                 if (mLinkCapabilities == null) {
                     mLinkCapabilities = new LinkCapabilities();
                 }
-                // don't want to send redundent state messages
+
+                mWifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
+                // don't want to send redundant state messages
                 // but send portal check detailed state notice
                 NetworkInfo.State state = mNetworkInfo.getState();
                 if (mLastState == state &&
@@ -237,13 +287,15 @@
                     return;
                 } else {
                     mLastState = state;
+                    /* lets not sample traffic data across state changes */
+                    mSamplingDataTracker.resetSamplingData();
                 }
+
                 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
                         new NetworkInfo(mNetworkInfo));
                 msg.sendToTarget();
             } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
-                mLinkProperties = (LinkProperties) intent.getParcelableExtra(
-                        WifiManager.EXTRA_LINK_PROPERTIES);
+                mLinkProperties = intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES);
                 Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
                 msg.sendToTarget();
             }
@@ -268,4 +320,15 @@
     public void supplyMessenger(Messenger messenger) {
         // not supported on this network
     }
+
+    @Override
+    public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
+        mSamplingDataTracker.startSampling(s);
+    }
+
+    @Override
+    public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
+        mSamplingDataTracker.stopSampling(s);
+    }
 }
+
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index eb47a4a..6278c89 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -75,8 +75,7 @@
  */
 public class WifiWatchdogStateMachine extends StateMachine {
 
-    /* STOPSHIP: Keep this configurable for debugging until ship */
-    private static boolean DBG = false;
+    private static final boolean DBG = false;
 
     private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
 
@@ -697,10 +696,6 @@
             switch (msg.what) {
                 case EVENT_WATCHDOG_SETTINGS_CHANGE:
                     updateSettings();
-                    // STOPSHIP: Remove this at ship
-                    logd("Updated secure settings and turned debug on");
-                    DBG = true;
-
                     if (mPoorNetworkDetectionEnabled) {
                         transitionTo(mOnlineWatchState);
                     } else {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 737ab91..4988b92 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -30,6 +30,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.Looper;
@@ -430,6 +431,28 @@
     /** @hide */
     public static final int START_WPS_SUCCEEDED                     = BASE + 64;
 
+    /** @hide */
+    public static final int START_LISTEN                            = BASE + 65;
+    /** @hide */
+    public static final int START_LISTEN_FAILED                     = BASE + 66;
+    /** @hide */
+    public static final int START_LISTEN_SUCCEEDED                  = BASE + 67;
+
+    /** @hide */
+    public static final int STOP_LISTEN                             = BASE + 68;
+    /** @hide */
+    public static final int STOP_LISTEN_FAILED                      = BASE + 69;
+    /** @hide */
+    public static final int STOP_LISTEN_SUCCEEDED                   = BASE + 70;
+
+    /** @hide */
+    public static final int SET_CHANNEL                             = BASE + 71;
+    /** @hide */
+    public static final int SET_CHANNEL_FAILED                      = BASE + 72;
+    /** @hide */
+    public static final int SET_CHANNEL_SUCCEEDED                   = BASE + 73;
+
+
     /**
      * Create a new WifiP2pManager instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -667,6 +690,9 @@
                     case DELETE_PERSISTENT_GROUP_FAILED:
                     case SET_WFD_INFO_FAILED:
                     case START_WPS_FAILED:
+                    case START_LISTEN_FAILED:
+                    case STOP_LISTEN_FAILED:
+                    case SET_CHANNEL_FAILED:
                         if (listener != null) {
                             ((ActionListener) listener).onFailure(message.arg1);
                         }
@@ -689,6 +715,9 @@
                     case DELETE_PERSISTENT_GROUP_SUCCEEDED:
                     case SET_WFD_INFO_SUCCEEDED:
                     case START_WPS_SUCCEEDED:
+                    case START_LISTEN_SUCCEEDED:
+                    case STOP_LISTEN_SUCCEEDED:
+                    case SET_CHANNEL_SUCCEEDED:
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -955,6 +984,22 @@
         c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
     }
 
+    /** @hide */
+    public void listen(Channel c, boolean enable, ActionListener listener) {
+        checkChannel(c);
+        c.mAsyncChannel.sendMessage(enable ? START_LISTEN : STOP_LISTEN,
+                0, c.putListener(listener));
+    }
+
+    /** @hide */
+    public void setWifiP2pChannels(Channel c, int lc, int oc, ActionListener listener) {
+        checkChannel(c);
+        Bundle p2pChannels = new Bundle();
+        p2pChannels.putInt("lc", lc);
+        p2pChannels.putInt("oc", oc);
+        c.mAsyncChannel.sendMessage(SET_CHANNEL, 0, c.putListener(listener), p2pChannels);
+    }
+
     /**
      * Start a Wi-Fi Protected Setup (WPS) session.
      *
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 68a082a..50e8e3d 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -48,6 +48,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Handler;
@@ -173,6 +174,9 @@
     //   msg.obj  = StateMachine to send to when blocked
     public static final int BLOCK_DISCOVERY                 =   BASE + 15;
 
+    // set country code
+    public static final int SET_COUNTRY_CODE                =   BASE + 16;
+
     public static final int ENABLED                         = 1;
     public static final int DISABLED                        = 0;
 
@@ -628,6 +632,10 @@
                 case DhcpStateMachine.CMD_ON_QUIT:
                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
                 case SET_MIRACAST_MODE:
+                case WifiP2pManager.START_LISTEN:
+                case WifiP2pManager.STOP_LISTEN:
+                case WifiP2pManager.SET_CHANNEL:
+                case SET_COUNTRY_CODE:
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
                     // Enable is lazy and has no response
@@ -729,7 +737,16 @@
                     replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
-               default:
+                case WifiP2pManager.START_LISTEN:
+                    replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
+                case WifiP2pManager.STOP_LISTEN:
+                    replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
+
+                default:
                     return NOT_HANDLED;
             }
             return HANDLED;
@@ -858,7 +875,7 @@
                     }
                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
 
-                    mWifiNative.closeSupplicantConnection();
+                    mWifiMonitor.stopMonitoring();
                     transitionTo(mP2pDisablingState);
                     break;
                 case WifiP2pManager.SET_DEVICE_NAME:
@@ -1022,6 +1039,39 @@
                 case SET_MIRACAST_MODE:
                     mWifiNative.setMiracastMode(message.arg1);
                     break;
+                case WifiP2pManager.START_LISTEN:
+                    if (DBG) logd(getName() + " start listen mode");
+                    mWifiNative.p2pFlush();
+                    if (mWifiNative.p2pExtListen(true, 500, 500)) {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
+                    }
+                    break;
+                case WifiP2pManager.STOP_LISTEN:
+                    if (DBG) logd(getName() + " stop listen mode");
+                    if (mWifiNative.p2pExtListen(false, 0, 0)) {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
+                    }
+                    mWifiNative.p2pFlush();
+                    break;
+                case WifiP2pManager.SET_CHANNEL:
+                    Bundle p2pChannels = (Bundle) message.obj;
+                    int lc = p2pChannels.getInt("lc", 0);
+                    int oc = p2pChannels.getInt("oc", 0);
+                    if (DBG) logd(getName() + " set listen and operating channel");
+                    if (mWifiNative.p2pSetChannel(lc, oc)) {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
+                    }
+                    break;
+                case SET_COUNTRY_CODE:
+                    String countryCode = (String) message.obj;
+                    mWifiNative.setCountryCode(countryCode);
+                    break;
                 default:
                    return NOT_HANDLED;
             }
@@ -1171,6 +1221,35 @@
                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
                     }
                     break;
+                case WifiP2pManager.START_LISTEN:
+                    if (DBG) logd(getName() + " start listen mode");
+                    mWifiNative.p2pFlush();
+                    if (mWifiNative.p2pExtListen(true, 500, 500)) {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
+                    }
+                    break;
+                case WifiP2pManager.STOP_LISTEN:
+                    if (DBG) logd(getName() + " stop listen mode");
+                    if (mWifiNative.p2pExtListen(false, 0, 0)) {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
+                    }
+                    mWifiNative.p2pFlush();
+                    break;
+                case WifiP2pManager.SET_CHANNEL:
+                    Bundle p2pChannels = (Bundle) message.obj;
+                    int lc = p2pChannels.getInt("lc", 0);
+                    int oc = p2pChannels.getInt("oc", 0);
+                    if (DBG) logd(getName() + " set listen and operating channel");
+                    if (mWifiNative.p2pSetChannel(lc, oc)) {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index 1ba991e..d65d03e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -19,6 +19,8 @@
 import android.os.Parcelable;
 import android.os.Parcel;
 
+import java.util.Locale;
+
 /**
  * A class representing Wifi Display information for a device
  * @hide
@@ -135,7 +137,8 @@
     }
 
     public String getDeviceInfoHex() {
-        return String.format("%04x%04x%04x%04x", 6, mDeviceInfo, mCtrlPort, mMaxThroughput);
+        return String.format(
+                Locale.US, "%04x%04x%04x%04x", 6, mDeviceInfo, mCtrlPort, mMaxThroughput);
     }
 
     public String toString() {
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index 9879d4e..a4118dc 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -127,7 +127,7 @@
         sb.append(" ");
 
         byte[] data = instanceName.getBytes();
-        sb.append(String.format("%02x", data.length));
+        sb.append(String.format(Locale.US, "%02x", data.length));
         sb.append(WifiP2pServiceInfo.bin2HexStr(data));
         // This is the start point of this response.
         // Therefore, it indicates the request domain name.
@@ -187,8 +187,8 @@
             dnsName = dnsName.toLowerCase(Locale.ROOT); // TODO: is this right?
         }
         sb.append(compressDnsName(dnsName));
-        sb.append(String.format("%04x", dnsType));
-        sb.append(String.format("%02x", version));
+        sb.append(String.format(Locale.US, "%04x", dnsType));
+        sb.append(String.format(Locale.US, "%02x", version));
 
         return sb.toString();
     }
@@ -215,7 +215,7 @@
             int i = dnsName.indexOf('.');
             if (i == -1) {
                 if (dnsName.length() > 0) {
-                    sb.append(String.format("%02x", dnsName.length()));
+                    sb.append(String.format(Locale.US, "%02x", dnsName.length()));
                     sb.append(WifiP2pServiceInfo.bin2HexStr(dnsName.getBytes()));
                 }
                 // for a sequence of labels ending in a zero octet
@@ -225,7 +225,7 @@
 
             String name = dnsName.substring(0, i);
             dnsName = dnsName.substring(i + 1);
-            sb.append(String.format("%02x", name.length()));
+            sb.append(String.format(Locale.US, "%02x", name.length()));
             sb.append(WifiP2pServiceInfo.bin2HexStr(name.getBytes()));
         }
         return sb.toString();
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
index eabd8e5..7462b85c 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
@@ -136,10 +136,10 @@
     public String getSupplicantQuery() {
         StringBuffer sb = new StringBuffer();
         // length is retained as little endian format.
-        sb.append(String.format("%02x", (mLength) & 0xff));
-        sb.append(String.format("%02x", (mLength >> 8) & 0xff));
-        sb.append(String.format("%02x", mProtocolType));
-        sb.append(String.format("%02x", mTransId));
+        sb.append(String.format(Locale.US, "%02x", (mLength) & 0xff));
+        sb.append(String.format(Locale.US, "%02x", (mLength >> 8) & 0xff));
+        sb.append(String.format(Locale.US, "%02x", mProtocolType));
+        sb.append(String.format(Locale.US, "%02x", mTransId));
         if (mQuery != null) {
             sb.append(mQuery);
         }
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
index 40a0d61..a4cdfd9 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.UUID;
 
 /**
@@ -98,7 +99,7 @@
     private static String createSupplicantQuery(String uuid, String data) {
         StringBuffer sb = new StringBuffer();
         sb.append("upnp ");
-        sb.append(String.format("%02x ", VERSION_1_0));
+        sb.append(String.format(Locale.US, "%02x ", VERSION_1_0));
         sb.append("uuid:");
         sb.append(uuid);
         if (data != null) {
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
index b5cf144..98e447e 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
@@ -18,6 +18,8 @@
 
 import android.net.wifi.p2p.WifiP2pManager;
 
+import java.util.Locale;
+
 /**
  * A class for creating a Upnp service discovery request for use with
  * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
@@ -73,7 +75,7 @@
             throw new IllegalArgumentException("search target cannot be null");
         }
         StringBuffer sb = new StringBuffer();
-        sb.append(String.format("%02x", WifiP2pUpnpServiceInfo.VERSION_1_0));
+        sb.append(String.format(Locale.US, "%02x", WifiP2pUpnpServiceInfo.VERSION_1_0));
         sb.append(WifiP2pServiceInfo.bin2HexStr(st.getBytes()));
         return new WifiP2pUpnpServiceRequest(sb.toString());
     }